diff --git a/.gitignore b/.gitignore index 90fb50a3dc5c..2cd966ff705a 100644 --- a/.gitignore +++ b/.gitignore @@ -140,3 +140,10 @@ kernel/configs/android-*.cfg #Ignoring Android.bp link file # Android.bp + +# ln the wakelock_profiler +drivers/soc/oplus/owakelock +include/soc/oplus/oplus_wakelock_profiler.h + +# ignore net/oplus_modules +net/oplus_modules diff --git a/AndroidKernel.mk b/AndroidKernel.mk index f404b5abe9c0..887a5c6f47f8 100644 --- a/AndroidKernel.mk +++ b/AndroidKernel.mk @@ -208,7 +208,7 @@ $(KERNEL_HEADERS_INSTALL): $(KERNEL_OUT) # Creating a dtb.img once the kernel is compiled if TARGET_KERNEL_APPEND_DTB is set to be false $(INSTALLED_DTBIMAGE_TARGET): $(TARGET_PREBUILT_INT_KERNEL) - cat $(KERNEL_OUT)/arch/$(KERNEL_ARCH)/boot/dts/vendor/qcom/*.dtb > $@ + cat $(KERNEL_OUT)/arch/$(KERNEL_ARCH)/boot/dts/vendor/*/*.dtb > $@ .PHONY: kerneltags kerneltags: $(KERNEL_OUT) $(KERNEL_CONFIG) diff --git a/Kconfig b/Kconfig index 0f27b9e7ae30..edbf510b29a3 100644 --- a/Kconfig +++ b/Kconfig @@ -7,6 +7,85 @@ mainmenu "Linux/$(ARCH) $(KERNELVERSION) Kernel Configuration" comment "Compiler: $(CC_VERSION_TEXT)" +#ifdef CONFIG_OPLUS_SYSTEM_KERNEL +config OPLUS_SYSTEM_KERNEL_QCOM + bool "config oplus system feature " + default y + help + define this config to Distinguish between qcom and mtk platform + +config OPLUS_SYSTEM_KERNEL_MTK + bool "config oplus system feature " + default n + help + define this config to Distinguish between qcom and mtk platform + +config OPLUS_SLUB_TEST + string + default "$(OPLUS_SLUB_TEST)" + +config OPLUS_KASAN_TEST + string + default "$(OPLUS_KASAN_TEST)" + +config OPLUS_KMEMLEAK_TEST + string + default "$(OPLUS_KMEMLEAK_TEST)" + +config OPLUS_AGING_TEST + string + default "$(OPLUS_AGING_TEST)" + +config OPLUS_PAGEOWNER_TEST + string + default "$(OPLUS_PAGEOWNER_TEST)" + +config OPLUS_AGING_DEBUG + bool "oplus aging add config" + select IPC_LOGGING + select QCOM_RTB + select QCOM_RTB_SEPARATE_CPUS + select SCSI_LOGGING + select SCSI_UFSHCD_CMD_LOGGING + select KPROBES + select MHI_DEBUG + default y if OPLUS_AGING_TEST = "true" + default n + +config OPLUS_KASAN_DEBUG + bool "oplus kasan debug" + select KASAN + select KASAN_GENERIC + #select KCOV + #select KCOV_ENABLE_COMPARISONS + default y if OPLUS_KASAN_TEST = "true" + default n + +config OPLUS_KMEMLEAK_DEBUG + bool "oplus kmemleak debug" + select DEBUG_KMEMLEAK + select SLUB_DEBUG + select SLABTRACE_DEBUG + default y if OPLUS_KMEMLEAK_TEST = "true" + default n + +config OPLUS_SLUB_DEBUG + bool "oplus slub debug" + select SLUB_DEBUG + select SLUB_DEBUG_ON + select SLUB_DEBUG_PANIC_ON + default y if OPLUS_SLUB_TEST = "true" + default n + +config OPLUS_PAGEOWNER_DEBUG + bool "oplus pageowner debug" + select PAGE_OWNER + select PAGE_OWNER_ENABLE_DEFAULT + default y if OPLUS_PAGEOWNER_TEST = "true" + default n +#endif /*CONFIG_OPLUS_SYSTEM_KERNEL*/ + + source "scripts/Kconfig.include" source "init/Kconfig" diff --git a/Makefile b/Makefile index 771da222fcd4..f62794a79ffb 100644 --- a/Makefile +++ b/Makefile @@ -450,7 +450,82 @@ KBUILD_LDFLAGS := GCC_PLUGINS_CFLAGS := CLANG_FLAGS := -export ARCH SRCARCH CONFIG_SHELL HOSTCC KBUILD_HOSTCFLAGS CROSS_COMPILE LD CC +# ifdef VENDOR_EDIT +KBUILD_CFLAGS += -DVENDOR_EDIT +KBUILD_CPPFLAGS += -DVENDOR_EDIT +CFLAGS_KERNEL += -DVENDOR_EDIT +CFLAGS_MODULE += -DVENDOR_EDIT +# endif +ifeq ($(BRAND_SHOW_FLAG),oneplus) +KBUILD_CFLAGS += -DOPLUS_CUSTOM_OP_DEF +endif + +# ifdef OPLUS_FEATURE_POWER_EFFICIENCY +KBUILD_CFLAGS += -DOPLUS_FEATURE_POWER_EFFICIENCY +KBUILD_CPPFLAGS += -DOPLUS_FEATURE_POWER_EFFICIENCY +CFLAGS_KERNEL += -DOPLUS_FEATURE_POWER_EFFICIENCY +CFLAGS_MODULE += -DOPLUS_FEATURE_POWER_EFFICIENCY +# endif + +-include OplusKernelEnvConfig.mk + +#ifdef VENDOR_EDIT +ifneq (,$(findstring Aging,$(SPECIAL_VERSION))) +OPLUS_F2FS_DEBUG := true +endif + +export OPLUS_F2FS_DEBUG +#endif /* VENDOR_EDIT */ + +#ifdef OPLUS_BUG_STABILITY +#Add for Debug Config, slub/kmemleak/kasan config +ifeq ($(AGING_DEBUG_MASK),1) +#Agingtest enable rtb +OPLUS_MEMLEAK_DETECT := true +OPLUS_AGING_TEST := true +endif + +ifeq ($(AGING_DEBUG_MASK),2) +#enable kasan +OPLUS_KASAN_TEST := true +endif + +ifeq ($(AGING_DEBUG_MASK),3) +#enable kmemleak +OPLUS_KMEMLEAK_TEST := true +endif + +ifeq ($(AGING_DEBUG_MASK),4) +#enable rtb +OPLUS_AGING_TEST := true +#enable kasan +OPLUS_SLUB_TEST := true +endif + +ifeq ($(AGING_DEBUG_MASK),5) +#enable rtb +OPLUS_AGING_TEST := true +#enable kasan +OPLUS_PAGEOWNER_TEST := true +endif + +export OPLUS_AGING_TEST OPLUS_KASAN_TEST OPLUS_KMEMLEAK_TEST OPLUS_SLUB_TEST OPLUS_PAGEOWNER_TEST +#endif + +#ifdef OPLUS_FEATURE_MEMLEAK_DETECT +#Add for memleak test +ifeq ($(TARGET_MEMLEAK_DETECT_TEST),0) +OPLUS_MEMLEAK_DETECT := false +else ifeq ($(TARGET_MEMLEAK_DETECT_TEST),1) +OPLUS_MEMLEAK_DETECT := true +OPLUS_SLUB_TEST := true +endif + +#Add for memleak test +export OPLUS_MEMLEAK_DETECT +#endif + +export ARCH SRCARCH CONFIG_SHELL HOSTCC KBUILD_HOSTCFLAGS CROSS_COMPILE AS LD CC export CPP AR NM STRIP OBJCOPY OBJDUMP OBJSIZE READELF KBUILD_HOSTLDFLAGS KBUILD_HOSTLDLIBS export MAKE LEX YACC AWK GENKSYMS INSTALLKERNEL PERL PYTHON PYTHON2 PYTHON3 UTS_MACHINE export HOSTCXX KBUILD_HOSTCXXFLAGS LDFLAGS_MODULE CHECK CHECKFLAGS diff --git a/OplusKernelEnvConfig.mk b/OplusKernelEnvConfig.mk new file mode 100644 index 000000000000..2f83a55c5c5a --- /dev/null +++ b/OplusKernelEnvConfig.mk @@ -0,0 +1,189 @@ +# Copyright (C), 2008-2030, OPLUS Mobile Comm Corp., Ltd +### All rights reserved. +### +### File: - OplusKernelEnvConfig.mk +### Description: +### you can get the oplus feature variables set in android side in this file +### this file will add global macro for common oplus added feature +### BSP team can do customzation by referring the feature variables +### Version: 1.0 +### Date: 2020-03-18 +### Author: Liang.Sun +### +### ------------------------------- Revision History: ---------------------------- +### +### ------------------------------------------------------------------------------ +################################################################################## + +-include oplus_native_features.mk + +###ifdef OPLUS_ARCH_INJECT +OPLUS_CONNECTIVITY_NATIVE_FEATURE_SET := + +##Add OPLUS Debug/Feature Macro Support for kernel/driver +##ifeq ($(OPLUS_FEATURE_TEST), yes) +## OPLUS_CONNECTIVITY_NATIVE_FEATURE_SET += OPLUS_FEATURE_TEST +##endif + +ifeq ($(OPLUS_FEATURE_WIFI_MTUDETECT), yes) +OPLUS_CONNECTIVITY_NATIVE_FEATURE_SET += OPLUS_FEATURE_WIFI_MTUDETECT +endif + +$(foreach myfeature,$(OPLUS_CONNECTIVITY_NATIVE_FEATURE_SET),\ + $( \ + $(eval KBUILD_CFLAGS += -D$(myfeature)) \ + $(eval KBUILD_CPPFLAGS += -D$(myfeature)) \ + $(eval CFLAGS_KERNEL += -D$(myfeature)) \ + $(eval CFLAGS_MODULE += -D$(myfeature)) \ + ) \ +) +###endif OPLUS_ARCH_INJECT + +ALLOWED_MCROS := OPLUS_FEATURE_FG_IO_OPT \ +OPLUS_FEATURE_SPECIALOPT \ +OPLUS_FEATURE_PERFORMANCE \ +OPLUS_FEATURE_STORAGE_TOOL \ +OPLUS_FEATURE_UFS_DRIVER \ +OPLUS_FEATURE_UFS_SHOW_LATENCY \ +OPLUS_FEATURE_UFSPLUS \ +OPLUS_FEATURE_PADL_STATISTICS \ +OPLUS_FEATURE_EMMC_SDCARD_OPTIMIZE \ +OPLUS_FEATURE_EMMC_DRIVER \ +OPLUS_FEATURE_HEALTHINFO \ +OPLUS_FEATURE_TASK_CPUSTATS \ +OPLUS_FEATURE_HANS_FREEZE \ +OPLUS_FEATURE_SCHED_ASSIST \ +OPLUS_FEATURE_IOMONITOR \ +OPLUS_FEATURE_TP_BSPFWUPDATE \ +OPLUS_FEATURE_LOWMEM_DBG \ +OPLUS_FEATURE_QCOM_PMICWD \ +OPLUS_FEATURE_CHG_BASIC \ +OPLUS_FEATURE_NWPOWER \ +OPLUS_FEATURE_WIFI_BDF \ +OPLUS_FEATURE_CONNFCSOFT \ +OPLUS_FEATURE_AGINGTEST \ +OPLUS_FEATURE_SENSOR_SMEM \ +OPLUS_FEATURE_SSR \ +OPLUS_FEATURE_TP_BASIC \ +OPLUS_FEATURE_EDTASK_IMPROVE \ +OPLUS_FEATURE_WIFI_SLA \ +OPLUS_FEATURE_WIFI_ROUTERBOOST \ +OPLUS_FEATURE_IPV6_OPTIMIZE \ +OPLUS_FEATURE_DATA_EVAL \ +OPLUS_FEATURE_DHCP \ +OPLUS_FEATURE_PHOENIX \ +OPLUS_FEATURE_PHOENIX_REBOOT_SPEED \ +OPLUS_FEATURE_KMSG_WB \ +OPLUS_FEATURE_SHUTDOWN_SPEED \ +OPLUS_FEATURE_OLC \ +OPLUS_FEATURE_DUMPDEVICE \ +OPLUS_FEATURE_SAUPWK \ +OPLUS_FEATURE_MEMORY_ISOLATE \ +OPLUS_FEATURE_MULTI_KSWAPD \ +OPLUS_FEATURE_WIFI_MTUDETECT \ +OPLUS_FEATURE_XTOWNER_INPUT \ +OPLUS_FEATURE_SELINUX_CONTROL_LOG \ +OPLUS_FEATURE_PXLW_IRIS5 \ +OPLUS_FEATURE_MULTI_FREEAREA \ +OPLUS_FEATURE_VIRTUAL_RESERVE_MEMORY \ +OPLUS_FEATURE_GPU_MINIDUMP \ +OPLUS_FEATURE_PROCESS_RECLAIM \ +OPLUS_FEATURE_ZRAM_OPT \ +OPLUS_FEATURE_AUDIO_FTM \ +OPLUS_FEATURE_SPEAKER_MUTE \ +OPLUS_FEATURE_MM_FEEDBACK \ +OPLUS_FEATURE_MI2S_SLAVE \ +OPLUS_FEATURE_KTV \ +OPLUS_FEATURE_QCOM_WATCHDOG \ +OPLUS_FEATURE_MEMLEAK_DETECT \ +OPLUS_FEATURE_EXFAT_SUPPORT \ +OPLUS_FEATURE_SDCARDFS_SUPPORT \ +OPLUS_FEATURE_CAMERA_OIS \ +OPLUS_BUG_COMPATIBILITY \ +OPLUS_BUG_STABILITY \ +OPLUS_BUG_DEBUG \ +OPLUS_ARCH_INJECT \ +OPLUS_ARCH_EXTENDS \ +OPLUS_FEATURE_AUDIODETECT \ +VENDOR_EDIT \ +OPLUS_FEATURE_DC \ +OPLUS_FEATURE_POWERINFO_STANDBY \ +OPLUS_FEATURE_POWERINFO_RPMH \ +OPLUS_FEATURE_CAMERA_COMMON \ +OPLUS_FEATURE_ADSP_RECOVERY \ +OPLUS_FEATURE_SMARTPA_PM \ +OPLUS_FEATURE_IMPEDANCE_MATCH \ +OPLUS_FEATURE_MODEM_MINIDUMP \ +OPLUS_FEATURE_THEIA \ +OPLUS_FEATURE_POWER_CPUFREQ \ +OPLUS_FEATURE_MIDAS \ +OPLUS_FEATURE_WIFI_OPLUSWFD \ +OPLUS_FEATURE_WIFI_DUALSTA_AP_BLACKLIST \ +OPLUS_FEATURE_WIFI_DCS_SWITCH \ +OPLUS_FEATURE_IM \ +OPLUS_FEATURE_TPD \ +OPLUS_FEATURE_APP_MONITOR\ +OPLUS_FEATURE_RT_INFO \ +OPLUS_FEATURE_MIC_VA_MIC_CLK_SWITCH + +ifeq ($(OPLUS_FEATURE_ADFR_KERNEL), yes) + $(warning add OPLUS_FEATURE_ADFR in kernel) + ALLOWED_MCROS += OPLUS_FEATURE_ADFR +endif + +ifeq ($(OPLUS_FEATURE_GAMMA_SWITCH_KERNEL), yes) + $(warning add OPLUS_FEATURE_GAMMA_SWITCH_KERNEL in kernel) + ALLOWED_MCROS += OPLUS_FEATURE_GAMMA_SWITCH +endif + + +$(foreach myfeature,$(ALLOWED_MCROS),\ + $(warning make $(myfeature) to be a macro here) \ + $(eval KBUILD_CFLAGS += -D$(myfeature)) \ + $(eval KBUILD_CPPFLAGS += -D$(myfeature)) \ + $(eval CFLAGS_KERNEL += -D$(myfeature)) \ + $(eval CFLAGS_MODULE += -D$(myfeature)) \ +) + +# BSP team can do customzation by referring the feature variables + +ifeq ($(OPLUS_FEATURE_SECURE_GUARD),yes) +export CONFIG_OPLUS_SECURE_GUARD=y +KBUILD_CFLAGS += -DCONFIG_OPLUS_SECURE_GUARD +endif + +ifeq ($(OPLUS_FEATURE_SECURE_ROOTGUARD),yes) +export CONFIG_OPLUS_ROOT_CHECK=y +KBUILD_CFLAGS += -DCONFIG_OPLUS_ROOT_CHECK +endif + +ifeq ($(OPLUS_FEATURE_SECURE_MOUNTGUARD),yes) +export CONFIG_OPLUS_MOUNT_BLOCK=y +KBUILD_CFLAGS += -DCONFIG_OPLUS_MOUNT_BLOCK +endif + +ifeq ($(OPLUS_FEATURE_SECURE_EXECGUARD),yes) +export CONFIG_OPLUS_EXECVE_BLOCK=y +KBUILD_CFLAGS += -DCONFIG_OPLUS_EXECVE_BLOCK +KBUILD_CFLAGS += -DCONFIG_OPLUS_EXECVE_REPORT +endif + +ifeq ($(OPLUS_FEATURE_SECURE_KEVENTUPLOAD),yes) +export CONFIG_OPLUS_KEVENT_UPLOAD=y +KBUILD_CFLAGS += -DCONFIG_OPLUS_KEVENT_UPLOAD +endif + +ifeq ($(OPLUS_FEATURE_SECURE_KEYINTERFACESGUARD),yes) +KBUILD_CFLAGS += -DOPLUS_DISALLOW_KEY_INTERFACES +endif + +ifeq ($(OPLUS_FEATURE_AOD_RAMLESS),yes) +KBUILD_CFLAGS += -DOPLUS_FEATURE_AOD_RAMLESS +KBUILD_CPPFLAGS += -DOPLUS_FEATURE_AOD_RAMLESS +CFLAGS_KERNEL += -DOPLUS_FEATURE_AOD_RAMLESS +CFLAGS_MODULE += -DOPLUS_FEATURE_AOD_RAMLESS +endif + +ifeq ($(OPLUS_FEATURE_OP_SPECIFIC_AUDIO_KERNEL),yes) +KBUILD_CFLAGS += -DOPLUS_FEATURE_OP_SPECIFIC_AUDIO_KERNEL +endif diff --git a/arch/Kconfig b/arch/Kconfig index b892d0781c4e..65b7fc74b2ad 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -1008,6 +1008,15 @@ config RELR well as compatible NM and OBJCOPY utilities (llvm-nm and llvm-objcopy are compatible). +config ARCH_HAS_NONLEAF_PMD_YOUNG + bool + depends on PGTABLE_LEVELS > 2 + help + Architectures that select this option are capable of setting the + accessed bit in non-leaf PMD entries when using them as part of linear + address translations. Page table walkers that clear the accessed bit + may use this capability to reduce their search space. + source "kernel/gcov/Kconfig" source "scripts/gcc-plugins/Kconfig" diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index 28a3fa76fb3c..aa3f1784e9f2 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -1421,6 +1421,7 @@ config RELOCATABLE config RANDOMIZE_BASE bool "Randomize the address of the kernel image" + depends on !KASAN select ARM64_MODULE_PLTS if MODULES select RELOCATABLE help diff --git a/arch/arm64/configs/vendor/bengal-perf_defconfig b/arch/arm64/configs/vendor/bengal-perf_defconfig index b7dadf49a69a..85ef86e28254 100644 --- a/arch/arm64/configs/vendor/bengal-perf_defconfig +++ b/arch/arm64/configs/vendor/bengal-perf_defconfig @@ -378,7 +378,9 @@ CONFIG_SMB1355_SLAVE_CHARGER=y CONFIG_QPNP_QG=y CONFIG_SMB1398_CHARGER=y CONFIG_THERMAL=y -CONFIG_THERMAL_STATISTICS=y +#ifndef OPLUS_FEATURE_THERMAL_STATISTICS +#CONFIG_THERMAL_STATISTICS=y +#endif CONFIG_THERMAL_EMERGENCY_POWEROFF_DELAY_MS=10000 CONFIG_THERMAL_WRITABLE_TRIPS=y CONFIG_THERMAL_GOV_USER_SPACE=y @@ -632,6 +634,10 @@ CONFIG_OVERLAY_FS=y CONFIG_INCREMENTAL_FS=y CONFIG_MSDOS_FS=y CONFIG_VFAT_FS=y +#ifdef OPLUS_FEATURE_EXFAT_SUPPORT +CONFIG_NLS_UTF8=y +CONFIG_EXFAT_FS=y +# endif CONFIG_TMPFS=y CONFIG_TMPFS_POSIX_ACL=y CONFIG_EFIVAR_FS=y diff --git a/arch/arm64/configs/vendor/bengal_defconfig b/arch/arm64/configs/vendor/bengal_defconfig index c682f557d605..ae55bfeed25e 100644 --- a/arch/arm64/configs/vendor/bengal_defconfig +++ b/arch/arm64/configs/vendor/bengal_defconfig @@ -391,7 +391,9 @@ CONFIG_SMB1355_SLAVE_CHARGER=y CONFIG_QPNP_QG=y CONFIG_SMB1398_CHARGER=y CONFIG_THERMAL=y -CONFIG_THERMAL_STATISTICS=y +#ifndef OPLUS_FEATURE_THERMAL_STATISTICS +#CONFIG_THERMAL_STATISTICS=y +#endif CONFIG_THERMAL_EMERGENCY_POWEROFF_DELAY_MS=10000 CONFIG_THERMAL_WRITABLE_TRIPS=y CONFIG_THERMAL_GOV_USER_SPACE=y @@ -661,6 +663,10 @@ CONFIG_OVERLAY_FS=y CONFIG_INCREMENTAL_FS=y CONFIG_MSDOS_FS=y CONFIG_VFAT_FS=y +#ifdef OPLUS_FEATURE_EXFAT_SUPPORT +CONFIG_NLS_UTF8=y +CONFIG_EXFAT_FS=y +# endif CONFIG_TMPFS=y CONFIG_TMPFS_POSIX_ACL=y CONFIG_EFIVAR_FS=y diff --git a/arch/arm64/configs/vendor/kona-iot-perf_defconfig b/arch/arm64/configs/vendor/kona-iot-perf_defconfig index f7c78cf985ac..58b9f61fc415 100644 --- a/arch/arm64/configs/vendor/kona-iot-perf_defconfig +++ b/arch/arm64/configs/vendor/kona-iot-perf_defconfig @@ -654,6 +654,10 @@ CONFIG_OVERLAY_FS=y CONFIG_INCREMENTAL_FS=y CONFIG_MSDOS_FS=y CONFIG_VFAT_FS=y +#ifdef OPLUS_FEATURE_EXFAT_SUPPORT +CONFIG_NLS_UTF8=y +CONFIG_EXFAT_FS=y +# endif CONFIG_TMPFS=y CONFIG_TMPFS_POSIX_ACL=y CONFIG_ECRYPT_FS=y diff --git a/arch/arm64/configs/vendor/kona-iot_defconfig b/arch/arm64/configs/vendor/kona-iot_defconfig index 149c475cf998..d99b15669bd0 100644 --- a/arch/arm64/configs/vendor/kona-iot_defconfig +++ b/arch/arm64/configs/vendor/kona-iot_defconfig @@ -685,6 +685,10 @@ CONFIG_OVERLAY_FS=y CONFIG_INCREMENTAL_FS=y CONFIG_MSDOS_FS=y CONFIG_VFAT_FS=y +#ifdef OPLUS_FEATURE_EXFAT_SUPPORT +CONFIG_NLS_UTF8=y +CONFIG_EXFAT_FS=y +# endif CONFIG_TMPFS=y CONFIG_TMPFS_POSIX_ACL=y CONFIG_EFIVAR_FS=y diff --git a/arch/arm64/configs/vendor/kona-perf_defconfig b/arch/arm64/configs/vendor/kona-perf_defconfig index 6853fe5364ca..9f9185dc820e 100644 --- a/arch/arm64/configs/vendor/kona-perf_defconfig +++ b/arch/arm64/configs/vendor/kona-perf_defconfig @@ -5,6 +5,7 @@ CONFIG_HIGH_RES_TIMERS=y CONFIG_PREEMPT=y CONFIG_IRQ_TIME_ACCOUNTING=y CONFIG_SCHED_WALT=y +CONFIG_MMAP_LOCK_OPT=y CONFIG_TASKSTATS=y CONFIG_TASK_XACCT=y CONFIG_TASK_IO_ACCOUNTING=y @@ -21,6 +22,10 @@ CONFIG_MEMCG_SWAP=y CONFIG_BLK_CGROUP=y CONFIG_CGROUP_FREEZER=y CONFIG_CPUSETS=y +#ifdef OPLUS_FEATURE_TASK_CPUSTATS +CONFIG_OPLUS_SCHED=y +CONFIG_OPLUS_CTP=y +#endif /* OPLUS_FEATURE_TASK_CPUSTATS */ CONFIG_CGROUP_CPUACCT=y CONFIG_CGROUP_BPF=y CONFIG_SCHED_CORE_CTL=y @@ -53,7 +58,7 @@ CONFIG_SCHED_MC=y CONFIG_NR_CPUS=8 CONFIG_SECCOMP=y CONFIG_OKL4_GUEST=y -# CONFIG_UNMAP_KERNEL_AT_EL0 is not set +CONFIG_UNMAP_KERNEL_AT_EL0=y CONFIG_ARM64_SSBD=y CONFIG_ARMV8_DEPRECATED=y CONFIG_SWP_EMULATION=y @@ -82,6 +87,9 @@ CONFIG_CPU_FREQ_GOV_ONDEMAND=y CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y CONFIG_CPU_BOOST=y CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y +#ifdef VENDOR_EDIT +CONFIG_CPU_FREQ_STAT=y +#endif CONFIG_ARM_QCOM_CPUFREQ_HW=y CONFIG_MSM_TZ_LOG=y CONFIG_ARM64_CRYPTO=y @@ -92,6 +100,10 @@ CONFIG_CRYPTO_AES_ARM64_CE_CCM=y CONFIG_CRYPTO_AES_ARM64_CE_BLK=y CONFIG_CRYPTO_AES_ARM64_NEON_BLK=y CONFIG_PANIC_ON_REFCOUNT_ERROR=y +#ifdef OPLUS_FEATURE_UID_PERF +CONFIG_OPLUS_FEATURE_UID_PERF=y +#endif + CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y CONFIG_MODVERSIONS=y @@ -105,7 +117,10 @@ CONFIG_CFQ_GROUP_IOSCHED=y CONFIG_IOSCHED_BFQ=y CONFIG_BFQ_GROUP_IOSCHED=y # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set -CONFIG_MEMORY_HOTPLUG=y +#ifdef OPLUS_DEBUG_STABILITY +##CONFIG_MEMORY_HOTPLUG=y +# CONFIG_MEMORY_HOTPLUG is not set +# endif CONFIG_MEMORY_HOTPLUG_DEFAULT_ONLINE=y CONFIG_MEMORY_HOTPLUG_MOVABLE_NODE=y CONFIG_MEMORY_HOTREMOVE=y @@ -283,6 +298,10 @@ CONFIG_MHI_NETDEV=y CONFIG_MHI_UCI=y CONFIG_MHI_SATELLITE=y CONFIG_ZRAM=y +#ifdef OPLUS_FEATURE_ZRAM_WRITEBACK +#CONFIG_ZRAM_WRITEBACK=y +#CONFIG_ZWB_HANDLE=y +#endif /* OPLUS_FEATURE_ZRAM_WRITEBACK */ CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_LOOP_MIN_COUNT=16 CONFIG_BLK_DEV_RAM=y @@ -305,6 +324,16 @@ CONFIG_SCSI_SCAN_ASYNC=y CONFIG_SCSI_UFSHCD=y CONFIG_SCSI_UFSHCD_PLATFORM=y CONFIG_SCSI_UFS_QCOM=y +CONFIG_SCSI_UFS_QCOM_ICE=y +#ifdef OPLUS_FEATURE_UFSPLUS +CONFIG_UFSFEATURE=y +# CONFIG_UFSHPB is not set +CONFIG_UFSTW=y +CONFIG_UFSTW_IGNORE_GUARANTEE_BIT=y +CONFIG_UFSTW_BOOT_ENABLED=y +CONFIG_UFSHID=y +CONFIG_UFSHID_POC=y +#endif /*OPLUS_FEATURE_UFSPLUS*/ CONFIG_SCSI_UFS_CRYPTO=y CONFIG_SCSI_UFS_CRYPTO_QTI=y CONFIG_MD=y @@ -357,6 +386,47 @@ CONFIG_TABLET_USB_HANWANG=y CONFIG_TABLET_USB_KBTAB=y CONFIG_INPUT_TOUCHSCREEN=y CONFIG_TOUCHSCREEN_FTS=y + +#ifdef OPLUS_FEATURE_TP_BASIC +CONFIG_TOUCHPANEL_SAMSUNG_S6SY791=y +CONFIG_TOUCHPANEL_SAMSUNG_S6SY792=y +CONFIG_TOUCHPANEL_SAMSUNG_S6SY771=y +CONFIG_TOUCHPANEL_SYNAPTICS=y +CONFIG_TOUCHPANEL_SYNAPTICS_TCM_ONCELL=y +CONFIG_TOUCHPANEL_SYNAPTICS_S3706=y +CONFIG_TOUCHPANEL_SAMSUNG=y +CONFIG_TOUCHPANEL_OPLUS=y +CONFIG_TOUCHPANEL_GOODIX=y +CONFIG_TOUCHPANEL_GOODIX_GT9886=y +CONFIG_TOUCHPANEL_FOCAL=y +CONFIG_TOUCHPANEL_FOCAL_FT3658U=y +CONFIG_TOUCHIRQ_UPDATE_QOS=y +CONFIG_TOUCHPANEL_NEW_SET_IRQ_WAKE=y +CONFIG_OPLUS_TP_APK=y +CONFIG_TOUCHPANEL_ALGORITHM=y +#endif /* OPLUS_FEATURE_TP_BASIC */ + +CONFIG_OPLUS_TRIKEY=y +CONFIG_OPLUS_TRIKEY_MAIN=y +CONFIG_OPLUS_TRIKEY_HALL=y +CONFIG_IST_UP=y +CONFIG_IST_DOWN=y +CONFIG_MXM_UP=y +CONFIG_MXM_DOWN=y +#ifdef OPLUS_FEATURE_TP_BASIC +CONFIG_OPLUS_FW_UPDATE=y +CONFIG_TOUCHPANEL_NOVA=y +CONFIG_TOUCHPANEL_NOVA_NT36523_NOFLASH=y +CONFIG_TOUCHPANEL_NT_PEN_SUPPORT=y +CONFIG_TOUCHPANEL_NT_DIGITALNOISE_TEST=y +#endif /*OPLUS_FEATURE_TP_BASIC*/ + +#ifdef OPLUS_FEATURE_TP_BASIC +CONFIG_COLOR_CTRL=y +#endif /* OPLUS_FEATURE_TP_BASIC */ +#ifdef OPLUS_FEATURE_TP_BASIC +CONFIG_COLOR_CTRL_V2=y +#endif /* OPLUS_FEATURE_TP_BASIC */ CONFIG_INPUT_MISC=y CONFIG_INPUT_QPNP_POWER_ON=y CONFIG_INPUT_QTI_HAPTICS=y @@ -365,6 +435,7 @@ CONFIG_INPUT_UINPUT=y # CONFIG_LEGACY_PTYS is not set # CONFIG_DEVMEM is not set CONFIG_SERIAL_MSM_GENI=y +CONFIG_SERIAL_MSM_GENI_CONSOLE=y CONFIG_SERIAL_MSM_GENI_HALF_SAMPLING=y CONFIG_HW_RANDOM=y CONFIG_HW_RANDOM_MSM_LEGACY=y @@ -390,11 +461,43 @@ CONFIG_POWER_RESET_QCOM=y CONFIG_POWER_RESET_XGENE=y CONFIG_POWER_RESET_SYSCON=y CONFIG_QPNP_SMB5=y -CONFIG_SMB1390_CHARGE_PUMP_PSY=y -CONFIG_SMB1355_SLAVE_CHARGER=y -CONFIG_QPNP_QNOVO5=y +#ifdef OPLUS_FEATURE_CHG_BASIC//tongfeng.Huang@ProDrv.CHG,add 2019/06/22 for charger +CONFIG_OPLUS_SM8250_CHARGER=y +CONFIG_OPLUS_CHIP_SOC_NODE=y CONFIG_QPNP_FG_GEN4=y -CONFIG_HL6111R=y +CONFIG_OPLUS_CHARGER_WIRELESS_PEN=y +CONFIG_OPLUS_CHARGER_WIRELESS_RA9530=y +#else +#CONFIG_SMB1390_CHARGE_PUMP_PSY=y +#CONFIG_SMB1355_SLAVE_CHARGER=y +#CONFIG_QPNP_QNOVO5=y +#CONFIG_QPNP_FG_GEN4=y +#endif +#ifdef OPLUS_FEATURE_CHG_BASIC +CONFIG_OPLUS_SHORT_HW_CHECK=y +CONFIG_OPLUS_SHORT_USERSPACE=y +CONFIG_OPLUS_SHIP_MODE_SUPPORT=y +CONFIG_OPLUS_SMART_CHARGER_SUPPORT=y +CONFIG_OPLUS_CALL_MODE_SUPPORT=y +CONFIG_OPLUS_SHORT_C_BATT_CHECK=y +CONFIG_OPLUS_CHECK_CHARGERID_VOLT=y +CONFIG_OPLUS_SHORT_IC_CHECK=y +CONFIG_SONY_FF=y +CONFIG_HID_BETOP_FF=y +CONFIG_HID_PLAYSTATION=y +CONFIG_PLAYSTATION_FF=y +#endif +#ifndef OPLUS_FEATURE_CHG_BASIC//tongfeng.Huang@ProDrv.CHG,add 2019/12/22 for charger +#CONFIG_HL6111R=y +#endif + +#ifdef OPLUS_FEATURE_CHG_BASIC +CONFIG_INPUT_JOYSTICK=y +CONFIG_JOYSTICK_XPAD=y +CONFIG_JOYSTICK_XPAD_FF=y +CONFIG_JOYSTICK_XPAD_LEDS=y +#endif /* OPLUS_FEATURE_CHG_BASIC */ + CONFIG_THERMAL=y CONFIG_THERMAL_WRITABLE_TRIPS=y CONFIG_THERMAL_GOV_USER_SPACE=y @@ -442,6 +545,9 @@ CONFIG_DVB_MPQ_SW=y CONFIG_VIDEO_V4L2_VIDEOBUF2_CORE=y CONFIG_I2C_RTC6226_QCA=y CONFIG_DRM=y +#ifdef VENDOR_EDIT +CONFIG_DRM_MSM=y +#endif /* VENDOR_EDIT */ CONFIG_DRM_LONTIUM_LT9611UXC=y CONFIG_BACKLIGHT_LCD_SUPPORT=y CONFIG_BACKLIGHT_CLASS_DEVICE=y @@ -570,8 +676,10 @@ CONFIG_MSM_QMP=y CONFIG_IOMMU_IO_PGTABLE_FAST=y CONFIG_ARM_SMMU=y CONFIG_QCOM_LAZY_MAPPING=y -CONFIG_IOMMU_DEBUG=y -CONFIG_IOMMU_TESTS=y +#ifdef VENDOR_EDIT +#CONFIG_IOMMU_DEBUG=y +#CONFIG_IOMMU_TESTS=y +#endif CONFIG_RPMSG_CHAR=y CONFIG_RPMSG_QCOM_GLINK_SMEM=y CONFIG_RPMSG_QCOM_GLINK_SPSS=y @@ -673,11 +781,13 @@ CONFIG_ESOC_CLIENT=y CONFIG_ESOC_MDM_4x=y CONFIG_ESOC_MDM_DRV=y CONFIG_SENSORS_SSC=y +CONFIG_SENSORS_SIMULATED_HALL=y CONFIG_QCOM_KGSL=y CONFIG_EXT4_FS=y CONFIG_EXT4_FS_POSIX_ACL=y CONFIG_EXT4_FS_SECURITY=y CONFIG_EXT4_ENCRYPTION=y +CONFIG_OPLUS_FEATURE_OEXT4=y CONFIG_F2FS_FS=y CONFIG_F2FS_FS_SECURITY=y CONFIG_FS_ENCRYPTION_INLINE_CRYPT=y @@ -691,6 +801,13 @@ CONFIG_OVERLAY_FS=y CONFIG_INCREMENTAL_FS=y CONFIG_MSDOS_FS=y CONFIG_VFAT_FS=y +#ifdef OPLUS_FEATURE_EXFAT_SUPPORT +CONFIG_NLS_UTF8=y +CONFIG_EXFAT_FS=y +# endif +#ifdef OPLUS_FEATURE_EMMC_SDCARD_OPTIMIZE +CONFIG_EMMC_SDCARD_OPTIMIZE=y +#endif CONFIG_TMPFS=y CONFIG_TMPFS_POSIX_ACL=y CONFIG_ECRYPT_FS=y @@ -737,3 +854,283 @@ CONFIG_CORESIGHT_HWEVENT=y CONFIG_CORESIGHT_DUMMY=y CONFIG_CORESIGHT_REMOTE_ETM=y CONFIG_CORESIGHT_TGU=y +#ifdef OPLUS_SYSTEM_KERNEL +CONFIG_OPLUS_COMMON_SOFT=y +CONFIG_OPLUS_DEVICE_IFNO=y +CONFIG_OPLUS_RF_CABLE_MONITOR=y +CONFIG_RECORD_MDMRST=y +#endif +# ifdef OPLUS_FEATURE_POWERINFO_STANDBY +CONFIG_OPLUS_WAKELOCK_PROFILER=y +#endif /* OPLUS_FEATURE_POWERINFO_STANDBY */ +# ifdef VENDOR_EDIT +CONFIG_CS_F61_NDT=y +# endif /* VENDOR_EDIT */ + +#ifdef OPLUS_FEATURE_INPUT_BOOST_V4 +# CONFIG_OPLUS_FEATURE_INPUT_BOOST_V4 is not set +#endif + +#ifdef OPLUS_SYSTEM_KERNEL +#all system oplus feature writer here +CONFIG_OPLUS_FEATURE_UBOOT_LOG=y +CONFIG_DETECT_HUNG_TASK=y +CONFIG_OPLUS_FEATURE_HUNG_TASK_ENHANCE=y +CONFIG_DEFAULT_HUNG_TASK_TIMEOUT=60 +CONFIG_OPLUS_FEATURE_FEEDBACK=y +CONFIG_OPLUS_FEATURE_OPROJECT=y +CONFIG_OPLUS_FEATURE_CMDLINE=y +CONFIG_OPLUS_FEATURE_PROJECTINFO=y +CONFIG_OPLUS_FEATURE_PHOENIX=y +CONFIG_OPLUS_FEATURE_PHOENIX_REBOOT_SPEED=y +CONFIG_OPLUS_FEATURE_KMSG_WB=y +CONFIG_OPLUS_FEATURE_SHUTDOWN_SPEED=y +CONFIG_OPLUS_FEATURE_OLC=y +CONFIG_KPROBES=y +CONFIG_KRETPROBES=y +CONFIG_OPLUS_FEATURE_FDLEAK_CHECK=y +CONFIG_OPLUS_FEATURE_DUMP_DEVICE_INFO=y +#add for qcom minidump customized +CONFIG_OPLUS_FEATURE_QCOM_MINIDUMP_ENHANCE=y +# Add for shutdown detect +CONFIG_OPLUS_FEATURE_SHUTDOWN_DETECT=y +#add slabtrace function +#CONFIG_OPLUS_FEATURE_SLABTRACE_DEBUG=y +#endif +#ifdef OPLUS_FEATURE_QCOM_PMICWD +#Add for qcom pmic watchdog +CONFIG_OPLUS_FEATURE_QCOM_PMICWD=y +#endif +#ifdef OPLUS_FEATURE_FINGERPRINT +CONFIG_OPLUS_FINGERPRINT=y +CONFIG_OPLUS_FINGERPRINT_QCOM=y +CONFIG_OPLUS_FINGERPRINT_GOODIX_OPTICAL=y +CONFIG_OPLUS_FINGERPRINT_JIIOV_OPTICAL=y +#endif +CONFIG_OPLUS_FINGERPRINT_GKI_DISABLE=y + +#ifdef OPLUS_FEATURE_SECURITY_COMMON +CONFIG_OPLUS_SECURE=y +CONFIG_OPLUS_SECURE_QCOM=y +CONFIG_OPLUS_SECURE_COMMON=y +#endif /* OPLUS_FEATURE_SECURITY_COMMON */ + +#ifdef OPLUS_FEATURE_HANS_FREEZE +CONFIG_OPLUS_HANS=y +#endif /*OPLUS_FEATURE_HANS_FREEZE*/ +#ifdef VENDOR_EDIT//Qingjun.Wang@BSP.Haptic,add 2020/03/17 for vib aw8697 +CONFIG_AW8697_HAPTIC=y +CONFIG_HAPTIC_FEEDBACK=y +#endif +#ifdef OPLUS_FEATURE_HEALTHINFO +CONFIG_OPLUS_MEM_MONITOR=y +CONFIG_FG_TASK_UID=y +CONFIG_OPLUS_HEALTHINFO=y +CONFIG_SLUB_DEBUG=y +#endif /*OPLUS_FEATURE_HEALTHINFO*/ +#ifdef OPLUS_FEATURE_HEALTHINFO +CONFIG_OPLUS_JANK_INFO=y +#endif /* OPLUS_FEATURE_HEALTHINFO */ + +#ifdef OPLUS_FEATURE_SCHED_ASSIST +CONFIG_OPLUS_FEATURE_AUDIO_OPT=y +#endif + +#ifdef OPLUS_FEATURE_ZRAM_OPT +CONFIG_OPLUS_ZRAM_OPT=y +CONFIG_CRYPTO_LZ4=y +CONFIG_PGTABLE_MAPPING=y +CONFIG_CRYPTO_ZSTD=y +#endif + +#ifdef OPLUS_FEATURE_MULTI_KSWAPD +CONFIG_OPLUS_MULTI_KSWAPD=y +CONFIG_KSWAPD_UNBIND_MAX_CPU=y +#endif + +#ifdef VENDOR_EDIT +CONFIG_REGULATOR_PM8008=y + +#ifdef OPLUS_FEATURE_DUMPDEVICE +CONFIG_PSTORE=y +CONFIG_PSTORE_CONSOLE=y +CONFIG_PSTORE_PMSG=y +CONFIG_PSTORE_RAM=y +#endif + +CONFIG_OPLUS_FEATURE_EROFS=y +CONFIG_EROFS_FS=y + +#ifdef OPLUS_FEATURE_IOMONITOR +CONFIG_IOMONITOR=y +#CONFIG_IOMONITOR_WITH_F2FS=n +#endif /*OPLUS_FEATURE_IOMONITOR*/ + +CONFIG_OPLUS_FEATURE_PMIC_MONITOR=y + +CONFIG_OPLUS_FEATURE_OF2FS=y +CONFIG_OPLUS_FEATURE_PANIC_FLUSH=y +CONFIG_F2FS_BD_STAT=y +#CONFIG_F2FS_GRADING_SSR is not set + +#ifdef OPLUS_FEATURE_LOWMEM_DBG +CONFIG_OPLUS_FEATURE_LOWMEM_DBG=y +#endif /* OPLUS_FEATURE_LOWMEM_DBG */ + +#ifdef OPLUS_FEATURE_SCHED_ASSIST +CONFIG_BLK_WBT_SQ=y +CONFIG_BLK_WBT=y +CONFIG_OPLUS_FEATURE_UXIO_FIRST=y +#CONFIG_OPLUS_FEATURE_SCHED_SPREAD=y +#endif /*OPLUS_FEATURE_SCHED_ASSIST*/ + +#ifdef OPLUS_FEATURE_MEMLEAK_DETECT +CONFIG_KMALLOC_DEBUG=y +CONFIG_VMALLOC_DEBUG=y +CONFIG_DUMP_TASKS_MEM=y +#endif /*OPLUS_FEATURE_MEMLEAK_DETECT*/ + +#ifdef OPLUS_FEATURE_MEMLEAK_DETECT +CONFIG_SVELTE=y +#endif + +#ifdef OPLUS_FEATURE_SENSOR_DRIVER +CONFIG_OPLUS_SENSOR_FB_QC=y +#endif + +#ifdef VEDOR_EDIT +CONFIG_OPLUS_FEATURE_RECORD_MDMRST=y +#endif + +#ifdef OPLUS_ARCH_EXTENDS +CONFIG_OPLUS_FEATURE_MM_FEEDBACK=y +#endif + +#ifdef VENDOR_EDIT +CONFIG_OPLUS_FEATURE_MIDAS=y +#endif + +#ifdef CONFIG_OPLUS_FEATURE_BINDER_STATS_ENABLE +CONFIG_OPLUS_FEATURE_BINDER_STATS_ENABLE=y +#endif + +#ifdef OPLUS_FEATURE_ACM +CONFIG_OPLUS_FEATURE_ACM=y +CONFIG_OPLUS_FEATURE_ACM_LOGGING=y +#endif /* OPLUS_FEATURE_ACM */ + +#ifdef OPLUS_BUG_STABILITY +CONFIG_HARDEN_BRANCH_PREDICTOR=y +#endif + +#add by shaojun.zou for cobuck opt 2021/08/16 +CONFIG_SCHED_WALT_COBUCK=y + +#ifdef OPLUS_FEATURE_SIM_DETECT +CONFIG_SIM_DETECT=y +#endif + +#ifdef OPLUS_FEATURE_SIM_DETECT +CONFIG_OEM_QMI=y +#endif + +CONFIG_OPLUS_FEATURE_THEIA=y +##endif /* OPLUS_FEATURE_THEIA */ + +#ifdef OPLUS_FEATURE_ESIM +CONFIG_OPLUS_GPIO=y +#endif + +#ifdef OPLUS_FEATURE_SAUPWK +CONFIG_OPLUS_FEATURE_SAUPWK=y +#endif /* OPLUS_FEATURE_SAUPWK */ + +#ifdef OPLUS_FEATURE_RT_INFO +CONFIG_OPLUS_FEATURE_RT_INFO=n +#endif + +#ifdef OPLUS_FEATURE_TPP +#jacky.ho@optimization add for tpp module +CONFIG_OPLUS_FEATURE_TPP=y +#endif /* OPLUS_FEATURE_TPP */ + +#ifdef OPLUS_FEATURE_IM +#ted.lin@optimization add for im module +CONFIG_OPLUS_FEATURE_IM=y +#endif /* OPLUS_FEATURE_IM */ + +#ifdef OPLUS_FEATURE_ION_BOOSTPOOL +CONFIG_OPLUS_ION_BOOSTPOOL=y +#endif /* OPLUS_FEATURE_ION_BOOSTPOOL */ + +#ifdef OPLUS_FEATURE_TPD +CONFIG_OPLUS_FEATURE_TPD=y +#endif +#ifdef OPLUS_FEATURE_SENSOR +CONFIG_SSC_INTERACTIVE=y +#endif + +#ifdef OPLUS_FEATURE_WIFI_SLA +#todo: need to change to m when GKI +CONFIG_OPLUS_FEATURE_WIFI_SLA=y +#endif /* OPLUS_FEATURE_WIFI_SLA */ + +#ifdef OPLUS_FEATURE_WIFI_ROUTERBOOST +CONFIG_OPLUS_FEATURE_WIFI_ROUTERBOOST=m +#endif /* OPLUS_FEATURE_WIFI_ROUTERBOOST */ + +CONFIG_DYNAMIC_TUNNING_SWAPPINESS=y + +#ifdef OPLUS_FEATURE_DATA_EVAL +CONFIG_OPLUS_FEATURE_DATA_EVAL=y +#endif /* OPLUS_FEATURE_DATA_VAL */ + +#ifdef OPLUS_FEATURE_DATA_LIMIT +CONFIG_IFB=y +CONFIG_NET_SCH_MULTIQ=y +CONFIG_NET_SCH_NETEM=y +CONFIG_CLS_U32_MARK=y +CONFIG_NET_CLS_FLOW=y +CONFIG_NET_EMATCH_CMP=y +CONFIG_NET_EMATCH_NBYTE=y +CONFIG_NET_EMATCH_META=y +CONFIG_NET_EMATCH_TEXT=y +CONFIG_NET_ACT_GACT=y +CONFIG_NET_ACT_MIRRED=y +CONFIG_NET_ACT_SKBEDIT=y +#endif /* OPLUS_FEATURE_DATA_LIMIT */ + +#CONFIG_NANDSWAP=y +#CONFIG_NANDSWAP_DEBUG=y +CONFIG_FRAME_WARN=4096 +#ifdef OPLUS_FEATURE_HYBRIDSWAP +CONFIG_HYBRIDSWAP=y +CONFIG_HYBRIDSWAP_SWAPD=y +CONFIG_HYBRIDSWAP_CORE=y +#endif + +#ifdef OPLUS_FEATURE_DNS_HOOK +CONFIG_OPLUS_FEATURE_DNS_HOOK=y +#endif /* OPLUS_FEATURE_DNS_HOOK */ + +#ifdef OPLUS_FEATURE_STATS_CALC +CONFIG_OPLUS_FEATURE_STATS_CALC=y +#endif /* OPLUS_FEATURE_STATS_CALC */ +CONFIG_OPLUS_BINDER_STRATEGY=n + +#ifdef OPLUS_FEATURE_MDMFEATURE +CONFIG_OPLUS_FEATURE_MDMFEATURE=y +#endif + +#ifdef OPLUS_FEATURE_GAME_OPT +CONFIG_OPLUS_FEATURE_GAME_OPT=y +#endif + +#ifdef Multi-gen LRU +CONFIG_LRU_GEN=y +CONFIG_LRU_GEN_ENABLED=n +CONFIG_LRU_GEN_STATS=n +#endif +CONFIG_OPLUS_FEATURE_CPU_JANKINFO=y + +CONFIG_CRYPTO_CHACHA20POLY1305=y diff --git a/arch/arm64/configs/vendor/kona_defconfig b/arch/arm64/configs/vendor/kona_defconfig index f6dade1f20b7..406de899c463 100644 --- a/arch/arm64/configs/vendor/kona_defconfig +++ b/arch/arm64/configs/vendor/kona_defconfig @@ -4,6 +4,7 @@ CONFIG_HIGH_RES_TIMERS=y CONFIG_PREEMPT=y CONFIG_IRQ_TIME_ACCOUNTING=y CONFIG_SCHED_WALT=y +CONFIG_MMAP_LOCK_OPT=y CONFIG_TASKSTATS=y CONFIG_TASK_XACCT=y CONFIG_TASK_IO_ACCOUNTING=y @@ -22,11 +23,18 @@ CONFIG_BLK_CGROUP=y CONFIG_DEBUG_BLK_CGROUP=y CONFIG_CGROUP_FREEZER=y CONFIG_CPUSETS=y +#ifdef OPLUS_FEATURE_TASK_CPUSTATS +CONFIG_OPLUS_SCHED=y +CONFIG_OPLUS_CTP=y +#endif /* OPLUS_FEATURE_TASK_CPUSTATS */ CONFIG_CGROUP_CPUACCT=y CONFIG_CGROUP_BPF=y CONFIG_CGROUP_DEBUG=y CONFIG_SCHED_CORE_CTL=y CONFIG_NAMESPACES=y +#ifdef OPLUS_FEATURE_UID_PERF +CONFIG_OPLUS_FEATURE_UID_PERF=y +#endif # CONFIG_PID_NS is not set CONFIG_SCHED_AUTOGROUP=y CONFIG_SCHED_TUNE=y @@ -53,7 +61,7 @@ CONFIG_SCHED_MC=y CONFIG_NR_CPUS=8 CONFIG_SECCOMP=y CONFIG_OKL4_GUEST=y -# CONFIG_UNMAP_KERNEL_AT_EL0 is not set +CONFIG_UNMAP_KERNEL_AT_EL0=y CONFIG_ARM64_SSBD=y CONFIG_PRINT_VMEMLAYOUT=y CONFIG_ARMV8_DEPRECATED=y @@ -63,6 +71,7 @@ CONFIG_SETEND_EMULATION=y CONFIG_ARM64_SW_TTBR0_PAN=y # CONFIG_ARM64_VHE is not set CONFIG_RANDOMIZE_BASE=y +CONFIG_BUILD_ARM64_KERNEL_COMPRESSION_GZIP=n CONFIG_CMDLINE="cgroup_disable=pressure" CONFIG_CMDLINE_EXTEND=y CONFIG_BUILD_ARM64_UNCOMPRESSED_KERNEL=y @@ -83,6 +92,9 @@ CONFIG_CPU_FREQ_GOV_ONDEMAND=y CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y CONFIG_CPU_BOOST=y CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y +#ifdef OPLUS_BUG_STABILITY +CONFIG_CPU_FREQ_STAT=y +#endif CONFIG_ARM_QCOM_CPUFREQ_HW=y CONFIG_MSM_TZ_LOG=y CONFIG_ARM64_CRYPTO=y @@ -109,7 +121,10 @@ CONFIG_CFQ_GROUP_IOSCHED=y CONFIG_IOSCHED_BFQ=y CONFIG_BFQ_GROUP_IOSCHED=y # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set -CONFIG_MEMORY_HOTPLUG=y +#ifdef OPLUS_DEBUG_STABILITY +##CONFIG_MEMORY_HOTPLUG=y +# CONFIG_MEMORY_HOTPLUG is not set +# endif CONFIG_MEMORY_HOTPLUG_DEFAULT_ONLINE=y CONFIG_MEMORY_HOTPLUG_MOVABLE_NODE=y CONFIG_MEMORY_HOTREMOVE=y @@ -295,6 +310,10 @@ CONFIG_MHI_NETDEV=y CONFIG_MHI_UCI=y CONFIG_MHI_SATELLITE=y CONFIG_ZRAM=y +#ifdef OPLUS_FEATURE_ZRAM_WRITEBACK +#CONFIG_ZRAM_WRITEBACK=y +#CONFIG_ZWB_HANDLE=y +#endif /* OPLUS_FEATURE_ZRAM_WRITEBACK */ CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_LOOP_MIN_COUNT=16 CONFIG_BLK_DEV_RAM=y @@ -318,6 +337,15 @@ CONFIG_SCSI_UFSHCD=y CONFIG_SCSI_UFSHCD_PLATFORM=y CONFIG_SCSI_UFS_QCOM=y CONFIG_SCSI_UFSHCD_CMD_LOGGING=y +#ifdef OPLUS_FEATURE_UFSPLUS +CONFIG_UFSFEATURE=y +# CONFIG_UFSHPB is not set +CONFIG_UFSTW=y +CONFIG_UFSTW_IGNORE_GUARANTEE_BIT=y +CONFIG_UFSTW_BOOT_ENABLED=y +CONFIG_UFSHID=y +CONFIG_UFSHID_POC=y +#endif /*OPLUS_FEATURE_UFSPLUS*/ CONFIG_SCSI_UFS_CRYPTO=y CONFIG_SCSI_UFS_CRYPTO_QTI=y CONFIG_MD=y @@ -369,7 +397,47 @@ CONFIG_TABLET_USB_HANWANG=y CONFIG_TABLET_USB_KBTAB=y CONFIG_INPUT_TOUCHSCREEN=y CONFIG_TOUCHSCREEN_FTS=y -CONFIG_TOUCHSCREEN_NT36XXX=y +#ifdef OPLUS_FEATURE_TP_BASIC +CONFIG_TOUCHPANEL_SAMSUNG_S6SY791=y +CONFIG_TOUCHPANEL_SAMSUNG_S6SY792=y +CONFIG_TOUCHPANEL_SAMSUNG_S6SY771=y +CONFIG_TOUCHPANEL_SYNAPTICS=y +CONFIG_TOUCHPANEL_SYNAPTICS_TCM_ONCELL=y +CONFIG_TOUCHPANEL_SYNAPTICS_S3706=y +CONFIG_TOUCHPANEL_SAMSUNG=y +CONFIG_TOUCHPANEL_OPLUS=y +CONFIG_TOUCHPANEL_GOODIX=y +CONFIG_TOUCHPANEL_GOODIX_GT9886=y +CONFIG_TOUCHPANEL_FOCAL=y +CONFIG_TOUCHPANEL_FOCAL_FT3658U=y +CONFIG_TOUCHIRQ_UPDATE_QOS=y +CONFIG_TOUCHPANEL_NEW_SET_IRQ_WAKE=y +CONFIG_OPLUS_TP_APK=y +CONFIG_TOUCHPANEL_ALGORITHM=y +CONFIG_TOUCHPANEL_NOVA=y +CONFIG_TOUCHPANEL_NOVA_NT36523_NOFLASH=y +CONFIG_TOUCHPANEL_NT_PEN_SUPPORT=y +CONFIG_TOUCHPANEL_NT_DIGITALNOISE_TEST=y +#endif /* OPLUS_FEATURE_TP_BASIC */ + +CONFIG_OPLUS_TRIKEY=y +CONFIG_OPLUS_TRIKEY_MAIN=y +CONFIG_OPLUS_TRIKEY_HALL=y +CONFIG_IST_UP=y +CONFIG_IST_DOWN=y +CONFIG_MXM_UP=y +CONFIG_MXM_DOWN=y +#ifdef OPLUS_FEATURE_TP_BASIC +CONFIG_OPLUS_FW_UPDATE=y +#endif /*OPLUS_FEATURE_TP_BASIC*/ + +#ifdef OPLUS_FEATURE_TP_BASIC +CONFIG_COLOR_CTRL=y +#endif /* OPLUS_FEATURE_TP_BASIC */ +#ifdef OPLUS_FEATURE_TP_BASIC +CONFIG_COLOR_CTRL_V2=y +#endif /* OPLUS_FEATURE_TP_BASIC */ +#CONFIG_TOUCHSCREEN_NT36XXX=y CONFIG_INPUT_MISC=y CONFIG_INPUT_QPNP_POWER_ON=y CONFIG_INPUT_QTI_HAPTICS=y @@ -407,11 +475,43 @@ CONFIG_POWER_RESET_QCOM=y CONFIG_POWER_RESET_XGENE=y CONFIG_POWER_RESET_SYSCON=y CONFIG_QPNP_SMB5=y -CONFIG_SMB1390_CHARGE_PUMP_PSY=y -CONFIG_SMB1355_SLAVE_CHARGER=y -CONFIG_QPNP_QNOVO5=y +#ifdef OPLUS_FEATURE_CHG_BASIC//tongfeng.Huang@ProDrv.CHG,add 2019/06/22 for charger +CONFIG_OPLUS_SM8250_CHARGER=y +CONFIG_OPLUS_CHIP_SOC_NODE=y CONFIG_QPNP_FG_GEN4=y -CONFIG_HL6111R=y +CONFIG_OPLUS_CHARGER_WIRELESS_PEN=y +CONFIG_OPLUS_CHARGER_WIRELESS_RA9530=y +#else +#CONFIG_SMB1390_CHARGE_PUMP_PSY=y +#CONFIG_SMB1355_SLAVE_CHARGER=y +#CONFIG_QPNP_QNOVO5=y +#CONFIG_QPNP_FG_GEN4=y +#endif +#ifdef OPLUS_FEATURE_CHG_BASIC +CONFIG_OPLUS_SHORT_HW_CHECK=y +CONFIG_OPLUS_SHORT_USERSPACE=y +CONFIG_OPLUS_SHIP_MODE_SUPPORT=y +CONFIG_OPLUS_SMART_CHARGER_SUPPORT=y +CONFIG_OPLUS_CALL_MODE_SUPPORT=y +CONFIG_OPLUS_SHORT_C_BATT_CHECK=y +CONFIG_OPLUS_CHECK_CHARGERID_VOLT=y +CONFIG_OPLUS_SHORT_IC_CHECK=y +CONFIG_SONY_FF=y +CONFIG_HID_BETOP_FF=y +CONFIG_HID_PLAYSTATION=y +CONFIG_PLAYSTATION_FF=y +#endif +#ifndef OPLUS_FEATURE_CHG_BASIC//tongfeng.Huang@ProDrv.CHG,add 2019/12/22 for charger +#CONFIG_HL6111R=y +#endif + +#ifdef OPLUS_FEATURE_CHG_BASIC +CONFIG_INPUT_JOYSTICK=y +CONFIG_JOYSTICK_XPAD=y +CONFIG_JOYSTICK_XPAD_FF=y +CONFIG_JOYSTICK_XPAD_LEDS=y +#endif /* OPLUS_FEATURE_CHG_BASIC */ + CONFIG_THERMAL=y CONFIG_THERMAL_WRITABLE_TRIPS=y CONFIG_THERMAL_GOV_USER_SPACE=y @@ -459,6 +559,9 @@ CONFIG_DVB_MPQ_SW=y CONFIG_VIDEO_V4L2_VIDEOBUF2_CORE=y CONFIG_I2C_RTC6226_QCA=y CONFIG_DRM=y +#ifdef VENDOR_EDIT +CONFIG_DRM_MSM=y +#endif /* VENDOR_EDIT */ CONFIG_DRM_LONTIUM_LT9611UXC=y CONFIG_BACKLIGHT_LCD_SUPPORT=y CONFIG_BACKLIGHT_CLASS_DEVICE=y @@ -706,6 +809,7 @@ CONFIG_ESOC_MDM_4x=y CONFIG_ESOC_MDM_DRV=y CONFIG_ESOC_MDM_DBG_ENG=y CONFIG_SENSORS_SSC=y +CONFIG_SENSORS_SIMULATED_HALL=y CONFIG_QCOM_KGSL=y CONFIG_EXT4_FS=y CONFIG_EXT4_FS_POSIX_ACL=y @@ -724,6 +828,13 @@ CONFIG_OVERLAY_FS=y CONFIG_INCREMENTAL_FS=y CONFIG_MSDOS_FS=y CONFIG_VFAT_FS=y +#ifdef OPLUS_FEATURE_EXFAT_SUPPORT +CONFIG_NLS_UTF8=y +CONFIG_EXFAT_FS=y +# endif +#ifdef OPLUS_FEATURE_EMMC_SDCARD_OPTIMIZE +CONFIG_EMMC_SDCARD_OPTIMIZE=y +#endif CONFIG_TMPFS=y CONFIG_TMPFS_POSIX_ACL=y CONFIG_EFIVAR_FS=y @@ -754,7 +865,7 @@ CONFIG_CRYPTO_DEV_QCOM_ICE=y CONFIG_XZ_DEC=y CONFIG_PRINTK_TIME=y CONFIG_DYNAMIC_DEBUG=y -CONFIG_DEBUG_CONSOLE_UNHASHED_POINTERS=y +# CONFIG_DEBUG_CONSOLE_UNHASHED_POINTERS is not set CONFIG_DEBUG_MODULE_LOAD_INFO=y CONFIG_DEBUG_INFO=y CONFIG_PAGE_OWNER=y @@ -822,3 +933,286 @@ CONFIG_CORESIGHT_HWEVENT=y CONFIG_CORESIGHT_DUMMY=y CONFIG_CORESIGHT_REMOTE_ETM=y CONFIG_CORESIGHT_TGU=y +#ifdef OPLUS_SYSTEM_KERNEL +#/*Add for oplus project*/ +CONFIG_OPLUS_COMMON_SOFT=y +CONFIG_OPLUS_DEVICE_IFNO=y +CONFIG_OPLUS_RF_CABLE_MONITOR=y +CONFIG_RECORD_MDMRST=y +#endif +#ifdef OPLUS_FEATURE_POWERINFO_STANDBY +CONFIG_OPLUS_WAKELOCK_PROFILER=y +#endif /* OPLUS_FEATURE_POWERINFO_STANDBY */ +# ifdef VENDOR_EDIT +CONFIG_CS_F61_NDT=y +# endif /* VENDOR_EDIT */ + +#ifdef OPLUS_FEATURE_INPUT_BOOST_V4 +# CONFIG_OPLUS_FEATURE_INPUT_BOOST_V4 is not set +#endif + +#ifdef OPLUS_SYSTEM_KERNEL +#all system oplus feature writer here +CONFIG_OPLUS_FEATURE_UBOOT_LOG=y +CONFIG_DETECT_HUNG_TASK=y +CONFIG_OPLUS_FEATURE_HUNG_TASK_ENHANCE=y +CONFIG_DEFAULT_HUNG_TASK_TIMEOUT=60 +CONFIG_OPLUS_FEATURE_FEEDBACK=y +CONFIG_OPLUS_FEATURE_OPROJECT=y +CONFIG_OPLUS_FEATURE_CMDLINE=y +CONFIG_OPLUS_FEATURE_PROJECTINFO=y +CONFIG_OPLUS_FEATURE_PHOENIX=y +CONFIG_OPLUS_FEATURE_PHOENIX_REBOOT_SPEED=y +CONFIG_OPLUS_FEATURE_KMSG_WB=y +CONFIG_OPLUS_FEATURE_SHUTDOWN_SPEED=y +CONFIG_OPLUS_FEATURE_OLC=y +CONFIG_OPLUS_FEATURE_FDLEAK_CHECK=y +CONFIG_OPLUS_FEATURE_DUMP_DEVICE_INFO=y +#add for qcom minidump customized +CONFIG_OPLUS_FEATURE_QCOM_MINIDUMP_ENHANCE=y +#Add for shutdown detect +CONFIG_OPLUS_FEATURE_SHUTDOWN_DETECT=y +#add slabtrace function +CONFIG_OPLUS_FEATURE_SLABTRACE_DEBUG=y +#endif +#ifdef OPLUS_FEATURE_QCOM_PMICWD +#Add for qcom pmic watchdog +CONFIG_OPLUS_FEATURE_QCOM_PMICWD=y +#endif +#ifdef OPLUS_FEATURE_FINGERPRINT +CONFIG_OPLUS_FINGERPRINT=y +CONFIG_OPLUS_FINGERPRINT_QCOM=y +CONFIG_OPLUS_FINGERPRINT_GOODIX_OPTICAL=y +CONFIG_OPLUS_FINGERPRINT_JIIOV_OPTICAL=y +#endif +CONFIG_OPLUS_FINGERPRINT_GKI_DISABLE=y + +#ifdef OPLUS_FEATURE_SECURITY_COMMON +CONFIG_OPLUS_SECURE=y +CONFIG_OPLUS_SECURE_QCOM=y +CONFIG_OPLUS_SECURE_COMMON=y +#endif /* OPLUS_FEATURE_SECURITY_COMMON */ + +#ifdef OPLUS_FEATURE_HANS_FREEZE +CONFIG_OPLUS_HANS=y +#endif /*OPLUS_FEATURE_HANS_FREEZE*/ +#ifdef VENDOR_EDIT//Qingjun.Wang@BSP.Haptic,add 2020/03/17 for vib aw8697 +CONFIG_AW8697_HAPTIC=y +CONFIG_HAPTIC_FEEDBACK=y +#endif +#ifdef OPLUS_FEATURE_HEALTHINFO +CONFIG_OPLUS_MEM_MONITOR=y +CONFIG_FG_TASK_UID=y +CONFIG_OPLUS_HEALTHINFO=y +CONFIG_SLUB_DEBUG=y +#endif /* OPLUS_FEATURE_HEALTHINFO */ +#ifdef OPLUS_FEATURE_HEALTHINFO +CONFIG_OPLUS_JANK_INFO=y +#endif /* OPLUS_FEATURE_HEALTHINFO */ + +#ifdef OPLUS_FEATURE_SCHED_ASSIST +CONFIG_OPLUS_FEATURE_AUDIO_OPT=y +#endif + +#ifdef OPLUS_FEATURE_ZRAM_OPT +CONFIG_OPLUS_ZRAM_OPT=y +CONFIG_CRYPTO_LZ4=y +CONFIG_PGTABLE_MAPPING=y +CONFIG_CRYPTO_ZSTD=y +#endif + +#ifdef OPLUS_FEATURE_MULTI_KSWAPD +CONFIG_OPLUS_MULTI_KSWAPD=y +CONFIG_KSWAPD_UNBIND_MAX_CPU=y +#endif + +#ifdef VENDOR_EDIT +CONFIG_REGULATOR_PM8008=y + +#ifdef OPLUS_FEATURE_DUMPDEVICE +#Add for dump device info +CONFIG_PSTORE=y +CONFIG_PSTORE_CONSOLE=y +CONFIG_PSTORE_PMSG=y +CONFIG_PSTORE_RAM=y +#endif + +CONFIG_OPLUS_FEATURE_EROFS=y +CONFIG_EROFS_FS=y + +#ifdef OPLUS_FEATURE_IOMONITOR +CONFIG_IOMONITOR=y +#CONFIG_IOMONITOR_WITH_F2FS=n +#endif /*OPLUS_FEATURE_IOMONITOR*/ + +CONFIG_OPLUS_FEATURE_PMIC_MONITOR=y + +CONFIG_OPLUS_FEATURE_OF2FS=y +CONFIG_OPLUS_FEATURE_PANIC_FLUSH=y +CONFIG_OPLUS_FEATURE_OEXT4=y +CONFIG_F2FS_BD_STAT=y +#CONFIG_F2FS_GRADING_SSR is not set + +#ifdef OPLUS_FEATURE_LOWMEM_DBG +CONFIG_OPLUS_FEATURE_LOWMEM_DBG=y +#endif /* OPLUS_FEATURE_LOWMEM_DBG */ + +#ifdef OPLUS_FEATURE_SCHED_ASSIST +CONFIG_BLK_WBT_SQ=y +CONFIG_BLK_WBT=y +CONFIG_OPLUS_FEATURE_UXIO_FIRST=y +#CONFIG_OPLUS_FEATURE_SCHED_SPREAD=y +#endif /*OPLUS_FEATURE_SCHED_ASSIST*/ + +#ifdef OPLUS_FEATURE_MEMLEAK_DETECT +CONFIG_KMALLOC_DEBUG=y +CONFIG_VMALLOC_DEBUG=y +CONFIG_DUMP_TASKS_MEM=y +#endif /*OPLUS_FEATURE_MEMLEAK_DETECT*/ + +#ifdef OPLUS_FEATURE_MEMLEAK_DETECT +CONFIG_SVELTE=y +#endif + +#ifdef VEDOR_EDIT +CONFIG_OPLUS_FEATURE_RECORD_MDMRST=y +#endif + +#ifdef OPLUS_ARCH_EXTENDS +CONFIG_OPLUS_FEATURE_MM_FEEDBACK=y +#endif + +#ifdef VENDOR_EDIT +CONFIG_OPLUS_FEATURE_MIDAS=y +#endif + +#ifdef CONFIG_OPLUS_FEATURE_BINDER_STATS_ENABLE +CONFIG_OPLUS_FEATURE_BINDER_STATS_ENABLE=y +#endif + +#ifdef OPLUS_FEATURE_ACM +CONFIG_OPLUS_FEATURE_ACM=y +CONFIG_OPLUS_FEATURE_ACM_LOGGING=y +#endif /* OPLUS_FEATURE_ACM */ + +#ifdef OPLUS_FEATURE_SENSOR_DRIVER +CONFIG_OPLUS_SENSOR_FB_QC=y +#endif + +#ifdef OPLUS_BUG_STABILITY +CONFIG_HARDEN_BRANCH_PREDICTOR=y +#endif + +#add by shaojun.zou for cobuck opt 2021/08/16 +CONFIG_SCHED_WALT_COBUCK=y + +#ifdef OPLUS_FEATURE_SIM_DETECT +CONFIG_SIM_DETECT=y +#endif + +#ifdef OPLUS_FEATURE_SIM_DETECT +CONFIG_OEM_QMI=y +#endif + +#Add for theia +CONFIG_OPLUS_FEATURE_THEIA=y +##endif /* OPLUS_FEATURE_THEIA */ + +#ifdef OPLUS_FEATURE_ESIM +CONFIG_OPLUS_GPIO=y +#endif + +#ifdef OPLUS_FEATURE_SAUPWK +#Add for theia saupwrkey +CONFIG_OPLUS_FEATURE_SAUPWK=y +#endif /* OPLUS_FEATURE_SAUPWK */ + +#ifdef OPLUS_FEATURE_RT_INFO +CONFIG_OPLUS_FEATURE_RT_INFO=n +#endif + +#ifdef OPLUS_FEATURE_TPP +#jacky.ho@optimization add for tpp module +CONFIG_OPLUS_FEATURE_TPP=y +#endif /* OPLUS_FEATURE_TPP */ + +#ifdef OPLUS_FEATURE_IM +#ted.lin@optimization add for im module +CONFIG_OPLUS_FEATURE_IM=y +#endif /* OPLUS_FEATURE_IM */ + +#ifdef OPLUS_FEATURE_ION_BOOSTPOOL +CONFIG_OPLUS_ION_BOOSTPOOL=y +#endif /* OPLUS_FEATURE_ION_BOOSTPOOL */ + +#ifdef OPLUS_FEATURE_TPD +CONFIG_OPLUS_FEATURE_TPD=y +#endif +#ifdef OPLUS_FEATURE_SENSOR +CONFIG_SSC_INTERACTIVE=y +#endif + +#ifdef OPLUS_FEATURE_WIFI_SLA +#todo: need to change to m when GKI +CONFIG_OPLUS_FEATURE_WIFI_SLA=y +#endif /* OPLUS_FEATURE_WIFI_SLA */ + +#ifdef OPLUS_FEATURE_WIFI_ROUTERBOOST +CONFIG_OPLUS_FEATURE_WIFI_ROUTERBOOST=m +#endif /* OPLUS_FEATURE_WIFI_ROUTERBOOST */ + +CONFIG_DYNAMIC_TUNNING_SWAPPINESS=y + +#ifdef OPLUS_FEATURE_DATA_EVAL +CONFIG_OPLUS_FEATURE_DATA_EVAL=y +#endif /* OPLUS_FEATURE_DATA_VAL */ + +#ifdef OPLUS_FEATURE_DATA_LIMIT +CONFIG_IFB=y +CONFIG_NET_SCH_MULTIQ=y +CONFIG_NET_SCH_NETEM=y +CONFIG_CLS_U32_MARK=y +CONFIG_NET_CLS_FLOW=y +CONFIG_NET_EMATCH_CMP=y +CONFIG_NET_EMATCH_NBYTE=y +CONFIG_NET_EMATCH_META=y +CONFIG_NET_EMATCH_TEXT=y +CONFIG_NET_ACT_GACT=y +CONFIG_NET_ACT_MIRRED=y +CONFIG_NET_ACT_SKBEDIT=y +#endif /* OPLUS_FEATURE_DATA_LIMIT */ + +#CONFIG_NANDSWAP=y +#CONFIG_NANDSWAP_DEBUG=y +CONFIG_FRAME_WARN=4096 +#ifdef OPLUS_FEATURE_HYBRIDSWAP +CONFIG_HYBRIDSWAP=y +CONFIG_HYBRIDSWAP_SWAPD=y +CONFIG_HYBRIDSWAP_CORE=y +#endif + +#ifdef OPLUS_FEATURE_DNS_HOOK +CONFIG_OPLUS_FEATURE_DNS_HOOK=y +#endif /* OPLUS_FEATURE_DNS_HOOK */ + +#ifdef OPLUS_FEATURE_STATS_CALC +CONFIG_OPLUS_FEATURE_STATS_CALC=y +#endif /* OPLUS_FEATURE_STATS_CALC */ + +#ifdef OPLUS_FEATURE_MDMFEATURE +CONFIG_OPLUS_FEATURE_MDMFEATURE=y +#endif + +#ifdef OPLUS_FEATURE_GAME_OPT +CONFIG_OPLUS_FEATURE_GAME_OPT=y +#endif +CONFIG_OPLUS_BINDER_STRATEGY=n + +#ifdef Multi-gen LRU +CONFIG_LRU_GEN=y +CONFIG_LRU_GEN_ENABLED=n +CONFIG_LRU_GEN_STATS=n +#endif +CONFIG_OPLUS_FEATURE_CPU_JANKINFO=y + +CONFIG_CRYPTO_CHACHA20POLY1305=y diff --git a/arch/arm64/configs/vendor/lito-perf_defconfig b/arch/arm64/configs/vendor/lito-perf_defconfig index 5eab5980de62..c321d26e630f 100644 --- a/arch/arm64/configs/vendor/lito-perf_defconfig +++ b/arch/arm64/configs/vendor/lito-perf_defconfig @@ -6,6 +6,7 @@ CONFIG_HIGH_RES_TIMERS=y CONFIG_PREEMPT=y CONFIG_IRQ_TIME_ACCOUNTING=y CONFIG_SCHED_WALT=y +CONFIG_MMAP_LOCK_OPT=y CONFIG_TASKSTATS=y CONFIG_TASK_XACCT=y CONFIG_TASK_IO_ACCOUNTING=y @@ -22,6 +23,10 @@ CONFIG_MEMCG_SWAP=y CONFIG_BLK_CGROUP=y CONFIG_CGROUP_FREEZER=y CONFIG_CPUSETS=y +#ifdef OPLUS_FEATURE_TASK_CPUSTATS +CONFIG_OPLUS_SCHED=y +CONFIG_OPLUS_CTP=y +#endif /* OPLUS_FEATURE_TASK_CPUSTATS */ CONFIG_CGROUP_CPUACCT=y CONFIG_CGROUP_BPF=y CONFIG_SCHED_CORE_CTL=y @@ -38,7 +43,6 @@ CONFIG_KALLSYMS_ALL=y CONFIG_BPF_SYSCALL=y CONFIG_BPF_JIT_ALWAYS_ON=y CONFIG_EMBEDDED=y -# CONFIG_SLUB_DEBUG is not set # CONFIG_COMPAT_BRK is not set CONFIG_SLAB_FREELIST_RANDOM=y CONFIG_SLAB_FREELIST_HARDENED=y @@ -64,6 +68,8 @@ CONFIG_RANDOMIZE_BASE=y CONFIG_CMDLINE="cgroup_disable=pressure" CONFIG_CMDLINE_EXTEND=y # CONFIG_EFI is not set +CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE=y +CONFIG_IMG_GZ_DTB=y CONFIG_BUILD_ARM64_UNCOMPRESSED_KERNEL=y CONFIG_COMPAT=y CONFIG_PM_WAKELOCKS=y @@ -80,6 +86,9 @@ CONFIG_CPU_FREQ_GOV_ONDEMAND=y CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y CONFIG_CPU_BOOST=y CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y +#ifdef VENDOR_EDIT +CONFIG_CPU_FREQ_STAT=y +#endif CONFIG_ARM_QCOM_CPUFREQ_HW=y CONFIG_ARM_QCOM_CPUFREQ_HW_DEBUG=y CONFIG_MSM_TZ_LOG=y @@ -106,7 +115,10 @@ CONFIG_CFQ_GROUP_IOSCHED=y CONFIG_IOSCHED_BFQ=y CONFIG_BFQ_GROUP_IOSCHED=y # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set -CONFIG_MEMORY_HOTPLUG=y +#ifdef OPLUS_DEBUG_STABILITY +##CONFIG_MEMORY_HOTPLUG=y +# CONFIG_MEMORY_HOTPLUG is not set +# endif CONFIG_MEMORY_HOTPLUG_DEFAULT_ONLINE=y CONFIG_MEMORY_HOTPLUG_MOVABLE_NODE=y CONFIG_MEMORY_HOTREMOVE=y @@ -271,6 +283,11 @@ CONFIG_CFG80211=y CONFIG_CFG80211_INTERNAL_REGDB=y CONFIG_RFKILL=y CONFIG_NFC_NQ=y +#ifdef OPLUS_NFC_BRINGUP +#Add for the kernel Macro for NXP PN557 NFC kernel +CONFIG_NFC_PN553_DEVICES=y +CONFIG_NXP_P73_DEVICES=y +#endif /*OPLUS_NFC_BRINGUP*/ CONFIG_FW_LOADER_USER_HELPER=y CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y # CONFIG_FW_CACHE is not set @@ -279,7 +296,7 @@ CONFIG_REGMAP_ALLOW_WRITE_DEBUGFS=y CONFIG_DMA_CMA=y CONFIG_MHI_BUS=y CONFIG_ZRAM=y -CONFIG_ZRAM_DEDUP=y +#CONFIG_ZRAM_DEDUP=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_LOOP_MIN_COUNT=16 CONFIG_BLK_DEV_RAM=y @@ -293,11 +310,21 @@ CONFIG_BLK_DEV_SD=y CONFIG_CHR_DEV_SG=y CONFIG_CHR_DEV_SCH=y CONFIG_SCSI_CONSTANTS=y -CONFIG_SCSI_LOGGING=y +#CONFIG_SCSI_LOGGING=y CONFIG_SCSI_SCAN_ASYNC=y CONFIG_SCSI_UFSHCD=y CONFIG_SCSI_UFSHCD_PLATFORM=y CONFIG_SCSI_UFS_QCOM=y +CONFIG_SCSI_UFS_QCOM_ICE=y +#ifdef OPLUS_FEATURE_UFSPLUS +CONFIG_UFSFEATURE=y +# CONFIG_UFSHPB is not set +CONFIG_UFSTW=y +# CONFIG_HPB_SUP_ONLY_4 is not set +# CONFIG_HPB_SUP_8_TO_32 is not set +# CONFIG_HPB_SUP_OVER_36 is not set +CONFIG_UFSTW_IGNORE_GUARANTEE_BIT=y +#endif /*OPLUS_FEATURE_UFSPLUS*/ CONFIG_SCSI_UFS_CRYPTO=y CONFIG_SCSI_UFS_CRYPTO_QTI=y CONFIG_MD=y @@ -344,10 +371,29 @@ CONFIG_TABLET_USB_GTCO=y CONFIG_TABLET_USB_HANWANG=y CONFIG_TABLET_USB_KBTAB=y CONFIG_INPUT_TOUCHSCREEN=y -CONFIG_SECURE_TOUCH_SYNAPTICS_DSX=y +CONFIG_OPLUS_TRI_STATE_KEY=y +CONFIG_TOUCHIRQ_UPDATE_QOS=y +CONFIG_TOUCHPANEL_NEW_SET_IRQ_WAKE=y +CONFIG_TOUCHPANEL_OPLUS=y +CONFIG_TOUCHPANEL_ALGORITHM=y +CONFIG_TOUCHPANEL_SYNAPTICS=y +CONFIG_TOUCHPANEL_GOODIX=y +CONFIG_TOUCHPANEL_SAMSUNG=y +CONFIG_TOUCHPANEL_SYNAPTICS_TCM_ONCELL=y +CONFIG_TOUCHPANEL_GOODIX_GT9886=y +CONFIG_TOUCHPANEL_SAMSUNG_S6SY771=y +CONFIG_TOUCHPANEL_FOCAL=y +CONFIG_TOUCHPANEL_FOCAL_FT3518=y +CONFIG_TOUCHPANEL_NOVA=y +CONFIG_TOUCHPANEL_NOVA_NT36672C_NOFLASH=y +CONFIG_TOUCHPANEL_NT_DIGITALNOISE_TEST=y +CONFIG_TOUCHPANEL_ILITEK=y +CONFIG_TOUCHPANEL_ILITEK_ILITEK7807S=y +# CONFIG_SECURE_TOUCH_SYNAPTICS_DSX is not set CONFIG_TOUCHSCREEN_SYNAPTICS_TCM_REFLASH=y CONFIG_TOUCHSCREEN_SYNAPTICS_TCM_RECOVERY=y -CONFIG_TOUCHSCREEN_FTS=y +CONFIG_TOUCHSCREEN_FTS=n +CONFIG_TOUCHSCREEN_ST=n CONFIG_INPUT_MISC=y CONFIG_INPUT_QPNP_POWER_ON=y CONFIG_INPUT_UINPUT=y @@ -356,6 +402,7 @@ CONFIG_INPUT_UINPUT=y # CONFIG_LEGACY_PTYS is not set # CONFIG_DEVMEM is not set CONFIG_SERIAL_MSM_GENI=y +CONFIG_SERIAL_MSM_GENI_CONSOLE=y CONFIG_SERIAL_MSM_GENI_HALF_SAMPLING=y CONFIG_TTY_PRINTK=y CONFIG_HW_RANDOM=y @@ -379,12 +426,44 @@ CONFIG_POWER_RESET_QCOM=y CONFIG_POWER_RESET_XGENE=y CONFIG_POWER_RESET_SYSCON=y CONFIG_QPNP_SMB5=y -CONFIG_SMB1390_CHARGE_PUMP_PSY=y +#ifdef OPLUS_FEATURE_CHG_BASIC//tongfeng.Huang@ProDrv.CHG,add 2019/06/22 for charger +CONFIG_OPLUS_SM7250R_CHARGER=y CONFIG_SMB1355_SLAVE_CHARGER=y -CONFIG_QPNP_QG=y -CONFIG_SMB1398_CHARGER=y +CONFIG_OPLUS_CHIP_SOC_NODE=y +CONFIG_OPLUS_QPNP_QG=y +#else +#CONFIG_SMB1390_CHARGE_PUMP_PSY=y +#CONFIG_SMB1398_CHARGER=y +#CONFIG_QPNP_QG=y +#CONFIG_QPNP_FG_GEN4=y +#endif +#ifdef OPLUS_FEATURE_CHG_BASIC +CONFIG_OPLUS_SHORT_HW_CHECK=y +CONFIG_OPLUS_SHORT_USERSPACE=y +CONFIG_OPLUS_SHIP_MODE_SUPPORT=y +CONFIG_OPLUS_SMART_CHARGER_SUPPORT=y +CONFIG_OPLUS_CHARGER_OPTIGA=y +CONFIG_OPLUS_SHORT_C_BATT_CHECK=y +CONFIG_OPLUS_CHECK_CHARGERID_VOLT=y +CONFIG_OPLUS_SHORT_IC_CHECK=y +CONFIG_SONY_FF=y +CONFIG_HID_BETOP_FF=y +CONFIG_HID_PLAYSTATION=y +CONFIG_PLAYSTATION_FF=y +#endif +#ifndef OPLUS_FEATURE_CHG_BASIC//tongfeng.Huang@ProDrv.CHG,add 2019/12/22 for charger +#CONFIG_HL6111R=y +#endif +#ifdef OPLUS_FEATURE_CHG_BASIC +CONFIG_INPUT_JOYSTICK=y +CONFIG_JOYSTICK_XPAD=y +CONFIG_JOYSTICK_XPAD_FF=y +CONFIG_JOYSTICK_XPAD_LEDS=y +#endif /* OPLUS_FEATURE_CHG_BASIC */ CONFIG_THERMAL=y -CONFIG_THERMAL_STATISTICS=y +#ifndef OPLUS_FEATURE_THERMAL_STATISTICS +#CONFIG_THERMAL_STATISTICS=y +#endif CONFIG_THERMAL_WRITABLE_TRIPS=y CONFIG_THERMAL_GOV_USER_SPACE=y CONFIG_THERMAL_GOV_LOW_LIMITS=y @@ -395,6 +474,9 @@ CONFIG_THERMAL_TSENS=y CONFIG_QTI_ADC_TM=y CONFIG_QTI_VIRTUAL_SENSOR=y CONFIG_QTI_QMI_SENSOR=y +CONFIG_SSC_INTERACTIVE=y +CONFIG_OPLUS_SENSOR_FB_QC=y +CONFIG_SENSORS_SSC=y CONFIG_QTI_BCL_PMIC5=y CONFIG_QTI_BCL_SOC_DRIVER=y CONFIG_QTI_QMI_COOLING_DEVICE=y @@ -417,12 +499,16 @@ CONFIG_REGULATOR_REFGEN=y CONFIG_REGULATOR_RPMH=y CONFIG_REGULATOR_STUB=y CONFIG_REGULATOR_PM8008=y +#ifdef OPLUS_BUG_STABILITY +CONFIG_REGULATOR_TPS65132=y +CONFIG_REGULATOR_TPS65132_FOR_20267=y +#endif /* OPLUS_BUG_STABILITY */ CONFIG_MEDIA_SUPPORT=y CONFIG_MEDIA_CAMERA_SUPPORT=y CONFIG_MEDIA_DIGITAL_TV_SUPPORT=y CONFIG_MEDIA_CONTROLLER=y CONFIG_VIDEO_V4L2_SUBDEV_API=y -CONFIG_VIDEO_ADV_DEBUG=y +#CONFIG_VIDEO_ADV_DEBUG=y CONFIG_VIDEO_FIXED_MINOR_RANGES=y CONFIG_V4L_PLATFORM_DRIVERS=y CONFIG_MSM_NPU=y @@ -431,6 +517,10 @@ CONFIG_DVB_MPQ_DEMUX=m CONFIG_DVB_MPQ_SW=y CONFIG_VIDEO_V4L2_VIDEOBUF2_CORE=y CONFIG_DRM=y +#ifdef VENDOR_EDIT +CONFIG_DRM_MSM=y +#endif /* VENDOR_EDIT */ +CONFIG_DRM_LONTIUM_LT9611UXC=y CONFIG_BACKLIGHT_LCD_SUPPORT=y CONFIG_BACKLIGHT_CLASS_DEVICE=y CONFIG_BACKLIGHT_QCOM_SPMI_WLED=y @@ -661,6 +751,15 @@ CONFIG_OVERLAY_FS=y CONFIG_INCREMENTAL_FS=y CONFIG_MSDOS_FS=y CONFIG_VFAT_FS=y +CONFIG_OPLUS_FEATURE_EROFS=y +CONFIG_EROFS_FS=y +#ifdef OPLUS_FEATURE_EXFAT_SUPPORT +CONFIG_NLS_UTF8=y +CONFIG_EXFAT_FS=y +# endif +#ifdef OPLUS_FEATURE_EMMC_SDCARD_OPTIMIZE +CONFIG_EMMC_SDCARD_OPTIMIZE=y +#endif CONFIG_TMPFS=y CONFIG_TMPFS_POSIX_ACL=y CONFIG_ECRYPT_FS=y @@ -694,7 +793,7 @@ CONFIG_SCHEDSTATS=y # CONFIG_DEBUG_PREEMPT is not set CONFIG_DEBUG_LIST=y CONFIG_IPC_LOGGING=y -CONFIG_DEBUG_ALIGN_RODATA=y +#CONFIG_DEBUG_ALIGN_RODATA=y CONFIG_ARM64_STRICT_BREAK_BEFORE_MAKE=y CONFIG_CORESIGHT=y CONFIG_CORESIGHT_LINK_AND_SINK_TMC=y @@ -708,3 +807,262 @@ CONFIG_CORESIGHT_HWEVENT=y CONFIG_CORESIGHT_DUMMY=y CONFIG_CORESIGHT_REMOTE_ETM=y CONFIG_CORESIGHT_TGU=y +#ifdef OPLUS_SYSTEM_KERNEL +#/*Add for oplus project*/ +CONFIG_OPLUS_COMMON_SOFT=y +CONFIG_OPLUS_DEVICE_IFNO=y +CONFIG_OPLUS_RF_CABLE_MONITOR=y +CONFIG_RECORD_MDMRST=y +#endif +#ifdef OPLUS_FEATURE_POWERINFO_STANDBY +CONFIG_OPLUS_WAKELOCK_PROFILER=y +#endif /* OPLUS_FEATURE_POWERINFO_STANDBY */ +# ifdef VENDOR_EDIT +CONFIG_CS_F61_NDT=y +# endif /* VENDOR_EDIT */ + + +#ifdef OPLUS_SYSTEM_KERNEL +#all system oplus feature writer here +CONFIG_OPLUS_FEATURE_UBOOT_LOG=y +CONFIG_DETECT_HUNG_TASK=y +CONFIG_OPLUS_FEATURE_HUNG_TASK_ENHANCE=y +CONFIG_DEFAULT_HUNG_TASK_TIMEOUT=60 +CONFIG_OPLUS_FEATURE_FEEDBACK=y +CONFIG_OPLUS_FEATURE_OPROJECT=y +CONFIG_OPLUS_FEATURE_CMDLINE=y +CONFIG_OPLUS_FEATURE_PROJECTINFO=y +CONFIG_OPLUS_FEATURE_PHOENIX=y +CONFIG_OPLUS_FEATURE_PHOENIX_REBOOT_SPEED=y +CONFIG_OPLUS_FEATURE_KMSG_WB=y +CONFIG_OPLUS_FEATURE_SHUTDOWN_SPEED=y +CONFIG_OPLUS_FEATURE_OLC=y +CONFIG_KPROBES=y +CONFIG_KRETPROBES=y +CONFIG_OPLUS_FEATURE_FDLEAK_CHECK=y +#add for qcom minidump customized +CONFIG_OPLUS_FEATURE_QCOM_MINIDUMP_ENHANCE=y +#Add for shutdown detect +CONFIG_OPLUS_FEATURE_SHUTDOWN_DETECT=y +#add slabtrace function +# CONFIG_OPLUS_FEATURE_SLABTRACE_DEBUG is not set +#enable oplus misc feature +#CONFIG_OPLUS_FEATURE_MISC is not set +#endif +#ifdef OPLUS_FEATURE_QCOM_PMICWD +# Add for qcom pmic watchdog +CONFIG_OPLUS_FEATURE_QCOM_PMICWD=y +#endif +#ifdef OPLUS_FEATURE_FINGERPRINT +CONFIG_OPLUS_FINGERPRINT=y +CONFIG_OPLUS_FINGERPRINT_QCOM=y +CONFIG_OPLUS_FINGERPRINT_GOODIX_OPTICAL=y +CONFIG_OPLUS_FINGERPRINT_JIIOV_OPTICAL=y +CONFIG_OPLUS_FINGERPRINT_SILEAD=y +#endif +CONFIG_OPLUS_FINGERPRINT_GKI_DISABLE=y + +#ifdef OPLUS_FEATURE_SECURITY_COMMON +CONFIG_OPLUS_SECURE=y +CONFIG_OPLUS_SECURE_QCOM=y +CONFIG_OPLUS_SECURE_COMMON=y +#endif /* OPLUS_FEATURE_SECURITY_COMMON */ + +#ifdef OPLUS_FEATURE_HANS_FREEZE +CONFIG_OPLUS_HANS=y +#endif /*OPLUS_FEATURE_HANS_FREEZE*/ +#ifdef VENDOR_EDIT//Qingjun.Wang@BSP.Haptic,add 2020/03/17 for vib aw8697 +CONFIG_AW8697_HAPTIC=y +#endif +#ifdef OPLUS_FEATURE_HEALTHINFO +CONFIG_OPLUS_MEM_MONITOR=y +CONFIG_FG_TASK_UID=y +CONFIG_OPLUS_HEALTHINFO=y +CONFIG_SLUB_DEBUG=y +#endif /* OPLUS_FEATURE_HEALTHINFO */ +#ifdef OPLUS_FEATURE_HEALTHINFO +CONFIG_OPLUS_JANK_INFO=y +#endif /* OPLUS_FEATURE_HEALTHINFO */ + +#ifdef OPLUS_FEATURE_ZRAM_OPT +CONFIG_OPLUS_ZRAM_OPT=y +CONFIG_CRYPTO_LZ4=y +CONFIG_PGTABLE_MAPPING=y +CONFIG_CRYPTO_ZSTD=y +#endif +#ifdef OPLUS_FEATURE_MULTI_KSWAPD +CONFIG_OPLUS_MULTI_KSWAPD=y +CONFIG_KSWAPD_UNBIND_MAX_CPU=y +#endif +#ifdef VENDOR_EDIT +CONFIG_REGULATOR_PM8008=y +#ifdef OPLUS_FEATURE_DUMPDEVICE +#Add for dump device info +CONFIG_PSTORE=y +CONFIG_PSTORE_CONSOLE=y +CONFIG_PSTORE_PMSG=y +CONFIG_PSTORE_RAM=y +#endif +#ifdef OPLUS_FEATURE_IOMONITOR +#CONFIG_IOMONITOR=y +#CONFIG_IOMONITOR_WITH_F2FS=n +#endif /*OPLUS_FEATURE_IOMONITOR*/ +CONFIG_OPLUS_FEATURE_PMIC_MONITOR=y +CONFIG_OPLUS_FEATURE_OF2FS=y +CONFIG_OPLUS_FEATURE_PANIC_FLUSH=y +CONFIG_OPLUS_FEATURE_OEXT4=y +CONFIG_F2FS_BD_STAT=y +#CONFIG_F2FS_GRADING_SSR is not set + +#ifdef OPLUS_FEATURE_LOWMEM_DBG +CONFIG_OPLUS_FEATURE_LOWMEM_DBG=y +#endif /* OPLUS_FEATURE_LOWMEM_DBG */ +#ifdef OPLUS_FEATURE_SCHED_ASSIST +CONFIG_BLK_WBT_SQ=y +CONFIG_BLK_WBT=y +CONFIG_OPLUS_FEATURE_UXIO_FIRST=y +#endif /*OPLUS_FEATURE_SCHED_ASSIST*/ +#ifdef OPLUS_FEATURE_MEMLEAK_DETECT +CONFIG_KMALLOC_DEBUG=y +CONFIG_VMALLOC_DEBUG=y +CONFIG_DUMP_TASKS_MEM=y +#endif /*OPLUS_FEATURE_MEMLEAK_DETECT*/ +#ifdef OPLUS_FEATURE_MEMLEAK_DETECT +CONFIG_SVELTE=y +#endif +#ifdef VEDOR_EDIT +CONFIG_OPLUS_FEATURE_RECORD_MDMRST=y +#endif +#ifdef OPLUS_ARCH_EXTENDS +CONFIG_OPLUS_FEATURE_MM_FEEDBACK=y +#endif + +#ifdef OPLUS_FEATURE_MIDAS +CONFIG_OPLUS_FEATURE_MIDAS=y +#endif + +#ifdef CONFIG_OPLUS_FEATURE_BINDER_STATS_ENABLE +CONFIG_OPLUS_FEATURE_BINDER_STATS_ENABLE=y +#endif + +#ifdef OPLUS_FEATURE_ACM +CONFIG_OPLUS_FEATURE_ACM=y +CONFIG_OPLUS_FEATURE_ACM_LOGGING=y +#endif /* OPLUS_FEATURE_ACM */ +#ifdef OPLUS_BUG_STABILITY +CONFIG_HARDEN_BRANCH_PREDICTOR=y +#endif +CONFIG_OPLUS_FEATURE_THEIA=y +##endif /* OPLUS_FEATURE_THEIA */ + +#ifdef OPLUS_FEATURE_SAUPWK +CONFIG_OPLUS_FEATURE_SAUPWK=y +#endif /* OPLUS_FEATURE_SAUPWK */ + +#ifdef OPLUS_FEATURE_DUMP_DEVICE_INFO +CONFIG_OPLUS_FEATURE_DUMP_DEVICE_INFO=y +#endif /* OPLUS_FEATURE_DUMP_DEVICE_INFO */ + +#ifdef OPLUS_BUG_STABILITY +CONFIG_UNMAP_KERNEL_AT_EL0=y +#endif + +#ifdef OPLUS_FEATURE_GPIO_NC +CONFIG_OPLUS_GPIO_NC=y +#endif + +#ifdef OPLUS_FEATURE_BOOTLOADER_LOG +CONFIG_BOOTLOADER_LOG=y +#endif +#ifdef OPLUS_FEATURE_PARAM +CONFIG_PARAM_READ_WRITE=y +#endif + +#ifdef OPLUS_FEATURE_TP_BASIC +CONFIG_SIM_DETECT=y +#endif + +#ifdef OPLUS_FEATURE_TP_BASIC +CONFIG_OPLUS_FW_UPDATE=y +#endif /*OPLUS_FEATURE_TP_BASIC*/ + +#ifdef OPLUS_FEATURE_ION_BOOSTPOOL +#CONFIG_OPLUS_ION_BOOSTPOOL=y ,Add for disable boost pool ,fill generic ION POOL +#endif /* OPLUS_FEATURE_ION_BOOSTPOOL */ + +#ifdef OPLUS_FEATURE_WIFI_SLA +#todo: need to change to m when GKI +CONFIG_OPLUS_FEATURE_WIFI_SLA=y +#endif /* OPLUS_FEATURE_WIFI_SLA */ + +#ifdef OPLUS_FEATURE_WIFI_ROUTERBOOST +CONFIG_OPLUS_FEATURE_WIFI_ROUTERBOOST=m +#endif /* OPLUS_FEATURE_WIFI_ROUTERBOOST */ + +#ifdef OPLUS_FEATURE_DATA_EVAL +CONFIG_OPLUS_FEATURE_DATA_EVAL=y +#endif /* OPLUS_FEATURE_DATA_VAL */ + +#ifdef OPLUS_FEATURE_DATA_LIMIT +CONFIG_IFB=y +CONFIG_NET_SCH_MULTIQ=y +CONFIG_NET_SCH_NETEM=y +CONFIG_CLS_U32_MARK=y +CONFIG_NET_CLS_FLOW=y +CONFIG_NET_EMATCH_CMP=y +CONFIG_NET_EMATCH_NBYTE=y +CONFIG_NET_EMATCH_META=y +CONFIG_NET_EMATCH_TEXT=y +CONFIG_NET_ACT_GACT=y +CONFIG_NET_ACT_MIRRED=y +CONFIG_NET_ACT_SKBEDIT=y +#endif /* OPLUS_FEATURE_DATA_LIMIT */ + +#CONFIG_DEBUG_SPINLOCK=y + +#CONFIG_NANDSWAP=y +#CONFIG_NANDSWAP_DEBUG=y +#ifdef OPLUS_FEATURE_IM +#ted.lin@optimization add for im module +CONFIG_OPLUS_FEATURE_IM=y +#endif /* OPLUS_FEATURE_IM */ + +CONFIG_FRAME_WARN=4096 + +CONFIG_DYNAMIC_TUNNING_SWAPPINESS=y + +#ifdef OPLUS_FEATURE_HYBRIDSWAP +CONFIG_HYBRIDSWAP=y +CONFIG_HYBRIDSWAP_SWAPD=y +CONFIG_HYBRIDSWAP_CORE=y +#endif + +#ifdef OPLUS_FEATURE_UID_PERF +CONFIG_OPLUS_FEATURE_UID_PERF=y +#endif + +#ifdef OPLUS_FEATURE_ESIM +CONFIG_OPLUS_GPIO=y +#endif /* OPLUS_FEATURE_ESIM */ + +#ifdef OPLUS_FEATURE_TPD +CONFIG_OPLUS_FEATURE_TPD=y +#endif + +#ifdef OPLUS_FEATURE_DNS_HOOK +CONFIG_OPLUS_FEATURE_DNS_HOOK=y +#endif /* OPLUS_FEATURE_DNS_HOOK */ + +#ifdef OPLUS_FEATURE_STATS_CALC +CONFIG_OPLUS_FEATURE_STATS_CALC=y +#endif /* OPLUS_FEATURE_STATS_CALC */ +CONFIG_OPLUS_BINDER_STRATEGY=n + +#ifdef OPLUS_FEATURE_MDMFEATURE +CONFIG_OPLUS_FEATURE_MDMFEATURE=y +#endif + +#ifdef OPLUS_FEATURE_GAME_OPT +CONFIG_OPLUS_FEATURE_GAME_OPT=y +#endif +CONFIG_OPLUS_FEATURE_CPU_JANKINFO=y diff --git a/arch/arm64/configs/vendor/lito_defconfig b/arch/arm64/configs/vendor/lito_defconfig index f8d3d3081b0c..095e5d50c6ad 100644 --- a/arch/arm64/configs/vendor/lito_defconfig +++ b/arch/arm64/configs/vendor/lito_defconfig @@ -5,6 +5,7 @@ CONFIG_HIGH_RES_TIMERS=y CONFIG_PREEMPT=y CONFIG_IRQ_TIME_ACCOUNTING=y CONFIG_SCHED_WALT=y +CONFIG_MMAP_LOCK_OPT=y CONFIG_TASKSTATS=y CONFIG_TASK_XACCT=y CONFIG_TASK_IO_ACCOUNTING=y @@ -23,6 +24,10 @@ CONFIG_BLK_CGROUP=y CONFIG_DEBUG_BLK_CGROUP=y CONFIG_CGROUP_FREEZER=y CONFIG_CPUSETS=y +#ifdef OPLUS_FEATURE_TASK_CPUSTATS +CONFIG_OPLUS_SCHED=y +CONFIG_OPLUS_CTP=y +#endif /* OPLUS_FEATURE_TASK_CPUSTATS */ CONFIG_CGROUP_CPUACCT=y CONFIG_CGROUP_BPF=y CONFIG_CGROUP_DEBUG=y @@ -64,7 +69,7 @@ CONFIG_ARM64_SW_TTBR0_PAN=y CONFIG_RANDOMIZE_BASE=y CONFIG_CMDLINE="cgroup_disable=pressure" CONFIG_CMDLINE_EXTEND=y -CONFIG_BUILD_ARM64_UNCOMPRESSED_KERNEL=y +CONFIG_BUILD_ARM64_KERNEL_COMPRESSION_GZIP=y CONFIG_COMPAT=y CONFIG_PM_WAKELOCKS=y CONFIG_PM_WAKELOCKS_LIMIT=0 @@ -81,6 +86,9 @@ CONFIG_CPU_FREQ_GOV_ONDEMAND=y CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y CONFIG_CPU_BOOST=y CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y +#ifdef VENDOR_EDIT +CONFIG_CPU_FREQ_STAT=y +#endif CONFIG_ARM_QCOM_CPUFREQ_HW=y CONFIG_ARM_QCOM_CPUFREQ_HW_DEBUG=y CONFIG_MSM_TZ_LOG=y @@ -108,7 +116,10 @@ CONFIG_CFQ_GROUP_IOSCHED=y CONFIG_IOSCHED_BFQ=y CONFIG_BFQ_GROUP_IOSCHED=y # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set -CONFIG_MEMORY_HOTPLUG=y +#ifdef OPLUS_DEBUG_STABILITY +##CONFIG_MEMORY_HOTPLUG=y +# CONFIG_MEMORY_HOTPLUG is not set +# endif CONFIG_MEMORY_HOTPLUG_DEFAULT_ONLINE=y CONFIG_MEMORY_HOTPLUG_MOVABLE_NODE=y CONFIG_MEMORY_HOTREMOVE=y @@ -277,6 +288,11 @@ CONFIG_CFG80211=y CONFIG_CFG80211_INTERNAL_REGDB=y CONFIG_RFKILL=y CONFIG_NFC_NQ=y +#ifdef OPLUS_NFC_BRINGUP +#Add for the kernel Macro for NXP PN557 NFC kernel +CONFIG_NFC_PN553_DEVICES=y +CONFIG_NXP_P73_DEVICES=y +#endif /*OPLUS_NFC_BRINGUP*/ CONFIG_FW_LOADER_USER_HELPER=y CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y # CONFIG_FW_CACHE is not set @@ -285,7 +301,7 @@ CONFIG_REGMAP_ALLOW_WRITE_DEBUGFS=y CONFIG_DMA_CMA=y CONFIG_MHI_BUS=y CONFIG_ZRAM=y -CONFIG_ZRAM_DEDUP=y +#CONFIG_ZRAM_DEDUP=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_LOOP_MIN_COUNT=16 CONFIG_BLK_DEV_RAM=y @@ -305,6 +321,15 @@ CONFIG_SCSI_UFSHCD=y CONFIG_SCSI_UFSHCD_PLATFORM=y CONFIG_SCSI_UFS_QCOM=y CONFIG_SCSI_UFSHCD_CMD_LOGGING=y +#ifdef OPLUS_FEATURE_UFSPLUS +CONFIG_UFSFEATURE=y +# CONFIG_UFSHPB is not set +CONFIG_UFSTW=y +# CONFIG_HPB_SUP_ONLY_4 is not set +# CONFIG_HPB_SUP_8_TO_32 is not set +# CONFIG_HPB_SUP_OVER_36 is not set +CONFIG_UFSTW_IGNORE_GUARANTEE_BIT=y +#endif /*OPLUS_FEATURE_UFSPLUS*/ CONFIG_SCSI_UFS_CRYPTO=y CONFIG_SCSI_UFS_CRYPTO_QTI=y CONFIG_MD=y @@ -351,10 +376,29 @@ CONFIG_TABLET_USB_GTCO=y CONFIG_TABLET_USB_HANWANG=y CONFIG_TABLET_USB_KBTAB=y CONFIG_INPUT_TOUCHSCREEN=y -CONFIG_SECURE_TOUCH_SYNAPTICS_DSX=y +CONFIG_OPLUS_TRI_STATE_KEY=y +CONFIG_TOUCHIRQ_UPDATE_QOS=y +CONFIG_TOUCHPANEL_NEW_SET_IRQ_WAKE=y +CONFIG_TOUCHPANEL_OPLUS=y +CONFIG_TOUCHPANEL_ALGORITHM=y +CONFIG_TOUCHPANEL_SYNAPTICS=y +CONFIG_TOUCHPANEL_GOODIX=y +CONFIG_TOUCHPANEL_SAMSUNG=y +CONFIG_TOUCHPANEL_SYNAPTICS_TCM_ONCELL=y +CONFIG_TOUCHPANEL_GOODIX_GT9886=y +CONFIG_TOUCHPANEL_SAMSUNG_S6SY771=y +CONFIG_TOUCHPANEL_FOCAL=y +CONFIG_TOUCHPANEL_FOCAL_FT3518=y +CONFIG_TOUCHPANEL_NOVA=y +CONFIG_TOUCHPANEL_NOVA_NT36672C_NOFLASH=y +CONFIG_TOUCHPANEL_NT_DIGITALNOISE_TEST=y +CONFIG_TOUCHPANEL_ILITEK=y +CONFIG_TOUCHPANEL_ILITEK_ILITEK7807S=y +# CONFIG_SECURE_TOUCH_SYNAPTICS_DSX is not set CONFIG_TOUCHSCREEN_SYNAPTICS_TCM_REFLASH=y CONFIG_TOUCHSCREEN_SYNAPTICS_TCM_RECOVERY=y -CONFIG_TOUCHSCREEN_FTS=y +CONFIG_TOUCHSCREEN_FTS=n +CONFIG_TOUCHSCREEN_ST=n CONFIG_INPUT_MISC=y CONFIG_INPUT_QPNP_POWER_ON=y CONFIG_INPUT_UINPUT=y @@ -387,12 +431,46 @@ CONFIG_POWER_RESET_QCOM=y CONFIG_POWER_RESET_XGENE=y CONFIG_POWER_RESET_SYSCON=y CONFIG_QPNP_SMB5=y -CONFIG_SMB1390_CHARGE_PUMP_PSY=y +#ifdef OPLUS_FEATURE_CHG_BASIC//tongfeng.Huang@ProDrv.CHG,add 2019/06/22 for charger +CONFIG_OPLUS_SM7250R_CHARGER=y CONFIG_SMB1355_SLAVE_CHARGER=y -CONFIG_QPNP_QG=y -CONFIG_SMB1398_CHARGER=y +CONFIG_OPLUS_CHIP_SOC_NODE=y +CONFIG_OPLUS_QPNP_QG=y +#else +#CONFIG_SMB1390_CHARGE_PUMP_PSY=y +#CONFIG_SMB1398_CHARGER=y +#CONFIG_QPNP_QG=y +#CONFIG_QPNP_FG_GEN4=y +#endif +#ifdef OPLUS_FEATURE_CHG_BASIC +CONFIG_OPLUS_SHORT_HW_CHECK=y +CONFIG_OPLUS_SHORT_USERSPACE=y +CONFIG_OPLUS_SHIP_MODE_SUPPORT=y +CONFIG_OPLUS_SMART_CHARGER_SUPPORT=y +CONFIG_OPLUS_CHARGER_OPTIGA=y +CONFIG_OPLUS_SHORT_C_BATT_CHECK=y +CONFIG_OPLUS_CHECK_CHARGERID_VOLT=y +CONFIG_OPLUS_SHORT_IC_CHECK=y +CONFIG_SONY_FF=y +CONFIG_HID_BETOP_FF=y +CONFIG_HID_PLAYSTATION=y +CONFIG_PLAYSTATION_FF=y +#endif +#ifndef OPLUS_FEATURE_CHG_BASIC//tongfeng.Huang@ProDrv.CHG,add 2019/12/22 for charger +#CONFIG_HL6111R=y +#endif + +#ifdef OPLUS_FEATURE_CHG_BASIC +CONFIG_INPUT_JOYSTICK=y +CONFIG_JOYSTICK_XPAD=y +CONFIG_JOYSTICK_XPAD_FF=y +CONFIG_JOYSTICK_XPAD_LEDS=y +#endif /* OPLUS_FEATURE_CHG_BASIC */ + CONFIG_THERMAL=y -CONFIG_THERMAL_STATISTICS=y +#ifndef OPLUS_FEATURE_THERMAL_STATISTICS +#CONFIG_THERMAL_STATISTICS=y +#endif CONFIG_THERMAL_WRITABLE_TRIPS=y CONFIG_THERMAL_GOV_USER_SPACE=y CONFIG_THERMAL_GOV_LOW_LIMITS=y @@ -403,6 +481,9 @@ CONFIG_THERMAL_TSENS=y CONFIG_QTI_ADC_TM=y CONFIG_QTI_VIRTUAL_SENSOR=y CONFIG_QTI_QMI_SENSOR=y +CONFIG_SSC_INTERACTIVE=y +CONFIG_OPLUS_SENSOR_FB_QC=y +CONFIG_SENSORS_SSC=y CONFIG_QTI_BCL_PMIC5=y CONFIG_QTI_BCL_SOC_DRIVER=y CONFIG_QTI_QMI_COOLING_DEVICE=y @@ -425,6 +506,10 @@ CONFIG_REGULATOR_REFGEN=y CONFIG_REGULATOR_RPMH=y CONFIG_REGULATOR_STUB=y CONFIG_REGULATOR_PM8008=y +#ifdef OPLUS_BUG_STABILITY +CONFIG_REGULATOR_TPS65132=y +CONFIG_REGULATOR_TPS65132_FOR_20267=y +#endif /* OPLUS_BUG_STABILITY */ CONFIG_MEDIA_SUPPORT=y CONFIG_MEDIA_CAMERA_SUPPORT=y CONFIG_MEDIA_DIGITAL_TV_SUPPORT=y @@ -439,6 +524,10 @@ CONFIG_DVB_MPQ_DEMUX=m CONFIG_DVB_MPQ_SW=y CONFIG_VIDEO_V4L2_VIDEOBUF2_CORE=y CONFIG_DRM=y +#ifdef VENDOR_EDIT +CONFIG_DRM_MSM=y +#endif /* VENDOR_EDIT */ +CONFIG_DRM_LONTIUM_LT9611UXC=y CONFIG_BACKLIGHT_LCD_SUPPORT=y CONFIG_BACKLIGHT_CLASS_DEVICE=y CONFIG_BACKLIGHT_QCOM_SPMI_WLED=y @@ -544,6 +633,7 @@ CONFIG_IPA_UT=y CONFIG_USB_BAM=y CONFIG_QCOM_GENI_SE=y # CONFIG_QCOM_A53PLL is not set +# CONFIG_IPA3_REGDUMP is not set CONFIG_QCOM_CLK_RPMH=y CONFIG_SPMI_PMIC_CLKDIV=y CONFIG_MSM_CLK_AOP_QMP=y @@ -560,6 +650,7 @@ CONFIG_SDM_DISPCC_LAGOON=y CONFIG_SDM_GPUCC_LAGOON=y CONFIG_SDM_NPUCC_LAGOON=y CONFIG_SDM_VIDEOCC_LAGOON=y + CONFIG_HWSPINLOCK=y CONFIG_HWSPINLOCK_QCOM=y CONFIG_MAILBOX=y @@ -682,6 +773,15 @@ CONFIG_OVERLAY_FS=y CONFIG_INCREMENTAL_FS=y CONFIG_MSDOS_FS=y CONFIG_VFAT_FS=y +CONFIG_OPLUS_FEATURE_EROFS=y +CONFIG_EROFS_FS=y +#ifdef OPLUS_FEATURE_EXFAT_SUPPORT +CONFIG_NLS_UTF8=y +CONFIG_EXFAT_FS=y +# endif +#ifdef OPLUS_FEATURE_EMMC_SDCARD_OPTIMIZE +CONFIG_EMMC_SDCARD_OPTIMIZE=y +#endif CONFIG_TMPFS=y CONFIG_TMPFS_POSIX_ACL=y CONFIG_EFIVAR_FS=y @@ -708,7 +808,7 @@ CONFIG_CRYPTO_DEV_QCEDEV=y CONFIG_XZ_DEC=y CONFIG_PRINTK_TIME=y CONFIG_DYNAMIC_DEBUG=y -CONFIG_DEBUG_CONSOLE_UNHASHED_POINTERS=y +# CONFIG_DEBUG_CONSOLE_UNHASHED_POINTERS is not set CONFIG_DEBUG_MODULE_LOAD_INFO=y CONFIG_DEBUG_INFO=y CONFIG_PAGE_OWNER=y @@ -722,15 +822,20 @@ CONFIG_DEBUG_PANIC_ON_OOM=y CONFIG_DEBUG_PAGEALLOC_ENABLE_DEFAULT=y CONFIG_PAGE_POISONING=y CONFIG_PAGE_POISONING_ENABLE_DEFAULT=y -CONFIG_SLUB_DEBUG_ON=y -CONFIG_DEBUG_KMEMLEAK=y +#ifndef VENDOR_EDIT +#CONFIG_SLUB_DEBUG_ON=y +#CONFIG_DEBUG_KMEMLEAK=y +#else +CONFIG_DEBUG_KMEMLEAK=n +CONFIG_HAVE_DEBUG_KMEMLEAK=n +#endif//VENDOR_EDIT CONFIG_DEBUG_KMEMLEAK_EARLY_LOG_SIZE=4000 CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF=y CONFIG_DEBUG_STACK_USAGE=y CONFIG_DEBUG_MEMORY_INIT=y CONFIG_SOFTLOCKUP_DETECTOR=y CONFIG_WQ_WATCHDOG=y -CONFIG_PANIC_TIMEOUT=5 +CONFIG_PANIC_TIMEOUT=-1 CONFIG_PANIC_ON_SCHED_BUG=y CONFIG_PANIC_ON_RT_THROTTLING=y CONFIG_SCHEDSTATS=y @@ -752,8 +857,9 @@ CONFIG_IPC_LOGGING=y CONFIG_QCOM_RTB=y CONFIG_QCOM_RTB_SEPARATE_CPUS=y CONFIG_FUNCTION_TRACER=y -CONFIG_PREEMPTIRQ_EVENTS=y -CONFIG_IRQSOFF_TRACER=y +#ifndef VENDOR_EDIT +#CONFIG_PREEMPTIRQ_EVENTS=y +#endif//VENDOR_EDITCONFIG_IRQSOFF_TRACER=y CONFIG_PREEMPT_TRACER=y CONFIG_BLK_DEV_IO_TRACE=y CONFIG_LKDTM=m @@ -775,3 +881,269 @@ CONFIG_CORESIGHT_HWEVENT=y CONFIG_CORESIGHT_DUMMY=y CONFIG_CORESIGHT_REMOTE_ETM=y CONFIG_CORESIGHT_TGU=y +#ifdef OPLUS_SYSTEM_KERNEL +#/*Add for oplus project*/ +CONFIG_OPLUS_COMMON_SOFT=y +CONFIG_OPLUS_DEVICE_IFNO=y +CONFIG_OPLUS_RF_CABLE_MONITOR=y +CONFIG_RECORD_MDMRST=y +#endif +#ifdef OPLUS_FEATURE_POWERINFO_STANDBY +CONFIG_OPLUS_WAKELOCK_PROFILER=y +#endif /* OPLUS_FEATURE_POWERINFO_STANDBY */ +# ifdef VENDOR_EDIT +CONFIG_CS_F61_NDT=y +# endif /* VENDOR_EDIT */ + +#ifdef OPLUS_SYSTEM_KERNEL +#all system oplus feature writer here +CONFIG_OPLUS_FEATURE_UBOOT_LOG=y +CONFIG_DETECT_HUNG_TASK=y +CONFIG_OPLUS_FEATURE_HUNG_TASK_ENHANCE=y +CONFIG_DEFAULT_HUNG_TASK_TIMEOUT=60 +CONFIG_OPLUS_FEATURE_FEEDBACK=y +CONFIG_OPLUS_FEATURE_OPROJECT=y +CONFIG_OPLUS_FEATURE_CMDLINE=y +CONFIG_OPLUS_FEATURE_PROJECTINFO=y +CONFIG_OPLUS_FEATURE_PHOENIX=y +CONFIG_OPLUS_FEATURE_PHOENIX_REBOOT_SPEED=y +CONFIG_OPLUS_FEATURE_KMSG_WB=y +CONFIG_OPLUS_FEATURE_SHUTDOWN_SPEED=y +CONFIG_OPLUS_FEATURE_OLC=y +CONFIG_OPLUS_FEATURE_FDLEAK_CHECK=y +#add for qcom minidump customized +CONFIG_OPLUS_FEATURE_QCOM_MINIDUMP_ENHANCE=y +#Add for shutdown detect +CONFIG_OPLUS_FEATURE_SHUTDOWN_DETECT=y +#add slabtrace function +CONFIG_OPLUS_FEATURE_SLABTRACE_DEBUG=y +#enable oplus misc feature +#CONFIG_OPLUS_FEATURE_MISC is not set +#endif +#ifdef OPLUS_FEATURE_QCOM_PMICWD +#Add for qcom pmic watchdog +CONFIG_OPLUS_FEATURE_QCOM_PMICWD=y +#endif +#ifdef OPLUS_FEATURE_FINGERPRINT +CONFIG_OPLUS_FINGERPRINT=y +CONFIG_OPLUS_FINGERPRINT_QCOM=y +CONFIG_OPLUS_FINGERPRINT_GOODIX_OPTICAL=y +CONFIG_OPLUS_FINGERPRINT_JIIOV_OPTICAL=y +CONFIG_OPLUS_FINGERPRINT_SILEAD=y +CONFIG_OPLUS_FINGERPRINT_GOODIX=y +#endif +CONFIG_OPLUS_FINGERPRINT_GKI_DISABLE=y + +#ifdef OPLUS_FEATURE_SECURITY_COMMON +CONFIG_OPLUS_SECURE=y +CONFIG_OPLUS_SECURE_QCOM=y +CONFIG_OPLUS_SECURE_COMMON=y +#endif /* OPLUS_FEATURE_SECURITY_COMMON */ +#ifdef OPLUS_FEATURE_HANS_FREEZE +CONFIG_OPLUS_HANS=y +#endif /*OPLUS_FEATURE_HANS_FREEZE*/ +#ifdef VENDOR_EDIT//Qingjun.Wang@BSP.Haptic,add 2020/03/17 for vib aw8697 +CONFIG_AW8697_HAPTIC=y +#endif +#ifdef OPLUS_FEATURE_HEALTHINFO +CONFIG_OPLUS_MEM_MONITOR=y +CONFIG_FG_TASK_UID=y +CONFIG_OPLUS_HEALTHINFO=y +CONFIG_SLUB_DEBUG=y +#endif /* OPLUS_FEATURE_HEALTHINFO */ +#ifdef OPLUS_FEATURE_HEALTHINFO +CONFIG_OPLUS_JANK_INFO=y +#endif /* OPLUS_FEATURE_HEALTHINFO */ + +#ifdef OPLUS_FEATURE_ZRAM_OPT +CONFIG_OPLUS_ZRAM_OPT=y +CONFIG_CRYPTO_LZ4=y +CONFIG_PGTABLE_MAPPING=y +CONFIG_CRYPTO_ZSTD=y +#endif + +#ifdef OPLUS_FEATURE_MULTI_KSWAPD +CONFIG_OPLUS_MULTI_KSWAPD=y +CONFIG_KSWAPD_UNBIND_MAX_CPU=y +#endif + +#ifdef VENDOR_EDIT +CONFIG_REGULATOR_PM8008=y + +#ifdef OPLUS_FEATURE_DUMPDEVICE +CONFIG_PSTORE=y +CONFIG_PSTORE_CONSOLE=y +CONFIG_PSTORE_PMSG=y +CONFIG_PSTORE_RAM=y +#endif + +#ifdef OPLUS_FEATURE_IOMONITOR +CONFIG_IOMONITOR=y +#CONFIG_IOMONITOR_WITH_F2FS=n +#endif /*OPLUS_FEATURE_IOMONITOR*/ + +CONFIG_OPLUS_FEATURE_PMIC_MONITOR=y + +CONFIG_OPLUS_FEATURE_OF2FS=y +CONFIG_OPLUS_FEATURE_PANIC_FLUSH=y +CONFIG_OPLUS_FEATURE_OEXT4=y +CONFIG_F2FS_BD_STAT=y +#CONFIG_F2FS_GRADING_SSR is not set + +#ifdef OPLUS_FEATURE_LOWMEM_DBG +CONFIG_OPLUS_FEATURE_LOWMEM_DBG=y +#endif /* OPLUS_FEATURE_LOWMEM_DBG */ + +#ifdef OPLUS_FEATURE_SCHED_ASSIST +CONFIG_BLK_WBT_SQ=y +CONFIG_BLK_WBT=y +CONFIG_OPLUS_FEATURE_UXIO_FIRST=y +#endif /*OPLUS_FEATURE_SCHED_ASSIST*/ + +#ifdef OPLUS_FEATURE_MEMLEAK_DETECT +CONFIG_KMALLOC_DEBUG=y +CONFIG_VMALLOC_DEBUG=y +CONFIG_DUMP_TASKS_MEM=y +#endif /*OPLUS_FEATURE_MEMLEAK_DETECT*/ + +#ifdef OPLUS_FEATURE_MEMLEAK_DETECT +CONFIG_SVELTE=y +#endif + +#ifdef VEDOR_EDIT +CONFIG_OPLUS_FEATURE_RECORD_MDMRST=y +#endif +#ifdef OPLUS_ARCH_EXTENDS +CONFIG_OPLUS_FEATURE_MM_FEEDBACK=y +#endif + +#ifdef OPLUS_FEATURE_MIDAS +CONFIG_OPLUS_FEATURE_MIDAS=y +#endif + +#ifdef CONFIG_OPLUS_FEATURE_BINDER_STATS_ENABLE +CONFIG_OPLUS_FEATURE_BINDER_STATS_ENABLE=y +#endif + +#ifdef OPLUS_FEATURE_ACM +CONFIG_OPLUS_FEATURE_ACM=y +CONFIG_OPLUS_FEATURE_ACM_LOGGING=y +#endif /* OPLUS_FEATURE_ACM */ +#ifdef OPLUS_BUG_STABILITY +CONFIG_HARDEN_BRANCH_PREDICTOR=y +#endif +CONFIG_OPLUS_FEATURE_THEIA=y +##endif /* OPLUS_FEATURE_THEIA */ + +#ifdef OPLUS_FEATURE_SAUPWK +CONFIG_OPLUS_FEATURE_SAUPWK=y +#endif /* OPLUS_FEATURE_SAUPWK */ + +#ifdef OPLUS_FEATURE_DUMP_DEVICE_INFO +CONFIG_OPLUS_FEATURE_DUMP_DEVICE_INFO=y +#endif /* OPLUS_FEATURE_DUMP_DEVICE_INFO */ + +#ifdef OPLUS_BUG_STABILITY +CONFIG_UNMAP_KERNEL_AT_EL0=y +#endif + +#ifdef OPLUS_FEATURE_GPIO_NC +CONFIG_OPLUS_GPIO_NC=y +#endif + +#ifdef OPLUS_FEATURE_BOOTLOADER_LOG +CONFIG_BOOTLOADER_LOG=y +#endif +#ifdef OPLUS_FEATURE_PARAM +CONFIG_PARAM_READ_WRITE=y +#endif + +#ifdef OPLUS_FEATURE_TP_BASIC +CONFIG_SIM_DETECT=y +#endif + +#ifdef OPLUS_FEATURE_TP_BASIC +CONFIG_OPLUS_FW_UPDATE=y +#endif /*OPLUS_FEATURE_TP_BASIC*/ + +#ifdef OPLUS_FEATURE_ION_BOOSTPOOL +#CONFIG_OPLUS_ION_BOOSTPOOL=y ,Add for disable boost pool ,fill generic ION POOL +#endif /* OPLUS_FEATURE_ION_BOOSTPOOL */ + +#ifdef OPLUS_FEATURE_WIFI_SLA +#todo: need to change to m when GKI +CONFIG_OPLUS_FEATURE_WIFI_SLA=y +#endif /* OPLUS_FEATURE_WIFI_SLA */ + +#ifdef OPLUS_FEATURE_WIFI_ROUTERBOOST +CONFIG_OPLUS_FEATURE_WIFI_ROUTERBOOST=m +#endif /* OPLUS_FEATURE_WIFI_ROUTERBOOST */ + +#ifdef OPLUS_FEATURE_DATA_EVAL +CONFIG_OPLUS_FEATURE_DATA_EVAL=y +#endif /* OPLUS_FEATURE_DATA_VAL */ + +#ifdef OPLUS_FEATURE_DATA_LIMIT +CONFIG_IFB=y +CONFIG_NET_SCH_MULTIQ=y +CONFIG_NET_SCH_NETEM=y +CONFIG_CLS_U32_MARK=y +CONFIG_NET_CLS_FLOW=y +CONFIG_NET_EMATCH_CMP=y +CONFIG_NET_EMATCH_NBYTE=y +CONFIG_NET_EMATCH_META=y +CONFIG_NET_EMATCH_TEXT=y +CONFIG_NET_ACT_GACT=y +CONFIG_NET_ACT_MIRRED=y +CONFIG_NET_ACT_SKBEDIT=y +#endif /* OPLUS_FEATURE_DATA_LIMIT */ + +CONFIG_DEBUG_SPINLOCK=y + +#CONFIG_NANDSWAP=y +#CONFIG_NANDSWAP_DEBUG=y +#ifdef OPLUS_FEATURE_IM +#ted.lin@optimization add for im module +CONFIG_OPLUS_FEATURE_IM=y +#endif /* OPLUS_FEATURE_IM */ + +CONFIG_FRAME_WARN=4096 + +CONFIG_DYNAMIC_TUNNING_SWAPPINESS=y + +#ifdef OPLUS_FEATURE_HYBRIDSWAP +CONFIG_HYBRIDSWAP=y +CONFIG_HYBRIDSWAP_SWAPD=y +CONFIG_HYBRIDSWAP_CORE=y +#endif + +#ifdef OPLUS_FEATURE_UID_PERF +CONFIG_OPLUS_FEATURE_UID_PERF=y +#endif + +#ifdef OPLUS_FEATURE_ESIM +CONFIG_OPLUS_GPIO=y +#endif /* OPLUS_FEATURE_ESIM */ + +#ifdef OPLUS_FEATURE_DNS_HOOK +CONFIG_OPLUS_FEATURE_DNS_HOOK=y +#endif /* OPLUS_FEATURE_DNS_HOOK */ + +#ifdef OPLUS_FEATURE_STATS_CALC +CONFIG_OPLUS_FEATURE_STATS_CALC=y +#endif /* OPLUS_FEATURE_STATS_CALC */ + +#ifdef OPLUS_FEATURE_TPD +CONFIG_OPLUS_FEATURE_TPD=y +#endif + +#ifdef OPLUS_FEATURE_MDMFEATURE +CONFIG_OPLUS_FEATURE_MDMFEATURE=y +#endif + +#ifdef OPLUS_FEATURE_GAME_OPT +CONFIG_OPLUS_FEATURE_GAME_OPT=y +#endif +CONFIG_OPLUS_BINDER_STRATEGY=n + +CONFIG_OPLUS_FEATURE_CPU_JANKINFO=y diff --git a/arch/arm64/include/asm/cacheflush.h b/arch/arm64/include/asm/cacheflush.h index 3f8a615bfc82..87aa95b97955 100644 --- a/arch/arm64/include/asm/cacheflush.h +++ b/arch/arm64/include/asm/cacheflush.h @@ -200,5 +200,4 @@ static inline void flush_cache_vunmap(unsigned long start, unsigned long end) } int set_memory_valid(unsigned long addr, int numpages, int enable); - #endif diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h index c5bd9a724319..57432c316c61 100644 --- a/arch/arm64/include/asm/cpufeature.h +++ b/arch/arm64/include/asm/cpufeature.h @@ -571,6 +571,20 @@ enum mitigation_state arm64_get_spectre_bhb_state(void); bool is_spectre_bhb_affected(const struct arm64_cpu_capabilities *entry, int scope); u8 spectre_bhb_loop_affected(int scope); void spectre_bhb_enable_mitigation(const struct arm64_cpu_capabilities *__unused); + +/* Check whether hardware update of the Access flag is supported */ +static inline bool cpu_has_hw_af(void) +{ + u64 mmfr1; + + if (!IS_ENABLED(CONFIG_ARM64_HW_AFDBM)) + return false; + + mmfr1 = read_cpuid(ID_AA64MMFR1_EL1); + return cpuid_feature_extract_unsigned_field(mmfr1, + ID_AA64MMFR1_HADBS_SHIFT); +} + #endif /* __ASSEMBLY__ */ #endif diff --git a/arch/arm64/include/asm/io.h b/arch/arm64/include/asm/io.h index 3b21bcd2c1cd..d7c1263282d8 100644 --- a/arch/arm64/include/asm/io.h +++ b/arch/arm64/include/asm/io.h @@ -115,9 +115,20 @@ static inline u64 __raw_readq_no_log(const volatile void __iomem *addr) LOG_BARRIER; \ }) +#ifdef OPLUS_FEATURE_CHG_BASIC +#define __raw_write_logged_oplus_vooc(v, a, _t) ({ \ + volatile void __iomem *_a = (a); \ + __raw_write##_t##_no_log((v), _a); \ + }) +#endif /* OPLUS_FEATURE_CHG_BASIC */ + #define __raw_writeb(v, a) __raw_write_logged((v), a, b) #define __raw_writew(v, a) __raw_write_logged((v), a, w) #define __raw_writel(v, a) __raw_write_logged((v), a, l) +#ifdef OPLUS_FEATURE_CHG_BASIC +#define __raw_writel_oplus_vooc(v, a) __raw_write_logged_oplus_vooc((v), a, l) +#endif /* OPLUS_FEATURE_CHG_BASIC */ + #define __raw_writeq(v, a) __raw_write_logged((v), a, q) #define __raw_read_logged(a, _l, _t) ({ \ @@ -132,9 +143,20 @@ static inline u64 __raw_readq_no_log(const volatile void __iomem *addr) __a; \ }) +#ifdef OPLUS_FEATURE_CHG_BASIC +#define __raw_read_logged_oplus_vooc(a, _l, _t) ({ \ + _t __a; \ + const volatile void __iomem *_a = (const volatile void __iomem *)(a); \ + __a = __raw_read##_l##_no_log(_a); \ + }) +#endif /* OPLUS_FEATURE_CHG_BASIC */ + #define __raw_readb(a) __raw_read_logged((a), b, u8) #define __raw_readw(a) __raw_read_logged((a), w, u16) #define __raw_readl(a) __raw_read_logged((a), l, u32) +#ifdef OPLUS_FEATURE_CHG_BASIC +#define __raw_readl_oplus_vooc(a) __raw_read_logged_oplus_vooc((a), l, u32) +#endif /* OPLUS_FEATURE_CHG_BASIC */ #define __raw_readq(a) __raw_read_logged((a), q, u64) /* IO barriers */ @@ -167,11 +189,18 @@ static inline u64 __raw_readq_no_log(const volatile void __iomem *addr) #define readb_relaxed(c) ({ u8 __r = __raw_readb(c); __r; }) #define readw_relaxed(c) ({ u16 __r = le16_to_cpu((__force __le16)__raw_readw(c)); __r; }) #define readl_relaxed(c) ({ u32 __r = le32_to_cpu((__force __le32)__raw_readl(c)); __r; }) +#ifdef OPLUS_FEATURE_CHG_BASIC +#define readl_relaxed_oplus_vooc(c) ({ u32 __r = le32_to_cpu((__force __le32)__raw_readl_oplus_vooc(c)); __r; }) +#endif /* OPLUS_FEATURE_CHG_BASIC */ #define readq_relaxed(c) ({ u64 __r = le64_to_cpu((__force __le64)__raw_readq(c)); __r; }) #define writeb_relaxed(v,c) ((void)__raw_writeb((v),(c))) #define writew_relaxed(v,c) ((void)__raw_writew((__force u16)cpu_to_le16(v),(c))) #define writel_relaxed(v,c) ((void)__raw_writel((__force u32)cpu_to_le32(v),(c))) +#ifdef OPLUS_FEATURE_CHG_BASIC +#define writel_relaxed_oplus_vooc(v,c) ((void)__raw_writel_oplus_vooc((__force u32)cpu_to_le32(v),(c))) +#endif /* OPLUS_FEATURE_CHG_BASIC */ + #define writeq_relaxed(v,c) ((void)__raw_writeq((__force u64)cpu_to_le64(v),(c))) #define readb_relaxed_no_log(c) ({ u8 __v = __raw_readb_no_log(c); __v; }) @@ -198,11 +227,17 @@ static inline u64 __raw_readq_no_log(const volatile void __iomem *addr) #define readb(c) ({ u8 __v = readb_relaxed(c); __iormb(__v); __v; }) #define readw(c) ({ u16 __v = readw_relaxed(c); __iormb(__v); __v; }) #define readl(c) ({ u32 __v = readl_relaxed(c); __iormb(__v); __v; }) +#ifdef OPLUS_FEATURE_CHG_BASIC +#define readl_oplus_vooc(c) ({ u32 __v = readl_relaxed_oplus_vooc(c); __v; }) +#endif /* OPLUS_FEATURE_CHG_BASIC */ #define readq(c) ({ u64 __v = readq_relaxed(c); __iormb(__v); __v; }) #define writeb(v,c) ({ __iowmb(); writeb_relaxed((v),(c)); }) #define writew(v,c) ({ __iowmb(); writew_relaxed((v),(c)); }) #define writel(v,c) ({ __iowmb(); writel_relaxed((v),(c)); }) +#ifdef OPLUS_FEATURE_CHG_BASIC +#define writel_oplus_vooc(v,c) ({ writel_relaxed_oplus_vooc((v),(c)); }) +#endif /* OPLUS_FEATURE_CHG_BASIC */ #define writeq(v,c) ({ __iowmb(); writeq_relaxed((v),(c)); }) #define readb_no_log(c) \ diff --git a/arch/arm64/include/asm/pgtable-prot.h b/arch/arm64/include/asm/pgtable-prot.h index af547be1779b..c42d954b89db 100644 --- a/arch/arm64/include/asm/pgtable-prot.h +++ b/arch/arm64/include/asm/pgtable-prot.h @@ -32,6 +32,7 @@ #ifndef __ASSEMBLY__ +#include #include #define _PROT_DEFAULT (PTE_TYPE_PAGE | PTE_AF | PTE_SHARED) diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h index 10c1ff13b992..14183ed6057e 100644 --- a/arch/arm64/include/asm/pgtable.h +++ b/arch/arm64/include/asm/pgtable.h @@ -782,6 +782,8 @@ extern pgd_t tramp_pg_dir[PTRS_PER_PGD]; extern int kern_addr_valid(unsigned long addr); +#define arch_has_hw_pte_young cpu_has_hw_af + #include void pgd_cache_init(void); diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile index f0d7f22fae63..7fc27fba97c4 100644 --- a/arch/arm64/kernel/Makefile +++ b/arch/arm64/kernel/Makefile @@ -73,3 +73,7 @@ extra-y += $(head-y) vmlinux.lds ifeq ($(CONFIG_DEBUG_EFI),y) AFLAGS_head.o += -DVMLINUX_PATH="\"$(realpath $(objtree)/vmlinux)\"" endif + +#ifdef CONFIG_OPLUS_SECURE_GUARD +obj-$(CONFIG_OPLUS_SECURE_GUARD) += rootguard/ +#endif /* CONFIG_OPLUS_SECURE_GUARD */ \ No newline at end of file diff --git a/arch/arm64/kernel/asm-offsets.c b/arch/arm64/kernel/asm-offsets.c index b8f83cfe43f3..cd4153f72c3f 100644 --- a/arch/arm64/kernel/asm-offsets.c +++ b/arch/arm64/kernel/asm-offsets.c @@ -180,6 +180,21 @@ int main(void) #ifdef CONFIG_UNMAP_KERNEL_AT_EL0 DEFINE(TRAMP_VALIAS, TRAMP_VALIAS); #endif + +#ifdef CONFIG_OPLUS_SECURE_GUARD +#ifdef CONFIG_OPLUS_ROOT_CHECK + DEFINE(PROOT_TSK_CRED, offsetof(struct task_struct, cred)); + DEFINE(PROOT_CRED_UID, offsetof(struct cred, uid)); + DEFINE(PROOT_CRED_EUID, offsetof(struct cred, euid)); + DEFINE(PROOT_CRED_FSUID, offsetof(struct cred, fsuid)); +#ifdef CONFIG_THREAD_INFO_IN_TASK + DEFINE(PROOT_THREAD_ADDR_LIMIT, offsetof(struct task_struct, thread_info.addr_limit)); +#else + DEFINE(PROOT_THREAD_TSK, offsetof(struct thread_info,task)); + DEFINE(PROOT_THREAD_ADDR_LIMIT, offsetof(struct thread_info, addr_limit)); +#endif +#endif /* CONFIG_OPLUS_ROOT_CHECK */ +#endif /* CONFIG_OPLUS_SECURE_GUARD */ #ifdef CONFIG_ARM_SDE_INTERFACE DEFINE(SDEI_EVENT_INTREGS, offsetof(struct sdei_registered_event, interrupted_regs)); DEFINE(SDEI_EVENT_PRIORITY, offsetof(struct sdei_registered_event, priority)); diff --git a/arch/arm64/kernel/kaslr.c b/arch/arm64/kernel/kaslr.c index 92bb53460401..8507e89bd4d3 100644 --- a/arch/arm64/kernel/kaslr.c +++ b/arch/arm64/kernel/kaslr.c @@ -35,6 +35,13 @@ static __init u64 get_kaslr_seed(void *fdt) if (node < 0) return 0; +#ifdef OPLUS_BUG_STABILITY +/* Aging/kasan version disable kaslr, easier to analysis problem */ +#ifdef CONFIG_KASAN + return 0; +#endif +#endif + prop = fdt_getprop_w(fdt, node, "kaslr-seed", &len); if (!prop || len != sizeof(u64)) return 0; diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c index 152514428ac8..dcd55c0b54c4 100644 --- a/arch/arm64/kernel/process.c +++ b/arch/arm64/kernel/process.c @@ -68,6 +68,8 @@ unsigned long __stack_chk_guard __ro_after_init; EXPORT_SYMBOL(__stack_chk_guard); #endif +#ifndef CONFIG_OPLUS_FEATURE_QCOM_MINIDUMP_ENHANCE + /* * Function pointers to optional machine specific functions */ @@ -77,6 +79,19 @@ EXPORT_SYMBOL_GPL(pm_power_off); void (*arm_pm_restart)(enum reboot_mode reboot_mode, const char *cmd); EXPORT_SYMBOL_GPL(arm_pm_restart); +#else + +#include + +/* + * Function pointers to optional machine specific functions + */ +void (*pm_power_off)(void) = do_poweroff_early; +EXPORT_SYMBOL_GPL(pm_power_off); +void (*arm_pm_restart)(enum reboot_mode reboot_mode, const char *cmd) = do_restart_early; + +#endif /* CONFIG_OPLUS_FEATURE_QCOM_MINIDUMP_ENHANCE */ + /* * This is our default idle handler. */ @@ -289,13 +304,18 @@ void __show_regs(struct pt_regs *regs) sp = regs->sp; top_reg = 29; } - + show_regs_print_info(KERN_DEFAULT); print_pstate(regs); if (!user_mode(regs)) { printk("pc : %pS\n", (void *)regs->pc); printk("lr : %pS\n", (void *)lr); +#ifdef CONFIG_OPLUS_FEATURE_QCOM_MINIDUMP_ENHANCE + printk("pc : %016llx\n", regs->pc); + printk("lr : %016llx\n", lr); +#endif + } else { printk("pc : %016llx\n", regs->pc); printk("lr : %016llx\n", lr); diff --git a/arch/arm64/kernel/rootguard b/arch/arm64/kernel/rootguard new file mode 120000 index 000000000000..87d3ea33cfb5 --- /dev/null +++ b/arch/arm64/kernel/rootguard @@ -0,0 +1 @@ +../../../../../vendor/oplus/kernel/secureguard/rootguard \ No newline at end of file diff --git a/arch/arm64/kernel/syscall.c b/arch/arm64/kernel/syscall.c index f2d2dbbbfca2..223ba6f9fec1 100644 --- a/arch/arm64/kernel/syscall.c +++ b/arch/arm64/kernel/syscall.c @@ -17,6 +17,11 @@ long compat_arm_syscall(struct pt_regs *regs, int scno); long sys_ni_syscall(void); +#ifdef CONFIG_OPLUS_SECURE_GUARD +extern void oplus_invoke_syscall(struct pt_regs *regs, unsigned int scno, + unsigned int sc_nr, + const syscall_fn_t syscall_table[]); +#else static long do_ni_syscall(struct pt_regs *regs, int scno) { #ifdef CONFIG_COMPAT @@ -41,7 +46,6 @@ static void invoke_syscall(struct pt_regs *regs, unsigned int scno, const syscall_fn_t syscall_table[]) { long ret; - if (scno < sc_nr) { syscall_fn_t syscall_fn; syscall_fn = syscall_table[array_index_nospec(scno, sc_nr)]; @@ -55,6 +59,7 @@ static void invoke_syscall(struct pt_regs *regs, unsigned int scno, regs->regs[0] = ret; } +#endif /* CONFIG_OPLUS_SECURE_GUARD */ static inline bool has_syscall_work(unsigned long flags) { @@ -113,9 +118,11 @@ static void el0_svc_common(struct pt_regs *regs, int scno, int sc_nr, if (scno == NO_SYSCALL) goto trace_exit; } - +#ifdef CONFIG_OPLUS_SECURE_GUARD + oplus_invoke_syscall(regs, scno, sc_nr, syscall_table); +#else invoke_syscall(regs, scno, sc_nr, syscall_table); - +#endif /* CONFIG_OPLUS_SECURE_GUARD */ /* * The tracing status may have changed under our feet, so we have to * check again. However, if we were tracing entry, then we always trace diff --git a/arch/arm64/mm/arch_mmap.h b/arch/arm64/mm/arch_mmap.h new file mode 120000 index 000000000000..226371c1811c --- /dev/null +++ b/arch/arm64/mm/arch_mmap.h @@ -0,0 +1 @@ +../../../../../vendor/oplus/kernel/oplus_performance/gloom_new/arch_mmap.h \ No newline at end of file diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c index 5e9df5bd73df..40badc1ad228 100644 --- a/arch/arm64/mm/fault.c +++ b/arch/arm64/mm/fault.c @@ -48,6 +48,9 @@ #include #include +#if defined(OPLUS_FEATURE_IOMONITOR) && defined(CONFIG_IOMONITOR) +#include +#endif /*OPLUS_FEATURE_IOMONITOR*/ struct fault_info { int (*fn)(unsigned long addr, unsigned int esr, @@ -567,6 +570,9 @@ done: */ if (major) { tsk->maj_flt++; +#if defined(OPLUS_FEATURE_IOMONITOR) && defined(CONFIG_IOMONITOR) + iomonitor_update_fs_stats(FS_MAJOR_FAULT, 1); +#endif /*OPLUS_FEATURE_IOMONITOR*/ perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MAJ, 1, regs, addr); } else { diff --git a/arch/arm64/mm/mmap.c b/arch/arm64/mm/mmap.c index 157f2caa1351..9d35b52e3108 100644 --- a/arch/arm64/mm/mmap.c +++ b/arch/arm64/mm/mmap.c @@ -30,6 +30,9 @@ #include #include +#if defined(OPLUS_FEATURE_VIRTUAL_RESERVE_MEMORY) && defined(CONFIG_VIRTUAL_RESERVE_MEMORY) +#include "arch_mmap.h" +#endif /* * Leave enough space between the mmap area and the stack to honour ulimit in diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index a12dc211399f..2912ef832881 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -62,6 +62,7 @@ config X86 select ARCH_HAS_PMEM_API if X86_64 select ARCH_HAS_PTE_SPECIAL select ARCH_HAS_REFCOUNT + select ARCH_HAS_NONLEAF_PMD_YOUNG select ARCH_HAS_UACCESS_FLUSHCACHE if X86_64 select ARCH_HAS_UACCESS_MCSAFE if X86_64 && X86_MCE select ARCH_HAS_SET_MEMORY diff --git a/arch/x86/include/asm/pgtable.h b/arch/x86/include/asm/pgtable.h index 7de459cf36b5..f3ca6a3e2644 100644 --- a/arch/x86/include/asm/pgtable.h +++ b/arch/x86/include/asm/pgtable.h @@ -826,7 +826,8 @@ static inline pte_t *pte_offset_kernel(pmd_t *pmd, unsigned long address) static inline int pmd_bad(pmd_t pmd) { - return (pmd_flags(pmd) & ~_PAGE_USER) != _KERNPG_TABLE; + return (pmd_flags(pmd) & ~(_PAGE_USER | _PAGE_ACCESSED)) != + (_KERNPG_TABLE & ~_PAGE_ACCESSED); } static inline unsigned long pages_to_mb(unsigned long npg) @@ -1442,6 +1443,12 @@ static inline bool arch_has_pfn_modify_check(void) return boot_cpu_has_bug(X86_BUG_L1TF); } +#define arch_has_hw_pte_young arch_has_hw_pte_young +static inline bool arch_has_hw_pte_young(void) +{ + return true; +} + #include #endif /* __ASSEMBLY__ */ diff --git a/arch/x86/mm/pgtable.c b/arch/x86/mm/pgtable.c index c0e9c00402ac..71b8d760bc3a 100644 --- a/arch/x86/mm/pgtable.c +++ b/arch/x86/mm/pgtable.c @@ -560,7 +560,7 @@ int ptep_test_and_clear_young(struct vm_area_struct *vma, return ret; } -#ifdef CONFIG_TRANSPARENT_HUGEPAGE +#if defined(CONFIG_TRANSPARENT_HUGEPAGE) || defined(CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG) int pmdp_test_and_clear_young(struct vm_area_struct *vma, unsigned long addr, pmd_t *pmdp) { @@ -572,6 +572,9 @@ int pmdp_test_and_clear_young(struct vm_area_struct *vma, return ret; } +#endif + +#ifdef CONFIG_TRANSPARENT_HUGEPAGE int pudp_test_and_clear_young(struct vm_area_struct *vma, unsigned long addr, pud_t *pudp) { diff --git a/block/Kconfig b/block/Kconfig index d4f96c78862e..4a0e44ef7b36 100644 --- a/block/Kconfig +++ b/block/Kconfig @@ -36,7 +36,7 @@ config LBDAF This option is required to support the full capacity of large (2TB+) block devices, including RAID, disk, Network Block Device, Logical Volume Manager (LVM) and loopback. - + This option also enables support for single files larger than 2TB. @@ -246,3 +246,7 @@ config BLK_MQ_RDMA default y source block/Kconfig.iosched + +#ifdef OPLUS_FEATURE_SCHED_ASSIST +source block/uxio_first/Kconfig +#endif diff --git a/block/Makefile b/block/Makefile index a2e05332682f..ab08e77d657f 100644 --- a/block/Makefile +++ b/block/Makefile @@ -39,4 +39,7 @@ obj-$(CONFIG_BLK_DEBUG_FS_ZONED)+= blk-mq-debugfs-zoned.o obj-$(CONFIG_BLK_SED_OPAL) += sed-opal.o obj-$(CONFIG_BLK_INLINE_ENCRYPTION) += keyslot-manager.o bio-crypt-ctx.o \ blk-crypto.o -obj-$(CONFIG_BLK_INLINE_ENCRYPTION_FALLBACK) += blk-crypto-fallback.o \ No newline at end of file +obj-$(CONFIG_BLK_INLINE_ENCRYPTION_FALLBACK) += blk-crypto-fallback.o +#ifdef OPLUS_FEATURE_SCHED_ASSIST +obj-$(CONFIG_OPLUS_FEATURE_UXIO_FIRST) += uxio_first/ +#endif /*OPLUS_FEATURE_SCHED_ASSIST*/ diff --git a/block/blk-core.c b/block/blk-core.c index d3a6da3012a4..cf73c525be8f 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -46,6 +46,14 @@ #include "blk-mq-sched.h" #include "blk-rq-qos.h" +#if defined(OPLUS_FEATURE_IOMONITOR) && defined(CONFIG_IOMONITOR) +#include +#endif /*OPLUS_FEATURE_IOMONITOR*/ + +#if defined(OPLUS_FEATURE_SCHED_ASSIST) && defined(CONFIG_OPLUS_FEATURE_UXIO_FIRST) +#include "uxio_first/uxio_first_opt.h" +#endif + #ifdef CONFIG_DEBUG_FS struct dentry *blk_debugfs_root; #endif @@ -190,6 +198,9 @@ void blk_rq_init(struct request_queue *q, struct request *rq) memset(rq, 0, sizeof(*rq)); INIT_LIST_HEAD(&rq->queuelist); +#if defined(OPLUS_FEATURE_SCHED_ASSIST) && defined(CONFIG_OPLUS_FEATURE_UXIO_FIRST) + INIT_LIST_HEAD(&rq->ux_fg_bg_list); +#endif INIT_LIST_HEAD(&rq->timeout_list); rq->cpu = -1; rq->q = q; @@ -1016,6 +1027,11 @@ struct request_queue *blk_alloc_queue_node(gfp_t gfp_mask, int node_id, return NULL; INIT_LIST_HEAD(&q->queue_head); +#if defined(OPLUS_FEATURE_SCHED_ASSIST) && defined(CONFIG_OPLUS_FEATURE_UXIO_FIRST) + INIT_LIST_HEAD(&q->ux_head); + INIT_LIST_HEAD(&q->fg_head); + INIT_LIST_HEAD(&q->bg_head); +#endif q->last_merge = NULL; q->end_sector = 0; q->boundary_rq = NULL; @@ -1476,7 +1492,9 @@ out: */ if (ioc_batching(q, ioc)) ioc->nr_batch_requests--; - +#if defined(OPLUS_FEATURE_IOMONITOR) && defined(CONFIG_IOMONITOR) + iomonitor_init_reqstats(rq); +#endif /*OPLUS_FEATURE_IOMONITOR*/ trace_block_getrq(q, bio, op); return rq; @@ -1774,8 +1792,11 @@ void __blk_put_request(struct request_queue *q, struct request *req) /* this is a bio leak */ WARN_ON(req->bio != NULL); +#if defined(OPLUS_FEATURE_SCHED_ASSIST) && defined(CONFIG_OPLUS_FEATURE_UXIO_FIRST) + rq_qos_done(q, req, (bool)((req->cmd_flags & REQ_FG)||(req->cmd_flags & REQ_UX))); +#else rq_qos_done(q, req); - +#endif /* * Request may not have originated from ll_rw_blk. if not, * it didn't come out of our reserved rq pools @@ -1986,9 +2007,14 @@ out: void blk_init_request_from_bio(struct request *req, struct bio *bio) { struct io_context *ioc = rq_ioc(bio); - if (bio->bi_opf & REQ_RAHEAD) req->cmd_flags |= REQ_FAILFAST_MASK; +#if defined(OPLUS_FEATURE_SCHED_ASSIST) && defined(CONFIG_OPLUS_FEATURE_UXIO_FIRST) + if (bio->bi_opf & REQ_UX) + req->cmd_flags |= REQ_UX; + else if (bio->bi_opf & REQ_FG) + req->cmd_flags |= REQ_FG; +#endif req->__sector = bio->bi_iter.bi_sector; if (ioprio_valid(bio_prio(bio))) @@ -2570,11 +2596,17 @@ blk_qc_t submit_bio(struct bio *bio) if (op_is_write(bio_op(bio))) { count_vm_events(PGPGOUT, count); +#if defined(OPLUS_FEATURE_IOMONITOR) && defined(CONFIG_IOMONITOR) + iomonitor_update_vm_stats(PGPGOUT, count); +#endif /*OPLUS_FEATURE_IOMONITOR*/ } else { if (bio_flagged(bio, BIO_WORKINGSET)) workingset_read = true; task_io_account_read(bio->bi_iter.bi_size); count_vm_events(PGPGIN, count); +#if defined(OPLUS_FEATURE_IOMONITOR) && defined(CONFIG_IOMONITOR) + iomonitor_update_vm_stats(PGPGIN, count); +#endif /*OPLUS_FEATURE_IOMONITOR*/ } if (unlikely(block_dump)) { @@ -2586,7 +2618,12 @@ blk_qc_t submit_bio(struct bio *bio) bio_devname(bio, b), count); } } - +#if defined(OPLUS_FEATURE_SCHED_ASSIST) && defined(CONFIG_OPLUS_FEATURE_UXIO_FIRST) + if (test_task_ux(current)) + bio->bi_opf |= REQ_UX; + else if (high_prio_for_task(current)) + bio->bi_opf |= REQ_FG; +#endif /* * If we're reading data that is part of the userspace * workingset, count submission time as memory stall. When the @@ -2793,7 +2830,11 @@ void blk_account_io_done(struct request *req, u64 now) * Don't process normal requests when queue is suspended * or in the process of suspending/resuming */ +#if defined(OPLUS_FEATURE_SCHED_ASSIST) && defined(CONFIG_OPLUS_FEATURE_UXIO_FIRST) +bool blk_pm_allow_request(struct request *rq) +#else static bool blk_pm_allow_request(struct request *rq) +#endif { switch (rq->q->rpm_status) { case RPM_RESUMING: @@ -2806,7 +2847,11 @@ static bool blk_pm_allow_request(struct request *rq) } } #else + #if defined(OPLUS_FEATURE_SCHED_ASSIST) && defined(CONFIG_OPLUS_FEATURE_UXIO_FIRST) + bool blk_pm_allow_request(struct request *rq) + #else static bool blk_pm_allow_request(struct request *rq) +#endif { return true; } @@ -2856,14 +2901,24 @@ static struct request *elv_next_request(struct request_queue *q) WARN_ON_ONCE(q->mq_ops); while (1) { - list_for_each_entry(rq, &q->queue_head, queuelist) { +#if defined(OPLUS_FEATURE_SCHED_ASSIST) && defined(CONFIG_OPLUS_FEATURE_UXIO_FIRST) + if (likely(sysctl_uxio_io_opt)){ + rq = smart_peek_request(q); + if (rq) + return rq; + } else + { +#endif + list_for_each_entry(rq, &q->queue_head, queuelist) { if (blk_pm_allow_request(rq)) return rq; if (rq->rq_flags & RQF_SOFTBARRIER) break; } - +#if defined(OPLUS_FEATURE_SCHED_ASSIST) && defined(CONFIG_OPLUS_FEATURE_UXIO_FIRST) + } +#endif /* * Flush request is running and flush request isn't queueable * in the drive, we can hold the queue till flush request is @@ -2927,6 +2982,10 @@ struct request *blk_peek_request(struct request_queue *q) * not be passed by new incoming requests */ rq->rq_flags |= RQF_STARTED; +#if defined(OPLUS_FEATURE_IOMONITOR) && defined(CONFIG_IOMONITOR) + rq->req_td = ktime_get(); +#endif /*OPLUS_FEATURE_IOMONITOR*/ + trace_block_rq_issue(q, rq); } @@ -2986,7 +3045,9 @@ struct request *blk_peek_request(struct request_queue *q) break; } } - +#if defined(OPLUS_FEATURE_IOMONITOR) && defined(CONFIG_IOMONITOR) + iomonitor_record_io_history(rq); +#endif /*OPLUS_FEATURE_IOMONITOR*/ return rq; } EXPORT_SYMBOL(blk_peek_request); @@ -2999,14 +3060,27 @@ static void blk_dequeue_request(struct request *rq) BUG_ON(ELV_ON_HASH(rq)); list_del_init(&rq->queuelist); +#if defined(OPLUS_FEATURE_SCHED_ASSIST) && defined(CONFIG_OPLUS_FEATURE_UXIO_FIRST) + list_del_init(&rq->ux_fg_bg_list); +#endif /* * the time frame between a request being removed from the lists * and to it is freed is accounted as io that is in progress at * the driver side. */ - if (blk_account_rq(rq)) - q->in_flight[rq_is_sync(rq)]++; +#ifdef OPLUS_FEATURE_HEALTHINFO +// Add for ioqueue +#ifdef CONFIG_OPLUS_HEALTHINFO + if (blk_account_rq(rq)) { + q->in_flight[rq_is_sync(rq)]++; + ohm_ioqueue_add_inflight(q, rq); + } +#else + if (blk_account_rq(rq)) + q->in_flight[rq_is_sync(rq)]++; +#endif +#endif } /** @@ -3117,6 +3191,9 @@ bool blk_update_request(struct request *req, blk_status_t error, int total_bytes; trace_block_rq_complete(req, blk_status_to_errno(error), nr_bytes); +#if defined(OPLUS_FEATURE_IOMONITOR) && defined(CONFIG_IOMONITOR) + iomonitor_record_reqstats(req, nr_bytes); +#endif /*OPLUS_FEATURE_IOMONITOR*/ if (!req->bio) return false; @@ -3254,7 +3331,11 @@ void blk_finish_request(struct request *req, blk_status_t error) blk_account_io_done(req, now); if (req->end_io) { +#if defined(OPLUS_FEATURE_SCHED_ASSIST) && defined(CONFIG_OPLUS_FEATURE_UXIO_FIRST) + rq_qos_done(q, req, (bool)((req->cmd_flags & REQ_FG)||(req->cmd_flags & REQ_UX))); +#else rq_qos_done(q, req); +#endif req->end_io(req, error); } else { if (blk_bidi_rq(req)) diff --git a/block/blk-flush.c b/block/blk-flush.c index dc71da0e6b0e..961b37f06b43 100644 --- a/block/blk-flush.c +++ b/block/blk-flush.c @@ -76,6 +76,10 @@ #include "blk-mq-tag.h" #include "blk-mq-sched.h" +#if defined(OPLUS_FEATURE_SCHED_ASSIST) && defined(CONFIG_OPLUS_FEATURE_UXIO_FIRST) +#include "uxio_first/uxio_first_opt.h" +#endif + /* PREFLUSH/FUA sequences */ enum { REQ_FSEQ_PREFLUSH = (1 << 0), /* pre-flushing in progress */ @@ -142,6 +146,9 @@ static bool blk_flush_queue_rq(struct request *rq, bool add_front) list_add(&rq->queuelist, &rq->q->queue_head); else list_add_tail(&rq->queuelist, &rq->q->queue_head); +#if defined(OPLUS_FEATURE_SCHED_ASSIST) && defined(CONFIG_OPLUS_FEATURE_UXIO_FIRST) + queue_throtl_add_request(rq->q, rq, add_front); +#endif /*OPLUS_FEATURE_SCHED_ASSIST*/ return true; } } @@ -499,7 +506,14 @@ void blk_insert_flush(struct request *rq) if (q->mq_ops) blk_mq_request_bypass_insert(rq, false); else +#if defined(OPLUS_FEATURE_SCHED_ASSIST) && defined(CONFIG_OPLUS_FEATURE_UXIO_FIRST) + { list_add_tail(&rq->queuelist, &q->queue_head); + queue_throtl_add_request(q, rq, false); + } +#else + list_add_tail(&rq->queuelist, &q->queue_head); +#endif return; } diff --git a/block/blk-mq.c b/block/blk-mq.c index ae70b4809bec..6c1e973a8c11 100644 --- a/block/blk-mq.c +++ b/block/blk-mq.c @@ -505,8 +505,11 @@ void blk_mq_free_request(struct request *rq) if (unlikely(laptop_mode && !blk_rq_is_passthrough(rq))) laptop_io_completion(q->backing_dev_info); - +#if defined(OPLUS_FEATURE_SCHED_ASSIST) && defined(CONFIG_OPLUS_FEATURE_UXIO_FIRST) + rq_qos_done(q, rq,(bool)((rq->cmd_flags & REQ_FG)||(rq->cmd_flags & REQ_UX))); +#else rq_qos_done(q, rq); +#endif if (blk_rq_rl(rq)) blk_put_rl(blk_rq_rl(rq)); @@ -529,7 +532,11 @@ inline void __blk_mq_end_request(struct request *rq, blk_status_t error) blk_account_io_done(rq, now); if (rq->end_io) { +#if defined(OPLUS_FEATURE_SCHED_ASSIST) && defined(CONFIG_OPLUS_FEATURE_UXIO_FIRST) + rq_qos_done(rq->q, rq,(bool)((rq->cmd_flags & REQ_FG)||(rq->cmd_flags & REQ_UX))); +#else rq_qos_done(rq->q, rq); +#endif rq->end_io(rq, error); } else { if (unlikely(blk_bidi_rq(rq))) diff --git a/block/blk-rq-qos.c b/block/blk-rq-qos.c index 43bcd4e7a7f9..9dcc3ab6806d 100644 --- a/block/blk-rq-qos.c +++ b/block/blk-rq-qos.c @@ -36,7 +36,17 @@ void rq_qos_cleanup(struct request_queue *q, struct bio *bio) rqos->ops->cleanup(rqos, bio); } } +#if defined(OPLUS_FEATURE_SCHED_ASSIST) && defined(CONFIG_OPLUS_FEATURE_UXIO_FIRST) +void rq_qos_done(struct request_queue *q, struct request *rq, bool fgux) +{ + struct rq_qos *rqos; + for (rqos = q->rq_qos; rqos; rqos = rqos->next) { + if (rqos->ops->done) + rqos->ops->done(rqos, rq, fgux); + } +} +#else void rq_qos_done(struct request_queue *q, struct request *rq) { struct rq_qos *rqos; @@ -46,7 +56,7 @@ void rq_qos_done(struct request_queue *q, struct request *rq) rqos->ops->done(rqos, rq); } } - +#endif void rq_qos_issue(struct request_queue *q, struct request *rq) { struct rq_qos *rqos; diff --git a/block/blk-rq-qos.h b/block/blk-rq-qos.h index 98caba3e962e..8e6b865434f7 100644 --- a/block/blk-rq-qos.h +++ b/block/blk-rq-qos.h @@ -29,7 +29,11 @@ struct rq_qos_ops { void (*track)(struct rq_qos *, struct request *, struct bio *); void (*issue)(struct rq_qos *, struct request *); void (*requeue)(struct rq_qos *, struct request *); +#if defined(OPLUS_FEATURE_SCHED_ASSIST) && defined(CONFIG_OPLUS_FEATURE_UXIO_FIRST) + void (*done)(struct rq_qos *, struct request *, bool); +#else void (*done)(struct rq_qos *, struct request *); +#endif void (*done_bio)(struct rq_qos *, struct bio *); void (*cleanup)(struct rq_qos *, struct bio *); void (*exit)(struct rq_qos *); @@ -96,7 +100,11 @@ bool rq_depth_scale_down(struct rq_depth *rqd, bool hard_throttle); bool rq_depth_calc_max_depth(struct rq_depth *rqd); void rq_qos_cleanup(struct request_queue *, struct bio *); +#if defined(OPLUS_FEATURE_SCHED_ASSIST) && defined(CONFIG_OPLUS_FEATURE_UXIO_FIRST) +void rq_qos_done(struct request_queue *, struct request *, bool); +#else void rq_qos_done(struct request_queue *, struct request *); +#endif void rq_qos_issue(struct request_queue *, struct request *); void rq_qos_requeue(struct request_queue *, struct request *); void rq_qos_done_bio(struct request_queue *q, struct bio *bio); diff --git a/block/blk-sysfs.c b/block/blk-sysfs.c index 50cd3fbb0b8e..8bdc3c61ed75 100644 --- a/block/blk-sysfs.c +++ b/block/blk-sysfs.c @@ -393,6 +393,61 @@ static ssize_t queue_poll_delay_store(struct request_queue *q, const char *page, return count; } +#ifdef OPLUS_FEATURE_HEALTHINFO +// Add for ioqueue +#ifdef CONFIG_OPLUS_HEALTHINFO +static ssize_t queue_show_ohm_inflight(struct request_queue *q, char *page) +{ + ssize_t ret; + + ret = sprintf(page, "async:%d\n", q->in_flight[0]); + ret += sprintf(page + ret, "sync:%d\n", q->in_flight[1]); + ret += sprintf(page + ret, "ux:%d\n", q->in_flight[2]); + ret += sprintf(page + ret, "fg:%d\n", q->in_flight[3]); + ret += sprintf(page + ret, "bg:%d\n", q->in_flight[4]); + return ret; +} +#endif +#endif /* OPLUS_FEATURE_HEALTHINFO */ +#if defined(OPLUS_FEATURE_SCHED_ASSIST) && defined(CONFIG_OPLUS_FEATURE_UXIO_FIRST) +static ssize_t queue_bg_max_depth_show(struct request_queue *q, char *page) +{ + ssize_t ret; + + if (!q->queue_tags) + return -EINVAL; + + ret = sprintf(page, "%d\n", q->queue_tags->bg_max_depth); + + return ret; +} + +static ssize_t queue_bg_max_depth_store(struct request_queue *q, + const char *page, size_t count) +{ + unsigned long val; + int ret; + + if (!q->queue_tags) + return -EINVAL; + + ret = queue_var_store(&val, page, count); + if (ret < 0) + return ret; + + if (val > q->queue_tags->max_depth) + return -EINVAL; + + q->queue_tags->bg_max_depth = val; + return (ssize_t)count; +} + +static struct queue_sysfs_entry queue_bg_max_depth_entry = { + .attr = {.name = "bg_max_depth", .mode = S_IRUGO | S_IWUSR }, + .show = queue_bg_max_depth_show, + .store = queue_bg_max_depth_store, +}; +#endif static ssize_t queue_poll_show(struct request_queue *q, char *page) { @@ -527,7 +582,6 @@ static struct queue_sysfs_entry queue_ra_entry = { .show = queue_ra_show, .store = queue_ra_store, }; - static struct queue_sysfs_entry queue_max_sectors_entry = { .attr = {.name = "max_sectors_kb", .mode = 0644 }, .show = queue_max_sectors_show, @@ -654,6 +708,15 @@ static struct queue_sysfs_entry queue_iostats_entry = { .show = queue_show_iostats, .store = queue_store_iostats, }; +#ifdef OPLUS_FEATURE_HEALTHINFO +// Add for ioqueue +#ifdef CONFIG_OPLUS_HEALTHINFO +static struct queue_sysfs_entry queue_ohm_inflight_entry = { + .attr = {.name = "ohm_inflight", .mode = S_IRUGO }, + .show = queue_show_ohm_inflight, +}; +#endif +#endif /* OPLUS_FEATURE_HEALTHINFO */ static struct queue_sysfs_entry queue_random_entry = { .attr = {.name = "add_random", .mode = 0644 }, @@ -730,6 +793,14 @@ static struct attribute *default_attrs[] = { &queue_nomerges_entry.attr, &queue_rq_affinity_entry.attr, &queue_iostats_entry.attr, +#if defined OPLUS_FEATURE_HEALTHINFO && defined CONFIG_OPLUS_HEALTHINFO +// Add for ioqueue + &queue_ohm_inflight_entry.attr, +#endif /* OPLUS_FEATURE_HEALTHINFO */ + +#if defined(OPLUS_FEATURE_SCHED_ASSIST) && defined(CONFIG_OPLUS_FEATURE_UXIO_FIRST) + &queue_bg_max_depth_entry.attr, +#endif &queue_random_entry.attr, &queue_poll_entry.attr, &queue_wc_entry.attr, diff --git a/block/blk-tag.c b/block/blk-tag.c index fbc153aef166..492a6516f63f 100644 --- a/block/blk-tag.c +++ b/block/blk-tag.c @@ -10,6 +10,10 @@ #include "blk.h" +#if defined(OPLUS_FEATURE_SCHED_ASSIST) && defined(CONFIG_OPLUS_FEATURE_UXIO_FIRST) +#include "uxio_first/uxio_first_opt.h" +#endif + /** * blk_queue_find_tag - find a request by its tag and queue * @q: The request queue for the device @@ -110,6 +114,9 @@ init_tag_map(struct request_queue *q, struct blk_queue_tag *tags, int depth) tags->real_max_depth = depth; tags->max_depth = depth; +#if defined(OPLUS_FEATURE_SCHED_ASSIST) && defined(CONFIG_OPLUS_FEATURE_UXIO_FIRST) + tags->bg_max_depth = BLK_MAX_BG_DEPTH; +#endif tags->tag_index = tag_index; tags->tag_map = tag_map; diff --git a/block/blk-wbt.c b/block/blk-wbt.c index 880a41adde8f..33241effaac7 100644 --- a/block/blk-wbt.c +++ b/block/blk-wbt.c @@ -30,6 +30,9 @@ #define CREATE_TRACE_POINTS #include +#if defined(OPLUS_FEATURE_SCHED_ASSIST) && defined(CONFIG_OPLUS_FEATURE_UXIO_FIRST) +extern bool sysctl_wbt_enable; +#endif static inline void wbt_clear_state(struct request *rq) { rq->wbt_flags = 0; @@ -76,8 +79,14 @@ enum { static inline bool rwb_enabled(struct rq_wb *rwb) { +#if defined(OPLUS_FEATURE_SCHED_ASSIST) && defined(CONFIG_OPLUS_FEATURE_UXIO_FIRST) + return sysctl_wbt_enable && rwb && + rwb->enable_state != WBT_STATE_OFF_DEFAULT && + rwb->wb_normal != 0; +#else return rwb && rwb->enable_state != WBT_STATE_OFF_DEFAULT && rwb->wb_normal != 0; +#endif } static void wb_timestamp(struct rq_wb *rwb, unsigned long *var) @@ -182,7 +191,11 @@ static void __wbt_done(struct rq_qos *rqos, enum wbt_flags wb_acct) * Called on completion of a request. Note that it's also called when * a request is merged, when the request gets freed. */ +#if defined(OPLUS_FEATURE_SCHED_ASSIST) && defined(CONFIG_OPLUS_FEATURE_UXIO_FIRST) +static void wbt_done(struct rq_qos *rqos, struct request *rq, bool fgux) +#else static void wbt_done(struct rq_qos *rqos, struct request *rq) +#endif { struct rq_wb *rwb = RQWB(rqos); @@ -192,7 +205,11 @@ static void wbt_done(struct rq_qos *rqos, struct request *rq) rwb->sync_cookie = NULL; } +#if defined(OPLUS_FEATURE_SCHED_ASSIST) && defined(CONFIG_OPLUS_FEATURE_UXIO_FIRST) + if (wbt_is_read(rq) || fgux) +#else if (wbt_is_read(rq)) +#endif wb_timestamp(rwb, &rwb->last_comp); } else { WARN_ON_ONCE(rq == rwb->sync_cookie); diff --git a/block/elevator.c b/block/elevator.c index 9909aa54a802..d0ae32cfcd4f 100644 --- a/block/elevator.c +++ b/block/elevator.c @@ -42,6 +42,9 @@ #include "blk.h" #include "blk-mq-sched.h" #include "blk-wbt.h" +#if defined(OPLUS_FEATURE_SCHED_ASSIST) && defined(CONFIG_OPLUS_FEATURE_UXIO_FIRST) +#include "uxio_first/uxio_first_opt.h" +#endif static DEFINE_SPINLOCK(elv_list_lock); static LIST_HEAD(elv_list); @@ -394,6 +397,9 @@ void elv_dispatch_sort(struct request_queue *q, struct request *rq) } list_add(&rq->queuelist, entry); +#if defined(OPLUS_FEATURE_SCHED_ASSIST) && defined(CONFIG_OPLUS_FEATURE_UXIO_FIRST) + queue_throtl_add_request(q, rq, false); +#endif } EXPORT_SYMBOL(elv_dispatch_sort); @@ -414,6 +420,9 @@ void elv_dispatch_add_tail(struct request_queue *q, struct request *rq) q->end_sector = rq_end_sector(rq); q->boundary_rq = rq; list_add_tail(&rq->queuelist, &q->queue_head); +#if defined(OPLUS_FEATURE_SCHED_ASSIST) && defined(CONFIG_OPLUS_FEATURE_UXIO_FIRST) + queue_throtl_add_request(q, rq, false); +#endif } EXPORT_SYMBOL(elv_dispatch_add_tail); @@ -593,6 +602,12 @@ void elv_requeue_request(struct request_queue *q, struct request *rq) */ if (blk_account_rq(rq)) { q->in_flight[rq_is_sync(rq)]--; +#ifdef OPLUS_FEATURE_HEALTHINFO +// Add for ioqueue +#ifdef CONFIG_OPLUS_HEALTHINFO + ohm_ioqueue_dec_inflight(q, rq); +#endif +#endif /* OPLUS_FEATURE_HEALTHINFO */ if (rq->rq_flags & RQF_SORTED) elv_deactivate_rq(q, rq); } @@ -625,6 +640,10 @@ void elv_drain_elevator(struct request_queue *q) void __elv_add_request(struct request_queue *q, struct request *rq, int where) { +#if defined(OPLUS_FEATURE_IOMONITOR) && defined(CONFIG_IOMONITOR) + rq->req_ti = ktime_get(); +#endif /*OPLUS_FEATURE_IOMONITOR*/ + trace_block_rq_insert(q, rq); blk_pm_add_request(q, rq); @@ -647,12 +666,18 @@ void __elv_add_request(struct request_queue *q, struct request *rq, int where) case ELEVATOR_INSERT_FRONT: rq->rq_flags |= RQF_SOFTBARRIER; list_add(&rq->queuelist, &q->queue_head); +#if defined(OPLUS_FEATURE_SCHED_ASSIST) && defined(CONFIG_OPLUS_FEATURE_UXIO_FIRST) + queue_throtl_add_request(q, rq, true); +#endif break; case ELEVATOR_INSERT_BACK: rq->rq_flags |= RQF_SOFTBARRIER; elv_drain_elevator(q); list_add_tail(&rq->queuelist, &q->queue_head); +#if defined(OPLUS_FEATURE_SCHED_ASSIST) && defined(CONFIG_OPLUS_FEATURE_UXIO_FIRST) + queue_throtl_add_request(q, rq, false); +#endif /* * We kick the queue here for the following reasons. * - The elevator might have returned NULL previously @@ -787,6 +812,12 @@ void elv_completed_request(struct request_queue *q, struct request *rq) */ if (blk_account_rq(rq)) { q->in_flight[rq_is_sync(rq)]--; +#ifdef OPLUS_FEATURE_HEALTHINFO +// Add for ioqueue +#ifdef CONFIG_OPLUS_HEALTHINFO + ohm_ioqueue_dec_inflight(q, rq); +#endif +#endif /* OPLUS_FEATURE_HEALTHINFO */ if ((rq->rq_flags & RQF_SORTED) && e->type->ops.sq.elevator_completed_req_fn) e->type->ops.sq.elevator_completed_req_fn(q, rq); diff --git a/block/partitions/efi.c b/block/partitions/efi.c index 39f70d968754..b6aa14f5d167 100644 --- a/block/partitions/efi.c +++ b/block/partitions/efi.c @@ -689,6 +689,36 @@ static int find_valid_gpt(struct parsed_partitions *state, gpt_header **gpt, * 1 if successful * */ + +struct replace_partition_tbl { + char *old_name; + char *new_name; +}; +static struct replace_partition_tbl tbl[] = { + {"oplus_sec", "oplus_sec"}, + {"oppodycnvbk","oplusdycnvbk"}, + {"oppostanvbk", "oplusstanvbk"}, + {"opporeserve1", "oplusreserve1"}, + {"opporeserve2", "oplusreserve2"}, + {"opporeserve3", "oplusreserve3"}, + {"opporeserve4", "oplusreserve4"}, + {"opporeserve5", "oplusreserve5"}, +}; + +static void oplus_replace_partition_name(char *name) +{ + int part_idx = 0; + + for (part_idx = 0; part_idx < ARRAY_SIZE(tbl); part_idx++) { + if (!strncmp(name, tbl[part_idx].old_name, strlen(tbl[part_idx].old_name))) { + pr_warn("rename partition name: %s->%s\n", name, tbl[part_idx].new_name); + memset(name, 0, strlen(tbl[part_idx].old_name)); + strcpy(name, tbl[part_idx].new_name); + return; + } + } +} + int efi_partition(struct parsed_partitions *state) { gpt_header *gpt = NULL; @@ -736,6 +766,7 @@ int efi_partition(struct parsed_partitions *state) label_count++; } state->parts[i + 1].has_info = true; + oplus_replace_partition_name(&info->volname[0]); } kfree(ptes); kfree(gpt); diff --git a/block/scsi_ioctl.c b/block/scsi_ioctl.c index 533f4aee8567..58996837997a 100644 --- a/block/scsi_ioctl.c +++ b/block/scsi_ioctl.c @@ -205,6 +205,12 @@ static void blk_set_cmd_filter_defaults(struct blk_cmd_filter *filter) __set_bit(GPCMD_LOAD_UNLOAD, filter->write_ok); __set_bit(GPCMD_SET_STREAMING, filter->write_ok); __set_bit(GPCMD_SET_READ_AHEAD, filter->write_ok); +#ifdef OPLUS_FEATURE_STORAGE_TOOL +// add write buffer command for common user +// add vendor command for common user + __set_bit(WRITE_BUFFER, filter->write_ok); + __set_bit(VENDOR_SPECIFIC_CDB, filter->write_ok); +#endif } int blk_verify_command(unsigned char *cmd, fmode_t mode) @@ -424,6 +430,11 @@ int sg_scsi_ioctl(struct request_queue *q, struct gendisk *disk, fmode_t mode, int err; unsigned int in_len, out_len, bytes, opcode, cmdlen; char *buffer = NULL; +#ifdef OPLUS_FEATURE_STORAGE_TOOL +// vendor cmd len is 16 and not 10 in spec. +// in current application ,only samsung health will use this cmd. + struct scsi_device *sdev = NULL; +#endif if (!sic) return -EINVAL; @@ -456,6 +467,16 @@ int sg_scsi_ioctl(struct request_queue *q, struct gendisk *disk, fmode_t mode, req = scsi_req(rq); cmdlen = COMMAND_SIZE(opcode); +#ifdef OPLUS_FEATURE_STORAGE_TOOL +// vendor cmd len is 16 and not 10 in spec. +// in current application ,only samsung health will use this cmd. + sdev = (struct scsi_device*)(q->queuedata); + if ((VENDOR_SPECIFIC_CDB == opcode) + &&(0 == strncmp(sdev->vendor, "SAMSUNG ", 8)) + ){ + cmdlen = 16; + } +#endif /* * get command and data to send to device, if any diff --git a/block/uxio_first b/block/uxio_first new file mode 120000 index 000000000000..e83c1411361b --- /dev/null +++ b/block/uxio_first @@ -0,0 +1 @@ +../../../vendor/oplus/kernel/oplus_performance/uxio_first \ No newline at end of file diff --git a/crypto/zstd.c b/crypto/zstd.c index 9a76b3ed8b8b..f6f5de75b7cd 100644 --- a/crypto/zstd.c +++ b/crypto/zstd.c @@ -23,7 +23,7 @@ #include -#define ZSTD_DEF_LEVEL 3 +#define ZSTD_DEF_LEVEL 1 struct zstd_ctx { ZSTD_CCtx *cctx; @@ -248,6 +248,7 @@ static int __init zstd_mod_init(void) if (ret) crypto_unregister_alg(&alg); + pr_warn("ZSTD_DEF_LEVEL val %d\n", ZSTD_DEF_LEVEL); return ret; } diff --git a/drivers/Kconfig b/drivers/Kconfig index e0866eda8bbd..c182112c6f15 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -232,4 +232,10 @@ source "drivers/sensors/Kconfig" source "drivers/gpu/msm/Kconfig" source "drivers/energy_model/Kconfig" + +#ifdef OPLUS_NFC_BRINGUP +#Add for the kernel Macro for NXP PN557 NFC kernel +source "drivers/nfc/pn553-i2c/Kconfig" +source "drivers/nfc/p73-spi/Kconfig" +#endif /*OPLUS_NFC_BRINGUP*/ endmenu diff --git a/drivers/Makefile b/drivers/Makefile index 9a258f18ec6f..1266025ada2f 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -192,3 +192,4 @@ obj-$(CONFIG_UNISYS_VISORBUS) += visorbus/ obj-$(CONFIG_SIOX) += siox/ obj-$(CONFIG_GNSS) += gnss/ obj-$(CONFIG_SENSORS_SSC) += sensors/ +obj-$(CONFIG_SENSORS_SIMULATED_HALL) += sensors/ diff --git a/drivers/android/Kconfig b/drivers/android/Kconfig index 6fdf2abe4598..123a5050fd2c 100644 --- a/drivers/android/Kconfig +++ b/drivers/android/Kconfig @@ -54,6 +54,11 @@ config ANDROID_BINDER_IPC_SELFTEST exhaustively with combinations of various buffer sizes and alignments. +config OPLUS_BINDER_STRATEGY + default n + bool "config binder control" + help + it helps to reduce anr by restricting background app binder behavior. endif # if ANDROID endmenu diff --git a/drivers/android/binder.c b/drivers/android/binder.c index 41222500e1a3..d74050487e6e 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -81,6 +81,21 @@ #include "binder_internal.h" #include "binder_trace.h" +#ifdef OPLUS_FEATURE_HANS_FREEZE +#include +#endif /*OPLUS_FEATURE_HANS_FREEZE*/ +#ifdef OPLUS_FEATURE_SCHED_ASSIST +#include +#endif /* OPLUS_FEATURE_SCHED_ASSIST */ + +#ifdef CONFIG_OPLUS_FEATURE_INPUT_BOOST_V4 +#include +#endif /* CONFIG_OPLUS_FEATURE_INPUT_BOOST_V4 */ + +#if IS_ENABLED(CONFIG_OPLUS_FEATURE_CPU_JANKINFO) +#include +#endif + static HLIST_HEAD(binder_deferred_list); static DEFINE_MUTEX(binder_deferred_lock); @@ -136,6 +151,40 @@ module_param_named(devices, binder_devices_param, charp, 0444); static DECLARE_WAIT_QUEUE_HEAD(binder_user_error_wait); static int binder_stop_on_user_error; +#if defined(CONFIG_OPLUS_FEATURE_BINDER_STATS_ENABLE) + +#include +#ifndef CONFIG_OPLUS_FEATURE_CPU_JANKINFO +#define OPLUS_MAX_SERVICE_NAME_LEN 32 +#endif +#define OPLUS_MAGIC_SERVICE_NAME_OFFSET 76 + +struct binder_notify { + struct task_struct *caller_task; + struct task_struct *binder_task; + char service_name[OPLUS_MAX_SERVICE_NAME_LEN]; + bool pending_async; +}; + +static ATOMIC_NOTIFIER_HEAD(binderevent_notif_chain); + +int register_binderevent_notifier(struct notifier_block *nb) { + return atomic_notifier_chain_register(&binderevent_notif_chain, nb); +} +EXPORT_SYMBOL_GPL(register_binderevent_notifier); + +int unregister_binderevent_notifier(struct notifier_block *nb) { + return atomic_notifier_chain_unregister(&binderevent_notif_chain, nb); +} +EXPORT_SYMBOL_GPL(unregister_binderevent_notifier); + +int call_binderevent_notifiers(unsigned long val, void *v) { + return atomic_notifier_call_chain(&binderevent_notif_chain, val, v); +} +EXPORT_SYMBOL_GPL(call_binderevent_notifiers); + +#endif // #if defined(CONFIG_OPLUS_FEATURE_BINDER_STATS_ENABLE) + static int binder_set_stop_on_user_error(const char *val, const struct kernel_param *kp) { @@ -174,6 +223,7 @@ module_param_call(stop_on_user_error, binder_set_stop_on_user_error, #define to_binder_fd_array_object(hdr) \ container_of(hdr, struct binder_fd_array_object, hdr) +#ifndef CONFIG_OPLUS_FEATURE_CPU_JANKINFO enum binder_stat_types { BINDER_STAT_PROC, BINDER_STAT_THREAD, @@ -191,6 +241,7 @@ struct binder_stats { atomic_t obj_created[BINDER_STAT_COUNT]; atomic_t obj_deleted[BINDER_STAT_COUNT]; }; +#endif static struct binder_stats binder_stats; @@ -227,6 +278,7 @@ static struct binder_transaction_log_entry *binder_transaction_log_add( return e; } +#ifndef CONFIG_OPLUS_FEATURE_CPU_JANKINFO /** * struct binder_work - work enqueued on a worklist * @entry: node enqueued on list @@ -246,6 +298,9 @@ struct binder_work { BINDER_WORK_DEAD_BINDER_AND_CLEAR, BINDER_WORK_CLEAR_DEATH_NOTIFICATION, } type; +#ifdef CONFIG_OPLUS_BINDER_STRATEGY + u64 ob_begin; +#endif }; struct binder_error { @@ -354,6 +409,9 @@ struct binder_node { }; bool has_async_transaction; struct list_head async_todo; +#if defined(CONFIG_OPLUS_FEATURE_BINDER_STATS_ENABLE) + char service_name[OPLUS_MAX_SERVICE_NAME_LEN]; +#endif }; struct binder_ref_death { @@ -513,6 +571,9 @@ struct binder_proc { struct hlist_node deferred_work_node; int deferred_work; bool is_dead; +#ifdef OPLUS_FEATURE_SCHED_ASSIST + int proc_type; +#endif /* OPLUS_FEATURE_SCHED_ASSIST */ struct list_head todo; struct binder_stats stats; @@ -537,6 +598,9 @@ enum { BINDER_LOOPER_STATE_INVALID = 0x08, BINDER_LOOPER_STATE_WAITING = 0x10, BINDER_LOOPER_STATE_POLL = 0x20, +#ifdef CONFIG_OPLUS_BINDER_STRATEGY + BINDER_LOOPER_STATE_BACKGROUND = 0x40, +#endif }; /** @@ -594,6 +658,7 @@ struct binder_thread { bool is_dead; struct task_struct *task; }; +#endif struct binder_transaction { int debug_id; @@ -643,6 +708,58 @@ struct binder_object { }; }; +#if defined(CONFIG_OPLUS_FEATURE_BINDER_STATS_ENABLE) + +static void oplus_parse_service_name(struct binder_transaction_data *tr, + struct binder_proc *proc, + char *name) { + unsigned int i, len = 0; + char *tmp; + char c; + char sname[OPLUS_MAX_SERVICE_NAME_LEN]; + + if (NULL != tr && tr->target.handle == 0 && NULL != proc && NULL != proc->context) { + if (!strcmp(proc->context->name, "hwbinder")) { + strcpy(sname, "hwbinderService"); + } else { + for (i = 0; (2 * i) < tr->data_size; i++) { + if ((2 * i) < OPLUS_MAGIC_SERVICE_NAME_OFFSET) { + continue; + } + if (len >= (OPLUS_MAX_SERVICE_NAME_LEN - 1)) + break; + tmp = (char *)(uintptr_t)(tr->data.ptr.buffer + (2*i)); + get_user(c, tmp); + if (c >= 32 && c <= 126) { // visible character range [32, 126] + if (len < OPLUS_MAX_SERVICE_NAME_LEN - 1) + len += sprintf(sname + len, "%c", c); + else + break; + } + if ('\0' == c) { + break; + } + } + sname[len] = '\0'; + } + pr_info("context.name[%s] tr.size:%lu service:%s\n", + proc->context->name, (unsigned long)tr->data_size, sname); + } else { + if (NULL != tr && 0 != tr->target.handle) { + sprintf(sname, "AnonymousCallback"); + } else { + sprintf(sname, "unknown"); + } + } + + if (NULL != name){ + strncpy(name, sname, OPLUS_MAX_SERVICE_NAME_LEN); + name[OPLUS_MAX_SERVICE_NAME_LEN-1] = '\0'; + } +} + +#endif // #if defined(CONFIG_OPLUS_FEATURE_BINDER_STATS_ENABLE) + /** * binder_proc_lock() - Acquire outer lock for given binder_proc * @proc: struct binder_proc to acquire @@ -967,13 +1084,25 @@ err: return retval; } +#ifdef CONFIG_OPLUS_BINDER_STRATEGY +bool obthread_has_work(struct binder_thread *thread); +static struct binder_thread * +binder_select_thread_ilocked(struct binder_proc *proc); +#endif static bool binder_has_work_ilocked(struct binder_thread *thread, bool do_proc_work) { +#ifdef CONFIG_OPLUS_BINDER_STRATEGY + return thread->process_todo || + thread->looper_need_return || (do_proc_work && obthread_has_work(thread)) || + (do_proc_work && + !binder_worklist_empty_ilocked(&thread->proc->todo)); +#else return thread->process_todo || thread->looper_need_return || (do_proc_work && !binder_worklist_empty_ilocked(&thread->proc->todo)); +#endif } static bool binder_has_work(struct binder_thread *thread, bool do_proc_work) @@ -987,6 +1116,290 @@ static bool binder_has_work(struct binder_thread *thread, bool do_proc_work) return has_work; } +#ifdef CONFIG_OPLUS_BINDER_STRATEGY +#include + + +#define BINDER_LOOPER_STATE_BACKGROUND 0x40 +#define OBPROC_CHECK_CYCLE_NS 100000000 +#define OBWORK_TIMEOUT_NS 800000000 +#define BG_THREAD (2) +#define SA_CGROUP_BACKGROUND (3) + +struct ob_struct ob_target; +pid_t ob_pid; +int ob_err; +int sysctl_ob_control_enable = 1; +noinline void ob_tracing_mark_write(const char *buf) +{ + trace_printk(buf); +} + +void ob_sysctrace_c(struct binder_proc *proc, struct binder_thread *thread) +{ + char buf[256]; + + snprintf(buf, sizeof(buf), "C|%d|oplus_bt%s|%d", proc->pid, thread->task->comm, 1); + ob_tracing_mark_write(buf); +} + +int get_task_cgroup_id(struct task_struct *task) +{ + struct cgroup_subsys_state *css = task_css(task, schedtune_cgrp_id); + return css ? css->id : -1; +} + +bool test_task_bg(struct task_struct *task) +{ + return (SA_CGROUP_BACKGROUND == get_task_cgroup_id(task)) ? 1 : 0; +} + +bool obtrans_is_from_background(struct binder_transaction *t) +{ + return test_task_bg(t->from->task); +} + +bool obtrans_is_from_third_party(struct binder_transaction *t) +{ + return (from_kuid(current_user_ns(), t->sender_euid) % 100000) >= 10000; +} + +bool obtrans_is_from_main(struct binder_transaction *t) +{ + return t->from->proc->pid == t->from->pid; +} + +static char *obs_blacklist[] = { + "rocess.contacts" +}; + +bool obs_black_list(struct binder_transaction *t) +{ + int i = 0; + + if (!t->from->proc->tsk) + return false; + for (i = 0; i < ARRAY_SIZE(obs_blacklist); i++) { + if (strstr(t->from->proc->tsk->comm, obs_blacklist[i])) { + pr_debug("%s is obs blacklist, don't limit it!!!",obs_blacklist[i]); + return true; + } + } + return false; +} + +bool obwork_is_restrict(struct binder_transaction *t) +{ + if ((!t->from) || (!t->from->proc)) + return false; + if (obs_black_list(t)) + return false; + return (obtrans_is_from_background(t)) && obtrans_is_from_third_party(t) && + (!obtrans_is_from_main(t)) && (!test_task_ux(t->from->task)); +} + +void obwork_check_restrict_off(struct binder_proc *proc) +{ + struct binder_work *w = NULL; + struct binder_work *tmp = NULL; + struct binder_transaction *t = NULL; + u64 now = sched_clock(); + + if (proc != ob_target.ob_proc || binder_worklist_empty_ilocked(&ob_target.ob_list) || (now - ob_target.ob_check_ts) < OBPROC_CHECK_CYCLE_NS) + return; + list_for_each_entry_safe(w, tmp, &ob_target.ob_list, entry) { + if (!w) + continue; + t = container_of(w, struct binder_transaction, work); + if (now - w->ob_begin < OBWORK_TIMEOUT_NS) + break; + list_del_init(&w->entry); + //pr_info("%s timeoutinfo:t->from:%d,t->start:%llu now:%llu",__func__,t->from->pid,w->ob_begin,now); + binder_enqueue_work_ilocked(w, &proc->todo); + } + ob_target.ob_check_ts = sched_clock(); +} + +void obtrans_restrict_start(struct binder_proc *proc, struct binder_transaction *t) +{ + if (!sysctl_ob_control_enable) + return; + if (obwork_is_restrict(t)) { + t->work.ob_begin = sched_clock(); + } + obwork_check_restrict_off(proc); +} + +void oblist_dequeue_all(void) +{ + struct binder_work *w; + struct binder_work *w_tmp; + if (ob_target.ob_proc == NULL) + return; + binder_inner_proc_lock(ob_target.ob_proc); + if (binder_worklist_empty_ilocked(&ob_target.ob_list)) { + binder_inner_proc_unlock(ob_target.ob_proc); + return; + } + list_for_each_entry_safe(w, w_tmp, &ob_target.ob_list, entry) { + if (!w) + continue; + list_del_init(&w->entry); + binder_enqueue_work_ilocked(w, &ob_target.ob_proc->todo); + } + binder_inner_proc_unlock(ob_target.ob_proc); + return; +} + +void oblist_dequeue_topapp_change(uid_t topuid) +{ + struct binder_work *w; + struct binder_work *w_tmp; + struct binder_transaction *t; + if (ob_target.ob_proc == NULL) + return; + binder_inner_proc_lock(ob_target.ob_proc); + if (!binder_worklist_empty_ilocked(&ob_target.ob_list)) { + list_for_each_entry_safe(w, w_tmp, &ob_target.ob_list, entry) { + if (!w) + continue; + t = container_of(w, struct binder_transaction, work); + if (from_kuid(current_user_ns(), t->sender_euid) != topuid) + continue; + list_del_init(&w->entry); + binder_enqueue_work_ilocked(w, &ob_target.ob_proc->todo); + } + } + binder_inner_proc_unlock(ob_target.ob_proc); + return; +} + +void obwork_restrict(struct binder_proc *proc, struct binder_transaction *t) +{ + if (!sysctl_ob_control_enable || (proc != ob_target.ob_proc) || !obwork_is_restrict(t)) + binder_enqueue_work_ilocked(&t->work, &proc->todo); + else + binder_enqueue_work_ilocked(&t->work, &ob_target.ob_list); +} + +void obtarget_init(struct binder_proc *proc) +{ + if (!proc->tsk || !proc->context || !proc->context->name) + return; + if (ob_target.init) + return; + if ((!strncmp(proc->tsk->comm, "system_server", TASK_COMM_LEN)) && !strcmp(proc->context->name, "binder")) { + ob_target.ob_proc = proc; + ob_target.ob_check_ts = sched_clock(); + INIT_LIST_HEAD(&ob_target.ob_list); + ob_target.init = true; + //pr_info("%s: ob_target->pid:%d ob_target->name:%s\n", __func__, proc->tsk->pid,proc->tsk->comm); + } +} + +void obthread_init(struct binder_proc *proc, struct binder_thread *thread) +{ + if (proc != ob_target.ob_proc) + return; + if (proc->requested_threads_started == BG_THREAD) { + thread->looper |= BINDER_LOOPER_STATE_BACKGROUND; + ob_pid = thread->task->pid; + //pr_info("%s :bg thread->name:%s thread->pid:%d", __func__,thread->task->comm,thread->task->pid); + } +} + +bool obthread_has_work(struct binder_thread *thread) +{ + if (!sysctl_ob_control_enable || !(thread->looper & BINDER_LOOPER_STATE_BACKGROUND) || (thread->proc != ob_target.ob_proc)) + return false; + return !binder_worklist_empty_ilocked(&ob_target.ob_list); +} + +bool obproc_has_work(struct binder_proc *proc) +{ + if (!sysctl_ob_control_enable || ob_target.ob_proc != proc) + return false; + if (!binder_worklist_empty_ilocked(&ob_target.ob_list)) + return true; + else + return false; +} + +void obthread_wakeup(struct binder_proc *proc) +{ + struct binder_thread *thread = NULL; + + list_for_each_entry(thread, &proc->waiting_threads, waiting_thread_node) { + if (thread && (thread->looper & BINDER_LOOPER_STATE_BACKGROUND)) { + list_del_init(&thread->waiting_thread_node); + wake_up_interruptible(&thread->wait); + } + } + return; +} + +void obproc_free(struct binder_proc *proc) +{ + if (proc == ob_target.ob_proc) { + BUG_ON(!list_empty(&ob_target.ob_list)); + ob_target.ob_check_ts = 0; + ob_target.ob_proc = NULL; + } +} + +void obprint_oblist(void) +{ + struct binder_work *w; + struct binder_work *w_tmp; + struct binder_transaction *t; + if (!sysctl_ob_control_enable) + return; + if (ob_target.ob_proc == NULL) + return; + if (binder_worklist_empty_ilocked(&ob_target.ob_list)) + return; + list_for_each_entry_safe(w, w_tmp, &ob_target.ob_list, entry) { + if (!w) + continue; + t = container_of(w, struct binder_transaction, work); + if (!obwork_is_restrict(t)) + ob_err++; + } +} + +struct binder_thread *obthread_get(struct binder_proc *proc, struct binder_transaction *t, bool oneway) +{ + struct binder_thread *thread = NULL; + if (sysctl_ob_control_enable && (proc == ob_target.ob_proc) && obwork_is_restrict(t) && !oneway) { + list_for_each_entry(thread, &proc->waiting_threads, waiting_thread_node) + if (thread && (thread->looper & BINDER_LOOPER_STATE_BACKGROUND)) { + list_del_init(&thread->waiting_thread_node); + pr_info("%s :bg thread->name:%s thread->pid:%d", __func__, thread->task->comm, thread->task->pid); + return thread; + } + return NULL; + } + return binder_select_thread_ilocked(proc); +} + +int sysctl_ob_control_handler(struct ctl_table *table, int write, void __user *buffer, size_t *lenp, loff_t *ppos) +{ + int ret; + + if (write && *ppos) + *ppos = 0; + ret = proc_dointvec(table, write, buffer, lenp, ppos); + if (!write) + goto out; + if (!sysctl_ob_control_enable) { + pr_info("_%s dequeue all bg work", __func__); + oblist_dequeue_all(); + } +out: + return ret; +} +#endif + static bool binder_available_for_proc_work_ilocked(struct binder_thread *thread) { return !thread->transaction_stack && @@ -1212,10 +1625,17 @@ static void binder_restore_priority(struct task_struct *task, binder_do_set_priority(task, desired, /* verify = */ false); } +#ifdef OPLUS_FEATURE_SCHED_ASSIST +static void binder_transaction_priority(struct binder_thread *thread, struct task_struct *task, + struct binder_transaction *t, + struct binder_priority node_prio, + bool inherit_rt) +#else static void binder_transaction_priority(struct task_struct *task, struct binder_transaction *t, struct binder_priority node_prio, bool inherit_rt) +#endif /* OPLUS_FEATURE_SCHED_ASSIST */ { struct binder_priority desired_prio = t->priority; @@ -1226,6 +1646,13 @@ static void binder_transaction_priority(struct task_struct *task, t->saved_priority.sched_policy = task->policy; t->saved_priority.prio = task->normal_prio; +#ifdef OPLUS_FEATURE_SCHED_ASSIST + //NOTE: if task is main thread, and doesn't join pool as a binder thread, + //DON'T actually change priority in binder transaction. + if ((task->tgid == task->pid) && !(thread->looper & BINDER_LOOPER_STATE_ENTERED)) { + return; + } +#endif /* OPLUS_FEATURE_SCHED_ASSIST */ if (!inherit_rt && is_rt_policy(desired_prio.sched_policy)) { desired_prio.prio = NICE_TO_PRIO(0); desired_prio.sched_policy = SCHED_NORMAL; @@ -2528,9 +2955,16 @@ static void binder_transaction_buffer_release(struct binder_proc *proc, } } +#if defined(CONFIG_OPLUS_FEATURE_BINDER_STATS_ENABLE) +static int binder_translate_binder(struct binder_transaction_data *tr, + struct flat_binder_object *fp, + struct binder_transaction *t, + struct binder_thread *thread) +#else static int binder_translate_binder(struct flat_binder_object *fp, struct binder_transaction *t, struct binder_thread *thread) +#endif { struct binder_node *node; struct binder_proc *proc = thread->proc; @@ -2543,6 +2977,9 @@ static int binder_translate_binder(struct flat_binder_object *fp, node = binder_new_node(proc, fp); if (!node) return -ENOMEM; +#if defined(CONFIG_OPLUS_FEATURE_BINDER_STATS_ENABLE) + oplus_parse_service_name(tr, proc, node->service_name); +#endif } if (fp->cookie != node->cookie) { binder_user_error("%d:%d sending u%016llx node %d, cookie mismatch %016llx != %016llx\n", @@ -2833,6 +3270,13 @@ static int binder_fixup_parent(struct binder_transaction *t, return 0; } +#ifdef OPLUS_FEATURE_SCHED_ASSIST +static inline bool is_binder_proc_sf(struct binder_proc *proc) +{ + return proc && proc->tsk && strstr(proc->tsk->comm, "surfaceflinger") + && (task_uid(proc->tsk).val == 1000); +} +#endif /* OPLUS_FEATURE_SCHED_ASSIST */ /** * binder_proc_transaction() - sends a transaction to a process and wakes it up * @t: transaction to send @@ -2850,6 +3294,9 @@ static int binder_fixup_parent(struct binder_transaction *t, * Return: true if the transactions was successfully queued * false if the target process or thread is dead */ +#if defined(OPLUS_FEATURE_SCHED_ASSIST) +extern bool is_sf(struct task_struct *p); +#endif static bool binder_proc_transaction(struct binder_transaction *t, struct binder_proc *proc, struct binder_thread *thread) @@ -2858,7 +3305,13 @@ static bool binder_proc_transaction(struct binder_transaction *t, struct binder_priority node_prio; bool oneway = !!(t->flags & TF_ONE_WAY); bool pending_async = false; - +#if defined(CONFIG_OPLUS_FEATURE_BINDER_STATS_ENABLE) + struct binder_notify binder_notify_obj; +#endif +#if defined(OPLUS_FEATURE_SCHED_ASSIST) + struct task_struct *grp_leader = NULL; + struct task_struct *curr = current; +#endif BUG_ON(!node); binder_node_lock(node); node_prio.prio = node->min_priority; @@ -2880,22 +3333,84 @@ static bool binder_proc_transaction(struct binder_transaction *t, binder_node_unlock(node); return false; } - +#ifdef CONFIG_OPLUS_BINDER_STRATEGY + obtrans_restrict_start(proc, t); + if (!thread && !pending_async) { + thread = obthread_get(proc, t, oneway); + } +#else if (!thread && !pending_async) thread = binder_select_thread_ilocked(proc); +#endif + +#if defined(CONFIG_OPLUS_FEATURE_BINDER_STATS_ENABLE) + if (NULL != node && NULL != proc->tsk) { + binder_notify_obj.caller_task = current; + strncpy(binder_notify_obj.service_name, node->service_name, OPLUS_MAX_SERVICE_NAME_LEN); + binder_notify_obj.service_name[OPLUS_MAX_SERVICE_NAME_LEN-1] = '\0'; + binder_notify_obj.pending_async = pending_async; + } +#endif if (thread) { +#if defined(CONFIG_OPLUS_FEATURE_BINDER_STATS_ENABLE) + if (NULL != thread && NULL != thread->task) { + binder_notify_obj.binder_task = thread->task; + call_binderevent_notifiers(0, (void *)&binder_notify_obj); + } +#endif +#ifdef OPLUS_FEATURE_SCHED_ASSIST + binder_transaction_priority(thread, thread->task, t, node_prio, + node->inherit_rt); +#else binder_transaction_priority(thread->task, t, node_prio, node->inherit_rt); +#endif /* OPLUS_FEATURE_SCHED_ASSIST */ binder_enqueue_thread_work_ilocked(thread, &t->work); +#ifdef OPLUS_FEATURE_SCHED_ASSIST + if (sysctl_sched_assist_enabled) { + if (!oneway || proc->proc_type) + binder_set_inherit_ux(thread->task, current); + } +#endif /* OPLUS_FEATURE_SCHED_ASSIST */ +#ifdef CONFIG_OPLUS_FEATURE_INPUT_BOOST_V4 + if (t->from) { + binder_thread_set_fbg(thread->task, t->from->task, oneway); + } +#endif /* CONFIG_OPLUS_FEATURE_INPUT_BOOST_V4 */ } else if (!pending_async) { +#if defined(CONFIG_OPLUS_FEATURE_BINDER_STATS_ENABLE) + if (NULL != proc && NULL != proc->tsk) { + binder_notify_obj.binder_task = proc->tsk; + call_binderevent_notifiers(0, (void *)&binder_notify_obj); + } +#endif +#ifdef CONFIG_OPLUS_BINDER_STRATEGY + obwork_restrict(proc, t); +#else binder_enqueue_work_ilocked(&t->work, &proc->todo); +#endif } else { +#if defined(CONFIG_OPLUS_FEATURE_BINDER_STATS_ENABLE) + if (NULL != proc && NULL != proc->tsk) { + binder_notify_obj.binder_task = proc->tsk; + call_binderevent_notifiers(0, (void *)&binder_notify_obj); + } +#endif binder_enqueue_work_ilocked(&t->work, &node->async_todo); } - if (!pending_async) + if (!pending_async) { +#if defined(OPLUS_FEATURE_SCHED_ASSIST) + if (thread && thread->task) { + grp_leader = thread->task->group_leader; + if (grp_leader && is_sf(curr) && test_task_ux(thread->task->group_leader) && oneway) { + set_once_ux(thread->task); + } + } +#endif binder_wakeup_thread_ilocked(proc, thread, !oneway /* sync */); + } binder_inner_proc_unlock(proc); binder_node_unlock(node); @@ -2972,6 +3487,13 @@ static void binder_transaction(struct binder_proc *proc, int t_debug_id = atomic_inc_return(&binder_last_id); char *secctx = NULL; u32 secctx_sz = 0; +#ifdef OPLUS_FEATURE_HANS_FREEZE + char buf_data[INTERFACETOKEN_BUFF_SIZE]; + size_t buf_data_size; + char buf[INTERFACETOKEN_BUFF_SIZE] = {0}; + int i = 0; + int j = 0; +#endif /*OPLUS_FEATURE_HANS_FREEZE*/ e = binder_transaction_log_add(&binder_transaction_log); e->debug_id = t_debug_id; @@ -3087,6 +3609,26 @@ static void binder_transaction(struct binder_proc *proc, return_error_line = __LINE__; goto err_dead_binder; } + +#ifdef OPLUS_FEATURE_HANS_FREEZE + if (!(tr->flags & TF_ONE_WAY) //report sync binder call + && target_proc + && (task_uid(target_proc->tsk).val > MIN_USERAPP_UID) + && (proc->pid != target_proc->pid) + && is_frozen_tg(target_proc->tsk)) { + hans_report(SYNC_BINDER, task_tgid_nr(proc->tsk), task_uid(proc->tsk).val, task_tgid_nr(target_proc->tsk), task_uid(target_proc->tsk).val, "SYNC_BINDER", -1); + } +#endif /*OPLUS_FEATURE_HANS_FREEZE*/ + +#if defined(CONFIG_CFS_BANDWIDTH) + if (!(tr->flags & TF_ONE_WAY) //report sync binder call + && target_proc + && (task_uid(target_proc->tsk).val > MIN_USERAPP_UID || task_uid(target_proc->tsk).val == HANS_SYSTEM_UID) //uid >10000 + && is_belong_cpugrp(target_proc->tsk)) { + hans_report(SYNC_BINDER_CPUCTL, task_tgid_nr(proc->tsk), task_uid(proc->tsk).val, task_tgid_nr(target_proc->tsk), task_uid(target_proc->tsk).val, "SYNC_BINDER_CPUCTL", -1); + } +#endif + e->to_node = target_node->debug_id; if (security_binder_transaction(proc->cred, target_proc->cred) < 0) { @@ -3319,6 +3861,31 @@ static void binder_transaction(struct binder_proc *proc, return_error_line = __LINE__; goto err_bad_offset; } +#ifdef OPLUS_FEATURE_HANS_FREEZE + if ((tr->flags & TF_ONE_WAY) //report async binder call + && target_proc + && (task_uid(target_proc->tsk).val > MIN_USERAPP_UID) + && (proc->pid != target_proc->pid) + && is_frozen_tg(target_proc->tsk)) { + buf_data_size = tr->data_size>INTERFACETOKEN_BUFF_SIZE ?INTERFACETOKEN_BUFF_SIZE:tr->data_size; + if (!copy_from_user(buf_data, (char*)tr->data.ptr.buffer, buf_data_size)) { + //1.skip first PARCEL_OFFSET bytes (useless data) + //2.make sure the invalid address issue is not occuring(j =PARCEL_OFFSET+1, j+=2) + //3.java layer uses 2 bytes char. And only the first bytes has the data.(p+=2) + if (buf_data_size > PARCEL_OFFSET) { + char *p = (char *)(buf_data) + PARCEL_OFFSET; + j = PARCEL_OFFSET + 1; + while (i < INTERFACETOKEN_BUFF_SIZE && j < buf_data_size && *p != '\0') { + buf[i++] = *p; + j += 2; + p += 2; + } + if (i == INTERFACETOKEN_BUFF_SIZE) buf[i-1] = '\0'; + } + hans_report(ASYNC_BINDER, task_tgid_nr(proc->tsk), task_uid(proc->tsk).val, task_tgid_nr(target_proc->tsk), task_uid(target_proc->tsk).val, buf, tr->code); + } + } +#endif /*OPLUS_FEATURE_HANS_FREEZE*/ off_start_offset = ALIGN(tr->data_size, sizeof(void *)); buffer_offset = off_start_offset; off_end_offset = off_start_offset + tr->offsets_size; @@ -3360,7 +3927,11 @@ static void binder_transaction(struct binder_proc *proc, struct flat_binder_object *fp; fp = to_flat_binder_object(hdr); +#if defined(CONFIG_OPLUS_FEATURE_BINDER_STATS_ENABLE) + ret = binder_translate_binder(tr, fp, t, thread); +#else ret = binder_translate_binder(fp, t, thread); +#endif if (ret < 0) { return_error = BR_FAILED_REPLY; return_error_param = ret; @@ -3516,6 +4087,9 @@ static void binder_transaction(struct binder_proc *proc, t->work.type = BINDER_WORK_TRANSACTION; if (reply) { +#ifdef CONFIG_OPLUS_FEATURE_INPUT_BOOST_V4 + bool oneway = !!(t->flags & TF_ONE_WAY); +#endif /* CONFIG_OPLUS_FEATURE_INPUT_BOOST_V4 */ binder_enqueue_thread_work(thread, tcomplete); binder_inner_proc_lock(target_proc); if (target_thread->is_dead) { @@ -3528,6 +4102,19 @@ static void binder_transaction(struct binder_proc *proc, binder_inner_proc_unlock(target_proc); wake_up_interruptible_sync(&target_thread->wait); +#ifdef OPLUS_FEATURE_SCHED_ASSIST + if (sysctl_sched_assist_enabled && !proc->proc_type) { + binder_unset_inherit_ux(thread->task); + } +#endif /* OPLUS_FEATURE_SCHED_ASSIST */ +#ifdef CONFIG_OPLUS_FEATURE_INPUT_BOOST_V4 + binder_thread_remove_fbg(thread->task, oneway); +#endif /* CONFIG_OPLUS_FEATURE_INPUT_BOOST_V4 */ +#ifdef CONFIG_OPLUS_BINDER_STRATEGY + binder_inner_proc_lock(proc); + obwork_check_restrict_off(proc); + binder_inner_proc_unlock(proc); +#endif binder_restore_priority(current, in_reply_to->saved_priority); binder_free_transaction(in_reply_to); } else if (!(t->flags & TF_ONE_WAY)) { @@ -3911,6 +4498,9 @@ static int binder_thread_write(struct binder_proc *proc, proc->requested_threads_started++; } thread->looper |= BINDER_LOOPER_STATE_REGISTERED; +#ifdef CONFIG_OPLUS_BINDER_STRATEGY + obthread_init(proc, thread); +#endif binder_inner_proc_unlock(proc); break; case BC_ENTER_LOOPER: @@ -4170,11 +4760,36 @@ static int binder_wait_for_work(struct binder_thread *thread, prepare_to_wait(&thread->wait, &wait, TASK_INTERRUPTIBLE); if (binder_has_work_ilocked(thread, do_proc_work)) break; +#ifdef OPLUS_FEATURE_SCHED_ASSIST + if (do_proc_work) { + list_add(&thread->waiting_thread_node, + &proc->waiting_threads); + + if (sysctl_sched_assist_enabled) { + binder_unset_inherit_ux(thread->task); + } + } +#else /* OPLUS_FEATURE_SCHED_ASSIST */ if (do_proc_work) list_add(&thread->waiting_thread_node, &proc->waiting_threads); +#endif /* OPLUS_FEATURE_SCHED_ASSIST */ +#if IS_ENABLED(CONFIG_OPLUS_FEATURE_CPU_JANKINFO) + android_vh_binder_wait_for_work_hanlder(NULL, + do_proc_work, thread, proc); +#endif binder_inner_proc_unlock(proc); +#ifdef OPLUS_FEATURE_HEALTHINFO +#ifdef CONFIG_OPLUS_JANK_INFO + current->in_binder = 1; +#endif +#endif /* OPLUS_FEATURE_HEALTHINFO */ schedule(); +#ifdef OPLUS_FEATURE_HEALTHINFO +#ifdef CONFIG_OPLUS_JANK_INFO + current->in_binder = 0; +#endif +#endif /* OPLUS_FEATURE_HEALTHINFO */ binder_inner_proc_lock(proc); list_del_init(&thread->waiting_thread_node); if (signal_pending(current)) { @@ -4253,6 +4868,11 @@ retry: binder_inner_proc_lock(proc); if (!binder_worklist_empty_ilocked(&thread->todo)) list = &thread->todo; +#ifdef CONFIG_OPLUS_BINDER_STRATEGY + else if (obthread_has_work(thread) && wait_for_proc_work) { + list = &ob_target.ob_list; + } +#endif else if (!binder_worklist_empty_ilocked(&proc->todo) && wait_for_proc_work) list = &proc->todo; @@ -4448,8 +5068,13 @@ retry: trd->cookie = target_node->cookie; node_prio.sched_policy = target_node->sched_policy; node_prio.prio = target_node->min_priority; +#ifdef OPLUS_FEATURE_SCHED_ASSIST + binder_transaction_priority(thread, current, t, node_prio, + target_node->inherit_rt); +#else binder_transaction_priority(current, t, node_prio, target_node->inherit_rt); +#endif /* OPLUS_FEATURE_SCHED_ASSIST */ cmd = BR_TRANSACTION; } else { trd->target.ptr = 0; @@ -4467,6 +5092,11 @@ retry: trd->sender_pid = task_tgid_nr_ns(sender, task_active_pid_ns(current)); +#ifdef OPLUS_FEATURE_SCHED_ASSIST + if (sysctl_sched_assist_enabled) { + binder_set_inherit_ux(thread->task, t_from->task); + } +#endif /* OPLUS_FEATURE_SCHED_ASSIST */ } else { trd->sender_pid = 0; } @@ -4686,6 +5316,9 @@ static void binder_free_proc(struct binder_proc *proc) BUG_ON(!list_empty(&proc->todo)); BUG_ON(!list_empty(&proc->delivered_death)); +#ifdef CONFIG_OPLUS_BINDER_STRATEGY + obproc_free(proc); +#endif device = container_of(proc->context, struct binder_device, context); if (refcount_dec_and_test(&device->ref)) { kfree(proc->context->name); @@ -4861,6 +5494,10 @@ static int binder_ioctl_write_read(struct file *filp, binder_inner_proc_lock(proc); if (!binder_worklist_empty_ilocked(&proc->todo)) binder_wakeup_proc_ilocked(proc); +#ifdef CONFIG_OPLUS_BINDER_STRATEGY + if (obproc_has_work(proc)) + obthread_wakeup(proc); +#endif binder_inner_proc_unlock(proc); if (ret < 0) { if (copy_to_user(ubuf, &bwr, sizeof(bwr))) @@ -4922,6 +5559,15 @@ static int binder_ioctl_set_ctx_mgr(struct file *filp, new_node->has_strong_ref = 1; new_node->has_weak_ref = 1; context->binder_context_mgr_node = new_node; +#if defined(CONFIG_OPLUS_FEATURE_BINDER_STATS_ENABLE) + if (NULL != context->binder_context_mgr_node && + NULL != context->binder_context_mgr_node->proc && + NULL != context->binder_context_mgr_node->proc->tsk) { + snprintf(context->binder_context_mgr_node->service_name, OPLUS_MAX_SERVICE_NAME_LEN, + "%s", context->binder_context_mgr_node->proc->tsk->comm); + context->binder_context_mgr_node->service_name[OPLUS_MAX_SERVICE_NAME_LEN-1] = '\0'; + } +#endif binder_node_unlock(new_node); binder_put_node(new_node); out: @@ -5219,6 +5865,9 @@ static int binder_open(struct inode *nodp, struct file *filp) spin_lock_init(&proc->outer_lock); get_task_struct(current->group_leader); proc->tsk = current->group_leader; +#ifdef OPLUS_FEATURE_SCHED_ASSIST + proc->proc_type = is_binder_proc_sf(proc) ? 1 : 0; +#endif /* OPLUS_FEATURE_SCHED_ASSIST */ mutex_init(&proc->files_lock); proc->cred = get_cred(filp->f_cred); INIT_LIST_HEAD(&proc->todo); @@ -5248,6 +5897,9 @@ static int binder_open(struct inode *nodp, struct file *filp) INIT_LIST_HEAD(&proc->delivered_death); INIT_LIST_HEAD(&proc->waiting_threads); filp->private_data = proc; +#ifdef CONFIG_OPLUS_BINDER_STRATEGY + obtarget_init(proc); +#endif mutex_lock(&binder_procs_lock); hlist_add_head(&proc->proc_node, &binder_procs); @@ -5491,6 +6143,10 @@ static void binder_deferred_release(struct binder_proc *proc) binder_release_work(proc, &proc->todo); binder_release_work(proc, &proc->delivered_death); +#ifdef CONFIG_OPLUS_BINDER_STRATEGY + if (proc == ob_target.ob_proc) + binder_release_work(proc, &ob_target.ob_list); +#endif binder_debug(BINDER_DEBUG_OPEN_CLOSE, "%s: %d threads %d, nodes %d (ref %d), refs %d, active transactions %d\n", @@ -5989,6 +6645,71 @@ int binder_state_show(struct seq_file *m, void *unused) return 0; } +#ifdef OPLUS_FEATURE_HANS_FREEZE +static void hans_check_uid_proc_status(struct binder_proc *proc, enum message_type type) +{ + struct rb_node *n = NULL; + struct binder_thread *thread = NULL; + int uid = -1; + struct binder_transaction *btrans = NULL; + bool empty = true; + + /* check binder_thread/transaction_stack/binder_proc ongoing transaction */ + binder_inner_proc_lock(proc); + for (n = rb_first(&proc->threads); n != NULL; n = rb_next(n)) { + thread = rb_entry(n, struct binder_thread, rb_node); + empty = binder_worklist_empty_ilocked(&thread->todo); + + if (thread->task != NULL) { + /* has "todo" binder thread in worklist? */ + uid = task_uid(thread->task).val; + if (!empty) { + binder_inner_proc_unlock(proc); + hans_report(type, -1, -1, -1, uid, "FROZEN_TRANS_THREAD", 1); + return; + } + + /* has transcation in transaction_stack? */ + btrans = thread->transaction_stack; + if (btrans) { + spin_lock(&btrans->lock); + if (btrans->to_thread == thread) { + /* only report incoming binder call */ + spin_unlock(&btrans->lock); + binder_inner_proc_unlock(proc); + hans_report(type, -1, -1, -1, uid, "FROZEN_TRANS_STACK", 1); + return; + } + spin_unlock(&btrans->lock); + } + } + } + + /* has "todo" binder proc in worklist */ + empty = binder_worklist_empty_ilocked(&proc->todo); + if (proc->tsk != NULL && !empty) { + uid = task_uid(proc->tsk).val; + binder_inner_proc_unlock(proc); + hans_report(type, -1, -1, -1, uid, "FROZEN_TRANS_PROC", 1); + return; + } + binder_inner_proc_unlock(proc); +} + +void hans_check_frozen_transcation(uid_t uid, enum message_type type) +{ + struct binder_proc *proc; + + mutex_lock(&binder_procs_lock); + hlist_for_each_entry(proc, &binder_procs, proc_node) { + if (proc != NULL && (task_uid(proc->tsk).val == uid)) { + hans_check_uid_proc_status(proc, type); + } + } + mutex_unlock(&binder_procs_lock); +} +#endif /*OPLUS_FEATURE_HANS_FREEZE*/ + int binder_stats_show(struct seq_file *m, void *unused) { struct binder_proc *proc; diff --git a/drivers/android/binder_alloc.c b/drivers/android/binder_alloc.c index 59ffccbcca3c..34340f9c3f96 100644 --- a/drivers/android/binder_alloc.c +++ b/drivers/android/binder_alloc.c @@ -33,6 +33,9 @@ #include #include "binder_alloc.h" #include "binder_trace.h" +#ifdef OPLUS_FEATURE_HANS_FREEZE +#include +#endif /*OPLUS_FEATURE_HANS_FREEZE*/ struct list_lru binder_alloc_lru; @@ -400,6 +403,9 @@ static struct binder_buffer *binder_alloc_new_buf_locked( void __user *end_page_addr; size_t size, data_offsets_size; int ret; +#ifdef OPLUS_FEATURE_HANS_FREEZE + struct task_struct *p = NULL; +#endif /*OPLUS_FEATURE_HANS_FREEZE*/ if (!binder_alloc_get_vma(alloc)) { binder_alloc_debug(BINDER_DEBUG_USER_ERROR, @@ -424,6 +430,18 @@ static struct binder_buffer *binder_alloc_new_buf_locked( alloc->pid, extra_buffers_size); return ERR_PTR(-EINVAL); } +#ifdef OPLUS_FEATURE_HANS_FREEZE + if (is_async + && (alloc->free_async_space < 3 * (size + sizeof(struct binder_buffer)) + || (alloc->free_async_space < ((alloc->buffer_size / 2) * 9 / 10)))) { + rcu_read_lock(); + p = find_task_by_vpid(alloc->pid); + rcu_read_unlock(); + if (p != NULL && is_frozen_tg(p)) { + hans_report(ASYNC_BINDER, task_tgid_nr(current), task_uid(current).val, task_tgid_nr(p), task_uid(p).val, "free_buffer_full", -1); + } + } +#endif /*OPLUS_FEATURE_HANS_FREEZE*/ if (is_async && alloc->free_async_space < size + sizeof(struct binder_buffer)) { binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC, @@ -548,6 +566,15 @@ static struct binder_buffer *binder_alloc_new_buf_locked( debug_low_async_space_locked(alloc, pid); } } + + #ifdef OPLUS_BUG_STABILITY + if (size > 2000000 /*2MB*/){ + binder_alloc_debug(BINDER_DEBUG_USER_ERROR, + "%d: binder_alloc_buf size %zd successed, but it seems too large.\n", + alloc->pid, size); + } + #endif /*OPLUS_BUG_STABILITY*/ + return buffer; err_alloc_buf_struct_failed: diff --git a/drivers/android/binder_internal.h b/drivers/android/binder_internal.h index 8d0bffcc9e27..e30ccc1ef8b4 100644 --- a/drivers/android/binder_internal.h +++ b/drivers/android/binder_internal.h @@ -12,6 +12,10 @@ #include #include #include +#ifdef CONFIG_OPLUS_FEATURE_CPU_JANKINFO +#include "binder_alloc.h" +#endif + struct binder_context { struct binder_node *binder_context_mgr_node; @@ -141,6 +145,406 @@ struct binder_transaction_log { struct binder_transaction_log_entry entry[32]; }; +#ifdef CONFIG_OPLUS_FEATURE_CPU_JANKINFO +#define OPLUS_MAX_SERVICE_NAME_LEN 32 +enum binder_stat_types { + BINDER_STAT_PROC, + BINDER_STAT_THREAD, + BINDER_STAT_NODE, + BINDER_STAT_REF, + BINDER_STAT_DEATH, + BINDER_STAT_TRANSACTION, + BINDER_STAT_TRANSACTION_COMPLETE, + BINDER_STAT_COUNT +}; + +struct binder_stats { + atomic_t br[_IOC_NR(BR_FAILED_REPLY) + 1]; + atomic_t bc[_IOC_NR(BC_REPLY_SG) + 1]; + atomic_t obj_created[BINDER_STAT_COUNT]; + atomic_t obj_deleted[BINDER_STAT_COUNT]; +}; +/** + * struct binder_work - work enqueued on a worklist + * @entry: node enqueued on list + * @type: type of work to be performed + * + * There are separate work lists for proc, thread, and node (async). + */ +struct binder_work { + struct list_head entry; + + enum binder_work_type { + BINDER_WORK_TRANSACTION = 1, + BINDER_WORK_TRANSACTION_COMPLETE, + BINDER_WORK_RETURN_ERROR, + BINDER_WORK_NODE, + BINDER_WORK_DEAD_BINDER, + BINDER_WORK_DEAD_BINDER_AND_CLEAR, + BINDER_WORK_CLEAR_DEATH_NOTIFICATION, + } type; +#ifdef CONFIG_OPLUS_BINDER_STRATEGY + u64 ob_begin; +#endif +}; + +struct binder_error { + struct binder_work work; + uint32_t cmd; +}; +/** + * struct binder_node - binder node bookkeeping + * @debug_id: unique ID for debugging + * (invariant after initialized) + * @lock: lock for node fields + * @work: worklist element for node work + * (protected by @proc->inner_lock) + * @rb_node: element for proc->nodes tree + * (protected by @proc->inner_lock) + * @dead_node: element for binder_dead_nodes list + * (protected by binder_dead_nodes_lock) + * @proc: binder_proc that owns this node + * (invariant after initialized) + * @refs: list of references on this node + * (protected by @lock) + * @internal_strong_refs: used to take strong references when + * initiating a transaction + * (protected by @proc->inner_lock if @proc + * and by @lock) + * @local_weak_refs: weak user refs from local process + * (protected by @proc->inner_lock if @proc + * and by @lock) + * @local_strong_refs: strong user refs from local process + * (protected by @proc->inner_lock if @proc + * and by @lock) + * @tmp_refs: temporary kernel refs + * (protected by @proc->inner_lock while @proc + * is valid, and by binder_dead_nodes_lock + * if @proc is NULL. During inc/dec and node release + * it is also protected by @lock to provide safety + * as the node dies and @proc becomes NULL) + * @ptr: userspace pointer for node + * (invariant, no lock needed) + * @cookie: userspace cookie for node + * (invariant, no lock needed) + * @has_strong_ref: userspace notified of strong ref + * (protected by @proc->inner_lock if @proc + * and by @lock) + * @pending_strong_ref: userspace has acked notification of strong ref + * (protected by @proc->inner_lock if @proc + * and by @lock) + * @has_weak_ref: userspace notified of weak ref + * (protected by @proc->inner_lock if @proc + * and by @lock) + * @pending_weak_ref: userspace has acked notification of weak ref + * (protected by @proc->inner_lock if @proc + * and by @lock) + * @has_async_transaction: async transaction to node in progress + * (protected by @lock) + * @sched_policy: minimum scheduling policy for node + * (invariant after initialized) + * @accept_fds: file descriptor operations supported for node + * (invariant after initialized) + * @min_priority: minimum scheduling priority + * (invariant after initialized) + * @inherit_rt: inherit RT scheduling policy from caller + * @txn_security_ctx: require sender's security context + * (invariant after initialized) + * @async_todo: list of async work items + * (protected by @proc->inner_lock) + * + * Bookkeeping structure for binder nodes. + */ +struct binder_node { + int debug_id; + spinlock_t lock; + struct binder_work work; + union { + struct rb_node rb_node; + struct hlist_node dead_node; + }; + struct binder_proc *proc; + struct hlist_head refs; + int internal_strong_refs; + int local_weak_refs; + int local_strong_refs; + int tmp_refs; + binder_uintptr_t ptr; + binder_uintptr_t cookie; + struct { + /* + * bitfield elements protected by + * proc inner_lock + */ + u8 has_strong_ref:1; + u8 pending_strong_ref:1; + u8 has_weak_ref:1; + u8 pending_weak_ref:1; + }; + struct { + /* + * invariant after initialization + */ + u8 sched_policy:2; + u8 inherit_rt:1; + u8 accept_fds:1; + u8 txn_security_ctx:1; + u8 min_priority; + }; + bool has_async_transaction; + struct list_head async_todo; +#if defined(CONFIG_OPLUS_FEATURE_BINDER_STATS_ENABLE) + char service_name[OPLUS_MAX_SERVICE_NAME_LEN]; +#endif +}; + +struct binder_ref_death { + /** + * @work: worklist element for death notifications + * (protected by inner_lock of the proc that + * this ref belongs to) + */ + struct binder_work work; + binder_uintptr_t cookie; +}; + +/** + * struct binder_ref_data - binder_ref counts and id + * @debug_id: unique ID for the ref + * @desc: unique userspace handle for ref + * @strong: strong ref count (debugging only if not locked) + * @weak: weak ref count (debugging only if not locked) + * + * Structure to hold ref count and ref id information. Since + * the actual ref can only be accessed with a lock, this structure + * is used to return information about the ref to callers of + * ref inc/dec functions. + */ +struct binder_ref_data { + int debug_id; + uint32_t desc; + int strong; + int weak; +}; + +/** + * struct binder_ref - struct to track references on nodes + * @data: binder_ref_data containing id, handle, and current refcounts + * @rb_node_desc: node for lookup by @data.desc in proc's rb_tree + * @rb_node_node: node for lookup by @node in proc's rb_tree + * @node_entry: list entry for node->refs list in target node + * (protected by @node->lock) + * @proc: binder_proc containing ref + * @node: binder_node of target node. When cleaning up a + * ref for deletion in binder_cleanup_ref, a non-NULL + * @node indicates the node must be freed + * @death: pointer to death notification (ref_death) if requested + * (protected by @node->lock) + * + * Structure to track references from procA to target node (on procB). This + * structure is unsafe to access without holding @proc->outer_lock. + */ +struct binder_ref { + /* Lookups needed: */ + /* node + proc => ref (transaction) */ + /* desc + proc => ref (transaction, inc/dec ref) */ + /* node => refs + procs (proc exit) */ + struct binder_ref_data data; + struct rb_node rb_node_desc; + struct rb_node rb_node_node; + struct hlist_node node_entry; + struct binder_proc *proc; + struct binder_node *node; + struct binder_ref_death *death; +}; + +enum binder_deferred_state { + BINDER_DEFERRED_PUT_FILES = 0x01, + BINDER_DEFERRED_FLUSH = 0x02, + BINDER_DEFERRED_RELEASE = 0x04, +}; + +/** + * struct binder_priority - scheduler policy and priority + * @sched_policy scheduler policy + * @prio [100..139] for SCHED_NORMAL, [0..99] for FIFO/RT + * + * The binder driver supports inheriting the following scheduler policies: + * SCHED_NORMAL + * SCHED_BATCH + * SCHED_FIFO + * SCHED_RR + */ +struct binder_priority { + unsigned int sched_policy; + int prio; +}; + +/** + * struct binder_proc - binder process bookkeeping + * @proc_node: element for binder_procs list + * @threads: rbtree of binder_threads in this proc + * (protected by @inner_lock) + * @nodes: rbtree of binder nodes associated with + * this proc ordered by node->ptr + * (protected by @inner_lock) + * @refs_by_desc: rbtree of refs ordered by ref->desc + * (protected by @outer_lock) + * @refs_by_node: rbtree of refs ordered by ref->node + * (protected by @outer_lock) + * @waiting_threads: threads currently waiting for proc work + * (protected by @inner_lock) + * @pid PID of group_leader of process + * (invariant after initialized) + * @tsk task_struct for group_leader of process + * (invariant after initialized) + * @files files_struct for process + * (protected by @files_lock) + * @files_lock mutex to protect @files + * @cred struct cred associated with the `struct file` + * in binder_open() + * (invariant after initialized) + * @deferred_work_node: element for binder_deferred_list + * (protected by binder_deferred_lock) + * @deferred_work: bitmap of deferred work to perform + * (protected by binder_deferred_lock) + * @is_dead: process is dead and awaiting free + * when outstanding transactions are cleaned up + * (protected by @inner_lock) + * @todo: list of work for this process + * (protected by @inner_lock) + * @stats: per-process binder statistics + * (atomics, no lock needed) + * @delivered_death: list of delivered death notification + * (protected by @inner_lock) + * @max_threads: cap on number of binder threads + * (protected by @inner_lock) + * @requested_threads: number of binder threads requested but not + * yet started. In current implementation, can + * only be 0 or 1. + * (protected by @inner_lock) + * @requested_threads_started: number binder threads started + * (protected by @inner_lock) + * @tmp_ref: temporary reference to indicate proc is in use + * (protected by @inner_lock) + * @default_priority: default scheduler priority + * (invariant after initialized) + * @debugfs_entry: debugfs node + * @alloc: binder allocator bookkeeping + * @context: binder_context for this proc + * (invariant after initialized) + * @inner_lock: can nest under outer_lock and/or node lock + * @outer_lock: no nesting under innor or node lock + * Lock order: 1) outer, 2) node, 3) inner + * @binderfs_entry: process-specific binderfs log file + * + * Bookkeeping structure for binder processes + */ +struct binder_proc { + struct hlist_node proc_node; + struct rb_root threads; + struct rb_root nodes; + struct rb_root refs_by_desc; + struct rb_root refs_by_node; + struct list_head waiting_threads; + int pid; + struct task_struct *tsk; + struct files_struct *files; + struct mutex files_lock; + const struct cred *cred; + struct hlist_node deferred_work_node; + int deferred_work; + bool is_dead; +#ifdef OPLUS_FEATURE_SCHED_ASSIST + int proc_type; +#endif /* OPLUS_FEATURE_SCHED_ASSIST */ + + struct list_head todo; + struct binder_stats stats; + struct list_head delivered_death; + int max_threads; + int requested_threads; + int requested_threads_started; + int tmp_ref; + struct binder_priority default_priority; + struct dentry *debugfs_entry; + struct binder_alloc alloc; + struct binder_context *context; + spinlock_t inner_lock; + spinlock_t outer_lock; + struct dentry *binderfs_entry; +}; + +enum { + BINDER_LOOPER_STATE_REGISTERED = 0x01, + BINDER_LOOPER_STATE_ENTERED = 0x02, + BINDER_LOOPER_STATE_EXITED = 0x04, + BINDER_LOOPER_STATE_INVALID = 0x08, + BINDER_LOOPER_STATE_WAITING = 0x10, + BINDER_LOOPER_STATE_POLL = 0x20, +#ifdef CONFIG_OPLUS_BINDER_STRATEGY + BINDER_LOOPER_STATE_BACKGROUND = 0x40, +#endif +}; + +/** + * struct binder_thread - binder thread bookkeeping + * @proc: binder process for this thread + * (invariant after initialization) + * @rb_node: element for proc->threads rbtree + * (protected by @proc->inner_lock) + * @waiting_thread_node: element for @proc->waiting_threads list + * (protected by @proc->inner_lock) + * @pid: PID for this thread + * (invariant after initialization) + * @looper: bitmap of looping state + * (only accessed by this thread) + * @looper_needs_return: looping thread needs to exit driver + * (no lock needed) + * @transaction_stack: stack of in-progress transactions for this thread + * (protected by @proc->inner_lock) + * @todo: list of work to do for this thread + * (protected by @proc->inner_lock) + * @process_todo: whether work in @todo should be processed + * (protected by @proc->inner_lock) + * @return_error: transaction errors reported by this thread + * (only accessed by this thread) + * @reply_error: transaction errors reported by target thread + * (protected by @proc->inner_lock) + * @wait: wait queue for thread work + * @stats: per-thread statistics + * (atomics, no lock needed) + * @tmp_ref: temporary reference to indicate thread is in use + * (atomic since @proc->inner_lock cannot + * always be acquired) + * @is_dead: thread is dead and awaiting free + * when outstanding transactions are cleaned up + * (protected by @proc->inner_lock) + * @task: struct task_struct for this thread + * + * Bookkeeping structure for binder threads. + */ +struct binder_thread { + struct binder_proc *proc; + struct rb_node rb_node; + struct list_head waiting_thread_node; + int pid; + int looper; /* only modified by this thread */ + bool looper_need_return; /* can be written by other thread */ + struct binder_transaction *transaction_stack; + struct list_head todo; + bool process_todo; + struct binder_error return_error; + struct binder_error reply_error; + wait_queue_head_t wait; + struct binder_stats stats; + atomic_t tmp_ref; + bool is_dead; + struct task_struct *task; +}; + +#endif + extern struct binder_transaction_log binder_transaction_log; extern struct binder_transaction_log binder_transaction_log_failed; #endif /* _LINUX_BINDER_INTERNAL_H */ diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig index d85275a7e0da..df1089f03414 100644 --- a/drivers/base/Kconfig +++ b/drivers/base/Kconfig @@ -156,6 +156,10 @@ config DEBUG_TEST_DRIVER_REMOVE source "drivers/base/test/Kconfig" +#ifdef OPLUS_FEATURE_TP_BASIC +source "drivers/base/kernelFwUpdate/Kconfig" +#endif /*OPLUS_FEATURE_TP_BASIC*/ + config SYS_HYPERVISOR bool default n diff --git a/drivers/base/Makefile b/drivers/base/Makefile index 704f44295810..e8226ec70749 100644 --- a/drivers/base/Makefile +++ b/drivers/base/Makefile @@ -28,3 +28,6 @@ obj-y += test/ ccflags-$(CONFIG_DEBUG_DRIVER) := -DDEBUG +#ifdef OPLUS_FEATURE_TP_BASIC +obj-$(CONFIG_OPLUS_FW_UPDATE) += kernelFwUpdate/ +#endif /*OPLUS_FEATURE_TP_BASIC*/ diff --git a/drivers/base/firmware_loader/fallback.c b/drivers/base/firmware_loader/fallback.c index 821e27bda4ca..8a1bbfb346b7 100644 --- a/drivers/base/firmware_loader/fallback.c +++ b/drivers/base/firmware_loader/fallback.c @@ -544,6 +544,10 @@ static int fw_load_sysfs_fallback(struct fw_sysfs *fw_sysfs, struct device *f_dev = &fw_sysfs->dev; struct fw_priv *fw_priv = fw_sysfs->fw_priv; +#ifdef OPLUS_FEATURE_TP_BSPFWUPDATE + char *envp[2]={"FwUp=compare", NULL}; +#endif/*OPLUS_FEATURE_TP_BSPFWUPDATE*/ + /* fall back on userspace loading */ if (!fw_priv->data) fw_priv->is_paged_buf = true; @@ -569,7 +573,15 @@ static int fw_load_sysfs_fallback(struct fw_sysfs *fw_sysfs, fw_priv->need_uevent = true; dev_set_uevent_suppress(f_dev, false); dev_dbg(f_dev, "firmware: requesting %s\n", fw_priv->fw_name); +#ifdef OPLUS_FEATURE_TP_BSPFWUPDATE + if (opt_flags & FW_OPT_COMPARE) { + kobject_uevent_env(&fw_sysfs->dev.kobj, KOBJ_CHANGE,envp); + } else { + kobject_uevent(&fw_sysfs->dev.kobj, KOBJ_ADD); + } +#else kobject_uevent(&fw_sysfs->dev.kobj, KOBJ_ADD); +#endif/*OPLUS_FEATURE_TP_BSPFWUPDATE*/ } else { timeout = MAX_JIFFY_OFFSET; } diff --git a/drivers/base/firmware_loader/firmware.h b/drivers/base/firmware_loader/firmware.h index e2000b4ad09b..ef05a791b5af 100644 --- a/drivers/base/firmware_loader/firmware.h +++ b/drivers/base/firmware_loader/firmware.h @@ -37,6 +37,9 @@ enum fw_opt { FW_OPT_NO_WARN = BIT(3), FW_OPT_NOCACHE = BIT(4), FW_OPT_NOFALLBACK = BIT(5), +#ifdef OPLUS_FEATURE_TP_BSPFWUPDATE + FW_OPT_COMPARE = BIT(6), +#endif/*OPLUS_FEATURE_TP_BSPFWUPDATE*/ }; enum fw_status { diff --git a/drivers/base/firmware_loader/main.c b/drivers/base/firmware_loader/main.c index 8b716933fe89..7c676ed56cf7 100644 --- a/drivers/base/firmware_loader/main.c +++ b/drivers/base/firmware_loader/main.c @@ -283,6 +283,10 @@ static void free_fw_priv(struct fw_priv *fw_priv) /* direct firmware loading support */ static char fw_path_para[256]; static const char * const fw_path[] = { + //#ifdef OPLUS_FEATURE_WIFI_RUSUPGRADE + //add for: support auto update function, include mtk fw, mtk wifi.cfg, qcom fw, qcom bdf, qcom ini + "/data/misc/firmware/active", + //#endif /* OPLUS_FEATURE_WIFI_RUSUPGRADE */ fw_path_para, "/lib/firmware/updates/" UTS_RELEASE, "/lib/firmware/updates", @@ -298,8 +302,14 @@ static const char * const fw_path[] = { module_param_string(path, fw_path_para, sizeof(fw_path_para), 0644); MODULE_PARM_DESC(path, "customized firmware image search path with a higher priority than default path"); +#ifdef OPLUS_FEATURE_TP_BSPFWUPDATE +static int fw_get_filesystem_firmware(struct device *device, + struct fw_priv *fw_priv, + enum fw_opt opt_flags) +#else static int fw_get_filesystem_firmware(struct device *device, struct fw_priv *fw_priv) +#endif /*OPLUS_FEATURE_TP_BSPFWUPDATE*/ { loff_t size; int i, len; @@ -308,6 +318,13 @@ fw_get_filesystem_firmware(struct device *device, struct fw_priv *fw_priv) enum kernel_read_file_id id = READING_FIRMWARE; size_t msize = INT_MAX; +#ifdef OPLUS_FEATURE_TP_BSPFWUPDATE + if(opt_flags & FW_OPT_COMPARE) { + pr_err("%s opt_flags get FW_OPT_COMPARE!\n", __func__); + return rc; + } +#endif/*OPLUS_FEATURE_TP_BSPFWUPDATE*/ + /* Already populated data member means we're loading into a buffer */ if (fw_priv->data) { id = READING_FIRMWARE_PREALLOC_BUFFER; @@ -330,6 +347,24 @@ fw_get_filesystem_firmware(struct device *device, struct fw_priv *fw_priv) break; } +#if defined(OPLUS_FEATURE_CAMERA_OIS) + if (strstr(fw_path[i], "/lib/firmware/") != NULL) { + if (strstr(fw_priv->fw_name, "ois_") != NULL) { + snprintf(path, PATH_MAX, "%s/%s", "/odm/vendor/firmware", fw_priv->fw_name); + } + } +#endif /*OPLUS_FEATURE_CAMERA_OIS*/ +#if defined(OPLUS_FEATURE_PXLW_IRIS5) + if (!strcmp(fw_priv->fw_name, "iris5.fw") + || !strcmp(fw_priv->fw_name, "iris5_ccf1.fw") + || !strcmp(fw_priv->fw_name, "iris5_ccf2.fw")) { + snprintf(path, PATH_MAX, "%s/%s", "/odm/vendor/firmware", fw_priv->fw_name); + } + if (!strcmp(fw_priv->fw_name, "iris5_ccf1b.fw") + || !strcmp(fw_priv->fw_name, "iris5_ccf2b.fw")) { + snprintf(path, PATH_MAX, "%s/%s", "/data/vendor/display", fw_priv->fw_name); + } +#endif /*OPLUS_FEATURE_PXLW_IRIS5*/ fw_priv->size = 0; rc = kernel_read_file_from_path(path, &fw_priv->data, &size, msize, id); @@ -592,7 +627,11 @@ _request_firmware(const struct firmware **firmware_p, const char *name, if (ret <= 0) /* error or already assigned */ goto out; +#ifdef OPLUS_FEATURE_TP_BSPFWUPDATE + ret = fw_get_filesystem_firmware(device, fw->priv, opt_flags); +#else ret = fw_get_filesystem_firmware(device, fw->priv); +#endif/*OPLUS_FEATURE_TP_BSPFWUPDATE*/ if (ret) { if (!(opt_flags & FW_OPT_NO_WARN)) dev_dbg(device, @@ -648,6 +687,25 @@ request_firmware(const struct firmware **firmware_p, const char *name, } EXPORT_SYMBOL(request_firmware); + +#ifdef VENDOR_EDIT +//Add for: reload wlan bdf without using cache +int +request_firmware_no_cache(const struct firmware **firmware_p, const char *name, + struct device *device) +{ + int ret; + + /* Need to pin this module until return */ + __module_get(THIS_MODULE); + ret = _request_firmware(firmware_p, name, device, NULL, 0, + FW_OPT_UEVENT | FW_OPT_NOCACHE); + module_put(THIS_MODULE); + return ret; +} +EXPORT_SYMBOL(request_firmware_no_cache); +#endif /* VENDOR_EDIT */ + /** * firmware_request_nowarn() - request for an optional fw module * @firmware: pointer to firmware image diff --git a/drivers/base/kernelFwUpdate b/drivers/base/kernelFwUpdate new file mode 120000 index 000000000000..e1d84774ab42 --- /dev/null +++ b/drivers/base/kernelFwUpdate @@ -0,0 +1 @@ +../../../../vendor/oplus/kernel/touchpanel/kernelFwUpdate/ \ No newline at end of file diff --git a/drivers/base/memory.c b/drivers/base/memory.c index 25090f9284f7..d0d6b212dd97 100644 --- a/drivers/base/memory.c +++ b/drivers/base/memory.c @@ -25,7 +25,9 @@ #include #include - +#if defined(OPLUS_FEATURE_MULTI_FREEAREA) && defined(CONFIG_PHYSICAL_ANTI_FRAGMENTATION) +#include +#endif static DEFINE_MUTEX(mem_sysfs_mutex); #define MEMORY_CLASS_NAME "memory" @@ -447,12 +449,32 @@ static DEVICE_ATTR(valid_zones, 0444, show_valid_zones, NULL); #ifdef CONFIG_MEMORY_HOTPLUG static int count_num_free_block_pages(struct zone *zone, int bid) { +#if defined(OPLUS_FEATURE_MULTI_FREEAREA) && defined(CONFIG_PHYSICAL_ANTI_FRAGMENTATION) + int order, type, flc; +#else int order, type; +#endif unsigned long freecount = 0; unsigned long flags; spin_lock_irqsave(&zone->lock, flags); for (type = 0; type < MIGRATE_TYPES; type++) { +#if defined(OPLUS_FEATURE_MULTI_FREEAREA) && defined(CONFIG_PHYSICAL_ANTI_FRAGMENTATION) + for (flc = 0; flc < FREE_AREA_COUNTS; flc++) { + struct free_area *area; + struct page *page; + for (order = 0; order < MAX_ORDER; ++order) { + area = &(zone->free_area[flc][order]); + list_for_each_entry(page, &area->free_list[type], lru) { + unsigned long pfn = page_to_pfn(page); + int section_nr = pfn_to_section_nr(pfn); + + if (bid == base_memory_block_id(section_nr)) + freecount += (1 << order); + } + } + } +#else for (order = 0; order < MAX_ORDER; ++order) { struct free_area *area; struct page *page; @@ -467,6 +489,7 @@ static int count_num_free_block_pages(struct zone *zone, int bid) } } +#endif } spin_unlock_irqrestore(&zone->lock, flags); diff --git a/drivers/base/power/wakeup.c b/drivers/base/power/wakeup.c index f72608d1be4b..9af5d826c66c 100644 --- a/drivers/base/power/wakeup.c +++ b/drivers/base/power/wakeup.c @@ -19,12 +19,22 @@ #include #include #include +#ifdef OPLUS_FEATURE_LOGKIT +#include +#include +#endif /* OPLUS_FEATURE_LOGKIT */ #include #include #include +#ifdef OPLUS_FEATURE_POWERINFO_STANDBY +#include +#endif /* OPLUS_FEATURE_POWERINFO_STANDBY */ + #include "power.h" +#include + #ifndef CONFIG_SUSPEND suspend_state_t pm_suspend_target_state; #define pm_suspend_target_state (PM_SUSPEND_ON) @@ -545,6 +555,10 @@ static void wakeup_source_activate(struct wakeup_source *ws) "unregistered wakeup source\n")) return; + #ifdef OPLUS_FEATURE_POWERINFO_STANDBY + wakeup_get_start_time(); + #endif /* OPLUS_FEATURE_POWERINFO_STANDBY */ + ws->active = true; ws->active_count++; ws->last_time = ktime_get(); @@ -686,8 +700,12 @@ static void wakeup_source_deactivate(struct wakeup_source *ws) trace_wakeup_source_deactivate(ws->name, cec); split_counters(&cnt, &inpr); - if (!inpr && waitqueue_active(&wakeup_count_wait_queue)) + if (!inpr && waitqueue_active(&wakeup_count_wait_queue)) { + #ifdef OPLUS_FEATURE_POWERINFO_STANDBY + wakeup_get_end_hold_time(); + #endif /* OPLUS_FEATURE_POWERINFO_STANDBY */ wake_up(&wakeup_count_wait_queue); + } } /** @@ -861,7 +879,11 @@ void pm_print_active_wakeup_sources(void) srcuidx = srcu_read_lock(&wakeup_srcu); list_for_each_entry_rcu(ws, &wakeup_sources, entry) { if (ws->active) { + #ifdef OPLUS_FEATURE_POWERINFO_STANDBY + pr_info("active wakeup source: %s\n", ws->name); + #else pr_debug("active wakeup source: %s\n", ws->name); + #endif /* OPLUS_FEATURE_POWERINFO_STANDBY */ active = 1; } else if (!active && (!last_activity_ws || @@ -871,13 +893,46 @@ void pm_print_active_wakeup_sources(void) } } - if (!active && last_activity_ws) + if (!active && last_activity_ws) { + #ifdef OPLUS_FEATURE_POWERINFO_STANDBY + pr_info("last active wakeup source: %s\n", + last_activity_ws->name); + #else pr_debug("last active wakeup source: %s\n", last_activity_ws->name); + #endif /* OPLUS_FEATURE_POWERINFO_STANDBY */ + } srcu_read_unlock(&wakeup_srcu, srcuidx); } EXPORT_SYMBOL_GPL(pm_print_active_wakeup_sources); +#ifdef OPLUS_FEATURE_POWERINFO_STANDBY +void get_ws_listhead(struct list_head **ws) +{ + if (ws) + *ws = &wakeup_sources; +} + +void wakeup_srcu_read_lock(int *srcuidx) +{ + *srcuidx = srcu_read_lock(&wakeup_srcu); +} + +void wakeup_srcu_read_unlock(int srcuidx) +{ + srcu_read_unlock(&wakeup_srcu, srcuidx); +} + +bool ws_all_release(void) +{ + unsigned int cnt, inpr; + + pr_info("Enter: %s\n", __func__); + split_counters(&cnt, &inpr); + return (!inpr) ? true : false; +} +#endif /* OPLUS_FEATURE_POWERINFO_STANDBY */ + /** * pm_wakeup_pending - Check if power transition in progress should be aborted. * @@ -903,6 +958,12 @@ bool pm_wakeup_pending(void) raw_spin_unlock_irqrestore(&events_lock, flags); if (ret) { + #ifndef OPLUS_FEATURE_POWERINFO_STANDBY + pr_debug("PM: Wakeup pending, aborting suspend\n"); + #else + pr_info("PM: Wakeup pending, aborting suspend\n"); + wakeup_reasons_statics(IRQ_NAME_ABORT, WS_CNT_ABORT); + #endif /* OPLUS_FEATURE_POWERINFO_STANDBY */ pm_get_active_wakeup_sources(suspend_abort, MAX_SUSPEND_ABORT_LEN); log_suspend_abort_reason(suspend_abort); @@ -946,6 +1007,11 @@ void pm_system_irq_wakeup(unsigned int irq_number) log_irq_wakeup_reason(irq_number); pr_warn("%s: %d triggered %s\n", __func__, irq_number, name); + #ifdef OPLUS_FEATURE_POWERINFO_STANDBY + pr_info("%s: resume caused by irq=%d, name=%s\n", __func__, irq_number, name); + wakeup_reasons_statics(name, WS_CNT_POWERKEY|WS_CNT_RTCALARM); + #endif /* OPLUS_FEATURE_POWERINFO_STANDBY */ + pm_wakeup_irq = irq_number; pm_system_wakeup(); } @@ -1169,12 +1235,22 @@ static const struct file_operations wakeup_sources_stats_fops = { .read = seq_read, .llseek = seq_lseek, .release = seq_release_private, +#ifdef OPLUS_FEATURE_LOGKIT + .write = watchdog_write, +#endif /* OPLUS_FEATURE_LOGKIT */ }; static int __init wakeup_sources_debugfs_init(void) { + #ifndef OPLUS_FEATURE_LOGKIT wakeup_sources_stats_dentry = debugfs_create_file("wakeup_sources", S_IRUGO, NULL, NULL, &wakeup_sources_stats_fops); + #else /* OPLUS_FEATURE_LOGKIT */ + wakeup_sources_stats_dentry = debugfs_create_file("wakeup_sources", + S_IRUGO| S_IWUGO, NULL, NULL, &wakeup_sources_stats_fops); + #endif /* OPLUS_FEATURE_LOGKIT */ + + proc_create_data("wakeup_sources", 0444, NULL, &wakeup_sources_stats_fops, NULL); return 0; } diff --git a/drivers/block/zram/Kconfig b/drivers/block/zram/Kconfig index c8aab3115733..3c69e370cf7c 100644 --- a/drivers/block/zram/Kconfig +++ b/drivers/block/zram/Kconfig @@ -53,3 +53,55 @@ config ZRAM_MEMORY_TRACKING /sys/kernel/debug/zram/zramX/block_state. See Documentation/blockdev/zram.txt for more information. + +#ifdef OPLUS_FEATURE_ZRAM_OPT +config OPLUS_ZRAM_OPT + bool "oplus zram optimization" + depends on ZRAM + default y + help + oplus zram optimization +#endif /*OPLUS_FEATURE_ZRAM_OPT*/ + +#ifdef OPLUS_FEATURE_ZRAM_WRITEBACK +source "drivers/block/zram/zwb_handle/Kconfig" +#endif /* OPLUS_FEATURE_ZRAM_WRITEBACK */ + +config HYBRIDSWAP + bool "Enable Hybridswap" + depends on MEMCG && ZRAM && !ZRAM_DEDUP && !ZRAM_WRITEBACK && !ZWB_HANDLE + default n + help + Hybridswap is a intelligent memory management solution. + +config HYBRIDSWAP_SWAPD + bool "Enable hybridswap swapd thread to reclaim anon pages in background" + default n + depends on HYBRIDSWAP + help + swapd is a kernel thread that reclaim anonymous pages in the + background. When the use of swap pages reaches the watermark + and the refault of anonymous pages is high, the content of + zram will exchanged to eswap by a certain percentage. + +# Selected when system need hybridswap container +config HYBRIDSWAP_CORE + bool "Hybridswap container device support" + depends on ZRAM && HYBRIDSWAP + default n + help + Say Y here if you want to use the hybridswap + as the backend device in ZRAM. + If unsure, say N here. + This module can't be compiled as a module, + the module is as one part of the ZRAM driver. + +config HYBRIDSWAP_ASYNC_COMPRESS + bool "hypbridswap support asynchronous compress anon pages" + depends on ZRAM && HYBRIDSWAP + default n + help + Say Y here if you want to create asynchronous thread + for compress anon pages. + If unsure, say N here. + This feature will reduce the kswapd cpu load. diff --git a/drivers/block/zram/Makefile b/drivers/block/zram/Makefile index d7204ef6ee53..f08cdabb26ac 100644 --- a/drivers/block/zram/Makefile +++ b/drivers/block/zram/Makefile @@ -1,4 +1,14 @@ -zram-y := zcomp.o zram_drv.o +# SPDX-License-Identifier: GPL-2.0-only +zram-y := zcomp.o zram_drv.o zram-$(CONFIG_ZRAM_DEDUP) += zram_dedup.o obj-$(CONFIG_ZRAM) += zram.o + +#ifdef OPLUS_FEATURE_ZRAM_WRITEBACK +obj-$(CONFIG_ZWB_HANDLE) += zwb_handle/ +#endif /* OPLUS_FEATURE_ZRAM_WRITEBACK */ + +zram-$(CONFIG_HYBRIDSWAP) += hybridswap/hybridswap_main.o +zram-$(CONFIG_HYBRIDSWAP_SWAPD) += hybridswap/hybridswap_swapd.o +zram-$(CONFIG_HYBRIDSWAP_ASYNC_COMPRESS) += hybridswap/hybridswap_akcompress.o +zram-$(CONFIG_HYBRIDSWAP_CORE) += hybridswap/hybridswap_eswap.o diff --git a/drivers/block/zram/hybridswap/hybridswap.h b/drivers/block/zram/hybridswap/hybridswap.h new file mode 100644 index 000000000000..13b3bea215fd --- /dev/null +++ b/drivers/block/zram/hybridswap/hybridswap.h @@ -0,0 +1,98 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2020-2022 Oplus. All rights reserved. + */ + +#ifndef HYBRIDSWAP_H +#define HYBRIDSWAP_H +extern int __init hybridswap_pre_init(void); +extern ssize_t hybridswap_vmstat_show(struct device *dev, + struct device_attribute *attr, char *buf); +extern ssize_t hybridswap_loglevel_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t len); +extern ssize_t hybridswap_loglevel_show(struct device *dev, + struct device_attribute *attr, char *buf); +extern ssize_t hybridswap_enable_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t len); +extern ssize_t hybridswap_enable_show(struct device *dev, + struct device_attribute *attr, char *buf); +#ifdef CONFIG_HYBRIDSWAP_CORE +extern void hybridswap_record(struct zram *zram, u32 index, struct mem_cgroup *memcg); +extern void hybridswap_untrack(struct zram *zram, u32 index); +extern int hybridswap_page_fault(struct zram *zram, u32 index); +extern bool hybridswap_delete(struct zram *zram, u32 index); + +extern ssize_t hybridswap_report_show(struct device *dev, + struct device_attribute *attr, char *buf); +extern ssize_t hybridswap_stat_snap_show(struct device *dev, + struct device_attribute *attr, char *buf); +extern ssize_t hybridswap_meminfo_show(struct device *dev, + struct device_attribute *attr, char *buf); +extern ssize_t hybridswap_core_enable_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t len); +extern ssize_t hybridswap_core_enable_show(struct device *dev, + struct device_attribute *attr, char *buf); +extern ssize_t hybridswap_loop_device_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t len); +extern ssize_t hybridswap_loop_device_show(struct device *dev, + struct device_attribute *attr, char *buf); +extern ssize_t hybridswap_dev_life_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t len); +extern ssize_t hybridswap_dev_life_show(struct device *dev, + struct device_attribute *attr, char *buf); +extern ssize_t hybridswap_quota_day_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t len); +extern ssize_t hybridswap_quota_day_show(struct device *dev, + struct device_attribute *attr, char *buf); +extern ssize_t hybridswap_zram_increase_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t len); +extern ssize_t hybridswap_zram_increase_show(struct device *dev, + struct device_attribute *attr, char *buf); +#endif + +#ifdef CONFIG_HYBRIDSWAP_ASYNC_COMPRESS +/* 63---48,47--32,31-0 : cgroup id, thread_index, index*/ +#define ZRAM_INDEX_SHIFT 32 +#define CACHE_INDEX_SHIFT 32 +#define CACHE_INDEX_MASK ((1llu << CACHE_INDEX_SHIFT) - 1) +#define ZRAM_INDEX_MASK ((1llu << ZRAM_INDEX_SHIFT) - 1) + +#define cache_index_val(index) (((unsigned long)index & CACHE_INDEX_MASK) << ZRAM_INDEX_SHIFT) +#define zram_index_val(id) ((unsigned long)id & ZRAM_INDEX_MASK) +#define mk_page_val(cache_index, index) (cache_index_val(cache_index) | zram_index_val(index)) + +#define fetch_cache_id(page) ((page->private >> 32) & CACHE_INDEX_MASK) +#define fetch_zram_index(page) (page->private & ZRAM_INDEX_MASK) + +#define zram_set_page(zram, index, page) (zram->table[index].page = page) +#define zram_fetch_page(zram, index) (zram->table[index].page) + +extern void del_page_from_cache(struct page *page); +extern int add_anon_page2cache(struct zram * zram, u32 index, + struct page *page); +extern ssize_t hybridswap_akcompress_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t len); +extern ssize_t hybridswap_akcompress_show(struct device *dev, + struct device_attribute *attr, char *buf); +extern void put_free_page(struct page *page); +extern void put_anon_pages(struct page *page); +extern int akcompress_cache_page_fault(struct zram *zram, + struct page *page, u32 index); +extern void destroy_akcompressd_task(struct zram *zram); +#endif + +#ifdef CONFIG_HYBRIDSWAP_SWAPD +extern ssize_t hybridswap_swapd_pause_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t len); +extern ssize_t hybridswap_swapd_pause_show(struct device *dev, + struct device_attribute *attr, char *buf); +#endif +static inline bool current_is_swapd(void) +{ +#ifdef CONFIG_HYBRIDSWAP_SWAPD + return (strncmp(current->comm, "hybridswapd:", sizeof("hybridswapd:") - 1) == 0); +#else + return false; +#endif +} +#endif /* HYBRIDSWAP_H */ diff --git a/drivers/block/zram/hybridswap/hybridswap_akcompress.c b/drivers/block/zram/hybridswap/hybridswap_akcompress.c new file mode 100644 index 000000000000..3548f042cf2e --- /dev/null +++ b/drivers/block/zram/hybridswap/hybridswap_akcompress.c @@ -0,0 +1,575 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2020-2022 Oplus. All rights reserved. + */ + +#define pr_fmt(fmt) "[HYBRIDSWAP]" fmt + +#include +#include +#include +#include +#include + +#include "../zram_drv.h" +#include "../zram_drv_internal.h" +#include "hybridswap_internal.h" +#include "hybridswap.h" + +struct compress_info_s { + struct list_head free_page_head; + spinlock_t free_lock; + unsigned int free_cnt; + + unsigned int max_cnt; +} compress_info; + +#define MAX_AKCOMPRESSD_THREADS 4 +#define DEFAULT_CACHE_SIZE_MB 64 +#define DEFAULT_COMPRESS_BATCH_MB 1 +#define DEFAULT_CACHE_COUNT ((DEFAULT_CACHE_SIZE_MB << 20) >> PAGE_SHIFT) +#define WAKEUP_AKCOMPRESSD_WATERMARK ((DEFAULT_COMPRESS_BATCH_MB << 20) >> PAGE_SHIFT) + +static wait_queue_head_t akcompressd_wait; +static struct task_struct *akc_task[MAX_AKCOMPRESSD_THREADS]; +static atomic64_t akc_cnt[MAX_AKCOMPRESSD_THREADS]; +static int akcompressd_threads = 0; +static atomic64_t cached_cnt; +static struct zram *zram_info; +static DEFINE_MUTEX(akcompress_init_lock); + +struct idr cached_idr = IDR_INIT(cached_idr); +DEFINE_SPINLOCK(cached_idr_lock); + +static void wake_all_akcompressd(void); + +void clear_page_memcg(struct cgroup_cache_page *cache) +{ + struct list_head *pos; + struct page *page; + + spin_lock(&cache->lock); + if (list_empty(&cache->head)) + goto out; + + list_for_each(pos, &cache->head) { + page = list_entry(pos, struct page, lru); + if (!page->mem_cgroup) + BUG(); + page->mem_cgroup = NULL; + } + +out: + cache->dead = 1; + spin_unlock(&cache->lock); +} + +static inline struct page * fetch_free_page(void) +{ + struct page *page = NULL; + + spin_lock(&compress_info.free_lock); + if (compress_info.free_cnt > 0) { + if (list_empty(&compress_info.free_page_head)) + BUG(); + page = lru_to_page(&compress_info.free_page_head); + list_del(&page->lru); + compress_info.free_cnt--; + } + spin_unlock(&compress_info.free_lock); + + return page; +} + +void put_free_page(struct page *page) +{ + set_page_private(page, 0); + spin_lock(&compress_info.free_lock); + list_add_tail(&page->lru, &compress_info.free_page_head); + compress_info.free_cnt++; + spin_unlock(&compress_info.free_lock); +} + +static inline struct cgroup_cache_page *find_and_fetch_memcg_cache(int cache_id) +{ + struct cgroup_cache_page *cache; + + spin_lock(&cached_idr_lock); + cache = (struct cgroup_cache_page *)idr_find(&cached_idr, cache_id); + if (unlikely(!cache)) { + spin_unlock(&cached_idr_lock); + pr_err("cache_id %d cache not find.\n", cache_id); + + return NULL; + } + fetch_memcg_cache(container_of(cache, memcg_hybs_t, cache)); + spin_unlock(&cached_idr_lock); + + return cache; +} + +void del_page_from_cache(struct page *page) +{ + int cache_id; + struct cgroup_cache_page *cache; + + if (!page) + return; + + cache_id = fetch_cache_id(page); + if (unlikely(cache_id < 0 || cache_id > MEM_CGROUP_ID_MAX)) { + hybp(HYB_ERR, "page %p cache_id %d index %u is invalid.\n", + page, cache_id, fetch_zram_index(page)); + return; + } + + cache = find_and_fetch_memcg_cache(cache_id); + if (!cache) + return; + + spin_lock(&cache->lock); + list_del(&page->lru); + cache->cnt--; + spin_unlock(&cache->lock); + put_memcg_cache(container_of(cache, memcg_hybs_t, cache)); + atomic64_dec(&cached_cnt); +} + +void del_page_from_cache_with_cache(struct page *page, + struct cgroup_cache_page *cache) +{ + spin_lock(&cache->lock); + list_del(&page->lru); + cache->cnt--; + spin_unlock(&cache->lock); + atomic64_dec(&cached_cnt); +} + +void put_anon_pages(struct page *page) +{ + memcg_hybs_t *hybs = MEMCGRP_ITEM_DATA(page->mem_cgroup); + + spin_lock(&hybs->cache.lock); + list_add(&page->lru, &hybs->cache.head); + hybs->cache.cnt++; + spin_unlock(&hybs->cache.lock); +} + +static inline bool can_stop_working(struct cgroup_cache_page *cache, int index) +{ + spin_lock(&cache->lock); + if (unlikely(!list_empty(&cache->head))) { + spin_unlock(&cache->lock); + return false; + } + spin_unlock(&cache->lock); + return 1; +} + +static int check_cache_state(struct cgroup_cache_page *cache) +{ + if (cache->cnt == 0 || cache->compressing == 1) + return 0; + + spin_lock(&cache->lock); + if (cache->cnt == 0 || cache->compressing) { + spin_unlock(&cache->lock); + return 0; + } + cache->compressing = 1; + spin_unlock(&cache->lock); + fetch_memcg_cache(container_of(cache, memcg_hybs_t, cache)); + return 1; +} + +struct cgroup_cache_page *fetch_one_cache(void) +{ + struct cgroup_cache_page *cache = NULL; + int id; + + spin_lock(&cached_idr_lock); + idr_for_each_entry(&cached_idr, cache, id) { + if (check_cache_state(cache)) + break; + } + spin_unlock(&cached_idr_lock); + + return cache; +} + +void mark_compressing_stop(struct cgroup_cache_page *cache) +{ + spin_lock(&cache->lock); + if (cache->dead) + hybp(HYB_WARN, "stop compressing, may be cgroup is delelted\n"); + cache->compressing = 0; + spin_unlock(&cache->lock); + put_memcg_cache(container_of(cache, memcg_hybs_t, cache)); +} + +static inline struct page *fetch_anon_page(struct zram *zram, + struct cgroup_cache_page *cache) +{ + struct page *page, *prev_page; + int index; + + if (compress_info.free_cnt == 0) + return NULL; + + prev_page = NULL; +try_again: + page = NULL; + + spin_lock(&cache->lock); + if (!list_empty(&cache->head)) { + page = lru_to_page(&cache->head); + index = fetch_zram_index(page); + } + spin_unlock(&cache->lock); + + if (page) { + if (prev_page && (page == prev_page)) { + hybp(HYB_ERR, "zram %p index %d page %p\n", + zram, index, page); + BUG(); + } + + zram_slot_lock(zram, index); + if (!zram_test_flag(zram, index, ZRAM_CACHED)) { + zram_slot_unlock(zram, index); + prev_page = page; + goto try_again; + } + + prev_page = NULL; + zram_clear_flag(zram, index, ZRAM_CACHED); + del_page_from_cache_with_cache(page, cache); + zram_set_flag(zram, index, ZRAM_CACHED_COMPRESS); + zram_slot_unlock(zram, index); + } + + return page; +} + +int add_anon_page2cache(struct zram * zram, u32 index, struct page *page) +{ + struct page *dst_page; + void *src, *dst; + struct mem_cgroup *memcg; + struct cgroup_cache_page *cache; + memcg_hybs_t *hybs; + + if (akcompressd_threads == 0) + return 0; + + memcg = page->mem_cgroup; + if (!memcg || !MEMCGRP_ITEM_DATA(memcg)) + return 0; + + hybs = MEMCGRP_ITEM_DATA(memcg); + cache = &hybs->cache; + if (find_and_fetch_memcg_cache(cache->id) != cache) + return 0; + + spin_lock(&cache->lock); + if (cache->dead == 1) { + spin_unlock(&cache->lock); + return 0; + } + spin_unlock(&cache->lock); + + dst_page = fetch_free_page(); + if (!dst_page) + return 0; + + src = kmap_atomic(page); + dst = kmap_atomic(dst_page); + memcpy(dst, src, PAGE_SIZE); + kunmap_atomic(src); + kunmap_atomic(dst); + + dst_page->mem_cgroup = memcg; + set_page_private(dst_page, mk_page_val(cache->id, index)); + update_zram_index(zram, index, (unsigned long)dst_page); + atomic64_inc(&cached_cnt); + wake_all_akcompressd(); + hybp(HYB_DEBUG, "add_anon_page2cache index %u page %p passed\n", + index, dst_page); + return 1; +} + +static inline void akcompressd_try_to_sleep(wait_queue_head_t *waitq) +{ + DEFINE_WAIT(wait); + + prepare_to_wait(waitq, &wait, TASK_INTERRUPTIBLE); + freezable_schedule(); + finish_wait(waitq, &wait); +} + +static int akcompressd_func(void *data) +{ + struct page *page; + int ret, thread_index; + struct list_head compress_fail_list; + struct cgroup_cache_page *cache = NULL; + + thread_index = (int)data; + if (thread_index < 0 || thread_index >= MAX_AKCOMPRESSD_THREADS) { + hybp(HYB_ERR, "akcompress task index %d is invalid.\n", thread_index); + return -EINVAL; + } + + set_freezable(); + while (!kthread_should_stop()) { + akcompressd_try_to_sleep(&akcompressd_wait); + count_swapd_event(AKCOMPRESSD_WAKEUP); + + cache = fetch_one_cache(); + if (!cache) + continue; + +finish_last_jobs: + INIT_LIST_HEAD(&compress_fail_list); + page = fetch_anon_page(zram_info, cache); + while (page) { + ret = async_compress_page(zram_info, page); + put_memcg_cache(container_of(cache, memcg_hybs_t, cache)); + + if (ret) + list_add(&page->lru, &compress_fail_list); + else { + atomic64_inc(&akc_cnt[thread_index]); + page->mem_cgroup = NULL; + put_free_page(page); + } + page = fetch_anon_page(zram_info, cache); + } + + if (!list_empty(&compress_fail_list)) + hybp(HYB_ERR, "have some compress failed pages.\n"); + + if (kthread_should_stop()) { + if (!can_stop_working(cache, thread_index)) + goto finish_last_jobs; + } + mark_compressing_stop(cache); + } + + return 0; +} + +static int update_akcompressd_threads(int thread_count, struct zram *zram) +{ + int drop, increase; + int last_index, start_index, hid; + static DEFINE_MUTEX(update_lock); + + if (thread_count < 0 || thread_count > MAX_AKCOMPRESSD_THREADS) { + hybp(HYB_ERR, "thread_count %d is invalid\n", thread_count); + return -EINVAL; + } + + mutex_lock(&update_lock); + if (!zram_info || zram_info != zram) + zram_info = zram; + + if (thread_count == akcompressd_threads) { + mutex_unlock(&update_lock); + return thread_count; + } + + last_index = akcompressd_threads - 1; + if (thread_count < akcompressd_threads) { + drop = akcompressd_threads - thread_count; + for (hid = last_index; hid > (last_index - drop); hid--) { + if (akc_task[hid]) { + kthread_stop(akc_task[hid]); + akc_task[hid] = NULL; + } + } + } else { + increase = thread_count - akcompressd_threads; + start_index = last_index + 1; + for (hid = start_index; hid < (start_index + increase); hid++) { + if (unlikely(akc_task[hid])) + BUG(); + akc_task[hid]= kthread_run(akcompressd_func, + (void*)(unsigned long)hid, "akcompressd:%d", hid); + if (IS_ERR(akc_task[hid])) { + pr_err("Failed to start akcompressd%d\n", hid); + akc_task[hid] = NULL; + break; + } + } + } + + hybp(HYB_INFO, "akcompressd_threads count changed, old:%d new:%d\n", + akcompressd_threads, thread_count); + akcompressd_threads = thread_count; + mutex_unlock(&update_lock); + + return thread_count; +} + +static void wake_all_akcompressd(void) +{ + if (atomic64_read(&cached_cnt) < WAKEUP_AKCOMPRESSD_WATERMARK) + return; + + if (!waitqueue_active(&akcompressd_wait)) + return; + + wake_up_interruptible(&akcompressd_wait); +} + +int create_akcompressd_task(struct zram *zram) +{ + return update_akcompressd_threads(1, zram) != 1; +} + +void destroy_akcompressd_task(struct zram *zram) +{ + (void)update_akcompressd_threads(0, zram); +} + +ssize_t hybridswap_akcompress_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t len) +{ + int ret; + unsigned long val; + struct zram *zram = dev_to_zram(dev); + + ret = kstrtoul(buf, 0, &val); + if (unlikely(ret)) { + hybp(HYB_ERR, "val is error!\n"); + return -EINVAL; + } + + ret = update_akcompressd_threads(val, zram); + if (ret < 0) { + hybp(HYB_ERR, "create task failed, val %d\n", val); + return ret; + } + + return len; +} + +ssize_t hybridswap_akcompress_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int len = 0, id, i; + struct cgroup_cache_page *cache = NULL; + unsigned long cnt = atomic64_read(&cached_cnt); + memcg_hybs_t *hybs; + + len += sprintf(buf + len, "akcompressd_threads: %d\n", akcompressd_threads); + len += sprintf(buf + len, "cached page cnt: %lu\n", cnt); + len += sprintf(buf + len, "free page cnt: %u\n", compress_info.free_cnt); + + for (i = 0; i < MAX_AKCOMPRESSD_THREADS; i++) + len += sprintf(buf + len, "%-d %-d\n", i, atomic64_read(&akc_cnt[i])); + + if (cnt == 0) + return len; + + spin_lock(&cached_idr_lock); + idr_for_each_entry(&cached_idr, cache, id) { + hybs = container_of(cache, memcg_hybs_t, cache); + if (cache->cnt == 0) + continue; + + len += scnprintf(buf + len, PAGE_SIZE - len, "%s %d\n", + hybs->name, cache->cnt); + + if (len >= PAGE_SIZE) + break; + } + spin_unlock(&cached_idr_lock); + + return len; +} + +void __init akcompressd_pre_init(void) +{ + int i; + struct page *page; + + mutex_lock(&akcompress_init_lock); + INIT_LIST_HEAD(&compress_info.free_page_head); + spin_lock_init(&compress_info.free_lock); + compress_info.free_cnt = 0; + + init_waitqueue_head(&akcompressd_wait); + + atomic64_set(&cached_cnt, 0); + for (i = 0; i < MAX_AKCOMPRESSD_THREADS; i++) + atomic64_set(&akc_cnt[i], 0); + + for (i = 0; i < DEFAULT_CACHE_COUNT; i ++) { + page = alloc_page(GFP_KERNEL); + + if (page) { + list_add_tail(&page->lru, &compress_info.free_page_head); + } else + break; + } + compress_info.free_cnt = i; + mutex_unlock(&akcompress_init_lock); +} + +void __exit akcompressd_pre_deinit(void) +{ + int i; + struct page *page, *tmp; + + mutex_lock(&akcompress_init_lock); + if (list_empty(&compress_info.free_page_head)) + goto out; + list_for_each_entry_safe(page, tmp, &compress_info.free_page_head , lru) { + list_del(&page->lru); + free_page(page); + } + +out: + compress_info.free_cnt = 0; + mutex_unlock(&akcompress_init_lock); +} + +int akcompress_cache_page_fault(struct zram *zram, + struct page *page, u32 index) +{ + void *src, *dst; + + if (zram_test_flag(zram, index, ZRAM_CACHED)) { + struct page *src_page = (struct page *)zram_fetch_page(zram, index); + + src = kmap_atomic(src_page); + dst = kmap_atomic(page); + memcpy(dst, src, PAGE_SIZE); + kunmap_atomic(src); + kunmap_atomic(dst); + zram_slot_unlock(zram, index); + + hybp(HYB_DEBUG, "read_anon_page_from_cache index %u page %p passed, ZRAM_CACHED\n", + index, src_page); + return 1; + } + + if (zram_test_flag(zram, index, ZRAM_CACHED_COMPRESS)) { + struct page *src_page = (struct page *)zram_fetch_page(zram, index); + + src = kmap_atomic(src_page); + dst = kmap_atomic(page); + memcpy(dst, src, PAGE_SIZE); + kunmap_atomic(src); + kunmap_atomic(dst); + zram_slot_unlock(zram, index); + + hybp(HYB_DEBUG, "read_anon_page_from_cache index %u page %p passed, ZRAM_CACHED_COMPRESS\n", + index, src_page); + return 1; + } + + return 0; +} diff --git a/drivers/block/zram/hybridswap/hybridswap_eswap.c b/drivers/block/zram/hybridswap/hybridswap_eswap.c new file mode 100644 index 000000000000..9073bf1b621c --- /dev/null +++ b/drivers/block/zram/hybridswap/hybridswap_eswap.c @@ -0,0 +1,5476 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2020-2022 Oplus. All rights reserved. + */ + +#define pr_fmt(fmt) "[HYBRIDSWAP]" fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_FG_TASK_UID +#include +#endif + +#include "../zram_drv.h" +#include "../zram_drv_internal.h" +#include "hybridswap_internal.h" +#include "hybridswap.h" + +#define PRE_EOL_INFO_OVER_VAL 2 +#define LIFE_TIME_EST_OVER_VAL 8 +#define DEFAULT_STORED_WM_RATIO 90 +#define DEVICE_NAME_LEN 64 +#define MIN_RECLAIM_ZRAM_SZ (1024 * 1024) +#define esentry_extid(e) ((e) >> ESWAP_SHIFT) +#define esentry_pgid(e) (((e) & ((1 << ESWAP_SHIFT) - 1)) >> PAGE_SHIFT) +#define esentry_pgoff(e) ((e) & (PAGE_SIZE - 1)) +#define DUMP_BUF_LEN 512 +#define HYBRIDSWAP_KEY_INDEX 0 +#define HYBRIDSWAP_KEY_SIZE 64 +#define HYBRIDSWAP_KEY_INDEX_SHIFT 3 +#define HYBRIDSWAP_MAX_INFILGHT_NUM 256 +#define HYBRIDSWAP_SECTOR_SHIFT 9 +#define HYBRIDSWAP_PAGE_SIZE_SECTOR (PAGE_SIZE >> HYBRIDSWAP_SECTOR_SHIFT) +#define HYBRIDSWAP_READ_TIME 10 +#define HYBRIDSWAP_WRITE_TIME 100 +#define HYB_FAULT_OUT_TIME 10 +#define CLASS_NAME_LEN 32 +#define MBYTE_SHIFT 20 +#define ENTRY_PTR_SHIFT 23 +#define ENTRY_MCG_SHIFT_HALF 8 +#define ENTRY_LOCK_BIT ENTRY_MCG_SHIFT_HALF +#define ENTRY_DATA_BIT (ENTRY_PTR_SHIFT + ENTRY_MCG_SHIFT_HALF + \ + ENTRY_MCG_SHIFT_HALF + 1) + +struct zs_eswap_para { + struct hybridswap_page_pool *pool; + size_t alloc_size; + bool fast; + bool nofail; +}; + +struct hybridswap_cfg { + atomic_t enable; + atomic_t out_to_eswap_enable; + struct hybstatus *stat; + struct workqueue_struct *reclaim_wq; + struct zram *zram; + + atomic_t dev_life; + unsigned long quota_day; + struct timer_list lpc_timer; + struct work_struct lpc_work; +}; + +struct async_req { + struct mem_cgroup *mcg; + unsigned long size; + unsigned long out_size; + unsigned long reclaimined_sz; + struct work_struct work; + int nice; + bool preload; +}; + +struct io_priv { + struct zram *zram; + enum hybridswap_class class; + struct hybridswap_page_pool page_pool; +}; + +struct io_work_arg { + void *iohandle; + struct hybridswap_entry *ioentry; + struct hybridswap_buffer io_buf; + struct io_priv data; + struct hybridswap_key_point_record record; +}; + +struct hyb_sgm_time { + ktime_t submit_bio; + ktime_t end_io; +}; + +struct hyb_sgm { + struct work_struct stopio_work; + struct hyb_sgm_time time; + struct hybridswap_io_req *req; + struct hybridswap_entry *io_entries_fifo[BIO_MAX_PAGES]; + struct list_head io_entries; + sector_t segment_sector; + int eswap_cnt; + u32 bio_result; + int page_cnt; +}; + +struct hyb_info { + unsigned long size; + int total_objects; + int nr_es; + int memcg_num; + + unsigned long *bitmask; + atomic_t last_alloc_bit; + + struct hyb_entries_table *eswap_table; + struct hyb_entries_head *eswap; + + struct hyb_entries_table *objects; + struct hyb_entries_head *maps; + struct hyb_entries_head *lru; + + atomic_t stored_exts; + atomic_t *eswap_stored_pages; + + unsigned int memcgid_cnt[MEM_CGROUP_ID_MAX + 1]; +}; + +struct hyb_entries_head { + unsigned int mcg_left : 8; + unsigned int lock : 1; + unsigned int prev : 23; + unsigned int mcg_right : 8; + unsigned int data : 1; + unsigned int next : 23; +}; + +struct hyb_entries_table { + struct hyb_entries_head *(*fetch_node)(int, void *); + void *private; +}; + +#define index_node(index, tab) ((tab)->fetch_node((index), (tab)->private)) +#define next_index(index, tab) (index_node((index), (tab))->next) +#define prev_index(index, tab) (index_node((index), (tab))->prev) +#define is_last_index(index, hindex, tab) (next_index(index, tab) == (hindex)) +#define is_first_index(index, hindex, tab) (prev_index(index, tab) == (hindex)) +#define hyb_entries_for_each_entry(index, hindex, tab) \ + for ((index) = next_index((hindex), (tab)); \ + (index) != (hindex); (index) = next_index((index), (tab))) +#define hyb_entries_for_each_entry_safe(index, tmp, hindex, tab) \ + for ((index) = next_index((hindex), (tab)), (tmp) = next_index((index), (tab)); \ + (index) != (hindex); (index) = (tmp), (tmp) = next_index((index), (tab))) +#define hyb_entries_for_each_entry_reverse(index, hindex, tab) \ + for ((index) = prev_index((hindex), (tab)); \ + (index) != (hindex); (index) = prev_index((index), (tab))) +#define hyb_entries_for_each_entry_reverse_safe(index, tmp, hindex, tab) \ + for ((index) = prev_index((hindex), (tab)), (tmp) = prev_index((index), (tab)); \ + (index) != (hindex); (index) = (tmp), (tmp) = prev_index((index), (tab))) + +static unsigned long warn_level[HYB_CLASS_BUTT] = { + 0, 200, 500, 0 +}; + +const char *key_point_name[HYB_KYE_POINT_BUTT] = { + "START", + "INIT", + "IOENTRY_ALLOC", + "FIND_ESWAP", + "IO_ESWAP", + "SEGMENT_ALLOC", + "BIO_ALLOC", + "SUBMIT_BIO", + "END_IO", + "SCHED_WORK", + "END_WORK", + "CALL_BACK", + "WAKE_UP", + "ZRAM_LOCK", + "DONE" +}; + +static const char class_name[HYB_CLASS_BUTT][CLASS_NAME_LEN] = { + "out_to_eswap", + "page_fault", + "batches", + "readahead" +}; + +static const char *fg_bg[2] = {"BG", "FG"}; + +bool hyb_io_work_begin_flag; +struct hybridswap_cfg global_settings; + +static u8 hybridswap_io_key[HYBRIDSWAP_KEY_SIZE]; +static struct workqueue_struct *hybridswap_proc_read_workqueue; +static struct workqueue_struct *hybridswap_proc_write_workqueue; +static char loop_device[DEVICE_NAME_LEN]; + +struct mem_cgroup *find_memcg_by_id(unsigned short memcgid); +int obj_index(struct hyb_info *infos, int index); +int eswap_index(struct hyb_info *infos, int index); +int memcgindex(struct hyb_info *infos, int index); +void free_hyb_info(struct hyb_info *infos); +struct hyb_info *alloc_hyb_info(unsigned long ori_size, unsigned long comp_size); +void hybridswap_check_infos_eswap(struct hyb_info *infos); +void hybridswap_free_eswap(struct hyb_info *infos, int eswapid); +int hybridswap_alloc_eswap(struct hyb_info *infos, struct mem_cgroup *mcg); +int fetch_eswap(struct hyb_info *infos, int eswapid); +void put_eswap(struct hyb_info *infos, int eswapid); +int fetch_memcg_eswap(struct hyb_info *infos, struct mem_cgroup *mcg); +int fetch_memcg_zram_entry(struct hyb_info *infos, struct mem_cgroup *mcg); +int fetch_eswap_zram_entry(struct hyb_info *infos, int eswapid); +struct hyb_entries_table *alloc_table(struct hyb_entries_head *(*fetch_node)(int, void *), + void *private, gfp_t gfp); +void hyb_lock_with_idx(int index, struct hyb_entries_table *table); +void hyb_unlock_with_idx(int index, struct hyb_entries_table *table); +void hyb_entries_init(int index, struct hyb_entries_table *table); +void hyb_entries_add_nolock(int index, int hindex, struct hyb_entries_table *table); +void hyb_entries_add_tail_nolock(int index, int hindex, struct hyb_entries_table *table); +void hyb_entries_del_nolock(int index, int hindex, struct hyb_entries_table *table); +void hyb_entries_add(int index, int hindex, struct hyb_entries_table *table); +void hyb_entries_add_tail(int index, int hindex, struct hyb_entries_table *table); +void hyb_entries_del(int index, int hindex, struct hyb_entries_table *table); +unsigned short hyb_entries_fetch_memcgid(int index, struct hyb_entries_table *table); +void hyb_entries_set_memcgid(int index, struct hyb_entries_table *table, int memcgid); +bool hyb_entries_set_priv(int index, struct hyb_entries_table *table); +bool hyb_entries_clear_priv(int index, struct hyb_entries_table *table); +bool hyb_entries_test_priv(int index, struct hyb_entries_table *table); +bool hyb_entries_empty(int hindex, struct hyb_entries_table *table); +void zram_set_mcg(struct zram *zram, u32 index, int memcgid); +struct mem_cgroup *zram_fetch_mcg(struct zram *zram, u32 index); +int zram_fetch_mcg_last_index(struct hyb_info *infos, + struct mem_cgroup *mcg, + int *index, int max_cnt); +int swap_maps_fetch_eswap_index(struct hyb_info *infos, + int eswapid, int *index); +void swap_sorted_list_add(struct zram *zram, u32 index, struct mem_cgroup *memcg); +void swap_sorted_list_add_tail(struct zram *zram, u32 index, struct mem_cgroup *mcg); +void swap_sorted_list_del(struct zram *zram, u32 index); +void swap_maps_insert(struct zram *zram, u32 index); +void swap_maps_destroy(struct zram *zram, u32 index); + +static void hybridswapiowrkshow(struct seq_file *m, struct hybstatus *stat) +{ + int i; + + for (i = 0; i < HYB_CLASS_BUTT; ++i) { + seq_printf(m, "hybridswap_%s_total_lat: %lld\n", + class_name[i], + atomic64_read(&stat->lat[i].total_lat)); + seq_printf(m, "hybridswap_%s_max_lat: %lld\n", + class_name[i], + atomic64_read(&stat->lat[i].max_lat)); + seq_printf(m, "hybridswap_%s_timeout_cnt: %lld\n", + class_name[i], + atomic64_read(&stat->lat[i].timeout_cnt)); + } + + for (i = 0; i < 2; i++) { + seq_printf(m, "page_fault_timeout_100ms_cnt(%s): %lld\n", + fg_bg[i], + atomic64_read(&stat->fault_stat[i].timeout_100ms_cnt)); + seq_printf(m, "page_fault_timeout_500ms_cnt(%s): %lld\n", + fg_bg[i], + atomic64_read(&stat->fault_stat[i].timeout_500ms_cnt)); + } +} + +static void hybstatuss_show(struct seq_file *m, + struct hybstatus *stat) +{ + seq_printf(m, "hybridswap_out_times: %lld\n", + atomic64_read(&stat->reclaimin_cnt)); + seq_printf(m, "hybridswap_out_comp_size: %lld MB\n", + atomic64_read(&stat->reclaimin_bytes) >> MBYTE_SHIFT); + if (PAGE_SHIFT < MBYTE_SHIFT) + seq_printf(m, "hybridswap_out_ori_size: %lld MB\n", + atomic64_read(&stat->reclaimin_pages) >> + (MBYTE_SHIFT - PAGE_SHIFT)); + seq_printf(m, "hybridswap_in_times: %lld\n", + atomic64_read(&stat->batchout_cnt)); + seq_printf(m, "hybridswap_in_comp_size: %lld MB\n", + atomic64_read(&stat->batchout_bytes) >> MBYTE_SHIFT); + if (PAGE_SHIFT < MBYTE_SHIFT) + seq_printf(m, "hybridswap_in_ori_size: %lld MB\n", + atomic64_read(&stat->batchout_pages) >> + (MBYTE_SHIFT - PAGE_SHIFT)); + seq_printf(m, "hybridswap_all_fault: %lld\n", + atomic64_read(&stat->fault_cnt)); + seq_printf(m, "hybridswap_fault: %lld\n", + atomic64_read(&stat->hybridswap_fault_cnt)); +} + +static void hyb_info_info_show(struct seq_file *m, + struct hybstatus *stat) +{ + seq_printf(m, "hybridswap_reout_ori_size: %lld MB\n", + atomic64_read(&stat->reout_pages) >> + (MBYTE_SHIFT - PAGE_SHIFT)); + seq_printf(m, "hybridswap_reout_comp_size: %lld MB\n", + atomic64_read(&stat->reout_bytes) >> MBYTE_SHIFT); + seq_printf(m, "hybridswap_store_comp_size: %lld MB\n", + atomic64_read(&stat->stored_size) >> MBYTE_SHIFT); + seq_printf(m, "hybridswap_store_ori_size: %lld MB\n", + atomic64_read(&stat->stored_pages) >> + (MBYTE_SHIFT - PAGE_SHIFT)); + seq_printf(m, "hybridswap_notify_free_size: %lld MB\n", + atomic64_read(&stat->notify_free) >> + (MBYTE_SHIFT - ESWAP_SHIFT)); + seq_printf(m, "hybridswap_store_memcg_cnt: %lld\n", + atomic64_read(&stat->mcg_cnt)); + seq_printf(m, "hybridswap_store_eswap_cnt: %lld\n", + atomic64_read(&stat->eswap_cnt)); + seq_printf(m, "hybridswap_store_frag_info_cnt: %lld\n", + atomic64_read(&stat->frag_cnt)); +} + +static void hybridswap_fail_show(struct seq_file *m, + struct hybstatus *stat) +{ + int i; + + for (i = 0; i < HYB_CLASS_BUTT; ++i) { + seq_printf(m, "hybridswap_%s_io_fail_cnt: %lld\n", + class_name[i], + atomic64_read(&stat->io_fail_cnt[i])); + seq_printf(m, "hybridswap_%s_alloc_fail_cnt: %lld\n", + class_name[i], + atomic64_read(&stat->alloc_fail_cnt[i])); + } +} + +int hybridswap_psi_show(struct seq_file *m, void *v) +{ + struct hybstatus *stat = NULL; + + if (!hybridswap_core_enabled()) + return -EINVAL; + + stat = hybridswap_fetch_stat_obj(); + if (unlikely(!stat)) { + hybp(HYB_ERR, "can't fetch stat obj!\n"); + return -EINVAL; + } + + hybstatuss_show(m, stat); + hyb_info_info_show(m, stat); + hybridswapiowrkshow(m, stat); + hybridswap_fail_show(m, stat); + + return 0; +} + +unsigned long long hybridswap_fetch_zram_pagefault(void) +{ + struct hybstatus *stat = NULL; + + if (!hybridswap_core_enabled()) + return 0; + + stat = hybridswap_fetch_stat_obj(); + if (unlikely(!stat)) { + hybp(HYB_ERR, "can't fetch stat obj!\n"); + + return 0; + } + + return atomic64_read(&stat->fault_cnt); +} + +bool hybridswap_reclaim_work_running(void) +{ + struct hybstatus *stat = NULL; + + if (!hybridswap_core_enabled()) + return false; + + stat = hybridswap_fetch_stat_obj(); + if (unlikely(!stat)) { + hybp(HYB_ERR, "can't fetch stat obj!\n"); + + return 0; + } + + return atomic64_read(&stat->reclaimin_infight) ? true : false; +} + +unsigned long long hybridswap_read_mcg_stats(struct mem_cgroup *mcg, + enum hybridswap_mcg_member mcg_member) +{ + struct mem_cgroup_hybridswap *mcg_hybs; + + unsigned long long val = 0; + int extcnt; + + if (!hybridswap_core_enabled()) + return 0; + + mcg_hybs = MEMCGRP_ITEM_DATA(mcg); + if (!mcg_hybs) { + hybp(HYB_DEBUG, "NULL mcg_hybs\n"); + return 0; + } + + switch (mcg_member) { + case MCG_ZRAM_STORED_SZ: + val = atomic64_read(&mcg_hybs->zram_stored_size); + break; + case MCG_ZRAM_STORED_PG_SZ: + val = atomic64_read(&mcg_hybs->zram_page_size); + break; + case MCG_DISK_STORED_SZ: + val = atomic64_read(&mcg_hybs->hybridswap_stored_size); + break; + case MCG_DISK_STORED_PG_SZ: + val = atomic64_read(&mcg_hybs->hybridswap_stored_pages); + break; + case MCG_ANON_FAULT_CNT: + val = atomic64_read(&mcg_hybs->hybridswap_allfaultcnt); + break; + case MCG_DISK_FAULT_CNT: + val = atomic64_read(&mcg_hybs->hybridswap_faultcnt); + break; + case MCG_ESWAPOUT_CNT: + val = atomic64_read(&mcg_hybs->hybridswap_outcnt); + break; + case MCG_ESWAPOUT_SZ: + val = atomic64_read(&mcg_hybs->hybridswap_outextcnt) << ESWAP_SHIFT; + break; + case MCG_ESWAPIN_CNT: + val = atomic64_read(&mcg_hybs->hybridswap_incnt); + break; + case MCG_ESWAPIN_SZ: + val = atomic64_read(&mcg_hybs->hybridswap_inextcnt) << ESWAP_SHIFT; + break; + case MCG_DISK_SPACE: + extcnt = atomic_read(&mcg_hybs->hybridswap_extcnt); + if (extcnt < 0) + extcnt = 0; + val = ((unsigned long long) extcnt) << ESWAP_SHIFT; + break; + case MCG_DISK_SPACE_PEAK: + extcnt = atomic_read(&mcg_hybs->hybridswap_peakextcnt); + if (extcnt < 0) + extcnt = 0; + val = ((unsigned long long) extcnt) << ESWAP_SHIFT; + break; + default: + break; + } + + return val; +} + +void hybridswap_fail_record(enum hybridswap_fail_point point, + u32 index, int eswapid, unsigned char *task_comm) +{ + struct hybstatus *stat = NULL; + unsigned long flags; + unsigned int copylen = strlen(task_comm) + 1; + + stat = hybridswap_fetch_stat_obj(); + if (unlikely(!stat)) { + hybp(HYB_ERR, "can't fetch stat obj!\n"); + return; + } + + if (copylen > TASK_COMM_LEN) { + hybp(HYB_ERR, "task_comm len %d is err\n", copylen); + return; + } + + spin_lock_irqsave(&stat->record.lock, flags); + if (stat->record.num < MAX_FAIL_RECORD_NUM) { + stat->record.record[stat->record.num].point = point; + stat->record.record[stat->record.num].index = index; + stat->record.record[stat->record.num].eswapid = eswapid; + stat->record.record[stat->record.num].time = ktime_get(); + memcpy(stat->record.record[stat->record.num].task_comm, + task_comm, copylen); + stat->record.num++; + } + spin_unlock_irqrestore(&stat->record.lock, flags); +} + +static void hybridswap_fail_record_fetch( + struct hybridswap_fail_record_info *record_info) +{ + struct hybstatus *stat = NULL; + unsigned long flags; + + if (!hybridswap_core_enabled()) + return; + + stat = hybridswap_fetch_stat_obj(); + if (unlikely(!stat)) { + hybp(HYB_ERR, "can't fetch stat obj!\n"); + return; + } + + spin_lock_irqsave(&stat->record.lock, flags); + memcpy(record_info, &stat->record, + sizeof(struct hybridswap_fail_record_info)); + stat->record.num = 0; + spin_unlock_irqrestore(&stat->record.lock, flags); +} + +static ssize_t hybridswap_fail_record_show(char *buf) +{ + int i; + ssize_t size = 0; + struct hybridswap_fail_record_info record_info = { 0 }; + + hybridswap_fail_record_fetch(&record_info); + + size += scnprintf(buf + size, PAGE_SIZE, + "hybridswap_fail_record_num: %d\n", record_info.num); + for (i = 0; i < record_info.num; ++i) + size += scnprintf(buf + size, PAGE_SIZE - size, + "point[%u]time[%lld]taskname[%s]index[%u]eswapid[%d]\n", + record_info.record[i].point, + ktime_us_delta(ktime_get(), + record_info.record[i].time), + record_info.record[i].task_comm, + record_info.record[i].index, + record_info.record[i].eswapid); + + return size; +} + +ssize_t hybridswap_report_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return hybridswap_fail_record_show(buf); +} + +static inline meminfo_show(struct hybstatus *stat, char *buf, ssize_t len) +{ + unsigned long eswap_total_pages = 0, eswap_compressed_pages = 0; + unsigned long eswap_used_pages = 0; + unsigned long zram_total_pags, zram_used_pages, zram_compressed; + ssize_t size = 0; + + if (!stat || !buf || !len) + return 0; + + (void)hybridswap_stored_info(&eswap_total_pages, &eswap_compressed_pages); + eswap_used_pages = atomic64_read(&stat->stored_pages); +#ifdef CONFIG_HYBRIDSWAP_SWAPD + zram_total_pags = fetch_nr_zram_total(); +#else + zram_total_pags = 0; +#endif + zram_compressed = atomic64_read(&stat->zram_stored_size); + zram_used_pages = atomic64_read(&stat->zram_stored_pages); + + size += scnprintf(buf + size, len - size, "%-32s %12llu KB\n", + "EST:", eswap_total_pages << (PAGE_SHIFT - 10)); + size += scnprintf(buf + size, len - size, "%-32s %12llu KB\n", + "ESU_C:", eswap_compressed_pages << (PAGE_SHIFT - 10)); + size += scnprintf(buf + size, len - size, "%-32s %12llu KB\n", + "ESU_O:", eswap_used_pages << (PAGE_SHIFT - 10)); + size += scnprintf(buf + size, len - size, "%-32s %12llu KB\n", + "ZST:", zram_total_pags << (PAGE_SHIFT - 10)); + size += scnprintf(buf + size, len - size, "%-32s %12llu KB\n", + "ZSU_C:", zram_compressed >> 10); + size += scnprintf(buf + size, len - size, "%-32s %12llu KB\n", + "ZSU_O:", zram_used_pages << (PAGE_SHIFT - 10)); + + return size; +} + +ssize_t hybridswap_stat_snap_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t size = 0; + struct hybstatus *stat = NULL; + + if (!hybridswap_core_enabled()) + return 0; + + stat = hybridswap_fetch_stat_obj(); + if (unlikely(!stat)) { + hybp(HYB_INFO, "can't fetch stat obj!\n"); + return 0; + } + + size += scnprintf(buf + size, PAGE_SIZE - size, "%-32s %12llu\n", + "reclaimin_cnt:", atomic64_read(&stat->reclaimin_cnt)); + size += scnprintf(buf + size, PAGE_SIZE - size, "%-32s %12llu KB\n", + "reclaimin_bytes:", atomic64_read(&stat->reclaimin_bytes) / SZ_1K); + size += scnprintf(buf + size, PAGE_SIZE - size, "%-32s %12llu KB\n", + "reclaimin_real_load:", atomic64_read(&stat->reclaimin_real_load) / SZ_1K); + size += scnprintf(buf + size, PAGE_SIZE - size, "%-32s %12llu KB\n", + "reclaimin_bytes_daily:", atomic64_read(&stat->reclaimin_bytes_daily) / SZ_1K); + size += scnprintf(buf + size, PAGE_SIZE - size, "%-32s %12llu KB\n", + "reclaimin_pages:", atomic64_read(&stat->reclaimin_pages) * PAGE_SIZE / SZ_1K); + size += scnprintf(buf + size, PAGE_SIZE - size, "%-32s %12llu\n", + "reclaimin_infight:", atomic64_read(&stat->reclaimin_infight)); + size += scnprintf(buf + size, PAGE_SIZE - size, "%-32s %12llu\n", + "batchout_cnt:", atomic64_read(&stat->batchout_cnt)); + size += scnprintf(buf + size, PAGE_SIZE - size, "%-32s %12llu KB\n", + "batchout_bytes:", atomic64_read(&stat->batchout_bytes) / SZ_1K); + size += scnprintf(buf + size, PAGE_SIZE - size, "%-32s %12llu KB\n", + "batchout_real_load:", atomic64_read(&stat->batchout_real_load) / SZ_1K); + size += scnprintf(buf + size, PAGE_SIZE - size, "%-32s %12llu KB\n", + "batchout_pages:", atomic64_read(&stat->batchout_pages) * PAGE_SIZE / SZ_1K); + size += scnprintf(buf + size, PAGE_SIZE - size, "%-32s %12llu\n", + "batchout_inflight:", atomic64_read(&stat->batchout_inflight)); + size += scnprintf(buf + size, PAGE_SIZE - size, "%-32s %12llu\n", + "fault_cnt:", atomic64_read(&stat->fault_cnt)); + size += scnprintf(buf + size, PAGE_SIZE - size, "%-32s %12llu\n", + "hybridswap_fault_cnt:", atomic64_read(&stat->hybridswap_fault_cnt)); + size += scnprintf(buf + size, PAGE_SIZE - size, "%-32s %12llu KB\n", + "reout_pages:", atomic64_read(&stat->reout_pages) * PAGE_SIZE / SZ_1K); + size += scnprintf(buf + size, PAGE_SIZE - size, "%-32s %12llu KB\n", + "reout_bytes:", atomic64_read(&stat->reout_bytes) / SZ_1K); + size += scnprintf(buf + size, PAGE_SIZE - size, "%-32s %12llu KB\n", + "zram_stored_pages:", atomic64_read(&stat->zram_stored_pages) * PAGE_SIZE / SZ_1K); + size += scnprintf(buf + size, PAGE_SIZE - size, "%-32s %12llu KB\n", + "zram_stored_size:", atomic64_read(&stat->zram_stored_size) / SZ_1K); + size += scnprintf(buf + size, PAGE_SIZE - size, "%-32s %12llu KB\n", + "stored_pages:", atomic64_read(&stat->stored_pages) * PAGE_SIZE / SZ_1K); + size += scnprintf(buf + size, PAGE_SIZE - size, "%-32s %12llu KB\n", + "stored_size:", atomic64_read(&stat->stored_size) / SZ_1K); + size += scnprintf(buf + size, PAGE_SIZE - size, "%-32s %12llu KB\n", + "reclain-batchout:", (atomic64_read(&stat->reclaimin_real_load) - + atomic64_read(&stat->batchout_real_load)) / SZ_1K); + size += scnprintf(buf + size, PAGE_SIZE - size, "%-32s %12lld KB\n", + "reclain-batchout-stored:", + (atomic64_read(&stat->reclaimin_real_load) - + atomic64_read(&stat->batchout_real_load) - + atomic64_read(&stat->stored_size)) / SZ_1K); + size += scnprintf(buf + size, PAGE_SIZE - size, "%-32s %12lld KB\n", + "dropped_eswap_size:", atomic64_read(&stat->dropped_eswap_size) / SZ_1K); + size += scnprintf(buf + size, PAGE_SIZE - size, "%-32s %12llu\n", + "notify_free:", atomic64_read(&stat->notify_free)); + size += scnprintf(buf + size, PAGE_SIZE - size, "%-32s %12llu\n", + "frag_cnt:", atomic64_read(&stat->frag_cnt)); + size += scnprintf(buf + size, PAGE_SIZE - size, "%-32s %12llu\n", + "mcg_cnt:", atomic64_read(&stat->mcg_cnt)); + size += scnprintf(buf + size, PAGE_SIZE - size, "%-32s %12llu\n", + "ext_cnt:", atomic64_read(&stat->eswap_cnt)); + size += scnprintf(buf + size, PAGE_SIZE - size, "%-32s %12llu\n", + "miss_free:", atomic64_read(&stat->miss_free)); + size += scnprintf(buf + size, PAGE_SIZE - size, "%-32s %12llu\n", + "memcgid_clear:", atomic64_read(&stat->memcgid_clear)); + size += scnprintf(buf + size, PAGE_SIZE - size, "%-32s %12llu\n", + "skip_track_cnt:", atomic64_read(&stat->skip_track_cnt)); + size += scnprintf(buf + size, PAGE_SIZE - size, "%-32s %12llu\n", + "null_memcg_skip_track_cnt:", + atomic64_read(&stat->null_memcg_skip_track_cnt)); + size += scnprintf(buf + size, PAGE_SIZE - size, "%-32s %12llu\n", + "used_swap_pages:", atomic64_read(&stat->used_swap_pages) * PAGE_SIZE / SZ_1K); + size += meminfo_show(stat, buf + size, PAGE_SIZE - size); + + return size; +} + +ssize_t hybridswap_meminfo_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct hybstatus *stat = NULL; + + if (!hybridswap_core_enabled()) + return 0; + + stat = hybridswap_fetch_stat_obj(); + if (unlikely(!stat)) { + hybp(HYB_INFO, "can't fetch stat obj!\n"); + return 0; + } + + return meminfo_show(stat, buf, PAGE_SIZE); +} + +static void hybridswap_iostatus_bytes(struct hybridswap_io_req *req) +{ + struct hybstatus *stat = hybridswap_fetch_stat_obj(); + + if (!stat || !req->page_cnt) + return; + + if (req->io_para.class == HYB_RECLAIM_IN) { + atomic64_add(req->page_cnt * PAGE_SIZE, &stat->reclaimin_bytes); + atomic64_add(req->page_cnt * PAGE_SIZE, &stat->reclaimin_bytes_daily); + atomic64_add(atomic64_read(&req->real_load), &stat->reclaimin_real_load); + atomic64_inc(&stat->reclaimin_cnt); + } else { + atomic64_add(req->page_cnt * PAGE_SIZE, &stat->batchout_bytes); + atomic64_inc(&stat->batchout_cnt); + } +} + +static void hybridswap_key_init(void) +{ + get_random_bytes(hybridswap_io_key, HYBRIDSWAP_KEY_SIZE); +} + +static void hybridswap_io_req_release(struct kref *ref) +{ + struct hybridswap_io_req *req = + container_of(ref, struct hybridswap_io_req, refcount); + + if (req->io_para.complete_notify && req->io_para.private) + req->io_para.complete_notify(req->io_para.private); + + kfree(req); +} + +static void hyb_sgm_free(struct hybridswap_io_req *req, + struct hyb_sgm *segment) +{ + int i; + + for (i = 0; i < segment->eswap_cnt; ++i) { + INIT_LIST_HEAD(&segment->io_entries_fifo[i]->list); + req->io_para.done_callback(segment->io_entries_fifo[i], -EIO, req); + } + kfree(segment); +} + +static void hybridswap_limit_doing(struct hybridswap_io_req *req) +{ + int ret; + + if (!req->limit_doing_flag) + return; + + if (atomic_read(&req->eswap_doing) >= HYBRIDSWAP_MAX_INFILGHT_NUM) { + do { + hybp(HYB_DEBUG, "wait doing start\n"); + ret = wait_event_timeout(req->io_wait, + atomic_read(&req->eswap_doing) < + HYBRIDSWAP_MAX_INFILGHT_NUM, + msecs_to_jiffies(100)); + } while (!ret); + } +} + +static void hybridswap_wait_io_finish(struct hybridswap_io_req *req) +{ + int ret; + unsigned int wait_time; + + if (!req->wait_io_finish_flag || !req->page_cnt) + return; + + if (req->io_para.class == HYB_FAULT_OUT) { + hybp(HYB_DEBUG, "fault out wait finish start\n"); + wait_for_completion_io_timeout(&req->io_end_flag, + MAX_SCHEDULE_TIMEOUT); + + return; + } + + wait_time = (req->io_para.class == HYB_RECLAIM_IN) ? + HYBRIDSWAP_WRITE_TIME : HYBRIDSWAP_READ_TIME; + + do { + hybp(HYB_DEBUG, "wait finish start\n"); + ret = wait_event_timeout(req->io_wait, + (!atomic_read(&req->eswap_doing)), + msecs_to_jiffies(wait_time)); + } while (!ret); +} + +static void hybridswap_doing_inc(struct hyb_sgm *segment) +{ + mutex_lock(&segment->req->refmutex); + kref_get(&segment->req->refcount); + mutex_unlock(&segment->req->refmutex); + atomic_add(segment->page_cnt, &segment->req->eswap_doing); +} + +static void hybridswap_doing_dec(struct hybridswap_io_req *req, + int num) +{ + if ((atomic_sub_return(num, &req->eswap_doing) < + HYBRIDSWAP_MAX_INFILGHT_NUM) && req->limit_doing_flag && + wq_has_sleeper(&req->io_wait)) + wake_up(&req->io_wait); +} + +static void hybridswap_io_end_wake_up(struct hybridswap_io_req *req) +{ + if (req->io_para.class == HYB_FAULT_OUT) { + complete(&req->io_end_flag); + return; + } + + if (wq_has_sleeper(&req->io_wait)) + wake_up(&req->io_wait); +} + +static void hybridswap_ioentry_proc(struct hyb_sgm *segment) +{ + int i; + struct hybridswap_io_req *req = segment->req; + struct hybridswap_key_point_record *record = req->io_para.record; + int page_num; + ktime_t callback_start; + unsigned long long callback_start_ravg_sum; + + for (i = 0; i < segment->eswap_cnt; ++i) { + INIT_LIST_HEAD(&segment->io_entries_fifo[i]->list); + page_num = segment->io_entries_fifo[i]->pages_sz; + hybp(HYB_DEBUG, "eswap_id[%d] %d page_num %d\n", + i, segment->io_entries_fifo[i]->eswapid, page_num); + callback_start = ktime_get(); + callback_start_ravg_sum = hybridswap_fetch_ravg_sum(); + if (req->io_para.done_callback) + req->io_para.done_callback(segment->io_entries_fifo[i], + 0, req); + hybperf_async_perf(record, HYB_CALL_BACK, + callback_start, callback_start_ravg_sum); + hybridswap_doing_dec(req, page_num); + } +} + +static void hybridswap_errio_record(enum hybridswap_fail_point point, + struct hybridswap_io_req *req, int eswapid) +{ + if (req->io_para.class == HYB_FAULT_OUT) + hybridswap_fail_record(point, 0, eswapid, + req->io_para.record->task_comm); +} + +static void hybridswap_iostatus_fail(enum hybridswap_class class) +{ + struct hybstatus *stat = hybridswap_fetch_stat_obj(); + + if (!stat || (class >= HYB_CLASS_BUTT)) + return; + + atomic64_inc(&stat->io_fail_cnt[class]); +} + +static void hybridswap_errio_proc(struct hybridswap_io_req *req, + struct hyb_sgm *segment) +{ + hybp(HYB_ERR, "segment sector 0x%llx, eswap_cnt %d\n", + segment->segment_sector, segment->eswap_cnt); + hybp(HYB_ERR, "class %u, bio_result %u\n", + req->io_para.class, segment->bio_result); + hybridswap_iostatus_fail(req->io_para.class); + hybridswap_errio_record(HYB_FAULT_OUT_IO_FAIL, req, + segment->io_entries_fifo[0]->eswapid); + hybridswap_doing_dec(req, segment->page_cnt); + hybridswap_io_end_wake_up(req); + hyb_sgm_free(req, segment); + kref_put_mutex(&req->refcount, hybridswap_io_req_release, + &req->refmutex); +} + +static void hybridswap_io_end_work(struct work_struct *work) +{ + struct hyb_sgm *segment = + container_of(work, struct hyb_sgm, stopio_work); + struct hybridswap_io_req *req = segment->req; + struct hybridswap_key_point_record *record = req->io_para.record; + int old_nice = task_nice(current); + ktime_t work_start; + unsigned long long work_start_ravg_sum; + + if (unlikely(segment->bio_result)) { + hybridswap_errio_proc(req, segment); + return; + } + + hybp(HYB_DEBUG, "segment sector 0x%llx, eswap_cnt %d passed\n", + segment->segment_sector, segment->eswap_cnt); + hybp(HYB_DEBUG, "class %u, bio_result %u passed\n", + req->io_para.class, segment->bio_result); + + set_user_nice(current, req->nice); + + hybperf_async_perf(record, HYB_SCHED_WORK, + segment->time.end_io, 0); + work_start = ktime_get(); + work_start_ravg_sum = hybridswap_fetch_ravg_sum(); + + hybridswap_ioentry_proc(segment); + + hybperf_async_perf(record, HYB_END_WORK, work_start, + work_start_ravg_sum); + + hybridswap_io_end_wake_up(req); + + kref_put_mutex(&req->refcount, hybridswap_io_req_release, + &req->refmutex); + kfree(segment); + + set_user_nice(current, old_nice); +} + +static void hybridswap_end_io(struct bio *bio) +{ + struct hyb_sgm *segment = bio->bi_private; + struct hybridswap_io_req *req = NULL; + struct workqueue_struct *workqueue = NULL; + struct hybridswap_key_point_record *record = NULL; + + if (unlikely(!segment || !(segment->req))) { + hybp(HYB_ERR, "segment or req null\n"); + bio_put(bio); + + return; + } + + req = segment->req; + record = req->io_para.record; + + hybperf_async_perf(record, HYB_END_IO, + segment->time.submit_bio, 0); + + workqueue = (req->io_para.class == HYB_RECLAIM_IN) ? + hybridswap_proc_write_workqueue : hybridswap_proc_read_workqueue; + segment->time.end_io = ktime_get(); + segment->bio_result = bio->bi_status; + + queue_work(workqueue, &segment->stopio_work); + bio_put(bio); +} + +static bool hybridswap_eswap_merge_back( + struct hyb_sgm *segment, + struct hybridswap_entry *ioentry) +{ + struct hybridswap_entry *tail_ioentry = + list_last_entry(&segment->io_entries, + struct hybridswap_entry, list); + + return ((tail_ioentry->addr + + tail_ioentry->pages_sz * HYBRIDSWAP_PAGE_SIZE_SECTOR) == + ioentry->addr); +} + +static bool hybridswap_eswap_merge_front( + struct hyb_sgm *segment, + struct hybridswap_entry *ioentry) +{ + struct hybridswap_entry *head_ioentry = + list_first_entry(&segment->io_entries, + struct hybridswap_entry, list); + + return (head_ioentry->addr == + (ioentry->addr + + ioentry->pages_sz * HYBRIDSWAP_PAGE_SIZE_SECTOR)); +} + +static bool hybridswap_eswap_merge(struct hybridswap_io_req *req, + struct hybridswap_entry *ioentry) +{ + struct hyb_sgm *segment = req->segment; + + if (segment == NULL) + return false; + + if ((segment->page_cnt + ioentry->pages_sz) > BIO_MAX_PAGES) + return false; + + if (hybridswap_eswap_merge_front(segment, ioentry)) { + list_add(&ioentry->list, &segment->io_entries); + segment->io_entries_fifo[segment->eswap_cnt++] = ioentry; + segment->segment_sector = ioentry->addr; + segment->page_cnt += ioentry->pages_sz; + return true; + } + + if (hybridswap_eswap_merge_back(segment, ioentry)) { + list_add_tail(&ioentry->list, &segment->io_entries); + segment->io_entries_fifo[segment->eswap_cnt++] = ioentry; + segment->page_cnt += ioentry->pages_sz; + return true; + } + + return false; +} + +static struct bio *hybridswap_bio_alloc(enum hybridswap_class class) +{ + gfp_t gfp = (class != HYB_RECLAIM_IN) ? GFP_ATOMIC : GFP_NOIO; + struct bio *bio = bio_alloc(gfp, BIO_MAX_PAGES); + + if (!bio && (class == HYB_FAULT_OUT)) + bio = bio_alloc(GFP_NOIO, BIO_MAX_PAGES); + + return bio; +} + +static int hybridswap_bio_add_page(struct bio *bio, + struct hyb_sgm *segment) +{ + int i; + int k = 0; + struct hybridswap_entry *ioentry = NULL; + struct hybridswap_entry *tmp = NULL; + + list_for_each_entry_safe(ioentry, tmp, &segment->io_entries, list) { + for (i = 0; i < ioentry->pages_sz; i++) { + ioentry->dest_pages[i]->index = + bio->bi_iter.bi_sector + k; + if (unlikely(!bio_add_page(bio, + ioentry->dest_pages[i], PAGE_SIZE, 0))) { + return -EIO; + } + k += HYBRIDSWAP_PAGE_SIZE_SECTOR; + } + } + + return 0; +} + +static void hybridswap_set_bio_opf(struct bio *bio, + struct hyb_sgm *segment) +{ + if (segment->req->io_para.class == HYB_RECLAIM_IN) { + bio->bi_opf |= REQ_BACKGROUND; + return; + } + + bio->bi_opf |= REQ_SYNC; +} + +int hybridswap_submit_bio(struct hyb_sgm *segment) +{ + unsigned int op = + (segment->req->io_para.class == HYB_RECLAIM_IN) ? + REQ_OP_WRITE : REQ_OP_READ; + struct hybridswap_entry *head_ioentry = + list_first_entry(&segment->io_entries, + struct hybridswap_entry, list); + struct hybridswap_key_point_record *record = + segment->req->io_para.record; + struct bio *bio = NULL; + + hybperfiowrkstart(record, HYB_BIO_ALLOC); + bio = hybridswap_bio_alloc(segment->req->io_para.class); + hybperfiowrkend(record, HYB_BIO_ALLOC); + if (unlikely(!bio)) { + hybp(HYB_ERR, "bio is null.\n"); + hybridswap_errio_record(HYB_FAULT_OUT_BIO_ALLOC_FAIL, + segment->req, segment->io_entries_fifo[0]->eswapid); + + return -ENOMEM; + } + + bio->bi_iter.bi_sector = segment->segment_sector; + bio_set_dev(bio, segment->req->io_para.bdev); + bio->bi_private = segment; + bio_set_op_attrs(bio, op, 0); + bio->bi_end_io = hybridswap_end_io; + hybridswap_set_bio_opf(bio, segment); + + if (unlikely(hybridswap_bio_add_page(bio, segment))) { + bio_put(bio); + hybp(HYB_ERR, "bio_add_page fail\n"); + hybridswap_errio_record(HYB_FAULT_OUT_BIO_ADD_FAIL, + segment->req, segment->io_entries_fifo[0]->eswapid); + + return -EIO; + } + + hybridswap_doing_inc(segment); + hybp(HYB_DEBUG, "submit bio sector %llu eswapid %d\n", + segment->segment_sector, head_ioentry->eswapid); + hybp(HYB_DEBUG, "eswap_cnt %d class %u\n", + segment->eswap_cnt, segment->req->io_para.class); + + segment->req->page_cnt += segment->page_cnt; + segment->req->segment_cnt++; + segment->time.submit_bio = ktime_get(); + + hybperfiowrkstart(record, HYB_SUBMIT_BIO); + submit_bio(bio); + hybperfiowrkend(record, HYB_SUBMIT_BIO); + + return 0; +} + +static int hybridswap_new_segment_init(struct hybridswap_io_req *req, + struct hybridswap_entry *ioentry) +{ + gfp_t gfp = (req->io_para.class != HYB_RECLAIM_IN) ? + GFP_ATOMIC : GFP_NOIO; + struct hyb_sgm *segment = NULL; + struct hybridswap_key_point_record *record = req->io_para.record; + + hybperfiowrkstart(record, HYB_SEGMENT_ALLOC); + segment = kzalloc(sizeof(struct hyb_sgm), gfp); + if (!segment && (req->io_para.class == HYB_FAULT_OUT)) + segment = kzalloc(sizeof(struct hyb_sgm), GFP_NOIO); + hybperfiowrkend(record, HYB_SEGMENT_ALLOC); + if (unlikely(!segment)) { + hybridswap_errio_record(HYB_FAULT_OUT_SEGMENT_ALLOC_FAIL, + req, ioentry->eswapid); + + return -ENOMEM; + } + + segment->req = req; + INIT_LIST_HEAD(&segment->io_entries); + list_add_tail(&ioentry->list, &segment->io_entries); + segment->io_entries_fifo[segment->eswap_cnt++] = ioentry; + segment->page_cnt = ioentry->pages_sz; + INIT_WORK(&segment->stopio_work, hybridswap_io_end_work); + segment->segment_sector = ioentry->addr; + req->segment = segment; + + return 0; +} + +static int hybridswap_io_submit(struct hybridswap_io_req *req, + bool merge_flag) +{ + int ret; + struct hyb_sgm *segment = req->segment; + + if (!segment || ((merge_flag) && (segment->page_cnt < BIO_MAX_PAGES))) + return 0; + + hybridswap_limit_doing(req); + + ret = hybridswap_submit_bio(segment); + if (unlikely(ret)) { + hybp(HYB_WARN, "submit bio failed, ret %d\n", ret); + hyb_sgm_free(req, segment); + } + req->segment = NULL; + + return ret; +} + +static bool hybridswap_check_io_para_err(struct hybridswap_io *io_para) +{ + if (unlikely(!io_para)) { + hybp(HYB_ERR, "io_para null\n"); + + return true; + } + + if (unlikely(!io_para->bdev || + (io_para->class >= HYB_CLASS_BUTT))) { + hybp(HYB_ERR, "io_para err, class %u\n", + io_para->class); + + return true; + } + + if (unlikely(!io_para->done_callback)) { + hybp(HYB_ERR, "done_callback err\n"); + + return true; + } + + return false; +} + +static bool hybridswap_check_entry_err( + struct hybridswap_entry *ioentry) +{ + int i; + + if (unlikely(!ioentry)) { + hybp(HYB_ERR, "ioentry null\n"); + + return true; + } + + if (unlikely((!ioentry->dest_pages) || + (ioentry->eswapid < 0) || + (ioentry->pages_sz > BIO_MAX_PAGES) || + (ioentry->pages_sz <= 0))) { + hybp(HYB_ERR, "eswapid %d, page_sz %d\n", ioentry->eswapid, + ioentry->pages_sz); + + return true; + } + + for (i = 0; i < ioentry->pages_sz; ++i) { + if (!ioentry->dest_pages[i]) { + hybp(HYB_ERR, "dest_pages[%d] is null\n", i); + return true; + } + } + + return false; +} + +static int hybridswap_io_eswapent(void *iohandle, + struct hybridswap_entry *ioentry) +{ + int ret; + struct hybridswap_io_req *req = (struct hybridswap_io_req *)iohandle; + + if (unlikely(hybridswap_check_entry_err(ioentry))) { + hybridswap_errio_record(HYB_FAULT_OUT_IO_ENTRY_PARA_FAIL, + req, ioentry ? ioentry->eswapid : -EINVAL); + req->io_para.done_callback(ioentry, -EIO, req); + + return -EFAULT; + } + + hybp(HYB_DEBUG, "eswap id %d, pages_sz %d, addr %llx\n", + ioentry->eswapid, ioentry->pages_sz, + ioentry->addr); + + if (hybridswap_eswap_merge(req, ioentry)) + return hybridswap_io_submit(req, true); + + ret = hybridswap_io_submit(req, false); + if (unlikely(ret)) { + hybp(HYB_ERR, "submit fail %d\n", ret); + req->io_para.done_callback(ioentry, -EIO, req); + + return ret; + } + + ret = hybridswap_new_segment_init(req, ioentry); + if (unlikely(ret)) { + hybp(HYB_ERR, "hybridswap_new_segment_init fail %d\n", ret); + req->io_para.done_callback(ioentry, -EIO, req); + + return ret; + } + + return 0; +} + +int hyb_io_work_begin(void) +{ + if (hyb_io_work_begin_flag) + return 0; + + hybridswap_proc_read_workqueue = alloc_workqueue("proc_hybridswap_read", + WQ_HIGHPRI | WQ_UNBOUND, 0); + if (unlikely(!hybridswap_proc_read_workqueue)) + return -EFAULT; + + hybridswap_proc_write_workqueue = alloc_workqueue("proc_hybridswap_write", + WQ_CPU_INTENSIVE, 0); + if (unlikely(!hybridswap_proc_write_workqueue)) { + destroy_workqueue(hybridswap_proc_read_workqueue); + + return -EFAULT; + } + + hybridswap_key_init(); + + hyb_io_work_begin_flag = true; + + return 0; +} + +void *hybridswap_plug_start(struct hybridswap_io *io_para) +{ + gfp_t gfp; + struct hybridswap_io_req *req = NULL; + + if (unlikely(hybridswap_check_io_para_err(io_para))) + return NULL; + + gfp = (io_para->class != HYB_RECLAIM_IN) ? + GFP_ATOMIC : GFP_NOIO; + req = kzalloc(sizeof(struct hybridswap_io_req), gfp); + if (!req && (io_para->class == HYB_FAULT_OUT)) + req = kzalloc(sizeof(struct hybridswap_io_req), GFP_NOIO); + + if (unlikely(!req)) { + hybp(HYB_ERR, "io_req null\n"); + + return NULL; + } + + kref_init(&req->refcount); + mutex_init(&req->refmutex); + atomic_set(&req->eswap_doing, 0); + init_waitqueue_head(&req->io_wait); + req->io_para.bdev = io_para->bdev; + req->io_para.class = io_para->class; + req->io_para.done_callback = io_para->done_callback; + req->io_para.complete_notify = io_para->complete_notify; + req->io_para.private = io_para->private; + req->io_para.record = io_para->record; + req->limit_doing_flag = + (io_para->class == HYB_RECLAIM_IN) || + (io_para->class == HYB_PRE_OUT); + req->wait_io_finish_flag = + (io_para->class == HYB_RECLAIM_IN) || + (io_para->class == HYB_FAULT_OUT); + req->nice = task_nice(current); + init_completion(&req->io_end_flag); + + return (void *)req; +} + +int hybridswap_read_eswap(void *iohandle, + struct hybridswap_entry *ioentry) +{ + return hybridswap_io_eswapent(iohandle, ioentry); +} + +int hybridswap_write_eswap(void *iohandle, + struct hybridswap_entry *ioentry) +{ + return hybridswap_io_eswapent(iohandle, ioentry); +} + +int hybridswap_plug_finish(void *iohandle) +{ + int ret; + struct hybridswap_io_req *req = (struct hybridswap_io_req *)iohandle; + + hybperfiowrkstart(req->io_para.record, HYB_IO_ESWAP); + ret = hybridswap_io_submit(req, false); + if (unlikely(ret)) + hybp(HYB_ERR, "submit fail %d\n", ret); + + hybperfiowrkend(req->io_para.record, HYB_IO_ESWAP); + hybridswap_wait_io_finish(req); + hybperfiowrkpoint(req->io_para.record, HYB_WAKE_UP); + + hybridswap_iostatus_bytes(req); + hybperf_io_stat(req->io_para.record, req->page_cnt, + req->segment_cnt); + + kref_put_mutex(&req->refcount, hybridswap_io_req_release, + &req->refmutex); + + hybp(HYB_DEBUG, "io schedule finish succ\n"); + + return ret; +} + +static void hybridswap_dump_point_lat( + struct hybridswap_key_point_record *record, ktime_t start) +{ + int i; + + for (i = 0; i < HYB_KYE_POINT_BUTT; ++i) { + if (!record->key_point[i].record_cnt) + continue; + + hybp(HYB_ERR, + "%s diff %lld cnt %u end %u lat %lld ravg_sum %llu\n", + key_point_name[i], + ktime_us_delta(record->key_point[i].first_time, start), + record->key_point[i].record_cnt, + record->key_point[i].end_cnt, + record->key_point[i].proc_total_time, + record->key_point[i].proc_ravg_sum); + } +} + +static void hybridswap_dump_no_record_point( + struct hybridswap_key_point_record *record, char *log, + unsigned int *count) +{ + int i; + unsigned int point = 0; + + for (i = 0; i < HYB_KYE_POINT_BUTT; ++i) + if (record->key_point[i].record_cnt) + point = i; + + point++; + if (point < HYB_KYE_POINT_BUTT) + *count += snprintf(log + *count, + (size_t)(DUMP_BUF_LEN - *count), + " no_record_point %s", key_point_name[point]); + else + *count += snprintf(log + *count, + (size_t)(DUMP_BUF_LEN - *count), " all_point_record"); +} + +static long long hybridswap_calc_speed(s64 page_cnt, s64 time) +{ + s64 size; + + if (!page_cnt) + return 0; + + size = page_cnt * PAGE_SIZE * BITS_PER_BYTE; + if (time) + return size * USEC_PER_SEC / time; + else + return S64_MAX; +} + +static void hybridswap_dump_lat( + struct hybridswap_key_point_record *record, ktime_t curr_time, + bool perf_end_flag) +{ + char log[DUMP_BUF_LEN] = { 0 }; + unsigned int count = 0; + ktime_t start; + s64 total_time; + + start = record->key_point[HYB_START].first_time; + total_time = ktime_us_delta(curr_time, start); + count += snprintf(log + count, + (size_t)(DUMP_BUF_LEN - count), + "totaltime(us) %lld class %u task %s nice %d", + total_time, record->class, record->task_comm, record->nice); + + if (perf_end_flag) + count += snprintf(log + count, (size_t)(DUMP_BUF_LEN - count), + " page %d segment %d speed(bps) %lld level %llu", + record->page_cnt, record->segment_cnt, + hybridswap_calc_speed(record->page_cnt, total_time), + record->warn_level); + else + count += snprintf(log + count, (size_t)(DUMP_BUF_LEN - count), + " state %c", task_state_to_char(record->task)); + + hybridswap_dump_no_record_point(record, log, &count); + + hybp(HYB_ERR, "perf end flag %u %s\n", perf_end_flag, log); + hybridswap_dump_point_lat(record, start); + dump_stack(); +} + +static unsigned long hybperf_warn_level( + enum hybridswap_class class) +{ + if (unlikely(class >= HYB_CLASS_BUTT)) + return 0; + + return warn_level[class]; +} + +void hybperf_warning(struct timer_list *t) +{ + struct hybridswap_key_point_record *record = + from_timer(record, t, lat_monitor); + static unsigned long last_dumpiowrkjiffies = 0; + + if (!record->warn_level) + return; + + if (jiffies_to_msecs(jiffies - last_dumpiowrkjiffies) <= 60000) + return; + + hybridswap_dump_lat(record, ktime_get(), false); + + if (likely(record->task)) + sched_show_task(record->task); + last_dumpiowrkjiffies = jiffies; + record->warn_level <<= 2; + record->timeout_flag = true; + mod_timer(&record->lat_monitor, + jiffies + msecs_to_jiffies(record->warn_level)); +} + +static void hybperf_init_monitor( + struct hybridswap_key_point_record *record, + enum hybridswap_class class) +{ + record->warn_level = hybperf_warn_level(class); + + if (!record->warn_level) + return; + + record->task = current; + get_task_struct(record->task); + timer_setup(&record->lat_monitor, hybperf_warning, 0); + mod_timer(&record->lat_monitor, + jiffies + msecs_to_jiffies(record->warn_level)); +} + +static void hybperf_stop_monitor( + struct hybridswap_key_point_record *record) +{ + if (!record->warn_level) + return; + + del_timer_sync(&record->lat_monitor); + put_task_struct(record->task); +} + +static void hybperf_init(struct hybridswap_key_point_record *record, + enum hybridswap_class class) +{ + int i; + + for (i = 0; i < HYB_KYE_POINT_BUTT; ++i) + spin_lock_init(&record->key_point[i].time_lock); + + record->nice = task_nice(current); + record->class = class; + get_task_comm(record->task_comm, current); + hybperf_init_monitor(record, class); +} + +void hybperf_start_proc( + struct hybridswap_key_point_record *record, + enum hybridswap_key_point type, ktime_t curr_time, + unsigned long long current_ravg_sum) +{ + struct hybridswap_key_point_info *key_point = + &record->key_point[type]; + + if (!key_point->record_cnt) + key_point->first_time = curr_time; + + key_point->record_cnt++; + key_point->last_time = curr_time; + key_point->last_ravg_sum = current_ravg_sum; +} + +void hybperf_end_proc( + struct hybridswap_key_point_record *record, + enum hybridswap_key_point type, ktime_t curr_time, + unsigned long long current_ravg_sum) +{ + struct hybridswap_key_point_info *key_point = + &record->key_point[type]; + s64 diff_time = ktime_us_delta(curr_time, key_point->last_time); + + key_point->proc_total_time += diff_time; + if (diff_time > key_point->proc_max_time) + key_point->proc_max_time = diff_time; + + key_point->proc_ravg_sum += current_ravg_sum - + key_point->last_ravg_sum; + key_point->end_cnt++; + key_point->last_time = curr_time; + key_point->last_ravg_sum = current_ravg_sum; +} + +void hybperf_async_perf( + struct hybridswap_key_point_record *record, + enum hybridswap_key_point type, ktime_t start, + unsigned long long start_ravg_sum) +{ + unsigned long long current_ravg_sum = ((type == HYB_CALL_BACK) || + (type == HYB_END_WORK)) ? hybridswap_fetch_ravg_sum() : 0; + unsigned long flags; + + spin_lock_irqsave(&record->key_point[type].time_lock, flags); + hybperf_start_proc(record, type, start, start_ravg_sum); + hybperf_end_proc(record, type, ktime_get(), + current_ravg_sum); + spin_unlock_irqrestore(&record->key_point[type].time_lock, flags); +} + +void hybperfiowrkpoint( + struct hybridswap_key_point_record *record, + enum hybridswap_key_point type) +{ + hybperf_start_proc(record, type, ktime_get(), + hybridswap_fetch_ravg_sum()); + record->key_point[type].end_cnt++; +} + +void hybperf_start( + struct hybridswap_key_point_record *record, + ktime_t stsrt, unsigned long long start_ravg_sum, + enum hybridswap_class class) +{ + hybperf_init(record, class); + hybperf_start_proc(record, HYB_START, stsrt, + start_ravg_sum); + record->key_point[HYB_START].end_cnt++; +} + +void hybperfiowrkstat( + struct hybridswap_key_point_record *record) +{ + int task_is_fg = 0; + struct hybstatus *stat = hybridswap_fetch_stat_obj(); + s64 curr_lat; + s64 timeout_value[HYB_CLASS_BUTT] = { + 2000000, 100000, 500000, 2000000 + }; + + if (!stat || (record->class >= HYB_CLASS_BUTT)) + return; + + curr_lat = ktime_us_delta(record->key_point[HYB_DONE].first_time, + record->key_point[HYB_START].first_time); + atomic64_add(curr_lat, &stat->lat[record->class].total_lat); + if (curr_lat > atomic64_read(&stat->lat[record->class].max_lat)) + atomic64_set(&stat->lat[record->class].max_lat, curr_lat); + if (curr_lat > timeout_value[record->class]) + atomic64_inc(&stat->lat[record->class].timeout_cnt); + if (record->class == HYB_FAULT_OUT) { + if (curr_lat <= timeout_value[HYB_FAULT_OUT]) + return; +#ifdef CONFIG_FG_TASK_UID + task_is_fg = current_is_fg() ? 1 : 0; +#endif + if (curr_lat > 500000) + atomic64_inc(&stat->fault_stat[task_is_fg].timeout_500ms_cnt); + else if (curr_lat > 100000) + atomic64_inc(&stat->fault_stat[task_is_fg].timeout_100ms_cnt); + hybp(HYB_INFO, "task %s:%d fault out timeout us %llu fg %d\n", + current->comm, current->pid, curr_lat, task_is_fg); + } +} + +void hybperf_end(struct hybridswap_key_point_record *record) +{ + int loglevel; + + hybperf_stop_monitor(record); + hybperfiowrkpoint(record, HYB_DONE); + hybperfiowrkstat(record); + + loglevel = record->timeout_flag ? HYB_ERR : HYB_DEBUG; + if (loglevel > hybridswap_loglevel()) + return; + + hybridswap_dump_lat(record, + record->key_point[HYB_DONE].first_time, true); +} + +void hybperfiowrkstart( + struct hybridswap_key_point_record *record, + enum hybridswap_key_point type) +{ + hybperf_start_proc(record, type, ktime_get(), + hybridswap_fetch_ravg_sum()); +} + +void hybperfiowrkend( + struct hybridswap_key_point_record *record, + enum hybridswap_key_point type) +{ + hybperf_end_proc(record, type, ktime_get(), + hybridswap_fetch_ravg_sum()); +} + +void hybperf_io_stat( + struct hybridswap_key_point_record *record, int page_cnt, + int segment_cnt) +{ + record->page_cnt = page_cnt; + record->segment_cnt = segment_cnt; +} + +static struct io_eswapent *alloc_io_eswapent(struct hybridswap_page_pool *pool, + bool fast, bool nofail) +{ + int i; + struct io_eswapent *io_eswap = hybridswap_malloc(sizeof(struct io_eswapent), + fast, nofail); + + if (!io_eswap) { + hybp(HYB_ERR, "alloc io_eswap failed\n"); + return NULL; + } + + io_eswap->eswapid = -EINVAL; + io_eswap->pool = pool; + for (i = 0; i < (int)ESWAP_PG_CNT; i++) { + io_eswap->pages[i] = hybridswap_alloc_page(pool, GFP_ATOMIC, + fast, nofail); + if (!io_eswap->pages[i]) { + hybp(HYB_ERR, "alloc page[%d] failed\n", i); + goto page_free; + } + } + return io_eswap; +page_free: + for (i = 0; i < (int)ESWAP_PG_CNT; i++) + if (io_eswap->pages[i]) + hybridswap_page_recycle(io_eswap->pages[i], pool); + hybridswap_free(io_eswap); + + return NULL; +} + +static void discard_io_eswapent(struct io_eswapent *io_eswap, unsigned int op) +{ + struct zram *zram = NULL; + int i; + + if (!io_eswap) { + hybp(HYB_ERR, "NULL io_eswap\n"); + return; + } + if (!io_eswap->mcg) + zram = io_eswap->zram; + else + zram = MEMCGRP_ITEM(io_eswap->mcg, zram); + if (!zram) { + hybp(HYB_ERR, "NULL zram\n"); + goto out; + } + for (i = 0; i < (int)ESWAP_PG_CNT; i++) + if (io_eswap->pages[i]) + hybridswap_page_recycle(io_eswap->pages[i], io_eswap->pool); + if (io_eswap->eswapid < 0) + goto out; + hybp(HYB_DEBUG, "eswap = %d, op = %d\n", io_eswap->eswapid, op); + if (op == REQ_OP_READ) { + put_eswap(zram->infos, io_eswap->eswapid); + goto out; + } + for (i = 0; i < io_eswap->cnt; i++) { + u32 index = io_eswap->index[i]; + + zram_slot_lock(zram, index); + if (io_eswap->mcg) + swap_sorted_list_add_tail(zram, index, io_eswap->mcg); + zram_clear_flag(zram, index, ZRAM_UNDER_WB); + zram_slot_unlock(zram, index); + } + hybridswap_free_eswap(zram->infos, io_eswap->eswapid); +out: + hybridswap_free(io_eswap); +} + +static void copy_to_pages(u8 *src, struct page *pages[], + unsigned long eswpentry, int size) +{ + u8 *dst = NULL; + int pg_id = esentry_pgid(eswpentry); + int offset = esentry_pgoff(eswpentry); + + if (!src) { + hybp(HYB_ERR, "NULL src\n"); + return; + } + if (!pages) { + hybp(HYB_ERR, "NULL pages\n"); + return; + } + if (size < 0 || size > (int)PAGE_SIZE) { + hybp(HYB_ERR, "size = %d invalid\n", size); + return; + } + dst = page_to_virt(pages[pg_id]); + if (offset + size <= (int)PAGE_SIZE) { + memcpy(dst + offset, src, size); + return; + } + if (pg_id == ESWAP_PG_CNT - 1) { + hybp(HYB_ERR, "eswap overflow, addr = %lx, size = %d\n", + eswpentry, size); + return; + } + memcpy(dst + offset, src, PAGE_SIZE - offset); + dst = page_to_virt(pages[pg_id + 1]); + memcpy(dst, src + PAGE_SIZE - offset, offset + size - PAGE_SIZE); +} + +static void copy_from_pages(u8 *dst, struct page *pages[], + unsigned long eswpentry, int size) +{ + u8 *src = NULL; + int pg_id = esentry_pgid(eswpentry); + int offset = esentry_pgoff(eswpentry); + + if (!dst) { + hybp(HYB_ERR, "NULL dst\n"); + return; + } + if (!pages) { + hybp(HYB_ERR, "NULL pages\n"); + return; + } + if (size < 0 || size > (int)PAGE_SIZE) { + hybp(HYB_ERR, "size = %d invalid\n", size); + return; + } + + src = page_to_virt(pages[pg_id]); + if (offset + size <= (int)PAGE_SIZE) { + memcpy(dst, src + offset, size); + return; + } + if (pg_id == ESWAP_PG_CNT - 1) { + hybp(HYB_ERR, "eswap overflow, addr = %lx, size = %d\n", + eswpentry, size); + return; + } + memcpy(dst, src + offset, PAGE_SIZE - offset); + src = page_to_virt(pages[pg_id + 1]); + memcpy(dst + PAGE_SIZE - offset, src, offset + size - PAGE_SIZE); +} + +static bool zram_test_skip(struct zram *zram, u32 index, struct mem_cgroup *mcg) +{ + if (zram_test_flag(zram, index, ZRAM_WB)) + return true; + if (zram_test_flag(zram, index, ZRAM_UNDER_WB)) + return true; + if (zram_test_flag(zram, index, ZRAM_BATCHING_OUT)) + return true; + if (zram_test_flag(zram, index, ZRAM_SAME)) + return true; + if (mcg != zram_fetch_mcg(zram, index)) + return true; + if (!zram_get_obj_size(zram, index)) + return true; + + return false; +} + +static bool zram_test_overwrite(struct zram *zram, u32 index, int eswapid) +{ + if (!zram_test_flag(zram, index, ZRAM_WB)) + return true; + if (eswapid != esentry_extid(zram_get_handle(zram, index))) + return true; + + return false; +} + +static void update_size_info(struct zram *zram, u32 index) +{ + struct hybstatus *stat; + int size = zram_get_obj_size(zram, index); + struct mem_cgroup *mcg; + memcg_hybs_t *hybs; + int eswapid; + + if (!zram_test_flag(zram, index, ZRAM_IN_BD)) + return; + + eswapid = esentry_extid(zram_get_handle(zram, index)); + hybp(HYB_INFO, "eswapid %d index %d\n", eswapid, index); + + if (eswapid >= 0 && eswapid < zram->infos->nr_es) + atomic_dec(&zram->infos->eswap_stored_pages[eswapid]); + else { + hybp(HYB_ERR, "eswap = %d invalid\n", eswapid); + eswapid = -1; + } + + stat = hybridswap_fetch_stat_obj(); + if (stat) { + atomic64_add(size, &stat->dropped_eswap_size); + atomic64_sub(size, &stat->stored_size); + atomic64_dec(&stat->stored_pages); + } else + hybp(HYB_ERR, "NULL stat\n"); + + mcg = zram_fetch_mcg(zram, index); + if (mcg) { + hybs = MEMCGRP_ITEM_DATA(mcg); + + if (hybs) { + atomic64_sub(size, &hybs->hybridswap_stored_size); + atomic64_dec(&hybs->hybridswap_stored_pages); + } else + hybp(HYB_ERR, "NULL hybs\n"); + } else + hybp(HYB_ERR, "NULL mcg\n"); + zram_clear_flag(zram, index, ZRAM_IN_BD); +} + +static void move_to_hybridswap(struct zram *zram, u32 index, + unsigned long eswpentry, struct mem_cgroup *mcg) +{ + int size; + struct hybstatus *stat = hybridswap_fetch_stat_obj(); + + if (!stat) { + hybp(HYB_ERR, "NULL stat\n"); + return; + } + if (!zram) { + hybp(HYB_ERR, "NULL zram\n"); + return; + } + if (index >= (u32)zram->infos->total_objects) { + hybp(HYB_ERR, "index = %d invalid\n", index); + return; + } + if (!mcg) { + hybp(HYB_ERR, "NULL mcg\n"); + return; + } + + size = zram_get_obj_size(zram, index); + + zram_clear_flag(zram, index, ZRAM_UNDER_WB); + + zs_free(zram->mem_pool, zram_get_handle(zram, index)); + atomic64_sub(size, &zram->stats.compr_data_size); + atomic64_dec(&zram->stats.pages_stored); + + zram_set_mcg(zram, index, mcg->id.id); + zram_set_flag(zram, index, ZRAM_IN_BD); + zram_set_flag(zram, index, ZRAM_WB); + zram_set_obj_size(zram, index, size); + if (size == PAGE_SIZE) + zram_set_flag(zram, index, ZRAM_HUGE); + zram_set_handle(zram, index, eswpentry); + swap_maps_insert(zram, index); + + atomic64_add(size, &stat->stored_size); + atomic64_add(size, &MEMCGRP_ITEM(mcg, hybridswap_stored_size)); + atomic64_inc(&stat->stored_pages); + atomic_inc(&zram->infos->eswap_stored_pages[esentry_extid(eswpentry)]); + atomic64_inc(&MEMCGRP_ITEM(mcg, hybridswap_stored_pages)); +} + +static void __move_to_zram(struct zram *zram, u32 index, unsigned long handle, + struct io_eswapent *io_eswap) +{ + struct hybstatus *stat = hybridswap_fetch_stat_obj(); + struct mem_cgroup *mcg = io_eswap->mcg; + int size = zram_get_obj_size(zram, index); + + if (!stat) { + hybp(HYB_ERR, "NULL stat\n"); + return; + } + + zram_slot_lock(zram, index); + if (zram_test_overwrite(zram, index, io_eswap->eswapid)) { + zram_slot_unlock(zram, index); + zs_free(zram->mem_pool, handle); + return; + } + swap_maps_destroy(zram, index); + zram_set_handle(zram, index, handle); + zram_clear_flag(zram, index, ZRAM_WB); + if (mcg) + swap_sorted_list_add_tail(zram, index, mcg); + zram_set_flag(zram, index, ZRAM_FROM_HYBRIDSWAP); + atomic64_add(size, &zram->stats.compr_data_size); + atomic64_inc(&zram->stats.pages_stored); + zram_clear_flag(zram, index, ZRAM_IN_BD); + zram_slot_unlock(zram, index); + + atomic64_inc(&stat->batchout_pages); + atomic64_sub(size, &stat->stored_size); + atomic64_dec(&stat->stored_pages); + atomic64_add(size, &stat->batchout_real_load); + atomic_dec(&zram->infos->eswap_stored_pages[io_eswap->eswapid]); + if (mcg) { + atomic64_sub(size, &MEMCGRP_ITEM(mcg, hybridswap_stored_size)); + atomic64_dec(&MEMCGRP_ITEM(mcg, hybridswap_stored_pages)); + } +} + +static int move_to_zram(struct zram *zram, u32 index, struct io_eswapent *io_eswap) +{ + unsigned long handle, eswpentry; + struct mem_cgroup *mcg = NULL; + int size, i; + u8 *dst = NULL; + + if (!zram) { + hybp(HYB_ERR, "NULL zram\n"); + return -EINVAL; + } + if (index >= (u32)zram->infos->total_objects) { + hybp(HYB_ERR, "index = %d invalid\n", index); + return -EINVAL; + } + if (!io_eswap) { + hybp(HYB_ERR, "NULL io_eswap\n"); + return -EINVAL; + } + + mcg = io_eswap->mcg; + zram_slot_lock(zram, index); + eswpentry = zram_get_handle(zram, index); + if (zram_test_overwrite(zram, index, io_eswap->eswapid)) { + zram_slot_unlock(zram, index); + return 0; + } + size = zram_get_obj_size(zram, index); + zram_slot_unlock(zram, index); + + for (i = esentry_pgid(eswpentry) - 1; i >= 0 && io_eswap->pages[i]; i--) { + hybridswap_page_recycle(io_eswap->pages[i], io_eswap->pool); + io_eswap->pages[i] = NULL; + } + handle = hybridswap_zsmalloc(zram->mem_pool, size, io_eswap->pool); + if (!handle) { + hybp(HYB_ERR, "alloc handle failed, size = %d\n", size); + return -ENOMEM; + } + dst = zs_map_object(zram->mem_pool, handle, ZS_MM_WO); + copy_from_pages(dst, io_eswap->pages, eswpentry, size); + zs_unmap_object(zram->mem_pool, handle); + __move_to_zram(zram, index, handle, io_eswap); + + return 0; +} + +static int eswap_unlock(struct io_eswapent *io_eswap) +{ + int eswapid; + struct mem_cgroup *mcg = NULL; + struct zram *zram = NULL; + int k; + unsigned long eswpentry; + int real_load = 0, size; + + if (!io_eswap) { + hybp(HYB_ERR, "NULL io_eswap\n"); + goto out; + } + + mcg = io_eswap->mcg; + if (!mcg) { + hybp(HYB_ERR, "NULL mcg\n"); + goto out; + } + zram = MEMCGRP_ITEM(mcg, zram); + if (!zram) { + hybp(HYB_ERR, "NULL zram\n"); + goto out; + } + eswapid = io_eswap->eswapid; + if (eswapid < 0) + goto out; + + eswapid = io_eswap->eswapid; + if (MEMCGRP_ITEM(mcg, in_swapin)) + goto out; + hybp(HYB_DEBUG, "add eswapid = %d, cnt = %d.\n", + eswapid, io_eswap->cnt); + eswpentry = ((unsigned long)eswapid) << ESWAP_SHIFT; + for (k = 0; k < io_eswap->cnt; k++) + zram_slot_lock(zram, io_eswap->index[k]); + for (k = 0; k < io_eswap->cnt; k++) { + move_to_hybridswap(zram, io_eswap->index[k], eswpentry, mcg); + size = zram_get_obj_size(zram, io_eswap->index[k]); + eswpentry += size; + real_load += size; + } + put_eswap(zram->infos, eswapid); + io_eswap->eswapid = -EINVAL; + for (k = 0; k < io_eswap->cnt; k++) + zram_slot_unlock(zram, io_eswap->index[k]); + hybp(HYB_DEBUG, "add eswap OK.\n"); +out: + discard_io_eswapent(io_eswap, REQ_OP_WRITE); + if (mcg) + css_put(&mcg->css); + + return real_load; +} + +static void eswap_add(struct io_eswapent *io_eswap, + enum hybridswap_class class) +{ + struct mem_cgroup *mcg = NULL; + struct zram *zram = NULL; + int eswapid; + int k; + + if (!io_eswap) { + hybp(HYB_ERR, "NULL io_eswap\n"); + return; + } + + mcg = io_eswap->mcg; + if (!mcg) + zram = io_eswap->zram; + else + zram = MEMCGRP_ITEM(mcg, zram); + if (!zram) { + hybp(HYB_ERR, "NULL zram\n"); + goto out; + } + + eswapid = io_eswap->eswapid; + if (eswapid < 0) + goto out; + + io_eswap->cnt = swap_maps_fetch_eswap_index(zram->infos, + eswapid, + io_eswap->index); + hybp(HYB_DEBUG, "eswapid = %d, cnt = %d.\n", eswapid, io_eswap->cnt); + for (k = 0; k < io_eswap->cnt; k++) { + int ret = move_to_zram(zram, io_eswap->index[k], io_eswap); + + if (ret < 0) + goto out; + } + hybp(HYB_DEBUG, "eswap add OK, free eswapid = %d.\n", eswapid); + hybridswap_free_eswap(zram->infos, io_eswap->eswapid); + io_eswap->eswapid = -EINVAL; + if (mcg) { + atomic64_inc(&MEMCGRP_ITEM(mcg, hybridswap_inextcnt)); + atomic_dec(&MEMCGRP_ITEM(mcg, hybridswap_extcnt)); + } +out: + discard_io_eswapent(io_eswap, REQ_OP_READ); + if (mcg) + css_put(&mcg->css); +} + +static void eswap_clear(struct zram *zram, int eswapid) +{ + int *index = NULL; + int cnt; + int k; + struct hybstatus *stat = hybridswap_fetch_stat_obj(); + + if (!stat) { + hybp(HYB_ERR, "NULL stat\n"); + return; + } + + index = kzalloc(sizeof(int) * ESWAP_MAX_OBJ_CNT, GFP_NOIO); + if (!index) + index = kzalloc(sizeof(int) * ESWAP_MAX_OBJ_CNT, + GFP_NOIO | __GFP_NOFAIL); + + cnt = swap_maps_fetch_eswap_index(zram->infos, eswapid, index); + + for (k = 0; k < cnt; k++) { + zram_slot_lock(zram, index[k]); + if (zram_test_overwrite(zram, index[k], eswapid)) { + zram_slot_unlock(zram, index[k]); + continue; + } + zram_set_mcg(zram, index[k], 0); + zram_set_flag(zram, index[k], ZRAM_MCGID_CLEAR); + atomic64_inc(&stat->memcgid_clear); + zram_slot_unlock(zram, index[k]); + } + + kfree(index); +} + +static int shrink_entry(struct zram *zram, u32 index, struct io_eswapent *io_eswap, + unsigned long eswap_off) +{ + unsigned long handle; + int size; + u8 *src = NULL; + struct hybstatus *stat = hybridswap_fetch_stat_obj(); + + if (!stat) { + hybp(HYB_ERR, "NULL stat\n"); + return -EINVAL; + } + if (!zram) { + hybp(HYB_ERR, "NULL zram\n"); + return -EINVAL; + } + if (index >= (u32)zram->infos->total_objects) { + hybp(HYB_ERR, "index = %d invalid\n", index); + return -EINVAL; + } + + zram_slot_lock(zram, index); + handle = zram_get_handle(zram, index); + if (!handle || zram_test_skip(zram, index, io_eswap->mcg)) { + zram_slot_unlock(zram, index); + return 0; + } + size = zram_get_obj_size(zram, index); + if (eswap_off + size > ESWAP_SIZE) { + zram_slot_unlock(zram, index); + return -ENOSPC; + } + + src = zs_map_object(zram->mem_pool, handle, ZS_MM_RO); + copy_to_pages(src, io_eswap->pages, eswap_off, size); + zs_unmap_object(zram->mem_pool, handle); + io_eswap->index[io_eswap->cnt++] = index; + + swap_sorted_list_del(zram, index); + zram_set_flag(zram, index, ZRAM_UNDER_WB); + if (zram_test_flag(zram, index, ZRAM_FROM_HYBRIDSWAP)) { + atomic64_inc(&stat->reout_pages); + atomic64_add(size, &stat->reout_bytes); + } + zram_slot_unlock(zram, index); + atomic64_inc(&stat->reclaimin_pages); + + return size; +} + +static int shrink_entry_list(struct io_eswapent *io_eswap) +{ + struct mem_cgroup *mcg = NULL; + struct zram *zram = NULL; + unsigned long stored_size; + int *swap_index = NULL; + int swap_cnt, k; + int swap_size = 0; + + if (!io_eswap) { + hybp(HYB_ERR, "NULL io_eswap\n"); + return -EINVAL; + } + + mcg = io_eswap->mcg; + zram = MEMCGRP_ITEM(mcg, zram); + hybp(HYB_DEBUG, "mcg = %d\n", mcg->id.id); + stored_size = atomic64_read(&MEMCGRP_ITEM(mcg, zram_stored_size)); + hybp(HYB_DEBUG, "zram_stored_size = %ld\n", stored_size); + if (stored_size < ESWAP_SIZE) { + hybp(HYB_INFO, "%lu is smaller than ESWAP_SIZE\n", stored_size); + return -ENOENT; + } + + swap_index = kzalloc(sizeof(int) * ESWAP_MAX_OBJ_CNT, GFP_NOIO); + if (!swap_index) + return -ENOMEM; + io_eswap->eswapid = hybridswap_alloc_eswap(zram->infos, mcg); + if (io_eswap->eswapid < 0) { + kfree(swap_index); + return io_eswap->eswapid; + } + swap_cnt = zram_fetch_mcg_last_index(zram->infos, mcg, swap_index, + ESWAP_MAX_OBJ_CNT); + io_eswap->cnt = 0; + for (k = 0; k < swap_cnt && swap_size < (int)ESWAP_SIZE; k++) { + int size = shrink_entry(zram, swap_index[k], io_eswap, swap_size); + + if (size < 0) + break; + swap_size += size; + } + kfree(swap_index); + hybp(HYB_DEBUG, "fill eswap = %d, cnt = %d, overhead = %ld.\n", + io_eswap->eswapid, io_eswap->cnt, ESWAP_SIZE - swap_size); + if (swap_size == 0) { + hybp(HYB_ERR, "swap_size = 0, free eswapid = %d.\n", + io_eswap->eswapid); + hybridswap_free_eswap(zram->infos, io_eswap->eswapid); + io_eswap->eswapid = -EINVAL; + return -ENOENT; + } + + return swap_size; +} + +void hybridswap_manager_deinit(struct zram *zram) +{ + if (!zram) { + hybp(HYB_ERR, "NULL zram\n"); + return; + } + + free_hyb_info(zram->infos); + zram->infos = NULL; +} + +int hybridswap_manager_init(struct zram *zram) +{ + int ret; + + if (!zram) { + hybp(HYB_ERR, "NULL zram\n"); + ret = -EINVAL; + goto out; + } + + zram->infos = alloc_hyb_info(zram->disksize, + zram->nr_pages << PAGE_SHIFT); + if (!zram->infos) { + ret = -ENOMEM; + goto out; + } + return 0; +out: + hybridswap_manager_deinit(zram); + + return ret; +} + +void hybridswap_manager_memcg_init(struct zram *zram, + struct mem_cgroup *memcg) +{ + memcg_hybs_t *hybs; + + if (!memcg || !zram || !zram->infos) { + hybp(HYB_ERR, "invalid zram or mcg_hyb\n"); + return; + } + + hyb_entries_init(memcgindex(zram->infos, memcg->id.id), zram->infos->objects); + hyb_entries_init(memcgindex(zram->infos, memcg->id.id), zram->infos->eswap_table); + + hybs = MEMCGRP_ITEM_DATA(memcg); + hybs->in_swapin = false; + atomic64_set(&hybs->zram_stored_size, 0); + atomic64_set(&hybs->zram_page_size, 0); + atomic64_set(&hybs->hybridswap_stored_pages, 0); + atomic64_set(&hybs->hybridswap_stored_size, 0); + atomic64_set(&hybs->hybridswap_allfaultcnt, 0); + atomic64_set(&hybs->hybridswap_outcnt, 0); + atomic64_set(&hybs->hybridswap_incnt, 0); + atomic64_set(&hybs->hybridswap_faultcnt, 0); + atomic64_set(&hybs->hybridswap_outextcnt, 0); + atomic64_set(&hybs->hybridswap_inextcnt, 0); + atomic_set(&hybs->hybridswap_extcnt, 0); + atomic_set(&hybs->hybridswap_peakextcnt, 0); + mutex_init(&hybs->swap_lock); + + smp_wmb(); + hybs->zram = zram; + hybp(HYB_DEBUG, "new memcg in zram, id = %d.\n", memcg->id.id); +} + +void hybridswap_manager_memcg_deinit(struct mem_cgroup *mcg) +{ + struct zram *zram = NULL; + struct hyb_info *infos = NULL; + struct hybstatus *stat = hybridswap_fetch_stat_obj(); + int last_index = -1; + memcg_hybs_t *hybs; + + if (!stat) { + hybp(HYB_ERR, "NULL stat\n"); + return; + } + + hybs = MEMCGRP_ITEM_DATA(mcg); + if (!hybs->zram) + return; + + zram = hybs->zram; + if (!zram->infos) { + hybp(HYB_WARN, "mcg %p name %s id %d zram %p infos is NULL\n", + mcg, hybs->name, mcg->id.id, zram); + return; + } + + hybp(HYB_DEBUG, "deinit mcg %d %s\n", mcg->id.id, hybs->name); + if (mcg->id.id == 0) + return; + + infos = zram->infos; + while (1) { + int index = fetch_memcg_zram_entry(infos, mcg); + + if (index == -ENOENT) + break; + + if (index < 0) { + hybp(HYB_ERR, "invalid index\n"); + return; + } + + if (last_index == index) { + hybp(HYB_ERR, "dup index %d\n", index); + dump_stack(); + } + + zram_slot_lock(zram, index); + if (index == last_index || mcg == zram_fetch_mcg(zram, index)) { + hyb_entries_del(obj_index(zram->infos, index), + memcgindex(zram->infos, mcg->id.id), + zram->infos->objects); + zram_set_mcg(zram, index, 0); + zram_set_flag(zram, index, ZRAM_MCGID_CLEAR); + atomic64_inc(&stat->memcgid_clear); + } + zram_slot_unlock(zram, index); + last_index = index; + } + + hybp(HYB_DEBUG, "deinit mcg %d %s, entry done\n", mcg->id.id, hybs->name); + while (1) { + int eswapid = fetch_memcg_eswap(infos, mcg); + + if (eswapid == -ENOENT) + break; + + eswap_clear(zram, eswapid); + hyb_entries_set_memcgid(eswap_index(infos, eswapid), infos->eswap_table, 0); + put_eswap(infos, eswapid); + } + hybp(HYB_DEBUG, "deinit mcg %d %s, eswap done\n", mcg->id.id, hybs->name); + hybs->zram = NULL; +} +void hybridswap_swap_sorted_list_add(struct zram *zram, + u32 index, struct mem_cgroup *memcg) +{ + if (!zram) { + hybp(HYB_ERR, "NULL zram\n"); + return; + } + if (index >= (u32)zram->infos->total_objects) { + hybp(HYB_ERR, "index = %d invalid\n", index); + return; + } + + swap_sorted_list_add(zram, index, memcg); +} + +void hybridswap_swap_sorted_list_del(struct zram *zram, u32 index) +{ + struct hybstatus *stat = hybridswap_fetch_stat_obj(); + + if (!stat) { + hybp(HYB_ERR, "NULL stat\n"); + return; + } + if (!zram) { + hybp(HYB_ERR, "NULL zram\n"); + return; + } + if (index >= (u32)zram->infos->total_objects) { + hybp(HYB_ERR, "index = %d invalid\n", index); + return; + } + + zram_clear_flag(zram, index, ZRAM_FROM_HYBRIDSWAP); + if (zram_test_flag(zram, index, ZRAM_MCGID_CLEAR)) { + zram_clear_flag(zram, index, ZRAM_MCGID_CLEAR); + atomic64_dec(&stat->memcgid_clear); + } + + if (zram_test_flag(zram, index, ZRAM_WB)) { + update_size_info(zram, index); + swap_maps_destroy(zram, index); + zram_clear_flag(zram, index, ZRAM_WB); + zram_set_mcg(zram, index, 0); + zram_set_handle(zram, index, 0); + } else { + swap_sorted_list_del(zram, index); + } +} + +unsigned long hybridswap_eswap_create(struct mem_cgroup *mcg, + int *eswapid, + struct hybridswap_buffer *buf, + void **private) +{ + struct io_eswapent *io_eswap = NULL; + int reclaim_size; + + if (!mcg) { + hybp(HYB_ERR, "NULL mcg\n"); + return 0; + } + if (!eswapid) { + hybp(HYB_ERR, "NULL eswapid\n"); + return 0; + } + (*eswapid) = -EINVAL; + if (!buf) { + hybp(HYB_ERR, "NULL buf\n"); + return 0; + } + if (!private) { + hybp(HYB_ERR, "NULL private\n"); + return 0; + } + + io_eswap = alloc_io_eswapent(buf->pool, false, true); + if (!io_eswap) + return 0; + io_eswap->mcg = mcg; + reclaim_size = shrink_entry_list(io_eswap); + if (reclaim_size < 0) { + discard_io_eswapent(io_eswap, REQ_OP_WRITE); + (*eswapid) = reclaim_size; + return 0; + } + io_eswap->real_load = reclaim_size; + css_get(&mcg->css); + (*eswapid) = io_eswap->eswapid; + buf->dest_pages = io_eswap->pages; + (*private) = io_eswap; + hybp(HYB_DEBUG, "mcg = %d, eswapid = %d\n", mcg->id.id, io_eswap->eswapid); + + return reclaim_size; +} + +void hybridswap_eswap_register(void *private, struct hybridswap_io_req *req) +{ + struct io_eswapent *io_eswap = private; + + if (!io_eswap) { + hybp(HYB_ERR, "NULL io_eswap\n"); + return; + } + hybp(HYB_DEBUG, "eswapid = %d\n", io_eswap->eswapid); + atomic64_add(eswap_unlock(io_eswap), &req->real_load); +} + +void hybridswap_eswap_objs_del(struct zram *zram, u32 index) +{ + int eswapid; + struct mem_cgroup *mcg = NULL; + unsigned long eswpentry; + int size; + struct hybstatus *stat = hybridswap_fetch_stat_obj(); + + if (!stat) { + hybp(HYB_ERR, "NULL stat\n"); + return; + } + if (!zram || !zram->infos) { + hybp(HYB_ERR, "NULL zram\n"); + return; + } + if (index >= (u32)zram->infos->total_objects) { + hybp(HYB_ERR, "index = %d invalid\n", index); + return; + } + if (!zram_test_flag(zram, index, ZRAM_WB)) { + hybp(HYB_ERR, "not WB object\n"); + return; + } + + eswpentry = zram_get_handle(zram, index); + size = zram_get_obj_size(zram, index); + atomic64_sub(size, &stat->stored_size); + atomic64_dec(&stat->stored_pages); + atomic64_add(size, &stat->dropped_eswap_size); + mcg = zram_fetch_mcg(zram, index); + if (mcg) { + atomic64_sub(size, &MEMCGRP_ITEM(mcg, hybridswap_stored_size)); + atomic64_dec(&MEMCGRP_ITEM(mcg, hybridswap_stored_pages)); + } + + zram_clear_flag(zram, index, ZRAM_IN_BD); + if (!atomic_dec_and_test( + &zram->infos->eswap_stored_pages[esentry_extid(eswpentry)])) + return; + eswapid = fetch_eswap(zram->infos, esentry_extid(eswpentry)); + if (eswapid < 0) + return; + + atomic64_inc(&stat->notify_free); + if (mcg) + atomic64_inc(&MEMCGRP_ITEM(mcg, hybridswap_eswap_notify_free)); + hybp(HYB_DEBUG, "free eswapid = %d\n", eswapid); + hybridswap_free_eswap(zram->infos, eswapid); +} + +int hybridswap_find_eswap_by_index(unsigned long eswpentry, + struct hybridswap_buffer *buf, + void **private) +{ + int eswapid; + struct io_eswapent *io_eswap = NULL; + struct zram *zram = NULL; + + if (!buf) { + hybp(HYB_ERR, "NULL buf\n"); + return -EINVAL; + } + if (!private) { + hybp(HYB_ERR, "NULL private\n"); + return -EINVAL; + } + + zram = buf->zram; + eswapid = fetch_eswap(zram->infos, esentry_extid(eswpentry)); + if (eswapid < 0) + return eswapid; + io_eswap = alloc_io_eswapent(buf->pool, true, true); + if (!io_eswap) { + hybp(HYB_ERR, "io_eswap alloc failed\n"); + put_eswap(zram->infos, eswapid); + return -ENOMEM; + } + + io_eswap->eswapid = eswapid; + io_eswap->zram = zram; + io_eswap->mcg = find_memcg_by_id( + hyb_entries_fetch_memcgid(eswap_index(zram->infos, eswapid), + zram->infos->eswap_table)); + if (io_eswap->mcg) + css_get(&io_eswap->mcg->css); + buf->dest_pages = io_eswap->pages; + (*private) = io_eswap; + hybp(HYB_DEBUG, "fetch entry = %lx eswap = %d\n", eswpentry, eswapid); + + return eswapid; +} + +int hybridswap_find_eswap_by_memcg(struct mem_cgroup *mcg, + struct hybridswap_buffer *buf, + void **private) +{ + int eswapid; + struct io_eswapent *io_eswap = NULL; + + if (!mcg) { + hybp(HYB_ERR, "NULL mcg\n"); + return -EINVAL; + } + if (!buf) { + hybp(HYB_ERR, "NULL buf\n"); + return -EINVAL; + } + if (!private) { + hybp(HYB_ERR, "NULL private\n"); + return -EINVAL; + } + + eswapid = fetch_memcg_eswap(MEMCGRP_ITEM(mcg, zram)->infos, mcg); + if (eswapid < 0) + return eswapid; + io_eswap = alloc_io_eswapent(buf->pool, true, false); + if (!io_eswap) { + hybp(HYB_ERR, "io_eswap alloc failed\n"); + put_eswap(MEMCGRP_ITEM(mcg, zram)->infos, eswapid); + return -ENOMEM; + } + io_eswap->eswapid = eswapid; + io_eswap->mcg = mcg; + css_get(&mcg->css); + buf->dest_pages = io_eswap->pages; + (*private) = io_eswap; + hybp(HYB_DEBUG, "fetch mcg = %d, eswap = %d\n", mcg->id.id, eswapid); + + return eswapid; +} + +void hybridswap_eswap_destroy(void *private, enum hybridswap_class class) +{ + struct io_eswapent *io_eswap = private; + + if (!io_eswap) { + hybp(HYB_ERR, "NULL io_eswap\n"); + return; + } + + hybp(HYB_DEBUG, "eswapid = %d\n", io_eswap->eswapid); + eswap_add(io_eswap, class); +} + +void hybridswap_eswap_exception(enum hybridswap_class class, + void *private) +{ + struct io_eswapent *io_eswap = private; + struct mem_cgroup *mcg = NULL; + unsigned int op = (class == HYB_RECLAIM_IN) ? + REQ_OP_WRITE : REQ_OP_READ; + + if (!io_eswap) { + hybp(HYB_ERR, "NULL io_eswap\n"); + return; + } + + hybp(HYB_DEBUG, "eswapid = %d, op = %d\n", io_eswap->eswapid, op); + mcg = io_eswap->mcg; + discard_io_eswapent(io_eswap, op); + if (mcg) + css_put(&mcg->css); +} + +struct mem_cgroup *hybridswap_zram_fetch_mcg(struct zram *zram, u32 index) +{ + return zram_fetch_mcg(zram, index); +} + +void zram_set_mcg(struct zram *zram, u32 index, int memcgid) +{ + hyb_entries_set_memcgid(obj_index(zram->infos, index), + zram->infos->objects, memcgid); +} + +struct mem_cgroup *zram_fetch_mcg(struct zram *zram, u32 index) +{ + unsigned short memcgid; + + memcgid = hyb_entries_fetch_memcgid(obj_index(zram->infos, index), + zram->infos->objects); + + return find_memcg_by_id(memcgid); +} + +int zram_fetch_mcg_last_index(struct hyb_info *infos, + struct mem_cgroup *mcg, + int *index, int max_cnt) +{ + int cnt = 0; + u32 i, tmp; + + if (!infos) { + hybp(HYB_ERR, "NULL infos\n"); + return 0; + } + if (!infos->objects) { + hybp(HYB_ERR, "NULL table\n"); + return 0; + } + if (!mcg) { + hybp(HYB_ERR, "NULL mcg\n"); + return 0; + } + if (!index) { + hybp(HYB_ERR, "NULL index\n"); + return 0; + } + + hyb_lock_with_idx(memcgindex(infos, mcg->id.id), infos->objects); + hyb_entries_for_each_entry_reverse_safe(i, tmp, + memcgindex(infos, mcg->id.id), infos->objects) { + if (i >= (u32)infos->total_objects) { + hybp(HYB_ERR, "index = %d invalid\n", i); + continue; + } + index[cnt++] = i; + if (cnt >= max_cnt) + break; + } + hyb_unlock_with_idx(memcgindex(infos, mcg->id.id), infos->objects); + + return cnt; +} + +int swap_maps_fetch_eswap_index(struct hyb_info *infos, + int eswapid, int *index) +{ + int cnt = 0; + u32 i; + + if (!infos) { + hybp(HYB_ERR, "NULL infos\n"); + return 0; + } + if (!infos->objects) { + hybp(HYB_ERR, "NULL table\n"); + return 0; + } + if (!index) { + hybp(HYB_ERR, "NULL index\n"); + return 0; + } + if (eswapid < 0 || eswapid >= infos->nr_es) { + hybp(HYB_ERR, "eswap = %d invalid\n", eswapid); + return 0; + } + + hyb_lock_with_idx(eswap_index(infos, eswapid), infos->objects); + hyb_entries_for_each_entry(i, eswap_index(infos, eswapid), infos->objects) { + if (cnt >= (int)ESWAP_MAX_OBJ_CNT) { + WARN_ON_ONCE(1); + break; + } + index[cnt++] = i; + } + hyb_unlock_with_idx(eswap_index(infos, eswapid), infos->objects); + + return cnt; +} + +void swap_sorted_list_add(struct zram *zram, u32 index, struct mem_cgroup *memcg) +{ + unsigned long size; + struct hybstatus *stat = hybridswap_fetch_stat_obj(); + + if (!stat) { + hybp(HYB_ERR, "NULL stat\n"); + return; + } + if (!zram) { + hybp(HYB_ERR, "NULL zram\n"); + return; + } + if (index >= (u32)zram->infos->total_objects) { + hybp(HYB_ERR, "index = %d invalid\n", index); + return; + } + if (zram_test_flag(zram, index, ZRAM_WB)) { + hybp(HYB_ERR, "WB object, index = %d\n", index); + return; + } +#ifdef CONFIG_HYBRIDSWAP_ASYNC_COMPRESS + if (zram_test_flag(zram, index, ZRAM_CACHED)) { + hybp(HYB_ERR, "CACHED object, index = %d\n", index); + return; + } + if (zram_test_flag(zram, index, ZRAM_CACHED_COMPRESS)) { + hybp(HYB_ERR, "CACHED_COMPRESS object, index = %d\n", index); + return; + } +#endif + if (zram_test_flag(zram, index, ZRAM_SAME)) + return; + + zram_set_mcg(zram, index, memcg->id.id); + hyb_entries_add(obj_index(zram->infos, index), + memcgindex(zram->infos, memcg->id.id), + zram->infos->objects); + + size = zram_get_obj_size(zram, index); + + atomic64_add(size, &MEMCGRP_ITEM(memcg, zram_stored_size)); + atomic64_inc(&MEMCGRP_ITEM(memcg, zram_page_size)); + atomic64_add(size, &stat->zram_stored_size); + atomic64_inc(&stat->zram_stored_pages); +} + +void swap_sorted_list_add_tail(struct zram *zram, u32 index, struct mem_cgroup *mcg) +{ + unsigned long size; + struct hybstatus *stat = hybridswap_fetch_stat_obj(); + + if (!stat) { + hybp(HYB_ERR, "NULL stat\n"); + return; + } + if (!zram) { + hybp(HYB_ERR, "NULL zram\n"); + return; + } + if (!mcg || !MEMCGRP_ITEM(mcg, zram) || !MEMCGRP_ITEM(mcg, zram)->infos) { + hybp(HYB_ERR, "invalid mcg\n"); + return; + } + if (index >= (u32)zram->infos->total_objects) { + hybp(HYB_ERR, "index = %d invalid\n", index); + return; + } + if (zram_test_flag(zram, index, ZRAM_WB)) { + hybp(HYB_ERR, "WB object, index = %d\n", index); + return; + } +#ifdef CONFIG_HYBRIDSWAP_ASYNC_COMPRESS + if (zram_test_flag(zram, index, ZRAM_CACHED)) { + hybp(HYB_ERR, "CACHED object, index = %d\n", index); + return; + } + if (zram_test_flag(zram, index, ZRAM_CACHED_COMPRESS)) { + hybp(HYB_ERR, "CACHED_COMPRESS object, index = %d\n", index); + return; + } +#endif + if (zram_test_flag(zram, index, ZRAM_SAME)) + return; + + zram_set_mcg(zram, index, mcg->id.id); + hyb_entries_add_tail(obj_index(zram->infos, index), + memcgindex(zram->infos, mcg->id.id), + zram->infos->objects); + + size = zram_get_obj_size(zram, index); + + atomic64_add(size, &MEMCGRP_ITEM(mcg, zram_stored_size)); + atomic64_inc(&MEMCGRP_ITEM(mcg, zram_page_size)); + atomic64_add(size, &stat->zram_stored_size); + atomic64_inc(&stat->zram_stored_pages); +} + +void swap_sorted_list_del(struct zram *zram, u32 index) +{ + struct mem_cgroup *mcg = NULL; + unsigned long size; + struct hybstatus *stat = hybridswap_fetch_stat_obj(); + + if (!stat) { + hybp(HYB_ERR, "NULL stat\n"); + return; + } + if (!zram || !zram->infos) { + hybp(HYB_ERR, "NULL zram\n"); + return; + } + if (index >= (u32)zram->infos->total_objects) { + hybp(HYB_ERR, "index = %d invalid\n", index); + return; + } + if (zram_test_flag(zram, index, ZRAM_WB)) { + hybp(HYB_ERR, "WB object, index = %d\n", index); + return; + } + + mcg = zram_fetch_mcg(zram, index); + if (!mcg || !MEMCGRP_ITEM(mcg, zram) || !MEMCGRP_ITEM(mcg, zram)->infos) + return; + if (zram_test_flag(zram, index, ZRAM_SAME)) + return; + + size = zram_get_obj_size(zram, index); + hyb_entries_del(obj_index(zram->infos, index), + memcgindex(zram->infos, mcg->id.id), + zram->infos->objects); + zram_set_mcg(zram, index, 0); + + atomic64_sub(size, &MEMCGRP_ITEM(mcg, zram_stored_size)); + atomic64_dec(&MEMCGRP_ITEM(mcg, zram_page_size)); + atomic64_sub(size, &stat->zram_stored_size); + atomic64_dec(&stat->zram_stored_pages); +} + +void swap_maps_insert(struct zram *zram, u32 index) +{ + unsigned long eswpentry; + u32 eswapid; + + if (!zram) { + hybp(HYB_ERR, "NULL zram\n"); + return; + } + if (index >= (u32)zram->infos->total_objects) { + hybp(HYB_ERR, "index = %d invalid\n", index); + return; + } + + eswpentry = zram_get_handle(zram, index); + eswapid = esentry_extid(eswpentry); + hyb_entries_add_tail(obj_index(zram->infos, index), + eswap_index(zram->infos, eswapid), + zram->infos->objects); +} + +void swap_maps_destroy(struct zram *zram, u32 index) +{ + unsigned long eswpentry; + u32 eswapid; + + if (!zram) { + hybp(HYB_ERR, "NULL zram\n"); + return; + } + if (index >= (u32)zram->infos->total_objects) { + hybp(HYB_ERR, "index = %d invalid\n", index); + return; + } + + eswpentry = zram_get_handle(zram, index); + eswapid = esentry_extid(eswpentry); + hyb_entries_del(obj_index(zram->infos, index), + eswap_index(zram->infos, eswapid), + zram->infos->objects); +} + +static struct hyb_entries_head *fetch_node_default(int index, void *private) +{ + struct hyb_entries_head *table = private; + + return &table[index]; +} + +struct hyb_entries_table *alloc_table(struct hyb_entries_head *(*fetch_node)(int, void *), + void *private, gfp_t gfp) +{ + struct hyb_entries_table *table = + kmalloc(sizeof(struct hyb_entries_table), gfp); + + if (!table) + return NULL; + table->fetch_node = fetch_node ? fetch_node : fetch_node_default; + table->private = private; + + return table; +} + +void hyb_lock_with_idx(int index, struct hyb_entries_table *table) +{ + struct hyb_entries_head *node = index_node(index, table); + + if (!node) { + hybp(HYB_ERR, "index = %d, table = %pK\n", index, table); + return; + } + bit_spin_lock(ENTRY_LOCK_BIT, (unsigned long *)node); +} + +void hyb_unlock_with_idx(int index, struct hyb_entries_table *table) +{ + struct hyb_entries_head *node = index_node(index, table); + + if (!node) { + hybp(HYB_ERR, "index = %d, table = %pK\n", index, table); + return; + } + bit_spin_unlock(ENTRY_LOCK_BIT, (unsigned long *)node); +} + +bool hyb_entries_empty(int hindex, struct hyb_entries_table *table) +{ + bool ret = false; + + hyb_lock_with_idx(hindex, table); + ret = (prev_index(hindex, table) == hindex) && (next_index(hindex, table) == hindex); + hyb_unlock_with_idx(hindex, table); + + return ret; +} + +void hyb_entries_init(int index, struct hyb_entries_table *table) +{ + struct hyb_entries_head *node = index_node(index, table); + + if (!node) { + hybp(HYB_ERR, "index = %d, table = %pS func %pS\n", + index, table, table->fetch_node); + return; + } + memset(node, 0, sizeof(struct hyb_entries_head)); + node->prev = index; + node->next = index; +} + +void hyb_entries_add_nolock(int index, int hindex, struct hyb_entries_table *table) +{ + struct hyb_entries_head *node = NULL; + struct hyb_entries_head *head = NULL; + struct hyb_entries_head *next = NULL; + int nindex; + + node = index_node(index, table); + if (!node) { + hybp(HYB_ERR, + "NULL node, index = %d, hindex = %d, table = %pK\n", + index, hindex, table); + return; + } + head = index_node(hindex, table); + if (!head) { + hybp(HYB_ERR, + "NULL head, index = %d, hindex = %d, table = %pK\n", + index, hindex, table); + return; + } + next = index_node(head->next, table); + if (!next) { + hybp(HYB_ERR, + "NULL next, index = %d, hindex = %d, table = %pK\n", + index, hindex, table); + return; + } + + nindex = head->next; + if (index != hindex) + hyb_lock_with_idx(index, table); + node->prev = hindex; + node->next = nindex; + if (index != hindex) + hyb_unlock_with_idx(index, table); + head->next = index; + if (nindex != hindex) + hyb_lock_with_idx(nindex, table); + next->prev = index; + if (nindex != hindex) + hyb_unlock_with_idx(nindex, table); +} + +void hyb_entries_add_tail_nolock(int index, int hindex, struct hyb_entries_table *table) +{ + struct hyb_entries_head *node = NULL; + struct hyb_entries_head *head = NULL; + struct hyb_entries_head *tail = NULL; + int tindex; + + node = index_node(index, table); + if (!node) { + hybp(HYB_ERR, + "NULL node, index = %d, hindex = %d, table = %pK\n", + index, hindex, table); + return; + } + head = index_node(hindex, table); + if (!head) { + hybp(HYB_ERR, + "NULL head, index = %d, hindex = %d, table = %pK\n", + index, hindex, table); + return; + } + tail = index_node(head->prev, table); + if (!tail) { + hybp(HYB_ERR, + "NULL tail, index = %d, hindex = %d, table = %pK\n", + index, hindex, table); + return; + } + + tindex = head->prev; + if (index != hindex) + hyb_lock_with_idx(index, table); + node->prev = tindex; + node->next = hindex; + if (index != hindex) + hyb_unlock_with_idx(index, table); + head->prev = index; + if (tindex != hindex) + hyb_lock_with_idx(tindex, table); + tail->next = index; + if (tindex != hindex) + hyb_unlock_with_idx(tindex, table); +} + +void hyb_entries_del_nolock(int index, int hindex, struct hyb_entries_table *table) +{ + struct hyb_entries_head *node = NULL; + struct hyb_entries_head *prev = NULL; + struct hyb_entries_head *next = NULL; + int pindex, nindex; + + node = index_node(index, table); + if (!node) { + hybp(HYB_ERR, + "NULL node, index = %d, hindex = %d, table = %pK\n", + index, hindex, table); + return; + } + prev = index_node(node->prev, table); + if (!prev) { + hybp(HYB_ERR, + "NULL prev, index = %d, hindex = %d, table = %pK\n", + index, hindex, table); + return; + } + next = index_node(node->next, table); + if (!next) { + hybp(HYB_ERR, + "NULL next, index = %d, hindex = %d, table = %pK\n", + index, hindex, table); + return; + } + + if (index != hindex) + hyb_lock_with_idx(index, table); + pindex = node->prev; + nindex = node->next; + node->prev = index; + node->next = index; + if (index != hindex) + hyb_unlock_with_idx(index, table); + if (pindex != hindex) + hyb_lock_with_idx(pindex, table); + prev->next = nindex; + if (pindex != hindex) + hyb_unlock_with_idx(pindex, table); + if (nindex != hindex) + hyb_lock_with_idx(nindex, table); + next->prev = pindex; + if (nindex != hindex) + hyb_unlock_with_idx(nindex, table); +} + +void hyb_entries_add(int index, int hindex, struct hyb_entries_table *table) +{ + hyb_lock_with_idx(hindex, table); + hyb_entries_add_nolock(index, hindex, table); + hyb_unlock_with_idx(hindex, table); +} + +void hyb_entries_add_tail(int index, int hindex, struct hyb_entries_table *table) +{ + hyb_lock_with_idx(hindex, table); + hyb_entries_add_tail_nolock(index, hindex, table); + hyb_unlock_with_idx(hindex, table); +} + +void hyb_entries_del(int index, int hindex, struct hyb_entries_table *table) +{ + hyb_lock_with_idx(hindex, table); + hyb_entries_del_nolock(index, hindex, table); + hyb_unlock_with_idx(hindex, table); +} + +unsigned short hyb_entries_fetch_memcgid(int index, struct hyb_entries_table *table) +{ + struct hyb_entries_head *node = index_node(index, table); + int memcgid; + + if (!node) { + hybp(HYB_ERR, "index = %d, table = %pK\n", index, table); + return 0; + } + + hyb_lock_with_idx(index, table); + memcgid = (node->mcg_left << ENTRY_MCG_SHIFT_HALF) | node->mcg_right; + hyb_unlock_with_idx(index, table); + + return memcgid; +} + +void hyb_entries_set_memcgid(int index, struct hyb_entries_table *table, int memcgid) +{ + struct hyb_entries_head *node = index_node(index, table); + + if (!node) { + hybp(HYB_ERR, "index = %d, table = %pK, mcg = %d\n", + index, table, memcgid); + return; + } + + hyb_lock_with_idx(index, table); + node->mcg_left = (u32)memcgid >> ENTRY_MCG_SHIFT_HALF; + node->mcg_right = (u32)memcgid & ((1 << ENTRY_MCG_SHIFT_HALF) - 1); + hyb_unlock_with_idx(index, table); +} + +bool hyb_entries_set_priv(int index, struct hyb_entries_table *table) +{ + struct hyb_entries_head *node = index_node(index, table); + bool ret = false; + + if (!node) { + hybp(HYB_ERR, "index = %d, table = %pK\n", index, table); + return false; + } + hyb_lock_with_idx(index, table); + ret = !test_and_set_bit(ENTRY_DATA_BIT, (unsigned long *)node); + hyb_unlock_with_idx(index, table); + + return ret; +} + +bool hyb_entries_test_priv(int index, struct hyb_entries_table *table) +{ + struct hyb_entries_head *node = index_node(index, table); + bool ret = false; + + if (!node) { + hybp(HYB_ERR, "index = %d, table = %pK\n", index, table); + return false; + } + hyb_lock_with_idx(index, table); + ret = test_bit(ENTRY_DATA_BIT, (unsigned long *)node); + hyb_unlock_with_idx(index, table); + + return ret; +} + +bool hyb_entries_clear_priv(int index, struct hyb_entries_table *table) +{ + struct hyb_entries_head *node = index_node(index, table); + bool ret = false; + + if (!node) { + hybp(HYB_ERR, "index = %d, table = %pK\n", index, table); + return false; + } + + hyb_lock_with_idx(index, table); + ret = test_and_clear_bit(ENTRY_DATA_BIT, (unsigned long *)node); + hyb_unlock_with_idx(index, table); + + return ret; +} + +struct mem_cgroup *find_memcg_by_id(unsigned short memcgid) +{ + struct mem_cgroup *mcg = NULL; + + rcu_read_lock(); + mcg = mem_cgroup_from_id(memcgid); + rcu_read_unlock(); + + return mcg; +} + +static bool frag_info_dec(bool prev_flag, bool next_flag, + struct hybstatus *stat) +{ + if (prev_flag && next_flag) { + atomic64_inc(&stat->frag_cnt); + return false; + } + + if (prev_flag || next_flag) + return false; + + return true; +} + +static bool frag_info_inc(bool prev_flag, bool next_flag, + struct hybstatus *stat) +{ + if (prev_flag && next_flag) { + atomic64_dec(&stat->frag_cnt); + return false; + } + + if (prev_flag || next_flag) + return false; + + return true; +} + +static bool pre_is_conted(struct hyb_info *infos, int eswapid, int memcgid) +{ + int prev; + + if (is_first_index(eswap_index(infos, eswapid), memcgindex(infos, memcgid), + infos->eswap_table)) + return false; + prev = prev_index(eswap_index(infos, eswapid), infos->eswap_table); + + return (prev >= 0) && (eswap_index(infos, eswapid) == prev + 1); +} + +static bool ne_is_conted(struct hyb_info *infos, int eswapid, int memcgid) +{ + int next; + + if (is_last_index(eswap_index(infos, eswapid), memcgindex(infos, memcgid), + infos->eswap_table)) + return false; + next = next_index(eswap_index(infos, eswapid), infos->eswap_table); + + return (next >= 0) && (eswap_index(infos, eswapid) + 1 == next); +} + +static void eswap_frag_info_sub(struct hyb_info *infos, int eswapid) +{ + bool prev_flag = false; + bool next_flag = false; + int memcgid; + struct hybstatus *stat = hybridswap_fetch_stat_obj(); + + if (!stat) { + hybp(HYB_ERR, "NULL stat\n"); + return; + } + + if (!infos->eswap_table) { + hybp(HYB_ERR, "NULL table\n"); + return; + } + if (eswapid < 0 || eswapid >= infos->nr_es) { + hybp(HYB_ERR, "eswap = %d invalid\n", eswapid); + return; + } + + memcgid = hyb_entries_fetch_memcgid(eswap_index(infos, eswapid), infos->eswap_table); + if (memcgid <= 0 || memcgid >= infos->memcg_num) { + hybp(HYB_ERR, "memcgid = %d invalid\n", memcgid); + return; + } + + atomic64_dec(&stat->eswap_cnt); + infos->memcgid_cnt[memcgid]--; + if (infos->memcgid_cnt[memcgid] == 0) { + atomic64_dec(&stat->mcg_cnt); + atomic64_dec(&stat->frag_cnt); + return; + } + + prev_flag = pre_is_conted(infos, eswapid, memcgid); + next_flag = ne_is_conted(infos, eswapid, memcgid); + + if (frag_info_dec(prev_flag, next_flag, stat)) + atomic64_dec(&stat->frag_cnt); +} + +static void eswap_frag_info_add(struct hyb_info *infos, int eswapid) +{ + bool prev_flag = false; + bool next_flag = false; + int memcgid; + struct hybstatus *stat = hybridswap_fetch_stat_obj(); + + if (!stat) { + hybp(HYB_ERR, "NULL stat\n"); + return; + } + + if (!infos->eswap_table) { + hybp(HYB_ERR, "NULL table\n"); + return; + } + if (eswapid < 0 || eswapid >= infos->nr_es) { + hybp(HYB_ERR, "eswap = %d invalid\n", eswapid); + return; + } + + memcgid = hyb_entries_fetch_memcgid(eswap_index(infos, eswapid), infos->eswap_table); + if (memcgid <= 0 || memcgid >= infos->memcg_num) { + hybp(HYB_ERR, "memcgid = %d invalid\n", memcgid); + return; + } + + atomic64_inc(&stat->eswap_cnt); + if (infos->memcgid_cnt[memcgid] == 0) { + infos->memcgid_cnt[memcgid]++; + atomic64_inc(&stat->frag_cnt); + atomic64_inc(&stat->mcg_cnt); + return; + } + infos->memcgid_cnt[memcgid]++; + + prev_flag = pre_is_conted(infos, eswapid, memcgid); + next_flag = ne_is_conted(infos, eswapid, memcgid); + + if (frag_info_inc(prev_flag, next_flag, stat)) + atomic64_inc(&stat->frag_cnt); +} + +static int eswap_bit2id(struct hyb_info *infos, int bit) +{ + if (bit < 0 || bit >= infos->nr_es) { + hybp(HYB_ERR, "bit = %d invalid\n", bit); + return -EINVAL; + } + + return infos->nr_es - bit - 1; +} + +static int eswap_id2bit(struct hyb_info *infos, int id) +{ + if (id < 0 || id >= infos->nr_es) { + hybp(HYB_ERR, "id = %d invalid\n", id); + return -EINVAL; + } + + return infos->nr_es - id - 1; +} + +int obj_index(struct hyb_info *infos, int index) +{ + if (!infos) { + hybp(HYB_ERR, "NULL infos\n"); + return -EINVAL; + } + if (index < 0 || index >= infos->total_objects) { + hybp(HYB_ERR, "index = %d invalid\n", index); + return -EINVAL; + } + + return index; +} + +int eswap_index(struct hyb_info *infos, int index) +{ + if (!infos) { + hybp(HYB_ERR, "NULL infos\n"); + return -EINVAL; + } + if (index < 0 || index >= infos->nr_es) { + hybp(HYB_ERR, "index = %d invalid\n", index); + return -EINVAL; + } + + return index + infos->total_objects; +} + +int memcgindex(struct hyb_info *infos, int index) +{ + if (!infos) { + hybp(HYB_ERR, "NULL infos\n"); + return -EINVAL; + } + if (index <= 0 || index >= infos->memcg_num) { + hybp(HYB_ERR, "index = %d invalid, memcg_num %d\n", index, + infos->memcg_num); + return -EINVAL; + } + + return index + infos->total_objects + infos->nr_es; +} + +static struct hyb_entries_head *fetch_objects_node(int index, void *private) +{ + struct hyb_info *infos = private; + + if (!infos) { + hybp(HYB_ERR, "NULL infos\n"); + return NULL; + } + if (index < 0) { + hybp(HYB_ERR, "index = %d invalid\n", index); + return NULL; + } + if (index < infos->total_objects) + return &infos->lru[index]; + index -= infos->total_objects; + if (index < infos->nr_es) + return &infos->maps[index]; + index -= infos->nr_es; + if (index > 0 && index < infos->memcg_num) { + struct mem_cgroup *mcg = find_memcg_by_id(index); + + if (!mcg) + goto err_out; + return (struct hyb_entries_head *)(&MEMCGRP_ITEM(mcg, swap_sorted_list)); + } +err_out: + hybp(HYB_ERR, "index = %d invalid, mcg is NULL\n", index); + + return NULL; +} + +static void free_obj_list_table(struct hyb_info *infos) +{ + if (!infos) { + hybp(HYB_ERR, "NULL infos\n"); + return; + } + + if (infos->lru) { + vfree(infos->lru); + infos->lru = NULL; + } + if (infos->maps) { + vfree(infos->maps); + infos->maps = NULL; + } + + kfree(infos->objects); + infos->objects = NULL; +} + +static int init_obj_list_table(struct hyb_info *infos) +{ + int i; + + if (!infos) { + hybp(HYB_ERR, "NULL infos\n"); + return -EINVAL; + } + + infos->lru = vzalloc(sizeof(struct hyb_entries_head) * infos->total_objects); + if (!infos->lru) { + hybp(HYB_ERR, "infos->lru alloc failed\n"); + goto err_out; + } + infos->maps = vzalloc(sizeof(struct hyb_entries_head) * infos->nr_es); + if (!infos->maps) { + hybp(HYB_ERR, "infos->maps alloc failed\n"); + goto err_out; + } + infos->objects = alloc_table(fetch_objects_node, infos, GFP_KERNEL); + if (!infos->objects) { + hybp(HYB_ERR, "infos->objects alloc failed\n"); + goto err_out; + } + for (i = 0; i < infos->total_objects; i++) + hyb_entries_init(obj_index(infos, i), infos->objects); + for (i = 0; i < infos->nr_es; i++) + hyb_entries_init(eswap_index(infos, i), infos->objects); + + hybp(HYB_INFO, "hybridswap obj list table init OK.\n"); + return 0; +err_out: + free_obj_list_table(infos); + hybp(HYB_ERR, "hybridswap obj list table init failed.\n"); + + return -ENOMEM; +} + +static struct hyb_entries_head *fetch_eswap_table_node(int index, void *private) +{ + struct hyb_info *infos = private; + + if (!infos) { + hybp(HYB_ERR, "NULL infos\n"); + return NULL; + } + + if (index < infos->total_objects) + goto err_out; + index -= infos->total_objects; + if (index < infos->nr_es) + return &infos->eswap[index]; + index -= infos->nr_es; + if (index > 0 && index < infos->memcg_num) { + struct mem_cgroup *mcg = find_memcg_by_id(index); + + if (!mcg) + return NULL; + return (struct hyb_entries_head *)(&MEMCGRP_ITEM(mcg, eswap_lru)); + } +err_out: + hybp(HYB_ERR, "index = %d invalid\n", index); + + return NULL; +} + +static void free_eswap_list_table(struct hyb_info *infos) +{ + if (!infos) { + hybp(HYB_ERR, "NULL infos\n"); + return; + } + + if (infos->eswap) + vfree(infos->eswap); + + kfree(infos->eswap_table); +} + +static int init_eswap_list_table(struct hyb_info *infos) +{ + int i; + + if (!infos) { + hybp(HYB_ERR, "NULL infos\n"); + return -EINVAL; + } + infos->eswap = vzalloc(sizeof(struct hyb_entries_head) * infos->nr_es); + if (!infos->eswap) + goto err_out; + infos->eswap_table = alloc_table(fetch_eswap_table_node, infos, GFP_KERNEL); + if (!infos->eswap_table) + goto err_out; + for (i = 0; i < infos->nr_es; i++) + hyb_entries_init(eswap_index(infos, i), infos->eswap_table); + hybp(HYB_INFO, "hybridswap eswap list table init OK.\n"); + return 0; +err_out: + free_eswap_list_table(infos); + hybp(HYB_ERR, "hybridswap eswap list table init failed.\n"); + + return -ENOMEM; +} + +void free_hyb_info(struct hyb_info *infos) +{ + if (!infos) { + hybp(HYB_ERR, "NULL infos\n"); + return; + } + + vfree(infos->bitmask); + vfree(infos->eswap_stored_pages); + free_obj_list_table(infos); + free_eswap_list_table(infos); + vfree(infos); +} + +struct hyb_info *alloc_hyb_info(unsigned long ori_size, + unsigned long comp_size) +{ + struct hyb_info *infos = vzalloc(sizeof(struct hyb_info)); + + if (!infos) { + hybp(HYB_ERR, "infos alloc failed\n"); + goto err_out; + } + if (comp_size & (ESWAP_SIZE - 1)) { + hybp(HYB_ERR, "disksize = %ld align invalid (32K align needed)\n", + comp_size); + goto err_out; + } + infos->size = comp_size; + infos->nr_es = comp_size >> ESWAP_SHIFT; + infos->memcg_num = MEM_CGROUP_ID_MAX; + infos->total_objects = ori_size >> PAGE_SHIFT; + infos->bitmask = vzalloc(BITS_TO_LONGS(infos->nr_es) * sizeof(long)); + if (!infos->bitmask) { + hybp(HYB_ERR, "infos->bitmask alloc failed, %lu\n", + BITS_TO_LONGS(infos->nr_es) * sizeof(long)); + goto err_out; + } + infos->eswap_stored_pages = vzalloc(sizeof(atomic_t) * infos->nr_es); + if (!infos->eswap_stored_pages) { + hybp(HYB_ERR, "infos->eswap_stored_pages alloc failed\n"); + goto err_out; + } + if (init_obj_list_table(infos)) { + hybp(HYB_ERR, "init obj list table failed\n"); + goto err_out; + } + if (init_eswap_list_table(infos)) { + hybp(HYB_ERR, "init eswap list table failed\n"); + goto err_out; + } + hybp(HYB_INFO, "infos %p size %lu nr_es %lu memcg_num %lu total_objects %lu\n", + infos, infos->size, infos->nr_es, infos->memcg_num, + infos->total_objects); + hybp(HYB_INFO, "hyb_info init OK.\n"); + return infos; +err_out: + free_hyb_info(infos); + hybp(HYB_ERR, "hyb_info init failed.\n"); + + return NULL; +} + +void hybridswap_check_infos_eswap(struct hyb_info *infos) +{ + int i; + + if (!infos) + return; + + for (i = 0; i < infos->nr_es; i++) { + int cnt = atomic_read(&infos->eswap_stored_pages[i]); + int eswapid = eswap_index(infos, i); + bool data = hyb_entries_test_priv(eswapid, infos->eswap_table); + int memcgid = hyb_entries_fetch_memcgid(eswapid, infos->eswap_table); + + if (cnt < 0 || (cnt > 0 && memcgid == 0)) + hybp(HYB_ERR, "%8d %8d %8d %8d %4d\n", i, cnt, eswapid, + memcgid, data); + } +} + +void hybridswap_free_eswap(struct hyb_info *infos, int eswapid) +{ + if (!infos) { + hybp(HYB_ERR, "NULL infos\n"); + return; + } + if (eswapid < 0 || eswapid >= infos->nr_es) { + hybp(HYB_ERR, "INVALID eswap %d\n", eswapid); + return; + } + hybp(HYB_DEBUG, "free eswap id = %d.\n", eswapid); + + hyb_entries_set_memcgid(eswap_index(infos, eswapid), infos->eswap_table, 0); + if (!test_and_clear_bit(eswap_id2bit(infos, eswapid), infos->bitmask)) { + hybp(HYB_ERR, "bit not set, eswap = %d\n", eswapid); + WARN_ON_ONCE(1); + } + atomic_dec(&infos->stored_exts); +} + +static int alloc_bitmask(unsigned long *bitmask, int max, int last_bit) +{ + int bit; + + if (!bitmask) { + hybp(HYB_ERR, "NULL bitmask.\n"); + return -EINVAL; + } +retry: + bit = find_next_zero_bit(bitmask, max, last_bit); + if (bit == max) { + if (last_bit == 0) { + hybp(HYB_ERR, "alloc bitmask failed.\n"); + return -ENOSPC; + } + last_bit = 0; + goto retry; + } + if (test_and_set_bit(bit, bitmask)) + goto retry; + + return bit; +} + +int hybridswap_alloc_eswap(struct hyb_info *infos, struct mem_cgroup *mcg) +{ + int last_bit; + int bit; + int eswapid; + int memcgid; + + if (!infos) { + hybp(HYB_ERR, "NULL infos\n"); + return -EINVAL; + } + if (!mcg) { + hybp(HYB_ERR, "NULL mcg\n"); + return -EINVAL; + } + + last_bit = atomic_read(&infos->last_alloc_bit); + hybp(HYB_DEBUG, "last_bit = %d.\n", last_bit); + bit = alloc_bitmask(infos->bitmask, infos->nr_es, last_bit); + if (bit < 0) { + hybp(HYB_ERR, "alloc bitmask failed.\n"); + return bit; + } + eswapid = eswap_bit2id(infos, bit); + memcgid = hyb_entries_fetch_memcgid(eswap_index(infos, eswapid), infos->eswap_table); + if (memcgid) { + hybp(HYB_ERR, "already has mcg %d, eswap %d\n", + memcgid, eswapid); + goto err_out; + } + hyb_entries_set_memcgid(eswap_index(infos, eswapid), infos->eswap_table, mcg->id.id); + + atomic_set(&infos->last_alloc_bit, bit); + atomic_inc(&infos->stored_exts); + hybp(HYB_DEBUG, "eswap %d init OK.\n", eswapid); + hybp(HYB_DEBUG, "memcgid = %d, eswap id = %d\n", mcg->id.id, eswapid); + + return eswapid; +err_out: + clear_bit(bit, infos->bitmask); + WARN_ON_ONCE(1); + return -EBUSY; +} + +int fetch_eswap(struct hyb_info *infos, int eswapid) +{ + int memcgid; + + if (!infos) { + hybp(HYB_ERR, "NULL infos\n"); + return -EINVAL; + } + if (eswapid < 0 || eswapid >= infos->nr_es) { + hybp(HYB_ERR, "eswap = %d invalid\n", eswapid); + return -EINVAL; + } + + if (!hyb_entries_clear_priv(eswap_index(infos, eswapid), infos->eswap_table)) + return -EBUSY; + memcgid = hyb_entries_fetch_memcgid(eswap_index(infos, eswapid), infos->eswap_table); + if (memcgid) { + eswap_frag_info_sub(infos, eswapid); + hyb_entries_del(eswap_index(infos, eswapid), memcgindex(infos, memcgid), + infos->eswap_table); + } + hybp(HYB_DEBUG, "eswap id = %d\n", eswapid); + + return eswapid; +} + +void put_eswap(struct hyb_info *infos, int eswapid) +{ + int memcgid; + + if (!infos) { + hybp(HYB_ERR, "NULL infos\n"); + return; + } + if (eswapid < 0 || eswapid >= infos->nr_es) { + hybp(HYB_ERR, "eswap = %d invalid\n", eswapid); + return; + } + + memcgid = hyb_entries_fetch_memcgid(eswap_index(infos, eswapid), infos->eswap_table); + if (memcgid) { + hyb_lock_with_idx(memcgindex(infos, memcgid), infos->eswap_table); + hyb_entries_add_nolock(eswap_index(infos, eswapid), memcgindex(infos, memcgid), + infos->eswap_table); + eswap_frag_info_add(infos, eswapid); + hyb_unlock_with_idx(memcgindex(infos, memcgid), infos->eswap_table); + } + if (!hyb_entries_set_priv(eswap_index(infos, eswapid), infos->eswap_table)) { + hybp(HYB_ERR, "private not set, eswap = %d\n", eswapid); + WARN_ON_ONCE(1); + return; + } + hybp(HYB_DEBUG, "put eswap %d.\n", eswapid); +} + +int fetch_memcg_eswap(struct hyb_info *infos, struct mem_cgroup *mcg) +{ + int memcgid; + int eswapid = -ENOENT; + int index; + + if (!infos) { + hybp(HYB_ERR, "NULL infos\n"); + return -EINVAL; + } + if (!infos->eswap_table) { + hybp(HYB_ERR, "NULL table\n"); + return -EINVAL; + } + if (!mcg) { + hybp(HYB_ERR, "NULL mcg\n"); + return -EINVAL; + } + + memcgid = mcg->id.id; + hyb_lock_with_idx(memcgindex(infos, memcgid), infos->eswap_table); + hyb_entries_for_each_entry(index, memcgindex(infos, memcgid), infos->eswap_table) + if (hyb_entries_clear_priv(index, infos->eswap_table)) { + eswapid = index - infos->total_objects; + break; + } + if (eswapid >= 0 && eswapid < infos->nr_es) { + eswap_frag_info_sub(infos, eswapid); + hyb_entries_del_nolock(index, memcgindex(infos, memcgid), infos->eswap_table); + hybp(HYB_DEBUG, "eswap id = %d\n", eswapid); + } + hyb_unlock_with_idx(memcgindex(infos, memcgid), infos->eswap_table); + + return eswapid; +} + +int fetch_memcg_zram_entry(struct hyb_info *infos, struct mem_cgroup *mcg) +{ + int memcgid, idx; + int index = -ENOENT; + + if (!infos) { + hybp(HYB_ERR, "NULL infos\n"); + return -EINVAL; + } + if (!infos->objects) { + hybp(HYB_ERR, "NULL table\n"); + return -EINVAL; + } + if (!mcg) { + hybp(HYB_ERR, "NULL mcg\n"); + return -EINVAL; + } + + memcgid = mcg->id.id; + hyb_lock_with_idx(memcgindex(infos, memcgid), infos->objects); + hyb_entries_for_each_entry(idx, memcgindex(infos, memcgid), infos->objects) { + index = idx; + break; + } + hyb_unlock_with_idx(memcgindex(infos, memcgid), infos->objects); + + return index; +} + +int fetch_eswap_zram_entry(struct hyb_info *infos, int eswapid) +{ + int index = -ENOENT; + int idx; + + if (!infos) { + hybp(HYB_ERR, "NULL infos\n"); + return -EINVAL; + } + if (!infos->objects) { + hybp(HYB_ERR, "NULL table\n"); + return -EINVAL; + } + if (eswapid < 0 || eswapid >= infos->nr_es) { + hybp(HYB_ERR, "eswap = %d invalid\n", eswapid); + return -EINVAL; + } + + hyb_lock_with_idx(eswap_index(infos, eswapid), infos->objects); + hyb_entries_for_each_entry(idx, eswap_index(infos, eswapid), infos->objects) { + index = idx; + break; + } + hyb_unlock_with_idx(eswap_index(infos, eswapid), infos->objects); + + return index; +} + +void *hybridswap_malloc(size_t size, bool fast, bool nofail) +{ + void *mem = NULL; + + if (likely(fast)) { + mem = kzalloc(size, GFP_ATOMIC); + if (likely(mem || !nofail)) + return mem; + } + + mem = kzalloc(size, GFP_NOIO); + + return mem; +} + +void hybridswap_free(const void *mem) +{ + kfree(mem); +} + +struct page *hybridswap_alloc_page_common(void *data, gfp_t gfp) +{ + struct page *page = NULL; + struct zs_eswap_para *eswap_para = (struct zs_eswap_para *)data; + + if (eswap_para->pool) { + spin_lock(&eswap_para->pool->page_pool_lock); + if (!list_empty(&eswap_para->pool->page_pool_list)) { + page = list_first_entry( + &eswap_para->pool->page_pool_list, + struct page, lru); + list_del(&page->lru); + } + spin_unlock(&eswap_para->pool->page_pool_lock); + } + + if (!page) { + if (eswap_para->fast) { + page = alloc_page(GFP_ATOMIC); + if (likely(page)) + goto out; + } + if (eswap_para->nofail) + page = alloc_page(GFP_NOIO); + else + page = alloc_page(gfp); + } +out: + return page; +} + +unsigned long hybridswap_zsmalloc(struct zs_pool *zs_pool, + size_t size, struct hybridswap_page_pool *pool) +{ + gfp_t gfp = __GFP_DIRECT_RECLAIM | __GFP_KSWAPD_RECLAIM | + __GFP_NOWARN | __GFP_HIGHMEM | __GFP_MOVABLE; + return zs_malloc(zs_pool, size, gfp); +} + +unsigned long zram_zsmalloc(struct zs_pool *zs_pool, size_t size, gfp_t gfp) +{ + return zs_malloc(zs_pool, size, gfp); +} + +struct page *hybridswap_alloc_page(struct hybridswap_page_pool *pool, + gfp_t gfp, bool fast, bool nofail) +{ + struct zs_eswap_para eswap_para; + + eswap_para.pool = pool; + eswap_para.fast = fast; + eswap_para.nofail = nofail; + + return hybridswap_alloc_page_common((void *)&eswap_para, gfp); +} + +void hybridswap_page_recycle(struct page *page, struct hybridswap_page_pool *pool) +{ + if (pool) { + spin_lock(&pool->page_pool_lock); + list_add(&page->lru, &pool->page_pool_list); + spin_unlock(&pool->page_pool_lock); + } else { + __free_page(page); + } +} + +bool hybridswap_out_to_eswap_enable(void) +{ + return !!atomic_read(&global_settings.out_to_eswap_enable); +} + +void hybridswap_set_out_to_eswap_disable(void) +{ + atomic_set(&global_settings.out_to_eswap_enable, false); +} + +void hybridswap_set_out_to_eswap_enable(bool en) +{ + atomic_set(&global_settings.out_to_eswap_enable, en ? 1 : 0); +} + +bool hybridswap_core_enabled(void) +{ + return !!atomic_read(&global_settings.enable); +} + +void hybridswap_set_enable(bool en) +{ + hybridswap_set_out_to_eswap_enable(en); + + if (!hybridswap_core_enabled()) + atomic_set(&global_settings.enable, en ? 1 : 0); +} + +struct hybstatus *hybridswap_fetch_stat_obj(void) +{ + return global_settings.stat; +} + +bool hybridswap_dev_life(void) +{ + return !!atomic_read(&global_settings.dev_life); +} + +void hybridswap_set_dev_life(bool en) +{ + atomic_set(&global_settings.dev_life, en ? 1 : 0); +} + +unsigned long hybridswap_quota_day(void) +{ + return global_settings.quota_day; +} + +void hybridswap_set_quota_day(unsigned long val) +{ + global_settings.quota_day = val; +} + +bool hybridswap_reach_life_protect(void) +{ + struct hybstatus *stat = hybridswap_fetch_stat_obj(); + unsigned long quota = hybridswap_quota_day(); + + if (hybridswap_dev_life()) + quota /= 10; + return atomic64_read(&stat->reclaimin_bytes_daily) > quota; +} + +static void hybridswap_life_protect_ctrl_work(struct work_struct *work) +{ + struct tm tm; + struct timespec64 ts; + struct hybstatus *stat = hybridswap_fetch_stat_obj(); + + ktime_get_real_ts64(&ts); + time64_to_tm(ts.tv_sec - sys_tz.tz_minuteswest * 60, 0, &tm); + + if (tm.tm_hour > 2) + atomic64_set(&stat->reclaimin_bytes_daily, 0); +} + +static void hybridswap_life_protect_ctrl_timer(struct timer_list *t) +{ + schedule_work(&global_settings.lpc_work); + mod_timer(&global_settings.lpc_timer, + jiffies + HYBRIDSWAP_CHECK_GAP * HZ); +} + +void hybridswap_close_bdev(struct block_device *bdev, struct file *backing_dev) +{ + if (bdev) + blkdev_put(bdev, FMODE_READ | FMODE_WRITE | FMODE_EXCL); + + if (backing_dev) + filp_close(backing_dev, NULL); +} + +struct file *hybridswap_open_bdev(const char *file_name) +{ + struct file *backing_dev = NULL; + + backing_dev = filp_open(file_name, O_RDWR|O_LARGEFILE, 0); + if (unlikely(IS_ERR(backing_dev))) { + hybp(HYB_ERR, "open the %s failed! eno = %lld\n", + file_name, PTR_ERR(backing_dev)); + backing_dev = NULL; + return NULL; + } + + if (unlikely(!S_ISBLK(backing_dev->f_mapping->host->i_mode))) { + hybp(HYB_ERR, "%s isn't a blk device\n", file_name); + hybridswap_close_bdev(NULL, backing_dev); + return NULL; + } + + return backing_dev; +} + +int hybridswap_bind(struct zram *zram, const char *file_name) +{ + struct file *backing_dev = NULL; + struct inode *inode = NULL; + unsigned long nr_pages; + struct block_device *bdev = NULL; + int err; + + backing_dev = hybridswap_open_bdev(file_name); + if (unlikely(!backing_dev)) + return -EINVAL; + + inode = backing_dev->f_mapping->host; + bdev = blkdev_get_by_dev(inode->i_rdev, + FMODE_READ | FMODE_WRITE | FMODE_EXCL, zram); + if (IS_ERR(bdev)) { + hybp(HYB_ERR, "%s blkdev_fetch failed!\n", file_name); + err = PTR_ERR(bdev); + bdev = NULL; + goto out; + } + + nr_pages = (unsigned long)i_size_read(inode) >> PAGE_SHIFT; + err = set_blocksize(bdev, PAGE_SIZE); + if (unlikely(err)) { + hybp(HYB_ERR, + "%s set blocksize failed! eno = %d\n", file_name, err); + goto out; + } + + zram->bdev = bdev; + zram->backing_dev = backing_dev; + zram->nr_pages = nr_pages; + return 0; + +out: + hybridswap_close_bdev(bdev, backing_dev); + + return err; +} + +static inline unsigned long fetch_original_used_swap(void) +{ + struct sysinfo val; + + si_swapinfo(&val); + + return val.totalswap - val.freeswap; +} + +void hybstatus_init(struct hybstatus *stat) +{ + int i; + + atomic64_set(&stat->reclaimin_cnt, 0); + atomic64_set(&stat->reclaimin_bytes, 0); + atomic64_set(&stat->reclaimin_real_load, 0); + atomic64_set(&stat->dropped_eswap_size, 0); + atomic64_set(&stat->reclaimin_bytes_daily, 0); + atomic64_set(&stat->reclaimin_pages, 0); + atomic64_set(&stat->reclaimin_infight, 0); + atomic64_set(&stat->batchout_cnt, 0); + atomic64_set(&stat->batchout_bytes, 0); + atomic64_set(&stat->batchout_real_load, 0); + atomic64_set(&stat->batchout_pages, 0); + atomic64_set(&stat->batchout_inflight, 0); + atomic64_set(&stat->fault_cnt, 0); + atomic64_set(&stat->hybridswap_fault_cnt, 0); + atomic64_set(&stat->reout_pages, 0); + atomic64_set(&stat->reout_bytes, 0); + atomic64_set(&stat->zram_stored_pages, 0); + atomic64_set(&stat->zram_stored_size, 0); + atomic64_set(&stat->stored_pages, 0); + atomic64_set(&stat->stored_size, 0); + atomic64_set(&stat->notify_free, 0); + atomic64_set(&stat->frag_cnt, 0); + atomic64_set(&stat->mcg_cnt, 0); + atomic64_set(&stat->eswap_cnt, 0); + atomic64_set(&stat->miss_free, 0); + atomic64_set(&stat->memcgid_clear, 0); + atomic64_set(&stat->skip_track_cnt, 0); + atomic64_set(&stat->null_memcg_skip_track_cnt, 0); + atomic64_set(&stat->used_swap_pages, fetch_original_used_swap()); + atomic64_set(&stat->stored_wm_scale, DEFAULT_STORED_WM_RATIO); + + for (i = 0; i < HYB_CLASS_BUTT; ++i) { + atomic64_set(&stat->io_fail_cnt[i], 0); + atomic64_set(&stat->alloc_fail_cnt[i], 0); + atomic64_set(&stat->lat[i].total_lat, 0); + atomic64_set(&stat->lat[i].max_lat, 0); + } + + stat->record.num = 0; + spin_lock_init(&stat->record.lock); +} + +static bool hybridswap_global_setting_init(struct zram *zram) +{ + if (unlikely(global_settings.stat)) + return false; + + global_settings.zram = zram; + hybridswap_set_enable(false); + global_settings.stat = hybridswap_malloc( + sizeof(struct hybstatus), false, true); + if (unlikely(!global_settings.stat)) { + hybp(HYB_ERR, "global stat allocation failed!\n"); + return false; + } + + hybstatus_init(global_settings.stat); + global_settings.reclaim_wq = alloc_workqueue("hybridswap_reclaim", + WQ_CPU_INTENSIVE, 0); + if (unlikely(!global_settings.reclaim_wq)) { + hybp(HYB_ERR, "reclaim workqueue allocation failed!\n"); + hybridswap_free(global_settings.stat); + global_settings.stat = NULL; + + return false; + } + + global_settings.quota_day = HYBRIDSWAP_QUOTA_DAY; + INIT_WORK(&global_settings.lpc_work, hybridswap_life_protect_ctrl_work); + global_settings.lpc_timer.expires = jiffies + HYBRIDSWAP_CHECK_GAP * HZ; + timer_setup(&global_settings.lpc_timer, hybridswap_life_protect_ctrl_timer, 0); + add_timer(&global_settings.lpc_timer); + + hybp(HYB_DEBUG, "global settings init success\n"); + return true; +} + +void hybridswap_global_setting_deinit(void) +{ + destroy_workqueue(global_settings.reclaim_wq); + hybridswap_free(global_settings.stat); + global_settings.stat = NULL; + global_settings.zram = NULL; + global_settings.reclaim_wq = NULL; +} + +struct workqueue_struct *hybridswap_fetch_reclaim_workqueue(void) +{ + return global_settings.reclaim_wq; +} + +static int hybridswap_core_init(struct zram *zram) +{ + int ret; + + if (loop_device[0] == '\0') { + hybp(HYB_ERR, "please setting loop_device first\n"); + return -EINVAL; + } + + if (!hybridswap_global_setting_init(zram)) + return -EINVAL; + + ret = hybridswap_bind(zram, loop_device); + if (unlikely(ret)) { + hybp(HYB_ERR, "bind storage device failed! %d\n", ret); + hybridswap_global_setting_deinit(); + } + + return 0; +} + +int hybridswap_set_enable_init(bool en) +{ + int ret; + + if (hybridswap_core_enabled() || !en) + return 0; + + if (!global_settings.stat) { + hybp(HYB_ERR, "global_settings.stat is null!\n"); + + return -EINVAL; + } + + ret = hybridswap_manager_init(global_settings.zram); + if (unlikely(ret)) { + hybp(HYB_ERR, "init manager failed! %d\n", ret); + + return -EINVAL; + } + + ret = hyb_io_work_begin(); + if (unlikely(ret)) { + hybp(HYB_ERR, "init schedule failed! %d\n", ret); + hybridswap_manager_deinit(global_settings.zram); + + return -EINVAL; + } + + return 0; +} + +ssize_t hybridswap_core_enable_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t len) +{ + int ret; + unsigned long val; + + ret = kstrtoul(buf, 0, &val); + if (unlikely(ret)) { + hybp(HYB_ERR, "val is error!\n"); + + return -EINVAL; + } + + if (hybridswap_set_enable_init(!!val)) + return -EINVAL; + + hybridswap_set_enable(!!val); + + return len; +} + +ssize_t hybridswap_core_enable_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int len = snprintf(buf, PAGE_SIZE, "hybridswap %s out_to_eswap %s\n", + hybridswap_core_enabled() ? "enable" : "disable", + hybridswap_out_to_eswap_enable() ? "enable" : "disable"); + + return len; +} + +ssize_t hybridswap_loop_device_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t len) +{ + struct zram *zram; + int ret = 0; + + if (len > (DEVICE_NAME_LEN - 1)) { + hybp(HYB_ERR, "buf %s len %d is too long\n", buf, len); + return -EINVAL; + } + + memcpy(loop_device, buf, len); + loop_device[len] = '\0'; + strstrip(loop_device); + + zram = dev_to_zram(dev); + down_write(&zram->init_lock); + if (zram->disksize == 0) { + hybp(HYB_ERR, "disksize is 0\n"); + goto out; + } + + ret = hybridswap_core_init(zram); + if (ret) + hybp(HYB_ERR, "hybridswap_core_init init failed\n"); + +out: + up_write(&zram->init_lock); + return len; +} + +ssize_t hybridswap_loop_device_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int len = 0; + + len = sprintf(buf, "%s\n", loop_device); + + return len; +} + +ssize_t hybridswap_dev_life_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t len) +{ + int ret; + unsigned long val; + + ret = kstrtoul(buf, 0, &val); + if (unlikely(ret)) { + hybp(HYB_ERR, "val is error!\n"); + + return -EINVAL; + } + + hybridswap_set_dev_life(!!val); + + return len; +} + +ssize_t hybridswap_dev_life_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int len = 0; + + len = sprintf(buf, "%s\n", + hybridswap_dev_life() ? "enable" : "disable"); + + return len; +} + +ssize_t hybridswap_quota_day_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t len) +{ + int ret; + unsigned long val; + + ret = kstrtoul(buf, 0, &val); + if (unlikely(ret)) { + hybp(HYB_ERR, "val is error!\n"); + + return -EINVAL; + } + + hybridswap_set_quota_day(val); + + return len; +} + +ssize_t hybridswap_quota_day_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int len = 0; + + len = sprintf(buf, "%llu\n", hybridswap_quota_day()); + + return len; +} + +ssize_t hybridswap_zram_increase_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t len) +{ + char *type_buf = NULL; + unsigned long val; + struct zram *zram = dev_to_zram(dev); + + type_buf = strstrip((char *)buf); + if (kstrtoul(type_buf, 0, &val)) + return -EINVAL; + + zram->increase_nr_pages = (val << 8); + return len; +} + +ssize_t hybridswap_zram_increase_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t size = 0; + struct zram *zram = dev_to_zram(dev); + + size += scnprintf(buf + size, PAGE_SIZE - size, + "%lu\n", zram->increase_nr_pages >> 8); + + return size; +} + +int mem_cgroup_stored_wm_scale_write( + struct cgroup_subsys_state *css, struct cftype *cft, s64 val) +{ + if (val > MAX_RATIO || val < MIN_RATIO) + return -EINVAL; + + if (!global_settings.stat) + return -EINVAL; + + atomic64_set(&global_settings.stat->stored_wm_scale, val); + + return 0; +} + +s64 mem_cgroup_stored_wm_scale_read( + struct cgroup_subsys_state *css, struct cftype *cft) +{ + if (!global_settings.stat) + return -EINVAL; + + return atomic64_read(&global_settings.stat->stored_wm_scale); +} + +int hybridswap_stored_info(unsigned long *total, unsigned long *used) +{ + if (!total || !used) + return -EINVAL; + + if (!global_settings.stat || !global_settings.zram) { + *total = 0; + *used = 0; + return 0; + } + + *used = atomic64_read(&global_settings.stat->eswap_cnt) * ESWAP_PG_CNT; + *total = global_settings.zram->nr_pages; + + return 0; +} + +bool hybridswap_stored_wm_ok(void) +{ + unsigned long scale, stored_pages, total_pages, wm_scale; + int ret; + + if (!hybridswap_core_enabled()) + return false; + + ret = hybridswap_stored_info(&total_pages, &stored_pages); + if (ret) + return false; + + scale = (stored_pages * 100) / (total_pages + 1); + wm_scale = atomic64_read(&global_settings.stat->stored_wm_scale); + + return scale <= wm_scale; +} + +int hybridswap_core_enable(void) +{ + int ret; + + ret = hybridswap_set_enable_init(true); + if (ret) { + hybp(HYB_ERR, "set true failed, ret=%d\n", ret); + return ret; + } + + hybridswap_set_enable(true); + return 0; +} + +void hybridswap_core_disable(void) +{ + (void)hybridswap_set_enable_init(false); + hybridswap_set_enable(false); +} + +static void hybridswap_memcg_iter( + int (*iter)(struct mem_cgroup *, void *), void *data) +{ + struct mem_cgroup *mcg = fetch_next_memcg(NULL); + int ret; + + while (mcg) { + ret = iter(mcg, data); + hybp(HYB_DEBUG, "%pS mcg %d %s %s, ret %d\n", + iter, mcg->id.id, + MEMCGRP_ITEM(mcg, name), + ret ? "failed" : "pass", + ret); + if (ret) { + fetch_next_memcg_break(mcg); + return; + } + mcg = fetch_next_memcg(mcg); + } +} + +void hybridswap_record(struct zram *zram, u32 index, + struct mem_cgroup *memcg) +{ + memcg_hybs_t *hybs; + struct hybstatus *stat; + + if (!hybridswap_core_enabled()) + return; + + if (!memcg || !memcg->id.id) { + stat = hybridswap_fetch_stat_obj(); + if (stat) + atomic64_inc(&stat->null_memcg_skip_track_cnt); + return; + } + + hybs = MEMCGRP_ITEM_DATA(memcg); + if (!hybs) { + hybs = hybridswap_cache_alloc(memcg, false); + if (!hybs) { + stat = hybridswap_fetch_stat_obj(); + if (stat) + atomic64_inc(&stat->skip_track_cnt); + return; + } + } + + if (unlikely(!hybs->zram)) { + spin_lock(&hybs->zram_init_lock); + if (!hybs->zram) + hybridswap_manager_memcg_init(zram, memcg); + spin_unlock(&hybs->zram_init_lock); + } + + hybridswap_swap_sorted_list_add(zram, index, memcg); + +#ifdef CONFIG_HYBRIDSWAP_SWAPD + zram_slot_unlock(zram, index); + if (!zram_watermark_ok()) + wake_all_swapd(); + zram_slot_lock(zram, index); +#endif +} + +void hybridswap_untrack(struct zram *zram, u32 index) +{ + if (!hybridswap_core_enabled()) + return; + + while (zram_test_flag(zram, index, ZRAM_UNDER_WB) || + zram_test_flag(zram, index, ZRAM_BATCHING_OUT)) { + zram_slot_unlock(zram, index); + udelay(50); + zram_slot_lock(zram, index); + } + + hybridswap_swap_sorted_list_del(zram, index); +} + +static unsigned long memcg_reclaim_size(struct mem_cgroup *memcg) +{ + memcg_hybs_t *hybs = MEMCGRP_ITEM_DATA(memcg); + unsigned long zram_size, cur_size, new_size; + + if (!hybs) + return 0; + + zram_size = atomic64_read(&hybs->zram_stored_size); + if (hybs->force_swapout) { + hybs->can_eswaped = zram_size; + return zram_size; + } + + cur_size = atomic64_read(&hybs->hybridswap_stored_size); + new_size = (zram_size + cur_size) * + atomic_read(&hybs->zram2ufs_scale) / 100; + + hybs->can_eswaped = (new_size > cur_size) ? (new_size - cur_size) : 0; + return hybs->can_eswaped; +} + +static int hybridswap_permcg_sz(struct mem_cgroup *memcg, void *data) +{ + unsigned long *out_size = (unsigned long *)data; + + *out_size += memcg_reclaim_size(memcg); + return 0; +} + +static void hybridswap_flush_cb(enum hybridswap_class class, + void *pri, struct hybridswap_io_req *req) +{ + switch (class) { + case HYB_FAULT_OUT: + case HYB_PRE_OUT: + case HYB_BATCH_OUT: + hybridswap_eswap_destroy(pri, class); + break; + case HYB_RECLAIM_IN: + hybridswap_eswap_register(pri, req); + break; + default: + break; + } +} + +static void hybridswap_flush_done(struct hybridswap_entry *ioentry, + int err, struct hybridswap_io_req *req) +{ + struct io_priv *data; + + if (unlikely(!ioentry)) + return; + + data = (struct io_priv *)(ioentry->private); + if (likely(!err)) { + hybridswap_flush_cb(data->class, + ioentry->manager_private, req); +#ifdef CONFIG_HYBRIDSWAP_SWAPD + if (!zram_watermark_ok()) + wake_all_swapd(); +#endif + } else { + hybridswap_eswap_exception(data->class, + ioentry->manager_private); + } + hybridswap_free(ioentry); +} + +static void hybridswap_free_pagepool(struct io_work_arg *iowork) +{ + struct page *free_page = NULL; + + spin_lock(&iowork->data.page_pool.page_pool_lock); + while (!list_empty(&iowork->data.page_pool.page_pool_list)) { + free_page = list_first_entry( + &iowork->data.page_pool.page_pool_list, + struct page, lru); + list_del_init(&free_page->lru); + __free_page(free_page); + } + spin_unlock(&iowork->data.page_pool.page_pool_lock); +} + +static void hybridswap_plug_complete(void *data) +{ + struct io_work_arg *iowork = (struct io_work_arg *)data; + + hybridswap_free_pagepool(iowork); + + hybperf_end(&iowork->record); + + hybridswap_free(iowork); +} + +static void *hybridswap_init_plug(struct zram *zram, + enum hybridswap_class class, + struct io_work_arg *iowork) +{ + struct hybridswap_io io_para; + + io_para.bdev = zram->bdev; + io_para.class = class; + io_para.private = (void *)iowork; + io_para.record = &iowork->record; + INIT_LIST_HEAD(&iowork->data.page_pool.page_pool_list); + spin_lock_init(&iowork->data.page_pool.page_pool_lock); + io_para.done_callback = hybridswap_flush_done; + switch (io_para.class) { + case HYB_RECLAIM_IN: + io_para.complete_notify = hybridswap_plug_complete; + iowork->io_buf.pool = NULL; + break; + case HYB_BATCH_OUT: + case HYB_PRE_OUT: + io_para.complete_notify = hybridswap_plug_complete; + iowork->io_buf.pool = &iowork->data.page_pool; + break; + case HYB_FAULT_OUT: + io_para.complete_notify = NULL; + iowork->io_buf.pool = NULL; + break; + default: + break; + } + iowork->io_buf.zram = zram; + iowork->data.zram = zram; + iowork->data.class = io_para.class; + return hybridswap_plug_start(&io_para); +} + +static void hybridswap_fill_entry(struct hybridswap_entry *ioentry, + struct hybridswap_buffer *io_buf, + void *private) +{ + ioentry->addr = ioentry->eswapid * ESWAP_SECTOR_SIZE; + ioentry->dest_pages = io_buf->dest_pages; + ioentry->pages_sz = ESWAP_PG_CNT; + ioentry->private = private; +} + +static int hybridswap_reclaim_check(struct mem_cgroup *memcg, + unsigned long *require_size) +{ + memcg_hybs_t *hybs = MEMCGRP_ITEM_DATA(memcg); + + if (unlikely(!hybs) || unlikely(!hybs->zram)) + return -EAGAIN; + if (unlikely(hybs->in_swapin)) + return -EAGAIN; + if (!hybs->force_swapout && *require_size < MIN_RECLAIM_ZRAM_SZ) + return -EAGAIN; + + return 0; +} + +static int hybridswap_update_reclaim_sz(unsigned long *require_size, + unsigned long *mcg_reclaimed_sz, + unsigned long reclaim_size) +{ + *mcg_reclaimed_sz += reclaim_size; + + if (*require_size > reclaim_size) + *require_size -= reclaim_size; + else + *require_size = 0; + + return 0; +} + +static void hybstatus_alloc_fail(enum hybridswap_class class, + int err) +{ + struct hybstatus *stat = hybridswap_fetch_stat_obj(); + + if (!stat || (err != -ENOMEM) || (class >= HYB_CLASS_BUTT)) + return; + + atomic64_inc(&stat->alloc_fail_cnt[class]); +} + +static int hybridswap_reclaim_eswap(struct mem_cgroup *memcg, + struct io_work_arg *iowork, + unsigned long *require_size, + unsigned long *mcg_reclaimed_sz, + int *errio) +{ + int ret; + unsigned long reclaim_size; + + hybperfiowrkstart(&iowork->record, HYB_IOENTRY_ALLOC); + iowork->ioentry = hybridswap_malloc( + sizeof(struct hybridswap_entry), false, true); + hybperfiowrkend(&iowork->record, HYB_IOENTRY_ALLOC); + if (unlikely(!iowork->ioentry)) { + hybp(HYB_ERR, "alloc io entry failed!\n"); + *require_size = 0; + *errio = -ENOMEM; + hybstatus_alloc_fail(HYB_RECLAIM_IN, -ENOMEM); + + return *errio; + } + + hybperfiowrkstart(&iowork->record, HYB_FIND_ESWAP); + reclaim_size = hybridswap_eswap_create( + memcg, &iowork->ioentry->eswapid, + &iowork->io_buf, &iowork->ioentry->manager_private); + hybperfiowrkend(&iowork->record, HYB_FIND_ESWAP); + if (unlikely(!reclaim_size)) { + if (iowork->ioentry->eswapid != -ENOENT) + *require_size = 0; + hybridswap_free(iowork->ioentry); + return -EAGAIN; + } + + hybridswap_fill_entry(iowork->ioentry, &iowork->io_buf, + (void *)(&iowork->data)); + + hybperfiowrkstart(&iowork->record, HYB_IO_ESWAP); + ret = hybridswap_write_eswap(iowork->iohandle, iowork->ioentry); + hybperfiowrkend(&iowork->record, HYB_IO_ESWAP); + if (unlikely(ret)) { + hybp(HYB_ERR, "hybridswap write failed! %d\n", ret); + *require_size = 0; + *errio = ret; + hybstatus_alloc_fail(HYB_RECLAIM_IN, ret); + + return *errio; + } + + ret = hybridswap_update_reclaim_sz(require_size, mcg_reclaimed_sz, + reclaim_size); + if (MEMCGRP_ITEM(memcg, force_swapout)) + return 0; + return ret; +} + +static int hybridswap_permcg_reclaim(struct mem_cgroup *memcg, + unsigned long require_size, unsigned long *mcg_reclaimed_sz) +{ + int ret, extcnt; + int errio = 0; + unsigned long require_size_before = 0; + struct io_work_arg *iowork = NULL; + ktime_t start = ktime_get(); + unsigned long long start_ravg_sum = hybridswap_fetch_ravg_sum(); + memcg_hybs_t *hybs = MEMCGRP_ITEM_DATA(memcg); + + ret = hybridswap_reclaim_check(memcg, &require_size); + if (ret) + return ret == -EAGAIN ? 0 : ret; + + iowork = hybridswap_malloc(sizeof(struct io_work_arg), false, true); + if (unlikely(!iowork)) { + hybp(HYB_ERR, "alloc iowork failed!\n"); + hybstatus_alloc_fail(HYB_RECLAIM_IN, -ENOMEM); + + return -ENOMEM; + } + + hybperf_start(&iowork->record, start, start_ravg_sum, + HYB_RECLAIM_IN); + hybperfiowrkstart(&iowork->record, HYB_INIT); + iowork->iohandle = hybridswap_init_plug(hybs->zram, + HYB_RECLAIM_IN, iowork); + hybperfiowrkend(&iowork->record, HYB_INIT); + if (unlikely(!iowork->iohandle)) { + hybp(HYB_ERR, "plug start failed!\n"); + hybperf_end(&iowork->record); + hybridswap_free(iowork); + hybstatus_alloc_fail(HYB_RECLAIM_IN, -ENOMEM); + ret = -EIO; + goto out; + } + + require_size_before = require_size; + while (require_size) { + if (hybridswap_reclaim_eswap(memcg, iowork, + &require_size, mcg_reclaimed_sz, &errio)) + break; + + atomic64_inc(&hybs->hybridswap_outextcnt); + extcnt = atomic_inc_return(&hybs->hybridswap_extcnt); + if (extcnt > atomic_read(&hybs->hybridswap_peakextcnt)) + atomic_set(&hybs->hybridswap_peakextcnt, extcnt); + } + + ret = hybridswap_plug_finish(iowork->iohandle); + if (unlikely(ret)) { + hybp(HYB_ERR, "hybridswap write flush failed! %d\n", ret); + hybstatus_alloc_fail(HYB_RECLAIM_IN, ret); + require_size = 0; + } else { + ret = errio; + } + atomic64_inc(&hybs->hybridswap_outcnt); + +out: + hybp(HYB_INFO, "memcg %s %lu %lu out_to_eswap %lu KB eswap %lu zram %lu %d\n", + hybs->name, require_size_before, require_size, + (require_size_before - require_size) >> 10, + atomic64_read(&hybs->hybridswap_stored_size), + atomic64_read(&hybs->zram_stored_size), ret); + return ret; +} + +static void hybridswap_reclaimin_inc(void) +{ + struct hybstatus *stat; + + stat = hybridswap_fetch_stat_obj(); + if (unlikely(!stat)) + return; + atomic64_inc(&stat->reclaimin_infight); +} + +static void hybridswap_reclaimin_dec(void) +{ + struct hybstatus *stat; + + stat = hybridswap_fetch_stat_obj(); + if (unlikely(!stat)) + return; + atomic64_dec(&stat->reclaimin_infight); +} + +static int hybridswap_permcg_reclaimin(struct mem_cgroup *memcg, + void *data) +{ + struct async_req *rq = (struct async_req *)data; + unsigned long mcg_reclaimed_size = 0, require_size; + int ret; + memcg_hybs_t *hybs; + + hybs = MEMCGRP_ITEM_DATA(memcg); + if (!hybs) + return 0; + + require_size = hybs->can_eswaped * rq->size / rq->out_size; + if (require_size < MIN_RECLAIM_ZRAM_SZ) + return 0; + + if (!mutex_trylock(&hybs->swap_lock)) + return 0; + + ret = hybridswap_permcg_reclaim(memcg, require_size, + &mcg_reclaimed_size); + rq->reclaimined_sz += mcg_reclaimed_size; + mutex_unlock(&hybs->swap_lock); + + hybp(HYB_INFO, "memcg %s mcg_reclaimed_size %lu rq->reclaimined_sz %lu rq->size %lu rq->out_size %lu ret %d\n", + hybs->name, mcg_reclaimed_size, rq->reclaimined_sz, + rq->size, rq->out_size, ret); + + if (!ret && rq->reclaimined_sz >= rq->size) + return -EINVAL; + + return ret; +} + +static void hybridswap_reclaim_work(struct work_struct *work) +{ + struct async_req *rq = container_of(work, struct async_req, work); + int old_nice = task_nice(current); + + set_user_nice(current, rq->nice); + hybridswap_reclaimin_inc(); + hybridswap_memcg_iter(hybridswap_permcg_reclaimin, rq); + hybridswap_reclaimin_dec(); + set_user_nice(current, old_nice); + hybp(HYB_INFO, "SWAPOUT want %lu MB real %lu Mb\n", rq->size >> 20, + rq->reclaimined_sz >> 20); + hybridswap_free(rq); +} + +unsigned long hybridswap_out_to_eswap(unsigned long size) +{ + struct async_req *rq = NULL; + unsigned long out_size = 0; + + if (!hybridswap_core_enabled() || !hybridswap_out_to_eswap_enable() + || hybridswap_reach_life_protect() || !size) + return 0; + + hybridswap_memcg_iter(hybridswap_permcg_sz, &out_size); + if (!out_size) + return 0; + + rq = hybridswap_malloc(sizeof(struct async_req), false, true); + if (unlikely(!rq)) { + hybp(HYB_ERR, "alloc async req fail!\n"); + hybstatus_alloc_fail(HYB_RECLAIM_IN, -ENOMEM); + return 0; + } + + if (out_size < size) + size = out_size; + rq->size = size; + rq->out_size = out_size; + rq->reclaimined_sz = 0; + rq->nice = task_nice(current); + INIT_WORK(&rq->work, hybridswap_reclaim_work); + queue_work(hybridswap_fetch_reclaim_workqueue(), &rq->work); + + return out_size > size ? size : out_size; +} + +static int hybridswap_batches_eswap(struct io_work_arg *iowork, + struct mem_cgroup *mcg, + bool preload, + int *errio) +{ + int ret; + + hybperfiowrkstart(&iowork->record, HYB_IOENTRY_ALLOC); + iowork->ioentry = hybridswap_malloc( + sizeof(struct hybridswap_entry), !preload, preload); + hybperfiowrkend(&iowork->record, HYB_IOENTRY_ALLOC); + if (unlikely(!iowork->ioentry)) { + hybp(HYB_ERR, "alloc io entry failed!\n"); + *errio = -ENOMEM; + hybstatus_alloc_fail(HYB_BATCH_OUT, -ENOMEM); + + return *errio; + } + + hybperfiowrkstart(&iowork->record, HYB_FIND_ESWAP); + iowork->ioentry->eswapid = hybridswap_find_eswap_by_memcg( + mcg, &iowork->io_buf, + &iowork->ioentry->manager_private); + hybperfiowrkend(&iowork->record, HYB_FIND_ESWAP); + if (iowork->ioentry->eswapid < 0) { + hybstatus_alloc_fail(HYB_BATCH_OUT, + iowork->ioentry->eswapid); + hybridswap_free(iowork->ioentry); + return -EAGAIN; + } + + hybridswap_fill_entry(iowork->ioentry, &iowork->io_buf, + (void *)(&iowork->data)); + + hybperfiowrkstart(&iowork->record, HYB_IO_ESWAP); + ret = hybridswap_read_eswap(iowork->iohandle, iowork->ioentry); + hybperfiowrkend(&iowork->record, HYB_IO_ESWAP); + if (unlikely(ret)) { + hybp(HYB_ERR, "hybridswap read failed! %d\n", ret); + hybstatus_alloc_fail(HYB_BATCH_OUT, ret); + *errio = ret; + + return *errio; + } + + return 0; +} + +static int hybridswap_do_batches_init(struct io_work_arg **out_sched, + struct mem_cgroup *mcg, bool preload) +{ + struct io_work_arg *iowork = NULL; + ktime_t start = ktime_get(); + unsigned long long start_ravg_sum = hybridswap_fetch_ravg_sum(); + + iowork = hybridswap_malloc(sizeof(struct io_work_arg), + !preload, preload); + if (unlikely(!iowork)) { + hybp(HYB_ERR, "alloc iowork failed!\n"); + hybstatus_alloc_fail(HYB_BATCH_OUT, -ENOMEM); + + return -ENOMEM; + } + + hybperf_start(&iowork->record, start, start_ravg_sum, + preload ? HYB_PRE_OUT : HYB_BATCH_OUT); + + hybperfiowrkstart(&iowork->record, HYB_INIT); + iowork->iohandle = hybridswap_init_plug(MEMCGRP_ITEM(mcg, zram), + preload ? HYB_PRE_OUT : HYB_BATCH_OUT, + iowork); + hybperfiowrkend(&iowork->record, HYB_INIT); + if (unlikely(!iowork->iohandle)) { + hybp(HYB_ERR, "plug start failed!\n"); + hybperf_end(&iowork->record); + hybridswap_free(iowork); + hybstatus_alloc_fail(HYB_BATCH_OUT, -ENOMEM); + + return -EIO; + } + + *out_sched = iowork; + + return 0; +} + +static int hybridswap_do_batches(struct mem_cgroup *mcg, + unsigned long size, bool preload) +{ + int ret = 0; + int errio = 0; + struct io_work_arg *iowork = NULL; + + if (unlikely(!mcg || !MEMCGRP_ITEM(mcg, zram))) { + hybp(HYB_WARN, "no zram in mcg!\n"); + ret = -EINVAL; + goto out; + } + + ret = hybridswap_do_batches_init(&iowork, mcg, preload); + if (unlikely(ret)) + goto out; + + MEMCGRP_ITEM(mcg, in_swapin) = true; + while (size) { + if (hybridswap_batches_eswap(iowork, mcg, preload, &errio)) + break; + size -= ESWAP_SIZE; + } + + ret = hybridswap_plug_finish(iowork->iohandle); + if (unlikely(ret)) { + hybp(HYB_ERR, "hybridswap read flush failed! %d\n", ret); + hybstatus_alloc_fail(HYB_BATCH_OUT, ret); + } else { + ret = errio; + } + + if (atomic64_read(&MEMCGRP_ITEM(mcg, hybridswap_stored_size)) && + hybridswap_loglevel() >= HYB_INFO) + hybridswap_check_infos_eswap((MEMCGRP_ITEM(mcg, zram)->infos)); + + atomic64_inc(&MEMCGRP_ITEM(mcg, hybridswap_incnt)); + MEMCGRP_ITEM(mcg, in_swapin) = false; +out: + return ret; +} + +static void hybridswap_batchout_inc(void) +{ + struct hybstatus *stat; + + stat = hybridswap_fetch_stat_obj(); + if (unlikely(!stat)) + return; + atomic64_inc(&stat->batchout_inflight); +} + +static void hybridswap_batchout_dec(void) +{ + struct hybstatus *stat; + + stat = hybridswap_fetch_stat_obj(); + if (unlikely(!stat)) + return; + atomic64_dec(&stat->batchout_inflight); +} + +int hybridswap_batches(struct mem_cgroup *mcg, + unsigned long size, bool preload) +{ + int ret; + + if (!hybridswap_core_enabled()) + return 0; + + hybridswap_batchout_inc(); + ret = hybridswap_do_batches(mcg, size, preload); + hybridswap_batchout_dec(); + + return ret; +} + +static void hybridswap_fault_stat(struct zram *zram, u32 index) +{ + struct mem_cgroup *mcg = NULL; + struct hybstatus *stat = hybridswap_fetch_stat_obj(); + + if (unlikely(!stat)) + return; + + atomic64_inc(&stat->fault_cnt); + + mcg = hybridswap_zram_fetch_mcg(zram, index); + if (mcg) + atomic64_inc(&MEMCGRP_ITEM(mcg, hybridswap_allfaultcnt)); +} + +static void hybridswap_fault2_stat(struct zram *zram, u32 index) +{ + struct mem_cgroup *mcg = NULL; + struct hybstatus *stat = hybridswap_fetch_stat_obj(); + + if (unlikely(!stat)) + return; + + atomic64_inc(&stat->hybridswap_fault_cnt); + + mcg = hybridswap_zram_fetch_mcg(zram, index); + if (mcg) + atomic64_inc(&MEMCGRP_ITEM(mcg, hybridswap_faultcnt)); +} + +static bool hybridswap_page_fault_check(struct zram *zram, + u32 index, unsigned long *zentry) +{ + if (!hybridswap_core_enabled()) + return false; + + hybridswap_fault_stat(zram, index); + + if (!zram_test_flag(zram, index, ZRAM_WB)) + return false; + + zram_set_flag(zram, index, ZRAM_BATCHING_OUT); + *zentry = zram_get_handle(zram, index); + zram_slot_unlock(zram, index); + return true; +} + +static int hybridswap_page_fault_fetch_eswap(struct zram *zram, + struct io_work_arg *iowork, + unsigned long zentry, + u32 index) +{ + int wait_cycle = 0; + + iowork->io_buf.zram = zram; + iowork->data.zram = zram; + iowork->io_buf.pool = NULL; + hybperfiowrkstart(&iowork->record, HYB_FIND_ESWAP); + iowork->ioentry->eswapid = hybridswap_find_eswap_by_index(zentry, + &iowork->io_buf, &iowork->ioentry->manager_private); + hybperfiowrkend(&iowork->record, HYB_FIND_ESWAP); + if (unlikely(iowork->ioentry->eswapid == -EBUSY)) { + while (1) { + zram_slot_lock(zram, index); + if (!zram_test_flag(zram, index, ZRAM_WB)) { + zram_slot_unlock(zram, index); + hybridswap_free(iowork->ioentry); +#ifdef CONFIG_HYBRIDSWAP_SWAPD + if (wait_cycle >= 1000) + atomic_long_dec(&page_fault_pause); +#endif + return -EAGAIN; + } + zram_slot_unlock(zram, index); + + hybperfiowrkstart(&iowork->record, + HYB_FIND_ESWAP); + iowork->ioentry->eswapid = + hybridswap_find_eswap_by_index(zentry, + &iowork->io_buf, + &iowork->ioentry->manager_private); + hybperfiowrkend(&iowork->record, + HYB_FIND_ESWAP); + if (likely(iowork->ioentry->eswapid != -EBUSY)) + break; + + if (wait_cycle < 100) + udelay(50); + else + usleep_range(50, 100); + wait_cycle++; +#ifdef CONFIG_HYBRIDSWAP_SWAPD + if (wait_cycle == 1000) { + atomic_long_inc(&page_fault_pause); + atomic_long_inc(&page_fault_pause_cnt); + } +#endif + } + } +#ifdef CONFIG_HYBRIDSWAP_SWAPD + if (wait_cycle >= 1000) + atomic_long_dec(&page_fault_pause); +#endif + if (iowork->ioentry->eswapid < 0) { + hybstatus_alloc_fail(HYB_FAULT_OUT, + iowork->ioentry->eswapid); + + return iowork->ioentry->eswapid; + } + hybridswap_fault2_stat(zram, index); + hybridswap_fill_entry(iowork->ioentry, &iowork->io_buf, + (void *)(&iowork->data)); + return 0; +} + +static int hybridswap_page_fault_exit_check(struct zram *zram, + u32 index, int ret) +{ + zram_slot_lock(zram, index); + if (likely(!ret)) { + if (unlikely(zram_test_flag(zram, index, ZRAM_WB))) { + hybp(HYB_ERR, "still in WB status!\n"); + ret = -EIO; + } + } + zram_clear_flag(zram, index, ZRAM_BATCHING_OUT); + + return ret; +} + +static int hybridswap_page_fault_eswap(struct zram *zram, u32 index, + struct io_work_arg *iowork, unsigned long zentry) +{ + int ret; + + hybperfiowrkstart(&iowork->record, HYB_IOENTRY_ALLOC); + iowork->ioentry = hybridswap_malloc(sizeof(struct hybridswap_entry), + true, true); + hybperfiowrkend(&iowork->record, HYB_IOENTRY_ALLOC); + if (unlikely(!iowork->ioentry)) { + hybp(HYB_ERR, "alloc io entry failed!\n"); + hybstatus_alloc_fail(HYB_FAULT_OUT, -ENOMEM); + hybridswap_fail_record(HYB_FAULT_OUT_ENTRY_ALLOC_FAIL, + index, 0, iowork->record.task_comm); + return -ENOMEM; + } + + ret = hybridswap_page_fault_fetch_eswap(zram, iowork, zentry, index); + if (ret) + return ret; + + hybperfiowrkstart(&iowork->record, HYB_IO_ESWAP); + ret = hybridswap_read_eswap(iowork->iohandle, iowork->ioentry); + hybperfiowrkend(&iowork->record, HYB_IO_ESWAP); + if (unlikely(ret)) { + hybp(HYB_ERR, "hybridswap read failed! %d\n", ret); + hybstatus_alloc_fail(HYB_FAULT_OUT, ret); + } + + return ret; +} + +int hybridswap_page_fault(struct zram *zram, u32 index) +{ + int ret = 0; + int errio; + struct io_work_arg iowork; + unsigned long zentry; + ktime_t start = ktime_get(); + unsigned long long start_ravg_sum = hybridswap_fetch_ravg_sum(); + + if (!hybridswap_page_fault_check(zram, index, &zentry)) + return ret; + + memset(&iowork.record, 0, sizeof(struct hybridswap_key_point_record)); + hybperf_start(&iowork.record, start, start_ravg_sum, + HYB_FAULT_OUT); + + hybperfiowrkstart(&iowork.record, HYB_INIT); + iowork.iohandle = hybridswap_init_plug(zram, + HYB_FAULT_OUT, &iowork); + hybperfiowrkend(&iowork.record, HYB_INIT); + if (unlikely(!iowork.iohandle)) { + hybp(HYB_ERR, "plug start failed!\n"); + hybstatus_alloc_fail(HYB_FAULT_OUT, -ENOMEM); + ret = -EIO; + hybridswap_fail_record(HYB_FAULT_OUT_INIT_FAIL, + index, 0, iowork.record.task_comm); + + goto out; + } + + errio = hybridswap_page_fault_eswap(zram, index, &iowork, zentry); + ret = hybridswap_plug_finish(iowork.iohandle); + if (unlikely(ret)) { + hybp(HYB_ERR, "hybridswap flush failed! %d\n", ret); + hybstatus_alloc_fail(HYB_FAULT_OUT, ret); + } else { + ret = (errio != -EAGAIN) ? errio : 0; + } +out: + hybperfiowrkstart(&iowork.record, HYB_ZRAM_LOCK); + ret = hybridswap_page_fault_exit_check(zram, index, ret); + hybperfiowrkend(&iowork.record, HYB_ZRAM_LOCK); + hybperf_end(&iowork.record); + + return ret; +} + +bool hybridswap_delete(struct zram *zram, u32 index) +{ + if (!hybridswap_core_enabled()) + return true; + + if (zram_test_flag(zram, index, ZRAM_UNDER_WB) + || zram_test_flag(zram, index, ZRAM_BATCHING_OUT)) { + struct hybstatus *stat = hybridswap_fetch_stat_obj(); + + if (stat) + atomic64_inc(&stat->miss_free); + return false; + } + + if (!zram_test_flag(zram, index, ZRAM_WB)) + return true; + + hybridswap_eswap_objs_del(zram, index); + + return true; +} + +void hybridswap_mem_cgroup_deinit(struct mem_cgroup *memcg) +{ + if (!hybridswap_core_enabled()) + return; + + hybridswap_manager_memcg_deinit(memcg); +} + +void hybridswap_force_reclaim(struct mem_cgroup *mcg) +{ + unsigned long mcg_reclaimed_size = 0, require_size; + memcg_hybs_t *hybs; + + if (!hybridswap_core_enabled() || !hybridswap_out_to_eswap_enable() + || hybridswap_reach_life_protect()) + return; + + if (!mcg) + return; + + hybs = MEMCGRP_ITEM_DATA(mcg); + if (!hybs || !hybs->zram) + return; + + mutex_lock(&hybs->swap_lock); + require_size = atomic64_read(&hybs->zram_stored_size); + hybs->force_swapout = true; + hybridswap_permcg_reclaim(mcg, require_size, &mcg_reclaimed_size); + hybs->force_swapout = false; + mutex_unlock(&hybs->swap_lock); +} + +void mem_cgroup_id_remove_hook(void *data, struct mem_cgroup *memcg) +{ + if (!memcg->android_oem_data1) + return; + + hybridswap_mem_cgroup_deinit(memcg); + hybp(HYB_DEBUG, "hybridswap remove mcg id = %d\n", memcg->id.id); +} diff --git a/drivers/block/zram/hybridswap/hybridswap_internal.h b/drivers/block/zram/hybridswap/hybridswap_internal.h new file mode 100644 index 000000000000..526f9f49c9e7 --- /dev/null +++ b/drivers/block/zram/hybridswap/hybridswap_internal.h @@ -0,0 +1,553 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2020-2022 Oplus. All rights reserved. + */ + +#ifndef HYBRIDSWAP_INTERNAL_H +#define HYBRIDSWAP_INTERNAL_H + +#include +#include +#include +#include +#include + +#define ESWAP_SHIFT 15 +#define ESWAP_SIZE (1UL << ESWAP_SHIFT) +#define ESWAP_PG_CNT (ESWAP_SIZE >> PAGE_SHIFT) +#define ESWAP_SECTOR_SIZE (ESWAP_PG_CNT << 3) +#define ESWAP_MAX_OBJ_CNT (30 * ESWAP_PG_CNT) +#define ESWAP_MASK (~(ESWAP_SIZE - 1)) +#define ESWAP_ALIGN_UP(size) ((size + ESWAP_SIZE - 1) & ESWAP_MASK) + +#define MAX_FAIL_RECORD_NUM 4 +#define MAX_APP_GRADE 600 + +#define HYBRIDSWAP_QUOTA_DAY 0x280000000 /* 10G bytes */ +#define HYBRIDSWAP_CHECK_GAP 86400 /* 24 hour */ +#define MEM_CGROUP_NAME_MAX_LEN 32 + +#define MAX_RATIO 100 +#define MIN_RATIO 0 + +enum { + HYB_ERR = 0, + HYB_WARN, + HYB_INFO, + HYB_DEBUG, + HYB_MAX +}; + +void hybridswap_loglevel_set(int level); +int hybridswap_loglevel(void); + +#define DUMP_STACK_ON_ERR 0 +#define pt(l, f, ...) pr_err("[%s]<%d:%s>:"f, #l, __LINE__, __func__, ##__VA_ARGS__) +static inline void pr_none(void) {} +#define hybp(l, f, ...) do {\ + (l <= hybridswap_loglevel()) ? pt(l, f, ##__VA_ARGS__) : pr_none();\ + if (DUMP_STACK_ON_ERR && l == HYB_ERR) dump_stack();\ +} while (0) + +enum hybridswap_class { + HYB_RECLAIM_IN = 0, + HYB_FAULT_OUT, + HYB_BATCH_OUT, + HYB_PRE_OUT, + HYB_CLASS_BUTT +}; + +enum hybridswap_key_point { + HYB_START = 0, + HYB_INIT, + HYB_IOENTRY_ALLOC, + HYB_FIND_ESWAP, + HYB_IO_ESWAP, + HYB_SEGMENT_ALLOC, + HYB_BIO_ALLOC, + HYB_SUBMIT_BIO, + HYB_END_IO, + HYB_SCHED_WORK, + HYB_END_WORK, + HYB_CALL_BACK, + HYB_WAKE_UP, + HYB_ZRAM_LOCK, + HYB_DONE, + HYB_KYE_POINT_BUTT +}; + +enum hybridswap_mcg_member { + MCG_ZRAM_STORED_SZ = 0, + MCG_ZRAM_STORED_PG_SZ, + MCG_DISK_STORED_SZ, + MCG_DISK_STORED_PG_SZ, + MCG_ANON_FAULT_CNT, + MCG_DISK_FAULT_CNT, + MCG_ESWAPOUT_CNT, + MCG_ESWAPOUT_SZ, + MCG_ESWAPIN_CNT, + MCG_ESWAPIN_SZ, + MCG_DISK_SPACE, + MCG_DISK_SPACE_PEAK, +}; + +enum hybridswap_fail_point { + HYB_FAULT_OUT_INIT_FAIL = 0, + HYB_FAULT_OUT_ENTRY_ALLOC_FAIL, + HYB_FAULT_OUT_IO_ENTRY_PARA_FAIL, + HYB_FAULT_OUT_SEGMENT_ALLOC_FAIL, + HYB_FAULT_OUT_BIO_ALLOC_FAIL, + HYB_FAULT_OUT_BIO_ADD_FAIL, + HYB_FAULT_OUT_IO_FAIL, + HYBRIDSWAP_FAIL_POINT_BUTT +}; + +struct hybridswap_fail_record { + unsigned char task_comm[TASK_COMM_LEN]; + enum hybridswap_fail_point point; + ktime_t time; + u32 index; + int eswapid; +}; + +struct hybridswap_fail_record_info { + int num; + spinlock_t lock; + struct hybridswap_fail_record record[MAX_FAIL_RECORD_NUM]; +}; + +struct hybridswap_key_point_info { + unsigned int record_cnt; + unsigned int end_cnt; + ktime_t first_time; + ktime_t last_time; + s64 proc_total_time; + s64 proc_max_time; + unsigned long long last_ravg_sum; + unsigned long long proc_ravg_sum; + spinlock_t time_lock; +}; + +struct hybridswap_key_point_record { + struct timer_list lat_monitor; + unsigned long warn_level; + int page_cnt; + int segment_cnt; + int nice; + bool timeout_flag; + unsigned char task_comm[TASK_COMM_LEN]; + struct task_struct *task; + enum hybridswap_class class; + struct hybridswap_key_point_info key_point[HYB_KYE_POINT_BUTT]; +}; + +struct hybridswapiowrkstat { + atomic64_t total_lat; + atomic64_t max_lat; + atomic64_t timeout_cnt; +}; + +struct hybridswap_fault_timeout_cnt{ + atomic64_t timeout_100ms_cnt; + atomic64_t timeout_500ms_cnt; +}; + +struct hybstatus { + atomic64_t reclaimin_cnt; + atomic64_t reclaimin_bytes; + atomic64_t reclaimin_real_load; + atomic64_t reclaimin_bytes_daily; + atomic64_t reclaimin_pages; + atomic64_t reclaimin_infight; + atomic64_t batchout_cnt; + atomic64_t batchout_bytes; + atomic64_t batchout_real_load; + atomic64_t batchout_pages; + atomic64_t batchout_inflight; + atomic64_t fault_cnt; + atomic64_t hybridswap_fault_cnt; + atomic64_t reout_pages; + atomic64_t reout_bytes; + atomic64_t zram_stored_pages; + atomic64_t zram_stored_size; + atomic64_t stored_pages; + atomic64_t stored_size; + atomic64_t notify_free; + atomic64_t frag_cnt; + atomic64_t mcg_cnt; + atomic64_t eswap_cnt; + atomic64_t miss_free; + atomic64_t memcgid_clear; + atomic64_t skip_track_cnt; + atomic64_t used_swap_pages; + atomic64_t null_memcg_skip_track_cnt; + atomic64_t stored_wm_scale; + atomic64_t dropped_eswap_size; + atomic64_t io_fail_cnt[HYB_CLASS_BUTT]; + atomic64_t alloc_fail_cnt[HYB_CLASS_BUTT]; + struct hybridswapiowrkstat lat[HYB_CLASS_BUTT]; + struct hybridswap_fault_timeout_cnt fault_stat[2]; /* 0:bg 1:fg */ + struct hybridswap_fail_record_info record; +}; + +struct hybridswap_page_pool { + struct list_head page_pool_list; + spinlock_t page_pool_lock; +}; + +struct io_eswapent { + int eswapid; + struct zram *zram; + struct mem_cgroup *mcg; + struct page *pages[ESWAP_PG_CNT]; + u32 index[ESWAP_MAX_OBJ_CNT]; + int cnt; + int real_load; + + struct hybridswap_page_pool *pool; +}; + +struct hybridswap_buffer { + struct zram *zram; + struct hybridswap_page_pool *pool; + struct page **dest_pages; +}; + +struct hybridswap_entry { + int eswapid; + sector_t addr; + struct page **dest_pages; + int pages_sz; + struct list_head list; + void *private; + void *manager_private; +}; + +struct hybridswap_io_req; +struct hybridswap_io { + struct block_device *bdev; + enum hybridswap_class class; + void (*done_callback)(struct hybridswap_entry *, int, struct hybridswap_io_req *); + void (*complete_notify)(void *); + void *private; + struct hybridswap_key_point_record *record; +}; + +struct hybridswap_io_req { + struct hybridswap_io io_para; + struct kref refcount; + struct mutex refmutex; + struct wait_queue_head io_wait; + atomic_t eswap_doing; + struct completion io_end_flag; + struct hyb_sgm *segment; + bool limit_doing_flag; + bool wait_io_finish_flag; + int page_cnt; + int segment_cnt; + int nice; + atomic64_t real_load; +}; + +/* Change hybridswap_event_item, you should change swapd_text togather*/ +enum hybridswap_event_item { +#ifdef CONFIG_HYBRIDSWAP_SWAPD + SWAPD_WAKEUP, + SWAPD_REFAULT, + SWAPD_MEMCG_RATIO_SKIP, + SWAPD_MEMCG_REFAULT_SKIP, + SWAPD_SHRINK_ANON, + SWAPD_SWAPOUT, + SWAPD_SKIP_SWAPOUT, + SWAPD_EMPTY_ROUND, + SWAPD_OVER_MIN_BUFFER_SKIP_TIMES, + SWAPD_EMPTY_ROUND_SKIP_TIMES, + SWAPD_SNAPSHOT_TIMES, + SWAPD_SKIP_SHRINK_OF_WINDOW, + SWAPD_MANUAL_PAUSE, +#ifdef CONFIG_OPLUS_JANK + SWAPD_CPU_BUSY_SKIP_TIMES, + SWAPD_CPU_BUSY_BREAK_TIMES, +#endif +#endif +#ifdef CONFIG_HYBRIDSWAP_ASYNC_COMPRESS + AKCOMPRESSD_WAKEUP, +#endif + NR_EVENT_ITEMS +}; + +struct swapd_event_state { + unsigned long event[NR_EVENT_ITEMS]; +}; + +#ifdef CONFIG_HYBRIDSWAP_ASYNC_COMPRESS +struct cgroup_cache_page { + spinlock_t lock; + struct list_head head; + unsigned int cnt; + int id; + char compressing; + char dead; +}; +#endif + +typedef struct mem_cgroup_hybridswap { +#ifdef CONFIG_HYBRIDSWAP + atomic64_t ufs2zram_scale; + atomic_t zram2ufs_scale; + atomic64_t app_grade; + atomic64_t app_uid; + struct list_head grade_node; + char name[MEM_CGROUP_NAME_MAX_LEN]; + struct zram *zram; + struct mem_cgroup *memcg; + refcount_t usage; +#endif +#ifdef CONFIG_HYBRIDSWAP_SWAPD + atomic_t mem2zram_scale; + atomic_t pagefault_level; + unsigned long long reclaimed_pagefault; + long long can_reclaimed; +#endif +#ifdef CONFIG_HYBRIDSWAP_CORE + unsigned long swap_sorted_list; + unsigned long eswap_lru; + struct list_head link_list; + spinlock_t zram_init_lock; + long long can_eswaped; + + atomic64_t zram_stored_size; + atomic64_t zram_page_size; + unsigned long zram_watermark; + + atomic_t hybridswap_extcnt; + atomic_t hybridswap_peakextcnt; + + atomic64_t hybridswap_stored_pages; + atomic64_t hybridswap_stored_size; + atomic64_t hybridswap_eswap_notify_free; + + atomic64_t hybridswap_outcnt; + atomic64_t hybridswap_incnt; + atomic64_t hybridswap_allfaultcnt; + atomic64_t hybridswap_faultcnt; + + atomic64_t hybridswap_outextcnt; + atomic64_t hybridswap_inextcnt; + + struct mutex swap_lock; + bool in_swapin; + bool force_swapout; +#endif +#ifdef CONFIG_HYBRIDSWAP_ASYNC_COMPRESS + struct cgroup_cache_page cache; +#endif +}memcg_hybs_t; + +#define MEMCGRP_ITEM_DATA(memcg) ((memcg_hybs_t *)(memcg)->android_oem_data1) +#define MEMCGRP_ITEM(memcg, item) (MEMCGRP_ITEM_DATA(memcg)->item) + +extern void __put_memcg_cache(memcg_hybs_t *hybs); + +static inline memcg_hybs_t *fetch_memcg_cache(memcg_hybs_t *hybs) +{ + refcount_inc(&hybs->usage); + return hybs; +} + +static inline void put_memcg_cache(memcg_hybs_t *hybs) +{ + if (refcount_dec_and_test(&hybs->usage)) + __put_memcg_cache(hybs); +} + +DECLARE_PER_CPU(struct swapd_event_state, swapd_event_states); +extern struct mutex reclaim_para_lock; + +static inline void __count_swapd_event(enum hybridswap_event_item item) +{ + raw_cpu_inc(swapd_event_states.event[item]); +} + +static inline void count_swapd_event(enum hybridswap_event_item item) +{ + this_cpu_inc(swapd_event_states.event[item]); +} + +static inline void __count_swapd_events(enum hybridswap_event_item item, long delta) +{ + raw_cpu_add(swapd_event_states.event[item], delta); +} + +static inline void count_swapd_events(enum hybridswap_event_item item, long delta) +{ + this_cpu_add(swapd_event_states.event[item], delta); +} + +void *hybridswap_malloc(size_t size, bool fast, bool nofail); +void hybridswap_free(const void *mem); +unsigned long hybridswap_zsmalloc(struct zs_pool *zs_pool, + size_t size, struct hybridswap_page_pool *pool); +struct page *hybridswap_alloc_page( + struct hybridswap_page_pool *pool, gfp_t gfp, + bool fast, bool nofail); +void hybridswap_page_recycle(struct page *page, + struct hybridswap_page_pool *pool); +struct hybstatus *hybridswap_fetch_stat_obj(void); +int hybridswap_manager_init(struct zram *zram); +void hybridswap_manager_memcg_init(struct zram *zram, + struct mem_cgroup *memcg); +void hybridswap_manager_memcg_deinit(struct mem_cgroup *mcg); +void hybridswap_swap_sorted_list_add(struct zram *zram, u32 index, + struct mem_cgroup *memcg); +void hybridswap_swap_sorted_list_del(struct zram *zram, u32 index); +unsigned long hybridswap_eswap_create(struct mem_cgroup *memcg, + int *eswapid, + struct hybridswap_buffer *dest_buf, + void **private); +void hybridswap_eswap_register(void *private, struct hybridswap_io_req *req); +void hybridswap_eswap_objs_del(struct zram *zram, u32 index); +int hybridswap_find_eswap_by_index( + unsigned long eswpentry, struct hybridswap_buffer *buf, void **private); +int hybridswap_find_eswap_by_memcg( + struct mem_cgroup *mcg, + struct hybridswap_buffer *dest_buf, void **private); +void hybridswap_eswap_destroy(void *private, enum hybridswap_class class); +void hybridswap_eswap_exception(enum hybridswap_class class, + void *private); +void hybridswap_manager_deinit(struct zram *zram); +struct mem_cgroup *hybridswap_zram_fetch_mcg(struct zram *zram, u32 index); +int hyb_io_work_begin(void); +void *hybridswap_plug_start(struct hybridswap_io *io_para); +int hybridswap_read_eswap(void *iohandle, + struct hybridswap_entry *ioentry); +int hybridswap_write_eswap(void *iohandle, + struct hybridswap_entry *ioentry); + +int hybridswap_plug_finish(void *iohandle); + +void hybperf_start( + struct hybridswap_key_point_record *record, + ktime_t stsrt, unsigned long long start_ravg_sum, + enum hybridswap_class class); + +void hybperf_end(struct hybridswap_key_point_record *record); + +void hybperfiowrkstart( + struct hybridswap_key_point_record *record, + enum hybridswap_key_point type); + +void hybperfiowrkend( + struct hybridswap_key_point_record *record, + enum hybridswap_key_point type); + +void hybperfiowrkpoint( + struct hybridswap_key_point_record *record, + enum hybridswap_key_point type); + +void hybperf_async_perf( + struct hybridswap_key_point_record *record, + enum hybridswap_key_point type, ktime_t start, + unsigned long long start_ravg_sum); + +void hybperf_io_stat( + struct hybridswap_key_point_record *record, int page_cnt, + int segment_cnt); + +static inline unsigned long long hybridswap_fetch_ravg_sum(void) +{ + return 0; +} + +void hybridswap_fail_record(enum hybridswap_fail_point point, + u32 index, int eswapid, unsigned char *task_comm); +bool hybridswap_reach_life_protect(void); +struct workqueue_struct *hybridswap_fetch_reclaim_workqueue(void); +extern struct mem_cgroup *fetch_next_memcg(struct mem_cgroup *prev); +extern void fetch_next_memcg_break(struct mem_cgroup *prev); +extern memcg_hybs_t *hybridswap_cache_alloc(struct mem_cgroup *memcg, bool atomic); +extern void memcg_app_grade_resort(void); +extern unsigned long memcg_anon_pages(struct mem_cgroup *memcg); + +#ifdef CONFIG_HYBRIDSWAP_CORE +extern bool hybridswap_core_enabled(void); +extern bool hybridswap_out_to_eswap_enable(void); +extern void hybridswap_mem_cgroup_deinit(struct mem_cgroup *memcg); +extern unsigned long hybridswap_out_to_eswap(unsigned long size); +extern int hybridswap_batches(struct mem_cgroup *mcg, + unsigned long size, bool preload); +extern unsigned long zram_zsmalloc(struct zs_pool *zs_pool, + size_t size, gfp_t gfp); +extern struct task_struct *fetch_task_from_proc(struct inode *inode); +extern unsigned long long hybridswap_fetch_zram_pagefault(void); +extern bool hybridswap_reclaim_work_running(void); +extern void hybridswap_force_reclaim(struct mem_cgroup *mcg); +extern bool hybridswap_stored_wm_ok(void); +extern void mem_cgroup_id_remove_hook(void *data, struct mem_cgroup *memcg); +extern int mem_cgroup_stored_wm_scale_write( + struct cgroup_subsys_state *css, struct cftype *cft, s64 val); +extern s64 mem_cgroup_stored_wm_scale_read( + struct cgroup_subsys_state *css, struct cftype *cft); +extern bool hybridswap_delete(struct zram *zram, u32 index); +extern int hybridswap_stored_info(unsigned long *total, unsigned long *used); + +extern unsigned long long hybridswap_read_mcg_stats( + struct mem_cgroup *mcg, enum hybridswap_mcg_member mcg_member); +extern int hybridswap_core_enable(void); +extern void hybridswap_core_disable(void); +extern int hybridswap_psi_show(struct seq_file *m, void *v); +#else +static inline unsigned long long hybridswap_read_mcg_stats( + struct mem_cgroup *mcg, enum hybridswap_mcg_member mcg_member) +{ + return 0; +} + +static inline unsigned long long hybridswap_fetch_zram_pagefault(void) +{ + return 0; +} + +static inline bool hybridswap_reclaim_work_running(void) +{ + return false; +} + +static inline bool hybridswap_core_enabled(void) { return false; } +static inline bool hybridswap_out_to_eswap_enable(void) { return false; } +#endif + +#ifdef CONFIG_HYBRIDSWAP_SWAPD +extern atomic_long_t page_fault_pause; +extern atomic_long_t page_fault_pause_cnt; +extern struct cftype mem_cgroup_swapd_legacy_files[]; +extern bool zram_watermark_ok(void); +extern void wake_all_swapd(void); +extern void alloc_pages_slowpath_hook(void *data, gfp_t gfp_mask, + unsigned int order, unsigned long delta); +extern void rmqueue_hook(void *data, struct zone *preferred_zone, + struct zone *zone, unsigned int order, gfp_t gfp_flags, + unsigned int alloc_flags, int migratetype); +extern void __init swapd_pre_init(void); +extern void swapd_pre_deinit(void); +extern void update_swapd_mcg_setup(struct mem_cgroup *memcg); +extern bool free_zram_is_ok(void); +extern unsigned long fetch_nr_zram_total(void); +extern int swapd_init(struct zram *zram); +extern void swapd_exit(void); +extern bool hybridswap_swapd_enabled(void); +#else +static inline bool hybridswap_swapd_enabled(void) { return false; } +#endif + +#ifdef CONFIG_HYBRIDSWAP_ASYNC_COMPRESS +extern spinlock_t cached_idr_lock; +extern struct idr cached_idr; + +extern void __init akcompressd_pre_init(void); +extern void __exit akcompressd_pre_deinit(void); +extern int create_akcompressd_task(struct zram *zram); +extern void clear_page_memcg(struct cgroup_cache_page *cache); +#endif + +#endif /* end of HYBRIDSWAP_INTERNAL_H */ diff --git a/drivers/block/zram/hybridswap/hybridswap_main.c b/drivers/block/zram/hybridswap/hybridswap_main.c new file mode 100644 index 000000000000..88d84bd023ee --- /dev/null +++ b/drivers/block/zram/hybridswap/hybridswap_main.c @@ -0,0 +1,1029 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2020-2022 Oplus. All rights reserved. + */ + +#define pr_fmt(fmt) "[HYBRIDSWAP]" fmt + +#include +#include +#include +#include +#include +#include + +#include "../zram_drv.h" +#include "../zram_drv_internal.h" +#include "hybridswap_internal.h" +#include "hybridswap.h" + +static const char *swapd_text[NR_EVENT_ITEMS] = { +#ifdef CONFIG_HYBRIDSWAP_SWAPD + "swapd_wakeup", + "swapd_hit_pagefaults", + "swapd_memcg_scale_skip", + "swapd_memcg_pagefault_skip", + "swapd_shrink_anon", + "swapd_swapout", + "swapd_skip_swapout", + "swapd_nothing_ignore", + "swapd_over_min_buffer_skip_times", + "swapd_nothing_ignore_skip_times", + "swapd_snapshot_times", + "swapd_skip_shrink_of_window", + "swapd_manual_pause", +#ifdef CONFIG_OPLUS_JANK + "swapd_cpu_busy_skip_times", + "swapd_cpu_busy_break_times", +#endif +#endif +#ifdef CONFIG_HYBRIDSWAP_ASYNC_COMPRESS + "akcompressd_running", +#endif +}; + +enum scan_balance { + SCAN_EQUAL, + SCAN_FRACT, + SCAN_ANON, + SCAN_FILE, +}; + +static int log_level = HYB_MAX; +static struct kmem_cache *hybridswap_cache; +static struct list_head grade_head; +static DEFINE_SPINLOCK(grade_list_lock); +static DEFINE_MUTEX(hybridswap_enable_lock); +static bool hybridswap_enabled = false; + +DEFINE_MUTEX(reclaim_para_lock); +DEFINE_PER_CPU(struct swapd_event_state, swapd_event_states); + +extern unsigned long try_to_free_mem_cgroup_pages(struct mem_cgroup *memcg, + unsigned long nr_pages, + gfp_t gfp_mask, + bool may_swap); + +void hybridswap_loglevel_set(int level) +{ + log_level = level; +} + +int hybridswap_loglevel(void) +{ + return log_level; +} + +void __put_memcg_cache(memcg_hybs_t *hybs) +{ +#ifdef CONFIG_HYBRIDSWAP_ASYNC_COMPRESS + if (hybs->cache.id > 0) { + spin_lock(&cached_idr_lock); + idr_replace(&cached_idr, NULL, hybs->cache.id); + idr_remove(&cached_idr, hybs->cache.id); + spin_unlock(&cached_idr_lock); + } + + spin_lock(&hybs->cache.lock); + if (hybs->cache.dead != 1) + BUG(); + spin_unlock(&hybs->cache.lock); +#endif + kmem_cache_free(hybridswap_cache, (void *)hybs); +} + +static inline void sum_hybridswap_vm_events(unsigned long *ret) +{ + int cpu; + int i; + + memset(ret, 0, NR_EVENT_ITEMS * sizeof(unsigned long)); + + for_each_online_cpu(cpu) { + struct swapd_event_state *this = + &per_cpu(swapd_event_states, cpu); + + for (i = 0; i < NR_EVENT_ITEMS; i++) + ret[i] += this->event[i]; + } +} + +static inline void all_hybridswap_vm_events(unsigned long *ret) +{ + get_online_cpus(); + sum_hybridswap_vm_events(ret); + put_online_cpus(); +} + +ssize_t hybridswap_vmstat_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned long *vm_buf = NULL; + int len = 0; + int i = 0; + + vm_buf = kzalloc(sizeof(struct swapd_event_state), GFP_KERNEL); + if (!vm_buf) + return -ENOMEM; + all_hybridswap_vm_events(vm_buf); + +#ifdef CONFIG_HYBRIDSWAP_SWAPD + len += snprintf(buf + len, PAGE_SIZE - len, "%-32s %12lu\n", + "page_fault_pause", atomic_long_read(&page_fault_pause)); + len += snprintf(buf + len, PAGE_SIZE - len, "%-32s %12lu\n", + "page_fault_pause_cnt", atomic_long_read(&page_fault_pause_cnt)); +#endif + + for (;i < NR_EVENT_ITEMS; i++) { + len += snprintf(buf + len, PAGE_SIZE - len, "%-32s %12lu\n", + swapd_text[i], vm_buf[i]); + if (len == PAGE_SIZE) + break; + } + kfree(vm_buf); + + return len; +} + +ssize_t hybridswap_loglevel_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t len) +{ + char *type_buf = NULL; + unsigned long val; + + type_buf = strstrip((char *)buf); + if (kstrtoul(type_buf, 0, &val)) + return -EINVAL; + + if (val >= HYB_MAX) { + hybp(HYB_ERR, "val %lu is not valid\n", val); + return -EINVAL; + } + hybridswap_loglevel_set((int)val); + + return len; +} + +ssize_t hybridswap_loglevel_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t size = 0; + + size += scnprintf(buf + size, PAGE_SIZE - size, + "Hybridswap log level: %d\n", hybridswap_loglevel()); + + return size; +} + +/* Make sure the memcg is not NULL in caller */ +memcg_hybs_t *hybridswap_cache_alloc(struct mem_cgroup *memcg, bool atomic) +{ + memcg_hybs_t *hybs; + u64 ret; + gfp_t flags = GFP_KERNEL; + + if (memcg->android_oem_data1) + BUG(); + + if (atomic) + flags &= ~__GFP_DIRECT_RECLAIM; + + hybs = (memcg_hybs_t *)kmem_cache_zalloc(hybridswap_cache, flags); + if (!hybs) + return NULL; + +#ifdef CONFIG_HYBRIDSWAP_ASYNC_COMPRESS + spin_lock_init(&hybs->cache.lock); + INIT_LIST_HEAD(&hybs->cache.head); + hybs->cache.cnt = 0; + hybs->cache.compressing = 0; + hybs->cache.dead = 0; + spin_lock(&cached_idr_lock); + hybs->cache.id = idr_alloc(&cached_idr, NULL, 1, MEM_CGROUP_ID_MAX, + GFP_KERNEL); + if (hybs->cache.id < 0) { + spin_unlock(&cached_idr_lock); + kmem_cache_free(hybridswap_cache, (void*)hybs); + return NULL; + } + idr_replace(&cached_idr, &hybs->cache, hybs->cache.id); + spin_unlock(&cached_idr_lock); +#endif + INIT_LIST_HEAD(&hybs->grade_node); +#ifdef CONFIG_HYBRIDSWAP_CORE + spin_lock_init(&hybs->zram_init_lock); +#endif + atomic64_set(&hybs->app_grade, 300); + atomic64_set(&hybs->ufs2zram_scale, 100); +#ifdef CONFIG_HYBRIDSWAP_SWAPD + atomic_set(&hybs->mem2zram_scale, 80); + atomic_set(&hybs->zram2ufs_scale, 50); + atomic_set(&hybs->pagefault_level, 50); +#endif + hybs->memcg = memcg; + refcount_set(&hybs->usage, 1); + + ret = atomic64_cmpxchg((atomic64_t *)&memcg->android_oem_data1, 0, (u64)hybs); + if (ret != 0) { +#ifdef CONFIG_HYBRIDSWAP_ASYNC_COMPRESS + hybs->cache.dead = 1; +#endif + put_memcg_cache(hybs); + return (memcg_hybs_t *)ret; + } + + return hybs; +} + +#ifdef CONFIG_HYBRIDSWAP_SWAPD +static void tune_scan_type_hook(void *data, char *scan_balance) +{ + /*hybrid swapd,scan anon only*/ + if (current_is_swapd()) { + *scan_balance = SCAN_ANON; + return; + } + +#ifdef CONFIG_HYBRIDSWAP_CORE + if (unlikely(!hybridswap_core_enabled())) + return; + + /*real zram full, scan file only*/ + if (!free_zram_is_ok()) { + *scan_balance = SCAN_FILE; + return; + } +#endif +} +#endif + +static void mem_cgroup_alloc_hook(void *data, struct mem_cgroup *memcg) +{ + if (memcg->android_oem_data1) + BUG(); + + hybridswap_cache_alloc(memcg, true); +} + +static void mem_cgroup_free_hook(void *data, struct mem_cgroup *memcg) +{ + memcg_hybs_t *hybs; + + if (!memcg->android_oem_data1) + return; + + hybs = (memcg_hybs_t *)memcg->android_oem_data1; + memcg->android_oem_data1 = 0; +#ifdef CONFIG_HYBRIDSWAP_ASYNC_COMPRESS + clear_page_memcg(&hybs->cache); +#endif + put_memcg_cache(hybs); +} + +void memcg_app_grade_update(struct mem_cgroup *tarfetch) +{ + struct list_head *pos = NULL; + unsigned long flags; + +#ifdef CONFIG_HYBRIDSWAP_SWAPD + update_swapd_mcg_setup(tarfetch); +#endif + spin_lock_irqsave(&grade_list_lock, flags); + list_for_each(pos, &grade_head) { + memcg_hybs_t *hybs = list_entry(pos, memcg_hybs_t, grade_node); + if (atomic64_read(&hybs->app_grade) < + atomic64_read(&MEMCGRP_ITEM(tarfetch, app_grade))) + break; + } + list_move_tail(&MEMCGRP_ITEM(tarfetch, grade_node), pos); + spin_unlock_irqrestore(&grade_list_lock, flags); +} + +static void mem_cgroup_css_online_hook(void *data, + struct cgroup_subsys_state *css, struct mem_cgroup *memcg) +{ + if (memcg->android_oem_data1) + memcg_app_grade_update(memcg); + + css_get(css); +} + +static void mem_cgroup_css_offline_hook(void *data, + struct cgroup_subsys_state *css, struct mem_cgroup *memcg) +{ + unsigned long flags; + + if (memcg->android_oem_data1) { + spin_lock_irqsave(&grade_list_lock, flags); + list_del_init(&MEMCGRP_ITEM(memcg, grade_node)); + spin_unlock_irqrestore(&grade_list_lock, flags); + } + + css_put(css); +} + +#define REGISTER_HOOK(name) do {\ + rc = register_trace_android_vh_##name(name##_hook, NULL);\ + if (rc) {\ + hybp(HYB_ERR, "%s:%d register hook %s failed", __FILE__, __LINE__, #name);\ + goto err_out_##name;\ + }\ +} while (0) + +#define UNREGISTER_HOOK(name) do {\ + unregister_trace_android_vh_##name(name##_hook, NULL);\ +} while (0) + +#define ERROR_OUT(name) err_out_##name + +static int register_all_hooks(void) +{ + int rc; + + /* mem_cgroup_alloc_hook */ + REGISTER_HOOK(mem_cgroup_alloc); + /* mem_cgroup_free_hook */ + REGISTER_HOOK(mem_cgroup_free); + /* mem_cgroup_css_online_hook */ + REGISTER_HOOK(mem_cgroup_css_online); + /* mem_cgroup_css_offline_hook */ + REGISTER_HOOK(mem_cgroup_css_offline); +#ifdef CONFIG_HYBRIDSWAP_SWAPD + /* rmqueue_hook */ + REGISTER_HOOK(rmqueue); + /* tune_scan_type_hook */ + REGISTER_HOOK(tune_scan_type); +#endif +#ifdef CONFIG_HYBRIDSWAP_CORE + /* mem_cgroup_id_remove_hook */ + REGISTER_HOOK(mem_cgroup_id_remove); +#endif + return 0; + +#ifdef CONFIG_HYBRIDSWAP_CORE + UNREGISTER_HOOK(mem_cgroup_id_remove); +ERROR_OUT(mem_cgroup_id_remove): +#endif +#ifdef CONFIG_HYBRIDSWAP_SWAPD + UNREGISTER_HOOK(tune_scan_type); +ERROR_OUT(tune_scan_type): + UNREGISTER_HOOK(rmqueue); +ERROR_OUT(rmqueue): +#endif + UNREGISTER_HOOK(mem_cgroup_css_offline); +ERROR_OUT(mem_cgroup_css_offline): + UNREGISTER_HOOK(mem_cgroup_css_online); +ERROR_OUT(mem_cgroup_css_online): + UNREGISTER_HOOK(mem_cgroup_free); +ERROR_OUT(mem_cgroup_free): + UNREGISTER_HOOK(mem_cgroup_alloc); +ERROR_OUT(mem_cgroup_alloc): + return rc; +} + +static void unregister_all_hook(void) +{ + UNREGISTER_HOOK(mem_cgroup_alloc); + UNREGISTER_HOOK(mem_cgroup_free); + UNREGISTER_HOOK(mem_cgroup_css_offline); + UNREGISTER_HOOK(mem_cgroup_css_online); +#ifdef CONFIG_HYBRIDSWAP_CORE + UNREGISTER_HOOK(mem_cgroup_id_remove); +#endif +#ifdef CONFIG_HYBRIDSWAP_SWAPD + UNREGISTER_HOOK(rmqueue); + UNREGISTER_HOOK(tune_scan_type); +#endif +} + +unsigned long memcg_anon_pages(struct mem_cgroup *memcg) +{ +#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0) + struct lruvec *lruvec = NULL; + struct mem_cgroup_per_node *mz = NULL; +#endif + if (!memcg) + return 0; + +#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0) + mz = mem_cgroup_nodeinfo(memcg, 0); + if (!mz) { + fetch_next_memcg_break(memcg); + return 0; + } + + lruvec = &mz->lruvec; + if (!lruvec) { + fetch_next_memcg_break(memcg); + return 0; + } + +#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 4, 0) + return (mem_cgroup_get_lru_size(lruvec, LRU_ACTIVE_ANON) + + mem_cgroup_get_lru_size(lruvec, LRU_INACTIVE_ANON)); +#else + return (lruvec_page_state(lruvec, NR_ACTIVE_ANON) + + lruvec_page_state(lruvec, NR_INACTIVE_ANON)); +#endif +#else + return (memcg_page_state_local(memcg, NR_ACTIVE_ANON) + + memcg_page_state_local(memcg, NR_INACTIVE_ANON)); +#endif +} + +static unsigned long memcg_inactive_anon_pages(struct mem_cgroup *memcg) +{ +#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0) + struct lruvec *lruvec = NULL; + struct mem_cgroup_per_node *mz = NULL; +#endif + + if (!memcg) + return 0; + +#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0) + mz = mem_cgroup_nodeinfo(memcg, 0); + if (!mz) { + fetch_next_memcg_break(memcg); + return 0; + } + + lruvec = &mz->lruvec; + if (!lruvec) { + fetch_next_memcg_break(memcg); + return 0; + } + +#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 4, 0) + return mem_cgroup_get_lru_size(lruvec, LRU_INACTIVE_ANON); +#else + return lruvec_page_state(lruvec, NR_INACTIVE_ANON); +#endif +#else + return memcg_page_state_local(memcg, NR_INACTIVE_ANON); +#endif +} + +static ssize_t mem_cgroup_force_shrink_anon(struct kernfs_open_file *of, + char *buf, size_t nbytes, loff_t off) +{ + struct mem_cgroup *memcg; + unsigned long nr_need_reclaim, reclaim_total, nr_reclaimed; + int ret; + + buf = strstrip(buf); + ret = kstrtoul(buf, 0, &reclaim_total); + if (unlikely(ret)) { + hybp(HYB_ERR, "reclaim_total %s value is error!\n", buf); + return -EINVAL; + } + + memcg = mem_cgroup_from_css(of_css(of)); + + if (reclaim_total) + nr_need_reclaim = memcg_anon_pages(memcg); + else + nr_need_reclaim = memcg_inactive_anon_pages(memcg); + + nr_reclaimed = try_to_free_mem_cgroup_pages(memcg, nr_need_reclaim, + GFP_KERNEL, true); + + return nbytes; +} + +static int memcg_total_info_per_app_show(struct seq_file *m, void *v) +{ + struct mem_cgroup *memcg = NULL; + unsigned long anon_size; + unsigned long zram_compress_size; + unsigned long eswap_compress_size; + unsigned long zram_page_size; + unsigned long eswap_page_size; + + seq_printf(m, "%-8s %-8s %-8s %-8s %-8s %s \n", + "anon", "zram_c", "zram_p", "eswap_c", "eswap_p", + "memcg_n"); + while ((memcg = fetch_next_memcg(memcg))) { + if (!MEMCGRP_ITEM_DATA(memcg)) + continue; + + anon_size = memcg_anon_pages(memcg); + zram_compress_size = hybridswap_read_mcg_stats(memcg, + MCG_ZRAM_STORED_SZ); + eswap_compress_size = hybridswap_read_mcg_stats(memcg, + MCG_DISK_STORED_SZ); + zram_page_size = hybridswap_read_mcg_stats(memcg, + MCG_ZRAM_STORED_PG_SZ); + eswap_page_size = hybridswap_read_mcg_stats(memcg, + MCG_DISK_STORED_PG_SZ); + + anon_size *= PAGE_SIZE / SZ_1K; + zram_compress_size /= SZ_1K; + eswap_compress_size /= SZ_1K; + zram_page_size *= PAGE_SIZE / SZ_1K; + eswap_page_size *= PAGE_SIZE / SZ_1K; + + seq_printf(m, "%-8lu %-8lu %-8lu %-8lu %-8lu %s \n", + anon_size, zram_compress_size, zram_page_size, + eswap_compress_size, eswap_page_size, + MEMCGRP_ITEM(memcg, name)); + } + + return 0; +} + +static int memcg_swap_stat_show(struct seq_file *m, void *v) +{ + struct mem_cgroup *memcg = NULL; + unsigned long eswap_out_cnt; + unsigned long eswap_out_size; + unsigned long eswap_in_size; + unsigned long eswap_in_cnt; + unsigned long page_fault_cnt; + unsigned long cur_eswap_size; + unsigned long max_eswap_size; + unsigned long zram_compress_size, zram_page_size; + unsigned long eswap_compress_size, eswap_page_size; + + memcg = mem_cgroup_from_css(seq_css(m)); + + zram_compress_size = hybridswap_read_mcg_stats(memcg, MCG_ZRAM_STORED_SZ); + zram_page_size = hybridswap_read_mcg_stats(memcg, MCG_ZRAM_STORED_PG_SZ); + eswap_compress_size = hybridswap_read_mcg_stats(memcg, MCG_DISK_STORED_SZ); + eswap_page_size = hybridswap_read_mcg_stats(memcg, MCG_DISK_STORED_PG_SZ); + + eswap_out_cnt = hybridswap_read_mcg_stats(memcg, MCG_ESWAPOUT_CNT); + eswap_out_size = hybridswap_read_mcg_stats(memcg, MCG_ESWAPOUT_SZ); + eswap_in_size = hybridswap_read_mcg_stats(memcg, MCG_ESWAPIN_SZ); + eswap_in_cnt = hybridswap_read_mcg_stats(memcg, MCG_ESWAPIN_CNT); + page_fault_cnt = hybridswap_read_mcg_stats(memcg, MCG_DISK_FAULT_CNT); + cur_eswap_size = hybridswap_read_mcg_stats(memcg, MCG_DISK_SPACE); + max_eswap_size = hybridswap_read_mcg_stats(memcg, MCG_DISK_SPACE_PEAK); + + seq_printf(m, "%-32s %12lu KB\n", "zramCompressedSize:", + zram_compress_size / SZ_1K); + seq_printf(m, "%-32s %12lu KB\n", "zramOrignalSize:", + zram_page_size << (PAGE_SHIFT - 10)); + seq_printf(m, "%-32s %12lu KB\n", "eswapCompressedSize:", + eswap_compress_size / SZ_1K); + seq_printf(m, "%-32s %12lu KB\n", "eswapOrignalSize:", + eswap_page_size << (PAGE_SHIFT - 10)); + seq_printf(m, "%-32s %12lu \n", "eswapOutTotal:", eswap_out_cnt); + seq_printf(m, "%-32s %12lu KB\n", "eswapOutSize:", eswap_out_size / SZ_1K); + seq_printf(m, "%-32s %12lu\n", "eswapInTotal:", eswap_in_cnt); + seq_printf(m, "%-32s %12lu KB\n", "eswapInSize:", eswap_in_size / SZ_1K); + seq_printf(m, "%-32s %12lu\n", "pageInTotal:", page_fault_cnt); + seq_printf(m, "%-32s %12lu KB\n", "eswapSizeCur:", cur_eswap_size / SZ_1K); + seq_printf(m, "%-32s %12lu KB\n", "eswapSizeMax:", max_eswap_size / SZ_1K); + + return 0; +} + +static ssize_t mem_cgroup_name_write(struct kernfs_open_file *of, char *buf, + size_t nbytes, loff_t off) +{ + struct mem_cgroup *memcg = mem_cgroup_from_css(of_css(of)); + memcg_hybs_t *hybp = MEMCGRP_ITEM_DATA(memcg); + int len, w_len; + + if (!hybp) + return -EINVAL; + + buf = strstrip(buf); + len = strlen(buf) + 1; + if (len > MEM_CGROUP_NAME_MAX_LEN) + len = MEM_CGROUP_NAME_MAX_LEN; + + w_len = snprintf(hybp->name, len, "%s", buf); + if (w_len > len) + hybp->name[len - 1] = '\0'; + + return nbytes; +} + +static int mem_cgroup_name_show(struct seq_file *m, void *v) +{ + struct mem_cgroup *memcg = mem_cgroup_from_css(seq_css(m)); + + if (!MEMCGRP_ITEM_DATA(memcg)) + return -EPERM; + + seq_printf(m, "%s\n", MEMCGRP_ITEM(memcg, name)); + + return 0; +} + +static int mem_cgroup_app_grade_write(struct cgroup_subsys_state *css, + struct cftype *cft, s64 val) +{ + struct mem_cgroup *memcg; + memcg_hybs_t *hybs; + + if (val > MAX_APP_GRADE || val < 0) + return -EINVAL; + + memcg = mem_cgroup_from_css(css); + hybs = MEMCGRP_ITEM_DATA(memcg); + if (!hybs) { + hybs = hybridswap_cache_alloc(memcg, false); + if (!hybs) + return -EINVAL; + } + + if (atomic64_read(&MEMCGRP_ITEM(memcg, app_grade)) != val) + atomic64_set(&MEMCGRP_ITEM(memcg, app_grade), val); + memcg_app_grade_update(memcg); + + return 0; +} + +static s64 mem_cgroup_app_grade_read(struct cgroup_subsys_state *css, + struct cftype *cft) +{ + struct mem_cgroup *memcg = mem_cgroup_from_css(css); + + if (!MEMCGRP_ITEM_DATA(memcg)) + return -EPERM; + + return atomic64_read(&MEMCGRP_ITEM(memcg, app_grade)); +} + +int mem_cgroup_app_uid_write(struct cgroup_subsys_state *css, + struct cftype *cft, s64 val) +{ + struct mem_cgroup *memcg; + memcg_hybs_t *hybs; + + if (val < 0) + return -EINVAL; + + memcg = mem_cgroup_from_css(css); + hybs = MEMCGRP_ITEM_DATA(memcg); + if (!hybs) { + return -EINVAL; + } + + if (atomic64_read(&MEMCGRP_ITEM(memcg, app_uid)) != val) + atomic64_set(&MEMCGRP_ITEM(memcg, app_uid), val); + + return 0; +} + +static s64 mem_cgroup_app_uid_read(struct cgroup_subsys_state *css, struct cftype *cft) +{ + struct mem_cgroup *memcg = mem_cgroup_from_css(css); + + if (!MEMCGRP_ITEM_DATA(memcg)) + return -EPERM; + + return atomic64_read(&MEMCGRP_ITEM(memcg, app_uid)); +} + +static int mem_cgroup_ufs2zram_scale_write(struct cgroup_subsys_state *css, + struct cftype *cft, s64 val) +{ + struct mem_cgroup *memcg = mem_cgroup_from_css(css); + + if (!MEMCGRP_ITEM_DATA(memcg)) + return -EPERM; + + if (val > MAX_RATIO || val < MIN_RATIO) + return -EINVAL; + + atomic64_set(&MEMCGRP_ITEM(memcg, ufs2zram_scale), val); + + return 0; +} + +static s64 mem_cgroup_ufs2zram_scale_read(struct cgroup_subsys_state *css, + struct cftype *cft) +{ + struct mem_cgroup *memcg = mem_cgroup_from_css(css); + + if (!MEMCGRP_ITEM_DATA(memcg)) + return -EPERM; + + return atomic64_read(&MEMCGRP_ITEM(memcg, ufs2zram_scale)); +} + +static int mem_cgroup_force_swapin_write(struct cgroup_subsys_state *css, + struct cftype *cft, s64 val) +{ + struct mem_cgroup *memcg = mem_cgroup_from_css(css); + memcg_hybs_t *hybs; + unsigned long size = 0; + const unsigned int scale = 100; + + hybs = MEMCGRP_ITEM_DATA(memcg); + if (!hybs) + return -EPERM; + +#ifdef CONFIG_HYBRIDSWAP_CORE + size = atomic64_read(&hybs->hybridswap_stored_size); +#endif + size = atomic64_read(&hybs->ufs2zram_scale) * size / scale; + size = ESWAP_ALIGN_UP(size); + +#ifdef CONFIG_HYBRIDSWAP_CORE + hybridswap_batches(memcg, size, val ? true : false); +#endif + + return 0; +} + +static int mem_cgroup_force_swapout_write(struct cgroup_subsys_state *css, + struct cftype *cft, s64 val) +{ +#ifdef CONFIG_HYBRIDSWAP_CORE + hybridswap_force_reclaim(mem_cgroup_from_css(css)); +#endif + return 0; +} + +struct mem_cgroup *fetch_next_memcg(struct mem_cgroup *prev) +{ + memcg_hybs_t *hybs = NULL; + struct mem_cgroup *memcg = NULL; + struct list_head *pos = NULL; + unsigned long flags; + bool prev_got = true; + + spin_lock_irqsave(&grade_list_lock, flags); +find_again: + if (unlikely(!prev)) + pos = &grade_head; + else + pos = &MEMCGRP_ITEM(prev, grade_node); + + if (list_empty(pos)) /* deleted node */ + goto unlock; + + if (pos->next == &grade_head) + goto unlock; + + hybs = list_entry(pos->next, struct mem_cgroup_hybridswap, grade_node); + memcg = hybs->memcg; + if (unlikely(!memcg)) + goto unlock; + + if (!css_tryget(&memcg->css)) { + if (prev && prev_got) + css_put(&prev->css); + prev = memcg; + prev_got = false; + goto find_again; + } + +unlock: + spin_unlock_irqrestore(&grade_list_lock, flags); + if (prev && prev_got) + css_put(&prev->css); + + return memcg; +} + +void fetch_next_memcg_break(struct mem_cgroup *memcg) +{ + if (memcg) + css_put(&memcg->css); +} + +static struct cftype mem_cgroup_hybridswap_legacy_files[] = { + { + .name = "force_shrink_anon", + .write = mem_cgroup_force_shrink_anon, + }, + { + .name = "total_info_per_app", + .flags = CFTYPE_ONLY_ON_ROOT, + .seq_show = memcg_total_info_per_app_show, + }, + { + .name = "swap_stat", + .seq_show = memcg_swap_stat_show, + }, + { + .name = "name", + .write = mem_cgroup_name_write, + .seq_show = mem_cgroup_name_show, + }, + { + .name = "app_score", + .write_s64 = mem_cgroup_app_grade_write, + .read_s64 = mem_cgroup_app_grade_read, + }, + { + .name = "app_uid", + .write_s64 = mem_cgroup_app_uid_write, + .read_s64 = mem_cgroup_app_uid_read, + }, + { + .name = "ub_ufs2zram_ratio", + .write_s64 = mem_cgroup_ufs2zram_scale_write, + .read_s64 = mem_cgroup_ufs2zram_scale_read, + }, + { + .name = "force_swapin", + .write_s64 = mem_cgroup_force_swapin_write, + }, + { + .name = "force_swapout", + .write_s64 = mem_cgroup_force_swapout_write, + }, +#ifdef CONFIG_HYBRIDSWAP_CORE + { + .name = "psi", + .flags = CFTYPE_ONLY_ON_ROOT, + .seq_show = hybridswap_psi_show, + }, + { + .name = "stored_wm_ratio", + .flags = CFTYPE_ONLY_ON_ROOT, + .write_s64 = mem_cgroup_stored_wm_scale_write, + .read_s64 = mem_cgroup_stored_wm_scale_read, + }, +#endif + { }, /* terminate */ +}; + +static int hybridswap_enable(struct zram *zram) +{ + int ret = 0; + + if (hybridswap_enabled) { + hybp(HYB_WARN, "hybridswap_enabled is true\n"); + return ret; + } + +#ifdef CONFIG_HYBRIDSWAP_SWAPD + ret = swapd_init(zram); + if (ret) + return ret; +#endif + +#ifdef CONFIG_HYBRIDSWAP_ASYNC_COMPRESS + ret = create_akcompressd_task(zram); + if (ret) + goto create_akcompressd_task_fail; +#endif + +#ifdef CONFIG_HYBRIDSWAP_CORE + ret = hybridswap_core_enable(); + if (ret) + goto hybridswap_core_enable_fail; +#endif + hybridswap_enabled = true; + + return 0; + +#ifdef CONFIG_HYBRIDSWAP_CORE +hybridswap_core_enable_fail: +#endif +#ifdef CONFIG_HYBRIDSWAP_ASYNC_COMPRESS + destroy_akcompressd_task(zram); +create_akcompressd_task_fail: +#endif +#ifdef CONFIG_HYBRIDSWAP_SWAPD + swapd_exit(); +#endif + return ret; +} + +static void hybridswap_disable(struct zram * zram) +{ + if (!hybridswap_enabled) { + hybp(HYB_WARN, "hybridswap_enabled is false\n"); + return; + } + +#ifdef CONFIG_HYBRIDSWAP_CORE + hybridswap_core_disable(); +#endif + +#ifdef CONFIG_HYBRIDSWAP_ASYNC_COMPRESS + destroy_akcompressd_task(zram); +#endif + +#ifdef CONFIG_HYBRIDSWAP_SWAPD + swapd_exit(); +#endif + hybridswap_enabled = false; +} + +ssize_t hybridswap_enable_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int len = snprintf(buf, PAGE_SIZE, "hybridswap %s out_to_eswap %s swapd %s\n", + hybridswap_core_enabled() ? "enable" : "disable", + hybridswap_out_to_eswap_enable() ? "enable" : "disable", + hybridswap_swapd_enabled() ? "enable" : "disable"); + + return len; +} + +ssize_t hybridswap_enable_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t len) +{ + int ret; + unsigned long val; + char *kbuf; + struct zram *zram; + + kbuf = strstrip((char *)buf); + ret = kstrtoul(kbuf, 0, &val); + if (unlikely(ret)) { + hybp(HYB_ERR, "val %s is invalid!\n", kbuf); + + return -EINVAL; + } + + mutex_lock(&hybridswap_enable_lock); + zram = dev_to_zram(dev); + if (val == 0) + hybridswap_disable(zram); + else + ret = hybridswap_enable(zram); + mutex_unlock(&hybridswap_enable_lock); + + if (ret == 0) + ret = len; + return ret; +} + +int __init hybridswap_pre_init(void) +{ + int ret; + + INIT_LIST_HEAD(&grade_head); + log_level = HYB_INFO; + + hybridswap_cache = kmem_cache_create("mem_cgroup_hybridswap", + sizeof(struct mem_cgroup_hybridswap), + 0, SLAB_PANIC, NULL); + if (!hybridswap_cache) { + hybp(HYB_ERR, "create hybridswap_cache failed\n"); + ret = -ENOMEM; + return ret; + } + + ret = cgroup_add_legacy_cftypes(&memory_cgrp_subsys, + mem_cgroup_hybridswap_legacy_files); + if (ret) { + hybp(HYB_INFO, "add mem_cgroup_hybridswap_legacy_files failed\n"); + goto error_out; + } + +#ifdef CONFIG_HYBRIDSWAP_SWAPD + ret = cgroup_add_legacy_cftypes(&memory_cgrp_subsys, + mem_cgroup_swapd_legacy_files); + if (ret) { + hybp(HYB_INFO, "add mem_cgroup_swapd_legacy_files failed!\n"); + goto error_out; + } +#endif + +#ifdef CONFIG_HYBRIDSWAP_ASYNC_COMPRESS + akcompressd_pre_init(); +#endif + +#ifdef CONFIG_HYBRIDSWAP_SWAPD + swapd_pre_init(); +#endif + ret = register_all_hooks(); + if (ret) + goto fail_out; + + hybp(HYB_INFO, "hybridswap inited success!\n"); + return 0; + +fail_out: +#ifdef CONFIG_HYBRIDSWAP_SWAPD + swapd_pre_deinit(); +#endif +#ifdef CONFIG_HYBRIDSWAP_ASYNC_COMPRESS + akcompressd_pre_deinit(); +#endif +error_out: + if (hybridswap_cache) { + kmem_cache_destroy(hybridswap_cache); + hybridswap_cache = NULL; + } + return ret; +} + +void __exit hybridswap_exit(void) +{ + unregister_all_hook(); + +#ifdef CONFIG_HYBRIDSWAP_SWAPD + swapd_pre_deinit(); +#endif +#ifdef CONFIG_HYBRIDSWAP_ASYNC_COMPRESS + akcompressd_pre_deinit(); +#endif + + if (hybridswap_cache) { + kmem_cache_destroy(hybridswap_cache); + hybridswap_cache = NULL; + } +} diff --git a/drivers/block/zram/hybridswap/hybridswap_swapd.c b/drivers/block/zram/hybridswap/hybridswap_swapd.c new file mode 100644 index 000000000000..437c60985475 --- /dev/null +++ b/drivers/block/zram/hybridswap/hybridswap_swapd.c @@ -0,0 +1,1908 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2020-2022 Oplus. All rights reserved. + */ + +#define pr_fmt(fmt) "[HYBRIDSWAP]" fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if IS_ENABLED(CONFIG_DRM_MSM) || IS_ENABLED(CONFIG_DRM_OPLUS_NOTIFY) +#include +#endif + +#include "../zram_drv.h" +#include "../zram_drv_internal.h" +#include "hybridswap_internal.h" + +struct swapd_param { + unsigned int min_grade; + unsigned int max_grade; + unsigned int mem2zram_scale; + unsigned int zram2ufs_scale; + unsigned int pagefault_level; +}; + +struct hybridswapd_task { + wait_queue_head_t swapd_wait; + atomic_t swapd_wait_flag; + struct task_struct *swapd; + struct cpumask swapd_bind_cpumask; +}; +#define PGDAT_ITEM_DATA(pgdat) ((struct hybridswapd_task*)(pgdat)->android_oem_data1) +#define PGDAT_ITEM(pgdat, item) (PGDAT_ITEM_DATA(pgdat)->item) + +#define INFOS_PAGEFAULT_THRESHOLD 3600 +#define PAGEFAULT_SNAPSHOT_MIN_GAP 150 +#define NOTHING_IGNORE_VALUE 20 +#define MAX_SKIP_GAP 1000 +#define EMPTY_ROUND_CHECK_THRESHOLD 10 +#define ZRAM_WM_RATIO 75 +#define COMPRESS_RATIO 33 +#define SWAPD_MAX_LEVEL_NUM 4 +#define SWAPD_DEFAULT_BIND_CPUS "0-3" +#define MAX_RECLAIMIN_SZ (200llu << 20) +#define page_to_kb(nr) (nr << (PAGE_SHIFT - 10)) +#define SWAPD_SHRINK_WINDOW (HZ * 10) +#define SWAPD_SHRINK_SIZE_PER_WINDOW 1024 +#define PAGES_TO_MB(pages) ((pages) >> 8) +#define PAGES_PER_1MB (1 << 8) + +unsigned long long total_pagefault_percent; +unsigned long long swapd_skip_interval; +bool last_round_is_empty; +unsigned long last_swapd_time; +atomic64_t zram_wm_scale = ATOMIC_LONG_INIT(ZRAM_WM_RATIO); +atomic64_t compress_scale = ATOMIC_LONG_INIT(COMPRESS_RATIO); +atomic_t usable_mem = ATOMIC_INIT(0); +atomic_t min_mem_watermark = ATOMIC_INIT(0); +atomic_t high_mem_watermark = ATOMIC_INIT(0); +atomic_t max_reclaim_size = ATOMIC_INIT(100); +atomic64_t free_swap_level = ATOMIC64_INIT(0); +atomic64_t zram_crit_thres = ATOMIC_LONG_INIT(0); +atomic64_t cpuload_level = ATOMIC_LONG_INIT(0); +atomic64_t infos_pagefault_level = ATOMIC_LONG_INIT(INFOS_PAGEFAULT_THRESHOLD); +atomic64_t pagefault_refresh_min = ATOMIC_LONG_INIT(PAGEFAULT_SNAPSHOT_MIN_GAP); +atomic64_t nothing_ignore_skip_interval = ATOMIC_LONG_INIT(NOTHING_IGNORE_VALUE); +atomic64_t max_skip_interval = ATOMIC_LONG_INIT(MAX_SKIP_GAP); +atomic64_t nothing_ignore_check_level = ATOMIC_LONG_INIT(EMPTY_ROUND_CHECK_THRESHOLD); +static unsigned long reclaim_exceed_sleep_ms = 50; +static unsigned long all_totalreserve_pages; + +static wait_queue_head_t refresh_daemonwait; +static atomic_t refresh_daemonwait_flag; +static atomic_t refresh_daemoninit_flag = ATOMIC_LONG_INIT(0); +static struct task_struct *refresh_daemontask; +static DEFINE_MUTEX(lowmem_event_lock); +static pid_t swapid = -1; +static unsigned long long infos_last_anon_pagefault; +static unsigned long last_refresh_t; +static struct swapd_param zswap_param[SWAPD_MAX_LEVEL_NUM]; +static enum cpuhp_state swapd_online; +static struct zram *swapd_zram = NULL; +static u64 max_reclaimin_size = MAX_RECLAIMIN_SZ; +atomic_long_t page_fault_pause = ATOMIC_LONG_INIT(0); +atomic_long_t page_fault_pause_cnt = ATOMIC_LONG_INIT(0); +#if IS_ENABLED(CONFIG_DRM_MSM) || IS_ENABLED(CONFIG_DRM_OPLUS_NOTIFY) +static struct notifier_block fb_notif; +static atomic_t display_off = ATOMIC_LONG_INIT(0); +#endif +static unsigned long swapd_shrink_window = SWAPD_SHRINK_WINDOW; +static unsigned long swapd_shrink_limit_per_window = SWAPD_SHRINK_SIZE_PER_WINDOW; +static unsigned long swapd_last_window_start; +static unsigned long swapd_last_window_shrink; +static atomic_t swapd_pause = ATOMIC_INIT(0); +static atomic_t swapd_enabled = ATOMIC_INIT(0); +static unsigned long swapd_nap_jiffies = 1; + +extern unsigned long try_to_free_mem_cgroup_pages(struct mem_cgroup *memcg, + unsigned long nr_pages, + gfp_t gfp_mask, + bool may_swap); +#ifdef CONFIG_OPLUS_JANK +extern u32 fetch_cpu_load(u32 win_cnt, struct cpumask *mask); +#endif + +inline u64 fetch_zram_wm_scale_value(void) +{ + return atomic64_read(&zram_wm_scale); +} + +inline u64 fetch_compress_scale_value(void) +{ + return atomic64_read(&compress_scale); +} + +inline unsigned int fetch_usable_mem_value(void) +{ + return atomic_read(&usable_mem); +} + +inline unsigned int fetch_min_mem_watermark_value(void) +{ + return atomic_read(&min_mem_watermark); +} + +inline unsigned int fetch_high_mem_watermark_value(void) +{ + return atomic_read(&high_mem_watermark); +} + +inline u64 fetch_swapd_max_reclaim_size(void) +{ + return atomic_read(&max_reclaim_size); +} + +inline u64 fetch_free_swap_level_value(void) +{ + return atomic64_read(&free_swap_level); +} + +inline unsigned long long fetch_infos_pagefault_level_value(void) +{ + return atomic64_read(&infos_pagefault_level); +} + +inline unsigned long fetch_pagefault_refresh_min_value(void) +{ + return atomic64_read(&pagefault_refresh_min); +} + +inline unsigned long long fetch_nothing_ignore_skip_interval_value(void) +{ + return atomic64_read(¬hing_ignore_skip_interval); +} + +inline unsigned long long fetch_max_skip_interval_value(void) +{ + return atomic64_read(&max_skip_interval); +} + +inline unsigned long long fetch_nothing_ignore_check_level_value(void) +{ + return atomic64_read(¬hing_ignore_check_level); +} + +inline u64 fetch_zram_critical_level_value(void) +{ + return atomic64_read(&zram_crit_thres); +} + +inline u64 fetch_cpuload_level_value(void) +{ + return atomic64_read(&cpuload_level); +} + +static ssize_t usable_mem_params_write(struct kernfs_open_file *of, + char *buf, size_t nbytes, loff_t off) +{ + unsigned int usable_mem_value; + unsigned int min_mem_watermark_value; + unsigned int high_mem_watermark_value; + u64 free_swap_level_value; + + buf = strstrip(buf); + + if (sscanf(buf, "%u %u %u %llu", + &usable_mem_value, + &min_mem_watermark_value, + &high_mem_watermark_value, + &free_swap_level_value) != 4) + return -EINVAL; + + atomic_set(&usable_mem, usable_mem_value); + atomic_set(&min_mem_watermark, min_mem_watermark_value); + atomic_set(&high_mem_watermark, high_mem_watermark_value); + atomic64_set(&free_swap_level, + (free_swap_level_value * (SZ_1M / PAGE_SIZE))); + + if (atomic_read(&min_mem_watermark) == 0) + atomic_set(&refresh_daemoninit_flag, 0); + else + atomic_set(&refresh_daemoninit_flag, 1); + + wake_all_swapd(); + + return nbytes; +} + +static int usable_mem_params_show(struct seq_file *m, void *v) +{ + seq_printf(m, "avail_buffers: %u\n", + atomic_read(&usable_mem)); + seq_printf(m, "min_avail_buffers: %u\n", + atomic_read(&min_mem_watermark)); + seq_printf(m, "high_avail_buffers: %u\n", + atomic_read(&high_mem_watermark)); + seq_printf(m, "free_swap_threshold: %llu\n", + (atomic64_read(&free_swap_level) * PAGE_SIZE / SZ_1M)); + + return 0; +} + +static ssize_t swapd_max_reclaim_size_write(struct kernfs_open_file *of, + char *buf, size_t nbytes, loff_t off) +{ + const unsigned int base = 10; + u32 max_reclaim_size_value; + int ret; + + buf = strstrip(buf); + ret = kstrtouint(buf, base, &max_reclaim_size_value); + if (ret) + return -EINVAL; + + atomic_set(&max_reclaim_size, max_reclaim_size_value); + + return nbytes; +} + +static int swapd_max_reclaim_size_show(struct seq_file *m, void *v) +{ + seq_printf(m, "swapd_max_reclaim_size: %u\n", + atomic_read(&max_reclaim_size)); + + return 0; +} + +static int infos_pagefault_level_write(struct cgroup_subsys_state *css, + struct cftype *cft, s64 val) +{ + if (val < 0) + return -EINVAL; + + atomic64_set(&infos_pagefault_level, val); + + return 0; +} + +static s64 infos_pagefault_level_read(struct cgroup_subsys_state *css, + struct cftype *cft) +{ + return atomic64_read(&infos_pagefault_level); +} + +static int nothing_ignore_skip_interval_write(struct cgroup_subsys_state *css, + struct cftype *cft, s64 val) +{ + if (val < 0) + return -EINVAL; + + atomic64_set(¬hing_ignore_skip_interval, val); + + return 0; +} + +static s64 nothing_ignore_skip_interval_read(struct cgroup_subsys_state *css, + struct cftype *cft) +{ + return atomic64_read(¬hing_ignore_skip_interval); +} + +static int max_skip_interval_write(struct cgroup_subsys_state *css, + struct cftype *cft, s64 val) +{ + if (val < 0) + return -EINVAL; + + atomic64_set(&max_skip_interval, val); + + return 0; +} + +static s64 max_skip_interval_read(struct cgroup_subsys_state *css, + struct cftype *cft) +{ + return atomic64_read(&max_skip_interval); +} + +static int nothing_ignore_check_level_write(struct cgroup_subsys_state *css, + struct cftype *cft, s64 val) +{ + if (val < 0) + return -EINVAL; + + atomic64_set(¬hing_ignore_check_level, val); + + return 0; +} + +static s64 nothing_ignore_check_level_read(struct cgroup_subsys_state *css, + struct cftype *cft) +{ + return atomic64_read(¬hing_ignore_check_level); +} + +static int pagefault_refresh_min_write( + struct cgroup_subsys_state *css, struct cftype *cft, s64 val) +{ + if (val < 0) + return -EINVAL; + + atomic64_set(&pagefault_refresh_min, val); + + return 0; +} + +static s64 pagefault_refresh_min_read( + struct cgroup_subsys_state *css, struct cftype *cft) +{ + return atomic64_read(&pagefault_refresh_min); +} + +static int zram_critical_thres_write(struct cgroup_subsys_state *css, + struct cftype *cft, s64 val) +{ + if (val < 0) + return -EINVAL; + + atomic64_set(&zram_crit_thres, val << (20 - PAGE_SHIFT)); + + return 0; +} + +static s64 zram_critical_thres_read(struct cgroup_subsys_state *css, + struct cftype *cft) +{ + return atomic64_read(&zram_crit_thres) >> (20 - PAGE_SHIFT); +} + +static s64 cpuload_level_read(struct cgroup_subsys_state *css, + struct cftype *cft) + +{ + return atomic64_read(&cpuload_level); +} + +static int cpuload_level_write(struct cgroup_subsys_state *css, + struct cftype *cft, s64 val) +{ + if (val < 0) + return -EINVAL; + + atomic64_set(&cpuload_level, val); + + return 0; +} + +static s64 swapid_read(struct cgroup_subsys_state *css, struct cftype *cft) +{ + return swapid; +} + +static void swapd_mcgs_setup_parse(int level_num) +{ + struct mem_cgroup *memcg = NULL; + memcg_hybs_t *hybs = NULL; + int i; + + while ((memcg = fetch_next_memcg(memcg))) { + hybs = MEMCGRP_ITEM_DATA(memcg); + + for (i = 0; i < level_num; ++i) { + if (atomic64_read(&hybs->app_grade) >= zswap_param[i].min_grade && + atomic64_read(&hybs->app_grade) <= zswap_param[i].max_grade) + break; + } + atomic_set(&hybs->mem2zram_scale, zswap_param[i].mem2zram_scale); + atomic_set(&hybs->zram2ufs_scale, zswap_param[i].zram2ufs_scale); + atomic_set(&hybs->pagefault_level, zswap_param[i].pagefault_level); + } +} + +static void update_swapd_memcg_hybs(memcg_hybs_t *hybs) +{ + int i; + + for (i = 0; i < SWAPD_MAX_LEVEL_NUM; ++i) { + if (!zswap_param[i].min_grade && !zswap_param[i].max_grade) + return; + + if (atomic64_read(&hybs->app_grade) >= zswap_param[i].min_grade && + atomic64_read(&hybs->app_grade) <= zswap_param[i].max_grade) + break; + } + + if (i == SWAPD_MAX_LEVEL_NUM) + return; + + atomic_set(&hybs->mem2zram_scale, zswap_param[i].mem2zram_scale); + atomic_set(&hybs->zram2ufs_scale, zswap_param[i].zram2ufs_scale); + atomic_set(&hybs->pagefault_level, zswap_param[i].pagefault_level); +} + +void update_swapd_mcg_setup(struct mem_cgroup *memcg) +{ + memcg_hybs_t *hybs = MEMCGRP_ITEM_DATA(memcg); + + if (!hybs) + return; + + update_swapd_memcg_hybs(hybs); +} + +static int update_swapd_mcgs_setup(char *buf) +{ + const char delim[] = " "; + char *token = NULL; + int level_num; + int i; + + buf = strstrip(buf); + token = strsep(&buf, delim); + + if (!token) + return -EINVAL; + + if (kstrtoint(token, 0, &level_num)) + return -EINVAL; + + if (level_num > SWAPD_MAX_LEVEL_NUM || level_num < 0) + return -EINVAL; + + mutex_lock(&reclaim_para_lock); + for (i = 0; i < level_num; ++i) { + token = strsep(&buf, delim); + if (!token) + goto out; + + if (kstrtoint(token, 0, &zswap_param[i].min_grade) || + zswap_param[i].min_grade > MAX_APP_GRADE) + goto out; + + token = strsep(&buf, delim); + if (!token) + goto out; + + if (kstrtoint(token, 0, &zswap_param[i].max_grade) || + zswap_param[i].max_grade > MAX_APP_GRADE) + goto out; + + token = strsep(&buf, delim); + if (!token) + goto out; + + if (kstrtoint(token, 0, &zswap_param[i].mem2zram_scale) || + zswap_param[i].mem2zram_scale > MAX_RATIO) + goto out; + + token = strsep(&buf, delim); + if (!token) + goto out; + + if (kstrtoint(token, 0, &zswap_param[i].zram2ufs_scale) || + zswap_param[i].zram2ufs_scale > MAX_RATIO) + goto out; + + token = strsep(&buf, delim); + if (!token) + goto out; + + if (kstrtoint(token, 0, &zswap_param[i].pagefault_level)) + goto out; + } + + swapd_mcgs_setup_parse(level_num); + mutex_unlock(&reclaim_para_lock); + return 0; + +out: + mutex_unlock(&reclaim_para_lock); + return -EINVAL; +} + +static ssize_t swapd_mcgs_setup_write(struct kernfs_open_file *of, char *buf, + size_t nbytes, loff_t off) +{ + int ret = update_swapd_mcgs_setup(buf); + + if (ret) + return ret; + + return nbytes; +} + +static int swapd_mcgs_setup_show(struct seq_file *m, void *v) +{ + int i; + + for (i = 0; i < SWAPD_MAX_LEVEL_NUM; ++i) { + seq_printf(m, "level %d min score: %u\n", + i, zswap_param[i].min_grade); + seq_printf(m, "level %d max score: %u\n", + i, zswap_param[i].max_grade); + seq_printf(m, "level %d ub_mem2zram_ratio: %u\n", + i, zswap_param[i].mem2zram_scale); + seq_printf(m, "level %d ub_zram2ufs_ratio: %u\n", + i, zswap_param[i].zram2ufs_scale); + seq_printf(m, "memcg %d refault_threshold: %u\n", + i, zswap_param[i].pagefault_level); + } + + return 0; +} + +static ssize_t swapd_nap_jiffies_write(struct kernfs_open_file *of, char *buf, + size_t nbytes, loff_t off) +{ + unsigned long nap; + + buf = strstrip(buf); + if (!buf) + return -EINVAL; + + if (kstrtoul(buf, 0, &nap)) + return -EINVAL; + + swapd_nap_jiffies = nap; + return nbytes; +} + +static int swapd_nap_jiffies_show(struct seq_file *m, void *v) +{ + seq_printf(m, "%lu\n", swapd_nap_jiffies); + + return 0; +} + +static ssize_t swapd_single_mcg_setup_write(struct kernfs_open_file *of, + char *buf, size_t nbytes, loff_t off) +{ + struct mem_cgroup *memcg = mem_cgroup_from_css(of_css(of)); + unsigned int mem2zram_scale; + unsigned int zram2ufs_scale; + unsigned int pagefault_level; + memcg_hybs_t *hybs = MEMCGRP_ITEM_DATA(memcg); + + if (!hybs) + return -EINVAL; + + buf = strstrip(buf); + + if (sscanf(buf, "%u %u %u", &mem2zram_scale, &zram2ufs_scale, + &pagefault_level) != 3) + return -EINVAL; + + if (mem2zram_scale > MAX_RATIO || zram2ufs_scale > MAX_RATIO) + return -EINVAL; + + atomic_set(&MEMCGRP_ITEM(memcg, mem2zram_scale), mem2zram_scale); + atomic_set(&MEMCGRP_ITEM(memcg, zram2ufs_scale), zram2ufs_scale); + atomic_set(&MEMCGRP_ITEM(memcg, pagefault_level), pagefault_level); + + return nbytes; +} + +static int swapd_single_mcg_setup_show(struct seq_file *m, void *v) +{ + struct mem_cgroup *memcg = mem_cgroup_from_css(seq_css(m)); + memcg_hybs_t *hybs = MEMCGRP_ITEM_DATA(memcg); + + if (!hybs) + return -EINVAL; + + seq_printf(m, "memcg score: %lu\n", + atomic64_read(&hybs->app_grade)); + seq_printf(m, "memcg ub_mem2zram_ratio: %u\n", + atomic_read(&hybs->mem2zram_scale)); + seq_printf(m, "memcg ub_zram2ufs_ratio: %u\n", + atomic_read(&hybs->zram2ufs_scale)); + seq_printf(m, "memcg refault_threshold: %u\n", + atomic_read(&hybs->pagefault_level)); + + return 0; +} + +static int mem_cgroup_zram_wm_scale_write(struct cgroup_subsys_state *css, + struct cftype *cft, s64 val) +{ + if (val > MAX_RATIO || val < MIN_RATIO) + return -EINVAL; + + atomic64_set(&zram_wm_scale, val); + + return 0; +} + +static s64 mem_cgroup_zram_wm_scale_read(struct cgroup_subsys_state *css, + struct cftype *cft) +{ + return atomic64_read(&zram_wm_scale); +} + +static int mem_cgroup_compress_scale_write(struct cgroup_subsys_state *css, + struct cftype *cft, s64 val) +{ + if (val > MAX_RATIO || val < MIN_RATIO) + return -EINVAL; + + atomic64_set(&compress_scale, val); + + return 0; +} + +static s64 mem_cgroup_compress_scale_read(struct cgroup_subsys_state *css, + struct cftype *cft) +{ + return atomic64_read(&compress_scale); +} + +static int memcg_active_app_info_list_show(struct seq_file *m, void *v) +{ + struct mem_cgroup *memcg = NULL; + unsigned long anon_size; + unsigned long zram_size; + unsigned long eswap_size; + + while ((memcg = fetch_next_memcg(memcg))) { + u64 grade; + + if (!MEMCGRP_ITEM_DATA(memcg)) + continue; + + grade = atomic64_read(&MEMCGRP_ITEM(memcg, app_grade)); + anon_size = memcg_anon_pages(memcg); + eswap_size = hybridswap_read_mcg_stats(memcg, + MCG_DISK_STORED_PG_SZ); + zram_size = hybridswap_read_mcg_stats(memcg, + MCG_ZRAM_STORED_PG_SZ); + + if (anon_size + zram_size + eswap_size == 0) + continue; + + if (!strlen(MEMCGRP_ITEM(memcg, name))) + continue; + + anon_size *= PAGE_SIZE / SZ_1K; + zram_size *= PAGE_SIZE / SZ_1K; + eswap_size *= PAGE_SIZE / SZ_1K; + + seq_printf(m, "%s %llu %lu %lu %lu %llu\n", + MEMCGRP_ITEM(memcg, name), grade, + anon_size, zram_size, eswap_size, + MEMCGRP_ITEM(memcg, reclaimed_pagefault)); + } + return 0; +} + +static unsigned long fetch_totalreserve_pages(void) +{ + int nid; + unsigned long val = 0; + + for_each_node_state(nid, N_MEMORY) { + pg_data_t *pgdat = NODE_DATA(nid); + + if (pgdat) + val += pgdat->totalreserve_pages; + } + + return val; +} + +unsigned int system_cur_usable_mem(void) +{ + unsigned long reclaimable; + long buffers; + unsigned long pagecache; + unsigned long wmark_low = 0; + struct zone *zone; + + buffers = global_zone_page_state(NR_FREE_PAGES) - all_totalreserve_pages; + + for_each_zone(zone) + wmark_low += low_wmark_pages(zone); + pagecache = global_node_page_state(NR_ACTIVE_FILE) + + global_node_page_state(NR_INACTIVE_FILE); + pagecache -= min(pagecache / 2, wmark_low); + buffers += pagecache; + + reclaimable = global_node_page_state(NR_SLAB_RECLAIMABLE) + + global_node_page_state(NR_KERNEL_MISC_RECLAIMABLE); + buffers += reclaimable - min(reclaimable / 2, wmark_low); + + if (buffers < 0) + buffers = 0; + + return buffers >> 8; /* pages to MB */ +} + +static bool min_buffer_is_suitable(void) +{ + u32 curr_buffers = system_cur_usable_mem(); + + if (curr_buffers >= fetch_min_mem_watermark_value()) + return true; + + return false; +} + +bool high_buffer_is_suitable(void) +{ + u32 curr_buffers = system_cur_usable_mem(); + + if (curr_buffers >= fetch_high_mem_watermark_value()) + return true; + + return false; +} + +static void refresh_pagefaults(void) +{ + struct mem_cgroup *memcg = NULL; + + while ((memcg = fetch_next_memcg(memcg))) { + MEMCGRP_ITEM(memcg, reclaimed_pagefault) = + hybridswap_read_mcg_stats(memcg, MCG_ANON_FAULT_CNT); + } + + infos_last_anon_pagefault = hybridswap_fetch_zram_pagefault(); + last_refresh_t = jiffies; +} + +bool fetch_memcg_pagefault_status(struct mem_cgroup *memcg, + pg_data_t *pgdat) +{ + const unsigned int percent_constant = 100; + unsigned long long cur_anon_pagefault; + unsigned long anon_total; + unsigned long long scale, thresh; + memcg_hybs_t *hybs; + + if (!memcg || !MEMCGRP_ITEM_DATA(memcg)) + return false; + + hybs = MEMCGRP_ITEM_DATA(memcg); + thresh = atomic_read(&hybs->pagefault_level); + if (thresh == 0) + return false; + + cur_anon_pagefault = hybridswap_read_mcg_stats(memcg, MCG_ANON_FAULT_CNT); + if (cur_anon_pagefault == hybs->reclaimed_pagefault) + return false; + + anon_total = memcg_anon_pages(memcg) + + hybridswap_read_mcg_stats(memcg, MCG_DISK_STORED_PG_SZ) + + hybridswap_read_mcg_stats(memcg, MCG_ZRAM_STORED_PG_SZ); + scale = (cur_anon_pagefault - hybs->reclaimed_pagefault) * + percent_constant / (anon_total + 1); + hybp(HYB_INFO, "memcg %16s scale %8llu level %8llu\n", hybs->name, + scale, thresh); + + if (scale >= thresh) + return true; + + return false; +} + +static bool hybridswap_scale_ok(void) +{ + struct hybstatus *stat = NULL; + + stat = hybridswap_fetch_stat_obj(); + if (unlikely(!stat)) { + hybp(HYB_ERR, "can't fetch stat obj!\n"); + + return false; + } + + return (atomic64_read(&stat->zram_stored_pages) > + atomic64_read(&stat->stored_pages)); +} + +static bool fetch_infos_pagefault_status(void) +{ + const unsigned int percent_constant = 1000; + unsigned long long cur_anon_pagefault; + unsigned long long cur_time; + unsigned long long scale = 0; + + cur_anon_pagefault = hybridswap_fetch_zram_pagefault(); + cur_time = jiffies; + + if (cur_anon_pagefault == infos_last_anon_pagefault + || cur_time == last_refresh_t) + goto false_out; + + scale = (cur_anon_pagefault - infos_last_anon_pagefault) * + percent_constant / (jiffies_to_msecs(cur_time - + last_refresh_t) + 1); + + total_pagefault_percent = scale; + + if (scale > fetch_infos_pagefault_level_value()) + return true; + + hybp(HYB_INFO, "current %llu t %llu last %llu t %llu scale %llu pagefault_scale %llu\n", + cur_anon_pagefault, cur_time, + infos_last_anon_pagefault, last_refresh_t, + scale, infos_pagefault_level); +false_out: + return false; +} + +static int reclaim_exceed_sleep_ms_write( + struct cgroup_subsys_state *css, struct cftype *cft, s64 val) +{ + if (val < 0) + return -EINVAL; + + reclaim_exceed_sleep_ms = val; + + return 0; +} + +static s64 reclaim_exceed_sleep_ms_read( + struct cgroup_subsys_state *css, struct cftype *cft) +{ + return reclaim_exceed_sleep_ms; +} + +static int max_reclaimin_size_mb_write( + struct cgroup_subsys_state *css, struct cftype *cft, u64 val) +{ + max_reclaimin_size = (val << 20); + + return 0; +} + +static u64 max_reclaimin_size_mb_read( + struct cgroup_subsys_state *css, struct cftype *cft) +{ + return max_reclaimin_size >> 20; +} + +static ssize_t swapd_shrink_parameter_write(struct kernfs_open_file *of, + char *buf, size_t nbytes, loff_t off) +{ + unsigned long window, limit; + + buf = strstrip(buf); + if (sscanf(buf, "%lu %lu", &window, &limit) != 2) + return -EINVAL; + + swapd_shrink_window = msecs_to_jiffies(window); + swapd_shrink_limit_per_window = limit; + + return nbytes; +} + +static int swapd_shrink_parameter_show(struct seq_file *m, void *v) +{ + seq_printf(m, "%-32s %lu(jiffies) %u(msec)\n", "swapd_shrink_window", + swapd_shrink_window, jiffies_to_msecs(swapd_shrink_window)); + seq_printf(m, "%-32s %lu MB\n", "swapd_shrink_limit_per_window", + swapd_shrink_limit_per_window); + seq_printf(m, "%-32s %u msec\n", "swapd_last_window", + jiffies_to_msecs(jiffies - swapd_last_window_start)); + seq_printf(m, "%-32s %lu MB\n", "swapd_last_window_shrink", + swapd_last_window_shrink); + + return 0; +} + +static int swapd_update_cpumask(struct task_struct *tsk, char *buf, + struct pglist_data *pgdat) +{ + int retval; + struct cpumask temp_mask; + const struct cpumask *cpumask = cpumask_of_node(pgdat->node_id); + struct hybridswapd_task* hyb_task = PGDAT_ITEM_DATA(pgdat); + + if (unlikely(!hyb_task)) { + hybp(HYB_ERR, "set task %s cpumask %s node %d failed, " + "hyb_task is NULL\n", tsk->comm, buf, pgdat->node_id); + return -EINVAL; + } + + cpumask_clear(&temp_mask); + retval = cpulist_parse(buf, &temp_mask); + if (retval < 0 || cpumask_empty(&temp_mask)) { + hybp(HYB_ERR, "%s are invalid, use default\n", buf); + goto use_default; + } + + if (!cpumask_subset(&temp_mask, cpu_present_mask)) { + hybp(HYB_ERR, "%s is not subset of cpu_present_mask, use default\n", + buf); + goto use_default; + } + + if (!cpumask_subset(&temp_mask, cpumask)) { + hybp(HYB_ERR, "%s is not subset of cpumask, use default\n", buf); + goto use_default; + } + + set_cpus_allowed_ptr(tsk, &temp_mask); + cpumask_copy(&hyb_task->swapd_bind_cpumask, &temp_mask); + return 0; + +use_default: + if (cpumask_empty(&hyb_task->swapd_bind_cpumask)) + set_cpus_allowed_ptr(tsk, cpumask); + return -EINVAL; +} + +static ssize_t swapd_bind_write(struct kernfs_open_file *of, char *buf, + size_t nbytes, loff_t off) +{ + int ret = 0, nid; + struct pglist_data *pgdat; + + buf = strstrip(buf); + for_each_node_state(nid, N_MEMORY) { + pgdat = NODE_DATA(nid); + if (!PGDAT_ITEM_DATA(pgdat)) + continue; + + if (PGDAT_ITEM(pgdat, swapd)) { + ret = swapd_update_cpumask(PGDAT_ITEM(pgdat, swapd), + buf, pgdat); + if (ret) + break; + } + } + + if (ret) + return ret; + + return nbytes; +} + +static int swapd_bind_read(struct seq_file *m, void *v) +{ + int nid; + struct pglist_data *pgdat; + struct hybridswapd_task* hyb_task; + + seq_printf(m, "%4s %s\n", "Node", "mask"); + for_each_node_state(nid, N_MEMORY) { + pgdat = NODE_DATA(nid); + hyb_task = PGDAT_ITEM_DATA(pgdat); + if (!hyb_task) + continue; + + if (!hyb_task->swapd) + continue; + seq_printf(m, "%4d %*pbl\n", nid, + cpumask_pr_args(&hyb_task->swapd_bind_cpumask)); + } + + return 0; +} + +struct cftype mem_cgroup_swapd_legacy_files[] = { + { + .name = "active_app_info_list", + .flags = CFTYPE_ONLY_ON_ROOT, + .seq_show = memcg_active_app_info_list_show, + }, + { + .name = "zram_wm_ratio", + .flags = CFTYPE_ONLY_ON_ROOT, + .write_s64 = mem_cgroup_zram_wm_scale_write, + .read_s64 = mem_cgroup_zram_wm_scale_read, + }, + { + .name = "compress_ratio", + .flags = CFTYPE_ONLY_ON_ROOT, + .write_s64 = mem_cgroup_compress_scale_write, + .read_s64 = mem_cgroup_compress_scale_read, + }, + { + .name = "swapd_pid", + .flags = CFTYPE_ONLY_ON_ROOT, + .read_s64 = swapid_read, + }, + { + .name = "avail_buffers", + .flags = CFTYPE_ONLY_ON_ROOT, + .write = usable_mem_params_write, + .seq_show = usable_mem_params_show, + }, + { + .name = "swapd_max_reclaim_size", + .flags = CFTYPE_ONLY_ON_ROOT, + .write = swapd_max_reclaim_size_write, + .seq_show = swapd_max_reclaim_size_show, + }, + { + .name = "area_anon_refault_threshold", + .flags = CFTYPE_ONLY_ON_ROOT, + .write_s64 = infos_pagefault_level_write, + .read_s64 = infos_pagefault_level_read, + }, + { + .name = "empty_round_skip_interval", + .flags = CFTYPE_ONLY_ON_ROOT, + .write_s64 = nothing_ignore_skip_interval_write, + .read_s64 = nothing_ignore_skip_interval_read, + }, + { + .name = "max_skip_interval", + .flags = CFTYPE_ONLY_ON_ROOT, + .write_s64 = max_skip_interval_write, + .read_s64 = max_skip_interval_read, + }, + { + .name = "empty_round_check_threshold", + .flags = CFTYPE_ONLY_ON_ROOT, + .write_s64 = nothing_ignore_check_level_write, + .read_s64 = nothing_ignore_check_level_read, + }, + { + .name = "anon_refault_snapshot_min_interval", + .flags = CFTYPE_ONLY_ON_ROOT, + .write_s64 = pagefault_refresh_min_write, + .read_s64 = pagefault_refresh_min_read, + }, + { + .name = "swapd_mcgs_setup", + .flags = CFTYPE_ONLY_ON_ROOT, + .write = swapd_mcgs_setup_write, + .seq_show = swapd_mcgs_setup_show, + }, + { + .name = "swapd_single_mcg_setup", + .write = swapd_single_mcg_setup_write, + .seq_show = swapd_single_mcg_setup_show, + }, + { + .name = "zram_critical_threshold", + .flags = CFTYPE_ONLY_ON_ROOT, + .write_s64 = zram_critical_thres_write, + .read_s64 = zram_critical_thres_read, + }, + { + .name = "cpuload_threshold", + .flags = CFTYPE_ONLY_ON_ROOT, + .write_s64 = cpuload_level_write, + .read_s64 = cpuload_level_read, + }, + { + .name = "reclaim_exceed_sleep_ms", + .flags = CFTYPE_ONLY_ON_ROOT, + .write_s64 = reclaim_exceed_sleep_ms_write, + .read_s64 = reclaim_exceed_sleep_ms_read, + }, + { + .name = "swapd_bind", + .flags = CFTYPE_ONLY_ON_ROOT, + .write = swapd_bind_write, + .seq_show = swapd_bind_read, + }, + { + .name = "max_reclaimin_size_mb", + .flags = CFTYPE_ONLY_ON_ROOT, + .write_u64 = max_reclaimin_size_mb_write, + .read_u64 = max_reclaimin_size_mb_read, + }, + { + .name = "swapd_shrink_parameter", + .flags = CFTYPE_ONLY_ON_ROOT, + .write = swapd_shrink_parameter_write, + .seq_show = swapd_shrink_parameter_show, + }, + { + .name = "swapd_nap_jiffies", + .flags = CFTYPE_ONLY_ON_ROOT, + .write = swapd_nap_jiffies_write, + .seq_show = swapd_nap_jiffies_show, + }, + { }, /* terminate */ +}; + +void wakeup_refresh_daemon(void) +{ + unsigned long curr_refresh = + jiffies_to_msecs(jiffies - last_refresh_t); + + if (curr_refresh >= + fetch_pagefault_refresh_min_value()) { + atomic_set(&refresh_daemonwait_flag, 1); + wake_up_interruptible(&refresh_daemonwait); + } +} + +static int refresh_daemon(void *p) +{ + int ret; + + while (!kthread_should_stop()) { + ret = wait_event_interruptible(refresh_daemonwait, + atomic_read(&refresh_daemonwait_flag)); + if (ret) + continue; + + if (unlikely(kthread_should_stop())) + break; + + atomic_set(&refresh_daemonwait_flag, 0); + + refresh_pagefaults(); + count_swapd_event(SWAPD_SNAPSHOT_TIMES); + } + + return 0; +} + +static int refresh_daemonrun(void) +{ + atomic_set(&refresh_daemonwait_flag, 0); + init_waitqueue_head(&refresh_daemonwait); + refresh_daemontask = kthread_run(refresh_daemon, NULL, "snapshotd"); + + if (IS_ERR(refresh_daemontask)) { + hybp(HYB_ERR, "Failed to start refresh_daemon\n"); + return PTR_ERR(refresh_daemontask); + } + + return 0; +} + +static void refresh_daemonexit(void) +{ + if (refresh_daemontask) { + atomic_set(&refresh_daemonwait_flag, 1); + kthread_stop(refresh_daemontask); + } + refresh_daemontask = NULL; +} + +unsigned long fetch_nr_zram_total(void) +{ + unsigned long nr_zram = 1; + + if (!swapd_zram) + return nr_zram; + + nr_zram = swapd_zram->disksize >> PAGE_SHIFT; +#if (defined CONFIG_ZRAM_WRITEBACK) || (defined CONFIG_HYBRIDSWAP_CORE) + nr_zram -= swapd_zram->increase_nr_pages; +#endif + return nr_zram ?: 1; +} + +static inline unsigned long hybridswap_fetch_zram_used_pages(void) +{ + if (swapd_zram) + return atomic64_read(&swapd_zram->stats.pages_stored); + + return 0; +} + +u64 get_hybridswap_meminfo(const char *type) +{ + if (!type || !swapd_zram) + return 0; + + if (!strcmp(type, "same_pages")) + return (u64)atomic64_read(&swapd_zram->stats.same_pages); + if (!strcmp(type, "compr_data_size")) + return (u64)atomic64_read(&swapd_zram->stats.compr_data_size); + if (!strcmp(type, "pages_stored")) + return (u64)atomic64_read(&swapd_zram->stats.pages_stored); + return 0; +} +EXPORT_SYMBOL(get_hybridswap_meminfo); + +bool zram_watermark_ok(void) +{ + long long diff_buffers; + long long wm = 0; + long long cur_scale = 0; + unsigned long zram_used = hybridswap_fetch_zram_used_pages(); + const unsigned int percent_constant = 100; + + diff_buffers = fetch_high_mem_watermark_value() - + system_cur_usable_mem(); + diff_buffers *= SZ_1M / PAGE_SIZE; + diff_buffers *= fetch_compress_scale_value() / 10; + diff_buffers = diff_buffers * percent_constant / fetch_nr_zram_total(); + + cur_scale = zram_used * percent_constant / fetch_nr_zram_total(); + wm = min(fetch_zram_wm_scale_value(), fetch_zram_wm_scale_value()- diff_buffers); + + return cur_scale > wm; +} + +static inline bool zram_is_full(void) +{ + unsigned long nr_used = hybridswap_fetch_zram_used_pages(); + unsigned long nr_total = fetch_nr_zram_total(); + + return nr_used >= nr_total; +} + +bool free_zram_is_ok(void) +{ + unsigned long nr_used = hybridswap_fetch_zram_used_pages(); + unsigned long nr_total = fetch_nr_zram_total(); + unsigned long reserve = nr_total >> 6; + + return (nr_used < (nr_total - reserve)); +} + +static bool zram_need_swapout(void) +{ + bool zram_wm_ok = zram_watermark_ok(); + bool avail_buffer_wm_ok = !high_buffer_is_suitable(); + bool ufs_wm_ok = true; + +#ifdef CONFIG_HYBRIDSWAP_CORE + ufs_wm_ok = hybridswap_stored_wm_ok(); +#endif + + if (zram_wm_ok && avail_buffer_wm_ok && ufs_wm_ok) + return true; + + hybp(HYB_INFO, "zram_wm_ok %d avail_buffer_wm_ok %d ufs_wm_ok %d\n", + zram_wm_ok, avail_buffer_wm_ok, ufs_wm_ok); + + return false; +} + +bool zram_watermark_exceed(void) +{ + u64 nr_zram_used; + u64 nr_wm = fetch_zram_critical_level_value(); + + if (!nr_wm) + return false; + + nr_zram_used = hybridswap_fetch_zram_used_pages(); + + if (nr_zram_used > nr_wm) + return true; + + return false; +} + +#ifdef CONFIG_OPLUS_JANK +static bool is_cpu_busy(void) +{ + unsigned int cpuload = 0; + int i; + struct cpumask mask; + + cpumask_clear(&mask); + + for (i = 0; i < 6; i++) + cpumask_set_cpu(i, &mask); + + cpuload = fetch_cpu_load(1, &mask); + if (cpuload > fetch_cpuload_level_value()) { + hybp(HYB_INFO, "cpuload %d\n", cpuload); + return true; + } + + return false; +} +#endif + +static void wakeup_swapd(pg_data_t *pgdat) +{ + unsigned long curr_interval; + struct hybridswapd_task* hyb_task = PGDAT_ITEM_DATA(pgdat); + + if (!hyb_task || !hyb_task->swapd) + return; + + if (atomic_read(&swapd_pause)) { + count_swapd_event(SWAPD_MANUAL_PAUSE); + return; + } + +#if IS_ENABLED(CONFIG_DRM_MSM) || IS_ENABLED(CONFIG_DRM_OPLUS_NOTIFY) + if (atomic_read(&display_off)) + return; +#endif + + if (!waitqueue_active(&hyb_task->swapd_wait)) + return; + + if (atomic_read(&refresh_daemoninit_flag) == 1) + wakeup_refresh_daemon(); + + if (min_buffer_is_suitable()) { + count_swapd_event(SWAPD_OVER_MIN_BUFFER_SKIP_TIMES); + return; + } + + curr_interval = jiffies_to_msecs(jiffies - last_swapd_time); + if (curr_interval < swapd_skip_interval) { + count_swapd_event(SWAPD_EMPTY_ROUND_SKIP_TIMES); + return; + } + + atomic_set(&hyb_task->swapd_wait_flag, 1); + wake_up_interruptible(&hyb_task->swapd_wait); +} + +void wake_all_swapd(void) +{ + pg_data_t *pgdat = NULL; + int nid; + + for_each_online_node(nid) { + pgdat = NODE_DATA(nid); + wakeup_swapd(pgdat); + } +} + +bool free_swap_is_low(void) +{ + struct sysinfo info; + + si_swapinfo(&info); + + return (info.freeswap < fetch_free_swap_level_value()); +} +EXPORT_SYMBOL(free_swap_is_low); + +static inline u64 __calc_nr_to_reclaim(void) +{ + u32 curr_buffers; + u64 high_buffers; + u64 max_reclaim_size_value; + u64 reclaim_size = 0; + + high_buffers = fetch_high_mem_watermark_value(); + curr_buffers = system_cur_usable_mem(); + max_reclaim_size_value = fetch_swapd_max_reclaim_size(); + if (curr_buffers < high_buffers) + reclaim_size = high_buffers - curr_buffers; + + reclaim_size = min(reclaim_size, max_reclaim_size_value); + + return reclaim_size * SZ_1M / PAGE_SIZE; +} + +static inline u64 calc_shrink_scale(pg_data_t *pgdat) +{ + struct mem_cgroup *memcg = NULL; + const u32 percent_constant = 100; + u64 total_can_reclaimed = 0; + + while ((memcg = fetch_next_memcg(memcg))) { + s64 nr_anon, nr_zram, nr_eswap, total, can_reclaimed, thresh; + memcg_hybs_t *hybs; + + hybs = MEMCGRP_ITEM_DATA(memcg); + thresh = atomic_read(&hybs->mem2zram_scale); + if (!thresh || fetch_memcg_pagefault_status(memcg, pgdat)) { + hybs->can_reclaimed = 0; + continue; + } + + nr_anon = memcg_anon_pages(memcg); + nr_zram = hybridswap_read_mcg_stats(memcg, MCG_ZRAM_STORED_PG_SZ); + nr_eswap = hybridswap_read_mcg_stats(memcg, MCG_DISK_STORED_PG_SZ); + total = nr_anon + nr_zram + nr_eswap; + + can_reclaimed = total * thresh / percent_constant; + if (can_reclaimed <= (nr_zram + nr_eswap)) + hybs->can_reclaimed = 0; + else + hybs->can_reclaimed = can_reclaimed - (nr_zram + nr_eswap); + hybp(HYB_INFO, "memcg %s can_reclaimed %lu nr_anon %lu zram %lu eswap %lu total %lu scale %lu thresh %lu\n", + hybs->name, page_to_kb(hybs->can_reclaimed), + page_to_kb(nr_anon), page_to_kb(nr_zram), + page_to_kb(nr_eswap), page_to_kb(total), + (nr_zram + nr_eswap) * 100 / (total + 1), + thresh); + total_can_reclaimed += hybs->can_reclaimed; + } + + return total_can_reclaimed; +} + +static unsigned long swapd_shrink_anon(pg_data_t *pgdat, + unsigned long nr_to_reclaim) +{ + struct mem_cgroup *memcg = NULL; + unsigned long nr_reclaimed = 0; + unsigned long reclaim_memcg_cnt = 0; + u64 total_can_reclaimed = calc_shrink_scale(pgdat); + unsigned long start_js = jiffies; + unsigned long reclaim_cycles; + bool exit = false; + unsigned long reclaim_size_per_cycle = PAGES_PER_1MB >> 1; + + if (unlikely(total_can_reclaimed == 0)) + goto out; + + if (total_can_reclaimed < nr_to_reclaim) + nr_to_reclaim = total_can_reclaimed; + + reclaim_cycles = nr_to_reclaim / reclaim_size_per_cycle; + while (reclaim_cycles) { + while ((memcg = fetch_next_memcg(memcg))) { + unsigned long memcg_nr_reclaimed, memcg_to_reclaim; + memcg_hybs_t *hybs; + + if (high_buffer_is_suitable()) { + fetch_next_memcg_break(memcg); + exit = true; + break; + } + + hybs = MEMCGRP_ITEM_DATA(memcg); + if (!hybs->can_reclaimed) + continue; + + memcg_to_reclaim = reclaim_size_per_cycle * hybs->can_reclaimed / total_can_reclaimed; + memcg_nr_reclaimed = try_to_free_mem_cgroup_pages(memcg, + memcg_to_reclaim, GFP_KERNEL, true); + reclaim_memcg_cnt++; + hybs->can_reclaimed -= memcg_nr_reclaimed; + hybp(HYB_INFO, "memcg %s reclaim %lu want %lu\n", hybs->name, + memcg_nr_reclaimed, memcg_to_reclaim); + nr_reclaimed += memcg_nr_reclaimed; + if (nr_reclaimed >= nr_to_reclaim) { + fetch_next_memcg_break(memcg); + exit = true; + break; + } + + if (hybs->can_reclaimed < 0) + hybs->can_reclaimed = 0; + + if (swapd_nap_jiffies && time_after_eq(jiffies, start_js + swapd_nap_jiffies)) { + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout((jiffies - start_js) * 2); + start_js = jiffies; + } + } + if (exit) + break; + + if (zram_is_full()) + break; + reclaim_cycles--; + } + +out: + hybp(HYB_INFO, "total_reclaim %lu nr_to_reclaim %lu from memcg %lu total_can_reclaimed %lu\n", + page_to_kb(nr_reclaimed), page_to_kb(nr_to_reclaim), + reclaim_memcg_cnt, page_to_kb(total_can_reclaimed)); + return nr_reclaimed; +} + +static void swapd_shrink_node(pg_data_t *pgdat) +{ + const unsigned int increase_rate = 2; + unsigned long nr_reclaimed = 0; + unsigned long nr_to_reclaim; + unsigned int before_avail = system_cur_usable_mem(); + unsigned int after_avail; + +#if IS_ENABLED(CONFIG_DRM_MSM) || IS_ENABLED(CONFIG_DRM_OPLUS_NOTIFY) + if (atomic_read(&display_off)) + return; +#endif + + if (zram_is_full()) + return; + + if (high_buffer_is_suitable()) + return; + +#ifdef CONFIG_OPLUS_JANK + if (is_cpu_busy()) { + count_swapd_event(SWAPD_CPU_BUSY_BREAK_TIMES); + return; + } +#endif + + if ((jiffies - swapd_last_window_start) < swapd_shrink_window) { + if (swapd_last_window_shrink >= swapd_shrink_limit_per_window) { + count_swapd_event(SWAPD_SKIP_SHRINK_OF_WINDOW); + hybp(HYB_INFO, "swapd_last_window_shrink %lu, skip shrink\n", + swapd_last_window_shrink); + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(msecs_to_jiffies(reclaim_exceed_sleep_ms)); + return; + } + } else { + swapd_last_window_start = jiffies; + swapd_last_window_shrink = 0lu; + } + + nr_to_reclaim = __calc_nr_to_reclaim(); + if (!nr_to_reclaim) + return; + + count_swapd_event(SWAPD_SHRINK_ANON); + nr_reclaimed = swapd_shrink_anon(pgdat, nr_to_reclaim); + swapd_last_window_shrink += PAGES_TO_MB(nr_reclaimed); + + if (nr_reclaimed < fetch_nothing_ignore_check_level_value()) { + count_swapd_event(SWAPD_EMPTY_ROUND); + if (last_round_is_empty) + swapd_skip_interval = min(swapd_skip_interval * + increase_rate, + fetch_max_skip_interval_value()); + else + swapd_skip_interval = + fetch_nothing_ignore_skip_interval_value(); + last_round_is_empty = true; + } else { + swapd_skip_interval = 0; + last_round_is_empty = false; + } + + after_avail = system_cur_usable_mem(); + hybp(HYB_INFO, "total_reclaimed %lu KB, avail buffer %lu %lu MB, swapd_skip_interval %llu\n", + nr_reclaimed * 4, before_avail, after_avail, swapd_skip_interval); +} + +static int swapd(void *p) +{ + pg_data_t *pgdat = (pg_data_t *)p; + struct task_struct *tsk = current; + struct hybridswapd_task* hyb_task = PGDAT_ITEM_DATA(pgdat); + static unsigned long last_reclaimin_jiffies = 0; + long page_fault_pause_value; + int display_un_blank = 1; + + swapid = tsk->pid; + + cpumask_clear(&hyb_task->swapd_bind_cpumask); + (void)swapd_update_cpumask(tsk, SWAPD_DEFAULT_BIND_CPUS, pgdat); + set_freezable(); + + swapd_last_window_start = jiffies - swapd_shrink_window; + while (!kthread_should_stop()) { + bool pagefault = false; + u64 curr_buffers, avail; + u64 size, swapout_size = 0; + + wait_event_freezable(hyb_task->swapd_wait, + atomic_read(&hyb_task->swapd_wait_flag)); + atomic_set(&hyb_task->swapd_wait_flag, 0); + if (unlikely(kthread_should_stop())) + break; + count_swapd_event(SWAPD_WAKEUP); + + if (fetch_infos_pagefault_status() && hybridswap_scale_ok()) { + pagefault = true; + count_swapd_event(SWAPD_REFAULT); + goto do_eswap; + } + + swapd_shrink_node(pgdat); + last_swapd_time = jiffies; +do_eswap: + page_fault_pause_value = atomic_long_read(&page_fault_pause); +#if IS_ENABLED(CONFIG_DRM_MSM) || IS_ENABLED(CONFIG_DRM_OPLUS_NOTIFY) + display_un_blank = !atomic_read(&display_off); +#endif + if (!hybridswap_reclaim_work_running() && display_un_blank && + (zram_need_swapout() || pagefault) && !page_fault_pause_value && + jiffies_to_msecs(jiffies - last_reclaimin_jiffies) >= 50) { + avail = fetch_high_mem_watermark_value(); + curr_buffers = system_cur_usable_mem(); + + if (curr_buffers < avail) { + size = (avail - curr_buffers) * SZ_1M; + size = min_t(u64, size, max_reclaimin_size); +#ifdef CONFIG_HYBRIDSWAP_CORE + swapout_size = hybridswap_out_to_eswap(size); + count_swapd_event(SWAPD_SWAPOUT); + last_reclaimin_jiffies = jiffies; +#endif + hybp(HYB_DEBUG, "SWAPD_SWAPOUT curr %u avail %lu size %lu maybe swapout %lu\n", + curr_buffers, avail, + size / SZ_1M, swapout_size / SZ_1M); + } else { + hybp(HYB_INFO, "SWAPD_SKIP_SWAPOUT curr %u avail %lu\n", + curr_buffers, avail); + count_swapd_event(SWAPD_SKIP_SWAPOUT); + } + } + } + + return 0; +} + +int swapd_run(int nid) +{ + pg_data_t *pgdat = NODE_DATA(nid); + struct sched_param param = { + .sched_priority = DEFAULT_PRIO, + }; + struct hybridswapd_task* hyb_task = PGDAT_ITEM_DATA(pgdat); + int ret; + + if (!hyb_task || hyb_task->swapd) + return 0; + + atomic_set(&hyb_task->swapd_wait_flag, 0); + hyb_task->swapd = kthread_create(swapd, pgdat, "hybridswapd:%d", nid); + if (IS_ERR(hyb_task->swapd)) { + hybp(HYB_ERR, "Failed to start swapd on node %d\n", nid); + ret = PTR_ERR(hyb_task->swapd); + hyb_task->swapd = NULL; + return ret; + } + + sched_setscheduler_nocheck(hyb_task->swapd, SCHED_NORMAL, ¶m); + set_user_nice(hyb_task->swapd, PRIO_TO_NICE(param.sched_priority)); + wake_up_process(hyb_task->swapd); + + return 0; +} + +void swapd_stop(int nid) +{ + struct pglist_data *pgdata = NODE_DATA(nid); + struct task_struct *swapd; + struct hybridswapd_task* hyb_task; + + if (unlikely(!PGDAT_ITEM_DATA(pgdata))) { + hybp(HYB_ERR, "nid %d pgdata %p PGDAT_ITEM_DATA is NULL\n", + nid, pgdata); + return; + } + + hyb_task = PGDAT_ITEM_DATA(pgdata); + swapd = hyb_task->swapd; + if (swapd) { + atomic_set(&hyb_task->swapd_wait_flag, 1); + kthread_stop(swapd); + hyb_task->swapd = NULL; + } + + swapid = -1; +} + +static int mem_hotplug_swapd_notifier(struct notifier_block *nb, + unsigned long action, void *data) +{ + struct memory_notify *arg = (struct memory_notify*)data; + int nid = arg->status_change_nid; + + if (action == MEM_ONLINE) + swapd_run(nid); + else if (action == MEM_OFFLINE) + swapd_stop(nid); + + return NOTIFY_OK; +} + +static struct notifier_block swapd_notifier_nb = { + .notifier_call = mem_hotplug_swapd_notifier, +}; + +static int swapd_cpu_online(unsigned int cpu) +{ + int nid; + + for_each_node_state(nid, N_MEMORY) { + pg_data_t *pgdat = NODE_DATA(nid); + struct hybridswapd_task* hyb_task; + struct cpumask *mask; + + hyb_task = PGDAT_ITEM_DATA(pgdat); + mask = &hyb_task->swapd_bind_cpumask; + + if (cpumask_any_and(cpu_online_mask, mask) < nr_cpu_ids) + set_cpus_allowed_ptr(PGDAT_ITEM(pgdat, swapd), mask); + } + return 0; +} + +void alloc_pages_slowpath_hook(void *data, gfp_t gfp_flags, + unsigned int order, unsigned long delta) +{ + if (gfp_flags & __GFP_KSWAPD_RECLAIM) + wake_all_swapd(); +} + +void rmqueue_hook(void *data, struct zone *preferred_zone, + struct zone *zone, unsigned int order, gfp_t gfp_flags, + unsigned int alloc_flags, int migratetype) +{ + if (gfp_flags & __GFP_KSWAPD_RECLAIM) + wake_all_swapd(); +} + +static int create_swapd_thread(struct zram *zram) +{ + int nid; + int ret; + struct pglist_data *pgdat; + struct hybridswapd_task *tsk_info; + + for_each_node(nid) { + pgdat = NODE_DATA(nid); + if (!PGDAT_ITEM_DATA(pgdat)) { + tsk_info = kzalloc(sizeof(struct hybridswapd_task), + GFP_KERNEL); + if (!tsk_info) { + hybp(HYB_ERR, "kmalloc tsk_info failed node %d\n", nid); + goto error_out; + } + + pgdat->android_oem_data1 = (u64)tsk_info; + } + + init_waitqueue_head(&PGDAT_ITEM(pgdat, swapd_wait)); + } + + for_each_node_state(nid, N_MEMORY) { + if (swapd_run(nid)) + goto error_out; + } + + ret = cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE_DYN, + "mm/swapd:online", swapd_cpu_online, NULL); + if (ret < 0) { + hybp(HYB_ERR, "swapd: failed to register hotplug callbacks.\n"); + goto error_out; + } + swapd_online = ret; + + return 0; + +error_out: + for_each_node(nid) { + pgdat = NODE_DATA(node); + + if (!PGDAT_ITEM_DATA(pgdat)) + continue; + + if (PGDAT_ITEM(pgdat, swapd)) { + kthread_stop(PGDAT_ITEM(pgdat, swapd)); + PGDAT_ITEM(pgdat, swapd) = NULL; + } + + kfree((void*)PGDAT_ITEM_DATA(pgdat)); + pgdat->android_oem_data1 = 0; + } + + return -ENOMEM; +} + +static void destroy_swapd_thread(void) +{ + int nid; + struct pglist_data *pgdat; + + cpuhp_remove_state_nocalls(swapd_online); + for_each_node(nid) { + pgdat = NODE_DATA(node); + if (!PGDAT_ITEM_DATA(pgdat)) + continue; + + swapd_stop(nid); + kfree((void*)PGDAT_ITEM_DATA(pgdat)); + pgdat->android_oem_data1 = 0; + } +} + +ssize_t hybridswap_swapd_pause_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t len) +{ + char *type_buf = NULL; + bool val; + + type_buf = strstrip((char *)buf); + if (kstrtobool(type_buf, &val)) + return -EINVAL; + atomic_set(&swapd_pause, val); + + return len; +} + +ssize_t hybridswap_swapd_pause_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t size = 0; + + size += scnprintf(buf + size, PAGE_SIZE - size, + "%d\n", atomic_read(&swapd_pause)); + + return size; +} + +#if IS_ENABLED(CONFIG_DRM_MSM) || IS_ENABLED(CONFIG_DRM_OPLUS_NOTIFY) +static int bright_fb_notifier_callback(struct notifier_block *self, + unsigned long event, void *data) +{ + struct msm_drm_notifier *evdata = data; + int *blank; + + if (evdata && evdata->data) { + blank = evdata->data; + + if (*blank == MSM_DRM_BLANK_POWERDOWN) + atomic_set(&display_off, 1); + else if (*blank == MSM_DRM_BLANK_UNBLANK) + atomic_set(&display_off, 0); + } + + return NOTIFY_OK; +} +#endif + +void __init swapd_pre_init(void) +{ + all_totalreserve_pages = fetch_totalreserve_pages(); +} + +void swapd_pre_deinit(void) +{ + all_totalreserve_pages = 0; +} + +int swapd_init(struct zram *zram) +{ + int ret; + + ret = register_memory_notifier(&swapd_notifier_nb); + if (ret) { + hybp(HYB_ERR, "register_memory_notifier failed, ret = %d\n", ret); + return ret; + } + +#if IS_ENABLED(CONFIG_DRM_MSM) || IS_ENABLED(CONFIG_DRM_OPLUS_NOTIFY) + fb_notif.notifier_call = bright_fb_notifier_callback; + ret = msm_drm_register_client(&fb_notif); + if (ret) { + hybp(HYB_ERR, "msm_drm_register_client failed, ret=%d\n", ret); + goto msm_drm_register_fail; + } +#endif + + ret = refresh_daemonrun(); + if (ret) { + hybp(HYB_ERR, "refresh_daemonrun failed, ret=%d\n", ret); + goto refresh_daemonfail; + } + + ret = create_swapd_thread(zram); + if (ret) { + hybp(HYB_ERR, "create_swapd_thread failed, ret=%d\n", ret); + goto create_swapd_fail; + } + + swapd_zram = zram; + atomic_set(&swapd_enabled, 1); + return 0; + +create_swapd_fail: + refresh_daemonexit(); +refresh_daemonfail: +#if IS_ENABLED(CONFIG_DRM_MSM) || IS_ENABLED(CONFIG_DRM_OPLUS_NOTIFY) + msm_drm_unregister_client(&fb_notif); +msm_drm_register_fail: +#endif + unregister_memory_notifier(&swapd_notifier_nb); + return ret; +} + +void swapd_exit(void) +{ + destroy_swapd_thread(); + refresh_daemonexit(); +#if IS_ENABLED(CONFIG_DRM_MSM) || IS_ENABLED(CONFIG_DRM_OPLUS_NOTIFY) + msm_drm_unregister_client(&fb_notif); +#endif + unregister_memory_notifier(&swapd_notifier_nb); + atomic_set(&swapd_enabled, 0); +} + +bool hybridswap_swapd_enabled(void) +{ + return !!atomic_read(&swapd_enabled); +} diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c index e0c96c81a9a1..3c9f6b62a169 100644 --- a/drivers/block/zram/zram_drv.c +++ b/drivers/block/zram/zram_drv.c @@ -35,6 +35,10 @@ #include #include "zram_drv.h" +#include "zram_drv_internal.h" +#ifdef CONFIG_HYBRIDSWAP +#include "hybridswap/hybridswap.h" +#endif static DEFINE_IDR(zram_index_idr); /* idr index must be protected */ @@ -55,32 +59,14 @@ static void zram_free_page(struct zram *zram, size_t index); static int zram_bvec_read(struct zram *zram, struct bio_vec *bvec, u32 index, int offset, struct bio *bio); +unsigned long znr_swap_pages; +bool is_enable_zlimit; static int zram_slot_trylock(struct zram *zram, u32 index) { return bit_spin_trylock(ZRAM_LOCK, &zram->table[index].flags); } -static void zram_slot_lock(struct zram *zram, u32 index) -{ - bit_spin_lock(ZRAM_LOCK, &zram->table[index].flags); -} - -static void zram_slot_unlock(struct zram *zram, u32 index) -{ - bit_spin_unlock(ZRAM_LOCK, &zram->table[index].flags); -} - -static inline bool init_done(struct zram *zram) -{ - return zram->disksize; -} - -static inline struct zram *dev_to_zram(struct device *dev) -{ - return (struct zram *)dev_to_disk(dev)->private_data; -} - static struct zram_entry *zram_get_entry(struct zram *zram, u32 index) { return zram->table[index].entry; @@ -92,49 +78,11 @@ static void zram_set_entry(struct zram *zram, u32 index, zram->table[index].entry = entry; } -/* flag operations require table entry bit_spin_lock() being held */ -static bool zram_test_flag(struct zram *zram, u32 index, - enum zram_pageflags flag) -{ - return zram->table[index].flags & BIT(flag); -} - -static void zram_set_flag(struct zram *zram, u32 index, - enum zram_pageflags flag) -{ - zram->table[index].flags |= BIT(flag); -} - -static void zram_clear_flag(struct zram *zram, u32 index, - enum zram_pageflags flag) -{ - zram->table[index].flags &= ~BIT(flag); -} - -static inline void zram_set_element(struct zram *zram, u32 index, - unsigned long element) -{ - zram->table[index].element = element; -} - static unsigned long zram_get_element(struct zram *zram, u32 index) { return zram->table[index].element; } -static size_t zram_get_obj_size(struct zram *zram, u32 index) -{ - return zram->table[index].flags & (BIT(ZRAM_FLAG_SHIFT) - 1); -} - -static void zram_set_obj_size(struct zram *zram, - u32 index, size_t size) -{ - unsigned long flags = zram->table[index].flags >> ZRAM_FLAG_SHIFT; - - zram->table[index].flags = (flags << ZRAM_FLAG_SHIFT) | size; -} - static inline bool zram_allocated(struct zram *zram, u32 index) { return zram_get_obj_size(zram, index) || @@ -259,6 +207,11 @@ static ssize_t mem_limit_store(struct device *dev, down_write(&zram->init_lock); zram->limit_pages = PAGE_ALIGN(limit) >> PAGE_SHIFT; + if (zram->limit_pages) { + is_enable_zlimit = true; + znr_swap_pages = zram->limit_pages * 3; + } else + is_enable_zlimit = false; up_write(&zram->init_lock); return len; @@ -325,6 +278,10 @@ static ssize_t idle_store(struct device *dev, up_read(&zram->init_lock); +#ifdef CONFIG_ZWB_HANDLE + wake_up_process(zwb_clear_tsk); +#endif + return len; } @@ -785,6 +742,7 @@ next: free_block_bdev(zram, blk_idx); ret = len; __free_page(page); + ksys_sync(); release_init_lock: up_read(&zram->init_lock); @@ -1294,9 +1252,31 @@ static void zram_free_page(struct zram *zram, size_t index) atomic64_dec(&zram->stats.huge_pages); } +#ifdef CONFIG_HYBRIDSWAP_ASYNC_COMPRESS + if (zram_test_flag(zram, index, ZRAM_CACHED)) { + struct page *page = (struct page *)zram_get_page(zram, index); + + del_page_from_cache(page); + page->mem_cgroup = NULL; + put_free_page(page); + zram_clear_flag(zram, index, ZRAM_CACHED); + goto out; + } + + if (zram_test_flag(zram, index, ZRAM_CACHED_COMPRESS)) { + zram_clear_flag(zram, index, ZRAM_CACHED_COMPRESS); + goto out; + } +#endif + +#ifdef CONFIG_HYBRIDSWAP_CORE + hybridswap_untrack(zram, index); +#endif + if (zram_test_flag(zram, index, ZRAM_WB)) { zram_clear_flag(zram, index, ZRAM_WB); free_block_bdev(zram, zram_get_element(zram, index)); + atomic64_dec(&zram->stats.pages_stored); goto out; } @@ -1307,6 +1287,7 @@ static void zram_free_page(struct zram *zram, size_t index) if (zram_test_flag(zram, index, ZRAM_SAME)) { zram_clear_flag(zram, index, ZRAM_SAME); atomic64_dec(&zram->stats.same_pages); + atomic64_dec(&zram->stats.pages_stored); goto out; } @@ -1318,14 +1299,134 @@ static void zram_free_page(struct zram *zram, size_t index) atomic64_sub(zram_get_obj_size(zram, index), &zram->stats.compr_data_size); -out: atomic64_dec(&zram->stats.pages_stored); + +out: zram_set_entry(zram, index, NULL); zram_set_obj_size(zram, index, 0); WARN_ON_ONCE(zram->table[index].flags & ~(1UL << ZRAM_LOCK | 1UL << ZRAM_UNDER_WB)); } +#ifdef CONFIG_HYBRIDSWAP_ASYNC_COMPRESS +void update_zram_index(struct zram *zram, u32 index, unsigned long page) +{ + zram_slot_lock(zram, index); + put_anon_pages((struct page*)page); + + zram_free_page(zram, index); + zram_set_flag(zram, index, ZRAM_CACHED); + zram_set_page(zram, index, page); + zram_set_obj_size(zram, index, PAGE_SIZE); + zram_slot_unlock(zram, index); +} + +int async_compress_page(struct zram *zram, struct page* page) +{ + int ret = 0; + unsigned long alloced_pages; + unsigned long handle = 0; + unsigned int comp_len = 0; + void *src, *dst; + struct zcomp_strm *zstrm; + int index = get_zram_index(page); + +compress_again: + zram_slot_lock(zram, index); + if (!zram_test_flag(zram, index, ZRAM_CACHED_COMPRESS)) { + zram_slot_unlock(zram, index); + return 0; + } + zram_slot_unlock(zram, index); + + zstrm = zcomp_stream_get(zram->comp); + src = kmap_atomic(page); + ret = zcomp_compress(zstrm, src, &comp_len); + kunmap_atomic(src); + + if (unlikely(ret)) { + zcomp_stream_put(zram->comp); + pr_err("Compression failed! err=%d\n", ret); + zs_free(zram->mem_pool, handle); + return ret; + } + + if (comp_len >= huge_class_size) + comp_len = PAGE_SIZE; + + if (!handle) + handle = zs_malloc(zram->mem_pool, comp_len, + __GFP_KSWAPD_RECLAIM | + __GFP_NOWARN | + __GFP_HIGHMEM | + __GFP_MOVABLE | + __GFP_CMA); + if (!handle) { + zcomp_stream_put(zram->comp); + atomic64_inc(&zram->stats.writestall); + handle = zs_malloc(zram->mem_pool, comp_len, + GFP_NOIO | __GFP_HIGHMEM | + __GFP_MOVABLE | __GFP_CMA | + GFP_ATOMIC | ___GFP_HIGH_ATOMIC_ZRAM); + if (handle) + goto compress_again; + return -ENOMEM; + } + + alloced_pages = zs_get_total_pages(zram->mem_pool); + update_used_max(zram, alloced_pages); + + if (zram->limit_pages && alloced_pages > zram->limit_pages) { + zcomp_stream_put(zram->comp); + zs_free(zram->mem_pool, handle); + return -ENOMEM; + } + + dst = zs_map_object(zram->mem_pool, handle, ZS_MM_WO); + + src = zstrm->buffer; + if (comp_len == PAGE_SIZE) + src = kmap_atomic(page); + memcpy(dst, src, comp_len); + if (comp_len == PAGE_SIZE) + kunmap_atomic(src); + + zcomp_stream_put(zram->comp); + zs_unmap_object(zram->mem_pool, handle); + atomic64_add(comp_len, &zram->stats.compr_data_size); + + /* + * Free memory associated with this sector + * before overwriting unused sectors. + */ + zram_slot_lock(zram, index); + if (!zram_test_flag(zram, index, ZRAM_CACHED_COMPRESS)) { + atomic64_sub(comp_len, &zram->stats.compr_data_size); + zs_free(zram->mem_pool, handle); + zram_slot_unlock(zram, index); + return 0; + } + zram_free_page(zram, index); + + if (comp_len == PAGE_SIZE) { + zram_set_flag(zram, index, ZRAM_HUGE); + atomic64_inc(&zram->stats.huge_pages); + } + + zram_set_handle(zram, index, handle); + zram_set_obj_size(zram, index, comp_len); +#ifdef CONFIG_HYBRIDSWAP_CORE + hybridswap_record(zram, index, page->mem_cgroup); +#endif + zram_slot_unlock(zram, index); + + /* Update stats */ + atomic64_inc(&zram->stats.pages_stored); + + return ret; +} +#endif + static int __zram_bvec_read(struct zram *zram, struct page *page, u32 index, struct bio *bio, bool partial_io) { @@ -1335,6 +1436,22 @@ static int __zram_bvec_read(struct zram *zram, struct page *page, u32 index, void *src, *dst; zram_slot_lock(zram, index); +#ifdef CONFIG_HYBRIDSWAP_ASYNC_COMPRESS + if (akcompress_cache_page_fault(zram, page, index)) + return 0; +#endif + +#ifdef CONFIG_HYBRIDSWAP_CORE + if (likely(!bio)) { + ret = hybridswap_page_fault(zram, index); + if (unlikely(ret)) { + pr_err("search in hybridswap failed! err=%d, page=%u\n", + ret, index); + zram_slot_unlock(zram, index); + return ret; + } + } +#endif if (zram_test_flag(zram, index, ZRAM_WB)) { struct bio_vec bvec; @@ -1451,6 +1568,13 @@ static int __zram_bvec_write(struct zram *zram, struct bio_vec *bvec, goto out; } +#ifdef CONFIG_HYBRIDSWAP_ASYNC_COMPRESS + if ((current_is_kswapd() || current_is_swapd(current)) && + add_anon_page2cache(zram, index, page)) { + return 0; + } +#endif + compress_again: zstrm = zcomp_stream_get(zram->comp); src = kmap_atomic(page); @@ -1492,7 +1616,7 @@ compress_again: atomic64_inc(&zram->stats.writestall); entry = zram_entry_alloc(zram, comp_len, GFP_NOIO | __GFP_HIGHMEM | - __GFP_MOVABLE | __GFP_CMA); + __GFP_MOVABLE | __GFP_CMA | GFP_ATOMIC | ___GFP_HIGH_ATOMIC_ZRAM); if (entry) goto compress_again; return -ENOMEM; @@ -1501,6 +1625,14 @@ compress_again: alloced_pages = zs_get_total_pages(zram->mem_pool); update_used_max(zram, alloced_pages); + if (is_enable_zlimit) { + if (alloced_pages < zram->limit_pages) + znr_swap_pages = (zram->limit_pages + - alloced_pages) * 3; + else + znr_swap_pages = 0; + } + if (zram->limit_pages && alloced_pages > zram->limit_pages) { zcomp_stream_put(zram->comp); zram_entry_free(zram, entry); @@ -1541,6 +1673,10 @@ out: zram_set_entry(zram, index, entry); zram_set_obj_size(zram, index, comp_len); } + +#ifdef CONFIG_HYBRIDSWAP_CORE + hybridswap_record(zram, index, page->mem_cgroup); +#endif zram_slot_unlock(zram, index); /* Update stats */ @@ -1747,6 +1883,13 @@ static void zram_slot_free_notify(struct block_device *bdev, return; } +#ifdef CONFIG_HYBRIDSWAP_CORE + if (!hybridswap_delete(zram, index)) { + zram_slot_unlock(zram, index); + atomic64_inc(&zram->stats.miss_free); + return; + } +#endif zram_free_page(zram, index); zram_slot_unlock(zram, index); } @@ -1810,6 +1953,7 @@ static void zram_reset_device(struct zram *zram) down_write(&zram->init_lock); zram->limit_pages = 0; + is_enable_zlimit = false; if (!init_done(zram)) { up_write(&zram->init_lock); @@ -1967,6 +2111,27 @@ static DEVICE_ATTR_RW(use_dedup); #else static DEVICE_ATTR_RO(use_dedup); #endif +#ifdef CONFIG_HYBRIDSWAP +static DEVICE_ATTR_RO(hybridswap_vmstat); +static DEVICE_ATTR_RW(hybridswap_loglevel); +static DEVICE_ATTR_RW(hybridswap_enable); +#endif +#ifdef CONFIG_HYBRIDSWAP_SWAPD +static DEVICE_ATTR_RW(hybridswap_swapd_pause); +#endif +#ifdef CONFIG_HYBRIDSWAP_CORE +static DEVICE_ATTR_RW(hybridswap_core_enable); +static DEVICE_ATTR_RW(hybridswap_loop_device); +static DEVICE_ATTR_RW(hybridswap_dev_life); +static DEVICE_ATTR_RW(hybridswap_quota_day); +static DEVICE_ATTR_RO(hybridswap_report); +static DEVICE_ATTR_RO(hybridswap_stat_snap); +static DEVICE_ATTR_RO(hybridswap_meminfo); +static DEVICE_ATTR_RW(hybridswap_zram_increase); +#endif +#ifdef CONFIG_HYBRIDSWAP_ASYNC_COMPRESS +static DEVICE_ATTR_RW(hybridswap_akcompress); +#endif static struct attribute *zram_disk_attrs[] = { &dev_attr_disksize.attr, @@ -1991,6 +2156,27 @@ static struct attribute *zram_disk_attrs[] = { &dev_attr_bd_stat.attr, #endif &dev_attr_debug_stat.attr, +#ifdef CONFIG_HYBRIDSWAP + &dev_attr_hybridswap_vmstat.attr, + &dev_attr_hybridswap_loglevel.attr, + &dev_attr_hybridswap_enable.attr, +#endif +#ifdef CONFIG_HYBRIDSWAP_SWAPD + &dev_attr_hybridswap_swapd_pause.attr, +#endif +#ifdef CONFIG_HYBRIDSWAP_CORE + &dev_attr_hybridswap_core_enable.attr, + &dev_attr_hybridswap_report.attr, + &dev_attr_hybridswap_meminfo.attr, + &dev_attr_hybridswap_stat_snap.attr, + &dev_attr_hybridswap_loop_device.attr, + &dev_attr_hybridswap_dev_life.attr, + &dev_attr_hybridswap_quota_day.attr, + &dev_attr_hybridswap_zram_increase.attr, +#endif +#ifdef CONFIG_HYBRIDSWAP_ASYNC_COMPRESS + &dev_attr_hybridswap_akcompress.attr, +#endif NULL, }; @@ -2132,6 +2318,9 @@ static int zram_remove(struct zram *zram) del_gendisk(zram->disk); blk_cleanup_queue(zram->disk->queue); put_disk(zram->disk); +#ifdef CONFIG_HYBRIDSWAP_ASYNC_COMPRESS + destroy_akcompressd_task(zram); +#endif kfree(zram); return 0; } @@ -2255,6 +2444,11 @@ static int __init zram_init(void) num_devices--; } +#ifdef CONFIG_HYBRIDSWAP + ret = hybridswap_pre_init(); + if (ret) + goto out_error; +#endif return 0; out_error: diff --git a/drivers/block/zram/zram_drv.h b/drivers/block/zram/zram_drv.h index 22f8366d7971..ed9a8fd4f8fa 100644 --- a/drivers/block/zram/zram_drv.h +++ b/drivers/block/zram/zram_drv.h @@ -52,7 +52,16 @@ enum zram_pageflags { ZRAM_UNDER_WB, /* page is under writeback */ ZRAM_HUGE, /* Incompressible page */ ZRAM_IDLE, /* not accessed page since last idle marking */ - +#ifdef CONFIG_HYBRIDSWAP_ASYNC_COMPRESS + ZRAM_CACHED, /* page is cached in async compress cache buffer */ + ZRAM_CACHED_COMPRESS, /* page is under async compress */ +#endif +#ifdef CONFIG_HYBRIDSWAP_CORE + ZRAM_BATCHING_OUT, + ZRAM_FROM_HYBRIDSWAP, + ZRAM_MCGID_CLEAR, + ZRAM_IN_BD, /* zram stored in back device */ +#endif __NR_ZRAM_PAGEFLAGS, }; @@ -71,6 +80,9 @@ struct zram_table_entry { union { struct zram_entry *entry; unsigned long element; +#ifdef CONFIG_HYBRIDSWAP_ASYNC_COMPRESS + unsigned long page; +#endif }; unsigned long flags; #ifdef CONFIG_ZRAM_MEMORY_TRACKING @@ -148,6 +160,15 @@ struct zram { #ifdef CONFIG_ZRAM_MEMORY_TRACKING struct dentry *debugfs_dir; #endif +#if (defined CONFIG_ZRAM_WRITEBACK) || (defined CONFIG_HYBRIDSWAP_CORE) + struct block_device *bdev; + unsigned int old_block_size; + unsigned long nr_pages; + unsigned long increase_nr_pages; +#endif +#ifdef CONFIG_HYBRIDSWAP_CORE + struct hyb_info *infos; +#endif }; static inline bool zram_dedup_enabled(struct zram *zram) @@ -160,4 +181,11 @@ static inline bool zram_dedup_enabled(struct zram *zram) } void zram_entry_free(struct zram *zram, struct zram_entry *entry); + +#ifdef CONFIG_ZRAM_WRITEBACK +void ksys_sync(void); +#endif +#ifdef CONFIG_ZWB_HANDLE +extern struct task_struct *zwb_clear_tsk; +#endif #endif diff --git a/drivers/block/zram/zram_drv_internal.h b/drivers/block/zram/zram_drv_internal.h new file mode 100644 index 000000000000..23ce13969f0a --- /dev/null +++ b/drivers/block/zram/zram_drv_internal.h @@ -0,0 +1,42 @@ +#ifndef _ZRAM_DRV_INTERNAL_H_ +#define _ZRAM_DRV_INTERNAL_H_ + +#include "zram_drv.h" + +#ifdef BIT +#undef BIT +#define BIT(nr) (1lu << (nr)) +#endif + +#define zram_slot_lock(zram, index) (bit_spin_lock(ZRAM_LOCK, &zram->table[index].flags)) + +#define zram_slot_unlock(zram, index) (bit_spin_unlock(ZRAM_LOCK, &zram->table[index].flags)) + +#define init_done(zram) (zram->disksize) + +#define dev_to_zram(dev) ((struct zram *)dev_to_disk(dev)->private_data) + +#define zram_get_handle(zram, index) ((unsigned long)(zram->table[index].entry)) + +#define zram_set_handle(zram, index, handle_val) (zram->table[index].entry = (struct zram_entry *)handle_val) + +#define zram_test_flag(zram, index, flag) (zram->table[index].flags & BIT(flag)) + +#define zram_set_flag(zram, index, flag) (zram->table[index].flags |= BIT(flag)) + +#define zram_clear_flag(zram, index, flag) (zram->table[index].flags &= ~BIT(flag)) + +#define zram_set_element(zram, index, element) (zram->table[index].element = element) + +#define zram_get_obj_size(zram, index) (zram->table[index].flags & (BIT(ZRAM_FLAG_SHIFT) - 1)) + +#define zram_set_obj_size(zram, index, size) do {\ + unsigned long flags = zram->table[index].flags >> ZRAM_FLAG_SHIFT; \ + zram->table[index].flags = (flags << ZRAM_FLAG_SHIFT) | size; \ +} while(0) + +#ifdef CONFIG_HYBRIDSWAP_ASYNC_COMPRESS +extern int async_compress_page(struct zram *zram, struct page* page); +extern void update_zram_index(struct zram *zram, u32 index, unsigned long page); +#endif +#endif /* _ZRAM_DRV_INTERNAL_H_ */ diff --git a/drivers/block/zram/zwb_handle b/drivers/block/zram/zwb_handle new file mode 120000 index 000000000000..78e1f952251e --- /dev/null +++ b/drivers/block/zram/zwb_handle @@ -0,0 +1 @@ +../../../../../vendor/oplus/kernel/oplus_performance/zwb_handle/ \ No newline at end of file diff --git a/drivers/bluetooth/bluetooth-power.c b/drivers/bluetooth/bluetooth-power.c index f66ff5c3e34e..474008b35c6d 100644 --- a/drivers/bluetooth/bluetooth-power.c +++ b/drivers/bluetooth/bluetooth-power.c @@ -659,10 +659,13 @@ vdd_xtal_fail: bt_vreg_unvote(bt_power_pdata->bt_vdd_rfa2); if (bt_power_pdata->bt_vdd_rfa1) bt_vreg_unvote(bt_power_pdata->bt_vdd_rfa1); + /* + * if did't have pm8009 dig power and aon power disable enter Retention mode if (bt_power_pdata->bt_vdd_dig) bt_vreg_unvote(bt_power_pdata->bt_vdd_dig); if (bt_power_pdata->bt_vdd_aon) bt_vreg_unvote(bt_power_pdata->bt_vdd_aon); + */ } else { BT_PWR_ERR("Invalid power mode: %d", on); rc = -1; diff --git a/drivers/bluetooth/btfm_slim_codec.c b/drivers/bluetooth/btfm_slim_codec.c index 1b38246db8db..5d456ae85656 100644 --- a/drivers/bluetooth/btfm_slim_codec.c +++ b/drivers/bluetooth/btfm_slim_codec.c @@ -210,9 +210,9 @@ static int btfm_slim_dai_prepare(struct snd_pcm_substream *substream, /* save the enable channel status */ if (ret == 0) bt_soc_enable_status = 1; - if (ret == -EISCONN) { - BTFMSLIM_ERR("channel opened without closing, return success"); + BTFMSLIM_ERR("channel opened without closing, returning success"); + ret = 0; } return ret; diff --git a/drivers/bus/mhi/core/mhi_init.c b/drivers/bus/mhi/core/mhi_init.c index a27b96345f2f..0d9a14809fc5 100644 --- a/drivers/bus/mhi/core/mhi_init.c +++ b/drivers/bus/mhi/core/mhi_init.c @@ -1573,7 +1573,7 @@ int of_register_mhi_controller(struct mhi_controller *mhi_cntrl) init_waitqueue_head(&mhi_cntrl->state_event); mhi_cntrl->wq = alloc_ordered_workqueue("mhi_w", - WQ_MEM_RECLAIM | WQ_HIGHPRI); + WQ_HIGHPRI); if (!mhi_cntrl->wq) goto error_alloc_cmd; diff --git a/drivers/bus/mhi/core/mhi_pm.c b/drivers/bus/mhi/core/mhi_pm.c index 710d17cb14bb..4c0bcbb52e75 100644 --- a/drivers/bus/mhi/core/mhi_pm.c +++ b/drivers/bus/mhi/core/mhi_pm.c @@ -1045,6 +1045,10 @@ error_dev_ctxt: } EXPORT_SYMBOL(mhi_async_power_up); +#ifdef OPLUS_BUG_STABILITY +extern bool direct_panic; +#endif + /* Transition MHI into error state and notify critical clients */ void mhi_control_error(struct mhi_controller *mhi_cntrl) { @@ -1060,6 +1064,11 @@ void mhi_control_error(struct mhi_controller *mhi_cntrl) memcpy(sfr_info->str, sfr_info->buf_addr, sfr_info->len); MHI_CNTRL_ERR("mhi:%s sfr: %s\n", mhi_cntrl->name, sfr_info->buf_addr); +#ifdef OPLUS_BUG_STABILITY + if(strstr(sfr_info->buf_addr, "remotefs_sahara.c")) { + direct_panic = true; + } +#endif } /* link is not down if device supports RDDM */ @@ -1142,10 +1151,18 @@ int mhi_sync_power_up(struct mhi_controller *mhi_cntrl) if (ret) return ret; +#ifndef OPLUS_BUG_STABILITY + //Modify for: mhi timeout 10s to 20s wait_event_timeout(mhi_cntrl->state_event, MHI_IN_MISSION_MODE(mhi_cntrl->ee) || MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state), msecs_to_jiffies(mhi_cntrl->timeout_ms)); +#else /* OPLUS_BUG_STABILITY */ + wait_event_timeout(mhi_cntrl->state_event, + MHI_IN_MISSION_MODE(mhi_cntrl->ee) || + MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state), + msecs_to_jiffies(20000)); +#endif /* OPLUS_BUG_STABILITY */ if (MHI_IN_MISSION_MODE(mhi_cntrl->ee)) return 0; diff --git a/drivers/bus/mhi/devices/mhi_uci.c b/drivers/bus/mhi/devices/mhi_uci.c index 2a7fbfa7062a..1ee002eda187 100644 --- a/drivers/bus/mhi/devices/mhi_uci.c +++ b/drivers/bus/mhi/devices/mhi_uci.c @@ -65,7 +65,12 @@ enum MHI_DEBUG_LEVEL msg_lvl = MHI_MSG_LVL_ERROR; #ifdef CONFIG_MHI_DEBUG -#define MHI_UCI_IPC_LOG_PAGES (25) +#ifdef OPLUS_BUG_STABILITY +#define MHI_UCI_IPC_LOG_PAGES (100) +#else +#define MHI_UCI_IPC_LOG_PAGES (25) +#endif /* OPLUS_BUG_STABILITY */ + #define MSG_VERB(fmt, ...) do { \ if (msg_lvl <= MHI_MSG_LVL_VERBOSE) \ pr_err("[D][%s] " fmt, __func__, ##__VA_ARGS__); \ diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c index d87f71f3f2c9..619bf6ef7f8e 100644 --- a/drivers/char/adsprpc.c +++ b/drivers/char/adsprpc.c @@ -3853,6 +3853,7 @@ static int fastrpc_file_free(struct fastrpc_file *fl) mutex_destroy(&fl->map_mutex); mutex_destroy(&fl->pm_qos_mutex); mutex_destroy(&fl->internal_map_mutex); + mutex_destroy(&fl->pm_qos_mutex); kfree(fl); return 0; } diff --git a/drivers/char/diag/diag_ipc_logging.h b/drivers/char/diag/diag_ipc_logging.h index 2e0b7ee4b822..5fa3d42cda90 100644 --- a/drivers/char/diag/diag_ipc_logging.h +++ b/drivers/char/diag/diag_ipc_logging.h @@ -7,7 +7,11 @@ #include +#if defined(CONFIG_MHI_DEBUG) && defined(OPLUS_BUG_STABILITY) +#define DIAG_IPC_LOG_PAGES 200 +#else #define DIAG_IPC_LOG_PAGES 50 +#endif /* CONFIG_MHI_DEBUG and OPLUS_BUG_STABILITY */ #define DIAG_DEBUG_USERSPACE 0x0001 #define DIAG_DEBUG_MUX 0x0002 diff --git a/drivers/char/diag/diagfwd_bridge.c b/drivers/char/diag/diagfwd_bridge.c index 7635f6d87faf..71a47570f9c9 100644 --- a/drivers/char/diag/diagfwd_bridge.c +++ b/drivers/char/diag/diagfwd_bridge.c @@ -22,6 +22,9 @@ #include "diagfwd_mhi.h" #include "diag_dci.h" #include "diag_ipc_logging.h" +#ifdef OPLUS_FEATURE_CHG_BASIC +#include "diagfwd.h" +#endif #ifdef CONFIG_MHI_BUS #define diag_mdm_init diag_mhi_init @@ -310,6 +313,29 @@ int diagfwd_bridge_close(int id) int diagfwd_bridge_write(int id, unsigned char *buf, int len) { +#ifdef OPLUS_FEATURE_CHG_BASIC + uint16_t cmd_code; + uint16_t subsys_id; + uint16_t cmd_code_lo; + uint16_t cmd_code_hi; + unsigned char *temp = NULL; + + temp = buf; + cmd_code = (uint16_t)(*(uint8_t *)temp); + temp += sizeof(uint8_t); + subsys_id = (uint16_t)(*(uint8_t *)temp); + temp += sizeof(uint8_t); + cmd_code_hi = (uint16_t)(*(uint16_t *)temp); + cmd_code_lo = (uint16_t)(*(uint16_t *)temp); + if (cmd_code == 0x4b && subsys_id == 0xb && cmd_code_hi == 0x35 && cmd_code_lo == 0x35) { + pr_err("diag command with 75 11 53\n"); + if (!driver->hdlc_disabled) + diag_process_hdlc_pkt(buf, len, 0); + else + diag_process_non_hdlc_pkt(buf, len, 0); + } +#endif /* OPLUS_FEATURE_CHG_BASIC */ + if (id < 0 || id >= NUM_REMOTE_DEV) return -EINVAL; if (bridge_info[id].dev_ops && bridge_info[id].dev_ops->write) { diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index 95f42baff399..474e9769e29b 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -28,6 +28,7 @@ #include #include #include +#include #include "clk.h" @@ -103,6 +104,9 @@ struct clk_core { #ifdef CONFIG_DEBUG_FS struct dentry *dentry; struct hlist_node debug_node; +#elif defined OPLUS_FEATURE_POWERINFO_RPMH + struct proc_dir_entry *dentry; + struct hlist_node debug_node; #endif struct kref ref; struct clk_vdd_class *vdd_class; @@ -4038,6 +4042,825 @@ static int __init clk_debug_init(void) return 0; } late_initcall(clk_debug_init); +#elif defined OPLUS_FEATURE_POWERINFO_RPMH +static struct proc_dir_entry *rootdir; +static int inited = 0; +static u32 debug_suspend; +static DEFINE_MUTEX(clk_debug_lock); +static HLIST_HEAD(clk_debug_list); + +static struct hlist_head *all_lists[] = { + &clk_root_list, + &clk_orphan_list, + NULL, +}; + +static void clk_state_subtree(struct clk_core *c) +{ + int vdd_level = 0; + struct clk_core *child; + + if (!c) + return; + + if (c->vdd_class) { + vdd_level = clk_find_vdd_level(c, c->rate); + if (vdd_level < 0) + vdd_level = 0; + } + + trace_clk_state(c->name, c->prepare_count, c->enable_count, + c->rate, vdd_level); + + hlist_for_each_entry(child, &c->children, child_node) + clk_state_subtree(child); +} + +static int clk_state_show(struct seq_file *s, void *data) +{ + struct clk_core *c; + struct hlist_head **lists = (struct hlist_head **)s->private; + + clk_prepare_lock(); + + for (; *lists; lists++) + hlist_for_each_entry(c, *lists, child_node) + clk_state_subtree(c); + + clk_prepare_unlock(); + + return 0; +} + + +static int clk_state_open(struct inode *inode, struct file *file) +{ + return single_open(file, clk_state_show, inode->i_private); +} + +static const struct file_operations clk_state_fops = { + .open = clk_state_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static void clk_summary_show_one(struct seq_file *s, struct clk_core *c, + int level) +{ + if (!c) + return; + + seq_printf(s, "%*s%-*s %7d %8d %8d %11lu %10lu %5d %6d\n", + level * 3 + 1, "", + 30 - level * 3, c->name, + c->enable_count, c->prepare_count, c->protect_count, + clk_core_get_rate(c), clk_core_get_accuracy(c), + clk_core_get_phase(c), + clk_core_get_scaled_duty_cycle(c, 100000)); +} + +static void clk_summary_show_subtree(struct seq_file *s, struct clk_core *c, + int level) +{ + struct clk_core *child; + + if (!c) + return; + + if (c->ops->bus_vote) + c->ops->bus_vote(c->hw, true); + clk_summary_show_one(s, c, level); + + hlist_for_each_entry(child, &c->children, child_node) + clk_summary_show_subtree(s, child, level + 1); + if (c->ops->bus_vote) + c->ops->bus_vote(c->hw, false); +} + +static int clk_summary_show(struct seq_file *s, void *data) +{ + struct clk_core *c; + struct hlist_head **lists = (struct hlist_head **)s->private; + + seq_puts(s, " enable prepare protect duty\n"); + seq_puts(s, " clock count count count rate accuracy phase cycle\n"); + seq_puts(s, "---------------------------------------------------------------------------------------------\n"); + + clk_prepare_lock(); + + for (; *lists; lists++) + hlist_for_each_entry(c, *lists, child_node) + clk_summary_show_subtree(s, c, 0); + + clk_prepare_unlock(); + + return 0; +} +DEFINE_PROC_SHOW_ATTRIBUTE(clk_summary); + +static void clk_dump_one(struct seq_file *s, struct clk_core *c, int level) +{ + if (!c) + return; + + /* This should be JSON format, i.e. elements separated with a comma */ + seq_printf(s, "\"%s\": { ", c->name); + seq_printf(s, "\"enable_count\": %d,", c->enable_count); + seq_printf(s, "\"prepare_count\": %d,", c->prepare_count); + seq_printf(s, "\"protect_count\": %d,", c->protect_count); + seq_printf(s, "\"rate\": %lu,", clk_core_get_rate(c)); + seq_printf(s, "\"accuracy\": %lu,", clk_core_get_accuracy(c)); + seq_printf(s, "\"phase\": %d,", clk_core_get_phase(c)); + seq_printf(s, "\"duty_cycle\": %u", + clk_core_get_scaled_duty_cycle(c, 100000)); +} + +static void clk_dump_subtree(struct seq_file *s, struct clk_core *c, int level) +{ + struct clk_core *child; + + if (!c) + return; + + if (c->ops->bus_vote) + c->ops->bus_vote(c->hw, true); + + clk_dump_one(s, c, level); + + hlist_for_each_entry(child, &c->children, child_node) { + seq_putc(s, ','); + clk_dump_subtree(s, child, level + 1); + } + + seq_putc(s, '}'); + + if (c->ops->bus_vote) + c->ops->bus_vote(c->hw, false); +} + +static int clk_dump_show(struct seq_file *s, void *data) +{ + struct clk_core *c; + bool first_node = true; + struct hlist_head **lists = (struct hlist_head **)s->private; + + seq_putc(s, '{'); + clk_prepare_lock(); + + for (; *lists; lists++) { + hlist_for_each_entry(c, *lists, child_node) { + if (!first_node) + seq_putc(s, ','); + first_node = false; + clk_dump_subtree(s, c, 0); + } + } + + clk_prepare_unlock(); + + seq_puts(s, "}\n"); + return 0; +} +DEFINE_PROC_SHOW_ATTRIBUTE(clk_dump); + +static const struct { + unsigned long flag; + const char *name; +} clk_flags[] = { +#define ENTRY(f) { f, #f } + ENTRY(CLK_SET_RATE_GATE), + ENTRY(CLK_SET_PARENT_GATE), + ENTRY(CLK_SET_RATE_PARENT), + ENTRY(CLK_IGNORE_UNUSED), + ENTRY(CLK_IS_BASIC), + ENTRY(CLK_GET_RATE_NOCACHE), + ENTRY(CLK_SET_RATE_NO_REPARENT), + ENTRY(CLK_GET_ACCURACY_NOCACHE), + ENTRY(CLK_RECALC_NEW_RATES), + ENTRY(CLK_SET_RATE_UNGATE), + ENTRY(CLK_IS_CRITICAL), + ENTRY(CLK_OPS_PARENT_ENABLE), + ENTRY(CLK_DUTY_CYCLE_PARENT), +#undef ENTRY +}; + +static int clk_flags_show(struct seq_file *s, void *data) +{ + struct clk_core *core = s->private; + unsigned long flags = core->flags; + unsigned int i; + + for (i = 0; flags && i < ARRAY_SIZE(clk_flags); i++) { + if (flags & clk_flags[i].flag) { + seq_printf(s, "%s\n", clk_flags[i].name); + flags &= ~clk_flags[i].flag; + } + } + if (flags) { + /* Unknown flags */ + seq_printf(s, "0x%lx\n", flags); + } + + return 0; +} +DEFINE_PROC_SHOW_ATTRIBUTE(clk_flags); + +static int possible_parents_show(struct seq_file *s, void *data) +{ + struct clk_core *core = s->private; + int i; + + for (i = 0; i < core->num_parents - 1; i++) + seq_printf(s, "%s ", core->parent_names[i]); + + seq_printf(s, "%s\n", core->parent_names[i]); + + return 0; +} +DEFINE_PROC_SHOW_ATTRIBUTE(possible_parents); + +static int clk_duty_cycle_show(struct seq_file *s, void *data) +{ + struct clk_core *core = s->private; + struct clk_duty *duty = &core->duty; + + seq_printf(s, "%u/%u\n", duty->num, duty->den); + + return 0; +} +DEFINE_PROC_SHOW_ATTRIBUTE(clk_duty_cycle); + +static ssize_t clock_debug_rate_store(struct file *file, + const char __user *buffer, size_t count, loff_t *ppos) +{ + char buff_temp[8]; + char *end; + u64 val; + int ret ; + struct clk_core *core = ((struct seq_file *)file->private_data)->private; + + if(count <= 0 || buffer == NULL){ + pr_err("Input buf is NULL\n"); + return 0; + } + + copy_from_user(buff_temp, buffer, 8); + val = simple_strtoll(buff_temp, &end, 0); + + clk_prepare_lock(); + if (core->ops->bus_vote) + core->ops->bus_vote(core->hw, true); + + ret = clk_set_rate(core->hw->clk, val); + if (ret) + pr_err("clk_set_rate(%llu) failed (%d)\n", + (unsigned long)val, ret); + + if (core->ops->bus_vote) + core->ops->bus_vote(core->hw, false); + clk_prepare_unlock(); + + return count; +} + +static int clock_debug_rate_show(struct seq_file *file, void *v) +{ + struct clk_core *core = file->private; + u64 val; + + clk_prepare_lock(); + if (core->ops->bus_vote) + core->ops->bus_vote(core->hw, true); + + val = clk_get_rate(core->hw->clk); + + if (core->ops->bus_vote) + core->ops->bus_vote(core->hw, false); + clk_prepare_unlock(); + + seq_printf(file, "%llu\n", val); + return 0; +} + +static int clock_debug_rate_open(struct inode *inode, struct file *file) +{ + return single_open(file, clock_debug_rate_show, PDE_DATA(inode)); +} + +static const struct file_operations clock_rate_fops = { + .open = clock_debug_rate_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .write = clock_debug_rate_store, +}; + + +static int clock_parent_show(struct seq_file *file, void *v) +{ + char name[256] = {0}; + struct clk_core *core = file->private; + struct clk_core *p = core->hw->core->parent; + + snprintf(name, sizeof(name), "%s\n", p ? p->name : "None\n"); + + seq_printf(file, "%d\n", name); + return 0; + //return simple_read_from_buffer(ubuf, cnt, ppos, name, strlen(name)); +} +DEFINE_PROC_SHOW_ATTRIBUTE(clock_parent); + +static ssize_t clock_enable_store(struct file *file, + const char __user *buffer, size_t count, loff_t *ppos) +{ + char buff_temp[8]; + char *end; + u64 val; + + struct clk_core *core = ((struct seq_file *)file->private_data)->private; + int rc = 0; + + + if(count <= 0 || buffer == NULL){ + pr_err("Input buf is NULL\n"); + return 0; + } + + copy_from_user(buff_temp, buffer, 8); + val = simple_strtoll(buff_temp, &end, 0); + + clk_prepare_lock(); + if (core->ops->bus_vote) + core->ops->bus_vote(core->hw, true); + + if (val) + rc = clk_prepare_enable(core->hw->clk); + else + clk_disable_unprepare(core->hw->clk); + + if (core->ops->bus_vote) + core->ops->bus_vote(core->hw, false); + clk_prepare_unlock(); + + return count; +} + +static int clock_enable_show(struct seq_file *file, void *v) +{ + struct clk_core *core = file->private; + int enabled = 0; + + enabled = core->enable_count; + + seq_printf(file, "%d\n", enabled); + return 0; +} + +DEFINE_PROC_SHOW_STORE_ATTRIBUTE(clock_enable); + +#define clock_debug_output(m, c, fmt, ...) \ +do { \ + if (m) \ + seq_printf(m, fmt, ##__VA_ARGS__); \ + else if (c) \ + pr_cont(fmt, ##__VA_ARGS__); \ + else \ + pr_info(fmt, ##__VA_ARGS__); \ +} while (0) + +static int clock_debug_print_clock(struct clk_core *c, struct seq_file *s) +{ + char *start = ""; + struct clk *clk; + + if (!c || !c->prepare_count) + return 0; + + clk = c->hw->clk; + + clock_debug_output(s, 0, " "); + + do { + if (clk->core->vdd_class) + clock_debug_output(s, 1, "%s%s:%u:%u [%ld, %d]", start, + clk->core->name, + clk->core->prepare_count, + clk->core->enable_count, + clk->core->rate, + clk_find_vdd_level(clk->core, clk->core->rate)); + else + clock_debug_output(s, 1, "%s%s:%u:%u [%ld]", start, + clk->core->name, + clk->core->prepare_count, + clk->core->enable_count, + clk->core->rate); + start = " -> "; + } while ((clk = clk_get_parent(clk))); + + clock_debug_output(s, 1, "\n"); + + return 1; +} + +/* + * clock_debug_print_enabled_clocks() - Print names of enabled clocks + */ +static void clock_debug_print_enabled_clocks(struct seq_file *s) +{ + struct clk_core *core; + int cnt = 0; + + if (!mutex_trylock(&clk_debug_lock)) + return; + + clock_debug_output(s, 0, "Enabled clocks:\n"); + + hlist_for_each_entry(core, &clk_debug_list, debug_node) + cnt += clock_debug_print_clock(core, s); + + mutex_unlock(&clk_debug_lock); + + if (cnt) + clock_debug_output(s, 0, "Enabled clock count: %d\n", cnt); + else + clock_debug_output(s, 0, "No clocks enabled.\n"); +} + +static int clk_enabled_list_show(struct seq_file *s, void *unused) +{ + clock_debug_print_enabled_clocks(s); + + return 0; +} +DEFINE_PROC_SHOW_ATTRIBUTE(clk_enabled_list); + +void clk_debug_print_hw(struct clk_core *clk, struct seq_file *f) +{ + if (IS_ERR_OR_NULL(clk)) + return; + + clk_debug_print_hw(clk->parent, f); + + clock_debug_output(f, false, "%s\n", clk->name); + + if (!clk->ops->list_registers) + return; + + clk->ops->list_registers(f, clk->hw); +} +EXPORT_SYMBOL(clk_debug_print_hw); + +static int clock_print_hw_show(struct seq_file *m, void *unused) +{ + struct clk_core *c = m->private; + struct clk_core *clk; + + clk_prepare_lock(); + for (clk = c; clk; clk = clk->parent) + if (clk->ops->bus_vote) + clk->ops->bus_vote(clk->hw, true); + + clk_debug_print_hw(c, m); + + for (clk = c; clk; clk = clk->parent) + if (clk->ops->bus_vote) + clk->ops->bus_vote(c->hw, false); + clk_prepare_unlock(); + + return 0; +} +DEFINE_PROC_SHOW_ATTRIBUTE(clock_print_hw); + +static int list_rates_show(struct seq_file *s, void *unused) +{ + struct clk_core *core = s->private; + int level = 0, i = 0; + unsigned long rate, rate_max = 0; + + /* Find max frequency supported within voltage constraints. */ + if (!core->vdd_class) { + rate_max = ULONG_MAX; + } else { + for (level = 0; level < core->num_rate_max; level++) + if (core->rate_max[level]) + rate_max = core->rate_max[level]; + } + + /* + * List supported frequencies <= rate_max. Higher frequencies may + * appear in the frequency table, but are not valid and should not + * be listed. + */ + while (!IS_ERR_VALUE(rate = + core->ops->list_rate(core->hw, i++, rate_max))) { + if (rate <= 0) + break; + if (rate <= rate_max) + seq_printf(s, "%lu\n", rate); + } + + return 0; +} +DEFINE_PROC_SHOW_ATTRIBUTE(list_rates); + +static void clock_print_rate_max_by_level(struct seq_file *s, int level) +{ + struct clk_core *core = s->private; + struct clk_vdd_class *vdd_class = core->vdd_class; + int off, i, vdd_level, nregs = vdd_class->num_regulators; + + vdd_level = clk_find_vdd_level(core, core->rate); + + seq_printf(s, "%2s%10lu", vdd_level == level ? "[" : "", + core->rate_max[level]); + + for (i = 0; i < nregs; i++) { + off = nregs*level + i; + if (vdd_class->vdd_uv) + seq_printf(s, "%10u", vdd_class->vdd_uv[off]); + } + + if (vdd_level == level) + seq_puts(s, "]"); + + seq_puts(s, "\n"); +} + +static int rate_max_show(struct seq_file *s, void *unused) +{ + struct clk_core *core = s->private; + struct clk_vdd_class *vdd_class = core->vdd_class; + int level = 0, i, nregs = vdd_class->num_regulators; + char reg_name[10]; + + int vdd_level = clk_find_vdd_level(core, core->rate); + + if (vdd_level < 0) { + seq_printf(s, "could not find_vdd_level for %s, %ld\n", + core->name, core->rate); + return 0; + } + + seq_printf(s, "%12s", ""); + for (i = 0; i < nregs; i++) { + snprintf(reg_name, ARRAY_SIZE(reg_name), "reg %d", i); + seq_printf(s, "%10s", reg_name); + } + + seq_printf(s, "\n%12s", "freq"); + for (i = 0; i < nregs; i++) + seq_printf(s, "%10s", "uV"); + + seq_puts(s, "\n"); + + for (level = 0; level < core->num_rate_max; level++) + clock_print_rate_max_by_level(s, level); + + return 0; +} +DEFINE_PROC_SHOW_ATTRIBUTE(rate_max); + +static int clk_accuracy_show(struct seq_file *s, void *data) +{ + struct clk_core *core = s->private; + + seq_printf(s, "%lu\n", core->accuracy); + + return 0; +} +DEFINE_PROC_SHOW_ATTRIBUTE(clk_accuracy); + +static int clk_phase_show(struct seq_file *s, void *data) +{ + struct clk_core *core = s->private; + + seq_printf(s, "%d\n", core->phase); + + return 0; +} +DEFINE_PROC_SHOW_ATTRIBUTE(clk_phase); + +static int clk_prepare_count_show(struct seq_file *s, void *data) +{ + struct clk_core *core = s->private; + + seq_printf(s, "%d\n", core->prepare_count); + + return 0; +} +DEFINE_PROC_SHOW_ATTRIBUTE(clk_prepare_count); + +static int clk_notifier_count_show(struct seq_file *s, void *data) +{ + struct clk_core *core = s->private; + + seq_printf(s, "%d\n", core->notifier_count); + + return 0; +} +DEFINE_PROC_SHOW_ATTRIBUTE(clk_notifier_count); + + +static int clk_debug_create_one(struct clk_core *core, struct proc_dir_entry *pdentry) +{ + struct proc_dir_entry *d; + int ret = -ENOMEM; + + if (!core || !pdentry) { + ret = -EINVAL; + goto out; + } + + d = proc_mkdir(core->name, pdentry); + if (!d) + goto out; + + core->dentry = d; + + d = proc_create_data("clk_rate", 0444, core->dentry, &clock_rate_fops, core); + if (!d) + goto err_out; + + if (core->ops->list_rate) { + if (!proc_create_data("clk_list_rates", + 0444, core->dentry, &list_rates_fops, core)) + goto err_out; + } + + if (core->vdd_class && !proc_create_data("clk_rate_max", + 0444, core->dentry, &rate_max_fops, core)) + goto err_out; + + d = proc_create_data("clk_accuracy", 0444, core->dentry, &clk_accuracy_fops, core); + if (!d) + goto err_out; + + d = proc_create_data("clk_phase", 0444, core->dentry, &clk_phase_fops, core); + if (!d) + goto err_out; + + d = proc_create_data("clk_prepare_count", 0444, core->dentry, &clk_prepare_count_fops, core); + if (!d) + goto err_out; + + d = proc_create_data("clk_flags", 0444, core->dentry, &clk_flags_fops, core); + if (!d) + goto err_out; + + d = proc_create_data("clk_enable_count", 0444, core->dentry, &clock_enable_fops, core); + if (!d) + goto err_out; + + d = proc_create_data("clk_notifier_count", 0444, core->dentry, &clk_notifier_count_fops, core); + if (!d) + goto err_out; + + if (core->num_parents > 1) { + d = proc_create_data("clk_possible_parents", 0444, + core->dentry, &possible_parents_fops, core); + if (!d) + goto err_out; + } + + d = proc_create_data("clk_parent", 0444, core->dentry, &clock_parent_fops, core); + if (!d) + goto err_out; + + d = proc_create_data("clk_print_regs", 0444, core->dentry, &clock_print_hw_fops, core); + if (!d) + goto err_out; + + //if (core->ops->debug_init) + // core->ops->debug_init(core->hw, core->dentry); + + ret = 0; + goto out; + +err_out: + proc_remove(core->dentry); + core->dentry = NULL; +out: + return ret; +} + +/** + * clk_debug_register - add a clk node to the debugfs clk directory + * @core: the clk being added to the debugfs clk directory + * + * Dynamically adds a clk to the debugfs clk directory if debugfs has been + * initialized. Otherwise it bails out early since the debugfs clk directory + * will be created lazily by clk_debug_init as part of a late_initcall. + */ +static void clk_debug_register(struct clk_core *core) +{ + mutex_lock(&clk_debug_lock); + hlist_add_head(&core->debug_node, &clk_debug_list); + if (inited) + clk_debug_create_one(core, rootdir); + mutex_unlock(&clk_debug_lock); +} + + /** + * clk_debug_unregister - remove a clk node from the debugfs clk directory + * @core: the clk being removed from the debugfs clk directory + * + * Dynamically removes a clk and all its child nodes from the + * debugfs clk directory if clk->dentry points to debugfs created by + * clk_debug_register in __clk_core_init. + */ +static void clk_debug_unregister(struct clk_core *core) +{ + mutex_lock(&clk_debug_lock); + hlist_del_init(&core->debug_node); + proc_remove(core->dentry); + core->dentry = NULL; + mutex_unlock(&clk_debug_lock); +} + +/* + * Print the names of all enabled clocks and their parents if + * debug_suspend is set from debugfs. + */ +void clock_debug_print_enabled(void) +{ + if (likely(!debug_suspend)) + return; + clock_debug_print_enabled_clocks(NULL); +} +EXPORT_SYMBOL_GPL(clock_debug_print_enabled); + +static ssize_t debug_suspend_store(struct file *file, + const char __user *buffer, size_t count, loff_t *ppos) +{ + char buff_temp[8]; + char *end; + + if(count <= 0 || buffer == NULL){ + pr_err("Input buf is NULL\n"); + return 0; + } + + copy_from_user(buff_temp, buffer, 8); + debug_suspend = simple_strtoll(buff_temp, &end, 0); + + return count; +} + +static int debug_suspend_show(struct seq_file *m, void *v) +{ + seq_printf(m, "%d\n", debug_suspend); + return 0; +} +DEFINE_PROC_SHOW_STORE_ATTRIBUTE(debug_suspend); +/** + * oplus_clk_debug_init - lazily populate the debugfs clk directory + * + * clks are often initialized very early during boot before memory can be + * dynamically allocated and well before debugfs is setup. This function + * populates the debugfs clk directory once at boot-time when we know that + * debugfs is setup. It should only be called once at boot-time, all other clks + * added dynamically will be done so with clk_debug_register. + */ +static int __init oplus_clk_debug_init(void) +{ + struct proc_dir_entry *d; + struct clk_core *core; + + rootdir = proc_mkdir("oplus_clk", NULL); + if(!rootdir) { + return -ENOMEM; + } + + d = proc_create_data("clk_summary", 0444, rootdir, &clk_summary_fops, &all_lists); + if (!d) + return -ENOMEM; + + d = proc_create_data("clk_dump", 0444, rootdir, &clk_dump_fops, &all_lists); + if (!d) + return -ENOMEM; + + d = proc_create_data("clk_enabled_list", 0444, rootdir, &clk_enabled_list_fops, &clk_debug_list); + if (!d) + return -ENOMEM; + + d = proc_create("debug_suspend", 0644, rootdir, &debug_suspend_fops); + if (!d) + return -ENOMEM; + + d = proc_create_data("trace_clocks", 0444, rootdir, &clk_state_fops, &all_lists); + if (!d) + return -ENOMEM; + + mutex_lock(&clk_debug_lock); + hlist_for_each_entry(core, &clk_debug_list, debug_node) + clk_debug_create_one(core, rootdir); + + inited = 1; + mutex_unlock(&clk_debug_lock); + return 0; +} +late_initcall(oplus_clk_debug_init); #else static inline void clk_debug_register(struct clk_core *core) { } static inline void clk_debug_reparent(struct clk_core *core, @@ -4057,6 +4880,14 @@ void clock_debug_print_enabled(void) } #endif + +#if (defined OPLUS_FEATURE_POWERINFO_RPMH)||(defined CONFIG_DEBUG_FS) +void oplus_clock_debug_print_enabled(void) +{ + clock_debug_print_enabled_clocks(NULL); +} +EXPORT_SYMBOL_GPL(oplus_clock_debug_print_enabled); +#endif /** * __clk_core_init - initialize the data structures in a struct clk_core * @core: clk_core being initialized @@ -5554,4 +6385,4 @@ void __init of_clk_init(const struct of_device_id *matches) force = true; } } -#endif +#endif \ No newline at end of file diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index b050316480fc..42904ffee78a 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -34,6 +34,16 @@ #include #include +#ifdef CONFIG_OPLUS_FEATURE_TPD +#include +#endif + +#if IS_ENABLED(CONFIG_OPLUS_FEATURE_CPU_JANKINFO) +#include +#endif +#if defined(OPLUS_FEATURE_TASK_CPUSTATS) && defined(CONFIG_OPLUS_SCHED) +#include +#endif /* defined(OPLUS_FEATURE_TASK_CPUSTATS) && defined(CONFIG_OPLUS_SCHED) */ static LIST_HEAD(cpufreq_policy_list); @@ -200,6 +210,14 @@ struct cpufreq_policy *cpufreq_cpu_get_raw(unsigned int cpu) } EXPORT_SYMBOL_GPL(cpufreq_cpu_get_raw); +#ifdef OPLUS_FEATURE_HEALTHINFO +struct list_head *get_cpufreq_policy_list(void) +{ + return &cpufreq_policy_list; +} +EXPORT_SYMBOL(get_cpufreq_policy_list); +#endif /* OPLUS_FEATURE_HEALTHINFO */ + unsigned int cpufreq_generic_get(unsigned int cpu) { struct cpufreq_policy *policy = cpufreq_cpu_get_raw(cpu); @@ -361,6 +379,9 @@ static void cpufreq_notify_transition(struct cpufreq_policy *policy, cpufreq_stats_record_transition(policy, freqs->new); cpufreq_times_record_transition(policy, freqs->new); policy->cur = freqs->new; +#if defined(OPLUS_FEATURE_TASK_CPUSTATS) && defined(CONFIG_OPLUS_SCHED) + update_freq_info(policy); +#endif /* defined(OPLUS_FEATURE_TASK_CPUSTATS) && defined(CONFIG_OPLUS_SCHED) */ } } @@ -507,7 +528,15 @@ EXPORT_SYMBOL_GPL(cpufreq_disable_fast_switch); unsigned int cpufreq_driver_resolve_freq(struct cpufreq_policy *policy, unsigned int target_freq) { +#if IS_ENABLED(CONFIG_OPLUS_FEATURE_CPU_JANKINFO) + unsigned int old_target_freq = target_freq; +#endif target_freq = clamp_val(target_freq, policy->min, policy->max); + +#if IS_ENABLED(CONFIG_OPLUS_FEATURE_CPU_JANKINFO) + jankinfo_update_freq_reach_limit_count(policy, + old_target_freq, target_freq, DO_CLAMP); +#endif policy->cached_target_freq = target_freq; if (cpufreq_driver->target_index) { @@ -905,6 +934,19 @@ static ssize_t show_bios_limit(struct cpufreq_policy *policy, char *buf) return sprintf(buf, "%u\n", policy->cpuinfo.max_freq); } +#ifdef OPLUS_FEATURE_HEALTHINFO +#ifdef CONFIG_OPLUS_HEALTHINFO +static ssize_t show_freq_change_info(struct cpufreq_policy *policy, char *buf) +{ + ssize_t i = 0; + + i += sprintf(buf, "%u,%s\n", policy->org_max, policy->change_comm); + + return i; +} +#endif +#endif /* OPLUS_FEATURE_HEALTHINFO */ + cpufreq_freq_attr_ro_perm(cpuinfo_cur_freq, 0400); cpufreq_freq_attr_ro(cpuinfo_min_freq); cpufreq_freq_attr_ro(cpuinfo_max_freq); @@ -915,6 +957,11 @@ cpufreq_freq_attr_ro(scaling_cur_freq); cpufreq_freq_attr_ro(bios_limit); cpufreq_freq_attr_ro(related_cpus); cpufreq_freq_attr_ro(affected_cpus); +#ifdef OPLUS_FEATURE_HEALTHINFO +#ifdef CONFIG_OPLUS_HEALTHINFO +cpufreq_freq_attr_ro(freq_change_info); +#endif +#endif /* OPLUS_FEATURE_HEALTHINFO */ cpufreq_freq_attr_rw(scaling_min_freq); cpufreq_freq_attr_rw(scaling_max_freq); cpufreq_freq_attr_rw(scaling_governor); @@ -932,6 +979,11 @@ static struct attribute *default_attrs[] = { &scaling_driver.attr, &scaling_available_governors.attr, &scaling_setspeed.attr, +#ifdef OPLUS_FEATURE_HEALTHINFO +#ifdef CONFIG_OPLUS_HEALTHINFO + &freq_change_info.attr, +#endif +#endif /* OPLUS_FEATURE_HEALTHINFO */ NULL }; @@ -1279,6 +1331,9 @@ static int cpufreq_online(unsigned int cpu) per_cpu(cpufreq_cpu_data, j) = policy; add_cpu_dev_symlink(policy, j); } +#ifdef CONFIG_OPLUS_FEATURE_TPD + tpd_init_policy(policy); +#endif } else { policy->min = policy->user_policy.min; policy->max = policy->user_policy.max; @@ -1902,8 +1957,14 @@ unsigned int cpufreq_driver_fast_switch(struct cpufreq_policy *policy, unsigned int target_freq) { int ret; - +#if IS_ENABLED(CONFIG_OPLUS_FEATURE_CPU_JANKINFO) + unsigned int old_target_freq = target_freq; +#endif target_freq = clamp_val(target_freq, policy->min, policy->max); +#if IS_ENABLED(CONFIG_OPLUS_FEATURE_CPU_JANKINFO) + jankinfo_update_freq_reach_limit_count(policy, + old_target_freq, target_freq, DO_CLAMP | DO_INCREASE); +#endif ret = cpufreq_driver->fast_switch(policy, target_freq); if (ret) { @@ -2010,6 +2071,10 @@ int __cpufreq_driver_target(struct cpufreq_policy *policy, /* Make sure that target_freq is within supported range */ target_freq = clamp_val(target_freq, policy->min, policy->max); +#if IS_ENABLED(CONFIG_OPLUS_FEATURE_CPU_JANKINFO) + jankinfo_update_freq_reach_limit_count(policy, + old_target_freq, target_freq, DO_CLAMP); +#endif pr_debug("target for CPU %u: %u kHz, relation %u, requested %u kHz\n", policy->cpu, target_freq, relation, old_target_freq); @@ -2247,7 +2312,11 @@ static int cpufreq_set_policy(struct cpufreq_policy *policy, pr_debug("setting new policy for CPU %u: %u - %u kHz\n", new_policy->cpu, new_policy->min, new_policy->max); - +#ifdef OPLUS_FEATURE_HEALTHINFO +#ifdef CONFIG_OPLUS_HEALTHINFO + policy->org_max = new_policy->max; +#endif +#endif /* OPLUS_FEATURE_HEALTHINFO */ memcpy(&new_policy->cpuinfo, &policy->cpuinfo, sizeof(policy->cpuinfo)); /* @@ -2286,6 +2355,16 @@ static int cpufreq_set_policy(struct cpufreq_policy *policy, policy->max = new_policy->max; trace_cpu_frequency_limits(policy); +#ifdef OPLUS_FEATURE_HEALTHINFO +#ifdef CONFIG_OPLUS_HEALTHINFO + strncpy(policy->change_comm, current->comm, TASK_COMM_LEN); +#endif +#endif /* OPLUS_FEATURE_HEALTHINFO */ + +#if defined(OPLUS_FEATURE_TASK_CPUSTATS) && defined(CONFIG_OPLUS_SCHED) + update_freq_limit_info(policy); +#endif /* defined(OPLUS_FEATURE_TASK_CPUSTATS) && defined(CONFIG_OPLUS_SCHED) */ + arch_set_max_freq_scale(policy->cpus, policy->max); policy->cached_target_freq = UINT_MAX; diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c index 21b919bfaecc..9ff33943e972 100644 --- a/drivers/cpufreq/cpufreq_stats.c +++ b/drivers/cpufreq/cpufreq_stats.c @@ -212,7 +212,7 @@ void cpufreq_stats_create_table(struct cpufreq_policy *policy) /* We failed, release resources */ policy->stats = NULL; - kfree(stats->time_in_state); + free_stat: kfree(stats); } diff --git a/drivers/cpufreq/cpufreq_times.c b/drivers/cpufreq/cpufreq_times.c index 210742e963e0..a41a6c66a3a7 100644 --- a/drivers/cpufreq/cpufreq_times.c +++ b/drivers/cpufreq/cpufreq_times.c @@ -25,6 +25,10 @@ #include #include +#ifdef CONFIG_OPLUS_FEATURE_MIDAS +#include +#endif + #define UID_HASH_BITS 10 static DECLARE_HASHTABLE(uid_hash_table, UID_HASH_BITS); @@ -424,6 +428,9 @@ void cpufreq_acct_update_power(struct task_struct *p, u64 cputime) uid_entry->time_in_state[state] += cputime; spin_unlock_irqrestore(&uid_lock, flags); +#ifdef CONFIG_OPLUS_FEATURE_MIDAS + midas_record_task_times(uid, cputime, p, state); +#endif rcu_read_lock(); uid_entry = find_uid_entry_rcu(uid); if (!uid_entry) { diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c index 219704cd87eb..8c9e44a13b86 100644 --- a/drivers/cpuidle/cpuidle.c +++ b/drivers/cpuidle/cpuidle.c @@ -228,6 +228,9 @@ int cpuidle_enter_state(struct cpuidle_device *dev, struct cpuidle_driver *drv, trace_cpu_idle_rcuidle(index, dev->cpu); time_start = ns_to_ktime(local_clock()); +#ifdef CONFIG_OPLUS_FEATURE_GAME_OPT + g_time_in_state_update_idle(dev->cpu, 1); +#endif stop_critical_timings(); entered_state = target_state->enter(dev, drv, index); @@ -235,6 +238,9 @@ int cpuidle_enter_state(struct cpuidle_device *dev, struct cpuidle_driver *drv, sched_clock_idle_wakeup_event(); time_end = ns_to_ktime(local_clock()); +#ifdef CONFIG_OPLUS_FEATURE_GAME_OPT + g_time_in_state_update_idle(dev->cpu, 0); +#endif trace_cpu_idle_rcuidle(PWR_EVENT_EXIT, dev->cpu); /* The cpu is no longer idle or about to enter idle. */ diff --git a/drivers/cpuidle/cpuidle.h b/drivers/cpuidle/cpuidle.h index 2965ab32a583..6d2556f08117 100644 --- a/drivers/cpuidle/cpuidle.h +++ b/drivers/cpuidle/cpuidle.h @@ -5,7 +5,9 @@ #ifndef __DRIVER_CPUIDLE_H #define __DRIVER_CPUIDLE_H - +#ifdef CONFIG_OPLUS_FEATURE_GAME_OPT +#include "../soc/oplus/game_opt/game_ctrl.h" +#endif /* For internal use only */ extern struct cpuidle_governor *cpuidle_curr_governor; extern struct list_head cpuidle_governors; diff --git a/drivers/devfreq/governor_bw_hwmon.c b/drivers/devfreq/governor_bw_hwmon.c index 1076d3ca99c6..23e07809ac99 100644 --- a/drivers/devfreq/governor_bw_hwmon.c +++ b/drivers/devfreq/governor_bw_hwmon.c @@ -113,6 +113,13 @@ show_attr(__attr) \ store_attr(__attr, (min), (max)) \ static DEVICE_ATTR(__attr, 0644, show_##__attr, store_##__attr) +#ifdef VENDOR_EDIT +#define gov_attr_rw(__attr, min, max) \ +show_attr(__attr) \ +store_attr(__attr, (min), (max)) \ +static DEVICE_ATTR(__attr, 0664, show_##__attr, store_##__attr) +#endif /* VENDOR_EDIT */ + #define show_list_attr(name, n) \ static ssize_t show_list_##name(struct device *dev, \ struct device_attribute *attr, char *buf) \ @@ -808,9 +815,17 @@ gov_attr(up_scale, 0U, 500U); gov_attr(up_thres, 1U, 100U); gov_attr(down_thres, 0U, 90U); gov_attr(down_count, 0U, 90U); + +#ifdef VENDOR_EDIT +gov_attr_rw(hist_memory, 0U, 90U); +gov_attr_rw(hyst_trigger_count, 0U, 90U); +gov_attr_rw(hyst_length, 0U, 90U); +#else gov_attr(hist_memory, 0U, 90U); gov_attr(hyst_trigger_count, 0U, 90U); gov_attr(hyst_length, 0U, 90U); +#endif /* VENDOR_EDIT */ + gov_attr(idle_mbps, 0U, 2000U); gov_attr(use_ab, 0U, 1U); gov_list_attr(mbps_zones, NUM_MBPS_ZONES, 0U, UINT_MAX); diff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c index 5fadc4c2910d..23f714774c61 100644 --- a/drivers/dma-buf/dma-buf.c +++ b/drivers/dma-buf/dma-buf.c @@ -44,6 +44,16 @@ #include #include +#ifdef OPLUS_FEATURE_LOWMEM_DBG +/* Add for dump memory */ +/* usage when lowmmem occurs. */ +#include +#endif /* OPLUS_FEATURE_LOWMEM_DBG */ + +#if defined(OPLUS_FEATURE_PERFORMANCE) && defined(CONFIG_PROC_FS) +#include +#endif + static inline int is_dma_buf_file(struct file *); struct dma_buf_list { @@ -522,6 +532,15 @@ static inline int is_dma_buf_file(struct file *file) return file->f_op == &dma_buf_fops; } +#ifdef OPLUS_FEATURE_LOWMEM_DBG +/* Add for dump memory */ +/* usage when lowmmem occurs. */ +inline int oplus_is_dma_buf_file(struct file *file) +{ + return is_dma_buf_file(file); +} +#endif /* OPLUS_FEATURE_LOWMEM_DBG */ + static struct file *dma_buf_getfile(struct dma_buf *dmabuf, int flags) { struct file *file; @@ -1328,7 +1347,7 @@ int dma_buf_get_uuid(struct dma_buf *dmabuf, uuid_t *uuid) } EXPORT_SYMBOL_GPL(dma_buf_get_uuid); -#ifdef CONFIG_DEBUG_FS +#if defined(CONFIG_DEBUG_FS) || (defined(OPLUS_FEATURE_PERFORMANCE) && defined(CONFIG_PROC_FS)) static int dma_buf_debug_show(struct seq_file *s, void *unused) { int ret; @@ -1568,6 +1587,7 @@ static const struct file_operations dma_procs_debug_fops = { .release = single_release }; +#ifdef CONFIG_DEBUG_FS static struct dentry *dma_buf_debugfs_dir; static int dma_buf_init_debugfs(void) @@ -1608,6 +1628,64 @@ static void dma_buf_uninit_debugfs(void) { debugfs_remove_recursive(dma_buf_debugfs_dir); } +#else /* CONFIG_DEBUG_FS */ +static inline int dma_buf_init_debugfs(void) +{ + return 0; +} +static inline void dma_buf_uninit_debugfs(void) +{ +} +#endif /* CONFIG_DEBUG_FS */ + +#if defined(OPLUS_FEATURE_PERFORMANCE) && defined(CONFIG_PROC_FS) +static struct proc_dir_entry *dma_buf_procfs_root; + +int dma_buf_init_procfs(void) +{ + struct proc_dir_entry *p; + int err = 0; + + p = proc_mkdir("dma_buf", NULL); + if (IS_ERR(p)) + return PTR_ERR(p); + + dma_buf_procfs_root = p; + + p = proc_create_data("bufinfo", + S_IFREG | 0664, + dma_buf_procfs_root, + &dma_buf_debug_fops, + NULL); + if (IS_ERR(p)) { + pr_debug("dma_buf: procfs: failed to create node bufinfo\n"); + proc_remove(dma_buf_procfs_root); + dma_buf_procfs_root = NULL; + err = PTR_ERR(dma_buf_procfs_root); + return err; + } + + p = proc_create_data("dmaprocs", + S_IFREG | 0664, + dma_buf_procfs_root, + &dma_procs_debug_fops, + NULL); + if (IS_ERR(p)) { + pr_debug("dma_buf: procfs: failed to create node dmaprocs\n"); + proc_remove(dma_buf_procfs_root); + dma_buf_procfs_root = NULL; + err = PTR_ERR(dma_buf_procfs_root); + } + + return err; +} + +void dma_buf_uninit_procfs(void) +{ + proc_remove(dma_buf_procfs_root); +} +#endif /* defined(OPLUS_FEATURE_PERFORMANCE) && defined(CONFIG_PROC_FS) */ + #else static inline int dma_buf_init_debugfs(void) { @@ -1627,6 +1705,9 @@ static int __init dma_buf_init(void) mutex_init(&db_list.lock); INIT_LIST_HEAD(&db_list.head); dma_buf_init_debugfs(); +#if defined(OPLUS_FEATURE_PERFORMANCE) && defined(CONFIG_PROC_FS) + dma_buf_init_procfs(); +#endif return 0; } subsys_initcall(dma_buf_init); @@ -1635,5 +1716,8 @@ static void __exit dma_buf_deinit(void) { dma_buf_uninit_debugfs(); kern_unmount(dma_buf_mnt); +#if defined(OPLUS_FEATURE_PERFORMANCE) && defined(CONFIG_PROC_FS) + dma_buf_uninit_procfs(); +#endif } __exitcall(dma_buf_deinit); diff --git a/drivers/esoc/esoc-mdm-4x.c b/drivers/esoc/esoc-mdm-4x.c index 2a0dcc95f2f0..1ce447d0d5c6 100644 --- a/drivers/esoc/esoc-mdm-4x.c +++ b/drivers/esoc/esoc-mdm-4x.c @@ -9,6 +9,16 @@ #include #include #include "esoc-mdm.h" +#include + +#ifdef OPLUS_BUG_STABILITY +/*Add for 5G modem dump*/ +extern bool delay_panic; +#endif + +#ifdef OPLUS_FEATURE_MODEM_MINIDUMP +#include +#endif /*OPLUS_FEATURE_MODEM_MINIDUMP*/ enum gpio_update_config { GPIO_UPDATE_BOOTING_CONFIG = 1, @@ -363,13 +373,42 @@ static void mdm_status_fn(struct work_struct *work) mdm_update_gpio_configs(mdm, GPIO_UPDATE_RUNNING_CONFIG); } +#ifdef OPLUS_FEATURE_MODEM_MINIDUMP +extern void mdmreason_set(char * buf); +#endif /*OPLUS_FEATURE_MODEM_MINIDUMP*/ + +#ifdef OPLUS_FEATURE_MODEM_MINIDUMP +static int strn(const char *p, const char chr) +{ + int count = 0; + while(*p) + { + if(*p == chr) + ++count; + ++p; + } + return count; +} +#endif /*OPLUS_FEATURE_MODEM_MINIDUMP*/ + +bool modem_force_rst = false; + static void mdm_get_restart_reason(struct work_struct *work) { int ret, ntries = 0; +#ifdef OPLUS_FEATURE_MODEM_MINIDUMP + char mdmflag = ':'; + int mdmnum,mdmret1,mdmret2,mdmret3=0; + char sfr_buf2[RD_BUF_SIZE]; +#endif /*OPLUS_FEATURE_MODEM_MINIDUMP*/ + char sfr_buf[RD_BUF_SIZE]; struct mdm_ctrl *mdm = container_of(work, struct mdm_ctrl, restart_reason_work); struct device *dev = mdm->dev; +#ifdef OPLUS_FEATURE_MODEM_MINIDUMP + const char *name = mdm->esoc->subsys.name; +#endif /*OPLUS_FEATURE_MODEM_MINIDUMP*/ do { ret = sysmon_get_reason(&mdm->esoc->subsys, sfr_buf, @@ -377,6 +416,35 @@ static void mdm_get_restart_reason(struct work_struct *work) if (!ret) { esoc_mdm_log("restart reason is %s\n", sfr_buf); dev_err(dev, "mdm restart reason is %s\n", sfr_buf); +#ifdef OPLUS_FEATURE_MODEM_MINIDUMP + mdmnum = strn(sfr_buf,mdmflag); + mdmret1=0; + mdmret2=0; + mdmret3=0; + if(mdmnum >= 2) + { + mdmnum = 2; + } + while(mdmret3++ < mdmnum) + { + while(sfr_buf[mdmret1++] != mdmflag); + } + while(sfr_buf[mdmret1]) + { + sfr_buf2[mdmret2++] = sfr_buf[mdmret1++]; + } + sfr_buf2[mdmret2]='\0'; + if (!strcmp(name , "esoc0")){ + if (modem_force_rst) { + modem_force_rst = false; + mdmreason_set("Force modem reset"); + __subsystem_send_uevent(dev, "Force modem reset"); + } else { + mdmreason_set(sfr_buf2); + __subsystem_send_uevent(dev, sfr_buf2); + } + } +#endif /*OPLUS_FEATURE_MODEM_MINIDUMP*/ break; } msleep(SFR_RETRY_INTERVAL); @@ -387,6 +455,17 @@ static void mdm_get_restart_reason(struct work_struct *work) __func__, ret); } mdm->get_restart_reason = false; + +#ifdef OPLUS_BUG_STABILITY +/*Add for 5G modem dump*/ + if (delay_panic) { + snprintf(sfr_buf + strlen(sfr_buf), RD_BUF_SIZE - strlen(sfr_buf), " :SDX5x esoc0 modem crash"); + dev_err(dev, "SDX5x trigger dump after 5s !\n"); + msleep(5000); + mdm_power_down(mdm); + panic(sfr_buf); + } +#endif } void mdm_wait_for_status_low(struct mdm_ctrl *mdm, bool atomic) diff --git a/drivers/esoc/esoc-mdm-drv.c b/drivers/esoc/esoc-mdm-drv.c index 5301be93d38f..9b31642e16bb 100644 --- a/drivers/esoc/esoc-mdm-drv.c +++ b/drivers/esoc/esoc-mdm-drv.c @@ -271,6 +271,23 @@ static void esoc_client_link_mdm_crash(struct esoc_clink *esoc_clink) } } +static void mdm_force_reset(const struct subsys_desc *mdm_subsys) +{ + struct esoc_clink *esoc_clink = + container_of(mdm_subsys, + struct esoc_clink, + subsys); + struct mdm_ctrl *mdm = get_esoc_clink_data(esoc_clink); + + esoc_mdm_log("MDM force reset\n"); + + if (mdm->pon_ops->soft_reset) { + mdm->pon_ops->soft_reset(mdm, true); + } + + return; +} + static void mdm_crash_shutdown(const struct subsys_desc *mdm_subsys) { struct esoc_clink *esoc_clink = @@ -557,6 +574,7 @@ static int mdm_register_ssr(struct esoc_clink *esoc_clink) subsys->ramdump = mdm_subsys_ramdumps; subsys->powerup = mdm_subsys_powerup; subsys->crash_shutdown = mdm_crash_shutdown; + subsys->force_reset = mdm_force_reset; return esoc_clink_register_ssr(esoc_clink); } diff --git a/drivers/firmware/qcom/Kconfig b/drivers/firmware/qcom/Kconfig index 7ab2b74ed528..62ac622e2125 100644 --- a/drivers/firmware/qcom/Kconfig +++ b/drivers/firmware/qcom/Kconfig @@ -1,7 +1,9 @@ # SPDX-License-Identifier: GPL-2.0-only config MSM_TZ_LOG tristate "MSM Trust Zone (TZ) Log Driver" - depends on DEBUG_FS + #ifdef OPLUS_FEATURE_SECURITY_COMMON + #depends on DEBUG_FS + #endif help This option enables a driver with a debugfs interface for messages produced by the Secure code (Trust zone). These messages provide diff --git a/drivers/firmware/qcom/tz_log.c b/drivers/firmware/qcom/tz_log.c index 15abf43254dd..8dbb79fefd17 100644 --- a/drivers/firmware/qcom/tz_log.c +++ b/drivers/firmware/qcom/tz_log.c @@ -23,6 +23,10 @@ #include #include +//#ifdef OPLUS_FEATURE_SECURITY_COMMON +#include +#define TZDBG_DIR_NAME "tzdbg" +//#endif /* QSEE_LOG_BUF_SIZE = 32K */ #define QSEE_LOG_BUF_SIZE 0x8000 @@ -1131,7 +1135,12 @@ static ssize_t tzdbgfs_read_unencrypted(struct file *file, char __user *buf, size_t count, loff_t *offp) { int len = 0; - int tz_id = *(int *)(file->private_data); +//#ifdef OPLUS_FEATURE_SECURITY_COMMON + struct seq_file *seq = file->private_data; + int tz_id = *(int *)(seq->private); +//else + //int tz_id = *(int *)(file->private_data); +//#endif if (tz_id == TZDBG_BOOT || tz_id == TZDBG_RESET || tz_id == TZDBG_INTERRUPT || tz_id == TZDBG_GENERAL || @@ -1253,10 +1262,27 @@ static ssize_t tzdbgfs_read(struct file *file, char __user *buf, return tzdbgfs_read_encrypted(file, buf, count, offp); } +//#ifdef OPLUS_FEATURE_SECURITY_COMMON +static int tzdbg_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, NULL, PDE_DATA(inode)); +} + +static int tzdbg_proc_release(struct inode *inode, struct file *file) +{ + return single_release(inode, file); +} +//#endif + static const struct file_operations tzdbg_fops = { .owner = THIS_MODULE, .read = tzdbgfs_read, - .open = simple_open, +//#ifdef OPLUS_FEATURE_SECURITY_COMMON + .open = tzdbg_proc_open, + .release = tzdbg_proc_release, +//else + //.open = simple_open, +//#endif }; @@ -1410,6 +1436,63 @@ static void tzdbg_free_encrypted_log_buf(struct platform_device *pdev) enc_qseelog_info.vaddr, enc_qseelog_info.paddr); } +//#ifdef OPLUS_FEATURE_SECURITY_COMMON +//change tzdbg node to proc. +static int tzdbg_procfs_init(struct platform_device *pdev) +{ + int rc = 0; + int i; + struct proc_dir_entry *dent_dir; + struct proc_dir_entry *dent; + + dent_dir = proc_mkdir(TZDBG_DIR_NAME, NULL); + if (dent_dir == NULL) { + dev_err(&pdev->dev, "tzdbg proc_mkdir failed\n"); + return -ENOMEM; + } + + for (i = 0; i < TZDBG_STATS_MAX; i++) { + tzdbg.debug_tz[i] = i; + dent = proc_create_data(tzdbg.stat[i].name, + 0444, dent_dir, + &tzdbg_fops, &tzdbg.debug_tz[i]); + if (dent == NULL) { + dev_err(&pdev->dev, "TZ proc_create_data failed\n"); + rc = -ENOMEM; + goto err; + } + } + tzdbg.disp_buf = kzalloc(max(debug_rw_buf_size, + tzdbg.hyp_debug_rw_buf_size), GFP_KERNEL); + if (tzdbg.disp_buf == NULL) + goto err; + platform_set_drvdata(pdev, dent_dir); + return 0; +err: + if(dent_dir){ + remove_proc_entry(TZDBG_DIR_NAME, NULL); + } + + return rc; +} + +static void tzdbg_procfs_exit(struct platform_device *pdev) +{ + struct proc_dir_entry *dent_dir; + + if (g_qsee_log) { + qtee_shmbridge_deregister(qseelog_shmbridge_handle); + dma_free_coherent(&pdev->dev, QSEE_LOG_BUF_SIZE, + (void *)g_qsee_log, coh_pmem); + } + kzfree(tzdbg.disp_buf); + dent_dir = platform_get_drvdata(pdev); + if(dent_dir){ + remove_proc_entry(TZDBG_DIR_NAME, NULL); + } +} +//else +/* static int tzdbgfs_init(struct platform_device *pdev) { int rc = 0; @@ -1449,7 +1532,8 @@ static void tzdbgfs_exit(struct platform_device *pdev) dent_dir = platform_get_drvdata(pdev); debugfs_remove_recursive(dent_dir); } - +*/ +//#endif static int __update_hypdbg_base(struct platform_device *pdev, void __iomem *virt_iobase) { @@ -1671,8 +1755,13 @@ static int tz_log_probe(struct platform_device *pdev) goto exit_free_encr_log_buf; } - if (tzdbgfs_init(pdev)) +//#ifdef OPLUS_FEATURE_SECURITY_COMMON + if (tzdbg_procfs_init(pdev)) +//else + //if (tzdbgfs_init(pdev)) +//#endif goto exit_free_disp_buf; + return 0; exit_free_disp_buf: @@ -1689,7 +1778,11 @@ exit_free_diag_buf: static int tz_log_remove(struct platform_device *pdev) { - tzdbgfs_exit(pdev); + //#ifdef OPLUS_FEATURE_SECURITY_COMMON + tzdbg_procfs_exit(pdev); + //else + //tzdbgfs_exit(pdev); + //#endif dma_free_coherent(&pdev->dev, display_buf_size, (void *)tzdbg.disp_buf, disp_buf_paddr); tzdbg_free_encrypted_log_buf(pdev); diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 602dce9a1759..3c91dd8c6e6f 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -33,6 +33,11 @@ #define CREATE_TRACE_POINTS #include +#ifdef OPLUS_FEATURE_CHG_BASIC +extern bool oplus_vooc_adapter_update_is_tx_gpio(unsigned long gpio_num); +extern bool oplus_vooc_adapter_update_is_rx_gpio(unsigned long gpio_num); +#endif /* OPLUS_FEATURE_CHG_BASIC */ + /* Implementation infrastructure for GPIO interfaces. * * The GPIO programming interface allows for inlining speed-critical @@ -2839,9 +2844,24 @@ static int gpiod_get_raw_value_commit(const struct gpio_desc *desc) chip = desc->gdev->chip; offset = gpio_chip_hwgpio(desc); +#ifndef OPLUS_FEATURE_CHG_BASIC value = chip->get ? chip->get(chip, offset) : -EIO; value = value < 0 ? value : !!value; trace_gpio_value(desc_to_gpio(desc), 1, value); +#else + if(oplus_vooc_adapter_update_is_rx_gpio(desc_to_gpio(desc))) { + if(chip->get_oplus_vooc) { + value = chip->get_oplus_vooc(chip, offset); + } else { + pr_err("%s get_oplus_vooc not exist\n", __func__); + value = chip->get ? chip->get(chip, offset) : 0; + } + } else { + value = chip->get ? chip->get(chip, offset) : -EIO; + value = !!value; + trace_gpio_value(desc_to_gpio(desc), 1, value); + } +#endif /* OPLUS_FEATURE_CHG_BASIC */ return value; } @@ -3076,8 +3096,22 @@ static void gpiod_set_raw_value_commit(struct gpio_desc *desc, bool value) struct gpio_chip *chip; chip = desc->gdev->chip; +#ifndef OPLUS_FEATURE_CHG_BASIC trace_gpio_value(desc_to_gpio(desc), 0, value); chip->set(chip, gpio_chip_hwgpio(desc), value); +#else + if(oplus_vooc_adapter_update_is_tx_gpio(desc_to_gpio(desc)) == false) { + trace_gpio_value(desc_to_gpio(desc), 0, value); + chip->set(chip, gpio_chip_hwgpio(desc), value); + } else { + if(chip->set_oplus_vooc) { + chip->set_oplus_vooc(chip, gpio_chip_hwgpio(desc), value); + } else { + pr_err("%s set_oplus_vooc not exist\n", __func__); + chip->set(chip, gpio_chip_hwgpio(desc), value); + } + } +#endif /* OPLUS_FEATURE_CHG_BASIC */ } /* diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index a6771cef85e2..725ee0f7cb63 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile @@ -87,7 +87,9 @@ obj-y += tilcdc/ obj-$(CONFIG_DRM_QXL) += qxl/ obj-$(CONFIG_DRM_BOCHS) += bochs/ obj-$(CONFIG_DRM_VIRTIO_GPU) += virtio/ -obj-$(CONFIG_DRM_MSM) += msm/ +#ifdef OPLUS_BUG_STABILITY +#obj-$(CONFIG_DRM_MSM) += msm/ +#endif obj-$(CONFIG_DRM_TEGRA) += tegra/ obj-$(CONFIG_DRM_STM) += stm/ obj-$(CONFIG_DRM_STI) += sti/ diff --git a/drivers/gpu/drm/drm_mipi_dsi.c b/drivers/gpu/drm/drm_mipi_dsi.c index 14aae7184efd..a63eaedec094 100644 --- a/drivers/gpu/drm/drm_mipi_dsi.c +++ b/drivers/gpu/drm/drm_mipi_dsi.c @@ -1059,7 +1059,11 @@ EXPORT_SYMBOL(mipi_dsi_dcs_set_tear_scanline); int mipi_dsi_dcs_set_display_brightness(struct mipi_dsi_device *dsi, u16 brightness) { +#ifndef OPLUS_BUG_STABILITY u8 payload[2] = { brightness & 0xff, brightness >> 8 }; +#else /*OPLUS_BUG_STABILITY*/ + u8 payload[2] = { brightness >> 8, brightness & 0xff}; +#endif /*OPLUS_BUG_STABILITY*/ ssize_t err; err = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_DISPLAY_BRIGHTNESS, diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c index 7550435c3ac5..0829e6a50675 100644 --- a/drivers/gpu/drm/drm_modes.c +++ b/drivers/gpu/drm/drm_modes.c @@ -958,6 +958,9 @@ static bool drm_mode_match_timings(const struct drm_display_mode *mode1, mode1->vsync_start == mode2->vsync_start && mode1->vsync_end == mode2->vsync_end && mode1->vtotal == mode2->vtotal && +#ifdef OPLUS_BUG_STABILITY + drm_mode_vrefresh(mode1) == drm_mode_vrefresh(mode2) && +#endif /* OPLUS_BUG_STABILITY */ mode1->vscan == mode2->vscan; } diff --git a/drivers/gpu/msm/Makefile b/drivers/gpu/msm/Makefile index 126bafb1ec18..f39aff88dde7 100644 --- a/drivers/gpu/msm/Makefile +++ b/drivers/gpu/msm/Makefile @@ -1,5 +1,8 @@ # SPDX-License-Identifier: GPL-2.0-only ccflags-y += -I$(src) +#ifdef OPLUS_BUG_STABILITY +ccflags-y += -I$(srctree)/techpack/display/oplus +#endif /*OPLUS_BUG_STABILITY*/ msm_kgsl_core-y = \ kgsl.o \ diff --git a/drivers/gpu/msm/adreno_a6xx_preempt.c b/drivers/gpu/msm/adreno_a6xx_preempt.c index a58f8b2c899a..b03b9b26b33e 100644 --- a/drivers/gpu/msm/adreno_a6xx_preempt.c +++ b/drivers/gpu/msm/adreno_a6xx_preempt.c @@ -487,7 +487,7 @@ void a6xx_preemption_schedule(struct adreno_device *adreno_dev) { struct kgsl_device *device = KGSL_DEVICE(adreno_dev); - if (!adreno_is_preemption_enabled(adreno_dev)) + if (!ADRENO_FEATURE(adreno_dev, ADRENO_PREEMPTION)) return; mutex_lock(&device->mutex); @@ -602,7 +602,7 @@ void a6xx_preemption_start(struct adreno_device *adreno_dev) struct adreno_ringbuffer *rb; unsigned int i; - if (!adreno_is_preemption_enabled(adreno_dev)) + if (!ADRENO_FEATURE(adreno_dev, ADRENO_PREEMPTION)) return; /* Force the state to be clear */ diff --git a/drivers/gpu/msm/adreno_dispatch.c b/drivers/gpu/msm/adreno_dispatch.c index b6db7f848305..9c969ce1613d 100644 --- a/drivers/gpu/msm/adreno_dispatch.c +++ b/drivers/gpu/msm/adreno_dispatch.c @@ -2211,6 +2211,10 @@ static int dispatcher_do_fault(struct adreno_device *adreno_dev) adreno_readreg64(adreno_dev, ADRENO_REG_CP_RB_BASE, ADRENO_REG_CP_RB_BASE_HI, &base); + #if defined(OPLUS_FEATURE_GPU_MINIDUMP) + device->snapshotfault = fault; + #endif /*OPLUS_FEATURE_GPU_MINIDUMP*/ + /* * Force the CP off for anything but a hard fault to make sure it is * good and stopped diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c index 8e6bb0341cb5..9b162ab82df0 100644 --- a/drivers/gpu/msm/kgsl.c +++ b/drivers/gpu/msm/kgsl.c @@ -28,6 +28,9 @@ #include "kgsl_reclaim.h" #include "kgsl_sync.h" #include "kgsl_trace.h" +#if defined(OPLUS_FEATURE_VIRTUAL_RESERVE_MEMORY) && defined(CONFIG_VIRTUAL_RESERVE_MEMORY) +#include "kgsl_reserve.h" +#endif #ifndef arch_mmap_check #define arch_mmap_check(addr, len, flags) (0) @@ -700,6 +703,7 @@ void kgsl_context_detach(struct kgsl_context *context) kgsl_del_event_group(&context->events); kgsl_sync_timeline_detach(context->ktimeline); + kgsl_context_put(context); } @@ -4777,7 +4781,6 @@ static unsigned long _gpu_set_svm_region(struct kgsl_process_private *private, * trying to map a SVM region at the same time */ spin_lock(&entry->memdesc.gpuaddr_lock); - if (entry->memdesc.gpuaddr) { spin_unlock(&entry->memdesc.gpuaddr_lock); return (unsigned long) -EBUSY; @@ -4814,7 +4817,6 @@ static unsigned long _gpu_find_svm(struct kgsl_process_private *private, { uint64_t addr = kgsl_mmu_find_svm_region(private->pagetable, (uint64_t) start, (uint64_t)end, (uint64_t) len, align); - WARN(!IS_ERR_VALUE((unsigned long)addr) && (addr > ULONG_MAX), "Couldn't find range\n"); @@ -4827,7 +4829,6 @@ static unsigned long _cpu_get_unmapped_area(unsigned long bottom, { struct vm_unmapped_area_info info; unsigned long addr, err; - info.flags = VM_UNMAPPED_AREA_TOPDOWN; info.low_limit = bottom; info.high_limit = top; @@ -4837,8 +4838,9 @@ static unsigned long _cpu_get_unmapped_area(unsigned long bottom, addr = vm_unmapped_area(&info); - if (IS_ERR_VALUE(addr)) + if (IS_ERR_VALUE(addr)) { return addr; + } err = security_mmap_addr(addr); return err ? err : addr; @@ -4881,7 +4883,8 @@ static unsigned long _search_range(struct kgsl_process_private *private, /* move downward to the next empty spot on the GPU */ gpu = _gpu_find_svm(private, start, cpu, len, align); - if (IS_ERR_VALUE(gpu)) { + + if (IS_ERR_VALUE(gpu)) { result = gpu; break; } @@ -4974,6 +4977,11 @@ static unsigned long _get_svm_area(struct kgsl_process_private *private, * Search downwards from the hint first. If that fails we * must try to search above it. */ +#if defined(OPLUS_FEATURE_VIRTUAL_RESERVE_MEMORY) && defined(CONFIG_VIRTUAL_RESERVE_MEMORY) + result = kgsl_get_unmmaped_area_from_anti_fragment(private, entry, len, align); + if (result > 0) + return result; +#endif result = _search_range(private, entry, start, addr, len, align); if (IS_ERR_VALUE(result) && hint != 0) result = _search_range(private, entry, addr, end, len, align); @@ -5026,7 +5034,11 @@ kgsl_get_unmapped_area(struct file *file, unsigned long addr, pid_nr(private->pid), current->mm->mmap_base, addr, pgoff, len, (int) val); + } +#if defined(OPLUS_FEATURE_VIRTUAL_RESERVE_MEMORY) && defined(CONFIG_VIRTUAL_RESERVE_MEMORY) + update_oom_pid_and_time(len, val, flags); +#endif put: kgsl_mem_entry_put(entry); @@ -5383,9 +5395,15 @@ int kgsl_device_platform_probe(struct kgsl_device *device) PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE); } - +#ifdef OPLUS_FEATURE_SCHED_ASSIST + if (sysctl_sched_assist_enabled) + device->events_wq = alloc_workqueue("kgsl-events", + WQ_UNBOUND | WQ_MEM_RECLAIM | WQ_SYSFS | WQ_HIGHPRI | WQ_UX, 0); +#else device->events_wq = alloc_workqueue("kgsl-events", WQ_UNBOUND | WQ_MEM_RECLAIM | WQ_SYSFS | WQ_HIGHPRI, 0); +#endif + /* Initialize the snapshot engine */ kgsl_device_snapshot_init(device); diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h index 55008e288e72..46b210c65d8e 100644 --- a/drivers/gpu/msm/kgsl_device.h +++ b/drivers/gpu/msm/kgsl_device.h @@ -323,6 +323,11 @@ struct kgsl_device { unsigned int num_l3_pwrlevels; /* store current L3 vote to determine if we should change our vote */ unsigned int cur_l3_pwrlevel; + + #if defined(OPLUS_FEATURE_GPU_MINIDUMP) + bool snapshot_control; + int snapshotfault; + #endif /* OPLUS_FEATURE_GPU_MINIDUMP */ /** @timelines: Iterator for assigning IDs to timelines */ struct idr timelines; /** @timelines_lock: Spinlock to protect the timelines idr */ @@ -551,6 +556,10 @@ struct kgsl_snapshot { bool gmu_fault; bool recovered; struct kgsl_device *device; + + #if defined(OPLUS_FEATURE_GPU_MINIDUMP) + char snapshot_hashid[96]; + #endif /* OPLUS_FEATURE_GPU_MINIDUMP */ }; /** diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c index e4b9924baec2..3897793e189d 100644 --- a/drivers/gpu/msm/kgsl_iommu.c +++ b/drivers/gpu/msm/kgsl_iommu.c @@ -21,6 +21,10 @@ #include "kgsl_sharedmem.h" #include "kgsl_trace.h" +#ifdef OPLUS_BUG_STABILITY +#include +#endif /*OPLUS_BUG_STABILITY*/ + #define _IOMMU_PRIV(_mmu) (&((_mmu)->priv.iommu)) #define ADDR_IN_GLOBAL(_mmu, _a) \ @@ -826,6 +830,13 @@ static int kgsl_iommu_fault_handler(struct iommu_domain *domain, no_page_fault_log = kgsl_mmu_log_fault_addr(mmu, ptbase, addr); if (!no_page_fault_log && __ratelimit(&_rs)) { + #ifdef OPLUS_BUG_STABILITY + mm_fb_kevent(OPLUS_MM_DIRVER_FB_EVENT_DISPLAY, + OPLUS_DISPLAY_EVENTID_GPU_FAULT, + "gpu fault", MM_FB_KEY_RATELIMIT_1H, + "pid=%08lx,comm=%d", ptname, comm); + #endif /*OPLUS_BUG_STABILITY*/ + dev_crit(ctx->kgsldev->dev, "GPU PAGE FAULT: addr = %lX pid= %d name=%s\n", addr, ptname, comm); @@ -1046,6 +1057,7 @@ static void setup_64bit_pagetable(struct kgsl_mmu *mmu, pt->compat_va_end = KGSL_IOMMU_SECURE_BASE(mmu); pt->va_start = KGSL_IOMMU_VA_BASE64; pt->va_end = KGSL_IOMMU_VA_END64; + } if (pagetable->name != KGSL_MMU_GLOBAL_PT && diff --git a/drivers/gpu/msm/kgsl_mmu.c b/drivers/gpu/msm/kgsl_mmu.c index efe6d6513ab2..9d68eaf8ac6b 100644 --- a/drivers/gpu/msm/kgsl_mmu.c +++ b/drivers/gpu/msm/kgsl_mmu.c @@ -448,7 +448,6 @@ void kgsl_mmu_put_gpuaddr(struct kgsl_memdesc *memdesc) if (!kgsl_memdesc_is_global(memdesc)) memdesc->gpuaddr = 0; - } EXPORT_SYMBOL(kgsl_mmu_put_gpuaddr); diff --git a/drivers/gpu/msm/kgsl_pool.c b/drivers/gpu/msm/kgsl_pool.c index ecb05b9b9a06..14970659c10b 100644 --- a/drivers/gpu/msm/kgsl_pool.c +++ b/drivers/gpu/msm/kgsl_pool.c @@ -316,6 +316,7 @@ int kgsl_pool_alloc_page(int *page_size, struct page **pages, if (page == NULL) { gfp_t gfp_mask = kgsl_gfp_mask(order); +#ifndef OPLUS_FEATURE_SPECIALOPT /* Only allocate non-reserved memory for certain pools */ if (!pool->allocation_allowed && pool_idx > 0) { size = PAGE_SIZE << @@ -324,6 +325,16 @@ int kgsl_pool_alloc_page(int *page_size, struct page **pages, } page = alloc_pages(gfp_mask, order); +#else + page = alloc_pages(gfp_mask, order); + + /* Only allocate non-reserved memory for certain pools */ + if (!page &&!pool->allocation_allowed && pool_idx > 0) { + size = PAGE_SIZE << + kgsl_pools[pool_idx-1].pool_order; + goto eagain; + } +#endif if (!page) { if (pool_idx > 0) { diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c index efc0e77da52a..9a6b61491361 100644 --- a/drivers/gpu/msm/kgsl_pwrctrl.c +++ b/drivers/gpu/msm/kgsl_pwrctrl.c @@ -1432,6 +1432,26 @@ static ssize_t gpu_busy_percentage_show(struct device *dev, return ret; } +#ifdef CONFIG_OPLUS_FEATURE_MIDAS +static ssize_t gpu_status_time_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct kgsl_device *device = dev_get_drvdata(dev); + struct kgsl_pwrctrl *pwr; + + u64 slumber_time = 0; + + if (device == NULL) + return 0; + pwr = &device->pwrctrl; + + slumber_time = pwr->gpu_stats.gpu_pwr_stats[PWR_STAT_SLUMBER].total; + + return scnprintf(buf, PAGE_SIZE, "%llu\n", slumber_time); +} +#endif + static ssize_t min_clock_mhz_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -1613,6 +1633,9 @@ static DEVICE_ATTR_RW(max_clock_mhz); static DEVICE_ATTR_RO(clock_mhz); static DEVICE_ATTR_RO(freq_table_mhz); static DEVICE_ATTR_RW(pwrscale); +#ifdef CONFIG_OPLUS_FEATURE_MIDAS +static DEVICE_ATTR_RO(gpu_status_time); +#endif static const struct attribute *pwrctrl_attr_list[] = { &dev_attr_gpuclk.attr, @@ -1642,6 +1665,9 @@ static const struct attribute *pwrctrl_attr_list[] = { &dev_attr_freq_table_mhz.attr, &dev_attr_temp.attr, &dev_attr_pwrscale.attr, +#ifdef CONFIG_OPLUS_FEATURE_MIDAS + &dev_attr_gpu_status_time.attr, +#endif NULL, }; @@ -3055,6 +3081,11 @@ int kgsl_pwrctrl_change_state(struct kgsl_device *device, int state) _record_pwrevent(device, t, KGSL_PWREVENT_STATE); } + +#ifdef CONFIG_OPLUS_FEATURE_MIDAS + oplus_pwrctrl_update_stats_info(device); +#endif + return status; } EXPORT_SYMBOL(kgsl_pwrctrl_change_state); @@ -3445,3 +3476,38 @@ int kgsl_pwrctrl_set_default_gpu_pwrlevel(struct kgsl_device *device) /* Request adjusted DCVS level */ return kgsl_clk_set_rate(device, pwr->active_pwrlevel); } + +#ifdef CONFIG_OPLUS_FEATURE_MIDAS +/** + * oplus_pwrctrl_update_stats_info() - update oplus gpu_info + * @device: Pointer to the kgsl_device struct + * + * Update gpu state changes in gpu_info only, now only + * consider KGSL_STATE_SLUMBER status. + */ +void oplus_pwrctrl_update_stats_info(struct kgsl_device *device) +{ + struct kgsl_pwrctrl *pwr = &device->pwrctrl; + u64 total; + ktime_t tmp; + + tmp = ktime_get(); + total = ktime_us_delta(tmp, pwr->gpu_stats.timestamp); + + if (pwr->gpu_stats.last_state == KGSL_STATE_NONE) { + if(device->state == KGSL_STATE_SLUMBER) + goto update; + } + else { + // it means we met state transition + if(pwr->gpu_stats.last_state == KGSL_STATE_SLUMBER) { + pwr->gpu_stats.gpu_pwr_stats[PWR_STAT_SLUMBER].total += total; + goto update; + } + } + +update: + pwr->gpu_stats.timestamp = tmp; + pwr->gpu_stats.last_state = device->state; +} +#endif diff --git a/drivers/gpu/msm/kgsl_pwrctrl.h b/drivers/gpu/msm/kgsl_pwrctrl.h index 406486a8f065..3f90d051db45 100644 --- a/drivers/gpu/msm/kgsl_pwrctrl.h +++ b/drivers/gpu/msm/kgsl_pwrctrl.h @@ -79,6 +79,41 @@ enum kgsl_pwrctrl_timer_type { struct platform_device; +#ifdef CONFIG_OPLUS_FEATURE_MIDAS +// KGSL_MAX_PWRLEVELS + SLUMBER +#define MAX_GPU_PWR_STAT KGSL_MAX_PWRLEVELS + 1 +#define PWR_STAT_SLUMBER KGSL_MAX_PWRLEVELS + +/** + * struct gpu_pwr_stats - Struct holding different gpu power info obtained from + * pwrscale and pwrctrl + * @total: total us seconds are sampled in this power level + * @busy: total busy us seconds in this power level when sampled + * @ram_time: total ram read+write us seconds in this power level when sampled + * @ram_wait: total ram wait us seconds in this power level when sampled + */ +struct gpu_pwr_stats { + u64 total; + u64 busy; + u64 ram_time; + u64 ram_wait; +}; + +/** + * struct gpu_info - Struct holding gpu info we want to record + * @gpu_pwr_stats: gpu_pwr_stats of each power level + SLUMBER + * @gpu_total: total us seconds are sampled + * @timestamp: last timestamp when sampled + * @last_state: last KGSL device state when sampled + */ +struct gpu_info { + struct gpu_pwr_stats gpu_pwr_stats[MAX_GPU_PWR_STAT]; + u64 gpu_total; + ktime_t timestamp; + int last_state; +}; +#endif + struct kgsl_clk_stats { unsigned int busy; unsigned int total; @@ -243,6 +278,10 @@ struct kgsl_pwrctrl { unsigned int gpu_bimc_int_clk_freq; bool gpu_bimc_interface_enabled; struct gpu_cx_ipeak_client gpu_ipeak_client[2]; +#ifdef CONFIG_OPLUS_FEATURE_MIDAS +/* gpu_stats - collect gpu power status of each pwrlevel */ + struct gpu_info gpu_stats; +#endif }; int kgsl_pwrctrl_init(struct kgsl_device *device); @@ -293,4 +332,7 @@ int kgsl_pwrctrl_set_default_gpu_pwrlevel(struct kgsl_device *device); void kgsl_pwrctrl_disable_unused_opp(struct kgsl_device *device, struct device *dev); +#ifdef CONFIG_OPLUS_FEATURE_MIDAS +void oplus_pwrctrl_update_stats_info(struct kgsl_device *device); +#endif #endif /* __KGSL_PWRCTRL_H */ diff --git a/drivers/gpu/msm/kgsl_reserve.h b/drivers/gpu/msm/kgsl_reserve.h new file mode 120000 index 000000000000..37d68e409f86 --- /dev/null +++ b/drivers/gpu/msm/kgsl_reserve.h @@ -0,0 +1 @@ +../../../../../vendor/oplus/kernel/oplus_performance/gloom_new/kgsl_reserve.h \ No newline at end of file diff --git a/drivers/gpu/msm/kgsl_sharedmem.c b/drivers/gpu/msm/kgsl_sharedmem.c index 621ab3db5a49..6a2fce9417f1 100644 --- a/drivers/gpu/msm/kgsl_sharedmem.c +++ b/drivers/gpu/msm/kgsl_sharedmem.c @@ -339,6 +339,13 @@ void kgsl_process_init_sysfs(struct kgsl_device *device, kgsl_reclaim_proc_sysfs_init(private); } +#ifdef OPLUS_FEATURE_HEALTHINFO +unsigned long gpu_total(void) +{ + return (unsigned long)atomic_long_read(&kgsl_driver.stats.page_alloc); +} +#endif /* OPLUS_FEATURE_HEALTHINFO */ + static ssize_t memstat_show(struct device *dev, struct device_attribute *attr, char *buf) { diff --git a/drivers/gpu/msm/kgsl_snapshot.c b/drivers/gpu/msm/kgsl_snapshot.c index a4fe2efad2f0..b9271fdf9748 100644 --- a/drivers/gpu/msm/kgsl_snapshot.c +++ b/drivers/gpu/msm/kgsl_snapshot.c @@ -639,6 +639,47 @@ static void set_isdb_breakpoint_registers(struct kgsl_device *device) isdb_write(device->qdss_gfx_virt, 0x5000); } +#if defined(OPLUS_FEATURE_GPU_MINIDUMP) + +/************************************************ +adreno.h +#define ADRENO_SOFT_FAULT BIT(0) +#define ADRENO_HARD_FAULT BIT(1) +#define ADRENO_TIMEOUT_FAULT BIT(2) +#define ADRENO_IOMMU_PAGE_FAULT BIT(3) +#define ADRENO_PREEMPT_FAULT BIT(4) +#define ADRENO_GMU_FAULT BIT(5) +#define ADRENO_CTX_DETATCH_TIMEOUT_FAULT BIT(6) +#define ADRENO_GMU_FAULT_SKIP_SNAPSHOT BIT(7) +*************************************************/ +char* kgsl_get_reason(int faulttype, bool gmu_fault){ + if(gmu_fault){ + return "GMUFAULT"; + }else{ + switch(faulttype){ + case 0: + return "SOFTFAULT"; + case 1: + return "HANGFAULT"; + case 2: + return "TIMEOUTFAULT"; + case 3: + return "IOMMUPAGEFAULT"; + case 4: + return "PREEMPTFAULT"; + case 5: + return "GMUFAULT"; + case 6: + return "CTXDETATCHFAULT"; + case 7: + return "GMUSKIPFAULT"; + default: + return "UNKNOW"; + } + } +} +#endif /*OPLUS_FEATURE_GPU_MINIDUMP*/ + /** * kgsl_snapshot() - construct a device snapshot * @device: device to snapshot @@ -756,6 +797,17 @@ void kgsl_device_snapshot(struct kgsl_device *device, dev_err(device->dev, "%s snapshot created at pa %pa++0x%zx\n", gmu_fault ? "GMU" : "GPU", &pa, snapshot->size); + #if defined(OPLUS_FEATURE_GPU_MINIDUMP) + if(context!= NULL){ + dev_err(device->dev, "falut=%s, pid=%d, processname=%s\n", + kgsl_get_reason(device->snapshotfault, gmu_fault), context->proc_priv->pid, context->proc_priv->comm); + + memset(snapshot->snapshot_hashid, '\0', sizeof(snapshot->snapshot_hashid)); + scnprintf(snapshot->snapshot_hashid, sizeof(snapshot->snapshot_hashid), "%d@%s@%s", + context->proc_priv->pid, context->proc_priv->comm, kgsl_get_reason(device->snapshotfault, gmu_fault)); + } + #endif /* OPLUS_FEATURE_GPU_MINIDUMP */ + if (device->skip_ib_capture) BUG_ON(device->force_panic); @@ -835,6 +887,41 @@ static int snapshot_release(struct kgsl_device *device, return ret; } +#if defined(OPLUS_FEATURE_GPU_MINIDUMP) +static bool snapshot_ontrol_on = 0; + +static ssize_t snapshot_control_show(struct kgsl_device *device, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%d\n", device->snapshot_control); +} + +static ssize_t snapshot_control_store(struct kgsl_device *device, const char *buf, + size_t count) +{ + unsigned int val = 0; + int ret; + + if (device && count > 0) + device->snapshot_control = 0; + + ret = kgsl_sysfs_store(buf, &val); + + if (!ret && device){ + device->snapshot_control = (bool)val; + snapshot_ontrol_on = device->snapshot_control; + } + + return (ssize_t) ret < 0 ? ret : count; +} + +static ssize_t snapshot_hashid_show(struct kgsl_device *device, char *buf) +{ + if(device->snapshot == NULL) + return 0; + return strlcpy(buf, device->snapshot->snapshot_hashid, PAGE_SIZE); +} +#endif /*OPLUS_FEATURE_GPU_MINIDUMP*/ + /* Dump the sysfs binary data to the user */ static ssize_t snapshot_show(struct file *filep, struct kobject *kobj, struct bin_attribute *attr, char *buf, loff_t off, @@ -846,6 +933,13 @@ static ssize_t snapshot_show(struct file *filep, struct kobject *kobj, struct snapshot_obj_itr itr; int ret = 0; + #if defined(OPLUS_FEATURE_GPU_MINIDUMP) + if (snapshot_ontrol_on) { + dev_err(device->dev, "snapshot: snapshot_ontrol_on is true, skip snapshot\n"); + return 0; + } + #endif /* OPLUS_FEATURE_GPU_MINIDUMP */ + mutex_lock(&device->mutex); snapshot = device->snapshot; if (snapshot != NULL) { @@ -1064,6 +1158,11 @@ static SNAPSHOT_ATTR(snapshot_legacy, 0644, snapshot_legacy_show, static SNAPSHOT_ATTR(skip_ib_capture, 0644, skip_ib_capture_show, skip_ib_capture_store); +#if defined(OPLUS_FEATURE_GPU_MINIDUMP) +static SNAPSHOT_ATTR(snapshot_hashid, 0666, snapshot_hashid_show, NULL); +static SNAPSHOT_ATTR(snapshot_control, 0666, snapshot_control_show, snapshot_control_store); +#endif /* OPLUS_FEATURE_GPU_MINIDUMP */ + static ssize_t snapshot_sysfs_show(struct kobject *kobj, struct attribute *attr, char *buf) { @@ -1157,6 +1256,10 @@ int kgsl_device_snapshot_init(struct kgsl_device *device) device->snapshot_crashdumper = true; device->snapshot_legacy = false; + #if defined(OPLUS_FEATURE_GPU_MINIDUMP) + device->snapshot_control = 0; + #endif /* OPLUS_FEATURE_GPU_MINIDUMP */ + /* * Set this to false so that we only ever keep the first snapshot around * If we want to over-write with a gmu snapshot, then set it to true @@ -1175,6 +1278,16 @@ int kgsl_device_snapshot_init(struct kgsl_device *device) ret = sysfs_create_files(&device->snapshot_kobj, snapshot_attrs); + #if defined(OPLUS_FEATURE_GPU_MINIDUMP) + ret = sysfs_create_file(&device->snapshot_kobj, &attr_snapshot_hashid.attr); + if (ret) + return ret; + + ret = sysfs_create_file(&device->snapshot_kobj, &attr_snapshot_control.attr); + if (ret) + return ret; + #endif /* OPLUS_FEATURE_GPU_MINIDUMP */ + return ret; } EXPORT_SYMBOL(kgsl_device_snapshot_init); @@ -1200,6 +1313,10 @@ void kgsl_device_snapshot_close(struct kgsl_device *device) device->snapshot_faultcount = 0; device->force_panic = false; device->snapshot_crashdumper = true; + + #if defined(OPLUS_FEATURE_GPU_MINIDUMP) + device->snapshot_control = 0; + #endif /* OPLUS_FEATURE_GPU_MINIDUMP */ } EXPORT_SYMBOL(kgsl_device_snapshot_close); diff --git a/drivers/gpu/msm/kgsl_sync.c b/drivers/gpu/msm/kgsl_sync.c index 229f8baa7822..817f134c08e7 100644 --- a/drivers/gpu/msm/kgsl_sync.c +++ b/drivers/gpu/msm/kgsl_sync.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2012-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2020,2021 The Linux Foundation. All rights reserved. */ #include @@ -250,8 +250,6 @@ static void kgsl_sync_timeline_value_str(struct dma_fence *fence, struct kgsl_sync_fence *kfence = (struct kgsl_sync_fence *)fence; struct kgsl_sync_timeline *ktimeline = kfence->parent; struct kgsl_context *context = NULL; - unsigned long flags; - int ret = 0; unsigned int timestamp_retired; unsigned int timestamp_queued; @@ -261,21 +259,17 @@ static void kgsl_sync_timeline_value_str(struct dma_fence *fence, if (!ktimeline->device) goto put_timeline; - spin_lock_irqsave(&ktimeline->lock, flags); - ret = _kgsl_context_get(ktimeline->context); - context = ret ? ktimeline->context : NULL; - spin_unlock_irqrestore(&ktimeline->lock, flags); - - /* Get the last signaled timestamp if the context is not valid */ timestamp_queued = ktimeline->last_timestamp; timestamp_retired = timestamp_queued; + if (!ktimeline->detached) + context = kgsl_context_get(ktimeline->device, + ktimeline->context_id); if (context) { kgsl_readtimestamp(ktimeline->device, context, KGSL_TIMESTAMP_RETIRED, ×tamp_retired); kgsl_readtimestamp(ktimeline->device, context, KGSL_TIMESTAMP_QUEUED, ×tamp_queued); - kgsl_context_put(context); } @@ -312,15 +306,9 @@ int kgsl_sync_timeline_create(struct kgsl_context *context) { struct kgsl_sync_timeline *ktimeline; - /* Put context at detach time */ - if (!_kgsl_context_get(context)) - return -ENOENT; - ktimeline = kzalloc(sizeof(*ktimeline), GFP_KERNEL); - if (ktimeline == NULL) { - kgsl_context_put(context); + if (ktimeline == NULL) return -ENOMEM; - } kref_init(&ktimeline->kref); ktimeline->name = kasprintf(GFP_KERNEL, "%s_%d-%.15s(%d)-%.15s(%d)", @@ -333,12 +321,8 @@ int kgsl_sync_timeline_create(struct kgsl_context *context) INIT_LIST_HEAD(&ktimeline->child_list_head); spin_lock_init(&ktimeline->lock); ktimeline->device = context->device; - - /* - * The context pointer is valid till detach time, where we put the - * refcount on the context - */ - ktimeline->context = context; + ktimeline->context_id = context->id; + ktimeline->detached = false; context->ktimeline = ktimeline; @@ -372,14 +356,7 @@ static void kgsl_sync_timeline_signal(struct kgsl_sync_timeline *ktimeline, void kgsl_sync_timeline_detach(struct kgsl_sync_timeline *ktimeline) { - unsigned long flags; - struct kgsl_context *context = ktimeline->context; - - /* Set context pointer to NULL and drop our refcount on the context */ - spin_lock_irqsave(&ktimeline->lock, flags); - ktimeline->context = NULL; - spin_unlock_irqrestore(&ktimeline->lock, flags); - kgsl_context_put(context); + ktimeline->detached = true; } static void kgsl_sync_timeline_destroy(struct kref *kref) diff --git a/drivers/gpu/msm/kgsl_sync.h b/drivers/gpu/msm/kgsl_sync.h index f49f9e04f255..f41318aa8e9c 100644 --- a/drivers/gpu/msm/kgsl_sync.h +++ b/drivers/gpu/msm/kgsl_sync.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2012-2014,2018-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2014,2018-2020,2021 The Linux Foundation. All rights reserved. */ #ifndef __KGSL_SYNC_H #define __KGSL_SYNC_H @@ -9,6 +9,7 @@ /** * struct kgsl_sync_timeline - A sync timeline associated with a kgsl context + * @kref: Refcount to keep the struct alive until all its fences are released * @kref: Refcount to keep the struct alive until all its fences are signaled, and as long as the context exists * @name: String to describe this timeline @@ -18,7 +19,8 @@ * @lock: Spinlock to protect this timeline * @last_timestamp: Last timestamp when signaling fences * @device: kgsl device - * @context: kgsl context + * @context_id: kgsl context id + * @detached: whether the context is detached */ struct kgsl_sync_timeline { struct kref kref; @@ -31,7 +33,8 @@ struct kgsl_sync_timeline { spinlock_t lock; unsigned int last_timestamp; struct kgsl_device *device; - struct kgsl_context *context; + unsigned int context_id; + bool detached; }; /** @@ -119,8 +122,7 @@ static inline int kgsl_sync_timeline_create(struct kgsl_context *context) return 0; } -static inline void kgsl_sync_timeline_detach( - struct kgsl_sync_timeline *ktimeline) +static inline void kgsl_sync_timeline_detach(struct kgsl_sync_timeline *ktimeline) { } diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 4549fbb74156..18ee1193e0ba 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -910,7 +910,16 @@ static int hid_scan_report(struct hid_device *hid) hid->group = HID_GROUP_RMI; break; } +#ifdef OPLUS_BUG_STABILITY +//add for BLE-M1 uhid group change HID_GROUP_GENERIC + if (0x248a == hid->vendor && 2 == hid->group) { + hid_warn(hid, "scan_report change to GENERIC %u\n", hid->group); + hid->group = HID_GROUP_GENERIC; + } + /* fall back to generic driver in case specific driver doesn't exist */ + hid_warn(hid, "report vendor %u,group %u\n", hid->vendor, hid->group); +#endif /* OPLUS_BUG_STABILITY */ kfree(parser->collection_stack); vfree(parser); return 0; diff --git a/drivers/hid/hid-uclogic.c b/drivers/hid/hid-uclogic.c index e0bc31ee1576..baecbe927602 100644 --- a/drivers/hid/hid-uclogic.c +++ b/drivers/hid/hid-uclogic.c @@ -944,6 +944,9 @@ static int uclogic_probe(struct hid_device *hdev, struct usb_device *udev = hid_to_usb_dev(hdev); struct uclogic_drvdata *drvdata; + if (!hid_is_usb(hdev)) + return -EINVAL; + /* * libinput requires the pad interface to be on a different node * than the pen, so use QUIRK_MULTI_INPUT for all tablets. diff --git a/drivers/i2c/busses/i2c-qcom-geni.c b/drivers/i2c/busses/i2c-qcom-geni.c index 116d4914a799..0df601746dcf 100644 --- a/drivers/i2c/busses/i2c-qcom-geni.c +++ b/drivers/i2c/busses/i2c-qcom-geni.c @@ -22,12 +22,21 @@ #include #include #include +#ifdef OPLUS_FEATURE_CHG_BASIC +#include "../../power/oplus/oplus_vooc.h" +#include +#endif #define SE_I2C_TX_TRANS_LEN (0x26C) #define SE_I2C_RX_TRANS_LEN (0x270) #define SE_I2C_SCL_COUNTERS (0x278) #define SE_GENI_IOS (0x908) +#ifdef OPLUS_FEATURE_CHG_BASIC +#define SE_I2C_NOISE_CANCEL_CTL (0x234) +#endif + + #define SE_I2C_ERR (M_CMD_OVERRUN_EN | M_ILLEGAL_CMD_EN | M_CMD_FAILURE_EN |\ M_GP_IRQ_1_EN | M_GP_IRQ_3_EN | M_GP_IRQ_4_EN) #define SE_I2C_ABORT (1U << 1) @@ -128,6 +137,11 @@ struct geni_i2c_dev { bool is_shared; u32 dbg_num; struct dbg_buf_ctxt *dbg_buf_ptr; +#ifdef OPLUS_FEATURE_CHG_BASIC + u32 noise_rjct_scl; + u32 noise_rjct_sda; + bool noise_rjct_support; +#endif }; static struct geni_i2c_dev *gi2c_dev_dbg[MAX_SE]; @@ -201,6 +215,13 @@ static inline void qcom_geni_i2c_conf(struct geni_i2c_dev *gi2c, int dfs) geni_write_reg(((itr->t_high << 20) | (itr->t_low << 10) | itr->t_cycle), gi2c->base, SE_I2C_SCL_COUNTERS); +#ifdef OPLUS_FEATURE_CHG_BASIC + if (gi2c->noise_rjct_support) { + geni_write_reg(gi2c->noise_rjct_scl << 1 | gi2c->noise_rjct_sda << 3, + gi2c->base, SE_I2C_NOISE_CANCEL_CTL); + } +#endif + /* * Ensure Clk config completes before return. */ @@ -724,7 +745,103 @@ geni_i2c_gsi_xfer_out: ret = gi2c->err; return ret; } +#ifdef OPLUS_FEATURE_CHG_BASIC +#define MAX_RESET_COUNT 10 +#define MIN_RESET_COUNT 0 +#define I2C_RESET_BUS 0 +#define FG_DEVICE_ADDR 0x55 +#define DA9313_DEVICE_ADDR 0x68 +//#define CHARGER_DEVICE_ADDR 0x5c +//#define MCU_DEVICE_ADDR 0x26 +static bool i2c_err_occured = false; +static unsigned int err_count = MAX_RESET_COUNT; +extern int rpmb_is_enable(void); +bool oplus_get_fg_i2c_err_occured(void) +{ + return i2c_err_occured; +} +EXPORT_SYMBOL(oplus_get_fg_i2c_err_occured); + +void oplus_set_fg_i2c_err_occured(bool i2c_err) +{ + i2c_err_occured = i2c_err; +} +EXPORT_SYMBOL(oplus_set_fg_i2c_err_occured); + +static void i2c_oplus_gpio_reset(struct geni_i2c_dev *gi2c) +{ + int ret = 0; + int i = 0; + static bool i2c_reset_processing = false; + int boot_mode = get_boot_mode(); + + //dev_err(gi2c->dev, "%s: start, return\n", __func__); + if (gi2c == NULL) + return; + + if ((boot_mode != MSM_BOOT_MODE__NORMAL) + && (boot_mode != MSM_BOOT_MODE__RECOVERY) + && (boot_mode != MSM_BOOT_MODE__SILENCE) + && (boot_mode != MSM_BOOT_MODE__SAU) + && (boot_mode != MSM_BOOT_MODE__CHARGE)) { + dev_err(gi2c->dev, "%s: get_boot_mode[%d], return\n", __func__, boot_mode); + return; + } + + if (i2c_reset_processing == true) { + dev_err(gi2c->dev, "%s: i2c_reset is processing, return\n", __func__); + return; + } + + i2c_reset_processing = true; + + if (!IS_ERR_OR_NULL(gi2c->i2c_rsc.geni_gpio_pulldown)) { + dev_err(gi2c->dev, "%s: set geni_gpio_pulldown\n", __func__); + ret = pinctrl_select_state(gi2c->i2c_rsc.geni_pinctrl, gi2c->i2c_rsc.geni_gpio_pulldown); + if (ret) { + dev_err(gi2c->dev, "%s: error pinctrl_select_state pulldown, ret:%d\n", __func__, ret); + goto err; + } + } else { + goto err; + } + + for (i = 0; i < 220; i++) { + usleep_range(10000, 11000); + if (oplus_vooc_get_fastchg_started() == true && oplus_vooc_get_fastchg_ing() == false) { + dev_err(gi2c->dev, "%s: vooc ready to start, don't pull down i2c, i:%d\n", __func__, i); + break; + } + } + oplus_set_fg_i2c_err_occured(true); + + if (!IS_ERR_OR_NULL(gi2c->i2c_rsc.geni_gpio_pullup)) { + dev_err(gi2c->dev, "%s: set geni_gpio_pullup\n", __func__); + ret = pinctrl_select_state(gi2c->i2c_rsc.geni_pinctrl, gi2c->i2c_rsc.geni_gpio_pullup); + if (ret) { + dev_err(gi2c->dev, "%s:error pinctrl_select_state pullup, ret:%d\n", __func__, ret); + } + } + if (!IS_ERR_OR_NULL(gi2c->i2c_rsc.geni_gpio_active)) { + dev_err(gi2c->dev, "%s: set geni_gpio_active\n", __func__); + ret = pinctrl_select_state(gi2c->i2c_rsc.geni_pinctrl, gi2c->i2c_rsc.geni_gpio_active); + if (ret) { + dev_err(gi2c->dev, "%s:error pinctrl_select_state active, ret:%d\n", __func__, ret); + goto err; + } + } else { + goto err; + } + + i2c_reset_processing = false; + dev_err(gi2c->dev, "%s: gpio reset successful id:%d\n", __func__, gi2c->adap.nr); + return; + +err: + i2c_reset_processing = false; +} +#endif /*OPLUS_FEATURE_CHG_BASIC*/ static int geni_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) @@ -902,6 +1019,23 @@ static int geni_i2c_xfer(struct i2c_adapter *adap, } ret = gi2c->err; +#ifdef OPLUS_FEATURE_CHG_BASIC + if(msgs[i].addr == FG_DEVICE_ADDR || msgs[i].addr == DA9313_DEVICE_ADDR) { + if (gi2c->err) { + dev_err(gi2c->dev, "gi2c->adap.nr[%d], err_count[%d], msgs[i].addr[0x%x]\n", gi2c->adap.nr, err_count, msgs[i].addr); + if (err_count > MIN_RESET_COUNT && err_count < MAX_RESET_COUNT) { + i2c_oplus_gpio_reset(gi2c); + } else { + dev_err(gi2c->dev, "err_count(%d) >= %d so not reset\n", err_count, MAX_RESET_COUNT); + } + err_count++; + } else { + if(msgs[i].addr == FG_DEVICE_ADDR) { + err_count = 0; + } + } + } +#endif if (gi2c->err) { GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev, "i2c error :%d\n", gi2c->err); @@ -1027,7 +1161,24 @@ static int geni_i2c_probe(struct platform_device *pdev) gi2c->is_shared = true; dev_info(&pdev->dev, "Multi-EE usecase\n"); } - +#ifdef OPLUS_FEATURE_CHG_BASIC + gi2c->i2c_rsc.geni_gpio_pulldown = + pinctrl_lookup_state(gi2c->i2c_rsc.geni_pinctrl, + PINCTRL_PULLDOWN); + if (IS_ERR_OR_NULL(gi2c->i2c_rsc.geni_gpio_pulldown)) { + /*dev_err(&pdev->dev, "No pulldown config specified\n"); + ret = PTR_ERR(gi2c->i2c_rsc.geni_gpio_pulldown); + return ret;*/ + } + gi2c->i2c_rsc.geni_gpio_pullup = + pinctrl_lookup_state(gi2c->i2c_rsc.geni_pinctrl, + PINCTRL_PULLUP); + if (IS_ERR_OR_NULL(gi2c->i2c_rsc.geni_gpio_pullup)) { + /*dev_err(&pdev->dev, "No pulldown config specified\n"); + ret = PTR_ERR(gi2c->i2c_rsc.geni_gpio_pullup); + return ret;*/ + } +#endif if (of_property_read_u32(pdev->dev.of_node, "qcom,clk-freq-out", &gi2c->i2c_rsc.clk_freq_out)) { gi2c->i2c_rsc.clk_freq_out = KHz(400); @@ -1035,6 +1186,22 @@ static int geni_i2c_probe(struct platform_device *pdev) dev_info(&pdev->dev, "Bus frequency is set to %dHz\n", gi2c->i2c_rsc.clk_freq_out); +#ifdef OPLUS_FEATURE_CHG_BASIC + gi2c->noise_rjct_scl = 0; + gi2c->noise_rjct_sda = 0; + gi2c->noise_rjct_support = true; + + ret = of_property_read_u32(pdev->dev.of_node, "qcom,noise-rjct-scl", + &gi2c->noise_rjct_scl); + if(ret < 0) + gi2c->noise_rjct_support = false; + + of_property_read_u32(pdev->dev.of_node, "qcom,noise-rjct-sda", + &gi2c->noise_rjct_sda); + if(ret < 0) + gi2c->noise_rjct_support = false; +#endif + gi2c->irq = platform_get_irq(pdev, 0); if (gi2c->irq < 0) { dev_err(gi2c->dev, "IRQ error for i2c-geni\n"); diff --git a/drivers/iio/adc/qcom-spmi-adc5.c b/drivers/iio/adc/qcom-spmi-adc5.c index d5f06dffb7de..8045cf3c2d82 100644 --- a/drivers/iio/adc/qcom-spmi-adc5.c +++ b/drivers/iio/adc/qcom-spmi-adc5.c @@ -142,6 +142,11 @@ struct adc_channel_prop { unsigned int lut_index; enum vadc_scale_fn_type scale_fn_type; const char *datasheet_name; + +#ifdef OPLUS_FEATURE_CHG_BASIC + int cust_type; + int cust_scale_fn_type; +#endif }; /** @@ -405,9 +410,14 @@ static int adc_pre_configure_usb_in_read(struct adc_chip *adc) u8 data = ADC_CAL_DELAY_CTL_VAL_256S; bool channel_check = false; - if (adc->pmic_rev_id) + if (adc->pmic_rev_id){ +#ifndef OPLUS_FEATURE_CHG_BASIC if (adc->pmic_rev_id->pmic_subtype == PMI632_SUBTYPE) +#else + if (adc->pmic_rev_id->pmic_subtype == PMI632_SUBTYPE || adc->pmic_rev_id->pmic_subtype == PM7250B_SUBTYPE) +#endif channel_check = true; + } /* Increase calibration measurement interval to 256s */ ret = regmap_bulk_write(adc->regmap, @@ -483,9 +493,14 @@ static int adc_configure(struct adc_chip *adc, u8 conv_req = 0; bool channel_check = false; - if (adc->pmic_rev_id) + if (adc->pmic_rev_id){ +#ifndef OPLUS_FEATURE_CHG_BASIC if (adc->pmic_rev_id->pmic_subtype == PMI632_SUBTYPE) +#else + if (adc->pmic_rev_id->pmic_subtype == PMI632_SUBTYPE || adc->pmic_rev_id->pmic_subtype == PM7250B_SUBTYPE) +#endif channel_check = true; + } /* Read registers 0x42 through 0x46 */ ret = adc_read(adc, ADC_USR_DIG_PARAM, buf, ADC5_MULTI_TRANSFER); @@ -767,10 +782,38 @@ static int adc_read_raw(struct iio_dev *indio_dev, struct adc_channel_prop *prop; u16 adc_code_volt, adc_code_cur; int ret; +#ifdef OPLUS_FEATURE_CHG_BASIC + s64 voltage = 0, adc_vdd_ref_mv = 1875; +#endif prop = &adc->chan_props[chan->address]; switch (mask) { +#ifdef OPLUS_FEATURE_CHG_BASIC + case IIO_CHAN_INFO_OFFSET: + ret = adc_do_conversion(adc, prop, chan, + &adc_code_volt, &adc_code_cur); + if (ret) + break; + if (*val2 < 0) { + voltage = (s64) adc_code_volt * adc_vdd_ref_mv * 1000; + voltage = div64_s64(voltage, adc->data->full_scale_code_volt); + pr_err("%s : adc_code_volt before compensation : %d(uV)\n", __func__, voltage); + voltage += *val2; + pr_err("%s : adc_code_volt after compensation : %d(uV)\n", __func__, voltage); + voltage = voltage * adc->data->full_scale_code_volt; + adc_code_volt = (u16)div64_s64(voltage, (adc_vdd_ref_mv * 1000)); + } + if ((chan->type == IIO_VOLTAGE) || (chan->type == IIO_TEMP)) + ret = qcom_vadc_hw_scale(prop->scale_fn_type, + &adc_prescale_ratios[prop->prescale], + adc->data, prop->lut_index, + adc_code_volt, val); + if (ret) + break; + + return IIO_VAL_INT; +#endif case IIO_CHAN_INFO_PROCESSED: ret = adc_do_conversion(adc, prop, chan, &adc_code_volt, &adc_code_cur); @@ -905,10 +948,25 @@ static const struct adc_channels adc_chans_pmic5[ADC_MAX_CHANNEL] = { SCALE_HW_CALIB_THERM_100K_PULLUP) [ADC_AMUX_THM2_PU2] = ADC_CHAN_TEMP("amux_thm2_pu2", 1, SCALE_HW_CALIB_THERM_100K_PULLUP) +#ifdef CONFIG_OPLUS_SM7250R_CHARGER //OPLUS_FEATURE_CHG_BASIC + [ADC_AMUX_THM3_PU2] = ADC_CHAN_TEMP("amux_thm3_pu2", 1, + SCALE_HW_CALIB_DEFAULT) +#else [ADC_AMUX_THM3_PU2] = ADC_CHAN_TEMP("amux_thm3_pu2", 1, SCALE_HW_CALIB_THERM_100K_PULLUP) +#endif +#ifdef OPLUS_FEATURE_CHG_BASIC + [ADC_AMUX_THM4_PU2] = ADC_CHAN_VOLT("amux_thm4_pu2", 1, + SCALE_HW_CALIB_DEFAULT) +#else [ADC_AMUX_THM4_PU2] = ADC_CHAN_TEMP("amux_thm4_pu2", 1, SCALE_HW_CALIB_THERM_100K_PULLUP) +#endif +#ifdef OPLUS_FEATURE_CHG_BASIC +/* yangmingjin,2020/3/9, add for usbtemp_adc */ + [ADC_AMUX_THM4] = ADC_CHAN_VOLT("amux_thm4", 1, + SCALE_HW_CALIB_DEFAULT) +#endif [ADC_PARALLEL_ISENSE] = ADC_CHAN_VOLT("parallel_isense", 1, SCALE_HW_CALIB_CUR) [ADC_INT_EXT_ISENSE_VBAT_VDATA] = ADC_CHAN_POWER( @@ -929,10 +987,469 @@ static const struct adc_channels adc_chans_pmic5[ADC_MAX_CHANNEL] = { SCALE_HW_CALIB_THERM_100K_PULLUP) [ADC_GPIO3_PU2] = ADC_CHAN_TEMP("gpio3_pu2", 1, SCALE_HW_CALIB_THERM_100K_PULLUP) + [ADC_GPIO3] = ADC_CHAN_VOLT("gpio7_v", 1, + SCALE_HW_CALIB_DEFAULT) + + [ADC_GPIO3_DIV3] = ADC_CHAN_VOLT("gpio7_div3", 1, + SCALE_HW_CALIB_DEFAULT) + +#ifdef CONFIG_OPLUS_SM7250R_CHARGER //OPLUS_FEATURE_CHG_BASIC [ADC_GPIO4_PU2] = ADC_CHAN_TEMP("gpio4_pu2", 1, SCALE_HW_CALIB_THERM_100K_PULLUP) +#else + [ADC_GPIO4_PU2] = ADC_CHAN_VOLT("gpio8_v", 1, + SCALE_HW_CALIB_DEFAULT) +#endif + +#ifdef OPLUS_FEATURE_CHG_BASIC +/* yangmingjin,2020/3/9, add for usbtemp_adc */ + [ADC_GPIO4] = ADC_CHAN_VOLT("gpio8_vol", 1, + SCALE_HW_CALIB_DEFAULT) +#endif + +#ifdef OPLUS_FEATURE_CHG_BASIC +#ifdef OPLUS_CUSTOM_OP_DEF +#ifdef CONFIG_ARCH_LITO + [ADC_GPIO1_PU1] = ADC_CHAN_VOLT("usb_temp_l", 1, + SCALE_HW_CALIB_DEFAULT) + [ADC_GPIO2_PU1] = ADC_CHAN_VOLT("usb_temp_r", 1, + SCALE_HW_CALIB_DEFAULT) +#else + [ADC_AMUX_THM4_PU1] = ADC_CHAN_VOLT("usb_temp_adc", 1, + SCALE_HW_CALIB_DEFAULT) + [ADC_GPIO4_PU1] = ADC_CHAN_VOLT("usb_supplementary_temp_adc", 1, + SCALE_HW_CALIB_DEFAULT) +#endif // CONFIG_ARCH_LITO +#endif // OPLUS_CUSTOM_OP_DEF +#endif // OPLUS_FEATURE_CHG_BASIC + +#ifdef OPLUS_FEATURE_CHG_BASIC + [ADC_GPIO1] = ADC_CHAN_VOLT("board_id_vdata", 1, + SCALE_HW_CALIB_DEFAULT) +#endif + [ADC_INT_EXT_ISENSE] = ADC_CHAN_VOLT("ext_isense", 1, + SCALE_HW_CALIB_CUR) }; +static const struct adc_channels adc_chans_pmic5_21027[ADC_MAX_CHANNEL] = { + [ADC_REF_GND] = ADC_CHAN_VOLT("ref_gnd", 1, + SCALE_HW_CALIB_DEFAULT) + [ADC_1P25VREF] = ADC_CHAN_VOLT("vref_1p25", 1, + SCALE_HW_CALIB_DEFAULT) + [ADC_VPH_PWR] = ADC_CHAN_VOLT("vph_pwr", 3, + SCALE_HW_CALIB_DEFAULT) + [ADC_VBAT_SNS] = ADC_CHAN_VOLT("vbat_sns", 3, + SCALE_HW_CALIB_DEFAULT) + [ADC_VCOIN] = ADC_CHAN_VOLT("vcoin", 3, + SCALE_HW_CALIB_DEFAULT) + [ADC_DIE_TEMP] = ADC_CHAN_TEMP("die_temp", 1, + SCALE_HW_CALIB_PMIC_THERM) + [ADC_USB_IN_I] = ADC_CHAN_VOLT("usb_in_i_uv", 1, + SCALE_HW_CALIB_DEFAULT) + [ADC_USB_IN_V_16] = ADC_CHAN_VOLT("usb_in_v_div_16", 16, + SCALE_HW_CALIB_DEFAULT) + [ADC_CHG_TEMP] = ADC_CHAN_TEMP("chg_temp", 1, + SCALE_HW_CALIB_PM5_CHG_TEMP) + /* Charger prescales SBUx and MID_CHG to fit within 1.8V upper unit */ + [ADC_SBUx] = ADC_CHAN_VOLT("chg_sbux", 3, + SCALE_HW_CALIB_DEFAULT) + [ADC_MID_CHG_DIV6] = ADC_CHAN_VOLT("chg_mid_chg", 6, + SCALE_HW_CALIB_DEFAULT) + [ADC_XO_THERM_PU2] = ADC_CHAN_TEMP("xo_therm", 1, + SCALE_HW_CALIB_XOTHERM) +#ifdef OPLUS_FEATURE_CHG_BASIC +/* gaoxian,2021/10/29, add for battemp_adc */ + [ADC_BAT_THERM_PU2] = ADC_CHAN_VOLT("bat_therm_pu2", 1, + SCALE_HW_CALIB_BATT_THERM_100K) +#else + [ADC_BAT_THERM_PU2] = ADC_CHAN_TEMP("bat_therm_pu2", 1, + SCALE_HW_CALIB_BATT_THERM_100K) +#endif + [ADC_BAT_THERM_PU1] = ADC_CHAN_TEMP("bat_therm_pu1", 1, + SCALE_HW_CALIB_BATT_THERM_30K) + [ADC_BAT_THERM_PU3] = ADC_CHAN_TEMP("bat_therm_pu3", 1, + SCALE_HW_CALIB_BATT_THERM_400K) + [ADC_BAT_ID_PU2] = ADC_CHAN_TEMP("bat_id", 1, + SCALE_HW_CALIB_DEFAULT) + [ADC_AMUX_THM1_PU2] = ADC_CHAN_TEMP("amux_thm1_pu2", 1, + SCALE_HW_CALIB_THERM_100K_PULLUP) + +#ifdef OPLUS_FEATURE_CHG_BASIC +/* gaoxian,2021/10/29, add for usbtemp_adc */ + [ADC_AMUX_THM2_PU2] = ADC_CHAN_TEMP("amux_thm2_pu2", 1, + SCALE_HW_CALIB_DEFAULT) +#else + [ADC_AMUX_THM2_PU2] = ADC_CHAN_TEMP("amux_thm2_pu2", 1, + SCALE_HW_CALIB_THERM_100K_PULLUP) +#endif + +#ifdef OPLUS_FEATURE_CHG_BASIC + [ADC_AMUX_THM3_PU2] = ADC_CHAN_TEMP("amux_thm3_pu2", 1, + SCALE_HW_CALIB_DEFAULT) +#else + [ADC_AMUX_THM3_PU2] = ADC_CHAN_TEMP("amux_thm3_pu2", 1, + SCALE_HW_CALIB_THERM_100K_PULLUP) +#endif +#ifdef OPLUS_FEATURE_CHG_BASIC + [ADC_AMUX_THM4_PU2] = ADC_CHAN_VOLT("amux_thm4_pu2", 1, + SCALE_HW_CALIB_DEFAULT) +#else + [ADC_AMUX_THM4_PU2] = ADC_CHAN_TEMP("amux_thm4_pu2", 1, + SCALE_HW_CALIB_THERM_100K_PULLUP) +#endif +#ifdef OPLUS_FEATURE_CHG_BASIC +/* yangmingjin,2020/3/9, add for usbtemp_adc */ + [ADC_AMUX_THM4] = ADC_CHAN_VOLT("amux_thm4", 1, + SCALE_HW_CALIB_DEFAULT) +#endif + [ADC_PARALLEL_ISENSE] = ADC_CHAN_VOLT("parallel_isense", 1, + SCALE_HW_CALIB_CUR) + [ADC_INT_EXT_ISENSE_VBAT_VDATA] = ADC_CHAN_POWER( + "int_ext_vbat_isense", 1, + SCALE_HW_CALIB_CUR) + [ADC_EXT_ISENSE_VBAT_VDATA] = ADC_CHAN_POWER("ext_vbat_isense", 1, + SCALE_HW_CALIB_CUR) + [ADC_PARALLEL_ISENSE_VBAT_VDATA] = ADC_CHAN_POWER( + "parallel_vbat_isense", 1, + SCALE_HW_CALIB_CUR) + +#ifdef OPLUS_FEATURE_CHG_BASIC +/* gaoxian,2021/10/29, add for usbtemp_adc */ + [ADC_AMUX_THM2] = ADC_CHAN_TEMP("amux_thm2", 1, + SCALE_HW_CALIB_THERM_100K_PULLUP) +#else + [ADC_AMUX_THM2] = ADC_CHAN_TEMP("amux_thm2", 1, + SCALE_HW_CALIB_PM5_SMB_TEMP) +#endif + + [ADC_AMUX_THM3] = ADC_CHAN_TEMP("amux_thm3", 1, + SCALE_HW_CALIB_PM5_SMB_TEMP) + [ADC_GPIO1_PU2] = ADC_CHAN_TEMP("gpio1_pu2", 1, + SCALE_HW_CALIB_THERM_100K_PULLUP) + [ADC_GPIO2_PU2] = ADC_CHAN_TEMP("gpio2_pu2", 1, + SCALE_HW_CALIB_THERM_100K_PULLUP) + [ADC_GPIO3_PU2] = ADC_CHAN_TEMP("gpio3_pu2", 1, + SCALE_HW_CALIB_THERM_100K_PULLUP) + [ADC_GPIO3] = ADC_CHAN_VOLT("gpio7_v", 1, + SCALE_HW_CALIB_DEFAULT) + + [ADC_GPIO3_DIV3] = ADC_CHAN_VOLT("gpio7_div3", 1, + SCALE_HW_CALIB_DEFAULT) + +#ifdef CONFIG_OPLUS_SM7250R_CHARGER //OPLUS_FEATURE_CHG_BASIC + [ADC_GPIO4_PU2] = ADC_CHAN_TEMP("gpio4_pu2", 1, + SCALE_HW_CALIB_THERM_100K_PULLUP) +#else + [ADC_GPIO4_PU2] = ADC_CHAN_VOLT("gpio8_v", 1, + SCALE_HW_CALIB_DEFAULT) +#endif + +#ifdef OPLUS_FEATURE_CHG_BASIC +/* yangmingjin,2020/3/9, add for usbtemp_adc */ + [ADC_GPIO4] = ADC_CHAN_VOLT("gpio8_vol", 1, + SCALE_HW_CALIB_DEFAULT) +#endif +#ifdef OPLUS_FEATURE_CHG_BASIC + [ADC_GPIO1] = ADC_CHAN_VOLT("board_id_vdata", 1, + SCALE_HW_CALIB_DEFAULT) +#endif +}; + +//#ifdef OPLUS_FEATURE_TEMP_ADAPTER +static const struct adc_channels adc_chans_pmic5_temp[ADC_MAX_CHANNEL] = { + [ADC_REF_GND] = ADC_CHAN_VOLT("ref_gnd", 1, + SCALE_HW_CALIB_DEFAULT) + [ADC_1P25VREF] = ADC_CHAN_VOLT("vref_1p25", 1, + SCALE_HW_CALIB_DEFAULT) + [ADC_VPH_PWR] = ADC_CHAN_VOLT("vph_pwr", 3, + SCALE_HW_CALIB_DEFAULT) + [ADC_VBAT_SNS] = ADC_CHAN_VOLT("vbat_sns", 3, + SCALE_HW_CALIB_DEFAULT) + [ADC_VCOIN] = ADC_CHAN_VOLT("vcoin", 3, + SCALE_HW_CALIB_DEFAULT) + [ADC_DIE_TEMP] = ADC_CHAN_TEMP("die_temp", 1, + SCALE_HW_CALIB_PMIC_THERM) + [ADC_USB_IN_I] = ADC_CHAN_VOLT("usb_in_i_uv", 1, + SCALE_HW_CALIB_DEFAULT) + [ADC_USB_IN_V_16] = ADC_CHAN_VOLT("usb_in_v_div_16", 16, + SCALE_HW_CALIB_DEFAULT) + [ADC_CHG_TEMP] = ADC_CHAN_TEMP("chg_temp", 1, + SCALE_HW_CALIB_PM5_CHG_TEMP) + /* Charger prescales SBUx and MID_CHG to fit within 1.8V upper unit */ + [ADC_SBUx] = ADC_CHAN_VOLT("chg_sbux", 3, + SCALE_HW_CALIB_DEFAULT) + [ADC_MID_CHG_DIV6] = ADC_CHAN_VOLT("chg_mid_chg", 6, + SCALE_HW_CALIB_DEFAULT) + [ADC_XO_THERM_PU2] = ADC_CHAN_TEMP("xo_therm", 1, + SCALE_HW_CALIB_XOTHERM) + [ADC_BAT_THERM_PU2] = ADC_CHAN_TEMP("bat_therm_pu2", 1, + SCALE_HW_CALIB_BATT_THERM_100K) + [ADC_BAT_THERM_PU1] = ADC_CHAN_TEMP("bat_therm_pu1", 1, + SCALE_HW_CALIB_BATT_THERM_30K) + [ADC_BAT_THERM_PU3] = ADC_CHAN_TEMP("bat_therm_pu3", 1, + SCALE_HW_CALIB_BATT_THERM_400K) + [ADC_BAT_ID_PU2] = ADC_CHAN_TEMP("bat_id", 1, + SCALE_HW_CALIB_DEFAULT) + [ADC_AMUX_THM1_PU2] = ADC_CHAN_TEMP("amux_thm1_pu2", 1, + SCALE_HW_CALIB_THERM_100K_PULLUP) + [ADC_AMUX_THM2_PU2] = ADC_CHAN_TEMP("amux_thm2_pu2", 1, + SCALE_HW_CALIB_THERM_100K_PULLUP) + [ADC_AMUX_THM3_PU2] = ADC_CHAN_TEMP("amux_thm3_pu2", 1, + SCALE_HW_CALIB_THERM_100K_PULLUP) +#ifdef OPLUS_FEATURE_CHG_BASIC + [ADC_AMUX_THM4_PU2] = ADC_CHAN_VOLT("amux_thm4_pu2", 1, + SCALE_HW_CALIB_DEFAULT) +#else + [ADC_AMUX_THM4_PU2] = ADC_CHAN_TEMP("amux_thm4_pu2", 1, + SCALE_HW_CALIB_THERM_100K_PULLUP) +#endif +#ifdef OPLUS_FEATURE_CHG_BASIC +/* yangmingjin,2020/3/9, add for usbtemp_adc */ + [ADC_AMUX_THM4] = ADC_CHAN_VOLT("amux_thm4", 1, + SCALE_HW_CALIB_DEFAULT) +#endif + [ADC_PARALLEL_ISENSE] = ADC_CHAN_VOLT("parallel_isense", 1, + SCALE_HW_CALIB_CUR) + [ADC_INT_EXT_ISENSE_VBAT_VDATA] = ADC_CHAN_POWER( + "int_ext_vbat_isense", 1, + SCALE_HW_CALIB_CUR) + [ADC_EXT_ISENSE_VBAT_VDATA] = ADC_CHAN_POWER("ext_vbat_isense", 1, + SCALE_HW_CALIB_CUR) + [ADC_PARALLEL_ISENSE_VBAT_VDATA] = ADC_CHAN_POWER( + "parallel_vbat_isense", 1, + SCALE_HW_CALIB_CUR) + [ADC_AMUX_THM2] = ADC_CHAN_TEMP("amux_thm2", 1, + SCALE_HW_CALIB_PM5_SMB_TEMP) + [ADC_AMUX_THM3] = ADC_CHAN_TEMP("amux_thm3", 1, + SCALE_HW_CALIB_PM5_SMB_TEMP) + [ADC_GPIO1_PU2] = ADC_CHAN_TEMP("gpio1_pu2", 1, + SCALE_HW_CALIB_THERM_100K_PULLUP) + [ADC_GPIO2_PU2] = ADC_CHAN_TEMP("gpio2_pu2", 1, + SCALE_HW_CALIB_THERM_100K_PULLUP) + [ADC_GPIO3_PU2] = ADC_CHAN_TEMP("gpio3_pu2", 1, + SCALE_HW_CALIB_THERM_100K_PULLUP) + [ADC_GPIO3] = ADC_CHAN_VOLT("gpio7_v", 1, + SCALE_HW_CALIB_DEFAULT) +#ifdef CONFIG_OPLUS_SM7250R_CHARGER //OPLUS_FEATURE_CHG_BASIC + [ADC_GPIO4_PU2] = ADC_CHAN_TEMP("gpio4_pu2", 1, + SCALE_HW_CALIB_THERM_100K_PULLUP) +#else + [ADC_GPIO4_PU2] = ADC_CHAN_VOLT("gpio8_v", 1, + SCALE_HW_CALIB_DEFAULT) +#endif + +#ifdef OPLUS_FEATURE_CHG_BASIC +/* yangmingjin,2020/3/9, add for usbtemp_adc */ + [ADC_GPIO4] = ADC_CHAN_VOLT("gpio8_vol", 1, + SCALE_HW_CALIB_DEFAULT) +#endif +#ifdef OPLUS_FEATURE_CHG_BASIC + [ADC_GPIO1] = ADC_CHAN_VOLT("board_id_vdata", 1, + SCALE_HW_CALIB_DEFAULT) +#endif +}; +//#endif + +#ifdef OPLUS_FEATURE_CHG_BASIC +static const struct adc_channels adc_chans_pmic5_7225[ADC_MAX_CHANNEL] = { + [ADC_REF_GND] = ADC_CHAN_VOLT("ref_gnd", 1, + SCALE_HW_CALIB_DEFAULT) + [ADC_1P25VREF] = ADC_CHAN_VOLT("vref_1p25", 1, + SCALE_HW_CALIB_DEFAULT) + [ADC_VPH_PWR] = ADC_CHAN_VOLT("vph_pwr", 3, + SCALE_HW_CALIB_DEFAULT) + [ADC_VBAT_SNS] = ADC_CHAN_VOLT("vbat_sns", 3, + SCALE_HW_CALIB_DEFAULT) + [ADC_VCOIN] = ADC_CHAN_VOLT("vcoin", 3, + SCALE_HW_CALIB_DEFAULT) + [ADC_DIE_TEMP] = ADC_CHAN_TEMP("die_temp", 1, + SCALE_HW_CALIB_PMIC_THERM) + [ADC_USB_IN_I] = ADC_CHAN_VOLT("usb_in_i_uv", 1, + SCALE_HW_CALIB_DEFAULT) + [ADC_USB_IN_V_16] = ADC_CHAN_VOLT("usb_in_v_div_16", 16, + SCALE_HW_CALIB_DEFAULT) + [ADC_CHG_TEMP] = ADC_CHAN_TEMP("chg_temp", 1, + SCALE_HW_CALIB_PM5_CHG_TEMP) + /* Charger prescales SBUx and MID_CHG to fit within 1.8V upper unit */ + [ADC_SBUx] = ADC_CHAN_VOLT("chg_sbux", 3, + SCALE_HW_CALIB_DEFAULT) + [ADC_MID_CHG_DIV6] = ADC_CHAN_VOLT("chg_mid_chg", 6, + SCALE_HW_CALIB_DEFAULT) + [ADC_XO_THERM_PU2] = ADC_CHAN_TEMP("xo_therm", 1, + SCALE_HW_CALIB_XOTHERM) + [ADC_BAT_THERM_PU2] = ADC_CHAN_TEMP("bat_therm_pu2", 1, + SCALE_HW_CALIB_BATT_THERM_100K) + [ADC_BAT_THERM_PU1] = ADC_CHAN_TEMP("bat_therm_pu1", 1, + SCALE_HW_CALIB_BATT_THERM_30K) + [ADC_BAT_THERM_PU3] = ADC_CHAN_TEMP("bat_therm_pu3", 1, + SCALE_HW_CALIB_BATT_THERM_400K) + [ADC_BAT_ID_PU2] = ADC_CHAN_TEMP("bat_id", 1, + SCALE_HW_CALIB_DEFAULT) + [ADC_AMUX_THM1_PU2] = ADC_CHAN_TEMP("amux_thm1_pu2", 1, + SCALE_HW_CALIB_THERM_100K_PULLUP) + [ADC_AMUX_THM2_PU2] = ADC_CHAN_TEMP("amux_thm2_pu2", 1, + SCALE_HW_CALIB_THERM_100K_PULLUP) +#ifdef CONFIG_OPLUS_SM7225R_CHARGER + [ADC_AMUX_THM3_PU2] = ADC_CHAN_VOLT("amux_thm3_pu2", 1, + SCALE_HW_CALIB_DEFAULT) +#else + [ADC_AMUX_THM3_PU2] = ADC_CHAN_TEMP("amux_thm3_pu2", 1, + SCALE_HW_CALIB_THERM_100K_PULLUP) +#endif +#ifdef OPLUS_FEATURE_CHG_BASIC + [ADC_AMUX_THM4_PU2] = ADC_CHAN_VOLT("amux_thm4_pu2", 1, + SCALE_HW_CALIB_DEFAULT) +#else + [ADC_AMUX_THM4_PU2] = ADC_CHAN_TEMP("amux_thm4_pu2", 1, + SCALE_HW_CALIB_THERM_100K_PULLUP) +#endif +#ifdef OPLUS_FEATURE_CHG_BASIC +/* yangmingjin,2020/3/9, add for usbtemp_adc */ + [ADC_AMUX_THM4] = ADC_CHAN_VOLT("amux_thm4", 1, + SCALE_HW_CALIB_DEFAULT) +#endif + [ADC_PARALLEL_ISENSE] = ADC_CHAN_VOLT("parallel_isense", 1, + SCALE_HW_CALIB_CUR) + [ADC_INT_EXT_ISENSE_VBAT_VDATA] = ADC_CHAN_POWER( + "int_ext_vbat_isense", 1, + SCALE_HW_CALIB_CUR) + [ADC_EXT_ISENSE_VBAT_VDATA] = ADC_CHAN_POWER("ext_vbat_isense", 1, + SCALE_HW_CALIB_CUR) + [ADC_PARALLEL_ISENSE_VBAT_VDATA] = ADC_CHAN_POWER( + "parallel_vbat_isense", 1, + SCALE_HW_CALIB_CUR) + [ADC_AMUX_THM2] = ADC_CHAN_TEMP("amux_thm2", 1, + SCALE_HW_CALIB_PM5_SMB_TEMP) + [ADC_AMUX_THM3] = ADC_CHAN_TEMP("amux_thm3", 1, + SCALE_HW_CALIB_PM5_SMB_TEMP) + [ADC_GPIO1_PU2] = ADC_CHAN_TEMP("gpio1_pu2", 1, + SCALE_HW_CALIB_THERM_100K_PULLUP) + [ADC_GPIO2_PU2] = ADC_CHAN_TEMP("gpio2_pu2", 1, + SCALE_HW_CALIB_THERM_100K_PULLUP) + [ADC_GPIO3_PU2] = ADC_CHAN_TEMP("gpio3_pu2", 1, + SCALE_HW_CALIB_THERM_100K_PULLUP) + [ADC_GPIO3] = ADC_CHAN_VOLT("gpio7_v", 1, + SCALE_HW_CALIB_DEFAULT) +#ifdef CONFIG_OPLUS_SM7250R_CHARGER //OPLUS_FEATURE_CHG_BASIC + [ADC_GPIO4_PU2] = ADC_CHAN_TEMP("gpio4_pu2", 1, + SCALE_HW_CALIB_THERM_100K_PULLUP) +#else + [ADC_GPIO4_PU2] = ADC_CHAN_VOLT("gpio8_v", 1, + SCALE_HW_CALIB_DEFAULT) +#endif + +#ifdef OPLUS_FEATURE_CHG_BASIC +/* yangmingjin,2020/3/9, add for usbtemp_adc */ + [ADC_GPIO4] = ADC_CHAN_VOLT("gpio8_vol", 1, + SCALE_HW_CALIB_DEFAULT) +#endif +#ifdef OPLUS_FEATURE_CHG_BASIC + [ADC_GPIO1] = ADC_CHAN_VOLT("board_id_vdata", 1, + SCALE_HW_CALIB_DEFAULT) +#endif +}; +#endif + +#ifdef OPLUS_FEATURE_CHG_BASIC +static const struct adc_channels adc_chans_pmic5_7225_s[ADC_MAX_CHANNEL] = { + [ADC_REF_GND] = ADC_CHAN_VOLT("ref_gnd", 1, + SCALE_HW_CALIB_DEFAULT) + [ADC_1P25VREF] = ADC_CHAN_VOLT("vref_1p25", 1, + SCALE_HW_CALIB_DEFAULT) + [ADC_VPH_PWR] = ADC_CHAN_VOLT("vph_pwr", 3, + SCALE_HW_CALIB_DEFAULT) + [ADC_VBAT_SNS] = ADC_CHAN_VOLT("vbat_sns", 3, + SCALE_HW_CALIB_DEFAULT) + [ADC_VCOIN] = ADC_CHAN_VOLT("vcoin", 3, + SCALE_HW_CALIB_DEFAULT) + [ADC_DIE_TEMP] = ADC_CHAN_TEMP("die_temp", 1, + SCALE_HW_CALIB_PMIC_THERM) + [ADC_USB_IN_I] = ADC_CHAN_VOLT("usb_in_i_uv", 1, + SCALE_HW_CALIB_DEFAULT) + [ADC_USB_IN_V_16] = ADC_CHAN_VOLT("usb_in_v_div_16", 16, + SCALE_HW_CALIB_DEFAULT) + [ADC_CHG_TEMP] = ADC_CHAN_TEMP("chg_temp", 1, + SCALE_HW_CALIB_PM5_CHG_TEMP) + /* Charger prescales SBUx and MID_CHG to fit within 1.8V upper unit */ + [ADC_SBUx] = ADC_CHAN_VOLT("chg_sbux", 3, + SCALE_HW_CALIB_DEFAULT) + [ADC_MID_CHG_DIV6] = ADC_CHAN_VOLT("chg_mid_chg", 6, + SCALE_HW_CALIB_DEFAULT) + [ADC_XO_THERM_PU2] = ADC_CHAN_TEMP("xo_therm", 1, + SCALE_HW_CALIB_XOTHERM) + [ADC_BAT_THERM_PU2] = ADC_CHAN_TEMP("bat_therm_pu2", 1, + SCALE_HW_CALIB_BATT_THERM_100K) + [ADC_BAT_THERM_PU1] = ADC_CHAN_TEMP("bat_therm_pu1", 1, + SCALE_HW_CALIB_BATT_THERM_30K) + [ADC_BAT_THERM_PU3] = ADC_CHAN_TEMP("bat_therm_pu3", 1, + SCALE_HW_CALIB_BATT_THERM_400K) + [ADC_BAT_ID_PU2] = ADC_CHAN_TEMP("bat_id", 1, + SCALE_HW_CALIB_DEFAULT) + [ADC_AMUX_THM1_PU2] = ADC_CHAN_TEMP("amux_thm1_pu2", 1, + SCALE_HW_CALIB_THERM_100K_PULLUP) + [ADC_AMUX_THM2_PU2] = ADC_CHAN_TEMP("amux_thm2_pu2", 1, + SCALE_HW_CALIB_THERM_100K_PULLUP) +//#ifdef CONFIG_OPLUS_SM7225R_CHARGER + [ADC_AMUX_THM3_PU2] = ADC_CHAN_VOLT("amux_thm3_pu2", 1, + SCALE_HW_CALIB_DEFAULT) +//#else +// [ADC_AMUX_THM3_PU2] = ADC_CHAN_TEMP("amux_thm3_pu2", 1, +// SCALE_HW_CALIB_THERM_100K_PULLUP) +//#endif +#ifdef OPLUS_FEATURE_CHG_BASIC + [ADC_AMUX_THM4_PU2] = ADC_CHAN_VOLT("amux_thm4_pu2", 1, + SCALE_HW_CALIB_DEFAULT) +#else + [ADC_AMUX_THM4_PU2] = ADC_CHAN_TEMP("amux_thm4_pu2", 1, + SCALE_HW_CALIB_THERM_100K_PULLUP) +#endif +#ifdef OPLUS_FEATURE_CHG_BASIC +/* yangmingjin,2020/3/9, add for usbtemp_adc */ + [ADC_AMUX_THM4] = ADC_CHAN_VOLT("amux_thm4", 1, + SCALE_HW_CALIB_DEFAULT) +#endif + [ADC_PARALLEL_ISENSE] = ADC_CHAN_VOLT("parallel_isense", 1, + SCALE_HW_CALIB_CUR) + [ADC_INT_EXT_ISENSE_VBAT_VDATA] = ADC_CHAN_POWER( + "int_ext_vbat_isense", 1, + SCALE_HW_CALIB_CUR) + [ADC_EXT_ISENSE_VBAT_VDATA] = ADC_CHAN_POWER("ext_vbat_isense", 1, + SCALE_HW_CALIB_CUR) + [ADC_PARALLEL_ISENSE_VBAT_VDATA] = ADC_CHAN_POWER( + "parallel_vbat_isense", 1, + SCALE_HW_CALIB_CUR) + [ADC_AMUX_THM2] = ADC_CHAN_TEMP("amux_thm2", 1, + SCALE_HW_CALIB_PM5_SMB_TEMP) + [ADC_AMUX_THM3] = ADC_CHAN_TEMP("amux_thm3", 1, + SCALE_HW_CALIB_PM5_SMB_TEMP) + [ADC_GPIO1_PU2] = ADC_CHAN_TEMP("gpio1_pu2", 1, + SCALE_HW_CALIB_THERM_100K_PULLUP) + [ADC_GPIO2_PU2] = ADC_CHAN_TEMP("gpio2_pu2", 1, + SCALE_HW_CALIB_THERM_100K_PULLUP) + [ADC_GPIO3_PU2] = ADC_CHAN_TEMP("gpio3_pu2", 1, + SCALE_HW_CALIB_THERM_100K_PULLUP) + [ADC_GPIO3] = ADC_CHAN_VOLT("gpio7_v", 1, + SCALE_HW_CALIB_DEFAULT) +#ifdef CONFIG_OPLUS_SM7250R_CHARGER //OPLUS_FEATURE_CHG_BASIC + [ADC_GPIO4_PU2] = ADC_CHAN_TEMP("gpio4_pu2", 1, + SCALE_HW_CALIB_THERM_100K_PULLUP) +#else + [ADC_GPIO4_PU2] = ADC_CHAN_VOLT("gpio8_v", 1, + SCALE_HW_CALIB_DEFAULT) +#endif + +#ifdef OPLUS_FEATURE_CHG_BASIC +/* yangmingjin,2020/3/9, add for usbtemp_adc */ + [ADC_GPIO4] = ADC_CHAN_VOLT("gpio8_vol", 1, + SCALE_HW_CALIB_DEFAULT) +#endif +#ifdef OPLUS_FEATURE_CHG_BASIC + [ADC_GPIO1] = ADC_CHAN_VOLT("board_id_vdata", 1, + SCALE_HW_CALIB_DEFAULT) +#endif +}; +#endif + static const struct adc_channels adc7_chans_pmic[ADC_MAX_CHANNEL] = { [ADC7_REF_GND] = ADC_CHAN_VOLT("ref_gnd", 0, SCALE_HW_CALIB_DEFAULT) @@ -981,8 +1498,13 @@ static const struct adc_channels adc_chans_rev2[ADC_MAX_CHANNEL] = { SCALE_HW_CALIB_PMIC_THERM) [ADC_AMUX_THM1_PU2] = ADC_CHAN_TEMP("amux_thm1_pu2", 1, SCALE_HW_CALIB_THERM_100K_PULLUP) +#ifdef CONFIG_OPLUS_SM7250R_CHARGER //OPLUS_FEATURE_CHG_BASIC [ADC_AMUX_THM3_PU2] = ADC_CHAN_TEMP("amux_thm3_pu2", 1, + SCALE_HW_CALIB_DEFAULT) +#else + [ADC_AMUX_THM3_PU2] = ADC_CHAN_TEMP("amux_thm3_pu2", 1, SCALE_HW_CALIB_THERM_100K_PULLUP) +#endif [ADC_AMUX_THM5_PU2] = ADC_CHAN_TEMP("amux_thm5_pu2", 1, SCALE_HW_CALIB_THERM_100K_PULLUP) [ADC_XO_THERM_PU2] = ADC_CHAN_TEMP("xo_therm", 1, @@ -1102,6 +1624,17 @@ static int adc_get_dt_channel_data(struct adc_chip *adc, else prop->cal_method = ADC_ABSOLUTE_CAL; +#ifdef OPLUS_FEATURE_CHG_BASIC + if (!of_property_read_u32(node, "oplus,cust_type", &value)) + prop->cust_type = value; + else + prop->cust_type = -1; + + if (!of_property_read_u32(node, "oplus,cust_scale_fn_type", &value)) + prop->cust_scale_fn_type = value; + else + prop->cust_scale_fn_type = -1; +#endif /* * Default to using timer calibration. Using a fresh calibration value * for every conversion will increase the overall time for a request. @@ -1123,6 +1656,53 @@ const struct adc_data data_pmic5 = { 800, 900, 1, 2, 4, 6, 8, 10}, }; +const struct adc_data data_pmic5_21027 = { + .full_scale_code_volt = 0x70e4, + /* On PM8150B, IBAT LSB = 10A/32767 */ + .full_scale_code_cur = 10000, + .adc_chans = adc_chans_pmic5_21027, + .decimation = (unsigned int []) {250, 420, 840}, + .hw_settle = (unsigned int []) {15, 100, 200, 300, 400, 500, 600, 700, + 800, 900, 1, 2, 4, 6, 8, 10}, + .battemp_for_adc = 1, +}; + +#ifdef OPLUS_FEATURE_CHG_BASIC +const struct adc_data data_pmic5_7225 = { + .full_scale_code_volt = 0x70e4, + /* On PM8150B, IBAT LSB = 10A/32767 */ + .full_scale_code_cur = 10000, + .adc_chans = adc_chans_pmic5_7225, + .decimation = (unsigned int []) {250, 420, 840}, + .hw_settle = (unsigned int []) {15, 100, 200, 300, 400, 500, 600, 700, + 800, 900, 1, 2, 4, 6, 8, 10}, +}; +#endif + +//#ifdef OPLUS_FEATURE_TEMP_ADAPTER +const struct adc_data data_pmic5_temp = { + .full_scale_code_volt = 0x70e4, + /* On PM8150B, IBAT LSB = 10A/32767 */ + .full_scale_code_cur = 10000, + .adc_chans = adc_chans_pmic5_temp, + .decimation = (unsigned int []) {250, 420, 840}, + .hw_settle = (unsigned int []) {15, 100, 200, 300, 400, 500, 600, 700, + 800, 900, 1, 2, 4, 6, 8, 10}, +}; +//#endif + +#ifdef OPLUS_FEATURE_CHG_BASIC +const struct adc_data data_pmic5_7225_s = { + .full_scale_code_volt = 0x70e4, + /* On PM8150B, IBAT LSB = 10A/32767 */ + .full_scale_code_cur = 10000, + .adc_chans = adc_chans_pmic5_7225_s, + .decimation = (unsigned int []) {250, 420, 840}, + .hw_settle = (unsigned int []) {15, 100, 200, 300, 400, 500, 600, 700, + 800, 900, 1, 2, 4, 6, 8, 10}, +}; +#endif + const struct adc_data data_pmic5_lite = { .full_scale_code_volt = 0x70e4, /* On PMI632, IBAT LSB = 5A/32767 */ @@ -1155,6 +1735,30 @@ static const struct of_device_id adc_match_table[] = { .compatible = "qcom,spmi-adc5", .data = &data_pmic5, }, +#ifdef OPLUS_FEATURE_CHG_BASIC + { + .compatible = "qcom,spmi-adc5-7225", + .data = &data_pmic5_7225, + }, +#endif +//#ifdef OPLUS_FEATURE_TEMP_ADAPTER + { + .compatible = "qcom,spmi-adc5-temp", + .data = &data_pmic5_temp, + }, +//#endif +#ifdef OPLUS_FEATURE_CHG_BASIC + { + .compatible = "qcom,spmi-adc5-7225_s", + .data = &data_pmic5_7225_s, + }, +#endif +#ifdef OPLUS_FEATURE_CHG_BASIC + { + .compatible = "qcom,spmi-adc5_21027", + .data = &data_pmic5_21027, + }, +#endif { .compatible = "qcom,spmi-adc7", .data = &adc7_data_pmic, @@ -1224,6 +1828,15 @@ static int adc_get_dt_data(struct adc_chip *adc, struct device_node *node) iio_chan->info_mask_separate = adc_chan->info_mask; iio_chan->type = adc_chan->type; iio_chan->address = index; + +#ifdef OPLUS_FEATURE_CHG_BASIC + if(prop.cust_type != -1 && prop.cust_scale_fn_type != -1) { + pr_err("%s: force to cust_type %d, cust_scale_fn_type %d\n", prop.datasheet_name, prop.cust_type, prop.cust_scale_fn_type); + iio_chan->type = prop.cust_type; + iio_chan->info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_PROCESSED); + adc->chan_props[index].scale_fn_type = prop.cust_scale_fn_type; + } +#endif iio_chan++; index++; } diff --git a/drivers/iio/adc/qcom-vadc-common.c b/drivers/iio/adc/qcom-vadc-common.c index 8467d0fbddf4..49e3d186f853 100644 --- a/drivers/iio/adc/qcom-vadc-common.c +++ b/drivers/iio/adc/qcom-vadc-common.c @@ -246,7 +246,81 @@ static const struct vadc_map_pt adcmap_batt_therm_100k_6125[] = { * Voltage to temperature table for 30k pull up for bat_therm with * Alium. */ -static const struct vadc_map_pt adcmap_batt_therm_30k[] = { +#ifdef OPLUS_FEATURE_CHG_BASIC + static const struct vadc_map_pt adcmap_batt_therm_30k[] = { + { 1623 , -400 }, + { 1600 , -380 }, + { 1575 , -360 }, + { 1548 , -340 }, + { 1520 , -320 }, + { 1491 , -300 }, + { 1460 , -280 }, + { 1429 , -260 }, + { 1396 , -240 }, + { 1363 , -220 }, + { 1328 , -200 }, + { 1293 , -180 }, + { 1258 , -160 }, + { 1222 , -140 }, + { 1186 , -120 }, + { 1150 , -100 }, + { 1114 , -80 }, + { 1078 , -60 }, + { 1042 , -40 }, + { 1008 , -20 }, + { 973 , 0 }, + { 940 , 20 }, + { 907 , 40 }, + { 875 , 60 }, + { 845 , 80 }, + { 815 , 100 }, + { 786 , 120 }, + { 759 , 140 }, + { 732 , 160 }, + { 707 , 180 }, + { 683 , 200 }, + { 660 , 220 }, + { 638 , 240 }, + { 618 , 260 }, + { 598 , 280 }, + { 579 , 300 }, + { 562 , 320 }, + { 545 , 340 }, + { 529 , 360 }, + { 514 , 380 }, + { 501 , 400 }, + { 487 , 420 }, + { 475 , 440 }, + { 463 , 460 }, + { 452 , 480 }, + { 442 , 500 }, + { 433 , 520 }, + { 423 , 540 }, + { 415 , 560 }, + { 407 , 580 }, + { 399 , 600 }, + { 392 , 620 }, + { 386 , 640 }, + { 379 , 660 }, + { 374 , 680 }, + { 368 , 700 }, + { 363 , 720 }, + { 358 , 740 }, + { 353 , 760 }, + { 349 , 780 }, + { 345 , 800 }, + { 341 , 820 }, + { 338 , 840 }, + { 334 , 860 }, + { 331 , 880 }, + { 328 , 900 }, + { 325 , 920 }, + { 323 , 940 }, + { 320 , 960 }, + { 318 , 980 }, + }; +#else + static const struct vadc_map_pt adcmap_batt_therm_30k[] = { {1864, -400}, {1863, -380}, {1861, -360}, @@ -317,7 +391,9 @@ static const struct vadc_map_pt adcmap_batt_therm_30k[] = { {349, 940}, {332, 960}, {315, 980} -}; + }; +#endif + /* * Voltage to temperature table for 30k pull up for bat_therm with @@ -1421,8 +1497,17 @@ int qcom_vadc_hw_scale(enum vadc_scale_fn_type scaletype, return qcom_vadc_scale_hw_calib_therm(prescale, data, adc_code, result); case SCALE_HW_CALIB_BATT_THERM_100K: - return qcom_vadc_scale_hw_calib_batt_therm_100(prescale, +#ifdef OPLUS_FEATURE_CHG_BASIC + if (data->battemp_for_adc == 1) { + return qcom_vadc_scale_hw_calib_volt(prescale, + data,adc_code, result); + } else { +#endif + return qcom_vadc_scale_hw_calib_batt_therm_100(prescale, data, lut_index, adc_code, result); +#ifdef OPLUS_FEATURE_CHG_BASIC + } +#endif case SCALE_HW_CALIB_BATT_THERM_30K: return qcom_vadc_scale_hw_calib_batt_therm_30(prescale, data, lut_index, adc_code, result); diff --git a/drivers/iio/adc/qcom-vadc-common.h b/drivers/iio/adc/qcom-vadc-common.h index e0ff98bf5f15..3b900ff2151f 100644 --- a/drivers/iio/adc/qcom-vadc-common.h +++ b/drivers/iio/adc/qcom-vadc-common.h @@ -208,6 +208,9 @@ struct adc_data { const struct adc_channels *adc_chans; unsigned int *decimation; unsigned int *hw_settle; +#ifdef OPLUS_FEATURE_CHG_BASIC + int battemp_for_adc; +#endif }; int qcom_vadc_scale(enum vadc_scale_fn_type scaletype, diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig index a78c8309bb3f..6c46da3cfc91 100644 --- a/drivers/input/Kconfig +++ b/drivers/input/Kconfig @@ -213,6 +213,10 @@ source "drivers/input/misc/Kconfig" source "drivers/input/rmi4/Kconfig" +#ifdef OPLUS_FEATURE_FINGERPRINT +source "drivers/input/oplus_fp_drivers/Kconfig" +source "drivers/input/oplus_secure_drivers/Kconfig" +#endif endif menu "Hardware I/O ports" diff --git a/drivers/input/Makefile b/drivers/input/Makefile index d670bfc10bbe..a72c026c6403 100644 --- a/drivers/input/Makefile +++ b/drivers/input/Makefile @@ -31,3 +31,11 @@ obj-$(CONFIG_INPUT_KEYRESET) += keyreset.o obj-$(CONFIG_INPUT_KEYCOMBO) += keycombo.o obj-$(CONFIG_RMI4_CORE) += rmi4/ + +#ifdef OPLUS_FEATURE_FINGERPRINT +ifneq ($(TARGET_PRODUCT), qssi) +obj-$(CONFIG_OPLUS_FINGERPRINT) += oplus_fp_drivers/ +obj-$(CONFIG_OPLUS_SECURE) += oplus_secure_drivers/ +#endif /* OPLUS_FEATURE_FINGERPRINT */ +endif +#endif diff --git a/drivers/input/input.c b/drivers/input/input.c index 159dd87b93b0..e00a03158339 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -29,6 +29,7 @@ #include #include "input-compat.h" + MODULE_AUTHOR("Vojtech Pavlik "); MODULE_DESCRIPTION("Input core"); MODULE_LICENSE("GPL"); @@ -378,11 +379,20 @@ static int input_get_disposition(struct input_dev *dev, return disposition; } +#ifdef OPLUS_FEATURE_SAUPWK +extern void __attribute__((weak)) oplus_sync_saupwk_event(unsigned int , unsigned int , int); +#endif /* OPLUS_FEATURE_SAUPWK */ + static void input_handle_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) { int disposition = input_get_disposition(dev, type, code, &value); +#ifdef OPLUS_FEATURE_SAUPWK + if(oplus_sync_saupwk_event) + oplus_sync_saupwk_event(type, code, value); +#endif /* OPLUS_FEATURE_SAUPWK */ + if (disposition != INPUT_IGNORE_EVENT && type != EV_SYN) add_input_randomness(type, code, value); diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c index 492a971b95b5..93aabf3460db 100644 --- a/drivers/input/keyboard/gpio_keys.c +++ b/drivers/input/keyboard/gpio_keys.c @@ -380,6 +380,15 @@ static void gpio_keys_gpio_report_event(struct gpio_button_data *bdata) input_event(input, type, *bdata->code, state); } input_sync(input); + +#ifdef OPLUS_FEATURE_TP_BASIC + if (!strcmp(button->desc, "volume_up")) { + dev_info(input->dev.parent, "vol_up %s\n", !!state?"pressed":"release"); + } + if (!strcmp(button->desc, "volume_down")) { + dev_info(input->dev.parent, "vol_down %s\n", !!state?"pressed":"release"); + } +#endif } static void gpio_keys_gpio_work_func(struct work_struct *work) diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index 3d7ca037962d..4d539df73afc 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig @@ -885,4 +885,14 @@ config INPUT_SC27XX_VIBRA To compile this driver as a module, choose M here. The module will be called sc27xx_vibra. +config STMVL53L1 + tristate "STM VL53L1 Proximity support" + depends on I2C=y + default y + help + Say Y here if you want to use STMicroelectronics's vl53L1 TOF AF sensor + through I2C interface. + + To compile this driver as a module, choose M here: the + module will be called stmvl53l1. endif diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile index a99ea9586234..7d75a9aef844 100644 --- a/drivers/input/misc/Makefile +++ b/drivers/input/misc/Makefile @@ -85,3 +85,4 @@ obj-$(CONFIG_INPUT_WM831X_ON) += wm831x-on.o obj-$(CONFIG_INPUT_XEN_KBDDEV_FRONTEND) += xen-kbdfront.o obj-$(CONFIG_INPUT_YEALINK) += yealink.o obj-$(CONFIG_INPUT_IDEAPAD_SLIDEBAR) += ideapad_slidebar.o +obj-$(CONFIG_STMVL53L1) += vl53L1/ diff --git a/drivers/input/misc/qpnp-power-on.c b/drivers/input/misc/qpnp-power-on.c index 56918e9ef768..dda507e05fb1 100644 --- a/drivers/input/misc/qpnp-power-on.c +++ b/drivers/input/misc/qpnp-power-on.c @@ -26,6 +26,18 @@ #include #include +#ifdef OPLUS_FEATURE_THEIA +#include +#include +#endif + +#ifdef CONFIG_OPLUS_FEATURE_MISC +#include +#include +#include +#include +#endif + #define PMIC_VER_8941 0x01 #define PMIC_VERSION_REG 0x0105 #define PMIC_VERSION_REV4_REG 0x0103 @@ -191,6 +203,56 @@ struct pon_regulator { bool enabled; }; +#ifdef OPLUS_FEATURE_QCOM_PMICWD +#ifndef CONFIG_OPLUS_FEATURE_QCOM_PMICWD +struct qpnp_pon { + struct device *dev; + struct regmap *regmap; + struct input_dev *pon_input; + struct qpnp_pon_config *pon_cfg; + struct pon_regulator *pon_reg_cfg; + struct list_head list; + struct delayed_work bark_work; + struct dentry *debugfs; + u16 base; + u8 subtype; + u8 pon_ver; + u8 warm_reset_reason1; + u8 warm_reset_reason2; + int num_pon_config; + int num_pon_reg; + int pon_trigger_reason; + int pon_power_off_reason; + u32 dbc_time_us; + u32 uvlo; + int warm_reset_poff_type; + int hard_reset_poff_type; + int shutdown_poff_type; + int resin_warm_reset_type; + int resin_hard_reset_type; + int resin_shutdown_type; + bool is_spon; + bool store_hard_reset_reason; + bool resin_hard_reset_disable; + bool resin_shutdown_disable; + bool ps_hold_hard_reset_disable; + bool ps_hold_shutdown_disable; + bool kpdpwr_dbc_enable; + bool resin_pon_reset; + ktime_t kpdpwr_last_release_time; +}; +#endif + +static int pon_ship_mode_en; +module_param_named( + ship_mode_en, pon_ship_mode_en, int, 0600 +); + +#ifndef CONFIG_OPLUS_FEATURE_QCOM_PMICWD +static struct qpnp_pon *sys_reset_dev; +#endif + +#else struct qpnp_pon { struct device *dev; struct regmap *regmap; @@ -235,6 +297,8 @@ module_param_named( ); static struct qpnp_pon *sys_reset_dev; +#endif /* OPLUS_FEATURE_QCOM_PMICWD */ + static struct qpnp_pon *modem_reset_dev; static DEFINE_SPINLOCK(spon_list_slock); static LIST_HEAD(spon_dev_list); @@ -305,8 +369,18 @@ static const char * const qpnp_poff_reason[] = { [39] = "Triggered from S3_RESET_KPDPWR_ANDOR_RESIN", }; +#ifdef OPLUS_FEATURE_QCOM_PMICWD +#ifdef CONFIG_OPLUS_FEATURE_QCOM_PMICWD +int qpnp_pon_masked_write(struct qpnp_pon *pon, u16 addr, u8 mask, u8 val) +#else static int qpnp_pon_masked_write(struct qpnp_pon *pon, u16 addr, u8 mask, u8 val) +#endif + +#else +static int +qpnp_pon_masked_write(struct qpnp_pon *pon, u16 addr, u8 mask, u8 val) +#endif /* OPLUS_FEATURE_QCOM_PMICWD */ { int rc; @@ -690,7 +764,7 @@ out: if (!!pon_ship_mode_en) { batt_psy = power_supply_get_by_name("battery"); if (batt_psy) { - pr_debug("Setting ship mode\n"); + pr_err("Setting ship mode\n"); val.intval = 1; rc = power_supply_set_property(batt_psy, POWER_SUPPLY_PROP_SET_SHIP_MODE, &val); @@ -930,7 +1004,7 @@ static int qpnp_pon_input_dispatch(struct qpnp_pon *pon, u32 pon_type) elapsed_us = ktime_us_delta(ktime_get(), pon->kpdpwr_last_release_time); if (elapsed_us < pon->dbc_time_us) { - pr_debug("Ignoring kpdpwr event; within debounce time\n"); + pr_err("Ignoring kpdpwr event; within debounce time\n"); return 0; } } @@ -943,6 +1017,16 @@ static int qpnp_pon_input_dispatch(struct qpnp_pon *pon, u32 pon_type) switch (cfg->pon_type) { case PON_KPDPWR: pon_rt_bit = QPNP_PON_KPDPWR_N_SET; +#ifdef CONFIG_OPLUS_FEATURE_MISC + if ((pon_rt_sts & pon_rt_bit) == 0) { + pr_debug("Power-Key UP\n"); + cancel_delayed_work(&pon->press_work); + } else { + pr_debug("Power-Key DOWN\n"); + schedule_delayed_work(&pon->press_work, + msecs_to_jiffies(4000)); + } +#endif break; case PON_RESIN: pon_rt_bit = QPNP_PON_RESIN_N_SET; @@ -957,7 +1041,7 @@ static int qpnp_pon_input_dispatch(struct qpnp_pon *pon, u32 pon_type) return -EINVAL; } - pr_debug("PMIC input: code=%d, status=0x%02X\n", cfg->key_code, + pr_err("PMIC input: code=%d, status=0x%02X\n", cfg->key_code, pon_rt_sts); key_status = pon_rt_sts & pon_rt_bit; @@ -979,6 +1063,21 @@ static int qpnp_pon_input_dispatch(struct qpnp_pon *pon, u32 pon_type) input_sync(pon->pon_input); } + #ifdef OPLUS_FEATURE_QCOM_PMICWD + #ifdef CONFIG_OPLUS_FEATURE_QCOM_PMICWD + pr_err("keycode = %d,key_st = %d\n",cfg->key_code, key_status); + #endif + #endif /* OPLUS_FEATURE_QCOM_PMICWD */ + + #ifdef OPLUS_FEATURE_THEIA + pr_err("keycode = %d,key_st = %d old_state= %d %d \n",cfg->key_code, key_status,cfg->old_state ,KEY_POWER); + if(cfg->key_code == KEY_POWER && key_status == 1 && cfg->old_state == 0){ + //we should canel per work + black_screen_timer_restart(); + bright_screen_timer_restart(); + } + #endif + input_report_key(pon->pon_input, cfg->key_code, key_status); input_sync(pon->pon_input); @@ -1132,6 +1231,44 @@ static void bark_work_func(struct work_struct *work) } } +#ifdef CONFIG_OPLUS_FEATURE_MISC +static void press_work_func(struct work_struct *work) +{ + int display_bl, boot_mode; + int rc; + uint pon_rt_sts = 0; + struct qpnp_pon_config *cfg; + struct qpnp_pon *pon = + container_of(work, struct qpnp_pon, press_work.work); + + cfg = qpnp_get_cfg(pon, PON_KPDPWR); + if (!cfg) { + dev_err(pon->dev, "Invalid config pointer\n"); + goto err_return; + } + /* check the RT status to get the current status of the line */ + rc = regmap_read(pon->regmap, QPNP_PON_RT_STS(pon), &pon_rt_sts); + if (rc) { + dev_err(pon->dev, "Unable to read PON RT status\n"); + goto err_return; + } + if ((pon_rt_sts & QPNP_PON_KPDPWR_N_SET) == 1) { + dev_err(pon->dev, "after 4s Power-Key is still DOWN\n"); + display_bl = dsi_panel_backlight_get(); + boot_mode = get_boot_mode(); + if (display_bl == 0 && boot_mode == MSM_BOOT_MODE__NORMAL) { + oplus_switch_fulldump(0); + show_state_filter(TASK_UNINTERRUPTIBLE); + panic("power key still pressed\n"); + } + } + msleep(20); + ksys_sync(); +err_return: + return; +} +#endif + static irqreturn_t qpnp_resin_bark_irq(int irq, void *_pon) { struct qpnp_pon *pon = _pon; @@ -2086,6 +2223,12 @@ static int qpnp_pon_configure_s3_reset(struct qpnp_pon *pon) return 0; } +#ifdef OPLUS_BUG_STABILITY +extern char pon_reason[]; +extern char poff_reason[]; +int preason_initialized; +#endif /*OPLUS_BUG_STABILITY*/ + static int qpnp_pon_read_hardware_info(struct qpnp_pon *pon, bool sys_reset) { struct device *dev = pon->dev; @@ -2131,25 +2274,45 @@ static int qpnp_pon_read_hardware_info(struct qpnp_pon *pon, bool sys_reset) /* PON reason */ rc = qpnp_pon_read(pon, QPNP_PON_REASON1(pon), &pon_sts); - if (rc) + if (rc){ +#ifdef OPLUS_BUG_STABILITY + dev_err(dev,"Unable to read PON_RESASON1 reg rc: %d\n",rc); + if (!preason_initialized) { + snprintf(pon_reason, 128, "Unable to read PON_RESASON1 reg rc: %d\n", rc); + preason_initialized = 1; + } +#endif /*OPLUS_BUG_STABILITY*/ return rc; - + } if (sys_reset) boot_reason = ffs(pon_sts); index = ffs(pon_sts) - 1; +#ifdef OPLUS_BUG_STABILITY + if (pon_sts & 0x80) + index = 7; +#endif /*OPLUS_BUG_STABILITY*/ cold_boot = sys_reset_dev ? !_qpnp_pon_is_warm_reset(sys_reset_dev) : !_qpnp_pon_is_warm_reset(pon); if (index >= ARRAY_SIZE(qpnp_pon_reason) || index < 0) { dev_info(dev, "PMIC@SID%d Power-on reason: Unknown and '%s' boot\n", to_spmi_device(dev->parent)->usid, cold_boot ? "cold" : "warm"); +#ifdef OPLUS_BUG_STABILITY + if (!preason_initialized) + snprintf(pon_reason, 128, "Unknown[0x%02X] and '%s' boot\n", pon_sts, cold_boot ? "cold" : "warm"); +#endif /*OPLUS_BUG_STABILITY*/ } else { pon->pon_trigger_reason = index; dev_info(dev, "PMIC@SID%d Power-on reason: %s and '%s' boot\n", to_spmi_device(dev->parent)->usid, qpnp_pon_reason[index], cold_boot ? "cold" : "warm"); +#ifdef OPLUS_BUG_STABILITY + if (!preason_initialized) + snprintf(pon_reason, 128, "[0x%02X]%s and '%s' boot\n", pon_sts, + qpnp_pon_reason[index], cold_boot ? "cold" : "warm"); +#endif /*OPLUS_BUG_STABILITY*/ } /* POFF reason */ @@ -2157,13 +2320,19 @@ static int qpnp_pon_read_hardware_info(struct qpnp_pon *pon, bool sys_reset) rc = qpnp_pon_read_gen2_pon_off_reason(pon, &poff_sts, &reason_index_offset); if (rc) - return rc; + return rc; } else { rc = regmap_bulk_read(pon->regmap, QPNP_POFF_REASON1(pon), buf, 2); if (rc) { dev_err(dev, "Register read failed, addr=0x%04X, rc=%d\n", QPNP_POFF_REASON1(pon), rc); +#ifdef OPLUS_BUG_STABILITY + if (!preason_initialized) { + snprintf(poff_reason, 128, "Unable to read POFF_RESASON regs rc:%d\n", rc); + preason_initialized = 1; + } +#endif /*OPLUS_BUG_STABILITY*/ return rc; } poff_sts = buf[0] | (u16)(buf[1] << 8); @@ -2173,11 +2342,23 @@ static int qpnp_pon_read_hardware_info(struct qpnp_pon *pon, bool sys_reset) index < reason_index_offset) { dev_info(dev, "PMIC@SID%d: Unknown power-off reason\n", to_spmi_device(dev->parent)->usid); +#ifdef OPLUS_BUG_STABILITY + if (!preason_initialized) { + snprintf(poff_reason, 128, "Unknown[0x%4X]\n", poff_sts); + preason_initialized = 1; + } +#endif /*OPLUS_BUG_STABILITY*/ } else { pon->pon_power_off_reason = index; dev_info(dev, "PMIC@SID%d: Power-off reason: %s\n", to_spmi_device(dev->parent)->usid, qpnp_poff_reason[index]); +#ifdef OPLUS_BUG_STABILITY + if (!preason_initialized) { + snprintf(poff_reason, 128, "[0x%04X]%s\n", poff_sts, qpnp_poff_reason[index]); + preason_initialized = 1; + } +#endif /*OPLUS_BUG_STABILITY*/ } if ((pon->pon_trigger_reason == PON_SMPL || @@ -2338,7 +2519,9 @@ static int qpnp_pon_probe(struct platform_device *pdev) dev_set_drvdata(dev, pon); INIT_DELAYED_WORK(&pon->bark_work, bark_work_func); - +#ifdef CONFIG_OPLUS_FEATURE_MISC + INIT_DELAYED_WORK(&pon->press_work, press_work_func); +#endif rc = qpnp_pon_parse_dt_power_off_config(pon); if (rc) return rc; @@ -2397,7 +2580,14 @@ static int qpnp_pon_probe(struct platform_device *pdev) if (modem_reset) modem_reset_dev = pon; - qpnp_pon_debugfs_init(pon); + qpnp_pon_debugfs_init(pon); + + #ifdef OPLUS_FEATURE_QCOM_PMICWD + #ifdef CONFIG_OPLUS_FEATURE_QCOM_PMICWD + pmicwd_init(pdev, pon, sys_reset); + kpdpwr_init(pon, sys_reset); + #endif + #endif /* OPLUS_FEATURE_QCOM_PMICWD */ return 0; } @@ -2428,6 +2618,11 @@ static const struct of_device_id qpnp_pon_match_table[] = { static struct platform_driver qpnp_pon_driver = { .driver = { + #ifdef OPLUS_FEATURE_QCOM_PMICWD + #ifdef CONFIG_OPLUS_FEATURE_QCOM_PMICWD + .pm = &qpnp_pm_ops, + #endif + #endif /* OPLUS_FEATURE_QCOM_PMICWD */ .name = "qcom,qpnp-power-on", .of_match_table = qpnp_pon_match_table, }, diff --git a/drivers/input/misc/vl53L1/Makefile b/drivers/input/misc/vl53L1/Makefile new file mode 100644 index 000000000000..98bec8a7a9c3 --- /dev/null +++ b/drivers/input/misc/vl53L1/Makefile @@ -0,0 +1,6 @@ +$(warning, "wkj $(TARGET_PRODUCT)") +ifeq ($(TARGET_PRODUCT), kona) +obj-$(CONFIG_STMVL53L1) += kona/ +else ifeq ($(TARGET_PRODUCT), lito) +obj-$(CONFIG_STMVL53L1) += lito/ +endif diff --git a/drivers/input/misc/vl53L1/kona/Kbuild b/drivers/input/misc/vl53L1/kona/Kbuild new file mode 100644 index 000000000000..a4a62d819181 --- /dev/null +++ b/drivers/input/misc/vl53L1/kona/Kbuild @@ -0,0 +1,30 @@ +# +# Kbuild for the vl53L1 drivers. +# + +ccflags-y += -I$(src)/inc -I$(src)/ipp -I$(src) +ccflags-y += -Itechpack/camera/drivers/cam_sensor_module/cam_cci + +# define this environment variable if you want to compile driver for an old +# kernel +ifdef OLD_NETLINK_API +ccflags-y += -DOLD_NETLINK_API +endif + +ifdef VL53L1_LOG_ENABLE +ccflags-y += -DVL53L1_LOG_ENABLE +endif + +obj-$(CONFIG_STMVL53L1) += stmvl53l1.o +stmvl53l1-objs := stmvl53l1_module.o stmvl53l1_module-i2c.o stmvl53l1_module-cci.o +stmvl53l1-objs += stmvl53l1_i2c.o stmvl53l1_ipp_nl.o stmvl53l1_log.o +stmvl53l1-objs += src/vl53l1_api.o src/vl53l1_api_core.o +stmvl53l1-objs += src/vl53l1_api_strings.o src/vl53l1_error_strings.o +stmvl53l1-objs += src/vl53l1_core.o src/vl53l1_register_funcs.o +stmvl53l1-objs += src/vl53l1_api_preset_modes.o +stmvl53l1-objs += src/vl53l1_api_calibration.o +stmvl53l1-objs += src/vl53l1_silicon_core.o +stmvl53l1-objs += src/vl53l1_zone_presets.o src/vl53l1_nvm.o +stmvl53l1-objs += src/vl53l1_api_debug.o src/vl53l1_core_support.o +stmvl53l1-objs += src/vl53l1_wait.o ipp/ipp_linux.o +stmvl53l1-objs += src/vl53l1_nvm_debug.o diff --git a/drivers/input/misc/vl53L1/kona/Makefile b/drivers/input/misc/vl53L1/kona/Makefile new file mode 100644 index 000000000000..4dd06f8d49f8 --- /dev/null +++ b/drivers/input/misc/vl53L1/kona/Makefile @@ -0,0 +1,12 @@ +ifneq ($(KERNELRELEASE),) +include Kbuild + +else +KDIR ?= /lib/modules/`uname -r`/build + +default: + CONFIG_STMVL53L1=m $(MAKE) -C $(KDIR) M=$$PWD +clean: + CONFIG_STMVL53L1=m $(MAKE) -C $(KDIR) M=$$PWD clean + +endif \ No newline at end of file diff --git a/drivers/input/misc/vl53L1/kona/inc/vl53l1_api.h b/drivers/input/misc/vl53L1/kona/inc/vl53l1_api.h new file mode 100644 index 000000000000..28ccd45c7e61 --- /dev/null +++ b/drivers/input/misc/vl53L1/kona/inc/vl53l1_api.h @@ -0,0 +1,1497 @@ + +/****************************************************************************** + * Copyright (c) 2017, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + + ****************************************************************************** + + 'STMicroelectronics Proprietary license' + + ******************************************************************************* + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + + ******************************************************************************* + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones mentioned above : + + ******************************************************************************* + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + ******************************************************************************* + */ + +#ifndef _VL53L1_API_H_ +#define _VL53L1_API_H_ + +#include "vl53l1_api_strings.h" +#include "vl53l1_api_core.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +#if !defined(VL53L1DevDataGet) +#warning "PALDevDataGet is deprecated define VL53L1DevDataGet instead" +#define VL53L1DevDataGet(Dev, field) (Dev->Data.field) +#endif + +#if !defined(VL53L1DevDataSet) +#warning "PALDevDataSet is deprecated define VL53L1DevDataSet instead" +#define VL53L1DevDataSet(Dev, field, data) ((Dev->Data.field) = (data)) +#endif + +/** @defgroup VL53L1_cut11_group VL53L1 cut1.1 Function Definition + * @brief VL53L1 cut1.1 Function Definition + * @{ + */ + +/** @defgroup VL53L1_general_group VL53L1 General Functions + * @brief General functions and definitions + * @{ + */ + +/** + * @brief Return the VL53L1 driver Version + * + * @note This function doesn't access to the device + * + * @param pVersion Rer to current driver Version + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetVersion(VL53L1_Version_t *pVersion); + +/** + * @brief Reads the Product Revision for a for given Device + * This function can be used to distinguish cut1.0 from cut1.1. + * + * @param Dev Device Handle + * @param pProductRevisionMajor Pointer to Product Revision Major + * for a given Device + * @param pProductRevisionMinor Pointer to Product Revision Minor + * for a given Device + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetProductRevision(VL53L1_DEV Dev, + uint8_t *pProductRevisionMajor, uint8_t *pProductRevisionMinor); + +/** + * @brief Reads the Device information for given Device + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @param pVL53L1_DeviceInfo Pointer to current device info for a given + * Device + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetDeviceInfo(VL53L1_DEV Dev, + VL53L1_DeviceInfo_t *pVL53L1_DeviceInfo); + +/** + * @brief Reads the Device unique identifier + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @param pUid Pointer to current device unique ID + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetUID(VL53L1_DEV Dev, uint64_t *pUid); + +/** + * @brief Human readable Range Status string for a given RangeStatus + * + * @note This function doesn't access to the device + * + * @param RangeStatus The RangeStatus code as stored on + * @a VL53L1_RangingMeasurementData_t + * @param pRangeStatusString The returned RangeStatus string. Shall be + * defined as char buf[VL53L1_MAX_STRING_LENGTH] + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetRangeStatusString(uint8_t RangeStatus, + char *pRangeStatusString); + +/** + * @brief Human readable error string for driver error status + * + * @note This function doesn't access to the device + * + * @param PalErrorCode The error code as stored on @a VL53L1_Error + * @param pPalErrorString The error string corresponding to the + * PalErrorCode. Shall be defined as char buf[VL53L1_MAX_STRING_LENGTH] + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetPalErrorString(VL53L1_Error PalErrorCode, + char *pPalErrorString); + +/** + * @brief Human readable driver State string + * + * @note This function doesn't access to the device + * + * @param PalStateCode The State code as stored on @a VL53L1_State + * @param pPalStateString The State string corresponding to the + * PalStateCode. Shall be defined as char buf[VL53L1_MAX_STRING_LENGTH] + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetPalStateString(VL53L1_State PalStateCode, + char *pPalStateString); + +/** + * @brief Reads the internal state of the driver for a given Device + * + * @note This function doesn't access to the device + * + * @param Dev Device Handle + * @param pPalState Pointer to current state of the PAL for a + * given Device + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetPalState(VL53L1_DEV Dev, + VL53L1_State *pPalState); + + + +/** @} VL53L1_general_group */ + +/** @defgroup VL53L1_init_group VL53L1 Init Functions + * @brief VL53L1 Init Functions + * @{ + */ + +/** + * @brief Set new device address + * + * After completion the device will answer to the new address programmed. + * This function should be called when several devices are used in parallel + * before start programming the sensor. + * When a single device us used, there is no need to call this function. + * + * When it is requested for multi devices system this function MUST be called + * prior to VL53L1_DataInit() + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @param DeviceAddress The new Device address + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_SetDeviceAddress(VL53L1_DEV Dev, + uint8_t DeviceAddress); + +/** + * + * @brief One time device initialization + * + * To be called after device has been powered on and booted + * see @a VL53L1_WaitDeviceBooted() + * + * @par Function Description + * When not used after a fresh device "power up", it may return + * @a #VL53L1_ERROR_CALIBRATION_WARNING meaning wrong calibration data + * may have been fetched from device that can result in ranging offset error\n + * If VL53L1_DataInit is called several times then the application must restore + * calibration calling @a VL53L1_SetOffsetCalibrationData() + * It implies application has gathered calibration data thanks to + * @a VL53L1_GetOffsetCalibrationData() after an initial calibration stage. + * This function will change the VL53L1_State from VL53L1_STATE_POWERDOWN to + * VL53L1_STATE_WAIT_STATICINIT. + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_DataInit(VL53L1_DEV Dev); + + +/** + * @brief Do basic device init (and eventually patch loading) + * This function will change the VL53L1_State from + * VL53L1_STATE_WAIT_STATICINIT to VL53L1_STATE_IDLE. + * In this stage all default setting will be applied. + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_StaticInit(VL53L1_DEV Dev); + +/** + * @brief Wait for device booted after chip enable (hardware standby) + * This function can be run only when VL53L1_State is VL53L1_STATE_POWERDOWN. + * + * @param Dev Device Handle + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + * + */ +VL53L1_Error VL53L1_WaitDeviceBooted(VL53L1_DEV Dev); + + +/** @} VL53L1_init_group */ + +/** @defgroup VL53L1_parameters_group VL53L1 Parameters Functions + * @brief Functions used to prepare and setup the device + * @{ + */ + +/** + * @brief Set a new Preset Mode + * @par Function Description + * Set device to a new Operating Mode (High speed ranging, Multi objects ...) + * + * @note This function doesn't Access to the device + * + * @warning This function change the timing budget to 16 ms and the inter- + * measurement period to 1000 ms. Also the VL53L1_DISTANCEMODE_LONG is used. + * + * @param Dev Device Handle + * @param PresetMode New Preset mode to apply + *
Valid values are: + */ +/** + * @li VL53L1_PRESETMODE_MULTIZONES_SCANNING + * @li VL53L1_PRESETMODE_RANGING + * @li VL53L1_PRESETMODE_AUTONOMOUS + * @li VL53L1_PRESETMODE_LOWPOWER_AUTONOMOUS + * @li VL53L1_PRESETMODE_LITE_RANGING + * @li VL53L1_PRESETMODE_OLT + */ +/** + * + * @return VL53L1_ERROR_NONE Success + * @return VL53L1_ERROR_MODE_NOT_SUPPORTED This error occurs when PresetMode is + * not in the supported list + */ +VL53L1_Error VL53L1_SetPresetMode(VL53L1_DEV Dev, + VL53L1_PresetModes PresetMode); + +/** + * @brief Get current Preset Mode + * @par Function Description + * Get actual mode of the device(ranging, histogram ...) + * + * @note This function doesn't Access to the device + * + * @param Dev Device Handle + * @param pPresetMode Pointer to current apply mode value + * + * @return VL53L1_ERROR_NONE Success + * @return VL53L1_ERROR_MODE_NOT_SUPPORTED This error occurs when + * DeviceMode is not in the supported list + */ +VL53L1_Error VL53L1_GetPresetMode(VL53L1_DEV Dev, + VL53L1_PresetModes *pPresetMode); + + +/** + * @brief Set the distance mode + * @par Function Description + * Set the distance mode to be used for the next ranging.
+ * The modes Short, Medium and Long are used to optimize the ranging accuracy + * in a specific range of distance.
The user select one of these modes to + * select the distance range.
+ * Two additional modes are supported: AUTO and AUTO_LITE the difference between + * these modes is the following.
+ * The mode AUTO take into account both the ranging distance (RangeMilliMeter) + * and the dmax distance (DmaxMilliMeter).
The algorithm uses the ranging + * distance when the range status is ok and uses the dmax distance when the + * range status is not ok.
+ * The AUTO_LITE take into account only the ranging distance, so nothing is done + * in case of range error i.e. the distance mode will not be changed. + * @note This function doesn't Access to the device + * + * @warning This function should be called after @a VL53L1_SetPresetMode(). + + * @param Dev Device Handle + * @param DistanceMode Distance mode to apply valid values are: + * @li VL53L1_DISTANCEMODE_SHORT + * @li VL53L1_DISTANCEMODE_MEDIUM + * @li VL53L1_DISTANCEMODE_LONG + * @li VL53L1_DISTANCEMODE_AUTO_LITE + * @li VL53L1_DISTANCEMODE_AUTO + * @return VL53L1_ERROR_NONE Success + * @return VL53L1_ERROR_MODE_NOT_SUPPORTED This error occurs when DistanceMode + * is not in the supported list + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_SetDistanceMode(VL53L1_DEV Dev, + VL53L1_DistanceModes DistanceMode); + +/** + * @brief Get the distance mode + * @par Function Description + * Get the distance mode used for the next ranging. + * + * @param Dev Device Handle + * @param *pDistanceMode Pointer to Distance mode + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetDistanceMode(VL53L1_DEV Dev, + VL53L1_DistanceModes *pDistanceMode); + + +/** + * @brief Set the output mode + * @par Function Description + * Set the output mode to be used for the next ranging. The output mode is used + * to select, in case of multiple objects, which one will be used in + * function @a VL53L1_GetRangingMeasurementData(). + * VL53L1_SetOutputMode also sets the object used by automatic + * distance mode algorithm when @a VL53L1_SetDistanceMode() is + * set to automatic mode. + * + * @note This function doesn't Access to the device + * + * @warning This function should be called after @a VL53L1_SetPresetMode(). + + * @param Dev Device Handle + * @param OutputMode Output mode to apply valid values are: + * @li VL53L1_OUTPUTMODE_NEAREST + * @li VL53L1_OUTPUTMODE_STRONGEST + * + * @return VL53L1_ERROR_NONE Success + * @return VL53L1_ERROR_MODE_NOT_SUPPORTED This error occurs when OutputMode + * is not in the supported list + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_SetOutputMode(VL53L1_DEV Dev, + VL53L1_OutputModes OutputMode); + +/** + * @brief Get the output mode + * @par Function Description + * Get the output mode used for the next ranging. + * + * @param Dev Device Handle + * @param *pOutputMode Pointer to Output mode + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetOutputMode(VL53L1_DEV Dev, + VL53L1_OutputModes *pOutputMode); + + +/** + * @brief Set Ranging Timing Budget in microseconds + * + * @par Function Description + * Defines the maximum time allowed by the user to the device to run a + * full ranging sequence for the current mode (ranging, histogram, ASL ...) + * + * @param Dev Device Handle + * @param MeasurementTimingBudgetMicroSeconds Max measurement time in + * microseconds. + * @return VL53L1_ERROR_NONE Success + * @return VL53L1_ERROR_INVALID_PARAMS Error timing parameter not + * supported. + * The maximum accepted value for the + * computed timing budget is 10 seconds + * the minimum value depends on the preset + * mode selected. + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_SetMeasurementTimingBudgetMicroSeconds( + VL53L1_DEV Dev, uint32_t MeasurementTimingBudgetMicroSeconds); + +/** + * @brief Get Ranging Timing Budget in microseconds + * + * @par Function Description + * Returns the programmed the maximum time allowed by the user to the + * device to run a full ranging sequence for the current mode + * (ranging, histogram, ASL ...) + * + * @param Dev Device Handle + * @param pMeasurementTimingBudgetMicroSeconds Max measurement time in + * microseconds. + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetMeasurementTimingBudgetMicroSeconds( + VL53L1_DEV Dev, uint32_t *pMeasurementTimingBudgetMicroSeconds); + + +/** + * Program continuous mode Inter-Measurement period in milliseconds + * + * @par Function Description + * When trying to set too short time return INVALID_PARAMS minimal value + * + * @param Dev Device Handle + * @param InterMeasurementPeriodMilliSeconds Inter-Measurement Period in ms. + * this value should be greater than the duration set in + * @a VL53L1_SetMeasurementTimingBudgetMicroSeconds() to ensure smooth ranging + * operation. + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_SetInterMeasurementPeriodMilliSeconds( + VL53L1_DEV Dev, uint32_t InterMeasurementPeriodMilliSeconds); + +/** + * Get continuous mode Inter-Measurement period in milliseconds + * + * @par Function Description + * + * @param Dev Device Handle + * @param pInterMeasurementPeriodMilliSeconds Pointer to programmed + * Inter-Measurement Period in milliseconds. + * @return VL53L1_ERROR_NONE + */ +VL53L1_Error VL53L1_GetInterMeasurementPeriodMilliSeconds( + VL53L1_DEV Dev, uint32_t *pInterMeasurementPeriodMilliSeconds); + +/** + * @brief target reflectance for Dmax setting + * @par Function Description + * Allow user to set the value for target reflectance @ 940nm to calculate the + * ambient DMAX values for. Set to 50% by default by @a VL53L1_DataInit() + * + * @param Dev Device Handle + * @param DmaxReflectance Reflectance % in 16.16 fixed point + * @return VL53L1_ERROR_NONE Success + * @return VL53L1_ERROR_INVALID_PARAMS in case input value is not in range + * from 0 to 100. Note that this is a fix point value so the max value is + * 100 * 65536. + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_SetDmaxReflectance(VL53L1_DEV Dev, + FixPoint1616_t DmaxReflectance); + +/** + * @brief Get target reflectance for Dmax + * @par Function Description + * Retrieves the value for target reflectance @ 940nm to calculate the + * ambient DMAX values for. Set to 50% by default by @a VL53L1_DataInit() + * + * @param Dev Device Handle + * @param pDmaxReflectance pointer to Reflectance % in 16.16 fixed point + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetDmaxReflectance(VL53L1_DEV Dev, + FixPoint1616_t *pDmaxReflectance); +/** + * @brief Set function for ambient Dmax mode + * + * + * @param Dev Device Handle + * @param DmaxMode DMAX mode to be used in ranging + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + + +VL53L1_Error VL53L1_SetDmaxMode(VL53L1_DEV Dev, + VL53L1_DeviceDmaxModes DmaxMode); + +/** + * @brief Get function for ambient Dmax mode + * + * @param Dev Device Handle + * @param pDmaxMode output pointer to DMAX mode currently in use + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_GetDmaxMode(VL53L1_DEV Dev, + VL53L1_DeviceDmaxModes *pDmaxMode); + +/** @} VL53L1_parameters_group */ + + +/** @defgroup VL53L1_limitcheck_group VL53L1 Limit Check Functions + * @brief Functions used for the Limit checks + * @{ + */ + + + +/** + * @brief Get the number of the check limit managed by a given Device + * + * @par Function Description + * This function give the number of the check limit managed by the Device + * + * @param pNumberOfLimitCheck Pointer to the number of check limit. + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetNumberOfLimitCheck( + uint16_t *pNumberOfLimitCheck); + +/** + * @brief Return a description string for a given limit check number + * + * @par Function Description + * This function returns a description string for a given limit check number. + * The limit check is identified with the LimitCheckId. + * + * @param LimitCheckId Limit Check ID + * (0<= LimitCheckId < VL53L1_GetNumberOfLimitCheck() ). + * @param pLimitCheckString Pointer to the description string of + * the given check limit. Shall be defined as char buf[VL53L1_MAX_STRING_LENGTH] + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetLimitCheckInfo(uint16_t LimitCheckId, + char *pLimitCheckString); + +/** + * @brief Return a the Status of the specified check limit + * + * @par Function Description + * This function returns the Status of the specified check limit. + * The value indicate if the check is fail or not. + * The limit check is identified with the LimitCheckId. + * + * @param Dev Device Handle + * @param LimitCheckId Limit Check ID + (0<= LimitCheckId < VL53L1_GetNumberOfLimitCheck() ). + * @param pLimitCheckStatus Pointer to the + Limit Check Status of the given check limit. + * LimitCheckStatus : + * 0 the check is not fail or not enabled + * 1 the check if fail + * + *

    + *
  • VL53L1_CHECKENABLE_SIGMA_FINAL_RANGE: the sigma indicate the quality + * of the measure. The more it is little the better it is. + * The status is 1 when current sigma is greater then the limit.
  • + *
  • VL53L1_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE: the signal rate indicate + * the strength of the returned signal. The more it is big the better it is. + * The status is 1 when current signal is lower then the limit.
  • + *

+ * + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetLimitCheckStatus(VL53L1_DEV Dev, + uint16_t LimitCheckId, uint8_t *pLimitCheckStatus); + +/** + * @brief Enable/Disable a specific limit check + * + * @par Function Description + * This function Enable/Disable a specific limit check. + * The limit check is identified with the LimitCheckId. + * + * @note This function doesn't Access to the device + * + * @param Dev Device Handle + * @param LimitCheckId Limit Check ID + * (0<= LimitCheckId < VL53L1_GetNumberOfLimitCheck() ). + * @param LimitCheckEnable + * @li set LimitCheckEnable=1 enables the LimitCheckId limit + * @li set LimitCheckEnable=0 disables the LimitCheckId limit + * @return VL53L1_ERROR_NONE Success + * @return VL53L1_ERROR_INVALID_PARAMS This error is returned + * when LimitCheckId value is out of range. + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_SetLimitCheckEnable(VL53L1_DEV Dev, + uint16_t LimitCheckId, uint8_t LimitCheckEnable); + +/** + * @brief Get specific limit check enable state + * + * @par Function Description + * This function get the enable state of a specific limit check. + * The limit check is identified with the LimitCheckId. + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @param LimitCheckId Limit Check ID + * (0<= LimitCheckId < VL53L1_GetNumberOfLimitCheck() ). + * @param pLimitCheckEnable Pointer to the check limit enable + * value. + * @li if 1 the check limit corresponding to LimitCheckId is Enabled + * @li if 0 the check limit corresponding to LimitCheckId is disabled + * @return VL53L1_ERROR_NONE Success + * @return VL53L1_ERROR_INVALID_PARAMS This error is returned + * when LimitCheckId value is out of range. + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetLimitCheckEnable(VL53L1_DEV Dev, + uint16_t LimitCheckId, uint8_t *pLimitCheckEnable); + +/** + * @brief Set a specific limit check value + * + * @par Function Description + * This function set a specific limit check value. + * The limit check is identified with the LimitCheckId. + * + * @note Note that the value written with that function will not be applied if + * the limit is not enabled. In other words this function will not enable the + * limit but change only the value. In case the limit is not enabled the value + * is saved internally and applied with VL53L1_SetLimitCheckEnable. + * + * @param Dev Device Handle + * @param LimitCheckId Limit Check ID + * (0<= LimitCheckId < VL53L1_GetNumberOfLimitCheck() ). + * @param LimitCheckValue Limit check Value for a given + * LimitCheckId + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_SetLimitCheckValue(VL53L1_DEV Dev, + uint16_t LimitCheckId, FixPoint1616_t LimitCheckValue); + +/** + * @brief Get a specific limit check value + * + * @par Function Description + * This function get a specific limit check value from device then it updates + * internal values and check enables. + * The limit check is identified with the LimitCheckId. + * + * @note This function get the current value from device if zero then the value + * returned is the one stored by the user, but in that case the check is store + * as disabled. If the value from device is not zero, this is returned and set + * into the memory at the same way that user call VL53L1_SetLimitCheckValue() + * + * @param Dev Device Handle + * @param LimitCheckId Limit Check ID + * (0<= LimitCheckId < VL53L1_GetNumberOfLimitCheck() ). + * @param pLimitCheckValue Pointer to Limit + * check Value for a given LimitCheckId. + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetLimitCheckValue(VL53L1_DEV Dev, + uint16_t LimitCheckId, FixPoint1616_t *pLimitCheckValue); + +/** + * @brief Get the current value of the signal used for the limit check + * + * @par Function Description + * This function get a the current value of the signal used for the limit check. + * To obtain the latest value you should run a valid ranging before. + * The value reported is linked to the limit check identified with the + * LimitCheckId. + * + * @param Dev Device Handle + * @param LimitCheckId Limit Check ID + * (0<= LimitCheckId < VL53L1_GetNumberOfLimitCheck() ). + * @param pLimitCheckCurrent Pointer to current Value for a + * given LimitCheckId. + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetLimitCheckCurrent(VL53L1_DEV Dev, + uint16_t LimitCheckId, FixPoint1616_t *pLimitCheckCurrent); + +/** @} VL53L1_limitcheck_group */ + + + +/** @defgroup VL53L1_ROI_group VL53L1 ROI Functions + * @brief Functions used to select ROIs + * @{ + */ + +/** + * @brief Get the Maximum number of ROI Zones managed by the Device + * + * @par Function Description + * Get Maximum number of ROI Zones managed by the Device. + * + * @note The number of Zone depends on the preset mode used so to have the + * right number this function should be call after @a VL53L1_SetPresetMode() + * @note This function doesn't Access to the device + * + * @param Dev Device Handle + * @param pMaxNumberOfROI Pointer to the Maximum Number + * of ROI Zones value. + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetMaxNumberOfROI(VL53L1_DEV Dev, + uint8_t *pMaxNumberOfROI); +/** + * @brief Set the ROI to be used for ranging + * + * @par Function Description + * The user defined ROIs are rectangles described as per the following system + * from the Top Left corner to the Bottom Right corner. + *
Minimal ROI size is 4x4 spads + * @image html roi_coord.png + * + * @param Dev Device Handle + * @param pRoiConfig Pointer to the Structure containing all the + * ROI to be used. + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_SetROI(VL53L1_DEV Dev, + VL53L1_RoiConfig_t *pRoiConfig); + +/** + * @brief Get the ROI managed by the Device + * + * @par Function Description + * Get the ROI managed by the Device + * + * @param Dev Device Handle + * @param pRoiConfig Pointer to the Structure containing all the + * ROI to be used. + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetROI(VL53L1_DEV Dev, + VL53L1_RoiConfig_t *pRoiConfig); + +/** @} VL53L1_ROI_group */ + +/* \internal */ +/** @defgroup VL53L1_sequencestep_group VL53L1 Sequence Step Functions + * @brief Functions used to select Steps done on each ranging + * @{ + */ + +/** + * @brief Gets number of sequence steps managed by the API. + * + * @par Function Description + * This function retrieves the number of sequence steps currently managed + * by the API + * + * @note This function Accesses the device + * + * @param Dev Device Handle + * @param pNumberOfSequenceSteps Out parameter reporting the number of + * sequence steps. + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetNumberOfSequenceSteps(VL53L1_DEV Dev, + uint8_t *pNumberOfSequenceSteps); + +/** + * @brief Gets the name of a given sequence step. + * + * @par Function Description + * This function retrieves the name of sequence steps corresponding to + * SequenceStepId. + * + * @note This function doesn't Accesses the device + * + * @param SequenceStepId Sequence step identifier. + * @param pSequenceStepsString Pointer to Info string. Shall be + * defined as char buf[VL53L1_MAX_STRING_LENGTH] + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetSequenceStepsInfo( + VL53L1_SequenceStepId SequenceStepId, char *pSequenceStepsString); + + + +/** + * @brief Sets the (on/off) state of a requested sequence step. + * + * @par Function Description + * This function enables/disables a requested sequence step. + * + * @note This function Accesses the device + * + * @param Dev Device Handle + * @param SequenceStepId Sequence step identifier. + * @param SequenceStepEnabled Demanded state {0=Off,1=On} + * is enabled. + * @return VL53L1_ERROR_NONE Success + * @return VL53L1_ERROR_INVALID_PARAMS Error SequenceStepId parameter not + * supported. + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_SetSequenceStepEnable(VL53L1_DEV Dev, + VL53L1_SequenceStepId SequenceStepId, uint8_t SequenceStepEnabled); + +/** + * @brief Gets the (on/off) state of a requested sequence step. + * + * @par Function Description + * This function retrieves the state of a requested sequence step, i.e. on/off. + * + * @note This function Accesses the device + * + * @param Dev Device Handle + * @param SequenceStepId Sequence step identifier. + * @param pSequenceStepEnabled Out parameter reporting if the sequence step + * is enabled {0=Off,1=On}. + * @return VL53L1_ERROR_NONE Success + * @return VL53L1_ERROR_INVALID_PARAMS Error SequenceStepId parameter not + * supported. + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetSequenceStepEnable(VL53L1_DEV Dev, + VL53L1_SequenceStepId SequenceStepId, uint8_t *pSequenceStepEnabled); + + +/** @} VL53L1_sequencestep_group */ +/* \endinternal */ + + + +/** @defgroup VL53L1_measurement_group VL53L1 Measurement Functions + * @brief Functions used for the measurements + * @{ + */ + +/** + * @brief Start device measurement + * + * @details Started measurement will depend on preset parameters set through + * @a VL53L1_SetPreseMode() + * This function will change the VL53L1_State from VL53L1_STATE_IDLE to + * VL53L1_STATE_RUNNING. + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @return VL53L1_ERROR_NONE Success + * @return VL53L1_ERROR_MODE_NOT_SUPPORTED This error occurs when + * PresetMode programmed with @a VL53L1_SetPresetMode + * @return VL53L1_ERROR_TIME_OUT Time out on start measurement + * @return VL53L1_ERROR_INVALID_PARAMS This error might occur in timed mode + * when inter measurement period is smaller or too close to the timing budget. + * In such case measurements are not started and user must correct the timings + * passed to @a VL53L1_SetMeasurementTimingBudgetMicroSeconds() and + * @a VL53L1_SetInterMeasurementPeriodMilliSeconds() functions. + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_StartMeasurement(VL53L1_DEV Dev); + +/** + * @brief Stop device measurement + * + * @details Will set the device in standby mode at end of current measurement\n + * Not necessary in single mode as device shall return automatically + * in standby mode at end of measurement. + * This function will change the VL53L1_State from VL53L1_STATE_RUNNING + * to VL53L1_STATE_IDLE. + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_StopMeasurement(VL53L1_DEV Dev); + +/** + * @brief Clear the Interrupt flag and start new measurement + * * + * @note This function Access to the device + * + * @param Dev Device Handle + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_ClearInterruptAndStartMeasurement(VL53L1_DEV Dev); + +/** + * @brief Return Measurement Data Ready + * + * @par Function Description + * This function indicate that a measurement data is ready. + * This function is used for non-blocking capture. + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @param pMeasurementDataReady Pointer to Measurement Data Ready. + * 0 = data not ready, 1 = data ready + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetMeasurementDataReady(VL53L1_DEV Dev, + uint8_t *pMeasurementDataReady); + +/** + * @brief Wait for measurement data ready. + * Blocking function. + * Note that the timeout is given by: + * VL53L1_RANGE_COMPLETION_POLLING_TIMEOUT_MS defined in def.h + * + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @return VL53L1_ERROR_NONE Success + * @return VL53L1_ERROR_TIME_OUT In case of timeout + */ +VL53L1_Error VL53L1_WaitMeasurementDataReady(VL53L1_DEV Dev); + + +/** + * @brief Retrieve the measurements from device for a given setup + * + * @par Function Description + * Get data from last successful Ranging measurement + */ +/** + * @warning this function will return only the first ROI data and only the + * first object. For multi objects or multi ROI use: + * @a Vl53L1_GetMultiRangingData. + * In case of RANGING only one output is given, this can + * be selected with the help of @a VL53L1_SetOutputMode() + * In case of MULTIZONES_SCANNING and error will be raised because not + * supported in that function. + */ +/** + * + * @warning USER must call @a VL53L1_ClearInterruptAndStartMeasurement() prior + * to call again this function + * + * @note This function Access to the device + * + * @note The first valid value returned by this function will have a range + * status equal to VL53L1_RANGESTATUS_RANGE_VALID_NO_WRAP_CHECK which means that + * the data is valid but no wrap around check have been done. User should take + * care about that. + * + * @param Dev Device Handle + * @param pRangingMeasurementData Pointer to the data structure to fill up. + * @return VL53L1_ERROR_NONE Success + * @return VL53L1_ERROR_MODE_NOT_SUPPORTED in case of MULTIZONES_SCANNING + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetRangingMeasurementData(VL53L1_DEV Dev, + VL53L1_RangingMeasurementData_t *pRangingMeasurementData); + +/** + * @brief Retrieve all ROI's measurements from device for a given setup + * + * @par Function Description + * Get data from last successful Ranging measurement + * @warning USER should take care about @a VL53L1_GetNumberOfROI() + * before get data. + * Bare driver will fill a NumberOfROI times the corresponding data + * structure used in the measurement function. + * + * @warning USER must call @a VL53L1_ClearInterruptAndStartMeasurement() prior + * to call again this function + * + * @note This function Access to the device + * + * @note The first valid value returned by this function will have a range + * status equal to VL53L1_RANGESTATUS_RANGE_VALID_NO_WRAP_CHECK which means that + * the data is valid but no wrap around check have been done. User should take + * care about that. + * + * @param Dev Device Handle + * @param pMultiRangingData Pointer to the data structure to fill up. + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetMultiRangingData(VL53L1_DEV Dev, + VL53L1_MultiRangingData_t *pMultiRangingData); + +/** + * @brief Get Additional Data + * + * @par Function Description + * This function is used to get lld debugging data on the last histogram + * measurement. shall be called when a new measurement is ready (interrupt or + * positive VL53L1_GetMeasurementDataReady() polling) and before a call to + * VL53L1_ClearInterruptAndStartMeasurement(). Depending on the PresetMode + * currently set parts of the returned data structure may be not relevant. + * + * @param Dev Device Handle + * @param pAdditionalData Pointer to Additional data + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetAdditionalData(VL53L1_DEV Dev, + VL53L1_AdditionalData_t *pAdditionalData); + + +/** @} VL53L1_measurement_group */ + +/** @defgroup VL53L1_Calibration_group VL53L1 Calibration Functions + * @brief Functions used for Calibration + * @{ + */ + + +/** + * @brief Set Tuning Parameter value for a given parameter ID + * + * @par Function Description + * This function is used to improve the performance of the device. It permit to + * change a particular value used for a timeout or a threshold or a constant + * in an algorithm. The function will change the value of the parameter + * identified by an unique ID. + * + * @note This function doesn't Access to the device + * + * @param Dev Device Handle + * @param TuningParameterId Tuning Parameter ID + * @param TuningParameterValue Tuning Parameter Value + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_SetTuningParameter(VL53L1_DEV Dev, + uint16_t TuningParameterId, int32_t TuningParameterValue); + +/** + * @brief Get Tuning Parameter value for a given parameter ID + * + * @par Function Description + * This function is used to get the value of the parameter + * identified by an unique ID. + * + * @note This function doesn't Access to the device + * + * @param Dev Device Handle + * @param TuningParameterId Tuning Parameter ID + * @param pTuningParameterValue Pointer to Tuning Parameter Value + * for a given TuningParameterId. + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetTuningParameter(VL53L1_DEV Dev, + uint16_t TuningParameterId, int32_t *pTuningParameterValue); + +/** + * @brief Performs Reference Spad Management + * + * @par Function Description + * The reference SPAD initialization procedure determines the minimum amount + * of reference spads to be enables to achieve a target reference signal rate + * and should be performed once during initialization. + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_PerformRefSpadManagement(VL53L1_DEV Dev); + +/** + * @brief Enable/Disable dynamic Xtalk compensation feature + * + * Enable/Disable dynamic Xtalk compensation (aka smudge correction). + * + * @param Dev Device Handle + * @param Mode Set the smudge correction mode + * See ::VL53L1_SmudgeCorrectionModes + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_SmudgeCorrectionEnable(VL53L1_DEV Dev, + VL53L1_SmudgeCorrectionModes Mode); + +/** + * @brief Enable/Disable Cross talk compensation feature + * + * Enable/Disable Cross Talk correction. + * + * @param Dev Device Handle + * @param XTalkCompensationEnable Cross talk compensation + * to be set 0 = disabled or 1 = enabled. + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_SetXTalkCompensationEnable(VL53L1_DEV Dev, +uint8_t XTalkCompensationEnable); + +/** + * @brief Get Cross talk compensation rate enable + * + * Get if the Cross Talk is Enabled or Disabled. + * + * @note This function doesn't access to the device + * + * @param Dev Device Handle + * @param pXTalkCompensationEnable Pointer to the Cross talk compensation + * state 0=disabled or 1 = enabled + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetXTalkCompensationEnable(VL53L1_DEV Dev, + uint8_t *pXTalkCompensationEnable); + + +/** + * @brief Perform XTalk Calibration + * + * @details Perform a XTalk calibration of the Device. + * This function will launch a ranging measurement, if interrupts + * are enabled an interrupt will be done. + * This function will clear the interrupt generated automatically. + * This function will program a new value for the XTalk compensation + * and it will enable the cross talk before exit. + * + * @warning This function is a blocking function + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @param CalibrationOption Select the Calibration to be run : + * @param CalibrationOption + * @li VL53L1_XTALKCALIBRATIONMODE_SINGLE_TARGET the calibration uses current + * preset and distance mode without altering them.
+ * User must call @a VL53L1_SetPresetMode() with VL53L1_PRESETMODE_AUTONOMOUS, + * VL53L1_PRESETMODE_LITE_RANGING or VL53L1_PRESETMODE_LOWPOWER_AUTONOMOUS + * parameter prior to launch calibration + * @li VL53L1_XTALKCALIBRATIONMODE_NO_TARGET the calibration sets appropriate + * preset and distance mode and thus override existing ones
+ * User must call @a VL53L1_SetPresetMode() again after calibration to set the + * desired one. during this calibration mode no object must be put below a 80cm + * distance from the target + * @li VL53L1_XTALKCALIBRATIONMODE_FULL_ROI the calibration sets appropriate + * preset and distance mode and thus override existing ones
+ * User must call @a VL53L1_SetPresetMode() again after calibration to set the + * desired one. + * The ROI settings must define a single 16x16 ROI before to launch this + * function. + * The calibration uses a target which should be located at least @60cm from the + * device. The actual location of the target shall be passed + * through the bare driver tuning parameters table + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_PerformXTalkCalibration(VL53L1_DEV Dev, + uint8_t CalibrationOption); + +/** + * @brief Define the mode to be used for the offset calibration + * + * Define the mode to be used for the offset calibration. This function should + * be called before run the @a VL53L1_PerformOffsetCalibration() + * + * @param Dev Device Handle + * @param OffsetCalibrationMode Offset Calibration Mode valid values are: + * @li VL53L1_OFFSETCALIBRATIONMODE_STANDARD + * @li VL53L1_OFFSETCALIBRATIONMODE_PRERANGE_ONLY + * @li VL53L1_OFFSETCALIBRATIONMODE_MULTI_ZONE + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_SetOffsetCalibrationMode(VL53L1_DEV Dev, + VL53L1_OffsetCalibrationModes OffsetCalibrationMode); + +/** + * @brief Define the mode to be used for the offset correction + * + * Define the mode to be used for the offset correction. + * + * @param Dev Device Handle + * @param OffsetCorrectionMode Offset Correction Mode valid values are: + * @li VL53L1_OFFSETCORRECTIONMODE_STANDARD + * @li VL53L1_OFFSETCORRECTIONMODE_PERZONE + * @li VL53L1_OFFSETCORRECTIONMODE_PERVCSEL + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_SetOffsetCorrectionMode(VL53L1_DEV Dev, + VL53L1_OffsetCorrectionModes OffsetCorrectionMode); + + +/** + * @brief Perform Offset Calibration + * + * @details Perform a Offset calibration of the Device. + * This function will launch a ranging measurement, if interrupts are + * enabled interrupts will be done. + * This function will program a new value for the Offset calibration value + * + * @warning This function is a blocking function + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @param CalDistanceMilliMeter Calibration distance value used for the + * offset compensation. + * @param CalReflectancePercent Calibration Target reflectance @ 940nm + * in percentage. + * + * @return VL53L1_ERROR_NONE + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_PerformOffsetCalibration(VL53L1_DEV Dev, + int32_t CalDistanceMilliMeter, + FixPoint1616_t CalReflectancePercent); + +/** + * @brief Perform Offset simple Calibration + * + * @details Perform a very simple offset calibration of the Device. + * This function will launch few ranging measurements and computes offset + * calibration. The preset mode and the distance mode MUST be set by the + * application before to call this function. + * + * @warning This function is a blocking function + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @param CalDistanceMilliMeter Calibration distance value used for the + * offset compensation. + * + * @return VL53L1_ERROR_NONE + * @return VL53L1_ERROR_OFFSET_CAL_NO_SAMPLE_FAIL the calibration failed by + * lack of valid measurements + * @return VL53L1_WARNING_OFFSET_CAL_SIGMA_TOO_HIGH means that the target + * distance combined to the number of loops performed in the calibration lead to + * an internal overflow. Try to reduce the distance of the target (140 mm) + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_PerformOffsetSimpleCalibration(VL53L1_DEV Dev, + int32_t CalDistanceMilliMeter); + +/** + * @brief Perform Offset simple Calibration with a "zero distance" target + * + * @details Perform a simple offset calibration of the Device. + * This function will launch few ranging measurements and computes offset + * calibration. The preset mode and the distance mode MUST be set by the + * application before to call this function. + * A target must be place very close to the device. + * Ideally the target shall be touching the coverglass. + * + * @warning This function is a blocking function + * + * @note This function Access to the device + * + * @param Dev Device Handle + * + * @return VL53L1_ERROR_NONE + * @return VL53L1_ERROR_OFFSET_CAL_NO_SAMPLE_FAIL the calibration failed by + * lack of valid measurements + * @return VL53L1_WARNING_OFFSET_CAL_SIGMA_TOO_HIGH means that the target + * distance is too large, try to put the target closer to the device + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_PerformOffsetZeroDistanceCalibration(VL53L1_DEV Dev); + +/** + * @brief Perform Offset per Vcsel Calibration. i.e. per distance mode + * + * @details Perform offset calibration of the Device depending on the + * three distance mode settings: short, medium and long. + * This function will launch few ranging measurements and computes offset + * calibration in each of the three distance modes. + * The preset mode MUST be set by the application before to call this function. + * + * @warning This function is a blocking function + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @param CalDistanceMilliMeter Distance of the target used for the + * offset compensation calibration. + * + * @return VL53L1_ERROR_NONE + * @return VL53L1_ERROR_OFFSET_CAL_NO_SAMPLE_FAIL the calibration failed by + * lack of valid measurements + * @return VL53L1_WARNING_OFFSET_CAL_SIGMA_TOO_HIGH means that the target + * distance combined to the number of loops performed in the calibration lead to + * an internal overflow. Try to reduce the distance of the target (140 mm) + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_PerformOffsetPerVcselCalibration(VL53L1_DEV Dev, + int32_t CalDistanceMilliMeter); +/** + * @brief Sets the Calibration Data. + * + * @par Function Description + * This function set all the Calibration Data issued from the functions + * @a VL53L1_PerformRefSpadManagement(), @a VL53L1_PerformXTalkCalibration, + * @a VL53L1_PerformOffsetCalibration() + * + * @note This function doesn't Accesses the device + * + * @param Dev Device Handle + * @param *pCalibrationData Pointer to Calibration data to be set. + * @return VL53L1_ERROR_NONE Success + * @return VL53L1_ERROR_INVALID_PARAMS pCalibrationData points to an older + * version of the inner structure. Need for support to convert its content. + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_SetCalibrationData(VL53L1_DEV Dev, + VL53L1_CalibrationData_t *pCalibrationData); + +/** + * @brief Gets the Calibration Data. + * + * @par Function Description + * This function get all the Calibration Data issued from the functions + * @a VL53L1_PerformRefSpadManagement(), @a VL53L1_PerformXTalkCalibration, + * @a VL53L1_PerformOffsetCalibration() + * + * @note This function doesn't Accesses the device + * + * @param Dev Device Handle + * @param *pCalibrationData pointer where to store Calibration + * data. + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetCalibrationData(VL53L1_DEV Dev, + VL53L1_CalibrationData_t *pCalibrationData); + +/** + * @brief Sets the Zone Calibration Data. + * + * @par Function Description + * This function set all the Zone nCalibration Data issued from the functions + * @a VL53L1_PerformOffsetCalibration() in multi zone + * + * @note This function doesn't Accesses the device + * + * @param Dev Device Handle + * @param *pZoneCalibrationData Pointer to Zone Calibration data to be + * set. + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_SetZoneCalibrationData(VL53L1_DEV Dev, + VL53L1_ZoneCalibrationData_t *pZoneCalibrationData); + +/** + * @brief Gets the Zone Calibration Data. + * + * @par Function Description + * This function get all the Zone Calibration Data issued from the functions + * @a VL53L1_PerformOffsetCalibration() + * + * @note This function doesn't Accesses the device + * + * @param Dev Device Handle + * @param *pZoneCalibrationData pointer where to store Zone Calibration + * data. + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetZoneCalibrationData(VL53L1_DEV Dev, + VL53L1_ZoneCalibrationData_t *pZoneCalibrationData); +/** + * @brief Gets the optical center. + * + * @par Function Description + * This function get the optical center issued from the nvm set at FTM stage + * expressed in the same coordinate system as the ROI are + * + * @note This function doesn't Accesses the device + * + * @param Dev Device Handle + * @param pOpticalCenterX pointer to the X position of center + * in 16.16 fix point + * @param pOpticalCenterY pointer to the Y position of center + * in 16.16 fix point + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetOpticalCenter(VL53L1_DEV Dev, + FixPoint1616_t *pOpticalCenterX, + FixPoint1616_t *pOpticalCenterY); + +/** @} VL53L1_Calibration_group */ + +/** @defgroup VL53L1_Thresholds_group VL53L1 IRQ Triggered events Functions + * @brief Functions used to configure interrupt to be triggered only when + * a measurement satisfies some thresholds parameters + * @{ + */ + +/** + * @brief Configure the interrupt config, from the given structure + * + * @param[in] Dev : Device Handle + * @param[in] pConfig : pointer to configuration structure + */ + +VL53L1_Error VL53L1_SetThresholdConfig(VL53L1_DEV Dev, + VL53L1_DetectionConfig_t *pConfig); + +/** + * @brief Retrieves the interrupt config structure currently programmed + * into the API + * + * @param[in] Dev : Device Handle + * @param[out] pConfig : pointer to configuration structure + */ + +VL53L1_Error VL53L1_GetThresholdConfig(VL53L1_DEV Dev, + VL53L1_DetectionConfig_t *pConfig); + + +/** @} VL53L1_Thresholds_group */ + + +/** @} VL53L1_cut11_group */ + +#ifdef __cplusplus +} +#endif + +#endif /* _VL53L1_API_H_ */ diff --git a/drivers/input/misc/vl53L1/kona/inc/vl53l1_api_calibration.h b/drivers/input/misc/vl53L1/kona/inc/vl53l1_api_calibration.h new file mode 100644 index 000000000000..62cb011a37f2 --- /dev/null +++ b/drivers/input/misc/vl53L1/kona/inc/vl53l1_api_calibration.h @@ -0,0 +1,596 @@ + +/******************************************************************************* + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#ifndef _VL53L1_API_CALIBRATION_H_ +#define _VL53L1_API_CALIBRATION_H_ + +#include "vl53l1_platform.h" + +#ifdef __cplusplus +extern "C" { +#endif + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_run_ref_spad_char(VL53L1_DEV Dev, + VL53L1_Error * pcal_status); + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_run_device_test( + VL53L1_DEV Dev, + VL53L1_DeviceTestMode device_test_mode); + + + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_run_spad_rate_map( + VL53L1_DEV Dev, + VL53L1_DeviceTestMode device_test_mode, + VL53L1_DeviceSscArray array_select, + uint32_t ssc_config_timeout_us, + VL53L1_spad_rate_data_t *pspad_rate_data); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_run_xtalk_extraction( + VL53L1_DEV Dev, + VL53L1_Error *pcal_status); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_and_avg_xtalk_samples( + VL53L1_DEV Dev, + uint8_t num_of_samples, + uint8_t measurement_mode, + int16_t xtalk_filter_thresh_max_mm, + int16_t xtalk_filter_thresh_min_mm, + uint16_t xtalk_max_valid_rate_kcps, + uint8_t xtalk_result_id, + uint8_t xtalk_histo_id, + VL53L1_xtalk_range_results_t *pxtalk_results, + VL53L1_histogram_bin_data_t *psum_histo, + VL53L1_histogram_bin_data_t *pavg_histo); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_run_offset_calibration( + VL53L1_DEV Dev, + int16_t cal_distance_mm, + uint16_t cal_reflectance_pc, + VL53L1_Error *pcal_status); + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_run_phasecal_average( + VL53L1_DEV Dev, + uint8_t measurement_mode, + uint8_t phasecal_result__vcsel_start, + uint16_t phasecal_num_of_samples, + VL53L1_range_results_t *prange_results, + uint16_t *pphasecal_result__reference_phase, + uint16_t *pzero_distance_phase); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_run_zone_calibration( + VL53L1_DEV Dev, + VL53L1_DevicePresetModes device_preset_mode, + VL53L1_DeviceZonePreset zone_preset, + VL53L1_zone_config_t *pzone_cfg, + int16_t cal_distance_mm, + uint16_t cal_reflectance_pc, + VL53L1_Error *pcal_status); + + + + + + + + + + + + +void VL53L1_hist_xtalk_extract_data_init( + VL53L1_hist_xtalk_extract_data_t *pxtalk_data); + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_hist_xtalk_extract_update( + int16_t target_distance_mm, + uint16_t target_width_oversize, + VL53L1_histogram_bin_data_t *phist_bins, + VL53L1_hist_xtalk_extract_data_t *pxtalk_data); + + + + + + + + + + + + + + +VL53L1_Error VL53L1_hist_xtalk_extract_fini( + VL53L1_histogram_bin_data_t *phist_bins, + VL53L1_hist_xtalk_extract_data_t *pxtalk_data, + VL53L1_xtalk_calibration_results_t *pxtalk_cal, + VL53L1_xtalk_histogram_shape_t *pxtalk_shape); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_run_hist_xtalk_extraction( + VL53L1_DEV Dev, + int16_t cal_distance_mm, + VL53L1_Error *pcal_status); + + +#ifdef __cplusplus +} +#endif + +#endif + + diff --git a/drivers/input/misc/vl53L1/kona/inc/vl53l1_api_core.h b/drivers/input/misc/vl53L1/kona/inc/vl53l1_api_core.h new file mode 100644 index 000000000000..9c853c7ef81c --- /dev/null +++ b/drivers/input/misc/vl53L1/kona/inc/vl53l1_api_core.h @@ -0,0 +1,1944 @@ + +/******************************************************************************* + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#ifndef _VL53L1_API_CORE_H_ +#define _VL53L1_API_CORE_H_ + +#include "vl53l1_platform.h" + +#ifdef __cplusplus +extern "C" { +#endif + + + + + + + + + + + + +VL53L1_Error VL53L1_get_version( + VL53L1_DEV Dev, + VL53L1_ll_version_t *pversion); + + + + + + + + + + + + +VL53L1_Error VL53L1_get_device_firmware_version( + VL53L1_DEV Dev, + uint16_t *pfw_version); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_data_init( + VL53L1_DEV Dev, + uint8_t read_p2p_data); + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_read_p2p_data( + VL53L1_DEV Dev); + + + + + + + + + + + + + +VL53L1_Error VL53L1_software_reset( + VL53L1_DEV Dev); + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_part_to_part_data( + VL53L1_DEV Dev, + VL53L1_calibration_data_t *pcal_data); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_part_to_part_data( + VL53L1_DEV Dev, + VL53L1_calibration_data_t *pcal_data); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_tuning_debug_data( + VL53L1_DEV Dev, + VL53L1_tuning_parameters_t *ptun_data); + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_inter_measurement_period_ms( + VL53L1_DEV Dev, + uint32_t inter_measurement_period_ms); + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_inter_measurement_period_ms( + VL53L1_DEV Dev, + uint32_t *pinter_measurement_period_ms); + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_timeouts_us( + VL53L1_DEV Dev, + uint32_t phasecal_config_timeout_us, + uint32_t mm_config_timeout_us, + uint32_t range_config_timeout_us); + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_timeouts_us( + VL53L1_DEV Dev, + uint32_t *pphasecal_config_timeout_us, + uint32_t *pmm_config_timeout_us, + uint32_t *prange_config_timeout_us); + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_calibration_repeat_period( + VL53L1_DEV Dev, + uint16_t cal_config__repeat_period); + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_calibration_repeat_period( + VL53L1_DEV Dev, + uint16_t *pcal_config__repeat_period); + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_sequence_config_bit( + VL53L1_DEV Dev, + VL53L1_DeviceSequenceConfig bit_id, + uint8_t value); + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_sequence_config_bit( + VL53L1_DEV Dev, + VL53L1_DeviceSequenceConfig bit_id, + uint8_t *pvalue); + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_interrupt_polarity( + VL53L1_DEV Dev, + VL53L1_DeviceInterruptPolarity interrupt_polarity); + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_interrupt_polarity( + VL53L1_DEV Dev, + VL53L1_DeviceInterruptPolarity *pinterrupt_polarity); + + + + + + + + + + + + +VL53L1_Error VL53L1_get_refspadchar_config_struct( + VL53L1_DEV Dev, + VL53L1_refspadchar_config_t *pdata); + + + + + + + + + + + + +VL53L1_Error VL53L1_set_refspadchar_config_struct( + VL53L1_DEV Dev, + VL53L1_refspadchar_config_t *pdata); + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_range_ignore_threshold( + VL53L1_DEV Dev, + uint8_t range_ignore_thresh_mult, + uint16_t range_ignore_threshold_mcps); + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_range_ignore_threshold( + VL53L1_DEV Dev, + uint8_t *prange_ignore_thresh_mult, + uint16_t *prange_ignore_threshold_mcps_internal, + uint16_t *prange_ignore_threshold_mcps_current); + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_user_zone( + VL53L1_DEV Dev, + VL53L1_user_zone_t *puser_zone); + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_user_zone( + VL53L1_DEV Dev, + VL53L1_user_zone_t *puser_zone); + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_mode_mitigation_roi( + VL53L1_DEV Dev, + VL53L1_user_zone_t *pmm_roi); + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_zone_config( + VL53L1_DEV Dev, + VL53L1_zone_config_t *pzone_cfg); + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_zone_config( + VL53L1_DEV Dev, + VL53L1_zone_config_t *pzone_cfg); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_preset_mode( + VL53L1_DEV Dev, + VL53L1_DevicePresetModes device_preset_mode, + uint16_t dss_config__target_total_rate_mcps, + uint32_t phasecal_config_timeout_us, + uint32_t mm_config_timeout_us, + uint32_t range_config_timeout_us, + uint32_t inter_measurement_period_ms); + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_preset_mode_timing_cfg( + VL53L1_DEV Dev, + VL53L1_DevicePresetModes device_preset_mode, + uint16_t *pdss_config__target_total_rate_mcps, + uint32_t *pphasecal_config_timeout_us, + uint32_t *pmm_config_timeout_us, + uint32_t *prange_config_timeout_us); + + + + + + + + + + + + +VL53L1_Error VL53L1_set_zone_preset( + VL53L1_DEV Dev, + VL53L1_DeviceZonePreset zone_preset); + + + + + + + + + + + + + + +VL53L1_Error VL53L1_enable_xtalk_compensation( + VL53L1_DEV Dev); + + + + + + + + + + + + + + +VL53L1_Error VL53L1_disable_xtalk_compensation( + VL53L1_DEV Dev); + + + + + + + + + + + + + + +void VL53L1_get_xtalk_compensation_enable( + VL53L1_DEV Dev, + uint8_t *pcrosstalk_compensation_enable); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_init_and_start_range( + VL53L1_DEV Dev, + uint8_t measurement_mode, + VL53L1_DeviceConfigLevel device_config_level); + + + + + + + + + + + + + +VL53L1_Error VL53L1_stop_range( + VL53L1_DEV Dev); + + + + + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_measurement_results( + VL53L1_DEV Dev, + VL53L1_DeviceResultsLevel device_result_level); + + + + + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_device_results( + VL53L1_DEV Dev, + VL53L1_DeviceResultsLevel device_result_level, + VL53L1_range_results_t *prange_results); + + + + + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_clear_interrupt_and_enable_next_range( + VL53L1_DEV Dev, + uint8_t measurement_mode); + + + + + + + + + + +VL53L1_Error VL53L1_get_histogram_bin_data( + VL53L1_DEV Dev, + VL53L1_histogram_bin_data_t *phist_data); + + + + + + + + + + + + +void VL53L1_copy_sys_and_core_results_to_range_results( + int32_t gain_factor, + VL53L1_system_results_t *psys, + VL53L1_core_results_t *pcore, + VL53L1_range_results_t *presults); + + + + + + + + + + +VL53L1_Error VL53L1_set_zone_dss_config( + VL53L1_DEV Dev, + VL53L1_zone_private_dyn_cfg_t *pzone_dyn_cfg); + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_calc_ambient_dmax( + VL53L1_DEV Dev, + uint16_t target_reflectance, + int16_t *pambient_dmax_mm); + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_GPIO_interrupt_config( + VL53L1_DEV Dev, + VL53L1_GPIO_Interrupt_Mode intr_mode_distance, + VL53L1_GPIO_Interrupt_Mode intr_mode_rate, + uint8_t intr_new_measure_ready, + uint8_t intr_no_target, + uint8_t intr_combined_mode, + uint16_t thresh_distance_high, + uint16_t thresh_distance_low, + uint16_t thresh_rate_high, + uint16_t thresh_rate_low + ); + + + + + + + + + +VL53L1_Error VL53L1_set_GPIO_interrupt_config_struct( + VL53L1_DEV Dev, + VL53L1_GPIO_interrupt_config_t intconf); + + + + + + + + + + +VL53L1_Error VL53L1_get_GPIO_interrupt_config( + VL53L1_DEV Dev, + VL53L1_GPIO_interrupt_config_t *pintconf); + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_dmax_mode( + VL53L1_DEV Dev, + VL53L1_DeviceDmaxMode dmax_mode); + + + + + + + + + + + + +VL53L1_Error VL53L1_get_dmax_mode( + VL53L1_DEV Dev, + VL53L1_DeviceDmaxMode *pdmax_mode); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_dmax_calibration_data( + VL53L1_DEV Dev, + VL53L1_DeviceDmaxMode dmax_mode, + uint8_t zone_id, + VL53L1_dmax_calibration_data_t *pdmax_cal); + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_hist_dmax_config( + VL53L1_DEV Dev, + VL53L1_hist_gen3_dmax_config_t *pdmax_cfg); + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_hist_dmax_config( + VL53L1_DEV Dev, + VL53L1_hist_gen3_dmax_config_t *pdmax_cfg); + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_offset_calibration_mode( + VL53L1_DEV Dev, + VL53L1_OffsetCalibrationMode offset_cal_mode); + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_offset_calibration_mode( + VL53L1_DEV Dev, + VL53L1_OffsetCalibrationMode *poffset_cal_mode); + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_offset_correction_mode( + VL53L1_DEV Dev, + VL53L1_OffsetCalibrationMode offset_cor_mode); + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_offset_correction_mode( + VL53L1_DEV Dev, + VL53L1_OffsetCorrectionMode *poffset_cor_mode); + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_zone_calibration_data( + VL53L1_DEV Dev, + VL53L1_zone_calibration_results_t *pzone_cal); + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_zone_calibration_data( + VL53L1_DEV Dev, + VL53L1_zone_calibration_results_t *pzone_cal); + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_lite_xtalk_margin_kcps( + VL53L1_DEV Dev, + int16_t *pxtalk_margin); + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_lite_xtalk_margin_kcps( + VL53L1_DEV Dev, + int16_t xtalk_margin); + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_histogram_xtalk_margin_kcps( + VL53L1_DEV Dev, + int16_t *pxtalk_margin); + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_histogram_xtalk_margin_kcps( + VL53L1_DEV Dev, + int16_t xtalk_margin); + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_histogram_phase_consistency( + VL53L1_DEV Dev, + uint8_t *pphase_consistency); + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_histogram_phase_consistency( + VL53L1_DEV Dev, + uint8_t phase_consistency); + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_histogram_event_consistency( + VL53L1_DEV Dev, + uint8_t *pevent_consistency); + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_histogram_event_consistency( + VL53L1_DEV Dev, + uint8_t event_consistency); + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_histogram_ambient_threshold_sigma( + VL53L1_DEV Dev, + uint8_t *pamb_thresh_sigma); + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_histogram_ambient_threshold_sigma( + VL53L1_DEV Dev, + uint8_t amb_thresh_sigma); + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_lite_min_count_rate( + VL53L1_DEV Dev, + uint16_t *plite_mincountrate); + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_lite_min_count_rate( + VL53L1_DEV Dev, + uint16_t lite_mincountrate); + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_lite_sigma_threshold( + VL53L1_DEV Dev, + uint16_t *plite_sigma); + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_lite_sigma_threshold( + VL53L1_DEV Dev, + uint16_t lite_sigma); + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_restore_xtalk_nvm_default( + VL53L1_DEV Dev); + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_xtalk_detect_config( + VL53L1_DEV Dev, + int16_t *pmax_valid_range_mm, + int16_t *pmin_valid_range_mm, + uint16_t *pmax_valid_rate_kcps, + uint16_t *pmax_sigma_mm); + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_xtalk_detect_config( + VL53L1_DEV Dev, + int16_t max_valid_range_mm, + int16_t min_valid_range_mm, + uint16_t max_valid_rate_kcps, + uint16_t max_sigma_mm); + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_target_order_mode( + VL53L1_DEV Dev, + VL53L1_HistTargetOrder *phist_target_order); + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_target_order_mode( + VL53L1_DEV Dev, + VL53L1_HistTargetOrder hist_target_order); + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_dmax_reflectance_values( + VL53L1_DEV Dev, + VL53L1_dmax_reflectance_array_t *pdmax_reflectances); + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_dmax_reflectance_values( + VL53L1_DEV Dev, + VL53L1_dmax_reflectance_array_t *pdmax_reflectances); + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_vhv_config( + VL53L1_DEV Dev, + uint8_t vhv_init_en, + uint8_t vhv_init_value); + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_vhv_config( + VL53L1_DEV Dev, + uint8_t *pvhv_init_en, + uint8_t *pvhv_init_value); + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_vhv_loopbound( + VL53L1_DEV Dev, + uint8_t vhv_loopbound); + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_vhv_loopbound( + VL53L1_DEV Dev, + uint8_t *pvhv_loopbound); + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_tuning_parm( + VL53L1_DEV Dev, + VL53L1_TuningParms tuning_parm_key, + int32_t *ptuning_parm_value); + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_tuning_parm( + VL53L1_DEV Dev, + VL53L1_TuningParms tuning_parm_key, + int32_t tuning_parm_value); + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_dynamic_xtalk_correction_enable( + VL53L1_DEV Dev + ); + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_dynamic_xtalk_correction_disable( + VL53L1_DEV Dev + ); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_dynamic_xtalk_correction_apply_enable( + VL53L1_DEV Dev + ); + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_dynamic_xtalk_correction_apply_disable( + VL53L1_DEV Dev + ); + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_dynamic_xtalk_correction_single_apply_enable( + VL53L1_DEV Dev + ); + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_dynamic_xtalk_correction_single_apply_disable( + VL53L1_DEV Dev + ); + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_dynamic_xtalk_correction_set_scalers( + VL53L1_DEV Dev, + int16_t x_scaler_in, + int16_t y_scaler_in, + uint8_t user_scaler_set_in + ); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_current_xtalk_settings( + VL53L1_DEV Dev, + VL53L1_xtalk_calibration_results_t *pxtalk + ); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_current_xtalk_settings( + VL53L1_DEV Dev, + VL53L1_xtalk_calibration_results_t *pxtalk + ); + +VL53L1_Error VL53L1_load_patch(VL53L1_DEV Dev); + +VL53L1_Error VL53L1_unload_patch(VL53L1_DEV Dev); + +#ifdef __cplusplus +} +#endif + +#endif + + diff --git a/drivers/input/misc/vl53L1/kona/inc/vl53l1_api_debug.h b/drivers/input/misc/vl53L1/kona/inc/vl53l1_api_debug.h new file mode 100644 index 000000000000..f7161fbcd849 --- /dev/null +++ b/drivers/input/misc/vl53L1/kona/inc/vl53l1_api_debug.h @@ -0,0 +1,756 @@ + +/******************************************************************************* + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#ifndef _VL53L1_API_DEBUG_H_ +#define _VL53L1_API_DEBUG_H_ + +#include "vl53l1_platform.h" +#include "vl53l1_nvm_structs.h" + +#ifdef __cplusplus +extern "C" { +#endif + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_decode_calibration_data_buffer( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_calibration_data_t *pdata); + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_nvm_debug_data( + VL53L1_DEV Dev, + VL53L1_decoded_nvm_data_t *pdata); + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_histogram_debug_data( + VL53L1_DEV Dev, + VL53L1_histogram_bin_data_t *pdata); + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_additional_data( + VL53L1_DEV Dev, + VL53L1_additional_data_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_xtalk_debug_data( + VL53L1_DEV Dev, + VL53L1_xtalk_debug_data_t *pdata); + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_offset_debug_data( + VL53L1_DEV Dev, + VL53L1_offset_debug_data_t *pdata); + +#ifdef VL53L1_LOG_ENABLE + + + + + + + + + + + + +void VL53L1_signed_fixed_point_sprintf( + int32_t fp_value, + uint8_t frac_bits, + uint16_t buf_size, + char *pbuffer); + + + + + + + + + + + + +void VL53L1_print_static_nvm_managed( + VL53L1_static_nvm_managed_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + + + + + + + + + +void VL53L1_print_customer_nvm_managed( + VL53L1_customer_nvm_managed_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + + + + + + + + +void VL53L1_print_nvm_copy_data( + VL53L1_nvm_copy_data_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + + + + + + + + + +void VL53L1_print_histogram_bin_data( + VL53L1_histogram_bin_data_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + + + + + + + + + +void VL53L1_print_xtalk_histogram_data( + VL53L1_xtalk_histogram_data_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + + + + + + + + + +void VL53L1_print_xtalk_histogram_shape_data( + VL53L1_xtalk_histogram_shape_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + + + + + + + + + +void VL53L1_print_range_results( + VL53L1_range_results_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + + + + + + + + +void VL53L1_print_range_data( + VL53L1_range_data_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + + + + + + + + + + +void VL53L1_print_offset_range_results( + VL53L1_offset_range_results_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + + + + + + + + + +void VL53L1_print_offset_range_data( + VL53L1_offset_range_data_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + + + + + + + + + +void VL53L1_print_cal_peak_rate_map( + VL53L1_cal_peak_rate_map_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + + + + + + + + + + +void VL53L1_print_additional_offset_cal_data( + VL53L1_additional_offset_cal_data_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + + + + + + + + +void VL53L1_print_additional_data( + VL53L1_additional_data_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + + + + + + + + + + +void VL53L1_print_gain_calibration_data( + VL53L1_gain_calibration_data_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + + + + + + + + + + +void VL53L1_print_zone_calibration_data( + VL53L1_zone_calibration_data_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + + + + + + + + + + +void VL53L1_print_zone_calibration_results( + VL53L1_zone_calibration_results_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + + + + + + + + + +void VL53L1_print_xtalk_range_results( + VL53L1_xtalk_range_results_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + + + + + + + + + +void VL53L1_print_xtalk_range_data( + VL53L1_xtalk_range_data_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + + + + + + + + + + +void VL53L1_print_xtalk_calibration_results( + VL53L1_xtalk_calibration_results_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + + + + + + + + + +void VL53L1_print_xtalk_config( + VL53L1_xtalk_config_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + + + + + + + + +void VL53L1_print_xtalk_extract_config( + VL53L1_xtalkextract_config_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + + + + + + + + +void VL53L1_print_zone_cal_config( + VL53L1_zonecal_config_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + + + + + + + + +void VL53L1_print_offset_cal_config( + VL53L1_offsetcal_config_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + + + + + + + + + +void VL53L1_print_dmax_calibration_data( + VL53L1_dmax_calibration_data_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + + + + + + + + + +void VL53L1_print_calibration_data( + VL53L1_calibration_data_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + + + + + + + + + +void VL53L1_print_xtalk_debug_data( + VL53L1_xtalk_debug_data_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + + + + + + + + +void VL53L1_print_offset_debug_data( + VL53L1_offset_debug_data_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + + + + + + + + + +void VL53L1_print_optical_centre( + VL53L1_optical_centre_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + + + + + + + + + +void VL53L1_print_user_zone( + VL53L1_user_zone_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + + + + + + + + +void VL53L1_print_zone_config( + VL53L1_zone_config_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + + + + + + + + +void VL53L1_print_spad_rate_data( + VL53L1_spad_rate_data_t *pspad_rates, + char *pprefix, + uint32_t trace_flags); + + + + + + + + + + + +void VL53L1_print_spad_rate_map( + VL53L1_spad_rate_data_t *pspad_rates, + char *pprefix, + uint32_t trace_flags); + + +#endif + + +#ifdef __cplusplus +} +#endif + +#endif + + diff --git a/drivers/input/misc/vl53L1/kona/inc/vl53l1_api_preset_modes.h b/drivers/input/misc/vl53L1/kona/inc/vl53l1_api_preset_modes.h new file mode 100644 index 000000000000..3126bae2f85e --- /dev/null +++ b/drivers/input/misc/vl53L1/kona/inc/vl53l1_api_preset_modes.h @@ -0,0 +1,1637 @@ + +/******************************************************************************* + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#ifndef _VL53L1_API_PRESET_MODES_H_ +#define _VL53L1_API_PRESET_MODES_H_ + +#include "vl53l1_ll_def.h" +#include "vl53l1_dmax_structs.h" + +#ifdef __cplusplus +extern "C" { +#endif + + + + + + + + + + + + + +VL53L1_Error VL53L1_init_refspadchar_config_struct( + VL53L1_refspadchar_config_t *pdata); + + + + + + + + + + + + +VL53L1_Error VL53L1_init_ssc_config_struct( + VL53L1_ssc_config_t *pdata); + + + + + + + + + + + + + + +VL53L1_Error VL53L1_init_xtalk_config_struct( + VL53L1_customer_nvm_managed_t *pnvm, + VL53L1_xtalk_config_t *pdata); + + + + + + + + + + + + +VL53L1_Error VL53L1_init_xtalk_extract_config_struct( + VL53L1_xtalkextract_config_t *pdata); + + + + + + + + + + + +VL53L1_Error VL53L1_init_offset_cal_config_struct( + VL53L1_offsetcal_config_t *pdata); + + + + + + + + + + + +VL53L1_Error VL53L1_init_zone_cal_config_struct( + VL53L1_zonecal_config_t *pdata); + + + + + + + + + + + + + + +VL53L1_Error VL53L1_init_hist_post_process_config_struct( + uint8_t xtalk_compensation_enable, + VL53L1_hist_post_process_config_t *pdata); + + + + + + + + + + + + + +VL53L1_Error VL53L1_init_dmax_calibration_data_struct( + VL53L1_dmax_calibration_data_t *pdata); + + + + + + + + + + + + + +VL53L1_Error VL53L1_init_tuning_parm_storage_struct( + VL53L1_tuning_parm_storage_t *pdata); + + + + + + + + + + + + +VL53L1_Error VL53L1_init_hist_gen3_dmax_config_struct( + VL53L1_hist_gen3_dmax_config_t *pdata); + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_preset_mode_standard_ranging( + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_preset_mode_standard_ranging_short_range( + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_preset_mode_standard_ranging_long_range( + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_preset_mode_standard_ranging_mm1_cal( + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_preset_mode_standard_ranging_mm2_cal( + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_preset_mode_timed_ranging( + + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_preset_mode_timed_ranging_short_range( + + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_preset_mode_timed_ranging_long_range( + + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_preset_mode_low_power_auto_ranging( + + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg, + VL53L1_low_power_auto_data_t *plpadata); + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_preset_mode_low_power_auto_short_ranging( + + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg, + VL53L1_low_power_auto_data_t *plpadata); + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_preset_mode_low_power_auto_long_ranging( + + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg, + VL53L1_low_power_auto_data_t *plpadata); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_preset_mode_histogram_ranging( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_preset_mode_histogram_ranging_with_mm1( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_preset_mode_histogram_ranging_with_mm2( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_preset_mode_histogram_ranging_mm1_cal( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_preset_mode_histogram_ranging_mm2_cal( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_preset_mode_histogram_ranging_ref( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_preset_mode_histogram_characterisation( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_preset_mode_histogram_xtalk_planar( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_preset_mode_histogram_xtalk_mm1( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_preset_mode_histogram_xtalk_mm2( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_preset_mode_histogram_multizone( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_preset_mode_histogram_multizone_short_range( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_preset_mode_histogram_multizone_long_range( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_preset_mode_histogram_ranging_short_timing( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_preset_mode_histogram_long_range( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_preset_mode_histogram_medium_range( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_preset_mode_histogram_short_range( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_preset_mode_special_histogram_short_range( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_preset_mode_histogram_long_range_mm1( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_preset_mode_histogram_long_range_mm2( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_preset_mode_histogram_medium_range_mm1( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_preset_mode_histogram_medium_range_mm2( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_preset_mode_histogram_short_range_mm1( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_preset_mode_histogram_short_range_mm2( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_preset_mode_olt( + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_preset_mode_singleshot_ranging( + + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + + + + + + + + + + + + + + + +void VL53L1_copy_hist_cfg_to_static_cfg( + VL53L1_histogram_config_t *phistogram, + VL53L1_static_config_t *pstatic, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic); + + + + + + + + + + + + + + +void VL53L1_copy_hist_bins_to_static_cfg( + VL53L1_histogram_config_t *phistogram, + VL53L1_static_config_t *pstatic, + VL53L1_timing_config_t *ptiming); + +#ifdef __cplusplus +} +#endif + +#endif + + diff --git a/drivers/input/misc/vl53L1/kona/inc/vl53l1_api_strings.h b/drivers/input/misc/vl53L1/kona/inc/vl53l1_api_strings.h new file mode 100644 index 000000000000..051fcb2b000c --- /dev/null +++ b/drivers/input/misc/vl53L1/kona/inc/vl53l1_api_strings.h @@ -0,0 +1,210 @@ + +/****************************************************************************** + * Copyright (c) 2017, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + + ****************************************************************************** + + 'STMicroelectronics Proprietary license' + + ******************************************************************************* + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + + ******************************************************************************* + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones mentioned above : + + ******************************************************************************* + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + ******************************************************************************* + */ + +/** + * @file vl53l1_api_strings.h + * @brief VL53L1 API function declarations for decoding error codes to a + * text strings + */ + + +#ifndef VL53L1_API_STRINGS_H_ +#define VL53L1_API_STRINGS_H_ + +#include "vl53l1_def.h" + +#ifdef __cplusplus +extern "C" { +#endif + + + +/** + * @brief Generates a string for the input device range status code + * + * @param[in] RangeStatus : Device Range AStatus Code + * @param[out] pRangeStatusString : pointer to character buffer + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_get_range_status_string( + uint8_t RangeStatus, + char *pRangeStatusString); + +/** + * @brief Generates an error string for the input PAL error code + * + * @param[in] PalErrorCode : PAL Error Code + * @param[out] pPalErrorString : pointer to character buffer + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_get_pal_error_string( + VL53L1_Error PalErrorCode, + char *pPalErrorString); + +/** + * @brief Generates a string for the input PAL State code + * + * @param[in] PalStateCode : PAL State Code + * @param[out] pPalStateString : pointer to character buffer + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_get_pal_state_string( + VL53L1_State PalStateCode, + char *pPalStateString); + + +/** + * @brief Generates a string for the sequence step Id + * + * @param[in] SequenceStepId : Sequence Step Id + * @param[out] pSequenceStepsString : pointer to character buffer + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_get_sequence_steps_info( + VL53L1_SequenceStepId SequenceStepId, + char *pSequenceStepsString); + +/** + * @brief Generates a string for the limit check Id + * + * @param[in] LimitCheckId : Limit check Id + * @param[out] pLimitCheckString : pointer to character buffer + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_get_limit_check_info(uint16_t LimitCheckId, + char *pLimitCheckString); + +#ifndef VL53L1_USE_EMPTY_STRING + #define VL53L1_STRING_DEVICE_INFO_NAME0 "VL53L1 cut1.0" + #define VL53L1_STRING_DEVICE_INFO_NAME1 "VL53L1 cut1.1" + #define VL53L1_STRING_DEVICE_INFO_TYPE "VL53L1" + + /* Range Status */ + #define VL53L1_STRING_RANGESTATUS_NONE "No Update" + #define VL53L1_STRING_RANGESTATUS_RANGEVALID "Range Valid" + #define VL53L1_STRING_RANGESTATUS_SIGMA "Sigma Fail" + #define VL53L1_STRING_RANGESTATUS_SIGNAL "Signal Fail" + #define VL53L1_STRING_RANGESTATUS_MINRANGE "Min Range Fail" + #define VL53L1_STRING_RANGESTATUS_PHASE "Phase Fail" + #define VL53L1_STRING_RANGESTATUS_HW "Hardware Fail" + + + /* Range Status */ + #define VL53L1_STRING_STATE_POWERDOWN "POWERDOWN State" + #define VL53L1_STRING_STATE_WAIT_STATICINIT \ + "Wait for staticinit State" + #define VL53L1_STRING_STATE_STANDBY "STANDBY State" + #define VL53L1_STRING_STATE_IDLE "IDLE State" + #define VL53L1_STRING_STATE_RUNNING "RUNNING State" + #define VL53L1_STRING_STATE_RESET "RESET State" + #define VL53L1_STRING_STATE_UNKNOWN "UNKNOWN State" + #define VL53L1_STRING_STATE_ERROR "ERROR State" + + + + /* Check Enable */ + #define VL53L1_STRING_CHECKENABLE_SIGMA_FINAL_RANGE \ + "SIGMA FINAL RANGE" + #define VL53L1_STRING_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE \ + "SIGNAL RATE FINAL RANGE" + #define VL53L1_STRING_CHECKENABLE_SIGNAL_MIN_CLIP \ + "SIGNAL MIN CLIP" + #define VL53L1_STRING_CHECKENABLE_RANGE_IGNORE_THRESHOLD \ + "RANGE IGNORE THRESHOLD" + #define VL53L1_STRING_CHECKENABLE_RANGE_PHASE_HIGH \ + "RANGE PHASE HIGH" + #define VL53L1_STRING_CHECKENABLE_RANGE_PHASE_LOW \ + "RANGE PHASE LOW" + #define VL53L1_STRING_CHECKENABLE_RANGE_PHASE_CONSISTENCY \ + "RANGE PHASE CONSISTENCY" + + /* Sequence Step */ + #define VL53L1_STRING_SEQUENCESTEP_VHV "VHV" + #define VL53L1_STRING_SEQUENCESTEP_PHASECAL "PHASE CAL" + #define VL53L1_STRING_SEQUENCESTEP_REFPHASE "REF PHASE" + #define VL53L1_STRING_SEQUENCESTEP_DSS1 "DSS1" + #define VL53L1_STRING_SEQUENCESTEP_DSS2 "DSS2" + #define VL53L1_STRING_SEQUENCESTEP_MM1 "MM1" + #define VL53L1_STRING_SEQUENCESTEP_MM2 "MM2" + #define VL53L1_STRING_SEQUENCESTEP_RANGE "RANGE" +#endif /* VL53L1_USE_EMPTY_STRING */ + + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/drivers/input/misc/vl53L1/kona/inc/vl53l1_core.h b/drivers/input/misc/vl53L1/kona/inc/vl53l1_core.h new file mode 100644 index 000000000000..c6b2e6e634a9 --- /dev/null +++ b/drivers/input/misc/vl53L1/kona/inc/vl53l1_core.h @@ -0,0 +1,1926 @@ + +/******************************************************************************* + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#ifndef _VL53L1_CORE_H_ +#define _VL53L1_CORE_H_ + +#include "vl53l1_platform.h" +#include "vl53l1_core_support.h" + +#ifdef __cplusplus +extern "C" { +#endif + + + + + + + + + +void VL53L1_init_version( + VL53L1_DEV Dev); + + + + + + + + + + +void VL53L1_init_ll_driver_state( + VL53L1_DEV Dev, + VL53L1_DeviceState ll_state); + + + + + + + + + + + + +VL53L1_Error VL53L1_update_ll_driver_rd_state( + VL53L1_DEV Dev); + + + + + + + + + + + + + +VL53L1_Error VL53L1_check_ll_driver_rd_state( + VL53L1_DEV Dev); + + + + + + + + + + + + +VL53L1_Error VL53L1_update_ll_driver_cfg_state( + VL53L1_DEV Dev); + + + + + + + + + + +void VL53L1_copy_rtn_good_spads_to_buffer( + VL53L1_nvm_copy_data_t *pdata, + uint8_t *pbuffer); + + + + + + + + + + + + +void VL53L1_init_system_results( + VL53L1_system_results_t *pdata); + + + + + + + + + + +void V53L1_init_zone_results_structure( + uint8_t active_zones, + VL53L1_zone_results_t *pdata); + + + + + + + + + +void V53L1_init_zone_dss_configs( + VL53L1_DEV Dev); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +void VL53L1_init_histogram_config_structure( + uint8_t even_bin0, + uint8_t even_bin1, + uint8_t even_bin2, + uint8_t even_bin3, + uint8_t even_bin4, + uint8_t even_bin5, + uint8_t odd_bin0, + uint8_t odd_bin1, + uint8_t odd_bin2, + uint8_t odd_bin3, + uint8_t odd_bin4, + uint8_t odd_bin5, + VL53L1_histogram_config_t *pdata); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +void VL53L1_init_histogram_multizone_config_structure( + uint8_t even_bin0, + uint8_t even_bin1, + uint8_t even_bin2, + uint8_t even_bin3, + uint8_t even_bin4, + uint8_t even_bin5, + uint8_t odd_bin0, + uint8_t odd_bin1, + uint8_t odd_bin2, + uint8_t odd_bin3, + uint8_t odd_bin4, + uint8_t odd_bin5, + VL53L1_histogram_config_t *pdata); + + + + + + + + + + + +void VL53L1_init_xtalk_bin_data_struct( + uint32_t bin_value, + uint16_t VL53L1_p_024, + VL53L1_xtalk_histogram_shape_t *pdata); + + + + + + + + + + + + + +void VL53L1_i2c_encode_uint16_t( + uint16_t ip_value, + uint16_t count, + uint8_t *pbuffer); + + + + + + + + + + + + + + +uint16_t VL53L1_i2c_decode_uint16_t( + uint16_t count, + uint8_t *pbuffer); + + + + + + + + + + + + + +void VL53L1_i2c_encode_int16_t( + int16_t ip_value, + uint16_t count, + uint8_t *pbuffer); + + + + + + + + + + + + + + +int16_t VL53L1_i2c_decode_int16_t( + uint16_t count, + uint8_t *pbuffer); + + + + + + + + + + + + + +void VL53L1_i2c_encode_uint32_t( + uint32_t ip_value, + uint16_t count, + uint8_t *pbuffer); + + + + + + + + + + + + + + +uint32_t VL53L1_i2c_decode_uint32_t( + uint16_t count, + uint8_t *pbuffer); + + + + + + + + + + + + + + + + + +uint32_t VL53L1_i2c_decode_with_mask( + uint16_t count, + uint8_t *pbuffer, + uint32_t bit_mask, + uint32_t down_shift, + uint32_t offset); + + + + + + + + + + + + + +void VL53L1_i2c_encode_int32_t( + int32_t ip_value, + uint16_t count, + uint8_t *pbuffer); + + + + + + + + + + + + + + +int32_t VL53L1_i2c_decode_int32_t( + uint16_t count, + uint8_t *pbuffer); + + + + + + + + + + + + + +VL53L1_Error VL53L1_start_test( + VL53L1_DEV Dev, + uint8_t test_mode__ctrl); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_firmware_enable_register( + VL53L1_DEV Dev, + uint8_t value); + + + + + + + + + + + + +VL53L1_Error VL53L1_enable_firmware( + VL53L1_DEV Dev); + + + + + + + + + + + + + + +VL53L1_Error VL53L1_disable_firmware( + VL53L1_DEV Dev); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_powerforce_register( + VL53L1_DEV Dev, + uint8_t value); + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_enable_powerforce( + VL53L1_DEV Dev); + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_disable_powerforce( + VL53L1_DEV Dev); + + + + + + + + + + + + + +VL53L1_Error VL53L1_clear_interrupt( + VL53L1_DEV Dev); + + + + + + + + + + + + + +VL53L1_Error VL53L1_force_shadow_stream_count_to_zero( + VL53L1_DEV Dev); + + + + + + + + + + + + + + + + + + + +uint32_t VL53L1_calc_macro_period_us( + uint16_t fast_osc_frequency, + uint8_t VL53L1_p_009); + + + + + + + + + + + + + + + + + + +uint16_t VL53L1_calc_range_ignore_threshold( + uint32_t central_rate, + int16_t x_gradient, + int16_t y_gradient, + uint8_t rate_mult); + + + + + + + + + + + + + +uint32_t VL53L1_calc_timeout_mclks( + uint32_t timeout_us, + uint32_t macro_period_us); + + + + + + + + + + + + +uint16_t VL53L1_calc_encoded_timeout( + uint32_t timeout_us, + uint32_t macro_period_us); + + + + + + + + + + + + + +uint32_t VL53L1_calc_timeout_us( + uint32_t timeout_mclks, + uint32_t macro_period_us); + + + + + + + + + + + + +uint32_t VL53L1_calc_decoded_timeout_us( + uint16_t timeout_encoded, + uint32_t macro_period_us); + + + + + + + + + + + +uint16_t VL53L1_encode_timeout( + uint32_t timeout_mclks); + + + + + + + + + + + + +uint32_t VL53L1_decode_timeout( + uint16_t encoded_timeout); + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_calc_timeout_register_values( + uint32_t phasecal_config_timeout_us, + uint32_t mm_config_timeout_us, + uint32_t range_config_timeout_us, + uint16_t fast_osc_frequency, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming); + + + + + + + + + + + + +uint8_t VL53L1_encode_vcsel_period( + uint8_t VL53L1_p_031); + + + + + + + + + + + + + + + +uint32_t VL53L1_decode_unsigned_integer( + uint8_t *pbuffer, + uint8_t no_of_bytes); + + + + + + + + + + + + +void VL53L1_encode_unsigned_integer( + uint32_t ip_value, + uint8_t no_of_bytes, + uint8_t *pbuffer); + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_hist_copy_and_scale_ambient_info( + VL53L1_zone_hist_info_t *pidata, + VL53L1_histogram_bin_data_t *podata); + + + + + + + + + + + + +void VL53L1_hist_get_bin_sequence_config( + VL53L1_DEV Dev, + VL53L1_histogram_bin_data_t *pdata); + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_hist_phase_consistency_check( + VL53L1_DEV Dev, + VL53L1_zone_hist_info_t *phist_prev, + VL53L1_zone_objects_t *prange_prev, + VL53L1_range_results_t *prange_curr); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_hist_events_consistency_check( + uint8_t event_sigma, + uint16_t min_effective_spad_count, + VL53L1_zone_hist_info_t *phist_prev, + VL53L1_object_data_t *prange_prev, + VL53L1_range_data_t *prange_curr, + int32_t *pevents_tolerance, + int32_t *pevents_delta, + VL53L1_DeviceError *prange_status); + + + + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_hist_merged_pulse_check( + int16_t min_max_tolerance_mm, + VL53L1_range_data_t *pdata, + VL53L1_DeviceError *prange_status); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_hist_xmonitor_consistency_check( + VL53L1_DEV Dev, + VL53L1_zone_hist_info_t *phist_prev, + VL53L1_zone_objects_t *prange_prev, + VL53L1_range_data_t *prange_curr); + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_hist_wrap_dmax( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_histogram_bin_data_t *pcurrent, + int16_t *pwrap_dmax_mm); + + + + + + + + + + + + + + + + + + + + + +void VL53L1_hist_combine_mm1_mm2_offsets( + int16_t mm1_offset_mm, + int16_t mm2_offset_mm, + uint8_t encoded_mm_roi_centre, + uint8_t encoded_mm_roi_size, + uint8_t encoded_zone_centre, + uint8_t encoded_zone_size, + VL53L1_additional_offset_cal_data_t *pcal_data, + uint8_t *pgood_spads, + uint16_t aperture_attenuation, + int16_t *prange_offset_mm); + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_hist_xtalk_extract_calc_window( + int16_t target_distance_mm, + uint16_t target_width_oversize, + VL53L1_histogram_bin_data_t *phist_bins, + VL53L1_hist_xtalk_extract_data_t *pxtalk_data); + + + + + + + + + + + + + + +VL53L1_Error VL53L1_hist_xtalk_extract_calc_event_sums( + VL53L1_histogram_bin_data_t *phist_bins, + VL53L1_hist_xtalk_extract_data_t *pxtalk_data); + + + + + + + + + + + + +VL53L1_Error VL53L1_hist_xtalk_extract_calc_rate_per_spad( + VL53L1_hist_xtalk_extract_data_t *pxtalk_data); + + + + + + + + + + + + + +VL53L1_Error VL53L1_hist_xtalk_extract_calc_shape( + VL53L1_hist_xtalk_extract_data_t *pxtalk_data, + VL53L1_xtalk_histogram_shape_t *pxtalk_shape); + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_hist_xtalk_shape_model( + uint16_t events_per_bin, + uint16_t pulse_centre, + uint16_t pulse_width, + VL53L1_xtalk_histogram_shape_t *pxtalk_shape); + + + + + + + + + + + + + + +uint16_t VL53L1_hist_xtalk_shape_model_interp( + uint16_t events_per_bin, + uint32_t phase_delta); + + + + + + + + + + + + + + + + + + +void VL53L1_spad_number_to_byte_bit_index( + uint8_t spad_number, + uint8_t *pbyte_index, + uint8_t *pbit_index, + uint8_t *pbit_mask); + + + + + + + + + + + + + +void VL53L1_encode_row_col( + uint8_t row, + uint8_t col, + uint8_t *pspad_number); + + + + + + + + + + + + +void VL53L1_decode_zone_size( + uint8_t encoded_xy_size, + uint8_t *pwidth, + uint8_t *pheight); + + + + + + + + + + + + +void VL53L1_encode_zone_size( + uint8_t width, + uint8_t height, + uint8_t *pencoded_xy_size); + + + + + + + + + + + + + + + + + +void VL53L1_decode_zone_limits( + uint8_t encoded_xy_centre, + uint8_t encoded_xy_size, + int16_t *px_ll, + int16_t *py_ll, + int16_t *px_ur, + int16_t *py_ur); + + + + + + + + + + + + +uint8_t VL53L1_is_aperture_location( + uint8_t row, + uint8_t col); + + + + + + + + + + + + + + + +void VL53L1_calc_max_effective_spads( + uint8_t encoded_zone_centre, + uint8_t encoded_zone_size, + uint8_t *pgood_spads, + uint16_t aperture_attenuation, + uint16_t *pmax_effective_spads); + + + + + + + + + + + + + + + + + + + +void VL53L1_calc_mm_effective_spads( + uint8_t encoded_mm_roi_centre, + uint8_t encoded_mm_roi_size, + uint8_t encoded_zone_centre, + uint8_t encoded_zone_size, + uint8_t *pgood_spads, + uint16_t aperture_attenuation, + uint16_t *pmm_inner_effective_spads, + uint16_t *pmm_outer_effective_spads); + + + + + + + + + + + + + + +void VL53L1_hist_copy_results_to_sys_and_core( + VL53L1_histogram_bin_data_t *pbins, + VL53L1_range_results_t *phist, + VL53L1_system_results_t *psys, + VL53L1_core_results_t *pcore); + + + + + + + + + + + + + + +VL53L1_Error VL53L1_sum_histogram_data( + VL53L1_histogram_bin_data_t *phist_input, + VL53L1_histogram_bin_data_t *phist_output); + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_avg_histogram_data( + uint8_t no_of_samples, + VL53L1_histogram_bin_data_t *phist_sum, + VL53L1_histogram_bin_data_t *phist_avg); + + + + + + + + + + + + + +VL53L1_Error VL53L1_save_cfg_data( + VL53L1_DEV Dev); + + + + + + + + + + + + + + +VL53L1_Error VL53L1_dynamic_zone_update( + VL53L1_DEV Dev, + VL53L1_range_results_t *presults); + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_update_internal_stream_counters( + VL53L1_DEV Dev, + uint8_t external_stream_count, + uint8_t *pinternal_stream_count, + uint8_t *pinternal_stream_count_val + ); + + + + + + + + + + + + +VL53L1_Error VL53L1_multizone_hist_bins_update( + VL53L1_DEV Dev); + + + + + + + +VL53L1_Error VL53L1_set_histogram_multizone_initial_bin_config( + VL53L1_zone_config_t *pzone_cfg, + VL53L1_histogram_config_t *phist_cfg, + VL53L1_histogram_config_t *pmulti_hist + ); + + + + + + + + + +uint8_t VL53L1_encode_GPIO_interrupt_config( + VL53L1_GPIO_interrupt_config_t *pintconf); + + + + + + + + + +VL53L1_GPIO_interrupt_config_t VL53L1_decode_GPIO_interrupt_config( + uint8_t system__interrupt_config); + + + + + + + + + + +VL53L1_Error VL53L1_set_GPIO_distance_threshold( + VL53L1_DEV Dev, + uint16_t threshold_high, + uint16_t threshold_low); + + + + + + + + + + +VL53L1_Error VL53L1_set_GPIO_rate_threshold( + VL53L1_DEV Dev, + uint16_t threshold_high, + uint16_t threshold_low); + + + + + + + + + + +VL53L1_Error VL53L1_set_GPIO_thresholds_from_struct( + VL53L1_DEV Dev, + VL53L1_GPIO_interrupt_config_t *pintconf); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_ref_spad_char_config( + VL53L1_DEV Dev, + uint8_t vcsel_period_a, + uint32_t phasecal_timeout_us, + uint16_t total_rate_target_mcps, + uint16_t max_count_rate_rtn_limit_mcps, + uint16_t min_count_rate_rtn_limit_mcps, + uint16_t fast_osc_frequency); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_ssc_config( + VL53L1_DEV Dev, + VL53L1_ssc_config_t *pssc_cfg, + uint16_t fast_osc_frequency); + + + + + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_spad_rate_data( + VL53L1_DEV Dev, + VL53L1_spad_rate_data_t *pspad_rates); + + + + + + + + + + + + + + + + +uint32_t VL53L1_calc_crosstalk_plane_offset_with_margin( + uint32_t plane_offset_kcps, + int16_t margin_offset_kcps); + + + + + + + + + + + + + +VL53L1_Error VL53L1_low_power_auto_data_init( + VL53L1_DEV Dev + ); + + + + + + + + + + + + + +VL53L1_Error VL53L1_low_power_auto_data_stop_range( + VL53L1_DEV Dev + ); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_dynamic_xtalk_correction_calc_required_samples( + VL53L1_DEV Dev + ); + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_dynamic_xtalk_correction_calc_new_xtalk( + VL53L1_DEV Dev, + uint32_t xtalk_offset_out, + VL53L1_smudge_corrector_config_t *pconfig, + VL53L1_smudge_corrector_data_t *pout, + uint8_t add_smudge, + uint8_t soft_update + ); + + + + + + + + + + + + + +VL53L1_Error VL53L1_dynamic_xtalk_correction_corrector( + VL53L1_DEV Dev + ); + + + + + + + + + + + + + + +VL53L1_Error VL53L1_dynamic_xtalk_correction_data_init( + VL53L1_DEV Dev + ); + + + + + + + + + + + + + +VL53L1_Error VL53L1_dynamic_xtalk_correction_output_init( + VL53L1_LLDriverResults_t *pres + ); + + + + + + + + + + + + + +VL53L1_Error VL53L1_xtalk_cal_data_init( + VL53L1_DEV Dev + ); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_config_low_power_auto_mode( + VL53L1_general_config_t *pgeneral, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_low_power_auto_data_t *plpadata + ); + + + + + + + + + + + + + + +VL53L1_Error VL53L1_low_power_auto_setup_manual_calibration( + VL53L1_DEV Dev); + + + + + + + + + + + + + +VL53L1_Error VL53L1_low_power_auto_update_DSS( + VL53L1_DEV Dev); + + + + + +VL53L1_Error VL53L1_compute_histo_merge_nb( + VL53L1_DEV Dev, uint8_t *histo_merge_nb); + +#ifdef __cplusplus +} +#endif + +#endif + + diff --git a/drivers/input/misc/vl53L1/kona/inc/vl53l1_core_support.h b/drivers/input/misc/vl53L1/kona/inc/vl53l1_core_support.h new file mode 100644 index 000000000000..3cc76a2de52c --- /dev/null +++ b/drivers/input/misc/vl53L1/kona/inc/vl53l1_core_support.h @@ -0,0 +1,414 @@ + +/******************************************************************************* + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#ifndef _VL53L1_CORE_SUPPORT_H_ +#define _VL53L1_CORE_SUPPORT_H_ + +#include "vl53l1_types.h" +#include "vl53l1_hist_structs.h" + +#ifdef __cplusplus +extern "C" { +#endif + + + + + + + + + + + + +uint32_t VL53L1_calc_pll_period_us( + uint16_t fast_osc_frequency); + + + + + + + + + + + + + + + + + + +uint32_t VL53L1_duration_maths( + uint32_t pll_period_us, + uint32_t vcsel_parm_pclks, + uint32_t window_vclks, + uint32_t periods_elapsed_mclks); + + + + + + + + + + + + + + + + +uint32_t VL53L1_events_per_spad_maths( + int32_t VL53L1_p_013, + uint16_t num_spads, + uint32_t duration); + + + + + + + + + + + + + +uint32_t VL53L1_isqrt( + uint32_t num); + + + + + + + + + + +void VL53L1_hist_calc_zero_distance_phase( + VL53L1_histogram_bin_data_t *pdata); + + + + + + + + + + + + + + + + + + + +void VL53L1_hist_estimate_ambient_from_thresholded_bins( + int32_t ambient_threshold_sigma, + VL53L1_histogram_bin_data_t *pdata); + + + + + + + + + + + + + +void VL53L1_hist_remove_ambient_bins( + VL53L1_histogram_bin_data_t *pdata); + + + + + + + + + + + + + + +uint32_t VL53L1_calc_pll_period_mm( + uint16_t fast_osc_frequency); + + + + + + + + + + + + + + + +uint16_t VL53L1_rate_maths( + int32_t VL53L1_p_008, + uint32_t time_us); + + + + + + + + + + + + + + + + + + +uint16_t VL53L1_rate_per_spad_maths( + uint32_t frac_bits, + uint32_t peak_count_rate, + uint16_t num_spads, + uint32_t max_output_value); + + + + + + + + + + + + + + + + + + + +int32_t VL53L1_range_maths( + uint16_t fast_osc_frequency, + uint16_t VL53L1_p_017, + uint16_t zero_distance_phase, + uint8_t fractional_bits, + int32_t gain_factor, + int32_t range_offset_mm); + + + + + + + + + + + + +uint8_t VL53L1_decode_vcsel_period( + uint8_t vcsel_period_reg); + + + + + + + + + + + +void VL53L1_copy_xtalk_bin_data_to_histogram_data_struct( + VL53L1_xtalk_histogram_shape_t *pxtalk, + VL53L1_histogram_bin_data_t *phist); + + + + + + + + + + + +void VL53L1_init_histogram_bin_data_struct( + int32_t bin_value, + uint16_t VL53L1_p_024, + VL53L1_histogram_bin_data_t *pdata); + + + + + + + + + + + + +void VL53L1_decode_row_col( + uint8_t spad_number, + uint8_t *prow, + uint8_t *pcol); + + + + + + + + + + + + + + + +void VL53L1_hist_find_min_max_bin_values( + VL53L1_histogram_bin_data_t *pdata); + + + + + + + + + + + + + + + +void VL53L1_hist_estimate_ambient_from_ambient_bins( + VL53L1_histogram_bin_data_t *pdata); + + +#ifdef __cplusplus +} +#endif + +#endif + + diff --git a/drivers/input/misc/vl53L1/kona/inc/vl53l1_def.h b/drivers/input/misc/vl53L1/kona/inc/vl53l1_def.h new file mode 100644 index 000000000000..0560050cba2e --- /dev/null +++ b/drivers/input/misc/vl53L1/kona/inc/vl53l1_def.h @@ -0,0 +1,852 @@ +/****************************************************************************** + * Copyright (c) 2017, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + + ****************************************************************************** + + 'STMicroelectronics Proprietary license' + + ******************************************************************************* + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + + ******************************************************************************* + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones mentioned above : + + ******************************************************************************* + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + ******************************************************************************* + */ + +/** + * @file vl53l1_def.h + * + * @brief Type definitions for VL53L1 API. + * + */ + + +#ifndef _VL53L1_DEF_H_ +#define _VL53L1_DEF_H_ + +#include "vl53l1_ll_def.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** @defgroup VL53L1_globaldefine_group VL53L1 Defines + * @brief VL53L1 Defines + * @{ + */ + + +/** VL53L1 IMPLEMENTATION major version */ +#define VL53L1_IMPLEMENTATION_VER_MAJOR 6 +/** VL53L1 IMPLEMENTATION minor version */ +#define VL53L1_IMPLEMENTATION_VER_MINOR 4 +/** VL53L1 IMPLEMENTATION sub version */ +#define VL53L1_IMPLEMENTATION_VER_SUB 2 +/** VL53L1 IMPLEMENTATION sub version */ +#define VL53L1_IMPLEMENTATION_VER_REVISION 2365 + +/**************************************** + * PRIVATE define do not edit + ****************************************/ + +/** @brief Defines the parameters of the Get Version Functions + */ +typedef struct { + uint32_t revision; /*!< revision number */ + uint8_t major; /*!< major number */ + uint8_t minor; /*!< minor number */ + uint8_t build; /*!< build number */ +} VL53L1_Version_t; + + +#define VL53L1_DEVINFO_STRLEN 32 + +/** @brief Defines the parameters of the Get Device Info Functions + */ +typedef struct { + char Name[VL53L1_DEVINFO_STRLEN]; + /*!< Full Name of the Device e.g. VL53L1 cut1.1 */ + char Type[VL53L1_DEVINFO_STRLEN]; + /*!< Type of the Device e.g VL53L1 */ + char ProductId[VL53L1_DEVINFO_STRLEN]; + /*!< Product Identifier String + * @warning Not yet implemented + */ + uint8_t ProductType; + /*!< Product Type, VL53L1 = 0xCC, VL53L3 = 0xAA + * Stands as module_type in the datasheet + */ + uint8_t ProductRevisionMajor; + /*!< Product revision major */ + uint8_t ProductRevisionMinor; + /*!< Product revision minor */ +} VL53L1_DeviceInfo_t; + + + +/** @defgroup VL53L1_define_PresetModes_group Defines Preset modes + * Defines all possible preset modes for the device + * @{ + */ +typedef uint8_t VL53L1_PresetModes; + +#define VL53L1_PRESETMODE_RANGING ((VL53L1_PresetModes) 1) +#define VL53L1_PRESETMODE_MULTIZONES_SCANNING ((VL53L1_PresetModes) 2) +#define VL53L1_PRESETMODE_AUTONOMOUS ((VL53L1_PresetModes) 3) +#define VL53L1_PRESETMODE_LITE_RANGING ((VL53L1_PresetModes) 4) +#define VL53L1_PRESETMODE_OLT ((VL53L1_PresetModes) 7) +#define VL53L1_PRESETMODE_LOWPOWER_AUTONOMOUS ((VL53L1_PresetModes) 8) +#define VL53L1_PRESETMODE_PROXY_RANGING_MODE ((VL53L1_PresetModes) 9) + +/** default preset ranging mode */ +//songyt test replace VL53L1_PRESETMODE_RANGING +#define STMVL53L1_CFG_DEFAULT_MODE VL53L1_PRESETMODE_RANGING + + /* ... Modes to be added depending on device */ +/** @} VL53L1_define_PresetModes_group */ + + +/** @defgroup VL53L1_define_DistanceModes_group Defines Distance modes + * Defines all possible Distance modes for the device + * @{ + */ +typedef uint8_t VL53L1_DistanceModes; + +#define VL53L1_DISTANCEMODE_SHORT ((VL53L1_DistanceModes) 1) +#define VL53L1_DISTANCEMODE_MEDIUM ((VL53L1_DistanceModes) 2) +#define VL53L1_DISTANCEMODE_LONG ((VL53L1_DistanceModes) 3) +/** @} VL53L1_define_DistanceModes_group */ + +/** @defgroup VL53L1_define_OutputModes_group Defines Output modes + * Defines all possible Output modes for the device + * @{ + */ +typedef uint8_t VL53L1_OutputModes; + +#define VL53L1_OUTPUTMODE_NEAREST ((VL53L1_OutputModes) 1) +#define VL53L1_OUTPUTMODE_STRONGEST ((VL53L1_OutputModes) 2) + +/** @} VL53L1_define_OutputModes_group */ + +/** @defgroup VL53L1_define_XtalkCal_group Defines Xtalk Calibration modes + * Defines all possible Offset Calibration modes for the device + * @{ + */ +typedef uint8_t VL53L1_XtalkCalibrationModes; + +#define VL53L1_XTALKCALIBRATIONMODE_NO_TARGET \ + ((VL53L1_OffsetCalibrationModes) 0) +/*!< To perform Xtalk calibration with no target below 80 cm */ +#define VL53L1_XTALKCALIBRATIONMODE_SINGLE_TARGET \ + ((VL53L1_OffsetCalibrationModes) 1) +/*!< To perform Xtalk calibration with one target */ +#define VL53L1_XTALKCALIBRATIONMODE_FULL_ROI \ + ((VL53L1_OffsetCalibrationModes) 2) +/*!< To perform Xtalk calibration based on histogram with full ROI */ + +/** @} VL53L1_define_XtalkCal_group */ + +/** @defgroup VL53L1_define_OffsetCal_group Defines Offset Calibration modes + * Defines all possible Offset Calibration modes for the device + * @{ + */ +typedef uint8_t VL53L1_OffsetCalibrationModes; + +#define VL53L1_OFFSETCALIBRATIONMODE_STANDARD \ + ((VL53L1_OffsetCalibrationModes) 1) +#define VL53L1_OFFSETCALIBRATIONMODE_PRERANGE_ONLY \ + ((VL53L1_OffsetCalibrationModes) 2) +#define VL53L1_OFFSETCALIBRATIONMODE_MULTI_ZONE \ + ((VL53L1_OffsetCalibrationModes) 3) + +/** @} VL53L1_define_OffsetCal_group */ + +/** @defgroup VL53L1_define_DeviceDmaxModes_group Defines Dmax source modes + * Defines all possible sources for Dmax calibration for the device + * @{ + */ +typedef uint8_t VL53L1_DeviceDmaxModes; + +#define VL53L1_DMAXMODE_FMT_CAL_DATA ((VL53L1_DeviceDmaxModes) 1) +#define VL53L1_DMAXMODE_CUSTCAL_DATA ((VL53L1_DeviceDmaxModes) 2) +#define VL53L1_DMAXMODE_PER_ZONE_CAL_DATA ((VL53L1_DeviceDmaxModes) 3) + +/** @} VL53L1_define_DeviceDmaxModes_group */ + +/** @defgroup VL53L1_define_OffsetCorrectionModesBD_group + * Device Offset Correction Mode + * + * @brief Defines all possible offset correction modes for the device + * @{ + */ +typedef uint8_t VL53L1_OffsetCorrectionModes; + +#define VL53L1_OFFSETCORRECTIONMODE_STANDARD ((VL53L1_OffsetCorrectionMode) 1) +#define VL53L1_OFFSETCORRECTIONMODE_PERZONE ((VL53L1_OffsetCorrectionMode) 2) +#define VL53L1_OFFSETCORRECTIONMODE_PERVCSEL ((VL53L1_OffsetCorrectionMode) 3) + +/** @} VL53L1_define_OffsetCorrectionModesBD_group */ + +/** @defgroup VL53L1_define_RoiStatus_group Defines Roi Status + * Defines the read status mode + * @{ + */ +typedef uint8_t VL53L1_RoiStatus; + +#define VL53L1_ROISTATUS_NOT_VALID ((VL53L1_RoiStatus) 0) +#define VL53L1_ROISTATUS_VALID_NOT_LAST ((VL53L1_RoiStatus) 1) +#define VL53L1_ROISTATUS_VALID_LAST ((VL53L1_RoiStatus) 2) +/** @} VL53L1_define_RoiStatus_group */ + + +/** @defgroup VL53L1_CheckEnable_group Check Enable list + * @brief Check Enable code + * + * Define used to specify the LimitCheckId. + * Use @a VL53L1_GetLimitCheckInfo() to get the string. + * @{ + */ + +#define VL53L1_CHECKENABLE_SIGMA_FINAL_RANGE 0 +#define VL53L1_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE 1 + +#define VL53L1_CHECKENABLE_NUMBER_OF_CHECKS 2 + +/** @} end of VL53L1_CheckEnable_group */ + + +/** @defgroup VL53L1_ThresholdMode_gropup Detection Functionality + * @brief Defines the different functionalities for the detection feature + * @{ + */ +typedef uint8_t VL53L1_ThresholdMode; + +#define VL53L1_THRESHOLD_CROSSED_LOW \ + ((VL53L1_ThresholdMode) 0) + /*!< Trigger interrupt if value < thresh_low */ +#define VL53L1_THRESHOLD_CROSSED_HIGH \ + ((VL53L1_ThresholdMode) 1) + /*!< Trigger interrupt if value > thresh_high */ +#define VL53L1_THRESHOLD_OUT_OF_WINDOW \ + ((VL53L1_ThresholdMode) 2) + /*!< Trigger interrupt if value < thresh_low OR value > thresh_high */ +#define VL53L1_THRESHOLD_IN_WINDOW \ + ((VL53L1_ThresholdMode) 3) + /*!< Trigger interrupt if value > thresh_low AND value < thresh_high */ + +/** @} end of VL53L1_ThresholdMode_gropup */ + +/** @brief Defines parameters for Distance detection Thresholds configuration + */ +typedef struct { + VL53L1_ThresholdMode CrossMode; + uint16_t High; /*!< Distance threshold high limit in mm */ + uint16_t Low; /*!< Distance threshold low limit in mm */ +} VL53L1_DistanceThreshold_t; + +/** @brief Defines parameters for Signal rate detection Thresholds configuration + */ +typedef struct { + VL53L1_ThresholdMode CrossMode; + FixPoint1616_t High; /*!< Signal rate threshold high limit */ + FixPoint1616_t Low; /*!< Signal rate threshold low limit */ +} VL53L1_RateThreshold_t; + +/** @defgroup VL53L1_DetectionMode_group Gpio Functionality + * @brief Defines conditions leading to device's IT on GPIO + * @{ + */ +typedef uint8_t VL53L1_DetectionMode; + +#define VL53L1_DETECTION_NORMAL_RUN \ + ((VL53L1_DetectionMode) 0) + /*!< Trigger interrupt on new measurement regardless of threshold + * just like after a VL53L1_SetPresetMode() call + */ +#define VL53L1_DETECTION_DISTANCE_ONLY \ + ((VL53L1_DetectionMode) 1) + /*!< Trigger interrupt if "threshold event" occurs on distance */ +#define VL53L1_DETECTION_RATE_ONLY \ + ((VL53L1_DetectionMode) 2) + /*!< Trigger interrupt if "threshold event" occurs on signal rate */ +#define VL53L1_DETECTION_DISTANCE_AND_RATE \ + ((VL53L1_DetectionMode) 3) + /*!< Trigger interrupt if "threshold event" occurs on distance AND rate + */ +#define VL53L1_DETECTION_DISTANCE_OR_RATE \ + ((VL53L1_DetectionMode) 4) + /*!< Trigger interrupt if "threshold event" occurs on distance OR rate + */ + +/** @} end of VL53L1_DetectionMode_group */ + +/** @brief Defines parameters for User/object Detection configuration + */ +typedef struct { + VL53L1_DetectionMode DetectionMode; /*!< See #VL53L1_DetectionMode*/ + uint8_t IntrNoTarget; /*!< 1 to trigger IT in case of no target found */ + VL53L1_DistanceThreshold_t Distance; /*!< limits in mm */ + VL53L1_RateThreshold_t Rate;/*!< limits in FixPoint1616_t */ +} VL53L1_DetectionConfig_t; + + +/** @brief Defines all parameters for the device + */ +typedef struct { + VL53L1_PresetModes PresetMode; + /*!< Defines the operating mode to be used for the next measure */ + VL53L1_OutputModes OutputMode; + /*!< Defines the Output mode to be used for the next measure */ + VL53L1_DistanceModes DistanceMode; + /*!< Defines the operating mode to be used for the next measure */ + uint32_t MeasurementTimingBudgetMicroSeconds; + /*!< Defines the allowed total time for a single measurement */ + uint8_t LimitChecksEnable[VL53L1_CHECKENABLE_NUMBER_OF_CHECKS]; + /*!< This Array store all the Limit Check enable for this device. */ + uint8_t LimitChecksStatus[VL53L1_CHECKENABLE_NUMBER_OF_CHECKS]; + /*!< This Array stores all the Status of the check linked to last + * measurement. + */ + FixPoint1616_t LimitChecksValue[VL53L1_CHECKENABLE_NUMBER_OF_CHECKS]; + /*!< This Array stores all the Limit Check value for this device */ + FixPoint1616_t LimitChecksCurrent[VL53L1_CHECKENABLE_NUMBER_OF_CHECKS]; + /*!< This Array stores all the Limit Check current value from latest + * ranging + */ +} VL53L1_DeviceParameters_t; + + +/** @defgroup VL53L1_define_State_group Defines the current status of the device + * Defines the current status of the device + * @{ + */ + +typedef uint8_t VL53L1_State; + +#define VL53L1_STATE_POWERDOWN ((VL53L1_State) 0) + /*!< Device is in HW reset */ +#define VL53L1_STATE_WAIT_STATICINIT ((VL53L1_State) 1) + /*!< Device is initialized and wait for static initialization */ +#define VL53L1_STATE_STANDBY ((VL53L1_State) 2) + /*!< Device is in Low power Standby mode */ +#define VL53L1_STATE_IDLE ((VL53L1_State) 3) + /*!< Device has been initialized and ready to do measurements */ +#define VL53L1_STATE_RUNNING ((VL53L1_State) 4) + /*!< Device is performing measurement */ +#define VL53L1_STATE_RESET ((VL53L1_State) 5) + /*!< Soft reset has been run on Device */ +#define VL53L1_STATE_UNKNOWN ((VL53L1_State) 98) + /*!< Device is in unknown state and need to be rebooted */ +#define VL53L1_STATE_ERROR ((VL53L1_State) 99) + /*!< Device is in error state and need to be rebooted */ + +/** @} VL53L1_define_State_group */ + +/** @defgroup VL53L1_define_Smudge_Mode_group Defines smudge correction modes + * Defines the smudge correction modes + * @{ + */ + +typedef uint8_t VL53L1_SmudgeCorrectionModes; + +#define VL53L1_SMUDGE_CORRECTION_NONE ((VL53L1_SmudgeCorrectionModes) 0) + /*!< Smudge correction is applied continously accross the rangings */ +#define VL53L1_SMUDGE_CORRECTION_CONTINUOUS ((VL53L1_SmudgeCorrectionModes) 1) + /*!< Smudge correction is applied continously accross the rangings */ +#define VL53L1_SMUDGE_CORRECTION_SINGLE ((VL53L1_SmudgeCorrectionModes) 2) + /*!< Smudge correction is applied only once accross the rangings */ +#define VL53L1_SMUDGE_CORRECTION_DEBUG ((VL53L1_SmudgeCorrectionModes) 3) + /*!< Smudge detection is applied continously but Xtalk values are not + * updated automatically within the driver + */ + +/** @} VL53L1_define_Smudge_Correction_Mode_group */ + + +/** + * @struct VL53L1_RangingMeasurementData_t + * @brief Single Range measurement data. + */ +typedef struct { + uint32_t TimeStamp; + /*!< 32-bit time stamp. + * @warning Not yet implemented + */ + + uint8_t StreamCount; + /*!< 8-bit Stream Count. */ + + uint8_t RangeQualityLevel; + /*!< indicate a quality level in percentage from 0 to 100 + * @warning Not yet implemented + */ + + FixPoint1616_t SignalRateRtnMegaCps; + /*!< Return signal rate (MCPS)\n these is a 16.16 fix point + * value, which is effectively a measure of target + * reflectance. + */ + + FixPoint1616_t AmbientRateRtnMegaCps; + /*!< Return ambient rate (MCPS)\n these is a 16.16 fix point + * value, which is effectively a measure of the ambien + * t light. + */ + + uint16_t EffectiveSpadRtnCount; + /*!< Return the effective SPAD count for the return signal. + * To obtain Real value it should be divided by 256 + */ + + FixPoint1616_t SigmaMilliMeter; + /*!< Return the Sigma value in millimeter */ + + int16_t RangeMilliMeter; + /*!< range distance in millimeter. This should be between + * RangeMinMilliMeter and RangeMaxMilliMeter + */ + + uint8_t RangeFractionalPart; + /*!< Fractional part of range distance. Final value is a + * RangeMilliMeter + RangeFractionalPart/256. + * @warning Not yet implemented + */ + + uint8_t RangeStatus; + /*!< Range Status for the current measurement. This is device + * dependent. Value = 0 means value is valid. + */ +} VL53L1_RangingMeasurementData_t; + +/** + * @struct VL53L1_TargetRangeData_t + * @brief One Range measurement data for each target. + */ +typedef struct { + uint8_t RangeQualityLevel; + /*!< indicate a quality level in percentage from 0 to 100 + * @warning Not yet implemented + */ + + int16_t RangeMaxMilliMeter; + /*!< Tells what is the maximum detection distance of the object + * in current setup and environment conditions (Filled when + * applicable) + */ + + int16_t RangeMinMilliMeter; + /*!< Tells what is the minimum detection distance of the object + * in current setup and environment conditions (Filled when + * applicable) + */ + + FixPoint1616_t SignalRateRtnMegaCps; + /*!< Return signal rate (MCPS)\n these is a 16.16 fix point + * value, which is effectively a measure of target + * reflectance. + */ + + FixPoint1616_t AmbientRateRtnMegaCps; + /*!< Return ambient rate (MCPS)\n these is a 16.16 fix point + * value, which is effectively a measure of the ambien + * t light. + */ + + FixPoint1616_t SigmaMilliMeter; + /*!< Return the Sigma value in millimeter */ + + int16_t RangeMilliMeter; + /*!< range distance in millimeter. This should be between + * RangeMinMilliMeter and RangeMaxMilliMeter + */ + + uint8_t RangeFractionalPart; + /*!< Fractional part of range distance. Final value is a + * RangeMilliMeter + RangeFractionalPart/256. + * @warning Not yet implemented + */ + + uint8_t RangeStatus; + /*!< Range Status for the current measurement. This is device + * dependent. Value = 0 means value is valid. + */ +} VL53L1_TargetRangeData_t; +/** + * @struct VL53L1_MultiRangingData_t + * @brief Structure for storing the set of range results for a single ROI + * + */ +typedef struct { + uint32_t TimeStamp; + /*!< 32-bit time stamp. + * @warning Not yet implemented + */ + + uint8_t StreamCount; + /*!< 8-bit Stream Count. */ + + uint8_t RoiNumber; + /*!< Denotes on which ROI the range data is related to. */ + uint8_t NumberOfObjectsFound; + /*!< Indicate the number of objects found in the current ROI. + * This is used to know how many ranging data should be get. + * NumberOfObjectsFound is in the range 0 to + * VL53L1_MAX_RANGE_RESULTS. + */ + VL53L1_RoiStatus RoiStatus; + /*!< Indicate if the data read is valid or not or if this is + * the last valid data in the ROI. + */ + VL53L1_TargetRangeData_t RangeData[VL53L1_MAX_RANGE_RESULTS]; + /*!< Range data each target distance */ + uint8_t HasXtalkValueChanged; + /*!< set to 1 if a new Xtalk value has been computed whilst + * smudge correction mode enable by with + * VL53L1_SmudgeCorrectionEnable() function is either + * VL53L1_SMUDGE_CORRECTION_CONTINUOUS or + * VL53L1_SMUDGE_CORRECTION_SINGLE. + */ + uint16_t EffectiveSpadRtnCount; + /*!< Return the effective SPAD count for the return signal. + * To obtain Real value it should be divided by 256 + */ + int16_t DmaxMilliMeter; + /*!< range Dmax distance in millimeter. + */ + VL53L1_DistanceModes RecommendedDistanceMode; + /*!< suggestion for a better distance mode choice to improve + * range accuracy. + */ +} VL53L1_MultiRangingData_t; + + +/** @brief Defines User Zone(ROI) parameters + * + */ +typedef struct { + + uint8_t TopLeftX; /*!< Top Left x coordinate: 0-15 range */ + uint8_t TopLeftY; /*!< Top Left y coordinate: 0-15 range */ + uint8_t BotRightX; /*!< Bot Right x coordinate: 0-15 range */ + uint8_t BotRightY; /*!< Bot Right y coordinate: 0-15 range */ + +} VL53L1_UserRoi_t; + + +/** @brief Defines ROI configuration parameters + * + * Support up a max of 16 zones, Each Zone has the same size + * + */ +typedef struct { + + uint8_t NumberOfRoi; /*!< Number of Rois defined*/ + + VL53L1_UserRoi_t UserRois[VL53L1_MAX_USER_ZONES]; + /*!< List of Rois */ + +} VL53L1_RoiConfig_t; + +/** + * @struct VL53L1_CustomerNvmManaged_t + * + */ + +typedef struct { + uint8_t global_config__spad_enables_ref_0; + uint8_t global_config__spad_enables_ref_1; + uint8_t global_config__spad_enables_ref_2; + uint8_t global_config__spad_enables_ref_3; + uint8_t global_config__spad_enables_ref_4; + uint8_t global_config__spad_enables_ref_5; + uint8_t global_config__ref_en_start_select; + uint8_t ref_spad_man__num_requested_ref_spads; + uint8_t ref_spad_man__ref_location; + uint32_t algo__crosstalk_compensation_plane_offset_kcps; + int16_t algo__crosstalk_compensation_x_plane_gradient_kcps; + int16_t algo__crosstalk_compensation_y_plane_gradient_kcps; + uint16_t ref_spad_char__total_rate_target_mcps; + int16_t algo__part_to_part_range_offset_mm; + int16_t mm_config__inner_offset_mm; + int16_t mm_config__outer_offset_mm; +} VL53L1_CustomerNvmManaged_t; + +/** + * @struct VL53L1_CalibrationData_t + * @brief Structure for storing the Calibration Data + * + */ + +typedef struct { + + uint32_t struct_version; + VL53L1_CustomerNvmManaged_t customer; + VL53L1_dmax_calibration_data_t fmt_dmax_cal; + VL53L1_dmax_calibration_data_t cust_dmax_cal; + VL53L1_additional_offset_cal_data_t add_off_cal_data; + VL53L1_optical_centre_t optical_centre; + VL53L1_xtalk_histogram_data_t xtalkhisto; + VL53L1_gain_calibration_data_t gain_cal; + VL53L1_cal_peak_rate_map_t cal_peak_rate_map; + VL53L1_per_vcsel_period_offset_cal_data_t per_vcsel_cal_data; + uint32_t algo__xtalk_cpo_HistoMerge_kcps[VL53L1_BIN_REC_SIZE]; +} VL53L1_CalibrationData_t; + +#define VL53L1_ADDITIONAL_CALIBRATION_DATA_STRUCT_VERSION 0x10 +/** VL53L1 additional Calibration Data struct version final struct version + * is given by adding it to VL53L1_LL_CALIBRATION_DATA_STRUCT_VERSION + */ + +#define VL53L1_CALIBRATION_DATA_STRUCT_VERSION \ + (VL53L1_LL_CALIBRATION_DATA_STRUCT_VERSION + \ + VL53L1_ADDITIONAL_CALIBRATION_DATA_STRUCT_VERSION) +/* VL53L1 Calibration Data struct version */ + +/** + * @struct VL53L1_AdditionalData_t + * @brief Structure for storing the Additional Data + * + */ +typedef VL53L1_additional_data_t VL53L1_AdditionalData_t; + +/** + * @struct VL53L1_ZoneCalibrationData_t + * @brief Structure for storing the Zone Calibration Data + * + */ +typedef VL53L1_zone_calibration_results_t VL53L1_ZoneCalibrationData_t; + +/** @defgroup VL53L1_define_SequenceStepId_group Defines the SequenceStep + * Defines the the sequence steps performed during ranging.. + * @{ + */ +typedef uint8_t VL53L1_SequenceStepId; + +#define VL53L1_SEQUENCESTEP_VHV ((VL53L1_SequenceStepId) 0) +/*!>12)&0xFFFF) +#define VL53L1_FIXPOINT44TOFIXPOINT1616(Value) \ + (FixPoint1616_t)((uint32_t)Value<<12) + +#define VL53L1_FIXPOINT1616TOFIXPOINT72(Value) \ + (uint16_t)((Value>>14)&0xFFFF) +#define VL53L1_FIXPOINT72TOFIXPOINT1616(Value) \ + (FixPoint1616_t)((uint32_t)Value<<14) + +#define VL53L1_FIXPOINT1616TOFIXPOINT97(Value) \ + (uint16_t)((Value>>9)&0xFFFF) +#define VL53L1_FIXPOINT97TOFIXPOINT1616(Value) \ + (FixPoint1616_t)((uint32_t)Value<<9) + +#define VL53L1_FIXPOINT1616TOFIXPOINT88(Value) \ + (uint16_t)((Value>>8)&0xFFFF) +#define VL53L1_FIXPOINT88TOFIXPOINT1616(Value) \ + (FixPoint1616_t)((uint32_t)Value<<8) + +#define VL53L1_FIXPOINT1616TOFIXPOINT412(Value) \ + (uint16_t)((Value>>4)&0xFFFF) +#define VL53L1_FIXPOINT412TOFIXPOINT1616(Value) \ + (FixPoint1616_t)((uint32_t)Value<<4) + +#define VL53L1_FIXPOINT1616TOFIXPOINT313(Value) \ + (uint16_t)((Value>>3)&0xFFFF) +#define VL53L1_FIXPOINT313TOFIXPOINT1616(Value) \ + (FixPoint1616_t)((uint32_t)Value<<3) + +#define VL53L1_FIXPOINT1616TOFIXPOINT08(Value) \ + (uint8_t)((Value>>8)&0x00FF) +#define VL53L1_FIXPOINT08TOFIXPOINT1616(Value) \ + (FixPoint1616_t)((uint32_t)Value<<8) + +#define VL53L1_FIXPOINT1616TOFIXPOINT53(Value) \ + (uint8_t)((Value>>13)&0x00FF) +#define VL53L1_FIXPOINT53TOFIXPOINT1616(Value) \ + (FixPoint1616_t)((uint32_t)Value<<13) + +#define VL53L1_FIXPOINT1616TOFIXPOINT102(Value) \ + (uint16_t)((Value>>14)&0x0FFF) +#define VL53L1_FIXPOINT102TOFIXPOINT1616(Value) \ + (FixPoint1616_t)((uint32_t)Value<<14) + +#define VL53L1_FIXPOINT1616TOFIXPOINT142(Value) \ + (uint16_t)((Value>>14)&0xFFFF) +#define VL53L1_FIXPOINT142TOFIXPOINT1616(Value) \ + (FixPoint1616_t)((uint32_t)Value<<14) + +#define VL53L1_FIXPOINT1616TOFIXPOINT160(Value) \ + (uint16_t)((Value>>16)&0xFFFF) +#define VL53L1_FIXPOINT160TOFIXPOINT1616(Value) \ + (FixPoint1616_t)((uint32_t)Value<<16) + +#define VL53L1_MAKEUINT16(lsb, msb) (uint16_t)((((uint16_t)msb)<<8) + \ + (uint16_t)lsb) + +#ifndef SUPPRESS_UNUSED_WARNING +#define SUPPRESS_UNUSED_WARNING(x) ((void) (x)) +#endif + +/** @} VL53L1_define_GeneralMacro_group */ + +/** @} VL53L1_globaldefine_group */ + + + +#ifdef __cplusplus +} +#endif + + +#endif /* _VL53L1_DEF_H_ */ diff --git a/drivers/input/misc/vl53L1/kona/inc/vl53l1_dmax_structs.h b/drivers/input/misc/vl53L1/kona/inc/vl53l1_dmax_structs.h new file mode 100644 index 000000000000..969be0ba40e8 --- /dev/null +++ b/drivers/input/misc/vl53L1/kona/inc/vl53l1_dmax_structs.h @@ -0,0 +1,210 @@ + +/******************************************************************************* + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#ifndef _VL53L1_DMAX_STRUCTS_H_ +#define _VL53L1_DMAX_STRUCTS_H_ + +#include "vl53l1_types.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + + +#define VL53L1_MAX_AMBIENT_DMAX_VALUES 5 + + + + + + + + + + + + +typedef struct { + + + + + uint16_t ref__actual_effective_spads; + + + uint16_t ref__peak_signal_count_rate_mcps; + + + uint16_t ref__distance_mm; + + + uint16_t ref_reflectance_pc; + + + + + + + uint16_t coverglass_transmission; + + + +} VL53L1_dmax_calibration_data_t; + + + + + + + + + + +typedef struct { + + + + + uint8_t signal_thresh_sigma; + + + uint8_t ambient_thresh_sigma; + + + int32_t min_ambient_thresh_events; + + + int32_t signal_total_events_limit; + + + + uint16_t target_reflectance_for_dmax_calc[ + VL53L1_MAX_AMBIENT_DMAX_VALUES]; + + + uint16_t max_effective_spads; + + + + + + + uint16_t dss_config__target_total_rate_mcps; + + + uint8_t dss_config__aperture_attenuation; + + + +} VL53L1_hist_gen3_dmax_config_t; + + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/drivers/input/misc/vl53L1/kona/inc/vl53l1_error_codes.h b/drivers/input/misc/vl53L1/kona/inc/vl53l1_error_codes.h new file mode 100644 index 000000000000..1bf727eaf560 --- /dev/null +++ b/drivers/input/misc/vl53L1/kona/inc/vl53l1_error_codes.h @@ -0,0 +1,273 @@ +/****************************************************************************** + * Copyright (c) 2017, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + + ****************************************************************************** + + 'STMicroelectronics Proprietary license' + + ******************************************************************************* + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + + ******************************************************************************* + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones mentioned above : + + ******************************************************************************* + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + ******************************************************************************* + */ + +/** + * @file vl53l1_error_codes.h + * + * @brief Error Code definitions for VL53L1 API. + * + */ + +#ifndef _VL53L1_ERROR_CODES_H_ +#define _VL53L1_ERROR_CODES_H_ + +#include "vl53l1_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +/* + **************************************** + * PRIVATE define do not edit + *************************************** + */ + +/* + * @defgroup VL53L1_define_Error_group Error and Warning code returned by API + * The following DEFINE are used to identify the PAL ERROR + * @{ + */ + +typedef int8_t VL53L1_Error; + +#define VL53L1_ERROR_NONE ((VL53L1_Error) 0) +#define VL53L1_ERROR_CALIBRATION_WARNING ((VL53L1_Error) - 1) + /*!< Warning invalid calibration data may be in used + * \a VL53L1_InitData() + * \a VL53L1_GetOffsetCalibrationData + * \a VL53L1_SetOffsetCalibrationData + */ +#define VL53L1_ERROR_MIN_CLIPPED ((VL53L1_Error) - 2) + /*!< Warning parameter passed was clipped to min before to be applied */ + +#define VL53L1_ERROR_UNDEFINED ((VL53L1_Error) - 3) + /*!< Unqualified error */ +#define VL53L1_ERROR_INVALID_PARAMS ((VL53L1_Error) - 4) + /*!< Parameter passed is invalid or out of range */ +#define VL53L1_ERROR_NOT_SUPPORTED ((VL53L1_Error) - 5) + /*!< Function is not supported in current mode or configuration */ +#define VL53L1_ERROR_RANGE_ERROR ((VL53L1_Error) - 6) + /*!< Device report a ranging error interrupt status */ +#define VL53L1_ERROR_TIME_OUT ((VL53L1_Error) - 7) + /*!< Aborted due to time out */ +#define VL53L1_ERROR_MODE_NOT_SUPPORTED ((VL53L1_Error) - 8) + /*!< Asked mode is not supported by the device */ +#define VL53L1_ERROR_BUFFER_TOO_SMALL ((VL53L1_Error) - 9) + /*!< ... */ +#define VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL ((VL53L1_Error) - 10) + /*!< Supplied buffer is larger than I2C supports */ +#define VL53L1_ERROR_GPIO_NOT_EXISTING ((VL53L1_Error) - 11) + /*!< User tried to setup a non-existing GPIO pin */ +#define VL53L1_ERROR_GPIO_FUNCTIONALITY_NOT_SUPPORTED ((VL53L1_Error) - 12) + /*!< unsupported GPIO functionality */ +#define VL53L1_ERROR_CONTROL_INTERFACE ((VL53L1_Error) - 13) + /*!< error reported from IO functions */ +#define VL53L1_ERROR_INVALID_COMMAND ((VL53L1_Error) - 14) + /*!< The command is not allowed in the current device state + * (power down) + */ +#define VL53L1_ERROR_DIVISION_BY_ZERO ((VL53L1_Error) - 15) + /*!< In the function a division by zero occurs */ +#define VL53L1_ERROR_REF_SPAD_INIT ((VL53L1_Error) - 16) + /*!< Error during reference SPAD initialization */ +#define VL53L1_ERROR_GPH_SYNC_CHECK_FAIL ((VL53L1_Error) - 17) + /*!< GPH sync interrupt check fail - API out of sync with device*/ +#define VL53L1_ERROR_STREAM_COUNT_CHECK_FAIL ((VL53L1_Error) - 18) + /*!< Stream count check fail - API out of sync with device */ +#define VL53L1_ERROR_GPH_ID_CHECK_FAIL ((VL53L1_Error) - 19) + /*!< GPH ID check fail - API out of sync with device */ +#define VL53L1_ERROR_ZONE_STREAM_COUNT_CHECK_FAIL ((VL53L1_Error) - 20) + /*!< Zone dynamic config stream count check failed - API out of sync */ +#define VL53L1_ERROR_ZONE_GPH_ID_CHECK_FAIL ((VL53L1_Error) - 21) + /*!< Zone dynamic config GPH ID check failed - API out of sync */ + +#define VL53L1_ERROR_XTALK_EXTRACTION_NO_SAMPLE_FAIL ((VL53L1_Error) - 22) + /*!< Thrown when run_xtalk_extraction fn has 0 succesful samples + * when using the full array to sample the xtalk. In this case there is + * not enough information to generate new Xtalk parm info. The function + * will exit and leave the current xtalk parameters unaltered + */ +#define VL53L1_ERROR_XTALK_EXTRACTION_SIGMA_LIMIT_FAIL ((VL53L1_Error) - 23) + /*!< Thrown when run_xtalk_extraction fn has found that the + * avg sigma estimate of the full array xtalk sample is > than the + * maximal limit allowed. In this case the xtalk sample is too noisy for + * measurement. The function will exit and leave the current xtalk + * parameters unaltered. + */ + + +#define VL53L1_ERROR_OFFSET_CAL_NO_SAMPLE_FAIL ((VL53L1_Error) - 24) + /*!< Thrown if there one of stages has no valid offset calibration + * samples. A fatal error calibration not valid + */ +#define VL53L1_ERROR_OFFSET_CAL_NO_SPADS_ENABLED_FAIL ((VL53L1_Error) - 25) + /*!< Thrown if there one of stages has zero effective SPADS + * Traps the case when MM1 SPADs is zero. + * A fatal error calibration not valid + */ +#define VL53L1_ERROR_ZONE_CAL_NO_SAMPLE_FAIL ((VL53L1_Error) - 26) + /*!< Thrown if then some of the zones have no valid samples + * A fatal error calibration not valid + */ + +#define VL53L1_ERROR_TUNING_PARM_KEY_MISMATCH ((VL53L1_Error) - 27) + /*!< Thrown if the tuning file key table version does not match with + * expected value. The driver expects the key table version to match + * the compiled default version number in the define + * #VL53L1_TUNINGPARM_KEY_TABLE_VERSION_DEFAULT + */ + +#define VL53L1_WARNING_REF_SPAD_CHAR_NOT_ENOUGH_SPADS ((VL53L1_Error) - 28) + /*!< Thrown if there are less than 5 good SPADs are available. */ +#define VL53L1_WARNING_REF_SPAD_CHAR_RATE_TOO_HIGH ((VL53L1_Error) - 29) + /*!< Thrown if the final reference rate is greater than + * the upper reference rate limit - default is 40 Mcps. + * Implies a minimum Q3 (x10) SPAD (5) selected + */ +#define VL53L1_WARNING_REF_SPAD_CHAR_RATE_TOO_LOW ((VL53L1_Error) - 30) + /*!< Thrown if the final reference rate is less than + * the lower reference rate limit - default is 10 Mcps. + * Implies maximum Q1 (x1) SPADs selected + */ + + +#define VL53L1_WARNING_OFFSET_CAL_MISSING_SAMPLES ((VL53L1_Error) - 31) + /*!< Thrown if there is less than the requested number of + * valid samples. + */ +#define VL53L1_WARNING_OFFSET_CAL_SIGMA_TOO_HIGH ((VL53L1_Error) - 32) + /*!< Thrown if the offset calibration range sigma estimate is greater + * than 8.0 mm. This is the recommended min value to yield a stable + * offset measurement + */ +#define VL53L1_WARNING_OFFSET_CAL_RATE_TOO_HIGH ((VL53L1_Error) - 33) + /*!< Thrown when VL53L1_run_offset_calibration() peak rate is greater + * than that 50.0Mcps. This is the recommended max rate to avoid + * pile-up influencing the offset measurement + */ +#define VL53L1_WARNING_OFFSET_CAL_SPAD_COUNT_TOO_LOW ((VL53L1_Error) - 34) + /*!< Thrown when VL53L1_run_offset_calibration() when one of stages + * range has less that 5.0 effective SPADS. This is the recommended + * min value to yield a stable offset + */ + + +#define VL53L1_WARNING_ZONE_CAL_MISSING_SAMPLES ((VL53L1_Error) - 35) + /*!< Thrown if one of more of the zones have less than + * the requested number of valid samples + */ +#define VL53L1_WARNING_ZONE_CAL_SIGMA_TOO_HIGH ((VL53L1_Error) - 36) + /*!< Thrown if one or more zones have sigma estimate value greater + * than 8.0 mm. This is the recommended min value to yield a stable + * offset measurement + */ +#define VL53L1_WARNING_ZONE_CAL_RATE_TOO_HIGH ((VL53L1_Error) - 37) + /*!< Thrown if one of more zones have peak rate higher than + * that 50.0Mcps. This is the recommended max rate to avoid + * pile-up influencing the offset measurement + */ + + +#define VL53L1_WARNING_XTALK_MISSING_SAMPLES ((VL53L1_Error) - 38) + /*!< Thrown to notify that some of the xtalk samples did not yield + * valid ranging pulse data while attempting to measure + * the xtalk signal in vl53l1_run_xtalk_extract(). This can signify any + * of the zones are missing samples, for further debug information the + * xtalk_results struct should be referred to. This warning is for + * notification only, xtalk pulse and shape have still been generated + */ +#define VL53L1_WARNING_XTALK_NO_SAMPLES_FOR_GRADIENT ((VL53L1_Error) - 39) + /*!< Thrown to notify that some of teh xtalk samples used for gradient + * generation did not yield valid ranging pulse data while attempting to + * measure the xtalk signal in vl53l1_run_xtalk_extract(). This can + * signify that any one of the zones 0-3 yielded no successful samples. + * xtalk_results struct should be referred to for further debug info. + * This warning is for notification only, the xtalk pulse and shape + * have still been generated. + */ +#define VL53L1_WARNING_XTALK_SIGMA_LIMIT_FOR_GRADIENT ((VL53L1_Error) - 40) + /*!< Thrown to notify that some of the xtalk samples used for gradient + * generation did not pass the sigma limit check while attempting to + * measure the xtalk signal in vl53l1_run_xtalk_extract(). This can + * signify that any one of the zones 0-3 yielded an avg sigma_mm + * value > the limit. The xtalk_results struct should be referred to for + * further debug info. + * This warning is for notification only, the xtalk pulse and shape + * have still been generated. + */ + +#define VL53L1_ERROR_NOT_IMPLEMENTED ((VL53L1_Error) - 41) + /*!< Tells requested functionality has not been implemented yet or + * not compatible with the device + */ +#define VL53L1_ERROR_PLATFORM_SPECIFIC_START ((VL53L1_Error) - 60) + /*!< Tells the starting code for platform */ +/** @} VL53L1_define_Error_group */ + + +#ifdef __cplusplus +} +#endif + + +#endif /* _VL53L1_ERROR_CODES_H_ */ diff --git a/drivers/input/misc/vl53L1/kona/inc/vl53l1_error_exceptions.h b/drivers/input/misc/vl53L1/kona/inc/vl53l1_error_exceptions.h new file mode 100644 index 000000000000..8fd8a7edd9f4 --- /dev/null +++ b/drivers/input/misc/vl53L1/kona/inc/vl53l1_error_exceptions.h @@ -0,0 +1,126 @@ + +/******************************************************************************* + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#ifndef _VL53L1_ERROR_EXCEPTIONS_H_ +#define _VL53L1_ERROR_EXCEPTIONS_H_ + +#define IGNORE_DIVISION_BY_ZERO 0 + +#define IGNORE_XTALK_EXTRACTION_NO_SAMPLE_FAIL 0 +#define IGNORE_XTALK_EXTRACTION_SIGMA_LIMIT_FAIL 0 +#define IGNORE_XTALK_EXTRACTION_NO_SAMPLE_FOR_GRADIENT_WARN 0 +#define IGNORE_XTALK_EXTRACTION_SIGMA_LIMIT_FOR_GRADIENT_WARN 0 +#define IGNORE_XTALK_EXTRACTION_MISSING_SAMPLES_WARN 0 + +#define IGNORE_REF_SPAD_CHAR_NOT_ENOUGH_SPADS 0 +#define IGNORE_REF_SPAD_CHAR_RATE_TOO_HIGH 0 +#define IGNORE_REF_SPAD_CHAR_RATE_TOO_LOW 0 + +#define IGNORE_OFFSET_CAL_MISSING_SAMPLES 0 +#define IGNORE_OFFSET_CAL_SIGMA_TOO_HIGH 0 +#define IGNORE_OFFSET_CAL_RATE_TOO_HIGH 0 +#define IGNORE_OFFSET_CAL_SPAD_COUNT_TOO_LOW 0 + +#define IGNORE_ZONE_CAL_MISSING_SAMPLES 0 +#define IGNORE_ZONE_CAL_SIGMA_TOO_HIGH 0 +#define IGNORE_ZONE_CAL_RATE_TOO_HIGH 0 + +#endif + + diff --git a/drivers/input/misc/vl53L1/kona/inc/vl53l1_error_strings.h b/drivers/input/misc/vl53L1/kona/inc/vl53l1_error_strings.h new file mode 100644 index 000000000000..7eab1fec2536 --- /dev/null +++ b/drivers/input/misc/vl53L1/kona/inc/vl53l1_error_strings.h @@ -0,0 +1,244 @@ + +/******************************************************************************* + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#ifndef VL53L1_ERROR_STRINGS_H_ +#define VL53L1_ERROR_STRINGS_H_ + +#include "vl53l1_error_codes.h" + +#ifdef __cplusplus +extern "C" { +#endif + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_pal_error_string( + VL53L1_Error PalErrorCode, + char *pPalErrorString); + + +#ifndef VL53L1_USE_EMPTY_STRING + + + + #define VL53L1_STRING_ERROR_NONE \ + "No Error" + #define VL53L1_STRING_ERROR_CALIBRATION_WARNING \ + "Calibration Warning Error" + #define VL53L1_STRING_ERROR_MIN_CLIPPED \ + "Min clipped error" + #define VL53L1_STRING_ERROR_UNDEFINED \ + "Undefined error" + #define VL53L1_STRING_ERROR_INVALID_PARAMS \ + "Invalid parameters error" + #define VL53L1_STRING_ERROR_NOT_SUPPORTED \ + "Not supported error" + #define VL53L1_STRING_ERROR_RANGE_ERROR \ + "Range error" + #define VL53L1_STRING_ERROR_TIME_OUT \ + "Time out error" + #define VL53L1_STRING_ERROR_MODE_NOT_SUPPORTED \ + "Mode not supported error" + #define VL53L1_STRING_ERROR_BUFFER_TOO_SMALL \ + "Buffer too small" + #define VL53L1_STRING_ERROR_COMMS_BUFFER_TOO_SMALL \ + "Comms Buffer too small" + #define VL53L1_STRING_ERROR_GPIO_NOT_EXISTING \ + "GPIO not existing" + #define VL53L1_STRING_ERROR_GPIO_FUNCTIONALITY_NOT_SUPPORTED \ + "GPIO funct not supported" + #define VL53L1_STRING_ERROR_CONTROL_INTERFACE \ + "Control Interface Error" + #define VL53L1_STRING_ERROR_INVALID_COMMAND \ + "Invalid Command Error" + #define VL53L1_STRING_ERROR_DIVISION_BY_ZERO \ + "Division by zero Error" + #define VL53L1_STRING_ERROR_REF_SPAD_INIT \ + "Reference Spad Init Error" + #define VL53L1_STRING_ERROR_GPH_SYNC_CHECK_FAIL \ + "GPH Sync Check Fail - API out of sync" + #define VL53L1_STRING_ERROR_STREAM_COUNT_CHECK_FAIL \ + "Stream Count Check Fail - API out of sync" + #define VL53L1_STRING_ERROR_GPH_ID_CHECK_FAIL \ + "GPH ID Check Fail - API out of sync" + #define VL53L1_STRING_ERROR_ZONE_STREAM_COUNT_CHECK_FAIL \ + "Zone Stream Count Check Fail - API out of sync" + #define VL53L1_STRING_ERROR_ZONE_GPH_ID_CHECK_FAIL \ + "Zone GPH ID Check Fail - API out of sync" + + #define VL53L1_STRING_ERROR_XTALK_EXTRACTION_NO_SAMPLES_FAIL \ + "No Xtalk using full array - Xtalk Extract Fail" + #define VL53L1_STRING_ERROR_XTALK_EXTRACTION_SIGMA_LIMIT_FAIL \ + "Xtalk does not meet required VL53L1_p_011 limit - Xtalk Extract Fail" + + #define VL53L1_STRING_ERROR_OFFSET_CAL_NO_SAMPLE_FAIL \ + "Offset Cal - one of more stages with no valid samples - fatal" + #define VL53L1_STRING_ERROR_OFFSET_CAL_NO_SPADS_ENABLED_FAIL \ + "Offset Cal - one of more stages with no SPADS enables - fatal" + #define VL53L1_STRING_ERROR_ZONE_CAL_NO_SAMPLE_FAIL \ + "Zone Cal - one of more zones with no valid samples - fatal" + + #define VL53L1_STRING_WARNING_REF_SPAD_CHAR_NOT_ENOUGH_SPADS \ + "Ref SPAD Char - Not Enough Good SPADs" + #define VL53L1_STRING_WARNING_REF_SPAD_CHAR_RATE_TOO_HIGH \ + "Ref SPAD Char - Final Ref Rate too high" + #define VL53L1_STRING_WARNING_REF_SPAD_CHAR_RATE_TOO_LOW \ + "Ref SPAD Char - Final Ref Rate too low" + + #define VL53L1_STRING_WARNING_OFFSET_CAL_MISSING_SAMPLES \ + "Offset Cal - Less than the requested number of valid samples" + #define VL53L1_STRING_WARNING_OFFSET_CAL_SIGMA_TOO_HIGH \ + "Offset Cal - Sigma estimate value too high - offset not stable" + #define VL53L1_STRING_WARNING_OFFSET_CAL_RATE_TOO_HIGH \ + "Offset Cal - Rate too high - in pile up" + #define VL53L1_STRING_WARNING_OFFSET_CAL_SPAD_COUNT_TOO_LOW \ + "Offset Cal - Insufficient SPADs - offset may not be stable" + + #define VL53L1_STRING_WARNING_ZONE_CAL_MISSING_SAMPLES \ + "Zone Cal - One or more zone with less than requested valid samples" + #define VL53L1_STRING_WARNING_ZONE_CAL_SIGMA_TOO_HIGH \ + "Zone Cal - One of more zones the VL53L1_p_011 estimate too high" + #define VL53L1_STRING_WARNING_ZONE_CAL_RATE_TOO_HIGH \ + "Zone Cal - One of more zones with rate too high - in pile up" + + #define VL53L1_STRING_WARNING_XTALK_NO_SAMPLES_FOR_GRADIENT \ + "Xtalk - Gradient sample num = 0" + #define VL53L1_STRING_WARNING_XTALK_SIGMA_LIMIT_FOR_GRADIENT \ + "Xtalk - Gradient Sigma > Limit" + #define VL53L1_STRING_WARNING_XTALK_MISSING_SAMPLES \ + "Xtalk - Some missing and invalid samples" + + #define VL53L1_STRING_ERROR_DEVICE_FIRMWARE_TOO_OLD \ + "Device Firmware too old" + #define VL53L1_STRING_ERROR_DEVICE_FIRMWARE_TOO_NEW \ + "Device Firmware too new" + #define VL53L1_STRING_ERROR_UNIT_TEST_FAIL \ + "Unit Test Fail" + #define VL53L1_STRING_ERROR_FILE_READ_FAIL \ + "File Read Fail" + #define VL53L1_STRING_ERROR_FILE_WRITE_FAIL \ + "File Write Fail" + + #define VL53L1_STRING_ERROR_NOT_IMPLEMENTED \ + "Not implemented error" + #define VL53L1_STRING_UNKNOW_ERROR_CODE \ + "Unknown Error Code" + +#endif + + + +#ifdef __cplusplus +} +#endif + +#endif + + diff --git a/drivers/input/misc/vl53L1/kona/inc/vl53l1_hist_char.h b/drivers/input/misc/vl53L1/kona/inc/vl53l1_hist_char.h new file mode 100644 index 000000000000..6c509aadc7f2 --- /dev/null +++ b/drivers/input/misc/vl53L1/kona/inc/vl53l1_hist_char.h @@ -0,0 +1,176 @@ + +/******************************************************************************* + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#ifndef _VL53L1_HIST_CHAR_H_ +#define _VL53L1_HIST_CHAR_H_ + +#include "vl53l1_platform.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_calib_config( + VL53L1_DEV Dev, + uint8_t vcsel_delay__a0, + uint8_t calib_1, + uint8_t calib_2, + uint8_t calib_3, + uint8_t calib_2__a0, + uint8_t spad_readout); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_hist_calib_pulse_delay( + VL53L1_DEV Dev, + uint8_t calib_delay); + + + + + + + + + + + + +VL53L1_Error VL53L1_disable_calib_pulse_delay( + VL53L1_DEV Dev); + + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/drivers/input/misc/vl53L1/kona/inc/vl53l1_hist_map.h b/drivers/input/misc/vl53L1/kona/inc/vl53l1_hist_map.h new file mode 100644 index 000000000000..d3703c1616b4 --- /dev/null +++ b/drivers/input/misc/vl53L1/kona/inc/vl53l1_hist_map.h @@ -0,0 +1,156 @@ + +/******************************************************************************* + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#ifndef _VL53L1_HIST_MAP_H_ +#define _VL53L1_HIST_MAP_H_ + +#include "vl53l1_register_map.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + + + + + +#define VL53L1_HISTOGRAM_CONFIG__OPCODE_SEQUENCE_0 \ + VL53L1_SIGMA_ESTIMATOR__EFFECTIVE_PULSE_WIDTH_NS + +#define VL53L1_HISTOGRAM_CONFIG__OPCODE_SEQUENCE_1 \ + VL53L1_SIGMA_ESTIMATOR__EFFECTIVE_AMBIENT_WIDTH_NS + +#define VL53L1_HISTOGRAM_CONFIG__OPCODE_SEQUENCE_2 \ + VL53L1_SIGMA_ESTIMATOR__SIGMA_REF_MM + +#define VL53L1_HISTOGRAM_CONFIG__AMB_THRESH_HIGH \ + VL53L1_ALGO__RANGE_IGNORE_THRESHOLD_MCPS + + + + + +#define VL53L1_RESULT__HISTOGRAM_BIN_0_2 0x008E +#define VL53L1_RESULT__HISTOGRAM_BIN_0_1 0x008F +#define VL53L1_RESULT__HISTOGRAM_BIN_0_0 0x0090 + +#define VL53L1_RESULT__HISTOGRAM_BIN_23_2 0x00D3 +#define VL53L1_RESULT__HISTOGRAM_BIN_23_1 0x00D4 +#define VL53L1_RESULT__HISTOGRAM_BIN_23_0 0x00D5 + +#define VL53L1_RESULT__HISTOGRAM_BIN_23_0_MSB 0x00D9 +#define VL53L1_RESULT__HISTOGRAM_BIN_23_0_LSB 0x00DA + + + + +#define VL53L1_HISTOGRAM_BIN_DATA_I2C_INDEX \ + VL53L1_RESULT__INTERRUPT_STATUS +#define VL53L1_HISTOGRAM_BIN_DATA_I2C_SIZE_BYTES \ + (VL53L1_RESULT__HISTOGRAM_BIN_23_0_LSB - \ + VL53L1_RESULT__INTERRUPT_STATUS + 1) + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/drivers/input/misc/vl53L1/kona/inc/vl53l1_hist_structs.h b/drivers/input/misc/vl53L1/kona/inc/vl53l1_hist_structs.h new file mode 100644 index 000000000000..08aefabba7c8 --- /dev/null +++ b/drivers/input/misc/vl53L1/kona/inc/vl53l1_hist_structs.h @@ -0,0 +1,515 @@ + +/******************************************************************************* + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#ifndef _VL53L1_HIST_STRUCTS_H_ +#define _VL53L1_HIST_STRUCTS_H_ + +#include "vl53l1_ll_device.h" +#include "vl53l1_dmax_structs.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +#define VL53L1_MAX_BIN_SEQUENCE_LENGTH 6 +#define VL53L1_MAX_BIN_SEQUENCE_CODE 15 +#define VL53L1_HISTOGRAM_BUFFER_SIZE 24 +#define VL53L1_XTALK_HISTO_BINS 12 + + + + + + + + +typedef struct { + + uint8_t histogram_config__spad_array_selection; + + uint8_t histogram_config__low_amb_even_bin_0_1; + uint8_t histogram_config__low_amb_even_bin_2_3; + uint8_t histogram_config__low_amb_even_bin_4_5; + + uint8_t histogram_config__low_amb_odd_bin_0_1; + uint8_t histogram_config__low_amb_odd_bin_2_3; + uint8_t histogram_config__low_amb_odd_bin_4_5; + + uint8_t histogram_config__mid_amb_even_bin_0_1; + uint8_t histogram_config__mid_amb_even_bin_2_3; + uint8_t histogram_config__mid_amb_even_bin_4_5; + + uint8_t histogram_config__mid_amb_odd_bin_0_1; + uint8_t histogram_config__mid_amb_odd_bin_2; + uint8_t histogram_config__mid_amb_odd_bin_3_4; + uint8_t histogram_config__mid_amb_odd_bin_5; + + uint8_t histogram_config__user_bin_offset; + + uint8_t histogram_config__high_amb_even_bin_0_1; + uint8_t histogram_config__high_amb_even_bin_2_3; + uint8_t histogram_config__high_amb_even_bin_4_5; + + uint8_t histogram_config__high_amb_odd_bin_0_1; + uint8_t histogram_config__high_amb_odd_bin_2_3; + uint8_t histogram_config__high_amb_odd_bin_4_5; + + uint16_t histogram_config__amb_thresh_low; + + + + uint16_t histogram_config__amb_thresh_high; + + + + +} VL53L1_histogram_config_t; + + + + + + + + + +typedef struct { + + VL53L1_HistAlgoSelect hist_algo_select; + + + + VL53L1_HistTargetOrder hist_target_order; + + + + + + uint8_t filter_woi0; + + + + uint8_t filter_woi1; + + + + + VL53L1_HistAmbEstMethod hist_amb_est_method; + + + uint8_t ambient_thresh_sigma0; + + + + uint8_t ambient_thresh_sigma1; + + + + + + uint16_t ambient_thresh_events_scaler; + + + + + + + int32_t min_ambient_thresh_events; + + + uint16_t noise_threshold; + + + + int32_t signal_total_events_limit; + + + uint8_t sigma_estimator__sigma_ref_mm; + + + uint16_t sigma_thresh; + + + int16_t range_offset_mm; + + + uint16_t gain_factor; + + + + uint8_t valid_phase_low; + + + + uint8_t valid_phase_high; + + + + uint8_t algo__consistency_check__phase_tolerance; + + + + uint8_t algo__consistency_check__event_sigma; + + + + + + + uint16_t algo__consistency_check__event_min_spad_count; + + + + + + + uint16_t algo__consistency_check__min_max_tolerance; + + + + uint8_t algo__crosstalk_compensation_enable; + + + uint32_t algo__crosstalk_compensation_plane_offset_kcps; + + + int16_t algo__crosstalk_compensation_x_plane_gradient_kcps; + + + int16_t algo__crosstalk_compensation_y_plane_gradient_kcps; + + + + int16_t algo__crosstalk_detect_min_valid_range_mm; + + + int16_t algo__crosstalk_detect_max_valid_range_mm; + + + uint16_t algo__crosstalk_detect_max_valid_rate_kcps; + + + + uint16_t algo__crosstalk_detect_max_sigma_mm; + + + + + + + uint8_t algo__crosstalk_detect_event_sigma; + + + + + + + uint16_t algo__crosstalk_detect_min_max_tolerance; + + + + +} VL53L1_hist_post_process_config_t; + + + + + + + +typedef struct { + + + + VL53L1_DeviceState cfg_device_state; + + + VL53L1_DeviceState rd_device_state; + + + + uint8_t zone_id; + + + uint32_t time_stamp; + + + + uint8_t VL53L1_p_022; + + + uint8_t VL53L1_p_023; + + + uint8_t VL53L1_p_024; + + + + uint8_t number_of_ambient_bins; + + + + uint8_t bin_seq[VL53L1_MAX_BIN_SEQUENCE_LENGTH]; + + + uint8_t bin_rep[VL53L1_MAX_BIN_SEQUENCE_LENGTH]; + + + + + int32_t bin_data[VL53L1_HISTOGRAM_BUFFER_SIZE]; + + + + uint8_t result__interrupt_status; + + + uint8_t result__range_status; + + + uint8_t result__report_status; + + + uint8_t result__stream_count; + + + uint16_t result__dss_actual_effective_spads; + + + + uint16_t phasecal_result__reference_phase; + + + uint8_t phasecal_result__vcsel_start; + + + uint8_t cal_config__vcsel_start; + + + uint16_t vcsel_width; + + + uint8_t VL53L1_p_009; + + + uint16_t VL53L1_p_019; + + + uint32_t total_periods_elapsed; + + + + uint32_t peak_duration_us; + + + uint32_t woi_duration_us; + + + + int32_t min_bin_value; + + + int32_t max_bin_value; + + + + uint16_t zero_distance_phase; + + + uint8_t number_of_ambient_samples; + + + int32_t ambient_events_sum; + + + int32_t VL53L1_p_004; + + + + uint8_t roi_config__user_roi_centre_spad; + + + uint8_t roi_config__user_roi_requested_global_xy_size; + + + +} VL53L1_histogram_bin_data_t; + + + + + + + + +typedef struct { + + + + uint8_t zone_id; + + + uint32_t time_stamp; + + + + uint8_t VL53L1_p_022; + + + uint8_t VL53L1_p_023; + + + uint8_t VL53L1_p_024; + + + uint32_t bin_data[VL53L1_XTALK_HISTO_BINS]; + + + + + uint16_t phasecal_result__reference_phase; + + + uint8_t phasecal_result__vcsel_start; + + + uint8_t cal_config__vcsel_start; + + + uint16_t vcsel_width; + + + uint16_t VL53L1_p_019; + + + uint16_t zero_distance_phase; + + + +} VL53L1_xtalk_histogram_shape_t; + + + + + + + + +typedef struct { + + + + VL53L1_xtalk_histogram_shape_t xtalk_shape; + + + VL53L1_histogram_bin_data_t xtalk_hist_removed; + +} VL53L1_xtalk_histogram_data_t; + + + + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/drivers/input/misc/vl53L1/kona/inc/vl53l1_ll_def.h b/drivers/input/misc/vl53L1/kona/inc/vl53l1_ll_def.h new file mode 100644 index 000000000000..4e6653cade3b --- /dev/null +++ b/drivers/input/misc/vl53L1/kona/inc/vl53l1_ll_def.h @@ -0,0 +1,2781 @@ + +/******************************************************************************* + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#ifndef _VL53L1_LL_DEF_H_ +#define _VL53L1_LL_DEF_H_ + +#include "vl53l1_error_codes.h" +#include "vl53l1_register_structs.h" +#include "vl53l1_platform_user_config.h" +#include "vl53l1_platform_user_defines.h" +#include "vl53l1_hist_structs.h" +#include "vl53l1_dmax_structs.h" +#include "vl53l1_error_exceptions.h" + +#ifdef __cplusplus +extern "C" { +#endif + + + + + + + + + +#define VL53L1_LL_API_IMPLEMENTATION_VER_MAJOR 1 + + +#define VL53L1_LL_API_IMPLEMENTATION_VER_MINOR 1 + + +#define VL53L1_LL_API_IMPLEMENTATION_VER_SUB 48 + + +#define VL53L1_LL_API_IMPLEMENTATION_VER_REVISION 12224 + +#define VL53L1_LL_API_IMPLEMENTATION_VER_STRING "1.1.48.12224" + + + +#define VL53L1_FIRMWARE_VER_MINIMUM 398 +#define VL53L1_FIRMWARE_VER_MAXIMUM 400 + + + + + + + +#define VL53L1_LL_CALIBRATION_DATA_STRUCT_VERSION 0xECAB0102 + + + + + + +#define VL53L1_LL_ZONE_CALIBRATION_DATA_STRUCT_VERSION 0xECAE0101 + + + + + + + + +#define VL53L1_BIN_REC_SIZE 6 + + +#define VL53L1_TIMING_CONF_A_B_SIZE 2 + + +#define VL53L1_FRAME_WAIT_EVENT 6 + + + + + +#define VL53L1_MAX_XTALK_RANGE_RESULTS 5 + + + + + + +#define VL53L1_MAX_OFFSET_RANGE_RESULTS 3 + + + + + +#define VL53L1_NVM_MAX_FMT_RANGE_DATA 4 + + + +#define VL53L1_NVM_PEAK_RATE_MAP_SAMPLES 25 + + +#define VL53L1_NVM_PEAK_RATE_MAP_WIDTH 5 + + +#define VL53L1_NVM_PEAK_RATE_MAP_HEIGHT 5 + + + + + + + + + +#define VL53L1_ERROR_DEVICE_FIRMWARE_TOO_OLD ((VL53L1_Error) - 80) + + +#define VL53L1_ERROR_DEVICE_FIRMWARE_TOO_NEW ((VL53L1_Error) - 85) + + +#define VL53L1_ERROR_UNIT_TEST_FAIL ((VL53L1_Error) - 90) + + +#define VL53L1_ERROR_FILE_READ_FAIL ((VL53L1_Error) - 95) + + +#define VL53L1_ERROR_FILE_WRITE_FAIL ((VL53L1_Error) - 96) + + + + + + + + + + + + +typedef struct { + uint32_t ll_revision; + + uint8_t ll_major; + + uint8_t ll_minor; + + uint8_t ll_build; + +} VL53L1_ll_version_t; + + + + + + +typedef struct { + + uint8_t device_test_mode; + + uint8_t VL53L1_p_009; + + uint32_t timeout_us; + + uint16_t target_count_rate_mcps; + + + uint16_t min_count_rate_limit_mcps; + + + uint16_t max_count_rate_limit_mcps; + + + +} VL53L1_refspadchar_config_t; + + + + + + +typedef struct { + + uint16_t dss_config__target_total_rate_mcps; + + + uint32_t phasecal_config_timeout_us; + + + uint32_t mm_config_timeout_us; + + + uint32_t range_config_timeout_us; + + + uint8_t num_of_samples; + + + int16_t algo__crosstalk_extract_min_valid_range_mm; + + + int16_t algo__crosstalk_extract_max_valid_range_mm; + + + uint16_t algo__crosstalk_extract_max_valid_rate_kcps; + + + + uint16_t algo__crosstalk_extract_max_sigma_mm; + + + + + +} VL53L1_xtalkextract_config_t; + + + + + + +typedef struct { + + uint16_t dss_config__target_total_rate_mcps; + + + + uint32_t phasecal_config_timeout_us; + + + + uint32_t range_config_timeout_us; + + + + uint32_t mm_config_timeout_us; + + + + + uint8_t pre_num_of_samples; + + + + uint8_t mm1_num_of_samples; + + + + uint8_t mm2_num_of_samples; + + + + +} VL53L1_offsetcal_config_t; + + + + + + +typedef struct { + + uint16_t dss_config__target_total_rate_mcps; + + + + uint32_t phasecal_config_timeout_us; + + + + uint32_t mm_config_timeout_us; + + + + uint32_t range_config_timeout_us; + + + + uint16_t phasecal_num_of_samples; + + + + uint16_t zone_num_of_samples; + + + + +} VL53L1_zonecal_config_t; + + + + + + + +typedef struct { + + VL53L1_DeviceSscArray array_select; + + + + + uint8_t VL53L1_p_009; + + + uint8_t vcsel_start; + + + uint8_t vcsel_width; + + + uint32_t timeout_us; + + + uint16_t rate_limit_mcps; + + + + + +} VL53L1_ssc_config_t; + + + + + + +typedef struct { + + + uint32_t algo__crosstalk_compensation_plane_offset_kcps; + + + int16_t algo__crosstalk_compensation_x_plane_gradient_kcps; + + + int16_t algo__crosstalk_compensation_y_plane_gradient_kcps; + + + uint32_t nvm_default__crosstalk_compensation_plane_offset_kcps; + + + int16_t nvm_default__crosstalk_compensation_x_plane_gradient_kcps; + + + int16_t nvm_default__crosstalk_compensation_y_plane_gradient_kcps; + + + uint8_t global_crosstalk_compensation_enable; + + + int16_t histogram_mode_crosstalk_margin_kcps; + + + + + + + int16_t lite_mode_crosstalk_margin_kcps; + + + + + + + uint8_t crosstalk_range_ignore_threshold_mult; + + + uint16_t crosstalk_range_ignore_threshold_rate_mcps; + + + + + int16_t algo__crosstalk_detect_min_valid_range_mm; + + + int16_t algo__crosstalk_detect_max_valid_range_mm; + + + uint16_t algo__crosstalk_detect_max_valid_rate_kcps; + + + + uint16_t algo__crosstalk_detect_max_sigma_mm; + + + + + + +} VL53L1_xtalk_config_t; + + + + + + + + + + + + +typedef struct { + + + uint16_t tp_tuning_parm_version; + + + + uint16_t tp_tuning_parm_key_table_version; + + + + + uint16_t tp_tuning_parm_lld_version; + + + + + uint8_t tp_init_phase_rtn_lite_long; + + + + + uint8_t tp_init_phase_rtn_lite_med; + + + + + uint8_t tp_init_phase_rtn_lite_short; + + + + + uint8_t tp_init_phase_ref_lite_long; + + + + + uint8_t tp_init_phase_ref_lite_med; + + + + + uint8_t tp_init_phase_ref_lite_short; + + + + + + uint8_t tp_init_phase_rtn_hist_long; + + + + + uint8_t tp_init_phase_rtn_hist_med; + + + + + uint8_t tp_init_phase_rtn_hist_short; + + + + + uint8_t tp_init_phase_ref_hist_long; + + + + + uint8_t tp_init_phase_ref_hist_med; + + + + + uint8_t tp_init_phase_ref_hist_short; + + + + + + uint8_t tp_consistency_lite_phase_tolerance; + + + + + uint8_t tp_phasecal_target; + + + + + uint16_t tp_cal_repeat_rate; + + + + + uint8_t tp_lite_min_clip; + + + + + + uint16_t tp_lite_long_sigma_thresh_mm; + + + + + uint16_t tp_lite_med_sigma_thresh_mm; + + + + + uint16_t tp_lite_short_sigma_thresh_mm; + + + + + + uint16_t tp_lite_long_min_count_rate_rtn_mcps; + + + + + uint16_t tp_lite_med_min_count_rate_rtn_mcps; + + + + + uint16_t tp_lite_short_min_count_rate_rtn_mcps; + + + + + + uint8_t tp_lite_sigma_est_pulse_width_ns; + + + + uint8_t tp_lite_sigma_est_amb_width_ns; + + + + uint8_t tp_lite_sigma_ref_mm; + + + + uint8_t tp_lite_seed_cfg; + + + + uint8_t tp_timed_seed_cfg; + + + + + uint8_t tp_lite_quantifier; + + + + uint8_t tp_lite_first_order_select; + + + + + uint16_t tp_dss_target_lite_mcps; + + + + uint16_t tp_dss_target_histo_mcps; + + + + uint16_t tp_dss_target_histo_mz_mcps; + + + + uint16_t tp_dss_target_timed_mcps; + + + + uint16_t tp_dss_target_very_short_mcps; + + + + + uint32_t tp_phasecal_timeout_lite_us; + + + + uint32_t tp_phasecal_timeout_hist_long_us; + + + + uint32_t tp_phasecal_timeout_hist_med_us; + + + + uint32_t tp_phasecal_timeout_hist_short_us; + + + + + uint32_t tp_phasecal_timeout_mz_long_us; + + + + uint32_t tp_phasecal_timeout_mz_med_us; + + + + uint32_t tp_phasecal_timeout_mz_short_us; + + + + uint32_t tp_phasecal_timeout_timed_us; + + + + + uint32_t tp_mm_timeout_lite_us; + + + + uint32_t tp_mm_timeout_histo_us; + + + + uint32_t tp_mm_timeout_mz_us; + + + + uint32_t tp_mm_timeout_timed_us; + + + + uint32_t tp_mm_timeout_lpa_us; + + + + + uint32_t tp_range_timeout_lite_us; + + + + uint32_t tp_range_timeout_histo_us; + + + + uint32_t tp_range_timeout_mz_us; + + + + uint32_t tp_range_timeout_timed_us; + + + + uint32_t tp_range_timeout_lpa_us; + + + + uint32_t tp_phasecal_patch_power; + + + + uint32_t tp_hist_merge; + + + + uint32_t tp_reset_merge_threshold; + + + + uint32_t tp_hist_merge_max_size; + + + + +} VL53L1_tuning_parm_storage_t; + + + + + + + + +typedef struct { + + uint8_t x_centre; + + uint8_t y_centre; + + +} VL53L1_optical_centre_t; + + + + + + + +typedef struct { + + uint8_t x_centre; + + uint8_t y_centre; + + uint8_t width; + + uint8_t height; + + +} VL53L1_user_zone_t; + + + + + + + + + +typedef struct { + + uint8_t max_zones; + + uint8_t active_zones; + + + + + + + + + +VL53L1_histogram_config_t multizone_hist_cfg; + + VL53L1_user_zone_t user_zones[VL53L1_MAX_USER_ZONES]; + + + + uint8_t bin_config[VL53L1_MAX_USER_ZONES]; + + + +} VL53L1_zone_config_t; + + + + + + + + + +typedef struct { + + + + VL53L1_GPIO_Interrupt_Mode intr_mode_distance; + + + + VL53L1_GPIO_Interrupt_Mode intr_mode_rate; + + + + + + uint8_t intr_new_measure_ready; + + + + uint8_t intr_no_target; + + + + + + + uint8_t intr_combined_mode; + + + + + + + + + + + uint16_t threshold_distance_high; + + + + uint16_t threshold_distance_low; + + + + uint16_t threshold_rate_high; + + + + uint16_t threshold_rate_low; + +} VL53L1_GPIO_interrupt_config_t; + + + + + + + + + + + + +typedef struct { + + + + + + + uint8_t vhv_loop_bound; + + + + uint8_t is_low_power_auto_mode; + + + + + uint8_t low_power_auto_range_count; + + + + uint8_t saved_interrupt_config; + + + + uint8_t saved_vhv_init; + + + + uint8_t saved_vhv_timeout; + + + + uint8_t first_run_phasecal_result; + + + + uint32_t dss__total_rate_per_spad_mcps; + + + + uint16_t dss__required_spads; + +} VL53L1_low_power_auto_data_t; + + + + + + + + + + + + + + + +typedef struct { + + + + uint8_t smudge_corr_enabled; + + + + uint8_t smudge_corr_apply_enabled; + + + + uint8_t smudge_corr_single_apply; + + + + + + + uint16_t smudge_margin; + + + + uint32_t noise_margin; + + + + + uint32_t user_xtalk_offset_limit; + + + + + uint8_t user_xtalk_offset_limit_hi; + + + + + uint32_t sample_limit; + + + + + uint32_t single_xtalk_delta; + + + + + uint32_t averaged_xtalk_delta; + + + + + uint32_t smudge_corr_clip_limit; + + + + + uint32_t smudge_corr_ambient_threshold; + + + + + + + + + + + + + + + uint8_t scaler_calc_method; + + + + + + + int16_t x_gradient_scaler; + + + + + + + int16_t y_gradient_scaler; + + + + + + + uint8_t user_scaler_set; + + + + + uint32_t nodetect_ambient_threshold; + + + + + uint32_t nodetect_sample_limit; + + + + + uint32_t nodetect_xtalk_offset; + + + + + uint16_t nodetect_min_range_mm; + + +} VL53L1_smudge_corrector_config_t; + + + + + + + + + +typedef struct { + + + + uint32_t current_samples; + + + + uint32_t required_samples; + + + + uint64_t accumulator; + + + + uint32_t nodetect_counter; + +} VL53L1_smudge_corrector_internals_t; + + + + + + + + + +typedef struct { + + + + + + + + + uint8_t smudge_corr_valid; + + + + uint8_t smudge_corr_clipped; + + + + + + + + + uint8_t single_xtalk_delta_flag; + + + + + + + + + uint8_t averaged_xtalk_delta_flag; + + + + uint8_t sample_limit_exceeded_flag; + + + + + + + uint8_t gradient_zero_flag; + + + + uint8_t new_xtalk_applied_flag; + + + + uint32_t algo__crosstalk_compensation_plane_offset_kcps; + + + + int16_t algo__crosstalk_compensation_x_plane_gradient_kcps; + + + + int16_t algo__crosstalk_compensation_y_plane_gradient_kcps; + + +} VL53L1_smudge_corrector_data_t; + + + + + + + + + + + +typedef struct { + + + + + uint8_t range_id; + + + uint32_t time_stamp; + + + uint8_t VL53L1_p_015; + + + uint8_t VL53L1_p_022; + + + uint8_t VL53L1_p_025; + + + uint8_t VL53L1_p_026; + + + uint8_t VL53L1_p_016; + + + uint8_t VL53L1_p_027; + + + + uint16_t width; + + + uint8_t VL53L1_p_030; + + + + + uint16_t fast_osc_frequency; + + + uint16_t zero_distance_phase; + + + uint16_t VL53L1_p_006; + + + + uint32_t total_periods_elapsed; + + + + uint32_t peak_duration_us; + + + + uint32_t woi_duration_us; + + + + + + + + uint32_t VL53L1_p_020; + + + uint32_t VL53L1_p_021; + + + + int32_t VL53L1_p_013; + + + + + + + + uint16_t peak_signal_count_rate_mcps; + + + uint16_t avg_signal_count_rate_mcps; + + + uint16_t ambient_count_rate_mcps; + + + uint16_t total_rate_per_spad_mcps; + + + uint32_t VL53L1_p_012; + + + + + + + uint16_t VL53L1_p_005; + + + + + + + uint16_t VL53L1_p_028; + + + + uint16_t VL53L1_p_014; + + + uint16_t VL53L1_p_029; + + + + + + + + int16_t min_range_mm; + + + + + + int16_t median_range_mm; + + + + + int16_t max_range_mm; + + + + + + + + + + uint8_t range_status; + +} VL53L1_range_data_t; + + + + + + + + + + +typedef struct { + + VL53L1_DeviceState cfg_device_state; + + + VL53L1_DeviceState rd_device_state; + + + uint8_t zone_id; + + + uint8_t stream_count; + + + + int16_t VL53L1_p_007[VL53L1_MAX_AMBIENT_DMAX_VALUES]; + + + + + int16_t wrap_dmax_mm; + + + + uint8_t device_status; + + + + uint8_t max_results; + + + + uint8_t active_results; + + + VL53L1_range_data_t VL53L1_p_002[VL53L1_MAX_RANGE_RESULTS]; + + + VL53L1_range_data_t xmonitor; + + + VL53L1_smudge_corrector_data_t smudge_corrector_data; + + + + +} VL53L1_range_results_t; + + + + + + + + + + +typedef struct { + + uint8_t no_of_samples; + + + uint32_t rate_per_spad_kcps_sum; + + + + uint32_t rate_per_spad_kcps_avg; + + + int32_t signal_total_events_sum; + + + + int32_t signal_total_events_avg; + + + + uint32_t sigma_mm_sum; + + + + uint32_t sigma_mm_avg; + + + uint32_t median_phase_sum; + + + + + uint32_t median_phase_avg; + + + + +} VL53L1_xtalk_range_data_t; + + + + + + + + + + +typedef struct { + + VL53L1_Error cal_status; + + + uint8_t num_of_samples_status; + + + + + + + + + uint8_t zero_samples_status; + + + + + + + + + uint8_t max_sigma_status; + + + + + + + + + + + + + + + + + + + uint8_t max_results; + + + + uint8_t active_results; + + + + VL53L1_xtalk_range_data_t + VL53L1_p_002[VL53L1_MAX_XTALK_RANGE_RESULTS]; + + + VL53L1_histogram_bin_data_t central_histogram_sum; + + + + VL53L1_histogram_bin_data_t central_histogram_avg; + + + + uint8_t central_histogram__window_start; + + + + uint8_t central_histogram__window_end; + + + + VL53L1_histogram_bin_data_t + histogram_avg_1[VL53L1_MAX_XTALK_RANGE_RESULTS]; + + + + VL53L1_histogram_bin_data_t + histogram_avg_2[VL53L1_MAX_XTALK_RANGE_RESULTS]; + + + + VL53L1_histogram_bin_data_t + xtalk_avg[VL53L1_MAX_XTALK_RANGE_RESULTS]; + + + + +} VL53L1_xtalk_range_results_t; + + + + + + + + + + + +typedef struct { + + uint8_t preset_mode; + + + uint8_t dss_config__roi_mode_control; + + + uint16_t dss_config__manual_effective_spads_select; + + + uint8_t no_of_samples; + + + uint32_t effective_spads; + + + uint32_t peak_rate_mcps; + + + uint32_t VL53L1_p_005; + + + int32_t median_range_mm; + + + + int32_t range_mm_offset; + + + +} VL53L1_offset_range_data_t; + + + + + + + + + + +typedef struct { + + int16_t cal_distance_mm; + + + uint16_t cal_reflectance_pc; + + + VL53L1_Error cal_status; + + + uint8_t cal_report; + + + uint8_t max_results; + + + + uint8_t active_results; + + + VL53L1_offset_range_data_t + VL53L1_p_002[VL53L1_MAX_OFFSET_RANGE_RESULTS]; + + + +} VL53L1_offset_range_results_t; + + + + + + + + + + + + +typedef struct { + + uint16_t result__mm_inner_actual_effective_spads; + + + uint16_t result__mm_outer_actual_effective_spads; + + + uint16_t result__mm_inner_peak_signal_count_rtn_mcps; + + + uint16_t result__mm_outer_peak_signal_count_rtn_mcps; + + + +} VL53L1_additional_offset_cal_data_t; + + + + + + + + + +typedef struct { + int16_t short_a_offset_mm; + int16_t short_b_offset_mm; + int16_t medium_a_offset_mm; + int16_t medium_b_offset_mm; + int16_t long_a_offset_mm; + int16_t long_b_offset_mm; +} VL53L1_per_vcsel_period_offset_cal_data_t; + + + + + + + + + + + + +typedef struct { + + uint32_t VL53L1_p_020; + + + uint32_t VL53L1_p_021; + + + + uint16_t VL53L1_p_014; + + + uint8_t range_status; + + + +} VL53L1_object_data_t; + + + + + + + + + + +typedef struct { + + VL53L1_DeviceState cfg_device_state; + + + VL53L1_DeviceState rd_device_state; + + + uint8_t zone_id; + + + uint8_t stream_count; + + + uint8_t max_objects; + + + + uint8_t active_objects; + + + VL53L1_object_data_t VL53L1_p_002[VL53L1_MAX_RANGE_RESULTS]; + + + + VL53L1_object_data_t xmonitor; + + + +} VL53L1_zone_objects_t; + + + + + + + + + + + + + +typedef struct { + + uint8_t max_zones; + + + + uint8_t active_zones; + + + VL53L1_zone_objects_t VL53L1_p_002[VL53L1_MAX_USER_ZONES]; + + + +} VL53L1_zone_results_t; + + + + + + + + + +typedef struct { + + VL53L1_DeviceState rd_device_state; + + + + uint8_t number_of_ambient_bins; + + + + + uint16_t result__dss_actual_effective_spads; + + + uint8_t VL53L1_p_009; + + + uint32_t total_periods_elapsed; + + + + int32_t ambient_events_sum; + + + +} VL53L1_zone_hist_info_t; + + + + + + + + + + +typedef struct { + + uint8_t max_zones; + + + + uint8_t active_zones; + + + VL53L1_zone_hist_info_t VL53L1_p_002[VL53L1_MAX_USER_ZONES]; + + + +} VL53L1_zone_histograms_t; + + + + + + + + + +typedef struct { + + uint32_t no_of_samples; + + + uint32_t effective_spads; + + + uint32_t peak_rate_mcps; + + + uint32_t VL53L1_p_014; + + + uint32_t VL53L1_p_005; + + + + int32_t median_range_mm; + + + + int32_t range_mm_offset; + + + +} VL53L1_zone_calibration_data_t; + + + + + + + + + + + +typedef struct { + + uint32_t struct_version; + + + VL53L1_DevicePresetModes preset_mode; + + + VL53L1_DeviceZonePreset zone_preset; + + + int16_t cal_distance_mm; + + + uint16_t cal_reflectance_pc; + + + uint16_t phasecal_result__reference_phase; + + + uint16_t zero_distance_phase; + + + VL53L1_Error cal_status; + + + uint8_t max_zones; + + + + uint8_t active_zones; + + + VL53L1_zone_calibration_data_t VL53L1_p_002[VL53L1_MAX_USER_ZONES]; + + + +} VL53L1_zone_calibration_results_t; + + + + + + + + + + + + + +typedef struct { + + int16_t cal_distance_mm; + + + uint16_t cal_reflectance_pc; + + + uint16_t max_samples; + + + uint16_t width; + + + uint16_t height; + + + uint16_t peak_rate_mcps[VL53L1_NVM_PEAK_RATE_MAP_SAMPLES]; + + + +} VL53L1_cal_peak_rate_map_t; + + + + + + + + + +typedef struct { + + uint8_t expected_stream_count; + + + uint8_t expected_gph_id; + + + uint8_t dss_mode; + + + uint16_t dss_requested_effective_spad_count; + + + + uint8_t seed_cfg; + + + uint8_t initial_phase_seed; + + + + uint8_t roi_config__user_roi_centre_spad; + + + uint8_t roi_config__user_roi_requested_global_xy_size; + + + +} VL53L1_zone_private_dyn_cfg_t; + + + + + + + + + +typedef struct { + + uint8_t max_zones; + + + + uint8_t active_zones; + + + VL53L1_zone_private_dyn_cfg_t VL53L1_p_002[VL53L1_MAX_USER_ZONES]; + + + +} VL53L1_zone_private_dyn_cfgs_t; + + + + + + + + + +typedef struct { + + uint32_t algo__crosstalk_compensation_plane_offset_kcps; + + + int16_t algo__crosstalk_compensation_x_plane_gradient_kcps; + + + int16_t algo__crosstalk_compensation_y_plane_gradient_kcps; + + + uint32_t algo__xtalk_cpo_HistoMerge_kcps[VL53L1_BIN_REC_SIZE]; + + + +} VL53L1_xtalk_calibration_results_t; + + + + + + + + +typedef struct { + + + + uint32_t sample_count; + + + + uint32_t pll_period_mm; + + + + uint32_t peak_duration_us_sum; + + + + uint32_t effective_spad_count_sum; + + + + uint32_t zero_distance_phase_sum; + + + + uint32_t zero_distance_phase_avg; + + + + int32_t event_scaler_sum; + + + + int32_t event_scaler_avg; + + + + int32_t signal_events_sum; + + + + uint32_t xtalk_rate_kcps_per_spad; + + + + int32_t xtalk_start_phase; + + + + int32_t xtalk_end_phase; + + + + int32_t xtalk_width_phase; + + + + int32_t target_start_phase; + + + + int32_t target_end_phase; + + + + int32_t target_width_phase; + + + + int32_t effective_width; + + + + int32_t event_scaler; + + + + uint8_t VL53L1_p_015; + + + + uint8_t VL53L1_p_016; + + + + uint8_t target_start; + + + + int32_t max_shape_value; + + + + int32_t bin_data_sums[VL53L1_XTALK_HISTO_BINS]; + +} VL53L1_hist_xtalk_extract_data_t; + + + + + + + + + + +typedef struct { + + uint16_t standard_ranging_gain_factor; + + + uint16_t histogram_ranging_gain_factor; + + + +} VL53L1_gain_calibration_data_t; + + + + + + + + + + +typedef struct { + + VL53L1_DeviceState cfg_device_state; + + + uint8_t cfg_stream_count; + + + + uint8_t cfg_internal_stream_count; + + + uint8_t cfg_internal_stream_count_val; + + + uint8_t cfg_gph_id; + + + uint8_t cfg_timing_status; + + + uint8_t cfg_zone_id; + + + + VL53L1_DeviceState rd_device_state; + + + uint8_t rd_stream_count; + + + uint8_t rd_internal_stream_count; + + + uint8_t rd_internal_stream_count_val; + + + uint8_t rd_gph_id; + + + uint8_t rd_timing_status; + + + uint8_t rd_zone_id; + + + +} VL53L1_ll_driver_state_t; + + + + + + + + + + +typedef struct { + + uint8_t wait_method; + + + VL53L1_DevicePresetModes preset_mode; + + + VL53L1_DeviceZonePreset zone_preset; + + + VL53L1_DeviceMeasurementModes measurement_mode; + + + VL53L1_OffsetCalibrationMode offset_calibration_mode; + + + VL53L1_OffsetCorrectionMode offset_correction_mode; + + + VL53L1_DeviceDmaxMode dmax_mode; + + + uint32_t phasecal_config_timeout_us; + + + uint32_t mm_config_timeout_us; + + + uint32_t range_config_timeout_us; + + + uint32_t inter_measurement_period_ms; + + + uint16_t dss_config__target_total_rate_mcps; + + + + uint32_t fw_ready_poll_duration_ms; + + + uint8_t fw_ready; + + + uint8_t debug_mode; + + + + + + VL53L1_ll_version_t version; + + + + VL53L1_ll_driver_state_t ll_state; + + + + VL53L1_GPIO_interrupt_config_t gpio_interrupt_config; + + + + VL53L1_customer_nvm_managed_t customer; + VL53L1_cal_peak_rate_map_t cal_peak_rate_map; + VL53L1_additional_offset_cal_data_t add_off_cal_data; + VL53L1_dmax_calibration_data_t fmt_dmax_cal; + VL53L1_dmax_calibration_data_t cust_dmax_cal; + VL53L1_gain_calibration_data_t gain_cal; + VL53L1_user_zone_t mm_roi; + VL53L1_optical_centre_t optical_centre; + VL53L1_zone_config_t zone_cfg; + + + + VL53L1_tuning_parm_storage_t tuning_parms; + + + + uint8_t rtn_good_spads[VL53L1_RTN_SPAD_BUFFER_SIZE]; + + + + VL53L1_refspadchar_config_t refspadchar; + VL53L1_ssc_config_t ssc_cfg; + VL53L1_hist_post_process_config_t histpostprocess; + VL53L1_hist_gen3_dmax_config_t dmax_cfg; + VL53L1_xtalkextract_config_t xtalk_extract_cfg; + VL53L1_xtalk_config_t xtalk_cfg; + VL53L1_offsetcal_config_t offsetcal_cfg; + VL53L1_zonecal_config_t zonecal_cfg; + + + + VL53L1_static_nvm_managed_t stat_nvm; + VL53L1_histogram_config_t hist_cfg; + VL53L1_static_config_t stat_cfg; + VL53L1_general_config_t gen_cfg; + VL53L1_timing_config_t tim_cfg; + VL53L1_dynamic_config_t dyn_cfg; + VL53L1_system_control_t sys_ctrl; + VL53L1_system_results_t sys_results; + VL53L1_nvm_copy_data_t nvm_copy_data; + + + + VL53L1_histogram_bin_data_t hist_data; + VL53L1_histogram_bin_data_t hist_xtalk; + + + + VL53L1_xtalk_histogram_data_t xtalk_shapes; + VL53L1_xtalk_range_results_t xtalk_results; + VL53L1_xtalk_calibration_results_t xtalk_cal; + VL53L1_hist_xtalk_extract_data_t xtalk_extract; + + + + VL53L1_offset_range_results_t offset_results; + + + + VL53L1_core_results_t core_results; + VL53L1_debug_results_t dbg_results; + + VL53L1_smudge_corrector_config_t smudge_correct_config; + + + VL53L1_smudge_corrector_internals_t smudge_corrector_internals; + + + + + + + + VL53L1_low_power_auto_data_t low_power_auto_data; + + + +#ifdef PAL_EXTENDED + + + VL53L1_patch_results_t patch_results; + VL53L1_shadow_core_results_t shadow_core_results; + VL53L1_shadow_system_results_t shadow_sys_results; + VL53L1_prev_shadow_core_results_t prev_shadow_core_results; + VL53L1_prev_shadow_system_results_t prev_shadow_sys_results; +#endif + uint8_t wArea1[1536]; + uint8_t wArea2[512]; + VL53L1_per_vcsel_period_offset_cal_data_t per_vcsel_cal_data; + + + uint8_t bin_rec_pos; + + + uint8_t pos_before_next_recom; + + + int32_t multi_bins_rec[VL53L1_BIN_REC_SIZE] + [VL53L1_TIMING_CONF_A_B_SIZE][VL53L1_HISTOGRAM_BUFFER_SIZE]; + + + +} VL53L1_LLDriverData_t; + + + + + + + + + + +typedef struct { + + + + VL53L1_range_results_t range_results; + + + + VL53L1_zone_private_dyn_cfgs_t zone_dyn_cfgs; + + + + VL53L1_zone_results_t zone_results; + VL53L1_zone_histograms_t zone_hists; + VL53L1_zone_calibration_results_t zone_cal; + +} VL53L1_LLDriverResults_t; + + + + + + + + + + +typedef struct { + + uint32_t struct_version; + VL53L1_customer_nvm_managed_t customer; + VL53L1_dmax_calibration_data_t fmt_dmax_cal; + VL53L1_dmax_calibration_data_t cust_dmax_cal; + VL53L1_additional_offset_cal_data_t add_off_cal_data; + VL53L1_optical_centre_t optical_centre; + VL53L1_xtalk_histogram_data_t xtalkhisto; + VL53L1_gain_calibration_data_t gain_cal; + VL53L1_cal_peak_rate_map_t cal_peak_rate_map; + VL53L1_per_vcsel_period_offset_cal_data_t per_vcsel_cal_data; + +} VL53L1_calibration_data_t; + + + + + + + + + + +typedef struct { + + VL53L1_customer_nvm_managed_t customer; + VL53L1_xtalkextract_config_t xtalk_extract_cfg; + VL53L1_xtalk_config_t xtalk_cfg; + VL53L1_histogram_bin_data_t hist_data; + VL53L1_xtalk_histogram_data_t xtalk_shapes; + VL53L1_xtalk_range_results_t xtalk_results; + +} VL53L1_xtalk_debug_data_t; + + + + + + + + + + +typedef struct { + + VL53L1_customer_nvm_managed_t customer; + VL53L1_dmax_calibration_data_t fmt_dmax_cal; + VL53L1_dmax_calibration_data_t cust_dmax_cal; + VL53L1_additional_offset_cal_data_t add_off_cal_data; + VL53L1_offset_range_results_t offset_results; + +} VL53L1_offset_debug_data_t; + + + + + + + + + + +typedef struct { + uint16_t vl53l1_tuningparm_version; + uint16_t vl53l1_tuningparm_key_table_version; + uint16_t vl53l1_tuningparm_lld_version; + uint8_t vl53l1_tuningparm_hist_algo_select; + uint8_t vl53l1_tuningparm_hist_target_order; + uint8_t vl53l1_tuningparm_hist_filter_woi_0; + uint8_t vl53l1_tuningparm_hist_filter_woi_1; + uint8_t vl53l1_tuningparm_hist_amb_est_method; + uint8_t vl53l1_tuningparm_hist_amb_thresh_sigma_0; + uint8_t vl53l1_tuningparm_hist_amb_thresh_sigma_1; + int32_t vl53l1_tuningparm_hist_min_amb_thresh_events; + uint16_t vl53l1_tuningparm_hist_amb_events_scaler; + uint16_t vl53l1_tuningparm_hist_noise_threshold; + int32_t vl53l1_tuningparm_hist_signal_total_events_limit; + uint8_t vl53l1_tuningparm_hist_sigma_est_ref_mm; + uint16_t vl53l1_tuningparm_hist_sigma_thresh_mm; + uint16_t vl53l1_tuningparm_hist_gain_factor; + uint8_t vl53l1_tuningparm_consistency_hist_phase_tolerance; + uint16_t vl53l1_tuningparm_consistency_hist_min_max_tolerance_mm; + uint8_t vl53l1_tuningparm_consistency_hist_event_sigma; + uint16_t vl53l1_tuningparm_consistency_hist_event_sigma_min_spad_limit; + uint8_t vl53l1_tuningparm_initial_phase_rtn_histo_long_range; + uint8_t vl53l1_tuningparm_initial_phase_rtn_histo_med_range; + uint8_t vl53l1_tuningparm_initial_phase_rtn_histo_short_range; + uint8_t vl53l1_tuningparm_initial_phase_ref_histo_long_range; + uint8_t vl53l1_tuningparm_initial_phase_ref_histo_med_range; + uint8_t vl53l1_tuningparm_initial_phase_ref_histo_short_range; + int16_t vl53l1_tuningparm_xtalk_detect_min_valid_range_mm; + int16_t vl53l1_tuningparm_xtalk_detect_max_valid_range_mm; + uint16_t vl53l1_tuningparm_xtalk_detect_max_sigma_mm; + uint16_t vl53l1_tuningparm_xtalk_detect_min_max_tolerance; + uint16_t vl53l1_tuningparm_xtalk_detect_max_valid_rate_kcps; + uint8_t vl53l1_tuningparm_xtalk_detect_event_sigma; + int16_t vl53l1_tuningparm_hist_xtalk_margin_kcps; + uint8_t vl53l1_tuningparm_consistency_lite_phase_tolerance; + uint8_t vl53l1_tuningparm_phasecal_target; + uint16_t vl53l1_tuningparm_lite_cal_repeat_rate; + uint16_t vl53l1_tuningparm_lite_ranging_gain_factor; + uint8_t vl53l1_tuningparm_lite_min_clip_mm; + uint16_t vl53l1_tuningparm_lite_long_sigma_thresh_mm; + uint16_t vl53l1_tuningparm_lite_med_sigma_thresh_mm; + uint16_t vl53l1_tuningparm_lite_short_sigma_thresh_mm; + uint16_t vl53l1_tuningparm_lite_long_min_count_rate_rtn_mcps; + uint16_t vl53l1_tuningparm_lite_med_min_count_rate_rtn_mcps; + uint16_t vl53l1_tuningparm_lite_short_min_count_rate_rtn_mcps; + uint8_t vl53l1_tuningparm_lite_sigma_est_pulse_width; + uint8_t vl53l1_tuningparm_lite_sigma_est_amb_width_ns; + uint8_t vl53l1_tuningparm_lite_sigma_ref_mm; + uint8_t vl53l1_tuningparm_lite_rit_mult; + uint8_t vl53l1_tuningparm_lite_seed_config; + uint8_t vl53l1_tuningparm_lite_quantifier; + uint8_t vl53l1_tuningparm_lite_first_order_select; + int16_t vl53l1_tuningparm_lite_xtalk_margin_kcps; + uint8_t vl53l1_tuningparm_initial_phase_rtn_lite_long_range; + uint8_t vl53l1_tuningparm_initial_phase_rtn_lite_med_range; + uint8_t vl53l1_tuningparm_initial_phase_rtn_lite_short_range; + uint8_t vl53l1_tuningparm_initial_phase_ref_lite_long_range; + uint8_t vl53l1_tuningparm_initial_phase_ref_lite_med_range; + uint8_t vl53l1_tuningparm_initial_phase_ref_lite_short_range; + uint8_t vl53l1_tuningparm_timed_seed_config; + uint8_t vl53l1_tuningparm_dmax_cfg_signal_thresh_sigma; + uint16_t vl53l1_tuningparm_dmax_cfg_reflectance_array_0; + uint16_t vl53l1_tuningparm_dmax_cfg_reflectance_array_1; + uint16_t vl53l1_tuningparm_dmax_cfg_reflectance_array_2; + uint16_t vl53l1_tuningparm_dmax_cfg_reflectance_array_3; + uint16_t vl53l1_tuningparm_dmax_cfg_reflectance_array_4; + uint8_t vl53l1_tuningparm_vhv_loopbound; + uint8_t vl53l1_tuningparm_refspadchar_device_test_mode; + uint8_t vl53l1_tuningparm_refspadchar_vcsel_period; + uint32_t vl53l1_tuningparm_refspadchar_phasecal_timeout_us; + uint16_t vl53l1_tuningparm_refspadchar_target_count_rate_mcps; + uint16_t vl53l1_tuningparm_refspadchar_min_countrate_limit_mcps; + uint16_t vl53l1_tuningparm_refspadchar_max_countrate_limit_mcps; + uint8_t vl53l1_tuningparm_xtalk_extract_num_of_samples; + int16_t vl53l1_tuningparm_xtalk_extract_min_filter_thresh_mm; + int16_t vl53l1_tuningparm_xtalk_extract_max_filter_thresh_mm; + uint16_t vl53l1_tuningparm_xtalk_extract_dss_rate_mcps; + uint32_t vl53l1_tuningparm_xtalk_extract_phasecal_timeout_us; + uint16_t vl53l1_tuningparm_xtalk_extract_max_valid_rate_kcps; + uint16_t vl53l1_tuningparm_xtalk_extract_sigma_threshold_mm; + uint32_t vl53l1_tuningparm_xtalk_extract_dss_timeout_us; + uint32_t vl53l1_tuningparm_xtalk_extract_bin_timeout_us; + uint16_t vl53l1_tuningparm_offset_cal_dss_rate_mcps; + uint32_t vl53l1_tuningparm_offset_cal_phasecal_timeout_us; + uint32_t vl53l1_tuningparm_offset_cal_mm_timeout_us; + uint32_t vl53l1_tuningparm_offset_cal_range_timeout_us; + uint8_t vl53l1_tuningparm_offset_cal_pre_samples; + uint8_t vl53l1_tuningparm_offset_cal_mm1_samples; + uint8_t vl53l1_tuningparm_offset_cal_mm2_samples; + uint16_t vl53l1_tuningparm_zone_cal_dss_rate_mcps; + uint32_t vl53l1_tuningparm_zone_cal_phasecal_timeout_us; + uint32_t vl53l1_tuningparm_zone_cal_dss_timeout_us; + uint16_t vl53l1_tuningparm_zone_cal_phasecal_num_samples; + uint32_t vl53l1_tuningparm_zone_cal_range_timeout_us; + uint16_t vl53l1_tuningparm_zone_cal_zone_num_samples; + uint8_t vl53l1_tuningparm_spadmap_vcsel_period; + uint8_t vl53l1_tuningparm_spadmap_vcsel_start; + uint16_t vl53l1_tuningparm_spadmap_rate_limit_mcps; + uint16_t vl53l1_tuningparm_lite_dss_config_target_total_rate_mcps; + uint16_t vl53l1_tuningparm_ranging_dss_config_target_total_rate_mcps; + uint16_t vl53l1_tuningparm_mz_dss_config_target_total_rate_mcps; + uint16_t vl53l1_tuningparm_timed_dss_config_target_total_rate_mcps; + uint32_t vl53l1_tuningparm_lite_phasecal_config_timeout_us; + uint32_t vl53l1_tuningparm_ranging_long_phasecal_config_timeout_us; + uint32_t vl53l1_tuningparm_ranging_med_phasecal_config_timeout_us; + uint32_t vl53l1_tuningparm_ranging_short_phasecal_config_timeout_us; + uint32_t vl53l1_tuningparm_mz_long_phasecal_config_timeout_us; + uint32_t vl53l1_tuningparm_mz_med_phasecal_config_timeout_us; + uint32_t vl53l1_tuningparm_mz_short_phasecal_config_timeout_us; + uint32_t vl53l1_tuningparm_timed_phasecal_config_timeout_us; + uint32_t vl53l1_tuningparm_lite_mm_config_timeout_us; + uint32_t vl53l1_tuningparm_ranging_mm_config_timeout_us; + uint32_t vl53l1_tuningparm_mz_mm_config_timeout_us; + uint32_t vl53l1_tuningparm_timed_mm_config_timeout_us; + uint32_t vl53l1_tuningparm_lite_range_config_timeout_us; + uint32_t vl53l1_tuningparm_ranging_range_config_timeout_us; + uint32_t vl53l1_tuningparm_mz_range_config_timeout_us; + uint32_t vl53l1_tuningparm_timed_range_config_timeout_us; + uint16_t vl53l1_tuningparm_dynxtalk_smudge_margin; + uint32_t vl53l1_tuningparm_dynxtalk_noise_margin; + uint32_t vl53l1_tuningparm_dynxtalk_xtalk_offset_limit; + uint8_t vl53l1_tuningparm_dynxtalk_xtalk_offset_limit_hi; + uint32_t vl53l1_tuningparm_dynxtalk_sample_limit; + uint32_t vl53l1_tuningparm_dynxtalk_single_xtalk_delta; + uint32_t vl53l1_tuningparm_dynxtalk_averaged_xtalk_delta; + uint32_t vl53l1_tuningparm_dynxtalk_clip_limit; + uint8_t vl53l1_tuningparm_dynxtalk_scaler_calc_method; + int16_t vl53l1_tuningparm_dynxtalk_xgradient_scaler; + int16_t vl53l1_tuningparm_dynxtalk_ygradient_scaler; + uint8_t vl53l1_tuningparm_dynxtalk_user_scaler_set; + uint8_t vl53l1_tuningparm_dynxtalk_smudge_cor_single_apply; + uint32_t vl53l1_tuningparm_dynxtalk_xtalk_amb_threshold; + uint32_t vl53l1_tuningparm_dynxtalk_nodetect_amb_threshold_kcps; + uint32_t vl53l1_tuningparm_dynxtalk_nodetect_sample_limit; + uint32_t vl53l1_tuningparm_dynxtalk_nodetect_xtalk_offset_kcps; + uint16_t vl53l1_tuningparm_dynxtalk_nodetect_min_range_mm; + uint8_t vl53l1_tuningparm_lowpowerauto_vhv_loop_bound; + uint32_t vl53l1_tuningparm_lowpowerauto_mm_config_timeout_us; + uint32_t vl53l1_tuningparm_lowpowerauto_range_config_timeout_us; + uint16_t vl53l1_tuningparm_very_short_dss_rate_mcps; + uint32_t vl53l1_tuningparm_phasecal_patch_power; +} VL53L1_tuning_parameters_t; + + + + + + + + + + + + +typedef struct { + + uint16_t target_reflectance_for_dmax[VL53L1_MAX_AMBIENT_DMAX_VALUES]; + +} VL53L1_dmax_reflectance_array_t; + + + + + + + + + + + + + + +typedef struct { + + uint8_t spad_type; + + + uint16_t VL53L1_p_023; + + + uint16_t rate_data[VL53L1_NO_OF_SPAD_ENABLES]; + + + uint16_t no_of_values; + + + uint8_t fractional_bits; + + + uint8_t error_status; + + + +} VL53L1_spad_rate_data_t; + + + + + + + + + + + + + + +typedef struct { + + VL53L1_DevicePresetModes preset_mode; + + + VL53L1_DeviceZonePreset zone_preset; + + + VL53L1_DeviceMeasurementModes measurement_mode; + + + VL53L1_OffsetCalibrationMode offset_calibration_mode; + + + VL53L1_OffsetCorrectionMode offset_correction_mode; + + + VL53L1_DeviceDmaxMode dmax_mode; + + + + uint32_t phasecal_config_timeout_us; + + + uint32_t mm_config_timeout_us; + + + uint32_t range_config_timeout_us; + + + uint32_t inter_measurement_period_ms; + + + uint16_t dss_config__target_total_rate_mcps; + + + + VL53L1_histogram_bin_data_t VL53L1_p_010; + + + +} VL53L1_additional_data_t; + + + + + + + + + + +#define SUPPRESS_UNUSED_WARNING(x) \ + ((void) (x)) + + +#define IGNORE_STATUS(__FUNCTION_ID__, __ERROR_STATUS_CHECK__, __STATUS__) \ + do { \ + DISABLE_WARNINGS(); \ + if (__FUNCTION_ID__) { \ + if (__STATUS__ == __ERROR_STATUS_CHECK__) { \ + __STATUS__ = VL53L1_ERROR_NONE; \ + WARN_OVERRIDE_STATUS(__FUNCTION_ID__); \ + } \ + } \ + ENABLE_WARNINGS(); \ + } \ + while (0) + +#define VL53L1_COPYSTRING(str, ...) \ + (strncpy(str, ##__VA_ARGS__, VL53L1_MAX_STRING_LENGTH-1)) + +#ifdef __cplusplus +} +#endif + +#endif + + + + diff --git a/drivers/input/misc/vl53L1/kona/inc/vl53l1_ll_device.h b/drivers/input/misc/vl53L1/kona/inc/vl53l1_ll_device.h new file mode 100644 index 000000000000..587efb61b87c --- /dev/null +++ b/drivers/input/misc/vl53L1/kona/inc/vl53l1_ll_device.h @@ -0,0 +1,1296 @@ + +/******************************************************************************* + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#ifndef _VL53L1_LL_DEVICE_H_ +#define _VL53L1_LL_DEVICE_H_ + +#include "vl53l1_types.h" +#include "vl53l1_platform_user_config.h" + +#define VL53L1_I2C 0x01 +#define VL53L1_SPI 0x00 + + + + + + + + + + + + + +typedef uint8_t VL53L1_WaitMethod; + +#define VL53L1_WAIT_METHOD_BLOCKING ((VL53L1_WaitMethod) 0) +#define VL53L1_WAIT_METHOD_NON_BLOCKING ((VL53L1_WaitMethod) 1) + + + + + + + + + + +typedef uint8_t VL53L1_DeviceState; + +#define VL53L1_DEVICESTATE_POWERDOWN ((VL53L1_DeviceState) 0) +#define VL53L1_DEVICESTATE_HW_STANDBY ((VL53L1_DeviceState) 1) +#define VL53L1_DEVICESTATE_FW_COLDBOOT ((VL53L1_DeviceState) 2) +#define VL53L1_DEVICESTATE_SW_STANDBY ((VL53L1_DeviceState) 3) +#define VL53L1_DEVICESTATE_RANGING_DSS_AUTO ((VL53L1_DeviceState) 4) +#define VL53L1_DEVICESTATE_RANGING_DSS_MANUAL ((VL53L1_DeviceState) 5) +#define VL53L1_DEVICESTATE_RANGING_WAIT_GPH_SYNC ((VL53L1_DeviceState) 6) +#define VL53L1_DEVICESTATE_RANGING_GATHER_DATA ((VL53L1_DeviceState) 7) +#define VL53L1_DEVICESTATE_RANGING_OUTPUT_DATA ((VL53L1_DeviceState) 8) + +#define VL53L1_DEVICESTATE_UNKNOWN ((VL53L1_DeviceState) 98) +#define VL53L1_DEVICESTATE_ERROR ((VL53L1_DeviceState) 99) + + + + + + + + + + + +typedef uint8_t VL53L1_DeviceZonePreset; + +#define VL53L1_DEVICEZONEPRESET_NONE \ + ((VL53L1_DeviceZonePreset) 0) + +#define VL53L1_DEVICEZONEPRESET_XTALK_PLANAR \ + ((VL53L1_DeviceZonePreset) 1) +#define VL53L1_DEVICEZONEPRESET_1X1_SIZE_16X16 \ + ((VL53L1_DeviceZonePreset) 2) +#define VL53L1_DEVICEZONEPRESET_1X2_SIZE_16X8 \ + ((VL53L1_DeviceZonePreset) 3) +#define VL53L1_DEVICEZONEPRESET_2X1_SIZE_8X16 \ + ((VL53L1_DeviceZonePreset) 4) +#define VL53L1_DEVICEZONEPRESET_2X2_SIZE_8X8 \ + ((VL53L1_DeviceZonePreset) 5) +#define VL53L1_DEVICEZONEPRESET_3X3_SIZE_5X5 \ + ((VL53L1_DeviceZonePreset) 6) +#define VL53L1_DEVICEZONEPRESET_4X4_SIZE_4X4 \ + ((VL53L1_DeviceZonePreset) 7) +#define VL53L1_DEVICEZONEPRESET_5X5_SIZE_4X4 \ + ((VL53L1_DeviceZonePreset) 8) +#define VL53L1_DEVICEZONEPRESET_11X11_SIZE_5X5 \ + ((VL53L1_DeviceZonePreset) 9) +#define VL53L1_DEVICEZONEPRESET_13X13_SIZE_4X4 \ + ((VL53L1_DeviceZonePreset) 10) + +#define VL53L1_DEVICEZONEPRESET_1X1_SIZE_4X4_POS_8X8 \ + ((VL53L1_DeviceZonePreset) 11) + +#define VL53L1_DEVICEZONEPRESET_CUSTOM \ + ((VL53L1_DeviceZonePreset) 255) + + + + + + + + + + + +typedef uint8_t VL53L1_DevicePresetModes; + +#define VL53L1_DEVICEPRESETMODE_NONE \ + ((VL53L1_DevicePresetModes) 0) +#define VL53L1_DEVICEPRESETMODE_STANDARD_RANGING \ + ((VL53L1_DevicePresetModes) 1) +#define VL53L1_DEVICEPRESETMODE_STANDARD_RANGING_SHORT_RANGE \ + ((VL53L1_DevicePresetModes) 2) +#define VL53L1_DEVICEPRESETMODE_STANDARD_RANGING_LONG_RANGE \ + ((VL53L1_DevicePresetModes) 3) +#define VL53L1_DEVICEPRESETMODE_STANDARD_RANGING_MM1_CAL \ + ((VL53L1_DevicePresetModes) 4) +#define VL53L1_DEVICEPRESETMODE_STANDARD_RANGING_MM2_CAL \ + ((VL53L1_DevicePresetModes) 5) +#define VL53L1_DEVICEPRESETMODE_TIMED_RANGING \ + ((VL53L1_DevicePresetModes) 6) +#define VL53L1_DEVICEPRESETMODE_TIMED_RANGING_SHORT_RANGE \ + ((VL53L1_DevicePresetModes) 7) +#define VL53L1_DEVICEPRESETMODE_TIMED_RANGING_LONG_RANGE \ + ((VL53L1_DevicePresetModes) 8) +#define VL53L1_DEVICEPRESETMODE_NEAR_FARRANGING \ + ((VL53L1_DevicePresetModes) 9) +#define VL53L1_DEVICEPRESETMODE_QUADRANT_RANGING \ + ((VL53L1_DevicePresetModes) 10) +#define VL53L1_DEVICEPRESETMODE_HISTOGRAM_RANGING \ + ((VL53L1_DevicePresetModes) 11) +#define VL53L1_DEVICEPRESETMODE_HISTOGRAM_RANGING_SHORT_TIMING \ + ((VL53L1_DevicePresetModes) 12) +#define VL53L1_DEVICEPRESETMODE_HISTOGRAM_CHARACTERISATION \ + ((VL53L1_DevicePresetModes) 13) +#define VL53L1_DEVICEPRESETMODE_HISTOGRAM_XTALK_PLANAR \ + ((VL53L1_DevicePresetModes) 14) +#define VL53L1_DEVICEPRESETMODE_HISTOGRAM_XTALK_MM1 \ + ((VL53L1_DevicePresetModes) 15) +#define VL53L1_DEVICEPRESETMODE_HISTOGRAM_XTALK_MM2 \ + ((VL53L1_DevicePresetModes) 16) +#define VL53L1_DEVICEPRESETMODE_OLT \ + ((VL53L1_DevicePresetModes) 17) +#define VL53L1_DEVICEPRESETMODE_SINGLESHOT_RANGING \ + ((VL53L1_DevicePresetModes) 18) +#define VL53L1_DEVICEPRESETMODE_HISTOGRAM_REF_ARRAY \ + ((VL53L1_DevicePresetModes) 19) +#define VL53L1_DEVICEPRESETMODE_HISTOGRAM_RANGING_WITH_MM1 \ + ((VL53L1_DevicePresetModes) 20) +#define VL53L1_DEVICEPRESETMODE_HISTOGRAM_RANGING_WITH_MM2 \ + ((VL53L1_DevicePresetModes) 21) +#define VL53L1_DEVICEPRESETMODE_HISTOGRAM_RANGING_MM1_CAL \ + ((VL53L1_DevicePresetModes) 22) +#define VL53L1_DEVICEPRESETMODE_HISTOGRAM_RANGING_MM2_CAL \ + ((VL53L1_DevicePresetModes) 23) +#define VL53L1_DEVICEPRESETMODE_HISTOGRAM_MULTIZONE \ + ((VL53L1_DevicePresetModes) 24) +#define VL53L1_DEVICEPRESETMODE_HISTOGRAM_MULTIZONE_SHORT_RANGE \ + ((VL53L1_DevicePresetModes) 25) +#define VL53L1_DEVICEPRESETMODE_HISTOGRAM_MULTIZONE_LONG_RANGE \ + ((VL53L1_DevicePresetModes) 26) +#define VL53L1_DEVICEPRESETMODE_HISTOGRAM_LONG_RANGE \ + ((VL53L1_DevicePresetModes) 27) +#define VL53L1_DEVICEPRESETMODE_HISTOGRAM_LONG_RANGE_MM1 \ + ((VL53L1_DevicePresetModes) 28) +#define VL53L1_DEVICEPRESETMODE_HISTOGRAM_LONG_RANGE_MM2 \ + ((VL53L1_DevicePresetModes) 29) +#define VL53L1_DEVICEPRESETMODE_HISTOGRAM_MEDIUM_RANGE \ + ((VL53L1_DevicePresetModes) 30) +#define VL53L1_DEVICEPRESETMODE_HISTOGRAM_MEDIUM_RANGE_MM1 \ + ((VL53L1_DevicePresetModes) 31) +#define VL53L1_DEVICEPRESETMODE_HISTOGRAM_MEDIUM_RANGE_MM2 \ + ((VL53L1_DevicePresetModes) 32) +#define VL53L1_DEVICEPRESETMODE_HISTOGRAM_SHORT_RANGE \ + ((VL53L1_DevicePresetModes) 33) +#define VL53L1_DEVICEPRESETMODE_HISTOGRAM_SHORT_RANGE_MM1 \ + ((VL53L1_DevicePresetModes) 34) +#define VL53L1_DEVICEPRESETMODE_HISTOGRAM_SHORT_RANGE_MM2 \ + ((VL53L1_DevicePresetModes) 35) +#define VL53L1_DEVICEPRESETMODE_LOWPOWERAUTO_SHORT_RANGE \ + ((VL53L1_DevicePresetModes) 36) +#define VL53L1_DEVICEPRESETMODE_LOWPOWERAUTO_MEDIUM_RANGE \ + ((VL53L1_DevicePresetModes) 37) +#define VL53L1_DEVICEPRESETMODE_LOWPOWERAUTO_LONG_RANGE \ + ((VL53L1_DevicePresetModes) 38) +#define VL53L1_DEVICEPRESETMODE_SPECIAL_HISTOGRAM_SHORT_RANGE \ + ((VL53L1_DevicePresetModes) 39) + + + + + + + + + + + +typedef uint8_t VL53L1_DeviceMeasurementModes; + +#define VL53L1_DEVICEMEASUREMENTMODE_STOP \ + ((VL53L1_DeviceMeasurementModes) 0x00) +#define VL53L1_DEVICEMEASUREMENTMODE_SINGLESHOT \ + ((VL53L1_DeviceMeasurementModes) 0x10) +#define VL53L1_DEVICEMEASUREMENTMODE_BACKTOBACK \ + ((VL53L1_DeviceMeasurementModes) 0x20) +#define VL53L1_DEVICEMEASUREMENTMODE_TIMED \ + ((VL53L1_DeviceMeasurementModes) 0x40) +#define VL53L1_DEVICEMEASUREMENTMODE_ABORT \ + ((VL53L1_DeviceMeasurementModes) 0x80) + + + + + + + + + + + +typedef uint8_t VL53L1_OffsetCalibrationMode; + +#define VL53L1_OFFSETCALIBRATIONMODE__NONE \ + ((VL53L1_OffsetCalibrationMode) 0) +#define VL53L1_OFFSETCALIBRATIONMODE__MM1_MM2__STANDARD \ + ((VL53L1_OffsetCalibrationMode) 1) +#define VL53L1_OFFSETCALIBRATIONMODE__MM1_MM2__HISTOGRAM \ + ((VL53L1_OffsetCalibrationMode) 2) +#define VL53L1_OFFSETCALIBRATIONMODE__MM1_MM2__STANDARD_PRE_RANGE_ONLY \ + ((VL53L1_OffsetCalibrationMode) 3) +#define VL53L1_OFFSETCALIBRATIONMODE__MM1_MM2__HISTOGRAM_PRE_RANGE_ONLY \ + ((VL53L1_OffsetCalibrationMode) 4) +#define VL53L1_OFFSETCALIBRATIONMODE__PER_ZONE \ + ((VL53L1_OffsetCalibrationMode) 5) + + + + + + + + + + + +typedef uint8_t VL53L1_OffsetCorrectionMode; + +#define VL53L1_OFFSETCORRECTIONMODE__NONE \ + ((VL53L1_OffsetCorrectionMode) 0) +#define VL53L1_OFFSETCORRECTIONMODE__MM1_MM2_OFFSETS \ + ((VL53L1_OffsetCorrectionMode) 1) +#define VL53L1_OFFSETCORRECTIONMODE__PER_ZONE_OFFSETS \ + ((VL53L1_OffsetCorrectionMode) 2) +#define VL53L1_OFFSETCORRECTIONMODE__PER_VCSEL_OFFSETS \ + ((VL53L1_OffsetCorrectionMode) 3) + + + + + + + + + + + +typedef uint8_t VL53L1_DeviceDmaxMode; + +#define VL53L1_DEVICEDMAXMODE__NONE \ + ((VL53L1_DeviceDmaxMode) 0) +#define VL53L1_DEVICEDMAXMODE__FMT_CAL_DATA \ + ((VL53L1_DeviceDmaxMode) 1) +#define VL53L1_DEVICEDMAXMODE__CUST_CAL_DATA \ + ((VL53L1_DeviceDmaxMode) 2) +#define VL53L1_DEVICEDMAXMODE__PER_ZONE_CAL_DATA \ + ((VL53L1_DeviceDmaxMode) 3) + + + + + + + + + + + + +typedef uint8_t VL53L1_DeviceSequenceConfig; + +#define VL53L1_DEVICESEQUENCECONFIG_VHV \ + ((VL53L1_DeviceSequenceConfig) 0) +#define VL53L1_DEVICESEQUENCECONFIG_PHASECAL \ + ((VL53L1_DeviceSequenceConfig) 1) +#define VL53L1_DEVICESEQUENCECONFIG_REFERENCE_PHASE \ + ((VL53L1_DeviceSequenceConfig) 2) +#define VL53L1_DEVICESEQUENCECONFIG_DSS1 \ + ((VL53L1_DeviceSequenceConfig) 3) +#define VL53L1_DEVICESEQUENCECONFIG_DSS2 \ + ((VL53L1_DeviceSequenceConfig) 4) +#define VL53L1_DEVICESEQUENCECONFIG_MM1 \ + ((VL53L1_DeviceSequenceConfig) 5) +#define VL53L1_DEVICESEQUENCECONFIG_MM2 \ + ((VL53L1_DeviceSequenceConfig) 6) +#define VL53L1_DEVICESEQUENCECONFIG_RANGE \ + ((VL53L1_DeviceSequenceConfig) 7) + + + + + + + + + + + +typedef uint8_t VL53L1_DeviceInterruptPolarity; + +#define VL53L1_DEVICEINTERRUPTPOLARITY_ACTIVE_HIGH \ + ((VL53L1_DeviceInterruptPolarity) 0x00) +#define VL53L1_DEVICEINTERRUPTPOLARITY_ACTIVE_LOW \ + ((VL53L1_DeviceInterruptPolarity) 0x10) +#define VL53L1_DEVICEINTERRUPTPOLARITY_BIT_MASK \ + ((VL53L1_DeviceInterruptPolarity) 0x10) +#define VL53L1_DEVICEINTERRUPTPOLARITY_CLEAR_MASK \ + ((VL53L1_DeviceInterruptPolarity) 0xEF) + + + + + + + + + + + +typedef uint8_t VL53L1_DeviceGpioMode; + +#define VL53L1_DEVICEGPIOMODE_OUTPUT_CONSTANT_ZERO \ + ((VL53L1_DeviceGpioMode) 0x00) +#define VL53L1_DEVICEGPIOMODE_OUTPUT_RANGE_AND_ERROR_INTERRUPTS \ + ((VL53L1_DeviceGpioMode) 0x01) +#define VL53L1_DEVICEGPIOMODE_OUTPUT_TIMIER_INTERRUPTS \ + ((VL53L1_DeviceGpioMode) 0x02) +#define VL53L1_DEVICEGPIOMODE_OUTPUT_RANGE_MODE_INTERRUPT_STATUS \ + ((VL53L1_DeviceGpioMode) 0x03) +#define VL53L1_DEVICEGPIOMODE_OUTPUT_SLOW_OSCILLATOR_CLOCK \ + ((VL53L1_DeviceGpioMode) 0x04) +#define VL53L1_DEVICEGPIOMODE_BIT_MASK \ + ((VL53L1_DeviceGpioMode) 0x0F) +#define VL53L1_DEVICEGPIOMODE_CLEAR_MASK \ + ((VL53L1_DeviceGpioMode) 0xF0) + + + + + + + + + + + + + + + +typedef uint8_t VL53L1_DeviceError; + +#define VL53L1_DEVICEERROR_NOUPDATE \ + ((VL53L1_DeviceError) 0) + + +#define VL53L1_DEVICEERROR_VCSELCONTINUITYTESTFAILURE \ + ((VL53L1_DeviceError) 1) +#define VL53L1_DEVICEERROR_VCSELWATCHDOGTESTFAILURE \ + ((VL53L1_DeviceError) 2) +#define VL53L1_DEVICEERROR_NOVHVVALUEFOUND \ + ((VL53L1_DeviceError) 3) +#define VL53L1_DEVICEERROR_MSRCNOTARGET \ + ((VL53L1_DeviceError) 4) +#define VL53L1_DEVICEERROR_RANGEPHASECHECK \ + ((VL53L1_DeviceError) 5) +#define VL53L1_DEVICEERROR_SIGMATHRESHOLDCHECK \ + ((VL53L1_DeviceError) 6) +#define VL53L1_DEVICEERROR_PHASECONSISTENCY \ + ((VL53L1_DeviceError) 7) +#define VL53L1_DEVICEERROR_MINCLIP \ + ((VL53L1_DeviceError) 8) +#define VL53L1_DEVICEERROR_RANGECOMPLETE \ + ((VL53L1_DeviceError) 9) +#define VL53L1_DEVICEERROR_ALGOUNDERFLOW \ + ((VL53L1_DeviceError) 10) +#define VL53L1_DEVICEERROR_ALGOOVERFLOW \ + ((VL53L1_DeviceError) 11) +#define VL53L1_DEVICEERROR_RANGEIGNORETHRESHOLD \ + ((VL53L1_DeviceError) 12) +#define VL53L1_DEVICEERROR_USERROICLIP \ + ((VL53L1_DeviceError) 13) +#define VL53L1_DEVICEERROR_REFSPADCHARNOTENOUGHDPADS \ + ((VL53L1_DeviceError) 14) +#define VL53L1_DEVICEERROR_REFSPADCHARMORETHANTARGET \ + ((VL53L1_DeviceError) 15) +#define VL53L1_DEVICEERROR_REFSPADCHARLESSTHANTARGET \ + ((VL53L1_DeviceError) 16) +#define VL53L1_DEVICEERROR_MULTCLIPFAIL \ + ((VL53L1_DeviceError) 17) +#define VL53L1_DEVICEERROR_GPHSTREAMCOUNT0READY \ + ((VL53L1_DeviceError) 18) +#define VL53L1_DEVICEERROR_RANGECOMPLETE_NO_WRAP_CHECK \ + ((VL53L1_DeviceError) 19) +#define VL53L1_DEVICEERROR_EVENTCONSISTENCY \ + ((VL53L1_DeviceError) 20) +#define VL53L1_DEVICEERROR_MINSIGNALEVENTCHECK \ + ((VL53L1_DeviceError) 21) +#define VL53L1_DEVICEERROR_RANGECOMPLETE_MERGED_PULSE \ + ((VL53L1_DeviceError) 22) + + + +#define VL53L1_DEVICEERROR_PREV_RANGE_NO_TARGETS \ + ((VL53L1_DeviceError) 23) + + + + + + + + + + + +typedef uint8_t VL53L1_DeviceReportStatus; + +#define VL53L1_DEVICEREPORTSTATUS_NOUPDATE \ + ((VL53L1_DeviceReportStatus) 0) + + +#define VL53L1_DEVICEREPORTSTATUS_ROI_SETUP \ + ((VL53L1_DeviceReportStatus) 1) +#define VL53L1_DEVICEREPORTSTATUS_VHV \ + ((VL53L1_DeviceReportStatus) 2) +#define VL53L1_DEVICEREPORTSTATUS_PHASECAL \ + ((VL53L1_DeviceReportStatus) 3) +#define VL53L1_DEVICEREPORTSTATUS_REFERENCE_PHASE \ + ((VL53L1_DeviceReportStatus) 4) +#define VL53L1_DEVICEREPORTSTATUS_DSS1 \ + ((VL53L1_DeviceReportStatus) 5) +#define VL53L1_DEVICEREPORTSTATUS_DSS2 \ + ((VL53L1_DeviceReportStatus) 6) +#define VL53L1_DEVICEREPORTSTATUS_MM1 \ + ((VL53L1_DeviceReportStatus) 7) +#define VL53L1_DEVICEREPORTSTATUS_MM2 \ + ((VL53L1_DeviceReportStatus) 8) +#define VL53L1_DEVICEREPORTSTATUS_RANGE \ + ((VL53L1_DeviceReportStatus) 9) +#define VL53L1_DEVICEREPORTSTATUS_HISTOGRAM \ + ((VL53L1_DeviceReportStatus) 10) + + + + + + + + + + +typedef uint8_t VL53L1_DeviceDssMode; + +#define VL53L1_DEVICEDSSMODE__DISABLED \ + ((VL53L1_DeviceDssMode) 0) +#define VL53L1_DEVICEDSSMODE__TARGET_RATE \ + ((VL53L1_DeviceDssMode) 1) +#define VL53L1_DEVICEDSSMODE__REQUESTED_EFFFECTIVE_SPADS \ + ((VL53L1_DeviceDssMode) 2) +#define VL53L1_DEVICEDSSMODE__BLOCK_SELECT \ + ((VL53L1_DeviceDssMode) 3) + + + + + + + + + + + + +typedef uint8_t VL53L1_HistAlgoSelect; + +#define VL53L1_HIST_ALGO_SELECT__PW_HIST_GEN1 \ + ((VL53L1_HistAlgoSelect) 1) +#define VL53L1_HIST_ALGO_SELECT__PW_HIST_GEN2 \ + ((VL53L1_HistAlgoSelect) 2) +#define VL53L1_HIST_ALGO_SELECT__PW_HIST_GEN3 \ + ((VL53L1_HistAlgoSelect) 3) +#define VL53L1_HIST_ALGO_SELECT__PW_HIST_GEN4 \ + ((VL53L1_HistAlgoSelect) 4) + + + + + + + + + + + +typedef uint8_t VL53L1_HistTargetOrder; + +#define VL53L1_HIST_TARGET_ORDER__INCREASING_DISTANCE \ + ((VL53L1_HistTargetOrder) 1) +#define VL53L1_HIST_TARGET_ORDER__STRONGEST_FIRST \ + ((VL53L1_HistTargetOrder) 2) + + + + + + + + + + + +typedef uint8_t VL53L1_HistAmbEstMethod; + +#define VL53L1_HIST_AMB_EST_METHOD__AMBIENT_BINS \ + ((VL53L1_HistAmbEstMethod) 1) +#define VL53L1_HIST_AMB_EST_METHOD__THRESHOLDED_BINS \ + ((VL53L1_HistAmbEstMethod) 2) + + + + + + + + + + + + +typedef uint8_t VL53L1_HistXtalkCompEnable; + +#define VL53L1_HIST_XTALK_COMP__DIS \ + ((VL53L1_HistXtalkCompEnable) 0) +#define VL53L1_HIST_XTALK_COMP__EN \ + ((VL53L1_HistXtalkCompEnable) 1) + + + + + + + + + +typedef uint8_t VL53L1_DeviceConfigLevel; + +#define VL53L1_DEVICECONFIGLEVEL_SYSTEM_CONTROL \ + ((VL53L1_DeviceConfigLevel) 0) + + +#define VL53L1_DEVICECONFIGLEVEL_DYNAMIC_ONWARDS \ + ((VL53L1_DeviceConfigLevel) 1) + + +#define VL53L1_DEVICECONFIGLEVEL_TIMING_ONWARDS \ + ((VL53L1_DeviceConfigLevel) 2) + + + +#define VL53L1_DEVICECONFIGLEVEL_GENERAL_ONWARDS \ + ((VL53L1_DeviceConfigLevel) 3) + + + +#define VL53L1_DEVICECONFIGLEVEL_STATIC_ONWARDS \ + ((VL53L1_DeviceConfigLevel) 4) + + + +#define VL53L1_DEVICECONFIGLEVEL_CUSTOMER_ONWARDS \ + ((VL53L1_DeviceConfigLevel) 5) + + + +#define VL53L1_DEVICECONFIGLEVEL_FULL \ + ((VL53L1_DeviceConfigLevel) 6) + + + + + + + + + + + + + + +typedef uint8_t VL53L1_DeviceResultsLevel; + +#define VL53L1_DEVICERESULTSLEVEL_SYSTEM_RESULTS \ + ((VL53L1_DeviceResultsLevel) 0) + + +#define VL53L1_DEVICERESULTSLEVEL_UPTO_CORE \ + ((VL53L1_DeviceResultsLevel) 1) + + +#define VL53L1_DEVICERESULTSLEVEL_FULL \ + ((VL53L1_DeviceResultsLevel) 2) + + + + + + + + + + + + + + + +typedef uint8_t VL53L1_DeviceTestMode; + +#define VL53L1_DEVICETESTMODE_NONE \ + ((VL53L1_DeviceTestMode) 0x00) + + +#define VL53L1_DEVICETESTMODE_NVM_ZERO \ + ((VL53L1_DeviceTestMode) 0x01) + + +#define VL53L1_DEVICETESTMODE_NVM_COPY \ + ((VL53L1_DeviceTestMode) 0x02) + + +#define VL53L1_DEVICETESTMODE_PATCH \ + ((VL53L1_DeviceTestMode) 0x03) + + +#define VL53L1_DEVICETESTMODE_DCR \ + ((VL53L1_DeviceTestMode) 0x04) + + +#define VL53L1_DEVICETESTMODE_LCR_VCSEL_OFF \ + ((VL53L1_DeviceTestMode) 0x05) + + + +#define VL53L1_DEVICETESTMODE_LCR_VCSEL_ON \ + ((VL53L1_DeviceTestMode) 0x06) + + + +#define VL53L1_DEVICETESTMODE_SPOT_CENTRE_LOCATE \ + ((VL53L1_DeviceTestMode) 0x07) + + +#define VL53L1_DEVICETESTMODE_REF_SPAD_CHAR_WITH_PRE_VHV \ + ((VL53L1_DeviceTestMode) 0x08) + + +#define VL53L1_DEVICETESTMODE_REF_SPAD_CHAR_ONLY \ + ((VL53L1_DeviceTestMode) 0x09) + + + + + + + + + + + + + +typedef uint8_t VL53L1_DeviceSscArray; + +#define VL53L1_DEVICESSCARRAY_RTN ((VL53L1_DeviceSscArray) 0x00) + + +#define VL53L1_DEVICETESTMODE_REF ((VL53L1_DeviceSscArray) 0x01) + + + + + + + + + + + + + +#define VL53L1_RETURN_ARRAY_ONLY 0x01 + + +#define VL53L1_REFERENCE_ARRAY_ONLY 0x10 + + +#define VL53L1_BOTH_RETURN_AND_REFERENCE_ARRAYS 0x11 + + +#define VL53L1_NEITHER_RETURN_AND_REFERENCE_ARRAYS 0x00 + + + + + + + + + + + + +#define VL53L1_DEVICEINTERRUPTLEVEL_ACTIVE_HIGH 0x00 + + +#define VL53L1_DEVICEINTERRUPTLEVEL_ACTIVE_LOW 0x10 + + +#define VL53L1_DEVICEINTERRUPTLEVEL_ACTIVE_MASK 0x10 + + + + + + + + + + + + +#define VL53L1_POLLING_DELAY_US 1000 + + +#define VL53L1_SOFTWARE_RESET_DURATION_US 100 + + +#define VL53L1_FIRMWARE_BOOT_TIME_US 1200 + + + +#define VL53L1_ENABLE_POWERFORCE_SETTLING_TIME_US 250 + + + + +#define VL53L1_SPAD_ARRAY_WIDTH 16 + + +#define VL53L1_SPAD_ARRAY_HEIGHT 16 + + +#define VL53L1_NVM_SIZE_IN_BYTES 512 + + +#define VL53L1_NO_OF_SPAD_ENABLES 256 + + +#define VL53L1_RTN_SPAD_BUFFER_SIZE 32 + + +#define VL53L1_REF_SPAD_BUFFER_SIZE 6 + + +#define VL53L1_AMBIENT_WINDOW_VCSEL_PERIODS 256 + + +#define VL53L1_RANGING_WINDOW_VCSEL_PERIODS 2048 + + +#define VL53L1_MACRO_PERIOD_VCSEL_PERIODS \ + (VL53L1_AMBIENT_WINDOW_VCSEL_PERIODS + \ + VL53L1_RANGING_WINDOW_VCSEL_PERIODS) + + +#define VL53L1_MAX_ALLOWED_PHASE 0xFFFF + + + +#define VL53L1_RTN_SPAD_UNITY_TRANSMISSION 0x0100 + + +#define VL53L1_RTN_SPAD_APERTURE_TRANSMISSION 0x0038 + + + + + +#define VL53L1_SPAD_TOTAL_COUNT_MAX ((0x01 << 29) - 1) + + +#define VL53L1_SPAD_TOTAL_COUNT_RES_THRES (0x01 << 24) + + +#define VL53L1_COUNT_RATE_INTERNAL_MAX ((0x01 << 24) - 1) + + +#define VL53L1_SPEED_OF_LIGHT_IN_AIR 299704 + + +#define VL53L1_SPEED_OF_LIGHT_IN_AIR_DIV_8 (299704 >> 3) + + + + + + + + + + + + + + + + +typedef uint8_t VL53L1_ZoneConfig_BinConfig_select; + +#define VL53L1_ZONECONFIG_BINCONFIG__LOWAMB \ + ((VL53L1_ZoneConfig_BinConfig_select) 1) +#define VL53L1_ZONECONFIG_BINCONFIG__MIDAMB \ + ((VL53L1_ZoneConfig_BinConfig_select) 2) +#define VL53L1_ZONECONFIG_BINCONFIG__HIGHAMB \ + ((VL53L1_ZoneConfig_BinConfig_select) 3) + + + + + + + + + + +typedef uint8_t VL53L1_GPIO_Interrupt_Mode; + +#define VL53L1_GPIOINTMODE_LEVEL_LOW \ + ((VL53L1_GPIO_Interrupt_Mode) 0) + + +#define VL53L1_GPIOINTMODE_LEVEL_HIGH \ + ((VL53L1_GPIO_Interrupt_Mode) 1) + + +#define VL53L1_GPIOINTMODE_OUT_OF_WINDOW \ + ((VL53L1_GPIO_Interrupt_Mode) 2) + + +#define VL53L1_GPIOINTMODE_IN_WINDOW \ + ((VL53L1_GPIO_Interrupt_Mode) 3) + + + + + + + + + + + + + +typedef uint16_t VL53L1_TuningParms; + +#define VL53L1_TUNINGPARMS_LLD_PUBLIC_MIN_ADDRESS \ + ((VL53L1_TuningParms) VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS) +#define VL53L1_TUNINGPARMS_LLD_PUBLIC_MAX_ADDRESS \ + ((VL53L1_TuningParms) VL53L1_TUNINGPARM_HIST_MERGE_MAX_SIZE) + +#define VL53L1_TUNINGPARMS_LLD_PRIVATE_MIN_ADDRESS \ + ((VL53L1_TuningParms) VL53L1_TUNINGPARM_PRIVATE_PAGE_BASE_ADDRESS) +#define VL53L1_TUNINGPARMS_LLD_PRIVATE_MAX_ADDRESS \ + ((VL53L1_TuningParms) VL53L1_TUNINGPARMS_LLD_PRIVATE_MIN_ADDRESS) + +#define VL53L1_TUNINGPARM_VERSION \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 0)) +#define VL53L1_TUNINGPARM_KEY_TABLE_VERSION \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 1)) +#define VL53L1_TUNINGPARM_LLD_VERSION \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 2)) +#define VL53L1_TUNINGPARM_HIST_ALGO_SELECT \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 3)) +#define VL53L1_TUNINGPARM_HIST_TARGET_ORDER \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 4)) +#define VL53L1_TUNINGPARM_HIST_FILTER_WOI_0 \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 5)) +#define VL53L1_TUNINGPARM_HIST_FILTER_WOI_1 \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 6)) +#define VL53L1_TUNINGPARM_HIST_AMB_EST_METHOD \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 7)) +#define VL53L1_TUNINGPARM_HIST_AMB_THRESH_SIGMA_0 \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 8)) +#define VL53L1_TUNINGPARM_HIST_AMB_THRESH_SIGMA_1 \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 9)) +#define VL53L1_TUNINGPARM_HIST_MIN_AMB_THRESH_EVENTS \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 10)) +#define VL53L1_TUNINGPARM_HIST_AMB_EVENTS_SCALER \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 11)) +#define VL53L1_TUNINGPARM_HIST_NOISE_THRESHOLD \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 12)) +#define VL53L1_TUNINGPARM_HIST_SIGNAL_TOTAL_EVENTS_LIMIT \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 13)) +#define VL53L1_TUNINGPARM_HIST_SIGMA_EST_REF_MM \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 14)) +#define VL53L1_TUNINGPARM_HIST_SIGMA_THRESH_MM \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 15)) +#define VL53L1_TUNINGPARM_HIST_GAIN_FACTOR \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 16)) +#define VL53L1_TUNINGPARM_CONSISTENCY_HIST_PHASE_TOLERANCE \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 17)) +#define VL53L1_TUNINGPARM_CONSISTENCY_HIST_MIN_MAX_TOLERANCE_MM \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 18)) +#define VL53L1_TUNINGPARM_CONSISTENCY_HIST_EVENT_SIGMA \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 19)) +#define VL53L1_TUNINGPARM_CONSISTENCY_HIST_EVENT_SIGMA_MIN_SPAD_LIMIT \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 20)) +#define VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_HISTO_LONG_RANGE \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 21)) +#define VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_HISTO_MED_RANGE \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 22)) +#define VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_HISTO_SHORT_RANGE \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 23)) +#define VL53L1_TUNINGPARM_INITIAL_PHASE_REF_HISTO_LONG_RANGE \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 24)) +#define VL53L1_TUNINGPARM_INITIAL_PHASE_REF_HISTO_MED_RANGE \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 25)) +#define VL53L1_TUNINGPARM_INITIAL_PHASE_REF_HISTO_SHORT_RANGE \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 26)) +#define VL53L1_TUNINGPARM_XTALK_DETECT_MIN_VALID_RANGE_MM \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 27)) +#define VL53L1_TUNINGPARM_XTALK_DETECT_MAX_VALID_RANGE_MM \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 28)) +#define VL53L1_TUNINGPARM_XTALK_DETECT_MAX_SIGMA_MM \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 29)) +#define VL53L1_TUNINGPARM_XTALK_DETECT_MIN_MAX_TOLERANCE \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 30)) +#define VL53L1_TUNINGPARM_XTALK_DETECT_MAX_VALID_RATE_KCPS \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 31)) +#define VL53L1_TUNINGPARM_XTALK_DETECT_EVENT_SIGMA \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 32)) +#define VL53L1_TUNINGPARM_HIST_XTALK_MARGIN_KCPS \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 33)) +#define VL53L1_TUNINGPARM_CONSISTENCY_LITE_PHASE_TOLERANCE \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 34)) +#define VL53L1_TUNINGPARM_PHASECAL_TARGET \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 35)) +#define VL53L1_TUNINGPARM_LITE_CAL_REPEAT_RATE \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 36)) +#define VL53L1_TUNINGPARM_LITE_RANGING_GAIN_FACTOR \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 37)) +#define VL53L1_TUNINGPARM_LITE_MIN_CLIP_MM \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 38)) +#define VL53L1_TUNINGPARM_LITE_LONG_SIGMA_THRESH_MM \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 39)) +#define VL53L1_TUNINGPARM_LITE_MED_SIGMA_THRESH_MM \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 40)) +#define VL53L1_TUNINGPARM_LITE_SHORT_SIGMA_THRESH_MM \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 41)) +#define VL53L1_TUNINGPARM_LITE_LONG_MIN_COUNT_RATE_RTN_MCPS \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 42)) +#define VL53L1_TUNINGPARM_LITE_MED_MIN_COUNT_RATE_RTN_MCPS \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 43)) +#define VL53L1_TUNINGPARM_LITE_SHORT_MIN_COUNT_RATE_RTN_MCPS \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 44)) +#define VL53L1_TUNINGPARM_LITE_SIGMA_EST_PULSE_WIDTH \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 45)) +#define VL53L1_TUNINGPARM_LITE_SIGMA_EST_AMB_WIDTH_NS \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 46)) +#define VL53L1_TUNINGPARM_LITE_SIGMA_REF_MM \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 47)) +#define VL53L1_TUNINGPARM_LITE_RIT_MULT \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 48)) +#define VL53L1_TUNINGPARM_LITE_SEED_CONFIG \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 49)) +#define VL53L1_TUNINGPARM_LITE_QUANTIFIER \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 50)) +#define VL53L1_TUNINGPARM_LITE_FIRST_ORDER_SELECT \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 51)) +#define VL53L1_TUNINGPARM_LITE_XTALK_MARGIN_KCPS \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 52)) +#define VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_LITE_LONG_RANGE \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 53)) +#define VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_LITE_MED_RANGE \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 54)) +#define VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_LITE_SHORT_RANGE \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 55)) +#define VL53L1_TUNINGPARM_INITIAL_PHASE_REF_LITE_LONG_RANGE \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 56)) +#define VL53L1_TUNINGPARM_INITIAL_PHASE_REF_LITE_MED_RANGE \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 57)) +#define VL53L1_TUNINGPARM_INITIAL_PHASE_REF_LITE_SHORT_RANGE \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 58)) +#define VL53L1_TUNINGPARM_TIMED_SEED_CONFIG \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 59)) +#define VL53L1_TUNINGPARM_DMAX_CFG_SIGNAL_THRESH_SIGMA \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 60)) +#define VL53L1_TUNINGPARM_DMAX_CFG_REFLECTANCE_ARRAY_0 \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 61)) +#define VL53L1_TUNINGPARM_DMAX_CFG_REFLECTANCE_ARRAY_1 \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 62)) +#define VL53L1_TUNINGPARM_DMAX_CFG_REFLECTANCE_ARRAY_2 \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 63)) +#define VL53L1_TUNINGPARM_DMAX_CFG_REFLECTANCE_ARRAY_3 \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 64)) +#define VL53L1_TUNINGPARM_DMAX_CFG_REFLECTANCE_ARRAY_4 \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 65)) +#define VL53L1_TUNINGPARM_VHV_LOOPBOUND \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 66)) +#define VL53L1_TUNINGPARM_REFSPADCHAR_DEVICE_TEST_MODE \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 67)) +#define VL53L1_TUNINGPARM_REFSPADCHAR_VCSEL_PERIOD \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 68)) +#define VL53L1_TUNINGPARM_REFSPADCHAR_PHASECAL_TIMEOUT_US \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 69)) +#define VL53L1_TUNINGPARM_REFSPADCHAR_TARGET_COUNT_RATE_MCPS \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 70)) +#define VL53L1_TUNINGPARM_REFSPADCHAR_MIN_COUNTRATE_LIMIT_MCPS \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 71)) +#define VL53L1_TUNINGPARM_REFSPADCHAR_MAX_COUNTRATE_LIMIT_MCPS \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 72)) +#define VL53L1_TUNINGPARM_XTALK_EXTRACT_NUM_OF_SAMPLES \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 73)) +#define VL53L1_TUNINGPARM_XTALK_EXTRACT_MIN_FILTER_THRESH_MM \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 74)) +#define VL53L1_TUNINGPARM_XTALK_EXTRACT_MAX_FILTER_THRESH_MM \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 75)) +#define VL53L1_TUNINGPARM_XTALK_EXTRACT_DSS_RATE_MCPS \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 76)) +#define VL53L1_TUNINGPARM_XTALK_EXTRACT_PHASECAL_TIMEOUT_US \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 77)) +#define VL53L1_TUNINGPARM_XTALK_EXTRACT_MAX_VALID_RATE_KCPS \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 78)) +#define VL53L1_TUNINGPARM_XTALK_EXTRACT_SIGMA_THRESHOLD_MM \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 79)) +#define VL53L1_TUNINGPARM_XTALK_EXTRACT_DSS_TIMEOUT_US \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 80)) +#define VL53L1_TUNINGPARM_XTALK_EXTRACT_BIN_TIMEOUT_US \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 81)) +#define VL53L1_TUNINGPARM_OFFSET_CAL_DSS_RATE_MCPS \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 82)) +#define VL53L1_TUNINGPARM_OFFSET_CAL_PHASECAL_TIMEOUT_US \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 83)) +#define VL53L1_TUNINGPARM_OFFSET_CAL_MM_TIMEOUT_US \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 84)) +#define VL53L1_TUNINGPARM_OFFSET_CAL_RANGE_TIMEOUT_US \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 85)) +#define VL53L1_TUNINGPARM_OFFSET_CAL_PRE_SAMPLES \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 86)) +#define VL53L1_TUNINGPARM_OFFSET_CAL_MM1_SAMPLES \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 87)) +#define VL53L1_TUNINGPARM_OFFSET_CAL_MM2_SAMPLES \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 88)) +#define VL53L1_TUNINGPARM_ZONE_CAL_DSS_RATE_MCPS \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 89)) +#define VL53L1_TUNINGPARM_ZONE_CAL_PHASECAL_TIMEOUT_US \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 90)) +#define VL53L1_TUNINGPARM_ZONE_CAL_DSS_TIMEOUT_US \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 91)) +#define VL53L1_TUNINGPARM_ZONE_CAL_PHASECAL_NUM_SAMPLES \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 92)) +#define VL53L1_TUNINGPARM_ZONE_CAL_RANGE_TIMEOUT_US \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 93)) +#define VL53L1_TUNINGPARM_ZONE_CAL_ZONE_NUM_SAMPLES \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 94)) +#define VL53L1_TUNINGPARM_SPADMAP_VCSEL_PERIOD \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 95)) +#define VL53L1_TUNINGPARM_SPADMAP_VCSEL_START \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 96)) +#define VL53L1_TUNINGPARM_SPADMAP_RATE_LIMIT_MCPS \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 97)) +#define VL53L1_TUNINGPARM_LITE_DSS_CONFIG_TARGET_TOTAL_RATE_MCPS \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 98)) +#define VL53L1_TUNINGPARM_RANGING_DSS_CONFIG_TARGET_TOTAL_RATE_MCPS \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 99)) +#define VL53L1_TUNINGPARM_MZ_DSS_CONFIG_TARGET_TOTAL_RATE_MCPS \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 100)) +#define VL53L1_TUNINGPARM_TIMED_DSS_CONFIG_TARGET_TOTAL_RATE_MCPS \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 101)) +#define VL53L1_TUNINGPARM_LITE_PHASECAL_CONFIG_TIMEOUT_US \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 102)) +#define VL53L1_TUNINGPARM_RANGING_LONG_PHASECAL_CONFIG_TIMEOUT_US \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 103)) +#define VL53L1_TUNINGPARM_RANGING_MED_PHASECAL_CONFIG_TIMEOUT_US \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 104)) +#define VL53L1_TUNINGPARM_RANGING_SHORT_PHASECAL_CONFIG_TIMEOUT_US \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 105)) +#define VL53L1_TUNINGPARM_MZ_LONG_PHASECAL_CONFIG_TIMEOUT_US \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 106)) +#define VL53L1_TUNINGPARM_MZ_MED_PHASECAL_CONFIG_TIMEOUT_US \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 107)) +#define VL53L1_TUNINGPARM_MZ_SHORT_PHASECAL_CONFIG_TIMEOUT_US \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 108)) +#define VL53L1_TUNINGPARM_TIMED_PHASECAL_CONFIG_TIMEOUT_US \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 109)) +#define VL53L1_TUNINGPARM_LITE_MM_CONFIG_TIMEOUT_US \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 110)) +#define VL53L1_TUNINGPARM_RANGING_MM_CONFIG_TIMEOUT_US \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 111)) +#define VL53L1_TUNINGPARM_MZ_MM_CONFIG_TIMEOUT_US \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 112)) +#define VL53L1_TUNINGPARM_TIMED_MM_CONFIG_TIMEOUT_US \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 113)) +#define VL53L1_TUNINGPARM_LITE_RANGE_CONFIG_TIMEOUT_US \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 114)) +#define VL53L1_TUNINGPARM_RANGING_RANGE_CONFIG_TIMEOUT_US \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 115)) +#define VL53L1_TUNINGPARM_MZ_RANGE_CONFIG_TIMEOUT_US \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 116)) +#define VL53L1_TUNINGPARM_TIMED_RANGE_CONFIG_TIMEOUT_US \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 117)) +#define VL53L1_TUNINGPARM_DYNXTALK_SMUDGE_MARGIN \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 118)) +#define VL53L1_TUNINGPARM_DYNXTALK_NOISE_MARGIN \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 119)) +#define VL53L1_TUNINGPARM_DYNXTALK_XTALK_OFFSET_LIMIT \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 120)) +#define VL53L1_TUNINGPARM_DYNXTALK_XTALK_OFFSET_LIMIT_HI \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 121)) +#define VL53L1_TUNINGPARM_DYNXTALK_SAMPLE_LIMIT \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 122)) +#define VL53L1_TUNINGPARM_DYNXTALK_SINGLE_XTALK_DELTA \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 123)) +#define VL53L1_TUNINGPARM_DYNXTALK_AVERAGED_XTALK_DELTA \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 124)) +#define VL53L1_TUNINGPARM_DYNXTALK_CLIP_LIMIT \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 125)) +#define VL53L1_TUNINGPARM_DYNXTALK_SCALER_CALC_METHOD \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 126)) +#define VL53L1_TUNINGPARM_DYNXTALK_XGRADIENT_SCALER \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 127)) +#define VL53L1_TUNINGPARM_DYNXTALK_YGRADIENT_SCALER \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 128)) +#define VL53L1_TUNINGPARM_DYNXTALK_USER_SCALER_SET \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 129)) +#define VL53L1_TUNINGPARM_DYNXTALK_SMUDGE_COR_SINGLE_APPLY \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 130)) +#define VL53L1_TUNINGPARM_DYNXTALK_XTALK_AMB_THRESHOLD \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 131)) +#define VL53L1_TUNINGPARM_DYNXTALK_NODETECT_AMB_THRESHOLD_KCPS \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 132)) +#define VL53L1_TUNINGPARM_DYNXTALK_NODETECT_SAMPLE_LIMIT \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 133)) +#define VL53L1_TUNINGPARM_DYNXTALK_NODETECT_XTALK_OFFSET_KCPS \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 134)) +#define VL53L1_TUNINGPARM_DYNXTALK_NODETECT_MIN_RANGE_MM \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 135)) +#define VL53L1_TUNINGPARM_LOWPOWERAUTO_VHV_LOOP_BOUND \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 136)) +#define VL53L1_TUNINGPARM_LOWPOWERAUTO_MM_CONFIG_TIMEOUT_US \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 137)) +#define VL53L1_TUNINGPARM_LOWPOWERAUTO_RANGE_CONFIG_TIMEOUT_US \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 138)) +#define VL53L1_TUNINGPARM_VERY_SHORT_DSS_RATE_MCPS \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 139)) +#define VL53L1_TUNINGPARM_PHASECAL_PATCH_POWER \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 140)) +#define VL53L1_TUNINGPARM_HIST_MERGE \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 141)) +#define VL53L1_TUNINGPARM_RESET_MERGE_THRESHOLD \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 142)) +#define VL53L1_TUNINGPARM_HIST_MERGE_MAX_SIZE \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 143)) + + + + + + +#endif + + + + + + diff --git a/drivers/input/misc/vl53L1/kona/inc/vl53l1_nvm.h b/drivers/input/misc/vl53L1/kona/inc/vl53l1_nvm.h new file mode 100644 index 000000000000..fc297c7f046e --- /dev/null +++ b/drivers/input/misc/vl53L1/kona/inc/vl53l1_nvm.h @@ -0,0 +1,459 @@ + +/******************************************************************************* + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#ifndef _VL53L1_NVM_H_ +#define _VL53L1_NVM_H_ + +#include "vl53l1_ll_def.h" +#include "vl53l1_platform.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +#define VL53L1_NVM_POWER_UP_DELAY_US 50 +#define VL53L1_NVM_READ_TRIGGER_DELAY_US 5 + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_nvm_enable( + VL53L1_DEV Dev, + uint16_t nvm_ctrl_pulse_width, + int32_t nvm_power_up_delay_us); + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_nvm_read( + VL53L1_DEV Dev, + uint8_t start_address, + uint8_t count, + uint8_t *pdata); + + + + + + + + + + + + + + +VL53L1_Error VL53L1_nvm_disable( + VL53L1_DEV Dev); + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_nvm_format_decode( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_decoded_nvm_data_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_nvm_decode_optical_centre( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_optical_centre_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_nvm_decode_cal_peak_rate_map( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_cal_peak_rate_map_t *pdata); + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_nvm_decode_additional_offset_cal_data( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_additional_offset_cal_data_t *pdata); + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_nvm_decode_fmt_range_results_data( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_decoded_nvm_fmt_range_data_t *pdata); + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_nvm_decode_fmt_info( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_decoded_nvm_fmt_info_t *pdata); + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_nvm_decode_ews_info( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_decoded_nvm_ews_info_t *pdata); + + + + + + + + + + + + + + +void VL53L1_nvm_format_encode( + VL53L1_decoded_nvm_data_t *pnvm_info, + uint8_t *pnvm_data); + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_read_nvm_raw_data( + VL53L1_DEV Dev, + uint8_t start_address, + uint8_t count, + uint8_t *pnvm_raw_data); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_read_nvm( + VL53L1_DEV Dev, + uint8_t nvm_format, + VL53L1_decoded_nvm_data_t *pnvm_info); + + + + + + + + + + + + + +VL53L1_Error VL53L1_read_nvm_optical_centre( + VL53L1_DEV Dev, + VL53L1_optical_centre_t *pcentre); + + + + + + + + + + + + + +VL53L1_Error VL53L1_read_nvm_cal_peak_rate_map( + VL53L1_DEV Dev, + VL53L1_cal_peak_rate_map_t *pcal_data); + + + + + + + + + + + + + +VL53L1_Error VL53L1_read_nvm_additional_offset_cal_data( + VL53L1_DEV Dev, + VL53L1_additional_offset_cal_data_t *pcal_data); + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_read_nvm_fmt_range_results_data( + VL53L1_DEV Dev, + uint16_t range_results_select, + VL53L1_decoded_nvm_fmt_range_data_t *prange_data); + + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/drivers/input/misc/vl53L1/kona/inc/vl53l1_nvm_debug.h b/drivers/input/misc/vl53L1/kona/inc/vl53l1_nvm_debug.h new file mode 100644 index 000000000000..755fc76cb835 --- /dev/null +++ b/drivers/input/misc/vl53L1/kona/inc/vl53l1_nvm_debug.h @@ -0,0 +1,202 @@ + +/******************************************************************************* + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#ifndef _VL53L1_NVM_DEBUG_H_ +#define _VL53L1_NVM_DEBUG_H_ + +#include "vl53l1_ll_def.h" +#include "vl53l1_nvm_structs.h" + + + +#ifdef __cplusplus +extern "C" +{ +#endif + +#ifdef VL53L1_LOG_ENABLE + + + + + + + + + + + + +void VL53L1_print_nvm_raw_data( + uint8_t *pnvm_raw_data, + uint32_t trace_flags); + + + + + + + + + + + + +void VL53L1_print_decoded_nvm_data( + VL53L1_decoded_nvm_data_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + + + + + + + + + +void VL53L1_print_decoded_nvm_fmt_range_data( + VL53L1_decoded_nvm_fmt_range_data_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + + + + + + + + + +void VL53L1_print_decoded_nvm_fmt_info( + VL53L1_decoded_nvm_fmt_info_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + + + + + + + + +void VL53L1_print_decoded_nvm_ews_info( + VL53L1_decoded_nvm_ews_info_t *pdata, + char *pprefix, + uint32_t trace_flags); + +#endif + + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/drivers/input/misc/vl53L1/kona/inc/vl53l1_nvm_map.h b/drivers/input/misc/vl53L1/kona/inc/vl53l1_nvm_map.h new file mode 100644 index 000000000000..b79219dc2c94 --- /dev/null +++ b/drivers/input/misc/vl53L1/kona/inc/vl53l1_nvm_map.h @@ -0,0 +1,3254 @@ + +/******************************************************************************* + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#ifndef _VL53L1_NVM_MAP_H_ +#define _VL53L1_NVM_MAP_H_ + + +#ifdef __cplusplus +extern "C" +{ +#endif + + + + + + + +#define VL53L1_NVM__IDENTIFICATION__MODEL_ID 0x0008 + + + + + + + + + + + + + + + +#define VL53L1_NVM__IDENTIFICATION__MODULE_TYPE 0x000C + + + + + + + + + + + + + + + +#define VL53L1_NVM__IDENTIFICATION__REVISION_ID 0x000D + + + + + + + + + + + + + + + +#define VL53L1_NVM__IDENTIFICATION__MODULE_ID 0x000E + + + + + + + + + + + + + + + +#define VL53L1_NVM__I2C_VALID 0x0010 + + + + + + + + + + + + + + + +#define VL53L1_NVM__I2C_SLAVE__DEVICE_ADDRESS 0x0011 + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__OSC_MEASURED__FAST_OSC_FREQUENCY 0x0014 + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__FAST_OSC_TRIM_MAX 0x0016 + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__FAST_OSC_FREQ_SET 0x0017 + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SLOW_OSC_CALIBRATION 0x0018 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__OSC_MEASURED__FAST_OSC_FREQUENCY 0x001C + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__FAST_OSC_TRIM_MAX 0x001E + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__FAST_OSC_FREQ_SET 0x001F + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SLOW_OSC_CALIBRATION 0x0020 + + + + + + + + + + + + + + + +#define VL53L1_NVM__VHV_CONFIG_UNLOCK 0x0028 + + + + + + + + + + + + + + + +#define VL53L1_NVM__REF_SELVDDPIX 0x0029 + + + + + + + + + + + + + + + +#define VL53L1_NVM__REF_SELVQUENCH 0x002A + + + + + + + + + + + + + + + +#define VL53L1_NVM__REGAVDD1V2_SEL_REGDVDD1V2_SEL 0x002B + + + + + + + + + + + + + + + + +#define VL53L1_NVM__VHV_CONFIG__TIMEOUT_MACROP_LOOP_BOUND 0x002C + + + + + + + + + + + + + + + + +#define VL53L1_NVM__VHV_CONFIG__COUNT_THRESH 0x002D + + + + + + + + + + + + + + + +#define VL53L1_NVM__VHV_CONFIG__OFFSET 0x002E + + + + + + + + + + + + + + + +#define VL53L1_NVM__VHV_CONFIG__INIT 0x002F + + + + + + + + + + + + + + + + +#define VL53L1_NVM__LASER_SAFETY__VCSEL_TRIM_LL 0x0030 + + + + + + + + + + + + + + + +#define VL53L1_NVM__LASER_SAFETY__VCSEL_SELION_LL 0x0031 + + + + + + + + + + + + + + + +#define VL53L1_NVM__LASER_SAFETY__VCSEL_SELION_MAX_LL 0x0032 + + + + + + + + + + + + + + + +#define VL53L1_NVM__LASER_SAFETY__MULT_LL 0x0034 + + + + + + + + + + + + + + + +#define VL53L1_NVM__LASER_SAFETY__CLIP_LL 0x0035 + + + + + + + + + + + + + + + +#define VL53L1_NVM__LASER_SAFETY__VCSEL_TRIM_LD 0x0038 + + + + + + + + + + + + + + + +#define VL53L1_NVM__LASER_SAFETY__VCSEL_SELION_LD 0x0039 + + + + + + + + + + + + + + + +#define VL53L1_NVM__LASER_SAFETY__VCSEL_SELION_MAX_LD 0x003A + + + + + + + + + + + + + + + +#define VL53L1_NVM__LASER_SAFETY__MULT_LD 0x003C + + + + + + + + + + + + + + + +#define VL53L1_NVM__LASER_SAFETY__CLIP_LD 0x003D + + + + + + + + + + + + + + + +#define VL53L1_NVM__LASER_SAFETY_LOCK_BYTE 0x0040 + + + + + + + + + + + + + + + +#define VL53L1_NVM__LASER_SAFETY_UNLOCK_BYTE 0x0044 + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_0_ 0x0048 + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_1_ 0x0049 + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_2_ 0x004A + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_3_ 0x004B + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_4_ 0x004C + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_5_ 0x004D + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_6_ 0x004E + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_7_ 0x004F + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_8_ 0x0050 + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_9_ 0x0051 + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_10_ 0x0052 + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_11_ 0x0053 + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_12_ 0x0054 + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_13_ 0x0055 + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_14_ 0x0056 + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_15_ 0x0057 + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_16_ 0x0058 + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_17_ 0x0059 + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_18_ 0x005A + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_19_ 0x005B + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_20_ 0x005C + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_21_ 0x005D + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_22_ 0x005E + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_23_ 0x005F + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_24_ 0x0060 + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_25_ 0x0061 + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_26_ 0x0062 + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_27_ 0x0063 + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_28_ 0x0064 + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_29_ 0x0065 + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_30_ 0x0066 + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_31_ 0x0067 + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_REF__LOC1_0_ 0x0068 + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_REF__LOC1_1_ 0x0069 + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_REF__LOC1_2_ 0x006A + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_REF__LOC1_3_ 0x006B + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_REF__LOC1_4_ 0x006C + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_REF__LOC1_5_ 0x006D + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_REF__LOC2_0_ 0x0070 + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_REF__LOC2_1_ 0x0071 + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_REF__LOC2_2_ 0x0072 + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_REF__LOC2_3_ 0x0073 + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_REF__LOC2_4_ 0x0074 + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_REF__LOC2_5_ 0x0075 + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_REF__LOC3_0_ 0x0078 + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_REF__LOC3_1_ 0x0079 + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_REF__LOC3_2_ 0x007A + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_REF__LOC3_3_ 0x007B + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_REF__LOC3_4_ 0x007C + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_REF__LOC3_5_ 0x007D + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_0_ 0x0080 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_1_ 0x0081 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_2_ 0x0082 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_3_ 0x0083 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_4_ 0x0084 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_5_ 0x0085 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_6_ 0x0086 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_7_ 0x0087 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_8_ 0x0088 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_9_ 0x0089 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_10_ 0x008A + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_11_ 0x008B + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_12_ 0x008C + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_13_ 0x008D + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_14_ 0x008E + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_15_ 0x008F + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_16_ 0x0090 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_17_ 0x0091 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_18_ 0x0092 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_19_ 0x0093 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_20_ 0x0094 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_21_ 0x0095 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_22_ 0x0096 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_23_ 0x0097 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_24_ 0x0098 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_25_ 0x0099 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_26_ 0x009A + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_27_ 0x009B + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_28_ 0x009C + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_29_ 0x009D + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_30_ 0x009E + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_31_ 0x009F + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_REF__LOC1_0_ 0x00A0 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_REF__LOC1_1_ 0x00A1 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_REF__LOC1_2_ 0x00A2 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_REF__LOC1_3_ 0x00A3 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_REF__LOC1_4_ 0x00A4 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_REF__LOC1_5_ 0x00A5 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_REF__LOC2_0_ 0x00A8 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_REF__LOC2_1_ 0x00A9 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_REF__LOC2_2_ 0x00AA + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_REF__LOC2_3_ 0x00AB + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_REF__LOC2_4_ 0x00AC + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_REF__LOC2_5_ 0x00AD + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_REF__LOC3_0_ 0x00B0 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_REF__LOC3_1_ 0x00B1 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_REF__LOC3_2_ 0x00B2 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_REF__LOC3_3_ 0x00B3 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_REF__LOC3_4_ 0x00B4 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_REF__LOC3_5_ 0x00B5 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__ROI_CONFIG__MODE_ROI_CENTRE_SPAD 0x00B8 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__ROI_CONFIG__MODE_ROI_XY_SIZE 0x00B9 + + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__REF_SPAD_APPLY__NUM_REQUESTED_REF_SPAD 0x00BC + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__REF_SPAD_MAN__REF_LOCATION 0x00BD + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__MM_CONFIG__INNER_OFFSET_MM 0x00C0 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__MM_CONFIG__OUTER_OFFSET_MM 0x00C2 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__ALGO__PART_TO_PART_RANGE_OFFSET_MM 0x00C4 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__ALGO__CROSSTALK_COMPENSATION_PLANE_OFFSET_KCPS 0x00C8 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__ALGO__CROSSTALK_COMPENSATION_X_PLANE_GRADIENT_KCPS \ + 0x00CA + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__ALGO__CROSSTALK_COMPENSATION_Y_PLANE_GRADIENT_KCPS \ + 0x00CC + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPARE_HOST_CONFIG__NVM_CONFIG_SPARE_0 0x00CE + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPARE_HOST_CONFIG__NVM_CONFIG_SPARE_1 0x00CF + + + + + + + + + + + + + + + +#define VL53L1_NVM__CUSTOMER_NVM_SPACE_PROGRAMMED 0x00E0 + + + + + + + + + + + + + + + +#define VL53L1_NVM__CUST__I2C_SLAVE__DEVICE_ADDRESS 0x00E4 + + + + + + + + + + + + + + + +#define VL53L1_NVM__CUST__REF_SPAD_APPLY__NUM_REQUESTED_REF_SPAD 0x00E8 + + + + + + + + + + + + + + + +#define VL53L1_NVM__CUST__REF_SPAD_MAN__REF_LOCATION 0x00E9 + + + + + + + + + + + + + + + +#define VL53L1_NVM__CUST__MM_CONFIG__INNER_OFFSET_MM 0x00EC + + + + + + + + + + + + + + + +#define VL53L1_NVM__CUST__MM_CONFIG__OUTER_OFFSET_MM 0x00EE + + + + + + + + + + + + + + + +#define VL53L1_NVM__CUST__ALGO__PART_TO_PART_RANGE_OFFSET_MM 0x00F0 + + + + + + + + + + + + + + + +#define VL53L1_NVM__CUST__ALGO__CROSSTALK_COMPENSATION_PLANE_OFFSET_KCPS 0x00F4 + + + + + + + + + + + + + + + +#define VL53L1_NVM__CUST__ALGO__CROSSTALK_COMPENSATION_X_PLANE_GRADIENT_KCPS \ + 0x00F6 + + + + + + + + + + + + + + + +#define VL53L1_NVM__CUST__ALGO__CROSSTALK_COMPENSATION_Y_PLANE_GRADIENT_KCPS \ + 0x00F8 + + + + + + + + + + + + + + + +#define VL53L1_NVM__CUST__SPARE_HOST_CONFIG__NVM_CONFIG_SPARE_0 0x00FA + + + + + + + + + + + + + + + +#define VL53L1_NVM__CUST__SPARE_HOST_CONFIG__NVM_CONFIG_SPARE_1 0x00FB + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__FGC__BYTE_0 0x01DC + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__FGC__BYTE_1 0x01DD + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__FGC__BYTE_2 0x01DE + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__FGC__BYTE_3 0x01DF + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__FGC__BYTE_4 0x01E0 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__FGC__BYTE_5 0x01E1 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__FGC__BYTE_6 0x01E2 + + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__FGC__BYTE_7 0x01E3 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__FGC__BYTE_8 0x01E4 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__FGC__BYTE_9 0x01E5 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__FGC__BYTE_10 0x01E6 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__FGC__BYTE_11 0x01E7 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__FGC__BYTE_12 0x01E8 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__FGC__BYTE_13 0x01E9 + + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__FGC__BYTE_14 0x01EA + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__FGC__BYTE_15 0x01EB + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__TEST_PROGRAM_MAJOR_MINOR 0x01EC + + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__MAP_MAJOR_MINOR 0x01ED + + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__YEAR_MONTH 0x01EE + + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__DAY_MODULE_DATE_PHASE 0x01EF + + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__TIME 0x01F0 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__TESTER_ID 0x01F2 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SITE_ID 0x01F3 + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__TEST_PROGRAM_MAJOR_MINOR 0x01F4 + + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__PROBE_CARD_MAJOR_MINOR 0x01F5 + + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__TESTER_ID 0x01F6 + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__LOT__BYTE_0 0x01F8 + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__LOT__BYTE_1 0x01F9 + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__LOT__BYTE_2 0x01FA + + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__LOT__BYTE_3 0x01FB + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__LOT__BYTE_4 0x01FC + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__LOT__BYTE_5 0x01FD + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__WAFER 0x01FD + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__XCOORD 0x01FE + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__YCOORD 0x01FF + + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__OPTICAL_CENTRE_DATA_INDEX 0x00B8 +#define VL53L1_NVM__FMT__OPTICAL_CENTRE_DATA_SIZE 4 + +#define VL53L1_NVM__FMT__CAL_PEAK_RATE_MAP_DATA_INDEX 0x015C +#define VL53L1_NVM__FMT__CAL_PEAK_RATE_MAP_DATA_SIZE 56 + +#define VL53L1_NVM__FMT__ADDITIONAL_OFFSET_CAL_DATA_INDEX 0x0194 +#define VL53L1_NVM__FMT__ADDITIONAL_OFFSET_CAL_DATA_SIZE 8 + +#define VL53L1_NVM__FMT__RANGE_RESULTS__140MM_MM_PRE_RANGE 0x019C +#define VL53L1_NVM__FMT__RANGE_RESULTS__140MM_DARK 0x01AC +#define VL53L1_NVM__FMT__RANGE_RESULTS__400MM_DARK 0x01BC +#define VL53L1_NVM__FMT__RANGE_RESULTS__400MM_AMBIENT 0x01CC +#define VL53L1_NVM__FMT__RANGE_RESULTS__SIZE_BYTES 16 + + + + + + + + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/drivers/input/misc/vl53L1/kona/inc/vl53l1_nvm_structs.h b/drivers/input/misc/vl53L1/kona/inc/vl53l1_nvm_structs.h new file mode 100644 index 000000000000..782f2d808650 --- /dev/null +++ b/drivers/input/misc/vl53L1/kona/inc/vl53l1_nvm_structs.h @@ -0,0 +1,809 @@ + +/******************************************************************************* + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#ifndef _VL53L1_NVM_STRUCTS_H_ +#define _VL53L1_NVM_STRUCTS_H_ + + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include "vl53l1_platform.h" +#include "vl53l1_ll_def.h" + + + + + + + + + + +typedef struct { + + uint16_t result__actual_effective_rtn_spads; + + + uint8_t ref_spad_array__num_requested_ref_spads; + + + uint8_t ref_spad_array__ref_location; + + + uint16_t result__peak_signal_count_rate_rtn_mcps; + + + uint16_t result__ambient_count_rate_rtn_mcps; + + + uint16_t result__peak_signal_count_rate_ref_mcps; + + + uint16_t result__ambient_count_rate_ref_mcps; + + + uint16_t measured_distance_mm; + + + uint16_t measured_distance_stdev_mm; + + + +} VL53L1_decoded_nvm_fmt_range_data_t; + + + + + + + + + + +typedef struct { + + char nvm__fmt__fgc[19]; + + + uint8_t nvm__fmt__test_program_major; + + + + + + uint8_t nvm__fmt__test_program_minor; + + + + + + uint8_t nvm__fmt__map_major; + + + + + + uint8_t nvm__fmt__map_minor; + + + + + + uint8_t nvm__fmt__year; + + + + + + uint8_t nvm__fmt__month; + + + + + + uint8_t nvm__fmt__day; + + + + + + uint8_t nvm__fmt__module_date_phase; + + + + + + uint16_t nvm__fmt__time; + + + + + + uint8_t nvm__fmt__tester_id; + + + + + + uint8_t nvm__fmt__site_id; + + + + + + uint8_t nvm__ews__test_program_major; + + + + + + uint8_t nvm__ews__test_program_minor; + + + + + + uint8_t nvm__ews__probe_card_major; + + + + + + uint8_t nvm__ews__probe_card_minor; + + + + + + uint8_t nvm__ews__tester_id; + + + + + + + char nvm__ews__lot[8]; + + + uint8_t nvm__ews__wafer; + + + + + + uint8_t nvm__ews__xcoord; + + + + + + uint8_t nvm__ews__ycoord; + + + + + +} VL53L1_decoded_nvm_fmt_info_t; + + + + + + + + + + +typedef struct { + + uint8_t nvm__ews__test_program_major; + + + + + + uint8_t nvm__ews__test_program_minor; + + + + + + uint8_t nvm__ews__probe_card_major; + + + + + + uint8_t nvm__ews__probe_card_minor; + + + + + + uint8_t nvm__ews__tester_id; + + + + + + + char nvm__ews__lot[8]; + + + uint8_t nvm__ews__wafer; + + + + + + uint8_t nvm__ews__xcoord; + + + + + + uint8_t nvm__ews__ycoord; + + + + + + +} VL53L1_decoded_nvm_ews_info_t; + + + + + + + + + + +typedef struct { + uint8_t nvm__identification_model_id; + + + + + + uint8_t nvm__identification_module_type; + + + + + + uint8_t nvm__identification_revision_id; + + + + + + uint16_t nvm__identification_module_id; + + + + + + uint8_t nvm__i2c_valid; + + + + + + uint8_t nvm__i2c_device_address_ews; + + + + + + uint16_t nvm__ews__fast_osc_frequency; + + + + + + uint8_t nvm__ews__fast_osc_trim_max; + + + + + + uint8_t nvm__ews__fast_osc_freq_set; + + + + + + uint16_t nvm__ews__slow_osc_calibration; + + + + + + uint16_t nvm__fmt__fast_osc_frequency; + + + + + + uint8_t nvm__fmt__fast_osc_trim_max; + + + + + + uint8_t nvm__fmt__fast_osc_freq_set; + + + + + + uint16_t nvm__fmt__slow_osc_calibration; + + + + + + uint8_t nvm__vhv_config_unlock; + + + + + + uint8_t nvm__ref_selvddpix; + + + + + + uint8_t nvm__ref_selvquench; + + + + + + uint8_t nvm__regavdd1v2_sel; + + + + + + uint8_t nvm__regdvdd1v2_sel; + + + + + + uint8_t nvm__vhv_timeout__macrop; + + + + + + uint8_t nvm__vhv_loop_bound; + + + + + + uint8_t nvm__vhv_count_threshold; + + + + + + uint8_t nvm__vhv_offset; + + + + + + uint8_t nvm__vhv_init_enable; + + + + + + uint8_t nvm__vhv_init_value; + + + + + + uint8_t nvm__laser_safety_vcsel_trim_ll; + + + + + + uint8_t nvm__laser_safety_vcsel_selion_ll; + + + + + + uint8_t nvm__laser_safety_vcsel_selion_max_ll; + + + + + + uint8_t nvm__laser_safety_mult_ll; + + + + + + uint8_t nvm__laser_safety_clip_ll; + + + + + + uint8_t nvm__laser_safety_vcsel_trim_ld; + + + + + + uint8_t nvm__laser_safety_vcsel_selion_ld; + + + + + + uint8_t nvm__laser_safety_vcsel_selion_max_ld; + + + + + + uint8_t nvm__laser_safety_mult_ld; + + + + + + uint8_t nvm__laser_safety_clip_ld; + + + + + + uint8_t nvm__laser_safety_lock_byte; + + + + + + uint8_t nvm__laser_safety_unlock_byte; + + + + + + uint8_t nvm__ews__spad_enables_rtn[VL53L1_RTN_SPAD_BUFFER_SIZE]; + + + + + + uint8_t nvm__ews__spad_enables_ref__loc1[VL53L1_REF_SPAD_BUFFER_SIZE]; + + + + + + uint8_t nvm__ews__spad_enables_ref__loc2[VL53L1_REF_SPAD_BUFFER_SIZE]; + + + + + + uint8_t nvm__ews__spad_enables_ref__loc3[VL53L1_REF_SPAD_BUFFER_SIZE]; + + + + + + uint8_t nvm__fmt__spad_enables_rtn[VL53L1_RTN_SPAD_BUFFER_SIZE]; + + + + + + uint8_t nvm__fmt__spad_enables_ref__loc1[VL53L1_REF_SPAD_BUFFER_SIZE]; + + + + + + uint8_t nvm__fmt__spad_enables_ref__loc2[VL53L1_REF_SPAD_BUFFER_SIZE]; + + + + + + uint8_t nvm__fmt__spad_enables_ref__loc3[VL53L1_REF_SPAD_BUFFER_SIZE]; + + + + + + uint8_t nvm__fmt__roi_config__mode_roi_centre_spad; + + + + + + uint8_t nvm__fmt__roi_config__mode_roi_x_size; + + + + + + uint8_t nvm__fmt__roi_config__mode_roi_y_size; + + + + + + uint8_t nvm__fmt__ref_spad_apply__num_requested_ref_spad; + + + + + + uint8_t nvm__fmt__ref_spad_man__ref_location; + + + + + + uint16_t nvm__fmt__mm_config__inner_offset_mm; + + + + + + uint16_t nvm__fmt__mm_config__outer_offset_mm; + + + + + + uint16_t nvm__fmt__algo_part_to_part_range_offset_mm; + + + + + + uint16_t nvm__fmt__algo__crosstalk_compensation_plane_offset_kcps; + + + + + + uint16_t nvm__fmt__algo__crosstalk_compensation_x_plane_gradient_kcps; + + + + + + uint16_t nvm__fmt__algo__crosstalk_compensation_y_plane_gradient_kcps; + + + + + + uint8_t nvm__fmt__spare__host_config__nvm_config_spare_0; + + + + + + uint8_t nvm__fmt__spare__host_config__nvm_config_spare_1; + + + + + + uint8_t nvm__customer_space_programmed; + + + + + + uint8_t nvm__cust__i2c_device_address; + + + + + + uint8_t nvm__cust__ref_spad_apply__num_requested_ref_spad; + + + + + + uint8_t nvm__cust__ref_spad_man__ref_location; + + + + + + uint16_t nvm__cust__mm_config__inner_offset_mm; + + + + + + uint16_t nvm__cust__mm_config__outer_offset_mm; + + + + + + uint16_t nvm__cust__algo_part_to_part_range_offset_mm; + + + + + + uint16_t nvm__cust__algo__crosstalk_compensation_plane_offset_kcps; + + + + + + uint16_t nvm__cust__algo__crosstalk_compensation_x_plane_gradient_kcps; + + + + + + uint16_t nvm__cust__algo__crosstalk_compensation_y_plane_gradient_kcps; + + + + + + uint8_t nvm__cust__spare__host_config__nvm_config_spare_0; + + + + + + uint8_t nvm__cust__spare__host_config__nvm_config_spare_1; + + + + + + + VL53L1_optical_centre_t fmt_optical_centre; + VL53L1_cal_peak_rate_map_t fmt_peak_rate_map; + VL53L1_additional_offset_cal_data_t fmt_add_offset_data; + + VL53L1_decoded_nvm_fmt_range_data_t + fmt_range_data[VL53L1_NVM_MAX_FMT_RANGE_DATA]; + + VL53L1_decoded_nvm_fmt_info_t fmt_info; + VL53L1_decoded_nvm_ews_info_t ews_info; + +} VL53L1_decoded_nvm_data_t; + + + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/drivers/input/misc/vl53L1/kona/inc/vl53l1_preset_setup.h b/drivers/input/misc/vl53L1/kona/inc/vl53l1_preset_setup.h new file mode 100644 index 000000000000..f8f949a9d53a --- /dev/null +++ b/drivers/input/misc/vl53L1/kona/inc/vl53l1_preset_setup.h @@ -0,0 +1,125 @@ + +/****************************************************************************** + * Copyright (c) 2017, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + + ****************************************************************************** + + 'STMicroelectronics Proprietary license' + + ******************************************************************************* + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + + ******************************************************************************* + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones mentioned above : + + ******************************************************************************* + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + ******************************************************************************* + */ + +#ifndef _VL53L1_PRESET_SETUP_H_ +#define _VL53L1_PRESET_SETUP_H_ + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* indexes for the bare driver tuning setting API function */ +enum VL53L1_Tuning_t { + VL53L1_TUNING_VERSION = 0, + VL53L1_TUNING_PROXY_MIN, + VL53L1_TUNING_SINGLE_TARGET_XTALK_TARGET_DISTANCE_MM, + VL53L1_TUNING_SINGLE_TARGET_XTALK_SAMPLE_NUMBER, + VL53L1_TUNING_MIN_AMBIENT_DMAX_VALID, + VL53L1_TUNING_MAX_SIMPLE_OFFSET_CALIBRATION_SAMPLE_NUMBER, + VL53L1_TUNING_XTALK_FULL_ROI_TARGET_DISTANCE_MM, + VL53L1_TUNING_SIMPLE_OFFSET_CALIBRATION_REPEAT, + VL53L1_TUNING_XTALK_FULL_ROI_MAX_THRESHOLD, + VL53L1_TUNING_XTALK_FULL_ROI_BIN_SUM_MARGIN, + VL53L1_TUNING_XTALK_FULL_ROI_DEFAULT_OFFSET, + VL53L1_TUNING_ZERO_DISTANCE_OFFSET_NON_LINEAR_FACTOR, + VL53L1_TUNING_MAX_TUNABLE_KEY +}; + +/* default values for the tuning settings parameters */ +#define TUNING_VERSION 0x0006 + +#define TUNING_PROXY_MIN -30 /* min distance in mm */ +#define TUNING_SINGLE_TARGET_XTALK_TARGET_DISTANCE_MM 600 +/* Target distance in mm for single target Xtalk */ +#define TUNING_SINGLE_TARGET_XTALK_SAMPLE_NUMBER 50 +/* Number of sample used for single target Xtalk */ +#define TUNING_MIN_AMBIENT_DMAX_VALID 8 +/* Minimum ambient level to state the Dmax returned by the device is valid */ +#define TUNING_MAX_SIMPLE_OFFSET_CALIBRATION_SAMPLE_NUMBER 10 +/* Maximum loops to perform simple offset calibration */ +#define TUNING_XTALK_FULL_ROI_TARGET_DISTANCE_MM 600 +/* Target distance in mm for target Xtalk from Bins method*/ +#define TUNING_SIMPLE_OFFSET_CALIBRATION_REPEAT 3 +/* Number of loops done during the simple offset calibration*/ +#define TUNING_ZERO_DISTANCE_OFFSET_NON_LINEAR_FACTOR_DEFAULT 9 +/* zero distance offset calibration non linear compensation default value */ + +/* The 3 following settings are related to the fix for ticket EwokP #558410 */ +#define TUNING_XTALK_FULL_ROI_MAX_THRESHOLD 262144 +/* Maximum possible plane offset (262144 stands for 512 kcps in 7.9 format) */ +#define TUNING_XTALK_FULL_ROI_BIN_SUM_MARGIN 24 +/* Acceptance margin for the xtalk_shape bin_data sum computation */ +#define TUNING_XTALK_FULL_ROI_DEFAULT_OFFSET 50 +/* Recovery value for Xtalk compensation plane offset in kcps */ +/* 50 stands for ~0.10 kcps cover glass in 7.9 format */ +/* End of settings related to the fix for ticket EwokP #558410 */ + +/* the following table should actually be defined as static and shall be part + * of the VL53L1_StaticInit() function code + */ + +#ifdef __cplusplus +} +#endif + +#endif /* _VL53L1_PRESET_SETUP_H_ */ diff --git a/drivers/input/misc/vl53L1/kona/inc/vl53l1_register_funcs.h b/drivers/input/misc/vl53L1/kona/inc/vl53l1_register_funcs.h new file mode 100644 index 000000000000..881aea81c009 --- /dev/null +++ b/drivers/input/misc/vl53L1/kona/inc/vl53l1_register_funcs.h @@ -0,0 +1,1694 @@ + +/******************************************************************************* + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#ifndef _VL53L1_REGISTER_FUNCS_H_ +#define _VL53L1_REGISTER_FUNCS_H_ + +#include "vl53l1_platform.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_encode_static_nvm_managed( + VL53L1_static_nvm_managed_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_decode_static_nvm_managed( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_static_nvm_managed_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_static_nvm_managed( + VL53L1_DEV Dev, + VL53L1_static_nvm_managed_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_static_nvm_managed( + VL53L1_DEV Dev, + VL53L1_static_nvm_managed_t *pdata); + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_encode_customer_nvm_managed( + VL53L1_customer_nvm_managed_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_decode_customer_nvm_managed( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_customer_nvm_managed_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_customer_nvm_managed( + VL53L1_DEV Dev, + VL53L1_customer_nvm_managed_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_customer_nvm_managed( + VL53L1_DEV Dev, + VL53L1_customer_nvm_managed_t *pdata); + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_encode_static_config( + VL53L1_static_config_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_decode_static_config( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_static_config_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_static_config( + VL53L1_DEV Dev, + VL53L1_static_config_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_static_config( + VL53L1_DEV Dev, + VL53L1_static_config_t *pdata); + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_encode_general_config( + VL53L1_general_config_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_decode_general_config( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_general_config_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_general_config( + VL53L1_DEV Dev, + VL53L1_general_config_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_general_config( + VL53L1_DEV Dev, + VL53L1_general_config_t *pdata); + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_encode_timing_config( + VL53L1_timing_config_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_decode_timing_config( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_timing_config_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_timing_config( + VL53L1_DEV Dev, + VL53L1_timing_config_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_timing_config( + VL53L1_DEV Dev, + VL53L1_timing_config_t *pdata); + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_encode_dynamic_config( + VL53L1_dynamic_config_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_decode_dynamic_config( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_dynamic_config_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_dynamic_config( + VL53L1_DEV Dev, + VL53L1_dynamic_config_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_dynamic_config( + VL53L1_DEV Dev, + VL53L1_dynamic_config_t *pdata); + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_encode_system_control( + VL53L1_system_control_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_decode_system_control( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_system_control_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_system_control( + VL53L1_DEV Dev, + VL53L1_system_control_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_system_control( + VL53L1_DEV Dev, + VL53L1_system_control_t *pdata); + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_encode_system_results( + VL53L1_system_results_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_decode_system_results( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_system_results_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_system_results( + VL53L1_DEV Dev, + VL53L1_system_results_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_system_results( + VL53L1_DEV Dev, + VL53L1_system_results_t *pdata); + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_encode_core_results( + VL53L1_core_results_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_decode_core_results( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_core_results_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_core_results( + VL53L1_DEV Dev, + VL53L1_core_results_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_core_results( + VL53L1_DEV Dev, + VL53L1_core_results_t *pdata); + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_encode_debug_results( + VL53L1_debug_results_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_decode_debug_results( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_debug_results_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_debug_results( + VL53L1_DEV Dev, + VL53L1_debug_results_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_debug_results( + VL53L1_DEV Dev, + VL53L1_debug_results_t *pdata); + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_encode_nvm_copy_data( + VL53L1_nvm_copy_data_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_decode_nvm_copy_data( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_nvm_copy_data_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_nvm_copy_data( + VL53L1_DEV Dev, + VL53L1_nvm_copy_data_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_nvm_copy_data( + VL53L1_DEV Dev, + VL53L1_nvm_copy_data_t *pdata); + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_encode_prev_shadow_system_results( + VL53L1_prev_shadow_system_results_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_decode_prev_shadow_system_results( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_prev_shadow_system_results_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_prev_shadow_system_results( + VL53L1_DEV Dev, + VL53L1_prev_shadow_system_results_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_prev_shadow_system_results( + VL53L1_DEV Dev, + VL53L1_prev_shadow_system_results_t *pdata); + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_encode_prev_shadow_core_results( + VL53L1_prev_shadow_core_results_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_decode_prev_shadow_core_results( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_prev_shadow_core_results_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_prev_shadow_core_results( + VL53L1_DEV Dev, + VL53L1_prev_shadow_core_results_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_prev_shadow_core_results( + VL53L1_DEV Dev, + VL53L1_prev_shadow_core_results_t *pdata); + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_encode_patch_debug( + VL53L1_patch_debug_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_decode_patch_debug( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_patch_debug_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_patch_debug( + VL53L1_DEV Dev, + VL53L1_patch_debug_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_patch_debug( + VL53L1_DEV Dev, + VL53L1_patch_debug_t *pdata); + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_encode_gph_general_config( + VL53L1_gph_general_config_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_decode_gph_general_config( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_gph_general_config_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_gph_general_config( + VL53L1_DEV Dev, + VL53L1_gph_general_config_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_gph_general_config( + VL53L1_DEV Dev, + VL53L1_gph_general_config_t *pdata); + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_encode_gph_static_config( + VL53L1_gph_static_config_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_decode_gph_static_config( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_gph_static_config_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_gph_static_config( + VL53L1_DEV Dev, + VL53L1_gph_static_config_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_gph_static_config( + VL53L1_DEV Dev, + VL53L1_gph_static_config_t *pdata); + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_encode_gph_timing_config( + VL53L1_gph_timing_config_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_decode_gph_timing_config( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_gph_timing_config_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_gph_timing_config( + VL53L1_DEV Dev, + VL53L1_gph_timing_config_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_gph_timing_config( + VL53L1_DEV Dev, + VL53L1_gph_timing_config_t *pdata); + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_encode_fw_internal( + VL53L1_fw_internal_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_decode_fw_internal( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_fw_internal_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_fw_internal( + VL53L1_DEV Dev, + VL53L1_fw_internal_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_fw_internal( + VL53L1_DEV Dev, + VL53L1_fw_internal_t *pdata); + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_encode_patch_results( + VL53L1_patch_results_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_decode_patch_results( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_patch_results_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_patch_results( + VL53L1_DEV Dev, + VL53L1_patch_results_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_patch_results( + VL53L1_DEV Dev, + VL53L1_patch_results_t *pdata); + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_encode_shadow_system_results( + VL53L1_shadow_system_results_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_decode_shadow_system_results( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_shadow_system_results_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_shadow_system_results( + VL53L1_DEV Dev, + VL53L1_shadow_system_results_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_shadow_system_results( + VL53L1_DEV Dev, + VL53L1_shadow_system_results_t *pdata); + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_encode_shadow_core_results( + VL53L1_shadow_core_results_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_decode_shadow_core_results( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_shadow_core_results_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_shadow_core_results( + VL53L1_DEV Dev, + VL53L1_shadow_core_results_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_shadow_core_results( + VL53L1_DEV Dev, + VL53L1_shadow_core_results_t *pdata); + + +#ifdef __cplusplus +} +#endif + +#endif + + diff --git a/drivers/input/misc/vl53L1/kona/inc/vl53l1_register_map.h b/drivers/input/misc/vl53L1/kona/inc/vl53l1_register_map.h new file mode 100644 index 000000000000..288c80b9af20 --- /dev/null +++ b/drivers/input/misc/vl53L1/kona/inc/vl53l1_register_map.h @@ -0,0 +1,13151 @@ + +/******************************************************************************* + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#ifndef _VL53L1_REGISTER_MAP_H_ +#define _VL53L1_REGISTER_MAP_H_ + + + + + + + +#define VL53L1_SOFT_RESET 0x0000 + + + + + + + +#define VL53L1_I2C_SLAVE__DEVICE_ADDRESS 0x0001 + + + + + + + + + + + + + + + +#define VL53L1_ANA_CONFIG__VHV_REF_SEL_VDDPIX 0x0002 + + + + + + + + + + + + + + + +#define VL53L1_ANA_CONFIG__VHV_REF_SEL_VQUENCH 0x0003 + + + + + + + + + + + + + + + +#define VL53L1_ANA_CONFIG__REG_AVDD1V2_SEL 0x0004 + + + + + + + + + + + + + + + +#define VL53L1_ANA_CONFIG__FAST_OSC__TRIM 0x0005 + + + + + + + + + + + + + + + +#define VL53L1_OSC_MEASURED__FAST_OSC__FREQUENCY 0x0006 + + + + + + + + + + + + + + + +#define VL53L1_OSC_MEASURED__FAST_OSC__FREQUENCY_HI 0x0006 + + + + + + + +#define VL53L1_OSC_MEASURED__FAST_OSC__FREQUENCY_LO 0x0007 + + + + + + + +#define VL53L1_VHV_CONFIG__TIMEOUT_MACROP_LOOP_BOUND 0x0008 + + + + + + + + + + + + + + + + +#define VL53L1_VHV_CONFIG__COUNT_THRESH 0x0009 + + + + + + + + + + + + + + + +#define VL53L1_VHV_CONFIG__OFFSET 0x000A + + + + + + + + + + + + + + + +#define VL53L1_VHV_CONFIG__INIT 0x000B + + + + + + + + + + + + + + + + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_REF_0 0x000D + + + + + + + + + + + + + + + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_REF_1 0x000E + + + + + + + + + + + + + + + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_REF_2 0x000F + + + + + + + + + + + + + + + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_REF_3 0x0010 + + + + + + + + + + + + + + + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_REF_4 0x0011 + + + + + + + + + + + + + + + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_REF_5 0x0012 + + + + + + + + + + + + + + + +#define VL53L1_GLOBAL_CONFIG__REF_EN_START_SELECT 0x0013 + + + + + + + + + + + + + + + +#define VL53L1_REF_SPAD_MAN__NUM_REQUESTED_REF_SPADS 0x0014 + + + + + + + + + + + + + + + +#define VL53L1_REF_SPAD_MAN__REF_LOCATION 0x0015 + + + + + + + + + + + + + + + +#define VL53L1_ALGO__CROSSTALK_COMPENSATION_PLANE_OFFSET_KCPS 0x0016 + + + + + + + + + + + + + + + + +#define VL53L1_ALGO__CROSSTALK_COMPENSATION_PLANE_OFFSET_KCPS_HI 0x0016 + + + + + + + +#define VL53L1_ALGO__CROSSTALK_COMPENSATION_PLANE_OFFSET_KCPS_LO 0x0017 + + + + + + + +#define VL53L1_ALGO__CROSSTALK_COMPENSATION_X_PLANE_GRADIENT_KCPS 0x0018 + + + + + + + + + + + + + + + + +#define VL53L1_ALGO__CROSSTALK_COMPENSATION_X_PLANE_GRADIENT_KCPS_HI 0x0018 + + + + + + + +#define VL53L1_ALGO__CROSSTALK_COMPENSATION_X_PLANE_GRADIENT_KCPS_LO 0x0019 + + + + + + + +#define VL53L1_ALGO__CROSSTALK_COMPENSATION_Y_PLANE_GRADIENT_KCPS 0x001A + + + + + + + + + + + + + + + + +#define VL53L1_ALGO__CROSSTALK_COMPENSATION_Y_PLANE_GRADIENT_KCPS_HI 0x001A + + + + + + + +#define VL53L1_ALGO__CROSSTALK_COMPENSATION_Y_PLANE_GRADIENT_KCPS_LO 0x001B + + + + + + + +#define VL53L1_REF_SPAD_CHAR__TOTAL_RATE_TARGET_MCPS 0x001C + + + + + + + + + + + + + + + + +#define VL53L1_REF_SPAD_CHAR__TOTAL_RATE_TARGET_MCPS_HI 0x001C + + + + + + + +#define VL53L1_REF_SPAD_CHAR__TOTAL_RATE_TARGET_MCPS_LO 0x001D + + + + + + + +#define VL53L1_ALGO__PART_TO_PART_RANGE_OFFSET_MM 0x001E + + + + + + + + + + + + + + + +#define VL53L1_ALGO__PART_TO_PART_RANGE_OFFSET_MM_HI 0x001E + + + + + + + +#define VL53L1_ALGO__PART_TO_PART_RANGE_OFFSET_MM_LO 0x001F + + + + + + + +#define VL53L1_MM_CONFIG__INNER_OFFSET_MM 0x0020 + + + + + + + + + + + + + + + +#define VL53L1_MM_CONFIG__INNER_OFFSET_MM_HI 0x0020 + + + + + + + +#define VL53L1_MM_CONFIG__INNER_OFFSET_MM_LO 0x0021 + + + + + + + +#define VL53L1_MM_CONFIG__OUTER_OFFSET_MM 0x0022 + + + + + + + + + + + + + + + +#define VL53L1_MM_CONFIG__OUTER_OFFSET_MM_HI 0x0022 + + + + + + + +#define VL53L1_MM_CONFIG__OUTER_OFFSET_MM_LO 0x0023 + + + + + + + +#define VL53L1_DSS_CONFIG__TARGET_TOTAL_RATE_MCPS 0x0024 + + + + + + + + + + + + + + + +#define VL53L1_DSS_CONFIG__TARGET_TOTAL_RATE_MCPS_HI 0x0024 + + + + + + + +#define VL53L1_DSS_CONFIG__TARGET_TOTAL_RATE_MCPS_LO 0x0025 + + + + + + + +#define VL53L1_DEBUG__CTRL 0x0026 + + + + + + + + + + + + + + + +#define VL53L1_TEST_MODE__CTRL 0x0027 + + + + + + + + + + + + + + + +#define VL53L1_CLK_GATING__CTRL 0x0028 + + + + + + + + + + + + + + + + + + +#define VL53L1_NVM_BIST__CTRL 0x0029 + + + + + + + + + + + + + + + + +#define VL53L1_NVM_BIST__NUM_NVM_WORDS 0x002A + + + + + + + + + + + + + + + +#define VL53L1_NVM_BIST__START_ADDRESS 0x002B + + + + + + + + + + + + + + + +#define VL53L1_HOST_IF__STATUS 0x002C + + + + + + + + + + + + + + + +#define VL53L1_PAD_I2C_HV__CONFIG 0x002D + + + + + + + + + + + + + + + + + + + + +#define VL53L1_PAD_I2C_HV__EXTSUP_CONFIG 0x002E + + + + + + + + + + + + + + + +#define VL53L1_GPIO_HV_PAD__CTRL 0x002F + + + + + + + + + + + + + + + + +#define VL53L1_GPIO_HV_MUX__CTRL 0x0030 + + + + + + + + + + + + + + + + +#define VL53L1_GPIO__TIO_HV_STATUS 0x0031 + + + + + + + + + + + + + + + + +#define VL53L1_GPIO__FIO_HV_STATUS 0x0032 + + + + + + + + + + + + + + + +#define VL53L1_ANA_CONFIG__SPAD_SEL_PSWIDTH 0x0033 + + + + + + + + + + + + + + + +#define VL53L1_ANA_CONFIG__VCSEL_PULSE_WIDTH_OFFSET 0x0034 + + + + + + + + + + + + + + + +#define VL53L1_ANA_CONFIG__FAST_OSC__CONFIG_CTRL 0x0035 + + + + + + + + + + + + + + + +#define VL53L1_SIGMA_ESTIMATOR__EFFECTIVE_PULSE_WIDTH_NS 0x0036 + + + + + + + + + + + + + + + +#define VL53L1_SIGMA_ESTIMATOR__EFFECTIVE_AMBIENT_WIDTH_NS 0x0037 + + + + + + + + + + + + + + + +#define VL53L1_SIGMA_ESTIMATOR__SIGMA_REF_MM 0x0038 + + + + + + + + + + + + + + + +#define VL53L1_ALGO__CROSSTALK_COMPENSATION_VALID_HEIGHT_MM 0x0039 + + + + + + + + + + + + + + + +#define VL53L1_SPARE_HOST_CONFIG__STATIC_CONFIG_SPARE_0 0x003A + + + + + + + + + + + + + + + +#define VL53L1_SPARE_HOST_CONFIG__STATIC_CONFIG_SPARE_1 0x003B + + + + + + + + + + + + + + + +#define VL53L1_ALGO__RANGE_IGNORE_THRESHOLD_MCPS 0x003C + + + + + + + + + + + + + + + +#define VL53L1_ALGO__RANGE_IGNORE_THRESHOLD_MCPS_HI 0x003C + + + + + + + +#define VL53L1_ALGO__RANGE_IGNORE_THRESHOLD_MCPS_LO 0x003D + + + + + + + +#define VL53L1_ALGO__RANGE_IGNORE_VALID_HEIGHT_MM 0x003E + + + + + + + + + + + + + + + +#define VL53L1_ALGO__RANGE_MIN_CLIP 0x003F + + + + + + + + + + + + + + + + +#define VL53L1_ALGO__CONSISTENCY_CHECK__TOLERANCE 0x0040 + + + + + + + + + + + + + + + +#define VL53L1_SPARE_HOST_CONFIG__STATIC_CONFIG_SPARE_2 0x0041 + + + + + + + + + + + + + + + +#define VL53L1_SD_CONFIG__RESET_STAGES_MSB 0x0042 + + + + + + + + + + + + + + + +#define VL53L1_SD_CONFIG__RESET_STAGES_LSB 0x0043 + + + + + + + + + + + + + + + + +#define VL53L1_GPH_CONFIG__STREAM_COUNT_UPDATE_VALUE 0x0044 + + + + + + + + + + + + + + + +#define VL53L1_GLOBAL_CONFIG__STREAM_DIVIDER 0x0045 + + + + + + + + + + + + + + + +#define VL53L1_SYSTEM__INTERRUPT_CONFIG_GPIO 0x0046 + + + + + + + + + + + + + + + + + + + + +#define VL53L1_CAL_CONFIG__VCSEL_START 0x0047 + + + + + + + + + + + + + + + +#define VL53L1_CAL_CONFIG__REPEAT_RATE 0x0048 + + + + + + + + + + + + + + + +#define VL53L1_CAL_CONFIG__REPEAT_RATE_HI 0x0048 + + + + + + + +#define VL53L1_CAL_CONFIG__REPEAT_RATE_LO 0x0049 + + + + + + + +#define VL53L1_GLOBAL_CONFIG__VCSEL_WIDTH 0x004A + + + + + + + + + + + + + + + +#define VL53L1_PHASECAL_CONFIG__TIMEOUT_MACROP 0x004B + + + + + + + + + + + + + + + +#define VL53L1_PHASECAL_CONFIG__TARGET 0x004C + + + + + + + + + + + + + + + +#define VL53L1_PHASECAL_CONFIG__OVERRIDE 0x004D + + + + + + + + + + + + + + + +#define VL53L1_DSS_CONFIG__ROI_MODE_CONTROL 0x004F + + + + + + + + + + + + + + + + +#define VL53L1_SYSTEM__THRESH_RATE_HIGH 0x0050 + + + + + + + + + + + + + + + +#define VL53L1_SYSTEM__THRESH_RATE_HIGH_HI 0x0050 + + + + + + + +#define VL53L1_SYSTEM__THRESH_RATE_HIGH_LO 0x0051 + + + + + + + +#define VL53L1_SYSTEM__THRESH_RATE_LOW 0x0052 + + + + + + + + + + + + + + + +#define VL53L1_SYSTEM__THRESH_RATE_LOW_HI 0x0052 + + + + + + + +#define VL53L1_SYSTEM__THRESH_RATE_LOW_LO 0x0053 + + + + + + + +#define VL53L1_DSS_CONFIG__MANUAL_EFFECTIVE_SPADS_SELECT 0x0054 + + + + + + + + + + + + + + + +#define VL53L1_DSS_CONFIG__MANUAL_EFFECTIVE_SPADS_SELECT_HI 0x0054 + + + + + + + +#define VL53L1_DSS_CONFIG__MANUAL_EFFECTIVE_SPADS_SELECT_LO 0x0055 + + + + + + + +#define VL53L1_DSS_CONFIG__MANUAL_BLOCK_SELECT 0x0056 + + + + + + + + + + + + + + + +#define VL53L1_DSS_CONFIG__APERTURE_ATTENUATION 0x0057 + + + + + + + + + + + + + + + +#define VL53L1_DSS_CONFIG__MAX_SPADS_LIMIT 0x0058 + + + + + + + + + + + + + + + +#define VL53L1_DSS_CONFIG__MIN_SPADS_LIMIT 0x0059 + + + + + + + + + + + + + + + +#define VL53L1_MM_CONFIG__TIMEOUT_MACROP_A_HI 0x005A + + + + + + + + + + + + + + + +#define VL53L1_MM_CONFIG__TIMEOUT_MACROP_A_LO 0x005B + + + + + + + + + + + + + + + +#define VL53L1_MM_CONFIG__TIMEOUT_MACROP_B_HI 0x005C + + + + + + + + + + + + + + + +#define VL53L1_MM_CONFIG__TIMEOUT_MACROP_B_LO 0x005D + + + + + + + + + + + + + + + +#define VL53L1_RANGE_CONFIG__TIMEOUT_MACROP_A_HI 0x005E + + + + + + + + + + + + + + + +#define VL53L1_RANGE_CONFIG__TIMEOUT_MACROP_A_LO 0x005F + + + + + + + + + + + + + + + +#define VL53L1_RANGE_CONFIG__VCSEL_PERIOD_A 0x0060 + + + + + + + + + + + + + + + +#define VL53L1_RANGE_CONFIG__TIMEOUT_MACROP_B_HI 0x0061 + + + + + + + + + + + + + + + +#define VL53L1_RANGE_CONFIG__TIMEOUT_MACROP_B_LO 0x0062 + + + + + + + + + + + + + + + +#define VL53L1_RANGE_CONFIG__VCSEL_PERIOD_B 0x0063 + + + + + + + + + + + + + + + +#define VL53L1_RANGE_CONFIG__SIGMA_THRESH 0x0064 + + + + + + + + + + + + + + + +#define VL53L1_RANGE_CONFIG__SIGMA_THRESH_HI 0x0064 + + + + + + + +#define VL53L1_RANGE_CONFIG__SIGMA_THRESH_LO 0x0065 + + + + + + + +#define VL53L1_RANGE_CONFIG__MIN_COUNT_RATE_RTN_LIMIT_MCPS 0x0066 + + + + + + + + + + + + + + + + +#define VL53L1_RANGE_CONFIG__MIN_COUNT_RATE_RTN_LIMIT_MCPS_HI 0x0066 + + + + + + + +#define VL53L1_RANGE_CONFIG__MIN_COUNT_RATE_RTN_LIMIT_MCPS_LO 0x0067 + + + + + + + +#define VL53L1_RANGE_CONFIG__VALID_PHASE_LOW 0x0068 + + + + + + + + + + + + + + + +#define VL53L1_RANGE_CONFIG__VALID_PHASE_HIGH 0x0069 + + + + + + + + + + + + + + + +#define VL53L1_SYSTEM__INTERMEASUREMENT_PERIOD 0x006C + + + + + + + + + + + + + + + +#define VL53L1_SYSTEM__INTERMEASUREMENT_PERIOD_3 0x006C + + + + + + + +#define VL53L1_SYSTEM__INTERMEASUREMENT_PERIOD_2 0x006D + + + + + + + +#define VL53L1_SYSTEM__INTERMEASUREMENT_PERIOD_1 0x006E + + + + + + + +#define VL53L1_SYSTEM__INTERMEASUREMENT_PERIOD_0 0x006F + + + + + + + +#define VL53L1_SYSTEM__FRACTIONAL_ENABLE 0x0070 + + + + + + + + + + + + + + + +#define VL53L1_SYSTEM__GROUPED_PARAMETER_HOLD_0 0x0071 + + + + + + + + + + + + + + + + +#define VL53L1_SYSTEM__THRESH_HIGH 0x0072 + + + + + + + + + + + + + + + +#define VL53L1_SYSTEM__THRESH_HIGH_HI 0x0072 + + + + + + + +#define VL53L1_SYSTEM__THRESH_HIGH_LO 0x0073 + + + + + + + +#define VL53L1_SYSTEM__THRESH_LOW 0x0074 + + + + + + + + + + + + + + + +#define VL53L1_SYSTEM__THRESH_LOW_HI 0x0074 + + + + + + + +#define VL53L1_SYSTEM__THRESH_LOW_LO 0x0075 + + + + + + + +#define VL53L1_SYSTEM__ENABLE_XTALK_PER_QUADRANT 0x0076 + + + + + + + + + + + + + + + +#define VL53L1_SYSTEM__SEED_CONFIG 0x0077 + + + + + + + + + + + + + + + + +#define VL53L1_SD_CONFIG__WOI_SD0 0x0078 + + + + + + + + + + + + + + + +#define VL53L1_SD_CONFIG__WOI_SD1 0x0079 + + + + + + + + + + + + + + + +#define VL53L1_SD_CONFIG__INITIAL_PHASE_SD0 0x007A + + + + + + + + + + + + + + + +#define VL53L1_SD_CONFIG__INITIAL_PHASE_SD1 0x007B + + + + + + + + + + + + + + + +#define VL53L1_SYSTEM__GROUPED_PARAMETER_HOLD_1 0x007C + + + + + + + + + + + + + + + + +#define VL53L1_SD_CONFIG__FIRST_ORDER_SELECT 0x007D + + + + + + + + + + + + + + + + +#define VL53L1_SD_CONFIG__QUANTIFIER 0x007E + + + + + + + + + + + + + + + +#define VL53L1_ROI_CONFIG__USER_ROI_CENTRE_SPAD 0x007F + + + + + + + + + + + + + + + +#define VL53L1_ROI_CONFIG__USER_ROI_REQUESTED_GLOBAL_XY_SIZE 0x0080 + + + + + + + + + + + + + + + +#define VL53L1_SYSTEM__SEQUENCE_CONFIG 0x0081 + + + + + + + + + + + + + + + + + + + + + + +#define VL53L1_SYSTEM__GROUPED_PARAMETER_HOLD 0x0082 + + + + + + + + + + + + + + + + +#define VL53L1_POWER_MANAGEMENT__GO1_POWER_FORCE 0x0083 + + + + + + + + + + + + + + + +#define VL53L1_SYSTEM__STREAM_COUNT_CTRL 0x0084 + + + + + + + + + + + + + + + +#define VL53L1_FIRMWARE__ENABLE 0x0085 + + + + + + + + + + + + + + + +#define VL53L1_SYSTEM__INTERRUPT_CLEAR 0x0086 + + + + + + + + + + + + + + + + +#define VL53L1_SYSTEM__MODE_START 0x0087 + + + + + + + + + + + + + + + + + + + + +#define VL53L1_RESULT__INTERRUPT_STATUS 0x0088 + + + + + + + + + + + + + + + + + +#define VL53L1_RESULT__RANGE_STATUS 0x0089 + + + + + + + + + + + + + + + + + + +#define VL53L1_RESULT__REPORT_STATUS 0x008A + + + + + + + + + + + + + + + +#define VL53L1_RESULT__STREAM_COUNT 0x008B + + + + + + + + + + + + + + + +#define VL53L1_RESULT__DSS_ACTUAL_EFFECTIVE_SPADS_SD0 0x008C + + + + + + + + + + + + + + + + +#define VL53L1_RESULT__DSS_ACTUAL_EFFECTIVE_SPADS_SD0_HI 0x008C + + + + + + + +#define VL53L1_RESULT__DSS_ACTUAL_EFFECTIVE_SPADS_SD0_LO 0x008D + + + + + + + +#define VL53L1_RESULT__PEAK_SIGNAL_COUNT_RATE_MCPS_SD0 0x008E + + + + + + + + + + + + + + + + +#define VL53L1_RESULT__PEAK_SIGNAL_COUNT_RATE_MCPS_SD0_HI 0x008E + + + + + + + +#define VL53L1_RESULT__PEAK_SIGNAL_COUNT_RATE_MCPS_SD0_LO 0x008F + + + + + + + +#define VL53L1_RESULT__AMBIENT_COUNT_RATE_MCPS_SD0 0x0090 + + + + + + + + + + + + + + + + +#define VL53L1_RESULT__AMBIENT_COUNT_RATE_MCPS_SD0_HI 0x0090 + + + + + + + +#define VL53L1_RESULT__AMBIENT_COUNT_RATE_MCPS_SD0_LO 0x0091 + + + + + + + +#define VL53L1_RESULT__SIGMA_SD0 0x0092 + + + + + + + + + + + + + + + +#define VL53L1_RESULT__SIGMA_SD0_HI 0x0092 + + + + + + + +#define VL53L1_RESULT__SIGMA_SD0_LO 0x0093 + + + + + + + +#define VL53L1_RESULT__PHASE_SD0 0x0094 + + + + + + + + + + + + + + + +#define VL53L1_RESULT__PHASE_SD0_HI 0x0094 + + + + + + + +#define VL53L1_RESULT__PHASE_SD0_LO 0x0095 + + + + + + + +#define VL53L1_RESULT__FINAL_CROSSTALK_CORRECTED_RANGE_MM_SD0 0x0096 + + + + + + + + + + + + + + + +#define VL53L1_RESULT__FINAL_CROSSTALK_CORRECTED_RANGE_MM_SD0_HI 0x0096 + + + + + + + +#define VL53L1_RESULT__FINAL_CROSSTALK_CORRECTED_RANGE_MM_SD0_LO 0x0097 + + + + + + + +#define VL53L1_PEAK_SIGNAL_COUNT_RATE_CROSSTALK_CORRECTED_MCPS_SD0 0x0098 + + + + + + + + + + + + + +#define VL53L1__PEAK_SIGNAL_COUNT_RATE_CROSSTALK_CORRECTED_MCPS_SD0_HI 0x0098 + + + + + + + +#define VL53L1___PEAK_SIGNAL_COUNT_RATE_CROSSTALK_CORRECTED_MCPS_SD0_LO 0x0099 + + + + + + + +#define VL53L1_RESULT__MM_INNER_ACTUAL_EFFECTIVE_SPADS_SD0 0x009A + + + + + + + + + + + + + + + + +#define VL53L1_RESULT__MM_INNER_ACTUAL_EFFECTIVE_SPADS_SD0_HI 0x009A + + + + + + + +#define VL53L1_RESULT__MM_INNER_ACTUAL_EFFECTIVE_SPADS_SD0_LO 0x009B + + + + + + + +#define VL53L1_RESULT__MM_OUTER_ACTUAL_EFFECTIVE_SPADS_SD0 0x009C + + + + + + + + + + + + + + + + +#define VL53L1_RESULT__MM_OUTER_ACTUAL_EFFECTIVE_SPADS_SD0_HI 0x009C + + + + + + + +#define VL53L1_RESULT__MM_OUTER_ACTUAL_EFFECTIVE_SPADS_SD0_LO 0x009D + + + + + + + +#define VL53L1_RESULT__AVG_SIGNAL_COUNT_RATE_MCPS_SD0 0x009E + + + + + + + + + + + + + + + + +#define VL53L1_RESULT__AVG_SIGNAL_COUNT_RATE_MCPS_SD0_HI 0x009E + + + + + + + +#define VL53L1_RESULT__AVG_SIGNAL_COUNT_RATE_MCPS_SD0_LO 0x009F + + + + + + + +#define VL53L1_RESULT__DSS_ACTUAL_EFFECTIVE_SPADS_SD1 0x00A0 + + + + + + + + + + + + + + + + +#define VL53L1_RESULT__DSS_ACTUAL_EFFECTIVE_SPADS_SD1_HI 0x00A0 + + + + + + + +#define VL53L1_RESULT__DSS_ACTUAL_EFFECTIVE_SPADS_SD1_LO 0x00A1 + + + + + + + +#define VL53L1_RESULT__PEAK_SIGNAL_COUNT_RATE_MCPS_SD1 0x00A2 + + + + + + + + + + + + + + + + +#define VL53L1_RESULT__PEAK_SIGNAL_COUNT_RATE_MCPS_SD1_HI 0x00A2 + + + + + + + +#define VL53L1_RESULT__PEAK_SIGNAL_COUNT_RATE_MCPS_SD1_LO 0x00A3 + + + + + + + +#define VL53L1_RESULT__AMBIENT_COUNT_RATE_MCPS_SD1 0x00A4 + + + + + + + + + + + + + + + +#define VL53L1_RESULT__AMBIENT_COUNT_RATE_MCPS_SD1_HI 0x00A4 + + + + + + + +#define VL53L1_RESULT__AMBIENT_COUNT_RATE_MCPS_SD1_LO 0x00A5 + + + + + + + +#define VL53L1_RESULT__SIGMA_SD1 0x00A6 + + + + + + + + + + + + + + + +#define VL53L1_RESULT__SIGMA_SD1_HI 0x00A6 + + + + + + + +#define VL53L1_RESULT__SIGMA_SD1_LO 0x00A7 + + + + + + + +#define VL53L1_RESULT__PHASE_SD1 0x00A8 + + + + + + + + + + + + + + + +#define VL53L1_RESULT__PHASE_SD1_HI 0x00A8 + + + + + + + +#define VL53L1_RESULT__PHASE_SD1_LO 0x00A9 + + + + + + + +#define VL53L1_RESULT__FINAL_CROSSTALK_CORRECTED_RANGE_MM_SD1 0x00AA + + + + + + + + + + + + + + + +#define VL53L1_RESULT__FINAL_CROSSTALK_CORRECTED_RANGE_MM_SD1_HI 0x00AA + + + + + + + +#define VL53L1_RESULT__FINAL_CROSSTALK_CORRECTED_RANGE_MM_SD1_LO 0x00AB + + + + + + + +#define VL53L1_RESULT__SPARE_0_SD1 0x00AC + + + + + + + + + + + + + + + +#define VL53L1_RESULT__SPARE_0_SD1_HI 0x00AC + + + + + + + +#define VL53L1_RESULT__SPARE_0_SD1_LO 0x00AD + + + + + + + +#define VL53L1_RESULT__SPARE_1_SD1 0x00AE + + + + + + + + + + + + + + + +#define VL53L1_RESULT__SPARE_1_SD1_HI 0x00AE + + + + + + + +#define VL53L1_RESULT__SPARE_1_SD1_LO 0x00AF + + + + + + + +#define VL53L1_RESULT__SPARE_2_SD1 0x00B0 + + + + + + + + + + + + + + + +#define VL53L1_RESULT__SPARE_2_SD1_HI 0x00B0 + + + + + + + +#define VL53L1_RESULT__SPARE_2_SD1_LO 0x00B1 + + + + + + + +#define VL53L1_RESULT__SPARE_3_SD1 0x00B2 + + + + + + + + + + + + + + + +#define VL53L1_RESULT__THRESH_INFO 0x00B3 + + + + + + + + + + + + + + + + +#define VL53L1_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD0 0x00B4 + + + + + + + + + + + + + + + +#define VL53L1_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD0_3 0x00B4 + + + + + + + +#define VL53L1_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD0_2 0x00B5 + + + + + + + +#define VL53L1_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD0_1 0x00B6 + + + + + + + +#define VL53L1_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD0_0 0x00B7 + + + + + + + +#define VL53L1_RESULT_CORE__RANGING_TOTAL_EVENTS_SD0 0x00B8 + + + + + + + + + + + + + + + +#define VL53L1_RESULT_CORE__RANGING_TOTAL_EVENTS_SD0_3 0x00B8 + + + + + + + +#define VL53L1_RESULT_CORE__RANGING_TOTAL_EVENTS_SD0_2 0x00B9 + + + + + + + +#define VL53L1_RESULT_CORE__RANGING_TOTAL_EVENTS_SD0_1 0x00BA + + + + + + + +#define VL53L1_RESULT_CORE__RANGING_TOTAL_EVENTS_SD0_0 0x00BB + + + + + + + +#define VL53L1_RESULT_CORE__SIGNAL_TOTAL_EVENTS_SD0 0x00BC + + + + + + + + + + + + + + + +#define VL53L1_RESULT_CORE__SIGNAL_TOTAL_EVENTS_SD0_3 0x00BC + + + + + + + +#define VL53L1_RESULT_CORE__SIGNAL_TOTAL_EVENTS_SD0_2 0x00BD + + + + + + + +#define VL53L1_RESULT_CORE__SIGNAL_TOTAL_EVENTS_SD0_1 0x00BE + + + + + + + +#define VL53L1_RESULT_CORE__SIGNAL_TOTAL_EVENTS_SD0_0 0x00BF + + + + + + + +#define VL53L1_RESULT_CORE__TOTAL_PERIODS_ELAPSED_SD0 0x00C0 + + + + + + + + + + + + + + + +#define VL53L1_RESULT_CORE__TOTAL_PERIODS_ELAPSED_SD0_3 0x00C0 + + + + + + + +#define VL53L1_RESULT_CORE__TOTAL_PERIODS_ELAPSED_SD0_2 0x00C1 + + + + + + + +#define VL53L1_RESULT_CORE__TOTAL_PERIODS_ELAPSED_SD0_1 0x00C2 + + + + + + + +#define VL53L1_RESULT_CORE__TOTAL_PERIODS_ELAPSED_SD0_0 0x00C3 + + + + + + + +#define VL53L1_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD1 0x00C4 + + + + + + + + + + + + + + + +#define VL53L1_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD1_3 0x00C4 + + + + + + + +#define VL53L1_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD1_2 0x00C5 + + + + + + + +#define VL53L1_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD1_1 0x00C6 + + + + + + + +#define VL53L1_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD1_0 0x00C7 + + + + + + + +#define VL53L1_RESULT_CORE__RANGING_TOTAL_EVENTS_SD1 0x00C8 + + + + + + + + + + + + + + + +#define VL53L1_RESULT_CORE__RANGING_TOTAL_EVENTS_SD1_3 0x00C8 + + + + + + + +#define VL53L1_RESULT_CORE__RANGING_TOTAL_EVENTS_SD1_2 0x00C9 + + + + + + + +#define VL53L1_RESULT_CORE__RANGING_TOTAL_EVENTS_SD1_1 0x00CA + + + + + + + +#define VL53L1_RESULT_CORE__RANGING_TOTAL_EVENTS_SD1_0 0x00CB + + + + + + + +#define VL53L1_RESULT_CORE__SIGNAL_TOTAL_EVENTS_SD1 0x00CC + + + + + + + + + + + + + + + +#define VL53L1_RESULT_CORE__SIGNAL_TOTAL_EVENTS_SD1_3 0x00CC + + + + + + + +#define VL53L1_RESULT_CORE__SIGNAL_TOTAL_EVENTS_SD1_2 0x00CD + + + + + + + +#define VL53L1_RESULT_CORE__SIGNAL_TOTAL_EVENTS_SD1_1 0x00CE + + + + + + + +#define VL53L1_RESULT_CORE__SIGNAL_TOTAL_EVENTS_SD1_0 0x00CF + + + + + + + +#define VL53L1_RESULT_CORE__TOTAL_PERIODS_ELAPSED_SD1 0x00D0 + + + + + + + + + + + + + + + +#define VL53L1_RESULT_CORE__TOTAL_PERIODS_ELAPSED_SD1_3 0x00D0 + + + + + + + +#define VL53L1_RESULT_CORE__TOTAL_PERIODS_ELAPSED_SD1_2 0x00D1 + + + + + + + +#define VL53L1_RESULT_CORE__TOTAL_PERIODS_ELAPSED_SD1_1 0x00D2 + + + + + + + +#define VL53L1_RESULT_CORE__TOTAL_PERIODS_ELAPSED_SD1_0 0x00D3 + + + + + + + +#define VL53L1_RESULT_CORE__SPARE_0 0x00D4 + + + + + + + + + + + + + + + +#define VL53L1_PHASECAL_RESULT__REFERENCE_PHASE 0x00D6 + + + + + + + + + + + + + + + +#define VL53L1_PHASECAL_RESULT__REFERENCE_PHASE_HI 0x00D6 + + + + + + + +#define VL53L1_PHASECAL_RESULT__REFERENCE_PHASE_LO 0x00D7 + + + + + + + +#define VL53L1_PHASECAL_RESULT__VCSEL_START 0x00D8 + + + + + + + + + + + + + + + +#define VL53L1_REF_SPAD_CHAR_RESULT__NUM_ACTUAL_REF_SPADS 0x00D9 + + + + + + + + + + + + + + + +#define VL53L1_REF_SPAD_CHAR_RESULT__REF_LOCATION 0x00DA + + + + + + + + + + + + + + + +#define VL53L1_VHV_RESULT__COLDBOOT_STATUS 0x00DB + + + + + + + + + + + + + + + +#define VL53L1_VHV_RESULT__SEARCH_RESULT 0x00DC + + + + + + + + + + + + + + + +#define VL53L1_VHV_RESULT__LATEST_SETTING 0x00DD + + + + + + + + + + + + + + + +#define VL53L1_RESULT__OSC_CALIBRATE_VAL 0x00DE + + + + + + + + + + + + + + + +#define VL53L1_RESULT__OSC_CALIBRATE_VAL_HI 0x00DE + + + + + + + +#define VL53L1_RESULT__OSC_CALIBRATE_VAL_LO 0x00DF + + + + + + + +#define VL53L1_ANA_CONFIG__POWERDOWN_GO1 0x00E0 + + + + + + + + + + + + + + + + +#define VL53L1_ANA_CONFIG__REF_BG_CTRL 0x00E1 + + + + + + + + + + + + + + + + +#define VL53L1_ANA_CONFIG__REGDVDD1V2_CTRL 0x00E2 + + + + + + + + + + + + + + + + + +#define VL53L1_ANA_CONFIG__OSC_SLOW_CTRL 0x00E3 + + + + + + + + + + + + + + + + + +#define VL53L1_TEST_MODE__STATUS 0x00E4 + + + + + + + + + + + + + + + +#define VL53L1_FIRMWARE__SYSTEM_STATUS 0x00E5 + + + + + + + + + + + + + + + + +#define VL53L1_FIRMWARE__MODE_STATUS 0x00E6 + + + + + + + + + + + + + + + +#define VL53L1_FIRMWARE__SECONDARY_MODE_STATUS 0x00E7 + + + + + + + + + + + + + + + +#define VL53L1_FIRMWARE__CAL_REPEAT_RATE_COUNTER 0x00E8 + + + + + + + + + + + + + + + +#define VL53L1_FIRMWARE__CAL_REPEAT_RATE_COUNTER_HI 0x00E8 + + + + + + + +#define VL53L1_FIRMWARE__CAL_REPEAT_RATE_COUNTER_LO 0x00E9 + + + + + + + +#define VL53L1_FIRMWARE__HISTOGRAM_BIN 0x00EA + + + + + + + +#define VL53L1_GPH__SYSTEM__THRESH_HIGH 0x00EC + + + + + + + + + + + + + + + +#define VL53L1_GPH__SYSTEM__THRESH_HIGH_HI 0x00EC + + + + + + + +#define VL53L1_GPH__SYSTEM__THRESH_HIGH_LO 0x00ED + + + + + + + +#define VL53L1_GPH__SYSTEM__THRESH_LOW 0x00EE + + + + + + + + + + + + + + + +#define VL53L1_GPH__SYSTEM__THRESH_LOW_HI 0x00EE + + + + + + + +#define VL53L1_GPH__SYSTEM__THRESH_LOW_LO 0x00EF + + + + + + + +#define VL53L1_GPH__SYSTEM__ENABLE_XTALK_PER_QUADRANT 0x00F0 + + + + + + + + + + + + + + + +#define VL53L1_GPH__SPARE_0 0x00F1 + + + + + + + + + + + + + + + + + +#define VL53L1_GPH__SD_CONFIG__WOI_SD0 0x00F2 + + + + + + + + + + + + + + + +#define VL53L1_GPH__SD_CONFIG__WOI_SD1 0x00F3 + + + + + + + + + + + + + + + +#define VL53L1_GPH__SD_CONFIG__INITIAL_PHASE_SD0 0x00F4 + + + + + + + + + + + + + + + +#define VL53L1_GPH__SD_CONFIG__INITIAL_PHASE_SD1 0x00F5 + + + + + + + + + + + + + + + +#define VL53L1_GPH__SD_CONFIG__FIRST_ORDER_SELECT 0x00F6 + + + + + + + + + + + + + + + + +#define VL53L1_GPH__SD_CONFIG__QUANTIFIER 0x00F7 + + + + + + + + + + + + + + + +#define VL53L1_GPH__ROI_CONFIG__USER_ROI_CENTRE_SPAD 0x00F8 + + + + + + + + + + + + + + + +#define VL53L1_GPH__ROI_CONFIG__USER_ROI_REQUESTED_GLOBAL_XY_SIZE 0x00F9 + + + + + + + + + + + + + + + +#define VL53L1_GPH__SYSTEM__SEQUENCE_CONFIG 0x00FA + + + + + + + + + + + + + + + + + + + + + + +#define VL53L1_GPH__GPH_ID 0x00FB + + + + + + + + + + + + + + + +#define VL53L1_SYSTEM__INTERRUPT_SET 0x00FC + + + + + + + + + + + + + + + + +#define VL53L1_INTERRUPT_MANAGER__ENABLES 0x00FD + + + + + + + + + + + + + + + + + + + +#define VL53L1_INTERRUPT_MANAGER__CLEAR 0x00FE + + + + + + + + + + + + + + + + + + + +#define VL53L1_INTERRUPT_MANAGER__STATUS 0x00FF + + + + + + + + + + + + + + + + + + + +#define VL53L1_MCU_TO_HOST_BANK__WR_ACCESS_EN 0x0100 + + + + + + + + + + + + + + + +#define VL53L1_POWER_MANAGEMENT__GO1_RESET_STATUS 0x0101 + + + + + + + + + + + + + + + +#define VL53L1_PAD_STARTUP_MODE__VALUE_RO 0x0102 + + + + + + + + + + + + + + + + +#define VL53L1_PAD_STARTUP_MODE__VALUE_CTRL 0x0103 + + + + + + + + + + + + + + + + + + +#define VL53L1_PLL_PERIOD_US 0x0104 + + + + + + + + + + + + + + + +#define VL53L1_PLL_PERIOD_US_3 0x0104 + + + + + + + +#define VL53L1_PLL_PERIOD_US_2 0x0105 + + + + + + + +#define VL53L1_PLL_PERIOD_US_1 0x0106 + + + + + + + +#define VL53L1_PLL_PERIOD_US_0 0x0107 + + + + + + + +#define VL53L1_INTERRUPT_SCHEDULER__DATA_OUT 0x0108 + + + + + + + + + + + + + + + +#define VL53L1_INTERRUPT_SCHEDULER__DATA_OUT_3 0x0108 + + + + + + + +#define VL53L1_INTERRUPT_SCHEDULER__DATA_OUT_2 0x0109 + + + + + + + +#define VL53L1_INTERRUPT_SCHEDULER__DATA_OUT_1 0x010A + + + + + + + +#define VL53L1_INTERRUPT_SCHEDULER__DATA_OUT_0 0x010B + + + + + + + +#define VL53L1_NVM_BIST__COMPLETE 0x010C + + + + + + + + + + + + + + + +#define VL53L1_NVM_BIST__STATUS 0x010D + + + + + + + + + + + + + + + +#define VL53L1_IDENTIFICATION__MODEL_ID 0x010F + + + + + + + + + + + + + + + +#define VL53L1_IDENTIFICATION__MODULE_TYPE 0x0110 + + + + + + + + + + + + + + + +#define VL53L1_IDENTIFICATION__REVISION_ID 0x0111 + + + + + + + + + + + + + + + + +#define VL53L1_IDENTIFICATION__MODULE_ID 0x0112 + + + + + + + + + + + + + + + +#define VL53L1_IDENTIFICATION__MODULE_ID_HI 0x0112 + + + + + + + +#define VL53L1_IDENTIFICATION__MODULE_ID_LO 0x0113 + + + + + + + +#define VL53L1_ANA_CONFIG__FAST_OSC__TRIM_MAX 0x0114 + + + + + + + + + + + + + + + +#define VL53L1_ANA_CONFIG__FAST_OSC__FREQ_SET 0x0115 + + + + + + + + + + + + + + + +#define VL53L1_ANA_CONFIG__VCSEL_TRIM 0x0116 + + + + + + + + + + + + + + + +#define VL53L1_ANA_CONFIG__VCSEL_SELION 0x0117 + + + + + + + + + + + + + + + +#define VL53L1_ANA_CONFIG__VCSEL_SELION_MAX 0x0118 + + + + + + + + + + + + + + + +#define VL53L1_PROTECTED_LASER_SAFETY__LOCK_BIT 0x0119 + + + + + + + + + + + + + + + +#define VL53L1_LASER_SAFETY__KEY 0x011A + + + + + + + + + + + + + + + +#define VL53L1_LASER_SAFETY__KEY_RO 0x011B + + + + + + + + + + + + + + + +#define VL53L1_LASER_SAFETY__CLIP 0x011C + + + + + + + + + + + + + + + +#define VL53L1_LASER_SAFETY__MULT 0x011D + + + + + + + + + + + + + + + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_0 0x011E + + + + + + + + + + + + + + + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_1 0x011F + + + + + + + + + + + + + + + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_2 0x0120 + + + + + + + + + + + + + + + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_3 0x0121 + + + + + + + + + + + + + + + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_4 0x0122 + + + + + + + + + + + + + + + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_5 0x0123 + + + + + + + + + + + + + + + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_6 0x0124 + + + + + + + + + + + + + + + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_7 0x0125 + + + + + + + + + + + + + + + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_8 0x0126 + + + + + + + + + + + + + + + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_9 0x0127 + + + + + + + + + + + + + + + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_10 0x0128 + + + + + + + + + + + + + + + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_11 0x0129 + + + + + + + + + + + + + + + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_12 0x012A + + + + + + + + + + + + + + + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_13 0x012B + + + + + + + + + + + + + + + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_14 0x012C + + + + + + + + + + + + + + + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_15 0x012D + + + + + + + + + + + + + + + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_16 0x012E + + + + + + + + + + + + + + + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_17 0x012F + + + + + + + + + + + + + + + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_18 0x0130 + + + + + + + + + + + + + + + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_19 0x0131 + + + + + + + + + + + + + + + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_20 0x0132 + + + + + + + + + + + + + + + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_21 0x0133 + + + + + + + + + + + + + + + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_22 0x0134 + + + + + + + + + + + + + + + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_23 0x0135 + + + + + + + + + + + + + + + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_24 0x0136 + + + + + + + + + + + + + + + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_25 0x0137 + + + + + + + + + + + + + + + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_26 0x0138 + + + + + + + + + + + + + + + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_27 0x0139 + + + + + + + + + + + + + + + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_28 0x013A + + + + + + + + + + + + + + + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_29 0x013B + + + + + + + + + + + + + + + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_30 0x013C + + + + + + + + + + + + + + + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_31 0x013D + + + + + + + + + + + + + + + +#define VL53L1_ROI_CONFIG__MODE_ROI_CENTRE_SPAD 0x013E + + + + + + + + + + + + + + + +#define VL53L1_ROI_CONFIG__MODE_ROI_XY_SIZE 0x013F + + + + + + + + + + + + + + + +#define VL53L1_GO2_HOST_BANK_ACCESS__OVERRIDE 0x0300 + + + + + + + +#define VL53L1_MCU_UTIL_MULTIPLIER__MULTIPLICAND 0x0400 + + + + + + + +#define VL53L1_MCU_UTIL_MULTIPLIER__MULTIPLICAND_3 0x0400 + + + + + + + +#define VL53L1_MCU_UTIL_MULTIPLIER__MULTIPLICAND_2 0x0401 + + + + + + + +#define VL53L1_MCU_UTIL_MULTIPLIER__MULTIPLICAND_1 0x0402 + + + + + + + +#define VL53L1_MCU_UTIL_MULTIPLIER__MULTIPLICAND_0 0x0403 + + + + + + + +#define VL53L1_MCU_UTIL_MULTIPLIER__MULTIPLIER 0x0404 + + + + + + + +#define VL53L1_MCU_UTIL_MULTIPLIER__MULTIPLIER_3 0x0404 + + + + + + + +#define VL53L1_MCU_UTIL_MULTIPLIER__MULTIPLIER_2 0x0405 + + + + + + + +#define VL53L1_MCU_UTIL_MULTIPLIER__MULTIPLIER_1 0x0406 + + + + + + + +#define VL53L1_MCU_UTIL_MULTIPLIER__MULTIPLIER_0 0x0407 + + + + + + + +#define VL53L1_MCU_UTIL_MULTIPLIER__PRODUCT_HI 0x0408 + + + + + + + +#define VL53L1_MCU_UTIL_MULTIPLIER__PRODUCT_HI_3 0x0408 + + + + + + + +#define VL53L1_MCU_UTIL_MULTIPLIER__PRODUCT_HI_2 0x0409 + + + + + + + +#define VL53L1_MCU_UTIL_MULTIPLIER__PRODUCT_HI_1 0x040A + + + + + + + +#define VL53L1_MCU_UTIL_MULTIPLIER__PRODUCT_HI_0 0x040B + + + + + + + +#define VL53L1_MCU_UTIL_MULTIPLIER__PRODUCT_LO 0x040C + + + + + + + +#define VL53L1_MCU_UTIL_MULTIPLIER__PRODUCT_LO_3 0x040C + + + + + + + +#define VL53L1_MCU_UTIL_MULTIPLIER__PRODUCT_LO_2 0x040D + + + + + + + +#define VL53L1_MCU_UTIL_MULTIPLIER__PRODUCT_LO_1 0x040E + + + + + + + +#define VL53L1_MCU_UTIL_MULTIPLIER__PRODUCT_LO_0 0x040F + + + + + + + +#define VL53L1_MCU_UTIL_MULTIPLIER__START 0x0410 + + + + + + + +#define VL53L1_MCU_UTIL_MULTIPLIER__STATUS 0x0411 + + + + + + + +#define VL53L1_MCU_UTIL_DIVIDER__START 0x0412 + + + + + + + +#define VL53L1_MCU_UTIL_DIVIDER__STATUS 0x0413 + + + + + + + +#define VL53L1_MCU_UTIL_DIVIDER__DIVIDEND 0x0414 + + + + + + + +#define VL53L1_MCU_UTIL_DIVIDER__DIVIDEND_3 0x0414 + + + + + + + +#define VL53L1_MCU_UTIL_DIVIDER__DIVIDEND_2 0x0415 + + + + + + + +#define VL53L1_MCU_UTIL_DIVIDER__DIVIDEND_1 0x0416 + + + + + + + +#define VL53L1_MCU_UTIL_DIVIDER__DIVIDEND_0 0x0417 + + + + + + + +#define VL53L1_MCU_UTIL_DIVIDER__DIVISOR 0x0418 + + + + + + + +#define VL53L1_MCU_UTIL_DIVIDER__DIVISOR_3 0x0418 + + + + + + + +#define VL53L1_MCU_UTIL_DIVIDER__DIVISOR_2 0x0419 + + + + + + + +#define VL53L1_MCU_UTIL_DIVIDER__DIVISOR_1 0x041A + + + + + + + +#define VL53L1_MCU_UTIL_DIVIDER__DIVISOR_0 0x041B + + + + + + + +#define VL53L1_MCU_UTIL_DIVIDER__QUOTIENT 0x041C + + + + + + + +#define VL53L1_MCU_UTIL_DIVIDER__QUOTIENT_3 0x041C + + + + + + + +#define VL53L1_MCU_UTIL_DIVIDER__QUOTIENT_2 0x041D + + + + + + + +#define VL53L1_MCU_UTIL_DIVIDER__QUOTIENT_1 0x041E + + + + + + + +#define VL53L1_MCU_UTIL_DIVIDER__QUOTIENT_0 0x041F + + + + + + + +#define VL53L1_TIMER0__VALUE_IN 0x0420 + + + + + + + +#define VL53L1_TIMER0__VALUE_IN_3 0x0420 + + + + + + + +#define VL53L1_TIMER0__VALUE_IN_2 0x0421 + + + + + + + +#define VL53L1_TIMER0__VALUE_IN_1 0x0422 + + + + + + + +#define VL53L1_TIMER0__VALUE_IN_0 0x0423 + + + + + + + +#define VL53L1_TIMER1__VALUE_IN 0x0424 + + + + + + + +#define VL53L1_TIMER1__VALUE_IN_3 0x0424 + + + + + + + +#define VL53L1_TIMER1__VALUE_IN_2 0x0425 + + + + + + + +#define VL53L1_TIMER1__VALUE_IN_1 0x0426 + + + + + + + +#define VL53L1_TIMER1__VALUE_IN_0 0x0427 + + + + + + + +#define VL53L1_TIMER0__CTRL 0x0428 + + + + + + + +#define VL53L1_TIMER1__CTRL 0x0429 + + + + + + + +#define VL53L1_MCU_GENERAL_PURPOSE__GP_0 0x042C + + + + + + + + + + + + + + + +#define VL53L1_MCU_GENERAL_PURPOSE__GP_1 0x042D + + + + + + + + + + + + + + + +#define VL53L1_MCU_GENERAL_PURPOSE__GP_2 0x042E + + + + + + + + + + + + + + + +#define VL53L1_MCU_GENERAL_PURPOSE__GP_3 0x042F + + + + + + + + + + + + + + + +#define VL53L1_MCU_RANGE_CALC__CONFIG 0x0430 + + + + + + + + + + + + + + + + + + + + + +#define VL53L1_MCU_RANGE_CALC__OFFSET_CORRECTED_RANGE 0x0432 + + + + + + + + + + + + + + + +#define VL53L1_MCU_RANGE_CALC__OFFSET_CORRECTED_RANGE_HI 0x0432 + + + + + + + +#define VL53L1_MCU_RANGE_CALC__OFFSET_CORRECTED_RANGE_LO 0x0433 + + + + + + + +#define VL53L1_MCU_RANGE_CALC__SPARE_4 0x0434 + + + + + + + + + + + + + + + +#define VL53L1_MCU_RANGE_CALC__SPARE_4_3 0x0434 + + + + + + + +#define VL53L1_MCU_RANGE_CALC__SPARE_4_2 0x0435 + + + + + + + +#define VL53L1_MCU_RANGE_CALC__SPARE_4_1 0x0436 + + + + + + + +#define VL53L1_MCU_RANGE_CALC__SPARE_4_0 0x0437 + + + + + + + +#define VL53L1_MCU_RANGE_CALC__AMBIENT_DURATION_PRE_CALC 0x0438 + + + + + + + + + + + + + + + +#define VL53L1_MCU_RANGE_CALC__AMBIENT_DURATION_PRE_CALC_HI 0x0438 + + + + + + + +#define VL53L1_MCU_RANGE_CALC__AMBIENT_DURATION_PRE_CALC_LO 0x0439 + + + + + + + +#define VL53L1_MCU_RANGE_CALC__ALGO_VCSEL_PERIOD 0x043C + + + + + + + + + + + + + + + +#define VL53L1_MCU_RANGE_CALC__SPARE_5 0x043D + + + + + + + + + + + + + + + +#define VL53L1_MCU_RANGE_CALC__ALGO_TOTAL_PERIODS 0x043E + + + + + + + + + + + + + + + +#define VL53L1_MCU_RANGE_CALC__ALGO_TOTAL_PERIODS_HI 0x043E + + + + + + + +#define VL53L1_MCU_RANGE_CALC__ALGO_TOTAL_PERIODS_LO 0x043F + + + + + + + +#define VL53L1_MCU_RANGE_CALC__ALGO_ACCUM_PHASE 0x0440 + + + + + + + + + + + + + + + +#define VL53L1_MCU_RANGE_CALC__ALGO_ACCUM_PHASE_3 0x0440 + + + + + + + +#define VL53L1_MCU_RANGE_CALC__ALGO_ACCUM_PHASE_2 0x0441 + + + + + + + +#define VL53L1_MCU_RANGE_CALC__ALGO_ACCUM_PHASE_1 0x0442 + + + + + + + +#define VL53L1_MCU_RANGE_CALC__ALGO_ACCUM_PHASE_0 0x0443 + + + + + + + +#define VL53L1_MCU_RANGE_CALC__ALGO_SIGNAL_EVENTS 0x0444 + + + + + + + + + + + + + + + +#define VL53L1_MCU_RANGE_CALC__ALGO_SIGNAL_EVENTS_3 0x0444 + + + + + + + +#define VL53L1_MCU_RANGE_CALC__ALGO_SIGNAL_EVENTS_2 0x0445 + + + + + + + +#define VL53L1_MCU_RANGE_CALC__ALGO_SIGNAL_EVENTS_1 0x0446 + + + + + + + +#define VL53L1_MCU_RANGE_CALC__ALGO_SIGNAL_EVENTS_0 0x0447 + + + + + + + +#define VL53L1_MCU_RANGE_CALC__ALGO_AMBIENT_EVENTS 0x0448 + + + + + + + + + + + + + + + +#define VL53L1_MCU_RANGE_CALC__ALGO_AMBIENT_EVENTS_3 0x0448 + + + + + + + +#define VL53L1_MCU_RANGE_CALC__ALGO_AMBIENT_EVENTS_2 0x0449 + + + + + + + +#define VL53L1_MCU_RANGE_CALC__ALGO_AMBIENT_EVENTS_1 0x044A + + + + + + + +#define VL53L1_MCU_RANGE_CALC__ALGO_AMBIENT_EVENTS_0 0x044B + + + + + + + +#define VL53L1_MCU_RANGE_CALC__SPARE_6 0x044C + + + + + + + + + + + + + + + +#define VL53L1_MCU_RANGE_CALC__SPARE_6_HI 0x044C + + + + + + + +#define VL53L1_MCU_RANGE_CALC__SPARE_6_LO 0x044D + + + + + + + +#define VL53L1_MCU_RANGE_CALC__ALGO_ADJUST_VCSEL_PERIOD 0x044E + + + + + + + + + + + + + + + +#define VL53L1_MCU_RANGE_CALC__ALGO_ADJUST_VCSEL_PERIOD_HI 0x044E + + + + + + + +#define VL53L1_MCU_RANGE_CALC__ALGO_ADJUST_VCSEL_PERIOD_LO 0x044F + + + + + + + +#define VL53L1_MCU_RANGE_CALC__NUM_SPADS 0x0450 + + + + + + + + + + + + + + + +#define VL53L1_MCU_RANGE_CALC__NUM_SPADS_HI 0x0450 + + + + + + + +#define VL53L1_MCU_RANGE_CALC__NUM_SPADS_LO 0x0451 + + + + + + + +#define VL53L1_MCU_RANGE_CALC__PHASE_OUTPUT 0x0452 + + + + + + + + + + + + + + + +#define VL53L1_MCU_RANGE_CALC__PHASE_OUTPUT_HI 0x0452 + + + + + + + +#define VL53L1_MCU_RANGE_CALC__PHASE_OUTPUT_LO 0x0453 + + + + + + + +#define VL53L1_MCU_RANGE_CALC__RATE_PER_SPAD_MCPS 0x0454 + + + + + + + + + + + + + + + +#define VL53L1_MCU_RANGE_CALC__RATE_PER_SPAD_MCPS_3 0x0454 + + + + + + + +#define VL53L1_MCU_RANGE_CALC__RATE_PER_SPAD_MCPS_2 0x0455 + + + + + + + +#define VL53L1_MCU_RANGE_CALC__RATE_PER_SPAD_MCPS_1 0x0456 + + + + + + + +#define VL53L1_MCU_RANGE_CALC__RATE_PER_SPAD_MCPS_0 0x0457 + + + + + + + +#define VL53L1_MCU_RANGE_CALC__SPARE_7 0x0458 + + + + + + + + + + + + + + + +#define VL53L1_MCU_RANGE_CALC__SPARE_8 0x0459 + + + + + + + + + + + + + + + +#define VL53L1_MCU_RANGE_CALC__PEAK_SIGNAL_RATE_MCPS 0x045A + + + + + + + + + + + + + + + +#define VL53L1_MCU_RANGE_CALC__PEAK_SIGNAL_RATE_MCPS_HI 0x045A + + + + + + + +#define VL53L1_MCU_RANGE_CALC__PEAK_SIGNAL_RATE_MCPS_LO 0x045B + + + + + + + +#define VL53L1_MCU_RANGE_CALC__AVG_SIGNAL_RATE_MCPS 0x045C + + + + + + + + + + + + + + + +#define VL53L1_MCU_RANGE_CALC__AVG_SIGNAL_RATE_MCPS_HI 0x045C + + + + + + + +#define VL53L1_MCU_RANGE_CALC__AVG_SIGNAL_RATE_MCPS_LO 0x045D + + + + + + + +#define VL53L1_MCU_RANGE_CALC__AMBIENT_RATE_MCPS 0x045E + + + + + + + + + + + + + + + +#define VL53L1_MCU_RANGE_CALC__AMBIENT_RATE_MCPS_HI 0x045E + + + + + + + +#define VL53L1_MCU_RANGE_CALC__AMBIENT_RATE_MCPS_LO 0x045F + + + + + + + +#define VL53L1_MCU_RANGE_CALC__XTALK 0x0460 + + + + + + + + + + + + + + + +#define VL53L1_MCU_RANGE_CALC__XTALK_HI 0x0460 + + + + + + + +#define VL53L1_MCU_RANGE_CALC__XTALK_LO 0x0461 + + + + + + + +#define VL53L1_MCU_RANGE_CALC__CALC_STATUS 0x0462 + + + + + + + + + + + + + + + +#define VL53L1_MCU_RANGE_CALC__DEBUG 0x0463 + + + + + + + + + + + + + + + +#define VL53L1_MCU_RANGE_CALC__PEAK_SIGNAL_RATE_XTALK_CORR_MCPS 0x0464 + + + + + + + + + + + + + + + +#define VL53L1_MCU_RANGE_CALC__PEAK_SIGNAL_RATE_XTALK_CORR_MCPS_HI 0x0464 + + + + + + + +#define VL53L1_MCU_RANGE_CALC__PEAK_SIGNAL_RATE_XTALK_CORR_MCPS_LO 0x0465 + + + + + + + +#define VL53L1_MCU_RANGE_CALC__SPARE_0 0x0468 + + + + + + + + + + + + + + + +#define VL53L1_MCU_RANGE_CALC__SPARE_1 0x0469 + + + + + + + + + + + + + + + +#define VL53L1_MCU_RANGE_CALC__SPARE_2 0x046A + + + + + + + + + + + + + + + +#define VL53L1_MCU_RANGE_CALC__SPARE_3 0x046B + + + + + + + + + + + + + + + +#define VL53L1_PATCH__CTRL 0x0470 + + + + + + + +#define VL53L1_PATCH__JMP_ENABLES 0x0472 + + + + + + + +#define VL53L1_PATCH__JMP_ENABLES_HI 0x0472 + + + + + + + +#define VL53L1_PATCH__JMP_ENABLES_LO 0x0473 + + + + + + + +#define VL53L1_PATCH__DATA_ENABLES 0x0474 + + + + + + + +#define VL53L1_PATCH__DATA_ENABLES_HI 0x0474 + + + + + + + +#define VL53L1_PATCH__DATA_ENABLES_LO 0x0475 + + + + + + + +#define VL53L1_PATCH__OFFSET_0 0x0476 + + + + + + + +#define VL53L1_PATCH__OFFSET_0_HI 0x0476 + + + + + + + +#define VL53L1_PATCH__OFFSET_0_LO 0x0477 + + + + + + + +#define VL53L1_PATCH__OFFSET_1 0x0478 + + + + + + + +#define VL53L1_PATCH__OFFSET_1_HI 0x0478 + + + + + + + +#define VL53L1_PATCH__OFFSET_1_LO 0x0479 + + + + + + + +#define VL53L1_PATCH__OFFSET_2 0x047A + + + + + + + +#define VL53L1_PATCH__OFFSET_2_HI 0x047A + + + + + + + +#define VL53L1_PATCH__OFFSET_2_LO 0x047B + + + + + + + +#define VL53L1_PATCH__OFFSET_3 0x047C + + + + + + + +#define VL53L1_PATCH__OFFSET_3_HI 0x047C + + + + + + + +#define VL53L1_PATCH__OFFSET_3_LO 0x047D + + + + + + + +#define VL53L1_PATCH__OFFSET_4 0x047E + + + + + + + +#define VL53L1_PATCH__OFFSET_4_HI 0x047E + + + + + + + +#define VL53L1_PATCH__OFFSET_4_LO 0x047F + + + + + + + +#define VL53L1_PATCH__OFFSET_5 0x0480 + + + + + + + +#define VL53L1_PATCH__OFFSET_5_HI 0x0480 + + + + + + + +#define VL53L1_PATCH__OFFSET_5_LO 0x0481 + + + + + + + +#define VL53L1_PATCH__OFFSET_6 0x0482 + + + + + + + +#define VL53L1_PATCH__OFFSET_6_HI 0x0482 + + + + + + + +#define VL53L1_PATCH__OFFSET_6_LO 0x0483 + + + + + + + +#define VL53L1_PATCH__OFFSET_7 0x0484 + + + + + + + +#define VL53L1_PATCH__OFFSET_7_HI 0x0484 + + + + + + + +#define VL53L1_PATCH__OFFSET_7_LO 0x0485 + + + + + + + +#define VL53L1_PATCH__OFFSET_8 0x0486 + + + + + + + +#define VL53L1_PATCH__OFFSET_8_HI 0x0486 + + + + + + + +#define VL53L1_PATCH__OFFSET_8_LO 0x0487 + + + + + + + +#define VL53L1_PATCH__OFFSET_9 0x0488 + + + + + + + +#define VL53L1_PATCH__OFFSET_9_HI 0x0488 + + + + + + + +#define VL53L1_PATCH__OFFSET_9_LO 0x0489 + + + + + + + +#define VL53L1_PATCH__OFFSET_10 0x048A + + + + + + + +#define VL53L1_PATCH__OFFSET_10_HI 0x048A + + + + + + + +#define VL53L1_PATCH__OFFSET_10_LO 0x048B + + + + + + + +#define VL53L1_PATCH__OFFSET_11 0x048C + + + + + + + +#define VL53L1_PATCH__OFFSET_11_HI 0x048C + + + + + + + +#define VL53L1_PATCH__OFFSET_11_LO 0x048D + + + + + + + +#define VL53L1_PATCH__OFFSET_12 0x048E + + + + + + + +#define VL53L1_PATCH__OFFSET_12_HI 0x048E + + + + + + + +#define VL53L1_PATCH__OFFSET_12_LO 0x048F + + + + + + + +#define VL53L1_PATCH__OFFSET_13 0x0490 + + + + + + + +#define VL53L1_PATCH__OFFSET_13_HI 0x0490 + + + + + + + +#define VL53L1_PATCH__OFFSET_13_LO 0x0491 + + + + + + + +#define VL53L1_PATCH__OFFSET_14 0x0492 + + + + + + + +#define VL53L1_PATCH__OFFSET_14_HI 0x0492 + + + + + + + +#define VL53L1_PATCH__OFFSET_14_LO 0x0493 + + + + + + + +#define VL53L1_PATCH__OFFSET_15 0x0494 + + + + + + + +#define VL53L1_PATCH__OFFSET_15_HI 0x0494 + + + + + + + +#define VL53L1_PATCH__OFFSET_15_LO 0x0495 + + + + + + + +#define VL53L1_PATCH__ADDRESS_0 0x0496 + + + + + + + +#define VL53L1_PATCH__ADDRESS_0_HI 0x0496 + + + + + + + +#define VL53L1_PATCH__ADDRESS_0_LO 0x0497 + + + + + + + +#define VL53L1_PATCH__ADDRESS_1 0x0498 + + + + + + + +#define VL53L1_PATCH__ADDRESS_1_HI 0x0498 + + + + + + + +#define VL53L1_PATCH__ADDRESS_1_LO 0x0499 + + + + + + + +#define VL53L1_PATCH__ADDRESS_2 0x049A + + + + + + + +#define VL53L1_PATCH__ADDRESS_2_HI 0x049A + + + + + + + +#define VL53L1_PATCH__ADDRESS_2_LO 0x049B + + + + + + + +#define VL53L1_PATCH__ADDRESS_3 0x049C + + + + + + + +#define VL53L1_PATCH__ADDRESS_3_HI 0x049C + + + + + + + +#define VL53L1_PATCH__ADDRESS_3_LO 0x049D + + + + + + + +#define VL53L1_PATCH__ADDRESS_4 0x049E + + + + + + + +#define VL53L1_PATCH__ADDRESS_4_HI 0x049E + + + + + + + +#define VL53L1_PATCH__ADDRESS_4_LO 0x049F + + + + + + + +#define VL53L1_PATCH__ADDRESS_5 0x04A0 + + + + + + + +#define VL53L1_PATCH__ADDRESS_5_HI 0x04A0 + + + + + + + +#define VL53L1_PATCH__ADDRESS_5_LO 0x04A1 + + + + + + + +#define VL53L1_PATCH__ADDRESS_6 0x04A2 + + + + + + + +#define VL53L1_PATCH__ADDRESS_6_HI 0x04A2 + + + + + + + +#define VL53L1_PATCH__ADDRESS_6_LO 0x04A3 + + + + + + + +#define VL53L1_PATCH__ADDRESS_7 0x04A4 + + + + + + + +#define VL53L1_PATCH__ADDRESS_7_HI 0x04A4 + + + + + + + +#define VL53L1_PATCH__ADDRESS_7_LO 0x04A5 + + + + + + + +#define VL53L1_PATCH__ADDRESS_8 0x04A6 + + + + + + + +#define VL53L1_PATCH__ADDRESS_8_HI 0x04A6 + + + + + + + +#define VL53L1_PATCH__ADDRESS_8_LO 0x04A7 + + + + + + + +#define VL53L1_PATCH__ADDRESS_9 0x04A8 + + + + + + + +#define VL53L1_PATCH__ADDRESS_9_HI 0x04A8 + + + + + + + +#define VL53L1_PATCH__ADDRESS_9_LO 0x04A9 + + + + + + + +#define VL53L1_PATCH__ADDRESS_10 0x04AA + + + + + + + +#define VL53L1_PATCH__ADDRESS_10_HI 0x04AA + + + + + + + +#define VL53L1_PATCH__ADDRESS_10_LO 0x04AB + + + + + + + +#define VL53L1_PATCH__ADDRESS_11 0x04AC + + + + + + + +#define VL53L1_PATCH__ADDRESS_11_HI 0x04AC + + + + + + + +#define VL53L1_PATCH__ADDRESS_11_LO 0x04AD + + + + + + + +#define VL53L1_PATCH__ADDRESS_12 0x04AE + + + + + + + +#define VL53L1_PATCH__ADDRESS_12_HI 0x04AE + + + + + + + +#define VL53L1_PATCH__ADDRESS_12_LO 0x04AF + + + + + + + +#define VL53L1_PATCH__ADDRESS_13 0x04B0 + + + + + + + +#define VL53L1_PATCH__ADDRESS_13_HI 0x04B0 + + + + + + + +#define VL53L1_PATCH__ADDRESS_13_LO 0x04B1 + + + + + + + +#define VL53L1_PATCH__ADDRESS_14 0x04B2 + + + + + + + +#define VL53L1_PATCH__ADDRESS_14_HI 0x04B2 + + + + + + + +#define VL53L1_PATCH__ADDRESS_14_LO 0x04B3 + + + + + + + +#define VL53L1_PATCH__ADDRESS_15 0x04B4 + + + + + + + +#define VL53L1_PATCH__ADDRESS_15_HI 0x04B4 + + + + + + + +#define VL53L1_PATCH__ADDRESS_15_LO 0x04B5 + + + + + + + +#define VL53L1_SPI_ASYNC_MUX__CTRL 0x04C0 + + + + + + + +#define VL53L1_CLK__CONFIG 0x04C4 + + + + + + + + + + + + + + + +#define VL53L1_GPIO_LV_MUX__CTRL 0x04CC + + + + + + + + + + + + + + + + +#define VL53L1_GPIO_LV_PAD__CTRL 0x04CD + + + + + + + + + + + + + + + +#define VL53L1_PAD_I2C_LV__CONFIG 0x04D0 + + + + + + + +#define VL53L1_PAD_STARTUP_MODE__VALUE_RO_GO1 0x04D4 + + + + + + + + + + + + + + + +#define VL53L1_HOST_IF__STATUS_GO1 0x04D5 + + + + + + + + + + + + + + + +#define VL53L1_MCU_CLK_GATING__CTRL 0x04D8 + + + + + + + + + + + + + + + + + + +#define VL53L1_TEST__BIST_ROM_CTRL 0x04E0 + + + + + + + +#define VL53L1_TEST__BIST_ROM_RESULT 0x04E1 + + + + + + + +#define VL53L1_TEST__BIST_ROM_MCU_SIG 0x04E2 + + + + + + + +#define VL53L1_TEST__BIST_ROM_MCU_SIG_HI 0x04E2 + + + + + + + +#define VL53L1_TEST__BIST_ROM_MCU_SIG_LO 0x04E3 + + + + + + + +#define VL53L1_TEST__BIST_RAM_CTRL 0x04E4 + + + + + + + +#define VL53L1_TEST__BIST_RAM_RESULT 0x04E5 + + + + + + + +#define VL53L1_TEST__TMC 0x04E8 + + + + + + + +#define VL53L1_TEST__PLL_BIST_MIN_THRESHOLD 0x04F0 + + + + + + + +#define VL53L1_TEST__PLL_BIST_MIN_THRESHOLD_HI 0x04F0 + + + + + + + +#define VL53L1_TEST__PLL_BIST_MIN_THRESHOLD_LO 0x04F1 + + + + + + + +#define VL53L1_TEST__PLL_BIST_MAX_THRESHOLD 0x04F2 + + + + + + + +#define VL53L1_TEST__PLL_BIST_MAX_THRESHOLD_HI 0x04F2 + + + + + + + +#define VL53L1_TEST__PLL_BIST_MAX_THRESHOLD_LO 0x04F3 + + + + + + + +#define VL53L1_TEST__PLL_BIST_COUNT_OUT 0x04F4 + + + + + + + +#define VL53L1_TEST__PLL_BIST_COUNT_OUT_HI 0x04F4 + + + + + + + +#define VL53L1_TEST__PLL_BIST_COUNT_OUT_LO 0x04F5 + + + + + + + +#define VL53L1_TEST__PLL_BIST_GONOGO 0x04F6 + + + + + + + +#define VL53L1_TEST__PLL_BIST_CTRL 0x04F7 + + + + + + + +#define VL53L1_RANGING_CORE__DEVICE_ID 0x0680 + + + + + + + +#define VL53L1_RANGING_CORE__REVISION_ID 0x0681 + + + + + + + +#define VL53L1_RANGING_CORE__CLK_CTRL1 0x0683 + + + + + + + +#define VL53L1_RANGING_CORE__CLK_CTRL2 0x0684 + + + + + + + +#define VL53L1_RANGING_CORE__WOI_1 0x0685 + + + + + + + +#define VL53L1_RANGING_CORE__WOI_REF_1 0x0686 + + + + + + + +#define VL53L1_RANGING_CORE__START_RANGING 0x0687 + + + + + + + +#define VL53L1_RANGING_CORE__LOW_LIMIT_1 0x0690 + + + + + + + +#define VL53L1_RANGING_CORE__HIGH_LIMIT_1 0x0691 + + + + + + + +#define VL53L1_RANGING_CORE__LOW_LIMIT_REF_1 0x0692 + + + + + + + +#define VL53L1_RANGING_CORE__HIGH_LIMIT_REF_1 0x0693 + + + + + + + +#define VL53L1_RANGING_CORE__QUANTIFIER_1_MSB 0x0694 + + + + + + + +#define VL53L1_RANGING_CORE__QUANTIFIER_1_LSB 0x0695 + + + + + + + +#define VL53L1_RANGING_CORE__QUANTIFIER_REF_1_MSB 0x0696 + + + + + + + +#define VL53L1_RANGING_CORE__QUANTIFIER_REF_1_LSB 0x0697 + + + + + + + +#define VL53L1_RANGING_CORE__AMBIENT_OFFSET_1_MSB 0x0698 + + + + + + + +#define VL53L1_RANGING_CORE__AMBIENT_OFFSET_1_LSB 0x0699 + + + + + + + +#define VL53L1_RANGING_CORE__AMBIENT_OFFSET_REF_1_MSB 0x069A + + + + + + + +#define VL53L1_RANGING_CORE__AMBIENT_OFFSET_REF_1_LSB 0x069B + + + + + + + +#define VL53L1_RANGING_CORE__FILTER_STRENGTH_1 0x069C + + + + + + + +#define VL53L1_RANGING_CORE__FILTER_STRENGTH_REF_1 0x069D + + + + + + + +#define VL53L1_RANGING_CORE__SIGNAL_EVENT_LIMIT_1_MSB 0x069E + + + + + + + +#define VL53L1_RANGING_CORE__SIGNAL_EVENT_LIMIT_1_LSB 0x069F + + + + + + + +#define VL53L1_RANGING_CORE__SIGNAL_EVENT_LIMIT_REF_1_MSB 0x06A0 + + + + + + + +#define VL53L1_RANGING_CORE__SIGNAL_EVENT_LIMIT_REF_1_LSB 0x06A1 + + + + + + + +#define VL53L1_RANGING_CORE__TIMEOUT_OVERALL_PERIODS_MSB 0x06A4 + + + + + + + +#define VL53L1_RANGING_CORE__TIMEOUT_OVERALL_PERIODS_LSB 0x06A5 + + + + + + + +#define VL53L1_RANGING_CORE__INVERT_HW 0x06A6 + + + + + + + +#define VL53L1_RANGING_CORE__FORCE_HW 0x06A7 + + + + + + + +#define VL53L1_RANGING_CORE__STATIC_HW_VALUE 0x06A8 + + + + + + + +#define VL53L1_RANGING_CORE__FORCE_CONTINUOUS_AMBIENT 0x06A9 + + + + + + + +#define VL53L1_RANGING_CORE__TEST_PHASE_SELECT_TO_FILTER 0x06AA + + + + + + + +#define VL53L1_RANGING_CORE__TEST_PHASE_SELECT_TO_TIMING_GEN 0x06AB + + + + + + + +#define VL53L1_RANGING_CORE__INITIAL_PHASE_VALUE_1 0x06AC + + + + + + + +#define VL53L1_RANGING_CORE__INITIAL_PHASE_VALUE_REF_1 0x06AD + + + + + + + +#define VL53L1_RANGING_CORE__FORCE_UP_IN 0x06AE + + + + + + + +#define VL53L1_RANGING_CORE__FORCE_DN_IN 0x06AF + + + + + + + +#define VL53L1_RANGING_CORE__STATIC_UP_VALUE_1 0x06B0 + + + + + + + +#define VL53L1_RANGING_CORE__STATIC_UP_VALUE_REF_1 0x06B1 + + + + + + + +#define VL53L1_RANGING_CORE__STATIC_DN_VALUE_1 0x06B2 + + + + + + + +#define VL53L1_RANGING_CORE__STATIC_DN_VALUE_REF_1 0x06B3 + + + + + + + +#define VL53L1_RANGING_CORE__MONITOR_UP_DN 0x06B4 + + + + + + + +#define VL53L1_RANGING_CORE__INVERT_UP_DN 0x06B5 + + + + + + + +#define VL53L1_RANGING_CORE__CPUMP_1 0x06B6 + + + + + + + +#define VL53L1_RANGING_CORE__CPUMP_2 0x06B7 + + + + + + + +#define VL53L1_RANGING_CORE__CPUMP_3 0x06B8 + + + + + + + +#define VL53L1_RANGING_CORE__OSC_1 0x06B9 + + + + + + + +#define VL53L1_RANGING_CORE__PLL_1 0x06BB + + + + + + + +#define VL53L1_RANGING_CORE__PLL_2 0x06BC + + + + + + + +#define VL53L1_RANGING_CORE__REFERENCE_1 0x06BD + + + + + + + +#define VL53L1_RANGING_CORE__REFERENCE_3 0x06BF + + + + + + + +#define VL53L1_RANGING_CORE__REFERENCE_4 0x06C0 + + + + + + + +#define VL53L1_RANGING_CORE__REFERENCE_5 0x06C1 + + + + + + + +#define VL53L1_RANGING_CORE__REGAVDD1V2 0x06C3 + + + + + + + +#define VL53L1_RANGING_CORE__CALIB_1 0x06C4 + + + + + + + +#define VL53L1_RANGING_CORE__CALIB_2 0x06C5 + + + + + + + +#define VL53L1_RANGING_CORE__CALIB_3 0x06C6 + + + + + + + +#define VL53L1_RANGING_CORE__TST_MUX_SEL1 0x06C9 + + + + + + + +#define VL53L1_RANGING_CORE__TST_MUX_SEL2 0x06CA + + + + + + + +#define VL53L1_RANGING_CORE__TST_MUX 0x06CB + + + + + + + +#define VL53L1_RANGING_CORE__GPIO_OUT_TESTMUX 0x06CC + + + + + + + +#define VL53L1_RANGING_CORE__CUSTOM_FE 0x06CD + + + + + + + +#define VL53L1_RANGING_CORE__CUSTOM_FE_2 0x06CE + + + + + + + +#define VL53L1_RANGING_CORE__SPAD_READOUT 0x06CF + + + + + + + +#define VL53L1_RANGING_CORE__SPAD_READOUT_1 0x06D0 + + + + + + + +#define VL53L1_RANGING_CORE__SPAD_READOUT_2 0x06D1 + + + + + + + +#define VL53L1_RANGING_CORE__SPAD_PS 0x06D2 + + + + + + + +#define VL53L1_RANGING_CORE__LASER_SAFETY_2 0x06D4 + + + + + + + +#define VL53L1_RANGING_CORE__NVM_CTRL__MODE 0x0780 + + + + + + + +#define VL53L1_RANGING_CORE__NVM_CTRL__PDN 0x0781 + + + + + + + +#define VL53L1_RANGING_CORE__NVM_CTRL__PROGN 0x0782 + + + + + + + +#define VL53L1_RANGING_CORE__NVM_CTRL__READN 0x0783 + + + + + + + +#define VL53L1_RANGING_CORE__NVM_CTRL__PULSE_WIDTH_MSB 0x0784 + + + + + + + +#define VL53L1_RANGING_CORE__NVM_CTRL__PULSE_WIDTH_LSB 0x0785 + + + + + + + +#define VL53L1_RANGING_CORE__NVM_CTRL__HV_RISE_MSB 0x0786 + + + + + + + +#define VL53L1_RANGING_CORE__NVM_CTRL__HV_RISE_LSB 0x0787 + + + + + + + +#define VL53L1_RANGING_CORE__NVM_CTRL__HV_FALL_MSB 0x0788 + + + + + + + +#define VL53L1_RANGING_CORE__NVM_CTRL__HV_FALL_LSB 0x0789 + + + + + + + +#define VL53L1_RANGING_CORE__NVM_CTRL__TST 0x078A + + + + + + + +#define VL53L1_RANGING_CORE__NVM_CTRL__TESTREAD 0x078B + + + + + + + +#define VL53L1_RANGING_CORE__NVM_CTRL__DATAIN_MMM 0x078C + + + + + + + +#define VL53L1_RANGING_CORE__NVM_CTRL__DATAIN_LMM 0x078D + + + + + + + +#define VL53L1_RANGING_CORE__NVM_CTRL__DATAIN_LLM 0x078E + + + + + + + +#define VL53L1_RANGING_CORE__NVM_CTRL__DATAIN_LLL 0x078F + + + + + + + +#define VL53L1_RANGING_CORE__NVM_CTRL__DATAOUT_MMM 0x0790 + + + + + + + +#define VL53L1_RANGING_CORE__NVM_CTRL__DATAOUT_LMM 0x0791 + + + + + + + +#define VL53L1_RANGING_CORE__NVM_CTRL__DATAOUT_LLM 0x0792 + + + + + + + +#define VL53L1_RANGING_CORE__NVM_CTRL__DATAOUT_LLL 0x0793 + + + + + + + +#define VL53L1_RANGING_CORE__NVM_CTRL__ADDR 0x0794 + + + + + + + +#define VL53L1_RANGING_CORE__NVM_CTRL__DATAOUT_ECC 0x0795 + + + + + + + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_0 0x0796 + + + + + + + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_1 0x0797 + + + + + + + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_2 0x0798 + + + + + + + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_3 0x0799 + + + + + + + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_4 0x079A + + + + + + + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_5 0x079B + + + + + + + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_6 0x079C + + + + + + + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_7 0x079D + + + + + + + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_8 0x079E + + + + + + + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_9 0x079F + + + + + + + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_10 0x07A0 + + + + + + + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_11 0x07A1 + + + + + + + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_12 0x07A2 + + + + + + + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_13 0x07A3 + + + + + + + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_14 0x07A4 + + + + + + + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_15 0x07A5 + + + + + + + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_16 0x07A6 + + + + + + + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_17 0x07A7 + + + + + + + +#define VL53L1_RANGING_CORE__SPAD_SHIFT_EN 0x07BA + + + + + + + +#define VL53L1_RANGING_CORE__SPAD_DISABLE_CTRL 0x07BB + + + + + + + +#define VL53L1_RANGING_CORE__SPAD_EN_SHIFT_OUT_DEBUG 0x07BC + + + + + + + +#define VL53L1_RANGING_CORE__SPI_MODE 0x07BD + + + + + + + +#define VL53L1_RANGING_CORE__GPIO_DIR 0x07BE + + + + + + + +#define VL53L1_RANGING_CORE__VCSEL_PERIOD 0x0880 + + + + + + + +#define VL53L1_RANGING_CORE__VCSEL_START 0x0881 + + + + + + + +#define VL53L1_RANGING_CORE__VCSEL_STOP 0x0882 + + + + + + + +#define VL53L1_RANGING_CORE__VCSEL_1 0x0885 + + + + + + + +#define VL53L1_RANGING_CORE__VCSEL_STATUS 0x088D + + + + + + + +#define VL53L1_RANGING_CORE__STATUS 0x0980 + + + + + + + +#define VL53L1_RANGING_CORE__LASER_CONTINUITY_STATE 0x0981 + + + + + + + +#define VL53L1_RANGING_CORE__RANGE_1_MMM 0x0982 + + + + + + + +#define VL53L1_RANGING_CORE__RANGE_1_LMM 0x0983 + + + + + + + +#define VL53L1_RANGING_CORE__RANGE_1_LLM 0x0984 + + + + + + + +#define VL53L1_RANGING_CORE__RANGE_1_LLL 0x0985 + + + + + + + +#define VL53L1_RANGING_CORE__RANGE_REF_1_MMM 0x0986 + + + + + + + +#define VL53L1_RANGING_CORE__RANGE_REF_1_LMM 0x0987 + + + + + + + +#define VL53L1_RANGING_CORE__RANGE_REF_1_LLM 0x0988 + + + + + + + +#define VL53L1_RANGING_CORE__RANGE_REF_1_LLL 0x0989 + + + + + + + +#define VL53L1_RANGING_CORE__AMBIENT_WINDOW_EVENTS_1_MMM 0x098A + + + + + + + +#define VL53L1_RANGING_CORE__AMBIENT_WINDOW_EVENTS_1_LMM 0x098B + + + + + + + +#define VL53L1_RANGING_CORE__AMBIENT_WINDOW_EVENTS_1_LLM 0x098C + + + + + + + +#define VL53L1_RANGING_CORE__AMBIENT_WINDOW_EVENTS_1_LLL 0x098D + + + + + + + +#define VL53L1_RANGING_CORE__RANGING_TOTAL_EVENTS_1_MMM 0x098E + + + + + + + +#define VL53L1_RANGING_CORE__RANGING_TOTAL_EVENTS_1_LMM 0x098F + + + + + + + +#define VL53L1_RANGING_CORE__RANGING_TOTAL_EVENTS_1_LLM 0x0990 + + + + + + + +#define VL53L1_RANGING_CORE__RANGING_TOTAL_EVENTS_1_LLL 0x0991 + + + + + + + +#define VL53L1_RANGING_CORE__SIGNAL_TOTAL_EVENTS_1_MMM 0x0992 + + + + + + + +#define VL53L1_RANGING_CORE__SIGNAL_TOTAL_EVENTS_1_LMM 0x0993 + + + + + + + +#define VL53L1_RANGING_CORE__SIGNAL_TOTAL_EVENTS_1_LLM 0x0994 + + + + + + + +#define VL53L1_RANGING_CORE__SIGNAL_TOTAL_EVENTS_1_LLL 0x0995 + + + + + + + +#define VL53L1_RANGING_CORE__TOTAL_PERIODS_ELAPSED_1_MM 0x0996 + + + + + + + +#define VL53L1_RANGING_CORE__TOTAL_PERIODS_ELAPSED_1_LM 0x0997 + + + + + + + +#define VL53L1_RANGING_CORE__TOTAL_PERIODS_ELAPSED_1_LL 0x0998 + + + + + + + +#define VL53L1_RANGING_CORE__AMBIENT_MISMATCH_MM 0x0999 + + + + + + + +#define VL53L1_RANGING_CORE__AMBIENT_MISMATCH_LM 0x099A + + + + + + + +#define VL53L1_RANGING_CORE__AMBIENT_MISMATCH_LL 0x099B + + + + + + + +#define VL53L1_RANGING_CORE__AMBIENT_WINDOW_EVENTS_REF_1_MMM 0x099C + + + + + + + +#define VL53L1_RANGING_CORE__AMBIENT_WINDOW_EVENTS_REF_1_LMM 0x099D + + + + + + + +#define VL53L1_RANGING_CORE__AMBIENT_WINDOW_EVENTS_REF_1_LLM 0x099E + + + + + + + +#define VL53L1_RANGING_CORE__AMBIENT_WINDOW_EVENTS_REF_1_LLL 0x099F + + + + + + + +#define VL53L1_RANGING_CORE__RANGING_TOTAL_EVENTS_REF_1_MMM 0x09A0 + + + + + + + +#define VL53L1_RANGING_CORE__RANGING_TOTAL_EVENTS_REF_1_LMM 0x09A1 + + + + + + + +#define VL53L1_RANGING_CORE__RANGING_TOTAL_EVENTS_REF_1_LLM 0x09A2 + + + + + + + +#define VL53L1_RANGING_CORE__RANGING_TOTAL_EVENTS_REF_1_LLL 0x09A3 + + + + + + + +#define VL53L1_RANGING_CORE__SIGNAL_TOTAL_EVENTS_REF_1_MMM 0x09A4 + + + + + + + +#define VL53L1_RANGING_CORE__SIGNAL_TOTAL_EVENTS_REF_1_LMM 0x09A5 + + + + + + + +#define VL53L1_RANGING_CORE__SIGNAL_TOTAL_EVENTS_REF_1_LLM 0x09A6 + + + + + + + +#define VL53L1_RANGING_CORE__SIGNAL_TOTAL_EVENTS_REF_1_LLL 0x09A7 + + + + + + + +#define VL53L1_RANGING_CORE__TOTAL_PERIODS_ELAPSED_REF_1_MM 0x09A8 + + + + + + + +#define VL53L1_RANGING_CORE__TOTAL_PERIODS_ELAPSED_REF_1_LM 0x09A9 + + + + + + + +#define VL53L1_RANGING_CORE__TOTAL_PERIODS_ELAPSED_REF_1_LL 0x09AA + + + + + + + +#define VL53L1_RANGING_CORE__AMBIENT_MISMATCH_REF_MM 0x09AB + + + + + + + +#define VL53L1_RANGING_CORE__AMBIENT_MISMATCH_REF_LM 0x09AC + + + + + + + +#define VL53L1_RANGING_CORE__AMBIENT_MISMATCH_REF_LL 0x09AD + + + + + + + +#define VL53L1_RANGING_CORE__GPIO_CONFIG__A0 0x0A00 + + + + + + + +#define VL53L1_RANGING_CORE__RESET_CONTROL__A0 0x0A01 + + + + + + + +#define VL53L1_RANGING_CORE__INTR_MANAGER__A0 0x0A02 + + + + + + + +#define VL53L1_RANGING_CORE__POWER_FSM_TIME_OSC__A0 0x0A06 + + + + + + + +#define VL53L1_RANGING_CORE__VCSEL_ATEST__A0 0x0A07 + + + + + + + +#define VL53L1_RANGING_CORE__VCSEL_PERIOD_CLIPPED__A0 0x0A08 + + + + + + + +#define VL53L1_RANGING_CORE__VCSEL_STOP_CLIPPED__A0 0x0A09 + + + + + + + +#define VL53L1_RANGING_CORE__CALIB_2__A0 0x0A0A + + + + + + + +#define VL53L1_RANGING_CORE__STOP_CONDITION__A0 0x0A0B + + + + + + + +#define VL53L1_RANGING_CORE__STATUS_RESET__A0 0x0A0C + + + + + + + +#define VL53L1_RANGING_CORE__READOUT_CFG__A0 0x0A0D + + + + + + + +#define VL53L1_RANGING_CORE__WINDOW_SETTING__A0 0x0A0E + + + + + + + +#define VL53L1_RANGING_CORE__VCSEL_DELAY__A0 0x0A1A + + + + + + + +#define VL53L1_RANGING_CORE__REFERENCE_2__A0 0x0A1B + + + + + + + +#define VL53L1_RANGING_CORE__REGAVDD1V2__A0 0x0A1D + + + + + + + +#define VL53L1_RANGING_CORE__TST_MUX__A0 0x0A1F + + + + + + + +#define VL53L1_RANGING_CORE__CUSTOM_FE_2__A0 0x0A20 + + + + + + + +#define VL53L1_RANGING_CORE__SPAD_READOUT__A0 0x0A21 + + + + + + + +#define VL53L1_RANGING_CORE__CPUMP_1__A0 0x0A22 + + + + + + + +#define VL53L1_RANGING_CORE__SPARE_REGISTER__A0 0x0A23 + + + + + + + +#define VL53L1_RANGING_CORE__VCSEL_CONT_STAGE5_BYPASS__A0 0x0A24 + + + + + + + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_18 0x0A25 + + + + + + + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_19 0x0A26 + + + + + + + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_20 0x0A27 + + + + + + + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_21 0x0A28 + + + + + + + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_22 0x0A29 + + + + + + + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_23 0x0A2A + + + + + + + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_24 0x0A2B + + + + + + + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_25 0x0A2C + + + + + + + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_26 0x0A2D + + + + + + + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_27 0x0A2E + + + + + + + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_28 0x0A2F + + + + + + + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_29 0x0A30 + + + + + + + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_30 0x0A31 + + + + + + + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_31 0x0A32 + + + + + + + +#define VL53L1_RANGING_CORE__REF_SPAD_EN_0__EWOK 0x0A33 + + + + + + + +#define VL53L1_RANGING_CORE__REF_SPAD_EN_1__EWOK 0x0A34 + + + + + + + +#define VL53L1_RANGING_CORE__REF_SPAD_EN_2__EWOK 0x0A35 + + + + + + + +#define VL53L1_RANGING_CORE__REF_SPAD_EN_3__EWOK 0x0A36 + + + + + + + +#define VL53L1_RANGING_CORE__REF_SPAD_EN_4__EWOK 0x0A37 + + + + + + + +#define VL53L1_RANGING_CORE__REF_SPAD_EN_5__EWOK 0x0A38 + + + + + + + +#define VL53L1_RANGING_CORE__REF_EN_START_SELECT 0x0A39 + + + + + + + +#define VL53L1_RANGING_CORE__REGDVDD1V2_ATEST__EWOK 0x0A41 + + + + + + + +#define VL53L1_SOFT_RESET_GO1 0x0B00 + + + + + + + +#define VL53L1_PRIVATE__PATCH_BASE_ADDR_RSLV 0x0E00 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__INTERRUPT_STATUS 0x0ED0 + + + + + + + + + + + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__RANGE_STATUS 0x0ED1 + + + + + + + + + + + + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__REPORT_STATUS 0x0ED2 + + + + + + + + + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__STREAM_COUNT 0x0ED3 + + + + + + + + + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__DSS_ACTUAL_EFFECTIVE_SPADS_SD0 0x0ED4 + + + + + + + + + + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__DSS_ACTUAL_EFFECTIVE_SPADS_SD0_HI 0x0ED4 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__DSS_ACTUAL_EFFECTIVE_SPADS_SD0_LO 0x0ED5 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__PEAK_SIGNAL_COUNT_RATE_MCPS_SD0 0x0ED6 + + + + + + + + + + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__PEAK_SIGNAL_COUNT_RATE_MCPS_SD0_HI 0x0ED6 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__PEAK_SIGNAL_COUNT_RATE_MCPS_SD0_LO 0x0ED7 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__AMBIENT_COUNT_RATE_MCPS_SD0 0x0ED8 + + + + + + + + + + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__AMBIENT_COUNT_RATE_MCPS_SD0_HI 0x0ED8 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__AMBIENT_COUNT_RATE_MCPS_SD0_LO 0x0ED9 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__SIGMA_SD0 0x0EDA + + + + + + + + + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__SIGMA_SD0_HI 0x0EDA + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__SIGMA_SD0_LO 0x0EDB + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__PHASE_SD0 0x0EDC + + + + + + + + + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__PHASE_SD0_HI 0x0EDC + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__PHASE_SD0_LO 0x0EDD + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__FINAL_CROSSTALK_CORRECTED_RANGE_MM_SD0 0x0EDE + + + + + + + + + + + + + + + +#define VL53L1_PREV__FINAL_CROSSTALK_CORRECTED_RANGE_MM_SD0_HI 0x0EDE + + + + + + + +#define VL53L1_PREV__FINAL_CROSSTALK_CORRECTED_RANGE_MM_SD0_LO 0x0EDF + + + + + + + +#define VL53L1_PREV__PEAK_SIGNAL_COUNT_RATE_CROSSTALK_CORRECTED_MCPS_SD0 0x0EE0 + + + + + + + + + + + + + + + + +#define VL53L1_PPEAK_SIGNAL_COUNT_RATE_CROSSTALK_CORRECTED_MCPS_SD0_HI 0x0EE0 + + + + + + + +#define VL53L1_PPEAK_SIGNAL_COUNT_RATE_CROSSTALK_CORRECTED_MCPS_SD0_LO 0x0EE1 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__MM_INNER_ACTUAL_EFFECTIVE_SPADS_SD0 0x0EE2 + + + + + + + + + + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__MM_INNER_ACTUAL_EFFECTIVE_SPADS_SD0_HI 0x0EE2 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__MM_INNER_ACTUAL_EFFECTIVE_SPADS_SD0_LO 0x0EE3 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__MM_OUTER_ACTUAL_EFFECTIVE_SPADS_SD0 0x0EE4 + + + + + + + + + + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__MM_OUTER_ACTUAL_EFFECTIVE_SPADS_SD0_HI 0x0EE4 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__MM_OUTER_ACTUAL_EFFECTIVE_SPADS_SD0_LO 0x0EE5 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__AVG_SIGNAL_COUNT_RATE_MCPS_SD0 0x0EE6 + + + + + + + + + + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__AVG_SIGNAL_COUNT_RATE_MCPS_SD0_HI 0x0EE6 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__AVG_SIGNAL_COUNT_RATE_MCPS_SD0_LO 0x0EE7 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__DSS_ACTUAL_EFFECTIVE_SPADS_SD1 0x0EE8 + + + + + + + + + + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__DSS_ACTUAL_EFFECTIVE_SPADS_SD1_HI 0x0EE8 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__DSS_ACTUAL_EFFECTIVE_SPADS_SD1_LO 0x0EE9 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__PEAK_SIGNAL_COUNT_RATE_MCPS_SD1 0x0EEA + + + + + + + + + + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__PEAK_SIGNAL_COUNT_RATE_MCPS_SD1_HI 0x0EEA + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__PEAK_SIGNAL_COUNT_RATE_MCPS_SD1_LO 0x0EEB + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__AMBIENT_COUNT_RATE_MCPS_SD1 0x0EEC + + + + + + + + + + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__AMBIENT_COUNT_RATE_MCPS_SD1_HI 0x0EEC + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__AMBIENT_COUNT_RATE_MCPS_SD1_LO 0x0EED + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__SIGMA_SD1 0x0EEE + + + + + + + + + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__SIGMA_SD1_HI 0x0EEE + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__SIGMA_SD1_LO 0x0EEF + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__PHASE_SD1 0x0EF0 + + + + + + + + + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__PHASE_SD1_HI 0x0EF0 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__PHASE_SD1_LO 0x0EF1 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__FINAL_CROSSTALK_CORRECTED_RANGE_MM_SD1 0x0EF2 + + + + + + + + + + + + + + + + +#define VL53L1_PFINAL_CROSSTALK_CORRECTED_RANGE_MM_SD1_HI 0x0EF2 + + + + + + + +#define VL53L1_PFINAL_CROSSTALK_CORRECTED_RANGE_MM_SD1_LO 0x0EF3 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__SPARE_0_SD1 0x0EF4 + + + + + + + + + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__SPARE_0_SD1_HI 0x0EF4 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__SPARE_0_SD1_LO 0x0EF5 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__SPARE_1_SD1 0x0EF6 + + + + + + + + + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__SPARE_1_SD1_HI 0x0EF6 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__SPARE_1_SD1_LO 0x0EF7 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__SPARE_2_SD1 0x0EF8 + + + + + + + + + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__SPARE_2_SD1_HI 0x0EF8 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__SPARE_2_SD1_LO 0x0EF9 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__SPARE_3_SD1 0x0EFA + + + + + + + + + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__SPARE_3_SD1_HI 0x0EFA + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__SPARE_3_SD1_LO 0x0EFB + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD0 0x0EFC + + + + + + + + + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD0_3 0x0EFC + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD0_2 0x0EFD + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD0_1 0x0EFE + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD0_0 0x0EFF + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__RANGING_TOTAL_EVENTS_SD0 0x0F00 + + + + + + + + + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__RANGING_TOTAL_EVENTS_SD0_3 0x0F00 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__RANGING_TOTAL_EVENTS_SD0_2 0x0F01 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__RANGING_TOTAL_EVENTS_SD0_1 0x0F02 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__RANGING_TOTAL_EVENTS_SD0_0 0x0F03 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__SIGNAL_TOTAL_EVENTS_SD0 0x0F04 + + + + + + + + + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__SIGNAL_TOTAL_EVENTS_SD0_3 0x0F04 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__SIGNAL_TOTAL_EVENTS_SD0_2 0x0F05 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__SIGNAL_TOTAL_EVENTS_SD0_1 0x0F06 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__SIGNAL_TOTAL_EVENTS_SD0_0 0x0F07 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__TOTAL_PERIODS_ELAPSED_SD0 0x0F08 + + + + + + + + + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__TOTAL_PERIODS_ELAPSED_SD0_3 0x0F08 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__TOTAL_PERIODS_ELAPSED_SD0_2 0x0F09 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__TOTAL_PERIODS_ELAPSED_SD0_1 0x0F0A + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__TOTAL_PERIODS_ELAPSED_SD0_0 0x0F0B + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD1 0x0F0C + + + + + + + + + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD1_3 0x0F0C + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD1_2 0x0F0D + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD1_1 0x0F0E + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD1_0 0x0F0F + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__RANGING_TOTAL_EVENTS_SD1 0x0F10 + + + + + + + + + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__RANGING_TOTAL_EVENTS_SD1_3 0x0F10 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__RANGING_TOTAL_EVENTS_SD1_2 0x0F11 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__RANGING_TOTAL_EVENTS_SD1_1 0x0F12 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__RANGING_TOTAL_EVENTS_SD1_0 0x0F13 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__SIGNAL_TOTAL_EVENTS_SD1 0x0F14 + + + + + + + + + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__SIGNAL_TOTAL_EVENTS_SD1_3 0x0F14 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__SIGNAL_TOTAL_EVENTS_SD1_2 0x0F15 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__SIGNAL_TOTAL_EVENTS_SD1_1 0x0F16 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__SIGNAL_TOTAL_EVENTS_SD1_0 0x0F17 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__TOTAL_PERIODS_ELAPSED_SD1 0x0F18 + + + + + + + + + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__TOTAL_PERIODS_ELAPSED_SD1_3 0x0F18 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__TOTAL_PERIODS_ELAPSED_SD1_2 0x0F19 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__TOTAL_PERIODS_ELAPSED_SD1_1 0x0F1A + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__TOTAL_PERIODS_ELAPSED_SD1_0 0x0F1B + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__SPARE_0 0x0F1C + + + + + + + + + + + + + + + +#define VL53L1_RESULT__DEBUG_STATUS 0x0F20 + + + + + + + + + + + + + + + +#define VL53L1_RESULT__DEBUG_STAGE 0x0F21 + + + + + + + + + + + + + + + +#define VL53L1_GPH__SYSTEM__THRESH_RATE_HIGH 0x0F24 + + + + + + + + + + + + + + + +#define VL53L1_GPH__SYSTEM__THRESH_RATE_HIGH_HI 0x0F24 + + + + + + + +#define VL53L1_GPH__SYSTEM__THRESH_RATE_HIGH_LO 0x0F25 + + + + + + + +#define VL53L1_GPH__SYSTEM__THRESH_RATE_LOW 0x0F26 + + + + + + + + + + + + + + + +#define VL53L1_GPH__SYSTEM__THRESH_RATE_LOW_HI 0x0F26 + + + + + + + +#define VL53L1_GPH__SYSTEM__THRESH_RATE_LOW_LO 0x0F27 + + + + + + + +#define VL53L1_GPH__SYSTEM__INTERRUPT_CONFIG_GPIO 0x0F28 + + + + + + + + + + + + + + + + + + + + +#define VL53L1_GPH__DSS_CONFIG__ROI_MODE_CONTROL 0x0F2F + + + + + + + + + + + + + + + + +#define VL53L1_GPH__DSS_CONFIG__MANUAL_EFFECTIVE_SPADS_SELECT 0x0F30 + + + + + + + + + + + + + + + +#define VL53L1_GPH__DSS_CONFIG__MANUAL_EFFECTIVE_SPADS_SELECT_HI 0x0F30 + + + + + + + +#define VL53L1_GPH__DSS_CONFIG__MANUAL_EFFECTIVE_SPADS_SELECT_LO 0x0F31 + + + + + + + +#define VL53L1_GPH__DSS_CONFIG__MANUAL_BLOCK_SELECT 0x0F32 + + + + + + + + + + + + + + + +#define VL53L1_GPH__DSS_CONFIG__MAX_SPADS_LIMIT 0x0F33 + + + + + + + + + + + + + + + +#define VL53L1_GPH__DSS_CONFIG__MIN_SPADS_LIMIT 0x0F34 + + + + + + + + + + + + + + + +#define VL53L1_GPH__MM_CONFIG__TIMEOUT_MACROP_A_HI 0x0F36 + + + + + + + + + + + + + + + +#define VL53L1_GPH__MM_CONFIG__TIMEOUT_MACROP_A_LO 0x0F37 + + + + + + + + + + + + + + + +#define VL53L1_GPH__MM_CONFIG__TIMEOUT_MACROP_B_HI 0x0F38 + + + + + + + + + + + + + + + +#define VL53L1_GPH__MM_CONFIG__TIMEOUT_MACROP_B_LO 0x0F39 + + + + + + + + + + + + + + + +#define VL53L1_GPH__RANGE_CONFIG__TIMEOUT_MACROP_A_HI 0x0F3A + + + + + + + + + + + + + + + +#define VL53L1_GPH__RANGE_CONFIG__TIMEOUT_MACROP_A_LO 0x0F3B + + + + + + + + + + + + + + + +#define VL53L1_GPH__RANGE_CONFIG__VCSEL_PERIOD_A 0x0F3C + + + + + + + + + + + + + + + +#define VL53L1_GPH__RANGE_CONFIG__VCSEL_PERIOD_B 0x0F3D + + + + + + + + + + + + + + + +#define VL53L1_GPH__RANGE_CONFIG__TIMEOUT_MACROP_B_HI 0x0F3E + + + + + + + + + + + + + + + +#define VL53L1_GPH__RANGE_CONFIG__TIMEOUT_MACROP_B_LO 0x0F3F + + + + + + + + + + + + + + + +#define VL53L1_GPH__RANGE_CONFIG__SIGMA_THRESH 0x0F40 + + + + + + + + + + + + + + + +#define VL53L1_GPH__RANGE_CONFIG__SIGMA_THRESH_HI 0x0F40 + + + + + + + +#define VL53L1_GPH__RANGE_CONFIG__SIGMA_THRESH_LO 0x0F41 + + + + + + + +#define VL53L1_GPH__RANGE_CONFIG__MIN_COUNT_RATE_RTN_LIMIT_MCPS 0x0F42 + + + + + + + + + + + + + + + + +#define VL53L1_GPH__RANGE_CONFIG__MIN_COUNT_RATE_RTN_LIMIT_MCPS_HI 0x0F42 + + + + + + + +#define VL53L1_GPH__RANGE_CONFIG__MIN_COUNT_RATE_RTN_LIMIT_MCPS_LO 0x0F43 + + + + + + + +#define VL53L1_GPH__RANGE_CONFIG__VALID_PHASE_LOW 0x0F44 + + + + + + + + + + + + + + + +#define VL53L1_GPH__RANGE_CONFIG__VALID_PHASE_HIGH 0x0F45 + + + + + + + + + + + + + + + +#define VL53L1_FIRMWARE__INTERNAL_STREAM_COUNT_DIV 0x0F46 + + + + + + + + + + + + + + + +#define VL53L1_FIRMWARE__INTERNAL_STREAM_COUNTER_VAL 0x0F47 + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__ROI_CTRL 0x0F54 + + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__SPARE_1 0x0F55 + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__SPARE_2 0x0F56 + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__SPARE_3 0x0F57 + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__SPARE_4 0x0F58 + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__SPARE_5 0x0F59 + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__SPARE_6 0x0F5A + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__SPARE_7 0x0F5B + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_0 0x0F5C + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_1 0x0F5D + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_2 0x0F5E + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_3 0x0F5F + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_4 0x0F60 + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_5 0x0F61 + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_6 0x0F62 + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_7 0x0F63 + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_8 0x0F64 + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_9 0x0F65 + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_10 0x0F66 + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_11 0x0F67 + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_12 0x0F68 + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_13 0x0F69 + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_14 0x0F6A + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_15 0x0F6B + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_16 0x0F6C + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_17 0x0F6D + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_18 0x0F6E + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_19 0x0F6F + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_20 0x0F70 + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_21 0x0F71 + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_22 0x0F72 + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_23 0x0F73 + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_24 0x0F74 + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_25 0x0F75 + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_26 0x0F76 + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_27 0x0F77 + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_28 0x0F78 + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_29 0x0F79 + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_30 0x0F7A + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_31 0x0F7B + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__USER_ROI_0 0x0F7C + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__USER_ROI_1 0x0F7D + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__MODE_ROI_0 0x0F7E + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__MODE_ROI_1 0x0F7F + + + + + + + + + + + + + + + +#define VL53L1_SIGMA_ESTIMATOR_CALC__SPARE_0 0x0F80 + + + + + + + + + + + + + + + +#define VL53L1_VHV_RESULT__PEAK_SIGNAL_RATE_MCPS 0x0F82 + + + + + + + + + + + + + + + +#define VL53L1_VHV_RESULT__PEAK_SIGNAL_RATE_MCPS_HI 0x0F82 + + + + + + + +#define VL53L1_VHV_RESULT__PEAK_SIGNAL_RATE_MCPS_LO 0x0F83 + + + + + + + +#define VL53L1_VHV_RESULT__SIGNAL_TOTAL_EVENTS_REF 0x0F84 + + + + + + + + + + + + + + + +#define VL53L1_VHV_RESULT__SIGNAL_TOTAL_EVENTS_REF_3 0x0F84 + + + + + + + +#define VL53L1_VHV_RESULT__SIGNAL_TOTAL_EVENTS_REF_2 0x0F85 + + + + + + + +#define VL53L1_VHV_RESULT__SIGNAL_TOTAL_EVENTS_REF_1 0x0F86 + + + + + + + +#define VL53L1_VHV_RESULT__SIGNAL_TOTAL_EVENTS_REF_0 0x0F87 + + + + + + + +#define VL53L1_PHASECAL_RESULT__PHASE_OUTPUT_REF 0x0F88 + + + + + + + + + + + + + + + +#define VL53L1_PHASECAL_RESULT__PHASE_OUTPUT_REF_HI 0x0F88 + + + + + + + +#define VL53L1_PHASECAL_RESULT__PHASE_OUTPUT_REF_LO 0x0F89 + + + + + + + +#define VL53L1_DSS_RESULT__TOTAL_RATE_PER_SPAD 0x0F8A + + + + + + + + + + + + + + + +#define VL53L1_DSS_RESULT__TOTAL_RATE_PER_SPAD_HI 0x0F8A + + + + + + + +#define VL53L1_DSS_RESULT__TOTAL_RATE_PER_SPAD_LO 0x0F8B + + + + + + + +#define VL53L1_DSS_RESULT__ENABLED_BLOCKS 0x0F8C + + + + + + + + + + + + + + + +#define VL53L1_DSS_RESULT__NUM_REQUESTED_SPADS 0x0F8E + + + + + + + + + + + + + + + +#define VL53L1_DSS_RESULT__NUM_REQUESTED_SPADS_HI 0x0F8E + + + + + + + +#define VL53L1_DSS_RESULT__NUM_REQUESTED_SPADS_LO 0x0F8F + + + + + + + +#define VL53L1_MM_RESULT__INNER_INTERSECTION_RATE 0x0F92 + + + + + + + + + + + + + + + +#define VL53L1_MM_RESULT__INNER_INTERSECTION_RATE_HI 0x0F92 + + + + + + + +#define VL53L1_MM_RESULT__INNER_INTERSECTION_RATE_LO 0x0F93 + + + + + + + +#define VL53L1_MM_RESULT__OUTER_COMPLEMENT_RATE 0x0F94 + + + + + + + + + + + + + + + +#define VL53L1_MM_RESULT__OUTER_COMPLEMENT_RATE_HI 0x0F94 + + + + + + + +#define VL53L1_MM_RESULT__OUTER_COMPLEMENT_RATE_LO 0x0F95 + + + + + + + +#define VL53L1_MM_RESULT__TOTAL_OFFSET 0x0F96 + + + + + + + + + + + + + + + +#define VL53L1_MM_RESULT__TOTAL_OFFSET_HI 0x0F96 + + + + + + + +#define VL53L1_MM_RESULT__TOTAL_OFFSET_LO 0x0F97 + + + + + + + +#define VL53L1_XTALK_CALC__XTALK_FOR_ENABLED_SPADS 0x0F98 + + + + + + + + + + + + + + + +#define VL53L1_XTALK_CALC__XTALK_FOR_ENABLED_SPADS_3 0x0F98 + + + + + + + +#define VL53L1_XTALK_CALC__XTALK_FOR_ENABLED_SPADS_2 0x0F99 + + + + + + + +#define VL53L1_XTALK_CALC__XTALK_FOR_ENABLED_SPADS_1 0x0F9A + + + + + + + +#define VL53L1_XTALK_CALC__XTALK_FOR_ENABLED_SPADS_0 0x0F9B + + + + + + + +#define VL53L1_XTALK_RESULT__AVG_XTALK_USER_ROI_KCPS 0x0F9C + + + + + + + + + + + + + + + + +#define VL53L1_XTALK_RESULT__AVG_XTALK_USER_ROI_KCPS_3 0x0F9C + + + + + + + +#define VL53L1_XTALK_RESULT__AVG_XTALK_USER_ROI_KCPS_2 0x0F9D + + + + + + + +#define VL53L1_XTALK_RESULT__AVG_XTALK_USER_ROI_KCPS_1 0x0F9E + + + + + + + +#define VL53L1_XTALK_RESULT__AVG_XTALK_USER_ROI_KCPS_0 0x0F9F + + + + + + + +#define VL53L1_XTALK_RESULT__AVG_XTALK_MM_INNER_ROI_KCPS 0x0FA0 + + + + + + + + + + + + + + + + +#define VL53L1_XTALK_RESULT__AVG_XTALK_MM_INNER_ROI_KCPS_3 0x0FA0 + + + + + + + +#define VL53L1_XTALK_RESULT__AVG_XTALK_MM_INNER_ROI_KCPS_2 0x0FA1 + + + + + + + +#define VL53L1_XTALK_RESULT__AVG_XTALK_MM_INNER_ROI_KCPS_1 0x0FA2 + + + + + + + +#define VL53L1_XTALK_RESULT__AVG_XTALK_MM_INNER_ROI_KCPS_0 0x0FA3 + + + + + + + +#define VL53L1_XTALK_RESULT__AVG_XTALK_MM_OUTER_ROI_KCPS 0x0FA4 + + + + + + + + + + + + + + + + +#define VL53L1_XTALK_RESULT__AVG_XTALK_MM_OUTER_ROI_KCPS_3 0x0FA4 + + + + + + + +#define VL53L1_XTALK_RESULT__AVG_XTALK_MM_OUTER_ROI_KCPS_2 0x0FA5 + + + + + + + +#define VL53L1_XTALK_RESULT__AVG_XTALK_MM_OUTER_ROI_KCPS_1 0x0FA6 + + + + + + + +#define VL53L1_XTALK_RESULT__AVG_XTALK_MM_OUTER_ROI_KCPS_0 0x0FA7 + + + + + + + +#define VL53L1_RANGE_RESULT__ACCUM_PHASE 0x0FA8 + + + + + + + + + + + + + + + +#define VL53L1_RANGE_RESULT__ACCUM_PHASE_3 0x0FA8 + + + + + + + +#define VL53L1_RANGE_RESULT__ACCUM_PHASE_2 0x0FA9 + + + + + + + +#define VL53L1_RANGE_RESULT__ACCUM_PHASE_1 0x0FAA + + + + + + + +#define VL53L1_RANGE_RESULT__ACCUM_PHASE_0 0x0FAB + + + + + + + +#define VL53L1_RANGE_RESULT__OFFSET_CORRECTED_RANGE 0x0FAC + + + + + + + + + + + + + + + +#define VL53L1_RANGE_RESULT__OFFSET_CORRECTED_RANGE_HI 0x0FAC + + + + + + + +#define VL53L1_RANGE_RESULT__OFFSET_CORRECTED_RANGE_LO 0x0FAD + + + + + + + +#define VL53L1_SHADOW_PHASECAL_RESULT__VCSEL_START 0x0FAE + + + + + + + + + + + + + + + +#define VL53L1_SHADOW_RESULT__INTERRUPT_STATUS 0x0FB0 + + + + + + + + + + + + + + + + + +#define VL53L1_SHADOW_RESULT__RANGE_STATUS 0x0FB1 + + + + + + + + + + + + + + + + + + +#define VL53L1_SHADOW_RESULT__REPORT_STATUS 0x0FB2 + + + + + + + + + + + + + + + +#define VL53L1_SHADOW_RESULT__STREAM_COUNT 0x0FB3 + + + + + + + + + + + + + + + +#define VL53L1_SHADOW_RESULT__DSS_ACTUAL_EFFECTIVE_SPADS_SD0 0x0FB4 + + + + + + + + + + + + + + + + +#define VL53L1_SHADOW_RESULT__DSS_ACTUAL_EFFECTIVE_SPADS_SD0_HI 0x0FB4 + + + + + + + +#define VL53L1_SHADOW_RESULT__DSS_ACTUAL_EFFECTIVE_SPADS_SD0_LO 0x0FB5 + + + + + + + +#define VL53L1_SHADOW_RESULT__PEAK_SIGNAL_COUNT_RATE_MCPS_SD0 0x0FB6 + + + + + + + + + + + + + + + + +#define VL53L1_SHADOW_RESULT__PEAK_SIGNAL_COUNT_RATE_MCPS_SD0_HI 0x0FB6 + + + + + + + +#define VL53L1_SHADOW_RESULT__PEAK_SIGNAL_COUNT_RATE_MCPS_SD0_LO 0x0FB7 + + + + + + + +#define VL53L1_SHADOW_RESULT__AMBIENT_COUNT_RATE_MCPS_SD0 0x0FB8 + + + + + + + + + + + + + + + + +#define VL53L1_SHADOW_RESULT__AMBIENT_COUNT_RATE_MCPS_SD0_HI 0x0FB8 + + + + + + + +#define VL53L1_SHADOW_RESULT__AMBIENT_COUNT_RATE_MCPS_SD0_LO 0x0FB9 + + + + + + + +#define VL53L1_SHADOW_RESULT__SIGMA_SD0 0x0FBA + + + + + + + + + + + + + + + +#define VL53L1_SHADOW_RESULT__SIGMA_SD0_HI 0x0FBA + + + + + + + +#define VL53L1_SHADOW_RESULT__SIGMA_SD0_LO 0x0FBB + + + + + + + +#define VL53L1_SHADOW_RESULT__PHASE_SD0 0x0FBC + + + + + + + + + + + + + + + +#define VL53L1_SHADOW_RESULT__PHASE_SD0_HI 0x0FBC + + + + + + + +#define VL53L1_SHADOW_RESULT__PHASE_SD0_LO 0x0FBD + + + + + + + +#define VL53L1_SHADOW_RESULT__FINAL_CROSSTALK_CORRECTED_RANGE_MM_SD0 0x0FBE + + + + + + + + + + + + + + + +#define VL53L1_SHADOW_RESULT__FINAL_CROSSTALK_CORRECTED_RANGE_MM_SD0_HI 0x0FBE + + + + + + + +#define VL53L1_SHADOW_RESULT__FINAL_CROSSTALK_CORRECTED_RANGE_MM_SD0_LO 0x0FBF + + + + + + + +#define VL53L1_SHPEAK_SIGNAL_COUNT_RATE_CROSSTALK_CORRECTED_MCPS_SD0 0x0FC0 + + + + + + + + + + + + + + + + +#define VL53L1_SHPEAK_SIGNAL_COUNT_RATE_CROSSTALK_CORRECTED_MCPS_SD0_HI 0x0FC0 + + + + + + + +#define VL53L1_SHPEAK_SIGNAL_COUNT_RATE_CROSSTALK_CORRECTED_MCPS_SD0_LO 0x0FC1 + + + + + + + +#define VL53L1_SHADOW_RESULT__MM_INNER_ACTUAL_EFFECTIVE_SPADS_SD0 0x0FC2 + + + + + + + + + + + + + + + + +#define VL53L1_SHADOW_RESULT__MM_INNER_ACTUAL_EFFECTIVE_SPADS_SD0_HI 0x0FC2 + + + + + + + +#define VL53L1_SHADOW_RESULT__MM_INNER_ACTUAL_EFFECTIVE_SPADS_SD0_LO 0x0FC3 + + + + + + + +#define VL53L1_SHADOW_RESULT__MM_OUTER_ACTUAL_EFFECTIVE_SPADS_SD0 0x0FC4 + + + + + + + + + + + + + + + + +#define VL53L1_SHADOW_RESULT__MM_OUTER_ACTUAL_EFFECTIVE_SPADS_SD0_HI 0x0FC4 + + + + + + + +#define VL53L1_SHADOW_RESULT__MM_OUTER_ACTUAL_EFFECTIVE_SPADS_SD0_LO 0x0FC5 + + + + + + + +#define VL53L1_SHADOW_RESULT__AVG_SIGNAL_COUNT_RATE_MCPS_SD0 0x0FC6 + + + + + + + + + + + + + + + + +#define VL53L1_SHADOW_RESULT__AVG_SIGNAL_COUNT_RATE_MCPS_SD0_HI 0x0FC6 + + + + + + + +#define VL53L1_SHADOW_RESULT__AVG_SIGNAL_COUNT_RATE_MCPS_SD0_LO 0x0FC7 + + + + + + + +#define VL53L1_SHADOW_RESULT__DSS_ACTUAL_EFFECTIVE_SPADS_SD1 0x0FC8 + + + + + + + + + + + + + + + + +#define VL53L1_SHADOW_RESULT__DSS_ACTUAL_EFFECTIVE_SPADS_SD1_HI 0x0FC8 + + + + + + + +#define VL53L1_SHADOW_RESULT__DSS_ACTUAL_EFFECTIVE_SPADS_SD1_LO 0x0FC9 + + + + + + + +#define VL53L1_SHADOW_RESULT__PEAK_SIGNAL_COUNT_RATE_MCPS_SD1 0x0FCA + + + + + + + + + + + + + + + + +#define VL53L1_SHADOW_RESULT__PEAK_SIGNAL_COUNT_RATE_MCPS_SD1_HI 0x0FCA + + + + + + + +#define VL53L1_SHADOW_RESULT__PEAK_SIGNAL_COUNT_RATE_MCPS_SD1_LO 0x0FCB + + + + + + + +#define VL53L1_SHADOW_RESULT__AMBIENT_COUNT_RATE_MCPS_SD1 0x0FCC + + + + + + + + + + + + + + + + +#define VL53L1_SHADOW_RESULT__AMBIENT_COUNT_RATE_MCPS_SD1_HI 0x0FCC + + + + + + + +#define VL53L1_SHADOW_RESULT__AMBIENT_COUNT_RATE_MCPS_SD1_LO 0x0FCD + + + + + + + +#define VL53L1_SHADOW_RESULT__SIGMA_SD1 0x0FCE + + + + + + + + + + + + + + + +#define VL53L1_SHADOW_RESULT__SIGMA_SD1_HI 0x0FCE + + + + + + + +#define VL53L1_SHADOW_RESULT__SIGMA_SD1_LO 0x0FCF + + + + + + + +#define VL53L1_SHADOW_RESULT__PHASE_SD1 0x0FD0 + + + + + + + + + + + + + + + +#define VL53L1_SHADOW_RESULT__PHASE_SD1_HI 0x0FD0 + + + + + + + +#define VL53L1_SHADOW_RESULT__PHASE_SD1_LO 0x0FD1 + + + + + + + +#define VL53L1_SHADOW_RESULT__FINAL_CROSSTALK_CORRECTED_RANGE_MM_SD1 0x0FD2 + + + + + + + + + + + + + + + +#define VL53L1_SHADOW_RESULT__FINAL_CROSSTALK_CORRECTED_RANGE_MM_SD1_HI 0x0FD2 + + + + + + + +#define VL53L1_SHADOW_RESULT__FINAL_CROSSTALK_CORRECTED_RANGE_MM_SD1_LO 0x0FD3 + + + + + + + +#define VL53L1_SHADOW_RESULT__SPARE_0_SD1 0x0FD4 + + + + + + + + + + + + + + + +#define VL53L1_SHADOW_RESULT__SPARE_0_SD1_HI 0x0FD4 + + + + + + + +#define VL53L1_SHADOW_RESULT__SPARE_0_SD1_LO 0x0FD5 + + + + + + + +#define VL53L1_SHADOW_RESULT__SPARE_1_SD1 0x0FD6 + + + + + + + + + + + + + + + +#define VL53L1_SHADOW_RESULT__SPARE_1_SD1_HI 0x0FD6 + + + + + + + +#define VL53L1_SHADOW_RESULT__SPARE_1_SD1_LO 0x0FD7 + + + + + + + +#define VL53L1_SHADOW_RESULT__SPARE_2_SD1 0x0FD8 + + + + + + + + + + + + + + + +#define VL53L1_SHADOW_RESULT__SPARE_2_SD1_HI 0x0FD8 + + + + + + + +#define VL53L1_SHADOW_RESULT__SPARE_2_SD1_LO 0x0FD9 + + + + + + + +#define VL53L1_SHADOW_RESULT__SPARE_3_SD1 0x0FDA + + + + + + + + + + + + + + + +#define VL53L1_SHADOW_RESULT__THRESH_INFO 0x0FDB + + + + + + + + + + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD0 0x0FDC + + + + + + + + + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD0_3 0x0FDC + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD0_2 0x0FDD + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD0_1 0x0FDE + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD0_0 0x0FDF + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__RANGING_TOTAL_EVENTS_SD0 0x0FE0 + + + + + + + + + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__RANGING_TOTAL_EVENTS_SD0_3 0x0FE0 + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__RANGING_TOTAL_EVENTS_SD0_2 0x0FE1 + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__RANGING_TOTAL_EVENTS_SD0_1 0x0FE2 + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__RANGING_TOTAL_EVENTS_SD0_0 0x0FE3 + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__SIGNAL_TOTAL_EVENTS_SD0 0x0FE4 + + + + + + + + + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__SIGNAL_TOTAL_EVENTS_SD0_3 0x0FE4 + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__SIGNAL_TOTAL_EVENTS_SD0_2 0x0FE5 + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__SIGNAL_TOTAL_EVENTS_SD0_1 0x0FE6 + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__SIGNAL_TOTAL_EVENTS_SD0_0 0x0FE7 + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__TOTAL_PERIODS_ELAPSED_SD0 0x0FE8 + + + + + + + + + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__TOTAL_PERIODS_ELAPSED_SD0_3 0x0FE8 + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__TOTAL_PERIODS_ELAPSED_SD0_2 0x0FE9 + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__TOTAL_PERIODS_ELAPSED_SD0_1 0x0FEA + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__TOTAL_PERIODS_ELAPSED_SD0_0 0x0FEB + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD1 0x0FEC + + + + + + + + + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD1_3 0x0FEC + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD1_2 0x0FED + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD1_1 0x0FEE + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD1_0 0x0FEF + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__RANGING_TOTAL_EVENTS_SD1 0x0FF0 + + + + + + + + + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__RANGING_TOTAL_EVENTS_SD1_3 0x0FF0 + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__RANGING_TOTAL_EVENTS_SD1_2 0x0FF1 + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__RANGING_TOTAL_EVENTS_SD1_1 0x0FF2 + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__RANGING_TOTAL_EVENTS_SD1_0 0x0FF3 + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__SIGNAL_TOTAL_EVENTS_SD1 0x0FF4 + + + + + + + + + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__SIGNAL_TOTAL_EVENTS_SD1_3 0x0FF4 + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__SIGNAL_TOTAL_EVENTS_SD1_2 0x0FF5 + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__SIGNAL_TOTAL_EVENTS_SD1_1 0x0FF6 + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__SIGNAL_TOTAL_EVENTS_SD1_0 0x0FF7 + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__TOTAL_PERIODS_ELAPSED_SD1 0x0FF8 + + + + + + + + + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__TOTAL_PERIODS_ELAPSED_SD1_3 0x0FF8 + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__TOTAL_PERIODS_ELAPSED_SD1_2 0x0FF9 + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__TOTAL_PERIODS_ELAPSED_SD1_1 0x0FFA + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__TOTAL_PERIODS_ELAPSED_SD1_0 0x0FFB + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__SPARE_0 0x0FFC + + + + + + + + + + + + + + + +#define VL53L1_SHADOW_PHASECAL_RESULT__REFERENCE_PHASE_HI 0x0FFE + + + + + + + + + + + + + + + +#define VL53L1_SHADOW_PHASECAL_RESULT__REFERENCE_PHASE_LO 0x0FFF + + + + + + + + + + + + + + + + + + + + +#endif + + diff --git a/drivers/input/misc/vl53L1/kona/inc/vl53l1_register_settings.h b/drivers/input/misc/vl53L1/kona/inc/vl53l1_register_settings.h new file mode 100644 index 000000000000..22bb9ef0fa67 --- /dev/null +++ b/drivers/input/misc/vl53L1/kona/inc/vl53l1_register_settings.h @@ -0,0 +1,274 @@ + +/******************************************************************************* + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#ifndef _VL53L1_REGISTER_SETTINGS_H_ +#define _VL53L1_REGISTER_SETTINGS_H_ + + + + + + + + + + + + + + + + +#define VL53L1_DEVICESCHEDULERMODE_PSEUDO_SOLO 0x00 +#define VL53L1_DEVICESCHEDULERMODE_STREAMING 0x01 +#define VL53L1_DEVICESCHEDULERMODE_HISTOGRAM 0x02 + + + + + + + + + + + +#define VL53L1_DEVICEREADOUTMODE_SINGLE_SD (0x00 << 2) +#define VL53L1_DEVICEREADOUTMODE_DUAL_SD (0x01 << 2) +#define VL53L1_DEVICEREADOUTMODE_SPLIT_READOUT (0x02 << 2) +#define VL53L1_DEVICEREADOUTMODE_SPLIT_MANUAL (0x03 << 2) + + + + + + + + + + + + + + + + + + + +#define VL53L1_DEVICEMEASUREMENTMODE_MODE_MASK 0xF0 +#define VL53L1_DEVICEMEASUREMENTMODE_STOP_MASK 0x0F + +#define VL53L1_GROUPEDPARAMETERHOLD_ID_MASK 0x02 + + + + +#define VL53L1_EWOK_I2C_DEV_ADDR_DEFAULT 0x29 + + +#define VL53L1_OSC_FREQUENCY 0x00 +#define VL53L1_OSC_TRIM_DEFAULT 0x00 +#define VL53L1_OSC_FREQ_SET_DEFAULT 0x00 + +#define VL53L1_RANGE_HISTOGRAM_REF 0x08 +#define VL53L1_RANGE_HISTOGRAM_RET 0x10 +#define VL53L1_RANGE_HISTOGRAM_BOTH 0x18 +#define VL53L1_RANGE_HISTOGRAM_INIT 0x20 +#define VL53L1_RANGE_VHV_INIT 0x40 + + + +#define VL53L1_RESULT_RANGE_STATUS 0x1F + + + +#define VL53L1_SYSTEM__SEED_CONFIG__MANUAL 0x00 +#define VL53L1_SYSTEM__SEED_CONFIG__STANDARD 0x01 +#define VL53L1_SYSTEM__SEED_CONFIG__EVEN_UPDATE_ONLY 0x02 + + + +#define VL53L1_INTERRUPT_CONFIG_LEVEL_LOW 0x00 +#define VL53L1_INTERRUPT_CONFIG_LEVEL_HIGH 0x01 +#define VL53L1_INTERRUPT_CONFIG_OUT_OF_WINDOW 0x02 +#define VL53L1_INTERRUPT_CONFIG_IN_WINDOW 0x03 +#define VL53L1_INTERRUPT_CONFIG_NEW_SAMPLE_READY 0x20 + + + +#define VL53L1_CLEAR_RANGE_INT 0x01 +#define VL53L1_CLEAR_ERROR_INT 0x02 + + + +#define VL53L1_SEQUENCE_VHV_EN 0x01 +#define VL53L1_SEQUENCE_PHASECAL_EN 0x02 +#define VL53L1_SEQUENCE_REFERENCE_PHASE_EN 0x04 +#define VL53L1_SEQUENCE_DSS1_EN 0x08 +#define VL53L1_SEQUENCE_DSS2_EN 0x10 +#define VL53L1_SEQUENCE_MM1_EN 0x20 +#define VL53L1_SEQUENCE_MM2_EN 0x40 +#define VL53L1_SEQUENCE_RANGE_EN 0x80 + + + +#define VL53L1_DSS_CONTROL__ROI_SUBTRACT 0x20 +#define VL53L1_DSS_CONTROL__ROI_INTERSECT 0x10 + +#define VL53L1_DSS_CONTROL__MODE_DISABLED 0x00 +#define VL53L1_DSS_CONTROL__MODE_TARGET_RATE 0x01 +#define VL53L1_DSS_CONTROL__MODE_EFFSPADS 0x02 +#define VL53L1_DSS_CONTROL__MODE_BLOCKSELECT 0x03 + + + + + + + + + + +#define VL53L1_RANGING_CORE__SPAD_READOUT__STANDARD 0x45 +#define VL53L1_RANGING_CORE__SPAD_READOUT__RETURN_ARRAY_ONLY 0x05 +#define VL53L1_RANGING_CORE__SPAD_READOUT__REFERENCE_ARRAY_ONLY 0x55 +#define VL53L1_RANGING_CORE__SPAD_READOUT__RETURN_SPLIT_ARRAY 0x25 +#define VL53L1_RANGING_CORE__SPAD_READOUT__CALIB_PULSES 0xF5 + + +#define VL53L1_LASER_SAFETY__KEY_VALUE 0x6C + + + + + + + + + + +#define VL53L1_RANGE_STATUS__RANGE_STATUS_MASK 0x1F +#define VL53L1_RANGE_STATUS__MAX_THRESHOLD_HIT_MASK 0x20 +#define VL53L1_RANGE_STATUS__MIN_THRESHOLD_HIT_MASK 0x40 +#define VL53L1_RANGE_STATUS__GPH_ID_RANGE_STATUS_MASK 0x80 + + + + + + + + + +#define VL53L1_INTERRUPT_STATUS__INT_STATUS_MASK 0x07 +#define VL53L1_INTERRUPT_STATUS__INT_ERROR_STATUS_MASK 0x18 +#define VL53L1_INTERRUPT_STATUS__GPH_ID_INT_STATUS_MASK 0x20 + + + + + +#endif + + + + + + diff --git a/drivers/input/misc/vl53L1/kona/inc/vl53l1_register_structs.h b/drivers/input/misc/vl53L1/kona/inc/vl53l1_register_structs.h new file mode 100644 index 000000000000..f928566a883d --- /dev/null +++ b/drivers/input/misc/vl53L1/kona/inc/vl53l1_register_structs.h @@ -0,0 +1,4872 @@ + +/******************************************************************************* + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#ifndef _VL53L1_REGISTER_STRUCTS_H_ +#define _VL53L1_REGISTER_STRUCTS_H_ + +#include "vl53l1_types.h" +#include "vl53l1_register_map.h" + +#define VL53L1_STATIC_NVM_MANAGED_I2C_INDEX \ + VL53L1_I2C_SLAVE__DEVICE_ADDRESS +#define VL53L1_CUSTOMER_NVM_MANAGED_I2C_INDEX \ + VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_REF_0 +#define VL53L1_STATIC_CONFIG_I2C_INDEX \ + VL53L1_DSS_CONFIG__TARGET_TOTAL_RATE_MCPS +#define VL53L1_GENERAL_CONFIG_I2C_INDEX \ + VL53L1_GPH_CONFIG__STREAM_COUNT_UPDATE_VALUE +#define VL53L1_TIMING_CONFIG_I2C_INDEX \ + VL53L1_MM_CONFIG__TIMEOUT_MACROP_A_HI +#define VL53L1_DYNAMIC_CONFIG_I2C_INDEX \ + VL53L1_SYSTEM__GROUPED_PARAMETER_HOLD_0 +#define VL53L1_SYSTEM_CONTROL_I2C_INDEX \ + VL53L1_POWER_MANAGEMENT__GO1_POWER_FORCE +#define VL53L1_SYSTEM_RESULTS_I2C_INDEX \ + VL53L1_RESULT__INTERRUPT_STATUS +#define VL53L1_CORE_RESULTS_I2C_INDEX \ + VL53L1_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD0 +#define VL53L1_DEBUG_RESULTS_I2C_INDEX \ + VL53L1_PHASECAL_RESULT__REFERENCE_PHASE +#define VL53L1_NVM_COPY_DATA_I2C_INDEX \ + VL53L1_IDENTIFICATION__MODEL_ID +#define VL53L1_PREV_SHADOW_SYSTEM_RESULTS_I2C_INDEX \ + VL53L1_PREV_SHADOW_RESULT__INTERRUPT_STATUS +#define VL53L1_PREV_SHADOW_CORE_RESULTS_I2C_INDEX \ + VL53L1_PREV_SHADOW_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD0 +#define VL53L1_PATCH_DEBUG_I2C_INDEX \ + VL53L1_RESULT__DEBUG_STATUS +#define VL53L1_GPH_GENERAL_CONFIG_I2C_INDEX \ + VL53L1_GPH__SYSTEM__THRESH_RATE_HIGH +#define VL53L1_GPH_STATIC_CONFIG_I2C_INDEX \ + VL53L1_GPH__DSS_CONFIG__ROI_MODE_CONTROL +#define VL53L1_GPH_TIMING_CONFIG_I2C_INDEX \ + VL53L1_GPH__MM_CONFIG__TIMEOUT_MACROP_A_HI +#define VL53L1_FW_INTERNAL_I2C_INDEX \ + VL53L1_FIRMWARE__INTERNAL_STREAM_COUNT_DIV +#define VL53L1_PATCH_RESULTS_I2C_INDEX \ + VL53L1_DSS_CALC__ROI_CTRL +#define VL53L1_SHADOW_SYSTEM_RESULTS_I2C_INDEX \ + VL53L1_SHADOW_PHASECAL_RESULT__VCSEL_START +#define VL53L1_SHADOW_CORE_RESULTS_I2C_INDEX \ + VL53L1_SHADOW_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD0 + +#define VL53L1_STATIC_NVM_MANAGED_I2C_SIZE_BYTES 11 +#define VL53L1_CUSTOMER_NVM_MANAGED_I2C_SIZE_BYTES 23 +#define VL53L1_STATIC_CONFIG_I2C_SIZE_BYTES 32 +#define VL53L1_GENERAL_CONFIG_I2C_SIZE_BYTES 22 +#define VL53L1_TIMING_CONFIG_I2C_SIZE_BYTES 23 +#define VL53L1_DYNAMIC_CONFIG_I2C_SIZE_BYTES 18 +#define VL53L1_SYSTEM_CONTROL_I2C_SIZE_BYTES 5 +#define VL53L1_SYSTEM_RESULTS_I2C_SIZE_BYTES 44 +#define VL53L1_CORE_RESULTS_I2C_SIZE_BYTES 33 +#define VL53L1_DEBUG_RESULTS_I2C_SIZE_BYTES 56 +#define VL53L1_NVM_COPY_DATA_I2C_SIZE_BYTES 49 +#define VL53L1_PREV_SHADOW_SYSTEM_RESULTS_I2C_SIZE_BYTES 44 +#define VL53L1_PREV_SHADOW_CORE_RESULTS_I2C_SIZE_BYTES 33 +#define VL53L1_PATCH_DEBUG_I2C_SIZE_BYTES 2 +#define VL53L1_GPH_GENERAL_CONFIG_I2C_SIZE_BYTES 5 +#define VL53L1_GPH_STATIC_CONFIG_I2C_SIZE_BYTES 6 +#define VL53L1_GPH_TIMING_CONFIG_I2C_SIZE_BYTES 16 +#define VL53L1_FW_INTERNAL_I2C_SIZE_BYTES 2 +#define VL53L1_PATCH_RESULTS_I2C_SIZE_BYTES 90 +#define VL53L1_SHADOW_SYSTEM_RESULTS_I2C_SIZE_BYTES 82 +#define VL53L1_SHADOW_CORE_RESULTS_I2C_SIZE_BYTES 33 + + + + + + + + + + + + +typedef struct { + uint8_t i2c_slave__device_address; + + + + + + + + + + + uint8_t ana_config__vhv_ref_sel_vddpix; + + + + + + + + + + + uint8_t ana_config__vhv_ref_sel_vquench; + + + + + + + + + + + uint8_t ana_config__reg_avdd1v2_sel; + + + + + + + + + + + uint8_t ana_config__fast_osc__trim; + + + + + + + + + + + uint16_t osc_measured__fast_osc__frequency; + + + + + + + + + + + uint8_t vhv_config__timeout_macrop_loop_bound; + + + + + + + + + + + + uint8_t vhv_config__count_thresh; + + + + + + + + + + + uint8_t vhv_config__offset; + + + + + + + + + + + uint8_t vhv_config__init; + + + + + + + + + + + +} VL53L1_static_nvm_managed_t; + + + + + + + + + + + + +typedef struct { + uint8_t global_config__spad_enables_ref_0; + + + + + + + + + + + uint8_t global_config__spad_enables_ref_1; + + + + + + + + + + + uint8_t global_config__spad_enables_ref_2; + + + + + + + + + + + uint8_t global_config__spad_enables_ref_3; + + + + + + + + + + + uint8_t global_config__spad_enables_ref_4; + + + + + + + + + + + uint8_t global_config__spad_enables_ref_5; + + + + + + + + + + + uint8_t global_config__ref_en_start_select; + + + + + + + + + + + uint8_t ref_spad_man__num_requested_ref_spads; + + + + + + + + + + + uint8_t ref_spad_man__ref_location; + + + + + + + + + + + uint16_t algo__crosstalk_compensation_plane_offset_kcps; + + + + + + + + + + + int16_t algo__crosstalk_compensation_x_plane_gradient_kcps; + + + + + + + + + + + int16_t algo__crosstalk_compensation_y_plane_gradient_kcps; + + + + + + + + + + + uint16_t ref_spad_char__total_rate_target_mcps; + + + + + + + + + + + int16_t algo__part_to_part_range_offset_mm; + + + + + + + + + + + int16_t mm_config__inner_offset_mm; + + + + + + + + + + + int16_t mm_config__outer_offset_mm; + + + + + + + + + + +} VL53L1_customer_nvm_managed_t; + + + + + + + + + + + + +typedef struct { + uint16_t dss_config__target_total_rate_mcps; + + + + + + + + + + + uint8_t debug__ctrl; + + + + + + + + + + + uint8_t test_mode__ctrl; + + + + + + + + + + + uint8_t clk_gating__ctrl; + + + + + + + + + + + + + + uint8_t nvm_bist__ctrl; + + + + + + + + + + + + uint8_t nvm_bist__num_nvm_words; + + + + + + + + + + + uint8_t nvm_bist__start_address; + + + + + + + + + + + uint8_t host_if__status; + + + + + + + + + + + uint8_t pad_i2c_hv__config; + + + + + + + + + + + + + + + + uint8_t pad_i2c_hv__extsup_config; + + + + + + + + + + + uint8_t gpio_hv_pad__ctrl; + + + + + + + + + + + + uint8_t gpio_hv_mux__ctrl; + + + + + + + + + + + + uint8_t gpio__tio_hv_status; + + + + + + + + + + + + uint8_t gpio__fio_hv_status; + + + + + + + + + + + uint8_t ana_config__spad_sel_pswidth; + + + + + + + + + + + uint8_t ana_config__vcsel_pulse_width_offset; + + + + + + + + + + + uint8_t ana_config__fast_osc__config_ctrl; + + + + + + + + + + + uint8_t sigma_estimator__effective_pulse_width_ns; + + + + + + + + + + + uint8_t sigma_estimator__effective_ambient_width_ns; + + + + + + + + + + + uint8_t sigma_estimator__sigma_ref_mm; + + + + + + + + + + + uint8_t algo__crosstalk_compensation_valid_height_mm; + + + + + + + + + + + uint8_t spare_host_config__static_config_spare_0; + + + + + + + + + + + uint8_t spare_host_config__static_config_spare_1; + + + + + + + + + + + uint16_t algo__range_ignore_threshold_mcps; + + + + + + + + + + + uint8_t algo__range_ignore_valid_height_mm; + + + + + + + + + + + uint8_t algo__range_min_clip; + + + + + + + + + + + + uint8_t algo__consistency_check__tolerance; + + + + + + + + + + + uint8_t spare_host_config__static_config_spare_2; + + + + + + + + + + + uint8_t sd_config__reset_stages_msb; + + + + + + + + + + + uint8_t sd_config__reset_stages_lsb; + + + + + + + + + + + +} VL53L1_static_config_t; + + + + + + + + + + + + +typedef struct { + uint8_t gph_config__stream_count_update_value; + + + + + + + + + + + uint8_t global_config__stream_divider; + + + + + + + + + + + uint8_t system__interrupt_config_gpio; + + + + + + + + + + + + + + + + uint8_t cal_config__vcsel_start; + + + + + + + + + + + uint16_t cal_config__repeat_rate; + + + + + + + + + + + uint8_t global_config__vcsel_width; + + + + + + + + + + + uint8_t phasecal_config__timeout_macrop; + + + + + + + + + + + uint8_t phasecal_config__target; + + + + + + + + + + + uint8_t phasecal_config__override; + + + + + + + + + + + uint8_t dss_config__roi_mode_control; + + + + + + + + + + + + uint16_t system__thresh_rate_high; + + + + + + + + + + + uint16_t system__thresh_rate_low; + + + + + + + + + + + uint16_t dss_config__manual_effective_spads_select; + + + + + + + + + + + uint8_t dss_config__manual_block_select; + + + + + + + + + + + uint8_t dss_config__aperture_attenuation; + + + + + + + + + + + uint8_t dss_config__max_spads_limit; + + + + + + + + + + + uint8_t dss_config__min_spads_limit; + + + + + + + + + + +} VL53L1_general_config_t; + + + + + + + + + + + + +typedef struct { + uint8_t mm_config__timeout_macrop_a_hi; + + + + + + + + + + + uint8_t mm_config__timeout_macrop_a_lo; + + + + + + + + + + + uint8_t mm_config__timeout_macrop_b_hi; + + + + + + + + + + + uint8_t mm_config__timeout_macrop_b_lo; + + + + + + + + + + + uint8_t range_config__timeout_macrop_a_hi; + + + + + + + + + + + uint8_t range_config__timeout_macrop_a_lo; + + + + + + + + + + + uint8_t range_config__vcsel_period_a; + + + + + + + + + + + uint8_t range_config__timeout_macrop_b_hi; + + + + + + + + + + + uint8_t range_config__timeout_macrop_b_lo; + + + + + + + + + + + uint8_t range_config__vcsel_period_b; + + + + + + + + + + + uint16_t range_config__sigma_thresh; + + + + + + + + + + + uint16_t range_config__min_count_rate_rtn_limit_mcps; + + + + + + + + + + + uint8_t range_config__valid_phase_low; + + + + + + + + + + + uint8_t range_config__valid_phase_high; + + + + + + + + + + + uint32_t system__intermeasurement_period; + + + + + + + + + + + uint8_t system__fractional_enable; + + + + + + + + + + +} VL53L1_timing_config_t; + + + + + + + + + + + + +typedef struct { + uint8_t system__grouped_parameter_hold_0; + + + + + + + + + + + + uint16_t system__thresh_high; + + + + + + + + + + + uint16_t system__thresh_low; + + + + + + + + + + + uint8_t system__enable_xtalk_per_quadrant; + + + + + + + + + + + uint8_t system__seed_config; + + + + + + + + + + + + uint8_t sd_config__woi_sd0; + + + + + + + + + + + uint8_t sd_config__woi_sd1; + + + + + + + + + + + uint8_t sd_config__initial_phase_sd0; + + + + + + + + + + + uint8_t sd_config__initial_phase_sd1; + + + + + + + + + + + uint8_t system__grouped_parameter_hold_1; + + + + + + + + + + + + uint8_t sd_config__first_order_select; + + + + + + + + + + + + uint8_t sd_config__quantifier; + + + + + + + + + + + uint8_t roi_config__user_roi_centre_spad; + + + + + + + + + + + uint8_t roi_config__user_roi_requested_global_xy_size; + + + + + + + + + + + uint8_t system__sequence_config; + + + + + + + + + + + + + + + + + + uint8_t system__grouped_parameter_hold; + + + + + + + + + + + +} VL53L1_dynamic_config_t; + + + + + + + + + + + + +typedef struct { + uint8_t power_management__go1_power_force; + + + + + + + + + + + uint8_t system__stream_count_ctrl; + + + + + + + + + + + uint8_t firmware__enable; + + + + + + + + + + + uint8_t system__interrupt_clear; + + + + + + + + + + + + uint8_t system__mode_start; + + + + + + + + + + + + + + + +} VL53L1_system_control_t; + + + + + + + + + + + + +typedef struct { + uint8_t result__interrupt_status; + + + + + + + + + + + + + uint8_t result__range_status; + + + + + + + + + + + + + + uint8_t result__report_status; + + + + + + + + + + + uint8_t result__stream_count; + + + + + + + + + + + uint16_t result__dss_actual_effective_spads_sd0; + + + + + + + + + + + uint16_t result__peak_signal_count_rate_mcps_sd0; + + + + + + + + + + + uint16_t result__ambient_count_rate_mcps_sd0; + + + + + + + + + + + uint16_t result__sigma_sd0; + + + + + + + + + + + uint16_t result__phase_sd0; + + + + + + + + + + + uint16_t result__final_crosstalk_corrected_range_mm_sd0; + + + + + + + + + + + uint16_t result__peak_signal_count_rate_crosstalk_corrected_mcps_sd0; + + + + + + + + + + + uint16_t result__mm_inner_actual_effective_spads_sd0; + + + + + + + + + + + uint16_t result__mm_outer_actual_effective_spads_sd0; + + + + + + + + + + + uint16_t result__avg_signal_count_rate_mcps_sd0; + + + + + + + + + + + uint16_t result__dss_actual_effective_spads_sd1; + + + + + + + + + + + uint16_t result__peak_signal_count_rate_mcps_sd1; + + + + + + + + + + + uint16_t result__ambient_count_rate_mcps_sd1; + + + + + + + + + + + uint16_t result__sigma_sd1; + + + + + + + + + + + uint16_t result__phase_sd1; + + + + + + + + + + + uint16_t result__final_crosstalk_corrected_range_mm_sd1; + + + + + + + + + + + uint16_t result__spare_0_sd1; + + + + + + + + + + + uint16_t result__spare_1_sd1; + + + + + + + + + + + uint16_t result__spare_2_sd1; + + + + + + + + + + + uint8_t result__spare_3_sd1; + + + + + + + + + + + uint8_t result__thresh_info; + + + + + + + + + + + +} VL53L1_system_results_t; + + + + + + + + + + + + +typedef struct { + uint32_t result_core__ambient_window_events_sd0; + + + + + + + + + + + uint32_t result_core__ranging_total_events_sd0; + + + + + + + + + + + int32_t result_core__signal_total_events_sd0; + + + + + + + + + + + uint32_t result_core__total_periods_elapsed_sd0; + + + + + + + + + + + uint32_t result_core__ambient_window_events_sd1; + + + + + + + + + + + uint32_t result_core__ranging_total_events_sd1; + + + + + + + + + + + int32_t result_core__signal_total_events_sd1; + + + + + + + + + + + uint32_t result_core__total_periods_elapsed_sd1; + + + + + + + + + + + uint8_t result_core__spare_0; + + + + + + + + + + +} VL53L1_core_results_t; + + + + + + + + + + + + +typedef struct { + uint16_t phasecal_result__reference_phase; + + + + + + + + + + + uint8_t phasecal_result__vcsel_start; + + + + + + + + + + + uint8_t ref_spad_char_result__num_actual_ref_spads; + + + + + + + + + + + uint8_t ref_spad_char_result__ref_location; + + + + + + + + + + + uint8_t vhv_result__coldboot_status; + + + + + + + + + + + uint8_t vhv_result__search_result; + + + + + + + + + + + uint8_t vhv_result__latest_setting; + + + + + + + + + + + uint16_t result__osc_calibrate_val; + + + + + + + + + + + uint8_t ana_config__powerdown_go1; + + + + + + + + + + + + uint8_t ana_config__ref_bg_ctrl; + + + + + + + + + + + + uint8_t ana_config__regdvdd1v2_ctrl; + + + + + + + + + + + + + uint8_t ana_config__osc_slow_ctrl; + + + + + + + + + + + + + uint8_t test_mode__status; + + + + + + + + + + + uint8_t firmware__system_status; + + + + + + + + + + + + uint8_t firmware__mode_status; + + + + + + + + + + + uint8_t firmware__secondary_mode_status; + + + + + + + + + + + uint16_t firmware__cal_repeat_rate_counter; + + + + + + + + + + + uint16_t gph__system__thresh_high; + + + + + + + + + + + uint16_t gph__system__thresh_low; + + + + + + + + + + + uint8_t gph__system__enable_xtalk_per_quadrant; + + + + + + + + + + + uint8_t gph__spare_0; + + + + + + + + + + + + + uint8_t gph__sd_config__woi_sd0; + + + + + + + + + + + uint8_t gph__sd_config__woi_sd1; + + + + + + + + + + + uint8_t gph__sd_config__initial_phase_sd0; + + + + + + + + + + + uint8_t gph__sd_config__initial_phase_sd1; + + + + + + + + + + + uint8_t gph__sd_config__first_order_select; + + + + + + + + + + + + uint8_t gph__sd_config__quantifier; + + + + + + + + + + + uint8_t gph__roi_config__user_roi_centre_spad; + + + + + + + + + + + uint8_t gph__roi_config__user_roi_requested_global_xy_size; + + + + + + + + + + + uint8_t gph__system__sequence_config; + + + + + + + + + + + + + + + + + + uint8_t gph__gph_id; + + + + + + + + + + + uint8_t system__interrupt_set; + + + + + + + + + + + + uint8_t interrupt_manager__enables; + + + + + + + + + + + + + + + uint8_t interrupt_manager__clear; + + + + + + + + + + + + + + + uint8_t interrupt_manager__status; + + + + + + + + + + + + + + + uint8_t mcu_to_host_bank__wr_access_en; + + + + + + + + + + + uint8_t power_management__go1_reset_status; + + + + + + + + + + + uint8_t pad_startup_mode__value_ro; + + + + + + + + + + + + uint8_t pad_startup_mode__value_ctrl; + + + + + + + + + + + + + + uint32_t pll_period_us; + + + + + + + + + + + uint32_t interrupt_scheduler__data_out; + + + + + + + + + + + uint8_t nvm_bist__complete; + + + + + + + + + + + uint8_t nvm_bist__status; + + + + + + + + + + +} VL53L1_debug_results_t; + + + + + + + + + + + + +typedef struct { + uint8_t identification__model_id; + + + + + + + + + + + uint8_t identification__module_type; + + + + + + + + + + + uint8_t identification__revision_id; + + + + + + + + + + + + uint16_t identification__module_id; + + + + + + + + + + + uint8_t ana_config__fast_osc__trim_max; + + + + + + + + + + + uint8_t ana_config__fast_osc__freq_set; + + + + + + + + + + + uint8_t ana_config__vcsel_trim; + + + + + + + + + + + uint8_t ana_config__vcsel_selion; + + + + + + + + + + + uint8_t ana_config__vcsel_selion_max; + + + + + + + + + + + uint8_t protected_laser_safety__lock_bit; + + + + + + + + + + + uint8_t laser_safety__key; + + + + + + + + + + + uint8_t laser_safety__key_ro; + + + + + + + + + + + uint8_t laser_safety__clip; + + + + + + + + + + + uint8_t laser_safety__mult; + + + + + + + + + + + uint8_t global_config__spad_enables_rtn_0; + + + + + + + + + + + uint8_t global_config__spad_enables_rtn_1; + + + + + + + + + + + uint8_t global_config__spad_enables_rtn_2; + + + + + + + + + + + uint8_t global_config__spad_enables_rtn_3; + + + + + + + + + + + uint8_t global_config__spad_enables_rtn_4; + + + + + + + + + + + uint8_t global_config__spad_enables_rtn_5; + + + + + + + + + + + uint8_t global_config__spad_enables_rtn_6; + + + + + + + + + + + uint8_t global_config__spad_enables_rtn_7; + + + + + + + + + + + uint8_t global_config__spad_enables_rtn_8; + + + + + + + + + + + uint8_t global_config__spad_enables_rtn_9; + + + + + + + + + + + uint8_t global_config__spad_enables_rtn_10; + + + + + + + + + + + uint8_t global_config__spad_enables_rtn_11; + + + + + + + + + + + uint8_t global_config__spad_enables_rtn_12; + + + + + + + + + + + uint8_t global_config__spad_enables_rtn_13; + + + + + + + + + + + uint8_t global_config__spad_enables_rtn_14; + + + + + + + + + + + uint8_t global_config__spad_enables_rtn_15; + + + + + + + + + + + uint8_t global_config__spad_enables_rtn_16; + + + + + + + + + + + uint8_t global_config__spad_enables_rtn_17; + + + + + + + + + + + uint8_t global_config__spad_enables_rtn_18; + + + + + + + + + + + uint8_t global_config__spad_enables_rtn_19; + + + + + + + + + + + uint8_t global_config__spad_enables_rtn_20; + + + + + + + + + + + uint8_t global_config__spad_enables_rtn_21; + + + + + + + + + + + uint8_t global_config__spad_enables_rtn_22; + + + + + + + + + + + uint8_t global_config__spad_enables_rtn_23; + + + + + + + + + + + uint8_t global_config__spad_enables_rtn_24; + + + + + + + + + + + uint8_t global_config__spad_enables_rtn_25; + + + + + + + + + + + uint8_t global_config__spad_enables_rtn_26; + + + + + + + + + + + uint8_t global_config__spad_enables_rtn_27; + + + + + + + + + + + uint8_t global_config__spad_enables_rtn_28; + + + + + + + + + + + uint8_t global_config__spad_enables_rtn_29; + + + + + + + + + + + uint8_t global_config__spad_enables_rtn_30; + + + + + + + + + + + uint8_t global_config__spad_enables_rtn_31; + + + + + + + + + + + uint8_t roi_config__mode_roi_centre_spad; + + + + + + + + + + + uint8_t roi_config__mode_roi_xy_size; + + + + + + + + + + +} VL53L1_nvm_copy_data_t; + + + + + + + + + + + + +typedef struct { + uint8_t prev_shadow_result__interrupt_status; + + + + + + + + + + + + + uint8_t prev_shadow_result__range_status; + + + + + + + + + + + + + + uint8_t prev_shadow_result__report_status; + + + + + + + + + + + uint8_t prev_shadow_result__stream_count; + + + + + + + + + + + uint16_t prev_shadow_result__dss_actual_effective_spads_sd0; + + + + + + + + + + + uint16_t prev_shadow_result__peak_signal_count_rate_mcps_sd0; + + + + + + + + + + + uint16_t prev_shadow_result__ambient_count_rate_mcps_sd0; + + + + + + + + + + + uint16_t prev_shadow_result__sigma_sd0; + + + + + + + + + + + uint16_t prev_shadow_result__phase_sd0; + + + + + + + + + + + uint16_t prev_shadow_result__final_crosstalk_corrected_range_mm_sd0; + + + + + + + + + + + uint16_t + psr__peak_signal_count_rate_crosstalk_corrected_mcps_sd0; + + + + + + + + + + + uint16_t prev_shadow_result__mm_inner_actual_effective_spads_sd0; + + + + + + + + + + + uint16_t prev_shadow_result__mm_outer_actual_effective_spads_sd0; + + + + + + + + + + + uint16_t prev_shadow_result__avg_signal_count_rate_mcps_sd0; + + + + + + + + + + + uint16_t prev_shadow_result__dss_actual_effective_spads_sd1; + + + + + + + + + + + uint16_t prev_shadow_result__peak_signal_count_rate_mcps_sd1; + + + + + + + + + + + uint16_t prev_shadow_result__ambient_count_rate_mcps_sd1; + + + + + + + + + + + uint16_t prev_shadow_result__sigma_sd1; + + + + + + + + + + + uint16_t prev_shadow_result__phase_sd1; + + + + + + + + + + + uint16_t prev_shadow_result__final_crosstalk_corrected_range_mm_sd1; + + + + + + + + + + + uint16_t prev_shadow_result__spare_0_sd1; + + + + + + + + + + + uint16_t prev_shadow_result__spare_1_sd1; + + + + + + + + + + + uint16_t prev_shadow_result__spare_2_sd1; + + + + + + + + + + + uint16_t prev_shadow_result__spare_3_sd1; + + + + + + + + + + +} VL53L1_prev_shadow_system_results_t; + + + + + + + + + + + + +typedef struct { + uint32_t prev_shadow_result_core__ambient_window_events_sd0; + + + + + + + + + + + uint32_t prev_shadow_result_core__ranging_total_events_sd0; + + + + + + + + + + + int32_t prev_shadow_result_core__signal_total_events_sd0; + + + + + + + + + + + uint32_t prev_shadow_result_core__total_periods_elapsed_sd0; + + + + + + + + + + + uint32_t prev_shadow_result_core__ambient_window_events_sd1; + + + + + + + + + + + uint32_t prev_shadow_result_core__ranging_total_events_sd1; + + + + + + + + + + + int32_t prev_shadow_result_core__signal_total_events_sd1; + + + + + + + + + + + uint32_t prev_shadow_result_core__total_periods_elapsed_sd1; + + + + + + + + + + + uint8_t prev_shadow_result_core__spare_0; + + + + + + + + + + +} VL53L1_prev_shadow_core_results_t; + + + + + + + + + + + + +typedef struct { + uint8_t result__debug_status; + + + + + + + + + + + uint8_t result__debug_stage; + + + + + + + + + + +} VL53L1_patch_debug_t; + + + + + + + + + + + + +typedef struct { + uint16_t gph__system__thresh_rate_high; + + + + + + + + + + + uint16_t gph__system__thresh_rate_low; + + + + + + + + + + + uint8_t gph__system__interrupt_config_gpio; + + + + + + + + + + + + + + + +} VL53L1_gph_general_config_t; + + + + + + + + + + + + +typedef struct { + uint8_t gph__dss_config__roi_mode_control; + + + + + + + + + + + + uint16_t gph__dss_config__manual_effective_spads_select; + + + + + + + + + + + uint8_t gph__dss_config__manual_block_select; + + + + + + + + + + + uint8_t gph__dss_config__max_spads_limit; + + + + + + + + + + + uint8_t gph__dss_config__min_spads_limit; + + + + + + + + + + +} VL53L1_gph_static_config_t; + + + + + + + + + + + + +typedef struct { + uint8_t gph__mm_config__timeout_macrop_a_hi; + + + + + + + + + + + uint8_t gph__mm_config__timeout_macrop_a_lo; + + + + + + + + + + + uint8_t gph__mm_config__timeout_macrop_b_hi; + + + + + + + + + + + uint8_t gph__mm_config__timeout_macrop_b_lo; + + + + + + + + + + + uint8_t gph__range_config__timeout_macrop_a_hi; + + + + + + + + + + + uint8_t gph__range_config__timeout_macrop_a_lo; + + + + + + + + + + + uint8_t gph__range_config__vcsel_period_a; + + + + + + + + + + + uint8_t gph__range_config__vcsel_period_b; + + + + + + + + + + + uint8_t gph__range_config__timeout_macrop_b_hi; + + + + + + + + + + + uint8_t gph__range_config__timeout_macrop_b_lo; + + + + + + + + + + + uint16_t gph__range_config__sigma_thresh; + + + + + + + + + + + uint16_t gph__range_config__min_count_rate_rtn_limit_mcps; + + + + + + + + + + + uint8_t gph__range_config__valid_phase_low; + + + + + + + + + + + uint8_t gph__range_config__valid_phase_high; + + + + + + + + + + +} VL53L1_gph_timing_config_t; + + + + + + + + + + + + +typedef struct { + uint8_t firmware__internal_stream_count_div; + + + + + + + + + + + uint8_t firmware__internal_stream_counter_val; + + + + + + + + + + +} VL53L1_fw_internal_t; + + + + + + + + + + + + +typedef struct { + uint8_t dss_calc__roi_ctrl; + + + + + + + + + + + + uint8_t dss_calc__spare_1; + + + + + + + + + + + uint8_t dss_calc__spare_2; + + + + + + + + + + + uint8_t dss_calc__spare_3; + + + + + + + + + + + uint8_t dss_calc__spare_4; + + + + + + + + + + + uint8_t dss_calc__spare_5; + + + + + + + + + + + uint8_t dss_calc__spare_6; + + + + + + + + + + + uint8_t dss_calc__spare_7; + + + + + + + + + + + uint8_t dss_calc__user_roi_spad_en_0; + + + + + + + + + + + uint8_t dss_calc__user_roi_spad_en_1; + + + + + + + + + + + uint8_t dss_calc__user_roi_spad_en_2; + + + + + + + + + + + uint8_t dss_calc__user_roi_spad_en_3; + + + + + + + + + + + uint8_t dss_calc__user_roi_spad_en_4; + + + + + + + + + + + uint8_t dss_calc__user_roi_spad_en_5; + + + + + + + + + + + uint8_t dss_calc__user_roi_spad_en_6; + + + + + + + + + + + uint8_t dss_calc__user_roi_spad_en_7; + + + + + + + + + + + uint8_t dss_calc__user_roi_spad_en_8; + + + + + + + + + + + uint8_t dss_calc__user_roi_spad_en_9; + + + + + + + + + + + uint8_t dss_calc__user_roi_spad_en_10; + + + + + + + + + + + uint8_t dss_calc__user_roi_spad_en_11; + + + + + + + + + + + uint8_t dss_calc__user_roi_spad_en_12; + + + + + + + + + + + uint8_t dss_calc__user_roi_spad_en_13; + + + + + + + + + + + uint8_t dss_calc__user_roi_spad_en_14; + + + + + + + + + + + uint8_t dss_calc__user_roi_spad_en_15; + + + + + + + + + + + uint8_t dss_calc__user_roi_spad_en_16; + + + + + + + + + + + uint8_t dss_calc__user_roi_spad_en_17; + + + + + + + + + + + uint8_t dss_calc__user_roi_spad_en_18; + + + + + + + + + + + uint8_t dss_calc__user_roi_spad_en_19; + + + + + + + + + + + uint8_t dss_calc__user_roi_spad_en_20; + + + + + + + + + + + uint8_t dss_calc__user_roi_spad_en_21; + + + + + + + + + + + uint8_t dss_calc__user_roi_spad_en_22; + + + + + + + + + + + uint8_t dss_calc__user_roi_spad_en_23; + + + + + + + + + + + uint8_t dss_calc__user_roi_spad_en_24; + + + + + + + + + + + uint8_t dss_calc__user_roi_spad_en_25; + + + + + + + + + + + uint8_t dss_calc__user_roi_spad_en_26; + + + + + + + + + + + uint8_t dss_calc__user_roi_spad_en_27; + + + + + + + + + + + uint8_t dss_calc__user_roi_spad_en_28; + + + + + + + + + + + uint8_t dss_calc__user_roi_spad_en_29; + + + + + + + + + + + uint8_t dss_calc__user_roi_spad_en_30; + + + + + + + + + + + uint8_t dss_calc__user_roi_spad_en_31; + + + + + + + + + + + uint8_t dss_calc__user_roi_0; + + + + + + + + + + + uint8_t dss_calc__user_roi_1; + + + + + + + + + + + uint8_t dss_calc__mode_roi_0; + + + + + + + + + + + uint8_t dss_calc__mode_roi_1; + + + + + + + + + + + uint8_t sigma_estimator_calc__spare_0; + + + + + + + + + + + uint16_t vhv_result__peak_signal_rate_mcps; + + + + + + + + + + + uint32_t vhv_result__signal_total_events_ref; + + + + + + + + + + + uint16_t phasecal_result__phase_output_ref; + + + + + + + + + + + uint16_t dss_result__total_rate_per_spad; + + + + + + + + + + + uint8_t dss_result__enabled_blocks; + + + + + + + + + + + uint16_t dss_result__num_requested_spads; + + + + + + + + + + + uint16_t mm_result__inner_intersection_rate; + + + + + + + + + + + uint16_t mm_result__outer_complement_rate; + + + + + + + + + + + uint16_t mm_result__total_offset; + + + + + + + + + + + uint32_t xtalk_calc__xtalk_for_enabled_spads; + + + + + + + + + + + uint32_t xtalk_result__avg_xtalk_user_roi_kcps; + + + + + + + + + + + uint32_t xtalk_result__avg_xtalk_mm_inner_roi_kcps; + + + + + + + + + + + uint32_t xtalk_result__avg_xtalk_mm_outer_roi_kcps; + + + + + + + + + + + uint32_t range_result__accum_phase; + + + + + + + + + + + uint16_t range_result__offset_corrected_range; + + + + + + + + + + +} VL53L1_patch_results_t; + + + + + + + + + + + + +typedef struct { + uint8_t shadow_phasecal_result__vcsel_start; + + + + + + + + + + + uint8_t shadow_result__interrupt_status; + + + + + + + + + + + + + uint8_t shadow_result__range_status; + + + + + + + + + + + + + + uint8_t shadow_result__report_status; + + + + + + + + + + + uint8_t shadow_result__stream_count; + + + + + + + + + + + uint16_t shadow_result__dss_actual_effective_spads_sd0; + + + + + + + + + + + uint16_t shadow_result__peak_signal_count_rate_mcps_sd0; + + + + + + + + + + + uint16_t shadow_result__ambient_count_rate_mcps_sd0; + + + + + + + + + + + uint16_t shadow_result__sigma_sd0; + + + + + + + + + + + uint16_t shadow_result__phase_sd0; + + + + + + + + + + + uint16_t shadow_result__final_crosstalk_corrected_range_mm_sd0; + + + + + + + + + + + uint16_t + shr__peak_signal_count_rate_crosstalk_corrected_mcps_sd0; + + + + + + + + + + + uint16_t shadow_result__mm_inner_actual_effective_spads_sd0; + + + + + + + + + + + uint16_t shadow_result__mm_outer_actual_effective_spads_sd0; + + + + + + + + + + + uint16_t shadow_result__avg_signal_count_rate_mcps_sd0; + + + + + + + + + + + uint16_t shadow_result__dss_actual_effective_spads_sd1; + + + + + + + + + + + uint16_t shadow_result__peak_signal_count_rate_mcps_sd1; + + + + + + + + + + + uint16_t shadow_result__ambient_count_rate_mcps_sd1; + + + + + + + + + + + uint16_t shadow_result__sigma_sd1; + + + + + + + + + + + uint16_t shadow_result__phase_sd1; + + + + + + + + + + + uint16_t shadow_result__final_crosstalk_corrected_range_mm_sd1; + + + + + + + + + + + uint16_t shadow_result__spare_0_sd1; + + + + + + + + + + + uint16_t shadow_result__spare_1_sd1; + + + + + + + + + + + uint16_t shadow_result__spare_2_sd1; + + + + + + + + + + + uint8_t shadow_result__spare_3_sd1; + + + + + + + + + + + uint8_t shadow_result__thresh_info; + + + + + + + + + + + + uint8_t shadow_phasecal_result__reference_phase_hi; + + + + + + + + + + + uint8_t shadow_phasecal_result__reference_phase_lo; + + + + + + + + + + +} VL53L1_shadow_system_results_t; + + + + + + + + + + + + +typedef struct { + uint32_t shadow_result_core__ambient_window_events_sd0; + + + + + + + + + + + uint32_t shadow_result_core__ranging_total_events_sd0; + + + + + + + + + + + int32_t shadow_result_core__signal_total_events_sd0; + + + + + + + + + + + uint32_t shadow_result_core__total_periods_elapsed_sd0; + + + + + + + + + + + uint32_t shadow_result_core__ambient_window_events_sd1; + + + + + + + + + + + uint32_t shadow_result_core__ranging_total_events_sd1; + + + + + + + + + + + int32_t shadow_result_core__signal_total_events_sd1; + + + + + + + + + + + uint32_t shadow_result_core__total_periods_elapsed_sd1; + + + + + + + + + + + uint8_t shadow_result_core__spare_0; + + + + + + + + + + +} VL53L1_shadow_core_results_t; + + +#endif + + diff --git a/drivers/input/misc/vl53L1/kona/inc/vl53l1_silicon_core.h b/drivers/input/misc/vl53L1/kona/inc/vl53l1_silicon_core.h new file mode 100644 index 000000000000..d48393e143cd --- /dev/null +++ b/drivers/input/misc/vl53L1/kona/inc/vl53l1_silicon_core.h @@ -0,0 +1,134 @@ + +/******************************************************************************* + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#ifndef _VL53L1_SILICON_CORE_H_ +#define _VL53L1_SILICON_CORE_H_ + +#include "vl53l1_platform.h" + +#ifdef __cplusplus +extern "C" { +#endif + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_is_firmware_ready_silicon( + VL53L1_DEV Dev, + uint8_t *pready); + + +#ifdef __cplusplus +} +#endif + +#endif + + diff --git a/drivers/input/misc/vl53L1/kona/inc/vl53l1_tuning_parm_defaults.h b/drivers/input/misc/vl53L1/kona/inc/vl53l1_tuning_parm_defaults.h new file mode 100644 index 000000000000..b0753e2f0971 --- /dev/null +++ b/drivers/input/misc/vl53L1/kona/inc/vl53l1_tuning_parm_defaults.h @@ -0,0 +1,418 @@ + +/******************************************************************************* + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#ifndef _VL53L1_TUNING_PARM_DEFAULTS_H_ +#define _VL53L1_TUNING_PARM_DEFAULTS_H_ + + +#ifdef __cplusplus +extern "C" { +#endif + + + + + + + +#define VL53L1_TUNINGPARM_VERSION_DEFAULT \ +((uint16_t) 28) +#define VL53L1_TUNINGPARM_KEY_TABLE_VERSION_DEFAULT \ +((uint16_t) 14) +#define VL53L1_TUNINGPARM_LLD_VERSION_DEFAULT \ +((uint16_t) 12180) +#define VL53L1_TUNINGPARM_HIST_ALGO_SELECT_DEFAULT \ +((uint8_t) 4) +#define VL53L1_TUNINGPARM_HIST_TARGET_ORDER_DEFAULT \ +((uint8_t) 1) +#define VL53L1_TUNINGPARM_HIST_FILTER_WOI_0_DEFAULT \ +((uint8_t) 1) +#define VL53L1_TUNINGPARM_HIST_FILTER_WOI_1_DEFAULT \ +((uint8_t) 2) +#define VL53L1_TUNINGPARM_HIST_AMB_EST_METHOD_DEFAULT \ +((uint8_t) 1) +#define VL53L1_TUNINGPARM_HIST_AMB_THRESH_SIGMA_0_DEFAULT \ +((uint8_t) 80) +#define VL53L1_TUNINGPARM_HIST_AMB_THRESH_SIGMA_1_DEFAULT \ +((uint8_t) 100) +#define VL53L1_TUNINGPARM_HIST_MIN_AMB_THRESH_EVENTS_DEFAULT \ +((int32_t) 16) +#define VL53L1_TUNINGPARM_HIST_AMB_EVENTS_SCALER_DEFAULT \ +((uint16_t) 4157) +#define VL53L1_TUNINGPARM_HIST_NOISE_THRESHOLD_DEFAULT \ +((uint16_t) 50) +#define VL53L1_TUNINGPARM_HIST_SIGNAL_TOTAL_EVENTS_LIMIT_DEFAULT \ +((int32_t) 100) +#define VL53L1_TUNINGPARM_HIST_SIGMA_EST_REF_MM_DEFAULT \ +((uint8_t) 1) +#define VL53L1_TUNINGPARM_HIST_SIGMA_THRESH_MM_DEFAULT \ +((uint16_t) 180) +#define VL53L1_TUNINGPARM_HIST_GAIN_FACTOR_DEFAULT \ +((uint16_t) 1987) +#define VL53L1_TUNINGPARM_CONSISTENCY_HIST_PHASE_TOLERANCE_DEFAULT \ +((uint8_t) 8) +#define VL53L1_TUNINGPARM_CONSISTENCY_HIST_MIN_MAX_TOLERANCE_MM_DEFAULT \ +((uint16_t) 0) +#define VL53L1_TUNINGPARM_CONSISTENCY_HIST_EVENT_SIGMA_DEFAULT \ +((uint8_t) 0) +#define VL53L1_TUNINGPARM_CONSISTENCY_HIST_EVENT_SIGMA_MIN_SPAD_LIMIT_DEFAULT \ +((uint16_t) 2048) +#define VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_HISTO_LONG_RANGE_DEFAULT \ +((uint8_t) 9) +#define VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_HISTO_MED_RANGE_DEFAULT \ +((uint8_t) 5) +#define VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_HISTO_SHORT_RANGE_DEFAULT \ +((uint8_t) 3) +#define VL53L1_TUNINGPARM_INITIAL_PHASE_REF_HISTO_LONG_RANGE_DEFAULT \ +((uint8_t) 6) +#define VL53L1_TUNINGPARM_INITIAL_PHASE_REF_HISTO_MED_RANGE_DEFAULT \ +((uint8_t) 6) +#define VL53L1_TUNINGPARM_INITIAL_PHASE_REF_HISTO_SHORT_RANGE_DEFAULT \ +((uint8_t) 6) +#define VL53L1_TUNINGPARM_XTALK_DETECT_MIN_VALID_RANGE_MM_DEFAULT \ +((int16_t) -50) +#define VL53L1_TUNINGPARM_XTALK_DETECT_MAX_VALID_RANGE_MM_DEFAULT \ +((int16_t) 50) +#define VL53L1_TUNINGPARM_XTALK_DETECT_MAX_SIGMA_MM_DEFAULT \ +((uint16_t) 140) +#define VL53L1_TUNINGPARM_XTALK_DETECT_MIN_MAX_TOLERANCE_DEFAULT \ +((uint16_t) 50) +#define VL53L1_TUNINGPARM_XTALK_DETECT_MAX_VALID_RATE_KCPS_DEFAULT \ +((uint16_t) 400) +#define VL53L1_TUNINGPARM_XTALK_DETECT_EVENT_SIGMA_DEFAULT \ +((uint8_t) 80) +#define VL53L1_TUNINGPARM_HIST_XTALK_MARGIN_KCPS_DEFAULT \ +((int16_t) 0) +#define VL53L1_TUNINGPARM_CONSISTENCY_LITE_PHASE_TOLERANCE_DEFAULT \ +((uint8_t) 2) +#define VL53L1_TUNINGPARM_PHASECAL_TARGET_DEFAULT \ +((uint8_t) 33) +#define VL53L1_TUNINGPARM_LITE_CAL_REPEAT_RATE_DEFAULT \ +((uint16_t) 0) +#define VL53L1_TUNINGPARM_LITE_RANGING_GAIN_FACTOR_DEFAULT \ +((uint16_t) 2011) +#define VL53L1_TUNINGPARM_LITE_MIN_CLIP_MM_DEFAULT \ +((uint8_t) 0) +#define VL53L1_TUNINGPARM_LITE_LONG_SIGMA_THRESH_MM_DEFAULT \ +((uint16_t) 60) +#define VL53L1_TUNINGPARM_LITE_MED_SIGMA_THRESH_MM_DEFAULT \ +((uint16_t) 60) +#define VL53L1_TUNINGPARM_LITE_SHORT_SIGMA_THRESH_MM_DEFAULT \ +((uint16_t) 60) +#define VL53L1_TUNINGPARM_LITE_LONG_MIN_COUNT_RATE_RTN_MCPS_DEFAULT \ +((uint16_t) 128) +#define VL53L1_TUNINGPARM_LITE_MED_MIN_COUNT_RATE_RTN_MCPS_DEFAULT \ +((uint16_t) 128) +#define VL53L1_TUNINGPARM_LITE_SHORT_MIN_COUNT_RATE_RTN_MCPS_DEFAULT \ +((uint16_t) 128) +#define VL53L1_TUNINGPARM_LITE_SIGMA_EST_PULSE_WIDTH_DEFAULT \ +((uint8_t) 8) +#define VL53L1_TUNINGPARM_LITE_SIGMA_EST_AMB_WIDTH_NS_DEFAULT \ +((uint8_t) 16) +#define VL53L1_TUNINGPARM_LITE_SIGMA_REF_MM_DEFAULT \ +((uint8_t) 1) +#define VL53L1_TUNINGPARM_LITE_RIT_MULT_DEFAULT \ +((uint8_t) 64) +#define VL53L1_TUNINGPARM_LITE_SEED_CONFIG_DEFAULT \ +((uint8_t) 2) +#define VL53L1_TUNINGPARM_LITE_QUANTIFIER_DEFAULT \ +((uint8_t) 2) +#define VL53L1_TUNINGPARM_LITE_FIRST_ORDER_SELECT_DEFAULT \ +((uint8_t) 0) +#define VL53L1_TUNINGPARM_LITE_XTALK_MARGIN_KCPS_DEFAULT \ +((int16_t) 0) +#define VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_LITE_LONG_RANGE_DEFAULT \ +((uint8_t) 14) +#define VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_LITE_MED_RANGE_DEFAULT \ +((uint8_t) 10) +#define VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_LITE_SHORT_RANGE_DEFAULT \ +((uint8_t) 6) +#define VL53L1_TUNINGPARM_INITIAL_PHASE_REF_LITE_LONG_RANGE_DEFAULT \ +((uint8_t) 14) +#define VL53L1_TUNINGPARM_INITIAL_PHASE_REF_LITE_MED_RANGE_DEFAULT \ +((uint8_t) 10) +#define VL53L1_TUNINGPARM_INITIAL_PHASE_REF_LITE_SHORT_RANGE_DEFAULT \ +((uint8_t) 6) +#define VL53L1_TUNINGPARM_TIMED_SEED_CONFIG_DEFAULT \ +((uint8_t) 1) +#define VL53L1_TUNINGPARM_DMAX_CFG_SIGNAL_THRESH_SIGMA_DEFAULT \ +((uint8_t) 32) +#define VL53L1_TUNINGPARM_DMAX_CFG_REFLECTANCE_ARRAY_0_DEFAULT \ +((uint16_t) 15) +#define VL53L1_TUNINGPARM_DMAX_CFG_REFLECTANCE_ARRAY_1_DEFAULT \ +((uint16_t) 52) +#define VL53L1_TUNINGPARM_DMAX_CFG_REFLECTANCE_ARRAY_2_DEFAULT \ +((uint16_t) 200) +#define VL53L1_TUNINGPARM_DMAX_CFG_REFLECTANCE_ARRAY_3_DEFAULT \ +((uint16_t) 364) +#define VL53L1_TUNINGPARM_DMAX_CFG_REFLECTANCE_ARRAY_4_DEFAULT \ +((uint16_t) 400) +#define VL53L1_TUNINGPARM_VHV_LOOPBOUND_DEFAULT \ +((uint8_t) 129) +#define VL53L1_TUNINGPARM_REFSPADCHAR_DEVICE_TEST_MODE_DEFAULT \ +((uint8_t) 8) +#define VL53L1_TUNINGPARM_REFSPADCHAR_VCSEL_PERIOD_DEFAULT \ +((uint8_t) 11) +#define VL53L1_TUNINGPARM_REFSPADCHAR_PHASECAL_TIMEOUT_US_DEFAULT \ +((uint32_t) 1000) +#define VL53L1_TUNINGPARM_REFSPADCHAR_TARGET_COUNT_RATE_MCPS_DEFAULT \ +((uint16_t) 2560) +#define VL53L1_TUNINGPARM_REFSPADCHAR_MIN_COUNTRATE_LIMIT_MCPS_DEFAULT \ +((uint16_t) 1280) +#define VL53L1_TUNINGPARM_REFSPADCHAR_MAX_COUNTRATE_LIMIT_MCPS_DEFAULT \ +((uint16_t) 5120) +#define VL53L1_TUNINGPARM_XTALK_EXTRACT_NUM_OF_SAMPLES_DEFAULT \ +((uint8_t) 7) +#define VL53L1_TUNINGPARM_XTALK_EXTRACT_MIN_FILTER_THRESH_MM_DEFAULT \ +((int16_t) -70) +#define VL53L1_TUNINGPARM_XTALK_EXTRACT_MAX_FILTER_THRESH_MM_DEFAULT \ +((int16_t) 70) +#define VL53L1_TUNINGPARM_XTALK_EXTRACT_DSS_RATE_MCPS_DEFAULT \ +((uint16_t) 5120) +#define VL53L1_TUNINGPARM_XTALK_EXTRACT_PHASECAL_TIMEOUT_US_DEFAULT \ +((uint32_t) 15000) +#define VL53L1_TUNINGPARM_XTALK_EXTRACT_MAX_VALID_RATE_KCPS_DEFAULT \ +((uint16_t) 640) +#define VL53L1_TUNINGPARM_XTALK_EXTRACT_SIGMA_THRESHOLD_MM_DEFAULT \ +((uint16_t) 140) +#define VL53L1_TUNINGPARM_XTALK_EXTRACT_DSS_TIMEOUT_US_DEFAULT \ +((uint32_t) 2000) +#define VL53L1_TUNINGPARM_XTALK_EXTRACT_BIN_TIMEOUT_US_DEFAULT \ +((uint32_t) 10000) +#define VL53L1_TUNINGPARM_OFFSET_CAL_DSS_RATE_MCPS_DEFAULT \ +((uint16_t) 2560) +#define VL53L1_TUNINGPARM_OFFSET_CAL_PHASECAL_TIMEOUT_US_DEFAULT \ +((uint32_t) 15000) +#define VL53L1_TUNINGPARM_OFFSET_CAL_MM_TIMEOUT_US_DEFAULT \ +((uint32_t) 13000) +#define VL53L1_TUNINGPARM_OFFSET_CAL_RANGE_TIMEOUT_US_DEFAULT \ +((uint32_t) 13000) +#define VL53L1_TUNINGPARM_OFFSET_CAL_PRE_SAMPLES_DEFAULT \ +((uint8_t) 8) +#define VL53L1_TUNINGPARM_OFFSET_CAL_MM1_SAMPLES_DEFAULT \ +((uint8_t) 40) +#define VL53L1_TUNINGPARM_OFFSET_CAL_MM2_SAMPLES_DEFAULT \ +((uint8_t) 9) +#define VL53L1_TUNINGPARM_ZONE_CAL_DSS_RATE_MCPS_DEFAULT \ +((uint16_t) 5120) +#define VL53L1_TUNINGPARM_ZONE_CAL_PHASECAL_TIMEOUT_US_DEFAULT \ +((uint32_t) 15000) +#define VL53L1_TUNINGPARM_ZONE_CAL_DSS_TIMEOUT_US_DEFAULT \ +((uint32_t) 2000) +#define VL53L1_TUNINGPARM_ZONE_CAL_PHASECAL_NUM_SAMPLES_DEFAULT \ +((uint16_t) 16) +#define VL53L1_TUNINGPARM_ZONE_CAL_RANGE_TIMEOUT_US_DEFAULT \ +((uint32_t) 1000) +#define VL53L1_TUNINGPARM_ZONE_CAL_ZONE_NUM_SAMPLES_DEFAULT \ +((uint16_t) 8) +#define VL53L1_TUNINGPARM_SPADMAP_VCSEL_PERIOD_DEFAULT \ +((uint8_t) 18) +#define VL53L1_TUNINGPARM_SPADMAP_VCSEL_START_DEFAULT \ +((uint8_t) 15) +#define VL53L1_TUNINGPARM_SPADMAP_RATE_LIMIT_MCPS_DEFAULT \ +((uint16_t) 12) +#define VL53L1_TUNINGPARM_LITE_DSS_CONFIG_TARGET_TOTAL_RATE_MCPS_DEFAULT \ +((uint16_t) 2560) +#define VL53L1_TUNINGPARM_RANGING_DSS_CONFIG_TARGET_TOTAL_RATE_MCPS_DEFAULT \ +((uint16_t) 5120) +#define VL53L1_TUNINGPARM_MZ_DSS_CONFIG_TARGET_TOTAL_RATE_MCPS_DEFAULT \ +((uint16_t) 5120) +#define VL53L1_TUNINGPARM_TIMED_DSS_CONFIG_TARGET_TOTAL_RATE_MCPS_DEFAULT \ +((uint16_t) 2560) +#define VL53L1_TUNINGPARM_LITE_PHASECAL_CONFIG_TIMEOUT_US_DEFAULT \ +((uint32_t) 1000) +#define VL53L1_TUNINGPARM_RANGING_LONG_PHASECAL_CONFIG_TIMEOUT_US_DEFAULT \ +((uint32_t) 15000) +#define VL53L1_TUNINGPARM_RANGING_MED_PHASECAL_CONFIG_TIMEOUT_US_DEFAULT \ +((uint32_t) 9000) +#define VL53L1_TUNINGPARM_RANGING_SHORT_PHASECAL_CONFIG_TIMEOUT_US_DEFAULT \ +((uint32_t) 6000) +#define VL53L1_TUNINGPARM_MZ_LONG_PHASECAL_CONFIG_TIMEOUT_US_DEFAULT \ +((uint32_t) 15000) +#define VL53L1_TUNINGPARM_MZ_MED_PHASECAL_CONFIG_TIMEOUT_US_DEFAULT \ +((uint32_t) 9000) +#define VL53L1_TUNINGPARM_MZ_SHORT_PHASECAL_CONFIG_TIMEOUT_US_DEFAULT \ +((uint32_t) 6000) +#define VL53L1_TUNINGPARM_TIMED_PHASECAL_CONFIG_TIMEOUT_US_DEFAULT \ +((uint32_t) 1000) +#define VL53L1_TUNINGPARM_LITE_MM_CONFIG_TIMEOUT_US_DEFAULT \ +((uint32_t) 2000) +#define VL53L1_TUNINGPARM_RANGING_MM_CONFIG_TIMEOUT_US_DEFAULT \ +((uint32_t) 2000) +#define VL53L1_TUNINGPARM_MZ_MM_CONFIG_TIMEOUT_US_DEFAULT \ +((uint32_t) 2000) +#define VL53L1_TUNINGPARM_TIMED_MM_CONFIG_TIMEOUT_US_DEFAULT \ +((uint32_t) 2000) +#define VL53L1_TUNINGPARM_LITE_RANGE_CONFIG_TIMEOUT_US_DEFAULT \ +((uint32_t) 63000) +#define VL53L1_TUNINGPARM_RANGING_RANGE_CONFIG_TIMEOUT_US_DEFAULT \ +((uint32_t) 2500) +#define VL53L1_TUNINGPARM_MZ_RANGE_CONFIG_TIMEOUT_US_DEFAULT \ +((uint32_t) 2500) +#define VL53L1_TUNINGPARM_TIMED_RANGE_CONFIG_TIMEOUT_US_DEFAULT \ +((uint32_t) 13000) +#define VL53L1_TUNINGPARM_DYNXTALK_SMUDGE_MARGIN_DEFAULT \ +((uint16_t) 0) +#define VL53L1_TUNINGPARM_DYNXTALK_NOISE_MARGIN_DEFAULT \ +((uint32_t) 100) +#define VL53L1_TUNINGPARM_DYNXTALK_XTALK_OFFSET_LIMIT_DEFAULT \ +((uint32_t) 0) +#define VL53L1_TUNINGPARM_DYNXTALK_XTALK_OFFSET_LIMIT_HI_DEFAULT \ +((uint8_t) 0) +#define VL53L1_TUNINGPARM_DYNXTALK_SAMPLE_LIMIT_DEFAULT \ +((uint32_t) 200) +#define VL53L1_TUNINGPARM_DYNXTALK_SINGLE_XTALK_DELTA_DEFAULT \ +((uint32_t) 2048) +#define VL53L1_TUNINGPARM_DYNXTALK_AVERAGED_XTALK_DELTA_DEFAULT \ +((uint32_t) 308) +#define VL53L1_TUNINGPARM_DYNXTALK_CLIP_LIMIT_DEFAULT \ +((uint32_t) 10240) +#define VL53L1_TUNINGPARM_DYNXTALK_SCALER_CALC_METHOD_DEFAULT \ +((uint8_t) 0) +#define VL53L1_TUNINGPARM_DYNXTALK_XGRADIENT_SCALER_DEFAULT \ +((int16_t) 256) +#define VL53L1_TUNINGPARM_DYNXTALK_YGRADIENT_SCALER_DEFAULT \ +((int16_t) 256) +#define VL53L1_TUNINGPARM_DYNXTALK_USER_SCALER_SET_DEFAULT \ +((uint8_t) 0) +#define VL53L1_TUNINGPARM_DYNXTALK_SMUDGE_COR_SINGLE_APPLY_DEFAULT \ +((uint8_t) 0) +#define VL53L1_TUNINGPARM_DYNXTALK_XTALK_AMB_THRESHOLD_DEFAULT \ +((uint32_t) 128) +#define VL53L1_TUNINGPARM_DYNXTALK_NODETECT_AMB_THRESHOLD_KCPS_DEFAULT \ +((uint32_t) 57671680) +#define VL53L1_TUNINGPARM_DYNXTALK_NODETECT_SAMPLE_LIMIT_DEFAULT \ +((uint32_t) 40) +#define VL53L1_TUNINGPARM_DYNXTALK_NODETECT_XTALK_OFFSET_KCPS_DEFAULT \ +((uint32_t) 410) +#define VL53L1_TUNINGPARM_DYNXTALK_NODETECT_MIN_RANGE_MM_DEFAULT \ +((uint16_t) 900) +#define VL53L1_TUNINGPARM_LOWPOWERAUTO_VHV_LOOP_BOUND_DEFAULT \ +((uint8_t) 3) +#define VL53L1_TUNINGPARM_LOWPOWERAUTO_MM_CONFIG_TIMEOUT_US_DEFAULT \ +((uint32_t) 1) +#define VL53L1_TUNINGPARM_LOWPOWERAUTO_RANGE_CONFIG_TIMEOUT_US_DEFAULT \ +((uint32_t) 8000) +#define VL53L1_TUNINGPARM_VERY_SHORT_DSS_RATE_MCPS_DEFAULT \ +((uint16_t) 10240) +#define VL53L1_TUNINGPARM_PHASECAL_PATCH_POWER_DEFAULT \ +((uint32_t) 0) +#define VL53L1_TUNINGPARM_HIST_MERGE_DEFAULT \ +((uint32_t) 1) +#define VL53L1_TUNINGPARM_RESET_MERGE_THRESHOLD_DEFAULT \ +((uint32_t) 15000) +#define VL53L1_TUNINGPARM_HIST_MERGE_MAX_SIZE_DEFAULT \ +((uint32_t) 6) + + +#ifdef __cplusplus +} +#endif + +#endif + + + + diff --git a/drivers/input/misc/vl53L1/kona/inc/vl53l1_wait.h b/drivers/input/misc/vl53L1/kona/inc/vl53l1_wait.h new file mode 100644 index 000000000000..c76cb5ad050f --- /dev/null +++ b/drivers/input/misc/vl53L1/kona/inc/vl53l1_wait.h @@ -0,0 +1,319 @@ + +/******************************************************************************* + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#ifndef _VL53L1_WAIT_H_ +#define _VL53L1_WAIT_H_ + +#include "vl53l1_platform.h" + +#ifdef __cplusplus +extern "C" { +#endif + + + + + + + + + + + + + + +VL53L1_Error VL53L1_wait_for_boot_completion( + VL53L1_DEV Dev); + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_wait_for_firmware_ready( + VL53L1_DEV Dev); + + + + + + + + + + + + + + +VL53L1_Error VL53L1_wait_for_range_completion( + VL53L1_DEV Dev); + + + + + + + + + + + + + + +VL53L1_Error VL53L1_wait_for_test_completion( + VL53L1_DEV Dev); + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_is_boot_complete( + VL53L1_DEV Dev, + uint8_t *pready); + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_is_firmware_ready( + VL53L1_DEV Dev, + uint8_t *pready); + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_is_new_data_ready( + VL53L1_DEV Dev, + uint8_t *pready); + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_poll_for_boot_completion( + VL53L1_DEV Dev, + uint32_t timeout_ms); + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_poll_for_firmware_ready( + VL53L1_DEV Dev, + uint32_t timeout_ms); + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_poll_for_range_completion( + VL53L1_DEV Dev, + uint32_t timeout_ms); + + + +#ifdef __cplusplus +} +#endif + +#endif + + diff --git a/drivers/input/misc/vl53L1/kona/inc/vl53l1_zone_presets.h b/drivers/input/misc/vl53L1/kona/inc/vl53l1_zone_presets.h new file mode 100644 index 000000000000..68c8c4712a7e --- /dev/null +++ b/drivers/input/misc/vl53L1/kona/inc/vl53l1_zone_presets.h @@ -0,0 +1,183 @@ + +/******************************************************************************* + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#ifndef _VL53L1_ZONE_PRESETS_H_ +#define _VL53L1_ZONE_PRESETS_H_ + +#include "vl53l1_ll_def.h" + +#ifdef __cplusplus +extern "C" { +#endif + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_init_zone_config_structure( + uint8_t x_off, + uint8_t x_inc, + uint8_t x_zones, + uint8_t y_off, + uint8_t y_inc, + uint8_t y_zones, + uint8_t width, + uint8_t height, + VL53L1_zone_config_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_zone_preset_xtalk_planar( + VL53L1_general_config_t *pgeneral, + VL53L1_zone_config_t *pzone_cfg); + + + + + + + + + + + + + +VL53L1_Error VL53L1_init_zone_config_histogram_bins( + VL53L1_zone_config_t *pdata); + +#ifdef __cplusplus +} +#endif + +#endif + + diff --git a/drivers/input/misc/vl53L1/kona/ipp/ipp_linux.c b/drivers/input/misc/vl53L1/kona/ipp/ipp_linux.c new file mode 100644 index 000000000000..d220186fc10f --- /dev/null +++ b/drivers/input/misc/vl53L1/kona/ipp/ipp_linux.c @@ -0,0 +1,356 @@ +/************************************************************************** + * Copyright (c) 2016, STMicroelectronics - All Rights Reserved + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ****************************************************************************/ + +/** + * @file ipp_linux.c kernel side implementation of vl53l1 protected processing + * + * @date Sep 1, 2016 + * @author : imaging + * + * @ingroup ipp_dev + */ + +#include "stmvl53l1.h" + +#define IPP_ERR_CODE (VL53L1_ERROR_PLATFORM_SPECIFIC_START-1) + +static int stmvl53l1_ipp_do_wrapper(struct stmvl53l1_data *data, + struct ipp_work_t *pin, struct ipp_work_t *pout, int payload_out) +{ + int rc; + + if (data->ipp.buzy) { + vl53l1_errmsg("try exec new ipp but still buzy on previous"); + /* TODO shall we discard it and push new ? */ + rc = IPP_ERR_CODE; + goto done; + } + WARN_ON(pin->payload > IPP_WORK_MAX_PAYLOAD); + stmvl531_ipp_tim_start(data); + rc = stmvl53l1_ipp_do(data, pin, pout); + if (rc != 0) { + vl53l1_errmsg("stmvl53l1_ipp_do err %d\n", rc); + rc = IPP_ERR_CODE; + goto done; + } + //vl53l1_dbgmsg("ipp ok \n"); + /* check what we got back if valid answer error etc */ + if (pout->status) { + vl53l1_errmsg("ipp error status %d from user", pout->status); + if (pout->status >= stmvl53l1_ipp_status_proc_code) + rc = pout->status & (stmvl53l1_ipp_status_proc_code-1); + else + rc = IPP_ERR_CODE; + goto done; + } + WARN_ON(pout->payload > IPP_WORK_MAX_PAYLOAD); + if (pout->payload != payload_out) { + /* bad formated answer */ + vl53l1_errmsg("bad payload %d != %d in ipp work back", + pout->payload, payload_out); + rc = IPP_ERR_CODE; + goto done; + } + stmvl531_ipp_tim_stop(data); + stmvl531_ipp_stat(data, "ipp #%5x to=%3d fm=%3d in %5ld us", + pin->xfer_id, pin->payload, + pout->payload, + stmvl531_ipp_time(data)); + + rc = 0; +done: + + return rc; +} + +/** + * @file vl53l1_platform_ipp.h + * + * @brief EwokPlus25 IPP Wrapper Functions + */ + +/** + * @brief IPP Wrapper call for histogram post processing + * + * + * @param[in] Dev : Device handle + * @param[in] pdmax_cal : DMAX calibration data + * @param[in] pdmax_cfg : DMAX configuration data + * @param[in] ppost_cfg : VL53L1_hist_post_process_config_t + * @param[in] pbins : Input histogram raw bin data + * @param[in] pxtalk : Cross talk histogram data + * @param[in] pArea1 : Extern. allocated to save stack + * @param[in] pArea1 : Extern. allocated to save stack + * @param[out] presults : Output VL53L1_range_results_t + * structure + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_ipp_hist_process_data( + VL53L1_DEV dev, + VL53L1_dmax_calibration_data_t *pdmax_cal, + VL53L1_hist_gen3_dmax_config_t *pdmax_cfg, + VL53L1_hist_post_process_config_t *ppost_cfg, + VL53L1_histogram_bin_data_t *pbins, + VL53L1_xtalk_histogram_data_t *pxtalk, + uint8_t *pArea1, + uint8_t *pArea2, + uint8_t *phisto_merge_nb, + VL53L1_range_results_t *presults) +{ + struct stmvl53l1_data *data = (struct stmvl53l1_data *) + container_of(dev, struct stmvl53l1_data, stdev); + struct ipp_work_t *pout = &data->ipp.work_out; + struct ipp_work_t *pin = &data->ipp.work; + int rc; + VL53L1_range_results_t *presults_ipp; + + IPP_SERIALIZE_VAR; + + /* These external workspace input params are useless with IPP managed in + * the daemon because the histogram processing function is actually + * allocating its data in USER stack within the daemon not the kernel one + */ + (void)pArea1; + (void)pArea2; + + /* setup pin */ + IPP_SERIALIZE_START(pin->data, 6); + IPP_SET_ARG_PTR(pin->data, 0, pdmax_cal); + IPP_SET_ARG_PTR(pin->data, 1, pdmax_cfg); + IPP_SET_ARG_PTR(pin->data, 2, ppost_cfg); + IPP_SET_ARG_PTR(pin->data, 3, pbins); + IPP_SET_ARG_PTR(pin->data, 4, pxtalk); + IPP_SET_ARG_PTR(pin->data, 5, phisto_merge_nb); + pin->payload = IPP_SERIALIZE_PAYLAOD(); + pin->process_no = stmvl53l1_ipp_cal_hist; + + /* setup pout */ + IPP_SERIALIZE_START(pout->data, 1); + IPP_OUT_ARG_PTR(pout->data, 0, presults_ipp); + + /* do ipp */ + rc = stmvl53l1_ipp_do_wrapper(data, pin, pout, IPP_SERIALIZE_PAYLAOD()); + if (rc) + goto done; + + /* copy output */ + memcpy(presults, presults_ipp, sizeof(*presults)); + + rc = 0; +done: + + return rc; +} + +/** + * @brief IPP Wrapper call for histogram ambient dmax calc + * + * The target reflectance in percent for the DMAX calculation + * is set by target_reflectance input + * + * The fixed point format is 7.2 + * + * @param[in] Dev : Device handle + * @param[in] target_reflectance : target reflectance to report ambient DMAX + * Percentage in 7.2 fixed point format + * @param[in] pdmax_cal : DMAX calibration data + * @param[in] pdmax_cfg : DMAX configuration data + * @param[in] pbins : Input histogram raw bin data + * @param[out] pambient_dmax_mm : Output ambient DMAX distance in [mm] + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_ipp_hist_ambient_dmax( + VL53L1_DEV dev, + uint16_t target_reflectance, + VL53L1_dmax_calibration_data_t *pdmax_cal, + VL53L1_hist_gen3_dmax_config_t *pdmax_cfg, + VL53L1_histogram_bin_data_t *pbins, + int16_t *pambient_dmax_mm) +{ + struct stmvl53l1_data *data = (struct stmvl53l1_data *) + container_of(dev, struct stmvl53l1_data, stdev); + struct ipp_work_t *pout = &data->ipp.work_out; + struct ipp_work_t *pin = &data->ipp.work; + int rc; + int16_t *pambient_dmax_mm_ipp; + + IPP_SERIALIZE_VAR; + + /* setup pin */ + IPP_SERIALIZE_START(pin->data, 4); + IPP_SET_ARG(pin->data, 0, target_reflectance); + IPP_SET_ARG_PTR(pin->data, 1, pdmax_cal); + IPP_SET_ARG_PTR(pin->data, 2, pdmax_cfg); + IPP_SET_ARG_PTR(pin->data, 3, pbins); + pin->payload = IPP_SERIALIZE_PAYLAOD(); + pin->process_no = stmvl53l1_ipp_hist_ambient_dmax; + + /* setup pout */ + IPP_SERIALIZE_START(pout->data, 1); + IPP_OUT_ARG_PTR(pout->data, 0, pambient_dmax_mm_ipp); + + /* do ipp */ + rc = stmvl53l1_ipp_do_wrapper(data, pin, pout, IPP_SERIALIZE_PAYLAOD()); + if (rc) + goto done; + + /* copy output */ + memcpy(pambient_dmax_mm, pambient_dmax_mm_ipp, + sizeof(*pambient_dmax_mm)); + + rc = 0; +done: + + return rc; +} + +/** + * @brief IPP Wrapper call for xtalk calibration post processing + * + * @param[in] Dev : Device handle + * @param[in] pxtalk_ranges : Input VL53L1_xtalk_range_results_t + * Must contain 5 ranges, 4 quadrants + 1 + * full FoV + * @param[out] pxtalk_shape : Output normalised Cross talk histogram + * shape + * @param[out] pxtalk_cal : Output VL53L1_xtalk_calibration_results_t + * structure + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_ipp_xtalk_calibration_process_data( + VL53L1_DEV dev, + VL53L1_xtalk_range_results_t *pxtalk_ranges, + VL53L1_xtalk_histogram_data_t *pxtalk_shape, + VL53L1_xtalk_calibration_results_t *pxtalk_cal) +{ + struct stmvl53l1_data *data = (struct stmvl53l1_data *) + container_of(dev, struct stmvl53l1_data, stdev); + struct ipp_work_t *pout = &data->ipp.work_out; + struct ipp_work_t *pin = &data->ipp.work; + int rc; + VL53L1_xtalk_histogram_data_t *pxtalk_shape_ipp; + VL53L1_xtalk_calibration_results_t *pxtalk_cal_ipp; + + IPP_SERIALIZE_VAR; + + /* setup pin */ + IPP_SERIALIZE_START(pin->data, 1); + IPP_SET_ARG_PTR(pin->data, 0, pxtalk_ranges); + pin->payload = IPP_SERIALIZE_PAYLAOD(); + pin->process_no = stmvl53l1_ipp_xtalk_calibration; + + /* setup pout */ + IPP_SERIALIZE_START(pout->data, 2); + IPP_OUT_ARG_PTR(pout->data, 0, pxtalk_shape_ipp); + IPP_OUT_ARG_PTR(pout->data, 1, pxtalk_cal_ipp); + + /* do ipp */ + rc = stmvl53l1_ipp_do_wrapper(data, pin, pout, IPP_SERIALIZE_PAYLAOD()); + if (rc) + goto done; + + /* copy output */ + memcpy(pxtalk_shape, pxtalk_shape_ipp, sizeof(*pxtalk_shape)); + memcpy(pxtalk_cal, pxtalk_cal_ipp, sizeof(*pxtalk_cal)); + + rc = 0; +done: + + return rc; +} + +/** + * @brief IPP Wrapper call for Generating Xtalk data from dual reflectance + * histogram data + * + * @param[in] Dev : Device handle + * @param[in] pxtalk_results : Pointer to xtalk_results structure + * containing dual reflectance + * histogram data + * @param[in] expected_target_distance_mm : User input of true target distance + * @param[in] higher_reflectance : User input detailing which + * histogram data 1 or 2 has the + * highest reflectance. + * @param[out] pxtalk_avg_samples : Pointer to output xtalk histogram + * data + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_ipp_generate_dual_reflectance_xtalk_samples( + VL53L1_DEV dev, + VL53L1_xtalk_range_results_t *pxtalk_results, + uint16_t expected_target_distance_mm, + uint8_t higher_reflectance, + VL53L1_histogram_bin_data_t *pxtalk_avg_samples) +{ + struct stmvl53l1_data *data = (struct stmvl53l1_data *) + container_of(dev, struct stmvl53l1_data, stdev); + struct ipp_work_t *pout = &data->ipp.work_out; + struct ipp_work_t *pin = &data->ipp.work; + int rc; + VL53L1_histogram_bin_data_t *pxtalk_avg_samples_ipp; + + IPP_SERIALIZE_VAR; + + /* setup pin */ + IPP_SERIALIZE_START(pin->data, 3); + IPP_SET_ARG_PTR(pin->data, 0, pxtalk_results); + IPP_SET_ARG(pin->data, 1, expected_target_distance_mm); + IPP_SET_ARG(pin->data, 2, higher_reflectance); + pin->payload = IPP_SERIALIZE_PAYLAOD(); + pin->process_no = stmvl53l1_ipp_generate_dual_reflectance_xtalk_samples; + + /* setup pout */ + IPP_SERIALIZE_START(pout->data, 1); + IPP_OUT_ARG_PTR(pout->data, 0, pxtalk_avg_samples_ipp); + + /* do ipp */ + rc = stmvl53l1_ipp_do_wrapper(data, pin, pout, IPP_SERIALIZE_PAYLAOD()); + if (rc) + goto done; + + /* copy output */ + memcpy(pxtalk_avg_samples, pxtalk_avg_samples_ipp, + sizeof(*pxtalk_avg_samples)); + + rc = 0; +done: + + return rc; +} diff --git a/drivers/input/misc/vl53L1/kona/src/vl53l1_api.c b/drivers/input/misc/vl53L1/kona/src/vl53l1_api.c new file mode 100644 index 000000000000..9f366925573b --- /dev/null +++ b/drivers/input/misc/vl53L1/kona/src/vl53l1_api.c @@ -0,0 +1,4063 @@ + +/******************************************************************************* + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#include "vl53l1_api.h" +#include "vl53l1_api_strings.h" +#include "vl53l1_register_settings.h" +#include "vl53l1_register_funcs.h" +#include "vl53l1_core.h" +#include "vl53l1_api_calibration.h" +#include "vl53l1_wait.h" +#include "vl53l1_preset_setup.h" +#include "vl53l1_api_debug.h" +#include "vl53l1_api_core.h" +#include "vl53l1_nvm.h" + + + +#define ZONE_CHECK VL53L1_MAX_USER_ZONES + +#if ZONE_CHECK < 5 +#error Must define at least 5 zones in MAX_USER_ZONES constant +#endif + +#define LOG_FUNCTION_START(fmt, ...) \ + _LOG_FUNCTION_START(VL53L1_TRACE_MODULE_API, fmt, ##__VA_ARGS__) +#define LOG_FUNCTION_END(status, ...) \ + _LOG_FUNCTION_END(VL53L1_TRACE_MODULE_API, status, ##__VA_ARGS__) +#define LOG_FUNCTION_END_FMT(status, fmt, ...) \ + _LOG_FUNCTION_END_FMT(VL53L1_TRACE_MODULE_API, status, \ + fmt, ##__VA_ARGS__) + +#ifdef VL53L1_LOG_ENABLE +#define trace_print(level, ...) trace_print_module_function(\ + VL53L1_TRACE_MODULE_API, level, VL53L1_TRACE_FUNCTION_NONE, \ + ##__VA_ARGS__) +#endif + +#ifndef MIN +#define MIN(v1, v2) ((v1) < (v2) ? (v1) : (v2)) +#endif +#ifndef MAX +#define MAX(v1, v2) ((v1) < (v2) ? (v2) : (v1)) +#endif + +#define DMAX_REFLECTANCE_IDX 2 + + + + + + + +#define LOWPOWER_AUTO_VHV_LOOP_DURATION_US 245 +#define LOWPOWER_AUTO_OVERHEAD_BEFORE_A_RANGING 1448 +#define LOWPOWER_AUTO_OVERHEAD_BETWEEN_A_B_RANGING 2100 + +#define FDA_MAX_TIMING_BUDGET_US 550000 + + + + + + + + + +static int32_t BDTable[VL53L1_TUNING_MAX_TUNABLE_KEY] = { + TUNING_VERSION, + TUNING_PROXY_MIN, + TUNING_SINGLE_TARGET_XTALK_TARGET_DISTANCE_MM, + TUNING_SINGLE_TARGET_XTALK_SAMPLE_NUMBER, + TUNING_MIN_AMBIENT_DMAX_VALID, + TUNING_MAX_SIMPLE_OFFSET_CALIBRATION_SAMPLE_NUMBER, + TUNING_XTALK_FULL_ROI_TARGET_DISTANCE_MM, + TUNING_SIMPLE_OFFSET_CALIBRATION_REPEAT, + TUNING_XTALK_FULL_ROI_MAX_THRESHOLD, + TUNING_XTALK_FULL_ROI_BIN_SUM_MARGIN, + TUNING_XTALK_FULL_ROI_DEFAULT_OFFSET, + TUNING_ZERO_DISTANCE_OFFSET_NON_LINEAR_FACTOR_DEFAULT +}; + + + +static VL53L1_Error SingleTargetXTalkCalibration(VL53L1_DEV Dev) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + uint32_t sum_ranging = 0; + uint32_t sum_spads = 0; + FixPoint1616_t sum_signalRate = 0; + FixPoint1616_t total_count = 0; + uint8_t xtalk_meas = 0; + uint8_t xtalk_measmax = + BDTable[VL53L1_TUNING_SINGLE_TARGET_XTALK_SAMPLE_NUMBER]; + VL53L1_RangingMeasurementData_t RMData; + FixPoint1616_t xTalkStoredMeanSignalRate; + FixPoint1616_t xTalkStoredMeanRange; + FixPoint1616_t xTalkStoredMeanRtnSpads; + uint32_t xTalkStoredMeanRtnSpadsAsInt; + uint32_t xTalkCalDistanceAsInt; + FixPoint1616_t XTalkCompensationRateMegaCps; + uint32_t signalXTalkTotalPerSpad; + VL53L1_PresetModes PresetMode; + VL53L1_CalibrationData_t CalibrationData; + VL53L1_CustomerNvmManaged_t *pC; + + + LOG_FUNCTION_START(""); + + + + + + + + PresetMode = VL53L1DevDataGet(Dev, CurrentParameters.PresetMode); + + if ((PresetMode != VL53L1_PRESETMODE_AUTONOMOUS) && + (PresetMode != VL53L1_PRESETMODE_LOWPOWER_AUTONOMOUS) && + (PresetMode != VL53L1_PRESETMODE_LITE_RANGING)) { + Status = VL53L1_ERROR_MODE_NOT_SUPPORTED; + goto ENDFUNC; + } + + + + Status = VL53L1_disable_xtalk_compensation(Dev); + + if (Status != VL53L1_ERROR_NONE) + goto ENDFUNC; + + Status = VL53L1_StartMeasurement(Dev); + + if (Status != VL53L1_ERROR_NONE) + goto ENDFUNC; + + + + VL53L1_WaitMeasurementDataReady(Dev); + VL53L1_GetRangingMeasurementData(Dev, &RMData); + VL53L1_ClearInterruptAndStartMeasurement(Dev); + + sum_ranging = 0; + sum_spads = 0; + sum_signalRate = 0; + total_count = 0; + for (xtalk_meas = 0; xtalk_meas < xtalk_measmax; xtalk_meas++) { + VL53L1_WaitMeasurementDataReady(Dev); + VL53L1_GetRangingMeasurementData(Dev, &RMData); + VL53L1_ClearInterruptAndStartMeasurement(Dev); + if (RMData.RangeStatus == VL53L1_RANGESTATUS_RANGE_VALID) { + sum_ranging += RMData.RangeMilliMeter; + sum_signalRate += RMData.SignalRateRtnMegaCps; + sum_spads += RMData.EffectiveSpadRtnCount / 256; + total_count++; + } + } + Status = VL53L1_StopMeasurement(Dev); + + if (total_count > 0) { + + + xTalkStoredMeanSignalRate = sum_signalRate / total_count; + xTalkStoredMeanRange = (FixPoint1616_t)(sum_ranging << 16); + xTalkStoredMeanRange /= total_count; + xTalkStoredMeanRtnSpads = (FixPoint1616_t)(sum_spads << 16); + xTalkStoredMeanRtnSpads /= total_count; + + + + + + + + + + + + + + xTalkStoredMeanRtnSpadsAsInt = (xTalkStoredMeanRtnSpads + + 0x8000) >> 16; + + + + + + + xTalkCalDistanceAsInt = ((uint32_t)BDTable[ + VL53L1_TUNING_SINGLE_TARGET_XTALK_TARGET_DISTANCE_MM]); + if (xTalkStoredMeanRtnSpadsAsInt == 0 || + xTalkCalDistanceAsInt == 0 || + xTalkStoredMeanRange >= (xTalkCalDistanceAsInt << 16)) { + XTalkCompensationRateMegaCps = 0; + } else { + + + + + + + signalXTalkTotalPerSpad = (xTalkStoredMeanSignalRate) / + xTalkStoredMeanRtnSpadsAsInt; + + + + + + + + signalXTalkTotalPerSpad *= (((uint32_t)1 << 16) - + (xTalkStoredMeanRange / xTalkCalDistanceAsInt)); + + + + XTalkCompensationRateMegaCps = (signalXTalkTotalPerSpad + + 0x8000) >> 16; + } + + + Status = VL53L1_GetCalibrationData(Dev, &CalibrationData); + + if (Status != VL53L1_ERROR_NONE) + goto ENDFUNC; + + pC = &CalibrationData.customer; + + pC->algo__crosstalk_compensation_plane_offset_kcps = + (uint32_t)(1000 * ((XTalkCompensationRateMegaCps + + ((uint32_t)1<<6)) >> (16-9))); + + Status = VL53L1_SetCalibrationData(Dev, &CalibrationData); + + if (Status != VL53L1_ERROR_NONE) + goto ENDFUNC; + + Status = VL53L1_enable_xtalk_compensation(Dev); + + } else + + + Status = VL53L1_ERROR_XTALK_EXTRACTION_NO_SAMPLE_FAIL; + +ENDFUNC: + LOG_FUNCTION_END(Status); + return Status; + +} + + + + + + + + + + +static VL53L1_Error CheckValidRectRoi(VL53L1_UserRoi_t ROI) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + if ((ROI.TopLeftX > 15) || (ROI.TopLeftY > 15) || + (ROI.BotRightX > 15) || (ROI.BotRightY > 15)) + Status = VL53L1_ERROR_INVALID_PARAMS; + + if ((ROI.TopLeftX > ROI.BotRightX) || (ROI.TopLeftY < ROI.BotRightY)) + Status = VL53L1_ERROR_INVALID_PARAMS; + + LOG_FUNCTION_END(Status); + return Status; +} + +static VL53L1_GPIO_Interrupt_Mode ConvertModeToLLD(VL53L1_Error *pStatus, + VL53L1_ThresholdMode CrossMode) +{ + VL53L1_GPIO_Interrupt_Mode Mode; + + switch (CrossMode) { + case VL53L1_THRESHOLD_CROSSED_LOW: + Mode = VL53L1_GPIOINTMODE_LEVEL_LOW; + break; + case VL53L1_THRESHOLD_CROSSED_HIGH: + Mode = VL53L1_GPIOINTMODE_LEVEL_HIGH; + break; + case VL53L1_THRESHOLD_OUT_OF_WINDOW: + Mode = VL53L1_GPIOINTMODE_OUT_OF_WINDOW; + break; + case VL53L1_THRESHOLD_IN_WINDOW: + Mode = VL53L1_GPIOINTMODE_IN_WINDOW; + break; + default: + + + Mode = VL53L1_GPIOINTMODE_LEVEL_HIGH; + *pStatus = VL53L1_ERROR_INVALID_PARAMS; + } + return Mode; +} + +static VL53L1_ThresholdMode ConvertModeFromLLD(VL53L1_Error *pStatus, + VL53L1_GPIO_Interrupt_Mode CrossMode) +{ + VL53L1_ThresholdMode Mode; + + switch (CrossMode) { + case VL53L1_GPIOINTMODE_LEVEL_LOW: + Mode = VL53L1_THRESHOLD_CROSSED_LOW; + break; + case VL53L1_GPIOINTMODE_LEVEL_HIGH: + Mode = VL53L1_THRESHOLD_CROSSED_HIGH; + break; + case VL53L1_GPIOINTMODE_OUT_OF_WINDOW: + Mode = VL53L1_THRESHOLD_OUT_OF_WINDOW; + break; + case VL53L1_GPIOINTMODE_IN_WINDOW: + Mode = VL53L1_THRESHOLD_IN_WINDOW; + break; + default: + + + Mode = VL53L1_THRESHOLD_CROSSED_HIGH; + *pStatus = VL53L1_ERROR_UNDEFINED; + } + return Mode; +} + + + + +VL53L1_Error VL53L1_GetVersion(VL53L1_Version_t *pVersion) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + pVersion->major = VL53L1_IMPLEMENTATION_VER_MAJOR; + pVersion->minor = VL53L1_IMPLEMENTATION_VER_MINOR; + pVersion->build = VL53L1_IMPLEMENTATION_VER_SUB; + + pVersion->revision = VL53L1_IMPLEMENTATION_VER_REVISION; + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_GetProductRevision(VL53L1_DEV Dev, + uint8_t *pProductRevisionMajor, uint8_t *pProductRevisionMinor) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + uint8_t revision_id; + VL53L1_LLDriverData_t *pLLData; + + LOG_FUNCTION_START(""); + + pLLData = VL53L1DevStructGetLLDriverHandle(Dev); + revision_id = pLLData->nvm_copy_data.identification__revision_id; + *pProductRevisionMajor = 1; + *pProductRevisionMinor = (revision_id & 0xF0) >> 4; + + LOG_FUNCTION_END(Status); + return Status; + +} + +VL53L1_Error VL53L1_GetDeviceInfo(VL53L1_DEV Dev, + VL53L1_DeviceInfo_t *pVL53L1_DeviceInfo) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + uint8_t revision_id; + VL53L1_LLDriverData_t *pLLData; + + LOG_FUNCTION_START(""); + + pLLData = VL53L1DevStructGetLLDriverHandle(Dev); + + strncpy(pVL53L1_DeviceInfo->ProductId, "", + VL53L1_DEVINFO_STRLEN-1); + pVL53L1_DeviceInfo->ProductType = + pLLData->nvm_copy_data.identification__module_type; + + revision_id = pLLData->nvm_copy_data.identification__revision_id; + pVL53L1_DeviceInfo->ProductRevisionMajor = 1; + pVL53L1_DeviceInfo->ProductRevisionMinor = (revision_id & 0xF0) >> 4; + +#ifndef VL53L1_USE_EMPTY_STRING + if (pVL53L1_DeviceInfo->ProductRevisionMinor == 0) + strncpy(pVL53L1_DeviceInfo->Name, + VL53L1_STRING_DEVICE_INFO_NAME0, + VL53L1_DEVINFO_STRLEN-1); + else + strncpy(pVL53L1_DeviceInfo->Name, + VL53L1_STRING_DEVICE_INFO_NAME1, + VL53L1_DEVINFO_STRLEN-1); + strncpy(pVL53L1_DeviceInfo->Type, + VL53L1_STRING_DEVICE_INFO_TYPE, + VL53L1_DEVINFO_STRLEN-1); + + + if (pVL53L1_DeviceInfo->ProductType == 0xAA) { + pVL53L1_DeviceInfo->Name[5] = '3'; + pVL53L1_DeviceInfo->Type[5] = '3'; + } +#else + pVL53L1_DeviceInfo->Name[0] = 0; + pVL53L1_DeviceInfo->Type[0] = 0; +#endif + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_GetUID(VL53L1_DEV Dev, uint64_t *pUid) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + uint8_t fmtdata[8]; + + LOG_FUNCTION_START(""); + + Status = VL53L1_read_nvm_raw_data(Dev, + (uint8_t)(0x1F8 >> 2), + (uint8_t)(8 >> 2), + fmtdata); + memcpy(pUid, fmtdata, sizeof(uint64_t)); + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_GetRangeStatusString(uint8_t RangeStatus, + char *pRangeStatusString) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + Status = VL53L1_get_range_status_string(RangeStatus, + pRangeStatusString); + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_GetPalErrorString(VL53L1_Error PalErrorCode, + char *pPalErrorString) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + Status = VL53L1_get_pal_error_string(PalErrorCode, pPalErrorString); + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_GetPalStateString(VL53L1_State PalStateCode, + char *pPalStateString) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + Status = VL53L1_get_pal_state_string(PalStateCode, pPalStateString); + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_GetPalState(VL53L1_DEV Dev, VL53L1_State *pPalState) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + *pPalState = VL53L1DevDataGet(Dev, PalState); + + LOG_FUNCTION_END(Status); + return Status; +} + + + + + + +VL53L1_Error VL53L1_SetDeviceAddress(VL53L1_DEV Dev, uint8_t DeviceAddress) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + Status = VL53L1_WrByte(Dev, VL53L1_I2C_SLAVE__DEVICE_ADDRESS, + DeviceAddress / 2); + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_DataInit(VL53L1_DEV Dev) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + uint8_t i; + VL53L1_LLDriverData_t *pdev; + + LOG_FUNCTION_START(""); + + + +#ifdef USE_I2C_2V8 + Status = VL53L1_RdByte(Dev, VL53L1_PAD_I2C_HV__EXTSUP_CONFIG, &i); + if (Status == VL53L1_ERROR_NONE) { + i = (i & 0xfe) | 0x01; + Status = VL53L1_WrByte(Dev, VL53L1_PAD_I2C_HV__EXTSUP_CONFIG, + i); + } +#endif + + if (Status == VL53L1_ERROR_NONE) + Status = VL53L1_data_init(Dev, 1); + + if (Status == VL53L1_ERROR_NONE) { + pdev = VL53L1DevStructGetLLDriverHandle(Dev); + memset(&pdev->per_vcsel_cal_data, 0, + sizeof(pdev->per_vcsel_cal_data)); + } + + if (Status == VL53L1_ERROR_NONE) { + VL53L1DevDataSet(Dev, PalState, VL53L1_STATE_WAIT_STATICINIT); + VL53L1DevDataSet(Dev, CurrentParameters.PresetMode, + VL53L1_PRESETMODE_RANGING); + } + + + + for (i = 0; i < VL53L1_CHECKENABLE_NUMBER_OF_CHECKS; i++) { + if (Status == VL53L1_ERROR_NONE) + Status |= VL53L1_SetLimitCheckEnable(Dev, i, 1); + else + break; + + } + + + + + if (Status == VL53L1_ERROR_NONE) { + Status = VL53L1_set_dmax_mode(Dev, + VL53L1_DEVICEDMAXMODE__CUST_CAL_DATA); + } + + + + LOG_FUNCTION_END(Status); + return Status; +} + + +VL53L1_Error VL53L1_StaticInit(VL53L1_DEV Dev) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + uint8_t measurement_mode; + + LOG_FUNCTION_START(""); + + VL53L1DevDataSet(Dev, PalState, VL53L1_STATE_IDLE); + + measurement_mode = VL53L1_DEVICEMEASUREMENTMODE_BACKTOBACK; + VL53L1DevDataSet(Dev, LLData.measurement_mode, measurement_mode); + + VL53L1DevDataSet(Dev, CurrentParameters.DistanceMode, + VL53L1_DISTANCEMODE_LONG); + + VL53L1DevDataSet(Dev, CurrentParameters.OutputMode, + VL53L1_OUTPUTMODE_NEAREST); + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_WaitDeviceBooted(VL53L1_DEV Dev) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + Status = VL53L1_poll_for_boot_completion(Dev, + VL53L1_BOOT_COMPLETION_POLLING_TIMEOUT_MS); + + LOG_FUNCTION_END(Status); + return Status; +} + + + + + + +static VL53L1_Error ComputeDevicePresetMode( + VL53L1_PresetModes PresetMode, + VL53L1_DistanceModes DistanceMode, + VL53L1_DevicePresetModes *pDevicePresetMode) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + uint8_t DistIdx; + VL53L1_DevicePresetModes LightModes[3] = { + VL53L1_DEVICEPRESETMODE_STANDARD_RANGING_SHORT_RANGE, + VL53L1_DEVICEPRESETMODE_STANDARD_RANGING, + VL53L1_DEVICEPRESETMODE_STANDARD_RANGING_LONG_RANGE}; + + VL53L1_DevicePresetModes RangingModes[3] = { + VL53L1_DEVICEPRESETMODE_HISTOGRAM_SHORT_RANGE, + VL53L1_DEVICEPRESETMODE_HISTOGRAM_MEDIUM_RANGE, + VL53L1_DEVICEPRESETMODE_HISTOGRAM_LONG_RANGE}; + + VL53L1_DevicePresetModes ScanningModes[3] = { + VL53L1_DEVICEPRESETMODE_HISTOGRAM_MULTIZONE_SHORT_RANGE, + VL53L1_DEVICEPRESETMODE_HISTOGRAM_MULTIZONE, + VL53L1_DEVICEPRESETMODE_HISTOGRAM_MULTIZONE_LONG_RANGE}; + + VL53L1_DevicePresetModes TimedModes[3] = { + VL53L1_DEVICEPRESETMODE_TIMED_RANGING_SHORT_RANGE, + VL53L1_DEVICEPRESETMODE_TIMED_RANGING, + VL53L1_DEVICEPRESETMODE_TIMED_RANGING_LONG_RANGE}; + + VL53L1_DevicePresetModes LowPowerTimedModes[3] = { + VL53L1_DEVICEPRESETMODE_LOWPOWERAUTO_SHORT_RANGE, + VL53L1_DEVICEPRESETMODE_LOWPOWERAUTO_MEDIUM_RANGE, + VL53L1_DEVICEPRESETMODE_LOWPOWERAUTO_LONG_RANGE}; + + *pDevicePresetMode = VL53L1_DEVICEPRESETMODE_STANDARD_RANGING; + + switch (DistanceMode) { + case VL53L1_DISTANCEMODE_SHORT: + DistIdx = 0; + break; + case VL53L1_DISTANCEMODE_MEDIUM: + DistIdx = 1; + break; + default: + DistIdx = 2; + } + + switch (PresetMode) { + case VL53L1_PRESETMODE_LITE_RANGING: + *pDevicePresetMode = LightModes[DistIdx]; + break; + + case VL53L1_PRESETMODE_RANGING: + *pDevicePresetMode = RangingModes[DistIdx]; + break; + + case VL53L1_PRESETMODE_MULTIZONES_SCANNING: + *pDevicePresetMode = ScanningModes[DistIdx]; + break; + + case VL53L1_PRESETMODE_AUTONOMOUS: + *pDevicePresetMode = TimedModes[DistIdx]; + break; + + case VL53L1_PRESETMODE_LOWPOWER_AUTONOMOUS: + *pDevicePresetMode = LowPowerTimedModes[DistIdx]; + break; + case VL53L1_PRESETMODE_OLT: + *pDevicePresetMode = VL53L1_DEVICEPRESETMODE_OLT; + break; + case VL53L1_PRESETMODE_PROXY_RANGING_MODE: + *pDevicePresetMode = + VL53L1_DEVICEPRESETMODE_SPECIAL_HISTOGRAM_SHORT_RANGE; + break; + + default: + + + Status = VL53L1_ERROR_MODE_NOT_SUPPORTED; + } + + return Status; +} + +static VL53L1_Error SetPresetMode(VL53L1_DEV Dev, + VL53L1_PresetModes PresetMode, + VL53L1_DistanceModes DistanceMode, + uint32_t inter_measurement_period_ms) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + VL53L1_DevicePresetModes device_preset_mode; + uint8_t measurement_mode; + uint16_t dss_config__target_total_rate_mcps; + uint32_t phasecal_config_timeout_us; + uint32_t mm_config_timeout_us; + uint32_t lld_range_config_timeout_us; + + LOG_FUNCTION_START("%d", (int)PresetMode); + + if ((PresetMode == VL53L1_PRESETMODE_AUTONOMOUS) || + (PresetMode == VL53L1_PRESETMODE_LOWPOWER_AUTONOMOUS)) + measurement_mode = VL53L1_DEVICEMEASUREMENTMODE_TIMED; + else + measurement_mode = VL53L1_DEVICEMEASUREMENTMODE_BACKTOBACK; + + + Status = ComputeDevicePresetMode(PresetMode, DistanceMode, + &device_preset_mode); + + if (Status == VL53L1_ERROR_NONE) + Status = VL53L1_get_preset_mode_timing_cfg(Dev, + device_preset_mode, + &dss_config__target_total_rate_mcps, + &phasecal_config_timeout_us, + &mm_config_timeout_us, + &lld_range_config_timeout_us); + + if (Status == VL53L1_ERROR_NONE) + Status = VL53L1_set_preset_mode( + Dev, + device_preset_mode, + dss_config__target_total_rate_mcps, + phasecal_config_timeout_us, + mm_config_timeout_us, + lld_range_config_timeout_us, + inter_measurement_period_ms); + + if (Status == VL53L1_ERROR_NONE) + VL53L1DevDataSet(Dev, LLData.measurement_mode, + measurement_mode); + + if (Status == VL53L1_ERROR_NONE) + VL53L1DevDataSet(Dev, CurrentParameters.PresetMode, PresetMode); + + VL53L1DevDataSet(Dev, CurrentParameters.OutputMode, + VL53L1_OUTPUTMODE_NEAREST); + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_SetPresetMode(VL53L1_DEV Dev, VL53L1_PresetModes PresetMode) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + VL53L1_DistanceModes DistanceMode = VL53L1_DISTANCEMODE_LONG; + + LOG_FUNCTION_START("%d", (int)PresetMode); + + + + Status = VL53L1_low_power_auto_data_init(Dev); + + if (PresetMode == VL53L1_PRESETMODE_PROXY_RANGING_MODE) + DistanceMode = VL53L1_DISTANCEMODE_SHORT; + Status = SetPresetMode(Dev, + PresetMode, + DistanceMode, + 1000); + + if (Status == VL53L1_ERROR_NONE) { + if ((PresetMode == VL53L1_PRESETMODE_LITE_RANGING) || + (PresetMode == VL53L1_PRESETMODE_AUTONOMOUS) || + (PresetMode == VL53L1_PRESETMODE_LOWPOWER_AUTONOMOUS)) + Status = VL53L1_SetMeasurementTimingBudgetMicroSeconds( + Dev, 41000); + else + + + Status = VL53L1_SetMeasurementTimingBudgetMicroSeconds( + Dev, 33333); + } + + if (Status == VL53L1_ERROR_NONE) { + + + Status = VL53L1_SetInterMeasurementPeriodMilliSeconds(Dev, + 1000); + } + + LOG_FUNCTION_END(Status); + return Status; +} + + +VL53L1_Error VL53L1_GetPresetMode(VL53L1_DEV Dev, + VL53L1_PresetModes *pPresetMode) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + *pPresetMode = VL53L1DevDataGet(Dev, CurrentParameters.PresetMode); + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_SetDistanceMode(VL53L1_DEV Dev, + VL53L1_DistanceModes DistanceMode) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + VL53L1_PresetModes PresetMode; + uint32_t inter_measurement_period_ms; + uint32_t TimingBudget; + uint32_t MmTimeoutUs; + uint32_t PhaseCalTimeoutUs; + VL53L1_zone_config_t zone_config; + + LOG_FUNCTION_START("%d", (int)DistanceMode); + + PresetMode = VL53L1DevDataGet(Dev, CurrentParameters.PresetMode); + + + + + + + + if ((PresetMode == VL53L1_PRESETMODE_PROXY_RANGING_MODE) && + (DistanceMode != VL53L1_DISTANCEMODE_SHORT)) + return VL53L1_ERROR_INVALID_PARAMS; + if ((DistanceMode != VL53L1_DISTANCEMODE_SHORT) && + (DistanceMode != VL53L1_DISTANCEMODE_MEDIUM) && + (DistanceMode != VL53L1_DISTANCEMODE_LONG)) + return VL53L1_ERROR_INVALID_PARAMS; + + if (Status == VL53L1_ERROR_NONE) + Status = VL53L1_get_zone_config(Dev, &zone_config); + + inter_measurement_period_ms = VL53L1DevDataGet(Dev, + LLData.inter_measurement_period_ms); + + if (Status == VL53L1_ERROR_NONE) + Status = VL53L1_get_timeouts_us(Dev, &PhaseCalTimeoutUs, + &MmTimeoutUs, &TimingBudget); + + if (Status == VL53L1_ERROR_NONE) + Status = SetPresetMode(Dev, + PresetMode, + DistanceMode, + inter_measurement_period_ms); + + if (Status == VL53L1_ERROR_NONE) { + VL53L1DevDataSet(Dev, CurrentParameters.DistanceMode, + DistanceMode); + } + + if (Status == VL53L1_ERROR_NONE) { + Status = VL53L1_set_timeouts_us(Dev, PhaseCalTimeoutUs, + MmTimeoutUs, TimingBudget); + + if (Status == VL53L1_ERROR_NONE) + VL53L1DevDataSet(Dev, LLData.range_config_timeout_us, + TimingBudget); + } + + if (Status == VL53L1_ERROR_NONE) + Status = VL53L1_set_zone_config(Dev, &zone_config); + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_GetDistanceMode(VL53L1_DEV Dev, + VL53L1_DistanceModes *pDistanceMode) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + *pDistanceMode = VL53L1DevDataGet(Dev, CurrentParameters.DistanceMode); + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_SetOutputMode(VL53L1_DEV Dev, + VL53L1_OutputModes OutputMode) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if ((OutputMode != VL53L1_OUTPUTMODE_NEAREST) && + (OutputMode != VL53L1_OUTPUTMODE_STRONGEST)) + Status = VL53L1_ERROR_MODE_NOT_SUPPORTED; + else + VL53L1DevDataSet(Dev, CurrentParameters.OutputMode, OutputMode); + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_GetOutputMode(VL53L1_DEV Dev, + VL53L1_OutputModes *pOutputMode) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + *pOutputMode = VL53L1DevDataGet(Dev, CurrentParameters.OutputMode); + + LOG_FUNCTION_END(Status); + return Status; +} + + + +VL53L1_Error VL53L1_SetMeasurementTimingBudgetMicroSeconds(VL53L1_DEV Dev, + uint32_t MeasurementTimingBudgetMicroSeconds) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + uint8_t Mm1Enabled; + uint8_t Mm2Enabled; + uint32_t TimingGuard; + uint32_t divisor; + uint32_t TimingBudget; + uint32_t MmTimeoutUs; + VL53L1_PresetModes PresetMode; + uint32_t PhaseCalTimeoutUs; + uint32_t vhv; + int32_t vhv_loops; + uint32_t FDAMaxTimingBudgetUs = FDA_MAX_TIMING_BUDGET_US; + + LOG_FUNCTION_START(""); + + + + if (MeasurementTimingBudgetMicroSeconds > 10000000) + Status = VL53L1_ERROR_INVALID_PARAMS; + + if (Status == VL53L1_ERROR_NONE) { + Status = VL53L1_GetSequenceStepEnable(Dev, + VL53L1_SEQUENCESTEP_MM1, &Mm1Enabled); + } + + if (Status == VL53L1_ERROR_NONE) { + Status = VL53L1_GetSequenceStepEnable(Dev, + VL53L1_SEQUENCESTEP_MM2, &Mm2Enabled); + } + + if (Status == VL53L1_ERROR_NONE) + Status = VL53L1_get_timeouts_us(Dev, + &PhaseCalTimeoutUs, + &MmTimeoutUs, + &TimingBudget); + + if (Status == VL53L1_ERROR_NONE) { + PresetMode = VL53L1DevDataGet(Dev, + CurrentParameters.PresetMode); + + TimingGuard = 0; + divisor = 1; + switch (PresetMode) { + case VL53L1_PRESETMODE_LITE_RANGING: + if ((Mm1Enabled == 1) || (Mm2Enabled == 1)) + TimingGuard = 5000; + else + TimingGuard = 1000; + break; + + case VL53L1_PRESETMODE_AUTONOMOUS: + FDAMaxTimingBudgetUs *= 2; + if ((Mm1Enabled == 1) || (Mm2Enabled == 1)) + TimingGuard = 26600; + else + TimingGuard = 21600; + divisor = 2; + break; + + case VL53L1_PRESETMODE_LOWPOWER_AUTONOMOUS: + FDAMaxTimingBudgetUs *= 2; + vhv = LOWPOWER_AUTO_VHV_LOOP_DURATION_US; + VL53L1_get_tuning_parm(Dev, + VL53L1_TUNINGPARM_LOWPOWERAUTO_VHV_LOOP_BOUND, + &vhv_loops); + if (vhv_loops > 0) { + vhv += vhv_loops * + LOWPOWER_AUTO_VHV_LOOP_DURATION_US; + } + TimingGuard = LOWPOWER_AUTO_OVERHEAD_BEFORE_A_RANGING + + LOWPOWER_AUTO_OVERHEAD_BETWEEN_A_B_RANGING + + vhv; + divisor = 2; + break; + + case VL53L1_PRESETMODE_RANGING: + case VL53L1_PRESETMODE_MULTIZONES_SCANNING: + case VL53L1_PRESETMODE_PROXY_RANGING_MODE: + TimingGuard = 1700; + divisor = 6; + break; + + case VL53L1_PRESETMODE_OLT: + TimingGuard = MmTimeoutUs + 5000; + break; + default: + + + Status = VL53L1_ERROR_MODE_NOT_SUPPORTED; + } + + if (MeasurementTimingBudgetMicroSeconds <= TimingGuard) + Status = VL53L1_ERROR_INVALID_PARAMS; + else { + TimingBudget = (MeasurementTimingBudgetMicroSeconds + - TimingGuard); + } + + if (Status == VL53L1_ERROR_NONE) { + if (TimingBudget > FDAMaxTimingBudgetUs) + Status = VL53L1_ERROR_INVALID_PARAMS; + else { + TimingBudget /= divisor; + Status = VL53L1_set_timeouts_us( + Dev, + PhaseCalTimeoutUs, + MmTimeoutUs, + TimingBudget); + } + + if (Status == VL53L1_ERROR_NONE) + VL53L1DevDataSet(Dev, + LLData.range_config_timeout_us, + TimingBudget); + } + } + if (Status == VL53L1_ERROR_NONE) { + VL53L1DevDataSet(Dev, + CurrentParameters.MeasurementTimingBudgetMicroSeconds, + MeasurementTimingBudgetMicroSeconds); + } + + LOG_FUNCTION_END(Status); + return Status; +} + + +VL53L1_Error VL53L1_GetMeasurementTimingBudgetMicroSeconds(VL53L1_DEV Dev, + uint32_t *pMeasurementTimingBudgetMicroSeconds) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + uint8_t Mm1Enabled = 0; + uint8_t Mm2Enabled = 0; + uint32_t MmTimeoutUs = 0; + uint32_t RangeTimeoutUs = 0; + uint32_t MeasTimingBdg = 0; + uint32_t PhaseCalTimeoutUs = 0; + VL53L1_PresetModes PresetMode; + uint32_t TimingGuard; + uint32_t vhv; + int32_t vhv_loops; + + LOG_FUNCTION_START(""); + + *pMeasurementTimingBudgetMicroSeconds = 0; + + if (Status == VL53L1_ERROR_NONE) + Status = VL53L1_GetSequenceStepEnable(Dev, + VL53L1_SEQUENCESTEP_MM1, &Mm1Enabled); + + if (Status == VL53L1_ERROR_NONE) + Status = VL53L1_GetSequenceStepEnable(Dev, + VL53L1_SEQUENCESTEP_MM2, &Mm2Enabled); + + if (Status == VL53L1_ERROR_NONE) + Status = VL53L1_get_timeouts_us(Dev, + &PhaseCalTimeoutUs, + &MmTimeoutUs, + &RangeTimeoutUs); + + if (Status == VL53L1_ERROR_NONE) { + PresetMode = VL53L1DevDataGet(Dev, + CurrentParameters.PresetMode); + + switch (PresetMode) { + case VL53L1_PRESETMODE_LITE_RANGING: + if ((Mm1Enabled == 1) || (Mm2Enabled == 1)) + MeasTimingBdg = RangeTimeoutUs + 5000; + else + MeasTimingBdg = RangeTimeoutUs + 1000; + + break; + + case VL53L1_PRESETMODE_AUTONOMOUS: + if ((Mm1Enabled == 1) || (Mm2Enabled == 1)) + MeasTimingBdg = 2 * RangeTimeoutUs + 26600; + else + MeasTimingBdg = 2 * RangeTimeoutUs + 21600; + + break; + + case VL53L1_PRESETMODE_LOWPOWER_AUTONOMOUS: + vhv = LOWPOWER_AUTO_VHV_LOOP_DURATION_US; + VL53L1_get_tuning_parm(Dev, + VL53L1_TUNINGPARM_LOWPOWERAUTO_VHV_LOOP_BOUND, + &vhv_loops); + if (vhv_loops > 0) { + vhv += vhv_loops * + LOWPOWER_AUTO_VHV_LOOP_DURATION_US; + } + TimingGuard = LOWPOWER_AUTO_OVERHEAD_BEFORE_A_RANGING + + LOWPOWER_AUTO_OVERHEAD_BETWEEN_A_B_RANGING + + vhv; + MeasTimingBdg = 2 * RangeTimeoutUs + TimingGuard; + break; + + case VL53L1_PRESETMODE_RANGING: + case VL53L1_PRESETMODE_MULTIZONES_SCANNING: + case VL53L1_PRESETMODE_PROXY_RANGING_MODE: + MeasTimingBdg = (6 * RangeTimeoutUs) + 1700; + break; + + case VL53L1_PRESETMODE_OLT: + MeasTimingBdg = RangeTimeoutUs + MmTimeoutUs + 5000; + break; + default: + + + Status = VL53L1_ERROR_MODE_NOT_SUPPORTED; + } + } + if (Status == VL53L1_ERROR_NONE) + *pMeasurementTimingBudgetMicroSeconds = MeasTimingBdg; + + LOG_FUNCTION_END(Status); + return Status; +} + + + +VL53L1_Error VL53L1_SetInterMeasurementPeriodMilliSeconds(VL53L1_DEV Dev, + uint32_t InterMeasurementPeriodMilliSeconds) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + uint32_t adjustedIMP; + + LOG_FUNCTION_START(""); + + + + adjustedIMP = InterMeasurementPeriodMilliSeconds; + adjustedIMP += (adjustedIMP * 64) / 1000; + + + Status = VL53L1_set_inter_measurement_period_ms(Dev, + adjustedIMP); + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_GetInterMeasurementPeriodMilliSeconds(VL53L1_DEV Dev, + uint32_t *pInterMeasurementPeriodMilliSeconds) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + uint32_t adjustedIMP; + + LOG_FUNCTION_START(""); + + Status = VL53L1_get_inter_measurement_period_ms(Dev, &adjustedIMP); + + + adjustedIMP -= (adjustedIMP * 64) / 1000; + *pInterMeasurementPeriodMilliSeconds = adjustedIMP; + + + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_SetDmaxReflectance(VL53L1_DEV Dev, + FixPoint1616_t DmaxReflectance) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + VL53L1_dmax_reflectance_array_t dmax_reflectances; + + LOG_FUNCTION_START(""); + + if (DmaxReflectance > 100*65536) + Status = VL53L1_ERROR_INVALID_PARAMS; + + if (Status == VL53L1_ERROR_NONE) + Status = VL53L1_get_dmax_reflectance_values(Dev, + &dmax_reflectances); + + if (Status == VL53L1_ERROR_NONE) { + dmax_reflectances.target_reflectance_for_dmax[ + DMAX_REFLECTANCE_IDX] = + VL53L1_FIXPOINT1616TOFIXPOINT72(DmaxReflectance); + Status = VL53L1_set_dmax_reflectance_values(Dev, + &dmax_reflectances); + } + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_GetDmaxReflectance(VL53L1_DEV Dev, + FixPoint1616_t *pDmaxReflectance) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + VL53L1_dmax_reflectance_array_t dmax_reflectances; + uint16_t r; + + LOG_FUNCTION_START(""); + Status = VL53L1_get_dmax_reflectance_values(Dev, &dmax_reflectances); + if (Status == VL53L1_ERROR_NONE) { + r = dmax_reflectances.target_reflectance_for_dmax[ + DMAX_REFLECTANCE_IDX]; + *pDmaxReflectance = VL53L1_FIXPOINT72TOFIXPOINT1616(r); + } + + LOG_FUNCTION_END(Status); + return Status; +} + + +VL53L1_Error VL53L1_SetDmaxMode(VL53L1_DEV Dev, + VL53L1_DeviceDmaxModes DmaxMode) +{ + + VL53L1_Error Status = VL53L1_ERROR_NONE; + VL53L1_DeviceDmaxMode dmax_mode; + + LOG_FUNCTION_START(""); + + switch (DmaxMode) { + case VL53L1_DMAXMODE_FMT_CAL_DATA: + dmax_mode = VL53L1_DEVICEDMAXMODE__FMT_CAL_DATA; + break; + case VL53L1_DMAXMODE_CUSTCAL_DATA: + dmax_mode = VL53L1_DEVICEDMAXMODE__CUST_CAL_DATA; + break; + case VL53L1_DMAXMODE_PER_ZONE_CAL_DATA: + dmax_mode = VL53L1_DEVICEDMAXMODE__PER_ZONE_CAL_DATA; + break; + default: + Status = VL53L1_ERROR_INVALID_PARAMS; + break; + } + if (Status == VL53L1_ERROR_NONE) + Status = VL53L1_set_dmax_mode(Dev, dmax_mode); + + LOG_FUNCTION_END(Status); + return Status; +} + + +VL53L1_Error VL53L1_GetDmaxMode(VL53L1_DEV Dev, + VL53L1_DeviceDmaxModes *pDmaxMode) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + VL53L1_DeviceDmaxMode dmax_mode; + + LOG_FUNCTION_START(""); + + Status = VL53L1_get_dmax_mode(Dev, &dmax_mode); + if (Status == VL53L1_ERROR_NONE) { + switch (dmax_mode) { + case VL53L1_DEVICEDMAXMODE__FMT_CAL_DATA: + *pDmaxMode = VL53L1_DMAXMODE_FMT_CAL_DATA; + break; + case VL53L1_DEVICEDMAXMODE__CUST_CAL_DATA: + *pDmaxMode = VL53L1_DMAXMODE_CUSTCAL_DATA; + break; + case VL53L1_DEVICEDMAXMODE__PER_ZONE_CAL_DATA: + *pDmaxMode = VL53L1_DMAXMODE_PER_ZONE_CAL_DATA; + break; + default: + + + *pDmaxMode = VL53L1_ERROR_NOT_IMPLEMENTED; + break; + } + } + + LOG_FUNCTION_END(Status); + return Status; +} + + + + + + + + +VL53L1_Error VL53L1_GetNumberOfLimitCheck(uint16_t *pNumberOfLimitCheck) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + *pNumberOfLimitCheck = VL53L1_CHECKENABLE_NUMBER_OF_CHECKS; + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_GetLimitCheckInfo(uint16_t LimitCheckId, + char *pLimitCheckString) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + Status = VL53L1_get_limit_check_info(LimitCheckId, + pLimitCheckString); + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_GetLimitCheckStatus(VL53L1_DEV Dev, uint16_t LimitCheckId, + uint8_t *pLimitCheckStatus) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + uint8_t Temp8; + + LOG_FUNCTION_START(""); + + if (LimitCheckId >= VL53L1_CHECKENABLE_NUMBER_OF_CHECKS) { + Status = VL53L1_ERROR_INVALID_PARAMS; + } else { + VL53L1_GETARRAYPARAMETERFIELD(Dev, LimitChecksStatus, + LimitCheckId, Temp8); + *pLimitCheckStatus = Temp8; + } + + LOG_FUNCTION_END(Status); + return Status; +} + +static VL53L1_Error SetLimitValue(VL53L1_DEV Dev, uint16_t LimitCheckId, + FixPoint1616_t value) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + uint16_t tmpuint16; + + + LOG_FUNCTION_START(""); + + switch (LimitCheckId) { + case VL53L1_CHECKENABLE_SIGMA_FINAL_RANGE: + tmpuint16 = VL53L1_FIXPOINT1616TOFIXPOINT142(value); + VL53L1_set_lite_sigma_threshold(Dev, tmpuint16); + break; + case VL53L1_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE: + tmpuint16 = VL53L1_FIXPOINT1616TOFIXPOINT97(value); + VL53L1_set_lite_min_count_rate(Dev, tmpuint16); + break; + default: + Status = VL53L1_ERROR_INVALID_PARAMS; + } + + LOG_FUNCTION_END(Status); + return Status; +} + + +VL53L1_Error VL53L1_SetLimitCheckEnable(VL53L1_DEV Dev, uint16_t LimitCheckId, + uint8_t LimitCheckEnable) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + FixPoint1616_t TempFix1616 = 0; + + LOG_FUNCTION_START(""); + + + if (LimitCheckId >= VL53L1_CHECKENABLE_NUMBER_OF_CHECKS) { + Status = VL53L1_ERROR_INVALID_PARAMS; + } else { + + + if (LimitCheckEnable == 0) + TempFix1616 = 0; + else + VL53L1_GETARRAYPARAMETERFIELD(Dev, LimitChecksValue, + LimitCheckId, TempFix1616); + + Status = SetLimitValue(Dev, LimitCheckId, TempFix1616); + } + + if (Status == VL53L1_ERROR_NONE) + VL53L1_SETARRAYPARAMETERFIELD(Dev, + LimitChecksEnable, + LimitCheckId, + ((LimitCheckEnable == 0) ? 0 : 1)); + + + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_GetLimitCheckEnable(VL53L1_DEV Dev, uint16_t LimitCheckId, + uint8_t *pLimitCheckEnable) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + uint8_t Temp8; + + LOG_FUNCTION_START(""); + + if (LimitCheckId >= VL53L1_CHECKENABLE_NUMBER_OF_CHECKS) { + Status = VL53L1_ERROR_INVALID_PARAMS; + *pLimitCheckEnable = 0; + } else { + VL53L1_GETARRAYPARAMETERFIELD(Dev, LimitChecksEnable, + LimitCheckId, Temp8); + *pLimitCheckEnable = Temp8; + } + + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_SetLimitCheckValue(VL53L1_DEV Dev, uint16_t LimitCheckId, + FixPoint1616_t LimitCheckValue) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + uint8_t LimitChecksEnable; + + LOG_FUNCTION_START(""); + + if (LimitCheckId >= VL53L1_CHECKENABLE_NUMBER_OF_CHECKS) { + Status = VL53L1_ERROR_INVALID_PARAMS; + } else { + + VL53L1_GETARRAYPARAMETERFIELD(Dev, LimitChecksEnable, + LimitCheckId, + LimitChecksEnable); + + if (LimitChecksEnable == 0) { + + + VL53L1_SETARRAYPARAMETERFIELD(Dev, LimitChecksValue, + LimitCheckId, LimitCheckValue); + } else { + + Status = SetLimitValue(Dev, LimitCheckId, + LimitCheckValue); + + if (Status == VL53L1_ERROR_NONE) { + VL53L1_SETARRAYPARAMETERFIELD(Dev, + LimitChecksValue, + LimitCheckId, LimitCheckValue); + } + } + } + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_GetLimitCheckValue(VL53L1_DEV Dev, uint16_t LimitCheckId, + FixPoint1616_t *pLimitCheckValue) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + uint16_t MinCountRate; + FixPoint1616_t TempFix1616; + uint16_t SigmaThresh; + + LOG_FUNCTION_START(""); + + switch (LimitCheckId) { + case VL53L1_CHECKENABLE_SIGMA_FINAL_RANGE: + Status = VL53L1_get_lite_sigma_threshold(Dev, &SigmaThresh); + TempFix1616 = VL53L1_FIXPOINT142TOFIXPOINT1616(SigmaThresh); + break; + case VL53L1_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE: + Status = VL53L1_get_lite_min_count_rate(Dev, &MinCountRate); + TempFix1616 = VL53L1_FIXPOINT97TOFIXPOINT1616(MinCountRate); + break; + default: + Status = VL53L1_ERROR_INVALID_PARAMS; + } + + if (Status == VL53L1_ERROR_NONE) { + + if (TempFix1616 == 0) { + + + VL53L1_GETARRAYPARAMETERFIELD(Dev, + LimitChecksValue, LimitCheckId, + TempFix1616); + *pLimitCheckValue = TempFix1616; + VL53L1_SETARRAYPARAMETERFIELD(Dev, + LimitChecksEnable, LimitCheckId, 0); + } else { + *pLimitCheckValue = TempFix1616; + VL53L1_SETARRAYPARAMETERFIELD(Dev, + LimitChecksValue, LimitCheckId, + TempFix1616); + VL53L1_SETARRAYPARAMETERFIELD(Dev, + LimitChecksEnable, LimitCheckId, 1); + } + } + LOG_FUNCTION_END(Status); + return Status; + +} + +VL53L1_Error VL53L1_GetLimitCheckCurrent(VL53L1_DEV Dev, uint16_t LimitCheckId, + FixPoint1616_t *pLimitCheckCurrent) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + FixPoint1616_t TempFix1616 = 0; + + LOG_FUNCTION_START(""); + + if (LimitCheckId >= VL53L1_CHECKENABLE_NUMBER_OF_CHECKS) { + Status = VL53L1_ERROR_INVALID_PARAMS; + } else { + VL53L1_GETARRAYPARAMETERFIELD(Dev, LimitChecksCurrent, + LimitCheckId, TempFix1616); + *pLimitCheckCurrent = TempFix1616; + } + + LOG_FUNCTION_END(Status); + return Status; + +} + + + + + + + + + + +VL53L1_Error VL53L1_GetMaxNumberOfROI(VL53L1_DEV Dev, + uint8_t *pMaxNumberOfROI) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + VL53L1_PresetModes PresetMode; + + LOG_FUNCTION_START(""); + + PresetMode = VL53L1DevDataGet(Dev, CurrentParameters.PresetMode); + + + + if (PresetMode == VL53L1_PRESETMODE_MULTIZONES_SCANNING) + *pMaxNumberOfROI = VL53L1_MAX_USER_ZONES; + else + *pMaxNumberOfROI = 1; + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_SetROI(VL53L1_DEV Dev, + VL53L1_RoiConfig_t *pRoiConfig) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + VL53L1_PresetModes PresetMode; + uint8_t MaxNumberOfROI = 1; + VL53L1_zone_config_t zone_cfg; + VL53L1_UserRoi_t CurrROI; + uint8_t i; + uint8_t x_centre; + uint8_t y_centre; + uint8_t width, height; + + LOG_FUNCTION_START(""); + + + + PresetMode = VL53L1DevDataGet(Dev, CurrentParameters.PresetMode); + + + + if (PresetMode == VL53L1_PRESETMODE_MULTIZONES_SCANNING) + MaxNumberOfROI = VL53L1_MAX_USER_ZONES; + + if ((pRoiConfig->NumberOfRoi > MaxNumberOfROI) || + (pRoiConfig->NumberOfRoi < 1)) + Status = VL53L1_ERROR_INVALID_PARAMS; + + if (Status == VL53L1_ERROR_NONE) { + + + + zone_cfg.max_zones = MaxNumberOfROI; + zone_cfg.active_zones = pRoiConfig->NumberOfRoi - 1; + + for (i = 0; i < pRoiConfig->NumberOfRoi; i++) { + CurrROI = pRoiConfig->UserRois[i]; + + + + + + + + + + Status = CheckValidRectRoi(CurrROI); + if (Status != VL53L1_ERROR_NONE) + break; + + x_centre = (CurrROI.BotRightX + CurrROI.TopLeftX + 1) + / 2; + y_centre = (CurrROI.TopLeftY + CurrROI.BotRightY + 1) + / 2; + width = (CurrROI.BotRightX - CurrROI.TopLeftX); + height = (CurrROI.TopLeftY - CurrROI.BotRightY); + if ((width < 3) || (height < 3)) { + Status = VL53L1_ERROR_INVALID_PARAMS; + break; + } + zone_cfg.user_zones[i].x_centre = x_centre; + zone_cfg.user_zones[i].y_centre = y_centre; + zone_cfg.user_zones[i].width = width; + zone_cfg.user_zones[i].height = height; + } + } + + if (Status == VL53L1_ERROR_NONE) + Status = VL53L1_set_zone_config(Dev, &zone_cfg); + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_GetROI(VL53L1_DEV Dev, + VL53L1_RoiConfig_t *pRoiConfig) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + VL53L1_zone_config_t zone_cfg; + uint8_t i; + uint8_t TopLeftX; + uint8_t TopLeftY; + uint8_t BotRightX; + uint8_t BotRightY; + + LOG_FUNCTION_START(""); + + VL53L1_get_zone_config(Dev, &zone_cfg); + + pRoiConfig->NumberOfRoi = zone_cfg.active_zones + 1; + + for (i = 0; i < pRoiConfig->NumberOfRoi; i++) { + TopLeftX = (2 * zone_cfg.user_zones[i].x_centre - + zone_cfg.user_zones[i].width) >> 1; + TopLeftY = (2 * zone_cfg.user_zones[i].y_centre + + zone_cfg.user_zones[i].height) >> 1; + BotRightX = (2 * zone_cfg.user_zones[i].x_centre + + zone_cfg.user_zones[i].width) >> 1; + BotRightY = (2 * zone_cfg.user_zones[i].y_centre - + zone_cfg.user_zones[i].height) >> 1; + pRoiConfig->UserRois[i].TopLeftX = TopLeftX; + pRoiConfig->UserRois[i].TopLeftY = TopLeftY; + pRoiConfig->UserRois[i].BotRightX = BotRightX; + pRoiConfig->UserRois[i].BotRightY = BotRightY; + } + + LOG_FUNCTION_END(Status); + return Status; +} + + + + + + + + + +VL53L1_Error VL53L1_GetNumberOfSequenceSteps(VL53L1_DEV Dev, + uint8_t *pNumberOfSequenceSteps) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + SUPPRESS_UNUSED_WARNING(Dev); + + LOG_FUNCTION_START(""); + + *pNumberOfSequenceSteps = VL53L1_SEQUENCESTEP_NUMBER_OF_ITEMS; + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_GetSequenceStepsInfo(VL53L1_SequenceStepId SequenceStepId, + char *pSequenceStepsString) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + Status = VL53L1_get_sequence_steps_info( + SequenceStepId, + pSequenceStepsString); + + LOG_FUNCTION_END(Status); + + return Status; +} + +VL53L1_Error VL53L1_SetSequenceStepEnable(VL53L1_DEV Dev, + VL53L1_SequenceStepId SequenceStepId, uint8_t SequenceStepEnabled) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + uint32_t MeasurementTimingBudgetMicroSeconds; + + LOG_FUNCTION_START(""); + + + + + + + Status = VL53L1_set_sequence_config_bit(Dev, + (VL53L1_DeviceSequenceConfig)SequenceStepId, + SequenceStepEnabled); + + + + if (Status == VL53L1_ERROR_NONE) { + + + + MeasurementTimingBudgetMicroSeconds = VL53L1DevDataGet(Dev, + CurrentParameters.MeasurementTimingBudgetMicroSeconds); + + VL53L1_SetMeasurementTimingBudgetMicroSeconds(Dev, + MeasurementTimingBudgetMicroSeconds); + } + + LOG_FUNCTION_END(Status); + + return Status; +} + + +VL53L1_Error VL53L1_GetSequenceStepEnable(VL53L1_DEV Dev, + VL53L1_SequenceStepId SequenceStepId, uint8_t *pSequenceStepEnabled) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + Status = VL53L1_get_sequence_config_bit(Dev, + (VL53L1_DeviceSequenceConfig)SequenceStepId, + pSequenceStepEnabled); + + LOG_FUNCTION_END(Status); + return Status; +} + + + + + + + + + + + + +VL53L1_Error VL53L1_StartMeasurement(VL53L1_DEV Dev) +{ +#define TIMED_MODE_TIMING_GUARD_MILLISECONDS 4 + VL53L1_Error Status = VL53L1_ERROR_NONE; + uint8_t DeviceMeasurementMode; + VL53L1_State CurrPalState; + VL53L1_Error lStatus; + uint32_t MTBus, IMPms; + + LOG_FUNCTION_START(""); + + //VL53L1_load_patch(Dev); + + CurrPalState = VL53L1DevDataGet(Dev, PalState); + switch (CurrPalState) { + case VL53L1_STATE_IDLE: + Status = VL53L1_ERROR_NONE; + break; + case VL53L1_STATE_POWERDOWN: + case VL53L1_STATE_WAIT_STATICINIT: + case VL53L1_STATE_STANDBY: + case VL53L1_STATE_RUNNING: + case VL53L1_STATE_RESET: + case VL53L1_STATE_UNKNOWN: + case VL53L1_STATE_ERROR: + Status = VL53L1_ERROR_INVALID_COMMAND; + break; + default: + Status = VL53L1_ERROR_UNDEFINED; + } + + DeviceMeasurementMode = VL53L1DevDataGet(Dev, LLData.measurement_mode); + + + + + if ((Status == VL53L1_ERROR_NONE) && + (DeviceMeasurementMode == VL53L1_DEVICEMEASUREMENTMODE_TIMED)) { + lStatus = VL53L1_GetMeasurementTimingBudgetMicroSeconds(Dev, + &MTBus); + + + MTBus /= 1000; + lStatus = VL53L1_GetInterMeasurementPeriodMilliSeconds(Dev, + &IMPms); + + + SUPPRESS_UNUSED_WARNING(lStatus); + if (IMPms < MTBus + TIMED_MODE_TIMING_GUARD_MILLISECONDS) + Status = VL53L1_ERROR_INVALID_PARAMS; + } + + if (Status == VL53L1_ERROR_NONE) + Status = VL53L1_init_and_start_range( + Dev, + DeviceMeasurementMode, + VL53L1_DEVICECONFIGLEVEL_FULL); + + + + if (Status == VL53L1_ERROR_NONE) + VL53L1DevDataSet(Dev, PalState, VL53L1_STATE_RUNNING); + + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_StopMeasurement(VL53L1_DEV Dev) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + Status = VL53L1_stop_range(Dev); + + //VL53L1_unload_patch(Dev); + + + + if (Status == VL53L1_ERROR_NONE) + VL53L1DevDataSet(Dev, PalState, VL53L1_STATE_IDLE); + + LOG_FUNCTION_END(Status); + return Status; +} + + +VL53L1_Error VL53L1_ClearInterruptAndStartMeasurement(VL53L1_DEV Dev) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + uint8_t DeviceMeasurementMode; + + LOG_FUNCTION_START(""); + + DeviceMeasurementMode = VL53L1DevDataGet(Dev, LLData.measurement_mode); + + Status = VL53L1_clear_interrupt_and_enable_next_range(Dev, + DeviceMeasurementMode); + + LOG_FUNCTION_END(Status); + return Status; +} + + +VL53L1_Error VL53L1_GetMeasurementDataReady(VL53L1_DEV Dev, + uint8_t *pMeasurementDataReady) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + Status = VL53L1_is_new_data_ready(Dev, pMeasurementDataReady); + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_WaitMeasurementDataReady(VL53L1_DEV Dev) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + + + Status = VL53L1_poll_for_range_completion(Dev, + VL53L1_RANGE_COMPLETION_POLLING_TIMEOUT_MS); + + LOG_FUNCTION_END(Status); + return Status; +} + +static void GenNewPresetMode(int16_t RefRange, + VL53L1_DistanceModes InternalDistanceMode, + VL53L1_DistanceModes *pNewDistanceMode) +{ + uint16_t HRLI = 600; + uint16_t HRLH = 700; + uint16_t MRLI = 1400; + uint16_t MRLH = 1500; + + switch (InternalDistanceMode) { + case VL53L1_DISTANCEMODE_SHORT: + + + + + + if (RefRange > MRLH) + *pNewDistanceMode = VL53L1_DISTANCEMODE_LONG; + else if (RefRange > HRLH) + *pNewDistanceMode = VL53L1_DISTANCEMODE_MEDIUM; + break; + case VL53L1_DISTANCEMODE_MEDIUM: + + + + + + if (RefRange > MRLH) + *pNewDistanceMode = VL53L1_DISTANCEMODE_LONG; + else if (RefRange < HRLI) + *pNewDistanceMode = VL53L1_DISTANCEMODE_SHORT; + break; + default: + + + + + + + if (RefRange < HRLI) + *pNewDistanceMode = VL53L1_DISTANCEMODE_SHORT; + else if (RefRange < MRLI) + *pNewDistanceMode = VL53L1_DISTANCEMODE_MEDIUM; + break; + } +} + +static void CheckAndChangeDistanceMode(VL53L1_DEV Dev, + VL53L1_TargetRangeData_t *pRangeData, + int16_t Ambient100DmaxMm, + VL53L1_DistanceModes *pNewDistanceMode +) +{ + VL53L1_DistanceModes DistanceMode; + uint8_t RangeStatus = pRangeData->RangeStatus; + uint8_t DmaxValid; + int32_t MinAmbient = BDTable[VL53L1_TUNING_MIN_AMBIENT_DMAX_VALID]; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + int32_t tmpint32; + + + + switch (RangeStatus) { + case VL53L1_RANGESTATUS_RANGE_VALID_NO_WRAP_CHECK_FAIL: + case VL53L1_RANGESTATUS_WRAP_TARGET_FAIL: + case VL53L1_RANGESTATUS_RANGE_VALID_MERGED_PULSE: + case VL53L1_RANGESTATUS_TARGET_PRESENT_LACK_OF_SIGNAL: + case VL53L1_RANGESTATUS_SYNCRONISATION_INT: + case VL53L1_RANGESTATUS_NONE: + return; + default: + + + break; + } + + DmaxValid = 1; + tmpint32 = pdev->hist_data.VL53L1_p_004; + if ((tmpint32 < MinAmbient) || (Ambient100DmaxMm == 0)) + DmaxValid = 0; + + DistanceMode = VL53L1DevDataGet(Dev, + CurrentParameters.DistanceMode); + + *pNewDistanceMode = DistanceMode; + + if (RangeStatus == VL53L1_RANGESTATUS_RANGE_VALID) + GenNewPresetMode(pRangeData->RangeMilliMeter, + DistanceMode, pNewDistanceMode); + else { + if (DmaxValid) + GenNewPresetMode(Ambient100DmaxMm, + DistanceMode, pNewDistanceMode); + else + *pNewDistanceMode = VL53L1_DISTANCEMODE_LONG; + } +} + +static uint8_t ComputeRQL(uint8_t active_results, + uint8_t FilteredRangeStatus, + VL53L1_range_data_t *presults_data) +{ + int16_t T_Wide = 150; + int16_t SRL = 300; + uint16_t SRAS = 30; + FixPoint1616_t RAS; + FixPoint1616_t SRQL; + FixPoint1616_t GI = 7713587; + + FixPoint1616_t GGm = 3198157; + + FixPoint1616_t LRAP = 6554; + + FixPoint1616_t partial; + uint8_t finalvalue; + uint8_t returnvalue; + + if (active_results == 0) + returnvalue = 0; + else if (((presults_data->max_range_mm - + presults_data->min_range_mm) >= T_Wide) || + (FilteredRangeStatus == VL53L1_DEVICEERROR_PHASECONSISTENCY)) + returnvalue = 50; + else { + if (presults_data->median_range_mm < SRL) + RAS = SRAS * 65536; + else + RAS = LRAP * presults_data->median_range_mm; + + + + if (RAS != 0) { + partial = (GGm * presults_data->VL53L1_p_005); + partial = partial + (RAS >> 1); + partial = partial / RAS; + partial = partial * 65536; + if (partial <= GI) + SRQL = GI - partial; + else + SRQL = 50 * 65536; + } else + SRQL = 100 * 65536; + + finalvalue = (uint8_t)(SRQL >> 16); + returnvalue = MAX(50, MIN(100, finalvalue)); + } + + return returnvalue; +} + + +static uint8_t ConvertStatusLite(uint8_t FilteredRangeStatus) +{ + uint8_t RangeStatus; + + switch (FilteredRangeStatus) { + case VL53L1_DEVICEERROR_GPHSTREAMCOUNT0READY: + RangeStatus = VL53L1_RANGESTATUS_SYNCRONISATION_INT; + break; + case VL53L1_DEVICEERROR_RANGECOMPLETE_NO_WRAP_CHECK: + RangeStatus = VL53L1_RANGESTATUS_RANGE_VALID_NO_WRAP_CHECK_FAIL; + break; + case VL53L1_DEVICEERROR_RANGEPHASECHECK: + RangeStatus = VL53L1_RANGESTATUS_OUTOFBOUNDS_FAIL; + break; + case VL53L1_DEVICEERROR_MSRCNOTARGET: + RangeStatus = VL53L1_RANGESTATUS_SIGNAL_FAIL; + break; + case VL53L1_DEVICEERROR_SIGMATHRESHOLDCHECK: + RangeStatus = VL53L1_RANGESTATUS_SIGMA_FAIL; + break; + case VL53L1_DEVICEERROR_PHASECONSISTENCY: + RangeStatus = VL53L1_RANGESTATUS_WRAP_TARGET_FAIL; + break; + case VL53L1_DEVICEERROR_RANGEIGNORETHRESHOLD: + RangeStatus = VL53L1_RANGESTATUS_XTALK_SIGNAL_FAIL; + break; + case VL53L1_DEVICEERROR_MINCLIP: + RangeStatus = VL53L1_RANGESTATUS_RANGE_VALID_MIN_RANGE_CLIPPED; + break; + case VL53L1_DEVICEERROR_RANGECOMPLETE: + RangeStatus = VL53L1_RANGESTATUS_RANGE_VALID; + break; + default: + RangeStatus = VL53L1_RANGESTATUS_NONE; + } + + return RangeStatus; +} + + +static uint8_t ConvertStatusHisto(uint8_t FilteredRangeStatus) +{ + uint8_t RangeStatus; + + switch (FilteredRangeStatus) { + case VL53L1_DEVICEERROR_RANGEPHASECHECK: + RangeStatus = VL53L1_RANGESTATUS_OUTOFBOUNDS_FAIL; + break; + case VL53L1_DEVICEERROR_SIGMATHRESHOLDCHECK: + RangeStatus = VL53L1_RANGESTATUS_SIGMA_FAIL; + break; + case VL53L1_DEVICEERROR_RANGECOMPLETE_NO_WRAP_CHECK: + RangeStatus = VL53L1_RANGESTATUS_RANGE_VALID_NO_WRAP_CHECK_FAIL; + break; + case VL53L1_DEVICEERROR_PHASECONSISTENCY: + RangeStatus = VL53L1_RANGESTATUS_WRAP_TARGET_FAIL; + break; + case VL53L1_DEVICEERROR_PREV_RANGE_NO_TARGETS: + RangeStatus = VL53L1_RANGESTATUS_TARGET_PRESENT_LACK_OF_SIGNAL; + break; + case VL53L1_DEVICEERROR_EVENTCONSISTENCY: + RangeStatus = VL53L1_RANGESTATUS_WRAP_TARGET_FAIL; + break; + case VL53L1_DEVICEERROR_RANGECOMPLETE_MERGED_PULSE: + RangeStatus = VL53L1_RANGESTATUS_RANGE_VALID_MERGED_PULSE; + break; + case VL53L1_DEVICEERROR_RANGECOMPLETE: + RangeStatus = VL53L1_RANGESTATUS_RANGE_VALID; + break; + default: + RangeStatus = VL53L1_RANGESTATUS_NONE; + } + + return RangeStatus; +} + +static VL53L1_Error SetSimpleData(VL53L1_DEV Dev, + uint8_t active_results, uint8_t device_status, + VL53L1_range_data_t *presults_data, + VL53L1_RangingMeasurementData_t *pRangeData) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + uint8_t FilteredRangeStatus; + uint8_t SigmaLimitflag; + uint8_t SignalLimitflag; + uint8_t Temp8Enable; + uint8_t Temp8; + FixPoint1616_t AmbientRate; + FixPoint1616_t SignalRate; + FixPoint1616_t TempFix1616; + FixPoint1616_t LimitCheckValue; + VL53L1_PresetModes PresetMode; + int16_t Range; + + pRangeData->TimeStamp = presults_data->time_stamp; + + FilteredRangeStatus = presults_data->range_status & 0x1F; + + pRangeData->RangeQualityLevel = ComputeRQL(active_results, + FilteredRangeStatus, + presults_data); + + SignalRate = VL53L1_FIXPOINT97TOFIXPOINT1616( + presults_data->peak_signal_count_rate_mcps); + pRangeData->SignalRateRtnMegaCps + = SignalRate; + + AmbientRate = VL53L1_FIXPOINT97TOFIXPOINT1616( + presults_data->ambient_count_rate_mcps); + pRangeData->AmbientRateRtnMegaCps = AmbientRate; + + pRangeData->EffectiveSpadRtnCount = + presults_data->VL53L1_p_006; + + TempFix1616 = VL53L1_FIXPOINT97TOFIXPOINT1616( + presults_data->VL53L1_p_005); + + pRangeData->SigmaMilliMeter = TempFix1616; + + pRangeData->RangeMilliMeter = presults_data->median_range_mm; + + pRangeData->RangeFractionalPart = 0; + + + + switch (device_status) { + case VL53L1_DEVICEERROR_MULTCLIPFAIL: + case VL53L1_DEVICEERROR_VCSELWATCHDOGTESTFAILURE: + case VL53L1_DEVICEERROR_VCSELCONTINUITYTESTFAILURE: + case VL53L1_DEVICEERROR_NOVHVVALUEFOUND: + pRangeData->RangeStatus = VL53L1_RANGESTATUS_HARDWARE_FAIL; + break; + case VL53L1_DEVICEERROR_USERROICLIP: + pRangeData->RangeStatus = VL53L1_RANGESTATUS_MIN_RANGE_FAIL; + break; + default: + pRangeData->RangeStatus = VL53L1_RANGESTATUS_RANGE_VALID; + } + + + + if (pRangeData->RangeStatus == VL53L1_RANGESTATUS_RANGE_VALID) { + PresetMode = VL53L1DevDataGet(Dev, + CurrentParameters.PresetMode); + if ((PresetMode == VL53L1_PRESETMODE_MULTIZONES_SCANNING) || + (PresetMode == VL53L1_PRESETMODE_RANGING) || + (PresetMode == VL53L1_PRESETMODE_PROXY_RANGING_MODE)) + pRangeData->RangeStatus = + ConvertStatusHisto(FilteredRangeStatus); + else + pRangeData->RangeStatus = + ConvertStatusLite(FilteredRangeStatus); + } + + + + TempFix1616 = VL53L1_FIXPOINT97TOFIXPOINT1616( + presults_data->VL53L1_p_005); + VL53L1_SETARRAYPARAMETERFIELD(Dev, + LimitChecksCurrent, VL53L1_CHECKENABLE_SIGMA_FINAL_RANGE, + TempFix1616); + + TempFix1616 = VL53L1_FIXPOINT97TOFIXPOINT1616( + presults_data->peak_signal_count_rate_mcps); + VL53L1_SETARRAYPARAMETERFIELD(Dev, + LimitChecksCurrent, VL53L1_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE, + TempFix1616); + + + + + + VL53L1_GetLimitCheckValue(Dev, + VL53L1_CHECKENABLE_SIGMA_FINAL_RANGE, + &LimitCheckValue); + + SigmaLimitflag = (FilteredRangeStatus == + VL53L1_DEVICEERROR_SIGMATHRESHOLDCHECK) + ? 1 : 0; + + VL53L1_GetLimitCheckEnable(Dev, + VL53L1_CHECKENABLE_SIGMA_FINAL_RANGE, + &Temp8Enable); + + Temp8 = ((Temp8Enable == 1) && (SigmaLimitflag == 1)) ? 1 : 0; + VL53L1_SETARRAYPARAMETERFIELD(Dev, LimitChecksStatus, + VL53L1_CHECKENABLE_SIGMA_FINAL_RANGE, Temp8); + + + + VL53L1_GetLimitCheckValue(Dev, + VL53L1_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE, + &LimitCheckValue); + + SignalLimitflag = (FilteredRangeStatus == + VL53L1_DEVICEERROR_MSRCNOTARGET) + ? 1 : 0; + + VL53L1_GetLimitCheckEnable(Dev, + VL53L1_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE, + &Temp8Enable); + + Temp8 = ((Temp8Enable == 1) && (SignalLimitflag == 1)) ? 1 : 0; + VL53L1_SETARRAYPARAMETERFIELD(Dev, LimitChecksStatus, + VL53L1_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE, Temp8); + + Range = pRangeData->RangeMilliMeter; + if ((pRangeData->RangeStatus == VL53L1_RANGESTATUS_RANGE_VALID) && + (Range < 0)) { + if (Range < BDTable[VL53L1_TUNING_PROXY_MIN]) + pRangeData->RangeStatus = + VL53L1_RANGESTATUS_RANGE_INVALID; + else + pRangeData->RangeMilliMeter = 0; + } + + return Status; +} + +static VL53L1_Error SetTargetData(VL53L1_DEV Dev, + uint8_t active_results, uint8_t device_status, + VL53L1_range_data_t *presults_data, + VL53L1_TargetRangeData_t *pRangeData) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + uint8_t FilteredRangeStatus; + uint8_t SigmaLimitflag; + uint8_t SignalLimitflag; + uint8_t Temp8Enable; + uint8_t Temp8; + FixPoint1616_t AmbientRate; + FixPoint1616_t SignalRate; + FixPoint1616_t TempFix1616; + FixPoint1616_t LimitCheckValue; + VL53L1_PresetModes PresetMode; + int16_t Range; + + FilteredRangeStatus = presults_data->range_status & 0x1F; + + pRangeData->RangeQualityLevel = ComputeRQL(active_results, + FilteredRangeStatus, + presults_data); + + SignalRate = VL53L1_FIXPOINT97TOFIXPOINT1616( + presults_data->peak_signal_count_rate_mcps); + pRangeData->SignalRateRtnMegaCps + = SignalRate; + + AmbientRate = VL53L1_FIXPOINT97TOFIXPOINT1616( + presults_data->ambient_count_rate_mcps); + pRangeData->AmbientRateRtnMegaCps = AmbientRate; + + TempFix1616 = VL53L1_FIXPOINT97TOFIXPOINT1616( + presults_data->VL53L1_p_005); + + pRangeData->SigmaMilliMeter = TempFix1616; + + pRangeData->RangeMilliMeter = presults_data->median_range_mm; + pRangeData->RangeMaxMilliMeter = presults_data->max_range_mm; + pRangeData->RangeMinMilliMeter = presults_data->min_range_mm; + + pRangeData->RangeFractionalPart = 0; + + + + switch (device_status) { + case VL53L1_DEVICEERROR_MULTCLIPFAIL: + case VL53L1_DEVICEERROR_VCSELWATCHDOGTESTFAILURE: + case VL53L1_DEVICEERROR_VCSELCONTINUITYTESTFAILURE: + case VL53L1_DEVICEERROR_NOVHVVALUEFOUND: + pRangeData->RangeStatus = VL53L1_RANGESTATUS_HARDWARE_FAIL; + break; + case VL53L1_DEVICEERROR_USERROICLIP: + pRangeData->RangeStatus = VL53L1_RANGESTATUS_MIN_RANGE_FAIL; + break; + default: + pRangeData->RangeStatus = VL53L1_RANGESTATUS_RANGE_VALID; + } + + if ((pRangeData->RangeStatus == VL53L1_RANGESTATUS_RANGE_VALID) && + (active_results == 0)) { + pRangeData->RangeStatus = VL53L1_RANGESTATUS_NONE; + pRangeData->SignalRateRtnMegaCps = 0; + pRangeData->SigmaMilliMeter = 0; + pRangeData->RangeMilliMeter = 8191; + pRangeData->RangeMaxMilliMeter = 8191; + pRangeData->RangeMinMilliMeter = 8191; + } + + if (pRangeData->RangeStatus == VL53L1_RANGESTATUS_RANGE_VALID) { + PresetMode = VL53L1DevDataGet(Dev, + CurrentParameters.PresetMode); + if ((PresetMode == VL53L1_PRESETMODE_MULTIZONES_SCANNING) || + (PresetMode == VL53L1_PRESETMODE_RANGING) || + (PresetMode == VL53L1_PRESETMODE_PROXY_RANGING_MODE)) + pRangeData->RangeStatus = + ConvertStatusHisto(FilteredRangeStatus); + else + pRangeData->RangeStatus = + ConvertStatusLite(FilteredRangeStatus); + } + + + + TempFix1616 = VL53L1_FIXPOINT97TOFIXPOINT1616( + presults_data->VL53L1_p_005); + VL53L1_SETARRAYPARAMETERFIELD(Dev, + LimitChecksCurrent, VL53L1_CHECKENABLE_SIGMA_FINAL_RANGE, + TempFix1616); + + TempFix1616 = VL53L1_FIXPOINT97TOFIXPOINT1616( + presults_data->peak_signal_count_rate_mcps); + VL53L1_SETARRAYPARAMETERFIELD(Dev, + LimitChecksCurrent, VL53L1_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE, + TempFix1616); + + + + + + VL53L1_GetLimitCheckValue(Dev, + VL53L1_CHECKENABLE_SIGMA_FINAL_RANGE, + &LimitCheckValue); + + SigmaLimitflag = (FilteredRangeStatus == + VL53L1_DEVICEERROR_SIGMATHRESHOLDCHECK) + ? 1 : 0; + + VL53L1_GetLimitCheckEnable(Dev, + VL53L1_CHECKENABLE_SIGMA_FINAL_RANGE, + &Temp8Enable); + + Temp8 = ((Temp8Enable == 1) && (SigmaLimitflag == 1)) ? 1 : 0; + VL53L1_SETARRAYPARAMETERFIELD(Dev, LimitChecksStatus, + VL53L1_CHECKENABLE_SIGMA_FINAL_RANGE, Temp8); + + + + VL53L1_GetLimitCheckValue(Dev, + VL53L1_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE, + &LimitCheckValue); + + SignalLimitflag = (FilteredRangeStatus == + VL53L1_DEVICEERROR_MSRCNOTARGET) + ? 1 : 0; + + VL53L1_GetLimitCheckEnable(Dev, + VL53L1_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE, + &Temp8Enable); + + Temp8 = ((Temp8Enable == 1) && (SignalLimitflag == 1)) ? 1 : 0; + VL53L1_SETARRAYPARAMETERFIELD(Dev, LimitChecksStatus, + VL53L1_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE, Temp8); + + Range = pRangeData->RangeMilliMeter; + if ((pRangeData->RangeStatus == VL53L1_RANGESTATUS_RANGE_VALID) && + (Range < 0)) { + if (Range < BDTable[VL53L1_TUNING_PROXY_MIN]) + pRangeData->RangeStatus = + VL53L1_RANGESTATUS_RANGE_INVALID; + else + pRangeData->RangeMilliMeter = 0; + } + + return Status; +} + +static uint8_t GetOutputDataIndex(VL53L1_DEV Dev, + VL53L1_range_results_t *presults) +{ + uint8_t i; + uint8_t index = 0; + VL53L1_OutputModes OutputMode; + + OutputMode = VL53L1DevDataGet(Dev, CurrentParameters.OutputMode); + + + + + if (OutputMode == VL53L1_OUTPUTMODE_NEAREST) + return 0; + + + + + + for (i = 1; i < presults->active_results; i++) { + if (presults->VL53L1_p_002[i].peak_signal_count_rate_mcps > + presults->VL53L1_p_002[index].peak_signal_count_rate_mcps) + index = i; + } + + return index; +} + +VL53L1_Error VL53L1_GetRangingMeasurementData(VL53L1_DEV Dev, + VL53L1_RangingMeasurementData_t *pRangingMeasurementData) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_range_results_t *presults = + (VL53L1_range_results_t *) pdev->wArea1; + VL53L1_range_data_t *presults_data; + VL53L1_PresetModes PresetMode; + uint8_t index = 0; + + LOG_FUNCTION_START(""); + + + + PresetMode = VL53L1DevDataGet(Dev, CurrentParameters.PresetMode); + + if (PresetMode == VL53L1_PRESETMODE_MULTIZONES_SCANNING) { + Status = VL53L1_ERROR_MODE_NOT_SUPPORTED; + LOG_FUNCTION_END(Status); + return Status; + } + + + + memset(pRangingMeasurementData, 0xFF, + sizeof(VL53L1_RangingMeasurementData_t)); + + + + Status = VL53L1_get_device_results( + Dev, + VL53L1_DEVICERESULTSLEVEL_FULL, + presults); + + if (Status == VL53L1_ERROR_NONE) { + pRangingMeasurementData->StreamCount = presults->stream_count; + + + + + + index = GetOutputDataIndex(Dev, presults); + presults_data = &(presults->VL53L1_p_002[index]); + Status = SetSimpleData(Dev, presults->active_results, + presults->device_status, + presults_data, + pRangingMeasurementData); + } + + LOG_FUNCTION_END(Status); + return Status; +} + +static VL53L1_Error SetMeasurementData(VL53L1_DEV Dev, + VL53L1_range_results_t *presults, + VL53L1_MultiRangingData_t *pMultiRangingData) +{ + uint8_t i; + uint8_t iteration; + VL53L1_TargetRangeData_t *pRangeData; + VL53L1_range_data_t *presults_data; + int16_t dmax_min; + VL53L1_Error Status = VL53L1_ERROR_NONE; + uint8_t Furthest_idx = 0; + int16_t Furthest_range = 0; + uint8_t ActiveResults; + + pMultiRangingData->NumberOfObjectsFound = presults->active_results; + pMultiRangingData->RoiNumber = presults->zone_id; + pMultiRangingData->HasXtalkValueChanged = + presults->smudge_corrector_data.new_xtalk_applied_flag; + dmax_min = MIN(presults->wrap_dmax_mm, + presults->VL53L1_p_007[DMAX_REFLECTANCE_IDX]); + pMultiRangingData->DmaxMilliMeter = dmax_min; + + + + + + pMultiRangingData->TimeStamp = 0; + + pMultiRangingData->StreamCount = presults->stream_count; + + pMultiRangingData->RecommendedDistanceMode = + VL53L1DevDataGet(Dev, CurrentParameters.DistanceMode); + ActiveResults = presults->active_results; + if (ActiveResults < 1) + + + + + iteration = 1; + else + iteration = ActiveResults; + for (i = 0; i < iteration; i++) { + pRangeData = &(pMultiRangingData->RangeData[i]); + + presults_data = &(presults->VL53L1_p_002[i]); + if (Status == VL53L1_ERROR_NONE) + Status = SetTargetData(Dev, ActiveResults, + presults->device_status, + presults_data, + pRangeData); + + pMultiRangingData->EffectiveSpadRtnCount = + presults_data->VL53L1_p_006; + + if ((pRangeData->RangeStatus == VL53L1_RANGESTATUS_RANGE_VALID) + && (pRangeData->RangeMilliMeter > Furthest_range)) { + Furthest_range = pRangeData->RangeMilliMeter; + Furthest_idx = i; + } + + } + + if (Status == VL53L1_ERROR_NONE) { + if (ActiveResults > 0) { + pRangeData = &(pMultiRangingData->RangeData[Furthest_idx]); + CheckAndChangeDistanceMode(Dev, pRangeData, + presults->VL53L1_p_007[VL53L1_MAX_AMBIENT_DMAX_VALUES-1], + &pMultiRangingData->RecommendedDistanceMode); + } + } + + return Status; +} + +VL53L1_Error VL53L1_GetMultiRangingData(VL53L1_DEV Dev, + VL53L1_MultiRangingData_t *pMultiRangingData) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_range_results_t *presults = + (VL53L1_range_results_t *) pdev->wArea1; + + LOG_FUNCTION_START(""); + + + + memset(pMultiRangingData, 0xFF, + sizeof(VL53L1_MultiRangingData_t)); + + + + Status = VL53L1_get_device_results( + Dev, + VL53L1_DEVICERESULTSLEVEL_FULL, + presults); + + + if (Status == VL53L1_ERROR_NONE) { + + switch (presults->rd_device_state) { + case VL53L1_DEVICESTATE_RANGING_GATHER_DATA: + pMultiRangingData->RoiStatus = + VL53L1_ROISTATUS_VALID_NOT_LAST; + break; + case VL53L1_DEVICESTATE_RANGING_OUTPUT_DATA: + pMultiRangingData->RoiStatus = + VL53L1_ROISTATUS_VALID_LAST; + break; + default: + pMultiRangingData->RoiStatus = + VL53L1_ROISTATUS_NOT_VALID; + } + + Status = SetMeasurementData(Dev, + presults, + pMultiRangingData); + + } + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_GetAdditionalData(VL53L1_DEV Dev, + VL53L1_AdditionalData_t *pAdditionalData) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + Status = VL53L1_get_additional_data(Dev, pAdditionalData); + + LOG_FUNCTION_END(Status); + return Status; +} + + + + + + + + +VL53L1_Error VL53L1_SetTuningParameter(VL53L1_DEV Dev, + uint16_t TuningParameterId, int32_t TuningParameterValue) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + if (TuningParameterId == + VL53L1_TUNINGPARM_DYNXTALK_NODETECT_XTALK_OFFSET_KCPS) + return VL53L1_ERROR_INVALID_PARAMS; + + + if (TuningParameterId >= 32768) + Status = VL53L1_set_tuning_parm(Dev, + TuningParameterId, + TuningParameterValue); + else { + if (TuningParameterId < VL53L1_TUNING_MAX_TUNABLE_KEY) + BDTable[TuningParameterId] = TuningParameterValue; + else + Status = VL53L1_ERROR_INVALID_PARAMS; + } + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_GetTuningParameter(VL53L1_DEV Dev, + uint16_t TuningParameterId, int32_t *pTuningParameterValue) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (TuningParameterId >= 32768) + Status = VL53L1_get_tuning_parm(Dev, + TuningParameterId, + pTuningParameterValue); + else { + if (TuningParameterId < VL53L1_TUNING_MAX_TUNABLE_KEY) + *pTuningParameterValue = BDTable[TuningParameterId]; + else + Status = VL53L1_ERROR_INVALID_PARAMS; + } + + LOG_FUNCTION_END(Status); + return Status; +} + + +VL53L1_Error VL53L1_PerformRefSpadManagement(VL53L1_DEV Dev) +{ +#ifdef VL53L1_NOCALIB + VL53L1_Error Status = VL53L1_ERROR_NOT_SUPPORTED; + + SUPPRESS_UNUSED_WARNING(Dev); + + LOG_FUNCTION_START(""); +#else + VL53L1_Error Status = VL53L1_ERROR_NONE; + VL53L1_Error RawStatus; + uint8_t dcrbuffer[24]; + uint8_t *commbuf; + uint8_t numloc[2] = {5, 3}; + VL53L1_LLDriverData_t *pdev; + VL53L1_customer_nvm_managed_t *pc; + VL53L1_PresetModes PresetMode; + + LOG_FUNCTION_START(""); + + pdev = VL53L1DevStructGetLLDriverHandle(Dev); + pc = &pdev->customer; + + if (Status == VL53L1_ERROR_NONE) { + PresetMode = VL53L1DevDataGet(Dev, + CurrentParameters.PresetMode); + Status = VL53L1_run_ref_spad_char(Dev, &RawStatus); + + + + + if (Status == VL53L1_ERROR_NONE) + Status = VL53L1_SetPresetMode(Dev, PresetMode); + } + + if (Status == VL53L1_WARNING_REF_SPAD_CHAR_RATE_TOO_HIGH) { + + + + + Status = VL53L1_read_nvm_raw_data(Dev, + (uint8_t)(0xA0 >> 2), + (uint8_t)(24 >> 2), + dcrbuffer); + + if (Status == VL53L1_ERROR_NONE) + Status = VL53L1_WriteMulti(Dev, + VL53L1_REF_SPAD_MAN__NUM_REQUESTED_REF_SPADS, + numloc, 2); + + if (Status == VL53L1_ERROR_NONE) { + pc->ref_spad_man__num_requested_ref_spads = numloc[0]; + pc->ref_spad_man__ref_location = numloc[1]; + } + + if (Status == VL53L1_ERROR_NONE) + commbuf = &dcrbuffer[16]; + + + + + + + if (Status == VL53L1_ERROR_NONE) + Status = VL53L1_WriteMulti(Dev, + VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_REF_0, + commbuf, 6); + + if (Status == VL53L1_ERROR_NONE) { + pc->global_config__spad_enables_ref_0 = commbuf[0]; + pc->global_config__spad_enables_ref_1 = commbuf[1]; + pc->global_config__spad_enables_ref_2 = commbuf[2]; + pc->global_config__spad_enables_ref_3 = commbuf[3]; + pc->global_config__spad_enables_ref_4 = commbuf[4]; + pc->global_config__spad_enables_ref_5 = commbuf[5]; + } + + + } + +#endif + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_SmudgeCorrectionEnable(VL53L1_DEV Dev, + VL53L1_SmudgeCorrectionModes Mode) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + VL53L1_Error s1 = VL53L1_ERROR_NONE; + VL53L1_Error s2 = VL53L1_ERROR_NONE; + VL53L1_Error s3 = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + switch (Mode) { + case VL53L1_SMUDGE_CORRECTION_NONE: + s1 = VL53L1_dynamic_xtalk_correction_disable(Dev); + s2 = VL53L1_dynamic_xtalk_correction_apply_disable(Dev); + s3 = VL53L1_dynamic_xtalk_correction_single_apply_disable(Dev); + break; + case VL53L1_SMUDGE_CORRECTION_CONTINUOUS: + s1 = VL53L1_dynamic_xtalk_correction_enable(Dev); + s2 = VL53L1_dynamic_xtalk_correction_apply_enable(Dev); + s3 = VL53L1_dynamic_xtalk_correction_single_apply_disable(Dev); + break; + case VL53L1_SMUDGE_CORRECTION_SINGLE: + s1 = VL53L1_dynamic_xtalk_correction_enable(Dev); + s2 = VL53L1_dynamic_xtalk_correction_apply_enable(Dev); + s3 = VL53L1_dynamic_xtalk_correction_single_apply_enable(Dev); + break; + case VL53L1_SMUDGE_CORRECTION_DEBUG: + s1 = VL53L1_dynamic_xtalk_correction_enable(Dev); + s2 = VL53L1_dynamic_xtalk_correction_apply_disable(Dev); + s3 = VL53L1_dynamic_xtalk_correction_single_apply_disable(Dev); + break; + default: + Status = VL53L1_ERROR_INVALID_PARAMS; + break; + } + + if (Status == VL53L1_ERROR_NONE) { + Status = s1; + if (Status == VL53L1_ERROR_NONE) + Status = s2; + if (Status == VL53L1_ERROR_NONE) + Status = s3; + } + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_SetXTalkCompensationEnable(VL53L1_DEV Dev, + uint8_t XTalkCompensationEnable) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (XTalkCompensationEnable == 0) + Status = VL53L1_disable_xtalk_compensation(Dev); + else + Status = VL53L1_enable_xtalk_compensation(Dev); + + LOG_FUNCTION_END(Status); + return Status; +} + + +VL53L1_Error VL53L1_GetXTalkCompensationEnable(VL53L1_DEV Dev, + uint8_t *pXTalkCompensationEnable) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + VL53L1_get_xtalk_compensation_enable( + Dev, + pXTalkCompensationEnable); + + LOG_FUNCTION_END(Status); + return Status; +} + + +VL53L1_Error VL53L1_PerformXTalkCalibration(VL53L1_DEV Dev, + uint8_t CalibrationOption) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + VL53L1_Error UStatus; + int16_t CalDistanceMm; + VL53L1_xtalk_calibration_results_t xtalk; + + + VL53L1_CalibrationData_t caldata; + VL53L1_LLDriverData_t *pLLData; + int i; + uint32_t *pPlaneOffsetKcps; + uint32_t HugePlaneOffsetKcps = + BDTable[VL53L1_TUNING_XTALK_FULL_ROI_MAX_THRESHOLD]; + uint32_t Margin = + BDTable[VL53L1_TUNING_XTALK_FULL_ROI_BIN_SUM_MARGIN]; + uint32_t DefaultOffset = + BDTable[VL53L1_TUNING_XTALK_FULL_ROI_DEFAULT_OFFSET]; + uint32_t *pLLDataPlaneOffsetKcps; + uint32_t sum = 0; + uint8_t binok = 0; + int32_t merge; + + + LOG_FUNCTION_START(""); + + pPlaneOffsetKcps = + &caldata.customer.algo__crosstalk_compensation_plane_offset_kcps; + pLLData = VL53L1DevStructGetLLDriverHandle(Dev); + pLLDataPlaneOffsetKcps = + &pLLData->xtalk_cal.algo__crosstalk_compensation_plane_offset_kcps; + VL53L1_get_tuning_parm(Dev, VL53L1_TUNINGPARM_HIST_MERGE, &merge); + + + VL53L1_set_tuning_parm(Dev, VL53L1_TUNINGPARM_HIST_MERGE, 0); + switch (CalibrationOption) { + case VL53L1_XTALKCALIBRATIONMODE_NO_TARGET: + Status = VL53L1_run_xtalk_extraction(Dev, &UStatus); + + + if (Status == VL53L1_ERROR_XTALK_EXTRACTION_NO_SAMPLE_FAIL) + VL53L1_xtalk_cal_data_init(Dev); + break; + case VL53L1_XTALKCALIBRATIONMODE_SINGLE_TARGET: + Status = SingleTargetXTalkCalibration(Dev); + break; + case VL53L1_XTALKCALIBRATIONMODE_FULL_ROI: + CalDistanceMm = (int16_t) + BDTable[VL53L1_TUNING_XTALK_FULL_ROI_TARGET_DISTANCE_MM]; + + + VL53L1_set_tuning_parm(Dev, VL53L1_TUNINGPARM_HIST_MERGE, merge); + Status = VL53L1_run_hist_xtalk_extraction(Dev, CalDistanceMm, + &UStatus); + + + VL53L1_GetCalibrationData(Dev, &caldata); + for (i = 0; i < VL53L1_XTALK_HISTO_BINS; i++) { + sum += caldata.xtalkhisto.xtalk_shape.bin_data[i]; + if (caldata.xtalkhisto.xtalk_shape.bin_data[i] > 0) + binok++; + } + if ((UStatus == VL53L1_ERROR_XTALK_EXTRACTION_SIGMA_LIMIT_FAIL) + || (*pPlaneOffsetKcps > HugePlaneOffsetKcps) || + (sum > (1024 + Margin)) || (sum < (1024 - Margin)) || + (binok < 3)) { + *pPlaneOffsetKcps = DefaultOffset; + *pLLDataPlaneOffsetKcps = DefaultOffset; + caldata.xtalkhisto.xtalk_shape.bin_data[0] = 307; + caldata.xtalkhisto.xtalk_shape.bin_data[1] = 410; + caldata.xtalkhisto.xtalk_shape.bin_data[2] = 410; + caldata.xtalkhisto.xtalk_shape.bin_data[3] = 307; + for (i = 4; i < VL53L1_XTALK_HISTO_BINS; i++) + caldata.xtalkhisto.xtalk_shape.bin_data[i] = 0; + for (i = 0; i < VL53L1_BIN_REC_SIZE; i++) + caldata.algo__xtalk_cpo_HistoMerge_kcps[i] = + DefaultOffset + DefaultOffset * i; + VL53L1_SetCalibrationData(Dev, &caldata); + } + + + break; + default: + Status = VL53L1_ERROR_INVALID_PARAMS; + } + VL53L1_set_tuning_parm(Dev, VL53L1_TUNINGPARM_HIST_MERGE, merge); + + + if (Status == VL53L1_ERROR_NONE) { + Status = VL53L1_get_current_xtalk_settings(Dev, &xtalk); + Status = VL53L1_set_tuning_parm(Dev, + VL53L1_TUNINGPARM_DYNXTALK_NODETECT_XTALK_OFFSET_KCPS, + xtalk.algo__crosstalk_compensation_plane_offset_kcps); + } + + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_SetOffsetCalibrationMode(VL53L1_DEV Dev, + VL53L1_OffsetCalibrationModes OffsetCalibrationMode) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + VL53L1_OffsetCalibrationMode offset_cal_mode; + + LOG_FUNCTION_START(""); + + if (OffsetCalibrationMode == VL53L1_OFFSETCALIBRATIONMODE_STANDARD) { + offset_cal_mode = + VL53L1_OFFSETCALIBRATIONMODE__MM1_MM2__STANDARD; + } else if (OffsetCalibrationMode == + VL53L1_OFFSETCALIBRATIONMODE_PRERANGE_ONLY) { + offset_cal_mode = + VL53L1_OFFSETCALIBRATIONMODE__MM1_MM2__STANDARD_PRE_RANGE_ONLY; + } else if (OffsetCalibrationMode == + VL53L1_OFFSETCALIBRATIONMODE_MULTI_ZONE) { + offset_cal_mode = + VL53L1_OFFSETCALIBRATIONMODE__PER_ZONE; + } else { + Status = VL53L1_ERROR_INVALID_PARAMS; + } + + if (Status == VL53L1_ERROR_NONE) + Status = VL53L1_set_offset_calibration_mode(Dev, + offset_cal_mode); + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_SetOffsetCorrectionMode(VL53L1_DEV Dev, + VL53L1_OffsetCorrectionModes OffsetCorrectionMode) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + VL53L1_OffsetCorrectionMode offset_cor_mode; + + LOG_FUNCTION_START(""); + + if (OffsetCorrectionMode == VL53L1_OFFSETCORRECTIONMODE_STANDARD) { + offset_cor_mode = + VL53L1_OFFSETCORRECTIONMODE__MM1_MM2_OFFSETS; + } else if (OffsetCorrectionMode == + VL53L1_OFFSETCORRECTIONMODE_PERZONE) { + offset_cor_mode = + VL53L1_OFFSETCORRECTIONMODE__PER_ZONE_OFFSETS; + } else if (OffsetCorrectionMode == + VL53L1_OFFSETCORRECTIONMODE_PERVCSEL) { + offset_cor_mode = + VL53L1_OFFSETCORRECTIONMODE__PER_VCSEL_OFFSETS; + } else { + Status = VL53L1_ERROR_INVALID_PARAMS; + } + + if (Status == VL53L1_ERROR_NONE) + Status = VL53L1_set_offset_correction_mode(Dev, + offset_cor_mode); + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_PerformOffsetCalibration(VL53L1_DEV Dev, + int32_t CalDistanceMilliMeter, FixPoint1616_t CalReflectancePercent) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + VL53L1_Error UnfilteredStatus; + VL53L1_OffsetCalibrationMode offset_cal_mode; + uint16_t CalReflectancePercent_int; + + + VL53L1_DevicePresetModes device_preset_mode; + VL53L1_DeviceZonePreset zone_preset; + VL53L1_zone_config_t zone_cfg; + + LOG_FUNCTION_START(""); + + CalReflectancePercent_int = + VL53L1_FIXPOINT1616TOFIXPOINT72(CalReflectancePercent); + + if (Status == VL53L1_ERROR_NONE) + Status = VL53L1_get_offset_calibration_mode(Dev, + &offset_cal_mode); + + if (Status != VL53L1_ERROR_NONE) { + LOG_FUNCTION_END(Status); + return Status; + } + + + if ((offset_cal_mode == + VL53L1_OFFSETCALIBRATIONMODE__MM1_MM2__STANDARD) || + (offset_cal_mode == + VL53L1_OFFSETCALIBRATIONMODE__MM1_MM2__STANDARD_PRE_RANGE_ONLY + )) { + if (Status == VL53L1_ERROR_NONE) + Status = VL53L1_run_offset_calibration( + Dev, + (int16_t)CalDistanceMilliMeter, + CalReflectancePercent_int, + &UnfilteredStatus); + + } else if (offset_cal_mode == + VL53L1_OFFSETCALIBRATIONMODE__PER_ZONE) { + device_preset_mode = + VL53L1_DEVICEPRESETMODE_HISTOGRAM_MULTIZONE_LONG_RANGE; + zone_preset = VL53L1_DEVICEZONEPRESET_CUSTOM; + + Status = VL53L1_get_zone_config(Dev, &zone_cfg); + if (Status == VL53L1_ERROR_NONE) + Status = VL53L1_run_zone_calibration( + Dev, + device_preset_mode, + zone_preset, + &zone_cfg, + (int16_t)CalDistanceMilliMeter, + CalReflectancePercent_int, + &UnfilteredStatus); + + } else { + Status = VL53L1_ERROR_INVALID_PARAMS; + } + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_PerformOffsetSimpleCalibration(VL53L1_DEV Dev, + int32_t CalDistanceMilliMeter) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + int32_t sum_ranging; + uint8_t offset_meas; + int16_t Max, UnderMax, OverMax, Repeat; + int32_t total_count, inloopcount; + int32_t IncRounding; + int16_t meanDistance_mm; + int16_t offset; + VL53L1_RangingMeasurementData_t RangingMeasurementData; + VL53L1_LLDriverData_t *pdev; + uint8_t goodmeas; + VL53L1_Error SmudgeStatus = VL53L1_ERROR_NONE; + uint8_t smudge_corr_en; + + LOG_FUNCTION_START(""); + + pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + + smudge_corr_en = pdev->smudge_correct_config.smudge_corr_enabled; + SmudgeStatus = VL53L1_dynamic_xtalk_correction_disable(Dev); + + + pdev->customer.algo__part_to_part_range_offset_mm = 0; + pdev->customer.mm_config__inner_offset_mm = 0; + pdev->customer.mm_config__outer_offset_mm = 0; + memset(&pdev->per_vcsel_cal_data, 0, sizeof(pdev->per_vcsel_cal_data)); + Repeat = BDTable[VL53L1_TUNING_SIMPLE_OFFSET_CALIBRATION_REPEAT]; + Max = BDTable[ + VL53L1_TUNING_MAX_SIMPLE_OFFSET_CALIBRATION_SAMPLE_NUMBER]; + UnderMax = 1 + (Max / 2); + OverMax = Max + (Max / 2); + sum_ranging = 0; + total_count = 0; + + while ((Repeat > 0) && (Status == VL53L1_ERROR_NONE)) { + Status = VL53L1_StartMeasurement(Dev); + + + if (Status == VL53L1_ERROR_NONE) { + VL53L1_WaitMeasurementDataReady(Dev); + VL53L1_GetRangingMeasurementData(Dev, &RangingMeasurementData); + VL53L1_ClearInterruptAndStartMeasurement(Dev); + } + + + inloopcount = 0; + offset_meas = 0; + while ((Status == VL53L1_ERROR_NONE) && (inloopcount < Max) && + (offset_meas < OverMax)) { + Status = VL53L1_WaitMeasurementDataReady(Dev); + if (Status == VL53L1_ERROR_NONE) + Status = VL53L1_GetRangingMeasurementData(Dev, + &RangingMeasurementData); + goodmeas = (RangingMeasurementData.RangeStatus == + VL53L1_RANGESTATUS_RANGE_VALID); + if ((Status == VL53L1_ERROR_NONE) && goodmeas) { + sum_ranging = sum_ranging + + RangingMeasurementData.RangeMilliMeter; + inloopcount++; + } + Status = VL53L1_ClearInterruptAndStartMeasurement(Dev); + offset_meas++; + } + total_count += inloopcount; + + + + if (inloopcount < UnderMax) + Status = VL53L1_ERROR_OFFSET_CAL_NO_SAMPLE_FAIL; + + VL53L1_StopMeasurement(Dev); + + Repeat--; + + } + + + if ((SmudgeStatus == VL53L1_ERROR_NONE) && (smudge_corr_en == 1)) + SmudgeStatus = VL53L1_dynamic_xtalk_correction_enable(Dev); + + + if ((sum_ranging < 0) || + (sum_ranging > ((int32_t) total_count * 0xffff))) + Status = VL53L1_WARNING_OFFSET_CAL_SIGMA_TOO_HIGH; + + if ((Status == VL53L1_ERROR_NONE) && (total_count > 0)) { + IncRounding = total_count / 2; + meanDistance_mm = (int16_t)((sum_ranging + IncRounding) + / total_count); + offset = (int16_t)CalDistanceMilliMeter - meanDistance_mm; + pdev->customer.algo__part_to_part_range_offset_mm = 0; + pdev->customer.mm_config__inner_offset_mm = offset; + pdev->customer.mm_config__outer_offset_mm = offset; + + Status = VL53L1_set_customer_nvm_managed(Dev, + &(pdev->customer)); + } + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_PerformOffsetZeroDistanceCalibration(VL53L1_DEV Dev) + { + #define START_OFFSET 50 + VL53L1_Error Status = VL53L1_ERROR_NONE; + int32_t sum_ranging; + uint8_t offset_meas; + int16_t Max, UnderMax, OverMax, Repeat; + int32_t total_count, inloopcount; + int32_t IncRounding; + int16_t meanDistance_mm; + int16_t offset, ZeroDistanceOffset; + VL53L1_RangingMeasurementData_t RangingMeasurementData; + VL53L1_LLDriverData_t *pdev; + uint8_t goodmeas; + VL53L1_Error SmudgeStatus = VL53L1_ERROR_NONE; + uint8_t smudge_corr_en; + + LOG_FUNCTION_START(""); + + pdev = VL53L1DevStructGetLLDriverHandle(Dev); + smudge_corr_en = pdev->smudge_correct_config.smudge_corr_enabled; + SmudgeStatus = VL53L1_dynamic_xtalk_correction_disable(Dev); + pdev->customer.algo__part_to_part_range_offset_mm = 0; + pdev->customer.mm_config__inner_offset_mm = START_OFFSET; + pdev->customer.mm_config__outer_offset_mm = START_OFFSET; + memset(&pdev->per_vcsel_cal_data, 0, sizeof(pdev->per_vcsel_cal_data)); + ZeroDistanceOffset = BDTable[ + VL53L1_TUNING_ZERO_DISTANCE_OFFSET_NON_LINEAR_FACTOR]; + Repeat = BDTable[VL53L1_TUNING_SIMPLE_OFFSET_CALIBRATION_REPEAT]; + Max = BDTable[VL53L1_TUNING_MAX_SIMPLE_OFFSET_CALIBRATION_SAMPLE_NUMBER]; + UnderMax = 1 + (Max / 2); + OverMax = Max + (Max / 2); + sum_ranging = 0; + total_count = 0; + + while ((Repeat > 0) && (Status == VL53L1_ERROR_NONE)) { + Status = VL53L1_StartMeasurement(Dev); + if (Status == VL53L1_ERROR_NONE) { + VL53L1_WaitMeasurementDataReady(Dev); + VL53L1_GetRangingMeasurementData(Dev, &RangingMeasurementData); + VL53L1_ClearInterruptAndStartMeasurement(Dev); + } + inloopcount = 0; + offset_meas = 0; + while ((Status == VL53L1_ERROR_NONE) && (inloopcount < Max) && + (offset_meas < OverMax)) { + Status = VL53L1_WaitMeasurementDataReady(Dev); + if (Status == VL53L1_ERROR_NONE) + Status = VL53L1_GetRangingMeasurementData(Dev, + &RangingMeasurementData); + goodmeas = (RangingMeasurementData.RangeStatus == + VL53L1_RANGESTATUS_RANGE_VALID); + if ((Status == VL53L1_ERROR_NONE) && goodmeas) { + sum_ranging = sum_ranging + + RangingMeasurementData.RangeMilliMeter; + inloopcount++; + } + Status = VL53L1_ClearInterruptAndStartMeasurement(Dev); + offset_meas++; + } + total_count += inloopcount; + if (inloopcount < UnderMax) + Status = VL53L1_ERROR_OFFSET_CAL_NO_SAMPLE_FAIL; + VL53L1_StopMeasurement(Dev); + Repeat--; + } + if ((SmudgeStatus == VL53L1_ERROR_NONE) && (smudge_corr_en == 1)) + SmudgeStatus = VL53L1_dynamic_xtalk_correction_enable(Dev); + if ((sum_ranging < 0) || + (sum_ranging > ((int32_t) total_count * 0xffff))) + Status = VL53L1_WARNING_OFFSET_CAL_SIGMA_TOO_HIGH; + + if ((Status == VL53L1_ERROR_NONE) && (total_count > 0)) { + IncRounding = total_count / 2; + meanDistance_mm = (int16_t)((sum_ranging + IncRounding) / total_count); + offset = START_OFFSET - meanDistance_mm + ZeroDistanceOffset; + pdev->customer.algo__part_to_part_range_offset_mm = 0; + pdev->customer.mm_config__inner_offset_mm = offset; + pdev->customer.mm_config__outer_offset_mm = offset; + Status = VL53L1_set_customer_nvm_managed(Dev, &(pdev->customer)); + } + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_SetCalibrationData(VL53L1_DEV Dev, + VL53L1_CalibrationData_t *pCalibrationData) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + VL53L1_CustomerNvmManaged_t *pC; + VL53L1_calibration_data_t cal_data; + uint32_t x; + VL53L1_xtalk_calibration_results_t xtalk; + + LOG_FUNCTION_START(""); + + cal_data.struct_version = pCalibrationData->struct_version - + VL53L1_ADDITIONAL_CALIBRATION_DATA_STRUCT_VERSION; + + + + + + + memcpy( + &(cal_data.fmt_dmax_cal), + &(pCalibrationData->fmt_dmax_cal), + sizeof(VL53L1_dmax_calibration_data_t)); + + + + memcpy( + &(cal_data.cust_dmax_cal), + &(pCalibrationData->cust_dmax_cal), + sizeof(VL53L1_dmax_calibration_data_t)); + + + + + memcpy( + &(cal_data.add_off_cal_data), + &(pCalibrationData->add_off_cal_data), + sizeof(VL53L1_additional_offset_cal_data_t)); + + + + memcpy( + &(cal_data.optical_centre), + &(pCalibrationData->optical_centre), + sizeof(VL53L1_optical_centre_t)); + + + + memcpy( + &(cal_data.xtalkhisto), + &(pCalibrationData->xtalkhisto), + sizeof(VL53L1_xtalk_histogram_data_t)); + + + + memcpy( + &(cal_data.gain_cal), + &(pCalibrationData->gain_cal), + sizeof(VL53L1_gain_calibration_data_t)); + + + + memcpy( + &(cal_data.cal_peak_rate_map), + &(pCalibrationData->cal_peak_rate_map), + sizeof(VL53L1_cal_peak_rate_map_t)); + + + + memcpy( + &(cal_data.per_vcsel_cal_data), + &(pCalibrationData->per_vcsel_cal_data), + sizeof(VL53L1_per_vcsel_period_offset_cal_data_t)); + + pC = &pCalibrationData->customer; + x = pC->algo__crosstalk_compensation_plane_offset_kcps; + cal_data.customer.algo__crosstalk_compensation_plane_offset_kcps = + (uint16_t)(x&0x0000FFFF); + + cal_data.customer.global_config__spad_enables_ref_0 = + pC->global_config__spad_enables_ref_0; + cal_data.customer.global_config__spad_enables_ref_1 = + pC->global_config__spad_enables_ref_1; + cal_data.customer.global_config__spad_enables_ref_2 = + pC->global_config__spad_enables_ref_2; + cal_data.customer.global_config__spad_enables_ref_3 = + pC->global_config__spad_enables_ref_3; + cal_data.customer.global_config__spad_enables_ref_4 = + pC->global_config__spad_enables_ref_4; + cal_data.customer.global_config__spad_enables_ref_5 = + pC->global_config__spad_enables_ref_5; + cal_data.customer.global_config__ref_en_start_select = + pC->global_config__ref_en_start_select; + cal_data.customer.ref_spad_man__num_requested_ref_spads = + pC->ref_spad_man__num_requested_ref_spads; + cal_data.customer.ref_spad_man__ref_location = + pC->ref_spad_man__ref_location; + cal_data.customer.algo__crosstalk_compensation_x_plane_gradient_kcps = + pC->algo__crosstalk_compensation_x_plane_gradient_kcps; + cal_data.customer.algo__crosstalk_compensation_y_plane_gradient_kcps = + pC->algo__crosstalk_compensation_y_plane_gradient_kcps; + cal_data.customer.ref_spad_char__total_rate_target_mcps = + pC->ref_spad_char__total_rate_target_mcps; + cal_data.customer.algo__part_to_part_range_offset_mm = + pC->algo__part_to_part_range_offset_mm; + cal_data.customer.mm_config__inner_offset_mm = + pC->mm_config__inner_offset_mm; + cal_data.customer.mm_config__outer_offset_mm = + pC->mm_config__outer_offset_mm; + + Status = VL53L1_set_part_to_part_data(Dev, &cal_data); + if (Status != VL53L1_ERROR_NONE) + goto ENDFUNC; + + Status = VL53L1_get_current_xtalk_settings(Dev, &xtalk); + + if (Status != VL53L1_ERROR_NONE) + goto ENDFUNC; + + xtalk.algo__crosstalk_compensation_plane_offset_kcps = x; + + + Status = VL53L1_set_tuning_parm(Dev, + VL53L1_TUNINGPARM_DYNXTALK_NODETECT_XTALK_OFFSET_KCPS, + x); + + + + memcpy( + &(xtalk.algo__xtalk_cpo_HistoMerge_kcps[0]), + &(pCalibrationData->algo__xtalk_cpo_HistoMerge_kcps[0]), + sizeof(pCalibrationData->algo__xtalk_cpo_HistoMerge_kcps)); + + Status = VL53L1_set_current_xtalk_settings(Dev, &xtalk); + +ENDFUNC: + LOG_FUNCTION_END(Status); + return Status; + +} + +VL53L1_Error VL53L1_GetCalibrationData(VL53L1_DEV Dev, + VL53L1_CalibrationData_t *pCalibrationData) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + VL53L1_calibration_data_t cal_data; + VL53L1_CustomerNvmManaged_t *pC; + VL53L1_customer_nvm_managed_t *pC2; + VL53L1_xtalk_calibration_results_t xtalk; + uint32_t tmp; + VL53L1_PresetModes PresetMode; + + LOG_FUNCTION_START(""); + + + + Status = VL53L1_get_part_to_part_data(Dev, &cal_data); + + pCalibrationData->struct_version = cal_data.struct_version + + VL53L1_ADDITIONAL_CALIBRATION_DATA_STRUCT_VERSION; + + + + memcpy( + &(pCalibrationData->fmt_dmax_cal), + &(cal_data.fmt_dmax_cal), + sizeof(VL53L1_dmax_calibration_data_t)); + + + + memcpy( + &(pCalibrationData->cust_dmax_cal), + &(cal_data.cust_dmax_cal), + sizeof(VL53L1_dmax_calibration_data_t)); + + + + memcpy( + &(pCalibrationData->add_off_cal_data), + &(cal_data.add_off_cal_data), + sizeof(VL53L1_additional_offset_cal_data_t)); + + + + memcpy( + &(pCalibrationData->optical_centre), + &(cal_data.optical_centre), + sizeof(VL53L1_optical_centre_t)); + + + + memcpy( + &(pCalibrationData->xtalkhisto), + &(cal_data.xtalkhisto), + sizeof(VL53L1_xtalk_histogram_data_t)); + + + memcpy( + &(pCalibrationData->gain_cal), + &(cal_data.gain_cal), + sizeof(VL53L1_gain_calibration_data_t)); + + + + memcpy( + &(pCalibrationData->cal_peak_rate_map), + &(cal_data.cal_peak_rate_map), + sizeof(VL53L1_cal_peak_rate_map_t)); + + + + memcpy( + &(pCalibrationData->per_vcsel_cal_data), + &(cal_data.per_vcsel_cal_data), + sizeof(VL53L1_per_vcsel_period_offset_cal_data_t)); + + pC = &pCalibrationData->customer; + pC2 = &cal_data.customer; + pC->global_config__spad_enables_ref_0 = + pC2->global_config__spad_enables_ref_0; + pC->global_config__spad_enables_ref_1 = + pC2->global_config__spad_enables_ref_1; + pC->global_config__spad_enables_ref_2 = + pC2->global_config__spad_enables_ref_2; + pC->global_config__spad_enables_ref_3 = + pC2->global_config__spad_enables_ref_3; + pC->global_config__spad_enables_ref_4 = + pC2->global_config__spad_enables_ref_4; + pC->global_config__spad_enables_ref_5 = + pC2->global_config__spad_enables_ref_5; + pC->global_config__ref_en_start_select = + pC2->global_config__ref_en_start_select; + pC->ref_spad_man__num_requested_ref_spads = + pC2->ref_spad_man__num_requested_ref_spads; + pC->ref_spad_man__ref_location = + pC2->ref_spad_man__ref_location; + pC->algo__crosstalk_compensation_x_plane_gradient_kcps = + pC2->algo__crosstalk_compensation_x_plane_gradient_kcps; + pC->algo__crosstalk_compensation_y_plane_gradient_kcps = + pC2->algo__crosstalk_compensation_y_plane_gradient_kcps; + pC->ref_spad_char__total_rate_target_mcps = + pC2->ref_spad_char__total_rate_target_mcps; + pC->algo__part_to_part_range_offset_mm = + pC2->algo__part_to_part_range_offset_mm; + pC->mm_config__inner_offset_mm = + pC2->mm_config__inner_offset_mm; + pC->mm_config__outer_offset_mm = + pC2->mm_config__outer_offset_mm; + + pC->algo__crosstalk_compensation_plane_offset_kcps = + (uint32_t)( + pC2->algo__crosstalk_compensation_plane_offset_kcps); + + + PresetMode = VL53L1DevDataGet(Dev, CurrentParameters.PresetMode); + + if ((PresetMode == VL53L1_PRESETMODE_RANGING) || + (PresetMode == VL53L1_PRESETMODE_MULTIZONES_SCANNING) || + (PresetMode == VL53L1_PRESETMODE_PROXY_RANGING_MODE) + ) { + + Status = VL53L1_get_current_xtalk_settings(Dev, &xtalk); + + if (Status != VL53L1_ERROR_NONE) + goto ENDFUNC; + + tmp = xtalk.algo__crosstalk_compensation_plane_offset_kcps; + pC->algo__crosstalk_compensation_plane_offset_kcps = tmp; + tmp = xtalk.algo__crosstalk_compensation_x_plane_gradient_kcps; + pC->algo__crosstalk_compensation_x_plane_gradient_kcps = tmp; + tmp = xtalk.algo__crosstalk_compensation_y_plane_gradient_kcps; + pC->algo__crosstalk_compensation_y_plane_gradient_kcps = tmp; + + memcpy(&(pCalibrationData->algo__xtalk_cpo_HistoMerge_kcps[0]), + &(xtalk.algo__xtalk_cpo_HistoMerge_kcps[0]), + sizeof(pCalibrationData->algo__xtalk_cpo_HistoMerge_kcps)); + } +ENDFUNC: + LOG_FUNCTION_END(Status); + return Status; +} + + +VL53L1_Error VL53L1_SetZoneCalibrationData(VL53L1_DEV Dev, + VL53L1_ZoneCalibrationData_t *pZoneCalibrationData) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + Status = VL53L1_set_zone_calibration_data(Dev, pZoneCalibrationData); + + LOG_FUNCTION_END(Status); + return Status; + +} + +VL53L1_Error VL53L1_GetZoneCalibrationData(VL53L1_DEV Dev, + VL53L1_ZoneCalibrationData_t *pZoneCalibrationData) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + Status = VL53L1_get_zone_calibration_data(Dev, pZoneCalibrationData); + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_GetOpticalCenter(VL53L1_DEV Dev, + FixPoint1616_t *pOpticalCenterX, + FixPoint1616_t *pOpticalCenterY) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + VL53L1_calibration_data_t CalibrationData; + + LOG_FUNCTION_START(""); + + *pOpticalCenterX = 0; + *pOpticalCenterY = 0; + Status = VL53L1_get_part_to_part_data(Dev, &CalibrationData); + if (Status == VL53L1_ERROR_NONE) { + *pOpticalCenterX = VL53L1_FIXPOINT44TOFIXPOINT1616( + CalibrationData.optical_centre.x_centre); + *pOpticalCenterY = VL53L1_FIXPOINT44TOFIXPOINT1616( + CalibrationData.optical_centre.y_centre); + } + + LOG_FUNCTION_END(Status); + return Status; +} + + + + + + + + +VL53L1_Error VL53L1_SetThresholdConfig(VL53L1_DEV Dev, + VL53L1_DetectionConfig_t *pConfig) +{ +#define BADTHRESBOUNDS(T) \ + (((T.CrossMode == VL53L1_THRESHOLD_OUT_OF_WINDOW) || \ + (T.CrossMode == VL53L1_THRESHOLD_IN_WINDOW)) && (T.Low > T.High)) + + VL53L1_Error Status = VL53L1_ERROR_NONE; + VL53L1_GPIO_interrupt_config_t Cfg; + uint16_t g; + FixPoint1616_t gain, high1616, low1616; + VL53L1_LLDriverData_t *pdev; + + LOG_FUNCTION_START(""); + + pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + Status = VL53L1_get_GPIO_interrupt_config(Dev, &Cfg); + if (Status == VL53L1_ERROR_NONE) { + if (pConfig->DetectionMode == VL53L1_DETECTION_NORMAL_RUN) { + Cfg.intr_new_measure_ready = 1; + Status = VL53L1_set_GPIO_interrupt_config_struct(Dev, + Cfg); + } else { + if (BADTHRESBOUNDS(pConfig->Distance)) + Status = VL53L1_ERROR_INVALID_PARAMS; + if ((Status == VL53L1_ERROR_NONE) && + (BADTHRESBOUNDS(pConfig->Rate))) + Status = VL53L1_ERROR_INVALID_PARAMS; + if (Status == VL53L1_ERROR_NONE) { + Cfg.intr_new_measure_ready = 0; + Cfg.intr_no_target = pConfig->IntrNoTarget; + + + + g = pdev->gain_cal.standard_ranging_gain_factor; + if (g != 0) { + + + gain = (FixPoint1616_t) ((uint32_t)g << 5); + high1616 = (FixPoint1616_t) ((uint32_t) + pConfig->Distance.High << 16); + low1616 = (FixPoint1616_t) ((uint32_t) + pConfig->Distance.Low << 16); + + + high1616 = (high1616 + 32768) / gain; + low1616 = (low1616 + 32768) / gain; + Cfg.threshold_distance_high = (uint16_t) + (high1616 & 0xFFFF); + Cfg.threshold_distance_low = (uint16_t) + (low1616 & 0xFFFF); + } + + + Cfg.threshold_rate_high = + VL53L1_FIXPOINT1616TOFIXPOINT97( + pConfig->Rate.High); + Cfg.threshold_rate_low = + VL53L1_FIXPOINT1616TOFIXPOINT97( + pConfig->Rate.Low); + + Cfg.intr_mode_distance = ConvertModeToLLD( + &Status, + pConfig->Distance.CrossMode); + if (Status == VL53L1_ERROR_NONE) + Cfg.intr_mode_rate = ConvertModeToLLD( + &Status, + pConfig->Rate.CrossMode); + } + + + + if (Status == VL53L1_ERROR_NONE) { + Cfg.intr_combined_mode = 1; + switch (pConfig->DetectionMode) { + case VL53L1_DETECTION_DISTANCE_ONLY: + Cfg.threshold_rate_high = 0; + Cfg.threshold_rate_low = 0; + break; + case VL53L1_DETECTION_RATE_ONLY: + Cfg.threshold_distance_high = 0; + Cfg.threshold_distance_low = 0; + break; + case VL53L1_DETECTION_DISTANCE_OR_RATE: + + + + + break; + case VL53L1_DETECTION_DISTANCE_AND_RATE: + Cfg.intr_combined_mode = 0; + break; + default: + Status = VL53L1_ERROR_INVALID_PARAMS; + } + } + + if (Status == VL53L1_ERROR_NONE) + Status = + VL53L1_set_GPIO_interrupt_config_struct(Dev, + Cfg); + + } + } + + LOG_FUNCTION_END(Status); + return Status; +} + + +VL53L1_Error VL53L1_GetThresholdConfig(VL53L1_DEV Dev, + VL53L1_DetectionConfig_t *pConfig) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + VL53L1_GPIO_interrupt_config_t Cfg; + + LOG_FUNCTION_START(""); + + Status = VL53L1_get_GPIO_interrupt_config(Dev, &Cfg); + + if (Status != VL53L1_ERROR_NONE) { + LOG_FUNCTION_END(Status); + return Status; + } + + pConfig->IntrNoTarget = Cfg.intr_no_target; + pConfig->Distance.High = Cfg.threshold_distance_high; + pConfig->Distance.Low = Cfg.threshold_distance_low; + pConfig->Rate.High = + VL53L1_FIXPOINT97TOFIXPOINT1616( + Cfg.threshold_rate_high); + pConfig->Rate.Low = + VL53L1_FIXPOINT97TOFIXPOINT1616(Cfg.threshold_rate_low); + pConfig->Distance.CrossMode = + ConvertModeFromLLD(&Status, Cfg.intr_mode_distance); + if (Status == VL53L1_ERROR_NONE) + pConfig->Rate.CrossMode = + ConvertModeFromLLD(&Status, Cfg.intr_mode_rate); + + if (Cfg.intr_new_measure_ready == 1) { + pConfig->DetectionMode = VL53L1_DETECTION_NORMAL_RUN; + } else { + + + if (Status == VL53L1_ERROR_NONE) { + if (Cfg.intr_combined_mode == 0) + pConfig->DetectionMode = + VL53L1_DETECTION_DISTANCE_AND_RATE; + else { + if ((Cfg.threshold_distance_high == 0) && + (Cfg.threshold_distance_low == 0)) + pConfig->DetectionMode = + VL53L1_DETECTION_RATE_ONLY; + else if ((Cfg.threshold_rate_high == 0) && + (Cfg.threshold_rate_low == 0)) + pConfig->DetectionMode = + VL53L1_DETECTION_DISTANCE_ONLY; + else + pConfig->DetectionMode = + VL53L1_DETECTION_DISTANCE_OR_RATE; + } + } + } + + LOG_FUNCTION_END(Status); + return Status; +} + + + + + +VL53L1_Error VL53L1_PerformOffsetPerVcselCalibration(VL53L1_DEV Dev, + int32_t CalDistanceMilliMeter) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + int32_t sum_ranging_range_A, sum_ranging_range_B; + uint8_t offset_meas_range_A, offset_meas_range_B; + int16_t Max, UnderMax, OverMax, Repeat; + int32_t inloopcount; + int32_t IncRounding; + int16_t meanDistance_mm; + VL53L1_RangingMeasurementData_t RangingMeasurementData; + VL53L1_LLDriverData_t *pdev; + uint8_t goodmeas; + VL53L1_PresetModes currentMode; + VL53L1_DistanceModes currentDist; + VL53L1_DistanceModes DistMode[3] = {VL53L1_DISTANCEMODE_SHORT, + VL53L1_DISTANCEMODE_MEDIUM, VL53L1_DISTANCEMODE_LONG}; + int16_t offsetA[3]; + int16_t offsetB[3]; + + VL53L1_Error SmudgeStatus = VL53L1_ERROR_NONE; + uint8_t smudge_corr_en; + + LOG_FUNCTION_START(""); + + pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + + smudge_corr_en = pdev->smudge_correct_config.smudge_corr_enabled; + SmudgeStatus = VL53L1_dynamic_xtalk_correction_disable(Dev); + + + pdev->customer.algo__part_to_part_range_offset_mm = 0; + pdev->customer.mm_config__inner_offset_mm = 0; + pdev->customer.mm_config__outer_offset_mm = 0; + pdev->customer.mm_config__outer_offset_mm = 0; + memset(&pdev->per_vcsel_cal_data, 0, sizeof(pdev->per_vcsel_cal_data)); + + Repeat = 0; + Max = 2 * BDTable[ + VL53L1_TUNING_MAX_SIMPLE_OFFSET_CALIBRATION_SAMPLE_NUMBER]; + UnderMax = 1 + (Max / 2); + OverMax = Max + (Max / 2); + + Status = VL53L1_GetPresetMode(Dev, ¤tMode); + Status = VL53L1_GetDistanceMode(Dev, ¤tDist); + + while ((Repeat < 3) && (Status == VL53L1_ERROR_NONE)) { + Status = VL53L1_SetDistanceMode(Dev, DistMode[Repeat]); + Status = VL53L1_StartMeasurement(Dev); + + + if (Status == VL53L1_ERROR_NONE) { + VL53L1_WaitMeasurementDataReady(Dev); + VL53L1_GetRangingMeasurementData(Dev, &RangingMeasurementData); + VL53L1_ClearInterruptAndStartMeasurement(Dev); + } + + + inloopcount = 0; + offset_meas_range_A = 0; + sum_ranging_range_A = 0; + offset_meas_range_B = 0; + sum_ranging_range_B = 0; + while ((Status == VL53L1_ERROR_NONE) && (inloopcount < Max) && + (inloopcount < OverMax)) { + Status = VL53L1_WaitMeasurementDataReady(Dev); + if (Status == VL53L1_ERROR_NONE) + Status = VL53L1_GetRangingMeasurementData(Dev, + &RangingMeasurementData); + goodmeas = (RangingMeasurementData.RangeStatus == + VL53L1_RANGESTATUS_RANGE_VALID); + if ((Status == VL53L1_ERROR_NONE) && goodmeas) { + if ((pdev->ll_state.cfg_internal_stream_count) & 0x01) { + sum_ranging_range_A = sum_ranging_range_A + + RangingMeasurementData.RangeMilliMeter; + offset_meas_range_A++; + } else { + sum_ranging_range_B = sum_ranging_range_B + + RangingMeasurementData.RangeMilliMeter; + offset_meas_range_B++; + } + inloopcount = offset_meas_range_A + offset_meas_range_B; + } + Status = VL53L1_ClearInterruptAndStartMeasurement(Dev); + } + + + + if (inloopcount < UnderMax) + Status = VL53L1_ERROR_OFFSET_CAL_NO_SAMPLE_FAIL; + + VL53L1_StopMeasurement(Dev); + + if (Status == VL53L1_ERROR_NONE) { + + } + + + if ((sum_ranging_range_A < 0) || + (sum_ranging_range_B < 0) || + (sum_ranging_range_A > ((int32_t) offset_meas_range_A * 0xffff)) || + (sum_ranging_range_B > ((int32_t) offset_meas_range_B * 0xffff))) { + Status = VL53L1_WARNING_OFFSET_CAL_SIGMA_TOO_HIGH; + } + + if ((Status == VL53L1_ERROR_NONE) && (offset_meas_range_A > 0)) { + IncRounding = offset_meas_range_A / 2; + meanDistance_mm = (int16_t)((sum_ranging_range_A + IncRounding) + / offset_meas_range_A); + offsetA[Repeat] = + (int16_t)CalDistanceMilliMeter - meanDistance_mm; + } + + if ((Status == VL53L1_ERROR_NONE) && (offset_meas_range_B > 0)) { + IncRounding = offset_meas_range_B / 2; + meanDistance_mm = (int16_t)((sum_ranging_range_B + IncRounding) + / offset_meas_range_B); + offsetB[Repeat] = + (int16_t)CalDistanceMilliMeter - meanDistance_mm; + } + Repeat++; + } + + + if ((SmudgeStatus == VL53L1_ERROR_NONE) && (smudge_corr_en == 1)) + SmudgeStatus = VL53L1_dynamic_xtalk_correction_enable(Dev); + + if (Status == VL53L1_ERROR_NONE) { + pdev->per_vcsel_cal_data.short_a_offset_mm = offsetA[0]; + pdev->per_vcsel_cal_data.short_b_offset_mm = offsetB[0]; + pdev->per_vcsel_cal_data.medium_a_offset_mm = offsetA[1]; + pdev->per_vcsel_cal_data.medium_b_offset_mm = offsetB[1]; + pdev->per_vcsel_cal_data.long_a_offset_mm = offsetA[2]; + pdev->per_vcsel_cal_data.long_b_offset_mm = offsetB[2]; + } + + VL53L1_SetPresetMode(Dev, currentMode); + VL53L1_SetDistanceMode(Dev, currentDist); + + LOG_FUNCTION_END(Status); + return Status; +} + diff --git a/drivers/input/misc/vl53L1/kona/src/vl53l1_api_calibration.c b/drivers/input/misc/vl53L1/kona/src/vl53l1_api_calibration.c new file mode 100644 index 000000000000..8d3710017b4d --- /dev/null +++ b/drivers/input/misc/vl53L1/kona/src/vl53l1_api_calibration.c @@ -0,0 +1,2725 @@ + +/******************************************************************************* + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#include "vl53l1_ll_def.h" +#include "vl53l1_ll_device.h" +#include "vl53l1_platform.h" +#include "vl53l1_platform_ipp.h" +#include "vl53l1_register_map.h" +#include "vl53l1_register_funcs.h" +#include "vl53l1_register_settings.h" +#include "vl53l1_hist_map.h" +#include "vl53l1_hist_structs.h" +#include "vl53l1_core.h" +#include "vl53l1_wait.h" +#include "vl53l1_api_preset_modes.h" +#include "vl53l1_silicon_core.h" +#include "vl53l1_api_core.h" +#include "vl53l1_api_calibration.h" + +#ifdef VL53L1_LOG_ENABLE + #include "vl53l1_api_debug.h" +#endif + + + + +#define LOG_FUNCTION_START(fmt, ...) \ + _LOG_FUNCTION_START(VL53L1_TRACE_MODULE_CORE, fmt, ##__VA_ARGS__) +#define LOG_FUNCTION_END(status, ...) \ + _LOG_FUNCTION_END(VL53L1_TRACE_MODULE_CORE, status, ##__VA_ARGS__) +#define LOG_FUNCTION_END_FMT(status, fmt, ...) \ + _LOG_FUNCTION_END_FMT(VL53L1_TRACE_MODULE_CORE, status, \ + fmt, ##__VA_ARGS__) + +#define trace_print(level, ...) \ + _LOG_TRACE_PRINT(VL53L1_TRACE_MODULE_CORE, \ + level, VL53L1_TRACE_FUNCTION_NONE, ##__VA_ARGS__) + + +VL53L1_Error VL53L1_run_ref_spad_char( + VL53L1_DEV Dev, + VL53L1_Error *pcal_status) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + uint8_t comms_buffer[6]; + + VL53L1_refspadchar_config_t *prefspadchar = &(pdev->refspadchar); + + LOG_FUNCTION_START(""); + + + + + + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_enable_powerforce(Dev); + + + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_set_ref_spad_char_config( + Dev, + prefspadchar->VL53L1_p_009, + prefspadchar->timeout_us, + prefspadchar->target_count_rate_mcps, + prefspadchar->max_count_rate_limit_mcps, + prefspadchar->min_count_rate_limit_mcps, + pdev->stat_nvm.osc_measured__fast_osc__frequency); + + + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_run_device_test( + Dev, + prefspadchar->device_test_mode); + + + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_ReadMulti( + Dev, + VL53L1_REF_SPAD_CHAR_RESULT__NUM_ACTUAL_REF_SPADS, + comms_buffer, + 2); + + if (status == VL53L1_ERROR_NONE) { + pdev->dbg_results.ref_spad_char_result__num_actual_ref_spads = + comms_buffer[0]; + pdev->dbg_results.ref_spad_char_result__ref_location = + comms_buffer[1]; + } + + + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_WriteMulti( + Dev, + VL53L1_REF_SPAD_MAN__NUM_REQUESTED_REF_SPADS, + comms_buffer, + 2); + + if (status == VL53L1_ERROR_NONE) { + pdev->customer.ref_spad_man__num_requested_ref_spads = + comms_buffer[0]; + pdev->customer.ref_spad_man__ref_location = + comms_buffer[1]; + } + + + + + + + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_ReadMulti( + Dev, + VL53L1_RESULT__SPARE_0_SD1, + comms_buffer, + 6); + + + + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_WriteMulti( + Dev, + VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_REF_0, + comms_buffer, + 6); + + if (status == VL53L1_ERROR_NONE) { + pdev->customer.global_config__spad_enables_ref_0 = + comms_buffer[0]; + pdev->customer.global_config__spad_enables_ref_1 = + comms_buffer[1]; + pdev->customer.global_config__spad_enables_ref_2 = + comms_buffer[2]; + pdev->customer.global_config__spad_enables_ref_3 = + comms_buffer[3]; + pdev->customer.global_config__spad_enables_ref_4 = + comms_buffer[4]; + pdev->customer.global_config__spad_enables_ref_5 = + comms_buffer[5]; + } + +#ifdef VL53L1_LOG_ENABLE + + + if (status == VL53L1_ERROR_NONE) + VL53L1_print_customer_nvm_managed( + &(pdev->customer), + "run_ref_spad_char():pdev->lldata.customer.", + VL53L1_TRACE_MODULE_REF_SPAD_CHAR); +#endif + + if (status == VL53L1_ERROR_NONE) { + + switch (pdev->sys_results.result__range_status) { + + case VL53L1_DEVICEERROR_REFSPADCHARNOTENOUGHDPADS: + status = VL53L1_WARNING_REF_SPAD_CHAR_NOT_ENOUGH_SPADS; + break; + + case VL53L1_DEVICEERROR_REFSPADCHARMORETHANTARGET: + status = VL53L1_WARNING_REF_SPAD_CHAR_RATE_TOO_HIGH; + break; + + case VL53L1_DEVICEERROR_REFSPADCHARLESSTHANTARGET: + status = VL53L1_WARNING_REF_SPAD_CHAR_RATE_TOO_LOW; + break; + } + } + + + + + + + *pcal_status = status; + + + + + IGNORE_STATUS( + IGNORE_REF_SPAD_CHAR_NOT_ENOUGH_SPADS, + VL53L1_WARNING_REF_SPAD_CHAR_NOT_ENOUGH_SPADS, + status); + + IGNORE_STATUS( + IGNORE_REF_SPAD_CHAR_RATE_TOO_HIGH, + VL53L1_WARNING_REF_SPAD_CHAR_RATE_TOO_HIGH, + status); + + IGNORE_STATUS( + IGNORE_REF_SPAD_CHAR_RATE_TOO_LOW, + VL53L1_WARNING_REF_SPAD_CHAR_RATE_TOO_LOW, + status); + + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_run_xtalk_extraction( + VL53L1_DEV Dev, + VL53L1_Error *pcal_status) +{ + + + + + + + + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + + + + + + + VL53L1_xtalkextract_config_t *pX = &(pdev->xtalk_extract_cfg); + VL53L1_xtalk_config_t *pC = &(pdev->xtalk_cfg); + VL53L1_xtalk_calibration_results_t *pXC = &(pdev->xtalk_cal); + + uint8_t results_invalid = 0; + + uint8_t i = 0; + uint16_t tmp16 = 0; + + uint8_t measurement_mode = VL53L1_DEVICEMEASUREMENTMODE_BACKTOBACK; + + LOG_FUNCTION_START(""); + + + + + + + + VL53L1_init_histogram_bin_data_struct( + 0, + (uint16_t)VL53L1_HISTOGRAM_BUFFER_SIZE, + &(pdev->xtalk_results.central_histogram_avg)); + + VL53L1_init_histogram_bin_data_struct( + 0, + (uint16_t)VL53L1_HISTOGRAM_BUFFER_SIZE, + &(pdev->xtalk_results.central_histogram_sum)); + + + + + + + + + + + + if (status == VL53L1_ERROR_NONE) + + status = + VL53L1_set_preset_mode( + Dev, + VL53L1_DEVICEPRESETMODE_HISTOGRAM_XTALK_PLANAR, + + + pX->dss_config__target_total_rate_mcps, + pX->phasecal_config_timeout_us, + pX->mm_config_timeout_us, + pX->range_config_timeout_us, + + + 100); + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_disable_xtalk_compensation(Dev); + + + + + + + pdev->xtalk_results.max_results = VL53L1_MAX_XTALK_RANGE_RESULTS; + pdev->xtalk_results.active_results = pdev->zone_cfg.active_zones+1; + + + + + pdev->xtalk_results.central_histogram__window_start = 0xFF; + pdev->xtalk_results.central_histogram__window_end = 0x00; + + pdev->xtalk_results.num_of_samples_status = 0x00; + pdev->xtalk_results.zero_samples_status = 0x00; + pdev->xtalk_results.max_sigma_status = 0x00; + + for (i = 0; i < pdev->xtalk_results.max_results; i++) { + pdev->xtalk_results.VL53L1_p_002[i].no_of_samples = 0; + pdev->xtalk_results.VL53L1_p_002[i].signal_total_events_avg = 0; + pdev->xtalk_results.VL53L1_p_002[i].signal_total_events_sum = 0; + pdev->xtalk_results.VL53L1_p_002[i].rate_per_spad_kcps_sum = 0; + pdev->xtalk_results.VL53L1_p_002[i].rate_per_spad_kcps_avg = 0; + pdev->xtalk_results.VL53L1_p_002[i].sigma_mm_sum = 0; + pdev->xtalk_results.VL53L1_p_002[i].sigma_mm_avg = 0; + + + pdev->xtalk_results.VL53L1_p_002[i].median_phase_sum = 0; + pdev->xtalk_results.VL53L1_p_002[i].median_phase_avg = 0; + + + } + + + + if (status == VL53L1_ERROR_NONE) { + + status = + VL53L1_get_and_avg_xtalk_samples( + Dev, + + + pX->num_of_samples, + + + measurement_mode, + + + pX->algo__crosstalk_extract_max_valid_range_mm, + pX->algo__crosstalk_extract_min_valid_range_mm, + pX->algo__crosstalk_extract_max_valid_rate_kcps, + + + 0x0, + + 0x4, + + &(pdev->xtalk_results), + &(pdev->xtalk_results.central_histogram_sum), + &(pdev->xtalk_results.central_histogram_avg)); + } + + + + + + + + + + + + + + if (status == VL53L1_ERROR_NONE) + if ((pdev->xtalk_results.VL53L1_p_002[4].no_of_samples == 0) || + (pdev->xtalk_results.VL53L1_p_002[4].sigma_mm_avg > + ((uint32_t)pX->algo__crosstalk_extract_max_sigma_mm + << 5))) + results_invalid = 0x01; + + + + +#ifdef VL53L1_LOG_ENABLE + if (status == VL53L1_ERROR_NONE) + VL53L1_print_xtalk_range_results( + &(pdev->xtalk_results), + "pdev->xtalk_results", + VL53L1_TRACE_MODULE_CORE); +#endif + + if ((status == VL53L1_ERROR_NONE) && (results_invalid == 0)) { + + status = + VL53L1_ipp_xtalk_calibration_process_data( + Dev, + &(pdev->xtalk_results), + &(pdev->xtalk_shapes), + &(pdev->xtalk_cal)); + + if (status == VL53L1_ERROR_NONE) { + + for (i = 0; i < VL53L1_BIN_REC_SIZE; i++) + pXC->algo__xtalk_cpo_HistoMerge_kcps[i] = + pXC->algo__crosstalk_compensation_plane_offset_kcps; + pC->algo__crosstalk_compensation_x_plane_gradient_kcps = + pXC->algo__crosstalk_compensation_x_plane_gradient_kcps; + pC->algo__crosstalk_compensation_y_plane_gradient_kcps = + pXC->algo__crosstalk_compensation_y_plane_gradient_kcps; + pC->algo__crosstalk_compensation_plane_offset_kcps = + pXC->algo__crosstalk_compensation_plane_offset_kcps; + + + } + + + } + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_xtalk_compensation(Dev); + + + + + + if (status == VL53L1_ERROR_NONE) { + + for (i = 0; i < pdev->xtalk_results.max_results; i++) { + + + if (pdev->xtalk_results.VL53L1_p_002[i].no_of_samples != + + + pX->num_of_samples) { + + + pdev->xtalk_results.num_of_samples_status = + pdev->xtalk_results.num_of_samples_status | + (1 << i); + } + + + if (pdev->xtalk_results.VL53L1_p_002[i].no_of_samples == + 0x00) { + pdev->xtalk_results.zero_samples_status = + pdev->xtalk_results.zero_samples_status | + (1 << i); + } + + + + + + + + + + + + + tmp16 = pX->algo__crosstalk_extract_max_sigma_mm; + if (pdev->xtalk_results.VL53L1_p_002[i].sigma_mm_avg > + ((uint32_t)tmp16 << 5)) { + pdev->xtalk_results.max_sigma_status = + pdev->xtalk_results.max_sigma_status | + (1 << i); + } + + + } + } + + + + + + + + + + + + + + if (results_invalid > 0) { + + + if (pdev->xtalk_results.VL53L1_p_002[4].no_of_samples == 0) { + status = VL53L1_ERROR_XTALK_EXTRACTION_NO_SAMPLE_FAIL; + } else { + + + + if (pdev->xtalk_results.VL53L1_p_002[4].sigma_mm_avg > + (((uint32_t)pX->algo__crosstalk_extract_max_sigma_mm) + << 5)) { + status = + VL53L1_ERROR_XTALK_EXTRACTION_SIGMA_LIMIT_FAIL; + } + + + } + } else { + + + if (pdev->xtalk_results.zero_samples_status != 0x00) { + status = VL53L1_WARNING_XTALK_NO_SAMPLES_FOR_GRADIENT; + } else { + if (pdev->xtalk_results.max_sigma_status != 0x00) { + status = + VL53L1_WARNING_XTALK_SIGMA_LIMIT_FOR_GRADIENT; + } else { + if (pdev->xtalk_results.num_of_samples_status != + 0x00) + status = + VL53L1_WARNING_XTALK_MISSING_SAMPLES; + } + } + } + + + + + + + pdev->xtalk_results.cal_status = status; + *pcal_status = pdev->xtalk_results.cal_status; + + + + + IGNORE_STATUS( + IGNORE_XTALK_EXTRACTION_NO_SAMPLE_FAIL, + VL53L1_ERROR_XTALK_EXTRACTION_NO_SAMPLE_FAIL, + status); + + IGNORE_STATUS( + IGNORE_XTALK_EXTRACTION_SIGMA_LIMIT_FAIL, + VL53L1_ERROR_XTALK_EXTRACTION_SIGMA_LIMIT_FAIL, + status); + + IGNORE_STATUS( + IGNORE_XTALK_EXTRACTION_NO_SAMPLE_FOR_GRADIENT_WARN, + VL53L1_WARNING_XTALK_NO_SAMPLES_FOR_GRADIENT, + status); + + IGNORE_STATUS( + IGNORE_XTALK_EXTRACTION_SIGMA_LIMIT_FOR_GRADIENT_WARN, + VL53L1_WARNING_XTALK_SIGMA_LIMIT_FOR_GRADIENT, + status); + + IGNORE_STATUS( + IGNORE_XTALK_EXTRACTION_MISSING_SAMPLES_WARN, + VL53L1_WARNING_XTALK_MISSING_SAMPLES, + status); + +#ifdef VL53L1_LOG_ENABLE + + + + + VL53L1_print_customer_nvm_managed( + &(pdev->customer), + "run_xtalk_extraction():pdev->lldata.customer.", + VL53L1_TRACE_MODULE_XTALK_DATA); + + VL53L1_print_xtalk_config( + &(pdev->xtalk_cfg), + "run_xtalk_extraction():pdev->lldata.xtalk_cfg.", + VL53L1_TRACE_MODULE_XTALK_DATA); + + VL53L1_print_xtalk_extract_config( + &(pdev->xtalk_extract_cfg), + "run_xtalk_extraction():pdev->lldata.xtalk_extract_cfg.", + VL53L1_TRACE_MODULE_XTALK_DATA); + + VL53L1_print_histogram_bin_data( + &(pdev->hist_data), + "run_xtalk_extraction():pdev->lldata.hist_data.", + VL53L1_TRACE_MODULE_XTALK_DATA); + + VL53L1_print_xtalk_histogram_data( + &(pdev->xtalk_shapes), + "pdev->lldata.xtalk_shapes.", + VL53L1_TRACE_MODULE_XTALK_DATA); + + VL53L1_print_xtalk_range_results( + &(pdev->xtalk_results), + "run_xtalk_extraction():pdev->lldata.xtalk_results.", + VL53L1_TRACE_MODULE_XTALK_DATA); + +#endif + + LOG_FUNCTION_END(status); + + return status; + +} + + + +VL53L1_Error VL53L1_get_and_avg_xtalk_samples( + VL53L1_DEV Dev, + uint8_t num_of_samples, + uint8_t measurement_mode, + int16_t xtalk_filter_thresh_max_mm, + int16_t xtalk_filter_thresh_min_mm, + uint16_t xtalk_max_valid_rate_kcps, + uint8_t xtalk_result_id, + uint8_t xtalk_histo_id, + VL53L1_xtalk_range_results_t *pXR, + VL53L1_histogram_bin_data_t *psum_histo, + VL53L1_histogram_bin_data_t *pavg_histo) +{ + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + +#ifdef VL53L1_LOG_ENABLE + VL53L1_LLDriverResults_t *pres = + VL53L1DevStructGetLLResultsHandle(Dev); +#endif + + VL53L1_range_results_t *prs = + (VL53L1_range_results_t *) pdev->wArea1; + + VL53L1_range_data_t *prange_data; + VL53L1_xtalk_range_data_t *pxtalk_range_data; + + uint8_t i = 0; + uint8_t j = 0; + uint8_t zone_id = 0; + uint8_t final_zone = pdev->zone_cfg.active_zones+1; + uint8_t valid_result; + + uint8_t smudge_corr_en = 0; + + + + + + + smudge_corr_en = pdev->smudge_correct_config.smudge_corr_enabled; + + status = VL53L1_dynamic_xtalk_correction_disable(Dev); + + + + VL53L1_load_patch(Dev); + + + + + if (status == VL53L1_ERROR_NONE) + + status = + VL53L1_init_and_start_range( + Dev, + measurement_mode, + VL53L1_DEVICECONFIGLEVEL_CUSTOMER_ONWARDS); + + + for (i = 0; i <= (final_zone*num_of_samples); i++) { + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_wait_for_range_completion(Dev); + + + + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_get_device_results( + Dev, + VL53L1_DEVICERESULTSLEVEL_FULL, + prs); + + + + + + + if (status == VL53L1_ERROR_NONE && + pdev->ll_state.rd_device_state != + VL53L1_DEVICESTATE_RANGING_WAIT_GPH_SYNC) { + + zone_id = pdev->ll_state.rd_zone_id + xtalk_result_id; + prange_data = &(prs->VL53L1_p_002[0]); + + + + if (prs->active_results > 1) { + for (j = 1; + j < prs->active_results; j++) { + if (prs->VL53L1_p_002[j].median_range_mm + < + prange_data->median_range_mm) + prange_data = + &(prs->VL53L1_p_002[j]); + + } + } + + pxtalk_range_data = &(pXR->VL53L1_p_002[zone_id]); + + + + + if ((prs->active_results > 0) && + (prange_data->median_range_mm < + xtalk_filter_thresh_max_mm) && + (prange_data->median_range_mm > + xtalk_filter_thresh_min_mm) && + (prange_data->VL53L1_p_012 < + (uint32_t)(xtalk_max_valid_rate_kcps * 16))) + valid_result = 1; + else + valid_result = 0; + + if (valid_result == 1) { + + pxtalk_range_data->no_of_samples++; + + pxtalk_range_data->rate_per_spad_kcps_sum += + prange_data->VL53L1_p_012; + + pxtalk_range_data->signal_total_events_sum += + prange_data->VL53L1_p_013; + + pxtalk_range_data->sigma_mm_sum += + (uint32_t)prange_data->VL53L1_p_005; + + + + + pxtalk_range_data->median_phase_sum += + (uint32_t)prange_data->VL53L1_p_014; + + + + + + + + + + + } + + if ((valid_result == 1) && (zone_id >= 4)) { + status = VL53L1_sum_histogram_data( + &(pdev->hist_data), + psum_histo); + + + + + + if (prange_data->VL53L1_p_015 < + pXR->central_histogram__window_start) + pXR->central_histogram__window_start = + prange_data->VL53L1_p_015; + + + + if (prange_data->VL53L1_p_016 > + pXR->central_histogram__window_end) + pXR->central_histogram__window_end = + prange_data->VL53L1_p_016; + + } + + } + + + + + + + +#ifdef VL53L1_LOG_ENABLE + if (status == VL53L1_ERROR_NONE) { + VL53L1_print_range_results( + &(pres->range_results), + "pres->range_results.", + VL53L1_TRACE_MODULE_CORE); + } +#endif + + + + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_wait_for_firmware_ready(Dev); + + + + + + + + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_clear_interrupt_and_enable_next_range( + Dev, + measurement_mode); + + + } + + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_stop_range(Dev); + + VL53L1_unload_patch(Dev); + + + + + for (i = 0; i < (pdev->zone_cfg.active_zones+1); i++) { + + pxtalk_range_data = &(pXR->VL53L1_p_002[i+xtalk_result_id]); + + if (pxtalk_range_data->no_of_samples > 0) { + pxtalk_range_data->rate_per_spad_kcps_avg = + pxtalk_range_data->rate_per_spad_kcps_sum / + (uint32_t)pxtalk_range_data->no_of_samples; + + pxtalk_range_data->signal_total_events_avg = + pxtalk_range_data->signal_total_events_sum / + (int32_t)pxtalk_range_data->no_of_samples; + + pxtalk_range_data->sigma_mm_avg = + pxtalk_range_data->sigma_mm_sum / + (uint32_t)pxtalk_range_data->no_of_samples; + + + + + pxtalk_range_data->median_phase_avg = + pxtalk_range_data->median_phase_sum / + (uint32_t)pxtalk_range_data->no_of_samples; + + + + + } else { + pxtalk_range_data->rate_per_spad_kcps_avg = + pxtalk_range_data->rate_per_spad_kcps_sum; + pxtalk_range_data->signal_total_events_avg = + pxtalk_range_data->signal_total_events_sum; + pxtalk_range_data->sigma_mm_avg = + pxtalk_range_data->sigma_mm_sum; + + + + + pxtalk_range_data->median_phase_avg = + pxtalk_range_data->median_phase_sum; + + + + } + } + + + + + memcpy(pavg_histo, &(pdev->hist_data), + sizeof(VL53L1_histogram_bin_data_t)); + + + + + if (status == VL53L1_ERROR_NONE) { + + pxtalk_range_data = &(pXR->VL53L1_p_002[xtalk_histo_id]); + + status = VL53L1_avg_histogram_data( + pxtalk_range_data->no_of_samples, + psum_histo, + pavg_histo); + } + + + + + + + if (status == VL53L1_ERROR_NONE) { + if (smudge_corr_en == 1) + status = VL53L1_dynamic_xtalk_correction_enable(Dev); + } + + + + LOG_FUNCTION_END(status); + + return status; + +} + + + +VL53L1_Error VL53L1_run_offset_calibration( + VL53L1_DEV Dev, + int16_t cal_distance_mm, + uint16_t cal_reflectance_pc, + VL53L1_Error *pcal_status) +{ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + + VL53L1_DevicePresetModes device_preset_modes[ + VL53L1_MAX_OFFSET_RANGE_RESULTS]; + + VL53L1_range_results_t *prange_results = + (VL53L1_range_results_t *) pdev->wArea1; + + VL53L1_range_data_t *pRData = NULL; + VL53L1_offset_range_data_t *pfs = NULL; + VL53L1_general_config_t *pG = &(pdev->gen_cfg); + VL53L1_additional_offset_cal_data_t *pAO = &(pdev->add_off_cal_data); + + uint8_t i = 0; + uint8_t m = 0; + uint8_t measurement_mode = + VL53L1_DEVICEMEASUREMENTMODE_BACKTOBACK; + uint16_t manual_effective_spads = + pG->dss_config__manual_effective_spads_select; + + uint8_t num_of_samples[VL53L1_MAX_OFFSET_RANGE_RESULTS]; + + uint8_t smudge_corr_en = 0; + + LOG_FUNCTION_START(""); + + + + + switch (pdev->offset_calibration_mode) { + + case VL53L1_OFFSETCALIBRATIONMODE__MM1_MM2__HISTOGRAM: + case VL53L1_OFFSETCALIBRATIONMODE__MM1_MM2__HISTOGRAM_PRE_RANGE_ONLY: + device_preset_modes[0] = + VL53L1_DEVICEPRESETMODE_HISTOGRAM_RANGING; + device_preset_modes[1] = + VL53L1_DEVICEPRESETMODE_HISTOGRAM_RANGING_MM1_CAL; + device_preset_modes[2] = + VL53L1_DEVICEPRESETMODE_HISTOGRAM_RANGING_MM2_CAL; + break; + + default: + device_preset_modes[0] = + VL53L1_DEVICEPRESETMODE_STANDARD_RANGING; + device_preset_modes[1] = + VL53L1_DEVICEPRESETMODE_STANDARD_RANGING_MM1_CAL; + device_preset_modes[2] = + VL53L1_DEVICEPRESETMODE_STANDARD_RANGING_MM2_CAL; + break; + } + + + + + + num_of_samples[0] = pdev->offsetcal_cfg.pre_num_of_samples; + num_of_samples[1] = pdev->offsetcal_cfg.mm1_num_of_samples; + num_of_samples[2] = pdev->offsetcal_cfg.mm2_num_of_samples; + + + + + + + switch (pdev->offset_calibration_mode) { + + case VL53L1_OFFSETCALIBRATIONMODE__MM1_MM2__STANDARD_PRE_RANGE_ONLY: + case VL53L1_OFFSETCALIBRATIONMODE__MM1_MM2__HISTOGRAM_PRE_RANGE_ONLY: + + + pdev->offset_results.active_results = 1; + + break; + + default: + + pdev->customer.mm_config__inner_offset_mm = 0; + pdev->customer.mm_config__outer_offset_mm = 0; + pdev->offset_results.active_results = + VL53L1_MAX_OFFSET_RANGE_RESULTS; + + break; + } + + pdev->customer.algo__part_to_part_range_offset_mm = 0; + + + + + pdev->offset_results.max_results = VL53L1_MAX_OFFSET_RANGE_RESULTS; + pdev->offset_results.cal_distance_mm = cal_distance_mm; + pdev->offset_results.cal_reflectance_pc = cal_reflectance_pc; + + for (m = 0; m < VL53L1_MAX_OFFSET_RANGE_RESULTS; m++) { + + pfs = &(pdev->offset_results.VL53L1_p_002[m]); + pfs->preset_mode = 0; + pfs->no_of_samples = 0; + pfs->effective_spads = 0; + pfs->peak_rate_mcps = 0; + pfs->VL53L1_p_005 = 0; + pfs->median_range_mm = 0; + } + + + + + + + smudge_corr_en = pdev->smudge_correct_config.smudge_corr_enabled; + + status = VL53L1_dynamic_xtalk_correction_disable(Dev); + + + + + for (m = 0; m < pdev->offset_results.active_results; m++) { + + pfs = &(pdev->offset_results.VL53L1_p_002[m]); + + pfs->preset_mode = device_preset_modes[m]; + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_set_preset_mode( + Dev, + device_preset_modes[m], + + + pdev->offsetcal_cfg.dss_config__target_total_rate_mcps, + pdev->offsetcal_cfg.phasecal_config_timeout_us, + pdev->offsetcal_cfg.mm_config_timeout_us, + pdev->offsetcal_cfg.range_config_timeout_us, + + + 100); + + pG->dss_config__manual_effective_spads_select = + manual_effective_spads; + + + + VL53L1_load_patch(Dev); + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_init_and_start_range( + Dev, + measurement_mode, + VL53L1_DEVICECONFIGLEVEL_CUSTOMER_ONWARDS); + + for (i = 0; i <= (num_of_samples[m]+2); i++) { + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_wait_for_range_completion(Dev); + + + + + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_get_device_results( + Dev, + VL53L1_DEVICERESULTSLEVEL_FULL, + prange_results); + + + + + + + + + + pRData = &(prange_results->VL53L1_p_002[0]); + + if ((prange_results->active_results > 0 && + prange_results->stream_count > 1) && + (pRData->range_status == + VL53L1_DEVICEERROR_RANGECOMPLETE)) { + + pfs->no_of_samples++; + pfs->effective_spads += + (uint32_t)pRData->VL53L1_p_006; + pfs->peak_rate_mcps += + (uint32_t)pRData->peak_signal_count_rate_mcps; + pfs->VL53L1_p_005 += + (uint32_t)pRData->VL53L1_p_005; + pfs->median_range_mm += + (int32_t)pRData->median_range_mm; + + pfs->dss_config__roi_mode_control = + pG->dss_config__roi_mode_control; + pfs->dss_config__manual_effective_spads_select = + pG->dss_config__manual_effective_spads_select; + + } + + + + + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_wait_for_firmware_ready(Dev); + + + + + + + + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_clear_interrupt_and_enable_next_range( + Dev, + measurement_mode); + } + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_stop_range(Dev); + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WaitUs(Dev, 1000); + VL53L1_unload_patch(Dev); + + + + if (pfs->no_of_samples > 0) { + + pfs->effective_spads += (pfs->no_of_samples/2); + pfs->effective_spads /= pfs->no_of_samples; + + pfs->peak_rate_mcps += (pfs->no_of_samples/2); + pfs->peak_rate_mcps /= pfs->no_of_samples; + + pfs->VL53L1_p_005 += (pfs->no_of_samples/2); + pfs->VL53L1_p_005 /= pfs->no_of_samples; + + pfs->median_range_mm += (pfs->no_of_samples/2); + pfs->median_range_mm /= pfs->no_of_samples; + + pfs->range_mm_offset = (int32_t)cal_distance_mm; + pfs->range_mm_offset -= pfs->median_range_mm; + + + + if (pfs->preset_mode == + VL53L1_DEVICEPRESETMODE_STANDARD_RANGING) + manual_effective_spads = + (uint16_t)pfs->effective_spads; + } + } + + + + + switch (pdev->offset_calibration_mode) { + + case VL53L1_OFFSETCALIBRATIONMODE__MM1_MM2__STANDARD_PRE_RANGE_ONLY: + case VL53L1_OFFSETCALIBRATIONMODE__MM1_MM2__HISTOGRAM_PRE_RANGE_ONLY: + + + + pdev->customer.mm_config__inner_offset_mm += + (int16_t)pdev->offset_results.VL53L1_p_002[0].range_mm_offset; + pdev->customer.mm_config__outer_offset_mm += + (int16_t)pdev->offset_results.VL53L1_p_002[0].range_mm_offset; + break; + + default: + + + pdev->customer.mm_config__inner_offset_mm = + (int16_t)pdev->offset_results.VL53L1_p_002[1].range_mm_offset; + pdev->customer.mm_config__outer_offset_mm = + (int16_t)pdev->offset_results.VL53L1_p_002[2].range_mm_offset; + pdev->customer.algo__part_to_part_range_offset_mm = 0; + + + + + + pAO->result__mm_inner_actual_effective_spads = + (uint16_t)pdev->offset_results.VL53L1_p_002[1].effective_spads; + pAO->result__mm_outer_actual_effective_spads = + (uint16_t)pdev->offset_results.VL53L1_p_002[2].effective_spads; + + pAO->result__mm_inner_peak_signal_count_rtn_mcps = + (uint16_t)pdev->offset_results.VL53L1_p_002[1].peak_rate_mcps; + pAO->result__mm_outer_peak_signal_count_rtn_mcps = + (uint16_t)pdev->offset_results.VL53L1_p_002[2].peak_rate_mcps; + + break; + } + + + + + + + + pdev->cust_dmax_cal.ref__actual_effective_spads = + (uint16_t)pdev->offset_results.VL53L1_p_002[0].effective_spads; + pdev->cust_dmax_cal.ref__peak_signal_count_rate_mcps = + (uint16_t)pdev->offset_results.VL53L1_p_002[0].peak_rate_mcps; + + + + pdev->cust_dmax_cal.ref__distance_mm = cal_distance_mm * 16; + + pdev->cust_dmax_cal.ref_reflectance_pc = cal_reflectance_pc; + pdev->cust_dmax_cal.coverglass_transmission = 0x0100; + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_set_customer_nvm_managed( + Dev, + &(pdev->customer)); + + + + + + + if (status == VL53L1_ERROR_NONE) { + if (smudge_corr_en == 1) + status = VL53L1_dynamic_xtalk_correction_enable(Dev); + } + + + + + + + + + for (m = 0; m < pdev->offset_results.active_results; m++) { + + pfs = &(pdev->offset_results.VL53L1_p_002[m]); + + if (status == VL53L1_ERROR_NONE) { + + pdev->offset_results.cal_report = m; + + if (pfs->no_of_samples < num_of_samples[m]) + status = + VL53L1_WARNING_OFFSET_CAL_MISSING_SAMPLES; + + + + + + + if (m == 0 && pfs->VL53L1_p_005 > + ((uint32_t)VL53L1_OFFSET_CAL_MAX_SIGMA_MM << 5)) + status = + VL53L1_WARNING_OFFSET_CAL_SIGMA_TOO_HIGH; + + if (pfs->peak_rate_mcps > + VL53L1_OFFSET_CAL_MAX_PRE_PEAK_RATE_MCPS) + status = + VL53L1_WARNING_OFFSET_CAL_RATE_TOO_HIGH; + + if (pfs->dss_config__manual_effective_spads_select < + VL53L1_OFFSET_CAL_MIN_EFFECTIVE_SPADS) + status = + VL53L1_WARNING_OFFSET_CAL_SPAD_COUNT_TOO_LOW; + + if (pfs->dss_config__manual_effective_spads_select == 0) + status = + VL53L1_ERROR_OFFSET_CAL_NO_SPADS_ENABLED_FAIL; + + if (pfs->no_of_samples == 0) + status = VL53L1_ERROR_OFFSET_CAL_NO_SAMPLE_FAIL; + } + } + + + + + + + pdev->offset_results.cal_status = status; + *pcal_status = pdev->offset_results.cal_status; + + + + + IGNORE_STATUS( + IGNORE_OFFSET_CAL_MISSING_SAMPLES, + VL53L1_WARNING_OFFSET_CAL_MISSING_SAMPLES, + status); + + IGNORE_STATUS( + IGNORE_OFFSET_CAL_SIGMA_TOO_HIGH, + VL53L1_WARNING_OFFSET_CAL_SIGMA_TOO_HIGH, + status); + + IGNORE_STATUS( + IGNORE_OFFSET_CAL_RATE_TOO_HIGH, + VL53L1_WARNING_OFFSET_CAL_RATE_TOO_HIGH, + status); + + IGNORE_STATUS( + IGNORE_OFFSET_CAL_SPAD_COUNT_TOO_LOW, + VL53L1_WARNING_OFFSET_CAL_SPAD_COUNT_TOO_LOW, + status); + +#ifdef VL53L1_LOG_ENABLE + + + + + VL53L1_print_customer_nvm_managed( + &(pdev->customer), + "run_offset_calibration():pdev->lldata.customer.", + VL53L1_TRACE_MODULE_OFFSET_DATA); + + VL53L1_print_dmax_calibration_data( + &(pdev->fmt_dmax_cal), + "run_offset_calibration():pdev->lldata.fmt_dmax_cal.", + VL53L1_TRACE_MODULE_OFFSET_DATA); + + VL53L1_print_dmax_calibration_data( + &(pdev->cust_dmax_cal), + "run_offset_calibration():pdev->lldata.cust_dmax_cal.", + VL53L1_TRACE_MODULE_OFFSET_DATA); + + VL53L1_print_additional_offset_cal_data( + &(pdev->add_off_cal_data), + "run_offset_calibration():pdev->lldata.add_off_cal_data.", + VL53L1_TRACE_MODULE_OFFSET_DATA); + + VL53L1_print_offset_range_results( + &(pdev->offset_results), + "run_offset_calibration():pdev->lldata.offset_results.", + VL53L1_TRACE_MODULE_OFFSET_DATA); +#endif + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_run_phasecal_average( + VL53L1_DEV Dev, + uint8_t measurement_mode, + uint8_t phasecal_result__vcsel_start, + uint16_t phasecal_num_of_samples, + VL53L1_range_results_t *prange_results, + uint16_t *pphasecal_result__reference_phase, + uint16_t *pzero_distance_phase) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + + uint16_t i = 0; + uint16_t m = 0; + uint32_t samples = 0; + + uint32_t period = 0; + uint32_t VL53L1_p_017 = 0; + uint32_t phasecal_result__reference_phase = 0; + uint32_t zero_distance_phase = 0; + + + + VL53L1_load_patch(Dev); + + for (m = 0; m < phasecal_num_of_samples; m++) { + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_init_and_start_range( + Dev, + measurement_mode, + VL53L1_DEVICECONFIGLEVEL_CUSTOMER_ONWARDS); + + for (i = 0; i <= 1; i++) { + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_wait_for_range_completion(Dev); + + + + + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_get_device_results( + Dev, + VL53L1_DEVICERESULTSLEVEL_FULL, + prange_results); + + + + + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_wait_for_firmware_ready(Dev); + + + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_clear_interrupt_and_enable_next_range( + Dev, + measurement_mode); + } + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_stop_range(Dev); + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WaitUs(Dev, 1000); + + + + + if (status == VL53L1_ERROR_NONE) { + + samples++; + + + + + + + + period = 2048 * + (uint32_t)VL53L1_decode_vcsel_period( + pdev->hist_data.VL53L1_p_009); + + VL53L1_p_017 = period; + VL53L1_p_017 += (uint32_t)( + pdev->hist_data.phasecal_result__reference_phase); + VL53L1_p_017 += + (2048 * + (uint32_t)phasecal_result__vcsel_start); + VL53L1_p_017 -= (2048 * + (uint32_t)pdev->hist_data.cal_config__vcsel_start); + + VL53L1_p_017 = VL53L1_p_017 % period; + + phasecal_result__reference_phase += (uint32_t)( + pdev->hist_data.phasecal_result__reference_phase); + + zero_distance_phase += (uint32_t)VL53L1_p_017; + } + } + VL53L1_unload_patch(Dev); + + + + + if (status == VL53L1_ERROR_NONE && samples > 0) { + + phasecal_result__reference_phase += (samples >> 1); + phasecal_result__reference_phase /= samples; + + zero_distance_phase += (samples >> 1); + zero_distance_phase /= samples; + + *pphasecal_result__reference_phase = + (uint16_t)phasecal_result__reference_phase; + *pzero_distance_phase = + (uint16_t)zero_distance_phase; + } + + return status; +} + + +VL53L1_Error VL53L1_run_zone_calibration( + VL53L1_DEV Dev, + VL53L1_DevicePresetModes device_preset_mode, + VL53L1_DeviceZonePreset zone_preset, + VL53L1_zone_config_t *pzone_cfg, + int16_t cal_distance_mm, + uint16_t cal_reflectance_pc, + VL53L1_Error *pcal_status) +{ + + + + + + + + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + + VL53L1_LLDriverResults_t *pres = + VL53L1DevStructGetLLResultsHandle(Dev); + + VL53L1_range_results_t *pRR = + (VL53L1_range_results_t *) pdev->wArea1; + VL53L1_range_data_t *prange_data = NULL; + VL53L1_zone_calibration_data_t *pzone_data = NULL; + + uint16_t i = 0; + uint16_t m = 0; + + uint8_t z = 0; + uint8_t measurement_mode = + VL53L1_DEVICEMEASUREMENTMODE_BACKTOBACK; + + VL53L1_OffsetCorrectionMode offset_cor_mode = + VL53L1_OFFSETCORRECTIONMODE__NONE; + + LOG_FUNCTION_START(""); + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_set_preset_mode( + Dev, + device_preset_mode, + + + pdev->zonecal_cfg.dss_config__target_total_rate_mcps, + pdev->zonecal_cfg.phasecal_config_timeout_us, + pdev->zonecal_cfg.mm_config_timeout_us, + pdev->zonecal_cfg.range_config_timeout_us, + + + 100); + + + + + if (zone_preset == VL53L1_DEVICEZONEPRESET_CUSTOM) { + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_set_zone_config( + Dev, + pzone_cfg); + + } else if (zone_preset != VL53L1_DEVICEZONEPRESET_NONE) { + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_set_zone_preset( + Dev, + zone_preset); + } + + + + + + + pres->zone_cal.preset_mode = device_preset_mode; + pres->zone_cal.zone_preset = zone_preset; + + + pres->zone_cal.cal_distance_mm = cal_distance_mm * 16; + pres->zone_cal.cal_reflectance_pc = cal_reflectance_pc; + pres->zone_cal.max_zones = VL53L1_MAX_USER_ZONES; + pres->zone_cal.active_zones = pdev->zone_cfg.active_zones + 1; + + for (i = 0; i < VL53L1_MAX_USER_ZONES; i++) { + pres->zone_cal.VL53L1_p_002[i].no_of_samples = 0; + pres->zone_cal.VL53L1_p_002[i].effective_spads = 0; + pres->zone_cal.VL53L1_p_002[i].peak_rate_mcps = 0; + pres->zone_cal.VL53L1_p_002[i].VL53L1_p_014 = 0; + pres->zone_cal.VL53L1_p_002[i].VL53L1_p_005 = 0; + pres->zone_cal.VL53L1_p_002[i].median_range_mm = 0; + pres->zone_cal.VL53L1_p_002[i].range_mm_offset = 0; + } + + pres->zone_cal.phasecal_result__reference_phase = 0; + pres->zone_cal.zero_distance_phase = 0; + + + + + + + + status = + VL53L1_get_offset_correction_mode( + Dev, + &offset_cor_mode); + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_set_offset_correction_mode( + Dev, + VL53L1_OFFSETCORRECTIONMODE__NONE); + + + + VL53L1_load_patch(Dev); + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_init_and_start_range( + Dev, + measurement_mode, + VL53L1_DEVICECONFIGLEVEL_CUSTOMER_ONWARDS); + + + + + + + m = (pdev->zonecal_cfg.zone_num_of_samples + 2) * + (uint16_t)pres->zone_cal.active_zones; + + + + for (i = 0; i <= m; i++) { + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_wait_for_range_completion(Dev); + + + + + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_get_device_results( + Dev, + VL53L1_DEVICERESULTSLEVEL_FULL, + pRR); + + + + + + + + + + prange_data = &(pRR->VL53L1_p_002[0]); + + if (pRR->active_results > 0 && + i > (uint16_t)pres->zone_cal.active_zones) { + + if (prange_data->range_status == + VL53L1_DEVICEERROR_RANGECOMPLETE) { + + pres->zone_cal.phasecal_result__reference_phase + = + pdev->hist_data.phasecal_result__reference_phase + ; + pres->zone_cal.zero_distance_phase = + pdev->hist_data.zero_distance_phase; + + pzone_data = + &(pres->zone_cal.VL53L1_p_002[pRR->zone_id]); + pzone_data->no_of_samples++; + pzone_data->effective_spads += + (uint32_t)prange_data->VL53L1_p_006; + pzone_data->peak_rate_mcps += (uint32_t)( + prange_data->peak_signal_count_rate_mcps); + pzone_data->VL53L1_p_014 += + (uint32_t)prange_data->VL53L1_p_014; + pzone_data->VL53L1_p_005 += + (uint32_t)prange_data->VL53L1_p_005; + pzone_data->median_range_mm += + (int32_t)prange_data->median_range_mm; + + } + } + + + + + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_wait_for_firmware_ready(Dev); + + + + + + + + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_clear_interrupt_and_enable_next_range( + Dev, + measurement_mode); + } + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_stop_range(Dev); + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WaitUs(Dev, 1000); + VL53L1_unload_patch(Dev); + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_run_phasecal_average( + Dev, + measurement_mode, + pdev->hist_data.phasecal_result__vcsel_start, + + + pdev->zonecal_cfg.phasecal_num_of_samples, + + + pRR, + &(pres->zone_cal.phasecal_result__reference_phase), + &(pres->zone_cal.zero_distance_phase)); + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_set_offset_correction_mode( + Dev, + offset_cor_mode); + + + + + if (status == VL53L1_ERROR_NONE) { + + for (z = 0; z < pres->zone_cal.active_zones; z++) { + + pzone_data = &(pres->zone_cal.VL53L1_p_002[z]); + + + + if (pzone_data->no_of_samples > 0) { + + pzone_data->effective_spads += + (pzone_data->no_of_samples/2); + pzone_data->effective_spads /= + pzone_data->no_of_samples; + + pzone_data->peak_rate_mcps += + (pzone_data->no_of_samples/2); + pzone_data->peak_rate_mcps /= + pzone_data->no_of_samples; + + pzone_data->VL53L1_p_014 += + (pzone_data->no_of_samples/2); + pzone_data->VL53L1_p_014 /= + pzone_data->no_of_samples; + + pzone_data->VL53L1_p_005 += + (pzone_data->no_of_samples/2); + pzone_data->VL53L1_p_005 /= + pzone_data->no_of_samples; + + + + + + + + pzone_data->median_range_mm = + VL53L1_range_maths( + pdev->stat_nvm.osc_measured__fast_osc__frequency + , (uint16_t)pzone_data->VL53L1_p_014, + pres->zone_cal.zero_distance_phase, + 2, + + 0x0800, + + 0); + + + pzone_data->range_mm_offset = + ((int32_t)cal_distance_mm) * 4; + pzone_data->range_mm_offset -= + pzone_data->median_range_mm; + + + + if (pzone_data->no_of_samples < + pdev->zonecal_cfg.zone_num_of_samples) + status = + VL53L1_WARNING_ZONE_CAL_MISSING_SAMPLES; + + + + if (pzone_data->VL53L1_p_005 > + ((uint32_t)VL53L1_ZONE_CAL_MAX_SIGMA_MM + << 5)) + status = + VL53L1_WARNING_ZONE_CAL_SIGMA_TOO_HIGH; + + if (pzone_data->peak_rate_mcps > + VL53L1_ZONE_CAL_MAX_PRE_PEAK_RATE_MCPS) + status = + VL53L1_WARNING_ZONE_CAL_RATE_TOO_HIGH; + + } else { + status = VL53L1_ERROR_ZONE_CAL_NO_SAMPLE_FAIL; + } + } + } + + + + + + + pres->zone_cal.cal_status = status; + *pcal_status = pres->zone_cal.cal_status; + + + + + IGNORE_STATUS( + IGNORE_ZONE_CAL_MISSING_SAMPLES, + VL53L1_WARNING_ZONE_CAL_MISSING_SAMPLES, + status); + + IGNORE_STATUS( + IGNORE_ZONE_CAL_SIGMA_TOO_HIGH, + VL53L1_WARNING_ZONE_CAL_SIGMA_TOO_HIGH, + status); + + IGNORE_STATUS( + IGNORE_ZONE_CAL_RATE_TOO_HIGH, + VL53L1_WARNING_ZONE_CAL_RATE_TOO_HIGH, + status); + +#ifdef VL53L1_LOG_ENABLE + + + + + VL53L1_print_zone_calibration_results( + &(pres->zone_cal), + "run_zone_calibration():pdev->llresults.zone_cal.", + VL53L1_TRACE_MODULE_OFFSET_DATA); + +#endif + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_run_spad_rate_map( + VL53L1_DEV Dev, + VL53L1_DeviceTestMode device_test_mode, + VL53L1_DeviceSscArray array_select, + uint32_t ssc_config_timeout_us, + VL53L1_spad_rate_data_t *pspad_rate_data) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_powerforce(Dev); + + + + + + + if (status == VL53L1_ERROR_NONE) { + pdev->ssc_cfg.array_select = array_select; + pdev->ssc_cfg.timeout_us = ssc_config_timeout_us; + status = + VL53L1_set_ssc_config( + Dev, + &(pdev->ssc_cfg), + pdev->stat_nvm.osc_measured__fast_osc__frequency); + } + + + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_run_device_test( + Dev, + device_test_mode); + + + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_get_spad_rate_data( + Dev, + pspad_rate_data); + + if (device_test_mode == VL53L1_DEVICETESTMODE_LCR_VCSEL_ON) + pspad_rate_data->fractional_bits = 7; + else + pspad_rate_data->fractional_bits = 15; + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_disable_powerforce(Dev); + +#ifdef VL53L1_LOG_ENABLE + + + + if (status == VL53L1_ERROR_NONE) { + VL53L1_print_spad_rate_data( + pspad_rate_data, + "run_spad_rate_map():", + VL53L1_TRACE_MODULE_SPAD_RATE_MAP); + VL53L1_print_spad_rate_map( + pspad_rate_data, + "run_spad_rate_map():", + VL53L1_TRACE_MODULE_SPAD_RATE_MAP); + } +#endif + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_run_device_test( + VL53L1_DEV Dev, + VL53L1_DeviceTestMode device_test_mode) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + uint8_t comms_buffer[2]; + uint8_t gpio_hv_mux__ctrl = 0; + + LOG_FUNCTION_START(""); + + + + + + + if (status == VL53L1_ERROR_NONE) + + status = + VL53L1_RdByte( + Dev, + VL53L1_GPIO_HV_MUX__CTRL, + &gpio_hv_mux__ctrl); + + if (status == VL53L1_ERROR_NONE) + pdev->stat_cfg.gpio_hv_mux__ctrl = gpio_hv_mux__ctrl; + + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_start_test( + Dev, + device_test_mode); + + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_wait_for_test_completion(Dev); + + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_ReadMulti( + Dev, + VL53L1_RESULT__RANGE_STATUS, + comms_buffer, + 2); + + if (status == VL53L1_ERROR_NONE) { + pdev->sys_results.result__range_status = comms_buffer[0]; + pdev->sys_results.result__report_status = comms_buffer[1]; + } + + + + + pdev->sys_results.result__range_status &= + VL53L1_RANGE_STATUS__RANGE_STATUS_MASK; + + if (status == VL53L1_ERROR_NONE) { + trace_print( + VL53L1_TRACE_LEVEL_INFO, + " Device Test Complete:\n\t%-32s = %3u\n\t%-32s = %3u\n", + "result__range_status", + pdev->sys_results.result__range_status, + "result__report_status", + pdev->sys_results.result__report_status); + + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_clear_interrupt(Dev); + } + + + + + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_start_test( + Dev, + 0x00); + + LOG_FUNCTION_END(status); + + return status; +} + + +void VL53L1_hist_xtalk_extract_data_init( + VL53L1_hist_xtalk_extract_data_t *pxtalk_data) +{ + + + + + + int32_t lb = 0; + + pxtalk_data->sample_count = 0U; + pxtalk_data->pll_period_mm = 0U; + pxtalk_data->peak_duration_us_sum = 0U; + pxtalk_data->effective_spad_count_sum = 0U; + pxtalk_data->zero_distance_phase_sum = 0U; + pxtalk_data->zero_distance_phase_avg = 0U; + pxtalk_data->event_scaler_sum = 0U; + pxtalk_data->event_scaler_avg = 4096U; + pxtalk_data->signal_events_sum = 0; + pxtalk_data->xtalk_rate_kcps_per_spad = 0U; + pxtalk_data->VL53L1_p_015 = 0U; + pxtalk_data->VL53L1_p_016 = 0U; + pxtalk_data->target_start = 0U; + + for (lb = 0; lb < VL53L1_XTALK_HISTO_BINS; lb++) + pxtalk_data->bin_data_sums[lb] = 0; + +} + + +VL53L1_Error VL53L1_hist_xtalk_extract_update( + int16_t target_distance_mm, + uint16_t target_width_oversize, + VL53L1_histogram_bin_data_t *phist_bins, + VL53L1_hist_xtalk_extract_data_t *pxtalk_data) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + status = + VL53L1_hist_xtalk_extract_calc_window( + target_distance_mm, + target_width_oversize, + phist_bins, + pxtalk_data); + + if (status == VL53L1_ERROR_NONE) { + status = + VL53L1_hist_xtalk_extract_calc_event_sums( + phist_bins, + pxtalk_data); + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_hist_xtalk_extract_fini( + VL53L1_histogram_bin_data_t *phist_bins, + VL53L1_hist_xtalk_extract_data_t *pxtalk_data, + VL53L1_xtalk_calibration_results_t *pxtalk_cal, + VL53L1_xtalk_histogram_shape_t *pxtalk_shape) +{ + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_xtalk_calibration_results_t *pX = pxtalk_cal; + + LOG_FUNCTION_START(""); + + if (pxtalk_data->sample_count > 0) { + + + + pxtalk_data->event_scaler_avg = pxtalk_data->event_scaler_sum; + pxtalk_data->event_scaler_avg += + (pxtalk_data->sample_count >> 1); + pxtalk_data->event_scaler_avg /= pxtalk_data->sample_count; + + + + + + + status = + VL53L1_hist_xtalk_extract_calc_rate_per_spad( + pxtalk_data); + + + + + + + if (status == VL53L1_ERROR_NONE) { + + + + pxtalk_data->zero_distance_phase_avg = + pxtalk_data->zero_distance_phase_sum; + pxtalk_data->zero_distance_phase_avg += + (pxtalk_data->sample_count >> 1); + pxtalk_data->zero_distance_phase_avg /= + pxtalk_data->sample_count; + + + + status = + VL53L1_hist_xtalk_extract_calc_shape( + pxtalk_data, + pxtalk_shape); + + + + + + + + + + + + pxtalk_shape->phasecal_result__vcsel_start = + phist_bins->phasecal_result__vcsel_start; + pxtalk_shape->cal_config__vcsel_start = + phist_bins->cal_config__vcsel_start; + pxtalk_shape->vcsel_width = + phist_bins->vcsel_width; + pxtalk_shape->VL53L1_p_019 = + phist_bins->VL53L1_p_019; + } + + + + + + + if (status == VL53L1_ERROR_NONE) { + + + + pX->algo__crosstalk_compensation_plane_offset_kcps = + pxtalk_data->xtalk_rate_kcps_per_spad; + pX->algo__crosstalk_compensation_x_plane_gradient_kcps + = 0U; + pX->algo__crosstalk_compensation_y_plane_gradient_kcps + = 0U; + + } + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_run_hist_xtalk_extraction( + VL53L1_DEV Dev, + int16_t cal_distance_mm, + VL53L1_Error *pcal_status) +{ + #define OVERSIZE 4 + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_xtalkextract_config_t *pX = &(pdev->xtalk_extract_cfg); + VL53L1_xtalk_config_t *pC = &(pdev->xtalk_cfg); + VL53L1_xtalk_calibration_results_t *pXC = &(pdev->xtalk_cal); + uint8_t smudge_corr_en = 0; + uint8_t i = 0; + int8_t k = 0; + uint8_t nbloops; + int32_t initMergeSize = 0; + int32_t MergeEnabled = 0; + uint32_t deltaXtalk; + uint32_t stepXtalk; + uint32_t XtalkMin; + uint32_t XtalkMax; + uint8_t measurement_mode = VL53L1_DEVICEMEASUREMENTMODE_BACKTOBACK; + int8_t MaxId; + uint8_t histo_merge_nb; + uint8_t wait_for_accumulation; + VL53L1_range_results_t *prange_results = + (VL53L1_range_results_t *) pdev->wArea1; + uint8_t Very1stRange = 0; + + LOG_FUNCTION_START(""); + if (status == VL53L1_ERROR_NONE) + + status = + VL53L1_set_preset_mode( + Dev, + VL53L1_DEVICEPRESETMODE_HISTOGRAM_LONG_RANGE, + pX->dss_config__target_total_rate_mcps, + pX->phasecal_config_timeout_us, + pX->mm_config_timeout_us, + pX->range_config_timeout_us, + 100); + if (status != VL53L1_ERROR_NONE) + goto LOOPOUT; + + //if (status == VL53L1_ERROR_NONE) + status = VL53L1_disable_xtalk_compensation(Dev); + if (status != VL53L1_ERROR_NONE) + goto LOOPOUT; + + smudge_corr_en = pdev->smudge_correct_config.smudge_corr_enabled; + + //if (status == VL53L1_ERROR_NONE) + status = VL53L1_dynamic_xtalk_correction_disable(Dev); + if (status != VL53L1_ERROR_NONE) + goto LOOPOUT; + + VL53L1_load_patch(Dev); + + VL53L1_get_tuning_parm(Dev, VL53L1_TUNINGPARM_HIST_MERGE_MAX_SIZE, + &initMergeSize); + VL53L1_get_tuning_parm(Dev, VL53L1_TUNINGPARM_HIST_MERGE, + &MergeEnabled); + memset(&pdev->xtalk_cal, 0, sizeof(pdev->xtalk_cal)); + + //if (status == VL53L1_ERROR_NONE) + status = VL53L1_init_and_start_range( + Dev, measurement_mode, + VL53L1_DEVICECONFIGLEVEL_CUSTOMER_ONWARDS); + if (status != VL53L1_ERROR_NONE) + goto LOOPOUT; + + MaxId = VL53L1_BIN_REC_SIZE - 1; + nbloops = (MergeEnabled == 0 ? 1 : 2); + for (k = 0; k < nbloops; k++) { + VL53L1_hist_xtalk_extract_data_init( + &(pdev->xtalk_extract)); + VL53L1_set_tuning_parm(Dev, + VL53L1_TUNINGPARM_HIST_MERGE_MAX_SIZE, + k * MaxId + 1); + for (i = 0; i <= pX->num_of_samples; i++) { + //if (status == VL53L1_ERROR_NONE) + status = VL53L1_wait_for_range_completion(Dev); + if (status != VL53L1_ERROR_NONE) + goto LOOPOUT; + + //if (status == VL53L1_ERROR_NONE) + status = VL53L1_get_device_results(Dev, + VL53L1_DEVICERESULTSLEVEL_FULL, + prange_results); + if (status != VL53L1_ERROR_NONE) + goto LOOPOUT; + + Very1stRange = + (pdev->ll_state.rd_device_state == + VL53L1_DEVICESTATE_RANGING_WAIT_GPH_SYNC); + VL53L1_compute_histo_merge_nb(Dev, &histo_merge_nb); + wait_for_accumulation = ((k != 0) && + (status == VL53L1_ERROR_NONE) && + (histo_merge_nb < VL53L1_BIN_REC_SIZE)); + + if (wait_for_accumulation) + i = 0; + else { + if ((status == VL53L1_ERROR_NONE) && + (!Very1stRange)) { + status = + VL53L1_hist_xtalk_extract_update( + cal_distance_mm, + OVERSIZE, + &(pdev->hist_data), + &(pdev->xtalk_extract)); + } + if (status != VL53L1_ERROR_NONE) + goto LOOPOUT; + } + + //if (status == VL53L1_ERROR_NONE) + status = VL53L1_wait_for_firmware_ready(Dev); + if (status != VL53L1_ERROR_NONE) + goto LOOPOUT; + + //if (status == VL53L1_ERROR_NONE) + status = + VL53L1_clear_interrupt_and_enable_next_range( + Dev, measurement_mode); + if (status != VL53L1_ERROR_NONE) + goto LOOPOUT; + + //if (status == VL53L1_ERROR_NONE) + status = + VL53L1_hist_xtalk_extract_fini( + &(pdev->hist_data), + &(pdev->xtalk_extract), + &(pdev->xtalk_cal), + &(pdev->xtalk_shapes.xtalk_shape)); + if (status != VL53L1_ERROR_NONE) + goto LOOPOUT; + pXC->algo__xtalk_cpo_HistoMerge_kcps[k * MaxId] = + pXC->algo__crosstalk_compensation_plane_offset_kcps; + } + } + +LOOPOUT: + + status = VL53L1_stop_range(Dev); + + if (status == VL53L1_ERROR_NONE) { + status = VL53L1_set_tuning_parm(Dev, VL53L1_TUNINGPARM_HIST_MERGE_MAX_SIZE, + initMergeSize); + } + status = VL53L1_unload_patch(Dev); + + if (status != VL53L1_ERROR_NONE) + status = VL53L1_ERROR_XTALK_EXTRACTION_SIGMA_LIMIT_FAIL; + else if ((MergeEnabled == 1) && (MaxId > 0)) { + XtalkMin = pXC->algo__xtalk_cpo_HistoMerge_kcps[0]; + XtalkMax = pXC->algo__xtalk_cpo_HistoMerge_kcps[MaxId]; + pXC->algo__crosstalk_compensation_plane_offset_kcps = + XtalkMin; + if (XtalkMax >= XtalkMin) { + deltaXtalk = XtalkMax - XtalkMin; + stepXtalk = deltaXtalk / MaxId; + for (k = 1; k < MaxId; k++) + pXC->algo__xtalk_cpo_HistoMerge_kcps[k] = + XtalkMin + stepXtalk * k; + } else + status = + VL53L1_ERROR_XTALK_EXTRACTION_SIGMA_LIMIT_FAIL; + } + + + if (status == VL53L1_ERROR_NONE) { + pC->algo__crosstalk_compensation_x_plane_gradient_kcps = + pXC->algo__crosstalk_compensation_x_plane_gradient_kcps; + pC->algo__crosstalk_compensation_y_plane_gradient_kcps = + pXC->algo__crosstalk_compensation_y_plane_gradient_kcps; + pC->algo__crosstalk_compensation_plane_offset_kcps = + pXC->algo__crosstalk_compensation_plane_offset_kcps; + } + pdev->xtalk_results.cal_status = status; + *pcal_status = pdev->xtalk_results.cal_status; + + status = VL53L1_enable_xtalk_compensation(Dev); + if (smudge_corr_en == 1) + status = VL53L1_dynamic_xtalk_correction_enable(Dev); + +#ifdef VL53L1_LOG_ENABLE + VL53L1_print_customer_nvm_managed( + &(pdev->customer), + "run_xtalk_extraction():pdev->lldata.customer.", + VL53L1_TRACE_MODULE_XTALK_DATA); + + VL53L1_print_xtalk_config( + &(pdev->xtalk_cfg), + "run_xtalk_extraction():pdev->lldata.xtalk_cfg.", + VL53L1_TRACE_MODULE_XTALK_DATA); + + VL53L1_print_xtalk_histogram_data( + &(pdev->xtalk_shapes), + "pdev->lldata.xtalk_shapes.", + VL53L1_TRACE_MODULE_XTALK_DATA); +#endif + + LOG_FUNCTION_END(status); + + return status; +} + diff --git a/drivers/input/misc/vl53L1/kona/src/vl53l1_api_core.c b/drivers/input/misc/vl53L1/kona/src/vl53l1_api_core.c new file mode 100644 index 000000000000..9cf12aca1705 --- /dev/null +++ b/drivers/input/misc/vl53L1/kona/src/vl53l1_api_core.c @@ -0,0 +1,7798 @@ + +/******************************************************************************* + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#include "vl53l1_ll_def.h" +#include "vl53l1_ll_device.h" +#include "vl53l1_platform.h" +#include "vl53l1_platform_ipp.h" +#include "vl53l1_register_map.h" +#include "vl53l1_register_settings.h" +#include "vl53l1_register_funcs.h" +#include "vl53l1_hist_map.h" +#include "vl53l1_hist_structs.h" +#include "vl53l1_nvm_map.h" +#include "vl53l1_nvm_structs.h" +#include "vl53l1_nvm.h" +#include "vl53l1_core.h" +#include "vl53l1_wait.h" +#include "vl53l1_zone_presets.h" +#include "vl53l1_api_preset_modes.h" +#include "vl53l1_silicon_core.h" +#include "vl53l1_api_core.h" +#include "vl53l1_tuning_parm_defaults.h" + +#ifdef VL53L1_LOG_ENABLE +#include "vl53l1_api_debug.h" +#endif + +#define LOG_FUNCTION_START(fmt, ...) \ + _LOG_FUNCTION_START(VL53L1_TRACE_MODULE_CORE, fmt, ##__VA_ARGS__) +#define LOG_FUNCTION_END(status, ...) \ + _LOG_FUNCTION_END(VL53L1_TRACE_MODULE_CORE, status, ##__VA_ARGS__) +#define LOG_FUNCTION_END_FMT(status, fmt, ...) \ + _LOG_FUNCTION_END_FMT(VL53L1_TRACE_MODULE_CORE, status, \ + fmt, ##__VA_ARGS__) + +#define trace_print(level, ...) \ + _LOG_TRACE_PRINT(VL53L1_TRACE_MODULE_CORE, \ + level, VL53L1_TRACE_FUNCTION_NONE, ##__VA_ARGS__) + +#define VL53L1_MAX_I2C_XFER_SIZE 256 + +static VL53L1_Error select_offset_per_vcsel(VL53L1_LLDriverData_t *pdev, + int16_t *poffset) { + VL53L1_Error status = VL53L1_ERROR_NONE; + int16_t tA, tB; + + switch (pdev->preset_mode) { + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_SHORT_RANGE: + tA = pdev->per_vcsel_cal_data.short_a_offset_mm; + tB = pdev->per_vcsel_cal_data.short_b_offset_mm; + break; + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_MEDIUM_RANGE: + tA = pdev->per_vcsel_cal_data.medium_a_offset_mm; + tB = pdev->per_vcsel_cal_data.medium_b_offset_mm; + break; + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_LONG_RANGE: + tA = pdev->per_vcsel_cal_data.long_a_offset_mm; + tB = pdev->per_vcsel_cal_data.long_b_offset_mm; + break; + default: + status = VL53L1_ERROR_INVALID_PARAMS; + *poffset = 0; + break; + } + + if (status == VL53L1_ERROR_NONE) + *poffset = + ((pdev->ll_state.cfg_internal_stream_count) & 0x01) ? tA : tB; + + return status; +} + +VL53L1_Error VL53L1_load_patch( + VL53L1_DEV Dev) { + VL53L1_Error status = VL53L1_ERROR_NONE; + int32_t patch_tuning = 0; + uint8_t comms_buffer[256]; + uint32_t patch_power; + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WrByte(Dev, + VL53L1_FIRMWARE__ENABLE, 0x00); + + + if (status == VL53L1_ERROR_NONE) + VL53L1_enable_powerforce(Dev); + + VL53L1_get_tuning_parm(Dev, VL53L1_TUNINGPARM_PHASECAL_PATCH_POWER, + &patch_tuning); + + switch (patch_tuning) { + case 0: + patch_power = 0x00; + break; + case 1: + patch_power = 0x10; + break; + case 2: + patch_power = 0x20; + break; + case 3: + patch_power = 0x40; + break; + default: + patch_power = 0x00; + } + + + if (status == VL53L1_ERROR_NONE) { + + + comms_buffer[0] = 0x29; + comms_buffer[1] = 0xC9; + comms_buffer[2] = 0x0E; + comms_buffer[3] = 0x40; + comms_buffer[4] = 0x28; + comms_buffer[5] = patch_power; + + + status = VL53L1_WriteMulti(Dev, + VL53L1_PATCH__OFFSET_0, comms_buffer, 6); + } + + + if (status == VL53L1_ERROR_NONE) { + comms_buffer[0] = 0x03; + comms_buffer[1] = 0x6D; + comms_buffer[2] = 0x03; + comms_buffer[3] = 0x6F; + comms_buffer[4] = 0x07; + comms_buffer[5] = 0x29; + status = VL53L1_WriteMulti(Dev, + VL53L1_PATCH__ADDRESS_0, comms_buffer, 6); + } + + + if (status == VL53L1_ERROR_NONE) { + comms_buffer[0] = 0x00; + comms_buffer[1] = 0x07; + status = VL53L1_WriteMulti(Dev, + VL53L1_PATCH__JMP_ENABLES, comms_buffer, 2); + } + + + if (status == VL53L1_ERROR_NONE) { + comms_buffer[0] = 0x00; + comms_buffer[1] = 0x07; + status = VL53L1_WriteMulti(Dev, + VL53L1_PATCH__DATA_ENABLES, comms_buffer, 2); + } + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WrByte(Dev, + VL53L1_PATCH__CTRL, 0x01); + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WrByte(Dev, + VL53L1_FIRMWARE__ENABLE, 0x01); + + LOG_FUNCTION_END(status); + + return status; +} + +VL53L1_Error VL53L1_unload_patch( + VL53L1_DEV Dev) { + VL53L1_Error status = VL53L1_ERROR_NONE; + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WrByte(Dev, + VL53L1_FIRMWARE__ENABLE, 0x00); + + + if (status == VL53L1_ERROR_NONE) + VL53L1_disable_powerforce(Dev); + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WrByte(Dev, + VL53L1_PATCH__CTRL, 0x00); + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WrByte(Dev, + VL53L1_FIRMWARE__ENABLE, 0x01); + + LOG_FUNCTION_END(status); + + return status; +} + +VL53L1_Error VL53L1_get_version( + VL53L1_DEV Dev, + VL53L1_ll_version_t *pdata) +{ + + + + + + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + VL53L1_init_version(Dev); + + memcpy(pdata, &(pdev->version), sizeof(VL53L1_ll_version_t)); + + return VL53L1_ERROR_NONE; +} + + +VL53L1_Error VL53L1_get_device_firmware_version( + VL53L1_DEV Dev, + uint16_t *pfw_version) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_disable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_RdWord( + Dev, + VL53L1_MCU_GENERAL_PURPOSE__GP_0, + pfw_version); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_firmware(Dev); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_data_init( + VL53L1_DEV Dev, + uint8_t read_p2p_data) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_LLDriverResults_t *pres = + VL53L1DevStructGetLLResultsHandle(Dev); + + + + + VL53L1_zone_objects_t *pobjects; + + uint8_t i = 0; + + LOG_FUNCTION_START(""); + + VL53L1_init_ll_driver_state( + Dev, + VL53L1_DEVICESTATE_UNKNOWN); + + pres->range_results.max_results = VL53L1_MAX_RANGE_RESULTS; + pres->range_results.active_results = 0; + pres->zone_results.max_zones = VL53L1_MAX_USER_ZONES; + pres->zone_results.active_zones = 0; + + for (i = 0; i < VL53L1_MAX_USER_ZONES; i++) { + pobjects = &(pres->zone_results.VL53L1_p_002[i]); + pobjects->xmonitor.VL53L1_p_020 = 0; + pobjects->xmonitor.VL53L1_p_021 = 0; + pobjects->xmonitor.VL53L1_p_014 = 0; + pobjects->xmonitor.range_status = + VL53L1_DEVICEERROR_NOUPDATE; + } + + + + + pres->zone_hists.max_zones = VL53L1_MAX_USER_ZONES; + pres->zone_hists.active_zones = 0; + + + + + pres->zone_cal.max_zones = VL53L1_MAX_USER_ZONES; + pres->zone_cal.active_zones = 0; + for (i = 0; i < VL53L1_MAX_USER_ZONES; i++) { + pres->zone_cal.VL53L1_p_002[i].no_of_samples = 0; + pres->zone_cal.VL53L1_p_002[i].effective_spads = 0; + pres->zone_cal.VL53L1_p_002[i].peak_rate_mcps = 0; + pres->zone_cal.VL53L1_p_002[i].median_range_mm = 0; + pres->zone_cal.VL53L1_p_002[i].range_mm_offset = 0; + } + + pdev->wait_method = VL53L1_WAIT_METHOD_BLOCKING; + pdev->preset_mode = VL53L1_DEVICEPRESETMODE_STANDARD_RANGING; + pdev->zone_preset = VL53L1_DEVICEZONEPRESET_NONE; + pdev->measurement_mode = VL53L1_DEVICEMEASUREMENTMODE_STOP; + + pdev->offset_calibration_mode = + VL53L1_OFFSETCALIBRATIONMODE__MM1_MM2__STANDARD; + pdev->offset_correction_mode = + VL53L1_OFFSETCORRECTIONMODE__MM1_MM2_OFFSETS; + pdev->dmax_mode = + VL53L1_DEVICEDMAXMODE__FMT_CAL_DATA; + + pdev->phasecal_config_timeout_us = 1000; + pdev->mm_config_timeout_us = 2000; + pdev->range_config_timeout_us = 13000; + pdev->inter_measurement_period_ms = 100; + pdev->dss_config__target_total_rate_mcps = 0x0A00; + pdev->debug_mode = 0x00; + + pdev->offset_results.max_results = VL53L1_MAX_OFFSET_RANGE_RESULTS; + pdev->offset_results.active_results = 0; + + + + + + pdev->gain_cal.standard_ranging_gain_factor = + VL53L1_TUNINGPARM_LITE_RANGING_GAIN_FACTOR_DEFAULT; + pdev->gain_cal.histogram_ranging_gain_factor = + VL53L1_TUNINGPARM_HIST_GAIN_FACTOR_DEFAULT; + + + + + + VL53L1_init_version(Dev); + + + + memset(pdev->multi_bins_rec, 0, sizeof(pdev->multi_bins_rec)); + pdev->bin_rec_pos = 0; + pdev->pos_before_next_recom = 0; + + + + + + + + + + + if (read_p2p_data > 0 && status == VL53L1_ERROR_NONE) + + status = VL53L1_read_p2p_data(Dev); + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_init_refspadchar_config_struct( + &(pdev->refspadchar)); + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_init_ssc_config_struct( + &(pdev->ssc_cfg)); + + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_init_xtalk_config_struct( + &(pdev->customer), + &(pdev->xtalk_cfg)); + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_init_xtalk_extract_config_struct( + &(pdev->xtalk_extract_cfg)); + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_init_offset_cal_config_struct( + &(pdev->offsetcal_cfg)); + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_init_zone_cal_config_struct( + &(pdev->zonecal_cfg)); + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_init_hist_post_process_config_struct( + pdev->xtalk_cfg.global_crosstalk_compensation_enable, + &(pdev->histpostprocess)); + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_init_hist_gen3_dmax_config_struct( + &(pdev->dmax_cfg)); + + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_init_tuning_parm_storage_struct( + &(pdev->tuning_parms)); + + + + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_set_preset_mode( + Dev, + pdev->preset_mode, + pdev->dss_config__target_total_rate_mcps, + + pdev->phasecal_config_timeout_us, + pdev->mm_config_timeout_us, + pdev->range_config_timeout_us, + pdev->inter_measurement_period_ms); + + + + VL53L1_init_histogram_bin_data_struct( + 0, + VL53L1_HISTOGRAM_BUFFER_SIZE, + &(pdev->hist_data)); + + VL53L1_init_histogram_bin_data_struct( + 0, + VL53L1_HISTOGRAM_BUFFER_SIZE, + &(pdev->hist_xtalk)); + + + + VL53L1_init_xtalk_bin_data_struct( + 0, + VL53L1_XTALK_HISTO_BINS, + &(pdev->xtalk_shapes.xtalk_shape)); + + + + + + VL53L1_xtalk_cal_data_init( + Dev + ); + + + + + + VL53L1_dynamic_xtalk_correction_data_init( + Dev + ); + + + + + + VL53L1_low_power_auto_data_init( + Dev + ); + +#ifdef VL53L1_LOG_ENABLE + + + + + VL53L1_print_static_nvm_managed( + &(pdev->stat_nvm), + "data_init():pdev->lldata.stat_nvm.", + VL53L1_TRACE_MODULE_DATA_INIT); + + VL53L1_print_customer_nvm_managed( + &(pdev->customer), + "data_init():pdev->lldata.customer.", + VL53L1_TRACE_MODULE_DATA_INIT); + + VL53L1_print_nvm_copy_data( + &(pdev->nvm_copy_data), + "data_init():pdev->lldata.nvm_copy_data.", + VL53L1_TRACE_MODULE_DATA_INIT); + + VL53L1_print_dmax_calibration_data( + &(pdev->fmt_dmax_cal), + "data_init():pdev->lldata.fmt_dmax_cal.", + VL53L1_TRACE_MODULE_DATA_INIT); + + VL53L1_print_dmax_calibration_data( + &(pdev->cust_dmax_cal), + "data_init():pdev->lldata.cust_dmax_cal.", + VL53L1_TRACE_MODULE_DATA_INIT); + + VL53L1_print_additional_offset_cal_data( + &(pdev->add_off_cal_data), + "data_init():pdev->lldata.add_off_cal_data.", + VL53L1_TRACE_MODULE_DATA_INIT); + + VL53L1_print_user_zone( + &(pdev->mm_roi), + "data_init():pdev->lldata.mm_roi.", + VL53L1_TRACE_MODULE_DATA_INIT); + + VL53L1_print_optical_centre( + &(pdev->optical_centre), + "data_init():pdev->lldata.optical_centre.", + VL53L1_TRACE_MODULE_DATA_INIT); + + VL53L1_print_cal_peak_rate_map( + &(pdev->cal_peak_rate_map), + "data_init():pdev->lldata.cal_peak_rate_map.", + VL53L1_TRACE_MODULE_DATA_INIT); + +#endif + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_read_p2p_data( + VL53L1_DEV Dev) +{ + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_hist_post_process_config_t *pHP = &(pdev->histpostprocess); + VL53L1_customer_nvm_managed_t *pN = &(pdev->customer); + VL53L1_additional_offset_cal_data_t *pCD = &(pdev->add_off_cal_data); + + VL53L1_decoded_nvm_fmt_range_data_t fmt_rrd; + + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_get_static_nvm_managed( + Dev, + &(pdev->stat_nvm)); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_get_customer_nvm_managed( + Dev, + &(pdev->customer)); + + if (status == VL53L1_ERROR_NONE) { + + status = VL53L1_get_nvm_copy_data( + Dev, + &(pdev->nvm_copy_data)); + + + + if (status == VL53L1_ERROR_NONE) + VL53L1_copy_rtn_good_spads_to_buffer( + &(pdev->nvm_copy_data), + &(pdev->rtn_good_spads[0])); + } + + + + + if (status == VL53L1_ERROR_NONE) { + pHP->algo__crosstalk_compensation_plane_offset_kcps = + pN->algo__crosstalk_compensation_plane_offset_kcps; + pHP->algo__crosstalk_compensation_x_plane_gradient_kcps = + pN->algo__crosstalk_compensation_x_plane_gradient_kcps; + pHP->algo__crosstalk_compensation_y_plane_gradient_kcps = + pN->algo__crosstalk_compensation_y_plane_gradient_kcps; + } + + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_read_nvm_optical_centre( + Dev, + &(pdev->optical_centre)); + + + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_read_nvm_cal_peak_rate_map( + Dev, + &(pdev->cal_peak_rate_map)); + + + + + + + if (status == VL53L1_ERROR_NONE) { + + status = + VL53L1_read_nvm_additional_offset_cal_data( + Dev, + &(pdev->add_off_cal_data)); + + + + + + + if (pCD->result__mm_inner_peak_signal_count_rtn_mcps == 0 && + pCD->result__mm_outer_peak_signal_count_rtn_mcps == 0) { + + pCD->result__mm_inner_peak_signal_count_rtn_mcps + = 0x0080; + + pCD->result__mm_outer_peak_signal_count_rtn_mcps + = 0x0180; + + + + + + VL53L1_calc_mm_effective_spads( + pdev->nvm_copy_data.roi_config__mode_roi_centre_spad, + pdev->nvm_copy_data.roi_config__mode_roi_xy_size, + 0xC7, + + 0xFF, + &(pdev->rtn_good_spads[0]), + VL53L1_RTN_SPAD_APERTURE_TRANSMISSION, + &(pCD->result__mm_inner_actual_effective_spads), + &(pCD->result__mm_outer_actual_effective_spads)); + } + } + + + + + + if (status == VL53L1_ERROR_NONE) { + + status = + VL53L1_read_nvm_fmt_range_results_data( + Dev, + VL53L1_NVM__FMT__RANGE_RESULTS__140MM_DARK, + &fmt_rrd); + + if (status == VL53L1_ERROR_NONE) { + pdev->fmt_dmax_cal.ref__actual_effective_spads = + fmt_rrd.result__actual_effective_rtn_spads; + pdev->fmt_dmax_cal.ref__peak_signal_count_rate_mcps = + fmt_rrd.result__peak_signal_count_rate_rtn_mcps; + pdev->fmt_dmax_cal.ref__distance_mm = + fmt_rrd.measured_distance_mm; + + + + + + + if (pdev->cal_peak_rate_map.cal_reflectance_pc != 0) { + pdev->fmt_dmax_cal.ref_reflectance_pc = + pdev->cal_peak_rate_map.cal_reflectance_pc; + } else { + pdev->fmt_dmax_cal.ref_reflectance_pc = 0x0014; + } + + + + pdev->fmt_dmax_cal.coverglass_transmission = 0x0100; + } + } + + + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_RdWord( + Dev, + VL53L1_RESULT__OSC_CALIBRATE_VAL, + &(pdev->dbg_results.result__osc_calibrate_val)); + + + + + + + if (pdev->stat_nvm.osc_measured__fast_osc__frequency < 0x1000) { + trace_print( + VL53L1_TRACE_LEVEL_WARNING, + "\nInvalid %s value (0x%04X) - forcing to 0x%04X\n\n", + "pdev->stat_nvm.osc_measured__fast_osc__frequency", + pdev->stat_nvm.osc_measured__fast_osc__frequency, + 0xBCCC); + pdev->stat_nvm.osc_measured__fast_osc__frequency = 0xBCCC; + } + + + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_get_mode_mitigation_roi( + Dev, + &(pdev->mm_roi)); + + + + + + + if (pdev->optical_centre.x_centre == 0 && + pdev->optical_centre.y_centre == 0) { + pdev->optical_centre.x_centre = + pdev->mm_roi.x_centre << 4; + pdev->optical_centre.y_centre = + pdev->mm_roi.y_centre << 4; + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_software_reset( + VL53L1_DEV Dev) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_WrByte( + Dev, + VL53L1_SOFT_RESET, + 0x00); + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_WaitUs( + Dev, + VL53L1_SOFTWARE_RESET_DURATION_US); + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WrByte( + Dev, + VL53L1_SOFT_RESET, + 0x01); + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_wait_for_boot_completion(Dev); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_part_to_part_data( + VL53L1_DEV Dev, + VL53L1_calibration_data_t *pcal_data) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_xtalk_config_t *pC = &(pdev->xtalk_cfg); + VL53L1_hist_post_process_config_t *pHP = &(pdev->histpostprocess); + VL53L1_customer_nvm_managed_t *pN = &(pdev->customer); + + uint32_t tempu32; + + LOG_FUNCTION_START(""); + + if (pcal_data->struct_version != + VL53L1_LL_CALIBRATION_DATA_STRUCT_VERSION) { + status = VL53L1_ERROR_INVALID_PARAMS; + } + + if (status == VL53L1_ERROR_NONE) { + + + + memcpy( + &(pdev->customer), + &(pcal_data->customer), + sizeof(VL53L1_customer_nvm_managed_t)); + + + + memcpy( + &(pdev->add_off_cal_data), + &(pcal_data->add_off_cal_data), + sizeof(VL53L1_additional_offset_cal_data_t)); + + + + memcpy( + &(pdev->fmt_dmax_cal), + &(pcal_data->fmt_dmax_cal), + sizeof(VL53L1_dmax_calibration_data_t)); + + + + memcpy( + &(pdev->cust_dmax_cal), + &(pcal_data->cust_dmax_cal), + sizeof(VL53L1_dmax_calibration_data_t)); + + + + memcpy( + &(pdev->xtalk_shapes), + &(pcal_data->xtalkhisto), + sizeof(VL53L1_xtalk_histogram_data_t)); + + + + memcpy( + &(pdev->gain_cal), + &(pcal_data->gain_cal), + sizeof(VL53L1_gain_calibration_data_t)); + + + + memcpy( + &(pdev->cal_peak_rate_map), + &(pcal_data->cal_peak_rate_map), + sizeof(VL53L1_cal_peak_rate_map_t)); + + + + memcpy( + &(pdev->per_vcsel_cal_data), + &(pcal_data->per_vcsel_cal_data), + sizeof(VL53L1_per_vcsel_period_offset_cal_data_t)); + + + + + + + pC->algo__crosstalk_compensation_plane_offset_kcps = + pN->algo__crosstalk_compensation_plane_offset_kcps; + pC->algo__crosstalk_compensation_x_plane_gradient_kcps = + pN->algo__crosstalk_compensation_x_plane_gradient_kcps; + pC->algo__crosstalk_compensation_y_plane_gradient_kcps = + pN->algo__crosstalk_compensation_y_plane_gradient_kcps; + + pHP->algo__crosstalk_compensation_plane_offset_kcps = + VL53L1_calc_crosstalk_plane_offset_with_margin( + pC->algo__crosstalk_compensation_plane_offset_kcps, + pC->histogram_mode_crosstalk_margin_kcps); + + pHP->algo__crosstalk_compensation_x_plane_gradient_kcps = + pC->algo__crosstalk_compensation_x_plane_gradient_kcps; + pHP->algo__crosstalk_compensation_y_plane_gradient_kcps = + pC->algo__crosstalk_compensation_y_plane_gradient_kcps; + + + + + if (pC->global_crosstalk_compensation_enable == 0x00) { + pN->algo__crosstalk_compensation_plane_offset_kcps = + 0x00; + pN->algo__crosstalk_compensation_x_plane_gradient_kcps = + 0x00; + pN->algo__crosstalk_compensation_y_plane_gradient_kcps = + 0x00; + } else { + tempu32 = + VL53L1_calc_crosstalk_plane_offset_with_margin( + pC->algo__crosstalk_compensation_plane_offset_kcps, + pC->lite_mode_crosstalk_margin_kcps); + + + + if (tempu32 > 0xFFFF) + tempu32 = 0xFFFF; + + pN->algo__crosstalk_compensation_plane_offset_kcps = + (uint16_t)tempu32; + } + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_part_to_part_data( + VL53L1_DEV Dev, + VL53L1_calibration_data_t *pcal_data) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_xtalk_config_t *pC = &(pdev->xtalk_cfg); + VL53L1_customer_nvm_managed_t *pCN = &(pcal_data->customer); + + LOG_FUNCTION_START(""); + + pcal_data->struct_version = + VL53L1_LL_CALIBRATION_DATA_STRUCT_VERSION; + + + + memcpy( + &(pcal_data->customer), + &(pdev->customer), + sizeof(VL53L1_customer_nvm_managed_t)); + + + + + + + if (pC->algo__crosstalk_compensation_plane_offset_kcps > 0xFFFF) { + pCN->algo__crosstalk_compensation_plane_offset_kcps = + 0xFFFF; + } else { + pCN->algo__crosstalk_compensation_plane_offset_kcps = + (uint16_t)pC->algo__crosstalk_compensation_plane_offset_kcps; + } + pCN->algo__crosstalk_compensation_x_plane_gradient_kcps = + pC->algo__crosstalk_compensation_x_plane_gradient_kcps; + pCN->algo__crosstalk_compensation_y_plane_gradient_kcps = + pC->algo__crosstalk_compensation_y_plane_gradient_kcps; + + + + memcpy( + &(pcal_data->fmt_dmax_cal), + &(pdev->fmt_dmax_cal), + sizeof(VL53L1_dmax_calibration_data_t)); + + + + memcpy( + &(pcal_data->cust_dmax_cal), + &(pdev->cust_dmax_cal), + sizeof(VL53L1_dmax_calibration_data_t)); + + + + memcpy( + &(pcal_data->add_off_cal_data), + &(pdev->add_off_cal_data), + sizeof(VL53L1_additional_offset_cal_data_t)); + + + + memcpy( + &(pcal_data->optical_centre), + &(pdev->optical_centre), + sizeof(VL53L1_optical_centre_t)); + + + + memcpy( + &(pcal_data->xtalkhisto), + &(pdev->xtalk_shapes), + sizeof(VL53L1_xtalk_histogram_data_t)); + + + + memcpy( + &(pcal_data->gain_cal), + &(pdev->gain_cal), + sizeof(VL53L1_gain_calibration_data_t)); + + + + memcpy( + &(pcal_data->cal_peak_rate_map), + &(pdev->cal_peak_rate_map), + sizeof(VL53L1_cal_peak_rate_map_t)); + + + + memcpy( + &(pcal_data->per_vcsel_cal_data), + &(pdev->per_vcsel_cal_data), + sizeof(VL53L1_per_vcsel_period_offset_cal_data_t)); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_inter_measurement_period_ms( + VL53L1_DEV Dev, + uint32_t inter_measurement_period_ms) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + if (pdev->dbg_results.result__osc_calibrate_val == 0) + status = VL53L1_ERROR_DIVISION_BY_ZERO; + + if (status == VL53L1_ERROR_NONE) { + pdev->inter_measurement_period_ms = inter_measurement_period_ms; + pdev->tim_cfg.system__intermeasurement_period = + inter_measurement_period_ms * + (uint32_t)pdev->dbg_results.result__osc_calibrate_val; + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_inter_measurement_period_ms( + VL53L1_DEV Dev, + uint32_t *pinter_measurement_period_ms) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + if (pdev->dbg_results.result__osc_calibrate_val == 0) + status = VL53L1_ERROR_DIVISION_BY_ZERO; + + if (status == VL53L1_ERROR_NONE) + *pinter_measurement_period_ms = + pdev->tim_cfg.system__intermeasurement_period / + (uint32_t)pdev->dbg_results.result__osc_calibrate_val; + + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_timeouts_us( + VL53L1_DEV Dev, + uint32_t phasecal_config_timeout_us, + uint32_t mm_config_timeout_us, + uint32_t range_config_timeout_us) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + if (pdev->stat_nvm.osc_measured__fast_osc__frequency == 0) + status = VL53L1_ERROR_DIVISION_BY_ZERO; + + if (status == VL53L1_ERROR_NONE) { + + pdev->phasecal_config_timeout_us = phasecal_config_timeout_us; + pdev->mm_config_timeout_us = mm_config_timeout_us; + pdev->range_config_timeout_us = range_config_timeout_us; + + status = + VL53L1_calc_timeout_register_values( + phasecal_config_timeout_us, + mm_config_timeout_us, + range_config_timeout_us, + pdev->stat_nvm.osc_measured__fast_osc__frequency, + &(pdev->gen_cfg), + &(pdev->tim_cfg)); + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_timeouts_us( + VL53L1_DEV Dev, + uint32_t *pphasecal_config_timeout_us, + uint32_t *pmm_config_timeout_us, + uint32_t *prange_config_timeout_us) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + + uint32_t macro_period_us = 0; + uint16_t timeout_encoded = 0; + + LOG_FUNCTION_START(""); + + if (pdev->stat_nvm.osc_measured__fast_osc__frequency == 0) + status = VL53L1_ERROR_DIVISION_BY_ZERO; + + if (status == VL53L1_ERROR_NONE) { + + + + macro_period_us = + VL53L1_calc_macro_period_us( + pdev->stat_nvm.osc_measured__fast_osc__frequency, + pdev->tim_cfg.range_config__vcsel_period_a); + + + + + *pphasecal_config_timeout_us = + VL53L1_calc_timeout_us( + (uint32_t)pdev->gen_cfg.phasecal_config__timeout_macrop, + macro_period_us); + + + + + timeout_encoded = + (uint16_t)pdev->tim_cfg.mm_config__timeout_macrop_a_hi; + timeout_encoded = (timeout_encoded << 8) + + (uint16_t)pdev->tim_cfg.mm_config__timeout_macrop_a_lo; + + *pmm_config_timeout_us = + VL53L1_calc_decoded_timeout_us( + timeout_encoded, + macro_period_us); + + + + + timeout_encoded = + (uint16_t)pdev->tim_cfg.range_config__timeout_macrop_a_hi; + timeout_encoded = (timeout_encoded << 8) + + (uint16_t)pdev->tim_cfg.range_config__timeout_macrop_a_lo; + + *prange_config_timeout_us = + VL53L1_calc_decoded_timeout_us( + timeout_encoded, + macro_period_us); + + pdev->phasecal_config_timeout_us = *pphasecal_config_timeout_us; + pdev->mm_config_timeout_us = *pmm_config_timeout_us; + pdev->range_config_timeout_us = *prange_config_timeout_us; + + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_calibration_repeat_period( + VL53L1_DEV Dev, + uint16_t cal_config__repeat_period) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + + pdev->gen_cfg.cal_config__repeat_rate = cal_config__repeat_period; + + return status; + +} + + +VL53L1_Error VL53L1_get_calibration_repeat_period( + VL53L1_DEV Dev, + uint16_t *pcal_config__repeat_period) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + + *pcal_config__repeat_period = pdev->gen_cfg.cal_config__repeat_rate; + + return status; + +} + + +VL53L1_Error VL53L1_set_sequence_config_bit( + VL53L1_DEV Dev, + VL53L1_DeviceSequenceConfig bit_id, + uint8_t value) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + + uint8_t bit_mask = 0x01; + uint8_t clr_mask = 0xFF - bit_mask; + uint8_t bit_value = value & bit_mask; + + if (bit_id <= VL53L1_DEVICESEQUENCECONFIG_RANGE) { + + if (bit_id > 0) { + bit_mask = 0x01 << bit_id; + bit_value = bit_value << bit_id; + clr_mask = 0xFF - bit_mask; + } + + pdev->dyn_cfg.system__sequence_config = + (pdev->dyn_cfg.system__sequence_config & clr_mask) | + bit_value; + + } else { + status = VL53L1_ERROR_INVALID_PARAMS; + } + + return status; + +} + + +VL53L1_Error VL53L1_get_sequence_config_bit( + VL53L1_DEV Dev, + VL53L1_DeviceSequenceConfig bit_id, + uint8_t *pvalue) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + + uint8_t bit_mask = 0x01; + + if (bit_id <= VL53L1_DEVICESEQUENCECONFIG_RANGE) { + + if (bit_id > 0) + bit_mask = 0x01 << bit_id; + + *pvalue = + pdev->dyn_cfg.system__sequence_config & bit_mask; + + if (bit_id > 0) + *pvalue = *pvalue >> bit_id; + + } else { + status = VL53L1_ERROR_INVALID_PARAMS; + } + + return status; +} + + +VL53L1_Error VL53L1_set_interrupt_polarity( + VL53L1_DEV Dev, + VL53L1_DeviceInterruptPolarity interrupt_polarity) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + + pdev->stat_cfg.gpio_hv_mux__ctrl = + (pdev->stat_cfg.gpio_hv_mux__ctrl & + VL53L1_DEVICEINTERRUPTPOLARITY_CLEAR_MASK) | + (interrupt_polarity & + VL53L1_DEVICEINTERRUPTPOLARITY_BIT_MASK); + + return status; + +} + + +VL53L1_Error VL53L1_set_refspadchar_config_struct( + VL53L1_DEV Dev, + VL53L1_refspadchar_config_t *pdata) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + pdev->refspadchar.device_test_mode = pdata->device_test_mode; + pdev->refspadchar.VL53L1_p_009 = pdata->VL53L1_p_009; + pdev->refspadchar.timeout_us = pdata->timeout_us; + pdev->refspadchar.target_count_rate_mcps = + pdata->target_count_rate_mcps; + pdev->refspadchar.min_count_rate_limit_mcps = + pdata->min_count_rate_limit_mcps; + pdev->refspadchar.max_count_rate_limit_mcps = + pdata->max_count_rate_limit_mcps; + + LOG_FUNCTION_END(status); + + return status; +} + +VL53L1_Error VL53L1_get_refspadchar_config_struct( + VL53L1_DEV Dev, + VL53L1_refspadchar_config_t *pdata) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + pdata->device_test_mode = pdev->refspadchar.device_test_mode; + pdata->VL53L1_p_009 = pdev->refspadchar.VL53L1_p_009; + pdata->timeout_us = pdev->refspadchar.timeout_us; + pdata->target_count_rate_mcps = + pdev->refspadchar.target_count_rate_mcps; + pdata->min_count_rate_limit_mcps = + pdev->refspadchar.min_count_rate_limit_mcps; + pdata->max_count_rate_limit_mcps = + pdev->refspadchar.max_count_rate_limit_mcps; + + LOG_FUNCTION_END(status); + + return status; +} + + + +VL53L1_Error VL53L1_set_range_ignore_threshold( + VL53L1_DEV Dev, + uint8_t range_ignore_thresh_mult, + uint16_t range_ignore_threshold_mcps) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + + pdev->xtalk_cfg.crosstalk_range_ignore_threshold_rate_mcps = + range_ignore_threshold_mcps; + + pdev->xtalk_cfg.crosstalk_range_ignore_threshold_mult = + range_ignore_thresh_mult; + + return status; + +} + +VL53L1_Error VL53L1_get_range_ignore_threshold( + VL53L1_DEV Dev, + uint8_t *prange_ignore_thresh_mult, + uint16_t *prange_ignore_threshold_mcps_internal, + uint16_t *prange_ignore_threshold_mcps_current) +{ + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + + *prange_ignore_thresh_mult = + pdev->xtalk_cfg.crosstalk_range_ignore_threshold_mult; + + *prange_ignore_threshold_mcps_current = + pdev->stat_cfg.algo__range_ignore_threshold_mcps; + + *prange_ignore_threshold_mcps_internal = + pdev->xtalk_cfg.crosstalk_range_ignore_threshold_rate_mcps; + + return status; + +} + + + +VL53L1_Error VL53L1_get_interrupt_polarity( + VL53L1_DEV Dev, + VL53L1_DeviceInterruptPolarity *pinterrupt_polarity) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + + *pinterrupt_polarity = + pdev->stat_cfg.gpio_hv_mux__ctrl & + VL53L1_DEVICEINTERRUPTPOLARITY_BIT_MASK; + + return status; + +} + + +VL53L1_Error VL53L1_set_user_zone( + VL53L1_DEV Dev, + VL53L1_user_zone_t *puser_zone) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + + + VL53L1_encode_row_col( + puser_zone->y_centre, + puser_zone->x_centre, + &(pdev->dyn_cfg.roi_config__user_roi_centre_spad)); + + + + VL53L1_encode_zone_size( + puser_zone->width, + puser_zone->height, + &(pdev->dyn_cfg.roi_config__user_roi_requested_global_xy_size)); + + + + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_user_zone( + VL53L1_DEV Dev, + VL53L1_user_zone_t *puser_zone) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + + + VL53L1_decode_row_col( + pdev->dyn_cfg.roi_config__user_roi_centre_spad, + &(puser_zone->y_centre), + &(puser_zone->x_centre)); + + + + VL53L1_decode_zone_size( + pdev->dyn_cfg.roi_config__user_roi_requested_global_xy_size, + &(puser_zone->width), + &(puser_zone->height)); + + LOG_FUNCTION_END(status); + + return status; +} + + + +VL53L1_Error VL53L1_get_mode_mitigation_roi( + VL53L1_DEV Dev, + VL53L1_user_zone_t *pmm_roi) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + uint8_t x = 0; + uint8_t y = 0; + uint8_t xy_size = 0; + + LOG_FUNCTION_START(""); + + + + VL53L1_decode_row_col( + pdev->nvm_copy_data.roi_config__mode_roi_centre_spad, + &y, + &x); + + pmm_roi->x_centre = x; + pmm_roi->y_centre = y; + + + + + + + + + + + xy_size = pdev->nvm_copy_data.roi_config__mode_roi_xy_size; + + pmm_roi->height = xy_size >> 4; + pmm_roi->width = xy_size & 0x0F; + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_zone_config( + VL53L1_DEV Dev, + VL53L1_zone_config_t *pzone_cfg) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + + + memcpy(&(pdev->zone_cfg.user_zones), &(pzone_cfg->user_zones), + sizeof(pdev->zone_cfg.user_zones)); + + + + pdev->zone_cfg.max_zones = pzone_cfg->max_zones; + pdev->zone_cfg.active_zones = pzone_cfg->active_zones; + + status = VL53L1_init_zone_config_histogram_bins(&pdev->zone_cfg); + + + + + + + + + + + if (pzone_cfg->active_zones == 0) + pdev->gen_cfg.global_config__stream_divider = 0; + else if (pzone_cfg->active_zones < VL53L1_MAX_USER_ZONES) + pdev->gen_cfg.global_config__stream_divider = + pzone_cfg->active_zones + 1; + else + pdev->gen_cfg.global_config__stream_divider = + VL53L1_MAX_USER_ZONES + 1; + + LOG_FUNCTION_END(status); + + return status; + +} + + +VL53L1_Error VL53L1_get_zone_config( + VL53L1_DEV Dev, + VL53L1_zone_config_t *pzone_cfg) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + + + memcpy(pzone_cfg, &(pdev->zone_cfg), sizeof(VL53L1_zone_config_t)); + + LOG_FUNCTION_END(status); + + return status; +} + +VL53L1_Error VL53L1_get_preset_mode_timing_cfg( + VL53L1_DEV Dev, + VL53L1_DevicePresetModes device_preset_mode, + uint16_t *pdss_config__target_total_rate_mcps, + uint32_t *pphasecal_config_timeout_us, + uint32_t *pmm_config_timeout_us, + uint32_t *prange_config_timeout_us) +{ + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + + switch (device_preset_mode) { + + case VL53L1_DEVICEPRESETMODE_STANDARD_RANGING: + case VL53L1_DEVICEPRESETMODE_STANDARD_RANGING_SHORT_RANGE: + case VL53L1_DEVICEPRESETMODE_STANDARD_RANGING_LONG_RANGE: + case VL53L1_DEVICEPRESETMODE_STANDARD_RANGING_MM1_CAL: + case VL53L1_DEVICEPRESETMODE_STANDARD_RANGING_MM2_CAL: + case VL53L1_DEVICEPRESETMODE_OLT: + *pdss_config__target_total_rate_mcps = + pdev->tuning_parms.tp_dss_target_lite_mcps; + *pphasecal_config_timeout_us = + pdev->tuning_parms.tp_phasecal_timeout_lite_us; + *pmm_config_timeout_us = + pdev->tuning_parms.tp_mm_timeout_lite_us; + *prange_config_timeout_us = + pdev->tuning_parms.tp_range_timeout_lite_us; + break; + + case VL53L1_DEVICEPRESETMODE_TIMED_RANGING: + case VL53L1_DEVICEPRESETMODE_TIMED_RANGING_SHORT_RANGE: + case VL53L1_DEVICEPRESETMODE_TIMED_RANGING_LONG_RANGE: + case VL53L1_DEVICEPRESETMODE_SINGLESHOT_RANGING: + *pdss_config__target_total_rate_mcps = + pdev->tuning_parms.tp_dss_target_timed_mcps; + *pphasecal_config_timeout_us = + pdev->tuning_parms.tp_phasecal_timeout_timed_us; + *pmm_config_timeout_us = + pdev->tuning_parms.tp_mm_timeout_timed_us; + *prange_config_timeout_us = + pdev->tuning_parms.tp_range_timeout_timed_us; + break; + + case VL53L1_DEVICEPRESETMODE_LOWPOWERAUTO_SHORT_RANGE: + case VL53L1_DEVICEPRESETMODE_LOWPOWERAUTO_MEDIUM_RANGE: + case VL53L1_DEVICEPRESETMODE_LOWPOWERAUTO_LONG_RANGE: + *pdss_config__target_total_rate_mcps = + pdev->tuning_parms.tp_dss_target_timed_mcps; + *pphasecal_config_timeout_us = + pdev->tuning_parms.tp_phasecal_timeout_timed_us; + *pmm_config_timeout_us = + pdev->tuning_parms.tp_mm_timeout_lpa_us; + *prange_config_timeout_us = + pdev->tuning_parms.tp_range_timeout_lpa_us; + break; + + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_RANGING: + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_RANGING_WITH_MM1: + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_RANGING_WITH_MM2: + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_RANGING_MM1_CAL: + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_RANGING_MM2_CAL: + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_REF_ARRAY: + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_LONG_RANGE: + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_LONG_RANGE_MM1: + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_LONG_RANGE_MM2: + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_CHARACTERISATION: + *pdss_config__target_total_rate_mcps = + pdev->tuning_parms.tp_dss_target_histo_mcps; + *pphasecal_config_timeout_us = + pdev->tuning_parms.tp_phasecal_timeout_hist_long_us; + *pmm_config_timeout_us = + pdev->tuning_parms.tp_mm_timeout_histo_us; + *prange_config_timeout_us = + pdev->tuning_parms.tp_range_timeout_histo_us; + + break; + + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_MULTIZONE: + *pdss_config__target_total_rate_mcps = + pdev->tuning_parms.tp_dss_target_histo_mz_mcps; + *pphasecal_config_timeout_us = + pdev->tuning_parms.tp_phasecal_timeout_mz_med_us; + *pmm_config_timeout_us = + pdev->tuning_parms.tp_mm_timeout_mz_us; + *prange_config_timeout_us = + pdev->tuning_parms.tp_range_timeout_mz_us; + break; + + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_MULTIZONE_SHORT_RANGE: + *pdss_config__target_total_rate_mcps = + pdev->tuning_parms.tp_dss_target_histo_mz_mcps; + *pphasecal_config_timeout_us = + pdev->tuning_parms.tp_phasecal_timeout_mz_short_us; + *pmm_config_timeout_us = + pdev->tuning_parms.tp_mm_timeout_mz_us; + *prange_config_timeout_us = + pdev->tuning_parms.tp_range_timeout_mz_us; + break; + + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_MULTIZONE_LONG_RANGE: + *pdss_config__target_total_rate_mcps = + pdev->tuning_parms.tp_dss_target_histo_mz_mcps; + *pphasecal_config_timeout_us = + pdev->tuning_parms.tp_phasecal_timeout_mz_long_us; + *pmm_config_timeout_us = + pdev->tuning_parms.tp_mm_timeout_mz_us; + *prange_config_timeout_us = + pdev->tuning_parms.tp_range_timeout_mz_us; + break; + + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_RANGING_SHORT_TIMING: + *pdss_config__target_total_rate_mcps = + pdev->tuning_parms.tp_dss_target_histo_mcps; + *pphasecal_config_timeout_us = + pdev->tuning_parms.tp_phasecal_timeout_hist_short_us; + *pmm_config_timeout_us = + pdev->tuning_parms.tp_mm_timeout_histo_us; + *prange_config_timeout_us = + pdev->tuning_parms.tp_range_timeout_histo_us; + break; + + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_MEDIUM_RANGE: + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_MEDIUM_RANGE_MM1: + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_MEDIUM_RANGE_MM2: + *pdss_config__target_total_rate_mcps = + pdev->tuning_parms.tp_dss_target_histo_mcps; + *pphasecal_config_timeout_us = + pdev->tuning_parms.tp_phasecal_timeout_hist_med_us; + *pmm_config_timeout_us = + pdev->tuning_parms.tp_mm_timeout_histo_us; + *prange_config_timeout_us = + pdev->tuning_parms.tp_range_timeout_histo_us; + break; + + + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_SHORT_RANGE: + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_SHORT_RANGE_MM1: + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_SHORT_RANGE_MM2: + *pdss_config__target_total_rate_mcps = + pdev->tuning_parms.tp_dss_target_histo_mcps; + *pphasecal_config_timeout_us = + pdev->tuning_parms.tp_phasecal_timeout_hist_short_us; + *pmm_config_timeout_us = + pdev->tuning_parms.tp_mm_timeout_histo_us; + *prange_config_timeout_us = + pdev->tuning_parms.tp_range_timeout_histo_us; + break; + + case VL53L1_DEVICEPRESETMODE_SPECIAL_HISTOGRAM_SHORT_RANGE: + *pdss_config__target_total_rate_mcps = + pdev->tuning_parms.tp_dss_target_very_short_mcps; + *pphasecal_config_timeout_us = + pdev->tuning_parms.tp_phasecal_timeout_hist_short_us; + *pmm_config_timeout_us = + pdev->tuning_parms.tp_mm_timeout_histo_us; + *prange_config_timeout_us = + pdev->tuning_parms.tp_range_timeout_histo_us; + break; + + default: + status = VL53L1_ERROR_INVALID_PARAMS; + break; + + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_preset_mode( + VL53L1_DEV Dev, + VL53L1_DevicePresetModes device_preset_mode, + uint16_t dss_config__target_total_rate_mcps, + uint32_t phasecal_config_timeout_us, + uint32_t mm_config_timeout_us, + uint32_t range_config_timeout_us, + uint32_t inter_measurement_period_ms) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_LLDriverResults_t *pres = + VL53L1DevStructGetLLResultsHandle(Dev); + + VL53L1_hist_post_process_config_t *phistpostprocess = + &(pdev->histpostprocess); + + VL53L1_static_config_t *pstatic = &(pdev->stat_cfg); + VL53L1_histogram_config_t *phistogram = &(pdev->hist_cfg); + VL53L1_general_config_t *pgeneral = &(pdev->gen_cfg); + VL53L1_timing_config_t *ptiming = &(pdev->tim_cfg); + VL53L1_dynamic_config_t *pdynamic = &(pdev->dyn_cfg); + VL53L1_system_control_t *psystem = &(pdev->sys_ctrl); + VL53L1_zone_config_t *pzone_cfg = &(pdev->zone_cfg); + VL53L1_tuning_parm_storage_t *ptuning_parms = &(pdev->tuning_parms); + VL53L1_low_power_auto_data_t *plpadata = + &(pdev->low_power_auto_data); + + LOG_FUNCTION_START(""); + + + + pdev->preset_mode = device_preset_mode; + pdev->mm_config_timeout_us = mm_config_timeout_us; + pdev->range_config_timeout_us = range_config_timeout_us; + pdev->inter_measurement_period_ms = inter_measurement_period_ms; + + + + + VL53L1_init_ll_driver_state( + Dev, + VL53L1_DEVICESTATE_SW_STANDBY); + + + + + switch (device_preset_mode) { + + case VL53L1_DEVICEPRESETMODE_STANDARD_RANGING: + status = VL53L1_preset_mode_standard_ranging( + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_STANDARD_RANGING_SHORT_RANGE: + status = VL53L1_preset_mode_standard_ranging_short_range( + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_STANDARD_RANGING_LONG_RANGE: + status = VL53L1_preset_mode_standard_ranging_long_range( + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_STANDARD_RANGING_MM1_CAL: + status = VL53L1_preset_mode_standard_ranging_mm1_cal( + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_STANDARD_RANGING_MM2_CAL: + status = VL53L1_preset_mode_standard_ranging_mm2_cal( + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_TIMED_RANGING: + status = VL53L1_preset_mode_timed_ranging( + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_TIMED_RANGING_SHORT_RANGE: + status = VL53L1_preset_mode_timed_ranging_short_range( + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_TIMED_RANGING_LONG_RANGE: + status = VL53L1_preset_mode_timed_ranging_long_range( + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_RANGING: + status = VL53L1_preset_mode_histogram_ranging( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_RANGING_WITH_MM1: + status = VL53L1_preset_mode_histogram_ranging_with_mm1( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_RANGING_WITH_MM2: + status = VL53L1_preset_mode_histogram_ranging_with_mm2( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_RANGING_MM1_CAL: + status = VL53L1_preset_mode_histogram_ranging_mm1_cal( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_RANGING_MM2_CAL: + status = VL53L1_preset_mode_histogram_ranging_mm2_cal( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_MULTIZONE: + status = VL53L1_preset_mode_histogram_multizone( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_MULTIZONE_SHORT_RANGE: + status = VL53L1_preset_mode_histogram_multizone_short_range( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_MULTIZONE_LONG_RANGE: + status = VL53L1_preset_mode_histogram_multizone_long_range( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_REF_ARRAY: + status = VL53L1_preset_mode_histogram_ranging_ref( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_RANGING_SHORT_TIMING: + status = VL53L1_preset_mode_histogram_ranging_short_timing( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_LONG_RANGE: + status = VL53L1_preset_mode_histogram_long_range( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_LONG_RANGE_MM1: + status = VL53L1_preset_mode_histogram_long_range_mm1( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_LONG_RANGE_MM2: + status = VL53L1_preset_mode_histogram_long_range_mm2( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_MEDIUM_RANGE: + status = VL53L1_preset_mode_histogram_medium_range( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_MEDIUM_RANGE_MM1: + status = VL53L1_preset_mode_histogram_medium_range_mm1( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_MEDIUM_RANGE_MM2: + status = VL53L1_preset_mode_histogram_medium_range_mm2( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_SHORT_RANGE: + status = VL53L1_preset_mode_histogram_short_range( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_SHORT_RANGE_MM1: + status = VL53L1_preset_mode_histogram_short_range_mm1( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_SHORT_RANGE_MM2: + status = VL53L1_preset_mode_histogram_short_range_mm2( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_CHARACTERISATION: + status = VL53L1_preset_mode_histogram_characterisation( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_XTALK_PLANAR: + status = VL53L1_preset_mode_histogram_xtalk_planar( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_XTALK_MM1: + status = VL53L1_preset_mode_histogram_xtalk_mm1( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_XTALK_MM2: + status = VL53L1_preset_mode_histogram_xtalk_mm2( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_OLT: + status = VL53L1_preset_mode_olt( + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_SINGLESHOT_RANGING: + status = VL53L1_preset_mode_singleshot_ranging( + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_LOWPOWERAUTO_SHORT_RANGE: + status = VL53L1_preset_mode_low_power_auto_short_ranging( + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg, + plpadata); + break; + + case VL53L1_DEVICEPRESETMODE_LOWPOWERAUTO_MEDIUM_RANGE: + status = VL53L1_preset_mode_low_power_auto_ranging( + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg, + plpadata); + break; + + case VL53L1_DEVICEPRESETMODE_LOWPOWERAUTO_LONG_RANGE: + status = VL53L1_preset_mode_low_power_auto_long_ranging( + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg, + plpadata); + break; + + + case VL53L1_DEVICEPRESETMODE_SPECIAL_HISTOGRAM_SHORT_RANGE: + status = VL53L1_preset_mode_special_histogram_short_range( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + default: + status = VL53L1_ERROR_INVALID_PARAMS; + break; + + } + + + + + if (status == VL53L1_ERROR_NONE) { + + pstatic->dss_config__target_total_rate_mcps = + dss_config__target_total_rate_mcps; + pdev->dss_config__target_total_rate_mcps = + dss_config__target_total_rate_mcps; + + } + + + + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_set_timeouts_us( + Dev, + phasecal_config_timeout_us, + mm_config_timeout_us, + range_config_timeout_us); + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_set_inter_measurement_period_ms( + Dev, + inter_measurement_period_ms); + + + + + V53L1_init_zone_results_structure( + pdev->zone_cfg.active_zones+1, + &(pres->zone_results)); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_zone_preset( + VL53L1_DEV Dev, + VL53L1_DeviceZonePreset zone_preset) +{ + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + VL53L1_general_config_t *pgeneral = &(pdev->gen_cfg); + VL53L1_zone_config_t *pzone_cfg = &(pdev->zone_cfg); + + LOG_FUNCTION_START(""); + + + + pdev->zone_preset = zone_preset; + + + + + switch (zone_preset) { + + case VL53L1_DEVICEZONEPRESET_XTALK_PLANAR: + status = + VL53L1_zone_preset_xtalk_planar( + pgeneral, + pzone_cfg); + break; + + case VL53L1_DEVICEZONEPRESET_1X1_SIZE_16X16: + status = + VL53L1_init_zone_config_structure( + 8, 1, 1, + + 8, 1, 1, + + 15, 15, + + pzone_cfg); + break; + + case VL53L1_DEVICEZONEPRESET_1X2_SIZE_16X8: + status = + VL53L1_init_zone_config_structure( + 8, 1, 1, + + 4, 8, 2, + + 15, 7, + + pzone_cfg); + break; + + case VL53L1_DEVICEZONEPRESET_2X1_SIZE_8X16: + status = + VL53L1_init_zone_config_structure( + 4, 8, 2, + + 8, 1, 1, + + 7, 15, + + pzone_cfg); + break; + + case VL53L1_DEVICEZONEPRESET_2X2_SIZE_8X8: + status = + VL53L1_init_zone_config_structure( + 4, 8, 2, + + 4, 8, 2, + + 7, 7, + + pzone_cfg); + break; + + case VL53L1_DEVICEZONEPRESET_3X3_SIZE_5X5: + status = + VL53L1_init_zone_config_structure( + 2, 5, 3, + + 2, 5, 3, + + 4, 4, + + pzone_cfg); + break; + + case VL53L1_DEVICEZONEPRESET_4X4_SIZE_4X4: + status = + VL53L1_init_zone_config_structure( + 2, 4, 4, + + 2, 4, 4, + + 3, 3, + + pzone_cfg); + break; + + case VL53L1_DEVICEZONEPRESET_5X5_SIZE_4X4: + status = + VL53L1_init_zone_config_structure( + 2, 3, 5, + + 2, 3, 5, + + 3, 3, + + pzone_cfg); + break; + + case VL53L1_DEVICEZONEPRESET_11X11_SIZE_5X5: + status = + VL53L1_init_zone_config_structure( + 3, 1, 11, + + 3, 1, 11, + + 4, 4, + + pzone_cfg); + break; + + case VL53L1_DEVICEZONEPRESET_13X13_SIZE_4X4: + status = + VL53L1_init_zone_config_structure( + 2, 1, 13, + + 2, 1, 13, + + 3, 3, + + pzone_cfg); + + break; + + case VL53L1_DEVICEZONEPRESET_1X1_SIZE_4X4_POS_8X8: + status = + VL53L1_init_zone_config_structure( + 8, 1, 1, + + 8, 1, 1, + + 3, 3, + + pzone_cfg); + break; + + } + + + + + + + + + + + if (pzone_cfg->active_zones == 0) + pdev->gen_cfg.global_config__stream_divider = 0; + else if (pzone_cfg->active_zones < VL53L1_MAX_USER_ZONES) + pdev->gen_cfg.global_config__stream_divider = + pzone_cfg->active_zones + 1; + else + pdev->gen_cfg.global_config__stream_divider = + VL53L1_MAX_USER_ZONES + 1; + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_enable_xtalk_compensation( + VL53L1_DEV Dev) +{ + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint32_t tempu32; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_xtalk_config_t *pC = &(pdev->xtalk_cfg); + VL53L1_hist_post_process_config_t *pHP = &(pdev->histpostprocess); + VL53L1_customer_nvm_managed_t *pN = &(pdev->customer); + + LOG_FUNCTION_START(""); + + + + tempu32 = VL53L1_calc_crosstalk_plane_offset_with_margin( + pC->algo__crosstalk_compensation_plane_offset_kcps, + pC->lite_mode_crosstalk_margin_kcps); + if (tempu32 > 0xFFFF) + tempu32 = 0xFFFF; + + pN->algo__crosstalk_compensation_plane_offset_kcps = + (uint16_t)tempu32; + + pN->algo__crosstalk_compensation_x_plane_gradient_kcps = + pC->algo__crosstalk_compensation_x_plane_gradient_kcps; + + pN->algo__crosstalk_compensation_y_plane_gradient_kcps = + pC->algo__crosstalk_compensation_y_plane_gradient_kcps; + + + + pHP->algo__crosstalk_compensation_plane_offset_kcps = + VL53L1_calc_crosstalk_plane_offset_with_margin( + pC->algo__crosstalk_compensation_plane_offset_kcps, + pC->histogram_mode_crosstalk_margin_kcps); + + pHP->algo__crosstalk_compensation_x_plane_gradient_kcps + = pC->algo__crosstalk_compensation_x_plane_gradient_kcps; + pHP->algo__crosstalk_compensation_y_plane_gradient_kcps + = pC->algo__crosstalk_compensation_y_plane_gradient_kcps; + + + + + pC->global_crosstalk_compensation_enable = 0x01; + + pHP->algo__crosstalk_compensation_enable = + pC->global_crosstalk_compensation_enable; + + + + + + if (status == VL53L1_ERROR_NONE) { + pC->crosstalk_range_ignore_threshold_rate_mcps = + VL53L1_calc_range_ignore_threshold( + pC->algo__crosstalk_compensation_plane_offset_kcps, + pC->algo__crosstalk_compensation_x_plane_gradient_kcps, + pC->algo__crosstalk_compensation_y_plane_gradient_kcps, + pC->crosstalk_range_ignore_threshold_mult); +} + + + + + if (status == VL53L1_ERROR_NONE) + + status = + VL53L1_set_customer_nvm_managed( + Dev, + &(pdev->customer)); + + LOG_FUNCTION_END(status); + + return status; + +} + +void VL53L1_get_xtalk_compensation_enable( + VL53L1_DEV Dev, + uint8_t *pcrosstalk_compensation_enable) +{ + + + + + + + + + + + + + + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + + + + *pcrosstalk_compensation_enable = + pdev->xtalk_cfg.global_crosstalk_compensation_enable; + +} + + +VL53L1_Error VL53L1_get_lite_xtalk_margin_kcps( + VL53L1_DEV Dev, + int16_t *pxtalk_margin) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + *pxtalk_margin = pdev->xtalk_cfg.lite_mode_crosstalk_margin_kcps; + + LOG_FUNCTION_END(status); + + return status; + +} + +VL53L1_Error VL53L1_set_lite_xtalk_margin_kcps( + VL53L1_DEV Dev, + int16_t xtalk_margin) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + pdev->xtalk_cfg.lite_mode_crosstalk_margin_kcps = xtalk_margin; + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_histogram_xtalk_margin_kcps( + VL53L1_DEV Dev, + int16_t *pxtalk_margin) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + *pxtalk_margin = pdev->xtalk_cfg.histogram_mode_crosstalk_margin_kcps; + + LOG_FUNCTION_END(status); + + return status; + +} + +VL53L1_Error VL53L1_set_histogram_xtalk_margin_kcps( + VL53L1_DEV Dev, + int16_t xtalk_margin) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + pdev->xtalk_cfg.histogram_mode_crosstalk_margin_kcps = xtalk_margin; + + LOG_FUNCTION_END(status); + + return status; +} + +VL53L1_Error VL53L1_restore_xtalk_nvm_default( + VL53L1_DEV Dev) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_xtalk_config_t *pC = &(pdev->xtalk_cfg); + + LOG_FUNCTION_START(""); + + pC->algo__crosstalk_compensation_plane_offset_kcps = + pC->nvm_default__crosstalk_compensation_plane_offset_kcps; + pC->algo__crosstalk_compensation_x_plane_gradient_kcps = + pC->nvm_default__crosstalk_compensation_x_plane_gradient_kcps; + pC->algo__crosstalk_compensation_y_plane_gradient_kcps = + pC->nvm_default__crosstalk_compensation_y_plane_gradient_kcps; + + LOG_FUNCTION_END(status); + + return status; +} + +VL53L1_Error VL53L1_disable_xtalk_compensation( + VL53L1_DEV Dev) +{ + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_hist_post_process_config_t *pHP = &(pdev->histpostprocess); + VL53L1_customer_nvm_managed_t *pN = &(pdev->customer); + + LOG_FUNCTION_START(""); + + + + pN->algo__crosstalk_compensation_plane_offset_kcps = + 0x00; + + pN->algo__crosstalk_compensation_x_plane_gradient_kcps = + 0x00; + + pN->algo__crosstalk_compensation_y_plane_gradient_kcps = + 0x00; + + + + + pdev->xtalk_cfg.global_crosstalk_compensation_enable = 0x00; + + pHP->algo__crosstalk_compensation_enable = + pdev->xtalk_cfg.global_crosstalk_compensation_enable; + + + + + if (status == VL53L1_ERROR_NONE) { + pdev->xtalk_cfg.crosstalk_range_ignore_threshold_rate_mcps = + 0x0000; + } + + + + + if (status == VL53L1_ERROR_NONE) { + + status = + VL53L1_set_customer_nvm_managed( + Dev, + &(pdev->customer)); + } + LOG_FUNCTION_END(status); + + return status; + +} + + +VL53L1_Error VL53L1_get_histogram_phase_consistency( + VL53L1_DEV Dev, + uint8_t *pphase_consistency) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_hist_post_process_config_t *pHP = &(pdev->histpostprocess); + + LOG_FUNCTION_START(""); + + *pphase_consistency = + pHP->algo__consistency_check__phase_tolerance; + + LOG_FUNCTION_END(status); + + return status; + +} + +VL53L1_Error VL53L1_set_histogram_phase_consistency( + VL53L1_DEV Dev, + uint8_t phase_consistency) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + pdev->histpostprocess.algo__consistency_check__phase_tolerance = + phase_consistency; + + LOG_FUNCTION_END(status); + + return status; + +} + +VL53L1_Error VL53L1_get_histogram_event_consistency( + VL53L1_DEV Dev, + uint8_t *pevent_consistency) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + *pevent_consistency = + pdev->histpostprocess.algo__consistency_check__event_sigma; + + LOG_FUNCTION_END(status); + + return status; + +} + +VL53L1_Error VL53L1_set_histogram_event_consistency( + VL53L1_DEV Dev, + uint8_t event_consistency) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + pdev->histpostprocess.algo__consistency_check__event_sigma = + event_consistency; + + LOG_FUNCTION_END(status); + + return status; + +} + +VL53L1_Error VL53L1_get_histogram_ambient_threshold_sigma( + VL53L1_DEV Dev, + uint8_t *pamb_thresh_sigma) +{ + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + *pamb_thresh_sigma = + pdev->histpostprocess.ambient_thresh_sigma1; + + LOG_FUNCTION_END(status); + + return status; + +} + +VL53L1_Error VL53L1_set_histogram_ambient_threshold_sigma( + VL53L1_DEV Dev, + uint8_t amb_thresh_sigma) +{ + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + pdev->histpostprocess.ambient_thresh_sigma1 = + amb_thresh_sigma; + + LOG_FUNCTION_END(status); + + return status; + +} + +VL53L1_Error VL53L1_get_lite_sigma_threshold( + VL53L1_DEV Dev, + uint16_t *plite_sigma) +{ + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + *plite_sigma = + pdev->tim_cfg.range_config__sigma_thresh; + + LOG_FUNCTION_END(status); + + return status; + +} + +VL53L1_Error VL53L1_set_lite_sigma_threshold( + VL53L1_DEV Dev, + uint16_t lite_sigma) +{ + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + pdev->tim_cfg.range_config__sigma_thresh = lite_sigma; + + LOG_FUNCTION_END(status); + + return status; + +} + +VL53L1_Error VL53L1_get_lite_min_count_rate( + VL53L1_DEV Dev, + uint16_t *plite_mincountrate) +{ + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + *plite_mincountrate = + pdev->tim_cfg.range_config__min_count_rate_rtn_limit_mcps; + + LOG_FUNCTION_END(status); + + return status; + +} + +VL53L1_Error VL53L1_set_lite_min_count_rate( + VL53L1_DEV Dev, + uint16_t lite_mincountrate) +{ + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + pdev->tim_cfg.range_config__min_count_rate_rtn_limit_mcps = + lite_mincountrate; + + LOG_FUNCTION_END(status); + + return status; + +} + + +VL53L1_Error VL53L1_get_xtalk_detect_config( + VL53L1_DEV Dev, + int16_t *pmax_valid_range_mm, + int16_t *pmin_valid_range_mm, + uint16_t *pmax_valid_rate_kcps, + uint16_t *pmax_sigma_mm) +{ + + + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + *pmax_valid_range_mm = + pdev->xtalk_cfg.algo__crosstalk_detect_max_valid_range_mm; + *pmin_valid_range_mm = + pdev->xtalk_cfg.algo__crosstalk_detect_min_valid_range_mm; + *pmax_valid_rate_kcps = + pdev->xtalk_cfg.algo__crosstalk_detect_max_valid_rate_kcps; + *pmax_sigma_mm = + pdev->xtalk_cfg.algo__crosstalk_detect_max_sigma_mm; + + LOG_FUNCTION_END(status); + + return status; + +} + +VL53L1_Error VL53L1_set_xtalk_detect_config( + VL53L1_DEV Dev, + int16_t max_valid_range_mm, + int16_t min_valid_range_mm, + uint16_t max_valid_rate_kcps, + uint16_t max_sigma_mm) +{ + + + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + pdev->xtalk_cfg.algo__crosstalk_detect_max_valid_range_mm = + max_valid_range_mm; + pdev->xtalk_cfg.algo__crosstalk_detect_min_valid_range_mm = + min_valid_range_mm; + pdev->xtalk_cfg.algo__crosstalk_detect_max_valid_rate_kcps = + max_valid_rate_kcps; + pdev->xtalk_cfg.algo__crosstalk_detect_max_sigma_mm = + max_sigma_mm; + + LOG_FUNCTION_END(status); + + return status; + +} + +VL53L1_Error VL53L1_get_target_order_mode( + VL53L1_DEV Dev, + VL53L1_HistTargetOrder *phist_target_order) +{ + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + *phist_target_order = + pdev->histpostprocess.hist_target_order; + + LOG_FUNCTION_END(status); + + return status; + +} + +VL53L1_Error VL53L1_set_target_order_mode( + VL53L1_DEV Dev, + VL53L1_HistTargetOrder hist_target_order) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + pdev->histpostprocess.hist_target_order = hist_target_order; + + LOG_FUNCTION_END(status); + + return status; + +} + + +VL53L1_Error VL53L1_get_dmax_reflectance_values( + VL53L1_DEV Dev, + VL53L1_dmax_reflectance_array_t *pdmax_reflectances) +{ + + VL53L1_Error status = VL53L1_ERROR_NONE; + + uint8_t i = 0; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + + + + + + + + for (i = 0; i < VL53L1_MAX_AMBIENT_DMAX_VALUES; i++) { + pdmax_reflectances->target_reflectance_for_dmax[i] = + pdev->dmax_cfg.target_reflectance_for_dmax_calc[i]; + } + + LOG_FUNCTION_END(status); + + return status; + +} + +VL53L1_Error VL53L1_set_dmax_reflectance_values( + VL53L1_DEV Dev, + VL53L1_dmax_reflectance_array_t *pdmax_reflectances) +{ + + VL53L1_Error status = VL53L1_ERROR_NONE; + + uint8_t i = 0; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + + + + + + + + for (i = 0; i < VL53L1_MAX_AMBIENT_DMAX_VALUES; i++) { + pdev->dmax_cfg.target_reflectance_for_dmax_calc[i] = + pdmax_reflectances->target_reflectance_for_dmax[i]; + } + + LOG_FUNCTION_END(status); + + return status; + +} + +VL53L1_Error VL53L1_get_vhv_loopbound( + VL53L1_DEV Dev, + uint8_t *pvhv_loopbound) +{ + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + *pvhv_loopbound = + pdev->stat_nvm.vhv_config__timeout_macrop_loop_bound / 4; + + LOG_FUNCTION_END(status); + + return status; + +} + + + +VL53L1_Error VL53L1_set_vhv_loopbound( + VL53L1_DEV Dev, + uint8_t vhv_loopbound) +{ + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + pdev->stat_nvm.vhv_config__timeout_macrop_loop_bound = + (pdev->stat_nvm.vhv_config__timeout_macrop_loop_bound & 0x03) + + (vhv_loopbound * 4); + + LOG_FUNCTION_END(status); + + return status; + +} + + + +VL53L1_Error VL53L1_get_vhv_config( + VL53L1_DEV Dev, + uint8_t *pvhv_init_en, + uint8_t *pvhv_init_value) +{ + + + + + + + + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + *pvhv_init_en = (pdev->stat_nvm.vhv_config__init & 0x80) >> 7; + *pvhv_init_value = + (pdev->stat_nvm.vhv_config__init & 0x7F); + + LOG_FUNCTION_END(status); + + return status; + +} + + + +VL53L1_Error VL53L1_set_vhv_config( + VL53L1_DEV Dev, + uint8_t vhv_init_en, + uint8_t vhv_init_value) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + pdev->stat_nvm.vhv_config__init = + ((vhv_init_en & 0x01) << 7) + + (vhv_init_value & 0x7F); + + LOG_FUNCTION_END(status); + + return status; + +} + + + +VL53L1_Error VL53L1_init_and_start_range( + VL53L1_DEV Dev, + uint8_t measurement_mode, + VL53L1_DeviceConfigLevel device_config_level) +{ + + + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_LLDriverResults_t *pres = + VL53L1DevStructGetLLResultsHandle(Dev); + + uint8_t buffer[VL53L1_MAX_I2C_XFER_SIZE]; + + VL53L1_static_nvm_managed_t *pstatic_nvm = &(pdev->stat_nvm); + VL53L1_customer_nvm_managed_t *pcustomer_nvm = &(pdev->customer); + VL53L1_static_config_t *pstatic = &(pdev->stat_cfg); + VL53L1_general_config_t *pgeneral = &(pdev->gen_cfg); + VL53L1_timing_config_t *ptiming = &(pdev->tim_cfg); + VL53L1_dynamic_config_t *pdynamic = &(pdev->dyn_cfg); + VL53L1_system_control_t *psystem = &(pdev->sys_ctrl); + + VL53L1_ll_driver_state_t *pstate = &(pdev->ll_state); + VL53L1_customer_nvm_managed_t *pN = &(pdev->customer); + + uint8_t *pbuffer = &buffer[0]; + uint16_t i = 0; + uint16_t i2c_index = 0; + uint16_t i2c_buffer_offset_bytes = 0; + uint16_t i2c_buffer_size_bytes = 0; + + LOG_FUNCTION_START(""); + + + + pdev->measurement_mode = measurement_mode; + + + + + psystem->system__mode_start = + (psystem->system__mode_start & + VL53L1_DEVICEMEASUREMENTMODE_STOP_MASK) | + measurement_mode; + + + + + + + status = + VL53L1_set_user_zone( + Dev, + &(pdev->zone_cfg.user_zones[pdev->ll_state.cfg_zone_id])); + + + + + + if (pdev->zone_cfg.active_zones > 0) { + status = + VL53L1_set_zone_dss_config( + Dev, + &(pres->zone_dyn_cfgs.VL53L1_p_002[pdev->ll_state.cfg_zone_id]) + ); + } + + + + + + + if (((pdev->sys_ctrl.system__mode_start & + VL53L1_DEVICESCHEDULERMODE_HISTOGRAM) == 0x00) && + (pdev->xtalk_cfg.global_crosstalk_compensation_enable + == 0x01)) { + pdev->stat_cfg.algo__range_ignore_threshold_mcps = + pdev->xtalk_cfg.crosstalk_range_ignore_threshold_rate_mcps; + } + + + + + + + + + if (pdev->low_power_auto_data.low_power_auto_range_count == 0xFF) + pdev->low_power_auto_data.low_power_auto_range_count = 0x0; + + + + if ((pdev->low_power_auto_data.is_low_power_auto_mode == 1) && + (pdev->low_power_auto_data.low_power_auto_range_count == 0)) { + + + pdev->low_power_auto_data.saved_interrupt_config = + pdev->gen_cfg.system__interrupt_config_gpio; + + + pdev->gen_cfg.system__interrupt_config_gpio = 1 << 5; + + + if ((pdev->dyn_cfg.system__sequence_config & ( + VL53L1_SEQUENCE_MM1_EN | VL53L1_SEQUENCE_MM2_EN)) == + 0x0) { + pN->algo__part_to_part_range_offset_mm = + (pN->mm_config__outer_offset_mm << 2); + } else { + pN->algo__part_to_part_range_offset_mm = 0x0; + } + + + + if (device_config_level < + VL53L1_DEVICECONFIGLEVEL_CUSTOMER_ONWARDS) { + device_config_level = + VL53L1_DEVICECONFIGLEVEL_CUSTOMER_ONWARDS; + } + } + + if ((pdev->low_power_auto_data.is_low_power_auto_mode == 1) && + (pdev->low_power_auto_data.low_power_auto_range_count == 1)) { + + + pdev->gen_cfg.system__interrupt_config_gpio = + pdev->low_power_auto_data.saved_interrupt_config; + + + + device_config_level = VL53L1_DEVICECONFIGLEVEL_FULL; + } + + + + + + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_save_cfg_data(Dev); + + + + + + + switch (device_config_level) { + case VL53L1_DEVICECONFIGLEVEL_FULL: + i2c_index = VL53L1_STATIC_NVM_MANAGED_I2C_INDEX; + break; + case VL53L1_DEVICECONFIGLEVEL_CUSTOMER_ONWARDS: + i2c_index = VL53L1_CUSTOMER_NVM_MANAGED_I2C_INDEX; + break; + case VL53L1_DEVICECONFIGLEVEL_STATIC_ONWARDS: + i2c_index = VL53L1_STATIC_CONFIG_I2C_INDEX; + break; + case VL53L1_DEVICECONFIGLEVEL_GENERAL_ONWARDS: + i2c_index = VL53L1_GENERAL_CONFIG_I2C_INDEX; + break; + case VL53L1_DEVICECONFIGLEVEL_TIMING_ONWARDS: + i2c_index = VL53L1_TIMING_CONFIG_I2C_INDEX; + break; + case VL53L1_DEVICECONFIGLEVEL_DYNAMIC_ONWARDS: + i2c_index = VL53L1_DYNAMIC_CONFIG_I2C_INDEX; + break; + default: + i2c_index = VL53L1_SYSTEM_CONTROL_I2C_INDEX; + break; + } + + + + + i2c_buffer_size_bytes = + (VL53L1_SYSTEM_CONTROL_I2C_INDEX + + VL53L1_SYSTEM_CONTROL_I2C_SIZE_BYTES) - + i2c_index; + + + + + pbuffer = &buffer[0]; + for (i = 0; i < i2c_buffer_size_bytes; i++) + *pbuffer++ = 0; + + + + + if (device_config_level >= VL53L1_DEVICECONFIGLEVEL_FULL && + status == VL53L1_ERROR_NONE) { + + i2c_buffer_offset_bytes = + VL53L1_STATIC_NVM_MANAGED_I2C_INDEX - i2c_index; + + status = + VL53L1_i2c_encode_static_nvm_managed( + pstatic_nvm, + VL53L1_STATIC_NVM_MANAGED_I2C_SIZE_BYTES, + &buffer[i2c_buffer_offset_bytes]); + } + + if (device_config_level >= VL53L1_DEVICECONFIGLEVEL_CUSTOMER_ONWARDS && + status == VL53L1_ERROR_NONE) { + + i2c_buffer_offset_bytes = + VL53L1_CUSTOMER_NVM_MANAGED_I2C_INDEX - i2c_index; + + status = + VL53L1_i2c_encode_customer_nvm_managed( + pcustomer_nvm, + VL53L1_CUSTOMER_NVM_MANAGED_I2C_SIZE_BYTES, + &buffer[i2c_buffer_offset_bytes]); + } + + if (device_config_level >= VL53L1_DEVICECONFIGLEVEL_STATIC_ONWARDS && + status == VL53L1_ERROR_NONE) { + + i2c_buffer_offset_bytes = + VL53L1_STATIC_CONFIG_I2C_INDEX - i2c_index; + + status = + VL53L1_i2c_encode_static_config( + pstatic, + VL53L1_STATIC_CONFIG_I2C_SIZE_BYTES, + &buffer[i2c_buffer_offset_bytes]); + } + + if (device_config_level >= VL53L1_DEVICECONFIGLEVEL_GENERAL_ONWARDS && + status == VL53L1_ERROR_NONE) { + + i2c_buffer_offset_bytes = + VL53L1_GENERAL_CONFIG_I2C_INDEX - i2c_index; + + status = + VL53L1_i2c_encode_general_config( + pgeneral, + VL53L1_GENERAL_CONFIG_I2C_SIZE_BYTES, + &buffer[i2c_buffer_offset_bytes]); + } + + if (device_config_level >= VL53L1_DEVICECONFIGLEVEL_TIMING_ONWARDS && + status == VL53L1_ERROR_NONE) { + + i2c_buffer_offset_bytes = + VL53L1_TIMING_CONFIG_I2C_INDEX - i2c_index; + + status = + VL53L1_i2c_encode_timing_config( + ptiming, + VL53L1_TIMING_CONFIG_I2C_SIZE_BYTES, + &buffer[i2c_buffer_offset_bytes]); + } + + if (device_config_level >= VL53L1_DEVICECONFIGLEVEL_DYNAMIC_ONWARDS && + status == VL53L1_ERROR_NONE) { + + i2c_buffer_offset_bytes = + VL53L1_DYNAMIC_CONFIG_I2C_INDEX - i2c_index; + + + + if ((psystem->system__mode_start & + VL53L1_DEVICEMEASUREMENTMODE_BACKTOBACK) == + VL53L1_DEVICEMEASUREMENTMODE_BACKTOBACK) { + pdynamic->system__grouped_parameter_hold_0 = + pstate->cfg_gph_id | 0x01; + pdynamic->system__grouped_parameter_hold_1 = + pstate->cfg_gph_id | 0x01; + pdynamic->system__grouped_parameter_hold = + pstate->cfg_gph_id; + } + status = + VL53L1_i2c_encode_dynamic_config( + pdynamic, + VL53L1_DYNAMIC_CONFIG_I2C_SIZE_BYTES, + &buffer[i2c_buffer_offset_bytes]); + } + + if (status == VL53L1_ERROR_NONE) { + + i2c_buffer_offset_bytes = + VL53L1_SYSTEM_CONTROL_I2C_INDEX - i2c_index; + + status = + VL53L1_i2c_encode_system_control( + psystem, + VL53L1_SYSTEM_CONTROL_I2C_SIZE_BYTES, + &buffer[i2c_buffer_offset_bytes]); + } + + + + + if (status == VL53L1_ERROR_NONE) { + status = + VL53L1_WriteMulti( + Dev, + i2c_index, + buffer, + (uint32_t)i2c_buffer_size_bytes); + } + + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_update_ll_driver_rd_state(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_update_ll_driver_cfg_state(Dev); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_stop_range( + VL53L1_DEV Dev) +{ + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_LLDriverResults_t *pres = + VL53L1DevStructGetLLResultsHandle(Dev); + + pdev->sys_ctrl.system__mode_start = + (pdev->sys_ctrl.system__mode_start & + VL53L1_DEVICEMEASUREMENTMODE_STOP_MASK) | + VL53L1_DEVICEMEASUREMENTMODE_ABORT; + + status = VL53L1_set_system_control( + Dev, + &pdev->sys_ctrl); + + pdev->sys_ctrl.system__mode_start = + (pdev->sys_ctrl.system__mode_start & + VL53L1_DEVICEMEASUREMENTMODE_STOP_MASK); + + VL53L1_init_ll_driver_state( + Dev, + VL53L1_DEVICESTATE_SW_STANDBY); + + V53L1_init_zone_results_structure( + pdev->zone_cfg.active_zones+1, + &(pres->zone_results)); + + V53L1_init_zone_dss_configs(Dev); + if (pdev->low_power_auto_data.is_low_power_auto_mode == 1) + VL53L1_low_power_auto_data_stop_range(Dev); + return status; +} + + +VL53L1_Error VL53L1_get_measurement_results( + VL53L1_DEV Dev, + VL53L1_DeviceResultsLevel device_results_level) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + uint8_t buffer[VL53L1_MAX_I2C_XFER_SIZE]; + + VL53L1_system_results_t *psystem_results = &(pdev->sys_results); + VL53L1_core_results_t *pcore_results = &(pdev->core_results); + VL53L1_debug_results_t *pdebug_results = &(pdev->dbg_results); + + uint16_t i2c_index = VL53L1_SYSTEM_RESULTS_I2C_INDEX; + uint16_t i2c_buffer_offset_bytes = 0; + uint16_t i2c_buffer_size_bytes = 0; + + LOG_FUNCTION_START(""); + + + + + switch (device_results_level) { + case VL53L1_DEVICERESULTSLEVEL_FULL: + i2c_buffer_size_bytes = + (VL53L1_DEBUG_RESULTS_I2C_INDEX + + VL53L1_DEBUG_RESULTS_I2C_SIZE_BYTES) - + i2c_index; + break; + case VL53L1_DEVICERESULTSLEVEL_UPTO_CORE: + i2c_buffer_size_bytes = + (VL53L1_CORE_RESULTS_I2C_INDEX + + VL53L1_CORE_RESULTS_I2C_SIZE_BYTES) - + i2c_index; + break; + default: + i2c_buffer_size_bytes = + VL53L1_SYSTEM_RESULTS_I2C_SIZE_BYTES; + break; + } + + + + + if (status == VL53L1_ERROR_NONE) + + status = + VL53L1_ReadMulti( + Dev, + i2c_index, + buffer, + (uint32_t)i2c_buffer_size_bytes); + + + + + if (device_results_level >= VL53L1_DEVICERESULTSLEVEL_FULL && + status == VL53L1_ERROR_NONE) { + + i2c_buffer_offset_bytes = + VL53L1_DEBUG_RESULTS_I2C_INDEX - i2c_index; + + status = + VL53L1_i2c_decode_debug_results( + VL53L1_DEBUG_RESULTS_I2C_SIZE_BYTES, + &buffer[i2c_buffer_offset_bytes], + pdebug_results); + } + + if (device_results_level >= VL53L1_DEVICERESULTSLEVEL_UPTO_CORE && + status == VL53L1_ERROR_NONE) { + + i2c_buffer_offset_bytes = + VL53L1_CORE_RESULTS_I2C_INDEX - i2c_index; + + status = + VL53L1_i2c_decode_core_results( + VL53L1_CORE_RESULTS_I2C_SIZE_BYTES, + &buffer[i2c_buffer_offset_bytes], + pcore_results); + } + + if (status == VL53L1_ERROR_NONE) { + + i2c_buffer_offset_bytes = 0; + status = + VL53L1_i2c_decode_system_results( + VL53L1_SYSTEM_RESULTS_I2C_SIZE_BYTES, + &buffer[i2c_buffer_offset_bytes], + psystem_results); + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_device_results( + VL53L1_DEV Dev, + VL53L1_DeviceResultsLevel device_results_level, + VL53L1_range_results_t *prange_results) +{ + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_LLDriverResults_t *pres = + VL53L1DevStructGetLLResultsHandle(Dev); + + VL53L1_range_results_t *presults = + &(pres->range_results); + VL53L1_zone_objects_t *pobjects = + &(pres->zone_results.VL53L1_p_002[0]); + VL53L1_ll_driver_state_t *pstate = + &(pdev->ll_state); + VL53L1_zone_config_t *pzone_cfg = + &(pdev->zone_cfg); + VL53L1_zone_hist_info_t *phist_info = + &(pres->zone_hists.VL53L1_p_002[0]); + + VL53L1_dmax_calibration_data_t dmax_cal; + VL53L1_dmax_calibration_data_t *pdmax_cal = &dmax_cal; + VL53L1_hist_post_process_config_t *pHP = &(pdev->histpostprocess); + VL53L1_xtalk_config_t *pC = &(pdev->xtalk_cfg); + VL53L1_low_power_auto_data_t *pL = &(pdev->low_power_auto_data); + VL53L1_histogram_bin_data_t *pHD = &(pdev->hist_data); + VL53L1_customer_nvm_managed_t *pN = &(pdev->customer); + VL53L1_zone_histograms_t *pZH = &(pres->zone_hists); + VL53L1_xtalk_calibration_results_t *pXCR = &(pdev->xtalk_cal); + uint8_t tmp8; + uint8_t zid; + uint8_t i; + uint8_t histo_merge_nb; + VL53L1_range_data_t *pdata; + + LOG_FUNCTION_START(""); + + + + + if ((pdev->sys_ctrl.system__mode_start & + VL53L1_DEVICESCHEDULERMODE_HISTOGRAM) + == VL53L1_DEVICESCHEDULERMODE_HISTOGRAM) { + + + + + + + status = VL53L1_get_histogram_bin_data( + Dev, + &(pdev->hist_data)); + + + + + + + + if (status == VL53L1_ERROR_NONE && + pHD->number_of_ambient_bins == 0) { + zid = pdev->ll_state.rd_zone_id; + status = VL53L1_hist_copy_and_scale_ambient_info( + &(pZH->VL53L1_p_002[zid]), + &(pdev->hist_data)); + } + + + + + + + if (status != VL53L1_ERROR_NONE) + goto UPDATE_DYNAMIC_CONFIG; + + VL53L1_compute_histo_merge_nb(Dev, &histo_merge_nb); + if (histo_merge_nb == 0) + histo_merge_nb = 1; + pC->algo__crosstalk_compensation_plane_offset_kcps = + pXCR->algo__xtalk_cpo_HistoMerge_kcps[histo_merge_nb-1]; + + pHP->gain_factor = + pdev->gain_cal.histogram_ranging_gain_factor; + + pHP->algo__crosstalk_compensation_plane_offset_kcps = + VL53L1_calc_crosstalk_plane_offset_with_margin( + pC->algo__crosstalk_compensation_plane_offset_kcps, + pC->histogram_mode_crosstalk_margin_kcps); + + pHP->algo__crosstalk_compensation_x_plane_gradient_kcps = + pC->algo__crosstalk_compensation_x_plane_gradient_kcps; + pHP->algo__crosstalk_compensation_y_plane_gradient_kcps = + pC->algo__crosstalk_compensation_y_plane_gradient_kcps; + + pdev->dmax_cfg.ambient_thresh_sigma = + pHP->ambient_thresh_sigma1; + pdev->dmax_cfg.min_ambient_thresh_events = + pHP->min_ambient_thresh_events; + pdev->dmax_cfg.signal_total_events_limit = + pHP->signal_total_events_limit; + pdev->dmax_cfg.dss_config__target_total_rate_mcps = + pdev->stat_cfg.dss_config__target_total_rate_mcps; + pdev->dmax_cfg.dss_config__aperture_attenuation = + pdev->gen_cfg.dss_config__aperture_attenuation; + + pHP->algo__crosstalk_detect_max_valid_range_mm = + pC->algo__crosstalk_detect_max_valid_range_mm; + pHP->algo__crosstalk_detect_min_valid_range_mm = + pC->algo__crosstalk_detect_min_valid_range_mm; + pHP->algo__crosstalk_detect_max_valid_rate_kcps = + pC->algo__crosstalk_detect_max_valid_rate_kcps; + pHP->algo__crosstalk_detect_max_sigma_mm = + pC->algo__crosstalk_detect_max_sigma_mm; + + + + + VL53L1_copy_rtn_good_spads_to_buffer( + &(pdev->nvm_copy_data), + &(pdev->rtn_good_spads[0])); + + + + + switch (pdev->offset_correction_mode) { + + case VL53L1_OFFSETCORRECTIONMODE__MM1_MM2_OFFSETS: + tmp8 = pdev->gen_cfg.dss_config__aperture_attenuation; + + VL53L1_hist_combine_mm1_mm2_offsets( + pN->mm_config__inner_offset_mm, + pN->mm_config__outer_offset_mm, + pdev->nvm_copy_data.roi_config__mode_roi_centre_spad, + pdev->nvm_copy_data.roi_config__mode_roi_xy_size, + pHD->roi_config__user_roi_centre_spad, + pHD->roi_config__user_roi_requested_global_xy_size, + &(pdev->add_off_cal_data), + &(pdev->rtn_good_spads[0]), + (uint16_t)tmp8, + &(pHP->range_offset_mm)); + break; + case VL53L1_OFFSETCORRECTIONMODE__PER_ZONE_OFFSETS: + zid = pdev->ll_state.rd_zone_id; + pHP->range_offset_mm = (int16_t)( + pres->zone_cal.VL53L1_p_002[zid].range_mm_offset); + break; + case VL53L1_OFFSETCORRECTIONMODE__PER_VCSEL_OFFSETS: + select_offset_per_vcsel( + pdev, + &(pHP->range_offset_mm)); + pHP->range_offset_mm *= 4; + + break; + default: + pHP->range_offset_mm = 0; + break; + + } + #if 0 + if (status != VL53L1_ERROR_NONE) + goto UPDATE_DYNAMIC_CONFIG; + #endif + + VL53L1_calc_max_effective_spads( + pHD->roi_config__user_roi_centre_spad, + pHD->roi_config__user_roi_requested_global_xy_size, + &(pdev->rtn_good_spads[0]), + (uint16_t)pdev->gen_cfg.dss_config__aperture_attenuation, + &(pdev->dmax_cfg.max_effective_spads)); + + status = + VL53L1_get_dmax_calibration_data( + Dev, + pdev->dmax_mode, + pdev->ll_state.rd_zone_id, + pdmax_cal); + + + + + + + if (status != VL53L1_ERROR_NONE) + goto UPDATE_DYNAMIC_CONFIG; + + status = VL53L1_ipp_hist_process_data( + Dev, + pdmax_cal, + &(pdev->dmax_cfg), + &(pdev->histpostprocess), + &(pdev->hist_data), + &(pdev->xtalk_shapes), + pdev->wArea1, + pdev->wArea2, + &histo_merge_nb, + presults); + + + if ((pdev->tuning_parms.tp_hist_merge == 1) && + (histo_merge_nb > 1)) + for (i = 0; i < VL53L1_MAX_RANGE_RESULTS; i++) { + pdata = &(presults->VL53L1_p_002[i]); + pdata->VL53L1_p_020 /= histo_merge_nb; + pdata->VL53L1_p_021 /= histo_merge_nb; + pdata->VL53L1_p_013 /= histo_merge_nb; + pdata->peak_signal_count_rate_mcps /= histo_merge_nb; + pdata->avg_signal_count_rate_mcps /= histo_merge_nb; + pdata->ambient_count_rate_mcps /= histo_merge_nb; + pdata->VL53L1_p_012 /= histo_merge_nb; + } + + + + if (status != VL53L1_ERROR_NONE) + goto UPDATE_DYNAMIC_CONFIG; + + status = VL53L1_hist_wrap_dmax( + &(pdev->histpostprocess), + &(pdev->hist_data), + &(presults->wrap_dmax_mm)); + + + + if (status != VL53L1_ERROR_NONE) + goto UPDATE_DYNAMIC_CONFIG; + + zid = pdev->ll_state.rd_zone_id; + status = VL53L1_hist_phase_consistency_check( + Dev, + &(pZH->VL53L1_p_002[zid]), + &(pres->zone_results.VL53L1_p_002[zid]), + presults); + + + + if (status != VL53L1_ERROR_NONE) + goto UPDATE_DYNAMIC_CONFIG; + + zid = pdev->ll_state.rd_zone_id; + status = VL53L1_hist_xmonitor_consistency_check( + Dev, + &(pZH->VL53L1_p_002[zid]), + &(pres->zone_results.VL53L1_p_002[zid]), + &(presults->xmonitor)); + + + + + + if (status != VL53L1_ERROR_NONE) + goto UPDATE_DYNAMIC_CONFIG; + + + zid = pdev->ll_state.rd_zone_id; + pZH->max_zones = VL53L1_MAX_USER_ZONES; + pZH->active_zones = + pdev->zone_cfg.active_zones+1; + pHD->zone_id = zid; + + if (zid < + pres->zone_results.max_zones) { + + phist_info = + &(pZH->VL53L1_p_002[zid]); + + phist_info->rd_device_state = + pHD->rd_device_state; + + phist_info->number_of_ambient_bins = + pHD->number_of_ambient_bins; + + phist_info->result__dss_actual_effective_spads = + pHD->result__dss_actual_effective_spads; + + phist_info->VL53L1_p_009 = + pHD->VL53L1_p_009; + + phist_info->total_periods_elapsed = + pHD->total_periods_elapsed; + + phist_info->ambient_events_sum = + pHD->ambient_events_sum; + } + + + + + + /* + if (status != VL53L1_ERROR_NONE) + goto UPDATE_DYNAMIC_CONFIG; + */ + VL53L1_hist_copy_results_to_sys_and_core( + &(pdev->hist_data), + presults, + &(pdev->sys_results), + &(pdev->core_results)); + + + + + + +UPDATE_DYNAMIC_CONFIG: + if (pzone_cfg->active_zones > 0) { + if (pstate->rd_device_state != + VL53L1_DEVICESTATE_RANGING_WAIT_GPH_SYNC) { + if (status == VL53L1_ERROR_NONE) { + status = VL53L1_dynamic_zone_update( + Dev, presults); + } + } + + + + + + for (i = 0; i < VL53L1_MAX_USER_ZONES; i++) { + pzone_cfg->bin_config[i] = + ((pdev->ll_state.cfg_internal_stream_count) + & 0x01) ? + VL53L1_ZONECONFIG_BINCONFIG__HIGHAMB : + VL53L1_ZONECONFIG_BINCONFIG__LOWAMB; + } + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_multizone_hist_bins_update(Dev); + + } + + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_dynamic_xtalk_correction_corrector(Dev); + +#ifdef VL53L1_LOG_ENABLE + if (status == VL53L1_ERROR_NONE) + VL53L1_print_histogram_bin_data( + &(pdev->hist_data), + "get_device_results():pdev->lldata.hist_data.", + VL53L1_TRACE_MODULE_HISTOGRAM_DATA); +#endif + + } else { + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_get_measurement_results( + Dev, + device_results_level); + + if (status == VL53L1_ERROR_NONE) + VL53L1_copy_sys_and_core_results_to_range_results( + (int32_t)pdev->gain_cal.standard_ranging_gain_factor, + &(pdev->sys_results), + &(pdev->core_results), + presults); + + + + + + if (pL->is_low_power_auto_mode == 1) { + + + + if ((status == VL53L1_ERROR_NONE) && + (pL->low_power_auto_range_count == 0)) { + + status = + VL53L1_low_power_auto_setup_manual_calibration( + Dev); + pL->low_power_auto_range_count = 1; + } else if ((status == VL53L1_ERROR_NONE) && + (pL->low_power_auto_range_count == 1)) { + pL->low_power_auto_range_count = 2; + } + + + + if ((pL->low_power_auto_range_count != 0xFF) && + (status == VL53L1_ERROR_NONE)) { + status = VL53L1_low_power_auto_update_DSS( + Dev); + } + } + + + } + + + + presults->cfg_device_state = pdev->ll_state.cfg_device_state; + presults->rd_device_state = pdev->ll_state.rd_device_state; + presults->zone_id = pdev->ll_state.rd_zone_id; + + if (status == VL53L1_ERROR_NONE) { + + + + pres->zone_results.max_zones = VL53L1_MAX_USER_ZONES; + pres->zone_results.active_zones = pdev->zone_cfg.active_zones+1; + zid = pdev->ll_state.rd_zone_id; + + if (zid < pres->zone_results.max_zones) { + + pobjects = + &(pres->zone_results.VL53L1_p_002[zid]); + + pobjects->cfg_device_state = + presults->cfg_device_state; + pobjects->rd_device_state = presults->rd_device_state; + pobjects->zone_id = presults->zone_id; + pobjects->stream_count = presults->stream_count; + + + + + pobjects->xmonitor.VL53L1_p_020 = + presults->xmonitor.VL53L1_p_020; + pobjects->xmonitor.VL53L1_p_021 = + presults->xmonitor.VL53L1_p_021; + pobjects->xmonitor.VL53L1_p_014 = + presults->xmonitor.VL53L1_p_014; + pobjects->xmonitor.range_status = + presults->xmonitor.range_status; + + pobjects->max_objects = presults->max_results; + pobjects->active_objects = presults->active_results; + + for (i = 0; i < presults->active_results; i++) { + pobjects->VL53L1_p_002[i].VL53L1_p_020 = + presults->VL53L1_p_002[i].VL53L1_p_020; + pobjects->VL53L1_p_002[i].VL53L1_p_021 = + presults->VL53L1_p_002[i].VL53L1_p_021; + pobjects->VL53L1_p_002[i].VL53L1_p_014 = + presults->VL53L1_p_002[i].VL53L1_p_014; + pobjects->VL53L1_p_002[i].range_status = + presults->VL53L1_p_002[i].range_status; + } + + + + } + } + + + + + memcpy( + prange_results, + presults, + sizeof(VL53L1_range_results_t)); + + + + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_check_ll_driver_rd_state(Dev); + +#ifdef VL53L1_LOG_ENABLE + if (status == VL53L1_ERROR_NONE) + VL53L1_print_range_results( + presults, + "get_device_results():pdev->llresults.range_results.", + VL53L1_TRACE_MODULE_RANGE_RESULTS_DATA); +#endif + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_clear_interrupt_and_enable_next_range( + VL53L1_DEV Dev, + uint8_t measurement_mode) +{ + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + + + + + + + + + + + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_init_and_start_range( + Dev, + measurement_mode, + VL53L1_DEVICECONFIGLEVEL_GENERAL_ONWARDS); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_histogram_bin_data( + VL53L1_DEV Dev, + VL53L1_histogram_bin_data_t *pdata) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_LLDriverResults_t *pres = + VL53L1DevStructGetLLResultsHandle(Dev); + + VL53L1_zone_private_dyn_cfg_t *pzone_dyn_cfg; + + VL53L1_static_nvm_managed_t *pstat_nvm = &(pdev->stat_nvm); + VL53L1_static_config_t *pstat_cfg = &(pdev->stat_cfg); + VL53L1_general_config_t *pgen_cfg = &(pdev->gen_cfg); + VL53L1_timing_config_t *ptim_cfg = &(pdev->tim_cfg); + VL53L1_range_results_t *presults = &(pres->range_results); + + uint8_t buffer[VL53L1_MAX_I2C_XFER_SIZE]; + uint8_t *pbuffer = &buffer[0]; + uint8_t bin_23_0 = 0x00; + uint16_t bin = 0; + uint16_t i2c_buffer_offset_bytes = 0; + uint16_t encoded_timeout = 0; + + uint32_t pll_period_us = 0; + uint32_t periods_elapsed_tmp = 0; + + uint8_t i = 0; + int32_t hist_merge = 0; + int32_t TuningBinRecSize = 0; + uint8_t recom_been_reset = 0; + uint8_t timing = 0; + int32_t rmt = 0; + + int32_t diff_histo_stddev = 0; + int32_t total_rate_pre = 0; + int32_t total_rate_cur = 0; + uint8_t HighIndex, prev_pos; + int32_t PrevBin, CurrBin; + size_t copylength; + + LOG_FUNCTION_START(""); + + + + + + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_ReadMulti( + Dev, + VL53L1_HISTOGRAM_BIN_DATA_I2C_INDEX, + pbuffer, + VL53L1_HISTOGRAM_BIN_DATA_I2C_SIZE_BYTES); + + + + + + + pdata->result__interrupt_status = *(pbuffer + 0); + pdata->result__range_status = *(pbuffer + 1); + pdata->result__report_status = *(pbuffer + 2); + pdata->result__stream_count = *(pbuffer + 3); + pdata->result__dss_actual_effective_spads = + VL53L1_i2c_decode_uint16_t(2, pbuffer + 4); + + + + + + + i2c_buffer_offset_bytes = + VL53L1_PHASECAL_RESULT__REFERENCE_PHASE - + VL53L1_HISTOGRAM_BIN_DATA_I2C_INDEX; + + pbuffer = &buffer[i2c_buffer_offset_bytes]; + + pdata->phasecal_result__reference_phase = + VL53L1_i2c_decode_uint16_t(2, pbuffer); + + i2c_buffer_offset_bytes = + VL53L1_PHASECAL_RESULT__VCSEL_START - + VL53L1_HISTOGRAM_BIN_DATA_I2C_INDEX; + + pdata->phasecal_result__vcsel_start = buffer[i2c_buffer_offset_bytes]; + + + + + pdev->dbg_results.phasecal_result__reference_phase = + pdata->phasecal_result__reference_phase; + pdev->dbg_results.phasecal_result__vcsel_start = + pdata->phasecal_result__vcsel_start; + + + + + + + + i2c_buffer_offset_bytes = + VL53L1_RESULT__HISTOGRAM_BIN_23_0_MSB - + VL53L1_HISTOGRAM_BIN_DATA_I2C_INDEX; + + bin_23_0 = buffer[i2c_buffer_offset_bytes] << 2; + + i2c_buffer_offset_bytes = + VL53L1_RESULT__HISTOGRAM_BIN_23_0_LSB - + VL53L1_HISTOGRAM_BIN_DATA_I2C_INDEX; + + bin_23_0 += buffer[i2c_buffer_offset_bytes]; + + i2c_buffer_offset_bytes = + VL53L1_RESULT__HISTOGRAM_BIN_23_0 - + VL53L1_HISTOGRAM_BIN_DATA_I2C_INDEX; + + buffer[i2c_buffer_offset_bytes] = bin_23_0; + + + + + + + + i2c_buffer_offset_bytes = + VL53L1_RESULT__HISTOGRAM_BIN_0_2 - + VL53L1_HISTOGRAM_BIN_DATA_I2C_INDEX; + + pbuffer = &buffer[i2c_buffer_offset_bytes]; + for (bin = 0; bin < VL53L1_HISTOGRAM_BUFFER_SIZE; bin++) { + pdata->bin_data[bin] = + (int32_t)VL53L1_i2c_decode_uint32_t(3, pbuffer); + pbuffer += 3; + } + + + + + + + + + + + VL53L1_get_tuning_parm(Dev, VL53L1_TUNINGPARM_HIST_MERGE, + &hist_merge); + + VL53L1_get_tuning_parm(Dev, VL53L1_TUNINGPARM_HIST_MERGE_MAX_SIZE, + &TuningBinRecSize); + + VL53L1_get_tuning_parm(Dev, VL53L1_TUNINGPARM_RESET_MERGE_THRESHOLD, &rmt); + + if (pdata->result__stream_count == 0) { + + + memset(pdev->multi_bins_rec, 0, sizeof(pdev->multi_bins_rec)); + pdev->bin_rec_pos = 0; + pdev->pos_before_next_recom = 0; + } + + if (hist_merge == 1) { + + + + + + + + + if (pdev->pos_before_next_recom == 0) { + + + timing = 1 - pdata->result__stream_count % 2; + + + + + + diff_histo_stddev = 0; + total_rate_pre = 0; + total_rate_cur = 0; + HighIndex = VL53L1_HISTOGRAM_BUFFER_SIZE - timing * 4; + if (pdev->bin_rec_pos > 0) + prev_pos = pdev->bin_rec_pos - 1; + else + prev_pos = (TuningBinRecSize - 1); + + if (pdev->multi_bins_rec[prev_pos][timing][4] > 0) { + + + for (bin = timing * 4; bin < HighIndex; bin++) { + total_rate_pre += + pdev->multi_bins_rec[prev_pos][timing][bin]; + total_rate_cur += pdata->bin_data[bin]; + } + + if ((total_rate_pre != 0) && (total_rate_cur != 0)) + for (bin = timing * 4; bin < HighIndex; bin++) { + PrevBin = pdev->multi_bins_rec[prev_pos][timing][bin]; + PrevBin = (PrevBin * 1000) / total_rate_pre; + CurrBin = pdata->bin_data[bin] * 1000 / total_rate_cur; + diff_histo_stddev += (PrevBin - CurrBin) * + (PrevBin - CurrBin); + } + } + + if (diff_histo_stddev >= rmt) { + memset(pdev->multi_bins_rec, 0, sizeof(pdev->multi_bins_rec)); + pdev->bin_rec_pos = 0; + + + recom_been_reset = 1; + + + + + + + + if (timing == 0) + pdev->pos_before_next_recom = VL53L1_FRAME_WAIT_EVENT; + else + pdev->pos_before_next_recom = VL53L1_FRAME_WAIT_EVENT + 1; + } else { + + + + + + copylength = + sizeof(pdev->multi_bins_rec[pdev->bin_rec_pos][timing]); + memcpy(&(pdev->multi_bins_rec[pdev->bin_rec_pos][timing]), + pdata->bin_data, copylength); + } + + + + + + + + if (pdev->bin_rec_pos == (TuningBinRecSize - 1) && timing == 1) + pdev->bin_rec_pos = 0; + else if (timing == 1) + pdev->bin_rec_pos++; + + + + + + + + + if (!((recom_been_reset == 1) && (timing == 0)) && + (pdev->pos_before_next_recom == 0)) { + + + + + for (bin = 0; bin < VL53L1_HISTOGRAM_BUFFER_SIZE; bin++) + pdata->bin_data[bin] = 0; + + + + + for (bin = 0; bin < VL53L1_HISTOGRAM_BUFFER_SIZE; bin++) + for (i = 0; i < TuningBinRecSize; i++) + pdata->bin_data[bin] += + (pdev->multi_bins_rec[i][timing][bin]); + } + } else { + + + + + + pdev->pos_before_next_recom--; + if (pdev->pos_before_next_recom == 255) + pdev->pos_before_next_recom = 0; + } + } + + + + pdata->zone_id = pdev->ll_state.rd_zone_id; + pdata->VL53L1_p_022 = 0; + pdata->VL53L1_p_023 = VL53L1_HISTOGRAM_BUFFER_SIZE; + pdata->VL53L1_p_024 = VL53L1_HISTOGRAM_BUFFER_SIZE; + + pdata->cal_config__vcsel_start = pgen_cfg->cal_config__vcsel_start; + + + + + pdata->vcsel_width = + ((uint16_t)pgen_cfg->global_config__vcsel_width) << 4; + pdata->vcsel_width += + (uint16_t)pstat_cfg->ana_config__vcsel_pulse_width_offset; + + + + pdata->VL53L1_p_019 = + pstat_nvm->osc_measured__fast_osc__frequency; + + + + + VL53L1_hist_get_bin_sequence_config(Dev, pdata); + + + + + + + if (pdev->ll_state.rd_timing_status == 0) { + + encoded_timeout = + (ptim_cfg->range_config__timeout_macrop_a_hi << 8) + + ptim_cfg->range_config__timeout_macrop_a_lo; + pdata->VL53L1_p_009 = ptim_cfg->range_config__vcsel_period_a; + } else { + + encoded_timeout = + (ptim_cfg->range_config__timeout_macrop_b_hi << 8) + + ptim_cfg->range_config__timeout_macrop_b_lo; + pdata->VL53L1_p_009 = ptim_cfg->range_config__vcsel_period_b; + } + + + + + pdata->number_of_ambient_bins = 0; + + for (i = 0; i < 6; i++) { + if ((pdata->bin_seq[i] & 0x07) == 0x07) + pdata->number_of_ambient_bins = + pdata->number_of_ambient_bins + 0x04; + } + + pdata->total_periods_elapsed = + VL53L1_decode_timeout(encoded_timeout); + + + + + + + + pll_period_us = + VL53L1_calc_pll_period_us(pdata->VL53L1_p_019); + + + + + periods_elapsed_tmp = pdata->total_periods_elapsed + 1; + + + + + + + pdata->peak_duration_us = + VL53L1_duration_maths( + pll_period_us, + (uint32_t)pdata->vcsel_width, + VL53L1_RANGING_WINDOW_VCSEL_PERIODS, + periods_elapsed_tmp); + + pdata->woi_duration_us = 0; + + + + + VL53L1_hist_calc_zero_distance_phase(pdata); + + + + + + + VL53L1_hist_estimate_ambient_from_ambient_bins(pdata); + + + + + pdata->cfg_device_state = pdev->ll_state.cfg_device_state; + pdata->rd_device_state = pdev->ll_state.rd_device_state; + + + + + pzone_dyn_cfg = &(pres->zone_dyn_cfgs.VL53L1_p_002[pdata->zone_id]); + + pdata->roi_config__user_roi_centre_spad = + pzone_dyn_cfg->roi_config__user_roi_centre_spad; + pdata->roi_config__user_roi_requested_global_xy_size = + pzone_dyn_cfg->roi_config__user_roi_requested_global_xy_size; + + + + + + + presults->device_status = VL53L1_DEVICEERROR_NOUPDATE; + + + + + switch (pdata->result__range_status & + VL53L1_RANGE_STATUS__RANGE_STATUS_MASK) { + + case VL53L1_DEVICEERROR_VCSELCONTINUITYTESTFAILURE: + case VL53L1_DEVICEERROR_VCSELWATCHDOGTESTFAILURE: + case VL53L1_DEVICEERROR_NOVHVVALUEFOUND: + case VL53L1_DEVICEERROR_USERROICLIP: + case VL53L1_DEVICEERROR_MULTCLIPFAIL: + + presults->device_status = (pdata->result__range_status & + VL53L1_RANGE_STATUS__RANGE_STATUS_MASK); + + status = VL53L1_ERROR_RANGE_ERROR; + + break; + + } + + LOG_FUNCTION_END(status); + + return status; +} + + +void VL53L1_copy_sys_and_core_results_to_range_results( + int32_t gain_factor, + VL53L1_system_results_t *psys, + VL53L1_core_results_t *pcore, + VL53L1_range_results_t *presults) +{ + uint8_t i = 0; + + VL53L1_range_data_t *pdata; + int32_t range_mm = 0; + uint32_t tmpu32 = 0; + uint16_t rpscr_crosstalk_corrected_mcps_sd0; + uint16_t rmmo_effective_spads_sd0; + uint16_t rmmi_effective_spads_sd0; + + LOG_FUNCTION_START(""); + + + + + presults->zone_id = 0; + presults->stream_count = psys->result__stream_count; + presults->wrap_dmax_mm = 0; + presults->max_results = VL53L1_MAX_RANGE_RESULTS; + presults->active_results = 1; + rpscr_crosstalk_corrected_mcps_sd0 = + psys->result__peak_signal_count_rate_crosstalk_corrected_mcps_sd0; + rmmo_effective_spads_sd0 = + psys->result__mm_outer_actual_effective_spads_sd0; + rmmi_effective_spads_sd0 = + psys->result__mm_inner_actual_effective_spads_sd0; + + + for (i = 0; i < VL53L1_MAX_AMBIENT_DMAX_VALUES; i++) + presults->VL53L1_p_007[i] = 0; + + pdata = &(presults->VL53L1_p_002[0]); + + for (i = 0; i < 2; i++) { + + pdata->range_id = i; + pdata->time_stamp = 0; + + if ((psys->result__stream_count == 0) && + ((psys->result__range_status & + VL53L1_RANGE_STATUS__RANGE_STATUS_MASK) == + VL53L1_DEVICEERROR_RANGECOMPLETE)) { + pdata->range_status = + VL53L1_DEVICEERROR_RANGECOMPLETE_NO_WRAP_CHECK; + } else { + pdata->range_status = + psys->result__range_status & + VL53L1_RANGE_STATUS__RANGE_STATUS_MASK; + } + + pdata->VL53L1_p_015 = 0; + pdata->VL53L1_p_022 = 0; + pdata->VL53L1_p_025 = 0; + pdata->VL53L1_p_026 = 0; + pdata->VL53L1_p_016 = 0; + pdata->VL53L1_p_027 = 0; + + switch (i) { + + case 0: + if (psys->result__report_status == + VL53L1_DEVICEREPORTSTATUS_MM1) + pdata->VL53L1_p_006 = + rmmi_effective_spads_sd0; + else if (psys->result__report_status == + VL53L1_DEVICEREPORTSTATUS_MM2) + pdata->VL53L1_p_006 = + rmmo_effective_spads_sd0; + else + pdata->VL53L1_p_006 = + psys->result__dss_actual_effective_spads_sd0; + + pdata->peak_signal_count_rate_mcps = + rpscr_crosstalk_corrected_mcps_sd0; + pdata->avg_signal_count_rate_mcps = + psys->result__avg_signal_count_rate_mcps_sd0; + pdata->ambient_count_rate_mcps = + psys->result__ambient_count_rate_mcps_sd0; + + + + + + + tmpu32 = ((uint32_t)psys->result__sigma_sd0 << 5); + if (tmpu32 > 0xFFFF) + tmpu32 = 0xFFFF; + + pdata->VL53L1_p_005 = (uint16_t)tmpu32; + + + + + pdata->VL53L1_p_014 = + psys->result__phase_sd0; + + range_mm = (int32_t)( + psys->result__final_crosstalk_corrected_range_mm_sd0); + + + + range_mm *= gain_factor; + range_mm += 0x0400; + range_mm /= 0x0800; + + pdata->median_range_mm = (int16_t)range_mm; + + pdata->VL53L1_p_021 = + pcore->result_core__ranging_total_events_sd0; + pdata->VL53L1_p_013 = + pcore->result_core__signal_total_events_sd0; + pdata->total_periods_elapsed = + pcore->result_core__total_periods_elapsed_sd0; + pdata->VL53L1_p_020 = + pcore->result_core__ambient_window_events_sd0; + + break; + case 1: + + pdata->VL53L1_p_006 = + psys->result__dss_actual_effective_spads_sd1; + pdata->peak_signal_count_rate_mcps = + psys->result__peak_signal_count_rate_mcps_sd1; + pdata->avg_signal_count_rate_mcps = + 0xFFFF; + pdata->ambient_count_rate_mcps = + psys->result__ambient_count_rate_mcps_sd1; + + + + + + + tmpu32 = ((uint32_t)psys->result__sigma_sd1 << 5); + if (tmpu32 > 0xFFFF) + tmpu32 = 0xFFFF; + + pdata->VL53L1_p_005 = (uint16_t)tmpu32; + + + + + pdata->VL53L1_p_014 = + psys->result__phase_sd1; + + range_mm = (int32_t)( + psys->result__final_crosstalk_corrected_range_mm_sd1); + + + + range_mm *= gain_factor; + range_mm += 0x0400; + range_mm /= 0x0800; + + pdata->median_range_mm = (int16_t)range_mm; + + pdata->VL53L1_p_021 = + pcore->result_core__ranging_total_events_sd1; + pdata->VL53L1_p_013 = + pcore->result_core__signal_total_events_sd1; + pdata->total_periods_elapsed = + pcore->result_core__total_periods_elapsed_sd1; + pdata->VL53L1_p_020 = + pcore->result_core__ambient_window_events_sd1; + + break; + } + + + + + + pdata->VL53L1_p_028 = pdata->VL53L1_p_014; + pdata->VL53L1_p_029 = pdata->VL53L1_p_014; + pdata->min_range_mm = pdata->median_range_mm; + pdata->max_range_mm = pdata->median_range_mm; + + pdata++; + } + + + + + + + presults->device_status = VL53L1_DEVICEERROR_NOUPDATE; + + + + + + + + + switch (psys->result__range_status & + VL53L1_RANGE_STATUS__RANGE_STATUS_MASK) { + + case VL53L1_DEVICEERROR_VCSELCONTINUITYTESTFAILURE: + case VL53L1_DEVICEERROR_VCSELWATCHDOGTESTFAILURE: + case VL53L1_DEVICEERROR_NOVHVVALUEFOUND: + case VL53L1_DEVICEERROR_USERROICLIP: + case VL53L1_DEVICEERROR_MULTCLIPFAIL: + + presults->device_status = (psys->result__range_status & + VL53L1_RANGE_STATUS__RANGE_STATUS_MASK); + + presults->VL53L1_p_002[0].range_status = + VL53L1_DEVICEERROR_NOUPDATE; + break; + + } + + LOG_FUNCTION_END(0); +} + + +VL53L1_Error VL53L1_set_zone_dss_config( + VL53L1_DEV Dev, + VL53L1_zone_private_dyn_cfg_t *pzone_dyn_cfg) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_ll_driver_state_t *pstate = &(pdev->ll_state); + + LOG_FUNCTION_START(""); + + if (pstate->cfg_device_state == + VL53L1_DEVICESTATE_RANGING_DSS_MANUAL) { + pdev->gen_cfg.dss_config__roi_mode_control = + VL53L1_DSS_CONTROL__MODE_EFFSPADS; + pdev->gen_cfg.dss_config__manual_effective_spads_select = + pzone_dyn_cfg->dss_requested_effective_spad_count; + } else { + pdev->gen_cfg.dss_config__roi_mode_control = + VL53L1_DSS_CONTROL__MODE_TARGET_RATE; + } + + LOG_FUNCTION_END(status); + return status; +} + + +VL53L1_Error VL53L1_calc_ambient_dmax( + VL53L1_DEV Dev, + uint16_t target_reflectance, + int16_t *pambient_dmax_mm) +{ + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + + VL53L1_dmax_calibration_data_t dmax_cal; + VL53L1_dmax_calibration_data_t *pdmax_cal = &dmax_cal; + + LOG_FUNCTION_START(""); + + + + + + + status = + VL53L1_get_dmax_calibration_data( + Dev, + pdev->debug_mode, + pdev->ll_state.rd_zone_id, + pdmax_cal); + + + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_ipp_hist_ambient_dmax( + Dev, + target_reflectance, + &(pdev->fmt_dmax_cal), + &(pdev->dmax_cfg), + &(pdev->hist_data), + pambient_dmax_mm); + + LOG_FUNCTION_END(status); + + return status; +} + + + + + + +VL53L1_Error VL53L1_set_GPIO_interrupt_config( + VL53L1_DEV Dev, + VL53L1_GPIO_Interrupt_Mode intr_mode_distance, + VL53L1_GPIO_Interrupt_Mode intr_mode_rate, + uint8_t intr_new_measure_ready, + uint8_t intr_no_target, + uint8_t intr_combined_mode, + uint16_t thresh_distance_high, + uint16_t thresh_distance_low, + uint16_t thresh_rate_high, + uint16_t thresh_rate_low + ) +{ + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_GPIO_interrupt_config_t *pintconf = + &(pdev->gpio_interrupt_config); + + LOG_FUNCTION_START(""); + + + + pintconf->intr_mode_distance = intr_mode_distance; + pintconf->intr_mode_rate = intr_mode_rate; + pintconf->intr_new_measure_ready = intr_new_measure_ready; + pintconf->intr_no_target = intr_no_target; + pintconf->intr_combined_mode = intr_combined_mode; + pintconf->threshold_distance_high = thresh_distance_high; + pintconf->threshold_distance_low = thresh_distance_low; + pintconf->threshold_rate_high = thresh_rate_high; + pintconf->threshold_rate_low = thresh_rate_low; + + + + pdev->gen_cfg.system__interrupt_config_gpio = + VL53L1_encode_GPIO_interrupt_config(pintconf); + + + + + status = VL53L1_set_GPIO_thresholds_from_struct( + Dev, + pintconf); + + LOG_FUNCTION_END(status); + return status; +} + + + + + + +VL53L1_Error VL53L1_set_GPIO_interrupt_config_struct( + VL53L1_DEV Dev, + VL53L1_GPIO_interrupt_config_t intconf) +{ + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_GPIO_interrupt_config_t *pintconf = + &(pdev->gpio_interrupt_config); + + LOG_FUNCTION_START(""); + + + + memcpy(pintconf, &(intconf), sizeof(VL53L1_GPIO_interrupt_config_t)); + + + + pdev->gen_cfg.system__interrupt_config_gpio = + VL53L1_encode_GPIO_interrupt_config(pintconf); + + + + status = VL53L1_set_GPIO_thresholds_from_struct( + Dev, + pintconf); + + LOG_FUNCTION_END(status); + return status; +} + + + + + + +VL53L1_Error VL53L1_get_GPIO_interrupt_config( + VL53L1_DEV Dev, + VL53L1_GPIO_interrupt_config_t *pintconf) +{ + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + + + + + + pdev->gpio_interrupt_config = VL53L1_decode_GPIO_interrupt_config( + pdev->gen_cfg.system__interrupt_config_gpio); + + + + + + pdev->gpio_interrupt_config.threshold_distance_high = + pdev->dyn_cfg.system__thresh_high; + pdev->gpio_interrupt_config.threshold_distance_low = + pdev->dyn_cfg.system__thresh_low; + + pdev->gpio_interrupt_config.threshold_rate_high = + pdev->gen_cfg.system__thresh_rate_high; + pdev->gpio_interrupt_config.threshold_rate_low = + pdev->gen_cfg.system__thresh_rate_low; + + if (pintconf == &(pdev->gpio_interrupt_config)) { + + + } else { + + + + memcpy(pintconf, &(pdev->gpio_interrupt_config), + sizeof(VL53L1_GPIO_interrupt_config_t)); + } + + LOG_FUNCTION_END(status); + return status; +} + + +VL53L1_Error VL53L1_set_dmax_mode( + VL53L1_DEV Dev, + VL53L1_DeviceDmaxMode dmax_mode) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + pdev->dmax_mode = dmax_mode; + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_dmax_mode( + VL53L1_DEV Dev, + VL53L1_DeviceDmaxMode *pdmax_mode) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + *pdmax_mode = pdev->dmax_mode; + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_dmax_calibration_data( + VL53L1_DEV Dev, + VL53L1_DeviceDmaxMode dmax_mode, + uint8_t zone_id, + VL53L1_dmax_calibration_data_t *pdmax_cal) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_LLDriverResults_t *pres = + VL53L1DevStructGetLLResultsHandle(Dev); + + LOG_FUNCTION_START(""); + + switch (dmax_mode) { + + case VL53L1_DEVICEDMAXMODE__PER_ZONE_CAL_DATA: + pdmax_cal->ref__actual_effective_spads = + (uint16_t)pres->zone_cal.VL53L1_p_002[zone_id].effective_spads; + pdmax_cal->ref__peak_signal_count_rate_mcps = + (uint16_t)pres->zone_cal.VL53L1_p_002[zone_id].peak_rate_mcps; + pdmax_cal->ref__distance_mm = + pres->zone_cal.cal_distance_mm; + pdmax_cal->ref_reflectance_pc = + pres->zone_cal.cal_reflectance_pc; + pdmax_cal->coverglass_transmission = 0x0100; + break; + + case VL53L1_DEVICEDMAXMODE__CUST_CAL_DATA: + memcpy( + pdmax_cal, + &(pdev->cust_dmax_cal), + sizeof(VL53L1_dmax_calibration_data_t)); + break; + + case VL53L1_DEVICEDMAXMODE__FMT_CAL_DATA: + memcpy( + pdmax_cal, + &(pdev->fmt_dmax_cal), + sizeof(VL53L1_dmax_calibration_data_t)); + break; + + default: + status = VL53L1_ERROR_INVALID_PARAMS; + break; + + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_hist_dmax_config( + VL53L1_DEV Dev, + VL53L1_hist_gen3_dmax_config_t *pdmax_cfg) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + + + memcpy( + &(pdev->dmax_cfg), + pdmax_cfg, + sizeof(VL53L1_hist_gen3_dmax_config_t)); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_hist_dmax_config( + VL53L1_DEV Dev, + VL53L1_hist_gen3_dmax_config_t *pdmax_cfg) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + + + memcpy( + pdmax_cfg, + &(pdev->dmax_cfg), + sizeof(VL53L1_hist_gen3_dmax_config_t)); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_offset_calibration_mode( + VL53L1_DEV Dev, + VL53L1_OffsetCalibrationMode offset_cal_mode) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + pdev->offset_calibration_mode = offset_cal_mode; + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_offset_calibration_mode( + VL53L1_DEV Dev, + VL53L1_OffsetCalibrationMode *poffset_cal_mode) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + *poffset_cal_mode = pdev->offset_calibration_mode; + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_offset_correction_mode( + VL53L1_DEV Dev, + VL53L1_OffsetCorrectionMode offset_cor_mode) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + pdev->offset_correction_mode = offset_cor_mode; + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_offset_correction_mode( + VL53L1_DEV Dev, + VL53L1_OffsetCorrectionMode *poffset_cor_mode) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + *poffset_cor_mode = pdev->offset_correction_mode; + + LOG_FUNCTION_END(status); + + return status; +} + + + + + +VL53L1_Error VL53L1_set_zone_calibration_data( + VL53L1_DEV Dev, + VL53L1_zone_calibration_results_t *pzone_cal) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverResults_t *pres = VL53L1DevStructGetLLResultsHandle(Dev); + + LOG_FUNCTION_START(""); + + if (pzone_cal->struct_version != + VL53L1_LL_ZONE_CALIBRATION_DATA_STRUCT_VERSION) + status = VL53L1_ERROR_INVALID_PARAMS; + + + if (status == VL53L1_ERROR_NONE) + + + memcpy( + &(pres->zone_cal), + pzone_cal, + sizeof(VL53L1_zone_calibration_results_t)); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_zone_calibration_data( + VL53L1_DEV Dev, + VL53L1_zone_calibration_results_t *pzone_cal) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverResults_t *pres = VL53L1DevStructGetLLResultsHandle(Dev); + + LOG_FUNCTION_START(""); + + + + memcpy( + pzone_cal, + &(pres->zone_cal), + sizeof(VL53L1_zone_calibration_results_t)); + + pzone_cal->struct_version = + VL53L1_LL_ZONE_CALIBRATION_DATA_STRUCT_VERSION; + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_tuning_debug_data( + VL53L1_DEV Dev, + VL53L1_tuning_parameters_t *ptun_data) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_hist_post_process_config_t *pHP = &(pdev->histpostprocess); + VL53L1_xtalkextract_config_t *pXC = &(pdev->xtalk_extract_cfg); + + LOG_FUNCTION_START(""); + + ptun_data->vl53l1_tuningparm_version = + pdev->tuning_parms.tp_tuning_parm_version; + + ptun_data->vl53l1_tuningparm_key_table_version = + pdev->tuning_parms.tp_tuning_parm_key_table_version; + + + ptun_data->vl53l1_tuningparm_lld_version = + pdev->tuning_parms.tp_tuning_parm_lld_version; + + ptun_data->vl53l1_tuningparm_hist_algo_select = + pHP->hist_algo_select; + + ptun_data->vl53l1_tuningparm_hist_target_order = + pHP->hist_target_order; + + ptun_data->vl53l1_tuningparm_hist_filter_woi_0 = + pHP->filter_woi0; + + ptun_data->vl53l1_tuningparm_hist_filter_woi_1 = + pHP->filter_woi1; + + ptun_data->vl53l1_tuningparm_hist_amb_est_method = + pHP->hist_amb_est_method; + + ptun_data->vl53l1_tuningparm_hist_amb_thresh_sigma_0 = + pHP->ambient_thresh_sigma0; + + ptun_data->vl53l1_tuningparm_hist_amb_thresh_sigma_1 = + pHP->ambient_thresh_sigma1; + + ptun_data->vl53l1_tuningparm_hist_min_amb_thresh_events = + pHP->min_ambient_thresh_events; + + ptun_data->vl53l1_tuningparm_hist_amb_events_scaler = + pHP->ambient_thresh_events_scaler; + + ptun_data->vl53l1_tuningparm_hist_noise_threshold = + pHP->noise_threshold; + + ptun_data->vl53l1_tuningparm_hist_signal_total_events_limit = + pHP->signal_total_events_limit; + + ptun_data->vl53l1_tuningparm_hist_sigma_est_ref_mm = + pHP->sigma_estimator__sigma_ref_mm; + + ptun_data->vl53l1_tuningparm_hist_sigma_thresh_mm = + pHP->sigma_thresh; + + ptun_data->vl53l1_tuningparm_hist_gain_factor = + pdev->gain_cal.histogram_ranging_gain_factor; + + ptun_data->vl53l1_tuningparm_consistency_hist_phase_tolerance = + pHP->algo__consistency_check__phase_tolerance; + + ptun_data->vl53l1_tuningparm_consistency_hist_min_max_tolerance_mm = + pHP->algo__consistency_check__min_max_tolerance; + + ptun_data->vl53l1_tuningparm_consistency_hist_event_sigma = + pHP->algo__consistency_check__event_sigma; + + ptun_data->vl53l1_tuningparm_consistency_hist_event_sigma_min_spad_limit + = pHP->algo__consistency_check__event_min_spad_count; + + ptun_data->vl53l1_tuningparm_initial_phase_rtn_histo_long_range = + pdev->tuning_parms.tp_init_phase_rtn_hist_long; + + ptun_data->vl53l1_tuningparm_initial_phase_rtn_histo_med_range = + pdev->tuning_parms.tp_init_phase_rtn_hist_med; + + ptun_data->vl53l1_tuningparm_initial_phase_rtn_histo_short_range = + pdev->tuning_parms.tp_init_phase_rtn_hist_short; + + ptun_data->vl53l1_tuningparm_initial_phase_ref_histo_long_range = + pdev->tuning_parms.tp_init_phase_ref_hist_long; + + ptun_data->vl53l1_tuningparm_initial_phase_ref_histo_med_range = + pdev->tuning_parms.tp_init_phase_ref_hist_med; + + ptun_data->vl53l1_tuningparm_initial_phase_ref_histo_short_range = + pdev->tuning_parms.tp_init_phase_ref_hist_short; + + ptun_data->vl53l1_tuningparm_xtalk_detect_min_valid_range_mm = + pdev->xtalk_cfg.algo__crosstalk_detect_min_valid_range_mm; + + ptun_data->vl53l1_tuningparm_xtalk_detect_max_valid_range_mm = + pdev->xtalk_cfg.algo__crosstalk_detect_max_valid_range_mm; + + ptun_data->vl53l1_tuningparm_xtalk_detect_max_sigma_mm = + pdev->xtalk_cfg.algo__crosstalk_detect_max_sigma_mm; + + ptun_data->vl53l1_tuningparm_xtalk_detect_min_max_tolerance = + pHP->algo__crosstalk_detect_min_max_tolerance; + + ptun_data->vl53l1_tuningparm_xtalk_detect_max_valid_rate_kcps = + pdev->xtalk_cfg.algo__crosstalk_detect_max_valid_rate_kcps; + + ptun_data->vl53l1_tuningparm_xtalk_detect_event_sigma = + pHP->algo__crosstalk_detect_event_sigma; + + ptun_data->vl53l1_tuningparm_hist_xtalk_margin_kcps = + pdev->xtalk_cfg.histogram_mode_crosstalk_margin_kcps; + + ptun_data->vl53l1_tuningparm_consistency_lite_phase_tolerance = + pdev->tuning_parms.tp_consistency_lite_phase_tolerance; + + ptun_data->vl53l1_tuningparm_phasecal_target = + pdev->tuning_parms.tp_phasecal_target; + + ptun_data->vl53l1_tuningparm_lite_cal_repeat_rate = + pdev->tuning_parms.tp_cal_repeat_rate; + + ptun_data->vl53l1_tuningparm_lite_ranging_gain_factor = + pdev->gain_cal.standard_ranging_gain_factor; + + ptun_data->vl53l1_tuningparm_lite_min_clip_mm = + pdev->tuning_parms.tp_lite_min_clip; + + ptun_data->vl53l1_tuningparm_lite_long_sigma_thresh_mm = + pdev->tuning_parms.tp_lite_long_sigma_thresh_mm; + + ptun_data->vl53l1_tuningparm_lite_med_sigma_thresh_mm = + pdev->tuning_parms.tp_lite_med_sigma_thresh_mm; + + ptun_data->vl53l1_tuningparm_lite_short_sigma_thresh_mm = + pdev->tuning_parms.tp_lite_short_sigma_thresh_mm; + + ptun_data->vl53l1_tuningparm_lite_long_min_count_rate_rtn_mcps = + pdev->tuning_parms.tp_lite_long_min_count_rate_rtn_mcps; + + ptun_data->vl53l1_tuningparm_lite_med_min_count_rate_rtn_mcps = + pdev->tuning_parms.tp_lite_med_min_count_rate_rtn_mcps; + + ptun_data->vl53l1_tuningparm_lite_short_min_count_rate_rtn_mcps = + pdev->tuning_parms.tp_lite_short_min_count_rate_rtn_mcps; + + ptun_data->vl53l1_tuningparm_lite_sigma_est_pulse_width = + pdev->tuning_parms.tp_lite_sigma_est_pulse_width_ns; + + ptun_data->vl53l1_tuningparm_lite_sigma_est_amb_width_ns = + pdev->tuning_parms.tp_lite_sigma_est_amb_width_ns; + + ptun_data->vl53l1_tuningparm_lite_sigma_ref_mm = + pdev->tuning_parms.tp_lite_sigma_ref_mm; + + ptun_data->vl53l1_tuningparm_lite_rit_mult = + pdev->xtalk_cfg.crosstalk_range_ignore_threshold_mult; + + ptun_data->vl53l1_tuningparm_lite_seed_config = + pdev->tuning_parms.tp_lite_seed_cfg; + + ptun_data->vl53l1_tuningparm_lite_quantifier = + pdev->tuning_parms.tp_lite_quantifier; + + ptun_data->vl53l1_tuningparm_lite_first_order_select = + pdev->tuning_parms.tp_lite_first_order_select; + + ptun_data->vl53l1_tuningparm_lite_xtalk_margin_kcps = + pdev->xtalk_cfg.lite_mode_crosstalk_margin_kcps; + + ptun_data->vl53l1_tuningparm_initial_phase_rtn_lite_long_range = + pdev->tuning_parms.tp_init_phase_rtn_lite_long; + + ptun_data->vl53l1_tuningparm_initial_phase_rtn_lite_med_range = + pdev->tuning_parms.tp_init_phase_rtn_lite_med; + + ptun_data->vl53l1_tuningparm_initial_phase_rtn_lite_short_range = + pdev->tuning_parms.tp_init_phase_rtn_lite_short; + + ptun_data->vl53l1_tuningparm_initial_phase_ref_lite_long_range = + pdev->tuning_parms.tp_init_phase_ref_lite_long; + + ptun_data->vl53l1_tuningparm_initial_phase_ref_lite_med_range = + pdev->tuning_parms.tp_init_phase_ref_lite_med; + + ptun_data->vl53l1_tuningparm_initial_phase_ref_lite_short_range = + pdev->tuning_parms.tp_init_phase_ref_lite_short; + + ptun_data->vl53l1_tuningparm_timed_seed_config = + pdev->tuning_parms.tp_timed_seed_cfg; + + ptun_data->vl53l1_tuningparm_dmax_cfg_signal_thresh_sigma = + pdev->dmax_cfg.signal_thresh_sigma; + + ptun_data->vl53l1_tuningparm_dmax_cfg_reflectance_array_0 = + pdev->dmax_cfg.target_reflectance_for_dmax_calc[0]; + + ptun_data->vl53l1_tuningparm_dmax_cfg_reflectance_array_1 = + pdev->dmax_cfg.target_reflectance_for_dmax_calc[1]; + + ptun_data->vl53l1_tuningparm_dmax_cfg_reflectance_array_2 = + pdev->dmax_cfg.target_reflectance_for_dmax_calc[2]; + + ptun_data->vl53l1_tuningparm_dmax_cfg_reflectance_array_3 = + pdev->dmax_cfg.target_reflectance_for_dmax_calc[3]; + + ptun_data->vl53l1_tuningparm_dmax_cfg_reflectance_array_4 = + pdev->dmax_cfg.target_reflectance_for_dmax_calc[4]; + + ptun_data->vl53l1_tuningparm_vhv_loopbound = + pdev->stat_nvm.vhv_config__timeout_macrop_loop_bound; + + ptun_data->vl53l1_tuningparm_refspadchar_device_test_mode = + pdev->refspadchar.device_test_mode; + + ptun_data->vl53l1_tuningparm_refspadchar_vcsel_period = + pdev->refspadchar.VL53L1_p_009; + + ptun_data->vl53l1_tuningparm_refspadchar_phasecal_timeout_us = + pdev->refspadchar.timeout_us; + + ptun_data->vl53l1_tuningparm_refspadchar_target_count_rate_mcps = + pdev->refspadchar.target_count_rate_mcps; + + ptun_data->vl53l1_tuningparm_refspadchar_min_countrate_limit_mcps = + pdev->refspadchar.min_count_rate_limit_mcps; + + ptun_data->vl53l1_tuningparm_refspadchar_max_countrate_limit_mcps = + pdev->refspadchar.max_count_rate_limit_mcps; + + ptun_data->vl53l1_tuningparm_xtalk_extract_num_of_samples = + pXC->num_of_samples; + + ptun_data->vl53l1_tuningparm_xtalk_extract_min_filter_thresh_mm = + pXC->algo__crosstalk_extract_min_valid_range_mm; + + ptun_data->vl53l1_tuningparm_xtalk_extract_max_filter_thresh_mm = + pXC->algo__crosstalk_extract_max_valid_range_mm; + + ptun_data->vl53l1_tuningparm_xtalk_extract_dss_rate_mcps = + pXC->dss_config__target_total_rate_mcps; + + ptun_data->vl53l1_tuningparm_xtalk_extract_phasecal_timeout_us = + pXC->phasecal_config_timeout_us; + + ptun_data->vl53l1_tuningparm_xtalk_extract_max_valid_rate_kcps = + pXC->algo__crosstalk_extract_max_valid_rate_kcps; + + ptun_data->vl53l1_tuningparm_xtalk_extract_sigma_threshold_mm = + pXC->algo__crosstalk_extract_max_sigma_mm; + + ptun_data->vl53l1_tuningparm_xtalk_extract_dss_timeout_us = + pXC->mm_config_timeout_us; + + ptun_data->vl53l1_tuningparm_xtalk_extract_bin_timeout_us = + pXC->range_config_timeout_us; + + ptun_data->vl53l1_tuningparm_offset_cal_dss_rate_mcps = + pdev->offsetcal_cfg.dss_config__target_total_rate_mcps; + + ptun_data->vl53l1_tuningparm_offset_cal_phasecal_timeout_us = + pdev->offsetcal_cfg.phasecal_config_timeout_us; + + ptun_data->vl53l1_tuningparm_offset_cal_mm_timeout_us = + pdev->offsetcal_cfg.mm_config_timeout_us; + + ptun_data->vl53l1_tuningparm_offset_cal_range_timeout_us = + pdev->offsetcal_cfg.range_config_timeout_us; + + ptun_data->vl53l1_tuningparm_offset_cal_pre_samples = + pdev->offsetcal_cfg.pre_num_of_samples; + + ptun_data->vl53l1_tuningparm_offset_cal_mm1_samples = + pdev->offsetcal_cfg.mm1_num_of_samples; + + ptun_data->vl53l1_tuningparm_offset_cal_mm2_samples = + pdev->offsetcal_cfg.mm2_num_of_samples; + + ptun_data->vl53l1_tuningparm_zone_cal_dss_rate_mcps = + pdev->zonecal_cfg.dss_config__target_total_rate_mcps; + + ptun_data->vl53l1_tuningparm_zone_cal_phasecal_timeout_us = + pdev->zonecal_cfg.phasecal_config_timeout_us; + + ptun_data->vl53l1_tuningparm_zone_cal_dss_timeout_us = + pdev->zonecal_cfg.mm_config_timeout_us; + + ptun_data->vl53l1_tuningparm_zone_cal_phasecal_num_samples = + pdev->zonecal_cfg.phasecal_num_of_samples; + + ptun_data->vl53l1_tuningparm_zone_cal_range_timeout_us = + pdev->zonecal_cfg.range_config_timeout_us; + + ptun_data->vl53l1_tuningparm_zone_cal_zone_num_samples = + pdev->zonecal_cfg.zone_num_of_samples; + + ptun_data->vl53l1_tuningparm_spadmap_vcsel_period = + pdev->ssc_cfg.VL53L1_p_009; + + ptun_data->vl53l1_tuningparm_spadmap_vcsel_start = + pdev->ssc_cfg.vcsel_start; + + ptun_data->vl53l1_tuningparm_spadmap_rate_limit_mcps = + pdev->ssc_cfg.rate_limit_mcps; + + ptun_data->vl53l1_tuningparm_lite_dss_config_target_total_rate_mcps = + pdev->tuning_parms.tp_dss_target_lite_mcps; + + ptun_data->vl53l1_tuningparm_ranging_dss_config_target_total_rate_mcps = + pdev->tuning_parms.tp_dss_target_histo_mcps; + + ptun_data->vl53l1_tuningparm_mz_dss_config_target_total_rate_mcps = + pdev->tuning_parms.tp_dss_target_histo_mz_mcps; + + ptun_data->vl53l1_tuningparm_timed_dss_config_target_total_rate_mcps = + pdev->tuning_parms.tp_dss_target_timed_mcps; + + ptun_data->vl53l1_tuningparm_lite_phasecal_config_timeout_us = + pdev->tuning_parms.tp_phasecal_timeout_lite_us; + + ptun_data->vl53l1_tuningparm_ranging_long_phasecal_config_timeout_us = + pdev->tuning_parms.tp_phasecal_timeout_hist_long_us; + + ptun_data->vl53l1_tuningparm_ranging_med_phasecal_config_timeout_us = + pdev->tuning_parms.tp_phasecal_timeout_hist_med_us; + + ptun_data->vl53l1_tuningparm_ranging_short_phasecal_config_timeout_us = + pdev->tuning_parms.tp_phasecal_timeout_hist_short_us; + + ptun_data->vl53l1_tuningparm_mz_long_phasecal_config_timeout_us = + pdev->tuning_parms.tp_phasecal_timeout_mz_long_us; + + ptun_data->vl53l1_tuningparm_mz_med_phasecal_config_timeout_us = + pdev->tuning_parms.tp_phasecal_timeout_mz_med_us; + + ptun_data->vl53l1_tuningparm_mz_short_phasecal_config_timeout_us = + pdev->tuning_parms.tp_phasecal_timeout_mz_short_us; + + ptun_data->vl53l1_tuningparm_timed_phasecal_config_timeout_us = + pdev->tuning_parms.tp_phasecal_timeout_timed_us; + + ptun_data->vl53l1_tuningparm_lite_mm_config_timeout_us = + pdev->tuning_parms.tp_mm_timeout_lite_us; + + ptun_data->vl53l1_tuningparm_ranging_mm_config_timeout_us = + pdev->tuning_parms.tp_mm_timeout_histo_us; + + ptun_data->vl53l1_tuningparm_mz_mm_config_timeout_us = + pdev->tuning_parms.tp_mm_timeout_mz_us; + + ptun_data->vl53l1_tuningparm_timed_mm_config_timeout_us = + pdev->tuning_parms.tp_mm_timeout_timed_us; + + ptun_data->vl53l1_tuningparm_lite_range_config_timeout_us = + pdev->tuning_parms.tp_range_timeout_lite_us; + + ptun_data->vl53l1_tuningparm_ranging_range_config_timeout_us = + pdev->tuning_parms.tp_range_timeout_histo_us; + + ptun_data->vl53l1_tuningparm_mz_range_config_timeout_us = + pdev->tuning_parms.tp_range_timeout_mz_us; + + ptun_data->vl53l1_tuningparm_timed_range_config_timeout_us = + pdev->tuning_parms.tp_range_timeout_timed_us; + + ptun_data->vl53l1_tuningparm_dynxtalk_smudge_margin = + pdev->smudge_correct_config.smudge_margin; + + ptun_data->vl53l1_tuningparm_dynxtalk_noise_margin = + pdev->smudge_correct_config.noise_margin; + + ptun_data->vl53l1_tuningparm_dynxtalk_xtalk_offset_limit = + pdev->smudge_correct_config.user_xtalk_offset_limit; + + ptun_data->vl53l1_tuningparm_dynxtalk_xtalk_offset_limit_hi = + pdev->smudge_correct_config.user_xtalk_offset_limit_hi; + + ptun_data->vl53l1_tuningparm_dynxtalk_sample_limit = + pdev->smudge_correct_config.sample_limit; + + ptun_data->vl53l1_tuningparm_dynxtalk_single_xtalk_delta = + pdev->smudge_correct_config.single_xtalk_delta; + + ptun_data->vl53l1_tuningparm_dynxtalk_averaged_xtalk_delta = + pdev->smudge_correct_config.averaged_xtalk_delta; + + ptun_data->vl53l1_tuningparm_dynxtalk_clip_limit = + pdev->smudge_correct_config.smudge_corr_clip_limit; + + ptun_data->vl53l1_tuningparm_dynxtalk_scaler_calc_method = + pdev->smudge_correct_config.scaler_calc_method; + + ptun_data->vl53l1_tuningparm_dynxtalk_xgradient_scaler = + pdev->smudge_correct_config.x_gradient_scaler; + + ptun_data->vl53l1_tuningparm_dynxtalk_ygradient_scaler = + pdev->smudge_correct_config.y_gradient_scaler; + + ptun_data->vl53l1_tuningparm_dynxtalk_user_scaler_set = + pdev->smudge_correct_config.user_scaler_set; + + ptun_data->vl53l1_tuningparm_dynxtalk_smudge_cor_single_apply = + pdev->smudge_correct_config.smudge_corr_single_apply; + + ptun_data->vl53l1_tuningparm_dynxtalk_xtalk_amb_threshold = + pdev->smudge_correct_config.smudge_corr_ambient_threshold; + + ptun_data->vl53l1_tuningparm_dynxtalk_nodetect_amb_threshold_kcps = + pdev->smudge_correct_config.nodetect_ambient_threshold; + + ptun_data->vl53l1_tuningparm_dynxtalk_nodetect_sample_limit = + pdev->smudge_correct_config.nodetect_sample_limit; + + ptun_data->vl53l1_tuningparm_dynxtalk_nodetect_xtalk_offset_kcps = + pdev->smudge_correct_config.nodetect_xtalk_offset; + + ptun_data->vl53l1_tuningparm_dynxtalk_nodetect_min_range_mm = + pdev->smudge_correct_config.nodetect_min_range_mm; + + ptun_data->vl53l1_tuningparm_lowpowerauto_vhv_loop_bound = + pdev->low_power_auto_data.vhv_loop_bound; + + ptun_data->vl53l1_tuningparm_lowpowerauto_mm_config_timeout_us = + pdev->tuning_parms.tp_mm_timeout_lpa_us; + + ptun_data->vl53l1_tuningparm_lowpowerauto_range_config_timeout_us = + pdev->tuning_parms.tp_range_timeout_lpa_us; + + ptun_data->vl53l1_tuningparm_very_short_dss_rate_mcps = + pdev->tuning_parms.tp_dss_target_very_short_mcps; + + ptun_data->vl53l1_tuningparm_phasecal_patch_power = + pdev->tuning_parms.tp_phasecal_patch_power; + + LOG_FUNCTION_END(status); + + return status; +} + + + + + + + +VL53L1_Error VL53L1_get_tuning_parm( + VL53L1_DEV Dev, + VL53L1_TuningParms tuning_parm_key, + int32_t *ptuning_parm_value) +{ + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_hist_post_process_config_t *pHP = &(pdev->histpostprocess); + VL53L1_xtalkextract_config_t *pXC = &(pdev->xtalk_extract_cfg); + + LOG_FUNCTION_START(""); + + switch (tuning_parm_key) { + + case VL53L1_TUNINGPARM_VERSION: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_tuning_parm_version; + break; + case VL53L1_TUNINGPARM_KEY_TABLE_VERSION: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_tuning_parm_key_table_version; + break; + case VL53L1_TUNINGPARM_LLD_VERSION: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_tuning_parm_lld_version; + break; + case VL53L1_TUNINGPARM_HIST_ALGO_SELECT: + *ptuning_parm_value = + (int32_t)pHP->hist_algo_select; + break; + case VL53L1_TUNINGPARM_HIST_TARGET_ORDER: + *ptuning_parm_value = + (int32_t)pHP->hist_target_order; + break; + case VL53L1_TUNINGPARM_HIST_FILTER_WOI_0: + *ptuning_parm_value = + (int32_t)pHP->filter_woi0; + break; + case VL53L1_TUNINGPARM_HIST_FILTER_WOI_1: + *ptuning_parm_value = + (int32_t)pHP->filter_woi1; + break; + case VL53L1_TUNINGPARM_HIST_AMB_EST_METHOD: + *ptuning_parm_value = + (int32_t)pHP->hist_amb_est_method; + break; + case VL53L1_TUNINGPARM_HIST_AMB_THRESH_SIGMA_0: + *ptuning_parm_value = + (int32_t)pHP->ambient_thresh_sigma0; + break; + case VL53L1_TUNINGPARM_HIST_AMB_THRESH_SIGMA_1: + *ptuning_parm_value = + (int32_t)pHP->ambient_thresh_sigma1; + break; + case VL53L1_TUNINGPARM_HIST_MIN_AMB_THRESH_EVENTS: + *ptuning_parm_value = + (int32_t)pHP->min_ambient_thresh_events; + break; + case VL53L1_TUNINGPARM_HIST_AMB_EVENTS_SCALER: + *ptuning_parm_value = + (int32_t)pHP->ambient_thresh_events_scaler; + break; + case VL53L1_TUNINGPARM_HIST_NOISE_THRESHOLD: + *ptuning_parm_value = + (int32_t)pHP->noise_threshold; + break; + case VL53L1_TUNINGPARM_HIST_SIGNAL_TOTAL_EVENTS_LIMIT: + *ptuning_parm_value = + (int32_t)pHP->signal_total_events_limit; + break; + case VL53L1_TUNINGPARM_HIST_SIGMA_EST_REF_MM: + *ptuning_parm_value = + (int32_t)pHP->sigma_estimator__sigma_ref_mm; + break; + case VL53L1_TUNINGPARM_HIST_SIGMA_THRESH_MM: + *ptuning_parm_value = + (int32_t)pHP->sigma_thresh; + break; + case VL53L1_TUNINGPARM_HIST_GAIN_FACTOR: + *ptuning_parm_value = + (int32_t)pdev->gain_cal.histogram_ranging_gain_factor; + break; + case VL53L1_TUNINGPARM_CONSISTENCY_HIST_PHASE_TOLERANCE: + *ptuning_parm_value = + (int32_t)pHP->algo__consistency_check__phase_tolerance; + break; + case VL53L1_TUNINGPARM_CONSISTENCY_HIST_MIN_MAX_TOLERANCE_MM: + *ptuning_parm_value = + (int32_t)pHP->algo__consistency_check__min_max_tolerance; + break; + case VL53L1_TUNINGPARM_CONSISTENCY_HIST_EVENT_SIGMA: + *ptuning_parm_value = + (int32_t)pHP->algo__consistency_check__event_sigma; + break; + case VL53L1_TUNINGPARM_CONSISTENCY_HIST_EVENT_SIGMA_MIN_SPAD_LIMIT: + *ptuning_parm_value = + (int32_t)pHP->algo__consistency_check__event_min_spad_count; + break; + case VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_HISTO_LONG_RANGE: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_init_phase_rtn_hist_long; + break; + case VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_HISTO_MED_RANGE: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_init_phase_rtn_hist_med; + break; + case VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_HISTO_SHORT_RANGE: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_init_phase_rtn_hist_short; + break; + case VL53L1_TUNINGPARM_INITIAL_PHASE_REF_HISTO_LONG_RANGE: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_init_phase_ref_hist_long; + break; + case VL53L1_TUNINGPARM_INITIAL_PHASE_REF_HISTO_MED_RANGE: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_init_phase_ref_hist_med; + break; + case VL53L1_TUNINGPARM_INITIAL_PHASE_REF_HISTO_SHORT_RANGE: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_init_phase_ref_hist_short; + break; + case VL53L1_TUNINGPARM_XTALK_DETECT_MIN_VALID_RANGE_MM: + *ptuning_parm_value = (int32_t)( + pdev->xtalk_cfg.algo__crosstalk_detect_min_valid_range_mm); + break; + case VL53L1_TUNINGPARM_XTALK_DETECT_MAX_VALID_RANGE_MM: + *ptuning_parm_value = (int32_t)( + pdev->xtalk_cfg.algo__crosstalk_detect_max_valid_range_mm); + break; + case VL53L1_TUNINGPARM_XTALK_DETECT_MAX_SIGMA_MM: + *ptuning_parm_value = + (int32_t)pdev->xtalk_cfg.algo__crosstalk_detect_max_sigma_mm; + break; + case VL53L1_TUNINGPARM_XTALK_DETECT_MIN_MAX_TOLERANCE: + *ptuning_parm_value = + (int32_t)pHP->algo__crosstalk_detect_min_max_tolerance; + break; + case VL53L1_TUNINGPARM_XTALK_DETECT_MAX_VALID_RATE_KCPS: + *ptuning_parm_value = (int32_t)( + pdev->xtalk_cfg.algo__crosstalk_detect_max_valid_rate_kcps); + break; + case VL53L1_TUNINGPARM_XTALK_DETECT_EVENT_SIGMA: + *ptuning_parm_value = + (int32_t)pHP->algo__crosstalk_detect_event_sigma; + break; + case VL53L1_TUNINGPARM_HIST_XTALK_MARGIN_KCPS: + *ptuning_parm_value = + (int32_t)pdev->xtalk_cfg.histogram_mode_crosstalk_margin_kcps; + break; + case VL53L1_TUNINGPARM_CONSISTENCY_LITE_PHASE_TOLERANCE: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_consistency_lite_phase_tolerance; + break; + case VL53L1_TUNINGPARM_PHASECAL_TARGET: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_phasecal_target; + break; + case VL53L1_TUNINGPARM_LITE_CAL_REPEAT_RATE: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_cal_repeat_rate; + break; + case VL53L1_TUNINGPARM_LITE_RANGING_GAIN_FACTOR: + *ptuning_parm_value = + (int32_t)pdev->gain_cal.standard_ranging_gain_factor; + break; + case VL53L1_TUNINGPARM_LITE_MIN_CLIP_MM: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_lite_min_clip; + break; + case VL53L1_TUNINGPARM_LITE_LONG_SIGMA_THRESH_MM: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_lite_long_sigma_thresh_mm; + break; + case VL53L1_TUNINGPARM_LITE_MED_SIGMA_THRESH_MM: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_lite_med_sigma_thresh_mm; + break; + case VL53L1_TUNINGPARM_LITE_SHORT_SIGMA_THRESH_MM: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_lite_short_sigma_thresh_mm; + break; + case VL53L1_TUNINGPARM_LITE_LONG_MIN_COUNT_RATE_RTN_MCPS: + *ptuning_parm_value = (int32_t)( + pdev->tuning_parms.tp_lite_long_min_count_rate_rtn_mcps); + break; + case VL53L1_TUNINGPARM_LITE_MED_MIN_COUNT_RATE_RTN_MCPS: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_lite_med_min_count_rate_rtn_mcps; + break; + case VL53L1_TUNINGPARM_LITE_SHORT_MIN_COUNT_RATE_RTN_MCPS: + *ptuning_parm_value = (int32_t)( + pdev->tuning_parms.tp_lite_short_min_count_rate_rtn_mcps); + break; + case VL53L1_TUNINGPARM_LITE_SIGMA_EST_PULSE_WIDTH: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_lite_sigma_est_pulse_width_ns; + break; + case VL53L1_TUNINGPARM_LITE_SIGMA_EST_AMB_WIDTH_NS: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_lite_sigma_est_amb_width_ns; + break; + case VL53L1_TUNINGPARM_LITE_SIGMA_REF_MM: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_lite_sigma_ref_mm; + break; + case VL53L1_TUNINGPARM_LITE_RIT_MULT: + *ptuning_parm_value = + (int32_t)pdev->xtalk_cfg.crosstalk_range_ignore_threshold_mult; + break; + case VL53L1_TUNINGPARM_LITE_SEED_CONFIG: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_lite_seed_cfg; + break; + case VL53L1_TUNINGPARM_LITE_QUANTIFIER: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_lite_quantifier; + break; + case VL53L1_TUNINGPARM_LITE_FIRST_ORDER_SELECT: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_lite_first_order_select; + break; + case VL53L1_TUNINGPARM_LITE_XTALK_MARGIN_KCPS: + *ptuning_parm_value = + (int32_t)pdev->xtalk_cfg.lite_mode_crosstalk_margin_kcps; + break; + case VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_LITE_LONG_RANGE: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_init_phase_rtn_lite_long; + break; + case VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_LITE_MED_RANGE: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_init_phase_rtn_lite_med; + break; + case VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_LITE_SHORT_RANGE: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_init_phase_rtn_lite_short; + break; + case VL53L1_TUNINGPARM_INITIAL_PHASE_REF_LITE_LONG_RANGE: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_init_phase_ref_lite_long; + break; + case VL53L1_TUNINGPARM_INITIAL_PHASE_REF_LITE_MED_RANGE: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_init_phase_ref_lite_med; + break; + case VL53L1_TUNINGPARM_INITIAL_PHASE_REF_LITE_SHORT_RANGE: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_init_phase_ref_lite_short; + break; + case VL53L1_TUNINGPARM_TIMED_SEED_CONFIG: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_timed_seed_cfg; + break; + case VL53L1_TUNINGPARM_DMAX_CFG_SIGNAL_THRESH_SIGMA: + *ptuning_parm_value = + (int32_t)pdev->dmax_cfg.signal_thresh_sigma; + break; + case VL53L1_TUNINGPARM_DMAX_CFG_REFLECTANCE_ARRAY_0: + *ptuning_parm_value = + (int32_t)pdev->dmax_cfg.target_reflectance_for_dmax_calc[0]; + break; + case VL53L1_TUNINGPARM_DMAX_CFG_REFLECTANCE_ARRAY_1: + *ptuning_parm_value = + (int32_t)pdev->dmax_cfg.target_reflectance_for_dmax_calc[1]; + break; + case VL53L1_TUNINGPARM_DMAX_CFG_REFLECTANCE_ARRAY_2: + *ptuning_parm_value = + (int32_t)pdev->dmax_cfg.target_reflectance_for_dmax_calc[2]; + break; + case VL53L1_TUNINGPARM_DMAX_CFG_REFLECTANCE_ARRAY_3: + *ptuning_parm_value = + (int32_t)pdev->dmax_cfg.target_reflectance_for_dmax_calc[3]; + break; + case VL53L1_TUNINGPARM_DMAX_CFG_REFLECTANCE_ARRAY_4: + *ptuning_parm_value = + (int32_t)pdev->dmax_cfg.target_reflectance_for_dmax_calc[4]; + break; + case VL53L1_TUNINGPARM_VHV_LOOPBOUND: + *ptuning_parm_value = + (int32_t)pdev->stat_nvm.vhv_config__timeout_macrop_loop_bound; + break; + case VL53L1_TUNINGPARM_REFSPADCHAR_DEVICE_TEST_MODE: + *ptuning_parm_value = + (int32_t)pdev->refspadchar.device_test_mode; + break; + case VL53L1_TUNINGPARM_REFSPADCHAR_VCSEL_PERIOD: + *ptuning_parm_value = + (int32_t)pdev->refspadchar.VL53L1_p_009; + break; + case VL53L1_TUNINGPARM_REFSPADCHAR_PHASECAL_TIMEOUT_US: + *ptuning_parm_value = + (int32_t)pdev->refspadchar.timeout_us; + break; + case VL53L1_TUNINGPARM_REFSPADCHAR_TARGET_COUNT_RATE_MCPS: + *ptuning_parm_value = + (int32_t)pdev->refspadchar.target_count_rate_mcps; + break; + case VL53L1_TUNINGPARM_REFSPADCHAR_MIN_COUNTRATE_LIMIT_MCPS: + *ptuning_parm_value = + (int32_t)pdev->refspadchar.min_count_rate_limit_mcps; + break; + case VL53L1_TUNINGPARM_REFSPADCHAR_MAX_COUNTRATE_LIMIT_MCPS: + *ptuning_parm_value = + (int32_t)pdev->refspadchar.max_count_rate_limit_mcps; + break; + case VL53L1_TUNINGPARM_XTALK_EXTRACT_NUM_OF_SAMPLES: + *ptuning_parm_value = + (int32_t)pXC->num_of_samples; + break; + case VL53L1_TUNINGPARM_XTALK_EXTRACT_MIN_FILTER_THRESH_MM: + *ptuning_parm_value = + (int32_t)pXC->algo__crosstalk_extract_min_valid_range_mm; + break; + case VL53L1_TUNINGPARM_XTALK_EXTRACT_MAX_FILTER_THRESH_MM: + *ptuning_parm_value = + (int32_t)pXC->algo__crosstalk_extract_max_valid_range_mm; + break; + case VL53L1_TUNINGPARM_XTALK_EXTRACT_DSS_RATE_MCPS: + *ptuning_parm_value = + (int32_t)pXC->dss_config__target_total_rate_mcps; + break; + case VL53L1_TUNINGPARM_XTALK_EXTRACT_PHASECAL_TIMEOUT_US: + *ptuning_parm_value = + (int32_t)pXC->phasecal_config_timeout_us; + break; + case VL53L1_TUNINGPARM_XTALK_EXTRACT_MAX_VALID_RATE_KCPS: + *ptuning_parm_value = + (int32_t)pXC->algo__crosstalk_extract_max_valid_rate_kcps; + break; + case VL53L1_TUNINGPARM_XTALK_EXTRACT_SIGMA_THRESHOLD_MM: + *ptuning_parm_value = + (int32_t)pXC->algo__crosstalk_extract_max_sigma_mm; + break; + case VL53L1_TUNINGPARM_XTALK_EXTRACT_DSS_TIMEOUT_US: + *ptuning_parm_value = + (int32_t)pXC->mm_config_timeout_us; + break; + case VL53L1_TUNINGPARM_XTALK_EXTRACT_BIN_TIMEOUT_US: + *ptuning_parm_value = + (int32_t)pXC->range_config_timeout_us; + break; + case VL53L1_TUNINGPARM_OFFSET_CAL_DSS_RATE_MCPS: + *ptuning_parm_value = + (int32_t)pdev->offsetcal_cfg.dss_config__target_total_rate_mcps; + break; + case VL53L1_TUNINGPARM_OFFSET_CAL_PHASECAL_TIMEOUT_US: + *ptuning_parm_value = + (int32_t)pdev->offsetcal_cfg.phasecal_config_timeout_us; + break; + case VL53L1_TUNINGPARM_OFFSET_CAL_MM_TIMEOUT_US: + *ptuning_parm_value = + (int32_t)pdev->offsetcal_cfg.mm_config_timeout_us; + break; + case VL53L1_TUNINGPARM_OFFSET_CAL_RANGE_TIMEOUT_US: + *ptuning_parm_value = + (int32_t)pdev->offsetcal_cfg.range_config_timeout_us; + break; + case VL53L1_TUNINGPARM_OFFSET_CAL_PRE_SAMPLES: + *ptuning_parm_value = + (int32_t)pdev->offsetcal_cfg.pre_num_of_samples; + break; + case VL53L1_TUNINGPARM_OFFSET_CAL_MM1_SAMPLES: + *ptuning_parm_value = + (int32_t)pdev->offsetcal_cfg.mm1_num_of_samples; + break; + case VL53L1_TUNINGPARM_OFFSET_CAL_MM2_SAMPLES: + *ptuning_parm_value = + (int32_t)pdev->offsetcal_cfg.mm2_num_of_samples; + break; + case VL53L1_TUNINGPARM_ZONE_CAL_DSS_RATE_MCPS: + *ptuning_parm_value = + (int32_t)pdev->zonecal_cfg.dss_config__target_total_rate_mcps; + break; + case VL53L1_TUNINGPARM_ZONE_CAL_PHASECAL_TIMEOUT_US: + *ptuning_parm_value = + (int32_t)pdev->zonecal_cfg.phasecal_config_timeout_us; + break; + case VL53L1_TUNINGPARM_ZONE_CAL_DSS_TIMEOUT_US: + *ptuning_parm_value = + (int32_t)pdev->zonecal_cfg.mm_config_timeout_us; + break; + case VL53L1_TUNINGPARM_ZONE_CAL_PHASECAL_NUM_SAMPLES: + *ptuning_parm_value = + (int32_t)pdev->zonecal_cfg.phasecal_num_of_samples; + break; + case VL53L1_TUNINGPARM_ZONE_CAL_RANGE_TIMEOUT_US: + *ptuning_parm_value = + (int32_t)pdev->zonecal_cfg.range_config_timeout_us; + break; + case VL53L1_TUNINGPARM_ZONE_CAL_ZONE_NUM_SAMPLES: + *ptuning_parm_value = + (int32_t)pdev->zonecal_cfg.zone_num_of_samples; + break; + case VL53L1_TUNINGPARM_SPADMAP_VCSEL_PERIOD: + *ptuning_parm_value = + (int32_t)pdev->ssc_cfg.VL53L1_p_009; + break; + case VL53L1_TUNINGPARM_SPADMAP_VCSEL_START: + *ptuning_parm_value = + (int32_t)pdev->ssc_cfg.vcsel_start; + break; + case VL53L1_TUNINGPARM_SPADMAP_RATE_LIMIT_MCPS: + *ptuning_parm_value = + (int32_t)pdev->ssc_cfg.rate_limit_mcps; + break; + case VL53L1_TUNINGPARM_LITE_DSS_CONFIG_TARGET_TOTAL_RATE_MCPS: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_dss_target_lite_mcps; + break; + case VL53L1_TUNINGPARM_RANGING_DSS_CONFIG_TARGET_TOTAL_RATE_MCPS: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_dss_target_histo_mcps; + break; + case VL53L1_TUNINGPARM_MZ_DSS_CONFIG_TARGET_TOTAL_RATE_MCPS: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_dss_target_histo_mz_mcps; + break; + case VL53L1_TUNINGPARM_TIMED_DSS_CONFIG_TARGET_TOTAL_RATE_MCPS: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_dss_target_timed_mcps; + break; + case VL53L1_TUNINGPARM_LITE_PHASECAL_CONFIG_TIMEOUT_US: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_phasecal_timeout_lite_us; + break; + case VL53L1_TUNINGPARM_RANGING_LONG_PHASECAL_CONFIG_TIMEOUT_US: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_phasecal_timeout_hist_long_us; + break; + case VL53L1_TUNINGPARM_RANGING_MED_PHASECAL_CONFIG_TIMEOUT_US: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_phasecal_timeout_hist_med_us; + break; + case VL53L1_TUNINGPARM_RANGING_SHORT_PHASECAL_CONFIG_TIMEOUT_US: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_phasecal_timeout_hist_short_us; + break; + case VL53L1_TUNINGPARM_MZ_LONG_PHASECAL_CONFIG_TIMEOUT_US: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_phasecal_timeout_mz_long_us; + break; + case VL53L1_TUNINGPARM_MZ_MED_PHASECAL_CONFIG_TIMEOUT_US: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_phasecal_timeout_mz_med_us; + break; + case VL53L1_TUNINGPARM_MZ_SHORT_PHASECAL_CONFIG_TIMEOUT_US: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_phasecal_timeout_mz_short_us; + break; + case VL53L1_TUNINGPARM_TIMED_PHASECAL_CONFIG_TIMEOUT_US: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_phasecal_timeout_timed_us; + break; + case VL53L1_TUNINGPARM_LITE_MM_CONFIG_TIMEOUT_US: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_mm_timeout_lite_us; + break; + case VL53L1_TUNINGPARM_RANGING_MM_CONFIG_TIMEOUT_US: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_mm_timeout_histo_us; + break; + case VL53L1_TUNINGPARM_MZ_MM_CONFIG_TIMEOUT_US: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_mm_timeout_mz_us; + break; + case VL53L1_TUNINGPARM_TIMED_MM_CONFIG_TIMEOUT_US: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_mm_timeout_timed_us; + break; + case VL53L1_TUNINGPARM_LITE_RANGE_CONFIG_TIMEOUT_US: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_range_timeout_lite_us; + break; + case VL53L1_TUNINGPARM_RANGING_RANGE_CONFIG_TIMEOUT_US: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_range_timeout_histo_us; + break; + case VL53L1_TUNINGPARM_MZ_RANGE_CONFIG_TIMEOUT_US: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_range_timeout_mz_us; + break; + case VL53L1_TUNINGPARM_TIMED_RANGE_CONFIG_TIMEOUT_US: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_range_timeout_timed_us; + break; + case VL53L1_TUNINGPARM_DYNXTALK_SMUDGE_MARGIN: + *ptuning_parm_value = + (int32_t)pdev->smudge_correct_config.smudge_margin; + break; + case VL53L1_TUNINGPARM_DYNXTALK_NOISE_MARGIN: + *ptuning_parm_value = + (int32_t)pdev->smudge_correct_config.noise_margin; + break; + case VL53L1_TUNINGPARM_DYNXTALK_XTALK_OFFSET_LIMIT: + *ptuning_parm_value = + (int32_t)pdev->smudge_correct_config.user_xtalk_offset_limit; + break; + case VL53L1_TUNINGPARM_DYNXTALK_XTALK_OFFSET_LIMIT_HI: + *ptuning_parm_value = + (int32_t)pdev->smudge_correct_config.user_xtalk_offset_limit_hi; + break; + case VL53L1_TUNINGPARM_DYNXTALK_SAMPLE_LIMIT: + *ptuning_parm_value = + (int32_t)pdev->smudge_correct_config.sample_limit; + break; + case VL53L1_TUNINGPARM_DYNXTALK_SINGLE_XTALK_DELTA: + *ptuning_parm_value = + (int32_t)pdev->smudge_correct_config.single_xtalk_delta; + break; + case VL53L1_TUNINGPARM_DYNXTALK_AVERAGED_XTALK_DELTA: + *ptuning_parm_value = + (int32_t)pdev->smudge_correct_config.averaged_xtalk_delta; + break; + case VL53L1_TUNINGPARM_DYNXTALK_CLIP_LIMIT: + *ptuning_parm_value = + (int32_t)pdev->smudge_correct_config.smudge_corr_clip_limit; + break; + case VL53L1_TUNINGPARM_DYNXTALK_SCALER_CALC_METHOD: + *ptuning_parm_value = + (int32_t)pdev->smudge_correct_config.scaler_calc_method; + break; + case VL53L1_TUNINGPARM_DYNXTALK_XGRADIENT_SCALER: + *ptuning_parm_value = + (int32_t)pdev->smudge_correct_config.x_gradient_scaler; + break; + case VL53L1_TUNINGPARM_DYNXTALK_YGRADIENT_SCALER: + *ptuning_parm_value = + (int32_t)pdev->smudge_correct_config.y_gradient_scaler; + break; + case VL53L1_TUNINGPARM_DYNXTALK_USER_SCALER_SET: + *ptuning_parm_value = + (int32_t)pdev->smudge_correct_config.user_scaler_set; + break; + case VL53L1_TUNINGPARM_DYNXTALK_SMUDGE_COR_SINGLE_APPLY: + *ptuning_parm_value = + (int32_t)pdev->smudge_correct_config.smudge_corr_single_apply; + break; + case VL53L1_TUNINGPARM_DYNXTALK_XTALK_AMB_THRESHOLD: + *ptuning_parm_value = (int32_t)( + pdev->smudge_correct_config.smudge_corr_ambient_threshold); + break; + case VL53L1_TUNINGPARM_DYNXTALK_NODETECT_AMB_THRESHOLD_KCPS: + *ptuning_parm_value = + (int32_t)pdev->smudge_correct_config.nodetect_ambient_threshold; + break; + case VL53L1_TUNINGPARM_DYNXTALK_NODETECT_SAMPLE_LIMIT: + *ptuning_parm_value = + (int32_t)pdev->smudge_correct_config.nodetect_sample_limit; + break; + case VL53L1_TUNINGPARM_DYNXTALK_NODETECT_XTALK_OFFSET_KCPS: + *ptuning_parm_value = + (int32_t)pdev->smudge_correct_config.nodetect_xtalk_offset; + break; + case VL53L1_TUNINGPARM_DYNXTALK_NODETECT_MIN_RANGE_MM: + *ptuning_parm_value = + (int32_t)pdev->smudge_correct_config.nodetect_min_range_mm; + break; + case VL53L1_TUNINGPARM_LOWPOWERAUTO_VHV_LOOP_BOUND: + *ptuning_parm_value = + (int32_t)pdev->low_power_auto_data.vhv_loop_bound; + break; + case VL53L1_TUNINGPARM_LOWPOWERAUTO_MM_CONFIG_TIMEOUT_US: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_mm_timeout_lpa_us; + break; + case VL53L1_TUNINGPARM_LOWPOWERAUTO_RANGE_CONFIG_TIMEOUT_US: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_range_timeout_lpa_us; + break; + case VL53L1_TUNINGPARM_VERY_SHORT_DSS_RATE_MCPS: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_dss_target_very_short_mcps; + break; + case VL53L1_TUNINGPARM_PHASECAL_PATCH_POWER: + *ptuning_parm_value = + (int32_t) pdev->tuning_parms.tp_phasecal_patch_power; + break; + case VL53L1_TUNINGPARM_HIST_MERGE: + *ptuning_parm_value = + (int32_t) pdev->tuning_parms.tp_hist_merge; + break; + case VL53L1_TUNINGPARM_RESET_MERGE_THRESHOLD: + *ptuning_parm_value = + (int32_t) pdev->tuning_parms.tp_reset_merge_threshold; + break; + case VL53L1_TUNINGPARM_HIST_MERGE_MAX_SIZE: + *ptuning_parm_value = + (int32_t) pdev->tuning_parms.tp_hist_merge_max_size; + break; + + + default: + *ptuning_parm_value = 0x7FFFFFFF; + status = VL53L1_ERROR_INVALID_PARAMS; + break; + + } + + LOG_FUNCTION_END(status); + + return status; +} + +VL53L1_Error VL53L1_set_tuning_parm( + VL53L1_DEV Dev, + VL53L1_TuningParms tuning_parm_key, + int32_t tuning_parm_value) +{ + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_hist_post_process_config_t *pHP = &(pdev->histpostprocess); + VL53L1_xtalkextract_config_t *pXC = &(pdev->xtalk_extract_cfg); + + LOG_FUNCTION_START(""); + + switch (tuning_parm_key) { + + case VL53L1_TUNINGPARM_VERSION: + pdev->tuning_parms.tp_tuning_parm_version = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_KEY_TABLE_VERSION: + pdev->tuning_parms.tp_tuning_parm_key_table_version = + (uint16_t)tuning_parm_value; + if ((uint16_t)tuning_parm_value + != VL53L1_TUNINGPARM_KEY_TABLE_VERSION_DEFAULT) + status = VL53L1_ERROR_TUNING_PARM_KEY_MISMATCH; + + break; + case VL53L1_TUNINGPARM_LLD_VERSION: + pdev->tuning_parms.tp_tuning_parm_lld_version = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_HIST_ALGO_SELECT: + pHP->hist_algo_select = + (VL53L1_HistAlgoSelect)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_HIST_TARGET_ORDER: + pHP->hist_target_order = + (VL53L1_HistTargetOrder)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_HIST_FILTER_WOI_0: + pHP->filter_woi0 = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_HIST_FILTER_WOI_1: + pHP->filter_woi1 = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_HIST_AMB_EST_METHOD: + pHP->hist_amb_est_method = + (VL53L1_HistAmbEstMethod)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_HIST_AMB_THRESH_SIGMA_0: + pHP->ambient_thresh_sigma0 = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_HIST_AMB_THRESH_SIGMA_1: + pHP->ambient_thresh_sigma1 = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_HIST_MIN_AMB_THRESH_EVENTS: + pHP->min_ambient_thresh_events = + (int32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_HIST_AMB_EVENTS_SCALER: + pHP->ambient_thresh_events_scaler = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_HIST_NOISE_THRESHOLD: + pHP->noise_threshold = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_HIST_SIGNAL_TOTAL_EVENTS_LIMIT: + pHP->signal_total_events_limit = + (int32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_HIST_SIGMA_EST_REF_MM: + pHP->sigma_estimator__sigma_ref_mm = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_HIST_SIGMA_THRESH_MM: + pHP->sigma_thresh = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_HIST_GAIN_FACTOR: + pdev->gain_cal.histogram_ranging_gain_factor = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_CONSISTENCY_HIST_PHASE_TOLERANCE: + pHP->algo__consistency_check__phase_tolerance = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_CONSISTENCY_HIST_MIN_MAX_TOLERANCE_MM: + pHP->algo__consistency_check__min_max_tolerance = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_CONSISTENCY_HIST_EVENT_SIGMA: + pHP->algo__consistency_check__event_sigma = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_CONSISTENCY_HIST_EVENT_SIGMA_MIN_SPAD_LIMIT: + pHP->algo__consistency_check__event_min_spad_count = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_HISTO_LONG_RANGE: + pdev->tuning_parms.tp_init_phase_rtn_hist_long = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_HISTO_MED_RANGE: + pdev->tuning_parms.tp_init_phase_rtn_hist_med = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_HISTO_SHORT_RANGE: + pdev->tuning_parms.tp_init_phase_rtn_hist_short = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_INITIAL_PHASE_REF_HISTO_LONG_RANGE: + pdev->tuning_parms.tp_init_phase_ref_hist_long = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_INITIAL_PHASE_REF_HISTO_MED_RANGE: + pdev->tuning_parms.tp_init_phase_ref_hist_med = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_INITIAL_PHASE_REF_HISTO_SHORT_RANGE: + pdev->tuning_parms.tp_init_phase_ref_hist_short = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_XTALK_DETECT_MIN_VALID_RANGE_MM: + pdev->xtalk_cfg.algo__crosstalk_detect_min_valid_range_mm = + (int16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_XTALK_DETECT_MAX_VALID_RANGE_MM: + pdev->xtalk_cfg.algo__crosstalk_detect_max_valid_range_mm = + (int16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_XTALK_DETECT_MAX_SIGMA_MM: + pdev->xtalk_cfg.algo__crosstalk_detect_max_sigma_mm = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_XTALK_DETECT_MIN_MAX_TOLERANCE: + pHP->algo__crosstalk_detect_min_max_tolerance = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_XTALK_DETECT_MAX_VALID_RATE_KCPS: + pdev->xtalk_cfg.algo__crosstalk_detect_max_valid_rate_kcps = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_XTALK_DETECT_EVENT_SIGMA: + pHP->algo__crosstalk_detect_event_sigma = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_HIST_XTALK_MARGIN_KCPS: + pdev->xtalk_cfg.histogram_mode_crosstalk_margin_kcps = + (int16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_CONSISTENCY_LITE_PHASE_TOLERANCE: + pdev->tuning_parms.tp_consistency_lite_phase_tolerance = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_PHASECAL_TARGET: + pdev->tuning_parms.tp_phasecal_target = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_LITE_CAL_REPEAT_RATE: + pdev->tuning_parms.tp_cal_repeat_rate = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_LITE_RANGING_GAIN_FACTOR: + pdev->gain_cal.standard_ranging_gain_factor = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_LITE_MIN_CLIP_MM: + pdev->tuning_parms.tp_lite_min_clip = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_LITE_LONG_SIGMA_THRESH_MM: + pdev->tuning_parms.tp_lite_long_sigma_thresh_mm = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_LITE_MED_SIGMA_THRESH_MM: + pdev->tuning_parms.tp_lite_med_sigma_thresh_mm = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_LITE_SHORT_SIGMA_THRESH_MM: + pdev->tuning_parms.tp_lite_short_sigma_thresh_mm = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_LITE_LONG_MIN_COUNT_RATE_RTN_MCPS: + pdev->tuning_parms.tp_lite_long_min_count_rate_rtn_mcps = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_LITE_MED_MIN_COUNT_RATE_RTN_MCPS: + pdev->tuning_parms.tp_lite_med_min_count_rate_rtn_mcps = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_LITE_SHORT_MIN_COUNT_RATE_RTN_MCPS: + pdev->tuning_parms.tp_lite_short_min_count_rate_rtn_mcps = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_LITE_SIGMA_EST_PULSE_WIDTH: + pdev->tuning_parms.tp_lite_sigma_est_pulse_width_ns = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_LITE_SIGMA_EST_AMB_WIDTH_NS: + pdev->tuning_parms.tp_lite_sigma_est_amb_width_ns = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_LITE_SIGMA_REF_MM: + pdev->tuning_parms.tp_lite_sigma_ref_mm = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_LITE_RIT_MULT: + pdev->xtalk_cfg.crosstalk_range_ignore_threshold_mult = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_LITE_SEED_CONFIG: + pdev->tuning_parms.tp_lite_seed_cfg = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_LITE_QUANTIFIER: + pdev->tuning_parms.tp_lite_quantifier = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_LITE_FIRST_ORDER_SELECT: + pdev->tuning_parms.tp_lite_first_order_select = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_LITE_XTALK_MARGIN_KCPS: + pdev->xtalk_cfg.lite_mode_crosstalk_margin_kcps = + (int16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_LITE_LONG_RANGE: + pdev->tuning_parms.tp_init_phase_rtn_lite_long = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_LITE_MED_RANGE: + pdev->tuning_parms.tp_init_phase_rtn_lite_med = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_LITE_SHORT_RANGE: + pdev->tuning_parms.tp_init_phase_rtn_lite_short = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_INITIAL_PHASE_REF_LITE_LONG_RANGE: + pdev->tuning_parms.tp_init_phase_ref_lite_long = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_INITIAL_PHASE_REF_LITE_MED_RANGE: + pdev->tuning_parms.tp_init_phase_ref_lite_med = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_INITIAL_PHASE_REF_LITE_SHORT_RANGE: + pdev->tuning_parms.tp_init_phase_ref_lite_short = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_TIMED_SEED_CONFIG: + pdev->tuning_parms.tp_timed_seed_cfg = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_DMAX_CFG_SIGNAL_THRESH_SIGMA: + pdev->dmax_cfg.signal_thresh_sigma = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_DMAX_CFG_REFLECTANCE_ARRAY_0: + pdev->dmax_cfg.target_reflectance_for_dmax_calc[0] = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_DMAX_CFG_REFLECTANCE_ARRAY_1: + pdev->dmax_cfg.target_reflectance_for_dmax_calc[1] = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_DMAX_CFG_REFLECTANCE_ARRAY_2: + pdev->dmax_cfg.target_reflectance_for_dmax_calc[2] = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_DMAX_CFG_REFLECTANCE_ARRAY_3: + pdev->dmax_cfg.target_reflectance_for_dmax_calc[3] = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_DMAX_CFG_REFLECTANCE_ARRAY_4: + pdev->dmax_cfg.target_reflectance_for_dmax_calc[4] = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_VHV_LOOPBOUND: + pdev->stat_nvm.vhv_config__timeout_macrop_loop_bound = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_REFSPADCHAR_DEVICE_TEST_MODE: + pdev->refspadchar.device_test_mode = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_REFSPADCHAR_VCSEL_PERIOD: + pdev->refspadchar.VL53L1_p_009 = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_REFSPADCHAR_PHASECAL_TIMEOUT_US: + pdev->refspadchar.timeout_us = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_REFSPADCHAR_TARGET_COUNT_RATE_MCPS: + pdev->refspadchar.target_count_rate_mcps = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_REFSPADCHAR_MIN_COUNTRATE_LIMIT_MCPS: + pdev->refspadchar.min_count_rate_limit_mcps = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_REFSPADCHAR_MAX_COUNTRATE_LIMIT_MCPS: + pdev->refspadchar.max_count_rate_limit_mcps = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_XTALK_EXTRACT_NUM_OF_SAMPLES: + pXC->num_of_samples = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_XTALK_EXTRACT_MIN_FILTER_THRESH_MM: + pXC->algo__crosstalk_extract_min_valid_range_mm = + (int16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_XTALK_EXTRACT_MAX_FILTER_THRESH_MM: + pXC->algo__crosstalk_extract_max_valid_range_mm = + (int16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_XTALK_EXTRACT_DSS_RATE_MCPS: + pXC->dss_config__target_total_rate_mcps = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_XTALK_EXTRACT_PHASECAL_TIMEOUT_US: + pXC->phasecal_config_timeout_us = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_XTALK_EXTRACT_MAX_VALID_RATE_KCPS: + pXC->algo__crosstalk_extract_max_valid_rate_kcps = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_XTALK_EXTRACT_SIGMA_THRESHOLD_MM: + pXC->algo__crosstalk_extract_max_sigma_mm = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_XTALK_EXTRACT_DSS_TIMEOUT_US: + pXC->mm_config_timeout_us = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_XTALK_EXTRACT_BIN_TIMEOUT_US: + pXC->range_config_timeout_us = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_OFFSET_CAL_DSS_RATE_MCPS: + pdev->offsetcal_cfg.dss_config__target_total_rate_mcps = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_OFFSET_CAL_PHASECAL_TIMEOUT_US: + pdev->offsetcal_cfg.phasecal_config_timeout_us = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_OFFSET_CAL_MM_TIMEOUT_US: + pdev->offsetcal_cfg.mm_config_timeout_us = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_OFFSET_CAL_RANGE_TIMEOUT_US: + pdev->offsetcal_cfg.range_config_timeout_us = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_OFFSET_CAL_PRE_SAMPLES: + pdev->offsetcal_cfg.pre_num_of_samples = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_OFFSET_CAL_MM1_SAMPLES: + pdev->offsetcal_cfg.mm1_num_of_samples = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_OFFSET_CAL_MM2_SAMPLES: + pdev->offsetcal_cfg.mm2_num_of_samples = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_ZONE_CAL_DSS_RATE_MCPS: + pdev->zonecal_cfg.dss_config__target_total_rate_mcps = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_ZONE_CAL_PHASECAL_TIMEOUT_US: + pdev->zonecal_cfg.phasecal_config_timeout_us = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_ZONE_CAL_DSS_TIMEOUT_US: + pdev->zonecal_cfg.mm_config_timeout_us = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_ZONE_CAL_PHASECAL_NUM_SAMPLES: + pdev->zonecal_cfg.phasecal_num_of_samples = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_ZONE_CAL_RANGE_TIMEOUT_US: + pdev->zonecal_cfg.range_config_timeout_us = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_ZONE_CAL_ZONE_NUM_SAMPLES: + pdev->zonecal_cfg.zone_num_of_samples = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_SPADMAP_VCSEL_PERIOD: + pdev->ssc_cfg.VL53L1_p_009 = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_SPADMAP_VCSEL_START: + pdev->ssc_cfg.vcsel_start = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_SPADMAP_RATE_LIMIT_MCPS: + pdev->ssc_cfg.rate_limit_mcps = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_LITE_DSS_CONFIG_TARGET_TOTAL_RATE_MCPS: + pdev->tuning_parms.tp_dss_target_lite_mcps = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_RANGING_DSS_CONFIG_TARGET_TOTAL_RATE_MCPS: + pdev->tuning_parms.tp_dss_target_histo_mcps = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_MZ_DSS_CONFIG_TARGET_TOTAL_RATE_MCPS: + pdev->tuning_parms.tp_dss_target_histo_mz_mcps = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_TIMED_DSS_CONFIG_TARGET_TOTAL_RATE_MCPS: + pdev->tuning_parms.tp_dss_target_timed_mcps = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_LITE_PHASECAL_CONFIG_TIMEOUT_US: + pdev->tuning_parms.tp_phasecal_timeout_lite_us = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_RANGING_LONG_PHASECAL_CONFIG_TIMEOUT_US: + pdev->tuning_parms.tp_phasecal_timeout_hist_long_us = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_RANGING_MED_PHASECAL_CONFIG_TIMEOUT_US: + pdev->tuning_parms.tp_phasecal_timeout_hist_med_us = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_RANGING_SHORT_PHASECAL_CONFIG_TIMEOUT_US: + pdev->tuning_parms.tp_phasecal_timeout_hist_short_us = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_MZ_LONG_PHASECAL_CONFIG_TIMEOUT_US: + pdev->tuning_parms.tp_phasecal_timeout_mz_long_us = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_MZ_MED_PHASECAL_CONFIG_TIMEOUT_US: + pdev->tuning_parms.tp_phasecal_timeout_mz_med_us = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_MZ_SHORT_PHASECAL_CONFIG_TIMEOUT_US: + pdev->tuning_parms.tp_phasecal_timeout_mz_short_us = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_TIMED_PHASECAL_CONFIG_TIMEOUT_US: + pdev->tuning_parms.tp_phasecal_timeout_timed_us = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_LITE_MM_CONFIG_TIMEOUT_US: + pdev->tuning_parms.tp_mm_timeout_lite_us = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_RANGING_MM_CONFIG_TIMEOUT_US: + pdev->tuning_parms.tp_mm_timeout_histo_us = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_MZ_MM_CONFIG_TIMEOUT_US: + pdev->tuning_parms.tp_mm_timeout_mz_us = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_TIMED_MM_CONFIG_TIMEOUT_US: + pdev->tuning_parms.tp_mm_timeout_timed_us = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_LITE_RANGE_CONFIG_TIMEOUT_US: + pdev->tuning_parms.tp_range_timeout_lite_us = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_RANGING_RANGE_CONFIG_TIMEOUT_US: + pdev->tuning_parms.tp_range_timeout_histo_us = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_MZ_RANGE_CONFIG_TIMEOUT_US: + pdev->tuning_parms.tp_range_timeout_mz_us = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_TIMED_RANGE_CONFIG_TIMEOUT_US: + pdev->tuning_parms.tp_range_timeout_timed_us = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_DYNXTALK_SMUDGE_MARGIN: + pdev->smudge_correct_config.smudge_margin = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_DYNXTALK_NOISE_MARGIN: + pdev->smudge_correct_config.noise_margin = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_DYNXTALK_XTALK_OFFSET_LIMIT: + pdev->smudge_correct_config.user_xtalk_offset_limit = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_DYNXTALK_XTALK_OFFSET_LIMIT_HI: + pdev->smudge_correct_config.user_xtalk_offset_limit_hi = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_DYNXTALK_SAMPLE_LIMIT: + pdev->smudge_correct_config.sample_limit = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_DYNXTALK_SINGLE_XTALK_DELTA: + pdev->smudge_correct_config.single_xtalk_delta = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_DYNXTALK_AVERAGED_XTALK_DELTA: + pdev->smudge_correct_config.averaged_xtalk_delta = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_DYNXTALK_CLIP_LIMIT: + pdev->smudge_correct_config.smudge_corr_clip_limit = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_DYNXTALK_SCALER_CALC_METHOD: + pdev->smudge_correct_config.scaler_calc_method = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_DYNXTALK_XGRADIENT_SCALER: + pdev->smudge_correct_config.x_gradient_scaler = + (int16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_DYNXTALK_YGRADIENT_SCALER: + pdev->smudge_correct_config.y_gradient_scaler = + (int16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_DYNXTALK_USER_SCALER_SET: + pdev->smudge_correct_config.user_scaler_set = + (uint8_t)tuning_parm_value; + break; + + case VL53L1_TUNINGPARM_DYNXTALK_SMUDGE_COR_SINGLE_APPLY: + pdev->smudge_correct_config.smudge_corr_single_apply = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_DYNXTALK_XTALK_AMB_THRESHOLD: + pdev->smudge_correct_config.smudge_corr_ambient_threshold = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_DYNXTALK_NODETECT_AMB_THRESHOLD_KCPS: + pdev->smudge_correct_config.nodetect_ambient_threshold = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_DYNXTALK_NODETECT_SAMPLE_LIMIT: + pdev->smudge_correct_config.nodetect_sample_limit = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_DYNXTALK_NODETECT_XTALK_OFFSET_KCPS: + pdev->smudge_correct_config.nodetect_xtalk_offset = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_DYNXTALK_NODETECT_MIN_RANGE_MM: + pdev->smudge_correct_config.nodetect_min_range_mm = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_LOWPOWERAUTO_VHV_LOOP_BOUND: + pdev->low_power_auto_data.vhv_loop_bound = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_LOWPOWERAUTO_MM_CONFIG_TIMEOUT_US: + pdev->tuning_parms.tp_mm_timeout_lpa_us = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_LOWPOWERAUTO_RANGE_CONFIG_TIMEOUT_US: + pdev->tuning_parms.tp_range_timeout_lpa_us = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_VERY_SHORT_DSS_RATE_MCPS: + pdev->tuning_parms.tp_dss_target_very_short_mcps = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_PHASECAL_PATCH_POWER: + pdev->tuning_parms.tp_phasecal_patch_power = + (uint16_t) tuning_parm_value; + break; + case VL53L1_TUNINGPARM_HIST_MERGE: + pdev->tuning_parms.tp_hist_merge = + (uint16_t) tuning_parm_value; + break; + case VL53L1_TUNINGPARM_RESET_MERGE_THRESHOLD: + pdev->tuning_parms.tp_reset_merge_threshold = + (uint16_t) tuning_parm_value; + break; + case VL53L1_TUNINGPARM_HIST_MERGE_MAX_SIZE: + pdev->tuning_parms.tp_hist_merge_max_size = + (uint16_t) tuning_parm_value; + break; + + + default: + status = VL53L1_ERROR_INVALID_PARAMS; + break; + + } + + LOG_FUNCTION_END(status); + + return status; +} + + + + + + + +VL53L1_Error VL53L1_dynamic_xtalk_correction_enable( + VL53L1_DEV Dev + ) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + pdev->smudge_correct_config.smudge_corr_enabled = 1; + + LOG_FUNCTION_END(status); + + return status; +} + +VL53L1_Error VL53L1_dynamic_xtalk_correction_disable( + VL53L1_DEV Dev + ) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + pdev->smudge_correct_config.smudge_corr_enabled = 0; + + LOG_FUNCTION_END(status); + + return status; +} + +VL53L1_Error VL53L1_dynamic_xtalk_correction_apply_enable( + VL53L1_DEV Dev + ) +{ + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + pdev->smudge_correct_config.smudge_corr_apply_enabled = 1; + + LOG_FUNCTION_END(status); + + return status; +} + +VL53L1_Error VL53L1_dynamic_xtalk_correction_apply_disable( + VL53L1_DEV Dev + ) +{ + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + pdev->smudge_correct_config.smudge_corr_apply_enabled = 0; + + LOG_FUNCTION_END(status); + + return status; +} + +VL53L1_Error VL53L1_dynamic_xtalk_correction_single_apply_enable( + VL53L1_DEV Dev + ) +{ + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + pdev->smudge_correct_config.smudge_corr_single_apply = 1; + + LOG_FUNCTION_END(status); + + return status; +} + +VL53L1_Error VL53L1_dynamic_xtalk_correction_single_apply_disable( + VL53L1_DEV Dev + ) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + pdev->smudge_correct_config.smudge_corr_single_apply = 0; + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_dynamic_xtalk_correction_set_scalers( + VL53L1_DEV Dev, + int16_t x_scaler_in, + int16_t y_scaler_in, + uint8_t user_scaler_set_in + ) +{ + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + pdev->smudge_correct_config.x_gradient_scaler = x_scaler_in; + pdev->smudge_correct_config.y_gradient_scaler = y_scaler_in; + pdev->smudge_correct_config.user_scaler_set = user_scaler_set_in; + + LOG_FUNCTION_END(status); + + return status; +} + + + + + + + + +VL53L1_Error VL53L1_get_current_xtalk_settings( + VL53L1_DEV Dev, + VL53L1_xtalk_calibration_results_t *pxtalk + ) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t i; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + pxtalk->algo__crosstalk_compensation_plane_offset_kcps = + pdev->xtalk_cfg.algo__crosstalk_compensation_plane_offset_kcps; + pxtalk->algo__crosstalk_compensation_x_plane_gradient_kcps = + pdev->xtalk_cfg.algo__crosstalk_compensation_x_plane_gradient_kcps; + pxtalk->algo__crosstalk_compensation_y_plane_gradient_kcps = + pdev->xtalk_cfg.algo__crosstalk_compensation_y_plane_gradient_kcps; + for (i = 0; i < VL53L1_BIN_REC_SIZE; i++) + pxtalk->algo__xtalk_cpo_HistoMerge_kcps[i] = + pdev->xtalk_cal.algo__xtalk_cpo_HistoMerge_kcps[i]; + + LOG_FUNCTION_END(status); + + return status; + +} + + + + + + + +VL53L1_Error VL53L1_set_current_xtalk_settings( + VL53L1_DEV Dev, + VL53L1_xtalk_calibration_results_t *pxtalk + ) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t i; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + pdev->xtalk_cfg.algo__crosstalk_compensation_plane_offset_kcps = + pxtalk->algo__crosstalk_compensation_plane_offset_kcps; + pdev->xtalk_cfg.algo__crosstalk_compensation_x_plane_gradient_kcps = + pxtalk->algo__crosstalk_compensation_x_plane_gradient_kcps; + pdev->xtalk_cfg.algo__crosstalk_compensation_y_plane_gradient_kcps = + pxtalk->algo__crosstalk_compensation_y_plane_gradient_kcps; + for (i = 0; i < VL53L1_BIN_REC_SIZE; i++) + pdev->xtalk_cal.algo__xtalk_cpo_HistoMerge_kcps[i] = + pxtalk->algo__xtalk_cpo_HistoMerge_kcps[i]; + + LOG_FUNCTION_END(status); + + return status; + +} + + + + diff --git a/drivers/input/misc/vl53L1/kona/src/vl53l1_api_debug.c b/drivers/input/misc/vl53L1/kona/src/vl53l1_api_debug.c new file mode 100644 index 000000000000..0383bac3b14b --- /dev/null +++ b/drivers/input/misc/vl53L1/kona/src/vl53l1_api_debug.c @@ -0,0 +1,3629 @@ + +/******************************************************************************* + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#include "vl53l1_ll_def.h" +#include "vl53l1_ll_device.h" +#include "vl53l1_register_structs.h" +#include "vl53l1_hist_structs.h" +#include "vl53l1_nvm_structs.h" +#include "vl53l1_nvm.h" +#include "vl53l1_core.h" +#include "vl53l1_api_debug.h" + +#ifdef VL53L1_LOG_ENABLE +#include "vl53l1_nvm_debug.h" +#endif + +#define LOG_FUNCTION_START(fmt, ...) \ + _LOG_FUNCTION_START(VL53L1_TRACE_MODULE_CORE, fmt, ##__VA_ARGS__) +#define LOG_FUNCTION_END(status, ...) \ + _LOG_FUNCTION_END(VL53L1_TRACE_MODULE_CORE, status, ##__VA_ARGS__) +#define LOG_FUNCTION_END_FMT(status, fmt, ...) \ + _LOG_FUNCTION_END_FMT(VL53L1_TRACE_MODULE_CORE, status, \ + fmt, ##__VA_ARGS__) + +#define trace_print(level, ...) \ + _LOG_TRACE_PRINT(trace_flags, \ + level, VL53L1_TRACE_FUNCTION_NONE, ##__VA_ARGS__) + + +VL53L1_Error VL53L1_decode_calibration_data_buffer( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_calibration_data_t *pdata) +{ + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (sizeof(VL53L1_calibration_data_t) > buf_size) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + memcpy(pdata, pbuffer, sizeof(VL53L1_calibration_data_t)); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_nvm_debug_data( + VL53L1_DEV Dev, + VL53L1_decoded_nvm_data_t *pdata) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + status = VL53L1_read_nvm(Dev, 0, pdata); + +#ifdef VL53L1_LOG_ENABLE + if (status == VL53L1_ERROR_NONE) + VL53L1_print_decoded_nvm_data( + pdata, + "get_nvm_debug_data():pnvm_info.", + VL53L1_TRACE_MODULE_NVM_DATA); +#endif + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_histogram_debug_data( + VL53L1_DEV Dev, + VL53L1_histogram_bin_data_t *pdata) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + + + memcpy( + pdata, + &(pdev->hist_data), + sizeof(VL53L1_histogram_bin_data_t)); + + LOG_FUNCTION_END(status); + + return status; +} + + + + + +VL53L1_Error VL53L1_get_additional_data( + VL53L1_DEV Dev, + VL53L1_additional_data_t *pdata) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + + + + pdata->preset_mode = pdev->preset_mode; + pdata->zone_preset = pdev->zone_preset; + pdata->measurement_mode = pdev->measurement_mode; + pdata->offset_calibration_mode = pdev->offset_calibration_mode; + pdata->offset_correction_mode = pdev->offset_correction_mode; + pdata->dmax_mode = pdev->dmax_mode; + + pdata->phasecal_config_timeout_us = pdev->phasecal_config_timeout_us; + pdata->mm_config_timeout_us = pdev->mm_config_timeout_us; + pdata->range_config_timeout_us = pdev->range_config_timeout_us; + pdata->inter_measurement_period_ms = pdev->inter_measurement_period_ms; + pdata->dss_config__target_total_rate_mcps = + pdev->dss_config__target_total_rate_mcps; + + + + + status = + VL53L1_get_histogram_debug_data( + Dev, + &(pdata->VL53L1_p_010)); + + LOG_FUNCTION_END(status); + + return status; +} + + + + + +VL53L1_Error VL53L1_get_xtalk_debug_data( + VL53L1_DEV Dev, + VL53L1_xtalk_debug_data_t *pdata) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + + + memcpy( + &(pdata->customer), + &(pdev->customer), + sizeof(VL53L1_customer_nvm_managed_t)); + + memcpy( + &(pdata->xtalk_cfg), + &(pdev->xtalk_cfg), + sizeof(VL53L1_xtalk_config_t)); + + memcpy( + &(pdata->hist_data), + &(pdev->hist_data), + sizeof(VL53L1_histogram_bin_data_t)); + + memcpy( + &(pdata->xtalk_shapes), + &(pdev->xtalk_shapes), + sizeof(VL53L1_xtalk_histogram_data_t)); + + memcpy( + &(pdata->xtalk_results), + &(pdev->xtalk_results), + sizeof(VL53L1_xtalk_range_results_t)); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_offset_debug_data( + VL53L1_DEV Dev, + VL53L1_offset_debug_data_t *pdata) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + + + memcpy( + &(pdata->customer), + &(pdev->customer), + sizeof(VL53L1_customer_nvm_managed_t)); + + memcpy( + &(pdata->fmt_dmax_cal), + &(pdev->fmt_dmax_cal), + sizeof(VL53L1_dmax_calibration_data_t)); + + memcpy( + &(pdata->cust_dmax_cal), + &(pdev->cust_dmax_cal), + sizeof(VL53L1_dmax_calibration_data_t)); + + memcpy( + &(pdata->add_off_cal_data), + &(pdev->add_off_cal_data), + sizeof(VL53L1_additional_offset_cal_data_t)); + + memcpy( + &(pdata->offset_results), + &(pdev->offset_results), + sizeof(VL53L1_offset_range_results_t)); + + LOG_FUNCTION_END(status); + + return status; +} + +#ifdef VL53L1_LOG_ENABLE + +void VL53L1_signed_fixed_point_sprintf( + int32_t signed_fp_value, + uint8_t frac_bits, + uint16_t buf_size, + char *pbuffer) +{ + + + + + + uint32_t fp_value = 0; + uint32_t unity_fp_value = 0; + uint32_t sign_bit = 0; + uint32_t int_part = 0; + uint32_t frac_part = 0; + uint32_t dec_points = 0; + uint32_t dec_scaler = 0; + uint32_t dec_part = 0; + + uint64_t tmp_long_int = 0; + + char fmt[VL53L1_MAX_STRING_LENGTH]; + + SUPPRESS_UNUSED_WARNING(buf_size); + + + + + sign_bit = signed_fp_value >> 31; + + if (sign_bit > 0) { + fp_value = 0x80000000 - + (0x7FFFFFFF & (uint32_t)signed_fp_value); + } else + fp_value = (uint32_t)signed_fp_value; + + int_part = fp_value >> frac_bits; + unity_fp_value = 0x01 << frac_bits; + frac_part = fp_value & (unity_fp_value-1); + + + + + + dec_points = 2; + dec_scaler = 100; + + while (dec_scaler < unity_fp_value) { + dec_points++; + dec_scaler *= 10; + } + + + + if (sign_bit > 0) + sprintf(fmt, "-%%u.%%0%uu", dec_points); + else + sprintf(fmt, "%%u.%%0%uu", dec_points); + + + + + + tmp_long_int = (uint64_t)frac_part * (uint64_t)dec_scaler; + tmp_long_int += (uint64_t)unity_fp_value/2; + + tmp_long_int = do_division_u(tmp_long_int, (uint64_t)unity_fp_value); + + dec_part = (uint32_t)tmp_long_int; + + + + sprintf( + pbuffer, + fmt, + int_part, + dec_part); +} + + +void VL53L1_print_static_nvm_managed( + VL53L1_static_nvm_managed_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + + + + + + char fp_text[VL53L1_MAX_STRING_LENGTH]; + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = 0x%02X\n", + pprefix, + "i2c_slave__device_address", + pdata->i2c_slave__device_address); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "ana_config__vhv_ref_sel_vddpix", + pdata->ana_config__vhv_ref_sel_vddpix); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "ana_config__vhv_ref_sel_vquench", + pdata->ana_config__vhv_ref_sel_vquench); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "ana_config__reg_avdd1v2_sel", + pdata->ana_config__reg_avdd1v2_sel); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "ana_config__fast_osc__trim", + pdata->ana_config__fast_osc__trim); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->osc_measured__fast_osc__frequency, + 12, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "osc_measured__fast_osc__frequency", + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "vhv_config__timeout_macrop_loop_bound", + pdata->vhv_config__timeout_macrop_loop_bound); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "vhv_config__count_thresh", + pdata->vhv_config__count_thresh); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "vhv_config__offset", + pdata->vhv_config__offset); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "vhv_config__init", + pdata->vhv_config__init); +} + + +void VL53L1_print_customer_nvm_managed( + VL53L1_customer_nvm_managed_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + + + + + + char fp_text[VL53L1_MAX_STRING_LENGTH]; + int16_t tmpi16; + + trace_print(VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_ref_0", + pdata->global_config__spad_enables_ref_0); + + trace_print(VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_ref_1", + pdata->global_config__spad_enables_ref_1); + + trace_print(VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_ref_2", + pdata->global_config__spad_enables_ref_2); + + trace_print(VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_ref_3", + pdata->global_config__spad_enables_ref_3); + + trace_print(VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_ref_4", + pdata->global_config__spad_enables_ref_4); + + trace_print(VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_ref_5", + pdata->global_config__spad_enables_ref_5); + + trace_print(VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__ref_en_start_select", + pdata->global_config__ref_en_start_select); + + trace_print(VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "ref_spad_man__num_requested_ref_spads", + pdata->ref_spad_man__num_requested_ref_spads); + + trace_print(VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "ref_spad_man__ref_location", + pdata->ref_spad_man__ref_location); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->algo__crosstalk_compensation_plane_offset_kcps, + 9, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print(VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "algo__crosstalk_compensation_plane_offset_kcps", + fp_text); + + tmpi16 = pdata->algo__crosstalk_compensation_x_plane_gradient_kcps; + VL53L1_signed_fixed_point_sprintf( + (int32_t)tmpi16, + 11, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print(VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "algo__crosstalk_compensation_x_plane_gradient_kcps", + fp_text); + + tmpi16 = pdata->algo__crosstalk_compensation_y_plane_gradient_kcps; + VL53L1_signed_fixed_point_sprintf( + (int32_t)tmpi16, + 11, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print(VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "algo__crosstalk_compensation_y_plane_gradient_kcps", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->ref_spad_char__total_rate_target_mcps, + 7, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print(VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "ref_spad_char__total_rate_target_mcps", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->algo__part_to_part_range_offset_mm, + 2, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print(VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "algo__part_to_part_range_offset_mm", + fp_text); + + trace_print(VL53L1_TRACE_LEVEL_INFO, + "%s%s = %d\n", + pprefix, + "mm_config__inner_offset_mm", + pdata->mm_config__inner_offset_mm); + + trace_print(VL53L1_TRACE_LEVEL_INFO, + "%s%s = %d\n", + pprefix, + "mm_config__outer_offset_mm", + pdata->mm_config__outer_offset_mm); +} + + +void VL53L1_print_nvm_copy_data( + VL53L1_nvm_copy_data_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + + + + + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "identification__model_id", + pdata->identification__model_id); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "identification__module_type", + pdata->identification__module_type); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "identification__revision_id", + pdata->identification__revision_id); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "identification__module_id", + pdata->identification__module_id); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "ana_config__fast_osc__trim_max", + pdata->ana_config__fast_osc__trim_max); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "ana_config__fast_osc__freq_set", + pdata->ana_config__fast_osc__freq_set); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "ana_config__vcsel_trim", + pdata->ana_config__vcsel_trim); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "ana_config__vcsel_selion", + pdata->ana_config__vcsel_selion); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "ana_config__vcsel_selion_max", + pdata->ana_config__vcsel_selion_max); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "protected_laser_safety__lock_bit", + pdata->protected_laser_safety__lock_bit); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "laser_safety__key", + pdata->laser_safety__key); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "laser_safety__key_ro", + pdata->laser_safety__key_ro); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "laser_safety__clip", + pdata->laser_safety__clip); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "laser_safety__mult", + pdata->laser_safety__mult); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_0", + pdata->global_config__spad_enables_rtn_0); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_1", + pdata->global_config__spad_enables_rtn_1); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_2", + pdata->global_config__spad_enables_rtn_2); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_3", + pdata->global_config__spad_enables_rtn_3); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_4", + pdata->global_config__spad_enables_rtn_4); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_5", + pdata->global_config__spad_enables_rtn_5); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_6", + pdata->global_config__spad_enables_rtn_6); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_7", + pdata->global_config__spad_enables_rtn_7); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_8", + pdata->global_config__spad_enables_rtn_8); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_9", + pdata->global_config__spad_enables_rtn_9); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_10", + pdata->global_config__spad_enables_rtn_10); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_11", + pdata->global_config__spad_enables_rtn_11); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_12", + pdata->global_config__spad_enables_rtn_12); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_13", + pdata->global_config__spad_enables_rtn_13); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_14", + pdata->global_config__spad_enables_rtn_14); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_15", + pdata->global_config__spad_enables_rtn_15); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_16", + pdata->global_config__spad_enables_rtn_16); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_17", + pdata->global_config__spad_enables_rtn_17); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_18", + pdata->global_config__spad_enables_rtn_18); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_19", + pdata->global_config__spad_enables_rtn_19); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_20", + pdata->global_config__spad_enables_rtn_20); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_21", + pdata->global_config__spad_enables_rtn_21); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_22", + pdata->global_config__spad_enables_rtn_22); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_23", + pdata->global_config__spad_enables_rtn_23); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_24", + pdata->global_config__spad_enables_rtn_24); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_25", + pdata->global_config__spad_enables_rtn_25); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_26", + pdata->global_config__spad_enables_rtn_26); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_27", + pdata->global_config__spad_enables_rtn_27); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_28", + pdata->global_config__spad_enables_rtn_28); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_29", + pdata->global_config__spad_enables_rtn_29); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_30", + pdata->global_config__spad_enables_rtn_30); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_31", + pdata->global_config__spad_enables_rtn_31); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "roi_config__mode_roi_centre_spad", + pdata->roi_config__mode_roi_centre_spad); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = 0x%02X\n", + pprefix, + "roi_config__mode_roi_xy_size", + pdata->roi_config__mode_roi_xy_size); +} + + +void VL53L1_print_histogram_bin_data( + VL53L1_histogram_bin_data_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + + + + + + char fp_text[VL53L1_MAX_STRING_LENGTH]; + char pre_text[VL53L1_MAX_STRING_LENGTH]; + char *ppre_text = &(pre_text[0]); + + uint8_t i = 0; + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "cfg_device_state", + pdata->cfg_device_state); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "rd_device_state", + pdata->rd_device_state); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "VL53L1_p_022", + pdata->VL53L1_p_022); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "VL53L1_p_023", + pdata->VL53L1_p_023); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "VL53L1_p_024", + pdata->VL53L1_p_024); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "number_of_ambient_bins", + pdata->number_of_ambient_bins); + + for (i = 0; i < VL53L1_MAX_BIN_SEQUENCE_LENGTH; i++) { + sprintf(ppre_text, "%sbin_seq[%u]", pprefix, i); + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s = %u\n", + ppre_text, + pdata->bin_seq[i]); + } + + for (i = 0; i < VL53L1_MAX_BIN_SEQUENCE_LENGTH; i++) { + sprintf(ppre_text, "%sbin_rep[%u]", pprefix, i); + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s = %u\n", + ppre_text, + pdata->bin_rep[i]); + } + + for (i = 0; i < pdata->VL53L1_p_024; i++) { + sprintf(ppre_text, "%sbin_data[%u]", pprefix, i); + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s = %d\n", + ppre_text, + pdata->bin_data[i]); + } + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "result__interrupt_status", + pdata->result__interrupt_status); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "result__range_status", + pdata->result__range_status); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "result__report_status", + pdata->result__report_status); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "result__stream_count", + pdata->result__stream_count); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->result__dss_actual_effective_spads, + 8, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "result__dss_actual_effective_spads", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->phasecal_result__reference_phase, + 11, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "phasecal_result__reference_phase", + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "phasecal_result__vcsel_start", + pdata->phasecal_result__vcsel_start); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "cal_config__vcsel_start", + pdata->cal_config__vcsel_start); + + VL53L1_signed_fixed_point_sprintf( + (uint32_t)pdata->vcsel_width, + 4, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "vcsel_width", + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "VL53L1_p_009", + pdata->VL53L1_p_009); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->VL53L1_p_019, + 12, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "VL53L1_p_019", + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "total_periods_elapsed", + pdata->total_periods_elapsed); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "peak_duration_us", + pdata->peak_duration_us); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "woi_duration_us", + pdata->woi_duration_us); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "min_bin_value", + pdata->min_bin_value); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "max_bin_value", + pdata->max_bin_value); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->zero_distance_phase, + 11, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "zero_distance_phase", + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "number_of_ambient_samples", + pdata->number_of_ambient_samples); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %d\n", + pprefix, + "ambient_events_sum", + pdata->ambient_events_sum); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %d\n", + pprefix, + "VL53L1_p_004", + pdata->VL53L1_p_004); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = 0x%02X\n", + pprefix, + "roi_config__user_roi_centre_spad", + pdata->roi_config__user_roi_centre_spad); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = 0x%02X\n", + pprefix, + "roi_config__user_roi_requested_global_xy_size", + pdata->roi_config__user_roi_requested_global_xy_size); +} + + +void VL53L1_print_xtalk_histogram_shape_data( + VL53L1_xtalk_histogram_shape_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + + + + + + char fp_text[VL53L1_MAX_STRING_LENGTH]; + char pre_text[VL53L1_MAX_STRING_LENGTH]; + char *ppre_text = &(pre_text[0]); + + uint8_t i = 0; + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "VL53L1_p_022", + pdata->VL53L1_p_022); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "VL53L1_p_023", + pdata->VL53L1_p_023); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "VL53L1_p_024", + pdata->VL53L1_p_024); + + for (i = 0; i < pdata->VL53L1_p_024; i++) { + + sprintf(ppre_text, "%sbin_data[%u]", pprefix, i); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->bin_data[i], + 10, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s = %s\n", + ppre_text, + fp_text); + } + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->phasecal_result__reference_phase, + 11, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "phasecal_result__reference_phase", + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "phasecal_result__vcsel_start", + pdata->phasecal_result__vcsel_start); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "cal_config__vcsel_start", + pdata->cal_config__vcsel_start); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->vcsel_width, + 4, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "vcsel_width", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->VL53L1_p_019, + 12, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "VL53L1_p_019", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->zero_distance_phase, + 11, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "zero_distance_phase", + fp_text); +} + + +void VL53L1_print_xtalk_histogram_data( + VL53L1_xtalk_histogram_data_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + + + + + + char pre_text[VL53L1_MAX_STRING_LENGTH]; + char *ppre_text = &(pre_text[0]); + + + + sprintf(ppre_text, "%sxtalk_shape.", pprefix); + VL53L1_print_xtalk_histogram_shape_data( + &(pdata->xtalk_shape), + ppre_text, trace_flags); + + + + sprintf(ppre_text, "%sxtalk_hist_removed.", pprefix); + VL53L1_print_histogram_bin_data( + &(pdata->xtalk_hist_removed), + ppre_text, trace_flags); +} + + +void VL53L1_print_range_data( + VL53L1_range_data_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + + + + + + char fp_text[VL53L1_MAX_STRING_LENGTH]; + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "range_id", + pdata->range_id); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "time_stamp", + pdata->time_stamp); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "VL53L1_p_015", + pdata->VL53L1_p_015); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "VL53L1_p_022", + pdata->VL53L1_p_022); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "VL53L1_p_025", + pdata->VL53L1_p_025); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "VL53L1_p_026", + pdata->VL53L1_p_026); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "VL53L1_p_016", + pdata->VL53L1_p_016); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "VL53L1_p_027", + pdata->VL53L1_p_027); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->width, + 4, VL53L1_MAX_STRING_LENGTH, fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "width", + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "VL53L1_p_030", + pdata->VL53L1_p_030); + + + + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->fast_osc_frequency, + 12, VL53L1_MAX_STRING_LENGTH, fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "fast_osc_frequency", + fp_text); + + + + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->zero_distance_phase, + 11, VL53L1_MAX_STRING_LENGTH, fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "zero_distance_phase", + fp_text); + + + + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->VL53L1_p_006, + 8, VL53L1_MAX_STRING_LENGTH, fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "actual_effective_spad", + fp_text); + + + trace_print(VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "total_periods_elapsed", + pdata->total_periods_elapsed); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "peak_duration_us", + pdata->peak_duration_us); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "woi_duration_us", + pdata->woi_duration_us); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %d\n", + pprefix, + "VL53L1_p_020", + pdata->VL53L1_p_020); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %d\n", + pprefix, + "VL53L1_p_021", + pdata->VL53L1_p_021); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %d\n", + pprefix, + "VL53L1_p_013", + pdata->VL53L1_p_013); + + + + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->peak_signal_count_rate_mcps, + 7, VL53L1_MAX_STRING_LENGTH, fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "peak_signal_count_rate_mcps", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->avg_signal_count_rate_mcps, + 7, VL53L1_MAX_STRING_LENGTH, fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "avg_signal_count_rate_mcps", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->ambient_count_rate_mcps, + 7, VL53L1_MAX_STRING_LENGTH, fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "ambient_count_rate_mcps", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->total_rate_per_spad_mcps, + 13, VL53L1_MAX_STRING_LENGTH, fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "total_rate_per_spad_mcps", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->VL53L1_p_012, + 11, VL53L1_MAX_STRING_LENGTH, fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "VL53L1_p_012", + fp_text); + + + + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->VL53L1_p_005, + 2, VL53L1_MAX_STRING_LENGTH, fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "VL53L1_p_005", + fp_text); + + + + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->VL53L1_p_028, + 11, VL53L1_MAX_STRING_LENGTH, fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "VL53L1_p_028", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->VL53L1_p_014, + 11, VL53L1_MAX_STRING_LENGTH, fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "VL53L1_p_014", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->VL53L1_p_029, + 11, VL53L1_MAX_STRING_LENGTH, fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "VL53L1_p_029", + fp_text); + + + + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %d\n", + pprefix, + "min_range_mm", + pdata->min_range_mm); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %d\n", + pprefix, + "median_range_mm", + pdata->median_range_mm); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %d\n", + pprefix, + "max_range_mm", + pdata->max_range_mm); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "range_status", + pdata->range_status); +} + + +void VL53L1_print_range_results( + VL53L1_range_results_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + + + + + + char pre_text[VL53L1_MAX_STRING_LENGTH]; + char *ppre_text = &(pre_text[0]); + + uint8_t i = 0; + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "cfg_device_state", + pdata->cfg_device_state); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "rd_device_state", + pdata->rd_device_state); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "zone_id", + pdata->zone_id); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "stream_count", + pdata->stream_count); + + for (i = 0; i < VL53L1_MAX_AMBIENT_DMAX_VALUES; i++) { + sprintf( + ppre_text, + "%sambient_dmax_mm[%u]", + pprefix, i); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s = %u\n", + ppre_text, + pdata->VL53L1_p_007[i]); + } + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "device_status", + pdata->device_status); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "wrap_dmax_mm", + pdata->wrap_dmax_mm); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "max_results", + pdata->max_results); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "active_results", + pdata->active_results); + + for (i = 0; i < pdata->active_results; i++) { + sprintf(ppre_text, "%sdata[%u].", pprefix, i); + VL53L1_print_range_data( + &pdata->VL53L1_p_002[i], + ppre_text, trace_flags); + } + + sprintf(ppre_text, "%sxmonitor.", pprefix); + VL53L1_print_range_data( + &pdata->xmonitor, + ppre_text, trace_flags); +} + + +void VL53L1_print_offset_range_results( + VL53L1_offset_range_results_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + + + + + + char fp_text[VL53L1_MAX_STRING_LENGTH]; + char pre_text[VL53L1_MAX_STRING_LENGTH]; + char *ppre_text = &(pre_text[0]); + + uint8_t i = 0; + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "cal_distance_mm", + pdata->cal_distance_mm); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->cal_reflectance_pc, + 2, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "cal_reflectance_pc", + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "cal_status", + pdata->cal_status); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "cal_report", + pdata->cal_report); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "max_results", + pdata->max_results); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "active_results", + pdata->active_results); + + for (i = 0; i < pdata->active_results; i++) { + sprintf(ppre_text, "%sdata[%u].", pprefix, i); + VL53L1_print_offset_range_data( + &(pdata->VL53L1_p_002[i]), + ppre_text, trace_flags); + } +} + + +void VL53L1_print_offset_range_data( + VL53L1_offset_range_data_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + + + + + + char fp_text[VL53L1_MAX_STRING_LENGTH]; + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "preset_mode", + pdata->preset_mode); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "dss_config__roi_mode_control", + pdata->dss_config__roi_mode_control); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->dss_config__manual_effective_spads_select, + 8, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "dss_config__manual_effective_spads_select", + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "no_of_samples", + pdata->no_of_samples); + + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->effective_spads, + 8, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "effective_spads", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->peak_rate_mcps, + 7, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "peak_rate_mcps", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->VL53L1_p_005, + 2, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "VL53L1_p_005", + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %d\n", + pprefix, + "median_range_mm", + pdata->median_range_mm); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %d\n", + pprefix, + "range_mm_offset", + pdata->range_mm_offset); +} + + +void VL53L1_print_cal_peak_rate_map( + VL53L1_cal_peak_rate_map_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + + + + + + char fp_text[VL53L1_MAX_STRING_LENGTH]; + char pre_text[VL53L1_MAX_STRING_LENGTH]; + char *ppre_text = &(pre_text[0]); + + uint8_t i = 0; + uint8_t x = 0; + uint8_t y = 0; + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->cal_distance_mm, + 2, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "cal_distance_mm", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->cal_reflectance_pc, + 2, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "cal_reflectance_pc", + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "max_samples", + pdata->max_samples); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "width", + pdata->width); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "height", + pdata->height); + + i = 0; + for (y = 0; y < pdata->height; y++) { + for (x = 0; x < pdata->width; x++) { + + sprintf(ppre_text, "%speak_rate_mcps[%u]", pprefix, i); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->peak_rate_mcps[i], + 7, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s = %s\n", + ppre_text, + fp_text); + + i++; + } + } +} + +void VL53L1_print_additional_data( + VL53L1_additional_data_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + + + + + + + char fp_text[VL53L1_MAX_STRING_LENGTH]; + char pre_text[VL53L1_MAX_STRING_LENGTH]; + char *ppre_text = &(pre_text[0]); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "preset_mode", + pdata->preset_mode); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "zone_preset", + pdata->zone_preset); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "measurement_mode", + pdata->measurement_mode); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "offset_calibration_mode", + pdata->offset_calibration_mode); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "offset_correction_mode", + pdata->offset_correction_mode); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "dmax_mode", + pdata->dmax_mode); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "phasecal_config_timeout_us", + pdata->phasecal_config_timeout_us); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "mm_config_timeout_us", + pdata->mm_config_timeout_us); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "range_config_timeout_us", + pdata->range_config_timeout_us); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "inter_measurement_period_ms", + pdata->inter_measurement_period_ms); + + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->dss_config__target_total_rate_mcps, + 7, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "dss_config__target_total_rate_mcps", + fp_text); + + sprintf(ppre_text, "%s VL53L1_p_010.", pprefix); + VL53L1_print_histogram_bin_data( + &pdata->VL53L1_p_010, + ppre_text, trace_flags); + + +} + + +void VL53L1_print_additional_offset_cal_data( + VL53L1_additional_offset_cal_data_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + + + + + + char fp_text[VL53L1_MAX_STRING_LENGTH]; + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->result__mm_inner_actual_effective_spads, + 8, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "result__mm_inner_actual_effective_spads", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->result__mm_outer_actual_effective_spads, + 8, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "result__mm_outer_actual_effective_spads", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->result__mm_inner_peak_signal_count_rtn_mcps, + 7, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "result__mm_inner_peak_signal_count_rtn_mcps", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->result__mm_outer_peak_signal_count_rtn_mcps, + 7, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "result__mm_outer_peak_signal_count_rtn_mcps", + fp_text); +} + + +void VL53L1_print_gain_calibration_data( + VL53L1_gain_calibration_data_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + + + + + + char fp_text[VL53L1_MAX_STRING_LENGTH]; + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->standard_ranging_gain_factor, + 11, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "standard_ranging_gain_factor", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->histogram_ranging_gain_factor, + 11, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "histogram_ranging_gain_factor", + fp_text); +} + + +void VL53L1_print_zone_calibration_data( + VL53L1_zone_calibration_data_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + + + + + + char fp_text[VL53L1_MAX_STRING_LENGTH]; + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "no_of_samples", + pdata->no_of_samples); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->effective_spads, + 8, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "effective_spads", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->peak_rate_mcps, + 7, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "peak_rate_mcps", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->VL53L1_p_014, + 11, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "VL53L1_p_014", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->VL53L1_p_005, + 2, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "VL53L1_p_005", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->median_range_mm, + 2, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "median_range_mm", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->range_mm_offset, + 2, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "range_mm_offset", + fp_text); +} + + +void VL53L1_print_zone_calibration_results( + VL53L1_zone_calibration_results_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + + + + + + char fp_text[VL53L1_MAX_STRING_LENGTH]; + char pre_text[VL53L1_MAX_STRING_LENGTH]; + char *ppre_text = &(pre_text[0]); + + uint8_t i = 0; + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "preset_mode", + pdata->preset_mode); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "zone_preset", + pdata->zone_preset); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "cal_distance_mm", + pdata->cal_distance_mm); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->cal_reflectance_pc, + 2, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "cal_reflectance_pc", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->phasecal_result__reference_phase, + 11, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "phasecal_result__reference_phase", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->zero_distance_phase, + 11, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "zero_distance_phase", + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "cal_status", + pdata->cal_status); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "max_zones", + pdata->max_zones); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "active_zones", + pdata->active_zones); + + for (i = 0; i < pdata->active_zones; i++) { + sprintf(ppre_text, "%sdata[%u].", pprefix, i); + VL53L1_print_zone_calibration_data( + &(pdata->VL53L1_p_002[i]), + ppre_text, trace_flags); + } +} + +void VL53L1_print_xtalk_range_results( + VL53L1_xtalk_range_results_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + + + + + + char pre_text[VL53L1_MAX_STRING_LENGTH]; + char *ppre_text = &(pre_text[0]); + uint8_t i = 0; + + VL53L1_histogram_bin_data_t *pbin_data; + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "cal_status", + pdata->cal_status); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "num_of_samples_status", + pdata->num_of_samples_status); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "zero_samples_status", + pdata->zero_samples_status); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "max_sigma_status", + pdata->max_sigma_status); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "max_results", + pdata->max_results); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "active_results", + pdata->active_results); + + for (i = 0; i < pdata->active_results; i++) { + sprintf(ppre_text, "%sdata[%u].", pprefix, i); + VL53L1_print_xtalk_range_data( + &(pdata->VL53L1_p_002[i]), + ppre_text, trace_flags); + } + + sprintf(ppre_text, "%scentral_histogram_sum.", pprefix); + VL53L1_print_histogram_bin_data( + &pdata->central_histogram_sum, + ppre_text, trace_flags); + + sprintf(ppre_text, "%scentral_histogram_avg.", pprefix); + VL53L1_print_histogram_bin_data( + &pdata->central_histogram_avg, + ppre_text, trace_flags); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "VL53L1_p_015", + pdata->central_histogram__window_start); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "VL53L1_p_016", + pdata->central_histogram__window_end); + + pbin_data = &(pdata->histogram_avg_1[0]); + + for (i = 0; i < 5; i++) { + sprintf(ppre_text, "%shistogram_avg_1[%u].", pprefix, i); + VL53L1_print_histogram_bin_data( + pbin_data, + ppre_text, trace_flags); + pbin_data++; + } + + pbin_data = &(pdata->histogram_avg_2[0]); + + for (i = 0; i < 5; i++) { + sprintf(ppre_text, "%shistogram_avg_2[%u].", pprefix, i); + VL53L1_print_histogram_bin_data( + pbin_data, + ppre_text, trace_flags); + pbin_data++; + } + + pbin_data = &(pdata->xtalk_avg[0]); + + for (i = 0; i < 5; i++) { + sprintf(ppre_text, "%sxtalk_avg[%u].", pprefix, i); + VL53L1_print_histogram_bin_data( + pbin_data, + ppre_text, trace_flags); + pbin_data++; + } +} + + +void VL53L1_print_xtalk_range_data( + VL53L1_xtalk_range_data_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + + + + + + char fp_text[VL53L1_MAX_STRING_LENGTH]; + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "no_of_samples", + pdata->no_of_samples); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %d\n", + pprefix, + "signal_total_events_sum", + pdata->signal_total_events_sum); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %d\n", + pprefix, + "signal_total_events_avg", + pdata->signal_total_events_avg); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->rate_per_spad_kcps_sum, + 11, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "rate_per_spad_kcps_sum", + fp_text); + + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->rate_per_spad_kcps_avg, + 11, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "rate_per_spad_kcps_avg", + fp_text); +} + + +void VL53L1_print_xtalk_calibration_results( + VL53L1_xtalk_calibration_results_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + + + + + + char fp_text[VL53L1_MAX_STRING_LENGTH]; + int16_t tmpi16; + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->algo__crosstalk_compensation_plane_offset_kcps, + 9, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "algo__crosstalk_compensation_plane_offset_kcps", + fp_text); + + tmpi16 = pdata->algo__crosstalk_compensation_x_plane_gradient_kcps; + VL53L1_signed_fixed_point_sprintf( + (int32_t)tmpi16, + 11, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "algo__crosstalk_compensation_x_plane_gradient_kcps", + fp_text); + + tmpi16 = pdata->algo__crosstalk_compensation_y_plane_gradient_kcps; + VL53L1_signed_fixed_point_sprintf( + (int32_t)tmpi16, + 11, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "algo__crosstalk_compensation_y_plane_gradient_kcps", + fp_text); +} + + +void VL53L1_print_xtalk_config( + VL53L1_xtalk_config_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + + + + + + char fp_text[VL53L1_MAX_STRING_LENGTH]; + int16_t tmpi16; + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->algo__crosstalk_compensation_plane_offset_kcps, + 9, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "algo__crosstalk_compensation_plane_offset_kcps", + fp_text); + + tmpi16 = pdata->algo__crosstalk_compensation_x_plane_gradient_kcps; + VL53L1_signed_fixed_point_sprintf( + (int32_t)tmpi16, + 11, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "algo__crosstalk_compensation_x_plane_gradient_kcps", + fp_text); + + tmpi16 = pdata->algo__crosstalk_compensation_y_plane_gradient_kcps; + VL53L1_signed_fixed_point_sprintf( + (int32_t)tmpi16, + 11, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "algo__crosstalk_compensation_y_plane_gradient_kcps", + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_crosstalk_compensation_enable", + pdata->global_crosstalk_compensation_enable); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->histogram_mode_crosstalk_margin_kcps, + 9, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "histogram_mode_crosstalk_margin_kcps", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->lite_mode_crosstalk_margin_kcps, + 9, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "lite_mode_crosstalk_margin_kcps", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->crosstalk_range_ignore_threshold_mult, + 5, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "crosstalk_range_ignore_threshold_mult", + fp_text); + + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->crosstalk_range_ignore_threshold_rate_mcps, + 13, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "crosstalk_range_ignore_threshold_rate_mcps", + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "algo__crosstalk_detect_max_valid_range_mm", + pdata->algo__crosstalk_detect_max_valid_range_mm); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "algo__crosstalk_detect_min_valid_range_mm", + pdata->algo__crosstalk_detect_min_valid_range_mm); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->algo__crosstalk_detect_max_valid_rate_kcps, + 7, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "algo__crosstalk_detect_max_valid_rate_kcps", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->algo__crosstalk_detect_max_sigma_mm, + 2, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "algo__crosstalk_detect_max_sigma_mm", + fp_text); + +} + + +void VL53L1_print_xtalk_extract_config( + VL53L1_xtalkextract_config_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + + + + + + char fp_text[VL53L1_MAX_STRING_LENGTH]; + + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->dss_config__target_total_rate_mcps, + 7, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "dss_config__target_total_rate_mcps", + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "mm_config_timeout_us", + pdata->mm_config_timeout_us); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "range_config_timeout_us", + pdata->range_config_timeout_us); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "num_of_samples", + pdata->num_of_samples); + + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "algo__crosstalk_extract_max_valid_range_mm", + pdata->algo__crosstalk_extract_max_valid_range_mm); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "algo__crosstalk_extract_min_valid_range_mm", + pdata->algo__crosstalk_extract_min_valid_range_mm); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->algo__crosstalk_extract_max_valid_rate_kcps, + 9, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "algo__crosstalk_extract_max_valid_rate_kcps", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->algo__crosstalk_extract_max_sigma_mm, + 2, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "algo__crosstalk_extract_max_sigma_mm", + fp_text); + +} + + +void VL53L1_print_zone_cal_config( + VL53L1_zonecal_config_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + + + + + + char fp_text[VL53L1_MAX_STRING_LENGTH]; + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->dss_config__target_total_rate_mcps, + 7, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "dss_config__target_total_rate_mcps", + fp_text); + + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "mm_config_timeout_us", + pdata->mm_config_timeout_us); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "range_config_timeout_us", + pdata->range_config_timeout_us); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "phasecal_config_timeout_us", + pdata->phasecal_config_timeout_us); + + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "phasecal_num_of_samples", + pdata->phasecal_num_of_samples); + + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "zone_num_of_samples", + pdata->zone_num_of_samples); + +} + +void VL53L1_print_offset_cal_config( + VL53L1_offsetcal_config_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + + + + + + char fp_text[VL53L1_MAX_STRING_LENGTH]; + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->dss_config__target_total_rate_mcps, + 7, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "dss_config__target_total_rate_mcps", + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "phasecal_config_timeout_us", + pdata->phasecal_config_timeout_us); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "range_config_timeout_us", + pdata->range_config_timeout_us); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "pre_num_of_samples", + pdata->pre_num_of_samples); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "mm1_num_of_samples", + pdata->mm1_num_of_samples); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "mm2_num_of_samples", + pdata->mm2_num_of_samples); + + +} + + +void VL53L1_print_dmax_calibration_data( + VL53L1_dmax_calibration_data_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + + + + + + char fp_text[VL53L1_MAX_STRING_LENGTH]; + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->ref__actual_effective_spads, + 8, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "ref__actual_effective_spads", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->ref__peak_signal_count_rate_mcps, + 7, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "ref__peak_signal_count_rate_mcps", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->ref__distance_mm, + 4, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "ref__distance_mm", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->ref_reflectance_pc, + 2, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "ref_reflectance_pc", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->coverglass_transmission, + 8, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "coverglass_transmission", + fp_text); +} + + +void VL53L1_print_calibration_data( + VL53L1_calibration_data_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + + + + + + char pre_text[VL53L1_MAX_STRING_LENGTH]; + char *ppre_text = &(pre_text[0]); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = 0x%08X\n", + pprefix, + "struct_version", + pdata->struct_version); + + sprintf(ppre_text, "%scustomer.", pprefix); + VL53L1_print_customer_nvm_managed( + &(pdata->customer), + ppre_text, trace_flags); + + sprintf(ppre_text, "%sfmt_dmax_cal.", pprefix); + VL53L1_print_dmax_calibration_data( + &(pdata->fmt_dmax_cal), + ppre_text, trace_flags); + + sprintf(ppre_text, "%scust_dmax_cal.", pprefix); + VL53L1_print_dmax_calibration_data( + &(pdata->cust_dmax_cal), + ppre_text, trace_flags); + + sprintf(ppre_text, "%sadd_off_cal_data.", pprefix); + VL53L1_print_additional_offset_cal_data( + &(pdata->add_off_cal_data), + ppre_text, trace_flags); + + sprintf(ppre_text, "%soptical_centre.", pprefix); + VL53L1_print_optical_centre( + &(pdata->optical_centre), + ppre_text, trace_flags); + + sprintf(ppre_text, "%sxtalkhisto.", pprefix); + VL53L1_print_xtalk_histogram_data( + &(pdata->xtalkhisto), + ppre_text, trace_flags); + + sprintf(ppre_text, "%sgain_cal.", pprefix); + VL53L1_print_gain_calibration_data( + &(pdata->gain_cal), + ppre_text, trace_flags); + + sprintf(ppre_text, "%scal_peak_rate_map.", pprefix); + VL53L1_print_cal_peak_rate_map( + &(pdata->cal_peak_rate_map), + ppre_text, trace_flags); +} + + +void VL53L1_print_xtalk_debug_data( + VL53L1_xtalk_debug_data_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + + + + + + char pre_text[VL53L1_MAX_STRING_LENGTH]; + char *ppre_text = &(pre_text[0]); + + sprintf(ppre_text, "%scustomer.", pprefix); + VL53L1_print_customer_nvm_managed( + &(pdata->customer), + ppre_text, trace_flags); + + sprintf(ppre_text, "%sxtalk_cfg.", pprefix); + VL53L1_print_xtalk_config( + &(pdata->xtalk_cfg), + ppre_text, trace_flags); + + sprintf(ppre_text, "%sxtalk_extract_cfg.", pprefix); + VL53L1_print_xtalk_extract_config( + &(pdata->xtalk_extract_cfg), + ppre_text, trace_flags); + + sprintf(ppre_text, "%shist_data.", pprefix); + VL53L1_print_histogram_bin_data( + &(pdata->hist_data), + ppre_text, trace_flags); + + sprintf(ppre_text, "%sxtalk_shapes.", pprefix); + VL53L1_print_xtalk_histogram_data( + &(pdata->xtalk_shapes), + ppre_text, trace_flags); + + sprintf(ppre_text, "%sgain_cal.", pprefix); + VL53L1_print_xtalk_range_results( + &(pdata->xtalk_results), + ppre_text, trace_flags); +} + + +void VL53L1_print_offset_debug_data( + VL53L1_offset_debug_data_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + + + + + + char pre_text[VL53L1_MAX_STRING_LENGTH]; + char *ppre_text = &(pre_text[0]); + + sprintf(ppre_text, "%scustomer.", pprefix); + VL53L1_print_customer_nvm_managed( + &(pdata->customer), + ppre_text, trace_flags); + + sprintf(ppre_text, "%sfmt_dmax_cal.", pprefix); + VL53L1_print_dmax_calibration_data( + &(pdata->fmt_dmax_cal), + ppre_text, trace_flags); + + sprintf(ppre_text, "%scust_dmax_cal.", pprefix); + VL53L1_print_dmax_calibration_data( + &(pdata->cust_dmax_cal), + ppre_text, trace_flags); + + sprintf(ppre_text, "%sadd_off_cal_data.", pprefix); + VL53L1_print_additional_offset_cal_data( + &(pdata->add_off_cal_data), + ppre_text, trace_flags); + + sprintf(ppre_text, "%soffset_results.", pprefix); + VL53L1_print_offset_range_results( + &(pdata->offset_results), + ppre_text, trace_flags); +} + + +void VL53L1_print_zone_config( + VL53L1_zone_config_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + + + + + + + char pre_text[VL53L1_MAX_STRING_LENGTH]; + char *ppre_text = &(pre_text[0]); + + uint8_t i = 0; + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "max_zones", + pdata->max_zones); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "active_zones", + pdata->active_zones); + + for (i = 0; i < pdata->active_zones; i++) { + sprintf(ppre_text, "%suser_zones[%u].", pprefix, i); + VL53L1_print_user_zone( + &pdata->user_zones[i], + ppre_text, + trace_flags); + } +} + + +void VL53L1_print_optical_centre( + VL53L1_optical_centre_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + + + + + + char fp_text[VL53L1_MAX_STRING_LENGTH]; + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->x_centre, + 4, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "x_centre", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->y_centre, + 4, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "y_centre", + fp_text); +} + + +void VL53L1_print_user_zone( + VL53L1_user_zone_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + + + + + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "x_centre", + pdata->x_centre); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "y_centre", + pdata->y_centre); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "width", + pdata->width); + + trace_print(VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "height", + pdata->height); +} + + +void VL53L1_print_spad_rate_data( + VL53L1_spad_rate_data_t *pspad_rates, + char *pprefix, + uint32_t trace_flags) +{ + + + + + + + uint16_t spad_no = 0; + uint8_t row = 0; + uint8_t col = 0; + + char fp_text[VL53L1_MAX_STRING_LENGTH]; + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%8s,%4s,%4s, %s\n", + pprefix, + "spad_no", + "row", + "col", + "peak_rate_mcps"); + + for (spad_no = 0; spad_no < pspad_rates->no_of_values; spad_no++) { + + + + VL53L1_decode_row_col( + (uint8_t)spad_no, + &row, + &col); + + + + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pspad_rates->rate_data[spad_no], + pspad_rates->fractional_bits, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + + + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%8u,%4u,%4u, %s\n", + pprefix, + spad_no, + row, + col, + fp_text); + } +} + + +void VL53L1_print_spad_rate_map( + VL53L1_spad_rate_data_t *pspad_rates, + char *pprefix, + uint32_t trace_flags) +{ + + + + + + + uint8_t spad_no = 0; + uint8_t row = 0; + uint8_t col = 0; + + char fp_text[VL53L1_MAX_STRING_LENGTH]; + + + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%4s", + pprefix, + " "); + + for (col = 0; col < VL53L1_SPAD_ARRAY_WIDTH; col++) + trace_print( + VL53L1_TRACE_LEVEL_INFO, + ",%8u", + col); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "\n"); + + + + + for (row = 0; row < VL53L1_SPAD_ARRAY_HEIGHT; row++) { + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%4u", + pprefix, + row); + + for (col = 0; col < VL53L1_SPAD_ARRAY_HEIGHT; col++) { + + + + + VL53L1_encode_row_col( + row, + col, + &spad_no); + + + + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pspad_rates->rate_data[spad_no], + pspad_rates->fractional_bits, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + + + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + ",%8s", + fp_text); + } + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "\n"); + } +} + + +#endif + + + diff --git a/drivers/input/misc/vl53L1/kona/src/vl53l1_api_preset_modes.c b/drivers/input/misc/vl53L1/kona/src/vl53l1_api_preset_modes.c new file mode 100644 index 000000000000..224c82924f80 --- /dev/null +++ b/drivers/input/misc/vl53L1/kona/src/vl53l1_api_preset_modes.c @@ -0,0 +1,4939 @@ + +/******************************************************************************* + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#include "vl53l1_ll_def.h" +#include "vl53l1_platform_log.h" +#include "vl53l1_register_structs.h" +#include "vl53l1_register_settings.h" +#include "vl53l1_hist_structs.h" +#include "vl53l1_zone_presets.h" +#include "vl53l1_core.h" +#include "vl53l1_api_preset_modes.h" +#include "vl53l1_tuning_parm_defaults.h" + + +#define LOG_FUNCTION_START(fmt, ...) \ + _LOG_FUNCTION_START(VL53L1_TRACE_MODULE_API, fmt, ##__VA_ARGS__) +#define LOG_FUNCTION_END(status, ...) \ + _LOG_FUNCTION_END(VL53L1_TRACE_MODULE_API, status, ##__VA_ARGS__) +#define LOG_FUNCTION_END_FMT(status, fmt, ...) \ + _LOG_FUNCTION_END_FMT(VL53L1_TRACE_MODULE_API,\ + status, fmt, ##__VA_ARGS__) + + +VL53L1_Error VL53L1_init_refspadchar_config_struct( + VL53L1_refspadchar_config_t *pdata) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + + + + + + + + pdata->device_test_mode = + VL53L1_TUNINGPARM_REFSPADCHAR_DEVICE_TEST_MODE_DEFAULT; + pdata->VL53L1_p_009 = + VL53L1_TUNINGPARM_REFSPADCHAR_VCSEL_PERIOD_DEFAULT; + pdata->timeout_us = + VL53L1_TUNINGPARM_REFSPADCHAR_PHASECAL_TIMEOUT_US_DEFAULT; + pdata->target_count_rate_mcps = + VL53L1_TUNINGPARM_REFSPADCHAR_TARGET_COUNT_RATE_MCPS_DEFAULT; + pdata->min_count_rate_limit_mcps = + VL53L1_TUNINGPARM_REFSPADCHAR_MIN_COUNTRATE_LIMIT_MCPS_DEFAULT; + pdata->max_count_rate_limit_mcps = + VL53L1_TUNINGPARM_REFSPADCHAR_MAX_COUNTRATE_LIMIT_MCPS_DEFAULT; + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_init_ssc_config_struct( + VL53L1_ssc_config_t *pdata) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + + + + + pdata->array_select = VL53L1_DEVICESSCARRAY_RTN; + + + + pdata->VL53L1_p_009 = + VL53L1_TUNINGPARM_SPADMAP_VCSEL_PERIOD_DEFAULT; + + + + pdata->vcsel_start = + VL53L1_TUNINGPARM_SPADMAP_VCSEL_START_DEFAULT; + + + + pdata->vcsel_width = 0x02; + + + + pdata->timeout_us = 36000; + + + + + + + pdata->rate_limit_mcps = + VL53L1_TUNINGPARM_SPADMAP_RATE_LIMIT_MCPS_DEFAULT; + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_init_xtalk_config_struct( + VL53L1_customer_nvm_managed_t *pnvm, + VL53L1_xtalk_config_t *pdata) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + + + + + + + + + + + + + pdata->algo__crosstalk_compensation_plane_offset_kcps = + pnvm->algo__crosstalk_compensation_plane_offset_kcps; + pdata->algo__crosstalk_compensation_x_plane_gradient_kcps = + pnvm->algo__crosstalk_compensation_x_plane_gradient_kcps; + pdata->algo__crosstalk_compensation_y_plane_gradient_kcps = + pnvm->algo__crosstalk_compensation_y_plane_gradient_kcps; + + + + + pdata->nvm_default__crosstalk_compensation_plane_offset_kcps = + (uint32_t)pnvm->algo__crosstalk_compensation_plane_offset_kcps; + pdata->nvm_default__crosstalk_compensation_x_plane_gradient_kcps = + pnvm->algo__crosstalk_compensation_x_plane_gradient_kcps; + pdata->nvm_default__crosstalk_compensation_y_plane_gradient_kcps = + pnvm->algo__crosstalk_compensation_y_plane_gradient_kcps; + + pdata->histogram_mode_crosstalk_margin_kcps = + VL53L1_TUNINGPARM_HIST_XTALK_MARGIN_KCPS_DEFAULT; + pdata->lite_mode_crosstalk_margin_kcps = + VL53L1_TUNINGPARM_LITE_XTALK_MARGIN_KCPS_DEFAULT; + + + + + pdata->crosstalk_range_ignore_threshold_mult = + VL53L1_TUNINGPARM_LITE_RIT_MULT_DEFAULT; + + if ((pdata->algo__crosstalk_compensation_plane_offset_kcps == 0x00) + && (pdata->algo__crosstalk_compensation_x_plane_gradient_kcps + == 0x00) + && (pdata->algo__crosstalk_compensation_y_plane_gradient_kcps + == 0x00)) + pdata->global_crosstalk_compensation_enable = 0x00; + else + pdata->global_crosstalk_compensation_enable = 0x01; + + + if ((status == VL53L1_ERROR_NONE) && + (pdata->global_crosstalk_compensation_enable == 0x01)) { + pdata->crosstalk_range_ignore_threshold_rate_mcps = + VL53L1_calc_range_ignore_threshold( + pdata->algo__crosstalk_compensation_plane_offset_kcps, + pdata->algo__crosstalk_compensation_x_plane_gradient_kcps, + pdata->algo__crosstalk_compensation_y_plane_gradient_kcps, + pdata->crosstalk_range_ignore_threshold_mult); + } else { + pdata->crosstalk_range_ignore_threshold_rate_mcps = 0; + } + + + + + + + + pdata->algo__crosstalk_detect_min_valid_range_mm = + VL53L1_TUNINGPARM_XTALK_DETECT_MIN_VALID_RANGE_MM_DEFAULT; + pdata->algo__crosstalk_detect_max_valid_range_mm = + VL53L1_TUNINGPARM_XTALK_DETECT_MAX_VALID_RANGE_MM_DEFAULT; + pdata->algo__crosstalk_detect_max_valid_rate_kcps = + VL53L1_TUNINGPARM_XTALK_DETECT_MAX_VALID_RATE_KCPS_DEFAULT; + pdata->algo__crosstalk_detect_max_sigma_mm = + VL53L1_TUNINGPARM_XTALK_DETECT_MAX_SIGMA_MM_DEFAULT; + + LOG_FUNCTION_END(status); + + return status; +} + +VL53L1_Error VL53L1_init_xtalk_extract_config_struct( + VL53L1_xtalkextract_config_t *pdata) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + pdata->dss_config__target_total_rate_mcps = + VL53L1_TUNINGPARM_XTALK_EXTRACT_DSS_RATE_MCPS_DEFAULT; + + + pdata->mm_config_timeout_us = + VL53L1_TUNINGPARM_XTALK_EXTRACT_DSS_TIMEOUT_US_DEFAULT; + + + pdata->num_of_samples = + VL53L1_TUNINGPARM_XTALK_EXTRACT_NUM_OF_SAMPLES_DEFAULT; + + pdata->phasecal_config_timeout_us = + VL53L1_TUNINGPARM_XTALK_EXTRACT_PHASECAL_TIMEOUT_US_DEFAULT; + + + pdata->range_config_timeout_us = + VL53L1_TUNINGPARM_XTALK_EXTRACT_BIN_TIMEOUT_US_DEFAULT; + + + + + + + pdata->algo__crosstalk_extract_min_valid_range_mm = + VL53L1_TUNINGPARM_XTALK_EXTRACT_MIN_FILTER_THRESH_MM_DEFAULT; + pdata->algo__crosstalk_extract_max_valid_range_mm = + VL53L1_TUNINGPARM_XTALK_EXTRACT_MAX_FILTER_THRESH_MM_DEFAULT; + pdata->algo__crosstalk_extract_max_valid_rate_kcps = + VL53L1_TUNINGPARM_XTALK_EXTRACT_MAX_VALID_RATE_KCPS_DEFAULT; + pdata->algo__crosstalk_extract_max_sigma_mm = + VL53L1_TUNINGPARM_XTALK_EXTRACT_SIGMA_THRESHOLD_MM_DEFAULT; + + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_init_offset_cal_config_struct( + VL53L1_offsetcal_config_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + pdata->dss_config__target_total_rate_mcps = + VL53L1_TUNINGPARM_OFFSET_CAL_DSS_RATE_MCPS_DEFAULT; + + + pdata->phasecal_config_timeout_us = + VL53L1_TUNINGPARM_OFFSET_CAL_PHASECAL_TIMEOUT_US_DEFAULT; + + + pdata->range_config_timeout_us = + VL53L1_TUNINGPARM_OFFSET_CAL_RANGE_TIMEOUT_US_DEFAULT; + + + pdata->mm_config_timeout_us = + VL53L1_TUNINGPARM_OFFSET_CAL_MM_TIMEOUT_US_DEFAULT; + + + + + + + pdata->pre_num_of_samples = + VL53L1_TUNINGPARM_OFFSET_CAL_PRE_SAMPLES_DEFAULT; + pdata->mm1_num_of_samples = + VL53L1_TUNINGPARM_OFFSET_CAL_MM1_SAMPLES_DEFAULT; + pdata->mm2_num_of_samples = + VL53L1_TUNINGPARM_OFFSET_CAL_MM2_SAMPLES_DEFAULT; + + LOG_FUNCTION_END(status); + + return status; +} + +VL53L1_Error VL53L1_init_zone_cal_config_struct( + VL53L1_zonecal_config_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + pdata->dss_config__target_total_rate_mcps = + VL53L1_TUNINGPARM_ZONE_CAL_DSS_RATE_MCPS_DEFAULT; + + + pdata->phasecal_config_timeout_us = + VL53L1_TUNINGPARM_ZONE_CAL_PHASECAL_TIMEOUT_US_DEFAULT; + + + pdata->range_config_timeout_us = + VL53L1_TUNINGPARM_ZONE_CAL_RANGE_TIMEOUT_US_DEFAULT; + + + pdata->mm_config_timeout_us = + VL53L1_TUNINGPARM_ZONE_CAL_DSS_TIMEOUT_US_DEFAULT; + + + + + + + pdata->phasecal_num_of_samples = + VL53L1_TUNINGPARM_ZONE_CAL_PHASECAL_NUM_SAMPLES_DEFAULT; + pdata->zone_num_of_samples = + VL53L1_TUNINGPARM_ZONE_CAL_ZONE_NUM_SAMPLES_DEFAULT; + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_init_hist_post_process_config_struct( + uint8_t xtalk_compensation_enable, + VL53L1_hist_post_process_config_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + + + pdata->hist_algo_select = + VL53L1_TUNINGPARM_HIST_ALGO_SELECT_DEFAULT; + + + + + pdata->hist_target_order = + VL53L1_TUNINGPARM_HIST_TARGET_ORDER_DEFAULT; + + + + + pdata->filter_woi0 = + VL53L1_TUNINGPARM_HIST_FILTER_WOI_0_DEFAULT; + + pdata->filter_woi1 = + VL53L1_TUNINGPARM_HIST_FILTER_WOI_1_DEFAULT; + + + + + pdata->hist_amb_est_method = + VL53L1_TUNINGPARM_HIST_AMB_EST_METHOD_DEFAULT; + + pdata->ambient_thresh_sigma0 = + VL53L1_TUNINGPARM_HIST_AMB_THRESH_SIGMA_0_DEFAULT; + + pdata->ambient_thresh_sigma1 = + VL53L1_TUNINGPARM_HIST_AMB_THRESH_SIGMA_1_DEFAULT; + + + + + pdata->ambient_thresh_events_scaler = + VL53L1_TUNINGPARM_HIST_AMB_EVENTS_SCALER_DEFAULT; + + + + pdata->min_ambient_thresh_events = + VL53L1_TUNINGPARM_HIST_MIN_AMB_THRESH_EVENTS_DEFAULT; + + + pdata->noise_threshold = + VL53L1_TUNINGPARM_HIST_NOISE_THRESHOLD_DEFAULT; + + + pdata->signal_total_events_limit = + VL53L1_TUNINGPARM_HIST_SIGNAL_TOTAL_EVENTS_LIMIT_DEFAULT; + + pdata->sigma_estimator__sigma_ref_mm = + VL53L1_TUNINGPARM_HIST_SIGMA_EST_REF_MM_DEFAULT; + + + + + + + + + + + + + + + pdata->sigma_thresh = + VL53L1_TUNINGPARM_HIST_SIGMA_THRESH_MM_DEFAULT; + + pdata->range_offset_mm = 0; + + + pdata->gain_factor = + VL53L1_TUNINGPARM_HIST_GAIN_FACTOR_DEFAULT; + + + + + + + + + + + + + + + + pdata->valid_phase_low = 0x08; + pdata->valid_phase_high = 0x88; + + + + + + + + + + pdata->algo__consistency_check__phase_tolerance = + VL53L1_TUNINGPARM_CONSISTENCY_HIST_PHASE_TOLERANCE_DEFAULT; + + + + + + + + + + pdata->algo__consistency_check__event_sigma = + VL53L1_TUNINGPARM_CONSISTENCY_HIST_EVENT_SIGMA_DEFAULT; + + + + pdata->algo__consistency_check__event_min_spad_count = + VL53L1_TUNINGPARM_CONSISTENCY_HIST_EVENT_SIGMA_MIN_SPAD_LIMIT_DEFAULT; + + + + + + pdata->algo__consistency_check__min_max_tolerance = + VL53L1_TUNINGPARM_CONSISTENCY_HIST_MIN_MAX_TOLERANCE_MM_DEFAULT; + + + + pdata->algo__crosstalk_compensation_enable = xtalk_compensation_enable; + + + + + + + + + + + + pdata->algo__crosstalk_detect_min_valid_range_mm = + VL53L1_TUNINGPARM_XTALK_DETECT_MIN_VALID_RANGE_MM_DEFAULT; + pdata->algo__crosstalk_detect_max_valid_range_mm = + VL53L1_TUNINGPARM_XTALK_DETECT_MAX_VALID_RANGE_MM_DEFAULT; + pdata->algo__crosstalk_detect_max_valid_rate_kcps = + VL53L1_TUNINGPARM_XTALK_DETECT_MAX_VALID_RATE_KCPS_DEFAULT; + pdata->algo__crosstalk_detect_max_sigma_mm = + VL53L1_TUNINGPARM_XTALK_DETECT_MAX_SIGMA_MM_DEFAULT; + + + + + + + + + + + + + + pdata->algo__crosstalk_detect_event_sigma = + VL53L1_TUNINGPARM_XTALK_DETECT_EVENT_SIGMA_DEFAULT; + + + + + + pdata->algo__crosstalk_detect_min_max_tolerance = + VL53L1_TUNINGPARM_XTALK_DETECT_MIN_MAX_TOLERANCE_DEFAULT; + + + + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_init_dmax_calibration_data_struct( + VL53L1_dmax_calibration_data_t *pdata) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + + + pdata->ref__actual_effective_spads = 0x5F2D; + + + pdata->ref__peak_signal_count_rate_mcps = 0x0844; + + + pdata->ref__distance_mm = 0x08A5; + + + + + pdata->ref_reflectance_pc = 0x0014; + + + + pdata->coverglass_transmission = 0x0100; + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_init_tuning_parm_storage_struct( + VL53L1_tuning_parm_storage_t *pdata) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + + + + + pdata->tp_tuning_parm_version = + VL53L1_TUNINGPARM_VERSION_DEFAULT; + pdata->tp_tuning_parm_key_table_version = + VL53L1_TUNINGPARM_KEY_TABLE_VERSION_DEFAULT; + pdata->tp_tuning_parm_lld_version = + VL53L1_TUNINGPARM_LLD_VERSION_DEFAULT; + pdata->tp_init_phase_rtn_lite_long = + VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_LITE_LONG_RANGE_DEFAULT; + pdata->tp_init_phase_rtn_lite_med = + VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_LITE_MED_RANGE_DEFAULT; + pdata->tp_init_phase_rtn_lite_short = + VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_LITE_SHORT_RANGE_DEFAULT; + pdata->tp_init_phase_ref_lite_long = + VL53L1_TUNINGPARM_INITIAL_PHASE_REF_LITE_LONG_RANGE_DEFAULT; + pdata->tp_init_phase_ref_lite_med = + VL53L1_TUNINGPARM_INITIAL_PHASE_REF_LITE_MED_RANGE_DEFAULT; + pdata->tp_init_phase_ref_lite_short = + VL53L1_TUNINGPARM_INITIAL_PHASE_REF_LITE_SHORT_RANGE_DEFAULT; + pdata->tp_init_phase_rtn_hist_long = + VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_HISTO_LONG_RANGE_DEFAULT; + pdata->tp_init_phase_rtn_hist_med = + VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_HISTO_MED_RANGE_DEFAULT; + pdata->tp_init_phase_rtn_hist_short = + VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_HISTO_SHORT_RANGE_DEFAULT; + pdata->tp_init_phase_ref_hist_long = + VL53L1_TUNINGPARM_INITIAL_PHASE_REF_HISTO_LONG_RANGE_DEFAULT; + pdata->tp_init_phase_ref_hist_med = + VL53L1_TUNINGPARM_INITIAL_PHASE_REF_HISTO_MED_RANGE_DEFAULT; + pdata->tp_init_phase_ref_hist_short = + VL53L1_TUNINGPARM_INITIAL_PHASE_REF_HISTO_SHORT_RANGE_DEFAULT; + pdata->tp_consistency_lite_phase_tolerance = + VL53L1_TUNINGPARM_CONSISTENCY_LITE_PHASE_TOLERANCE_DEFAULT; + pdata->tp_phasecal_target = + VL53L1_TUNINGPARM_PHASECAL_TARGET_DEFAULT; + pdata->tp_cal_repeat_rate = + VL53L1_TUNINGPARM_LITE_CAL_REPEAT_RATE_DEFAULT; + pdata->tp_lite_min_clip = + VL53L1_TUNINGPARM_LITE_MIN_CLIP_MM_DEFAULT; + pdata->tp_lite_long_sigma_thresh_mm = + VL53L1_TUNINGPARM_LITE_LONG_SIGMA_THRESH_MM_DEFAULT; + pdata->tp_lite_med_sigma_thresh_mm = + VL53L1_TUNINGPARM_LITE_MED_SIGMA_THRESH_MM_DEFAULT; + pdata->tp_lite_short_sigma_thresh_mm = + VL53L1_TUNINGPARM_LITE_SHORT_SIGMA_THRESH_MM_DEFAULT; + pdata->tp_lite_long_min_count_rate_rtn_mcps = + VL53L1_TUNINGPARM_LITE_LONG_MIN_COUNT_RATE_RTN_MCPS_DEFAULT; + pdata->tp_lite_med_min_count_rate_rtn_mcps = + VL53L1_TUNINGPARM_LITE_MED_MIN_COUNT_RATE_RTN_MCPS_DEFAULT; + pdata->tp_lite_short_min_count_rate_rtn_mcps = + VL53L1_TUNINGPARM_LITE_SHORT_MIN_COUNT_RATE_RTN_MCPS_DEFAULT; + pdata->tp_lite_sigma_est_pulse_width_ns = + VL53L1_TUNINGPARM_LITE_SIGMA_EST_PULSE_WIDTH_DEFAULT; + pdata->tp_lite_sigma_est_amb_width_ns = + VL53L1_TUNINGPARM_LITE_SIGMA_EST_AMB_WIDTH_NS_DEFAULT; + pdata->tp_lite_sigma_ref_mm = + VL53L1_TUNINGPARM_LITE_SIGMA_REF_MM_DEFAULT; + pdata->tp_lite_seed_cfg = + VL53L1_TUNINGPARM_LITE_SEED_CONFIG_DEFAULT; + pdata->tp_timed_seed_cfg = + VL53L1_TUNINGPARM_TIMED_SEED_CONFIG_DEFAULT; + pdata->tp_lite_quantifier = + VL53L1_TUNINGPARM_LITE_QUANTIFIER_DEFAULT; + pdata->tp_lite_first_order_select = + VL53L1_TUNINGPARM_LITE_FIRST_ORDER_SELECT_DEFAULT; + + + + + + + pdata->tp_dss_target_lite_mcps = + VL53L1_TUNINGPARM_LITE_DSS_CONFIG_TARGET_TOTAL_RATE_MCPS_DEFAULT; + pdata->tp_dss_target_histo_mcps = + VL53L1_TUNINGPARM_RANGING_DSS_CONFIG_TARGET_TOTAL_RATE_MCPS_DEFAULT; + pdata->tp_dss_target_histo_mz_mcps = + VL53L1_TUNINGPARM_MZ_DSS_CONFIG_TARGET_TOTAL_RATE_MCPS_DEFAULT; + pdata->tp_dss_target_timed_mcps = + VL53L1_TUNINGPARM_TIMED_DSS_CONFIG_TARGET_TOTAL_RATE_MCPS_DEFAULT; + pdata->tp_phasecal_timeout_lite_us = + VL53L1_TUNINGPARM_LITE_PHASECAL_CONFIG_TIMEOUT_US_DEFAULT; + pdata->tp_phasecal_timeout_hist_long_us = + VL53L1_TUNINGPARM_RANGING_LONG_PHASECAL_CONFIG_TIMEOUT_US_DEFAULT; + pdata->tp_phasecal_timeout_hist_med_us = + VL53L1_TUNINGPARM_RANGING_MED_PHASECAL_CONFIG_TIMEOUT_US_DEFAULT; + pdata->tp_phasecal_timeout_hist_short_us = + VL53L1_TUNINGPARM_RANGING_SHORT_PHASECAL_CONFIG_TIMEOUT_US_DEFAULT; + pdata->tp_phasecal_timeout_mz_long_us = + VL53L1_TUNINGPARM_MZ_LONG_PHASECAL_CONFIG_TIMEOUT_US_DEFAULT; + pdata->tp_phasecal_timeout_mz_med_us = + VL53L1_TUNINGPARM_MZ_MED_PHASECAL_CONFIG_TIMEOUT_US_DEFAULT; + pdata->tp_phasecal_timeout_mz_short_us = + VL53L1_TUNINGPARM_MZ_SHORT_PHASECAL_CONFIG_TIMEOUT_US_DEFAULT; + pdata->tp_phasecal_timeout_timed_us = + VL53L1_TUNINGPARM_TIMED_PHASECAL_CONFIG_TIMEOUT_US_DEFAULT; + pdata->tp_mm_timeout_lite_us = + VL53L1_TUNINGPARM_LITE_MM_CONFIG_TIMEOUT_US_DEFAULT; + pdata->tp_mm_timeout_histo_us = + VL53L1_TUNINGPARM_RANGING_MM_CONFIG_TIMEOUT_US_DEFAULT; + pdata->tp_mm_timeout_mz_us = + VL53L1_TUNINGPARM_MZ_MM_CONFIG_TIMEOUT_US_DEFAULT; + pdata->tp_mm_timeout_timed_us = + VL53L1_TUNINGPARM_TIMED_MM_CONFIG_TIMEOUT_US_DEFAULT; + pdata->tp_range_timeout_lite_us = + VL53L1_TUNINGPARM_LITE_RANGE_CONFIG_TIMEOUT_US_DEFAULT; + pdata->tp_range_timeout_histo_us = + VL53L1_TUNINGPARM_RANGING_RANGE_CONFIG_TIMEOUT_US_DEFAULT; + pdata->tp_range_timeout_mz_us = + VL53L1_TUNINGPARM_MZ_RANGE_CONFIG_TIMEOUT_US_DEFAULT; + pdata->tp_range_timeout_timed_us = + VL53L1_TUNINGPARM_TIMED_RANGE_CONFIG_TIMEOUT_US_DEFAULT; + + + + + pdata->tp_mm_timeout_lpa_us = + VL53L1_TUNINGPARM_LOWPOWERAUTO_MM_CONFIG_TIMEOUT_US_DEFAULT; + pdata->tp_range_timeout_lpa_us = + VL53L1_TUNINGPARM_LOWPOWERAUTO_RANGE_CONFIG_TIMEOUT_US_DEFAULT; + + pdata->tp_dss_target_very_short_mcps = + VL53L1_TUNINGPARM_VERY_SHORT_DSS_RATE_MCPS_DEFAULT; + + pdata->tp_phasecal_patch_power = + VL53L1_TUNINGPARM_PHASECAL_PATCH_POWER_DEFAULT; + + pdata->tp_hist_merge = + VL53L1_TUNINGPARM_HIST_MERGE_DEFAULT; + + pdata->tp_reset_merge_threshold = + VL53L1_TUNINGPARM_RESET_MERGE_THRESHOLD_DEFAULT; + + pdata->tp_hist_merge_max_size = + VL53L1_TUNINGPARM_HIST_MERGE_MAX_SIZE_DEFAULT; + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_init_hist_gen3_dmax_config_struct( + VL53L1_hist_gen3_dmax_config_t *pdata) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + pdata->dss_config__target_total_rate_mcps = 0x1400; + pdata->dss_config__aperture_attenuation = 0x38; + + pdata->signal_thresh_sigma = + VL53L1_TUNINGPARM_DMAX_CFG_SIGNAL_THRESH_SIGMA_DEFAULT; + pdata->ambient_thresh_sigma = 0x70; + pdata->min_ambient_thresh_events = 16; + pdata->signal_total_events_limit = 100; + pdata->max_effective_spads = 0xFFFF; + + + + + + + + + + + + pdata->target_reflectance_for_dmax_calc[0] = + VL53L1_TUNINGPARM_DMAX_CFG_REFLECTANCE_ARRAY_0_DEFAULT; + pdata->target_reflectance_for_dmax_calc[1] = + VL53L1_TUNINGPARM_DMAX_CFG_REFLECTANCE_ARRAY_1_DEFAULT; + pdata->target_reflectance_for_dmax_calc[2] = + VL53L1_TUNINGPARM_DMAX_CFG_REFLECTANCE_ARRAY_2_DEFAULT; + pdata->target_reflectance_for_dmax_calc[3] = + VL53L1_TUNINGPARM_DMAX_CFG_REFLECTANCE_ARRAY_3_DEFAULT; + pdata->target_reflectance_for_dmax_calc[4] = + VL53L1_TUNINGPARM_DMAX_CFG_REFLECTANCE_ARRAY_4_DEFAULT; + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_preset_mode_standard_ranging( + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + + + pstatic->dss_config__target_total_rate_mcps = 0x0A00; + pstatic->debug__ctrl = 0x00; + pstatic->test_mode__ctrl = 0x00; + pstatic->clk_gating__ctrl = 0x00; + pstatic->nvm_bist__ctrl = 0x00; + pstatic->nvm_bist__num_nvm_words = 0x00; + pstatic->nvm_bist__start_address = 0x00; + pstatic->host_if__status = 0x00; + pstatic->pad_i2c_hv__config = 0x00; + pstatic->pad_i2c_hv__extsup_config = 0x00; + + + + + + + pstatic->gpio_hv_pad__ctrl = 0x00; + + + + + + + + + pstatic->gpio_hv_mux__ctrl = + VL53L1_DEVICEINTERRUPTPOLARITY_ACTIVE_LOW | + VL53L1_DEVICEGPIOMODE_OUTPUT_RANGE_AND_ERROR_INTERRUPTS; + + pstatic->gpio__tio_hv_status = 0x02; + pstatic->gpio__fio_hv_status = 0x00; + pstatic->ana_config__spad_sel_pswidth = 0x02; + pstatic->ana_config__vcsel_pulse_width_offset = 0x08; + pstatic->ana_config__fast_osc__config_ctrl = 0x00; + + pstatic->sigma_estimator__effective_pulse_width_ns = + ptuning_parms->tp_lite_sigma_est_pulse_width_ns; + pstatic->sigma_estimator__effective_ambient_width_ns = + ptuning_parms->tp_lite_sigma_est_amb_width_ns; + pstatic->sigma_estimator__sigma_ref_mm = + ptuning_parms->tp_lite_sigma_ref_mm; + + + pstatic->algo__crosstalk_compensation_valid_height_mm = 0x01; + pstatic->spare_host_config__static_config_spare_0 = 0x00; + pstatic->spare_host_config__static_config_spare_1 = 0x00; + + pstatic->algo__range_ignore_threshold_mcps = 0x0000; + + + + pstatic->algo__range_ignore_valid_height_mm = 0xff; + pstatic->algo__range_min_clip = + ptuning_parms->tp_lite_min_clip; + + + + + + + pstatic->algo__consistency_check__tolerance = + ptuning_parms->tp_consistency_lite_phase_tolerance; + pstatic->spare_host_config__static_config_spare_2 = 0x00; + pstatic->sd_config__reset_stages_msb = 0x00; + pstatic->sd_config__reset_stages_lsb = 0x00; + + pgeneral->gph_config__stream_count_update_value = 0x00; + pgeneral->global_config__stream_divider = 0x00; + pgeneral->system__interrupt_config_gpio = + VL53L1_INTERRUPT_CONFIG_NEW_SAMPLE_READY; + pgeneral->cal_config__vcsel_start = 0x0B; + + + + + + + + + pgeneral->cal_config__repeat_rate = + ptuning_parms->tp_cal_repeat_rate; + pgeneral->global_config__vcsel_width = 0x02; + + + pgeneral->phasecal_config__timeout_macrop = 0x0D; + + + pgeneral->phasecal_config__target = + ptuning_parms->tp_phasecal_target; + pgeneral->phasecal_config__override = 0x00; + pgeneral->dss_config__roi_mode_control = + VL53L1_DEVICEDSSMODE__TARGET_RATE; + + + pgeneral->system__thresh_rate_high = 0x0000; + pgeneral->system__thresh_rate_low = 0x0000; + + + pgeneral->dss_config__manual_effective_spads_select = 0x8C00; + pgeneral->dss_config__manual_block_select = 0x00; + + + + + + + + + pgeneral->dss_config__aperture_attenuation = 0x38; + pgeneral->dss_config__max_spads_limit = 0xFF; + pgeneral->dss_config__min_spads_limit = 0x01; + + + + + + + ptiming->mm_config__timeout_macrop_a_hi = 0x00; + ptiming->mm_config__timeout_macrop_a_lo = 0x1a; + ptiming->mm_config__timeout_macrop_b_hi = 0x00; + ptiming->mm_config__timeout_macrop_b_lo = 0x20; + + + ptiming->range_config__timeout_macrop_a_hi = 0x01; + ptiming->range_config__timeout_macrop_a_lo = 0xCC; + + + ptiming->range_config__vcsel_period_a = 0x0B; + + + ptiming->range_config__timeout_macrop_b_hi = 0x01; + ptiming->range_config__timeout_macrop_b_lo = 0xF5; + + + ptiming->range_config__vcsel_period_b = 0x09; + + + + + + + + ptiming->range_config__sigma_thresh = + ptuning_parms->tp_lite_med_sigma_thresh_mm; + + + + + + + ptiming->range_config__min_count_rate_rtn_limit_mcps = + ptuning_parms->tp_lite_med_min_count_rate_rtn_mcps; + + + + + + + ptiming->range_config__valid_phase_low = 0x08; + ptiming->range_config__valid_phase_high = 0x78; + ptiming->system__intermeasurement_period = 0x00000000; + ptiming->system__fractional_enable = 0x00; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + phistogram->histogram_config__low_amb_even_bin_0_1 = 0x07; + phistogram->histogram_config__low_amb_even_bin_2_3 = 0x21; + phistogram->histogram_config__low_amb_even_bin_4_5 = 0x43; + + phistogram->histogram_config__low_amb_odd_bin_0_1 = 0x10; + phistogram->histogram_config__low_amb_odd_bin_2_3 = 0x32; + phistogram->histogram_config__low_amb_odd_bin_4_5 = 0x54; + + phistogram->histogram_config__mid_amb_even_bin_0_1 = 0x07; + phistogram->histogram_config__mid_amb_even_bin_2_3 = 0x21; + phistogram->histogram_config__mid_amb_even_bin_4_5 = 0x43; + + phistogram->histogram_config__mid_amb_odd_bin_0_1 = 0x10; + phistogram->histogram_config__mid_amb_odd_bin_2 = 0x02; + phistogram->histogram_config__mid_amb_odd_bin_3_4 = 0x43; + phistogram->histogram_config__mid_amb_odd_bin_5 = 0x05; + + phistogram->histogram_config__user_bin_offset = 0x00; + + phistogram->histogram_config__high_amb_even_bin_0_1 = 0x07; + phistogram->histogram_config__high_amb_even_bin_2_3 = 0x21; + phistogram->histogram_config__high_amb_even_bin_4_5 = 0x43; + + phistogram->histogram_config__high_amb_odd_bin_0_1 = 0x10; + phistogram->histogram_config__high_amb_odd_bin_2_3 = 0x32; + phistogram->histogram_config__high_amb_odd_bin_4_5 = 0x54; + + phistogram->histogram_config__amb_thresh_low = 0xFFFF; + phistogram->histogram_config__amb_thresh_high = 0xFFFF; + + phistogram->histogram_config__spad_array_selection = 0x00; + + + + + + + + + pzone_cfg->max_zones = VL53L1_MAX_USER_ZONES; + pzone_cfg->active_zones = 0x00; + pzone_cfg->user_zones[0].height = 0x0f; + pzone_cfg->user_zones[0].width = 0x0f; + pzone_cfg->user_zones[0].x_centre = 0x08; + pzone_cfg->user_zones[0].y_centre = 0x08; + + + + + pdynamic->system__grouped_parameter_hold_0 = 0x01; + + pdynamic->system__thresh_high = 0x0000; + pdynamic->system__thresh_low = 0x0000; + pdynamic->system__enable_xtalk_per_quadrant = 0x00; + pdynamic->system__seed_config = + ptuning_parms->tp_lite_seed_cfg; + + + + pdynamic->sd_config__woi_sd0 = 0x0B; + + + pdynamic->sd_config__woi_sd1 = 0x09; + + pdynamic->sd_config__initial_phase_sd0 = + ptuning_parms->tp_init_phase_rtn_lite_med; + pdynamic->sd_config__initial_phase_sd1 = + ptuning_parms->tp_init_phase_ref_lite_med; + + pdynamic->system__grouped_parameter_hold_1 = 0x01; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pdynamic->sd_config__first_order_select = + ptuning_parms->tp_lite_first_order_select; + pdynamic->sd_config__quantifier = + ptuning_parms->tp_lite_quantifier; + + + + + + + pdynamic->roi_config__user_roi_centre_spad = 0xC7; + + + pdynamic->roi_config__user_roi_requested_global_xy_size = 0xFF; + + + pdynamic->system__sequence_config = + VL53L1_SEQUENCE_VHV_EN | + VL53L1_SEQUENCE_PHASECAL_EN | + VL53L1_SEQUENCE_DSS1_EN | + VL53L1_SEQUENCE_DSS2_EN | + VL53L1_SEQUENCE_MM2_EN | + VL53L1_SEQUENCE_RANGE_EN; + + pdynamic->system__grouped_parameter_hold = 0x02; + + + + + + psystem->system__stream_count_ctrl = 0x00; + psystem->firmware__enable = 0x01; + psystem->system__interrupt_clear = + VL53L1_CLEAR_RANGE_INT; + + psystem->system__mode_start = + VL53L1_DEVICESCHEDULERMODE_STREAMING | + VL53L1_DEVICEREADOUTMODE_SINGLE_SD | + VL53L1_DEVICEMEASUREMENTMODE_BACKTOBACK; + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_preset_mode_standard_ranging_short_range( + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + + + status = VL53L1_preset_mode_standard_ranging( + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + + if (status == VL53L1_ERROR_NONE) { + + + + + + + + + + + + + ptiming->range_config__vcsel_period_a = 0x07; + ptiming->range_config__vcsel_period_b = 0x05; + ptiming->range_config__sigma_thresh = + ptuning_parms->tp_lite_short_sigma_thresh_mm; + ptiming->range_config__min_count_rate_rtn_limit_mcps = + ptuning_parms->tp_lite_short_min_count_rate_rtn_mcps; + ptiming->range_config__valid_phase_low = 0x08; + ptiming->range_config__valid_phase_high = 0x38; + + + + + + + + pdynamic->sd_config__woi_sd0 = 0x07; + pdynamic->sd_config__woi_sd1 = 0x05; + pdynamic->sd_config__initial_phase_sd0 = + ptuning_parms->tp_init_phase_rtn_lite_short; + pdynamic->sd_config__initial_phase_sd1 = + ptuning_parms->tp_init_phase_ref_lite_short; + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_preset_mode_standard_ranging_long_range( + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + + + status = VL53L1_preset_mode_standard_ranging( + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + + if (status == VL53L1_ERROR_NONE) { + + + + + + + + + + + + + ptiming->range_config__vcsel_period_a = 0x0F; + ptiming->range_config__vcsel_period_b = 0x0D; + ptiming->range_config__sigma_thresh = + ptuning_parms->tp_lite_long_sigma_thresh_mm; + ptiming->range_config__min_count_rate_rtn_limit_mcps = + ptuning_parms->tp_lite_long_min_count_rate_rtn_mcps; + ptiming->range_config__valid_phase_low = 0x08; + ptiming->range_config__valid_phase_high = 0xB8; + + + + + + + + pdynamic->sd_config__woi_sd0 = 0x0F; + pdynamic->sd_config__woi_sd1 = 0x0D; + pdynamic->sd_config__initial_phase_sd0 = + ptuning_parms->tp_init_phase_rtn_lite_long; + pdynamic->sd_config__initial_phase_sd1 = + ptuning_parms->tp_init_phase_ref_lite_long; + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_preset_mode_standard_ranging_mm1_cal( + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + + + status = VL53L1_preset_mode_standard_ranging( + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + + if (status == VL53L1_ERROR_NONE) { + + pgeneral->dss_config__roi_mode_control = + VL53L1_DEVICEDSSMODE__REQUESTED_EFFFECTIVE_SPADS; + + pdynamic->system__sequence_config = + VL53L1_SEQUENCE_VHV_EN | + VL53L1_SEQUENCE_PHASECAL_EN | + VL53L1_SEQUENCE_DSS1_EN | + VL53L1_SEQUENCE_DSS2_EN | + VL53L1_SEQUENCE_MM1_EN; + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_preset_mode_standard_ranging_mm2_cal( + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + + + status = VL53L1_preset_mode_standard_ranging( + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + + if (status == VL53L1_ERROR_NONE) { + + pgeneral->dss_config__roi_mode_control = + VL53L1_DEVICEDSSMODE__REQUESTED_EFFFECTIVE_SPADS; + + pdynamic->system__sequence_config = + VL53L1_SEQUENCE_VHV_EN | + VL53L1_SEQUENCE_PHASECAL_EN | + VL53L1_SEQUENCE_DSS1_EN | + VL53L1_SEQUENCE_DSS2_EN | + VL53L1_SEQUENCE_MM2_EN; + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_preset_mode_timed_ranging( + + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + status = VL53L1_preset_mode_standard_ranging( + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + + if (status == VL53L1_ERROR_NONE) { + + + + + + + pdynamic->system__grouped_parameter_hold = 0x00; + + + + ptiming->range_config__timeout_macrop_a_hi = 0x00; + ptiming->range_config__timeout_macrop_a_lo = 0xB1; + + + ptiming->range_config__timeout_macrop_b_hi = 0x00; + ptiming->range_config__timeout_macrop_b_lo = 0xD4; + + + + + ptiming->system__intermeasurement_period = 0x00000600; + pdynamic->system__seed_config = + ptuning_parms->tp_timed_seed_cfg; + + + + + + + psystem->system__mode_start = + VL53L1_DEVICESCHEDULERMODE_PSEUDO_SOLO | + VL53L1_DEVICEREADOUTMODE_SINGLE_SD | + VL53L1_DEVICEMEASUREMENTMODE_TIMED; + } + + LOG_FUNCTION_END(status); + + return status; +} + +VL53L1_Error VL53L1_preset_mode_timed_ranging_short_range( + + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + status = VL53L1_preset_mode_standard_ranging_short_range( + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + + if (status == VL53L1_ERROR_NONE) { + + + + + + + pdynamic->system__grouped_parameter_hold = 0x00; + + + + + + + + ptiming->range_config__timeout_macrop_a_hi = 0x01; + ptiming->range_config__timeout_macrop_a_lo = 0x84; + + + ptiming->range_config__timeout_macrop_b_hi = 0x01; + ptiming->range_config__timeout_macrop_b_lo = 0xB1; + + ptiming->system__intermeasurement_period = 0x00000600; + pdynamic->system__seed_config = + ptuning_parms->tp_timed_seed_cfg; + + + + + + + psystem->system__mode_start = + VL53L1_DEVICESCHEDULERMODE_PSEUDO_SOLO | + VL53L1_DEVICEREADOUTMODE_SINGLE_SD | + VL53L1_DEVICEMEASUREMENTMODE_TIMED; + } + + LOG_FUNCTION_END(status); + + return status; +} + +VL53L1_Error VL53L1_preset_mode_timed_ranging_long_range( + + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + status = VL53L1_preset_mode_standard_ranging_long_range( + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + + if (status == VL53L1_ERROR_NONE) { + + + + + + + pdynamic->system__grouped_parameter_hold = 0x00; + + + + + + + + ptiming->range_config__timeout_macrop_a_hi = 0x00; + ptiming->range_config__timeout_macrop_a_lo = 0x97; + + + ptiming->range_config__timeout_macrop_b_hi = 0x00; + ptiming->range_config__timeout_macrop_b_lo = 0xB1; + + ptiming->system__intermeasurement_period = 0x00000600; + pdynamic->system__seed_config = + ptuning_parms->tp_timed_seed_cfg; + + + + + + + psystem->system__mode_start = + VL53L1_DEVICESCHEDULERMODE_PSEUDO_SOLO | + VL53L1_DEVICEREADOUTMODE_SINGLE_SD | + VL53L1_DEVICEMEASUREMENTMODE_TIMED; + } + + LOG_FUNCTION_END(status); + + return status; +} + + + +VL53L1_Error VL53L1_preset_mode_low_power_auto_ranging( + + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg, + VL53L1_low_power_auto_data_t *plpadata) +{ + + + + + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + status = VL53L1_preset_mode_timed_ranging( + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + + if (status == VL53L1_ERROR_NONE) { + status = VL53L1_config_low_power_auto_mode( + pgeneral, + pdynamic, + plpadata + ); + } + + LOG_FUNCTION_END(status); + + return status; +} + +VL53L1_Error VL53L1_preset_mode_low_power_auto_short_ranging( + + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg, + VL53L1_low_power_auto_data_t *plpadata) +{ + + + + + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + status = VL53L1_preset_mode_timed_ranging_short_range( + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + + if (status == VL53L1_ERROR_NONE) { + status = VL53L1_config_low_power_auto_mode( + pgeneral, + pdynamic, + plpadata + ); + } + + LOG_FUNCTION_END(status); + + return status; +} + +VL53L1_Error VL53L1_preset_mode_low_power_auto_long_ranging( + + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg, + VL53L1_low_power_auto_data_t *plpadata) +{ + + + + + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + status = VL53L1_preset_mode_timed_ranging_long_range( + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + + if (status == VL53L1_ERROR_NONE) { + status = VL53L1_config_low_power_auto_mode( + pgeneral, + pdynamic, + plpadata + ); + } + + LOG_FUNCTION_END(status); + + return status; +} + + + + +VL53L1_Error VL53L1_preset_mode_singleshot_ranging( + + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + status = VL53L1_preset_mode_standard_ranging( + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + + if (status == VL53L1_ERROR_NONE) { + + + + + + + pdynamic->system__grouped_parameter_hold = 0x00; + + + + + + + ptiming->range_config__timeout_macrop_a_hi = 0x00; + ptiming->range_config__timeout_macrop_a_lo = 0xB1; + + + ptiming->range_config__timeout_macrop_b_hi = 0x00; + ptiming->range_config__timeout_macrop_b_lo = 0xD4; + + pdynamic->system__seed_config = + ptuning_parms->tp_timed_seed_cfg; + + + + + + + psystem->system__mode_start = + VL53L1_DEVICESCHEDULERMODE_PSEUDO_SOLO | + VL53L1_DEVICEREADOUTMODE_SINGLE_SD | + VL53L1_DEVICEMEASUREMENTMODE_SINGLESHOT; + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_preset_mode_histogram_ranging( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + status = + VL53L1_preset_mode_standard_ranging( + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + + if (status == VL53L1_ERROR_NONE) { + + + + + + + pstatic->dss_config__target_total_rate_mcps = 0x1400; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + VL53L1_init_histogram_config_structure( + 7, 0, 1, 2, 3, 4, + 0, 1, 2, 3, 4, 5, + phistogram); + + + + + + + VL53L1_init_histogram_multizone_config_structure( + 7, 0, 1, 2, 3, 4, + 0, 1, 2, 3, 4, 5, + &(pzone_cfg->multizone_hist_cfg)); + + + + + + + + + + + ptiming->range_config__vcsel_period_a = 0x09; + ptiming->range_config__vcsel_period_b = 0x0B; + pdynamic->sd_config__woi_sd0 = 0x09; + pdynamic->sd_config__woi_sd1 = 0x0B; + + + + + + + ptiming->mm_config__timeout_macrop_a_hi = 0x00; + ptiming->mm_config__timeout_macrop_a_lo = 0x20; + ptiming->mm_config__timeout_macrop_b_hi = 0x00; + ptiming->mm_config__timeout_macrop_b_lo = 0x1A; + + + + ptiming->range_config__timeout_macrop_a_hi = 0x00; + ptiming->range_config__timeout_macrop_a_lo = 0x28; + + + + ptiming->range_config__timeout_macrop_b_hi = 0x00; + ptiming->range_config__timeout_macrop_b_lo = 0x21; + + + + pgeneral->phasecal_config__timeout_macrop = 0xF5; + + + + + + + + + phistpostprocess->valid_phase_low = 0x08; + phistpostprocess->valid_phase_high = 0x88; + + + + + VL53L1_copy_hist_cfg_to_static_cfg( + phistogram, + pstatic, + pgeneral, + ptiming, + pdynamic); + + + + + + pdynamic->system__sequence_config = + VL53L1_SEQUENCE_VHV_EN | + VL53L1_SEQUENCE_PHASECAL_EN | + VL53L1_SEQUENCE_DSS1_EN | + VL53L1_SEQUENCE_DSS2_EN | + + + + + VL53L1_SEQUENCE_RANGE_EN; + + + + + + psystem->system__mode_start = + VL53L1_DEVICESCHEDULERMODE_HISTOGRAM | + VL53L1_DEVICEREADOUTMODE_DUAL_SD | + VL53L1_DEVICEMEASUREMENTMODE_BACKTOBACK; + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_preset_mode_histogram_ranging_with_mm1( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + status = + VL53L1_preset_mode_histogram_ranging( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + + if (status == VL53L1_ERROR_NONE) { + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + VL53L1_init_histogram_config_structure( + 7, 0, 1, 2, 3, 4, + 8+0, 8+1, 8+2, 3, 4, 5, + phistogram); + + + + + + + VL53L1_init_histogram_multizone_config_structure( + 7, 0, 1, 2, 3, 4, + 8+0, 8+1, 8+2, 3, 4, 5, + &(pzone_cfg->multizone_hist_cfg)); + + + + + VL53L1_copy_hist_cfg_to_static_cfg( + phistogram, + pstatic, + pgeneral, + ptiming, + pdynamic); + + + + + pdynamic->system__sequence_config = + VL53L1_SEQUENCE_VHV_EN | + VL53L1_SEQUENCE_PHASECAL_EN | + VL53L1_SEQUENCE_DSS1_EN | + VL53L1_SEQUENCE_DSS2_EN | + VL53L1_SEQUENCE_MM1_EN | + VL53L1_SEQUENCE_RANGE_EN; + + + + + psystem->system__mode_start = + VL53L1_DEVICESCHEDULERMODE_HISTOGRAM | + VL53L1_DEVICEREADOUTMODE_DUAL_SD | + VL53L1_DEVICEMEASUREMENTMODE_BACKTOBACK; + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_preset_mode_histogram_ranging_with_mm2( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + status = + VL53L1_preset_mode_histogram_ranging_with_mm1( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + + if (status == VL53L1_ERROR_NONE) { + + + + + pdynamic->system__sequence_config = + VL53L1_SEQUENCE_VHV_EN | + VL53L1_SEQUENCE_PHASECAL_EN | + VL53L1_SEQUENCE_DSS1_EN | + VL53L1_SEQUENCE_DSS2_EN | + VL53L1_SEQUENCE_MM2_EN | + VL53L1_SEQUENCE_RANGE_EN; + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_preset_mode_histogram_ranging_mm1_cal( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + status = + VL53L1_preset_mode_histogram_ranging( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + + if (status == VL53L1_ERROR_NONE) { + + + + + + + + + + + + + + + + + VL53L1_init_histogram_config_structure( + 7, 8+0, 8+1, 8+2, 8+3, 8+4, + 8+0, 8+1, 8+2, 8+3, 8+4, 8+5, + phistogram); + + + + + + + VL53L1_init_histogram_multizone_config_structure( + 7, 8+0, 8+1, 8+2, 8+3, 8+4, + 8+0, 8+1, 8+2, 8+3, 8+4, 8+5, + &(pzone_cfg->multizone_hist_cfg)); + + + + + VL53L1_copy_hist_cfg_to_static_cfg( + phistogram, + pstatic, + pgeneral, + ptiming, + pdynamic); + + + + + pgeneral->dss_config__roi_mode_control = + VL53L1_DEVICEDSSMODE__REQUESTED_EFFFECTIVE_SPADS; + + + + + pdynamic->system__sequence_config = + VL53L1_SEQUENCE_VHV_EN | + VL53L1_SEQUENCE_PHASECAL_EN | + VL53L1_SEQUENCE_DSS1_EN | + VL53L1_SEQUENCE_DSS2_EN | + VL53L1_SEQUENCE_MM1_EN | + VL53L1_SEQUENCE_RANGE_EN; + + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_preset_mode_histogram_ranging_mm2_cal( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + status = + VL53L1_preset_mode_histogram_ranging_mm1_cal( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + if (status == VL53L1_ERROR_NONE) { + + + + + pdynamic->system__sequence_config = + VL53L1_SEQUENCE_VHV_EN | + VL53L1_SEQUENCE_PHASECAL_EN | + VL53L1_SEQUENCE_DSS1_EN | + VL53L1_SEQUENCE_DSS2_EN | + VL53L1_SEQUENCE_MM2_EN | + VL53L1_SEQUENCE_RANGE_EN; + + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_preset_mode_histogram_ranging_short_timing( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + status = + VL53L1_preset_mode_histogram_ranging( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + + if (status == VL53L1_ERROR_NONE) { + + + + + + + pstatic->dss_config__target_total_rate_mcps = 0x1400; + + + + + VL53L1_init_histogram_config_structure( + 7, 0, 1, 2, 3, 4, + 7, 0, 1, 2, 3, 4, + phistogram); + + + + + + + VL53L1_init_histogram_multizone_config_structure( + 7, 0, 1, 2, 3, 4, + 7, 0, 1, 2, 3, 4, + &(pzone_cfg->multizone_hist_cfg)); + + + + + VL53L1_copy_hist_cfg_to_static_cfg( + phistogram, + pstatic, + pgeneral, + ptiming, + pdynamic); + + + + + + + ptiming->range_config__vcsel_period_a = 0x04; + ptiming->range_config__vcsel_period_b = 0x03; + ptiming->mm_config__timeout_macrop_a_hi = 0x00; + ptiming->mm_config__timeout_macrop_a_lo = 0x42; + ptiming->mm_config__timeout_macrop_b_hi = 0x00; + ptiming->mm_config__timeout_macrop_b_lo = 0x42; + ptiming->range_config__timeout_macrop_a_hi = 0x00; + ptiming->range_config__timeout_macrop_a_lo = 0x52; + ptiming->range_config__timeout_macrop_b_hi = 0x00; + ptiming->range_config__timeout_macrop_b_lo = 0x66; + + pgeneral->cal_config__vcsel_start = 0x04; + + + + + + + + + + + pgeneral->phasecal_config__timeout_macrop = 0xa4; + + + + + pdynamic->system__sequence_config = + VL53L1_SEQUENCE_VHV_EN | + VL53L1_SEQUENCE_PHASECAL_EN | + VL53L1_SEQUENCE_DSS1_EN | + VL53L1_SEQUENCE_DSS2_EN | + + + + + VL53L1_SEQUENCE_RANGE_EN; + + + + + + psystem->system__mode_start = + VL53L1_DEVICESCHEDULERMODE_HISTOGRAM | + VL53L1_DEVICEREADOUTMODE_DUAL_SD | + VL53L1_DEVICEMEASUREMENTMODE_BACKTOBACK; + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_preset_mode_histogram_long_range( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + status = + VL53L1_preset_mode_histogram_ranging( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + + + + + + + + + if (status == VL53L1_ERROR_NONE) { + + + + + + + + + + VL53L1_init_histogram_config_structure( + 7, 0, 1, 2, 3, 4, + 0, 1, 2, 3, 4, 5, + phistogram); + + + + + + + VL53L1_init_histogram_multizone_config_structure( + 7, 0, 1, 2, 3, 4, + + 0, 1, 2, 3, 4, 5, + + &(pzone_cfg->multizone_hist_cfg)); + + + + + VL53L1_copy_hist_cfg_to_static_cfg( + phistogram, + pstatic, + pgeneral, + ptiming, + pdynamic); + + + + + + + ptiming->range_config__vcsel_period_a = 0x09; + ptiming->range_config__vcsel_period_b = 0x0b; + + + + + + + ptiming->mm_config__timeout_macrop_a_hi = 0x00; + ptiming->mm_config__timeout_macrop_a_lo = 0x21; + ptiming->mm_config__timeout_macrop_b_hi = 0x00; + ptiming->mm_config__timeout_macrop_b_lo = 0x1b; + + + + + ptiming->range_config__timeout_macrop_a_hi = 0x00; + ptiming->range_config__timeout_macrop_a_lo = 0x29; + ptiming->range_config__timeout_macrop_b_hi = 0x00; + ptiming->range_config__timeout_macrop_b_lo = 0x22; + + + + + pgeneral->cal_config__vcsel_start = 0x09; + + + + + + + + + + + + + + + pgeneral->phasecal_config__timeout_macrop = 0xF5; + + + + + pdynamic->sd_config__woi_sd0 = 0x09; + pdynamic->sd_config__woi_sd1 = 0x0B; + pdynamic->sd_config__initial_phase_sd0 = + ptuning_parms->tp_init_phase_rtn_hist_long; + pdynamic->sd_config__initial_phase_sd1 = + ptuning_parms->tp_init_phase_ref_hist_long; + + + + + + + + + phistpostprocess->valid_phase_low = 0x08; + phistpostprocess->valid_phase_high = 0x88; + + pdynamic->system__sequence_config = + VL53L1_SEQUENCE_VHV_EN | + VL53L1_SEQUENCE_PHASECAL_EN | + VL53L1_SEQUENCE_DSS1_EN | + VL53L1_SEQUENCE_DSS2_EN | + VL53L1_SEQUENCE_RANGE_EN; + + + + + + psystem->system__mode_start = + VL53L1_DEVICESCHEDULERMODE_HISTOGRAM | + VL53L1_DEVICEREADOUTMODE_DUAL_SD | + VL53L1_DEVICEMEASUREMENTMODE_BACKTOBACK; + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_preset_mode_histogram_long_range_mm1( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + status = + VL53L1_preset_mode_histogram_long_range( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + + + + + + + + + if (status == VL53L1_ERROR_NONE) { + + + + + + + + + + VL53L1_init_histogram_config_structure( + 7, 0, 1, 2, 3, 4, + 8+0, 8+1, 8+2, 3, 4, 5, + phistogram); + + + + + + + VL53L1_init_histogram_multizone_config_structure( + 7, 0, 1, 2, 3, 4, + 8+0, 8+1, 8+2, 3, 4, 5, + &(pzone_cfg->multizone_hist_cfg)); + + + + + VL53L1_copy_hist_cfg_to_static_cfg( + phistogram, + pstatic, + pgeneral, + ptiming, + pdynamic); + + + + + pdynamic->system__sequence_config = + VL53L1_SEQUENCE_VHV_EN | + VL53L1_SEQUENCE_PHASECAL_EN | + VL53L1_SEQUENCE_DSS1_EN | + VL53L1_SEQUENCE_DSS2_EN | + VL53L1_SEQUENCE_MM1_EN | + VL53L1_SEQUENCE_RANGE_EN; + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_preset_mode_histogram_long_range_mm2( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + status = + VL53L1_preset_mode_histogram_long_range_mm1( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + + if (status == VL53L1_ERROR_NONE) { + + + + + pdynamic->system__sequence_config = + VL53L1_SEQUENCE_VHV_EN | + VL53L1_SEQUENCE_PHASECAL_EN | + VL53L1_SEQUENCE_DSS1_EN | + VL53L1_SEQUENCE_DSS2_EN | + VL53L1_SEQUENCE_MM2_EN | + VL53L1_SEQUENCE_RANGE_EN; + } + + LOG_FUNCTION_END(status); + + return status; +} + + + +VL53L1_Error VL53L1_preset_mode_histogram_medium_range( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + status = + VL53L1_preset_mode_histogram_ranging( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + + + + + + + + + if (status == VL53L1_ERROR_NONE) { + + + + + + + + + + VL53L1_init_histogram_config_structure( + 7, 0, 1, 1, 2, 2, + 0, 1, 2, 1, 2, 3, + phistogram); + + + + + + + VL53L1_init_histogram_multizone_config_structure( + 7, 0, 1, 1, 2, 2, + 0, 1, 2, 1, 2, 3, + &(pzone_cfg->multizone_hist_cfg)); + + + + + VL53L1_copy_hist_cfg_to_static_cfg( + phistogram, + pstatic, + pgeneral, + ptiming, + pdynamic); + + + + + + + ptiming->range_config__vcsel_period_a = 0x05; + ptiming->range_config__vcsel_period_b = 0x07; + + + + + + + ptiming->mm_config__timeout_macrop_a_hi = 0x00; + ptiming->mm_config__timeout_macrop_a_lo = 0x36; + ptiming->mm_config__timeout_macrop_b_hi = 0x00; + ptiming->mm_config__timeout_macrop_b_lo = 0x28; + + + + + ptiming->range_config__timeout_macrop_a_hi = 0x00; + ptiming->range_config__timeout_macrop_a_lo = 0x44; + ptiming->range_config__timeout_macrop_b_hi = 0x00; + ptiming->range_config__timeout_macrop_b_lo = 0x33; + + + + + pgeneral->cal_config__vcsel_start = 0x05; + + + + + + + + + + + + + + + pgeneral->phasecal_config__timeout_macrop = 0xF5; + + + + + pdynamic->sd_config__woi_sd0 = 0x05; + pdynamic->sd_config__woi_sd1 = 0x07; + pdynamic->sd_config__initial_phase_sd0 = + ptuning_parms->tp_init_phase_rtn_hist_med; + pdynamic->sd_config__initial_phase_sd1 = + ptuning_parms->tp_init_phase_ref_hist_med; + + + + + + + + + phistpostprocess->valid_phase_low = 0x08; + phistpostprocess->valid_phase_high = 0x48; + + pdynamic->system__sequence_config = + VL53L1_SEQUENCE_VHV_EN | + VL53L1_SEQUENCE_PHASECAL_EN | + VL53L1_SEQUENCE_DSS1_EN | + VL53L1_SEQUENCE_DSS2_EN | + VL53L1_SEQUENCE_RANGE_EN; + + + + + + psystem->system__mode_start = + VL53L1_DEVICESCHEDULERMODE_HISTOGRAM | + VL53L1_DEVICEREADOUTMODE_DUAL_SD | + VL53L1_DEVICEMEASUREMENTMODE_BACKTOBACK; + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_preset_mode_histogram_medium_range_mm1( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + status = + VL53L1_preset_mode_histogram_medium_range( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + + + + + + + + + if (status == VL53L1_ERROR_NONE) { + + + + + VL53L1_init_histogram_config_structure( + 7, 0, 1, 1, 2, 2, + 8+0, 8+1, 8+2, 1, 2, 3, + phistogram); + + + + + + + VL53L1_init_histogram_multizone_config_structure( + 7, 0, 1, 1, 2, 2, + 8+0, 8+1, 8+2, 1, 2, 3, + &(pzone_cfg->multizone_hist_cfg)); + + + + + VL53L1_copy_hist_cfg_to_static_cfg( + phistogram, + pstatic, + pgeneral, + ptiming, + pdynamic); + + + + + pdynamic->system__sequence_config = + VL53L1_SEQUENCE_VHV_EN | + VL53L1_SEQUENCE_PHASECAL_EN | + VL53L1_SEQUENCE_DSS1_EN | + VL53L1_SEQUENCE_DSS2_EN | + VL53L1_SEQUENCE_MM1_EN | + VL53L1_SEQUENCE_RANGE_EN; + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_preset_mode_histogram_medium_range_mm2( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + status = + VL53L1_preset_mode_histogram_medium_range_mm1( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + + if (status == VL53L1_ERROR_NONE) { + + + + + pdynamic->system__sequence_config = + VL53L1_SEQUENCE_VHV_EN | + VL53L1_SEQUENCE_PHASECAL_EN | + VL53L1_SEQUENCE_DSS1_EN | + VL53L1_SEQUENCE_DSS2_EN | + VL53L1_SEQUENCE_MM2_EN | + VL53L1_SEQUENCE_RANGE_EN; + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_preset_mode_histogram_short_range( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + status = + VL53L1_preset_mode_histogram_ranging( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + + + + + + + + + if (status == VL53L1_ERROR_NONE) { + + + + + + + + + + VL53L1_init_histogram_config_structure( + 7, 7, 0, 1, 1, 1, + 0, 1, 1, 1, 2, 2, + phistogram); + + + + + + + VL53L1_init_histogram_multizone_config_structure( + 7, 7, 0, 1, 1, 1, + 0, 1, 1, 1, 2, 2, + &(pzone_cfg->multizone_hist_cfg)); + + + + + VL53L1_copy_hist_cfg_to_static_cfg( + phistogram, + pstatic, + pgeneral, + ptiming, + pdynamic); + + + + + + + ptiming->range_config__vcsel_period_a = 0x03; + ptiming->range_config__vcsel_period_b = 0x05; + + + + + + + ptiming->mm_config__timeout_macrop_a_hi = 0x00; + ptiming->mm_config__timeout_macrop_a_lo = 0x52; + ptiming->mm_config__timeout_macrop_b_hi = 0x00; + ptiming->mm_config__timeout_macrop_b_lo = 0x37; + + + + + ptiming->range_config__timeout_macrop_a_hi = 0x00; + ptiming->range_config__timeout_macrop_a_lo = 0x66; + ptiming->range_config__timeout_macrop_b_hi = 0x00; + ptiming->range_config__timeout_macrop_b_lo = 0x44; + + + + + pgeneral->cal_config__vcsel_start = 0x03; + + + + + + + + + + + + + + + pgeneral->phasecal_config__timeout_macrop = 0xF5; + + + + + pdynamic->sd_config__woi_sd0 = 0x03; + pdynamic->sd_config__woi_sd1 = 0x05; + pdynamic->sd_config__initial_phase_sd0 = + ptuning_parms->tp_init_phase_rtn_hist_short; + pdynamic->sd_config__initial_phase_sd1 = + ptuning_parms->tp_init_phase_ref_hist_short; + + + + + + + + phistpostprocess->valid_phase_low = 0x08; + phistpostprocess->valid_phase_high = 0x28; + + pdynamic->system__sequence_config = + VL53L1_SEQUENCE_VHV_EN | + VL53L1_SEQUENCE_PHASECAL_EN | + VL53L1_SEQUENCE_DSS1_EN | + VL53L1_SEQUENCE_DSS2_EN | + VL53L1_SEQUENCE_MM1_EN | + + + VL53L1_SEQUENCE_RANGE_EN; + + + + + + psystem->system__mode_start = + VL53L1_DEVICESCHEDULERMODE_HISTOGRAM | + VL53L1_DEVICEREADOUTMODE_DUAL_SD | + VL53L1_DEVICEMEASUREMENTMODE_BACKTOBACK; + } + + LOG_FUNCTION_END(status); + + return status; +} + + + + +VL53L1_Error VL53L1_preset_mode_special_histogram_short_range( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + status = + VL53L1_preset_mode_histogram_short_range( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + + + + + + + + + if (status == VL53L1_ERROR_NONE) { + + + + + + + + + + VL53L1_init_histogram_config_structure( + 7, 7, 0, 0, 1, 1, + 0, 0, 0, 1, 1, 1, + phistogram); + + + + + + + VL53L1_init_histogram_multizone_config_structure( + 7, 7, 0, 0, 1, 1, + 0, 0, 0, 1, 1, 1, + &(pzone_cfg->multizone_hist_cfg)); + + + + + VL53L1_copy_hist_cfg_to_static_cfg( + phistogram, + pstatic, + pgeneral, + ptiming, + pdynamic); + + + + + + + ptiming->range_config__vcsel_period_a = 0x02; + ptiming->range_config__vcsel_period_b = 0x03; + + + + + pgeneral->cal_config__vcsel_start = 0x00; + + + + + + pgeneral->phasecal_config__target = 0x31; + + + + + pdynamic->sd_config__woi_sd0 = 0x02; + pdynamic->sd_config__woi_sd1 = 0x03; + pdynamic->sd_config__initial_phase_sd0 = + ptuning_parms->tp_init_phase_rtn_hist_short; + pdynamic->sd_config__initial_phase_sd1 = + ptuning_parms->tp_init_phase_ref_hist_short; + + + + + + + + + phistpostprocess->valid_phase_low = 0x10; + phistpostprocess->valid_phase_high = 0x18; + + } + + LOG_FUNCTION_END(status); + + return status; +} + + + + +VL53L1_Error VL53L1_preset_mode_histogram_short_range_mm1( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + status = + VL53L1_preset_mode_histogram_short_range( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + + + + + + + + + if (status == VL53L1_ERROR_NONE) { + + + + + + + + + + VL53L1_init_histogram_config_structure( + 7, 7, 0, 1, 1, 1, + 8+0, 8+1, 1, 1, 2, 2, + phistogram); + + + + + + + VL53L1_init_histogram_multizone_config_structure( + 7, 7, 0, 1, 1, 1, + 8+0, 8+1, 1, 1, 2, 2, + &(pzone_cfg->multizone_hist_cfg)); + + + + + VL53L1_copy_hist_cfg_to_static_cfg( + phistogram, + pstatic, + pgeneral, + ptiming, + pdynamic); + + + + + pdynamic->system__sequence_config = + VL53L1_SEQUENCE_VHV_EN | + VL53L1_SEQUENCE_PHASECAL_EN | + VL53L1_SEQUENCE_DSS1_EN | + VL53L1_SEQUENCE_DSS2_EN | + VL53L1_SEQUENCE_MM1_EN | + VL53L1_SEQUENCE_RANGE_EN; + + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_preset_mode_histogram_short_range_mm2( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + status = + VL53L1_preset_mode_histogram_short_range_mm1( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + + if (status == VL53L1_ERROR_NONE) { + + + + + pdynamic->system__sequence_config = + VL53L1_SEQUENCE_VHV_EN | + VL53L1_SEQUENCE_PHASECAL_EN | + VL53L1_SEQUENCE_DSS1_EN | + VL53L1_SEQUENCE_DSS2_EN | + VL53L1_SEQUENCE_MM2_EN | + VL53L1_SEQUENCE_RANGE_EN; + } + + LOG_FUNCTION_END(status); + + return status; +} + + + +VL53L1_Error VL53L1_preset_mode_histogram_characterisation( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + status = + VL53L1_preset_mode_histogram_ranging( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + + if (status == VL53L1_ERROR_NONE) { + + + + + pstatic->debug__ctrl = 0x01; + psystem->power_management__go1_power_force = 0x01; + + pdynamic->system__sequence_config = + VL53L1_SEQUENCE_VHV_EN | + VL53L1_SEQUENCE_PHASECAL_EN | + VL53L1_SEQUENCE_RANGE_EN; + + psystem->system__mode_start = + VL53L1_DEVICESCHEDULERMODE_HISTOGRAM | + VL53L1_DEVICEREADOUTMODE_SPLIT_MANUAL | + VL53L1_DEVICEMEASUREMENTMODE_BACKTOBACK; + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_preset_mode_histogram_xtalk_planar( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + status = + VL53L1_preset_mode_histogram_multizone_long_range( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + + if (status == VL53L1_ERROR_NONE) { + + + + + + + status = + VL53L1_zone_preset_xtalk_planar( + pgeneral, + pzone_cfg); + + + + + + + + ptiming->range_config__vcsel_period_a = 0x09; + ptiming->range_config__vcsel_period_b = 0x09; + + + + + VL53L1_init_histogram_config_structure( + 7, 0, 1, 2, 3, 4, + 7, 0, 1, 2, 3, 4, + phistogram); + + + + + + + + VL53L1_init_histogram_multizone_config_structure( + 7, 0, 1, 2, 3, 4, + + 7, 0, 1, 2, 3, 4, + + &(pzone_cfg->multizone_hist_cfg)); + + + + + + + + + + + + if (status == VL53L1_ERROR_NONE) { + status = + VL53L1_set_histogram_multizone_initial_bin_config( + pzone_cfg, + phistogram, + &(pzone_cfg->multizone_hist_cfg)); + } + + + + + + + VL53L1_copy_hist_cfg_to_static_cfg( + phistogram, + pstatic, + pgeneral, + ptiming, + pdynamic); + + } + + LOG_FUNCTION_END(status); + + return status; +} + +VL53L1_Error VL53L1_preset_mode_histogram_xtalk_mm1( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + status = + VL53L1_preset_mode_histogram_ranging( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + + + + + + + + + + + if (status == VL53L1_ERROR_NONE) { + + + + + + + + + + VL53L1_init_histogram_config_structure( + 8+7, 8+0, 8+1, 8+2, 8+3, 8+4, + 8+7, 8+0, 8+1, 8+2, 8+3, 8+4, + phistogram); + + + + + + + VL53L1_init_histogram_multizone_config_structure( + 8+7, 8+0, 8+1, 8+2, 8+3, 8+4, + 8+7, 8+0, 8+1, 8+2, 8+3, 8+4, + &(pzone_cfg->multizone_hist_cfg)); + + + + + VL53L1_copy_hist_cfg_to_static_cfg( + phistogram, + pstatic, + pgeneral, + ptiming, + pdynamic); + + + + + + + ptiming->range_config__vcsel_period_a = 0x09; + ptiming->range_config__vcsel_period_b = 0x09; + + + + + + + ptiming->mm_config__timeout_macrop_a_hi = 0x00; + ptiming->mm_config__timeout_macrop_a_lo = 0x21; + ptiming->mm_config__timeout_macrop_b_hi = 0x00; + ptiming->mm_config__timeout_macrop_b_lo = 0x21; + + + + + ptiming->range_config__timeout_macrop_a_hi = 0x00; + ptiming->range_config__timeout_macrop_a_lo = 0x29; + ptiming->range_config__timeout_macrop_b_hi = 0x00; + ptiming->range_config__timeout_macrop_b_lo = 0x29; + + + + + pgeneral->cal_config__vcsel_start = 0x09; + + + + + + + + + + + + + + pgeneral->phasecal_config__timeout_macrop = 0xF5; + + + + + pdynamic->sd_config__woi_sd0 = 0x09; + pdynamic->sd_config__woi_sd1 = 0x09; + pdynamic->sd_config__initial_phase_sd0 = 0x09; + pdynamic->sd_config__initial_phase_sd1 = 0x06; + + pdynamic->system__sequence_config = + VL53L1_SEQUENCE_VHV_EN | + VL53L1_SEQUENCE_PHASECAL_EN | + VL53L1_SEQUENCE_DSS1_EN | + VL53L1_SEQUENCE_DSS2_EN | + VL53L1_SEQUENCE_MM1_EN | + VL53L1_SEQUENCE_RANGE_EN; + + + + + + psystem->system__mode_start = + VL53L1_DEVICESCHEDULERMODE_HISTOGRAM | + VL53L1_DEVICEREADOUTMODE_DUAL_SD | + VL53L1_DEVICEMEASUREMENTMODE_BACKTOBACK; + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_preset_mode_histogram_xtalk_mm2( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + status = + VL53L1_preset_mode_histogram_xtalk_mm1( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + pdynamic->system__sequence_config = + VL53L1_SEQUENCE_VHV_EN | + VL53L1_SEQUENCE_PHASECAL_EN | + VL53L1_SEQUENCE_DSS1_EN | + VL53L1_SEQUENCE_DSS2_EN | + VL53L1_SEQUENCE_MM2_EN | + VL53L1_SEQUENCE_RANGE_EN; + + + + LOG_FUNCTION_END(status); + + return status; +} + + + + +VL53L1_Error VL53L1_preset_mode_histogram_multizone( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + status = + VL53L1_preset_mode_histogram_medium_range( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + + if (status == VL53L1_ERROR_NONE) { + + + + + + + status = + VL53L1_init_zone_config_structure( + 4, 8, 2, + + 4, 8, 2, + + 7, 7, + + pzone_cfg); + + pgeneral->global_config__stream_divider = + pzone_cfg->active_zones + 1; + + + + + + + if (status == VL53L1_ERROR_NONE) { + status = + VL53L1_set_histogram_multizone_initial_bin_config( + pzone_cfg, + phistogram, + &(pzone_cfg->multizone_hist_cfg)); + } + + VL53L1_copy_hist_cfg_to_static_cfg( + phistogram, + pstatic, + pgeneral, + ptiming, + pdynamic); + } + + LOG_FUNCTION_END(status); + + return status; +} + +VL53L1_Error VL53L1_preset_mode_histogram_multizone_short_range( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + status = + VL53L1_preset_mode_histogram_short_range( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + + if (status == VL53L1_ERROR_NONE) { + + + + + + + status = + VL53L1_init_zone_config_structure( + 4, 8, 2, + + 4, 8, 2, + + 7, 7, + + pzone_cfg); + + pgeneral->global_config__stream_divider = + pzone_cfg->active_zones + 1; + + + + + + + if (status == VL53L1_ERROR_NONE) { + status = + VL53L1_set_histogram_multizone_initial_bin_config( + pzone_cfg, + phistogram, + &(pzone_cfg->multizone_hist_cfg) + ); + } + + + + + VL53L1_copy_hist_cfg_to_static_cfg( + phistogram, + pstatic, + pgeneral, + ptiming, + pdynamic); + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_preset_mode_histogram_multizone_long_range( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + status = + VL53L1_preset_mode_histogram_long_range( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + + if (status == VL53L1_ERROR_NONE) { + + + + + + + status = + VL53L1_init_zone_config_structure( + 4, 8, 2, + + 4, 8, 2, + + 7, 7, + + pzone_cfg); + + pgeneral->global_config__stream_divider = + pzone_cfg->active_zones + 1; + + + + + + + if (status == VL53L1_ERROR_NONE) { + status = + VL53L1_set_histogram_multizone_initial_bin_config( + pzone_cfg, + phistogram, + &(pzone_cfg->multizone_hist_cfg)); + } + + + + + VL53L1_copy_hist_cfg_to_static_cfg( + phistogram, + pstatic, + pgeneral, + ptiming, + pdynamic); + } + + LOG_FUNCTION_END(status); + + return status; +} + + + + +VL53L1_Error VL53L1_preset_mode_olt( + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + status = VL53L1_preset_mode_standard_ranging( + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + + if (status == VL53L1_ERROR_NONE) + + + psystem->system__stream_count_ctrl = 0x01; + + LOG_FUNCTION_END(status); + + return status; +} + + +void VL53L1_copy_hist_cfg_to_static_cfg( + VL53L1_histogram_config_t *phistogram, + VL53L1_static_config_t *pstatic, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic) +{ + + + + + + + LOG_FUNCTION_START(""); + + SUPPRESS_UNUSED_WARNING(pgeneral); + + pstatic->sigma_estimator__effective_pulse_width_ns = + phistogram->histogram_config__high_amb_even_bin_0_1; + pstatic->sigma_estimator__effective_ambient_width_ns = + phistogram->histogram_config__high_amb_even_bin_2_3; + pstatic->sigma_estimator__sigma_ref_mm = + phistogram->histogram_config__high_amb_even_bin_4_5; + + pstatic->algo__crosstalk_compensation_valid_height_mm = + phistogram->histogram_config__high_amb_odd_bin_0_1; + + pstatic->spare_host_config__static_config_spare_0 = + phistogram->histogram_config__high_amb_odd_bin_2_3; + pstatic->spare_host_config__static_config_spare_1 = + phistogram->histogram_config__high_amb_odd_bin_4_5; + + pstatic->algo__range_ignore_threshold_mcps = + (((uint16_t)phistogram->histogram_config__mid_amb_even_bin_0_1) + << 8) + + (uint16_t)phistogram->histogram_config__mid_amb_even_bin_2_3; + + pstatic->algo__range_ignore_valid_height_mm = + phistogram->histogram_config__mid_amb_even_bin_4_5; + pstatic->algo__range_min_clip = + phistogram->histogram_config__mid_amb_odd_bin_0_1; + pstatic->algo__consistency_check__tolerance = + phistogram->histogram_config__mid_amb_odd_bin_2; + + pstatic->spare_host_config__static_config_spare_2 = + phistogram->histogram_config__mid_amb_odd_bin_3_4; + pstatic->sd_config__reset_stages_msb = + phistogram->histogram_config__mid_amb_odd_bin_5; + + pstatic->sd_config__reset_stages_lsb = + phistogram->histogram_config__user_bin_offset; + + ptiming->range_config__sigma_thresh = + (((uint16_t)phistogram->histogram_config__low_amb_even_bin_0_1) + << 8) + + (uint16_t)phistogram->histogram_config__low_amb_even_bin_2_3; + + ptiming->range_config__min_count_rate_rtn_limit_mcps = + (((uint16_t)phistogram->histogram_config__low_amb_even_bin_4_5) + << 8) + + (uint16_t)phistogram->histogram_config__low_amb_odd_bin_0_1; + + ptiming->range_config__valid_phase_low = + phistogram->histogram_config__low_amb_odd_bin_2_3; + ptiming->range_config__valid_phase_high = + phistogram->histogram_config__low_amb_odd_bin_4_5; + + pdynamic->system__thresh_high = + phistogram->histogram_config__amb_thresh_low; + + pdynamic->system__thresh_low = + phistogram->histogram_config__amb_thresh_high; + + pdynamic->system__enable_xtalk_per_quadrant = + phistogram->histogram_config__spad_array_selection; + + LOG_FUNCTION_END(0); + +} + +void VL53L1_copy_hist_bins_to_static_cfg( + VL53L1_histogram_config_t *phistogram, + VL53L1_static_config_t *pstatic, + VL53L1_timing_config_t *ptiming) +{ + + + + + + + LOG_FUNCTION_START(""); + + pstatic->sigma_estimator__effective_pulse_width_ns = + phistogram->histogram_config__high_amb_even_bin_0_1; + pstatic->sigma_estimator__effective_ambient_width_ns = + phistogram->histogram_config__high_amb_even_bin_2_3; + pstatic->sigma_estimator__sigma_ref_mm = + phistogram->histogram_config__high_amb_even_bin_4_5; + + pstatic->algo__crosstalk_compensation_valid_height_mm = + phistogram->histogram_config__high_amb_odd_bin_0_1; + + pstatic->spare_host_config__static_config_spare_0 = + phistogram->histogram_config__high_amb_odd_bin_2_3; + pstatic->spare_host_config__static_config_spare_1 = + phistogram->histogram_config__high_amb_odd_bin_4_5; + + pstatic->algo__range_ignore_threshold_mcps = + (((uint16_t)phistogram->histogram_config__mid_amb_even_bin_0_1) + << 8) + + (uint16_t)phistogram->histogram_config__mid_amb_even_bin_2_3; + + pstatic->algo__range_ignore_valid_height_mm = + phistogram->histogram_config__mid_amb_even_bin_4_5; + pstatic->algo__range_min_clip = + phistogram->histogram_config__mid_amb_odd_bin_0_1; + pstatic->algo__consistency_check__tolerance = + phistogram->histogram_config__mid_amb_odd_bin_2; + + pstatic->spare_host_config__static_config_spare_2 = + phistogram->histogram_config__mid_amb_odd_bin_3_4; + pstatic->sd_config__reset_stages_msb = + phistogram->histogram_config__mid_amb_odd_bin_5; + + ptiming->range_config__sigma_thresh = + (((uint16_t)phistogram->histogram_config__low_amb_even_bin_0_1) + << 8) + + (uint16_t)phistogram->histogram_config__low_amb_even_bin_2_3; + + ptiming->range_config__min_count_rate_rtn_limit_mcps = + (((uint16_t)phistogram->histogram_config__low_amb_even_bin_4_5) + << 8) + + (uint16_t)phistogram->histogram_config__low_amb_odd_bin_0_1; + + ptiming->range_config__valid_phase_low = + phistogram->histogram_config__low_amb_odd_bin_2_3; + ptiming->range_config__valid_phase_high = + phistogram->histogram_config__low_amb_odd_bin_4_5; + + LOG_FUNCTION_END(0); + +} + + +VL53L1_Error VL53L1_preset_mode_histogram_ranging_ref( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + status = + VL53L1_preset_mode_histogram_ranging( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + + if (status == VL53L1_ERROR_NONE) { + + + + + phistogram->histogram_config__spad_array_selection = 0x01; + + + + + VL53L1_copy_hist_cfg_to_static_cfg( + phistogram, + pstatic, + pgeneral, + ptiming, + pdynamic); + } + + LOG_FUNCTION_END(status); + + return status; +} + + + + + diff --git a/drivers/input/misc/vl53L1/kona/src/vl53l1_api_strings.c b/drivers/input/misc/vl53L1/kona/src/vl53l1_api_strings.c new file mode 100644 index 000000000000..deec3c512107 --- /dev/null +++ b/drivers/input/misc/vl53L1/kona/src/vl53l1_api_strings.c @@ -0,0 +1,334 @@ + +/******************************************************************************* + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#include "vl53l1_api_core.h" +#include "vl53l1_api_strings.h" +#include "vl53l1_error_codes.h" +#include "vl53l1_error_strings.h" + +#define LOG_FUNCTION_START(fmt, ...) \ + _LOG_FUNCTION_START(VL53L1_TRACE_MODULE_API, fmt, ##__VA_ARGS__) +#define LOG_FUNCTION_END(status, ...) \ + _LOG_FUNCTION_END(VL53L1_TRACE_MODULE_API, status, ##__VA_ARGS__) +#define LOG_FUNCTION_END_FMT(status, fmt, ...) \ + _LOG_FUNCTION_END_FMT(VL53L1_TRACE_MODULE_API, status, fmt, \ + ##__VA_ARGS__) + + +VL53L1_Error VL53L1_get_range_status_string( + uint8_t RangeStatus, + char *pRangeStatusString) +{ + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + +#ifdef VL53L1_USE_EMPTY_STRING + VL53L1_COPYSTRING(pRangeStatusString, ""); +#else + switch (RangeStatus) { + case 0: + VL53L1_COPYSTRING(pRangeStatusString, + VL53L1_STRING_RANGESTATUS_RANGEVALID); + break; + case 1: + VL53L1_COPYSTRING(pRangeStatusString, + VL53L1_STRING_RANGESTATUS_SIGMA); + break; + case 2: + VL53L1_COPYSTRING(pRangeStatusString, + VL53L1_STRING_RANGESTATUS_SIGNAL); + break; + case 3: + VL53L1_COPYSTRING(pRangeStatusString, + VL53L1_STRING_RANGESTATUS_MINRANGE); + break; + case 4: + VL53L1_COPYSTRING(pRangeStatusString, + VL53L1_STRING_RANGESTATUS_PHASE); + break; + case 5: + VL53L1_COPYSTRING(pRangeStatusString, + VL53L1_STRING_RANGESTATUS_HW); + break; + + default: + + VL53L1_COPYSTRING(pRangeStatusString, + VL53L1_STRING_RANGESTATUS_NONE); + } +#endif + + LOG_FUNCTION_END(status); + return status; +} + + +VL53L1_Error VL53L1_get_pal_state_string( + VL53L1_State PalStateCode, + char *pPalStateString) +{ + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + +#ifdef VL53L1_USE_EMPTY_STRING + VL53L1_COPYSTRING(pPalStateString, ""); +#else + switch (PalStateCode) { + case VL53L1_STATE_POWERDOWN: + VL53L1_COPYSTRING(pPalStateString, + VL53L1_STRING_STATE_POWERDOWN); + break; + case VL53L1_STATE_WAIT_STATICINIT: + VL53L1_COPYSTRING(pPalStateString, + VL53L1_STRING_STATE_WAIT_STATICINIT); + break; + case VL53L1_STATE_STANDBY: + VL53L1_COPYSTRING(pPalStateString, + VL53L1_STRING_STATE_STANDBY); + break; + case VL53L1_STATE_IDLE: + VL53L1_COPYSTRING(pPalStateString, + VL53L1_STRING_STATE_IDLE); + break; + case VL53L1_STATE_RUNNING: + VL53L1_COPYSTRING(pPalStateString, + VL53L1_STRING_STATE_RUNNING); + break; + case VL53L1_STATE_RESET: + VL53L1_COPYSTRING(pPalStateString, + VL53L1_STRING_STATE_RESET); + break; + case VL53L1_STATE_UNKNOWN: + VL53L1_COPYSTRING(pPalStateString, + VL53L1_STRING_STATE_UNKNOWN); + break; + case VL53L1_STATE_ERROR: + VL53L1_COPYSTRING(pPalStateString, + VL53L1_STRING_STATE_ERROR); + break; + + default: + VL53L1_COPYSTRING(pPalStateString, + VL53L1_STRING_STATE_UNKNOWN); + } +#endif + + LOG_FUNCTION_END(status); + return status; +} + +VL53L1_Error VL53L1_get_sequence_steps_info( + VL53L1_SequenceStepId SequenceStepId, + char *pSequenceStepsString) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + +#ifdef VL53L1_USE_EMPTY_STRING + VL53L1_COPYSTRING(pSequenceStepsString, ""); +#else + switch (SequenceStepId) { + case VL53L1_SEQUENCESTEP_VHV: + VL53L1_COPYSTRING(pSequenceStepsString, + VL53L1_STRING_SEQUENCESTEP_VHV); + break; + case VL53L1_SEQUENCESTEP_PHASECAL: + VL53L1_COPYSTRING(pSequenceStepsString, + VL53L1_STRING_SEQUENCESTEP_PHASECAL); + break; + case VL53L1_SEQUENCESTEP_REFPHASE: + VL53L1_COPYSTRING(pSequenceStepsString, + VL53L1_STRING_SEQUENCESTEP_DSS1); + break; + case VL53L1_SEQUENCESTEP_DSS1: + VL53L1_COPYSTRING(pSequenceStepsString, + VL53L1_STRING_SEQUENCESTEP_DSS1); + break; + case VL53L1_SEQUENCESTEP_DSS2: + VL53L1_COPYSTRING(pSequenceStepsString, + VL53L1_STRING_SEQUENCESTEP_DSS2); + break; + case VL53L1_SEQUENCESTEP_MM1: + VL53L1_COPYSTRING(pSequenceStepsString, + VL53L1_STRING_SEQUENCESTEP_MM1); + break; + case VL53L1_SEQUENCESTEP_MM2: + VL53L1_COPYSTRING(pSequenceStepsString, + VL53L1_STRING_SEQUENCESTEP_MM2); + break; + case VL53L1_SEQUENCESTEP_RANGE: + VL53L1_COPYSTRING(pSequenceStepsString, + VL53L1_STRING_SEQUENCESTEP_RANGE); + break; + default: + Status = VL53L1_ERROR_INVALID_PARAMS; + } +#endif + + LOG_FUNCTION_END(Status); + + return Status; +} + +VL53L1_Error VL53L1_get_limit_check_info(uint16_t LimitCheckId, + char *pLimitCheckString) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + +#ifdef VL53L1_USE_EMPTY_STRING + VL53L1_COPYSTRING(pLimitCheckString, ""); +#else + switch (LimitCheckId) { + case VL53L1_CHECKENABLE_SIGMA_FINAL_RANGE: + VL53L1_COPYSTRING(pLimitCheckString, + VL53L1_STRING_CHECKENABLE_SIGMA_FINAL_RANGE); + break; + case VL53L1_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE: + VL53L1_COPYSTRING(pLimitCheckString, + VL53L1_STRING_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE); + break; + default: + VL53L1_COPYSTRING(pLimitCheckString, + VL53L1_STRING_UNKNOW_ERROR_CODE); + } +#endif + + LOG_FUNCTION_END(Status); + return Status; +} + + diff --git a/drivers/input/misc/vl53L1/kona/src/vl53l1_core.c b/drivers/input/misc/vl53L1/kona/src/vl53l1_core.c new file mode 100644 index 000000000000..8a5a8c67a634 --- /dev/null +++ b/drivers/input/misc/vl53L1/kona/src/vl53l1_core.c @@ -0,0 +1,5952 @@ + +/******************************************************************************* + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#include "vl53l1_ll_def.h" +#include "vl53l1_ll_device.h" +#include "vl53l1_platform.h" +#include "vl53l1_register_map.h" +#include "vl53l1_register_funcs.h" +#include "vl53l1_register_settings.h" +#include "vl53l1_hist_structs.h" +#include "vl53l1_api_preset_modes.h" +#include "vl53l1_core.h" +#include "vl53l1_tuning_parm_defaults.h" + + + + + + + +#define LOG_FUNCTION_START(fmt, ...) \ + _LOG_FUNCTION_START(VL53L1_TRACE_MODULE_CORE, fmt, ##__VA_ARGS__) +#define LOG_FUNCTION_END(status, ...) \ + _LOG_FUNCTION_END(VL53L1_TRACE_MODULE_CORE, status, ##__VA_ARGS__) +#define LOG_FUNCTION_END_FMT(status, fmt, ...) \ + _LOG_FUNCTION_END_FMT(VL53L1_TRACE_MODULE_CORE, \ + status, fmt, ##__VA_ARGS__) + +#define trace_print(level, ...) \ + _LOG_TRACE_PRINT(VL53L1_TRACE_MODULE_CORE, \ + level, VL53L1_TRACE_FUNCTION_NONE, ##__VA_ARGS__) + + +void VL53L1_init_version( + VL53L1_DEV Dev) +{ + + + + + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + pdev->version.ll_major = VL53L1_LL_API_IMPLEMENTATION_VER_MAJOR; + pdev->version.ll_minor = VL53L1_LL_API_IMPLEMENTATION_VER_MINOR; + pdev->version.ll_build = VL53L1_LL_API_IMPLEMENTATION_VER_SUB; + pdev->version.ll_revision = VL53L1_LL_API_IMPLEMENTATION_VER_REVISION; +} + + +void VL53L1_init_ll_driver_state( + VL53L1_DEV Dev, + VL53L1_DeviceState device_state) +{ + + + + + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_ll_driver_state_t *pstate = &(pdev->ll_state); + + pstate->cfg_device_state = device_state; + pstate->cfg_stream_count = 0; + pstate->cfg_gph_id = VL53L1_GROUPEDPARAMETERHOLD_ID_MASK; + pstate->cfg_timing_status = 0; + pstate->cfg_zone_id = 0; + + pstate->rd_device_state = device_state; + pstate->rd_stream_count = 0; + pstate->rd_gph_id = VL53L1_GROUPEDPARAMETERHOLD_ID_MASK; + pstate->rd_timing_status = 0; + pstate->rd_zone_id = 0; + +} + + +VL53L1_Error VL53L1_update_ll_driver_rd_state( + VL53L1_DEV Dev) +{ + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_ll_driver_state_t *pstate = &(pdev->ll_state); + + + + + LOG_FUNCTION_START(""); + + + + + + if ((pdev->sys_ctrl.system__mode_start & + VL53L1_DEVICEMEASUREMENTMODE_MODE_MASK) == 0x00) { + + pstate->rd_device_state = VL53L1_DEVICESTATE_SW_STANDBY; + pstate->rd_stream_count = 0; + pstate->rd_internal_stream_count = 0; + pstate->rd_internal_stream_count_val = 0; + pstate->rd_gph_id = VL53L1_GROUPEDPARAMETERHOLD_ID_MASK; + pstate->rd_timing_status = 0; + pstate->rd_zone_id = 0; + + } else { + + + + + + + if (pstate->rd_stream_count == 0xFF) + pstate->rd_stream_count = 0x80; + else + pstate->rd_stream_count++; + + + + + + status = VL53L1_update_internal_stream_counters(Dev, + pstate->rd_stream_count, + &(pstate->rd_internal_stream_count), + &(pstate->rd_internal_stream_count_val)); + + + + + + + pstate->rd_gph_id ^= VL53L1_GROUPEDPARAMETERHOLD_ID_MASK; + + + + + switch (pstate->rd_device_state) { + + case VL53L1_DEVICESTATE_SW_STANDBY: + + if ((pdev->dyn_cfg.system__grouped_parameter_hold & + VL53L1_GROUPEDPARAMETERHOLD_ID_MASK) > 0) { + pstate->rd_device_state = + VL53L1_DEVICESTATE_RANGING_WAIT_GPH_SYNC; + } else { + if (pstate->rd_zone_id >= + pdev->zone_cfg.active_zones) + pstate->rd_device_state = + VL53L1_DEVICESTATE_RANGING_OUTPUT_DATA; + else + pstate->rd_device_state = + VL53L1_DEVICESTATE_RANGING_GATHER_DATA; + } + + pstate->rd_stream_count = 0; + pstate->rd_internal_stream_count = 0; + pstate->rd_internal_stream_count_val = 0; + pstate->rd_timing_status = 0; + pstate->rd_zone_id = 0; + + break; + + case VL53L1_DEVICESTATE_RANGING_WAIT_GPH_SYNC: + pstate->rd_stream_count = 0; + pstate->rd_internal_stream_count = 0; + pstate->rd_internal_stream_count_val = 0; + pstate->rd_zone_id = 0; + if (pstate->rd_zone_id >= + pdev->zone_cfg.active_zones) + pstate->rd_device_state = + VL53L1_DEVICESTATE_RANGING_OUTPUT_DATA; + else + pstate->rd_device_state = + VL53L1_DEVICESTATE_RANGING_GATHER_DATA; + + break; + + case VL53L1_DEVICESTATE_RANGING_GATHER_DATA: + pstate->rd_zone_id++; + if (pstate->rd_zone_id >= + pdev->zone_cfg.active_zones) + pstate->rd_device_state = + VL53L1_DEVICESTATE_RANGING_OUTPUT_DATA; + else + pstate->rd_device_state = + VL53L1_DEVICESTATE_RANGING_GATHER_DATA; + + break; + + case VL53L1_DEVICESTATE_RANGING_OUTPUT_DATA: + pstate->rd_zone_id = 0; + pstate->rd_timing_status ^= 0x01; + + if (pstate->rd_zone_id >= + pdev->zone_cfg.active_zones) + pstate->rd_device_state = + VL53L1_DEVICESTATE_RANGING_OUTPUT_DATA; + else + pstate->rd_device_state = + VL53L1_DEVICESTATE_RANGING_GATHER_DATA; + break; + + default: + pstate->rd_device_state = + VL53L1_DEVICESTATE_SW_STANDBY; + pstate->rd_stream_count = 0; + pstate->rd_internal_stream_count = 0; + pstate->rd_internal_stream_count_val = 0; + pstate->rd_gph_id = VL53L1_GROUPEDPARAMETERHOLD_ID_MASK; + pstate->rd_timing_status = 0; + pstate->rd_zone_id = 0; + break; + } + } + + + + + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_check_ll_driver_rd_state( + VL53L1_DEV Dev) +{ + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_LLDriverResults_t *pres = + VL53L1DevStructGetLLResultsHandle(Dev); + + VL53L1_ll_driver_state_t *pstate = &(pdev->ll_state); + VL53L1_system_results_t *psys_results = &(pdev->sys_results); + VL53L1_histogram_bin_data_t *phist_data = &(pdev->hist_data); + VL53L1_zone_private_dyn_cfgs_t *pZ = &(pres->zone_dyn_cfgs); + + uint8_t device_range_status = 0; + uint8_t device_stream_count = 0; + uint8_t device_gph_id = 0; + uint8_t histogram_mode = 0; + uint8_t expected_stream_count = 0; + uint8_t expected_gph_id = 0; + + LOG_FUNCTION_START(""); + + + + + + device_range_status = + psys_results->result__range_status & + VL53L1_RANGE_STATUS__RANGE_STATUS_MASK; + + device_stream_count = psys_results->result__stream_count; + + + + + histogram_mode = + (pdev->sys_ctrl.system__mode_start & + VL53L1_DEVICESCHEDULERMODE_HISTOGRAM) == + VL53L1_DEVICESCHEDULERMODE_HISTOGRAM; + + + + device_gph_id = (psys_results->result__interrupt_status & + VL53L1_INTERRUPT_STATUS__GPH_ID_INT_STATUS_MASK) >> 4; + + if (histogram_mode) + device_gph_id = (phist_data->result__interrupt_status & + VL53L1_INTERRUPT_STATUS__GPH_ID_INT_STATUS_MASK) >> 4; + + + + + if (!((pdev->sys_ctrl.system__mode_start & + VL53L1_DEVICEMEASUREMENTMODE_BACKTOBACK) == + VL53L1_DEVICEMEASUREMENTMODE_BACKTOBACK)) + goto ENDFUNC; + + + + + + + + + + + + + + + if (pstate->rd_device_state == + VL53L1_DEVICESTATE_RANGING_WAIT_GPH_SYNC) { + + if (histogram_mode == 0) { + if (device_range_status != + VL53L1_DEVICEERROR_GPHSTREAMCOUNT0READY) + status = + VL53L1_ERROR_GPH_SYNC_CHECK_FAIL; + + } + } else { + if (pstate->rd_stream_count != device_stream_count) + status = VL53L1_ERROR_STREAM_COUNT_CHECK_FAIL; + + + + + + if (pstate->rd_gph_id != device_gph_id) + status = VL53L1_ERROR_GPH_ID_CHECK_FAIL; + + + + + + + + + + + + + + + + + + + + + + expected_stream_count = + pZ->VL53L1_p_002[pstate->rd_zone_id].expected_stream_count; + expected_gph_id = + pZ->VL53L1_p_002[pstate->rd_zone_id].expected_gph_id; + + + + + + + if (expected_stream_count != device_stream_count) { + + + + + + if (!((pdev->zone_cfg.active_zones == 0) && + (device_stream_count == 255))) + status = + VL53L1_ERROR_ZONE_STREAM_COUNT_CHECK_FAIL; + + + + + + + + + + + + + + + + + + + } + + + + + + + if (expected_gph_id != device_gph_id) + status = VL53L1_ERROR_ZONE_GPH_ID_CHECK_FAIL; + + + + + + + + + + + } + + + + + + + + + + + + + + +ENDFUNC: + LOG_FUNCTION_END(status); + return status; +} + + +VL53L1_Error VL53L1_update_ll_driver_cfg_state( + VL53L1_DEV Dev) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_LLDriverResults_t *pres = + VL53L1DevStructGetLLResultsHandle(Dev); + + VL53L1_ll_driver_state_t *pstate = &(pdev->ll_state); + VL53L1_zone_private_dyn_cfgs_t *pZ = &(pres->zone_dyn_cfgs); + + uint8_t prev_cfg_zone_id; + uint8_t prev_cfg_gph_id; + uint8_t prev_cfg_stream_count; + + LOG_FUNCTION_START(""); + + + + + + + + + if ((pdev->sys_ctrl.system__mode_start & + VL53L1_DEVICEMEASUREMENTMODE_MODE_MASK) == 0x00) { + + pstate->cfg_device_state = VL53L1_DEVICESTATE_SW_STANDBY; + pstate->cfg_stream_count = 0; + pstate->cfg_internal_stream_count = 0; + pstate->cfg_internal_stream_count_val = 0; + pstate->cfg_gph_id = VL53L1_GROUPEDPARAMETERHOLD_ID_MASK; + pstate->cfg_timing_status = 0; + pstate->cfg_zone_id = 0; + prev_cfg_zone_id = 0; + prev_cfg_gph_id = 0; + prev_cfg_stream_count = 0; + + } else { + + + + + prev_cfg_gph_id = pstate->cfg_gph_id; + prev_cfg_zone_id = pstate->cfg_zone_id; + prev_cfg_stream_count = pstate->cfg_stream_count; + + + + + + + if (pstate->cfg_stream_count == 0xFF) + pstate->cfg_stream_count = 0x80; + else + pstate->cfg_stream_count++; + + + + + + status = VL53L1_update_internal_stream_counters( + Dev, + pstate->cfg_stream_count, + &(pstate->cfg_internal_stream_count), + &(pstate->cfg_internal_stream_count_val)); + + + + + + + pstate->cfg_gph_id ^= VL53L1_GROUPEDPARAMETERHOLD_ID_MASK; + + + + + + + switch (pstate->cfg_device_state) { + + case VL53L1_DEVICESTATE_SW_STANDBY: + pstate->cfg_zone_id = 1; + if (pstate->cfg_zone_id > + pdev->zone_cfg.active_zones) { + pstate->cfg_zone_id = 0; + pstate->cfg_timing_status ^= 0x01; + } + pstate->cfg_stream_count = 1; + + if (pdev->gen_cfg.global_config__stream_divider == 0) { + pstate->cfg_internal_stream_count = 1; + pstate->cfg_internal_stream_count_val = 0; + } else { + pstate->cfg_internal_stream_count = 0; + pstate->cfg_internal_stream_count_val = 1; + } + pstate->cfg_device_state = + VL53L1_DEVICESTATE_RANGING_DSS_AUTO; + break; + + case VL53L1_DEVICESTATE_RANGING_DSS_AUTO: + pstate->cfg_zone_id++; + if (pstate->cfg_zone_id > + pdev->zone_cfg.active_zones) { + + pstate->cfg_zone_id = 0; + pstate->cfg_timing_status ^= 0x01; + + + + + + + if (pdev->zone_cfg.active_zones > 0) { + pstate->cfg_device_state = + VL53L1_DEVICESTATE_RANGING_DSS_MANUAL; + } + } + break; + + case VL53L1_DEVICESTATE_RANGING_DSS_MANUAL: + pstate->cfg_zone_id++; + if (pstate->cfg_zone_id > + pdev->zone_cfg.active_zones) { + pstate->cfg_zone_id = 0; + pstate->cfg_timing_status ^= 0x01; + } + break; + + default: + pstate->cfg_device_state = + VL53L1_DEVICESTATE_SW_STANDBY; + pstate->cfg_stream_count = 0; + pstate->cfg_internal_stream_count = 0; + pstate->cfg_internal_stream_count_val = 0; + pstate->cfg_gph_id = + VL53L1_GROUPEDPARAMETERHOLD_ID_MASK; + pstate->cfg_timing_status = 0; + pstate->cfg_zone_id = 0; + break; + } + } + + + + + + if (pdev->zone_cfg.active_zones == 0) { + + + + + + pZ->VL53L1_p_002[prev_cfg_zone_id].expected_stream_count + = prev_cfg_stream_count - 1; + + pZ->VL53L1_p_002[pstate->rd_zone_id].expected_gph_id = + prev_cfg_gph_id ^ VL53L1_GROUPEDPARAMETERHOLD_ID_MASK; + } else { + pZ->VL53L1_p_002[prev_cfg_zone_id].expected_stream_count + = prev_cfg_stream_count; + pZ->VL53L1_p_002[prev_cfg_zone_id].expected_gph_id = + prev_cfg_gph_id; + } + + + + + + LOG_FUNCTION_END(status); + + return status; +} + + +void VL53L1_copy_rtn_good_spads_to_buffer( + VL53L1_nvm_copy_data_t *pdata, + uint8_t *pbuffer) +{ + + + + + + *(pbuffer + 0) = pdata->global_config__spad_enables_rtn_0; + *(pbuffer + 1) = pdata->global_config__spad_enables_rtn_1; + *(pbuffer + 2) = pdata->global_config__spad_enables_rtn_2; + *(pbuffer + 3) = pdata->global_config__spad_enables_rtn_3; + *(pbuffer + 4) = pdata->global_config__spad_enables_rtn_4; + *(pbuffer + 5) = pdata->global_config__spad_enables_rtn_5; + *(pbuffer + 6) = pdata->global_config__spad_enables_rtn_6; + *(pbuffer + 7) = pdata->global_config__spad_enables_rtn_7; + *(pbuffer + 8) = pdata->global_config__spad_enables_rtn_8; + *(pbuffer + 9) = pdata->global_config__spad_enables_rtn_9; + *(pbuffer + 10) = pdata->global_config__spad_enables_rtn_10; + *(pbuffer + 11) = pdata->global_config__spad_enables_rtn_11; + *(pbuffer + 12) = pdata->global_config__spad_enables_rtn_12; + *(pbuffer + 13) = pdata->global_config__spad_enables_rtn_13; + *(pbuffer + 14) = pdata->global_config__spad_enables_rtn_14; + *(pbuffer + 15) = pdata->global_config__spad_enables_rtn_15; + *(pbuffer + 16) = pdata->global_config__spad_enables_rtn_16; + *(pbuffer + 17) = pdata->global_config__spad_enables_rtn_17; + *(pbuffer + 18) = pdata->global_config__spad_enables_rtn_18; + *(pbuffer + 19) = pdata->global_config__spad_enables_rtn_19; + *(pbuffer + 20) = pdata->global_config__spad_enables_rtn_20; + *(pbuffer + 21) = pdata->global_config__spad_enables_rtn_21; + *(pbuffer + 22) = pdata->global_config__spad_enables_rtn_22; + *(pbuffer + 23) = pdata->global_config__spad_enables_rtn_23; + *(pbuffer + 24) = pdata->global_config__spad_enables_rtn_24; + *(pbuffer + 25) = pdata->global_config__spad_enables_rtn_25; + *(pbuffer + 26) = pdata->global_config__spad_enables_rtn_26; + *(pbuffer + 27) = pdata->global_config__spad_enables_rtn_27; + *(pbuffer + 28) = pdata->global_config__spad_enables_rtn_28; + *(pbuffer + 29) = pdata->global_config__spad_enables_rtn_29; + *(pbuffer + 30) = pdata->global_config__spad_enables_rtn_30; + *(pbuffer + 31) = pdata->global_config__spad_enables_rtn_31; +} + + +void VL53L1_init_system_results( + VL53L1_system_results_t *pdata) +{ + + + + + + + pdata->result__interrupt_status = 0xFF; + pdata->result__range_status = 0xFF; + pdata->result__report_status = 0xFF; + pdata->result__stream_count = 0xFF; + + pdata->result__dss_actual_effective_spads_sd0 = 0xFFFF; + pdata->result__peak_signal_count_rate_mcps_sd0 = 0xFFFF; + pdata->result__ambient_count_rate_mcps_sd0 = 0xFFFF; + pdata->result__sigma_sd0 = 0xFFFF; + pdata->result__phase_sd0 = 0xFFFF; + pdata->result__final_crosstalk_corrected_range_mm_sd0 = 0xFFFF; + pdata->result__peak_signal_count_rate_crosstalk_corrected_mcps_sd0 = + 0xFFFF; + pdata->result__mm_inner_actual_effective_spads_sd0 = 0xFFFF; + pdata->result__mm_outer_actual_effective_spads_sd0 = 0xFFFF; + pdata->result__avg_signal_count_rate_mcps_sd0 = 0xFFFF; + + pdata->result__dss_actual_effective_spads_sd1 = 0xFFFF; + pdata->result__peak_signal_count_rate_mcps_sd1 = 0xFFFF; + pdata->result__ambient_count_rate_mcps_sd1 = 0xFFFF; + pdata->result__sigma_sd1 = 0xFFFF; + pdata->result__phase_sd1 = 0xFFFF; + pdata->result__final_crosstalk_corrected_range_mm_sd1 = 0xFFFF; + pdata->result__spare_0_sd1 = 0xFFFF; + pdata->result__spare_1_sd1 = 0xFFFF; + pdata->result__spare_2_sd1 = 0xFFFF; + pdata->result__spare_3_sd1 = 0xFF; + +} + + +void V53L1_init_zone_results_structure( + uint8_t active_zones, + VL53L1_zone_results_t *pdata) +{ + + + + + uint8_t z = 0; + VL53L1_zone_objects_t *pobjects; + + pdata->max_zones = VL53L1_MAX_USER_ZONES; + pdata->active_zones = active_zones; + + for (z = 0; z < pdata->max_zones; z++) { + pobjects = &(pdata->VL53L1_p_002[z]); + pobjects->cfg_device_state = VL53L1_DEVICESTATE_SW_STANDBY; + pobjects->rd_device_state = VL53L1_DEVICESTATE_SW_STANDBY; + pobjects->max_objects = VL53L1_MAX_RANGE_RESULTS; + pobjects->active_objects = 0; + } +} + +void V53L1_init_zone_dss_configs( + VL53L1_DEV Dev) +{ + + + + + VL53L1_LLDriverResults_t *pres = + VL53L1DevStructGetLLResultsHandle(Dev); + uint8_t z = 0; + uint8_t max_zones = VL53L1_MAX_USER_ZONES; + VL53L1_zone_private_dyn_cfgs_t *pdata = &(pres->zone_dyn_cfgs); + + for (z = 0; z < max_zones; z++) { + pdata->VL53L1_p_002[z].dss_mode = + VL53L1_DSS_CONTROL__MODE_TARGET_RATE; + pdata->VL53L1_p_002[z].dss_requested_effective_spad_count = 0; + } +} + + +void VL53L1_init_histogram_config_structure( + uint8_t even_bin0, + uint8_t even_bin1, + uint8_t even_bin2, + uint8_t even_bin3, + uint8_t even_bin4, + uint8_t even_bin5, + uint8_t odd_bin0, + uint8_t odd_bin1, + uint8_t odd_bin2, + uint8_t odd_bin3, + uint8_t odd_bin4, + uint8_t odd_bin5, + VL53L1_histogram_config_t *pdata) +{ + + + + + + + pdata->histogram_config__low_amb_even_bin_0_1 = + (even_bin1 << 4) + even_bin0; + pdata->histogram_config__low_amb_even_bin_2_3 = + (even_bin3 << 4) + even_bin2; + pdata->histogram_config__low_amb_even_bin_4_5 = + (even_bin5 << 4) + even_bin4; + + pdata->histogram_config__low_amb_odd_bin_0_1 = + (odd_bin1 << 4) + odd_bin0; + pdata->histogram_config__low_amb_odd_bin_2_3 = + (odd_bin3 << 4) + odd_bin2; + pdata->histogram_config__low_amb_odd_bin_4_5 = + (odd_bin5 << 4) + odd_bin4; + + pdata->histogram_config__mid_amb_even_bin_0_1 = + pdata->histogram_config__low_amb_even_bin_0_1; + pdata->histogram_config__mid_amb_even_bin_2_3 = + pdata->histogram_config__low_amb_even_bin_2_3; + pdata->histogram_config__mid_amb_even_bin_4_5 = + pdata->histogram_config__low_amb_even_bin_4_5; + + pdata->histogram_config__mid_amb_odd_bin_0_1 = + pdata->histogram_config__low_amb_odd_bin_0_1; + pdata->histogram_config__mid_amb_odd_bin_2 = odd_bin2; + pdata->histogram_config__mid_amb_odd_bin_3_4 = + (odd_bin4 << 4) + odd_bin3; + pdata->histogram_config__mid_amb_odd_bin_5 = odd_bin5; + + pdata->histogram_config__user_bin_offset = 0x00; + + pdata->histogram_config__high_amb_even_bin_0_1 = + pdata->histogram_config__low_amb_even_bin_0_1; + pdata->histogram_config__high_amb_even_bin_2_3 = + pdata->histogram_config__low_amb_even_bin_2_3; + pdata->histogram_config__high_amb_even_bin_4_5 = + pdata->histogram_config__low_amb_even_bin_4_5; + + pdata->histogram_config__high_amb_odd_bin_0_1 = + pdata->histogram_config__low_amb_odd_bin_0_1; + pdata->histogram_config__high_amb_odd_bin_2_3 = + pdata->histogram_config__low_amb_odd_bin_2_3; + pdata->histogram_config__high_amb_odd_bin_4_5 = + pdata->histogram_config__low_amb_odd_bin_4_5; + + + + + pdata->histogram_config__amb_thresh_low = 0xFFFF; + pdata->histogram_config__amb_thresh_high = 0xFFFF; + + + + + pdata->histogram_config__spad_array_selection = 0x00; + +} + +void VL53L1_init_histogram_multizone_config_structure( + uint8_t even_bin0, + uint8_t even_bin1, + uint8_t even_bin2, + uint8_t even_bin3, + uint8_t even_bin4, + uint8_t even_bin5, + uint8_t odd_bin0, + uint8_t odd_bin1, + uint8_t odd_bin2, + uint8_t odd_bin3, + uint8_t odd_bin4, + uint8_t odd_bin5, + VL53L1_histogram_config_t *pdata) +{ + + + + + + + + pdata->histogram_config__low_amb_even_bin_0_1 = + (even_bin1 << 4) + even_bin0; + pdata->histogram_config__low_amb_even_bin_2_3 = + (even_bin3 << 4) + even_bin2; + pdata->histogram_config__low_amb_even_bin_4_5 = + (even_bin5 << 4) + even_bin4; + + pdata->histogram_config__low_amb_odd_bin_0_1 = + pdata->histogram_config__low_amb_even_bin_0_1; + pdata->histogram_config__low_amb_odd_bin_2_3 + = pdata->histogram_config__low_amb_even_bin_2_3; + pdata->histogram_config__low_amb_odd_bin_4_5 + = pdata->histogram_config__low_amb_even_bin_4_5; + + pdata->histogram_config__mid_amb_even_bin_0_1 = + pdata->histogram_config__low_amb_even_bin_0_1; + pdata->histogram_config__mid_amb_even_bin_2_3 + = pdata->histogram_config__low_amb_even_bin_2_3; + pdata->histogram_config__mid_amb_even_bin_4_5 + = pdata->histogram_config__low_amb_even_bin_4_5; + + pdata->histogram_config__mid_amb_odd_bin_0_1 + = pdata->histogram_config__low_amb_odd_bin_0_1; + pdata->histogram_config__mid_amb_odd_bin_2 = odd_bin2; + pdata->histogram_config__mid_amb_odd_bin_3_4 = + (odd_bin4 << 4) + odd_bin3; + pdata->histogram_config__mid_amb_odd_bin_5 = odd_bin5; + + pdata->histogram_config__user_bin_offset = 0x00; + + pdata->histogram_config__high_amb_even_bin_0_1 = + (odd_bin1 << 4) + odd_bin0; + pdata->histogram_config__high_amb_even_bin_2_3 = + (odd_bin3 << 4) + odd_bin2; + pdata->histogram_config__high_amb_even_bin_4_5 = + (odd_bin5 << 4) + odd_bin4; + + pdata->histogram_config__high_amb_odd_bin_0_1 + = pdata->histogram_config__high_amb_even_bin_0_1; + pdata->histogram_config__high_amb_odd_bin_2_3 + = pdata->histogram_config__high_amb_even_bin_2_3; + pdata->histogram_config__high_amb_odd_bin_4_5 + = pdata->histogram_config__high_amb_even_bin_4_5; + + + + + pdata->histogram_config__amb_thresh_low = 0xFFFF; + pdata->histogram_config__amb_thresh_high = 0xFFFF; + + + + + pdata->histogram_config__spad_array_selection = 0x00; +} + + +void VL53L1_init_xtalk_bin_data_struct( + uint32_t bin_value, + uint16_t VL53L1_p_024, + VL53L1_xtalk_histogram_shape_t *pdata) +{ + + + + + + + uint16_t i = 0; + + pdata->zone_id = 0; + pdata->time_stamp = 0; + + pdata->VL53L1_p_022 = 0; + pdata->VL53L1_p_023 = VL53L1_XTALK_HISTO_BINS; + pdata->VL53L1_p_024 = (uint8_t)VL53L1_p_024; + + pdata->phasecal_result__reference_phase = 0; + pdata->phasecal_result__vcsel_start = 0; + pdata->cal_config__vcsel_start = 0; + + pdata->vcsel_width = 0; + pdata->VL53L1_p_019 = 0; + + pdata->zero_distance_phase = 0; + + for (i = 0; i < VL53L1_XTALK_HISTO_BINS; i++) { + if (i < VL53L1_p_024) + pdata->bin_data[i] = bin_value; + else + pdata->bin_data[i] = 0; + } +} + + +void VL53L1_i2c_encode_uint16_t( + uint16_t ip_value, + uint16_t count, + uint8_t *pbuffer) +{ + + + + + + + uint16_t i = 0; + uint16_t VL53L1_p_002 = 0; + + VL53L1_p_002 = ip_value; + + for (i = 0; i < count; i++) { + pbuffer[count-i-1] = (uint8_t)(VL53L1_p_002 & 0x00FF); + VL53L1_p_002 = VL53L1_p_002 >> 8; + } +} + +uint16_t VL53L1_i2c_decode_uint16_t( + uint16_t count, + uint8_t *pbuffer) +{ + + + + + + + uint16_t value = 0x00; + + while (count-- > 0) + value = (value << 8) | (uint16_t)*pbuffer++; + + return value; +} + + +void VL53L1_i2c_encode_int16_t( + int16_t ip_value, + uint16_t count, + uint8_t *pbuffer) +{ + + + + + + + uint16_t i = 0; + int16_t VL53L1_p_002 = 0; + + VL53L1_p_002 = ip_value; + + for (i = 0; i < count; i++) { + pbuffer[count-i-1] = (uint8_t)(VL53L1_p_002 & 0x00FF); + VL53L1_p_002 = VL53L1_p_002 >> 8; + } +} + +int16_t VL53L1_i2c_decode_int16_t( + uint16_t count, + uint8_t *pbuffer) +{ + + + + + + + int16_t value = 0x00; + + + + if (*pbuffer >= 0x80) + value = 0xFFFF; + + while (count-- > 0) + value = (value << 8) | (int16_t)*pbuffer++; + + return value; +} + +void VL53L1_i2c_encode_uint32_t( + uint32_t ip_value, + uint16_t count, + uint8_t *pbuffer) +{ + + + + + + + uint16_t i = 0; + uint32_t VL53L1_p_002 = 0; + + VL53L1_p_002 = ip_value; + + for (i = 0; i < count; i++) { + pbuffer[count-i-1] = (uint8_t)(VL53L1_p_002 & 0x00FF); + VL53L1_p_002 = VL53L1_p_002 >> 8; + } +} + +uint32_t VL53L1_i2c_decode_uint32_t( + uint16_t count, + uint8_t *pbuffer) +{ + + + + + + + uint32_t value = 0x00; + + while (count-- > 0) + value = (value << 8) | (uint32_t)*pbuffer++; + + return value; +} + + +uint32_t VL53L1_i2c_decode_with_mask( + uint16_t count, + uint8_t *pbuffer, + uint32_t bit_mask, + uint32_t down_shift, + uint32_t offset) +{ + + + + + + + uint32_t value = 0x00; + + + + while (count-- > 0) + value = (value << 8) | (uint32_t)*pbuffer++; + + + + value = value & bit_mask; + if (down_shift > 0) + value = value >> down_shift; + + + + value = value + offset; + + return value; +} + + +void VL53L1_i2c_encode_int32_t( + int32_t ip_value, + uint16_t count, + uint8_t *pbuffer) +{ + + + + + + + uint16_t i = 0; + int32_t VL53L1_p_002 = 0; + + VL53L1_p_002 = ip_value; + + for (i = 0; i < count; i++) { + pbuffer[count-i-1] = (uint8_t)(VL53L1_p_002 & 0x00FF); + VL53L1_p_002 = VL53L1_p_002 >> 8; + } +} + +int32_t VL53L1_i2c_decode_int32_t( + uint16_t count, + uint8_t *pbuffer) +{ + + + + + + + int32_t value = 0x00; + + + + if (*pbuffer >= 0x80) + value = 0xFFFFFFFF; + + while (count-- > 0) + value = (value << 8) | (int32_t)*pbuffer++; + + return value; +} + + +VL53L1_Error VL53L1_start_test( + VL53L1_DEV Dev, + uint8_t test_mode__ctrl) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) { + + status = VL53L1_WrByte( + Dev, + VL53L1_TEST_MODE__CTRL, + test_mode__ctrl); + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_firmware_enable_register( + VL53L1_DEV Dev, + uint8_t value) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + pdev->sys_ctrl.firmware__enable = value; + + status = VL53L1_WrByte( + Dev, + VL53L1_FIRMWARE__ENABLE, + pdev->sys_ctrl.firmware__enable); + + return status; +} + +VL53L1_Error VL53L1_enable_firmware( + VL53L1_DEV Dev) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + status = VL53L1_set_firmware_enable_register(Dev, 0x01); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_disable_firmware( + VL53L1_DEV Dev) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + status = VL53L1_set_firmware_enable_register(Dev, 0x00); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_powerforce_register( + VL53L1_DEV Dev, + uint8_t value) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + pdev->sys_ctrl.power_management__go1_power_force = value; + + status = VL53L1_WrByte( + Dev, + VL53L1_POWER_MANAGEMENT__GO1_POWER_FORCE, + pdev->sys_ctrl.power_management__go1_power_force); + + return status; +} + + +VL53L1_Error VL53L1_enable_powerforce( + VL53L1_DEV Dev) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + status = VL53L1_set_powerforce_register(Dev, 0x01); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_disable_powerforce( + VL53L1_DEV Dev) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + status = VL53L1_set_powerforce_register(Dev, 0x00); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_clear_interrupt( + VL53L1_DEV Dev) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + pdev->sys_ctrl.system__interrupt_clear = VL53L1_CLEAR_RANGE_INT; + + status = VL53L1_WrByte( + Dev, + VL53L1_SYSTEM__INTERRUPT_CLEAR, + pdev->sys_ctrl.system__interrupt_clear); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_force_shadow_stream_count_to_zero( + VL53L1_DEV Dev) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_disable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) { + status = VL53L1_WrByte( + Dev, + VL53L1_SHADOW_RESULT__STREAM_COUNT, + 0x00); + } + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_firmware(Dev); + + return status; +} + + +uint32_t VL53L1_calc_macro_period_us( + uint16_t fast_osc_frequency, + uint8_t VL53L1_p_009) +{ + + + + + + + + + uint32_t pll_period_us = 0; + uint8_t VL53L1_p_031 = 0; + uint32_t macro_period_us = 0; + + LOG_FUNCTION_START(""); + + + + + + + pll_period_us = VL53L1_calc_pll_period_us(fast_osc_frequency); + + + + + + + VL53L1_p_031 = VL53L1_decode_vcsel_period(VL53L1_p_009); + + + + + + + + + + + + + + + macro_period_us = + (uint32_t)VL53L1_MACRO_PERIOD_VCSEL_PERIODS * + pll_period_us; + macro_period_us = macro_period_us >> 6; + + macro_period_us = macro_period_us * (uint32_t)VL53L1_p_031; + macro_period_us = macro_period_us >> 6; + + + + + + + + + + + + + + LOG_FUNCTION_END(0); + + return macro_period_us; +} + + +uint16_t VL53L1_calc_range_ignore_threshold( + uint32_t central_rate, + int16_t x_gradient, + int16_t y_gradient, + uint8_t rate_mult) +{ + + + + + + + + + + + + + + + + int32_t range_ignore_thresh_int = 0; + uint16_t range_ignore_thresh_kcps = 0; + int32_t central_rate_int = 0; + int16_t x_gradient_int = 0; + int16_t y_gradient_int = 0; + + LOG_FUNCTION_START(""); + + + + + central_rate_int = ((int32_t)central_rate * (1 << 4)) / (1000); + + if (x_gradient < 0) + x_gradient_int = x_gradient * -1; + + if (y_gradient < 0) + y_gradient_int = y_gradient * -1; + + + + + + + + + range_ignore_thresh_int = (8 * x_gradient_int * 4) + + (8 * y_gradient_int * 4); + + + + + range_ignore_thresh_int = range_ignore_thresh_int / 1000; + + + + + range_ignore_thresh_int = range_ignore_thresh_int + central_rate_int; + + + + + range_ignore_thresh_int = (int32_t)rate_mult * range_ignore_thresh_int; + + range_ignore_thresh_int = (range_ignore_thresh_int + (1<<4)) / (1<<5); + + + + + if (range_ignore_thresh_int > 0xFFFF) + range_ignore_thresh_kcps = 0xFFFF; + else + range_ignore_thresh_kcps = (uint16_t)range_ignore_thresh_int; + + + + + + + + LOG_FUNCTION_END(0); + + return range_ignore_thresh_kcps; +} + + +uint32_t VL53L1_calc_timeout_mclks( + uint32_t timeout_us, + uint32_t macro_period_us) +{ + + + + + + + + + + + uint32_t timeout_mclks = 0; + + LOG_FUNCTION_START(""); + + timeout_mclks = + ((timeout_us << 12) + (macro_period_us>>1)) / + macro_period_us; + + LOG_FUNCTION_END(0); + + return timeout_mclks; +} + + +uint16_t VL53L1_calc_encoded_timeout( + uint32_t timeout_us, + uint32_t macro_period_us) +{ + + + + + + + + + + + uint32_t timeout_mclks = 0; + uint16_t timeout_encoded = 0; + + LOG_FUNCTION_START(""); + + timeout_mclks = + VL53L1_calc_timeout_mclks(timeout_us, macro_period_us); + + timeout_encoded = + VL53L1_encode_timeout(timeout_mclks); + + + + + + + + + + + LOG_FUNCTION_END(0); + + return timeout_encoded; +} + + +uint32_t VL53L1_calc_timeout_us( + uint32_t timeout_mclks, + uint32_t macro_period_us) +{ + + + + + + + + + + + uint32_t timeout_us = 0; + uint64_t tmp = 0; + + LOG_FUNCTION_START(""); + + tmp = (uint64_t)timeout_mclks * (uint64_t)macro_period_us; + tmp += 0x00800; + tmp = tmp >> 12; + + timeout_us = (uint32_t)tmp; + + + + + + + + + + + + LOG_FUNCTION_END(0); + + return timeout_us; +} + +uint32_t VL53L1_calc_crosstalk_plane_offset_with_margin( + uint32_t plane_offset_kcps, + int16_t margin_offset_kcps) +{ + uint32_t plane_offset_with_margin = 0; + int32_t plane_offset_kcps_temp = 0; + + LOG_FUNCTION_START(""); + + plane_offset_kcps_temp = + (int32_t)plane_offset_kcps + + (int32_t)margin_offset_kcps; + + if (plane_offset_kcps_temp < 0) + plane_offset_kcps_temp = 0; + else + if (plane_offset_kcps_temp > 0x3FFFF) + plane_offset_kcps_temp = 0x3FFFF; + + plane_offset_with_margin = (uint32_t) plane_offset_kcps_temp; + + LOG_FUNCTION_END(0); + + return plane_offset_with_margin; + +} + +uint32_t VL53L1_calc_decoded_timeout_us( + uint16_t timeout_encoded, + uint32_t macro_period_us) +{ + + + + + + + + + + + uint32_t timeout_mclks = 0; + uint32_t timeout_us = 0; + + LOG_FUNCTION_START(""); + + timeout_mclks = + VL53L1_decode_timeout(timeout_encoded); + + timeout_us = + VL53L1_calc_timeout_us(timeout_mclks, macro_period_us); + + LOG_FUNCTION_END(0); + + return timeout_us; +} + + +uint16_t VL53L1_encode_timeout(uint32_t timeout_mclks) +{ + + + + + + uint16_t encoded_timeout = 0; + uint32_t ls_byte = 0; + uint16_t ms_byte = 0; + + if (timeout_mclks > 0) { + ls_byte = timeout_mclks - 1; + + while ((ls_byte & 0xFFFFFF00) > 0) { + ls_byte = ls_byte >> 1; + ms_byte++; + } + + encoded_timeout = (ms_byte << 8) + + (uint16_t) (ls_byte & 0x000000FF); + } + + return encoded_timeout; +} + + +uint32_t VL53L1_decode_timeout(uint16_t encoded_timeout) +{ + + + + + + + uint32_t timeout_macro_clks = 0; + + timeout_macro_clks = ((uint32_t) (encoded_timeout & 0x00FF) + << (uint32_t) ((encoded_timeout & 0xFF00) >> 8)) + 1; + + return timeout_macro_clks; +} + + +VL53L1_Error VL53L1_calc_timeout_register_values( + uint32_t phasecal_config_timeout_us, + uint32_t mm_config_timeout_us, + uint32_t range_config_timeout_us, + uint16_t fast_osc_frequency, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming) +{ + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + uint32_t macro_period_us = 0; + uint32_t timeout_mclks = 0; + uint16_t timeout_encoded = 0; + + LOG_FUNCTION_START(""); + + if (fast_osc_frequency == 0) { + status = VL53L1_ERROR_DIVISION_BY_ZERO; + } else { + + + macro_period_us = + VL53L1_calc_macro_period_us( + fast_osc_frequency, + ptiming->range_config__vcsel_period_a); + + + + timeout_mclks = + VL53L1_calc_timeout_mclks( + phasecal_config_timeout_us, + macro_period_us); + + + + if (timeout_mclks > 0xFF) + timeout_mclks = 0xFF; + + pgeneral->phasecal_config__timeout_macrop = + (uint8_t)timeout_mclks; + + + + timeout_encoded = + VL53L1_calc_encoded_timeout( + mm_config_timeout_us, + macro_period_us); + + ptiming->mm_config__timeout_macrop_a_hi = + (uint8_t)((timeout_encoded & 0xFF00) >> 8); + ptiming->mm_config__timeout_macrop_a_lo = + (uint8_t) (timeout_encoded & 0x00FF); + + + + timeout_encoded = + VL53L1_calc_encoded_timeout( + range_config_timeout_us, + macro_period_us); + + ptiming->range_config__timeout_macrop_a_hi = + (uint8_t)((timeout_encoded & 0xFF00) >> 8); + ptiming->range_config__timeout_macrop_a_lo = + (uint8_t) (timeout_encoded & 0x00FF); + + + + macro_period_us = + VL53L1_calc_macro_period_us( + fast_osc_frequency, + ptiming->range_config__vcsel_period_b); + + + + timeout_encoded = + VL53L1_calc_encoded_timeout( + mm_config_timeout_us, + macro_period_us); + + ptiming->mm_config__timeout_macrop_b_hi = + (uint8_t)((timeout_encoded & 0xFF00) >> 8); + ptiming->mm_config__timeout_macrop_b_lo = + (uint8_t) (timeout_encoded & 0x00FF); + + + + timeout_encoded = VL53L1_calc_encoded_timeout( + range_config_timeout_us, + macro_period_us); + + ptiming->range_config__timeout_macrop_b_hi = + (uint8_t)((timeout_encoded & 0xFF00) >> 8); + ptiming->range_config__timeout_macrop_b_lo = + (uint8_t) (timeout_encoded & 0x00FF); + } + + LOG_FUNCTION_END(0); + + return status; + +} + + +uint8_t VL53L1_encode_vcsel_period(uint8_t VL53L1_p_031) +{ + + + + + + + uint8_t vcsel_period_reg = 0; + + vcsel_period_reg = (VL53L1_p_031 >> 1) - 1; + + return vcsel_period_reg; +} + + +uint32_t VL53L1_decode_unsigned_integer( + uint8_t *pbuffer, + uint8_t no_of_bytes) +{ + + + + + + uint8_t i = 0; + uint32_t decoded_value = 0; + + for (i = 0; i < no_of_bytes; i++) + decoded_value = (decoded_value << 8) + (uint32_t)pbuffer[i]; + + return decoded_value; +} + + +void VL53L1_encode_unsigned_integer( + uint32_t ip_value, + uint8_t no_of_bytes, + uint8_t *pbuffer) +{ + + + + + + uint8_t i = 0; + uint32_t VL53L1_p_002 = 0; + + VL53L1_p_002 = ip_value; + for (i = 0; i < no_of_bytes; i++) { + pbuffer[no_of_bytes-i-1] = VL53L1_p_002 & 0x00FF; + VL53L1_p_002 = VL53L1_p_002 >> 8; + } +} + + +VL53L1_Error VL53L1_hist_copy_and_scale_ambient_info( + VL53L1_zone_hist_info_t *pidata, + VL53L1_histogram_bin_data_t *podata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + int64_t VL53L1_p_008 = 0; + int64_t tmpi = 0; + int64_t tmpo = 0; + + LOG_FUNCTION_START(""); + + + if (pidata->result__dss_actual_effective_spads == 0) { + status = VL53L1_ERROR_DIVISION_BY_ZERO; + } else { + if (pidata->number_of_ambient_bins > 0 && + podata->number_of_ambient_bins == 0) { + + + + + + + + + + + tmpo = 1 + (int64_t)podata->total_periods_elapsed; + tmpo *= + (int64_t)podata->result__dss_actual_effective_spads; + + tmpi = 1 + (int64_t)pidata->total_periods_elapsed; + tmpi *= + (int64_t)pidata->result__dss_actual_effective_spads; + + VL53L1_p_008 = tmpo * + (int64_t)pidata->ambient_events_sum; + VL53L1_p_008 += (tmpi/2); + + + + + if (tmpi != 0) + VL53L1_p_008 = do_division_s(VL53L1_p_008, tmpi); + + podata->ambient_events_sum = (int32_t)VL53L1_p_008; + + + + + + + podata->VL53L1_p_004 = + podata->ambient_events_sum; + podata->VL53L1_p_004 += + ((int32_t)pidata->number_of_ambient_bins / 2); + podata->VL53L1_p_004 /= + (int32_t)pidata->number_of_ambient_bins; + } + } + + LOG_FUNCTION_END(0); + + return status; +} + + +void VL53L1_hist_get_bin_sequence_config( + VL53L1_DEV Dev, + VL53L1_histogram_bin_data_t *pdata) +{ + + + + + + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + int32_t amb_thresh_low = 0; + int32_t amb_thresh_high = 0; + + uint8_t i = 0; + + LOG_FUNCTION_START(""); + + + + + amb_thresh_low = 1024 * + (int32_t)pdev->hist_cfg.histogram_config__amb_thresh_low; + amb_thresh_high = 1024 * + (int32_t)pdev->hist_cfg.histogram_config__amb_thresh_high; + + + + + + + + + + + if ((pdev->ll_state.rd_stream_count & 0x01) == 0) { + + pdata->bin_seq[5] = + pdev->hist_cfg.histogram_config__mid_amb_even_bin_4_5 >> 4; + pdata->bin_seq[4] = + pdev->hist_cfg.histogram_config__mid_amb_even_bin_4_5 & 0x0F; + pdata->bin_seq[3] = + pdev->hist_cfg.histogram_config__mid_amb_even_bin_2_3 >> 4; + pdata->bin_seq[2] = + pdev->hist_cfg.histogram_config__mid_amb_even_bin_2_3 & 0x0F; + pdata->bin_seq[1] = + pdev->hist_cfg.histogram_config__mid_amb_even_bin_0_1 >> 4; + pdata->bin_seq[0] = + pdev->hist_cfg.histogram_config__mid_amb_even_bin_0_1 & 0x0F; + + if (pdata->ambient_events_sum > amb_thresh_high) { + pdata->bin_seq[5] = + pdev->hist_cfg.histogram_config__high_amb_even_bin_4_5 + >> 4; + pdata->bin_seq[4] = + pdev->hist_cfg.histogram_config__high_amb_even_bin_4_5 + & 0x0F; + pdata->bin_seq[3] = + pdev->hist_cfg.histogram_config__high_amb_even_bin_2_3 + >> 4; + pdata->bin_seq[2] = + pdev->hist_cfg.histogram_config__high_amb_even_bin_2_3 + & 0x0F; + pdata->bin_seq[1] = + pdev->hist_cfg.histogram_config__high_amb_even_bin_0_1 + >> 4; + pdata->bin_seq[0] = + pdev->hist_cfg.histogram_config__high_amb_even_bin_0_1 + & 0x0F; + } + + if (pdata->ambient_events_sum < amb_thresh_low) { + pdata->bin_seq[5] = + pdev->hist_cfg.histogram_config__low_amb_even_bin_4_5 + >> 4; + pdata->bin_seq[4] = + pdev->hist_cfg.histogram_config__low_amb_even_bin_4_5 + & 0x0F; + pdata->bin_seq[3] = + pdev->hist_cfg.histogram_config__low_amb_even_bin_2_3 + >> 4; + pdata->bin_seq[2] = + pdev->hist_cfg.histogram_config__low_amb_even_bin_2_3 + & 0x0F; + pdata->bin_seq[1] = + pdev->hist_cfg.histogram_config__low_amb_even_bin_0_1 + >> 4; + pdata->bin_seq[0] = + pdev->hist_cfg.histogram_config__low_amb_even_bin_0_1 + & 0x0F; + } + + } else { + pdata->bin_seq[5] = + pdev->hist_cfg.histogram_config__mid_amb_odd_bin_5 + & 0x0F; + pdata->bin_seq[4] = + pdev->hist_cfg.histogram_config__mid_amb_odd_bin_3_4 + & 0x0F; + pdata->bin_seq[3] = + pdev->hist_cfg.histogram_config__mid_amb_odd_bin_3_4 + >> 4; + pdata->bin_seq[2] = + pdev->hist_cfg.histogram_config__mid_amb_odd_bin_2 & + 0x0F; + pdata->bin_seq[1] = + pdev->hist_cfg.histogram_config__mid_amb_odd_bin_0_1 + >> 4; + pdata->bin_seq[0] = + pdev->hist_cfg.histogram_config__mid_amb_odd_bin_0_1 + & 0x0F; + + if (pdata->ambient_events_sum > amb_thresh_high) { + pdata->bin_seq[5] = + pdev->hist_cfg.histogram_config__high_amb_odd_bin_4_5 + >> 4; + pdata->bin_seq[4] = + pdev->hist_cfg.histogram_config__high_amb_odd_bin_4_5 + & 0x0F; + pdata->bin_seq[3] = + pdev->hist_cfg.histogram_config__high_amb_odd_bin_2_3 + >> 4; + pdata->bin_seq[2] = + pdev->hist_cfg.histogram_config__high_amb_odd_bin_2_3 + & 0x0F; + pdata->bin_seq[1] = + pdev->hist_cfg.histogram_config__high_amb_odd_bin_0_1 + >> 4; + pdata->bin_seq[0] = + pdev->hist_cfg.histogram_config__high_amb_odd_bin_0_1 + & 0x0F; + } + + if (pdata->ambient_events_sum < amb_thresh_low) { + pdata->bin_seq[5] = + pdev->hist_cfg.histogram_config__low_amb_odd_bin_4_5 + >> 4; + pdata->bin_seq[4] = + pdev->hist_cfg.histogram_config__low_amb_odd_bin_4_5 + & 0x0F; + pdata->bin_seq[3] = + pdev->hist_cfg.histogram_config__low_amb_odd_bin_2_3 + >> 4; + pdata->bin_seq[2] = + pdev->hist_cfg.histogram_config__low_amb_odd_bin_2_3 + & 0x0F; + pdata->bin_seq[1] = + pdev->hist_cfg.histogram_config__low_amb_odd_bin_0_1 + >> 4; + pdata->bin_seq[0] = + pdev->hist_cfg.histogram_config__low_amb_odd_bin_0_1 + & 0x0F; + } + } + + + + + for (i = 0; i < VL53L1_MAX_BIN_SEQUENCE_LENGTH; i++) + pdata->bin_rep[i] = 1; + + LOG_FUNCTION_END(0); + +} + + +VL53L1_Error VL53L1_hist_phase_consistency_check( + VL53L1_DEV Dev, + VL53L1_zone_hist_info_t *phist_prev, + VL53L1_zone_objects_t *prange_prev, + VL53L1_range_results_t *prange_curr) +{ + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + + uint8_t lc = 0; + uint8_t p = 0; + + uint16_t phase_delta = 0; + uint16_t phase_tolerance = 0; + + int32_t events_delta = 0; + int32_t events_tolerance = 0; + + + + uint8_t event_sigma; + uint16_t event_min_spad_count; + uint16_t min_max_tolerance; + uint8_t pht; + + VL53L1_DeviceError range_status = 0; + + LOG_FUNCTION_START(""); + + event_sigma = + pdev->histpostprocess.algo__consistency_check__event_sigma; + event_min_spad_count = + pdev->histpostprocess.algo__consistency_check__event_min_spad_count; + min_max_tolerance = + pdev->histpostprocess.algo__consistency_check__min_max_tolerance; + + + + pht = pdev->histpostprocess.algo__consistency_check__phase_tolerance; + phase_tolerance = (uint16_t)pht; + phase_tolerance = phase_tolerance << 8; + + + + + if (prange_prev->rd_device_state != + VL53L1_DEVICESTATE_RANGING_GATHER_DATA && + prange_prev->rd_device_state != + VL53L1_DEVICESTATE_RANGING_OUTPUT_DATA) + return status; + + + + + if (phase_tolerance == 0) + return status; + + for (lc = 0; lc < prange_curr->active_results; lc++) { + + if (!((prange_curr->VL53L1_p_002[lc].range_status == + VL53L1_DEVICEERROR_RANGECOMPLETE) || + (prange_curr->VL53L1_p_002[lc].range_status == + VL53L1_DEVICEERROR_RANGECOMPLETE_NO_WRAP_CHECK))) + continue; + + + + + + + + + if (prange_prev->active_objects == 0) + prange_curr->VL53L1_p_002[lc].range_status = + VL53L1_DEVICEERROR_PREV_RANGE_NO_TARGETS; + else + prange_curr->VL53L1_p_002[lc].range_status = + VL53L1_DEVICEERROR_PHASECONSISTENCY; + + + + + + + + + + + for (p = 0; p < prange_prev->active_objects; p++) { + + if (prange_curr->VL53L1_p_002[lc].VL53L1_p_014 > + prange_prev->VL53L1_p_002[p].VL53L1_p_014) { + phase_delta = + prange_curr->VL53L1_p_002[lc].VL53L1_p_014 - + prange_prev->VL53L1_p_002[p].VL53L1_p_014; + } else { + phase_delta = + prange_prev->VL53L1_p_002[p].VL53L1_p_014 - + prange_curr->VL53L1_p_002[lc].VL53L1_p_014; + } + + if (phase_delta < phase_tolerance) { + + + + + + + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_hist_events_consistency_check( + event_sigma, + event_min_spad_count, + phist_prev, + &(prange_prev->VL53L1_p_002[p]), + &(prange_curr->VL53L1_p_002[lc]), + &events_tolerance, + &events_delta, + &range_status); + + + + + + + + + + if (status == VL53L1_ERROR_NONE && + range_status == + VL53L1_DEVICEERROR_RANGECOMPLETE) + status = + VL53L1_hist_merged_pulse_check( + min_max_tolerance, + &(prange_curr->VL53L1_p_002[lc]), + &range_status); + + prange_curr->VL53L1_p_002[lc].range_status = + range_status; + } + } + + } + + LOG_FUNCTION_END(status); + + return status; +} + + + + +VL53L1_Error VL53L1_hist_events_consistency_check( + uint8_t event_sigma, + uint16_t min_effective_spad_count, + VL53L1_zone_hist_info_t *phist_prev, + VL53L1_object_data_t *prange_prev, + VL53L1_range_data_t *prange_curr, + int32_t *pevents_tolerance, + int32_t *pevents_delta, + VL53L1_DeviceError *prange_status) +{ + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + int64_t tmpp = 0; + int64_t tmpc = 0; + int64_t events_scaler = 0; + int64_t events_scaler_sq = 0; + int64_t c_signal_events = 0; + int64_t c_sig_noise_sq = 0; + int64_t c_amb_noise_sq = 0; + int64_t p_amb_noise_sq = 0; + + int32_t p_signal_events = 0; + uint32_t noise_sq_sum = 0; + + + + + if (event_sigma == 0) { + *prange_status = VL53L1_DEVICEERROR_RANGECOMPLETE; + return status; + } + + + + + tmpp = 1 + (int64_t)phist_prev->total_periods_elapsed; + tmpp *= (int64_t)phist_prev->result__dss_actual_effective_spads; + + + + + tmpc = 1 + (int64_t)prange_curr->total_periods_elapsed; + tmpc *= (int64_t)prange_curr->VL53L1_p_006; + + + + + events_scaler = tmpp * 4096; + events_scaler += (tmpc/2); + if (tmpc != 0) + events_scaler = do_division_s(events_scaler, tmpc); + + events_scaler_sq = events_scaler * events_scaler; + events_scaler_sq += 2048; + events_scaler_sq /= 4096; + + + + + c_signal_events = (int64_t)prange_curr->VL53L1_p_021; + c_signal_events -= (int64_t)prange_curr->VL53L1_p_020; + c_signal_events *= (int64_t)events_scaler; + c_signal_events += 2048; + c_signal_events /= 4096; + + c_sig_noise_sq = (int64_t)events_scaler_sq; + c_sig_noise_sq *= (int64_t)prange_curr->VL53L1_p_021; + c_sig_noise_sq += 2048; + c_sig_noise_sq /= 4096; + + c_amb_noise_sq = (int64_t)events_scaler_sq; + c_amb_noise_sq *= (int64_t)prange_curr->VL53L1_p_020; + c_amb_noise_sq += 2048; + c_amb_noise_sq /= 4096; + + + + c_amb_noise_sq += 2; + c_amb_noise_sq /= 4; + + + + + + + + p_amb_noise_sq = + (int64_t)prange_prev->VL53L1_p_020; + + + + p_amb_noise_sq += 2; + p_amb_noise_sq /= 4; + + noise_sq_sum = + (uint32_t)prange_prev->VL53L1_p_021 + + (uint32_t)c_sig_noise_sq + + (uint32_t)p_amb_noise_sq + + (uint32_t)c_amb_noise_sq; + + *pevents_tolerance = + (int32_t)VL53L1_isqrt(noise_sq_sum * 16); + + *pevents_tolerance *= (int32_t)event_sigma; + *pevents_tolerance += 32; + *pevents_tolerance /= 64; + + p_signal_events = (int32_t)prange_prev->VL53L1_p_021; + p_signal_events -= (int32_t)prange_prev->VL53L1_p_020; + + if ((int32_t)c_signal_events > p_signal_events) + *pevents_delta = + (int32_t)c_signal_events - p_signal_events; + else + *pevents_delta = + p_signal_events - (int32_t)c_signal_events; + + if (*pevents_delta > *pevents_tolerance && + prange_curr->VL53L1_p_006 > min_effective_spad_count) + *prange_status = VL53L1_DEVICEERROR_EVENTCONSISTENCY; + else + *prange_status = VL53L1_DEVICEERROR_RANGECOMPLETE; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + return status; +} + + + + + +VL53L1_Error VL53L1_hist_merged_pulse_check( + int16_t min_max_tolerance_mm, + VL53L1_range_data_t *pdata, + VL53L1_DeviceError *prange_status) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + int16_t delta_mm = 0; + + if (pdata->max_range_mm > pdata->min_range_mm) + delta_mm = + pdata->max_range_mm - pdata->min_range_mm; + else + delta_mm = + pdata->min_range_mm - pdata->max_range_mm; + + if (min_max_tolerance_mm > 0 && + delta_mm > min_max_tolerance_mm) + *prange_status = VL53L1_DEVICEERROR_RANGECOMPLETE_MERGED_PULSE; + else + *prange_status = VL53L1_DEVICEERROR_RANGECOMPLETE; + + return status; +} + + + + + +VL53L1_Error VL53L1_hist_xmonitor_consistency_check( + VL53L1_DEV Dev, + VL53L1_zone_hist_info_t *phist_prev, + VL53L1_zone_objects_t *prange_prev, + VL53L1_range_data_t *prange_curr) +{ + + + + + + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + + int32_t events_delta = 0; + int32_t events_tolerance = 0; + uint8_t event_sigma; + uint16_t min_spad_count; + + event_sigma = pdev->histpostprocess.algo__crosstalk_detect_event_sigma; + min_spad_count = + pdev->histpostprocess.algo__consistency_check__event_min_spad_count; + + if (prange_curr->range_status == VL53L1_DEVICEERROR_RANGECOMPLETE || + prange_curr->range_status == + VL53L1_DEVICEERROR_RANGECOMPLETE_NO_WRAP_CHECK || + prange_curr->range_status == + VL53L1_DEVICEERROR_EVENTCONSISTENCY) { + + if (prange_prev->xmonitor.range_status == + VL53L1_DEVICEERROR_RANGECOMPLETE || + prange_prev->xmonitor.range_status == + VL53L1_DEVICEERROR_RANGECOMPLETE_NO_WRAP_CHECK || + prange_prev->xmonitor.range_status == + VL53L1_DEVICEERROR_EVENTCONSISTENCY) { + + prange_curr->range_status = + VL53L1_DEVICEERROR_RANGECOMPLETE; + + status = + VL53L1_hist_events_consistency_check( + event_sigma, + min_spad_count, + phist_prev, + &(prange_prev->xmonitor), + prange_curr, + &events_tolerance, + &events_delta, + &(prange_curr->range_status)); + + } + } + + return status; +} + + + + + +VL53L1_Error VL53L1_hist_wrap_dmax( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_histogram_bin_data_t *pcurrent, + int16_t *pwrap_dmax_mm) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + uint32_t pll_period_mm = 0; + uint32_t wrap_dmax_phase = 0; + uint32_t range_mm = 0; + + LOG_FUNCTION_START(""); + + *pwrap_dmax_mm = 0; + + + if (pcurrent->VL53L1_p_019 != 0) { + + + + + pll_period_mm = + VL53L1_calc_pll_period_mm( + pcurrent->VL53L1_p_019); + + + + + wrap_dmax_phase = + (uint32_t)phistpostprocess->valid_phase_high << 8; + + + + + + range_mm = wrap_dmax_phase * pll_period_mm; + range_mm = (range_mm + (1<<14)) >> 15; + + *pwrap_dmax_mm = (int16_t)range_mm; + } + + LOG_FUNCTION_END(status); + + return status; +} + + +void VL53L1_hist_combine_mm1_mm2_offsets( + int16_t mm1_offset_mm, + int16_t mm2_offset_mm, + uint8_t encoded_mm_roi_centre, + uint8_t encoded_mm_roi_size, + uint8_t encoded_zone_centre, + uint8_t encoded_zone_size, + VL53L1_additional_offset_cal_data_t *pcal_data, + uint8_t *pgood_spads, + uint16_t aperture_attenuation, + int16_t *prange_offset_mm) +{ + + + + + + + + + + + + + + + + uint16_t max_mm_inner_effective_spads = 0; + uint16_t max_mm_outer_effective_spads = 0; + uint16_t mm_inner_effective_spads = 0; + uint16_t mm_outer_effective_spads = 0; + + uint32_t scaled_mm1_peak_rate_mcps = 0; + uint32_t scaled_mm2_peak_rate_mcps = 0; + + int32_t tmp0 = 0; + int32_t tmp1 = 0; + + + + + VL53L1_calc_mm_effective_spads( + encoded_mm_roi_centre, + encoded_mm_roi_size, + 0xC7, + + 0xFF, + pgood_spads, + aperture_attenuation, + &max_mm_inner_effective_spads, + &max_mm_outer_effective_spads); + + if ((max_mm_inner_effective_spads == 0) || + (max_mm_outer_effective_spads == 0)) + goto FAIL; + + + + + VL53L1_calc_mm_effective_spads( + encoded_mm_roi_centre, + encoded_mm_roi_size, + encoded_zone_centre, + encoded_zone_size, + pgood_spads, + aperture_attenuation, + &mm_inner_effective_spads, + &mm_outer_effective_spads); + + + + + scaled_mm1_peak_rate_mcps = + (uint32_t)pcal_data->result__mm_inner_peak_signal_count_rtn_mcps; + scaled_mm1_peak_rate_mcps *= (uint32_t)mm_inner_effective_spads; + scaled_mm1_peak_rate_mcps /= (uint32_t)max_mm_inner_effective_spads; + + scaled_mm2_peak_rate_mcps = + (uint32_t)pcal_data->result__mm_outer_peak_signal_count_rtn_mcps; + scaled_mm2_peak_rate_mcps *= (uint32_t)mm_outer_effective_spads; + scaled_mm2_peak_rate_mcps /= (uint32_t)max_mm_outer_effective_spads; + + + + + tmp0 = ((int32_t)mm1_offset_mm * (int32_t)scaled_mm1_peak_rate_mcps); + tmp0 += ((int32_t)mm2_offset_mm * (int32_t)scaled_mm2_peak_rate_mcps); + + tmp1 = (int32_t)scaled_mm1_peak_rate_mcps + + (int32_t)scaled_mm2_peak_rate_mcps; + + + + + + + if (tmp1 != 0) + tmp0 = (tmp0 * 4) / tmp1; +FAIL: + *prange_offset_mm = (int16_t)tmp0; + +} + + +VL53L1_Error VL53L1_hist_xtalk_extract_calc_window( + int16_t target_distance_mm, + uint16_t target_width_oversize, + VL53L1_histogram_bin_data_t *phist_bins, + VL53L1_hist_xtalk_extract_data_t *pxtalk_data) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + pxtalk_data->pll_period_mm = + VL53L1_calc_pll_period_mm(phist_bins->VL53L1_p_019); + + + + pxtalk_data->xtalk_width_phase = + (int32_t)phist_bins->vcsel_width * 128; + pxtalk_data->target_width_phase = + pxtalk_data->xtalk_width_phase + + (int32_t)target_width_oversize * 128; + + + + + + + + pxtalk_data->xtalk_start_phase = + (int32_t)phist_bins->zero_distance_phase - + (pxtalk_data->xtalk_width_phase / 2); + pxtalk_data->xtalk_end_phase = + (int32_t)pxtalk_data->xtalk_start_phase + + pxtalk_data->xtalk_width_phase; + + if (pxtalk_data->xtalk_start_phase < 0) + pxtalk_data->xtalk_start_phase = 0; + + + + + + + + + pxtalk_data->VL53L1_p_015 = + (uint8_t)(pxtalk_data->xtalk_start_phase / 2048); + + + + pxtalk_data->VL53L1_p_016 = + (uint8_t)((pxtalk_data->xtalk_end_phase + 2047) / 2048); + + + + + + + + pxtalk_data->target_start_phase = + (int32_t)target_distance_mm * 2048 * 16; + pxtalk_data->target_start_phase += + ((int32_t)pxtalk_data->pll_period_mm / 2); + pxtalk_data->target_start_phase /= (int32_t)pxtalk_data->pll_period_mm; + pxtalk_data->target_start_phase += + (int32_t)phist_bins->zero_distance_phase; + + + + + + + pxtalk_data->target_start_phase -= + (pxtalk_data->target_width_phase / 2); + pxtalk_data->target_end_phase = + (int32_t)pxtalk_data->target_start_phase + + pxtalk_data->target_width_phase; + + if (pxtalk_data->target_start_phase < 0) + pxtalk_data->target_start_phase = 0; + + + + pxtalk_data->target_start = + (uint8_t)(pxtalk_data->target_start_phase / 2048); + + + + if (pxtalk_data->VL53L1_p_016 > (pxtalk_data->target_start-1)) + pxtalk_data->VL53L1_p_016 = pxtalk_data->target_start-1; + + + + pxtalk_data->effective_width = + (2048 * ((int32_t)pxtalk_data->VL53L1_p_016+1)); + pxtalk_data->effective_width -= pxtalk_data->xtalk_start_phase; + + + + + + if (pxtalk_data->effective_width > pxtalk_data->xtalk_width_phase) + pxtalk_data->effective_width = pxtalk_data->xtalk_width_phase; + + if (pxtalk_data->effective_width < 1) + pxtalk_data->effective_width = 1; + + + + pxtalk_data->event_scaler = pxtalk_data->xtalk_width_phase * 1000; + pxtalk_data->event_scaler += (pxtalk_data->effective_width / 2); + pxtalk_data->event_scaler /= pxtalk_data->effective_width; + + + + + + if (pxtalk_data->event_scaler < 1000) + pxtalk_data->event_scaler = 1000; + + if (pxtalk_data->event_scaler > 4000) + pxtalk_data->event_scaler = 4000; + + + + pxtalk_data->event_scaler_sum += pxtalk_data->event_scaler; + + + + pxtalk_data->peak_duration_us_sum += + (uint32_t)phist_bins->peak_duration_us; + + + + pxtalk_data->effective_spad_count_sum += + (uint32_t)phist_bins->result__dss_actual_effective_spads; + + + + pxtalk_data->zero_distance_phase_sum += + (uint32_t)phist_bins->zero_distance_phase; + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_hist_xtalk_extract_calc_event_sums( + VL53L1_histogram_bin_data_t *phist_bins, + VL53L1_hist_xtalk_extract_data_t *pxtalk_data) +{ + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + uint8_t lb = 0; + uint8_t i = 0; + + LOG_FUNCTION_START(""); + + + + + for (lb = pxtalk_data->VL53L1_p_015; + lb <= pxtalk_data->VL53L1_p_016; + lb++) { + + + + i = (lb + phist_bins->number_of_ambient_bins + + phist_bins->VL53L1_p_024) % + phist_bins->VL53L1_p_024; + + + + pxtalk_data->signal_events_sum += phist_bins->bin_data[i]; + pxtalk_data->signal_events_sum -= + phist_bins->VL53L1_p_004; + } + + + + + for (lb = 0; lb < VL53L1_XTALK_HISTO_BINS && + lb < phist_bins->VL53L1_p_024; lb++) { + + + + i = (lb + phist_bins->number_of_ambient_bins + + phist_bins->VL53L1_p_024) % + phist_bins->VL53L1_p_024; + + + + pxtalk_data->bin_data_sums[lb] += phist_bins->bin_data[i]; + pxtalk_data->bin_data_sums[lb] -= + phist_bins->VL53L1_p_004; + } + + pxtalk_data->sample_count += 1; + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_hist_xtalk_extract_calc_rate_per_spad( + VL53L1_hist_xtalk_extract_data_t *pxtalk_data) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + uint64_t tmp64_0 = 0; + uint64_t tmp64_1 = 0; + uint64_t xtalk_per_spad = 0; + + LOG_FUNCTION_START(""); + + + + + + + + + + + + + + + + + + if (pxtalk_data->signal_events_sum > 0) { + tmp64_0 = + ((uint64_t)pxtalk_data->signal_events_sum * + (uint64_t)pxtalk_data->sample_count * + (uint64_t)pxtalk_data->event_scaler_avg * 256U) << 9U; + tmp64_1 = + (uint64_t)pxtalk_data->effective_spad_count_sum * + (uint64_t)pxtalk_data->peak_duration_us_sum; + + + + + if (tmp64_1 > 0U) { + + + tmp64_0 = tmp64_0 + (tmp64_1 >> 1U); + xtalk_per_spad = do_division_u(tmp64_0, tmp64_1); + } else { + xtalk_per_spad = (uint64_t)tmp64_0; + } + + } else { + status = VL53L1_ERROR_XTALK_EXTRACTION_SIGMA_LIMIT_FAIL; + } + + pxtalk_data->xtalk_rate_kcps_per_spad = (uint32_t)xtalk_per_spad; + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_hist_xtalk_extract_calc_shape( + VL53L1_hist_xtalk_extract_data_t *pxtalk_data, + VL53L1_xtalk_histogram_shape_t *pxtalk_shape) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + int32_t lb = 0; + uint64_t total_events = 0U; + uint64_t tmp64_0 = 0U; + int32_t remaining_area = 1024; + + LOG_FUNCTION_START(""); + + + + + pxtalk_shape->VL53L1_p_022 = 0; + pxtalk_shape->VL53L1_p_023 = VL53L1_XTALK_HISTO_BINS; + pxtalk_shape->VL53L1_p_024 = VL53L1_XTALK_HISTO_BINS; + + pxtalk_shape->zero_distance_phase = + (uint16_t)pxtalk_data->zero_distance_phase_avg; + pxtalk_shape->phasecal_result__reference_phase = + (uint16_t)pxtalk_data->zero_distance_phase_avg + (3*2048); + + + + + if (pxtalk_data->signal_events_sum > 0) + total_events = + (uint64_t)pxtalk_data->signal_events_sum * + (uint64_t)pxtalk_data->event_scaler_avg; + else + total_events = 1; + if (total_events == 0) + total_events = 1; + + + + remaining_area = 1024; + pxtalk_data->max_shape_value = 0; + + for (lb = 0; lb < VL53L1_XTALK_HISTO_BINS; lb++) { + + if ((lb < (int32_t)pxtalk_data->VL53L1_p_015 || + lb > (int32_t)pxtalk_data->VL53L1_p_016) || + pxtalk_data->bin_data_sums[lb] < 0) { + + + + + + + if (remaining_area > 0 && remaining_area < 1024) { + if (remaining_area > + pxtalk_data->max_shape_value) { + pxtalk_shape->bin_data[lb] = + (uint32_t)pxtalk_data->max_shape_value; + remaining_area -= + pxtalk_data->max_shape_value; + } else { + pxtalk_shape->bin_data[lb] = + (uint32_t)remaining_area; + remaining_area = 0; + } + } else { + pxtalk_shape->bin_data[lb] = 0; + } + + } else { + + + + + tmp64_0 = + (uint64_t)pxtalk_data->bin_data_sums[lb] + * 1024U * 1000U; + tmp64_0 += (total_events >> 1); + tmp64_0 = do_division_u(tmp64_0, total_events); + if (tmp64_0 > 0xFFFFU) + tmp64_0 = 0xFFFFU; + + pxtalk_shape->bin_data[lb] = (uint32_t)tmp64_0; + + + + + + if ((int32_t)pxtalk_shape->bin_data[lb] > + pxtalk_data->max_shape_value) + pxtalk_data->max_shape_value = + (int32_t)pxtalk_shape->bin_data[lb]; + + remaining_area -= (int32_t)pxtalk_shape->bin_data[lb]; + } + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_hist_xtalk_shape_model( + uint16_t events_per_bin, + uint16_t pulse_centre, + uint16_t pulse_width, + VL53L1_xtalk_histogram_shape_t *pxtalk_shape) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + uint32_t phase_start = 0; + uint32_t phase_stop = 0; + uint32_t phase_bin = 0; + + uint32_t bin_start = 0; + uint32_t bin_stop = 0; + + uint32_t lb = 0; + uint16_t VL53L1_p_008 = 0; + + LOG_FUNCTION_START(""); + + + + + pxtalk_shape->VL53L1_p_022 = 0; + pxtalk_shape->VL53L1_p_023 = VL53L1_XTALK_HISTO_BINS; + pxtalk_shape->VL53L1_p_024 = VL53L1_XTALK_HISTO_BINS; + + pxtalk_shape->zero_distance_phase = pulse_centre; + pxtalk_shape->phasecal_result__reference_phase = + pulse_centre + (3*2048); + + + + if (pulse_centre > (pulse_width >> 1)) + phase_start = (uint32_t)pulse_centre - + ((uint32_t)pulse_width >> 1); + else + phase_start = 0; + + phase_stop = (uint32_t)pulse_centre + + ((uint32_t)pulse_width >> 1); + + + + bin_start = (phase_start / 2048); + bin_stop = (phase_stop / 2048); + + for (lb = 0; lb < VL53L1_XTALK_HISTO_BINS; lb++) { + VL53L1_p_008 = 0; + + + + if (lb == bin_start && lb == bin_stop) { + VL53L1_p_008 = + VL53L1_hist_xtalk_shape_model_interp( + events_per_bin, + phase_stop - phase_start); + + } else if (lb > bin_start && lb < bin_stop) { + + + + VL53L1_p_008 = events_per_bin; + + } else if (lb == bin_start) { + + + + phase_bin = (lb + 1) * 2048; + VL53L1_p_008 = + VL53L1_hist_xtalk_shape_model_interp( + events_per_bin, + (phase_bin - phase_start)); + + } else if (lb == bin_stop) { + + + + phase_bin = lb * 2048; + VL53L1_p_008 = + VL53L1_hist_xtalk_shape_model_interp( + events_per_bin, + (phase_stop - phase_bin)); + } + + pxtalk_shape->bin_data[lb] = VL53L1_p_008; + } + + LOG_FUNCTION_END(status); + + return status; +} + + +uint16_t VL53L1_hist_xtalk_shape_model_interp( + uint16_t events_per_bin, + uint32_t phase_delta) +{ + + + + + + + + + + uint32_t VL53L1_p_008 = 0; + + LOG_FUNCTION_START(""); + + + + VL53L1_p_008 = (uint32_t)events_per_bin * phase_delta; + VL53L1_p_008 += 1024; + VL53L1_p_008 /= 2048; + + + + if (VL53L1_p_008 > 0xFFFFU) + VL53L1_p_008 = 0xFFFFU; + + LOG_FUNCTION_END(0); + + return (uint16_t)VL53L1_p_008; +} + + +void VL53L1_spad_number_to_byte_bit_index( + uint8_t spad_number, + uint8_t *pbyte_index, + uint8_t *pbit_index, + uint8_t *pbit_mask) +{ + + + + + + + + + + + *pbyte_index = spad_number >> 3; + *pbit_index = spad_number & 0x07; + *pbit_mask = 0x01 << *pbit_index; + +} + + +void VL53L1_encode_row_col( + uint8_t row, + uint8_t col, + uint8_t *pspad_number) +{ + + + + + + if (row > 7) + *pspad_number = 128 + (col << 3) + (15-row); + else + *pspad_number = ((15-col) << 3) + row; + +} + + +void VL53L1_decode_zone_size( + uint8_t encoded_xy_size, + uint8_t *pwidth, + uint8_t *pheight) +{ + + + + + + + + + + + + *pheight = encoded_xy_size >> 4; + *pwidth = encoded_xy_size & 0x0F; + +} + + +void VL53L1_encode_zone_size( + uint8_t width, + uint8_t height, + uint8_t *pencoded_xy_size) +{ + + + + + + + + + + + *pencoded_xy_size = (height << 4) + width; + +} + + +void VL53L1_decode_zone_limits( + uint8_t encoded_xy_centre, + uint8_t encoded_xy_size, + int16_t *px_ll, + int16_t *py_ll, + int16_t *px_ur, + int16_t *py_ur) +{ + + + + + + + + + + uint8_t x_centre = 0; + uint8_t y_centre = 0; + uint8_t width = 0; + uint8_t height = 0; + + + + + VL53L1_decode_row_col( + encoded_xy_centre, + &y_centre, + &x_centre); + + VL53L1_decode_zone_size( + encoded_xy_size, + &width, + &height); + + + + + *px_ll = (int16_t)x_centre - ((int16_t)width + 1) / 2; + if (*px_ll < 0) + *px_ll = 0; + + *px_ur = *px_ll + (int16_t)width; + if (*px_ur > (VL53L1_SPAD_ARRAY_WIDTH-1)) + *px_ur = VL53L1_SPAD_ARRAY_WIDTH-1; + + *py_ll = (int16_t)y_centre - ((int16_t)height + 1) / 2; + if (*py_ll < 0) + *py_ll = 0; + + *py_ur = *py_ll + (int16_t)height; + if (*py_ur > (VL53L1_SPAD_ARRAY_HEIGHT-1)) + *py_ur = VL53L1_SPAD_ARRAY_HEIGHT-1; +} + + +uint8_t VL53L1_is_aperture_location( + uint8_t row, + uint8_t col) +{ + + + + + + uint8_t is_aperture = 0; + uint8_t mod_row = row % 4; + uint8_t mod_col = col % 4; + + if (mod_row == 0 && mod_col == 2) + is_aperture = 1; + + if (mod_row == 2 && mod_col == 0) + is_aperture = 1; + + return is_aperture; +} + + +void VL53L1_calc_max_effective_spads( + uint8_t encoded_zone_centre, + uint8_t encoded_zone_size, + uint8_t *pgood_spads, + uint16_t aperture_attenuation, + uint16_t *pmax_effective_spads) +{ + + + + + + + int16_t x = 0; + int16_t y = 0; + + int16_t zone_x_ll = 0; + int16_t zone_y_ll = 0; + int16_t zone_x_ur = 0; + int16_t zone_y_ur = 0; + + uint8_t spad_number = 0; + uint8_t byte_index = 0; + uint8_t bit_index = 0; + uint8_t bit_mask = 0; + + uint8_t is_aperture = 0; + + + + + VL53L1_decode_zone_limits( + encoded_zone_centre, + encoded_zone_size, + &zone_x_ll, + &zone_y_ll, + &zone_x_ur, + &zone_y_ur); + + + + + + + + *pmax_effective_spads = 0; + + for (y = zone_y_ll; y <= zone_y_ur; y++) { + for (x = zone_x_ll; x <= zone_x_ur; x++) { + + + + + VL53L1_encode_row_col( + (uint8_t)y, + (uint8_t)x, + &spad_number); + + + + + + + + + VL53L1_spad_number_to_byte_bit_index( + spad_number, + &byte_index, + &bit_index, + &bit_mask); + + + + + if ((pgood_spads[byte_index] & bit_mask) > 0) { + + + + is_aperture = VL53L1_is_aperture_location( + (uint8_t)y, + (uint8_t)x); + + if (is_aperture > 0) + *pmax_effective_spads += + aperture_attenuation; + else + *pmax_effective_spads += 0x0100; + + } + } + } +} + + +void VL53L1_calc_mm_effective_spads( + uint8_t encoded_mm_roi_centre, + uint8_t encoded_mm_roi_size, + uint8_t encoded_zone_centre, + uint8_t encoded_zone_size, + uint8_t *pgood_spads, + uint16_t aperture_attenuation, + uint16_t *pmm_inner_effective_spads, + uint16_t *pmm_outer_effective_spads) +{ + + + + + + + + int16_t x = 0; + int16_t y = 0; + + int16_t mm_x_ll = 0; + int16_t mm_y_ll = 0; + int16_t mm_x_ur = 0; + int16_t mm_y_ur = 0; + + int16_t zone_x_ll = 0; + int16_t zone_y_ll = 0; + int16_t zone_x_ur = 0; + int16_t zone_y_ur = 0; + + uint8_t spad_number = 0; + uint8_t byte_index = 0; + uint8_t bit_index = 0; + uint8_t bit_mask = 0; + + uint8_t is_aperture = 0; + uint16_t spad_attenuation = 0; + + + + + VL53L1_decode_zone_limits( + encoded_mm_roi_centre, + encoded_mm_roi_size, + &mm_x_ll, + &mm_y_ll, + &mm_x_ur, + &mm_y_ur); + + VL53L1_decode_zone_limits( + encoded_zone_centre, + encoded_zone_size, + &zone_x_ll, + &zone_y_ll, + &zone_x_ur, + &zone_y_ur); + + + + + + + + + + *pmm_inner_effective_spads = 0; + *pmm_outer_effective_spads = 0; + + for (y = zone_y_ll; y <= zone_y_ur; y++) { + for (x = zone_x_ll; x <= zone_x_ur; x++) { + + + + + VL53L1_encode_row_col( + (uint8_t)y, + (uint8_t)x, + &spad_number); + + + + + + + + + VL53L1_spad_number_to_byte_bit_index( + spad_number, + &byte_index, + &bit_index, + &bit_mask); + + + + + if ((pgood_spads[byte_index] & bit_mask) > 0) { + + + + is_aperture = VL53L1_is_aperture_location( + (uint8_t)y, + (uint8_t)x); + + if (is_aperture > 0) + spad_attenuation = aperture_attenuation; + else + spad_attenuation = 0x0100; + + + + + + + + if (x >= mm_x_ll && x <= mm_x_ur && + y >= mm_y_ll && y <= mm_y_ur) + *pmm_inner_effective_spads += + spad_attenuation; + else + *pmm_outer_effective_spads += + spad_attenuation; + } + } + } +} + + +void VL53L1_hist_copy_results_to_sys_and_core( + VL53L1_histogram_bin_data_t *pbins, + VL53L1_range_results_t *phist, + VL53L1_system_results_t *psys, + VL53L1_core_results_t *pcore) +{ + + + + + + uint8_t i = 0; + + VL53L1_range_data_t *pdata; + + LOG_FUNCTION_START(""); + + + + + VL53L1_init_system_results(psys); + + + + + psys->result__interrupt_status = pbins->result__interrupt_status; + psys->result__range_status = phist->active_results; + psys->result__report_status = pbins->result__report_status; + psys->result__stream_count = pbins->result__stream_count; + + pdata = &(phist->VL53L1_p_002[0]); + + for (i = 0; i < phist->active_results; i++) { + + switch (i) { + case 0: + psys->result__dss_actual_effective_spads_sd0 = + pdata->VL53L1_p_006; + psys->result__peak_signal_count_rate_mcps_sd0 = + pdata->peak_signal_count_rate_mcps; + psys->result__avg_signal_count_rate_mcps_sd0 = + pdata->avg_signal_count_rate_mcps; + psys->result__ambient_count_rate_mcps_sd0 = + pdata->ambient_count_rate_mcps; + + psys->result__sigma_sd0 = pdata->VL53L1_p_005; + psys->result__phase_sd0 = pdata->VL53L1_p_014; + + psys->result__final_crosstalk_corrected_range_mm_sd0 = + (uint16_t)pdata->median_range_mm; + + psys->result__phase_sd1 = pdata->zero_distance_phase; + + pcore->result_core__ranging_total_events_sd0 = + pdata->VL53L1_p_021; + pcore->result_core__signal_total_events_sd0 = + pdata->VL53L1_p_013; + pcore->result_core__total_periods_elapsed_sd0 = + pdata->total_periods_elapsed; + pcore->result_core__ambient_window_events_sd0 = + pdata->VL53L1_p_020; + + break; + case 1: + psys->result__dss_actual_effective_spads_sd1 = + pdata->VL53L1_p_006; + psys->result__peak_signal_count_rate_mcps_sd1 = + pdata->peak_signal_count_rate_mcps; + psys->result__ambient_count_rate_mcps_sd1 = + pdata->ambient_count_rate_mcps; + + psys->result__sigma_sd1 = pdata->VL53L1_p_005; + psys->result__phase_sd1 = pdata->VL53L1_p_014; + + psys->result__final_crosstalk_corrected_range_mm_sd1 = + (uint16_t)pdata->median_range_mm; + + pcore->result_core__ranging_total_events_sd1 = + pdata->VL53L1_p_021; + pcore->result_core__signal_total_events_sd1 = + pdata->VL53L1_p_013; + pcore->result_core__total_periods_elapsed_sd1 = + pdata->total_periods_elapsed; + pcore->result_core__ambient_window_events_sd1 = + pdata->VL53L1_p_020; + break; + } + + pdata++; + } + + LOG_FUNCTION_END(0); + +} + + +VL53L1_Error VL53L1_sum_histogram_data( + VL53L1_histogram_bin_data_t *phist_input, + VL53L1_histogram_bin_data_t *phist_output) +{ + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + uint8_t i = 0; + uint8_t smallest_bin_num = 0; + + LOG_FUNCTION_START(""); + + + + + if (status == VL53L1_ERROR_NONE) { + + if (phist_output->VL53L1_p_024 >= + phist_input->VL53L1_p_024) + smallest_bin_num = phist_input->VL53L1_p_024; + else + smallest_bin_num = phist_output->VL53L1_p_024; + } + + + + + + + + + if (status == VL53L1_ERROR_NONE) + + for (i = 0; i < smallest_bin_num; i++) + + + phist_output->bin_data[i] += phist_input->bin_data[i]; + + if (status == VL53L1_ERROR_NONE) + + phist_output->VL53L1_p_004 += + phist_input->VL53L1_p_004; + + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_avg_histogram_data( + uint8_t no_of_samples, + VL53L1_histogram_bin_data_t *phist_sum, + VL53L1_histogram_bin_data_t *phist_avg) +{ + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + uint8_t i = 0; + + LOG_FUNCTION_START(""); + + + + + + + + + if (status == VL53L1_ERROR_NONE) { + + for (i = 0; i < phist_sum->VL53L1_p_024; i++) { + + + + + if (no_of_samples > 0) + phist_avg->bin_data[i] = + phist_sum->bin_data[i] / + (int32_t)no_of_samples; + else + phist_avg->bin_data[i] = phist_sum->bin_data[i]; + } + } + + if (status == VL53L1_ERROR_NONE) { + + if (no_of_samples > 0) + phist_avg->VL53L1_p_004 = + phist_sum->VL53L1_p_004 / + (int32_t)no_of_samples; + else + phist_avg->VL53L1_p_004 = + phist_sum->VL53L1_p_004; + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_save_cfg_data( + VL53L1_DEV Dev) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_LLDriverResults_t *pres = + VL53L1DevStructGetLLResultsHandle(Dev); + + VL53L1_zone_private_dyn_cfg_t *pzone_dyn_cfg; + VL53L1_dynamic_config_t *pdynamic = &(pdev->dyn_cfg); + + LOG_FUNCTION_START(""); + + pzone_dyn_cfg = + &(pres->zone_dyn_cfgs.VL53L1_p_002[pdev->ll_state.cfg_zone_id]); + + pzone_dyn_cfg->expected_stream_count = + pdev->ll_state.cfg_stream_count; + + pzone_dyn_cfg->expected_gph_id = + pdev->ll_state.cfg_gph_id; + + pzone_dyn_cfg->roi_config__user_roi_centre_spad = + pdynamic->roi_config__user_roi_centre_spad; + + pzone_dyn_cfg->roi_config__user_roi_requested_global_xy_size = + pdynamic->roi_config__user_roi_requested_global_xy_size; + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_dynamic_zone_update( + VL53L1_DEV Dev, + VL53L1_range_results_t *presults) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_LLDriverResults_t *pres = + VL53L1DevStructGetLLResultsHandle(Dev); + VL53L1_zone_private_dyn_cfgs_t *pZ = &(pres->zone_dyn_cfgs); + + uint8_t zone_id = pdev->ll_state.rd_zone_id; + uint8_t i; + uint16_t max_total_rate_per_spads; + uint16_t target_rate = + pdev->stat_cfg.dss_config__target_total_rate_mcps; + uint32_t temp = 0xFFFF; +#ifdef VL53L1_LOG_ENABLE + uint16_t eff_spad_cnt = + pZ->VL53L1_p_002[zone_id].dss_requested_effective_spad_count; +#endif + + LOG_FUNCTION_START(""); + + pZ->VL53L1_p_002[zone_id].dss_requested_effective_spad_count = 0; + + trace_print(VL53L1_TRACE_LEVEL_DEBUG, + " DYNZONEUPDATE: peak signal count rate mcps:"); + + trace_print(VL53L1_TRACE_LEVEL_DEBUG, + "%u actual effective spads: %u\n", + presults->VL53L1_p_002[0].peak_signal_count_rate_mcps, + presults->VL53L1_p_002[0].VL53L1_p_006); + + trace_print(VL53L1_TRACE_LEVEL_DEBUG, + " DYNZONEUPDATE: active results: %u\n", + presults->active_results); + + max_total_rate_per_spads = + presults->VL53L1_p_002[0].total_rate_per_spad_mcps; + + trace_print(VL53L1_TRACE_LEVEL_DEBUG, + " DYNZONEUPDATE: max total rate per spad at start: %u\n", + max_total_rate_per_spads); + + for (i = 1; i < presults->active_results; i++) { + trace_print(VL53L1_TRACE_LEVEL_DEBUG, + " DYNZONEUPDATE: zone total rate per spad: zone_id: %u,", + i); + + trace_print(VL53L1_TRACE_LEVEL_DEBUG, + "total rate per spad: %u\n", + presults->VL53L1_p_002[i].total_rate_per_spad_mcps); + + if (presults->VL53L1_p_002[i].total_rate_per_spad_mcps > + max_total_rate_per_spads) + max_total_rate_per_spads = + presults->VL53L1_p_002[i].total_rate_per_spad_mcps; + + } + + if (max_total_rate_per_spads == 0) { + + + + + + temp = 0xFFFF; + } else { + + + + + + temp = target_rate << 14; + trace_print(VL53L1_TRACE_LEVEL_DEBUG, + " DYNZONEUPDATE: 1: temp: %u\n", + temp); + + + + + + temp = temp / max_total_rate_per_spads; + + trace_print(VL53L1_TRACE_LEVEL_DEBUG, + " DYNZONEUPDATE: 2: temp: %u\n", + temp); + + + + + + if (temp > 0xFFFF) + temp = 0xFFFF; + + trace_print(VL53L1_TRACE_LEVEL_DEBUG, + " DYNZONEUPDATE: 3: temp: %u\n", + temp); + } + + pZ->VL53L1_p_002[zone_id].dss_requested_effective_spad_count = + (uint16_t)temp; + + trace_print(VL53L1_TRACE_LEVEL_DEBUG, + " DYNZONEUPDATE: zone_id: %u, target_rate: %u,", + zone_id, + target_rate); + + trace_print(VL53L1_TRACE_LEVEL_DEBUG, + "max_total_rate_per_spads: %u, requested_spads: %u\n", + max_total_rate_per_spads, + eff_spad_cnt); + + LOG_FUNCTION_END(status); + + return status; +} + +VL53L1_Error VL53L1_multizone_hist_bins_update( + VL53L1_DEV Dev) +{ + + + + + + + + + + + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_ll_driver_state_t *pstate = &(pdev->ll_state); + VL53L1_zone_config_t *pzone_cfg = &(pdev->zone_cfg); + VL53L1_histogram_config_t *phist_cfg = &(pdev->hist_cfg); + VL53L1_histogram_config_t *pmulti_hist = + &(pzone_cfg->multizone_hist_cfg); + + uint8_t next_range_is_odd_timing = (pstate->cfg_stream_count) % 2; + + LOG_FUNCTION_START(""); + + + + + + if (pzone_cfg->bin_config[pdev->ll_state.cfg_zone_id] == + VL53L1_ZONECONFIG_BINCONFIG__LOWAMB) { + if (!next_range_is_odd_timing) { + trace_print (VL53L1_TRACE_LEVEL_DEBUG, + " HISTBINCONFIGUPDATE: Setting LOWAMB EVEN timing\n"); + phist_cfg->histogram_config__low_amb_even_bin_0_1 = + pmulti_hist->histogram_config__low_amb_even_bin_0_1; + phist_cfg->histogram_config__low_amb_even_bin_2_3 = + pmulti_hist->histogram_config__low_amb_even_bin_2_3; + phist_cfg->histogram_config__low_amb_even_bin_4_5 = + pmulti_hist->histogram_config__low_amb_even_bin_4_5; + } + + if (next_range_is_odd_timing) { + trace_print (VL53L1_TRACE_LEVEL_DEBUG, + " HISTBINCONFIGUPDATE: Setting LOWAMB ODD timing\n"); + phist_cfg->histogram_config__low_amb_odd_bin_0_1 = + pmulti_hist->histogram_config__low_amb_even_bin_0_1; + phist_cfg->histogram_config__low_amb_odd_bin_2_3 = + pmulti_hist->histogram_config__low_amb_even_bin_2_3; + phist_cfg->histogram_config__low_amb_odd_bin_4_5 = + pmulti_hist->histogram_config__low_amb_even_bin_4_5; + } + } else if (pzone_cfg->bin_config[pdev->ll_state.cfg_zone_id] == + VL53L1_ZONECONFIG_BINCONFIG__MIDAMB) { + + trace_print (VL53L1_TRACE_LEVEL_DEBUG, + " HISTBINCONFIGUPDATE: Setting MIDAMB timing\n"); + if (!next_range_is_odd_timing) { + trace_print(VL53L1_TRACE_LEVEL_DEBUG, + " HISTBINCONFIGUPDATE: Setting MIDAMB EVEN timing\n"); + phist_cfg->histogram_config__low_amb_even_bin_0_1 = + pmulti_hist->histogram_config__mid_amb_even_bin_0_1; + phist_cfg->histogram_config__low_amb_even_bin_2_3 = + pmulti_hist->histogram_config__mid_amb_even_bin_2_3; + phist_cfg->histogram_config__low_amb_even_bin_4_5 = + pmulti_hist->histogram_config__mid_amb_even_bin_4_5; + } + + if (next_range_is_odd_timing) { + trace_print (VL53L1_TRACE_LEVEL_DEBUG, + " HISTBINCONFIGUPDATE: Setting MIDAMB ODD timing\n"); + phist_cfg->histogram_config__low_amb_odd_bin_0_1 = + pmulti_hist->histogram_config__mid_amb_even_bin_0_1; + phist_cfg->histogram_config__low_amb_odd_bin_2_3 = + pmulti_hist->histogram_config__mid_amb_even_bin_2_3; + phist_cfg->histogram_config__low_amb_odd_bin_4_5 = + pmulti_hist->histogram_config__mid_amb_even_bin_4_5; + } + } else if (pzone_cfg->bin_config[pdev->ll_state.cfg_zone_id] == + VL53L1_ZONECONFIG_BINCONFIG__HIGHAMB) { + if (!next_range_is_odd_timing) { + trace_print (VL53L1_TRACE_LEVEL_DEBUG, + " HISTBINCONFIGUPDATE: Setting HIGHAMB EVEN timing\n" + ); + phist_cfg->histogram_config__low_amb_even_bin_0_1 = + pmulti_hist->histogram_config__high_amb_even_bin_0_1; + phist_cfg->histogram_config__low_amb_even_bin_2_3 = + pmulti_hist->histogram_config__high_amb_even_bin_2_3; + phist_cfg->histogram_config__low_amb_even_bin_4_5 = + pmulti_hist->histogram_config__high_amb_even_bin_4_5; + } + + if (next_range_is_odd_timing) { + trace_print (VL53L1_TRACE_LEVEL_DEBUG, + " HISTBINCONFIGUPDATE: Setting HIGHAMB ODD timing\n"); + phist_cfg->histogram_config__low_amb_odd_bin_0_1 = + pmulti_hist->histogram_config__high_amb_even_bin_0_1; + phist_cfg->histogram_config__low_amb_odd_bin_2_3 = + pmulti_hist->histogram_config__high_amb_even_bin_2_3; + phist_cfg->histogram_config__low_amb_odd_bin_4_5 = + pmulti_hist->histogram_config__high_amb_even_bin_4_5; + } + } + + + + + + + if (status == VL53L1_ERROR_NONE) { + + VL53L1_copy_hist_bins_to_static_cfg( + phist_cfg, + &(pdev->stat_cfg), + &(pdev->tim_cfg)); + } + + LOG_FUNCTION_END(status); + + return status; +} + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_update_internal_stream_counters( + VL53L1_DEV Dev, + uint8_t external_stream_count, + uint8_t *pinternal_stream_count, + uint8_t *pinternal_stream_count_val) +{ + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t stream_divider; + + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + stream_divider = pdev->gen_cfg.global_config__stream_divider; + + if (stream_divider == 0) { + + + + + + + *pinternal_stream_count = external_stream_count; + + } else if (*pinternal_stream_count_val == (stream_divider-1)) { + + + + + + if (*pinternal_stream_count == 0xFF) + *pinternal_stream_count = 0x80; + else + *pinternal_stream_count = *pinternal_stream_count + 1; + + + + + + *pinternal_stream_count_val = 0; + + } else { + + + + + + *pinternal_stream_count_val = *pinternal_stream_count_val + 1; + } + + trace_print(VL53L1_TRACE_LEVEL_DEBUG, + "UPDINTSTREAMCOUNT internal_steam_count: %d,", + *pinternal_stream_count); + + trace_print(VL53L1_TRACE_LEVEL_DEBUG, + "internal_stream_count_val: %d, divider: %d\n", + *pinternal_stream_count_val, + stream_divider); + + LOG_FUNCTION_END(status); + + return status; +} + + + + + + + +VL53L1_Error VL53L1_set_histogram_multizone_initial_bin_config( + VL53L1_zone_config_t *pzone_cfg, + VL53L1_histogram_config_t *phist_cfg, + VL53L1_histogram_config_t *pmulti_hist) +{ + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + + if (pzone_cfg->bin_config[0] == + VL53L1_ZONECONFIG_BINCONFIG__LOWAMB) { + phist_cfg->histogram_config__low_amb_even_bin_0_1 = + pmulti_hist->histogram_config__low_amb_even_bin_0_1; + phist_cfg->histogram_config__low_amb_even_bin_2_3 = + pmulti_hist->histogram_config__low_amb_even_bin_2_3; + phist_cfg->histogram_config__low_amb_even_bin_4_5 = + pmulti_hist->histogram_config__low_amb_even_bin_4_5; + + phist_cfg->histogram_config__low_amb_odd_bin_0_1 = + pmulti_hist->histogram_config__low_amb_even_bin_0_1; + phist_cfg->histogram_config__low_amb_odd_bin_2_3 = + pmulti_hist->histogram_config__low_amb_even_bin_2_3; + phist_cfg->histogram_config__low_amb_odd_bin_4_5 = + pmulti_hist->histogram_config__low_amb_even_bin_4_5; + } else if (pzone_cfg->bin_config[0] == + VL53L1_ZONECONFIG_BINCONFIG__MIDAMB) { + + phist_cfg->histogram_config__low_amb_even_bin_0_1 = + pmulti_hist->histogram_config__mid_amb_even_bin_0_1; + phist_cfg->histogram_config__low_amb_even_bin_2_3 = + pmulti_hist->histogram_config__mid_amb_even_bin_2_3; + phist_cfg->histogram_config__low_amb_even_bin_4_5 = + pmulti_hist->histogram_config__mid_amb_even_bin_4_5; + + phist_cfg->histogram_config__low_amb_odd_bin_0_1 = + pmulti_hist->histogram_config__mid_amb_even_bin_0_1; + phist_cfg->histogram_config__low_amb_odd_bin_2_3 = + pmulti_hist->histogram_config__mid_amb_even_bin_2_3; + phist_cfg->histogram_config__low_amb_odd_bin_4_5 = + pmulti_hist->histogram_config__mid_amb_even_bin_4_5; + } else if (pzone_cfg->bin_config[0] == + VL53L1_ZONECONFIG_BINCONFIG__HIGHAMB) { + phist_cfg->histogram_config__low_amb_even_bin_0_1 = + pmulti_hist->histogram_config__high_amb_even_bin_0_1; + phist_cfg->histogram_config__low_amb_even_bin_2_3 = + pmulti_hist->histogram_config__high_amb_even_bin_2_3; + phist_cfg->histogram_config__low_amb_even_bin_4_5 = + pmulti_hist->histogram_config__high_amb_even_bin_4_5; + phist_cfg->histogram_config__low_amb_odd_bin_0_1 = + pmulti_hist->histogram_config__high_amb_even_bin_0_1; + phist_cfg->histogram_config__low_amb_odd_bin_2_3 = + pmulti_hist->histogram_config__high_amb_even_bin_2_3; + phist_cfg->histogram_config__low_amb_odd_bin_4_5 = + pmulti_hist->histogram_config__high_amb_even_bin_4_5; + } + + LOG_FUNCTION_END(status); + return status; +} + + + + + + +uint8_t VL53L1_encode_GPIO_interrupt_config( + VL53L1_GPIO_interrupt_config_t *pintconf) +{ + uint8_t system__interrupt_config; + + system__interrupt_config = pintconf->intr_mode_distance; + system__interrupt_config |= ((pintconf->intr_mode_rate) << 2); + system__interrupt_config |= ((pintconf->intr_new_measure_ready) << 5); + system__interrupt_config |= ((pintconf->intr_no_target) << 6); + system__interrupt_config |= ((pintconf->intr_combined_mode) << 7); + + return system__interrupt_config; +} + + + + + + +VL53L1_GPIO_interrupt_config_t VL53L1_decode_GPIO_interrupt_config( + uint8_t system__interrupt_config) +{ + VL53L1_GPIO_interrupt_config_t intconf; + + intconf.intr_mode_distance = system__interrupt_config & 0x03; + intconf.intr_mode_rate = (system__interrupt_config >> 2) & 0x03; + intconf.intr_new_measure_ready = (system__interrupt_config >> 5) & 0x01; + intconf.intr_no_target = (system__interrupt_config >> 6) & 0x01; + intconf.intr_combined_mode = (system__interrupt_config >> 7) & 0x01; + + + + intconf.threshold_rate_low = 0; + intconf.threshold_rate_high = 0; + intconf.threshold_distance_low = 0; + intconf.threshold_distance_high = 0; + + return intconf; +} + + + + + + +VL53L1_Error VL53L1_set_GPIO_distance_threshold( + VL53L1_DEV Dev, + uint16_t threshold_high, + uint16_t threshold_low) +{ + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + pdev->dyn_cfg.system__thresh_high = threshold_high; + pdev->dyn_cfg.system__thresh_low = threshold_low; + + LOG_FUNCTION_END(status); + return status; +} + + + + + + +VL53L1_Error VL53L1_set_GPIO_rate_threshold( + VL53L1_DEV Dev, + uint16_t threshold_high, + uint16_t threshold_low) +{ + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + pdev->gen_cfg.system__thresh_rate_high = threshold_high; + pdev->gen_cfg.system__thresh_rate_low = threshold_low; + + LOG_FUNCTION_END(status); + return status; +} + + + + + + +VL53L1_Error VL53L1_set_GPIO_thresholds_from_struct( + VL53L1_DEV Dev, + VL53L1_GPIO_interrupt_config_t *pintconf) +{ + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + status = VL53L1_set_GPIO_distance_threshold( + Dev, + pintconf->threshold_distance_high, + pintconf->threshold_distance_low); + + if (status == VL53L1_ERROR_NONE) { + status = + VL53L1_set_GPIO_rate_threshold( + Dev, + pintconf->threshold_rate_high, + pintconf->threshold_rate_low); + } + + LOG_FUNCTION_END(status); + return status; +} + + +VL53L1_Error VL53L1_set_ref_spad_char_config( + VL53L1_DEV Dev, + uint8_t vcsel_period_a, + uint32_t phasecal_timeout_us, + uint16_t total_rate_target_mcps, + uint16_t max_count_rate_rtn_limit_mcps, + uint16_t min_count_rate_rtn_limit_mcps, + uint16_t fast_osc_frequency) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + uint8_t buffer[2]; + + uint32_t macro_period_us = 0; + uint32_t timeout_mclks = 0; + + LOG_FUNCTION_START(""); + + + + + + macro_period_us = + VL53L1_calc_macro_period_us( + fast_osc_frequency, + vcsel_period_a); + + + + + + + timeout_mclks = phasecal_timeout_us << 12; + timeout_mclks = timeout_mclks + (macro_period_us>>1); + timeout_mclks = timeout_mclks / macro_period_us; + + if (timeout_mclks > 0xFF) + pdev->gen_cfg.phasecal_config__timeout_macrop = 0xFF; + else + pdev->gen_cfg.phasecal_config__timeout_macrop = + (uint8_t)timeout_mclks; + + pdev->tim_cfg.range_config__vcsel_period_a = vcsel_period_a; + + + + + + + if (status == VL53L1_ERROR_NONE) + + status = + VL53L1_WrByte( + Dev, + VL53L1_PHASECAL_CONFIG__TIMEOUT_MACROP, + pdev->gen_cfg.phasecal_config__timeout_macrop); + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_WrByte( + Dev, + VL53L1_RANGE_CONFIG__VCSEL_PERIOD_A, + pdev->tim_cfg.range_config__vcsel_period_a); + + + + + + + + buffer[0] = pdev->tim_cfg.range_config__vcsel_period_a; + buffer[1] = pdev->tim_cfg.range_config__vcsel_period_a; + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_WriteMulti( + Dev, + VL53L1_SD_CONFIG__WOI_SD0, + buffer, + 2); + + + + + + + + pdev->customer.ref_spad_char__total_rate_target_mcps = + total_rate_target_mcps; + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_WrWord( + Dev, + VL53L1_REF_SPAD_CHAR__TOTAL_RATE_TARGET_MCPS, + total_rate_target_mcps); + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_WrWord( + Dev, + VL53L1_RANGE_CONFIG__SIGMA_THRESH, + max_count_rate_rtn_limit_mcps); + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_WrWord( + Dev, + VL53L1_RANGE_CONFIG__MIN_COUNT_RATE_RTN_LIMIT_MCPS, + min_count_rate_rtn_limit_mcps); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_ssc_config( + VL53L1_DEV Dev, + VL53L1_ssc_config_t *pssc_cfg, + uint16_t fast_osc_frequency) +{ + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t buffer[5]; + + uint32_t macro_period_us = 0; + uint16_t timeout_encoded = 0; + + LOG_FUNCTION_START(""); + + + + + + macro_period_us = + VL53L1_calc_macro_period_us( + fast_osc_frequency, + pssc_cfg->VL53L1_p_009); + + + + + + timeout_encoded = + VL53L1_calc_encoded_timeout( + pssc_cfg->timeout_us, + macro_period_us); + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_WrByte( + Dev, + VL53L1_CAL_CONFIG__VCSEL_START, + pssc_cfg->vcsel_start); + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_WrByte( + Dev, + VL53L1_GLOBAL_CONFIG__VCSEL_WIDTH, + pssc_cfg->vcsel_width); + + + + + buffer[0] = (uint8_t)((timeout_encoded & 0x0000FF00) >> 8); + buffer[1] = (uint8_t) (timeout_encoded & 0x000000FF); + buffer[2] = pssc_cfg->VL53L1_p_009; + buffer[3] = (uint8_t)((pssc_cfg->rate_limit_mcps & 0x0000FF00) >> 8); + buffer[4] = (uint8_t) (pssc_cfg->rate_limit_mcps & 0x000000FF); + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_WriteMulti( + Dev, + VL53L1_RANGE_CONFIG__TIMEOUT_MACROP_B_HI, + buffer, + 5); + + + + + + + + buffer[0] = pssc_cfg->VL53L1_p_009; + buffer[1] = pssc_cfg->VL53L1_p_009; + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_WriteMulti( + Dev, + VL53L1_SD_CONFIG__WOI_SD0, + buffer, + 2); + + + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_WrByte( + Dev, + VL53L1_NVM_BIST__CTRL, + pssc_cfg->array_select); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_spad_rate_data( + VL53L1_DEV Dev, + VL53L1_spad_rate_data_t *pspad_rates) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + int i = 0; + + uint8_t VL53L1_p_002[512]; + uint8_t *pdata = &VL53L1_p_002[0]; + + LOG_FUNCTION_START(""); + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_disable_firmware(Dev); + + + + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_ReadMulti( + Dev, + VL53L1_PRIVATE__PATCH_BASE_ADDR_RSLV, + pdata, + 512); + + + + pdata = &VL53L1_p_002[0]; + for (i = 0; i < VL53L1_NO_OF_SPAD_ENABLES; i++) { + pspad_rates->rate_data[i] = + (uint16_t)VL53L1_decode_unsigned_integer(pdata, 2); + pdata += 2; + } + + + + + pspad_rates->VL53L1_p_023 = VL53L1_NO_OF_SPAD_ENABLES; + pspad_rates->no_of_values = VL53L1_NO_OF_SPAD_ENABLES; + pspad_rates->fractional_bits = 15; + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_firmware(Dev); + + LOG_FUNCTION_END(status); + + return status; +} + + + + +VL53L1_Error VL53L1_dynamic_xtalk_correction_calc_required_samples( + VL53L1_DEV Dev + ) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_LLDriverResults_t *pres = VL53L1DevStructGetLLResultsHandle(Dev); + VL53L1_smudge_corrector_config_t *pconfig = + &(pdev->smudge_correct_config); + VL53L1_smudge_corrector_internals_t *pint = + &(pdev->smudge_corrector_internals); + + VL53L1_range_results_t *presults = &(pres->range_results); + VL53L1_range_data_t *pxmonitor = &(presults->xmonitor); + + uint32_t peak_duration_us = pxmonitor->peak_duration_us; + + uint64_t temp64a; + uint64_t temp64z; + + LOG_FUNCTION_START(""); + + if (peak_duration_us == 0) + peak_duration_us = 1000; + + temp64a = pxmonitor->VL53L1_p_021 + + pxmonitor->VL53L1_p_020; + temp64a = do_division_u((temp64a * 1000), peak_duration_us); + temp64a = do_division_u((temp64a * 1000), peak_duration_us); + + temp64z = (uint64_t)pconfig->noise_margin * (uint64_t)pxmonitor->VL53L1_p_006; + if (temp64z == 0) + temp64z = 1; + temp64a = temp64a * 1000 * 256; + temp64a = do_division_u(temp64a, temp64z); + temp64a = temp64a * 1000 * 256; + temp64a = do_division_u(temp64a, temp64z); + + pint->required_samples = (uint32_t)temp64a; + + + + if (pint->required_samples < 2) + pint->required_samples = 2; + + LOG_FUNCTION_END(status); + + return status; +} + +VL53L1_Error VL53L1_dynamic_xtalk_correction_calc_new_xtalk( + VL53L1_DEV Dev, + uint32_t xtalk_offset_out, + VL53L1_smudge_corrector_config_t *pconfig, + VL53L1_smudge_corrector_data_t *pout, + uint8_t add_smudge, + uint8_t soft_update + ) +{ + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + int16_t x_gradient_scaler; + int16_t y_gradient_scaler; + uint32_t orig_xtalk_offset; + int16_t orig_x_gradient; + int16_t orig_y_gradient; + uint8_t histo_merge_nb; + uint8_t i; + int32_t itemp32; + uint32_t SmudgeFactor; + VL53L1_xtalk_config_t *pX = &(pdev->xtalk_cfg); + VL53L1_xtalk_calibration_results_t *pC = &(pdev->xtalk_cal); + + LOG_FUNCTION_START(""); + + + + if (add_smudge == 1) { + pout->algo__crosstalk_compensation_plane_offset_kcps = + (uint32_t)xtalk_offset_out + + (uint32_t)pconfig->smudge_margin; + } else { + pout->algo__crosstalk_compensation_plane_offset_kcps = + (uint32_t)xtalk_offset_out; + } + + + + orig_xtalk_offset = + pX->nvm_default__crosstalk_compensation_plane_offset_kcps; + + orig_x_gradient = + pX->nvm_default__crosstalk_compensation_x_plane_gradient_kcps; + + orig_y_gradient = + pX->nvm_default__crosstalk_compensation_y_plane_gradient_kcps; + + if (((pconfig->user_scaler_set == 0) || + (pconfig->scaler_calc_method == 1)) && + (pC->algo__crosstalk_compensation_plane_offset_kcps != 0)) { + + + VL53L1_compute_histo_merge_nb(Dev, &histo_merge_nb); + if (histo_merge_nb == 0) + orig_xtalk_offset = + pC->algo__crosstalk_compensation_plane_offset_kcps; + else + orig_xtalk_offset = + pC->algo__xtalk_cpo_HistoMerge_kcps[histo_merge_nb-1]; + + + orig_x_gradient = + pC->algo__crosstalk_compensation_x_plane_gradient_kcps; + + orig_y_gradient = + pC->algo__crosstalk_compensation_y_plane_gradient_kcps; + } + + + + if ((pconfig->user_scaler_set == 0) && (orig_x_gradient == 0)) + pout->gradient_zero_flag |= 0x01; + + if ((pconfig->user_scaler_set == 0) && (orig_y_gradient == 0)) + pout->gradient_zero_flag |= 0x02; + + + + + + + if (orig_xtalk_offset == 0) + orig_xtalk_offset = 1; + + + + + if (pconfig->user_scaler_set == 1) { + x_gradient_scaler = pconfig->x_gradient_scaler; + y_gradient_scaler = pconfig->y_gradient_scaler; + } else { + + + + + x_gradient_scaler = (int16_t)do_division_s( + (((int32_t)orig_x_gradient) << 6), + orig_xtalk_offset); + pconfig->x_gradient_scaler = x_gradient_scaler; + y_gradient_scaler = (int16_t)do_division_s( + (((int32_t)orig_y_gradient) << 6), + orig_xtalk_offset); + pconfig->y_gradient_scaler = y_gradient_scaler; + } + + + + + if (pconfig->scaler_calc_method == 0) { + + + + + + + itemp32 = (int32_t)( + pout->algo__crosstalk_compensation_plane_offset_kcps * + x_gradient_scaler); + itemp32 = itemp32 >> 6; + if (itemp32 > 0xFFFF) + itemp32 = 0xFFFF; + + pout->algo__crosstalk_compensation_x_plane_gradient_kcps = + (int16_t)itemp32; + + itemp32 = (int32_t)( + pout->algo__crosstalk_compensation_plane_offset_kcps * + y_gradient_scaler); + itemp32 = itemp32 >> 6; + if (itemp32 > 0xFFFF) + itemp32 = 0xFFFF; + + pout->algo__crosstalk_compensation_y_plane_gradient_kcps = + (int16_t)itemp32; + } else if (pconfig->scaler_calc_method == 1) { + + + + + + itemp32 = (int32_t)(orig_xtalk_offset - + pout->algo__crosstalk_compensation_plane_offset_kcps); + itemp32 = (int32_t)(do_division_s(itemp32, 16)); + itemp32 = itemp32 << 2; + itemp32 = itemp32 + (int32_t)(orig_x_gradient); + if (itemp32 > 0xFFFF) + itemp32 = 0xFFFF; + + pout->algo__crosstalk_compensation_x_plane_gradient_kcps = + (int16_t)itemp32; + + itemp32 = (int32_t)(orig_xtalk_offset - + pout->algo__crosstalk_compensation_plane_offset_kcps); + itemp32 = (int32_t)(do_division_s(itemp32, 80)); + itemp32 = itemp32 << 2; + itemp32 = itemp32 + (int32_t)(orig_y_gradient); + if (itemp32 > 0xFFFF) + itemp32 = 0xFFFF; + + pout->algo__crosstalk_compensation_y_plane_gradient_kcps = + (int16_t)itemp32; + } + + + + if (pconfig->smudge_corr_apply_enabled == 1 && + (soft_update != 1) + ) { + + + pout->new_xtalk_applied_flag = 1; + + + + pX->algo__crosstalk_compensation_plane_offset_kcps = + pout->algo__crosstalk_compensation_plane_offset_kcps; + pX->algo__crosstalk_compensation_x_plane_gradient_kcps = + pout->algo__crosstalk_compensation_x_plane_gradient_kcps; + pX->algo__crosstalk_compensation_y_plane_gradient_kcps = + pout->algo__crosstalk_compensation_y_plane_gradient_kcps; + + + VL53L1_compute_histo_merge_nb(Dev, &histo_merge_nb); + if ((histo_merge_nb > 0) && + (pout->algo__crosstalk_compensation_plane_offset_kcps != 0)) { + + + SmudgeFactor = pC->algo__xtalk_cpo_HistoMerge_kcps[histo_merge_nb-1] * 1000 / + pout->algo__crosstalk_compensation_plane_offset_kcps ; + if (SmudgeFactor > 0) + for (i = 0; i < VL53L1_BIN_REC_SIZE; i++) { + pC->algo__xtalk_cpo_HistoMerge_kcps[i] *= 1000; + pC->algo__xtalk_cpo_HistoMerge_kcps[i] /= SmudgeFactor; + } + } + + + + if (pconfig->smudge_corr_single_apply == 1) { + + + pconfig->smudge_corr_apply_enabled = 0; + pconfig->smudge_corr_single_apply = 0; + } + } + + + + if (soft_update != 1) + pout->smudge_corr_valid = 1; + + LOG_FUNCTION_END(status); + + return status; +} + +#define CONT_CONTINUE 0 +#define CONT_NEXT_LOOP 1 +#define CONT_RESET 2 +VL53L1_Error VL53L1_dynamic_xtalk_correction_corrector( + VL53L1_DEV Dev + ) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_LLDriverResults_t *pres = VL53L1DevStructGetLLResultsHandle(Dev); + VL53L1_smudge_corrector_config_t *pconfig = + &(pdev->smudge_correct_config); + VL53L1_smudge_corrector_internals_t *pint = + &(pdev->smudge_corrector_internals); + VL53L1_smudge_corrector_data_t *pout = + &(pres->range_results.smudge_corrector_data); + VL53L1_range_results_t *pR = &(pres->range_results); + VL53L1_xtalk_config_t *pX = &(pdev->xtalk_cfg); + + uint8_t run_smudge_detection = 0; + uint8_t run_nodetect = 0; + uint8_t ambient_check = 0; + int32_t itemp32 = 0; + uint64_t utemp64 = 0; + uint8_t continue_processing = CONT_CONTINUE; + uint32_t xtalk_offset_out = 0; + uint32_t xtalk_offset_in = 0; + uint32_t current_xtalk = 0; + uint32_t smudge_margin_adjusted = 0; + uint8_t i = 0; + uint8_t nodetect_index = 0; + uint16_t amr; + + uint32_t cco; + + uint8_t histo_merge_nb; + + + LOG_FUNCTION_START(""); + + VL53L1_compute_histo_merge_nb(Dev, &histo_merge_nb); + if (histo_merge_nb == 0) + histo_merge_nb = 1; + + + VL53L1_dynamic_xtalk_correction_output_init(pres); + + + + ambient_check = (pconfig->smudge_corr_ambient_threshold == 0) || + ((pconfig->smudge_corr_ambient_threshold * histo_merge_nb) > + ((uint32_t)pR->xmonitor.ambient_count_rate_mcps)); + + + + + run_smudge_detection = (pconfig->smudge_corr_enabled == 1) && + ambient_check && + (pR->xmonitor.range_status + == VL53L1_DEVICEERROR_RANGECOMPLETE) && + (histo_merge_nb == VL53L1_BIN_REC_SIZE); + + + + + if ((pR->xmonitor.range_status + != VL53L1_DEVICEERROR_RANGECOMPLETE) && + (pconfig->smudge_corr_enabled == 1)) { + + + run_nodetect = 2; + for (i = 0; i < pR->active_results; i++) { + if (pR->VL53L1_p_002[i].range_status == + VL53L1_DEVICEERROR_RANGECOMPLETE) { + if (pR->VL53L1_p_002[i].median_range_mm + <= + pconfig->nodetect_min_range_mm) { + run_nodetect = 0; + } else { + if (run_nodetect == 2) { + run_nodetect = 1; + nodetect_index = i; + } + } + } + } + + if (run_nodetect == 2) + + + run_nodetect = 0; + + amr = + pR->VL53L1_p_002[nodetect_index].ambient_count_rate_mcps; + + if (run_nodetect == 1) { + + + + + + + + utemp64 = 1000 * ((uint64_t)amr); + + + + utemp64 = utemp64 << 9; + + + + if (utemp64 < pconfig->nodetect_ambient_threshold) + run_nodetect = 1; + else + run_nodetect = 0; + + } + } + + + if (run_smudge_detection == 1) { + + + pint->nodetect_counter = 0; + + + + VL53L1_dynamic_xtalk_correction_calc_required_samples(Dev); + + + + xtalk_offset_in = + pR->xmonitor.VL53L1_p_012; + + + + cco = pX->algo__crosstalk_compensation_plane_offset_kcps; + current_xtalk = ((uint32_t)cco) << 2; + + + + smudge_margin_adjusted = + ((uint32_t)(pconfig->smudge_margin)) << 2; + + + + itemp32 = xtalk_offset_in - current_xtalk + + smudge_margin_adjusted; + + if (itemp32 < 0) + itemp32 = itemp32 * (-1); + + + if (itemp32 > ((int32_t)pconfig->single_xtalk_delta)) { + if ((int32_t)xtalk_offset_in > + ((int32_t)current_xtalk - + (int32_t)smudge_margin_adjusted)) { + pout->single_xtalk_delta_flag = 1; + } else { + pout->single_xtalk_delta_flag = 2; + } + } + + + + pint->current_samples = pint->current_samples + 1; + + + + if (pint->current_samples > pconfig->sample_limit) { + pout->sample_limit_exceeded_flag = 1; + continue_processing = CONT_RESET; + } else { + + pint->accumulator = pint->accumulator + + xtalk_offset_in; + } + + if (pint->current_samples < pint->required_samples) + continue_processing = CONT_NEXT_LOOP; + + + + xtalk_offset_out = + (uint32_t)(do_division_u(pint->accumulator, + pint->current_samples)); + + + + itemp32 = xtalk_offset_out - current_xtalk + + smudge_margin_adjusted; + + if (itemp32 < 0) + itemp32 = itemp32 * (-1); + + if (continue_processing == CONT_CONTINUE && + (itemp32 >= ((int32_t)(pconfig->averaged_xtalk_delta))) + ) { + if ((int32_t)xtalk_offset_out > + ((int32_t)current_xtalk - + (int32_t)smudge_margin_adjusted)) + pout->averaged_xtalk_delta_flag = 1; + else + pout->averaged_xtalk_delta_flag = 2; + } + + if (continue_processing == CONT_CONTINUE && + (itemp32 < ((int32_t)(pconfig->averaged_xtalk_delta))) + ) + + + continue_processing = CONT_RESET; + + + + + pout->smudge_corr_clipped = 0; + if ((continue_processing == CONT_CONTINUE) && + (pconfig->smudge_corr_clip_limit != 0)) { + if (xtalk_offset_out > + (pconfig->smudge_corr_clip_limit * histo_merge_nb)) { + pout->smudge_corr_clipped = 1; + continue_processing = CONT_RESET; + } + } + + + + + + if (pconfig->user_xtalk_offset_limit_hi && + (xtalk_offset_out > + pconfig->user_xtalk_offset_limit)) + xtalk_offset_out = + pconfig->user_xtalk_offset_limit; + + + + + if ((pconfig->user_xtalk_offset_limit_hi == 0) && + (xtalk_offset_out < + pconfig->user_xtalk_offset_limit)) + xtalk_offset_out = + pconfig->user_xtalk_offset_limit; + + + + + xtalk_offset_out = xtalk_offset_out >> 2; + if (xtalk_offset_out > 0x3FFFF) + xtalk_offset_out = 0x3FFFF; + + + + if (continue_processing == CONT_CONTINUE) { + + + VL53L1_dynamic_xtalk_correction_calc_new_xtalk( + Dev, + xtalk_offset_out, + pconfig, + pout, + 1, + + 0 + + ); + + + + continue_processing = CONT_RESET; + } else { + + + VL53L1_dynamic_xtalk_correction_calc_new_xtalk( + Dev, + xtalk_offset_out, + pconfig, + pout, + 1, + + 1 + + ); + } + + + + if (continue_processing == CONT_RESET) { + pint->accumulator = 0; + pint->current_samples = 0; + pint->nodetect_counter = 0; + } + + } + + continue_processing = CONT_CONTINUE; + if (run_nodetect == 1) { + + + pint->nodetect_counter += 1; + + + + if (pint->nodetect_counter < pconfig->nodetect_sample_limit) + continue_processing = CONT_NEXT_LOOP; + + + + xtalk_offset_out = (uint32_t)(pconfig->nodetect_xtalk_offset); + + if (continue_processing == CONT_CONTINUE) { + + + VL53L1_dynamic_xtalk_correction_calc_new_xtalk( + Dev, + xtalk_offset_out, + pconfig, + pout, + 0, + + 0 + + ); + + + + pout->smudge_corr_valid = 2; + + + + continue_processing = CONT_RESET; + } else { + + + VL53L1_dynamic_xtalk_correction_calc_new_xtalk( + Dev, + xtalk_offset_out, + pconfig, + pout, + 0, + + 1 + + ); + } + + + + if (continue_processing == CONT_RESET) { + pint->accumulator = 0; + pint->current_samples = 0; + pint->nodetect_counter = 0; + } + } + + LOG_FUNCTION_END(status); + + return status; +} + +VL53L1_Error VL53L1_dynamic_xtalk_correction_data_init( + VL53L1_DEV Dev + ) +{ + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_LLDriverResults_t *pres = VL53L1DevStructGetLLResultsHandle(Dev); + + LOG_FUNCTION_START(""); + + + + + pdev->smudge_correct_config.smudge_corr_enabled = 1; + pdev->smudge_correct_config.smudge_corr_apply_enabled = 1; + pdev->smudge_correct_config.smudge_corr_single_apply = + VL53L1_TUNINGPARM_DYNXTALK_SMUDGE_COR_SINGLE_APPLY_DEFAULT; + + pdev->smudge_correct_config.smudge_margin = + VL53L1_TUNINGPARM_DYNXTALK_SMUDGE_MARGIN_DEFAULT; + pdev->smudge_correct_config.noise_margin = + VL53L1_TUNINGPARM_DYNXTALK_NOISE_MARGIN_DEFAULT; + pdev->smudge_correct_config.user_xtalk_offset_limit = + VL53L1_TUNINGPARM_DYNXTALK_XTALK_OFFSET_LIMIT_DEFAULT; + pdev->smudge_correct_config.user_xtalk_offset_limit_hi = + VL53L1_TUNINGPARM_DYNXTALK_XTALK_OFFSET_LIMIT_HI_DEFAULT; + pdev->smudge_correct_config.sample_limit = + VL53L1_TUNINGPARM_DYNXTALK_SAMPLE_LIMIT_DEFAULT; + pdev->smudge_correct_config.single_xtalk_delta = + VL53L1_TUNINGPARM_DYNXTALK_SINGLE_XTALK_DELTA_DEFAULT; + pdev->smudge_correct_config.averaged_xtalk_delta = + VL53L1_TUNINGPARM_DYNXTALK_AVERAGED_XTALK_DELTA_DEFAULT; + pdev->smudge_correct_config.smudge_corr_clip_limit = + VL53L1_TUNINGPARM_DYNXTALK_CLIP_LIMIT_DEFAULT; + pdev->smudge_correct_config.smudge_corr_ambient_threshold = + VL53L1_TUNINGPARM_DYNXTALK_XTALK_AMB_THRESHOLD_DEFAULT; + pdev->smudge_correct_config.scaler_calc_method = + 0; + + pdev->smudge_correct_config.x_gradient_scaler = + VL53L1_TUNINGPARM_DYNXTALK_XGRADIENT_SCALER_DEFAULT; + pdev->smudge_correct_config.y_gradient_scaler = + VL53L1_TUNINGPARM_DYNXTALK_YGRADIENT_SCALER_DEFAULT; + pdev->smudge_correct_config.user_scaler_set = + VL53L1_TUNINGPARM_DYNXTALK_USER_SCALER_SET_DEFAULT; + pdev->smudge_correct_config.nodetect_ambient_threshold = + VL53L1_TUNINGPARM_DYNXTALK_NODETECT_AMB_THRESHOLD_KCPS_DEFAULT; + pdev->smudge_correct_config.nodetect_sample_limit = + VL53L1_TUNINGPARM_DYNXTALK_NODETECT_SAMPLE_LIMIT_DEFAULT; + pdev->smudge_correct_config.nodetect_xtalk_offset = + VL53L1_TUNINGPARM_DYNXTALK_NODETECT_XTALK_OFFSET_KCPS_DEFAULT; + pdev->smudge_correct_config.nodetect_min_range_mm = + VL53L1_TUNINGPARM_DYNXTALK_NODETECT_MIN_RANGE_MM_DEFAULT; + + + + pdev->smudge_corrector_internals.current_samples = 0; + pdev->smudge_corrector_internals.required_samples = 0; + pdev->smudge_corrector_internals.accumulator = 0; + pdev->smudge_corrector_internals.nodetect_counter = 0; + + + + VL53L1_dynamic_xtalk_correction_output_init(pres); + + LOG_FUNCTION_END(status); + + return status; +} + +VL53L1_Error VL53L1_dynamic_xtalk_correction_output_init( + VL53L1_LLDriverResults_t *pres + ) +{ + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_smudge_corrector_data_t *pdata; + + LOG_FUNCTION_START(""); + + + + pdata = &(pres->range_results.smudge_corrector_data); + + pdata->smudge_corr_valid = 0; + pdata->smudge_corr_clipped = 0; + pdata->single_xtalk_delta_flag = 0; + pdata->averaged_xtalk_delta_flag = 0; + pdata->sample_limit_exceeded_flag = 0; + pdata->gradient_zero_flag = 0; + pdata->new_xtalk_applied_flag = 0; + + pdata->algo__crosstalk_compensation_plane_offset_kcps = 0; + pdata->algo__crosstalk_compensation_x_plane_gradient_kcps = 0; + pdata->algo__crosstalk_compensation_y_plane_gradient_kcps = 0; + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_xtalk_cal_data_init( + VL53L1_DEV Dev + ) +{ + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + + + + pdev->xtalk_cal.algo__crosstalk_compensation_plane_offset_kcps = 0; + pdev->xtalk_cal.algo__crosstalk_compensation_x_plane_gradient_kcps = 0; + pdev->xtalk_cal.algo__crosstalk_compensation_y_plane_gradient_kcps = 0; + memset(&pdev->xtalk_cal.algo__xtalk_cpo_HistoMerge_kcps[0], 0, sizeof(pdev->xtalk_cal.algo__xtalk_cpo_HistoMerge_kcps)); + + LOG_FUNCTION_END(status); + + return status; +} + + + + + + + + +VL53L1_Error VL53L1_low_power_auto_data_init( + VL53L1_DEV Dev + ) +{ + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + pdev->low_power_auto_data.vhv_loop_bound = + VL53L1_TUNINGPARM_LOWPOWERAUTO_VHV_LOOP_BOUND_DEFAULT; + pdev->low_power_auto_data.is_low_power_auto_mode = 0; + pdev->low_power_auto_data.low_power_auto_range_count = 0; + pdev->low_power_auto_data.saved_interrupt_config = 0; + pdev->low_power_auto_data.saved_vhv_init = 0; + pdev->low_power_auto_data.saved_vhv_timeout = 0; + pdev->low_power_auto_data.first_run_phasecal_result = 0; + pdev->low_power_auto_data.dss__total_rate_per_spad_mcps = 0; + pdev->low_power_auto_data.dss__required_spads = 0; + + LOG_FUNCTION_END(status); + + return status; +} + +VL53L1_Error VL53L1_low_power_auto_data_stop_range( + VL53L1_DEV Dev + ) +{ + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + + + + + pdev->low_power_auto_data.low_power_auto_range_count = 0xFF; + + pdev->low_power_auto_data.first_run_phasecal_result = 0; + pdev->low_power_auto_data.dss__total_rate_per_spad_mcps = 0; + pdev->low_power_auto_data.dss__required_spads = 0; + + + + if (pdev->low_power_auto_data.saved_vhv_init != 0) + pdev->stat_nvm.vhv_config__init = + pdev->low_power_auto_data.saved_vhv_init; + if (pdev->low_power_auto_data.saved_vhv_timeout != 0) + pdev->stat_nvm.vhv_config__timeout_macrop_loop_bound = + pdev->low_power_auto_data.saved_vhv_timeout; + + + + pdev->gen_cfg.phasecal_config__override = 0x00; + + LOG_FUNCTION_END(status); + + return status; +} + +VL53L1_Error VL53L1_config_low_power_auto_mode( + VL53L1_general_config_t *pgeneral, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_low_power_auto_data_t *plpadata + ) +{ + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + plpadata->is_low_power_auto_mode = 1; + + + + plpadata->low_power_auto_range_count = 0; + + + + pdynamic->system__sequence_config = + VL53L1_SEQUENCE_VHV_EN | + VL53L1_SEQUENCE_PHASECAL_EN | + VL53L1_SEQUENCE_DSS1_EN | + + + + + + + VL53L1_SEQUENCE_RANGE_EN; + + + + pgeneral->dss_config__manual_effective_spads_select = 200 << 8; + pgeneral->dss_config__roi_mode_control = + VL53L1_DEVICEDSSMODE__REQUESTED_EFFFECTIVE_SPADS; + + LOG_FUNCTION_END(status); + + return status; +} + +VL53L1_Error VL53L1_low_power_auto_setup_manual_calibration( + VL53L1_DEV Dev) +{ + + + + + + + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + pdev->low_power_auto_data.saved_vhv_init = + pdev->stat_nvm.vhv_config__init; + pdev->low_power_auto_data.saved_vhv_timeout = + pdev->stat_nvm.vhv_config__timeout_macrop_loop_bound; + + + + pdev->stat_nvm.vhv_config__init &= 0x7F; + + + pdev->stat_nvm.vhv_config__timeout_macrop_loop_bound = + (pdev->stat_nvm.vhv_config__timeout_macrop_loop_bound & 0x03) + + (pdev->low_power_auto_data.vhv_loop_bound << 2); + + + pdev->gen_cfg.phasecal_config__override = 0x01; + pdev->low_power_auto_data.first_run_phasecal_result = + pdev->dbg_results.phasecal_result__vcsel_start; + pdev->gen_cfg.cal_config__vcsel_start = + pdev->low_power_auto_data.first_run_phasecal_result; + + LOG_FUNCTION_END(status); + + return status; +} + +VL53L1_Error VL53L1_low_power_auto_update_DSS( + VL53L1_DEV Dev) +{ + + + + + + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + VL53L1_system_results_t *pS = &(pdev->sys_results); + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + uint32_t utemp32a; + + LOG_FUNCTION_START(""); + + + + + + + utemp32a = + pS->result__peak_signal_count_rate_crosstalk_corrected_mcps_sd0 + + pS->result__ambient_count_rate_mcps_sd0; + + + + if (utemp32a > 0xFFFF) + utemp32a = 0xFFFF; + + + + + + utemp32a = utemp32a << 16; + + + + if (pdev->sys_results.result__dss_actual_effective_spads_sd0 == 0) + status = VL53L1_ERROR_DIVISION_BY_ZERO; + else { + + + utemp32a = utemp32a / + pdev->sys_results.result__dss_actual_effective_spads_sd0; + + + pdev->low_power_auto_data.dss__total_rate_per_spad_mcps = + utemp32a; + + + + + utemp32a = pdev->stat_cfg.dss_config__target_total_rate_mcps << + 16; + + + + if (pdev->low_power_auto_data.dss__total_rate_per_spad_mcps + == 0) + status = VL53L1_ERROR_DIVISION_BY_ZERO; + else { + + + + utemp32a = utemp32a / + pdev->low_power_auto_data.dss__total_rate_per_spad_mcps; + + + + if (utemp32a > 0xFFFF) + utemp32a = 0xFFFF; + + + + pdev->low_power_auto_data.dss__required_spads = + (uint16_t)utemp32a; + + + + pdev->gen_cfg.dss_config__manual_effective_spads_select + = pdev->low_power_auto_data.dss__required_spads; + pdev->gen_cfg.dss_config__roi_mode_control = + VL53L1_DEVICEDSSMODE__REQUESTED_EFFFECTIVE_SPADS; + } + + } + + if (status == VL53L1_ERROR_DIVISION_BY_ZERO) { + + + + + + + pdev->low_power_auto_data.dss__required_spads = 0x8000; + + + + pdev->gen_cfg.dss_config__manual_effective_spads_select = + pdev->low_power_auto_data.dss__required_spads; + pdev->gen_cfg.dss_config__roi_mode_control = + VL53L1_DEVICEDSSMODE__REQUESTED_EFFFECTIVE_SPADS; + + + + status = VL53L1_ERROR_NONE; + } + + LOG_FUNCTION_END(status); + + return status; +} + + + + + +VL53L1_Error VL53L1_compute_histo_merge_nb( + VL53L1_DEV Dev, uint8_t *histo_merge_nb) +{ + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t i, timing; + uint8_t sum = 0; + + timing = (pdev->hist_data.bin_seq[0] == 7 ? 1 : 0); + for (i = 0; i < VL53L1_BIN_REC_SIZE; i++) + if (pdev->multi_bins_rec[i][timing][7] > 0) + sum++; + *histo_merge_nb = sum; + + return status; +} + diff --git a/drivers/input/misc/vl53L1/kona/src/vl53l1_core_support.c b/drivers/input/misc/vl53L1/kona/src/vl53l1_core_support.c new file mode 100644 index 000000000000..660b88488055 --- /dev/null +++ b/drivers/input/misc/vl53L1/kona/src/vl53l1_core_support.c @@ -0,0 +1,941 @@ + +/******************************************************************************* + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#include "vl53l1_ll_def.h" +#include "vl53l1_ll_device.h" +#include "vl53l1_platform_log.h" +#include "vl53l1_core_support.h" +#include "vl53l1_platform_user_data.h" +#include "vl53l1_platform_user_defines.h" + + + + + + +#define LOG_FUNCTION_START(fmt, ...) \ + _LOG_FUNCTION_START(VL53L1_TRACE_MODULE_CORE, fmt, ##__VA_ARGS__) +#define LOG_FUNCTION_END(status, ...) \ + _LOG_FUNCTION_END(VL53L1_TRACE_MODULE_CORE, status, ##__VA_ARGS__) +#define LOG_FUNCTION_END_FMT(status, fmt, ...) \ + _LOG_FUNCTION_END_FMT(VL53L1_TRACE_MODULE_CORE, \ + status, fmt, ##__VA_ARGS__) + +#define trace_print(level, ...) \ + _LOG_TRACE_PRINT(VL53L1_TRACE_MODULE_CORE, \ + level, VL53L1_TRACE_FUNCTION_NONE, ##__VA_ARGS__) + + +uint32_t VL53L1_calc_pll_period_us( + uint16_t fast_osc_frequency) +{ + + + + + + + + + + + + + + + uint32_t pll_period_us = 0; + + LOG_FUNCTION_START(""); + + if (fast_osc_frequency > 0) + pll_period_us = (0x01 << 30) / fast_osc_frequency; + + + + + + + + LOG_FUNCTION_END(0); + + return pll_period_us; +} + + +uint32_t VL53L1_duration_maths( + uint32_t pll_period_us, + uint32_t vcsel_parm_pclks, + uint32_t window_vclks, + uint32_t elapsed_mclks) +{ + + + + + + + + + + + uint64_t tmp_long_int = 0; + uint32_t duration_us = 0; + + + + + + + duration_us = window_vclks * pll_period_us; + + + + + + duration_us = duration_us >> 12; + + + + tmp_long_int = (uint64_t)duration_us; + + + + + + + duration_us = elapsed_mclks * vcsel_parm_pclks; + + + + + + duration_us = duration_us >> 4; + + + + + + tmp_long_int = tmp_long_int * (uint64_t)duration_us; + + + + + + tmp_long_int = tmp_long_int >> 12; + + + + if (tmp_long_int > 0xFFFFFFFF) + tmp_long_int = 0xFFFFFFFF; + + duration_us = (uint32_t)tmp_long_int; + + return duration_us; +} + + +uint32_t VL53L1_events_per_spad_maths( + int32_t VL53L1_p_013, + uint16_t num_spads, + uint32_t duration) +{ + uint64_t total_hist_counts = 0; + uint64_t xtalk_per_spad = 0; + uint32_t rate_per_spad_kcps = 0; + + + + + + + + + + + + + + + + + + uint64_t dividend = ((uint64_t)VL53L1_p_013 + * 1000 * 256); + + if (num_spads != 0) + total_hist_counts = do_division_u( + dividend, (uint64_t)num_spads); + + + + + if (duration > 0) { + + + + + + + + + uint64_t dividend = (((uint64_t)(total_hist_counts << 11)) + + ((uint64_t)duration / 2)); + + xtalk_per_spad = do_division_u(dividend, (uint64_t)duration); + } else { + xtalk_per_spad = (uint64_t)(total_hist_counts << 11); + } + + rate_per_spad_kcps = (uint32_t)xtalk_per_spad; + + return rate_per_spad_kcps; +} + + +uint32_t VL53L1_isqrt(uint32_t num) +{ + + + + + + + + + uint32_t res = 0; + uint32_t bit = 1 << 30; + + + + + while (bit > num) + bit >>= 2; + + while (bit != 0) { + if (num >= res + bit) { + num -= res + bit; + res = (res >> 1) + bit; + } else { + res >>= 1; + } + bit >>= 2; + } + + return res; +} + + +void VL53L1_hist_calc_zero_distance_phase( + VL53L1_histogram_bin_data_t *pdata) +{ + + + + + + + uint32_t period = 0; + uint32_t VL53L1_p_017 = 0; + + LOG_FUNCTION_START(""); + + period = 2048 * + (uint32_t)VL53L1_decode_vcsel_period(pdata->VL53L1_p_009); + + VL53L1_p_017 = period; + VL53L1_p_017 += (uint32_t)pdata->phasecal_result__reference_phase; + VL53L1_p_017 += (2048 * (uint32_t)pdata->phasecal_result__vcsel_start); + VL53L1_p_017 -= (2048 * (uint32_t)pdata->cal_config__vcsel_start); + + VL53L1_p_017 = VL53L1_p_017 % period; + + pdata->zero_distance_phase = (uint16_t)VL53L1_p_017; + + LOG_FUNCTION_END(0); +} + + +void VL53L1_hist_estimate_ambient_from_thresholded_bins( + int32_t ambient_threshold_sigma, + VL53L1_histogram_bin_data_t *pdata) +{ + + + + + + + + + + uint8_t bin = 0; + int32_t VL53L1_p_032 = 0; + + LOG_FUNCTION_START(""); + + + + + + + VL53L1_hist_find_min_max_bin_values(pdata); + + + + + + + + VL53L1_p_032 = + (int32_t)VL53L1_isqrt((uint32_t)pdata->min_bin_value); + VL53L1_p_032 *= ambient_threshold_sigma; + VL53L1_p_032 += 0x07; + VL53L1_p_032 = VL53L1_p_032 >> 4; + VL53L1_p_032 += pdata->min_bin_value; + + + + + + + pdata->number_of_ambient_samples = 0; + pdata->ambient_events_sum = 0; + + for (bin = 0; bin < pdata->VL53L1_p_024; bin++) + if (pdata->bin_data[bin] < VL53L1_p_032) { + pdata->ambient_events_sum += pdata->bin_data[bin]; + pdata->number_of_ambient_samples++; + } + + + + + + + if (pdata->number_of_ambient_samples > 0) { + pdata->VL53L1_p_004 = + pdata->ambient_events_sum; + pdata->VL53L1_p_004 += + ((int32_t)pdata->number_of_ambient_samples/2); + pdata->VL53L1_p_004 /= + (int32_t)pdata->number_of_ambient_samples; + } + + LOG_FUNCTION_END(0); +} + + +void VL53L1_hist_remove_ambient_bins( + VL53L1_histogram_bin_data_t *pdata) +{ + + + + + + + + uint8_t bin = 0; + uint8_t lc = 0; + uint8_t i = 0; + + + + + if ((pdata->bin_seq[0] & 0x07) == 0x07) { + + i = 0; + for (lc = 0; lc < VL53L1_MAX_BIN_SEQUENCE_LENGTH; lc++) { + if ((pdata->bin_seq[lc] & 0x07) != 0x07) { + pdata->bin_seq[i] = pdata->bin_seq[lc]; + pdata->bin_rep[i] = pdata->bin_rep[lc]; + i++; + } + } + + + + + + + for (lc = i; lc < VL53L1_MAX_BIN_SEQUENCE_LENGTH; lc++) { + pdata->bin_seq[lc] = VL53L1_MAX_BIN_SEQUENCE_CODE + 1; + pdata->bin_rep[lc] = 0; + } + } + + if (pdata->number_of_ambient_bins > 0) { + + + + for (bin = pdata->number_of_ambient_bins; + bin < pdata->VL53L1_p_023; bin++) { + pdata->bin_data[bin-pdata->number_of_ambient_bins] = + pdata->bin_data[bin]; + } + + + + pdata->VL53L1_p_024 = + pdata->VL53L1_p_024 - + pdata->number_of_ambient_bins; + pdata->number_of_ambient_bins = 0; + } +} + + +uint32_t VL53L1_calc_pll_period_mm( + uint16_t fast_osc_frequency) +{ + + + + + + + uint32_t pll_period_us = 0; + uint32_t pll_period_mm = 0; + + LOG_FUNCTION_START(""); + + + + + + + pll_period_us = VL53L1_calc_pll_period_us(fast_osc_frequency); + + + + + + + + + + + + + pll_period_mm = + VL53L1_SPEED_OF_LIGHT_IN_AIR_DIV_8 * + (pll_period_us >> 2); + + + + pll_period_mm = (pll_period_mm + (0x01<<15)) >> 16; + + LOG_FUNCTION_END(0); + + return pll_period_mm; +} + + +uint16_t VL53L1_rate_maths( + int32_t VL53L1_p_008, + uint32_t time_us) +{ + + + + + + + + + + + + + uint32_t tmp_int = 0; + uint32_t frac_bits = 7; + uint16_t rate_mcps = 0; + + + + + + + + if (VL53L1_p_008 > VL53L1_SPAD_TOTAL_COUNT_MAX) + tmp_int = VL53L1_SPAD_TOTAL_COUNT_MAX; + else if (VL53L1_p_008 > 0) + tmp_int = (uint32_t)VL53L1_p_008; + + + + + + + + + if (VL53L1_p_008 > VL53L1_SPAD_TOTAL_COUNT_RES_THRES) + frac_bits = 3; + else + frac_bits = 7; + + + + + + + + if (time_us > 0) + tmp_int = ((tmp_int << frac_bits) + (time_us / 2)) / time_us; + + + + + + if (VL53L1_p_008 > VL53L1_SPAD_TOTAL_COUNT_RES_THRES) + tmp_int = tmp_int << 4; + + + + + + + + if (tmp_int > 0xFFFF) + tmp_int = 0xFFFF; + + rate_mcps = (uint16_t)tmp_int; + + return rate_mcps; +} + + +uint16_t VL53L1_rate_per_spad_maths( + uint32_t frac_bits, + uint32_t peak_count_rate, + uint16_t num_spads, + uint32_t max_output_value) +{ + + uint32_t tmp_int = 0; + + + + uint16_t rate_per_spad = 0; + + + + + + + + + + if (num_spads > 0) { + tmp_int = (peak_count_rate << 8) << frac_bits; + tmp_int = (tmp_int + + ((uint32_t)num_spads / 2)) / + (uint32_t)num_spads; + } else { + tmp_int = ((peak_count_rate) << frac_bits); + } + + + + + if (tmp_int > max_output_value) + tmp_int = max_output_value; + + rate_per_spad = (uint16_t)tmp_int; + + return rate_per_spad; +} + + +int32_t VL53L1_range_maths( + uint16_t fast_osc_frequency, + uint16_t VL53L1_p_017, + uint16_t zero_distance_phase, + uint8_t fractional_bits, + int32_t gain_factor, + int32_t range_offset_mm) +{ + + + + + + uint32_t pll_period_us = 0; + + int64_t tmp_long_int = 0; + int32_t range_mm = 0; + int32_t range_mm_10 = 0; + + + + + pll_period_us = VL53L1_calc_pll_period_us(fast_osc_frequency); + + + + + + + + + + + tmp_long_int = (int64_t)VL53L1_p_017 - (int64_t)zero_distance_phase; + + + + + + + + + + + tmp_long_int = tmp_long_int * (int64_t)pll_period_us; + + + + + + + tmp_long_int = tmp_long_int / (0x01 << 9); + + + + + + + + + + + + tmp_long_int = tmp_long_int * VL53L1_SPEED_OF_LIGHT_IN_AIR_DIV_8; + + + + + + + tmp_long_int = tmp_long_int / (0x01 << 22); + + + + range_mm = (int32_t)tmp_long_int + range_offset_mm; + + + + range_mm *= gain_factor; + range_mm += 0x0400; + range_mm /= 0x0800; + + + + if (fractional_bits == 0) { + range_mm_10 = range_mm * 10; + range_mm_10 = range_mm_10 / (0x01 << 2); + if ((range_mm_10 % 10) < 5) + range_mm = (int16_t)(range_mm_10 / 10); + else + range_mm = (int16_t)(range_mm_10 / 10 + 1); + } else if (fractional_bits == 1) + range_mm = range_mm / (0x01 << 1); + + return range_mm; +} + + +uint8_t VL53L1_decode_vcsel_period(uint8_t vcsel_period_reg) +{ + + + + + + + uint8_t VL53L1_p_031 = 0; + + VL53L1_p_031 = (vcsel_period_reg + 1) << 1; + + return VL53L1_p_031; +} + + +void VL53L1_copy_xtalk_bin_data_to_histogram_data_struct( + VL53L1_xtalk_histogram_shape_t *pxtalk, + VL53L1_histogram_bin_data_t *phist) +{ + + + + + + + phist->cal_config__vcsel_start = + pxtalk->cal_config__vcsel_start; + phist->VL53L1_p_019 = + pxtalk->VL53L1_p_019; + phist->VL53L1_p_022 = + pxtalk->VL53L1_p_022; + + phist->phasecal_result__reference_phase = + pxtalk->phasecal_result__reference_phase; + phist->phasecal_result__vcsel_start = + pxtalk->phasecal_result__vcsel_start; + + phist->vcsel_width = + pxtalk->vcsel_width; + phist->zero_distance_phase = + pxtalk->zero_distance_phase; + + phist->zone_id = pxtalk->zone_id; + phist->VL53L1_p_023 = pxtalk->VL53L1_p_023; + phist->time_stamp = pxtalk->time_stamp; +} + + +void VL53L1_init_histogram_bin_data_struct( + int32_t bin_value, + uint16_t VL53L1_p_024, + VL53L1_histogram_bin_data_t *pdata) +{ + + + + + + + uint16_t i = 0; + + pdata->cfg_device_state = VL53L1_DEVICESTATE_SW_STANDBY; + pdata->rd_device_state = VL53L1_DEVICESTATE_SW_STANDBY; + + pdata->zone_id = 0; + pdata->time_stamp = 0; + + pdata->VL53L1_p_022 = 0; + pdata->VL53L1_p_023 = VL53L1_HISTOGRAM_BUFFER_SIZE; + pdata->VL53L1_p_024 = (uint8_t)VL53L1_p_024; + pdata->number_of_ambient_bins = 0; + + pdata->result__interrupt_status = 0; + pdata->result__range_status = 0; + pdata->result__report_status = 0; + pdata->result__stream_count = 0; + + pdata->result__dss_actual_effective_spads = 0; + pdata->phasecal_result__reference_phase = 0; + pdata->phasecal_result__vcsel_start = 0; + pdata->cal_config__vcsel_start = 0; + + pdata->vcsel_width = 0; + pdata->VL53L1_p_009 = 0; + pdata->VL53L1_p_019 = 0; + pdata->total_periods_elapsed = 0; + + pdata->min_bin_value = 0; + pdata->max_bin_value = 0; + + pdata->zero_distance_phase = 0; + pdata->number_of_ambient_samples = 0; + pdata->ambient_events_sum = 0; + pdata->VL53L1_p_004 = 0; + + for (i = 0; i < VL53L1_MAX_BIN_SEQUENCE_LENGTH; i++) + pdata->bin_seq[i] = (uint8_t)i; + + for (i = 0; i < VL53L1_MAX_BIN_SEQUENCE_LENGTH; i++) + pdata->bin_rep[i] = 1; + + + for (i = 0; i < VL53L1_HISTOGRAM_BUFFER_SIZE; i++) + if (i < VL53L1_p_024) + pdata->bin_data[i] = bin_value; + else + pdata->bin_data[i] = 0; + + +} + + +void VL53L1_decode_row_col( + uint8_t spad_number, + uint8_t *prow, + uint8_t *pcol) +{ + + + + + + + + if (spad_number > 127) { + *prow = 8 + ((255-spad_number) & 0x07); + *pcol = (spad_number-128) >> 3; + } else { + *prow = spad_number & 0x07; + *pcol = (127-spad_number) >> 3; + } +} + + +void VL53L1_hist_find_min_max_bin_values( + VL53L1_histogram_bin_data_t *pdata) +{ + + + + + + uint8_t bin = 0; + + LOG_FUNCTION_START(""); + + for (bin = 0; bin < pdata->VL53L1_p_024; bin++) { + + if (bin == 0 || pdata->min_bin_value >= pdata->bin_data[bin]) + pdata->min_bin_value = pdata->bin_data[bin]; + + if (bin == 0 || pdata->max_bin_value <= pdata->bin_data[bin]) + pdata->max_bin_value = pdata->bin_data[bin]; + + } + + LOG_FUNCTION_END(0); + +} + + +void VL53L1_hist_estimate_ambient_from_ambient_bins( + VL53L1_histogram_bin_data_t *pdata) +{ + + + + + + + uint8_t bin = 0; + + LOG_FUNCTION_START(""); + + if (pdata->number_of_ambient_bins > 0) { + + pdata->number_of_ambient_samples = + pdata->number_of_ambient_bins; + + + + + pdata->ambient_events_sum = 0; + for (bin = 0; bin < pdata->number_of_ambient_bins; bin++) + pdata->ambient_events_sum += pdata->bin_data[bin]; + + pdata->VL53L1_p_004 = pdata->ambient_events_sum; + pdata->VL53L1_p_004 += + ((int32_t)pdata->number_of_ambient_bins / 2); + pdata->VL53L1_p_004 /= + (int32_t)pdata->number_of_ambient_bins; + + } + + LOG_FUNCTION_END(0); +} + + diff --git a/drivers/input/misc/vl53L1/kona/src/vl53l1_error_strings.c b/drivers/input/misc/vl53L1/kona/src/vl53l1_error_strings.c new file mode 100644 index 000000000000..f559233e2ae9 --- /dev/null +++ b/drivers/input/misc/vl53L1/kona/src/vl53l1_error_strings.c @@ -0,0 +1,334 @@ + +/******************************************************************************* + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#include "vl53l1_error_codes.h" +#include "vl53l1_error_strings.h" +#include "vl53l1_platform_log.h" +#include "vl53l1_ll_def.h" + +#define LOG_FUNCTION_START(fmt, ...) \ + _LOG_FUNCTION_START(VL53L1_TRACE_MODULE_API, fmt, ##__VA_ARGS__) +#define LOG_FUNCTION_END(status, ...) \ + _LOG_FUNCTION_END(VL53L1_TRACE_MODULE_API, status, ##__VA_ARGS__) +#define LOG_FUNCTION_END_FMT(status, fmt, ...) \ + _LOG_FUNCTION_END_FMT(VL53L1_TRACE_MODULE_API, \ + status, fmt, ##__VA_ARGS__) + + +VL53L1_Error VL53L1_get_pal_error_string( +#ifndef VL53L1_USE_EMPTY_STRING + VL53L1_Error PalErrorCode, +#endif + char *pPalErrorString) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + +#ifdef VL53L1_USE_EMPTY_STRING + SUPPRESS_UNUSED_WARNING(PalErrorCode); +#endif + + LOG_FUNCTION_START(""); + +#ifdef VL53L1_USE_EMPTY_STRING + VL53L1_COPYSTRING(pPalErrorString, ""); +#else + + switch (PalErrorCode) { + case VL53L1_ERROR_NONE: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_NONE); + break; + case VL53L1_ERROR_CALIBRATION_WARNING: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_CALIBRATION_WARNING); + break; + case VL53L1_ERROR_MIN_CLIPPED: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_MIN_CLIPPED); + break; + case VL53L1_ERROR_UNDEFINED: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_UNDEFINED); + break; + case VL53L1_ERROR_INVALID_PARAMS: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_INVALID_PARAMS); + break; + case VL53L1_ERROR_NOT_SUPPORTED: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_NOT_SUPPORTED); + break; + case VL53L1_ERROR_RANGE_ERROR: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_RANGE_ERROR); + break; + case VL53L1_ERROR_TIME_OUT: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_TIME_OUT); + break; + case VL53L1_ERROR_MODE_NOT_SUPPORTED: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_MODE_NOT_SUPPORTED); + break; + case VL53L1_ERROR_BUFFER_TOO_SMALL: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_BUFFER_TOO_SMALL); + break; + case VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_COMMS_BUFFER_TOO_SMALL); + break; + case VL53L1_ERROR_GPIO_NOT_EXISTING: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_GPIO_NOT_EXISTING); + break; + case VL53L1_ERROR_GPIO_FUNCTIONALITY_NOT_SUPPORTED: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_GPIO_FUNCTIONALITY_NOT_SUPPORTED); + break; + case VL53L1_ERROR_CONTROL_INTERFACE: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_CONTROL_INTERFACE); + break; + case VL53L1_ERROR_INVALID_COMMAND: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_INVALID_COMMAND); + break; + case VL53L1_ERROR_DIVISION_BY_ZERO: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_DIVISION_BY_ZERO); + break; + case VL53L1_ERROR_REF_SPAD_INIT: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_REF_SPAD_INIT); + break; + case VL53L1_ERROR_GPH_SYNC_CHECK_FAIL: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_GPH_SYNC_CHECK_FAIL); + break; + case VL53L1_ERROR_STREAM_COUNT_CHECK_FAIL: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_STREAM_COUNT_CHECK_FAIL); + break; + case VL53L1_ERROR_GPH_ID_CHECK_FAIL: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_GPH_ID_CHECK_FAIL); + break; + case VL53L1_ERROR_ZONE_STREAM_COUNT_CHECK_FAIL: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_ZONE_STREAM_COUNT_CHECK_FAIL); + break; + case VL53L1_ERROR_ZONE_GPH_ID_CHECK_FAIL: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_ZONE_GPH_ID_CHECK_FAIL); + break; + + case VL53L1_ERROR_XTALK_EXTRACTION_NO_SAMPLE_FAIL: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_XTALK_EXTRACTION_NO_SAMPLES_FAIL); + break; + case VL53L1_ERROR_XTALK_EXTRACTION_SIGMA_LIMIT_FAIL: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_XTALK_EXTRACTION_SIGMA_LIMIT_FAIL); + break; + + case VL53L1_ERROR_OFFSET_CAL_NO_SAMPLE_FAIL: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_OFFSET_CAL_NO_SAMPLE_FAIL); + break; + case VL53L1_ERROR_OFFSET_CAL_NO_SPADS_ENABLED_FAIL: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_OFFSET_CAL_NO_SPADS_ENABLED_FAIL); + break; + case VL53L1_ERROR_ZONE_CAL_NO_SAMPLE_FAIL: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_ZONE_CAL_NO_SAMPLE_FAIL); + break; + + case VL53L1_WARNING_OFFSET_CAL_MISSING_SAMPLES: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_WARNING_OFFSET_CAL_MISSING_SAMPLES); + break; + case VL53L1_WARNING_OFFSET_CAL_SIGMA_TOO_HIGH: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_WARNING_OFFSET_CAL_SIGMA_TOO_HIGH); + break; + case VL53L1_WARNING_OFFSET_CAL_RATE_TOO_HIGH: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_WARNING_OFFSET_CAL_RATE_TOO_HIGH); + break; + case VL53L1_WARNING_OFFSET_CAL_SPAD_COUNT_TOO_LOW: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_WARNING_OFFSET_CAL_SPAD_COUNT_TOO_LOW); + break; + + case VL53L1_WARNING_ZONE_CAL_MISSING_SAMPLES: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_WARNING_ZONE_CAL_MISSING_SAMPLES); + break; + case VL53L1_WARNING_ZONE_CAL_SIGMA_TOO_HIGH: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_WARNING_ZONE_CAL_SIGMA_TOO_HIGH); + break; + case VL53L1_WARNING_ZONE_CAL_RATE_TOO_HIGH: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_WARNING_ZONE_CAL_RATE_TOO_HIGH); + break; + + case VL53L1_WARNING_REF_SPAD_CHAR_NOT_ENOUGH_SPADS: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_WARNING_REF_SPAD_CHAR_NOT_ENOUGH_SPADS); + break; + case VL53L1_WARNING_REF_SPAD_CHAR_RATE_TOO_HIGH: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_WARNING_REF_SPAD_CHAR_RATE_TOO_HIGH); + break; + case VL53L1_WARNING_REF_SPAD_CHAR_RATE_TOO_LOW: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_WARNING_REF_SPAD_CHAR_RATE_TOO_LOW); + break; + + case VL53L1_WARNING_XTALK_MISSING_SAMPLES: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_WARNING_XTALK_MISSING_SAMPLES); + break; + case VL53L1_WARNING_XTALK_NO_SAMPLES_FOR_GRADIENT: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_WARNING_XTALK_NO_SAMPLES_FOR_GRADIENT); + break; + case VL53L1_WARNING_XTALK_SIGMA_LIMIT_FOR_GRADIENT: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_WARNING_XTALK_SIGMA_LIMIT_FOR_GRADIENT); + break; + + case VL53L1_ERROR_DEVICE_FIRMWARE_TOO_OLD: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_DEVICE_FIRMWARE_TOO_OLD); + break; + case VL53L1_ERROR_DEVICE_FIRMWARE_TOO_NEW: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_DEVICE_FIRMWARE_TOO_NEW); + break; + case VL53L1_ERROR_UNIT_TEST_FAIL: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_UNIT_TEST_FAIL); + break; + case VL53L1_ERROR_FILE_READ_FAIL: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_FILE_READ_FAIL); + break; + case VL53L1_ERROR_FILE_WRITE_FAIL: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_FILE_WRITE_FAIL); + break; + case VL53L1_ERROR_NOT_IMPLEMENTED: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_NOT_IMPLEMENTED); + break; + default: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_UNKNOW_ERROR_CODE); + } + +#endif + + LOG_FUNCTION_END(Status); + + return Status; +} + diff --git a/drivers/input/misc/vl53L1/kona/src/vl53l1_hist_char.c b/drivers/input/misc/vl53L1/kona/src/vl53l1_hist_char.c new file mode 100644 index 000000000000..e5b12c7fe3c6 --- /dev/null +++ b/drivers/input/misc/vl53L1/kona/src/vl53l1_hist_char.c @@ -0,0 +1,282 @@ + +/******************************************************************************* + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#include + +#include + + + + + + + +#include "vl53l1_core.h" +#include "vl53l1_register_settings.h" +#include "vl53l1_hist_char.h" + +#define LOG_FUNCTION_START(fmt, ...) \ + _LOG_FUNCTION_START(VL53L1_TRACE_MODULE_HISTOGRAM, fmt, ##__VA_ARGS__) +#define LOG_FUNCTION_END(status, ...) \ + _LOG_FUNCTION_END(VL53L1_TRACE_MODULE_HISTOGRAM, status, ##__VA_ARGS__) +#define LOG_FUNCTION_END_FMT(status, fmt, ...) \ + _LOG_FUNCTION_END_FMT(VL53L1_TRACE_MODULE_HISTOGRAM,\ + status, fmt, ##__VA_ARGS__) + + +VL53L1_Error VL53L1_set_calib_config( + VL53L1_DEV Dev, + uint8_t vcsel_delay__a0, + uint8_t calib_1, + uint8_t calib_2, + uint8_t calib_3, + uint8_t calib_2__a0, + uint8_t spad_readout) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[3]; + + LOG_FUNCTION_START(""); + + + + + status = VL53L1_enable_powerforce(Dev); + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_disable_firmware(Dev); + + + + + + if (status == VL53L1_ERROR_NONE) { + status = VL53L1_WrByte( + Dev, + VL53L1_RANGING_CORE__VCSEL_DELAY__A0, + vcsel_delay__a0); + } + + + + + if (status == VL53L1_ERROR_NONE) { + + + + + + + + comms_buffer[0] = calib_1; + comms_buffer[1] = calib_2; + comms_buffer[2] = calib_3; + + status = VL53L1_WriteMulti( + Dev, + VL53L1_RANGING_CORE__CALIB_1, + comms_buffer, + 3); + } + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WrByte( + Dev, + VL53L1_RANGING_CORE__CALIB_2__A0, + calib_2__a0); + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WrByte( + Dev, + VL53L1_RANGING_CORE__SPAD_READOUT, + spad_readout); + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_firmware(Dev); + + LOG_FUNCTION_END(status); + + return status; +} + + + +VL53L1_Error VL53L1_set_hist_calib_pulse_delay( + VL53L1_DEV Dev, + uint8_t calib_delay) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + status = + VL53L1_set_calib_config( + Dev, + 0x01, + + calib_delay, + + 0x04, + + 0x08, + + 0x14, + + VL53L1_RANGING_CORE__SPAD_READOUT__CALIB_PULSES); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_disable_calib_pulse_delay( + VL53L1_DEV Dev) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + status = + VL53L1_set_calib_config( + Dev, + 0x00, + + 0x00, + + 0x00, + + 0x00, + + 0x00, + + VL53L1_RANGING_CORE__SPAD_READOUT__STANDARD); + + LOG_FUNCTION_END(status); + + return status; +} + + diff --git a/drivers/input/misc/vl53L1/kona/src/vl53l1_nvm.c b/drivers/input/misc/vl53L1/kona/src/vl53l1_nvm.c new file mode 100644 index 000000000000..312f49b9c690 --- /dev/null +++ b/drivers/input/misc/vl53L1/kona/src/vl53l1_nvm.c @@ -0,0 +1,1751 @@ + +/******************************************************************************* + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#ifdef _MSC_VER +#define snprintf _snprintf +#endif + + + + + + +#include "vl53l1_ll_def.h" +#include "vl53l1_platform.h" +#include "vl53l1_platform_log.h" +#include "vl53l1_register_map.h" +#include "vl53l1_core.h" +#include "vl53l1_nvm_structs.h" +#include "vl53l1_nvm_map.h" +#include "vl53l1_nvm.h" + + + + + +#define LOG_FUNCTION_START(fmt, ...) \ + _LOG_FUNCTION_START(VL53L1_TRACE_MODULE_NVM, fmt, ##__VA_ARGS__) +#define LOG_FUNCTION_END(status, ...) \ + _LOG_FUNCTION_END(VL53L1_TRACE_MODULE_NVM, status, ##__VA_ARGS__) +#define LOG_FUNCTION_END_FMT(status, fmt, ...) \ + _LOG_FUNCTION_END_FMT(VL53L1_TRACE_MODULE_NVM,\ + status, fmt, ##__VA_ARGS__) + +#define trace_print(level, ...) \ + _LOG_TRACE_PRINT(VL53L1_TRACE_MODULE_NVM, \ + level, VL53L1_TRACE_FUNCTION_NONE, ##__VA_ARGS__) + + +VL53L1_Error VL53L1_nvm_enable( + VL53L1_DEV Dev, + uint16_t nvm_ctrl_pulse_width, + int32_t nvm_power_up_delay_us) +{ + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_disable_firmware(Dev); + + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_powerforce(Dev); + + + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WaitUs( + Dev, + VL53L1_ENABLE_POWERFORCE_SETTLING_TIME_US); + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WrByte( + Dev, + VL53L1_RANGING_CORE__NVM_CTRL__PDN, + 0x01); + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WrByte( + Dev, + VL53L1_RANGING_CORE__CLK_CTRL1, + 0x05); + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WaitUs( + Dev, + nvm_power_up_delay_us); + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WrByte( + Dev, + VL53L1_RANGING_CORE__NVM_CTRL__MODE, + 0x01); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WrWord( + Dev, + VL53L1_RANGING_CORE__NVM_CTRL__PULSE_WIDTH_MSB, + nvm_ctrl_pulse_width); + + LOG_FUNCTION_END(status); + + return status; + +} + + +VL53L1_Error VL53L1_nvm_read( + VL53L1_DEV Dev, + uint8_t start_address, + uint8_t count, + uint8_t *pdata) +{ + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t nvm_addr = 0; + + LOG_FUNCTION_START(""); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%-12s = 0x%02X (%3u)\n", + "nvm_addr", nvm_addr, nvm_addr); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%-12s = 0x%02X (%3u)\n", + "count", count, count); + + for (nvm_addr = start_address; + nvm_addr < (start_address+count) ; nvm_addr++) { + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WrByte( + Dev, + VL53L1_RANGING_CORE__NVM_CTRL__ADDR, + nvm_addr); + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WrByte( + Dev, + VL53L1_RANGING_CORE__NVM_CTRL__READN, + 0x00); + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WaitUs( + Dev, + VL53L1_NVM_READ_TRIGGER_DELAY_US); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WrByte( + Dev, + VL53L1_RANGING_CORE__NVM_CTRL__READN, + 0x01); + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_ReadMulti( + Dev, + VL53L1_RANGING_CORE__NVM_CTRL__DATAOUT_MMM, + pdata, + 4); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "NVM address : 0x%02X = 0x%02X%02X%02X%02X\n", + nvm_addr, *pdata, *(pdata+1), *(pdata+2), *(pdata+3)); + + + + + pdata = pdata + 4; + + + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_nvm_disable( + VL53L1_DEV Dev) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_WrByte( + Dev, + VL53L1_RANGING_CORE__NVM_CTRL__READN, + 0x01); + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WrByte( + Dev, + VL53L1_RANGING_CORE__NVM_CTRL__PDN, + 0x00); + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_disable_powerforce(Dev); + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_firmware(Dev); + + LOG_FUNCTION_END(status); + + return status; + +} + + +VL53L1_Error VL53L1_nvm_format_decode( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_decoded_nvm_data_t *pdata) +{ + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + uint8_t i = 0; + uint8_t *ptmp = NULL; + int pptmp[VL53L1_NVM_MAX_FMT_RANGE_DATA]; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_NVM_SIZE_IN_BYTES) + return VL53L1_ERROR_BUFFER_TOO_SMALL; + + pdata->nvm__identification_model_id = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__IDENTIFICATION__MODEL_ID, + 0x000000FF, + 0, + 0); + pdata->nvm__identification_module_type = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__IDENTIFICATION__MODULE_TYPE, + 0x000000FF, + 0, + 0); + pdata->nvm__identification_revision_id = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__IDENTIFICATION__REVISION_ID, + 0x0000000F, + 0, + 0); + pdata->nvm__identification_module_id = + (uint16_t)VL53L1_i2c_decode_with_mask( + 2, + pbuffer + VL53L1_NVM__IDENTIFICATION__MODULE_ID, + 0x0000FFFF, + 0, + 0); + pdata->nvm__i2c_valid = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__I2C_VALID, + 0x000000FF, + 0, + 0); + pdata->nvm__i2c_device_address_ews = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__I2C_SLAVE__DEVICE_ADDRESS, + 0x000000FF, + 0, + 0); + pdata->nvm__ews__fast_osc_frequency = + (uint16_t)VL53L1_i2c_decode_with_mask( + 2, + pbuffer + + VL53L1_NVM__EWS__OSC_MEASURED__FAST_OSC_FREQUENCY, + 0x0000FFFF, + 0, + 0); + pdata->nvm__ews__fast_osc_trim_max = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__EWS__FAST_OSC_TRIM_MAX, + 0x0000007F, + 0, + 0); + pdata->nvm__ews__fast_osc_freq_set = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__EWS__FAST_OSC_FREQ_SET, + 0x00000007, + 0, + 0); + pdata->nvm__ews__slow_osc_calibration = + (uint16_t)VL53L1_i2c_decode_with_mask( + 2, + pbuffer + VL53L1_NVM__EWS__SLOW_OSC_CALIBRATION, + 0x000003FF, + 0, + 0); + pdata->nvm__fmt__fast_osc_frequency = + (uint16_t)VL53L1_i2c_decode_with_mask( + 2, + pbuffer + + VL53L1_NVM__FMT__OSC_MEASURED__FAST_OSC_FREQUENCY, + 0x0000FFFF, + 0, + 0); + pdata->nvm__fmt__fast_osc_trim_max = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__FAST_OSC_TRIM_MAX, + 0x0000007F, + 0, + 0); + pdata->nvm__fmt__fast_osc_freq_set = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__FAST_OSC_FREQ_SET, + 0x00000007, + 0, + 0); + pdata->nvm__fmt__slow_osc_calibration = + (uint16_t)VL53L1_i2c_decode_with_mask( + 2, + pbuffer + VL53L1_NVM__FMT__SLOW_OSC_CALIBRATION, + 0x000003FF, + 0, + 0); + pdata->nvm__vhv_config_unlock = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__VHV_CONFIG_UNLOCK, + 0x000000FF, + 0, + 0); + pdata->nvm__ref_selvddpix = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__REF_SELVDDPIX, + 0x0000000F, + 0, + 0); + pdata->nvm__ref_selvquench = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__REF_SELVQUENCH, + 0x00000078, + 3, + 0); + pdata->nvm__regavdd1v2_sel = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__REGAVDD1V2_SEL_REGDVDD1V2_SEL, + 0x0000000C, + 2, + 0); + pdata->nvm__regdvdd1v2_sel = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__REGAVDD1V2_SEL_REGDVDD1V2_SEL, + 0x00000003, + 0, + 0); + pdata->nvm__vhv_timeout__macrop = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + + VL53L1_NVM__VHV_CONFIG__TIMEOUT_MACROP_LOOP_BOUND, + 0x00000003, + 0, + 0); + pdata->nvm__vhv_loop_bound = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + + VL53L1_NVM__VHV_CONFIG__TIMEOUT_MACROP_LOOP_BOUND, + 0x000000FC, + 2, + 0); + pdata->nvm__vhv_count_threshold = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__VHV_CONFIG__COUNT_THRESH, + 0x000000FF, + 0, + 0); + pdata->nvm__vhv_offset = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__VHV_CONFIG__OFFSET, + 0x0000003F, + 0, + 0); + pdata->nvm__vhv_init_enable = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__VHV_CONFIG__INIT, + 0x00000080, + 7, + 0); + pdata->nvm__vhv_init_value = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__VHV_CONFIG__INIT, + 0x0000003F, + 0, + 0); + pdata->nvm__laser_safety_vcsel_trim_ll = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__LASER_SAFETY__VCSEL_TRIM_LL, + 0x00000007, + 0, + 0); + pdata->nvm__laser_safety_vcsel_selion_ll = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__LASER_SAFETY__VCSEL_SELION_LL, + 0x0000003F, + 0, + 0); + pdata->nvm__laser_safety_vcsel_selion_max_ll = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__LASER_SAFETY__VCSEL_SELION_MAX_LL, + 0x0000003F, + 0, + 0); + pdata->nvm__laser_safety_mult_ll = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__LASER_SAFETY__MULT_LL, + 0x0000003F, + 0, + 0); + pdata->nvm__laser_safety_clip_ll = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__LASER_SAFETY__CLIP_LL, + 0x0000003F, + 0, + 0); + pdata->nvm__laser_safety_vcsel_trim_ld = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__LASER_SAFETY__VCSEL_TRIM_LD, + 0x00000007, + 0, + 0); + pdata->nvm__laser_safety_vcsel_selion_ld = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__LASER_SAFETY__VCSEL_SELION_LD, + 0x0000003F, + 0, + 0); + pdata->nvm__laser_safety_vcsel_selion_max_ld = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__LASER_SAFETY__VCSEL_SELION_MAX_LD, + 0x0000003F, + 0, + 0); + pdata->nvm__laser_safety_mult_ld = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__LASER_SAFETY__MULT_LD, + 0x0000003F, + 0, + 0); + pdata->nvm__laser_safety_clip_ld = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__LASER_SAFETY__CLIP_LD, + 0x0000003F, + 0, + 0); + pdata->nvm__laser_safety_lock_byte = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__LASER_SAFETY_LOCK_BYTE, + 0x000000FF, + 0, + 0); + pdata->nvm__laser_safety_unlock_byte = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__LASER_SAFETY_UNLOCK_BYTE, + 0x000000FF, + 0, + 0); + + + + + ptmp = pbuffer + VL53L1_NVM__EWS__SPAD_ENABLES_RTN_0_; + for (i = 0 ; i < VL53L1_RTN_SPAD_BUFFER_SIZE ; i++) + pdata->nvm__ews__spad_enables_rtn[i] = *ptmp++; + + ptmp = pbuffer + VL53L1_NVM__EWS__SPAD_ENABLES_REF__LOC1_0_; + for (i = 0 ; i < VL53L1_REF_SPAD_BUFFER_SIZE ; i++) + pdata->nvm__ews__spad_enables_ref__loc1[i] = *ptmp++; + + ptmp = pbuffer + VL53L1_NVM__EWS__SPAD_ENABLES_REF__LOC2_0_; + for (i = 0 ; i < VL53L1_REF_SPAD_BUFFER_SIZE ; i++) + pdata->nvm__ews__spad_enables_ref__loc2[i] = *ptmp++; + + ptmp = pbuffer + VL53L1_NVM__EWS__SPAD_ENABLES_REF__LOC3_0_; + for (i = 0 ; i < VL53L1_REF_SPAD_BUFFER_SIZE ; i++) + pdata->nvm__ews__spad_enables_ref__loc3[i] = *ptmp++; + + + + + ptmp = pbuffer + VL53L1_NVM__FMT__SPAD_ENABLES_RTN_0_; + for (i = 0 ; i < VL53L1_RTN_SPAD_BUFFER_SIZE ; i++) + pdata->nvm__fmt__spad_enables_rtn[i] = *ptmp++; + + ptmp = pbuffer + VL53L1_NVM__FMT__SPAD_ENABLES_REF__LOC1_0_; + for (i = 0 ; i < VL53L1_REF_SPAD_BUFFER_SIZE ; i++) + pdata->nvm__fmt__spad_enables_ref__loc1[i] = *ptmp++; + + ptmp = pbuffer + VL53L1_NVM__FMT__SPAD_ENABLES_REF__LOC2_0_; + for (i = 0 ; i < VL53L1_REF_SPAD_BUFFER_SIZE ; i++) + pdata->nvm__fmt__spad_enables_ref__loc2[i] = *ptmp++; + + ptmp = pbuffer + VL53L1_NVM__FMT__SPAD_ENABLES_REF__LOC3_0_; + for (i = 0 ; i < VL53L1_REF_SPAD_BUFFER_SIZE ; i++) + pdata->nvm__fmt__spad_enables_ref__loc3[i] = *ptmp++; + + + pdata->nvm__fmt__roi_config__mode_roi_centre_spad = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + + VL53L1_NVM__FMT__ROI_CONFIG__MODE_ROI_CENTRE_SPAD, + 0x000000FF, + 0, + 0); + pdata->nvm__fmt__roi_config__mode_roi_x_size = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + + VL53L1_NVM__FMT__ROI_CONFIG__MODE_ROI_XY_SIZE, + 0x000000F0, + 4, + 0); + pdata->nvm__fmt__roi_config__mode_roi_y_size = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__ROI_CONFIG__MODE_ROI_XY_SIZE, + 0x0000000F, + 0, + 0); + pdata->nvm__fmt__ref_spad_apply__num_requested_ref_spad = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + + VL53L1_NVM__FMT__REF_SPAD_APPLY__NUM_REQUESTED_REF_SPAD, + 0x000000FF, + 0, + 0); + pdata->nvm__fmt__ref_spad_man__ref_location = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__REF_SPAD_MAN__REF_LOCATION, + 0x00000003, + 0, + 0); + pdata->nvm__fmt__mm_config__inner_offset_mm = + (uint16_t)VL53L1_i2c_decode_with_mask( + 2, + pbuffer + VL53L1_NVM__FMT__MM_CONFIG__INNER_OFFSET_MM, + 0x0000FFFF, + 0, + 0); + pdata->nvm__fmt__mm_config__outer_offset_mm = + (uint16_t)VL53L1_i2c_decode_with_mask( + 2, + pbuffer + VL53L1_NVM__FMT__MM_CONFIG__OUTER_OFFSET_MM, + 0x0000FFFF, + 0, + 0); + pdata->nvm__fmt__algo_part_to_part_range_offset_mm = + (uint16_t)VL53L1_i2c_decode_with_mask( + 2, + pbuffer + + VL53L1_NVM__FMT__ALGO__PART_TO_PART_RANGE_OFFSET_MM, + 0x00000FFF, + 0, + 0); + pdata->nvm__fmt__algo__crosstalk_compensation_plane_offset_kcps = + (uint16_t)VL53L1_i2c_decode_with_mask( + 2, + pbuffer + + VL53L1_NVM__FMT__ALGO__CROSSTALK_COMPENSATION_PLANE_OFFSET_KCPS, + 0x0000FFFF, + 0, + 0); + pdata->nvm__fmt__algo__crosstalk_compensation_x_plane_gradient_kcps = + (uint16_t)VL53L1_i2c_decode_with_mask( + 2, + pbuffer + + VL53L1_NVM__FMT__ALGO__CROSSTALK_COMPENSATION_X_PLANE_GRADIENT_KCPS, + 0x0000FFFF, + 0, + 0); + pdata->nvm__fmt__algo__crosstalk_compensation_y_plane_gradient_kcps = + (uint16_t)VL53L1_i2c_decode_with_mask( + 2, + pbuffer + + VL53L1_NVM__FMT__ALGO__CROSSTALK_COMPENSATION_Y_PLANE_GRADIENT_KCPS, + 0x0000FFFF, + 0, + 0); + pdata->nvm__fmt__spare__host_config__nvm_config_spare_0 = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + + VL53L1_NVM__FMT__SPARE_HOST_CONFIG__NVM_CONFIG_SPARE_0, + 0x000000FF, + 0, + 0); + pdata->nvm__fmt__spare__host_config__nvm_config_spare_1 = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + + VL53L1_NVM__FMT__SPARE_HOST_CONFIG__NVM_CONFIG_SPARE_1, + 0x000000FF, + 0, + 0); + pdata->nvm__customer_space_programmed = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__CUSTOMER_NVM_SPACE_PROGRAMMED, + 0x000000FF, + 0, + 0); + pdata->nvm__cust__i2c_device_address = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__CUST__I2C_SLAVE__DEVICE_ADDRESS, + 0x000000FF, + 0, + 0); + pdata->nvm__cust__ref_spad_apply__num_requested_ref_spad = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + + VL53L1_NVM__CUST__REF_SPAD_APPLY__NUM_REQUESTED_REF_SPAD, + 0x000000FF, + 0, + 0); + pdata->nvm__cust__ref_spad_man__ref_location = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__CUST__REF_SPAD_MAN__REF_LOCATION, + 0x00000003, + 0, + 0); + pdata->nvm__cust__mm_config__inner_offset_mm = + (uint16_t)VL53L1_i2c_decode_with_mask( + 2, + pbuffer + VL53L1_NVM__CUST__MM_CONFIG__INNER_OFFSET_MM, + 0x0000FFFF, + 0, + 0); + pdata->nvm__cust__mm_config__outer_offset_mm = + (uint16_t)VL53L1_i2c_decode_with_mask( + 2, + pbuffer + VL53L1_NVM__CUST__MM_CONFIG__OUTER_OFFSET_MM, + 0x0000FFFF, + 0, + 0); + pdata->nvm__cust__algo_part_to_part_range_offset_mm = + (uint16_t)VL53L1_i2c_decode_with_mask( + 2, + pbuffer + + VL53L1_NVM__CUST__ALGO__PART_TO_PART_RANGE_OFFSET_MM, + 0x00000FFF, + 0, + 0); + pdata->nvm__cust__algo__crosstalk_compensation_plane_offset_kcps = + (uint16_t)VL53L1_i2c_decode_with_mask( + 2, + pbuffer + + VL53L1_NVM__CUST__ALGO__CROSSTALK_COMPENSATION_PLANE_OFFSET_KCPS, + 0x0000FFFF, + 0, + 0); + pdata->nvm__cust__algo__crosstalk_compensation_x_plane_gradient_kcps = + (uint16_t)VL53L1_i2c_decode_with_mask( + 2, + pbuffer + + VL53L1_NVM__CUST__ALGO__CROSSTALK_COMPENSATION_X_PLANE_GRADIENT_KCPS, + 0x0000FFFF, + 0, + 0); + pdata->nvm__cust__algo__crosstalk_compensation_y_plane_gradient_kcps = + (uint16_t)VL53L1_i2c_decode_with_mask( + 2, + pbuffer + + VL53L1_NVM__CUST__ALGO__CROSSTALK_COMPENSATION_Y_PLANE_GRADIENT_KCPS, + 0x0000FFFF, + 0, + 0); + pdata->nvm__cust__spare__host_config__nvm_config_spare_0 = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__CUST__SPARE_HOST_CONFIG__NVM_CONFIG_SPARE_0, + 0x000000FF, + 0, + 0); + pdata->nvm__cust__spare__host_config__nvm_config_spare_1 = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + + VL53L1_NVM__CUST__SPARE_HOST_CONFIG__NVM_CONFIG_SPARE_1, + 0x000000FF, + 0, + 0); + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_nvm_decode_optical_centre( + buf_size, + pbuffer + VL53L1_NVM__FMT__OPTICAL_CENTRE_DATA_INDEX, + &(pdata->fmt_optical_centre)); + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_nvm_decode_cal_peak_rate_map( + buf_size, + pbuffer + VL53L1_NVM__FMT__CAL_PEAK_RATE_MAP_DATA_INDEX, + &(pdata->fmt_peak_rate_map)); + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_nvm_decode_additional_offset_cal_data( + buf_size, + pbuffer + + VL53L1_NVM__FMT__ADDITIONAL_OFFSET_CAL_DATA_INDEX, + &(pdata->fmt_add_offset_data)); + + + + + pptmp[0] = VL53L1_NVM__FMT__RANGE_RESULTS__140MM_MM_PRE_RANGE; + pptmp[1] = VL53L1_NVM__FMT__RANGE_RESULTS__140MM_DARK; + pptmp[2] = VL53L1_NVM__FMT__RANGE_RESULTS__400MM_DARK; + pptmp[3] = VL53L1_NVM__FMT__RANGE_RESULTS__400MM_AMBIENT; + + for (i = 0 ; i < VL53L1_NVM_MAX_FMT_RANGE_DATA ; i++) { + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_nvm_decode_fmt_range_results_data( + buf_size, + pbuffer + pptmp[i], + &(pdata->fmt_range_data[i])); + } + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_nvm_decode_fmt_info( + buf_size, + pbuffer, + &(pdata->fmt_info)); + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_nvm_decode_ews_info( + buf_size, + pbuffer, + &(pdata->ews_info)); + + LOG_FUNCTION_END(status); + + return status; + +} + + +VL53L1_Error VL53L1_nvm_decode_optical_centre( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_optical_centre_t *pdata) +{ + + VL53L1_Error status = VL53L1_ERROR_NONE; + + uint16_t tmp = 0; + + if (buf_size < VL53L1_NVM__FMT__OPTICAL_CENTRE_DATA_SIZE) + return VL53L1_ERROR_BUFFER_TOO_SMALL; + + + + + + tmp = 0x0100; + tmp -= (uint16_t)*(pbuffer + 2); + if (tmp > 0x0FF) + tmp = 0; + + pdata->x_centre = (uint8_t)tmp; + pdata->y_centre = *(pbuffer + 3); + + return status; +} + + +VL53L1_Error VL53L1_nvm_decode_cal_peak_rate_map( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_cal_peak_rate_map_t *pdata) +{ + + VL53L1_Error status = VL53L1_ERROR_NONE; + + uint8_t *ptmp = NULL; + uint8_t i = 0; + + if (buf_size < VL53L1_NVM__FMT__CAL_PEAK_RATE_MAP_DATA_SIZE) + return VL53L1_ERROR_BUFFER_TOO_SMALL; + + pdata->cal_distance_mm = + (uint16_t)VL53L1_i2c_decode_uint16_t(2, pbuffer); + + pdata->cal_reflectance_pc = + (uint16_t)VL53L1_i2c_decode_uint16_t(2, pbuffer + 2); + pdata->cal_reflectance_pc = + pdata->cal_reflectance_pc >> 6; + + pdata->max_samples = VL53L1_NVM_PEAK_RATE_MAP_SAMPLES; + pdata->width = VL53L1_NVM_PEAK_RATE_MAP_WIDTH; + pdata->height = VL53L1_NVM_PEAK_RATE_MAP_HEIGHT; + + ptmp = pbuffer + 4; + for (i = 0 ; i < VL53L1_NVM_PEAK_RATE_MAP_SAMPLES ; i++) { + pdata->peak_rate_mcps[i] = + (uint16_t)VL53L1_i2c_decode_uint16_t(2, ptmp); + ptmp += 2; + } + + return status; +} + + +VL53L1_Error VL53L1_nvm_decode_additional_offset_cal_data( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_additional_offset_cal_data_t *pdata) +{ + + VL53L1_Error status = VL53L1_ERROR_NONE; + + if (buf_size < VL53L1_NVM__FMT__ADDITIONAL_OFFSET_CAL_DATA_SIZE) + return VL53L1_ERROR_BUFFER_TOO_SMALL; + + pdata->result__mm_inner_actual_effective_spads = + (uint16_t)VL53L1_i2c_decode_uint16_t(2, pbuffer); + + pdata->result__mm_outer_actual_effective_spads = + (uint16_t)VL53L1_i2c_decode_uint16_t(2, pbuffer + 2); + + pdata->result__mm_inner_peak_signal_count_rtn_mcps = + (uint16_t)VL53L1_i2c_decode_uint16_t(2, pbuffer + 4); + + pdata->result__mm_outer_peak_signal_count_rtn_mcps = + (uint16_t)VL53L1_i2c_decode_uint16_t(2, pbuffer + 6); + + return status; +} + + +VL53L1_Error VL53L1_nvm_decode_fmt_range_results_data( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_decoded_nvm_fmt_range_data_t *pdata) +{ + + VL53L1_Error status = VL53L1_ERROR_NONE; + + if (buf_size < VL53L1_NVM__FMT__RANGE_RESULTS__SIZE_BYTES) + return VL53L1_ERROR_BUFFER_TOO_SMALL; + + pdata->result__actual_effective_rtn_spads = + (uint16_t)VL53L1_i2c_decode_uint16_t(2, pbuffer); + + pdata->ref_spad_array__num_requested_ref_spads = + *(pbuffer+2); + + pdata->ref_spad_array__ref_location = + *(pbuffer+3); + + pdata->result__peak_signal_count_rate_rtn_mcps = + (uint16_t)VL53L1_i2c_decode_uint16_t(2, pbuffer + 4); + + pdata->result__ambient_count_rate_rtn_mcps = + (uint16_t)VL53L1_i2c_decode_uint16_t(2, pbuffer + 6); + + pdata->result__peak_signal_count_rate_ref_mcps = + (uint16_t)VL53L1_i2c_decode_uint16_t(2, pbuffer + 8); + + pdata->result__ambient_count_rate_ref_mcps = + (uint16_t)VL53L1_i2c_decode_uint16_t(2, pbuffer + 10); + + pdata->measured_distance_mm = + (uint16_t)VL53L1_i2c_decode_uint16_t(2, pbuffer + 12); + + pdata->measured_distance_stdev_mm = + (uint16_t)VL53L1_i2c_decode_uint16_t(2, pbuffer + 14); + + return status; +} + + +VL53L1_Error VL53L1_nvm_decode_fmt_info( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_decoded_nvm_fmt_info_t *pdata) +{ + + VL53L1_Error status = VL53L1_ERROR_NONE; + + if (buf_size < VL53L1_NVM_SIZE_IN_BYTES) + return VL53L1_ERROR_BUFFER_TOO_SMALL; + + pdata->nvm__fmt__fgc[0] = + (char)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__FGC__BYTE_0, + 0x000000FE, + 1, + 0); + pdata->nvm__fmt__fgc[1] = + (char)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__FGC__BYTE_1, + 0x000001FC, + 2, + 0); + pdata->nvm__fmt__fgc[2] = + (char)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__FGC__BYTE_2 - 1, + 0x000003F8, + 3, + 0); + pdata->nvm__fmt__fgc[3] = + (char)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__FGC__BYTE_3 - 1, + 0x000007F0, + 4, + 0); + pdata->nvm__fmt__fgc[4] = + (char)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__FGC__BYTE_4 - 1, + 0x00000FE0, + 5, + 0); + pdata->nvm__fmt__fgc[5] = + (char)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__FGC__BYTE_5 - 1, + 0x00001FC0, + 6, + 0); + pdata->nvm__fmt__fgc[6] = + (char)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__FGC__BYTE_6 - 1, + 0x00003F80, + 7, + 0); + pdata->nvm__fmt__fgc[7] = + (char)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__FGC__BYTE_6, + 0x0000007F, + 0, + 0); + pdata->nvm__fmt__fgc[8] = + (char)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__FGC__BYTE_7, + 0x000000FE, + 1, + 0); + pdata->nvm__fmt__fgc[9] = + (char)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__FGC__BYTE_8, + 0x000001FC, + 2, + 0); + pdata->nvm__fmt__fgc[10] = + (char)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__FGC__BYTE_9 - 1, + 0x000003F8, + 3, + 0); + pdata->nvm__fmt__fgc[11] = + (char)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__FGC__BYTE_10 - 1, + 0x000007F0, + 4, + 0); + pdata->nvm__fmt__fgc[12] = + (char)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__FGC__BYTE_11 - 1, + 0x00000FE0, + 5, + 0); + pdata->nvm__fmt__fgc[13] = + (char)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__FGC__BYTE_12 - 1, + 0x00001FC0, + 6, + 0); + pdata->nvm__fmt__fgc[14] = + (char)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__FGC__BYTE_13 - 1, + 0x00003F80, + 7, + 0); + pdata->nvm__fmt__fgc[15] = + (char)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__FGC__BYTE_13, + 0x0000007F, + 0, + 0); + pdata->nvm__fmt__fgc[16] = + (char)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__FGC__BYTE_14, + 0x000000FE, + 1, + 0); + pdata->nvm__fmt__fgc[17] = + (char)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__FGC__BYTE_15, + 0x000001FC, + 2, + 0); + pdata->nvm__fmt__fgc[18] = 0x00; + + pdata->nvm__fmt__test_program_major = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__TEST_PROGRAM_MAJOR_MINOR, + 0x000000E0, + 5, + 0); + pdata->nvm__fmt__test_program_minor = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__TEST_PROGRAM_MAJOR_MINOR, + 0x0000001F, + 0, + 0); + pdata->nvm__fmt__map_major = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__MAP_MAJOR_MINOR, + 0x000000E0, + 5, + 0); + pdata->nvm__fmt__map_minor = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__MAP_MAJOR_MINOR, + 0x0000001F, + 0, + 0); + pdata->nvm__fmt__year = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__YEAR_MONTH, + 0x000000F0, + 4, + 0); + pdata->nvm__fmt__month = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__YEAR_MONTH, + 0x0000000F, + 0, + 0); + pdata->nvm__fmt__day = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__DAY_MODULE_DATE_PHASE, + 0x000000F8, + 3, + 0); + pdata->nvm__fmt__module_date_phase = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__DAY_MODULE_DATE_PHASE, + 0x00000007, + 0, + 0); + pdata->nvm__fmt__time = + (uint16_t)VL53L1_i2c_decode_with_mask( + 2, + pbuffer + VL53L1_NVM__FMT__TIME, + 0x0000FFFF, + 0, + 0); + pdata->nvm__fmt__tester_id = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__TESTER_ID, + 0x000000FF, + 0, + 0); + pdata->nvm__fmt__site_id = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__SITE_ID, + 0x000000FF, + 0, + 0); + + return status; +} + + +VL53L1_Error VL53L1_nvm_decode_ews_info( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_decoded_nvm_ews_info_t *pdata) +{ + + VL53L1_Error status = VL53L1_ERROR_NONE; + + if (buf_size < VL53L1_NVM_SIZE_IN_BYTES) + return VL53L1_ERROR_BUFFER_TOO_SMALL; + + pdata->nvm__ews__test_program_major = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__EWS__TEST_PROGRAM_MAJOR_MINOR, + 0x000000E0, + 5, + 0); + pdata->nvm__ews__test_program_minor = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__EWS__TEST_PROGRAM_MAJOR_MINOR, + 0x0000001F, + 0, + 0); + pdata->nvm__ews__probe_card_major = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__EWS__PROBE_CARD_MAJOR_MINOR, + 0x000000F0, + 4, + 0); + pdata->nvm__ews__probe_card_minor = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__EWS__PROBE_CARD_MAJOR_MINOR, + 0x0000000F, + 0, + 0); + pdata->nvm__ews__tester_id = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__EWS__TESTER_ID, + 0x000000FF, + 0, + 0); + pdata->nvm__ews__lot[0] = + (char)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__EWS__LOT__BYTE_0, + 0x000000FC, + 2, + 32); + pdata->nvm__ews__lot[1] = + (char)VL53L1_i2c_decode_with_mask( + 2, + pbuffer + VL53L1_NVM__EWS__LOT__BYTE_1 - 1, + 0x000003F0, + 4, + 32); + pdata->nvm__ews__lot[2] = + (char)VL53L1_i2c_decode_with_mask( + 2, + pbuffer + VL53L1_NVM__EWS__LOT__BYTE_2 - 1, + 0x00000FC0, + 6, + 32); + pdata->nvm__ews__lot[3] = + (char)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__EWS__LOT__BYTE_2, + 0x0000003F, + 0, + 32); + pdata->nvm__ews__lot[4] = + (char)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__EWS__LOT__BYTE_3, + 0x000000FC, + 2, + 32); + pdata->nvm__ews__lot[5] = + (char)VL53L1_i2c_decode_with_mask( + 2, + pbuffer + VL53L1_NVM__EWS__LOT__BYTE_4 - 1, + 0x000003F0, + 4, + 32); + pdata->nvm__ews__lot[6] = + (char)VL53L1_i2c_decode_with_mask( + 2, + pbuffer + VL53L1_NVM__EWS__LOT__BYTE_5 - 1, + 0x00000FC0, + 6, + 32); + + pdata->nvm__ews__lot[7] = 0x00; + + pdata->nvm__ews__wafer = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__EWS__WAFER, + 0x0000001F, + 0, + 0); + pdata->nvm__ews__xcoord = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__EWS__XCOORD, + 0x000000FF, + 0, + 0); + pdata->nvm__ews__ycoord = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__EWS__YCOORD, + 0x000000FF, + 0, + 0); + + return status; + +} + + +void VL53L1_nvm_format_encode( + VL53L1_decoded_nvm_data_t *pnvm_info, + uint8_t *pnvm_data) +{ + SUPPRESS_UNUSED_WARNING(pnvm_info); + SUPPRESS_UNUSED_WARNING(pnvm_data); +} + + +VL53L1_Error VL53L1_read_nvm_raw_data( + VL53L1_DEV Dev, + uint8_t start_address, + uint8_t count, + uint8_t *pnvm_raw_data) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_nvm_enable( + Dev, + 0x0004, + VL53L1_NVM_POWER_UP_DELAY_US); + + + + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_nvm_read( + Dev, + start_address, + count, + pnvm_raw_data); + + + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_nvm_disable(Dev); + + LOG_FUNCTION_END(status); + + return status; + +} + + +VL53L1_Error VL53L1_read_nvm( + VL53L1_DEV Dev, + uint8_t nvm_format, + VL53L1_decoded_nvm_data_t *pnvm_info) +{ + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + + + uint8_t nvm_data[2*VL53L1_NVM_SIZE_IN_BYTES]; + + LOG_FUNCTION_START(""); + + SUPPRESS_UNUSED_WARNING(nvm_format); + + + + + status = VL53L1_read_nvm_raw_data( + Dev, + 0, + VL53L1_NVM_SIZE_IN_BYTES >> 2, + nvm_data); + + + + + + + + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_nvm_format_decode( + VL53L1_NVM_SIZE_IN_BYTES, + nvm_data, + pnvm_info); + + LOG_FUNCTION_END(status); + + return status; + +} + + +VL53L1_Error VL53L1_read_nvm_optical_centre( + VL53L1_DEV Dev, + VL53L1_optical_centre_t *pcentre) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + + + uint8_t nvm_data[2*VL53L1_NVM__FMT__OPTICAL_CENTRE_DATA_SIZE]; + + LOG_FUNCTION_START(""); + + + + + status = + VL53L1_read_nvm_raw_data( + Dev, + (uint8_t)(VL53L1_NVM__FMT__OPTICAL_CENTRE_DATA_INDEX + >> 2), + (uint8_t)(VL53L1_NVM__FMT__OPTICAL_CENTRE_DATA_SIZE + >> 2), + nvm_data); + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_nvm_decode_optical_centre( + VL53L1_NVM__FMT__OPTICAL_CENTRE_DATA_SIZE, + nvm_data, + pcentre); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_read_nvm_cal_peak_rate_map( + VL53L1_DEV Dev, + VL53L1_cal_peak_rate_map_t *pcal_data) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + + + uint8_t nvm_data[2*VL53L1_NVM__FMT__CAL_PEAK_RATE_MAP_DATA_SIZE]; + + LOG_FUNCTION_START(""); + + + + + status = + VL53L1_read_nvm_raw_data( + Dev, + (uint8_t)(VL53L1_NVM__FMT__CAL_PEAK_RATE_MAP_DATA_INDEX + >> 2), + (uint8_t)(VL53L1_NVM__FMT__CAL_PEAK_RATE_MAP_DATA_SIZE + >> 2), + nvm_data); + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_nvm_decode_cal_peak_rate_map( + VL53L1_NVM__FMT__CAL_PEAK_RATE_MAP_DATA_SIZE, + nvm_data, + pcal_data); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_read_nvm_additional_offset_cal_data( + VL53L1_DEV Dev, + VL53L1_additional_offset_cal_data_t *pcal_data) +{ + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + + + uint8_t nvm_data[2*VL53L1_NVM__FMT__ADDITIONAL_OFFSET_CAL_DATA_SIZE]; + + LOG_FUNCTION_START(""); + + + + + status = + VL53L1_read_nvm_raw_data( + Dev, + (uint8_t)( + VL53L1_NVM__FMT__ADDITIONAL_OFFSET_CAL_DATA_INDEX >> 2), + (uint8_t)( + VL53L1_NVM__FMT__ADDITIONAL_OFFSET_CAL_DATA_SIZE >> 2), + nvm_data); + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_nvm_decode_additional_offset_cal_data( + VL53L1_NVM__FMT__ADDITIONAL_OFFSET_CAL_DATA_SIZE, + nvm_data, + pcal_data); + + LOG_FUNCTION_END(status); + + return status; + +} + + +VL53L1_Error VL53L1_read_nvm_fmt_range_results_data( + VL53L1_DEV Dev, + uint16_t range_results_select, + VL53L1_decoded_nvm_fmt_range_data_t *prange_data) +{ + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + + + uint8_t nvm_data[2*VL53L1_NVM__FMT__RANGE_RESULTS__SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + + + + status = VL53L1_read_nvm_raw_data( + Dev, + (uint8_t)(range_results_select >> 2), + (uint8_t)(VL53L1_NVM__FMT__RANGE_RESULTS__SIZE_BYTES >> 2), + nvm_data); + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_nvm_decode_fmt_range_results_data( + VL53L1_NVM__FMT__RANGE_RESULTS__SIZE_BYTES, + nvm_data, + prange_data); + + LOG_FUNCTION_END(status); + + return status; + +} + + diff --git a/drivers/input/misc/vl53L1/kona/src/vl53l1_nvm_debug.c b/drivers/input/misc/vl53L1/kona/src/vl53l1_nvm_debug.c new file mode 100644 index 000000000000..3ac30357e198 --- /dev/null +++ b/drivers/input/misc/vl53L1/kona/src/vl53l1_nvm_debug.c @@ -0,0 +1,1126 @@ + +/******************************************************************************* + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#include "vl53l1_ll_def.h" +#include "vl53l1_platform.h" +#include "vl53l1_platform_log.h" +#include "vl53l1_register_map.h" +#include "vl53l1_api_debug.h" +#include "vl53l1_nvm_structs.h" +#include "vl53l1_nvm_debug.h" + +#define LOG_FUNCTION_START(fmt, ...) \ + _LOG_FUNCTION_START(VL53L1_TRACE_MODULE_NVM, fmt, ##__VA_ARGS__) +#define LOG_FUNCTION_END(status, ...) \ + _LOG_FUNCTION_END(VL53L1_TRACE_MODULE_NVM, status, ##__VA_ARGS__) +#define LOG_FUNCTION_END_FMT(status, fmt, ...) \ + _LOG_FUNCTION_END_FMT(VL53L1_TRACE_MODULE_NVM,\ + status, fmt, ##__VA_ARGS__) + +#define trace_print(level, ...) \ + _LOG_TRACE_PRINT(trace_flags, \ + level, VL53L1_TRACE_FUNCTION_NONE, ##__VA_ARGS__) + +#ifdef VL53L1_LOG_ENABLE + +void VL53L1_print_nvm_raw_data( + uint8_t *pnvm_raw_data, + uint32_t trace_flags) +{ + + + + + + int i = 0; + + LOG_FUNCTION_START(""); + + for (i = 0 ; i < VL53L1_NVM_SIZE_IN_BYTES ; i++) { + if (i % 4 == 0) + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "\n NVM Addr 0x%02X : 0x", + i/4); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%02X", + *pnvm_raw_data++); + } + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "\n"); + + LOG_FUNCTION_END(0); +} + + +void VL53L1_print_decoded_nvm_data( + VL53L1_decoded_nvm_data_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + char fp_text[VL53L1_MAX_STRING_LENGTH]; + char pre_text[VL53L1_MAX_STRING_LENGTH]; + char *ppre_text = &(pre_text[0]); + + uint8_t i = 0; + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__identification_model_id", + pdata->nvm__identification_model_id); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__identification_module_type", + pdata->nvm__identification_module_type); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__identification_revision_id", + pdata->nvm__identification_revision_id); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__identification_module_id", + pdata->nvm__identification_module_id); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__i2c_valid", + pdata->nvm__i2c_valid); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__i2c_device_address_ews", + pdata->nvm__i2c_device_address_ews); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->nvm__ews__fast_osc_frequency, + 12, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "nvm__ews__fast_osc_frequency", + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__ews__fast_osc_trim_max", + pdata->nvm__ews__fast_osc_trim_max); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__ews__fast_osc_freq_set", + pdata->nvm__ews__fast_osc_freq_set); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__ews__slow_osc_calibration", + pdata->nvm__ews__slow_osc_calibration); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->nvm__fmt__fast_osc_frequency, + 12, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "nvm__fmt__fast_osc_frequency", + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__fmt__fast_osc_trim_max", + pdata->nvm__fmt__fast_osc_trim_max); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__fmt__fast_osc_freq_set", + pdata->nvm__fmt__fast_osc_freq_set); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__fmt__slow_osc_calibration", + pdata->nvm__fmt__slow_osc_calibration); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__vhv_config_unlock", + pdata->nvm__vhv_config_unlock); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__ref_selvddpix", + pdata->nvm__ref_selvddpix); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__ref_selvquench", + pdata->nvm__ref_selvquench); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__regavdd1v2_sel", + pdata->nvm__regavdd1v2_sel); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__regdvdd1v2_sel", + pdata->nvm__regdvdd1v2_sel); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__vhv_timeout__macrop", + pdata->nvm__vhv_timeout__macrop); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__vhv_loop_bound", + pdata->nvm__vhv_loop_bound); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__vhv_count_threshold", + pdata->nvm__vhv_count_threshold); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__vhv_offset", + pdata->nvm__vhv_offset); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__vhv_init_enable", + pdata->nvm__vhv_init_enable); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__vhv_init_value", + pdata->nvm__vhv_init_value); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__laser_safety_vcsel_trim_ll", + pdata->nvm__laser_safety_vcsel_trim_ll); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__laser_safety_vcsel_selion_ll", + pdata->nvm__laser_safety_vcsel_selion_ll); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__laser_safety_vcsel_selion_max_ll", + pdata->nvm__laser_safety_vcsel_selion_max_ll); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__laser_safety_mult_ll", + pdata->nvm__laser_safety_mult_ll); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__laser_safety_clip_ll", + pdata->nvm__laser_safety_clip_ll); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__laser_safety_vcsel_trim_ld", + pdata->nvm__laser_safety_vcsel_trim_ld); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__laser_safety_vcsel_selion_ld", + pdata->nvm__laser_safety_vcsel_selion_ld); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__laser_safety_vcsel_selion_max_ld", + pdata->nvm__laser_safety_vcsel_selion_max_ld); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__laser_safety_mult_ld", + pdata->nvm__laser_safety_mult_ld); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__laser_safety_clip_ld", + pdata->nvm__laser_safety_clip_ld); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__laser_safety_lock_byte", + pdata->nvm__laser_safety_lock_byte); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__laser_safety_unlock_byte", + pdata->nvm__laser_safety_unlock_byte); + + + + + for (i = 0 ; i < VL53L1_RTN_SPAD_BUFFER_SIZE ; i++) { + sprintf( + ppre_text, + "%snvm__ews__spad_enables_rtn[%u]", + pprefix, i); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s = %u\n", + ppre_text, + pdata->nvm__ews__spad_enables_rtn[i]); + } + + for (i = 0 ; i < VL53L1_REF_SPAD_BUFFER_SIZE ; i++) { + sprintf( + ppre_text, + "%snvm__ews__spad_enables_ref__loc1[%u]", + pprefix, i); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s = %u\n", + ppre_text, + pdata->nvm__ews__spad_enables_ref__loc1[i]); + } + + for (i = 0 ; i < VL53L1_REF_SPAD_BUFFER_SIZE ; i++) { + sprintf( + ppre_text, + "%snvm__ews__spad_enables_ref__loc2[%u]", + pprefix, i); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s = %u\n", + ppre_text, + pdata->nvm__ews__spad_enables_ref__loc2[i]); + } + + for (i = 0 ; i < VL53L1_REF_SPAD_BUFFER_SIZE ; i++) { + sprintf( + ppre_text, + "%snvm__ews__spad_enables_ref__loc3[%u]", + pprefix, i); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s = %u\n", + ppre_text, + pdata->nvm__ews__spad_enables_ref__loc3[i]); + } + + + + + + for (i = 0 ; i < VL53L1_RTN_SPAD_BUFFER_SIZE ; i++) { + sprintf( + ppre_text, + "%snvm__fmt__spad_enables_rtn[%u]", + pprefix, i); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s = %u\n", + ppre_text, + pdata->nvm__fmt__spad_enables_rtn[i]); + } + + for (i = 0 ; i < VL53L1_REF_SPAD_BUFFER_SIZE ; i++) { + sprintf( + ppre_text, + "%snvm__fmt__spad_enables_ref__loc1[%u]", + pprefix, i); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s = %u\n", + ppre_text, + pdata->nvm__fmt__spad_enables_ref__loc1[i]); + } + + for (i = 0 ; i < VL53L1_REF_SPAD_BUFFER_SIZE ; i++) { + sprintf( + ppre_text, + "%snvm__fmt__spad_enables_ref__loc2[%u]", + pprefix, i); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s = %u\n", + ppre_text, + pdata->nvm__fmt__spad_enables_ref__loc2[i]); + } + + for (i = 0 ; i < VL53L1_REF_SPAD_BUFFER_SIZE ; i++) { + sprintf( + ppre_text, + "%snvm__fmt__spad_enables_ref__loc3[%u]", + pprefix, i); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s = %u\n", + ppre_text, + pdata->nvm__fmt__spad_enables_ref__loc3[i]); + } + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__fmt__roi_config__mode_roi_centre_spad", + pdata->nvm__fmt__roi_config__mode_roi_centre_spad); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__fmt__roi_config__mode_roi_x_size", + pdata->nvm__fmt__roi_config__mode_roi_x_size); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__fmt__roi_config__mode_roi_y_size", + pdata->nvm__fmt__roi_config__mode_roi_y_size); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__fmt__ref_spad_apply__num_requested_ref_spad", + pdata->nvm__fmt__ref_spad_apply__num_requested_ref_spad); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__fmt__ref_spad_man__ref_location", + pdata->nvm__fmt__ref_spad_man__ref_location); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %d\n", + pprefix, + "nvm__fmt__mm_config__inner_offset_mm", + pdata->nvm__fmt__mm_config__inner_offset_mm); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %d\n", + pprefix, + "nvm__fmt__mm_config__outer_offset_mm", + pdata->nvm__fmt__mm_config__outer_offset_mm); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->nvm__fmt__algo_part_to_part_range_offset_mm, + 2, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "nvm__fmt__algo_part_to_part_range_offset_mm", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)( + pdata->nvm__fmt__algo__crosstalk_compensation_plane_offset_kcps), + 9, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "nvm__fmt__algo__crosstalk_compensation_plane_offset_kcps", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)( + pdata->nvm__fmt__algo__crosstalk_compensation_x_plane_gradient_kcps), + 11, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "nvm__fmt__algo__crosstalk_compensation_x_plane_gradient_kcps", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)( + pdata->nvm__fmt__algo__crosstalk_compensation_y_plane_gradient_kcps), + 11, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "nvm__fmt__algo__crosstalk_compensation_y_plane_gradient_kcps", + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__fmt__spare__host_config__nvm_config_spare_0", + pdata->nvm__fmt__spare__host_config__nvm_config_spare_0); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__fmt__spare__host_config__nvm_config_spare_1", + pdata->nvm__fmt__spare__host_config__nvm_config_spare_1); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__customer_space_programmed", + pdata->nvm__customer_space_programmed); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__cust__i2c_device_address", + pdata->nvm__cust__i2c_device_address); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__cust__ref_spad_apply__num_requested_ref_spad", + pdata->nvm__cust__ref_spad_apply__num_requested_ref_spad); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__cust__ref_spad_man__ref_location", + pdata->nvm__cust__ref_spad_man__ref_location); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %d\n", + pprefix, + "nvm__cust__mm_config__inner_offset_mm", + pdata->nvm__cust__mm_config__inner_offset_mm); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %d\n", + pprefix, + "nvm__cust__mm_config__outer_offset_mm", + pdata->nvm__cust__mm_config__outer_offset_mm); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->nvm__cust__algo_part_to_part_range_offset_mm, + 2, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "nvm__cust__algo_part_to_part_range_offset_mm", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (uint32_t)( + pdata->nvm__cust__algo__crosstalk_compensation_plane_offset_kcps), + 9, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "nvm__cust__algo__crosstalk_compensation_plane_offset_kcps", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)( + pdata->nvm__cust__algo__crosstalk_compensation_x_plane_gradient_kcps), + 11, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "nvm__cust__algo__crosstalk_compensation_x_plane_gradient_kcps", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)( + pdata->nvm__cust__algo__crosstalk_compensation_y_plane_gradient_kcps), + 11, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "nvm__cust__algo__crosstalk_compensation_y_plane_gradient_kcps", + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__cust__spare__host_config__nvm_config_spare_0", + pdata->nvm__cust__spare__host_config__nvm_config_spare_0); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__cust__spare__host_config__nvm_config_spare_1", + pdata->nvm__cust__spare__host_config__nvm_config_spare_1); + + + + + sprintf( + ppre_text, + "%sfmt_optical_centre.", pprefix); + + VL53L1_print_optical_centre( + &(pdata->fmt_optical_centre), + ppre_text, + VL53L1_TRACE_MODULE_NVM_DATA); + + + + + sprintf( + ppre_text, + "%sfmt_peak_rate_map.", pprefix); + + VL53L1_print_cal_peak_rate_map( + &(pdata->fmt_peak_rate_map), + ppre_text, + VL53L1_TRACE_MODULE_NVM_DATA); + + + + + sprintf( + ppre_text, + "%sfmt_add_offset_data.", + pprefix); + + VL53L1_print_additional_offset_cal_data( + &(pdata->fmt_add_offset_data), + ppre_text, + VL53L1_TRACE_MODULE_NVM_DATA); + + + + + for (i = 0 ; i < VL53L1_NVM_MAX_FMT_RANGE_DATA ; i++) { + sprintf( + ppre_text, + "%sfmt_range_data[%u].", + pprefix, i); + + VL53L1_print_decoded_nvm_fmt_range_data( + &(pdata->fmt_range_data[i]), + ppre_text, + trace_flags); + } + + sprintf( + ppre_text, + "%sfmt_info.", + pprefix); + + VL53L1_print_decoded_nvm_fmt_info( + &(pdata->fmt_info), + ppre_text, + trace_flags); + + sprintf( + ppre_text, + "%sews_info.", + pprefix); + + VL53L1_print_decoded_nvm_ews_info( + &(pdata->ews_info), + ppre_text, + trace_flags); +} + + +void VL53L1_print_decoded_nvm_fmt_range_data( + VL53L1_decoded_nvm_fmt_range_data_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + char fp_text[VL53L1_MAX_STRING_LENGTH]; + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->result__actual_effective_rtn_spads, + 8, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "result__actual_effective_rtn_spads", + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "ref_spad_array__num_requested_ref_spads", + pdata->ref_spad_array__num_requested_ref_spads); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "ref_spad_array__ref_location", + pdata->ref_spad_array__ref_location); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->result__peak_signal_count_rate_rtn_mcps, + 7, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "result__peak_signal_count_rate_rtn_mcps", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->result__ambient_count_rate_rtn_mcps, + 7, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "result__ambient_count_rate_rtn_mcps", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->result__peak_signal_count_rate_ref_mcps, + 7, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "result__peak_signal_count_rate_ref_mcps", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->result__ambient_count_rate_ref_mcps, + 7, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "result__ambient_count_rate_ref_mcps", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->measured_distance_mm, + 4, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "measured_distance_mm", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (uint32_t)pdata->measured_distance_stdev_mm, + 4, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "measured_distance_stdev_mm", + fp_text); +} + + +void VL53L1_print_decoded_nvm_fmt_info( + VL53L1_decoded_nvm_fmt_info_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + trace_print(VL53L1_TRACE_LEVEL_INFO, + "%s%s = \"%s\"\n", + pprefix, + "nvm__fmt__fgc", + pdata->nvm__fmt__fgc); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__fmt__test_program_major", + pdata->nvm__fmt__test_program_major); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__fmt__test_program_minor", + pdata->nvm__fmt__test_program_minor); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__fmt__map_major", + pdata->nvm__fmt__map_major); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__fmt__map_minor", + pdata->nvm__fmt__map_minor); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__fmt__year", + pdata->nvm__fmt__year); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__fmt__month", + pdata->nvm__fmt__month); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__fmt__day", + pdata->nvm__fmt__day); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__fmt__module_date_phase", + pdata->nvm__fmt__module_date_phase); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__fmt__time", + pdata->nvm__fmt__time); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__fmt__tester_id", + pdata->nvm__fmt__tester_id); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__fmt__site_id", + pdata->nvm__fmt__site_id); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__ews__test_program_major", + pdata->nvm__ews__test_program_major); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__ews__test_program_minor", + pdata->nvm__ews__test_program_minor); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__ews__probe_card_major", + pdata->nvm__ews__probe_card_major); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__ews__probe_card_minor", + pdata->nvm__ews__probe_card_minor); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__ews__tester_id", + pdata->nvm__ews__tester_id); +} + + +void VL53L1_print_decoded_nvm_ews_info( + VL53L1_decoded_nvm_ews_info_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + trace_print(VL53L1_TRACE_LEVEL_INFO, + "%s%s = \"%s\"\n", + pprefix, + "nvm__ews__lot", + pdata->nvm__ews__lot); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__ews__wafer", + pdata->nvm__ews__wafer); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__ews__xcoord", + pdata->nvm__ews__xcoord); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__ews__ycoord", + pdata->nvm__ews__ycoord); +} + +#endif + + + diff --git a/drivers/input/misc/vl53L1/kona/src/vl53l1_register_funcs.c b/drivers/input/misc/vl53L1/kona/src/vl53l1_register_funcs.c new file mode 100644 index 000000000000..1738d2076ca7 --- /dev/null +++ b/drivers/input/misc/vl53L1/kona/src/vl53l1_register_funcs.c @@ -0,0 +1,4596 @@ + +/******************************************************************************* + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#include "vl53l1_ll_def.h" +#include "vl53l1_platform.h" +#include "vl53l1_platform_log.h" +#include "vl53l1_core.h" +#include "vl53l1_register_map.h" +#include "vl53l1_register_structs.h" +#include "vl53l1_register_funcs.h" + +#define LOG_FUNCTION_START(fmt, ...) \ + _LOG_FUNCTION_START(VL53L1_TRACE_MODULE_REGISTERS, fmt, ##__VA_ARGS__) +#define LOG_FUNCTION_END(status, ...) \ + _LOG_FUNCTION_END(VL53L1_TRACE_MODULE_REGISTERS, status, ##__VA_ARGS__) +#define LOG_FUNCTION_END_FMT(status, fmt, ...) \ + _LOG_FUNCTION_END_FMT(VL53L1_TRACE_MODULE_REGISTERS,\ + status, fmt, ##__VA_ARGS__) + + +VL53L1_Error VL53L1_i2c_encode_static_nvm_managed( + VL53L1_static_nvm_managed_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_STATIC_NVM_MANAGED_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + *(pbuffer + 0) = + pdata->i2c_slave__device_address & 0x7F; + *(pbuffer + 1) = + pdata->ana_config__vhv_ref_sel_vddpix & 0xF; + *(pbuffer + 2) = + pdata->ana_config__vhv_ref_sel_vquench & 0x7F; + *(pbuffer + 3) = + pdata->ana_config__reg_avdd1v2_sel & 0x3; + *(pbuffer + 4) = + pdata->ana_config__fast_osc__trim & 0x7F; + VL53L1_i2c_encode_uint16_t( + pdata->osc_measured__fast_osc__frequency, + 2, + pbuffer + 5); + *(pbuffer + 7) = + pdata->vhv_config__timeout_macrop_loop_bound; + *(pbuffer + 8) = + pdata->vhv_config__count_thresh; + *(pbuffer + 9) = + pdata->vhv_config__offset & 0x3F; + *(pbuffer + 10) = + pdata->vhv_config__init; + LOG_FUNCTION_END(status); + + + return status; +} + + +VL53L1_Error VL53L1_i2c_decode_static_nvm_managed( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_static_nvm_managed_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_STATIC_NVM_MANAGED_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + pdata->i2c_slave__device_address = + (*(pbuffer + 0)) & 0x7F; + pdata->ana_config__vhv_ref_sel_vddpix = + (*(pbuffer + 1)) & 0xF; + pdata->ana_config__vhv_ref_sel_vquench = + (*(pbuffer + 2)) & 0x7F; + pdata->ana_config__reg_avdd1v2_sel = + (*(pbuffer + 3)) & 0x3; + pdata->ana_config__fast_osc__trim = + (*(pbuffer + 4)) & 0x7F; + pdata->osc_measured__fast_osc__frequency = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 5)); + pdata->vhv_config__timeout_macrop_loop_bound = + (*(pbuffer + 7)); + pdata->vhv_config__count_thresh = + (*(pbuffer + 8)); + pdata->vhv_config__offset = + (*(pbuffer + 9)) & 0x3F; + pdata->vhv_config__init = + (*(pbuffer + 10)); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_static_nvm_managed( + VL53L1_DEV Dev, + VL53L1_static_nvm_managed_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_STATIC_NVM_MANAGED_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_i2c_encode_static_nvm_managed( + pdata, + VL53L1_STATIC_NVM_MANAGED_I2C_SIZE_BYTES, + comms_buffer); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WriteMulti( + Dev, + VL53L1_I2C_SLAVE__DEVICE_ADDRESS, + comms_buffer, + VL53L1_STATIC_NVM_MANAGED_I2C_SIZE_BYTES); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_static_nvm_managed( + VL53L1_DEV Dev, + VL53L1_static_nvm_managed_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_STATIC_NVM_MANAGED_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_ReadMulti( + Dev, + VL53L1_I2C_SLAVE__DEVICE_ADDRESS, + comms_buffer, + VL53L1_STATIC_NVM_MANAGED_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_i2c_decode_static_nvm_managed( + VL53L1_STATIC_NVM_MANAGED_I2C_SIZE_BYTES, + comms_buffer, + pdata); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_i2c_encode_customer_nvm_managed( + VL53L1_customer_nvm_managed_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_CUSTOMER_NVM_MANAGED_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + *(pbuffer + 0) = + pdata->global_config__spad_enables_ref_0; + *(pbuffer + 1) = + pdata->global_config__spad_enables_ref_1; + *(pbuffer + 2) = + pdata->global_config__spad_enables_ref_2; + *(pbuffer + 3) = + pdata->global_config__spad_enables_ref_3; + *(pbuffer + 4) = + pdata->global_config__spad_enables_ref_4; + *(pbuffer + 5) = + pdata->global_config__spad_enables_ref_5 & 0xF; + *(pbuffer + 6) = + pdata->global_config__ref_en_start_select; + *(pbuffer + 7) = + pdata->ref_spad_man__num_requested_ref_spads & 0x3F; + *(pbuffer + 8) = + pdata->ref_spad_man__ref_location & 0x3; + VL53L1_i2c_encode_uint16_t( + pdata->algo__crosstalk_compensation_plane_offset_kcps, + 2, + pbuffer + 9); + VL53L1_i2c_encode_int16_t( + pdata->algo__crosstalk_compensation_x_plane_gradient_kcps, + 2, + pbuffer + 11); + VL53L1_i2c_encode_int16_t( + pdata->algo__crosstalk_compensation_y_plane_gradient_kcps, + 2, + pbuffer + 13); + VL53L1_i2c_encode_uint16_t( + pdata->ref_spad_char__total_rate_target_mcps, + 2, + pbuffer + 15); + VL53L1_i2c_encode_int16_t( + pdata->algo__part_to_part_range_offset_mm & 0x1FFF, + 2, + pbuffer + 17); + VL53L1_i2c_encode_int16_t( + pdata->mm_config__inner_offset_mm, + 2, + pbuffer + 19); + VL53L1_i2c_encode_int16_t( + pdata->mm_config__outer_offset_mm, + 2, + pbuffer + 21); + LOG_FUNCTION_END(status); + + + return status; +} + + +VL53L1_Error VL53L1_i2c_decode_customer_nvm_managed( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_customer_nvm_managed_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_CUSTOMER_NVM_MANAGED_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + pdata->global_config__spad_enables_ref_0 = + (*(pbuffer + 0)); + pdata->global_config__spad_enables_ref_1 = + (*(pbuffer + 1)); + pdata->global_config__spad_enables_ref_2 = + (*(pbuffer + 2)); + pdata->global_config__spad_enables_ref_3 = + (*(pbuffer + 3)); + pdata->global_config__spad_enables_ref_4 = + (*(pbuffer + 4)); + pdata->global_config__spad_enables_ref_5 = + (*(pbuffer + 5)) & 0xF; + pdata->global_config__ref_en_start_select = + (*(pbuffer + 6)); + pdata->ref_spad_man__num_requested_ref_spads = + (*(pbuffer + 7)) & 0x3F; + pdata->ref_spad_man__ref_location = + (*(pbuffer + 8)) & 0x3; + pdata->algo__crosstalk_compensation_plane_offset_kcps = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 9)); + pdata->algo__crosstalk_compensation_x_plane_gradient_kcps = + (VL53L1_i2c_decode_int16_t(2, pbuffer + 11)); + pdata->algo__crosstalk_compensation_y_plane_gradient_kcps = + (VL53L1_i2c_decode_int16_t(2, pbuffer + 13)); + pdata->ref_spad_char__total_rate_target_mcps = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 15)); + pdata->algo__part_to_part_range_offset_mm = + (VL53L1_i2c_decode_int16_t(2, pbuffer + 17)) & 0x1FFF; + pdata->mm_config__inner_offset_mm = + (VL53L1_i2c_decode_int16_t(2, pbuffer + 19)); + pdata->mm_config__outer_offset_mm = + (VL53L1_i2c_decode_int16_t(2, pbuffer + 21)); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_customer_nvm_managed( + VL53L1_DEV Dev, + VL53L1_customer_nvm_managed_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_CUSTOMER_NVM_MANAGED_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_i2c_encode_customer_nvm_managed( + pdata, + VL53L1_CUSTOMER_NVM_MANAGED_I2C_SIZE_BYTES, + comms_buffer); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WriteMulti( + Dev, + VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_REF_0, + comms_buffer, + VL53L1_CUSTOMER_NVM_MANAGED_I2C_SIZE_BYTES); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_customer_nvm_managed( + VL53L1_DEV Dev, + VL53L1_customer_nvm_managed_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_CUSTOMER_NVM_MANAGED_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_ReadMulti( + Dev, + VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_REF_0, + comms_buffer, + VL53L1_CUSTOMER_NVM_MANAGED_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_i2c_decode_customer_nvm_managed( + VL53L1_CUSTOMER_NVM_MANAGED_I2C_SIZE_BYTES, + comms_buffer, + pdata); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_i2c_encode_static_config( + VL53L1_static_config_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_STATIC_CONFIG_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + VL53L1_i2c_encode_uint16_t( + pdata->dss_config__target_total_rate_mcps, + 2, + pbuffer + 0); + *(pbuffer + 2) = + pdata->debug__ctrl & 0x1; + *(pbuffer + 3) = + pdata->test_mode__ctrl & 0xF; + *(pbuffer + 4) = + pdata->clk_gating__ctrl & 0xF; + *(pbuffer + 5) = + pdata->nvm_bist__ctrl & 0x1F; + *(pbuffer + 6) = + pdata->nvm_bist__num_nvm_words & 0x7F; + *(pbuffer + 7) = + pdata->nvm_bist__start_address & 0x7F; + *(pbuffer + 8) = + pdata->host_if__status & 0x1; + *(pbuffer + 9) = + pdata->pad_i2c_hv__config; + *(pbuffer + 10) = + pdata->pad_i2c_hv__extsup_config & 0x1; + *(pbuffer + 11) = + pdata->gpio_hv_pad__ctrl & 0x3; + *(pbuffer + 12) = + pdata->gpio_hv_mux__ctrl & 0x1F; + *(pbuffer + 13) = + pdata->gpio__tio_hv_status & 0x3; + *(pbuffer + 14) = + pdata->gpio__fio_hv_status & 0x3; + *(pbuffer + 15) = + pdata->ana_config__spad_sel_pswidth & 0x7; + *(pbuffer + 16) = + pdata->ana_config__vcsel_pulse_width_offset & 0x1F; + *(pbuffer + 17) = + pdata->ana_config__fast_osc__config_ctrl & 0x1; + *(pbuffer + 18) = + pdata->sigma_estimator__effective_pulse_width_ns; + *(pbuffer + 19) = + pdata->sigma_estimator__effective_ambient_width_ns; + *(pbuffer + 20) = + pdata->sigma_estimator__sigma_ref_mm; + *(pbuffer + 21) = + pdata->algo__crosstalk_compensation_valid_height_mm; + *(pbuffer + 22) = + pdata->spare_host_config__static_config_spare_0; + *(pbuffer + 23) = + pdata->spare_host_config__static_config_spare_1; + VL53L1_i2c_encode_uint16_t( + pdata->algo__range_ignore_threshold_mcps, + 2, + pbuffer + 24); + *(pbuffer + 26) = + pdata->algo__range_ignore_valid_height_mm; + *(pbuffer + 27) = + pdata->algo__range_min_clip; + *(pbuffer + 28) = + pdata->algo__consistency_check__tolerance & 0xF; + *(pbuffer + 29) = + pdata->spare_host_config__static_config_spare_2; + *(pbuffer + 30) = + pdata->sd_config__reset_stages_msb & 0xF; + *(pbuffer + 31) = + pdata->sd_config__reset_stages_lsb; + LOG_FUNCTION_END(status); + + + return status; +} + + +VL53L1_Error VL53L1_i2c_decode_static_config( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_static_config_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_STATIC_CONFIG_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + pdata->dss_config__target_total_rate_mcps = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 0)); + pdata->debug__ctrl = + (*(pbuffer + 2)) & 0x1; + pdata->test_mode__ctrl = + (*(pbuffer + 3)) & 0xF; + pdata->clk_gating__ctrl = + (*(pbuffer + 4)) & 0xF; + pdata->nvm_bist__ctrl = + (*(pbuffer + 5)) & 0x1F; + pdata->nvm_bist__num_nvm_words = + (*(pbuffer + 6)) & 0x7F; + pdata->nvm_bist__start_address = + (*(pbuffer + 7)) & 0x7F; + pdata->host_if__status = + (*(pbuffer + 8)) & 0x1; + pdata->pad_i2c_hv__config = + (*(pbuffer + 9)); + pdata->pad_i2c_hv__extsup_config = + (*(pbuffer + 10)) & 0x1; + pdata->gpio_hv_pad__ctrl = + (*(pbuffer + 11)) & 0x3; + pdata->gpio_hv_mux__ctrl = + (*(pbuffer + 12)) & 0x1F; + pdata->gpio__tio_hv_status = + (*(pbuffer + 13)) & 0x3; + pdata->gpio__fio_hv_status = + (*(pbuffer + 14)) & 0x3; + pdata->ana_config__spad_sel_pswidth = + (*(pbuffer + 15)) & 0x7; + pdata->ana_config__vcsel_pulse_width_offset = + (*(pbuffer + 16)) & 0x1F; + pdata->ana_config__fast_osc__config_ctrl = + (*(pbuffer + 17)) & 0x1; + pdata->sigma_estimator__effective_pulse_width_ns = + (*(pbuffer + 18)); + pdata->sigma_estimator__effective_ambient_width_ns = + (*(pbuffer + 19)); + pdata->sigma_estimator__sigma_ref_mm = + (*(pbuffer + 20)); + pdata->algo__crosstalk_compensation_valid_height_mm = + (*(pbuffer + 21)); + pdata->spare_host_config__static_config_spare_0 = + (*(pbuffer + 22)); + pdata->spare_host_config__static_config_spare_1 = + (*(pbuffer + 23)); + pdata->algo__range_ignore_threshold_mcps = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 24)); + pdata->algo__range_ignore_valid_height_mm = + (*(pbuffer + 26)); + pdata->algo__range_min_clip = + (*(pbuffer + 27)); + pdata->algo__consistency_check__tolerance = + (*(pbuffer + 28)) & 0xF; + pdata->spare_host_config__static_config_spare_2 = + (*(pbuffer + 29)); + pdata->sd_config__reset_stages_msb = + (*(pbuffer + 30)) & 0xF; + pdata->sd_config__reset_stages_lsb = + (*(pbuffer + 31)); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_static_config( + VL53L1_DEV Dev, + VL53L1_static_config_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_STATIC_CONFIG_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_i2c_encode_static_config( + pdata, + VL53L1_STATIC_CONFIG_I2C_SIZE_BYTES, + comms_buffer); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WriteMulti( + Dev, + VL53L1_DSS_CONFIG__TARGET_TOTAL_RATE_MCPS, + comms_buffer, + VL53L1_STATIC_CONFIG_I2C_SIZE_BYTES); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_static_config( + VL53L1_DEV Dev, + VL53L1_static_config_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_STATIC_CONFIG_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_ReadMulti( + Dev, + VL53L1_DSS_CONFIG__TARGET_TOTAL_RATE_MCPS, + comms_buffer, + VL53L1_STATIC_CONFIG_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_i2c_decode_static_config( + VL53L1_STATIC_CONFIG_I2C_SIZE_BYTES, + comms_buffer, + pdata); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_i2c_encode_general_config( + VL53L1_general_config_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_GENERAL_CONFIG_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + *(pbuffer + 0) = + pdata->gph_config__stream_count_update_value; + *(pbuffer + 1) = + pdata->global_config__stream_divider; + *(pbuffer + 2) = + pdata->system__interrupt_config_gpio; + *(pbuffer + 3) = + pdata->cal_config__vcsel_start & 0x7F; + VL53L1_i2c_encode_uint16_t( + pdata->cal_config__repeat_rate & 0xFFF, + 2, + pbuffer + 4); + *(pbuffer + 6) = + pdata->global_config__vcsel_width & 0x7F; + *(pbuffer + 7) = + pdata->phasecal_config__timeout_macrop; + *(pbuffer + 8) = + pdata->phasecal_config__target; + *(pbuffer + 9) = + pdata->phasecal_config__override & 0x1; + *(pbuffer + 11) = + pdata->dss_config__roi_mode_control & 0x7; + VL53L1_i2c_encode_uint16_t( + pdata->system__thresh_rate_high, + 2, + pbuffer + 12); + VL53L1_i2c_encode_uint16_t( + pdata->system__thresh_rate_low, + 2, + pbuffer + 14); + VL53L1_i2c_encode_uint16_t( + pdata->dss_config__manual_effective_spads_select, + 2, + pbuffer + 16); + *(pbuffer + 18) = + pdata->dss_config__manual_block_select; + *(pbuffer + 19) = + pdata->dss_config__aperture_attenuation; + *(pbuffer + 20) = + pdata->dss_config__max_spads_limit; + *(pbuffer + 21) = + pdata->dss_config__min_spads_limit; + LOG_FUNCTION_END(status); + + + return status; +} + + +VL53L1_Error VL53L1_i2c_decode_general_config( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_general_config_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_GENERAL_CONFIG_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + pdata->gph_config__stream_count_update_value = + (*(pbuffer + 0)); + pdata->global_config__stream_divider = + (*(pbuffer + 1)); + pdata->system__interrupt_config_gpio = + (*(pbuffer + 2)); + pdata->cal_config__vcsel_start = + (*(pbuffer + 3)) & 0x7F; + pdata->cal_config__repeat_rate = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 4)) & 0xFFF; + pdata->global_config__vcsel_width = + (*(pbuffer + 6)) & 0x7F; + pdata->phasecal_config__timeout_macrop = + (*(pbuffer + 7)); + pdata->phasecal_config__target = + (*(pbuffer + 8)); + pdata->phasecal_config__override = + (*(pbuffer + 9)) & 0x1; + pdata->dss_config__roi_mode_control = + (*(pbuffer + 11)) & 0x7; + pdata->system__thresh_rate_high = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 12)); + pdata->system__thresh_rate_low = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 14)); + pdata->dss_config__manual_effective_spads_select = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 16)); + pdata->dss_config__manual_block_select = + (*(pbuffer + 18)); + pdata->dss_config__aperture_attenuation = + (*(pbuffer + 19)); + pdata->dss_config__max_spads_limit = + (*(pbuffer + 20)); + pdata->dss_config__min_spads_limit = + (*(pbuffer + 21)); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_general_config( + VL53L1_DEV Dev, + VL53L1_general_config_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_GENERAL_CONFIG_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_i2c_encode_general_config( + pdata, + VL53L1_GENERAL_CONFIG_I2C_SIZE_BYTES, + comms_buffer); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WriteMulti( + Dev, + VL53L1_GPH_CONFIG__STREAM_COUNT_UPDATE_VALUE, + comms_buffer, + VL53L1_GENERAL_CONFIG_I2C_SIZE_BYTES); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_general_config( + VL53L1_DEV Dev, + VL53L1_general_config_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_GENERAL_CONFIG_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_ReadMulti( + Dev, + VL53L1_GPH_CONFIG__STREAM_COUNT_UPDATE_VALUE, + comms_buffer, + VL53L1_GENERAL_CONFIG_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_i2c_decode_general_config( + VL53L1_GENERAL_CONFIG_I2C_SIZE_BYTES, + comms_buffer, + pdata); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_i2c_encode_timing_config( + VL53L1_timing_config_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_TIMING_CONFIG_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + *(pbuffer + 0) = + pdata->mm_config__timeout_macrop_a_hi & 0xF; + *(pbuffer + 1) = + pdata->mm_config__timeout_macrop_a_lo; + *(pbuffer + 2) = + pdata->mm_config__timeout_macrop_b_hi & 0xF; + *(pbuffer + 3) = + pdata->mm_config__timeout_macrop_b_lo; + *(pbuffer + 4) = + pdata->range_config__timeout_macrop_a_hi & 0xF; + *(pbuffer + 5) = + pdata->range_config__timeout_macrop_a_lo; + *(pbuffer + 6) = + pdata->range_config__vcsel_period_a & 0x3F; + *(pbuffer + 7) = + pdata->range_config__timeout_macrop_b_hi & 0xF; + *(pbuffer + 8) = + pdata->range_config__timeout_macrop_b_lo; + *(pbuffer + 9) = + pdata->range_config__vcsel_period_b & 0x3F; + VL53L1_i2c_encode_uint16_t( + pdata->range_config__sigma_thresh, + 2, + pbuffer + 10); + VL53L1_i2c_encode_uint16_t( + pdata->range_config__min_count_rate_rtn_limit_mcps, + 2, + pbuffer + 12); + *(pbuffer + 14) = + pdata->range_config__valid_phase_low; + *(pbuffer + 15) = + pdata->range_config__valid_phase_high; + VL53L1_i2c_encode_uint32_t( + pdata->system__intermeasurement_period, + 4, + pbuffer + 18); + *(pbuffer + 22) = + pdata->system__fractional_enable & 0x1; + LOG_FUNCTION_END(status); + + + return status; +} + + +VL53L1_Error VL53L1_i2c_decode_timing_config( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_timing_config_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_TIMING_CONFIG_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + pdata->mm_config__timeout_macrop_a_hi = + (*(pbuffer + 0)) & 0xF; + pdata->mm_config__timeout_macrop_a_lo = + (*(pbuffer + 1)); + pdata->mm_config__timeout_macrop_b_hi = + (*(pbuffer + 2)) & 0xF; + pdata->mm_config__timeout_macrop_b_lo = + (*(pbuffer + 3)); + pdata->range_config__timeout_macrop_a_hi = + (*(pbuffer + 4)) & 0xF; + pdata->range_config__timeout_macrop_a_lo = + (*(pbuffer + 5)); + pdata->range_config__vcsel_period_a = + (*(pbuffer + 6)) & 0x3F; + pdata->range_config__timeout_macrop_b_hi = + (*(pbuffer + 7)) & 0xF; + pdata->range_config__timeout_macrop_b_lo = + (*(pbuffer + 8)); + pdata->range_config__vcsel_period_b = + (*(pbuffer + 9)) & 0x3F; + pdata->range_config__sigma_thresh = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 10)); + pdata->range_config__min_count_rate_rtn_limit_mcps = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 12)); + pdata->range_config__valid_phase_low = + (*(pbuffer + 14)); + pdata->range_config__valid_phase_high = + (*(pbuffer + 15)); + pdata->system__intermeasurement_period = + (VL53L1_i2c_decode_uint32_t(4, pbuffer + 18)); + pdata->system__fractional_enable = + (*(pbuffer + 22)) & 0x1; + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_timing_config( + VL53L1_DEV Dev, + VL53L1_timing_config_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_TIMING_CONFIG_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_i2c_encode_timing_config( + pdata, + VL53L1_TIMING_CONFIG_I2C_SIZE_BYTES, + comms_buffer); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WriteMulti( + Dev, + VL53L1_MM_CONFIG__TIMEOUT_MACROP_A_HI, + comms_buffer, + VL53L1_TIMING_CONFIG_I2C_SIZE_BYTES); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_timing_config( + VL53L1_DEV Dev, + VL53L1_timing_config_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_TIMING_CONFIG_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_ReadMulti( + Dev, + VL53L1_MM_CONFIG__TIMEOUT_MACROP_A_HI, + comms_buffer, + VL53L1_TIMING_CONFIG_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_i2c_decode_timing_config( + VL53L1_TIMING_CONFIG_I2C_SIZE_BYTES, + comms_buffer, + pdata); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_i2c_encode_dynamic_config( + VL53L1_dynamic_config_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_DYNAMIC_CONFIG_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + *(pbuffer + 0) = + pdata->system__grouped_parameter_hold_0 & 0x3; + VL53L1_i2c_encode_uint16_t( + pdata->system__thresh_high, + 2, + pbuffer + 1); + VL53L1_i2c_encode_uint16_t( + pdata->system__thresh_low, + 2, + pbuffer + 3); + *(pbuffer + 5) = + pdata->system__enable_xtalk_per_quadrant & 0x1; + *(pbuffer + 6) = + pdata->system__seed_config & 0x7; + *(pbuffer + 7) = + pdata->sd_config__woi_sd0; + *(pbuffer + 8) = + pdata->sd_config__woi_sd1; + *(pbuffer + 9) = + pdata->sd_config__initial_phase_sd0 & 0x7F; + *(pbuffer + 10) = + pdata->sd_config__initial_phase_sd1 & 0x7F; + *(pbuffer + 11) = + pdata->system__grouped_parameter_hold_1 & 0x3; + *(pbuffer + 12) = + pdata->sd_config__first_order_select & 0x3; + *(pbuffer + 13) = + pdata->sd_config__quantifier & 0xF; + *(pbuffer + 14) = + pdata->roi_config__user_roi_centre_spad; + *(pbuffer + 15) = + pdata->roi_config__user_roi_requested_global_xy_size; + *(pbuffer + 16) = + pdata->system__sequence_config; + *(pbuffer + 17) = + pdata->system__grouped_parameter_hold & 0x3; + LOG_FUNCTION_END(status); + + + return status; +} + + +VL53L1_Error VL53L1_i2c_decode_dynamic_config( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_dynamic_config_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_DYNAMIC_CONFIG_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + pdata->system__grouped_parameter_hold_0 = + (*(pbuffer + 0)) & 0x3; + pdata->system__thresh_high = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 1)); + pdata->system__thresh_low = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 3)); + pdata->system__enable_xtalk_per_quadrant = + (*(pbuffer + 5)) & 0x1; + pdata->system__seed_config = + (*(pbuffer + 6)) & 0x7; + pdata->sd_config__woi_sd0 = + (*(pbuffer + 7)); + pdata->sd_config__woi_sd1 = + (*(pbuffer + 8)); + pdata->sd_config__initial_phase_sd0 = + (*(pbuffer + 9)) & 0x7F; + pdata->sd_config__initial_phase_sd1 = + (*(pbuffer + 10)) & 0x7F; + pdata->system__grouped_parameter_hold_1 = + (*(pbuffer + 11)) & 0x3; + pdata->sd_config__first_order_select = + (*(pbuffer + 12)) & 0x3; + pdata->sd_config__quantifier = + (*(pbuffer + 13)) & 0xF; + pdata->roi_config__user_roi_centre_spad = + (*(pbuffer + 14)); + pdata->roi_config__user_roi_requested_global_xy_size = + (*(pbuffer + 15)); + pdata->system__sequence_config = + (*(pbuffer + 16)); + pdata->system__grouped_parameter_hold = + (*(pbuffer + 17)) & 0x3; + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_dynamic_config( + VL53L1_DEV Dev, + VL53L1_dynamic_config_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_DYNAMIC_CONFIG_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_i2c_encode_dynamic_config( + pdata, + VL53L1_DYNAMIC_CONFIG_I2C_SIZE_BYTES, + comms_buffer); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WriteMulti( + Dev, + VL53L1_SYSTEM__GROUPED_PARAMETER_HOLD_0, + comms_buffer, + VL53L1_DYNAMIC_CONFIG_I2C_SIZE_BYTES); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_dynamic_config( + VL53L1_DEV Dev, + VL53L1_dynamic_config_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_DYNAMIC_CONFIG_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_ReadMulti( + Dev, + VL53L1_SYSTEM__GROUPED_PARAMETER_HOLD_0, + comms_buffer, + VL53L1_DYNAMIC_CONFIG_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_i2c_decode_dynamic_config( + VL53L1_DYNAMIC_CONFIG_I2C_SIZE_BYTES, + comms_buffer, + pdata); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_i2c_encode_system_control( + VL53L1_system_control_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_SYSTEM_CONTROL_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + *(pbuffer + 0) = + pdata->power_management__go1_power_force & 0x1; + *(pbuffer + 1) = + pdata->system__stream_count_ctrl & 0x1; + *(pbuffer + 2) = + pdata->firmware__enable & 0x1; + *(pbuffer + 3) = + pdata->system__interrupt_clear & 0x3; + *(pbuffer + 4) = + pdata->system__mode_start; + LOG_FUNCTION_END(status); + + + return status; +} + + +VL53L1_Error VL53L1_i2c_decode_system_control( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_system_control_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_SYSTEM_CONTROL_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + pdata->power_management__go1_power_force = + (*(pbuffer + 0)) & 0x1; + pdata->system__stream_count_ctrl = + (*(pbuffer + 1)) & 0x1; + pdata->firmware__enable = + (*(pbuffer + 2)) & 0x1; + pdata->system__interrupt_clear = + (*(pbuffer + 3)) & 0x3; + pdata->system__mode_start = + (*(pbuffer + 4)); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_system_control( + VL53L1_DEV Dev, + VL53L1_system_control_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_SYSTEM_CONTROL_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_i2c_encode_system_control( + pdata, + VL53L1_SYSTEM_CONTROL_I2C_SIZE_BYTES, + comms_buffer); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WriteMulti( + Dev, + VL53L1_POWER_MANAGEMENT__GO1_POWER_FORCE, + comms_buffer, + VL53L1_SYSTEM_CONTROL_I2C_SIZE_BYTES); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_system_control( + VL53L1_DEV Dev, + VL53L1_system_control_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_SYSTEM_CONTROL_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_ReadMulti( + Dev, + VL53L1_POWER_MANAGEMENT__GO1_POWER_FORCE, + comms_buffer, + VL53L1_SYSTEM_CONTROL_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_i2c_decode_system_control( + VL53L1_SYSTEM_CONTROL_I2C_SIZE_BYTES, + comms_buffer, + pdata); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_i2c_encode_system_results( + VL53L1_system_results_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_SYSTEM_RESULTS_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + *(pbuffer + 0) = + pdata->result__interrupt_status & 0x3F; + *(pbuffer + 1) = + pdata->result__range_status; + *(pbuffer + 2) = + pdata->result__report_status & 0xF; + *(pbuffer + 3) = + pdata->result__stream_count; + VL53L1_i2c_encode_uint16_t( + pdata->result__dss_actual_effective_spads_sd0, + 2, + pbuffer + 4); + VL53L1_i2c_encode_uint16_t( + pdata->result__peak_signal_count_rate_mcps_sd0, + 2, + pbuffer + 6); + VL53L1_i2c_encode_uint16_t( + pdata->result__ambient_count_rate_mcps_sd0, + 2, + pbuffer + 8); + VL53L1_i2c_encode_uint16_t( + pdata->result__sigma_sd0, + 2, + pbuffer + 10); + VL53L1_i2c_encode_uint16_t( + pdata->result__phase_sd0, + 2, + pbuffer + 12); + VL53L1_i2c_encode_uint16_t( + pdata->result__final_crosstalk_corrected_range_mm_sd0, + 2, + pbuffer + 14); + VL53L1_i2c_encode_uint16_t( + pdata->result__peak_signal_count_rate_crosstalk_corrected_mcps_sd0, + 2, + pbuffer + 16); + VL53L1_i2c_encode_uint16_t( + pdata->result__mm_inner_actual_effective_spads_sd0, + 2, + pbuffer + 18); + VL53L1_i2c_encode_uint16_t( + pdata->result__mm_outer_actual_effective_spads_sd0, + 2, + pbuffer + 20); + VL53L1_i2c_encode_uint16_t( + pdata->result__avg_signal_count_rate_mcps_sd0, + 2, + pbuffer + 22); + VL53L1_i2c_encode_uint16_t( + pdata->result__dss_actual_effective_spads_sd1, + 2, + pbuffer + 24); + VL53L1_i2c_encode_uint16_t( + pdata->result__peak_signal_count_rate_mcps_sd1, + 2, + pbuffer + 26); + VL53L1_i2c_encode_uint16_t( + pdata->result__ambient_count_rate_mcps_sd1, + 2, + pbuffer + 28); + VL53L1_i2c_encode_uint16_t( + pdata->result__sigma_sd1, + 2, + pbuffer + 30); + VL53L1_i2c_encode_uint16_t( + pdata->result__phase_sd1, + 2, + pbuffer + 32); + VL53L1_i2c_encode_uint16_t( + pdata->result__final_crosstalk_corrected_range_mm_sd1, + 2, + pbuffer + 34); + VL53L1_i2c_encode_uint16_t( + pdata->result__spare_0_sd1, + 2, + pbuffer + 36); + VL53L1_i2c_encode_uint16_t( + pdata->result__spare_1_sd1, + 2, + pbuffer + 38); + VL53L1_i2c_encode_uint16_t( + pdata->result__spare_2_sd1, + 2, + pbuffer + 40); + *(pbuffer + 42) = + pdata->result__spare_3_sd1; + *(pbuffer + 43) = + pdata->result__thresh_info; + LOG_FUNCTION_END(status); + + + return status; +} + + +VL53L1_Error VL53L1_i2c_decode_system_results( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_system_results_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_SYSTEM_RESULTS_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + pdata->result__interrupt_status = + (*(pbuffer + 0)) & 0x3F; + pdata->result__range_status = + (*(pbuffer + 1)); + pdata->result__report_status = + (*(pbuffer + 2)) & 0xF; + pdata->result__stream_count = + (*(pbuffer + 3)); + pdata->result__dss_actual_effective_spads_sd0 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 4)); + pdata->result__peak_signal_count_rate_mcps_sd0 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 6)); + pdata->result__ambient_count_rate_mcps_sd0 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 8)); + pdata->result__sigma_sd0 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 10)); + pdata->result__phase_sd0 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 12)); + pdata->result__final_crosstalk_corrected_range_mm_sd0 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 14)); + pdata->result__peak_signal_count_rate_crosstalk_corrected_mcps_sd0 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 16)); + pdata->result__mm_inner_actual_effective_spads_sd0 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 18)); + pdata->result__mm_outer_actual_effective_spads_sd0 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 20)); + pdata->result__avg_signal_count_rate_mcps_sd0 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 22)); + pdata->result__dss_actual_effective_spads_sd1 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 24)); + pdata->result__peak_signal_count_rate_mcps_sd1 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 26)); + pdata->result__ambient_count_rate_mcps_sd1 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 28)); + pdata->result__sigma_sd1 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 30)); + pdata->result__phase_sd1 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 32)); + pdata->result__final_crosstalk_corrected_range_mm_sd1 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 34)); + pdata->result__spare_0_sd1 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 36)); + pdata->result__spare_1_sd1 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 38)); + pdata->result__spare_2_sd1 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 40)); + pdata->result__spare_3_sd1 = + (*(pbuffer + 42)); + pdata->result__thresh_info = + (*(pbuffer + 43)); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_system_results( + VL53L1_DEV Dev, + VL53L1_system_results_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_SYSTEM_RESULTS_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_i2c_encode_system_results( + pdata, + VL53L1_SYSTEM_RESULTS_I2C_SIZE_BYTES, + comms_buffer); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WriteMulti( + Dev, + VL53L1_RESULT__INTERRUPT_STATUS, + comms_buffer, + VL53L1_SYSTEM_RESULTS_I2C_SIZE_BYTES); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_system_results( + VL53L1_DEV Dev, + VL53L1_system_results_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_SYSTEM_RESULTS_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_ReadMulti( + Dev, + VL53L1_RESULT__INTERRUPT_STATUS, + comms_buffer, + VL53L1_SYSTEM_RESULTS_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_i2c_decode_system_results( + VL53L1_SYSTEM_RESULTS_I2C_SIZE_BYTES, + comms_buffer, + pdata); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_i2c_encode_core_results( + VL53L1_core_results_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_CORE_RESULTS_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + VL53L1_i2c_encode_uint32_t( + pdata->result_core__ambient_window_events_sd0, + 4, + pbuffer + 0); + VL53L1_i2c_encode_uint32_t( + pdata->result_core__ranging_total_events_sd0, + 4, + pbuffer + 4); + VL53L1_i2c_encode_int32_t( + pdata->result_core__signal_total_events_sd0, + 4, + pbuffer + 8); + VL53L1_i2c_encode_uint32_t( + pdata->result_core__total_periods_elapsed_sd0, + 4, + pbuffer + 12); + VL53L1_i2c_encode_uint32_t( + pdata->result_core__ambient_window_events_sd1, + 4, + pbuffer + 16); + VL53L1_i2c_encode_uint32_t( + pdata->result_core__ranging_total_events_sd1, + 4, + pbuffer + 20); + VL53L1_i2c_encode_int32_t( + pdata->result_core__signal_total_events_sd1, + 4, + pbuffer + 24); + VL53L1_i2c_encode_uint32_t( + pdata->result_core__total_periods_elapsed_sd1, + 4, + pbuffer + 28); + *(pbuffer + 32) = + pdata->result_core__spare_0; + LOG_FUNCTION_END(status); + + + return status; +} + + +VL53L1_Error VL53L1_i2c_decode_core_results( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_core_results_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_CORE_RESULTS_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + pdata->result_core__ambient_window_events_sd0 = + (VL53L1_i2c_decode_uint32_t(4, pbuffer + 0)); + pdata->result_core__ranging_total_events_sd0 = + (VL53L1_i2c_decode_uint32_t(4, pbuffer + 4)); + pdata->result_core__signal_total_events_sd0 = + (VL53L1_i2c_decode_int32_t(4, pbuffer + 8)); + pdata->result_core__total_periods_elapsed_sd0 = + (VL53L1_i2c_decode_uint32_t(4, pbuffer + 12)); + pdata->result_core__ambient_window_events_sd1 = + (VL53L1_i2c_decode_uint32_t(4, pbuffer + 16)); + pdata->result_core__ranging_total_events_sd1 = + (VL53L1_i2c_decode_uint32_t(4, pbuffer + 20)); + pdata->result_core__signal_total_events_sd1 = + (VL53L1_i2c_decode_int32_t(4, pbuffer + 24)); + pdata->result_core__total_periods_elapsed_sd1 = + (VL53L1_i2c_decode_uint32_t(4, pbuffer + 28)); + pdata->result_core__spare_0 = + (*(pbuffer + 32)); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_core_results( + VL53L1_DEV Dev, + VL53L1_core_results_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_CORE_RESULTS_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_i2c_encode_core_results( + pdata, + VL53L1_CORE_RESULTS_I2C_SIZE_BYTES, + comms_buffer); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_disable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WriteMulti( + Dev, + VL53L1_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD0, + comms_buffer, + VL53L1_CORE_RESULTS_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_firmware(Dev); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_core_results( + VL53L1_DEV Dev, + VL53L1_core_results_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_CORE_RESULTS_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_ReadMulti( + Dev, + VL53L1_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD0, + comms_buffer, + VL53L1_CORE_RESULTS_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_i2c_decode_core_results( + VL53L1_CORE_RESULTS_I2C_SIZE_BYTES, + comms_buffer, + pdata); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_i2c_encode_debug_results( + VL53L1_debug_results_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_DEBUG_RESULTS_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + VL53L1_i2c_encode_uint16_t( + pdata->phasecal_result__reference_phase, + 2, + pbuffer + 0); + *(pbuffer + 2) = + pdata->phasecal_result__vcsel_start & 0x7F; + *(pbuffer + 3) = + pdata->ref_spad_char_result__num_actual_ref_spads & 0x3F; + *(pbuffer + 4) = + pdata->ref_spad_char_result__ref_location & 0x3; + *(pbuffer + 5) = + pdata->vhv_result__coldboot_status & 0x1; + *(pbuffer + 6) = + pdata->vhv_result__search_result & 0x3F; + *(pbuffer + 7) = + pdata->vhv_result__latest_setting & 0x3F; + VL53L1_i2c_encode_uint16_t( + pdata->result__osc_calibrate_val & 0x3FF, + 2, + pbuffer + 8); + *(pbuffer + 10) = + pdata->ana_config__powerdown_go1 & 0x3; + *(pbuffer + 11) = + pdata->ana_config__ref_bg_ctrl & 0x3; + *(pbuffer + 12) = + pdata->ana_config__regdvdd1v2_ctrl & 0xF; + *(pbuffer + 13) = + pdata->ana_config__osc_slow_ctrl & 0x7; + *(pbuffer + 14) = + pdata->test_mode__status & 0x1; + *(pbuffer + 15) = + pdata->firmware__system_status & 0x3; + *(pbuffer + 16) = + pdata->firmware__mode_status; + *(pbuffer + 17) = + pdata->firmware__secondary_mode_status; + VL53L1_i2c_encode_uint16_t( + pdata->firmware__cal_repeat_rate_counter & 0xFFF, + 2, + pbuffer + 18); + VL53L1_i2c_encode_uint16_t( + pdata->gph__system__thresh_high, + 2, + pbuffer + 22); + VL53L1_i2c_encode_uint16_t( + pdata->gph__system__thresh_low, + 2, + pbuffer + 24); + *(pbuffer + 26) = + pdata->gph__system__enable_xtalk_per_quadrant & 0x1; + *(pbuffer + 27) = + pdata->gph__spare_0 & 0x7; + *(pbuffer + 28) = + pdata->gph__sd_config__woi_sd0; + *(pbuffer + 29) = + pdata->gph__sd_config__woi_sd1; + *(pbuffer + 30) = + pdata->gph__sd_config__initial_phase_sd0 & 0x7F; + *(pbuffer + 31) = + pdata->gph__sd_config__initial_phase_sd1 & 0x7F; + *(pbuffer + 32) = + pdata->gph__sd_config__first_order_select & 0x3; + *(pbuffer + 33) = + pdata->gph__sd_config__quantifier & 0xF; + *(pbuffer + 34) = + pdata->gph__roi_config__user_roi_centre_spad; + *(pbuffer + 35) = + pdata->gph__roi_config__user_roi_requested_global_xy_size; + *(pbuffer + 36) = + pdata->gph__system__sequence_config; + *(pbuffer + 37) = + pdata->gph__gph_id & 0x1; + *(pbuffer + 38) = + pdata->system__interrupt_set & 0x3; + *(pbuffer + 39) = + pdata->interrupt_manager__enables & 0x1F; + *(pbuffer + 40) = + pdata->interrupt_manager__clear & 0x1F; + *(pbuffer + 41) = + pdata->interrupt_manager__status & 0x1F; + *(pbuffer + 42) = + pdata->mcu_to_host_bank__wr_access_en & 0x1; + *(pbuffer + 43) = + pdata->power_management__go1_reset_status & 0x1; + *(pbuffer + 44) = + pdata->pad_startup_mode__value_ro & 0x3; + *(pbuffer + 45) = + pdata->pad_startup_mode__value_ctrl & 0x3F; + VL53L1_i2c_encode_uint32_t( + pdata->pll_period_us & 0x3FFFF, + 4, + pbuffer + 46); + VL53L1_i2c_encode_uint32_t( + pdata->interrupt_scheduler__data_out, + 4, + pbuffer + 50); + *(pbuffer + 54) = + pdata->nvm_bist__complete & 0x1; + *(pbuffer + 55) = + pdata->nvm_bist__status & 0x1; + LOG_FUNCTION_END(status); + + + return status; +} + + +VL53L1_Error VL53L1_i2c_decode_debug_results( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_debug_results_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_DEBUG_RESULTS_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + pdata->phasecal_result__reference_phase = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 0)); + pdata->phasecal_result__vcsel_start = + (*(pbuffer + 2)) & 0x7F; + pdata->ref_spad_char_result__num_actual_ref_spads = + (*(pbuffer + 3)) & 0x3F; + pdata->ref_spad_char_result__ref_location = + (*(pbuffer + 4)) & 0x3; + pdata->vhv_result__coldboot_status = + (*(pbuffer + 5)) & 0x1; + pdata->vhv_result__search_result = + (*(pbuffer + 6)) & 0x3F; + pdata->vhv_result__latest_setting = + (*(pbuffer + 7)) & 0x3F; + pdata->result__osc_calibrate_val = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 8)) & 0x3FF; + pdata->ana_config__powerdown_go1 = + (*(pbuffer + 10)) & 0x3; + pdata->ana_config__ref_bg_ctrl = + (*(pbuffer + 11)) & 0x3; + pdata->ana_config__regdvdd1v2_ctrl = + (*(pbuffer + 12)) & 0xF; + pdata->ana_config__osc_slow_ctrl = + (*(pbuffer + 13)) & 0x7; + pdata->test_mode__status = + (*(pbuffer + 14)) & 0x1; + pdata->firmware__system_status = + (*(pbuffer + 15)) & 0x3; + pdata->firmware__mode_status = + (*(pbuffer + 16)); + pdata->firmware__secondary_mode_status = + (*(pbuffer + 17)); + pdata->firmware__cal_repeat_rate_counter = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 18)) & 0xFFF; + pdata->gph__system__thresh_high = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 22)); + pdata->gph__system__thresh_low = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 24)); + pdata->gph__system__enable_xtalk_per_quadrant = + (*(pbuffer + 26)) & 0x1; + pdata->gph__spare_0 = + (*(pbuffer + 27)) & 0x7; + pdata->gph__sd_config__woi_sd0 = + (*(pbuffer + 28)); + pdata->gph__sd_config__woi_sd1 = + (*(pbuffer + 29)); + pdata->gph__sd_config__initial_phase_sd0 = + (*(pbuffer + 30)) & 0x7F; + pdata->gph__sd_config__initial_phase_sd1 = + (*(pbuffer + 31)) & 0x7F; + pdata->gph__sd_config__first_order_select = + (*(pbuffer + 32)) & 0x3; + pdata->gph__sd_config__quantifier = + (*(pbuffer + 33)) & 0xF; + pdata->gph__roi_config__user_roi_centre_spad = + (*(pbuffer + 34)); + pdata->gph__roi_config__user_roi_requested_global_xy_size = + (*(pbuffer + 35)); + pdata->gph__system__sequence_config = + (*(pbuffer + 36)); + pdata->gph__gph_id = + (*(pbuffer + 37)) & 0x1; + pdata->system__interrupt_set = + (*(pbuffer + 38)) & 0x3; + pdata->interrupt_manager__enables = + (*(pbuffer + 39)) & 0x1F; + pdata->interrupt_manager__clear = + (*(pbuffer + 40)) & 0x1F; + pdata->interrupt_manager__status = + (*(pbuffer + 41)) & 0x1F; + pdata->mcu_to_host_bank__wr_access_en = + (*(pbuffer + 42)) & 0x1; + pdata->power_management__go1_reset_status = + (*(pbuffer + 43)) & 0x1; + pdata->pad_startup_mode__value_ro = + (*(pbuffer + 44)) & 0x3; + pdata->pad_startup_mode__value_ctrl = + (*(pbuffer + 45)) & 0x3F; + pdata->pll_period_us = + (VL53L1_i2c_decode_uint32_t(4, pbuffer + 46)) & 0x3FFFF; + pdata->interrupt_scheduler__data_out = + (VL53L1_i2c_decode_uint32_t(4, pbuffer + 50)); + pdata->nvm_bist__complete = + (*(pbuffer + 54)) & 0x1; + pdata->nvm_bist__status = + (*(pbuffer + 55)) & 0x1; + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_debug_results( + VL53L1_DEV Dev, + VL53L1_debug_results_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_DEBUG_RESULTS_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_i2c_encode_debug_results( + pdata, + VL53L1_DEBUG_RESULTS_I2C_SIZE_BYTES, + comms_buffer); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_disable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WriteMulti( + Dev, + VL53L1_PHASECAL_RESULT__REFERENCE_PHASE, + comms_buffer, + VL53L1_DEBUG_RESULTS_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_firmware(Dev); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_debug_results( + VL53L1_DEV Dev, + VL53L1_debug_results_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_DEBUG_RESULTS_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_ReadMulti( + Dev, + VL53L1_PHASECAL_RESULT__REFERENCE_PHASE, + comms_buffer, + VL53L1_DEBUG_RESULTS_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_i2c_decode_debug_results( + VL53L1_DEBUG_RESULTS_I2C_SIZE_BYTES, + comms_buffer, + pdata); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_i2c_encode_nvm_copy_data( + VL53L1_nvm_copy_data_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_NVM_COPY_DATA_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + *(pbuffer + 0) = + pdata->identification__model_id; + *(pbuffer + 1) = + pdata->identification__module_type; + *(pbuffer + 2) = + pdata->identification__revision_id; + VL53L1_i2c_encode_uint16_t( + pdata->identification__module_id, + 2, + pbuffer + 3); + *(pbuffer + 5) = + pdata->ana_config__fast_osc__trim_max & 0x7F; + *(pbuffer + 6) = + pdata->ana_config__fast_osc__freq_set & 0x7; + *(pbuffer + 7) = + pdata->ana_config__vcsel_trim & 0x7; + *(pbuffer + 8) = + pdata->ana_config__vcsel_selion & 0x3F; + *(pbuffer + 9) = + pdata->ana_config__vcsel_selion_max & 0x3F; + *(pbuffer + 10) = + pdata->protected_laser_safety__lock_bit & 0x1; + *(pbuffer + 11) = + pdata->laser_safety__key & 0x7F; + *(pbuffer + 12) = + pdata->laser_safety__key_ro & 0x1; + *(pbuffer + 13) = + pdata->laser_safety__clip & 0x3F; + *(pbuffer + 14) = + pdata->laser_safety__mult & 0x3F; + *(pbuffer + 15) = + pdata->global_config__spad_enables_rtn_0; + *(pbuffer + 16) = + pdata->global_config__spad_enables_rtn_1; + *(pbuffer + 17) = + pdata->global_config__spad_enables_rtn_2; + *(pbuffer + 18) = + pdata->global_config__spad_enables_rtn_3; + *(pbuffer + 19) = + pdata->global_config__spad_enables_rtn_4; + *(pbuffer + 20) = + pdata->global_config__spad_enables_rtn_5; + *(pbuffer + 21) = + pdata->global_config__spad_enables_rtn_6; + *(pbuffer + 22) = + pdata->global_config__spad_enables_rtn_7; + *(pbuffer + 23) = + pdata->global_config__spad_enables_rtn_8; + *(pbuffer + 24) = + pdata->global_config__spad_enables_rtn_9; + *(pbuffer + 25) = + pdata->global_config__spad_enables_rtn_10; + *(pbuffer + 26) = + pdata->global_config__spad_enables_rtn_11; + *(pbuffer + 27) = + pdata->global_config__spad_enables_rtn_12; + *(pbuffer + 28) = + pdata->global_config__spad_enables_rtn_13; + *(pbuffer + 29) = + pdata->global_config__spad_enables_rtn_14; + *(pbuffer + 30) = + pdata->global_config__spad_enables_rtn_15; + *(pbuffer + 31) = + pdata->global_config__spad_enables_rtn_16; + *(pbuffer + 32) = + pdata->global_config__spad_enables_rtn_17; + *(pbuffer + 33) = + pdata->global_config__spad_enables_rtn_18; + *(pbuffer + 34) = + pdata->global_config__spad_enables_rtn_19; + *(pbuffer + 35) = + pdata->global_config__spad_enables_rtn_20; + *(pbuffer + 36) = + pdata->global_config__spad_enables_rtn_21; + *(pbuffer + 37) = + pdata->global_config__spad_enables_rtn_22; + *(pbuffer + 38) = + pdata->global_config__spad_enables_rtn_23; + *(pbuffer + 39) = + pdata->global_config__spad_enables_rtn_24; + *(pbuffer + 40) = + pdata->global_config__spad_enables_rtn_25; + *(pbuffer + 41) = + pdata->global_config__spad_enables_rtn_26; + *(pbuffer + 42) = + pdata->global_config__spad_enables_rtn_27; + *(pbuffer + 43) = + pdata->global_config__spad_enables_rtn_28; + *(pbuffer + 44) = + pdata->global_config__spad_enables_rtn_29; + *(pbuffer + 45) = + pdata->global_config__spad_enables_rtn_30; + *(pbuffer + 46) = + pdata->global_config__spad_enables_rtn_31; + *(pbuffer + 47) = + pdata->roi_config__mode_roi_centre_spad; + *(pbuffer + 48) = + pdata->roi_config__mode_roi_xy_size; + LOG_FUNCTION_END(status); + + + return status; +} + + +VL53L1_Error VL53L1_i2c_decode_nvm_copy_data( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_nvm_copy_data_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_NVM_COPY_DATA_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + pdata->identification__model_id = + (*(pbuffer + 0)); + pdata->identification__module_type = + (*(pbuffer + 1)); + pdata->identification__revision_id = + (*(pbuffer + 2)); + pdata->identification__module_id = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 3)); + pdata->ana_config__fast_osc__trim_max = + (*(pbuffer + 5)) & 0x7F; + pdata->ana_config__fast_osc__freq_set = + (*(pbuffer + 6)) & 0x7; + pdata->ana_config__vcsel_trim = + (*(pbuffer + 7)) & 0x7; + pdata->ana_config__vcsel_selion = + (*(pbuffer + 8)) & 0x3F; + pdata->ana_config__vcsel_selion_max = + (*(pbuffer + 9)) & 0x3F; + pdata->protected_laser_safety__lock_bit = + (*(pbuffer + 10)) & 0x1; + pdata->laser_safety__key = + (*(pbuffer + 11)) & 0x7F; + pdata->laser_safety__key_ro = + (*(pbuffer + 12)) & 0x1; + pdata->laser_safety__clip = + (*(pbuffer + 13)) & 0x3F; + pdata->laser_safety__mult = + (*(pbuffer + 14)) & 0x3F; + pdata->global_config__spad_enables_rtn_0 = + (*(pbuffer + 15)); + pdata->global_config__spad_enables_rtn_1 = + (*(pbuffer + 16)); + pdata->global_config__spad_enables_rtn_2 = + (*(pbuffer + 17)); + pdata->global_config__spad_enables_rtn_3 = + (*(pbuffer + 18)); + pdata->global_config__spad_enables_rtn_4 = + (*(pbuffer + 19)); + pdata->global_config__spad_enables_rtn_5 = + (*(pbuffer + 20)); + pdata->global_config__spad_enables_rtn_6 = + (*(pbuffer + 21)); + pdata->global_config__spad_enables_rtn_7 = + (*(pbuffer + 22)); + pdata->global_config__spad_enables_rtn_8 = + (*(pbuffer + 23)); + pdata->global_config__spad_enables_rtn_9 = + (*(pbuffer + 24)); + pdata->global_config__spad_enables_rtn_10 = + (*(pbuffer + 25)); + pdata->global_config__spad_enables_rtn_11 = + (*(pbuffer + 26)); + pdata->global_config__spad_enables_rtn_12 = + (*(pbuffer + 27)); + pdata->global_config__spad_enables_rtn_13 = + (*(pbuffer + 28)); + pdata->global_config__spad_enables_rtn_14 = + (*(pbuffer + 29)); + pdata->global_config__spad_enables_rtn_15 = + (*(pbuffer + 30)); + pdata->global_config__spad_enables_rtn_16 = + (*(pbuffer + 31)); + pdata->global_config__spad_enables_rtn_17 = + (*(pbuffer + 32)); + pdata->global_config__spad_enables_rtn_18 = + (*(pbuffer + 33)); + pdata->global_config__spad_enables_rtn_19 = + (*(pbuffer + 34)); + pdata->global_config__spad_enables_rtn_20 = + (*(pbuffer + 35)); + pdata->global_config__spad_enables_rtn_21 = + (*(pbuffer + 36)); + pdata->global_config__spad_enables_rtn_22 = + (*(pbuffer + 37)); + pdata->global_config__spad_enables_rtn_23 = + (*(pbuffer + 38)); + pdata->global_config__spad_enables_rtn_24 = + (*(pbuffer + 39)); + pdata->global_config__spad_enables_rtn_25 = + (*(pbuffer + 40)); + pdata->global_config__spad_enables_rtn_26 = + (*(pbuffer + 41)); + pdata->global_config__spad_enables_rtn_27 = + (*(pbuffer + 42)); + pdata->global_config__spad_enables_rtn_28 = + (*(pbuffer + 43)); + pdata->global_config__spad_enables_rtn_29 = + (*(pbuffer + 44)); + pdata->global_config__spad_enables_rtn_30 = + (*(pbuffer + 45)); + pdata->global_config__spad_enables_rtn_31 = + (*(pbuffer + 46)); + pdata->roi_config__mode_roi_centre_spad = + (*(pbuffer + 47)); + pdata->roi_config__mode_roi_xy_size = + (*(pbuffer + 48)); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_nvm_copy_data( + VL53L1_DEV Dev, + VL53L1_nvm_copy_data_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_NVM_COPY_DATA_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_i2c_encode_nvm_copy_data( + pdata, + VL53L1_NVM_COPY_DATA_I2C_SIZE_BYTES, + comms_buffer); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_disable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WriteMulti( + Dev, + VL53L1_IDENTIFICATION__MODEL_ID, + comms_buffer, + VL53L1_NVM_COPY_DATA_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_firmware(Dev); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_nvm_copy_data( + VL53L1_DEV Dev, + VL53L1_nvm_copy_data_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_NVM_COPY_DATA_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_ReadMulti( + Dev, + VL53L1_IDENTIFICATION__MODEL_ID, + comms_buffer, + VL53L1_NVM_COPY_DATA_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_i2c_decode_nvm_copy_data( + VL53L1_NVM_COPY_DATA_I2C_SIZE_BYTES, + comms_buffer, + pdata); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_i2c_encode_prev_shadow_system_results( + VL53L1_prev_shadow_system_results_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_PREV_SHADOW_SYSTEM_RESULTS_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + *(pbuffer + 0) = + pdata->prev_shadow_result__interrupt_status & 0x3F; + *(pbuffer + 1) = + pdata->prev_shadow_result__range_status; + *(pbuffer + 2) = + pdata->prev_shadow_result__report_status & 0xF; + *(pbuffer + 3) = + pdata->prev_shadow_result__stream_count; + VL53L1_i2c_encode_uint16_t( + pdata->prev_shadow_result__dss_actual_effective_spads_sd0, + 2, + pbuffer + 4); + VL53L1_i2c_encode_uint16_t( + pdata->prev_shadow_result__peak_signal_count_rate_mcps_sd0, + 2, + pbuffer + 6); + VL53L1_i2c_encode_uint16_t( + pdata->prev_shadow_result__ambient_count_rate_mcps_sd0, + 2, + pbuffer + 8); + VL53L1_i2c_encode_uint16_t( + pdata->prev_shadow_result__sigma_sd0, + 2, + pbuffer + 10); + VL53L1_i2c_encode_uint16_t( + pdata->prev_shadow_result__phase_sd0, + 2, + pbuffer + 12); + VL53L1_i2c_encode_uint16_t( + pdata->prev_shadow_result__final_crosstalk_corrected_range_mm_sd0, + 2, + pbuffer + 14); + VL53L1_i2c_encode_uint16_t( + pdata->psr__peak_signal_count_rate_crosstalk_corrected_mcps_sd0, + 2, + pbuffer + 16); + VL53L1_i2c_encode_uint16_t( + pdata->prev_shadow_result__mm_inner_actual_effective_spads_sd0, + 2, + pbuffer + 18); + VL53L1_i2c_encode_uint16_t( + pdata->prev_shadow_result__mm_outer_actual_effective_spads_sd0, + 2, + pbuffer + 20); + VL53L1_i2c_encode_uint16_t( + pdata->prev_shadow_result__avg_signal_count_rate_mcps_sd0, + 2, + pbuffer + 22); + VL53L1_i2c_encode_uint16_t( + pdata->prev_shadow_result__dss_actual_effective_spads_sd1, + 2, + pbuffer + 24); + VL53L1_i2c_encode_uint16_t( + pdata->prev_shadow_result__peak_signal_count_rate_mcps_sd1, + 2, + pbuffer + 26); + VL53L1_i2c_encode_uint16_t( + pdata->prev_shadow_result__ambient_count_rate_mcps_sd1, + 2, + pbuffer + 28); + VL53L1_i2c_encode_uint16_t( + pdata->prev_shadow_result__sigma_sd1, + 2, + pbuffer + 30); + VL53L1_i2c_encode_uint16_t( + pdata->prev_shadow_result__phase_sd1, + 2, + pbuffer + 32); + VL53L1_i2c_encode_uint16_t( + pdata->prev_shadow_result__final_crosstalk_corrected_range_mm_sd1, + 2, + pbuffer + 34); + VL53L1_i2c_encode_uint16_t( + pdata->prev_shadow_result__spare_0_sd1, + 2, + pbuffer + 36); + VL53L1_i2c_encode_uint16_t( + pdata->prev_shadow_result__spare_1_sd1, + 2, + pbuffer + 38); + VL53L1_i2c_encode_uint16_t( + pdata->prev_shadow_result__spare_2_sd1, + 2, + pbuffer + 40); + VL53L1_i2c_encode_uint16_t( + pdata->prev_shadow_result__spare_3_sd1, + 2, + pbuffer + 42); + LOG_FUNCTION_END(status); + + + return status; +} + + +VL53L1_Error VL53L1_i2c_decode_prev_shadow_system_results( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_prev_shadow_system_results_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_PREV_SHADOW_SYSTEM_RESULTS_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + pdata->prev_shadow_result__interrupt_status = + (*(pbuffer + 0)) & 0x3F; + pdata->prev_shadow_result__range_status = + (*(pbuffer + 1)); + pdata->prev_shadow_result__report_status = + (*(pbuffer + 2)) & 0xF; + pdata->prev_shadow_result__stream_count = + (*(pbuffer + 3)); + pdata->prev_shadow_result__dss_actual_effective_spads_sd0 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 4)); + pdata->prev_shadow_result__peak_signal_count_rate_mcps_sd0 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 6)); + pdata->prev_shadow_result__ambient_count_rate_mcps_sd0 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 8)); + pdata->prev_shadow_result__sigma_sd0 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 10)); + pdata->prev_shadow_result__phase_sd0 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 12)); + pdata->prev_shadow_result__final_crosstalk_corrected_range_mm_sd0 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 14)); + pdata->psr__peak_signal_count_rate_crosstalk_corrected_mcps_sd0 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 16)); + pdata->prev_shadow_result__mm_inner_actual_effective_spads_sd0 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 18)); + pdata->prev_shadow_result__mm_outer_actual_effective_spads_sd0 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 20)); + pdata->prev_shadow_result__avg_signal_count_rate_mcps_sd0 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 22)); + pdata->prev_shadow_result__dss_actual_effective_spads_sd1 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 24)); + pdata->prev_shadow_result__peak_signal_count_rate_mcps_sd1 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 26)); + pdata->prev_shadow_result__ambient_count_rate_mcps_sd1 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 28)); + pdata->prev_shadow_result__sigma_sd1 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 30)); + pdata->prev_shadow_result__phase_sd1 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 32)); + pdata->prev_shadow_result__final_crosstalk_corrected_range_mm_sd1 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 34)); + pdata->prev_shadow_result__spare_0_sd1 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 36)); + pdata->prev_shadow_result__spare_1_sd1 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 38)); + pdata->prev_shadow_result__spare_2_sd1 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 40)); + pdata->prev_shadow_result__spare_3_sd1 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 42)); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_prev_shadow_system_results( + VL53L1_DEV Dev, + VL53L1_prev_shadow_system_results_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_PREV_SHADOW_SYSTEM_RESULTS_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_i2c_encode_prev_shadow_system_results( + pdata, + VL53L1_PREV_SHADOW_SYSTEM_RESULTS_I2C_SIZE_BYTES, + comms_buffer); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_disable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WriteMulti( + Dev, + VL53L1_PREV_SHADOW_RESULT__INTERRUPT_STATUS, + comms_buffer, + VL53L1_PREV_SHADOW_SYSTEM_RESULTS_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_firmware(Dev); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_prev_shadow_system_results( + VL53L1_DEV Dev, + VL53L1_prev_shadow_system_results_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_PREV_SHADOW_SYSTEM_RESULTS_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_disable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_ReadMulti( + Dev, + VL53L1_PREV_SHADOW_RESULT__INTERRUPT_STATUS, + comms_buffer, + VL53L1_PREV_SHADOW_SYSTEM_RESULTS_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_i2c_decode_prev_shadow_system_results( + VL53L1_PREV_SHADOW_SYSTEM_RESULTS_I2C_SIZE_BYTES, + comms_buffer, + pdata); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_i2c_encode_prev_shadow_core_results( + VL53L1_prev_shadow_core_results_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_PREV_SHADOW_CORE_RESULTS_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + VL53L1_i2c_encode_uint32_t( + pdata->prev_shadow_result_core__ambient_window_events_sd0, + 4, + pbuffer + 0); + VL53L1_i2c_encode_uint32_t( + pdata->prev_shadow_result_core__ranging_total_events_sd0, + 4, + pbuffer + 4); + VL53L1_i2c_encode_int32_t( + pdata->prev_shadow_result_core__signal_total_events_sd0, + 4, + pbuffer + 8); + VL53L1_i2c_encode_uint32_t( + pdata->prev_shadow_result_core__total_periods_elapsed_sd0, + 4, + pbuffer + 12); + VL53L1_i2c_encode_uint32_t( + pdata->prev_shadow_result_core__ambient_window_events_sd1, + 4, + pbuffer + 16); + VL53L1_i2c_encode_uint32_t( + pdata->prev_shadow_result_core__ranging_total_events_sd1, + 4, + pbuffer + 20); + VL53L1_i2c_encode_int32_t( + pdata->prev_shadow_result_core__signal_total_events_sd1, + 4, + pbuffer + 24); + VL53L1_i2c_encode_uint32_t( + pdata->prev_shadow_result_core__total_periods_elapsed_sd1, + 4, + pbuffer + 28); + *(pbuffer + 32) = + pdata->prev_shadow_result_core__spare_0; + LOG_FUNCTION_END(status); + + + return status; +} + + +VL53L1_Error VL53L1_i2c_decode_prev_shadow_core_results( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_prev_shadow_core_results_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_PREV_SHADOW_CORE_RESULTS_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + pdata->prev_shadow_result_core__ambient_window_events_sd0 = + (VL53L1_i2c_decode_uint32_t(4, pbuffer + 0)); + pdata->prev_shadow_result_core__ranging_total_events_sd0 = + (VL53L1_i2c_decode_uint32_t(4, pbuffer + 4)); + pdata->prev_shadow_result_core__signal_total_events_sd0 = + (VL53L1_i2c_decode_int32_t(4, pbuffer + 8)); + pdata->prev_shadow_result_core__total_periods_elapsed_sd0 = + (VL53L1_i2c_decode_uint32_t(4, pbuffer + 12)); + pdata->prev_shadow_result_core__ambient_window_events_sd1 = + (VL53L1_i2c_decode_uint32_t(4, pbuffer + 16)); + pdata->prev_shadow_result_core__ranging_total_events_sd1 = + (VL53L1_i2c_decode_uint32_t(4, pbuffer + 20)); + pdata->prev_shadow_result_core__signal_total_events_sd1 = + (VL53L1_i2c_decode_int32_t(4, pbuffer + 24)); + pdata->prev_shadow_result_core__total_periods_elapsed_sd1 = + (VL53L1_i2c_decode_uint32_t(4, pbuffer + 28)); + pdata->prev_shadow_result_core__spare_0 = + (*(pbuffer + 32)); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_prev_shadow_core_results( + VL53L1_DEV Dev, + VL53L1_prev_shadow_core_results_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_PREV_SHADOW_CORE_RESULTS_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_i2c_encode_prev_shadow_core_results( + pdata, + VL53L1_PREV_SHADOW_CORE_RESULTS_I2C_SIZE_BYTES, + comms_buffer); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_disable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WriteMulti( + Dev, + VL53L1_PREV_SHADOW_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD0, + comms_buffer, + VL53L1_PREV_SHADOW_CORE_RESULTS_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_firmware(Dev); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_prev_shadow_core_results( + VL53L1_DEV Dev, + VL53L1_prev_shadow_core_results_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_PREV_SHADOW_CORE_RESULTS_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_disable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_ReadMulti( + Dev, + VL53L1_PREV_SHADOW_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD0, + comms_buffer, + VL53L1_PREV_SHADOW_CORE_RESULTS_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_i2c_decode_prev_shadow_core_results( + VL53L1_PREV_SHADOW_CORE_RESULTS_I2C_SIZE_BYTES, + comms_buffer, + pdata); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_i2c_encode_patch_debug( + VL53L1_patch_debug_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_PATCH_DEBUG_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + *(pbuffer + 0) = + pdata->result__debug_status; + *(pbuffer + 1) = + pdata->result__debug_stage; + LOG_FUNCTION_END(status); + + + return status; +} + + +VL53L1_Error VL53L1_i2c_decode_patch_debug( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_patch_debug_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_PATCH_DEBUG_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + pdata->result__debug_status = + (*(pbuffer + 0)); + pdata->result__debug_stage = + (*(pbuffer + 1)); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_patch_debug( + VL53L1_DEV Dev, + VL53L1_patch_debug_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_PATCH_DEBUG_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_i2c_encode_patch_debug( + pdata, + VL53L1_PATCH_DEBUG_I2C_SIZE_BYTES, + comms_buffer); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_disable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WriteMulti( + Dev, + VL53L1_RESULT__DEBUG_STATUS, + comms_buffer, + VL53L1_PATCH_DEBUG_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_firmware(Dev); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_patch_debug( + VL53L1_DEV Dev, + VL53L1_patch_debug_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_PATCH_DEBUG_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_disable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_ReadMulti( + Dev, + VL53L1_RESULT__DEBUG_STATUS, + comms_buffer, + VL53L1_PATCH_DEBUG_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_i2c_decode_patch_debug( + VL53L1_PATCH_DEBUG_I2C_SIZE_BYTES, + comms_buffer, + pdata); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_i2c_encode_gph_general_config( + VL53L1_gph_general_config_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_GPH_GENERAL_CONFIG_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + VL53L1_i2c_encode_uint16_t( + pdata->gph__system__thresh_rate_high, + 2, + pbuffer + 0); + VL53L1_i2c_encode_uint16_t( + pdata->gph__system__thresh_rate_low, + 2, + pbuffer + 2); + *(pbuffer + 4) = + pdata->gph__system__interrupt_config_gpio; + LOG_FUNCTION_END(status); + + + return status; +} + + +VL53L1_Error VL53L1_i2c_decode_gph_general_config( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_gph_general_config_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_GPH_GENERAL_CONFIG_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + pdata->gph__system__thresh_rate_high = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 0)); + pdata->gph__system__thresh_rate_low = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 2)); + pdata->gph__system__interrupt_config_gpio = + (*(pbuffer + 4)); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_gph_general_config( + VL53L1_DEV Dev, + VL53L1_gph_general_config_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_GPH_GENERAL_CONFIG_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_i2c_encode_gph_general_config( + pdata, + VL53L1_GPH_GENERAL_CONFIG_I2C_SIZE_BYTES, + comms_buffer); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_disable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WriteMulti( + Dev, + VL53L1_GPH__SYSTEM__THRESH_RATE_HIGH, + comms_buffer, + VL53L1_GPH_GENERAL_CONFIG_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_firmware(Dev); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_gph_general_config( + VL53L1_DEV Dev, + VL53L1_gph_general_config_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_GPH_GENERAL_CONFIG_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_disable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_ReadMulti( + Dev, + VL53L1_GPH__SYSTEM__THRESH_RATE_HIGH, + comms_buffer, + VL53L1_GPH_GENERAL_CONFIG_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_i2c_decode_gph_general_config( + VL53L1_GPH_GENERAL_CONFIG_I2C_SIZE_BYTES, + comms_buffer, + pdata); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_i2c_encode_gph_static_config( + VL53L1_gph_static_config_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_GPH_STATIC_CONFIG_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + *(pbuffer + 0) = + pdata->gph__dss_config__roi_mode_control & 0x7; + VL53L1_i2c_encode_uint16_t( + pdata->gph__dss_config__manual_effective_spads_select, + 2, + pbuffer + 1); + *(pbuffer + 3) = + pdata->gph__dss_config__manual_block_select; + *(pbuffer + 4) = + pdata->gph__dss_config__max_spads_limit; + *(pbuffer + 5) = + pdata->gph__dss_config__min_spads_limit; + LOG_FUNCTION_END(status); + + + return status; +} + + +VL53L1_Error VL53L1_i2c_decode_gph_static_config( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_gph_static_config_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_GPH_STATIC_CONFIG_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + pdata->gph__dss_config__roi_mode_control = + (*(pbuffer + 0)) & 0x7; + pdata->gph__dss_config__manual_effective_spads_select = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 1)); + pdata->gph__dss_config__manual_block_select = + (*(pbuffer + 3)); + pdata->gph__dss_config__max_spads_limit = + (*(pbuffer + 4)); + pdata->gph__dss_config__min_spads_limit = + (*(pbuffer + 5)); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_gph_static_config( + VL53L1_DEV Dev, + VL53L1_gph_static_config_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_GPH_STATIC_CONFIG_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_i2c_encode_gph_static_config( + pdata, + VL53L1_GPH_STATIC_CONFIG_I2C_SIZE_BYTES, + comms_buffer); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_disable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WriteMulti( + Dev, + VL53L1_GPH__DSS_CONFIG__ROI_MODE_CONTROL, + comms_buffer, + VL53L1_GPH_STATIC_CONFIG_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_firmware(Dev); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_gph_static_config( + VL53L1_DEV Dev, + VL53L1_gph_static_config_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_GPH_STATIC_CONFIG_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_disable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_ReadMulti( + Dev, + VL53L1_GPH__DSS_CONFIG__ROI_MODE_CONTROL, + comms_buffer, + VL53L1_GPH_STATIC_CONFIG_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_i2c_decode_gph_static_config( + VL53L1_GPH_STATIC_CONFIG_I2C_SIZE_BYTES, + comms_buffer, + pdata); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_i2c_encode_gph_timing_config( + VL53L1_gph_timing_config_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_GPH_TIMING_CONFIG_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + *(pbuffer + 0) = + pdata->gph__mm_config__timeout_macrop_a_hi & 0xF; + *(pbuffer + 1) = + pdata->gph__mm_config__timeout_macrop_a_lo; + *(pbuffer + 2) = + pdata->gph__mm_config__timeout_macrop_b_hi & 0xF; + *(pbuffer + 3) = + pdata->gph__mm_config__timeout_macrop_b_lo; + *(pbuffer + 4) = + pdata->gph__range_config__timeout_macrop_a_hi & 0xF; + *(pbuffer + 5) = + pdata->gph__range_config__timeout_macrop_a_lo; + *(pbuffer + 6) = + pdata->gph__range_config__vcsel_period_a & 0x3F; + *(pbuffer + 7) = + pdata->gph__range_config__vcsel_period_b & 0x3F; + *(pbuffer + 8) = + pdata->gph__range_config__timeout_macrop_b_hi & 0xF; + *(pbuffer + 9) = + pdata->gph__range_config__timeout_macrop_b_lo; + VL53L1_i2c_encode_uint16_t( + pdata->gph__range_config__sigma_thresh, + 2, + pbuffer + 10); + VL53L1_i2c_encode_uint16_t( + pdata->gph__range_config__min_count_rate_rtn_limit_mcps, + 2, + pbuffer + 12); + *(pbuffer + 14) = + pdata->gph__range_config__valid_phase_low; + *(pbuffer + 15) = + pdata->gph__range_config__valid_phase_high; + LOG_FUNCTION_END(status); + + + return status; +} + + +VL53L1_Error VL53L1_i2c_decode_gph_timing_config( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_gph_timing_config_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_GPH_TIMING_CONFIG_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + pdata->gph__mm_config__timeout_macrop_a_hi = + (*(pbuffer + 0)) & 0xF; + pdata->gph__mm_config__timeout_macrop_a_lo = + (*(pbuffer + 1)); + pdata->gph__mm_config__timeout_macrop_b_hi = + (*(pbuffer + 2)) & 0xF; + pdata->gph__mm_config__timeout_macrop_b_lo = + (*(pbuffer + 3)); + pdata->gph__range_config__timeout_macrop_a_hi = + (*(pbuffer + 4)) & 0xF; + pdata->gph__range_config__timeout_macrop_a_lo = + (*(pbuffer + 5)); + pdata->gph__range_config__vcsel_period_a = + (*(pbuffer + 6)) & 0x3F; + pdata->gph__range_config__vcsel_period_b = + (*(pbuffer + 7)) & 0x3F; + pdata->gph__range_config__timeout_macrop_b_hi = + (*(pbuffer + 8)) & 0xF; + pdata->gph__range_config__timeout_macrop_b_lo = + (*(pbuffer + 9)); + pdata->gph__range_config__sigma_thresh = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 10)); + pdata->gph__range_config__min_count_rate_rtn_limit_mcps = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 12)); + pdata->gph__range_config__valid_phase_low = + (*(pbuffer + 14)); + pdata->gph__range_config__valid_phase_high = + (*(pbuffer + 15)); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_gph_timing_config( + VL53L1_DEV Dev, + VL53L1_gph_timing_config_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_GPH_TIMING_CONFIG_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_i2c_encode_gph_timing_config( + pdata, + VL53L1_GPH_TIMING_CONFIG_I2C_SIZE_BYTES, + comms_buffer); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_disable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WriteMulti( + Dev, + VL53L1_GPH__MM_CONFIG__TIMEOUT_MACROP_A_HI, + comms_buffer, + VL53L1_GPH_TIMING_CONFIG_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_firmware(Dev); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_gph_timing_config( + VL53L1_DEV Dev, + VL53L1_gph_timing_config_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_GPH_TIMING_CONFIG_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_disable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_ReadMulti( + Dev, + VL53L1_GPH__MM_CONFIG__TIMEOUT_MACROP_A_HI, + comms_buffer, + VL53L1_GPH_TIMING_CONFIG_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_i2c_decode_gph_timing_config( + VL53L1_GPH_TIMING_CONFIG_I2C_SIZE_BYTES, + comms_buffer, + pdata); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_i2c_encode_fw_internal( + VL53L1_fw_internal_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_FW_INTERNAL_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + *(pbuffer + 0) = + pdata->firmware__internal_stream_count_div; + *(pbuffer + 1) = + pdata->firmware__internal_stream_counter_val; + LOG_FUNCTION_END(status); + + + return status; +} + + +VL53L1_Error VL53L1_i2c_decode_fw_internal( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_fw_internal_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_FW_INTERNAL_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + pdata->firmware__internal_stream_count_div = + (*(pbuffer + 0)); + pdata->firmware__internal_stream_counter_val = + (*(pbuffer + 1)); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_fw_internal( + VL53L1_DEV Dev, + VL53L1_fw_internal_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_FW_INTERNAL_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_i2c_encode_fw_internal( + pdata, + VL53L1_FW_INTERNAL_I2C_SIZE_BYTES, + comms_buffer); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_disable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WriteMulti( + Dev, + VL53L1_FIRMWARE__INTERNAL_STREAM_COUNT_DIV, + comms_buffer, + VL53L1_FW_INTERNAL_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_firmware(Dev); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_fw_internal( + VL53L1_DEV Dev, + VL53L1_fw_internal_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_FW_INTERNAL_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_disable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_ReadMulti( + Dev, + VL53L1_FIRMWARE__INTERNAL_STREAM_COUNT_DIV, + comms_buffer, + VL53L1_FW_INTERNAL_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_i2c_decode_fw_internal( + VL53L1_FW_INTERNAL_I2C_SIZE_BYTES, + comms_buffer, + pdata); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_i2c_encode_patch_results( + VL53L1_patch_results_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_PATCH_RESULTS_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + *(pbuffer + 0) = + pdata->dss_calc__roi_ctrl & 0x3; + *(pbuffer + 1) = + pdata->dss_calc__spare_1; + *(pbuffer + 2) = + pdata->dss_calc__spare_2; + *(pbuffer + 3) = + pdata->dss_calc__spare_3; + *(pbuffer + 4) = + pdata->dss_calc__spare_4; + *(pbuffer + 5) = + pdata->dss_calc__spare_5; + *(pbuffer + 6) = + pdata->dss_calc__spare_6; + *(pbuffer + 7) = + pdata->dss_calc__spare_7; + *(pbuffer + 8) = + pdata->dss_calc__user_roi_spad_en_0; + *(pbuffer + 9) = + pdata->dss_calc__user_roi_spad_en_1; + *(pbuffer + 10) = + pdata->dss_calc__user_roi_spad_en_2; + *(pbuffer + 11) = + pdata->dss_calc__user_roi_spad_en_3; + *(pbuffer + 12) = + pdata->dss_calc__user_roi_spad_en_4; + *(pbuffer + 13) = + pdata->dss_calc__user_roi_spad_en_5; + *(pbuffer + 14) = + pdata->dss_calc__user_roi_spad_en_6; + *(pbuffer + 15) = + pdata->dss_calc__user_roi_spad_en_7; + *(pbuffer + 16) = + pdata->dss_calc__user_roi_spad_en_8; + *(pbuffer + 17) = + pdata->dss_calc__user_roi_spad_en_9; + *(pbuffer + 18) = + pdata->dss_calc__user_roi_spad_en_10; + *(pbuffer + 19) = + pdata->dss_calc__user_roi_spad_en_11; + *(pbuffer + 20) = + pdata->dss_calc__user_roi_spad_en_12; + *(pbuffer + 21) = + pdata->dss_calc__user_roi_spad_en_13; + *(pbuffer + 22) = + pdata->dss_calc__user_roi_spad_en_14; + *(pbuffer + 23) = + pdata->dss_calc__user_roi_spad_en_15; + *(pbuffer + 24) = + pdata->dss_calc__user_roi_spad_en_16; + *(pbuffer + 25) = + pdata->dss_calc__user_roi_spad_en_17; + *(pbuffer + 26) = + pdata->dss_calc__user_roi_spad_en_18; + *(pbuffer + 27) = + pdata->dss_calc__user_roi_spad_en_19; + *(pbuffer + 28) = + pdata->dss_calc__user_roi_spad_en_20; + *(pbuffer + 29) = + pdata->dss_calc__user_roi_spad_en_21; + *(pbuffer + 30) = + pdata->dss_calc__user_roi_spad_en_22; + *(pbuffer + 31) = + pdata->dss_calc__user_roi_spad_en_23; + *(pbuffer + 32) = + pdata->dss_calc__user_roi_spad_en_24; + *(pbuffer + 33) = + pdata->dss_calc__user_roi_spad_en_25; + *(pbuffer + 34) = + pdata->dss_calc__user_roi_spad_en_26; + *(pbuffer + 35) = + pdata->dss_calc__user_roi_spad_en_27; + *(pbuffer + 36) = + pdata->dss_calc__user_roi_spad_en_28; + *(pbuffer + 37) = + pdata->dss_calc__user_roi_spad_en_29; + *(pbuffer + 38) = + pdata->dss_calc__user_roi_spad_en_30; + *(pbuffer + 39) = + pdata->dss_calc__user_roi_spad_en_31; + *(pbuffer + 40) = + pdata->dss_calc__user_roi_0; + *(pbuffer + 41) = + pdata->dss_calc__user_roi_1; + *(pbuffer + 42) = + pdata->dss_calc__mode_roi_0; + *(pbuffer + 43) = + pdata->dss_calc__mode_roi_1; + *(pbuffer + 44) = + pdata->sigma_estimator_calc__spare_0; + VL53L1_i2c_encode_uint16_t( + pdata->vhv_result__peak_signal_rate_mcps, + 2, + pbuffer + 46); + VL53L1_i2c_encode_uint32_t( + pdata->vhv_result__signal_total_events_ref, + 4, + pbuffer + 48); + VL53L1_i2c_encode_uint16_t( + pdata->phasecal_result__phase_output_ref, + 2, + pbuffer + 52); + VL53L1_i2c_encode_uint16_t( + pdata->dss_result__total_rate_per_spad, + 2, + pbuffer + 54); + *(pbuffer + 56) = + pdata->dss_result__enabled_blocks; + VL53L1_i2c_encode_uint16_t( + pdata->dss_result__num_requested_spads, + 2, + pbuffer + 58); + VL53L1_i2c_encode_uint16_t( + pdata->mm_result__inner_intersection_rate, + 2, + pbuffer + 62); + VL53L1_i2c_encode_uint16_t( + pdata->mm_result__outer_complement_rate, + 2, + pbuffer + 64); + VL53L1_i2c_encode_uint16_t( + pdata->mm_result__total_offset, + 2, + pbuffer + 66); + VL53L1_i2c_encode_uint32_t( + pdata->xtalk_calc__xtalk_for_enabled_spads & 0xFFFFFF, + 4, + pbuffer + 68); + VL53L1_i2c_encode_uint32_t( + pdata->xtalk_result__avg_xtalk_user_roi_kcps & 0xFFFFFF, + 4, + pbuffer + 72); + VL53L1_i2c_encode_uint32_t( + pdata->xtalk_result__avg_xtalk_mm_inner_roi_kcps & 0xFFFFFF, + 4, + pbuffer + 76); + VL53L1_i2c_encode_uint32_t( + pdata->xtalk_result__avg_xtalk_mm_outer_roi_kcps & 0xFFFFFF, + 4, + pbuffer + 80); + VL53L1_i2c_encode_uint32_t( + pdata->range_result__accum_phase, + 4, + pbuffer + 84); + VL53L1_i2c_encode_uint16_t( + pdata->range_result__offset_corrected_range, + 2, + pbuffer + 88); + LOG_FUNCTION_END(status); + + + return status; +} + + +VL53L1_Error VL53L1_i2c_decode_patch_results( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_patch_results_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_PATCH_RESULTS_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + pdata->dss_calc__roi_ctrl = + (*(pbuffer + 0)) & 0x3; + pdata->dss_calc__spare_1 = + (*(pbuffer + 1)); + pdata->dss_calc__spare_2 = + (*(pbuffer + 2)); + pdata->dss_calc__spare_3 = + (*(pbuffer + 3)); + pdata->dss_calc__spare_4 = + (*(pbuffer + 4)); + pdata->dss_calc__spare_5 = + (*(pbuffer + 5)); + pdata->dss_calc__spare_6 = + (*(pbuffer + 6)); + pdata->dss_calc__spare_7 = + (*(pbuffer + 7)); + pdata->dss_calc__user_roi_spad_en_0 = + (*(pbuffer + 8)); + pdata->dss_calc__user_roi_spad_en_1 = + (*(pbuffer + 9)); + pdata->dss_calc__user_roi_spad_en_2 = + (*(pbuffer + 10)); + pdata->dss_calc__user_roi_spad_en_3 = + (*(pbuffer + 11)); + pdata->dss_calc__user_roi_spad_en_4 = + (*(pbuffer + 12)); + pdata->dss_calc__user_roi_spad_en_5 = + (*(pbuffer + 13)); + pdata->dss_calc__user_roi_spad_en_6 = + (*(pbuffer + 14)); + pdata->dss_calc__user_roi_spad_en_7 = + (*(pbuffer + 15)); + pdata->dss_calc__user_roi_spad_en_8 = + (*(pbuffer + 16)); + pdata->dss_calc__user_roi_spad_en_9 = + (*(pbuffer + 17)); + pdata->dss_calc__user_roi_spad_en_10 = + (*(pbuffer + 18)); + pdata->dss_calc__user_roi_spad_en_11 = + (*(pbuffer + 19)); + pdata->dss_calc__user_roi_spad_en_12 = + (*(pbuffer + 20)); + pdata->dss_calc__user_roi_spad_en_13 = + (*(pbuffer + 21)); + pdata->dss_calc__user_roi_spad_en_14 = + (*(pbuffer + 22)); + pdata->dss_calc__user_roi_spad_en_15 = + (*(pbuffer + 23)); + pdata->dss_calc__user_roi_spad_en_16 = + (*(pbuffer + 24)); + pdata->dss_calc__user_roi_spad_en_17 = + (*(pbuffer + 25)); + pdata->dss_calc__user_roi_spad_en_18 = + (*(pbuffer + 26)); + pdata->dss_calc__user_roi_spad_en_19 = + (*(pbuffer + 27)); + pdata->dss_calc__user_roi_spad_en_20 = + (*(pbuffer + 28)); + pdata->dss_calc__user_roi_spad_en_21 = + (*(pbuffer + 29)); + pdata->dss_calc__user_roi_spad_en_22 = + (*(pbuffer + 30)); + pdata->dss_calc__user_roi_spad_en_23 = + (*(pbuffer + 31)); + pdata->dss_calc__user_roi_spad_en_24 = + (*(pbuffer + 32)); + pdata->dss_calc__user_roi_spad_en_25 = + (*(pbuffer + 33)); + pdata->dss_calc__user_roi_spad_en_26 = + (*(pbuffer + 34)); + pdata->dss_calc__user_roi_spad_en_27 = + (*(pbuffer + 35)); + pdata->dss_calc__user_roi_spad_en_28 = + (*(pbuffer + 36)); + pdata->dss_calc__user_roi_spad_en_29 = + (*(pbuffer + 37)); + pdata->dss_calc__user_roi_spad_en_30 = + (*(pbuffer + 38)); + pdata->dss_calc__user_roi_spad_en_31 = + (*(pbuffer + 39)); + pdata->dss_calc__user_roi_0 = + (*(pbuffer + 40)); + pdata->dss_calc__user_roi_1 = + (*(pbuffer + 41)); + pdata->dss_calc__mode_roi_0 = + (*(pbuffer + 42)); + pdata->dss_calc__mode_roi_1 = + (*(pbuffer + 43)); + pdata->sigma_estimator_calc__spare_0 = + (*(pbuffer + 44)); + pdata->vhv_result__peak_signal_rate_mcps = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 46)); + pdata->vhv_result__signal_total_events_ref = + (VL53L1_i2c_decode_uint32_t(4, pbuffer + 48)); + pdata->phasecal_result__phase_output_ref = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 52)); + pdata->dss_result__total_rate_per_spad = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 54)); + pdata->dss_result__enabled_blocks = + (*(pbuffer + 56)); + pdata->dss_result__num_requested_spads = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 58)); + pdata->mm_result__inner_intersection_rate = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 62)); + pdata->mm_result__outer_complement_rate = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 64)); + pdata->mm_result__total_offset = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 66)); + pdata->xtalk_calc__xtalk_for_enabled_spads = + (VL53L1_i2c_decode_uint32_t(4, pbuffer + 68)) & 0xFFFFFF; + pdata->xtalk_result__avg_xtalk_user_roi_kcps = + (VL53L1_i2c_decode_uint32_t(4, pbuffer + 72)) & 0xFFFFFF; + pdata->xtalk_result__avg_xtalk_mm_inner_roi_kcps = + (VL53L1_i2c_decode_uint32_t(4, pbuffer + 76)) & 0xFFFFFF; + pdata->xtalk_result__avg_xtalk_mm_outer_roi_kcps = + (VL53L1_i2c_decode_uint32_t(4, pbuffer + 80)) & 0xFFFFFF; + pdata->range_result__accum_phase = + (VL53L1_i2c_decode_uint32_t(4, pbuffer + 84)); + pdata->range_result__offset_corrected_range = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 88)); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_patch_results( + VL53L1_DEV Dev, + VL53L1_patch_results_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_PATCH_RESULTS_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_i2c_encode_patch_results( + pdata, + VL53L1_PATCH_RESULTS_I2C_SIZE_BYTES, + comms_buffer); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_disable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WriteMulti( + Dev, + VL53L1_DSS_CALC__ROI_CTRL, + comms_buffer, + VL53L1_PATCH_RESULTS_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_firmware(Dev); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_patch_results( + VL53L1_DEV Dev, + VL53L1_patch_results_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_PATCH_RESULTS_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_disable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_ReadMulti( + Dev, + VL53L1_DSS_CALC__ROI_CTRL, + comms_buffer, + VL53L1_PATCH_RESULTS_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_i2c_decode_patch_results( + VL53L1_PATCH_RESULTS_I2C_SIZE_BYTES, + comms_buffer, + pdata); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_i2c_encode_shadow_system_results( + VL53L1_shadow_system_results_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_SHADOW_SYSTEM_RESULTS_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + *(pbuffer + 0) = + pdata->shadow_phasecal_result__vcsel_start; + *(pbuffer + 2) = + pdata->shadow_result__interrupt_status & 0x3F; + *(pbuffer + 3) = + pdata->shadow_result__range_status; + *(pbuffer + 4) = + pdata->shadow_result__report_status & 0xF; + *(pbuffer + 5) = + pdata->shadow_result__stream_count; + VL53L1_i2c_encode_uint16_t( + pdata->shadow_result__dss_actual_effective_spads_sd0, + 2, + pbuffer + 6); + VL53L1_i2c_encode_uint16_t( + pdata->shadow_result__peak_signal_count_rate_mcps_sd0, + 2, + pbuffer + 8); + VL53L1_i2c_encode_uint16_t( + pdata->shadow_result__ambient_count_rate_mcps_sd0, + 2, + pbuffer + 10); + VL53L1_i2c_encode_uint16_t( + pdata->shadow_result__sigma_sd0, + 2, + pbuffer + 12); + VL53L1_i2c_encode_uint16_t( + pdata->shadow_result__phase_sd0, + 2, + pbuffer + 14); + VL53L1_i2c_encode_uint16_t( + pdata->shadow_result__final_crosstalk_corrected_range_mm_sd0, + 2, + pbuffer + 16); + VL53L1_i2c_encode_uint16_t( + pdata->shr__peak_signal_count_rate_crosstalk_corrected_mcps_sd0, + 2, + pbuffer + 18); + VL53L1_i2c_encode_uint16_t( + pdata->shadow_result__mm_inner_actual_effective_spads_sd0, + 2, + pbuffer + 20); + VL53L1_i2c_encode_uint16_t( + pdata->shadow_result__mm_outer_actual_effective_spads_sd0, + 2, + pbuffer + 22); + VL53L1_i2c_encode_uint16_t( + pdata->shadow_result__avg_signal_count_rate_mcps_sd0, + 2, + pbuffer + 24); + VL53L1_i2c_encode_uint16_t( + pdata->shadow_result__dss_actual_effective_spads_sd1, + 2, + pbuffer + 26); + VL53L1_i2c_encode_uint16_t( + pdata->shadow_result__peak_signal_count_rate_mcps_sd1, + 2, + pbuffer + 28); + VL53L1_i2c_encode_uint16_t( + pdata->shadow_result__ambient_count_rate_mcps_sd1, + 2, + pbuffer + 30); + VL53L1_i2c_encode_uint16_t( + pdata->shadow_result__sigma_sd1, + 2, + pbuffer + 32); + VL53L1_i2c_encode_uint16_t( + pdata->shadow_result__phase_sd1, + 2, + pbuffer + 34); + VL53L1_i2c_encode_uint16_t( + pdata->shadow_result__final_crosstalk_corrected_range_mm_sd1, + 2, + pbuffer + 36); + VL53L1_i2c_encode_uint16_t( + pdata->shadow_result__spare_0_sd1, + 2, + pbuffer + 38); + VL53L1_i2c_encode_uint16_t( + pdata->shadow_result__spare_1_sd1, + 2, + pbuffer + 40); + VL53L1_i2c_encode_uint16_t( + pdata->shadow_result__spare_2_sd1, + 2, + pbuffer + 42); + *(pbuffer + 44) = + pdata->shadow_result__spare_3_sd1; + *(pbuffer + 45) = + pdata->shadow_result__thresh_info; + *(pbuffer + 80) = + pdata->shadow_phasecal_result__reference_phase_hi; + *(pbuffer + 81) = + pdata->shadow_phasecal_result__reference_phase_lo; + LOG_FUNCTION_END(status); + + + return status; +} + + +VL53L1_Error VL53L1_i2c_decode_shadow_system_results( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_shadow_system_results_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_SHADOW_SYSTEM_RESULTS_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + pdata->shadow_phasecal_result__vcsel_start = + (*(pbuffer + 0)); + pdata->shadow_result__interrupt_status = + (*(pbuffer + 2)) & 0x3F; + pdata->shadow_result__range_status = + (*(pbuffer + 3)); + pdata->shadow_result__report_status = + (*(pbuffer + 4)) & 0xF; + pdata->shadow_result__stream_count = + (*(pbuffer + 5)); + pdata->shadow_result__dss_actual_effective_spads_sd0 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 6)); + pdata->shadow_result__peak_signal_count_rate_mcps_sd0 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 8)); + pdata->shadow_result__ambient_count_rate_mcps_sd0 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 10)); + pdata->shadow_result__sigma_sd0 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 12)); + pdata->shadow_result__phase_sd0 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 14)); + pdata->shadow_result__final_crosstalk_corrected_range_mm_sd0 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 16)); + pdata->shr__peak_signal_count_rate_crosstalk_corrected_mcps_sd0 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 18)); + pdata->shadow_result__mm_inner_actual_effective_spads_sd0 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 20)); + pdata->shadow_result__mm_outer_actual_effective_spads_sd0 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 22)); + pdata->shadow_result__avg_signal_count_rate_mcps_sd0 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 24)); + pdata->shadow_result__dss_actual_effective_spads_sd1 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 26)); + pdata->shadow_result__peak_signal_count_rate_mcps_sd1 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 28)); + pdata->shadow_result__ambient_count_rate_mcps_sd1 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 30)); + pdata->shadow_result__sigma_sd1 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 32)); + pdata->shadow_result__phase_sd1 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 34)); + pdata->shadow_result__final_crosstalk_corrected_range_mm_sd1 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 36)); + pdata->shadow_result__spare_0_sd1 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 38)); + pdata->shadow_result__spare_1_sd1 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 40)); + pdata->shadow_result__spare_2_sd1 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 42)); + pdata->shadow_result__spare_3_sd1 = + (*(pbuffer + 44)); + pdata->shadow_result__thresh_info = + (*(pbuffer + 45)); + pdata->shadow_phasecal_result__reference_phase_hi = + (*(pbuffer + 80)); + pdata->shadow_phasecal_result__reference_phase_lo = + (*(pbuffer + 81)); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_shadow_system_results( + VL53L1_DEV Dev, + VL53L1_shadow_system_results_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_SHADOW_SYSTEM_RESULTS_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_i2c_encode_shadow_system_results( + pdata, + VL53L1_SHADOW_SYSTEM_RESULTS_I2C_SIZE_BYTES, + comms_buffer); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_disable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WriteMulti( + Dev, + VL53L1_SHADOW_PHASECAL_RESULT__VCSEL_START, + comms_buffer, + VL53L1_SHADOW_SYSTEM_RESULTS_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_firmware(Dev); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_shadow_system_results( + VL53L1_DEV Dev, + VL53L1_shadow_system_results_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_SHADOW_SYSTEM_RESULTS_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_disable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_ReadMulti( + Dev, + VL53L1_SHADOW_PHASECAL_RESULT__VCSEL_START, + comms_buffer, + VL53L1_SHADOW_SYSTEM_RESULTS_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_i2c_decode_shadow_system_results( + VL53L1_SHADOW_SYSTEM_RESULTS_I2C_SIZE_BYTES, + comms_buffer, + pdata); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_i2c_encode_shadow_core_results( + VL53L1_shadow_core_results_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_SHADOW_CORE_RESULTS_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + VL53L1_i2c_encode_uint32_t( + pdata->shadow_result_core__ambient_window_events_sd0, + 4, + pbuffer + 0); + VL53L1_i2c_encode_uint32_t( + pdata->shadow_result_core__ranging_total_events_sd0, + 4, + pbuffer + 4); + VL53L1_i2c_encode_int32_t( + pdata->shadow_result_core__signal_total_events_sd0, + 4, + pbuffer + 8); + VL53L1_i2c_encode_uint32_t( + pdata->shadow_result_core__total_periods_elapsed_sd0, + 4, + pbuffer + 12); + VL53L1_i2c_encode_uint32_t( + pdata->shadow_result_core__ambient_window_events_sd1, + 4, + pbuffer + 16); + VL53L1_i2c_encode_uint32_t( + pdata->shadow_result_core__ranging_total_events_sd1, + 4, + pbuffer + 20); + VL53L1_i2c_encode_int32_t( + pdata->shadow_result_core__signal_total_events_sd1, + 4, + pbuffer + 24); + VL53L1_i2c_encode_uint32_t( + pdata->shadow_result_core__total_periods_elapsed_sd1, + 4, + pbuffer + 28); + *(pbuffer + 32) = + pdata->shadow_result_core__spare_0; + LOG_FUNCTION_END(status); + + + return status; +} + + +VL53L1_Error VL53L1_i2c_decode_shadow_core_results( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_shadow_core_results_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_SHADOW_CORE_RESULTS_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + pdata->shadow_result_core__ambient_window_events_sd0 = + (VL53L1_i2c_decode_uint32_t(4, pbuffer + 0)); + pdata->shadow_result_core__ranging_total_events_sd0 = + (VL53L1_i2c_decode_uint32_t(4, pbuffer + 4)); + pdata->shadow_result_core__signal_total_events_sd0 = + (VL53L1_i2c_decode_int32_t(4, pbuffer + 8)); + pdata->shadow_result_core__total_periods_elapsed_sd0 = + (VL53L1_i2c_decode_uint32_t(4, pbuffer + 12)); + pdata->shadow_result_core__ambient_window_events_sd1 = + (VL53L1_i2c_decode_uint32_t(4, pbuffer + 16)); + pdata->shadow_result_core__ranging_total_events_sd1 = + (VL53L1_i2c_decode_uint32_t(4, pbuffer + 20)); + pdata->shadow_result_core__signal_total_events_sd1 = + (VL53L1_i2c_decode_int32_t(4, pbuffer + 24)); + pdata->shadow_result_core__total_periods_elapsed_sd1 = + (VL53L1_i2c_decode_uint32_t(4, pbuffer + 28)); + pdata->shadow_result_core__spare_0 = + (*(pbuffer + 32)); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_shadow_core_results( + VL53L1_DEV Dev, + VL53L1_shadow_core_results_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_SHADOW_CORE_RESULTS_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_i2c_encode_shadow_core_results( + pdata, + VL53L1_SHADOW_CORE_RESULTS_I2C_SIZE_BYTES, + comms_buffer); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_disable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WriteMulti( + Dev, + VL53L1_SHADOW_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD0, + comms_buffer, + VL53L1_SHADOW_CORE_RESULTS_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_firmware(Dev); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_shadow_core_results( + VL53L1_DEV Dev, + VL53L1_shadow_core_results_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_SHADOW_CORE_RESULTS_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_disable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_ReadMulti( + Dev, + VL53L1_SHADOW_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD0, + comms_buffer, + VL53L1_SHADOW_CORE_RESULTS_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_i2c_decode_shadow_core_results( + VL53L1_SHADOW_CORE_RESULTS_I2C_SIZE_BYTES, + comms_buffer, + pdata); + + LOG_FUNCTION_END(status); + + return status; +} + + diff --git a/drivers/input/misc/vl53L1/kona/src/vl53l1_silicon_core.c b/drivers/input/misc/vl53L1/kona/src/vl53l1_silicon_core.c new file mode 100644 index 000000000000..14387ec03a04 --- /dev/null +++ b/drivers/input/misc/vl53L1/kona/src/vl53l1_silicon_core.c @@ -0,0 +1,187 @@ + +/******************************************************************************* + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#include "vl53l1_ll_def.h" +#include "vl53l1_platform.h" +#include "vl53l1_register_map.h" +#include "vl53l1_core.h" +#include "vl53l1_silicon_core.h" + + +#define LOG_FUNCTION_START(fmt, ...) \ + _LOG_FUNCTION_START(VL53L1_TRACE_MODULE_CORE, fmt, ##__VA_ARGS__) +#define LOG_FUNCTION_END(status, ...) \ + _LOG_FUNCTION_END(VL53L1_TRACE_MODULE_CORE, status, ##__VA_ARGS__) +#define LOG_FUNCTION_END_FMT(status, fmt, ...) \ + _LOG_FUNCTION_END_FMT(VL53L1_TRACE_MODULE_CORE,\ + status, fmt, ##__VA_ARGS__) + + +VL53L1_Error VL53L1_is_firmware_ready_silicon( + VL53L1_DEV Dev, + uint8_t *pready) +{ + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + uint8_t comms_buffer[5]; + + LOG_FUNCTION_START(""); + + + + + status = VL53L1_ReadMulti( + Dev, + VL53L1_INTERRUPT_MANAGER__ENABLES, + comms_buffer, + 5); + + if (status != VL53L1_ERROR_NONE) + goto ENDFUNC; + + pdev->dbg_results.interrupt_manager__enables = + comms_buffer[0]; + pdev->dbg_results.interrupt_manager__clear = + comms_buffer[1]; + pdev->dbg_results.interrupt_manager__status = + comms_buffer[2]; + pdev->dbg_results.mcu_to_host_bank__wr_access_en = + comms_buffer[3]; + pdev->dbg_results.power_management__go1_reset_status = + comms_buffer[4]; + + if ((pdev->sys_ctrl.power_management__go1_power_force & 0x01) + == 0x01) { + + if (((pdev->dbg_results.interrupt_manager__enables & + 0x1F) == 0x1F) && + ((pdev->dbg_results.interrupt_manager__clear + & 0x1F) == 0x1F)) + *pready = 0x01; + else + *pready = 0x00; + + } else { + + + + if ((pdev->dbg_results.power_management__go1_reset_status + & 0x01) == 0x00) + *pready = 0x01; + else + *pready = 0x00; + } + + +ENDFUNC: + LOG_FUNCTION_END(status); + + return status; +} + diff --git a/drivers/input/misc/vl53L1/kona/src/vl53l1_wait.c b/drivers/input/misc/vl53L1/kona/src/vl53l1_wait.c new file mode 100644 index 000000000000..7ae89b9219eb --- /dev/null +++ b/drivers/input/misc/vl53L1/kona/src/vl53l1_wait.c @@ -0,0 +1,621 @@ + +/******************************************************************************* + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#include "vl53l1_ll_def.h" +#include "vl53l1_ll_device.h" +#include "vl53l1_platform.h" +#include "vl53l1_core.h" +#include "vl53l1_silicon_core.h" +#include "vl53l1_wait.h" +#include "vl53l1_register_settings.h" + + +#define LOG_FUNCTION_START(fmt, ...) \ + _LOG_FUNCTION_START(VL53L1_TRACE_MODULE_CORE, fmt, ##__VA_ARGS__) +#define LOG_FUNCTION_END(status, ...) \ + _LOG_FUNCTION_END(VL53L1_TRACE_MODULE_CORE, status, ##__VA_ARGS__) +#define LOG_FUNCTION_END_FMT(status, fmt, ...) \ + _LOG_FUNCTION_END_FMT(VL53L1_TRACE_MODULE_CORE, status, \ + fmt, ##__VA_ARGS__) + + +VL53L1_Error VL53L1_wait_for_boot_completion( + VL53L1_DEV Dev) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + uint8_t fw_ready = 0; + + LOG_FUNCTION_START(""); + + if (pdev->wait_method == VL53L1_WAIT_METHOD_BLOCKING) { + + + + + status = + VL53L1_poll_for_boot_completion( + Dev, + VL53L1_BOOT_COMPLETION_POLLING_TIMEOUT_MS); + + } else { + + + + + fw_ready = 0; + while (fw_ready == 0x00 && status == VL53L1_ERROR_NONE) { + status = VL53L1_is_boot_complete( + Dev, + &fw_ready); + + if (status == VL53L1_ERROR_NONE) { + status = VL53L1_WaitMs( + Dev, + VL53L1_POLLING_DELAY_MS); + } + } + } + + LOG_FUNCTION_END(status); + + return status; + +} + + +VL53L1_Error VL53L1_wait_for_firmware_ready( + VL53L1_DEV Dev) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + uint8_t fw_ready = 0; + uint8_t mode_start = 0; + + LOG_FUNCTION_START(""); + + + + + + mode_start = + pdev->sys_ctrl.system__mode_start & + VL53L1_DEVICEMEASUREMENTMODE_MODE_MASK; + + + + + + + + if ((mode_start == VL53L1_DEVICEMEASUREMENTMODE_TIMED) || + (mode_start == VL53L1_DEVICEMEASUREMENTMODE_SINGLESHOT)) { + + if (pdev->wait_method == VL53L1_WAIT_METHOD_BLOCKING) { + + + + + status = + VL53L1_poll_for_firmware_ready( + Dev, + VL53L1_RANGE_COMPLETION_POLLING_TIMEOUT_MS); + + } else { + + + + + fw_ready = 0; + while (fw_ready == 0x00 && status == + VL53L1_ERROR_NONE) { + status = VL53L1_is_firmware_ready( + Dev, + &fw_ready); + + if (status == VL53L1_ERROR_NONE) { + status = VL53L1_WaitMs( + Dev, + VL53L1_POLLING_DELAY_MS); + } + } + } + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_wait_for_range_completion( + VL53L1_DEV Dev) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + uint8_t data_ready = 0; + + LOG_FUNCTION_START(""); + + if (pdev->wait_method == VL53L1_WAIT_METHOD_BLOCKING) { + + + + + status = + VL53L1_poll_for_range_completion( + Dev, + VL53L1_RANGE_COMPLETION_POLLING_TIMEOUT_MS); + + } else { + + + + + data_ready = 0; + while (data_ready == 0x00 && status == VL53L1_ERROR_NONE) { + status = VL53L1_is_new_data_ready( + Dev, + &data_ready); + + if (status == VL53L1_ERROR_NONE) { + status = VL53L1_WaitMs( + Dev, + VL53L1_POLLING_DELAY_MS); + } + } + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_wait_for_test_completion( + VL53L1_DEV Dev) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + uint8_t data_ready = 0; + + LOG_FUNCTION_START(""); + + if (pdev->wait_method == VL53L1_WAIT_METHOD_BLOCKING) { + + + + + status = + VL53L1_poll_for_range_completion( + Dev, + VL53L1_TEST_COMPLETION_POLLING_TIMEOUT_MS); + + } else { + + + + + data_ready = 0; + while (data_ready == 0x00 && status == VL53L1_ERROR_NONE) { + status = VL53L1_is_new_data_ready( + Dev, + &data_ready); + + if (status == VL53L1_ERROR_NONE) { + status = VL53L1_WaitMs( + Dev, + VL53L1_POLLING_DELAY_MS); + } + } + } + + LOG_FUNCTION_END(status); + + return status; +} + + + + +VL53L1_Error VL53L1_is_boot_complete( + VL53L1_DEV Dev, + uint8_t *pready) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t firmware__system_status = 0; + + LOG_FUNCTION_START(""); + + + + + status = + VL53L1_RdByte( + Dev, + VL53L1_FIRMWARE__SYSTEM_STATUS, + &firmware__system_status); + + + + + + + if ((firmware__system_status & 0x01) == 0x01) { + *pready = 0x01; + VL53L1_init_ll_driver_state( + Dev, + VL53L1_DEVICESTATE_SW_STANDBY); + } else { + *pready = 0x00; + VL53L1_init_ll_driver_state( + Dev, + VL53L1_DEVICESTATE_FW_COLDBOOT); + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_is_firmware_ready( + VL53L1_DEV Dev, + uint8_t *pready) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + status = VL53L1_is_firmware_ready_silicon( + Dev, + pready); + + pdev->fw_ready = *pready; + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_is_new_data_ready( + VL53L1_DEV Dev, + uint8_t *pready) +{ + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + uint8_t gpio__mux_active_high_hv = 0; + uint8_t gpio__tio_hv_status = 0; + uint8_t interrupt_ready = 0; + + LOG_FUNCTION_START(""); + + gpio__mux_active_high_hv = + pdev->stat_cfg.gpio_hv_mux__ctrl & + VL53L1_DEVICEINTERRUPTLEVEL_ACTIVE_MASK; + + if (gpio__mux_active_high_hv == VL53L1_DEVICEINTERRUPTLEVEL_ACTIVE_HIGH) + interrupt_ready = 0x01; + else + interrupt_ready = 0x00; + + + + + status = VL53L1_RdByte( + Dev, + VL53L1_GPIO__TIO_HV_STATUS, + &gpio__tio_hv_status); + + + + + if ((gpio__tio_hv_status & 0x01) == interrupt_ready) + *pready = 0x01; + else + *pready = 0x00; + + LOG_FUNCTION_END(status); + + return status; +} + + + + +VL53L1_Error VL53L1_poll_for_boot_completion( + VL53L1_DEV Dev, + uint32_t timeout_ms) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + + + + + status = VL53L1_WaitUs( + Dev, + VL53L1_FIRMWARE_BOOT_TIME_US); + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_WaitValueMaskEx( + Dev, + timeout_ms, + VL53L1_FIRMWARE__SYSTEM_STATUS, + 0x01, + 0x01, + VL53L1_POLLING_DELAY_MS); + + if (status == VL53L1_ERROR_NONE) + VL53L1_init_ll_driver_state(Dev, VL53L1_DEVICESTATE_SW_STANDBY); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_poll_for_firmware_ready( + VL53L1_DEV Dev, + uint32_t timeout_ms) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + uint32_t start_time_ms = 0; + uint32_t current_time_ms = 0; + int32_t poll_delay_ms = VL53L1_POLLING_DELAY_MS; + uint8_t fw_ready = 0; + + + + + VL53L1_GetTickCount(&start_time_ms); + + pdev->fw_ready_poll_duration_ms = 0; + + + + + while ((status == VL53L1_ERROR_NONE) && + (pdev->fw_ready_poll_duration_ms < timeout_ms) && + (fw_ready == 0)) { + + status = VL53L1_is_firmware_ready( + Dev, + &fw_ready); + + if (status == VL53L1_ERROR_NONE && + fw_ready == 0 && + poll_delay_ms > 0) { + status = VL53L1_WaitMs( + Dev, + poll_delay_ms); + } + + + + + + + VL53L1_GetTickCount(¤t_time_ms); + + pdev->fw_ready_poll_duration_ms = + current_time_ms - start_time_ms; + } + + if (fw_ready == 0 && status == VL53L1_ERROR_NONE) + status = VL53L1_ERROR_TIME_OUT; + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_poll_for_range_completion( + VL53L1_DEV Dev, + uint32_t timeout_ms) +{ + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + uint8_t gpio__mux_active_high_hv = 0; + uint8_t interrupt_ready = 0; + + LOG_FUNCTION_START(""); + + gpio__mux_active_high_hv = + pdev->stat_cfg.gpio_hv_mux__ctrl & + VL53L1_DEVICEINTERRUPTLEVEL_ACTIVE_MASK; + + if (gpio__mux_active_high_hv == VL53L1_DEVICEINTERRUPTLEVEL_ACTIVE_HIGH) + interrupt_ready = 0x01; + else + interrupt_ready = 0x00; + + status = + VL53L1_WaitValueMaskEx( + Dev, + timeout_ms, + VL53L1_GPIO__TIO_HV_STATUS, + interrupt_ready, + 0x01, + VL53L1_POLLING_DELAY_MS); + + LOG_FUNCTION_END(status); + + return status; +} + + diff --git a/drivers/input/misc/vl53L1/kona/src/vl53l1_zone_presets.c b/drivers/input/misc/vl53L1/kona/src/vl53l1_zone_presets.c new file mode 100644 index 000000000000..98378cbff3ea --- /dev/null +++ b/drivers/input/misc/vl53L1/kona/src/vl53l1_zone_presets.c @@ -0,0 +1,253 @@ + +/******************************************************************************* + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#include "vl53l1_ll_def.h" +#include "vl53l1_ll_device.h" +#include "vl53l1_platform_log.h" +#include "vl53l1_zone_presets.h" + + +#define LOG_FUNCTION_START(fmt, ...) \ + _LOG_FUNCTION_START(VL53L1_TRACE_MODULE_CORE, fmt, ##__VA_ARGS__) +#define LOG_FUNCTION_END(status, ...) \ + _LOG_FUNCTION_END(VL53L1_TRACE_MODULE_CORE, status, ##__VA_ARGS__) +#define LOG_FUNCTION_END_FMT(status, fmt, ...) \ + _LOG_FUNCTION_END_FMT(VL53L1_TRACE_MODULE_CORE,\ + status, fmt, ##__VA_ARGS__) + + +VL53L1_Error VL53L1_init_zone_config_structure( + uint8_t x_off, + uint8_t x_inc, + uint8_t x_zones, + uint8_t y_off, + uint8_t y_inc, + uint8_t y_zones, + uint8_t width, + uint8_t height, + VL53L1_zone_config_t *pdata) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + uint8_t x = 0; + uint8_t y = 0; + uint16_t i = 0; + + LOG_FUNCTION_START(""); + + pdata->max_zones = VL53L1_MAX_USER_ZONES; + + i = 0; + + for (x = 0 ; x < x_zones ; x++) { + for (y = 0 ; y < y_zones ; y++) { + + if (i < VL53L1_MAX_USER_ZONES) { + + pdata->active_zones = (uint8_t)i; + pdata->user_zones[i].height = height; + pdata->user_zones[i].width = width; + pdata->user_zones[i].x_centre = + x_off + (x * x_inc); + pdata->user_zones[i].y_centre = + y_off + (y * y_inc); + } + + i++; + } + } + + status = VL53L1_init_zone_config_histogram_bins(pdata); + + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_zone_preset_xtalk_planar( + VL53L1_general_config_t *pgeneral, + VL53L1_zone_config_t *pzone_cfg) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + + + pgeneral->global_config__stream_divider = 0x05; + + + + pzone_cfg->active_zones = 0x04; + + pzone_cfg->user_zones[0].height = 15; + pzone_cfg->user_zones[0].width = 7; + pzone_cfg->user_zones[0].x_centre = 4; + pzone_cfg->user_zones[0].y_centre = 8; + + pzone_cfg->user_zones[1].height = 15; + pzone_cfg->user_zones[1].width = 7; + pzone_cfg->user_zones[1].x_centre = 12; + pzone_cfg->user_zones[1].y_centre = 8; + + pzone_cfg->user_zones[2].height = 7; + pzone_cfg->user_zones[2].width = 15; + pzone_cfg->user_zones[2].x_centre = 8; + pzone_cfg->user_zones[2].y_centre = 4; + + pzone_cfg->user_zones[3].height = 7; + pzone_cfg->user_zones[3].width = 15; + pzone_cfg->user_zones[3].x_centre = 8; + pzone_cfg->user_zones[3].y_centre = 12; + + + + + pzone_cfg->user_zones[4].height = 15; + pzone_cfg->user_zones[4].width = 15; + pzone_cfg->user_zones[4].x_centre = 8; + pzone_cfg->user_zones[4].y_centre = 8; + + status = VL53L1_init_zone_config_histogram_bins(pzone_cfg); + + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_init_zone_config_histogram_bins( + VL53L1_zone_config_t *pdata) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + uint8_t i; + + LOG_FUNCTION_START(""); + + for (i = 0; i < pdata->max_zones; i++) + pdata->bin_config[i] = VL53L1_ZONECONFIG_BINCONFIG__LOWAMB; + + LOG_FUNCTION_END(status); + + return status; +} + diff --git a/drivers/input/misc/vl53L1/kona/st,stmvl53l1.txt b/drivers/input/misc/vl53L1/kona/st,stmvl53l1.txt new file mode 100644 index 000000000000..3f81932590c2 --- /dev/null +++ b/drivers/input/misc/vl53L1/kona/st,stmvl53l1.txt @@ -0,0 +1,26 @@ +StMicroelectronis vl53l1 + +Requires properties: +- compatible: must be "st,stmvl53l1". +- reg: I2C address of the chip. +- xsdn-gpio: gpio number connected to vl53l1 reset pin. + +Optional properties: +- intr-gpio: gpio number connected to vl53l1 irq pin. +- vdd: a phandle for the regulator supplying power for vl53l1. +- pwren-gpio: gpio number use to control vl53l1 power. + +Example: + &i2c1 { + /* ... */ + + stmvl53l1: stmvl53l1@29 { + compatible = "st,stmvl53l1"; + reg = <0x29>; + xsdn-gpio = <19>; + pwren-gpio = <12>; + intr-gpio = <16>; + }; + + /* ... */ + }; diff --git a/drivers/input/misc/vl53L1/kona/stmvl53l1-i2c.h b/drivers/input/misc/vl53L1/kona/stmvl53l1-i2c.h new file mode 100644 index 000000000000..e7a84bc20eeb --- /dev/null +++ b/drivers/input/misc/vl53L1/kona/stmvl53l1-i2c.h @@ -0,0 +1,118 @@ +/************************************************************************** + * Copyright (c) 2016, STMicroelectronics - All Rights Reserved + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ****************************************************************************/ + +/** @file stmvl53l1-i2c.h + * Linux kernel i2c/cci wrapper for ST VL53L1 sensor i2c interface + **/ + +#ifndef STMVL53L1_I2C_H +#define STMVL53L1_I2C_H +#include +#include "stmvl53l1.h" + +struct i2c_data { + struct i2c_client *client; + /** back link to driver for interrupt and clean-up */ + struct stmvl53l1_data *vl53l1_data; + + /* reference counter */ + struct kref ref; + + /*!< if null no regulator use for power ctrl */ + struct regulator *vdd; + struct regulator *xsd; + + /*!< power enable gpio number + * + * if -1 no gpio if vdd not avl pwr is not controllable + */ + int pwren_gpio; + + /*!< xsdn reset (low active) gpio number to device + * + * -1 mean none assume no "resetable" + */ + int xsdn_gpio; + + /*!< intr gpio number to device + * + * intr is active/low negative edge by default + * + * -1 mean none assume use polling + * @warning if the dev tree and intr gpio is require please adapt code + */ + int intr_gpio; + + int ver_gpio; + /*!< device boot i2c register address + * + * boot_reg is the value of device i2c address after it is bring out + * of reset. + */ + int boot_reg; + + /*!< is set if above irq gpio got acquired */ + struct i2d_data_flags_t { + unsigned pwr_owned:1; /*!< set if pwren gpio is owned*/ + unsigned xsdn_owned:1; /*!< set if sxdn gpio is owned*/ + unsigned intr_owned:1; /*!< set if intr gpio is owned*/ + unsigned intr_started:1; /*!< set if irq is hanlde */ + } io_flag; + + /** the irq vectore assigned to gpio + * -1 if no irq hanled + */ + int irq; + + struct msgtctrl_t { + unsigned unhandled_irq_vec:1; + } msg_flag; +}; + +#ifdef USE_CAMERA_CCI +int __init stmvl53l1_init_cci(void); +void __exit stmvl53l1_exit_cci(void*); +int stmvl53l1_enable_pinctrl(void); +int stmvl53l1_disable_pinctrl(void); +#else +int stmvl53l1_init_i2c(void); +void __exit stmvl53l1_exit_i2c(void *arg); +#endif +int stmvl53l1_power_up_i2c(void *arg); +int stmvl53l1_power_down_i2c(void *arg); +int stmvl53l1_reset_release_i2c(void *arg); +int stmvl53l1_reset_hold_i2c(void *arg); +void stmvl53l1_clean_up_i2c(void); +int stmvl53l1_start_intr(void *object, int *poll_mode); +void *stmvl53l1_get(void *arg); +void stmvl53l1_put(void *arg); + +#endif /* STMVL53L1_I2C_H */ diff --git a/drivers/input/misc/vl53L1/kona/stmvl53l1.h b/drivers/input/misc/vl53L1/kona/stmvl53l1.h new file mode 100644 index 000000000000..51712edf6679 --- /dev/null +++ b/drivers/input/misc/vl53L1/kona/stmvl53l1.h @@ -0,0 +1,391 @@ +/************************************************************************** + * Copyright (c) 2016, STMicroelectronics - All Rights Reserved + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ****************************************************************************/ +/** + * @file stmvl53l1.h header for vl53l1 sensor driver + */ +#ifndef STMVL53L1_H +#define STMVL53L1_H + +#include +#include +#include +#include +#include + +#include "vl53l1_api.h" + +/** + * IPP adapt + */ +#ifdef DEBUG +# define IPP_PRINT(...) printk(__VA_ARGS__) +#else +# define IPP_PRINT(...) (void)0 +#endif + +#include "stmvl53l1_ipp.h" +#include "stmvl53l1_if.h" + +/** + * Configure the Netlink-id use + */ +#define STMVL531_CFG_NETLINK_USER 31 + +#define STMVL53L1_MAX_CCI_XFER_SZ 256 +#define STMVL53L1_DRV_NAME "stmvl53l1" + +/** + * configure usage of regulator device from device tree info + * to enable/disable sensor power + * see module-i2c or module-cci file + */ +/* define CFG_STMVL53L1_HAVE_REGULATOR */ + +#define DRIVER_VERSION "13.4.2" + +/** @ingroup vl53l1_config + * @{ + */ +/** + * Configure max number of device the driver can support + */ +#define STMVL53L1_CFG_MAX_DEV 2 +/** @} */ /* ingroup vl53l1_config */ + +/** @ingroup vl53l1_mod_dbg + * @{ + */ +#if 0 +#define DEBUG 1 +#endif +#if 0 +#define FORCE_CONSOLE_DEBUG +#endif + +extern int stmvl53l1_enable_debug; + +#ifdef DEBUG +# ifdef FORCE_CONSOLE_DEBUG +#define vl53l1_dbgmsg(str, ...) do { \ + if (stmvl53l1_enable_debug) \ + pr_info("%s: " str, __func__, ##__VA_ARGS__); \ +} while (0) +# else +#define vl53l1_dbgmsg(str, ...) do { \ + if (stmvl53l1_enable_debug) \ + pr_debug("%s: " str, __func__, ##__VA_ARGS__); \ +} while (0) +# endif +#else +# define vl53l1_dbgmsg(...) (void)0 +#endif + +/** + * set to 0 1 activate or not debug from work (data interrupt/polling) + */ +#define WORK_DEBUG 0 +#if WORK_DEBUG +# define work_dbg(msg, ...)\ + printk("[D WK53L1] :" msg "\n", ##__VA_ARGS__) +#else +# define work_dbg(...) (void)0 +#endif + +#define vl53l1_info(str, args...) \ + pr_info("%s: " str "\n", __func__, ##args) + +#define vl53l1_errmsg(str, args...) \ + pr_err("%s: " str, __func__, ##args) + +#define vl53l1_wanrmsg(str, args...) \ + pr_warn("%s: " str, __func__, ##args) + +/* turn off poll log if not defined */ +#ifndef STMVL53L1_LOG_POLL_TIMING +# define STMVL53L1_LOG_POLL_TIMING 0 +#endif +/* turn off cci log timing if not defined */ +#ifndef STMVL53L1_LOG_CCI_TIMING +# define STMVL53L1_LOG_CCI_TIMING 0 +#endif + +/**@} */ /* ingroup mod_dbg*/ + +#include +#include +#include + +/** if set to 1 enable ipp execution timing (if debug enabled) + * @ingroup vl53l1_mod_dbg + */ +#define IPP_LOG_TIMING 1 + +struct ipp_data_t { + struct ipp_work_t work; + struct ipp_work_t work_out; + int test_n; + /*!< buzy state 0 is idle + *any other value do not try to use (state value defined in source) + */ + int buzy; + int waited_xfer_id; + /*!< when buzy is set that is the id we are expecting + * note that value 0 is reserved and stand for "not waiting" + * as such never id 0 will be in any round trip exchange + * it's ok for daemon to use 0 in "ping" when it identify himself + */ + int status; /** if that is not 0 do not look at out work data */ + wait_queue_head_t waitq; + /*!< ipp caller are put in that queue wait while job is posted to user + * @warning ipp and dev mutex will be released before waiting + * see @ref ipp_abort + */ +#if IPP_LOG_TIMING + struct timeval start_tv, stop_tv; +#endif +}; + +struct stmvl53l1_waiters { + struct list_head list; + pid_t pid; +}; + +/* + * driver data structs + */ +struct stmvl53l1_data { + int id; /*!< multiple device id 0 based*/ + char name[64]; /*!< misc device name */ + + VL53L1_DevData_t stdev; /*!ipp.stop_tv) +# define stmvl531_ipp_tim_start(data)\ + do_gettimeofday(&data->ipp.start_tv) +# define stmvl531_ipp_time(data)\ + stmvl53l1_tv_dif(&data->ipp.start_tv, &data->ipp.stop_tv) +# define stmvl531_ipp_stat(data, fmt, ...)\ + vl53l1_dbgmsg("IPPSTAT " fmt "\n", ##__VA_ARGS__) +#else +# define stmvl531_ipp_tim_stop(data) (void)0 +# define stmvl531_ipp_tim_start(data) (void)0 +# define stmvl531_ipp_stat(...) (void)0 +#endif +}; + + +/** + * timeval diff in us + * + * @param pstart_tv + * @param pstop_tv + */ +long stmvl53l1_tv_dif(struct timeval *pstart_tv, struct timeval *pstop_tv); + + +/** + * The device table list table is update as device get added + * we do not support adding removing device mutiple time ! + * use for clean "unload" purpose + */ +extern struct stmvl53l1_data *stmvl53l1_dev_table[]; + +int stmvl53l1_setup(struct stmvl53l1_data *data); +void stmvl53l1_cleanup(struct stmvl53l1_data *data); +#ifdef CONFIG_PM_SLEEP +void stmvl53l1_pm_suspend_stop(struct stmvl53l1_data *data); +#endif +int stmvl53l1_intr_handler(struct stmvl53l1_data *data); + + +/** + * request ipp to abort or stop + * + * require dev work_mutex held + * + * @warning because the "waiting" work can't be aborted we must wake it up + * it will happen and at some later time not earlier than release of lock + * if after lock release we have a new request to start the race may not be + * handled correctly + * + * @param data the device + * @return 0 if no ipp got canceled, @warning this is maybe not grant we + * can't re-sched "dev work" and re-run the worker back + */ +int stmvl53l1_ipp_stop(struct stmvl53l1_data *data); + +int stmvl53l1_ipp_do(struct stmvl53l1_data *data, struct ipp_work_t *work_in, + struct ipp_work_t *work_out); + +/** + * per device netlink init + * @param data + * @return + */ +int stmvl53l1_ipp_setup(struct stmvl53l1_data *data); +/** + * per device ipp netlink cleaning + * @param data + * @return + */ +void stmvl53l1_ipp_cleanup(struct stmvl53l1_data *data); + +/** + * Module init for netlink + * @return 0 on success + */ +int stmvl53l1_ipp_init(void); + +/** + * Module exit for netlink + * @return 0 on success + */ +void stmvl53l1_ipp_exit(void); + +/** + * enable and start ipp exhange + * @param n_dev number of device to run on + * @param data dev struct + * @return 0 on success + */ +int stmvl53l1_ipp_enable(int n_dev, struct stmvl53l1_data *data); + + +/* + * function pointer structs + */ + + + +#endif /* STMVL53L1_H */ diff --git a/drivers/input/misc/vl53L1/kona/stmvl53l1_i2c.c b/drivers/input/misc/vl53L1/kona/stmvl53l1_i2c.c new file mode 100644 index 000000000000..906c0ea57090 --- /dev/null +++ b/drivers/input/misc/vl53L1/kona/stmvl53l1_i2c.c @@ -0,0 +1,412 @@ +/************************************************************************** + * Copyright (c) 2016, STMicroelectronics - All Rights Reserved + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ****************************************************************************/ + +/** + * @file stmvl53l1_i2c.c vl53l1 linux native i2c interface + * + */ +#include "stmvl53l1.h" +#include "stmvl53l1-i2c.h" +#include +#include "cam_cci_ctrl_interface.h" + + +#if STMVL53L1_LOG_POLL_TIMING +/** + * helper to elapse time in polling + * @param ptv pointer to start time_val + + */ +# define poll_timing_log(ptv) \ + vl53l1_dbgmsg("poll in %d us\n", tv_elapsed_us(ptv)) +#else +# define poll_timing_log(...) (void)0 +#endif + +#if STMVL53L1_LOG_CCI_TIMING +/** + * compute elapsed time in in micro sec based on do_gettimeofday + * @param tv pointer to start time_val + * @return time elapsed in micro seconde + */ + +/** + * compute elapsed time in in micro sec based on do_gettimeofday + * @param tv pointer to start time_val + * @return time elapsed in micro seconde + */ +static uint32_t tv_elapsed_us(struct timeval *tv) +{ + struct timeval now; + + do_gettimeofday(&now); + return (now.tv_sec - tv->tv_sec) * 1000000 + (now.tv_usec - + tv->tv_usec); +} + +# define cci_access_var struct timeval cci_log_start_tv +# define cci_access_start()\ + do_gettimeofday(&cci_log_start_tv) +# define cci_access_over(fmt, ...) \ + vl53l1_dbgmsg("cci_timing %d us" fmt "\n", \ + tv_elapsed_us(&cci_log_start_tv), ##__VA_ARGS__) +#else +# define cci_access_var +# define cci_access_start(...) (void)0 +# define cci_access_over(...) (void)0 +#endif + +#ifdef STMVL53L1_DEBUG_I2C +# define i2c_debug(fmt, ...) vl53l1_dbgmsg(fmt, ##__VA_ARGS__) +#else +# define i2c_debug(fmt, ...) (void)0 +#endif + +VL53L1_Error VL53L1_GetTickCount(uint32_t *ptime_ms) +{ + (void)ptime_ms; + BUG_ON(1); +} + +/** + * compute elapsed time in in milli sec based on do_gettimeofday + * @param tv pointer to start time_val + * @return time elapsed in milli seconde + */ +static uint32_t tv_elapsed_ms(struct timeval *tv) +{ + struct timeval now; + + do_gettimeofday(&now); + return (now.tv_sec - tv->tv_sec) * 1000 + + (now.tv_usec - tv->tv_usec) / 1000; +} + +#ifndef USE_CAMERA_CCI +static int cci_write(struct stmvl53l1_data *dev, int index, + uint8_t *data, uint16_t len) +{ + uint8_t buffer[STMVL53L1_MAX_CCI_XFER_SZ + 2]; + struct i2c_msg msg; + struct i2c_data *i2c_client_obj = (struct i2c_data *)dev->client_object; + struct i2c_client *client = (struct i2c_client *)i2c_client_obj->client; + int rc; + + cci_access_var; + if (len > STMVL53L1_MAX_CCI_XFER_SZ || len == 0) { + vl53l1_errmsg("invalid len %d\n", len); + return -1; + } + cci_access_start(); + /* build up little endian index in buffer */ + buffer[0] = (index >> 8) & 0xFF; + buffer[1] = (index >> 0) & 0xFF; + /* copy write data to buffer after index */ + memcpy(buffer + 2, data, len); + /* set i2c msg */ + msg.addr = client->addr; + msg.flags = client->flags; + msg.buf = buffer; + msg.len = len + 2; + + rc = i2c_transfer(client->adapter, &msg, 1); + if (rc != 1) { + vl53l1_errmsg("wr i2c_transfer err:%d, index 0x%x len %d\n", + rc, index, len); + } + cci_access_over("rd status %d long %d ", rc != 1, len); + return rc != 1; +} + +static int cci_read(struct stmvl53l1_data *dev, int index, + uint8_t *data, uint16_t len) +{ + uint8_t buffer[2]; + struct i2c_msg msg[2]; + struct i2c_data *i2c_client_obj = (struct i2c_data *)dev->client_object; + struct i2c_client *client = (struct i2c_client *)i2c_client_obj->client; + int rc; + + cci_access_var; + if (len > STMVL53L1_MAX_CCI_XFER_SZ || len == 0) { + vl53l1_errmsg("invalid len %d\n", len); + return -1; + } + cci_access_start(); + + /* build up little endian index in buffer */ + buffer[0] = (index >> 8) & 0xFF; + buffer[1] = (index >> 0) & 0xFF; + + msg[0].addr = client->addr; + msg[0].flags = client->flags; /* Write */ + msg[0].buf = buffer; + msg[0].len = 2; + /* read part of the i2c transaction */ + msg[1].addr = client->addr; + msg[1].flags = I2C_M_RD | client->flags; + msg[1].buf = data; + msg[1].len = len; + + rc = i2c_transfer(client->adapter, msg, 2); + if (rc != 2) { + pr_err("%s: i2c_transfer :%d, @%x index 0x%x len %d\n", + __func__, rc, client->addr, index, len); + + } + cci_access_over(" wr len %d status %d", rc != 2, len); + return rc != 2; +} +#endif +VL53L1_Error VL53L1_WrByte(VL53L1_DEV pdev, uint16_t index, uint8_t data) +{ + struct stmvl53l1_data *dev; + +#ifdef USE_CAMERA_CCI + struct camera_cci_transfer ccit; +#endif + dev = (struct stmvl53l1_data *)container_of(pdev, + struct stmvl53l1_data, stdev); +#ifdef USE_CAMERA_CCI + memset(&ccit,0,sizeof(ccit)); + ccit.cmd = CAMERA_CCI_WRITE; + ccit.addr = index; + ccit.data = &data; + ccit.count = 1; + return cam_cci_control_interface(&ccit); +#else + return cci_write(dev, index, &data, 1); +#endif +} + +VL53L1_Error VL53L1_RdByte(VL53L1_DEV pdev, uint16_t index, uint8_t *pdata) +{ + struct stmvl53l1_data *dev; +#ifdef USE_CAMERA_CCI + struct camera_cci_transfer ccit; +#endif + + dev = (struct stmvl53l1_data *) container_of(pdev, + struct stmvl53l1_data, stdev); +#ifdef USE_CAMERA_CCI + memset(&ccit,0,sizeof(ccit)); + ccit.cmd = CAMERA_CCI_READ; + ccit.addr = index; + ccit.data = pdata; + ccit.count = 1; + return cam_cci_control_interface(&ccit); +#else + return cci_read(dev, index, pdata, 1) ? + VL53L1_ERROR_CONTROL_INTERFACE : VL53L1_ERROR_NONE; +#endif +} + +VL53L1_Error VL53L1_WrWord(VL53L1_DEV pdev, uint16_t index, uint16_t data) +{ + VL53L1_Error status; + uint8_t buffer[2]; + + /* Split 16-bit word into MS and L* stmvl53l1 FlightSense sensor */ + + buffer[0] = (uint8_t) (data >> 8); + buffer[1] = (uint8_t) (data & 0x00FF); + i2c_debug(" @%x d= %x => [ %x , %x ] ", index, data, buffer[0], + buffer[1]); + status = VL53L1_WriteMulti(pdev, index, buffer, 2); + + return status; +} + +VL53L1_Error VL53L1_RdWord(VL53L1_DEV pdev, uint16_t index, uint16_t *pdata) +{ + VL53L1_Error status; + uint8_t buffer[2]; + + status = VL53L1_ReadMulti(pdev, index, buffer, 2); + + *pdata = ((uint16_t) buffer[0] << 8) + (uint16_t) buffer[1]; + + return status; +} + +VL53L1_Error VL53L1_WrDWord(VL53L1_DEV pdev, uint16_t index, uint32_t data) +{ + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t buffer[4]; + + /* Split 32-bit word into MS ... LS bytes */ + buffer[0] = (uint8_t) (data >> 24); + buffer[1] = (uint8_t) ((data & 0x00FF0000) >> 16); + buffer[2] = (uint8_t) ((data & 0x0000FF00) >> 8); + buffer[3] = (uint8_t) (data & 0x000000FF); + + status = VL53L1_WriteMulti(pdev, index, buffer, 4); + + return status; +} + +VL53L1_Error VL53L1_RdDWord(VL53L1_DEV pdev, uint16_t index, uint32_t *pdata) +{ + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t buffer[4]; + + status = VL53L1_ReadMulti(pdev, index, buffer, 4); + + *pdata = ((uint32_t) buffer[0] << 24) + ((uint32_t) buffer[1] << 16) + + ((uint32_t) buffer[2] << 8) + (uint32_t) buffer[3]; + + return status; +} + +VL53L1_Error VL53L1_WriteMulti(VL53L1_DEV pdev, uint16_t index, + uint8_t *pdata, uint32_t count) +{ + struct stmvl53l1_data *dev; + +#ifdef USE_CAMERA_CCI + struct camera_cci_transfer ccit; +#endif + + dev = (struct stmvl53l1_data *) container_of(pdev, + struct stmvl53l1_data, stdev); +#ifdef USE_CAMERA_CCI + memset(&ccit,0,sizeof(ccit)); + ccit.cmd = CAMERA_CCI_WRITE; + ccit.addr = index; + ccit.data = pdata; + ccit.count = count; + return cam_cci_control_interface(&ccit); +#else + return cci_write(dev, index, pdata, count) ? + VL53L1_ERROR_CONTROL_INTERFACE : VL53L1_ERROR_NONE; +#endif +} + +VL53L1_Error VL53L1_ReadMulti(VL53L1_DEV pdev, uint16_t index, + uint8_t *pdata, uint32_t count) +{ + struct stmvl53l1_data *dev; +#ifdef USE_CAMERA_CCI + struct camera_cci_transfer ccit; +#endif + + dev = (struct stmvl53l1_data *) container_of(pdev, + struct stmvl53l1_data, stdev); +#ifdef USE_CAMERA_CCI + memset(&ccit,0,sizeof(ccit)); + ccit.cmd = CAMERA_CCI_READ; + ccit.addr = index; + ccit.data = pdata; + ccit.count = count; + return cam_cci_control_interface(&ccit); +#else + return cci_read(dev, index, pdata, count) ? + VL53L1_ERROR_CONTROL_INTERFACE : VL53L1_ERROR_NONE; +#endif +} + +static int is_time_over(struct timeval *tv, uint32_t msec) +{ + return tv_elapsed_ms(tv) >= msec; +} + +VL53L1_Error VL53L1_WaitValueMaskEx(VL53L1_DEV pdev, + uint32_t timeout_ms, + uint16_t index, + uint8_t value, + uint8_t mask, uint32_t poll_delay_ms) +{ + struct timeval start_tv; + struct stmvl53l1_data *dev; + int rc, time_over; + uint8_t rd_val; + +#ifdef USE_CAMERA_CCI + struct camera_cci_transfer ccit; +#endif + + dev = (struct stmvl53l1_data *) container_of(pdev, + struct stmvl53l1_data, stdev); + + do_gettimeofday(&start_tv); + do { +#ifdef USE_CAMERA_CCI + memset(&ccit,0,sizeof(ccit)); + ccit.cmd = CAMERA_CCI_READ; + ccit.addr = index; + ccit.data = &rd_val; + ccit.count = 1; + rc = cam_cci_control_interface(&ccit); +#else + rc = cci_read(dev, index, &rd_val, 1); +#endif + if (rc) + return VL53L1_ERROR_CONTROL_INTERFACE; + if ((rd_val & mask) == value) { + poll_timing_log(&start_tv); + return VL53L1_ERROR_NONE; + } + vl53l1_dbgmsg("poll @%x %x & %d != %x", index, + rd_val, mask, value); + time_over = is_time_over(&start_tv, timeout_ms); + if (!time_over) + msleep(poll_delay_ms); + } while (!time_over); + vl53l1_errmsg("time over %d ms", timeout_ms); + return VL53L1_ERROR_TIME_OUT; +} + +VL53L1_Error VL53L1_WaitUs(VL53L1_DEV pdev, int32_t wait_us) +{ + struct stmvl53l1_data *data; + + data = (struct stmvl53l1_data *)container_of(pdev, + struct stmvl53l1_data, + stdev); + + if (!data->is_delay_allowed) + return VL53L1_ERROR_PLATFORM_SPECIFIC_START; + + /* follow Documentation/timers/timers-howto.txt recommendations */ + if (wait_us < 10) + udelay(wait_us); + else if (wait_us < 20000) + usleep_range(wait_us, wait_us + 1); + else + msleep(wait_us / 1000); + + return VL53L1_ERROR_NONE; +} + +VL53L1_Error VL53L1_WaitMs(VL53L1_DEV pdev, int32_t wait_ms) +{ + return VL53L1_WaitUs(pdev, wait_ms * 1000); +} diff --git a/drivers/input/misc/vl53L1/kona/stmvl53l1_if.h b/drivers/input/misc/vl53L1/kona/stmvl53l1_if.h new file mode 100644 index 000000000000..a43f63cb382b --- /dev/null +++ b/drivers/input/misc/vl53L1/kona/stmvl53l1_if.h @@ -0,0 +1,696 @@ +/************************************************************************** + * Copyright (c) 2016, STMicroelectronics - All Rights Reserved + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ****************************************************************************/ + + +/** + * @file stmvl53l1_if.h vl53l1 kernel driver user interface + * + * @note to use this header in a user space application it requires + * all st bare/ll driver platform wrapper files (for data struct def) + * this files (types etc ..) shall be same or compliant with bar driver version + * used in the kernel module + */ + +#ifndef STMVL53L1_IF_H +#define STMVL53L1_IF_H + + +#include "vl53l1_def.h" +/** + * @addtogroup vl53l1_ioctl + * @{ + */ + +/** + * misc device name for ioctl device + * + * for mutli instance all device 2nd and next instance are basic name +"1"+"2" + * @li stmvl53l1_ranging + * @li stmvl53l1_ranging1 + * @li stmvl53l1_ranging2 + */ +#define VL53L1_MISC_DEV_NAME "stmvl53l1_ranging" +/** + * register data use for simple/single ranging data @ref VL53L1_IOCTL_GETDATAS + * + * @warning this definition is subject to change ! + */ +#define stmvl531_range_data_t VL53L1_RangingMeasurementData_t + +/** + * parameter name in @ref stmvl53l1_parameter when using + * @ref VL53L1_IOCTL_PARAMETER + */ +enum __stmv53l1_parameter_name_e { + VL53L1_XTALKENABLE_PAR = 2, + /*!< VL53L1_XTALKENABLE_PAR enable/disable crosstalk compensation\n + * valid value : + * @li 0 disable crosstalk compensation + * @li 1 enable crosstalk compensation + * + * @warning mode can only be set while not ranging + */ + + VL53L1_DEVICEMODE_PAR = 6, + /*!< DEVICEMODE_PAR set ranging mode  \n + * valid mode value : + * @li 1 @a VL53L1_PRESETMODE_RANGING default ranging + * @li 2 @a VL53L1_PRESETMODE_MULTIZONES_SCANNING multiple zone + * @li 3 @a VL53L1_PRESETMODE_AUTONOMOUS autonomous mode + * @li 4 @a VL53L1_PRESETMODE_LITE_RANGING low mips ranging mode + * @li 8 @a VL53L1_PRESETMODE_LOWPOWER_AUTONOMOUS low power autonomous + * mode + * + * @warning mode can only be set while not ranging + */ + + VL53L1_POLLDELAY_PAR = 10, + /*!< set the polling delay (msec)\n + * + * @note apply only when operates in polling mode as no effect + * otherwise + */ + VL53L1_TIMINGBUDGET_PAR = 11, + /*!< VL53L1_TIMINGBUDGET_PAR + * @ref stmvl53l1_parameter.value field is timing budget in micro second + * + * @note Please refer to VL53L1 user manual for minimum timing budget according to the selected mode + * + * Mode / timing budget | Min | Typical + * ------------------------------------- | ----- | ------- + * VL53L1_PRESETMODE_RANGING | 8 ms | 16 ms + * VL53L1_PRESETMODE_MULTIZONES_SCANNING | 8 ms | 16 ms + * VL53L1_PRESETMODE_AUTONOMOUS | 41 ms | 76 ms + * VL53L1_PRESETMODE_LITE_RANGING | 17 ms | 66 ms + * VL53L1_PRESETMODE_LOWPOWER_AUTONOMOUS | 20 ms | 20 ms + * + */ + + VL53L1_DISTANCEMODE_PAR = 12, + /*!< VL53L1_DISTANCEMODE_PAR + * valid distance mode value : + * @li 1 @a VL53L1_DISTANCEMODE_SHORT + * @li 2 @a VL53L1_DISTANCEMODE_MEDIUM + * @li 3 @a VL53L1_DISTANCEMODE_LONG + * + * @warning distance mode can only be set while not ranging + */ + + VL53L1_OUTPUTMODE_PAR = 13, + /*!< VL53L1_OUTPUTMODE_PAR + * valid output mode value : + * @li 1 @a VL53L1_OUTPUTMODE_NEAREST + * @li 2 @a VL53L1_OUTPUTMODE_STRONGEST + * + * @warning distance mode can only be set while not ranging + */ + + VL53L1_FORCEDEVICEONEN_PAR = 14, + /*!< VL53L1_FORCEDEVICEONEN_PAR + * This parameter will control if device is put under reset when + * stopped. + * valid force device on value : + * @li 0 feature is disable. Device is put under reset when stopped. + * @li 1 feature is enable. Device is not put under reset when stopped. + */ + + VL53L1_LASTERROR_PAR = 15, + /*!< VL53L1_LASTERROR_PAR + * This is a read only parameter. It will return last device internal + * error. It's valid only after an ioctl/sysfs return an -EIO error. + */ + + VL53L1_OFFSETCORRECTIONMODE_PAR = 16, + /*!< VL53L1_OFFSETCORRECTIONMODE_PAR + * This parameter will define which mode to use for the offset + * correction. + * valid force device on value : + * @li 1 @a VL53L1_OFFSETCORRECTIONMODE_STANDARD + * @li 2 @a VL53L1_OFFSETCORRECTIONMODE_PERZONE + * + * @warning offset correction mode can only be set while not ranging + */ + + VL53L1_OPTICALCENTER_PAR = 17, + /*!< VL53L1_OPTICALCENTER_PAR + * This is a read only parameter. It will return optical center issued + * from the nvm set at FTM stage. value will contain X position of + * center. value2 will contain Y position of center. + * Return values have FixPoint1616_t type. + */ + + VL53L1_DMAXREFLECTANCE_PAR = 18, + /*!< VL53L1_DMAXREFLECTANCE_PAR + * This parameter will define target reflectance @ 940nm used to + * calculate the ambient DMAX. Parameter is of type FixPoint1616_t. + * + * @warning dmax reflectance can only be be set while not ranging + */ + + VL53L1_DMAXMODE_PAR = 19, + /*!< VL53L1_DMAXMODE_PAR + * This parameter will select Dmax mode. + * valid Dmax mode value : + * @li 1 @a VL53L1_DMAXMODE_FMT_CAL_DATA + * @li 2 @a VL53L1_DMAXMODE_CUSTCAL_DATA + * @li 3 @a VL53L1_DMAXMODE_PER_ZONE_CAL_DATA + * + * @warning Dmax mode can only be set while not ranging + */ + + VL53L1_TUNING_PAR = 20, + /*!< VL53L1_DMAXMODE_PAR + * This parameter is a write only parameter. It will allow to provide + * low level layer with a configuration parameter. + * value will be use as a key parameter. + * value2 will be use as value parameter. + * + * @warning those configuration parameter settings are only allowed + * before device is start once. + */ + + VL53L1_SMUDGECORRECTIONMODE_PAR = 21, + /*!< VL53L1_SMUDGECORRECTIONMODE_PAR + * This parameter will control if smudge correction is enable and how + * crosstalk values are updated. + * @li 0 @a VL53L1_SMUDGE_CORRECTION_NONE + * @li 1 @a VL53L1_SMUDGE_CORRECTION_CONTINUOUS + * @li 2 @a VL53L1_SMUDGE_CORRECTION_SINGLE + * @li 3 @a VL53L1_SMUDGE_CORRECTION_DEBUG + */ + + VL53L1_ISXTALKVALUECHANGED_PAR = 22, + /*!< VL53L1_ISXTALKCHANGED_PAR + * This is a read only parameter. It will return if Xtalk value has + * been updated while ranging. This parameter is reset each time device + * start to range. + * @li 0 Xtalk values has not been changed. + * @li 1 Xtalk values has been changed. + */ +}; +#define stmv53l1_parameter_name_e enum __stmv53l1_parameter_name_e + +/** + * parameter structure use in @ref VL53L1_IOCTL_PARAMETER + */ +struct stmvl53l1_parameter { + uint32_t is_read; /*!< [in] 1: Get 0: Set*/ + /*!< [in] parameter to set/get + * see @ref stmv53l1_parameter_name_e + */ + stmv53l1_parameter_name_e name; + int32_t value; /*!< [in/out] value to set /get */ + int32_t value2; /*!< [in/out] optional 2nd value */ + int32_t status; /*!< [out] status of the operation */ +}; + + +/** + * roi structure use as @ref VL53L1_IOCTL_ROI arg + * + * see @ref stmvl53l1_roi_full_t for easy to use type variable declaration + * required + */ +struct stmvl53l1_roi_t { + int32_t is_read; + /*!< specify roi transfer direction \n + * @li 0 to get roi + * @li !0 to set roi + */ + /*! roi data and count type use in @ VL53L1_IOCTL_ROI */ + struct roi_cfg_t { + uint8_t NumberOfRoi; + /*!< [in/out] Number of Rois to set/get + * + * on set :\n + * [in] number of roi to set + * @note 0 set can be used to return to device default roi usage + * + * on get :\n + * [in] max number provided\n + * [out] number of ROI copied back to user\n + * @warning 0 will not return any roi datas! + */ + VL53L1_UserRoi_t UserRois[1]; + /*!< roi data array length definition is 1 but + * NumberOfRoi+ FirstRoiToScan in array are required + * and will be effectively copy to/from user space + * + * @sa stmvl53l1_roi_full_t + */ + } roi_cfg /*! [in/out] roi data and count */; +}; + +/** + * full roi struct use in @ref VL53L1_IOCTL_ROI arg + * + * this definition make easier variable declaration with the max roi storage + * capabilities. + * + * @sa stmvl53l1_roi_t for field details + */ +struct stmvl53l1_roi_full_t { + int32_t is_read; + /*!< specify roi transfer direction \n + * @li 0 to get roi + * @li !0 to set roi + */ + VL53L1_RoiConfig_t roi_cfg; + /*!< roi data array of max length but only requested copy to/from user + * space effectively used + * see @a stmvl53l1_roi_t::roi_cfg for details + */ +}; + +/** + * parameter structure use in @ref VL53L1_IOCTL_CALIBRATION_DATA + */ +struct stmvl53l1_ioctl_calibration_data_t { + int32_t is_read; /*!< [in] 1: Get 0: Set*/ + VL53L1_CalibrationData_t data; + /*!< [in/out] data to set /get. Caller + * should consider this structure as an opaque one + */ +}; + +/** + * Opaque structure use to hold content of zone offset calibration result. + */ +#define stmvl531_zone_calibration_data_t \ + struct _stmvl531_zone_calibration_data_t + +struct _stmvl531_zone_calibration_data_t { + uint32_t id; + VL53L1_ZoneCalibrationData_t data; +}; + +/** + * parameter structure use in @ref VL53L1_IOCTL_ZONE_CALIBRATION_DATA + */ +struct stmvl53l1_ioctl_zone_calibration_data_t { + int32_t is_read; /*!< [in] 1: Get 0: Set*/ + stmvl531_zone_calibration_data_t data; + /*!< [in/out] data to set /get. Caller + * should consider this structure as an opaque one + */ +}; + +/** Select reference spad calibration in @ref VL53L1_IOCTL_PERFORM_CALIBRATION. + * + * param1, param2 and param3 not use + */ +#define VL53L1_CALIBRATION_REF_SPAD 0 + +/** Select crosstalk calibration in @ref VL53L1_IOCTL_PERFORM_CALIBRATION. + * + * param1 is calibration method. param2 and param3 not use. + * @li VL53L1_XTALKCALIBRATIONMODE_NO_TARGET + * @li VL53L1_XTALKCALIBRATIONMODE_SINGLE_TARGET + * @li VL53L1_XTALKCALIBRATIONMODE_FULL_ROI + */ +#define VL53L1_CALIBRATION_CROSSTALK 1 + +/** Select offset calibration @ref VL53L1_IOCTL_PERFORM_CALIBRATION. + * param1 is offset calibration mode. Parameter is either: + * - VL53L1_OFFSETCALIBRATIONMODE_STANDARD + * - VL53L1_OFFSETCALIBRATIONMODE_PRERANGE_ONLY + * - VL53L1_OFFSETCALIBRATIONMODE_MULTI_ZONE (deprecated) + * param2 is target distance in mm. + * param3 is target reflectance in percent. Parameter is of type FixPoint1616_t. + * + * Note that VL53L1_OFFSETCALIBRATIONMODE_MULTI_ZONE usage is deprecated. Per + * zone offset calibration should use VL53L1_CALIBRATION_OFFSET_PER_ZONE + * instead. + */ +#define VL53L1_CALIBRATION_OFFSET 2 + +/** Select offset calibration per zone @ref VL53L1_IOCTL_PERFORM_CALIBRATION. + * param1 is offset calibration mode. Parameter is: + * - VL53L1_OFFSETCALIBRATIONMODE_MULTI_ZONE + * param2 is target distance in mm. + * param3 is target reflectance in percent. Parameter is of type FixPoint1616_t. + * + * Note that region of interest should be defined by a prior call to + * VL53L1_IOCTL_ROI before calling VL53L1_IOCTL_PERFORM_CALIBRATION / + * VL53L1_CALIBRATION_OFFSET combinaison. + */ +#define VL53L1_CALIBRATION_OFFSET_PER_ZONE 3 + +/** Select simple offset calibration @ref VL53L1_IOCTL_PERFORM_CALIBRATION. + * param1 is target distance in mm. + * param2 and param3 are not used + */ +#define VL53L1_CALIBRATION_OFFSET_SIMPLE 4 + +/** Select per Vcsel offset calibration @ref VL53L1_IOCTL_PERFORM_CALIBRATION. + * param1 is target distance in mm. + * param2 and param3 are not used + * this calibration is used by the VL53L1_OFFSETCORRECTIONMODE_PERVCSEL mode + */ +#define VL53L1_CALIBRATION_OFFSET_PER_VCSEL 5 + +/** Select no Distance offset calibration @ref VL53L1_IOCTL_PERFORM_CALIBRATION. + * param1, param2 and param3 are not used + */ +#define VL53L1_CALIBRATION_OFFSET_ZERO_DISTANCE 6 + +/** + * parameter structure use in @ref VL53L1_IOCTL_PERFORM_CALIBRATION + */ +struct stmvl53l1_ioctl_perform_calibration_t { + uint32_t calibration_type; + /*!< [in] select which calibration to do : + * @li @ref VL53L1_CALIBRATION_REF_SPAD + * @li @ref VL53L1_CALIBRATION_CROSSTALK + * @li @ref VL53L1_CALIBRATION_OFFSET + * @li @ref VL53L1_CALIBRATION_OFFSET_PER_ZONE + * @li @ref VL53L1_CALIBRATION_OFFSET_SIMPLE + * @li @ref VL53L1_CALIBRATION_OFFSET_PER_VCSEL + * @li @ref VL53L1_CALIBRATION_OFFSET_ZERO_DISTANCE + */ + uint32_t param1; + /*!< [in] first param. Usage depends on calibration_type */ + uint32_t param2; + /*!< [in] second param. Usage depends on calibration_type */ + uint32_t param3; + /*!< [in] third param. Usage depends on calibration_type */ +}; + +/** + * parameter structure use in @ref VL53L1_IOCTL_AUTONOMOUS_CONFIG + */ +struct stmvl53l1_autonomous_config_t { + int32_t is_read; + /*!< [in] 1: Get 0: Set*/ + uint32_t pollingTimeInMs; + /*!< [in/out] interval between two measure in ms */ + VL53L1_DetectionConfig_t config; + /*!< [int/out] autonomous mode configuration structure */ +}; + +/* + * IOCTL definitions + */ + + +/** + * Start ranging (no argument) + * + * @note sysfs and ioctl control are assumed mutual exclusive use + * control from ioctl execute with no consideration of sysfs path. + * + * @return : + * @li 0 on success + * @li -EBUSY if already started + * @li -ENXIO failed to change i2c address change after reset release + * @li -EIO. Read last_error to get device error code + * @li -ENODEV. Device has been removed. + * + * example user land : + @code + int smtvl53l1_start(int fd){error + int rc; + rc= ioctl(fd, VL53L1_IOCTL_START,NULL); + if( rc ){ + if( errno == EBUSY){ + //the device is already started + ioctl_warn("already started"); + return EBUSY; + } + } + if( rc ){ + ioctl_error("%d %s", rc,strerror(errno)); + } + return rc; +} + @endcode +*/ + +#define VL53L1_IOCTL_START _IO('p', 0x01) + +/** + * stop ranging (no argument) + + * @note sysfs and ioctl control are assumed mutual exclusive use + * control from ioctl execute action with no consideration of sysfs path. + * + * @return + * @li 0 on success + * @li -EBUSY if it was already + * @li -EIO. Read last_error to get device error code + * @li -ENODEV. Device has been removed. + * + * c example userland : + @code +int smtvl53l1_stop(int fd){ + int rc; + rc= ioctl(fd, VL53L1_IOCTL_STOP,NULL); + if( rc ){ + if( errno == EBUSY ){ + ioctl_warn("already stopped"); + return errno; + } + ioctl_error("%d %s", rc,strerror(errno)); + } + return rc; +} +@endcode + */ +#define VL53L1_IOCTL_STOP _IO('p', 0x05) + +/** + * get single ranging data @sa for multi zone/objet + * + * retrieve the last range data available form the device + * + * @param in/out data struct ptr of type @ref stmvl531_range_data_t + * it may come in but is out as of now + * + * @return 0 on success else o, error check errno + * @li -EFAULT fault in cpy to f/m user out range data not copied + * @li -ENODEV. Device has been removed. + * + * @warning this ioctl will not wait for a new range sample acquisition + * it will return what available at time it get called . Hence same data maybe + * returned many time when doing fast polling.\n + * End user must inspect the data structure (time stamp etc )to find about it\n + * Despite it's non "waiting" nature this ioctl may still block/sleep shortly + * to ensure race free usage acquiring mutex and/or locks. + */ +#define VL53L1_IOCTL_GETDATAS \ + _IOWR('p', 0x0b, stmvl531_range_data_t) + +/** + * set or get parameter + * + * @param parameter in/out @ref stmvl53l1_parameter + * @sa stmv53l1_parameter_name_e + * + * for get if ioctl fail do not check for out params it is not valid + * for set theirs not copy back only see ioctl status, errno to get error case + * + * @return 0 on success else o, error check errno + * @li -ENODEV. Device has been removed. + * + * @note a set parameter may not be absorbed straight aways ! + */ +#define VL53L1_IOCTL_PARAMETER \ + _IOWR('p', 0x0d, struct stmvl53l1_parameter) + + +/** + * set/get roi + * + * shall only be use while device is stopped (EBUSY error otherwise) + * setting 0 rois stand for "disable user define roi usage, use device default" + * + * @param roi_cfg [in/out] type @ref stmvl53l1_roi_t and + * @ref stmvl53l1_roi_full_t + * @note when getting roi the returned roi cnt is set to available number + * of roi in driver but at most requested number or available one + * will be set in returned structure + * @warning the coordinate system is not usual image x,y (y down)but traditional + * ecludian x,y (y up) + * + * @warning once defined the user roi is kept alive until unset by user . + * User shall update roi when required (mode change etc ..)\n + * To return to default unset roi by setting none, device will return to default + * at next start + * + * @note roi validity is only checked at start ranging , as such invalid roi set + * can make start to fail + * + * @return 0 on success , see errno for error detail + * @li EBUSY when trying to set roi while ranging + * @li ENODEV never device get started and trying to get more rois than set + * @li other errno code could be ll driver specific + */ +#define VL53L1_IOCTL_ROI\ + _IOWR('p', 0x0e, struct stmvl53l1_roi_t) + +/** + * Get multi object/zone ranging data + * + * this call is non blocking and will return what available internally + * in all case (veen error) + * + * @param [out] multi zone range @ref VL53L1_MultiRangingData_t always update + * but -EFAULT error case + * + * @return 0 on success else o, error check errno + * @li -EFAULT fault in cpy to f/m user out range data not copyed + * @li -ENOEXEC active mode is not mutli-zone + * @li -ENODEV device is not ranging or device has been removed. + * as in that case MZ data may not be fully valid + */ +#define VL53L1_IOCTL_MZ_DATA\ + _IOR('p', 0x0f, VL53L1_MultiRangingData_t) + +/** + * get single ranging data @sa for multi zone/objet + * + * this call is equivalent to VL53L1_IOCTL_GETDATAS but will block until + * new data are available since previous call. + * + * @param in/out data struct ptr of type @ref stmvl531_range_data_t + * it may come in but is out as of now + * + * @return 0 on success else o, error check errno + * @li -EFAULT fault in cpy to f/m user out range data not copied + * @li -ENODEV device is not ranging or device has been removed. + * @li -ERESTARTSYS interrupt while sleeping. + */ +#define VL53L1_IOCTL_GETDATAS_BLOCKING\ + _IOWR('p', 0x10, stmvl531_range_data_t) + +/** + * Get multi object/zone ranging data + * + * this call is equivalent to VL53L1_IOCTL_MZ_DATA but will block until + * new data are available since previous call. + * + * @param [out] multi zone range @ref VL53L1_MultiRangingData_t always update + * but -EFAULT error case + * + * @return 0 on success else o, error check errno + * @li -EFAULT fault in cpy to f/m user out range data not copyed + * @li -ENOEXEC active mode is not mutli-zone + * @li -ENODEV device is not ranging or device has been removed. + * @li -ERESTARTSYS interrupt while sleeping. + * as in that case MZ data may not be fully valid + */ +#define VL53L1_IOCTL_MZ_DATA_BLOCKING\ + _IOR('p', 0x11, VL53L1_MultiRangingData_t) + +/** + * Get / set calibration data + * + * this call allow client to either read calibration data after calibration + * has been performed to store them in the host filesystem or push calibration + * data before ranging at each start-up. + * + * @param [in/out] data struct ptr of type + * @ref stmvl53l1_ioctl_calibration_data_t. Caller should consider it as an + * opaque structure. + * + * use this after either VL53L1_CALIBRATION_REF_SPAD, + * VL53L1_CALIBRATION_CROSSTALK or VL53L1_CALIBRATION_OFFSET. + * + * @return 0 on success else o, error check errno + * @li -EFAULT fault in cpy to f/m user out range data not copied + * @li -EBUSY when trying to set calibration data while ranging + * @li -EIO. Read last_error to get device error code + * @li -ENODEV. Device has been removed. + */ +#define VL53L1_IOCTL_CALIBRATION_DATA\ + _IOWR('p', 0x12, struct stmvl53l1_ioctl_calibration_data_t) + +/** + * Get / set zone calibration data + * + * this call allow client to either read zone calibration data after calibration + * has been performed to store them in the host filesystem or push zone + * calibration data before ranging at each start-up. + * + * use this after VL53L1_CALIBRATION_OFFSET_PER_ZONE calibration. + * + * @param [in/out] data struct ptr of type + * @ref stmvl53l1_ioctl_zone_calibration_data_t. Caller should consider it as an + * opaque structure. + * + * @return 0 on success else o, error check errno + * @li -EFAULT fault in cpy to f/m user out range data not copied + * @li -EBUSY when trying to set calibration data while ranging + * @li -EIO. Read last_error to get device error code + * @li -ENODEV. Device has been removed. + */ +#define VL53L1_IOCTL_ZONE_CALIBRATION_DATA\ + _IOWR('p', 0x12, struct stmvl53l1_ioctl_zone_calibration_data_t) + +/** + * perform calibration squence according to calibration_type + * + * this call is attended to be used during factory calibration. You select + * calibration to issue using calibration_type. + * + * @param [in] data struct ptr of type + * @ref stmvl53l1_ioctl_perform_calibration_t. + * + * @return 0 on success else o, error check errno + * @li -EFAULT fault in cpy to f/m user out range data not copied + * @li -EBUSY when trying to perform calibration data while ranging + * @li -EIO. Read last_error to get device error code + * @li -ENODEV. Device has been removed. + */ +#define VL53L1_IOCTL_PERFORM_CALIBRATION\ + _IOW('p', 0x13, struct stmvl53l1_ioctl_perform_calibration_t) + +/** + * set/get configure autonomous mode parameters + * + * Allow to get or set autonomous configuration. Change it only when device + * is stopped otherwise you will receive an EBUSY error. + * + * @param stmvl53l1_autonomous_config_t [in/out] + * + * @note autonomous config validity is only checked at start ranging , as such + * invalid autonomous config set can make start to fail. + * + * @return 0 on success , see errno for error detail + * @li -EFAULT failed to copy from/to configuration. + * @li -EBUSY when trying to change configuration while ranging. + * @li -ENODEV. Device has been removed. + */ +#define VL53L1_IOCTL_AUTONOMOUS_CONFIG\ + _IOWR('p', 0x14, struct stmvl53l1_autonomous_config_t) + +/** @} */ /* ioctl group */ +#endif /* STMVL53L1_IF_H */ diff --git a/drivers/input/misc/vl53L1/kona/stmvl53l1_internal_if.h b/drivers/input/misc/vl53L1/kona/stmvl53l1_internal_if.h new file mode 100644 index 000000000000..5a4c004c1ffd --- /dev/null +++ b/drivers/input/misc/vl53L1/kona/stmvl53l1_internal_if.h @@ -0,0 +1,120 @@ +/************************************************************************** + * Copyright (c) 2016, STMicroelectronics - All Rights Reserved + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ****************************************************************************/ + +#ifndef STMVL53L1_INTERNAL_IF_H +#define STMVL53L1_INTERNAL_IF_H + +#include "vl53l1_def.h" + +/* interface definition move in this file is not supposed to be use by a normal + * client. It's only here for internal testing purpose. + */ + +/* structure and ioctl that allow raw access to vl53l1 register */ +struct stmvl53l1_register { + uint32_t is_read; /*!< type of the access 1: read 0: write*/ + uint32_t index; /*!< register index */ + uint32_t cnt; /*!< register size shall be 1 to n */ + int32_t status; /*!< operation status 0 ok else error */ + + union reg_data_t { + uint8_t b; /*!< single data byte*/ + uint16_t w; /*!< single data word (16 bits)*/ + uint32_t dw; /*!< single data dword (32 bits)*/ + /*!< any size byte array + * @note only effectively used array size is needed and will be + * set/used another possible register definition is + * @ref stmvl53l1_register_flexi + */ + uint8_t bytes[256]; + /*!< data only *@warning device is big endian and + * no endianess adaptation is performed by + * @ref VL53L1_IOCTL_REGISTER + */ + } data; +}; + +struct stmvl53l1_register_flexi { + uint32_t is_read; /*!< [in] type of the access 1: read 0: write*/ + uint32_t index; /*!< [in] register index */ + uint32_t cnt; /*!< [în] register size shall be 1 to n */ + int32_t status; /*!< [out] operation status 0 ok else error */ + uint8_t data[]; /*!< [in/out] flexible array size data */ + /*!< data only *@warning device is big endian and + * no endianess adaptation is performed by @ref VL53L1_IOCTL_REGISTER + */ +}; + +#define VL53L1_IOCTL_REGISTER _IOWR('p', 0x0c, struct stmvl53l1_register) + +struct stmvl53l1_data_with_additional { + VL53L1_MultiRangingData_t data; + VL53L1_AdditionalData_t additional_data; +}; + +/** + * Get multi object/zone ranging data with additional data for debug + * + * this call is non blocking and will return what available internally + * in all case (veen error) + * + * @param [out] multi zone range @ref VL53L1_MultiRangingData_t always update + * but -EFAULT error case + * + * @return 0 on success else o, error check errno + * @li -EFAULT fault in cpy to f/m user out range data not copyed + * @li -ENOEXEC active mode is not mutli-zone + * @li -ENODEV device is not ranging or device has been removed. + * as in that case MZ data may not be fully valid + */ +#define VL53L1_IOCTL_MZ_DATA_ADDITIONAL\ + _IOR('p', 0x15, struct stmvl53l1_data_with_additional) + +/** + * Get multi object/zone ranging data + * + * this call is equivalent to VL53L1_IOCTL_MZ_DATA_ADDITIONAL but will block + * until new data are available since previous call. + * + * @param [out] multi zone range @ref VL53L1_MultiRangingData_t always update + * but -EFAULT error case + * + * @return 0 on success else o, error check errno + * @li -EFAULT fault in cpy to f/m user out range data not copyed + * @li -ENOEXEC active mode is not mutli-zone + * @li -ENODEV device is not ranging or device has been removed. + * @li -ERESTARTSYS interrupt while sleeping. + * as in that case MZ data may not be fully valid + */ +#define VL53L1_IOCTL_MZ_DATA_ADDITIONAL_BLOCKING\ + _IOR('p', 0x16, struct stmvl53l1_data_with_additional) + +#endif diff --git a/drivers/input/misc/vl53L1/kona/stmvl53l1_ipp.h b/drivers/input/misc/vl53L1/kona/stmvl53l1_ipp.h new file mode 100644 index 000000000000..31e75a196deb --- /dev/null +++ b/drivers/input/misc/vl53L1/kona/stmvl53l1_ipp.h @@ -0,0 +1,386 @@ +/************************************************************************** + * Copyright (c) 2016, STMicroelectronics - All Rights Reserved + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ****************************************************************************/ + +/** + * @file stmvl53l1_ipp.h + * + * helper to serialize de-serialize data in ipp exchange between user/kernel + * + * @date Sep 2, 2016 + * @author imaging + */ + +#ifndef _STMVL53L1_IPP_H_ +#define _STMVL53L1_IPP_H_ + +#include "vl53l1_types.h" + + +/** @ingroup ipp_dev + * @{ + */ + +/** + * @defgroup ipp_serialize ST IPP serialization helper + * + * to use the dump help you lust define first a few extra "specific" + * + * @li IPP_PRINT(fmt,..) with typical printf/printk interface + */ + /** @{ */ +/** + * generic data type to serialized scalar and offset for pointer + * + * serialized data can be seen as a first array of n ipp_art_t + * where each input are arg value for scaler type + * and an offset with respect to the ipp_arg base array where the data + * + * @note if all ipp argument can fit on 32 bit then ipp_arg_t is best set as + * a 32 bit base type '(i e uint32_t) to save space + * on 64 bit cpu it can remain 64 bit type to get better alignment + */ +typedef uint64_t ipp_arg_t; + +/** + * set to the cpu structure alignment and packing constrain + * + * all serialized argument passed by pointer will be stored with + * this memory align constrain + * + * + * @note if target cpu is ok to access unaligned data or less constrain ie 64 + * bit data align 32 are ok then it can be set to 4 to save space in data + * packing and copy\n + * We may be over constraining in many cases as a struct is only required to + * be aligned on i'st biggest item size + * + * @warning it must be a 2 power of 2 (& operation instead of mudulo used in + * align calculation) + * @warning using 8 byte constrain require that the @a ipp_arg_t is already + * aligned on that constrain + */ +#define IPP_ALIGN_REQ 8 + +/** + * set x to it's nearest aligned offset (not that 0 is fine as a valid offset + * than will not be up aligned to next align chunk ) + */ +#define IPP_ALIGN_OFFSET(x) (((x)+(IPP_ALIGN_REQ-1)) & (~(IPP_ALIGN_REQ-1))) + +/** + * declare variable needed for ipp serialization + */ +#define IPP_SERIALIZE_VAR int ipp_offset +/** + * Put in function start to init the serialization coding + * + * @param ipp_args buffer for data serialization + * @param n_args is the total number of argument scalar and ptr to serialized + * dot not count out only arg that will be returned + * + * it define local var "ipp_offset" used to accumulate all input args that must + * be serialize. It reserve header room in the buffer to place for scalar args + * and offset for args ptr copy + * + * args pass by pointer must be serialized by @ref IPP_SET_ARG_PTR in order they + * are declare\n + * scalar args can be serialized in any order with @ref IPP_SET_ARG + * + * scalar args that can't be cast to basic @ref ipp_arg_t shall be serialized + * Manually or using a macro similar to ptr that can be pass by copy + * + *@note @ref IPP_SERIALIZE_VAR must be use first + * @code + * int ipp_to _ser(int arg0, struct st_t *pdata1){ + * char *local var; + * ipp_arg_t args[256]; + * IPP_SERIALIZE_START(2); + * IPP_SET_ARG(args, 0, arg0); + * IPP_SET_ARG_PTR(args, 1, pdata); + * do_one_ipp(args); + * } + * @endcode + * + */ +#define IPP_SERIALIZE_START(ipp_args, n_args)\ + (ipp_offset = IPP_ALIGN_OFFSET((char *)(&ipp_args[n_args]) - \ + (char *)ipp_args)) + +/** + * @brief Serialize scalar argument + * + * serialized arg number n into ipp_args\n + * can be used in any order + * + * @param ipp_args the args buffer + * @param n 0 base arg number + * @param v the scalar argument variable + * @warning usable only for scalar type that can be copy on a ipp_arg_t + */ +#define IPP_SET_ARG(ipp_args, n, v) memcpy(&ipp_args[n], &v, sizeof(v)) + +/** + * @brief Serialize an arg passed by pointer + * + * @param ipp_args the arg ptr array + * @param n the arg number to serialize + * @param pdata argument it must be a type like struct x_t * int [n] etc ... + * that size is given by size of and and be copied by a single memcpy + */ +#define IPP_SET_ARG_PTR(ipp_args, n, pdata)\ + do {\ + ipp_args[n] = ipp_offset;\ + memcpy(((char *)ipp_args) + ipp_offset, pdata, sizeof(*pdata));\ + ipp_offset = IPP_ALIGN_OFFSET(ipp_offset + sizeof(*pdata));\ + } while (0) + +/** + * serialize out get ptr for pdata + * + * @note it does not cpy data just set ptr and update the offset + * @warning to be use in order + * + * @param ipp_args the arg ptr array + * @param n the arg number to serialize (unused) + * @param pdata init to ptr in ipp_args type is used for offset computation + * @warning to use sequential in order agr are serialized + */ +#define IPP_OUT_ARG_PTR(ipp_args, n, pdata)\ + do {\ + pdata = (void *)(((char *)ipp_args) + ipp_offset);\ + ipp_offset = IPP_ALIGN_OFFSET(ipp_offset + \ + (int)sizeof(*pdata));\ + } while (0) + + +/** + * @brief ipp get payload + * + * @return paylaod at time used \n + * when all done it's overall out payload + * + * require @ref IPP_SERIALIZE_VAR and @ref IPP_SERIALIZE_START used first\n + * best use after all @ref IPP_OUT_ARG_PTR or @ref IPP_SET_ARG_PTR done to get + * full payload + **/ +#define IPP_SERIALIZE_PAYLAOD() (ipp_offset + IPP_WORK_HDR_SIZE) + +/** + * de-serialize and argument that was passed by value + * @param ipp_args the args array + * @param n the 0 base argument number + * @param v argument it must be exact type + * + * + * @code + * f_deserialize(ipp_arg_t args[]) + * { + * // f_ser is like (uint16_t arg0, struct s_arg_t * arg1, int arg2) + * uint16_t arg0; + * void * parg1; + * int arg2; + * + * IPP_GET_ARG( args, 0, arg0) + * IPP_GET_ARG( args, 2, arg2) + * } + * @endcode + */ +#define IPP_GET_ARG(ipp_args, n, v) memcpy(&v, &ipp_args[n], sizeof(v)) + + +/** + * de-serialize an argument passed by pointer + * + * @param ipp_args the serialized argument array + * @param n 0 base argument number + * @param p ptr to arg to be set + * + * @note unlike serializing de-serializing pointer args data can be done in any + * order + * + * @code + * struct some_struct_t *parg2; + * IPP_GET_ARG_PTR(args,2,parg2); + * @endcode + */ +#define IPP_GET_ARG_PTR(ipp_args, n, p) (p = (void *)((char *)ipp_args + \ + ipp_args[n])) + + + + +/** + * debug macro to pint out all serialized args + * + * Implementation shall define IPP_PRINT_FUNC function to use + */ +#define IPP_PRINT_ARGS(ipp_args, n) \ + do {\ + int i;\ + for (i = 0; i < n; i++)\ + IPP_PRINT("arg#%d/%d is %8d 0x%08x\n", i, n,\ + ipp_args[i], ipp_args[i]);\ + IPP_PRINT("used data size %d\n", ipp_offset);\ + } while (0) + + +/** + * processing code type of proccesing + * + * used in @a ipp_work_t::process_no + */ +enum stmvl53l1_ipp_proccesing_e { + stmvl53l1_ipp_ping = 0, + /*!< stmvl53l1_ipp_ping + * @li can be sent by driver to check client is alive + * @li daemon sent it to identify and register himself to the driver + */ + stmvl53l1_ipp_cal_hist = 1, + /*!< stmvl53l1_ipp_cal_hist process cal hist*/ + + stmvl53l1_ipp_xtalk_calibration = 2, + /*!< stmvl53l1_ipp_xtalk_calibration process crosstalk calibration data + */ + + stmvl53l1_ipp_hist_ambient_dmax = 3, + /*!< stmvl53l1_ipp_hist_ambient_dmax process ambient dmac calculation + * from histogram + */ + + stmvl53l1_ipp_generate_dual_reflectance_xtalk_samples = 4, + /*!< stmvl53l1_ipp_generate_dual_reflectance_xtalk_samples process + * Xtalk data from dual reflectance histogram data + */ + + /** keep last*/ + stmvl53l1_ipp_max /*!< stmvl53l1_ipp_max */ +}; + +/** + * status use on @a ipp_work_t::status + */ +enum stmvl53l1_ipp_status_e { + stmvl53l1_ipp_status_ok = 0, /*!< ok work done */ + stmvl53l1_ipp_status_inv_id, /*!< dev id not supported or invalid */ + stmvl53l1_ipp_status_inv_proc, + /*!< process_no asked not supported or not implemented */ + stmvl53l1_ipp_status_inv_payload, + /*!< data payload for asked processing incorrect*/ + + stmvl53l1_ipp_status_proc_code = 0x100, + /*!< the lowest 8 bit is the error code form the processing */ +}; + +/** + * Ipp work (job) struct + * + * containing header with sequenc control information plus serialized data + */ +struct ipp_work_t { + int8_t dev_id; /*!< [in]/[out] device id */ + /*!< Identify the work do be run see @a stmvl53l1_ipp_proccesing_e */ + uint8_t process_no; + /*!< [out] status from daemon */ + int16_t status; + /*!< [in/out] unique xfer id */ + uint32_t xfer_id; + /*!< [in/out] effective data length including header*/ + uint32_t payload; + +/** max IPP data payload (not including header) + * + * we substract size of of item above + * must be lesss than one netlink packet + */ +#define MAX_IPP_DATA ((4096-4*3)/8) + ipp_arg_t data[MAX_IPP_DATA]; /*!< [in][out] */ +}; + +/** + * size of header only message ( no payload) + * require \#include in user land + */ +#define IPP_WORK_HDR_SIZE (offsetof(struct ipp_work_t, data[0])) +/** + * max payload per ipp transfer + */ +#define IPP_WORK_MAX_PAYLOAD sizeof(struct ipp_work_t) + +/** copy ipp header from src to dest + * + * used to prepare return work using incoming work header + * @param dest dest work ptr + * @param src src work ptr + */ +#define IPP_CPY_HEADER(dest, src) memcpy(dest, src, IPP_WORK_HDR_SIZE) + +/** + * dump in human readble way ipp struct + * + * @note require IPP_PRINT macro + * + * @param pw ipp_work struct to dump + * @param max_data max amount of data to be dump + * @param max_dev max number of dev (for check) + */ +static inline void ipp_dump_work(struct ipp_work_t *pw, uint32_t max_data, + int max_dev) +{ + uint32_t data_cnt; + uint32_t i; + uint8_t *pbdata; + + (void)max_dev; /* avoid warning when not used */ + (void)pbdata; /*avoid warning in case no print no use*/ + + IPP_PRINT("dev #%d (%s)\n", pw->dev_id, pw->dev_id < max_dev ? + "ok" : "bad"); + IPP_PRINT("process #%d (%s)\n", pw->process_no, + pw->process_no < stmvl53l1_ipp_max ? "ok" : "bad"); + IPP_PRINT("status %d\n", pw->status); + IPP_PRINT("Xfer id 0x%08X payload %d bytes (%s)\n", pw->xfer_id, + pw->payload, + pw->payload > IPP_WORK_MAX_PAYLOAD ? "invalid" : "ok"); + data_cnt = pw->payload > IPP_WORK_MAX_PAYLOAD ? + IPP_WORK_MAX_PAYLOAD : pw->payload; + data_cnt = data_cnt > max_data ? max_data : data_cnt; + for (i = 0, pbdata = (uint8_t *)pw->data; i < data_cnt; i++) { + if (i%16 == 0) + IPP_PRINT("\n%4X\t", i); + IPP_PRINT("%02X ", pbdata[i]); + } + IPP_PRINT("\n"); +} + +/** @} */ /* ingroup helper */ + +/** @} */ /* ingroup ipp_dev */ +#endif /* _STMVL53L1_IPP_H_ */ diff --git a/drivers/input/misc/vl53L1/kona/stmvl53l1_ipp_nl.c b/drivers/input/misc/vl53L1/kona/stmvl53l1_ipp_nl.c new file mode 100644 index 000000000000..aea6fe21fc4c --- /dev/null +++ b/drivers/input/misc/vl53L1/kona/stmvl53l1_ipp_nl.c @@ -0,0 +1,384 @@ +/************************************************************************** + * Copyright (c) 2016, STMicroelectronics - All Rights Reserved + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ****************************************************************************/ + +/** + * @file stmvl53l1_ipp_nl.c vl53l1 ipp proxy over netlink kernel side + */ +#include +#include +#include +#include +#include + +#include "stmvl53l1.h" + +#include "vl53l1_platform_ipp.h" +#include "stmvl53l1_ipp.h" + +#define IPP_DEBUG 1 +#ifndef IPP_DEBUG +# define _ipp_dump_work(...) (void)0 +#else +# define _ipp_dump_work(...) ipp_dump_work(__VA_ARGS__) +#endif + +#define IPP_STATE_PENDING 1 +#define IPP_STATE_COMPLETED 2 +#define IPP_STATE_CANCELED 4 + +#define IPP_TIMEOUT_MS 100 + +/** the single netlink strut use by all instance + * @note is NULL until set + */ +static struct sock *nl_sk; + +static DEFINE_MUTEX(ipp_mutex); + +/** + * current registered daemon pid + * @note default value 0 or later 1 is kind of invalid and will require + * user space to connect before we can send any packet + */ +static int daemon_pid; + +/** + * next xfer_id (shared other all dev) + * no direct us used @@ref get_next_xfer_id (will get lock) + * @note default to 0 what is "reserved" + */ +static int next_xfer_id; + + +#define ipp_err(fmt, ...) pr_err("STMVL53L1 IPP Err in %s %d :" fmt "\n", \ + __func__, __LINE__, ##__VA_ARGS__) + +#define ipp_warn(fmt, ...) pr_warn("STMVL53L1 IPP wng in %s %d : "fmt"\n",\ + __func__, __LINE__, ##__VA_ARGS__) + +#if 0 +# define ipp_dbg(fmt, ...) pr_info("IPP %s %d " fmt "\n",\ + __func__, __LINE__, ##__VA_ARGS__) +#else +# define ipp_dbg(...) (void)0 +#endif + +/** + * get and managed increment of next xfer_id + * @note will get ipp_mutex + * @return the xfer_id to be used + */ +static int get_next_xfer_id(void) +{ + mutex_lock(&ipp_mutex); + next_xfer_id++; + /*0 is reserved skip it*/ + if (next_xfer_id == 0) + next_xfer_id = 1; + mutex_unlock(&ipp_mutex); + + return next_xfer_id; +} + +static int send_client_msg(void *msg_data, int msg_size) +{ + int rc; + struct sk_buff *skb_out; + struct nlmsghdr *nlh; + void *nl_data = NULL; + + ipp_dbg("to send %d byte", msg_size); + skb_out = nlmsg_new(msg_size, 0); + if (!skb_out) { + ipp_err("nlmsg_new fail\n"); + return -1; + } + + nlh = nlmsg_put(skb_out, 0, 0, NLMSG_DONE, msg_size, 0); + NETLINK_CB(skb_out).dst_group = 0; /* not in mcast group */ + nl_data = nlmsg_data(nlh); /*get data ptr from header*/ + + if ((nl_data != NULL) && (msg_data != NULL) && (msg_size > 0)) { + memcpy(nl_data, msg_data, msg_size); + } + /* FIXME do we real need to lock to send a data other nl_sk ? */ + mutex_lock(&ipp_mutex); + rc = nlmsg_unicast(nl_sk, skb_out, daemon_pid); + if (rc < 0) + ipp_err("fail to send data size %d to pid %d\n", + msg_size, daemon_pid); + /* stat can be done here in else case */ + mutex_unlock(&ipp_mutex); + + return rc; +} + +/* + * ipp lock is held ping already handled + */ +int ipp_in_process(struct ipp_work_t *pwork) +{ + struct stmvl53l1_data *data; + + ipp_dbg("enter"); + _ipp_dump_work(pwork, IPP_WORK_MAX_PAYLOAD, STMVL53L1_CFG_MAX_DEV); + + /* work id check already done */ + data = stmvl53l1_dev_table[pwork->dev_id]; + ipp_dbg("to lock "); + /* Release now useless ipp_mutex for below work since we may deadlock + * with irq path. + */ + mutex_unlock(&ipp_mutex); + mutex_lock(&data->work_mutex); + if (data->ipp.buzy == IPP_STATE_PENDING) { + /* if it was already handled ignore it */ + if (data->ipp.waited_xfer_id == pwork->xfer_id) { + /* ok that is what we are expecting back */ + memcpy(&data->ipp.work_out, pwork, pwork->payload); + data->ipp.buzy |= IPP_STATE_COMPLETED; + ipp_dbg("to wake ipp waiter as buzy state %d", + data->ipp.buzy); + wake_up(&data->ipp.waitq); + goto done_lock; + } + } + /* either not waiting any more or not the expected id drop it */ + ipp_err("dev #%d ippp buzy %d xfer id %d rcv id %d droping it", + data->id, data->ipp.buzy, data->ipp.waited_xfer_id, + pwork->xfer_id); +done_lock: + mutex_unlock(&data->work_mutex); + mutex_lock(&ipp_mutex); + + return 0; +} + +int stmvl53l1_ipp_stop(struct stmvl53l1_data *data) +{ + int rc; + + rc = data->ipp.buzy; + ipp_dbg("#%d to stop buzy %d", data->id, data->ipp.buzy); + if (data->ipp.buzy) { + /* set invalid wait id to discard canceled job when back */ + data->ipp.waited_xfer_id = 0; + data->ipp.buzy |= IPP_STATE_CANCELED|IPP_STATE_COMPLETED; + ipp_dbg("#%dto wake up worker", data->id); + /* wake up worker or abort the thread */ + wake_up(&data->ipp.waitq); + } + + return rc; +} + +/* + * ipp and dev lock are held + * release and re-grabbed here + */ +int stmvl53l1_ipp_do(struct stmvl53l1_data *data, + struct ipp_work_t *pin, struct ipp_work_t *pout) +{ + int xfer_id; + int rc; + bool has_timeout; + + ipp_dbg("enter"); + + xfer_id = get_next_xfer_id(); + /* set xfer and device dependent part of the work */ + pin->dev_id = data->id; + pin->xfer_id = xfer_id; + data->ipp.waited_xfer_id = xfer_id; + /* try to do it */ + rc = send_client_msg(pin, pin->payload); + /* shall we retry if fail to send for some time or number of try ? */ + if (rc < 0) { + rc = -1; + ipp_err("fail to send msg %d", rc); + } else if (data->ipp.buzy == 0) { + /* send ok put the ipp on buzy state while locked */ + data->ipp.buzy = IPP_STATE_PENDING; + /* unlock now that state is marked buzy */ + mutex_unlock(&data->work_mutex); + + /* put task to wait for completion */ + ipp_dbg("to wait"); + has_timeout = !wait_event_timeout(data->ipp.waitq, + (data->ipp.buzy != IPP_STATE_PENDING), + msecs_to_jiffies(IPP_TIMEOUT_MS)); + + /* relock the main lock */ + mutex_lock(&data->work_mutex); + + rc = (data->ipp.buzy & IPP_STATE_CANCELED) || has_timeout ? + -1 : 0; + if (rc) { + ipp_dbg("waking up with from canceled/timeout ipp"); + } else { + /* return status from the ipp itself */ + ipp_dbg("ip back with status %d", data->ipp.status); + rc = data->ipp.status; + } + data->ipp.buzy = 0;/* buzy clear but locked so safe */ + } else { + ipp_dbg("buzy still not zero %d", data->ipp.buzy); + rc = -1; + } + + +/* done_lock: */ + return rc; +} + + +static void stmvl53l1_nl_recv_msg(struct sk_buff *skb_in) +{ + int pid_chg = 0; + int pid; + struct nlmsghdr *nlh; + struct ipp_work_t *pwork; + + ipp_dbg("Entering"); + + nlh = (struct nlmsghdr *)skb_in->data; + pid = nlh->nlmsg_pid; /*pid of sending process */ + + pwork = nlmsg_data(nlh); + if (pwork->payload < IPP_WORK_HDR_SIZE || + pwork->payload > IPP_WORK_MAX_PAYLOAD){ + /* invalid header size */ + ipp_err("invalid msg header size %d", pwork->payload); + _ipp_dump_work(pwork, IPP_WORK_MAX_PAYLOAD, + STMVL53L1_CFG_MAX_DEV); + return; + } + + mutex_lock(&ipp_mutex); + + if ((pwork->dev_id >= STMVL53L1_CFG_MAX_DEV) || (pwork->dev_id < 0)) { + ipp_err("invalid dev id on msg %d", pwork->dev_id); + _ipp_dump_work(pwork, IPP_WORK_MAX_PAYLOAD, + STMVL53L1_CFG_MAX_DEV); + goto done_locked; + } + + if (pwork->process_no == stmvl53l1_ipp_ping) { + /* in that case the payload must be exact status size only + * if not it is a badly format message or bad message + */ + if (pwork->payload != IPP_WORK_HDR_SIZE) { + ipp_err("invalid ping msg size %d!=%zu ", + pwork->payload, IPP_WORK_HDR_SIZE); + _ipp_dump_work(pwork, IPP_WORK_MAX_PAYLOAD, + STMVL53L1_CFG_MAX_DEV); + goto done_locked; + } + /* if pid was not set or change resent all ongoing ipp */ + if (pid != daemon_pid) + ipp_warn("pid chg %d => %d\n", daemon_pid, pid); + else + ipp_dbg("got ping fm pid %d\n", daemon_pid); + daemon_pid = pid; + pid_chg = 1; + } else { + ipp_in_process(pwork); + } + done_locked: + mutex_unlock(&ipp_mutex); +} + +int stmvl53l1_ipp_setup(struct stmvl53l1_data *data) +{ + int rc; + + mutex_lock(&ipp_mutex); + + data->ipp.buzy = 0; + init_waitqueue_head(&data->ipp.waitq); + ipp_dbg("now %d dev daemon pid is %d", STMVL53L1_CFG_MAX_DEV, + daemon_pid); + rc = 0; + + mutex_unlock(&ipp_mutex); + + return rc; +} + +void stmvl53l1_ipp_cleanup(struct stmvl53l1_data *data) +{ + /* nothink to do */ +} + +#if !defined(OLD_NETLINK_API) +struct netlink_kernel_cfg cfg = { + .input = stmvl53l1_nl_recv_msg +}; +#endif + +static int netlink_protocol_type = STMVL531_CFG_NETLINK_USER; + +module_param(netlink_protocol_type, int, 0444); +MODULE_PARM_DESC(netlink_protocol_type, + "select netlink protocol type for ipp communications"); + +int stmvl53l1_ipp_init(void) +{ + mutex_init(&ipp_mutex); + daemon_pid = 1; /* pid 1 is safe should not be use for user space */ + +#if defined(OLD_NETLINK_API) + nl_sk = netlink_kernel_create(&init_net, + netlink_protocol_type, + 0, + stmvl53l1_nl_recv_msg, + NULL, + THIS_MODULE); +#else + nl_sk = netlink_kernel_create(&init_net, + netlink_protocol_type, + &cfg); +#endif + + return nl_sk ? 0 : -1; +} + + +void stmvl53l1_ipp_exit(void) +{ + if (nl_sk != NULL) { + vl53l1_dbgmsg("releasing netlink socket"); + netlink_kernel_release(nl_sk); + nl_sk = NULL; + } +} + + diff --git a/drivers/input/misc/vl53L1/kona/stmvl53l1_log.c b/drivers/input/misc/vl53L1/kona/stmvl53l1_log.c new file mode 100644 index 000000000000..ecedcb446dda --- /dev/null +++ b/drivers/input/misc/vl53L1/kona/stmvl53l1_log.c @@ -0,0 +1,78 @@ +/************************************************************************** + * Copyright (c) 2016, STMicroelectronics - All Rights Reserved + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ****************************************************************************/ +/** + * @file /stmvl53l1_module.c vl53l1_module ST VL53L1 linux kernel module + * + * This is implementation of low level driver trace support + */ +#include +#include + +#include "stmvl53l1.h" + +#ifdef VL53L1_LOG_ENABLE + +static bool trace_function; +static int trace_module; +static int trace_level; + +module_param(trace_function, bool, 0644); +MODULE_PARM_DESC(trace_function, + "allow tracing of low level function entry and exit"); + +module_param(trace_module, int, 0644); +MODULE_PARM_DESC(trace_module, + "control tracing of low level per module"); + +module_param(trace_level, int, 0644); +MODULE_PARM_DESC(trace_level, + "control tracing of low level per level"); + +void log_trace_print(uint32_t module, uint32_t level, uint32_t function, + const char *format, ...) +{ + va_list args; + + if (function && !trace_function) + return; + + if (!(module & trace_module)) + return; + + if (level > trace_level) + return; + + va_start(args, format); + vprintk(format, args); + va_end(args); +} + +#endif diff --git a/drivers/input/misc/vl53L1/kona/stmvl53l1_module-cci.c b/drivers/input/misc/vl53L1/kona/stmvl53l1_module-cci.c new file mode 100644 index 000000000000..53122c85de88 --- /dev/null +++ b/drivers/input/misc/vl53L1/kona/stmvl53l1_module-cci.c @@ -0,0 +1,338 @@ +/* +* Copyright (c) 2016, STMicroelectronics - All Rights Reserved +* +* License terms: BSD 3-clause "New" or "Revised" License. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* +* 1. Redistributions of source code must retain the above copyright notice, this +* list of conditions and the following disclaimer. +* +* 2. Redistributions in binary form must reproduce the above copyright notice, +* this list of conditions and the following disclaimer in the documentation +* and/or other materials provided with the distribution. +* +* 3. Neither the name of the copyright holder nor the names of its contributors +* may be used to endorse or promote products derived from this software +* without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/** + * @file stmvl53l1_module-i2c.c + * + * implement STM VL53L1 module interface i2c wrapper + control + * using linux native i2c + gpio + reg api + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * power specific includes + */ +#include +#include +#include +#include +#include +#include +#include + +#include "stmvl53l1-i2c.h" +#include "stmvl53l1.h" +struct stmvl53l1_pinctrl_info { + struct pinctrl *pinctrl; + struct pinctrl_state *gpio_state_active; + struct pinctrl_state *gpio_state_suspend; + struct pinctrl_state *gpio_state_pullup; +}; + + +struct stmvl53l1_pinctrl_info stmvl53l1_pinctrl; +int flash_version = 0; + +extern int stmvl53l1_parse_tree(struct device *dev, struct i2c_data *i2c_data); +extern void stmvl53l1_release_gpios(struct i2c_data *i2c_data); +extern int get_version(struct device *dev, struct i2c_data *i2c_data); + +static int stmvl53l1_request_pinctrl(struct device *dev) +{ + struct stmvl53l1_pinctrl_info *device_pctrl = &stmvl53l1_pinctrl; + device_pctrl->pinctrl = devm_pinctrl_get(dev); + if (IS_ERR_OR_NULL(device_pctrl->pinctrl)) { + vl53l1_errmsg("Pinctrl not available"); + device_pctrl->pinctrl = NULL; + return 0; + } + device_pctrl->gpio_state_active = + pinctrl_lookup_state(device_pctrl->pinctrl, + "laser_default"); + if (IS_ERR_OR_NULL(device_pctrl->gpio_state_active)) { + vl53l1_errmsg("Failed to get the active state pinctrl handle"); + device_pctrl->gpio_state_active = NULL; + return -EINVAL; + } + device_pctrl->gpio_state_suspend + = pinctrl_lookup_state(device_pctrl->pinctrl, + "laser_suspend"); + if (IS_ERR_OR_NULL(device_pctrl->gpio_state_suspend)) { + vl53l1_errmsg("Failed to get the suspend state pinctrl handle"); + device_pctrl->gpio_state_suspend = NULL; + return -EINVAL; + } + device_pctrl->gpio_state_pullup + = pinctrl_lookup_state(device_pctrl->pinctrl, + "gpio_pullup"); + if (IS_ERR_OR_NULL(device_pctrl->gpio_state_pullup)) { + vl53l1_info("Failed to get the pullup state pinctrl handle"); + device_pctrl->gpio_state_pullup = NULL; + } + + return 0; +} + +int stmvl53l1_enable_pinctrl(void) +{ + int rc = 0; + + if (stmvl53l1_pinctrl.pinctrl && + stmvl53l1_pinctrl.gpio_state_active) { + rc = pinctrl_select_state(stmvl53l1_pinctrl.pinctrl, + stmvl53l1_pinctrl.gpio_state_active); + vl53l1_errmsg("enable pinctrl rc=%d\n", rc); + } + + return rc; +} + +int stmvl53l1_disable_pinctrl(void) +{ + int rc = 0; + + if (stmvl53l1_pinctrl.pinctrl && + stmvl53l1_pinctrl.gpio_state_suspend) { + rc = pinctrl_select_state(stmvl53l1_pinctrl.pinctrl, + stmvl53l1_pinctrl.gpio_state_suspend); + vl53l1_errmsg("disable pinctrl rc=%d\n", rc); + } + + return rc; + +} + +int stmvl53l1_release_pinctrl(struct device *dev) +{ + if (stmvl53l1_pinctrl.pinctrl) + devm_pinctrl_put(stmvl53l1_pinctrl.pinctrl); + stmvl53l1_pinctrl.pinctrl = NULL; + + return 0; +} + +static ssize_t version_proc_write(struct file *filp, const char __user *buff, + size_t len, loff_t *data) +{ + char buf[5] = {0}; + if (len > 5) + len = 5; + if (copy_from_user(buf, buff, len)) { + pr_err("proc write error.\n"); + return -EFAULT; + } + flash_version = simple_strtoul(buf, NULL, 10); + return len; +} + +static ssize_t version_proc_read(struct file *filp, char __user *buff, + size_t len, loff_t *data) +{ + char value[2] = {0}; + snprintf(value, sizeof(value), "%d", flash_version); + return simple_read_from_buffer(buff, len, data, value,1); +} + +static const struct file_operations version_fops = { + .owner = THIS_MODULE, + .read = version_proc_read, + .write = version_proc_write, +}; + +static int version_proc_init(void) +{ + int ret = 0; + char proc_flash[16] = "flashlight_ver"; + struct proc_dir_entry *proc_entry; + + proc_entry = proc_create_data(proc_flash, 0666, NULL, &version_fops, NULL); + if (proc_entry == NULL) { + ret = -ENOMEM; + pr_err("[%s]: Error! Couldn't create flashlight_ver proc entry\n", __func__); + } + return ret; +} + +static int32_t stmvl53l1_probe_cci( + struct platform_device *pdev) +{ + int rc = 0; + struct stmvl53l1_data *vl53l1_data = NULL; + struct i2c_data *i2c_data = NULL; + + vl53l1_dbgmsg("Enter %s : 0x%02x\n", pdev->name, pdev->id); + + + vl53l1_data = kzalloc(sizeof(struct stmvl53l1_data), GFP_KERNEL); + if (!vl53l1_data) { + rc = -ENOMEM; + return rc; + } + if (vl53l1_data) { + vl53l1_data->client_object = + kzalloc(sizeof(struct i2c_data), GFP_KERNEL); + if (!vl53l1_data->client_object) + goto done_freemem; + i2c_data = (struct i2c_data *)vl53l1_data->client_object; + } + //i2c_data->client = client; + i2c_data->vl53l1_data = vl53l1_data; + i2c_data->irq = -1 ; + rc = stmvl53l1_parse_tree(&(pdev->dev), i2c_data); + if (rc) + goto done_freemem; + + rc = stmvl53l1_request_pinctrl(&(pdev->dev)); + if (rc){ + vl53l1_errmsg("fail to request pinctrl,rc = %d", rc); + goto done_freemem; + } + rc = stmvl53l1_enable_pinctrl(); + if (rc){ + vl53l1_errmsg("fail to enable pinctrl,rc = %d", rc); + goto release_gpios; + } + + if (stmvl53l1_pinctrl.pinctrl && + stmvl53l1_pinctrl.gpio_state_pullup) { + rc = pinctrl_select_state(stmvl53l1_pinctrl.pinctrl, + stmvl53l1_pinctrl.gpio_state_pullup); + vl53l1_errmsg("enable gpio_state_pullup rc=%d\n", rc); + flash_version = !get_version(&(pdev->dev), i2c_data); + version_proc_init(); + } + + platform_set_drvdata(pdev, vl53l1_data); + //vl53l1_data->plat_dev = pdev; + + rc = stmvl53l1_setup(vl53l1_data); + if (rc) + goto release_gpios; + vl53l1_dbgmsg("End\n"); + + kref_init(&i2c_data->ref); + + return rc; + +release_gpios: + stmvl53l1_release_gpios(i2c_data); + +done_freemem: + kfree(vl53l1_data); + kfree(i2c_data); + + return 0; +} + +static int32_t stmvl53l1_remove_cci(struct platform_device *pdev) +{ + int rc = 0; + struct stmvl53l1_data *data = platform_get_drvdata(pdev); + struct i2c_data *i2c_data = (struct i2c_data *)data->client_object; + + vl53l1_dbgmsg("Enter\n"); + mutex_lock(&data->work_mutex); + /* main driver cleanup */ + stmvl53l1_cleanup(data); + + rc = stmvl53l1_disable_pinctrl(); + if (rc){ + vl53l1_errmsg("fatal,fail to disable pinctrl,rc = %d", rc); + } + rc = stmvl53l1_release_pinctrl(&(pdev->dev)); + if (rc){ + vl53l1_errmsg("fatal,fail to release pinctrl,rc = %d", rc); + } + + /* release gpios */ + stmvl53l1_release_gpios(i2c_data); + + mutex_unlock(&data->work_mutex); + + stmvl53l1_put(data->client_object); + + vl53l1_dbgmsg("End\n"); + + return 0; +} + +static const struct of_device_id stmvl53l1_driver_dt_match[] = { + {.compatible = "st,stmvl53l1"}, + {} +}; + +MODULE_DEVICE_TABLE(of, stmvl53l1_driver_dt_match); + +static struct platform_driver stmvl53l1_platform_driver = { + .probe = stmvl53l1_probe_cci, + .driver = { + .name = "st,stmvl53l1", + .owner = THIS_MODULE, + .of_match_table = stmvl53l1_driver_dt_match, + }, + .remove = stmvl53l1_remove_cci, +}; + +int __init stmvl53l1_init_cci(void) +{ + int32_t rc = 0; + vl53l1_dbgmsg("enter\n"); + rc = platform_driver_register(&stmvl53l1_platform_driver); + if (rc < 0) { + vl53l1_dbgmsg("platform_driver_register fail\n"); + return rc; + } + + return rc; +} + +void __exit stmvl53l1_exit_cci(void* obj) +{ + vl53l1_dbgmsg("enter\n"); + platform_driver_unregister(&stmvl53l1_platform_driver); +} + diff --git a/drivers/input/misc/vl53L1/kona/stmvl53l1_module-i2c.c b/drivers/input/misc/vl53L1/kona/stmvl53l1_module-i2c.c new file mode 100644 index 000000000000..546096ed09a8 --- /dev/null +++ b/drivers/input/misc/vl53L1/kona/stmvl53l1_module-i2c.c @@ -0,0 +1,946 @@ +/************************************************************************** + * Copyright (c) 2016, STMicroelectronics - All Rights Reserved + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ****************************************************************************/ + +/** + * @file stmvl53l1_module-i2c.c + * + * implement STM VL53L1 module interface i2c wrapper + control + * using linux native i2c + gpio + reg api + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * power specific includes + */ +#include +#include +#include +#include +#include +#include + +#include "stmvl53l1-i2c.h" +#include "stmvl53l1.h" +#include "cam_cci_ctrl_interface.h" + +#define STMVL53L1_SLAVE_ADDR (0x52>>1) +#define IGNORE_IRQ 0 //songyt add +/** @ingroup drv_port + * @{ + */ + +/** + * control specific debug message echo + * + * Set to 0/1 do not remove + * + * most dbg warn err messages goes true main driver macro + * this one permit some specific debug without activating all main dbg + */ +#define MODI2C_DEBUG 0 + +/* + * mutex to handle device i2c address changes. It allow to avoid multiple + * device active with same i2c addresses at the same time. Note that we don't + * support case where boot_reg has the same value as a final i2c address of + * another device. + */ +static DEFINE_MUTEX(dev_addr_change_mutex); + +/** + * i2c client assigned to our driver + * + * this is use for stm test purpose as we fake client create and regstration + * we stores the i2c client for release in clean-up overwise we wan't reload + * the module multiple time + * + * in a normal dev tree prod system this is not required + */ +static struct i2c_client *stm_test_i2c_client; + +/* + * pi3: + * insmod stmvl53l1.ko force_device=1 adapter_nb=1 xsdn_gpio_nb=19 + * intr_gpio_nb=16 pwren_gpio_nb=12 + * + * panda + * insmod stmvl53l1.ko force_device=1 adapter_nb=4 xsdn_gpio_nb=56 + * intr_gpio_nb=59 pwren_gpio_nb=55 +*/ + +static int force_device; +static int adapter_nb = -1; +static int xsdn_gpio_nb = -1; +static int pwren_gpio_nb = -1; +static int intr_gpio_nb = -1; + +module_param(force_device, int, 0000); +MODULE_PARM_DESC(force_device, "force device insertion at module init"); + +module_param(adapter_nb, int, 0000); +MODULE_PARM_DESC(adapter_nb, "i2c adapter to use"); + +module_param(xsdn_gpio_nb, int, 0000); +MODULE_PARM_DESC(xsdn_gpio_nb, "select gpio numer to use for vl53l1 reset"); + +module_param(pwren_gpio_nb, int, 0000); +MODULE_PARM_DESC(pwren_gpio_nb, "select gpio numer to use for vl53l1 power"); + +module_param(intr_gpio_nb, int, 0000); +MODULE_PARM_DESC(intr_gpio_nb, "select gpio numer to use for vl53l1 interrupt"); + +/** + * warn message + * + * @warning use only in scope where i2c_data ptr is present + **/ +#define modi2c_warn(fmt, ...)\ + dev_WARN(&i2c_data->client->dev, fmt, ##__VA_ARGS__) + +/** + * err message + * + * @warning use only in scope where i2c_data ptr is present + */ +#define modi2c_err(fmt, ...)\ + dev_err(&i2c_data->client->dev, fmt, ##__VA_ARGS__) + + + +#if MODI2C_DEBUG +# define modi2c_dbg(fmt, ...)\ + pr_devel("%s "fmt"\n", __func__, ##__VA_ARGS__) +#else +# define modi2c_dbg(...) (void)0 +#endif + +static int insert_device(void) +{ + int ret = 0; + struct i2c_adapter *adapter; + struct i2c_board_info info = { + .type = "stmvl53l1", + .addr = STMVL53L1_SLAVE_ADDR, + }; + + memset(&info, 0, sizeof(info)); + strcpy(info.type, "stmvl53l1"); + info.addr = STMVL53L1_SLAVE_ADDR; + adapter = i2c_get_adapter(adapter_nb); + if (!adapter) { + ret = -EINVAL; + goto done; + } + stm_test_i2c_client = i2c_new_device(adapter, &info); + if (!stm_test_i2c_client) + ret = -EINVAL; + +done: + return ret; +} + +static int get_xsdn(struct device *dev, struct i2c_data *i2c_data) +{ + int rc = 0; + + i2c_data->io_flag.xsdn_owned = 0; + if (i2c_data->xsdn_gpio == -1) { + vl53l1_errmsg("reset gpio is required"); + rc = -ENODEV; + goto no_gpio; + } + + vl53l1_dbgmsg("request xsdn_gpio %d", i2c_data->xsdn_gpio); + rc = gpio_request(i2c_data->xsdn_gpio, "vl53l1_xsdn"); + if (rc) { + vl53l1_errmsg("fail to acquire xsdn %d", rc); + goto request_failed; + } + + rc = gpio_direction_output(i2c_data->xsdn_gpio, 0); + if (rc) { + vl53l1_errmsg("fail to configure xsdn as output %d", rc); + goto direction_failed; + } + i2c_data->io_flag.xsdn_owned = 1; + + return rc; + +direction_failed: + gpio_free(i2c_data->xsdn_gpio); + +request_failed: +no_gpio: + return rc; +} + +static void put_xsdn(struct i2c_data *i2c_data) +{ + if (i2c_data->io_flag.xsdn_owned) { + vl53l1_dbgmsg("release xsdn_gpio %d", i2c_data->xsdn_gpio); + gpio_free(i2c_data->xsdn_gpio); + i2c_data->io_flag.xsdn_owned = 0; + i2c_data->xsdn_gpio = -1; + } + i2c_data->xsdn_gpio = -1; +} + +static int get_pwren(struct device *dev, struct i2c_data *i2c_data) +{ + int rc = 0; + + i2c_data->io_flag.pwr_owned = 0; + if (i2c_data->pwren_gpio == -1) { + vl53l1_wanrmsg("pwren gpio disable"); + goto no_gpio; + } + + vl53l1_dbgmsg("request pwren_gpio %d", i2c_data->pwren_gpio); + rc = gpio_request(i2c_data->pwren_gpio, "vl53l1_pwren"); + if (rc) { + vl53l1_errmsg("fail to acquire pwren %d", rc); + goto request_failed; + } + + rc = gpio_direction_output(i2c_data->pwren_gpio, 0); + if (rc) { + vl53l1_errmsg("fail to configure pwren as output %d", rc); + goto direction_failed; + } + i2c_data->io_flag.pwr_owned = 1; + + return rc; + +direction_failed: + gpio_free(i2c_data->xsdn_gpio); + +request_failed: +no_gpio: + return rc; +} + +static void put_pwren(struct i2c_data *i2c_data) +{ + if (i2c_data->io_flag.pwr_owned) { + vl53l1_dbgmsg("release pwren_gpio %d", i2c_data->pwren_gpio); + gpio_free(i2c_data->pwren_gpio); + i2c_data->io_flag.pwr_owned = 0; + i2c_data->pwren_gpio = -1; + } + i2c_data->pwren_gpio = -1; +} + +static int get_intr(struct device *dev, struct i2c_data *i2c_data) +{ + int rc = 0; + + i2c_data->io_flag.intr_owned = 0; + if (i2c_data->intr_gpio == -1) { + vl53l1_wanrmsg("no interrupt gpio"); + goto no_gpio; + } + + vl53l1_dbgmsg("request intr_gpio %d", i2c_data->intr_gpio); + rc = gpio_request(i2c_data->intr_gpio, "vl53l1_intr"); + if (rc) { + vl53l1_errmsg("fail to acquire intr %d", rc); + goto request_failed; + } + + rc = gpio_direction_input(i2c_data->intr_gpio); + if (rc) { + vl53l1_errmsg("fail to configure intr as input %d", rc); + goto direction_failed; + } + + i2c_data->irq = gpio_to_irq(i2c_data->intr_gpio); + if (i2c_data->irq < 0) { + vl53l1_errmsg("fail to map GPIO: %d to interrupt:%d\n", + i2c_data->intr_gpio, i2c_data->irq); + goto irq_failed; + } + i2c_data->io_flag.intr_owned = 1; + + return rc; + +irq_failed: +direction_failed: + gpio_free(i2c_data->intr_gpio); + +request_failed: +no_gpio: + return rc; +} + +static void put_intr(struct i2c_data *i2c_data) +{ + if (i2c_data->io_flag.intr_owned) { + if (i2c_data->io_flag.intr_started) { + free_irq(i2c_data->irq, i2c_data); + i2c_data->io_flag.intr_started = 0; + } + vl53l1_dbgmsg("release intr_gpio %d", i2c_data->intr_gpio); + gpio_free(i2c_data->intr_gpio); + i2c_data->io_flag.intr_owned = 0; + } + i2c_data->intr_gpio = -1; +} + +int get_version(struct device *dev, struct i2c_data *i2c_data) +{ + int rc = 0; + int gpio_val = -1; + if (i2c_data->ver_gpio== -1) { + vl53l1_wanrmsg("version gpio disable"); + goto no_gpio; + } + + vl53l1_errmsg("request version_gpio %d", i2c_data->ver_gpio); + rc = gpio_request(i2c_data->ver_gpio, "version_gpio"); + if (rc) { + vl53l1_errmsg("fail to acquire version_gpio %d", rc); + goto request_failed; + } + + gpio_val = gpio_get_value(i2c_data->ver_gpio); + vl53l1_errmsg("get version_gpio val: %d", gpio_val); + + gpio_free(i2c_data->ver_gpio); + +request_failed: +no_gpio: + return gpio_val; +} + +/** + * parse dev tree for all platform specific input + */ +int stmvl53l1_parse_tree(struct device *dev, struct i2c_data *i2c_data) +{ + int rc = 0; + enum of_gpio_flags flags; + /* if force device is in use then gpio nb comes from module param else + * we use devicetree. + */ + i2c_data->vdd = NULL; + i2c_data->xsd = NULL; + i2c_data->pwren_gpio = -1; + i2c_data->xsdn_gpio = -1; + i2c_data->intr_gpio = -1; + i2c_data->boot_reg = STMVL53L1_SLAVE_ADDR; + if (force_device) { + i2c_data->xsdn_gpio = xsdn_gpio_nb; + i2c_data->pwren_gpio = pwren_gpio_nb; + i2c_data->intr_gpio = intr_gpio_nb; + } else if (dev->of_node) { + /* power : either vdd or pwren_gpio. try reulator first */ + i2c_data->vdd = regulator_get(dev, "laser_vdd"); + if (IS_ERR(i2c_data->vdd) || i2c_data->vdd == NULL) { + i2c_data->vdd = NULL; + vl53l1_wanrmsg( + "no laser_vdd, fatal."); + } + i2c_data->xsd = regulator_get(dev, "laser_xsd"); + if (IS_ERR(i2c_data->xsd) || i2c_data->xsd == NULL) { + i2c_data->xsd = NULL; + vl53l1_wanrmsg( + "no laser_xsd, fatal."); + } + i2c_data->pwren_gpio = of_get_named_gpio_flags(dev->of_node, "pwren-gpio", 0, + &flags); + if (gpio_is_valid(i2c_data->pwren_gpio)) { + vl53l1_dbgmsg("pwren-gpio %d", + i2c_data->pwren_gpio); + } else { + vl53l1_wanrmsg( + "no regulator, nor power gpio => power ctrl disabled"); + i2c_data->pwren_gpio = -1; + } + i2c_data->xsdn_gpio = of_get_named_gpio_flags(dev->of_node, "xsdn-gpio", 0, + &flags); + if (gpio_is_valid(i2c_data->xsdn_gpio)) { + vl53l1_dbgmsg("xsdn-gpio %d", + i2c_data->xsdn_gpio); + } else { + vl53l1_wanrmsg("Unable to find xsdn-gpio %d", + i2c_data->xsdn_gpio); + i2c_data->xsdn_gpio = -1; + } + i2c_data->ver_gpio = of_get_named_gpio_flags(dev->of_node, "ver-gpio", 0, + &flags); + if (gpio_is_valid(i2c_data->ver_gpio)) { + vl53l1_dbgmsg("version-gpio %d", + i2c_data->ver_gpio); + } else { + vl53l1_wanrmsg("Unable to find version-gpio %d", + i2c_data->ver_gpio); + i2c_data->ver_gpio = -1; + } + +#if IGNORE_IRQ + i2c_data->intr_gpio = -1; + vl53l1_dbgmsg("do not use intr-gpio!"); +#else + i2c_data->intr_gpio = of_get_named_gpio_flags(dev->of_node, "intr-gpio", 0,&flags); + if (gpio_is_valid(i2c_data->intr_gpio)) { + vl53l1_dbgmsg("intr-gpio %d", + i2c_data->intr_gpio); + } else { + vl53l1_wanrmsg("Unable to find intr-gpio %d", + i2c_data->intr_gpio); + i2c_data->intr_gpio = -1; + } +#endif + } + + /* configure gpios */ + rc = get_xsdn(dev, i2c_data); + if (rc) + goto no_xsdn; + if(i2c_data->pwren_gpio != -1){ + rc = get_pwren(dev, i2c_data); + if (rc) + goto no_pwren; + } + rc = get_intr(dev, i2c_data); + if (rc){ + vl53l1_errmsg("get_intr failed."); + goto no_intr; + } + return rc; + +no_intr: +#if IGNORE_IRQ + return 0; +#else + if (i2c_data->vdd) { + regulator_put(i2c_data->vdd); + i2c_data->vdd = NULL; + } + put_pwren(i2c_data); +#endif +no_pwren: + if (i2c_data->xsd) { + regulator_put(i2c_data->xsd); + i2c_data->xsd = NULL; + } + + put_xsdn(i2c_data); +no_xsdn: + return rc; +} + +void stmvl53l1_release_gpios(struct i2c_data *i2c_data) +{ + if (i2c_data->xsd) { + regulator_put(i2c_data->xsd); + i2c_data->xsd = NULL; + } + put_xsdn(i2c_data); + if (i2c_data->vdd) { + regulator_put(i2c_data->vdd); + i2c_data->vdd = NULL; + } + put_pwren(i2c_data); + put_intr(i2c_data); +} + +static int stmvl53l1_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int rc = 0; + struct stmvl53l1_data *vl53l1_data = NULL; + struct i2c_data *i2c_data = NULL; + + vl53l1_dbgmsg("Enter %s : 0x%02x\n", client->name, client->addr); + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE)) { + rc = -EIO; + return rc; + } + + vl53l1_data = kzalloc(sizeof(struct stmvl53l1_data), GFP_KERNEL); + if (!vl53l1_data) { + rc = -ENOMEM; + return rc; + } + if (vl53l1_data) { + vl53l1_data->client_object = + kzalloc(sizeof(struct i2c_data), GFP_KERNEL); + if (!vl53l1_data) + goto done_freemem; + i2c_data = (struct i2c_data *)vl53l1_data->client_object; + } + i2c_data->client = client; + i2c_data->vl53l1_data = vl53l1_data; + i2c_data->irq = -1 ; /* init to no irq */ + + /* parse and configure hardware */ + rc = stmvl53l1_parse_tree(&i2c_data->client->dev, i2c_data); + if (rc) + goto done_freemem; + + /* setup device name */ + /* vl53l1_data->dev_name = dev_name(&client->dev); */ + + /* setup client data */ + i2c_set_clientdata(client, vl53l1_data); + + /* end up by core driver setup */ + rc = stmvl53l1_setup(vl53l1_data); + if (rc) + goto release_gpios; + vl53l1_dbgmsg("End\n"); + + kref_init(&i2c_data->ref); + + return rc; + +release_gpios: + stmvl53l1_release_gpios(i2c_data); + +done_freemem: + /* kfree safe against NULL */ + kfree(vl53l1_data); + kfree(i2c_data); + + return -1; +} + +static int stmvl53l1_remove(struct i2c_client *client) +{ + struct stmvl53l1_data *data = i2c_get_clientdata(client); + struct i2c_data *i2c_data = (struct i2c_data *)data->client_object; + + vl53l1_dbgmsg("Enter\n"); + mutex_lock(&data->work_mutex); + /* main driver cleanup */ + stmvl53l1_cleanup(data); + + /* release gpios */ + stmvl53l1_release_gpios(i2c_data); + + mutex_unlock(&data->work_mutex); + + stmvl53l1_put(data->client_object); + + vl53l1_dbgmsg("End\n"); + + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int stmvl53l1_suspend(struct device *dev) +{ + struct stmvl53l1_data *data = i2c_get_clientdata(to_i2c_client(dev)); + + vl53l1_dbgmsg("Enter\n"); + mutex_lock(&data->work_mutex); + /* Stop ranging */ + stmvl53l1_pm_suspend_stop(data); + + mutex_unlock(&data->work_mutex); + + vl53l1_dbgmsg("End\n"); + + return 0; +} + +static int stmvl53l1_resume(struct device *dev) +{ +#if 0 + struct stmvl53l1_data *data = i2c_get_clientdata(to_i2c_client(dev)); + + vl53l1_dbgmsg("Enter\n"); + + mutex_lock(&data->work_mutex); + + /* do nothing user will restart measurements */ + + mutex_unlock(&data->work_mutex); + + vl53l1_dbgmsg("End\n"); +#else + vl53l1_dbgmsg("Enter\n"); + vl53l1_dbgmsg("End\n"); +#endif + return 0; +} +#endif + + +static SIMPLE_DEV_PM_OPS(stmvl53l1_pm_ops, stmvl53l1_suspend, stmvl53l1_resume); + +static const struct i2c_device_id stmvl53l1_id[] = { + { STMVL53L1_DRV_NAME, 0 }, + { }, +}; +MODULE_DEVICE_TABLE(i2c, stmvl53l1_id); + +static const struct of_device_id st_stmvl53l1_dt_match[] = { + { .compatible = "st,"STMVL53L1_DRV_NAME, }, + { }, +}; + +static struct i2c_driver stmvl53l1_driver = { + .driver = { + .name = STMVL53L1_DRV_NAME, + .owner = THIS_MODULE, + .of_match_table = st_stmvl53l1_dt_match, + .pm = &stmvl53l1_pm_ops, + }, + .probe = stmvl53l1_probe, + .remove = stmvl53l1_remove, + .id_table = stmvl53l1_id, + +}; + +/** + * give power to device + * + * @param object the i2c layer object + * @return + */ +int stmvl53l1_power_up_i2c(void *object) +{ + int rc = 0; + struct i2c_data *data = (struct i2c_data *) object; + + vl53l1_dbgmsg("Enter\n"); + + /* turn on power */ + if (data->vdd) { + rc = regulator_enable(data->vdd); + if (rc) { + vl53l1_errmsg("fail to turn on regulator"); + return rc; + } + } + if (data->pwren_gpio != -1) { + gpio_set_value(data->pwren_gpio, 1); + vl53l1_info("slow power on"); + } else + vl53l1_wanrmsg("no power control"); + + if (data->xsd) { + rc = regulator_enable(data->xsd); + if (rc) { + vl53l1_errmsg("fail to turn on regulator"); + return rc; + } + } + if (data->xsdn_gpio != -1) { + gpio_set_value(data->xsdn_gpio, 1); + vl53l1_info("slow power on"); + } else + vl53l1_wanrmsg("no power control"); + + + return rc; +} + +/** + * remove power to device (reset it) + * + * @param i2c_object the i2c layer object + * @return 0 on success + */ +int stmvl53l1_power_down_i2c(void *i2c_object) +{ + struct i2c_data *data = (struct i2c_data *) i2c_object; + int rc = 0; + + vl53l1_dbgmsg("Enter\n"); + + /* turn off power */ + if (data->vdd) { + rc = regulator_disable(data->vdd); + if (rc) + vl53l1_errmsg("reg disable failed. rc=%d\n", + rc); + } + if (data->pwren_gpio != -1) { + gpio_set_value(data->pwren_gpio, 0); + } + + if (data->xsd) { + rc = regulator_disable(data->xsd); + if (rc) + vl53l1_errmsg("reg disable failed. rc=%d\n", + rc); + } + if (data->xsdn_gpio != -1) { + gpio_set_value(data->xsdn_gpio, 0); + } + + vl53l1_dbgmsg("power off"); + + vl53l1_dbgmsg("End\n"); + + return rc; +} + +static int handle_i2c_address_device_change_lock(struct i2c_data *data) +{ + return 0; +} + +/* reset release will also handle device address change. It will avoid state + * where multiple stm53l1 are bring out of reset at the same time with the + * same boot address. + * Note that we don't manage case where boot_reg has the same value as a final + * i2c address of another device. This case is not supported and will lead + * to unpredictable behavior. + */ +static int release_reset(struct i2c_data *data) +{ + //struct i2c_client *client = (struct i2c_client *) data->client; + int rc = 0; + bool is_address_change = false;//client->addr != data->boot_reg;//songyt modify + + if (is_address_change) + mutex_lock(&dev_addr_change_mutex); + //vl53l1_dbgmsg("reset xsdn pin to 1\n"); + gpio_set_value(data->xsdn_gpio, 1); + if (is_address_change) { + rc = handle_i2c_address_device_change_lock(data); + if (rc){ + gpio_set_value(data->xsdn_gpio, 0); + //vl53l1_dbgmsg("reset xsdn pin to 0\n"); + } + } + + if (is_address_change) + mutex_unlock(&dev_addr_change_mutex); + + return rc; +} + +/** + * release device reset + * + * @param i2c_object the i2c layer object + * @return 0 on success + */ +int stmvl53l1_reset_release_i2c(void *i2c_object) +{ + int rc; + struct i2c_data *data = (struct i2c_data *) i2c_object; + + vl53l1_dbgmsg("Enter\n"); + + rc = release_reset(data); + if (rc) + goto error; + + /* and now wait for device end of boot */ + data->vl53l1_data->is_delay_allowed = true; + rc = VL53L1_WaitDeviceBooted(&data->vl53l1_data->stdev); + data->vl53l1_data->is_delay_allowed = false; + if (rc) { + gpio_set_value(data->xsdn_gpio, 0); + vl53l1_errmsg("boot fail with error %d,change xsdn pin to 0", rc); + data->vl53l1_data->last_error = rc; + rc = -EIO; + } + +error: + vl53l1_dbgmsg("End\n"); + + return rc; +} + +/** + * put device under reset + * + * @param i2c_object the i2c layer object + * @return 0 on success + */ +int stmvl53l1_reset_hold_i2c(void *i2c_object) +{ + struct i2c_data *data = (struct i2c_data *) i2c_object; + + vl53l1_dbgmsg("Enter\n"); + + gpio_set_value(data->xsdn_gpio, 0); + + vl53l1_dbgmsg("End\n"); + + return 0; +} + +int stmvl53l1_init_i2c(void) +{ + int ret = 0; + + vl53l1_dbgmsg("Enter\n"); + + /* register as a i2c client device */ + ret = i2c_add_driver(&stmvl53l1_driver); + if (ret) + vl53l1_errmsg("%d erro ret:%d\n", __LINE__, ret); + + if (!ret && force_device) + ret = insert_device(); + + if (ret) + i2c_del_driver(&stmvl53l1_driver); + + vl53l1_dbgmsg("End with rc:%d\n", ret); + + return ret; +} + + +void stmvl53l1_clean_up_i2c(void) +{ + if (stm_test_i2c_client) { + vl53l1_dbgmsg("to unregister i2c client\n"); + i2c_unregister_device(stm_test_i2c_client); + } +} + +static irqreturn_t stmvl53l1_irq_handler_i2c(int vec, void *info) +{ + struct i2c_data *i2c_data = (struct i2c_data *)info; + + if (i2c_data->irq == vec) { + modi2c_dbg("irq"); + stmvl53l1_intr_handler(i2c_data->vl53l1_data); + modi2c_dbg("over"); + } else { + if (!i2c_data->msg_flag.unhandled_irq_vec) { + modi2c_warn("unmatching vec %d != %d\n", + vec, i2c_data->irq); + i2c_data->msg_flag.unhandled_irq_vec = 1; + } + } + + return IRQ_HANDLED; +} + +/** + * enable and start intr handling + * + * @param object our i2c_data specific object + * @param poll_mode [in/out] set to force mode clear to use irq + * @return 0 on success and set ->poll_mode if it faill ranging wan't start + */ +int stmvl53l1_start_intr(void *object, int *poll_mode) +{ + struct i2c_data *i2c_data; + int rc; + + i2c_data = (struct i2c_data *)object; + /* irq and gpio acquire config done in parse_tree */ + if (i2c_data->irq < 0) { + /* the i2c tree as no intr force polling mode */ + *poll_mode = -1; + return 0; + } + /* clear irq warning report enabe it again for this session */ + i2c_data->msg_flag.unhandled_irq_vec = 0; + /* if started do no nothing */ + if (i2c_data->io_flag.intr_started) { + /* nothing to do */ + *poll_mode = 0; + return 0; + } + + vl53l1_dbgmsg("to register_irq:%d\n", i2c_data->irq); + rc = request_threaded_irq(i2c_data->irq, NULL, + stmvl53l1_irq_handler_i2c, + IRQF_TRIGGER_FALLING|IRQF_ONESHOT, + "vl53l1_interrupt", + (void *)i2c_data); + if (rc) { + vl53l1_errmsg("fail to req threaded irq rc=%d\n", rc); + *poll_mode = 0; + } else { + vl53l1_dbgmsg("irq %d now handled\n", i2c_data->irq); + i2c_data->io_flag.intr_started = 1; + *poll_mode = 0; + } + return rc; +} + +void *stmvl53l1_get(void *object) +{ + struct i2c_data *data = (struct i2c_data *) object; + + vl53l1_dbgmsg("Enter\n"); + kref_get(&data->ref); + vl53l1_dbgmsg("End\n"); + + return object; +} + +static void memory_release(struct kref *kref) +{ + struct i2c_data *data = container_of(kref, struct i2c_data, ref); + + vl53l1_dbgmsg("Enter\n"); + kfree(data->vl53l1_data); + kfree(data); + vl53l1_dbgmsg("End\n"); +} + +void stmvl53l1_put(void *object) +{ + struct i2c_data *data = (struct i2c_data *) object; + + vl53l1_dbgmsg("Enter\n"); + kref_put(&data->ref, memory_release); + vl53l1_dbgmsg("End\n"); +} + +void __exit stmvl53l1_exit_i2c(void *i2c_object) +{ + vl53l1_dbgmsg("Enter\n"); + i2c_del_driver(&stmvl53l1_driver); + vl53l1_dbgmsg("End\n"); +} diff --git a/drivers/input/misc/vl53L1/kona/stmvl53l1_module.c b/drivers/input/misc/vl53L1/kona/stmvl53l1_module.c new file mode 100644 index 000000000000..eb783f8dc121 --- /dev/null +++ b/drivers/input/misc/vl53L1/kona/stmvl53l1_module.c @@ -0,0 +1,4350 @@ +/************************************************************************** + * Copyright (c) 2016, STMicroelectronics - All Rights Reserved + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ****************************************************************************/ +/** + * @file /stmvl53l1_module.c vl53l1_module ST VL53L1 linux kernel module + * + * main file + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * API includes + */ + +#include "stmvl53l1.h" +#include "cam_cci_ctrl_interface.h" +#include "stmvl53l1-i2c.h" +#include "stmvl53l1_ipp.h" + +#include "stmvl53l1_if.h" /* our device interface to user space */ +#include "stmvl53l1_internal_if.h" + +/* + * include default tuning file + */ +#include "stmvl53l1_tunings.h" + +/** @ingroup vl53l1_config + * @{ + */ +/** + * default polling period delay in millisecond + * + * It can be set at run time via @ref vl53l1_ioctl or @ref sysfs_attrib + * + * @note apply only for device operating in polling mode only + */ +#define STMVL53L1_CFG_POLL_DELAY_MS 30 + +/** + * default timing budget in microsecond + * + * Can be change at run time via @ref vl53l1_ioctl or @ref sysfs_attrib + */ +#define STMVL53L1_CFG_TIMING_BUDGET_US 30000 //songyt test 16000 + +/** default preset ranging mode */ +#define STMVL53L1_CFG_DEFAULT_MODE VL53L1_PRESETMODE_RANGING + +/** default distance mode */ +#define STMVL53L1_CFG_DEFAULT_DISTANCE_MODE VL53L1_DISTANCEMODE_LONG + +/** default crosstalk enable */ +#define STMVL53L1_CFG_DEFAULT_CROSSTALK_ENABLE 1 + +/** default output mode */ +#define STMVL53L1_CFG_DEFAULT_OUTPUT_MODE VL53L1_OUTPUTMODE_NEAREST + +#define STMVL53L1_CFG_DEFAULT_OFFSET_CORRECTION_MODE \ + VL53L1_OFFSETCORRECTIONMODE_STANDARD + +/** default Dmax mode */ +#define STMVL53L1_CFG_DEFAULT_DMAX_MODE VL53L1_DMAXMODE_FMT_CAL_DATA + +/** default smudge correction enable value */ +#define STMVL53L1_CFG_DEFAULT_SMUDGE_CORRECTION_MODE \ + VL53L1_SMUDGE_CORRECTION_CONTINUOUS + +/** @} */ /* ingroup vl53l1_config */ + +/** @ingroup vl53l1_mod_dbg + * @{ + */ + +/** + * activate dump of roi in roi ctrl operation + * + * @note uses @a vl53l1_dbgmsg for output so make sure to enable debug + * to get roi dump + */ +#define STMVL53L1_CFG_ROI_DEBUG 1 //songyt 0 to 1 + +/** @} */ /* ingroup vl53l1_mod_dbg*/ + +/* #define DEBUG_TIME_LOG */ + + +#ifdef DEBUG_TIME_LOG +struct timeval start_tv, stop_tv; +#endif + +/* Set default value to 1 to allow to see module insertion debug messages */ +int stmvl53l1_enable_debug = 1; + +#define VL53L1_INPUT_DEVICE_NAME "STM VL53L1 proximity sensor" + +static long stmvl53l1_ioctl(struct file *file, + unsigned int cmd, unsigned long arg); +static int stmvl53l1_open(struct inode *inode, struct file *file); +static int stmvl53l1_release(struct inode *inode, struct file *file); +static int ctrl_start(struct stmvl53l1_data *data); +static int ctrl_stop(struct stmvl53l1_data *data); + +static bool force_device_on_en_default = false;//songyt change true to false + +module_param(force_device_on_en_default, bool, 0444); +MODULE_PARM_DESC(force_device_on_en_default, + "select whether force_device_on_en is true or false by default"); + +/* boilerplate for integer parameter */ +#define IMPLEMENT_PARAMETER_INTEGER(sysfs_name, info_name)\ +static ssize_t stmvl53l1_show_##sysfs_name(struct device *dev, \ + struct device_attribute *attr, char *buf) \ +{ \ + struct stmvl53l1_data *data = dev_get_drvdata(dev); \ + int param; \ +\ + mutex_lock(&data->work_mutex); \ + param = data->sysfs_name; \ + mutex_unlock(&data->work_mutex);; \ +\ + return scnprintf(buf, PAGE_SIZE, "%d\n", param); \ +} \ +\ +static ssize_t stmvl53l1_store_##sysfs_name(struct device *dev, \ + struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + struct stmvl53l1_data *data = dev_get_drvdata(dev); \ + int rc; \ + int param; \ +\ + mutex_lock(&data->work_mutex); \ +\ + if (kstrtoint(buf, 0, ¶m)) { \ + vl53l1_errmsg("invalid syntax in %s", buf); \ + rc = -EINVAL; \ + } else \ + rc = stmvl53l1_set_##sysfs_name(data, param); \ +\ + mutex_unlock(&data->work_mutex); \ +\ + return rc ? rc : count; \ +} \ +\ +static int ctrl_param_##sysfs_name(struct stmvl53l1_data *data, \ + struct stmvl53l1_parameter *param) \ +{ \ + int rc; \ +\ + if (param->is_read) { \ + param->value = data->sysfs_name; \ + param->status = 0; \ + vl53l1_dbgmsg("get " info_name " %d", param->value); \ + rc = 0; \ + } else { \ + rc = stmvl53l1_set_##sysfs_name(data, param->value); \ + vl53l1_dbgmsg("rc %d req %d now %d", rc, \ + param->value, data->sysfs_name); \ + } \ +\ + return rc; \ +} + +/** + * module interface struct + * interface to platform speficic device handling , concern power/reset ... + */ +struct stmvl53l1_module_fn_t { + int (*init)(void); /*!< init */ + /** + * clean up job + * @param data module specific data ptr + */ + void (*deinit)(void *data); + /** + * give device power + * @param data specific module storage ptr + * @return 0 on sucess + */ + int (*power_up)(void *data); + /** + * power down TOFO also stop intr + */ + int (*power_down)(void *data); + /* + * release reset so device start. + */ + int (*reset_release)(void *data); + /* + * put device under reset. + */ + int (*reset_hold)(void *data); + + /** + * enable interrupt + * + * @param object : interface speficic ptr + * @note "module specfic ptr is data->client_object + * @return 0 on success else error then drievr wan't start ranging! + * if no interrupt or it can't be hooked but still to operated in poll + * mode then return 0 and force data->poll_mode + * might have to clear poll_mode exlplcilty if to operate in real intr + * mode as pool mode + * is the default + */ + int (*start_intr)(void *object, int *poll_mode); + + void (*clean_up)(void); /*!< optional can be void */ + + /* increment reference counter */ + void *(*get)(void *object); + + /* decrement reference counter and deallocate memory when zero */ + void (*put)(void *object); +}; + +/** i2c module interface*/ +static struct stmvl53l1_module_fn_t stmvl53l1_module_func_tbl = { +#ifdef USE_CAMERA_CCI + .init = stmvl53l1_init_cci, + .deinit = stmvl53l1_exit_cci, +#else + .init = stmvl53l1_init_i2c, + .deinit = stmvl53l1_exit_i2c, +#endif + .power_up = stmvl53l1_power_up_i2c, + .power_down = stmvl53l1_power_down_i2c, + .reset_release = stmvl53l1_reset_release_i2c, + .reset_hold = stmvl53l1_reset_hold_i2c, + .clean_up = stmvl53l1_clean_up_i2c, + .start_intr = stmvl53l1_start_intr, + .get = stmvl53l1_get, + .put = stmvl53l1_put, +}; +static bool ipp_inited = false; + + +#ifndef MIN +# define MIN(a, b) ((a) < (b) ? (a) : (b)) +#endif + +/* + * INPUT Subsys interface + */ + +static void stmvl53l1_input_push_data(struct stmvl53l1_data *data); + +/* + * Mutex to handle device id add/removal + */ +static DEFINE_MUTEX(dev_table_mutex); + +/** + * in-used device LUT + * we need this as the message reception from netlink message can't + * associate directly to a device instance that is as we look up id + * to device data structure + */ +struct stmvl53l1_data *stmvl53l1_dev_table[STMVL53L1_CFG_MAX_DEV]; + +/** + * Misc device device operations + */ +static const struct file_operations stmvl53l1_ranging_fops = { + .owner = THIS_MODULE, + .unlocked_ioctl = stmvl53l1_ioctl, + .open = stmvl53l1_open, + .release = stmvl53l1_release, + /* .flush = stmvl53l0_flush, */ +}; + +static int store_last_error(struct stmvl53l1_data *data, int rc) +{ + data->last_error = rc; + + return -EIO; +} + +static int allocate_dev_id(void) +{ + int i; + + mutex_lock(&dev_table_mutex); + + for (i = 0; i < STMVL53L1_CFG_MAX_DEV; i++) + if (!stmvl53l1_dev_table[i]) + break; + i = i < STMVL53L1_CFG_MAX_DEV ? i : -1; + + mutex_unlock(&dev_table_mutex); + + return i; +} + +static void deallocate_dev_id(int id) +{ + mutex_lock(&dev_table_mutex); + + stmvl53l1_dev_table[id] = NULL; + + mutex_unlock(&dev_table_mutex); +} + +/* helpers to manage reader list for blockint ioctl */ +/* call them with lock */ +static void empty_and_free_list(struct list_head *head) +{ + struct stmvl53l1_waiters *waiter; + struct stmvl53l1_waiters *tmp; + + list_for_each_entry_safe(waiter, tmp, head, list) { + list_del(&waiter->list); + kfree(waiter); + } +} + +static int add_reader(pid_t pid, struct list_head *head) +{ + struct stmvl53l1_waiters *new_waiter; + + new_waiter = kmalloc(sizeof(struct stmvl53l1_waiters), GFP_KERNEL); + if (!new_waiter) + return -ENOMEM; + new_waiter->pid = pid; + list_add(&new_waiter->list, head); + + return 0; +} + +static bool is_pid_in_list(pid_t pid, struct list_head *head) +{ + struct stmvl53l1_waiters *waiter; + + list_for_each_entry(waiter, head, list) + if (waiter->pid == pid) + return true; + + return false; +} + +static void wake_up_data_waiters(struct stmvl53l1_data *data) +{ + empty_and_free_list(&data->simple_data_reader_list); + empty_and_free_list(&data->mz_data_reader_list); + wake_up(&data->waiter_for_data); +} + +static void stmvl53l1_insert_flush_events_lock(struct stmvl53l1_data *data) +{ + while (data->flush_todo_counter) { + data->flushCount++; + input_report_abs(data->input_dev_ps, ABS_GAS, data->flushCount); + input_sync(data->input_dev_ps); + vl53l1_dbgmsg("Sensor HAL Flush Count = %u\n", + data->flushCount); + data->flush_todo_counter--; + } +} + +static int reset_release(struct stmvl53l1_data *data) +{ + int rc; +#ifdef USE_CAMERA_CCI + struct camera_cci_transfer ccit; +#endif + + if (!data->reset_state) + return 0; +#ifdef USE_CAMERA_CCI + memset(&ccit,0,sizeof(ccit)); + ccit.cmd = CAMERA_CCI_INIT; + cam_cci_control_interface(&ccit); +#endif + + rc = stmvl53l1_module_func_tbl.reset_release(data->client_object); + if (rc){ + vl53l1_errmsg("reset release fail rc=%d try to release cci\n", rc); +#ifdef USE_CAMERA_CCI + memset(&ccit,0,sizeof(ccit)); + ccit.cmd = CAMERA_CCI_RELEASE; + cam_cci_control_interface(&ccit); +#endif + }else + data->reset_state = 0; + + return rc; +} + +static int reset_hold(struct stmvl53l1_data *data) +{ + int rc; +#ifdef USE_CAMERA_CCI + struct camera_cci_transfer ccit; +#endif + if (data->reset_state) + return 0; + + if (data->force_device_on_en) + return 0; + + rc = stmvl53l1_module_func_tbl.reset_hold(data->client_object); + if (!rc) + data->reset_state = 1; +#ifdef USE_CAMERA_CCI + memset(&ccit,0,sizeof(ccit)); + ccit.cmd = CAMERA_CCI_RELEASE; + cam_cci_control_interface(&ccit); +#endif + + return rc; +} + +#ifdef DEBUG_TIME_LOG +static void stmvl53l0_DebugTimeGet(struct timeval *ptv) +{ + do_gettimeofday(ptv); +} + +#endif + +/** + * + * @param pstart_tv time val starting point + * @param pstop_tv time val end point + * @return time dif in usec + */ +long stmvl53l1_tv_dif(struct timeval *pstart_tv, struct timeval *pstop_tv) +{ + long total_sec, total_usec; + + total_sec = pstop_tv->tv_sec - pstart_tv->tv_sec; + total_usec = (pstop_tv->tv_usec - pstart_tv->tv_usec); + + return total_sec*1000000+total_usec; +} + +#if STMVL53L1_CFG_ROI_DEBUG +static void dump_roi(VL53L1_UserRoi_t *rois, uint32_t n) +{ + uint32_t i; + + vl53l1_dbgmsg("roi dump %d roi:\n", n); + for (i = 0; i < n ; i++) { + vl53l1_dbgmsg("ROI#%02d %2d %2d %2d %2d\n", (int)i, + (int)rois[i].TopLeftX, (int)rois[i].TopLeftY, + (int)rois[i].BotRightX, (int)rois[i].BotRightY); + } +} +#else +# define dump_roi(...) (void)0 +#endif + +static int setup_tunings(struct stmvl53l1_data *data) +{ + int rc = 0; + int i, size; + size = (int)ARRAY_SIZE(tunings); + if (size > 0) { + for (i = 0; i < size; i++) { + rc = VL53L1_SetTuningParameter(&data->stdev, tunings[i][0], + tunings[i][1]); + if (rc) { + rc = store_last_error(data, rc); + break; + } + } + } + return rc; +} + +/** + * + * @param data device data + * @return non 0 if current "preset mode" is a multi zone one + */ +static int is_mz_mode(struct stmvl53l1_data *data) +{ + return data->preset_mode == VL53L1_PRESETMODE_RANGING || + data->preset_mode == VL53L1_PRESETMODE_MULTIZONES_SCANNING; +} + +static void kill_mz_data(VL53L1_MultiRangingData_t *pdata) +{ + int i; + + memset(pdata, 0, sizeof(*pdata)); + for (i = 0; i < VL53L1_MAX_RANGE_RESULTS; i++) + pdata->RangeData[i].RangeStatus = VL53L1_RANGESTATUS_NONE; + pdata->RoiStatus = VL53L1_ROISTATUS_NOT_VALID; +} + +static void stmvl53l1_setup_auto_config(struct stmvl53l1_data *data) +{ + /* default config is detect object below 300mm with 1s period */ + data->auto_pollingTimeInMs = 1000; + data->auto_config.DetectionMode = VL53L1_DETECTION_DISTANCE_ONLY; + data->auto_config.IntrNoTarget = 0; + data->auto_config.Distance.CrossMode = VL53L1_THRESHOLD_CROSSED_LOW; + data->auto_config.Distance.High = 1000; + data->auto_config.Distance.Low = 300; + data->auto_config.Rate.CrossMode = VL53L1_THRESHOLD_CROSSED_LOW; + data->auto_config.Rate.High = 0; + data->auto_config.Rate.Low = 0; +} + +static uint32_t stmvl53l1_compute_hash(VL53L1_RoiConfig_t *roi_cfg) +{ + return jhash(roi_cfg->UserRois, + roi_cfg->NumberOfRoi * sizeof(VL53L1_UserRoi_t), + roi_cfg->NumberOfRoi); +} + +static int stmvl53l1_check_calibration_id(struct stmvl53l1_data *data) +{ + uint32_t roi_id; + int rc; + + if (data->offset_correction_mode != VL53L1_OFFSETCORRECTIONMODE_PERZONE) + return 0; + if (data->current_roi_id == 0) + return 0; + + roi_id = stmvl53l1_compute_hash(&data->roi_cfg); + rc = roi_id == data->current_roi_id ? 0 : -EINVAL; + + if (rc) + vl53l1_errmsg( + "Mismatch in zone calibration data 0x%08x != 0x%08x", + roi_id, data->current_roi_id); + + return rc; +} + +/** + * send params to sensor + * + * @warning must be used if only stopped + * @param data device data + * @return 0 on sucess + */ +static int stmvl53l1_sendparams(struct stmvl53l1_data *data) +{ + int rc; + + /* activated stored or last request defined mode */ + rc = VL53L1_SetPresetMode(&data->stdev, data->preset_mode); + if (rc) { + vl53l1_errmsg("VL53L1_SetPresetMode %d fail %d", + data->preset_mode, rc); + rc = store_last_error(data, rc); + goto done; + } + + rc = VL53L1_SetXTalkCompensationEnable(&data->stdev, + data->crosstalk_enable); + if (rc) { + vl53l1_errmsg("VL53L1_SetXTalkCompensationEnable %d fail %d", + data->crosstalk_enable, rc); + rc = store_last_error(data, rc); + goto done; + } + + /* apply distance mode only in lite and standard ranging */ + rc = VL53L1_SetDistanceMode(&data->stdev, data->distance_mode); + if (rc) { + vl53l1_errmsg("VL53L1_SetDistanceMode %d fail %d", + data->distance_mode, rc); + rc = store_last_error(data, rc); + goto done; + } + + /* apply timing budget */ + rc = VL53L1_SetMeasurementTimingBudgetMicroSeconds(&data->stdev, + data->timing_budget); + if (rc) { + vl53l1_errmsg("SetTimingBudget %d fail %d", + data->timing_budget, rc); + rc = store_last_error(data, rc); + goto done; + } + vl53l1_dbgmsg("timing budget @%d\n", data->timing_budget); + + /* apply offset correction mode */ + rc = VL53L1_SetOffsetCorrectionMode(&data->stdev, + data->offset_correction_mode); + if (rc) { + vl53l1_errmsg("offset correction mode %d fail %d", + data->offset_correction_mode, rc); + rc = store_last_error(data, rc); + goto done; + } + vl53l1_dbgmsg("offset correction mode @%d\n", + data->offset_correction_mode); + + /* check zone calibration vs roi */ + rc = stmvl53l1_check_calibration_id(data); + if (rc) + goto done; + + /* apply Dmax reflectance */ + rc = VL53L1_SetDmaxReflectance(&data->stdev, data->dmax_reflectance); + if (rc) { + vl53l1_errmsg("dmax relectance %d fail %d", + data->dmax_reflectance, rc); + rc = store_last_error(data, rc); + goto done; + } + vl53l1_dbgmsg("dmax reflectance @%d\n", data->dmax_reflectance); + + /* apply Dmax mode */ + rc = VL53L1_SetDmaxMode(&data->stdev, data->dmax_mode); + if (rc) { + vl53l1_errmsg("dmax mode %d fail %d", data->dmax_mode, rc); + rc = store_last_error(data, rc); + goto done; + } + vl53l1_dbgmsg("dmax mode @%d\n", data->dmax_mode); + + /* apply smudge correction enable */ + rc = VL53L1_SmudgeCorrectionEnable(&data->stdev, + data->smudge_correction_mode); + if (rc) { + vl53l1_errmsg("smudge correction mode %d fail %d", + data->smudge_correction_mode, rc); + rc = store_last_error(data, rc); + goto done; + } + vl53l1_dbgmsg("smudge correction mode @%d\n", + data->smudge_correction_mode); + + /* apply roi if any set */ + if (data->roi_cfg.NumberOfRoi) { + rc = VL53L1_SetROI(&data->stdev, &data->roi_cfg); + if (rc) { + vl53l1_errmsg("VL53L1_SetROI fail %d\n", rc); + rc = store_last_error(data, rc); + goto done; + } + vl53l1_dbgmsg("#%d custom ROI set status\n", + data->roi_cfg.NumberOfRoi); + } else { + vl53l1_dbgmsg("using default ROI\n"); + } + + /* set autonomous mode configuration */ + if ((data->preset_mode == VL53L1_PRESETMODE_AUTONOMOUS) || + (data->preset_mode == VL53L1_PRESETMODE_LOWPOWER_AUTONOMOUS)) { + rc = VL53L1_SetInterMeasurementPeriodMilliSeconds(&data->stdev, + data->auto_pollingTimeInMs); + if (rc) { + vl53l1_errmsg("Fail to set auto period %d\n", rc); + rc = store_last_error(data, rc); + goto done; + } + rc = VL53L1_SetThresholdConfig(&data->stdev, + &data->auto_config); + if (rc) { + vl53l1_errmsg("Fail to set auto config %d\n", rc); + rc = store_last_error(data, rc); + goto done; + } + } + +done: + + return rc; +} + +/** + * start sensor + * + * @warning must be used if only stopped + * @param data device data + * @return 0 on sucess + */ +static int stmvl53l1_start(struct stmvl53l1_data *data) +{ + int rc; + + data->is_first_irq = true; + data->is_data_valid = false; + data->is_xtalk_value_changed = false; +#ifdef USE_CAMERA_CCI + stmvl53l1_enable_pinctrl(); +#endif + + stmvl53l1_module_func_tbl.power_up(data->client_object); + rc = reset_release(data); + if (rc) + goto done; + + /* full setup when out of reset or power up */ + rc = VL53L1_StaticInit(&data->stdev); + if (rc) { + vl53l1_errmsg("VL53L1_StaticInit @%d fail %d\n", + __LINE__, rc); + rc = store_last_error(data, rc); + goto done; + } + + rc = stmvl53l1_sendparams(data); + if (rc) + goto done; + + /* init the timing */ + do_gettimeofday(&data->start_tv); + data->meas.start_tv = data->start_tv; + /* init the ranging data => kill the previous ranging mz data */ + kill_mz_data(&data->meas.multi_range_data); + /* kill the single ranging data */ + memset(&data->meas.single_range_data, 0, + sizeof(VL53L1_RangingMeasurementData_t)); + + data->allow_hidden_start_stop = false; + /* kick off ranging */ + rc = VL53L1_StartMeasurement(&data->stdev); + if (rc) { + vl53l1_errmsg("VL53L1_StartMeasurement @%d fail %d", + __LINE__, rc); + rc = store_last_error(data, rc); + goto done; + } + + data->meas.cnt = 0; + data->meas.err_cnt = 0; + data->meas.err_tot = 0; + data->meas.poll_cnt = 0; + data->meas.intr = 0; + data->enable_sensor = 1; + + if (data->poll_mode) { + /* kick off the periodical polling work */ + schedule_delayed_work(&data->dwork, + msecs_to_jiffies(data->poll_delay_ms)); + } +done: + data->is_first_start_done = true; + + return rc; +} + +/** + * stop sensor + * + * work lock must be held + * @warning to be used if only started! + */ +static int stmvl53l1_stop(struct stmvl53l1_data *data) +{ + int rc; + + rc = VL53L1_StopMeasurement(&data->stdev); + if (rc) { + vl53l1_errmsg("VL53L1_StopMeasurement @%d fail %d", + __LINE__, rc); + rc = store_last_error(data, rc); + } + /* put device under reset */ + /* do we ask explicit intr stop or just use stop */ + reset_hold(data); + + data->enable_sensor = 0; + if (data->poll_mode) { + /* cancel periodical polling work */ + cancel_delayed_work(&data->dwork); + } + + /* if we are in ipp waiting mode then abort it */ + stmvl53l1_ipp_stop(data); + /* wake up all waiters */ + /* they will receive -ENODEV error */ + wake_up_data_waiters(data); + stmvl53l1_module_func_tbl.power_down(data->client_object); + +#ifdef USE_CAMERA_CCI + stmvl53l1_disable_pinctrl(); +#endif + + return rc; +} + +/* + * SysFS support + */ +static ssize_t stmvl53l1_show_enable_ps_sensor(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct stmvl53l1_data *data = dev_get_drvdata(dev); + + return snprintf(buf, 5, "%d\n", data->enable_sensor); +} + +static ssize_t stmvl53l1_store_enable_ps_sensor(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) +{ + struct stmvl53l1_data *data = dev_get_drvdata(dev); + int rc = 0; + unsigned long val; + + rc = kstrtoul(buf, 10, &val); + if (rc) { + vl53l1_errmsg("enable sensor syntax in %s\n", buf); + return -EINVAL; + } + if (val == 1) { + rc = ctrl_start(data); + } else if (val == 0) { + rc = ctrl_stop(data); + } else { + //TODO: Remove this workaround after investigation + //see Codex - 479397 for details + vl53l1_dbgmsg("Unclog Input sub-system\n"); + /* Unclog the input device sub-system */ + input_report_abs(data->input_dev_ps, ABS_HAT0X, -1); + input_report_abs(data->input_dev_ps, ABS_HAT0Y, -1); + input_report_abs(data->input_dev_ps, ABS_HAT1X, -1); + input_report_abs(data->input_dev_ps, ABS_HAT1Y, -1); + input_report_abs(data->input_dev_ps, ABS_HAT2X, -1); + input_report_abs(data->input_dev_ps, ABS_HAT2Y, -1); + input_report_abs(data->input_dev_ps, ABS_HAT3X, -1); + input_report_abs(data->input_dev_ps, ABS_HAT3Y, -1); + input_report_abs(data->input_dev_ps, ABS_WHEEL, -1); + input_report_abs(data->input_dev_ps, ABS_BRAKE, -1); + input_report_abs(data->input_dev_ps, ABS_GAS, -1); + input_report_abs(data->input_dev_ps, ABS_TILT_X, -1); + input_report_abs(data->input_dev_ps, ABS_TILT_Y, -1); + input_report_abs(data->input_dev_ps, ABS_TOOL_WIDTH, -1); + input_report_abs(data->input_dev_ps, ABS_DISTANCE, -1); + input_report_abs(data->input_dev_ps, ABS_THROTTLE, -1); + input_report_abs(data->input_dev_ps, ABS_RUDDER, -1); + input_report_abs(data->input_dev_ps, ABS_MISC, -1); + input_report_abs(data->input_dev_ps, ABS_VOLUME, + -1); + input_sync(data->input_dev_ps); + vl53l1_dbgmsg("Unclog the input sub-system\n"); + rc = 0; + } + + vl53l1_dbgmsg("End\n"); + + return rc ? rc : count; +} + +/** + * sysfs attribute "enable_ps_sensor" [rd/wr] + * + * @li read show the current enable state + * @li write set the new state value "0" put sensor off "1" put it on + * + * @return 0 on success , EINVAL if fail to start + * + * @warning their's no check and assume exclusive usage of sysfs and ioctl\n + * Sensor will be put on/off disregard of any setup done by the ioctl channel. + * + * @ingroup sysfs_attrib + */ +static DEVICE_ATTR(enable_ps_sensor, 0664/*S_IWUGO | S_IRUGO*/, + stmvl53l1_show_enable_ps_sensor, + stmvl53l1_store_enable_ps_sensor); + +static int stmvl53l1_set_poll_delay_ms(struct stmvl53l1_data *data, int delay) +{ + int rc = 0; + + if (delay <= 0) + rc = -EINVAL; + else + data->poll_delay_ms = delay; + + return rc; +} + +IMPLEMENT_PARAMETER_INTEGER(poll_delay_ms, "poll delay ms") + +/** + * sysfs attribute "poll_delay_ms" [rd/wr] + * + * @li read show the current polling delay in millisecond + * @li write set the new polling delay in millisecond + * + * @note apply only if device is in polling mode\n + * for best performances (minimal delay and cpu load ) set it to the device + * period operating period +1 millis + + * @ingroup sysfs_attrib + */ +static DEVICE_ATTR(set_delay_ms, 0660/*S_IWUGO | S_IRUGO*/, + stmvl53l1_show_poll_delay_ms, + stmvl53l1_store_poll_delay_ms); + +/* Timing Budget */ +static int stmvl53l1_set_timing_budget(struct stmvl53l1_data *data, int timing) +{ + int rc = 0; + + if (timing <= 0) { + vl53l1_errmsg("invalid timing valid %d\n", timing); + rc = -EINVAL; + } else if (data->enable_sensor) { + rc = VL53L1_SetMeasurementTimingBudgetMicroSeconds(&data->stdev, + timing); + if (rc) { + vl53l1_errmsg("SetTimingBudget %d fail %d", timing, rc); + rc = store_last_error(data, rc); + } else + data->timing_budget = timing; + } else + data->timing_budget = timing; + + return rc; +} + +IMPLEMENT_PARAMETER_INTEGER(timing_budget, "timing budget") + +/** + * sysfs "timing_budget" [rd/wr] + * + * set or get the ranging timing budget in microsecond + * + * @ingroup sysfs_attrib + */ +static DEVICE_ATTR(timing_budget, 0660/*S_IWUGO | S_IRUGO*/, + stmvl53l1_show_timing_budget, + stmvl53l1_store_timing_budget); + + +static ssize_t stmvl53l1_show_roi(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct stmvl53l1_data *data = dev_get_drvdata(dev); + int i; + int n; + + + mutex_lock(&data->work_mutex); + if (data->roi_cfg.NumberOfRoi == 0) { + /* none define by user */ + /* we could get what stored but may not even be default */ + n = scnprintf(buf, PAGE_SIZE, "device default\n"); + } else { + for (i = 0, n = 0; i < data->roi_cfg.NumberOfRoi; i++) { + n += scnprintf(buf+n, PAGE_SIZE-n, "%d %d %d %d%c", + data->roi_cfg.UserRois[i].TopLeftX, + data->roi_cfg.UserRois[i].TopLeftY, + data->roi_cfg.UserRois[i].BotRightX, + data->roi_cfg.UserRois[i].BotRightY, + i == data->roi_cfg.NumberOfRoi-1 ? + '\n' : ','); + } + } + mutex_unlock(&data->work_mutex); + return n; +} + + +static const char str_roi_ranging[] = "ERROR can't set roi while ranging\n"; + +static ssize_t stmvl53l1_store_roi(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct stmvl53l1_data *data = dev_get_drvdata(dev); + VL53L1_UserRoi_t rois[VL53L1_MAX_USER_ZONES]; + int rc; + + mutex_lock(&data->work_mutex); + if (data->enable_sensor) { + vl53l1_errmsg(" cant set roi now\n"); + rc = -EBUSY; + } else { + int n, n_roi = 0; + const char *pc = buf; + int tlx, tly, brx, bry; + + while (n_roi < VL53L1_MAX_USER_ZONES && pc != NULL + && *pc != 0 && *pc != '\n') { + n = sscanf(pc, "%d %d %d %d", &tlx, &tly, &brx, &bry); + if (n == 4) { + rois[n_roi].TopLeftX = tlx; + rois[n_roi].TopLeftY = tly; + rois[n_roi].BotRightX = brx; + rois[n_roi].BotRightY = bry; + n_roi++; + } else { + vl53l1_errmsg( +"wrong roi #%d syntax around %s of %s", n_roi, pc, buf); + n_roi = -1; + break; + } + /* find next roi separator */ + pc = strchr(pc, ','); + if (pc) + pc++; + } + /*if any set them */ + if (n_roi >= 0) { + if (n_roi) + memcpy(data->roi_cfg.UserRois, rois, + n_roi*sizeof(rois[0])); + data->roi_cfg.NumberOfRoi = n_roi; + dump_roi(data->roi_cfg.UserRois, + data->roi_cfg.NumberOfRoi); + rc = count; + } else { + rc = -EINVAL; + } + } + mutex_unlock(&data->work_mutex); + vl53l1_dbgmsg("ret %d count %d\n", rc, (int)count); + + return rc; +} + +/** + * sysfs attribute "roi" [rd/wr] + * + * @li read show the current user customized roi setting + * @li write set user custom roi, it can only be done while not ranging. + * + * syntax for set input roi + * @li "[tlx tly brx bry,]\n" repeat n time require will set the n roi + * @li "\n" will reset + * + * @warning roi coordinate is not image x,y(down) but euclidian x,y(up) + * + * @warning roi validity is only check at next range start + * @warning user is responsible to set appropriate number an roi before each + * mode change + * @note roi can be return to default by setting none "" + * + *@code + * >#to set 2x roi + * >echo "0 15 15 0, 0 8 8 0" > /sys/class/input6/roi + * >echo $? + * 0 + * >cat /sys/class/input6/roi + * "0 15 15 0,0 8 8 0" + * #to cancel user define roi" + * >echo "" > /sys/class/input1/roi + * >echo $? + * 0 + * >echo "1" > /sys/class/input6/enable_ps_senspor + * #try to set roi while ranging + * >echo "0 15 15 0, 0 8 8 0" > /sys/class/input6/roi + * [58451.912109] stmvl53l1_store_roi: cant set roi now + * >echo $? + * 1 + *@endcode + * @ingroup sysfs_attrib + */ +static DEVICE_ATTR(roi, 0660/*S_IWUGO | S_IRUGO*/, + stmvl53l1_show_roi, + stmvl53l1_store_roi); + + +static int stmvl53l1_set_preset_mode(struct stmvl53l1_data *data, int mode) +{ + int rc = 0; + + if (data->enable_sensor) { + vl53l1_errmsg("can't change mode while ranging\n"); + rc = -EBUSY; + } else { + switch (mode) { + case VL53L1_PRESETMODE_RANGING: + case VL53L1_PRESETMODE_MULTIZONES_SCANNING: + case VL53L1_PRESETMODE_LITE_RANGING: + case VL53L1_PRESETMODE_AUTONOMOUS: + case VL53L1_PRESETMODE_LOWPOWER_AUTONOMOUS: + data->preset_mode = mode; + vl53l1_dbgmsg("preset mode %d\n", mode); + break; + default: + vl53l1_errmsg("invalid mode %d\n", mode); + rc = -EINVAL; + break; + } + } + + return rc; +} + +IMPLEMENT_PARAMETER_INTEGER(preset_mode, "preset mode") + +/** + * sysfs attribute "mode " [rd/wr] + * + * set the mode value can only be used while: not ranging + * @li 1 @a VL53L1_PRESETMODE_RANGING default ranging + * @li 2 @a VL53L1_PRESETMODE_MULTIZONES_SCANNING multiple zone + * @li 3 @a VL53L1_PRESETMODE_AUTONOMOUS autonomous mode + * @li 4 @a VL53L1_PRESETMODE_LOWPOWER_AUTONOMOUS low Power autonomous mode + * @li 5 @a VL53L1_PRESETMODE_LITE_RANGING low mips ranging mode + * + * @ingroup sysfs_attrib + */ +static DEVICE_ATTR(mode, 0660/*S_IWUGO | S_IRUGO*/, + stmvl53l1_show_preset_mode, + stmvl53l1_store_preset_mode); + +static int stmvl53l1_set_distance_mode(struct stmvl53l1_data *data, + int distance_mode) +{ + int rc = 0; + + if (data->enable_sensor) { + vl53l1_errmsg("can't change distance mode while ranging\n"); + rc = -EBUSY; + } else { + switch (distance_mode) { + case VL53L1_DISTANCEMODE_SHORT: + case VL53L1_DISTANCEMODE_MEDIUM: + case VL53L1_DISTANCEMODE_LONG: + data->distance_mode = distance_mode; + vl53l1_dbgmsg("distance mode %d\n",distance_mode); + break; + default: + vl53l1_errmsg("invalid distance mode %d\n", + distance_mode); + rc = -EINVAL; + break; + } + } + + return rc; +} + +IMPLEMENT_PARAMETER_INTEGER(distance_mode, "distance mode") + +/** + * sysfs attribute " distance mode" [rd/wr] + * + * set the distance mode value can only be used while: not ranging + * @li 1 @a VL53L1_DISTANCEMODE_SHORT + * @li 2 @a VL53L1_DISTANCEMODE_MEDIUM + * @li 3 @a VL53L1_DISTANCEMODE_LONG + * + * @ingroup sysfs_attrib + */ +static DEVICE_ATTR(distance_mode, 0660/*S_IWUGO | S_IRUGO*/, + stmvl53l1_show_distance_mode, + stmvl53l1_store_distance_mode); + +static int stmvl53l1_set_crosstalk_enable(struct stmvl53l1_data *data, + int crosstalk_enable) +{ + int rc = 0; + + if (data->enable_sensor) { + vl53l1_errmsg("can't change crosstalk enable while ranging\n"); + rc = -EBUSY; + } else if (crosstalk_enable == 0 || crosstalk_enable == 1) { + data->crosstalk_enable = crosstalk_enable; + } else { + vl53l1_errmsg("invalid crosstalk enable %d\n", + crosstalk_enable); + rc = -EINVAL; + } + + return rc; +} + +IMPLEMENT_PARAMETER_INTEGER(crosstalk_enable, "crosstalk enable") + +/** + * sysfs attribute " crosstalk enable" [rd/wr] + * + * control if crosstalk compensation is eanble or not + * @li 0 disable crosstalk compensation + * @li 1 enable crosstalk compensation + * + * @ingroup sysfs_attrib + */ +static DEVICE_ATTR(crosstalk_enable, 0660/*S_IWUGO | S_IRUGO*/, + stmvl53l1_show_crosstalk_enable, + stmvl53l1_store_crosstalk_enable); + +static int stmvl53l1_set_output_mode(struct stmvl53l1_data *data, + int output_mode) +{ + int rc = 0; + + if (data->enable_sensor) { + vl53l1_errmsg("can't change output mode while ranging\n"); + rc = -EBUSY; + } else { + switch (output_mode) { + case VL53L1_OUTPUTMODE_NEAREST: + case VL53L1_OUTPUTMODE_STRONGEST: + data->output_mode = output_mode; + vl53l1_dbgmsg("output mode %d\n", output_mode); + break; + default: + vl53l1_errmsg("invalid output mode %d\n", output_mode); + rc = -EINVAL; + break; + } + } + + return rc; +} + +IMPLEMENT_PARAMETER_INTEGER(output_mode, "output mode") + +/** + * sysfs attribute " output mode" [rd/wr] + * + * set the output mode value can only be used while: not ranging + * @li 1 @a VL53L1_OUTPUTMODE_NEAREST + * @li 2 @a VL53L1_OUTPUTMODE_STRONGEST + * + * @ingroup sysfs_attrib + */ +static DEVICE_ATTR(output_mode, 0660/*S_IWUGO | S_IRUGO*/, + stmvl53l1_show_output_mode, + stmvl53l1_store_output_mode); + + +static int stmvl53l1_set_force_device_on_en(struct stmvl53l1_data *data, + int force_device_on_en) +{ + int rc; + + if (force_device_on_en != 0 && force_device_on_en != 1) { + vl53l1_errmsg("invalid force_device_on_en mode %d\n", + force_device_on_en); + return -EINVAL; + } + + data->force_device_on_en = force_device_on_en; + + /* don't update reset if sensor is enable */ + if (data->enable_sensor) + return 0; + + /* ok update reset according force_device_on_en value */ + if (force_device_on_en){ + rc = reset_release(data); + vl53l1_dbgmsg("force_device_on_en.\n"); + }else{ + vl53l1_dbgmsg("force_device_on_en disable.\n"); + rc = reset_hold(data); + } + + return rc; +} + +IMPLEMENT_PARAMETER_INTEGER(force_device_on_en, "force device on enable") + +/** + * sysfs attribute " force_device_on_enable" [rd/wr] + * + * Control if device is put under reset when stopped. + * @li 0 feature is disable. Device is put under reset when stopped. + * @li 1 feature is enable. Device is not put under reset when stopped. + * + * @ingroup sysfs_attrib + */ +static DEVICE_ATTR(force_device_on_enable, 0660/*S_IWUGO | S_IRUGO*/, + stmvl53l1_show_force_device_on_en, + stmvl53l1_store_force_device_on_en); + +static int stmvl53l1_set_offset_correction_mode(struct stmvl53l1_data *data, + int offset_correction_mode) +{ + int rc = 0; + + if (data->enable_sensor) { + vl53l1_errmsg( + "can't change offset correction mode while ranging\n"); + rc = -EBUSY; + } else { + switch (offset_correction_mode) { + case VL53L1_OFFSETCORRECTIONMODE_STANDARD: + case VL53L1_OFFSETCORRECTIONMODE_PERZONE: + case VL53L1_OFFSETCORRECTIONMODE_PERVCSEL: + data->offset_correction_mode = offset_correction_mode; + break; + default: + vl53l1_errmsg("invalid offset correction mode %d\n", + offset_correction_mode); + rc = -EINVAL; + break; + } + } + + return rc; +} + +IMPLEMENT_PARAMETER_INTEGER(offset_correction_mode, "offset correction mode") + +/** + * sysfs attribute " offset_correction_mode" [rd/wr] + * + * Control which offset correction is apply on result. can only be used + * while: not ranging + * @li 1 @a VL53L1_OFFSETCORRECTIONMODE_STANDARD + * @li 2 @a VL53L1_OFFSETCORRECTIONMODE_PERZONE + * + * @ingroup sysfs_attrib + */ +static DEVICE_ATTR(offset_correction_mode, 0660/*S_IWUGO | S_IRUGO*/, + stmvl53l1_show_offset_correction_mode, + stmvl53l1_store_offset_correction_mode); + +static ssize_t stmvl53l1_do_flush(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct stmvl53l1_data *data = dev_get_drvdata(dev); + + mutex_lock(&data->work_mutex); + + data->flush_todo_counter++; + if (data->enable_sensor == 0) + stmvl53l1_insert_flush_events_lock(data); + + mutex_unlock(&data->work_mutex); + + return count; +} + +static DEVICE_ATTR(do_flush, 0660/*S_IWUGO | S_IRUGO*/, + NULL, + stmvl53l1_do_flush); + +static ssize_t stmvl53l1_show_enable_debug(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return scnprintf(buf, PAGE_SIZE, "%d\n", stmvl53l1_enable_debug); +} + +static ssize_t stmvl53l1_store_enable_debug(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int enable_debug; + int rc = 0; + + if (kstrtoint(buf, 0, &enable_debug)) { + vl53l1_errmsg("invalid syntax in %s", buf); + rc = -EINVAL; + } else + stmvl53l1_enable_debug = enable_debug; + + return rc ? rc : count; +} + +/** + * sysfs attribute " debug enable" [rd/wr] + * + * dynamic control of vl53l1_dbgmsg messages. Note that in any case your code + * must be enable with DEBUG in stmvl53l1.h at compile time. + * @li 0 disable vl53l1_dbgmsg messages + * @li 1 enable vl53l1_dbgmsg messages + * + * @ingroup sysfs_attrib + */ +static DEVICE_ATTR(enable_debug, 0660/*S_IWUGO | S_IRUGO*/, + stmvl53l1_show_enable_debug, + stmvl53l1_store_enable_debug); + +static ssize_t display_FixPoint1616(char *buf, size_t size, FixPoint1616_t fix) +{ + uint32_t msb = fix >> 16; + uint32_t lsb = fix & 0xffff; + + lsb = (lsb * 1000000ULL + 32768) / 65536; + + return scnprintf(buf, size, "%d.%06d", msb, (uint32_t) lsb); +} + +static ssize_t stmvl53l1_show_autonomous_config(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct stmvl53l1_data *data = dev_get_drvdata(dev); + ssize_t res = 0; + + res += scnprintf(&buf[res], PAGE_SIZE, "%d %d %d %d %d %d %d ", + data->auto_pollingTimeInMs, + data->auto_config.DetectionMode, + data->auto_config.IntrNoTarget, + data->auto_config.Distance.CrossMode, + data->auto_config.Distance.High, + data->auto_config.Distance.Low, + data->auto_config.Rate.CrossMode); + + res += display_FixPoint1616(&buf[res], PAGE_SIZE - res, + data->auto_config.Rate.High); + + res += scnprintf(&buf[res], PAGE_SIZE - res, " "); + + res += display_FixPoint1616(&buf[res], PAGE_SIZE - res, + data->auto_config.Rate.Low); + + res += scnprintf(&buf[res], PAGE_SIZE - res, "\n"); + + return res; +} + +static const char *parse_integer(const char *buf, int *res) +{ + int rc; + + while (*buf == ' ') + buf++; + rc = sscanf(buf, "%d ", res); + if (!rc) + return NULL; + + return strchr(buf, ' '); +} + +static bool is_float_format(const char *buf, bool is_last) +{ + char *dot = strchr(buf, '.'); + char *space_or_eos = strchr(buf, is_last ? '\0' : ' '); + + if (!space_or_eos) + return !!dot; + if (!dot) + return false; + + return dot < space_or_eos ? true : false; +} + +static int parse_FixPoint16x16_lsb(const char *lsb_char) +{ + int lsb = 0; + int digit_nb = 0; + + /* parse at most 6 digits */ + lsb_char++; + while (isdigit(*lsb_char) && digit_nb < 6) { + lsb = lsb * 10 + (*lsb_char - '0'); + lsb_char++; + digit_nb++; + } + while (digit_nb++ < 6) + lsb = lsb * 10; + + return div64_s64(lsb * 65536ULL + 500000, 1000000); +} + +/* parse next fix point value and return a pointer to next blank or newline + * character according to is_last parameter. + * parse string must have digit for integer part (something like '.125' will + * return an error) or an error will be return. Only the first 6 digit of the + * decimal part will be parsed. + */ +static const char *parse_FixPoint16x16(const char *buf, FixPoint1616_t *res, + bool is_last) +{ + bool is_float; + int msb; + int lsb = 0; + int rc; + + while (*buf == ' ') + buf++; + is_float = is_float_format(buf, is_last); + + /* scan msb */ + rc = sscanf(buf, "%d ", &msb); + if (!rc) + return NULL; + /* then lsb if present */ + if (is_float) + lsb = parse_FixPoint16x16_lsb(strchr(buf, '.')); + *res = (msb << 16) + lsb; + + return strchr(buf, is_last ? '\0' : ' '); +} + +static ssize_t stmvl53l1_store_autonomous_config(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct stmvl53l1_data *data = dev_get_drvdata(dev); + int pollingTimeInMs, DetectionMode, IntrNoTarget; + int d_CrossMode, d_High, d_Low; + int r_CrossMode; + FixPoint1616_t r_High, r_Low; + const char *buf_ori = buf; + int rc; + + mutex_lock(&data->work_mutex); + + if (data->enable_sensor) + goto busy; + + buf = parse_integer(buf, &pollingTimeInMs); + if (!buf) + goto invalid; + buf = parse_integer(buf, &DetectionMode); + if (!buf) + goto invalid; + buf = parse_integer(buf, &IntrNoTarget); + if (!buf) + goto invalid; + buf = parse_integer(buf, &d_CrossMode); + if (!buf) + goto invalid; + buf = parse_integer(buf, &d_High); + if (!buf) + goto invalid; + buf = parse_integer(buf, &d_Low); + if (!buf) + goto invalid; + buf = parse_integer(buf, &r_CrossMode); + if (!buf) + goto invalid; + buf = parse_FixPoint16x16(buf, &r_High, false); + if (!buf) + goto invalid; + buf = parse_FixPoint16x16(buf, &r_Low, true); + if (!buf) + goto invalid; + + data->auto_pollingTimeInMs = pollingTimeInMs; + data->auto_config.DetectionMode = DetectionMode; + data->auto_config.IntrNoTarget = IntrNoTarget; + data->auto_config.Distance.CrossMode = d_CrossMode; + data->auto_config.Distance.High = d_High; + data->auto_config.Distance.Low = d_Low; + data->auto_config.Rate.CrossMode = r_CrossMode; + data->auto_config.Rate.High = r_High; + data->auto_config.Rate.Low = r_Low; + + mutex_unlock(&data->work_mutex); + + return count; + +busy: + vl53l1_errmsg("can't change config while ranging"); + rc = -EBUSY; + goto error; + +invalid: + vl53l1_errmsg("invalid syntax in %s", buf_ori); + rc = -EINVAL; + goto error; + +error: + mutex_unlock(&data->work_mutex); + + return rc; +} + +/** + * sysfs attribute " autonomous_config" [rd/wr] + * + * Will set/get autonomous configuration using sysfs. + * + * format is the following : + * + * + * + *@code + * > echo "1000 1 0 0 1000 300 0 2.2 1.001" > autonomous_config + *@endcode + * + * @ingroup sysfs_attrib + */ +static DEVICE_ATTR(autonomous_config, 0660/*S_IWUGO | S_IRUGO*/, + stmvl53l1_show_autonomous_config, + stmvl53l1_store_autonomous_config); + +static ssize_t stmvl53l1_show_last_error_config(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct stmvl53l1_data *data = dev_get_drvdata(dev); + + return scnprintf(buf, PAGE_SIZE, "%d\n", data->last_error); +} + +/** + * sysfs attribute " last_error" [rd] + * + * Will get last internal error using sysfs. + * + * @ingroup sysfs_attrib + */ +static DEVICE_ATTR(last_error, 0440/*S_IRUGO*/, + stmvl53l1_show_last_error_config, + NULL); + +static ssize_t stmvl53l1_show_optical_center_config(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct stmvl53l1_data *data = dev_get_drvdata(dev); + ssize_t res = 0; + + res += display_FixPoint1616(&buf[res], PAGE_SIZE - res, + data->optical_offset_x); + res += scnprintf(&buf[res], PAGE_SIZE - res, " "); + res += display_FixPoint1616(&buf[res], PAGE_SIZE - res, + data->optical_offset_y); + + res += scnprintf(&buf[res], PAGE_SIZE - res, "\n"); + + return res; +} + +/** + * sysfs attribute " optical_center" [rd] + * + * Will get optical_center using sysfs. + * + * @ingroup sysfs_attrib + */ +static DEVICE_ATTR(optical_center, 0440/*S_IRUGO*/, + stmvl53l1_show_optical_center_config, + NULL); + +static int stmvl53l1_set_dmax_reflectance(struct stmvl53l1_data *data, + int dmax_reflectance) +{ + int rc = 0; + + if (data->enable_sensor) { + vl53l1_errmsg( + "can't change dmax reflectance while ranging\n"); + rc = -EBUSY; + } else + data->dmax_reflectance = dmax_reflectance; + + return rc; +} + +static ssize_t stmvl53l1_show_dmax_reflectance(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct stmvl53l1_data *data = dev_get_drvdata(dev); + ssize_t res = 0; + + res += display_FixPoint1616(&buf[res], PAGE_SIZE - res, + data->dmax_reflectance); + + res += scnprintf(&buf[res], PAGE_SIZE - res, "\n"); + + return res; +} + +static ssize_t stmvl53l1_store_dmax_reflectance(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct stmvl53l1_data *data = dev_get_drvdata(dev); + FixPoint1616_t dmax_reflectance; + const char *buf_ori = buf; + int rc; + + mutex_lock(&data->work_mutex); + + buf = parse_FixPoint16x16(buf, &dmax_reflectance, true); + if (!buf) + goto invalid; + rc = stmvl53l1_set_dmax_reflectance(data, dmax_reflectance); + if (rc) + goto error; + + mutex_unlock(&data->work_mutex); + + return count; + +invalid: + vl53l1_errmsg("invalid syntax in %s", buf_ori); + rc = -EINVAL; + goto error; + +error: + mutex_unlock(&data->work_mutex); + + return rc; +} + +/** + * sysfs attribute "dmax_reflectance" [rd/wr] + * + * target reflectance use for calculate the ambient DMAX. can only be used + * while: not ranging + * + * @ingroup sysfs_attrib + */ +static DEVICE_ATTR(dmax_reflectance, 0660/*S_IWUGO | S_IRUGO*/, + stmvl53l1_show_dmax_reflectance, + stmvl53l1_store_dmax_reflectance); + +static int stmvl53l1_set_dmax_mode(struct stmvl53l1_data *data, + int dmax_mode) +{ + int rc = 0; + + if (data->enable_sensor) { + vl53l1_errmsg("can't change dmax mode while ranging\n"); + rc = -EBUSY; + } else { + switch (dmax_mode) { + case VL53L1_DMAXMODE_FMT_CAL_DATA: + case VL53L1_DMAXMODE_CUSTCAL_DATA: + case VL53L1_DMAXMODE_PER_ZONE_CAL_DATA: + data->dmax_mode = dmax_mode; + break; + default: + vl53l1_errmsg("invalid dmax mode %d\n", dmax_mode); + rc = -EINVAL; + break; + } + } + + return rc; +} + +IMPLEMENT_PARAMETER_INTEGER(dmax_mode, "dmax mode") + +/** + * sysfs attribute " dmax mode" [rd/wr] + * + * set the dmax mode value can only be used while: not ranging + * @li 1 @a VL53L1_DMAXMODE_FMT_CAL_DATA + * @li 2 @a VL53L1_DMAXMODE_CUSTCAL_DATA + * @li 3 @a VL53L1_DMAXMODE_PER_ZONE_CAL_DATA + * + * @ingroup sysfs_attrib + */ +static DEVICE_ATTR(dmax_mode, 0660/*S_IWUGO | S_IRUGO*/, + stmvl53l1_show_dmax_mode, + stmvl53l1_store_dmax_mode); + +static int stmvl53l1_set_tuning(struct stmvl53l1_data *data, int key, + int value) +{ + int rc; + + if (data->enable_sensor) { + vl53l1_errmsg("can't change tuning params while ranging\n"); + return -EBUSY; + } + + if (data->is_calibrating) { + vl53l1_errmsg("can't change tuning params while calibrating\n"); + return -EBUSY; + } + + if (key & ~0xffff) + return -EINVAL; + + vl53l1_dbgmsg("trying to set %d with key %d", value, key); + + rc = VL53L1_SetTuningParameter(&data->stdev, key, value); + if (rc) + rc = store_last_error(data, rc); + + return rc; +} + +static ssize_t stmvl53l1_store_tuning(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct stmvl53l1_data *data = dev_get_drvdata(dev); + int key; + int value; + int n; + int rc; + + mutex_lock(&data->work_mutex); + + n = sscanf(buf, "%d %d", &key, &value); + if (n != 2) { + rc = -EINVAL; + goto error; + } + rc = stmvl53l1_set_tuning(data, key, value); + if (rc) + goto error; + + mutex_unlock(&data->work_mutex); + + return count; + +error: + mutex_unlock(&data->work_mutex); + + return rc; +} + +/** + * sysfs attribute "tuning" [wr] + * + * write a tuning parameter. Two integer parameters are given. First one + * is a key that specify which tuning parameter is update. Other one is the + * value which is write. + * + * writing a tuning parameter is only allowed before the first start. + * + * @ingroup sysfs_attrib + */ +static DEVICE_ATTR(tuning, 0220/*S_IWUGO */, + NULL, + stmvl53l1_store_tuning); + +static int stmvl53l1_display_tuning_key(struct stmvl53l1_data *data, char *buf, + int *pos, int key) +{ + int rc = 0; + int value = 0; + int sz; + + rc = VL53L1_GetTuningParameter(&data->stdev, key, &value); + if (rc) + return 0; + + sz = snprintf(&buf[*pos], PAGE_SIZE - *pos, "%d %d\n", key, value); + if (sz >= PAGE_SIZE - *pos) + return -ENOSPC; /* FIXME : another better error ? */ + + *pos += sz; + + return 0; +} + +static ssize_t stmvl53l1_show_tuning_status(struct device *dev, + struct device_attribute *attr, char *buf) +{ + const int max_tuning_key = 65535; + struct stmvl53l1_data *data = dev_get_drvdata(dev); + int rc; + int i; + int pos = 0; + + mutex_lock(&data->work_mutex); + + for (i = 0; i < max_tuning_key; ++i) { + rc = stmvl53l1_display_tuning_key(data, buf, &pos, i); + if (rc) + break; + } + + mutex_unlock(&data->work_mutex); + + return rc ? rc : pos; +} + +/** + * sysfs attribute "tuning_status" [rd] + * + * write a tuning parameter. Two integer parameters are given. First one + * is a key that specify which tuning parameter is update. Other one is the + * value which is write. + * + * writing a tuning parameter is only allowed before the first start. + * + * @ingroup sysfs_attrib + */ +static DEVICE_ATTR(tuning_status, 0440/*S_IRUGO */, + stmvl53l1_show_tuning_status, + NULL); + +static int stmvl53l1_set_smudge_correction_mode(struct stmvl53l1_data *data, + int smudge_correction_mode) +{ + int rc = 0; + + if (data->enable_sensor) { + vl53l1_errmsg("can't change smudge corr mode while ranging\n"); + rc = -EBUSY; + } else { + switch (smudge_correction_mode) { + case VL53L1_SMUDGE_CORRECTION_NONE: + case VL53L1_SMUDGE_CORRECTION_CONTINUOUS: + case VL53L1_SMUDGE_CORRECTION_SINGLE: + case VL53L1_SMUDGE_CORRECTION_DEBUG: + data->smudge_correction_mode = smudge_correction_mode; + break; + default: + vl53l1_errmsg("invalid smudge correction mode %d\n", + smudge_correction_mode); + rc = -EINVAL; + break; + } + } + + return rc; +} + +IMPLEMENT_PARAMETER_INTEGER(smudge_correction_mode, "smudge correction mode") + +/** + * sysfs attribute " smudge_correction_mode" [rd/wr] + * + * This parameter will control if smudge correction is enable and how crosstalk + * values are updated. + * @li 0 @a VL53L1_SMUDGE_CORRECTION_NONE + * @li 1 @a VL53L1_SMUDGE_CORRECTION_CONTINUOUS + * @li 2 @a VL53L1_SMUDGE_CORRECTION_SINGLE + * @li 3 @a VL53L1_SMUDGE_CORRECTION_DEBUG + * + * @ingroup sysfs_attrib + */ +static DEVICE_ATTR(smudge_correction_mode, 0660/*S_IWUGO | S_IRUGO*/, + stmvl53l1_show_smudge_correction_mode, + stmvl53l1_store_smudge_correction_mode); + +static ssize_t stmvl53l1_show_is_xtalk_value_changed_config(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct stmvl53l1_data *data = dev_get_drvdata(dev); + int param; + + mutex_lock(&data->work_mutex); + param = data->is_xtalk_value_changed; + mutex_unlock(&data->work_mutex); + + return scnprintf(buf, PAGE_SIZE, "%d\n", param); +} + +/** + * sysfs attribute " optical_center" [rd] + * + * Will get optical_center using sysfs. + * + * @ingroup sysfs_attrib + */ +static DEVICE_ATTR(is_xtalk_value_changed, 0440/*S_IRUGO*/, + stmvl53l1_show_is_xtalk_value_changed_config, + NULL); + +static struct attribute *stmvl53l1_attributes[] = { + &dev_attr_enable_ps_sensor.attr, + &dev_attr_set_delay_ms.attr, + &dev_attr_timing_budget.attr, + &dev_attr_roi.attr, + &dev_attr_mode.attr, + &dev_attr_do_flush.attr, + &dev_attr_distance_mode.attr, + &dev_attr_crosstalk_enable.attr, + &dev_attr_enable_debug.attr, + &dev_attr_output_mode.attr, + &dev_attr_force_device_on_enable.attr, + &dev_attr_autonomous_config.attr, + &dev_attr_last_error.attr, + &dev_attr_offset_correction_mode.attr, + &dev_attr_optical_center.attr, + &dev_attr_dmax_reflectance.attr, + &dev_attr_dmax_mode.attr, + &dev_attr_tuning.attr, + &dev_attr_tuning_status.attr, + &dev_attr_smudge_correction_mode.attr, + &dev_attr_is_xtalk_value_changed.attr, + NULL +}; + +static const struct attribute_group stmvl53l1_attr_group = { + .attrs = stmvl53l1_attributes, +}; + +static ssize_t stmvl53l1_calib_data_read(struct file *filp, + struct kobject *kobj, struct bin_attribute *attr, + char *buf, loff_t off, size_t count) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct stmvl53l1_data *data = dev_get_drvdata(dev); + VL53L1_CalibrationData_t calib; + int rc; + void *src = (void *) &calib; + + mutex_lock(&data->work_mutex); + + vl53l1_dbgmsg("off = %lld / count = %d", off, count); + + /* sanity check */ + if (off < 0 || off > sizeof(VL53L1_CalibrationData_t)) + goto invalid; + + /* got current calibration data */ + memset(&calib, 0, sizeof(calib)); + rc = VL53L1_GetCalibrationData(&data->stdev, &calib); + if (rc) { + vl53l1_errmsg("VL53L1_GetCalibrationData fail %d", rc); + rc = store_last_error(data, rc); + goto error; + } + + /* copy to buffer */ + if (off + count > sizeof(VL53L1_CalibrationData_t)) + count = sizeof(VL53L1_CalibrationData_t) - off; + memcpy(buf, src + off, count); + + mutex_unlock(&data->work_mutex); + + return count; + +invalid: + vl53l1_errmsg("invalid syntax"); + rc = -EINVAL; + goto error; + +error: + mutex_unlock(&data->work_mutex); + + return rc; +} + +static ssize_t stmvl53l1_calib_data_write(struct file *filp, + struct kobject *kobj, struct bin_attribute *attr, + char *buf, loff_t off, size_t count) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct stmvl53l1_data *data = dev_get_drvdata(dev); + int rc; + + mutex_lock(&data->work_mutex); + + vl53l1_dbgmsg("off = %lld / count = %d", off, count); + + if (data->enable_sensor) { + rc = -EBUSY; + vl53l1_errmsg("can't set calib data while ranging\n"); + goto error; + } + + /* we only support one time write */ + if (off != 0 || count != sizeof(VL53L1_CalibrationData_t)) + goto invalid; + + rc = VL53L1_SetCalibrationData(&data->stdev, + (VL53L1_CalibrationData_t *) buf); + if (rc) { + vl53l1_errmsg("VL53L1_SetCalibrationData fail %d", rc); + rc = store_last_error(data, rc); + goto error; + } + + mutex_unlock(&data->work_mutex); + + return count; + +invalid: + vl53l1_errmsg("invalid syntax"); + rc = -EINVAL; + goto error; + +error: + mutex_unlock(&data->work_mutex); + + return rc; +} + +static struct bin_attribute stmvl53l1_calib_data_attr = { + .attr = { + .name = "calibration_data", + .mode = 0660/*S_IWUGO | S_IRUGO*/, + }, + .size = sizeof(VL53L1_CalibrationData_t), + .read = stmvl53l1_calib_data_read, + .write = stmvl53l1_calib_data_write, +}; + +static ssize_t stmvl53l1_zone_calib_data_read(struct file *filp, + struct kobject *kobj, struct bin_attribute *attr, + char *buf, loff_t off, size_t count) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct stmvl53l1_data *data = dev_get_drvdata(dev); + int rc; + void *src = (void *) &data->calib.data; + + mutex_lock(&data->work_mutex); + + vl53l1_dbgmsg("off = %lld / count = %d", off, count); + + /* sanity check */ + if (off < 0 || off > sizeof(stmvl531_zone_calibration_data_t)) + goto invalid; + + /* got current zone calibration data */ + rc = VL53L1_GetZoneCalibrationData(&data->stdev, + &data->calib.data.data); + if (rc) { + vl53l1_errmsg("VL53L1_GetZoneCalibrationData fail %d", rc); + rc = store_last_error(data, rc); + goto error; + } + data->calib.data.id = data->current_roi_id; + + /* copy to buffer */ + if (off + count > sizeof(stmvl531_zone_calibration_data_t)) + count = sizeof(stmvl531_zone_calibration_data_t) - off; + memcpy(buf, src + off, count); + + mutex_unlock(&data->work_mutex); + + return count; + +invalid: + vl53l1_errmsg("invalid syntax"); + rc = -EINVAL; + goto error; + +error: + mutex_unlock(&data->work_mutex); + + return rc; +} + +static ssize_t stmvl53l1_zone_calib_data_write(struct file *filp, + struct kobject *kobj, struct bin_attribute *attr, + char *buf, loff_t off, size_t count) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct stmvl53l1_data *data = dev_get_drvdata(dev); + int rc; + void *dst = &data->calib.data; + + mutex_lock(&data->work_mutex); + + vl53l1_dbgmsg("off = %lld / count = %d", off, count); + + /* implementation if quite fragile. We suppose successive access. We + * trigger set on last byte write if amount is exact. + */ + if (off < 0 || off > sizeof(stmvl531_zone_calibration_data_t)) + goto invalid; + if (off + count > sizeof(stmvl531_zone_calibration_data_t)) + goto invalid; + + memcpy(dst + off, buf, count); + if (off + count == sizeof(stmvl531_zone_calibration_data_t)) { + vl53l1_dbgmsg("trigger zone calib setting"); + rc = VL53L1_SetZoneCalibrationData(&data->stdev, + &data->calib.data.data); + if (rc) { + vl53l1_errmsg("VL53L1_SetZoneCalibrationData fail %d", + rc); + rc = store_last_error(data, rc); + goto error; + } + data->current_roi_id = data->calib.data.id; + } + + mutex_unlock(&data->work_mutex); + + return count; + +invalid: + vl53l1_errmsg("invalid syntax"); + rc = -EINVAL; + goto error; + +error: + mutex_unlock(&data->work_mutex); + + return rc; +} + +static struct bin_attribute stmvl53l1_zone_calib_data_attr = { + .attr = { + .name = "zone_calibration_data", + .mode = 0660/*S_IWUGO | S_IRUGO*/, + }, + .size = sizeof(stmvl531_zone_calibration_data_t), + .read = stmvl53l1_zone_calib_data_read, + .write = stmvl53l1_zone_calib_data_write, +}; + +static int ctrl_reg_access(struct stmvl53l1_data *data, void *p) +{ + struct stmvl53l1_register reg; + size_t total_byte; + int rc; + + if (data->is_device_remove) + return -ENODEV; + + total_byte = offsetof(struct stmvl53l1_register, data.b); + if (copy_from_user(®, p, total_byte)) { + vl53l1_errmsg("%d, fail\n", __LINE__); + return -EFAULT; + } + + if (reg.cnt > STMVL53L1_MAX_CCI_XFER_SZ) { + vl53l1_errmsg("reg len %d > size limit\n", reg.cnt); + return -EINVAL; + } + + total_byte = offsetof(struct stmvl53l1_register, data.bytes[reg.cnt]); + /* for write get the effective data part of the structure */ + if (!reg.is_read) { + if (copy_from_user(®, p, total_byte)) { + vl53l1_errmsg(" data cpy fail\n"); + return -EFAULT; + } + } + + /* put back to user only needed amount of data */ + if (!reg.is_read) { + rc = VL53L1_WriteMulti(&data->stdev, (uint16_t)reg.index, + reg.data.bytes, reg.cnt); + reg.status = rc; + /* for write only write back status no data */ + total_byte = offsetof(struct stmvl53l1_register, data.b); + vl53l1_dbgmsg("wr %x %d bytes statu %d\n", + reg.index, reg.cnt, rc); + if (rc) + rc = store_last_error(data, rc); + } else { + rc = VL53L1_ReadMulti(&data->stdev, (uint16_t)reg.index, + reg.data.bytes, reg.cnt); + reg.status = rc; + vl53l1_dbgmsg("rd %x %d bytes status %d\n", + reg.index, reg.cnt, rc); + /* if fail do not copy back data only status */ + if (rc) { + total_byte = offsetof(struct stmvl53l1_register, + data.b); + rc = store_last_error(data, rc); + } + /* else the total byte is already the full pay-load with data */ + } + + if (copy_to_user(p, ®, total_byte)) { + vl53l1_errmsg("%d, fail\n", __LINE__); + return -EFAULT; + } + return rc; +} + + +/* + * + */ +static int ctrl_start(struct stmvl53l1_data *data) +{ + int rc; + + mutex_lock(&data->work_mutex); + + if (data->is_device_remove) { + rc = -ENODEV; + goto done; + } + + vl53l1_dbgmsg(" state = %d\n", data->enable_sensor); + + /* turn on tof sensor only if it's not already started */ + if (data->enable_sensor == 0 && !data->is_calibrating) { + /* to start */ + rc = stmvl53l1_start(data); + } else{ + rc = -EBUSY; + } + vl53l1_dbgmsg(" final state = %d\n", data->enable_sensor); + +done: + mutex_unlock(&data->work_mutex); + + return rc; +} + +/** + * no lock version of ctrl_stop (mutex shall be held) + * + * @warning exist only for use in device exit to ensure "locked and started" + * may also beuse in soem erro handling when mutex is already locked + * @return 0 on success and was running >0 if already off <0 on error + */ +static int _ctrl_stop(struct stmvl53l1_data *data) +{ + int rc; + + vl53l1_dbgmsg("enter state = %d\n", data->enable_sensor); + /* be sure waiters are woken */ + data->is_data_valid = true; + /* turn on tof sensor only if it's not enabled by other client */ + if (data->enable_sensor == 1) { + /* to stop */ + rc = stmvl53l1_stop(data); + } else { + vl53l1_dbgmsg("already off did nothing\n"); + rc = 0; + } + stmvl53l1_insert_flush_events_lock(data); + vl53l1_dbgmsg(" final state = %d\n", data->enable_sensor); + + return rc; +} + +/** + * get work lock and stop sensor + * + * see @ref _ctrl_stop + * + * @param data device + * @return 0 on success EBUSY if arleady off + */ +static int ctrl_stop(struct stmvl53l1_data *data) +{ + int rc; + + mutex_lock(&data->work_mutex); + + if (data->is_device_remove) { + rc = -ENODEV; + goto done; + } + if (data->enable_sensor) + rc = _ctrl_stop(data); + else + rc = -EBUSY; + +done: + mutex_unlock(&data->work_mutex); + + return rc; +} + +static int ctrl_getdata(struct stmvl53l1_data *data, void __user *p) +{ + int rc; + + mutex_lock(&data->work_mutex); + + if (data->is_device_remove) { + rc = -ENODEV; + goto done; + } + rc = copy_to_user(p, + &data->meas.single_range_data, + sizeof(stmvl531_range_data_t)); + if (rc) { + vl53l1_dbgmsg("copy to user fail %d", rc); + rc = -EFAULT; + } + +done: + mutex_unlock(&data->work_mutex); + + return rc; +} + +static bool is_new_data_for_me(struct stmvl53l1_data *data, pid_t pid, + struct list_head *head) +{ + return data->is_data_valid && !is_pid_in_list(pid, head); +} + +static bool sleep_for_data_condition(struct stmvl53l1_data *data, pid_t pid, + struct list_head *head) +{ + bool res; + + mutex_lock(&data->work_mutex); + res = is_new_data_for_me(data, pid, head); + mutex_unlock(&data->work_mutex); + + return res; +} + +static int sleep_for_data(struct stmvl53l1_data *data, pid_t pid, + struct list_head *head) +{ + int rc; + + mutex_unlock(&data->work_mutex); + #ifndef VENDOR_EDIT + if(data->preset_mode == VL53L1_PRESETMODE_LITE_RANGING){ + #else + if (1) { + #endif + rc = wait_event_killable(data->waiter_for_data, + sleep_for_data_condition(data, pid, head)); + }else{ + rc = wait_event_killable_timeout(data->waiter_for_data, + sleep_for_data_condition(data, pid, head),2*HZ); + } + mutex_lock(&data->work_mutex); + + return data->enable_sensor ? rc : -ENODEV; +} + +static int ctrl_getdata_blocking(struct stmvl53l1_data *data, void __user *p) +{ + int rc = 0; + pid_t pid = current->pid; + + mutex_lock(&data->work_mutex); + /* If device not ranging then exit on error */ + if (data->is_device_remove || !data->enable_sensor) { + rc = -ENODEV; + goto done; + } + /* sleep if data already read */ + if (!is_new_data_for_me(data, pid, &data->simple_data_reader_list)) + rc = sleep_for_data(data, pid, &data->simple_data_reader_list); + if (rc) + goto done; + + /* unless we got interrupted we return data to user and note read */ + rc = copy_to_user(p, &data->meas.single_range_data, + sizeof(stmvl531_range_data_t)); + if (rc) + goto done; + rc = add_reader(pid, &data->simple_data_reader_list); + +done: + mutex_unlock(&data->work_mutex); + + return rc; +} + +static int ctrl_mz_data_common(struct stmvl53l1_data *data, void __user *p, + bool is_additional) +{ + struct stmvl53l1_data_with_additional __user *d = p; + int rc; + + mutex_lock(&data->work_mutex); + if (data->is_device_remove) { + rc = -ENODEV; + goto done; + } + rc = copy_to_user(&d->data, &data->meas.multi_range_data, + sizeof(VL53L1_MultiRangingData_t)); + if (rc) { + vl53l1_dbgmsg("copy to user fail %d", rc); + rc = -EFAULT; + goto done; + } + if (is_additional) { + rc = copy_to_user(&d->additional_data, + &data->meas.additional_data, + sizeof(VL53L1_AdditionalData_t)); + if (rc) { + vl53l1_dbgmsg("copy to user fail %d", rc); + rc = -EFAULT; + goto done; + } + } + if (!data->enable_sensor) + rc = -ENODEV; + else if (!is_mz_mode(data)) + rc = -ENOEXEC; + +done: + mutex_unlock(&data->work_mutex); + + return rc; +} + +static int ctrl_mz_data_blocking_common(struct stmvl53l1_data *data, + void __user *p, bool is_additional) +{ + int rc = 0; + struct stmvl53l1_data_with_additional __user *d = p; + pid_t pid = current->pid; + + mutex_lock(&data->work_mutex); + if (data->is_device_remove) { + rc = -ENODEV; + goto done; + } + /* mode 2 or 3 */ + if (!is_mz_mode(data)) { + rc = -ENOEXEC; + goto done; + } + /* If device not ranging then exit on error */ + if (!data->enable_sensor) { + rc = -ENODEV; + goto done; + } + /* sleep if data already read */ + if (!is_new_data_for_me(data, pid, &data->mz_data_reader_list)) + rc = sleep_for_data(data, pid, &data->mz_data_reader_list);//songyt test + if (rc) + goto done; + + /* unless we got interrupted we return data to user and note read */ + rc = copy_to_user(&d->data, &data->meas.multi_range_data, + sizeof(VL53L1_MultiRangingData_t)); + if (rc) + goto done; + if (is_additional) { + rc = copy_to_user(&d->additional_data, + &data->meas.additional_data, + sizeof(VL53L1_AdditionalData_t)); + if (rc) + goto done; + } + rc = add_reader(pid, &data->mz_data_reader_list); + +done: + mutex_unlock(&data->work_mutex); + + return rc; +} + +/** + * Get multi zone data + * @param data + * @param p [out] user ptr to @ref VL53L1_MultiRangingData_t structure\n + * is always set but on EFAULT error + * + * @return + * @li 0 on success + * @li ENODEV if not ranging + * @li ENOEXEC not in multi zone mode + * @li EFAULT copy to user error + */ +static int ctrl_mz_data(struct stmvl53l1_data *data, void __user *p) +{ + return ctrl_mz_data_common(data, p, false); +} + +static int ctrl_mz_data_blocking(struct stmvl53l1_data *data, void __user *p) +{ + return ctrl_mz_data_blocking_common(data, p, false); +} + +/** + * Get multi zone data with histogram debug data + * @param data + * @param p [out] user ptr to @ref struct stmvl53l1_data_with_additional + * structure is always set but on EFAULT error + * + * @return + * @li 0 on success + * @li ENODEV if not ranging + * @li ENOEXEC not in multi zone mode + * @li EFAULT copy to user error + */ +static int ctrl_mz_data_additional(struct stmvl53l1_data *data, void __user *p) +{ + return ctrl_mz_data_common(data, p, true); +} + +static int ctrl_mz_data_blocking_additional(struct stmvl53l1_data *data, + void __user *p) +{ + return ctrl_mz_data_blocking_common(data, p, true); +} + +static int ctrl_param_last_error(struct stmvl53l1_data *data, + struct stmvl53l1_parameter *param) +{ + int rc; + + if (param->is_read) { + param->value = data->last_error; + param->status = 0; + vl53l1_dbgmsg("get last error %d", param->value); + rc = 0; + } else { + rc = -EINVAL; + } + + return rc; +} + +static int ctrl_param_optical_center(struct stmvl53l1_data *data, + struct stmvl53l1_parameter *param) +{ + if (!param->is_read) + return -EINVAL; + + param->value = data->optical_offset_x; + param->value2 = data->optical_offset_y; + + return 0; +} + +static int ctrl_param_dmax_reflectance(struct stmvl53l1_data *data, + struct stmvl53l1_parameter *param) +{ + int rc; + + if (param->is_read) { + param->value = data->dmax_reflectance; + param->status = 0; + vl53l1_dbgmsg("get dmax reflectance %d", param->value); + rc = 0; + } else { + rc = stmvl53l1_set_dmax_reflectance(data, param->value); + vl53l1_dbgmsg("rc %d req %d now %d", rc, + param->value, data->dmax_reflectance); + } + + return rc; +} + +static int ctrl_param_tuning(struct stmvl53l1_data *data, + struct stmvl53l1_parameter *param) +{ + if (param->is_read) + return -EINVAL; + + return stmvl53l1_set_tuning(data, param->value, param->value2); +} + +static int ctrl_param_is_xtalk_value_changed(struct stmvl53l1_data *data, + struct stmvl53l1_parameter *param) +{ + if (!param->is_read) + return -EINVAL; + + param->value = data->is_xtalk_value_changed; + + return 0; +} + +/** + * handle ioctl set param mode + * + * @param data + * @param p + * @return 0 on success + */ +static int ctrl_params(struct stmvl53l1_data *data, void __user *p) +{ + int rc, rc2; + struct stmvl53l1_parameter param; + + mutex_lock(&data->work_mutex); + + if (data->is_device_remove) { + rc = -ENODEV; + goto done; + } + rc = copy_from_user(¶m, p, sizeof(param)); + param.status = 0; + if (rc) { + rc = -EFAULT; + goto done; /* no need for status in user struct */ + } + switch (param.name) { + case VL53L1_POLLDELAY_PAR: + rc = ctrl_param_poll_delay_ms(data, ¶m); + break; + case VL53L1_TIMINGBUDGET_PAR: + rc = ctrl_param_timing_budget(data, ¶m); + break; + case VL53L1_DEVICEMODE_PAR: + rc = ctrl_param_preset_mode(data, ¶m); + break; + case VL53L1_DISTANCEMODE_PAR: + rc = ctrl_param_distance_mode(data, ¶m); + break; + case VL53L1_XTALKENABLE_PAR: + rc = ctrl_param_crosstalk_enable(data, ¶m); + break; + case VL53L1_OUTPUTMODE_PAR: + rc = ctrl_param_output_mode(data, ¶m); + break; + case VL53L1_FORCEDEVICEONEN_PAR: + rc = ctrl_param_force_device_on_en(data, ¶m); + break; + case VL53L1_LASTERROR_PAR: + rc = ctrl_param_last_error(data, ¶m); + break; + case VL53L1_OFFSETCORRECTIONMODE_PAR: + rc = ctrl_param_offset_correction_mode(data, ¶m); + break; + case VL53L1_OPTICALCENTER_PAR: + rc = ctrl_param_optical_center(data, ¶m); + break; + case VL53L1_DMAXREFLECTANCE_PAR: + rc = ctrl_param_dmax_reflectance(data, ¶m); + break; + case VL53L1_DMAXMODE_PAR: + rc = ctrl_param_dmax_mode(data, ¶m); + break; + case VL53L1_TUNING_PAR: + rc = ctrl_param_tuning(data, ¶m); + break; + case VL53L1_SMUDGECORRECTIONMODE_PAR: + rc = ctrl_param_smudge_correction_mode(data, ¶m); + break; + case VL53L1_ISXTALKVALUECHANGED_PAR: + rc = ctrl_param_is_xtalk_value_changed(data, ¶m); + break; + default: + vl53l1_errmsg("unknown or unsupported %d\n", param.name); + rc = -EINVAL; + } + /* copy back (status at least ) to user */ + if (param.is_read && rc == 0) { + rc2 = copy_to_user(p, ¶m, sizeof(param)); + if (rc2) { + rc = -EFAULT; /* kill prev status if that fail */ + vl53l1_errmsg("copy to user fail %d\n", rc); + } + } +done: + mutex_unlock(&data->work_mutex); + return rc; +} + +/** + * implement set/get roi ioctl + * @param data device + * @param p user space ioctl arg ptr + * @return 0 on success <0 errno code + * @li -EINVAL invalid number of roi + * @li -EBUSY when trying to set roi while ranging + * @li -EFAULT if cpy to/fm user fail for requested number of roi + */ +static int ctrl_roi(struct stmvl53l1_data *data, void __user *p) +{ + int rc; + int roi_cnt; + struct stmvl53l1_roi_full_t rois; + + mutex_lock(&data->work_mutex); + if (data->is_device_remove) { + rc = -ENODEV; + goto done; + } + /* copy fixed part of args at first */ + rc = copy_from_user(&rois, p, + offsetof(struct stmvl53l1_roi_full_t, + roi_cfg.UserRois[0])); + if (rc) { + rc = -EFAULT; + goto done; + } + /* check no of roi limit is ok */ + roi_cnt = rois.roi_cfg.NumberOfRoi; + if (roi_cnt > VL53L1_MAX_USER_ZONES) { + vl53l1_errmsg("invalid roi spec cnt=%d > %d", + rois.roi_cfg.NumberOfRoi, + VL53L1_MAX_USER_ZONES); + rc = -EINVAL; + goto done; + } + + if (rois.is_read) { + int cpy_size; + + roi_cnt = MIN(rois.roi_cfg.NumberOfRoi, + data->roi_cfg.NumberOfRoi); + cpy_size = offsetof(VL53L1_RoiConfig_t, UserRois[roi_cnt]); + /* copy from local to user only effective part requested */ + rc = copy_to_user(&((struct stmvl53l1_roi_full_t *)p)->roi_cfg, + &data->roi_cfg, cpy_size); + vl53l1_dbgmsg("return %d of %d\n", roi_cnt, + data->roi_cfg.NumberOfRoi); + } else { + /* SET check cnt roi is ok */ + if (data->enable_sensor) { + rc = -EBUSY; + vl53l1_errmsg("can't set roi while ranging\n"); + goto done; + } + /* get full data that required from user */ + rc = copy_from_user(&rois, p, + offsetof(struct stmvl53l1_roi_full_t, + roi_cfg.UserRois[roi_cnt])); + if (rc) { + vl53l1_errmsg("get %d roi fm user fail", roi_cnt); + rc = -EFAULT; + goto done; + } + dump_roi(data->roi_cfg.UserRois, data->roi_cfg.NumberOfRoi); + /* we may ask ll driver to check but check is mode dependent + * and so we could get erroneous error back + */ + memcpy(&data->roi_cfg, &rois.roi_cfg, sizeof(data->roi_cfg)); + } +done: + mutex_unlock(&data->work_mutex); + return rc; +} + +static int ctrl_autonomous_config(struct stmvl53l1_data *data, void __user *p) +{ + int rc = 0; + struct stmvl53l1_autonomous_config_t full; + + mutex_lock(&data->work_mutex); + if (data->is_device_remove) { + rc = -ENODEV; + goto done; + } + /* first copy all data */ + rc = copy_from_user(&full, p, sizeof(full)); + if (rc) { + rc = -EFAULT; + goto done; + } + + if (full.is_read) { + full.pollingTimeInMs = data->auto_pollingTimeInMs; + full.config = data->auto_config; + rc = copy_to_user(p, &full, sizeof(full)); + if (rc) + rc = -EFAULT; + } else { + if (data->enable_sensor) { + rc = -EBUSY; + vl53l1_errmsg("can't change config while ranging\n"); + goto done; + } + data->auto_pollingTimeInMs = full.pollingTimeInMs; + data->auto_config = full.config; + } + +done: + mutex_unlock(&data->work_mutex); + + return rc; +} + +static int ctrl_calibration_data(struct stmvl53l1_data *data, void __user *p) +{ + int rc; + struct stmvl53l1_ioctl_calibration_data_t calib; + int data_offset = offsetof(struct stmvl53l1_ioctl_calibration_data_t, + data); + + mutex_lock(&data->work_mutex); + + if (data->is_device_remove) { + rc = -ENODEV; + goto done; + } + rc = copy_from_user(&calib, p, data_offset); + if (rc) { + vl53l1_errmsg("fail to detect read or write %d", rc); + rc = -EFAULT; + goto done; + } + + if (calib.is_read) { + memset(&calib.data, 0, sizeof(calib.data)); + rc = VL53L1_GetCalibrationData(&data->stdev, &calib.data); + if (rc) { + vl53l1_errmsg("VL53L1_GetCalibrationData fail %d", rc); + rc = store_last_error(data, rc); + goto done; + } + rc = copy_to_user(p + data_offset, &calib.data, + sizeof(calib.data)); + } else { + if (data->enable_sensor) { + rc = -EBUSY; + vl53l1_errmsg("can't set calib data while ranging\n"); + goto done; + } + rc = copy_from_user(&calib.data, p + data_offset, + sizeof(calib.data)); + if (rc) { + vl53l1_errmsg("fail to copy calib data"); + rc = -EFAULT; + goto done; + } + rc = VL53L1_SetCalibrationData(&data->stdev, &calib.data); + if (rc) { + vl53l1_errmsg("VL53L1_SetCalibrationData fail %d", rc); + rc = store_last_error(data, rc); + } + } + +done: + mutex_unlock(&data->work_mutex); + + return rc; +} + +static int ctrl_zone_calibration_data(struct stmvl53l1_data *data, + void __user *p) +{ + int rc; + struct stmvl53l1_ioctl_zone_calibration_data_t *calib; + int data_offset = + offsetof(struct stmvl53l1_ioctl_zone_calibration_data_t, data); + + mutex_lock(&data->work_mutex); + + calib = &data->calib; + if (data->is_device_remove) { + rc = -ENODEV; + goto done; + } + rc = copy_from_user(calib, p, data_offset); + if (rc) { + vl53l1_errmsg("fail to detect read or write %d", rc); + rc = -EFAULT; + goto done; + } + + if (calib->is_read) { + memset(&calib->data, 0, sizeof(calib->data)); + rc = VL53L1_GetZoneCalibrationData(&data->stdev, + &calib->data.data); + if (rc) { + vl53l1_errmsg("VL53L1_GetZoneCalibrationData fail %d", + rc); + rc = store_last_error(data, rc); + goto done; + } + calib->data.id = data->current_roi_id; + rc = copy_to_user(p + data_offset, &calib->data, + sizeof(calib->data)); + } else { + if (data->enable_sensor) { + rc = -EBUSY; + vl53l1_errmsg("can't set calib data while ranging\n"); + goto done; + } + rc = copy_from_user(&calib->data, p + data_offset, + sizeof(calib->data)); + if (rc) { + vl53l1_errmsg("fail to copy calib data"); + rc = -EFAULT; + goto done; + } + rc = VL53L1_SetZoneCalibrationData(&data->stdev, + &calib->data.data); + if (rc) { + vl53l1_errmsg("VL53L1_SetZoneCalibrationData fail %d", + rc); + rc = store_last_error(data, rc); + goto done; + } + data->current_roi_id = calib->data.id; + } + +done: + mutex_unlock(&data->work_mutex); + + return rc; +} + +static int ctrl_perform_calibration_ref_spad_lock(struct stmvl53l1_data *data, + struct stmvl53l1_ioctl_perform_calibration_t *calib) +{ + int rc = VL53L1_PerformRefSpadManagement(&data->stdev); + + if (rc) { + vl53l1_errmsg("VL53L1_PerformRefSpadManagement fail => %d", rc); + rc = store_last_error(data, rc); + } + + return rc; +} + +static int ctrl_perform_calibration_crosstalk_lock(struct stmvl53l1_data *data, + struct stmvl53l1_ioctl_perform_calibration_t *calib) +{ + int rc = 0; + + /* Set the preset mode passed on param2 */ + data->preset_mode = (VL53L1_PresetModes)(calib->param2); + + rc = stmvl53l1_sendparams(data); + if (rc) + goto done; + + rc = VL53L1_PerformXTalkCalibration(&data->stdev, calib->param1); + if (rc) { + vl53l1_errmsg("VL53L1_PerformXTalkCalibration fail => %d", rc); + rc = store_last_error(data, rc); + } + +done: + return rc; +} + +static int ctrl_perform_zone_calibration_offset_lock( + struct stmvl53l1_data *data, + struct stmvl53l1_ioctl_perform_calibration_t *calib) +{ + int rc; + + /* first sanity check */ + if (calib->param1 != VL53L1_OFFSETCALIBRATIONMODE_MULTI_ZONE) { + vl53l1_errmsg("invalid param1"); + rc = -EINVAL; + goto done; + } + + /* setup offset calibration mode */ + rc = VL53L1_SetOffsetCalibrationMode(&data->stdev, calib->param1); + if (rc) { + vl53l1_errmsg("VL53L1_SetOffsetCalibrationMode fail => %d", rc); + rc = store_last_error(data, rc); + goto done; + } + + /* set mode to multi zone to allow roi settings */ + rc = VL53L1_SetPresetMode(&data->stdev, + VL53L1_PRESETMODE_MULTIZONES_SCANNING); + if (rc) { + vl53l1_errmsg("VL53L1_SetPresetMode fail => %d", rc); + rc = store_last_error(data, rc); + goto done; + } + + /* setup roi */ + rc = VL53L1_SetROI(&data->stdev, &data->roi_cfg); + if (rc) { + vl53l1_errmsg("VL53L1_SetROI fail => %d", rc); + rc = store_last_error(data, rc); + goto done; + } + + /* finally perform calibration */ + /* allow delay add after stop in VL53L1_run__calibration */ + data->is_delay_allowed = 1; + rc = VL53L1_PerformOffsetCalibration(&data->stdev, calib->param2, + calib->param3); + data->is_delay_allowed = 0; + if (rc) { + vl53l1_errmsg("VL53L1_PerformOffsetCalibration fail => %d", rc); + rc = store_last_error(data, rc); + } + + /* save roi hash for later use */ + data->current_roi_id = stmvl53l1_compute_hash(&data->roi_cfg); + +done: + return rc; +} + +static int ctrl_perform_calibration_offset_lock(struct stmvl53l1_data *data, + struct stmvl53l1_ioctl_perform_calibration_t *calib) +{ + int rc; + + /* for legacy purpose we still support mz */ + if (calib->param1 == VL53L1_OFFSETCALIBRATIONMODE_MULTI_ZONE) + return ctrl_perform_zone_calibration_offset_lock(data, calib); + + /* setup offset calibration mode */ + rc = VL53L1_SetOffsetCalibrationMode(&data->stdev, calib->param1); + if (rc) { + vl53l1_errmsg("VL53L1_SetOffsetCalibrationMode fail => %d", rc); + rc = store_last_error(data, rc); + goto done; + } + + /* finally perform calibration */ + /* allow delay add after stop in VL53L1_run__calibration */ + data->is_delay_allowed = 1; + rc = VL53L1_PerformOffsetCalibration(&data->stdev, calib->param2, + calib->param3); + data->is_delay_allowed = 0; + if (rc) { + vl53l1_errmsg("VL53L1_PerformOffsetCalibration fail => %d", rc); + rc = store_last_error(data, rc); + } + +done: + return rc; +} + +static int ctrl_perform_simple_calibration_offset_lock( + struct stmvl53l1_data *data, + struct stmvl53l1_ioctl_perform_calibration_t *calib) +{ + int rc; + + /* finally perform calibration */ + /* allow delay add after stop in VL53L1_run__calibration */ + data->is_delay_allowed = 1; + + rc = stmvl53l1_sendparams(data); + if (rc) + goto done; + + rc = VL53L1_PerformOffsetSimpleCalibration(&data->stdev, calib->param1); + data->is_delay_allowed = 0; + if (rc) { + vl53l1_errmsg( + "VL53L1_PerformOffsetSimpleCalibration fail => %d", rc); + rc = store_last_error(data, rc); + } + +done: + return rc; +} + +static int ctrl_perform_per_vcsel_calibration_offset_lock( + struct stmvl53l1_data *data, + struct stmvl53l1_ioctl_perform_calibration_t *calib) +{ + int rc; + + /* finally perform calibration */ + /* allow delay add after stop in VL53L1_run__calibration */ + data->is_delay_allowed = 1; + + rc = stmvl53l1_sendparams(data); + if (rc) + goto done; + + rc = VL53L1_PerformOffsetPerVcselCalibration(&data->stdev, calib->param1); + data->is_delay_allowed = 0; + if (rc) { + vl53l1_errmsg( + "VL53L1_PerformOffsetPerVcselCalibration fail => %d", rc); + rc = store_last_error(data, rc); + } + +done: + return rc; +} + +static int ctrl_perform_zero_distance_calibration_offset_lock( + struct stmvl53l1_data *data, + struct stmvl53l1_ioctl_perform_calibration_t *calib) +{ + int rc; + + /* finally perform calibration */ + /* allow delay add after stop in VL53L1_run__calibration */ + data->is_delay_allowed = 1; + + rc = stmvl53l1_sendparams(data); + if (rc) + goto done; + + rc = VL53L1_PerformOffsetZeroDistanceCalibration(&data->stdev); + data->is_delay_allowed = 0; + if (rc) { + vl53l1_errmsg( + "VL53L1_PerformOffsetZeroDistanceCalibration fail => %d", rc); + rc = store_last_error(data, rc); + } + +done: + return rc; +} + +static int ctrl_perform_calibration(struct stmvl53l1_data *data, void __user *p) +{ + int rc; + struct stmvl53l1_ioctl_perform_calibration_t calib; + + mutex_lock(&data->work_mutex); + + if (data->is_device_remove) { + rc = -ENODEV; + goto done; + } + data->is_calibrating = true; + rc = copy_from_user(&calib, p, sizeof(calib)); + if (rc) { + rc = -EFAULT; + goto done; + } + if (data->enable_sensor) { + rc = -EBUSY; + vl53l1_errmsg("can't perform calibration while ranging\n"); + goto done; + } + vl53l1_info("cali power on");//songyt add + stmvl53l1_module_func_tbl.power_up(data->client_object); + + rc = reset_release(data); + if (rc) + goto done; + + rc = VL53L1_StaticInit(&data->stdev); + if (rc) { + vl53l1_errmsg("VL53L1_StaticInit fail => %d", rc); + rc = store_last_error(data, rc); + goto done; + } + + switch (calib.calibration_type) { + case VL53L1_CALIBRATION_REF_SPAD: + rc = ctrl_perform_calibration_ref_spad_lock(data, + &calib); + break; + case VL53L1_CALIBRATION_CROSSTALK: + rc = ctrl_perform_calibration_crosstalk_lock(data, + &calib); + break; + case VL53L1_CALIBRATION_OFFSET: + rc = ctrl_perform_calibration_offset_lock(data, + &calib); + break; + case VL53L1_CALIBRATION_OFFSET_SIMPLE: + rc = ctrl_perform_simple_calibration_offset_lock(data, + &calib); + break; + case VL53L1_CALIBRATION_OFFSET_PER_ZONE: + rc = ctrl_perform_zone_calibration_offset_lock(data, + &calib); + break; + case VL53L1_CALIBRATION_OFFSET_PER_VCSEL: + rc = ctrl_perform_per_vcsel_calibration_offset_lock(data, + &calib); + break; + case VL53L1_CALIBRATION_OFFSET_ZERO_DISTANCE: + rc = ctrl_perform_zero_distance_calibration_offset_lock(data, + &calib); + break; + default: + rc = -EINVAL; + break; + } + + reset_hold(data); + vl53l1_info("cali power down");//songyt add + stmvl53l1_module_func_tbl.power_down(data->client_object); + +done: + data->is_calibrating = false; + data->is_first_start_done = true; + mutex_unlock(&data->work_mutex); + + return rc; +} + +static int stmvl53l1_ioctl_handler( + struct stmvl53l1_data *data, + unsigned int cmd, unsigned long arg, + void __user *p) +{ + int rc = 0; + + if (!data) + return -EINVAL; + + switch (cmd) { + + case VL53L1_IOCTL_START: + vl53l1_dbgmsg("VL53L1_IOCTL_START\n"); + rc = ctrl_start(data); + break; + + case VL53L1_IOCTL_STOP: + vl53l1_dbgmsg("VL53L1_IOCTL_STOP\n"); + rc = ctrl_stop(data); + break; + + case VL53L1_IOCTL_GETDATAS: + /* vl53l1_dbgmsg("VL53L1_IOCTL_GETDATAS\n"); */ + rc = ctrl_getdata(data, p); + break; + + case VL53L1_IOCTL_GETDATAS_BLOCKING: + /* vl53l1_dbgmsg("VL53L1_IOCTL_GETDATAS_BLOCKING\n"); */ + rc = ctrl_getdata_blocking(data, p); + break; + + /* Register tool */ + case VL53L1_IOCTL_REGISTER: + vl53l1_dbgmsg("VL53L1_IOCTL_REGISTER\n"); + rc = ctrl_reg_access(data, p); + break; + + case VL53L1_IOCTL_PARAMETER: + vl53l1_dbgmsg("VL53L1_IOCTL_PARAMETER\n"); + rc = ctrl_params(data, p); + break; + + case VL53L1_IOCTL_ROI: + vl53l1_dbgmsg("VL53L1_IOCTL_ROI\n"); + rc = ctrl_roi(data, p); + break; + case VL53L1_IOCTL_MZ_DATA: + /* vl53l1_dbgmsg("VL53L1_IOCTL_MZ_DATA\n"); */ + rc = ctrl_mz_data(data, p); + break; + case VL53L1_IOCTL_MZ_DATA_BLOCKING: + /* vl53l1_dbgmsg("VL53L1_IOCTL_MZ_DATA_BLOCKING\n"); */ + rc = ctrl_mz_data_blocking(data, p); + break; + case VL53L1_IOCTL_CALIBRATION_DATA: + vl53l1_dbgmsg("VL53L1_IOCTL_CALIBRATION_DATA\n"); + rc = ctrl_calibration_data(data, p); + break; + case VL53L1_IOCTL_PERFORM_CALIBRATION: + vl53l1_dbgmsg("VL53L1_IOCTL_PERFORM_CALIBRATION\n"); + rc = ctrl_perform_calibration(data, p); + break; + case VL53L1_IOCTL_AUTONOMOUS_CONFIG: + vl53l1_dbgmsg("VL53L1_IOCTL_AUTONOMOUS_CONFIG\n"); + rc = ctrl_autonomous_config(data, p); + break; + case VL53L1_IOCTL_ZONE_CALIBRATION_DATA: + vl53l1_dbgmsg("VL53L1_IOCTL_ZONE_CALIBRATION_DATA\n"); + rc = ctrl_zone_calibration_data(data, p); + break; + case VL53L1_IOCTL_MZ_DATA_ADDITIONAL: + /* vl53l1_dbgmsg("VL53L1_IOCTL_MZ_DATA_ADDITIONAL\n"); */ + rc = ctrl_mz_data_additional(data, p); + break; + case VL53L1_IOCTL_MZ_DATA_ADDITIONAL_BLOCKING: + /* vl53l1_dbgmsg("VL53L1_IOCTL_MZ_DATA_ADDITIONAL_BLOCKING\n"); + */ + rc = ctrl_mz_data_blocking_additional(data, p); + break; + default: + rc = -EINVAL; + break; + } + + return rc; +} + + + +static int stmvl53l1_open(struct inode *inode, struct file *file) +{ + struct stmvl53l1_data *data = container_of(file->private_data, + struct stmvl53l1_data, miscdev); + + vl53l1_dbgmsg("Start\n"); + stmvl53l1_module_func_tbl.get(data->client_object); + vl53l1_dbgmsg("End\n"); + + return 0; +} + +static int stmvl53l1_release(struct inode *inode, struct file *file) +{ + struct stmvl53l1_data *data = container_of(file->private_data, + struct stmvl53l1_data, miscdev); + + vl53l1_dbgmsg("Start\n"); + stmvl53l1_module_func_tbl.put(data->client_object); + vl53l1_dbgmsg("End\n"); + + return 0; +} + + +/** max number or error per measure too abort */ +#define stvm531_get_max_meas_err(...) 3 +/** max number or error per stream too abort */ +#define stvm531_get_max_stream_err(...) 6 + +static void detect_xtalk_value_change(struct stmvl53l1_data *data, + VL53L1_MultiRangingData_t *meas) +{ + data->is_xtalk_value_changed = meas->HasXtalkValueChanged ? true : + data->is_xtalk_value_changed; +} + +/** + * handle data retrieval and dispatch + * + * work lock must be held + * + * called form work or interrupt thread it must be a blocable context ! + * @param data the device + */ +static void stmvl53l1_on_newdata_event(struct stmvl53l1_data *data) +{ + int rc; + VL53L1_RangingMeasurementData_t *pmsinglerange; + VL53L1_MultiRangingData_t *pmrange; + VL53L1_MultiRangingData_t *tmprange; + VL53L1_TargetRangeData_t RangeData[VL53L1_MAX_RANGE_RESULTS]; + VL53L1_RangingMeasurementData_t singledata; + long ts_msec; + int i; + + do_gettimeofday(&data->meas.comp_tv); + ts_msec = stmvl53l1_tv_dif(&data->start_tv, &data->meas.comp_tv)/1000; + + pmrange = &data->meas.multi_range_data; + tmprange = &data->meas.tmp_range_data; + pmsinglerange = &data->meas.single_range_data; + + memcpy(&singledata, pmsinglerange, + sizeof(VL53L1_RangingMeasurementData_t)); + for (i = 0; i < VL53L1_MAX_RANGE_RESULTS; i++) + memcpy(&RangeData[i], &pmrange->RangeData[i], + sizeof(VL53L1_TargetRangeData_t)); + + data->meas.intr++; + + /* use get data method based on active mode */ + switch (data->preset_mode) { + case VL53L1_PRESETMODE_LITE_RANGING: + case VL53L1_PRESETMODE_AUTONOMOUS: + case VL53L1_PRESETMODE_LOWPOWER_AUTONOMOUS: + rc = VL53L1_GetRangingMeasurementData(&data->stdev, + pmsinglerange); + break; + case VL53L1_PRESETMODE_RANGING: + case VL53L1_PRESETMODE_MULTIZONES_SCANNING: + /* IMPORTANT : during VL53L1_GetMultiRangingData() call + * work_mutex is release during ipp. This is why we use + * tmp_range_data which is not access somewhere else. When we are + * back we then copy tmp_range_data in multi_range_data. + */ + + rc = VL53L1_GetMultiRangingData(&data->stdev, + &data->meas.tmp_range_data); + + /* be sure we got VL53L1_RANGESTATUS_NONE for object 0 if we got + * invalid roi or no object. So if client read data using + * VL53L1_IOCTL_GETDATAS we got correct status. + */ + if (tmprange->RoiStatus == VL53L1_ROISTATUS_NOT_VALID || + tmprange->NumberOfObjectsFound == 0) + tmprange->RangeData[0].RangeStatus = + VL53L1_RANGESTATUS_NONE; + + memcpy(pmrange, tmprange, sizeof(VL53L1_MultiRangingData_t)); + + /* got histogram debug data in case user want it later on */ + if (!rc) + rc = VL53L1_GetAdditionalData(&data->stdev, + &data->meas.additional_data); + detect_xtalk_value_change(data, pmrange); + break; + default: + /* that must be some bug or data corruption stop now */ + rc = -1; + vl53l1_errmsg("unsorted mode %d=>stop\n", data->preset_mode); + _ctrl_stop(data); + } + /* check if not stopped yet + * as we may have been unlocked we must re-check + */ + if (data->enable_sensor == 0) { + vl53l1_dbgmsg("at meas #%d we got stopped\n", data->meas.cnt); + return; + } + if (rc) { + vl53l1_errmsg("VL53L1_GetRangingMeasurementData @%d %d", + __LINE__, rc); + data->meas.err_cnt++; + data->meas.err_tot++; + if (data->meas.err_cnt > stvm531_get_max_meas_err(data) || + data->meas.err_tot > stvm531_get_max_stream_err(data)) { + vl53l1_errmsg("on #%d %d err %d tot stop", + data->meas.cnt, data->meas.err_cnt, + data->meas.err_tot); + _ctrl_stop(data); + } + return; + } + + /* FIXME: remove when implemented by ll or bare driver */ + pmrange->TimeStamp = ts_msec; + pmsinglerange->TimeStamp = ts_msec; + for (i = 1; i < pmrange->NumberOfObjectsFound; i++) + pmrange->TimeStamp = ts_msec; + + data->meas.cnt++; +#if 0 + vl53l1_dbgmsg("vl53l1: status=%d obj cnt=%d distance=%d sr=%d ar=%d\n", + pmrange->RangeData[0].RangeStatus, + pmrange->NumberOfObjectsFound, + (int)pmrange->RangeData[0].RangeMilliMeter, + (int)pmrange->RangeData[0].SignalRateRtnMegaCps, + (int)pmrange->RangeData[0].AmbientRateRtnMegaCps); + vl53l1_dbgmsg("#%3d %2d poll ts %5d status=%d obj cnt=%d\n", + data->meas.cnt, + data->meas.poll_cnt, + pmrange->TimeStamp, + pmrange->RangeData[0].RangeStatus, + pmrange->NumberOfObjectsFound); + + vl53l1_dbgmsg( +"meas m#%04d i#%04d p#%04d in %d ms data range status %d range %d\n", + (int)data->meas.cnt, + (int)data->meas.intr, + (int)data->meas.poll_cnt, + (int)stmvl53l1_tv_dif(&data->meas.start_tv, + &data->meas.comp_tv)/1000, + (int)data->meas.range_data.RangeStatus, + (int)data->meas.range_data.RangeMilliMeter); +#endif + /* ready that is not always on each new data event */ + + /* mark data as valid from now */ + data->is_data_valid = true; + + /* wake up sleeping client */ + wake_up_data_waiters(data); + + /* push data to input subsys and only and make val for ioctl*/ + stmvl53l1_input_push_data(data); + stmvl53l1_insert_flush_events_lock(data); + + /* roll time now data got used */ + data->meas.start_tv = data->meas.comp_tv; + data->meas.poll_cnt = 0; + data->meas.err_cnt = 0; +} + + +/** + * * handle interrupt/pusdo irq by polling handling + * + * work lock must be held + * + * @param data driver + * @return 0 on success + */ +static int stmvl53l1_intr_process(struct stmvl53l1_data *data) +{ + uint8_t data_rdy; + int rc = 0; + struct timeval tv_now; + + if (!data->enable_sensor) + goto done; + + data->meas.poll_cnt++; + rc = VL53L1_GetMeasurementDataReady(&data->stdev, &data_rdy); + if (rc) { + vl53l1_errmsg("GetMeasurementDataReady @%d %d, fail\n", + __LINE__, rc); + /* too many successive fail => stop but do not try to do any new + * i/o + */ + goto stop_io; + } + + if (!data_rdy) { + /* FIXME this part to completely skip + * if using interrupt and sure we have + * no false interrupt to handle or no to do any timing check + */ + long poll_us; + + do_gettimeofday(&tv_now); + poll_us = stmvl53l1_tv_dif(&data->meas.start_tv, &tv_now); + if (poll_us > data->timing_budget*4) { + vl53l1_errmsg("we're polling %ld ms too long\n", + poll_us/1000); + /* fixme stop or just warn ? */ + goto stop_io; + } + /* keep trying it could be intr with no processing */ + work_dbg("intr with no data rdy"); + goto done; + } + /* we have data to handle */ + /* first irq after reset has no data so we skip it */ + if (data->is_first_irq) { + data->is_first_irq = false; + + if (data->preset_mode == + VL53L1_PRESETMODE_LOWPOWER_AUTONOMOUS) { + /* + * If VL53L1_GetRangingMeasurementData() + * is not called after + * for the first ranging measurement, + * the thresholds do not seem + * to work for ALP mode + */ + VL53L1_RangingMeasurementData_t RangingMeasurementData; + + /* printk("Test Workaround for ALP mode\n"); */ + VL53L1_GetRangingMeasurementData(&data->stdev, + &RangingMeasurementData); + } + + } else + stmvl53l1_on_newdata_event(data); + /* enable_sensor could change on event handling check again */ + if (data->enable_sensor) { + /* clear interrupt and continue ranging */ + work_dbg("intr clr"); + /* In autonomous mode, bare driver will trigger stop/start + * sequence. In that case it wall call platform delay functions. + * So allow delay in VL53L1_ClearInterruptAndStartMeasurement() + * call. + */ + data->is_delay_allowed = data->allow_hidden_start_stop; + rc = VL53L1_ClearInterruptAndStartMeasurement(&data->stdev); + data->is_delay_allowed = 0; + if (rc) { + /* go to stop but stop any new i/o for dbg */ + vl53l1_errmsg("Cltr intr restart fail %d\n", rc); + goto stop_io; + } + } +done: + return rc; +stop_io: + /* too many successive fail take action => stop but do not try to do + * any new i/o + */ + vl53l1_errmsg("GetDatardy fail stop\n"); + _ctrl_stop(data); + return rc; + +} + +static void stmvl53l1_work_handler(struct work_struct *work) +{ + struct stmvl53l1_data *data; + + data = container_of(work, struct stmvl53l1_data, dwork.work); + work_dbg("enter"); + mutex_lock(&data->work_mutex); + stmvl53l1_intr_process(data); + if (data->poll_mode && data->enable_sensor) { + /* re-sched ourself */ + schedule_delayed_work(&data->dwork, + msecs_to_jiffies(data->poll_delay_ms)); + } + mutex_unlock(&data->work_mutex); +} + +static void stmvl53l1_input_push_data_singleobject(struct stmvl53l1_data *data) +{ + struct input_dev *input = data->input_dev_ps; + VL53L1_RangingMeasurementData_t *meas = &data->meas.single_range_data; + /* + FixPoint1616_t LimitCheckCurrent; + VL53L1_Error st = VL53L1_ERROR_NONE; + */ + vl53l1_dbgmsg("******* FIXME!!! ************\n"); + vl53l1_dbgmsg("Sensor HAL in Lite ranging mode not yet updated\n"); + vl53l1_dbgmsg("******* FIXME!!! ************\n"); + if (meas->TimeStamp > 0 && input != NULL) { + vl53l1_dbgmsg("******* TimeStamp:%d ************\n", meas->TimeStamp); + } + /* Do not send the events till this if fixed properly */ + return; + /* + input_report_abs(input, ABS_DISTANCE, (meas->RangeMilliMeter + 5) / 10); + input_report_abs(input, ABS_HAT0X, meas->TimeStamp / 1000); + input_report_abs(input, ABS_HAT0Y, (meas->TimeStamp % 1000) * 1000); + input_report_abs(input, ABS_HAT1X, meas->RangeMilliMeter); + input_report_abs(input, ABS_HAT1Y, meas->RangeStatus); + input_report_abs(input, ABS_HAT2X, meas->SignalRateRtnMegaCps); + input_report_abs(input, ABS_HAT2Y, meas->AmbientRateRtnMegaCps); + input_report_abs(input, ABS_HAT3X, meas->SigmaMilliMeter); + st = VL53L1_GetLimitCheckCurrent(&data->stdev, + VL53L1_CHECKENABLE_SIGMA_FINAL_RANGE, &LimitCheckCurrent); + if (st == VL53L1_ERROR_NONE) + input_report_abs(input, ABS_WHEEL, LimitCheckCurrent); + input_report_abs(input, ABS_TILT_Y, meas->EffectiveSpadRtnCount); + input_report_abs(input, ABS_TOOL_WIDTH, meas->RangeQualityLevel); + + input_sync(input); + */ +} + +static void stmvl53l1_input_push_data_multiobject(struct stmvl53l1_data *data) +{ + VL53L1_MultiRangingData_t *mmeas = &data->meas.multi_range_data; + int i; + int rc; + VL53L1_TargetRangeData_t *meas_array[4]; + VL53L1_CalibrationData_t calibration_data; + struct timeval tv; + struct input_dev *input = data->input_dev_ps; + + do_gettimeofday(&tv); + + for (i = 0; i < 4; i++) + meas_array[i] = &mmeas->RangeData[i]; + + /************************************************************* + * INPUT EVENT CODE L1/L3 Data + ABS_HAT0X Time in Sec(32) + ABS_HAT0Y Time in uSec(32) + ABS_HAT1X Obj0_Distance(16) : Obj0_Sigma(16) + ABS_HAT1Y Obj0_MinRange(16) : Obj0_MaxRange(16) + ABS_HAT2X Obj1_Distance(16) : Obj1_Sigma(16) + ABS_HAT2Y Obj1_ MinRange (16) : Obj1_ MaxRange (16) + ABS_HAT3X Obj0_SignalRate_Spad(32) + ABS_HAT3Y Obj1_SignalRate_Spad(32) + ABS_WHEEL AmbientRate(32) + ABS_BRAKE EffectiveSpadRtnCount(16):RangeStatus_1(8): + Range_status_0(8) + ABS_TILT_X XtalkChange(8) :StreamCount(8) : + NumberofObjects(2) : RoiNumber(4) : + RoiStatus(2) + ABS_TILT_Y DMAX + ABS_TOOL_WIDTH XtalkValue + ABS_DISTANCE + ABS_THROTTLE + ABS_RUDDER + ABS_MISC + ABS_VOLUME + ************************************************************/ + + rc = VL53L1_GetCalibrationData(&data->stdev, &calibration_data); + if (rc) { + //This should not happen + vl53l1_errmsg("%d error:%d\n", __LINE__, rc); + return; + } + + //ABS_HAT0X - Time in Sec(32) + + input_report_abs(input, ABS_HAT0X, tv.tv_sec); + //vl53l1_dbgmsg("ABS_HAT0X : %ld, %zu\n", tv.tv_sec, sizeof(tv.tv_sec)); + //ABS_HAT0Y - Time in uSec(32) + //REVISIT : The following code may cause loss of data due to + //8 bytes to 32 bits conversion + input_report_abs(input, ABS_HAT0Y, tv.tv_usec); + //vl53l1_dbgmsg("ABS_HAT0Y : %ld\n", tv.tv_usec); + + if (mmeas->NumberOfObjectsFound == 0) { + //ABS_TILT_X XtalkChange(8) :StreamCount(8) : + //Number of Objects(2) : RoiNumber(4) : RoiStatus(2) + input_report_abs(input, ABS_TILT_X, + (mmeas->HasXtalkValueChanged << 16) + | (mmeas->StreamCount << 8) + | ((mmeas->NumberOfObjectsFound & 0x3) << 6) + | ((mmeas->RoiNumber & 0xF) << 2) + | (mmeas->RoiStatus & 0x3)); + /*vl53l1_dbgmsg("ABS_TILT_X :(%d):(%d):(%d):(%d):(%d)\n\n", + mmeas->HasXtalkValueChanged, + mmeas->StreamCount, + mmeas->NumberOfObjectsFound, + mmeas->RoiNumber, + mmeas->RoiStatus + );*/ + + + //ABS_TILT_Y DMAX + input_report_abs(input, ABS_TILT_Y, mmeas->DmaxMilliMeter); + //vl53l1_dbgmsg("ABS_TILT_Y DMAX = %d\n", mmeas->DmaxMilliMeter); + + //ABS_TOOL_WIDTH + input_report_abs(input, ABS_TOOL_WIDTH, + calibration_data.customer.algo__crosstalk_compensation_plane_offset_kcps); + //vl53l1_dbgmsg("ABS_TOOL_WIDTH Xtalk = %d\n", + // calibration_data.customer.algo__crosstalk_compensation_plane_offset_kcps); + + + input_sync(input); + return; + } + + //ABS_HAT1X - Obj0_Distance(16) : Obj0_Sigma(16) + input_report_abs(input, ABS_HAT1X, meas_array[0]->RangeMilliMeter << 16 + | (meas_array[0]->SigmaMilliMeter/65536)); + /*vl53l1_dbgmsg("ABS_HAT1X : 0x%X(%d:%d)\n", + meas_array[0]->RangeMilliMeter << 16 + | (meas_array[0]->SigmaMilliMeter/65536), + meas_array[0]->RangeMilliMeter, + (meas_array[0]->SigmaMilliMeter/65536));*/ + + //ABS_HAT1Y - Obj0_MinRange(16) : Obj0_MaxRange(16) + input_report_abs(input, ABS_HAT1Y, + meas_array[0]->RangeMinMilliMeter << 16 + | meas_array[0]->RangeMaxMilliMeter); + + /*vl53l1_dbgmsg("ABS_HAT1Y : 0x%X(%d:%d)\n", + meas_array[0]->RangeMinMilliMeter << 16 + | meas_array[0]->RangeMaxMilliMeter, + meas_array[0]->RangeMinMilliMeter, + meas_array[0]->RangeMaxMilliMeter);*/ + + if (mmeas->NumberOfObjectsFound > 1) { + //ABS_HAT2X - Obj1_Distance(16) : Obj1_Sigma(16) + input_report_abs(input, ABS_HAT2X, + meas_array[1]->RangeMilliMeter << 16 + | (meas_array[1]->SigmaMilliMeter/65536)); + /*vl53l1_dbgmsg("ABS_HAT2X : 0x%x(%d:%d)\n", + meas_array[1]->RangeMilliMeter << 16 + | (meas_array[1]->SigmaMilliMeter/65536), + meas_array[1]->RangeMilliMeter, + (meas_array[1]->SigmaMilliMeter/65536));*/ + + //ABS_HAT2Y - Obj1_ MinRange (16) : Obj1_ MaxRange (16) + input_report_abs(input, ABS_HAT2Y, + meas_array[1]->RangeMinMilliMeter << 16 + | meas_array[1]->RangeMaxMilliMeter); + + /*vl53l1_dbgmsg("ABS_HAT1Y : 0x%X(%d:%d)\n", + meas_array[1]->RangeMinMilliMeter << 16 + | meas_array[1]->RangeMaxMilliMeter, + meas_array[1]->RangeMinMilliMeter, + meas_array[1]->RangeMaxMilliMeter);*/ + + } + + // ABS_HAT3X - Obj0_SignalRate_Spad(32) + input_report_abs(input, ABS_HAT3X, + meas_array[0]->SignalRateRtnMegaCps); + //vl53l1_dbgmsg("ABS_HAT3X : SignalRateRtnMegaCps_0(%d)\n", + // meas_array[0]->SignalRateRtnMegaCps); + if (mmeas->NumberOfObjectsFound > 1) { + //ABS_HAT3Y - Obj1_SignalRate_Spad(32) + input_report_abs(input, ABS_HAT3Y, + meas_array[1]->SignalRateRtnMegaCps); + // vl53l1_dbgmsg("ABS_HAT3Y : SignalRateRtnMegaCps_1(%d)\n", + // meas_array[1]->SignalRateRtnMegaCps); + } + //ABS_WHEEL - AmbientRate(32) + input_report_abs(input, ABS_WHEEL, + meas_array[0]->AmbientRateRtnMegaCps); + //vl53l1_dbgmsg("ABS_WHEEL : AmbRate = %d\n", + // meas_array[0]->AmbientRateRtnMegaCps); + + + //ABS_BRAKE - EffectiveSpadRtnCount(16):RangeStatus_3(1): + //Range_status_2(0) + input_report_abs(input, ABS_BRAKE, + mmeas->EffectiveSpadRtnCount << 16 + | ((meas_array[1]->RangeStatus) << 8) + | meas_array[0]->RangeStatus); + + /*vl53l1_dbgmsg("ABS_BRAKE : (%d):(%d):(%d)\n", + mmeas->EffectiveSpadRtnCount, + meas_array[1]->RangeStatus, + meas_array[0]->RangeStatus); + + vl53l1_dbgmsg("ABS_BRAKE : 0x%X\n", + (mmeas->EffectiveSpadRtnCount & 0xFFFF) << 16 + | ((meas_array[1]->RangeStatus) << 8) + | meas_array[0]->RangeStatus);*/ + //ABS_TILT_X XtalkChange(8) :StreamCount(8) : + //Number of Objects(2) : RoiNumber(4) : RoiStatus(2) + //On maint2 driver, the max possible range status value is 14. + //Revisit If this changes in future + input_report_abs(input, ABS_TILT_X, + (mmeas->HasXtalkValueChanged << 16) + | (mmeas->StreamCount << 8) + | ((mmeas->NumberOfObjectsFound & 0x3) << 6) + | ((mmeas->RoiNumber & 0xF) << 2) + | (mmeas->RoiStatus & 0x3)); + /*vl53l1_dbgmsg("ABS_TILT_X :(%d):(%d):(%d):(%d):(%d)\n", + mmeas->HasXtalkValueChanged, + mmeas->StreamCount, + mmeas->NumberOfObjectsFound, + mmeas->RoiNumber, + mmeas->RoiStatus + );*/ + //ABS_TILT_Y DMAX + input_report_abs(input, ABS_TILT_Y, mmeas->DmaxMilliMeter); + //vl53l1_dbgmsg("ABS_TILT_Y DMAX = %d\n", mmeas->DmaxMilliMeter); + + //ABS_TOOL_WIDTH + input_report_abs(input, ABS_TOOL_WIDTH, + calibration_data.customer.algo__crosstalk_compensation_plane_offset_kcps); + //vl53l1_dbgmsg("ABS_TOOL_WIDTH Xtalk = %d\n\n", + // calibration_data.customer.algo__crosstalk_compensation_plane_offset_kcps); + input_sync(input); +} + +static void stmvl53l1_input_push_data(struct stmvl53l1_data *data) +{ + /* use get data method based on active mode */ + switch (data->preset_mode) { + case VL53L1_PRESETMODE_LITE_RANGING: + case VL53L1_PRESETMODE_AUTONOMOUS: + case VL53L1_PRESETMODE_LOWPOWER_AUTONOMOUS: + stmvl53l1_input_push_data_singleobject(data); + break; + default: + /* VL53L1_PRESETMODE_RANGING: + * VL53L1_PRESETMODE_MULTIZONES_SCANNING: + */ + stmvl53l1_input_push_data_multiobject(data); + } +} + +static int stmvl53l1_input_setup(struct stmvl53l1_data *data) +{ + int rc; + struct input_dev *idev; + /* Register to Input Device */ + idev = input_allocate_device(); + if (idev == NULL) { + rc = -ENOMEM; + vl53l1_errmsg("%d error:%d\n", __LINE__, rc); + goto exit_err; + } + /* setup all event */ + set_bit(EV_ABS, idev->evbit); + + input_set_abs_params(idev, ABS_DISTANCE, 0, 0xff, 0, 0); + + input_set_abs_params(idev, ABS_HAT0X, 0, 0xffffffff, 0, 0); + input_set_abs_params(idev, ABS_HAT0Y, 0, 0xffffffff, 0, 0); + input_set_abs_params(idev, ABS_HAT1X, 0, 0xffffffff, 0, 0); + input_set_abs_params(idev, ABS_HAT1Y, 0, 0xffffffff, 0, 0); + input_set_abs_params(idev, ABS_HAT2X, 0, 0xffffffff, 0, 0); + input_set_abs_params(idev, ABS_HAT2Y, 0, 0xffffffff, 0, 0); + input_set_abs_params(idev, ABS_HAT3X, 0, 0xffffffff, 0, 0); + input_set_abs_params(idev, ABS_HAT3Y, 0, 0xffffffff, 0, 0); + input_set_abs_params(idev, ABS_WHEEL, 0, 0xffffffff, 0, 0); + + input_set_abs_params(idev, ABS_TILT_Y, 0, 0xffffffff, 0, 0); + + input_set_abs_params(idev, ABS_BRAKE, 0, 0xffffffff, 0, 0); + input_set_abs_params(idev, ABS_TILT_X, 0, 0xffffffff, 0, 0); + input_set_abs_params(idev, ABS_TOOL_WIDTH, 0, 0xffffffff, 0, 0); + + input_set_abs_params(idev, ABS_THROTTLE, 0, 0xffffffff, 0, 0); + input_set_abs_params(idev, ABS_RUDDER, 0, 0xffffffff, 0, 0); + input_set_abs_params(idev, ABS_MISC, 0, 0xffffffff, 0, 0); + + input_set_abs_params(idev, ABS_VOLUME, 0, 0xffffffff, 0, 0); + input_set_abs_params(idev, ABS_GAS, 0, 0xffffffff, 0, 0); + + idev->name = "STM VL53L1 proximity sensor"; + rc = input_register_device(idev); + if (rc) { + rc = -ENOMEM; + vl53l1_errmsg("%d error:%d\n", __LINE__, rc); + goto exit_free_dev_ps; + } + /* setup drv data */ + input_set_drvdata(idev, data); + data->input_dev_ps = idev; + return 0; + + +exit_free_dev_ps: + input_free_device(data->input_dev_ps); +exit_err: + return rc; +} + +/** + * handler to be called by interface module on interrupt + * + * managed poll/irq filtering in case poll/irq can be soft forced + * and the module side still fire interrupt + * + * @param data + * @return 0 if all ok else for error + */ +int stmvl53l1_intr_handler(struct stmvl53l1_data *data) +{ + int rc; + + mutex_lock(&data->work_mutex); + + /* handle it only if if we are not stopped */ + if (data->enable_sensor) { + rc = stmvl53l1_intr_process(data); + } else { + /* it's likely race/last unhandled interrupt after + * stop. + * Such dummy irq also occured during offset and crosstalk + * calibration procedures. + */ + //vl53l1_dbgmsg("got intr but not on (dummy or calibration)\n"); + rc = 0; + } + + mutex_unlock(&data->work_mutex); + return rc; +} + + +/** + * One time device setup + * + * call by bus (i2c/cci) level probe to finalize non bus related device setup + * + * @param data The device data + * @return 0 on success + */ +int stmvl53l1_setup(struct stmvl53l1_data *data) +{ + int rc = 0; + VL53L1_DeviceInfo_t dev_info; + + vl53l1_dbgmsg("Enter\n"); + + /* acquire an id */ + data->id = allocate_dev_id(); + if (data->id < 0) { + vl53l1_errmsg("too many device already created"); + return -1; + } + vl53l1_dbgmsg("Dev id %d is @%p\n", data->id, data); + stmvl53l1_dev_table[data->id] = data; + + /* init mutex */ + /* mutex_init(&data->update_lock); */ + mutex_init(&data->work_mutex); + + /* init work handler */ + INIT_DELAYED_WORK(&data->dwork, stmvl53l1_work_handler); + + /* init ipp side */ + stmvl53l1_ipp_setup(data); + + data->force_device_on_en = force_device_on_en_default; + data->reset_state = 1; + data->is_calibrating = false; + data->last_error = VL53L1_ERROR_NONE; + data->is_device_remove = false; + + rc = stmvl53l1_module_func_tbl.power_up(data->client_object); + if (rc) { + vl53l1_errmsg("%d,error rc %d\n", __LINE__, rc); + goto exit_ipp_cleanup; + } + rc = reset_release(data); + if (rc) + goto exit_ipp_cleanup; + + rc = stmvl53l1_input_setup(data); + if (rc) + goto exit_ipp_cleanup; + + /* init blocking ioctl stuff */ + INIT_LIST_HEAD(&data->simple_data_reader_list); + INIT_LIST_HEAD(&data->mz_data_reader_list); + init_waitqueue_head(&data->waiter_for_data); + data->is_data_valid = false; + + /* Register sysfs hooks under input dev */ + rc = sysfs_create_group(&data->input_dev_ps->dev.kobj, + &stmvl53l1_attr_group); + if (rc) { + rc = -ENOMEM; + vl53l1_errmsg("%d error:%d\n", __LINE__, rc); + goto exit_unregister_dev_ps; + } + rc = sysfs_create_bin_file(&data->input_dev_ps->dev.kobj, + &stmvl53l1_calib_data_attr); + if (rc) { + rc = -ENOMEM; + vl53l1_errmsg("%d error:%d\n", __LINE__, rc); + goto exit_unregister_dev_ps; + } + rc = sysfs_create_bin_file(&data->input_dev_ps->dev.kobj, + &stmvl53l1_zone_calib_data_attr); + if (rc) { + rc = -ENOMEM; + vl53l1_errmsg("%d error:%d\n", __LINE__, rc); + goto exit_unregister_dev_ps; + } + + data->enable_sensor = 0; + + data->poll_delay_ms = STMVL53L1_CFG_POLL_DELAY_MS; + data->timing_budget = STMVL53L1_CFG_TIMING_BUDGET_US; + data->preset_mode = STMVL53L1_CFG_DEFAULT_MODE; + //songyt add default range roi + if(data->preset_mode == VL53L1_PRESETMODE_MULTIZONES_SCANNING + /*|| data->preset_mode == VL53L1_PRESETMODE_RANGING*/){ + data->roi_cfg.NumberOfRoi = 4; + data->roi_cfg.UserRois[0].TopLeftX = 0; + data->roi_cfg.UserRois[0].TopLeftY = 15; + data->roi_cfg.UserRois[0].BotRightX = 7; + data->roi_cfg.UserRois[0].BotRightY = 8; + + data->roi_cfg.UserRois[1].TopLeftX = 8; + data->roi_cfg.UserRois[1].TopLeftY = 15; + data->roi_cfg.UserRois[1].BotRightX = 15; + data->roi_cfg.UserRois[1].BotRightY = 8; + + data->roi_cfg.UserRois[2].TopLeftX = 0; + data->roi_cfg.UserRois[2].TopLeftY = 7; + data->roi_cfg.UserRois[2].BotRightX = 7; + data->roi_cfg.UserRois[2].BotRightY = 0; + + data->roi_cfg.UserRois[3].TopLeftX = 8; + data->roi_cfg.UserRois[3].TopLeftY = 7; + data->roi_cfg.UserRois[3].BotRightX = 15; + data->roi_cfg.UserRois[3].BotRightY = 0; + }else{ + data->roi_cfg.NumberOfRoi = 0; + } + //end + data->distance_mode = STMVL53L1_CFG_DEFAULT_DISTANCE_MODE; + data->crosstalk_enable = STMVL53L1_CFG_DEFAULT_CROSSTALK_ENABLE; + data->output_mode = STMVL53L1_CFG_DEFAULT_OUTPUT_MODE; + data->offset_correction_mode = + STMVL53L1_CFG_DEFAULT_OFFSET_CORRECTION_MODE; + stmvl53l1_setup_auto_config(data); + data->dmax_mode = STMVL53L1_CFG_DEFAULT_DMAX_MODE; + data->smudge_correction_mode = + STMVL53L1_CFG_DEFAULT_SMUDGE_CORRECTION_MODE; + data->current_roi_id = 0; + data->is_xtalk_value_changed = false; + + data->is_delay_allowed = true; + /* need to be done once */ + rc = VL53L1_DataInit(&data->stdev); + data->is_delay_allowed = false; + if (rc) { + vl53l1_errmsg("VL53L1_DataInit %d\n", rc); + goto exit_unregister_dev_ps; + } + + rc = VL53L1_GetDeviceInfo(&data->stdev, &dev_info); + if (rc) { + vl53l1_errmsg("VL53L1_GetDeviceInfo %d\n", rc); + goto exit_unregister_dev_ps; + } + vl53l1_errmsg("device name %s\ntype %s\n", + dev_info.Name, dev_info.Type); + + /* get managed data here */ + rc = VL53L1_GetDmaxReflectance(&data->stdev, &data->dmax_reflectance); + if (rc) { + vl53l1_errmsg("VL53L1_GetDmaxReflectance %d\n", rc); + goto exit_unregister_dev_ps; + } + rc = VL53L1_GetOpticalCenter(&data->stdev, &data->optical_offset_x, + &data->optical_offset_y); + if (rc) { + vl53l1_errmsg("VL53L1_GetOpticalCenter %d\n", rc); + goto exit_unregister_dev_ps; + } + + /* set tuning from stmvl53l1_tunings.h */ + rc = setup_tunings(data); + if (rc) { + vl53l1_errmsg("setup_tunings %d\n", rc); + goto exit_unregister_dev_ps; + } + + /* Set special parameters for VL53L3 (ticket 513812) */ + if (dev_info.ProductType == 0xAA) + { + data->timing_budget = 30000; + data->crosstalk_enable = 1; + data->dmax_mode = VL53L1_DMAXMODE_CUSTCAL_DATA; + data->smudge_correction_mode = VL53L1_SMUDGE_CORRECTION_CONTINUOUS; + data->dmax_reflectance = (5 << 16); + } + /* End of Set special parameters for VL53L3 (ticket 513812) */ + + /* if working in interrupt ask intr to enable and hook the handler */ + data->poll_mode = 0; + rc = stmvl53l1_module_func_tbl.start_intr(data->client_object, + &data->poll_mode); + if (rc < 0) { + vl53l1_errmsg("can't start no intr\n"); + goto exit_unregister_dev_ps; + } + + data->is_first_irq = true; + data->is_first_start_done = false; + data->is_delay_allowed = false; + + /* to register as a misc device */ + data->miscdev.minor = MISC_DYNAMIC_MINOR; + /* multiple dev name use id in name but 1st */ + if (data->id == 0) + strcpy(data->name, VL53L1_MISC_DEV_NAME); + else + sprintf(data->name, "%s%d", VL53L1_MISC_DEV_NAME, data->id); + + data->miscdev.name = data->name; + data->miscdev.fops = &stmvl53l1_ranging_fops; + vl53l1_errmsg("Misc device registration name:%s\n", data->miscdev.name); + rc = misc_register(&data->miscdev); + if (rc != 0) { + vl53l1_errmsg("misc dev reg fail\n"); + goto exit_unregister_dev_ps; + } + /* bring back device under reset */ + reset_hold(data); + rc = stmvl53l1_module_func_tbl.power_down(data->client_object); + if (rc) { + vl53l1_errmsg("%d,error1 power_down rc %d\n", __LINE__, rc); + } + + return 0; + +exit_unregister_dev_ps: + sysfs_remove_bin_file(&data->input_dev_ps->dev.kobj, + &stmvl53l1_zone_calib_data_attr); + sysfs_remove_bin_file(&data->input_dev_ps->dev.kobj, + &stmvl53l1_calib_data_attr); + sysfs_remove_group(&data->input_dev_ps->dev.kobj, + &stmvl53l1_attr_group); + input_unregister_device(data->input_dev_ps); +exit_ipp_cleanup: + stmvl53l1_ipp_cleanup(data); + rc = stmvl53l1_module_func_tbl.power_down(data->client_object); + if (rc) { + vl53l1_errmsg("%d,error2 power_down rc %d\n", __LINE__, rc); + } + + return rc; +} + + +void stmvl53l1_cleanup(struct stmvl53l1_data *data) +{ + int rc; + + vl53l1_dbgmsg("enter\n"); + rc = _ctrl_stop(data); + if (rc < 0) + vl53l1_errmsg("stop failed %d aborting anyway\n", rc); + + if (data->input_dev_ps) { + vl53l1_dbgmsg("to remove sysfs group\n"); + sysfs_remove_group(&data->input_dev_ps->dev.kobj, + &stmvl53l1_attr_group); + sysfs_remove_bin_file(&data->input_dev_ps->dev.kobj, + &stmvl53l1_calib_data_attr); + sysfs_remove_bin_file(&data->input_dev_ps->dev.kobj, + &stmvl53l1_zone_calib_data_attr); + + vl53l1_dbgmsg("to unregister input dev\n"); + input_unregister_device(data->input_dev_ps); + } + + if (!IS_ERR(data->miscdev.this_device) && + data->miscdev.this_device != NULL) { + vl53l1_dbgmsg("to unregister misc dev\n"); + misc_deregister(&data->miscdev); + } + stmvl53l1_ipp_cleanup(data); + /* be sure device is put under reset */ + data->force_device_on_en = false; + reset_hold(data); + stmvl53l1_module_func_tbl.power_down(data->client_object); + vl53l1_dbgmsg("done\n"); + deallocate_dev_id(data->id); + data->is_device_remove = true; +} + +#ifdef CONFIG_PM_SLEEP +void stmvl53l1_pm_suspend_stop(struct stmvl53l1_data *data) +{ + int rc; + + vl53l1_dbgmsg("Enter\n"); + + rc = _ctrl_stop(data); + if (rc < 0) + vl53l1_errmsg("stop failed %d aborting anyway\n", rc); + + vl53l1_dbgmsg("done\n"); +} +#endif + +static long stmvl53l1_ioctl(struct file *file, + unsigned int cmd, unsigned long arg) +{ + long ret; + struct stmvl53l1_data *data = + container_of(file->private_data, + struct stmvl53l1_data, miscdev); + ret = stmvl53l1_ioctl_handler(data, cmd, arg, (void __user *)arg); + return ret; +} + +static int __init stmvl53l1_init(void) +{ + int rc = 0; + rc = stmvl53l1_ipp_init(); + vl53l1_dbgmsg("Enter,rc=%d\n",rc); + if (rc){ + stmvl53l1_ipp_exit(); + return rc; + } + ipp_inited = true; + return rc; +} + +static int __init stmvl53l1_late_init(void) +{ + int rc = 0; + + vl53l1_dbgmsg("Enter,rc=%d\n",rc); + rc = 0; + /* + if (rc) + goto done; + */ + /* i2c/cci client specific init function */ + rc = stmvl53l1_module_func_tbl.init(); + if (rc){ + if(ipp_inited) + stmvl53l1_ipp_exit(); + ipp_inited = false; + } +/* +done: +*/ + vl53l1_dbgmsg("End %d\n", rc); + + return rc; +} + +static void __exit stmvl53l1_exit(void) +{ + vl53l1_dbgmsg("Enter\n"); + stmvl53l1_module_func_tbl.deinit(NULL); + if (stmvl53l1_module_func_tbl.clean_up != NULL) + stmvl53l1_module_func_tbl.clean_up(); + if(ipp_inited) + stmvl53l1_ipp_exit(); + vl53l1_dbgmsg("End\n"); +} + +/* MODULE_DEVICE_TABLE(i2c, stmvl53l1_id); */ +MODULE_AUTHOR("STMicroelectronics Imaging Division"); +MODULE_DESCRIPTION("ST FlightSense Time-of-Flight sensor driver"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(DRIVER_VERSION); + +module_init(stmvl53l1_init); +late_initcall(stmvl53l1_late_init); +module_exit(stmvl53l1_exit); diff --git a/drivers/input/misc/vl53L1/kona/stmvl53l1_tunings.h b/drivers/input/misc/vl53L1/kona/stmvl53l1_tunings.h new file mode 100644 index 000000000000..6a92a3b2c3c2 --- /dev/null +++ b/drivers/input/misc/vl53L1/kona/stmvl53l1_tunings.h @@ -0,0 +1,42 @@ +/************************************************************************** + * Copyright (c) 2016, STMicroelectronics - All Rights Reserved + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ****************************************************************************/ + +/* + * THIS IS A GENERATED FILE + */ + +#ifndef STMVL53L1_TUNINGS_H +#define STMVL53L1_TUNINGS_H + +static const int tunings[][2] = { +}; + +#endif /* STMVL53L1_TUNINGS_H */ diff --git a/drivers/input/misc/vl53L1/kona/vl53l1_platform.h b/drivers/input/misc/vl53L1/kona/vl53l1_platform.h new file mode 100644 index 000000000000..742e25aa66da --- /dev/null +++ b/drivers/input/misc/vl53L1/kona/vl53l1_platform.h @@ -0,0 +1,444 @@ +/************************************************************************** + * Copyright (c) 2016, STMicroelectronics - All Rights Reserved + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ****************************************************************************/ + + +#ifndef _VL53L1_PLATFORM_H_ +#define _VL53L1_PLATFORM_H_ + +#include "vl53l1_ll_def.h" +#include "vl53l1_platform_log.h" + +#define VL53L1_IPP_API +#include "vl53l1_platform_ipp_imports.h" +#include "vl53l1_platform_user_data.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +/** + * @file vl53l1_platform.h + * + * @brief All end user OS/platform/application porting + */ + + + +/** + * @brief Initialise platform comms. + * + * @param[in] pdev : pointer to device structure (device handle) + * @param[in] comms_type : selects between I2C and SPI + * @param[in] comms_speed_khz : unsigned short containing the I2C speed in kHz + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_CommsInitialise( + VL53L1_Dev_t *pdev, + uint8_t comms_type, + uint16_t comms_speed_khz); + + +/** + * @brief Close platform comms. + * + * @param[in] pdev : pointer to device structure (device handle) + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_CommsClose( + VL53L1_Dev_t *pdev); + + +/** + * @brief Writes the supplied byte buffer to the device + * + * @param[in] pdev : pointer to device structure (device handle) + * @param[in] index : uint16_t register index value + * @param[in] pdata : pointer to uint8_t (byte) buffer containing the data + * to be written + * @param[in] count : number of bytes in the supplied byte buffer + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_WriteMulti( + VL53L1_Dev_t *pdev, + uint16_t index, + uint8_t *pdata, + uint32_t count); + + +/** + * @brief Reads the requested number of bytes from the device + * + * @param[in] pdev : pointer to device structure (device handle) + * @param[in] index : uint16_t register index value + * @param[out] pdata : pointer to the uint8_t (byte) buffer to store read + * data + * @param[in] count : number of bytes to read + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_ReadMulti( + VL53L1_Dev_t *pdev, + uint16_t index, + uint8_t *pdata, + uint32_t count); + + +/** + * @brief Writes a single byte to the device + * + * @param[in] pdev : pointer to device structure (device handle) + * @param[in] index : uint16_t register index value + * @param[in] data : uint8_t data value to write + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_WrByte( + VL53L1_Dev_t *pdev, + uint16_t index, + uint8_t data); + + +/** + * @brief Writes a single word (16-bit unsigned) to the device + * + * Manages the big-endian nature of the device register map + * (first byte written is the MS byte). + * + * @param[in] pdev : pointer to device structure (device handle) + * @param[in] index : uint16_t register index value + * @param[in] data : uin16_t data value write + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_WrWord( + VL53L1_Dev_t *pdev, + uint16_t index, + uint16_t data); + + +/** + * @brief Writes a single dword (32-bit unsigned) to the device + * + * Manages the big-endian nature of the device register map + * (first byte written is the MS byte). + * + * @param[in] pdev : pointer to device structure (device handle) + * @param[in] index : uint16_t register index value + * @param[in] data : uint32_t data value to write + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_WrDWord( + VL53L1_Dev_t *pdev, + uint16_t index, + uint32_t data); + + + +/** + * @brief Reads a single byte from the device + * + * @param[in] pdev : pointer to device structure (device handle) + * @param[in] index : uint16_t register index + * @param[out] pdata : pointer to uint8_t data value + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + * + */ + +VL53L1_Error VL53L1_RdByte( + VL53L1_Dev_t *pdev, + uint16_t index, + uint8_t *pdata); + + +/** + * @brief Reads a single word (16-bit unsigned) from the device + * + * Manages the big-endian nature of the device (first byte read is the MS byte). + * + * @param[in] pdev : pointer to device structure (device handle) + * @param[in] index : uint16_t register index value + * @param[out] pdata : pointer to uint16_t data value + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_RdWord( + VL53L1_Dev_t *pdev, + uint16_t index, + uint16_t *pdata); + + +/** + * @brief Reads a single dword (32-bit unsigned) from the device + * + * Manages the big-endian nature of the device (first byte read is the MS byte). + * + * @param[in] pdev : pointer to device structure (device handle) + * @param[in] index : uint16_t register index value + * @param[out] pdata : pointer to uint32_t data value + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_RdDWord( + VL53L1_Dev_t *pdev, + uint16_t index, + uint32_t *pdata); + + + +/** + * @brief Implements a programmable wait in us + * + * @param[in] pdev : pointer to device structure (device handle) + * @param[in] wait_us : integer wait in micro seconds + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_WaitUs( + VL53L1_Dev_t *pdev, + int32_t wait_us); + + +/** + * @brief Implements a programmable wait in ms + * + * @param[in] pdev : pointer to device structure (device handle) + * @param[in] wait_ms : integer wait in milliseconds + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_WaitMs( + VL53L1_Dev_t *pdev, + int32_t wait_ms); + + +/** + * @brief Get the frequency of the timer used for ranging results time stamps + * + * @param[out] ptimer_freq_hz : pointer for timer frequency + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_GetTimerFrequency(int32_t *ptimer_freq_hz); + +/** + * @brief Get the timer value in units of timer_freq_hz (see + * VL53L1_get_timestamp_frequency()) + * + * @param[out] ptimer_count : pointer for timer count value + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_GetTimerValue(int32_t *ptimer_count); + + +/** + * @brief Set the mode of a specified GPIO pin + * + * @param pin - an identifier specifying the pin being modified - defined per + * platform + * + * @param mode - an identifier specifying the requested mode - defined per + * platform + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_GpioSetMode(uint8_t pin, uint8_t mode); + + +/** + * @brief Set the value of a specified GPIO pin + * + * @param pin - an identifier specifying the pin being modified - defined per + * platform + * + * @param value - a value to set on the GPIO pin - typically 0 or 1 + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_GpioSetValue(uint8_t pin, uint8_t value); + + +/** + * @brief Get the value of a specified GPIO pin + * + * @param pin - an identifier specifying the pin being modified - defined per + * platform + * + * @param pvalue - a value retrieved from the GPIO pin - typically 0 or 1 + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_GpioGetValue(uint8_t pin, uint8_t *pvalue); + + +/** + * @brief Sets and clears the XShutdown pin on the Ewok + * + * @param value - the value for xshutdown - 0 = in reset, 1 = operational + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_GpioXshutdown(uint8_t value); + + +/** + * @brief Sets and clears the Comms Mode pin (NCS) on the Ewok + * + * @param value - the value for comms select - 0 = I2C, 1 = SPI + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_GpioCommsSelect(uint8_t value); + + +/** + * @brief Enables and disables the power to the Ewok module + * + * @param value - the state of the power supply - 0 = power off, 1 = power on + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_GpioPowerEnable(uint8_t value); + +/** + * @brief Enables callbacks to the supplied funtion pointer when Ewok interrupts + * ocurr + * + * @param function - a function callback supplies by the caller, for interrupt + * notification + * @param edge_type - falling edge or rising edge interrupt detection + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_GpioInterruptEnable(void (*function)(void), + uint8_t edge_type); + + +/** + * @brief Disables the callback on Ewok interrupts + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_GpioInterruptDisable(void); + + +/* + * @brief Gets current system tick count in [ms] + * + * @return time_ms : current time in [ms] + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_GetTickCount( + uint32_t *ptime_ms); + + +/** + * @brief Register "wait for value" polling routine + * + * Port of the V2WReg Script function WaitValueMaskEx() + * + * @param[in] pdev : pointer to device structure (device handle) + * @param[in] timeout_ms : timeout in [ms] + * @param[in] index : uint16_t register index value + * @param[in] value : value to wait for + * @param[in] mask : mask to be applied before comparison with value + * @param[in] poll_delay_ms : polling delay been each read transaction in [ms] + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_WaitValueMaskEx( + VL53L1_Dev_t *pdev, + uint32_t timeout_ms, + uint16_t index, + uint8_t value, + uint8_t mask, + uint32_t poll_delay_ms); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/drivers/input/misc/vl53L1/kona/vl53l1_platform_ipp.h b/drivers/input/misc/vl53L1/kona/vl53l1_platform_ipp.h new file mode 100644 index 000000000000..c6a93e1a3406 --- /dev/null +++ b/drivers/input/misc/vl53L1/kona/vl53l1_platform_ipp.h @@ -0,0 +1,191 @@ +/************************************************************************** + * Copyright (c) 2016, STMicroelectronics - All Rights Reserved + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ****************************************************************************/ + + +#ifndef _VL53L1_PLATFORM_IPP_H_ +#define _VL53L1_PLATFORM_IPP_H_ + +#include "vl53l1_ll_def.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +/** + * @file vl53l1_platform_ipp.h + * + * @brief EwokPlus25 IPP Wrapper Functions + */ + +/** + * @brief IPP Wrapper call for histogram post processing + * + * + * @param[in] Dev : Device handle + * @param[in] pdmax_cal : DMAX calibration data + * @param[in] pdmax_cfg : DMAX configuration data + * @param[in] ppost_cfg : VL53L1_hist_post_process_config_t + * @param[in] pbins : Input histogram raw bin data + * @param[in] pxtalk : Cross talk histogram data + * @param[out] presults : Output VL53L1_range_results_t + * structure + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_ipp_hist_process_data( + VL53L1_DEV Dev, + VL53L1_dmax_calibration_data_t *pdmax_cal, + VL53L1_hist_gen3_dmax_config_t *pdmax_cfg, + VL53L1_hist_post_process_config_t *ppost_cfg, + VL53L1_histogram_bin_data_t *pbins, + VL53L1_xtalk_histogram_data_t *pxtalk, + uint8_t *pArea1, + uint8_t *pArea2, + uint8_t *phisto_merge_nb, + VL53L1_range_results_t *presults); + + +/** + * @brief IPP Wrapper call for histogram ambient dmax calc + * + * The target reflectance in percent for the DMAX calculation + * is set by target_reflectance input + * + * The fixed point format is 7.2 + * + * @param[in] Dev : Device handle + * @param[in] target_reflectance : target reflectance to report ambient DMAX + * Percentage in 7.2 fixed point format + * @param[in] pdmax_cal : DMAX calibration data + * @param[in] pdmax_cfg : DMAX configuration data + * @param[in] pbins : Input histogram raw bin data + * @param[out] pambient_dmax_mm : Output ambient DMAX distance in [mm] + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_ipp_hist_ambient_dmax( + VL53L1_DEV Dev, + uint16_t target_reflectance, + VL53L1_dmax_calibration_data_t *pdmax_cal, + VL53L1_hist_gen3_dmax_config_t *pdmax_cfg, + VL53L1_histogram_bin_data_t *pbins, + int16_t *pambient_dmax_mm); + + +/** + * @brief IPP Wrapper call for xtalk calibration post processing + * + * @param[in] Dev : Device handle + * @param[in] pxtalk_ranges : Input VL53L1_xtalk_range_results_t + * Must contain 5 ranges, 4 quadrants + 1 + * full FoV + * @param[out] pxtalk_shape : Output normalised Cross talk histogram + * shape + * @param[out] pxtalk_cal : Output VL53L1_xtalk_calibration_results_t + * structure + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_ipp_xtalk_calibration_process_data( + VL53L1_DEV Dev, + VL53L1_xtalk_range_results_t *pxtalk_ranges, + VL53L1_xtalk_histogram_data_t *pxtalk_shape, + VL53L1_xtalk_calibration_results_t *pxtalk_cal); + + +/** + * @brief IPP Wrapper call for applying histogram xtalk correction + * + * @param[in] Dev : Device handle + * @param[in] pcustomer : Pointer to input customer data structure + * @param[in] pdyn_cfg : Pointer to input dynamic parameters + * structure + * @param[in] pxtalk_shape : Pointer to input normalised xtalk + * histogram shape + * @param[in] pip_hist_data : Pointer to input histogram data struct + * @param[out] pop_hist_data : Pointer to output xtalk corrected + * histogram data struct + * @param[out] pxtalk_count_data : Pointer to output xtalk histogram + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_ipp_hist_xtalk_correction( + VL53L1_DEV Dev, + VL53L1_customer_nvm_managed_t *pcustomer, + VL53L1_dynamic_config_t *pdyn_cfg, + VL53L1_xtalk_histogram_data_t *pxtalk_shape, + VL53L1_histogram_bin_data_t *pip_hist_data, + VL53L1_histogram_bin_data_t *pop_hist_data, + VL53L1_histogram_bin_data_t *pxtalk_count_data); + +/** + * @brief IPP Wrapper call for Generating Xtalk data from dual reflectance + * histogram data + * + * @param[in] Dev : Device handle + * @param[in] pxtalk_results : Pointer to xtalk_results structure + * containing dual reflectance + * histogram data + * @param[in] expected_target_distance_mm : User input of true target distance + * @param[in] higher_reflectance : User input detailing which + * histogram data 1 or 2 has the + * highest reflectance. + * @param[out] pxtalk_avg_samples : Pointer to output xtalk histogram + * data + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_ipp_generate_dual_reflectance_xtalk_samples( + VL53L1_DEV Dev, + VL53L1_xtalk_range_results_t *pxtalk_results, + uint16_t expected_target_distance_mm, + uint8_t higher_reflectance, + VL53L1_histogram_bin_data_t *pxtalk_avg_samples); + + + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/drivers/input/misc/vl53L1/kona/vl53l1_platform_ipp_imports.h b/drivers/input/misc/vl53L1/kona/vl53l1_platform_ipp_imports.h new file mode 100644 index 000000000000..b7700a919089 --- /dev/null +++ b/drivers/input/misc/vl53L1/kona/vl53l1_platform_ipp_imports.h @@ -0,0 +1,36 @@ +/************************************************************************** + * Copyright (c) 2016, STMicroelectronics - All Rights Reserved + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ****************************************************************************/ + + +#ifndef _VL53L1_PLATFORM_IPP_IMPORTS_H_ +#define _VL53L1_PLATFORM_IPP_IMPORTS_H_ + +#endif diff --git a/drivers/input/misc/vl53L1/kona/vl53l1_platform_log.h b/drivers/input/misc/vl53L1/kona/vl53l1_platform_log.h new file mode 100644 index 000000000000..357e0abb9773 --- /dev/null +++ b/drivers/input/misc/vl53L1/kona/vl53l1_platform_log.h @@ -0,0 +1,177 @@ +/************************************************************************** + * Copyright (c) 2016, STMicroelectronics - All Rights Reserved + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ****************************************************************************/ + +/** + * @file vl53l1_platform_log.h + * + * @brief EwokPlus25 platform logging function definition + */ + + +#ifndef _VL53L1_PLATFORM_LOG_H_ +#define _VL53L1_PLATFORM_LOG_H_ + +#include + +#ifdef VL53L1_LOG_ENABLE + #include "vl53l1_platform_user_config.h" + + #ifdef _MSC_VER + # define EWOKPLUS_EXPORTS __declspec(dllexport) + #else + # define EWOKPLUS_EXPORTS + #endif + + #include "vl53l1_types.h" + + #ifdef __cplusplus + extern "C" { + #endif + + #include + + /** + * @brief Set the level, output and specific functions for module + * logging. + * + * + * @param filename - full path of output log file, NULL for print to + * stdout + * + * @param modules - Module or None or All to trace + * VL53L1_TRACE_MODULE_NONE + * VL53L1_TRACE_MODULE_API + * VL53L1_TRACE_MODULE_CORE + * VL53L1_TRACE_MODULE_TUNING + * VL53L1_TRACE_MODULE_CHARACTERISATION + * VL53L1_TRACE_MODULE_PLATFORM + * VL53L1_TRACE_MODULE_ALL + * + * @param level - trace level + * VL53L1_TRACE_LEVEL_NONE + * VL53L1_TRACE_LEVEL_ERRORS + * VL53L1_TRACE_LEVEL_WARNING + * VL53L1_TRACE_LEVEL_INFO + * VL53L1_TRACE_LEVEL_DEBUG + * VL53L1_TRACE_LEVEL_ALL + * VL53L1_TRACE_LEVEL_IGNORE + * + * @param functions - function level to trace; + * VL53L1_TRACE_FUNCTION_NONE + * VL53L1_TRACE_FUNCTION_I2C + * VL53L1_TRACE_FUNCTION_ALL + * + * @return status - always VL53L1_ERROR_NONE + * + */ + + #define VL53L1_TRACE_LEVEL_NONE 0x00000000 + #define VL53L1_TRACE_LEVEL_ERRORS 0x00000001 + #define VL53L1_TRACE_LEVEL_WARNING 0x00000002 + #define VL53L1_TRACE_LEVEL_INFO 0x00000004 + #define VL53L1_TRACE_LEVEL_DEBUG 0x00000008 + #define VL53L1_TRACE_LEVEL_ALL 0x00000010 + #define VL53L1_TRACE_LEVEL_IGNORE 0x00000020 + + #define VL53L1_TRACE_FUNCTION_NONE 0x00000000 + #define VL53L1_TRACE_FUNCTION_I2C 0x00000001 + #define VL53L1_TRACE_FUNCTION_ALL 0x7fffffff + + #define VL53L1_TRACE_MODULE_NONE 0x00000000 + #define VL53L1_TRACE_MODULE_API 0x00000001 + #define VL53L1_TRACE_MODULE_CORE 0x00000002 + #define VL53L1_TRACE_MODULE_PROTECTED 0x00000004 + #define VL53L1_TRACE_MODULE_HISTOGRAM 0x00000008 + #define VL53L1_TRACE_MODULE_REGISTERS 0x00000010 + #define VL53L1_TRACE_MODULE_PLATFORM 0x00000020 + #define VL53L1_TRACE_MODULE_NVM 0x00000040 + #define VL53L1_TRACE_MODULE_CALIBRATION_DATA 0x00000080 + #define VL53L1_TRACE_MODULE_NVM_DATA 0x00000100 + #define VL53L1_TRACE_MODULE_HISTOGRAM_DATA 0x00000200 + #define VL53L1_TRACE_MODULE_RANGE_RESULTS_DATA 0x00000400 + #define VL53L1_TRACE_MODULE_XTALK_DATA 0x00000800 + #define VL53L1_TRACE_MODULE_OFFSET_DATA 0x00001000 + #define VL53L1_TRACE_MODULE_DATA_INIT 0x00002000 + #define VL53L1_TRACE_MODULE_REF_SPAD_CHAR 0x00004000 + #define VL53L1_TRACE_MODULE_SPAD_RATE_MAP 0x00008000 + #ifdef PAL_EXTENDED + #define VL53L1_TRACE_MODULE_SPAD 0x01000000 + #define VL53L1_TRACE_MODULE_FMT 0x02000000 + #define VL53L1_TRACE_MODULE_UTILS 0x04000000 + #define VL53L1_TRACE_MODULE_BENCH_FUNCS 0x08000000 + #endif + #define VL53L1_TRACE_MODULE_CUSTOMER_API 0x40000000 + #define VL53L1_TRACE_MODULE_ALL 0x7fffffff + + extern void log_trace_print(uint32_t module, uint32_t level, + uint32_t function, const char *format, ...); + + #define _LOG_TRACE_PRINT_FMT(module, level, function, format, ...) \ + log_trace_print(module, level, function, \ + KERN_INFO " " format, ##__VA_ARGS__) + #define _LOG_TRACE_PRINT(module, level, function, ...) \ + _LOG_TRACE_PRINT_FMT(module, level, function, ##__VA_ARGS__) + #define _LOG_FUNCTION_START(module, fmt, ...) \ + log_trace_print(module, VL53L1_TRACE_LEVEL_NONE, \ + VL53L1_TRACE_FUNCTION_ALL, \ + KERN_INFO " %s "fmt"\n", __func__, ##__VA_ARGS__) + #define _LOG_FUNCTION_END(module, status, ...) \ + log_trace_print(module, VL53L1_TRACE_LEVEL_NONE, \ + VL53L1_TRACE_FUNCTION_ALL, \ + KERN_INFO " %s %d\n", __func__, status) + #define _LOG_FUNCTION_END_FMT(module, status, fmt, ...) \ + log_trace_print(module, VL53L1_TRACE_LEVEL_NONE, \ + VL53L1_TRACE_FUNCTION_ALL, \ + KERN_INFO " %s %d"fmt"\n", __func__, status, \ + ##__VA_ARGS__) + #define _LOG_GET_TRACE_FUNCTIONS() 0 + #define _LOG_SET_TRACE_FUNCTIONS(functions) + + #define _LOG_STRING_BUFFER(x) char x[VL53L1_MAX_STRING_LENGTH] + + #ifdef __cplusplus + } + #endif + +#else /* VL53L1_LOG_ENABLE - no logging */ + #include "vl53l1_platform_user_config.h" + + #define _LOG_TRACE_PRINT(module, level, function, ...) + #define _LOG_FUNCTION_START(module, fmt, ...) + #define _LOG_FUNCTION_END(module, status, ...) + #define _LOG_FUNCTION_END_FMT(module, status, fmt, ...) + #define _LOG_GET_TRACE_FUNCTIONS() 0 + #define _LOG_SET_TRACE_FUNCTIONS(functions) + #define _LOG_STRING_BUFFER(x) + +#endif /* VL53L1_LOG_ENABLE */ + +#endif /* _VL53L1_PLATFORM_LOG_H_ */ diff --git a/drivers/input/misc/vl53L1/kona/vl53l1_platform_user_config.h b/drivers/input/misc/vl53L1/kona/vl53l1_platform_user_config.h new file mode 100644 index 000000000000..396d25762a5d --- /dev/null +++ b/drivers/input/misc/vl53L1/kona/vl53l1_platform_user_config.h @@ -0,0 +1,117 @@ +/************************************************************************** + * Copyright (c) 2016, STMicroelectronics - All Rights Reserved + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ****************************************************************************/ + +/** + * @file vl53l1_platform_user_config.h + * + * @brief EwokPlus compile time user modifiable configuration + */ + + +#ifndef _VL53L1_PLATFORM_USER_CONFIG_H_ +#define _VL53L1_PLATFORM_USER_CONFIG_H_ + +#define VL53L1_BYTES_PER_WORD 2 +#define VL53L1_BYTES_PER_DWORD 4 + +/* Define polling delays */ +#define VL53L1_BOOT_COMPLETION_POLLING_TIMEOUT_MS 500 +#define VL53L1_RANGE_COMPLETION_POLLING_TIMEOUT_MS 2000 +#define VL53L1_TEST_COMPLETION_POLLING_TIMEOUT_MS 60000 + +#define VL53L1_POLLING_DELAY_MS 1 + +/* Define LLD TuningParms Page Base Address + * - Part of Patch_AddedTuningParms_11761 + */ +#define VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS 0x8000 +#define VL53L1_TUNINGPARM_PRIVATE_PAGE_BASE_ADDRESS 0xC000 + +#define VL53L1_GAIN_FACTOR__STANDARD_DEFAULT 0x0800 + /*!< Default standard ranging gain correction factor + * 1.11 format. 1.0 = 0x0800, 0.980 = 0x07D7 + */ +#define VL53L1_GAIN_FACTOR__HISTOGRAM_DEFAULT 0x0800 + /*!< Default histogram ranging gain correction factor + * 1.11 format. 1.0 = 0x0800, 0.975 = 0x07CC + */ + + +#define VL53L1_OFFSET_CAL_MIN_EFFECTIVE_SPADS 0x0500 + /*!< Lower Limit for the MM1 effective SPAD count during offset + * calibration Format 8.8 0x0500 -> 5.0 effective SPADs + */ + +#define VL53L1_OFFSET_CAL_MAX_PRE_PEAK_RATE_MCPS 0x1900 + /*!< Max Limit for the pre range preak rate during offset + * calibration Format 9.7 0x1900 -> 50.0 Mcps. + * If larger then in pile up + */ + +#define VL53L1_OFFSET_CAL_MAX_SIGMA_MM 0x0040 + /*!< Max sigma estimate limit during offset calibration + * Check applies to pre-range, mm1 and mm2 ranges + * Format 14.2 0x0040 -> 16.0mm. + */ + + +#define VL53L1_ZONE_CAL_MAX_PRE_PEAK_RATE_MCPS 0x1900 + /*!< Max Peak Rate Limit for the during zone calibration + * Format 9.7 0x1900 -> 50.0 Mcps. + * If larger then in pile up + */ + +#define VL53L1_ZONE_CAL_MAX_SIGMA_MM 0x0040 + /*!< Max sigma estimate limit during zone calibration + * Format 14.2 0x0040 -> 16.0mm. + */ + + +#define VL53L1_XTALK_EXTRACT_MAX_SIGMA_MM 0x008C + /*!< Max Sigma value allowed for a successful xtalk extraction + * Format 14.2 0x008C -> 35.0 mm. + */ + + +#define VL53L1_MAX_USER_ZONES 169 + /*!< Max number of user Zones - maximal limitation from + * FW stream divide - value of 254 + */ + +#define VL53L1_MAX_RANGE_RESULTS 4 + /*!< Sets the maximum number of targets distances the histogram + * post processing can generate + */ + +#define VL53L1_MAX_STRING_LENGTH 512 + +#endif /* _VL53L1_PLATFORM_USER_CONFIG_H_ */ + diff --git a/drivers/input/misc/vl53L1/kona/vl53l1_platform_user_data.h b/drivers/input/misc/vl53L1/kona/vl53l1_platform_user_data.h new file mode 100644 index 000000000000..41da1dda1235 --- /dev/null +++ b/drivers/input/misc/vl53L1/kona/vl53l1_platform_user_data.h @@ -0,0 +1,63 @@ +/************************************************************************** + * Copyright (c) 2016, STMicroelectronics - All Rights Reserved + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ****************************************************************************/ + + +#ifndef _VL53L1_PLATFORM_USER_DATA_H_ +#define _VL53L1_PLATFORM_USER_DATA_H_ + +#include "vl53l1_ll_def.h" + +#include +#include "vl53l1_def.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include + +#define VL53L1_Dev_t VL53L1_DevData_t +#define VL53L1_DEV VL53L1_DevData_t * + +#define VL53L1DevDataGet(Dev, field) (Dev->field) +#define VL53L1DevDataSet(Dev, field, data) ((Dev->field) = (data)) + +#define VL53L1DevStructGetLLDriverHandle(Dev) (&VL53L1DevDataGet(Dev, LLData)) +#define VL53L1DevStructGetLLResultsHandle(Dev) (&VL53L1DevDataGet(Dev,\ + llresults)) + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/drivers/input/misc/vl53L1/kona/vl53l1_platform_user_defines.h b/drivers/input/misc/vl53L1/kona/vl53l1_platform_user_defines.h new file mode 100644 index 000000000000..731c48341756 --- /dev/null +++ b/drivers/input/misc/vl53L1/kona/vl53l1_platform_user_defines.h @@ -0,0 +1,92 @@ +/************************************************************************** + * Copyright (c) 2016, STMicroelectronics - All Rights Reserved + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ****************************************************************************/ + + +#ifndef _VL53L1_PLATFORM_USER_DEFINES_H_ +#define _VL53L1_PLATFORM_USER_DEFINES_H_ + +#ifdef __cplusplus +extern "C" +{ +#endif + +#ifdef __KERNEL__ +#include +#endif + +/** + * @file vl53l1_platform_user_defines.h + * + * @brief All end user OS/platform/application definitions + */ + + +/** + * @def do_division_u + * @brief customer supplied division operation - 64-bit unsigned + * + * @param dividend unsigned 64-bit numerator + * @param divisor unsigned 64-bit denominator + */ +#ifdef __KERNEL__ +#define do_division_u(dividend, divisor) div64_u64(dividend, divisor) +#else +#define do_division_u(dividend, divisor) (dividend / divisor) +#endif + +/** + * @def do_division_s + * @brief customer supplied division operation - 64-bit signed + * + * @param dividend signed 64-bit numerator + * @param divisor signed 64-bit denominator + */ +#ifdef __KERNEL__ +#define do_division_s(dividend, divisor) div64_s64(dividend, divisor) +#else +#define do_division_s(dividend, divisor) (dividend / divisor) +#endif + +#define WARN_OVERRIDE_STATUS(__X__)\ + trace_print(VL53L1_TRACE_LEVEL_WARNING, #__X__) + + +#define DISABLE_WARNINGS() +#define ENABLE_WARNINGS() + + + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/drivers/input/misc/vl53L1/kona/vl53l1_types.h b/drivers/input/misc/vl53L1/kona/vl53l1_types.h new file mode 100644 index 000000000000..3d78e2559204 --- /dev/null +++ b/drivers/input/misc/vl53L1/kona/vl53l1_types.h @@ -0,0 +1,46 @@ +/************************************************************************** + * Copyright (c) 2016, STMicroelectronics - All Rights Reserved + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ****************************************************************************/ +/** + * @file vl53l1_types.h + * @brief VL53L1 types definition + */ + +#ifndef _VL53L1_TYPES_H_ +#define _VL53L1_TYPES_H_ + +#include +/** use where fractional values are expected + * + * Given a floating point value f it's .16 bit point is (int)(f*(1<<16)) + */ +typedef uint32_t FixPoint1616_t; + +#endif /* VL53L1_TYPES_H_ */ diff --git a/drivers/input/misc/vl53L1/lito/Kbuild b/drivers/input/misc/vl53L1/lito/Kbuild new file mode 100644 index 000000000000..a4a62d819181 --- /dev/null +++ b/drivers/input/misc/vl53L1/lito/Kbuild @@ -0,0 +1,30 @@ +# +# Kbuild for the vl53L1 drivers. +# + +ccflags-y += -I$(src)/inc -I$(src)/ipp -I$(src) +ccflags-y += -Itechpack/camera/drivers/cam_sensor_module/cam_cci + +# define this environment variable if you want to compile driver for an old +# kernel +ifdef OLD_NETLINK_API +ccflags-y += -DOLD_NETLINK_API +endif + +ifdef VL53L1_LOG_ENABLE +ccflags-y += -DVL53L1_LOG_ENABLE +endif + +obj-$(CONFIG_STMVL53L1) += stmvl53l1.o +stmvl53l1-objs := stmvl53l1_module.o stmvl53l1_module-i2c.o stmvl53l1_module-cci.o +stmvl53l1-objs += stmvl53l1_i2c.o stmvl53l1_ipp_nl.o stmvl53l1_log.o +stmvl53l1-objs += src/vl53l1_api.o src/vl53l1_api_core.o +stmvl53l1-objs += src/vl53l1_api_strings.o src/vl53l1_error_strings.o +stmvl53l1-objs += src/vl53l1_core.o src/vl53l1_register_funcs.o +stmvl53l1-objs += src/vl53l1_api_preset_modes.o +stmvl53l1-objs += src/vl53l1_api_calibration.o +stmvl53l1-objs += src/vl53l1_silicon_core.o +stmvl53l1-objs += src/vl53l1_zone_presets.o src/vl53l1_nvm.o +stmvl53l1-objs += src/vl53l1_api_debug.o src/vl53l1_core_support.o +stmvl53l1-objs += src/vl53l1_wait.o ipp/ipp_linux.o +stmvl53l1-objs += src/vl53l1_nvm_debug.o diff --git a/drivers/input/misc/vl53L1/lito/Makefile b/drivers/input/misc/vl53L1/lito/Makefile new file mode 100644 index 000000000000..4dd06f8d49f8 --- /dev/null +++ b/drivers/input/misc/vl53L1/lito/Makefile @@ -0,0 +1,12 @@ +ifneq ($(KERNELRELEASE),) +include Kbuild + +else +KDIR ?= /lib/modules/`uname -r`/build + +default: + CONFIG_STMVL53L1=m $(MAKE) -C $(KDIR) M=$$PWD +clean: + CONFIG_STMVL53L1=m $(MAKE) -C $(KDIR) M=$$PWD clean + +endif \ No newline at end of file diff --git a/drivers/input/misc/vl53L1/lito/inc/vl53l1_api.h b/drivers/input/misc/vl53L1/lito/inc/vl53l1_api.h new file mode 100644 index 000000000000..b2aa4308a334 --- /dev/null +++ b/drivers/input/misc/vl53L1/lito/inc/vl53l1_api.h @@ -0,0 +1,1439 @@ + +/****************************************************************************** + * Copyright (c) 2017, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + + ****************************************************************************** + + 'STMicroelectronics Proprietary license' + + ******************************************************************************* + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + + ******************************************************************************* + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones mentioned above : + + ******************************************************************************* + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + ******************************************************************************* + */ + +#ifndef _VL53L1_API_H_ +#define _VL53L1_API_H_ + +#include "vl53l1_api_strings.h" +#include "vl53l1_api_core.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +#if !defined(VL53L1DevDataGet) +#warning "PALDevDataGet is deprecated define VL53L1DevDataGet instead" +#define VL53L1DevDataGet(Dev, field) (Dev->Data.field) +#endif + +#if !defined(VL53L1DevDataSet) +#warning "PALDevDataSet is deprecated define VL53L1DevDataSet instead" +#define VL53L1DevDataSet(Dev, field, data) ((Dev->Data.field) = (data)) +#endif + +/** @defgroup VL53L1_cut11_group VL53L1 cut1.1 Function Definition + * @brief VL53L1 cut1.1 Function Definition + * @{ + */ + +/** @defgroup VL53L1_general_group VL53L1 General Functions + * @brief General functions and definitions + * @{ + */ + +/** + * @brief Return the VL53L1 driver Version + * + * @note This function doesn't access to the device + * + * @param pVersion Rer to current driver Version + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetVersion(VL53L1_Version_t *pVersion); + +/** + * @brief Reads the Product Revision for a for given Device + * This function can be used to distinguish cut1.0 from cut1.1. + * + * @param Dev Device Handle + * @param pProductRevisionMajor Pointer to Product Revision Major + * for a given Device + * @param pProductRevisionMinor Pointer to Product Revision Minor + * for a given Device + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetProductRevision(VL53L1_DEV Dev, + uint8_t *pProductRevisionMajor, uint8_t *pProductRevisionMinor); + +/** + * @brief Reads the Device information for given Device + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @param pVL53L1_DeviceInfo Pointer to current device info for a given + * Device + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetDeviceInfo(VL53L1_DEV Dev, + VL53L1_DeviceInfo_t *pVL53L1_DeviceInfo); + +/** + * @brief Human readable Range Status string for a given RangeStatus + * + * @note This function doesn't access to the device + * + * @param RangeStatus The RangeStatus code as stored on + * @a VL53L1_RangingMeasurementData_t + * @param pRangeStatusString The returned RangeStatus string. Shall be + * defined as char buf[VL53L1_MAX_STRING_LENGTH] + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetRangeStatusString(uint8_t RangeStatus, + char *pRangeStatusString); + +/** + * @brief Human readable error string for driver error status + * + * @note This function doesn't access to the device + * + * @param PalErrorCode The error code as stored on @a VL53L1_Error + * @param pPalErrorString The error string corresponding to the + * PalErrorCode. Shall be defined as char buf[VL53L1_MAX_STRING_LENGTH] + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetPalErrorString(VL53L1_Error PalErrorCode, + char *pPalErrorString); + +/** + * @brief Human readable driver State string + * + * @note This function doesn't access to the device + * + * @param PalStateCode The State code as stored on @a VL53L1_State + * @param pPalStateString The State string corresponding to the + * PalStateCode. Shall be defined as char buf[VL53L1_MAX_STRING_LENGTH] + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetPalStateString(VL53L1_State PalStateCode, + char *pPalStateString); + +/** + * @brief Reads the internal state of the driver for a given Device + * + * @note This function doesn't access to the device + * + * @param Dev Device Handle + * @param pPalState Pointer to current state of the PAL for a + * given Device + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetPalState(VL53L1_DEV Dev, + VL53L1_State *pPalState); + + + +/** @} VL53L1_general_group */ + +/** @defgroup VL53L1_init_group VL53L1 Init Functions + * @brief VL53L1 Init Functions + * @{ + */ + +/** + * @brief Set new device address + * + * After completion the device will answer to the new address programmed. + * This function should be called when several devices are used in parallel + * before start programming the sensor. + * When a single device us used, there is no need to call this function. + * + * When it is requested for multi devices system this function MUST be called + * prior to VL53L1_DataInit() + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @param DeviceAddress The new Device address + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_SetDeviceAddress(VL53L1_DEV Dev, + uint8_t DeviceAddress); + +/** + * + * @brief One time device initialization + * + * To be called once and only once after device is brought out of reset + * (Chip enable) and booted see @a VL53L1_WaitDeviceBooted() + * + * @par Function Description + * When not used after a fresh device "power up" or reset, it may return + * @a #VL53L1_ERROR_CALIBRATION_WARNING meaning wrong calibration data + * may have been fetched from device that can result in ranging offset error\n + * If application cannot execute device reset or need to run VL53L1_DataInit + * multiple time then it must ensure proper offset calibration saving and + * restore on its own by using @a VL53L1_GetOffsetCalibrationData() on first + * power up and then @a VL53L1_SetOffsetCalibrationData() in all subsequent init + * This function will change the VL53L1_State from VL53L1_STATE_POWERDOWN to + * VL53L1_STATE_WAIT_STATICINIT. + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_DataInit(VL53L1_DEV Dev); + + +/** + * @brief Do basic device init (and eventually patch loading) + * This function will change the VL53L1_State from + * VL53L1_STATE_WAIT_STATICINIT to VL53L1_STATE_IDLE. + * In this stage all default setting will be applied. + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_StaticInit(VL53L1_DEV Dev); + +/** + * @brief Wait for device booted after chip enable (hardware standby) + * This function can be run only when VL53L1_State is VL53L1_STATE_POWERDOWN. + * + * @param Dev Device Handle + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + * + */ +VL53L1_Error VL53L1_WaitDeviceBooted(VL53L1_DEV Dev); + + +/** @} VL53L1_init_group */ + +/** @defgroup VL53L1_parameters_group VL53L1 Parameters Functions + * @brief Functions used to prepare and setup the device + * @{ + */ + +/** + * @brief Set a new Preset Mode + * @par Function Description + * Set device to a new Operating Mode (High speed ranging, Multi objects ...) + * + * @note This function doesn't Access to the device + * + * @warning This function change the timing budget to 16 ms and the inter- + * measurement period to 1000 ms. Also the VL53L1_DISTANCEMODE_LONG is used. + * + * @param Dev Device Handle + * @param PresetMode New Preset mode to apply + *
Valid values are: + */ +/** + * @li VL53L1_PRESETMODE_MULTIZONES_SCANNING + * @li VL53L1_PRESETMODE_RANGING + * @li VL53L1_PRESETMODE_AUTONOMOUS + * @li VL53L1_PRESETMODE_LOWPOWER_AUTONOMOUS + * @li VL53L1_PRESETMODE_LITE_RANGING + * @li VL53L1_PRESETMODE_OLT + */ +/** + * + * @return VL53L1_ERROR_NONE Success + * @return VL53L1_ERROR_MODE_NOT_SUPPORTED This error occurs when PresetMode is + * not in the supported list + */ +VL53L1_Error VL53L1_SetPresetMode(VL53L1_DEV Dev, + VL53L1_PresetModes PresetMode); + +/** + * @brief Get current Preset Mode + * @par Function Description + * Get actual mode of the device(ranging, histogram ...) + * + * @note This function doesn't Access to the device + * + * @param Dev Device Handle + * @param pPresetMode Pointer to current apply mode value + * + * @return VL53L1_ERROR_NONE Success + * @return VL53L1_ERROR_MODE_NOT_SUPPORTED This error occurs when + * DeviceMode is not in the supported list + */ +VL53L1_Error VL53L1_GetPresetMode(VL53L1_DEV Dev, + VL53L1_PresetModes *pPresetMode); + + +/** + * @brief Set the distance mode + * @par Function Description + * Set the distance mode to be used for the next ranging.
+ * The modes Short, Medium and Long are used to optimize the ranging accuracy + * in a specific range of distance.
The user select one of these modes to + * select the distance range.
+ * Two additional modes are supported: AUTO and AUTO_LITE the difference between + * these modes is the following.
+ * The mode AUTO take into account both the ranging distance (RangeMilliMeter) + * and the dmax distance (DmaxMilliMeter).
The algorithm uses the ranging + * distance when the range status is ok and uses the dmax distance when the + * range status is not ok.
+ * The AUTO_LITE take into account only the ranging distance, so nothing is done + * in case of range error i.e. the distance mode will not be changed. + * @note This function doesn't Access to the device + * + * @warning This function should be called after @a VL53L1_SetPresetMode(). + + * @param Dev Device Handle + * @param DistanceMode Distance mode to apply valid values are: + * @li VL53L1_DISTANCEMODE_SHORT + * @li VL53L1_DISTANCEMODE_MEDIUM + * @li VL53L1_DISTANCEMODE_LONG + * @li VL53L1_DISTANCEMODE_AUTO_LITE + * @li VL53L1_DISTANCEMODE_AUTO + * @return VL53L1_ERROR_NONE Success + * @return VL53L1_ERROR_MODE_NOT_SUPPORTED This error occurs when DistanceMode + * is not in the supported list + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_SetDistanceMode(VL53L1_DEV Dev, + VL53L1_DistanceModes DistanceMode); + +/** + * @brief Get the distance mode + * @par Function Description + * Get the distance mode used for the next ranging. + * + * @param Dev Device Handle + * @param *pDistanceMode Pointer to Distance mode + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetDistanceMode(VL53L1_DEV Dev, + VL53L1_DistanceModes *pDistanceMode); + + +/** + * @brief Set the output mode + * @par Function Description + * Set the output mode to be used for the next ranging. The output mode is used + * to select, in case of multiple objects, which one will be used in + * function @a VL53L1_GetRangingMeasurementData(). + * VL53L1_SetOutputMode also sets the object used by automatic + * distance mode algorithm when @a VL53L1_SetDistanceMode() is + * set to automatic mode. + * + * @note This function doesn't Access to the device + * + * @warning This function should be called after @a VL53L1_SetPresetMode(). + + * @param Dev Device Handle + * @param OutputMode Output mode to apply valid values are: + * @li VL53L1_OUTPUTMODE_NEAREST + * @li VL53L1_OUTPUTMODE_STRONGEST + * + * @return VL53L1_ERROR_NONE Success + * @return VL53L1_ERROR_MODE_NOT_SUPPORTED This error occurs when OutputMode + * is not in the supported list + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_SetOutputMode(VL53L1_DEV Dev, + VL53L1_OutputModes OutputMode); + +/** + * @brief Get the output mode + * @par Function Description + * Get the output mode used for the next ranging. + * + * @param Dev Device Handle + * @param *pOutputMode Pointer to Output mode + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetOutputMode(VL53L1_DEV Dev, + VL53L1_OutputModes *pOutputMode); + + +/** + * @brief Set Ranging Timing Budget in microseconds + * + * @par Function Description + * Defines the maximum time allowed by the user to the device to run a + * full ranging sequence for the current mode (ranging, histogram, ASL ...) + * + * @param Dev Device Handle + * @param MeasurementTimingBudgetMicroSeconds Max measurement time in + * microseconds. + * @return VL53L1_ERROR_NONE Success + * @return VL53L1_ERROR_INVALID_PARAMS Error timing parameter not + * supported. + * The maximum accepted value for the + * computed timing budget is 10 seconds + * the minimum value depends on the preset + * mode selected. + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_SetMeasurementTimingBudgetMicroSeconds( + VL53L1_DEV Dev, uint32_t MeasurementTimingBudgetMicroSeconds); + +/** + * @brief Get Ranging Timing Budget in microseconds + * + * @par Function Description + * Returns the programmed the maximum time allowed by the user to the + * device to run a full ranging sequence for the current mode + * (ranging, histogram, ASL ...) + * + * @param Dev Device Handle + * @param pMeasurementTimingBudgetMicroSeconds Max measurement time in + * microseconds. + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetMeasurementTimingBudgetMicroSeconds( + VL53L1_DEV Dev, uint32_t *pMeasurementTimingBudgetMicroSeconds); + + +/** + * Program continuous mode Inter-Measurement period in milliseconds + * + * @par Function Description + * When trying to set too short time return INVALID_PARAMS minimal value + * + * @param Dev Device Handle + * @param InterMeasurementPeriodMilliSeconds Inter-Measurement Period in ms. + * this value should be greater than the duration set in + * @a VL53L1_SetMeasurementTimingBudgetMicroSeconds() to ensure smooth ranging + * operation. + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_SetInterMeasurementPeriodMilliSeconds( + VL53L1_DEV Dev, uint32_t InterMeasurementPeriodMilliSeconds); + +/** + * Get continuous mode Inter-Measurement period in milliseconds + * + * @par Function Description + * + * @param Dev Device Handle + * @param pInterMeasurementPeriodMilliSeconds Pointer to programmed + * Inter-Measurement Period in milliseconds. + * @return VL53L1_ERROR_NONE + */ +VL53L1_Error VL53L1_GetInterMeasurementPeriodMilliSeconds( + VL53L1_DEV Dev, uint32_t *pInterMeasurementPeriodMilliSeconds); + +/** + * @brief target reflectance for Dmax setting + * @par Function Description + * Allow user to set the value for target reflectance @ 940nm to calculate the + * ambient DMAX values for. Set to 50% by default by @a VL53L1_DataInit() + * + * @param Dev Device Handle + * @param DmaxReflectance Reflectance % in 16.16 fixed point + * @return VL53L1_ERROR_NONE Success + * @return VL53L1_ERROR_INVALID_PARAMS in case input value is not in range + * from 0 to 100. Note that this is a fix point value so the max value is + * 100 * 65536. + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_SetDmaxReflectance(VL53L1_DEV Dev, + FixPoint1616_t DmaxReflectance); + +/** + * @brief Get target reflectance for Dmax + * @par Function Description + * Retrieves the value for target reflectance @ 940nm to calculate the + * ambient DMAX values for. Set to 50% by default by @a VL53L1_DataInit() + * + * @param Dev Device Handle + * @param pDmaxReflectance pointer to Reflectance % in 16.16 fixed point + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetDmaxReflectance(VL53L1_DEV Dev, + FixPoint1616_t *pDmaxReflectance); +/** + * @brief Set function for ambient Dmax mode + * + * + * @param Dev Device Handle + * @param DmaxMode DMAX mode to be used in ranging + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + + +VL53L1_Error VL53L1_SetDmaxMode(VL53L1_DEV Dev, + VL53L1_DeviceDmaxModes DmaxMode); + +/** + * @brief Get function for ambient Dmax mode + * + * @param Dev Device Handle + * @param pDmaxMode output pointer to DMAX mode currently in use + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_GetDmaxMode(VL53L1_DEV Dev, + VL53L1_DeviceDmaxModes *pDmaxMode); + +/** @} VL53L1_parameters_group */ + + +/** @defgroup VL53L1_limitcheck_group VL53L1 Limit Check Functions + * @brief Functions used for the Limit checks + * @{ + */ + + + +/** + * @brief Get the number of the check limit managed by a given Device + * + * @par Function Description + * This function give the number of the check limit managed by the Device + * + * @param pNumberOfLimitCheck Pointer to the number of check limit. + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetNumberOfLimitCheck( + uint16_t *pNumberOfLimitCheck); + +/** + * @brief Return a description string for a given limit check number + * + * @par Function Description + * This function returns a description string for a given limit check number. + * The limit check is identified with the LimitCheckId. + * + * @param LimitCheckId Limit Check ID + * (0<= LimitCheckId < VL53L1_GetNumberOfLimitCheck() ). + * @param pLimitCheckString Pointer to the description string of + * the given check limit. Shall be defined as char buf[VL53L1_MAX_STRING_LENGTH] + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetLimitCheckInfo(uint16_t LimitCheckId, + char *pLimitCheckString); + +/** + * @brief Return a the Status of the specified check limit + * + * @par Function Description + * This function returns the Status of the specified check limit. + * The value indicate if the check is fail or not. + * The limit check is identified with the LimitCheckId. + * + * @param Dev Device Handle + * @param LimitCheckId Limit Check ID + (0<= LimitCheckId < VL53L1_GetNumberOfLimitCheck() ). + * @param pLimitCheckStatus Pointer to the + Limit Check Status of the given check limit. + * LimitCheckStatus : + * 0 the check is not fail or not enabled + * 1 the check if fail + * + *

    + *
  • VL53L1_CHECKENABLE_SIGMA_FINAL_RANGE: the sigma indicate the quality + * of the measure. The more it is little the better it is. + * The status is 1 when current sigma is greater then the limit.
  • + *
  • VL53L1_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE: the signal rate indicate + * the strength of the returned signal. The more it is big the better it is. + * The status is 1 when current signal is lower then the limit.
  • + *

+ * + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetLimitCheckStatus(VL53L1_DEV Dev, + uint16_t LimitCheckId, uint8_t *pLimitCheckStatus); + +/** + * @brief Enable/Disable a specific limit check + * + * @par Function Description + * This function Enable/Disable a specific limit check. + * The limit check is identified with the LimitCheckId. + * + * @note This function doesn't Access to the device + * + * @param Dev Device Handle + * @param LimitCheckId Limit Check ID + * (0<= LimitCheckId < VL53L1_GetNumberOfLimitCheck() ). + * @param LimitCheckEnable + * @li set LimitCheckEnable=1 enables the LimitCheckId limit + * @li set LimitCheckEnable=0 disables the LimitCheckId limit + * @return VL53L1_ERROR_NONE Success + * @return VL53L1_ERROR_INVALID_PARAMS This error is returned + * when LimitCheckId value is out of range. + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_SetLimitCheckEnable(VL53L1_DEV Dev, + uint16_t LimitCheckId, uint8_t LimitCheckEnable); + +/** + * @brief Get specific limit check enable state + * + * @par Function Description + * This function get the enable state of a specific limit check. + * The limit check is identified with the LimitCheckId. + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @param LimitCheckId Limit Check ID + * (0<= LimitCheckId < VL53L1_GetNumberOfLimitCheck() ). + * @param pLimitCheckEnable Pointer to the check limit enable + * value. + * @li if 1 the check limit corresponding to LimitCheckId is Enabled + * @li if 0 the check limit corresponding to LimitCheckId is disabled + * @return VL53L1_ERROR_NONE Success + * @return VL53L1_ERROR_INVALID_PARAMS This error is returned + * when LimitCheckId value is out of range. + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetLimitCheckEnable(VL53L1_DEV Dev, + uint16_t LimitCheckId, uint8_t *pLimitCheckEnable); + +/** + * @brief Set a specific limit check value + * + * @par Function Description + * This function set a specific limit check value. + * The limit check is identified with the LimitCheckId. + * + * @note Note that the value written with that function will not be applied if + * the limit is not enabled. In other words this function will not enable the + * limit but change only the value. In case the limit is not enabled the value + * is saved internally and applied with VL53L1_SetLimitCheckEnable. + * + * @param Dev Device Handle + * @param LimitCheckId Limit Check ID + * (0<= LimitCheckId < VL53L1_GetNumberOfLimitCheck() ). + * @param LimitCheckValue Limit check Value for a given + * LimitCheckId + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_SetLimitCheckValue(VL53L1_DEV Dev, + uint16_t LimitCheckId, FixPoint1616_t LimitCheckValue); + +/** + * @brief Get a specific limit check value + * + * @par Function Description + * This function get a specific limit check value from device then it updates + * internal values and check enables. + * The limit check is identified with the LimitCheckId. + * + * @note This function get the current value from device if zero then the value + * returned is the one stored by the user, but in that case the check is store + * as disabled. If the value from device is not zero, this is returned and set + * into the memory at the same way that user call VL53L1_SetLimitCheckValue() + * + * @param Dev Device Handle + * @param LimitCheckId Limit Check ID + * (0<= LimitCheckId < VL53L1_GetNumberOfLimitCheck() ). + * @param pLimitCheckValue Pointer to Limit + * check Value for a given LimitCheckId. + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetLimitCheckValue(VL53L1_DEV Dev, + uint16_t LimitCheckId, FixPoint1616_t *pLimitCheckValue); + +/** + * @brief Get the current value of the signal used for the limit check + * + * @par Function Description + * This function get a the current value of the signal used for the limit check. + * To obtain the latest value you should run a valid ranging before. + * The value reported is linked to the limit check identified with the + * LimitCheckId. + * + * @param Dev Device Handle + * @param LimitCheckId Limit Check ID + * (0<= LimitCheckId < VL53L1_GetNumberOfLimitCheck() ). + * @param pLimitCheckCurrent Pointer to current Value for a + * given LimitCheckId. + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetLimitCheckCurrent(VL53L1_DEV Dev, + uint16_t LimitCheckId, FixPoint1616_t *pLimitCheckCurrent); + +/** @} VL53L1_limitcheck_group */ + + + +/** @defgroup VL53L1_ROI_group VL53L1 ROI Functions + * @brief Functions used to select ROIs + * @{ + */ + +/** + * @brief Get the Maximum number of ROI Zones managed by the Device + * + * @par Function Description + * Get Maximum number of ROI Zones managed by the Device. + * + * @note The number of Zone depends on the preset mode used so to have the + * right number this function should be call after @a VL53L1_SetPresetMode() + * @note This function doesn't Access to the device + * + * @param Dev Device Handle + * @param pMaxNumberOfROI Pointer to the Maximum Number + * of ROI Zones value. + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetMaxNumberOfROI(VL53L1_DEV Dev, + uint8_t *pMaxNumberOfROI); +/** + * @brief Set the ROI to be used for ranging + * + * @par Function Description + * The user defined ROIs are rectangles described as per the following system + * from the Top Left corner to the Bottom Right corner. + *
Minimal ROI size is 4x4 spads + * @image html roi_coord.png + * + * @param Dev Device Handle + * @param pRoiConfig Pointer to the Structure containing all the + * ROI to be used. + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_SetROI(VL53L1_DEV Dev, + VL53L1_RoiConfig_t *pRoiConfig); + +/** + * @brief Get the ROI managed by the Device + * + * @par Function Description + * Get the ROI managed by the Device + * + * @param Dev Device Handle + * @param pRoiConfig Pointer to the Structure containing all the + * ROI to be used. + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetROI(VL53L1_DEV Dev, + VL53L1_RoiConfig_t *pRoiConfig); + +/** @} VL53L1_ROI_group */ + +/* \internal */ +/** @defgroup VL53L1_sequencestep_group VL53L1 Sequence Step Functions + * @brief Functions used to select Steps done on each ranging + * @{ + */ + +/** + * @brief Gets number of sequence steps managed by the API. + * + * @par Function Description + * This function retrieves the number of sequence steps currently managed + * by the API + * + * @note This function Accesses the device + * + * @param Dev Device Handle + * @param pNumberOfSequenceSteps Out parameter reporting the number of + * sequence steps. + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetNumberOfSequenceSteps(VL53L1_DEV Dev, + uint8_t *pNumberOfSequenceSteps); + +/** + * @brief Gets the name of a given sequence step. + * + * @par Function Description + * This function retrieves the name of sequence steps corresponding to + * SequenceStepId. + * + * @note This function doesn't Accesses the device + * + * @param SequenceStepId Sequence step identifier. + * @param pSequenceStepsString Pointer to Info string. Shall be + * defined as char buf[VL53L1_MAX_STRING_LENGTH] + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetSequenceStepsInfo( + VL53L1_SequenceStepId SequenceStepId, char *pSequenceStepsString); + + + +/** + * @brief Sets the (on/off) state of a requested sequence step. + * + * @par Function Description + * This function enables/disables a requested sequence step. + * + * @note This function Accesses the device + * + * @param Dev Device Handle + * @param SequenceStepId Sequence step identifier. + * @param SequenceStepEnabled Demanded state {0=Off,1=On} + * is enabled. + * @return VL53L1_ERROR_NONE Success + * @return VL53L1_ERROR_INVALID_PARAMS Error SequenceStepId parameter not + * supported. + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_SetSequenceStepEnable(VL53L1_DEV Dev, + VL53L1_SequenceStepId SequenceStepId, uint8_t SequenceStepEnabled); + +/** + * @brief Gets the (on/off) state of a requested sequence step. + * + * @par Function Description + * This function retrieves the state of a requested sequence step, i.e. on/off. + * + * @note This function Accesses the device + * + * @param Dev Device Handle + * @param SequenceStepId Sequence step identifier. + * @param pSequenceStepEnabled Out parameter reporting if the sequence step + * is enabled {0=Off,1=On}. + * @return VL53L1_ERROR_NONE Success + * @return VL53L1_ERROR_INVALID_PARAMS Error SequenceStepId parameter not + * supported. + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetSequenceStepEnable(VL53L1_DEV Dev, + VL53L1_SequenceStepId SequenceStepId, uint8_t *pSequenceStepEnabled); + + +/** @} VL53L1_sequencestep_group */ +/* \endinternal */ + + + +/** @defgroup VL53L1_measurement_group VL53L1 Measurement Functions + * @brief Functions used for the measurements + * @{ + */ + +/** + * @brief Start device measurement + * + * @details Started measurement will depend on preset parameters set through + * @a VL53L1_SetPreseMode() + * This function will change the VL53L1_State from VL53L1_STATE_IDLE to + * VL53L1_STATE_RUNNING. + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @return VL53L1_ERROR_NONE Success + * @return VL53L1_ERROR_MODE_NOT_SUPPORTED This error occurs when + * PresetMode programmed with @a VL53L1_SetPresetMode + * @return VL53L1_ERROR_TIME_OUT Time out on start measurement + * @return VL53L1_ERROR_INVALID_PARAMS This error might occur in timed mode + * when inter measurement period is smaller or too close to the timing budget. + * In such case measurements are not started and user must correct the timings + * passed to @a VL53L1_SetMeasurementTimingBudgetMicroSeconds() and + * @a VL53L1_SetInterMeasurementPeriodMilliSeconds() functions. + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_StartMeasurement(VL53L1_DEV Dev); + +/** + * @brief Stop device measurement + * + * @details Will set the device in standby mode at end of current measurement\n + * Not necessary in single mode as device shall return automatically + * in standby mode at end of measurement. + * This function will change the VL53L1_State from VL53L1_STATE_RUNNING + * to VL53L1_STATE_IDLE. + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_StopMeasurement(VL53L1_DEV Dev); + +/** + * @brief Clear the Interrupt flag and start new measurement + * * + * @note This function Access to the device + * + * @param Dev Device Handle + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_ClearInterruptAndStartMeasurement(VL53L1_DEV Dev); + +/** + * @brief Return Measurement Data Ready + * + * @par Function Description + * This function indicate that a measurement data is ready. + * This function is used for non-blocking capture. + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @param pMeasurementDataReady Pointer to Measurement Data Ready. + * 0 = data not ready, 1 = data ready + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetMeasurementDataReady(VL53L1_DEV Dev, + uint8_t *pMeasurementDataReady); + +/** + * @brief Wait for measurement data ready. + * Blocking function. + * Note that the timeout is given by: + * VL53L1_RANGE_COMPLETION_POLLING_TIMEOUT_MS defined in def.h + * + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @return VL53L1_ERROR_NONE Success + * @return VL53L1_ERROR_TIME_OUT In case of timeout + */ +VL53L1_Error VL53L1_WaitMeasurementDataReady(VL53L1_DEV Dev); + + +/** + * @brief Retrieve the measurements from device for a given setup + * + * @par Function Description + * Get data from last successful Ranging measurement + */ +/** + * @warning this function will return only the first ROI data and only the + * first object. For multi objects or multi ROI use: + * @a Vl53L1_GetMultiRangingData. + * In case of RANGING only one output is given, this can + * be selected with the help of @a VL53L1_SetOutputMode() + * In case of MULTIZONES_SCANNING and error will be raised because not + * supported in that function. + */ +/** + * + * @warning USER must call @a VL53L1_ClearInterruptAndStartMeasurement() prior + * to call again this function + * + * @note This function Access to the device + * + * @note The first valid value returned by this function will have a range + * status equal to VL53L1_RANGESTATUS_RANGE_VALID_NO_WRAP_CHECK which means that + * the data is valid but no wrap around check have been done. User should take + * care about that. + * + * @param Dev Device Handle + * @param pRangingMeasurementData Pointer to the data structure to fill up. + * @return VL53L1_ERROR_NONE Success + * @return VL53L1_ERROR_MODE_NOT_SUPPORTED in case of MULTIZONES_SCANNING + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetRangingMeasurementData(VL53L1_DEV Dev, + VL53L1_RangingMeasurementData_t *pRangingMeasurementData); + +/** + * @brief Retrieve all ROI's measurements from device for a given setup + * + * @par Function Description + * Get data from last successful Ranging measurement + * @warning USER should take care about @a VL53L1_GetNumberOfROI() + * before get data. + * Bare driver will fill a NumberOfROI times the corresponding data + * structure used in the measurement function. + * + * @warning USER must call @a VL53L1_ClearInterruptAndStartMeasurement() prior + * to call again this function + * + * @note This function Access to the device + * + * @note The first valid value returned by this function will have a range + * status equal to VL53L1_RANGESTATUS_RANGE_VALID_NO_WRAP_CHECK which means that + * the data is valid but no wrap around check have been done. User should take + * care about that. + * + * @param Dev Device Handle + * @param pMultiRangingData Pointer to the data structure to fill up. + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetMultiRangingData(VL53L1_DEV Dev, + VL53L1_MultiRangingData_t *pMultiRangingData); + +/** + * @brief Get Additional Data + * + * @par Function Description + * This function is used to get lld debugging data on the last histogram + * measurement. shall be called when a new measurement is ready (interrupt or + * positive VL53L1_GetMeasurementDataReady() polling) and before a call to + * VL53L1_ClearInterruptAndStartMeasurement(). Depending on the PresetMode + * currently set parts of the returned data structure may be not relevant. + * + * @param Dev Device Handle + * @param VL53L1_AdditionalData_t Pointer to Additional data + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetAdditionalData(VL53L1_DEV Dev, + VL53L1_AdditionalData_t *pAdditionalData); + + +/** @} VL53L1_measurement_group */ + +/** @defgroup VL53L1_Calibration_group VL53L1 Calibration Functions + * @brief Functions used for Calibration + * @{ + */ + + +/** + * @brief Set Tuning Parameter value for a given parameter ID + * + * @par Function Description + * This function is used to improve the performance of the device. It permit to + * change a particular value used for a timeout or a threshold or a constant + * in an algorithm. The function will change the value of the parameter + * identified by an unique ID. + * + * @note This function doesn't Access to the device + * + * @param Dev Device Handle + * @param TuningParameterId Tuning Parameter ID + * @param TuningParameterValue Tuning Parameter Value + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_SetTuningParameter(VL53L1_DEV Dev, + uint16_t TuningParameterId, int32_t TuningParameterValue); + +/** + * @brief Get Tuning Parameter value for a given parameter ID + * + * @par Function Description + * This function is used to get the value of the parameter + * identified by an unique ID. + * + * @note This function doesn't Access to the device + * + * @param Dev Device Handle + * @param TuningParameterId Tuning Parameter ID + * @param pTuningParameterValue Pointer to Tuning Parameter Value + * for a given TuningParameterId. + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetTuningParameter(VL53L1_DEV Dev, + uint16_t TuningParameterId, int32_t *pTuningParameterValue); + +/** + * @brief Performs Reference Spad Management + * + * @par Function Description + * The reference SPAD initialization procedure determines the minimum amount + * of reference spads to be enables to achieve a target reference signal rate + * and should be performed once during initialization. + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_PerformRefSpadManagement(VL53L1_DEV Dev); + +/** + * @brief Enable/Disable dynamic Xtalk compensation feature + * + * Enable/Disable dynamic Xtalk compensation (aka smudge correction). + * + * @param Dev Device Handle + * @param Mode Set the smudge correction mode + * See ::VL53L1_SmudgeCorrectionModes + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_SmudgeCorrectionEnable(VL53L1_DEV Dev, + VL53L1_SmudgeCorrectionModes Mode); + +/** + * @brief Enable/Disable Cross talk compensation feature + * + * Enable/Disable Cross Talk correction. + * + * @param Dev Device Handle + * @param XTalkCompensationEnable Cross talk compensation + * to be set 0 = disabled or 1 = enabled. + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_SetXTalkCompensationEnable(VL53L1_DEV Dev, +uint8_t XTalkCompensationEnable); + +/** + * @brief Get Cross talk compensation rate enable + * + * Get if the Cross Talk is Enabled or Disabled. + * + * @note This function doesn't access to the device + * + * @param Dev Device Handle + * @param pXTalkCompensationEnable Pointer to the Cross talk compensation + * state 0=disabled or 1 = enabled + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetXTalkCompensationEnable(VL53L1_DEV Dev, + uint8_t *pXTalkCompensationEnable); + + +/** + * @brief Perform XTalk Calibration + * + * @details Perform a XTalk calibration of the Device. + * This function will launch a ranging measurement, if interrupts + * are enabled an interrupt will be done. + * This function will clear the interrupt generated automatically. + * This function will program a new value for the XTalk compensation + * and it will enable the cross talk before exit. + * + * @warning This function is a blocking function + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @param CalibrationOption Select the Calibration to be run : + * @param VL53L1_XTALKCALIBRATIONMODE_NO_TARGET the + * calibration works on its own and changes the current preset mode so user + * must call again @a VL53L1_SetPresetMode() after the calibration + * @param CalibrationOption + * @li VL53L1_XTALKCALIBRATIONMODE_SINGLE_TARGET the calibration uses current + * preset and distance mode without altering them.
+ * User must call @a VL53L1_SetPresetMode() with VL53L1_PRESETMODE_AUTONOMOUS, + * VL53L1_PRESETMODE_LITE_RANGING or VL53L1_PRESETMODE_LOWPOWER_AUTONOMOUS + * parameter prior to launch calibration + * @li VL53L1_XTALKCALIBRATIONMODE_NO_TARGET the calibration sets appropriate + * preset and distance mode and thus override existing ones
+ * User must call @a VL53L1_SetPresetMode() again after calibration to set the + * desired one. during this calibration mode no object must be put below a 80cm + * distance from the target + * @li VL53L1_XTALKCALIBRATIONMODE_FULL_ROI the calibration sets appropriate + * preset and distance mode and thus override existing ones
+ * User must call @a VL53L1_SetPresetMode() again after calibration to set the + * desired one. + * The ROI settings must define a single 16x16 ROI before to launch this + * function. + * The calibration uses a target which should be located at least @60cm from the + * device. The actual location of the target shall be passed + * through the bare driver tuning parameters table + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_PerformXTalkCalibration(VL53L1_DEV Dev, + uint8_t CalibrationOption); + +/** + * @brief Define the mode to be used for the offset calibration + * + * Define the mode to be used for the offset calibration. This function should + * be called before run the @a VL53L1_PerformOffsetCalibration() + * + * @param Dev Device Handle + * @param OffsetCalibrationMode Offset Calibration Mode valid values are: + * @li VL53L1_OFFSETCALIBRATIONMODE_STANDARD + * @li VL53L1_OFFSETCALIBRATIONMODE_PRERANGE_ONLY + */ +/** + * @li VL53L1_OFFSETCALIBRATIONMODE_MULTI_ZONE + */ +/** + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_SetOffsetCalibrationMode(VL53L1_DEV Dev, + VL53L1_OffsetCalibrationModes OffsetCalibrationMode); + +/** + * @brief Define the mode to be used for the offset correction + * + * Define the mode to be used for the offset correction. + * + * @param Dev Device Handle + * @param OffsetCorrectionMode Offset Correction Mode valid values are: + * @li VL53L1_OFFSETCORRECTIONMODE_STANDARD + * @li VL53L1_OFFSETCORRECTIONMODE_PERZONE + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_SetOffsetCorrectionMode(VL53L1_DEV Dev, + VL53L1_OffsetCorrectionModes OffsetCorrectionMode); + + +/** + * @brief Perform Offset Calibration + * + * @details Perform a Offset calibration of the Device. + * This function will launch a ranging measurement, if interrupts are + * enabled interrupts will be done. + * This function will program a new value for the Offset calibration value + * + * @warning This function is a blocking function + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @param CalDistanceMilliMeter Calibration distance value used for the + * offset compensation. + * @param CalReflectancePercent Calibration Target reflectance @ 940nm + * in percentage. + * + * @return VL53L1_ERROR_NONE + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_PerformOffsetCalibration(VL53L1_DEV Dev, + int32_t CalDistanceMilliMeter, + FixPoint1616_t CalReflectancePercent); + +/** + * @brief Perform Offset simple Calibration + * + * @details Perform a very simple offset calibration of the Device. + * This function will launch few ranging measurements and computes offset + * calibration. The preset mode and the distance mode MUST be set by the + * application before to call this function. + * + * @warning This function is a blocking function + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @param CalDistanceMilliMeter Calibration distance value used for the + * offset compensation. + * + * @return VL53L1_ERROR_NONE + * @return VL53L1_ERROR_OFFSET_CAL_NO_SAMPLE_FAIL the calibration failed by + * lack of valid measurements + * @return VL53L1_WARNING_OFFSET_CAL_SIGMA_TOO_HIGH means that the target + * distance combined to the number of loops performed in the calibration lead to + * an internal overflow. Try to reduce the distance of the target (140 mm) + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_PerformOffsetSimpleCalibration(VL53L1_DEV Dev, + int32_t CalDistanceMilliMeter); + +/** + * @brief Sets the Calibration Data. + * + * @par Function Description + * This function set all the Calibration Data issued from the functions + * @a VL53L1_PerformRefSpadManagement(), @a VL53L1_PerformXTalkCalibration, + * @a VL53L1_PerformOffsetCalibration() + * + * @note This function doesn't Accesses the device + * + * @param Dev Device Handle + * @param *pCalibrationData Pointer to Calibration data to be set. + * @return VL53L1_ERROR_NONE Success + * @return VL53L1_ERROR_INVALID_PARAMS pCalibrationData points to an older + * version of the inner structure. Need for support to convert its content. + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_SetCalibrationData(VL53L1_DEV Dev, + VL53L1_CalibrationData_t *pCalibrationData); + +/** + * @brief Gets the Calibration Data. + * + * @par Function Description + * This function get all the Calibration Data issued from the functions + * @a VL53L1_PerformRefSpadManagement(), @a VL53L1_PerformXTalkCalibration, + * @a VL53L1_PerformOffsetCalibration() + * + * @note This function doesn't Accesses the device + * + * @param Dev Device Handle + * @param *pCalibrationData pointer where to store Calibration + * data. + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetCalibrationData(VL53L1_DEV Dev, + VL53L1_CalibrationData_t *pCalibrationData); + +/** + * @brief Sets the Zone Calibration Data. + * + * @par Function Description + * This function set all the Zone nCalibration Data issued from the functions + * @a VL53L1_PerformOffsetCalibration() in multi zone + * + * @note This function doesn't Accesses the device + * + * @param Dev Device Handle + * @param *pZoneCalibrationData Pointer to Zone Calibration data to be + * set. + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_SetZoneCalibrationData(VL53L1_DEV Dev, + VL53L1_ZoneCalibrationData_t *pZoneCalibrationData); + +/** + * @brief Gets the Zone Calibration Data. + * + * @par Function Description + * This function get all the Zone Calibration Data issued from the functions + * @a VL53L1_PerformOffsetCalibration() + * + * @note This function doesn't Accesses the device + * + * @param Dev Device Handle + * @param *pZoneCalibrationData pointer where to store Zone Calibration + * data. + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetZoneCalibrationData(VL53L1_DEV Dev, + VL53L1_ZoneCalibrationData_t *pZoneCalibrationData); +/** + * @brief Gets the optical center. + * + * @par Function Description + * This function get the optical center issued from the nvm set at FTM stage + * expressed in the same coordinate system as the ROI are + * + * @note This function doesn't Accesses the device + * + * @param Dev Device Handle + * @param *pOpticalCentreX pointer to the X position of center + * in 16.16 fix point + * @param *pOpticalCentreY pointer to the Y position of center + * in 16.16 fix point + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetOpticalCenter(VL53L1_DEV Dev, + FixPoint1616_t *pOpticalCenterX, + FixPoint1616_t *pOpticalCenterY); + +/** @} VL53L1_Calibration_group */ + +/** @defgroup VL53L1_Thresholds_group VL53L1 IRQ Triggered events Functions + * @brief Functions used to configure interrupt to be triggered only when + * a measurement satisfies some thresholds parameters + * @{ + */ + +/** + * @brief Configure the interrupt config, from the given structure + * + * @param[in] Dev : Device Handle + * @param[in] pConfig : pointer to configuration structure + */ + +VL53L1_Error VL53L1_SetThresholdConfig(VL53L1_DEV Dev, + VL53L1_DetectionConfig_t *pConfig); + +/** + * @brief Retrieves the interrupt config structure currently programmed + * into the API + * + * @param[in] Dev : Device Handle + * @param[out] pConfig : pointer to configuration structure + */ + +VL53L1_Error VL53L1_GetThresholdConfig(VL53L1_DEV Dev, + VL53L1_DetectionConfig_t *pConfig); + + +/** @} VL53L1_Thresholds_group */ + + +/** @} VL53L1_cut11_group */ + +#ifdef __cplusplus +} +#endif + +#endif /* _VL53L1_API_H_ */ diff --git a/drivers/input/misc/vl53L1/lito/inc/vl53l1_api_calibration.h b/drivers/input/misc/vl53L1/lito/inc/vl53l1_api_calibration.h new file mode 100644 index 000000000000..01c9aeb2b8a2 --- /dev/null +++ b/drivers/input/misc/vl53L1/lito/inc/vl53l1_api_calibration.h @@ -0,0 +1,596 @@ + +/******************************************************************************* + * Copyright (c) 2017, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#ifndef _VL53L1_API_CALIBRATION_H_ +#define _VL53L1_API_CALIBRATION_H_ + +#include "vl53l1_platform.h" + +#ifdef __cplusplus +extern "C" { +#endif + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_run_ref_spad_char(VL53L1_DEV Dev, + VL53L1_Error * pcal_status); + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_run_device_test( + VL53L1_DEV Dev, + VL53L1_DeviceTestMode device_test_mode); + + + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_run_spad_rate_map( + VL53L1_DEV Dev, + VL53L1_DeviceTestMode device_test_mode, + VL53L1_DeviceSscArray array_select, + uint32_t ssc_config_timeout_us, + VL53L1_spad_rate_data_t *pspad_rate_data); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_run_xtalk_extraction( + VL53L1_DEV Dev, + VL53L1_Error *pcal_status); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_and_avg_xtalk_samples( + VL53L1_DEV Dev, + uint8_t num_of_samples, + uint8_t measurement_mode, + int16_t xtalk_filter_thresh_max_mm, + int16_t xtalk_filter_thresh_min_mm, + uint16_t xtalk_max_valid_rate_kcps, + uint8_t xtalk_result_id, + uint8_t xtalk_histo_id, + VL53L1_xtalk_range_results_t *pxtalk_results, + VL53L1_histogram_bin_data_t *psum_histo, + VL53L1_histogram_bin_data_t *pavg_histo); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_run_offset_calibration( + VL53L1_DEV Dev, + int16_t cal_distance_mm, + uint16_t cal_reflectance_pc, + VL53L1_Error *pcal_status); + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_run_phasecal_average( + VL53L1_DEV Dev, + uint8_t measurement_mode, + uint8_t phasecal_result__vcsel_start, + uint16_t phasecal_num_of_samples, + VL53L1_range_results_t *prange_results, + uint16_t *pphasecal_result__reference_phase, + uint16_t *pzero_distance_phase); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_run_zone_calibration( + VL53L1_DEV Dev, + VL53L1_DevicePresetModes device_preset_mode, + VL53L1_DeviceZonePreset zone_preset, + VL53L1_zone_config_t *pzone_cfg, + int16_t cal_distance_mm, + uint16_t cal_reflectance_pc, + VL53L1_Error *pcal_status); + + + + + + + + + + + + +void VL53L1_hist_xtalk_extract_data_init( + VL53L1_hist_xtalk_extract_data_t *pxtalk_data); + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_hist_xtalk_extract_update( + int16_t target_distance_mm, + uint16_t target_width_oversize, + VL53L1_histogram_bin_data_t *phist_bins, + VL53L1_hist_xtalk_extract_data_t *pxtalk_data); + + + + + + + + + + + + + + +VL53L1_Error VL53L1_hist_xtalk_extract_fini( + VL53L1_histogram_bin_data_t *phist_bins, + VL53L1_hist_xtalk_extract_data_t *pxtalk_data, + VL53L1_xtalk_calibration_results_t *pxtalk_cal, + VL53L1_xtalk_histogram_shape_t *pxtalk_shape); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_run_hist_xtalk_extraction( + VL53L1_DEV Dev, + int16_t cal_distance_mm, + VL53L1_Error *pcal_status); + + +#ifdef __cplusplus +} +#endif + +#endif + + diff --git a/drivers/input/misc/vl53L1/lito/inc/vl53l1_api_core.h b/drivers/input/misc/vl53L1/lito/inc/vl53l1_api_core.h new file mode 100644 index 000000000000..eb3122cb0516 --- /dev/null +++ b/drivers/input/misc/vl53L1/lito/inc/vl53l1_api_core.h @@ -0,0 +1,1941 @@ + +/******************************************************************************* + * Copyright (c) 2017, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#ifndef _VL53L1_API_CORE_H_ +#define _VL53L1_API_CORE_H_ + +#include "vl53l1_platform.h" + +#ifdef __cplusplus +extern "C" { +#endif + + + + + + + + + + + + +VL53L1_Error VL53L1_get_version( + VL53L1_DEV Dev, + VL53L1_ll_version_t *pversion); + + + + + + + + + + + + +VL53L1_Error VL53L1_get_device_firmware_version( + VL53L1_DEV Dev, + uint16_t *pfw_version); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_data_init( + VL53L1_DEV Dev, + uint8_t read_p2p_data); + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_read_p2p_data( + VL53L1_DEV Dev); + + + + + + + + + + + + + +VL53L1_Error VL53L1_software_reset( + VL53L1_DEV Dev); + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_part_to_part_data( + VL53L1_DEV Dev, + VL53L1_calibration_data_t *pcal_data); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_part_to_part_data( + VL53L1_DEV Dev, + VL53L1_calibration_data_t *pcal_data); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_tuning_debug_data( + VL53L1_DEV Dev, + VL53L1_tuning_parameters_t *ptun_data); + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_inter_measurement_period_ms( + VL53L1_DEV Dev, + uint32_t inter_measurement_period_ms); + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_inter_measurement_period_ms( + VL53L1_DEV Dev, + uint32_t *pinter_measurement_period_ms); + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_timeouts_us( + VL53L1_DEV Dev, + uint32_t phasecal_config_timeout_us, + uint32_t mm_config_timeout_us, + uint32_t range_config_timeout_us); + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_timeouts_us( + VL53L1_DEV Dev, + uint32_t *pphasecal_config_timeout_us, + uint32_t *pmm_config_timeout_us, + uint32_t *prange_config_timeout_us); + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_calibration_repeat_period( + VL53L1_DEV Dev, + uint16_t cal_config__repeat_period); + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_calibration_repeat_period( + VL53L1_DEV Dev, + uint16_t *pcal_config__repeat_period); + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_sequence_config_bit( + VL53L1_DEV Dev, + VL53L1_DeviceSequenceConfig bit_id, + uint8_t value); + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_sequence_config_bit( + VL53L1_DEV Dev, + VL53L1_DeviceSequenceConfig bit_id, + uint8_t *pvalue); + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_interrupt_polarity( + VL53L1_DEV Dev, + VL53L1_DeviceInterruptPolarity interrupt_polarity); + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_interrupt_polarity( + VL53L1_DEV Dev, + VL53L1_DeviceInterruptPolarity *pinterrupt_polarity); + + + + + + + + + + + + +VL53L1_Error VL53L1_get_refspadchar_config_struct( + VL53L1_DEV Dev, + VL53L1_refspadchar_config_t *pdata); + + + + + + + + + + + + +VL53L1_Error VL53L1_set_refspadchar_config_struct( + VL53L1_DEV Dev, + VL53L1_refspadchar_config_t *pdata); + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_range_ignore_threshold( + VL53L1_DEV Dev, + uint8_t range_ignore_thresh_mult, + uint16_t range_ignore_threshold_mcps); + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_range_ignore_threshold( + VL53L1_DEV Dev, + uint8_t *prange_ignore_thresh_mult, + uint16_t *prange_ignore_threshold_mcps_internal, + uint16_t *prange_ignore_threshold_mcps_current); + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_user_zone( + VL53L1_DEV Dev, + VL53L1_user_zone_t *puser_zone); + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_user_zone( + VL53L1_DEV Dev, + VL53L1_user_zone_t *puser_zone); + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_mode_mitigation_roi( + VL53L1_DEV Dev, + VL53L1_user_zone_t *pmm_roi); + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_zone_config( + VL53L1_DEV Dev, + VL53L1_zone_config_t *pzone_cfg); + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_zone_config( + VL53L1_DEV Dev, + VL53L1_zone_config_t *pzone_cfg); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_preset_mode( + VL53L1_DEV Dev, + VL53L1_DevicePresetModes device_preset_mode, + uint16_t dss_config__target_total_rate_mcps, + uint32_t phasecal_config_timeout_us, + uint32_t mm_config_timeout_us, + uint32_t range_config_timeout_us, + uint32_t inter_measurement_period_ms); + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_preset_mode_timing_cfg( + VL53L1_DEV Dev, + VL53L1_DevicePresetModes device_preset_mode, + uint16_t *pdss_config__target_total_rate_mcps, + uint32_t *pphasecal_config_timeout_us, + uint32_t *pmm_config_timeout_us, + uint32_t *prange_config_timeout_us); + + + + + + + + + + + + +VL53L1_Error VL53L1_set_zone_preset( + VL53L1_DEV Dev, + VL53L1_DeviceZonePreset zone_preset); + + + + + + + + + + + + + + +VL53L1_Error VL53L1_enable_xtalk_compensation( + VL53L1_DEV Dev); + + + + + + + + + + + + + + +VL53L1_Error VL53L1_disable_xtalk_compensation( + VL53L1_DEV Dev); + + + + + + + + + + + + + + +void VL53L1_get_xtalk_compensation_enable( + VL53L1_DEV Dev, + uint8_t *pcrosstalk_compensation_enable); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_init_and_start_range( + VL53L1_DEV Dev, + uint8_t measurement_mode, + VL53L1_DeviceConfigLevel device_config_level); + + + + + + + + + + + + + +VL53L1_Error VL53L1_stop_range( + VL53L1_DEV Dev); + + + + + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_measurement_results( + VL53L1_DEV Dev, + VL53L1_DeviceResultsLevel device_result_level); + + + + + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_device_results( + VL53L1_DEV Dev, + VL53L1_DeviceResultsLevel device_result_level, + VL53L1_range_results_t *prange_results); + + + + + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_clear_interrupt_and_enable_next_range( + VL53L1_DEV Dev, + uint8_t measurement_mode); + + + + + + + + + + +VL53L1_Error VL53L1_get_histogram_bin_data( + VL53L1_DEV Dev, + VL53L1_histogram_bin_data_t *phist_data); + + + + + + + + + + + + +void VL53L1_copy_sys_and_core_results_to_range_results( + int32_t gain_factor, + VL53L1_system_results_t *psys, + VL53L1_core_results_t *pcore, + VL53L1_range_results_t *presults); + + + + + + + + + + +VL53L1_Error VL53L1_set_zone_dss_config( + VL53L1_DEV Dev, + VL53L1_zone_private_dyn_cfg_t *pzone_dyn_cfg); + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_calc_ambient_dmax( + VL53L1_DEV Dev, + uint16_t target_reflectance, + int16_t *pambient_dmax_mm); + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_GPIO_interrupt_config( + VL53L1_DEV Dev, + VL53L1_GPIO_Interrupt_Mode intr_mode_distance, + VL53L1_GPIO_Interrupt_Mode intr_mode_rate, + uint8_t intr_new_measure_ready, + uint8_t intr_no_target, + uint8_t intr_combined_mode, + uint16_t thresh_distance_high, + uint16_t thresh_distance_low, + uint16_t thresh_rate_high, + uint16_t thresh_rate_low + ); + + + + + + + + + +VL53L1_Error VL53L1_set_GPIO_interrupt_config_struct( + VL53L1_DEV Dev, + VL53L1_GPIO_interrupt_config_t intconf); + + + + + + + + + + +VL53L1_Error VL53L1_get_GPIO_interrupt_config( + VL53L1_DEV Dev, + VL53L1_GPIO_interrupt_config_t *pintconf); + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_dmax_mode( + VL53L1_DEV Dev, + VL53L1_DeviceDmaxMode dmax_mode); + + + + + + + + + + + + +VL53L1_Error VL53L1_get_dmax_mode( + VL53L1_DEV Dev, + VL53L1_DeviceDmaxMode *pdmax_mode); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_dmax_calibration_data( + VL53L1_DEV Dev, + VL53L1_DeviceDmaxMode dmax_mode, + uint8_t zone_id, + VL53L1_dmax_calibration_data_t *pdmax_cal); + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_hist_dmax_config( + VL53L1_DEV Dev, + VL53L1_hist_gen3_dmax_config_t *pdmax_cfg); + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_hist_dmax_config( + VL53L1_DEV Dev, + VL53L1_hist_gen3_dmax_config_t *pdmax_cfg); + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_offset_calibration_mode( + VL53L1_DEV Dev, + VL53L1_OffsetCalibrationMode offset_cal_mode); + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_offset_calibration_mode( + VL53L1_DEV Dev, + VL53L1_OffsetCalibrationMode *poffset_cal_mode); + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_offset_correction_mode( + VL53L1_DEV Dev, + VL53L1_OffsetCalibrationMode offset_cor_mode); + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_offset_correction_mode( + VL53L1_DEV Dev, + VL53L1_OffsetCorrectionMode *poffset_cor_mode); + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_zone_calibration_data( + VL53L1_DEV Dev, + VL53L1_zone_calibration_results_t *pzone_cal); + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_zone_calibration_data( + VL53L1_DEV Dev, + VL53L1_zone_calibration_results_t *pzone_cal); + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_lite_xtalk_margin_kcps( + VL53L1_DEV Dev, + int16_t *pxtalk_margin); + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_lite_xtalk_margin_kcps( + VL53L1_DEV Dev, + int16_t xtalk_margin); + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_histogram_xtalk_margin_kcps( + VL53L1_DEV Dev, + int16_t *pxtalk_margin); + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_histogram_xtalk_margin_kcps( + VL53L1_DEV Dev, + int16_t xtalk_margin); + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_histogram_phase_consistency( + VL53L1_DEV Dev, + uint8_t *pphase_consistency); + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_histogram_phase_consistency( + VL53L1_DEV Dev, + uint8_t phase_consistency); + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_histogram_event_consistency( + VL53L1_DEV Dev, + uint8_t *pevent_consistency); + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_histogram_event_consistency( + VL53L1_DEV Dev, + uint8_t event_consistency); + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_histogram_ambient_threshold_sigma( + VL53L1_DEV Dev, + uint8_t *pamb_thresh_sigma); + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_histogram_ambient_threshold_sigma( + VL53L1_DEV Dev, + uint8_t amb_thresh_sigma); + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_lite_min_count_rate( + VL53L1_DEV Dev, + uint16_t *plite_mincountrate); + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_lite_min_count_rate( + VL53L1_DEV Dev, + uint16_t lite_mincountrate); + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_lite_sigma_threshold( + VL53L1_DEV Dev, + uint16_t *plite_sigma); + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_lite_sigma_threshold( + VL53L1_DEV Dev, + uint16_t lite_sigma); + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_restore_xtalk_nvm_default( + VL53L1_DEV Dev); + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_xtalk_detect_config( + VL53L1_DEV Dev, + int16_t *pmax_valid_range_mm, + int16_t *pmin_valid_range_mm, + uint16_t *pmax_valid_rate_kcps, + uint16_t *pmax_sigma_mm); + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_xtalk_detect_config( + VL53L1_DEV Dev, + int16_t max_valid_range_mm, + int16_t min_valid_range_mm, + uint16_t max_valid_rate_kcps, + uint16_t max_sigma_mm); + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_target_order_mode( + VL53L1_DEV Dev, + VL53L1_HistTargetOrder *phist_target_order); + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_target_order_mode( + VL53L1_DEV Dev, + VL53L1_HistTargetOrder hist_target_order); + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_dmax_reflectance_values( + VL53L1_DEV Dev, + VL53L1_dmax_reflectance_array_t *pdmax_reflectances); + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_dmax_reflectance_values( + VL53L1_DEV Dev, + VL53L1_dmax_reflectance_array_t *pdmax_reflectances); + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_vhv_config( + VL53L1_DEV Dev, + uint8_t vhv_init_en, + uint8_t vhv_init_value); + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_vhv_config( + VL53L1_DEV Dev, + uint8_t *pvhv_init_en, + uint8_t *pvhv_init_value); + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_vhv_loopbound( + VL53L1_DEV Dev, + uint8_t vhv_loopbound); + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_vhv_loopbound( + VL53L1_DEV Dev, + uint8_t *pvhv_loopbound); + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_tuning_parm( + VL53L1_DEV Dev, + VL53L1_TuningParms tuning_parm_key, + int32_t *ptuning_parm_value); + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_tuning_parm( + VL53L1_DEV Dev, + VL53L1_TuningParms tuning_parm_key, + int32_t tuning_parm_value); + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_dynamic_xtalk_correction_enable( + VL53L1_DEV Dev + ); + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_dynamic_xtalk_correction_disable( + VL53L1_DEV Dev + ); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_dynamic_xtalk_correction_apply_enable( + VL53L1_DEV Dev + ); + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_dynamic_xtalk_correction_apply_disable( + VL53L1_DEV Dev + ); + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_dynamic_xtalk_correction_single_apply_enable( + VL53L1_DEV Dev + ); + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_dynamic_xtalk_correction_single_apply_disable( + VL53L1_DEV Dev + ); + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_dynamic_xtalk_correction_set_scalers( + VL53L1_DEV Dev, + int16_t x_scaler_in, + int16_t y_scaler_in, + uint8_t user_scaler_set_in + ); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_current_xtalk_settings( + VL53L1_DEV Dev, + VL53L1_xtalk_calibration_results_t *pxtalk + ); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_current_xtalk_settings( + VL53L1_DEV Dev, + VL53L1_xtalk_calibration_results_t *pxtalk + ); + + +#ifdef __cplusplus +} +#endif + +#endif + + diff --git a/drivers/input/misc/vl53L1/lito/inc/vl53l1_api_debug.h b/drivers/input/misc/vl53L1/lito/inc/vl53l1_api_debug.h new file mode 100644 index 000000000000..46239a784864 --- /dev/null +++ b/drivers/input/misc/vl53L1/lito/inc/vl53l1_api_debug.h @@ -0,0 +1,756 @@ + +/******************************************************************************* + * Copyright (c) 2017, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#ifndef _VL53L1_API_DEBUG_H_ +#define _VL53L1_API_DEBUG_H_ + +#include "vl53l1_platform.h" +#include "vl53l1_nvm_structs.h" + +#ifdef __cplusplus +extern "C" { +#endif + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_decode_calibration_data_buffer( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_calibration_data_t *pdata); + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_nvm_debug_data( + VL53L1_DEV Dev, + VL53L1_decoded_nvm_data_t *pdata); + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_histogram_debug_data( + VL53L1_DEV Dev, + VL53L1_histogram_bin_data_t *pdata); + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_additional_data( + VL53L1_DEV Dev, + VL53L1_additional_data_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_xtalk_debug_data( + VL53L1_DEV Dev, + VL53L1_xtalk_debug_data_t *pdata); + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_offset_debug_data( + VL53L1_DEV Dev, + VL53L1_offset_debug_data_t *pdata); + +#ifdef VL53L1_LOG_ENABLE + + + + + + + + + + + + +void VL53L1_signed_fixed_point_sprintf( + int32_t fp_value, + uint8_t frac_bits, + uint16_t buf_size, + char *pbuffer); + + + + + + + + + + + + +void VL53L1_print_static_nvm_managed( + VL53L1_static_nvm_managed_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + + + + + + + + + +void VL53L1_print_customer_nvm_managed( + VL53L1_customer_nvm_managed_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + + + + + + + + +void VL53L1_print_nvm_copy_data( + VL53L1_nvm_copy_data_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + + + + + + + + + +void VL53L1_print_histogram_bin_data( + VL53L1_histogram_bin_data_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + + + + + + + + + +void VL53L1_print_xtalk_histogram_data( + VL53L1_xtalk_histogram_data_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + + + + + + + + + +void VL53L1_print_xtalk_histogram_shape_data( + VL53L1_xtalk_histogram_shape_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + + + + + + + + + +void VL53L1_print_range_results( + VL53L1_range_results_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + + + + + + + + +void VL53L1_print_range_data( + VL53L1_range_data_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + + + + + + + + + + +void VL53L1_print_offset_range_results( + VL53L1_offset_range_results_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + + + + + + + + + +void VL53L1_print_offset_range_data( + VL53L1_offset_range_data_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + + + + + + + + + +void VL53L1_print_cal_peak_rate_map( + VL53L1_cal_peak_rate_map_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + + + + + + + + + + +void VL53L1_print_additional_offset_cal_data( + VL53L1_additional_offset_cal_data_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + + + + + + + + +void VL53L1_print_additional_data( + VL53L1_additional_data_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + + + + + + + + + + +void VL53L1_print_gain_calibration_data( + VL53L1_gain_calibration_data_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + + + + + + + + + + +void VL53L1_print_zone_calibration_data( + VL53L1_zone_calibration_data_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + + + + + + + + + + +void VL53L1_print_zone_calibration_results( + VL53L1_zone_calibration_results_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + + + + + + + + + +void VL53L1_print_xtalk_range_results( + VL53L1_xtalk_range_results_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + + + + + + + + + +void VL53L1_print_xtalk_range_data( + VL53L1_xtalk_range_data_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + + + + + + + + + + +void VL53L1_print_xtalk_calibration_results( + VL53L1_xtalk_calibration_results_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + + + + + + + + + +void VL53L1_print_xtalk_config( + VL53L1_xtalk_config_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + + + + + + + + +void VL53L1_print_xtalk_extract_config( + VL53L1_xtalkextract_config_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + + + + + + + + +void VL53L1_print_zone_cal_config( + VL53L1_zonecal_config_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + + + + + + + + +void VL53L1_print_offset_cal_config( + VL53L1_offsetcal_config_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + + + + + + + + + +void VL53L1_print_dmax_calibration_data( + VL53L1_dmax_calibration_data_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + + + + + + + + + +void VL53L1_print_calibration_data( + VL53L1_calibration_data_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + + + + + + + + + +void VL53L1_print_xtalk_debug_data( + VL53L1_xtalk_debug_data_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + + + + + + + + +void VL53L1_print_offset_debug_data( + VL53L1_offset_debug_data_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + + + + + + + + + +void VL53L1_print_optical_centre( + VL53L1_optical_centre_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + + + + + + + + + +void VL53L1_print_user_zone( + VL53L1_user_zone_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + + + + + + + + +void VL53L1_print_zone_config( + VL53L1_zone_config_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + + + + + + + + +void VL53L1_print_spad_rate_data( + VL53L1_spad_rate_data_t *pspad_rates, + char *pprefix, + uint32_t trace_flags); + + + + + + + + + + + +void VL53L1_print_spad_rate_map( + VL53L1_spad_rate_data_t *pspad_rates, + char *pprefix, + uint32_t trace_flags); + + +#endif + + +#ifdef __cplusplus +} +#endif + +#endif + + diff --git a/drivers/input/misc/vl53L1/lito/inc/vl53l1_api_preset_modes.h b/drivers/input/misc/vl53L1/lito/inc/vl53l1_api_preset_modes.h new file mode 100644 index 000000000000..e5e166aa2214 --- /dev/null +++ b/drivers/input/misc/vl53L1/lito/inc/vl53l1_api_preset_modes.h @@ -0,0 +1,1637 @@ + +/******************************************************************************* + * Copyright (c) 2017, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#ifndef _VL53L1_API_PRESET_MODES_H_ +#define _VL53L1_API_PRESET_MODES_H_ + +#include "vl53l1_ll_def.h" +#include "vl53l1_dmax_structs.h" + +#ifdef __cplusplus +extern "C" { +#endif + + + + + + + + + + + + + +VL53L1_Error VL53L1_init_refspadchar_config_struct( + VL53L1_refspadchar_config_t *pdata); + + + + + + + + + + + + +VL53L1_Error VL53L1_init_ssc_config_struct( + VL53L1_ssc_config_t *pdata); + + + + + + + + + + + + + + +VL53L1_Error VL53L1_init_xtalk_config_struct( + VL53L1_customer_nvm_managed_t *pnvm, + VL53L1_xtalk_config_t *pdata); + + + + + + + + + + + + +VL53L1_Error VL53L1_init_xtalk_extract_config_struct( + VL53L1_xtalkextract_config_t *pdata); + + + + + + + + + + + +VL53L1_Error VL53L1_init_offset_cal_config_struct( + VL53L1_offsetcal_config_t *pdata); + + + + + + + + + + + +VL53L1_Error VL53L1_init_zone_cal_config_struct( + VL53L1_zonecal_config_t *pdata); + + + + + + + + + + + + + + +VL53L1_Error VL53L1_init_hist_post_process_config_struct( + uint8_t xtalk_compensation_enable, + VL53L1_hist_post_process_config_t *pdata); + + + + + + + + + + + + + +VL53L1_Error VL53L1_init_dmax_calibration_data_struct( + VL53L1_dmax_calibration_data_t *pdata); + + + + + + + + + + + + + +VL53L1_Error VL53L1_init_tuning_parm_storage_struct( + VL53L1_tuning_parm_storage_t *pdata); + + + + + + + + + + + + +VL53L1_Error VL53L1_init_hist_gen3_dmax_config_struct( + VL53L1_hist_gen3_dmax_config_t *pdata); + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_preset_mode_standard_ranging( + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_preset_mode_standard_ranging_short_range( + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_preset_mode_standard_ranging_long_range( + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_preset_mode_standard_ranging_mm1_cal( + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_preset_mode_standard_ranging_mm2_cal( + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_preset_mode_timed_ranging( + + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_preset_mode_timed_ranging_short_range( + + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_preset_mode_timed_ranging_long_range( + + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_preset_mode_low_power_auto_ranging( + + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg, + VL53L1_low_power_auto_data_t *plpadata); + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_preset_mode_low_power_auto_short_ranging( + + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg, + VL53L1_low_power_auto_data_t *plpadata); + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_preset_mode_low_power_auto_long_ranging( + + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg, + VL53L1_low_power_auto_data_t *plpadata); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_preset_mode_histogram_ranging( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_preset_mode_histogram_ranging_with_mm1( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_preset_mode_histogram_ranging_with_mm2( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_preset_mode_histogram_ranging_mm1_cal( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_preset_mode_histogram_ranging_mm2_cal( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_preset_mode_histogram_ranging_ref( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_preset_mode_histogram_characterisation( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_preset_mode_histogram_xtalk_planar( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_preset_mode_histogram_xtalk_mm1( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_preset_mode_histogram_xtalk_mm2( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_preset_mode_histogram_multizone( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_preset_mode_histogram_multizone_short_range( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_preset_mode_histogram_multizone_long_range( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_preset_mode_histogram_ranging_short_timing( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_preset_mode_histogram_long_range( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_preset_mode_histogram_medium_range( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_preset_mode_histogram_short_range( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_preset_mode_special_histogram_short_range( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_preset_mode_histogram_long_range_mm1( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_preset_mode_histogram_long_range_mm2( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_preset_mode_histogram_medium_range_mm1( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_preset_mode_histogram_medium_range_mm2( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_preset_mode_histogram_short_range_mm1( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_preset_mode_histogram_short_range_mm2( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_preset_mode_olt( + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_preset_mode_singleshot_ranging( + + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + + + + + + + + + + + + + + + +void VL53L1_copy_hist_cfg_to_static_cfg( + VL53L1_histogram_config_t *phistogram, + VL53L1_static_config_t *pstatic, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic); + + + + + + + + + + + + + + +void VL53L1_copy_hist_bins_to_static_cfg( + VL53L1_histogram_config_t *phistogram, + VL53L1_static_config_t *pstatic, + VL53L1_timing_config_t *ptiming); + +#ifdef __cplusplus +} +#endif + +#endif + + diff --git a/drivers/input/misc/vl53L1/lito/inc/vl53l1_api_strings.h b/drivers/input/misc/vl53L1/lito/inc/vl53l1_api_strings.h new file mode 100644 index 000000000000..051fcb2b000c --- /dev/null +++ b/drivers/input/misc/vl53L1/lito/inc/vl53l1_api_strings.h @@ -0,0 +1,210 @@ + +/****************************************************************************** + * Copyright (c) 2017, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + + ****************************************************************************** + + 'STMicroelectronics Proprietary license' + + ******************************************************************************* + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + + ******************************************************************************* + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones mentioned above : + + ******************************************************************************* + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + ******************************************************************************* + */ + +/** + * @file vl53l1_api_strings.h + * @brief VL53L1 API function declarations for decoding error codes to a + * text strings + */ + + +#ifndef VL53L1_API_STRINGS_H_ +#define VL53L1_API_STRINGS_H_ + +#include "vl53l1_def.h" + +#ifdef __cplusplus +extern "C" { +#endif + + + +/** + * @brief Generates a string for the input device range status code + * + * @param[in] RangeStatus : Device Range AStatus Code + * @param[out] pRangeStatusString : pointer to character buffer + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_get_range_status_string( + uint8_t RangeStatus, + char *pRangeStatusString); + +/** + * @brief Generates an error string for the input PAL error code + * + * @param[in] PalErrorCode : PAL Error Code + * @param[out] pPalErrorString : pointer to character buffer + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_get_pal_error_string( + VL53L1_Error PalErrorCode, + char *pPalErrorString); + +/** + * @brief Generates a string for the input PAL State code + * + * @param[in] PalStateCode : PAL State Code + * @param[out] pPalStateString : pointer to character buffer + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_get_pal_state_string( + VL53L1_State PalStateCode, + char *pPalStateString); + + +/** + * @brief Generates a string for the sequence step Id + * + * @param[in] SequenceStepId : Sequence Step Id + * @param[out] pSequenceStepsString : pointer to character buffer + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_get_sequence_steps_info( + VL53L1_SequenceStepId SequenceStepId, + char *pSequenceStepsString); + +/** + * @brief Generates a string for the limit check Id + * + * @param[in] LimitCheckId : Limit check Id + * @param[out] pLimitCheckString : pointer to character buffer + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_get_limit_check_info(uint16_t LimitCheckId, + char *pLimitCheckString); + +#ifndef VL53L1_USE_EMPTY_STRING + #define VL53L1_STRING_DEVICE_INFO_NAME0 "VL53L1 cut1.0" + #define VL53L1_STRING_DEVICE_INFO_NAME1 "VL53L1 cut1.1" + #define VL53L1_STRING_DEVICE_INFO_TYPE "VL53L1" + + /* Range Status */ + #define VL53L1_STRING_RANGESTATUS_NONE "No Update" + #define VL53L1_STRING_RANGESTATUS_RANGEVALID "Range Valid" + #define VL53L1_STRING_RANGESTATUS_SIGMA "Sigma Fail" + #define VL53L1_STRING_RANGESTATUS_SIGNAL "Signal Fail" + #define VL53L1_STRING_RANGESTATUS_MINRANGE "Min Range Fail" + #define VL53L1_STRING_RANGESTATUS_PHASE "Phase Fail" + #define VL53L1_STRING_RANGESTATUS_HW "Hardware Fail" + + + /* Range Status */ + #define VL53L1_STRING_STATE_POWERDOWN "POWERDOWN State" + #define VL53L1_STRING_STATE_WAIT_STATICINIT \ + "Wait for staticinit State" + #define VL53L1_STRING_STATE_STANDBY "STANDBY State" + #define VL53L1_STRING_STATE_IDLE "IDLE State" + #define VL53L1_STRING_STATE_RUNNING "RUNNING State" + #define VL53L1_STRING_STATE_RESET "RESET State" + #define VL53L1_STRING_STATE_UNKNOWN "UNKNOWN State" + #define VL53L1_STRING_STATE_ERROR "ERROR State" + + + + /* Check Enable */ + #define VL53L1_STRING_CHECKENABLE_SIGMA_FINAL_RANGE \ + "SIGMA FINAL RANGE" + #define VL53L1_STRING_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE \ + "SIGNAL RATE FINAL RANGE" + #define VL53L1_STRING_CHECKENABLE_SIGNAL_MIN_CLIP \ + "SIGNAL MIN CLIP" + #define VL53L1_STRING_CHECKENABLE_RANGE_IGNORE_THRESHOLD \ + "RANGE IGNORE THRESHOLD" + #define VL53L1_STRING_CHECKENABLE_RANGE_PHASE_HIGH \ + "RANGE PHASE HIGH" + #define VL53L1_STRING_CHECKENABLE_RANGE_PHASE_LOW \ + "RANGE PHASE LOW" + #define VL53L1_STRING_CHECKENABLE_RANGE_PHASE_CONSISTENCY \ + "RANGE PHASE CONSISTENCY" + + /* Sequence Step */ + #define VL53L1_STRING_SEQUENCESTEP_VHV "VHV" + #define VL53L1_STRING_SEQUENCESTEP_PHASECAL "PHASE CAL" + #define VL53L1_STRING_SEQUENCESTEP_REFPHASE "REF PHASE" + #define VL53L1_STRING_SEQUENCESTEP_DSS1 "DSS1" + #define VL53L1_STRING_SEQUENCESTEP_DSS2 "DSS2" + #define VL53L1_STRING_SEQUENCESTEP_MM1 "MM1" + #define VL53L1_STRING_SEQUENCESTEP_MM2 "MM2" + #define VL53L1_STRING_SEQUENCESTEP_RANGE "RANGE" +#endif /* VL53L1_USE_EMPTY_STRING */ + + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/drivers/input/misc/vl53L1/lito/inc/vl53l1_core.h b/drivers/input/misc/vl53L1/lito/inc/vl53l1_core.h new file mode 100644 index 000000000000..fa6dc8925a55 --- /dev/null +++ b/drivers/input/misc/vl53L1/lito/inc/vl53l1_core.h @@ -0,0 +1,1919 @@ + +/******************************************************************************* + * Copyright (c) 2017, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#ifndef _VL53L1_CORE_H_ +#define _VL53L1_CORE_H_ + +#include "vl53l1_platform.h" +#include "vl53l1_core_support.h" + +#ifdef __cplusplus +extern "C" { +#endif + + + + + + + + + +void VL53L1_init_version( + VL53L1_DEV Dev); + + + + + + + + + + +void VL53L1_init_ll_driver_state( + VL53L1_DEV Dev, + VL53L1_DeviceState ll_state); + + + + + + + + + + + + +VL53L1_Error VL53L1_update_ll_driver_rd_state( + VL53L1_DEV Dev); + + + + + + + + + + + + + +VL53L1_Error VL53L1_check_ll_driver_rd_state( + VL53L1_DEV Dev); + + + + + + + + + + + + +VL53L1_Error VL53L1_update_ll_driver_cfg_state( + VL53L1_DEV Dev); + + + + + + + + + + +void VL53L1_copy_rtn_good_spads_to_buffer( + VL53L1_nvm_copy_data_t *pdata, + uint8_t *pbuffer); + + + + + + + + + + + + +void VL53L1_init_system_results( + VL53L1_system_results_t *pdata); + + + + + + + + + + +void V53L1_init_zone_results_structure( + uint8_t active_zones, + VL53L1_zone_results_t *pdata); + + + + + + + + + +void V53L1_init_zone_dss_configs( + VL53L1_DEV Dev); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +void VL53L1_init_histogram_config_structure( + uint8_t even_bin0, + uint8_t even_bin1, + uint8_t even_bin2, + uint8_t even_bin3, + uint8_t even_bin4, + uint8_t even_bin5, + uint8_t odd_bin0, + uint8_t odd_bin1, + uint8_t odd_bin2, + uint8_t odd_bin3, + uint8_t odd_bin4, + uint8_t odd_bin5, + VL53L1_histogram_config_t *pdata); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +void VL53L1_init_histogram_multizone_config_structure( + uint8_t even_bin0, + uint8_t even_bin1, + uint8_t even_bin2, + uint8_t even_bin3, + uint8_t even_bin4, + uint8_t even_bin5, + uint8_t odd_bin0, + uint8_t odd_bin1, + uint8_t odd_bin2, + uint8_t odd_bin3, + uint8_t odd_bin4, + uint8_t odd_bin5, + VL53L1_histogram_config_t *pdata); + + + + + + + + + + + +void VL53L1_init_xtalk_bin_data_struct( + uint32_t bin_value, + uint16_t VL53L1_p_024, + VL53L1_xtalk_histogram_shape_t *pdata); + + + + + + + + + + + + + +void VL53L1_i2c_encode_uint16_t( + uint16_t ip_value, + uint16_t count, + uint8_t *pbuffer); + + + + + + + + + + + + + + +uint16_t VL53L1_i2c_decode_uint16_t( + uint16_t count, + uint8_t *pbuffer); + + + + + + + + + + + + + +void VL53L1_i2c_encode_int16_t( + int16_t ip_value, + uint16_t count, + uint8_t *pbuffer); + + + + + + + + + + + + + + +int16_t VL53L1_i2c_decode_int16_t( + uint16_t count, + uint8_t *pbuffer); + + + + + + + + + + + + + +void VL53L1_i2c_encode_uint32_t( + uint32_t ip_value, + uint16_t count, + uint8_t *pbuffer); + + + + + + + + + + + + + + +uint32_t VL53L1_i2c_decode_uint32_t( + uint16_t count, + uint8_t *pbuffer); + + + + + + + + + + + + + + + + + +uint32_t VL53L1_i2c_decode_with_mask( + uint16_t count, + uint8_t *pbuffer, + uint32_t bit_mask, + uint32_t down_shift, + uint32_t offset); + + + + + + + + + + + + + +void VL53L1_i2c_encode_int32_t( + int32_t ip_value, + uint16_t count, + uint8_t *pbuffer); + + + + + + + + + + + + + + +int32_t VL53L1_i2c_decode_int32_t( + uint16_t count, + uint8_t *pbuffer); + + + + + + + + + + + + + +VL53L1_Error VL53L1_start_test( + VL53L1_DEV Dev, + uint8_t test_mode__ctrl); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_firmware_enable_register( + VL53L1_DEV Dev, + uint8_t value); + + + + + + + + + + + + +VL53L1_Error VL53L1_enable_firmware( + VL53L1_DEV Dev); + + + + + + + + + + + + + + +VL53L1_Error VL53L1_disable_firmware( + VL53L1_DEV Dev); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_powerforce_register( + VL53L1_DEV Dev, + uint8_t value); + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_enable_powerforce( + VL53L1_DEV Dev); + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_disable_powerforce( + VL53L1_DEV Dev); + + + + + + + + + + + + + +VL53L1_Error VL53L1_clear_interrupt( + VL53L1_DEV Dev); + + + + + + + + + + + + + +VL53L1_Error VL53L1_force_shadow_stream_count_to_zero( + VL53L1_DEV Dev); + + + + + + + + + + + + + + + + + + + +uint32_t VL53L1_calc_macro_period_us( + uint16_t fast_osc_frequency, + uint8_t VL53L1_p_009); + + + + + + + + + + + + + + + + + + +uint16_t VL53L1_calc_range_ignore_threshold( + uint32_t central_rate, + int16_t x_gradient, + int16_t y_gradient, + uint8_t rate_mult); + + + + + + + + + + + + + +uint32_t VL53L1_calc_timeout_mclks( + uint32_t timeout_us, + uint32_t macro_period_us); + + + + + + + + + + + + +uint16_t VL53L1_calc_encoded_timeout( + uint32_t timeout_us, + uint32_t macro_period_us); + + + + + + + + + + + + + +uint32_t VL53L1_calc_timeout_us( + uint32_t timeout_mclks, + uint32_t macro_period_us); + + + + + + + + + + + + +uint32_t VL53L1_calc_decoded_timeout_us( + uint16_t timeout_encoded, + uint32_t macro_period_us); + + + + + + + + + + + +uint16_t VL53L1_encode_timeout( + uint32_t timeout_mclks); + + + + + + + + + + + + +uint32_t VL53L1_decode_timeout( + uint16_t encoded_timeout); + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_calc_timeout_register_values( + uint32_t phasecal_config_timeout_us, + uint32_t mm_config_timeout_us, + uint32_t range_config_timeout_us, + uint16_t fast_osc_frequency, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming); + + + + + + + + + + + + +uint8_t VL53L1_encode_vcsel_period( + uint8_t VL53L1_p_031); + + + + + + + + + + + + + + + +uint32_t VL53L1_decode_unsigned_integer( + uint8_t *pbuffer, + uint8_t no_of_bytes); + + + + + + + + + + + + +void VL53L1_encode_unsigned_integer( + uint32_t ip_value, + uint8_t no_of_bytes, + uint8_t *pbuffer); + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_hist_copy_and_scale_ambient_info( + VL53L1_zone_hist_info_t *pidata, + VL53L1_histogram_bin_data_t *podata); + + + + + + + + + + + + +void VL53L1_hist_get_bin_sequence_config( + VL53L1_DEV Dev, + VL53L1_histogram_bin_data_t *pdata); + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_hist_phase_consistency_check( + VL53L1_DEV Dev, + VL53L1_zone_hist_info_t *phist_prev, + VL53L1_zone_objects_t *prange_prev, + VL53L1_range_results_t *prange_curr); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_hist_events_consistency_check( + uint8_t event_sigma, + uint16_t min_effective_spad_count, + VL53L1_zone_hist_info_t *phist_prev, + VL53L1_object_data_t *prange_prev, + VL53L1_range_data_t *prange_curr, + int32_t *pevents_tolerance, + int32_t *pevents_delta, + VL53L1_DeviceError *prange_status); + + + + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_hist_merged_pulse_check( + int16_t min_max_tolerance_mm, + VL53L1_range_data_t *pdata, + VL53L1_DeviceError *prange_status); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_hist_xmonitor_consistency_check( + VL53L1_DEV Dev, + VL53L1_zone_hist_info_t *phist_prev, + VL53L1_zone_objects_t *prange_prev, + VL53L1_range_data_t *prange_curr); + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_hist_wrap_dmax( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_histogram_bin_data_t *pcurrent, + int16_t *pwrap_dmax_mm); + + + + + + + + + + + + + + + + + + + + + +void VL53L1_hist_combine_mm1_mm2_offsets( + int16_t mm1_offset_mm, + int16_t mm2_offset_mm, + uint8_t encoded_mm_roi_centre, + uint8_t encoded_mm_roi_size, + uint8_t encoded_zone_centre, + uint8_t encoded_zone_size, + VL53L1_additional_offset_cal_data_t *pcal_data, + uint8_t *pgood_spads, + uint16_t aperture_attenuation, + int16_t *prange_offset_mm); + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_hist_xtalk_extract_calc_window( + int16_t target_distance_mm, + uint16_t target_width_oversize, + VL53L1_histogram_bin_data_t *phist_bins, + VL53L1_hist_xtalk_extract_data_t *pxtalk_data); + + + + + + + + + + + + + + +VL53L1_Error VL53L1_hist_xtalk_extract_calc_event_sums( + VL53L1_histogram_bin_data_t *phist_bins, + VL53L1_hist_xtalk_extract_data_t *pxtalk_data); + + + + + + + + + + + + +VL53L1_Error VL53L1_hist_xtalk_extract_calc_rate_per_spad( + VL53L1_hist_xtalk_extract_data_t *pxtalk_data); + + + + + + + + + + + + + +VL53L1_Error VL53L1_hist_xtalk_extract_calc_shape( + VL53L1_hist_xtalk_extract_data_t *pxtalk_data, + VL53L1_xtalk_histogram_shape_t *pxtalk_shape); + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_hist_xtalk_shape_model( + uint16_t events_per_bin, + uint16_t pulse_centre, + uint16_t pulse_width, + VL53L1_xtalk_histogram_shape_t *pxtalk_shape); + + + + + + + + + + + + + + +uint16_t VL53L1_hist_xtalk_shape_model_interp( + uint16_t events_per_bin, + uint32_t phase_delta); + + + + + + + + + + + + + + + + + + +void VL53L1_spad_number_to_byte_bit_index( + uint8_t spad_number, + uint8_t *pbyte_index, + uint8_t *pbit_index, + uint8_t *pbit_mask); + + + + + + + + + + + + + +void VL53L1_encode_row_col( + uint8_t row, + uint8_t col, + uint8_t *pspad_number); + + + + + + + + + + + + +void VL53L1_decode_zone_size( + uint8_t encoded_xy_size, + uint8_t *pwidth, + uint8_t *pheight); + + + + + + + + + + + + +void VL53L1_encode_zone_size( + uint8_t width, + uint8_t height, + uint8_t *pencoded_xy_size); + + + + + + + + + + + + + + + + + +void VL53L1_decode_zone_limits( + uint8_t encoded_xy_centre, + uint8_t encoded_xy_size, + int16_t *px_ll, + int16_t *py_ll, + int16_t *px_ur, + int16_t *py_ur); + + + + + + + + + + + + +uint8_t VL53L1_is_aperture_location( + uint8_t row, + uint8_t col); + + + + + + + + + + + + + + + +void VL53L1_calc_max_effective_spads( + uint8_t encoded_zone_centre, + uint8_t encoded_zone_size, + uint8_t *pgood_spads, + uint16_t aperture_attenuation, + uint16_t *pmax_effective_spads); + + + + + + + + + + + + + + + + + + + +void VL53L1_calc_mm_effective_spads( + uint8_t encoded_mm_roi_centre, + uint8_t encoded_mm_roi_size, + uint8_t encoded_zone_centre, + uint8_t encoded_zone_size, + uint8_t *pgood_spads, + uint16_t aperture_attenuation, + uint16_t *pmm_inner_effective_spads, + uint16_t *pmm_outer_effective_spads); + + + + + + + + + + + + + + +void VL53L1_hist_copy_results_to_sys_and_core( + VL53L1_histogram_bin_data_t *pbins, + VL53L1_range_results_t *phist, + VL53L1_system_results_t *psys, + VL53L1_core_results_t *pcore); + + + + + + + + + + + + + + +VL53L1_Error VL53L1_sum_histogram_data( + VL53L1_histogram_bin_data_t *phist_input, + VL53L1_histogram_bin_data_t *phist_output); + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_avg_histogram_data( + uint8_t no_of_samples, + VL53L1_histogram_bin_data_t *phist_sum, + VL53L1_histogram_bin_data_t *phist_avg); + + + + + + + + + + + + + +VL53L1_Error VL53L1_save_cfg_data( + VL53L1_DEV Dev); + + + + + + + + + + + + + + +VL53L1_Error VL53L1_dynamic_zone_update( + VL53L1_DEV Dev, + VL53L1_range_results_t *presults); + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_update_internal_stream_counters( + VL53L1_DEV Dev, + uint8_t external_stream_count, + uint8_t *pinternal_stream_count, + uint8_t *pinternal_stream_count_val + ); + + + + + + + + + + + + +VL53L1_Error VL53L1_multizone_hist_bins_update( + VL53L1_DEV Dev); + + + + + + + +VL53L1_Error VL53L1_set_histogram_multizone_initial_bin_config( + VL53L1_zone_config_t *pzone_cfg, + VL53L1_histogram_config_t *phist_cfg, + VL53L1_histogram_config_t *pmulti_hist + ); + + + + + + + + + +uint8_t VL53L1_encode_GPIO_interrupt_config( + VL53L1_GPIO_interrupt_config_t *pintconf); + + + + + + + + + +VL53L1_GPIO_interrupt_config_t VL53L1_decode_GPIO_interrupt_config( + uint8_t system__interrupt_config); + + + + + + + + + + +VL53L1_Error VL53L1_set_GPIO_distance_threshold( + VL53L1_DEV Dev, + uint16_t threshold_high, + uint16_t threshold_low); + + + + + + + + + + +VL53L1_Error VL53L1_set_GPIO_rate_threshold( + VL53L1_DEV Dev, + uint16_t threshold_high, + uint16_t threshold_low); + + + + + + + + + + +VL53L1_Error VL53L1_set_GPIO_thresholds_from_struct( + VL53L1_DEV Dev, + VL53L1_GPIO_interrupt_config_t *pintconf); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_ref_spad_char_config( + VL53L1_DEV Dev, + uint8_t vcsel_period_a, + uint32_t phasecal_timeout_us, + uint16_t total_rate_target_mcps, + uint16_t max_count_rate_rtn_limit_mcps, + uint16_t min_count_rate_rtn_limit_mcps, + uint16_t fast_osc_frequency); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_ssc_config( + VL53L1_DEV Dev, + VL53L1_ssc_config_t *pssc_cfg, + uint16_t fast_osc_frequency); + + + + + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_spad_rate_data( + VL53L1_DEV Dev, + VL53L1_spad_rate_data_t *pspad_rates); + + + + + + + + + + + + + + + + +uint32_t VL53L1_calc_crosstalk_plane_offset_with_margin( + uint32_t plane_offset_kcps, + int16_t margin_offset_kcps); + + + + + + + + + + + + + +VL53L1_Error VL53L1_low_power_auto_data_init( + VL53L1_DEV Dev + ); + + + + + + + + + + + + + +VL53L1_Error VL53L1_low_power_auto_data_stop_range( + VL53L1_DEV Dev + ); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_dynamic_xtalk_correction_calc_required_samples( + VL53L1_DEV Dev + ); + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_dynamic_xtalk_correction_calc_new_xtalk( + VL53L1_DEV Dev, + uint32_t xtalk_offset_out, + VL53L1_smudge_corrector_config_t *pconfig, + VL53L1_smudge_corrector_data_t *pout, + uint8_t add_smudge, + uint8_t soft_update + ); + + + + + + + + + + + + + +VL53L1_Error VL53L1_dynamic_xtalk_correction_corrector( + VL53L1_DEV Dev + ); + + + + + + + + + + + + + + +VL53L1_Error VL53L1_dynamic_xtalk_correction_data_init( + VL53L1_DEV Dev + ); + + + + + + + + + + + + + +VL53L1_Error VL53L1_dynamic_xtalk_correction_output_init( + VL53L1_LLDriverResults_t *pres + ); + + + + + + + + + + + + + +VL53L1_Error VL53L1_xtalk_cal_data_init( + VL53L1_DEV Dev + ); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_config_low_power_auto_mode( + VL53L1_general_config_t *pgeneral, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_low_power_auto_data_t *plpadata + ); + + + + + + + + + + + + + + +VL53L1_Error VL53L1_low_power_auto_setup_manual_calibration( + VL53L1_DEV Dev); + + + + + + + + + + + + + +VL53L1_Error VL53L1_low_power_auto_update_DSS( + VL53L1_DEV Dev); + +#ifdef __cplusplus +} +#endif + +#endif + + diff --git a/drivers/input/misc/vl53L1/lito/inc/vl53l1_core_support.h b/drivers/input/misc/vl53L1/lito/inc/vl53l1_core_support.h new file mode 100644 index 000000000000..0b117491d6ce --- /dev/null +++ b/drivers/input/misc/vl53L1/lito/inc/vl53l1_core_support.h @@ -0,0 +1,414 @@ + +/******************************************************************************* + * Copyright (c) 2017, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#ifndef _VL53L1_CORE_SUPPORT_H_ +#define _VL53L1_CORE_SUPPORT_H_ + +#include "vl53l1_types.h" +#include "vl53l1_hist_structs.h" + +#ifdef __cplusplus +extern "C" { +#endif + + + + + + + + + + + + +uint32_t VL53L1_calc_pll_period_us( + uint16_t fast_osc_frequency); + + + + + + + + + + + + + + + + + + +uint32_t VL53L1_duration_maths( + uint32_t pll_period_us, + uint32_t vcsel_parm_pclks, + uint32_t window_vclks, + uint32_t periods_elapsed_mclks); + + + + + + + + + + + + + + + + +uint32_t VL53L1_events_per_spad_maths( + int32_t VL53L1_p_013, + uint16_t num_spads, + uint32_t duration); + + + + + + + + + + + + + +uint32_t VL53L1_isqrt( + uint32_t num); + + + + + + + + + + +void VL53L1_hist_calc_zero_distance_phase( + VL53L1_histogram_bin_data_t *pdata); + + + + + + + + + + + + + + + + + + + +void VL53L1_hist_estimate_ambient_from_thresholded_bins( + int32_t ambient_threshold_sigma, + VL53L1_histogram_bin_data_t *pdata); + + + + + + + + + + + + + +void VL53L1_hist_remove_ambient_bins( + VL53L1_histogram_bin_data_t *pdata); + + + + + + + + + + + + + + +uint32_t VL53L1_calc_pll_period_mm( + uint16_t fast_osc_frequency); + + + + + + + + + + + + + + + +uint16_t VL53L1_rate_maths( + int32_t VL53L1_p_008, + uint32_t time_us); + + + + + + + + + + + + + + + + + + +uint16_t VL53L1_rate_per_spad_maths( + uint32_t frac_bits, + uint32_t peak_count_rate, + uint16_t num_spads, + uint32_t max_output_value); + + + + + + + + + + + + + + + + + + + +int32_t VL53L1_range_maths( + uint16_t fast_osc_frequency, + uint16_t VL53L1_p_017, + uint16_t zero_distance_phase, + uint8_t fractional_bits, + int32_t gain_factor, + int32_t range_offset_mm); + + + + + + + + + + + + +uint8_t VL53L1_decode_vcsel_period( + uint8_t vcsel_period_reg); + + + + + + + + + + + +void VL53L1_copy_xtalk_bin_data_to_histogram_data_struct( + VL53L1_xtalk_histogram_shape_t *pxtalk, + VL53L1_histogram_bin_data_t *phist); + + + + + + + + + + + +void VL53L1_init_histogram_bin_data_struct( + int32_t bin_value, + uint16_t VL53L1_p_024, + VL53L1_histogram_bin_data_t *pdata); + + + + + + + + + + + + +void VL53L1_decode_row_col( + uint8_t spad_number, + uint8_t *prow, + uint8_t *pcol); + + + + + + + + + + + + + + + +void VL53L1_hist_find_min_max_bin_values( + VL53L1_histogram_bin_data_t *pdata); + + + + + + + + + + + + + + + +void VL53L1_hist_estimate_ambient_from_ambient_bins( + VL53L1_histogram_bin_data_t *pdata); + + +#ifdef __cplusplus +} +#endif + +#endif + + diff --git a/drivers/input/misc/vl53L1/lito/inc/vl53l1_def.h b/drivers/input/misc/vl53L1/lito/inc/vl53l1_def.h new file mode 100644 index 000000000000..abdd4a83ca8a --- /dev/null +++ b/drivers/input/misc/vl53L1/lito/inc/vl53l1_def.h @@ -0,0 +1,848 @@ +/****************************************************************************** + * Copyright (c) 2017, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + + ****************************************************************************** + + 'STMicroelectronics Proprietary license' + + ******************************************************************************* + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + + ******************************************************************************* + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones mentioned above : + + ******************************************************************************* + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + ******************************************************************************* + */ + +/** + * @file vl53l1_def.h + * + * @brief Type definitions for VL53L1 API. + * + */ + + +#ifndef _VL53L1_DEF_H_ +#define _VL53L1_DEF_H_ + +#include "vl53l1_ll_def.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** @defgroup VL53L1_globaldefine_group VL53L1 Defines + * @brief VL53L1 Defines + * @{ + */ + + +/** VL53L1 IMPLEMENTATION major version */ +#define VL53L1_IMPLEMENTATION_VER_MAJOR 6 +/** VL53L1 IMPLEMENTATION minor version */ +#define VL53L1_IMPLEMENTATION_VER_MINOR 0 +/** VL53L1 IMPLEMENTATION sub version */ +#define VL53L1_IMPLEMENTATION_VER_SUB 1 +/** VL53L1 IMPLEMENTATION sub version */ +#define VL53L1_IMPLEMENTATION_VER_REVISION 2003 + +/**************************************** + * PRIVATE define do not edit + ****************************************/ + +/** @brief Defines the parameters of the Get Version Functions + */ +typedef struct { + uint32_t revision; /*!< revision number */ + uint8_t major; /*!< major number */ + uint8_t minor; /*!< minor number */ + uint8_t build; /*!< build number */ +} VL53L1_Version_t; + + +#define VL53L1_DEVINFO_STRLEN 32 + +/** @brief Defines the parameters of the Get Device Info Functions + */ +typedef struct { + char Name[VL53L1_DEVINFO_STRLEN]; + /*!< Name of the Device e.g. Left_Distance */ + char Type[VL53L1_DEVINFO_STRLEN]; + /*!< Type of the Device e.g VL53L1 */ + char ProductId[VL53L1_DEVINFO_STRLEN]; + /*!< Product Identifier String + * @warning Not yet implemented + */ + uint8_t ProductType; + /*!< Product Type, VL53L1 = 1, VL53L1 = 2*/ + uint8_t ProductRevisionMajor; + /*!< Product revision major */ + uint8_t ProductRevisionMinor; + /*!< Product revision minor */ +} VL53L1_DeviceInfo_t; + + + +/** @defgroup VL53L1_define_PresetModes_group Defines Preset modes + * Defines all possible preset modes for the device + * @{ + */ +typedef uint8_t VL53L1_PresetModes; + +#define VL53L1_PRESETMODE_RANGING ((VL53L1_PresetModes) 1) +#define VL53L1_PRESETMODE_MULTIZONES_SCANNING ((VL53L1_PresetModes) 2) +#define VL53L1_PRESETMODE_AUTONOMOUS ((VL53L1_PresetModes) 3) +#define VL53L1_PRESETMODE_LITE_RANGING ((VL53L1_PresetModes) 4) +#define VL53L1_PRESETMODE_OLT ((VL53L1_PresetModes) 7) +#define VL53L1_PRESETMODE_LOWPOWER_AUTONOMOUS ((VL53L1_PresetModes) 8) +#define VL53L1_PRESETMODE_PROXY_RANGING_MODE ((VL53L1_PresetModes) 9) + +/** default preset ranging mode */ +//songyt test replace VL53L1_PRESETMODE_RANGING +#define STMVL53L1_CFG_DEFAULT_MODE VL53L1_PRESETMODE_RANGING + + /* ... Modes to be added depending on device */ +/** @} VL53L1_define_PresetModes_group */ + + +/** @defgroup VL53L1_define_DistanceModes_group Defines Distance modes + * Defines all possible Distance modes for the device + * @{ + */ +typedef uint8_t VL53L1_DistanceModes; + +#define VL53L1_DISTANCEMODE_SHORT ((VL53L1_DistanceModes) 1) +#define VL53L1_DISTANCEMODE_MEDIUM ((VL53L1_DistanceModes) 2) +#define VL53L1_DISTANCEMODE_LONG ((VL53L1_DistanceModes) 3) +/** @} VL53L1_define_DistanceModes_group */ + +/** @defgroup VL53L1_define_OutputModes_group Defines Output modes + * Defines all possible Output modes for the device + * @{ + */ +typedef uint8_t VL53L1_OutputModes; + +#define VL53L1_OUTPUTMODE_NEAREST ((VL53L1_OutputModes) 1) +#define VL53L1_OUTPUTMODE_STRONGEST ((VL53L1_OutputModes) 2) + +/** @} VL53L1_define_OutputModes_group */ + +/** @defgroup VL53L1_define_XtalkCal_group Defines Xtalk Calibration modes + * Defines all possible Offset Calibration modes for the device + * @{ + */ +typedef uint8_t VL53L1_XtalkCalibrationModes; + +#define VL53L1_XTALKCALIBRATIONMODE_NO_TARGET \ + ((VL53L1_OffsetCalibrationModes) 0) +/*!< To perform Xtalk calibration with no target below 80 cm */ +#define VL53L1_XTALKCALIBRATIONMODE_SINGLE_TARGET \ + ((VL53L1_OffsetCalibrationModes) 1) +/*!< To perform Xtalk calibration with one target */ +#define VL53L1_XTALKCALIBRATIONMODE_FULL_ROI \ + ((VL53L1_OffsetCalibrationModes) 2) +/*!< To perform Xtalk calibration based on histogram with full ROI */ + +/** @} VL53L1_define_XtalkCal_group */ + +/** @defgroup VL53L1_define_OffsetCal_group Defines Offset Calibration modes + * Defines all possible Offset Calibration modes for the device + * @{ + */ +typedef uint8_t VL53L1_OffsetCalibrationModes; + +#define VL53L1_OFFSETCALIBRATIONMODE_STANDARD \ + ((VL53L1_OffsetCalibrationModes) 1) +#define VL53L1_OFFSETCALIBRATIONMODE_PRERANGE_ONLY \ + ((VL53L1_OffsetCalibrationModes) 2) +#define VL53L1_OFFSETCALIBRATIONMODE_MULTI_ZONE \ + ((VL53L1_OffsetCalibrationModes) 3) + +/** @} VL53L1_define_OffsetCal_group */ + +/** @defgroup VL53L1_define_DeviceDmaxModes_group Defines Dmax source modes + * Defines all possible sources for Dmax calibration for the device + * @{ + */ +typedef uint8_t VL53L1_DeviceDmaxModes; + +#define VL53L1_DMAXMODE_FMT_CAL_DATA ((VL53L1_DeviceDmaxModes) 1) +#define VL53L1_DMAXMODE_CUSTCAL_DATA ((VL53L1_DeviceDmaxModes) 2) +#define VL53L1_DMAXMODE_PER_ZONE_CAL_DATA ((VL53L1_DeviceDmaxModes) 3) + +/** @} VL53L1_define_DeviceDmaxModes_group */ + +/** @defgroup VL53L1_define_OffsetCorrectionModesBD_group + * Device Offset Correction Mode + * + * @brief Defines all possible offset correction modes for the device + * @{ + */ +typedef uint8_t VL53L1_OffsetCorrectionModes; + +#define VL53L1_OFFSETCORRECTIONMODE_STANDARD ((VL53L1_OffsetCorrectionMode) 1) +#define VL53L1_OFFSETCORRECTIONMODE_PERZONE ((VL53L1_OffsetCorrectionMode) 2) + +/** @} VL53L1_define_OffsetCorrectionModesBD_group */ + +/** @defgroup VL53L1_define_RoiStatus_group Defines Roi Status + * Defines the read status mode + * @{ + */ +typedef uint8_t VL53L1_RoiStatus; + +#define VL53L1_ROISTATUS_NOT_VALID ((VL53L1_RoiStatus) 0) +#define VL53L1_ROISTATUS_VALID_NOT_LAST ((VL53L1_RoiStatus) 1) +#define VL53L1_ROISTATUS_VALID_LAST ((VL53L1_RoiStatus) 2) +/** @} VL53L1_define_RoiStatus_group */ + + +/** @defgroup VL53L1_CheckEnable_group Check Enable list + * @brief Check Enable code + * + * Define used to specify the LimitCheckId. + * Use @a VL53L1_GetLimitCheckInfo() to get the string. + * @{ + */ + +#define VL53L1_CHECKENABLE_SIGMA_FINAL_RANGE 0 +#define VL53L1_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE 1 + +#define VL53L1_CHECKENABLE_NUMBER_OF_CHECKS 2 + +/** @} end of VL53L1_CheckEnable_group */ + + +/** @defgroup VL53L1_ThresholdMode_gropup Detection Functionality + * @brief Defines the different functionalities for the detection feature + * @{ + */ +typedef uint8_t VL53L1_ThresholdMode; + +#define VL53L1_THRESHOLD_CROSSED_LOW \ + ((VL53L1_ThresholdMode) 0) + /*!< Trigger interrupt if value < thresh_low */ +#define VL53L1_THRESHOLD_CROSSED_HIGH \ + ((VL53L1_ThresholdMode) 1) + /*!< Trigger interrupt if value > thresh_high */ +#define VL53L1_THRESHOLD_OUT_OF_WINDOW \ + ((VL53L1_ThresholdMode) 2) + /*!< Trigger interrupt if value < thresh_low OR value > thresh_high */ +#define VL53L1_THRESHOLD_IN_WINDOW \ + ((VL53L1_ThresholdMode) 3) + /*!< Trigger interrupt if value > thresh_low AND value < thresh_high */ + +/** @} end of VL53L1_ThresholdMode_gropup */ + +/** @brief Defines parameters for Distance detection Thresholds configuration + */ +typedef struct { + VL53L1_ThresholdMode CrossMode; + uint16_t High; /*!< Distance threshold high limit in mm */ + uint16_t Low; /*!< Distance threshold low limit in mm */ +} VL53L1_DistanceThreshold_t; + +/** @brief Defines parameters for Signal rate detection Thresholds configuration + */ +typedef struct { + VL53L1_ThresholdMode CrossMode; + FixPoint1616_t High; /*!< Signal rate threshold high limit */ + FixPoint1616_t Low; /*!< Signal rate threshold low limit */ +} VL53L1_RateThreshold_t; + +/** @defgroup VL53L1_DetectionMode_group Gpio Functionality + * @brief Defines conditions leading to device's IT on GPIO + * @{ + */ +typedef uint8_t VL53L1_DetectionMode; + +#define VL53L1_DETECTION_NORMAL_RUN \ + ((VL53L1_DetectionMode) 0) + /*!< Trigger interrupt on new measurement regardless of threshold + * just like after a VL53L1_SetPresetMode() call + */ +#define VL53L1_DETECTION_DISTANCE_ONLY \ + ((VL53L1_DetectionMode) 1) + /*!< Trigger interrupt if "threshold event" occurs on distance */ +#define VL53L1_DETECTION_RATE_ONLY \ + ((VL53L1_DetectionMode) 2) + /*!< Trigger interrupt if "threshold event" occurs on signal rate */ +#define VL53L1_DETECTION_DISTANCE_AND_RATE \ + ((VL53L1_DetectionMode) 3) + /*!< Trigger interrupt if "threshold event" occurs on distance AND rate + */ +#define VL53L1_DETECTION_DISTANCE_OR_RATE \ + ((VL53L1_DetectionMode) 4) + /*!< Trigger interrupt if "threshold event" occurs on distance OR rate + */ + +/** @} end of VL53L1_DetectionMode_group */ + +/** @brief Defines parameters for User/object Detection configuration + */ +typedef struct { + VL53L1_DetectionMode DetectionMode; /*!< See #VL53L1_DetectionMode*/ + uint8_t IntrNoTarget; /*!< 1 to trigger IT in case of no target found */ + VL53L1_DistanceThreshold_t Distance; /*!< limits in mm */ + VL53L1_RateThreshold_t Rate;/*!< limits in FixPoint1616_t */ +} VL53L1_DetectionConfig_t; + + +/** @brief Defines all parameters for the device + */ +typedef struct { + VL53L1_PresetModes PresetMode; + /*!< Defines the operating mode to be used for the next measure */ + VL53L1_OutputModes OutputMode; + /*!< Defines the Output mode to be used for the next measure */ + VL53L1_DistanceModes DistanceMode; + /*!< Defines the operating mode to be used for the next measure */ + uint32_t MeasurementTimingBudgetMicroSeconds; + /*!< Defines the allowed total time for a single measurement */ + uint8_t LimitChecksEnable[VL53L1_CHECKENABLE_NUMBER_OF_CHECKS]; + /*!< This Array store all the Limit Check enable for this device. */ + uint8_t LimitChecksStatus[VL53L1_CHECKENABLE_NUMBER_OF_CHECKS]; + /*!< This Array stores all the Status of the check linked to last + * measurement. + */ + FixPoint1616_t LimitChecksValue[VL53L1_CHECKENABLE_NUMBER_OF_CHECKS]; + /*!< This Array stores all the Limit Check value for this device */ + FixPoint1616_t LimitChecksCurrent[VL53L1_CHECKENABLE_NUMBER_OF_CHECKS]; + /*!< This Array stores all the Limit Check current value from latest + * ranging + */ +} VL53L1_DeviceParameters_t; + + +/** @defgroup VL53L1_define_State_group Defines the current status of the device + * Defines the current status of the device + * @{ + */ + +typedef uint8_t VL53L1_State; + +#define VL53L1_STATE_POWERDOWN ((VL53L1_State) 0) + /*!< Device is in HW reset */ +#define VL53L1_STATE_WAIT_STATICINIT ((VL53L1_State) 1) + /*!< Device is initialized and wait for static initialization */ +#define VL53L1_STATE_STANDBY ((VL53L1_State) 2) + /*!< Device is in Low power Standby mode */ +#define VL53L1_STATE_IDLE ((VL53L1_State) 3) + /*!< Device has been initialized and ready to do measurements */ +#define VL53L1_STATE_RUNNING ((VL53L1_State) 4) + /*!< Device is performing measurement */ +#define VL53L1_STATE_RESET ((VL53L1_State) 5) + /*!< Soft reset has been run on Device */ +#define VL53L1_STATE_UNKNOWN ((VL53L1_State) 98) + /*!< Device is in unknown state and need to be rebooted */ +#define VL53L1_STATE_ERROR ((VL53L1_State) 99) + /*!< Device is in error state and need to be rebooted */ + +/** @} VL53L1_define_State_group */ + +/** @defgroup VL53L1_define_Smudge_Mode_group Defines smudge correction modes + * Defines the smudge correction modes + * @{ + */ + +typedef uint8_t VL53L1_SmudgeCorrectionModes; + +#define VL53L1_SMUDGE_CORRECTION_NONE ((VL53L1_SmudgeCorrectionModes) 0) + /*!< Smudge correction is applied continously accross the rangings */ +#define VL53L1_SMUDGE_CORRECTION_CONTINUOUS ((VL53L1_SmudgeCorrectionModes) 1) + /*!< Smudge correction is applied continously accross the rangings */ +#define VL53L1_SMUDGE_CORRECTION_SINGLE ((VL53L1_SmudgeCorrectionModes) 2) + /*!< Smudge correction is applied only once accross the rangings */ +#define VL53L1_SMUDGE_CORRECTION_DEBUG ((VL53L1_SmudgeCorrectionModes) 3) + /*!< Smudge detection is applied continously but Xtalk values are not + * updated automatically within the driver + */ + +/** @} VL53L1_define_Smudge_Correction_Mode_group */ + + +/** + * @struct VL53L1_RangingMeasurementData_t + * @brief Single Range measurement data. + */ +typedef struct { + uint32_t TimeStamp; + /*!< 32-bit time stamp. + * @warning Not yet implemented + */ + + uint8_t StreamCount; + /*!< 8-bit Stream Count. */ + + uint8_t RangeQualityLevel; + /*!< indicate a quality level in percentage from 0 to 100 + * @warning Not yet implemented + */ + + FixPoint1616_t SignalRateRtnMegaCps; + /*!< Return signal rate (MCPS)\n these is a 16.16 fix point + * value, which is effectively a measure of target + * reflectance. + */ + + FixPoint1616_t AmbientRateRtnMegaCps; + /*!< Return ambient rate (MCPS)\n these is a 16.16 fix point + * value, which is effectively a measure of the ambien + * t light. + */ + + uint16_t EffectiveSpadRtnCount; + /*!< Return the effective SPAD count for the return signal. + * To obtain Real value it should be divided by 256 + */ + + FixPoint1616_t SigmaMilliMeter; + /*!< Return the Sigma value in millimeter */ + + int16_t RangeMilliMeter; + /*!< range distance in millimeter. This should be between + * RangeMinMilliMeter and RangeMaxMilliMeter + */ + + uint8_t RangeFractionalPart; + /*!< Fractional part of range distance. Final value is a + * RangeMilliMeter + RangeFractionalPart/256. + * @warning Not yet implemented + */ + + uint8_t RangeStatus; + /*!< Range Status for the current measurement. This is device + * dependent. Value = 0 means value is valid. + */ +} VL53L1_RangingMeasurementData_t; + +/** + * @struct VL53L1_TargetRangeData_t + * @brief One Range measurement data for each target. + */ +typedef struct { + uint8_t RangeQualityLevel; + /*!< indicate a quality level in percentage from 0 to 100 + * @warning Not yet implemented + */ + + int16_t RangeMaxMilliMeter; + /*!< Tells what is the maximum detection distance of the object + * in current setup and environment conditions (Filled when + * applicable) + */ + + int16_t RangeMinMilliMeter; + /*!< Tells what is the minimum detection distance of the object + * in current setup and environment conditions (Filled when + * applicable) + */ + + FixPoint1616_t SignalRateRtnMegaCps; + /*!< Return signal rate (MCPS)\n these is a 16.16 fix point + * value, which is effectively a measure of target + * reflectance. + */ + + FixPoint1616_t AmbientRateRtnMegaCps; + /*!< Return ambient rate (MCPS)\n these is a 16.16 fix point + * value, which is effectively a measure of the ambien + * t light. + */ + + FixPoint1616_t SigmaMilliMeter; + /*!< Return the Sigma value in millimeter */ + + int16_t RangeMilliMeter; + /*!< range distance in millimeter. This should be between + * RangeMinMilliMeter and RangeMaxMilliMeter + */ + + uint8_t RangeFractionalPart; + /*!< Fractional part of range distance. Final value is a + * RangeMilliMeter + RangeFractionalPart/256. + * @warning Not yet implemented + */ + + uint8_t RangeStatus; + /*!< Range Status for the current measurement. This is device + * dependent. Value = 0 means value is valid. + */ +} VL53L1_TargetRangeData_t; +/** + * @struct VL53L1_MultiRangingData_t + * @brief Structure for storing the set of range results for a single ROI + * + */ +typedef struct { + uint32_t TimeStamp; + /*!< 32-bit time stamp. + * @warning Not yet implemented + */ + + uint8_t StreamCount; + /*!< 8-bit Stream Count. */ + + uint8_t RoiNumber; + /*!< Denotes on which ROI the range data is related to. */ + uint8_t NumberOfObjectsFound; + /*!< Indicate the number of objects found in the current ROI. + * This is used to know how many ranging data should be get. + * NumberOfObjectsFound is in the range 0 to + * VL53L1_MAX_RANGE_RESULTS. + */ + VL53L1_RoiStatus RoiStatus; + /*!< Indicate if the data read is valid or not or if this is + * the last valid data in the ROI. + */ + VL53L1_TargetRangeData_t RangeData[VL53L1_MAX_RANGE_RESULTS]; + /*!< Range data each target distance */ + uint8_t HasXtalkValueChanged; + /*!< set to 1 if a new Xtalk value has been computed whilst + * smudge correction mode enable by with + * VL53L1_SmudgeCorrectionEnable() function is either + * VL53L1_SMUDGE_CORRECTION_CONTINUOUS or + * VL53L1_SMUDGE_CORRECTION_SINGLE. + */ + uint16_t EffectiveSpadRtnCount; + /*!< Return the effective SPAD count for the return signal. + * To obtain Real value it should be divided by 256 + */ + int16_t DmaxMilliMeter; + /*!< range Dmax distance in millimeter. + */ + VL53L1_DistanceModes RecommendedDistanceMode; + /*!< suggestion for a better distance mode choice to improve + * range accuracy. + */ +} VL53L1_MultiRangingData_t; + + +/** @brief Defines User Zone(ROI) parameters + * + */ +typedef struct { + + uint8_t TopLeftX; /*!< Top Left x coordinate: 0-15 range */ + uint8_t TopLeftY; /*!< Top Left y coordinate: 0-15 range */ + uint8_t BotRightX; /*!< Bot Right x coordinate: 0-15 range */ + uint8_t BotRightY; /*!< Bot Right y coordinate: 0-15 range */ + +} VL53L1_UserRoi_t; + + +/** @brief Defines ROI configuration parameters + * + * Support up a max of 16 zones, Each Zone has the same size + * + */ +typedef struct { + + uint8_t NumberOfRoi; /*!< Number of Rois defined*/ + + VL53L1_UserRoi_t UserRois[VL53L1_MAX_USER_ZONES]; + /*!< List of Rois */ + +} VL53L1_RoiConfig_t; + +/** + * @struct VL53L1_CustomerNvmManaged_t + * + */ + +typedef struct { + uint8_t global_config__spad_enables_ref_0; + uint8_t global_config__spad_enables_ref_1; + uint8_t global_config__spad_enables_ref_2; + uint8_t global_config__spad_enables_ref_3; + uint8_t global_config__spad_enables_ref_4; + uint8_t global_config__spad_enables_ref_5; + uint8_t global_config__ref_en_start_select; + uint8_t ref_spad_man__num_requested_ref_spads; + uint8_t ref_spad_man__ref_location; + uint32_t algo__crosstalk_compensation_plane_offset_kcps; + int16_t algo__crosstalk_compensation_x_plane_gradient_kcps; + int16_t algo__crosstalk_compensation_y_plane_gradient_kcps; + uint16_t ref_spad_char__total_rate_target_mcps; + int16_t algo__part_to_part_range_offset_mm; + int16_t mm_config__inner_offset_mm; + int16_t mm_config__outer_offset_mm; +} VL53L1_CustomerNvmManaged_t; + +/** + * @struct VL53L1_CalibrationData_t + * @brief Structure for storing the Calibration Data + * + */ + +typedef struct { + + uint32_t struct_version; + VL53L1_CustomerNvmManaged_t customer; + VL53L1_dmax_calibration_data_t fmt_dmax_cal; + VL53L1_dmax_calibration_data_t cust_dmax_cal; + VL53L1_additional_offset_cal_data_t add_off_cal_data; + VL53L1_optical_centre_t optical_centre; + VL53L1_xtalk_histogram_data_t xtalkhisto; + VL53L1_gain_calibration_data_t gain_cal; + VL53L1_cal_peak_rate_map_t cal_peak_rate_map; + +} VL53L1_CalibrationData_t; + +#define VL53L1_ADDITIONAL_CALIBRATION_DATA_STRUCT_VERSION 0x10 +/** VL53L1 additional Calibration Data struct version final struct version + * is given by adding it to VL53L1_LL_CALIBRATION_DATA_STRUCT_VERSION + */ + +#define VL53L1_CALIBRATION_DATA_STRUCT_VERSION \ + (VL53L1_LL_CALIBRATION_DATA_STRUCT_VERSION + \ + VL53L1_ADDITIONAL_CALIBRATION_DATA_STRUCT_VERSION) +/* VL53L1 Calibration Data struct version */ + +/** + * @struct VL53L1_AdditionalData_t + * @brief Structure for storing the Additional Data + * + */ +typedef VL53L1_additional_data_t VL53L1_AdditionalData_t; + +/** + * @struct VL53L1_ZoneCalibrationData_t + * @brief Structure for storing the Zone Calibration Data + * + */ +typedef VL53L1_zone_calibration_results_t VL53L1_ZoneCalibrationData_t; + +/** @defgroup VL53L1_define_SequenceStepId_group Defines the SequenceStep + * Defines the the sequence steps performed during ranging.. + * @{ + */ +typedef uint8_t VL53L1_SequenceStepId; + +#define VL53L1_SEQUENCESTEP_VHV ((VL53L1_SequenceStepId) 0) +/*!>12)&0xFFFF) +#define VL53L1_FIXPOINT44TOFIXPOINT1616(Value) \ + (FixPoint1616_t)((uint32_t)Value<<12) + +#define VL53L1_FIXPOINT1616TOFIXPOINT72(Value) \ + (uint16_t)((Value>>14)&0xFFFF) +#define VL53L1_FIXPOINT72TOFIXPOINT1616(Value) \ + (FixPoint1616_t)((uint32_t)Value<<14) + +#define VL53L1_FIXPOINT1616TOFIXPOINT97(Value) \ + (uint16_t)((Value>>9)&0xFFFF) +#define VL53L1_FIXPOINT97TOFIXPOINT1616(Value) \ + (FixPoint1616_t)((uint32_t)Value<<9) + +#define VL53L1_FIXPOINT1616TOFIXPOINT88(Value) \ + (uint16_t)((Value>>8)&0xFFFF) +#define VL53L1_FIXPOINT88TOFIXPOINT1616(Value) \ + (FixPoint1616_t)((uint32_t)Value<<8) + +#define VL53L1_FIXPOINT1616TOFIXPOINT412(Value) \ + (uint16_t)((Value>>4)&0xFFFF) +#define VL53L1_FIXPOINT412TOFIXPOINT1616(Value) \ + (FixPoint1616_t)((uint32_t)Value<<4) + +#define VL53L1_FIXPOINT1616TOFIXPOINT313(Value) \ + (uint16_t)((Value>>3)&0xFFFF) +#define VL53L1_FIXPOINT313TOFIXPOINT1616(Value) \ + (FixPoint1616_t)((uint32_t)Value<<3) + +#define VL53L1_FIXPOINT1616TOFIXPOINT08(Value) \ + (uint8_t)((Value>>8)&0x00FF) +#define VL53L1_FIXPOINT08TOFIXPOINT1616(Value) \ + (FixPoint1616_t)((uint32_t)Value<<8) + +#define VL53L1_FIXPOINT1616TOFIXPOINT53(Value) \ + (uint8_t)((Value>>13)&0x00FF) +#define VL53L1_FIXPOINT53TOFIXPOINT1616(Value) \ + (FixPoint1616_t)((uint32_t)Value<<13) + +#define VL53L1_FIXPOINT1616TOFIXPOINT102(Value) \ + (uint16_t)((Value>>14)&0x0FFF) +#define VL53L1_FIXPOINT102TOFIXPOINT1616(Value) \ + (FixPoint1616_t)((uint32_t)Value<<14) + +#define VL53L1_FIXPOINT1616TOFIXPOINT142(Value) \ + (uint16_t)((Value>>14)&0xFFFF) +#define VL53L1_FIXPOINT142TOFIXPOINT1616(Value) \ + (FixPoint1616_t)((uint32_t)Value<<14) + +#define VL53L1_FIXPOINT1616TOFIXPOINT160(Value) \ + (uint16_t)((Value>>16)&0xFFFF) +#define VL53L1_FIXPOINT160TOFIXPOINT1616(Value) \ + (FixPoint1616_t)((uint32_t)Value<<16) + +#define VL53L1_MAKEUINT16(lsb, msb) (uint16_t)((((uint16_t)msb)<<8) + \ + (uint16_t)lsb) + +#ifndef SUPPRESS_UNUSED_WARNING +#define SUPPRESS_UNUSED_WARNING(x) ((void) (x)) +#endif + +/** @} VL53L1_define_GeneralMacro_group */ + +/** @} VL53L1_globaldefine_group */ + + + +#ifdef __cplusplus +} +#endif + + +#endif /* _VL53L1_DEF_H_ */ diff --git a/drivers/input/misc/vl53L1/lito/inc/vl53l1_dmax_structs.h b/drivers/input/misc/vl53L1/lito/inc/vl53l1_dmax_structs.h new file mode 100644 index 000000000000..5b4d9b7f20e3 --- /dev/null +++ b/drivers/input/misc/vl53L1/lito/inc/vl53l1_dmax_structs.h @@ -0,0 +1,210 @@ + +/******************************************************************************* + * Copyright (c) 2017, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#ifndef _VL53L1_DMAX_STRUCTS_H_ +#define _VL53L1_DMAX_STRUCTS_H_ + +#include "vl53l1_types.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + + +#define VL53L1_MAX_AMBIENT_DMAX_VALUES 5 + + + + + + + + + + + + +typedef struct { + + + + + uint16_t ref__actual_effective_spads; + + + uint16_t ref__peak_signal_count_rate_mcps; + + + uint16_t ref__distance_mm; + + + uint16_t ref_reflectance_pc; + + + + + + + uint16_t coverglass_transmission; + + + +} VL53L1_dmax_calibration_data_t; + + + + + + + + + + +typedef struct { + + + + + uint8_t signal_thresh_sigma; + + + uint8_t ambient_thresh_sigma; + + + int32_t min_ambient_thresh_events; + + + int32_t signal_total_events_limit; + + + + uint16_t target_reflectance_for_dmax_calc[ + VL53L1_MAX_AMBIENT_DMAX_VALUES]; + + + uint16_t max_effective_spads; + + + + + + + uint16_t dss_config__target_total_rate_mcps; + + + uint8_t dss_config__aperture_attenuation; + + + +} VL53L1_hist_gen3_dmax_config_t; + + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/drivers/input/misc/vl53L1/lito/inc/vl53l1_error_codes.h b/drivers/input/misc/vl53L1/lito/inc/vl53l1_error_codes.h new file mode 100644 index 000000000000..1bf727eaf560 --- /dev/null +++ b/drivers/input/misc/vl53L1/lito/inc/vl53l1_error_codes.h @@ -0,0 +1,273 @@ +/****************************************************************************** + * Copyright (c) 2017, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + + ****************************************************************************** + + 'STMicroelectronics Proprietary license' + + ******************************************************************************* + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + + ******************************************************************************* + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones mentioned above : + + ******************************************************************************* + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + ******************************************************************************* + */ + +/** + * @file vl53l1_error_codes.h + * + * @brief Error Code definitions for VL53L1 API. + * + */ + +#ifndef _VL53L1_ERROR_CODES_H_ +#define _VL53L1_ERROR_CODES_H_ + +#include "vl53l1_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +/* + **************************************** + * PRIVATE define do not edit + *************************************** + */ + +/* + * @defgroup VL53L1_define_Error_group Error and Warning code returned by API + * The following DEFINE are used to identify the PAL ERROR + * @{ + */ + +typedef int8_t VL53L1_Error; + +#define VL53L1_ERROR_NONE ((VL53L1_Error) 0) +#define VL53L1_ERROR_CALIBRATION_WARNING ((VL53L1_Error) - 1) + /*!< Warning invalid calibration data may be in used + * \a VL53L1_InitData() + * \a VL53L1_GetOffsetCalibrationData + * \a VL53L1_SetOffsetCalibrationData + */ +#define VL53L1_ERROR_MIN_CLIPPED ((VL53L1_Error) - 2) + /*!< Warning parameter passed was clipped to min before to be applied */ + +#define VL53L1_ERROR_UNDEFINED ((VL53L1_Error) - 3) + /*!< Unqualified error */ +#define VL53L1_ERROR_INVALID_PARAMS ((VL53L1_Error) - 4) + /*!< Parameter passed is invalid or out of range */ +#define VL53L1_ERROR_NOT_SUPPORTED ((VL53L1_Error) - 5) + /*!< Function is not supported in current mode or configuration */ +#define VL53L1_ERROR_RANGE_ERROR ((VL53L1_Error) - 6) + /*!< Device report a ranging error interrupt status */ +#define VL53L1_ERROR_TIME_OUT ((VL53L1_Error) - 7) + /*!< Aborted due to time out */ +#define VL53L1_ERROR_MODE_NOT_SUPPORTED ((VL53L1_Error) - 8) + /*!< Asked mode is not supported by the device */ +#define VL53L1_ERROR_BUFFER_TOO_SMALL ((VL53L1_Error) - 9) + /*!< ... */ +#define VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL ((VL53L1_Error) - 10) + /*!< Supplied buffer is larger than I2C supports */ +#define VL53L1_ERROR_GPIO_NOT_EXISTING ((VL53L1_Error) - 11) + /*!< User tried to setup a non-existing GPIO pin */ +#define VL53L1_ERROR_GPIO_FUNCTIONALITY_NOT_SUPPORTED ((VL53L1_Error) - 12) + /*!< unsupported GPIO functionality */ +#define VL53L1_ERROR_CONTROL_INTERFACE ((VL53L1_Error) - 13) + /*!< error reported from IO functions */ +#define VL53L1_ERROR_INVALID_COMMAND ((VL53L1_Error) - 14) + /*!< The command is not allowed in the current device state + * (power down) + */ +#define VL53L1_ERROR_DIVISION_BY_ZERO ((VL53L1_Error) - 15) + /*!< In the function a division by zero occurs */ +#define VL53L1_ERROR_REF_SPAD_INIT ((VL53L1_Error) - 16) + /*!< Error during reference SPAD initialization */ +#define VL53L1_ERROR_GPH_SYNC_CHECK_FAIL ((VL53L1_Error) - 17) + /*!< GPH sync interrupt check fail - API out of sync with device*/ +#define VL53L1_ERROR_STREAM_COUNT_CHECK_FAIL ((VL53L1_Error) - 18) + /*!< Stream count check fail - API out of sync with device */ +#define VL53L1_ERROR_GPH_ID_CHECK_FAIL ((VL53L1_Error) - 19) + /*!< GPH ID check fail - API out of sync with device */ +#define VL53L1_ERROR_ZONE_STREAM_COUNT_CHECK_FAIL ((VL53L1_Error) - 20) + /*!< Zone dynamic config stream count check failed - API out of sync */ +#define VL53L1_ERROR_ZONE_GPH_ID_CHECK_FAIL ((VL53L1_Error) - 21) + /*!< Zone dynamic config GPH ID check failed - API out of sync */ + +#define VL53L1_ERROR_XTALK_EXTRACTION_NO_SAMPLE_FAIL ((VL53L1_Error) - 22) + /*!< Thrown when run_xtalk_extraction fn has 0 succesful samples + * when using the full array to sample the xtalk. In this case there is + * not enough information to generate new Xtalk parm info. The function + * will exit and leave the current xtalk parameters unaltered + */ +#define VL53L1_ERROR_XTALK_EXTRACTION_SIGMA_LIMIT_FAIL ((VL53L1_Error) - 23) + /*!< Thrown when run_xtalk_extraction fn has found that the + * avg sigma estimate of the full array xtalk sample is > than the + * maximal limit allowed. In this case the xtalk sample is too noisy for + * measurement. The function will exit and leave the current xtalk + * parameters unaltered. + */ + + +#define VL53L1_ERROR_OFFSET_CAL_NO_SAMPLE_FAIL ((VL53L1_Error) - 24) + /*!< Thrown if there one of stages has no valid offset calibration + * samples. A fatal error calibration not valid + */ +#define VL53L1_ERROR_OFFSET_CAL_NO_SPADS_ENABLED_FAIL ((VL53L1_Error) - 25) + /*!< Thrown if there one of stages has zero effective SPADS + * Traps the case when MM1 SPADs is zero. + * A fatal error calibration not valid + */ +#define VL53L1_ERROR_ZONE_CAL_NO_SAMPLE_FAIL ((VL53L1_Error) - 26) + /*!< Thrown if then some of the zones have no valid samples + * A fatal error calibration not valid + */ + +#define VL53L1_ERROR_TUNING_PARM_KEY_MISMATCH ((VL53L1_Error) - 27) + /*!< Thrown if the tuning file key table version does not match with + * expected value. The driver expects the key table version to match + * the compiled default version number in the define + * #VL53L1_TUNINGPARM_KEY_TABLE_VERSION_DEFAULT + */ + +#define VL53L1_WARNING_REF_SPAD_CHAR_NOT_ENOUGH_SPADS ((VL53L1_Error) - 28) + /*!< Thrown if there are less than 5 good SPADs are available. */ +#define VL53L1_WARNING_REF_SPAD_CHAR_RATE_TOO_HIGH ((VL53L1_Error) - 29) + /*!< Thrown if the final reference rate is greater than + * the upper reference rate limit - default is 40 Mcps. + * Implies a minimum Q3 (x10) SPAD (5) selected + */ +#define VL53L1_WARNING_REF_SPAD_CHAR_RATE_TOO_LOW ((VL53L1_Error) - 30) + /*!< Thrown if the final reference rate is less than + * the lower reference rate limit - default is 10 Mcps. + * Implies maximum Q1 (x1) SPADs selected + */ + + +#define VL53L1_WARNING_OFFSET_CAL_MISSING_SAMPLES ((VL53L1_Error) - 31) + /*!< Thrown if there is less than the requested number of + * valid samples. + */ +#define VL53L1_WARNING_OFFSET_CAL_SIGMA_TOO_HIGH ((VL53L1_Error) - 32) + /*!< Thrown if the offset calibration range sigma estimate is greater + * than 8.0 mm. This is the recommended min value to yield a stable + * offset measurement + */ +#define VL53L1_WARNING_OFFSET_CAL_RATE_TOO_HIGH ((VL53L1_Error) - 33) + /*!< Thrown when VL53L1_run_offset_calibration() peak rate is greater + * than that 50.0Mcps. This is the recommended max rate to avoid + * pile-up influencing the offset measurement + */ +#define VL53L1_WARNING_OFFSET_CAL_SPAD_COUNT_TOO_LOW ((VL53L1_Error) - 34) + /*!< Thrown when VL53L1_run_offset_calibration() when one of stages + * range has less that 5.0 effective SPADS. This is the recommended + * min value to yield a stable offset + */ + + +#define VL53L1_WARNING_ZONE_CAL_MISSING_SAMPLES ((VL53L1_Error) - 35) + /*!< Thrown if one of more of the zones have less than + * the requested number of valid samples + */ +#define VL53L1_WARNING_ZONE_CAL_SIGMA_TOO_HIGH ((VL53L1_Error) - 36) + /*!< Thrown if one or more zones have sigma estimate value greater + * than 8.0 mm. This is the recommended min value to yield a stable + * offset measurement + */ +#define VL53L1_WARNING_ZONE_CAL_RATE_TOO_HIGH ((VL53L1_Error) - 37) + /*!< Thrown if one of more zones have peak rate higher than + * that 50.0Mcps. This is the recommended max rate to avoid + * pile-up influencing the offset measurement + */ + + +#define VL53L1_WARNING_XTALK_MISSING_SAMPLES ((VL53L1_Error) - 38) + /*!< Thrown to notify that some of the xtalk samples did not yield + * valid ranging pulse data while attempting to measure + * the xtalk signal in vl53l1_run_xtalk_extract(). This can signify any + * of the zones are missing samples, for further debug information the + * xtalk_results struct should be referred to. This warning is for + * notification only, xtalk pulse and shape have still been generated + */ +#define VL53L1_WARNING_XTALK_NO_SAMPLES_FOR_GRADIENT ((VL53L1_Error) - 39) + /*!< Thrown to notify that some of teh xtalk samples used for gradient + * generation did not yield valid ranging pulse data while attempting to + * measure the xtalk signal in vl53l1_run_xtalk_extract(). This can + * signify that any one of the zones 0-3 yielded no successful samples. + * xtalk_results struct should be referred to for further debug info. + * This warning is for notification only, the xtalk pulse and shape + * have still been generated. + */ +#define VL53L1_WARNING_XTALK_SIGMA_LIMIT_FOR_GRADIENT ((VL53L1_Error) - 40) + /*!< Thrown to notify that some of the xtalk samples used for gradient + * generation did not pass the sigma limit check while attempting to + * measure the xtalk signal in vl53l1_run_xtalk_extract(). This can + * signify that any one of the zones 0-3 yielded an avg sigma_mm + * value > the limit. The xtalk_results struct should be referred to for + * further debug info. + * This warning is for notification only, the xtalk pulse and shape + * have still been generated. + */ + +#define VL53L1_ERROR_NOT_IMPLEMENTED ((VL53L1_Error) - 41) + /*!< Tells requested functionality has not been implemented yet or + * not compatible with the device + */ +#define VL53L1_ERROR_PLATFORM_SPECIFIC_START ((VL53L1_Error) - 60) + /*!< Tells the starting code for platform */ +/** @} VL53L1_define_Error_group */ + + +#ifdef __cplusplus +} +#endif + + +#endif /* _VL53L1_ERROR_CODES_H_ */ diff --git a/drivers/input/misc/vl53L1/lito/inc/vl53l1_error_exceptions.h b/drivers/input/misc/vl53L1/lito/inc/vl53l1_error_exceptions.h new file mode 100644 index 000000000000..0b2db2ba0e28 --- /dev/null +++ b/drivers/input/misc/vl53L1/lito/inc/vl53l1_error_exceptions.h @@ -0,0 +1,126 @@ + +/******************************************************************************* + * Copyright (c) 2017, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#ifndef _VL53L1_ERROR_EXCEPTIONS_H_ +#define _VL53L1_ERROR_EXCEPTIONS_H_ + +#define IGNORE_DIVISION_BY_ZERO 0 + +#define IGNORE_XTALK_EXTRACTION_NO_SAMPLE_FAIL 0 +#define IGNORE_XTALK_EXTRACTION_SIGMA_LIMIT_FAIL 0 +#define IGNORE_XTALK_EXTRACTION_NO_SAMPLE_FOR_GRADIENT_WARN 0 +#define IGNORE_XTALK_EXTRACTION_SIGMA_LIMIT_FOR_GRADIENT_WARN 0 +#define IGNORE_XTALK_EXTRACTION_MISSING_SAMPLES_WARN 0 + +#define IGNORE_REF_SPAD_CHAR_NOT_ENOUGH_SPADS 0 +#define IGNORE_REF_SPAD_CHAR_RATE_TOO_HIGH 0 +#define IGNORE_REF_SPAD_CHAR_RATE_TOO_LOW 0 + +#define IGNORE_OFFSET_CAL_MISSING_SAMPLES 0 +#define IGNORE_OFFSET_CAL_SIGMA_TOO_HIGH 0 +#define IGNORE_OFFSET_CAL_RATE_TOO_HIGH 0 +#define IGNORE_OFFSET_CAL_SPAD_COUNT_TOO_LOW 0 + +#define IGNORE_ZONE_CAL_MISSING_SAMPLES 0 +#define IGNORE_ZONE_CAL_SIGMA_TOO_HIGH 0 +#define IGNORE_ZONE_CAL_RATE_TOO_HIGH 0 + +#endif + + diff --git a/drivers/input/misc/vl53L1/lito/inc/vl53l1_error_strings.h b/drivers/input/misc/vl53L1/lito/inc/vl53l1_error_strings.h new file mode 100644 index 000000000000..02cba46adb53 --- /dev/null +++ b/drivers/input/misc/vl53L1/lito/inc/vl53l1_error_strings.h @@ -0,0 +1,244 @@ + +/******************************************************************************* + * Copyright (c) 2017, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#ifndef VL53L1_ERROR_STRINGS_H_ +#define VL53L1_ERROR_STRINGS_H_ + +#include "vl53l1_error_codes.h" + +#ifdef __cplusplus +extern "C" { +#endif + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_pal_error_string( + VL53L1_Error PalErrorCode, + char *pPalErrorString); + + +#ifndef VL53L1_USE_EMPTY_STRING + + + + #define VL53L1_STRING_ERROR_NONE \ + "No Error" + #define VL53L1_STRING_ERROR_CALIBRATION_WARNING \ + "Calibration Warning Error" + #define VL53L1_STRING_ERROR_MIN_CLIPPED \ + "Min clipped error" + #define VL53L1_STRING_ERROR_UNDEFINED \ + "Undefined error" + #define VL53L1_STRING_ERROR_INVALID_PARAMS \ + "Invalid parameters error" + #define VL53L1_STRING_ERROR_NOT_SUPPORTED \ + "Not supported error" + #define VL53L1_STRING_ERROR_RANGE_ERROR \ + "Range error" + #define VL53L1_STRING_ERROR_TIME_OUT \ + "Time out error" + #define VL53L1_STRING_ERROR_MODE_NOT_SUPPORTED \ + "Mode not supported error" + #define VL53L1_STRING_ERROR_BUFFER_TOO_SMALL \ + "Buffer too small" + #define VL53L1_STRING_ERROR_COMMS_BUFFER_TOO_SMALL \ + "Comms Buffer too small" + #define VL53L1_STRING_ERROR_GPIO_NOT_EXISTING \ + "GPIO not existing" + #define VL53L1_STRING_ERROR_GPIO_FUNCTIONALITY_NOT_SUPPORTED \ + "GPIO funct not supported" + #define VL53L1_STRING_ERROR_CONTROL_INTERFACE \ + "Control Interface Error" + #define VL53L1_STRING_ERROR_INVALID_COMMAND \ + "Invalid Command Error" + #define VL53L1_STRING_ERROR_DIVISION_BY_ZERO \ + "Division by zero Error" + #define VL53L1_STRING_ERROR_REF_SPAD_INIT \ + "Reference Spad Init Error" + #define VL53L1_STRING_ERROR_GPH_SYNC_CHECK_FAIL \ + "GPH Sync Check Fail - API out of sync" + #define VL53L1_STRING_ERROR_STREAM_COUNT_CHECK_FAIL \ + "Stream Count Check Fail - API out of sync" + #define VL53L1_STRING_ERROR_GPH_ID_CHECK_FAIL \ + "GPH ID Check Fail - API out of sync" + #define VL53L1_STRING_ERROR_ZONE_STREAM_COUNT_CHECK_FAIL \ + "Zone Stream Count Check Fail - API out of sync" + #define VL53L1_STRING_ERROR_ZONE_GPH_ID_CHECK_FAIL \ + "Zone GPH ID Check Fail - API out of sync" + + #define VL53L1_STRING_ERROR_XTALK_EXTRACTION_NO_SAMPLES_FAIL \ + "No Xtalk using full array - Xtalk Extract Fail" + #define VL53L1_STRING_ERROR_XTALK_EXTRACTION_SIGMA_LIMIT_FAIL \ + "Xtalk does not meet required VL53L1_p_011 limit - Xtalk Extract Fail" + + #define VL53L1_STRING_ERROR_OFFSET_CAL_NO_SAMPLE_FAIL \ + "Offset Cal - one of more stages with no valid samples - fatal" + #define VL53L1_STRING_ERROR_OFFSET_CAL_NO_SPADS_ENABLED_FAIL \ + "Offset Cal - one of more stages with no SPADS enables - fatal" + #define VL53L1_STRING_ERROR_ZONE_CAL_NO_SAMPLE_FAIL \ + "Zone Cal - one of more zones with no valid samples - fatal" + + #define VL53L1_STRING_WARNING_REF_SPAD_CHAR_NOT_ENOUGH_SPADS \ + "Ref SPAD Char - Not Enough Good SPADs" + #define VL53L1_STRING_WARNING_REF_SPAD_CHAR_RATE_TOO_HIGH \ + "Ref SPAD Char - Final Ref Rate too high" + #define VL53L1_STRING_WARNING_REF_SPAD_CHAR_RATE_TOO_LOW \ + "Ref SPAD Char - Final Ref Rate too low" + + #define VL53L1_STRING_WARNING_OFFSET_CAL_MISSING_SAMPLES \ + "Offset Cal - Less than the requested number of valid samples" + #define VL53L1_STRING_WARNING_OFFSET_CAL_SIGMA_TOO_HIGH \ + "Offset Cal - Sigma estimate value too high - offset not stable" + #define VL53L1_STRING_WARNING_OFFSET_CAL_RATE_TOO_HIGH \ + "Offset Cal - Rate too high - in pile up" + #define VL53L1_STRING_WARNING_OFFSET_CAL_SPAD_COUNT_TOO_LOW \ + "Offset Cal - Insufficient SPADs - offset may not be stable" + + #define VL53L1_STRING_WARNING_ZONE_CAL_MISSING_SAMPLES \ + "Zone Cal - One or more zone with less than requested valid samples" + #define VL53L1_STRING_WARNING_ZONE_CAL_SIGMA_TOO_HIGH \ + "Zone Cal - One of more zones the VL53L1_p_011 estimate too high" + #define VL53L1_STRING_WARNING_ZONE_CAL_RATE_TOO_HIGH \ + "Zone Cal - One of more zones with rate too high - in pile up" + + #define VL53L1_STRING_WARNING_XTALK_NO_SAMPLES_FOR_GRADIENT \ + "Xtalk - Gradient sample num = 0" + #define VL53L1_STRING_WARNING_XTALK_SIGMA_LIMIT_FOR_GRADIENT \ + "Xtalk - Gradient Sigma > Limit" + #define VL53L1_STRING_WARNING_XTALK_MISSING_SAMPLES \ + "Xtalk - Some missing and invalid samples" + + #define VL53L1_STRING_ERROR_DEVICE_FIRMWARE_TOO_OLD \ + "Device Firmware too old" + #define VL53L1_STRING_ERROR_DEVICE_FIRMWARE_TOO_NEW \ + "Device Firmware too new" + #define VL53L1_STRING_ERROR_UNIT_TEST_FAIL \ + "Unit Test Fail" + #define VL53L1_STRING_ERROR_FILE_READ_FAIL \ + "File Read Fail" + #define VL53L1_STRING_ERROR_FILE_WRITE_FAIL \ + "File Write Fail" + + #define VL53L1_STRING_ERROR_NOT_IMPLEMENTED \ + "Not implemented error" + #define VL53L1_STRING_UNKNOW_ERROR_CODE \ + "Unknown Error Code" + +#endif + + + +#ifdef __cplusplus +} +#endif + +#endif + + diff --git a/drivers/input/misc/vl53L1/lito/inc/vl53l1_hist_char.h b/drivers/input/misc/vl53L1/lito/inc/vl53l1_hist_char.h new file mode 100644 index 000000000000..25d84d16240a --- /dev/null +++ b/drivers/input/misc/vl53L1/lito/inc/vl53l1_hist_char.h @@ -0,0 +1,176 @@ + +/******************************************************************************* + * Copyright (c) 2017, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#ifndef _VL53L1_HIST_CHAR_H_ +#define _VL53L1_HIST_CHAR_H_ + +#include "vl53l1_platform.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_calib_config( + VL53L1_DEV Dev, + uint8_t vcsel_delay__a0, + uint8_t calib_1, + uint8_t calib_2, + uint8_t calib_3, + uint8_t calib_2__a0, + uint8_t spad_readout); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_hist_calib_pulse_delay( + VL53L1_DEV Dev, + uint8_t calib_delay); + + + + + + + + + + + + +VL53L1_Error VL53L1_disable_calib_pulse_delay( + VL53L1_DEV Dev); + + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/drivers/input/misc/vl53L1/lito/inc/vl53l1_hist_map.h b/drivers/input/misc/vl53L1/lito/inc/vl53l1_hist_map.h new file mode 100644 index 000000000000..952dd16d6019 --- /dev/null +++ b/drivers/input/misc/vl53L1/lito/inc/vl53l1_hist_map.h @@ -0,0 +1,156 @@ + +/******************************************************************************* + * Copyright (c) 2017, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#ifndef _VL53L1_HIST_MAP_H_ +#define _VL53L1_HIST_MAP_H_ + +#include "vl53l1_register_map.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + + + + + +#define VL53L1_HISTOGRAM_CONFIG__OPCODE_SEQUENCE_0 \ + VL53L1_SIGMA_ESTIMATOR__EFFECTIVE_PULSE_WIDTH_NS + +#define VL53L1_HISTOGRAM_CONFIG__OPCODE_SEQUENCE_1 \ + VL53L1_SIGMA_ESTIMATOR__EFFECTIVE_AMBIENT_WIDTH_NS + +#define VL53L1_HISTOGRAM_CONFIG__OPCODE_SEQUENCE_2 \ + VL53L1_SIGMA_ESTIMATOR__SIGMA_REF_MM + +#define VL53L1_HISTOGRAM_CONFIG__AMB_THRESH_HIGH \ + VL53L1_ALGO__RANGE_IGNORE_THRESHOLD_MCPS + + + + + +#define VL53L1_RESULT__HISTOGRAM_BIN_0_2 0x008E +#define VL53L1_RESULT__HISTOGRAM_BIN_0_1 0x008F +#define VL53L1_RESULT__HISTOGRAM_BIN_0_0 0x0090 + +#define VL53L1_RESULT__HISTOGRAM_BIN_23_2 0x00D3 +#define VL53L1_RESULT__HISTOGRAM_BIN_23_1 0x00D4 +#define VL53L1_RESULT__HISTOGRAM_BIN_23_0 0x00D5 + +#define VL53L1_RESULT__HISTOGRAM_BIN_23_0_MSB 0x00D9 +#define VL53L1_RESULT__HISTOGRAM_BIN_23_0_LSB 0x00DA + + + + +#define VL53L1_HISTOGRAM_BIN_DATA_I2C_INDEX \ + VL53L1_RESULT__INTERRUPT_STATUS +#define VL53L1_HISTOGRAM_BIN_DATA_I2C_SIZE_BYTES \ + (VL53L1_RESULT__HISTOGRAM_BIN_23_0_LSB - \ + VL53L1_RESULT__INTERRUPT_STATUS + 1) + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/drivers/input/misc/vl53L1/lito/inc/vl53l1_hist_structs.h b/drivers/input/misc/vl53L1/lito/inc/vl53l1_hist_structs.h new file mode 100644 index 000000000000..48909e091ec3 --- /dev/null +++ b/drivers/input/misc/vl53L1/lito/inc/vl53l1_hist_structs.h @@ -0,0 +1,515 @@ + +/******************************************************************************* + * Copyright (c) 2017, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#ifndef _VL53L1_HIST_STRUCTS_H_ +#define _VL53L1_HIST_STRUCTS_H_ + +#include "vl53l1_ll_device.h" +#include "vl53l1_dmax_structs.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +#define VL53L1_MAX_BIN_SEQUENCE_LENGTH 6 +#define VL53L1_MAX_BIN_SEQUENCE_CODE 15 +#define VL53L1_HISTOGRAM_BUFFER_SIZE 24 +#define VL53L1_XTALK_HISTO_BINS 12 + + + + + + + + +typedef struct { + + uint8_t histogram_config__spad_array_selection; + + uint8_t histogram_config__low_amb_even_bin_0_1; + uint8_t histogram_config__low_amb_even_bin_2_3; + uint8_t histogram_config__low_amb_even_bin_4_5; + + uint8_t histogram_config__low_amb_odd_bin_0_1; + uint8_t histogram_config__low_amb_odd_bin_2_3; + uint8_t histogram_config__low_amb_odd_bin_4_5; + + uint8_t histogram_config__mid_amb_even_bin_0_1; + uint8_t histogram_config__mid_amb_even_bin_2_3; + uint8_t histogram_config__mid_amb_even_bin_4_5; + + uint8_t histogram_config__mid_amb_odd_bin_0_1; + uint8_t histogram_config__mid_amb_odd_bin_2; + uint8_t histogram_config__mid_amb_odd_bin_3_4; + uint8_t histogram_config__mid_amb_odd_bin_5; + + uint8_t histogram_config__user_bin_offset; + + uint8_t histogram_config__high_amb_even_bin_0_1; + uint8_t histogram_config__high_amb_even_bin_2_3; + uint8_t histogram_config__high_amb_even_bin_4_5; + + uint8_t histogram_config__high_amb_odd_bin_0_1; + uint8_t histogram_config__high_amb_odd_bin_2_3; + uint8_t histogram_config__high_amb_odd_bin_4_5; + + uint16_t histogram_config__amb_thresh_low; + + + + uint16_t histogram_config__amb_thresh_high; + + + + +} VL53L1_histogram_config_t; + + + + + + + + + +typedef struct { + + VL53L1_HistAlgoSelect hist_algo_select; + + + + VL53L1_HistTargetOrder hist_target_order; + + + + + + uint8_t filter_woi0; + + + + uint8_t filter_woi1; + + + + + VL53L1_HistAmbEstMethod hist_amb_est_method; + + + uint8_t ambient_thresh_sigma0; + + + + uint8_t ambient_thresh_sigma1; + + + + + + uint16_t ambient_thresh_events_scaler; + + + + + + + int32_t min_ambient_thresh_events; + + + uint16_t noise_threshold; + + + + int32_t signal_total_events_limit; + + + uint8_t sigma_estimator__sigma_ref_mm; + + + uint16_t sigma_thresh; + + + int16_t range_offset_mm; + + + uint16_t gain_factor; + + + + uint8_t valid_phase_low; + + + + uint8_t valid_phase_high; + + + + uint8_t algo__consistency_check__phase_tolerance; + + + + uint8_t algo__consistency_check__event_sigma; + + + + + + + uint16_t algo__consistency_check__event_min_spad_count; + + + + + + + uint16_t algo__consistency_check__min_max_tolerance; + + + + uint8_t algo__crosstalk_compensation_enable; + + + uint32_t algo__crosstalk_compensation_plane_offset_kcps; + + + int16_t algo__crosstalk_compensation_x_plane_gradient_kcps; + + + int16_t algo__crosstalk_compensation_y_plane_gradient_kcps; + + + + int16_t algo__crosstalk_detect_min_valid_range_mm; + + + int16_t algo__crosstalk_detect_max_valid_range_mm; + + + uint16_t algo__crosstalk_detect_max_valid_rate_kcps; + + + + uint16_t algo__crosstalk_detect_max_sigma_mm; + + + + + + + uint8_t algo__crosstalk_detect_event_sigma; + + + + + + + uint16_t algo__crosstalk_detect_min_max_tolerance; + + + + +} VL53L1_hist_post_process_config_t; + + + + + + + +typedef struct { + + + + VL53L1_DeviceState cfg_device_state; + + + VL53L1_DeviceState rd_device_state; + + + + uint8_t zone_id; + + + uint32_t time_stamp; + + + + uint8_t VL53L1_p_022; + + + uint8_t VL53L1_p_023; + + + uint8_t VL53L1_p_024; + + + + uint8_t number_of_ambient_bins; + + + + uint8_t bin_seq[VL53L1_MAX_BIN_SEQUENCE_LENGTH]; + + + uint8_t bin_rep[VL53L1_MAX_BIN_SEQUENCE_LENGTH]; + + + + + int32_t bin_data[VL53L1_HISTOGRAM_BUFFER_SIZE]; + + + + uint8_t result__interrupt_status; + + + uint8_t result__range_status; + + + uint8_t result__report_status; + + + uint8_t result__stream_count; + + + uint16_t result__dss_actual_effective_spads; + + + + uint16_t phasecal_result__reference_phase; + + + uint8_t phasecal_result__vcsel_start; + + + uint8_t cal_config__vcsel_start; + + + uint16_t vcsel_width; + + + uint8_t VL53L1_p_009; + + + uint16_t VL53L1_p_019; + + + uint32_t total_periods_elapsed; + + + + uint32_t peak_duration_us; + + + uint32_t woi_duration_us; + + + + int32_t min_bin_value; + + + int32_t max_bin_value; + + + + uint16_t zero_distance_phase; + + + uint8_t number_of_ambient_samples; + + + int32_t ambient_events_sum; + + + int32_t VL53L1_p_004; + + + + uint8_t roi_config__user_roi_centre_spad; + + + uint8_t roi_config__user_roi_requested_global_xy_size; + + + +} VL53L1_histogram_bin_data_t; + + + + + + + + +typedef struct { + + + + uint8_t zone_id; + + + uint32_t time_stamp; + + + + uint8_t VL53L1_p_022; + + + uint8_t VL53L1_p_023; + + + uint8_t VL53L1_p_024; + + + uint32_t bin_data[VL53L1_XTALK_HISTO_BINS]; + + + + + uint16_t phasecal_result__reference_phase; + + + uint8_t phasecal_result__vcsel_start; + + + uint8_t cal_config__vcsel_start; + + + uint16_t vcsel_width; + + + uint16_t VL53L1_p_019; + + + uint16_t zero_distance_phase; + + + +} VL53L1_xtalk_histogram_shape_t; + + + + + + + + +typedef struct { + + + + VL53L1_xtalk_histogram_shape_t xtalk_shape; + + + VL53L1_histogram_bin_data_t xtalk_hist_removed; + +} VL53L1_xtalk_histogram_data_t; + + + + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/drivers/input/misc/vl53L1/lito/inc/vl53l1_ll_def.h b/drivers/input/misc/vl53L1/lito/inc/vl53l1_ll_def.h new file mode 100644 index 000000000000..85ba193c8341 --- /dev/null +++ b/drivers/input/misc/vl53L1/lito/inc/vl53l1_ll_def.h @@ -0,0 +1,2715 @@ + +/******************************************************************************* + * Copyright (c) 2017, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#ifndef _VL53L1_LL_DEF_H_ +#define _VL53L1_LL_DEF_H_ + +#include "vl53l1_error_codes.h" +#include "vl53l1_register_structs.h" +#include "vl53l1_platform_user_config.h" +#include "vl53l1_platform_user_defines.h" +#include "vl53l1_hist_structs.h" +#include "vl53l1_dmax_structs.h" +#include "vl53l1_error_exceptions.h" + +#ifdef __cplusplus +extern "C" { +#endif + + + + + + + + + +#define VL53L1_LL_API_IMPLEMENTATION_VER_MAJOR 1 + + +#define VL53L1_LL_API_IMPLEMENTATION_VER_MINOR 1 + + +#define VL53L1_LL_API_IMPLEMENTATION_VER_SUB 46 + + +#define VL53L1_LL_API_IMPLEMENTATION_VER_REVISION 12207 + +#define VL53L1_LL_API_IMPLEMENTATION_VER_STRING "1.1.46p2" + + + +#define VL53L1_FIRMWARE_VER_MINIMUM 398 +#define VL53L1_FIRMWARE_VER_MAXIMUM 400 + + + + + + + +#define VL53L1_LL_CALIBRATION_DATA_STRUCT_VERSION 0xECAB0102 + + + + + + +#define VL53L1_LL_ZONE_CALIBRATION_DATA_STRUCT_VERSION 0xECAE0101 + + + + + + +#define VL53L1_MAX_XTALK_RANGE_RESULTS 5 + + + + + + +#define VL53L1_MAX_OFFSET_RANGE_RESULTS 3 + + + + + +#define VL53L1_NVM_MAX_FMT_RANGE_DATA 4 + + + +#define VL53L1_NVM_PEAK_RATE_MAP_SAMPLES 25 + + +#define VL53L1_NVM_PEAK_RATE_MAP_WIDTH 5 + + +#define VL53L1_NVM_PEAK_RATE_MAP_HEIGHT 5 + + + + + + + + + +#define VL53L1_ERROR_DEVICE_FIRMWARE_TOO_OLD ((VL53L1_Error) - 80) + + +#define VL53L1_ERROR_DEVICE_FIRMWARE_TOO_NEW ((VL53L1_Error) - 85) + + +#define VL53L1_ERROR_UNIT_TEST_FAIL ((VL53L1_Error) - 90) + + +#define VL53L1_ERROR_FILE_READ_FAIL ((VL53L1_Error) - 95) + + +#define VL53L1_ERROR_FILE_WRITE_FAIL ((VL53L1_Error) - 96) + + + + + + + + + + + + +typedef struct { + uint32_t ll_revision; + + uint8_t ll_major; + + uint8_t ll_minor; + + uint8_t ll_build; + +} VL53L1_ll_version_t; + + + + + + +typedef struct { + + uint8_t device_test_mode; + + uint8_t VL53L1_p_009; + + uint32_t timeout_us; + + uint16_t target_count_rate_mcps; + + + uint16_t min_count_rate_limit_mcps; + + + uint16_t max_count_rate_limit_mcps; + + + +} VL53L1_refspadchar_config_t; + + + + + + +typedef struct { + + uint16_t dss_config__target_total_rate_mcps; + + + uint32_t phasecal_config_timeout_us; + + + uint32_t mm_config_timeout_us; + + + uint32_t range_config_timeout_us; + + + uint8_t num_of_samples; + + + int16_t algo__crosstalk_extract_min_valid_range_mm; + + + int16_t algo__crosstalk_extract_max_valid_range_mm; + + + uint16_t algo__crosstalk_extract_max_valid_rate_kcps; + + + + uint16_t algo__crosstalk_extract_max_sigma_mm; + + + + + +} VL53L1_xtalkextract_config_t; + + + + + + +typedef struct { + + uint16_t dss_config__target_total_rate_mcps; + + + + uint32_t phasecal_config_timeout_us; + + + + uint32_t range_config_timeout_us; + + + + uint32_t mm_config_timeout_us; + + + + + uint8_t pre_num_of_samples; + + + + uint8_t mm1_num_of_samples; + + + + uint8_t mm2_num_of_samples; + + + + +} VL53L1_offsetcal_config_t; + + + + + + +typedef struct { + + uint16_t dss_config__target_total_rate_mcps; + + + + uint32_t phasecal_config_timeout_us; + + + + uint32_t mm_config_timeout_us; + + + + uint32_t range_config_timeout_us; + + + + uint16_t phasecal_num_of_samples; + + + + uint16_t zone_num_of_samples; + + + + +} VL53L1_zonecal_config_t; + + + + + + + +typedef struct { + + VL53L1_DeviceSscArray array_select; + + + + + uint8_t VL53L1_p_009; + + + uint8_t vcsel_start; + + + uint8_t vcsel_width; + + + uint32_t timeout_us; + + + uint16_t rate_limit_mcps; + + + + + +} VL53L1_ssc_config_t; + + + + + + +typedef struct { + + + uint32_t algo__crosstalk_compensation_plane_offset_kcps; + + + int16_t algo__crosstalk_compensation_x_plane_gradient_kcps; + + + int16_t algo__crosstalk_compensation_y_plane_gradient_kcps; + + + uint32_t nvm_default__crosstalk_compensation_plane_offset_kcps; + + + int16_t nvm_default__crosstalk_compensation_x_plane_gradient_kcps; + + + int16_t nvm_default__crosstalk_compensation_y_plane_gradient_kcps; + + + uint8_t global_crosstalk_compensation_enable; + + + int16_t histogram_mode_crosstalk_margin_kcps; + + + + + + + int16_t lite_mode_crosstalk_margin_kcps; + + + + + + + uint8_t crosstalk_range_ignore_threshold_mult; + + + uint16_t crosstalk_range_ignore_threshold_rate_mcps; + + + + + int16_t algo__crosstalk_detect_min_valid_range_mm; + + + int16_t algo__crosstalk_detect_max_valid_range_mm; + + + uint16_t algo__crosstalk_detect_max_valid_rate_kcps; + + + + uint16_t algo__crosstalk_detect_max_sigma_mm; + + + + + + +} VL53L1_xtalk_config_t; + + + + + + + + + + + + +typedef struct { + + + uint16_t tp_tuning_parm_version; + + + + uint16_t tp_tuning_parm_key_table_version; + + + + + uint16_t tp_tuning_parm_lld_version; + + + + + uint8_t tp_init_phase_rtn_lite_long; + + + + + uint8_t tp_init_phase_rtn_lite_med; + + + + + uint8_t tp_init_phase_rtn_lite_short; + + + + + uint8_t tp_init_phase_ref_lite_long; + + + + + uint8_t tp_init_phase_ref_lite_med; + + + + + uint8_t tp_init_phase_ref_lite_short; + + + + + + uint8_t tp_init_phase_rtn_hist_long; + + + + + uint8_t tp_init_phase_rtn_hist_med; + + + + + uint8_t tp_init_phase_rtn_hist_short; + + + + + uint8_t tp_init_phase_ref_hist_long; + + + + + uint8_t tp_init_phase_ref_hist_med; + + + + + uint8_t tp_init_phase_ref_hist_short; + + + + + + uint8_t tp_consistency_lite_phase_tolerance; + + + + + uint8_t tp_phasecal_target; + + + + + uint16_t tp_cal_repeat_rate; + + + + + uint8_t tp_lite_min_clip; + + + + + + uint16_t tp_lite_long_sigma_thresh_mm; + + + + + uint16_t tp_lite_med_sigma_thresh_mm; + + + + + uint16_t tp_lite_short_sigma_thresh_mm; + + + + + + uint16_t tp_lite_long_min_count_rate_rtn_mcps; + + + + + uint16_t tp_lite_med_min_count_rate_rtn_mcps; + + + + + uint16_t tp_lite_short_min_count_rate_rtn_mcps; + + + + + + uint8_t tp_lite_sigma_est_pulse_width_ns; + + + + uint8_t tp_lite_sigma_est_amb_width_ns; + + + + uint8_t tp_lite_sigma_ref_mm; + + + + uint8_t tp_lite_seed_cfg; + + + + uint8_t tp_timed_seed_cfg; + + + + + uint8_t tp_lite_quantifier; + + + + uint8_t tp_lite_first_order_select; + + + + + uint16_t tp_dss_target_lite_mcps; + + + + uint16_t tp_dss_target_histo_mcps; + + + + uint16_t tp_dss_target_histo_mz_mcps; + + + + uint16_t tp_dss_target_timed_mcps; + + + + uint16_t tp_dss_target_very_short_mcps; + + + + + uint32_t tp_phasecal_timeout_lite_us; + + + + uint32_t tp_phasecal_timeout_hist_long_us; + + + + uint32_t tp_phasecal_timeout_hist_med_us; + + + + uint32_t tp_phasecal_timeout_hist_short_us; + + + + + uint32_t tp_phasecal_timeout_mz_long_us; + + + + uint32_t tp_phasecal_timeout_mz_med_us; + + + + uint32_t tp_phasecal_timeout_mz_short_us; + + + + uint32_t tp_phasecal_timeout_timed_us; + + + + + uint32_t tp_mm_timeout_lite_us; + + + + uint32_t tp_mm_timeout_histo_us; + + + + uint32_t tp_mm_timeout_mz_us; + + + + uint32_t tp_mm_timeout_timed_us; + + + + uint32_t tp_mm_timeout_lpa_us; + + + + + uint32_t tp_range_timeout_lite_us; + + + + uint32_t tp_range_timeout_histo_us; + + + + uint32_t tp_range_timeout_mz_us; + + + + uint32_t tp_range_timeout_timed_us; + + + + uint32_t tp_range_timeout_lpa_us; + + + + +} VL53L1_tuning_parm_storage_t; + + + + + + + + +typedef struct { + + uint8_t x_centre; + + uint8_t y_centre; + + +} VL53L1_optical_centre_t; + + + + + + + +typedef struct { + + uint8_t x_centre; + + uint8_t y_centre; + + uint8_t width; + + uint8_t height; + + +} VL53L1_user_zone_t; + + + + + + + + + +typedef struct { + + uint8_t max_zones; + + uint8_t active_zones; + + + + + + + + + +VL53L1_histogram_config_t multizone_hist_cfg; + + VL53L1_user_zone_t user_zones[VL53L1_MAX_USER_ZONES]; + + + + uint8_t bin_config[VL53L1_MAX_USER_ZONES]; + + + +} VL53L1_zone_config_t; + + + + + + + + + +typedef struct { + + + + VL53L1_GPIO_Interrupt_Mode intr_mode_distance; + + + + VL53L1_GPIO_Interrupt_Mode intr_mode_rate; + + + + + + uint8_t intr_new_measure_ready; + + + + uint8_t intr_no_target; + + + + + + + uint8_t intr_combined_mode; + + + + + + + + + + + uint16_t threshold_distance_high; + + + + uint16_t threshold_distance_low; + + + + uint16_t threshold_rate_high; + + + + uint16_t threshold_rate_low; + +} VL53L1_GPIO_interrupt_config_t; + + + + + + + + + + + + +typedef struct { + + + + + + + uint8_t vhv_loop_bound; + + + + uint8_t is_low_power_auto_mode; + + + + + uint8_t low_power_auto_range_count; + + + + uint8_t saved_interrupt_config; + + + + uint8_t saved_vhv_init; + + + + uint8_t saved_vhv_timeout; + + + + uint8_t first_run_phasecal_result; + + + + uint32_t dss__total_rate_per_spad_mcps; + + + + uint16_t dss__required_spads; + +} VL53L1_low_power_auto_data_t; + + + + + + + + + + + + + + + +typedef struct { + + + + uint8_t smudge_corr_enabled; + + + + uint8_t smudge_corr_apply_enabled; + + + + uint8_t smudge_corr_single_apply; + + + + + + + uint16_t smudge_margin; + + + + uint32_t noise_margin; + + + + + uint32_t user_xtalk_offset_limit; + + + + + uint8_t user_xtalk_offset_limit_hi; + + + + + uint32_t sample_limit; + + + + + uint32_t single_xtalk_delta; + + + + + uint32_t averaged_xtalk_delta; + + + + + uint32_t smudge_corr_clip_limit; + + + + + uint32_t smudge_corr_ambient_threshold; + + + + + + + + + + + + + + + uint8_t scaler_calc_method; + + + + + + + int16_t x_gradient_scaler; + + + + + + + int16_t y_gradient_scaler; + + + + + + + uint8_t user_scaler_set; + + + + + uint32_t nodetect_ambient_threshold; + + + + + uint32_t nodetect_sample_limit; + + + + + uint32_t nodetect_xtalk_offset; + + + + + uint16_t nodetect_min_range_mm; + + +} VL53L1_smudge_corrector_config_t; + + + + + + + + + +typedef struct { + + + + uint32_t current_samples; + + + + uint32_t required_samples; + + + + uint64_t accumulator; + + + + uint32_t nodetect_counter; + +} VL53L1_smudge_corrector_internals_t; + + + + + + + + + +typedef struct { + + + + + + + + + uint8_t smudge_corr_valid; + + + + uint8_t smudge_corr_clipped; + + + + + + + + + uint8_t single_xtalk_delta_flag; + + + + + + + + + uint8_t averaged_xtalk_delta_flag; + + + + uint8_t sample_limit_exceeded_flag; + + + + + + + uint8_t gradient_zero_flag; + + + + uint8_t new_xtalk_applied_flag; + + + + uint32_t algo__crosstalk_compensation_plane_offset_kcps; + + + + int16_t algo__crosstalk_compensation_x_plane_gradient_kcps; + + + + int16_t algo__crosstalk_compensation_y_plane_gradient_kcps; + + +} VL53L1_smudge_corrector_data_t; + + + + + + + + + + + +typedef struct { + + + + + uint8_t range_id; + + + uint32_t time_stamp; + + + uint8_t VL53L1_p_015; + + + uint8_t VL53L1_p_022; + + + uint8_t VL53L1_p_025; + + + uint8_t VL53L1_p_026; + + + uint8_t VL53L1_p_016; + + + uint8_t VL53L1_p_027; + + + + uint16_t width; + + + uint8_t VL53L1_p_030; + + + + + uint16_t fast_osc_frequency; + + + uint16_t zero_distance_phase; + + + uint16_t VL53L1_p_006; + + + + uint32_t total_periods_elapsed; + + + + uint32_t peak_duration_us; + + + + uint32_t woi_duration_us; + + + + + + + + uint32_t VL53L1_p_020; + + + uint32_t VL53L1_p_021; + + + + int32_t VL53L1_p_013; + + + + + + + + uint16_t peak_signal_count_rate_mcps; + + + uint16_t avg_signal_count_rate_mcps; + + + uint16_t ambient_count_rate_mcps; + + + uint16_t total_rate_per_spad_mcps; + + + uint32_t VL53L1_p_012; + + + + + + + uint16_t VL53L1_p_005; + + + + + + + uint16_t VL53L1_p_028; + + + + uint16_t VL53L1_p_014; + + + uint16_t VL53L1_p_029; + + + + + + + + int16_t min_range_mm; + + + + + + int16_t median_range_mm; + + + + + int16_t max_range_mm; + + + + + + + + + + uint8_t range_status; + +} VL53L1_range_data_t; + + + + + + + + + + +typedef struct { + + VL53L1_DeviceState cfg_device_state; + + + VL53L1_DeviceState rd_device_state; + + + uint8_t zone_id; + + + uint8_t stream_count; + + + + int16_t VL53L1_p_007[VL53L1_MAX_AMBIENT_DMAX_VALUES]; + + + + + int16_t wrap_dmax_mm; + + + + uint8_t device_status; + + + + uint8_t max_results; + + + + uint8_t active_results; + + + VL53L1_range_data_t VL53L1_p_002[VL53L1_MAX_RANGE_RESULTS]; + + + VL53L1_range_data_t xmonitor; + + + VL53L1_smudge_corrector_data_t smudge_corrector_data; + + + + +} VL53L1_range_results_t; + + + + + + + + + + +typedef struct { + + uint8_t no_of_samples; + + + uint32_t rate_per_spad_kcps_sum; + + + + uint32_t rate_per_spad_kcps_avg; + + + int32_t signal_total_events_sum; + + + + int32_t signal_total_events_avg; + + + + uint32_t sigma_mm_sum; + + + + uint32_t sigma_mm_avg; + + + uint32_t median_phase_sum; + + + + + uint32_t median_phase_avg; + + + + +} VL53L1_xtalk_range_data_t; + + + + + + + + + + +typedef struct { + + VL53L1_Error cal_status; + + + uint8_t num_of_samples_status; + + + + + + + + + uint8_t zero_samples_status; + + + + + + + + + uint8_t max_sigma_status; + + + + + + + + + + + + + + + + + + + uint8_t max_results; + + + + uint8_t active_results; + + + + VL53L1_xtalk_range_data_t + VL53L1_p_002[VL53L1_MAX_XTALK_RANGE_RESULTS]; + + + VL53L1_histogram_bin_data_t central_histogram_sum; + + + + VL53L1_histogram_bin_data_t central_histogram_avg; + + + + uint8_t central_histogram__window_start; + + + + uint8_t central_histogram__window_end; + + + + VL53L1_histogram_bin_data_t + histogram_avg_1[VL53L1_MAX_XTALK_RANGE_RESULTS]; + + + + VL53L1_histogram_bin_data_t + histogram_avg_2[VL53L1_MAX_XTALK_RANGE_RESULTS]; + + + + VL53L1_histogram_bin_data_t + xtalk_avg[VL53L1_MAX_XTALK_RANGE_RESULTS]; + + + + +} VL53L1_xtalk_range_results_t; + + + + + + + + + + + +typedef struct { + + uint8_t preset_mode; + + + uint8_t dss_config__roi_mode_control; + + + uint16_t dss_config__manual_effective_spads_select; + + + uint8_t no_of_samples; + + + uint32_t effective_spads; + + + uint32_t peak_rate_mcps; + + + uint32_t VL53L1_p_005; + + + int32_t median_range_mm; + + + + int32_t range_mm_offset; + + + +} VL53L1_offset_range_data_t; + + + + + + + + + + +typedef struct { + + int16_t cal_distance_mm; + + + uint16_t cal_reflectance_pc; + + + VL53L1_Error cal_status; + + + uint8_t cal_report; + + + uint8_t max_results; + + + + uint8_t active_results; + + + VL53L1_offset_range_data_t + VL53L1_p_002[VL53L1_MAX_OFFSET_RANGE_RESULTS]; + + + +} VL53L1_offset_range_results_t; + + + + + + + + + + + + +typedef struct { + + uint16_t result__mm_inner_actual_effective_spads; + + + uint16_t result__mm_outer_actual_effective_spads; + + + uint16_t result__mm_inner_peak_signal_count_rtn_mcps; + + + uint16_t result__mm_outer_peak_signal_count_rtn_mcps; + + + +} VL53L1_additional_offset_cal_data_t; + + + + + + + + + + + + + +typedef struct { + + uint32_t VL53L1_p_020; + + + uint32_t VL53L1_p_021; + + + + uint16_t VL53L1_p_014; + + + uint8_t range_status; + + + +} VL53L1_object_data_t; + + + + + + + + + + +typedef struct { + + VL53L1_DeviceState cfg_device_state; + + + VL53L1_DeviceState rd_device_state; + + + uint8_t zone_id; + + + uint8_t stream_count; + + + uint8_t max_objects; + + + + uint8_t active_objects; + + + VL53L1_object_data_t VL53L1_p_002[VL53L1_MAX_RANGE_RESULTS]; + + + + VL53L1_object_data_t xmonitor; + + + +} VL53L1_zone_objects_t; + + + + + + + + + + + + + +typedef struct { + + uint8_t max_zones; + + + + uint8_t active_zones; + + + VL53L1_zone_objects_t VL53L1_p_002[VL53L1_MAX_USER_ZONES]; + + + +} VL53L1_zone_results_t; + + + + + + + + + +typedef struct { + + VL53L1_DeviceState rd_device_state; + + + + uint8_t number_of_ambient_bins; + + + + + uint16_t result__dss_actual_effective_spads; + + + uint8_t VL53L1_p_009; + + + uint32_t total_periods_elapsed; + + + + int32_t ambient_events_sum; + + + +} VL53L1_zone_hist_info_t; + + + + + + + + + + +typedef struct { + + uint8_t max_zones; + + + + uint8_t active_zones; + + + VL53L1_zone_hist_info_t VL53L1_p_002[VL53L1_MAX_USER_ZONES]; + + + +} VL53L1_zone_histograms_t; + + + + + + + + + +typedef struct { + + uint32_t no_of_samples; + + + uint32_t effective_spads; + + + uint32_t peak_rate_mcps; + + + uint32_t VL53L1_p_014; + + + uint32_t VL53L1_p_005; + + + + int32_t median_range_mm; + + + + int32_t range_mm_offset; + + + +} VL53L1_zone_calibration_data_t; + + + + + + + + + + + +typedef struct { + + uint32_t struct_version; + + + VL53L1_DevicePresetModes preset_mode; + + + VL53L1_DeviceZonePreset zone_preset; + + + int16_t cal_distance_mm; + + + uint16_t cal_reflectance_pc; + + + uint16_t phasecal_result__reference_phase; + + + uint16_t zero_distance_phase; + + + VL53L1_Error cal_status; + + + uint8_t max_zones; + + + + uint8_t active_zones; + + + VL53L1_zone_calibration_data_t VL53L1_p_002[VL53L1_MAX_USER_ZONES]; + + + +} VL53L1_zone_calibration_results_t; + + + + + + + + + + + + + +typedef struct { + + int16_t cal_distance_mm; + + + uint16_t cal_reflectance_pc; + + + uint16_t max_samples; + + + uint16_t width; + + + uint16_t height; + + + uint16_t peak_rate_mcps[VL53L1_NVM_PEAK_RATE_MAP_SAMPLES]; + + + +} VL53L1_cal_peak_rate_map_t; + + + + + + + + + +typedef struct { + + uint8_t expected_stream_count; + + + uint8_t expected_gph_id; + + + uint8_t dss_mode; + + + uint16_t dss_requested_effective_spad_count; + + + + uint8_t seed_cfg; + + + uint8_t initial_phase_seed; + + + + uint8_t roi_config__user_roi_centre_spad; + + + uint8_t roi_config__user_roi_requested_global_xy_size; + + + +} VL53L1_zone_private_dyn_cfg_t; + + + + + + + + + +typedef struct { + + uint8_t max_zones; + + + + uint8_t active_zones; + + + VL53L1_zone_private_dyn_cfg_t VL53L1_p_002[VL53L1_MAX_USER_ZONES]; + + + +} VL53L1_zone_private_dyn_cfgs_t; + + + + + + + + + +typedef struct { + + uint32_t algo__crosstalk_compensation_plane_offset_kcps; + + + int16_t algo__crosstalk_compensation_x_plane_gradient_kcps; + + + int16_t algo__crosstalk_compensation_y_plane_gradient_kcps; + + + +} VL53L1_xtalk_calibration_results_t; + + + + + + + + +typedef struct { + + + + uint32_t sample_count; + + + + uint32_t pll_period_mm; + + + + uint32_t peak_duration_us_sum; + + + + uint32_t effective_spad_count_sum; + + + + uint32_t zero_distance_phase_sum; + + + + uint32_t zero_distance_phase_avg; + + + + int32_t event_scaler_sum; + + + + int32_t event_scaler_avg; + + + + int32_t signal_events_sum; + + + + uint32_t xtalk_rate_kcps_per_spad; + + + + int32_t xtalk_start_phase; + + + + int32_t xtalk_end_phase; + + + + int32_t xtalk_width_phase; + + + + int32_t target_start_phase; + + + + int32_t target_end_phase; + + + + int32_t target_width_phase; + + + + int32_t effective_width; + + + + int32_t event_scaler; + + + + uint8_t VL53L1_p_015; + + + + uint8_t VL53L1_p_016; + + + + uint8_t target_start; + + + + int32_t max_shape_value; + + + + int32_t bin_data_sums[VL53L1_XTALK_HISTO_BINS]; + +} VL53L1_hist_xtalk_extract_data_t; + + + + + + + + + + +typedef struct { + + uint16_t standard_ranging_gain_factor; + + + uint16_t histogram_ranging_gain_factor; + + + +} VL53L1_gain_calibration_data_t; + + + + + + + + + + +typedef struct { + + VL53L1_DeviceState cfg_device_state; + + + uint8_t cfg_stream_count; + + + + uint8_t cfg_internal_stream_count; + + + uint8_t cfg_internal_stream_count_val; + + + uint8_t cfg_gph_id; + + + uint8_t cfg_timing_status; + + + uint8_t cfg_zone_id; + + + + VL53L1_DeviceState rd_device_state; + + + uint8_t rd_stream_count; + + + uint8_t rd_internal_stream_count; + + + uint8_t rd_internal_stream_count_val; + + + uint8_t rd_gph_id; + + + uint8_t rd_timing_status; + + + uint8_t rd_zone_id; + + + +} VL53L1_ll_driver_state_t; + + + + + + + + + + +typedef struct { + + uint8_t wait_method; + + + VL53L1_DevicePresetModes preset_mode; + + + VL53L1_DeviceZonePreset zone_preset; + + + VL53L1_DeviceMeasurementModes measurement_mode; + + + VL53L1_OffsetCalibrationMode offset_calibration_mode; + + + VL53L1_OffsetCorrectionMode offset_correction_mode; + + + VL53L1_DeviceDmaxMode dmax_mode; + + + uint32_t phasecal_config_timeout_us; + + + uint32_t mm_config_timeout_us; + + + uint32_t range_config_timeout_us; + + + uint32_t inter_measurement_period_ms; + + + uint16_t dss_config__target_total_rate_mcps; + + + + uint32_t fw_ready_poll_duration_ms; + + + uint8_t fw_ready; + + + uint8_t debug_mode; + + + + + + VL53L1_ll_version_t version; + + + + VL53L1_ll_driver_state_t ll_state; + + + + VL53L1_GPIO_interrupt_config_t gpio_interrupt_config; + + + + VL53L1_customer_nvm_managed_t customer; + VL53L1_cal_peak_rate_map_t cal_peak_rate_map; + VL53L1_additional_offset_cal_data_t add_off_cal_data; + VL53L1_dmax_calibration_data_t fmt_dmax_cal; + VL53L1_dmax_calibration_data_t cust_dmax_cal; + VL53L1_gain_calibration_data_t gain_cal; + VL53L1_user_zone_t mm_roi; + VL53L1_optical_centre_t optical_centre; + VL53L1_zone_config_t zone_cfg; + + + + VL53L1_tuning_parm_storage_t tuning_parms; + + + + uint8_t rtn_good_spads[VL53L1_RTN_SPAD_BUFFER_SIZE]; + + + + VL53L1_refspadchar_config_t refspadchar; + VL53L1_ssc_config_t ssc_cfg; + VL53L1_hist_post_process_config_t histpostprocess; + VL53L1_hist_gen3_dmax_config_t dmax_cfg; + VL53L1_xtalkextract_config_t xtalk_extract_cfg; + VL53L1_xtalk_config_t xtalk_cfg; + VL53L1_offsetcal_config_t offsetcal_cfg; + VL53L1_zonecal_config_t zonecal_cfg; + + + + VL53L1_static_nvm_managed_t stat_nvm; + VL53L1_histogram_config_t hist_cfg; + VL53L1_static_config_t stat_cfg; + VL53L1_general_config_t gen_cfg; + VL53L1_timing_config_t tim_cfg; + VL53L1_dynamic_config_t dyn_cfg; + VL53L1_system_control_t sys_ctrl; + VL53L1_system_results_t sys_results; + VL53L1_nvm_copy_data_t nvm_copy_data; + + + + VL53L1_histogram_bin_data_t hist_data; + VL53L1_histogram_bin_data_t hist_xtalk; + + + + VL53L1_xtalk_histogram_data_t xtalk_shapes; + VL53L1_xtalk_range_results_t xtalk_results; + VL53L1_xtalk_calibration_results_t xtalk_cal; + VL53L1_hist_xtalk_extract_data_t xtalk_extract; + + + + VL53L1_offset_range_results_t offset_results; + + + + VL53L1_core_results_t core_results; + VL53L1_debug_results_t dbg_results; + + VL53L1_smudge_corrector_config_t smudge_correct_config; + + + VL53L1_smudge_corrector_internals_t smudge_corrector_internals; + + + + + + + + VL53L1_low_power_auto_data_t low_power_auto_data; + + + +#ifdef PAL_EXTENDED + + + VL53L1_patch_results_t patch_results; + VL53L1_shadow_core_results_t shadow_core_results; + VL53L1_shadow_system_results_t shadow_sys_results; + VL53L1_prev_shadow_core_results_t prev_shadow_core_results; + VL53L1_prev_shadow_system_results_t prev_shadow_sys_results; +#endif + +} VL53L1_LLDriverData_t; + + + + + + + + + + +typedef struct { + + + + VL53L1_range_results_t range_results; + + + + VL53L1_zone_private_dyn_cfgs_t zone_dyn_cfgs; + + + + VL53L1_zone_results_t zone_results; + VL53L1_zone_histograms_t zone_hists; + VL53L1_zone_calibration_results_t zone_cal; + +} VL53L1_LLDriverResults_t; + + + + + + + + + + +typedef struct { + + uint32_t struct_version; + VL53L1_customer_nvm_managed_t customer; + VL53L1_dmax_calibration_data_t fmt_dmax_cal; + VL53L1_dmax_calibration_data_t cust_dmax_cal; + VL53L1_additional_offset_cal_data_t add_off_cal_data; + VL53L1_optical_centre_t optical_centre; + VL53L1_xtalk_histogram_data_t xtalkhisto; + VL53L1_gain_calibration_data_t gain_cal; + VL53L1_cal_peak_rate_map_t cal_peak_rate_map; + +} VL53L1_calibration_data_t; + + + + + + + + + + +typedef struct { + + VL53L1_customer_nvm_managed_t customer; + VL53L1_xtalkextract_config_t xtalk_extract_cfg; + VL53L1_xtalk_config_t xtalk_cfg; + VL53L1_histogram_bin_data_t hist_data; + VL53L1_xtalk_histogram_data_t xtalk_shapes; + VL53L1_xtalk_range_results_t xtalk_results; + +} VL53L1_xtalk_debug_data_t; + + + + + + + + + + +typedef struct { + + VL53L1_customer_nvm_managed_t customer; + VL53L1_dmax_calibration_data_t fmt_dmax_cal; + VL53L1_dmax_calibration_data_t cust_dmax_cal; + VL53L1_additional_offset_cal_data_t add_off_cal_data; + VL53L1_offset_range_results_t offset_results; + +} VL53L1_offset_debug_data_t; + + + + + + + + + + +typedef struct { + uint16_t vl53l1_tuningparm_version; + uint16_t vl53l1_tuningparm_key_table_version; + uint16_t vl53l1_tuningparm_lld_version; + uint8_t vl53l1_tuningparm_hist_algo_select; + uint8_t vl53l1_tuningparm_hist_target_order; + uint8_t vl53l1_tuningparm_hist_filter_woi_0; + uint8_t vl53l1_tuningparm_hist_filter_woi_1; + uint8_t vl53l1_tuningparm_hist_amb_est_method; + uint8_t vl53l1_tuningparm_hist_amb_thresh_sigma_0; + uint8_t vl53l1_tuningparm_hist_amb_thresh_sigma_1; + int32_t vl53l1_tuningparm_hist_min_amb_thresh_events; + uint16_t vl53l1_tuningparm_hist_amb_events_scaler; + uint16_t vl53l1_tuningparm_hist_noise_threshold; + int32_t vl53l1_tuningparm_hist_signal_total_events_limit; + uint8_t vl53l1_tuningparm_hist_sigma_est_ref_mm; + uint16_t vl53l1_tuningparm_hist_sigma_thresh_mm; + uint16_t vl53l1_tuningparm_hist_gain_factor; + uint8_t vl53l1_tuningparm_consistency_hist_phase_tolerance; + uint16_t vl53l1_tuningparm_consistency_hist_min_max_tolerance_mm; + uint8_t vl53l1_tuningparm_consistency_hist_event_sigma; + uint16_t vl53l1_tuningparm_consistency_hist_event_sigma_min_spad_limit; + uint8_t vl53l1_tuningparm_initial_phase_rtn_histo_long_range; + uint8_t vl53l1_tuningparm_initial_phase_rtn_histo_med_range; + uint8_t vl53l1_tuningparm_initial_phase_rtn_histo_short_range; + uint8_t vl53l1_tuningparm_initial_phase_ref_histo_long_range; + uint8_t vl53l1_tuningparm_initial_phase_ref_histo_med_range; + uint8_t vl53l1_tuningparm_initial_phase_ref_histo_short_range; + int16_t vl53l1_tuningparm_xtalk_detect_min_valid_range_mm; + int16_t vl53l1_tuningparm_xtalk_detect_max_valid_range_mm; + uint16_t vl53l1_tuningparm_xtalk_detect_max_sigma_mm; + uint16_t vl53l1_tuningparm_xtalk_detect_min_max_tolerance; + uint16_t vl53l1_tuningparm_xtalk_detect_max_valid_rate_kcps; + uint8_t vl53l1_tuningparm_xtalk_detect_event_sigma; + int16_t vl53l1_tuningparm_hist_xtalk_margin_kcps; + uint8_t vl53l1_tuningparm_consistency_lite_phase_tolerance; + uint8_t vl53l1_tuningparm_phasecal_target; + uint16_t vl53l1_tuningparm_lite_cal_repeat_rate; + uint16_t vl53l1_tuningparm_lite_ranging_gain_factor; + uint8_t vl53l1_tuningparm_lite_min_clip_mm; + uint16_t vl53l1_tuningparm_lite_long_sigma_thresh_mm; + uint16_t vl53l1_tuningparm_lite_med_sigma_thresh_mm; + uint16_t vl53l1_tuningparm_lite_short_sigma_thresh_mm; + uint16_t vl53l1_tuningparm_lite_long_min_count_rate_rtn_mcps; + uint16_t vl53l1_tuningparm_lite_med_min_count_rate_rtn_mcps; + uint16_t vl53l1_tuningparm_lite_short_min_count_rate_rtn_mcps; + uint8_t vl53l1_tuningparm_lite_sigma_est_pulse_width; + uint8_t vl53l1_tuningparm_lite_sigma_est_amb_width_ns; + uint8_t vl53l1_tuningparm_lite_sigma_ref_mm; + uint8_t vl53l1_tuningparm_lite_rit_mult; + uint8_t vl53l1_tuningparm_lite_seed_config; + uint8_t vl53l1_tuningparm_lite_quantifier; + uint8_t vl53l1_tuningparm_lite_first_order_select; + int16_t vl53l1_tuningparm_lite_xtalk_margin_kcps; + uint8_t vl53l1_tuningparm_initial_phase_rtn_lite_long_range; + uint8_t vl53l1_tuningparm_initial_phase_rtn_lite_med_range; + uint8_t vl53l1_tuningparm_initial_phase_rtn_lite_short_range; + uint8_t vl53l1_tuningparm_initial_phase_ref_lite_long_range; + uint8_t vl53l1_tuningparm_initial_phase_ref_lite_med_range; + uint8_t vl53l1_tuningparm_initial_phase_ref_lite_short_range; + uint8_t vl53l1_tuningparm_timed_seed_config; + uint8_t vl53l1_tuningparm_dmax_cfg_signal_thresh_sigma; + uint16_t vl53l1_tuningparm_dmax_cfg_reflectance_array_0; + uint16_t vl53l1_tuningparm_dmax_cfg_reflectance_array_1; + uint16_t vl53l1_tuningparm_dmax_cfg_reflectance_array_2; + uint16_t vl53l1_tuningparm_dmax_cfg_reflectance_array_3; + uint16_t vl53l1_tuningparm_dmax_cfg_reflectance_array_4; + uint8_t vl53l1_tuningparm_vhv_loopbound; + uint8_t vl53l1_tuningparm_refspadchar_device_test_mode; + uint8_t vl53l1_tuningparm_refspadchar_vcsel_period; + uint32_t vl53l1_tuningparm_refspadchar_phasecal_timeout_us; + uint16_t vl53l1_tuningparm_refspadchar_target_count_rate_mcps; + uint16_t vl53l1_tuningparm_refspadchar_min_countrate_limit_mcps; + uint16_t vl53l1_tuningparm_refspadchar_max_countrate_limit_mcps; + uint8_t vl53l1_tuningparm_xtalk_extract_num_of_samples; + int16_t vl53l1_tuningparm_xtalk_extract_min_filter_thresh_mm; + int16_t vl53l1_tuningparm_xtalk_extract_max_filter_thresh_mm; + uint16_t vl53l1_tuningparm_xtalk_extract_dss_rate_mcps; + uint32_t vl53l1_tuningparm_xtalk_extract_phasecal_timeout_us; + uint16_t vl53l1_tuningparm_xtalk_extract_max_valid_rate_kcps; + uint16_t vl53l1_tuningparm_xtalk_extract_sigma_threshold_mm; + uint32_t vl53l1_tuningparm_xtalk_extract_dss_timeout_us; + uint32_t vl53l1_tuningparm_xtalk_extract_bin_timeout_us; + uint16_t vl53l1_tuningparm_offset_cal_dss_rate_mcps; + uint32_t vl53l1_tuningparm_offset_cal_phasecal_timeout_us; + uint32_t vl53l1_tuningparm_offset_cal_mm_timeout_us; + uint32_t vl53l1_tuningparm_offset_cal_range_timeout_us; + uint8_t vl53l1_tuningparm_offset_cal_pre_samples; + uint8_t vl53l1_tuningparm_offset_cal_mm1_samples; + uint8_t vl53l1_tuningparm_offset_cal_mm2_samples; + uint16_t vl53l1_tuningparm_zone_cal_dss_rate_mcps; + uint32_t vl53l1_tuningparm_zone_cal_phasecal_timeout_us; + uint32_t vl53l1_tuningparm_zone_cal_dss_timeout_us; + uint16_t vl53l1_tuningparm_zone_cal_phasecal_num_samples; + uint32_t vl53l1_tuningparm_zone_cal_range_timeout_us; + uint16_t vl53l1_tuningparm_zone_cal_zone_num_samples; + uint8_t vl53l1_tuningparm_spadmap_vcsel_period; + uint8_t vl53l1_tuningparm_spadmap_vcsel_start; + uint16_t vl53l1_tuningparm_spadmap_rate_limit_mcps; + uint16_t vl53l1_tuningparm_lite_dss_config_target_total_rate_mcps; + uint16_t vl53l1_tuningparm_ranging_dss_config_target_total_rate_mcps; + uint16_t vl53l1_tuningparm_mz_dss_config_target_total_rate_mcps; + uint16_t vl53l1_tuningparm_timed_dss_config_target_total_rate_mcps; + uint32_t vl53l1_tuningparm_lite_phasecal_config_timeout_us; + uint32_t vl53l1_tuningparm_ranging_long_phasecal_config_timeout_us; + uint32_t vl53l1_tuningparm_ranging_med_phasecal_config_timeout_us; + uint32_t vl53l1_tuningparm_ranging_short_phasecal_config_timeout_us; + uint32_t vl53l1_tuningparm_mz_long_phasecal_config_timeout_us; + uint32_t vl53l1_tuningparm_mz_med_phasecal_config_timeout_us; + uint32_t vl53l1_tuningparm_mz_short_phasecal_config_timeout_us; + uint32_t vl53l1_tuningparm_timed_phasecal_config_timeout_us; + uint32_t vl53l1_tuningparm_lite_mm_config_timeout_us; + uint32_t vl53l1_tuningparm_ranging_mm_config_timeout_us; + uint32_t vl53l1_tuningparm_mz_mm_config_timeout_us; + uint32_t vl53l1_tuningparm_timed_mm_config_timeout_us; + uint32_t vl53l1_tuningparm_lite_range_config_timeout_us; + uint32_t vl53l1_tuningparm_ranging_range_config_timeout_us; + uint32_t vl53l1_tuningparm_mz_range_config_timeout_us; + uint32_t vl53l1_tuningparm_timed_range_config_timeout_us; + uint16_t vl53l1_tuningparm_dynxtalk_smudge_margin; + uint32_t vl53l1_tuningparm_dynxtalk_noise_margin; + uint32_t vl53l1_tuningparm_dynxtalk_xtalk_offset_limit; + uint8_t vl53l1_tuningparm_dynxtalk_xtalk_offset_limit_hi; + uint32_t vl53l1_tuningparm_dynxtalk_sample_limit; + uint32_t vl53l1_tuningparm_dynxtalk_single_xtalk_delta; + uint32_t vl53l1_tuningparm_dynxtalk_averaged_xtalk_delta; + uint32_t vl53l1_tuningparm_dynxtalk_clip_limit; + uint8_t vl53l1_tuningparm_dynxtalk_scaler_calc_method; + int16_t vl53l1_tuningparm_dynxtalk_xgradient_scaler; + int16_t vl53l1_tuningparm_dynxtalk_ygradient_scaler; + uint8_t vl53l1_tuningparm_dynxtalk_user_scaler_set; + uint8_t vl53l1_tuningparm_dynxtalk_smudge_cor_single_apply; + uint32_t vl53l1_tuningparm_dynxtalk_xtalk_amb_threshold; + uint32_t vl53l1_tuningparm_dynxtalk_nodetect_amb_threshold_kcps; + uint32_t vl53l1_tuningparm_dynxtalk_nodetect_sample_limit; + uint32_t vl53l1_tuningparm_dynxtalk_nodetect_xtalk_offset_kcps; + uint16_t vl53l1_tuningparm_dynxtalk_nodetect_min_range_mm; + uint8_t vl53l1_tuningparm_lowpowerauto_vhv_loop_bound; + uint32_t vl53l1_tuningparm_lowpowerauto_mm_config_timeout_us; + uint32_t vl53l1_tuningparm_lowpowerauto_range_config_timeout_us; + uint16_t vl53l1_tuningparm_very_short_dss_rate_mcps; +} VL53L1_tuning_parameters_t; + + + + + + + + + + + + +typedef struct { + + uint16_t target_reflectance_for_dmax[VL53L1_MAX_AMBIENT_DMAX_VALUES]; + +} VL53L1_dmax_reflectance_array_t; + + + + + + + + + + + + + + +typedef struct { + + uint8_t spad_type; + + + uint16_t VL53L1_p_023; + + + uint16_t rate_data[VL53L1_NO_OF_SPAD_ENABLES]; + + + uint16_t no_of_values; + + + uint8_t fractional_bits; + + + uint8_t error_status; + + + +} VL53L1_spad_rate_data_t; + + + + + + + + + + + + + + +typedef struct { + + VL53L1_DevicePresetModes preset_mode; + + + VL53L1_DeviceZonePreset zone_preset; + + + VL53L1_DeviceMeasurementModes measurement_mode; + + + VL53L1_OffsetCalibrationMode offset_calibration_mode; + + + VL53L1_OffsetCorrectionMode offset_correction_mode; + + + VL53L1_DeviceDmaxMode dmax_mode; + + + + uint32_t phasecal_config_timeout_us; + + + uint32_t mm_config_timeout_us; + + + uint32_t range_config_timeout_us; + + + uint32_t inter_measurement_period_ms; + + + uint16_t dss_config__target_total_rate_mcps; + + + + VL53L1_histogram_bin_data_t VL53L1_p_010; + + + +} VL53L1_additional_data_t; + + + + + + + + + + +#define SUPPRESS_UNUSED_WARNING(x) \ + ((void) (x)) + + +#define IGNORE_STATUS(__FUNCTION_ID__, __ERROR_STATUS_CHECK__, __STATUS__) \ + do { \ + DISABLE_WARNINGS(); \ + if (__FUNCTION_ID__) { \ + if (__STATUS__ == __ERROR_STATUS_CHECK__) { \ + __STATUS__ = VL53L1_ERROR_NONE; \ + WARN_OVERRIDE_STATUS(__FUNCTION_ID__); \ + } \ + } \ + ENABLE_WARNINGS(); \ + } \ + while (0) + +#define VL53L1_COPYSTRING(str, ...) \ + (strncpy(str, ##__VA_ARGS__, VL53L1_MAX_STRING_LENGTH-1)) + +#ifdef __cplusplus +} +#endif + +#endif + + + + diff --git a/drivers/input/misc/vl53L1/lito/inc/vl53l1_ll_device.h b/drivers/input/misc/vl53L1/lito/inc/vl53l1_ll_device.h new file mode 100644 index 000000000000..900c7df606cb --- /dev/null +++ b/drivers/input/misc/vl53L1/lito/inc/vl53l1_ll_device.h @@ -0,0 +1,1286 @@ + +/******************************************************************************* + * Copyright (c) 2017, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#ifndef _VL53L1_LL_DEVICE_H_ +#define _VL53L1_LL_DEVICE_H_ + +#include "vl53l1_types.h" +#include "vl53l1_platform_user_config.h" + +#define VL53L1_I2C 0x01 +#define VL53L1_SPI 0x00 + + + + + + + + + + + + + +typedef uint8_t VL53L1_WaitMethod; + +#define VL53L1_WAIT_METHOD_BLOCKING ((VL53L1_WaitMethod) 0) +#define VL53L1_WAIT_METHOD_NON_BLOCKING ((VL53L1_WaitMethod) 1) + + + + + + + + + + +typedef uint8_t VL53L1_DeviceState; + +#define VL53L1_DEVICESTATE_POWERDOWN ((VL53L1_DeviceState) 0) +#define VL53L1_DEVICESTATE_HW_STANDBY ((VL53L1_DeviceState) 1) +#define VL53L1_DEVICESTATE_FW_COLDBOOT ((VL53L1_DeviceState) 2) +#define VL53L1_DEVICESTATE_SW_STANDBY ((VL53L1_DeviceState) 3) +#define VL53L1_DEVICESTATE_RANGING_DSS_AUTO ((VL53L1_DeviceState) 4) +#define VL53L1_DEVICESTATE_RANGING_DSS_MANUAL ((VL53L1_DeviceState) 5) +#define VL53L1_DEVICESTATE_RANGING_WAIT_GPH_SYNC ((VL53L1_DeviceState) 6) +#define VL53L1_DEVICESTATE_RANGING_GATHER_DATA ((VL53L1_DeviceState) 7) +#define VL53L1_DEVICESTATE_RANGING_OUTPUT_DATA ((VL53L1_DeviceState) 8) + +#define VL53L1_DEVICESTATE_UNKNOWN ((VL53L1_DeviceState) 98) +#define VL53L1_DEVICESTATE_ERROR ((VL53L1_DeviceState) 99) + + + + + + + + + + + +typedef uint8_t VL53L1_DeviceZonePreset; + +#define VL53L1_DEVICEZONEPRESET_NONE \ + ((VL53L1_DeviceZonePreset) 0) + +#define VL53L1_DEVICEZONEPRESET_XTALK_PLANAR \ + ((VL53L1_DeviceZonePreset) 1) +#define VL53L1_DEVICEZONEPRESET_1X1_SIZE_16X16 \ + ((VL53L1_DeviceZonePreset) 2) +#define VL53L1_DEVICEZONEPRESET_1X2_SIZE_16X8 \ + ((VL53L1_DeviceZonePreset) 3) +#define VL53L1_DEVICEZONEPRESET_2X1_SIZE_8X16 \ + ((VL53L1_DeviceZonePreset) 4) +#define VL53L1_DEVICEZONEPRESET_2X2_SIZE_8X8 \ + ((VL53L1_DeviceZonePreset) 5) +#define VL53L1_DEVICEZONEPRESET_3X3_SIZE_5X5 \ + ((VL53L1_DeviceZonePreset) 6) +#define VL53L1_DEVICEZONEPRESET_4X4_SIZE_4X4 \ + ((VL53L1_DeviceZonePreset) 7) +#define VL53L1_DEVICEZONEPRESET_5X5_SIZE_4X4 \ + ((VL53L1_DeviceZonePreset) 8) +#define VL53L1_DEVICEZONEPRESET_11X11_SIZE_5X5 \ + ((VL53L1_DeviceZonePreset) 9) +#define VL53L1_DEVICEZONEPRESET_13X13_SIZE_4X4 \ + ((VL53L1_DeviceZonePreset) 10) + +#define VL53L1_DEVICEZONEPRESET_1X1_SIZE_4X4_POS_8X8 \ + ((VL53L1_DeviceZonePreset) 11) + +#define VL53L1_DEVICEZONEPRESET_CUSTOM \ + ((VL53L1_DeviceZonePreset) 255) + + + + + + + + + + + +typedef uint8_t VL53L1_DevicePresetModes; + +#define VL53L1_DEVICEPRESETMODE_NONE \ + ((VL53L1_DevicePresetModes) 0) +#define VL53L1_DEVICEPRESETMODE_STANDARD_RANGING \ + ((VL53L1_DevicePresetModes) 1) +#define VL53L1_DEVICEPRESETMODE_STANDARD_RANGING_SHORT_RANGE \ + ((VL53L1_DevicePresetModes) 2) +#define VL53L1_DEVICEPRESETMODE_STANDARD_RANGING_LONG_RANGE \ + ((VL53L1_DevicePresetModes) 3) +#define VL53L1_DEVICEPRESETMODE_STANDARD_RANGING_MM1_CAL \ + ((VL53L1_DevicePresetModes) 4) +#define VL53L1_DEVICEPRESETMODE_STANDARD_RANGING_MM2_CAL \ + ((VL53L1_DevicePresetModes) 5) +#define VL53L1_DEVICEPRESETMODE_TIMED_RANGING \ + ((VL53L1_DevicePresetModes) 6) +#define VL53L1_DEVICEPRESETMODE_TIMED_RANGING_SHORT_RANGE \ + ((VL53L1_DevicePresetModes) 7) +#define VL53L1_DEVICEPRESETMODE_TIMED_RANGING_LONG_RANGE \ + ((VL53L1_DevicePresetModes) 8) +#define VL53L1_DEVICEPRESETMODE_NEAR_FARRANGING \ + ((VL53L1_DevicePresetModes) 9) +#define VL53L1_DEVICEPRESETMODE_QUADRANT_RANGING \ + ((VL53L1_DevicePresetModes) 10) +#define VL53L1_DEVICEPRESETMODE_HISTOGRAM_RANGING \ + ((VL53L1_DevicePresetModes) 11) +#define VL53L1_DEVICEPRESETMODE_HISTOGRAM_RANGING_SHORT_TIMING \ + ((VL53L1_DevicePresetModes) 12) +#define VL53L1_DEVICEPRESETMODE_HISTOGRAM_CHARACTERISATION \ + ((VL53L1_DevicePresetModes) 13) +#define VL53L1_DEVICEPRESETMODE_HISTOGRAM_XTALK_PLANAR \ + ((VL53L1_DevicePresetModes) 14) +#define VL53L1_DEVICEPRESETMODE_HISTOGRAM_XTALK_MM1 \ + ((VL53L1_DevicePresetModes) 15) +#define VL53L1_DEVICEPRESETMODE_HISTOGRAM_XTALK_MM2 \ + ((VL53L1_DevicePresetModes) 16) +#define VL53L1_DEVICEPRESETMODE_OLT \ + ((VL53L1_DevicePresetModes) 17) +#define VL53L1_DEVICEPRESETMODE_SINGLESHOT_RANGING \ + ((VL53L1_DevicePresetModes) 18) +#define VL53L1_DEVICEPRESETMODE_HISTOGRAM_REF_ARRAY \ + ((VL53L1_DevicePresetModes) 19) +#define VL53L1_DEVICEPRESETMODE_HISTOGRAM_RANGING_WITH_MM1 \ + ((VL53L1_DevicePresetModes) 20) +#define VL53L1_DEVICEPRESETMODE_HISTOGRAM_RANGING_WITH_MM2 \ + ((VL53L1_DevicePresetModes) 21) +#define VL53L1_DEVICEPRESETMODE_HISTOGRAM_RANGING_MM1_CAL \ + ((VL53L1_DevicePresetModes) 22) +#define VL53L1_DEVICEPRESETMODE_HISTOGRAM_RANGING_MM2_CAL \ + ((VL53L1_DevicePresetModes) 23) +#define VL53L1_DEVICEPRESETMODE_HISTOGRAM_MULTIZONE \ + ((VL53L1_DevicePresetModes) 24) +#define VL53L1_DEVICEPRESETMODE_HISTOGRAM_MULTIZONE_SHORT_RANGE \ + ((VL53L1_DevicePresetModes) 25) +#define VL53L1_DEVICEPRESETMODE_HISTOGRAM_MULTIZONE_LONG_RANGE \ + ((VL53L1_DevicePresetModes) 26) +#define VL53L1_DEVICEPRESETMODE_HISTOGRAM_LONG_RANGE \ + ((VL53L1_DevicePresetModes) 27) +#define VL53L1_DEVICEPRESETMODE_HISTOGRAM_LONG_RANGE_MM1 \ + ((VL53L1_DevicePresetModes) 28) +#define VL53L1_DEVICEPRESETMODE_HISTOGRAM_LONG_RANGE_MM2 \ + ((VL53L1_DevicePresetModes) 29) +#define VL53L1_DEVICEPRESETMODE_HISTOGRAM_MEDIUM_RANGE \ + ((VL53L1_DevicePresetModes) 30) +#define VL53L1_DEVICEPRESETMODE_HISTOGRAM_MEDIUM_RANGE_MM1 \ + ((VL53L1_DevicePresetModes) 31) +#define VL53L1_DEVICEPRESETMODE_HISTOGRAM_MEDIUM_RANGE_MM2 \ + ((VL53L1_DevicePresetModes) 32) +#define VL53L1_DEVICEPRESETMODE_HISTOGRAM_SHORT_RANGE \ + ((VL53L1_DevicePresetModes) 33) +#define VL53L1_DEVICEPRESETMODE_HISTOGRAM_SHORT_RANGE_MM1 \ + ((VL53L1_DevicePresetModes) 34) +#define VL53L1_DEVICEPRESETMODE_HISTOGRAM_SHORT_RANGE_MM2 \ + ((VL53L1_DevicePresetModes) 35) +#define VL53L1_DEVICEPRESETMODE_LOWPOWERAUTO_SHORT_RANGE \ + ((VL53L1_DevicePresetModes) 36) +#define VL53L1_DEVICEPRESETMODE_LOWPOWERAUTO_MEDIUM_RANGE \ + ((VL53L1_DevicePresetModes) 37) +#define VL53L1_DEVICEPRESETMODE_LOWPOWERAUTO_LONG_RANGE \ + ((VL53L1_DevicePresetModes) 38) +#define VL53L1_DEVICEPRESETMODE_SPECIAL_HISTOGRAM_SHORT_RANGE \ + ((VL53L1_DevicePresetModes) 39) + + + + + + + + + + + +typedef uint8_t VL53L1_DeviceMeasurementModes; + +#define VL53L1_DEVICEMEASUREMENTMODE_STOP \ + ((VL53L1_DeviceMeasurementModes) 0x00) +#define VL53L1_DEVICEMEASUREMENTMODE_SINGLESHOT \ + ((VL53L1_DeviceMeasurementModes) 0x10) +#define VL53L1_DEVICEMEASUREMENTMODE_BACKTOBACK \ + ((VL53L1_DeviceMeasurementModes) 0x20) +#define VL53L1_DEVICEMEASUREMENTMODE_TIMED \ + ((VL53L1_DeviceMeasurementModes) 0x40) +#define VL53L1_DEVICEMEASUREMENTMODE_ABORT \ + ((VL53L1_DeviceMeasurementModes) 0x80) + + + + + + + + + + + +typedef uint8_t VL53L1_OffsetCalibrationMode; + +#define VL53L1_OFFSETCALIBRATIONMODE__NONE \ + ((VL53L1_OffsetCalibrationMode) 0) +#define VL53L1_OFFSETCALIBRATIONMODE__MM1_MM2__STANDARD \ + ((VL53L1_OffsetCalibrationMode) 1) +#define VL53L1_OFFSETCALIBRATIONMODE__MM1_MM2__HISTOGRAM \ + ((VL53L1_OffsetCalibrationMode) 2) +#define VL53L1_OFFSETCALIBRATIONMODE__MM1_MM2__STANDARD_PRE_RANGE_ONLY \ + ((VL53L1_OffsetCalibrationMode) 3) +#define VL53L1_OFFSETCALIBRATIONMODE__MM1_MM2__HISTOGRAM_PRE_RANGE_ONLY \ + ((VL53L1_OffsetCalibrationMode) 4) +#define VL53L1_OFFSETCALIBRATIONMODE__PER_ZONE \ + ((VL53L1_OffsetCalibrationMode) 5) + + + + + + + + + + + +typedef uint8_t VL53L1_OffsetCorrectionMode; + +#define VL53L1_OFFSETCORRECTIONMODE__NONE \ + ((VL53L1_OffsetCorrectionMode) 0) +#define VL53L1_OFFSETCORRECTIONMODE__MM1_MM2_OFFSETS \ + ((VL53L1_OffsetCorrectionMode) 1) +#define VL53L1_OFFSETCORRECTIONMODE__PER_ZONE_OFFSETS \ + ((VL53L1_OffsetCorrectionMode) 2) + + + + + + + + + + + +typedef uint8_t VL53L1_DeviceDmaxMode; + +#define VL53L1_DEVICEDMAXMODE__NONE \ + ((VL53L1_DeviceDmaxMode) 0) +#define VL53L1_DEVICEDMAXMODE__FMT_CAL_DATA \ + ((VL53L1_DeviceDmaxMode) 1) +#define VL53L1_DEVICEDMAXMODE__CUST_CAL_DATA \ + ((VL53L1_DeviceDmaxMode) 2) +#define VL53L1_DEVICEDMAXMODE__PER_ZONE_CAL_DATA \ + ((VL53L1_DeviceDmaxMode) 3) + + + + + + + + + + + + +typedef uint8_t VL53L1_DeviceSequenceConfig; + +#define VL53L1_DEVICESEQUENCECONFIG_VHV \ + ((VL53L1_DeviceSequenceConfig) 0) +#define VL53L1_DEVICESEQUENCECONFIG_PHASECAL \ + ((VL53L1_DeviceSequenceConfig) 1) +#define VL53L1_DEVICESEQUENCECONFIG_REFERENCE_PHASE \ + ((VL53L1_DeviceSequenceConfig) 2) +#define VL53L1_DEVICESEQUENCECONFIG_DSS1 \ + ((VL53L1_DeviceSequenceConfig) 3) +#define VL53L1_DEVICESEQUENCECONFIG_DSS2 \ + ((VL53L1_DeviceSequenceConfig) 4) +#define VL53L1_DEVICESEQUENCECONFIG_MM1 \ + ((VL53L1_DeviceSequenceConfig) 5) +#define VL53L1_DEVICESEQUENCECONFIG_MM2 \ + ((VL53L1_DeviceSequenceConfig) 6) +#define VL53L1_DEVICESEQUENCECONFIG_RANGE \ + ((VL53L1_DeviceSequenceConfig) 7) + + + + + + + + + + + +typedef uint8_t VL53L1_DeviceInterruptPolarity; + +#define VL53L1_DEVICEINTERRUPTPOLARITY_ACTIVE_HIGH \ + ((VL53L1_DeviceInterruptPolarity) 0x00) +#define VL53L1_DEVICEINTERRUPTPOLARITY_ACTIVE_LOW \ + ((VL53L1_DeviceInterruptPolarity) 0x10) +#define VL53L1_DEVICEINTERRUPTPOLARITY_BIT_MASK \ + ((VL53L1_DeviceInterruptPolarity) 0x10) +#define VL53L1_DEVICEINTERRUPTPOLARITY_CLEAR_MASK \ + ((VL53L1_DeviceInterruptPolarity) 0xEF) + + + + + + + + + + + +typedef uint8_t VL53L1_DeviceGpioMode; + +#define VL53L1_DEVICEGPIOMODE_OUTPUT_CONSTANT_ZERO \ + ((VL53L1_DeviceGpioMode) 0x00) +#define VL53L1_DEVICEGPIOMODE_OUTPUT_RANGE_AND_ERROR_INTERRUPTS \ + ((VL53L1_DeviceGpioMode) 0x01) +#define VL53L1_DEVICEGPIOMODE_OUTPUT_TIMIER_INTERRUPTS \ + ((VL53L1_DeviceGpioMode) 0x02) +#define VL53L1_DEVICEGPIOMODE_OUTPUT_RANGE_MODE_INTERRUPT_STATUS \ + ((VL53L1_DeviceGpioMode) 0x03) +#define VL53L1_DEVICEGPIOMODE_OUTPUT_SLOW_OSCILLATOR_CLOCK \ + ((VL53L1_DeviceGpioMode) 0x04) +#define VL53L1_DEVICEGPIOMODE_BIT_MASK \ + ((VL53L1_DeviceGpioMode) 0x0F) +#define VL53L1_DEVICEGPIOMODE_CLEAR_MASK \ + ((VL53L1_DeviceGpioMode) 0xF0) + + + + + + + + + + + + + + + +typedef uint8_t VL53L1_DeviceError; + +#define VL53L1_DEVICEERROR_NOUPDATE \ + ((VL53L1_DeviceError) 0) + + +#define VL53L1_DEVICEERROR_VCSELCONTINUITYTESTFAILURE \ + ((VL53L1_DeviceError) 1) +#define VL53L1_DEVICEERROR_VCSELWATCHDOGTESTFAILURE \ + ((VL53L1_DeviceError) 2) +#define VL53L1_DEVICEERROR_NOVHVVALUEFOUND \ + ((VL53L1_DeviceError) 3) +#define VL53L1_DEVICEERROR_MSRCNOTARGET \ + ((VL53L1_DeviceError) 4) +#define VL53L1_DEVICEERROR_RANGEPHASECHECK \ + ((VL53L1_DeviceError) 5) +#define VL53L1_DEVICEERROR_SIGMATHRESHOLDCHECK \ + ((VL53L1_DeviceError) 6) +#define VL53L1_DEVICEERROR_PHASECONSISTENCY \ + ((VL53L1_DeviceError) 7) +#define VL53L1_DEVICEERROR_MINCLIP \ + ((VL53L1_DeviceError) 8) +#define VL53L1_DEVICEERROR_RANGECOMPLETE \ + ((VL53L1_DeviceError) 9) +#define VL53L1_DEVICEERROR_ALGOUNDERFLOW \ + ((VL53L1_DeviceError) 10) +#define VL53L1_DEVICEERROR_ALGOOVERFLOW \ + ((VL53L1_DeviceError) 11) +#define VL53L1_DEVICEERROR_RANGEIGNORETHRESHOLD \ + ((VL53L1_DeviceError) 12) +#define VL53L1_DEVICEERROR_USERROICLIP \ + ((VL53L1_DeviceError) 13) +#define VL53L1_DEVICEERROR_REFSPADCHARNOTENOUGHDPADS \ + ((VL53L1_DeviceError) 14) +#define VL53L1_DEVICEERROR_REFSPADCHARMORETHANTARGET \ + ((VL53L1_DeviceError) 15) +#define VL53L1_DEVICEERROR_REFSPADCHARLESSTHANTARGET \ + ((VL53L1_DeviceError) 16) +#define VL53L1_DEVICEERROR_MULTCLIPFAIL \ + ((VL53L1_DeviceError) 17) +#define VL53L1_DEVICEERROR_GPHSTREAMCOUNT0READY \ + ((VL53L1_DeviceError) 18) +#define VL53L1_DEVICEERROR_RANGECOMPLETE_NO_WRAP_CHECK \ + ((VL53L1_DeviceError) 19) +#define VL53L1_DEVICEERROR_EVENTCONSISTENCY \ + ((VL53L1_DeviceError) 20) +#define VL53L1_DEVICEERROR_MINSIGNALEVENTCHECK \ + ((VL53L1_DeviceError) 21) +#define VL53L1_DEVICEERROR_RANGECOMPLETE_MERGED_PULSE \ + ((VL53L1_DeviceError) 22) + + + +#define VL53L1_DEVICEERROR_PREV_RANGE_NO_TARGETS \ + ((VL53L1_DeviceError) 23) + + + + + + + + + + + +typedef uint8_t VL53L1_DeviceReportStatus; + +#define VL53L1_DEVICEREPORTSTATUS_NOUPDATE \ + ((VL53L1_DeviceReportStatus) 0) + + +#define VL53L1_DEVICEREPORTSTATUS_ROI_SETUP \ + ((VL53L1_DeviceReportStatus) 1) +#define VL53L1_DEVICEREPORTSTATUS_VHV \ + ((VL53L1_DeviceReportStatus) 2) +#define VL53L1_DEVICEREPORTSTATUS_PHASECAL \ + ((VL53L1_DeviceReportStatus) 3) +#define VL53L1_DEVICEREPORTSTATUS_REFERENCE_PHASE \ + ((VL53L1_DeviceReportStatus) 4) +#define VL53L1_DEVICEREPORTSTATUS_DSS1 \ + ((VL53L1_DeviceReportStatus) 5) +#define VL53L1_DEVICEREPORTSTATUS_DSS2 \ + ((VL53L1_DeviceReportStatus) 6) +#define VL53L1_DEVICEREPORTSTATUS_MM1 \ + ((VL53L1_DeviceReportStatus) 7) +#define VL53L1_DEVICEREPORTSTATUS_MM2 \ + ((VL53L1_DeviceReportStatus) 8) +#define VL53L1_DEVICEREPORTSTATUS_RANGE \ + ((VL53L1_DeviceReportStatus) 9) +#define VL53L1_DEVICEREPORTSTATUS_HISTOGRAM \ + ((VL53L1_DeviceReportStatus) 10) + + + + + + + + + + +typedef uint8_t VL53L1_DeviceDssMode; + +#define VL53L1_DEVICEDSSMODE__DISABLED \ + ((VL53L1_DeviceDssMode) 0) +#define VL53L1_DEVICEDSSMODE__TARGET_RATE \ + ((VL53L1_DeviceDssMode) 1) +#define VL53L1_DEVICEDSSMODE__REQUESTED_EFFFECTIVE_SPADS \ + ((VL53L1_DeviceDssMode) 2) +#define VL53L1_DEVICEDSSMODE__BLOCK_SELECT \ + ((VL53L1_DeviceDssMode) 3) + + + + + + + + + + + + +typedef uint8_t VL53L1_HistAlgoSelect; + +#define VL53L1_HIST_ALGO_SELECT__PW_HIST_GEN1 \ + ((VL53L1_HistAlgoSelect) 1) +#define VL53L1_HIST_ALGO_SELECT__PW_HIST_GEN2 \ + ((VL53L1_HistAlgoSelect) 2) +#define VL53L1_HIST_ALGO_SELECT__PW_HIST_GEN3 \ + ((VL53L1_HistAlgoSelect) 3) +#define VL53L1_HIST_ALGO_SELECT__PW_HIST_GEN4 \ + ((VL53L1_HistAlgoSelect) 4) + + + + + + + + + + + +typedef uint8_t VL53L1_HistTargetOrder; + +#define VL53L1_HIST_TARGET_ORDER__INCREASING_DISTANCE \ + ((VL53L1_HistTargetOrder) 1) +#define VL53L1_HIST_TARGET_ORDER__STRONGEST_FIRST \ + ((VL53L1_HistTargetOrder) 2) + + + + + + + + + + + +typedef uint8_t VL53L1_HistAmbEstMethod; + +#define VL53L1_HIST_AMB_EST_METHOD__AMBIENT_BINS \ + ((VL53L1_HistAmbEstMethod) 1) +#define VL53L1_HIST_AMB_EST_METHOD__THRESHOLDED_BINS \ + ((VL53L1_HistAmbEstMethod) 2) + + + + + + + + + + + + +typedef uint8_t VL53L1_HistXtalkCompEnable; + +#define VL53L1_HIST_XTALK_COMP__DIS \ + ((VL53L1_HistXtalkCompEnable) 0) +#define VL53L1_HIST_XTALK_COMP__EN \ + ((VL53L1_HistXtalkCompEnable) 1) + + + + + + + + + +typedef uint8_t VL53L1_DeviceConfigLevel; + +#define VL53L1_DEVICECONFIGLEVEL_SYSTEM_CONTROL \ + ((VL53L1_DeviceConfigLevel) 0) + + +#define VL53L1_DEVICECONFIGLEVEL_DYNAMIC_ONWARDS \ + ((VL53L1_DeviceConfigLevel) 1) + + +#define VL53L1_DEVICECONFIGLEVEL_TIMING_ONWARDS \ + ((VL53L1_DeviceConfigLevel) 2) + + + +#define VL53L1_DEVICECONFIGLEVEL_GENERAL_ONWARDS \ + ((VL53L1_DeviceConfigLevel) 3) + + + +#define VL53L1_DEVICECONFIGLEVEL_STATIC_ONWARDS \ + ((VL53L1_DeviceConfigLevel) 4) + + + +#define VL53L1_DEVICECONFIGLEVEL_CUSTOMER_ONWARDS \ + ((VL53L1_DeviceConfigLevel) 5) + + + +#define VL53L1_DEVICECONFIGLEVEL_FULL \ + ((VL53L1_DeviceConfigLevel) 6) + + + + + + + + + + + + + + +typedef uint8_t VL53L1_DeviceResultsLevel; + +#define VL53L1_DEVICERESULTSLEVEL_SYSTEM_RESULTS \ + ((VL53L1_DeviceResultsLevel) 0) + + +#define VL53L1_DEVICERESULTSLEVEL_UPTO_CORE \ + ((VL53L1_DeviceResultsLevel) 1) + + +#define VL53L1_DEVICERESULTSLEVEL_FULL \ + ((VL53L1_DeviceResultsLevel) 2) + + + + + + + + + + + + + + + +typedef uint8_t VL53L1_DeviceTestMode; + +#define VL53L1_DEVICETESTMODE_NONE \ + ((VL53L1_DeviceTestMode) 0x00) + + +#define VL53L1_DEVICETESTMODE_NVM_ZERO \ + ((VL53L1_DeviceTestMode) 0x01) + + +#define VL53L1_DEVICETESTMODE_NVM_COPY \ + ((VL53L1_DeviceTestMode) 0x02) + + +#define VL53L1_DEVICETESTMODE_PATCH \ + ((VL53L1_DeviceTestMode) 0x03) + + +#define VL53L1_DEVICETESTMODE_DCR \ + ((VL53L1_DeviceTestMode) 0x04) + + +#define VL53L1_DEVICETESTMODE_LCR_VCSEL_OFF \ + ((VL53L1_DeviceTestMode) 0x05) + + + +#define VL53L1_DEVICETESTMODE_LCR_VCSEL_ON \ + ((VL53L1_DeviceTestMode) 0x06) + + + +#define VL53L1_DEVICETESTMODE_SPOT_CENTRE_LOCATE \ + ((VL53L1_DeviceTestMode) 0x07) + + +#define VL53L1_DEVICETESTMODE_REF_SPAD_CHAR_WITH_PRE_VHV \ + ((VL53L1_DeviceTestMode) 0x08) + + +#define VL53L1_DEVICETESTMODE_REF_SPAD_CHAR_ONLY \ + ((VL53L1_DeviceTestMode) 0x09) + + + + + + + + + + + + + +typedef uint8_t VL53L1_DeviceSscArray; + +#define VL53L1_DEVICESSCARRAY_RTN ((VL53L1_DeviceSscArray) 0x00) + + +#define VL53L1_DEVICETESTMODE_REF ((VL53L1_DeviceSscArray) 0x01) + + + + + + + + + + + + + +#define VL53L1_RETURN_ARRAY_ONLY 0x01 + + +#define VL53L1_REFERENCE_ARRAY_ONLY 0x10 + + +#define VL53L1_BOTH_RETURN_AND_REFERENCE_ARRAYS 0x11 + + +#define VL53L1_NEITHER_RETURN_AND_REFERENCE_ARRAYS 0x00 + + + + + + + + + + + + +#define VL53L1_DEVICEINTERRUPTLEVEL_ACTIVE_HIGH 0x00 + + +#define VL53L1_DEVICEINTERRUPTLEVEL_ACTIVE_LOW 0x10 + + +#define VL53L1_DEVICEINTERRUPTLEVEL_ACTIVE_MASK 0x10 + + + + + + + + + + + + +#define VL53L1_POLLING_DELAY_US 1000 + + +#define VL53L1_SOFTWARE_RESET_DURATION_US 100 + + +#define VL53L1_FIRMWARE_BOOT_TIME_US 1200 + + + +#define VL53L1_ENABLE_POWERFORCE_SETTLING_TIME_US 250 + + + + +#define VL53L1_SPAD_ARRAY_WIDTH 16 + + +#define VL53L1_SPAD_ARRAY_HEIGHT 16 + + +#define VL53L1_NVM_SIZE_IN_BYTES 512 + + +#define VL53L1_NO_OF_SPAD_ENABLES 256 + + +#define VL53L1_RTN_SPAD_BUFFER_SIZE 32 + + +#define VL53L1_REF_SPAD_BUFFER_SIZE 6 + + +#define VL53L1_AMBIENT_WINDOW_VCSEL_PERIODS 256 + + +#define VL53L1_RANGING_WINDOW_VCSEL_PERIODS 2048 + + +#define VL53L1_MACRO_PERIOD_VCSEL_PERIODS \ + (VL53L1_AMBIENT_WINDOW_VCSEL_PERIODS + \ + VL53L1_RANGING_WINDOW_VCSEL_PERIODS) + + +#define VL53L1_MAX_ALLOWED_PHASE 0xFFFF + + + +#define VL53L1_RTN_SPAD_UNITY_TRANSMISSION 0x0100 + + +#define VL53L1_RTN_SPAD_APERTURE_TRANSMISSION 0x0038 + + + + + +#define VL53L1_SPAD_TOTAL_COUNT_MAX ((0x01 << 29) - 1) + + +#define VL53L1_SPAD_TOTAL_COUNT_RES_THRES (0x01 << 24) + + +#define VL53L1_COUNT_RATE_INTERNAL_MAX ((0x01 << 24) - 1) + + +#define VL53L1_SPEED_OF_LIGHT_IN_AIR 299704 + + +#define VL53L1_SPEED_OF_LIGHT_IN_AIR_DIV_8 (299704 >> 3) + + + + + + + + + + + + + + + + +typedef uint8_t VL53L1_ZoneConfig_BinConfig_select; + +#define VL53L1_ZONECONFIG_BINCONFIG__LOWAMB \ + ((VL53L1_ZoneConfig_BinConfig_select) 1) +#define VL53L1_ZONECONFIG_BINCONFIG__MIDAMB \ + ((VL53L1_ZoneConfig_BinConfig_select) 2) +#define VL53L1_ZONECONFIG_BINCONFIG__HIGHAMB \ + ((VL53L1_ZoneConfig_BinConfig_select) 3) + + + + + + + + + + +typedef uint8_t VL53L1_GPIO_Interrupt_Mode; + +#define VL53L1_GPIOINTMODE_LEVEL_LOW \ + ((VL53L1_GPIO_Interrupt_Mode) 0) + + +#define VL53L1_GPIOINTMODE_LEVEL_HIGH \ + ((VL53L1_GPIO_Interrupt_Mode) 1) + + +#define VL53L1_GPIOINTMODE_OUT_OF_WINDOW \ + ((VL53L1_GPIO_Interrupt_Mode) 2) + + +#define VL53L1_GPIOINTMODE_IN_WINDOW \ + ((VL53L1_GPIO_Interrupt_Mode) 3) + + + + + + + + + + + + + +typedef uint16_t VL53L1_TuningParms; + +#define VL53L1_TUNINGPARMS_LLD_PUBLIC_MIN_ADDRESS \ + ((VL53L1_TuningParms) VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS) +#define VL53L1_TUNINGPARMS_LLD_PUBLIC_MAX_ADDRESS \ + ((VL53L1_TuningParms) VL53L1_TUNINGPARM_VERY_SHORT_DSS_RATE_MCPS) + +#define VL53L1_TUNINGPARMS_LLD_PRIVATE_MIN_ADDRESS \ + ((VL53L1_TuningParms) VL53L1_TUNINGPARM_PRIVATE_PAGE_BASE_ADDRESS) +#define VL53L1_TUNINGPARMS_LLD_PRIVATE_MAX_ADDRESS \ + ((VL53L1_TuningParms) VL53L1_TUNINGPARMS_LLD_PRIVATE_MIN_ADDRESS) + +#define VL53L1_TUNINGPARM_VERSION \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 0)) +#define VL53L1_TUNINGPARM_KEY_TABLE_VERSION \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 1)) +#define VL53L1_TUNINGPARM_LLD_VERSION \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 2)) +#define VL53L1_TUNINGPARM_HIST_ALGO_SELECT \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 3)) +#define VL53L1_TUNINGPARM_HIST_TARGET_ORDER \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 4)) +#define VL53L1_TUNINGPARM_HIST_FILTER_WOI_0 \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 5)) +#define VL53L1_TUNINGPARM_HIST_FILTER_WOI_1 \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 6)) +#define VL53L1_TUNINGPARM_HIST_AMB_EST_METHOD \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 7)) +#define VL53L1_TUNINGPARM_HIST_AMB_THRESH_SIGMA_0 \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 8)) +#define VL53L1_TUNINGPARM_HIST_AMB_THRESH_SIGMA_1 \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 9)) +#define VL53L1_TUNINGPARM_HIST_MIN_AMB_THRESH_EVENTS \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 10)) +#define VL53L1_TUNINGPARM_HIST_AMB_EVENTS_SCALER \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 11)) +#define VL53L1_TUNINGPARM_HIST_NOISE_THRESHOLD \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 12)) +#define VL53L1_TUNINGPARM_HIST_SIGNAL_TOTAL_EVENTS_LIMIT \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 13)) +#define VL53L1_TUNINGPARM_HIST_SIGMA_EST_REF_MM \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 14)) +#define VL53L1_TUNINGPARM_HIST_SIGMA_THRESH_MM \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 15)) +#define VL53L1_TUNINGPARM_HIST_GAIN_FACTOR \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 16)) +#define VL53L1_TUNINGPARM_CONSISTENCY_HIST_PHASE_TOLERANCE \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 17)) +#define VL53L1_TUNINGPARM_CONSISTENCY_HIST_MIN_MAX_TOLERANCE_MM \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 18)) +#define VL53L1_TUNINGPARM_CONSISTENCY_HIST_EVENT_SIGMA \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 19)) +#define VL53L1_TUNINGPARM_CONSISTENCY_HIST_EVENT_SIGMA_MIN_SPAD_LIMIT \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 20)) +#define VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_HISTO_LONG_RANGE \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 21)) +#define VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_HISTO_MED_RANGE \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 22)) +#define VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_HISTO_SHORT_RANGE \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 23)) +#define VL53L1_TUNINGPARM_INITIAL_PHASE_REF_HISTO_LONG_RANGE \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 24)) +#define VL53L1_TUNINGPARM_INITIAL_PHASE_REF_HISTO_MED_RANGE \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 25)) +#define VL53L1_TUNINGPARM_INITIAL_PHASE_REF_HISTO_SHORT_RANGE \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 26)) +#define VL53L1_TUNINGPARM_XTALK_DETECT_MIN_VALID_RANGE_MM \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 27)) +#define VL53L1_TUNINGPARM_XTALK_DETECT_MAX_VALID_RANGE_MM \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 28)) +#define VL53L1_TUNINGPARM_XTALK_DETECT_MAX_SIGMA_MM \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 29)) +#define VL53L1_TUNINGPARM_XTALK_DETECT_MIN_MAX_TOLERANCE \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 30)) +#define VL53L1_TUNINGPARM_XTALK_DETECT_MAX_VALID_RATE_KCPS \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 31)) +#define VL53L1_TUNINGPARM_XTALK_DETECT_EVENT_SIGMA \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 32)) +#define VL53L1_TUNINGPARM_HIST_XTALK_MARGIN_KCPS \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 33)) +#define VL53L1_TUNINGPARM_CONSISTENCY_LITE_PHASE_TOLERANCE \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 34)) +#define VL53L1_TUNINGPARM_PHASECAL_TARGET \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 35)) +#define VL53L1_TUNINGPARM_LITE_CAL_REPEAT_RATE \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 36)) +#define VL53L1_TUNINGPARM_LITE_RANGING_GAIN_FACTOR \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 37)) +#define VL53L1_TUNINGPARM_LITE_MIN_CLIP_MM \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 38)) +#define VL53L1_TUNINGPARM_LITE_LONG_SIGMA_THRESH_MM \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 39)) +#define VL53L1_TUNINGPARM_LITE_MED_SIGMA_THRESH_MM \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 40)) +#define VL53L1_TUNINGPARM_LITE_SHORT_SIGMA_THRESH_MM \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 41)) +#define VL53L1_TUNINGPARM_LITE_LONG_MIN_COUNT_RATE_RTN_MCPS \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 42)) +#define VL53L1_TUNINGPARM_LITE_MED_MIN_COUNT_RATE_RTN_MCPS \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 43)) +#define VL53L1_TUNINGPARM_LITE_SHORT_MIN_COUNT_RATE_RTN_MCPS \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 44)) +#define VL53L1_TUNINGPARM_LITE_SIGMA_EST_PULSE_WIDTH \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 45)) +#define VL53L1_TUNINGPARM_LITE_SIGMA_EST_AMB_WIDTH_NS \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 46)) +#define VL53L1_TUNINGPARM_LITE_SIGMA_REF_MM \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 47)) +#define VL53L1_TUNINGPARM_LITE_RIT_MULT \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 48)) +#define VL53L1_TUNINGPARM_LITE_SEED_CONFIG \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 49)) +#define VL53L1_TUNINGPARM_LITE_QUANTIFIER \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 50)) +#define VL53L1_TUNINGPARM_LITE_FIRST_ORDER_SELECT \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 51)) +#define VL53L1_TUNINGPARM_LITE_XTALK_MARGIN_KCPS \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 52)) +#define VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_LITE_LONG_RANGE \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 53)) +#define VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_LITE_MED_RANGE \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 54)) +#define VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_LITE_SHORT_RANGE \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 55)) +#define VL53L1_TUNINGPARM_INITIAL_PHASE_REF_LITE_LONG_RANGE \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 56)) +#define VL53L1_TUNINGPARM_INITIAL_PHASE_REF_LITE_MED_RANGE \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 57)) +#define VL53L1_TUNINGPARM_INITIAL_PHASE_REF_LITE_SHORT_RANGE \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 58)) +#define VL53L1_TUNINGPARM_TIMED_SEED_CONFIG \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 59)) +#define VL53L1_TUNINGPARM_DMAX_CFG_SIGNAL_THRESH_SIGMA \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 60)) +#define VL53L1_TUNINGPARM_DMAX_CFG_REFLECTANCE_ARRAY_0 \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 61)) +#define VL53L1_TUNINGPARM_DMAX_CFG_REFLECTANCE_ARRAY_1 \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 62)) +#define VL53L1_TUNINGPARM_DMAX_CFG_REFLECTANCE_ARRAY_2 \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 63)) +#define VL53L1_TUNINGPARM_DMAX_CFG_REFLECTANCE_ARRAY_3 \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 64)) +#define VL53L1_TUNINGPARM_DMAX_CFG_REFLECTANCE_ARRAY_4 \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 65)) +#define VL53L1_TUNINGPARM_VHV_LOOPBOUND \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 66)) +#define VL53L1_TUNINGPARM_REFSPADCHAR_DEVICE_TEST_MODE \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 67)) +#define VL53L1_TUNINGPARM_REFSPADCHAR_VCSEL_PERIOD \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 68)) +#define VL53L1_TUNINGPARM_REFSPADCHAR_PHASECAL_TIMEOUT_US \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 69)) +#define VL53L1_TUNINGPARM_REFSPADCHAR_TARGET_COUNT_RATE_MCPS \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 70)) +#define VL53L1_TUNINGPARM_REFSPADCHAR_MIN_COUNTRATE_LIMIT_MCPS \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 71)) +#define VL53L1_TUNINGPARM_REFSPADCHAR_MAX_COUNTRATE_LIMIT_MCPS \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 72)) +#define VL53L1_TUNINGPARM_XTALK_EXTRACT_NUM_OF_SAMPLES \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 73)) +#define VL53L1_TUNINGPARM_XTALK_EXTRACT_MIN_FILTER_THRESH_MM \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 74)) +#define VL53L1_TUNINGPARM_XTALK_EXTRACT_MAX_FILTER_THRESH_MM \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 75)) +#define VL53L1_TUNINGPARM_XTALK_EXTRACT_DSS_RATE_MCPS \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 76)) +#define VL53L1_TUNINGPARM_XTALK_EXTRACT_PHASECAL_TIMEOUT_US \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 77)) +#define VL53L1_TUNINGPARM_XTALK_EXTRACT_MAX_VALID_RATE_KCPS \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 78)) +#define VL53L1_TUNINGPARM_XTALK_EXTRACT_SIGMA_THRESHOLD_MM \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 79)) +#define VL53L1_TUNINGPARM_XTALK_EXTRACT_DSS_TIMEOUT_US \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 80)) +#define VL53L1_TUNINGPARM_XTALK_EXTRACT_BIN_TIMEOUT_US \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 81)) +#define VL53L1_TUNINGPARM_OFFSET_CAL_DSS_RATE_MCPS \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 82)) +#define VL53L1_TUNINGPARM_OFFSET_CAL_PHASECAL_TIMEOUT_US \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 83)) +#define VL53L1_TUNINGPARM_OFFSET_CAL_MM_TIMEOUT_US \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 84)) +#define VL53L1_TUNINGPARM_OFFSET_CAL_RANGE_TIMEOUT_US \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 85)) +#define VL53L1_TUNINGPARM_OFFSET_CAL_PRE_SAMPLES \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 86)) +#define VL53L1_TUNINGPARM_OFFSET_CAL_MM1_SAMPLES \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 87)) +#define VL53L1_TUNINGPARM_OFFSET_CAL_MM2_SAMPLES \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 88)) +#define VL53L1_TUNINGPARM_ZONE_CAL_DSS_RATE_MCPS \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 89)) +#define VL53L1_TUNINGPARM_ZONE_CAL_PHASECAL_TIMEOUT_US \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 90)) +#define VL53L1_TUNINGPARM_ZONE_CAL_DSS_TIMEOUT_US \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 91)) +#define VL53L1_TUNINGPARM_ZONE_CAL_PHASECAL_NUM_SAMPLES \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 92)) +#define VL53L1_TUNINGPARM_ZONE_CAL_RANGE_TIMEOUT_US \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 93)) +#define VL53L1_TUNINGPARM_ZONE_CAL_ZONE_NUM_SAMPLES \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 94)) +#define VL53L1_TUNINGPARM_SPADMAP_VCSEL_PERIOD \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 95)) +#define VL53L1_TUNINGPARM_SPADMAP_VCSEL_START \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 96)) +#define VL53L1_TUNINGPARM_SPADMAP_RATE_LIMIT_MCPS \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 97)) +#define VL53L1_TUNINGPARM_LITE_DSS_CONFIG_TARGET_TOTAL_RATE_MCPS \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 98)) +#define VL53L1_TUNINGPARM_RANGING_DSS_CONFIG_TARGET_TOTAL_RATE_MCPS \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 99)) +#define VL53L1_TUNINGPARM_MZ_DSS_CONFIG_TARGET_TOTAL_RATE_MCPS \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 100)) +#define VL53L1_TUNINGPARM_TIMED_DSS_CONFIG_TARGET_TOTAL_RATE_MCPS \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 101)) +#define VL53L1_TUNINGPARM_LITE_PHASECAL_CONFIG_TIMEOUT_US \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 102)) +#define VL53L1_TUNINGPARM_RANGING_LONG_PHASECAL_CONFIG_TIMEOUT_US \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 103)) +#define VL53L1_TUNINGPARM_RANGING_MED_PHASECAL_CONFIG_TIMEOUT_US \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 104)) +#define VL53L1_TUNINGPARM_RANGING_SHORT_PHASECAL_CONFIG_TIMEOUT_US \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 105)) +#define VL53L1_TUNINGPARM_MZ_LONG_PHASECAL_CONFIG_TIMEOUT_US \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 106)) +#define VL53L1_TUNINGPARM_MZ_MED_PHASECAL_CONFIG_TIMEOUT_US \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 107)) +#define VL53L1_TUNINGPARM_MZ_SHORT_PHASECAL_CONFIG_TIMEOUT_US \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 108)) +#define VL53L1_TUNINGPARM_TIMED_PHASECAL_CONFIG_TIMEOUT_US \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 109)) +#define VL53L1_TUNINGPARM_LITE_MM_CONFIG_TIMEOUT_US \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 110)) +#define VL53L1_TUNINGPARM_RANGING_MM_CONFIG_TIMEOUT_US \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 111)) +#define VL53L1_TUNINGPARM_MZ_MM_CONFIG_TIMEOUT_US \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 112)) +#define VL53L1_TUNINGPARM_TIMED_MM_CONFIG_TIMEOUT_US \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 113)) +#define VL53L1_TUNINGPARM_LITE_RANGE_CONFIG_TIMEOUT_US \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 114)) +#define VL53L1_TUNINGPARM_RANGING_RANGE_CONFIG_TIMEOUT_US \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 115)) +#define VL53L1_TUNINGPARM_MZ_RANGE_CONFIG_TIMEOUT_US \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 116)) +#define VL53L1_TUNINGPARM_TIMED_RANGE_CONFIG_TIMEOUT_US \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 117)) +#define VL53L1_TUNINGPARM_DYNXTALK_SMUDGE_MARGIN \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 118)) +#define VL53L1_TUNINGPARM_DYNXTALK_NOISE_MARGIN \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 119)) +#define VL53L1_TUNINGPARM_DYNXTALK_XTALK_OFFSET_LIMIT \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 120)) +#define VL53L1_TUNINGPARM_DYNXTALK_XTALK_OFFSET_LIMIT_HI \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 121)) +#define VL53L1_TUNINGPARM_DYNXTALK_SAMPLE_LIMIT \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 122)) +#define VL53L1_TUNINGPARM_DYNXTALK_SINGLE_XTALK_DELTA \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 123)) +#define VL53L1_TUNINGPARM_DYNXTALK_AVERAGED_XTALK_DELTA \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 124)) +#define VL53L1_TUNINGPARM_DYNXTALK_CLIP_LIMIT \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 125)) +#define VL53L1_TUNINGPARM_DYNXTALK_SCALER_CALC_METHOD \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 126)) +#define VL53L1_TUNINGPARM_DYNXTALK_XGRADIENT_SCALER \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 127)) +#define VL53L1_TUNINGPARM_DYNXTALK_YGRADIENT_SCALER \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 128)) +#define VL53L1_TUNINGPARM_DYNXTALK_USER_SCALER_SET \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 129)) +#define VL53L1_TUNINGPARM_DYNXTALK_SMUDGE_COR_SINGLE_APPLY \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 130)) +#define VL53L1_TUNINGPARM_DYNXTALK_XTALK_AMB_THRESHOLD \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 131)) +#define VL53L1_TUNINGPARM_DYNXTALK_NODETECT_AMB_THRESHOLD_KCPS \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 132)) +#define VL53L1_TUNINGPARM_DYNXTALK_NODETECT_SAMPLE_LIMIT \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 133)) +#define VL53L1_TUNINGPARM_DYNXTALK_NODETECT_XTALK_OFFSET_KCPS \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 134)) +#define VL53L1_TUNINGPARM_DYNXTALK_NODETECT_MIN_RANGE_MM \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 135)) +#define VL53L1_TUNINGPARM_LOWPOWERAUTO_VHV_LOOP_BOUND \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 136)) +#define VL53L1_TUNINGPARM_LOWPOWERAUTO_MM_CONFIG_TIMEOUT_US \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 137)) +#define VL53L1_TUNINGPARM_LOWPOWERAUTO_RANGE_CONFIG_TIMEOUT_US \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 138)) +#define VL53L1_TUNINGPARM_VERY_SHORT_DSS_RATE_MCPS \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 139)) + + + + + + +#endif + + + + + + diff --git a/drivers/input/misc/vl53L1/lito/inc/vl53l1_nvm.h b/drivers/input/misc/vl53L1/lito/inc/vl53l1_nvm.h new file mode 100644 index 000000000000..53ccad1c112e --- /dev/null +++ b/drivers/input/misc/vl53L1/lito/inc/vl53l1_nvm.h @@ -0,0 +1,459 @@ + +/******************************************************************************* + * Copyright (c) 2017, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#ifndef _VL53L1_NVM_H_ +#define _VL53L1_NVM_H_ + +#include "vl53l1_ll_def.h" +#include "vl53l1_platform.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +#define VL53L1_NVM_POWER_UP_DELAY_US 50 +#define VL53L1_NVM_READ_TRIGGER_DELAY_US 5 + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_nvm_enable( + VL53L1_DEV Dev, + uint16_t nvm_ctrl_pulse_width, + int32_t nvm_power_up_delay_us); + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_nvm_read( + VL53L1_DEV Dev, + uint8_t start_address, + uint8_t count, + uint8_t *pdata); + + + + + + + + + + + + + + +VL53L1_Error VL53L1_nvm_disable( + VL53L1_DEV Dev); + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_nvm_format_decode( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_decoded_nvm_data_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_nvm_decode_optical_centre( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_optical_centre_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_nvm_decode_cal_peak_rate_map( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_cal_peak_rate_map_t *pdata); + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_nvm_decode_additional_offset_cal_data( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_additional_offset_cal_data_t *pdata); + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_nvm_decode_fmt_range_results_data( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_decoded_nvm_fmt_range_data_t *pdata); + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_nvm_decode_fmt_info( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_decoded_nvm_fmt_info_t *pdata); + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_nvm_decode_ews_info( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_decoded_nvm_ews_info_t *pdata); + + + + + + + + + + + + + + +void VL53L1_nvm_format_encode( + VL53L1_decoded_nvm_data_t *pnvm_info, + uint8_t *pnvm_data); + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_read_nvm_raw_data( + VL53L1_DEV Dev, + uint8_t start_address, + uint8_t count, + uint8_t *pnvm_raw_data); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_read_nvm( + VL53L1_DEV Dev, + uint8_t nvm_format, + VL53L1_decoded_nvm_data_t *pnvm_info); + + + + + + + + + + + + + +VL53L1_Error VL53L1_read_nvm_optical_centre( + VL53L1_DEV Dev, + VL53L1_optical_centre_t *pcentre); + + + + + + + + + + + + + +VL53L1_Error VL53L1_read_nvm_cal_peak_rate_map( + VL53L1_DEV Dev, + VL53L1_cal_peak_rate_map_t *pcal_data); + + + + + + + + + + + + + +VL53L1_Error VL53L1_read_nvm_additional_offset_cal_data( + VL53L1_DEV Dev, + VL53L1_additional_offset_cal_data_t *pcal_data); + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_read_nvm_fmt_range_results_data( + VL53L1_DEV Dev, + uint16_t range_results_select, + VL53L1_decoded_nvm_fmt_range_data_t *prange_data); + + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/drivers/input/misc/vl53L1/lito/inc/vl53l1_nvm_debug.h b/drivers/input/misc/vl53L1/lito/inc/vl53l1_nvm_debug.h new file mode 100644 index 000000000000..0524c0c169f5 --- /dev/null +++ b/drivers/input/misc/vl53L1/lito/inc/vl53l1_nvm_debug.h @@ -0,0 +1,202 @@ + +/******************************************************************************* + * Copyright (c) 2017, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#ifndef _VL53L1_NVM_DEBUG_H_ +#define _VL53L1_NVM_DEBUG_H_ + +#include "vl53l1_ll_def.h" +#include "vl53l1_nvm_structs.h" + + + +#ifdef __cplusplus +extern "C" +{ +#endif + +#ifdef VL53L1_LOG_ENABLE + + + + + + + + + + + + +void VL53L1_print_nvm_raw_data( + uint8_t *pnvm_raw_data, + uint32_t trace_flags); + + + + + + + + + + + + +void VL53L1_print_decoded_nvm_data( + VL53L1_decoded_nvm_data_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + + + + + + + + + +void VL53L1_print_decoded_nvm_fmt_range_data( + VL53L1_decoded_nvm_fmt_range_data_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + + + + + + + + + +void VL53L1_print_decoded_nvm_fmt_info( + VL53L1_decoded_nvm_fmt_info_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + + + + + + + + +void VL53L1_print_decoded_nvm_ews_info( + VL53L1_decoded_nvm_ews_info_t *pdata, + char *pprefix, + uint32_t trace_flags); + +#endif + + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/drivers/input/misc/vl53L1/lito/inc/vl53l1_nvm_map.h b/drivers/input/misc/vl53L1/lito/inc/vl53l1_nvm_map.h new file mode 100644 index 000000000000..15b5e1276665 --- /dev/null +++ b/drivers/input/misc/vl53L1/lito/inc/vl53l1_nvm_map.h @@ -0,0 +1,3254 @@ + +/******************************************************************************* + * Copyright (c) 2017, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#ifndef _VL53L1_NVM_MAP_H_ +#define _VL53L1_NVM_MAP_H_ + + +#ifdef __cplusplus +extern "C" +{ +#endif + + + + + + + +#define VL53L1_NVM__IDENTIFICATION__MODEL_ID 0x0008 + + + + + + + + + + + + + + + +#define VL53L1_NVM__IDENTIFICATION__MODULE_TYPE 0x000C + + + + + + + + + + + + + + + +#define VL53L1_NVM__IDENTIFICATION__REVISION_ID 0x000D + + + + + + + + + + + + + + + +#define VL53L1_NVM__IDENTIFICATION__MODULE_ID 0x000E + + + + + + + + + + + + + + + +#define VL53L1_NVM__I2C_VALID 0x0010 + + + + + + + + + + + + + + + +#define VL53L1_NVM__I2C_SLAVE__DEVICE_ADDRESS 0x0011 + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__OSC_MEASURED__FAST_OSC_FREQUENCY 0x0014 + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__FAST_OSC_TRIM_MAX 0x0016 + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__FAST_OSC_FREQ_SET 0x0017 + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SLOW_OSC_CALIBRATION 0x0018 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__OSC_MEASURED__FAST_OSC_FREQUENCY 0x001C + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__FAST_OSC_TRIM_MAX 0x001E + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__FAST_OSC_FREQ_SET 0x001F + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SLOW_OSC_CALIBRATION 0x0020 + + + + + + + + + + + + + + + +#define VL53L1_NVM__VHV_CONFIG_UNLOCK 0x0028 + + + + + + + + + + + + + + + +#define VL53L1_NVM__REF_SELVDDPIX 0x0029 + + + + + + + + + + + + + + + +#define VL53L1_NVM__REF_SELVQUENCH 0x002A + + + + + + + + + + + + + + + +#define VL53L1_NVM__REGAVDD1V2_SEL_REGDVDD1V2_SEL 0x002B + + + + + + + + + + + + + + + + +#define VL53L1_NVM__VHV_CONFIG__TIMEOUT_MACROP_LOOP_BOUND 0x002C + + + + + + + + + + + + + + + + +#define VL53L1_NVM__VHV_CONFIG__COUNT_THRESH 0x002D + + + + + + + + + + + + + + + +#define VL53L1_NVM__VHV_CONFIG__OFFSET 0x002E + + + + + + + + + + + + + + + +#define VL53L1_NVM__VHV_CONFIG__INIT 0x002F + + + + + + + + + + + + + + + + +#define VL53L1_NVM__LASER_SAFETY__VCSEL_TRIM_LL 0x0030 + + + + + + + + + + + + + + + +#define VL53L1_NVM__LASER_SAFETY__VCSEL_SELION_LL 0x0031 + + + + + + + + + + + + + + + +#define VL53L1_NVM__LASER_SAFETY__VCSEL_SELION_MAX_LL 0x0032 + + + + + + + + + + + + + + + +#define VL53L1_NVM__LASER_SAFETY__MULT_LL 0x0034 + + + + + + + + + + + + + + + +#define VL53L1_NVM__LASER_SAFETY__CLIP_LL 0x0035 + + + + + + + + + + + + + + + +#define VL53L1_NVM__LASER_SAFETY__VCSEL_TRIM_LD 0x0038 + + + + + + + + + + + + + + + +#define VL53L1_NVM__LASER_SAFETY__VCSEL_SELION_LD 0x0039 + + + + + + + + + + + + + + + +#define VL53L1_NVM__LASER_SAFETY__VCSEL_SELION_MAX_LD 0x003A + + + + + + + + + + + + + + + +#define VL53L1_NVM__LASER_SAFETY__MULT_LD 0x003C + + + + + + + + + + + + + + + +#define VL53L1_NVM__LASER_SAFETY__CLIP_LD 0x003D + + + + + + + + + + + + + + + +#define VL53L1_NVM__LASER_SAFETY_LOCK_BYTE 0x0040 + + + + + + + + + + + + + + + +#define VL53L1_NVM__LASER_SAFETY_UNLOCK_BYTE 0x0044 + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_0_ 0x0048 + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_1_ 0x0049 + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_2_ 0x004A + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_3_ 0x004B + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_4_ 0x004C + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_5_ 0x004D + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_6_ 0x004E + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_7_ 0x004F + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_8_ 0x0050 + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_9_ 0x0051 + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_10_ 0x0052 + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_11_ 0x0053 + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_12_ 0x0054 + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_13_ 0x0055 + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_14_ 0x0056 + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_15_ 0x0057 + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_16_ 0x0058 + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_17_ 0x0059 + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_18_ 0x005A + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_19_ 0x005B + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_20_ 0x005C + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_21_ 0x005D + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_22_ 0x005E + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_23_ 0x005F + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_24_ 0x0060 + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_25_ 0x0061 + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_26_ 0x0062 + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_27_ 0x0063 + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_28_ 0x0064 + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_29_ 0x0065 + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_30_ 0x0066 + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_31_ 0x0067 + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_REF__LOC1_0_ 0x0068 + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_REF__LOC1_1_ 0x0069 + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_REF__LOC1_2_ 0x006A + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_REF__LOC1_3_ 0x006B + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_REF__LOC1_4_ 0x006C + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_REF__LOC1_5_ 0x006D + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_REF__LOC2_0_ 0x0070 + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_REF__LOC2_1_ 0x0071 + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_REF__LOC2_2_ 0x0072 + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_REF__LOC2_3_ 0x0073 + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_REF__LOC2_4_ 0x0074 + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_REF__LOC2_5_ 0x0075 + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_REF__LOC3_0_ 0x0078 + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_REF__LOC3_1_ 0x0079 + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_REF__LOC3_2_ 0x007A + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_REF__LOC3_3_ 0x007B + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_REF__LOC3_4_ 0x007C + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_REF__LOC3_5_ 0x007D + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_0_ 0x0080 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_1_ 0x0081 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_2_ 0x0082 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_3_ 0x0083 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_4_ 0x0084 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_5_ 0x0085 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_6_ 0x0086 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_7_ 0x0087 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_8_ 0x0088 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_9_ 0x0089 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_10_ 0x008A + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_11_ 0x008B + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_12_ 0x008C + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_13_ 0x008D + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_14_ 0x008E + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_15_ 0x008F + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_16_ 0x0090 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_17_ 0x0091 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_18_ 0x0092 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_19_ 0x0093 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_20_ 0x0094 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_21_ 0x0095 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_22_ 0x0096 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_23_ 0x0097 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_24_ 0x0098 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_25_ 0x0099 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_26_ 0x009A + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_27_ 0x009B + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_28_ 0x009C + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_29_ 0x009D + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_30_ 0x009E + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_31_ 0x009F + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_REF__LOC1_0_ 0x00A0 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_REF__LOC1_1_ 0x00A1 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_REF__LOC1_2_ 0x00A2 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_REF__LOC1_3_ 0x00A3 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_REF__LOC1_4_ 0x00A4 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_REF__LOC1_5_ 0x00A5 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_REF__LOC2_0_ 0x00A8 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_REF__LOC2_1_ 0x00A9 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_REF__LOC2_2_ 0x00AA + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_REF__LOC2_3_ 0x00AB + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_REF__LOC2_4_ 0x00AC + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_REF__LOC2_5_ 0x00AD + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_REF__LOC3_0_ 0x00B0 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_REF__LOC3_1_ 0x00B1 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_REF__LOC3_2_ 0x00B2 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_REF__LOC3_3_ 0x00B3 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_REF__LOC3_4_ 0x00B4 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_REF__LOC3_5_ 0x00B5 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__ROI_CONFIG__MODE_ROI_CENTRE_SPAD 0x00B8 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__ROI_CONFIG__MODE_ROI_XY_SIZE 0x00B9 + + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__REF_SPAD_APPLY__NUM_REQUESTED_REF_SPAD 0x00BC + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__REF_SPAD_MAN__REF_LOCATION 0x00BD + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__MM_CONFIG__INNER_OFFSET_MM 0x00C0 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__MM_CONFIG__OUTER_OFFSET_MM 0x00C2 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__ALGO__PART_TO_PART_RANGE_OFFSET_MM 0x00C4 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__ALGO__CROSSTALK_COMPENSATION_PLANE_OFFSET_KCPS 0x00C8 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__ALGO__CROSSTALK_COMPENSATION_X_PLANE_GRADIENT_KCPS \ + 0x00CA + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__ALGO__CROSSTALK_COMPENSATION_Y_PLANE_GRADIENT_KCPS \ + 0x00CC + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPARE_HOST_CONFIG__NVM_CONFIG_SPARE_0 0x00CE + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPARE_HOST_CONFIG__NVM_CONFIG_SPARE_1 0x00CF + + + + + + + + + + + + + + + +#define VL53L1_NVM__CUSTOMER_NVM_SPACE_PROGRAMMED 0x00E0 + + + + + + + + + + + + + + + +#define VL53L1_NVM__CUST__I2C_SLAVE__DEVICE_ADDRESS 0x00E4 + + + + + + + + + + + + + + + +#define VL53L1_NVM__CUST__REF_SPAD_APPLY__NUM_REQUESTED_REF_SPAD 0x00E8 + + + + + + + + + + + + + + + +#define VL53L1_NVM__CUST__REF_SPAD_MAN__REF_LOCATION 0x00E9 + + + + + + + + + + + + + + + +#define VL53L1_NVM__CUST__MM_CONFIG__INNER_OFFSET_MM 0x00EC + + + + + + + + + + + + + + + +#define VL53L1_NVM__CUST__MM_CONFIG__OUTER_OFFSET_MM 0x00EE + + + + + + + + + + + + + + + +#define VL53L1_NVM__CUST__ALGO__PART_TO_PART_RANGE_OFFSET_MM 0x00F0 + + + + + + + + + + + + + + + +#define VL53L1_NVM__CUST__ALGO__CROSSTALK_COMPENSATION_PLANE_OFFSET_KCPS 0x00F4 + + + + + + + + + + + + + + + +#define VL53L1_NVM__CUST__ALGO__CROSSTALK_COMPENSATION_X_PLANE_GRADIENT_KCPS \ + 0x00F6 + + + + + + + + + + + + + + + +#define VL53L1_NVM__CUST__ALGO__CROSSTALK_COMPENSATION_Y_PLANE_GRADIENT_KCPS \ + 0x00F8 + + + + + + + + + + + + + + + +#define VL53L1_NVM__CUST__SPARE_HOST_CONFIG__NVM_CONFIG_SPARE_0 0x00FA + + + + + + + + + + + + + + + +#define VL53L1_NVM__CUST__SPARE_HOST_CONFIG__NVM_CONFIG_SPARE_1 0x00FB + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__FGC__BYTE_0 0x01DC + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__FGC__BYTE_1 0x01DD + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__FGC__BYTE_2 0x01DE + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__FGC__BYTE_3 0x01DF + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__FGC__BYTE_4 0x01E0 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__FGC__BYTE_5 0x01E1 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__FGC__BYTE_6 0x01E2 + + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__FGC__BYTE_7 0x01E3 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__FGC__BYTE_8 0x01E4 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__FGC__BYTE_9 0x01E5 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__FGC__BYTE_10 0x01E6 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__FGC__BYTE_11 0x01E7 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__FGC__BYTE_12 0x01E8 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__FGC__BYTE_13 0x01E9 + + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__FGC__BYTE_14 0x01EA + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__FGC__BYTE_15 0x01EB + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__TEST_PROGRAM_MAJOR_MINOR 0x01EC + + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__MAP_MAJOR_MINOR 0x01ED + + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__YEAR_MONTH 0x01EE + + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__DAY_MODULE_DATE_PHASE 0x01EF + + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__TIME 0x01F0 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__TESTER_ID 0x01F2 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SITE_ID 0x01F3 + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__TEST_PROGRAM_MAJOR_MINOR 0x01F4 + + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__PROBE_CARD_MAJOR_MINOR 0x01F5 + + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__TESTER_ID 0x01F6 + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__LOT__BYTE_0 0x01F8 + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__LOT__BYTE_1 0x01F9 + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__LOT__BYTE_2 0x01FA + + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__LOT__BYTE_3 0x01FB + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__LOT__BYTE_4 0x01FC + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__LOT__BYTE_5 0x01FD + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__WAFER 0x01FD + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__XCOORD 0x01FE + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__YCOORD 0x01FF + + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__OPTICAL_CENTRE_DATA_INDEX 0x00B8 +#define VL53L1_NVM__FMT__OPTICAL_CENTRE_DATA_SIZE 4 + +#define VL53L1_NVM__FMT__CAL_PEAK_RATE_MAP_DATA_INDEX 0x015C +#define VL53L1_NVM__FMT__CAL_PEAK_RATE_MAP_DATA_SIZE 56 + +#define VL53L1_NVM__FMT__ADDITIONAL_OFFSET_CAL_DATA_INDEX 0x0194 +#define VL53L1_NVM__FMT__ADDITIONAL_OFFSET_CAL_DATA_SIZE 8 + +#define VL53L1_NVM__FMT__RANGE_RESULTS__140MM_MM_PRE_RANGE 0x019C +#define VL53L1_NVM__FMT__RANGE_RESULTS__140MM_DARK 0x01AC +#define VL53L1_NVM__FMT__RANGE_RESULTS__400MM_DARK 0x01BC +#define VL53L1_NVM__FMT__RANGE_RESULTS__400MM_AMBIENT 0x01CC +#define VL53L1_NVM__FMT__RANGE_RESULTS__SIZE_BYTES 16 + + + + + + + + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/drivers/input/misc/vl53L1/lito/inc/vl53l1_nvm_structs.h b/drivers/input/misc/vl53L1/lito/inc/vl53l1_nvm_structs.h new file mode 100644 index 000000000000..4f9504034bc4 --- /dev/null +++ b/drivers/input/misc/vl53L1/lito/inc/vl53l1_nvm_structs.h @@ -0,0 +1,809 @@ + +/******************************************************************************* + * Copyright (c) 2017, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#ifndef _VL53L1_NVM_STRUCTS_H_ +#define _VL53L1_NVM_STRUCTS_H_ + + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include "vl53l1_platform.h" +#include "vl53l1_ll_def.h" + + + + + + + + + + +typedef struct { + + uint16_t result__actual_effective_rtn_spads; + + + uint8_t ref_spad_array__num_requested_ref_spads; + + + uint8_t ref_spad_array__ref_location; + + + uint16_t result__peak_signal_count_rate_rtn_mcps; + + + uint16_t result__ambient_count_rate_rtn_mcps; + + + uint16_t result__peak_signal_count_rate_ref_mcps; + + + uint16_t result__ambient_count_rate_ref_mcps; + + + uint16_t measured_distance_mm; + + + uint16_t measured_distance_stdev_mm; + + + +} VL53L1_decoded_nvm_fmt_range_data_t; + + + + + + + + + + +typedef struct { + + char nvm__fmt__fgc[19]; + + + uint8_t nvm__fmt__test_program_major; + + + + + + uint8_t nvm__fmt__test_program_minor; + + + + + + uint8_t nvm__fmt__map_major; + + + + + + uint8_t nvm__fmt__map_minor; + + + + + + uint8_t nvm__fmt__year; + + + + + + uint8_t nvm__fmt__month; + + + + + + uint8_t nvm__fmt__day; + + + + + + uint8_t nvm__fmt__module_date_phase; + + + + + + uint16_t nvm__fmt__time; + + + + + + uint8_t nvm__fmt__tester_id; + + + + + + uint8_t nvm__fmt__site_id; + + + + + + uint8_t nvm__ews__test_program_major; + + + + + + uint8_t nvm__ews__test_program_minor; + + + + + + uint8_t nvm__ews__probe_card_major; + + + + + + uint8_t nvm__ews__probe_card_minor; + + + + + + uint8_t nvm__ews__tester_id; + + + + + + + char nvm__ews__lot[8]; + + + uint8_t nvm__ews__wafer; + + + + + + uint8_t nvm__ews__xcoord; + + + + + + uint8_t nvm__ews__ycoord; + + + + + +} VL53L1_decoded_nvm_fmt_info_t; + + + + + + + + + + +typedef struct { + + uint8_t nvm__ews__test_program_major; + + + + + + uint8_t nvm__ews__test_program_minor; + + + + + + uint8_t nvm__ews__probe_card_major; + + + + + + uint8_t nvm__ews__probe_card_minor; + + + + + + uint8_t nvm__ews__tester_id; + + + + + + + char nvm__ews__lot[8]; + + + uint8_t nvm__ews__wafer; + + + + + + uint8_t nvm__ews__xcoord; + + + + + + uint8_t nvm__ews__ycoord; + + + + + + +} VL53L1_decoded_nvm_ews_info_t; + + + + + + + + + + +typedef struct { + uint8_t nvm__identification_model_id; + + + + + + uint8_t nvm__identification_module_type; + + + + + + uint8_t nvm__identification_revision_id; + + + + + + uint16_t nvm__identification_module_id; + + + + + + uint8_t nvm__i2c_valid; + + + + + + uint8_t nvm__i2c_device_address_ews; + + + + + + uint16_t nvm__ews__fast_osc_frequency; + + + + + + uint8_t nvm__ews__fast_osc_trim_max; + + + + + + uint8_t nvm__ews__fast_osc_freq_set; + + + + + + uint16_t nvm__ews__slow_osc_calibration; + + + + + + uint16_t nvm__fmt__fast_osc_frequency; + + + + + + uint8_t nvm__fmt__fast_osc_trim_max; + + + + + + uint8_t nvm__fmt__fast_osc_freq_set; + + + + + + uint16_t nvm__fmt__slow_osc_calibration; + + + + + + uint8_t nvm__vhv_config_unlock; + + + + + + uint8_t nvm__ref_selvddpix; + + + + + + uint8_t nvm__ref_selvquench; + + + + + + uint8_t nvm__regavdd1v2_sel; + + + + + + uint8_t nvm__regdvdd1v2_sel; + + + + + + uint8_t nvm__vhv_timeout__macrop; + + + + + + uint8_t nvm__vhv_loop_bound; + + + + + + uint8_t nvm__vhv_count_threshold; + + + + + + uint8_t nvm__vhv_offset; + + + + + + uint8_t nvm__vhv_init_enable; + + + + + + uint8_t nvm__vhv_init_value; + + + + + + uint8_t nvm__laser_safety_vcsel_trim_ll; + + + + + + uint8_t nvm__laser_safety_vcsel_selion_ll; + + + + + + uint8_t nvm__laser_safety_vcsel_selion_max_ll; + + + + + + uint8_t nvm__laser_safety_mult_ll; + + + + + + uint8_t nvm__laser_safety_clip_ll; + + + + + + uint8_t nvm__laser_safety_vcsel_trim_ld; + + + + + + uint8_t nvm__laser_safety_vcsel_selion_ld; + + + + + + uint8_t nvm__laser_safety_vcsel_selion_max_ld; + + + + + + uint8_t nvm__laser_safety_mult_ld; + + + + + + uint8_t nvm__laser_safety_clip_ld; + + + + + + uint8_t nvm__laser_safety_lock_byte; + + + + + + uint8_t nvm__laser_safety_unlock_byte; + + + + + + uint8_t nvm__ews__spad_enables_rtn[VL53L1_RTN_SPAD_BUFFER_SIZE]; + + + + + + uint8_t nvm__ews__spad_enables_ref__loc1[VL53L1_REF_SPAD_BUFFER_SIZE]; + + + + + + uint8_t nvm__ews__spad_enables_ref__loc2[VL53L1_REF_SPAD_BUFFER_SIZE]; + + + + + + uint8_t nvm__ews__spad_enables_ref__loc3[VL53L1_REF_SPAD_BUFFER_SIZE]; + + + + + + uint8_t nvm__fmt__spad_enables_rtn[VL53L1_RTN_SPAD_BUFFER_SIZE]; + + + + + + uint8_t nvm__fmt__spad_enables_ref__loc1[VL53L1_REF_SPAD_BUFFER_SIZE]; + + + + + + uint8_t nvm__fmt__spad_enables_ref__loc2[VL53L1_REF_SPAD_BUFFER_SIZE]; + + + + + + uint8_t nvm__fmt__spad_enables_ref__loc3[VL53L1_REF_SPAD_BUFFER_SIZE]; + + + + + + uint8_t nvm__fmt__roi_config__mode_roi_centre_spad; + + + + + + uint8_t nvm__fmt__roi_config__mode_roi_x_size; + + + + + + uint8_t nvm__fmt__roi_config__mode_roi_y_size; + + + + + + uint8_t nvm__fmt__ref_spad_apply__num_requested_ref_spad; + + + + + + uint8_t nvm__fmt__ref_spad_man__ref_location; + + + + + + uint16_t nvm__fmt__mm_config__inner_offset_mm; + + + + + + uint16_t nvm__fmt__mm_config__outer_offset_mm; + + + + + + uint16_t nvm__fmt__algo_part_to_part_range_offset_mm; + + + + + + uint16_t nvm__fmt__algo__crosstalk_compensation_plane_offset_kcps; + + + + + + uint16_t nvm__fmt__algo__crosstalk_compensation_x_plane_gradient_kcps; + + + + + + uint16_t nvm__fmt__algo__crosstalk_compensation_y_plane_gradient_kcps; + + + + + + uint8_t nvm__fmt__spare__host_config__nvm_config_spare_0; + + + + + + uint8_t nvm__fmt__spare__host_config__nvm_config_spare_1; + + + + + + uint8_t nvm__customer_space_programmed; + + + + + + uint8_t nvm__cust__i2c_device_address; + + + + + + uint8_t nvm__cust__ref_spad_apply__num_requested_ref_spad; + + + + + + uint8_t nvm__cust__ref_spad_man__ref_location; + + + + + + uint16_t nvm__cust__mm_config__inner_offset_mm; + + + + + + uint16_t nvm__cust__mm_config__outer_offset_mm; + + + + + + uint16_t nvm__cust__algo_part_to_part_range_offset_mm; + + + + + + uint16_t nvm__cust__algo__crosstalk_compensation_plane_offset_kcps; + + + + + + uint16_t nvm__cust__algo__crosstalk_compensation_x_plane_gradient_kcps; + + + + + + uint16_t nvm__cust__algo__crosstalk_compensation_y_plane_gradient_kcps; + + + + + + uint8_t nvm__cust__spare__host_config__nvm_config_spare_0; + + + + + + uint8_t nvm__cust__spare__host_config__nvm_config_spare_1; + + + + + + + VL53L1_optical_centre_t fmt_optical_centre; + VL53L1_cal_peak_rate_map_t fmt_peak_rate_map; + VL53L1_additional_offset_cal_data_t fmt_add_offset_data; + + VL53L1_decoded_nvm_fmt_range_data_t + fmt_range_data[VL53L1_NVM_MAX_FMT_RANGE_DATA]; + + VL53L1_decoded_nvm_fmt_info_t fmt_info; + VL53L1_decoded_nvm_ews_info_t ews_info; + +} VL53L1_decoded_nvm_data_t; + + + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/drivers/input/misc/vl53L1/lito/inc/vl53l1_preset_setup.h b/drivers/input/misc/vl53L1/lito/inc/vl53l1_preset_setup.h new file mode 100644 index 000000000000..2a93fe70f330 --- /dev/null +++ b/drivers/input/misc/vl53L1/lito/inc/vl53l1_preset_setup.h @@ -0,0 +1,110 @@ + +/****************************************************************************** + * Copyright (c) 2017, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + + ****************************************************************************** + + 'STMicroelectronics Proprietary license' + + ******************************************************************************* + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + + ******************************************************************************* + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones mentioned above : + + ******************************************************************************* + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + ******************************************************************************* + */ + +#ifndef _VL53L1_PRESET_SETUP_H_ +#define _VL53L1_PRESET_SETUP_H_ + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* indexes for the bare driver tuning setting API function */ +enum VL53L1_Tuning_t { + VL53L1_TUNING_VERSION = 0, + VL53L1_TUNING_PROXY_MIN, + VL53L1_TUNING_SINGLE_TARGET_XTALK_TARGET_DISTANCE_MM, + VL53L1_TUNING_SINGLE_TARGET_XTALK_SAMPLE_NUMBER, + VL53L1_TUNING_MIN_AMBIENT_DMAX_VALID, + VL53L1_TUNING_MAX_SIMPLE_OFFSET_CALIBRATION_SAMPLE_NUMBER, + VL53L1_TUNING_XTALK_FULL_ROI_TARGET_DISTANCE_MM, + VL53L1_TUNING_SIMPLE_OFFSET_CALIBRATION_REPEAT, + + VL53L1_TUNING_MAX_TUNABLE_KEY +}; + +/* default values for the tuning settings parameters */ +#define TUNING_VERSION 0x0004 + +#define TUNING_PROXY_MIN -30 /* min distance in mm */ +#define TUNING_SINGLE_TARGET_XTALK_TARGET_DISTANCE_MM 600 +/* Target distance in mm for single target Xtalk */ +#define TUNING_SINGLE_TARGET_XTALK_SAMPLE_NUMBER 50 +/* Number of sample used for single target Xtalk */ +#define TUNING_MIN_AMBIENT_DMAX_VALID 8 +/* Minimum ambient level to state the Dmax returned by the device is valid */ +#define TUNING_MAX_SIMPLE_OFFSET_CALIBRATION_SAMPLE_NUMBER 5 +/* Maximum loops to perform simple offset calibration */ +#define TUNING_XTALK_FULL_ROI_TARGET_DISTANCE_MM 600 +/* Target distance in mm for target Xtalk from Bins method*/ +#define TUNING_SIMPLE_OFFSET_CALIBRATION_REPEAT 3 +/* Number of loops done during the simple offset calibration*/ + +/* the following table should actually be defined as static and shall be part + * of the VL53L1_StaticInit() function code + */ + +#ifdef __cplusplus +} +#endif + +#endif /* _VL53L1_PRESET_SETUP_H_ */ diff --git a/drivers/input/misc/vl53L1/lito/inc/vl53l1_register_funcs.h b/drivers/input/misc/vl53L1/lito/inc/vl53l1_register_funcs.h new file mode 100644 index 000000000000..37f492699c46 --- /dev/null +++ b/drivers/input/misc/vl53L1/lito/inc/vl53l1_register_funcs.h @@ -0,0 +1,1694 @@ + +/******************************************************************************* + * Copyright (c) 2017, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#ifndef _VL53L1_REGISTER_FUNCS_H_ +#define _VL53L1_REGISTER_FUNCS_H_ + +#include "vl53l1_platform.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_encode_static_nvm_managed( + VL53L1_static_nvm_managed_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_decode_static_nvm_managed( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_static_nvm_managed_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_static_nvm_managed( + VL53L1_DEV Dev, + VL53L1_static_nvm_managed_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_static_nvm_managed( + VL53L1_DEV Dev, + VL53L1_static_nvm_managed_t *pdata); + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_encode_customer_nvm_managed( + VL53L1_customer_nvm_managed_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_decode_customer_nvm_managed( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_customer_nvm_managed_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_customer_nvm_managed( + VL53L1_DEV Dev, + VL53L1_customer_nvm_managed_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_customer_nvm_managed( + VL53L1_DEV Dev, + VL53L1_customer_nvm_managed_t *pdata); + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_encode_static_config( + VL53L1_static_config_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_decode_static_config( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_static_config_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_static_config( + VL53L1_DEV Dev, + VL53L1_static_config_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_static_config( + VL53L1_DEV Dev, + VL53L1_static_config_t *pdata); + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_encode_general_config( + VL53L1_general_config_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_decode_general_config( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_general_config_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_general_config( + VL53L1_DEV Dev, + VL53L1_general_config_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_general_config( + VL53L1_DEV Dev, + VL53L1_general_config_t *pdata); + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_encode_timing_config( + VL53L1_timing_config_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_decode_timing_config( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_timing_config_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_timing_config( + VL53L1_DEV Dev, + VL53L1_timing_config_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_timing_config( + VL53L1_DEV Dev, + VL53L1_timing_config_t *pdata); + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_encode_dynamic_config( + VL53L1_dynamic_config_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_decode_dynamic_config( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_dynamic_config_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_dynamic_config( + VL53L1_DEV Dev, + VL53L1_dynamic_config_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_dynamic_config( + VL53L1_DEV Dev, + VL53L1_dynamic_config_t *pdata); + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_encode_system_control( + VL53L1_system_control_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_decode_system_control( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_system_control_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_system_control( + VL53L1_DEV Dev, + VL53L1_system_control_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_system_control( + VL53L1_DEV Dev, + VL53L1_system_control_t *pdata); + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_encode_system_results( + VL53L1_system_results_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_decode_system_results( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_system_results_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_system_results( + VL53L1_DEV Dev, + VL53L1_system_results_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_system_results( + VL53L1_DEV Dev, + VL53L1_system_results_t *pdata); + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_encode_core_results( + VL53L1_core_results_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_decode_core_results( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_core_results_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_core_results( + VL53L1_DEV Dev, + VL53L1_core_results_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_core_results( + VL53L1_DEV Dev, + VL53L1_core_results_t *pdata); + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_encode_debug_results( + VL53L1_debug_results_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_decode_debug_results( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_debug_results_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_debug_results( + VL53L1_DEV Dev, + VL53L1_debug_results_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_debug_results( + VL53L1_DEV Dev, + VL53L1_debug_results_t *pdata); + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_encode_nvm_copy_data( + VL53L1_nvm_copy_data_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_decode_nvm_copy_data( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_nvm_copy_data_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_nvm_copy_data( + VL53L1_DEV Dev, + VL53L1_nvm_copy_data_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_nvm_copy_data( + VL53L1_DEV Dev, + VL53L1_nvm_copy_data_t *pdata); + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_encode_prev_shadow_system_results( + VL53L1_prev_shadow_system_results_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_decode_prev_shadow_system_results( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_prev_shadow_system_results_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_prev_shadow_system_results( + VL53L1_DEV Dev, + VL53L1_prev_shadow_system_results_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_prev_shadow_system_results( + VL53L1_DEV Dev, + VL53L1_prev_shadow_system_results_t *pdata); + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_encode_prev_shadow_core_results( + VL53L1_prev_shadow_core_results_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_decode_prev_shadow_core_results( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_prev_shadow_core_results_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_prev_shadow_core_results( + VL53L1_DEV Dev, + VL53L1_prev_shadow_core_results_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_prev_shadow_core_results( + VL53L1_DEV Dev, + VL53L1_prev_shadow_core_results_t *pdata); + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_encode_patch_debug( + VL53L1_patch_debug_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_decode_patch_debug( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_patch_debug_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_patch_debug( + VL53L1_DEV Dev, + VL53L1_patch_debug_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_patch_debug( + VL53L1_DEV Dev, + VL53L1_patch_debug_t *pdata); + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_encode_gph_general_config( + VL53L1_gph_general_config_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_decode_gph_general_config( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_gph_general_config_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_gph_general_config( + VL53L1_DEV Dev, + VL53L1_gph_general_config_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_gph_general_config( + VL53L1_DEV Dev, + VL53L1_gph_general_config_t *pdata); + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_encode_gph_static_config( + VL53L1_gph_static_config_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_decode_gph_static_config( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_gph_static_config_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_gph_static_config( + VL53L1_DEV Dev, + VL53L1_gph_static_config_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_gph_static_config( + VL53L1_DEV Dev, + VL53L1_gph_static_config_t *pdata); + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_encode_gph_timing_config( + VL53L1_gph_timing_config_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_decode_gph_timing_config( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_gph_timing_config_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_gph_timing_config( + VL53L1_DEV Dev, + VL53L1_gph_timing_config_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_gph_timing_config( + VL53L1_DEV Dev, + VL53L1_gph_timing_config_t *pdata); + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_encode_fw_internal( + VL53L1_fw_internal_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_decode_fw_internal( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_fw_internal_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_fw_internal( + VL53L1_DEV Dev, + VL53L1_fw_internal_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_fw_internal( + VL53L1_DEV Dev, + VL53L1_fw_internal_t *pdata); + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_encode_patch_results( + VL53L1_patch_results_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_decode_patch_results( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_patch_results_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_patch_results( + VL53L1_DEV Dev, + VL53L1_patch_results_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_patch_results( + VL53L1_DEV Dev, + VL53L1_patch_results_t *pdata); + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_encode_shadow_system_results( + VL53L1_shadow_system_results_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_decode_shadow_system_results( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_shadow_system_results_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_shadow_system_results( + VL53L1_DEV Dev, + VL53L1_shadow_system_results_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_shadow_system_results( + VL53L1_DEV Dev, + VL53L1_shadow_system_results_t *pdata); + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_encode_shadow_core_results( + VL53L1_shadow_core_results_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_decode_shadow_core_results( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_shadow_core_results_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_shadow_core_results( + VL53L1_DEV Dev, + VL53L1_shadow_core_results_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_shadow_core_results( + VL53L1_DEV Dev, + VL53L1_shadow_core_results_t *pdata); + + +#ifdef __cplusplus +} +#endif + +#endif + + diff --git a/drivers/input/misc/vl53L1/lito/inc/vl53l1_register_map.h b/drivers/input/misc/vl53L1/lito/inc/vl53l1_register_map.h new file mode 100644 index 000000000000..5b73b703b453 --- /dev/null +++ b/drivers/input/misc/vl53L1/lito/inc/vl53l1_register_map.h @@ -0,0 +1,13151 @@ + +/******************************************************************************* + * Copyright (c) 2017, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#ifndef _VL53L1_REGISTER_MAP_H_ +#define _VL53L1_REGISTER_MAP_H_ + + + + + + + +#define VL53L1_SOFT_RESET 0x0000 + + + + + + + +#define VL53L1_I2C_SLAVE__DEVICE_ADDRESS 0x0001 + + + + + + + + + + + + + + + +#define VL53L1_ANA_CONFIG__VHV_REF_SEL_VDDPIX 0x0002 + + + + + + + + + + + + + + + +#define VL53L1_ANA_CONFIG__VHV_REF_SEL_VQUENCH 0x0003 + + + + + + + + + + + + + + + +#define VL53L1_ANA_CONFIG__REG_AVDD1V2_SEL 0x0004 + + + + + + + + + + + + + + + +#define VL53L1_ANA_CONFIG__FAST_OSC__TRIM 0x0005 + + + + + + + + + + + + + + + +#define VL53L1_OSC_MEASURED__FAST_OSC__FREQUENCY 0x0006 + + + + + + + + + + + + + + + +#define VL53L1_OSC_MEASURED__FAST_OSC__FREQUENCY_HI 0x0006 + + + + + + + +#define VL53L1_OSC_MEASURED__FAST_OSC__FREQUENCY_LO 0x0007 + + + + + + + +#define VL53L1_VHV_CONFIG__TIMEOUT_MACROP_LOOP_BOUND 0x0008 + + + + + + + + + + + + + + + + +#define VL53L1_VHV_CONFIG__COUNT_THRESH 0x0009 + + + + + + + + + + + + + + + +#define VL53L1_VHV_CONFIG__OFFSET 0x000A + + + + + + + + + + + + + + + +#define VL53L1_VHV_CONFIG__INIT 0x000B + + + + + + + + + + + + + + + + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_REF_0 0x000D + + + + + + + + + + + + + + + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_REF_1 0x000E + + + + + + + + + + + + + + + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_REF_2 0x000F + + + + + + + + + + + + + + + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_REF_3 0x0010 + + + + + + + + + + + + + + + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_REF_4 0x0011 + + + + + + + + + + + + + + + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_REF_5 0x0012 + + + + + + + + + + + + + + + +#define VL53L1_GLOBAL_CONFIG__REF_EN_START_SELECT 0x0013 + + + + + + + + + + + + + + + +#define VL53L1_REF_SPAD_MAN__NUM_REQUESTED_REF_SPADS 0x0014 + + + + + + + + + + + + + + + +#define VL53L1_REF_SPAD_MAN__REF_LOCATION 0x0015 + + + + + + + + + + + + + + + +#define VL53L1_ALGO__CROSSTALK_COMPENSATION_PLANE_OFFSET_KCPS 0x0016 + + + + + + + + + + + + + + + + +#define VL53L1_ALGO__CROSSTALK_COMPENSATION_PLANE_OFFSET_KCPS_HI 0x0016 + + + + + + + +#define VL53L1_ALGO__CROSSTALK_COMPENSATION_PLANE_OFFSET_KCPS_LO 0x0017 + + + + + + + +#define VL53L1_ALGO__CROSSTALK_COMPENSATION_X_PLANE_GRADIENT_KCPS 0x0018 + + + + + + + + + + + + + + + + +#define VL53L1_ALGO__CROSSTALK_COMPENSATION_X_PLANE_GRADIENT_KCPS_HI 0x0018 + + + + + + + +#define VL53L1_ALGO__CROSSTALK_COMPENSATION_X_PLANE_GRADIENT_KCPS_LO 0x0019 + + + + + + + +#define VL53L1_ALGO__CROSSTALK_COMPENSATION_Y_PLANE_GRADIENT_KCPS 0x001A + + + + + + + + + + + + + + + + +#define VL53L1_ALGO__CROSSTALK_COMPENSATION_Y_PLANE_GRADIENT_KCPS_HI 0x001A + + + + + + + +#define VL53L1_ALGO__CROSSTALK_COMPENSATION_Y_PLANE_GRADIENT_KCPS_LO 0x001B + + + + + + + +#define VL53L1_REF_SPAD_CHAR__TOTAL_RATE_TARGET_MCPS 0x001C + + + + + + + + + + + + + + + + +#define VL53L1_REF_SPAD_CHAR__TOTAL_RATE_TARGET_MCPS_HI 0x001C + + + + + + + +#define VL53L1_REF_SPAD_CHAR__TOTAL_RATE_TARGET_MCPS_LO 0x001D + + + + + + + +#define VL53L1_ALGO__PART_TO_PART_RANGE_OFFSET_MM 0x001E + + + + + + + + + + + + + + + +#define VL53L1_ALGO__PART_TO_PART_RANGE_OFFSET_MM_HI 0x001E + + + + + + + +#define VL53L1_ALGO__PART_TO_PART_RANGE_OFFSET_MM_LO 0x001F + + + + + + + +#define VL53L1_MM_CONFIG__INNER_OFFSET_MM 0x0020 + + + + + + + + + + + + + + + +#define VL53L1_MM_CONFIG__INNER_OFFSET_MM_HI 0x0020 + + + + + + + +#define VL53L1_MM_CONFIG__INNER_OFFSET_MM_LO 0x0021 + + + + + + + +#define VL53L1_MM_CONFIG__OUTER_OFFSET_MM 0x0022 + + + + + + + + + + + + + + + +#define VL53L1_MM_CONFIG__OUTER_OFFSET_MM_HI 0x0022 + + + + + + + +#define VL53L1_MM_CONFIG__OUTER_OFFSET_MM_LO 0x0023 + + + + + + + +#define VL53L1_DSS_CONFIG__TARGET_TOTAL_RATE_MCPS 0x0024 + + + + + + + + + + + + + + + +#define VL53L1_DSS_CONFIG__TARGET_TOTAL_RATE_MCPS_HI 0x0024 + + + + + + + +#define VL53L1_DSS_CONFIG__TARGET_TOTAL_RATE_MCPS_LO 0x0025 + + + + + + + +#define VL53L1_DEBUG__CTRL 0x0026 + + + + + + + + + + + + + + + +#define VL53L1_TEST_MODE__CTRL 0x0027 + + + + + + + + + + + + + + + +#define VL53L1_CLK_GATING__CTRL 0x0028 + + + + + + + + + + + + + + + + + + +#define VL53L1_NVM_BIST__CTRL 0x0029 + + + + + + + + + + + + + + + + +#define VL53L1_NVM_BIST__NUM_NVM_WORDS 0x002A + + + + + + + + + + + + + + + +#define VL53L1_NVM_BIST__START_ADDRESS 0x002B + + + + + + + + + + + + + + + +#define VL53L1_HOST_IF__STATUS 0x002C + + + + + + + + + + + + + + + +#define VL53L1_PAD_I2C_HV__CONFIG 0x002D + + + + + + + + + + + + + + + + + + + + +#define VL53L1_PAD_I2C_HV__EXTSUP_CONFIG 0x002E + + + + + + + + + + + + + + + +#define VL53L1_GPIO_HV_PAD__CTRL 0x002F + + + + + + + + + + + + + + + + +#define VL53L1_GPIO_HV_MUX__CTRL 0x0030 + + + + + + + + + + + + + + + + +#define VL53L1_GPIO__TIO_HV_STATUS 0x0031 + + + + + + + + + + + + + + + + +#define VL53L1_GPIO__FIO_HV_STATUS 0x0032 + + + + + + + + + + + + + + + +#define VL53L1_ANA_CONFIG__SPAD_SEL_PSWIDTH 0x0033 + + + + + + + + + + + + + + + +#define VL53L1_ANA_CONFIG__VCSEL_PULSE_WIDTH_OFFSET 0x0034 + + + + + + + + + + + + + + + +#define VL53L1_ANA_CONFIG__FAST_OSC__CONFIG_CTRL 0x0035 + + + + + + + + + + + + + + + +#define VL53L1_SIGMA_ESTIMATOR__EFFECTIVE_PULSE_WIDTH_NS 0x0036 + + + + + + + + + + + + + + + +#define VL53L1_SIGMA_ESTIMATOR__EFFECTIVE_AMBIENT_WIDTH_NS 0x0037 + + + + + + + + + + + + + + + +#define VL53L1_SIGMA_ESTIMATOR__SIGMA_REF_MM 0x0038 + + + + + + + + + + + + + + + +#define VL53L1_ALGO__CROSSTALK_COMPENSATION_VALID_HEIGHT_MM 0x0039 + + + + + + + + + + + + + + + +#define VL53L1_SPARE_HOST_CONFIG__STATIC_CONFIG_SPARE_0 0x003A + + + + + + + + + + + + + + + +#define VL53L1_SPARE_HOST_CONFIG__STATIC_CONFIG_SPARE_1 0x003B + + + + + + + + + + + + + + + +#define VL53L1_ALGO__RANGE_IGNORE_THRESHOLD_MCPS 0x003C + + + + + + + + + + + + + + + +#define VL53L1_ALGO__RANGE_IGNORE_THRESHOLD_MCPS_HI 0x003C + + + + + + + +#define VL53L1_ALGO__RANGE_IGNORE_THRESHOLD_MCPS_LO 0x003D + + + + + + + +#define VL53L1_ALGO__RANGE_IGNORE_VALID_HEIGHT_MM 0x003E + + + + + + + + + + + + + + + +#define VL53L1_ALGO__RANGE_MIN_CLIP 0x003F + + + + + + + + + + + + + + + + +#define VL53L1_ALGO__CONSISTENCY_CHECK__TOLERANCE 0x0040 + + + + + + + + + + + + + + + +#define VL53L1_SPARE_HOST_CONFIG__STATIC_CONFIG_SPARE_2 0x0041 + + + + + + + + + + + + + + + +#define VL53L1_SD_CONFIG__RESET_STAGES_MSB 0x0042 + + + + + + + + + + + + + + + +#define VL53L1_SD_CONFIG__RESET_STAGES_LSB 0x0043 + + + + + + + + + + + + + + + + +#define VL53L1_GPH_CONFIG__STREAM_COUNT_UPDATE_VALUE 0x0044 + + + + + + + + + + + + + + + +#define VL53L1_GLOBAL_CONFIG__STREAM_DIVIDER 0x0045 + + + + + + + + + + + + + + + +#define VL53L1_SYSTEM__INTERRUPT_CONFIG_GPIO 0x0046 + + + + + + + + + + + + + + + + + + + + +#define VL53L1_CAL_CONFIG__VCSEL_START 0x0047 + + + + + + + + + + + + + + + +#define VL53L1_CAL_CONFIG__REPEAT_RATE 0x0048 + + + + + + + + + + + + + + + +#define VL53L1_CAL_CONFIG__REPEAT_RATE_HI 0x0048 + + + + + + + +#define VL53L1_CAL_CONFIG__REPEAT_RATE_LO 0x0049 + + + + + + + +#define VL53L1_GLOBAL_CONFIG__VCSEL_WIDTH 0x004A + + + + + + + + + + + + + + + +#define VL53L1_PHASECAL_CONFIG__TIMEOUT_MACROP 0x004B + + + + + + + + + + + + + + + +#define VL53L1_PHASECAL_CONFIG__TARGET 0x004C + + + + + + + + + + + + + + + +#define VL53L1_PHASECAL_CONFIG__OVERRIDE 0x004D + + + + + + + + + + + + + + + +#define VL53L1_DSS_CONFIG__ROI_MODE_CONTROL 0x004F + + + + + + + + + + + + + + + + +#define VL53L1_SYSTEM__THRESH_RATE_HIGH 0x0050 + + + + + + + + + + + + + + + +#define VL53L1_SYSTEM__THRESH_RATE_HIGH_HI 0x0050 + + + + + + + +#define VL53L1_SYSTEM__THRESH_RATE_HIGH_LO 0x0051 + + + + + + + +#define VL53L1_SYSTEM__THRESH_RATE_LOW 0x0052 + + + + + + + + + + + + + + + +#define VL53L1_SYSTEM__THRESH_RATE_LOW_HI 0x0052 + + + + + + + +#define VL53L1_SYSTEM__THRESH_RATE_LOW_LO 0x0053 + + + + + + + +#define VL53L1_DSS_CONFIG__MANUAL_EFFECTIVE_SPADS_SELECT 0x0054 + + + + + + + + + + + + + + + +#define VL53L1_DSS_CONFIG__MANUAL_EFFECTIVE_SPADS_SELECT_HI 0x0054 + + + + + + + +#define VL53L1_DSS_CONFIG__MANUAL_EFFECTIVE_SPADS_SELECT_LO 0x0055 + + + + + + + +#define VL53L1_DSS_CONFIG__MANUAL_BLOCK_SELECT 0x0056 + + + + + + + + + + + + + + + +#define VL53L1_DSS_CONFIG__APERTURE_ATTENUATION 0x0057 + + + + + + + + + + + + + + + +#define VL53L1_DSS_CONFIG__MAX_SPADS_LIMIT 0x0058 + + + + + + + + + + + + + + + +#define VL53L1_DSS_CONFIG__MIN_SPADS_LIMIT 0x0059 + + + + + + + + + + + + + + + +#define VL53L1_MM_CONFIG__TIMEOUT_MACROP_A_HI 0x005A + + + + + + + + + + + + + + + +#define VL53L1_MM_CONFIG__TIMEOUT_MACROP_A_LO 0x005B + + + + + + + + + + + + + + + +#define VL53L1_MM_CONFIG__TIMEOUT_MACROP_B_HI 0x005C + + + + + + + + + + + + + + + +#define VL53L1_MM_CONFIG__TIMEOUT_MACROP_B_LO 0x005D + + + + + + + + + + + + + + + +#define VL53L1_RANGE_CONFIG__TIMEOUT_MACROP_A_HI 0x005E + + + + + + + + + + + + + + + +#define VL53L1_RANGE_CONFIG__TIMEOUT_MACROP_A_LO 0x005F + + + + + + + + + + + + + + + +#define VL53L1_RANGE_CONFIG__VCSEL_PERIOD_A 0x0060 + + + + + + + + + + + + + + + +#define VL53L1_RANGE_CONFIG__TIMEOUT_MACROP_B_HI 0x0061 + + + + + + + + + + + + + + + +#define VL53L1_RANGE_CONFIG__TIMEOUT_MACROP_B_LO 0x0062 + + + + + + + + + + + + + + + +#define VL53L1_RANGE_CONFIG__VCSEL_PERIOD_B 0x0063 + + + + + + + + + + + + + + + +#define VL53L1_RANGE_CONFIG__SIGMA_THRESH 0x0064 + + + + + + + + + + + + + + + +#define VL53L1_RANGE_CONFIG__SIGMA_THRESH_HI 0x0064 + + + + + + + +#define VL53L1_RANGE_CONFIG__SIGMA_THRESH_LO 0x0065 + + + + + + + +#define VL53L1_RANGE_CONFIG__MIN_COUNT_RATE_RTN_LIMIT_MCPS 0x0066 + + + + + + + + + + + + + + + + +#define VL53L1_RANGE_CONFIG__MIN_COUNT_RATE_RTN_LIMIT_MCPS_HI 0x0066 + + + + + + + +#define VL53L1_RANGE_CONFIG__MIN_COUNT_RATE_RTN_LIMIT_MCPS_LO 0x0067 + + + + + + + +#define VL53L1_RANGE_CONFIG__VALID_PHASE_LOW 0x0068 + + + + + + + + + + + + + + + +#define VL53L1_RANGE_CONFIG__VALID_PHASE_HIGH 0x0069 + + + + + + + + + + + + + + + +#define VL53L1_SYSTEM__INTERMEASUREMENT_PERIOD 0x006C + + + + + + + + + + + + + + + +#define VL53L1_SYSTEM__INTERMEASUREMENT_PERIOD_3 0x006C + + + + + + + +#define VL53L1_SYSTEM__INTERMEASUREMENT_PERIOD_2 0x006D + + + + + + + +#define VL53L1_SYSTEM__INTERMEASUREMENT_PERIOD_1 0x006E + + + + + + + +#define VL53L1_SYSTEM__INTERMEASUREMENT_PERIOD_0 0x006F + + + + + + + +#define VL53L1_SYSTEM__FRACTIONAL_ENABLE 0x0070 + + + + + + + + + + + + + + + +#define VL53L1_SYSTEM__GROUPED_PARAMETER_HOLD_0 0x0071 + + + + + + + + + + + + + + + + +#define VL53L1_SYSTEM__THRESH_HIGH 0x0072 + + + + + + + + + + + + + + + +#define VL53L1_SYSTEM__THRESH_HIGH_HI 0x0072 + + + + + + + +#define VL53L1_SYSTEM__THRESH_HIGH_LO 0x0073 + + + + + + + +#define VL53L1_SYSTEM__THRESH_LOW 0x0074 + + + + + + + + + + + + + + + +#define VL53L1_SYSTEM__THRESH_LOW_HI 0x0074 + + + + + + + +#define VL53L1_SYSTEM__THRESH_LOW_LO 0x0075 + + + + + + + +#define VL53L1_SYSTEM__ENABLE_XTALK_PER_QUADRANT 0x0076 + + + + + + + + + + + + + + + +#define VL53L1_SYSTEM__SEED_CONFIG 0x0077 + + + + + + + + + + + + + + + + +#define VL53L1_SD_CONFIG__WOI_SD0 0x0078 + + + + + + + + + + + + + + + +#define VL53L1_SD_CONFIG__WOI_SD1 0x0079 + + + + + + + + + + + + + + + +#define VL53L1_SD_CONFIG__INITIAL_PHASE_SD0 0x007A + + + + + + + + + + + + + + + +#define VL53L1_SD_CONFIG__INITIAL_PHASE_SD1 0x007B + + + + + + + + + + + + + + + +#define VL53L1_SYSTEM__GROUPED_PARAMETER_HOLD_1 0x007C + + + + + + + + + + + + + + + + +#define VL53L1_SD_CONFIG__FIRST_ORDER_SELECT 0x007D + + + + + + + + + + + + + + + + +#define VL53L1_SD_CONFIG__QUANTIFIER 0x007E + + + + + + + + + + + + + + + +#define VL53L1_ROI_CONFIG__USER_ROI_CENTRE_SPAD 0x007F + + + + + + + + + + + + + + + +#define VL53L1_ROI_CONFIG__USER_ROI_REQUESTED_GLOBAL_XY_SIZE 0x0080 + + + + + + + + + + + + + + + +#define VL53L1_SYSTEM__SEQUENCE_CONFIG 0x0081 + + + + + + + + + + + + + + + + + + + + + + +#define VL53L1_SYSTEM__GROUPED_PARAMETER_HOLD 0x0082 + + + + + + + + + + + + + + + + +#define VL53L1_POWER_MANAGEMENT__GO1_POWER_FORCE 0x0083 + + + + + + + + + + + + + + + +#define VL53L1_SYSTEM__STREAM_COUNT_CTRL 0x0084 + + + + + + + + + + + + + + + +#define VL53L1_FIRMWARE__ENABLE 0x0085 + + + + + + + + + + + + + + + +#define VL53L1_SYSTEM__INTERRUPT_CLEAR 0x0086 + + + + + + + + + + + + + + + + +#define VL53L1_SYSTEM__MODE_START 0x0087 + + + + + + + + + + + + + + + + + + + + +#define VL53L1_RESULT__INTERRUPT_STATUS 0x0088 + + + + + + + + + + + + + + + + + +#define VL53L1_RESULT__RANGE_STATUS 0x0089 + + + + + + + + + + + + + + + + + + +#define VL53L1_RESULT__REPORT_STATUS 0x008A + + + + + + + + + + + + + + + +#define VL53L1_RESULT__STREAM_COUNT 0x008B + + + + + + + + + + + + + + + +#define VL53L1_RESULT__DSS_ACTUAL_EFFECTIVE_SPADS_SD0 0x008C + + + + + + + + + + + + + + + + +#define VL53L1_RESULT__DSS_ACTUAL_EFFECTIVE_SPADS_SD0_HI 0x008C + + + + + + + +#define VL53L1_RESULT__DSS_ACTUAL_EFFECTIVE_SPADS_SD0_LO 0x008D + + + + + + + +#define VL53L1_RESULT__PEAK_SIGNAL_COUNT_RATE_MCPS_SD0 0x008E + + + + + + + + + + + + + + + + +#define VL53L1_RESULT__PEAK_SIGNAL_COUNT_RATE_MCPS_SD0_HI 0x008E + + + + + + + +#define VL53L1_RESULT__PEAK_SIGNAL_COUNT_RATE_MCPS_SD0_LO 0x008F + + + + + + + +#define VL53L1_RESULT__AMBIENT_COUNT_RATE_MCPS_SD0 0x0090 + + + + + + + + + + + + + + + + +#define VL53L1_RESULT__AMBIENT_COUNT_RATE_MCPS_SD0_HI 0x0090 + + + + + + + +#define VL53L1_RESULT__AMBIENT_COUNT_RATE_MCPS_SD0_LO 0x0091 + + + + + + + +#define VL53L1_RESULT__SIGMA_SD0 0x0092 + + + + + + + + + + + + + + + +#define VL53L1_RESULT__SIGMA_SD0_HI 0x0092 + + + + + + + +#define VL53L1_RESULT__SIGMA_SD0_LO 0x0093 + + + + + + + +#define VL53L1_RESULT__PHASE_SD0 0x0094 + + + + + + + + + + + + + + + +#define VL53L1_RESULT__PHASE_SD0_HI 0x0094 + + + + + + + +#define VL53L1_RESULT__PHASE_SD0_LO 0x0095 + + + + + + + +#define VL53L1_RESULT__FINAL_CROSSTALK_CORRECTED_RANGE_MM_SD0 0x0096 + + + + + + + + + + + + + + + +#define VL53L1_RESULT__FINAL_CROSSTALK_CORRECTED_RANGE_MM_SD0_HI 0x0096 + + + + + + + +#define VL53L1_RESULT__FINAL_CROSSTALK_CORRECTED_RANGE_MM_SD0_LO 0x0097 + + + + + + + +#define VL53L1_PEAK_SIGNAL_COUNT_RATE_CROSSTALK_CORRECTED_MCPS_SD0 0x0098 + + + + + + + + + + + + + +#define VL53L1__PEAK_SIGNAL_COUNT_RATE_CROSSTALK_CORRECTED_MCPS_SD0_HI 0x0098 + + + + + + + +#define VL53L1___PEAK_SIGNAL_COUNT_RATE_CROSSTALK_CORRECTED_MCPS_SD0_LO 0x0099 + + + + + + + +#define VL53L1_RESULT__MM_INNER_ACTUAL_EFFECTIVE_SPADS_SD0 0x009A + + + + + + + + + + + + + + + + +#define VL53L1_RESULT__MM_INNER_ACTUAL_EFFECTIVE_SPADS_SD0_HI 0x009A + + + + + + + +#define VL53L1_RESULT__MM_INNER_ACTUAL_EFFECTIVE_SPADS_SD0_LO 0x009B + + + + + + + +#define VL53L1_RESULT__MM_OUTER_ACTUAL_EFFECTIVE_SPADS_SD0 0x009C + + + + + + + + + + + + + + + + +#define VL53L1_RESULT__MM_OUTER_ACTUAL_EFFECTIVE_SPADS_SD0_HI 0x009C + + + + + + + +#define VL53L1_RESULT__MM_OUTER_ACTUAL_EFFECTIVE_SPADS_SD0_LO 0x009D + + + + + + + +#define VL53L1_RESULT__AVG_SIGNAL_COUNT_RATE_MCPS_SD0 0x009E + + + + + + + + + + + + + + + + +#define VL53L1_RESULT__AVG_SIGNAL_COUNT_RATE_MCPS_SD0_HI 0x009E + + + + + + + +#define VL53L1_RESULT__AVG_SIGNAL_COUNT_RATE_MCPS_SD0_LO 0x009F + + + + + + + +#define VL53L1_RESULT__DSS_ACTUAL_EFFECTIVE_SPADS_SD1 0x00A0 + + + + + + + + + + + + + + + + +#define VL53L1_RESULT__DSS_ACTUAL_EFFECTIVE_SPADS_SD1_HI 0x00A0 + + + + + + + +#define VL53L1_RESULT__DSS_ACTUAL_EFFECTIVE_SPADS_SD1_LO 0x00A1 + + + + + + + +#define VL53L1_RESULT__PEAK_SIGNAL_COUNT_RATE_MCPS_SD1 0x00A2 + + + + + + + + + + + + + + + + +#define VL53L1_RESULT__PEAK_SIGNAL_COUNT_RATE_MCPS_SD1_HI 0x00A2 + + + + + + + +#define VL53L1_RESULT__PEAK_SIGNAL_COUNT_RATE_MCPS_SD1_LO 0x00A3 + + + + + + + +#define VL53L1_RESULT__AMBIENT_COUNT_RATE_MCPS_SD1 0x00A4 + + + + + + + + + + + + + + + +#define VL53L1_RESULT__AMBIENT_COUNT_RATE_MCPS_SD1_HI 0x00A4 + + + + + + + +#define VL53L1_RESULT__AMBIENT_COUNT_RATE_MCPS_SD1_LO 0x00A5 + + + + + + + +#define VL53L1_RESULT__SIGMA_SD1 0x00A6 + + + + + + + + + + + + + + + +#define VL53L1_RESULT__SIGMA_SD1_HI 0x00A6 + + + + + + + +#define VL53L1_RESULT__SIGMA_SD1_LO 0x00A7 + + + + + + + +#define VL53L1_RESULT__PHASE_SD1 0x00A8 + + + + + + + + + + + + + + + +#define VL53L1_RESULT__PHASE_SD1_HI 0x00A8 + + + + + + + +#define VL53L1_RESULT__PHASE_SD1_LO 0x00A9 + + + + + + + +#define VL53L1_RESULT__FINAL_CROSSTALK_CORRECTED_RANGE_MM_SD1 0x00AA + + + + + + + + + + + + + + + +#define VL53L1_RESULT__FINAL_CROSSTALK_CORRECTED_RANGE_MM_SD1_HI 0x00AA + + + + + + + +#define VL53L1_RESULT__FINAL_CROSSTALK_CORRECTED_RANGE_MM_SD1_LO 0x00AB + + + + + + + +#define VL53L1_RESULT__SPARE_0_SD1 0x00AC + + + + + + + + + + + + + + + +#define VL53L1_RESULT__SPARE_0_SD1_HI 0x00AC + + + + + + + +#define VL53L1_RESULT__SPARE_0_SD1_LO 0x00AD + + + + + + + +#define VL53L1_RESULT__SPARE_1_SD1 0x00AE + + + + + + + + + + + + + + + +#define VL53L1_RESULT__SPARE_1_SD1_HI 0x00AE + + + + + + + +#define VL53L1_RESULT__SPARE_1_SD1_LO 0x00AF + + + + + + + +#define VL53L1_RESULT__SPARE_2_SD1 0x00B0 + + + + + + + + + + + + + + + +#define VL53L1_RESULT__SPARE_2_SD1_HI 0x00B0 + + + + + + + +#define VL53L1_RESULT__SPARE_2_SD1_LO 0x00B1 + + + + + + + +#define VL53L1_RESULT__SPARE_3_SD1 0x00B2 + + + + + + + + + + + + + + + +#define VL53L1_RESULT__THRESH_INFO 0x00B3 + + + + + + + + + + + + + + + + +#define VL53L1_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD0 0x00B4 + + + + + + + + + + + + + + + +#define VL53L1_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD0_3 0x00B4 + + + + + + + +#define VL53L1_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD0_2 0x00B5 + + + + + + + +#define VL53L1_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD0_1 0x00B6 + + + + + + + +#define VL53L1_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD0_0 0x00B7 + + + + + + + +#define VL53L1_RESULT_CORE__RANGING_TOTAL_EVENTS_SD0 0x00B8 + + + + + + + + + + + + + + + +#define VL53L1_RESULT_CORE__RANGING_TOTAL_EVENTS_SD0_3 0x00B8 + + + + + + + +#define VL53L1_RESULT_CORE__RANGING_TOTAL_EVENTS_SD0_2 0x00B9 + + + + + + + +#define VL53L1_RESULT_CORE__RANGING_TOTAL_EVENTS_SD0_1 0x00BA + + + + + + + +#define VL53L1_RESULT_CORE__RANGING_TOTAL_EVENTS_SD0_0 0x00BB + + + + + + + +#define VL53L1_RESULT_CORE__SIGNAL_TOTAL_EVENTS_SD0 0x00BC + + + + + + + + + + + + + + + +#define VL53L1_RESULT_CORE__SIGNAL_TOTAL_EVENTS_SD0_3 0x00BC + + + + + + + +#define VL53L1_RESULT_CORE__SIGNAL_TOTAL_EVENTS_SD0_2 0x00BD + + + + + + + +#define VL53L1_RESULT_CORE__SIGNAL_TOTAL_EVENTS_SD0_1 0x00BE + + + + + + + +#define VL53L1_RESULT_CORE__SIGNAL_TOTAL_EVENTS_SD0_0 0x00BF + + + + + + + +#define VL53L1_RESULT_CORE__TOTAL_PERIODS_ELAPSED_SD0 0x00C0 + + + + + + + + + + + + + + + +#define VL53L1_RESULT_CORE__TOTAL_PERIODS_ELAPSED_SD0_3 0x00C0 + + + + + + + +#define VL53L1_RESULT_CORE__TOTAL_PERIODS_ELAPSED_SD0_2 0x00C1 + + + + + + + +#define VL53L1_RESULT_CORE__TOTAL_PERIODS_ELAPSED_SD0_1 0x00C2 + + + + + + + +#define VL53L1_RESULT_CORE__TOTAL_PERIODS_ELAPSED_SD0_0 0x00C3 + + + + + + + +#define VL53L1_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD1 0x00C4 + + + + + + + + + + + + + + + +#define VL53L1_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD1_3 0x00C4 + + + + + + + +#define VL53L1_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD1_2 0x00C5 + + + + + + + +#define VL53L1_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD1_1 0x00C6 + + + + + + + +#define VL53L1_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD1_0 0x00C7 + + + + + + + +#define VL53L1_RESULT_CORE__RANGING_TOTAL_EVENTS_SD1 0x00C8 + + + + + + + + + + + + + + + +#define VL53L1_RESULT_CORE__RANGING_TOTAL_EVENTS_SD1_3 0x00C8 + + + + + + + +#define VL53L1_RESULT_CORE__RANGING_TOTAL_EVENTS_SD1_2 0x00C9 + + + + + + + +#define VL53L1_RESULT_CORE__RANGING_TOTAL_EVENTS_SD1_1 0x00CA + + + + + + + +#define VL53L1_RESULT_CORE__RANGING_TOTAL_EVENTS_SD1_0 0x00CB + + + + + + + +#define VL53L1_RESULT_CORE__SIGNAL_TOTAL_EVENTS_SD1 0x00CC + + + + + + + + + + + + + + + +#define VL53L1_RESULT_CORE__SIGNAL_TOTAL_EVENTS_SD1_3 0x00CC + + + + + + + +#define VL53L1_RESULT_CORE__SIGNAL_TOTAL_EVENTS_SD1_2 0x00CD + + + + + + + +#define VL53L1_RESULT_CORE__SIGNAL_TOTAL_EVENTS_SD1_1 0x00CE + + + + + + + +#define VL53L1_RESULT_CORE__SIGNAL_TOTAL_EVENTS_SD1_0 0x00CF + + + + + + + +#define VL53L1_RESULT_CORE__TOTAL_PERIODS_ELAPSED_SD1 0x00D0 + + + + + + + + + + + + + + + +#define VL53L1_RESULT_CORE__TOTAL_PERIODS_ELAPSED_SD1_3 0x00D0 + + + + + + + +#define VL53L1_RESULT_CORE__TOTAL_PERIODS_ELAPSED_SD1_2 0x00D1 + + + + + + + +#define VL53L1_RESULT_CORE__TOTAL_PERIODS_ELAPSED_SD1_1 0x00D2 + + + + + + + +#define VL53L1_RESULT_CORE__TOTAL_PERIODS_ELAPSED_SD1_0 0x00D3 + + + + + + + +#define VL53L1_RESULT_CORE__SPARE_0 0x00D4 + + + + + + + + + + + + + + + +#define VL53L1_PHASECAL_RESULT__REFERENCE_PHASE 0x00D6 + + + + + + + + + + + + + + + +#define VL53L1_PHASECAL_RESULT__REFERENCE_PHASE_HI 0x00D6 + + + + + + + +#define VL53L1_PHASECAL_RESULT__REFERENCE_PHASE_LO 0x00D7 + + + + + + + +#define VL53L1_PHASECAL_RESULT__VCSEL_START 0x00D8 + + + + + + + + + + + + + + + +#define VL53L1_REF_SPAD_CHAR_RESULT__NUM_ACTUAL_REF_SPADS 0x00D9 + + + + + + + + + + + + + + + +#define VL53L1_REF_SPAD_CHAR_RESULT__REF_LOCATION 0x00DA + + + + + + + + + + + + + + + +#define VL53L1_VHV_RESULT__COLDBOOT_STATUS 0x00DB + + + + + + + + + + + + + + + +#define VL53L1_VHV_RESULT__SEARCH_RESULT 0x00DC + + + + + + + + + + + + + + + +#define VL53L1_VHV_RESULT__LATEST_SETTING 0x00DD + + + + + + + + + + + + + + + +#define VL53L1_RESULT__OSC_CALIBRATE_VAL 0x00DE + + + + + + + + + + + + + + + +#define VL53L1_RESULT__OSC_CALIBRATE_VAL_HI 0x00DE + + + + + + + +#define VL53L1_RESULT__OSC_CALIBRATE_VAL_LO 0x00DF + + + + + + + +#define VL53L1_ANA_CONFIG__POWERDOWN_GO1 0x00E0 + + + + + + + + + + + + + + + + +#define VL53L1_ANA_CONFIG__REF_BG_CTRL 0x00E1 + + + + + + + + + + + + + + + + +#define VL53L1_ANA_CONFIG__REGDVDD1V2_CTRL 0x00E2 + + + + + + + + + + + + + + + + + +#define VL53L1_ANA_CONFIG__OSC_SLOW_CTRL 0x00E3 + + + + + + + + + + + + + + + + + +#define VL53L1_TEST_MODE__STATUS 0x00E4 + + + + + + + + + + + + + + + +#define VL53L1_FIRMWARE__SYSTEM_STATUS 0x00E5 + + + + + + + + + + + + + + + + +#define VL53L1_FIRMWARE__MODE_STATUS 0x00E6 + + + + + + + + + + + + + + + +#define VL53L1_FIRMWARE__SECONDARY_MODE_STATUS 0x00E7 + + + + + + + + + + + + + + + +#define VL53L1_FIRMWARE__CAL_REPEAT_RATE_COUNTER 0x00E8 + + + + + + + + + + + + + + + +#define VL53L1_FIRMWARE__CAL_REPEAT_RATE_COUNTER_HI 0x00E8 + + + + + + + +#define VL53L1_FIRMWARE__CAL_REPEAT_RATE_COUNTER_LO 0x00E9 + + + + + + + +#define VL53L1_FIRMWARE__HISTOGRAM_BIN 0x00EA + + + + + + + +#define VL53L1_GPH__SYSTEM__THRESH_HIGH 0x00EC + + + + + + + + + + + + + + + +#define VL53L1_GPH__SYSTEM__THRESH_HIGH_HI 0x00EC + + + + + + + +#define VL53L1_GPH__SYSTEM__THRESH_HIGH_LO 0x00ED + + + + + + + +#define VL53L1_GPH__SYSTEM__THRESH_LOW 0x00EE + + + + + + + + + + + + + + + +#define VL53L1_GPH__SYSTEM__THRESH_LOW_HI 0x00EE + + + + + + + +#define VL53L1_GPH__SYSTEM__THRESH_LOW_LO 0x00EF + + + + + + + +#define VL53L1_GPH__SYSTEM__ENABLE_XTALK_PER_QUADRANT 0x00F0 + + + + + + + + + + + + + + + +#define VL53L1_GPH__SPARE_0 0x00F1 + + + + + + + + + + + + + + + + + +#define VL53L1_GPH__SD_CONFIG__WOI_SD0 0x00F2 + + + + + + + + + + + + + + + +#define VL53L1_GPH__SD_CONFIG__WOI_SD1 0x00F3 + + + + + + + + + + + + + + + +#define VL53L1_GPH__SD_CONFIG__INITIAL_PHASE_SD0 0x00F4 + + + + + + + + + + + + + + + +#define VL53L1_GPH__SD_CONFIG__INITIAL_PHASE_SD1 0x00F5 + + + + + + + + + + + + + + + +#define VL53L1_GPH__SD_CONFIG__FIRST_ORDER_SELECT 0x00F6 + + + + + + + + + + + + + + + + +#define VL53L1_GPH__SD_CONFIG__QUANTIFIER 0x00F7 + + + + + + + + + + + + + + + +#define VL53L1_GPH__ROI_CONFIG__USER_ROI_CENTRE_SPAD 0x00F8 + + + + + + + + + + + + + + + +#define VL53L1_GPH__ROI_CONFIG__USER_ROI_REQUESTED_GLOBAL_XY_SIZE 0x00F9 + + + + + + + + + + + + + + + +#define VL53L1_GPH__SYSTEM__SEQUENCE_CONFIG 0x00FA + + + + + + + + + + + + + + + + + + + + + + +#define VL53L1_GPH__GPH_ID 0x00FB + + + + + + + + + + + + + + + +#define VL53L1_SYSTEM__INTERRUPT_SET 0x00FC + + + + + + + + + + + + + + + + +#define VL53L1_INTERRUPT_MANAGER__ENABLES 0x00FD + + + + + + + + + + + + + + + + + + + +#define VL53L1_INTERRUPT_MANAGER__CLEAR 0x00FE + + + + + + + + + + + + + + + + + + + +#define VL53L1_INTERRUPT_MANAGER__STATUS 0x00FF + + + + + + + + + + + + + + + + + + + +#define VL53L1_MCU_TO_HOST_BANK__WR_ACCESS_EN 0x0100 + + + + + + + + + + + + + + + +#define VL53L1_POWER_MANAGEMENT__GO1_RESET_STATUS 0x0101 + + + + + + + + + + + + + + + +#define VL53L1_PAD_STARTUP_MODE__VALUE_RO 0x0102 + + + + + + + + + + + + + + + + +#define VL53L1_PAD_STARTUP_MODE__VALUE_CTRL 0x0103 + + + + + + + + + + + + + + + + + + +#define VL53L1_PLL_PERIOD_US 0x0104 + + + + + + + + + + + + + + + +#define VL53L1_PLL_PERIOD_US_3 0x0104 + + + + + + + +#define VL53L1_PLL_PERIOD_US_2 0x0105 + + + + + + + +#define VL53L1_PLL_PERIOD_US_1 0x0106 + + + + + + + +#define VL53L1_PLL_PERIOD_US_0 0x0107 + + + + + + + +#define VL53L1_INTERRUPT_SCHEDULER__DATA_OUT 0x0108 + + + + + + + + + + + + + + + +#define VL53L1_INTERRUPT_SCHEDULER__DATA_OUT_3 0x0108 + + + + + + + +#define VL53L1_INTERRUPT_SCHEDULER__DATA_OUT_2 0x0109 + + + + + + + +#define VL53L1_INTERRUPT_SCHEDULER__DATA_OUT_1 0x010A + + + + + + + +#define VL53L1_INTERRUPT_SCHEDULER__DATA_OUT_0 0x010B + + + + + + + +#define VL53L1_NVM_BIST__COMPLETE 0x010C + + + + + + + + + + + + + + + +#define VL53L1_NVM_BIST__STATUS 0x010D + + + + + + + + + + + + + + + +#define VL53L1_IDENTIFICATION__MODEL_ID 0x010F + + + + + + + + + + + + + + + +#define VL53L1_IDENTIFICATION__MODULE_TYPE 0x0110 + + + + + + + + + + + + + + + +#define VL53L1_IDENTIFICATION__REVISION_ID 0x0111 + + + + + + + + + + + + + + + + +#define VL53L1_IDENTIFICATION__MODULE_ID 0x0112 + + + + + + + + + + + + + + + +#define VL53L1_IDENTIFICATION__MODULE_ID_HI 0x0112 + + + + + + + +#define VL53L1_IDENTIFICATION__MODULE_ID_LO 0x0113 + + + + + + + +#define VL53L1_ANA_CONFIG__FAST_OSC__TRIM_MAX 0x0114 + + + + + + + + + + + + + + + +#define VL53L1_ANA_CONFIG__FAST_OSC__FREQ_SET 0x0115 + + + + + + + + + + + + + + + +#define VL53L1_ANA_CONFIG__VCSEL_TRIM 0x0116 + + + + + + + + + + + + + + + +#define VL53L1_ANA_CONFIG__VCSEL_SELION 0x0117 + + + + + + + + + + + + + + + +#define VL53L1_ANA_CONFIG__VCSEL_SELION_MAX 0x0118 + + + + + + + + + + + + + + + +#define VL53L1_PROTECTED_LASER_SAFETY__LOCK_BIT 0x0119 + + + + + + + + + + + + + + + +#define VL53L1_LASER_SAFETY__KEY 0x011A + + + + + + + + + + + + + + + +#define VL53L1_LASER_SAFETY__KEY_RO 0x011B + + + + + + + + + + + + + + + +#define VL53L1_LASER_SAFETY__CLIP 0x011C + + + + + + + + + + + + + + + +#define VL53L1_LASER_SAFETY__MULT 0x011D + + + + + + + + + + + + + + + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_0 0x011E + + + + + + + + + + + + + + + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_1 0x011F + + + + + + + + + + + + + + + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_2 0x0120 + + + + + + + + + + + + + + + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_3 0x0121 + + + + + + + + + + + + + + + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_4 0x0122 + + + + + + + + + + + + + + + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_5 0x0123 + + + + + + + + + + + + + + + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_6 0x0124 + + + + + + + + + + + + + + + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_7 0x0125 + + + + + + + + + + + + + + + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_8 0x0126 + + + + + + + + + + + + + + + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_9 0x0127 + + + + + + + + + + + + + + + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_10 0x0128 + + + + + + + + + + + + + + + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_11 0x0129 + + + + + + + + + + + + + + + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_12 0x012A + + + + + + + + + + + + + + + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_13 0x012B + + + + + + + + + + + + + + + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_14 0x012C + + + + + + + + + + + + + + + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_15 0x012D + + + + + + + + + + + + + + + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_16 0x012E + + + + + + + + + + + + + + + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_17 0x012F + + + + + + + + + + + + + + + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_18 0x0130 + + + + + + + + + + + + + + + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_19 0x0131 + + + + + + + + + + + + + + + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_20 0x0132 + + + + + + + + + + + + + + + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_21 0x0133 + + + + + + + + + + + + + + + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_22 0x0134 + + + + + + + + + + + + + + + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_23 0x0135 + + + + + + + + + + + + + + + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_24 0x0136 + + + + + + + + + + + + + + + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_25 0x0137 + + + + + + + + + + + + + + + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_26 0x0138 + + + + + + + + + + + + + + + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_27 0x0139 + + + + + + + + + + + + + + + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_28 0x013A + + + + + + + + + + + + + + + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_29 0x013B + + + + + + + + + + + + + + + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_30 0x013C + + + + + + + + + + + + + + + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_31 0x013D + + + + + + + + + + + + + + + +#define VL53L1_ROI_CONFIG__MODE_ROI_CENTRE_SPAD 0x013E + + + + + + + + + + + + + + + +#define VL53L1_ROI_CONFIG__MODE_ROI_XY_SIZE 0x013F + + + + + + + + + + + + + + + +#define VL53L1_GO2_HOST_BANK_ACCESS__OVERRIDE 0x0300 + + + + + + + +#define VL53L1_MCU_UTIL_MULTIPLIER__MULTIPLICAND 0x0400 + + + + + + + +#define VL53L1_MCU_UTIL_MULTIPLIER__MULTIPLICAND_3 0x0400 + + + + + + + +#define VL53L1_MCU_UTIL_MULTIPLIER__MULTIPLICAND_2 0x0401 + + + + + + + +#define VL53L1_MCU_UTIL_MULTIPLIER__MULTIPLICAND_1 0x0402 + + + + + + + +#define VL53L1_MCU_UTIL_MULTIPLIER__MULTIPLICAND_0 0x0403 + + + + + + + +#define VL53L1_MCU_UTIL_MULTIPLIER__MULTIPLIER 0x0404 + + + + + + + +#define VL53L1_MCU_UTIL_MULTIPLIER__MULTIPLIER_3 0x0404 + + + + + + + +#define VL53L1_MCU_UTIL_MULTIPLIER__MULTIPLIER_2 0x0405 + + + + + + + +#define VL53L1_MCU_UTIL_MULTIPLIER__MULTIPLIER_1 0x0406 + + + + + + + +#define VL53L1_MCU_UTIL_MULTIPLIER__MULTIPLIER_0 0x0407 + + + + + + + +#define VL53L1_MCU_UTIL_MULTIPLIER__PRODUCT_HI 0x0408 + + + + + + + +#define VL53L1_MCU_UTIL_MULTIPLIER__PRODUCT_HI_3 0x0408 + + + + + + + +#define VL53L1_MCU_UTIL_MULTIPLIER__PRODUCT_HI_2 0x0409 + + + + + + + +#define VL53L1_MCU_UTIL_MULTIPLIER__PRODUCT_HI_1 0x040A + + + + + + + +#define VL53L1_MCU_UTIL_MULTIPLIER__PRODUCT_HI_0 0x040B + + + + + + + +#define VL53L1_MCU_UTIL_MULTIPLIER__PRODUCT_LO 0x040C + + + + + + + +#define VL53L1_MCU_UTIL_MULTIPLIER__PRODUCT_LO_3 0x040C + + + + + + + +#define VL53L1_MCU_UTIL_MULTIPLIER__PRODUCT_LO_2 0x040D + + + + + + + +#define VL53L1_MCU_UTIL_MULTIPLIER__PRODUCT_LO_1 0x040E + + + + + + + +#define VL53L1_MCU_UTIL_MULTIPLIER__PRODUCT_LO_0 0x040F + + + + + + + +#define VL53L1_MCU_UTIL_MULTIPLIER__START 0x0410 + + + + + + + +#define VL53L1_MCU_UTIL_MULTIPLIER__STATUS 0x0411 + + + + + + + +#define VL53L1_MCU_UTIL_DIVIDER__START 0x0412 + + + + + + + +#define VL53L1_MCU_UTIL_DIVIDER__STATUS 0x0413 + + + + + + + +#define VL53L1_MCU_UTIL_DIVIDER__DIVIDEND 0x0414 + + + + + + + +#define VL53L1_MCU_UTIL_DIVIDER__DIVIDEND_3 0x0414 + + + + + + + +#define VL53L1_MCU_UTIL_DIVIDER__DIVIDEND_2 0x0415 + + + + + + + +#define VL53L1_MCU_UTIL_DIVIDER__DIVIDEND_1 0x0416 + + + + + + + +#define VL53L1_MCU_UTIL_DIVIDER__DIVIDEND_0 0x0417 + + + + + + + +#define VL53L1_MCU_UTIL_DIVIDER__DIVISOR 0x0418 + + + + + + + +#define VL53L1_MCU_UTIL_DIVIDER__DIVISOR_3 0x0418 + + + + + + + +#define VL53L1_MCU_UTIL_DIVIDER__DIVISOR_2 0x0419 + + + + + + + +#define VL53L1_MCU_UTIL_DIVIDER__DIVISOR_1 0x041A + + + + + + + +#define VL53L1_MCU_UTIL_DIVIDER__DIVISOR_0 0x041B + + + + + + + +#define VL53L1_MCU_UTIL_DIVIDER__QUOTIENT 0x041C + + + + + + + +#define VL53L1_MCU_UTIL_DIVIDER__QUOTIENT_3 0x041C + + + + + + + +#define VL53L1_MCU_UTIL_DIVIDER__QUOTIENT_2 0x041D + + + + + + + +#define VL53L1_MCU_UTIL_DIVIDER__QUOTIENT_1 0x041E + + + + + + + +#define VL53L1_MCU_UTIL_DIVIDER__QUOTIENT_0 0x041F + + + + + + + +#define VL53L1_TIMER0__VALUE_IN 0x0420 + + + + + + + +#define VL53L1_TIMER0__VALUE_IN_3 0x0420 + + + + + + + +#define VL53L1_TIMER0__VALUE_IN_2 0x0421 + + + + + + + +#define VL53L1_TIMER0__VALUE_IN_1 0x0422 + + + + + + + +#define VL53L1_TIMER0__VALUE_IN_0 0x0423 + + + + + + + +#define VL53L1_TIMER1__VALUE_IN 0x0424 + + + + + + + +#define VL53L1_TIMER1__VALUE_IN_3 0x0424 + + + + + + + +#define VL53L1_TIMER1__VALUE_IN_2 0x0425 + + + + + + + +#define VL53L1_TIMER1__VALUE_IN_1 0x0426 + + + + + + + +#define VL53L1_TIMER1__VALUE_IN_0 0x0427 + + + + + + + +#define VL53L1_TIMER0__CTRL 0x0428 + + + + + + + +#define VL53L1_TIMER1__CTRL 0x0429 + + + + + + + +#define VL53L1_MCU_GENERAL_PURPOSE__GP_0 0x042C + + + + + + + + + + + + + + + +#define VL53L1_MCU_GENERAL_PURPOSE__GP_1 0x042D + + + + + + + + + + + + + + + +#define VL53L1_MCU_GENERAL_PURPOSE__GP_2 0x042E + + + + + + + + + + + + + + + +#define VL53L1_MCU_GENERAL_PURPOSE__GP_3 0x042F + + + + + + + + + + + + + + + +#define VL53L1_MCU_RANGE_CALC__CONFIG 0x0430 + + + + + + + + + + + + + + + + + + + + + +#define VL53L1_MCU_RANGE_CALC__OFFSET_CORRECTED_RANGE 0x0432 + + + + + + + + + + + + + + + +#define VL53L1_MCU_RANGE_CALC__OFFSET_CORRECTED_RANGE_HI 0x0432 + + + + + + + +#define VL53L1_MCU_RANGE_CALC__OFFSET_CORRECTED_RANGE_LO 0x0433 + + + + + + + +#define VL53L1_MCU_RANGE_CALC__SPARE_4 0x0434 + + + + + + + + + + + + + + + +#define VL53L1_MCU_RANGE_CALC__SPARE_4_3 0x0434 + + + + + + + +#define VL53L1_MCU_RANGE_CALC__SPARE_4_2 0x0435 + + + + + + + +#define VL53L1_MCU_RANGE_CALC__SPARE_4_1 0x0436 + + + + + + + +#define VL53L1_MCU_RANGE_CALC__SPARE_4_0 0x0437 + + + + + + + +#define VL53L1_MCU_RANGE_CALC__AMBIENT_DURATION_PRE_CALC 0x0438 + + + + + + + + + + + + + + + +#define VL53L1_MCU_RANGE_CALC__AMBIENT_DURATION_PRE_CALC_HI 0x0438 + + + + + + + +#define VL53L1_MCU_RANGE_CALC__AMBIENT_DURATION_PRE_CALC_LO 0x0439 + + + + + + + +#define VL53L1_MCU_RANGE_CALC__ALGO_VCSEL_PERIOD 0x043C + + + + + + + + + + + + + + + +#define VL53L1_MCU_RANGE_CALC__SPARE_5 0x043D + + + + + + + + + + + + + + + +#define VL53L1_MCU_RANGE_CALC__ALGO_TOTAL_PERIODS 0x043E + + + + + + + + + + + + + + + +#define VL53L1_MCU_RANGE_CALC__ALGO_TOTAL_PERIODS_HI 0x043E + + + + + + + +#define VL53L1_MCU_RANGE_CALC__ALGO_TOTAL_PERIODS_LO 0x043F + + + + + + + +#define VL53L1_MCU_RANGE_CALC__ALGO_ACCUM_PHASE 0x0440 + + + + + + + + + + + + + + + +#define VL53L1_MCU_RANGE_CALC__ALGO_ACCUM_PHASE_3 0x0440 + + + + + + + +#define VL53L1_MCU_RANGE_CALC__ALGO_ACCUM_PHASE_2 0x0441 + + + + + + + +#define VL53L1_MCU_RANGE_CALC__ALGO_ACCUM_PHASE_1 0x0442 + + + + + + + +#define VL53L1_MCU_RANGE_CALC__ALGO_ACCUM_PHASE_0 0x0443 + + + + + + + +#define VL53L1_MCU_RANGE_CALC__ALGO_SIGNAL_EVENTS 0x0444 + + + + + + + + + + + + + + + +#define VL53L1_MCU_RANGE_CALC__ALGO_SIGNAL_EVENTS_3 0x0444 + + + + + + + +#define VL53L1_MCU_RANGE_CALC__ALGO_SIGNAL_EVENTS_2 0x0445 + + + + + + + +#define VL53L1_MCU_RANGE_CALC__ALGO_SIGNAL_EVENTS_1 0x0446 + + + + + + + +#define VL53L1_MCU_RANGE_CALC__ALGO_SIGNAL_EVENTS_0 0x0447 + + + + + + + +#define VL53L1_MCU_RANGE_CALC__ALGO_AMBIENT_EVENTS 0x0448 + + + + + + + + + + + + + + + +#define VL53L1_MCU_RANGE_CALC__ALGO_AMBIENT_EVENTS_3 0x0448 + + + + + + + +#define VL53L1_MCU_RANGE_CALC__ALGO_AMBIENT_EVENTS_2 0x0449 + + + + + + + +#define VL53L1_MCU_RANGE_CALC__ALGO_AMBIENT_EVENTS_1 0x044A + + + + + + + +#define VL53L1_MCU_RANGE_CALC__ALGO_AMBIENT_EVENTS_0 0x044B + + + + + + + +#define VL53L1_MCU_RANGE_CALC__SPARE_6 0x044C + + + + + + + + + + + + + + + +#define VL53L1_MCU_RANGE_CALC__SPARE_6_HI 0x044C + + + + + + + +#define VL53L1_MCU_RANGE_CALC__SPARE_6_LO 0x044D + + + + + + + +#define VL53L1_MCU_RANGE_CALC__ALGO_ADJUST_VCSEL_PERIOD 0x044E + + + + + + + + + + + + + + + +#define VL53L1_MCU_RANGE_CALC__ALGO_ADJUST_VCSEL_PERIOD_HI 0x044E + + + + + + + +#define VL53L1_MCU_RANGE_CALC__ALGO_ADJUST_VCSEL_PERIOD_LO 0x044F + + + + + + + +#define VL53L1_MCU_RANGE_CALC__NUM_SPADS 0x0450 + + + + + + + + + + + + + + + +#define VL53L1_MCU_RANGE_CALC__NUM_SPADS_HI 0x0450 + + + + + + + +#define VL53L1_MCU_RANGE_CALC__NUM_SPADS_LO 0x0451 + + + + + + + +#define VL53L1_MCU_RANGE_CALC__PHASE_OUTPUT 0x0452 + + + + + + + + + + + + + + + +#define VL53L1_MCU_RANGE_CALC__PHASE_OUTPUT_HI 0x0452 + + + + + + + +#define VL53L1_MCU_RANGE_CALC__PHASE_OUTPUT_LO 0x0453 + + + + + + + +#define VL53L1_MCU_RANGE_CALC__RATE_PER_SPAD_MCPS 0x0454 + + + + + + + + + + + + + + + +#define VL53L1_MCU_RANGE_CALC__RATE_PER_SPAD_MCPS_3 0x0454 + + + + + + + +#define VL53L1_MCU_RANGE_CALC__RATE_PER_SPAD_MCPS_2 0x0455 + + + + + + + +#define VL53L1_MCU_RANGE_CALC__RATE_PER_SPAD_MCPS_1 0x0456 + + + + + + + +#define VL53L1_MCU_RANGE_CALC__RATE_PER_SPAD_MCPS_0 0x0457 + + + + + + + +#define VL53L1_MCU_RANGE_CALC__SPARE_7 0x0458 + + + + + + + + + + + + + + + +#define VL53L1_MCU_RANGE_CALC__SPARE_8 0x0459 + + + + + + + + + + + + + + + +#define VL53L1_MCU_RANGE_CALC__PEAK_SIGNAL_RATE_MCPS 0x045A + + + + + + + + + + + + + + + +#define VL53L1_MCU_RANGE_CALC__PEAK_SIGNAL_RATE_MCPS_HI 0x045A + + + + + + + +#define VL53L1_MCU_RANGE_CALC__PEAK_SIGNAL_RATE_MCPS_LO 0x045B + + + + + + + +#define VL53L1_MCU_RANGE_CALC__AVG_SIGNAL_RATE_MCPS 0x045C + + + + + + + + + + + + + + + +#define VL53L1_MCU_RANGE_CALC__AVG_SIGNAL_RATE_MCPS_HI 0x045C + + + + + + + +#define VL53L1_MCU_RANGE_CALC__AVG_SIGNAL_RATE_MCPS_LO 0x045D + + + + + + + +#define VL53L1_MCU_RANGE_CALC__AMBIENT_RATE_MCPS 0x045E + + + + + + + + + + + + + + + +#define VL53L1_MCU_RANGE_CALC__AMBIENT_RATE_MCPS_HI 0x045E + + + + + + + +#define VL53L1_MCU_RANGE_CALC__AMBIENT_RATE_MCPS_LO 0x045F + + + + + + + +#define VL53L1_MCU_RANGE_CALC__XTALK 0x0460 + + + + + + + + + + + + + + + +#define VL53L1_MCU_RANGE_CALC__XTALK_HI 0x0460 + + + + + + + +#define VL53L1_MCU_RANGE_CALC__XTALK_LO 0x0461 + + + + + + + +#define VL53L1_MCU_RANGE_CALC__CALC_STATUS 0x0462 + + + + + + + + + + + + + + + +#define VL53L1_MCU_RANGE_CALC__DEBUG 0x0463 + + + + + + + + + + + + + + + +#define VL53L1_MCU_RANGE_CALC__PEAK_SIGNAL_RATE_XTALK_CORR_MCPS 0x0464 + + + + + + + + + + + + + + + +#define VL53L1_MCU_RANGE_CALC__PEAK_SIGNAL_RATE_XTALK_CORR_MCPS_HI 0x0464 + + + + + + + +#define VL53L1_MCU_RANGE_CALC__PEAK_SIGNAL_RATE_XTALK_CORR_MCPS_LO 0x0465 + + + + + + + +#define VL53L1_MCU_RANGE_CALC__SPARE_0 0x0468 + + + + + + + + + + + + + + + +#define VL53L1_MCU_RANGE_CALC__SPARE_1 0x0469 + + + + + + + + + + + + + + + +#define VL53L1_MCU_RANGE_CALC__SPARE_2 0x046A + + + + + + + + + + + + + + + +#define VL53L1_MCU_RANGE_CALC__SPARE_3 0x046B + + + + + + + + + + + + + + + +#define VL53L1_PATCH__CTRL 0x0470 + + + + + + + +#define VL53L1_PATCH__JMP_ENABLES 0x0472 + + + + + + + +#define VL53L1_PATCH__JMP_ENABLES_HI 0x0472 + + + + + + + +#define VL53L1_PATCH__JMP_ENABLES_LO 0x0473 + + + + + + + +#define VL53L1_PATCH__DATA_ENABLES 0x0474 + + + + + + + +#define VL53L1_PATCH__DATA_ENABLES_HI 0x0474 + + + + + + + +#define VL53L1_PATCH__DATA_ENABLES_LO 0x0475 + + + + + + + +#define VL53L1_PATCH__OFFSET_0 0x0476 + + + + + + + +#define VL53L1_PATCH__OFFSET_0_HI 0x0476 + + + + + + + +#define VL53L1_PATCH__OFFSET_0_LO 0x0477 + + + + + + + +#define VL53L1_PATCH__OFFSET_1 0x0478 + + + + + + + +#define VL53L1_PATCH__OFFSET_1_HI 0x0478 + + + + + + + +#define VL53L1_PATCH__OFFSET_1_LO 0x0479 + + + + + + + +#define VL53L1_PATCH__OFFSET_2 0x047A + + + + + + + +#define VL53L1_PATCH__OFFSET_2_HI 0x047A + + + + + + + +#define VL53L1_PATCH__OFFSET_2_LO 0x047B + + + + + + + +#define VL53L1_PATCH__OFFSET_3 0x047C + + + + + + + +#define VL53L1_PATCH__OFFSET_3_HI 0x047C + + + + + + + +#define VL53L1_PATCH__OFFSET_3_LO 0x047D + + + + + + + +#define VL53L1_PATCH__OFFSET_4 0x047E + + + + + + + +#define VL53L1_PATCH__OFFSET_4_HI 0x047E + + + + + + + +#define VL53L1_PATCH__OFFSET_4_LO 0x047F + + + + + + + +#define VL53L1_PATCH__OFFSET_5 0x0480 + + + + + + + +#define VL53L1_PATCH__OFFSET_5_HI 0x0480 + + + + + + + +#define VL53L1_PATCH__OFFSET_5_LO 0x0481 + + + + + + + +#define VL53L1_PATCH__OFFSET_6 0x0482 + + + + + + + +#define VL53L1_PATCH__OFFSET_6_HI 0x0482 + + + + + + + +#define VL53L1_PATCH__OFFSET_6_LO 0x0483 + + + + + + + +#define VL53L1_PATCH__OFFSET_7 0x0484 + + + + + + + +#define VL53L1_PATCH__OFFSET_7_HI 0x0484 + + + + + + + +#define VL53L1_PATCH__OFFSET_7_LO 0x0485 + + + + + + + +#define VL53L1_PATCH__OFFSET_8 0x0486 + + + + + + + +#define VL53L1_PATCH__OFFSET_8_HI 0x0486 + + + + + + + +#define VL53L1_PATCH__OFFSET_8_LO 0x0487 + + + + + + + +#define VL53L1_PATCH__OFFSET_9 0x0488 + + + + + + + +#define VL53L1_PATCH__OFFSET_9_HI 0x0488 + + + + + + + +#define VL53L1_PATCH__OFFSET_9_LO 0x0489 + + + + + + + +#define VL53L1_PATCH__OFFSET_10 0x048A + + + + + + + +#define VL53L1_PATCH__OFFSET_10_HI 0x048A + + + + + + + +#define VL53L1_PATCH__OFFSET_10_LO 0x048B + + + + + + + +#define VL53L1_PATCH__OFFSET_11 0x048C + + + + + + + +#define VL53L1_PATCH__OFFSET_11_HI 0x048C + + + + + + + +#define VL53L1_PATCH__OFFSET_11_LO 0x048D + + + + + + + +#define VL53L1_PATCH__OFFSET_12 0x048E + + + + + + + +#define VL53L1_PATCH__OFFSET_12_HI 0x048E + + + + + + + +#define VL53L1_PATCH__OFFSET_12_LO 0x048F + + + + + + + +#define VL53L1_PATCH__OFFSET_13 0x0490 + + + + + + + +#define VL53L1_PATCH__OFFSET_13_HI 0x0490 + + + + + + + +#define VL53L1_PATCH__OFFSET_13_LO 0x0491 + + + + + + + +#define VL53L1_PATCH__OFFSET_14 0x0492 + + + + + + + +#define VL53L1_PATCH__OFFSET_14_HI 0x0492 + + + + + + + +#define VL53L1_PATCH__OFFSET_14_LO 0x0493 + + + + + + + +#define VL53L1_PATCH__OFFSET_15 0x0494 + + + + + + + +#define VL53L1_PATCH__OFFSET_15_HI 0x0494 + + + + + + + +#define VL53L1_PATCH__OFFSET_15_LO 0x0495 + + + + + + + +#define VL53L1_PATCH__ADDRESS_0 0x0496 + + + + + + + +#define VL53L1_PATCH__ADDRESS_0_HI 0x0496 + + + + + + + +#define VL53L1_PATCH__ADDRESS_0_LO 0x0497 + + + + + + + +#define VL53L1_PATCH__ADDRESS_1 0x0498 + + + + + + + +#define VL53L1_PATCH__ADDRESS_1_HI 0x0498 + + + + + + + +#define VL53L1_PATCH__ADDRESS_1_LO 0x0499 + + + + + + + +#define VL53L1_PATCH__ADDRESS_2 0x049A + + + + + + + +#define VL53L1_PATCH__ADDRESS_2_HI 0x049A + + + + + + + +#define VL53L1_PATCH__ADDRESS_2_LO 0x049B + + + + + + + +#define VL53L1_PATCH__ADDRESS_3 0x049C + + + + + + + +#define VL53L1_PATCH__ADDRESS_3_HI 0x049C + + + + + + + +#define VL53L1_PATCH__ADDRESS_3_LO 0x049D + + + + + + + +#define VL53L1_PATCH__ADDRESS_4 0x049E + + + + + + + +#define VL53L1_PATCH__ADDRESS_4_HI 0x049E + + + + + + + +#define VL53L1_PATCH__ADDRESS_4_LO 0x049F + + + + + + + +#define VL53L1_PATCH__ADDRESS_5 0x04A0 + + + + + + + +#define VL53L1_PATCH__ADDRESS_5_HI 0x04A0 + + + + + + + +#define VL53L1_PATCH__ADDRESS_5_LO 0x04A1 + + + + + + + +#define VL53L1_PATCH__ADDRESS_6 0x04A2 + + + + + + + +#define VL53L1_PATCH__ADDRESS_6_HI 0x04A2 + + + + + + + +#define VL53L1_PATCH__ADDRESS_6_LO 0x04A3 + + + + + + + +#define VL53L1_PATCH__ADDRESS_7 0x04A4 + + + + + + + +#define VL53L1_PATCH__ADDRESS_7_HI 0x04A4 + + + + + + + +#define VL53L1_PATCH__ADDRESS_7_LO 0x04A5 + + + + + + + +#define VL53L1_PATCH__ADDRESS_8 0x04A6 + + + + + + + +#define VL53L1_PATCH__ADDRESS_8_HI 0x04A6 + + + + + + + +#define VL53L1_PATCH__ADDRESS_8_LO 0x04A7 + + + + + + + +#define VL53L1_PATCH__ADDRESS_9 0x04A8 + + + + + + + +#define VL53L1_PATCH__ADDRESS_9_HI 0x04A8 + + + + + + + +#define VL53L1_PATCH__ADDRESS_9_LO 0x04A9 + + + + + + + +#define VL53L1_PATCH__ADDRESS_10 0x04AA + + + + + + + +#define VL53L1_PATCH__ADDRESS_10_HI 0x04AA + + + + + + + +#define VL53L1_PATCH__ADDRESS_10_LO 0x04AB + + + + + + + +#define VL53L1_PATCH__ADDRESS_11 0x04AC + + + + + + + +#define VL53L1_PATCH__ADDRESS_11_HI 0x04AC + + + + + + + +#define VL53L1_PATCH__ADDRESS_11_LO 0x04AD + + + + + + + +#define VL53L1_PATCH__ADDRESS_12 0x04AE + + + + + + + +#define VL53L1_PATCH__ADDRESS_12_HI 0x04AE + + + + + + + +#define VL53L1_PATCH__ADDRESS_12_LO 0x04AF + + + + + + + +#define VL53L1_PATCH__ADDRESS_13 0x04B0 + + + + + + + +#define VL53L1_PATCH__ADDRESS_13_HI 0x04B0 + + + + + + + +#define VL53L1_PATCH__ADDRESS_13_LO 0x04B1 + + + + + + + +#define VL53L1_PATCH__ADDRESS_14 0x04B2 + + + + + + + +#define VL53L1_PATCH__ADDRESS_14_HI 0x04B2 + + + + + + + +#define VL53L1_PATCH__ADDRESS_14_LO 0x04B3 + + + + + + + +#define VL53L1_PATCH__ADDRESS_15 0x04B4 + + + + + + + +#define VL53L1_PATCH__ADDRESS_15_HI 0x04B4 + + + + + + + +#define VL53L1_PATCH__ADDRESS_15_LO 0x04B5 + + + + + + + +#define VL53L1_SPI_ASYNC_MUX__CTRL 0x04C0 + + + + + + + +#define VL53L1_CLK__CONFIG 0x04C4 + + + + + + + + + + + + + + + +#define VL53L1_GPIO_LV_MUX__CTRL 0x04CC + + + + + + + + + + + + + + + + +#define VL53L1_GPIO_LV_PAD__CTRL 0x04CD + + + + + + + + + + + + + + + +#define VL53L1_PAD_I2C_LV__CONFIG 0x04D0 + + + + + + + +#define VL53L1_PAD_STARTUP_MODE__VALUE_RO_GO1 0x04D4 + + + + + + + + + + + + + + + +#define VL53L1_HOST_IF__STATUS_GO1 0x04D5 + + + + + + + + + + + + + + + +#define VL53L1_MCU_CLK_GATING__CTRL 0x04D8 + + + + + + + + + + + + + + + + + + +#define VL53L1_TEST__BIST_ROM_CTRL 0x04E0 + + + + + + + +#define VL53L1_TEST__BIST_ROM_RESULT 0x04E1 + + + + + + + +#define VL53L1_TEST__BIST_ROM_MCU_SIG 0x04E2 + + + + + + + +#define VL53L1_TEST__BIST_ROM_MCU_SIG_HI 0x04E2 + + + + + + + +#define VL53L1_TEST__BIST_ROM_MCU_SIG_LO 0x04E3 + + + + + + + +#define VL53L1_TEST__BIST_RAM_CTRL 0x04E4 + + + + + + + +#define VL53L1_TEST__BIST_RAM_RESULT 0x04E5 + + + + + + + +#define VL53L1_TEST__TMC 0x04E8 + + + + + + + +#define VL53L1_TEST__PLL_BIST_MIN_THRESHOLD 0x04F0 + + + + + + + +#define VL53L1_TEST__PLL_BIST_MIN_THRESHOLD_HI 0x04F0 + + + + + + + +#define VL53L1_TEST__PLL_BIST_MIN_THRESHOLD_LO 0x04F1 + + + + + + + +#define VL53L1_TEST__PLL_BIST_MAX_THRESHOLD 0x04F2 + + + + + + + +#define VL53L1_TEST__PLL_BIST_MAX_THRESHOLD_HI 0x04F2 + + + + + + + +#define VL53L1_TEST__PLL_BIST_MAX_THRESHOLD_LO 0x04F3 + + + + + + + +#define VL53L1_TEST__PLL_BIST_COUNT_OUT 0x04F4 + + + + + + + +#define VL53L1_TEST__PLL_BIST_COUNT_OUT_HI 0x04F4 + + + + + + + +#define VL53L1_TEST__PLL_BIST_COUNT_OUT_LO 0x04F5 + + + + + + + +#define VL53L1_TEST__PLL_BIST_GONOGO 0x04F6 + + + + + + + +#define VL53L1_TEST__PLL_BIST_CTRL 0x04F7 + + + + + + + +#define VL53L1_RANGING_CORE__DEVICE_ID 0x0680 + + + + + + + +#define VL53L1_RANGING_CORE__REVISION_ID 0x0681 + + + + + + + +#define VL53L1_RANGING_CORE__CLK_CTRL1 0x0683 + + + + + + + +#define VL53L1_RANGING_CORE__CLK_CTRL2 0x0684 + + + + + + + +#define VL53L1_RANGING_CORE__WOI_1 0x0685 + + + + + + + +#define VL53L1_RANGING_CORE__WOI_REF_1 0x0686 + + + + + + + +#define VL53L1_RANGING_CORE__START_RANGING 0x0687 + + + + + + + +#define VL53L1_RANGING_CORE__LOW_LIMIT_1 0x0690 + + + + + + + +#define VL53L1_RANGING_CORE__HIGH_LIMIT_1 0x0691 + + + + + + + +#define VL53L1_RANGING_CORE__LOW_LIMIT_REF_1 0x0692 + + + + + + + +#define VL53L1_RANGING_CORE__HIGH_LIMIT_REF_1 0x0693 + + + + + + + +#define VL53L1_RANGING_CORE__QUANTIFIER_1_MSB 0x0694 + + + + + + + +#define VL53L1_RANGING_CORE__QUANTIFIER_1_LSB 0x0695 + + + + + + + +#define VL53L1_RANGING_CORE__QUANTIFIER_REF_1_MSB 0x0696 + + + + + + + +#define VL53L1_RANGING_CORE__QUANTIFIER_REF_1_LSB 0x0697 + + + + + + + +#define VL53L1_RANGING_CORE__AMBIENT_OFFSET_1_MSB 0x0698 + + + + + + + +#define VL53L1_RANGING_CORE__AMBIENT_OFFSET_1_LSB 0x0699 + + + + + + + +#define VL53L1_RANGING_CORE__AMBIENT_OFFSET_REF_1_MSB 0x069A + + + + + + + +#define VL53L1_RANGING_CORE__AMBIENT_OFFSET_REF_1_LSB 0x069B + + + + + + + +#define VL53L1_RANGING_CORE__FILTER_STRENGTH_1 0x069C + + + + + + + +#define VL53L1_RANGING_CORE__FILTER_STRENGTH_REF_1 0x069D + + + + + + + +#define VL53L1_RANGING_CORE__SIGNAL_EVENT_LIMIT_1_MSB 0x069E + + + + + + + +#define VL53L1_RANGING_CORE__SIGNAL_EVENT_LIMIT_1_LSB 0x069F + + + + + + + +#define VL53L1_RANGING_CORE__SIGNAL_EVENT_LIMIT_REF_1_MSB 0x06A0 + + + + + + + +#define VL53L1_RANGING_CORE__SIGNAL_EVENT_LIMIT_REF_1_LSB 0x06A1 + + + + + + + +#define VL53L1_RANGING_CORE__TIMEOUT_OVERALL_PERIODS_MSB 0x06A4 + + + + + + + +#define VL53L1_RANGING_CORE__TIMEOUT_OVERALL_PERIODS_LSB 0x06A5 + + + + + + + +#define VL53L1_RANGING_CORE__INVERT_HW 0x06A6 + + + + + + + +#define VL53L1_RANGING_CORE__FORCE_HW 0x06A7 + + + + + + + +#define VL53L1_RANGING_CORE__STATIC_HW_VALUE 0x06A8 + + + + + + + +#define VL53L1_RANGING_CORE__FORCE_CONTINUOUS_AMBIENT 0x06A9 + + + + + + + +#define VL53L1_RANGING_CORE__TEST_PHASE_SELECT_TO_FILTER 0x06AA + + + + + + + +#define VL53L1_RANGING_CORE__TEST_PHASE_SELECT_TO_TIMING_GEN 0x06AB + + + + + + + +#define VL53L1_RANGING_CORE__INITIAL_PHASE_VALUE_1 0x06AC + + + + + + + +#define VL53L1_RANGING_CORE__INITIAL_PHASE_VALUE_REF_1 0x06AD + + + + + + + +#define VL53L1_RANGING_CORE__FORCE_UP_IN 0x06AE + + + + + + + +#define VL53L1_RANGING_CORE__FORCE_DN_IN 0x06AF + + + + + + + +#define VL53L1_RANGING_CORE__STATIC_UP_VALUE_1 0x06B0 + + + + + + + +#define VL53L1_RANGING_CORE__STATIC_UP_VALUE_REF_1 0x06B1 + + + + + + + +#define VL53L1_RANGING_CORE__STATIC_DN_VALUE_1 0x06B2 + + + + + + + +#define VL53L1_RANGING_CORE__STATIC_DN_VALUE_REF_1 0x06B3 + + + + + + + +#define VL53L1_RANGING_CORE__MONITOR_UP_DN 0x06B4 + + + + + + + +#define VL53L1_RANGING_CORE__INVERT_UP_DN 0x06B5 + + + + + + + +#define VL53L1_RANGING_CORE__CPUMP_1 0x06B6 + + + + + + + +#define VL53L1_RANGING_CORE__CPUMP_2 0x06B7 + + + + + + + +#define VL53L1_RANGING_CORE__CPUMP_3 0x06B8 + + + + + + + +#define VL53L1_RANGING_CORE__OSC_1 0x06B9 + + + + + + + +#define VL53L1_RANGING_CORE__PLL_1 0x06BB + + + + + + + +#define VL53L1_RANGING_CORE__PLL_2 0x06BC + + + + + + + +#define VL53L1_RANGING_CORE__REFERENCE_1 0x06BD + + + + + + + +#define VL53L1_RANGING_CORE__REFERENCE_3 0x06BF + + + + + + + +#define VL53L1_RANGING_CORE__REFERENCE_4 0x06C0 + + + + + + + +#define VL53L1_RANGING_CORE__REFERENCE_5 0x06C1 + + + + + + + +#define VL53L1_RANGING_CORE__REGAVDD1V2 0x06C3 + + + + + + + +#define VL53L1_RANGING_CORE__CALIB_1 0x06C4 + + + + + + + +#define VL53L1_RANGING_CORE__CALIB_2 0x06C5 + + + + + + + +#define VL53L1_RANGING_CORE__CALIB_3 0x06C6 + + + + + + + +#define VL53L1_RANGING_CORE__TST_MUX_SEL1 0x06C9 + + + + + + + +#define VL53L1_RANGING_CORE__TST_MUX_SEL2 0x06CA + + + + + + + +#define VL53L1_RANGING_CORE__TST_MUX 0x06CB + + + + + + + +#define VL53L1_RANGING_CORE__GPIO_OUT_TESTMUX 0x06CC + + + + + + + +#define VL53L1_RANGING_CORE__CUSTOM_FE 0x06CD + + + + + + + +#define VL53L1_RANGING_CORE__CUSTOM_FE_2 0x06CE + + + + + + + +#define VL53L1_RANGING_CORE__SPAD_READOUT 0x06CF + + + + + + + +#define VL53L1_RANGING_CORE__SPAD_READOUT_1 0x06D0 + + + + + + + +#define VL53L1_RANGING_CORE__SPAD_READOUT_2 0x06D1 + + + + + + + +#define VL53L1_RANGING_CORE__SPAD_PS 0x06D2 + + + + + + + +#define VL53L1_RANGING_CORE__LASER_SAFETY_2 0x06D4 + + + + + + + +#define VL53L1_RANGING_CORE__NVM_CTRL__MODE 0x0780 + + + + + + + +#define VL53L1_RANGING_CORE__NVM_CTRL__PDN 0x0781 + + + + + + + +#define VL53L1_RANGING_CORE__NVM_CTRL__PROGN 0x0782 + + + + + + + +#define VL53L1_RANGING_CORE__NVM_CTRL__READN 0x0783 + + + + + + + +#define VL53L1_RANGING_CORE__NVM_CTRL__PULSE_WIDTH_MSB 0x0784 + + + + + + + +#define VL53L1_RANGING_CORE__NVM_CTRL__PULSE_WIDTH_LSB 0x0785 + + + + + + + +#define VL53L1_RANGING_CORE__NVM_CTRL__HV_RISE_MSB 0x0786 + + + + + + + +#define VL53L1_RANGING_CORE__NVM_CTRL__HV_RISE_LSB 0x0787 + + + + + + + +#define VL53L1_RANGING_CORE__NVM_CTRL__HV_FALL_MSB 0x0788 + + + + + + + +#define VL53L1_RANGING_CORE__NVM_CTRL__HV_FALL_LSB 0x0789 + + + + + + + +#define VL53L1_RANGING_CORE__NVM_CTRL__TST 0x078A + + + + + + + +#define VL53L1_RANGING_CORE__NVM_CTRL__TESTREAD 0x078B + + + + + + + +#define VL53L1_RANGING_CORE__NVM_CTRL__DATAIN_MMM 0x078C + + + + + + + +#define VL53L1_RANGING_CORE__NVM_CTRL__DATAIN_LMM 0x078D + + + + + + + +#define VL53L1_RANGING_CORE__NVM_CTRL__DATAIN_LLM 0x078E + + + + + + + +#define VL53L1_RANGING_CORE__NVM_CTRL__DATAIN_LLL 0x078F + + + + + + + +#define VL53L1_RANGING_CORE__NVM_CTRL__DATAOUT_MMM 0x0790 + + + + + + + +#define VL53L1_RANGING_CORE__NVM_CTRL__DATAOUT_LMM 0x0791 + + + + + + + +#define VL53L1_RANGING_CORE__NVM_CTRL__DATAOUT_LLM 0x0792 + + + + + + + +#define VL53L1_RANGING_CORE__NVM_CTRL__DATAOUT_LLL 0x0793 + + + + + + + +#define VL53L1_RANGING_CORE__NVM_CTRL__ADDR 0x0794 + + + + + + + +#define VL53L1_RANGING_CORE__NVM_CTRL__DATAOUT_ECC 0x0795 + + + + + + + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_0 0x0796 + + + + + + + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_1 0x0797 + + + + + + + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_2 0x0798 + + + + + + + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_3 0x0799 + + + + + + + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_4 0x079A + + + + + + + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_5 0x079B + + + + + + + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_6 0x079C + + + + + + + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_7 0x079D + + + + + + + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_8 0x079E + + + + + + + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_9 0x079F + + + + + + + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_10 0x07A0 + + + + + + + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_11 0x07A1 + + + + + + + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_12 0x07A2 + + + + + + + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_13 0x07A3 + + + + + + + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_14 0x07A4 + + + + + + + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_15 0x07A5 + + + + + + + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_16 0x07A6 + + + + + + + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_17 0x07A7 + + + + + + + +#define VL53L1_RANGING_CORE__SPAD_SHIFT_EN 0x07BA + + + + + + + +#define VL53L1_RANGING_CORE__SPAD_DISABLE_CTRL 0x07BB + + + + + + + +#define VL53L1_RANGING_CORE__SPAD_EN_SHIFT_OUT_DEBUG 0x07BC + + + + + + + +#define VL53L1_RANGING_CORE__SPI_MODE 0x07BD + + + + + + + +#define VL53L1_RANGING_CORE__GPIO_DIR 0x07BE + + + + + + + +#define VL53L1_RANGING_CORE__VCSEL_PERIOD 0x0880 + + + + + + + +#define VL53L1_RANGING_CORE__VCSEL_START 0x0881 + + + + + + + +#define VL53L1_RANGING_CORE__VCSEL_STOP 0x0882 + + + + + + + +#define VL53L1_RANGING_CORE__VCSEL_1 0x0885 + + + + + + + +#define VL53L1_RANGING_CORE__VCSEL_STATUS 0x088D + + + + + + + +#define VL53L1_RANGING_CORE__STATUS 0x0980 + + + + + + + +#define VL53L1_RANGING_CORE__LASER_CONTINUITY_STATE 0x0981 + + + + + + + +#define VL53L1_RANGING_CORE__RANGE_1_MMM 0x0982 + + + + + + + +#define VL53L1_RANGING_CORE__RANGE_1_LMM 0x0983 + + + + + + + +#define VL53L1_RANGING_CORE__RANGE_1_LLM 0x0984 + + + + + + + +#define VL53L1_RANGING_CORE__RANGE_1_LLL 0x0985 + + + + + + + +#define VL53L1_RANGING_CORE__RANGE_REF_1_MMM 0x0986 + + + + + + + +#define VL53L1_RANGING_CORE__RANGE_REF_1_LMM 0x0987 + + + + + + + +#define VL53L1_RANGING_CORE__RANGE_REF_1_LLM 0x0988 + + + + + + + +#define VL53L1_RANGING_CORE__RANGE_REF_1_LLL 0x0989 + + + + + + + +#define VL53L1_RANGING_CORE__AMBIENT_WINDOW_EVENTS_1_MMM 0x098A + + + + + + + +#define VL53L1_RANGING_CORE__AMBIENT_WINDOW_EVENTS_1_LMM 0x098B + + + + + + + +#define VL53L1_RANGING_CORE__AMBIENT_WINDOW_EVENTS_1_LLM 0x098C + + + + + + + +#define VL53L1_RANGING_CORE__AMBIENT_WINDOW_EVENTS_1_LLL 0x098D + + + + + + + +#define VL53L1_RANGING_CORE__RANGING_TOTAL_EVENTS_1_MMM 0x098E + + + + + + + +#define VL53L1_RANGING_CORE__RANGING_TOTAL_EVENTS_1_LMM 0x098F + + + + + + + +#define VL53L1_RANGING_CORE__RANGING_TOTAL_EVENTS_1_LLM 0x0990 + + + + + + + +#define VL53L1_RANGING_CORE__RANGING_TOTAL_EVENTS_1_LLL 0x0991 + + + + + + + +#define VL53L1_RANGING_CORE__SIGNAL_TOTAL_EVENTS_1_MMM 0x0992 + + + + + + + +#define VL53L1_RANGING_CORE__SIGNAL_TOTAL_EVENTS_1_LMM 0x0993 + + + + + + + +#define VL53L1_RANGING_CORE__SIGNAL_TOTAL_EVENTS_1_LLM 0x0994 + + + + + + + +#define VL53L1_RANGING_CORE__SIGNAL_TOTAL_EVENTS_1_LLL 0x0995 + + + + + + + +#define VL53L1_RANGING_CORE__TOTAL_PERIODS_ELAPSED_1_MM 0x0996 + + + + + + + +#define VL53L1_RANGING_CORE__TOTAL_PERIODS_ELAPSED_1_LM 0x0997 + + + + + + + +#define VL53L1_RANGING_CORE__TOTAL_PERIODS_ELAPSED_1_LL 0x0998 + + + + + + + +#define VL53L1_RANGING_CORE__AMBIENT_MISMATCH_MM 0x0999 + + + + + + + +#define VL53L1_RANGING_CORE__AMBIENT_MISMATCH_LM 0x099A + + + + + + + +#define VL53L1_RANGING_CORE__AMBIENT_MISMATCH_LL 0x099B + + + + + + + +#define VL53L1_RANGING_CORE__AMBIENT_WINDOW_EVENTS_REF_1_MMM 0x099C + + + + + + + +#define VL53L1_RANGING_CORE__AMBIENT_WINDOW_EVENTS_REF_1_LMM 0x099D + + + + + + + +#define VL53L1_RANGING_CORE__AMBIENT_WINDOW_EVENTS_REF_1_LLM 0x099E + + + + + + + +#define VL53L1_RANGING_CORE__AMBIENT_WINDOW_EVENTS_REF_1_LLL 0x099F + + + + + + + +#define VL53L1_RANGING_CORE__RANGING_TOTAL_EVENTS_REF_1_MMM 0x09A0 + + + + + + + +#define VL53L1_RANGING_CORE__RANGING_TOTAL_EVENTS_REF_1_LMM 0x09A1 + + + + + + + +#define VL53L1_RANGING_CORE__RANGING_TOTAL_EVENTS_REF_1_LLM 0x09A2 + + + + + + + +#define VL53L1_RANGING_CORE__RANGING_TOTAL_EVENTS_REF_1_LLL 0x09A3 + + + + + + + +#define VL53L1_RANGING_CORE__SIGNAL_TOTAL_EVENTS_REF_1_MMM 0x09A4 + + + + + + + +#define VL53L1_RANGING_CORE__SIGNAL_TOTAL_EVENTS_REF_1_LMM 0x09A5 + + + + + + + +#define VL53L1_RANGING_CORE__SIGNAL_TOTAL_EVENTS_REF_1_LLM 0x09A6 + + + + + + + +#define VL53L1_RANGING_CORE__SIGNAL_TOTAL_EVENTS_REF_1_LLL 0x09A7 + + + + + + + +#define VL53L1_RANGING_CORE__TOTAL_PERIODS_ELAPSED_REF_1_MM 0x09A8 + + + + + + + +#define VL53L1_RANGING_CORE__TOTAL_PERIODS_ELAPSED_REF_1_LM 0x09A9 + + + + + + + +#define VL53L1_RANGING_CORE__TOTAL_PERIODS_ELAPSED_REF_1_LL 0x09AA + + + + + + + +#define VL53L1_RANGING_CORE__AMBIENT_MISMATCH_REF_MM 0x09AB + + + + + + + +#define VL53L1_RANGING_CORE__AMBIENT_MISMATCH_REF_LM 0x09AC + + + + + + + +#define VL53L1_RANGING_CORE__AMBIENT_MISMATCH_REF_LL 0x09AD + + + + + + + +#define VL53L1_RANGING_CORE__GPIO_CONFIG__A0 0x0A00 + + + + + + + +#define VL53L1_RANGING_CORE__RESET_CONTROL__A0 0x0A01 + + + + + + + +#define VL53L1_RANGING_CORE__INTR_MANAGER__A0 0x0A02 + + + + + + + +#define VL53L1_RANGING_CORE__POWER_FSM_TIME_OSC__A0 0x0A06 + + + + + + + +#define VL53L1_RANGING_CORE__VCSEL_ATEST__A0 0x0A07 + + + + + + + +#define VL53L1_RANGING_CORE__VCSEL_PERIOD_CLIPPED__A0 0x0A08 + + + + + + + +#define VL53L1_RANGING_CORE__VCSEL_STOP_CLIPPED__A0 0x0A09 + + + + + + + +#define VL53L1_RANGING_CORE__CALIB_2__A0 0x0A0A + + + + + + + +#define VL53L1_RANGING_CORE__STOP_CONDITION__A0 0x0A0B + + + + + + + +#define VL53L1_RANGING_CORE__STATUS_RESET__A0 0x0A0C + + + + + + + +#define VL53L1_RANGING_CORE__READOUT_CFG__A0 0x0A0D + + + + + + + +#define VL53L1_RANGING_CORE__WINDOW_SETTING__A0 0x0A0E + + + + + + + +#define VL53L1_RANGING_CORE__VCSEL_DELAY__A0 0x0A1A + + + + + + + +#define VL53L1_RANGING_CORE__REFERENCE_2__A0 0x0A1B + + + + + + + +#define VL53L1_RANGING_CORE__REGAVDD1V2__A0 0x0A1D + + + + + + + +#define VL53L1_RANGING_CORE__TST_MUX__A0 0x0A1F + + + + + + + +#define VL53L1_RANGING_CORE__CUSTOM_FE_2__A0 0x0A20 + + + + + + + +#define VL53L1_RANGING_CORE__SPAD_READOUT__A0 0x0A21 + + + + + + + +#define VL53L1_RANGING_CORE__CPUMP_1__A0 0x0A22 + + + + + + + +#define VL53L1_RANGING_CORE__SPARE_REGISTER__A0 0x0A23 + + + + + + + +#define VL53L1_RANGING_CORE__VCSEL_CONT_STAGE5_BYPASS__A0 0x0A24 + + + + + + + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_18 0x0A25 + + + + + + + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_19 0x0A26 + + + + + + + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_20 0x0A27 + + + + + + + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_21 0x0A28 + + + + + + + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_22 0x0A29 + + + + + + + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_23 0x0A2A + + + + + + + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_24 0x0A2B + + + + + + + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_25 0x0A2C + + + + + + + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_26 0x0A2D + + + + + + + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_27 0x0A2E + + + + + + + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_28 0x0A2F + + + + + + + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_29 0x0A30 + + + + + + + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_30 0x0A31 + + + + + + + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_31 0x0A32 + + + + + + + +#define VL53L1_RANGING_CORE__REF_SPAD_EN_0__EWOK 0x0A33 + + + + + + + +#define VL53L1_RANGING_CORE__REF_SPAD_EN_1__EWOK 0x0A34 + + + + + + + +#define VL53L1_RANGING_CORE__REF_SPAD_EN_2__EWOK 0x0A35 + + + + + + + +#define VL53L1_RANGING_CORE__REF_SPAD_EN_3__EWOK 0x0A36 + + + + + + + +#define VL53L1_RANGING_CORE__REF_SPAD_EN_4__EWOK 0x0A37 + + + + + + + +#define VL53L1_RANGING_CORE__REF_SPAD_EN_5__EWOK 0x0A38 + + + + + + + +#define VL53L1_RANGING_CORE__REF_EN_START_SELECT 0x0A39 + + + + + + + +#define VL53L1_RANGING_CORE__REGDVDD1V2_ATEST__EWOK 0x0A41 + + + + + + + +#define VL53L1_SOFT_RESET_GO1 0x0B00 + + + + + + + +#define VL53L1_PRIVATE__PATCH_BASE_ADDR_RSLV 0x0E00 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__INTERRUPT_STATUS 0x0ED0 + + + + + + + + + + + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__RANGE_STATUS 0x0ED1 + + + + + + + + + + + + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__REPORT_STATUS 0x0ED2 + + + + + + + + + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__STREAM_COUNT 0x0ED3 + + + + + + + + + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__DSS_ACTUAL_EFFECTIVE_SPADS_SD0 0x0ED4 + + + + + + + + + + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__DSS_ACTUAL_EFFECTIVE_SPADS_SD0_HI 0x0ED4 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__DSS_ACTUAL_EFFECTIVE_SPADS_SD0_LO 0x0ED5 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__PEAK_SIGNAL_COUNT_RATE_MCPS_SD0 0x0ED6 + + + + + + + + + + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__PEAK_SIGNAL_COUNT_RATE_MCPS_SD0_HI 0x0ED6 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__PEAK_SIGNAL_COUNT_RATE_MCPS_SD0_LO 0x0ED7 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__AMBIENT_COUNT_RATE_MCPS_SD0 0x0ED8 + + + + + + + + + + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__AMBIENT_COUNT_RATE_MCPS_SD0_HI 0x0ED8 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__AMBIENT_COUNT_RATE_MCPS_SD0_LO 0x0ED9 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__SIGMA_SD0 0x0EDA + + + + + + + + + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__SIGMA_SD0_HI 0x0EDA + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__SIGMA_SD0_LO 0x0EDB + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__PHASE_SD0 0x0EDC + + + + + + + + + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__PHASE_SD0_HI 0x0EDC + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__PHASE_SD0_LO 0x0EDD + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__FINAL_CROSSTALK_CORRECTED_RANGE_MM_SD0 0x0EDE + + + + + + + + + + + + + + + +#define VL53L1_PREV__FINAL_CROSSTALK_CORRECTED_RANGE_MM_SD0_HI 0x0EDE + + + + + + + +#define VL53L1_PREV__FINAL_CROSSTALK_CORRECTED_RANGE_MM_SD0_LO 0x0EDF + + + + + + + +#define VL53L1_PREV__PEAK_SIGNAL_COUNT_RATE_CROSSTALK_CORRECTED_MCPS_SD0 0x0EE0 + + + + + + + + + + + + + + + + +#define VL53L1_PPEAK_SIGNAL_COUNT_RATE_CROSSTALK_CORRECTED_MCPS_SD0_HI 0x0EE0 + + + + + + + +#define VL53L1_PPEAK_SIGNAL_COUNT_RATE_CROSSTALK_CORRECTED_MCPS_SD0_LO 0x0EE1 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__MM_INNER_ACTUAL_EFFECTIVE_SPADS_SD0 0x0EE2 + + + + + + + + + + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__MM_INNER_ACTUAL_EFFECTIVE_SPADS_SD0_HI 0x0EE2 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__MM_INNER_ACTUAL_EFFECTIVE_SPADS_SD0_LO 0x0EE3 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__MM_OUTER_ACTUAL_EFFECTIVE_SPADS_SD0 0x0EE4 + + + + + + + + + + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__MM_OUTER_ACTUAL_EFFECTIVE_SPADS_SD0_HI 0x0EE4 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__MM_OUTER_ACTUAL_EFFECTIVE_SPADS_SD0_LO 0x0EE5 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__AVG_SIGNAL_COUNT_RATE_MCPS_SD0 0x0EE6 + + + + + + + + + + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__AVG_SIGNAL_COUNT_RATE_MCPS_SD0_HI 0x0EE6 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__AVG_SIGNAL_COUNT_RATE_MCPS_SD0_LO 0x0EE7 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__DSS_ACTUAL_EFFECTIVE_SPADS_SD1 0x0EE8 + + + + + + + + + + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__DSS_ACTUAL_EFFECTIVE_SPADS_SD1_HI 0x0EE8 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__DSS_ACTUAL_EFFECTIVE_SPADS_SD1_LO 0x0EE9 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__PEAK_SIGNAL_COUNT_RATE_MCPS_SD1 0x0EEA + + + + + + + + + + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__PEAK_SIGNAL_COUNT_RATE_MCPS_SD1_HI 0x0EEA + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__PEAK_SIGNAL_COUNT_RATE_MCPS_SD1_LO 0x0EEB + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__AMBIENT_COUNT_RATE_MCPS_SD1 0x0EEC + + + + + + + + + + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__AMBIENT_COUNT_RATE_MCPS_SD1_HI 0x0EEC + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__AMBIENT_COUNT_RATE_MCPS_SD1_LO 0x0EED + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__SIGMA_SD1 0x0EEE + + + + + + + + + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__SIGMA_SD1_HI 0x0EEE + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__SIGMA_SD1_LO 0x0EEF + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__PHASE_SD1 0x0EF0 + + + + + + + + + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__PHASE_SD1_HI 0x0EF0 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__PHASE_SD1_LO 0x0EF1 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__FINAL_CROSSTALK_CORRECTED_RANGE_MM_SD1 0x0EF2 + + + + + + + + + + + + + + + + +#define VL53L1_PFINAL_CROSSTALK_CORRECTED_RANGE_MM_SD1_HI 0x0EF2 + + + + + + + +#define VL53L1_PFINAL_CROSSTALK_CORRECTED_RANGE_MM_SD1_LO 0x0EF3 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__SPARE_0_SD1 0x0EF4 + + + + + + + + + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__SPARE_0_SD1_HI 0x0EF4 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__SPARE_0_SD1_LO 0x0EF5 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__SPARE_1_SD1 0x0EF6 + + + + + + + + + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__SPARE_1_SD1_HI 0x0EF6 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__SPARE_1_SD1_LO 0x0EF7 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__SPARE_2_SD1 0x0EF8 + + + + + + + + + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__SPARE_2_SD1_HI 0x0EF8 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__SPARE_2_SD1_LO 0x0EF9 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__SPARE_3_SD1 0x0EFA + + + + + + + + + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__SPARE_3_SD1_HI 0x0EFA + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__SPARE_3_SD1_LO 0x0EFB + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD0 0x0EFC + + + + + + + + + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD0_3 0x0EFC + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD0_2 0x0EFD + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD0_1 0x0EFE + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD0_0 0x0EFF + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__RANGING_TOTAL_EVENTS_SD0 0x0F00 + + + + + + + + + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__RANGING_TOTAL_EVENTS_SD0_3 0x0F00 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__RANGING_TOTAL_EVENTS_SD0_2 0x0F01 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__RANGING_TOTAL_EVENTS_SD0_1 0x0F02 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__RANGING_TOTAL_EVENTS_SD0_0 0x0F03 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__SIGNAL_TOTAL_EVENTS_SD0 0x0F04 + + + + + + + + + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__SIGNAL_TOTAL_EVENTS_SD0_3 0x0F04 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__SIGNAL_TOTAL_EVENTS_SD0_2 0x0F05 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__SIGNAL_TOTAL_EVENTS_SD0_1 0x0F06 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__SIGNAL_TOTAL_EVENTS_SD0_0 0x0F07 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__TOTAL_PERIODS_ELAPSED_SD0 0x0F08 + + + + + + + + + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__TOTAL_PERIODS_ELAPSED_SD0_3 0x0F08 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__TOTAL_PERIODS_ELAPSED_SD0_2 0x0F09 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__TOTAL_PERIODS_ELAPSED_SD0_1 0x0F0A + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__TOTAL_PERIODS_ELAPSED_SD0_0 0x0F0B + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD1 0x0F0C + + + + + + + + + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD1_3 0x0F0C + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD1_2 0x0F0D + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD1_1 0x0F0E + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD1_0 0x0F0F + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__RANGING_TOTAL_EVENTS_SD1 0x0F10 + + + + + + + + + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__RANGING_TOTAL_EVENTS_SD1_3 0x0F10 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__RANGING_TOTAL_EVENTS_SD1_2 0x0F11 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__RANGING_TOTAL_EVENTS_SD1_1 0x0F12 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__RANGING_TOTAL_EVENTS_SD1_0 0x0F13 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__SIGNAL_TOTAL_EVENTS_SD1 0x0F14 + + + + + + + + + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__SIGNAL_TOTAL_EVENTS_SD1_3 0x0F14 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__SIGNAL_TOTAL_EVENTS_SD1_2 0x0F15 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__SIGNAL_TOTAL_EVENTS_SD1_1 0x0F16 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__SIGNAL_TOTAL_EVENTS_SD1_0 0x0F17 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__TOTAL_PERIODS_ELAPSED_SD1 0x0F18 + + + + + + + + + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__TOTAL_PERIODS_ELAPSED_SD1_3 0x0F18 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__TOTAL_PERIODS_ELAPSED_SD1_2 0x0F19 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__TOTAL_PERIODS_ELAPSED_SD1_1 0x0F1A + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__TOTAL_PERIODS_ELAPSED_SD1_0 0x0F1B + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__SPARE_0 0x0F1C + + + + + + + + + + + + + + + +#define VL53L1_RESULT__DEBUG_STATUS 0x0F20 + + + + + + + + + + + + + + + +#define VL53L1_RESULT__DEBUG_STAGE 0x0F21 + + + + + + + + + + + + + + + +#define VL53L1_GPH__SYSTEM__THRESH_RATE_HIGH 0x0F24 + + + + + + + + + + + + + + + +#define VL53L1_GPH__SYSTEM__THRESH_RATE_HIGH_HI 0x0F24 + + + + + + + +#define VL53L1_GPH__SYSTEM__THRESH_RATE_HIGH_LO 0x0F25 + + + + + + + +#define VL53L1_GPH__SYSTEM__THRESH_RATE_LOW 0x0F26 + + + + + + + + + + + + + + + +#define VL53L1_GPH__SYSTEM__THRESH_RATE_LOW_HI 0x0F26 + + + + + + + +#define VL53L1_GPH__SYSTEM__THRESH_RATE_LOW_LO 0x0F27 + + + + + + + +#define VL53L1_GPH__SYSTEM__INTERRUPT_CONFIG_GPIO 0x0F28 + + + + + + + + + + + + + + + + + + + + +#define VL53L1_GPH__DSS_CONFIG__ROI_MODE_CONTROL 0x0F2F + + + + + + + + + + + + + + + + +#define VL53L1_GPH__DSS_CONFIG__MANUAL_EFFECTIVE_SPADS_SELECT 0x0F30 + + + + + + + + + + + + + + + +#define VL53L1_GPH__DSS_CONFIG__MANUAL_EFFECTIVE_SPADS_SELECT_HI 0x0F30 + + + + + + + +#define VL53L1_GPH__DSS_CONFIG__MANUAL_EFFECTIVE_SPADS_SELECT_LO 0x0F31 + + + + + + + +#define VL53L1_GPH__DSS_CONFIG__MANUAL_BLOCK_SELECT 0x0F32 + + + + + + + + + + + + + + + +#define VL53L1_GPH__DSS_CONFIG__MAX_SPADS_LIMIT 0x0F33 + + + + + + + + + + + + + + + +#define VL53L1_GPH__DSS_CONFIG__MIN_SPADS_LIMIT 0x0F34 + + + + + + + + + + + + + + + +#define VL53L1_GPH__MM_CONFIG__TIMEOUT_MACROP_A_HI 0x0F36 + + + + + + + + + + + + + + + +#define VL53L1_GPH__MM_CONFIG__TIMEOUT_MACROP_A_LO 0x0F37 + + + + + + + + + + + + + + + +#define VL53L1_GPH__MM_CONFIG__TIMEOUT_MACROP_B_HI 0x0F38 + + + + + + + + + + + + + + + +#define VL53L1_GPH__MM_CONFIG__TIMEOUT_MACROP_B_LO 0x0F39 + + + + + + + + + + + + + + + +#define VL53L1_GPH__RANGE_CONFIG__TIMEOUT_MACROP_A_HI 0x0F3A + + + + + + + + + + + + + + + +#define VL53L1_GPH__RANGE_CONFIG__TIMEOUT_MACROP_A_LO 0x0F3B + + + + + + + + + + + + + + + +#define VL53L1_GPH__RANGE_CONFIG__VCSEL_PERIOD_A 0x0F3C + + + + + + + + + + + + + + + +#define VL53L1_GPH__RANGE_CONFIG__VCSEL_PERIOD_B 0x0F3D + + + + + + + + + + + + + + + +#define VL53L1_GPH__RANGE_CONFIG__TIMEOUT_MACROP_B_HI 0x0F3E + + + + + + + + + + + + + + + +#define VL53L1_GPH__RANGE_CONFIG__TIMEOUT_MACROP_B_LO 0x0F3F + + + + + + + + + + + + + + + +#define VL53L1_GPH__RANGE_CONFIG__SIGMA_THRESH 0x0F40 + + + + + + + + + + + + + + + +#define VL53L1_GPH__RANGE_CONFIG__SIGMA_THRESH_HI 0x0F40 + + + + + + + +#define VL53L1_GPH__RANGE_CONFIG__SIGMA_THRESH_LO 0x0F41 + + + + + + + +#define VL53L1_GPH__RANGE_CONFIG__MIN_COUNT_RATE_RTN_LIMIT_MCPS 0x0F42 + + + + + + + + + + + + + + + + +#define VL53L1_GPH__RANGE_CONFIG__MIN_COUNT_RATE_RTN_LIMIT_MCPS_HI 0x0F42 + + + + + + + +#define VL53L1_GPH__RANGE_CONFIG__MIN_COUNT_RATE_RTN_LIMIT_MCPS_LO 0x0F43 + + + + + + + +#define VL53L1_GPH__RANGE_CONFIG__VALID_PHASE_LOW 0x0F44 + + + + + + + + + + + + + + + +#define VL53L1_GPH__RANGE_CONFIG__VALID_PHASE_HIGH 0x0F45 + + + + + + + + + + + + + + + +#define VL53L1_FIRMWARE__INTERNAL_STREAM_COUNT_DIV 0x0F46 + + + + + + + + + + + + + + + +#define VL53L1_FIRMWARE__INTERNAL_STREAM_COUNTER_VAL 0x0F47 + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__ROI_CTRL 0x0F54 + + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__SPARE_1 0x0F55 + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__SPARE_2 0x0F56 + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__SPARE_3 0x0F57 + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__SPARE_4 0x0F58 + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__SPARE_5 0x0F59 + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__SPARE_6 0x0F5A + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__SPARE_7 0x0F5B + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_0 0x0F5C + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_1 0x0F5D + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_2 0x0F5E + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_3 0x0F5F + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_4 0x0F60 + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_5 0x0F61 + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_6 0x0F62 + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_7 0x0F63 + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_8 0x0F64 + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_9 0x0F65 + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_10 0x0F66 + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_11 0x0F67 + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_12 0x0F68 + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_13 0x0F69 + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_14 0x0F6A + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_15 0x0F6B + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_16 0x0F6C + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_17 0x0F6D + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_18 0x0F6E + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_19 0x0F6F + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_20 0x0F70 + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_21 0x0F71 + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_22 0x0F72 + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_23 0x0F73 + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_24 0x0F74 + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_25 0x0F75 + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_26 0x0F76 + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_27 0x0F77 + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_28 0x0F78 + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_29 0x0F79 + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_30 0x0F7A + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_31 0x0F7B + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__USER_ROI_0 0x0F7C + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__USER_ROI_1 0x0F7D + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__MODE_ROI_0 0x0F7E + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__MODE_ROI_1 0x0F7F + + + + + + + + + + + + + + + +#define VL53L1_SIGMA_ESTIMATOR_CALC__SPARE_0 0x0F80 + + + + + + + + + + + + + + + +#define VL53L1_VHV_RESULT__PEAK_SIGNAL_RATE_MCPS 0x0F82 + + + + + + + + + + + + + + + +#define VL53L1_VHV_RESULT__PEAK_SIGNAL_RATE_MCPS_HI 0x0F82 + + + + + + + +#define VL53L1_VHV_RESULT__PEAK_SIGNAL_RATE_MCPS_LO 0x0F83 + + + + + + + +#define VL53L1_VHV_RESULT__SIGNAL_TOTAL_EVENTS_REF 0x0F84 + + + + + + + + + + + + + + + +#define VL53L1_VHV_RESULT__SIGNAL_TOTAL_EVENTS_REF_3 0x0F84 + + + + + + + +#define VL53L1_VHV_RESULT__SIGNAL_TOTAL_EVENTS_REF_2 0x0F85 + + + + + + + +#define VL53L1_VHV_RESULT__SIGNAL_TOTAL_EVENTS_REF_1 0x0F86 + + + + + + + +#define VL53L1_VHV_RESULT__SIGNAL_TOTAL_EVENTS_REF_0 0x0F87 + + + + + + + +#define VL53L1_PHASECAL_RESULT__PHASE_OUTPUT_REF 0x0F88 + + + + + + + + + + + + + + + +#define VL53L1_PHASECAL_RESULT__PHASE_OUTPUT_REF_HI 0x0F88 + + + + + + + +#define VL53L1_PHASECAL_RESULT__PHASE_OUTPUT_REF_LO 0x0F89 + + + + + + + +#define VL53L1_DSS_RESULT__TOTAL_RATE_PER_SPAD 0x0F8A + + + + + + + + + + + + + + + +#define VL53L1_DSS_RESULT__TOTAL_RATE_PER_SPAD_HI 0x0F8A + + + + + + + +#define VL53L1_DSS_RESULT__TOTAL_RATE_PER_SPAD_LO 0x0F8B + + + + + + + +#define VL53L1_DSS_RESULT__ENABLED_BLOCKS 0x0F8C + + + + + + + + + + + + + + + +#define VL53L1_DSS_RESULT__NUM_REQUESTED_SPADS 0x0F8E + + + + + + + + + + + + + + + +#define VL53L1_DSS_RESULT__NUM_REQUESTED_SPADS_HI 0x0F8E + + + + + + + +#define VL53L1_DSS_RESULT__NUM_REQUESTED_SPADS_LO 0x0F8F + + + + + + + +#define VL53L1_MM_RESULT__INNER_INTERSECTION_RATE 0x0F92 + + + + + + + + + + + + + + + +#define VL53L1_MM_RESULT__INNER_INTERSECTION_RATE_HI 0x0F92 + + + + + + + +#define VL53L1_MM_RESULT__INNER_INTERSECTION_RATE_LO 0x0F93 + + + + + + + +#define VL53L1_MM_RESULT__OUTER_COMPLEMENT_RATE 0x0F94 + + + + + + + + + + + + + + + +#define VL53L1_MM_RESULT__OUTER_COMPLEMENT_RATE_HI 0x0F94 + + + + + + + +#define VL53L1_MM_RESULT__OUTER_COMPLEMENT_RATE_LO 0x0F95 + + + + + + + +#define VL53L1_MM_RESULT__TOTAL_OFFSET 0x0F96 + + + + + + + + + + + + + + + +#define VL53L1_MM_RESULT__TOTAL_OFFSET_HI 0x0F96 + + + + + + + +#define VL53L1_MM_RESULT__TOTAL_OFFSET_LO 0x0F97 + + + + + + + +#define VL53L1_XTALK_CALC__XTALK_FOR_ENABLED_SPADS 0x0F98 + + + + + + + + + + + + + + + +#define VL53L1_XTALK_CALC__XTALK_FOR_ENABLED_SPADS_3 0x0F98 + + + + + + + +#define VL53L1_XTALK_CALC__XTALK_FOR_ENABLED_SPADS_2 0x0F99 + + + + + + + +#define VL53L1_XTALK_CALC__XTALK_FOR_ENABLED_SPADS_1 0x0F9A + + + + + + + +#define VL53L1_XTALK_CALC__XTALK_FOR_ENABLED_SPADS_0 0x0F9B + + + + + + + +#define VL53L1_XTALK_RESULT__AVG_XTALK_USER_ROI_KCPS 0x0F9C + + + + + + + + + + + + + + + + +#define VL53L1_XTALK_RESULT__AVG_XTALK_USER_ROI_KCPS_3 0x0F9C + + + + + + + +#define VL53L1_XTALK_RESULT__AVG_XTALK_USER_ROI_KCPS_2 0x0F9D + + + + + + + +#define VL53L1_XTALK_RESULT__AVG_XTALK_USER_ROI_KCPS_1 0x0F9E + + + + + + + +#define VL53L1_XTALK_RESULT__AVG_XTALK_USER_ROI_KCPS_0 0x0F9F + + + + + + + +#define VL53L1_XTALK_RESULT__AVG_XTALK_MM_INNER_ROI_KCPS 0x0FA0 + + + + + + + + + + + + + + + + +#define VL53L1_XTALK_RESULT__AVG_XTALK_MM_INNER_ROI_KCPS_3 0x0FA0 + + + + + + + +#define VL53L1_XTALK_RESULT__AVG_XTALK_MM_INNER_ROI_KCPS_2 0x0FA1 + + + + + + + +#define VL53L1_XTALK_RESULT__AVG_XTALK_MM_INNER_ROI_KCPS_1 0x0FA2 + + + + + + + +#define VL53L1_XTALK_RESULT__AVG_XTALK_MM_INNER_ROI_KCPS_0 0x0FA3 + + + + + + + +#define VL53L1_XTALK_RESULT__AVG_XTALK_MM_OUTER_ROI_KCPS 0x0FA4 + + + + + + + + + + + + + + + + +#define VL53L1_XTALK_RESULT__AVG_XTALK_MM_OUTER_ROI_KCPS_3 0x0FA4 + + + + + + + +#define VL53L1_XTALK_RESULT__AVG_XTALK_MM_OUTER_ROI_KCPS_2 0x0FA5 + + + + + + + +#define VL53L1_XTALK_RESULT__AVG_XTALK_MM_OUTER_ROI_KCPS_1 0x0FA6 + + + + + + + +#define VL53L1_XTALK_RESULT__AVG_XTALK_MM_OUTER_ROI_KCPS_0 0x0FA7 + + + + + + + +#define VL53L1_RANGE_RESULT__ACCUM_PHASE 0x0FA8 + + + + + + + + + + + + + + + +#define VL53L1_RANGE_RESULT__ACCUM_PHASE_3 0x0FA8 + + + + + + + +#define VL53L1_RANGE_RESULT__ACCUM_PHASE_2 0x0FA9 + + + + + + + +#define VL53L1_RANGE_RESULT__ACCUM_PHASE_1 0x0FAA + + + + + + + +#define VL53L1_RANGE_RESULT__ACCUM_PHASE_0 0x0FAB + + + + + + + +#define VL53L1_RANGE_RESULT__OFFSET_CORRECTED_RANGE 0x0FAC + + + + + + + + + + + + + + + +#define VL53L1_RANGE_RESULT__OFFSET_CORRECTED_RANGE_HI 0x0FAC + + + + + + + +#define VL53L1_RANGE_RESULT__OFFSET_CORRECTED_RANGE_LO 0x0FAD + + + + + + + +#define VL53L1_SHADOW_PHASECAL_RESULT__VCSEL_START 0x0FAE + + + + + + + + + + + + + + + +#define VL53L1_SHADOW_RESULT__INTERRUPT_STATUS 0x0FB0 + + + + + + + + + + + + + + + + + +#define VL53L1_SHADOW_RESULT__RANGE_STATUS 0x0FB1 + + + + + + + + + + + + + + + + + + +#define VL53L1_SHADOW_RESULT__REPORT_STATUS 0x0FB2 + + + + + + + + + + + + + + + +#define VL53L1_SHADOW_RESULT__STREAM_COUNT 0x0FB3 + + + + + + + + + + + + + + + +#define VL53L1_SHADOW_RESULT__DSS_ACTUAL_EFFECTIVE_SPADS_SD0 0x0FB4 + + + + + + + + + + + + + + + + +#define VL53L1_SHADOW_RESULT__DSS_ACTUAL_EFFECTIVE_SPADS_SD0_HI 0x0FB4 + + + + + + + +#define VL53L1_SHADOW_RESULT__DSS_ACTUAL_EFFECTIVE_SPADS_SD0_LO 0x0FB5 + + + + + + + +#define VL53L1_SHADOW_RESULT__PEAK_SIGNAL_COUNT_RATE_MCPS_SD0 0x0FB6 + + + + + + + + + + + + + + + + +#define VL53L1_SHADOW_RESULT__PEAK_SIGNAL_COUNT_RATE_MCPS_SD0_HI 0x0FB6 + + + + + + + +#define VL53L1_SHADOW_RESULT__PEAK_SIGNAL_COUNT_RATE_MCPS_SD0_LO 0x0FB7 + + + + + + + +#define VL53L1_SHADOW_RESULT__AMBIENT_COUNT_RATE_MCPS_SD0 0x0FB8 + + + + + + + + + + + + + + + + +#define VL53L1_SHADOW_RESULT__AMBIENT_COUNT_RATE_MCPS_SD0_HI 0x0FB8 + + + + + + + +#define VL53L1_SHADOW_RESULT__AMBIENT_COUNT_RATE_MCPS_SD0_LO 0x0FB9 + + + + + + + +#define VL53L1_SHADOW_RESULT__SIGMA_SD0 0x0FBA + + + + + + + + + + + + + + + +#define VL53L1_SHADOW_RESULT__SIGMA_SD0_HI 0x0FBA + + + + + + + +#define VL53L1_SHADOW_RESULT__SIGMA_SD0_LO 0x0FBB + + + + + + + +#define VL53L1_SHADOW_RESULT__PHASE_SD0 0x0FBC + + + + + + + + + + + + + + + +#define VL53L1_SHADOW_RESULT__PHASE_SD0_HI 0x0FBC + + + + + + + +#define VL53L1_SHADOW_RESULT__PHASE_SD0_LO 0x0FBD + + + + + + + +#define VL53L1_SHADOW_RESULT__FINAL_CROSSTALK_CORRECTED_RANGE_MM_SD0 0x0FBE + + + + + + + + + + + + + + + +#define VL53L1_SHADOW_RESULT__FINAL_CROSSTALK_CORRECTED_RANGE_MM_SD0_HI 0x0FBE + + + + + + + +#define VL53L1_SHADOW_RESULT__FINAL_CROSSTALK_CORRECTED_RANGE_MM_SD0_LO 0x0FBF + + + + + + + +#define VL53L1_SHPEAK_SIGNAL_COUNT_RATE_CROSSTALK_CORRECTED_MCPS_SD0 0x0FC0 + + + + + + + + + + + + + + + + +#define VL53L1_SHPEAK_SIGNAL_COUNT_RATE_CROSSTALK_CORRECTED_MCPS_SD0_HI 0x0FC0 + + + + + + + +#define VL53L1_SHPEAK_SIGNAL_COUNT_RATE_CROSSTALK_CORRECTED_MCPS_SD0_LO 0x0FC1 + + + + + + + +#define VL53L1_SHADOW_RESULT__MM_INNER_ACTUAL_EFFECTIVE_SPADS_SD0 0x0FC2 + + + + + + + + + + + + + + + + +#define VL53L1_SHADOW_RESULT__MM_INNER_ACTUAL_EFFECTIVE_SPADS_SD0_HI 0x0FC2 + + + + + + + +#define VL53L1_SHADOW_RESULT__MM_INNER_ACTUAL_EFFECTIVE_SPADS_SD0_LO 0x0FC3 + + + + + + + +#define VL53L1_SHADOW_RESULT__MM_OUTER_ACTUAL_EFFECTIVE_SPADS_SD0 0x0FC4 + + + + + + + + + + + + + + + + +#define VL53L1_SHADOW_RESULT__MM_OUTER_ACTUAL_EFFECTIVE_SPADS_SD0_HI 0x0FC4 + + + + + + + +#define VL53L1_SHADOW_RESULT__MM_OUTER_ACTUAL_EFFECTIVE_SPADS_SD0_LO 0x0FC5 + + + + + + + +#define VL53L1_SHADOW_RESULT__AVG_SIGNAL_COUNT_RATE_MCPS_SD0 0x0FC6 + + + + + + + + + + + + + + + + +#define VL53L1_SHADOW_RESULT__AVG_SIGNAL_COUNT_RATE_MCPS_SD0_HI 0x0FC6 + + + + + + + +#define VL53L1_SHADOW_RESULT__AVG_SIGNAL_COUNT_RATE_MCPS_SD0_LO 0x0FC7 + + + + + + + +#define VL53L1_SHADOW_RESULT__DSS_ACTUAL_EFFECTIVE_SPADS_SD1 0x0FC8 + + + + + + + + + + + + + + + + +#define VL53L1_SHADOW_RESULT__DSS_ACTUAL_EFFECTIVE_SPADS_SD1_HI 0x0FC8 + + + + + + + +#define VL53L1_SHADOW_RESULT__DSS_ACTUAL_EFFECTIVE_SPADS_SD1_LO 0x0FC9 + + + + + + + +#define VL53L1_SHADOW_RESULT__PEAK_SIGNAL_COUNT_RATE_MCPS_SD1 0x0FCA + + + + + + + + + + + + + + + + +#define VL53L1_SHADOW_RESULT__PEAK_SIGNAL_COUNT_RATE_MCPS_SD1_HI 0x0FCA + + + + + + + +#define VL53L1_SHADOW_RESULT__PEAK_SIGNAL_COUNT_RATE_MCPS_SD1_LO 0x0FCB + + + + + + + +#define VL53L1_SHADOW_RESULT__AMBIENT_COUNT_RATE_MCPS_SD1 0x0FCC + + + + + + + + + + + + + + + + +#define VL53L1_SHADOW_RESULT__AMBIENT_COUNT_RATE_MCPS_SD1_HI 0x0FCC + + + + + + + +#define VL53L1_SHADOW_RESULT__AMBIENT_COUNT_RATE_MCPS_SD1_LO 0x0FCD + + + + + + + +#define VL53L1_SHADOW_RESULT__SIGMA_SD1 0x0FCE + + + + + + + + + + + + + + + +#define VL53L1_SHADOW_RESULT__SIGMA_SD1_HI 0x0FCE + + + + + + + +#define VL53L1_SHADOW_RESULT__SIGMA_SD1_LO 0x0FCF + + + + + + + +#define VL53L1_SHADOW_RESULT__PHASE_SD1 0x0FD0 + + + + + + + + + + + + + + + +#define VL53L1_SHADOW_RESULT__PHASE_SD1_HI 0x0FD0 + + + + + + + +#define VL53L1_SHADOW_RESULT__PHASE_SD1_LO 0x0FD1 + + + + + + + +#define VL53L1_SHADOW_RESULT__FINAL_CROSSTALK_CORRECTED_RANGE_MM_SD1 0x0FD2 + + + + + + + + + + + + + + + +#define VL53L1_SHADOW_RESULT__FINAL_CROSSTALK_CORRECTED_RANGE_MM_SD1_HI 0x0FD2 + + + + + + + +#define VL53L1_SHADOW_RESULT__FINAL_CROSSTALK_CORRECTED_RANGE_MM_SD1_LO 0x0FD3 + + + + + + + +#define VL53L1_SHADOW_RESULT__SPARE_0_SD1 0x0FD4 + + + + + + + + + + + + + + + +#define VL53L1_SHADOW_RESULT__SPARE_0_SD1_HI 0x0FD4 + + + + + + + +#define VL53L1_SHADOW_RESULT__SPARE_0_SD1_LO 0x0FD5 + + + + + + + +#define VL53L1_SHADOW_RESULT__SPARE_1_SD1 0x0FD6 + + + + + + + + + + + + + + + +#define VL53L1_SHADOW_RESULT__SPARE_1_SD1_HI 0x0FD6 + + + + + + + +#define VL53L1_SHADOW_RESULT__SPARE_1_SD1_LO 0x0FD7 + + + + + + + +#define VL53L1_SHADOW_RESULT__SPARE_2_SD1 0x0FD8 + + + + + + + + + + + + + + + +#define VL53L1_SHADOW_RESULT__SPARE_2_SD1_HI 0x0FD8 + + + + + + + +#define VL53L1_SHADOW_RESULT__SPARE_2_SD1_LO 0x0FD9 + + + + + + + +#define VL53L1_SHADOW_RESULT__SPARE_3_SD1 0x0FDA + + + + + + + + + + + + + + + +#define VL53L1_SHADOW_RESULT__THRESH_INFO 0x0FDB + + + + + + + + + + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD0 0x0FDC + + + + + + + + + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD0_3 0x0FDC + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD0_2 0x0FDD + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD0_1 0x0FDE + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD0_0 0x0FDF + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__RANGING_TOTAL_EVENTS_SD0 0x0FE0 + + + + + + + + + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__RANGING_TOTAL_EVENTS_SD0_3 0x0FE0 + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__RANGING_TOTAL_EVENTS_SD0_2 0x0FE1 + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__RANGING_TOTAL_EVENTS_SD0_1 0x0FE2 + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__RANGING_TOTAL_EVENTS_SD0_0 0x0FE3 + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__SIGNAL_TOTAL_EVENTS_SD0 0x0FE4 + + + + + + + + + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__SIGNAL_TOTAL_EVENTS_SD0_3 0x0FE4 + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__SIGNAL_TOTAL_EVENTS_SD0_2 0x0FE5 + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__SIGNAL_TOTAL_EVENTS_SD0_1 0x0FE6 + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__SIGNAL_TOTAL_EVENTS_SD0_0 0x0FE7 + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__TOTAL_PERIODS_ELAPSED_SD0 0x0FE8 + + + + + + + + + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__TOTAL_PERIODS_ELAPSED_SD0_3 0x0FE8 + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__TOTAL_PERIODS_ELAPSED_SD0_2 0x0FE9 + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__TOTAL_PERIODS_ELAPSED_SD0_1 0x0FEA + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__TOTAL_PERIODS_ELAPSED_SD0_0 0x0FEB + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD1 0x0FEC + + + + + + + + + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD1_3 0x0FEC + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD1_2 0x0FED + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD1_1 0x0FEE + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD1_0 0x0FEF + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__RANGING_TOTAL_EVENTS_SD1 0x0FF0 + + + + + + + + + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__RANGING_TOTAL_EVENTS_SD1_3 0x0FF0 + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__RANGING_TOTAL_EVENTS_SD1_2 0x0FF1 + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__RANGING_TOTAL_EVENTS_SD1_1 0x0FF2 + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__RANGING_TOTAL_EVENTS_SD1_0 0x0FF3 + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__SIGNAL_TOTAL_EVENTS_SD1 0x0FF4 + + + + + + + + + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__SIGNAL_TOTAL_EVENTS_SD1_3 0x0FF4 + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__SIGNAL_TOTAL_EVENTS_SD1_2 0x0FF5 + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__SIGNAL_TOTAL_EVENTS_SD1_1 0x0FF6 + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__SIGNAL_TOTAL_EVENTS_SD1_0 0x0FF7 + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__TOTAL_PERIODS_ELAPSED_SD1 0x0FF8 + + + + + + + + + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__TOTAL_PERIODS_ELAPSED_SD1_3 0x0FF8 + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__TOTAL_PERIODS_ELAPSED_SD1_2 0x0FF9 + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__TOTAL_PERIODS_ELAPSED_SD1_1 0x0FFA + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__TOTAL_PERIODS_ELAPSED_SD1_0 0x0FFB + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__SPARE_0 0x0FFC + + + + + + + + + + + + + + + +#define VL53L1_SHADOW_PHASECAL_RESULT__REFERENCE_PHASE_HI 0x0FFE + + + + + + + + + + + + + + + +#define VL53L1_SHADOW_PHASECAL_RESULT__REFERENCE_PHASE_LO 0x0FFF + + + + + + + + + + + + + + + + + + + + +#endif + + diff --git a/drivers/input/misc/vl53L1/lito/inc/vl53l1_register_settings.h b/drivers/input/misc/vl53L1/lito/inc/vl53l1_register_settings.h new file mode 100644 index 000000000000..767367f08217 --- /dev/null +++ b/drivers/input/misc/vl53L1/lito/inc/vl53l1_register_settings.h @@ -0,0 +1,274 @@ + +/******************************************************************************* + * Copyright (c) 2017, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#ifndef _VL53L1_REGISTER_SETTINGS_H_ +#define _VL53L1_REGISTER_SETTINGS_H_ + + + + + + + + + + + + + + + + +#define VL53L1_DEVICESCHEDULERMODE_PSEUDO_SOLO 0x00 +#define VL53L1_DEVICESCHEDULERMODE_STREAMING 0x01 +#define VL53L1_DEVICESCHEDULERMODE_HISTOGRAM 0x02 + + + + + + + + + + + +#define VL53L1_DEVICEREADOUTMODE_SINGLE_SD (0x00 << 2) +#define VL53L1_DEVICEREADOUTMODE_DUAL_SD (0x01 << 2) +#define VL53L1_DEVICEREADOUTMODE_SPLIT_READOUT (0x02 << 2) +#define VL53L1_DEVICEREADOUTMODE_SPLIT_MANUAL (0x03 << 2) + + + + + + + + + + + + + + + + + + + +#define VL53L1_DEVICEMEASUREMENTMODE_MODE_MASK 0xF0 +#define VL53L1_DEVICEMEASUREMENTMODE_STOP_MASK 0x0F + +#define VL53L1_GROUPEDPARAMETERHOLD_ID_MASK 0x02 + + + + +#define VL53L1_EWOK_I2C_DEV_ADDR_DEFAULT 0x29 + + +#define VL53L1_OSC_FREQUENCY 0x00 +#define VL53L1_OSC_TRIM_DEFAULT 0x00 +#define VL53L1_OSC_FREQ_SET_DEFAULT 0x00 + +#define VL53L1_RANGE_HISTOGRAM_REF 0x08 +#define VL53L1_RANGE_HISTOGRAM_RET 0x10 +#define VL53L1_RANGE_HISTOGRAM_BOTH 0x18 +#define VL53L1_RANGE_HISTOGRAM_INIT 0x20 +#define VL53L1_RANGE_VHV_INIT 0x40 + + + +#define VL53L1_RESULT_RANGE_STATUS 0x1F + + + +#define VL53L1_SYSTEM__SEED_CONFIG__MANUAL 0x00 +#define VL53L1_SYSTEM__SEED_CONFIG__STANDARD 0x01 +#define VL53L1_SYSTEM__SEED_CONFIG__EVEN_UPDATE_ONLY 0x02 + + + +#define VL53L1_INTERRUPT_CONFIG_LEVEL_LOW 0x00 +#define VL53L1_INTERRUPT_CONFIG_LEVEL_HIGH 0x01 +#define VL53L1_INTERRUPT_CONFIG_OUT_OF_WINDOW 0x02 +#define VL53L1_INTERRUPT_CONFIG_IN_WINDOW 0x03 +#define VL53L1_INTERRUPT_CONFIG_NEW_SAMPLE_READY 0x20 + + + +#define VL53L1_CLEAR_RANGE_INT 0x01 +#define VL53L1_CLEAR_ERROR_INT 0x02 + + + +#define VL53L1_SEQUENCE_VHV_EN 0x01 +#define VL53L1_SEQUENCE_PHASECAL_EN 0x02 +#define VL53L1_SEQUENCE_REFERENCE_PHASE_EN 0x04 +#define VL53L1_SEQUENCE_DSS1_EN 0x08 +#define VL53L1_SEQUENCE_DSS2_EN 0x10 +#define VL53L1_SEQUENCE_MM1_EN 0x20 +#define VL53L1_SEQUENCE_MM2_EN 0x40 +#define VL53L1_SEQUENCE_RANGE_EN 0x80 + + + +#define VL53L1_DSS_CONTROL__ROI_SUBTRACT 0x20 +#define VL53L1_DSS_CONTROL__ROI_INTERSECT 0x10 + +#define VL53L1_DSS_CONTROL__MODE_DISABLED 0x00 +#define VL53L1_DSS_CONTROL__MODE_TARGET_RATE 0x01 +#define VL53L1_DSS_CONTROL__MODE_EFFSPADS 0x02 +#define VL53L1_DSS_CONTROL__MODE_BLOCKSELECT 0x03 + + + + + + + + + + +#define VL53L1_RANGING_CORE__SPAD_READOUT__STANDARD 0x45 +#define VL53L1_RANGING_CORE__SPAD_READOUT__RETURN_ARRAY_ONLY 0x05 +#define VL53L1_RANGING_CORE__SPAD_READOUT__REFERENCE_ARRAY_ONLY 0x55 +#define VL53L1_RANGING_CORE__SPAD_READOUT__RETURN_SPLIT_ARRAY 0x25 +#define VL53L1_RANGING_CORE__SPAD_READOUT__CALIB_PULSES 0xF5 + + +#define VL53L1_LASER_SAFETY__KEY_VALUE 0x6C + + + + + + + + + + +#define VL53L1_RANGE_STATUS__RANGE_STATUS_MASK 0x1F +#define VL53L1_RANGE_STATUS__MAX_THRESHOLD_HIT_MASK 0x20 +#define VL53L1_RANGE_STATUS__MIN_THRESHOLD_HIT_MASK 0x40 +#define VL53L1_RANGE_STATUS__GPH_ID_RANGE_STATUS_MASK 0x80 + + + + + + + + + +#define VL53L1_INTERRUPT_STATUS__INT_STATUS_MASK 0x07 +#define VL53L1_INTERRUPT_STATUS__INT_ERROR_STATUS_MASK 0x18 +#define VL53L1_INTERRUPT_STATUS__GPH_ID_INT_STATUS_MASK 0x20 + + + + + +#endif + + + + + + diff --git a/drivers/input/misc/vl53L1/lito/inc/vl53l1_register_structs.h b/drivers/input/misc/vl53L1/lito/inc/vl53l1_register_structs.h new file mode 100644 index 000000000000..c5d70adf68f2 --- /dev/null +++ b/drivers/input/misc/vl53L1/lito/inc/vl53l1_register_structs.h @@ -0,0 +1,4872 @@ + +/******************************************************************************* + * Copyright (c) 2017, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#ifndef _VL53L1_REGISTER_STRUCTS_H_ +#define _VL53L1_REGISTER_STRUCTS_H_ + +#include "vl53l1_types.h" +#include "vl53l1_register_map.h" + +#define VL53L1_STATIC_NVM_MANAGED_I2C_INDEX \ + VL53L1_I2C_SLAVE__DEVICE_ADDRESS +#define VL53L1_CUSTOMER_NVM_MANAGED_I2C_INDEX \ + VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_REF_0 +#define VL53L1_STATIC_CONFIG_I2C_INDEX \ + VL53L1_DSS_CONFIG__TARGET_TOTAL_RATE_MCPS +#define VL53L1_GENERAL_CONFIG_I2C_INDEX \ + VL53L1_GPH_CONFIG__STREAM_COUNT_UPDATE_VALUE +#define VL53L1_TIMING_CONFIG_I2C_INDEX \ + VL53L1_MM_CONFIG__TIMEOUT_MACROP_A_HI +#define VL53L1_DYNAMIC_CONFIG_I2C_INDEX \ + VL53L1_SYSTEM__GROUPED_PARAMETER_HOLD_0 +#define VL53L1_SYSTEM_CONTROL_I2C_INDEX \ + VL53L1_POWER_MANAGEMENT__GO1_POWER_FORCE +#define VL53L1_SYSTEM_RESULTS_I2C_INDEX \ + VL53L1_RESULT__INTERRUPT_STATUS +#define VL53L1_CORE_RESULTS_I2C_INDEX \ + VL53L1_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD0 +#define VL53L1_DEBUG_RESULTS_I2C_INDEX \ + VL53L1_PHASECAL_RESULT__REFERENCE_PHASE +#define VL53L1_NVM_COPY_DATA_I2C_INDEX \ + VL53L1_IDENTIFICATION__MODEL_ID +#define VL53L1_PREV_SHADOW_SYSTEM_RESULTS_I2C_INDEX \ + VL53L1_PREV_SHADOW_RESULT__INTERRUPT_STATUS +#define VL53L1_PREV_SHADOW_CORE_RESULTS_I2C_INDEX \ + VL53L1_PREV_SHADOW_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD0 +#define VL53L1_PATCH_DEBUG_I2C_INDEX \ + VL53L1_RESULT__DEBUG_STATUS +#define VL53L1_GPH_GENERAL_CONFIG_I2C_INDEX \ + VL53L1_GPH__SYSTEM__THRESH_RATE_HIGH +#define VL53L1_GPH_STATIC_CONFIG_I2C_INDEX \ + VL53L1_GPH__DSS_CONFIG__ROI_MODE_CONTROL +#define VL53L1_GPH_TIMING_CONFIG_I2C_INDEX \ + VL53L1_GPH__MM_CONFIG__TIMEOUT_MACROP_A_HI +#define VL53L1_FW_INTERNAL_I2C_INDEX \ + VL53L1_FIRMWARE__INTERNAL_STREAM_COUNT_DIV +#define VL53L1_PATCH_RESULTS_I2C_INDEX \ + VL53L1_DSS_CALC__ROI_CTRL +#define VL53L1_SHADOW_SYSTEM_RESULTS_I2C_INDEX \ + VL53L1_SHADOW_PHASECAL_RESULT__VCSEL_START +#define VL53L1_SHADOW_CORE_RESULTS_I2C_INDEX \ + VL53L1_SHADOW_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD0 + +#define VL53L1_STATIC_NVM_MANAGED_I2C_SIZE_BYTES 11 +#define VL53L1_CUSTOMER_NVM_MANAGED_I2C_SIZE_BYTES 23 +#define VL53L1_STATIC_CONFIG_I2C_SIZE_BYTES 32 +#define VL53L1_GENERAL_CONFIG_I2C_SIZE_BYTES 22 +#define VL53L1_TIMING_CONFIG_I2C_SIZE_BYTES 23 +#define VL53L1_DYNAMIC_CONFIG_I2C_SIZE_BYTES 18 +#define VL53L1_SYSTEM_CONTROL_I2C_SIZE_BYTES 5 +#define VL53L1_SYSTEM_RESULTS_I2C_SIZE_BYTES 44 +#define VL53L1_CORE_RESULTS_I2C_SIZE_BYTES 33 +#define VL53L1_DEBUG_RESULTS_I2C_SIZE_BYTES 56 +#define VL53L1_NVM_COPY_DATA_I2C_SIZE_BYTES 49 +#define VL53L1_PREV_SHADOW_SYSTEM_RESULTS_I2C_SIZE_BYTES 44 +#define VL53L1_PREV_SHADOW_CORE_RESULTS_I2C_SIZE_BYTES 33 +#define VL53L1_PATCH_DEBUG_I2C_SIZE_BYTES 2 +#define VL53L1_GPH_GENERAL_CONFIG_I2C_SIZE_BYTES 5 +#define VL53L1_GPH_STATIC_CONFIG_I2C_SIZE_BYTES 6 +#define VL53L1_GPH_TIMING_CONFIG_I2C_SIZE_BYTES 16 +#define VL53L1_FW_INTERNAL_I2C_SIZE_BYTES 2 +#define VL53L1_PATCH_RESULTS_I2C_SIZE_BYTES 90 +#define VL53L1_SHADOW_SYSTEM_RESULTS_I2C_SIZE_BYTES 82 +#define VL53L1_SHADOW_CORE_RESULTS_I2C_SIZE_BYTES 33 + + + + + + + + + + + + +typedef struct { + uint8_t i2c_slave__device_address; + + + + + + + + + + + uint8_t ana_config__vhv_ref_sel_vddpix; + + + + + + + + + + + uint8_t ana_config__vhv_ref_sel_vquench; + + + + + + + + + + + uint8_t ana_config__reg_avdd1v2_sel; + + + + + + + + + + + uint8_t ana_config__fast_osc__trim; + + + + + + + + + + + uint16_t osc_measured__fast_osc__frequency; + + + + + + + + + + + uint8_t vhv_config__timeout_macrop_loop_bound; + + + + + + + + + + + + uint8_t vhv_config__count_thresh; + + + + + + + + + + + uint8_t vhv_config__offset; + + + + + + + + + + + uint8_t vhv_config__init; + + + + + + + + + + + +} VL53L1_static_nvm_managed_t; + + + + + + + + + + + + +typedef struct { + uint8_t global_config__spad_enables_ref_0; + + + + + + + + + + + uint8_t global_config__spad_enables_ref_1; + + + + + + + + + + + uint8_t global_config__spad_enables_ref_2; + + + + + + + + + + + uint8_t global_config__spad_enables_ref_3; + + + + + + + + + + + uint8_t global_config__spad_enables_ref_4; + + + + + + + + + + + uint8_t global_config__spad_enables_ref_5; + + + + + + + + + + + uint8_t global_config__ref_en_start_select; + + + + + + + + + + + uint8_t ref_spad_man__num_requested_ref_spads; + + + + + + + + + + + uint8_t ref_spad_man__ref_location; + + + + + + + + + + + uint16_t algo__crosstalk_compensation_plane_offset_kcps; + + + + + + + + + + + int16_t algo__crosstalk_compensation_x_plane_gradient_kcps; + + + + + + + + + + + int16_t algo__crosstalk_compensation_y_plane_gradient_kcps; + + + + + + + + + + + uint16_t ref_spad_char__total_rate_target_mcps; + + + + + + + + + + + int16_t algo__part_to_part_range_offset_mm; + + + + + + + + + + + int16_t mm_config__inner_offset_mm; + + + + + + + + + + + int16_t mm_config__outer_offset_mm; + + + + + + + + + + +} VL53L1_customer_nvm_managed_t; + + + + + + + + + + + + +typedef struct { + uint16_t dss_config__target_total_rate_mcps; + + + + + + + + + + + uint8_t debug__ctrl; + + + + + + + + + + + uint8_t test_mode__ctrl; + + + + + + + + + + + uint8_t clk_gating__ctrl; + + + + + + + + + + + + + + uint8_t nvm_bist__ctrl; + + + + + + + + + + + + uint8_t nvm_bist__num_nvm_words; + + + + + + + + + + + uint8_t nvm_bist__start_address; + + + + + + + + + + + uint8_t host_if__status; + + + + + + + + + + + uint8_t pad_i2c_hv__config; + + + + + + + + + + + + + + + + uint8_t pad_i2c_hv__extsup_config; + + + + + + + + + + + uint8_t gpio_hv_pad__ctrl; + + + + + + + + + + + + uint8_t gpio_hv_mux__ctrl; + + + + + + + + + + + + uint8_t gpio__tio_hv_status; + + + + + + + + + + + + uint8_t gpio__fio_hv_status; + + + + + + + + + + + uint8_t ana_config__spad_sel_pswidth; + + + + + + + + + + + uint8_t ana_config__vcsel_pulse_width_offset; + + + + + + + + + + + uint8_t ana_config__fast_osc__config_ctrl; + + + + + + + + + + + uint8_t sigma_estimator__effective_pulse_width_ns; + + + + + + + + + + + uint8_t sigma_estimator__effective_ambient_width_ns; + + + + + + + + + + + uint8_t sigma_estimator__sigma_ref_mm; + + + + + + + + + + + uint8_t algo__crosstalk_compensation_valid_height_mm; + + + + + + + + + + + uint8_t spare_host_config__static_config_spare_0; + + + + + + + + + + + uint8_t spare_host_config__static_config_spare_1; + + + + + + + + + + + uint16_t algo__range_ignore_threshold_mcps; + + + + + + + + + + + uint8_t algo__range_ignore_valid_height_mm; + + + + + + + + + + + uint8_t algo__range_min_clip; + + + + + + + + + + + + uint8_t algo__consistency_check__tolerance; + + + + + + + + + + + uint8_t spare_host_config__static_config_spare_2; + + + + + + + + + + + uint8_t sd_config__reset_stages_msb; + + + + + + + + + + + uint8_t sd_config__reset_stages_lsb; + + + + + + + + + + + +} VL53L1_static_config_t; + + + + + + + + + + + + +typedef struct { + uint8_t gph_config__stream_count_update_value; + + + + + + + + + + + uint8_t global_config__stream_divider; + + + + + + + + + + + uint8_t system__interrupt_config_gpio; + + + + + + + + + + + + + + + + uint8_t cal_config__vcsel_start; + + + + + + + + + + + uint16_t cal_config__repeat_rate; + + + + + + + + + + + uint8_t global_config__vcsel_width; + + + + + + + + + + + uint8_t phasecal_config__timeout_macrop; + + + + + + + + + + + uint8_t phasecal_config__target; + + + + + + + + + + + uint8_t phasecal_config__override; + + + + + + + + + + + uint8_t dss_config__roi_mode_control; + + + + + + + + + + + + uint16_t system__thresh_rate_high; + + + + + + + + + + + uint16_t system__thresh_rate_low; + + + + + + + + + + + uint16_t dss_config__manual_effective_spads_select; + + + + + + + + + + + uint8_t dss_config__manual_block_select; + + + + + + + + + + + uint8_t dss_config__aperture_attenuation; + + + + + + + + + + + uint8_t dss_config__max_spads_limit; + + + + + + + + + + + uint8_t dss_config__min_spads_limit; + + + + + + + + + + +} VL53L1_general_config_t; + + + + + + + + + + + + +typedef struct { + uint8_t mm_config__timeout_macrop_a_hi; + + + + + + + + + + + uint8_t mm_config__timeout_macrop_a_lo; + + + + + + + + + + + uint8_t mm_config__timeout_macrop_b_hi; + + + + + + + + + + + uint8_t mm_config__timeout_macrop_b_lo; + + + + + + + + + + + uint8_t range_config__timeout_macrop_a_hi; + + + + + + + + + + + uint8_t range_config__timeout_macrop_a_lo; + + + + + + + + + + + uint8_t range_config__vcsel_period_a; + + + + + + + + + + + uint8_t range_config__timeout_macrop_b_hi; + + + + + + + + + + + uint8_t range_config__timeout_macrop_b_lo; + + + + + + + + + + + uint8_t range_config__vcsel_period_b; + + + + + + + + + + + uint16_t range_config__sigma_thresh; + + + + + + + + + + + uint16_t range_config__min_count_rate_rtn_limit_mcps; + + + + + + + + + + + uint8_t range_config__valid_phase_low; + + + + + + + + + + + uint8_t range_config__valid_phase_high; + + + + + + + + + + + uint32_t system__intermeasurement_period; + + + + + + + + + + + uint8_t system__fractional_enable; + + + + + + + + + + +} VL53L1_timing_config_t; + + + + + + + + + + + + +typedef struct { + uint8_t system__grouped_parameter_hold_0; + + + + + + + + + + + + uint16_t system__thresh_high; + + + + + + + + + + + uint16_t system__thresh_low; + + + + + + + + + + + uint8_t system__enable_xtalk_per_quadrant; + + + + + + + + + + + uint8_t system__seed_config; + + + + + + + + + + + + uint8_t sd_config__woi_sd0; + + + + + + + + + + + uint8_t sd_config__woi_sd1; + + + + + + + + + + + uint8_t sd_config__initial_phase_sd0; + + + + + + + + + + + uint8_t sd_config__initial_phase_sd1; + + + + + + + + + + + uint8_t system__grouped_parameter_hold_1; + + + + + + + + + + + + uint8_t sd_config__first_order_select; + + + + + + + + + + + + uint8_t sd_config__quantifier; + + + + + + + + + + + uint8_t roi_config__user_roi_centre_spad; + + + + + + + + + + + uint8_t roi_config__user_roi_requested_global_xy_size; + + + + + + + + + + + uint8_t system__sequence_config; + + + + + + + + + + + + + + + + + + uint8_t system__grouped_parameter_hold; + + + + + + + + + + + +} VL53L1_dynamic_config_t; + + + + + + + + + + + + +typedef struct { + uint8_t power_management__go1_power_force; + + + + + + + + + + + uint8_t system__stream_count_ctrl; + + + + + + + + + + + uint8_t firmware__enable; + + + + + + + + + + + uint8_t system__interrupt_clear; + + + + + + + + + + + + uint8_t system__mode_start; + + + + + + + + + + + + + + + +} VL53L1_system_control_t; + + + + + + + + + + + + +typedef struct { + uint8_t result__interrupt_status; + + + + + + + + + + + + + uint8_t result__range_status; + + + + + + + + + + + + + + uint8_t result__report_status; + + + + + + + + + + + uint8_t result__stream_count; + + + + + + + + + + + uint16_t result__dss_actual_effective_spads_sd0; + + + + + + + + + + + uint16_t result__peak_signal_count_rate_mcps_sd0; + + + + + + + + + + + uint16_t result__ambient_count_rate_mcps_sd0; + + + + + + + + + + + uint16_t result__sigma_sd0; + + + + + + + + + + + uint16_t result__phase_sd0; + + + + + + + + + + + uint16_t result__final_crosstalk_corrected_range_mm_sd0; + + + + + + + + + + + uint16_t result__peak_signal_count_rate_crosstalk_corrected_mcps_sd0; + + + + + + + + + + + uint16_t result__mm_inner_actual_effective_spads_sd0; + + + + + + + + + + + uint16_t result__mm_outer_actual_effective_spads_sd0; + + + + + + + + + + + uint16_t result__avg_signal_count_rate_mcps_sd0; + + + + + + + + + + + uint16_t result__dss_actual_effective_spads_sd1; + + + + + + + + + + + uint16_t result__peak_signal_count_rate_mcps_sd1; + + + + + + + + + + + uint16_t result__ambient_count_rate_mcps_sd1; + + + + + + + + + + + uint16_t result__sigma_sd1; + + + + + + + + + + + uint16_t result__phase_sd1; + + + + + + + + + + + uint16_t result__final_crosstalk_corrected_range_mm_sd1; + + + + + + + + + + + uint16_t result__spare_0_sd1; + + + + + + + + + + + uint16_t result__spare_1_sd1; + + + + + + + + + + + uint16_t result__spare_2_sd1; + + + + + + + + + + + uint8_t result__spare_3_sd1; + + + + + + + + + + + uint8_t result__thresh_info; + + + + + + + + + + + +} VL53L1_system_results_t; + + + + + + + + + + + + +typedef struct { + uint32_t result_core__ambient_window_events_sd0; + + + + + + + + + + + uint32_t result_core__ranging_total_events_sd0; + + + + + + + + + + + int32_t result_core__signal_total_events_sd0; + + + + + + + + + + + uint32_t result_core__total_periods_elapsed_sd0; + + + + + + + + + + + uint32_t result_core__ambient_window_events_sd1; + + + + + + + + + + + uint32_t result_core__ranging_total_events_sd1; + + + + + + + + + + + int32_t result_core__signal_total_events_sd1; + + + + + + + + + + + uint32_t result_core__total_periods_elapsed_sd1; + + + + + + + + + + + uint8_t result_core__spare_0; + + + + + + + + + + +} VL53L1_core_results_t; + + + + + + + + + + + + +typedef struct { + uint16_t phasecal_result__reference_phase; + + + + + + + + + + + uint8_t phasecal_result__vcsel_start; + + + + + + + + + + + uint8_t ref_spad_char_result__num_actual_ref_spads; + + + + + + + + + + + uint8_t ref_spad_char_result__ref_location; + + + + + + + + + + + uint8_t vhv_result__coldboot_status; + + + + + + + + + + + uint8_t vhv_result__search_result; + + + + + + + + + + + uint8_t vhv_result__latest_setting; + + + + + + + + + + + uint16_t result__osc_calibrate_val; + + + + + + + + + + + uint8_t ana_config__powerdown_go1; + + + + + + + + + + + + uint8_t ana_config__ref_bg_ctrl; + + + + + + + + + + + + uint8_t ana_config__regdvdd1v2_ctrl; + + + + + + + + + + + + + uint8_t ana_config__osc_slow_ctrl; + + + + + + + + + + + + + uint8_t test_mode__status; + + + + + + + + + + + uint8_t firmware__system_status; + + + + + + + + + + + + uint8_t firmware__mode_status; + + + + + + + + + + + uint8_t firmware__secondary_mode_status; + + + + + + + + + + + uint16_t firmware__cal_repeat_rate_counter; + + + + + + + + + + + uint16_t gph__system__thresh_high; + + + + + + + + + + + uint16_t gph__system__thresh_low; + + + + + + + + + + + uint8_t gph__system__enable_xtalk_per_quadrant; + + + + + + + + + + + uint8_t gph__spare_0; + + + + + + + + + + + + + uint8_t gph__sd_config__woi_sd0; + + + + + + + + + + + uint8_t gph__sd_config__woi_sd1; + + + + + + + + + + + uint8_t gph__sd_config__initial_phase_sd0; + + + + + + + + + + + uint8_t gph__sd_config__initial_phase_sd1; + + + + + + + + + + + uint8_t gph__sd_config__first_order_select; + + + + + + + + + + + + uint8_t gph__sd_config__quantifier; + + + + + + + + + + + uint8_t gph__roi_config__user_roi_centre_spad; + + + + + + + + + + + uint8_t gph__roi_config__user_roi_requested_global_xy_size; + + + + + + + + + + + uint8_t gph__system__sequence_config; + + + + + + + + + + + + + + + + + + uint8_t gph__gph_id; + + + + + + + + + + + uint8_t system__interrupt_set; + + + + + + + + + + + + uint8_t interrupt_manager__enables; + + + + + + + + + + + + + + + uint8_t interrupt_manager__clear; + + + + + + + + + + + + + + + uint8_t interrupt_manager__status; + + + + + + + + + + + + + + + uint8_t mcu_to_host_bank__wr_access_en; + + + + + + + + + + + uint8_t power_management__go1_reset_status; + + + + + + + + + + + uint8_t pad_startup_mode__value_ro; + + + + + + + + + + + + uint8_t pad_startup_mode__value_ctrl; + + + + + + + + + + + + + + uint32_t pll_period_us; + + + + + + + + + + + uint32_t interrupt_scheduler__data_out; + + + + + + + + + + + uint8_t nvm_bist__complete; + + + + + + + + + + + uint8_t nvm_bist__status; + + + + + + + + + + +} VL53L1_debug_results_t; + + + + + + + + + + + + +typedef struct { + uint8_t identification__model_id; + + + + + + + + + + + uint8_t identification__module_type; + + + + + + + + + + + uint8_t identification__revision_id; + + + + + + + + + + + + uint16_t identification__module_id; + + + + + + + + + + + uint8_t ana_config__fast_osc__trim_max; + + + + + + + + + + + uint8_t ana_config__fast_osc__freq_set; + + + + + + + + + + + uint8_t ana_config__vcsel_trim; + + + + + + + + + + + uint8_t ana_config__vcsel_selion; + + + + + + + + + + + uint8_t ana_config__vcsel_selion_max; + + + + + + + + + + + uint8_t protected_laser_safety__lock_bit; + + + + + + + + + + + uint8_t laser_safety__key; + + + + + + + + + + + uint8_t laser_safety__key_ro; + + + + + + + + + + + uint8_t laser_safety__clip; + + + + + + + + + + + uint8_t laser_safety__mult; + + + + + + + + + + + uint8_t global_config__spad_enables_rtn_0; + + + + + + + + + + + uint8_t global_config__spad_enables_rtn_1; + + + + + + + + + + + uint8_t global_config__spad_enables_rtn_2; + + + + + + + + + + + uint8_t global_config__spad_enables_rtn_3; + + + + + + + + + + + uint8_t global_config__spad_enables_rtn_4; + + + + + + + + + + + uint8_t global_config__spad_enables_rtn_5; + + + + + + + + + + + uint8_t global_config__spad_enables_rtn_6; + + + + + + + + + + + uint8_t global_config__spad_enables_rtn_7; + + + + + + + + + + + uint8_t global_config__spad_enables_rtn_8; + + + + + + + + + + + uint8_t global_config__spad_enables_rtn_9; + + + + + + + + + + + uint8_t global_config__spad_enables_rtn_10; + + + + + + + + + + + uint8_t global_config__spad_enables_rtn_11; + + + + + + + + + + + uint8_t global_config__spad_enables_rtn_12; + + + + + + + + + + + uint8_t global_config__spad_enables_rtn_13; + + + + + + + + + + + uint8_t global_config__spad_enables_rtn_14; + + + + + + + + + + + uint8_t global_config__spad_enables_rtn_15; + + + + + + + + + + + uint8_t global_config__spad_enables_rtn_16; + + + + + + + + + + + uint8_t global_config__spad_enables_rtn_17; + + + + + + + + + + + uint8_t global_config__spad_enables_rtn_18; + + + + + + + + + + + uint8_t global_config__spad_enables_rtn_19; + + + + + + + + + + + uint8_t global_config__spad_enables_rtn_20; + + + + + + + + + + + uint8_t global_config__spad_enables_rtn_21; + + + + + + + + + + + uint8_t global_config__spad_enables_rtn_22; + + + + + + + + + + + uint8_t global_config__spad_enables_rtn_23; + + + + + + + + + + + uint8_t global_config__spad_enables_rtn_24; + + + + + + + + + + + uint8_t global_config__spad_enables_rtn_25; + + + + + + + + + + + uint8_t global_config__spad_enables_rtn_26; + + + + + + + + + + + uint8_t global_config__spad_enables_rtn_27; + + + + + + + + + + + uint8_t global_config__spad_enables_rtn_28; + + + + + + + + + + + uint8_t global_config__spad_enables_rtn_29; + + + + + + + + + + + uint8_t global_config__spad_enables_rtn_30; + + + + + + + + + + + uint8_t global_config__spad_enables_rtn_31; + + + + + + + + + + + uint8_t roi_config__mode_roi_centre_spad; + + + + + + + + + + + uint8_t roi_config__mode_roi_xy_size; + + + + + + + + + + +} VL53L1_nvm_copy_data_t; + + + + + + + + + + + + +typedef struct { + uint8_t prev_shadow_result__interrupt_status; + + + + + + + + + + + + + uint8_t prev_shadow_result__range_status; + + + + + + + + + + + + + + uint8_t prev_shadow_result__report_status; + + + + + + + + + + + uint8_t prev_shadow_result__stream_count; + + + + + + + + + + + uint16_t prev_shadow_result__dss_actual_effective_spads_sd0; + + + + + + + + + + + uint16_t prev_shadow_result__peak_signal_count_rate_mcps_sd0; + + + + + + + + + + + uint16_t prev_shadow_result__ambient_count_rate_mcps_sd0; + + + + + + + + + + + uint16_t prev_shadow_result__sigma_sd0; + + + + + + + + + + + uint16_t prev_shadow_result__phase_sd0; + + + + + + + + + + + uint16_t prev_shadow_result__final_crosstalk_corrected_range_mm_sd0; + + + + + + + + + + + uint16_t + psr__peak_signal_count_rate_crosstalk_corrected_mcps_sd0; + + + + + + + + + + + uint16_t prev_shadow_result__mm_inner_actual_effective_spads_sd0; + + + + + + + + + + + uint16_t prev_shadow_result__mm_outer_actual_effective_spads_sd0; + + + + + + + + + + + uint16_t prev_shadow_result__avg_signal_count_rate_mcps_sd0; + + + + + + + + + + + uint16_t prev_shadow_result__dss_actual_effective_spads_sd1; + + + + + + + + + + + uint16_t prev_shadow_result__peak_signal_count_rate_mcps_sd1; + + + + + + + + + + + uint16_t prev_shadow_result__ambient_count_rate_mcps_sd1; + + + + + + + + + + + uint16_t prev_shadow_result__sigma_sd1; + + + + + + + + + + + uint16_t prev_shadow_result__phase_sd1; + + + + + + + + + + + uint16_t prev_shadow_result__final_crosstalk_corrected_range_mm_sd1; + + + + + + + + + + + uint16_t prev_shadow_result__spare_0_sd1; + + + + + + + + + + + uint16_t prev_shadow_result__spare_1_sd1; + + + + + + + + + + + uint16_t prev_shadow_result__spare_2_sd1; + + + + + + + + + + + uint16_t prev_shadow_result__spare_3_sd1; + + + + + + + + + + +} VL53L1_prev_shadow_system_results_t; + + + + + + + + + + + + +typedef struct { + uint32_t prev_shadow_result_core__ambient_window_events_sd0; + + + + + + + + + + + uint32_t prev_shadow_result_core__ranging_total_events_sd0; + + + + + + + + + + + int32_t prev_shadow_result_core__signal_total_events_sd0; + + + + + + + + + + + uint32_t prev_shadow_result_core__total_periods_elapsed_sd0; + + + + + + + + + + + uint32_t prev_shadow_result_core__ambient_window_events_sd1; + + + + + + + + + + + uint32_t prev_shadow_result_core__ranging_total_events_sd1; + + + + + + + + + + + int32_t prev_shadow_result_core__signal_total_events_sd1; + + + + + + + + + + + uint32_t prev_shadow_result_core__total_periods_elapsed_sd1; + + + + + + + + + + + uint8_t prev_shadow_result_core__spare_0; + + + + + + + + + + +} VL53L1_prev_shadow_core_results_t; + + + + + + + + + + + + +typedef struct { + uint8_t result__debug_status; + + + + + + + + + + + uint8_t result__debug_stage; + + + + + + + + + + +} VL53L1_patch_debug_t; + + + + + + + + + + + + +typedef struct { + uint16_t gph__system__thresh_rate_high; + + + + + + + + + + + uint16_t gph__system__thresh_rate_low; + + + + + + + + + + + uint8_t gph__system__interrupt_config_gpio; + + + + + + + + + + + + + + + +} VL53L1_gph_general_config_t; + + + + + + + + + + + + +typedef struct { + uint8_t gph__dss_config__roi_mode_control; + + + + + + + + + + + + uint16_t gph__dss_config__manual_effective_spads_select; + + + + + + + + + + + uint8_t gph__dss_config__manual_block_select; + + + + + + + + + + + uint8_t gph__dss_config__max_spads_limit; + + + + + + + + + + + uint8_t gph__dss_config__min_spads_limit; + + + + + + + + + + +} VL53L1_gph_static_config_t; + + + + + + + + + + + + +typedef struct { + uint8_t gph__mm_config__timeout_macrop_a_hi; + + + + + + + + + + + uint8_t gph__mm_config__timeout_macrop_a_lo; + + + + + + + + + + + uint8_t gph__mm_config__timeout_macrop_b_hi; + + + + + + + + + + + uint8_t gph__mm_config__timeout_macrop_b_lo; + + + + + + + + + + + uint8_t gph__range_config__timeout_macrop_a_hi; + + + + + + + + + + + uint8_t gph__range_config__timeout_macrop_a_lo; + + + + + + + + + + + uint8_t gph__range_config__vcsel_period_a; + + + + + + + + + + + uint8_t gph__range_config__vcsel_period_b; + + + + + + + + + + + uint8_t gph__range_config__timeout_macrop_b_hi; + + + + + + + + + + + uint8_t gph__range_config__timeout_macrop_b_lo; + + + + + + + + + + + uint16_t gph__range_config__sigma_thresh; + + + + + + + + + + + uint16_t gph__range_config__min_count_rate_rtn_limit_mcps; + + + + + + + + + + + uint8_t gph__range_config__valid_phase_low; + + + + + + + + + + + uint8_t gph__range_config__valid_phase_high; + + + + + + + + + + +} VL53L1_gph_timing_config_t; + + + + + + + + + + + + +typedef struct { + uint8_t firmware__internal_stream_count_div; + + + + + + + + + + + uint8_t firmware__internal_stream_counter_val; + + + + + + + + + + +} VL53L1_fw_internal_t; + + + + + + + + + + + + +typedef struct { + uint8_t dss_calc__roi_ctrl; + + + + + + + + + + + + uint8_t dss_calc__spare_1; + + + + + + + + + + + uint8_t dss_calc__spare_2; + + + + + + + + + + + uint8_t dss_calc__spare_3; + + + + + + + + + + + uint8_t dss_calc__spare_4; + + + + + + + + + + + uint8_t dss_calc__spare_5; + + + + + + + + + + + uint8_t dss_calc__spare_6; + + + + + + + + + + + uint8_t dss_calc__spare_7; + + + + + + + + + + + uint8_t dss_calc__user_roi_spad_en_0; + + + + + + + + + + + uint8_t dss_calc__user_roi_spad_en_1; + + + + + + + + + + + uint8_t dss_calc__user_roi_spad_en_2; + + + + + + + + + + + uint8_t dss_calc__user_roi_spad_en_3; + + + + + + + + + + + uint8_t dss_calc__user_roi_spad_en_4; + + + + + + + + + + + uint8_t dss_calc__user_roi_spad_en_5; + + + + + + + + + + + uint8_t dss_calc__user_roi_spad_en_6; + + + + + + + + + + + uint8_t dss_calc__user_roi_spad_en_7; + + + + + + + + + + + uint8_t dss_calc__user_roi_spad_en_8; + + + + + + + + + + + uint8_t dss_calc__user_roi_spad_en_9; + + + + + + + + + + + uint8_t dss_calc__user_roi_spad_en_10; + + + + + + + + + + + uint8_t dss_calc__user_roi_spad_en_11; + + + + + + + + + + + uint8_t dss_calc__user_roi_spad_en_12; + + + + + + + + + + + uint8_t dss_calc__user_roi_spad_en_13; + + + + + + + + + + + uint8_t dss_calc__user_roi_spad_en_14; + + + + + + + + + + + uint8_t dss_calc__user_roi_spad_en_15; + + + + + + + + + + + uint8_t dss_calc__user_roi_spad_en_16; + + + + + + + + + + + uint8_t dss_calc__user_roi_spad_en_17; + + + + + + + + + + + uint8_t dss_calc__user_roi_spad_en_18; + + + + + + + + + + + uint8_t dss_calc__user_roi_spad_en_19; + + + + + + + + + + + uint8_t dss_calc__user_roi_spad_en_20; + + + + + + + + + + + uint8_t dss_calc__user_roi_spad_en_21; + + + + + + + + + + + uint8_t dss_calc__user_roi_spad_en_22; + + + + + + + + + + + uint8_t dss_calc__user_roi_spad_en_23; + + + + + + + + + + + uint8_t dss_calc__user_roi_spad_en_24; + + + + + + + + + + + uint8_t dss_calc__user_roi_spad_en_25; + + + + + + + + + + + uint8_t dss_calc__user_roi_spad_en_26; + + + + + + + + + + + uint8_t dss_calc__user_roi_spad_en_27; + + + + + + + + + + + uint8_t dss_calc__user_roi_spad_en_28; + + + + + + + + + + + uint8_t dss_calc__user_roi_spad_en_29; + + + + + + + + + + + uint8_t dss_calc__user_roi_spad_en_30; + + + + + + + + + + + uint8_t dss_calc__user_roi_spad_en_31; + + + + + + + + + + + uint8_t dss_calc__user_roi_0; + + + + + + + + + + + uint8_t dss_calc__user_roi_1; + + + + + + + + + + + uint8_t dss_calc__mode_roi_0; + + + + + + + + + + + uint8_t dss_calc__mode_roi_1; + + + + + + + + + + + uint8_t sigma_estimator_calc__spare_0; + + + + + + + + + + + uint16_t vhv_result__peak_signal_rate_mcps; + + + + + + + + + + + uint32_t vhv_result__signal_total_events_ref; + + + + + + + + + + + uint16_t phasecal_result__phase_output_ref; + + + + + + + + + + + uint16_t dss_result__total_rate_per_spad; + + + + + + + + + + + uint8_t dss_result__enabled_blocks; + + + + + + + + + + + uint16_t dss_result__num_requested_spads; + + + + + + + + + + + uint16_t mm_result__inner_intersection_rate; + + + + + + + + + + + uint16_t mm_result__outer_complement_rate; + + + + + + + + + + + uint16_t mm_result__total_offset; + + + + + + + + + + + uint32_t xtalk_calc__xtalk_for_enabled_spads; + + + + + + + + + + + uint32_t xtalk_result__avg_xtalk_user_roi_kcps; + + + + + + + + + + + uint32_t xtalk_result__avg_xtalk_mm_inner_roi_kcps; + + + + + + + + + + + uint32_t xtalk_result__avg_xtalk_mm_outer_roi_kcps; + + + + + + + + + + + uint32_t range_result__accum_phase; + + + + + + + + + + + uint16_t range_result__offset_corrected_range; + + + + + + + + + + +} VL53L1_patch_results_t; + + + + + + + + + + + + +typedef struct { + uint8_t shadow_phasecal_result__vcsel_start; + + + + + + + + + + + uint8_t shadow_result__interrupt_status; + + + + + + + + + + + + + uint8_t shadow_result__range_status; + + + + + + + + + + + + + + uint8_t shadow_result__report_status; + + + + + + + + + + + uint8_t shadow_result__stream_count; + + + + + + + + + + + uint16_t shadow_result__dss_actual_effective_spads_sd0; + + + + + + + + + + + uint16_t shadow_result__peak_signal_count_rate_mcps_sd0; + + + + + + + + + + + uint16_t shadow_result__ambient_count_rate_mcps_sd0; + + + + + + + + + + + uint16_t shadow_result__sigma_sd0; + + + + + + + + + + + uint16_t shadow_result__phase_sd0; + + + + + + + + + + + uint16_t shadow_result__final_crosstalk_corrected_range_mm_sd0; + + + + + + + + + + + uint16_t + shr__peak_signal_count_rate_crosstalk_corrected_mcps_sd0; + + + + + + + + + + + uint16_t shadow_result__mm_inner_actual_effective_spads_sd0; + + + + + + + + + + + uint16_t shadow_result__mm_outer_actual_effective_spads_sd0; + + + + + + + + + + + uint16_t shadow_result__avg_signal_count_rate_mcps_sd0; + + + + + + + + + + + uint16_t shadow_result__dss_actual_effective_spads_sd1; + + + + + + + + + + + uint16_t shadow_result__peak_signal_count_rate_mcps_sd1; + + + + + + + + + + + uint16_t shadow_result__ambient_count_rate_mcps_sd1; + + + + + + + + + + + uint16_t shadow_result__sigma_sd1; + + + + + + + + + + + uint16_t shadow_result__phase_sd1; + + + + + + + + + + + uint16_t shadow_result__final_crosstalk_corrected_range_mm_sd1; + + + + + + + + + + + uint16_t shadow_result__spare_0_sd1; + + + + + + + + + + + uint16_t shadow_result__spare_1_sd1; + + + + + + + + + + + uint16_t shadow_result__spare_2_sd1; + + + + + + + + + + + uint8_t shadow_result__spare_3_sd1; + + + + + + + + + + + uint8_t shadow_result__thresh_info; + + + + + + + + + + + + uint8_t shadow_phasecal_result__reference_phase_hi; + + + + + + + + + + + uint8_t shadow_phasecal_result__reference_phase_lo; + + + + + + + + + + +} VL53L1_shadow_system_results_t; + + + + + + + + + + + + +typedef struct { + uint32_t shadow_result_core__ambient_window_events_sd0; + + + + + + + + + + + uint32_t shadow_result_core__ranging_total_events_sd0; + + + + + + + + + + + int32_t shadow_result_core__signal_total_events_sd0; + + + + + + + + + + + uint32_t shadow_result_core__total_periods_elapsed_sd0; + + + + + + + + + + + uint32_t shadow_result_core__ambient_window_events_sd1; + + + + + + + + + + + uint32_t shadow_result_core__ranging_total_events_sd1; + + + + + + + + + + + int32_t shadow_result_core__signal_total_events_sd1; + + + + + + + + + + + uint32_t shadow_result_core__total_periods_elapsed_sd1; + + + + + + + + + + + uint8_t shadow_result_core__spare_0; + + + + + + + + + + +} VL53L1_shadow_core_results_t; + + +#endif + + diff --git a/drivers/input/misc/vl53L1/lito/inc/vl53l1_silicon_core.h b/drivers/input/misc/vl53L1/lito/inc/vl53l1_silicon_core.h new file mode 100644 index 000000000000..f9eea814d65f --- /dev/null +++ b/drivers/input/misc/vl53L1/lito/inc/vl53l1_silicon_core.h @@ -0,0 +1,134 @@ + +/******************************************************************************* + * Copyright (c) 2017, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#ifndef _VL53L1_SILICON_CORE_H_ +#define _VL53L1_SILICON_CORE_H_ + +#include "vl53l1_platform.h" + +#ifdef __cplusplus +extern "C" { +#endif + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_is_firmware_ready_silicon( + VL53L1_DEV Dev, + uint8_t *pready); + + +#ifdef __cplusplus +} +#endif + +#endif + + diff --git a/drivers/input/misc/vl53L1/lito/inc/vl53l1_tuning_parm_defaults.h b/drivers/input/misc/vl53L1/lito/inc/vl53l1_tuning_parm_defaults.h new file mode 100644 index 000000000000..ab9f47b637b4 --- /dev/null +++ b/drivers/input/misc/vl53L1/lito/inc/vl53l1_tuning_parm_defaults.h @@ -0,0 +1,410 @@ + +/******************************************************************************* + * Copyright (c) 2017, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#ifndef _VL53L1_TUNING_PARM_DEFAULTS_H_ +#define _VL53L1_TUNING_PARM_DEFAULTS_H_ + + +#ifdef __cplusplus +extern "C" { +#endif + + + + + + + +#define VL53L1_TUNINGPARM_VERSION_DEFAULT \ +((uint16_t) 27) +#define VL53L1_TUNINGPARM_KEY_TABLE_VERSION_DEFAULT \ +((uint16_t) 14) +#define VL53L1_TUNINGPARM_LLD_VERSION_DEFAULT \ +((uint16_t) 12180) +#define VL53L1_TUNINGPARM_HIST_ALGO_SELECT_DEFAULT \ +((uint8_t) 4) +#define VL53L1_TUNINGPARM_HIST_TARGET_ORDER_DEFAULT \ +((uint8_t) 1) +#define VL53L1_TUNINGPARM_HIST_FILTER_WOI_0_DEFAULT \ +((uint8_t) 1) +#define VL53L1_TUNINGPARM_HIST_FILTER_WOI_1_DEFAULT \ +((uint8_t) 2) +#define VL53L1_TUNINGPARM_HIST_AMB_EST_METHOD_DEFAULT \ +((uint8_t) 1) +#define VL53L1_TUNINGPARM_HIST_AMB_THRESH_SIGMA_0_DEFAULT \ +((uint8_t) 80) +#define VL53L1_TUNINGPARM_HIST_AMB_THRESH_SIGMA_1_DEFAULT \ +((uint8_t) 112) +#define VL53L1_TUNINGPARM_HIST_MIN_AMB_THRESH_EVENTS_DEFAULT \ +((int32_t) 16) +#define VL53L1_TUNINGPARM_HIST_AMB_EVENTS_SCALER_DEFAULT \ +((uint16_t) 4157) +#define VL53L1_TUNINGPARM_HIST_NOISE_THRESHOLD_DEFAULT \ +((uint16_t) 50) +#define VL53L1_TUNINGPARM_HIST_SIGNAL_TOTAL_EVENTS_LIMIT_DEFAULT \ +((int32_t) 100) +#define VL53L1_TUNINGPARM_HIST_SIGMA_EST_REF_MM_DEFAULT \ +((uint8_t) 1) +#define VL53L1_TUNINGPARM_HIST_SIGMA_THRESH_MM_DEFAULT \ +((uint16_t) 160) +#define VL53L1_TUNINGPARM_HIST_GAIN_FACTOR_DEFAULT \ +((uint16_t) 1997) +#define VL53L1_TUNINGPARM_CONSISTENCY_HIST_PHASE_TOLERANCE_DEFAULT \ +((uint8_t) 8) +#define VL53L1_TUNINGPARM_CONSISTENCY_HIST_MIN_MAX_TOLERANCE_MM_DEFAULT \ +((uint16_t) 250) +#define VL53L1_TUNINGPARM_CONSISTENCY_HIST_EVENT_SIGMA_DEFAULT \ +((uint8_t) 240) +#define VL53L1_TUNINGPARM_CONSISTENCY_HIST_EVENT_SIGMA_MIN_SPAD_LIMIT_DEFAULT \ +((uint16_t) 2048) +#define VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_HISTO_LONG_RANGE_DEFAULT \ +((uint8_t) 9) +#define VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_HISTO_MED_RANGE_DEFAULT \ +((uint8_t) 5) +#define VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_HISTO_SHORT_RANGE_DEFAULT \ +((uint8_t) 3) +#define VL53L1_TUNINGPARM_INITIAL_PHASE_REF_HISTO_LONG_RANGE_DEFAULT \ +((uint8_t) 6) +#define VL53L1_TUNINGPARM_INITIAL_PHASE_REF_HISTO_MED_RANGE_DEFAULT \ +((uint8_t) 6) +#define VL53L1_TUNINGPARM_INITIAL_PHASE_REF_HISTO_SHORT_RANGE_DEFAULT \ +((uint8_t) 6) +#define VL53L1_TUNINGPARM_XTALK_DETECT_MIN_VALID_RANGE_MM_DEFAULT \ +((int16_t) -50) +#define VL53L1_TUNINGPARM_XTALK_DETECT_MAX_VALID_RANGE_MM_DEFAULT \ +((int16_t) 50) +#define VL53L1_TUNINGPARM_XTALK_DETECT_MAX_SIGMA_MM_DEFAULT \ +((uint16_t) 140) +#define VL53L1_TUNINGPARM_XTALK_DETECT_MIN_MAX_TOLERANCE_DEFAULT \ +((uint16_t) 50) +#define VL53L1_TUNINGPARM_XTALK_DETECT_MAX_VALID_RATE_KCPS_DEFAULT \ +((uint16_t) 64000) +#define VL53L1_TUNINGPARM_XTALK_DETECT_EVENT_SIGMA_DEFAULT \ +((uint8_t) 80) +#define VL53L1_TUNINGPARM_HIST_XTALK_MARGIN_KCPS_DEFAULT \ +((int16_t) 512) +#define VL53L1_TUNINGPARM_CONSISTENCY_LITE_PHASE_TOLERANCE_DEFAULT \ +((uint8_t) 2) +#define VL53L1_TUNINGPARM_PHASECAL_TARGET_DEFAULT \ +((uint8_t) 33) +#define VL53L1_TUNINGPARM_LITE_CAL_REPEAT_RATE_DEFAULT \ +((uint16_t) 0) +#define VL53L1_TUNINGPARM_LITE_RANGING_GAIN_FACTOR_DEFAULT \ +((uint16_t) 2011) +#define VL53L1_TUNINGPARM_LITE_MIN_CLIP_MM_DEFAULT \ +((uint8_t) 0) +#define VL53L1_TUNINGPARM_LITE_LONG_SIGMA_THRESH_MM_DEFAULT \ +((uint16_t) 60) +#define VL53L1_TUNINGPARM_LITE_MED_SIGMA_THRESH_MM_DEFAULT \ +((uint16_t) 60) +#define VL53L1_TUNINGPARM_LITE_SHORT_SIGMA_THRESH_MM_DEFAULT \ +((uint16_t) 60) +#define VL53L1_TUNINGPARM_LITE_LONG_MIN_COUNT_RATE_RTN_MCPS_DEFAULT \ +((uint16_t) 128) +#define VL53L1_TUNINGPARM_LITE_MED_MIN_COUNT_RATE_RTN_MCPS_DEFAULT \ +((uint16_t) 128) +#define VL53L1_TUNINGPARM_LITE_SHORT_MIN_COUNT_RATE_RTN_MCPS_DEFAULT \ +((uint16_t) 128) +#define VL53L1_TUNINGPARM_LITE_SIGMA_EST_PULSE_WIDTH_DEFAULT \ +((uint8_t) 8) +#define VL53L1_TUNINGPARM_LITE_SIGMA_EST_AMB_WIDTH_NS_DEFAULT \ +((uint8_t) 16) +#define VL53L1_TUNINGPARM_LITE_SIGMA_REF_MM_DEFAULT \ +((uint8_t) 1) +#define VL53L1_TUNINGPARM_LITE_RIT_MULT_DEFAULT \ +((uint8_t) 64) +#define VL53L1_TUNINGPARM_LITE_SEED_CONFIG_DEFAULT \ +((uint8_t) 2) +#define VL53L1_TUNINGPARM_LITE_QUANTIFIER_DEFAULT \ +((uint8_t) 2) +#define VL53L1_TUNINGPARM_LITE_FIRST_ORDER_SELECT_DEFAULT \ +((uint8_t) 0) +#define VL53L1_TUNINGPARM_LITE_XTALK_MARGIN_KCPS_DEFAULT \ +((int16_t) 0) +#define VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_LITE_LONG_RANGE_DEFAULT \ +((uint8_t) 14) +#define VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_LITE_MED_RANGE_DEFAULT \ +((uint8_t) 10) +#define VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_LITE_SHORT_RANGE_DEFAULT \ +((uint8_t) 6) +#define VL53L1_TUNINGPARM_INITIAL_PHASE_REF_LITE_LONG_RANGE_DEFAULT \ +((uint8_t) 14) +#define VL53L1_TUNINGPARM_INITIAL_PHASE_REF_LITE_MED_RANGE_DEFAULT \ +((uint8_t) 10) +#define VL53L1_TUNINGPARM_INITIAL_PHASE_REF_LITE_SHORT_RANGE_DEFAULT \ +((uint8_t) 6) +#define VL53L1_TUNINGPARM_TIMED_SEED_CONFIG_DEFAULT \ +((uint8_t) 1) +#define VL53L1_TUNINGPARM_DMAX_CFG_SIGNAL_THRESH_SIGMA_DEFAULT \ +((uint8_t) 32) +#define VL53L1_TUNINGPARM_DMAX_CFG_REFLECTANCE_ARRAY_0_DEFAULT \ +((uint16_t) 15) +#define VL53L1_TUNINGPARM_DMAX_CFG_REFLECTANCE_ARRAY_1_DEFAULT \ +((uint16_t) 52) +#define VL53L1_TUNINGPARM_DMAX_CFG_REFLECTANCE_ARRAY_2_DEFAULT \ +((uint16_t) 200) +#define VL53L1_TUNINGPARM_DMAX_CFG_REFLECTANCE_ARRAY_3_DEFAULT \ +((uint16_t) 364) +#define VL53L1_TUNINGPARM_DMAX_CFG_REFLECTANCE_ARRAY_4_DEFAULT \ +((uint16_t) 400) +#define VL53L1_TUNINGPARM_VHV_LOOPBOUND_DEFAULT \ +((uint8_t) 129) +#define VL53L1_TUNINGPARM_REFSPADCHAR_DEVICE_TEST_MODE_DEFAULT \ +((uint8_t) 8) +#define VL53L1_TUNINGPARM_REFSPADCHAR_VCSEL_PERIOD_DEFAULT \ +((uint8_t) 11) +#define VL53L1_TUNINGPARM_REFSPADCHAR_PHASECAL_TIMEOUT_US_DEFAULT \ +((uint32_t) 1000) +#define VL53L1_TUNINGPARM_REFSPADCHAR_TARGET_COUNT_RATE_MCPS_DEFAULT \ +((uint16_t) 2560) +#define VL53L1_TUNINGPARM_REFSPADCHAR_MIN_COUNTRATE_LIMIT_MCPS_DEFAULT \ +((uint16_t) 1280) +#define VL53L1_TUNINGPARM_REFSPADCHAR_MAX_COUNTRATE_LIMIT_MCPS_DEFAULT \ +((uint16_t) 5120) +#define VL53L1_TUNINGPARM_XTALK_EXTRACT_NUM_OF_SAMPLES_DEFAULT \ +((uint8_t) 7) +#define VL53L1_TUNINGPARM_XTALK_EXTRACT_MIN_FILTER_THRESH_MM_DEFAULT \ +((int16_t) -70) +#define VL53L1_TUNINGPARM_XTALK_EXTRACT_MAX_FILTER_THRESH_MM_DEFAULT \ +((int16_t) 70) +#define VL53L1_TUNINGPARM_XTALK_EXTRACT_DSS_RATE_MCPS_DEFAULT \ +((uint16_t) 5120) +#define VL53L1_TUNINGPARM_XTALK_EXTRACT_PHASECAL_TIMEOUT_US_DEFAULT \ +((uint32_t) 15000) +#define VL53L1_TUNINGPARM_XTALK_EXTRACT_MAX_VALID_RATE_KCPS_DEFAULT \ +((uint16_t) 64000) +#define VL53L1_TUNINGPARM_XTALK_EXTRACT_SIGMA_THRESHOLD_MM_DEFAULT \ +((uint16_t) 140) +#define VL53L1_TUNINGPARM_XTALK_EXTRACT_DSS_TIMEOUT_US_DEFAULT \ +((uint32_t) 2000) +#define VL53L1_TUNINGPARM_XTALK_EXTRACT_BIN_TIMEOUT_US_DEFAULT \ +((uint32_t) 10000) +#define VL53L1_TUNINGPARM_OFFSET_CAL_DSS_RATE_MCPS_DEFAULT \ +((uint16_t) 2560) +#define VL53L1_TUNINGPARM_OFFSET_CAL_PHASECAL_TIMEOUT_US_DEFAULT \ +((uint32_t) 1000) +#define VL53L1_TUNINGPARM_OFFSET_CAL_MM_TIMEOUT_US_DEFAULT \ +((uint32_t) 13000) +#define VL53L1_TUNINGPARM_OFFSET_CAL_RANGE_TIMEOUT_US_DEFAULT \ +((uint32_t) 13000) +#define VL53L1_TUNINGPARM_OFFSET_CAL_PRE_SAMPLES_DEFAULT \ +((uint8_t) 8) +#define VL53L1_TUNINGPARM_OFFSET_CAL_MM1_SAMPLES_DEFAULT \ +((uint8_t) 40) +#define VL53L1_TUNINGPARM_OFFSET_CAL_MM2_SAMPLES_DEFAULT \ +((uint8_t) 9) +#define VL53L1_TUNINGPARM_ZONE_CAL_DSS_RATE_MCPS_DEFAULT \ +((uint16_t) 5120) +#define VL53L1_TUNINGPARM_ZONE_CAL_PHASECAL_TIMEOUT_US_DEFAULT \ +((uint32_t) 15000) +#define VL53L1_TUNINGPARM_ZONE_CAL_DSS_TIMEOUT_US_DEFAULT \ +((uint32_t) 2000) +#define VL53L1_TUNINGPARM_ZONE_CAL_PHASECAL_NUM_SAMPLES_DEFAULT \ +((uint16_t) 16) +#define VL53L1_TUNINGPARM_ZONE_CAL_RANGE_TIMEOUT_US_DEFAULT \ +((uint32_t) 1000) +#define VL53L1_TUNINGPARM_ZONE_CAL_ZONE_NUM_SAMPLES_DEFAULT \ +((uint16_t) 8) +#define VL53L1_TUNINGPARM_SPADMAP_VCSEL_PERIOD_DEFAULT \ +((uint8_t) 18) +#define VL53L1_TUNINGPARM_SPADMAP_VCSEL_START_DEFAULT \ +((uint8_t) 15) +#define VL53L1_TUNINGPARM_SPADMAP_RATE_LIMIT_MCPS_DEFAULT \ +((uint16_t) 12) +#define VL53L1_TUNINGPARM_LITE_DSS_CONFIG_TARGET_TOTAL_RATE_MCPS_DEFAULT \ +((uint16_t) 2560) +#define VL53L1_TUNINGPARM_RANGING_DSS_CONFIG_TARGET_TOTAL_RATE_MCPS_DEFAULT \ +((uint16_t) 5120) +#define VL53L1_TUNINGPARM_MZ_DSS_CONFIG_TARGET_TOTAL_RATE_MCPS_DEFAULT \ +((uint16_t) 5120) +#define VL53L1_TUNINGPARM_TIMED_DSS_CONFIG_TARGET_TOTAL_RATE_MCPS_DEFAULT \ +((uint16_t) 2560) +#define VL53L1_TUNINGPARM_LITE_PHASECAL_CONFIG_TIMEOUT_US_DEFAULT \ +((uint32_t) 1000) +#define VL53L1_TUNINGPARM_RANGING_LONG_PHASECAL_CONFIG_TIMEOUT_US_DEFAULT \ +((uint32_t) 15000) +#define VL53L1_TUNINGPARM_RANGING_MED_PHASECAL_CONFIG_TIMEOUT_US_DEFAULT \ +((uint32_t) 9000) +#define VL53L1_TUNINGPARM_RANGING_SHORT_PHASECAL_CONFIG_TIMEOUT_US_DEFAULT \ +((uint32_t) 6000) +#define VL53L1_TUNINGPARM_MZ_LONG_PHASECAL_CONFIG_TIMEOUT_US_DEFAULT \ +((uint32_t) 15000) +#define VL53L1_TUNINGPARM_MZ_MED_PHASECAL_CONFIG_TIMEOUT_US_DEFAULT \ +((uint32_t) 9000) +#define VL53L1_TUNINGPARM_MZ_SHORT_PHASECAL_CONFIG_TIMEOUT_US_DEFAULT \ +((uint32_t) 6000) +#define VL53L1_TUNINGPARM_TIMED_PHASECAL_CONFIG_TIMEOUT_US_DEFAULT \ +((uint32_t) 1000) +#define VL53L1_TUNINGPARM_LITE_MM_CONFIG_TIMEOUT_US_DEFAULT \ +((uint32_t) 2000) +#define VL53L1_TUNINGPARM_RANGING_MM_CONFIG_TIMEOUT_US_DEFAULT \ +((uint32_t) 2000) +#define VL53L1_TUNINGPARM_MZ_MM_CONFIG_TIMEOUT_US_DEFAULT \ +((uint32_t) 2000) +#define VL53L1_TUNINGPARM_TIMED_MM_CONFIG_TIMEOUT_US_DEFAULT \ +((uint32_t) 2000) +#define VL53L1_TUNINGPARM_LITE_RANGE_CONFIG_TIMEOUT_US_DEFAULT \ +((uint32_t) 63000) +#define VL53L1_TUNINGPARM_RANGING_RANGE_CONFIG_TIMEOUT_US_DEFAULT \ +((uint32_t) 2500) +#define VL53L1_TUNINGPARM_MZ_RANGE_CONFIG_TIMEOUT_US_DEFAULT \ +((uint32_t) 2500) +#define VL53L1_TUNINGPARM_TIMED_RANGE_CONFIG_TIMEOUT_US_DEFAULT \ +((uint32_t) 13000) +#define VL53L1_TUNINGPARM_DYNXTALK_SMUDGE_MARGIN_DEFAULT \ +((uint16_t) 512) +#define VL53L1_TUNINGPARM_DYNXTALK_NOISE_MARGIN_DEFAULT \ +((uint32_t) 500) +#define VL53L1_TUNINGPARM_DYNXTALK_XTALK_OFFSET_LIMIT_DEFAULT \ +((uint32_t) 0) +#define VL53L1_TUNINGPARM_DYNXTALK_XTALK_OFFSET_LIMIT_HI_DEFAULT \ +((uint8_t) 0) +#define VL53L1_TUNINGPARM_DYNXTALK_SAMPLE_LIMIT_DEFAULT \ +((uint32_t) 200) +#define VL53L1_TUNINGPARM_DYNXTALK_SINGLE_XTALK_DELTA_DEFAULT \ +((uint32_t) 10240) +#define VL53L1_TUNINGPARM_DYNXTALK_AVERAGED_XTALK_DELTA_DEFAULT \ +((uint32_t) 4096) +#define VL53L1_TUNINGPARM_DYNXTALK_CLIP_LIMIT_DEFAULT \ +((uint32_t) 1046528) +#define VL53L1_TUNINGPARM_DYNXTALK_SCALER_CALC_METHOD_DEFAULT \ +((uint8_t) 0) +#define VL53L1_TUNINGPARM_DYNXTALK_XGRADIENT_SCALER_DEFAULT \ +((int16_t) 256) +#define VL53L1_TUNINGPARM_DYNXTALK_YGRADIENT_SCALER_DEFAULT \ +((int16_t) 256) +#define VL53L1_TUNINGPARM_DYNXTALK_USER_SCALER_SET_DEFAULT \ +((uint8_t) 0) +#define VL53L1_TUNINGPARM_DYNXTALK_SMUDGE_COR_SINGLE_APPLY_DEFAULT \ +((uint8_t) 0) +#define VL53L1_TUNINGPARM_DYNXTALK_XTALK_AMB_THRESHOLD_DEFAULT \ +((uint32_t) 1280) +#define VL53L1_TUNINGPARM_DYNXTALK_NODETECT_AMB_THRESHOLD_KCPS_DEFAULT \ +((uint32_t) 57671680) +#define VL53L1_TUNINGPARM_DYNXTALK_NODETECT_SAMPLE_LIMIT_DEFAULT \ +((uint32_t) 10) +#define VL53L1_TUNINGPARM_DYNXTALK_NODETECT_XTALK_OFFSET_KCPS_DEFAULT \ +((uint32_t) 2048) +#define VL53L1_TUNINGPARM_DYNXTALK_NODETECT_MIN_RANGE_MM_DEFAULT \ +((uint16_t) 900) +#define VL53L1_TUNINGPARM_LOWPOWERAUTO_VHV_LOOP_BOUND_DEFAULT \ +((uint8_t) 3) +#define VL53L1_TUNINGPARM_LOWPOWERAUTO_MM_CONFIG_TIMEOUT_US_DEFAULT \ +((uint32_t) 1) +#define VL53L1_TUNINGPARM_LOWPOWERAUTO_RANGE_CONFIG_TIMEOUT_US_DEFAULT \ +((uint32_t) 8000) +#define VL53L1_TUNINGPARM_VERY_SHORT_DSS_RATE_MCPS_DEFAULT \ +((uint16_t) 10240) + + +#ifdef __cplusplus +} +#endif + +#endif + + + + diff --git a/drivers/input/misc/vl53L1/lito/inc/vl53l1_wait.h b/drivers/input/misc/vl53L1/lito/inc/vl53l1_wait.h new file mode 100644 index 000000000000..eb19e3b9bcb4 --- /dev/null +++ b/drivers/input/misc/vl53L1/lito/inc/vl53l1_wait.h @@ -0,0 +1,319 @@ + +/******************************************************************************* + * Copyright (c) 2017, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#ifndef _VL53L1_WAIT_H_ +#define _VL53L1_WAIT_H_ + +#include "vl53l1_platform.h" + +#ifdef __cplusplus +extern "C" { +#endif + + + + + + + + + + + + + + +VL53L1_Error VL53L1_wait_for_boot_completion( + VL53L1_DEV Dev); + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_wait_for_firmware_ready( + VL53L1_DEV Dev); + + + + + + + + + + + + + + +VL53L1_Error VL53L1_wait_for_range_completion( + VL53L1_DEV Dev); + + + + + + + + + + + + + + +VL53L1_Error VL53L1_wait_for_test_completion( + VL53L1_DEV Dev); + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_is_boot_complete( + VL53L1_DEV Dev, + uint8_t *pready); + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_is_firmware_ready( + VL53L1_DEV Dev, + uint8_t *pready); + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_is_new_data_ready( + VL53L1_DEV Dev, + uint8_t *pready); + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_poll_for_boot_completion( + VL53L1_DEV Dev, + uint32_t timeout_ms); + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_poll_for_firmware_ready( + VL53L1_DEV Dev, + uint32_t timeout_ms); + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_poll_for_range_completion( + VL53L1_DEV Dev, + uint32_t timeout_ms); + + + +#ifdef __cplusplus +} +#endif + +#endif + + diff --git a/drivers/input/misc/vl53L1/lito/inc/vl53l1_zone_presets.h b/drivers/input/misc/vl53L1/lito/inc/vl53l1_zone_presets.h new file mode 100644 index 000000000000..34f3652f0a95 --- /dev/null +++ b/drivers/input/misc/vl53L1/lito/inc/vl53l1_zone_presets.h @@ -0,0 +1,183 @@ + +/******************************************************************************* + * Copyright (c) 2017, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#ifndef _VL53L1_ZONE_PRESETS_H_ +#define _VL53L1_ZONE_PRESETS_H_ + +#include "vl53l1_ll_def.h" + +#ifdef __cplusplus +extern "C" { +#endif + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_init_zone_config_structure( + uint8_t x_off, + uint8_t x_inc, + uint8_t x_zones, + uint8_t y_off, + uint8_t y_inc, + uint8_t y_zones, + uint8_t width, + uint8_t height, + VL53L1_zone_config_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_zone_preset_xtalk_planar( + VL53L1_general_config_t *pgeneral, + VL53L1_zone_config_t *pzone_cfg); + + + + + + + + + + + + + +VL53L1_Error VL53L1_init_zone_config_histogram_bins( + VL53L1_zone_config_t *pdata); + +#ifdef __cplusplus +} +#endif + +#endif + + diff --git a/drivers/input/misc/vl53L1/lito/ipp/ipp_linux.c b/drivers/input/misc/vl53L1/lito/ipp/ipp_linux.c new file mode 100644 index 000000000000..7b8c5b76e2a1 --- /dev/null +++ b/drivers/input/misc/vl53L1/lito/ipp/ipp_linux.c @@ -0,0 +1,343 @@ +/************************************************************************** + * Copyright (c) 2016, STMicroelectronics - All Rights Reserved + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ****************************************************************************/ + +/** + * @file ipp_linux.c kernel side implementation of vl53l1 protected processing + * + * @date Sep 1, 2016 + * @author : imaging + * + * @ingroup ipp_dev + */ + +#include "stmvl53l1.h" + +#define IPP_ERR_CODE (VL53L1_ERROR_PLATFORM_SPECIFIC_START-1) + +static int stmvl53l1_ipp_do_wrapper(struct stmvl53l1_data *data, + struct ipp_work_t *pin, struct ipp_work_t *pout, int payload_out) +{ + int rc; + + if (data->ipp.buzy) { + vl53l1_errmsg("try exec new ipp but still buzy on previous"); + /* TODO shall we discard it and push new ? */ + rc = IPP_ERR_CODE; + goto done; + } + WARN_ON(pin->payload > IPP_WORK_MAX_PAYLOAD); + stmvl531_ipp_tim_start(data); + rc = stmvl53l1_ipp_do(data, pin, pout); + if (rc != 0) { + vl53l1_errmsg("stmvl53l1_ipp_do err %d\n", rc); + rc = IPP_ERR_CODE; + goto done; + } + //vl53l1_dbgmsg("ipp ok \n"); + /* check what we got back if valid answer error etc */ + if (pout->status) { + vl53l1_errmsg("ipp error status %d from user", pout->status); + if (pout->status >= stmvl53l1_ipp_status_proc_code) + rc = pout->status & (stmvl53l1_ipp_status_proc_code-1); + else + rc = IPP_ERR_CODE; + goto done; + } + WARN_ON(pout->payload > IPP_WORK_MAX_PAYLOAD); + if (pout->payload != payload_out) { + /* bad formated answer */ + vl53l1_errmsg("bad payload %d != %d in ipp work back", + pout->payload, payload_out); + rc = IPP_ERR_CODE; + goto done; + } + stmvl531_ipp_tim_stop(data); + /*stmvl531_ipp_stat(data, "ipp #%5x to=%3d fm=%3d in %5ld us", + pin->xfer_id, pin->payload, + pout->payload, + stmvl531_ipp_time(data));*/ + + rc = 0; +done: + + return rc; +} + +/** + * @file vl53l1_platform_ipp.h + * + * @brief EwokPlus25 IPP Wrapper Functions + */ + +/** + * @brief IPP Wrapper call for histogram post processing + * + * + * @param[in] Dev : Device handle + * @param[in] pdmax_cal : DMAX calibration data + * @param[in] pdmax_cfg : DMAX configuration data + * @param[in] ppost_cfg : VL53L1_hist_post_process_config_t + * @param[in] pbins : Input histogram raw bin data + * @param[in] pxtalk : Cross talk histogram data + * @param[out] presults : Output VL53L1_range_results_t + * structure + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_ipp_hist_process_data( + VL53L1_DEV dev, + VL53L1_dmax_calibration_data_t *pdmax_cal, + VL53L1_hist_gen3_dmax_config_t *pdmax_cfg, + VL53L1_hist_post_process_config_t *ppost_cfg, + VL53L1_histogram_bin_data_t *pbins, + VL53L1_xtalk_histogram_data_t *pxtalk, + VL53L1_range_results_t *presults) +{ + struct stmvl53l1_data *data = (struct stmvl53l1_data *) + container_of(dev, struct stmvl53l1_data, stdev); + struct ipp_work_t *pout = &data->ipp.work_out; + struct ipp_work_t *pin = &data->ipp.work; + int rc; + VL53L1_range_results_t *presults_ipp; + + IPP_SERIALIZE_VAR; + + /* setup pin */ + IPP_SERIALIZE_START(pin->data, 5); + IPP_SET_ARG_PTR(pin->data, 0, pdmax_cal); + IPP_SET_ARG_PTR(pin->data, 1, pdmax_cfg); + IPP_SET_ARG_PTR(pin->data, 2, ppost_cfg); + IPP_SET_ARG_PTR(pin->data, 3, pbins); + IPP_SET_ARG_PTR(pin->data, 4, pxtalk); + pin->payload = IPP_SERIALIZE_PAYLAOD(); + pin->process_no = stmvl53l1_ipp_cal_hist; + + /* setup pout */ + IPP_SERIALIZE_START(pout->data, 1); + IPP_OUT_ARG_PTR(pout->data, 0, presults_ipp); + + /* do ipp */ + rc = stmvl53l1_ipp_do_wrapper(data, pin, pout, IPP_SERIALIZE_PAYLAOD()); + if (rc) + goto done; + + /* copy output */ + memcpy(presults, presults_ipp, sizeof(*presults)); + + rc = 0; +done: + + return rc; +} + +/** + * @brief IPP Wrapper call for histogram ambient dmax calc + * + * The target reflectance in percent for the DMAX calculation + * is set by target_reflectance input + * + * The fixed point format is 7.2 + * + * @param[in] Dev : Device handle + * @param[in] target_reflectance : target reflectance to report ambient DMAX + * Percentage in 7.2 fixed point format + * @param[in] pdmax_cal : DMAX calibration data + * @param[in] pdmax_cfg : DMAX configuration data + * @param[in] pbins : Input histogram raw bin data + * @param[out] pambient_dmax_mm : Output ambient DMAX distance in [mm] + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_ipp_hist_ambient_dmax( + VL53L1_DEV dev, + uint16_t target_reflectance, + VL53L1_dmax_calibration_data_t *pdmax_cal, + VL53L1_hist_gen3_dmax_config_t *pdmax_cfg, + VL53L1_histogram_bin_data_t *pbins, + int16_t *pambient_dmax_mm) +{ + struct stmvl53l1_data *data = (struct stmvl53l1_data *) + container_of(dev, struct stmvl53l1_data, stdev); + struct ipp_work_t *pout = &data->ipp.work_out; + struct ipp_work_t *pin = &data->ipp.work; + int rc; + int16_t *pambient_dmax_mm_ipp; + + IPP_SERIALIZE_VAR; + + /* setup pin */ + IPP_SERIALIZE_START(pin->data, 4); + IPP_SET_ARG(pin->data, 0, target_reflectance); + IPP_SET_ARG_PTR(pin->data, 1, pdmax_cal); + IPP_SET_ARG_PTR(pin->data, 2, pdmax_cfg); + IPP_SET_ARG_PTR(pin->data, 3, pbins); + pin->payload = IPP_SERIALIZE_PAYLAOD(); + pin->process_no = stmvl53l1_ipp_hist_ambient_dmax; + + /* setup pout */ + IPP_SERIALIZE_START(pout->data, 1); + IPP_OUT_ARG_PTR(pout->data, 0, pambient_dmax_mm_ipp); + + /* do ipp */ + rc = stmvl53l1_ipp_do_wrapper(data, pin, pout, IPP_SERIALIZE_PAYLAOD()); + if (rc) + goto done; + + /* copy output */ + memcpy(pambient_dmax_mm, pambient_dmax_mm_ipp, + sizeof(*pambient_dmax_mm)); + + rc = 0; +done: + + return rc; +} + +/** + * @brief IPP Wrapper call for xtalk calibration post processing + * + * @param[in] Dev : Device handle + * @param[in] pxtalk_ranges : Input VL53L1_xtalk_range_results_t + * Must contain 5 ranges, 4 quadrants + 1 + * full FoV + * @param[out] pxtalk_shape : Output normalised Cross talk histogram + * shape + * @param[out] pxtalk_cal : Output VL53L1_xtalk_calibration_results_t + * structure + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_ipp_xtalk_calibration_process_data( + VL53L1_DEV dev, + VL53L1_xtalk_range_results_t *pxtalk_ranges, + VL53L1_xtalk_histogram_data_t *pxtalk_shape, + VL53L1_xtalk_calibration_results_t *pxtalk_cal) +{ + struct stmvl53l1_data *data = (struct stmvl53l1_data *) + container_of(dev, struct stmvl53l1_data, stdev); + struct ipp_work_t *pout = &data->ipp.work_out; + struct ipp_work_t *pin = &data->ipp.work; + int rc; + VL53L1_xtalk_histogram_data_t *pxtalk_shape_ipp; + VL53L1_xtalk_calibration_results_t *pxtalk_cal_ipp; + + IPP_SERIALIZE_VAR; + + /* setup pin */ + IPP_SERIALIZE_START(pin->data, 1); + IPP_SET_ARG_PTR(pin->data, 0, pxtalk_ranges); + pin->payload = IPP_SERIALIZE_PAYLAOD(); + pin->process_no = stmvl53l1_ipp_xtalk_calibration; + + /* setup pout */ + IPP_SERIALIZE_START(pout->data, 2); + IPP_OUT_ARG_PTR(pout->data, 0, pxtalk_shape_ipp); + IPP_OUT_ARG_PTR(pout->data, 1, pxtalk_cal_ipp); + + /* do ipp */ + rc = stmvl53l1_ipp_do_wrapper(data, pin, pout, IPP_SERIALIZE_PAYLAOD()); + if (rc) + goto done; + + /* copy output */ + memcpy(pxtalk_shape, pxtalk_shape_ipp, sizeof(*pxtalk_shape)); + memcpy(pxtalk_cal, pxtalk_cal_ipp, sizeof(*pxtalk_cal)); + + rc = 0; +done: + + return rc; +} + +/** + * @brief IPP Wrapper call for Generating Xtalk data from dual reflectance + * histogram data + * + * @param[in] Dev : Device handle + * @param[in] pxtalk_results : Pointer to xtalk_results structure + * containing dual reflectance + * histogram data + * @param[in] expected_target_distance_mm : User input of true target distance + * @param[in] higher_reflectance : User input detailing which + * histogram data 1 or 2 has the + * highest reflectance. + * @param[out] pxtalk_avg_samples : Pointer to output xtalk histogram + * data + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_ipp_generate_dual_reflectance_xtalk_samples( + VL53L1_DEV dev, + VL53L1_xtalk_range_results_t *pxtalk_results, + uint16_t expected_target_distance_mm, + uint8_t higher_reflectance, + VL53L1_histogram_bin_data_t *pxtalk_avg_samples) +{ + struct stmvl53l1_data *data = (struct stmvl53l1_data *) + container_of(dev, struct stmvl53l1_data, stdev); + struct ipp_work_t *pout = &data->ipp.work_out; + struct ipp_work_t *pin = &data->ipp.work; + int rc; + VL53L1_histogram_bin_data_t *pxtalk_avg_samples_ipp; + + IPP_SERIALIZE_VAR; + + /* setup pin */ + IPP_SERIALIZE_START(pin->data, 3); + IPP_SET_ARG_PTR(pin->data, 0, pxtalk_results); + IPP_SET_ARG(pin->data, 1, expected_target_distance_mm); + IPP_SET_ARG(pin->data, 2, higher_reflectance); + pin->payload = IPP_SERIALIZE_PAYLAOD(); + pin->process_no = stmvl53l1_ipp_generate_dual_reflectance_xtalk_samples; + + /* setup pout */ + IPP_SERIALIZE_START(pout->data, 1); + IPP_OUT_ARG_PTR(pout->data, 0, pxtalk_avg_samples_ipp); + + /* do ipp */ + rc = stmvl53l1_ipp_do_wrapper(data, pin, pout, IPP_SERIALIZE_PAYLAOD()); + if (rc) + goto done; + + /* copy output */ + memcpy(pxtalk_avg_samples, pxtalk_avg_samples_ipp, + sizeof(*pxtalk_avg_samples)); + + rc = 0; +done: + + return rc; +} diff --git a/drivers/input/misc/vl53L1/lito/src/vl53l1_api.c b/drivers/input/misc/vl53L1/lito/src/vl53l1_api.c new file mode 100644 index 000000000000..2a191b43c108 --- /dev/null +++ b/drivers/input/misc/vl53L1/lito/src/vl53l1_api.c @@ -0,0 +1,3791 @@ + +/******************************************************************************* + * Copyright (c) 2017, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#include "vl53l1_api.h" +#include "vl53l1_api_strings.h" +#include "vl53l1_register_settings.h" +#include "vl53l1_register_funcs.h" +#include "vl53l1_core.h" +#include "vl53l1_api_calibration.h" +#include "vl53l1_wait.h" +#include "vl53l1_preset_setup.h" +#include "vl53l1_api_debug.h" +#include "vl53l1_api_core.h" +#include "vl53l1_nvm.h" + + + +#define ZONE_CHECK VL53L1_MAX_USER_ZONES + +#if ZONE_CHECK < 5 +#error Must define at least 5 zones in MAX_USER_ZONES constant +#endif + + +#ifdef VL53L1_NOCALIB +#endif + +#ifndef VL53L1_NOCALIB +#endif + +#define LOG_FUNCTION_START(fmt, ...) \ + _LOG_FUNCTION_START(VL53L1_TRACE_MODULE_API, fmt, ##__VA_ARGS__) +#define LOG_FUNCTION_END(status, ...) \ + _LOG_FUNCTION_END(VL53L1_TRACE_MODULE_API, status, ##__VA_ARGS__) +#define LOG_FUNCTION_END_FMT(status, fmt, ...) \ + _LOG_FUNCTION_END_FMT(VL53L1_TRACE_MODULE_API, status, \ + fmt, ##__VA_ARGS__) + +#ifdef VL53L1_LOG_ENABLE +#define trace_print(level, ...) trace_print_module_function(\ + VL53L1_TRACE_MODULE_API, level, VL53L1_TRACE_FUNCTION_NONE, \ + ##__VA_ARGS__) +#endif + +#ifndef MIN +#define MIN(v1, v2) ((v1) < (v2) ? (v1) : (v2)) +#endif +#ifndef MAX +#define MAX(v1, v2) ((v1) < (v2) ? (v2) : (v1)) +#endif + +#define DMAX_REFLECTANCE_IDX 2 + + + + + + + +#define LOWPOWER_AUTO_VHV_LOOP_DURATION_US 245 +#define LOWPOWER_AUTO_OVERHEAD_BEFORE_A_RANGING 1448 +#define LOWPOWER_AUTO_OVERHEAD_BETWEEN_A_B_RANGING 2100 + +#define FDA_MAX_TIMING_BUDGET_US 550000 + + + + + + + + + +static int32_t BDTable[VL53L1_TUNING_MAX_TUNABLE_KEY] = { + TUNING_VERSION, + TUNING_PROXY_MIN, + TUNING_SINGLE_TARGET_XTALK_TARGET_DISTANCE_MM, + TUNING_SINGLE_TARGET_XTALK_SAMPLE_NUMBER, + TUNING_MIN_AMBIENT_DMAX_VALID, + TUNING_MAX_SIMPLE_OFFSET_CALIBRATION_SAMPLE_NUMBER, + TUNING_XTALK_FULL_ROI_TARGET_DISTANCE_MM, + TUNING_SIMPLE_OFFSET_CALIBRATION_REPEAT +}; + + + +static VL53L1_Error SingleTargetXTalkCalibration(VL53L1_DEV Dev) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + uint32_t sum_ranging = 0; + uint32_t sum_spads = 0; + FixPoint1616_t sum_signalRate = 0; + FixPoint1616_t total_count = 0; + uint8_t xtalk_meas = 0; + uint8_t xtalk_measmax = + BDTable[VL53L1_TUNING_SINGLE_TARGET_XTALK_SAMPLE_NUMBER]; + VL53L1_RangingMeasurementData_t RMData; + FixPoint1616_t xTalkStoredMeanSignalRate; + FixPoint1616_t xTalkStoredMeanRange; + FixPoint1616_t xTalkStoredMeanRtnSpads; + uint32_t xTalkStoredMeanRtnSpadsAsInt; + uint32_t xTalkCalDistanceAsInt; + FixPoint1616_t XTalkCompensationRateMegaCps; + uint32_t signalXTalkTotalPerSpad; + VL53L1_PresetModes PresetMode; + VL53L1_CalibrationData_t CalibrationData; + VL53L1_CustomerNvmManaged_t *pC; + + + LOG_FUNCTION_START(""); + + + + + + + + PresetMode = VL53L1DevDataGet(Dev, CurrentParameters.PresetMode); + + if ((PresetMode != VL53L1_PRESETMODE_AUTONOMOUS) && + (PresetMode != VL53L1_PRESETMODE_LOWPOWER_AUTONOMOUS) && + (PresetMode != VL53L1_PRESETMODE_LITE_RANGING)) { + Status = VL53L1_ERROR_MODE_NOT_SUPPORTED; + goto ENDFUNC; + } + + + + Status = VL53L1_disable_xtalk_compensation(Dev); + + if (Status != VL53L1_ERROR_NONE) + goto ENDFUNC; + + Status = VL53L1_StartMeasurement(Dev); + + if (Status != VL53L1_ERROR_NONE) + goto ENDFUNC; + + + + VL53L1_WaitMeasurementDataReady(Dev); + VL53L1_GetRangingMeasurementData(Dev, &RMData); + VL53L1_ClearInterruptAndStartMeasurement(Dev); + + sum_ranging = 0; + sum_spads = 0; + sum_signalRate = 0; + total_count = 0; + for (xtalk_meas = 0; xtalk_meas < xtalk_measmax; xtalk_meas++) { + VL53L1_WaitMeasurementDataReady(Dev); + VL53L1_GetRangingMeasurementData(Dev, &RMData); + VL53L1_ClearInterruptAndStartMeasurement(Dev); + if (RMData.RangeStatus == VL53L1_RANGESTATUS_RANGE_VALID) { + sum_ranging += RMData.RangeMilliMeter; + sum_signalRate += RMData.SignalRateRtnMegaCps; + sum_spads += RMData.EffectiveSpadRtnCount / 256; + total_count++; + } + } + Status = VL53L1_StopMeasurement(Dev); + + if (total_count > 0) { + + + xTalkStoredMeanSignalRate = sum_signalRate / total_count; + xTalkStoredMeanRange = (FixPoint1616_t)(sum_ranging << 16); + xTalkStoredMeanRange /= total_count; + xTalkStoredMeanRtnSpads = (FixPoint1616_t)(sum_spads << 16); + xTalkStoredMeanRtnSpads /= total_count; + + + + + + + + + + + + + + xTalkStoredMeanRtnSpadsAsInt = (xTalkStoredMeanRtnSpads + + 0x8000) >> 16; + + + + + + + xTalkCalDistanceAsInt = ((uint32_t)BDTable[ + VL53L1_TUNING_SINGLE_TARGET_XTALK_TARGET_DISTANCE_MM]); + if (xTalkStoredMeanRtnSpadsAsInt == 0 || + xTalkCalDistanceAsInt == 0 || + xTalkStoredMeanRange >= (xTalkCalDistanceAsInt << 16)) { + XTalkCompensationRateMegaCps = 0; + } else { + + + + + + + signalXTalkTotalPerSpad = (xTalkStoredMeanSignalRate) / + xTalkStoredMeanRtnSpadsAsInt; + + + + + + + + signalXTalkTotalPerSpad *= (((uint32_t)1 << 16) - + (xTalkStoredMeanRange / xTalkCalDistanceAsInt)); + + + + XTalkCompensationRateMegaCps = (signalXTalkTotalPerSpad + + 0x8000) >> 16; + } + + + Status = VL53L1_GetCalibrationData(Dev, &CalibrationData); + + if (Status != VL53L1_ERROR_NONE) + goto ENDFUNC; + + pC = &CalibrationData.customer; + + pC->algo__crosstalk_compensation_plane_offset_kcps = + (uint32_t)(1000 * ((XTalkCompensationRateMegaCps + + ((uint32_t)1<<6)) >> (16-9))); + + Status = VL53L1_SetCalibrationData(Dev, &CalibrationData); + + if (Status != VL53L1_ERROR_NONE) + goto ENDFUNC; + + Status = VL53L1_enable_xtalk_compensation(Dev); + + } else + + + Status = VL53L1_ERROR_XTALK_EXTRACTION_NO_SAMPLE_FAIL; + +ENDFUNC: + LOG_FUNCTION_END(Status); + return Status; + +} + + + + + + + + + + +static VL53L1_Error CheckValidRectRoi(VL53L1_UserRoi_t ROI) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + if ((ROI.TopLeftX > 15) || (ROI.TopLeftY > 15) || + (ROI.BotRightX > 15) || (ROI.BotRightY > 15)) + Status = VL53L1_ERROR_INVALID_PARAMS; + + if ((ROI.TopLeftX > ROI.BotRightX) || (ROI.TopLeftY < ROI.BotRightY)) + Status = VL53L1_ERROR_INVALID_PARAMS; + + LOG_FUNCTION_END(Status); + return Status; +} + +static VL53L1_GPIO_Interrupt_Mode ConvertModeToLLD(VL53L1_Error *pStatus, + VL53L1_ThresholdMode CrossMode) +{ + VL53L1_GPIO_Interrupt_Mode Mode; + + switch (CrossMode) { + case VL53L1_THRESHOLD_CROSSED_LOW: + Mode = VL53L1_GPIOINTMODE_LEVEL_LOW; + break; + case VL53L1_THRESHOLD_CROSSED_HIGH: + Mode = VL53L1_GPIOINTMODE_LEVEL_HIGH; + break; + case VL53L1_THRESHOLD_OUT_OF_WINDOW: + Mode = VL53L1_GPIOINTMODE_OUT_OF_WINDOW; + break; + case VL53L1_THRESHOLD_IN_WINDOW: + Mode = VL53L1_GPIOINTMODE_IN_WINDOW; + break; + default: + + + Mode = VL53L1_GPIOINTMODE_LEVEL_HIGH; + *pStatus = VL53L1_ERROR_INVALID_PARAMS; + } + return Mode; +} + +static VL53L1_ThresholdMode ConvertModeFromLLD(VL53L1_Error *pStatus, + VL53L1_GPIO_Interrupt_Mode CrossMode) +{ + VL53L1_ThresholdMode Mode; + + switch (CrossMode) { + case VL53L1_GPIOINTMODE_LEVEL_LOW: + Mode = VL53L1_THRESHOLD_CROSSED_LOW; + break; + case VL53L1_GPIOINTMODE_LEVEL_HIGH: + Mode = VL53L1_THRESHOLD_CROSSED_HIGH; + break; + case VL53L1_GPIOINTMODE_OUT_OF_WINDOW: + Mode = VL53L1_THRESHOLD_OUT_OF_WINDOW; + break; + case VL53L1_GPIOINTMODE_IN_WINDOW: + Mode = VL53L1_THRESHOLD_IN_WINDOW; + break; + default: + + + Mode = VL53L1_THRESHOLD_CROSSED_HIGH; + *pStatus = VL53L1_ERROR_UNDEFINED; + } + return Mode; +} + + + + +VL53L1_Error VL53L1_GetVersion(VL53L1_Version_t *pVersion) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + pVersion->major = VL53L1_IMPLEMENTATION_VER_MAJOR; + pVersion->minor = VL53L1_IMPLEMENTATION_VER_MINOR; + pVersion->build = VL53L1_IMPLEMENTATION_VER_SUB; + + pVersion->revision = VL53L1_IMPLEMENTATION_VER_REVISION; + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_GetProductRevision(VL53L1_DEV Dev, + uint8_t *pProductRevisionMajor, uint8_t *pProductRevisionMinor) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + uint8_t revision_id; + VL53L1_LLDriverData_t *pLLData; + + LOG_FUNCTION_START(""); + + pLLData = VL53L1DevStructGetLLDriverHandle(Dev); + revision_id = pLLData->nvm_copy_data.identification__revision_id; + *pProductRevisionMajor = 1; + *pProductRevisionMinor = (revision_id & 0xF0) >> 4; + + LOG_FUNCTION_END(Status); + return Status; + +} + +VL53L1_Error VL53L1_GetDeviceInfo(VL53L1_DEV Dev, + VL53L1_DeviceInfo_t *pVL53L1_DeviceInfo) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + uint8_t revision_id; + VL53L1_LLDriverData_t *pLLData; + + LOG_FUNCTION_START(""); + + pLLData = VL53L1DevStructGetLLDriverHandle(Dev); + + strncpy(pVL53L1_DeviceInfo->ProductId, "", + VL53L1_DEVINFO_STRLEN-1); + pVL53L1_DeviceInfo->ProductType = + pLLData->nvm_copy_data.identification__module_type; + + revision_id = pLLData->nvm_copy_data.identification__revision_id; + pVL53L1_DeviceInfo->ProductRevisionMajor = 1; + pVL53L1_DeviceInfo->ProductRevisionMinor = (revision_id & 0xF0) >> 4; + +#ifndef VL53L1_USE_EMPTY_STRING + if (pVL53L1_DeviceInfo->ProductRevisionMinor == 0) + strncpy(pVL53L1_DeviceInfo->Name, + VL53L1_STRING_DEVICE_INFO_NAME0, + VL53L1_DEVINFO_STRLEN-1); + else + strncpy(pVL53L1_DeviceInfo->Name, + VL53L1_STRING_DEVICE_INFO_NAME1, + VL53L1_DEVINFO_STRLEN-1); + strncpy(pVL53L1_DeviceInfo->Type, + VL53L1_STRING_DEVICE_INFO_TYPE, + VL53L1_DEVINFO_STRLEN-1); +#else + pVL53L1_DeviceInfo->Name[0] = 0; + pVL53L1_DeviceInfo->Type[0] = 0; +#endif + + LOG_FUNCTION_END(Status); + return Status; +} + + +VL53L1_Error VL53L1_GetRangeStatusString(uint8_t RangeStatus, + char *pRangeStatusString) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + Status = VL53L1_get_range_status_string(RangeStatus, + pRangeStatusString); + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_GetPalErrorString(VL53L1_Error PalErrorCode, + char *pPalErrorString) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + Status = VL53L1_get_pal_error_string(PalErrorCode, pPalErrorString); + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_GetPalStateString(VL53L1_State PalStateCode, + char *pPalStateString) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + Status = VL53L1_get_pal_state_string(PalStateCode, pPalStateString); + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_GetPalState(VL53L1_DEV Dev, VL53L1_State *pPalState) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + *pPalState = VL53L1DevDataGet(Dev, PalState); + + LOG_FUNCTION_END(Status); + return Status; +} + + + + + + +VL53L1_Error VL53L1_SetDeviceAddress(VL53L1_DEV Dev, uint8_t DeviceAddress) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + Status = VL53L1_WrByte(Dev, VL53L1_I2C_SLAVE__DEVICE_ADDRESS, + DeviceAddress / 2); + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_DataInit(VL53L1_DEV Dev) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + uint8_t i; + + LOG_FUNCTION_START(""); + + + +#ifdef USE_I2C_2V8 + Status = VL53L1_RdByte(Dev, VL53L1_PAD_I2C_HV__EXTSUP_CONFIG, &i); + if (Status == VL53L1_ERROR_NONE) { + i = (i & 0xfe) | 0x01; + Status = VL53L1_WrByte(Dev, VL53L1_PAD_I2C_HV__EXTSUP_CONFIG, + i); + } +#endif + + if (Status == VL53L1_ERROR_NONE) + Status = VL53L1_data_init(Dev, 1); + + if (Status == VL53L1_ERROR_NONE) { + VL53L1DevDataSet(Dev, PalState, VL53L1_STATE_WAIT_STATICINIT); + VL53L1DevDataSet(Dev, CurrentParameters.PresetMode, + VL53L1_PRESETMODE_RANGING); + } + + + + for (i = 0; i < VL53L1_CHECKENABLE_NUMBER_OF_CHECKS; i++) { + if (Status == VL53L1_ERROR_NONE) + Status |= VL53L1_SetLimitCheckEnable(Dev, i, 1); + else + break; + + } + + + + if (Status == VL53L1_ERROR_NONE) { + Status = VL53L1_SetLimitCheckValue(Dev, + VL53L1_CHECKENABLE_SIGMA_FINAL_RANGE, + (FixPoint1616_t)(18 * 65536)); + } + if (Status == VL53L1_ERROR_NONE) { + Status = VL53L1_SetLimitCheckValue(Dev, + VL53L1_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE, + (FixPoint1616_t)(25 * 65536 / 100)); + + + } + + LOG_FUNCTION_END(Status); + return Status; +} + + +VL53L1_Error VL53L1_StaticInit(VL53L1_DEV Dev) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + uint8_t measurement_mode; + + LOG_FUNCTION_START(""); + + VL53L1DevDataSet(Dev, PalState, VL53L1_STATE_IDLE); + + measurement_mode = VL53L1_DEVICEMEASUREMENTMODE_BACKTOBACK; + VL53L1DevDataSet(Dev, LLData.measurement_mode, measurement_mode); + + VL53L1DevDataSet(Dev, CurrentParameters.DistanceMode, + VL53L1_DISTANCEMODE_LONG); + + VL53L1DevDataSet(Dev, CurrentParameters.OutputMode, + VL53L1_OUTPUTMODE_NEAREST); + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_WaitDeviceBooted(VL53L1_DEV Dev) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + Status = VL53L1_poll_for_boot_completion(Dev, + VL53L1_BOOT_COMPLETION_POLLING_TIMEOUT_MS); + + LOG_FUNCTION_END(Status); + return Status; +} + + + + + + +static VL53L1_Error ComputeDevicePresetMode( + VL53L1_PresetModes PresetMode, + VL53L1_DistanceModes DistanceMode, + VL53L1_DevicePresetModes *pDevicePresetMode) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + uint8_t DistIdx; + VL53L1_DevicePresetModes LightModes[3] = { + VL53L1_DEVICEPRESETMODE_STANDARD_RANGING_SHORT_RANGE, + VL53L1_DEVICEPRESETMODE_STANDARD_RANGING, + VL53L1_DEVICEPRESETMODE_STANDARD_RANGING_LONG_RANGE}; + + VL53L1_DevicePresetModes RangingModes[3] = { + VL53L1_DEVICEPRESETMODE_HISTOGRAM_SHORT_RANGE, + VL53L1_DEVICEPRESETMODE_HISTOGRAM_MEDIUM_RANGE, + VL53L1_DEVICEPRESETMODE_HISTOGRAM_LONG_RANGE}; + + VL53L1_DevicePresetModes ScanningModes[3] = { + VL53L1_DEVICEPRESETMODE_HISTOGRAM_MULTIZONE_SHORT_RANGE, + VL53L1_DEVICEPRESETMODE_HISTOGRAM_MULTIZONE, + VL53L1_DEVICEPRESETMODE_HISTOGRAM_MULTIZONE_LONG_RANGE}; + + VL53L1_DevicePresetModes TimedModes[3] = { + VL53L1_DEVICEPRESETMODE_TIMED_RANGING_SHORT_RANGE, + VL53L1_DEVICEPRESETMODE_TIMED_RANGING, + VL53L1_DEVICEPRESETMODE_TIMED_RANGING_LONG_RANGE}; + + VL53L1_DevicePresetModes LowPowerTimedModes[3] = { + VL53L1_DEVICEPRESETMODE_LOWPOWERAUTO_SHORT_RANGE, + VL53L1_DEVICEPRESETMODE_LOWPOWERAUTO_MEDIUM_RANGE, + VL53L1_DEVICEPRESETMODE_LOWPOWERAUTO_LONG_RANGE}; + + *pDevicePresetMode = VL53L1_DEVICEPRESETMODE_STANDARD_RANGING; + + switch (DistanceMode) { + case VL53L1_DISTANCEMODE_SHORT: + DistIdx = 0; + break; + case VL53L1_DISTANCEMODE_MEDIUM: + DistIdx = 1; + break; + default: + DistIdx = 2; + } + + switch (PresetMode) { + case VL53L1_PRESETMODE_LITE_RANGING: + *pDevicePresetMode = LightModes[DistIdx]; + break; + + case VL53L1_PRESETMODE_RANGING: + *pDevicePresetMode = RangingModes[DistIdx]; + break; + + case VL53L1_PRESETMODE_MULTIZONES_SCANNING: + *pDevicePresetMode = ScanningModes[DistIdx]; + break; + + case VL53L1_PRESETMODE_AUTONOMOUS: + *pDevicePresetMode = TimedModes[DistIdx]; + break; + + case VL53L1_PRESETMODE_LOWPOWER_AUTONOMOUS: + *pDevicePresetMode = LowPowerTimedModes[DistIdx]; + break; + case VL53L1_PRESETMODE_OLT: + *pDevicePresetMode = VL53L1_DEVICEPRESETMODE_OLT; + break; + case VL53L1_PRESETMODE_PROXY_RANGING_MODE: + *pDevicePresetMode = + VL53L1_DEVICEPRESETMODE_SPECIAL_HISTOGRAM_SHORT_RANGE; + break; + + default: + + + Status = VL53L1_ERROR_MODE_NOT_SUPPORTED; + } + + return Status; +} + +static VL53L1_Error SetPresetMode(VL53L1_DEV Dev, + VL53L1_PresetModes PresetMode, + VL53L1_DistanceModes DistanceMode, + uint32_t inter_measurement_period_ms) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + VL53L1_DevicePresetModes device_preset_mode; + uint8_t measurement_mode; + uint16_t dss_config__target_total_rate_mcps; + uint32_t phasecal_config_timeout_us; + uint32_t mm_config_timeout_us; + uint32_t lld_range_config_timeout_us; + + LOG_FUNCTION_START("%d", (int)PresetMode); + + if ((PresetMode == VL53L1_PRESETMODE_AUTONOMOUS) || + (PresetMode == VL53L1_PRESETMODE_LOWPOWER_AUTONOMOUS)) + measurement_mode = VL53L1_DEVICEMEASUREMENTMODE_TIMED; + else + measurement_mode = VL53L1_DEVICEMEASUREMENTMODE_BACKTOBACK; + + + Status = ComputeDevicePresetMode(PresetMode, DistanceMode, + &device_preset_mode); + + if (Status == VL53L1_ERROR_NONE) + Status = VL53L1_get_preset_mode_timing_cfg(Dev, + device_preset_mode, + &dss_config__target_total_rate_mcps, + &phasecal_config_timeout_us, + &mm_config_timeout_us, + &lld_range_config_timeout_us); + + if (Status == VL53L1_ERROR_NONE) + Status = VL53L1_set_preset_mode( + Dev, + device_preset_mode, + dss_config__target_total_rate_mcps, + phasecal_config_timeout_us, + mm_config_timeout_us, + lld_range_config_timeout_us, + inter_measurement_period_ms); + + if (Status == VL53L1_ERROR_NONE) + VL53L1DevDataSet(Dev, LLData.measurement_mode, + measurement_mode); + + if (Status == VL53L1_ERROR_NONE) + VL53L1DevDataSet(Dev, CurrentParameters.PresetMode, PresetMode); + + VL53L1DevDataSet(Dev, CurrentParameters.OutputMode, + VL53L1_OUTPUTMODE_NEAREST); + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_SetPresetMode(VL53L1_DEV Dev, VL53L1_PresetModes PresetMode) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + VL53L1_DistanceModes DistanceMode = VL53L1_DISTANCEMODE_LONG; + + LOG_FUNCTION_START("%d", (int)PresetMode); + + + + Status = VL53L1_low_power_auto_data_init(Dev); + + if (PresetMode == VL53L1_PRESETMODE_PROXY_RANGING_MODE) + DistanceMode = VL53L1_DISTANCEMODE_SHORT; + Status = SetPresetMode(Dev, + PresetMode, + DistanceMode, + 1000); + + if (Status == VL53L1_ERROR_NONE) { + if ((PresetMode == VL53L1_PRESETMODE_LITE_RANGING) || + (PresetMode == VL53L1_PRESETMODE_AUTONOMOUS) || + (PresetMode == VL53L1_PRESETMODE_LOWPOWER_AUTONOMOUS)) + Status = VL53L1_SetMeasurementTimingBudgetMicroSeconds( + Dev, 41000); + else + + + Status = VL53L1_SetMeasurementTimingBudgetMicroSeconds( + Dev, 33333); + } + + if (Status == VL53L1_ERROR_NONE) { + + + Status = VL53L1_SetInterMeasurementPeriodMilliSeconds(Dev, + 1000); + } + + LOG_FUNCTION_END(Status); + return Status; +} + + +VL53L1_Error VL53L1_GetPresetMode(VL53L1_DEV Dev, + VL53L1_PresetModes *pPresetMode) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + *pPresetMode = VL53L1DevDataGet(Dev, CurrentParameters.PresetMode); + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_SetDistanceMode(VL53L1_DEV Dev, + VL53L1_DistanceModes DistanceMode) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + VL53L1_PresetModes PresetMode; + uint32_t inter_measurement_period_ms; + uint32_t TimingBudget; + uint32_t MmTimeoutUs; + uint32_t PhaseCalTimeoutUs; + VL53L1_zone_config_t zone_config; + + LOG_FUNCTION_START("%d", (int)DistanceMode); + + PresetMode = VL53L1DevDataGet(Dev, CurrentParameters.PresetMode); + + + + + + + + if ((PresetMode == VL53L1_PRESETMODE_PROXY_RANGING_MODE) && + (DistanceMode != VL53L1_DISTANCEMODE_SHORT)) + return VL53L1_ERROR_INVALID_PARAMS; + if ((DistanceMode != VL53L1_DISTANCEMODE_SHORT) && + (DistanceMode != VL53L1_DISTANCEMODE_MEDIUM) && + (DistanceMode != VL53L1_DISTANCEMODE_LONG)) + return VL53L1_ERROR_INVALID_PARAMS; + + if (Status == VL53L1_ERROR_NONE) + Status = VL53L1_get_zone_config(Dev, &zone_config); + + inter_measurement_period_ms = VL53L1DevDataGet(Dev, + LLData.inter_measurement_period_ms); + + if (Status == VL53L1_ERROR_NONE) + Status = VL53L1_get_timeouts_us(Dev, &PhaseCalTimeoutUs, + &MmTimeoutUs, &TimingBudget); + + if (Status == VL53L1_ERROR_NONE) + Status = SetPresetMode(Dev, + PresetMode, + DistanceMode, + inter_measurement_period_ms); + + if (Status == VL53L1_ERROR_NONE) { + VL53L1DevDataSet(Dev, CurrentParameters.DistanceMode, + DistanceMode); + } + + if (Status == VL53L1_ERROR_NONE) { + Status = VL53L1_set_timeouts_us(Dev, PhaseCalTimeoutUs, + MmTimeoutUs, TimingBudget); + + if (Status == VL53L1_ERROR_NONE) + VL53L1DevDataSet(Dev, LLData.range_config_timeout_us, + TimingBudget); + } + + if (Status == VL53L1_ERROR_NONE) + Status = VL53L1_set_zone_config(Dev, &zone_config); + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_GetDistanceMode(VL53L1_DEV Dev, + VL53L1_DistanceModes *pDistanceMode) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + *pDistanceMode = VL53L1DevDataGet(Dev, CurrentParameters.DistanceMode); + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_SetOutputMode(VL53L1_DEV Dev, + VL53L1_OutputModes OutputMode) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if ((OutputMode != VL53L1_OUTPUTMODE_NEAREST) && + (OutputMode != VL53L1_OUTPUTMODE_STRONGEST)) + Status = VL53L1_ERROR_MODE_NOT_SUPPORTED; + else + VL53L1DevDataSet(Dev, CurrentParameters.OutputMode, OutputMode); + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_GetOutputMode(VL53L1_DEV Dev, + VL53L1_OutputModes *pOutputMode) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + *pOutputMode = VL53L1DevDataGet(Dev, CurrentParameters.OutputMode); + + LOG_FUNCTION_END(Status); + return Status; +} + + + +VL53L1_Error VL53L1_SetMeasurementTimingBudgetMicroSeconds(VL53L1_DEV Dev, + uint32_t MeasurementTimingBudgetMicroSeconds) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + uint8_t Mm1Enabled; + uint8_t Mm2Enabled; + uint32_t TimingGuard; + uint32_t divisor; + uint32_t TimingBudget; + uint32_t MmTimeoutUs; + VL53L1_PresetModes PresetMode; + uint32_t PhaseCalTimeoutUs; + uint32_t vhv; + int32_t vhv_loops; + uint32_t FDAMaxTimingBudgetUs = FDA_MAX_TIMING_BUDGET_US; + + LOG_FUNCTION_START(""); + + + + if (MeasurementTimingBudgetMicroSeconds > 10000000) + Status = VL53L1_ERROR_INVALID_PARAMS; + + if (Status == VL53L1_ERROR_NONE) { + Status = VL53L1_GetSequenceStepEnable(Dev, + VL53L1_SEQUENCESTEP_MM1, &Mm1Enabled); + } + + if (Status == VL53L1_ERROR_NONE) { + Status = VL53L1_GetSequenceStepEnable(Dev, + VL53L1_SEQUENCESTEP_MM2, &Mm2Enabled); + } + + if (Status == VL53L1_ERROR_NONE) + Status = VL53L1_get_timeouts_us(Dev, + &PhaseCalTimeoutUs, + &MmTimeoutUs, + &TimingBudget); + + if (Status == VL53L1_ERROR_NONE) { + PresetMode = VL53L1DevDataGet(Dev, + CurrentParameters.PresetMode); + + TimingGuard = 0; + divisor = 1; + switch (PresetMode) { + case VL53L1_PRESETMODE_LITE_RANGING: + if ((Mm1Enabled == 1) || (Mm2Enabled == 1)) + TimingGuard = 5000; + else + TimingGuard = 1000; + break; + + case VL53L1_PRESETMODE_AUTONOMOUS: + FDAMaxTimingBudgetUs *= 2; + if ((Mm1Enabled == 1) || (Mm2Enabled == 1)) + TimingGuard = 26600; + else + TimingGuard = 21600; + divisor = 2; + break; + + case VL53L1_PRESETMODE_LOWPOWER_AUTONOMOUS: + FDAMaxTimingBudgetUs *= 2; + vhv = LOWPOWER_AUTO_VHV_LOOP_DURATION_US; + VL53L1_get_tuning_parm(Dev, + VL53L1_TUNINGPARM_LOWPOWERAUTO_VHV_LOOP_BOUND, + &vhv_loops); + if (vhv_loops > 0) { + vhv += vhv_loops * + LOWPOWER_AUTO_VHV_LOOP_DURATION_US; + } + TimingGuard = LOWPOWER_AUTO_OVERHEAD_BEFORE_A_RANGING + + LOWPOWER_AUTO_OVERHEAD_BETWEEN_A_B_RANGING + + vhv; + divisor = 2; + break; + + case VL53L1_PRESETMODE_RANGING: + case VL53L1_PRESETMODE_MULTIZONES_SCANNING: + case VL53L1_PRESETMODE_PROXY_RANGING_MODE: + TimingGuard = 1700; + divisor = 6; + break; + + case VL53L1_PRESETMODE_OLT: + TimingGuard = MmTimeoutUs + 5000; + break; + default: + + + Status = VL53L1_ERROR_MODE_NOT_SUPPORTED; + } + + if (MeasurementTimingBudgetMicroSeconds <= TimingGuard) + Status = VL53L1_ERROR_INVALID_PARAMS; + else { + TimingBudget = (MeasurementTimingBudgetMicroSeconds + - TimingGuard); + } + + if (Status == VL53L1_ERROR_NONE) { + if (TimingBudget > FDAMaxTimingBudgetUs) + Status = VL53L1_ERROR_INVALID_PARAMS; + else { + TimingBudget /= divisor; + Status = VL53L1_set_timeouts_us( + Dev, + PhaseCalTimeoutUs, + MmTimeoutUs, + TimingBudget); + } + + if (Status == VL53L1_ERROR_NONE) + VL53L1DevDataSet(Dev, + LLData.range_config_timeout_us, + TimingBudget); + } + } + if (Status == VL53L1_ERROR_NONE) { + VL53L1DevDataSet(Dev, + CurrentParameters.MeasurementTimingBudgetMicroSeconds, + MeasurementTimingBudgetMicroSeconds); + } + + LOG_FUNCTION_END(Status); + return Status; +} + + +VL53L1_Error VL53L1_GetMeasurementTimingBudgetMicroSeconds(VL53L1_DEV Dev, + uint32_t *pMeasurementTimingBudgetMicroSeconds) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + uint8_t Mm1Enabled = 0; + uint8_t Mm2Enabled = 0; + uint32_t MmTimeoutUs = 0; + uint32_t RangeTimeoutUs = 0; + uint32_t MeasTimingBdg = 0; + uint32_t PhaseCalTimeoutUs = 0; + VL53L1_PresetModes PresetMode; + uint32_t TimingGuard; + uint32_t vhv; + int32_t vhv_loops; + + LOG_FUNCTION_START(""); + + *pMeasurementTimingBudgetMicroSeconds = 0; + + if (Status == VL53L1_ERROR_NONE) + Status = VL53L1_GetSequenceStepEnable(Dev, + VL53L1_SEQUENCESTEP_MM1, &Mm1Enabled); + + if (Status == VL53L1_ERROR_NONE) + Status = VL53L1_GetSequenceStepEnable(Dev, + VL53L1_SEQUENCESTEP_MM2, &Mm2Enabled); + + if (Status == VL53L1_ERROR_NONE) + Status = VL53L1_get_timeouts_us(Dev, + &PhaseCalTimeoutUs, + &MmTimeoutUs, + &RangeTimeoutUs); + + if (Status == VL53L1_ERROR_NONE) { + PresetMode = VL53L1DevDataGet(Dev, + CurrentParameters.PresetMode); + + switch (PresetMode) { + case VL53L1_PRESETMODE_LITE_RANGING: + if ((Mm1Enabled == 1) || (Mm2Enabled == 1)) + MeasTimingBdg = RangeTimeoutUs + 5000; + else + MeasTimingBdg = RangeTimeoutUs + 1000; + + break; + + case VL53L1_PRESETMODE_AUTONOMOUS: + if ((Mm1Enabled == 1) || (Mm2Enabled == 1)) + MeasTimingBdg = 2 * RangeTimeoutUs + 26600; + else + MeasTimingBdg = 2 * RangeTimeoutUs + 21600; + + break; + + case VL53L1_PRESETMODE_LOWPOWER_AUTONOMOUS: + vhv = LOWPOWER_AUTO_VHV_LOOP_DURATION_US; + VL53L1_get_tuning_parm(Dev, + VL53L1_TUNINGPARM_LOWPOWERAUTO_VHV_LOOP_BOUND, + &vhv_loops); + if (vhv_loops > 0) { + vhv += vhv_loops * + LOWPOWER_AUTO_VHV_LOOP_DURATION_US; + } + TimingGuard = LOWPOWER_AUTO_OVERHEAD_BEFORE_A_RANGING + + LOWPOWER_AUTO_OVERHEAD_BETWEEN_A_B_RANGING + + vhv; + MeasTimingBdg = 2 * RangeTimeoutUs + TimingGuard; + break; + + case VL53L1_PRESETMODE_RANGING: + case VL53L1_PRESETMODE_MULTIZONES_SCANNING: + case VL53L1_PRESETMODE_PROXY_RANGING_MODE: + MeasTimingBdg = (6 * RangeTimeoutUs) + 1700; + break; + + case VL53L1_PRESETMODE_OLT: + MeasTimingBdg = RangeTimeoutUs + MmTimeoutUs + 5000; + break; + default: + + + Status = VL53L1_ERROR_MODE_NOT_SUPPORTED; + } + } + if (Status == VL53L1_ERROR_NONE) + *pMeasurementTimingBudgetMicroSeconds = MeasTimingBdg; + + LOG_FUNCTION_END(Status); + return Status; +} + + + +VL53L1_Error VL53L1_SetInterMeasurementPeriodMilliSeconds(VL53L1_DEV Dev, + uint32_t InterMeasurementPeriodMilliSeconds) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + uint32_t adjustedIMP; + + LOG_FUNCTION_START(""); + + + + adjustedIMP = InterMeasurementPeriodMilliSeconds; + adjustedIMP += (adjustedIMP * 64) / 1000; + + + Status = VL53L1_set_inter_measurement_period_ms(Dev, + adjustedIMP); + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_GetInterMeasurementPeriodMilliSeconds(VL53L1_DEV Dev, + uint32_t *pInterMeasurementPeriodMilliSeconds) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + uint32_t adjustedIMP; + + LOG_FUNCTION_START(""); + + Status = VL53L1_get_inter_measurement_period_ms(Dev, &adjustedIMP); + + + adjustedIMP -= (adjustedIMP * 64) / 1000; + *pInterMeasurementPeriodMilliSeconds = adjustedIMP; + + + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_SetDmaxReflectance(VL53L1_DEV Dev, + FixPoint1616_t DmaxReflectance) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + VL53L1_dmax_reflectance_array_t dmax_reflectances; + + LOG_FUNCTION_START(""); + + if (DmaxReflectance > 100*65536) + Status = VL53L1_ERROR_INVALID_PARAMS; + + if (Status == VL53L1_ERROR_NONE) + Status = VL53L1_get_dmax_reflectance_values(Dev, + &dmax_reflectances); + + if (Status == VL53L1_ERROR_NONE) { + dmax_reflectances.target_reflectance_for_dmax[ + DMAX_REFLECTANCE_IDX] = + VL53L1_FIXPOINT1616TOFIXPOINT72(DmaxReflectance); + Status = VL53L1_set_dmax_reflectance_values(Dev, + &dmax_reflectances); + } + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_GetDmaxReflectance(VL53L1_DEV Dev, + FixPoint1616_t *pDmaxReflectance) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + VL53L1_dmax_reflectance_array_t dmax_reflectances; + uint16_t r; + + LOG_FUNCTION_START(""); + Status = VL53L1_get_dmax_reflectance_values(Dev, &dmax_reflectances); + if (Status == VL53L1_ERROR_NONE) { + r = dmax_reflectances.target_reflectance_for_dmax[ + DMAX_REFLECTANCE_IDX]; + *pDmaxReflectance = VL53L1_FIXPOINT72TOFIXPOINT1616(r); + } + + LOG_FUNCTION_END(Status); + return Status; +} + + +VL53L1_Error VL53L1_SetDmaxMode(VL53L1_DEV Dev, + VL53L1_DeviceDmaxModes DmaxMode) +{ + + VL53L1_Error Status = VL53L1_ERROR_NONE; + VL53L1_DeviceDmaxMode dmax_mode; + + LOG_FUNCTION_START(""); + + switch (DmaxMode) { + case VL53L1_DMAXMODE_FMT_CAL_DATA: + dmax_mode = VL53L1_DEVICEDMAXMODE__FMT_CAL_DATA; + break; + case VL53L1_DMAXMODE_CUSTCAL_DATA: + dmax_mode = VL53L1_DEVICEDMAXMODE__CUST_CAL_DATA; + break; + case VL53L1_DMAXMODE_PER_ZONE_CAL_DATA: + dmax_mode = VL53L1_DEVICEDMAXMODE__PER_ZONE_CAL_DATA; + break; + default: + Status = VL53L1_ERROR_INVALID_PARAMS; + break; + } + if (Status == VL53L1_ERROR_NONE) + Status = VL53L1_set_dmax_mode(Dev, dmax_mode); + + LOG_FUNCTION_END(Status); + return Status; +} + + +VL53L1_Error VL53L1_GetDmaxMode(VL53L1_DEV Dev, + VL53L1_DeviceDmaxModes *pDmaxMode) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + VL53L1_DeviceDmaxMode dmax_mode; + + LOG_FUNCTION_START(""); + + Status = VL53L1_get_dmax_mode(Dev, &dmax_mode); + if (Status == VL53L1_ERROR_NONE) { + switch (dmax_mode) { + case VL53L1_DEVICEDMAXMODE__FMT_CAL_DATA: + *pDmaxMode = VL53L1_DMAXMODE_FMT_CAL_DATA; + break; + case VL53L1_DEVICEDMAXMODE__CUST_CAL_DATA: + *pDmaxMode = VL53L1_DMAXMODE_CUSTCAL_DATA; + break; + case VL53L1_DEVICEDMAXMODE__PER_ZONE_CAL_DATA: + *pDmaxMode = VL53L1_DMAXMODE_PER_ZONE_CAL_DATA; + break; + default: + + + *pDmaxMode = VL53L1_ERROR_NOT_IMPLEMENTED; + break; + } + } + + LOG_FUNCTION_END(Status); + return Status; +} + + + + + + + + +VL53L1_Error VL53L1_GetNumberOfLimitCheck(uint16_t *pNumberOfLimitCheck) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + *pNumberOfLimitCheck = VL53L1_CHECKENABLE_NUMBER_OF_CHECKS; + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_GetLimitCheckInfo(uint16_t LimitCheckId, + char *pLimitCheckString) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + Status = VL53L1_get_limit_check_info(LimitCheckId, + pLimitCheckString); + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_GetLimitCheckStatus(VL53L1_DEV Dev, uint16_t LimitCheckId, + uint8_t *pLimitCheckStatus) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + uint8_t Temp8; + + LOG_FUNCTION_START(""); + + if (LimitCheckId >= VL53L1_CHECKENABLE_NUMBER_OF_CHECKS) { + Status = VL53L1_ERROR_INVALID_PARAMS; + } else { + VL53L1_GETARRAYPARAMETERFIELD(Dev, LimitChecksStatus, + LimitCheckId, Temp8); + *pLimitCheckStatus = Temp8; + } + + LOG_FUNCTION_END(Status); + return Status; +} + +static VL53L1_Error SetLimitValue(VL53L1_DEV Dev, uint16_t LimitCheckId, + FixPoint1616_t value) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + uint16_t tmpuint16; + + + LOG_FUNCTION_START(""); + + switch (LimitCheckId) { + case VL53L1_CHECKENABLE_SIGMA_FINAL_RANGE: + tmpuint16 = VL53L1_FIXPOINT1616TOFIXPOINT142(value); + VL53L1_set_lite_sigma_threshold(Dev, tmpuint16); + break; + case VL53L1_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE: + tmpuint16 = VL53L1_FIXPOINT1616TOFIXPOINT97(value); + VL53L1_set_lite_min_count_rate(Dev, tmpuint16); + break; + default: + Status = VL53L1_ERROR_INVALID_PARAMS; + } + + LOG_FUNCTION_END(Status); + return Status; +} + + +VL53L1_Error VL53L1_SetLimitCheckEnable(VL53L1_DEV Dev, uint16_t LimitCheckId, + uint8_t LimitCheckEnable) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + FixPoint1616_t TempFix1616 = 0; + + LOG_FUNCTION_START(""); + + + if (LimitCheckId >= VL53L1_CHECKENABLE_NUMBER_OF_CHECKS) { + Status = VL53L1_ERROR_INVALID_PARAMS; + } else { + + + if (LimitCheckEnable == 0) + TempFix1616 = 0; + else + VL53L1_GETARRAYPARAMETERFIELD(Dev, LimitChecksValue, + LimitCheckId, TempFix1616); + + Status = SetLimitValue(Dev, LimitCheckId, TempFix1616); + } + + if (Status == VL53L1_ERROR_NONE) + VL53L1_SETARRAYPARAMETERFIELD(Dev, + LimitChecksEnable, + LimitCheckId, + ((LimitCheckEnable == 0) ? 0 : 1)); + + + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_GetLimitCheckEnable(VL53L1_DEV Dev, uint16_t LimitCheckId, + uint8_t *pLimitCheckEnable) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + uint8_t Temp8; + + LOG_FUNCTION_START(""); + + if (LimitCheckId >= VL53L1_CHECKENABLE_NUMBER_OF_CHECKS) { + Status = VL53L1_ERROR_INVALID_PARAMS; + *pLimitCheckEnable = 0; + } else { + VL53L1_GETARRAYPARAMETERFIELD(Dev, LimitChecksEnable, + LimitCheckId, Temp8); + *pLimitCheckEnable = Temp8; + } + + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_SetLimitCheckValue(VL53L1_DEV Dev, uint16_t LimitCheckId, + FixPoint1616_t LimitCheckValue) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + uint8_t LimitChecksEnable; + + LOG_FUNCTION_START(""); + + if (LimitCheckId >= VL53L1_CHECKENABLE_NUMBER_OF_CHECKS) { + Status = VL53L1_ERROR_INVALID_PARAMS; + } else { + + VL53L1_GETARRAYPARAMETERFIELD(Dev, LimitChecksEnable, + LimitCheckId, + LimitChecksEnable); + + if (LimitChecksEnable == 0) { + + + VL53L1_SETARRAYPARAMETERFIELD(Dev, LimitChecksValue, + LimitCheckId, LimitCheckValue); + } else { + + Status = SetLimitValue(Dev, LimitCheckId, + LimitCheckValue); + + if (Status == VL53L1_ERROR_NONE) { + VL53L1_SETARRAYPARAMETERFIELD(Dev, + LimitChecksValue, + LimitCheckId, LimitCheckValue); + } + } + } + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_GetLimitCheckValue(VL53L1_DEV Dev, uint16_t LimitCheckId, + FixPoint1616_t *pLimitCheckValue) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + uint16_t MinCountRate; + FixPoint1616_t TempFix1616; + uint16_t SigmaThresh; + + LOG_FUNCTION_START(""); + + switch (LimitCheckId) { + case VL53L1_CHECKENABLE_SIGMA_FINAL_RANGE: + Status = VL53L1_get_lite_sigma_threshold(Dev, &SigmaThresh); + TempFix1616 = VL53L1_FIXPOINT142TOFIXPOINT1616(SigmaThresh); + break; + case VL53L1_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE: + Status = VL53L1_get_lite_min_count_rate(Dev, &MinCountRate); + TempFix1616 = VL53L1_FIXPOINT97TOFIXPOINT1616(MinCountRate); + break; + default: + Status = VL53L1_ERROR_INVALID_PARAMS; + } + + if (Status == VL53L1_ERROR_NONE) { + + if (TempFix1616 == 0) { + + + VL53L1_GETARRAYPARAMETERFIELD(Dev, + LimitChecksValue, LimitCheckId, + TempFix1616); + *pLimitCheckValue = TempFix1616; + VL53L1_SETARRAYPARAMETERFIELD(Dev, + LimitChecksEnable, LimitCheckId, 0); + } else { + *pLimitCheckValue = TempFix1616; + VL53L1_SETARRAYPARAMETERFIELD(Dev, + LimitChecksValue, LimitCheckId, + TempFix1616); + VL53L1_SETARRAYPARAMETERFIELD(Dev, + LimitChecksEnable, LimitCheckId, 1); + } + } + LOG_FUNCTION_END(Status); + return Status; + +} + +VL53L1_Error VL53L1_GetLimitCheckCurrent(VL53L1_DEV Dev, uint16_t LimitCheckId, + FixPoint1616_t *pLimitCheckCurrent) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + FixPoint1616_t TempFix1616 = 0; + + LOG_FUNCTION_START(""); + + if (LimitCheckId >= VL53L1_CHECKENABLE_NUMBER_OF_CHECKS) { + Status = VL53L1_ERROR_INVALID_PARAMS; + } else { + VL53L1_GETARRAYPARAMETERFIELD(Dev, LimitChecksCurrent, + LimitCheckId, TempFix1616); + *pLimitCheckCurrent = TempFix1616; + } + + LOG_FUNCTION_END(Status); + return Status; + +} + + + + + + + + + + +VL53L1_Error VL53L1_GetMaxNumberOfROI(VL53L1_DEV Dev, + uint8_t *pMaxNumberOfROI) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + VL53L1_PresetModes PresetMode; + + LOG_FUNCTION_START(""); + + PresetMode = VL53L1DevDataGet(Dev, CurrentParameters.PresetMode); + + + + if (PresetMode == VL53L1_PRESETMODE_MULTIZONES_SCANNING) + *pMaxNumberOfROI = VL53L1_MAX_USER_ZONES; + else + *pMaxNumberOfROI = 1; + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_SetROI(VL53L1_DEV Dev, + VL53L1_RoiConfig_t *pRoiConfig) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + VL53L1_PresetModes PresetMode; + uint8_t MaxNumberOfROI = 1; + VL53L1_zone_config_t zone_cfg; + VL53L1_UserRoi_t CurrROI; + uint8_t i; + uint8_t x_centre; + uint8_t y_centre; + uint8_t width, height; + + LOG_FUNCTION_START(""); + + + + PresetMode = VL53L1DevDataGet(Dev, CurrentParameters.PresetMode); + + + + if (PresetMode == VL53L1_PRESETMODE_MULTIZONES_SCANNING) + MaxNumberOfROI = VL53L1_MAX_USER_ZONES; + + if ((pRoiConfig->NumberOfRoi > MaxNumberOfROI) || + (pRoiConfig->NumberOfRoi < 1)) + Status = VL53L1_ERROR_INVALID_PARAMS; + + if (Status == VL53L1_ERROR_NONE) { + + + + zone_cfg.max_zones = MaxNumberOfROI; + zone_cfg.active_zones = pRoiConfig->NumberOfRoi - 1; + + for (i = 0; i < pRoiConfig->NumberOfRoi; i++) { + CurrROI = pRoiConfig->UserRois[i]; + + + + + + + + + + Status = CheckValidRectRoi(CurrROI); + if (Status != VL53L1_ERROR_NONE) + break; + + x_centre = (CurrROI.BotRightX + CurrROI.TopLeftX + 1) + / 2; + y_centre = (CurrROI.TopLeftY + CurrROI.BotRightY + 1) + / 2; + width = (CurrROI.BotRightX - CurrROI.TopLeftX); + height = (CurrROI.TopLeftY - CurrROI.BotRightY); + if ((width < 3) || (height < 3)) { + Status = VL53L1_ERROR_INVALID_PARAMS; + break; + } + zone_cfg.user_zones[i].x_centre = x_centre; + zone_cfg.user_zones[i].y_centre = y_centre; + zone_cfg.user_zones[i].width = width; + zone_cfg.user_zones[i].height = height; + } + } + + if (Status == VL53L1_ERROR_NONE) + Status = VL53L1_set_zone_config(Dev, &zone_cfg); + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_GetROI(VL53L1_DEV Dev, + VL53L1_RoiConfig_t *pRoiConfig) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + VL53L1_zone_config_t zone_cfg; + uint8_t i; + uint8_t TopLeftX; + uint8_t TopLeftY; + uint8_t BotRightX; + uint8_t BotRightY; + + LOG_FUNCTION_START(""); + + VL53L1_get_zone_config(Dev, &zone_cfg); + + pRoiConfig->NumberOfRoi = zone_cfg.active_zones + 1; + + for (i = 0; i < pRoiConfig->NumberOfRoi; i++) { + TopLeftX = (2 * zone_cfg.user_zones[i].x_centre - + zone_cfg.user_zones[i].width) >> 1; + TopLeftY = (2 * zone_cfg.user_zones[i].y_centre + + zone_cfg.user_zones[i].height) >> 1; + BotRightX = (2 * zone_cfg.user_zones[i].x_centre + + zone_cfg.user_zones[i].width) >> 1; + BotRightY = (2 * zone_cfg.user_zones[i].y_centre - + zone_cfg.user_zones[i].height) >> 1; + pRoiConfig->UserRois[i].TopLeftX = TopLeftX; + pRoiConfig->UserRois[i].TopLeftY = TopLeftY; + pRoiConfig->UserRois[i].BotRightX = BotRightX; + pRoiConfig->UserRois[i].BotRightY = BotRightY; + } + + LOG_FUNCTION_END(Status); + return Status; +} + + + + + + + + + +VL53L1_Error VL53L1_GetNumberOfSequenceSteps(VL53L1_DEV Dev, + uint8_t *pNumberOfSequenceSteps) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + SUPPRESS_UNUSED_WARNING(Dev); + + LOG_FUNCTION_START(""); + + *pNumberOfSequenceSteps = VL53L1_SEQUENCESTEP_NUMBER_OF_ITEMS; + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_GetSequenceStepsInfo(VL53L1_SequenceStepId SequenceStepId, + char *pSequenceStepsString) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + Status = VL53L1_get_sequence_steps_info( + SequenceStepId, + pSequenceStepsString); + + LOG_FUNCTION_END(Status); + + return Status; +} + +VL53L1_Error VL53L1_SetSequenceStepEnable(VL53L1_DEV Dev, + VL53L1_SequenceStepId SequenceStepId, uint8_t SequenceStepEnabled) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + uint32_t MeasurementTimingBudgetMicroSeconds; + + LOG_FUNCTION_START(""); + + + + + + + Status = VL53L1_set_sequence_config_bit(Dev, + (VL53L1_DeviceSequenceConfig)SequenceStepId, + SequenceStepEnabled); + + + + if (Status == VL53L1_ERROR_NONE) { + + + + MeasurementTimingBudgetMicroSeconds = VL53L1DevDataGet(Dev, + CurrentParameters.MeasurementTimingBudgetMicroSeconds); + + VL53L1_SetMeasurementTimingBudgetMicroSeconds(Dev, + MeasurementTimingBudgetMicroSeconds); + } + + LOG_FUNCTION_END(Status); + + return Status; +} + + +VL53L1_Error VL53L1_GetSequenceStepEnable(VL53L1_DEV Dev, + VL53L1_SequenceStepId SequenceStepId, uint8_t *pSequenceStepEnabled) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + Status = VL53L1_get_sequence_config_bit(Dev, + (VL53L1_DeviceSequenceConfig)SequenceStepId, + pSequenceStepEnabled); + + LOG_FUNCTION_END(Status); + return Status; +} + + + + + + + + + + + + +VL53L1_Error VL53L1_StartMeasurement(VL53L1_DEV Dev) +{ +#define TIMED_MODE_TIMING_GUARD_MILLISECONDS 4 + VL53L1_Error Status = VL53L1_ERROR_NONE; + uint8_t DeviceMeasurementMode; + VL53L1_State CurrPalState; + VL53L1_Error lStatus; + uint32_t MTBus, IMPms; + + LOG_FUNCTION_START(""); + + CurrPalState = VL53L1DevDataGet(Dev, PalState); + switch (CurrPalState) { + case VL53L1_STATE_IDLE: + Status = VL53L1_ERROR_NONE; + break; + case VL53L1_STATE_POWERDOWN: + case VL53L1_STATE_WAIT_STATICINIT: + case VL53L1_STATE_STANDBY: + case VL53L1_STATE_RUNNING: + case VL53L1_STATE_RESET: + case VL53L1_STATE_UNKNOWN: + case VL53L1_STATE_ERROR: + Status = VL53L1_ERROR_INVALID_COMMAND; + break; + default: + Status = VL53L1_ERROR_UNDEFINED; + } + + DeviceMeasurementMode = VL53L1DevDataGet(Dev, LLData.measurement_mode); + + + + + if ((Status == VL53L1_ERROR_NONE) && + (DeviceMeasurementMode == VL53L1_DEVICEMEASUREMENTMODE_TIMED)) { + lStatus = VL53L1_GetMeasurementTimingBudgetMicroSeconds(Dev, + &MTBus); + + + MTBus /= 1000; + lStatus = VL53L1_GetInterMeasurementPeriodMilliSeconds(Dev, + &IMPms); + + + SUPPRESS_UNUSED_WARNING(lStatus); + if (IMPms < MTBus + TIMED_MODE_TIMING_GUARD_MILLISECONDS) + Status = VL53L1_ERROR_INVALID_PARAMS; + } + + if (Status == VL53L1_ERROR_NONE) + Status = VL53L1_init_and_start_range( + Dev, + DeviceMeasurementMode, + VL53L1_DEVICECONFIGLEVEL_FULL); + + + + if (Status == VL53L1_ERROR_NONE) + VL53L1DevDataSet(Dev, PalState, VL53L1_STATE_RUNNING); + + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_StopMeasurement(VL53L1_DEV Dev) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + Status = VL53L1_stop_range(Dev); + + + + if (Status == VL53L1_ERROR_NONE) + VL53L1DevDataSet(Dev, PalState, VL53L1_STATE_IDLE); + + LOG_FUNCTION_END(Status); + return Status; +} + + +VL53L1_Error VL53L1_ClearInterruptAndStartMeasurement(VL53L1_DEV Dev) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + uint8_t DeviceMeasurementMode; + + LOG_FUNCTION_START(""); + + DeviceMeasurementMode = VL53L1DevDataGet(Dev, LLData.measurement_mode); + + Status = VL53L1_clear_interrupt_and_enable_next_range(Dev, + DeviceMeasurementMode); + + LOG_FUNCTION_END(Status); + return Status; +} + + +VL53L1_Error VL53L1_GetMeasurementDataReady(VL53L1_DEV Dev, + uint8_t *pMeasurementDataReady) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + Status = VL53L1_is_new_data_ready(Dev, pMeasurementDataReady); + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_WaitMeasurementDataReady(VL53L1_DEV Dev) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + + + Status = VL53L1_poll_for_range_completion(Dev, + VL53L1_RANGE_COMPLETION_POLLING_TIMEOUT_MS); + + LOG_FUNCTION_END(Status); + return Status; +} + +static void GenNewPresetMode(int16_t RefRange, + VL53L1_DistanceModes InternalDistanceMode, + VL53L1_DistanceModes *pNewDistanceMode) +{ + uint16_t HRLI = 600; + uint16_t HRLH = 700; + uint16_t MRLI = 1400; + uint16_t MRLH = 1500; + + switch (InternalDistanceMode) { + case VL53L1_DISTANCEMODE_SHORT: + + + + + + if (RefRange > MRLH) + *pNewDistanceMode = VL53L1_DISTANCEMODE_LONG; + else if (RefRange > HRLH) + *pNewDistanceMode = VL53L1_DISTANCEMODE_MEDIUM; + break; + case VL53L1_DISTANCEMODE_MEDIUM: + + + + + + if (RefRange > MRLH) + *pNewDistanceMode = VL53L1_DISTANCEMODE_LONG; + else if (RefRange < HRLI) + *pNewDistanceMode = VL53L1_DISTANCEMODE_SHORT; + break; + default: + + + + + + + if (RefRange < HRLI) + *pNewDistanceMode = VL53L1_DISTANCEMODE_SHORT; + else if (RefRange < MRLI) + *pNewDistanceMode = VL53L1_DISTANCEMODE_MEDIUM; + break; + } +} + +static void CheckAndChangeDistanceMode(VL53L1_DEV Dev, + VL53L1_TargetRangeData_t *pRangeData, + int16_t Ambient100DmaxMm, + VL53L1_DistanceModes *pNewDistanceMode +) +{ + VL53L1_DistanceModes DistanceMode; + uint8_t RangeStatus = pRangeData->RangeStatus; + uint8_t DmaxValid; + int32_t MinAmbient = BDTable[VL53L1_TUNING_MIN_AMBIENT_DMAX_VALID]; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + int32_t tmpint32; + + + + switch (RangeStatus) { + case VL53L1_RANGESTATUS_RANGE_VALID_NO_WRAP_CHECK_FAIL: + case VL53L1_RANGESTATUS_WRAP_TARGET_FAIL: + case VL53L1_RANGESTATUS_RANGE_VALID_MERGED_PULSE: + case VL53L1_RANGESTATUS_TARGET_PRESENT_LACK_OF_SIGNAL: + case VL53L1_RANGESTATUS_SYNCRONISATION_INT: + case VL53L1_RANGESTATUS_NONE: + return; + default: + + + break; + } + + DmaxValid = 1; + tmpint32 = pdev->hist_data.VL53L1_p_004; + if (tmpint32 < MinAmbient) + DmaxValid = 0; + + DistanceMode = VL53L1DevDataGet(Dev, + CurrentParameters.DistanceMode); + + *pNewDistanceMode = DistanceMode; + + if (RangeStatus == VL53L1_RANGESTATUS_RANGE_VALID) + GenNewPresetMode(pRangeData->RangeMilliMeter, + DistanceMode, pNewDistanceMode); + else { + if (DmaxValid) + GenNewPresetMode(Ambient100DmaxMm, + DistanceMode, pNewDistanceMode); + else + *pNewDistanceMode = VL53L1_DISTANCEMODE_LONG; + } +} + +static uint8_t ComputeRQL(uint8_t active_results, + uint8_t FilteredRangeStatus, + VL53L1_range_data_t *presults_data) +{ + int16_t T_Wide = 150; + int16_t SRL = 300; + uint16_t SRAS = 30; + FixPoint1616_t RAS; + FixPoint1616_t SRQL; + FixPoint1616_t GI = 7713587; + + FixPoint1616_t GGm = 3198157; + + FixPoint1616_t LRAP = 6554; + + FixPoint1616_t partial; + uint8_t finalvalue; + uint8_t returnvalue; + + if (active_results == 0) + returnvalue = 0; + else if (((presults_data->max_range_mm - + presults_data->min_range_mm) >= T_Wide) || + (FilteredRangeStatus == VL53L1_DEVICEERROR_PHASECONSISTENCY)) + returnvalue = 50; + else { + if (presults_data->median_range_mm < SRL) + RAS = SRAS * 65536; + else + RAS = LRAP * presults_data->median_range_mm; + + + + if (RAS != 0) { + partial = (GGm * presults_data->VL53L1_p_005); + partial = partial + (RAS >> 1); + partial = partial / RAS; + partial = partial * 65536; + if (partial <= GI) + SRQL = GI - partial; + else + SRQL = 50 * 65536; + } else + SRQL = 100 * 65536; + + finalvalue = (uint8_t)(SRQL >> 16); + returnvalue = MAX(50, MIN(100, finalvalue)); + } + + return returnvalue; +} + + +static uint8_t ConvertStatusLite(uint8_t FilteredRangeStatus) +{ + uint8_t RangeStatus; + + switch (FilteredRangeStatus) { + case VL53L1_DEVICEERROR_GPHSTREAMCOUNT0READY: + RangeStatus = VL53L1_RANGESTATUS_SYNCRONISATION_INT; + break; + case VL53L1_DEVICEERROR_RANGECOMPLETE_NO_WRAP_CHECK: + RangeStatus = VL53L1_RANGESTATUS_RANGE_VALID_NO_WRAP_CHECK_FAIL; + break; + case VL53L1_DEVICEERROR_RANGEPHASECHECK: + RangeStatus = VL53L1_RANGESTATUS_OUTOFBOUNDS_FAIL; + break; + case VL53L1_DEVICEERROR_MSRCNOTARGET: + RangeStatus = VL53L1_RANGESTATUS_SIGNAL_FAIL; + break; + case VL53L1_DEVICEERROR_SIGMATHRESHOLDCHECK: + RangeStatus = VL53L1_RANGESTATUS_SIGMA_FAIL; + break; + case VL53L1_DEVICEERROR_PHASECONSISTENCY: + RangeStatus = VL53L1_RANGESTATUS_WRAP_TARGET_FAIL; + break; + case VL53L1_DEVICEERROR_RANGEIGNORETHRESHOLD: + RangeStatus = VL53L1_RANGESTATUS_XTALK_SIGNAL_FAIL; + break; + case VL53L1_DEVICEERROR_MINCLIP: + RangeStatus = VL53L1_RANGESTATUS_RANGE_VALID_MIN_RANGE_CLIPPED; + break; + case VL53L1_DEVICEERROR_RANGECOMPLETE: + RangeStatus = VL53L1_RANGESTATUS_RANGE_VALID; + break; + default: + RangeStatus = VL53L1_RANGESTATUS_NONE; + } + + return RangeStatus; +} + + +static uint8_t ConvertStatusHisto(uint8_t FilteredRangeStatus) +{ + uint8_t RangeStatus; + + switch (FilteredRangeStatus) { + case VL53L1_DEVICEERROR_RANGEPHASECHECK: + RangeStatus = VL53L1_RANGESTATUS_OUTOFBOUNDS_FAIL; + break; + case VL53L1_DEVICEERROR_SIGMATHRESHOLDCHECK: + RangeStatus = VL53L1_RANGESTATUS_SIGMA_FAIL; + break; + case VL53L1_DEVICEERROR_RANGECOMPLETE_NO_WRAP_CHECK: + RangeStatus = VL53L1_RANGESTATUS_RANGE_VALID_NO_WRAP_CHECK_FAIL; + break; + case VL53L1_DEVICEERROR_PHASECONSISTENCY: + RangeStatus = VL53L1_RANGESTATUS_WRAP_TARGET_FAIL; + break; + case VL53L1_DEVICEERROR_PREV_RANGE_NO_TARGETS: + RangeStatus = VL53L1_RANGESTATUS_TARGET_PRESENT_LACK_OF_SIGNAL; + break; + case VL53L1_DEVICEERROR_EVENTCONSISTENCY: + RangeStatus = VL53L1_RANGESTATUS_WRAP_TARGET_FAIL; + break; + case VL53L1_DEVICEERROR_RANGECOMPLETE_MERGED_PULSE: + RangeStatus = VL53L1_RANGESTATUS_RANGE_VALID_MERGED_PULSE; + break; + case VL53L1_DEVICEERROR_RANGECOMPLETE: + RangeStatus = VL53L1_RANGESTATUS_RANGE_VALID; + break; + default: + RangeStatus = VL53L1_RANGESTATUS_NONE; + } + + return RangeStatus; +} + +static VL53L1_Error SetSimpleData(VL53L1_DEV Dev, + uint8_t active_results, uint8_t device_status, + VL53L1_range_data_t *presults_data, + VL53L1_RangingMeasurementData_t *pRangeData) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + uint8_t FilteredRangeStatus; + uint8_t SigmaLimitflag; + uint8_t SignalLimitflag; + uint8_t Temp8Enable; + uint8_t Temp8; + FixPoint1616_t AmbientRate; + FixPoint1616_t SignalRate; + FixPoint1616_t TempFix1616; + FixPoint1616_t LimitCheckValue; + VL53L1_PresetModes PresetMode; + int16_t Range; + + pRangeData->TimeStamp = presults_data->time_stamp; + + FilteredRangeStatus = presults_data->range_status & 0x1F; + + pRangeData->RangeQualityLevel = ComputeRQL(active_results, + FilteredRangeStatus, + presults_data); + + SignalRate = VL53L1_FIXPOINT97TOFIXPOINT1616( + presults_data->peak_signal_count_rate_mcps); + pRangeData->SignalRateRtnMegaCps + = SignalRate; + + AmbientRate = VL53L1_FIXPOINT97TOFIXPOINT1616( + presults_data->ambient_count_rate_mcps); + pRangeData->AmbientRateRtnMegaCps = AmbientRate; + + pRangeData->EffectiveSpadRtnCount = + presults_data->VL53L1_p_006; + + TempFix1616 = VL53L1_FIXPOINT97TOFIXPOINT1616( + presults_data->VL53L1_p_005); + + pRangeData->SigmaMilliMeter = TempFix1616; + + pRangeData->RangeMilliMeter = presults_data->median_range_mm; + + pRangeData->RangeFractionalPart = 0; + + + + switch (device_status) { + case VL53L1_DEVICEERROR_MULTCLIPFAIL: + case VL53L1_DEVICEERROR_VCSELWATCHDOGTESTFAILURE: + case VL53L1_DEVICEERROR_VCSELCONTINUITYTESTFAILURE: + case VL53L1_DEVICEERROR_NOVHVVALUEFOUND: + pRangeData->RangeStatus = VL53L1_RANGESTATUS_HARDWARE_FAIL; + break; + case VL53L1_DEVICEERROR_USERROICLIP: + pRangeData->RangeStatus = VL53L1_RANGESTATUS_MIN_RANGE_FAIL; + break; + default: + pRangeData->RangeStatus = VL53L1_RANGESTATUS_RANGE_VALID; + } + + + + if (pRangeData->RangeStatus == VL53L1_RANGESTATUS_RANGE_VALID) { + PresetMode = VL53L1DevDataGet(Dev, + CurrentParameters.PresetMode); + if ((PresetMode == VL53L1_PRESETMODE_MULTIZONES_SCANNING) || + (PresetMode == VL53L1_PRESETMODE_RANGING) || + (PresetMode == VL53L1_PRESETMODE_PROXY_RANGING_MODE)) + pRangeData->RangeStatus = + ConvertStatusHisto(FilteredRangeStatus); + else + pRangeData->RangeStatus = + ConvertStatusLite(FilteredRangeStatus); + } + + + + TempFix1616 = VL53L1_FIXPOINT97TOFIXPOINT1616( + presults_data->VL53L1_p_005); + VL53L1_SETARRAYPARAMETERFIELD(Dev, + LimitChecksCurrent, VL53L1_CHECKENABLE_SIGMA_FINAL_RANGE, + TempFix1616); + + TempFix1616 = VL53L1_FIXPOINT97TOFIXPOINT1616( + presults_data->peak_signal_count_rate_mcps); + VL53L1_SETARRAYPARAMETERFIELD(Dev, + LimitChecksCurrent, VL53L1_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE, + TempFix1616); + + + + + + VL53L1_GetLimitCheckValue(Dev, + VL53L1_CHECKENABLE_SIGMA_FINAL_RANGE, + &LimitCheckValue); + + SigmaLimitflag = (FilteredRangeStatus == + VL53L1_DEVICEERROR_SIGMATHRESHOLDCHECK) + ? 1 : 0; + + VL53L1_GetLimitCheckEnable(Dev, + VL53L1_CHECKENABLE_SIGMA_FINAL_RANGE, + &Temp8Enable); + + Temp8 = ((Temp8Enable == 1) && (SigmaLimitflag == 1)) ? 1 : 0; + VL53L1_SETARRAYPARAMETERFIELD(Dev, LimitChecksStatus, + VL53L1_CHECKENABLE_SIGMA_FINAL_RANGE, Temp8); + + + + VL53L1_GetLimitCheckValue(Dev, + VL53L1_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE, + &LimitCheckValue); + + SignalLimitflag = (FilteredRangeStatus == + VL53L1_DEVICEERROR_MSRCNOTARGET) + ? 1 : 0; + + VL53L1_GetLimitCheckEnable(Dev, + VL53L1_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE, + &Temp8Enable); + + Temp8 = ((Temp8Enable == 1) && (SignalLimitflag == 1)) ? 1 : 0; + VL53L1_SETARRAYPARAMETERFIELD(Dev, LimitChecksStatus, + VL53L1_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE, Temp8); + + Range = pRangeData->RangeMilliMeter; + if ((pRangeData->RangeStatus == VL53L1_RANGESTATUS_RANGE_VALID) && + (Range < 0)) { + if (Range < BDTable[VL53L1_TUNING_PROXY_MIN]) + pRangeData->RangeStatus = + VL53L1_RANGESTATUS_RANGE_INVALID; + else + pRangeData->RangeMilliMeter = 0; + } + + return Status; +} + +static VL53L1_Error SetTargetData(VL53L1_DEV Dev, + uint8_t active_results, uint8_t device_status, + VL53L1_range_data_t *presults_data, + VL53L1_TargetRangeData_t *pRangeData) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + uint8_t FilteredRangeStatus; + uint8_t SigmaLimitflag; + uint8_t SignalLimitflag; + uint8_t Temp8Enable; + uint8_t Temp8; + FixPoint1616_t AmbientRate; + FixPoint1616_t SignalRate; + FixPoint1616_t TempFix1616; + FixPoint1616_t LimitCheckValue; + VL53L1_PresetModes PresetMode; + int16_t Range; + + FilteredRangeStatus = presults_data->range_status & 0x1F; + + pRangeData->RangeQualityLevel = ComputeRQL(active_results, + FilteredRangeStatus, + presults_data); + + SignalRate = VL53L1_FIXPOINT97TOFIXPOINT1616( + presults_data->peak_signal_count_rate_mcps); + pRangeData->SignalRateRtnMegaCps + = SignalRate; + + AmbientRate = VL53L1_FIXPOINT97TOFIXPOINT1616( + presults_data->ambient_count_rate_mcps); + pRangeData->AmbientRateRtnMegaCps = AmbientRate; + + TempFix1616 = VL53L1_FIXPOINT97TOFIXPOINT1616( + presults_data->VL53L1_p_005); + + pRangeData->SigmaMilliMeter = TempFix1616; + + pRangeData->RangeMilliMeter = presults_data->median_range_mm; + pRangeData->RangeMaxMilliMeter = presults_data->max_range_mm; + pRangeData->RangeMinMilliMeter = presults_data->min_range_mm; + + pRangeData->RangeFractionalPart = 0; + + + + switch (device_status) { + case VL53L1_DEVICEERROR_MULTCLIPFAIL: + case VL53L1_DEVICEERROR_VCSELWATCHDOGTESTFAILURE: + case VL53L1_DEVICEERROR_VCSELCONTINUITYTESTFAILURE: + case VL53L1_DEVICEERROR_NOVHVVALUEFOUND: + pRangeData->RangeStatus = VL53L1_RANGESTATUS_HARDWARE_FAIL; + break; + case VL53L1_DEVICEERROR_USERROICLIP: + pRangeData->RangeStatus = VL53L1_RANGESTATUS_MIN_RANGE_FAIL; + break; + default: + pRangeData->RangeStatus = VL53L1_RANGESTATUS_RANGE_VALID; + } + + + + if (pRangeData->RangeStatus == VL53L1_RANGESTATUS_RANGE_VALID) { + PresetMode = VL53L1DevDataGet(Dev, + CurrentParameters.PresetMode); + if ((PresetMode == VL53L1_PRESETMODE_MULTIZONES_SCANNING) || + (PresetMode == VL53L1_PRESETMODE_RANGING) || + (PresetMode == VL53L1_PRESETMODE_PROXY_RANGING_MODE)) + pRangeData->RangeStatus = + ConvertStatusHisto(FilteredRangeStatus); + else + pRangeData->RangeStatus = + ConvertStatusLite(FilteredRangeStatus); + } + + + + TempFix1616 = VL53L1_FIXPOINT97TOFIXPOINT1616( + presults_data->VL53L1_p_005); + VL53L1_SETARRAYPARAMETERFIELD(Dev, + LimitChecksCurrent, VL53L1_CHECKENABLE_SIGMA_FINAL_RANGE, + TempFix1616); + + TempFix1616 = VL53L1_FIXPOINT97TOFIXPOINT1616( + presults_data->peak_signal_count_rate_mcps); + VL53L1_SETARRAYPARAMETERFIELD(Dev, + LimitChecksCurrent, VL53L1_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE, + TempFix1616); + + + + + + VL53L1_GetLimitCheckValue(Dev, + VL53L1_CHECKENABLE_SIGMA_FINAL_RANGE, + &LimitCheckValue); + + SigmaLimitflag = (FilteredRangeStatus == + VL53L1_DEVICEERROR_SIGMATHRESHOLDCHECK) + ? 1 : 0; + + VL53L1_GetLimitCheckEnable(Dev, + VL53L1_CHECKENABLE_SIGMA_FINAL_RANGE, + &Temp8Enable); + + Temp8 = ((Temp8Enable == 1) && (SigmaLimitflag == 1)) ? 1 : 0; + VL53L1_SETARRAYPARAMETERFIELD(Dev, LimitChecksStatus, + VL53L1_CHECKENABLE_SIGMA_FINAL_RANGE, Temp8); + + + + VL53L1_GetLimitCheckValue(Dev, + VL53L1_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE, + &LimitCheckValue); + + SignalLimitflag = (FilteredRangeStatus == + VL53L1_DEVICEERROR_MSRCNOTARGET) + ? 1 : 0; + + VL53L1_GetLimitCheckEnable(Dev, + VL53L1_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE, + &Temp8Enable); + + Temp8 = ((Temp8Enable == 1) && (SignalLimitflag == 1)) ? 1 : 0; + VL53L1_SETARRAYPARAMETERFIELD(Dev, LimitChecksStatus, + VL53L1_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE, Temp8); + + Range = pRangeData->RangeMilliMeter; + if ((pRangeData->RangeStatus == VL53L1_RANGESTATUS_RANGE_VALID) && + (Range < 0)) { + if (Range < BDTable[VL53L1_TUNING_PROXY_MIN]) + pRangeData->RangeStatus = + VL53L1_RANGESTATUS_RANGE_INVALID; + else + pRangeData->RangeMilliMeter = 0; + } + + return Status; +} + +static uint8_t GetOutputDataIndex(VL53L1_DEV Dev, + VL53L1_range_results_t *presults) +{ + uint8_t i; + uint8_t index = 0; + VL53L1_OutputModes OutputMode; + + OutputMode = VL53L1DevDataGet(Dev, CurrentParameters.OutputMode); + + + + + if (OutputMode == VL53L1_OUTPUTMODE_NEAREST) + return 0; + + + + + + for (i = 1; i < presults->active_results; i++) { + if (presults->VL53L1_p_002[i].peak_signal_count_rate_mcps > + presults->VL53L1_p_002[index].peak_signal_count_rate_mcps) + index = i; + } + + return index; +} + +VL53L1_Error VL53L1_GetRangingMeasurementData(VL53L1_DEV Dev, + VL53L1_RangingMeasurementData_t *pRangingMeasurementData) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + VL53L1_range_results_t results; + VL53L1_range_results_t *presults = &results; + VL53L1_range_data_t *presults_data; + VL53L1_PresetModes PresetMode; + uint8_t index = 0; + + LOG_FUNCTION_START(""); + + + + PresetMode = VL53L1DevDataGet(Dev, CurrentParameters.PresetMode); + + if (PresetMode == VL53L1_PRESETMODE_MULTIZONES_SCANNING) { + Status = VL53L1_ERROR_MODE_NOT_SUPPORTED; + LOG_FUNCTION_END(Status); + return Status; + } + + + + memset(pRangingMeasurementData, 0xFF, + sizeof(VL53L1_RangingMeasurementData_t)); + + + + Status = VL53L1_get_device_results( + Dev, + VL53L1_DEVICERESULTSLEVEL_FULL, + presults); + + if (Status == VL53L1_ERROR_NONE) { + pRangingMeasurementData->StreamCount = presults->stream_count; + + + + + + index = GetOutputDataIndex(Dev, presults); + presults_data = &(presults->VL53L1_p_002[index]); + Status = SetSimpleData(Dev, presults->active_results, + presults->device_status, + presults_data, + pRangingMeasurementData); + } + + LOG_FUNCTION_END(Status); + return Status; +} + +static VL53L1_Error SetMeasurementData(VL53L1_DEV Dev, + VL53L1_range_results_t *presults, + VL53L1_MultiRangingData_t *pMultiRangingData) +{ + uint8_t i; + uint8_t iteration; + VL53L1_TargetRangeData_t *pRangeData; + VL53L1_range_data_t *presults_data; + int16_t dmax_min; + VL53L1_Error Status = VL53L1_ERROR_NONE; + uint8_t Furthest_idx = 0; + int16_t Furthest_range = 0; + uint8_t ActiveResults; + + pMultiRangingData->NumberOfObjectsFound = presults->active_results; + pMultiRangingData->RoiNumber = presults->zone_id; + pMultiRangingData->HasXtalkValueChanged = + presults->smudge_corrector_data.new_xtalk_applied_flag; + dmax_min = MIN(presults->wrap_dmax_mm, + presults->VL53L1_p_007[DMAX_REFLECTANCE_IDX]); + pMultiRangingData->DmaxMilliMeter = dmax_min; + + + + + + pMultiRangingData->TimeStamp = 0; + + pMultiRangingData->StreamCount = presults->stream_count; + + pMultiRangingData->RecommendedDistanceMode = + VL53L1DevDataGet(Dev, CurrentParameters.DistanceMode); + ActiveResults = presults->active_results; + if (ActiveResults < 1) + + + + + iteration = 1; + else + iteration = ActiveResults; + for (i = 0; i < iteration; i++) { + pRangeData = &(pMultiRangingData->RangeData[i]); + + presults_data = &(presults->VL53L1_p_002[i]); + if (Status == VL53L1_ERROR_NONE) + Status = SetTargetData(Dev, ActiveResults, + presults->device_status, + presults_data, + pRangeData); + + pMultiRangingData->EffectiveSpadRtnCount = + presults_data->VL53L1_p_006; + + if ((pRangeData->RangeStatus == VL53L1_RANGESTATUS_RANGE_VALID) + && (pRangeData->RangeMilliMeter > Furthest_range)) { + Furthest_range = pRangeData->RangeMilliMeter; + Furthest_idx = i; + } + + } + + + if ((Status == VL53L1_ERROR_NONE) && (ActiveResults > 0)) { + pRangeData = &(pMultiRangingData->RangeData[Furthest_idx]); + CheckAndChangeDistanceMode(Dev, pRangeData, + presults->VL53L1_p_007[VL53L1_MAX_AMBIENT_DMAX_VALUES-1], + &pMultiRangingData->RecommendedDistanceMode); + } + + + return Status; +} + +VL53L1_Error VL53L1_GetMultiRangingData(VL53L1_DEV Dev, + VL53L1_MultiRangingData_t *pMultiRangingData) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + VL53L1_range_results_t results; + VL53L1_range_results_t *presults = &results; + + LOG_FUNCTION_START(""); + + + + memset(pMultiRangingData, 0xFF, + sizeof(VL53L1_MultiRangingData_t)); + + + + Status = VL53L1_get_device_results( + Dev, + VL53L1_DEVICERESULTSLEVEL_FULL, + presults); + + + if (Status == VL53L1_ERROR_NONE) { + + switch (presults->rd_device_state) { + case VL53L1_DEVICESTATE_RANGING_GATHER_DATA: + pMultiRangingData->RoiStatus = + VL53L1_ROISTATUS_VALID_NOT_LAST; + break; + case VL53L1_DEVICESTATE_RANGING_OUTPUT_DATA: + pMultiRangingData->RoiStatus = + VL53L1_ROISTATUS_VALID_LAST; + break; + default: + pMultiRangingData->RoiStatus = + VL53L1_ROISTATUS_NOT_VALID; + } + + Status = SetMeasurementData(Dev, + presults, + pMultiRangingData); + + } + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_GetAdditionalData(VL53L1_DEV Dev, + VL53L1_AdditionalData_t *pAdditionalData) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + Status = VL53L1_get_additional_data(Dev, pAdditionalData); + + LOG_FUNCTION_END(Status); + return Status; +} + + + + + + + + +VL53L1_Error VL53L1_SetTuningParameter(VL53L1_DEV Dev, + uint16_t TuningParameterId, int32_t TuningParameterValue) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + if (TuningParameterId == + VL53L1_TUNINGPARM_DYNXTALK_NODETECT_XTALK_OFFSET_KCPS) + return VL53L1_ERROR_INVALID_PARAMS; + + + if (TuningParameterId >= 32768) + Status = VL53L1_set_tuning_parm(Dev, + TuningParameterId, + TuningParameterValue); + else { + if (TuningParameterId < VL53L1_TUNING_MAX_TUNABLE_KEY) + BDTable[TuningParameterId] = TuningParameterValue; + else + Status = VL53L1_ERROR_INVALID_PARAMS; + } + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_GetTuningParameter(VL53L1_DEV Dev, + uint16_t TuningParameterId, int32_t *pTuningParameterValue) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (TuningParameterId >= 32768) + Status = VL53L1_get_tuning_parm(Dev, + TuningParameterId, + pTuningParameterValue); + else { + if (TuningParameterId < VL53L1_TUNING_MAX_TUNABLE_KEY) + *pTuningParameterValue = BDTable[TuningParameterId]; + else + Status = VL53L1_ERROR_INVALID_PARAMS; + } + + LOG_FUNCTION_END(Status); + return Status; +} + + +VL53L1_Error VL53L1_PerformRefSpadManagement(VL53L1_DEV Dev) +{ +#ifdef VL53L1_NOCALIB + VL53L1_Error Status = VL53L1_ERROR_NOT_SUPPORTED; + + SUPPRESS_UNUSED_WARNING(Dev); + + LOG_FUNCTION_START(""); +#else + VL53L1_Error Status = VL53L1_ERROR_NONE; + VL53L1_Error RawStatus; + uint8_t dcrbuffer[24]; + uint8_t *commbuf; + uint8_t numloc[2] = {5, 3}; + VL53L1_LLDriverData_t *pdev; + VL53L1_customer_nvm_managed_t *pc; + VL53L1_PresetModes PresetMode; + + LOG_FUNCTION_START(""); + + pdev = VL53L1DevStructGetLLDriverHandle(Dev); + pc = &pdev->customer; + + if (Status == VL53L1_ERROR_NONE) { + PresetMode = VL53L1DevDataGet(Dev, + CurrentParameters.PresetMode); + Status = VL53L1_run_ref_spad_char(Dev, &RawStatus); + + + + + if (Status == VL53L1_ERROR_NONE) + Status = VL53L1_SetPresetMode(Dev, PresetMode); + } + + if (Status == VL53L1_WARNING_REF_SPAD_CHAR_RATE_TOO_HIGH) { + + + + + Status = VL53L1_read_nvm_raw_data(Dev, + (uint8_t)(0xA0 >> 2), + (uint8_t)(24 >> 2), + dcrbuffer); + + if (Status == VL53L1_ERROR_NONE) + Status = VL53L1_WriteMulti(Dev, + VL53L1_REF_SPAD_MAN__NUM_REQUESTED_REF_SPADS, + numloc, 2); + + if (Status == VL53L1_ERROR_NONE) { + pc->ref_spad_man__num_requested_ref_spads = numloc[0]; + pc->ref_spad_man__ref_location = numloc[1]; + } + + if (Status == VL53L1_ERROR_NONE) + commbuf = &dcrbuffer[16]; + + + + + + + if (Status == VL53L1_ERROR_NONE) + Status = VL53L1_WriteMulti(Dev, + VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_REF_0, + commbuf, 6); + + if (Status == VL53L1_ERROR_NONE) { + pc->global_config__spad_enables_ref_0 = commbuf[0]; + pc->global_config__spad_enables_ref_1 = commbuf[1]; + pc->global_config__spad_enables_ref_2 = commbuf[2]; + pc->global_config__spad_enables_ref_3 = commbuf[3]; + pc->global_config__spad_enables_ref_4 = commbuf[4]; + pc->global_config__spad_enables_ref_5 = commbuf[5]; + } + + + } + +#endif + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_SmudgeCorrectionEnable(VL53L1_DEV Dev, + VL53L1_SmudgeCorrectionModes Mode) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + VL53L1_Error s1 = VL53L1_ERROR_NONE; + VL53L1_Error s2 = VL53L1_ERROR_NONE; + VL53L1_Error s3 = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + switch (Mode) { + case VL53L1_SMUDGE_CORRECTION_NONE: + s1 = VL53L1_dynamic_xtalk_correction_disable(Dev); + s2 = VL53L1_dynamic_xtalk_correction_apply_disable(Dev); + s3 = VL53L1_dynamic_xtalk_correction_single_apply_disable(Dev); + break; + case VL53L1_SMUDGE_CORRECTION_CONTINUOUS: + s1 = VL53L1_dynamic_xtalk_correction_enable(Dev); + s2 = VL53L1_dynamic_xtalk_correction_apply_enable(Dev); + s3 = VL53L1_dynamic_xtalk_correction_single_apply_disable(Dev); + break; + case VL53L1_SMUDGE_CORRECTION_SINGLE: + s1 = VL53L1_dynamic_xtalk_correction_enable(Dev); + s2 = VL53L1_dynamic_xtalk_correction_apply_enable(Dev); + s3 = VL53L1_dynamic_xtalk_correction_single_apply_enable(Dev); + break; + case VL53L1_SMUDGE_CORRECTION_DEBUG: + s1 = VL53L1_dynamic_xtalk_correction_enable(Dev); + s2 = VL53L1_dynamic_xtalk_correction_apply_disable(Dev); + s3 = VL53L1_dynamic_xtalk_correction_single_apply_disable(Dev); + break; + default: + Status = VL53L1_ERROR_INVALID_PARAMS; + break; + } + + if (Status == VL53L1_ERROR_NONE) { + Status = s1; + if (Status == VL53L1_ERROR_NONE) + Status = s2; + if (Status == VL53L1_ERROR_NONE) + Status = s3; + } + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_SetXTalkCompensationEnable(VL53L1_DEV Dev, + uint8_t XTalkCompensationEnable) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (XTalkCompensationEnable == 0) + Status = VL53L1_disable_xtalk_compensation(Dev); + else + Status = VL53L1_enable_xtalk_compensation(Dev); + + LOG_FUNCTION_END(Status); + return Status; +} + + +VL53L1_Error VL53L1_GetXTalkCompensationEnable(VL53L1_DEV Dev, + uint8_t *pXTalkCompensationEnable) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + VL53L1_get_xtalk_compensation_enable( + Dev, + pXTalkCompensationEnable); + + LOG_FUNCTION_END(Status); + return Status; +} + + +VL53L1_Error VL53L1_PerformXTalkCalibration(VL53L1_DEV Dev, + uint8_t CalibrationOption) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + VL53L1_Error UnfilteredStatus; + int16_t CalDistanceMm; + VL53L1_xtalk_calibration_results_t xtalk; + + LOG_FUNCTION_START(""); + + switch (CalibrationOption) { + case VL53L1_XTALKCALIBRATIONMODE_NO_TARGET: + Status = VL53L1_run_xtalk_extraction(Dev, &UnfilteredStatus); + + + if (Status == VL53L1_ERROR_XTALK_EXTRACTION_NO_SAMPLE_FAIL) + VL53L1_xtalk_cal_data_init(Dev); + break; + case VL53L1_XTALKCALIBRATIONMODE_SINGLE_TARGET: + Status = SingleTargetXTalkCalibration(Dev); + break; + case VL53L1_XTALKCALIBRATIONMODE_FULL_ROI: + CalDistanceMm = (int16_t) + BDTable[VL53L1_TUNING_XTALK_FULL_ROI_TARGET_DISTANCE_MM]; + Status = VL53L1_run_hist_xtalk_extraction(Dev, CalDistanceMm, + &UnfilteredStatus); + +/*fix for low xtalk coverglass*/ + { + int i; + uint32_t sum = 0; + VL53L1_CalibrationData_t caldata; + + VL53L1_GetCalibrationData(Dev, &caldata); + for (i=0;i<12;i++){ + sum += caldata.xtalkhisto.xtalk_shape.bin_data[i]; + } + + if (((caldata.customer.algo__crosstalk_compensation_plane_offset_kcps) > 1024000)|| + ((sum>1048) || (sum<1000))) + { + caldata.customer.algo__crosstalk_compensation_plane_offset_kcps= 50; + Dev->LLData.xtalk_cal.algo__crosstalk_compensation_plane_offset_kcps = 50; + caldata.xtalkhisto.xtalk_shape.bin_data[0]=307; + caldata.xtalkhisto.xtalk_shape.bin_data[1]=410; + caldata.xtalkhisto.xtalk_shape.bin_data[2]=410; + caldata.xtalkhisto.xtalk_shape.bin_data[3]=307; + for (i=4;i<12;i++){ + caldata.xtalkhisto.xtalk_shape.bin_data[i]=0; + } + VL53L1_SetCalibrationData(Dev, &caldata); + } + } + /*end of fix for low xtalk coverglass*/ + + break; + default: + Status = VL53L1_ERROR_INVALID_PARAMS; + } + + if (Status == VL53L1_ERROR_NONE) { + Status = VL53L1_get_current_xtalk_settings(Dev, &xtalk); + Status = VL53L1_set_tuning_parm(Dev, + VL53L1_TUNINGPARM_DYNXTALK_NODETECT_XTALK_OFFSET_KCPS, + xtalk.algo__crosstalk_compensation_plane_offset_kcps); + } + + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_SetOffsetCalibrationMode(VL53L1_DEV Dev, + VL53L1_OffsetCalibrationModes OffsetCalibrationMode) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + VL53L1_OffsetCalibrationMode offset_cal_mode; + + LOG_FUNCTION_START(""); + + if (OffsetCalibrationMode == VL53L1_OFFSETCALIBRATIONMODE_STANDARD) { + offset_cal_mode = + VL53L1_OFFSETCALIBRATIONMODE__MM1_MM2__STANDARD; + } else if (OffsetCalibrationMode == + VL53L1_OFFSETCALIBRATIONMODE_PRERANGE_ONLY) { + offset_cal_mode = + VL53L1_OFFSETCALIBRATIONMODE__MM1_MM2__STANDARD_PRE_RANGE_ONLY; + } else if (OffsetCalibrationMode == + VL53L1_OFFSETCALIBRATIONMODE_MULTI_ZONE) { + offset_cal_mode = + VL53L1_OFFSETCALIBRATIONMODE__PER_ZONE; + } else { + Status = VL53L1_ERROR_INVALID_PARAMS; + } + + if (Status == VL53L1_ERROR_NONE) + Status = VL53L1_set_offset_calibration_mode(Dev, + offset_cal_mode); + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_SetOffsetCorrectionMode(VL53L1_DEV Dev, + VL53L1_OffsetCorrectionModes OffsetCorrectionMode) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + VL53L1_OffsetCorrectionMode offset_cor_mode; + + LOG_FUNCTION_START(""); + + if (OffsetCorrectionMode == VL53L1_OFFSETCORRECTIONMODE_STANDARD) { + offset_cor_mode = + VL53L1_OFFSETCORRECTIONMODE__MM1_MM2_OFFSETS; + } else if (OffsetCorrectionMode == + VL53L1_OFFSETCORRECTIONMODE_PERZONE) { + offset_cor_mode = + VL53L1_OFFSETCORRECTIONMODE__PER_ZONE_OFFSETS; + } else { + Status = VL53L1_ERROR_INVALID_PARAMS; + } + + if (Status == VL53L1_ERROR_NONE) + Status = VL53L1_set_offset_correction_mode(Dev, + offset_cor_mode); + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_PerformOffsetCalibration(VL53L1_DEV Dev, + int32_t CalDistanceMilliMeter, FixPoint1616_t CalReflectancePercent) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + VL53L1_Error UnfilteredStatus; + VL53L1_OffsetCalibrationMode offset_cal_mode; + uint16_t CalReflectancePercent_int; + + + VL53L1_DevicePresetModes device_preset_mode; + VL53L1_DeviceZonePreset zone_preset; + VL53L1_zone_config_t zone_cfg; + + LOG_FUNCTION_START(""); + + CalReflectancePercent_int = + VL53L1_FIXPOINT1616TOFIXPOINT72(CalReflectancePercent); + + if (Status == VL53L1_ERROR_NONE) + Status = VL53L1_get_offset_calibration_mode(Dev, + &offset_cal_mode); + + if (Status != VL53L1_ERROR_NONE) { + LOG_FUNCTION_END(Status); + return Status; + } + + + if ((offset_cal_mode == + VL53L1_OFFSETCALIBRATIONMODE__MM1_MM2__STANDARD) || + (offset_cal_mode == + VL53L1_OFFSETCALIBRATIONMODE__MM1_MM2__STANDARD_PRE_RANGE_ONLY + )) { + if (Status == VL53L1_ERROR_NONE) + Status = VL53L1_run_offset_calibration( + Dev, + (int16_t)CalDistanceMilliMeter, + CalReflectancePercent_int, + &UnfilteredStatus); + + } else if (offset_cal_mode == + VL53L1_OFFSETCALIBRATIONMODE__PER_ZONE) { + device_preset_mode = + VL53L1_DEVICEPRESETMODE_HISTOGRAM_MULTIZONE_LONG_RANGE; + zone_preset = VL53L1_DEVICEZONEPRESET_CUSTOM; + + Status = VL53L1_get_zone_config(Dev, &zone_cfg); + if (Status == VL53L1_ERROR_NONE) + Status = VL53L1_run_zone_calibration( + Dev, + device_preset_mode, + zone_preset, + &zone_cfg, + (int16_t)CalDistanceMilliMeter, + CalReflectancePercent_int, + &UnfilteredStatus); + + } else { + Status = VL53L1_ERROR_INVALID_PARAMS; + } + LOG_FUNCTION_END(Status); + return Status; +} +#ifdef OFFSET_CALIB +VL53L1_Error VL53L1_PerformOffsetCalibration(VL53L1_DEV Dev, + int32_t CalDistanceMilliMeter) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + VL53L1_Error UnfilteredStatus; + VL53L1_OffsetCalibrationMode offset_cal_mode; + + LOG_FUNCTION_START(""); + + if (Status == VL53L1_ERROR_NONE) + Status = VL53L1_get_offset_calibration_mode(Dev, + &offset_cal_mode); + + if (Status != VL53L1_ERROR_NONE) { + LOG_FUNCTION_END(Status); + return Status; + } + + if ((offset_cal_mode == + VL53L1_OFFSETCALIBRATIONMODE__MM1_MM2__STANDARD) || + (offset_cal_mode == + VL53L1_OFFSETCALIBRATIONMODE__MM1_MM2__STANDARD_PRE_RANGE_ONLY + )) { + if (Status == VL53L1_ERROR_NONE) + Status = VL53L1_run_offset_calibration( + Dev, + (int16_t)CalDistanceMilliMeter, + &UnfilteredStatus); + } else { + Status = VL53L1_ERROR_INVALID_PARAMS; + } + LOG_FUNCTION_END(Status); + return Status; +} +#endif +#ifdef OFFSET_CALIB_EMPTY +VL53L1_Error VL53L1_PerformOffsetCalibration(VL53L1_DEV Dev, + int32_t CalDistanceMilliMeter) +{ + VL53L1_Error Status = VL53L1_ERROR_NOT_SUPPORTED; + + SUPPRESS_UNUSED_WARNING(Dev); + SUPPRESS_UNUSED_WARNING(CalDistanceMilliMeter); + + return Status; +} +#endif + +VL53L1_Error VL53L1_PerformOffsetSimpleCalibration(VL53L1_DEV Dev, + int32_t CalDistanceMilliMeter) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + int32_t sum_ranging; + uint8_t offset_meas; + int16_t Max, UnderMax, OverMax, Repeat; + int32_t total_count, inloopcount; + int32_t IncRounding; + int16_t meanDistance_mm; + int16_t offset; + VL53L1_RangingMeasurementData_t RangingMeasurementData; + VL53L1_LLDriverData_t *pdev; + uint8_t goodmeas; + VL53L1_Error SmudgeStatus = VL53L1_ERROR_NONE; + uint8_t smudge_corr_en; + + LOG_FUNCTION_START(""); + + pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + + smudge_corr_en = pdev->smudge_correct_config.smudge_corr_enabled; + SmudgeStatus = VL53L1_dynamic_xtalk_correction_disable(Dev); + + + pdev->customer.algo__part_to_part_range_offset_mm = 0; + pdev->customer.mm_config__inner_offset_mm = 0; + pdev->customer.mm_config__outer_offset_mm = 0; + + Repeat = BDTable[VL53L1_TUNING_SIMPLE_OFFSET_CALIBRATION_REPEAT]; + Max = BDTable[ + VL53L1_TUNING_MAX_SIMPLE_OFFSET_CALIBRATION_SAMPLE_NUMBER]; + UnderMax = 1 + (Max / 2); + OverMax = Max + (Max / 2); + sum_ranging = 0; + total_count = 0; + + while ((Repeat > 0) && (Status == VL53L1_ERROR_NONE)) { + Status = VL53L1_StartMeasurement(Dev); + + + if (Status == VL53L1_ERROR_NONE) + Status = VL53L1_WaitMeasurementDataReady(Dev); + if (Status == VL53L1_ERROR_NONE) + Status = VL53L1_GetRangingMeasurementData(Dev, + &RangingMeasurementData); + if (Status == VL53L1_ERROR_NONE) + Status = VL53L1_ClearInterruptAndStartMeasurement(Dev); + + + inloopcount = 0; + offset_meas = 0; + while ((Status == VL53L1_ERROR_NONE) && (inloopcount < Max) && + (offset_meas < OverMax)) { + Status = VL53L1_WaitMeasurementDataReady(Dev); + if (Status == VL53L1_ERROR_NONE) + Status = VL53L1_GetRangingMeasurementData(Dev, + &RangingMeasurementData); + goodmeas = (RangingMeasurementData.RangeStatus == + VL53L1_RANGESTATUS_RANGE_VALID); + if ((Status == VL53L1_ERROR_NONE) && goodmeas) { + sum_ranging = sum_ranging + + RangingMeasurementData.RangeMilliMeter; + inloopcount++; + } + Status = VL53L1_ClearInterruptAndStartMeasurement(Dev); + offset_meas++; + } + total_count += inloopcount; + + + + if (inloopcount < UnderMax) + Status = VL53L1_ERROR_OFFSET_CAL_NO_SAMPLE_FAIL; + + VL53L1_StopMeasurement(Dev); + + Repeat--; + + } + + + if ((SmudgeStatus == VL53L1_ERROR_NONE) && (smudge_corr_en == 1)) + SmudgeStatus = VL53L1_dynamic_xtalk_correction_enable(Dev); + + + if ((sum_ranging < 0) || + (sum_ranging > ((int32_t) total_count * 0xffff))) { + Status = VL53L1_WARNING_OFFSET_CAL_SIGMA_TOO_HIGH; + } + + if ((Status == VL53L1_ERROR_NONE) && (total_count > 0)) { + IncRounding = total_count / 2; + meanDistance_mm = (int16_t)((sum_ranging + IncRounding) + / total_count); + offset = (int16_t)CalDistanceMilliMeter - meanDistance_mm; + pdev->customer.algo__part_to_part_range_offset_mm = 0; + pdev->customer.mm_config__inner_offset_mm = offset; + pdev->customer.mm_config__outer_offset_mm = offset; + + Status = VL53L1_set_customer_nvm_managed(Dev, + &(pdev->customer)); + } + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_SetCalibrationData(VL53L1_DEV Dev, + VL53L1_CalibrationData_t *pCalibrationData) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + VL53L1_CustomerNvmManaged_t *pC; + VL53L1_calibration_data_t cal_data; + uint32_t x; + VL53L1_xtalk_calibration_results_t xtalk; + + LOG_FUNCTION_START(""); + + cal_data.struct_version = pCalibrationData->struct_version - + VL53L1_ADDITIONAL_CALIBRATION_DATA_STRUCT_VERSION; + + + + + + + memcpy( + &(cal_data.fmt_dmax_cal), + &(pCalibrationData->fmt_dmax_cal), + sizeof(VL53L1_dmax_calibration_data_t)); + + + + memcpy( + &(cal_data.cust_dmax_cal), + &(pCalibrationData->cust_dmax_cal), + sizeof(VL53L1_dmax_calibration_data_t)); + + + + + memcpy( + &(cal_data.add_off_cal_data), + &(pCalibrationData->add_off_cal_data), + sizeof(VL53L1_additional_offset_cal_data_t)); + + + + memcpy( + &(cal_data.optical_centre), + &(pCalibrationData->optical_centre), + sizeof(VL53L1_optical_centre_t)); + + + + memcpy( + &(cal_data.xtalkhisto), + &(pCalibrationData->xtalkhisto), + sizeof(VL53L1_xtalk_histogram_data_t)); + + + + memcpy( + &(cal_data.gain_cal), + &(pCalibrationData->gain_cal), + sizeof(VL53L1_gain_calibration_data_t)); + + + + memcpy( + &(cal_data.cal_peak_rate_map), + &(pCalibrationData->cal_peak_rate_map), + sizeof(VL53L1_cal_peak_rate_map_t)); + + pC = &pCalibrationData->customer; + x = pC->algo__crosstalk_compensation_plane_offset_kcps; + cal_data.customer.algo__crosstalk_compensation_plane_offset_kcps = + (uint16_t)(x&0x0000FFFF); + + cal_data.customer.global_config__spad_enables_ref_0 = + pC->global_config__spad_enables_ref_0; + cal_data.customer.global_config__spad_enables_ref_1 = + pC->global_config__spad_enables_ref_1; + cal_data.customer.global_config__spad_enables_ref_2 = + pC->global_config__spad_enables_ref_2; + cal_data.customer.global_config__spad_enables_ref_3 = + pC->global_config__spad_enables_ref_3; + cal_data.customer.global_config__spad_enables_ref_4 = + pC->global_config__spad_enables_ref_4; + cal_data.customer.global_config__spad_enables_ref_5 = + pC->global_config__spad_enables_ref_5; + cal_data.customer.global_config__ref_en_start_select = + pC->global_config__ref_en_start_select; + cal_data.customer.ref_spad_man__num_requested_ref_spads = + pC->ref_spad_man__num_requested_ref_spads; + cal_data.customer.ref_spad_man__ref_location = + pC->ref_spad_man__ref_location; + cal_data.customer.algo__crosstalk_compensation_x_plane_gradient_kcps = + pC->algo__crosstalk_compensation_x_plane_gradient_kcps; + cal_data.customer.algo__crosstalk_compensation_y_plane_gradient_kcps = + pC->algo__crosstalk_compensation_y_plane_gradient_kcps; + cal_data.customer.ref_spad_char__total_rate_target_mcps = + pC->ref_spad_char__total_rate_target_mcps; + cal_data.customer.algo__part_to_part_range_offset_mm = + pC->algo__part_to_part_range_offset_mm; + cal_data.customer.mm_config__inner_offset_mm = + pC->mm_config__inner_offset_mm; + cal_data.customer.mm_config__outer_offset_mm = + pC->mm_config__outer_offset_mm; + + Status = VL53L1_set_part_to_part_data(Dev, &cal_data); + if (Status != VL53L1_ERROR_NONE) + goto ENDFUNC; + + Status = VL53L1_get_current_xtalk_settings(Dev, &xtalk); + + if (Status != VL53L1_ERROR_NONE) + goto ENDFUNC; + + xtalk.algo__crosstalk_compensation_plane_offset_kcps = x; + + + Status = VL53L1_set_tuning_parm(Dev, + VL53L1_TUNINGPARM_DYNXTALK_NODETECT_XTALK_OFFSET_KCPS, + x); + + + + Status = VL53L1_set_current_xtalk_settings(Dev, &xtalk); + +ENDFUNC: + LOG_FUNCTION_END(Status); + return Status; + +} + +VL53L1_Error VL53L1_GetCalibrationData(VL53L1_DEV Dev, + VL53L1_CalibrationData_t *pCalibrationData) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + VL53L1_calibration_data_t cal_data; + VL53L1_CustomerNvmManaged_t *pC; + VL53L1_customer_nvm_managed_t *pC2; + VL53L1_xtalk_calibration_results_t xtalk; + uint32_t tmp; + VL53L1_PresetModes PresetMode; + + LOG_FUNCTION_START(""); + + + + Status = VL53L1_get_part_to_part_data(Dev, &cal_data); + + pCalibrationData->struct_version = cal_data.struct_version + + VL53L1_ADDITIONAL_CALIBRATION_DATA_STRUCT_VERSION; + + + + memcpy( + &(pCalibrationData->fmt_dmax_cal), + &(cal_data.fmt_dmax_cal), + sizeof(VL53L1_dmax_calibration_data_t)); + + + + memcpy( + &(pCalibrationData->cust_dmax_cal), + &(cal_data.cust_dmax_cal), + sizeof(VL53L1_dmax_calibration_data_t)); + + + + memcpy( + &(pCalibrationData->add_off_cal_data), + &(cal_data.add_off_cal_data), + sizeof(VL53L1_additional_offset_cal_data_t)); + + + + memcpy( + &(pCalibrationData->optical_centre), + &(cal_data.optical_centre), + sizeof(VL53L1_optical_centre_t)); + + + + memcpy( + &(pCalibrationData->xtalkhisto), + &(cal_data.xtalkhisto), + sizeof(VL53L1_xtalk_histogram_data_t)); + + + memcpy( + &(pCalibrationData->gain_cal), + &(cal_data.gain_cal), + sizeof(VL53L1_gain_calibration_data_t)); + + + + memcpy( + &(pCalibrationData->cal_peak_rate_map), + &(cal_data.cal_peak_rate_map), + sizeof(VL53L1_cal_peak_rate_map_t)); + + + pC = &pCalibrationData->customer; + pC2 = &cal_data.customer; + pC->global_config__spad_enables_ref_0 = + pC2->global_config__spad_enables_ref_0; + pC->global_config__spad_enables_ref_1 = + pC2->global_config__spad_enables_ref_1; + pC->global_config__spad_enables_ref_2 = + pC2->global_config__spad_enables_ref_2; + pC->global_config__spad_enables_ref_3 = + pC2->global_config__spad_enables_ref_3; + pC->global_config__spad_enables_ref_4 = + pC2->global_config__spad_enables_ref_4; + pC->global_config__spad_enables_ref_5 = + pC2->global_config__spad_enables_ref_5; + pC->global_config__ref_en_start_select = + pC2->global_config__ref_en_start_select; + pC->ref_spad_man__num_requested_ref_spads = + pC2->ref_spad_man__num_requested_ref_spads; + pC->ref_spad_man__ref_location = + pC2->ref_spad_man__ref_location; + pC->algo__crosstalk_compensation_x_plane_gradient_kcps = + pC2->algo__crosstalk_compensation_x_plane_gradient_kcps; + pC->algo__crosstalk_compensation_y_plane_gradient_kcps = + pC2->algo__crosstalk_compensation_y_plane_gradient_kcps; + pC->ref_spad_char__total_rate_target_mcps = + pC2->ref_spad_char__total_rate_target_mcps; + pC->algo__part_to_part_range_offset_mm = + pC2->algo__part_to_part_range_offset_mm; + pC->mm_config__inner_offset_mm = + pC2->mm_config__inner_offset_mm; + pC->mm_config__outer_offset_mm = + pC2->mm_config__outer_offset_mm; + + pC->algo__crosstalk_compensation_plane_offset_kcps = + (uint32_t)( + pC2->algo__crosstalk_compensation_plane_offset_kcps); + + + PresetMode = VL53L1DevDataGet(Dev, CurrentParameters.PresetMode); + + if ((PresetMode == VL53L1_PRESETMODE_RANGING) || + (PresetMode == VL53L1_PRESETMODE_MULTIZONES_SCANNING) || + (PresetMode == VL53L1_PRESETMODE_PROXY_RANGING_MODE) + ) { + + Status = VL53L1_get_current_xtalk_settings(Dev, &xtalk); + + if (Status != VL53L1_ERROR_NONE) + goto ENDFUNC; + + tmp = xtalk.algo__crosstalk_compensation_plane_offset_kcps; + pC->algo__crosstalk_compensation_plane_offset_kcps = tmp; + tmp = xtalk.algo__crosstalk_compensation_x_plane_gradient_kcps; + pC->algo__crosstalk_compensation_x_plane_gradient_kcps = tmp; + tmp = xtalk.algo__crosstalk_compensation_y_plane_gradient_kcps; + pC->algo__crosstalk_compensation_y_plane_gradient_kcps = tmp; + } +ENDFUNC: + LOG_FUNCTION_END(Status); + return Status; +} + + +VL53L1_Error VL53L1_SetZoneCalibrationData(VL53L1_DEV Dev, + VL53L1_ZoneCalibrationData_t *pZoneCalibrationData) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + Status = VL53L1_set_zone_calibration_data(Dev, pZoneCalibrationData); + + LOG_FUNCTION_END(Status); + return Status; + +} + +VL53L1_Error VL53L1_GetZoneCalibrationData(VL53L1_DEV Dev, + VL53L1_ZoneCalibrationData_t *pZoneCalibrationData) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + Status = VL53L1_get_zone_calibration_data(Dev, pZoneCalibrationData); + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_GetOpticalCenter(VL53L1_DEV Dev, + FixPoint1616_t *pOpticalCenterX, + FixPoint1616_t *pOpticalCenterY) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + VL53L1_calibration_data_t CalibrationData; + + LOG_FUNCTION_START(""); + + *pOpticalCenterX = 0; + *pOpticalCenterY = 0; + Status = VL53L1_get_part_to_part_data(Dev, &CalibrationData); + if (Status == VL53L1_ERROR_NONE) { + *pOpticalCenterX = VL53L1_FIXPOINT44TOFIXPOINT1616( + CalibrationData.optical_centre.x_centre); + *pOpticalCenterY = VL53L1_FIXPOINT44TOFIXPOINT1616( + CalibrationData.optical_centre.y_centre); + } + + LOG_FUNCTION_END(Status); + return Status; +} + + + + + + + + +VL53L1_Error VL53L1_SetThresholdConfig(VL53L1_DEV Dev, + VL53L1_DetectionConfig_t *pConfig) +{ +#define BADTHRESBOUNDS(T) \ + (((T.CrossMode == VL53L1_THRESHOLD_OUT_OF_WINDOW) || \ + (T.CrossMode == VL53L1_THRESHOLD_IN_WINDOW)) && (T.Low > T.High)) + + VL53L1_Error Status = VL53L1_ERROR_NONE; + VL53L1_GPIO_interrupt_config_t Cfg; + uint16_t g; + FixPoint1616_t gain, high1616, low1616; + VL53L1_LLDriverData_t *pdev; + + LOG_FUNCTION_START(""); + + pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + Status = VL53L1_get_GPIO_interrupt_config(Dev, &Cfg); + if (Status == VL53L1_ERROR_NONE) { + if (pConfig->DetectionMode == VL53L1_DETECTION_NORMAL_RUN) { + Cfg.intr_new_measure_ready = 1; + Status = VL53L1_set_GPIO_interrupt_config_struct(Dev, + Cfg); + } else { + if (BADTHRESBOUNDS(pConfig->Distance)) + Status = VL53L1_ERROR_INVALID_PARAMS; + if ((Status == VL53L1_ERROR_NONE) && + (BADTHRESBOUNDS(pConfig->Rate))) + Status = VL53L1_ERROR_INVALID_PARAMS; + if (Status == VL53L1_ERROR_NONE) { + Cfg.intr_new_measure_ready = 0; + Cfg.intr_no_target = pConfig->IntrNoTarget; + + + + g = pdev->gain_cal.standard_ranging_gain_factor; + + + gain = (FixPoint1616_t) ((uint32_t)g << 5); + high1616 = (FixPoint1616_t) ((uint32_t) + pConfig->Distance.High << 16); + low1616 = (FixPoint1616_t) ((uint32_t) + pConfig->Distance.Low << 16); + + + high1616 = (high1616 + 32768) / gain; + low1616 = (low1616 + 32768) / gain; + Cfg.threshold_distance_high = (uint16_t) + (high1616 & 0xFFFF); + Cfg.threshold_distance_low = (uint16_t) + (low1616 & 0xFFFF); + + + Cfg.threshold_rate_high = + VL53L1_FIXPOINT1616TOFIXPOINT97( + pConfig->Rate.High); + Cfg.threshold_rate_low = + VL53L1_FIXPOINT1616TOFIXPOINT97( + pConfig->Rate.Low); + + Cfg.intr_mode_distance = ConvertModeToLLD( + &Status, + pConfig->Distance.CrossMode); + if (Status == VL53L1_ERROR_NONE) + Cfg.intr_mode_rate = ConvertModeToLLD( + &Status, + pConfig->Rate.CrossMode); + } + + + + if (Status == VL53L1_ERROR_NONE) { + Cfg.intr_combined_mode = 1; + switch (pConfig->DetectionMode) { + case VL53L1_DETECTION_DISTANCE_ONLY: + Cfg.threshold_rate_high = 0; + Cfg.threshold_rate_low = 0; + break; + case VL53L1_DETECTION_RATE_ONLY: + Cfg.threshold_distance_high = 0; + Cfg.threshold_distance_low = 0; + break; + case VL53L1_DETECTION_DISTANCE_OR_RATE: + + + + + break; + case VL53L1_DETECTION_DISTANCE_AND_RATE: + Cfg.intr_combined_mode = 0; + break; + default: + Status = VL53L1_ERROR_INVALID_PARAMS; + } + } + + if (Status == VL53L1_ERROR_NONE) + Status = + VL53L1_set_GPIO_interrupt_config_struct(Dev, + Cfg); + + } + } + + LOG_FUNCTION_END(Status); + return Status; +} + + +VL53L1_Error VL53L1_GetThresholdConfig(VL53L1_DEV Dev, + VL53L1_DetectionConfig_t *pConfig) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + VL53L1_GPIO_interrupt_config_t Cfg; + + LOG_FUNCTION_START(""); + + Status = VL53L1_get_GPIO_interrupt_config(Dev, &Cfg); + + if (Status != VL53L1_ERROR_NONE) { + LOG_FUNCTION_END(Status); + return Status; + } + + pConfig->IntrNoTarget = Cfg.intr_no_target; + pConfig->Distance.High = Cfg.threshold_distance_high; + pConfig->Distance.Low = Cfg.threshold_distance_low; + pConfig->Rate.High = + VL53L1_FIXPOINT97TOFIXPOINT1616( + Cfg.threshold_rate_high); + pConfig->Rate.Low = + VL53L1_FIXPOINT97TOFIXPOINT1616(Cfg.threshold_rate_low); + pConfig->Distance.CrossMode = + ConvertModeFromLLD(&Status, Cfg.intr_mode_distance); + if (Status == VL53L1_ERROR_NONE) + pConfig->Rate.CrossMode = + ConvertModeFromLLD(&Status, Cfg.intr_mode_rate); + + if (Cfg.intr_new_measure_ready == 1) { + pConfig->DetectionMode = VL53L1_DETECTION_NORMAL_RUN; + } else { + + + if (Status == VL53L1_ERROR_NONE) { + if (Cfg.intr_combined_mode == 0) + pConfig->DetectionMode = + VL53L1_DETECTION_DISTANCE_AND_RATE; + else { + if ((Cfg.threshold_distance_high == 0) && + (Cfg.threshold_distance_low == 0)) + pConfig->DetectionMode = + VL53L1_DETECTION_RATE_ONLY; + else if ((Cfg.threshold_rate_high == 0) && + (Cfg.threshold_rate_low == 0)) + pConfig->DetectionMode = + VL53L1_DETECTION_DISTANCE_ONLY; + else + pConfig->DetectionMode = + VL53L1_DETECTION_DISTANCE_OR_RATE; + } + } + } + + LOG_FUNCTION_END(Status); + return Status; +} + + + + + + diff --git a/drivers/input/misc/vl53L1/lito/src/vl53l1_api_calibration.c b/drivers/input/misc/vl53L1/lito/src/vl53l1_api_calibration.c new file mode 100644 index 000000000000..b3b1a98a20ae --- /dev/null +++ b/drivers/input/misc/vl53L1/lito/src/vl53l1_api_calibration.c @@ -0,0 +1,2765 @@ + +/******************************************************************************* + * Copyright (c) 2017, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#include "vl53l1_ll_def.h" +#include "vl53l1_ll_device.h" +#include "vl53l1_platform.h" +#include "vl53l1_platform_ipp.h" +#include "vl53l1_register_map.h" +#include "vl53l1_register_funcs.h" +#include "vl53l1_register_settings.h" +#include "vl53l1_hist_map.h" +#include "vl53l1_hist_structs.h" +#include "vl53l1_core.h" +#include "vl53l1_wait.h" +#include "vl53l1_api_preset_modes.h" +#include "vl53l1_silicon_core.h" +#include "vl53l1_api_core.h" +#include "vl53l1_api_calibration.h" + +#ifdef VL53L1_LOG_ENABLE + #include "vl53l1_api_debug.h" +#endif + + + + +#define LOG_FUNCTION_START(fmt, ...) \ + _LOG_FUNCTION_START(VL53L1_TRACE_MODULE_CORE, fmt, ##__VA_ARGS__) +#define LOG_FUNCTION_END(status, ...) \ + _LOG_FUNCTION_END(VL53L1_TRACE_MODULE_CORE, status, ##__VA_ARGS__) +#define LOG_FUNCTION_END_FMT(status, fmt, ...) \ + _LOG_FUNCTION_END_FMT(VL53L1_TRACE_MODULE_CORE, status, \ + fmt, ##__VA_ARGS__) + +#define trace_print(level, ...) \ + _LOG_TRACE_PRINT(VL53L1_TRACE_MODULE_CORE, \ + level, VL53L1_TRACE_FUNCTION_NONE, ##__VA_ARGS__) + + +VL53L1_Error VL53L1_run_ref_spad_char( + VL53L1_DEV Dev, + VL53L1_Error *pcal_status) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + uint8_t comms_buffer[6]; + + VL53L1_refspadchar_config_t *prefspadchar = &(pdev->refspadchar); + + LOG_FUNCTION_START(""); + + + + + + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_enable_powerforce(Dev); + + + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_set_ref_spad_char_config( + Dev, + prefspadchar->VL53L1_p_009, + prefspadchar->timeout_us, + prefspadchar->target_count_rate_mcps, + prefspadchar->max_count_rate_limit_mcps, + prefspadchar->min_count_rate_limit_mcps, + pdev->stat_nvm.osc_measured__fast_osc__frequency); + + + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_run_device_test( + Dev, + prefspadchar->device_test_mode); + + + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_ReadMulti( + Dev, + VL53L1_REF_SPAD_CHAR_RESULT__NUM_ACTUAL_REF_SPADS, + comms_buffer, + 2); + + if (status == VL53L1_ERROR_NONE) { + pdev->dbg_results.ref_spad_char_result__num_actual_ref_spads = + comms_buffer[0]; + pdev->dbg_results.ref_spad_char_result__ref_location = + comms_buffer[1]; + } + + + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_WriteMulti( + Dev, + VL53L1_REF_SPAD_MAN__NUM_REQUESTED_REF_SPADS, + comms_buffer, + 2); + + if (status == VL53L1_ERROR_NONE) { + pdev->customer.ref_spad_man__num_requested_ref_spads = + comms_buffer[0]; + pdev->customer.ref_spad_man__ref_location = + comms_buffer[1]; + } + + + + + + + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_ReadMulti( + Dev, + VL53L1_RESULT__SPARE_0_SD1, + comms_buffer, + 6); + + + + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_WriteMulti( + Dev, + VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_REF_0, + comms_buffer, + 6); + + if (status == VL53L1_ERROR_NONE) { + pdev->customer.global_config__spad_enables_ref_0 = + comms_buffer[0]; + pdev->customer.global_config__spad_enables_ref_1 = + comms_buffer[1]; + pdev->customer.global_config__spad_enables_ref_2 = + comms_buffer[2]; + pdev->customer.global_config__spad_enables_ref_3 = + comms_buffer[3]; + pdev->customer.global_config__spad_enables_ref_4 = + comms_buffer[4]; + pdev->customer.global_config__spad_enables_ref_5 = + comms_buffer[5]; + } + +#ifdef VL53L1_LOG_ENABLE + + + if (status == VL53L1_ERROR_NONE) + VL53L1_print_customer_nvm_managed( + &(pdev->customer), + "run_ref_spad_char():pdev->lldata.customer.", + VL53L1_TRACE_MODULE_REF_SPAD_CHAR); +#endif + + if (status == VL53L1_ERROR_NONE) { + + switch (pdev->sys_results.result__range_status) { + + case VL53L1_DEVICEERROR_REFSPADCHARNOTENOUGHDPADS: + status = VL53L1_WARNING_REF_SPAD_CHAR_NOT_ENOUGH_SPADS; + break; + + case VL53L1_DEVICEERROR_REFSPADCHARMORETHANTARGET: + status = VL53L1_WARNING_REF_SPAD_CHAR_RATE_TOO_HIGH; + break; + + case VL53L1_DEVICEERROR_REFSPADCHARLESSTHANTARGET: + status = VL53L1_WARNING_REF_SPAD_CHAR_RATE_TOO_LOW; + break; + } + } + + + + + + + *pcal_status = status; + + + + + IGNORE_STATUS( + IGNORE_REF_SPAD_CHAR_NOT_ENOUGH_SPADS, + VL53L1_WARNING_REF_SPAD_CHAR_NOT_ENOUGH_SPADS, + status); + + IGNORE_STATUS( + IGNORE_REF_SPAD_CHAR_RATE_TOO_HIGH, + VL53L1_WARNING_REF_SPAD_CHAR_RATE_TOO_HIGH, + status); + + IGNORE_STATUS( + IGNORE_REF_SPAD_CHAR_RATE_TOO_LOW, + VL53L1_WARNING_REF_SPAD_CHAR_RATE_TOO_LOW, + status); + + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_run_xtalk_extraction( + VL53L1_DEV Dev, + VL53L1_Error *pcal_status) +{ + + + + + + + + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + + + + + + + VL53L1_xtalkextract_config_t *pX = &(pdev->xtalk_extract_cfg); + VL53L1_xtalk_config_t *pC = &(pdev->xtalk_cfg); + VL53L1_xtalk_calibration_results_t *pXC = &(pdev->xtalk_cal); + + uint8_t results_invalid = 0; + + uint8_t i = 0; + uint16_t tmp16 = 0; + + uint8_t measurement_mode = VL53L1_DEVICEMEASUREMENTMODE_BACKTOBACK; + + LOG_FUNCTION_START(""); + + + + + + + + VL53L1_init_histogram_bin_data_struct( + 0, + (uint16_t)VL53L1_HISTOGRAM_BUFFER_SIZE, + &(pdev->xtalk_results.central_histogram_avg)); + + VL53L1_init_histogram_bin_data_struct( + 0, + (uint16_t)VL53L1_HISTOGRAM_BUFFER_SIZE, + &(pdev->xtalk_results.central_histogram_sum)); + + + + + + + + + + + + if (status == VL53L1_ERROR_NONE) + + status = + VL53L1_set_preset_mode( + Dev, + VL53L1_DEVICEPRESETMODE_HISTOGRAM_XTALK_PLANAR, + + + pX->dss_config__target_total_rate_mcps, + pX->phasecal_config_timeout_us, + pX->mm_config_timeout_us, + pX->range_config_timeout_us, + + + 100); + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_disable_xtalk_compensation(Dev); + + + + + + + pdev->xtalk_results.max_results = VL53L1_MAX_XTALK_RANGE_RESULTS; + pdev->xtalk_results.active_results = pdev->zone_cfg.active_zones+1; + + + + + pdev->xtalk_results.central_histogram__window_start = 0xFF; + pdev->xtalk_results.central_histogram__window_end = 0x00; + + pdev->xtalk_results.num_of_samples_status = 0x00; + pdev->xtalk_results.zero_samples_status = 0x00; + pdev->xtalk_results.max_sigma_status = 0x00; + + for (i = 0; i < pdev->xtalk_results.max_results; i++) { + pdev->xtalk_results.VL53L1_p_002[i].no_of_samples = 0; + pdev->xtalk_results.VL53L1_p_002[i].signal_total_events_avg = 0; + pdev->xtalk_results.VL53L1_p_002[i].signal_total_events_sum = 0; + pdev->xtalk_results.VL53L1_p_002[i].rate_per_spad_kcps_sum = 0; + pdev->xtalk_results.VL53L1_p_002[i].rate_per_spad_kcps_avg = 0; + pdev->xtalk_results.VL53L1_p_002[i].sigma_mm_sum = 0; + pdev->xtalk_results.VL53L1_p_002[i].sigma_mm_avg = 0; + + + pdev->xtalk_results.VL53L1_p_002[i].median_phase_sum = 0; + pdev->xtalk_results.VL53L1_p_002[i].median_phase_avg = 0; + + + } + + + + if (status == VL53L1_ERROR_NONE) { + + status = + VL53L1_get_and_avg_xtalk_samples( + Dev, + + + pX->num_of_samples, + + + measurement_mode, + + + pX->algo__crosstalk_extract_max_valid_range_mm, + pX->algo__crosstalk_extract_min_valid_range_mm, + pX->algo__crosstalk_extract_max_valid_rate_kcps, + + + 0x0, + + 0x4, + + &(pdev->xtalk_results), + &(pdev->xtalk_results.central_histogram_sum), + &(pdev->xtalk_results.central_histogram_avg)); + } + + + + + + + + + + + + + + if (status == VL53L1_ERROR_NONE) + if ((pdev->xtalk_results.VL53L1_p_002[4].no_of_samples == 0) || + (pdev->xtalk_results.VL53L1_p_002[4].sigma_mm_avg > + ((uint32_t)pX->algo__crosstalk_extract_max_sigma_mm + << 5))) + results_invalid = 0x01; + + + + +#ifdef VL53L1_LOG_ENABLE + if (status == VL53L1_ERROR_NONE) + VL53L1_print_xtalk_range_results( + &(pdev->xtalk_results), + "pdev->xtalk_results", + VL53L1_TRACE_MODULE_CORE); +#endif + + if ((status == VL53L1_ERROR_NONE) && (results_invalid == 0)) { + + status = + VL53L1_ipp_xtalk_calibration_process_data( + Dev, + &(pdev->xtalk_results), + &(pdev->xtalk_shapes), + &(pdev->xtalk_cal)); + + if (status == VL53L1_ERROR_NONE) { + + pC->algo__crosstalk_compensation_x_plane_gradient_kcps = + pXC->algo__crosstalk_compensation_x_plane_gradient_kcps; + pC->algo__crosstalk_compensation_y_plane_gradient_kcps = + pXC->algo__crosstalk_compensation_y_plane_gradient_kcps; + pC->algo__crosstalk_compensation_plane_offset_kcps = + pXC->algo__crosstalk_compensation_plane_offset_kcps; + + + } + + + } + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_xtalk_compensation(Dev); + + + + + + if (status == VL53L1_ERROR_NONE) { + + for (i = 0; i < pdev->xtalk_results.max_results; i++) { + + + if (pdev->xtalk_results.VL53L1_p_002[i].no_of_samples != + + + pX->num_of_samples) { + + + pdev->xtalk_results.num_of_samples_status = + pdev->xtalk_results.num_of_samples_status | + (1 << i); + } + + + if (pdev->xtalk_results.VL53L1_p_002[i].no_of_samples == + 0x00) { + pdev->xtalk_results.zero_samples_status = + pdev->xtalk_results.zero_samples_status | + (1 << i); + } + + + + + + + + + + + + + tmp16 = pX->algo__crosstalk_extract_max_sigma_mm; + if (pdev->xtalk_results.VL53L1_p_002[i].sigma_mm_avg > + ((uint32_t)tmp16 << 5)) { + pdev->xtalk_results.max_sigma_status = + pdev->xtalk_results.max_sigma_status | + (1 << i); + } + + + } + } + + + + + + + + + + + + + + if (results_invalid > 0) { + + + if (pdev->xtalk_results.VL53L1_p_002[4].no_of_samples == 0) { + status = VL53L1_ERROR_XTALK_EXTRACTION_NO_SAMPLE_FAIL; + } else { + + + + if (pdev->xtalk_results.VL53L1_p_002[4].sigma_mm_avg > + (((uint32_t)pX->algo__crosstalk_extract_max_sigma_mm) + << 5)) { + status = + VL53L1_ERROR_XTALK_EXTRACTION_SIGMA_LIMIT_FAIL; + } + + + } + } else { + + + if (pdev->xtalk_results.zero_samples_status != 0x00) { + status = VL53L1_WARNING_XTALK_NO_SAMPLES_FOR_GRADIENT; + } else { + if (pdev->xtalk_results.max_sigma_status != 0x00) { + status = + VL53L1_WARNING_XTALK_SIGMA_LIMIT_FOR_GRADIENT; + } else { + if (pdev->xtalk_results.num_of_samples_status != + 0x00) + status = + VL53L1_WARNING_XTALK_MISSING_SAMPLES; + } + } + } + + + + + + + pdev->xtalk_results.cal_status = status; + *pcal_status = pdev->xtalk_results.cal_status; + + + + + IGNORE_STATUS( + IGNORE_XTALK_EXTRACTION_NO_SAMPLE_FAIL, + VL53L1_ERROR_XTALK_EXTRACTION_NO_SAMPLE_FAIL, + status); + + IGNORE_STATUS( + IGNORE_XTALK_EXTRACTION_SIGMA_LIMIT_FAIL, + VL53L1_ERROR_XTALK_EXTRACTION_SIGMA_LIMIT_FAIL, + status); + + IGNORE_STATUS( + IGNORE_XTALK_EXTRACTION_NO_SAMPLE_FOR_GRADIENT_WARN, + VL53L1_WARNING_XTALK_NO_SAMPLES_FOR_GRADIENT, + status); + + IGNORE_STATUS( + IGNORE_XTALK_EXTRACTION_SIGMA_LIMIT_FOR_GRADIENT_WARN, + VL53L1_WARNING_XTALK_SIGMA_LIMIT_FOR_GRADIENT, + status); + + IGNORE_STATUS( + IGNORE_XTALK_EXTRACTION_MISSING_SAMPLES_WARN, + VL53L1_WARNING_XTALK_MISSING_SAMPLES, + status); + +#ifdef VL53L1_LOG_ENABLE + + + + + VL53L1_print_customer_nvm_managed( + &(pdev->customer), + "run_xtalk_extraction():pdev->lldata.customer.", + VL53L1_TRACE_MODULE_XTALK_DATA); + + VL53L1_print_xtalk_config( + &(pdev->xtalk_cfg), + "run_xtalk_extraction():pdev->lldata.xtalk_cfg.", + VL53L1_TRACE_MODULE_XTALK_DATA); + + VL53L1_print_xtalk_extract_config( + &(pdev->xtalk_extract_cfg), + "run_xtalk_extraction():pdev->lldata.xtalk_extract_cfg.", + VL53L1_TRACE_MODULE_XTALK_DATA); + + VL53L1_print_histogram_bin_data( + &(pdev->hist_data), + "run_xtalk_extraction():pdev->lldata.hist_data.", + VL53L1_TRACE_MODULE_XTALK_DATA); + + VL53L1_print_xtalk_histogram_data( + &(pdev->xtalk_shapes), + "pdev->lldata.xtalk_shapes.", + VL53L1_TRACE_MODULE_XTALK_DATA); + + VL53L1_print_xtalk_range_results( + &(pdev->xtalk_results), + "run_xtalk_extraction():pdev->lldata.xtalk_results.", + VL53L1_TRACE_MODULE_XTALK_DATA); + +#endif + + LOG_FUNCTION_END(status); + + return status; + +} + + + +VL53L1_Error VL53L1_get_and_avg_xtalk_samples( + VL53L1_DEV Dev, + uint8_t num_of_samples, + uint8_t measurement_mode, + int16_t xtalk_filter_thresh_max_mm, + int16_t xtalk_filter_thresh_min_mm, + uint16_t xtalk_max_valid_rate_kcps, + uint8_t xtalk_result_id, + uint8_t xtalk_histo_id, + VL53L1_xtalk_range_results_t *pXR, + VL53L1_histogram_bin_data_t *psum_histo, + VL53L1_histogram_bin_data_t *pavg_histo) +{ + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + +#ifdef VL53L1_LOG_ENABLE + VL53L1_LLDriverResults_t *pres = + VL53L1DevStructGetLLResultsHandle(Dev); +#endif + + VL53L1_range_results_t range_results; + VL53L1_range_results_t *prs = &range_results; + + VL53L1_range_data_t *prange_data; + VL53L1_xtalk_range_data_t *pxtalk_range_data; + + uint8_t i = 0; + uint8_t j = 0; + uint8_t zone_id = 0; + uint8_t final_zone = pdev->zone_cfg.active_zones+1; + uint8_t valid_result; + + uint8_t smudge_corr_en = 0; + + + + + + + smudge_corr_en = pdev->smudge_correct_config.smudge_corr_enabled; + + status = VL53L1_dynamic_xtalk_correction_disable(Dev); + + + + + + + if (status == VL53L1_ERROR_NONE) + + status = + VL53L1_init_and_start_range( + Dev, + measurement_mode, + VL53L1_DEVICECONFIGLEVEL_CUSTOMER_ONWARDS); + + + for (i = 0; i <= (final_zone*num_of_samples); i++) { + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_wait_for_range_completion(Dev); + + + + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_get_device_results( + Dev, + VL53L1_DEVICERESULTSLEVEL_FULL, + prs); + + + + + + + if (status == VL53L1_ERROR_NONE && + pdev->ll_state.rd_device_state != + VL53L1_DEVICESTATE_RANGING_WAIT_GPH_SYNC) { + + zone_id = pdev->ll_state.rd_zone_id + xtalk_result_id; + prange_data = &(prs->VL53L1_p_002[0]); + + + + if (prs->active_results > 1) { + for (j = 1; + j < prs->active_results; j++) { + if (prs->VL53L1_p_002[j].median_range_mm + < + prange_data->median_range_mm) + prange_data = + &(prs->VL53L1_p_002[j]); + + } + } + + pxtalk_range_data = &(pXR->VL53L1_p_002[zone_id]); + + + + + if ((prs->active_results > 0) && + (prange_data->median_range_mm < + xtalk_filter_thresh_max_mm) && + (prange_data->median_range_mm > + xtalk_filter_thresh_min_mm) && + (prange_data->VL53L1_p_012 < + (uint32_t)(xtalk_max_valid_rate_kcps * 16))) + valid_result = 1; + else + valid_result = 0; + + if (valid_result == 1) { + + pxtalk_range_data->no_of_samples++; + + pxtalk_range_data->rate_per_spad_kcps_sum += + prange_data->VL53L1_p_012; + + pxtalk_range_data->signal_total_events_sum += + prange_data->VL53L1_p_013; + + pxtalk_range_data->sigma_mm_sum += + (uint32_t)prange_data->VL53L1_p_005; + + + + + pxtalk_range_data->median_phase_sum += + (uint32_t)prange_data->VL53L1_p_014; + + + + + + + + + + + } + + if ((valid_result == 1) && (zone_id >= 4)) { + status = VL53L1_sum_histogram_data( + &(pdev->hist_data), + psum_histo); + + + + + + if (prange_data->VL53L1_p_015 < + pXR->central_histogram__window_start) + pXR->central_histogram__window_start = + prange_data->VL53L1_p_015; + + + + if (prange_data->VL53L1_p_016 > + pXR->central_histogram__window_end) + pXR->central_histogram__window_end = + prange_data->VL53L1_p_016; + + } + + } + + + + + + + +#ifdef VL53L1_LOG_ENABLE + if (status == VL53L1_ERROR_NONE) { + VL53L1_print_range_results( + &(pres->range_results), + "pres->range_results.", + VL53L1_TRACE_MODULE_CORE); + } +#endif + + + + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_wait_for_firmware_ready(Dev); + + + + + + + + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_clear_interrupt_and_enable_next_range( + Dev, + measurement_mode); + + + } + + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_stop_range(Dev); + + + + + + for (i = 0; i < (pdev->zone_cfg.active_zones+1); i++) { + + pxtalk_range_data = &(pXR->VL53L1_p_002[i+xtalk_result_id]); + + if (pxtalk_range_data->no_of_samples > 0) { + pxtalk_range_data->rate_per_spad_kcps_avg = + pxtalk_range_data->rate_per_spad_kcps_sum / + (uint32_t)pxtalk_range_data->no_of_samples; + + pxtalk_range_data->signal_total_events_avg = + pxtalk_range_data->signal_total_events_sum / + (int32_t)pxtalk_range_data->no_of_samples; + + pxtalk_range_data->sigma_mm_avg = + pxtalk_range_data->sigma_mm_sum / + (uint32_t)pxtalk_range_data->no_of_samples; + + + + + pxtalk_range_data->median_phase_avg = + pxtalk_range_data->median_phase_sum / + (uint32_t)pxtalk_range_data->no_of_samples; + + + + + } else { + pxtalk_range_data->rate_per_spad_kcps_avg = + pxtalk_range_data->rate_per_spad_kcps_sum; + pxtalk_range_data->signal_total_events_avg = + pxtalk_range_data->signal_total_events_sum; + pxtalk_range_data->sigma_mm_avg = + pxtalk_range_data->sigma_mm_sum; + + + + + pxtalk_range_data->median_phase_avg = + pxtalk_range_data->median_phase_sum; + + + + } + } + + + + + memcpy(pavg_histo, &(pdev->hist_data), + sizeof(VL53L1_histogram_bin_data_t)); + + + + + if (status == VL53L1_ERROR_NONE) { + + pxtalk_range_data = &(pXR->VL53L1_p_002[xtalk_histo_id]); + + status = VL53L1_avg_histogram_data( + pxtalk_range_data->no_of_samples, + psum_histo, + pavg_histo); + } + + + + + + + if (status == VL53L1_ERROR_NONE) { + if (smudge_corr_en == 1) + status = VL53L1_dynamic_xtalk_correction_enable(Dev); + } + + + + LOG_FUNCTION_END(status); + + return status; + +} + + + +VL53L1_Error VL53L1_run_offset_calibration( + VL53L1_DEV Dev, + int16_t cal_distance_mm, + uint16_t cal_reflectance_pc, + VL53L1_Error *pcal_status) +{ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + + VL53L1_DevicePresetModes device_preset_modes[ + VL53L1_MAX_OFFSET_RANGE_RESULTS]; + + VL53L1_range_results_t range_results; + VL53L1_range_results_t *prange_results = &range_results; + VL53L1_range_data_t *pRData = NULL; + VL53L1_offset_range_data_t *pfs = NULL; + VL53L1_general_config_t *pG = &(pdev->gen_cfg); + VL53L1_additional_offset_cal_data_t *pAO = &(pdev->add_off_cal_data); + + uint8_t i = 0; + uint8_t m = 0; + uint8_t measurement_mode = + VL53L1_DEVICEMEASUREMENTMODE_BACKTOBACK; + uint16_t manual_effective_spads = + pG->dss_config__manual_effective_spads_select; + + uint8_t num_of_samples[VL53L1_MAX_OFFSET_RANGE_RESULTS]; + + uint8_t smudge_corr_en = 0; + + LOG_FUNCTION_START(""); + + + + + switch (pdev->offset_calibration_mode) { + + case VL53L1_OFFSETCALIBRATIONMODE__MM1_MM2__HISTOGRAM: + case VL53L1_OFFSETCALIBRATIONMODE__MM1_MM2__HISTOGRAM_PRE_RANGE_ONLY: + device_preset_modes[0] = + VL53L1_DEVICEPRESETMODE_HISTOGRAM_RANGING; + device_preset_modes[1] = + VL53L1_DEVICEPRESETMODE_HISTOGRAM_RANGING_MM1_CAL; + device_preset_modes[2] = + VL53L1_DEVICEPRESETMODE_HISTOGRAM_RANGING_MM2_CAL; + break; + + default: + device_preset_modes[0] = + VL53L1_DEVICEPRESETMODE_STANDARD_RANGING; + device_preset_modes[1] = + VL53L1_DEVICEPRESETMODE_STANDARD_RANGING_MM1_CAL; + device_preset_modes[2] = + VL53L1_DEVICEPRESETMODE_STANDARD_RANGING_MM2_CAL; + break; + } + + + + + + num_of_samples[0] = pdev->offsetcal_cfg.pre_num_of_samples; + num_of_samples[1] = pdev->offsetcal_cfg.mm1_num_of_samples; + num_of_samples[2] = pdev->offsetcal_cfg.mm2_num_of_samples; + + + + + + + switch (pdev->offset_calibration_mode) { + + case VL53L1_OFFSETCALIBRATIONMODE__MM1_MM2__STANDARD_PRE_RANGE_ONLY: + case VL53L1_OFFSETCALIBRATIONMODE__MM1_MM2__HISTOGRAM_PRE_RANGE_ONLY: + + + pdev->offset_results.active_results = 1; + + break; + + default: + + pdev->customer.mm_config__inner_offset_mm = 0; + pdev->customer.mm_config__outer_offset_mm = 0; + pdev->offset_results.active_results = + VL53L1_MAX_OFFSET_RANGE_RESULTS; + + break; + } + + pdev->customer.algo__part_to_part_range_offset_mm = 0; + + + + + pdev->offset_results.max_results = VL53L1_MAX_OFFSET_RANGE_RESULTS; + pdev->offset_results.cal_distance_mm = cal_distance_mm; + pdev->offset_results.cal_reflectance_pc = cal_reflectance_pc; + + for (m = 0; m < VL53L1_MAX_OFFSET_RANGE_RESULTS; m++) { + + pfs = &(pdev->offset_results.VL53L1_p_002[m]); + pfs->preset_mode = 0; + pfs->no_of_samples = 0; + pfs->effective_spads = 0; + pfs->peak_rate_mcps = 0; + pfs->VL53L1_p_005 = 0; + pfs->median_range_mm = 0; + } + + + + + + + smudge_corr_en = pdev->smudge_correct_config.smudge_corr_enabled; + + status = VL53L1_dynamic_xtalk_correction_disable(Dev); + + + + + for (m = 0; m < pdev->offset_results.active_results; m++) { + + pfs = &(pdev->offset_results.VL53L1_p_002[m]); + + pfs->preset_mode = device_preset_modes[m]; + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_set_preset_mode( + Dev, + device_preset_modes[m], + + + pdev->offsetcal_cfg.dss_config__target_total_rate_mcps, + pdev->offsetcal_cfg.phasecal_config_timeout_us, + pdev->offsetcal_cfg.mm_config_timeout_us, + pdev->offsetcal_cfg.range_config_timeout_us, + + + 100); + + pG->dss_config__manual_effective_spads_select = + manual_effective_spads; + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_init_and_start_range( + Dev, + measurement_mode, + VL53L1_DEVICECONFIGLEVEL_CUSTOMER_ONWARDS); + + for (i = 0; i <= (num_of_samples[m]+2); i++) { + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_wait_for_range_completion(Dev); + + + + + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_get_device_results( + Dev, + VL53L1_DEVICERESULTSLEVEL_FULL, + prange_results); + + + + + + + + + + pRData = &(prange_results->VL53L1_p_002[0]); + + if ((prange_results->active_results > 0 && + prange_results->stream_count > 1) && + (pRData->range_status == + VL53L1_DEVICEERROR_RANGECOMPLETE)) { + + pfs->no_of_samples++; + pfs->effective_spads += + (uint32_t)pRData->VL53L1_p_006; + pfs->peak_rate_mcps += + (uint32_t)pRData->peak_signal_count_rate_mcps; + pfs->VL53L1_p_005 += + (uint32_t)pRData->VL53L1_p_005; + pfs->median_range_mm += + (int32_t)pRData->median_range_mm; + + pfs->dss_config__roi_mode_control = + pG->dss_config__roi_mode_control; + pfs->dss_config__manual_effective_spads_select = + pG->dss_config__manual_effective_spads_select; + + } + + + + + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_wait_for_firmware_ready(Dev); + + + + + + + + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_clear_interrupt_and_enable_next_range( + Dev, + measurement_mode); + } + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_stop_range(Dev); + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WaitUs(Dev, 1000); + + + + if (pfs->no_of_samples > 0) { + + pfs->effective_spads += (pfs->no_of_samples/2); + pfs->effective_spads /= pfs->no_of_samples; + + pfs->peak_rate_mcps += (pfs->no_of_samples/2); + pfs->peak_rate_mcps /= pfs->no_of_samples; + + pfs->VL53L1_p_005 += (pfs->no_of_samples/2); + pfs->VL53L1_p_005 /= pfs->no_of_samples; + + pfs->median_range_mm += (pfs->no_of_samples/2); + pfs->median_range_mm /= pfs->no_of_samples; + + pfs->range_mm_offset = (int32_t)cal_distance_mm; + pfs->range_mm_offset -= pfs->median_range_mm; + + + + if (pfs->preset_mode == + VL53L1_DEVICEPRESETMODE_STANDARD_RANGING) + manual_effective_spads = + (uint16_t)pfs->effective_spads; + } + } + + + + + switch (pdev->offset_calibration_mode) { + + case VL53L1_OFFSETCALIBRATIONMODE__MM1_MM2__STANDARD_PRE_RANGE_ONLY: + case VL53L1_OFFSETCALIBRATIONMODE__MM1_MM2__HISTOGRAM_PRE_RANGE_ONLY: + + + + pdev->customer.mm_config__inner_offset_mm += + (int16_t)pdev->offset_results.VL53L1_p_002[0].range_mm_offset; + pdev->customer.mm_config__outer_offset_mm += + (int16_t)pdev->offset_results.VL53L1_p_002[0].range_mm_offset; + break; + + default: + + + pdev->customer.mm_config__inner_offset_mm = + (int16_t)pdev->offset_results.VL53L1_p_002[1].range_mm_offset; + pdev->customer.mm_config__outer_offset_mm = + (int16_t)pdev->offset_results.VL53L1_p_002[2].range_mm_offset; + pdev->customer.algo__part_to_part_range_offset_mm = 0; + + + + + + pAO->result__mm_inner_actual_effective_spads = + (uint16_t)pdev->offset_results.VL53L1_p_002[1].effective_spads; + pAO->result__mm_outer_actual_effective_spads = + (uint16_t)pdev->offset_results.VL53L1_p_002[2].effective_spads; + + pAO->result__mm_inner_peak_signal_count_rtn_mcps = + (uint16_t)pdev->offset_results.VL53L1_p_002[1].peak_rate_mcps; + pAO->result__mm_outer_peak_signal_count_rtn_mcps = + (uint16_t)pdev->offset_results.VL53L1_p_002[2].peak_rate_mcps; + + break; + } + + + + + + + + pdev->cust_dmax_cal.ref__actual_effective_spads = + (uint16_t)pdev->offset_results.VL53L1_p_002[0].effective_spads; + pdev->cust_dmax_cal.ref__peak_signal_count_rate_mcps = + (uint16_t)pdev->offset_results.VL53L1_p_002[0].peak_rate_mcps; + + + + pdev->cust_dmax_cal.ref__distance_mm = cal_distance_mm * 16; + + pdev->cust_dmax_cal.ref_reflectance_pc = cal_reflectance_pc; + pdev->cust_dmax_cal.coverglass_transmission = 0x0100; + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_set_customer_nvm_managed( + Dev, + &(pdev->customer)); + + + + + + + if (status == VL53L1_ERROR_NONE) { + if (smudge_corr_en == 1) + status = VL53L1_dynamic_xtalk_correction_enable(Dev); + } + + + + + + + + + for (m = 0; m < pdev->offset_results.active_results; m++) { + + pfs = &(pdev->offset_results.VL53L1_p_002[m]); + + if (status == VL53L1_ERROR_NONE) { + + pdev->offset_results.cal_report = m; + + if (pfs->no_of_samples < num_of_samples[m]) + status = + VL53L1_WARNING_OFFSET_CAL_MISSING_SAMPLES; + + + + + + + if (m == 0 && pfs->VL53L1_p_005 > + ((uint32_t)VL53L1_OFFSET_CAL_MAX_SIGMA_MM << 5)) + status = + VL53L1_WARNING_OFFSET_CAL_SIGMA_TOO_HIGH; + + if (pfs->peak_rate_mcps > + VL53L1_OFFSET_CAL_MAX_PRE_PEAK_RATE_MCPS) + status = + VL53L1_WARNING_OFFSET_CAL_RATE_TOO_HIGH; + + if (pfs->dss_config__manual_effective_spads_select < + VL53L1_OFFSET_CAL_MIN_EFFECTIVE_SPADS) + status = + VL53L1_WARNING_OFFSET_CAL_SPAD_COUNT_TOO_LOW; + + if (pfs->dss_config__manual_effective_spads_select == 0) + status = + VL53L1_ERROR_OFFSET_CAL_NO_SPADS_ENABLED_FAIL; + + if (pfs->no_of_samples == 0) + status = VL53L1_ERROR_OFFSET_CAL_NO_SAMPLE_FAIL; + } + } + + + + + + + pdev->offset_results.cal_status = status; + *pcal_status = pdev->offset_results.cal_status; + + + + + IGNORE_STATUS( + IGNORE_OFFSET_CAL_MISSING_SAMPLES, + VL53L1_WARNING_OFFSET_CAL_MISSING_SAMPLES, + status); + + IGNORE_STATUS( + IGNORE_OFFSET_CAL_SIGMA_TOO_HIGH, + VL53L1_WARNING_OFFSET_CAL_SIGMA_TOO_HIGH, + status); + + IGNORE_STATUS( + IGNORE_OFFSET_CAL_RATE_TOO_HIGH, + VL53L1_WARNING_OFFSET_CAL_RATE_TOO_HIGH, + status); + + IGNORE_STATUS( + IGNORE_OFFSET_CAL_SPAD_COUNT_TOO_LOW, + VL53L1_WARNING_OFFSET_CAL_SPAD_COUNT_TOO_LOW, + status); + +#ifdef VL53L1_LOG_ENABLE + + + + + VL53L1_print_customer_nvm_managed( + &(pdev->customer), + "run_offset_calibration():pdev->lldata.customer.", + VL53L1_TRACE_MODULE_OFFSET_DATA); + + VL53L1_print_dmax_calibration_data( + &(pdev->fmt_dmax_cal), + "run_offset_calibration():pdev->lldata.fmt_dmax_cal.", + VL53L1_TRACE_MODULE_OFFSET_DATA); + + VL53L1_print_dmax_calibration_data( + &(pdev->cust_dmax_cal), + "run_offset_calibration():pdev->lldata.cust_dmax_cal.", + VL53L1_TRACE_MODULE_OFFSET_DATA); + + VL53L1_print_additional_offset_cal_data( + &(pdev->add_off_cal_data), + "run_offset_calibration():pdev->lldata.add_off_cal_data.", + VL53L1_TRACE_MODULE_OFFSET_DATA); + + VL53L1_print_offset_range_results( + &(pdev->offset_results), + "run_offset_calibration():pdev->lldata.offset_results.", + VL53L1_TRACE_MODULE_OFFSET_DATA); +#endif + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_run_phasecal_average( + VL53L1_DEV Dev, + uint8_t measurement_mode, + uint8_t phasecal_result__vcsel_start, + uint16_t phasecal_num_of_samples, + VL53L1_range_results_t *prange_results, + uint16_t *pphasecal_result__reference_phase, + uint16_t *pzero_distance_phase) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + + uint16_t i = 0; + uint16_t m = 0; + uint32_t samples = 0; + + uint32_t period = 0; + uint32_t VL53L1_p_017 = 0; + uint32_t phasecal_result__reference_phase = 0; + uint32_t zero_distance_phase = 0; + + + + + for (m = 0; m < phasecal_num_of_samples; m++) { + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_init_and_start_range( + Dev, + measurement_mode, + VL53L1_DEVICECONFIGLEVEL_CUSTOMER_ONWARDS); + + for (i = 0; i <= 1; i++) { + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_wait_for_range_completion(Dev); + + + + + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_get_device_results( + Dev, + VL53L1_DEVICERESULTSLEVEL_FULL, + prange_results); + + + + + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_wait_for_firmware_ready(Dev); + + + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_clear_interrupt_and_enable_next_range( + Dev, + measurement_mode); + } + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_stop_range(Dev); + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WaitUs(Dev, 1000); + + + + + if (status == VL53L1_ERROR_NONE) { + + samples++; + + + + + + + + period = 2048 * + (uint32_t)VL53L1_decode_vcsel_period( + pdev->hist_data.VL53L1_p_009); + + VL53L1_p_017 = period; + VL53L1_p_017 += (uint32_t)( + pdev->hist_data.phasecal_result__reference_phase); + VL53L1_p_017 += + (2048 * + (uint32_t)phasecal_result__vcsel_start); + VL53L1_p_017 -= (2048 * + (uint32_t)pdev->hist_data.cal_config__vcsel_start); + + VL53L1_p_017 = VL53L1_p_017 % period; + + phasecal_result__reference_phase += (uint32_t)( + pdev->hist_data.phasecal_result__reference_phase); + + zero_distance_phase += (uint32_t)VL53L1_p_017; + } + } + + + + + if (status == VL53L1_ERROR_NONE && samples > 0) { + + phasecal_result__reference_phase += (samples >> 1); + phasecal_result__reference_phase /= samples; + + zero_distance_phase += (samples >> 1); + zero_distance_phase /= samples; + + *pphasecal_result__reference_phase = + (uint16_t)phasecal_result__reference_phase; + *pzero_distance_phase = + (uint16_t)zero_distance_phase; + } + + return status; +} + + +VL53L1_Error VL53L1_run_zone_calibration( + VL53L1_DEV Dev, + VL53L1_DevicePresetModes device_preset_mode, + VL53L1_DeviceZonePreset zone_preset, + VL53L1_zone_config_t *pzone_cfg, + int16_t cal_distance_mm, + uint16_t cal_reflectance_pc, + VL53L1_Error *pcal_status) +{ + + + + + + + + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + + VL53L1_LLDriverResults_t *pres = + VL53L1DevStructGetLLResultsHandle(Dev); + + VL53L1_range_results_t range_results; + VL53L1_range_results_t *pRR = &range_results; + VL53L1_range_data_t *prange_data = NULL; + VL53L1_zone_calibration_data_t *pzone_data = NULL; + + uint16_t i = 0; + uint16_t m = 0; + + uint8_t z = 0; + uint8_t measurement_mode = + VL53L1_DEVICEMEASUREMENTMODE_BACKTOBACK; + + VL53L1_OffsetCorrectionMode offset_cor_mode = + VL53L1_OFFSETCORRECTIONMODE__NONE; + + LOG_FUNCTION_START(""); + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_set_preset_mode( + Dev, + device_preset_mode, + + + pdev->zonecal_cfg.dss_config__target_total_rate_mcps, + pdev->zonecal_cfg.phasecal_config_timeout_us, + pdev->zonecal_cfg.mm_config_timeout_us, + pdev->zonecal_cfg.range_config_timeout_us, + + + 100); + + + + + if (zone_preset == VL53L1_DEVICEZONEPRESET_CUSTOM) { + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_set_zone_config( + Dev, + pzone_cfg); + + } else if (zone_preset != VL53L1_DEVICEZONEPRESET_NONE) { + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_set_zone_preset( + Dev, + zone_preset); + } + + + + + + + pres->zone_cal.preset_mode = device_preset_mode; + pres->zone_cal.zone_preset = zone_preset; + + + pres->zone_cal.cal_distance_mm = cal_distance_mm * 16; + pres->zone_cal.cal_reflectance_pc = cal_reflectance_pc; + pres->zone_cal.max_zones = VL53L1_MAX_USER_ZONES; + pres->zone_cal.active_zones = pdev->zone_cfg.active_zones + 1; + + for (i = 0; i < VL53L1_MAX_USER_ZONES; i++) { + pres->zone_cal.VL53L1_p_002[i].no_of_samples = 0; + pres->zone_cal.VL53L1_p_002[i].effective_spads = 0; + pres->zone_cal.VL53L1_p_002[i].peak_rate_mcps = 0; + pres->zone_cal.VL53L1_p_002[i].VL53L1_p_014 = 0; + pres->zone_cal.VL53L1_p_002[i].VL53L1_p_005 = 0; + pres->zone_cal.VL53L1_p_002[i].median_range_mm = 0; + pres->zone_cal.VL53L1_p_002[i].range_mm_offset = 0; + } + + pres->zone_cal.phasecal_result__reference_phase = 0; + pres->zone_cal.zero_distance_phase = 0; + + + + + + + + status = + VL53L1_get_offset_correction_mode( + Dev, + &offset_cor_mode); + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_set_offset_correction_mode( + Dev, + VL53L1_OFFSETCORRECTIONMODE__NONE); + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_init_and_start_range( + Dev, + measurement_mode, + VL53L1_DEVICECONFIGLEVEL_CUSTOMER_ONWARDS); + + + + + + + m = (pdev->zonecal_cfg.zone_num_of_samples + 2) * + (uint16_t)pres->zone_cal.active_zones; + + + + for (i = 0; i <= m; i++) { + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_wait_for_range_completion(Dev); + + + + + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_get_device_results( + Dev, + VL53L1_DEVICERESULTSLEVEL_FULL, + pRR); + + + + + + + + + + prange_data = &(pRR->VL53L1_p_002[0]); + + if (pRR->active_results > 0 && + i > (uint16_t)pres->zone_cal.active_zones) { + + if (prange_data->range_status == + VL53L1_DEVICEERROR_RANGECOMPLETE) { + + pres->zone_cal.phasecal_result__reference_phase + = + pdev->hist_data.phasecal_result__reference_phase + ; + pres->zone_cal.zero_distance_phase = + pdev->hist_data.zero_distance_phase; + + pzone_data = + &(pres->zone_cal.VL53L1_p_002[pRR->zone_id]); + pzone_data->no_of_samples++; + pzone_data->effective_spads += + (uint32_t)prange_data->VL53L1_p_006; + pzone_data->peak_rate_mcps += (uint32_t)( + prange_data->peak_signal_count_rate_mcps); + pzone_data->VL53L1_p_014 += + (uint32_t)prange_data->VL53L1_p_014; + pzone_data->VL53L1_p_005 += + (uint32_t)prange_data->VL53L1_p_005; + pzone_data->median_range_mm += + (int32_t)prange_data->median_range_mm; + + } + } + + + + + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_wait_for_firmware_ready(Dev); + + + + + + + + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_clear_interrupt_and_enable_next_range( + Dev, + measurement_mode); + } + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_stop_range(Dev); + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WaitUs(Dev, 1000); + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_run_phasecal_average( + Dev, + measurement_mode, + pdev->hist_data.phasecal_result__vcsel_start, + + + pdev->zonecal_cfg.phasecal_num_of_samples, + + + pRR, + &(pres->zone_cal.phasecal_result__reference_phase), + &(pres->zone_cal.zero_distance_phase)); + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_set_offset_correction_mode( + Dev, + offset_cor_mode); + + + + + if (status == VL53L1_ERROR_NONE) { + + for (z = 0; z < pres->zone_cal.active_zones; z++) { + + pzone_data = &(pres->zone_cal.VL53L1_p_002[z]); + + + + if (pzone_data->no_of_samples > 0) { + + pzone_data->effective_spads += + (pzone_data->no_of_samples/2); + pzone_data->effective_spads /= + pzone_data->no_of_samples; + + pzone_data->peak_rate_mcps += + (pzone_data->no_of_samples/2); + pzone_data->peak_rate_mcps /= + pzone_data->no_of_samples; + + pzone_data->VL53L1_p_014 += + (pzone_data->no_of_samples/2); + pzone_data->VL53L1_p_014 /= + pzone_data->no_of_samples; + + pzone_data->VL53L1_p_005 += + (pzone_data->no_of_samples/2); + pzone_data->VL53L1_p_005 /= + pzone_data->no_of_samples; + + + + + + + + pzone_data->median_range_mm = + VL53L1_range_maths( + pdev->stat_nvm.osc_measured__fast_osc__frequency + , (uint16_t)pzone_data->VL53L1_p_014, + pres->zone_cal.zero_distance_phase, + 2, + + 0x0800, + + 0); + + + pzone_data->range_mm_offset = + ((int32_t)cal_distance_mm) * 4; + pzone_data->range_mm_offset -= + pzone_data->median_range_mm; + + + + if (pzone_data->no_of_samples < + pdev->zonecal_cfg.zone_num_of_samples) + status = + VL53L1_WARNING_ZONE_CAL_MISSING_SAMPLES; + + + + if (pzone_data->VL53L1_p_005 > + ((uint32_t)VL53L1_ZONE_CAL_MAX_SIGMA_MM + << 5)) + status = + VL53L1_WARNING_ZONE_CAL_SIGMA_TOO_HIGH; + + if (pzone_data->peak_rate_mcps > + VL53L1_ZONE_CAL_MAX_PRE_PEAK_RATE_MCPS) + status = + VL53L1_WARNING_ZONE_CAL_RATE_TOO_HIGH; + + } else { + status = VL53L1_ERROR_ZONE_CAL_NO_SAMPLE_FAIL; + } + } + } + + + + + + + pres->zone_cal.cal_status = status; + *pcal_status = pres->zone_cal.cal_status; + + + + + IGNORE_STATUS( + IGNORE_ZONE_CAL_MISSING_SAMPLES, + VL53L1_WARNING_ZONE_CAL_MISSING_SAMPLES, + status); + + IGNORE_STATUS( + IGNORE_ZONE_CAL_SIGMA_TOO_HIGH, + VL53L1_WARNING_ZONE_CAL_SIGMA_TOO_HIGH, + status); + + IGNORE_STATUS( + IGNORE_ZONE_CAL_RATE_TOO_HIGH, + VL53L1_WARNING_ZONE_CAL_RATE_TOO_HIGH, + status); + +#ifdef VL53L1_LOG_ENABLE + + + + + VL53L1_print_zone_calibration_results( + &(pres->zone_cal), + "run_zone_calibration():pdev->llresults.zone_cal.", + VL53L1_TRACE_MODULE_OFFSET_DATA); + +#endif + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_run_spad_rate_map( + VL53L1_DEV Dev, + VL53L1_DeviceTestMode device_test_mode, + VL53L1_DeviceSscArray array_select, + uint32_t ssc_config_timeout_us, + VL53L1_spad_rate_data_t *pspad_rate_data) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_powerforce(Dev); + + + + + + + if (status == VL53L1_ERROR_NONE) { + pdev->ssc_cfg.array_select = array_select; + pdev->ssc_cfg.timeout_us = ssc_config_timeout_us; + status = + VL53L1_set_ssc_config( + Dev, + &(pdev->ssc_cfg), + pdev->stat_nvm.osc_measured__fast_osc__frequency); + } + + + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_run_device_test( + Dev, + device_test_mode); + + + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_get_spad_rate_data( + Dev, + pspad_rate_data); + + if (device_test_mode == VL53L1_DEVICETESTMODE_LCR_VCSEL_ON) + pspad_rate_data->fractional_bits = 7; + else + pspad_rate_data->fractional_bits = 15; + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_disable_powerforce(Dev); + +#ifdef VL53L1_LOG_ENABLE + + + + if (status == VL53L1_ERROR_NONE) { + VL53L1_print_spad_rate_data( + pspad_rate_data, + "run_spad_rate_map():", + VL53L1_TRACE_MODULE_SPAD_RATE_MAP); + VL53L1_print_spad_rate_map( + pspad_rate_data, + "run_spad_rate_map():", + VL53L1_TRACE_MODULE_SPAD_RATE_MAP); + } +#endif + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_run_device_test( + VL53L1_DEV Dev, + VL53L1_DeviceTestMode device_test_mode) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + uint8_t comms_buffer[2]; + uint8_t gpio_hv_mux__ctrl = 0; + + LOG_FUNCTION_START(""); + + + + + + + if (status == VL53L1_ERROR_NONE) + + status = + VL53L1_RdByte( + Dev, + VL53L1_GPIO_HV_MUX__CTRL, + &gpio_hv_mux__ctrl); + + if (status == VL53L1_ERROR_NONE) + pdev->stat_cfg.gpio_hv_mux__ctrl = gpio_hv_mux__ctrl; + + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_start_test( + Dev, + device_test_mode); + + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_wait_for_test_completion(Dev); + + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_ReadMulti( + Dev, + VL53L1_RESULT__RANGE_STATUS, + comms_buffer, + 2); + + if (status == VL53L1_ERROR_NONE) { + pdev->sys_results.result__range_status = comms_buffer[0]; + pdev->sys_results.result__report_status = comms_buffer[1]; + } + + + + + pdev->sys_results.result__range_status &= + VL53L1_RANGE_STATUS__RANGE_STATUS_MASK; + + if (status == VL53L1_ERROR_NONE) { + trace_print( + VL53L1_TRACE_LEVEL_INFO, + " Device Test Complete:\n\t%-32s = %3u\n\t%-32s = %3u\n", + "result__range_status", + pdev->sys_results.result__range_status, + "result__report_status", + pdev->sys_results.result__report_status); + + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_clear_interrupt(Dev); + } + + + + + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_start_test( + Dev, + 0x00); + + LOG_FUNCTION_END(status); + + return status; +} + + +void VL53L1_hist_xtalk_extract_data_init( + VL53L1_hist_xtalk_extract_data_t *pxtalk_data) +{ + + + + + + int32_t lb = 0; + + pxtalk_data->sample_count = 0U; + pxtalk_data->pll_period_mm = 0U; + pxtalk_data->peak_duration_us_sum = 0U; + pxtalk_data->effective_spad_count_sum = 0U; + pxtalk_data->zero_distance_phase_sum = 0U; + pxtalk_data->zero_distance_phase_avg = 0U; + pxtalk_data->event_scaler_sum = 0U; + pxtalk_data->event_scaler_avg = 4096U; + pxtalk_data->signal_events_sum = 0; + pxtalk_data->xtalk_rate_kcps_per_spad = 0U; + pxtalk_data->VL53L1_p_015 = 0U; + pxtalk_data->VL53L1_p_016 = 0U; + pxtalk_data->target_start = 0U; + + for (lb = 0; lb < VL53L1_XTALK_HISTO_BINS; lb++) + pxtalk_data->bin_data_sums[lb] = 0; + +} + + +VL53L1_Error VL53L1_hist_xtalk_extract_update( + int16_t target_distance_mm, + uint16_t target_width_oversize, + VL53L1_histogram_bin_data_t *phist_bins, + VL53L1_hist_xtalk_extract_data_t *pxtalk_data) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + status = + VL53L1_hist_xtalk_extract_calc_window( + target_distance_mm, + target_width_oversize, + phist_bins, + pxtalk_data); + + if (status == VL53L1_ERROR_NONE) { + status = + VL53L1_hist_xtalk_extract_calc_event_sums( + phist_bins, + pxtalk_data); + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_hist_xtalk_extract_fini( + VL53L1_histogram_bin_data_t *phist_bins, + VL53L1_hist_xtalk_extract_data_t *pxtalk_data, + VL53L1_xtalk_calibration_results_t *pxtalk_cal, + VL53L1_xtalk_histogram_shape_t *pxtalk_shape) +{ + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_xtalk_calibration_results_t *pX = pxtalk_cal; + + LOG_FUNCTION_START(""); + + if (pxtalk_data->sample_count > 0) { + + + + pxtalk_data->event_scaler_avg = pxtalk_data->event_scaler_sum; + pxtalk_data->event_scaler_avg += + (pxtalk_data->sample_count >> 1); + pxtalk_data->event_scaler_avg /= pxtalk_data->sample_count; + + + + + + + status = + VL53L1_hist_xtalk_extract_calc_rate_per_spad( + pxtalk_data); + + + + + + + if (status == VL53L1_ERROR_NONE) { + + + + pxtalk_data->zero_distance_phase_avg = + pxtalk_data->zero_distance_phase_sum; + pxtalk_data->zero_distance_phase_avg += + (pxtalk_data->sample_count >> 1); + pxtalk_data->zero_distance_phase_avg /= + pxtalk_data->sample_count; + + + + status = + VL53L1_hist_xtalk_extract_calc_shape( + pxtalk_data, + pxtalk_shape); + + + + + + + + + + + + pxtalk_shape->phasecal_result__vcsel_start = + phist_bins->phasecal_result__vcsel_start; + pxtalk_shape->cal_config__vcsel_start = + phist_bins->cal_config__vcsel_start; + pxtalk_shape->vcsel_width = + phist_bins->vcsel_width; + pxtalk_shape->VL53L1_p_019 = + phist_bins->VL53L1_p_019; + } + + + + + + + if (status == VL53L1_ERROR_NONE) { + + + + pX->algo__crosstalk_compensation_plane_offset_kcps = + pxtalk_data->xtalk_rate_kcps_per_spad; + pX->algo__crosstalk_compensation_x_plane_gradient_kcps + = 0U; + pX->algo__crosstalk_compensation_y_plane_gradient_kcps + = 0U; + + } + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_run_hist_xtalk_extraction( + VL53L1_DEV Dev, + int16_t cal_distance_mm, + VL53L1_Error *pcal_status) +{ + + + + + + + + + + + + + + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_xtalkextract_config_t *pX = &(pdev->xtalk_extract_cfg); + VL53L1_xtalk_config_t *pC = &(pdev->xtalk_cfg); + VL53L1_xtalk_calibration_results_t *pXC = &(pdev->xtalk_cal); + + + + + + + uint8_t smudge_corr_en = 0; + uint8_t i = 0; + uint8_t measurement_mode = VL53L1_DEVICEMEASUREMENTMODE_BACKTOBACK; + + + + + VL53L1_range_results_t range_results; + VL53L1_range_results_t *prange_results = &range_results; + + LOG_FUNCTION_START(""); + + + + + VL53L1_hist_xtalk_extract_data_init( + &(pdev->xtalk_extract)); + + + + + + + + + + + + if (status == VL53L1_ERROR_NONE) + + status = + VL53L1_set_preset_mode( + Dev, + VL53L1_DEVICEPRESETMODE_HISTOGRAM_LONG_RANGE, + pX->dss_config__target_total_rate_mcps, + pX->phasecal_config_timeout_us, + pX->mm_config_timeout_us, + pX->range_config_timeout_us, + 100); + + + + + if (status == VL53L1_ERROR_NONE) { + status = VL53L1_disable_xtalk_compensation( + Dev); + } + + + + + smudge_corr_en = pdev->smudge_correct_config.smudge_corr_enabled; + + if (status == VL53L1_ERROR_NONE) { + status = + VL53L1_dynamic_xtalk_correction_disable(Dev); + } + + + + + if (status == VL53L1_ERROR_NONE) + + status = + VL53L1_init_and_start_range( + Dev, + measurement_mode, + VL53L1_DEVICECONFIGLEVEL_CUSTOMER_ONWARDS); + + + + + for (i = 0; i <= pX->num_of_samples; i++) { + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_wait_for_range_completion(Dev); + + + + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_get_device_results( + Dev, + VL53L1_DEVICERESULTSLEVEL_FULL, + prange_results); + + + + + + + if (status == VL53L1_ERROR_NONE && + pdev->ll_state.rd_device_state != + VL53L1_DEVICESTATE_RANGING_WAIT_GPH_SYNC) { + + status = + VL53L1_hist_xtalk_extract_update( + cal_distance_mm, + 4, + + &(pdev->hist_data), + &(pdev->xtalk_extract)); + } + + + + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_wait_for_firmware_ready(Dev); + + + + + + + + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_clear_interrupt_and_enable_next_range( + Dev, + measurement_mode); + } + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_stop_range(Dev); + + + + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_hist_xtalk_extract_fini( + &(pdev->hist_data), + &(pdev->xtalk_extract), + &(pdev->xtalk_cal), + &(pdev->xtalk_shapes.xtalk_shape)); + + + + + + if (status == VL53L1_ERROR_NONE) { + pC->algo__crosstalk_compensation_x_plane_gradient_kcps = + pXC->algo__crosstalk_compensation_x_plane_gradient_kcps; + pC->algo__crosstalk_compensation_y_plane_gradient_kcps = + pXC->algo__crosstalk_compensation_y_plane_gradient_kcps; + pC->algo__crosstalk_compensation_plane_offset_kcps = + pXC->algo__crosstalk_compensation_plane_offset_kcps; + } + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_xtalk_compensation(Dev); + + + + + + if (status == VL53L1_ERROR_NONE) + if (smudge_corr_en == 1) + status = VL53L1_dynamic_xtalk_correction_enable(Dev); + + + + + + + pdev->xtalk_results.cal_status = status; + *pcal_status = pdev->xtalk_results.cal_status; + + +#ifdef VL53L1_LOG_ENABLE + + + + + VL53L1_print_customer_nvm_managed( + &(pdev->customer), + "run_xtalk_extraction():pdev->lldata.customer.", + VL53L1_TRACE_MODULE_XTALK_DATA); + + VL53L1_print_xtalk_config( + &(pdev->xtalk_cfg), + "run_xtalk_extraction():pdev->lldata.xtalk_cfg.", + VL53L1_TRACE_MODULE_XTALK_DATA); + + VL53L1_print_xtalk_histogram_data( + &(pdev->xtalk_shapes), + "pdev->lldata.xtalk_shapes.", + VL53L1_TRACE_MODULE_XTALK_DATA); + +#endif + + LOG_FUNCTION_END(status); + + return status; +} + diff --git a/drivers/input/misc/vl53L1/lito/src/vl53l1_api_core.c b/drivers/input/misc/vl53L1/lito/src/vl53l1_api_core.c new file mode 100644 index 000000000000..d86bb88d802e --- /dev/null +++ b/drivers/input/misc/vl53L1/lito/src/vl53l1_api_core.c @@ -0,0 +1,7431 @@ + +/******************************************************************************* + * Copyright (c) 2017, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#include "vl53l1_ll_def.h" +#include "vl53l1_ll_device.h" +#include "vl53l1_platform.h" +#include "vl53l1_platform_ipp.h" +#include "vl53l1_register_map.h" +#include "vl53l1_register_settings.h" +#include "vl53l1_register_funcs.h" +#include "vl53l1_hist_map.h" +#include "vl53l1_hist_structs.h" +#include "vl53l1_nvm_map.h" +#include "vl53l1_nvm_structs.h" +#include "vl53l1_nvm.h" +#include "vl53l1_core.h" +#include "vl53l1_wait.h" +#include "vl53l1_zone_presets.h" +#include "vl53l1_api_preset_modes.h" +#include "vl53l1_silicon_core.h" +#include "vl53l1_api_core.h" +#include "vl53l1_tuning_parm_defaults.h" + +#ifdef VL53L1_LOG_ENABLE +#include "vl53l1_api_debug.h" +#endif + +#define LOG_FUNCTION_START(fmt, ...) \ + _LOG_FUNCTION_START(VL53L1_TRACE_MODULE_CORE, fmt, ##__VA_ARGS__) +#define LOG_FUNCTION_END(status, ...) \ + _LOG_FUNCTION_END(VL53L1_TRACE_MODULE_CORE, status, ##__VA_ARGS__) +#define LOG_FUNCTION_END_FMT(status, fmt, ...) \ + _LOG_FUNCTION_END_FMT(VL53L1_TRACE_MODULE_CORE, status, \ + fmt, ##__VA_ARGS__) + +#define trace_print(level, ...) \ + _LOG_TRACE_PRINT(VL53L1_TRACE_MODULE_CORE, \ + level, VL53L1_TRACE_FUNCTION_NONE, ##__VA_ARGS__) + +#define VL53L1_MAX_I2C_XFER_SIZE 256 + +VL53L1_Error VL53L1_get_version( + VL53L1_DEV Dev, + VL53L1_ll_version_t *pdata) +{ + + + + + + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + VL53L1_init_version(Dev); + + memcpy(pdata, &(pdev->version), sizeof(VL53L1_ll_version_t)); + + return VL53L1_ERROR_NONE; +} + + +VL53L1_Error VL53L1_get_device_firmware_version( + VL53L1_DEV Dev, + uint16_t *pfw_version) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_disable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_RdWord( + Dev, + VL53L1_MCU_GENERAL_PURPOSE__GP_0, + pfw_version); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_firmware(Dev); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_data_init( + VL53L1_DEV Dev, + uint8_t read_p2p_data) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_LLDriverResults_t *pres = + VL53L1DevStructGetLLResultsHandle(Dev); + + + + + VL53L1_zone_objects_t *pobjects; + + uint8_t i = 0; + + LOG_FUNCTION_START(""); + + VL53L1_init_ll_driver_state( + Dev, + VL53L1_DEVICESTATE_UNKNOWN); + + pres->range_results.max_results = VL53L1_MAX_RANGE_RESULTS; + pres->range_results.active_results = 0; + pres->zone_results.max_zones = VL53L1_MAX_USER_ZONES; + pres->zone_results.active_zones = 0; + + for (i = 0; i < VL53L1_MAX_USER_ZONES; i++) { + pobjects = &(pres->zone_results.VL53L1_p_002[i]); + pobjects->xmonitor.VL53L1_p_020 = 0; + pobjects->xmonitor.VL53L1_p_021 = 0; + pobjects->xmonitor.VL53L1_p_014 = 0; + pobjects->xmonitor.range_status = + VL53L1_DEVICEERROR_NOUPDATE; + } + + + + + pres->zone_hists.max_zones = VL53L1_MAX_USER_ZONES; + pres->zone_hists.active_zones = 0; + + + + + pres->zone_cal.max_zones = VL53L1_MAX_USER_ZONES; + pres->zone_cal.active_zones = 0; + for (i = 0; i < VL53L1_MAX_USER_ZONES; i++) { + pres->zone_cal.VL53L1_p_002[i].no_of_samples = 0; + pres->zone_cal.VL53L1_p_002[i].effective_spads = 0; + pres->zone_cal.VL53L1_p_002[i].peak_rate_mcps = 0; + pres->zone_cal.VL53L1_p_002[i].median_range_mm = 0; + pres->zone_cal.VL53L1_p_002[i].range_mm_offset = 0; + } + + pdev->wait_method = VL53L1_WAIT_METHOD_BLOCKING; + pdev->preset_mode = VL53L1_DEVICEPRESETMODE_STANDARD_RANGING; + pdev->zone_preset = VL53L1_DEVICEZONEPRESET_NONE; + pdev->measurement_mode = VL53L1_DEVICEMEASUREMENTMODE_STOP; + + pdev->offset_calibration_mode = + VL53L1_OFFSETCALIBRATIONMODE__MM1_MM2__STANDARD; + pdev->offset_correction_mode = + VL53L1_OFFSETCORRECTIONMODE__MM1_MM2_OFFSETS; + pdev->dmax_mode = + VL53L1_DEVICEDMAXMODE__FMT_CAL_DATA; + + pdev->phasecal_config_timeout_us = 1000; + pdev->mm_config_timeout_us = 2000; + pdev->range_config_timeout_us = 13000; + pdev->inter_measurement_period_ms = 100; + pdev->dss_config__target_total_rate_mcps = 0x0A00; + pdev->debug_mode = 0x00; + + pdev->offset_results.max_results = VL53L1_MAX_OFFSET_RANGE_RESULTS; + pdev->offset_results.active_results = 0; + + + + + + pdev->gain_cal.standard_ranging_gain_factor = + VL53L1_TUNINGPARM_LITE_RANGING_GAIN_FACTOR_DEFAULT; + pdev->gain_cal.histogram_ranging_gain_factor = + VL53L1_TUNINGPARM_HIST_GAIN_FACTOR_DEFAULT; + + + + + + VL53L1_init_version(Dev); + + + + + + + + + + + if (read_p2p_data > 0 && status == VL53L1_ERROR_NONE) + + status = VL53L1_read_p2p_data(Dev); + + + + status = + VL53L1_init_refspadchar_config_struct( + &(pdev->refspadchar)); + + + + status = + VL53L1_init_ssc_config_struct( + &(pdev->ssc_cfg)); + + + + + + status = + VL53L1_init_xtalk_config_struct( + &(pdev->customer), + &(pdev->xtalk_cfg)); + + + + + status = + VL53L1_init_xtalk_extract_config_struct( + &(pdev->xtalk_extract_cfg)); + + + + + status = + VL53L1_init_offset_cal_config_struct( + &(pdev->offsetcal_cfg)); + + + + + status = VL53L1_init_zone_cal_config_struct( + &(pdev->zonecal_cfg)); + + + + status = + VL53L1_init_hist_post_process_config_struct( + pdev->xtalk_cfg.global_crosstalk_compensation_enable, + &(pdev->histpostprocess)); + + + + status = + VL53L1_init_hist_gen3_dmax_config_struct( + &(pdev->dmax_cfg)); + + + + + + status = + VL53L1_init_tuning_parm_storage_struct( + &(pdev->tuning_parms)); + + + + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_set_preset_mode( + Dev, + pdev->preset_mode, + pdev->dss_config__target_total_rate_mcps, + + pdev->phasecal_config_timeout_us, + pdev->mm_config_timeout_us, + pdev->range_config_timeout_us, + pdev->inter_measurement_period_ms); + + + + VL53L1_init_histogram_bin_data_struct( + 0, + VL53L1_HISTOGRAM_BUFFER_SIZE, + &(pdev->hist_data)); + + VL53L1_init_histogram_bin_data_struct( + 0, + VL53L1_HISTOGRAM_BUFFER_SIZE, + &(pdev->hist_xtalk)); + + + + VL53L1_init_xtalk_bin_data_struct( + 0, + VL53L1_XTALK_HISTO_BINS, + &(pdev->xtalk_shapes.xtalk_shape)); + + + + + + VL53L1_xtalk_cal_data_init( + Dev + ); + + + + + + VL53L1_dynamic_xtalk_correction_data_init( + Dev + ); + + + + + + VL53L1_low_power_auto_data_init( + Dev + ); + +#ifdef VL53L1_LOG_ENABLE + + + + + VL53L1_print_static_nvm_managed( + &(pdev->stat_nvm), + "data_init():pdev->lldata.stat_nvm.", + VL53L1_TRACE_MODULE_DATA_INIT); + + VL53L1_print_customer_nvm_managed( + &(pdev->customer), + "data_init():pdev->lldata.customer.", + VL53L1_TRACE_MODULE_DATA_INIT); + + VL53L1_print_nvm_copy_data( + &(pdev->nvm_copy_data), + "data_init():pdev->lldata.nvm_copy_data.", + VL53L1_TRACE_MODULE_DATA_INIT); + + VL53L1_print_dmax_calibration_data( + &(pdev->fmt_dmax_cal), + "data_init():pdev->lldata.fmt_dmax_cal.", + VL53L1_TRACE_MODULE_DATA_INIT); + + VL53L1_print_dmax_calibration_data( + &(pdev->cust_dmax_cal), + "data_init():pdev->lldata.cust_dmax_cal.", + VL53L1_TRACE_MODULE_DATA_INIT); + + VL53L1_print_additional_offset_cal_data( + &(pdev->add_off_cal_data), + "data_init():pdev->lldata.add_off_cal_data.", + VL53L1_TRACE_MODULE_DATA_INIT); + + VL53L1_print_user_zone( + &(pdev->mm_roi), + "data_init():pdev->lldata.mm_roi.", + VL53L1_TRACE_MODULE_DATA_INIT); + + VL53L1_print_optical_centre( + &(pdev->optical_centre), + "data_init():pdev->lldata.optical_centre.", + VL53L1_TRACE_MODULE_DATA_INIT); + + VL53L1_print_cal_peak_rate_map( + &(pdev->cal_peak_rate_map), + "data_init():pdev->lldata.cal_peak_rate_map.", + VL53L1_TRACE_MODULE_DATA_INIT); + +#endif + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_read_p2p_data( + VL53L1_DEV Dev) +{ + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_hist_post_process_config_t *pHP = &(pdev->histpostprocess); + VL53L1_customer_nvm_managed_t *pN = &(pdev->customer); + VL53L1_additional_offset_cal_data_t *pCD = &(pdev->add_off_cal_data); + + VL53L1_decoded_nvm_fmt_range_data_t fmt_rrd; + + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_get_static_nvm_managed( + Dev, + &(pdev->stat_nvm)); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_get_customer_nvm_managed( + Dev, + &(pdev->customer)); + + if (status == VL53L1_ERROR_NONE) { + + status = VL53L1_get_nvm_copy_data( + Dev, + &(pdev->nvm_copy_data)); + + + + if (status == VL53L1_ERROR_NONE) + VL53L1_copy_rtn_good_spads_to_buffer( + &(pdev->nvm_copy_data), + &(pdev->rtn_good_spads[0])); + } + + + + + if (status == VL53L1_ERROR_NONE) { + pHP->algo__crosstalk_compensation_plane_offset_kcps = + pN->algo__crosstalk_compensation_plane_offset_kcps; + pHP->algo__crosstalk_compensation_x_plane_gradient_kcps = + pN->algo__crosstalk_compensation_x_plane_gradient_kcps; + pHP->algo__crosstalk_compensation_y_plane_gradient_kcps = + pN->algo__crosstalk_compensation_y_plane_gradient_kcps; + } + + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_read_nvm_optical_centre( + Dev, + &(pdev->optical_centre)); + + + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_read_nvm_cal_peak_rate_map( + Dev, + &(pdev->cal_peak_rate_map)); + + + + + + + if (status == VL53L1_ERROR_NONE) { + + status = + VL53L1_read_nvm_additional_offset_cal_data( + Dev, + &(pdev->add_off_cal_data)); + + + + + + + if (pCD->result__mm_inner_peak_signal_count_rtn_mcps == 0 && + pCD->result__mm_outer_peak_signal_count_rtn_mcps == 0) { + + pCD->result__mm_inner_peak_signal_count_rtn_mcps + = 0x0080; + + pCD->result__mm_outer_peak_signal_count_rtn_mcps + = 0x0180; + + + + + + VL53L1_calc_mm_effective_spads( + pdev->nvm_copy_data.roi_config__mode_roi_centre_spad, + pdev->nvm_copy_data.roi_config__mode_roi_xy_size, + 0xC7, + + 0xFF, + &(pdev->rtn_good_spads[0]), + VL53L1_RTN_SPAD_APERTURE_TRANSMISSION, + &(pCD->result__mm_inner_actual_effective_spads), + &(pCD->result__mm_outer_actual_effective_spads)); + } + } + + + + + + if (status == VL53L1_ERROR_NONE) { + + status = + VL53L1_read_nvm_fmt_range_results_data( + Dev, + VL53L1_NVM__FMT__RANGE_RESULTS__140MM_DARK, + &fmt_rrd); + + if (status == VL53L1_ERROR_NONE) { + pdev->fmt_dmax_cal.ref__actual_effective_spads = + fmt_rrd.result__actual_effective_rtn_spads; + pdev->fmt_dmax_cal.ref__peak_signal_count_rate_mcps = + fmt_rrd.result__peak_signal_count_rate_rtn_mcps; + pdev->fmt_dmax_cal.ref__distance_mm = + fmt_rrd.measured_distance_mm; + + + + + + + if (pdev->cal_peak_rate_map.cal_reflectance_pc != 0) { + pdev->fmt_dmax_cal.ref_reflectance_pc = + pdev->cal_peak_rate_map.cal_reflectance_pc; + } else { + pdev->fmt_dmax_cal.ref_reflectance_pc = 0x0014; + } + + + + pdev->fmt_dmax_cal.coverglass_transmission = 0x0100; + } + } + + + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_RdWord( + Dev, + VL53L1_RESULT__OSC_CALIBRATE_VAL, + &(pdev->dbg_results.result__osc_calibrate_val)); + + + + + + + if (pdev->stat_nvm.osc_measured__fast_osc__frequency < 0x1000) { + trace_print( + VL53L1_TRACE_LEVEL_WARNING, + "\nInvalid %s value (0x%04X) - forcing to 0x%04X\n\n", + "pdev->stat_nvm.osc_measured__fast_osc__frequency", + pdev->stat_nvm.osc_measured__fast_osc__frequency, + 0xBCCC); + pdev->stat_nvm.osc_measured__fast_osc__frequency = 0xBCCC; + } + + + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_get_mode_mitigation_roi( + Dev, + &(pdev->mm_roi)); + + + + + + + if (pdev->optical_centre.x_centre == 0 && + pdev->optical_centre.y_centre == 0) { + pdev->optical_centre.x_centre = + pdev->mm_roi.x_centre << 4; + pdev->optical_centre.y_centre = + pdev->mm_roi.y_centre << 4; + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_software_reset( + VL53L1_DEV Dev) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_WrByte( + Dev, + VL53L1_SOFT_RESET, + 0x00); + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_WaitUs( + Dev, + VL53L1_SOFTWARE_RESET_DURATION_US); + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WrByte( + Dev, + VL53L1_SOFT_RESET, + 0x01); + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_wait_for_boot_completion(Dev); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_part_to_part_data( + VL53L1_DEV Dev, + VL53L1_calibration_data_t *pcal_data) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_xtalk_config_t *pC = &(pdev->xtalk_cfg); + VL53L1_hist_post_process_config_t *pHP = &(pdev->histpostprocess); + VL53L1_customer_nvm_managed_t *pN = &(pdev->customer); + + uint32_t tempu32; + + LOG_FUNCTION_START(""); + + if (pcal_data->struct_version != + VL53L1_LL_CALIBRATION_DATA_STRUCT_VERSION) { + status = VL53L1_ERROR_INVALID_PARAMS; + } + + if (status == VL53L1_ERROR_NONE) { + + + + memcpy( + &(pdev->customer), + &(pcal_data->customer), + sizeof(VL53L1_customer_nvm_managed_t)); + + + + memcpy( + &(pdev->add_off_cal_data), + &(pcal_data->add_off_cal_data), + sizeof(VL53L1_additional_offset_cal_data_t)); + + + + memcpy( + &(pdev->fmt_dmax_cal), + &(pcal_data->fmt_dmax_cal), + sizeof(VL53L1_dmax_calibration_data_t)); + + + + memcpy( + &(pdev->cust_dmax_cal), + &(pcal_data->cust_dmax_cal), + sizeof(VL53L1_dmax_calibration_data_t)); + + + + memcpy( + &(pdev->xtalk_shapes), + &(pcal_data->xtalkhisto), + sizeof(VL53L1_xtalk_histogram_data_t)); + + + + memcpy( + &(pdev->gain_cal), + &(pcal_data->gain_cal), + sizeof(VL53L1_gain_calibration_data_t)); + + + + memcpy( + &(pdev->cal_peak_rate_map), + &(pcal_data->cal_peak_rate_map), + sizeof(VL53L1_cal_peak_rate_map_t)); + + + + + + + pC->algo__crosstalk_compensation_plane_offset_kcps = + pN->algo__crosstalk_compensation_plane_offset_kcps; + pC->algo__crosstalk_compensation_x_plane_gradient_kcps = + pN->algo__crosstalk_compensation_x_plane_gradient_kcps; + pC->algo__crosstalk_compensation_y_plane_gradient_kcps = + pN->algo__crosstalk_compensation_y_plane_gradient_kcps; + + pHP->algo__crosstalk_compensation_plane_offset_kcps = + VL53L1_calc_crosstalk_plane_offset_with_margin( + pC->algo__crosstalk_compensation_plane_offset_kcps, + pC->histogram_mode_crosstalk_margin_kcps); + + pHP->algo__crosstalk_compensation_x_plane_gradient_kcps = + pC->algo__crosstalk_compensation_x_plane_gradient_kcps; + pHP->algo__crosstalk_compensation_y_plane_gradient_kcps = + pC->algo__crosstalk_compensation_y_plane_gradient_kcps; + + + + + if (pC->global_crosstalk_compensation_enable == 0x00) { + pN->algo__crosstalk_compensation_plane_offset_kcps = + 0x00; + pN->algo__crosstalk_compensation_x_plane_gradient_kcps = + 0x00; + pN->algo__crosstalk_compensation_y_plane_gradient_kcps = + 0x00; + } else { + tempu32 = + VL53L1_calc_crosstalk_plane_offset_with_margin( + pC->algo__crosstalk_compensation_plane_offset_kcps, + pC->lite_mode_crosstalk_margin_kcps); + + + + if (tempu32 > 0xFFFF) + tempu32 = 0xFFFF; + + pN->algo__crosstalk_compensation_plane_offset_kcps = + (uint16_t)tempu32; + } + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_part_to_part_data( + VL53L1_DEV Dev, + VL53L1_calibration_data_t *pcal_data) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_xtalk_config_t *pC = &(pdev->xtalk_cfg); + VL53L1_customer_nvm_managed_t *pCN = &(pcal_data->customer); + + LOG_FUNCTION_START(""); + + pcal_data->struct_version = + VL53L1_LL_CALIBRATION_DATA_STRUCT_VERSION; + + + + memcpy( + &(pcal_data->customer), + &(pdev->customer), + sizeof(VL53L1_customer_nvm_managed_t)); + + + + + + + if (pC->algo__crosstalk_compensation_plane_offset_kcps > 0xFFFF) { + pCN->algo__crosstalk_compensation_plane_offset_kcps = + 0xFFFF; + } else { + pCN->algo__crosstalk_compensation_plane_offset_kcps = + (uint16_t)pC->algo__crosstalk_compensation_plane_offset_kcps; + } + pCN->algo__crosstalk_compensation_x_plane_gradient_kcps = + pC->algo__crosstalk_compensation_x_plane_gradient_kcps; + pCN->algo__crosstalk_compensation_y_plane_gradient_kcps = + pC->algo__crosstalk_compensation_y_plane_gradient_kcps; + + + + memcpy( + &(pcal_data->fmt_dmax_cal), + &(pdev->fmt_dmax_cal), + sizeof(VL53L1_dmax_calibration_data_t)); + + + + memcpy( + &(pcal_data->cust_dmax_cal), + &(pdev->cust_dmax_cal), + sizeof(VL53L1_dmax_calibration_data_t)); + + + + memcpy( + &(pcal_data->add_off_cal_data), + &(pdev->add_off_cal_data), + sizeof(VL53L1_additional_offset_cal_data_t)); + + + + memcpy( + &(pcal_data->optical_centre), + &(pdev->optical_centre), + sizeof(VL53L1_optical_centre_t)); + + + + memcpy( + &(pcal_data->xtalkhisto), + &(pdev->xtalk_shapes), + sizeof(VL53L1_xtalk_histogram_data_t)); + + + + memcpy( + &(pcal_data->gain_cal), + &(pdev->gain_cal), + sizeof(VL53L1_gain_calibration_data_t)); + + + + memcpy( + &(pcal_data->cal_peak_rate_map), + &(pdev->cal_peak_rate_map), + sizeof(VL53L1_cal_peak_rate_map_t)); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_inter_measurement_period_ms( + VL53L1_DEV Dev, + uint32_t inter_measurement_period_ms) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + if (pdev->dbg_results.result__osc_calibrate_val == 0) + status = VL53L1_ERROR_DIVISION_BY_ZERO; + + if (status == VL53L1_ERROR_NONE) { + pdev->inter_measurement_period_ms = inter_measurement_period_ms; + pdev->tim_cfg.system__intermeasurement_period = + inter_measurement_period_ms * + (uint32_t)pdev->dbg_results.result__osc_calibrate_val; + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_inter_measurement_period_ms( + VL53L1_DEV Dev, + uint32_t *pinter_measurement_period_ms) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + if (pdev->dbg_results.result__osc_calibrate_val == 0) + status = VL53L1_ERROR_DIVISION_BY_ZERO; + + if (status == VL53L1_ERROR_NONE) + *pinter_measurement_period_ms = + pdev->tim_cfg.system__intermeasurement_period / + (uint32_t)pdev->dbg_results.result__osc_calibrate_val; + + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_timeouts_us( + VL53L1_DEV Dev, + uint32_t phasecal_config_timeout_us, + uint32_t mm_config_timeout_us, + uint32_t range_config_timeout_us) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + if (pdev->stat_nvm.osc_measured__fast_osc__frequency == 0) + status = VL53L1_ERROR_DIVISION_BY_ZERO; + + if (status == VL53L1_ERROR_NONE) { + + pdev->phasecal_config_timeout_us = phasecal_config_timeout_us; + pdev->mm_config_timeout_us = mm_config_timeout_us; + pdev->range_config_timeout_us = range_config_timeout_us; + + status = + VL53L1_calc_timeout_register_values( + phasecal_config_timeout_us, + mm_config_timeout_us, + range_config_timeout_us, + pdev->stat_nvm.osc_measured__fast_osc__frequency, + &(pdev->gen_cfg), + &(pdev->tim_cfg)); + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_timeouts_us( + VL53L1_DEV Dev, + uint32_t *pphasecal_config_timeout_us, + uint32_t *pmm_config_timeout_us, + uint32_t *prange_config_timeout_us) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + + uint32_t macro_period_us = 0; + uint16_t timeout_encoded = 0; + + LOG_FUNCTION_START(""); + + if (pdev->stat_nvm.osc_measured__fast_osc__frequency == 0) + status = VL53L1_ERROR_DIVISION_BY_ZERO; + + if (status == VL53L1_ERROR_NONE) { + + + + macro_period_us = + VL53L1_calc_macro_period_us( + pdev->stat_nvm.osc_measured__fast_osc__frequency, + pdev->tim_cfg.range_config__vcsel_period_a); + + + + + *pphasecal_config_timeout_us = + VL53L1_calc_timeout_us( + (uint32_t)pdev->gen_cfg.phasecal_config__timeout_macrop, + macro_period_us); + + + + + timeout_encoded = + (uint16_t)pdev->tim_cfg.mm_config__timeout_macrop_a_hi; + timeout_encoded = (timeout_encoded << 8) + + (uint16_t)pdev->tim_cfg.mm_config__timeout_macrop_a_lo; + + *pmm_config_timeout_us = + VL53L1_calc_decoded_timeout_us( + timeout_encoded, + macro_period_us); + + + + + timeout_encoded = + (uint16_t)pdev->tim_cfg.range_config__timeout_macrop_a_hi; + timeout_encoded = (timeout_encoded << 8) + + (uint16_t)pdev->tim_cfg.range_config__timeout_macrop_a_lo; + + *prange_config_timeout_us = + VL53L1_calc_decoded_timeout_us( + timeout_encoded, + macro_period_us); + + pdev->phasecal_config_timeout_us = *pphasecal_config_timeout_us; + pdev->mm_config_timeout_us = *pmm_config_timeout_us; + pdev->range_config_timeout_us = *prange_config_timeout_us; + + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_calibration_repeat_period( + VL53L1_DEV Dev, + uint16_t cal_config__repeat_period) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + + pdev->gen_cfg.cal_config__repeat_rate = cal_config__repeat_period; + + return status; + +} + + +VL53L1_Error VL53L1_get_calibration_repeat_period( + VL53L1_DEV Dev, + uint16_t *pcal_config__repeat_period) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + + *pcal_config__repeat_period = pdev->gen_cfg.cal_config__repeat_rate; + + return status; + +} + + +VL53L1_Error VL53L1_set_sequence_config_bit( + VL53L1_DEV Dev, + VL53L1_DeviceSequenceConfig bit_id, + uint8_t value) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + + uint8_t bit_mask = 0x01; + uint8_t clr_mask = 0xFF - bit_mask; + uint8_t bit_value = value & bit_mask; + + if (bit_id <= VL53L1_DEVICESEQUENCECONFIG_RANGE) { + + if (bit_id > 0) { + bit_mask = 0x01 << bit_id; + bit_value = bit_value << bit_id; + clr_mask = 0xFF - bit_mask; + } + + pdev->dyn_cfg.system__sequence_config = + (pdev->dyn_cfg.system__sequence_config & clr_mask) | + bit_value; + + } else { + status = VL53L1_ERROR_INVALID_PARAMS; + } + + return status; + +} + + +VL53L1_Error VL53L1_get_sequence_config_bit( + VL53L1_DEV Dev, + VL53L1_DeviceSequenceConfig bit_id, + uint8_t *pvalue) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + + uint8_t bit_mask = 0x01; + + if (bit_id <= VL53L1_DEVICESEQUENCECONFIG_RANGE) { + + if (bit_id > 0) + bit_mask = 0x01 << bit_id; + + *pvalue = + pdev->dyn_cfg.system__sequence_config & bit_mask; + + if (bit_id > 0) + *pvalue = *pvalue >> bit_id; + + } else { + status = VL53L1_ERROR_INVALID_PARAMS; + } + + return status; +} + + +VL53L1_Error VL53L1_set_interrupt_polarity( + VL53L1_DEV Dev, + VL53L1_DeviceInterruptPolarity interrupt_polarity) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + + pdev->stat_cfg.gpio_hv_mux__ctrl = + (pdev->stat_cfg.gpio_hv_mux__ctrl & + VL53L1_DEVICEINTERRUPTPOLARITY_CLEAR_MASK) | + (interrupt_polarity & + VL53L1_DEVICEINTERRUPTPOLARITY_BIT_MASK); + + return status; + +} + + +VL53L1_Error VL53L1_set_refspadchar_config_struct( + VL53L1_DEV Dev, + VL53L1_refspadchar_config_t *pdata) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + pdev->refspadchar.device_test_mode = pdata->device_test_mode; + pdev->refspadchar.VL53L1_p_009 = pdata->VL53L1_p_009; + pdev->refspadchar.timeout_us = pdata->timeout_us; + pdev->refspadchar.target_count_rate_mcps = + pdata->target_count_rate_mcps; + pdev->refspadchar.min_count_rate_limit_mcps = + pdata->min_count_rate_limit_mcps; + pdev->refspadchar.max_count_rate_limit_mcps = + pdata->max_count_rate_limit_mcps; + + LOG_FUNCTION_END(status); + + return status; +} + +VL53L1_Error VL53L1_get_refspadchar_config_struct( + VL53L1_DEV Dev, + VL53L1_refspadchar_config_t *pdata) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + pdata->device_test_mode = pdev->refspadchar.device_test_mode; + pdata->VL53L1_p_009 = pdev->refspadchar.VL53L1_p_009; + pdata->timeout_us = pdev->refspadchar.timeout_us; + pdata->target_count_rate_mcps = + pdev->refspadchar.target_count_rate_mcps; + pdata->min_count_rate_limit_mcps = + pdev->refspadchar.min_count_rate_limit_mcps; + pdata->max_count_rate_limit_mcps = + pdev->refspadchar.max_count_rate_limit_mcps; + + LOG_FUNCTION_END(status); + + return status; +} + + + +VL53L1_Error VL53L1_set_range_ignore_threshold( + VL53L1_DEV Dev, + uint8_t range_ignore_thresh_mult, + uint16_t range_ignore_threshold_mcps) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + + pdev->xtalk_cfg.crosstalk_range_ignore_threshold_rate_mcps = + range_ignore_threshold_mcps; + + pdev->xtalk_cfg.crosstalk_range_ignore_threshold_mult = + range_ignore_thresh_mult; + + return status; + +} + +VL53L1_Error VL53L1_get_range_ignore_threshold( + VL53L1_DEV Dev, + uint8_t *prange_ignore_thresh_mult, + uint16_t *prange_ignore_threshold_mcps_internal, + uint16_t *prange_ignore_threshold_mcps_current) +{ + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + + *prange_ignore_thresh_mult = + pdev->xtalk_cfg.crosstalk_range_ignore_threshold_mult; + + *prange_ignore_threshold_mcps_current = + pdev->stat_cfg.algo__range_ignore_threshold_mcps; + + *prange_ignore_threshold_mcps_internal = + pdev->xtalk_cfg.crosstalk_range_ignore_threshold_rate_mcps; + + return status; + +} + + + +VL53L1_Error VL53L1_get_interrupt_polarity( + VL53L1_DEV Dev, + VL53L1_DeviceInterruptPolarity *pinterrupt_polarity) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + + *pinterrupt_polarity = + pdev->stat_cfg.gpio_hv_mux__ctrl & + VL53L1_DEVICEINTERRUPTPOLARITY_BIT_MASK; + + return status; + +} + + +VL53L1_Error VL53L1_set_user_zone( + VL53L1_DEV Dev, + VL53L1_user_zone_t *puser_zone) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + + + VL53L1_encode_row_col( + puser_zone->y_centre, + puser_zone->x_centre, + &(pdev->dyn_cfg.roi_config__user_roi_centre_spad)); + + + + VL53L1_encode_zone_size( + puser_zone->width, + puser_zone->height, + &(pdev->dyn_cfg.roi_config__user_roi_requested_global_xy_size)); + + + + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_user_zone( + VL53L1_DEV Dev, + VL53L1_user_zone_t *puser_zone) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + + + VL53L1_decode_row_col( + pdev->dyn_cfg.roi_config__user_roi_centre_spad, + &(puser_zone->y_centre), + &(puser_zone->x_centre)); + + + + VL53L1_decode_zone_size( + pdev->dyn_cfg.roi_config__user_roi_requested_global_xy_size, + &(puser_zone->width), + &(puser_zone->height)); + + LOG_FUNCTION_END(status); + + return status; +} + + + +VL53L1_Error VL53L1_get_mode_mitigation_roi( + VL53L1_DEV Dev, + VL53L1_user_zone_t *pmm_roi) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + uint8_t x = 0; + uint8_t y = 0; + uint8_t xy_size = 0; + + LOG_FUNCTION_START(""); + + + + VL53L1_decode_row_col( + pdev->nvm_copy_data.roi_config__mode_roi_centre_spad, + &y, + &x); + + pmm_roi->x_centre = x; + pmm_roi->y_centre = y; + + + + + + + + + + + xy_size = pdev->nvm_copy_data.roi_config__mode_roi_xy_size; + + pmm_roi->height = xy_size >> 4; + pmm_roi->width = xy_size & 0x0F; + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_zone_config( + VL53L1_DEV Dev, + VL53L1_zone_config_t *pzone_cfg) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + + + memcpy(&(pdev->zone_cfg.user_zones), &(pzone_cfg->user_zones), + sizeof(pdev->zone_cfg.user_zones)); + + + + pdev->zone_cfg.max_zones = pzone_cfg->max_zones; + pdev->zone_cfg.active_zones = pzone_cfg->active_zones; + + status = VL53L1_init_zone_config_histogram_bins(&pdev->zone_cfg); + + + + + + + + + + + if (pzone_cfg->active_zones == 0) + pdev->gen_cfg.global_config__stream_divider = 0; + else if (pzone_cfg->active_zones < VL53L1_MAX_USER_ZONES) + pdev->gen_cfg.global_config__stream_divider = + pzone_cfg->active_zones + 1; + else + pdev->gen_cfg.global_config__stream_divider = + VL53L1_MAX_USER_ZONES + 1; + + LOG_FUNCTION_END(status); + + return status; + +} + + +VL53L1_Error VL53L1_get_zone_config( + VL53L1_DEV Dev, + VL53L1_zone_config_t *pzone_cfg) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + + + memcpy(pzone_cfg, &(pdev->zone_cfg), sizeof(VL53L1_zone_config_t)); + + LOG_FUNCTION_END(status); + + return status; +} + +VL53L1_Error VL53L1_get_preset_mode_timing_cfg( + VL53L1_DEV Dev, + VL53L1_DevicePresetModes device_preset_mode, + uint16_t *pdss_config__target_total_rate_mcps, + uint32_t *pphasecal_config_timeout_us, + uint32_t *pmm_config_timeout_us, + uint32_t *prange_config_timeout_us) +{ + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + + switch (device_preset_mode) { + + case VL53L1_DEVICEPRESETMODE_STANDARD_RANGING: + case VL53L1_DEVICEPRESETMODE_STANDARD_RANGING_SHORT_RANGE: + case VL53L1_DEVICEPRESETMODE_STANDARD_RANGING_LONG_RANGE: + case VL53L1_DEVICEPRESETMODE_STANDARD_RANGING_MM1_CAL: + case VL53L1_DEVICEPRESETMODE_STANDARD_RANGING_MM2_CAL: + case VL53L1_DEVICEPRESETMODE_OLT: + *pdss_config__target_total_rate_mcps = + pdev->tuning_parms.tp_dss_target_lite_mcps; + *pphasecal_config_timeout_us = + pdev->tuning_parms.tp_phasecal_timeout_lite_us; + *pmm_config_timeout_us = + pdev->tuning_parms.tp_mm_timeout_lite_us; + *prange_config_timeout_us = + pdev->tuning_parms.tp_range_timeout_lite_us; + break; + + case VL53L1_DEVICEPRESETMODE_TIMED_RANGING: + case VL53L1_DEVICEPRESETMODE_TIMED_RANGING_SHORT_RANGE: + case VL53L1_DEVICEPRESETMODE_TIMED_RANGING_LONG_RANGE: + case VL53L1_DEVICEPRESETMODE_SINGLESHOT_RANGING: + *pdss_config__target_total_rate_mcps = + pdev->tuning_parms.tp_dss_target_timed_mcps; + *pphasecal_config_timeout_us = + pdev->tuning_parms.tp_phasecal_timeout_timed_us; + *pmm_config_timeout_us = + pdev->tuning_parms.tp_mm_timeout_timed_us; + *prange_config_timeout_us = + pdev->tuning_parms.tp_range_timeout_timed_us; + break; + + case VL53L1_DEVICEPRESETMODE_LOWPOWERAUTO_SHORT_RANGE: + case VL53L1_DEVICEPRESETMODE_LOWPOWERAUTO_MEDIUM_RANGE: + case VL53L1_DEVICEPRESETMODE_LOWPOWERAUTO_LONG_RANGE: + *pdss_config__target_total_rate_mcps = + pdev->tuning_parms.tp_dss_target_timed_mcps; + *pphasecal_config_timeout_us = + pdev->tuning_parms.tp_phasecal_timeout_timed_us; + *pmm_config_timeout_us = + pdev->tuning_parms.tp_mm_timeout_lpa_us; + *prange_config_timeout_us = + pdev->tuning_parms.tp_range_timeout_lpa_us; + break; + + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_RANGING: + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_RANGING_WITH_MM1: + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_RANGING_WITH_MM2: + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_RANGING_MM1_CAL: + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_RANGING_MM2_CAL: + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_REF_ARRAY: + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_LONG_RANGE: + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_LONG_RANGE_MM1: + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_LONG_RANGE_MM2: + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_CHARACTERISATION: + *pdss_config__target_total_rate_mcps = + pdev->tuning_parms.tp_dss_target_histo_mcps; + *pphasecal_config_timeout_us = + pdev->tuning_parms.tp_phasecal_timeout_hist_long_us; + *pmm_config_timeout_us = + pdev->tuning_parms.tp_mm_timeout_histo_us; + *prange_config_timeout_us = + pdev->tuning_parms.tp_range_timeout_histo_us; + + break; + + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_MULTIZONE: + *pdss_config__target_total_rate_mcps = + pdev->tuning_parms.tp_dss_target_histo_mz_mcps; + *pphasecal_config_timeout_us = + pdev->tuning_parms.tp_phasecal_timeout_mz_med_us; + *pmm_config_timeout_us = + pdev->tuning_parms.tp_mm_timeout_mz_us; + *prange_config_timeout_us = + pdev->tuning_parms.tp_range_timeout_mz_us; + break; + + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_MULTIZONE_SHORT_RANGE: + *pdss_config__target_total_rate_mcps = + pdev->tuning_parms.tp_dss_target_histo_mz_mcps; + *pphasecal_config_timeout_us = + pdev->tuning_parms.tp_phasecal_timeout_mz_short_us; + *pmm_config_timeout_us = + pdev->tuning_parms.tp_mm_timeout_mz_us; + *prange_config_timeout_us = + pdev->tuning_parms.tp_range_timeout_mz_us; + break; + + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_MULTIZONE_LONG_RANGE: + *pdss_config__target_total_rate_mcps = + pdev->tuning_parms.tp_dss_target_histo_mz_mcps; + *pphasecal_config_timeout_us = + pdev->tuning_parms.tp_phasecal_timeout_mz_long_us; + *pmm_config_timeout_us = + pdev->tuning_parms.tp_mm_timeout_mz_us; + *prange_config_timeout_us = + pdev->tuning_parms.tp_range_timeout_mz_us; + break; + + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_RANGING_SHORT_TIMING: + *pdss_config__target_total_rate_mcps = + pdev->tuning_parms.tp_dss_target_histo_mcps; + *pphasecal_config_timeout_us = + pdev->tuning_parms.tp_phasecal_timeout_hist_short_us; + *pmm_config_timeout_us = + pdev->tuning_parms.tp_mm_timeout_histo_us; + *prange_config_timeout_us = + pdev->tuning_parms.tp_range_timeout_histo_us; + break; + + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_MEDIUM_RANGE: + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_MEDIUM_RANGE_MM1: + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_MEDIUM_RANGE_MM2: + *pdss_config__target_total_rate_mcps = + pdev->tuning_parms.tp_dss_target_histo_mcps; + *pphasecal_config_timeout_us = + pdev->tuning_parms.tp_phasecal_timeout_hist_med_us; + *pmm_config_timeout_us = + pdev->tuning_parms.tp_mm_timeout_histo_us; + *prange_config_timeout_us = + pdev->tuning_parms.tp_range_timeout_histo_us; + break; + + + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_SHORT_RANGE: + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_SHORT_RANGE_MM1: + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_SHORT_RANGE_MM2: + *pdss_config__target_total_rate_mcps = + pdev->tuning_parms.tp_dss_target_histo_mcps; + *pphasecal_config_timeout_us = + pdev->tuning_parms.tp_phasecal_timeout_hist_short_us; + *pmm_config_timeout_us = + pdev->tuning_parms.tp_mm_timeout_histo_us; + *prange_config_timeout_us = + pdev->tuning_parms.tp_range_timeout_histo_us; + break; + + case VL53L1_DEVICEPRESETMODE_SPECIAL_HISTOGRAM_SHORT_RANGE: + *pdss_config__target_total_rate_mcps = + pdev->tuning_parms.tp_dss_target_very_short_mcps; + *pphasecal_config_timeout_us = + pdev->tuning_parms.tp_phasecal_timeout_hist_short_us; + *pmm_config_timeout_us = + pdev->tuning_parms.tp_mm_timeout_histo_us; + *prange_config_timeout_us = + pdev->tuning_parms.tp_range_timeout_histo_us; + break; + + default: + status = VL53L1_ERROR_INVALID_PARAMS; + break; + + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_preset_mode( + VL53L1_DEV Dev, + VL53L1_DevicePresetModes device_preset_mode, + uint16_t dss_config__target_total_rate_mcps, + uint32_t phasecal_config_timeout_us, + uint32_t mm_config_timeout_us, + uint32_t range_config_timeout_us, + uint32_t inter_measurement_period_ms) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_LLDriverResults_t *pres = + VL53L1DevStructGetLLResultsHandle(Dev); + + VL53L1_hist_post_process_config_t *phistpostprocess = + &(pdev->histpostprocess); + + VL53L1_static_config_t *pstatic = &(pdev->stat_cfg); + VL53L1_histogram_config_t *phistogram = &(pdev->hist_cfg); + VL53L1_general_config_t *pgeneral = &(pdev->gen_cfg); + VL53L1_timing_config_t *ptiming = &(pdev->tim_cfg); + VL53L1_dynamic_config_t *pdynamic = &(pdev->dyn_cfg); + VL53L1_system_control_t *psystem = &(pdev->sys_ctrl); + VL53L1_zone_config_t *pzone_cfg = &(pdev->zone_cfg); + VL53L1_tuning_parm_storage_t *ptuning_parms = &(pdev->tuning_parms); + VL53L1_low_power_auto_data_t *plpadata = + &(pdev->low_power_auto_data); + + LOG_FUNCTION_START(""); + + + + pdev->preset_mode = device_preset_mode; + pdev->mm_config_timeout_us = mm_config_timeout_us; + pdev->range_config_timeout_us = range_config_timeout_us; + pdev->inter_measurement_period_ms = inter_measurement_period_ms; + + + + + VL53L1_init_ll_driver_state( + Dev, + VL53L1_DEVICESTATE_SW_STANDBY); + + + + + switch (device_preset_mode) { + + case VL53L1_DEVICEPRESETMODE_STANDARD_RANGING: + status = VL53L1_preset_mode_standard_ranging( + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_STANDARD_RANGING_SHORT_RANGE: + status = VL53L1_preset_mode_standard_ranging_short_range( + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_STANDARD_RANGING_LONG_RANGE: + status = VL53L1_preset_mode_standard_ranging_long_range( + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_STANDARD_RANGING_MM1_CAL: + status = VL53L1_preset_mode_standard_ranging_mm1_cal( + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_STANDARD_RANGING_MM2_CAL: + status = VL53L1_preset_mode_standard_ranging_mm2_cal( + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_TIMED_RANGING: + status = VL53L1_preset_mode_timed_ranging( + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_TIMED_RANGING_SHORT_RANGE: + status = VL53L1_preset_mode_timed_ranging_short_range( + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_TIMED_RANGING_LONG_RANGE: + status = VL53L1_preset_mode_timed_ranging_long_range( + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_RANGING: + status = VL53L1_preset_mode_histogram_ranging( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_RANGING_WITH_MM1: + status = VL53L1_preset_mode_histogram_ranging_with_mm1( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_RANGING_WITH_MM2: + status = VL53L1_preset_mode_histogram_ranging_with_mm2( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_RANGING_MM1_CAL: + status = VL53L1_preset_mode_histogram_ranging_mm1_cal( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_RANGING_MM2_CAL: + status = VL53L1_preset_mode_histogram_ranging_mm2_cal( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_MULTIZONE: + status = VL53L1_preset_mode_histogram_multizone( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_MULTIZONE_SHORT_RANGE: + status = VL53L1_preset_mode_histogram_multizone_short_range( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_MULTIZONE_LONG_RANGE: + status = VL53L1_preset_mode_histogram_multizone_long_range( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_REF_ARRAY: + status = VL53L1_preset_mode_histogram_ranging_ref( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_RANGING_SHORT_TIMING: + status = VL53L1_preset_mode_histogram_ranging_short_timing( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_LONG_RANGE: + status = VL53L1_preset_mode_histogram_long_range( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_LONG_RANGE_MM1: + status = VL53L1_preset_mode_histogram_long_range_mm1( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_LONG_RANGE_MM2: + status = VL53L1_preset_mode_histogram_long_range_mm2( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_MEDIUM_RANGE: + status = VL53L1_preset_mode_histogram_medium_range( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_MEDIUM_RANGE_MM1: + status = VL53L1_preset_mode_histogram_medium_range_mm1( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_MEDIUM_RANGE_MM2: + status = VL53L1_preset_mode_histogram_medium_range_mm2( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_SHORT_RANGE: + status = VL53L1_preset_mode_histogram_short_range( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_SHORT_RANGE_MM1: + status = VL53L1_preset_mode_histogram_short_range_mm1( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_SHORT_RANGE_MM2: + status = VL53L1_preset_mode_histogram_short_range_mm2( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_CHARACTERISATION: + status = VL53L1_preset_mode_histogram_characterisation( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_XTALK_PLANAR: + status = VL53L1_preset_mode_histogram_xtalk_planar( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_XTALK_MM1: + status = VL53L1_preset_mode_histogram_xtalk_mm1( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_XTALK_MM2: + status = VL53L1_preset_mode_histogram_xtalk_mm2( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_OLT: + status = VL53L1_preset_mode_olt( + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_SINGLESHOT_RANGING: + status = VL53L1_preset_mode_singleshot_ranging( + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_LOWPOWERAUTO_SHORT_RANGE: + status = VL53L1_preset_mode_low_power_auto_short_ranging( + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg, + plpadata); + break; + + case VL53L1_DEVICEPRESETMODE_LOWPOWERAUTO_MEDIUM_RANGE: + status = VL53L1_preset_mode_low_power_auto_ranging( + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg, + plpadata); + break; + + case VL53L1_DEVICEPRESETMODE_LOWPOWERAUTO_LONG_RANGE: + status = VL53L1_preset_mode_low_power_auto_long_ranging( + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg, + plpadata); + break; + + + case VL53L1_DEVICEPRESETMODE_SPECIAL_HISTOGRAM_SHORT_RANGE: + status = VL53L1_preset_mode_special_histogram_short_range( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + default: + status = VL53L1_ERROR_INVALID_PARAMS; + break; + + } + + + + + if (status == VL53L1_ERROR_NONE) { + + pstatic->dss_config__target_total_rate_mcps = + dss_config__target_total_rate_mcps; + pdev->dss_config__target_total_rate_mcps = + dss_config__target_total_rate_mcps; + + } + + + + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_set_timeouts_us( + Dev, + phasecal_config_timeout_us, + mm_config_timeout_us, + range_config_timeout_us); + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_set_inter_measurement_period_ms( + Dev, + inter_measurement_period_ms); + + + + + V53L1_init_zone_results_structure( + pdev->zone_cfg.active_zones+1, + &(pres->zone_results)); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_zone_preset( + VL53L1_DEV Dev, + VL53L1_DeviceZonePreset zone_preset) +{ + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + VL53L1_general_config_t *pgeneral = &(pdev->gen_cfg); + VL53L1_zone_config_t *pzone_cfg = &(pdev->zone_cfg); + + LOG_FUNCTION_START(""); + + + + pdev->zone_preset = zone_preset; + + + + + switch (zone_preset) { + + case VL53L1_DEVICEZONEPRESET_XTALK_PLANAR: + status = + VL53L1_zone_preset_xtalk_planar( + pgeneral, + pzone_cfg); + break; + + case VL53L1_DEVICEZONEPRESET_1X1_SIZE_16X16: + status = + VL53L1_init_zone_config_structure( + 8, 1, 1, + + 8, 1, 1, + + 15, 15, + + pzone_cfg); + break; + + case VL53L1_DEVICEZONEPRESET_1X2_SIZE_16X8: + status = + VL53L1_init_zone_config_structure( + 8, 1, 1, + + 4, 8, 2, + + 15, 7, + + pzone_cfg); + break; + + case VL53L1_DEVICEZONEPRESET_2X1_SIZE_8X16: + status = + VL53L1_init_zone_config_structure( + 4, 8, 2, + + 8, 1, 1, + + 7, 15, + + pzone_cfg); + break; + + case VL53L1_DEVICEZONEPRESET_2X2_SIZE_8X8: + status = + VL53L1_init_zone_config_structure( + 4, 8, 2, + + 4, 8, 2, + + 7, 7, + + pzone_cfg); + break; + + case VL53L1_DEVICEZONEPRESET_3X3_SIZE_5X5: + status = + VL53L1_init_zone_config_structure( + 2, 5, 3, + + 2, 5, 3, + + 4, 4, + + pzone_cfg); + break; + + case VL53L1_DEVICEZONEPRESET_4X4_SIZE_4X4: + status = + VL53L1_init_zone_config_structure( + 2, 4, 4, + + 2, 4, 4, + + 3, 3, + + pzone_cfg); + break; + + case VL53L1_DEVICEZONEPRESET_5X5_SIZE_4X4: + status = + VL53L1_init_zone_config_structure( + 2, 3, 5, + + 2, 3, 5, + + 3, 3, + + pzone_cfg); + break; + + case VL53L1_DEVICEZONEPRESET_11X11_SIZE_5X5: + status = + VL53L1_init_zone_config_structure( + 3, 1, 11, + + 3, 1, 11, + + 4, 4, + + pzone_cfg); + break; + + case VL53L1_DEVICEZONEPRESET_13X13_SIZE_4X4: + status = + VL53L1_init_zone_config_structure( + 2, 1, 13, + + 2, 1, 13, + + 3, 3, + + pzone_cfg); + + break; + + case VL53L1_DEVICEZONEPRESET_1X1_SIZE_4X4_POS_8X8: + status = + VL53L1_init_zone_config_structure( + 8, 1, 1, + + 8, 1, 1, + + 3, 3, + + pzone_cfg); + break; + + } + + + + + + + + + + + if (pzone_cfg->active_zones == 0) + pdev->gen_cfg.global_config__stream_divider = 0; + else if (pzone_cfg->active_zones < VL53L1_MAX_USER_ZONES) + pdev->gen_cfg.global_config__stream_divider = + pzone_cfg->active_zones + 1; + else + pdev->gen_cfg.global_config__stream_divider = + VL53L1_MAX_USER_ZONES + 1; + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_enable_xtalk_compensation( + VL53L1_DEV Dev) +{ + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint32_t tempu32; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_xtalk_config_t *pC = &(pdev->xtalk_cfg); + VL53L1_hist_post_process_config_t *pHP = &(pdev->histpostprocess); + VL53L1_customer_nvm_managed_t *pN = &(pdev->customer); + + LOG_FUNCTION_START(""); + + + + tempu32 = VL53L1_calc_crosstalk_plane_offset_with_margin( + pC->algo__crosstalk_compensation_plane_offset_kcps, + pC->lite_mode_crosstalk_margin_kcps); + if (tempu32 > 0xFFFF) + tempu32 = 0xFFFF; + + pN->algo__crosstalk_compensation_plane_offset_kcps = + (uint16_t)tempu32; + + pN->algo__crosstalk_compensation_x_plane_gradient_kcps = + pC->algo__crosstalk_compensation_x_plane_gradient_kcps; + + pN->algo__crosstalk_compensation_y_plane_gradient_kcps = + pC->algo__crosstalk_compensation_y_plane_gradient_kcps; + + + + pHP->algo__crosstalk_compensation_plane_offset_kcps = + VL53L1_calc_crosstalk_plane_offset_with_margin( + pC->algo__crosstalk_compensation_plane_offset_kcps, + pC->histogram_mode_crosstalk_margin_kcps); + + pHP->algo__crosstalk_compensation_x_plane_gradient_kcps + = pC->algo__crosstalk_compensation_x_plane_gradient_kcps; + pHP->algo__crosstalk_compensation_y_plane_gradient_kcps + = pC->algo__crosstalk_compensation_y_plane_gradient_kcps; + + + + + pC->global_crosstalk_compensation_enable = 0x01; + + pHP->algo__crosstalk_compensation_enable = + pC->global_crosstalk_compensation_enable; + + + + + + if (status == VL53L1_ERROR_NONE) { + pC->crosstalk_range_ignore_threshold_rate_mcps = + VL53L1_calc_range_ignore_threshold( + pC->algo__crosstalk_compensation_plane_offset_kcps, + pC->algo__crosstalk_compensation_x_plane_gradient_kcps, + pC->algo__crosstalk_compensation_y_plane_gradient_kcps, + pC->crosstalk_range_ignore_threshold_mult); +} + + + + + if (status == VL53L1_ERROR_NONE) + + status = + VL53L1_set_customer_nvm_managed( + Dev, + &(pdev->customer)); + + LOG_FUNCTION_END(status); + + return status; + +} + +void VL53L1_get_xtalk_compensation_enable( + VL53L1_DEV Dev, + uint8_t *pcrosstalk_compensation_enable) +{ + + + + + + + + + + + + + + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + + + + *pcrosstalk_compensation_enable = + pdev->xtalk_cfg.global_crosstalk_compensation_enable; + +} + + +VL53L1_Error VL53L1_get_lite_xtalk_margin_kcps( + VL53L1_DEV Dev, + int16_t *pxtalk_margin) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + *pxtalk_margin = pdev->xtalk_cfg.lite_mode_crosstalk_margin_kcps; + + LOG_FUNCTION_END(status); + + return status; + +} + +VL53L1_Error VL53L1_set_lite_xtalk_margin_kcps( + VL53L1_DEV Dev, + int16_t xtalk_margin) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + pdev->xtalk_cfg.lite_mode_crosstalk_margin_kcps = xtalk_margin; + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_histogram_xtalk_margin_kcps( + VL53L1_DEV Dev, + int16_t *pxtalk_margin) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + *pxtalk_margin = pdev->xtalk_cfg.histogram_mode_crosstalk_margin_kcps; + + LOG_FUNCTION_END(status); + + return status; + +} + +VL53L1_Error VL53L1_set_histogram_xtalk_margin_kcps( + VL53L1_DEV Dev, + int16_t xtalk_margin) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + pdev->xtalk_cfg.histogram_mode_crosstalk_margin_kcps = xtalk_margin; + + LOG_FUNCTION_END(status); + + return status; +} + +VL53L1_Error VL53L1_restore_xtalk_nvm_default( + VL53L1_DEV Dev) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_xtalk_config_t *pC = &(pdev->xtalk_cfg); + + LOG_FUNCTION_START(""); + + pC->algo__crosstalk_compensation_plane_offset_kcps = + pC->nvm_default__crosstalk_compensation_plane_offset_kcps; + pC->algo__crosstalk_compensation_x_plane_gradient_kcps = + pC->nvm_default__crosstalk_compensation_x_plane_gradient_kcps; + pC->algo__crosstalk_compensation_y_plane_gradient_kcps = + pC->nvm_default__crosstalk_compensation_y_plane_gradient_kcps; + + LOG_FUNCTION_END(status); + + return status; +} + +VL53L1_Error VL53L1_disable_xtalk_compensation( + VL53L1_DEV Dev) +{ + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_hist_post_process_config_t *pHP = &(pdev->histpostprocess); + VL53L1_customer_nvm_managed_t *pN = &(pdev->customer); + + LOG_FUNCTION_START(""); + + + + pN->algo__crosstalk_compensation_plane_offset_kcps = + 0x00; + + pN->algo__crosstalk_compensation_x_plane_gradient_kcps = + 0x00; + + pN->algo__crosstalk_compensation_y_plane_gradient_kcps = + 0x00; + + + + + pdev->xtalk_cfg.global_crosstalk_compensation_enable = 0x00; + + pHP->algo__crosstalk_compensation_enable = + pdev->xtalk_cfg.global_crosstalk_compensation_enable; + + + + + if (status == VL53L1_ERROR_NONE) { + pdev->xtalk_cfg.crosstalk_range_ignore_threshold_rate_mcps = + 0x0000; + } + + + + + if (status == VL53L1_ERROR_NONE) { + + status = + VL53L1_set_customer_nvm_managed( + Dev, + &(pdev->customer)); + } + LOG_FUNCTION_END(status); + + return status; + +} + + +VL53L1_Error VL53L1_get_histogram_phase_consistency( + VL53L1_DEV Dev, + uint8_t *pphase_consistency) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_hist_post_process_config_t *pHP = &(pdev->histpostprocess); + + LOG_FUNCTION_START(""); + + *pphase_consistency = + pHP->algo__consistency_check__phase_tolerance; + + LOG_FUNCTION_END(status); + + return status; + +} + +VL53L1_Error VL53L1_set_histogram_phase_consistency( + VL53L1_DEV Dev, + uint8_t phase_consistency) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + pdev->histpostprocess.algo__consistency_check__phase_tolerance = + phase_consistency; + + LOG_FUNCTION_END(status); + + return status; + +} + +VL53L1_Error VL53L1_get_histogram_event_consistency( + VL53L1_DEV Dev, + uint8_t *pevent_consistency) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + *pevent_consistency = + pdev->histpostprocess.algo__consistency_check__event_sigma; + + LOG_FUNCTION_END(status); + + return status; + +} + +VL53L1_Error VL53L1_set_histogram_event_consistency( + VL53L1_DEV Dev, + uint8_t event_consistency) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + pdev->histpostprocess.algo__consistency_check__event_sigma = + event_consistency; + + LOG_FUNCTION_END(status); + + return status; + +} + +VL53L1_Error VL53L1_get_histogram_ambient_threshold_sigma( + VL53L1_DEV Dev, + uint8_t *pamb_thresh_sigma) +{ + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + *pamb_thresh_sigma = + pdev->histpostprocess.ambient_thresh_sigma1; + + LOG_FUNCTION_END(status); + + return status; + +} + +VL53L1_Error VL53L1_set_histogram_ambient_threshold_sigma( + VL53L1_DEV Dev, + uint8_t amb_thresh_sigma) +{ + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + pdev->histpostprocess.ambient_thresh_sigma1 = + amb_thresh_sigma; + + LOG_FUNCTION_END(status); + + return status; + +} + +VL53L1_Error VL53L1_get_lite_sigma_threshold( + VL53L1_DEV Dev, + uint16_t *plite_sigma) +{ + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + *plite_sigma = + pdev->tim_cfg.range_config__sigma_thresh; + + LOG_FUNCTION_END(status); + + return status; + +} + +VL53L1_Error VL53L1_set_lite_sigma_threshold( + VL53L1_DEV Dev, + uint16_t lite_sigma) +{ + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + pdev->tim_cfg.range_config__sigma_thresh = lite_sigma; + + LOG_FUNCTION_END(status); + + return status; + +} + +VL53L1_Error VL53L1_get_lite_min_count_rate( + VL53L1_DEV Dev, + uint16_t *plite_mincountrate) +{ + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + *plite_mincountrate = + pdev->tim_cfg.range_config__min_count_rate_rtn_limit_mcps; + + LOG_FUNCTION_END(status); + + return status; + +} + +VL53L1_Error VL53L1_set_lite_min_count_rate( + VL53L1_DEV Dev, + uint16_t lite_mincountrate) +{ + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + pdev->tim_cfg.range_config__min_count_rate_rtn_limit_mcps = + lite_mincountrate; + + LOG_FUNCTION_END(status); + + return status; + +} + + +VL53L1_Error VL53L1_get_xtalk_detect_config( + VL53L1_DEV Dev, + int16_t *pmax_valid_range_mm, + int16_t *pmin_valid_range_mm, + uint16_t *pmax_valid_rate_kcps, + uint16_t *pmax_sigma_mm) +{ + + + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + *pmax_valid_range_mm = + pdev->xtalk_cfg.algo__crosstalk_detect_max_valid_range_mm; + *pmin_valid_range_mm = + pdev->xtalk_cfg.algo__crosstalk_detect_min_valid_range_mm; + *pmax_valid_rate_kcps = + pdev->xtalk_cfg.algo__crosstalk_detect_max_valid_rate_kcps; + *pmax_sigma_mm = + pdev->xtalk_cfg.algo__crosstalk_detect_max_sigma_mm; + + LOG_FUNCTION_END(status); + + return status; + +} + +VL53L1_Error VL53L1_set_xtalk_detect_config( + VL53L1_DEV Dev, + int16_t max_valid_range_mm, + int16_t min_valid_range_mm, + uint16_t max_valid_rate_kcps, + uint16_t max_sigma_mm) +{ + + + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + pdev->xtalk_cfg.algo__crosstalk_detect_max_valid_range_mm = + max_valid_range_mm; + pdev->xtalk_cfg.algo__crosstalk_detect_min_valid_range_mm = + min_valid_range_mm; + pdev->xtalk_cfg.algo__crosstalk_detect_max_valid_rate_kcps = + max_valid_rate_kcps; + pdev->xtalk_cfg.algo__crosstalk_detect_max_sigma_mm = + max_sigma_mm; + + LOG_FUNCTION_END(status); + + return status; + +} + +VL53L1_Error VL53L1_get_target_order_mode( + VL53L1_DEV Dev, + VL53L1_HistTargetOrder *phist_target_order) +{ + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + *phist_target_order = + pdev->histpostprocess.hist_target_order; + + LOG_FUNCTION_END(status); + + return status; + +} + +VL53L1_Error VL53L1_set_target_order_mode( + VL53L1_DEV Dev, + VL53L1_HistTargetOrder hist_target_order) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + pdev->histpostprocess.hist_target_order = hist_target_order; + + LOG_FUNCTION_END(status); + + return status; + +} + + +VL53L1_Error VL53L1_get_dmax_reflectance_values( + VL53L1_DEV Dev, + VL53L1_dmax_reflectance_array_t *pdmax_reflectances) +{ + + VL53L1_Error status = VL53L1_ERROR_NONE; + + uint8_t i = 0; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + + + + + + + + for (i = 0; i < VL53L1_MAX_AMBIENT_DMAX_VALUES; i++) { + pdmax_reflectances->target_reflectance_for_dmax[i] = + pdev->dmax_cfg.target_reflectance_for_dmax_calc[i]; + } + + LOG_FUNCTION_END(status); + + return status; + +} + +VL53L1_Error VL53L1_set_dmax_reflectance_values( + VL53L1_DEV Dev, + VL53L1_dmax_reflectance_array_t *pdmax_reflectances) +{ + + VL53L1_Error status = VL53L1_ERROR_NONE; + + uint8_t i = 0; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + + + + + + + + for (i = 0; i < VL53L1_MAX_AMBIENT_DMAX_VALUES; i++) { + pdev->dmax_cfg.target_reflectance_for_dmax_calc[i] = + pdmax_reflectances->target_reflectance_for_dmax[i]; + } + + LOG_FUNCTION_END(status); + + return status; + +} + +VL53L1_Error VL53L1_get_vhv_loopbound( + VL53L1_DEV Dev, + uint8_t *pvhv_loopbound) +{ + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + *pvhv_loopbound = + pdev->stat_nvm.vhv_config__timeout_macrop_loop_bound / 4; + + LOG_FUNCTION_END(status); + + return status; + +} + + + +VL53L1_Error VL53L1_set_vhv_loopbound( + VL53L1_DEV Dev, + uint8_t vhv_loopbound) +{ + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + pdev->stat_nvm.vhv_config__timeout_macrop_loop_bound = + (pdev->stat_nvm.vhv_config__timeout_macrop_loop_bound & 0x03) + + (vhv_loopbound * 4); + + LOG_FUNCTION_END(status); + + return status; + +} + + + +VL53L1_Error VL53L1_get_vhv_config( + VL53L1_DEV Dev, + uint8_t *pvhv_init_en, + uint8_t *pvhv_init_value) +{ + + + + + + + + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + *pvhv_init_en = (pdev->stat_nvm.vhv_config__init & 0x80) >> 7; + *pvhv_init_value = + (pdev->stat_nvm.vhv_config__init & 0x7F); + + LOG_FUNCTION_END(status); + + return status; + +} + + + +VL53L1_Error VL53L1_set_vhv_config( + VL53L1_DEV Dev, + uint8_t vhv_init_en, + uint8_t vhv_init_value) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + pdev->stat_nvm.vhv_config__init = + ((vhv_init_en & 0x01) << 7) + + (vhv_init_value & 0x7F); + + LOG_FUNCTION_END(status); + + return status; + +} + + + +VL53L1_Error VL53L1_init_and_start_range( + VL53L1_DEV Dev, + uint8_t measurement_mode, + VL53L1_DeviceConfigLevel device_config_level) +{ + + + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_LLDriverResults_t *pres = + VL53L1DevStructGetLLResultsHandle(Dev); + + uint8_t buffer[VL53L1_MAX_I2C_XFER_SIZE]; + + VL53L1_static_nvm_managed_t *pstatic_nvm = &(pdev->stat_nvm); + VL53L1_customer_nvm_managed_t *pcustomer_nvm = &(pdev->customer); + VL53L1_static_config_t *pstatic = &(pdev->stat_cfg); + VL53L1_general_config_t *pgeneral = &(pdev->gen_cfg); + VL53L1_timing_config_t *ptiming = &(pdev->tim_cfg); + VL53L1_dynamic_config_t *pdynamic = &(pdev->dyn_cfg); + VL53L1_system_control_t *psystem = &(pdev->sys_ctrl); + + VL53L1_ll_driver_state_t *pstate = &(pdev->ll_state); + VL53L1_customer_nvm_managed_t *pN = &(pdev->customer); + + uint8_t *pbuffer = &buffer[0]; + uint16_t i = 0; + uint16_t i2c_index = 0; + uint16_t i2c_buffer_offset_bytes = 0; + uint16_t i2c_buffer_size_bytes = 0; + + LOG_FUNCTION_START(""); + + + + pdev->measurement_mode = measurement_mode; + + + + + psystem->system__mode_start = + (psystem->system__mode_start & + VL53L1_DEVICEMEASUREMENTMODE_STOP_MASK) | + measurement_mode; + + + + + + + status = + VL53L1_set_user_zone( + Dev, + &(pdev->zone_cfg.user_zones[pdev->ll_state.cfg_zone_id])); + + + + + + if (pdev->zone_cfg.active_zones > 0) { + status = + VL53L1_set_zone_dss_config( + Dev, + &(pres->zone_dyn_cfgs.VL53L1_p_002[pdev->ll_state.cfg_zone_id]) + ); + } + + + + + + + if (((pdev->sys_ctrl.system__mode_start & + VL53L1_DEVICESCHEDULERMODE_HISTOGRAM) == 0x00) && + (pdev->xtalk_cfg.global_crosstalk_compensation_enable + == 0x01)) { + pdev->stat_cfg.algo__range_ignore_threshold_mcps = + pdev->xtalk_cfg.crosstalk_range_ignore_threshold_rate_mcps; + } + + + + + + + + + if (pdev->low_power_auto_data.low_power_auto_range_count == 0xFF) + pdev->low_power_auto_data.low_power_auto_range_count = 0x0; + + + + if ((pdev->low_power_auto_data.is_low_power_auto_mode == 1) && + (pdev->low_power_auto_data.low_power_auto_range_count == 0)) { + + + pdev->low_power_auto_data.saved_interrupt_config = + pdev->gen_cfg.system__interrupt_config_gpio; + + + pdev->gen_cfg.system__interrupt_config_gpio = 1 << 5; + + + if ((pdev->dyn_cfg.system__sequence_config & ( + VL53L1_SEQUENCE_MM1_EN | VL53L1_SEQUENCE_MM2_EN)) == + 0x0) { + pN->algo__part_to_part_range_offset_mm = + (pN->mm_config__outer_offset_mm << 2); + } else { + pN->algo__part_to_part_range_offset_mm = 0x0; + } + + + + if (device_config_level < + VL53L1_DEVICECONFIGLEVEL_CUSTOMER_ONWARDS) { + device_config_level = + VL53L1_DEVICECONFIGLEVEL_CUSTOMER_ONWARDS; + } + } + + if ((pdev->low_power_auto_data.is_low_power_auto_mode == 1) && + (pdev->low_power_auto_data.low_power_auto_range_count == 1)) { + + + pdev->gen_cfg.system__interrupt_config_gpio = + pdev->low_power_auto_data.saved_interrupt_config; + + + + device_config_level = VL53L1_DEVICECONFIGLEVEL_FULL; + } + + + + + + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_save_cfg_data(Dev); + + + + + + + switch (device_config_level) { + case VL53L1_DEVICECONFIGLEVEL_FULL: + i2c_index = VL53L1_STATIC_NVM_MANAGED_I2C_INDEX; + break; + case VL53L1_DEVICECONFIGLEVEL_CUSTOMER_ONWARDS: + i2c_index = VL53L1_CUSTOMER_NVM_MANAGED_I2C_INDEX; + break; + case VL53L1_DEVICECONFIGLEVEL_STATIC_ONWARDS: + i2c_index = VL53L1_STATIC_CONFIG_I2C_INDEX; + break; + case VL53L1_DEVICECONFIGLEVEL_GENERAL_ONWARDS: + i2c_index = VL53L1_GENERAL_CONFIG_I2C_INDEX; + break; + case VL53L1_DEVICECONFIGLEVEL_TIMING_ONWARDS: + i2c_index = VL53L1_TIMING_CONFIG_I2C_INDEX; + break; + case VL53L1_DEVICECONFIGLEVEL_DYNAMIC_ONWARDS: + i2c_index = VL53L1_DYNAMIC_CONFIG_I2C_INDEX; + break; + default: + i2c_index = VL53L1_SYSTEM_CONTROL_I2C_INDEX; + break; + } + + + + + i2c_buffer_size_bytes = + (VL53L1_SYSTEM_CONTROL_I2C_INDEX + + VL53L1_SYSTEM_CONTROL_I2C_SIZE_BYTES) - + i2c_index; + + + + + pbuffer = &buffer[0]; + for (i = 0; i < i2c_buffer_size_bytes; i++) + *pbuffer++ = 0; + + + + + if (device_config_level >= VL53L1_DEVICECONFIGLEVEL_FULL && + status == VL53L1_ERROR_NONE) { + + i2c_buffer_offset_bytes = + VL53L1_STATIC_NVM_MANAGED_I2C_INDEX - i2c_index; + + status = + VL53L1_i2c_encode_static_nvm_managed( + pstatic_nvm, + VL53L1_STATIC_NVM_MANAGED_I2C_SIZE_BYTES, + &buffer[i2c_buffer_offset_bytes]); + } + + if (device_config_level >= VL53L1_DEVICECONFIGLEVEL_CUSTOMER_ONWARDS && + status == VL53L1_ERROR_NONE) { + + i2c_buffer_offset_bytes = + VL53L1_CUSTOMER_NVM_MANAGED_I2C_INDEX - i2c_index; + + status = + VL53L1_i2c_encode_customer_nvm_managed( + pcustomer_nvm, + VL53L1_CUSTOMER_NVM_MANAGED_I2C_SIZE_BYTES, + &buffer[i2c_buffer_offset_bytes]); + } + + if (device_config_level >= VL53L1_DEVICECONFIGLEVEL_STATIC_ONWARDS && + status == VL53L1_ERROR_NONE) { + + i2c_buffer_offset_bytes = + VL53L1_STATIC_CONFIG_I2C_INDEX - i2c_index; + + status = + VL53L1_i2c_encode_static_config( + pstatic, + VL53L1_STATIC_CONFIG_I2C_SIZE_BYTES, + &buffer[i2c_buffer_offset_bytes]); + } + + if (device_config_level >= VL53L1_DEVICECONFIGLEVEL_GENERAL_ONWARDS && + status == VL53L1_ERROR_NONE) { + + i2c_buffer_offset_bytes = + VL53L1_GENERAL_CONFIG_I2C_INDEX - i2c_index; + + status = + VL53L1_i2c_encode_general_config( + pgeneral, + VL53L1_GENERAL_CONFIG_I2C_SIZE_BYTES, + &buffer[i2c_buffer_offset_bytes]); + } + + if (device_config_level >= VL53L1_DEVICECONFIGLEVEL_TIMING_ONWARDS && + status == VL53L1_ERROR_NONE) { + + i2c_buffer_offset_bytes = + VL53L1_TIMING_CONFIG_I2C_INDEX - i2c_index; + + status = + VL53L1_i2c_encode_timing_config( + ptiming, + VL53L1_TIMING_CONFIG_I2C_SIZE_BYTES, + &buffer[i2c_buffer_offset_bytes]); + } + + if (device_config_level >= VL53L1_DEVICECONFIGLEVEL_DYNAMIC_ONWARDS && + status == VL53L1_ERROR_NONE) { + + i2c_buffer_offset_bytes = + VL53L1_DYNAMIC_CONFIG_I2C_INDEX - i2c_index; + + + + if ((psystem->system__mode_start & + VL53L1_DEVICEMEASUREMENTMODE_BACKTOBACK) == + VL53L1_DEVICEMEASUREMENTMODE_BACKTOBACK) { + pdynamic->system__grouped_parameter_hold_0 = + pstate->cfg_gph_id | 0x01; + pdynamic->system__grouped_parameter_hold_1 = + pstate->cfg_gph_id | 0x01; + pdynamic->system__grouped_parameter_hold = + pstate->cfg_gph_id; + } + status = + VL53L1_i2c_encode_dynamic_config( + pdynamic, + VL53L1_DYNAMIC_CONFIG_I2C_SIZE_BYTES, + &buffer[i2c_buffer_offset_bytes]); + } + + if (status == VL53L1_ERROR_NONE) { + + i2c_buffer_offset_bytes = + VL53L1_SYSTEM_CONTROL_I2C_INDEX - i2c_index; + + status = + VL53L1_i2c_encode_system_control( + psystem, + VL53L1_SYSTEM_CONTROL_I2C_SIZE_BYTES, + &buffer[i2c_buffer_offset_bytes]); + } + + + + + if (status == VL53L1_ERROR_NONE) { + status = + VL53L1_WriteMulti( + Dev, + i2c_index, + buffer, + (uint32_t)i2c_buffer_size_bytes); + } + + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_update_ll_driver_rd_state(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_update_ll_driver_cfg_state(Dev); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_stop_range( + VL53L1_DEV Dev) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_LLDriverResults_t *pres = + VL53L1DevStructGetLLResultsHandle(Dev); + + + + + pdev->sys_ctrl.system__mode_start = + (pdev->sys_ctrl.system__mode_start & + VL53L1_DEVICEMEASUREMENTMODE_STOP_MASK) | + VL53L1_DEVICEMEASUREMENTMODE_ABORT; + + status = VL53L1_set_system_control( + Dev, + &pdev->sys_ctrl); + + + + pdev->sys_ctrl.system__mode_start = + (pdev->sys_ctrl.system__mode_start & + VL53L1_DEVICEMEASUREMENTMODE_STOP_MASK); + + + + VL53L1_init_ll_driver_state( + Dev, + VL53L1_DEVICESTATE_SW_STANDBY); + + + + V53L1_init_zone_results_structure( + pdev->zone_cfg.active_zones+1, + &(pres->zone_results)); + + + + V53L1_init_zone_dss_configs(Dev); + + + + if (pdev->low_power_auto_data.is_low_power_auto_mode == 1) + VL53L1_low_power_auto_data_stop_range(Dev); + + return status; +} + + +VL53L1_Error VL53L1_get_measurement_results( + VL53L1_DEV Dev, + VL53L1_DeviceResultsLevel device_results_level) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + uint8_t buffer[VL53L1_MAX_I2C_XFER_SIZE]; + + VL53L1_system_results_t *psystem_results = &(pdev->sys_results); + VL53L1_core_results_t *pcore_results = &(pdev->core_results); + VL53L1_debug_results_t *pdebug_results = &(pdev->dbg_results); + + uint16_t i2c_index = VL53L1_SYSTEM_RESULTS_I2C_INDEX; + uint16_t i2c_buffer_offset_bytes = 0; + uint16_t i2c_buffer_size_bytes = 0; + + LOG_FUNCTION_START(""); + + + + + switch (device_results_level) { + case VL53L1_DEVICERESULTSLEVEL_FULL: + i2c_buffer_size_bytes = + (VL53L1_DEBUG_RESULTS_I2C_INDEX + + VL53L1_DEBUG_RESULTS_I2C_SIZE_BYTES) - + i2c_index; + break; + case VL53L1_DEVICERESULTSLEVEL_UPTO_CORE: + i2c_buffer_size_bytes = + (VL53L1_CORE_RESULTS_I2C_INDEX + + VL53L1_CORE_RESULTS_I2C_SIZE_BYTES) - + i2c_index; + break; + default: + i2c_buffer_size_bytes = + VL53L1_SYSTEM_RESULTS_I2C_SIZE_BYTES; + break; + } + + + + + if (status == VL53L1_ERROR_NONE) + + status = + VL53L1_ReadMulti( + Dev, + i2c_index, + buffer, + (uint32_t)i2c_buffer_size_bytes); + + + + + if (device_results_level >= VL53L1_DEVICERESULTSLEVEL_FULL && + status == VL53L1_ERROR_NONE) { + + i2c_buffer_offset_bytes = + VL53L1_DEBUG_RESULTS_I2C_INDEX - i2c_index; + + status = + VL53L1_i2c_decode_debug_results( + VL53L1_DEBUG_RESULTS_I2C_SIZE_BYTES, + &buffer[i2c_buffer_offset_bytes], + pdebug_results); + } + + if (device_results_level >= VL53L1_DEVICERESULTSLEVEL_UPTO_CORE && + status == VL53L1_ERROR_NONE) { + + i2c_buffer_offset_bytes = + VL53L1_CORE_RESULTS_I2C_INDEX - i2c_index; + + status = + VL53L1_i2c_decode_core_results( + VL53L1_CORE_RESULTS_I2C_SIZE_BYTES, + &buffer[i2c_buffer_offset_bytes], + pcore_results); + } + + if (status == VL53L1_ERROR_NONE) { + + i2c_buffer_offset_bytes = 0; + status = + VL53L1_i2c_decode_system_results( + VL53L1_SYSTEM_RESULTS_I2C_SIZE_BYTES, + &buffer[i2c_buffer_offset_bytes], + psystem_results); + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_device_results( + VL53L1_DEV Dev, + VL53L1_DeviceResultsLevel device_results_level, + VL53L1_range_results_t *prange_results) +{ + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_LLDriverResults_t *pres = + VL53L1DevStructGetLLResultsHandle(Dev); + + VL53L1_range_results_t *presults = + &(pres->range_results); + VL53L1_zone_objects_t *pobjects = + &(pres->zone_results.VL53L1_p_002[0]); + VL53L1_ll_driver_state_t *pstate = + &(pdev->ll_state); + VL53L1_zone_config_t *pzone_cfg = + &(pdev->zone_cfg); + VL53L1_zone_hist_info_t *phist_info = + &(pres->zone_hists.VL53L1_p_002[0]); + + VL53L1_dmax_calibration_data_t dmax_cal; + VL53L1_dmax_calibration_data_t *pdmax_cal = &dmax_cal; + VL53L1_hist_post_process_config_t *pHP = &(pdev->histpostprocess); + VL53L1_xtalk_config_t *pC = &(pdev->xtalk_cfg); + VL53L1_low_power_auto_data_t *pL = &(pdev->low_power_auto_data); + VL53L1_histogram_bin_data_t *pHD = &(pdev->hist_data); + VL53L1_customer_nvm_managed_t *pN = &(pdev->customer); + VL53L1_zone_histograms_t *pZH = &(pres->zone_hists); + + uint8_t i; + uint8_t tmp8; + uint8_t zid; + + LOG_FUNCTION_START(""); + + + + + if ((pdev->sys_ctrl.system__mode_start & + VL53L1_DEVICESCHEDULERMODE_HISTOGRAM) + == VL53L1_DEVICESCHEDULERMODE_HISTOGRAM) { + + + + + + + status = VL53L1_get_histogram_bin_data( + Dev, + &(pdev->hist_data)); + + + + + + + + if (status == VL53L1_ERROR_NONE && + pHD->number_of_ambient_bins == 0) { + zid = pdev->ll_state.rd_zone_id; + status = VL53L1_hist_copy_and_scale_ambient_info( + &(pZH->VL53L1_p_002[zid]), + &(pdev->hist_data)); + } + + + + + + + if (status != VL53L1_ERROR_NONE) + goto UPDATE_DYNAMIC_CONFIG; + + + pHP->gain_factor = + pdev->gain_cal.histogram_ranging_gain_factor; + + pHP->algo__crosstalk_compensation_plane_offset_kcps = + VL53L1_calc_crosstalk_plane_offset_with_margin( + pC->algo__crosstalk_compensation_plane_offset_kcps, + pC->histogram_mode_crosstalk_margin_kcps); + + pHP->algo__crosstalk_compensation_x_plane_gradient_kcps = + pC->algo__crosstalk_compensation_x_plane_gradient_kcps; + pHP->algo__crosstalk_compensation_y_plane_gradient_kcps = + pC->algo__crosstalk_compensation_y_plane_gradient_kcps; + + pdev->dmax_cfg.ambient_thresh_sigma = + pHP->ambient_thresh_sigma1; + pdev->dmax_cfg.min_ambient_thresh_events = + pHP->min_ambient_thresh_events; + pdev->dmax_cfg.signal_total_events_limit = + pHP->signal_total_events_limit; + pdev->dmax_cfg.dss_config__target_total_rate_mcps = + pdev->stat_cfg.dss_config__target_total_rate_mcps; + pdev->dmax_cfg.dss_config__aperture_attenuation = + pdev->gen_cfg.dss_config__aperture_attenuation; + + pHP->algo__crosstalk_detect_max_valid_range_mm = + pC->algo__crosstalk_detect_max_valid_range_mm; + pHP->algo__crosstalk_detect_min_valid_range_mm = + pC->algo__crosstalk_detect_min_valid_range_mm; + pHP->algo__crosstalk_detect_max_valid_rate_kcps = + pC->algo__crosstalk_detect_max_valid_rate_kcps; + pHP->algo__crosstalk_detect_max_sigma_mm = + pC->algo__crosstalk_detect_max_sigma_mm; + + + + + VL53L1_copy_rtn_good_spads_to_buffer( + &(pdev->nvm_copy_data), + &(pdev->rtn_good_spads[0])); + + + + + switch (pdev->offset_correction_mode) { + + case VL53L1_OFFSETCORRECTIONMODE__MM1_MM2_OFFSETS: + tmp8 = pdev->gen_cfg.dss_config__aperture_attenuation; + + VL53L1_hist_combine_mm1_mm2_offsets( + pN->mm_config__inner_offset_mm, + pN->mm_config__outer_offset_mm, + pdev->nvm_copy_data.roi_config__mode_roi_centre_spad, + pdev->nvm_copy_data.roi_config__mode_roi_xy_size, + pHD->roi_config__user_roi_centre_spad, + pHD->roi_config__user_roi_requested_global_xy_size, + &(pdev->add_off_cal_data), + &(pdev->rtn_good_spads[0]), + (uint16_t)tmp8, + &(pHP->range_offset_mm)); + break; + case VL53L1_OFFSETCORRECTIONMODE__PER_ZONE_OFFSETS: + zid = pdev->ll_state.rd_zone_id; + pHP->range_offset_mm = (int16_t)( + pres->zone_cal.VL53L1_p_002[zid].range_mm_offset); + break; + default: + pHP->range_offset_mm = 0; + break; + + } + #if 0 + if (status != VL53L1_ERROR_NONE) + goto UPDATE_DYNAMIC_CONFIG; + #endif + + VL53L1_calc_max_effective_spads( + pHD->roi_config__user_roi_centre_spad, + pHD->roi_config__user_roi_requested_global_xy_size, + &(pdev->rtn_good_spads[0]), + (uint16_t)pdev->gen_cfg.dss_config__aperture_attenuation, + &(pdev->dmax_cfg.max_effective_spads)); + + status = + VL53L1_get_dmax_calibration_data( + Dev, + pdev->dmax_mode, + pdev->ll_state.rd_zone_id, + pdmax_cal); + + + + + + + if (status != VL53L1_ERROR_NONE) + goto UPDATE_DYNAMIC_CONFIG; + + status = VL53L1_ipp_hist_process_data( + Dev, + pdmax_cal, + &(pdev->dmax_cfg), + &(pdev->histpostprocess), + &(pdev->hist_data), + &(pdev->xtalk_shapes), + presults); + + + + if (status != VL53L1_ERROR_NONE) + goto UPDATE_DYNAMIC_CONFIG; + + status = VL53L1_hist_wrap_dmax( + &(pdev->histpostprocess), + &(pdev->hist_data), + &(presults->wrap_dmax_mm)); + + + + if (status != VL53L1_ERROR_NONE) + goto UPDATE_DYNAMIC_CONFIG; + + zid = pdev->ll_state.rd_zone_id; + status = VL53L1_hist_phase_consistency_check( + Dev, + &(pZH->VL53L1_p_002[zid]), + &(pres->zone_results.VL53L1_p_002[zid]), + presults); + + + + if (status != VL53L1_ERROR_NONE) + goto UPDATE_DYNAMIC_CONFIG; + + zid = pdev->ll_state.rd_zone_id; + status = VL53L1_hist_xmonitor_consistency_check( + Dev, + &(pZH->VL53L1_p_002[zid]), + &(pres->zone_results.VL53L1_p_002[zid]), + &(presults->xmonitor)); + + + + + + if (status != VL53L1_ERROR_NONE) + goto UPDATE_DYNAMIC_CONFIG; + + + zid = pdev->ll_state.rd_zone_id; + pZH->max_zones = VL53L1_MAX_USER_ZONES; + pZH->active_zones = + pdev->zone_cfg.active_zones+1; + pHD->zone_id = zid; + + if (zid < + pres->zone_results.max_zones) { + + phist_info = + &(pZH->VL53L1_p_002[zid]); + + phist_info->rd_device_state = + pHD->rd_device_state; + + phist_info->number_of_ambient_bins = + pHD->number_of_ambient_bins; + + phist_info->result__dss_actual_effective_spads = + pHD->result__dss_actual_effective_spads; + + phist_info->VL53L1_p_009 = + pHD->VL53L1_p_009; + + phist_info->total_periods_elapsed = + pHD->total_periods_elapsed; + + phist_info->ambient_events_sum = + pHD->ambient_events_sum; + } + + + + + + /* + if (status != VL53L1_ERROR_NONE) + goto UPDATE_DYNAMIC_CONFIG; + */ + VL53L1_hist_copy_results_to_sys_and_core( + &(pdev->hist_data), + presults, + &(pdev->sys_results), + &(pdev->core_results)); + + + + + + +UPDATE_DYNAMIC_CONFIG: + if (pzone_cfg->active_zones > 0) { + if (pstate->rd_device_state != + VL53L1_DEVICESTATE_RANGING_WAIT_GPH_SYNC) { + if (status == VL53L1_ERROR_NONE) { + status = VL53L1_dynamic_zone_update( + Dev, presults); + } + } + + + + + + for (i = 0; i < VL53L1_MAX_USER_ZONES; i++) { + pzone_cfg->bin_config[i] = + ((pdev->ll_state.cfg_internal_stream_count) + & 0x01) ? + VL53L1_ZONECONFIG_BINCONFIG__HIGHAMB : + VL53L1_ZONECONFIG_BINCONFIG__LOWAMB; + } + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_multizone_hist_bins_update(Dev); + + } + + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_dynamic_xtalk_correction_corrector(Dev); + +#ifdef VL53L1_LOG_ENABLE + if (status == VL53L1_ERROR_NONE) + VL53L1_print_histogram_bin_data( + &(pdev->hist_data), + "get_device_results():pdev->lldata.hist_data.", + VL53L1_TRACE_MODULE_HISTOGRAM_DATA); +#endif + + } else { + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_get_measurement_results( + Dev, + device_results_level); + + if (status == VL53L1_ERROR_NONE) + VL53L1_copy_sys_and_core_results_to_range_results( + (int32_t)pdev->gain_cal.standard_ranging_gain_factor, + &(pdev->sys_results), + &(pdev->core_results), + presults); + + + + + + if (pL->is_low_power_auto_mode == 1) { + + + + if ((status == VL53L1_ERROR_NONE) && + (pL->low_power_auto_range_count == 0)) { + + status = + VL53L1_low_power_auto_setup_manual_calibration( + Dev); + pL->low_power_auto_range_count = 1; + } else if ((status == VL53L1_ERROR_NONE) && + (pL->low_power_auto_range_count == 1)) { + pL->low_power_auto_range_count = 2; + } + + + + if ((pL->low_power_auto_range_count != 0xFF) && + (status == VL53L1_ERROR_NONE)) { + status = VL53L1_low_power_auto_update_DSS( + Dev); + } + } + + + } + + + + presults->cfg_device_state = pdev->ll_state.cfg_device_state; + presults->rd_device_state = pdev->ll_state.rd_device_state; + presults->zone_id = pdev->ll_state.rd_zone_id; + + if (status == VL53L1_ERROR_NONE) { + + + + pres->zone_results.max_zones = VL53L1_MAX_USER_ZONES; + pres->zone_results.active_zones = pdev->zone_cfg.active_zones+1; + zid = pdev->ll_state.rd_zone_id; + + if (zid < pres->zone_results.max_zones) { + + pobjects = + &(pres->zone_results.VL53L1_p_002[zid]); + + pobjects->cfg_device_state = + presults->cfg_device_state; + pobjects->rd_device_state = presults->rd_device_state; + pobjects->zone_id = presults->zone_id; + pobjects->stream_count = presults->stream_count; + + + + + pobjects->xmonitor.VL53L1_p_020 = + presults->xmonitor.VL53L1_p_020; + pobjects->xmonitor.VL53L1_p_021 = + presults->xmonitor.VL53L1_p_021; + pobjects->xmonitor.VL53L1_p_014 = + presults->xmonitor.VL53L1_p_014; + pobjects->xmonitor.range_status = + presults->xmonitor.range_status; + + pobjects->max_objects = presults->max_results; + pobjects->active_objects = presults->active_results; + + for (i = 0; i < presults->active_results; i++) { + pobjects->VL53L1_p_002[i].VL53L1_p_020 = + presults->VL53L1_p_002[i].VL53L1_p_020; + pobjects->VL53L1_p_002[i].VL53L1_p_021 = + presults->VL53L1_p_002[i].VL53L1_p_021; + pobjects->VL53L1_p_002[i].VL53L1_p_014 = + presults->VL53L1_p_002[i].VL53L1_p_014; + pobjects->VL53L1_p_002[i].range_status = + presults->VL53L1_p_002[i].range_status; + } + + + + } + } + + + + + memcpy( + prange_results, + presults, + sizeof(VL53L1_range_results_t)); + + + + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_check_ll_driver_rd_state(Dev); + +#ifdef VL53L1_LOG_ENABLE + if (status == VL53L1_ERROR_NONE) + VL53L1_print_range_results( + presults, + "get_device_results():pdev->llresults.range_results.", + VL53L1_TRACE_MODULE_RANGE_RESULTS_DATA); +#endif + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_clear_interrupt_and_enable_next_range( + VL53L1_DEV Dev, + uint8_t measurement_mode) +{ + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + + + + + + + + + + + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_init_and_start_range( + Dev, + measurement_mode, + VL53L1_DEVICECONFIGLEVEL_GENERAL_ONWARDS); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_histogram_bin_data( + VL53L1_DEV Dev, + VL53L1_histogram_bin_data_t *pdata) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_LLDriverResults_t *pres = + VL53L1DevStructGetLLResultsHandle(Dev); + + VL53L1_zone_private_dyn_cfg_t *pzone_dyn_cfg; + + VL53L1_static_nvm_managed_t *pstat_nvm = &(pdev->stat_nvm); + VL53L1_static_config_t *pstat_cfg = &(pdev->stat_cfg); + VL53L1_general_config_t *pgen_cfg = &(pdev->gen_cfg); + VL53L1_timing_config_t *ptim_cfg = &(pdev->tim_cfg); + VL53L1_range_results_t *presults = &(pres->range_results); + + uint8_t buffer[VL53L1_MAX_I2C_XFER_SIZE]; + uint8_t *pbuffer = &buffer[0]; + uint8_t bin_23_0 = 0x00; + uint16_t bin = 0; + uint16_t i2c_buffer_offset_bytes = 0; + uint16_t encoded_timeout = 0; + + uint32_t pll_period_us = 0; + uint32_t periods_elapsed_tmp = 0; + + uint8_t i = 0; + + LOG_FUNCTION_START(""); + + + + + + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_ReadMulti( + Dev, + VL53L1_HISTOGRAM_BIN_DATA_I2C_INDEX, + pbuffer, + VL53L1_HISTOGRAM_BIN_DATA_I2C_SIZE_BYTES); + + + + + + + pdata->result__interrupt_status = *(pbuffer + 0); + pdata->result__range_status = *(pbuffer + 1); + pdata->result__report_status = *(pbuffer + 2); + pdata->result__stream_count = *(pbuffer + 3); + pdata->result__dss_actual_effective_spads = + VL53L1_i2c_decode_uint16_t(2, pbuffer + 4); + + + + + + + i2c_buffer_offset_bytes = + VL53L1_PHASECAL_RESULT__REFERENCE_PHASE - + VL53L1_HISTOGRAM_BIN_DATA_I2C_INDEX; + + pbuffer = &buffer[i2c_buffer_offset_bytes]; + + pdata->phasecal_result__reference_phase = + VL53L1_i2c_decode_uint16_t(2, pbuffer); + + i2c_buffer_offset_bytes = + VL53L1_PHASECAL_RESULT__VCSEL_START - + VL53L1_HISTOGRAM_BIN_DATA_I2C_INDEX; + + pdata->phasecal_result__vcsel_start = buffer[i2c_buffer_offset_bytes]; + + + + + pdev->dbg_results.phasecal_result__reference_phase = + pdata->phasecal_result__reference_phase; + pdev->dbg_results.phasecal_result__vcsel_start = + pdata->phasecal_result__vcsel_start; + + + + + + + + i2c_buffer_offset_bytes = + VL53L1_RESULT__HISTOGRAM_BIN_23_0_MSB - + VL53L1_HISTOGRAM_BIN_DATA_I2C_INDEX; + + bin_23_0 = buffer[i2c_buffer_offset_bytes] << 2; + + i2c_buffer_offset_bytes = + VL53L1_RESULT__HISTOGRAM_BIN_23_0_LSB - + VL53L1_HISTOGRAM_BIN_DATA_I2C_INDEX; + + bin_23_0 += buffer[i2c_buffer_offset_bytes]; + + i2c_buffer_offset_bytes = + VL53L1_RESULT__HISTOGRAM_BIN_23_0 - + VL53L1_HISTOGRAM_BIN_DATA_I2C_INDEX; + + buffer[i2c_buffer_offset_bytes] = bin_23_0; + + + + + + + + i2c_buffer_offset_bytes = + VL53L1_RESULT__HISTOGRAM_BIN_0_2 - + VL53L1_HISTOGRAM_BIN_DATA_I2C_INDEX; + + pbuffer = &buffer[i2c_buffer_offset_bytes]; + for (bin = 0; bin < VL53L1_HISTOGRAM_BUFFER_SIZE; bin++) { + pdata->bin_data[bin] = + (int32_t)VL53L1_i2c_decode_uint32_t(3, pbuffer); + pbuffer += 3; + } + + + + pdata->zone_id = pdev->ll_state.rd_zone_id; + pdata->VL53L1_p_022 = 0; + pdata->VL53L1_p_023 = VL53L1_HISTOGRAM_BUFFER_SIZE; + pdata->VL53L1_p_024 = VL53L1_HISTOGRAM_BUFFER_SIZE; + + pdata->cal_config__vcsel_start = pgen_cfg->cal_config__vcsel_start; + + + + + pdata->vcsel_width = + ((uint16_t)pgen_cfg->global_config__vcsel_width) << 4; + pdata->vcsel_width += + (uint16_t)pstat_cfg->ana_config__vcsel_pulse_width_offset; + + + + pdata->VL53L1_p_019 = + pstat_nvm->osc_measured__fast_osc__frequency; + + + + + VL53L1_hist_get_bin_sequence_config(Dev, pdata); + + + + + + + if (pdev->ll_state.rd_timing_status == 0) { + + encoded_timeout = + (ptim_cfg->range_config__timeout_macrop_a_hi << 8) + + ptim_cfg->range_config__timeout_macrop_a_lo; + pdata->VL53L1_p_009 = ptim_cfg->range_config__vcsel_period_a; + } else { + + encoded_timeout = + (ptim_cfg->range_config__timeout_macrop_b_hi << 8) + + ptim_cfg->range_config__timeout_macrop_b_lo; + pdata->VL53L1_p_009 = ptim_cfg->range_config__vcsel_period_b; + } + + + + + pdata->number_of_ambient_bins = 0; + + for (i = 0; i < 6; i++) { + if ((pdata->bin_seq[i] & 0x07) == 0x07) + pdata->number_of_ambient_bins = + pdata->number_of_ambient_bins + 0x04; + } + + pdata->total_periods_elapsed = + VL53L1_decode_timeout(encoded_timeout); + + + + + + + + pll_period_us = + VL53L1_calc_pll_period_us(pdata->VL53L1_p_019); + + + + + periods_elapsed_tmp = pdata->total_periods_elapsed + 1; + + + + + + + pdata->peak_duration_us = + VL53L1_duration_maths( + pll_period_us, + (uint32_t)pdata->vcsel_width, + VL53L1_RANGING_WINDOW_VCSEL_PERIODS, + periods_elapsed_tmp); + + pdata->woi_duration_us = 0; + + + + + VL53L1_hist_calc_zero_distance_phase(pdata); + + + + + + + VL53L1_hist_estimate_ambient_from_ambient_bins(pdata); + + + + + pdata->cfg_device_state = pdev->ll_state.cfg_device_state; + pdata->rd_device_state = pdev->ll_state.rd_device_state; + + + + + pzone_dyn_cfg = &(pres->zone_dyn_cfgs.VL53L1_p_002[pdata->zone_id]); + + pdata->roi_config__user_roi_centre_spad = + pzone_dyn_cfg->roi_config__user_roi_centre_spad; + pdata->roi_config__user_roi_requested_global_xy_size = + pzone_dyn_cfg->roi_config__user_roi_requested_global_xy_size; + + + + + + + presults->device_status = VL53L1_DEVICEERROR_NOUPDATE; + + + + + switch (pdata->result__range_status & + VL53L1_RANGE_STATUS__RANGE_STATUS_MASK) { + + case VL53L1_DEVICEERROR_VCSELCONTINUITYTESTFAILURE: + case VL53L1_DEVICEERROR_VCSELWATCHDOGTESTFAILURE: + case VL53L1_DEVICEERROR_NOVHVVALUEFOUND: + case VL53L1_DEVICEERROR_USERROICLIP: + case VL53L1_DEVICEERROR_MULTCLIPFAIL: + + presults->device_status = (pdata->result__range_status & + VL53L1_RANGE_STATUS__RANGE_STATUS_MASK); + + status = VL53L1_ERROR_RANGE_ERROR; + + break; + + } + + LOG_FUNCTION_END(status); + + return status; +} + + +void VL53L1_copy_sys_and_core_results_to_range_results( + int32_t gain_factor, + VL53L1_system_results_t *psys, + VL53L1_core_results_t *pcore, + VL53L1_range_results_t *presults) +{ + uint8_t i = 0; + + VL53L1_range_data_t *pdata; + int32_t range_mm = 0; + uint32_t tmpu32 = 0; + uint16_t rpscr_crosstalk_corrected_mcps_sd0; + uint16_t rmmo_effective_spads_sd0; + uint16_t rmmi_effective_spads_sd0; + + LOG_FUNCTION_START(""); + + + + + presults->zone_id = 0; + presults->stream_count = psys->result__stream_count; + presults->wrap_dmax_mm = 0; + presults->max_results = VL53L1_MAX_RANGE_RESULTS; + presults->active_results = 1; + rpscr_crosstalk_corrected_mcps_sd0 = + psys->result__peak_signal_count_rate_crosstalk_corrected_mcps_sd0; + rmmo_effective_spads_sd0 = + psys->result__mm_outer_actual_effective_spads_sd0; + rmmi_effective_spads_sd0 = + psys->result__mm_inner_actual_effective_spads_sd0; + + + for (i = 0; i < VL53L1_MAX_AMBIENT_DMAX_VALUES; i++) + presults->VL53L1_p_007[i] = 0; + + pdata = &(presults->VL53L1_p_002[0]); + + for (i = 0; i < 2; i++) { + + pdata->range_id = i; + pdata->time_stamp = 0; + + if ((psys->result__stream_count == 0) && + ((psys->result__range_status & + VL53L1_RANGE_STATUS__RANGE_STATUS_MASK) == + VL53L1_DEVICEERROR_RANGECOMPLETE)) { + pdata->range_status = + VL53L1_DEVICEERROR_RANGECOMPLETE_NO_WRAP_CHECK; + } else { + pdata->range_status = + psys->result__range_status & + VL53L1_RANGE_STATUS__RANGE_STATUS_MASK; + } + + pdata->VL53L1_p_015 = 0; + pdata->VL53L1_p_022 = 0; + pdata->VL53L1_p_025 = 0; + pdata->VL53L1_p_026 = 0; + pdata->VL53L1_p_016 = 0; + pdata->VL53L1_p_027 = 0; + + switch (i) { + + case 0: + if (psys->result__report_status == + VL53L1_DEVICEREPORTSTATUS_MM1) + pdata->VL53L1_p_006 = + rmmi_effective_spads_sd0; + else if (psys->result__report_status == + VL53L1_DEVICEREPORTSTATUS_MM2) + pdata->VL53L1_p_006 = + rmmo_effective_spads_sd0; + else + pdata->VL53L1_p_006 = + psys->result__dss_actual_effective_spads_sd0; + + pdata->peak_signal_count_rate_mcps = + rpscr_crosstalk_corrected_mcps_sd0; + pdata->avg_signal_count_rate_mcps = + psys->result__avg_signal_count_rate_mcps_sd0; + pdata->ambient_count_rate_mcps = + psys->result__ambient_count_rate_mcps_sd0; + + + + + + + tmpu32 = ((uint32_t)psys->result__sigma_sd0 << 5); + if (tmpu32 > 0xFFFF) + tmpu32 = 0xFFFF; + + pdata->VL53L1_p_005 = (uint16_t)tmpu32; + + + + + pdata->VL53L1_p_014 = + psys->result__phase_sd0; + + range_mm = (int32_t)( + psys->result__final_crosstalk_corrected_range_mm_sd0); + + + + range_mm *= gain_factor; + range_mm += 0x0400; + range_mm /= 0x0800; + + pdata->median_range_mm = (int16_t)range_mm; + + pdata->VL53L1_p_021 = + pcore->result_core__ranging_total_events_sd0; + pdata->VL53L1_p_013 = + pcore->result_core__signal_total_events_sd0; + pdata->total_periods_elapsed = + pcore->result_core__total_periods_elapsed_sd0; + pdata->VL53L1_p_020 = + pcore->result_core__ambient_window_events_sd0; + + break; + case 1: + + pdata->VL53L1_p_006 = + psys->result__dss_actual_effective_spads_sd1; + pdata->peak_signal_count_rate_mcps = + psys->result__peak_signal_count_rate_mcps_sd1; + pdata->avg_signal_count_rate_mcps = + 0xFFFF; + pdata->ambient_count_rate_mcps = + psys->result__ambient_count_rate_mcps_sd1; + + + + + + + tmpu32 = ((uint32_t)psys->result__sigma_sd1 << 5); + if (tmpu32 > 0xFFFF) + tmpu32 = 0xFFFF; + + pdata->VL53L1_p_005 = (uint16_t)tmpu32; + + + + + pdata->VL53L1_p_014 = + psys->result__phase_sd1; + + range_mm = (int32_t)( + psys->result__final_crosstalk_corrected_range_mm_sd1); + + + + range_mm *= gain_factor; + range_mm += 0x0400; + range_mm /= 0x0800; + + pdata->median_range_mm = (int16_t)range_mm; + + pdata->VL53L1_p_021 = + pcore->result_core__ranging_total_events_sd1; + pdata->VL53L1_p_013 = + pcore->result_core__signal_total_events_sd1; + pdata->total_periods_elapsed = + pcore->result_core__total_periods_elapsed_sd1; + pdata->VL53L1_p_020 = + pcore->result_core__ambient_window_events_sd1; + + break; + } + + + + + + pdata->VL53L1_p_028 = pdata->VL53L1_p_014; + pdata->VL53L1_p_029 = pdata->VL53L1_p_014; + pdata->min_range_mm = pdata->median_range_mm; + pdata->max_range_mm = pdata->median_range_mm; + + pdata++; + } + + + + + + + presults->device_status = VL53L1_DEVICEERROR_NOUPDATE; + + + + + + + + + switch (psys->result__range_status & + VL53L1_RANGE_STATUS__RANGE_STATUS_MASK) { + + case VL53L1_DEVICEERROR_VCSELCONTINUITYTESTFAILURE: + case VL53L1_DEVICEERROR_VCSELWATCHDOGTESTFAILURE: + case VL53L1_DEVICEERROR_NOVHVVALUEFOUND: + case VL53L1_DEVICEERROR_USERROICLIP: + case VL53L1_DEVICEERROR_MULTCLIPFAIL: + + presults->device_status = (psys->result__range_status & + VL53L1_RANGE_STATUS__RANGE_STATUS_MASK); + + presults->VL53L1_p_002[0].range_status = + VL53L1_DEVICEERROR_NOUPDATE; + break; + + } + + LOG_FUNCTION_END(0); +} + + +VL53L1_Error VL53L1_set_zone_dss_config( + VL53L1_DEV Dev, + VL53L1_zone_private_dyn_cfg_t *pzone_dyn_cfg) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_ll_driver_state_t *pstate = &(pdev->ll_state); + + LOG_FUNCTION_START(""); + + if (pstate->cfg_device_state == + VL53L1_DEVICESTATE_RANGING_DSS_MANUAL) { + pdev->gen_cfg.dss_config__roi_mode_control = + VL53L1_DSS_CONTROL__MODE_EFFSPADS; + pdev->gen_cfg.dss_config__manual_effective_spads_select = + pzone_dyn_cfg->dss_requested_effective_spad_count; + } else { + pdev->gen_cfg.dss_config__roi_mode_control = + VL53L1_DSS_CONTROL__MODE_TARGET_RATE; + } + + LOG_FUNCTION_END(status); + return status; +} + + +VL53L1_Error VL53L1_calc_ambient_dmax( + VL53L1_DEV Dev, + uint16_t target_reflectance, + int16_t *pambient_dmax_mm) +{ + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + + VL53L1_dmax_calibration_data_t dmax_cal; + VL53L1_dmax_calibration_data_t *pdmax_cal = &dmax_cal; + + LOG_FUNCTION_START(""); + + + + + + + status = + VL53L1_get_dmax_calibration_data( + Dev, + pdev->debug_mode, + pdev->ll_state.rd_zone_id, + pdmax_cal); + + + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_ipp_hist_ambient_dmax( + Dev, + target_reflectance, + &(pdev->fmt_dmax_cal), + &(pdev->dmax_cfg), + &(pdev->hist_data), + pambient_dmax_mm); + + LOG_FUNCTION_END(status); + + return status; +} + + + + + + +VL53L1_Error VL53L1_set_GPIO_interrupt_config( + VL53L1_DEV Dev, + VL53L1_GPIO_Interrupt_Mode intr_mode_distance, + VL53L1_GPIO_Interrupt_Mode intr_mode_rate, + uint8_t intr_new_measure_ready, + uint8_t intr_no_target, + uint8_t intr_combined_mode, + uint16_t thresh_distance_high, + uint16_t thresh_distance_low, + uint16_t thresh_rate_high, + uint16_t thresh_rate_low + ) +{ + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_GPIO_interrupt_config_t *pintconf = + &(pdev->gpio_interrupt_config); + + LOG_FUNCTION_START(""); + + + + pintconf->intr_mode_distance = intr_mode_distance; + pintconf->intr_mode_rate = intr_mode_rate; + pintconf->intr_new_measure_ready = intr_new_measure_ready; + pintconf->intr_no_target = intr_no_target; + pintconf->intr_combined_mode = intr_combined_mode; + pintconf->threshold_distance_high = thresh_distance_high; + pintconf->threshold_distance_low = thresh_distance_low; + pintconf->threshold_rate_high = thresh_rate_high; + pintconf->threshold_rate_low = thresh_rate_low; + + + + pdev->gen_cfg.system__interrupt_config_gpio = + VL53L1_encode_GPIO_interrupt_config(pintconf); + + + + + status = VL53L1_set_GPIO_thresholds_from_struct( + Dev, + pintconf); + + LOG_FUNCTION_END(status); + return status; +} + + + + + + +VL53L1_Error VL53L1_set_GPIO_interrupt_config_struct( + VL53L1_DEV Dev, + VL53L1_GPIO_interrupt_config_t intconf) +{ + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_GPIO_interrupt_config_t *pintconf = + &(pdev->gpio_interrupt_config); + + LOG_FUNCTION_START(""); + + + + memcpy(pintconf, &(intconf), sizeof(VL53L1_GPIO_interrupt_config_t)); + + + + pdev->gen_cfg.system__interrupt_config_gpio = + VL53L1_encode_GPIO_interrupt_config(pintconf); + + + + status = VL53L1_set_GPIO_thresholds_from_struct( + Dev, + pintconf); + + LOG_FUNCTION_END(status); + return status; +} + + + + + + +VL53L1_Error VL53L1_get_GPIO_interrupt_config( + VL53L1_DEV Dev, + VL53L1_GPIO_interrupt_config_t *pintconf) +{ + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + + + + + + pdev->gpio_interrupt_config = VL53L1_decode_GPIO_interrupt_config( + pdev->gen_cfg.system__interrupt_config_gpio); + + + + + + pdev->gpio_interrupt_config.threshold_distance_high = + pdev->dyn_cfg.system__thresh_high; + pdev->gpio_interrupt_config.threshold_distance_low = + pdev->dyn_cfg.system__thresh_low; + + pdev->gpio_interrupt_config.threshold_rate_high = + pdev->gen_cfg.system__thresh_rate_high; + pdev->gpio_interrupt_config.threshold_rate_low = + pdev->gen_cfg.system__thresh_rate_low; + + if (pintconf == &(pdev->gpio_interrupt_config)) { + + + } else { + + + + memcpy(pintconf, &(pdev->gpio_interrupt_config), + sizeof(VL53L1_GPIO_interrupt_config_t)); + } + + LOG_FUNCTION_END(status); + return status; +} + + +VL53L1_Error VL53L1_set_dmax_mode( + VL53L1_DEV Dev, + VL53L1_DeviceDmaxMode dmax_mode) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + pdev->dmax_mode = dmax_mode; + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_dmax_mode( + VL53L1_DEV Dev, + VL53L1_DeviceDmaxMode *pdmax_mode) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + *pdmax_mode = pdev->dmax_mode; + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_dmax_calibration_data( + VL53L1_DEV Dev, + VL53L1_DeviceDmaxMode dmax_mode, + uint8_t zone_id, + VL53L1_dmax_calibration_data_t *pdmax_cal) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_LLDriverResults_t *pres = + VL53L1DevStructGetLLResultsHandle(Dev); + + LOG_FUNCTION_START(""); + + switch (dmax_mode) { + + case VL53L1_DEVICEDMAXMODE__PER_ZONE_CAL_DATA: + pdmax_cal->ref__actual_effective_spads = + (uint16_t)pres->zone_cal.VL53L1_p_002[zone_id].effective_spads; + pdmax_cal->ref__peak_signal_count_rate_mcps = + (uint16_t)pres->zone_cal.VL53L1_p_002[zone_id].peak_rate_mcps; + pdmax_cal->ref__distance_mm = + pres->zone_cal.cal_distance_mm; + pdmax_cal->ref_reflectance_pc = + pres->zone_cal.cal_reflectance_pc; + pdmax_cal->coverglass_transmission = 0x0100; + break; + + case VL53L1_DEVICEDMAXMODE__CUST_CAL_DATA: + memcpy( + pdmax_cal, + &(pdev->cust_dmax_cal), + sizeof(VL53L1_dmax_calibration_data_t)); + break; + + case VL53L1_DEVICEDMAXMODE__FMT_CAL_DATA: + memcpy( + pdmax_cal, + &(pdev->fmt_dmax_cal), + sizeof(VL53L1_dmax_calibration_data_t)); + break; + + default: + status = VL53L1_ERROR_INVALID_PARAMS; + break; + + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_hist_dmax_config( + VL53L1_DEV Dev, + VL53L1_hist_gen3_dmax_config_t *pdmax_cfg) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + + + memcpy( + &(pdev->dmax_cfg), + pdmax_cfg, + sizeof(VL53L1_hist_gen3_dmax_config_t)); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_hist_dmax_config( + VL53L1_DEV Dev, + VL53L1_hist_gen3_dmax_config_t *pdmax_cfg) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + + + memcpy( + pdmax_cfg, + &(pdev->dmax_cfg), + sizeof(VL53L1_hist_gen3_dmax_config_t)); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_offset_calibration_mode( + VL53L1_DEV Dev, + VL53L1_OffsetCalibrationMode offset_cal_mode) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + pdev->offset_calibration_mode = offset_cal_mode; + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_offset_calibration_mode( + VL53L1_DEV Dev, + VL53L1_OffsetCalibrationMode *poffset_cal_mode) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + *poffset_cal_mode = pdev->offset_calibration_mode; + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_offset_correction_mode( + VL53L1_DEV Dev, + VL53L1_OffsetCorrectionMode offset_cor_mode) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + pdev->offset_correction_mode = offset_cor_mode; + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_offset_correction_mode( + VL53L1_DEV Dev, + VL53L1_OffsetCorrectionMode *poffset_cor_mode) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + *poffset_cor_mode = pdev->offset_correction_mode; + + LOG_FUNCTION_END(status); + + return status; +} + + + + + +VL53L1_Error VL53L1_set_zone_calibration_data( + VL53L1_DEV Dev, + VL53L1_zone_calibration_results_t *pzone_cal) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverResults_t *pres = VL53L1DevStructGetLLResultsHandle(Dev); + + LOG_FUNCTION_START(""); + + if (pzone_cal->struct_version != + VL53L1_LL_ZONE_CALIBRATION_DATA_STRUCT_VERSION) + status = VL53L1_ERROR_INVALID_PARAMS; + + + if (status == VL53L1_ERROR_NONE) + + + memcpy( + &(pres->zone_cal), + pzone_cal, + sizeof(VL53L1_zone_calibration_results_t)); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_zone_calibration_data( + VL53L1_DEV Dev, + VL53L1_zone_calibration_results_t *pzone_cal) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverResults_t *pres = VL53L1DevStructGetLLResultsHandle(Dev); + + LOG_FUNCTION_START(""); + + + + memcpy( + pzone_cal, + &(pres->zone_cal), + sizeof(VL53L1_zone_calibration_results_t)); + + pzone_cal->struct_version = + VL53L1_LL_ZONE_CALIBRATION_DATA_STRUCT_VERSION; + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_tuning_debug_data( + VL53L1_DEV Dev, + VL53L1_tuning_parameters_t *ptun_data) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_hist_post_process_config_t *pHP = &(pdev->histpostprocess); + VL53L1_xtalkextract_config_t *pXC = &(pdev->xtalk_extract_cfg); + + LOG_FUNCTION_START(""); + + ptun_data->vl53l1_tuningparm_version = + pdev->tuning_parms.tp_tuning_parm_version; + + ptun_data->vl53l1_tuningparm_key_table_version = + pdev->tuning_parms.tp_tuning_parm_key_table_version; + + + ptun_data->vl53l1_tuningparm_lld_version = + pdev->tuning_parms.tp_tuning_parm_lld_version; + + ptun_data->vl53l1_tuningparm_hist_algo_select = + pHP->hist_algo_select; + + ptun_data->vl53l1_tuningparm_hist_target_order = + pHP->hist_target_order; + + ptun_data->vl53l1_tuningparm_hist_filter_woi_0 = + pHP->filter_woi0; + + ptun_data->vl53l1_tuningparm_hist_filter_woi_1 = + pHP->filter_woi1; + + ptun_data->vl53l1_tuningparm_hist_amb_est_method = + pHP->hist_amb_est_method; + + ptun_data->vl53l1_tuningparm_hist_amb_thresh_sigma_0 = + pHP->ambient_thresh_sigma0; + + ptun_data->vl53l1_tuningparm_hist_amb_thresh_sigma_1 = + pHP->ambient_thresh_sigma1; + + ptun_data->vl53l1_tuningparm_hist_min_amb_thresh_events = + pHP->min_ambient_thresh_events; + + ptun_data->vl53l1_tuningparm_hist_amb_events_scaler = + pHP->ambient_thresh_events_scaler; + + ptun_data->vl53l1_tuningparm_hist_noise_threshold = + pHP->noise_threshold; + + ptun_data->vl53l1_tuningparm_hist_signal_total_events_limit = + pHP->signal_total_events_limit; + + ptun_data->vl53l1_tuningparm_hist_sigma_est_ref_mm = + pHP->sigma_estimator__sigma_ref_mm; + + ptun_data->vl53l1_tuningparm_hist_sigma_thresh_mm = + pHP->sigma_thresh; + + ptun_data->vl53l1_tuningparm_hist_gain_factor = + pdev->gain_cal.histogram_ranging_gain_factor; + + ptun_data->vl53l1_tuningparm_consistency_hist_phase_tolerance = + pHP->algo__consistency_check__phase_tolerance; + + ptun_data->vl53l1_tuningparm_consistency_hist_min_max_tolerance_mm = + pHP->algo__consistency_check__min_max_tolerance; + + ptun_data->vl53l1_tuningparm_consistency_hist_event_sigma = + pHP->algo__consistency_check__event_sigma; + + ptun_data->vl53l1_tuningparm_consistency_hist_event_sigma_min_spad_limit + = pHP->algo__consistency_check__event_min_spad_count; + + ptun_data->vl53l1_tuningparm_initial_phase_rtn_histo_long_range = + pdev->tuning_parms.tp_init_phase_rtn_hist_long; + + ptun_data->vl53l1_tuningparm_initial_phase_rtn_histo_med_range = + pdev->tuning_parms.tp_init_phase_rtn_hist_med; + + ptun_data->vl53l1_tuningparm_initial_phase_rtn_histo_short_range = + pdev->tuning_parms.tp_init_phase_rtn_hist_short; + + ptun_data->vl53l1_tuningparm_initial_phase_ref_histo_long_range = + pdev->tuning_parms.tp_init_phase_ref_hist_long; + + ptun_data->vl53l1_tuningparm_initial_phase_ref_histo_med_range = + pdev->tuning_parms.tp_init_phase_ref_hist_med; + + ptun_data->vl53l1_tuningparm_initial_phase_ref_histo_short_range = + pdev->tuning_parms.tp_init_phase_ref_hist_short; + + ptun_data->vl53l1_tuningparm_xtalk_detect_min_valid_range_mm = + pdev->xtalk_cfg.algo__crosstalk_detect_min_valid_range_mm; + + ptun_data->vl53l1_tuningparm_xtalk_detect_max_valid_range_mm = + pdev->xtalk_cfg.algo__crosstalk_detect_max_valid_range_mm; + + ptun_data->vl53l1_tuningparm_xtalk_detect_max_sigma_mm = + pdev->xtalk_cfg.algo__crosstalk_detect_max_sigma_mm; + + ptun_data->vl53l1_tuningparm_xtalk_detect_min_max_tolerance = + pHP->algo__crosstalk_detect_min_max_tolerance; + + ptun_data->vl53l1_tuningparm_xtalk_detect_max_valid_rate_kcps = + pdev->xtalk_cfg.algo__crosstalk_detect_max_valid_rate_kcps; + + ptun_data->vl53l1_tuningparm_xtalk_detect_event_sigma = + pHP->algo__crosstalk_detect_event_sigma; + + ptun_data->vl53l1_tuningparm_hist_xtalk_margin_kcps = + pdev->xtalk_cfg.histogram_mode_crosstalk_margin_kcps; + + ptun_data->vl53l1_tuningparm_consistency_lite_phase_tolerance = + pdev->tuning_parms.tp_consistency_lite_phase_tolerance; + + ptun_data->vl53l1_tuningparm_phasecal_target = + pdev->tuning_parms.tp_phasecal_target; + + ptun_data->vl53l1_tuningparm_lite_cal_repeat_rate = + pdev->tuning_parms.tp_cal_repeat_rate; + + ptun_data->vl53l1_tuningparm_lite_ranging_gain_factor = + pdev->gain_cal.standard_ranging_gain_factor; + + ptun_data->vl53l1_tuningparm_lite_min_clip_mm = + pdev->tuning_parms.tp_lite_min_clip; + + ptun_data->vl53l1_tuningparm_lite_long_sigma_thresh_mm = + pdev->tuning_parms.tp_lite_long_sigma_thresh_mm; + + ptun_data->vl53l1_tuningparm_lite_med_sigma_thresh_mm = + pdev->tuning_parms.tp_lite_med_sigma_thresh_mm; + + ptun_data->vl53l1_tuningparm_lite_short_sigma_thresh_mm = + pdev->tuning_parms.tp_lite_short_sigma_thresh_mm; + + ptun_data->vl53l1_tuningparm_lite_long_min_count_rate_rtn_mcps = + pdev->tuning_parms.tp_lite_long_min_count_rate_rtn_mcps; + + ptun_data->vl53l1_tuningparm_lite_med_min_count_rate_rtn_mcps = + pdev->tuning_parms.tp_lite_med_min_count_rate_rtn_mcps; + + ptun_data->vl53l1_tuningparm_lite_short_min_count_rate_rtn_mcps = + pdev->tuning_parms.tp_lite_short_min_count_rate_rtn_mcps; + + ptun_data->vl53l1_tuningparm_lite_sigma_est_pulse_width = + pdev->tuning_parms.tp_lite_sigma_est_pulse_width_ns; + + ptun_data->vl53l1_tuningparm_lite_sigma_est_amb_width_ns = + pdev->tuning_parms.tp_lite_sigma_est_amb_width_ns; + + ptun_data->vl53l1_tuningparm_lite_sigma_ref_mm = + pdev->tuning_parms.tp_lite_sigma_ref_mm; + + ptun_data->vl53l1_tuningparm_lite_rit_mult = + pdev->xtalk_cfg.crosstalk_range_ignore_threshold_mult; + + ptun_data->vl53l1_tuningparm_lite_seed_config = + pdev->tuning_parms.tp_lite_seed_cfg; + + ptun_data->vl53l1_tuningparm_lite_quantifier = + pdev->tuning_parms.tp_lite_quantifier; + + ptun_data->vl53l1_tuningparm_lite_first_order_select = + pdev->tuning_parms.tp_lite_first_order_select; + + ptun_data->vl53l1_tuningparm_lite_xtalk_margin_kcps = + pdev->xtalk_cfg.lite_mode_crosstalk_margin_kcps; + + ptun_data->vl53l1_tuningparm_initial_phase_rtn_lite_long_range = + pdev->tuning_parms.tp_init_phase_rtn_lite_long; + + ptun_data->vl53l1_tuningparm_initial_phase_rtn_lite_med_range = + pdev->tuning_parms.tp_init_phase_rtn_lite_med; + + ptun_data->vl53l1_tuningparm_initial_phase_rtn_lite_short_range = + pdev->tuning_parms.tp_init_phase_rtn_lite_short; + + ptun_data->vl53l1_tuningparm_initial_phase_ref_lite_long_range = + pdev->tuning_parms.tp_init_phase_ref_lite_long; + + ptun_data->vl53l1_tuningparm_initial_phase_ref_lite_med_range = + pdev->tuning_parms.tp_init_phase_ref_lite_med; + + ptun_data->vl53l1_tuningparm_initial_phase_ref_lite_short_range = + pdev->tuning_parms.tp_init_phase_ref_lite_short; + + ptun_data->vl53l1_tuningparm_timed_seed_config = + pdev->tuning_parms.tp_timed_seed_cfg; + + ptun_data->vl53l1_tuningparm_dmax_cfg_signal_thresh_sigma = + pdev->dmax_cfg.signal_thresh_sigma; + + ptun_data->vl53l1_tuningparm_dmax_cfg_reflectance_array_0 = + pdev->dmax_cfg.target_reflectance_for_dmax_calc[0]; + + ptun_data->vl53l1_tuningparm_dmax_cfg_reflectance_array_1 = + pdev->dmax_cfg.target_reflectance_for_dmax_calc[1]; + + ptun_data->vl53l1_tuningparm_dmax_cfg_reflectance_array_2 = + pdev->dmax_cfg.target_reflectance_for_dmax_calc[2]; + + ptun_data->vl53l1_tuningparm_dmax_cfg_reflectance_array_3 = + pdev->dmax_cfg.target_reflectance_for_dmax_calc[3]; + + ptun_data->vl53l1_tuningparm_dmax_cfg_reflectance_array_4 = + pdev->dmax_cfg.target_reflectance_for_dmax_calc[4]; + + ptun_data->vl53l1_tuningparm_vhv_loopbound = + pdev->stat_nvm.vhv_config__timeout_macrop_loop_bound; + + ptun_data->vl53l1_tuningparm_refspadchar_device_test_mode = + pdev->refspadchar.device_test_mode; + + ptun_data->vl53l1_tuningparm_refspadchar_vcsel_period = + pdev->refspadchar.VL53L1_p_009; + + ptun_data->vl53l1_tuningparm_refspadchar_phasecal_timeout_us = + pdev->refspadchar.timeout_us; + + ptun_data->vl53l1_tuningparm_refspadchar_target_count_rate_mcps = + pdev->refspadchar.target_count_rate_mcps; + + ptun_data->vl53l1_tuningparm_refspadchar_min_countrate_limit_mcps = + pdev->refspadchar.min_count_rate_limit_mcps; + + ptun_data->vl53l1_tuningparm_refspadchar_max_countrate_limit_mcps = + pdev->refspadchar.max_count_rate_limit_mcps; + + ptun_data->vl53l1_tuningparm_xtalk_extract_num_of_samples = + pXC->num_of_samples; + + ptun_data->vl53l1_tuningparm_xtalk_extract_min_filter_thresh_mm = + pXC->algo__crosstalk_extract_min_valid_range_mm; + + ptun_data->vl53l1_tuningparm_xtalk_extract_max_filter_thresh_mm = + pXC->algo__crosstalk_extract_max_valid_range_mm; + + ptun_data->vl53l1_tuningparm_xtalk_extract_dss_rate_mcps = + pXC->dss_config__target_total_rate_mcps; + + ptun_data->vl53l1_tuningparm_xtalk_extract_phasecal_timeout_us = + pXC->phasecal_config_timeout_us; + + ptun_data->vl53l1_tuningparm_xtalk_extract_max_valid_rate_kcps = + pXC->algo__crosstalk_extract_max_valid_rate_kcps; + + ptun_data->vl53l1_tuningparm_xtalk_extract_sigma_threshold_mm = + pXC->algo__crosstalk_extract_max_sigma_mm; + + ptun_data->vl53l1_tuningparm_xtalk_extract_dss_timeout_us = + pXC->mm_config_timeout_us; + + ptun_data->vl53l1_tuningparm_xtalk_extract_bin_timeout_us = + pXC->range_config_timeout_us; + + ptun_data->vl53l1_tuningparm_offset_cal_dss_rate_mcps = + pdev->offsetcal_cfg.dss_config__target_total_rate_mcps; + + ptun_data->vl53l1_tuningparm_offset_cal_phasecal_timeout_us = + pdev->offsetcal_cfg.phasecal_config_timeout_us; + + ptun_data->vl53l1_tuningparm_offset_cal_mm_timeout_us = + pdev->offsetcal_cfg.mm_config_timeout_us; + + ptun_data->vl53l1_tuningparm_offset_cal_range_timeout_us = + pdev->offsetcal_cfg.range_config_timeout_us; + + ptun_data->vl53l1_tuningparm_offset_cal_pre_samples = + pdev->offsetcal_cfg.pre_num_of_samples; + + ptun_data->vl53l1_tuningparm_offset_cal_mm1_samples = + pdev->offsetcal_cfg.mm1_num_of_samples; + + ptun_data->vl53l1_tuningparm_offset_cal_mm2_samples = + pdev->offsetcal_cfg.mm2_num_of_samples; + + ptun_data->vl53l1_tuningparm_zone_cal_dss_rate_mcps = + pdev->zonecal_cfg.dss_config__target_total_rate_mcps; + + ptun_data->vl53l1_tuningparm_zone_cal_phasecal_timeout_us = + pdev->zonecal_cfg.phasecal_config_timeout_us; + + ptun_data->vl53l1_tuningparm_zone_cal_dss_timeout_us = + pdev->zonecal_cfg.mm_config_timeout_us; + + ptun_data->vl53l1_tuningparm_zone_cal_phasecal_num_samples = + pdev->zonecal_cfg.phasecal_num_of_samples; + + ptun_data->vl53l1_tuningparm_zone_cal_range_timeout_us = + pdev->zonecal_cfg.range_config_timeout_us; + + ptun_data->vl53l1_tuningparm_zone_cal_zone_num_samples = + pdev->zonecal_cfg.zone_num_of_samples; + + ptun_data->vl53l1_tuningparm_spadmap_vcsel_period = + pdev->ssc_cfg.VL53L1_p_009; + + ptun_data->vl53l1_tuningparm_spadmap_vcsel_start = + pdev->ssc_cfg.vcsel_start; + + ptun_data->vl53l1_tuningparm_spadmap_rate_limit_mcps = + pdev->ssc_cfg.rate_limit_mcps; + + ptun_data->vl53l1_tuningparm_lite_dss_config_target_total_rate_mcps = + pdev->tuning_parms.tp_dss_target_lite_mcps; + + ptun_data->vl53l1_tuningparm_ranging_dss_config_target_total_rate_mcps = + pdev->tuning_parms.tp_dss_target_histo_mcps; + + ptun_data->vl53l1_tuningparm_mz_dss_config_target_total_rate_mcps = + pdev->tuning_parms.tp_dss_target_histo_mz_mcps; + + ptun_data->vl53l1_tuningparm_timed_dss_config_target_total_rate_mcps = + pdev->tuning_parms.tp_dss_target_timed_mcps; + + ptun_data->vl53l1_tuningparm_lite_phasecal_config_timeout_us = + pdev->tuning_parms.tp_phasecal_timeout_lite_us; + + ptun_data->vl53l1_tuningparm_ranging_long_phasecal_config_timeout_us = + pdev->tuning_parms.tp_phasecal_timeout_hist_long_us; + + ptun_data->vl53l1_tuningparm_ranging_med_phasecal_config_timeout_us = + pdev->tuning_parms.tp_phasecal_timeout_hist_med_us; + + ptun_data->vl53l1_tuningparm_ranging_short_phasecal_config_timeout_us = + pdev->tuning_parms.tp_phasecal_timeout_hist_short_us; + + ptun_data->vl53l1_tuningparm_mz_long_phasecal_config_timeout_us = + pdev->tuning_parms.tp_phasecal_timeout_mz_long_us; + + ptun_data->vl53l1_tuningparm_mz_med_phasecal_config_timeout_us = + pdev->tuning_parms.tp_phasecal_timeout_mz_med_us; + + ptun_data->vl53l1_tuningparm_mz_short_phasecal_config_timeout_us = + pdev->tuning_parms.tp_phasecal_timeout_mz_short_us; + + ptun_data->vl53l1_tuningparm_timed_phasecal_config_timeout_us = + pdev->tuning_parms.tp_phasecal_timeout_timed_us; + + ptun_data->vl53l1_tuningparm_lite_mm_config_timeout_us = + pdev->tuning_parms.tp_mm_timeout_lite_us; + + ptun_data->vl53l1_tuningparm_ranging_mm_config_timeout_us = + pdev->tuning_parms.tp_mm_timeout_histo_us; + + ptun_data->vl53l1_tuningparm_mz_mm_config_timeout_us = + pdev->tuning_parms.tp_mm_timeout_mz_us; + + ptun_data->vl53l1_tuningparm_timed_mm_config_timeout_us = + pdev->tuning_parms.tp_mm_timeout_timed_us; + + ptun_data->vl53l1_tuningparm_lite_range_config_timeout_us = + pdev->tuning_parms.tp_range_timeout_lite_us; + + ptun_data->vl53l1_tuningparm_ranging_range_config_timeout_us = + pdev->tuning_parms.tp_range_timeout_histo_us; + + ptun_data->vl53l1_tuningparm_mz_range_config_timeout_us = + pdev->tuning_parms.tp_range_timeout_mz_us; + + ptun_data->vl53l1_tuningparm_timed_range_config_timeout_us = + pdev->tuning_parms.tp_range_timeout_timed_us; + + ptun_data->vl53l1_tuningparm_dynxtalk_smudge_margin = + pdev->smudge_correct_config.smudge_margin; + + ptun_data->vl53l1_tuningparm_dynxtalk_noise_margin = + pdev->smudge_correct_config.noise_margin; + + ptun_data->vl53l1_tuningparm_dynxtalk_xtalk_offset_limit = + pdev->smudge_correct_config.user_xtalk_offset_limit; + + ptun_data->vl53l1_tuningparm_dynxtalk_xtalk_offset_limit_hi = + pdev->smudge_correct_config.user_xtalk_offset_limit_hi; + + ptun_data->vl53l1_tuningparm_dynxtalk_sample_limit = + pdev->smudge_correct_config.sample_limit; + + ptun_data->vl53l1_tuningparm_dynxtalk_single_xtalk_delta = + pdev->smudge_correct_config.single_xtalk_delta; + + ptun_data->vl53l1_tuningparm_dynxtalk_averaged_xtalk_delta = + pdev->smudge_correct_config.averaged_xtalk_delta; + + ptun_data->vl53l1_tuningparm_dynxtalk_clip_limit = + pdev->smudge_correct_config.smudge_corr_clip_limit; + + ptun_data->vl53l1_tuningparm_dynxtalk_scaler_calc_method = + pdev->smudge_correct_config.scaler_calc_method; + + ptun_data->vl53l1_tuningparm_dynxtalk_xgradient_scaler = + pdev->smudge_correct_config.x_gradient_scaler; + + ptun_data->vl53l1_tuningparm_dynxtalk_ygradient_scaler = + pdev->smudge_correct_config.y_gradient_scaler; + + ptun_data->vl53l1_tuningparm_dynxtalk_user_scaler_set = + pdev->smudge_correct_config.user_scaler_set; + + ptun_data->vl53l1_tuningparm_dynxtalk_smudge_cor_single_apply = + pdev->smudge_correct_config.smudge_corr_single_apply; + + ptun_data->vl53l1_tuningparm_dynxtalk_xtalk_amb_threshold = + pdev->smudge_correct_config.smudge_corr_ambient_threshold; + + ptun_data->vl53l1_tuningparm_dynxtalk_nodetect_amb_threshold_kcps = + pdev->smudge_correct_config.nodetect_ambient_threshold; + + ptun_data->vl53l1_tuningparm_dynxtalk_nodetect_sample_limit = + pdev->smudge_correct_config.nodetect_sample_limit; + + ptun_data->vl53l1_tuningparm_dynxtalk_nodetect_xtalk_offset_kcps = + pdev->smudge_correct_config.nodetect_xtalk_offset; + + ptun_data->vl53l1_tuningparm_dynxtalk_nodetect_min_range_mm = + pdev->smudge_correct_config.nodetect_min_range_mm; + + ptun_data->vl53l1_tuningparm_lowpowerauto_vhv_loop_bound = + pdev->low_power_auto_data.vhv_loop_bound; + + ptun_data->vl53l1_tuningparm_lowpowerauto_mm_config_timeout_us = + pdev->tuning_parms.tp_mm_timeout_lpa_us; + + ptun_data->vl53l1_tuningparm_lowpowerauto_range_config_timeout_us = + pdev->tuning_parms.tp_range_timeout_lpa_us; + + ptun_data->vl53l1_tuningparm_very_short_dss_rate_mcps = + pdev->tuning_parms.tp_dss_target_very_short_mcps; + + LOG_FUNCTION_END(status); + + return status; +} + + + + + + + +VL53L1_Error VL53L1_get_tuning_parm( + VL53L1_DEV Dev, + VL53L1_TuningParms tuning_parm_key, + int32_t *ptuning_parm_value) +{ + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_hist_post_process_config_t *pHP = &(pdev->histpostprocess); + VL53L1_xtalkextract_config_t *pXC = &(pdev->xtalk_extract_cfg); + + LOG_FUNCTION_START(""); + + switch (tuning_parm_key) { + + case VL53L1_TUNINGPARM_VERSION: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_tuning_parm_version; + break; + case VL53L1_TUNINGPARM_KEY_TABLE_VERSION: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_tuning_parm_key_table_version; + break; + case VL53L1_TUNINGPARM_LLD_VERSION: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_tuning_parm_lld_version; + break; + case VL53L1_TUNINGPARM_HIST_ALGO_SELECT: + *ptuning_parm_value = + (int32_t)pHP->hist_algo_select; + break; + case VL53L1_TUNINGPARM_HIST_TARGET_ORDER: + *ptuning_parm_value = + (int32_t)pHP->hist_target_order; + break; + case VL53L1_TUNINGPARM_HIST_FILTER_WOI_0: + *ptuning_parm_value = + (int32_t)pHP->filter_woi0; + break; + case VL53L1_TUNINGPARM_HIST_FILTER_WOI_1: + *ptuning_parm_value = + (int32_t)pHP->filter_woi1; + break; + case VL53L1_TUNINGPARM_HIST_AMB_EST_METHOD: + *ptuning_parm_value = + (int32_t)pHP->hist_amb_est_method; + break; + case VL53L1_TUNINGPARM_HIST_AMB_THRESH_SIGMA_0: + *ptuning_parm_value = + (int32_t)pHP->ambient_thresh_sigma0; + break; + case VL53L1_TUNINGPARM_HIST_AMB_THRESH_SIGMA_1: + *ptuning_parm_value = + (int32_t)pHP->ambient_thresh_sigma1; + break; + case VL53L1_TUNINGPARM_HIST_MIN_AMB_THRESH_EVENTS: + *ptuning_parm_value = + (int32_t)pHP->min_ambient_thresh_events; + break; + case VL53L1_TUNINGPARM_HIST_AMB_EVENTS_SCALER: + *ptuning_parm_value = + (int32_t)pHP->ambient_thresh_events_scaler; + break; + case VL53L1_TUNINGPARM_HIST_NOISE_THRESHOLD: + *ptuning_parm_value = + (int32_t)pHP->noise_threshold; + break; + case VL53L1_TUNINGPARM_HIST_SIGNAL_TOTAL_EVENTS_LIMIT: + *ptuning_parm_value = + (int32_t)pHP->signal_total_events_limit; + break; + case VL53L1_TUNINGPARM_HIST_SIGMA_EST_REF_MM: + *ptuning_parm_value = + (int32_t)pHP->sigma_estimator__sigma_ref_mm; + break; + case VL53L1_TUNINGPARM_HIST_SIGMA_THRESH_MM: + *ptuning_parm_value = + (int32_t)pHP->sigma_thresh; + break; + case VL53L1_TUNINGPARM_HIST_GAIN_FACTOR: + *ptuning_parm_value = + (int32_t)pdev->gain_cal.histogram_ranging_gain_factor; + break; + case VL53L1_TUNINGPARM_CONSISTENCY_HIST_PHASE_TOLERANCE: + *ptuning_parm_value = + (int32_t)pHP->algo__consistency_check__phase_tolerance; + break; + case VL53L1_TUNINGPARM_CONSISTENCY_HIST_MIN_MAX_TOLERANCE_MM: + *ptuning_parm_value = + (int32_t)pHP->algo__consistency_check__min_max_tolerance; + break; + case VL53L1_TUNINGPARM_CONSISTENCY_HIST_EVENT_SIGMA: + *ptuning_parm_value = + (int32_t)pHP->algo__consistency_check__event_sigma; + break; + case VL53L1_TUNINGPARM_CONSISTENCY_HIST_EVENT_SIGMA_MIN_SPAD_LIMIT: + *ptuning_parm_value = + (int32_t)pHP->algo__consistency_check__event_min_spad_count; + break; + case VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_HISTO_LONG_RANGE: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_init_phase_rtn_hist_long; + break; + case VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_HISTO_MED_RANGE: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_init_phase_rtn_hist_med; + break; + case VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_HISTO_SHORT_RANGE: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_init_phase_rtn_hist_short; + break; + case VL53L1_TUNINGPARM_INITIAL_PHASE_REF_HISTO_LONG_RANGE: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_init_phase_ref_hist_long; + break; + case VL53L1_TUNINGPARM_INITIAL_PHASE_REF_HISTO_MED_RANGE: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_init_phase_ref_hist_med; + break; + case VL53L1_TUNINGPARM_INITIAL_PHASE_REF_HISTO_SHORT_RANGE: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_init_phase_ref_hist_short; + break; + case VL53L1_TUNINGPARM_XTALK_DETECT_MIN_VALID_RANGE_MM: + *ptuning_parm_value = (int32_t)( + pdev->xtalk_cfg.algo__crosstalk_detect_min_valid_range_mm); + break; + case VL53L1_TUNINGPARM_XTALK_DETECT_MAX_VALID_RANGE_MM: + *ptuning_parm_value = (int32_t)( + pdev->xtalk_cfg.algo__crosstalk_detect_max_valid_range_mm); + break; + case VL53L1_TUNINGPARM_XTALK_DETECT_MAX_SIGMA_MM: + *ptuning_parm_value = + (int32_t)pdev->xtalk_cfg.algo__crosstalk_detect_max_sigma_mm; + break; + case VL53L1_TUNINGPARM_XTALK_DETECT_MIN_MAX_TOLERANCE: + *ptuning_parm_value = + (int32_t)pHP->algo__crosstalk_detect_min_max_tolerance; + break; + case VL53L1_TUNINGPARM_XTALK_DETECT_MAX_VALID_RATE_KCPS: + *ptuning_parm_value = (int32_t)( + pdev->xtalk_cfg.algo__crosstalk_detect_max_valid_rate_kcps); + break; + case VL53L1_TUNINGPARM_XTALK_DETECT_EVENT_SIGMA: + *ptuning_parm_value = + (int32_t)pHP->algo__crosstalk_detect_event_sigma; + break; + case VL53L1_TUNINGPARM_HIST_XTALK_MARGIN_KCPS: + *ptuning_parm_value = + (int32_t)pdev->xtalk_cfg.histogram_mode_crosstalk_margin_kcps; + break; + case VL53L1_TUNINGPARM_CONSISTENCY_LITE_PHASE_TOLERANCE: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_consistency_lite_phase_tolerance; + break; + case VL53L1_TUNINGPARM_PHASECAL_TARGET: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_phasecal_target; + break; + case VL53L1_TUNINGPARM_LITE_CAL_REPEAT_RATE: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_cal_repeat_rate; + break; + case VL53L1_TUNINGPARM_LITE_RANGING_GAIN_FACTOR: + *ptuning_parm_value = + (int32_t)pdev->gain_cal.standard_ranging_gain_factor; + break; + case VL53L1_TUNINGPARM_LITE_MIN_CLIP_MM: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_lite_min_clip; + break; + case VL53L1_TUNINGPARM_LITE_LONG_SIGMA_THRESH_MM: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_lite_long_sigma_thresh_mm; + break; + case VL53L1_TUNINGPARM_LITE_MED_SIGMA_THRESH_MM: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_lite_med_sigma_thresh_mm; + break; + case VL53L1_TUNINGPARM_LITE_SHORT_SIGMA_THRESH_MM: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_lite_short_sigma_thresh_mm; + break; + case VL53L1_TUNINGPARM_LITE_LONG_MIN_COUNT_RATE_RTN_MCPS: + *ptuning_parm_value = (int32_t)( + pdev->tuning_parms.tp_lite_long_min_count_rate_rtn_mcps); + break; + case VL53L1_TUNINGPARM_LITE_MED_MIN_COUNT_RATE_RTN_MCPS: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_lite_med_min_count_rate_rtn_mcps; + break; + case VL53L1_TUNINGPARM_LITE_SHORT_MIN_COUNT_RATE_RTN_MCPS: + *ptuning_parm_value = (int32_t)( + pdev->tuning_parms.tp_lite_short_min_count_rate_rtn_mcps); + break; + case VL53L1_TUNINGPARM_LITE_SIGMA_EST_PULSE_WIDTH: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_lite_sigma_est_pulse_width_ns; + break; + case VL53L1_TUNINGPARM_LITE_SIGMA_EST_AMB_WIDTH_NS: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_lite_sigma_est_amb_width_ns; + break; + case VL53L1_TUNINGPARM_LITE_SIGMA_REF_MM: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_lite_sigma_ref_mm; + break; + case VL53L1_TUNINGPARM_LITE_RIT_MULT: + *ptuning_parm_value = + (int32_t)pdev->xtalk_cfg.crosstalk_range_ignore_threshold_mult; + break; + case VL53L1_TUNINGPARM_LITE_SEED_CONFIG: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_lite_seed_cfg; + break; + case VL53L1_TUNINGPARM_LITE_QUANTIFIER: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_lite_quantifier; + break; + case VL53L1_TUNINGPARM_LITE_FIRST_ORDER_SELECT: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_lite_first_order_select; + break; + case VL53L1_TUNINGPARM_LITE_XTALK_MARGIN_KCPS: + *ptuning_parm_value = + (int32_t)pdev->xtalk_cfg.lite_mode_crosstalk_margin_kcps; + break; + case VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_LITE_LONG_RANGE: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_init_phase_rtn_lite_long; + break; + case VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_LITE_MED_RANGE: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_init_phase_rtn_lite_med; + break; + case VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_LITE_SHORT_RANGE: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_init_phase_rtn_lite_short; + break; + case VL53L1_TUNINGPARM_INITIAL_PHASE_REF_LITE_LONG_RANGE: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_init_phase_ref_lite_long; + break; + case VL53L1_TUNINGPARM_INITIAL_PHASE_REF_LITE_MED_RANGE: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_init_phase_ref_lite_med; + break; + case VL53L1_TUNINGPARM_INITIAL_PHASE_REF_LITE_SHORT_RANGE: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_init_phase_ref_lite_short; + break; + case VL53L1_TUNINGPARM_TIMED_SEED_CONFIG: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_timed_seed_cfg; + break; + case VL53L1_TUNINGPARM_DMAX_CFG_SIGNAL_THRESH_SIGMA: + *ptuning_parm_value = + (int32_t)pdev->dmax_cfg.signal_thresh_sigma; + break; + case VL53L1_TUNINGPARM_DMAX_CFG_REFLECTANCE_ARRAY_0: + *ptuning_parm_value = + (int32_t)pdev->dmax_cfg.target_reflectance_for_dmax_calc[0]; + break; + case VL53L1_TUNINGPARM_DMAX_CFG_REFLECTANCE_ARRAY_1: + *ptuning_parm_value = + (int32_t)pdev->dmax_cfg.target_reflectance_for_dmax_calc[1]; + break; + case VL53L1_TUNINGPARM_DMAX_CFG_REFLECTANCE_ARRAY_2: + *ptuning_parm_value = + (int32_t)pdev->dmax_cfg.target_reflectance_for_dmax_calc[2]; + break; + case VL53L1_TUNINGPARM_DMAX_CFG_REFLECTANCE_ARRAY_3: + *ptuning_parm_value = + (int32_t)pdev->dmax_cfg.target_reflectance_for_dmax_calc[3]; + break; + case VL53L1_TUNINGPARM_DMAX_CFG_REFLECTANCE_ARRAY_4: + *ptuning_parm_value = + (int32_t)pdev->dmax_cfg.target_reflectance_for_dmax_calc[4]; + break; + case VL53L1_TUNINGPARM_VHV_LOOPBOUND: + *ptuning_parm_value = + (int32_t)pdev->stat_nvm.vhv_config__timeout_macrop_loop_bound; + break; + case VL53L1_TUNINGPARM_REFSPADCHAR_DEVICE_TEST_MODE: + *ptuning_parm_value = + (int32_t)pdev->refspadchar.device_test_mode; + break; + case VL53L1_TUNINGPARM_REFSPADCHAR_VCSEL_PERIOD: + *ptuning_parm_value = + (int32_t)pdev->refspadchar.VL53L1_p_009; + break; + case VL53L1_TUNINGPARM_REFSPADCHAR_PHASECAL_TIMEOUT_US: + *ptuning_parm_value = + (int32_t)pdev->refspadchar.timeout_us; + break; + case VL53L1_TUNINGPARM_REFSPADCHAR_TARGET_COUNT_RATE_MCPS: + *ptuning_parm_value = + (int32_t)pdev->refspadchar.target_count_rate_mcps; + break; + case VL53L1_TUNINGPARM_REFSPADCHAR_MIN_COUNTRATE_LIMIT_MCPS: + *ptuning_parm_value = + (int32_t)pdev->refspadchar.min_count_rate_limit_mcps; + break; + case VL53L1_TUNINGPARM_REFSPADCHAR_MAX_COUNTRATE_LIMIT_MCPS: + *ptuning_parm_value = + (int32_t)pdev->refspadchar.max_count_rate_limit_mcps; + break; + case VL53L1_TUNINGPARM_XTALK_EXTRACT_NUM_OF_SAMPLES: + *ptuning_parm_value = + (int32_t)pXC->num_of_samples; + break; + case VL53L1_TUNINGPARM_XTALK_EXTRACT_MIN_FILTER_THRESH_MM: + *ptuning_parm_value = + (int32_t)pXC->algo__crosstalk_extract_min_valid_range_mm; + break; + case VL53L1_TUNINGPARM_XTALK_EXTRACT_MAX_FILTER_THRESH_MM: + *ptuning_parm_value = + (int32_t)pXC->algo__crosstalk_extract_max_valid_range_mm; + break; + case VL53L1_TUNINGPARM_XTALK_EXTRACT_DSS_RATE_MCPS: + *ptuning_parm_value = + (int32_t)pXC->dss_config__target_total_rate_mcps; + break; + case VL53L1_TUNINGPARM_XTALK_EXTRACT_PHASECAL_TIMEOUT_US: + *ptuning_parm_value = + (int32_t)pXC->phasecal_config_timeout_us; + break; + case VL53L1_TUNINGPARM_XTALK_EXTRACT_MAX_VALID_RATE_KCPS: + *ptuning_parm_value = + (int32_t)pXC->algo__crosstalk_extract_max_valid_rate_kcps; + break; + case VL53L1_TUNINGPARM_XTALK_EXTRACT_SIGMA_THRESHOLD_MM: + *ptuning_parm_value = + (int32_t)pXC->algo__crosstalk_extract_max_sigma_mm; + break; + case VL53L1_TUNINGPARM_XTALK_EXTRACT_DSS_TIMEOUT_US: + *ptuning_parm_value = + (int32_t)pXC->mm_config_timeout_us; + break; + case VL53L1_TUNINGPARM_XTALK_EXTRACT_BIN_TIMEOUT_US: + *ptuning_parm_value = + (int32_t)pXC->range_config_timeout_us; + break; + case VL53L1_TUNINGPARM_OFFSET_CAL_DSS_RATE_MCPS: + *ptuning_parm_value = + (int32_t)pdev->offsetcal_cfg.dss_config__target_total_rate_mcps; + break; + case VL53L1_TUNINGPARM_OFFSET_CAL_PHASECAL_TIMEOUT_US: + *ptuning_parm_value = + (int32_t)pdev->offsetcal_cfg.phasecal_config_timeout_us; + break; + case VL53L1_TUNINGPARM_OFFSET_CAL_MM_TIMEOUT_US: + *ptuning_parm_value = + (int32_t)pdev->offsetcal_cfg.mm_config_timeout_us; + break; + case VL53L1_TUNINGPARM_OFFSET_CAL_RANGE_TIMEOUT_US: + *ptuning_parm_value = + (int32_t)pdev->offsetcal_cfg.range_config_timeout_us; + break; + case VL53L1_TUNINGPARM_OFFSET_CAL_PRE_SAMPLES: + *ptuning_parm_value = + (int32_t)pdev->offsetcal_cfg.pre_num_of_samples; + break; + case VL53L1_TUNINGPARM_OFFSET_CAL_MM1_SAMPLES: + *ptuning_parm_value = + (int32_t)pdev->offsetcal_cfg.mm1_num_of_samples; + break; + case VL53L1_TUNINGPARM_OFFSET_CAL_MM2_SAMPLES: + *ptuning_parm_value = + (int32_t)pdev->offsetcal_cfg.mm2_num_of_samples; + break; + case VL53L1_TUNINGPARM_ZONE_CAL_DSS_RATE_MCPS: + *ptuning_parm_value = + (int32_t)pdev->zonecal_cfg.dss_config__target_total_rate_mcps; + break; + case VL53L1_TUNINGPARM_ZONE_CAL_PHASECAL_TIMEOUT_US: + *ptuning_parm_value = + (int32_t)pdev->zonecal_cfg.phasecal_config_timeout_us; + break; + case VL53L1_TUNINGPARM_ZONE_CAL_DSS_TIMEOUT_US: + *ptuning_parm_value = + (int32_t)pdev->zonecal_cfg.mm_config_timeout_us; + break; + case VL53L1_TUNINGPARM_ZONE_CAL_PHASECAL_NUM_SAMPLES: + *ptuning_parm_value = + (int32_t)pdev->zonecal_cfg.phasecal_num_of_samples; + break; + case VL53L1_TUNINGPARM_ZONE_CAL_RANGE_TIMEOUT_US: + *ptuning_parm_value = + (int32_t)pdev->zonecal_cfg.range_config_timeout_us; + break; + case VL53L1_TUNINGPARM_ZONE_CAL_ZONE_NUM_SAMPLES: + *ptuning_parm_value = + (int32_t)pdev->zonecal_cfg.zone_num_of_samples; + break; + case VL53L1_TUNINGPARM_SPADMAP_VCSEL_PERIOD: + *ptuning_parm_value = + (int32_t)pdev->ssc_cfg.VL53L1_p_009; + break; + case VL53L1_TUNINGPARM_SPADMAP_VCSEL_START: + *ptuning_parm_value = + (int32_t)pdev->ssc_cfg.vcsel_start; + break; + case VL53L1_TUNINGPARM_SPADMAP_RATE_LIMIT_MCPS: + *ptuning_parm_value = + (int32_t)pdev->ssc_cfg.rate_limit_mcps; + break; + case VL53L1_TUNINGPARM_LITE_DSS_CONFIG_TARGET_TOTAL_RATE_MCPS: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_dss_target_lite_mcps; + break; + case VL53L1_TUNINGPARM_RANGING_DSS_CONFIG_TARGET_TOTAL_RATE_MCPS: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_dss_target_histo_mcps; + break; + case VL53L1_TUNINGPARM_MZ_DSS_CONFIG_TARGET_TOTAL_RATE_MCPS: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_dss_target_histo_mz_mcps; + break; + case VL53L1_TUNINGPARM_TIMED_DSS_CONFIG_TARGET_TOTAL_RATE_MCPS: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_dss_target_timed_mcps; + break; + case VL53L1_TUNINGPARM_LITE_PHASECAL_CONFIG_TIMEOUT_US: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_phasecal_timeout_lite_us; + break; + case VL53L1_TUNINGPARM_RANGING_LONG_PHASECAL_CONFIG_TIMEOUT_US: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_phasecal_timeout_hist_long_us; + break; + case VL53L1_TUNINGPARM_RANGING_MED_PHASECAL_CONFIG_TIMEOUT_US: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_phasecal_timeout_hist_med_us; + break; + case VL53L1_TUNINGPARM_RANGING_SHORT_PHASECAL_CONFIG_TIMEOUT_US: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_phasecal_timeout_hist_short_us; + break; + case VL53L1_TUNINGPARM_MZ_LONG_PHASECAL_CONFIG_TIMEOUT_US: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_phasecal_timeout_mz_long_us; + break; + case VL53L1_TUNINGPARM_MZ_MED_PHASECAL_CONFIG_TIMEOUT_US: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_phasecal_timeout_mz_med_us; + break; + case VL53L1_TUNINGPARM_MZ_SHORT_PHASECAL_CONFIG_TIMEOUT_US: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_phasecal_timeout_mz_short_us; + break; + case VL53L1_TUNINGPARM_TIMED_PHASECAL_CONFIG_TIMEOUT_US: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_phasecal_timeout_timed_us; + break; + case VL53L1_TUNINGPARM_LITE_MM_CONFIG_TIMEOUT_US: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_mm_timeout_lite_us; + break; + case VL53L1_TUNINGPARM_RANGING_MM_CONFIG_TIMEOUT_US: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_mm_timeout_histo_us; + break; + case VL53L1_TUNINGPARM_MZ_MM_CONFIG_TIMEOUT_US: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_mm_timeout_mz_us; + break; + case VL53L1_TUNINGPARM_TIMED_MM_CONFIG_TIMEOUT_US: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_mm_timeout_timed_us; + break; + case VL53L1_TUNINGPARM_LITE_RANGE_CONFIG_TIMEOUT_US: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_range_timeout_lite_us; + break; + case VL53L1_TUNINGPARM_RANGING_RANGE_CONFIG_TIMEOUT_US: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_range_timeout_histo_us; + break; + case VL53L1_TUNINGPARM_MZ_RANGE_CONFIG_TIMEOUT_US: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_range_timeout_mz_us; + break; + case VL53L1_TUNINGPARM_TIMED_RANGE_CONFIG_TIMEOUT_US: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_range_timeout_timed_us; + break; + case VL53L1_TUNINGPARM_DYNXTALK_SMUDGE_MARGIN: + *ptuning_parm_value = + (int32_t)pdev->smudge_correct_config.smudge_margin; + break; + case VL53L1_TUNINGPARM_DYNXTALK_NOISE_MARGIN: + *ptuning_parm_value = + (int32_t)pdev->smudge_correct_config.noise_margin; + break; + case VL53L1_TUNINGPARM_DYNXTALK_XTALK_OFFSET_LIMIT: + *ptuning_parm_value = + (int32_t)pdev->smudge_correct_config.user_xtalk_offset_limit; + break; + case VL53L1_TUNINGPARM_DYNXTALK_XTALK_OFFSET_LIMIT_HI: + *ptuning_parm_value = + (int32_t)pdev->smudge_correct_config.user_xtalk_offset_limit_hi; + break; + case VL53L1_TUNINGPARM_DYNXTALK_SAMPLE_LIMIT: + *ptuning_parm_value = + (int32_t)pdev->smudge_correct_config.sample_limit; + break; + case VL53L1_TUNINGPARM_DYNXTALK_SINGLE_XTALK_DELTA: + *ptuning_parm_value = + (int32_t)pdev->smudge_correct_config.single_xtalk_delta; + break; + case VL53L1_TUNINGPARM_DYNXTALK_AVERAGED_XTALK_DELTA: + *ptuning_parm_value = + (int32_t)pdev->smudge_correct_config.averaged_xtalk_delta; + break; + case VL53L1_TUNINGPARM_DYNXTALK_CLIP_LIMIT: + *ptuning_parm_value = + (int32_t)pdev->smudge_correct_config.smudge_corr_clip_limit; + break; + case VL53L1_TUNINGPARM_DYNXTALK_SCALER_CALC_METHOD: + *ptuning_parm_value = + (int32_t)pdev->smudge_correct_config.scaler_calc_method; + break; + case VL53L1_TUNINGPARM_DYNXTALK_XGRADIENT_SCALER: + *ptuning_parm_value = + (int32_t)pdev->smudge_correct_config.x_gradient_scaler; + break; + case VL53L1_TUNINGPARM_DYNXTALK_YGRADIENT_SCALER: + *ptuning_parm_value = + (int32_t)pdev->smudge_correct_config.y_gradient_scaler; + break; + case VL53L1_TUNINGPARM_DYNXTALK_USER_SCALER_SET: + *ptuning_parm_value = + (int32_t)pdev->smudge_correct_config.user_scaler_set; + break; + case VL53L1_TUNINGPARM_DYNXTALK_SMUDGE_COR_SINGLE_APPLY: + *ptuning_parm_value = + (int32_t)pdev->smudge_correct_config.smudge_corr_single_apply; + break; + case VL53L1_TUNINGPARM_DYNXTALK_XTALK_AMB_THRESHOLD: + *ptuning_parm_value = (int32_t)( + pdev->smudge_correct_config.smudge_corr_ambient_threshold); + break; + case VL53L1_TUNINGPARM_DYNXTALK_NODETECT_AMB_THRESHOLD_KCPS: + *ptuning_parm_value = + (int32_t)pdev->smudge_correct_config.nodetect_ambient_threshold; + break; + case VL53L1_TUNINGPARM_DYNXTALK_NODETECT_SAMPLE_LIMIT: + *ptuning_parm_value = + (int32_t)pdev->smudge_correct_config.nodetect_sample_limit; + break; + case VL53L1_TUNINGPARM_DYNXTALK_NODETECT_XTALK_OFFSET_KCPS: + *ptuning_parm_value = + (int32_t)pdev->smudge_correct_config.nodetect_xtalk_offset; + break; + case VL53L1_TUNINGPARM_DYNXTALK_NODETECT_MIN_RANGE_MM: + *ptuning_parm_value = + (int32_t)pdev->smudge_correct_config.nodetect_min_range_mm; + break; + case VL53L1_TUNINGPARM_LOWPOWERAUTO_VHV_LOOP_BOUND: + *ptuning_parm_value = + (int32_t)pdev->low_power_auto_data.vhv_loop_bound; + break; + case VL53L1_TUNINGPARM_LOWPOWERAUTO_MM_CONFIG_TIMEOUT_US: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_mm_timeout_lpa_us; + break; + case VL53L1_TUNINGPARM_LOWPOWERAUTO_RANGE_CONFIG_TIMEOUT_US: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_range_timeout_lpa_us; + break; + case VL53L1_TUNINGPARM_VERY_SHORT_DSS_RATE_MCPS: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_dss_target_very_short_mcps; + break; + + + default: + *ptuning_parm_value = 0x7FFFFFFF; + status = VL53L1_ERROR_INVALID_PARAMS; + break; + + } + + LOG_FUNCTION_END(status); + + return status; +} + +VL53L1_Error VL53L1_set_tuning_parm( + VL53L1_DEV Dev, + VL53L1_TuningParms tuning_parm_key, + int32_t tuning_parm_value) +{ + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_hist_post_process_config_t *pHP = &(pdev->histpostprocess); + VL53L1_xtalkextract_config_t *pXC = &(pdev->xtalk_extract_cfg); + + LOG_FUNCTION_START(""); + + switch (tuning_parm_key) { + + case VL53L1_TUNINGPARM_VERSION: + pdev->tuning_parms.tp_tuning_parm_version = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_KEY_TABLE_VERSION: + pdev->tuning_parms.tp_tuning_parm_key_table_version = + (uint16_t)tuning_parm_value; + + + + + + + + + + + if ((uint16_t)tuning_parm_value + != VL53L1_TUNINGPARM_KEY_TABLE_VERSION_DEFAULT) + status = VL53L1_ERROR_TUNING_PARM_KEY_MISMATCH; + + break; + case VL53L1_TUNINGPARM_LLD_VERSION: + pdev->tuning_parms.tp_tuning_parm_lld_version = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_HIST_ALGO_SELECT: + pHP->hist_algo_select = + (VL53L1_HistAlgoSelect)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_HIST_TARGET_ORDER: + pHP->hist_target_order = + (VL53L1_HistTargetOrder)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_HIST_FILTER_WOI_0: + pHP->filter_woi0 = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_HIST_FILTER_WOI_1: + pHP->filter_woi1 = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_HIST_AMB_EST_METHOD: + pHP->hist_amb_est_method = + (VL53L1_HistAmbEstMethod)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_HIST_AMB_THRESH_SIGMA_0: + pHP->ambient_thresh_sigma0 = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_HIST_AMB_THRESH_SIGMA_1: + pHP->ambient_thresh_sigma1 = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_HIST_MIN_AMB_THRESH_EVENTS: + pHP->min_ambient_thresh_events = + (int32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_HIST_AMB_EVENTS_SCALER: + pHP->ambient_thresh_events_scaler = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_HIST_NOISE_THRESHOLD: + pHP->noise_threshold = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_HIST_SIGNAL_TOTAL_EVENTS_LIMIT: + pHP->signal_total_events_limit = + (int32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_HIST_SIGMA_EST_REF_MM: + pHP->sigma_estimator__sigma_ref_mm = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_HIST_SIGMA_THRESH_MM: + pHP->sigma_thresh = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_HIST_GAIN_FACTOR: + pdev->gain_cal.histogram_ranging_gain_factor = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_CONSISTENCY_HIST_PHASE_TOLERANCE: + pHP->algo__consistency_check__phase_tolerance = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_CONSISTENCY_HIST_MIN_MAX_TOLERANCE_MM: + pHP->algo__consistency_check__min_max_tolerance = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_CONSISTENCY_HIST_EVENT_SIGMA: + pHP->algo__consistency_check__event_sigma = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_CONSISTENCY_HIST_EVENT_SIGMA_MIN_SPAD_LIMIT: + pHP->algo__consistency_check__event_min_spad_count = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_HISTO_LONG_RANGE: + pdev->tuning_parms.tp_init_phase_rtn_hist_long = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_HISTO_MED_RANGE: + pdev->tuning_parms.tp_init_phase_rtn_hist_med = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_HISTO_SHORT_RANGE: + pdev->tuning_parms.tp_init_phase_rtn_hist_short = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_INITIAL_PHASE_REF_HISTO_LONG_RANGE: + pdev->tuning_parms.tp_init_phase_ref_hist_long = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_INITIAL_PHASE_REF_HISTO_MED_RANGE: + pdev->tuning_parms.tp_init_phase_ref_hist_med = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_INITIAL_PHASE_REF_HISTO_SHORT_RANGE: + pdev->tuning_parms.tp_init_phase_ref_hist_short = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_XTALK_DETECT_MIN_VALID_RANGE_MM: + pdev->xtalk_cfg.algo__crosstalk_detect_min_valid_range_mm = + (int16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_XTALK_DETECT_MAX_VALID_RANGE_MM: + pdev->xtalk_cfg.algo__crosstalk_detect_max_valid_range_mm = + (int16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_XTALK_DETECT_MAX_SIGMA_MM: + pdev->xtalk_cfg.algo__crosstalk_detect_max_sigma_mm = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_XTALK_DETECT_MIN_MAX_TOLERANCE: + pHP->algo__crosstalk_detect_min_max_tolerance = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_XTALK_DETECT_MAX_VALID_RATE_KCPS: + pdev->xtalk_cfg.algo__crosstalk_detect_max_valid_rate_kcps = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_XTALK_DETECT_EVENT_SIGMA: + pHP->algo__crosstalk_detect_event_sigma = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_HIST_XTALK_MARGIN_KCPS: + pdev->xtalk_cfg.histogram_mode_crosstalk_margin_kcps = + (int16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_CONSISTENCY_LITE_PHASE_TOLERANCE: + pdev->tuning_parms.tp_consistency_lite_phase_tolerance = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_PHASECAL_TARGET: + pdev->tuning_parms.tp_phasecal_target = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_LITE_CAL_REPEAT_RATE: + pdev->tuning_parms.tp_cal_repeat_rate = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_LITE_RANGING_GAIN_FACTOR: + pdev->gain_cal.standard_ranging_gain_factor = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_LITE_MIN_CLIP_MM: + pdev->tuning_parms.tp_lite_min_clip = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_LITE_LONG_SIGMA_THRESH_MM: + pdev->tuning_parms.tp_lite_long_sigma_thresh_mm = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_LITE_MED_SIGMA_THRESH_MM: + pdev->tuning_parms.tp_lite_med_sigma_thresh_mm = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_LITE_SHORT_SIGMA_THRESH_MM: + pdev->tuning_parms.tp_lite_short_sigma_thresh_mm = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_LITE_LONG_MIN_COUNT_RATE_RTN_MCPS: + pdev->tuning_parms.tp_lite_long_min_count_rate_rtn_mcps = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_LITE_MED_MIN_COUNT_RATE_RTN_MCPS: + pdev->tuning_parms.tp_lite_med_min_count_rate_rtn_mcps = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_LITE_SHORT_MIN_COUNT_RATE_RTN_MCPS: + pdev->tuning_parms.tp_lite_short_min_count_rate_rtn_mcps = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_LITE_SIGMA_EST_PULSE_WIDTH: + pdev->tuning_parms.tp_lite_sigma_est_pulse_width_ns = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_LITE_SIGMA_EST_AMB_WIDTH_NS: + pdev->tuning_parms.tp_lite_sigma_est_amb_width_ns = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_LITE_SIGMA_REF_MM: + pdev->tuning_parms.tp_lite_sigma_ref_mm = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_LITE_RIT_MULT: + pdev->xtalk_cfg.crosstalk_range_ignore_threshold_mult = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_LITE_SEED_CONFIG: + pdev->tuning_parms.tp_lite_seed_cfg = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_LITE_QUANTIFIER: + pdev->tuning_parms.tp_lite_quantifier = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_LITE_FIRST_ORDER_SELECT: + pdev->tuning_parms.tp_lite_first_order_select = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_LITE_XTALK_MARGIN_KCPS: + pdev->xtalk_cfg.lite_mode_crosstalk_margin_kcps = + (int16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_LITE_LONG_RANGE: + pdev->tuning_parms.tp_init_phase_rtn_lite_long = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_LITE_MED_RANGE: + pdev->tuning_parms.tp_init_phase_rtn_lite_med = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_LITE_SHORT_RANGE: + pdev->tuning_parms.tp_init_phase_rtn_lite_short = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_INITIAL_PHASE_REF_LITE_LONG_RANGE: + pdev->tuning_parms.tp_init_phase_ref_lite_long = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_INITIAL_PHASE_REF_LITE_MED_RANGE: + pdev->tuning_parms.tp_init_phase_ref_lite_med = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_INITIAL_PHASE_REF_LITE_SHORT_RANGE: + pdev->tuning_parms.tp_init_phase_ref_lite_short = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_TIMED_SEED_CONFIG: + pdev->tuning_parms.tp_timed_seed_cfg = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_DMAX_CFG_SIGNAL_THRESH_SIGMA: + pdev->dmax_cfg.signal_thresh_sigma = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_DMAX_CFG_REFLECTANCE_ARRAY_0: + pdev->dmax_cfg.target_reflectance_for_dmax_calc[0] = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_DMAX_CFG_REFLECTANCE_ARRAY_1: + pdev->dmax_cfg.target_reflectance_for_dmax_calc[1] = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_DMAX_CFG_REFLECTANCE_ARRAY_2: + pdev->dmax_cfg.target_reflectance_for_dmax_calc[2] = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_DMAX_CFG_REFLECTANCE_ARRAY_3: + pdev->dmax_cfg.target_reflectance_for_dmax_calc[3] = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_DMAX_CFG_REFLECTANCE_ARRAY_4: + pdev->dmax_cfg.target_reflectance_for_dmax_calc[4] = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_VHV_LOOPBOUND: + pdev->stat_nvm.vhv_config__timeout_macrop_loop_bound = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_REFSPADCHAR_DEVICE_TEST_MODE: + pdev->refspadchar.device_test_mode = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_REFSPADCHAR_VCSEL_PERIOD: + pdev->refspadchar.VL53L1_p_009 = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_REFSPADCHAR_PHASECAL_TIMEOUT_US: + pdev->refspadchar.timeout_us = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_REFSPADCHAR_TARGET_COUNT_RATE_MCPS: + pdev->refspadchar.target_count_rate_mcps = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_REFSPADCHAR_MIN_COUNTRATE_LIMIT_MCPS: + pdev->refspadchar.min_count_rate_limit_mcps = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_REFSPADCHAR_MAX_COUNTRATE_LIMIT_MCPS: + pdev->refspadchar.max_count_rate_limit_mcps = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_XTALK_EXTRACT_NUM_OF_SAMPLES: + pXC->num_of_samples = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_XTALK_EXTRACT_MIN_FILTER_THRESH_MM: + pXC->algo__crosstalk_extract_min_valid_range_mm = + (int16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_XTALK_EXTRACT_MAX_FILTER_THRESH_MM: + pXC->algo__crosstalk_extract_max_valid_range_mm = + (int16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_XTALK_EXTRACT_DSS_RATE_MCPS: + pXC->dss_config__target_total_rate_mcps = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_XTALK_EXTRACT_PHASECAL_TIMEOUT_US: + pXC->phasecal_config_timeout_us = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_XTALK_EXTRACT_MAX_VALID_RATE_KCPS: + pXC->algo__crosstalk_extract_max_valid_rate_kcps = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_XTALK_EXTRACT_SIGMA_THRESHOLD_MM: + pXC->algo__crosstalk_extract_max_sigma_mm = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_XTALK_EXTRACT_DSS_TIMEOUT_US: + pXC->mm_config_timeout_us = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_XTALK_EXTRACT_BIN_TIMEOUT_US: + pXC->range_config_timeout_us = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_OFFSET_CAL_DSS_RATE_MCPS: + pdev->offsetcal_cfg.dss_config__target_total_rate_mcps = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_OFFSET_CAL_PHASECAL_TIMEOUT_US: + pdev->offsetcal_cfg.phasecal_config_timeout_us = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_OFFSET_CAL_MM_TIMEOUT_US: + pdev->offsetcal_cfg.mm_config_timeout_us = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_OFFSET_CAL_RANGE_TIMEOUT_US: + pdev->offsetcal_cfg.range_config_timeout_us = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_OFFSET_CAL_PRE_SAMPLES: + pdev->offsetcal_cfg.pre_num_of_samples = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_OFFSET_CAL_MM1_SAMPLES: + pdev->offsetcal_cfg.mm1_num_of_samples = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_OFFSET_CAL_MM2_SAMPLES: + pdev->offsetcal_cfg.mm2_num_of_samples = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_ZONE_CAL_DSS_RATE_MCPS: + pdev->zonecal_cfg.dss_config__target_total_rate_mcps = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_ZONE_CAL_PHASECAL_TIMEOUT_US: + pdev->zonecal_cfg.phasecal_config_timeout_us = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_ZONE_CAL_DSS_TIMEOUT_US: + pdev->zonecal_cfg.mm_config_timeout_us = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_ZONE_CAL_PHASECAL_NUM_SAMPLES: + pdev->zonecal_cfg.phasecal_num_of_samples = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_ZONE_CAL_RANGE_TIMEOUT_US: + pdev->zonecal_cfg.range_config_timeout_us = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_ZONE_CAL_ZONE_NUM_SAMPLES: + pdev->zonecal_cfg.zone_num_of_samples = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_SPADMAP_VCSEL_PERIOD: + pdev->ssc_cfg.VL53L1_p_009 = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_SPADMAP_VCSEL_START: + pdev->ssc_cfg.vcsel_start = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_SPADMAP_RATE_LIMIT_MCPS: + pdev->ssc_cfg.rate_limit_mcps = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_LITE_DSS_CONFIG_TARGET_TOTAL_RATE_MCPS: + pdev->tuning_parms.tp_dss_target_lite_mcps = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_RANGING_DSS_CONFIG_TARGET_TOTAL_RATE_MCPS: + pdev->tuning_parms.tp_dss_target_histo_mcps = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_MZ_DSS_CONFIG_TARGET_TOTAL_RATE_MCPS: + pdev->tuning_parms.tp_dss_target_histo_mz_mcps = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_TIMED_DSS_CONFIG_TARGET_TOTAL_RATE_MCPS: + pdev->tuning_parms.tp_dss_target_timed_mcps = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_LITE_PHASECAL_CONFIG_TIMEOUT_US: + pdev->tuning_parms.tp_phasecal_timeout_lite_us = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_RANGING_LONG_PHASECAL_CONFIG_TIMEOUT_US: + pdev->tuning_parms.tp_phasecal_timeout_hist_long_us = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_RANGING_MED_PHASECAL_CONFIG_TIMEOUT_US: + pdev->tuning_parms.tp_phasecal_timeout_hist_med_us = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_RANGING_SHORT_PHASECAL_CONFIG_TIMEOUT_US: + pdev->tuning_parms.tp_phasecal_timeout_hist_short_us = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_MZ_LONG_PHASECAL_CONFIG_TIMEOUT_US: + pdev->tuning_parms.tp_phasecal_timeout_mz_long_us = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_MZ_MED_PHASECAL_CONFIG_TIMEOUT_US: + pdev->tuning_parms.tp_phasecal_timeout_mz_med_us = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_MZ_SHORT_PHASECAL_CONFIG_TIMEOUT_US: + pdev->tuning_parms.tp_phasecal_timeout_mz_short_us = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_TIMED_PHASECAL_CONFIG_TIMEOUT_US: + pdev->tuning_parms.tp_phasecal_timeout_timed_us = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_LITE_MM_CONFIG_TIMEOUT_US: + pdev->tuning_parms.tp_mm_timeout_lite_us = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_RANGING_MM_CONFIG_TIMEOUT_US: + pdev->tuning_parms.tp_mm_timeout_histo_us = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_MZ_MM_CONFIG_TIMEOUT_US: + pdev->tuning_parms.tp_mm_timeout_mz_us = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_TIMED_MM_CONFIG_TIMEOUT_US: + pdev->tuning_parms.tp_mm_timeout_timed_us = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_LITE_RANGE_CONFIG_TIMEOUT_US: + pdev->tuning_parms.tp_range_timeout_lite_us = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_RANGING_RANGE_CONFIG_TIMEOUT_US: + pdev->tuning_parms.tp_range_timeout_histo_us = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_MZ_RANGE_CONFIG_TIMEOUT_US: + pdev->tuning_parms.tp_range_timeout_mz_us = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_TIMED_RANGE_CONFIG_TIMEOUT_US: + pdev->tuning_parms.tp_range_timeout_timed_us = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_DYNXTALK_SMUDGE_MARGIN: + pdev->smudge_correct_config.smudge_margin = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_DYNXTALK_NOISE_MARGIN: + pdev->smudge_correct_config.noise_margin = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_DYNXTALK_XTALK_OFFSET_LIMIT: + pdev->smudge_correct_config.user_xtalk_offset_limit = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_DYNXTALK_XTALK_OFFSET_LIMIT_HI: + pdev->smudge_correct_config.user_xtalk_offset_limit_hi = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_DYNXTALK_SAMPLE_LIMIT: + pdev->smudge_correct_config.sample_limit = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_DYNXTALK_SINGLE_XTALK_DELTA: + pdev->smudge_correct_config.single_xtalk_delta = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_DYNXTALK_AVERAGED_XTALK_DELTA: + pdev->smudge_correct_config.averaged_xtalk_delta = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_DYNXTALK_CLIP_LIMIT: + pdev->smudge_correct_config.smudge_corr_clip_limit = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_DYNXTALK_SCALER_CALC_METHOD: + pdev->smudge_correct_config.scaler_calc_method = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_DYNXTALK_XGRADIENT_SCALER: + pdev->smudge_correct_config.x_gradient_scaler = + (int16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_DYNXTALK_YGRADIENT_SCALER: + pdev->smudge_correct_config.y_gradient_scaler = + (int16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_DYNXTALK_USER_SCALER_SET: + pdev->smudge_correct_config.user_scaler_set = + (uint8_t)tuning_parm_value; + break; + + case VL53L1_TUNINGPARM_DYNXTALK_SMUDGE_COR_SINGLE_APPLY: + pdev->smudge_correct_config.smudge_corr_single_apply = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_DYNXTALK_XTALK_AMB_THRESHOLD: + pdev->smudge_correct_config.smudge_corr_ambient_threshold = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_DYNXTALK_NODETECT_AMB_THRESHOLD_KCPS: + pdev->smudge_correct_config.nodetect_ambient_threshold = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_DYNXTALK_NODETECT_SAMPLE_LIMIT: + pdev->smudge_correct_config.nodetect_sample_limit = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_DYNXTALK_NODETECT_XTALK_OFFSET_KCPS: + pdev->smudge_correct_config.nodetect_xtalk_offset = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_DYNXTALK_NODETECT_MIN_RANGE_MM: + pdev->smudge_correct_config.nodetect_min_range_mm = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_LOWPOWERAUTO_VHV_LOOP_BOUND: + pdev->low_power_auto_data.vhv_loop_bound = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_LOWPOWERAUTO_MM_CONFIG_TIMEOUT_US: + pdev->tuning_parms.tp_mm_timeout_lpa_us = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_LOWPOWERAUTO_RANGE_CONFIG_TIMEOUT_US: + pdev->tuning_parms.tp_range_timeout_lpa_us = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_VERY_SHORT_DSS_RATE_MCPS: + pdev->tuning_parms.tp_dss_target_very_short_mcps = + (uint16_t)tuning_parm_value; + break; + + + default: + status = VL53L1_ERROR_INVALID_PARAMS; + break; + + } + + LOG_FUNCTION_END(status); + + return status; +} + + + + + + + +VL53L1_Error VL53L1_dynamic_xtalk_correction_enable( + VL53L1_DEV Dev + ) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + pdev->smudge_correct_config.smudge_corr_enabled = 1; + + LOG_FUNCTION_END(status); + + return status; +} + +VL53L1_Error VL53L1_dynamic_xtalk_correction_disable( + VL53L1_DEV Dev + ) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + pdev->smudge_correct_config.smudge_corr_enabled = 0; + + LOG_FUNCTION_END(status); + + return status; +} + +VL53L1_Error VL53L1_dynamic_xtalk_correction_apply_enable( + VL53L1_DEV Dev + ) +{ + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + pdev->smudge_correct_config.smudge_corr_apply_enabled = 1; + + LOG_FUNCTION_END(status); + + return status; +} + +VL53L1_Error VL53L1_dynamic_xtalk_correction_apply_disable( + VL53L1_DEV Dev + ) +{ + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + pdev->smudge_correct_config.smudge_corr_apply_enabled = 0; + + LOG_FUNCTION_END(status); + + return status; +} + +VL53L1_Error VL53L1_dynamic_xtalk_correction_single_apply_enable( + VL53L1_DEV Dev + ) +{ + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + pdev->smudge_correct_config.smudge_corr_single_apply = 1; + + LOG_FUNCTION_END(status); + + return status; +} + +VL53L1_Error VL53L1_dynamic_xtalk_correction_single_apply_disable( + VL53L1_DEV Dev + ) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + pdev->smudge_correct_config.smudge_corr_single_apply = 0; + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_dynamic_xtalk_correction_set_scalers( + VL53L1_DEV Dev, + int16_t x_scaler_in, + int16_t y_scaler_in, + uint8_t user_scaler_set_in + ) +{ + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + pdev->smudge_correct_config.x_gradient_scaler = x_scaler_in; + pdev->smudge_correct_config.y_gradient_scaler = y_scaler_in; + pdev->smudge_correct_config.user_scaler_set = user_scaler_set_in; + + LOG_FUNCTION_END(status); + + return status; +} + + + + + + + + +VL53L1_Error VL53L1_get_current_xtalk_settings( + VL53L1_DEV Dev, + VL53L1_xtalk_calibration_results_t *pxtalk + ) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + pxtalk->algo__crosstalk_compensation_plane_offset_kcps = + pdev->xtalk_cfg.algo__crosstalk_compensation_plane_offset_kcps; + pxtalk->algo__crosstalk_compensation_x_plane_gradient_kcps = + pdev->xtalk_cfg.algo__crosstalk_compensation_x_plane_gradient_kcps; + pxtalk->algo__crosstalk_compensation_y_plane_gradient_kcps = + pdev->xtalk_cfg.algo__crosstalk_compensation_y_plane_gradient_kcps; + + + + LOG_FUNCTION_END(status); + + return status; + +} + + + + + + + +VL53L1_Error VL53L1_set_current_xtalk_settings( + VL53L1_DEV Dev, + VL53L1_xtalk_calibration_results_t *pxtalk + ) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + pdev->xtalk_cfg.algo__crosstalk_compensation_plane_offset_kcps = + pxtalk->algo__crosstalk_compensation_plane_offset_kcps; + pdev->xtalk_cfg.algo__crosstalk_compensation_x_plane_gradient_kcps = + pxtalk->algo__crosstalk_compensation_x_plane_gradient_kcps; + pdev->xtalk_cfg.algo__crosstalk_compensation_y_plane_gradient_kcps = + pxtalk->algo__crosstalk_compensation_y_plane_gradient_kcps; + + + + LOG_FUNCTION_END(status); + + return status; + +} + + + + diff --git a/drivers/input/misc/vl53L1/lito/src/vl53l1_api_debug.c b/drivers/input/misc/vl53L1/lito/src/vl53l1_api_debug.c new file mode 100644 index 000000000000..46f7f0daa5d3 --- /dev/null +++ b/drivers/input/misc/vl53L1/lito/src/vl53l1_api_debug.c @@ -0,0 +1,3629 @@ + +/******************************************************************************* + * Copyright (c) 2017, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#include "vl53l1_ll_def.h" +#include "vl53l1_ll_device.h" +#include "vl53l1_register_structs.h" +#include "vl53l1_hist_structs.h" +#include "vl53l1_nvm_structs.h" +#include "vl53l1_nvm.h" +#include "vl53l1_core.h" +#include "vl53l1_api_debug.h" + +#ifdef VL53L1_LOG_ENABLE +#include "vl53l1_nvm_debug.h" +#endif + +#define LOG_FUNCTION_START(fmt, ...) \ + _LOG_FUNCTION_START(VL53L1_TRACE_MODULE_CORE, fmt, ##__VA_ARGS__) +#define LOG_FUNCTION_END(status, ...) \ + _LOG_FUNCTION_END(VL53L1_TRACE_MODULE_CORE, status, ##__VA_ARGS__) +#define LOG_FUNCTION_END_FMT(status, fmt, ...) \ + _LOG_FUNCTION_END_FMT(VL53L1_TRACE_MODULE_CORE, status, \ + fmt, ##__VA_ARGS__) + +#define trace_print(level, ...) \ + _LOG_TRACE_PRINT(trace_flags, \ + level, VL53L1_TRACE_FUNCTION_NONE, ##__VA_ARGS__) + + +VL53L1_Error VL53L1_decode_calibration_data_buffer( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_calibration_data_t *pdata) +{ + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (sizeof(VL53L1_calibration_data_t) > buf_size) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + memcpy(pdata, pbuffer, sizeof(VL53L1_calibration_data_t)); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_nvm_debug_data( + VL53L1_DEV Dev, + VL53L1_decoded_nvm_data_t *pdata) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + status = VL53L1_read_nvm(Dev, 0, pdata); + +#ifdef VL53L1_LOG_ENABLE + if (status == VL53L1_ERROR_NONE) + VL53L1_print_decoded_nvm_data( + pdata, + "get_nvm_debug_data():pnvm_info.", + VL53L1_TRACE_MODULE_NVM_DATA); +#endif + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_histogram_debug_data( + VL53L1_DEV Dev, + VL53L1_histogram_bin_data_t *pdata) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + + + memcpy( + pdata, + &(pdev->hist_data), + sizeof(VL53L1_histogram_bin_data_t)); + + LOG_FUNCTION_END(status); + + return status; +} + + + + + +VL53L1_Error VL53L1_get_additional_data( + VL53L1_DEV Dev, + VL53L1_additional_data_t *pdata) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + + + + pdata->preset_mode = pdev->preset_mode; + pdata->zone_preset = pdev->zone_preset; + pdata->measurement_mode = pdev->measurement_mode; + pdata->offset_calibration_mode = pdev->offset_calibration_mode; + pdata->offset_correction_mode = pdev->offset_correction_mode; + pdata->dmax_mode = pdev->dmax_mode; + + pdata->phasecal_config_timeout_us = pdev->phasecal_config_timeout_us; + pdata->mm_config_timeout_us = pdev->mm_config_timeout_us; + pdata->range_config_timeout_us = pdev->range_config_timeout_us; + pdata->inter_measurement_period_ms = pdev->inter_measurement_period_ms; + pdata->dss_config__target_total_rate_mcps = + pdev->dss_config__target_total_rate_mcps; + + + + + status = + VL53L1_get_histogram_debug_data( + Dev, + &(pdata->VL53L1_p_010)); + + LOG_FUNCTION_END(status); + + return status; +} + + + + + +VL53L1_Error VL53L1_get_xtalk_debug_data( + VL53L1_DEV Dev, + VL53L1_xtalk_debug_data_t *pdata) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + + + memcpy( + &(pdata->customer), + &(pdev->customer), + sizeof(VL53L1_customer_nvm_managed_t)); + + memcpy( + &(pdata->xtalk_cfg), + &(pdev->xtalk_cfg), + sizeof(VL53L1_xtalk_config_t)); + + memcpy( + &(pdata->hist_data), + &(pdev->hist_data), + sizeof(VL53L1_histogram_bin_data_t)); + + memcpy( + &(pdata->xtalk_shapes), + &(pdev->xtalk_shapes), + sizeof(VL53L1_xtalk_histogram_data_t)); + + memcpy( + &(pdata->xtalk_results), + &(pdev->xtalk_results), + sizeof(VL53L1_xtalk_range_results_t)); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_offset_debug_data( + VL53L1_DEV Dev, + VL53L1_offset_debug_data_t *pdata) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + + + memcpy( + &(pdata->customer), + &(pdev->customer), + sizeof(VL53L1_customer_nvm_managed_t)); + + memcpy( + &(pdata->fmt_dmax_cal), + &(pdev->fmt_dmax_cal), + sizeof(VL53L1_dmax_calibration_data_t)); + + memcpy( + &(pdata->cust_dmax_cal), + &(pdev->cust_dmax_cal), + sizeof(VL53L1_dmax_calibration_data_t)); + + memcpy( + &(pdata->add_off_cal_data), + &(pdev->add_off_cal_data), + sizeof(VL53L1_additional_offset_cal_data_t)); + + memcpy( + &(pdata->offset_results), + &(pdev->offset_results), + sizeof(VL53L1_offset_range_results_t)); + + LOG_FUNCTION_END(status); + + return status; +} + +#ifdef VL53L1_LOG_ENABLE + +void VL53L1_signed_fixed_point_sprintf( + int32_t signed_fp_value, + uint8_t frac_bits, + uint16_t buf_size, + char *pbuffer) +{ + + + + + + uint32_t fp_value = 0; + uint32_t unity_fp_value = 0; + uint32_t sign_bit = 0; + uint32_t int_part = 0; + uint32_t frac_part = 0; + uint32_t dec_points = 0; + uint32_t dec_scaler = 0; + uint32_t dec_part = 0; + + uint64_t tmp_long_int = 0; + + char fmt[VL53L1_MAX_STRING_LENGTH]; + + SUPPRESS_UNUSED_WARNING(buf_size); + + + + + sign_bit = signed_fp_value >> 31; + + if (sign_bit > 0) { + fp_value = 0x80000000 - + (0x7FFFFFFF & (uint32_t)signed_fp_value); + } else + fp_value = (uint32_t)signed_fp_value; + + int_part = fp_value >> frac_bits; + unity_fp_value = 0x01 << frac_bits; + frac_part = fp_value & (unity_fp_value-1); + + + + + + dec_points = 2; + dec_scaler = 100; + + while (dec_scaler < unity_fp_value) { + dec_points++; + dec_scaler *= 10; + } + + + + if (sign_bit > 0) + sprintf(fmt, "-%%u.%%0%uu", dec_points); + else + sprintf(fmt, "%%u.%%0%uu", dec_points); + + + + + + tmp_long_int = (uint64_t)frac_part * (uint64_t)dec_scaler; + tmp_long_int += (uint64_t)unity_fp_value/2; + + tmp_long_int = do_division_u(tmp_long_int, (uint64_t)unity_fp_value); + + dec_part = (uint32_t)tmp_long_int; + + + + sprintf( + pbuffer, + fmt, + int_part, + dec_part); +} + + +void VL53L1_print_static_nvm_managed( + VL53L1_static_nvm_managed_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + + + + + + char fp_text[VL53L1_MAX_STRING_LENGTH]; + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = 0x%02X\n", + pprefix, + "i2c_slave__device_address", + pdata->i2c_slave__device_address); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "ana_config__vhv_ref_sel_vddpix", + pdata->ana_config__vhv_ref_sel_vddpix); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "ana_config__vhv_ref_sel_vquench", + pdata->ana_config__vhv_ref_sel_vquench); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "ana_config__reg_avdd1v2_sel", + pdata->ana_config__reg_avdd1v2_sel); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "ana_config__fast_osc__trim", + pdata->ana_config__fast_osc__trim); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->osc_measured__fast_osc__frequency, + 12, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "osc_measured__fast_osc__frequency", + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "vhv_config__timeout_macrop_loop_bound", + pdata->vhv_config__timeout_macrop_loop_bound); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "vhv_config__count_thresh", + pdata->vhv_config__count_thresh); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "vhv_config__offset", + pdata->vhv_config__offset); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "vhv_config__init", + pdata->vhv_config__init); +} + + +void VL53L1_print_customer_nvm_managed( + VL53L1_customer_nvm_managed_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + + + + + + char fp_text[VL53L1_MAX_STRING_LENGTH]; + int16_t tmpi16; + + trace_print(VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_ref_0", + pdata->global_config__spad_enables_ref_0); + + trace_print(VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_ref_1", + pdata->global_config__spad_enables_ref_1); + + trace_print(VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_ref_2", + pdata->global_config__spad_enables_ref_2); + + trace_print(VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_ref_3", + pdata->global_config__spad_enables_ref_3); + + trace_print(VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_ref_4", + pdata->global_config__spad_enables_ref_4); + + trace_print(VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_ref_5", + pdata->global_config__spad_enables_ref_5); + + trace_print(VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__ref_en_start_select", + pdata->global_config__ref_en_start_select); + + trace_print(VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "ref_spad_man__num_requested_ref_spads", + pdata->ref_spad_man__num_requested_ref_spads); + + trace_print(VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "ref_spad_man__ref_location", + pdata->ref_spad_man__ref_location); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->algo__crosstalk_compensation_plane_offset_kcps, + 9, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print(VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "algo__crosstalk_compensation_plane_offset_kcps", + fp_text); + + tmpi16 = pdata->algo__crosstalk_compensation_x_plane_gradient_kcps; + VL53L1_signed_fixed_point_sprintf( + (int32_t)tmpi16, + 11, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print(VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "algo__crosstalk_compensation_x_plane_gradient_kcps", + fp_text); + + tmpi16 = pdata->algo__crosstalk_compensation_y_plane_gradient_kcps; + VL53L1_signed_fixed_point_sprintf( + (int32_t)tmpi16, + 11, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print(VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "algo__crosstalk_compensation_y_plane_gradient_kcps", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->ref_spad_char__total_rate_target_mcps, + 7, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print(VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "ref_spad_char__total_rate_target_mcps", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->algo__part_to_part_range_offset_mm, + 2, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print(VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "algo__part_to_part_range_offset_mm", + fp_text); + + trace_print(VL53L1_TRACE_LEVEL_INFO, + "%s%s = %d\n", + pprefix, + "mm_config__inner_offset_mm", + pdata->mm_config__inner_offset_mm); + + trace_print(VL53L1_TRACE_LEVEL_INFO, + "%s%s = %d\n", + pprefix, + "mm_config__outer_offset_mm", + pdata->mm_config__outer_offset_mm); +} + + +void VL53L1_print_nvm_copy_data( + VL53L1_nvm_copy_data_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + + + + + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "identification__model_id", + pdata->identification__model_id); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "identification__module_type", + pdata->identification__module_type); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "identification__revision_id", + pdata->identification__revision_id); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "identification__module_id", + pdata->identification__module_id); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "ana_config__fast_osc__trim_max", + pdata->ana_config__fast_osc__trim_max); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "ana_config__fast_osc__freq_set", + pdata->ana_config__fast_osc__freq_set); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "ana_config__vcsel_trim", + pdata->ana_config__vcsel_trim); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "ana_config__vcsel_selion", + pdata->ana_config__vcsel_selion); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "ana_config__vcsel_selion_max", + pdata->ana_config__vcsel_selion_max); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "protected_laser_safety__lock_bit", + pdata->protected_laser_safety__lock_bit); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "laser_safety__key", + pdata->laser_safety__key); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "laser_safety__key_ro", + pdata->laser_safety__key_ro); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "laser_safety__clip", + pdata->laser_safety__clip); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "laser_safety__mult", + pdata->laser_safety__mult); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_0", + pdata->global_config__spad_enables_rtn_0); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_1", + pdata->global_config__spad_enables_rtn_1); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_2", + pdata->global_config__spad_enables_rtn_2); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_3", + pdata->global_config__spad_enables_rtn_3); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_4", + pdata->global_config__spad_enables_rtn_4); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_5", + pdata->global_config__spad_enables_rtn_5); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_6", + pdata->global_config__spad_enables_rtn_6); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_7", + pdata->global_config__spad_enables_rtn_7); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_8", + pdata->global_config__spad_enables_rtn_8); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_9", + pdata->global_config__spad_enables_rtn_9); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_10", + pdata->global_config__spad_enables_rtn_10); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_11", + pdata->global_config__spad_enables_rtn_11); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_12", + pdata->global_config__spad_enables_rtn_12); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_13", + pdata->global_config__spad_enables_rtn_13); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_14", + pdata->global_config__spad_enables_rtn_14); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_15", + pdata->global_config__spad_enables_rtn_15); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_16", + pdata->global_config__spad_enables_rtn_16); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_17", + pdata->global_config__spad_enables_rtn_17); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_18", + pdata->global_config__spad_enables_rtn_18); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_19", + pdata->global_config__spad_enables_rtn_19); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_20", + pdata->global_config__spad_enables_rtn_20); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_21", + pdata->global_config__spad_enables_rtn_21); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_22", + pdata->global_config__spad_enables_rtn_22); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_23", + pdata->global_config__spad_enables_rtn_23); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_24", + pdata->global_config__spad_enables_rtn_24); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_25", + pdata->global_config__spad_enables_rtn_25); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_26", + pdata->global_config__spad_enables_rtn_26); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_27", + pdata->global_config__spad_enables_rtn_27); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_28", + pdata->global_config__spad_enables_rtn_28); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_29", + pdata->global_config__spad_enables_rtn_29); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_30", + pdata->global_config__spad_enables_rtn_30); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_31", + pdata->global_config__spad_enables_rtn_31); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "roi_config__mode_roi_centre_spad", + pdata->roi_config__mode_roi_centre_spad); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = 0x%02X\n", + pprefix, + "roi_config__mode_roi_xy_size", + pdata->roi_config__mode_roi_xy_size); +} + + +void VL53L1_print_histogram_bin_data( + VL53L1_histogram_bin_data_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + + + + + + char fp_text[VL53L1_MAX_STRING_LENGTH]; + char pre_text[VL53L1_MAX_STRING_LENGTH]; + char *ppre_text = &(pre_text[0]); + + uint8_t i = 0; + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "cfg_device_state", + pdata->cfg_device_state); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "rd_device_state", + pdata->rd_device_state); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "VL53L1_p_022", + pdata->VL53L1_p_022); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "VL53L1_p_023", + pdata->VL53L1_p_023); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "VL53L1_p_024", + pdata->VL53L1_p_024); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "number_of_ambient_bins", + pdata->number_of_ambient_bins); + + for (i = 0; i < VL53L1_MAX_BIN_SEQUENCE_LENGTH; i++) { + sprintf(ppre_text, "%sbin_seq[%u]", pprefix, i); + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s = %u\n", + ppre_text, + pdata->bin_seq[i]); + } + + for (i = 0; i < VL53L1_MAX_BIN_SEQUENCE_LENGTH; i++) { + sprintf(ppre_text, "%sbin_rep[%u]", pprefix, i); + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s = %u\n", + ppre_text, + pdata->bin_rep[i]); + } + + for (i = 0; i < pdata->VL53L1_p_024; i++) { + sprintf(ppre_text, "%sbin_data[%u]", pprefix, i); + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s = %d\n", + ppre_text, + pdata->bin_data[i]); + } + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "result__interrupt_status", + pdata->result__interrupt_status); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "result__range_status", + pdata->result__range_status); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "result__report_status", + pdata->result__report_status); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "result__stream_count", + pdata->result__stream_count); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->result__dss_actual_effective_spads, + 8, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "result__dss_actual_effective_spads", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->phasecal_result__reference_phase, + 11, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "phasecal_result__reference_phase", + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "phasecal_result__vcsel_start", + pdata->phasecal_result__vcsel_start); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "cal_config__vcsel_start", + pdata->cal_config__vcsel_start); + + VL53L1_signed_fixed_point_sprintf( + (uint32_t)pdata->vcsel_width, + 4, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "vcsel_width", + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "VL53L1_p_009", + pdata->VL53L1_p_009); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->VL53L1_p_019, + 12, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "VL53L1_p_019", + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "total_periods_elapsed", + pdata->total_periods_elapsed); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "peak_duration_us", + pdata->peak_duration_us); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "woi_duration_us", + pdata->woi_duration_us); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "min_bin_value", + pdata->min_bin_value); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "max_bin_value", + pdata->max_bin_value); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->zero_distance_phase, + 11, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "zero_distance_phase", + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "number_of_ambient_samples", + pdata->number_of_ambient_samples); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %d\n", + pprefix, + "ambient_events_sum", + pdata->ambient_events_sum); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %d\n", + pprefix, + "VL53L1_p_004", + pdata->VL53L1_p_004); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = 0x%02X\n", + pprefix, + "roi_config__user_roi_centre_spad", + pdata->roi_config__user_roi_centre_spad); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = 0x%02X\n", + pprefix, + "roi_config__user_roi_requested_global_xy_size", + pdata->roi_config__user_roi_requested_global_xy_size); +} + + +void VL53L1_print_xtalk_histogram_shape_data( + VL53L1_xtalk_histogram_shape_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + + + + + + char fp_text[VL53L1_MAX_STRING_LENGTH]; + char pre_text[VL53L1_MAX_STRING_LENGTH]; + char *ppre_text = &(pre_text[0]); + + uint8_t i = 0; + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "VL53L1_p_022", + pdata->VL53L1_p_022); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "VL53L1_p_023", + pdata->VL53L1_p_023); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "VL53L1_p_024", + pdata->VL53L1_p_024); + + for (i = 0; i < pdata->VL53L1_p_024; i++) { + + sprintf(ppre_text, "%sbin_data[%u]", pprefix, i); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->bin_data[i], + 10, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s = %s\n", + ppre_text, + fp_text); + } + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->phasecal_result__reference_phase, + 11, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "phasecal_result__reference_phase", + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "phasecal_result__vcsel_start", + pdata->phasecal_result__vcsel_start); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "cal_config__vcsel_start", + pdata->cal_config__vcsel_start); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->vcsel_width, + 4, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "vcsel_width", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->VL53L1_p_019, + 12, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "VL53L1_p_019", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->zero_distance_phase, + 11, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "zero_distance_phase", + fp_text); +} + + +void VL53L1_print_xtalk_histogram_data( + VL53L1_xtalk_histogram_data_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + + + + + + char pre_text[VL53L1_MAX_STRING_LENGTH]; + char *ppre_text = &(pre_text[0]); + + + + sprintf(ppre_text, "%sxtalk_shape.", pprefix); + VL53L1_print_xtalk_histogram_shape_data( + &(pdata->xtalk_shape), + ppre_text, trace_flags); + + + + sprintf(ppre_text, "%sxtalk_hist_removed.", pprefix); + VL53L1_print_histogram_bin_data( + &(pdata->xtalk_hist_removed), + ppre_text, trace_flags); +} + + +void VL53L1_print_range_data( + VL53L1_range_data_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + + + + + + char fp_text[VL53L1_MAX_STRING_LENGTH]; + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "range_id", + pdata->range_id); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "time_stamp", + pdata->time_stamp); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "VL53L1_p_015", + pdata->VL53L1_p_015); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "VL53L1_p_022", + pdata->VL53L1_p_022); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "VL53L1_p_025", + pdata->VL53L1_p_025); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "VL53L1_p_026", + pdata->VL53L1_p_026); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "VL53L1_p_016", + pdata->VL53L1_p_016); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "VL53L1_p_027", + pdata->VL53L1_p_027); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->width, + 4, VL53L1_MAX_STRING_LENGTH, fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "width", + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "VL53L1_p_030", + pdata->VL53L1_p_030); + + + + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->fast_osc_frequency, + 12, VL53L1_MAX_STRING_LENGTH, fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "fast_osc_frequency", + fp_text); + + + + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->zero_distance_phase, + 11, VL53L1_MAX_STRING_LENGTH, fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "zero_distance_phase", + fp_text); + + + + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->VL53L1_p_006, + 8, VL53L1_MAX_STRING_LENGTH, fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "actual_effective_spad", + fp_text); + + + trace_print(VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "total_periods_elapsed", + pdata->total_periods_elapsed); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "peak_duration_us", + pdata->peak_duration_us); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "woi_duration_us", + pdata->woi_duration_us); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %d\n", + pprefix, + "VL53L1_p_020", + pdata->VL53L1_p_020); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %d\n", + pprefix, + "VL53L1_p_021", + pdata->VL53L1_p_021); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %d\n", + pprefix, + "VL53L1_p_013", + pdata->VL53L1_p_013); + + + + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->peak_signal_count_rate_mcps, + 7, VL53L1_MAX_STRING_LENGTH, fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "peak_signal_count_rate_mcps", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->avg_signal_count_rate_mcps, + 7, VL53L1_MAX_STRING_LENGTH, fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "avg_signal_count_rate_mcps", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->ambient_count_rate_mcps, + 7, VL53L1_MAX_STRING_LENGTH, fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "ambient_count_rate_mcps", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->total_rate_per_spad_mcps, + 13, VL53L1_MAX_STRING_LENGTH, fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "total_rate_per_spad_mcps", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->VL53L1_p_012, + 11, VL53L1_MAX_STRING_LENGTH, fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "VL53L1_p_012", + fp_text); + + + + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->VL53L1_p_005, + 2, VL53L1_MAX_STRING_LENGTH, fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "VL53L1_p_005", + fp_text); + + + + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->VL53L1_p_028, + 11, VL53L1_MAX_STRING_LENGTH, fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "VL53L1_p_028", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->VL53L1_p_014, + 11, VL53L1_MAX_STRING_LENGTH, fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "VL53L1_p_014", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->VL53L1_p_029, + 11, VL53L1_MAX_STRING_LENGTH, fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "VL53L1_p_029", + fp_text); + + + + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %d\n", + pprefix, + "min_range_mm", + pdata->min_range_mm); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %d\n", + pprefix, + "median_range_mm", + pdata->median_range_mm); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %d\n", + pprefix, + "max_range_mm", + pdata->max_range_mm); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "range_status", + pdata->range_status); +} + + +void VL53L1_print_range_results( + VL53L1_range_results_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + + + + + + char pre_text[VL53L1_MAX_STRING_LENGTH]; + char *ppre_text = &(pre_text[0]); + + uint8_t i = 0; + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "cfg_device_state", + pdata->cfg_device_state); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "rd_device_state", + pdata->rd_device_state); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "zone_id", + pdata->zone_id); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "stream_count", + pdata->stream_count); + + for (i = 0; i < VL53L1_MAX_AMBIENT_DMAX_VALUES; i++) { + sprintf( + ppre_text, + "%sambient_dmax_mm[%u]", + pprefix, i); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s = %u\n", + ppre_text, + pdata->VL53L1_p_007[i]); + } + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "device_status", + pdata->device_status); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "wrap_dmax_mm", + pdata->wrap_dmax_mm); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "max_results", + pdata->max_results); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "active_results", + pdata->active_results); + + for (i = 0; i < pdata->active_results; i++) { + sprintf(ppre_text, "%sdata[%u].", pprefix, i); + VL53L1_print_range_data( + &pdata->VL53L1_p_002[i], + ppre_text, trace_flags); + } + + sprintf(ppre_text, "%sxmonitor.", pprefix); + VL53L1_print_range_data( + &pdata->xmonitor, + ppre_text, trace_flags); +} + + +void VL53L1_print_offset_range_results( + VL53L1_offset_range_results_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + + + + + + char fp_text[VL53L1_MAX_STRING_LENGTH]; + char pre_text[VL53L1_MAX_STRING_LENGTH]; + char *ppre_text = &(pre_text[0]); + + uint8_t i = 0; + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "cal_distance_mm", + pdata->cal_distance_mm); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->cal_reflectance_pc, + 2, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "cal_reflectance_pc", + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "cal_status", + pdata->cal_status); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "cal_report", + pdata->cal_report); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "max_results", + pdata->max_results); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "active_results", + pdata->active_results); + + for (i = 0; i < pdata->active_results; i++) { + sprintf(ppre_text, "%sdata[%u].", pprefix, i); + VL53L1_print_offset_range_data( + &(pdata->VL53L1_p_002[i]), + ppre_text, trace_flags); + } +} + + +void VL53L1_print_offset_range_data( + VL53L1_offset_range_data_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + + + + + + char fp_text[VL53L1_MAX_STRING_LENGTH]; + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "preset_mode", + pdata->preset_mode); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "dss_config__roi_mode_control", + pdata->dss_config__roi_mode_control); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->dss_config__manual_effective_spads_select, + 8, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "dss_config__manual_effective_spads_select", + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "no_of_samples", + pdata->no_of_samples); + + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->effective_spads, + 8, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "effective_spads", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->peak_rate_mcps, + 7, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "peak_rate_mcps", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->VL53L1_p_005, + 2, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "VL53L1_p_005", + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %d\n", + pprefix, + "median_range_mm", + pdata->median_range_mm); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %d\n", + pprefix, + "range_mm_offset", + pdata->range_mm_offset); +} + + +void VL53L1_print_cal_peak_rate_map( + VL53L1_cal_peak_rate_map_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + + + + + + char fp_text[VL53L1_MAX_STRING_LENGTH]; + char pre_text[VL53L1_MAX_STRING_LENGTH]; + char *ppre_text = &(pre_text[0]); + + uint8_t i = 0; + uint8_t x = 0; + uint8_t y = 0; + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->cal_distance_mm, + 2, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "cal_distance_mm", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->cal_reflectance_pc, + 2, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "cal_reflectance_pc", + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "max_samples", + pdata->max_samples); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "width", + pdata->width); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "height", + pdata->height); + + i = 0; + for (y = 0; y < pdata->height; y++) { + for (x = 0; x < pdata->width; x++) { + + sprintf(ppre_text, "%speak_rate_mcps[%u]", pprefix, i); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->peak_rate_mcps[i], + 7, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s = %s\n", + ppre_text, + fp_text); + + i++; + } + } +} + +void VL53L1_print_additional_data( + VL53L1_additional_data_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + + + + + + + char fp_text[VL53L1_MAX_STRING_LENGTH]; + char pre_text[VL53L1_MAX_STRING_LENGTH]; + char *ppre_text = &(pre_text[0]); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "preset_mode", + pdata->preset_mode); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "zone_preset", + pdata->zone_preset); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "measurement_mode", + pdata->measurement_mode); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "offset_calibration_mode", + pdata->offset_calibration_mode); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "offset_correction_mode", + pdata->offset_correction_mode); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "dmax_mode", + pdata->dmax_mode); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "phasecal_config_timeout_us", + pdata->phasecal_config_timeout_us); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "mm_config_timeout_us", + pdata->mm_config_timeout_us); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "range_config_timeout_us", + pdata->range_config_timeout_us); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "inter_measurement_period_ms", + pdata->inter_measurement_period_ms); + + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->dss_config__target_total_rate_mcps, + 7, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "dss_config__target_total_rate_mcps", + fp_text); + + sprintf(ppre_text, "%s VL53L1_p_010.", pprefix); + VL53L1_print_histogram_bin_data( + &pdata->VL53L1_p_010, + ppre_text, trace_flags); + + +} + + +void VL53L1_print_additional_offset_cal_data( + VL53L1_additional_offset_cal_data_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + + + + + + char fp_text[VL53L1_MAX_STRING_LENGTH]; + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->result__mm_inner_actual_effective_spads, + 8, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "result__mm_inner_actual_effective_spads", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->result__mm_outer_actual_effective_spads, + 8, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "result__mm_outer_actual_effective_spads", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->result__mm_inner_peak_signal_count_rtn_mcps, + 7, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "result__mm_inner_peak_signal_count_rtn_mcps", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->result__mm_outer_peak_signal_count_rtn_mcps, + 7, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "result__mm_outer_peak_signal_count_rtn_mcps", + fp_text); +} + + +void VL53L1_print_gain_calibration_data( + VL53L1_gain_calibration_data_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + + + + + + char fp_text[VL53L1_MAX_STRING_LENGTH]; + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->standard_ranging_gain_factor, + 11, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "standard_ranging_gain_factor", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->histogram_ranging_gain_factor, + 11, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "histogram_ranging_gain_factor", + fp_text); +} + + +void VL53L1_print_zone_calibration_data( + VL53L1_zone_calibration_data_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + + + + + + char fp_text[VL53L1_MAX_STRING_LENGTH]; + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "no_of_samples", + pdata->no_of_samples); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->effective_spads, + 8, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "effective_spads", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->peak_rate_mcps, + 7, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "peak_rate_mcps", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->VL53L1_p_014, + 11, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "VL53L1_p_014", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->VL53L1_p_005, + 2, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "VL53L1_p_005", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->median_range_mm, + 2, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "median_range_mm", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->range_mm_offset, + 2, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "range_mm_offset", + fp_text); +} + + +void VL53L1_print_zone_calibration_results( + VL53L1_zone_calibration_results_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + + + + + + char fp_text[VL53L1_MAX_STRING_LENGTH]; + char pre_text[VL53L1_MAX_STRING_LENGTH]; + char *ppre_text = &(pre_text[0]); + + uint8_t i = 0; + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "preset_mode", + pdata->preset_mode); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "zone_preset", + pdata->zone_preset); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "cal_distance_mm", + pdata->cal_distance_mm); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->cal_reflectance_pc, + 2, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "cal_reflectance_pc", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->phasecal_result__reference_phase, + 11, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "phasecal_result__reference_phase", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->zero_distance_phase, + 11, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "zero_distance_phase", + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "cal_status", + pdata->cal_status); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "max_zones", + pdata->max_zones); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "active_zones", + pdata->active_zones); + + for (i = 0; i < pdata->active_zones; i++) { + sprintf(ppre_text, "%sdata[%u].", pprefix, i); + VL53L1_print_zone_calibration_data( + &(pdata->VL53L1_p_002[i]), + ppre_text, trace_flags); + } +} + +void VL53L1_print_xtalk_range_results( + VL53L1_xtalk_range_results_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + + + + + + char pre_text[VL53L1_MAX_STRING_LENGTH]; + char *ppre_text = &(pre_text[0]); + uint8_t i = 0; + + VL53L1_histogram_bin_data_t *pbin_data; + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "cal_status", + pdata->cal_status); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "num_of_samples_status", + pdata->num_of_samples_status); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "zero_samples_status", + pdata->zero_samples_status); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "max_sigma_status", + pdata->max_sigma_status); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "max_results", + pdata->max_results); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "active_results", + pdata->active_results); + + for (i = 0; i < pdata->active_results; i++) { + sprintf(ppre_text, "%sdata[%u].", pprefix, i); + VL53L1_print_xtalk_range_data( + &(pdata->VL53L1_p_002[i]), + ppre_text, trace_flags); + } + + sprintf(ppre_text, "%scentral_histogram_sum.", pprefix); + VL53L1_print_histogram_bin_data( + &pdata->central_histogram_sum, + ppre_text, trace_flags); + + sprintf(ppre_text, "%scentral_histogram_avg.", pprefix); + VL53L1_print_histogram_bin_data( + &pdata->central_histogram_avg, + ppre_text, trace_flags); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "VL53L1_p_015", + pdata->central_histogram__window_start); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "VL53L1_p_016", + pdata->central_histogram__window_end); + + pbin_data = &(pdata->histogram_avg_1[0]); + + for (i = 0; i < 5; i++) { + sprintf(ppre_text, "%shistogram_avg_1[%u].", pprefix, i); + VL53L1_print_histogram_bin_data( + pbin_data, + ppre_text, trace_flags); + pbin_data++; + } + + pbin_data = &(pdata->histogram_avg_2[0]); + + for (i = 0; i < 5; i++) { + sprintf(ppre_text, "%shistogram_avg_2[%u].", pprefix, i); + VL53L1_print_histogram_bin_data( + pbin_data, + ppre_text, trace_flags); + pbin_data++; + } + + pbin_data = &(pdata->xtalk_avg[0]); + + for (i = 0; i < 5; i++) { + sprintf(ppre_text, "%sxtalk_avg[%u].", pprefix, i); + VL53L1_print_histogram_bin_data( + pbin_data, + ppre_text, trace_flags); + pbin_data++; + } +} + + +void VL53L1_print_xtalk_range_data( + VL53L1_xtalk_range_data_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + + + + + + char fp_text[VL53L1_MAX_STRING_LENGTH]; + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "no_of_samples", + pdata->no_of_samples); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %d\n", + pprefix, + "signal_total_events_sum", + pdata->signal_total_events_sum); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %d\n", + pprefix, + "signal_total_events_avg", + pdata->signal_total_events_avg); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->rate_per_spad_kcps_sum, + 11, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "rate_per_spad_kcps_sum", + fp_text); + + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->rate_per_spad_kcps_avg, + 11, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "rate_per_spad_kcps_avg", + fp_text); +} + + +void VL53L1_print_xtalk_calibration_results( + VL53L1_xtalk_calibration_results_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + + + + + + char fp_text[VL53L1_MAX_STRING_LENGTH]; + int16_t tmpi16; + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->algo__crosstalk_compensation_plane_offset_kcps, + 9, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "algo__crosstalk_compensation_plane_offset_kcps", + fp_text); + + tmpi16 = pdata->algo__crosstalk_compensation_x_plane_gradient_kcps; + VL53L1_signed_fixed_point_sprintf( + (int32_t)tmpi16, + 11, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "algo__crosstalk_compensation_x_plane_gradient_kcps", + fp_text); + + tmpi16 = pdata->algo__crosstalk_compensation_y_plane_gradient_kcps; + VL53L1_signed_fixed_point_sprintf( + (int32_t)tmpi16, + 11, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "algo__crosstalk_compensation_y_plane_gradient_kcps", + fp_text); +} + + +void VL53L1_print_xtalk_config( + VL53L1_xtalk_config_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + + + + + + char fp_text[VL53L1_MAX_STRING_LENGTH]; + int16_t tmpi16; + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->algo__crosstalk_compensation_plane_offset_kcps, + 9, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "algo__crosstalk_compensation_plane_offset_kcps", + fp_text); + + tmpi16 = pdata->algo__crosstalk_compensation_x_plane_gradient_kcps; + VL53L1_signed_fixed_point_sprintf( + (int32_t)tmpi16, + 11, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "algo__crosstalk_compensation_x_plane_gradient_kcps", + fp_text); + + tmpi16 = pdata->algo__crosstalk_compensation_y_plane_gradient_kcps; + VL53L1_signed_fixed_point_sprintf( + (int32_t)tmpi16, + 11, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "algo__crosstalk_compensation_y_plane_gradient_kcps", + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_crosstalk_compensation_enable", + pdata->global_crosstalk_compensation_enable); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->histogram_mode_crosstalk_margin_kcps, + 9, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "histogram_mode_crosstalk_margin_kcps", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->lite_mode_crosstalk_margin_kcps, + 9, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "lite_mode_crosstalk_margin_kcps", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->crosstalk_range_ignore_threshold_mult, + 5, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "crosstalk_range_ignore_threshold_mult", + fp_text); + + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->crosstalk_range_ignore_threshold_rate_mcps, + 13, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "crosstalk_range_ignore_threshold_rate_mcps", + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "algo__crosstalk_detect_max_valid_range_mm", + pdata->algo__crosstalk_detect_max_valid_range_mm); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "algo__crosstalk_detect_min_valid_range_mm", + pdata->algo__crosstalk_detect_min_valid_range_mm); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->algo__crosstalk_detect_max_valid_rate_kcps, + 7, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "algo__crosstalk_detect_max_valid_rate_kcps", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->algo__crosstalk_detect_max_sigma_mm, + 2, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "algo__crosstalk_detect_max_sigma_mm", + fp_text); + +} + + +void VL53L1_print_xtalk_extract_config( + VL53L1_xtalkextract_config_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + + + + + + char fp_text[VL53L1_MAX_STRING_LENGTH]; + + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->dss_config__target_total_rate_mcps, + 7, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "dss_config__target_total_rate_mcps", + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "mm_config_timeout_us", + pdata->mm_config_timeout_us); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "range_config_timeout_us", + pdata->range_config_timeout_us); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "num_of_samples", + pdata->num_of_samples); + + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "algo__crosstalk_extract_max_valid_range_mm", + pdata->algo__crosstalk_extract_max_valid_range_mm); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "algo__crosstalk_extract_min_valid_range_mm", + pdata->algo__crosstalk_extract_min_valid_range_mm); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->algo__crosstalk_extract_max_valid_rate_kcps, + 9, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "algo__crosstalk_extract_max_valid_rate_kcps", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->algo__crosstalk_extract_max_sigma_mm, + 2, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "algo__crosstalk_extract_max_sigma_mm", + fp_text); + +} + + +void VL53L1_print_zone_cal_config( + VL53L1_zonecal_config_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + + + + + + char fp_text[VL53L1_MAX_STRING_LENGTH]; + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->dss_config__target_total_rate_mcps, + 7, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "dss_config__target_total_rate_mcps", + fp_text); + + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "mm_config_timeout_us", + pdata->mm_config_timeout_us); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "range_config_timeout_us", + pdata->range_config_timeout_us); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "phasecal_config_timeout_us", + pdata->phasecal_config_timeout_us); + + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "phasecal_num_of_samples", + pdata->phasecal_num_of_samples); + + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "zone_num_of_samples", + pdata->zone_num_of_samples); + +} + +void VL53L1_print_offset_cal_config( + VL53L1_offsetcal_config_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + + + + + + char fp_text[VL53L1_MAX_STRING_LENGTH]; + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->dss_config__target_total_rate_mcps, + 7, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "dss_config__target_total_rate_mcps", + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "phasecal_config_timeout_us", + pdata->phasecal_config_timeout_us); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "range_config_timeout_us", + pdata->range_config_timeout_us); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "pre_num_of_samples", + pdata->pre_num_of_samples); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "mm1_num_of_samples", + pdata->mm1_num_of_samples); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "mm2_num_of_samples", + pdata->mm2_num_of_samples); + + +} + + +void VL53L1_print_dmax_calibration_data( + VL53L1_dmax_calibration_data_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + + + + + + char fp_text[VL53L1_MAX_STRING_LENGTH]; + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->ref__actual_effective_spads, + 8, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "ref__actual_effective_spads", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->ref__peak_signal_count_rate_mcps, + 7, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "ref__peak_signal_count_rate_mcps", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->ref__distance_mm, + 4, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "ref__distance_mm", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->ref_reflectance_pc, + 2, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "ref_reflectance_pc", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->coverglass_transmission, + 8, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "coverglass_transmission", + fp_text); +} + + +void VL53L1_print_calibration_data( + VL53L1_calibration_data_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + + + + + + char pre_text[VL53L1_MAX_STRING_LENGTH]; + char *ppre_text = &(pre_text[0]); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = 0x%08X\n", + pprefix, + "struct_version", + pdata->struct_version); + + sprintf(ppre_text, "%scustomer.", pprefix); + VL53L1_print_customer_nvm_managed( + &(pdata->customer), + ppre_text, trace_flags); + + sprintf(ppre_text, "%sfmt_dmax_cal.", pprefix); + VL53L1_print_dmax_calibration_data( + &(pdata->fmt_dmax_cal), + ppre_text, trace_flags); + + sprintf(ppre_text, "%scust_dmax_cal.", pprefix); + VL53L1_print_dmax_calibration_data( + &(pdata->cust_dmax_cal), + ppre_text, trace_flags); + + sprintf(ppre_text, "%sadd_off_cal_data.", pprefix); + VL53L1_print_additional_offset_cal_data( + &(pdata->add_off_cal_data), + ppre_text, trace_flags); + + sprintf(ppre_text, "%soptical_centre.", pprefix); + VL53L1_print_optical_centre( + &(pdata->optical_centre), + ppre_text, trace_flags); + + sprintf(ppre_text, "%sxtalkhisto.", pprefix); + VL53L1_print_xtalk_histogram_data( + &(pdata->xtalkhisto), + ppre_text, trace_flags); + + sprintf(ppre_text, "%sgain_cal.", pprefix); + VL53L1_print_gain_calibration_data( + &(pdata->gain_cal), + ppre_text, trace_flags); + + sprintf(ppre_text, "%scal_peak_rate_map.", pprefix); + VL53L1_print_cal_peak_rate_map( + &(pdata->cal_peak_rate_map), + ppre_text, trace_flags); +} + + +void VL53L1_print_xtalk_debug_data( + VL53L1_xtalk_debug_data_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + + + + + + char pre_text[VL53L1_MAX_STRING_LENGTH]; + char *ppre_text = &(pre_text[0]); + + sprintf(ppre_text, "%scustomer.", pprefix); + VL53L1_print_customer_nvm_managed( + &(pdata->customer), + ppre_text, trace_flags); + + sprintf(ppre_text, "%sxtalk_cfg.", pprefix); + VL53L1_print_xtalk_config( + &(pdata->xtalk_cfg), + ppre_text, trace_flags); + + sprintf(ppre_text, "%sxtalk_extract_cfg.", pprefix); + VL53L1_print_xtalk_extract_config( + &(pdata->xtalk_extract_cfg), + ppre_text, trace_flags); + + sprintf(ppre_text, "%shist_data.", pprefix); + VL53L1_print_histogram_bin_data( + &(pdata->hist_data), + ppre_text, trace_flags); + + sprintf(ppre_text, "%sxtalk_shapes.", pprefix); + VL53L1_print_xtalk_histogram_data( + &(pdata->xtalk_shapes), + ppre_text, trace_flags); + + sprintf(ppre_text, "%sgain_cal.", pprefix); + VL53L1_print_xtalk_range_results( + &(pdata->xtalk_results), + ppre_text, trace_flags); +} + + +void VL53L1_print_offset_debug_data( + VL53L1_offset_debug_data_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + + + + + + char pre_text[VL53L1_MAX_STRING_LENGTH]; + char *ppre_text = &(pre_text[0]); + + sprintf(ppre_text, "%scustomer.", pprefix); + VL53L1_print_customer_nvm_managed( + &(pdata->customer), + ppre_text, trace_flags); + + sprintf(ppre_text, "%sfmt_dmax_cal.", pprefix); + VL53L1_print_dmax_calibration_data( + &(pdata->fmt_dmax_cal), + ppre_text, trace_flags); + + sprintf(ppre_text, "%scust_dmax_cal.", pprefix); + VL53L1_print_dmax_calibration_data( + &(pdata->cust_dmax_cal), + ppre_text, trace_flags); + + sprintf(ppre_text, "%sadd_off_cal_data.", pprefix); + VL53L1_print_additional_offset_cal_data( + &(pdata->add_off_cal_data), + ppre_text, trace_flags); + + sprintf(ppre_text, "%soffset_results.", pprefix); + VL53L1_print_offset_range_results( + &(pdata->offset_results), + ppre_text, trace_flags); +} + + +void VL53L1_print_zone_config( + VL53L1_zone_config_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + + + + + + + char pre_text[VL53L1_MAX_STRING_LENGTH]; + char *ppre_text = &(pre_text[0]); + + uint8_t i = 0; + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "max_zones", + pdata->max_zones); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "active_zones", + pdata->active_zones); + + for (i = 0; i < pdata->active_zones; i++) { + sprintf(ppre_text, "%suser_zones[%u].", pprefix, i); + VL53L1_print_user_zone( + &pdata->user_zones[i], + ppre_text, + trace_flags); + } +} + + +void VL53L1_print_optical_centre( + VL53L1_optical_centre_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + + + + + + char fp_text[VL53L1_MAX_STRING_LENGTH]; + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->x_centre, + 4, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "x_centre", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->y_centre, + 4, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "y_centre", + fp_text); +} + + +void VL53L1_print_user_zone( + VL53L1_user_zone_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + + + + + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "x_centre", + pdata->x_centre); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "y_centre", + pdata->y_centre); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "width", + pdata->width); + + trace_print(VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "height", + pdata->height); +} + + +void VL53L1_print_spad_rate_data( + VL53L1_spad_rate_data_t *pspad_rates, + char *pprefix, + uint32_t trace_flags) +{ + + + + + + + uint16_t spad_no = 0; + uint8_t row = 0; + uint8_t col = 0; + + char fp_text[VL53L1_MAX_STRING_LENGTH]; + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%8s,%4s,%4s, %s\n", + pprefix, + "spad_no", + "row", + "col", + "peak_rate_mcps"); + + for (spad_no = 0; spad_no < pspad_rates->no_of_values; spad_no++) { + + + + VL53L1_decode_row_col( + (uint8_t)spad_no, + &row, + &col); + + + + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pspad_rates->rate_data[spad_no], + pspad_rates->fractional_bits, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + + + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%8u,%4u,%4u, %s\n", + pprefix, + spad_no, + row, + col, + fp_text); + } +} + + +void VL53L1_print_spad_rate_map( + VL53L1_spad_rate_data_t *pspad_rates, + char *pprefix, + uint32_t trace_flags) +{ + + + + + + + uint8_t spad_no = 0; + uint8_t row = 0; + uint8_t col = 0; + + char fp_text[VL53L1_MAX_STRING_LENGTH]; + + + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%4s", + pprefix, + " "); + + for (col = 0; col < VL53L1_SPAD_ARRAY_WIDTH; col++) + trace_print( + VL53L1_TRACE_LEVEL_INFO, + ",%8u", + col); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "\n"); + + + + + for (row = 0; row < VL53L1_SPAD_ARRAY_HEIGHT; row++) { + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%4u", + pprefix, + row); + + for (col = 0; col < VL53L1_SPAD_ARRAY_HEIGHT; col++) { + + + + + VL53L1_encode_row_col( + row, + col, + &spad_no); + + + + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pspad_rates->rate_data[spad_no], + pspad_rates->fractional_bits, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + + + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + ",%8s", + fp_text); + } + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "\n"); + } +} + + +#endif + + + diff --git a/drivers/input/misc/vl53L1/lito/src/vl53l1_api_preset_modes.c b/drivers/input/misc/vl53L1/lito/src/vl53l1_api_preset_modes.c new file mode 100644 index 000000000000..e00f48830d2d --- /dev/null +++ b/drivers/input/misc/vl53L1/lito/src/vl53l1_api_preset_modes.c @@ -0,0 +1,4927 @@ + +/******************************************************************************* + * Copyright (c) 2017, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#include "vl53l1_ll_def.h" +#include "vl53l1_platform_log.h" +#include "vl53l1_register_structs.h" +#include "vl53l1_register_settings.h" +#include "vl53l1_hist_structs.h" +#include "vl53l1_zone_presets.h" +#include "vl53l1_core.h" +#include "vl53l1_api_preset_modes.h" +#include "vl53l1_tuning_parm_defaults.h" + + +#define LOG_FUNCTION_START(fmt, ...) \ + _LOG_FUNCTION_START(VL53L1_TRACE_MODULE_API, fmt, ##__VA_ARGS__) +#define LOG_FUNCTION_END(status, ...) \ + _LOG_FUNCTION_END(VL53L1_TRACE_MODULE_API, status, ##__VA_ARGS__) +#define LOG_FUNCTION_END_FMT(status, fmt, ...) \ + _LOG_FUNCTION_END_FMT(VL53L1_TRACE_MODULE_API,\ + status, fmt, ##__VA_ARGS__) + + +VL53L1_Error VL53L1_init_refspadchar_config_struct( + VL53L1_refspadchar_config_t *pdata) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + + + + + + + + pdata->device_test_mode = + VL53L1_TUNINGPARM_REFSPADCHAR_DEVICE_TEST_MODE_DEFAULT; + pdata->VL53L1_p_009 = + VL53L1_TUNINGPARM_REFSPADCHAR_VCSEL_PERIOD_DEFAULT; + pdata->timeout_us = + VL53L1_TUNINGPARM_REFSPADCHAR_PHASECAL_TIMEOUT_US_DEFAULT; + pdata->target_count_rate_mcps = + VL53L1_TUNINGPARM_REFSPADCHAR_TARGET_COUNT_RATE_MCPS_DEFAULT; + pdata->min_count_rate_limit_mcps = + VL53L1_TUNINGPARM_REFSPADCHAR_MIN_COUNTRATE_LIMIT_MCPS_DEFAULT; + pdata->max_count_rate_limit_mcps = + VL53L1_TUNINGPARM_REFSPADCHAR_MAX_COUNTRATE_LIMIT_MCPS_DEFAULT; + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_init_ssc_config_struct( + VL53L1_ssc_config_t *pdata) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + + + + + pdata->array_select = VL53L1_DEVICESSCARRAY_RTN; + + + + pdata->VL53L1_p_009 = + VL53L1_TUNINGPARM_SPADMAP_VCSEL_PERIOD_DEFAULT; + + + + pdata->vcsel_start = + VL53L1_TUNINGPARM_SPADMAP_VCSEL_START_DEFAULT; + + + + pdata->vcsel_width = 0x02; + + + + pdata->timeout_us = 36000; + + + + + + + pdata->rate_limit_mcps = + VL53L1_TUNINGPARM_SPADMAP_RATE_LIMIT_MCPS_DEFAULT; + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_init_xtalk_config_struct( + VL53L1_customer_nvm_managed_t *pnvm, + VL53L1_xtalk_config_t *pdata) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + + + + + + + + + + + + + pdata->algo__crosstalk_compensation_plane_offset_kcps = + pnvm->algo__crosstalk_compensation_plane_offset_kcps; + pdata->algo__crosstalk_compensation_x_plane_gradient_kcps = + pnvm->algo__crosstalk_compensation_x_plane_gradient_kcps; + pdata->algo__crosstalk_compensation_y_plane_gradient_kcps = + pnvm->algo__crosstalk_compensation_y_plane_gradient_kcps; + + + + + pdata->nvm_default__crosstalk_compensation_plane_offset_kcps = + (uint32_t)pnvm->algo__crosstalk_compensation_plane_offset_kcps; + pdata->nvm_default__crosstalk_compensation_x_plane_gradient_kcps = + pnvm->algo__crosstalk_compensation_x_plane_gradient_kcps; + pdata->nvm_default__crosstalk_compensation_y_plane_gradient_kcps = + pnvm->algo__crosstalk_compensation_y_plane_gradient_kcps; + + pdata->histogram_mode_crosstalk_margin_kcps = + VL53L1_TUNINGPARM_HIST_XTALK_MARGIN_KCPS_DEFAULT; + pdata->lite_mode_crosstalk_margin_kcps = + VL53L1_TUNINGPARM_LITE_XTALK_MARGIN_KCPS_DEFAULT; + + + + + pdata->crosstalk_range_ignore_threshold_mult = + VL53L1_TUNINGPARM_LITE_RIT_MULT_DEFAULT; + + if ((pdata->algo__crosstalk_compensation_plane_offset_kcps == 0x00) + && (pdata->algo__crosstalk_compensation_x_plane_gradient_kcps + == 0x00) + && (pdata->algo__crosstalk_compensation_y_plane_gradient_kcps + == 0x00)) + pdata->global_crosstalk_compensation_enable = 0x00; + else + pdata->global_crosstalk_compensation_enable = 0x01; + + + if ((status == VL53L1_ERROR_NONE) && + (pdata->global_crosstalk_compensation_enable == 0x01)) { + pdata->crosstalk_range_ignore_threshold_rate_mcps = + VL53L1_calc_range_ignore_threshold( + pdata->algo__crosstalk_compensation_plane_offset_kcps, + pdata->algo__crosstalk_compensation_x_plane_gradient_kcps, + pdata->algo__crosstalk_compensation_y_plane_gradient_kcps, + pdata->crosstalk_range_ignore_threshold_mult); + } else { + pdata->crosstalk_range_ignore_threshold_rate_mcps = 0; + } + + + + + + + + pdata->algo__crosstalk_detect_min_valid_range_mm = + VL53L1_TUNINGPARM_XTALK_DETECT_MIN_VALID_RANGE_MM_DEFAULT; + pdata->algo__crosstalk_detect_max_valid_range_mm = + VL53L1_TUNINGPARM_XTALK_DETECT_MAX_VALID_RANGE_MM_DEFAULT; + pdata->algo__crosstalk_detect_max_valid_rate_kcps = + VL53L1_TUNINGPARM_XTALK_DETECT_MAX_VALID_RATE_KCPS_DEFAULT; + pdata->algo__crosstalk_detect_max_sigma_mm = + VL53L1_TUNINGPARM_XTALK_DETECT_MAX_SIGMA_MM_DEFAULT; + + LOG_FUNCTION_END(status); + + return status; +} + +VL53L1_Error VL53L1_init_xtalk_extract_config_struct( + VL53L1_xtalkextract_config_t *pdata) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + pdata->dss_config__target_total_rate_mcps = + VL53L1_TUNINGPARM_XTALK_EXTRACT_DSS_RATE_MCPS_DEFAULT; + + + pdata->mm_config_timeout_us = + VL53L1_TUNINGPARM_XTALK_EXTRACT_DSS_TIMEOUT_US_DEFAULT; + + + pdata->num_of_samples = + VL53L1_TUNINGPARM_XTALK_EXTRACT_NUM_OF_SAMPLES_DEFAULT; + + pdata->phasecal_config_timeout_us = + VL53L1_TUNINGPARM_XTALK_EXTRACT_PHASECAL_TIMEOUT_US_DEFAULT; + + + pdata->range_config_timeout_us = + VL53L1_TUNINGPARM_XTALK_EXTRACT_BIN_TIMEOUT_US_DEFAULT; + + + + + + + pdata->algo__crosstalk_extract_min_valid_range_mm = + VL53L1_TUNINGPARM_XTALK_EXTRACT_MIN_FILTER_THRESH_MM_DEFAULT; + pdata->algo__crosstalk_extract_max_valid_range_mm = + VL53L1_TUNINGPARM_XTALK_EXTRACT_MAX_FILTER_THRESH_MM_DEFAULT; + pdata->algo__crosstalk_extract_max_valid_rate_kcps = + VL53L1_TUNINGPARM_XTALK_EXTRACT_MAX_VALID_RATE_KCPS_DEFAULT; + pdata->algo__crosstalk_extract_max_sigma_mm = + VL53L1_TUNINGPARM_XTALK_EXTRACT_SIGMA_THRESHOLD_MM_DEFAULT; + + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_init_offset_cal_config_struct( + VL53L1_offsetcal_config_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + pdata->dss_config__target_total_rate_mcps = + VL53L1_TUNINGPARM_OFFSET_CAL_DSS_RATE_MCPS_DEFAULT; + + + pdata->phasecal_config_timeout_us = + VL53L1_TUNINGPARM_OFFSET_CAL_PHASECAL_TIMEOUT_US_DEFAULT; + + + pdata->range_config_timeout_us = + VL53L1_TUNINGPARM_OFFSET_CAL_RANGE_TIMEOUT_US_DEFAULT; + + + pdata->mm_config_timeout_us = + VL53L1_TUNINGPARM_OFFSET_CAL_MM_TIMEOUT_US_DEFAULT; + + + + + + + pdata->pre_num_of_samples = + VL53L1_TUNINGPARM_OFFSET_CAL_PRE_SAMPLES_DEFAULT; + pdata->mm1_num_of_samples = + VL53L1_TUNINGPARM_OFFSET_CAL_MM1_SAMPLES_DEFAULT; + pdata->mm2_num_of_samples = + VL53L1_TUNINGPARM_OFFSET_CAL_MM2_SAMPLES_DEFAULT; + + LOG_FUNCTION_END(status); + + return status; +} + +VL53L1_Error VL53L1_init_zone_cal_config_struct( + VL53L1_zonecal_config_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + pdata->dss_config__target_total_rate_mcps = + VL53L1_TUNINGPARM_ZONE_CAL_DSS_RATE_MCPS_DEFAULT; + + + pdata->phasecal_config_timeout_us = + VL53L1_TUNINGPARM_ZONE_CAL_PHASECAL_TIMEOUT_US_DEFAULT; + + + pdata->range_config_timeout_us = + VL53L1_TUNINGPARM_ZONE_CAL_RANGE_TIMEOUT_US_DEFAULT; + + + pdata->mm_config_timeout_us = + VL53L1_TUNINGPARM_ZONE_CAL_DSS_TIMEOUT_US_DEFAULT; + + + + + + + pdata->phasecal_num_of_samples = + VL53L1_TUNINGPARM_ZONE_CAL_PHASECAL_NUM_SAMPLES_DEFAULT; + pdata->zone_num_of_samples = + VL53L1_TUNINGPARM_ZONE_CAL_ZONE_NUM_SAMPLES_DEFAULT; + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_init_hist_post_process_config_struct( + uint8_t xtalk_compensation_enable, + VL53L1_hist_post_process_config_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + + + pdata->hist_algo_select = + VL53L1_TUNINGPARM_HIST_ALGO_SELECT_DEFAULT; + + + + + pdata->hist_target_order = + VL53L1_TUNINGPARM_HIST_TARGET_ORDER_DEFAULT; + + + + + pdata->filter_woi0 = + VL53L1_TUNINGPARM_HIST_FILTER_WOI_0_DEFAULT; + + pdata->filter_woi1 = + VL53L1_TUNINGPARM_HIST_FILTER_WOI_1_DEFAULT; + + + + + pdata->hist_amb_est_method = + VL53L1_TUNINGPARM_HIST_AMB_EST_METHOD_DEFAULT; + + pdata->ambient_thresh_sigma0 = + VL53L1_TUNINGPARM_HIST_AMB_THRESH_SIGMA_0_DEFAULT; + + pdata->ambient_thresh_sigma1 = + VL53L1_TUNINGPARM_HIST_AMB_THRESH_SIGMA_1_DEFAULT; + + + + + pdata->ambient_thresh_events_scaler = + VL53L1_TUNINGPARM_HIST_AMB_EVENTS_SCALER_DEFAULT; + + + + pdata->min_ambient_thresh_events = + VL53L1_TUNINGPARM_HIST_MIN_AMB_THRESH_EVENTS_DEFAULT; + + + pdata->noise_threshold = + VL53L1_TUNINGPARM_HIST_NOISE_THRESHOLD_DEFAULT; + + + pdata->signal_total_events_limit = + VL53L1_TUNINGPARM_HIST_SIGNAL_TOTAL_EVENTS_LIMIT_DEFAULT; + + pdata->sigma_estimator__sigma_ref_mm = + VL53L1_TUNINGPARM_HIST_SIGMA_EST_REF_MM_DEFAULT; + + + + + + + + + + + + + + + pdata->sigma_thresh = + VL53L1_TUNINGPARM_HIST_SIGMA_THRESH_MM_DEFAULT; + + pdata->range_offset_mm = 0; + + + pdata->gain_factor = + VL53L1_TUNINGPARM_HIST_GAIN_FACTOR_DEFAULT; + + + + + + + + + + + + + + + + pdata->valid_phase_low = 0x08; + pdata->valid_phase_high = 0x88; + + + + + + + + + + pdata->algo__consistency_check__phase_tolerance = + VL53L1_TUNINGPARM_CONSISTENCY_HIST_PHASE_TOLERANCE_DEFAULT; + + + + + + + + + + pdata->algo__consistency_check__event_sigma = + VL53L1_TUNINGPARM_CONSISTENCY_HIST_EVENT_SIGMA_DEFAULT; + + + + pdata->algo__consistency_check__event_min_spad_count = + VL53L1_TUNINGPARM_CONSISTENCY_HIST_EVENT_SIGMA_MIN_SPAD_LIMIT_DEFAULT; + + + + + + pdata->algo__consistency_check__min_max_tolerance = + VL53L1_TUNINGPARM_CONSISTENCY_HIST_MIN_MAX_TOLERANCE_MM_DEFAULT; + + + + pdata->algo__crosstalk_compensation_enable = xtalk_compensation_enable; + + + + + + + + + + + + pdata->algo__crosstalk_detect_min_valid_range_mm = + VL53L1_TUNINGPARM_XTALK_DETECT_MIN_VALID_RANGE_MM_DEFAULT; + pdata->algo__crosstalk_detect_max_valid_range_mm = + VL53L1_TUNINGPARM_XTALK_DETECT_MAX_VALID_RANGE_MM_DEFAULT; + pdata->algo__crosstalk_detect_max_valid_rate_kcps = + VL53L1_TUNINGPARM_XTALK_DETECT_MAX_VALID_RATE_KCPS_DEFAULT; + pdata->algo__crosstalk_detect_max_sigma_mm = + VL53L1_TUNINGPARM_XTALK_DETECT_MAX_SIGMA_MM_DEFAULT; + + + + + + + + + + + + + + pdata->algo__crosstalk_detect_event_sigma = + VL53L1_TUNINGPARM_XTALK_DETECT_EVENT_SIGMA_DEFAULT; + + + + + + pdata->algo__crosstalk_detect_min_max_tolerance = + VL53L1_TUNINGPARM_XTALK_DETECT_MIN_MAX_TOLERANCE_DEFAULT; + + + + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_init_dmax_calibration_data_struct( + VL53L1_dmax_calibration_data_t *pdata) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + + + pdata->ref__actual_effective_spads = 0x5F2D; + + + pdata->ref__peak_signal_count_rate_mcps = 0x0844; + + + pdata->ref__distance_mm = 0x08A5; + + + + + pdata->ref_reflectance_pc = 0x0014; + + + + pdata->coverglass_transmission = 0x0100; + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_init_tuning_parm_storage_struct( + VL53L1_tuning_parm_storage_t *pdata) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + + + + + pdata->tp_tuning_parm_version = + VL53L1_TUNINGPARM_VERSION_DEFAULT; + pdata->tp_tuning_parm_key_table_version = + VL53L1_TUNINGPARM_KEY_TABLE_VERSION_DEFAULT; + pdata->tp_tuning_parm_lld_version = + VL53L1_TUNINGPARM_LLD_VERSION_DEFAULT; + pdata->tp_init_phase_rtn_lite_long = + VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_LITE_LONG_RANGE_DEFAULT; + pdata->tp_init_phase_rtn_lite_med = + VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_LITE_MED_RANGE_DEFAULT; + pdata->tp_init_phase_rtn_lite_short = + VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_LITE_SHORT_RANGE_DEFAULT; + pdata->tp_init_phase_ref_lite_long = + VL53L1_TUNINGPARM_INITIAL_PHASE_REF_LITE_LONG_RANGE_DEFAULT; + pdata->tp_init_phase_ref_lite_med = + VL53L1_TUNINGPARM_INITIAL_PHASE_REF_LITE_MED_RANGE_DEFAULT; + pdata->tp_init_phase_ref_lite_short = + VL53L1_TUNINGPARM_INITIAL_PHASE_REF_LITE_SHORT_RANGE_DEFAULT; + pdata->tp_init_phase_rtn_hist_long = + VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_HISTO_LONG_RANGE_DEFAULT; + pdata->tp_init_phase_rtn_hist_med = + VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_HISTO_MED_RANGE_DEFAULT; + pdata->tp_init_phase_rtn_hist_short = + VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_HISTO_SHORT_RANGE_DEFAULT; + pdata->tp_init_phase_ref_hist_long = + VL53L1_TUNINGPARM_INITIAL_PHASE_REF_HISTO_LONG_RANGE_DEFAULT; + pdata->tp_init_phase_ref_hist_med = + VL53L1_TUNINGPARM_INITIAL_PHASE_REF_HISTO_MED_RANGE_DEFAULT; + pdata->tp_init_phase_ref_hist_short = + VL53L1_TUNINGPARM_INITIAL_PHASE_REF_HISTO_SHORT_RANGE_DEFAULT; + pdata->tp_consistency_lite_phase_tolerance = + VL53L1_TUNINGPARM_CONSISTENCY_LITE_PHASE_TOLERANCE_DEFAULT; + pdata->tp_phasecal_target = + VL53L1_TUNINGPARM_PHASECAL_TARGET_DEFAULT; + pdata->tp_cal_repeat_rate = + VL53L1_TUNINGPARM_LITE_CAL_REPEAT_RATE_DEFAULT; + pdata->tp_lite_min_clip = + VL53L1_TUNINGPARM_LITE_MIN_CLIP_MM_DEFAULT; + pdata->tp_lite_long_sigma_thresh_mm = + VL53L1_TUNINGPARM_LITE_LONG_SIGMA_THRESH_MM_DEFAULT; + pdata->tp_lite_med_sigma_thresh_mm = + VL53L1_TUNINGPARM_LITE_MED_SIGMA_THRESH_MM_DEFAULT; + pdata->tp_lite_short_sigma_thresh_mm = + VL53L1_TUNINGPARM_LITE_SHORT_SIGMA_THRESH_MM_DEFAULT; + pdata->tp_lite_long_min_count_rate_rtn_mcps = + VL53L1_TUNINGPARM_LITE_LONG_MIN_COUNT_RATE_RTN_MCPS_DEFAULT; + pdata->tp_lite_med_min_count_rate_rtn_mcps = + VL53L1_TUNINGPARM_LITE_MED_MIN_COUNT_RATE_RTN_MCPS_DEFAULT; + pdata->tp_lite_short_min_count_rate_rtn_mcps = + VL53L1_TUNINGPARM_LITE_SHORT_MIN_COUNT_RATE_RTN_MCPS_DEFAULT; + pdata->tp_lite_sigma_est_pulse_width_ns = + VL53L1_TUNINGPARM_LITE_SIGMA_EST_PULSE_WIDTH_DEFAULT; + pdata->tp_lite_sigma_est_amb_width_ns = + VL53L1_TUNINGPARM_LITE_SIGMA_EST_AMB_WIDTH_NS_DEFAULT; + pdata->tp_lite_sigma_ref_mm = + VL53L1_TUNINGPARM_LITE_SIGMA_REF_MM_DEFAULT; + pdata->tp_lite_seed_cfg = + VL53L1_TUNINGPARM_LITE_SEED_CONFIG_DEFAULT; + pdata->tp_timed_seed_cfg = + VL53L1_TUNINGPARM_TIMED_SEED_CONFIG_DEFAULT; + pdata->tp_lite_quantifier = + VL53L1_TUNINGPARM_LITE_QUANTIFIER_DEFAULT; + pdata->tp_lite_first_order_select = + VL53L1_TUNINGPARM_LITE_FIRST_ORDER_SELECT_DEFAULT; + + + + + + + pdata->tp_dss_target_lite_mcps = + VL53L1_TUNINGPARM_LITE_DSS_CONFIG_TARGET_TOTAL_RATE_MCPS_DEFAULT; + pdata->tp_dss_target_histo_mcps = + VL53L1_TUNINGPARM_RANGING_DSS_CONFIG_TARGET_TOTAL_RATE_MCPS_DEFAULT; + pdata->tp_dss_target_histo_mz_mcps = + VL53L1_TUNINGPARM_MZ_DSS_CONFIG_TARGET_TOTAL_RATE_MCPS_DEFAULT; + pdata->tp_dss_target_timed_mcps = + VL53L1_TUNINGPARM_TIMED_DSS_CONFIG_TARGET_TOTAL_RATE_MCPS_DEFAULT; + pdata->tp_phasecal_timeout_lite_us = + VL53L1_TUNINGPARM_LITE_PHASECAL_CONFIG_TIMEOUT_US_DEFAULT; + pdata->tp_phasecal_timeout_hist_long_us = + VL53L1_TUNINGPARM_RANGING_LONG_PHASECAL_CONFIG_TIMEOUT_US_DEFAULT; + pdata->tp_phasecal_timeout_hist_med_us = + VL53L1_TUNINGPARM_RANGING_MED_PHASECAL_CONFIG_TIMEOUT_US_DEFAULT; + pdata->tp_phasecal_timeout_hist_short_us = + VL53L1_TUNINGPARM_RANGING_SHORT_PHASECAL_CONFIG_TIMEOUT_US_DEFAULT; + pdata->tp_phasecal_timeout_mz_long_us = + VL53L1_TUNINGPARM_MZ_LONG_PHASECAL_CONFIG_TIMEOUT_US_DEFAULT; + pdata->tp_phasecal_timeout_mz_med_us = + VL53L1_TUNINGPARM_MZ_MED_PHASECAL_CONFIG_TIMEOUT_US_DEFAULT; + pdata->tp_phasecal_timeout_mz_short_us = + VL53L1_TUNINGPARM_MZ_SHORT_PHASECAL_CONFIG_TIMEOUT_US_DEFAULT; + pdata->tp_phasecal_timeout_timed_us = + VL53L1_TUNINGPARM_TIMED_PHASECAL_CONFIG_TIMEOUT_US_DEFAULT; + pdata->tp_mm_timeout_lite_us = + VL53L1_TUNINGPARM_LITE_MM_CONFIG_TIMEOUT_US_DEFAULT; + pdata->tp_mm_timeout_histo_us = + VL53L1_TUNINGPARM_RANGING_MM_CONFIG_TIMEOUT_US_DEFAULT; + pdata->tp_mm_timeout_mz_us = + VL53L1_TUNINGPARM_MZ_MM_CONFIG_TIMEOUT_US_DEFAULT; + pdata->tp_mm_timeout_timed_us = + VL53L1_TUNINGPARM_TIMED_MM_CONFIG_TIMEOUT_US_DEFAULT; + pdata->tp_range_timeout_lite_us = + VL53L1_TUNINGPARM_LITE_RANGE_CONFIG_TIMEOUT_US_DEFAULT; + pdata->tp_range_timeout_histo_us = + VL53L1_TUNINGPARM_RANGING_RANGE_CONFIG_TIMEOUT_US_DEFAULT; + pdata->tp_range_timeout_mz_us = + VL53L1_TUNINGPARM_MZ_RANGE_CONFIG_TIMEOUT_US_DEFAULT; + pdata->tp_range_timeout_timed_us = + VL53L1_TUNINGPARM_TIMED_RANGE_CONFIG_TIMEOUT_US_DEFAULT; + + + + + pdata->tp_mm_timeout_lpa_us = + VL53L1_TUNINGPARM_LOWPOWERAUTO_MM_CONFIG_TIMEOUT_US_DEFAULT; + pdata->tp_range_timeout_lpa_us = + VL53L1_TUNINGPARM_LOWPOWERAUTO_RANGE_CONFIG_TIMEOUT_US_DEFAULT; + + pdata->tp_dss_target_very_short_mcps = + VL53L1_TUNINGPARM_VERY_SHORT_DSS_RATE_MCPS_DEFAULT; + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_init_hist_gen3_dmax_config_struct( + VL53L1_hist_gen3_dmax_config_t *pdata) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + pdata->dss_config__target_total_rate_mcps = 0x1400; + pdata->dss_config__aperture_attenuation = 0x38; + + pdata->signal_thresh_sigma = + VL53L1_TUNINGPARM_DMAX_CFG_SIGNAL_THRESH_SIGMA_DEFAULT; + pdata->ambient_thresh_sigma = 0x70; + pdata->min_ambient_thresh_events = 16; + pdata->signal_total_events_limit = 100; + pdata->max_effective_spads = 0xFFFF; + + + + + + + + + + + + pdata->target_reflectance_for_dmax_calc[0] = + VL53L1_TUNINGPARM_DMAX_CFG_REFLECTANCE_ARRAY_0_DEFAULT; + pdata->target_reflectance_for_dmax_calc[1] = + VL53L1_TUNINGPARM_DMAX_CFG_REFLECTANCE_ARRAY_1_DEFAULT; + pdata->target_reflectance_for_dmax_calc[2] = + VL53L1_TUNINGPARM_DMAX_CFG_REFLECTANCE_ARRAY_2_DEFAULT; + pdata->target_reflectance_for_dmax_calc[3] = + VL53L1_TUNINGPARM_DMAX_CFG_REFLECTANCE_ARRAY_3_DEFAULT; + pdata->target_reflectance_for_dmax_calc[4] = + VL53L1_TUNINGPARM_DMAX_CFG_REFLECTANCE_ARRAY_4_DEFAULT; + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_preset_mode_standard_ranging( + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + + + pstatic->dss_config__target_total_rate_mcps = 0x0A00; + pstatic->debug__ctrl = 0x00; + pstatic->test_mode__ctrl = 0x00; + pstatic->clk_gating__ctrl = 0x00; + pstatic->nvm_bist__ctrl = 0x00; + pstatic->nvm_bist__num_nvm_words = 0x00; + pstatic->nvm_bist__start_address = 0x00; + pstatic->host_if__status = 0x00; + pstatic->pad_i2c_hv__config = 0x00; + pstatic->pad_i2c_hv__extsup_config = 0x00; + + + + + + + pstatic->gpio_hv_pad__ctrl = 0x00; + + + + + + + + + pstatic->gpio_hv_mux__ctrl = + VL53L1_DEVICEINTERRUPTPOLARITY_ACTIVE_LOW | + VL53L1_DEVICEGPIOMODE_OUTPUT_RANGE_AND_ERROR_INTERRUPTS; + + pstatic->gpio__tio_hv_status = 0x02; + pstatic->gpio__fio_hv_status = 0x00; + pstatic->ana_config__spad_sel_pswidth = 0x02; + pstatic->ana_config__vcsel_pulse_width_offset = 0x08; + pstatic->ana_config__fast_osc__config_ctrl = 0x00; + + pstatic->sigma_estimator__effective_pulse_width_ns = + ptuning_parms->tp_lite_sigma_est_pulse_width_ns; + pstatic->sigma_estimator__effective_ambient_width_ns = + ptuning_parms->tp_lite_sigma_est_amb_width_ns; + pstatic->sigma_estimator__sigma_ref_mm = + ptuning_parms->tp_lite_sigma_ref_mm; + + + pstatic->algo__crosstalk_compensation_valid_height_mm = 0x01; + pstatic->spare_host_config__static_config_spare_0 = 0x00; + pstatic->spare_host_config__static_config_spare_1 = 0x00; + + pstatic->algo__range_ignore_threshold_mcps = 0x0000; + + + + pstatic->algo__range_ignore_valid_height_mm = 0xff; + pstatic->algo__range_min_clip = + ptuning_parms->tp_lite_min_clip; + + + + + + + pstatic->algo__consistency_check__tolerance = + ptuning_parms->tp_consistency_lite_phase_tolerance; + pstatic->spare_host_config__static_config_spare_2 = 0x00; + pstatic->sd_config__reset_stages_msb = 0x00; + pstatic->sd_config__reset_stages_lsb = 0x00; + + pgeneral->gph_config__stream_count_update_value = 0x00; + pgeneral->global_config__stream_divider = 0x00; + pgeneral->system__interrupt_config_gpio = + VL53L1_INTERRUPT_CONFIG_NEW_SAMPLE_READY; + pgeneral->cal_config__vcsel_start = 0x0B; + + + + + + + + + pgeneral->cal_config__repeat_rate = + ptuning_parms->tp_cal_repeat_rate; + pgeneral->global_config__vcsel_width = 0x02; + + + pgeneral->phasecal_config__timeout_macrop = 0x0D; + + + pgeneral->phasecal_config__target = + ptuning_parms->tp_phasecal_target; + pgeneral->phasecal_config__override = 0x00; + pgeneral->dss_config__roi_mode_control = + VL53L1_DEVICEDSSMODE__TARGET_RATE; + + + pgeneral->system__thresh_rate_high = 0x0000; + pgeneral->system__thresh_rate_low = 0x0000; + + + pgeneral->dss_config__manual_effective_spads_select = 0x8C00; + pgeneral->dss_config__manual_block_select = 0x00; + + + + + + + + + pgeneral->dss_config__aperture_attenuation = 0x38; + pgeneral->dss_config__max_spads_limit = 0xFF; + pgeneral->dss_config__min_spads_limit = 0x01; + + + + + + + ptiming->mm_config__timeout_macrop_a_hi = 0x00; + ptiming->mm_config__timeout_macrop_a_lo = 0x1a; + ptiming->mm_config__timeout_macrop_b_hi = 0x00; + ptiming->mm_config__timeout_macrop_b_lo = 0x20; + + + ptiming->range_config__timeout_macrop_a_hi = 0x01; + ptiming->range_config__timeout_macrop_a_lo = 0xCC; + + + ptiming->range_config__vcsel_period_a = 0x0B; + + + ptiming->range_config__timeout_macrop_b_hi = 0x01; + ptiming->range_config__timeout_macrop_b_lo = 0xF5; + + + ptiming->range_config__vcsel_period_b = 0x09; + + + + + + + + ptiming->range_config__sigma_thresh = + ptuning_parms->tp_lite_med_sigma_thresh_mm; + + + + + + + ptiming->range_config__min_count_rate_rtn_limit_mcps = + ptuning_parms->tp_lite_med_min_count_rate_rtn_mcps; + + + + + + + ptiming->range_config__valid_phase_low = 0x08; + ptiming->range_config__valid_phase_high = 0x78; + ptiming->system__intermeasurement_period = 0x00000000; + ptiming->system__fractional_enable = 0x00; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + phistogram->histogram_config__low_amb_even_bin_0_1 = 0x07; + phistogram->histogram_config__low_amb_even_bin_2_3 = 0x21; + phistogram->histogram_config__low_amb_even_bin_4_5 = 0x43; + + phistogram->histogram_config__low_amb_odd_bin_0_1 = 0x10; + phistogram->histogram_config__low_amb_odd_bin_2_3 = 0x32; + phistogram->histogram_config__low_amb_odd_bin_4_5 = 0x54; + + phistogram->histogram_config__mid_amb_even_bin_0_1 = 0x07; + phistogram->histogram_config__mid_amb_even_bin_2_3 = 0x21; + phistogram->histogram_config__mid_amb_even_bin_4_5 = 0x43; + + phistogram->histogram_config__mid_amb_odd_bin_0_1 = 0x10; + phistogram->histogram_config__mid_amb_odd_bin_2 = 0x02; + phistogram->histogram_config__mid_amb_odd_bin_3_4 = 0x43; + phistogram->histogram_config__mid_amb_odd_bin_5 = 0x05; + + phistogram->histogram_config__user_bin_offset = 0x00; + + phistogram->histogram_config__high_amb_even_bin_0_1 = 0x07; + phistogram->histogram_config__high_amb_even_bin_2_3 = 0x21; + phistogram->histogram_config__high_amb_even_bin_4_5 = 0x43; + + phistogram->histogram_config__high_amb_odd_bin_0_1 = 0x10; + phistogram->histogram_config__high_amb_odd_bin_2_3 = 0x32; + phistogram->histogram_config__high_amb_odd_bin_4_5 = 0x54; + + phistogram->histogram_config__amb_thresh_low = 0xFFFF; + phistogram->histogram_config__amb_thresh_high = 0xFFFF; + + phistogram->histogram_config__spad_array_selection = 0x00; + + + + + + + + + pzone_cfg->max_zones = VL53L1_MAX_USER_ZONES; + pzone_cfg->active_zones = 0x00; + pzone_cfg->user_zones[0].height = 0x0f; + pzone_cfg->user_zones[0].width = 0x0f; + pzone_cfg->user_zones[0].x_centre = 0x08; + pzone_cfg->user_zones[0].y_centre = 0x08; + + + + + pdynamic->system__grouped_parameter_hold_0 = 0x01; + + pdynamic->system__thresh_high = 0x0000; + pdynamic->system__thresh_low = 0x0000; + pdynamic->system__enable_xtalk_per_quadrant = 0x00; + pdynamic->system__seed_config = + ptuning_parms->tp_lite_seed_cfg; + + + + pdynamic->sd_config__woi_sd0 = 0x0B; + + + pdynamic->sd_config__woi_sd1 = 0x09; + + pdynamic->sd_config__initial_phase_sd0 = + ptuning_parms->tp_init_phase_rtn_lite_med; + pdynamic->sd_config__initial_phase_sd1 = + ptuning_parms->tp_init_phase_ref_lite_med; + + pdynamic->system__grouped_parameter_hold_1 = 0x01; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pdynamic->sd_config__first_order_select = + ptuning_parms->tp_lite_first_order_select; + pdynamic->sd_config__quantifier = + ptuning_parms->tp_lite_quantifier; + + + + + + + pdynamic->roi_config__user_roi_centre_spad = 0xC7; + + + pdynamic->roi_config__user_roi_requested_global_xy_size = 0xFF; + + + pdynamic->system__sequence_config = + VL53L1_SEQUENCE_VHV_EN | + VL53L1_SEQUENCE_PHASECAL_EN | + VL53L1_SEQUENCE_DSS1_EN | + VL53L1_SEQUENCE_DSS2_EN | + VL53L1_SEQUENCE_MM2_EN | + VL53L1_SEQUENCE_RANGE_EN; + + pdynamic->system__grouped_parameter_hold = 0x02; + + + + + + psystem->system__stream_count_ctrl = 0x00; + psystem->firmware__enable = 0x01; + psystem->system__interrupt_clear = + VL53L1_CLEAR_RANGE_INT; + + psystem->system__mode_start = + VL53L1_DEVICESCHEDULERMODE_STREAMING | + VL53L1_DEVICEREADOUTMODE_SINGLE_SD | + VL53L1_DEVICEMEASUREMENTMODE_BACKTOBACK; + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_preset_mode_standard_ranging_short_range( + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + + + status = VL53L1_preset_mode_standard_ranging( + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + + if (status == VL53L1_ERROR_NONE) { + + + + + + + + + + + + + ptiming->range_config__vcsel_period_a = 0x07; + ptiming->range_config__vcsel_period_b = 0x05; + ptiming->range_config__sigma_thresh = + ptuning_parms->tp_lite_short_sigma_thresh_mm; + ptiming->range_config__min_count_rate_rtn_limit_mcps = + ptuning_parms->tp_lite_short_min_count_rate_rtn_mcps; + ptiming->range_config__valid_phase_low = 0x08; + ptiming->range_config__valid_phase_high = 0x38; + + + + + + + + pdynamic->sd_config__woi_sd0 = 0x07; + pdynamic->sd_config__woi_sd1 = 0x05; + pdynamic->sd_config__initial_phase_sd0 = + ptuning_parms->tp_init_phase_rtn_lite_short; + pdynamic->sd_config__initial_phase_sd1 = + ptuning_parms->tp_init_phase_ref_lite_short; + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_preset_mode_standard_ranging_long_range( + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + + + status = VL53L1_preset_mode_standard_ranging( + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + + if (status == VL53L1_ERROR_NONE) { + + + + + + + + + + + + + ptiming->range_config__vcsel_period_a = 0x0F; + ptiming->range_config__vcsel_period_b = 0x0D; + ptiming->range_config__sigma_thresh = + ptuning_parms->tp_lite_long_sigma_thresh_mm; + ptiming->range_config__min_count_rate_rtn_limit_mcps = + ptuning_parms->tp_lite_long_min_count_rate_rtn_mcps; + ptiming->range_config__valid_phase_low = 0x08; + ptiming->range_config__valid_phase_high = 0xB8; + + + + + + + + pdynamic->sd_config__woi_sd0 = 0x0F; + pdynamic->sd_config__woi_sd1 = 0x0D; + pdynamic->sd_config__initial_phase_sd0 = + ptuning_parms->tp_init_phase_rtn_lite_long; + pdynamic->sd_config__initial_phase_sd1 = + ptuning_parms->tp_init_phase_ref_lite_long; + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_preset_mode_standard_ranging_mm1_cal( + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + + + status = VL53L1_preset_mode_standard_ranging( + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + + if (status == VL53L1_ERROR_NONE) { + + pgeneral->dss_config__roi_mode_control = + VL53L1_DEVICEDSSMODE__REQUESTED_EFFFECTIVE_SPADS; + + pdynamic->system__sequence_config = + VL53L1_SEQUENCE_VHV_EN | + VL53L1_SEQUENCE_PHASECAL_EN | + VL53L1_SEQUENCE_DSS1_EN | + VL53L1_SEQUENCE_DSS2_EN | + VL53L1_SEQUENCE_MM1_EN; + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_preset_mode_standard_ranging_mm2_cal( + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + + + status = VL53L1_preset_mode_standard_ranging( + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + + if (status == VL53L1_ERROR_NONE) { + + pgeneral->dss_config__roi_mode_control = + VL53L1_DEVICEDSSMODE__REQUESTED_EFFFECTIVE_SPADS; + + pdynamic->system__sequence_config = + VL53L1_SEQUENCE_VHV_EN | + VL53L1_SEQUENCE_PHASECAL_EN | + VL53L1_SEQUENCE_DSS1_EN | + VL53L1_SEQUENCE_DSS2_EN | + VL53L1_SEQUENCE_MM2_EN; + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_preset_mode_timed_ranging( + + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + status = VL53L1_preset_mode_standard_ranging( + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + + if (status == VL53L1_ERROR_NONE) { + + + + + + + pdynamic->system__grouped_parameter_hold = 0x00; + + + + ptiming->range_config__timeout_macrop_a_hi = 0x00; + ptiming->range_config__timeout_macrop_a_lo = 0xB1; + + + ptiming->range_config__timeout_macrop_b_hi = 0x00; + ptiming->range_config__timeout_macrop_b_lo = 0xD4; + + + + + ptiming->system__intermeasurement_period = 0x00000600; + pdynamic->system__seed_config = + ptuning_parms->tp_timed_seed_cfg; + + + + + + + psystem->system__mode_start = + VL53L1_DEVICESCHEDULERMODE_PSEUDO_SOLO | + VL53L1_DEVICEREADOUTMODE_SINGLE_SD | + VL53L1_DEVICEMEASUREMENTMODE_TIMED; + } + + LOG_FUNCTION_END(status); + + return status; +} + +VL53L1_Error VL53L1_preset_mode_timed_ranging_short_range( + + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + status = VL53L1_preset_mode_standard_ranging_short_range( + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + + if (status == VL53L1_ERROR_NONE) { + + + + + + + pdynamic->system__grouped_parameter_hold = 0x00; + + + + + + + + ptiming->range_config__timeout_macrop_a_hi = 0x01; + ptiming->range_config__timeout_macrop_a_lo = 0x84; + + + ptiming->range_config__timeout_macrop_b_hi = 0x01; + ptiming->range_config__timeout_macrop_b_lo = 0xB1; + + ptiming->system__intermeasurement_period = 0x00000600; + pdynamic->system__seed_config = + ptuning_parms->tp_timed_seed_cfg; + + + + + + + psystem->system__mode_start = + VL53L1_DEVICESCHEDULERMODE_PSEUDO_SOLO | + VL53L1_DEVICEREADOUTMODE_SINGLE_SD | + VL53L1_DEVICEMEASUREMENTMODE_TIMED; + } + + LOG_FUNCTION_END(status); + + return status; +} + +VL53L1_Error VL53L1_preset_mode_timed_ranging_long_range( + + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + status = VL53L1_preset_mode_standard_ranging_long_range( + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + + if (status == VL53L1_ERROR_NONE) { + + + + + + + pdynamic->system__grouped_parameter_hold = 0x00; + + + + + + + + ptiming->range_config__timeout_macrop_a_hi = 0x00; + ptiming->range_config__timeout_macrop_a_lo = 0x97; + + + ptiming->range_config__timeout_macrop_b_hi = 0x00; + ptiming->range_config__timeout_macrop_b_lo = 0xB1; + + ptiming->system__intermeasurement_period = 0x00000600; + pdynamic->system__seed_config = + ptuning_parms->tp_timed_seed_cfg; + + + + + + + psystem->system__mode_start = + VL53L1_DEVICESCHEDULERMODE_PSEUDO_SOLO | + VL53L1_DEVICEREADOUTMODE_SINGLE_SD | + VL53L1_DEVICEMEASUREMENTMODE_TIMED; + } + + LOG_FUNCTION_END(status); + + return status; +} + + + +VL53L1_Error VL53L1_preset_mode_low_power_auto_ranging( + + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg, + VL53L1_low_power_auto_data_t *plpadata) +{ + + + + + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + status = VL53L1_preset_mode_timed_ranging( + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + + if (status == VL53L1_ERROR_NONE) { + status = VL53L1_config_low_power_auto_mode( + pgeneral, + pdynamic, + plpadata + ); + } + + LOG_FUNCTION_END(status); + + return status; +} + +VL53L1_Error VL53L1_preset_mode_low_power_auto_short_ranging( + + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg, + VL53L1_low_power_auto_data_t *plpadata) +{ + + + + + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + status = VL53L1_preset_mode_timed_ranging_short_range( + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + + if (status == VL53L1_ERROR_NONE) { + status = VL53L1_config_low_power_auto_mode( + pgeneral, + pdynamic, + plpadata + ); + } + + LOG_FUNCTION_END(status); + + return status; +} + +VL53L1_Error VL53L1_preset_mode_low_power_auto_long_ranging( + + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg, + VL53L1_low_power_auto_data_t *plpadata) +{ + + + + + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + status = VL53L1_preset_mode_timed_ranging_long_range( + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + + if (status == VL53L1_ERROR_NONE) { + status = VL53L1_config_low_power_auto_mode( + pgeneral, + pdynamic, + plpadata + ); + } + + LOG_FUNCTION_END(status); + + return status; +} + + + + +VL53L1_Error VL53L1_preset_mode_singleshot_ranging( + + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + status = VL53L1_preset_mode_standard_ranging( + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + + if (status == VL53L1_ERROR_NONE) { + + + + + + + pdynamic->system__grouped_parameter_hold = 0x00; + + + + + + + ptiming->range_config__timeout_macrop_a_hi = 0x00; + ptiming->range_config__timeout_macrop_a_lo = 0xB1; + + + ptiming->range_config__timeout_macrop_b_hi = 0x00; + ptiming->range_config__timeout_macrop_b_lo = 0xD4; + + pdynamic->system__seed_config = + ptuning_parms->tp_timed_seed_cfg; + + + + + + + psystem->system__mode_start = + VL53L1_DEVICESCHEDULERMODE_PSEUDO_SOLO | + VL53L1_DEVICEREADOUTMODE_SINGLE_SD | + VL53L1_DEVICEMEASUREMENTMODE_SINGLESHOT; + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_preset_mode_histogram_ranging( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + status = + VL53L1_preset_mode_standard_ranging( + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + + if (status == VL53L1_ERROR_NONE) { + + + + + + + pstatic->dss_config__target_total_rate_mcps = 0x1400; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + VL53L1_init_histogram_config_structure( + 7, 0, 1, 2, 3, 4, + 0, 1, 2, 3, 4, 5, + phistogram); + + + + + + + VL53L1_init_histogram_multizone_config_structure( + 7, 0, 1, 2, 3, 4, + 0, 1, 2, 3, 4, 5, + &(pzone_cfg->multizone_hist_cfg)); + + + + + + + + + + + ptiming->range_config__vcsel_period_a = 0x09; + ptiming->range_config__vcsel_period_b = 0x0B; + pdynamic->sd_config__woi_sd0 = 0x09; + pdynamic->sd_config__woi_sd1 = 0x0B; + + + + + + + ptiming->mm_config__timeout_macrop_a_hi = 0x00; + ptiming->mm_config__timeout_macrop_a_lo = 0x20; + ptiming->mm_config__timeout_macrop_b_hi = 0x00; + ptiming->mm_config__timeout_macrop_b_lo = 0x1A; + + + + ptiming->range_config__timeout_macrop_a_hi = 0x00; + ptiming->range_config__timeout_macrop_a_lo = 0x28; + + + + ptiming->range_config__timeout_macrop_b_hi = 0x00; + ptiming->range_config__timeout_macrop_b_lo = 0x21; + + + + pgeneral->phasecal_config__timeout_macrop = 0xF5; + + + + + + + + + phistpostprocess->valid_phase_low = 0x08; + phistpostprocess->valid_phase_high = 0x88; + + + + + VL53L1_copy_hist_cfg_to_static_cfg( + phistogram, + pstatic, + pgeneral, + ptiming, + pdynamic); + + + + + + pdynamic->system__sequence_config = + VL53L1_SEQUENCE_VHV_EN | + VL53L1_SEQUENCE_PHASECAL_EN | + VL53L1_SEQUENCE_DSS1_EN | + VL53L1_SEQUENCE_DSS2_EN | + + + + + VL53L1_SEQUENCE_RANGE_EN; + + + + + + psystem->system__mode_start = + VL53L1_DEVICESCHEDULERMODE_HISTOGRAM | + VL53L1_DEVICEREADOUTMODE_DUAL_SD | + VL53L1_DEVICEMEASUREMENTMODE_BACKTOBACK; + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_preset_mode_histogram_ranging_with_mm1( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + status = + VL53L1_preset_mode_histogram_ranging( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + + if (status == VL53L1_ERROR_NONE) { + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + VL53L1_init_histogram_config_structure( + 7, 0, 1, 2, 3, 4, + 8+0, 8+1, 8+2, 3, 4, 5, + phistogram); + + + + + + + VL53L1_init_histogram_multizone_config_structure( + 7, 0, 1, 2, 3, 4, + 8+0, 8+1, 8+2, 3, 4, 5, + &(pzone_cfg->multizone_hist_cfg)); + + + + + VL53L1_copy_hist_cfg_to_static_cfg( + phistogram, + pstatic, + pgeneral, + ptiming, + pdynamic); + + + + + pdynamic->system__sequence_config = + VL53L1_SEQUENCE_VHV_EN | + VL53L1_SEQUENCE_PHASECAL_EN | + VL53L1_SEQUENCE_DSS1_EN | + VL53L1_SEQUENCE_DSS2_EN | + VL53L1_SEQUENCE_MM1_EN | + VL53L1_SEQUENCE_RANGE_EN; + + + + + psystem->system__mode_start = + VL53L1_DEVICESCHEDULERMODE_HISTOGRAM | + VL53L1_DEVICEREADOUTMODE_DUAL_SD | + VL53L1_DEVICEMEASUREMENTMODE_BACKTOBACK; + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_preset_mode_histogram_ranging_with_mm2( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + status = + VL53L1_preset_mode_histogram_ranging_with_mm1( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + + if (status == VL53L1_ERROR_NONE) { + + + + + pdynamic->system__sequence_config = + VL53L1_SEQUENCE_VHV_EN | + VL53L1_SEQUENCE_PHASECAL_EN | + VL53L1_SEQUENCE_DSS1_EN | + VL53L1_SEQUENCE_DSS2_EN | + VL53L1_SEQUENCE_MM2_EN | + VL53L1_SEQUENCE_RANGE_EN; + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_preset_mode_histogram_ranging_mm1_cal( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + status = + VL53L1_preset_mode_histogram_ranging( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + + if (status == VL53L1_ERROR_NONE) { + + + + + + + + + + + + + + + + + VL53L1_init_histogram_config_structure( + 7, 8+0, 8+1, 8+2, 8+3, 8+4, + 8+0, 8+1, 8+2, 8+3, 8+4, 8+5, + phistogram); + + + + + + + VL53L1_init_histogram_multizone_config_structure( + 7, 8+0, 8+1, 8+2, 8+3, 8+4, + 8+0, 8+1, 8+2, 8+3, 8+4, 8+5, + &(pzone_cfg->multizone_hist_cfg)); + + + + + VL53L1_copy_hist_cfg_to_static_cfg( + phistogram, + pstatic, + pgeneral, + ptiming, + pdynamic); + + + + + pgeneral->dss_config__roi_mode_control = + VL53L1_DEVICEDSSMODE__REQUESTED_EFFFECTIVE_SPADS; + + + + + pdynamic->system__sequence_config = + VL53L1_SEQUENCE_VHV_EN | + VL53L1_SEQUENCE_PHASECAL_EN | + VL53L1_SEQUENCE_DSS1_EN | + VL53L1_SEQUENCE_DSS2_EN | + VL53L1_SEQUENCE_MM1_EN | + VL53L1_SEQUENCE_RANGE_EN; + + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_preset_mode_histogram_ranging_mm2_cal( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + status = + VL53L1_preset_mode_histogram_ranging_mm1_cal( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + if (status == VL53L1_ERROR_NONE) { + + + + + pdynamic->system__sequence_config = + VL53L1_SEQUENCE_VHV_EN | + VL53L1_SEQUENCE_PHASECAL_EN | + VL53L1_SEQUENCE_DSS1_EN | + VL53L1_SEQUENCE_DSS2_EN | + VL53L1_SEQUENCE_MM2_EN | + VL53L1_SEQUENCE_RANGE_EN; + + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_preset_mode_histogram_ranging_short_timing( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + status = + VL53L1_preset_mode_histogram_ranging( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + + if (status == VL53L1_ERROR_NONE) { + + + + + + + pstatic->dss_config__target_total_rate_mcps = 0x1400; + + + + + VL53L1_init_histogram_config_structure( + 7, 0, 1, 2, 3, 4, + 7, 0, 1, 2, 3, 4, + phistogram); + + + + + + + VL53L1_init_histogram_multizone_config_structure( + 7, 0, 1, 2, 3, 4, + 7, 0, 1, 2, 3, 4, + &(pzone_cfg->multizone_hist_cfg)); + + + + + VL53L1_copy_hist_cfg_to_static_cfg( + phistogram, + pstatic, + pgeneral, + ptiming, + pdynamic); + + + + + + + ptiming->range_config__vcsel_period_a = 0x04; + ptiming->range_config__vcsel_period_b = 0x03; + ptiming->mm_config__timeout_macrop_a_hi = 0x00; + ptiming->mm_config__timeout_macrop_a_lo = 0x42; + ptiming->mm_config__timeout_macrop_b_hi = 0x00; + ptiming->mm_config__timeout_macrop_b_lo = 0x42; + ptiming->range_config__timeout_macrop_a_hi = 0x00; + ptiming->range_config__timeout_macrop_a_lo = 0x52; + ptiming->range_config__timeout_macrop_b_hi = 0x00; + ptiming->range_config__timeout_macrop_b_lo = 0x66; + + pgeneral->cal_config__vcsel_start = 0x04; + + + + + + + + + + + pgeneral->phasecal_config__timeout_macrop = 0xa4; + + + + + pdynamic->system__sequence_config = + VL53L1_SEQUENCE_VHV_EN | + VL53L1_SEQUENCE_PHASECAL_EN | + VL53L1_SEQUENCE_DSS1_EN | + VL53L1_SEQUENCE_DSS2_EN | + + + + + VL53L1_SEQUENCE_RANGE_EN; + + + + + + psystem->system__mode_start = + VL53L1_DEVICESCHEDULERMODE_HISTOGRAM | + VL53L1_DEVICEREADOUTMODE_DUAL_SD | + VL53L1_DEVICEMEASUREMENTMODE_BACKTOBACK; + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_preset_mode_histogram_long_range( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + status = + VL53L1_preset_mode_histogram_ranging( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + + + + + + + + + if (status == VL53L1_ERROR_NONE) { + + + + + + + + + + VL53L1_init_histogram_config_structure( + 7, 0, 1, 2, 3, 4, + 0, 1, 2, 3, 4, 5, + phistogram); + + + + + + + VL53L1_init_histogram_multizone_config_structure( + 7, 0, 1, 2, 3, 4, + + 0, 1, 2, 3, 4, 5, + + &(pzone_cfg->multizone_hist_cfg)); + + + + + VL53L1_copy_hist_cfg_to_static_cfg( + phistogram, + pstatic, + pgeneral, + ptiming, + pdynamic); + + + + + + + ptiming->range_config__vcsel_period_a = 0x09; + ptiming->range_config__vcsel_period_b = 0x0b; + + + + + + + ptiming->mm_config__timeout_macrop_a_hi = 0x00; + ptiming->mm_config__timeout_macrop_a_lo = 0x21; + ptiming->mm_config__timeout_macrop_b_hi = 0x00; + ptiming->mm_config__timeout_macrop_b_lo = 0x1b; + + + + + ptiming->range_config__timeout_macrop_a_hi = 0x00; + ptiming->range_config__timeout_macrop_a_lo = 0x29; + ptiming->range_config__timeout_macrop_b_hi = 0x00; + ptiming->range_config__timeout_macrop_b_lo = 0x22; + + + + + pgeneral->cal_config__vcsel_start = 0x09; + + + + + + + + + + + + + + + pgeneral->phasecal_config__timeout_macrop = 0xF5; + + + + + pdynamic->sd_config__woi_sd0 = 0x09; + pdynamic->sd_config__woi_sd1 = 0x0B; + pdynamic->sd_config__initial_phase_sd0 = + ptuning_parms->tp_init_phase_rtn_hist_long; + pdynamic->sd_config__initial_phase_sd1 = + ptuning_parms->tp_init_phase_ref_hist_long; + + + + + + + + + phistpostprocess->valid_phase_low = 0x08; + phistpostprocess->valid_phase_high = 0x88; + + pdynamic->system__sequence_config = + VL53L1_SEQUENCE_VHV_EN | + VL53L1_SEQUENCE_PHASECAL_EN | + VL53L1_SEQUENCE_DSS1_EN | + VL53L1_SEQUENCE_DSS2_EN | + VL53L1_SEQUENCE_RANGE_EN; + + + + + + psystem->system__mode_start = + VL53L1_DEVICESCHEDULERMODE_HISTOGRAM | + VL53L1_DEVICEREADOUTMODE_DUAL_SD | + VL53L1_DEVICEMEASUREMENTMODE_BACKTOBACK; + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_preset_mode_histogram_long_range_mm1( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + status = + VL53L1_preset_mode_histogram_long_range( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + + + + + + + + + if (status == VL53L1_ERROR_NONE) { + + + + + + + + + + VL53L1_init_histogram_config_structure( + 7, 0, 1, 2, 3, 4, + 8+0, 8+1, 8+2, 3, 4, 5, + phistogram); + + + + + + + VL53L1_init_histogram_multizone_config_structure( + 7, 0, 1, 2, 3, 4, + 8+0, 8+1, 8+2, 3, 4, 5, + &(pzone_cfg->multizone_hist_cfg)); + + + + + VL53L1_copy_hist_cfg_to_static_cfg( + phistogram, + pstatic, + pgeneral, + ptiming, + pdynamic); + + + + + pdynamic->system__sequence_config = + VL53L1_SEQUENCE_VHV_EN | + VL53L1_SEQUENCE_PHASECAL_EN | + VL53L1_SEQUENCE_DSS1_EN | + VL53L1_SEQUENCE_DSS2_EN | + VL53L1_SEQUENCE_MM1_EN | + VL53L1_SEQUENCE_RANGE_EN; + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_preset_mode_histogram_long_range_mm2( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + status = + VL53L1_preset_mode_histogram_long_range_mm1( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + + if (status == VL53L1_ERROR_NONE) { + + + + + pdynamic->system__sequence_config = + VL53L1_SEQUENCE_VHV_EN | + VL53L1_SEQUENCE_PHASECAL_EN | + VL53L1_SEQUENCE_DSS1_EN | + VL53L1_SEQUENCE_DSS2_EN | + VL53L1_SEQUENCE_MM2_EN | + VL53L1_SEQUENCE_RANGE_EN; + } + + LOG_FUNCTION_END(status); + + return status; +} + + + +VL53L1_Error VL53L1_preset_mode_histogram_medium_range( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + status = + VL53L1_preset_mode_histogram_ranging( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + + + + + + + + + if (status == VL53L1_ERROR_NONE) { + + + + + + + + + + VL53L1_init_histogram_config_structure( + 7, 0, 1, 1, 2, 2, + 0, 1, 2, 1, 2, 3, + phistogram); + + + + + + + VL53L1_init_histogram_multizone_config_structure( + 7, 0, 1, 1, 2, 2, + 0, 1, 2, 1, 2, 3, + &(pzone_cfg->multizone_hist_cfg)); + + + + + VL53L1_copy_hist_cfg_to_static_cfg( + phistogram, + pstatic, + pgeneral, + ptiming, + pdynamic); + + + + + + + ptiming->range_config__vcsel_period_a = 0x05; + ptiming->range_config__vcsel_period_b = 0x07; + + + + + + + ptiming->mm_config__timeout_macrop_a_hi = 0x00; + ptiming->mm_config__timeout_macrop_a_lo = 0x36; + ptiming->mm_config__timeout_macrop_b_hi = 0x00; + ptiming->mm_config__timeout_macrop_b_lo = 0x28; + + + + + ptiming->range_config__timeout_macrop_a_hi = 0x00; + ptiming->range_config__timeout_macrop_a_lo = 0x44; + ptiming->range_config__timeout_macrop_b_hi = 0x00; + ptiming->range_config__timeout_macrop_b_lo = 0x33; + + + + + pgeneral->cal_config__vcsel_start = 0x05; + + + + + + + + + + + + + + + pgeneral->phasecal_config__timeout_macrop = 0xF5; + + + + + pdynamic->sd_config__woi_sd0 = 0x05; + pdynamic->sd_config__woi_sd1 = 0x07; + pdynamic->sd_config__initial_phase_sd0 = + ptuning_parms->tp_init_phase_rtn_hist_med; + pdynamic->sd_config__initial_phase_sd1 = + ptuning_parms->tp_init_phase_ref_hist_med; + + + + + + + + + phistpostprocess->valid_phase_low = 0x08; + phistpostprocess->valid_phase_high = 0x48; + + pdynamic->system__sequence_config = + VL53L1_SEQUENCE_VHV_EN | + VL53L1_SEQUENCE_PHASECAL_EN | + VL53L1_SEQUENCE_DSS1_EN | + VL53L1_SEQUENCE_DSS2_EN | + VL53L1_SEQUENCE_RANGE_EN; + + + + + + psystem->system__mode_start = + VL53L1_DEVICESCHEDULERMODE_HISTOGRAM | + VL53L1_DEVICEREADOUTMODE_DUAL_SD | + VL53L1_DEVICEMEASUREMENTMODE_BACKTOBACK; + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_preset_mode_histogram_medium_range_mm1( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + status = + VL53L1_preset_mode_histogram_medium_range( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + + + + + + + + + if (status == VL53L1_ERROR_NONE) { + + + + + VL53L1_init_histogram_config_structure( + 7, 0, 1, 1, 2, 2, + 8+0, 8+1, 8+2, 1, 2, 3, + phistogram); + + + + + + + VL53L1_init_histogram_multizone_config_structure( + 7, 0, 1, 1, 2, 2, + 8+0, 8+1, 8+2, 1, 2, 3, + &(pzone_cfg->multizone_hist_cfg)); + + + + + VL53L1_copy_hist_cfg_to_static_cfg( + phistogram, + pstatic, + pgeneral, + ptiming, + pdynamic); + + + + + pdynamic->system__sequence_config = + VL53L1_SEQUENCE_VHV_EN | + VL53L1_SEQUENCE_PHASECAL_EN | + VL53L1_SEQUENCE_DSS1_EN | + VL53L1_SEQUENCE_DSS2_EN | + VL53L1_SEQUENCE_MM1_EN | + VL53L1_SEQUENCE_RANGE_EN; + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_preset_mode_histogram_medium_range_mm2( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + status = + VL53L1_preset_mode_histogram_medium_range_mm1( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + + if (status == VL53L1_ERROR_NONE) { + + + + + pdynamic->system__sequence_config = + VL53L1_SEQUENCE_VHV_EN | + VL53L1_SEQUENCE_PHASECAL_EN | + VL53L1_SEQUENCE_DSS1_EN | + VL53L1_SEQUENCE_DSS2_EN | + VL53L1_SEQUENCE_MM2_EN | + VL53L1_SEQUENCE_RANGE_EN; + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_preset_mode_histogram_short_range( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + status = + VL53L1_preset_mode_histogram_ranging( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + + + + + + + + + if (status == VL53L1_ERROR_NONE) { + + + + + + + + + + VL53L1_init_histogram_config_structure( + 7, 7, 0, 1, 1, 1, + 0, 1, 1, 1, 2, 2, + phistogram); + + + + + + + VL53L1_init_histogram_multizone_config_structure( + 7, 7, 0, 1, 1, 1, + 0, 1, 1, 1, 2, 2, + &(pzone_cfg->multizone_hist_cfg)); + + + + + VL53L1_copy_hist_cfg_to_static_cfg( + phistogram, + pstatic, + pgeneral, + ptiming, + pdynamic); + + + + + + + ptiming->range_config__vcsel_period_a = 0x03; + ptiming->range_config__vcsel_period_b = 0x05; + + + + + + + ptiming->mm_config__timeout_macrop_a_hi = 0x00; + ptiming->mm_config__timeout_macrop_a_lo = 0x52; + ptiming->mm_config__timeout_macrop_b_hi = 0x00; + ptiming->mm_config__timeout_macrop_b_lo = 0x37; + + + + + ptiming->range_config__timeout_macrop_a_hi = 0x00; + ptiming->range_config__timeout_macrop_a_lo = 0x66; + ptiming->range_config__timeout_macrop_b_hi = 0x00; + ptiming->range_config__timeout_macrop_b_lo = 0x44; + + + + + pgeneral->cal_config__vcsel_start = 0x03; + + + + + + + + + + + + + + + pgeneral->phasecal_config__timeout_macrop = 0xF5; + + + + + pdynamic->sd_config__woi_sd0 = 0x03; + pdynamic->sd_config__woi_sd1 = 0x05; + pdynamic->sd_config__initial_phase_sd0 = + ptuning_parms->tp_init_phase_rtn_hist_short; + pdynamic->sd_config__initial_phase_sd1 = + ptuning_parms->tp_init_phase_ref_hist_short; + + + + + + + + phistpostprocess->valid_phase_low = 0x08; + phistpostprocess->valid_phase_high = 0x28; + + pdynamic->system__sequence_config = + VL53L1_SEQUENCE_VHV_EN | + VL53L1_SEQUENCE_PHASECAL_EN | + VL53L1_SEQUENCE_DSS1_EN | + VL53L1_SEQUENCE_DSS2_EN | + VL53L1_SEQUENCE_MM1_EN | + + + VL53L1_SEQUENCE_RANGE_EN; + + + + + + psystem->system__mode_start = + VL53L1_DEVICESCHEDULERMODE_HISTOGRAM | + VL53L1_DEVICEREADOUTMODE_DUAL_SD | + VL53L1_DEVICEMEASUREMENTMODE_BACKTOBACK; + } + + LOG_FUNCTION_END(status); + + return status; +} + + + + +VL53L1_Error VL53L1_preset_mode_special_histogram_short_range( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + status = + VL53L1_preset_mode_histogram_short_range( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + + + + + + + + + if (status == VL53L1_ERROR_NONE) { + + + + + + + + + + VL53L1_init_histogram_config_structure( + 7, 7, 0, 0, 1, 1, + 0, 0, 0, 1, 1, 1, + phistogram); + + + + + + + VL53L1_init_histogram_multizone_config_structure( + 7, 7, 0, 0, 1, 1, + 0, 0, 0, 1, 1, 1, + &(pzone_cfg->multizone_hist_cfg)); + + + + + VL53L1_copy_hist_cfg_to_static_cfg( + phistogram, + pstatic, + pgeneral, + ptiming, + pdynamic); + + + + + + + ptiming->range_config__vcsel_period_a = 0x02; + ptiming->range_config__vcsel_period_b = 0x03; + + + + + pgeneral->cal_config__vcsel_start = 0x00; + + + + + + pgeneral->phasecal_config__target = 0x31; + + + + + pdynamic->sd_config__woi_sd0 = 0x02; + pdynamic->sd_config__woi_sd1 = 0x03; + pdynamic->sd_config__initial_phase_sd0 = + ptuning_parms->tp_init_phase_rtn_hist_short; + pdynamic->sd_config__initial_phase_sd1 = + ptuning_parms->tp_init_phase_ref_hist_short; + + + + + + + + + phistpostprocess->valid_phase_low = 0x10; + phistpostprocess->valid_phase_high = 0x18; + + } + + LOG_FUNCTION_END(status); + + return status; +} + + + + +VL53L1_Error VL53L1_preset_mode_histogram_short_range_mm1( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + status = + VL53L1_preset_mode_histogram_short_range( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + + + + + + + + + if (status == VL53L1_ERROR_NONE) { + + + + + + + + + + VL53L1_init_histogram_config_structure( + 7, 7, 0, 1, 1, 1, + 8+0, 8+1, 1, 1, 2, 2, + phistogram); + + + + + + + VL53L1_init_histogram_multizone_config_structure( + 7, 7, 0, 1, 1, 1, + 8+0, 8+1, 1, 1, 2, 2, + &(pzone_cfg->multizone_hist_cfg)); + + + + + VL53L1_copy_hist_cfg_to_static_cfg( + phistogram, + pstatic, + pgeneral, + ptiming, + pdynamic); + + + + + pdynamic->system__sequence_config = + VL53L1_SEQUENCE_VHV_EN | + VL53L1_SEQUENCE_PHASECAL_EN | + VL53L1_SEQUENCE_DSS1_EN | + VL53L1_SEQUENCE_DSS2_EN | + VL53L1_SEQUENCE_MM1_EN | + VL53L1_SEQUENCE_RANGE_EN; + + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_preset_mode_histogram_short_range_mm2( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + status = + VL53L1_preset_mode_histogram_short_range_mm1( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + + if (status == VL53L1_ERROR_NONE) { + + + + + pdynamic->system__sequence_config = + VL53L1_SEQUENCE_VHV_EN | + VL53L1_SEQUENCE_PHASECAL_EN | + VL53L1_SEQUENCE_DSS1_EN | + VL53L1_SEQUENCE_DSS2_EN | + VL53L1_SEQUENCE_MM2_EN | + VL53L1_SEQUENCE_RANGE_EN; + } + + LOG_FUNCTION_END(status); + + return status; +} + + + +VL53L1_Error VL53L1_preset_mode_histogram_characterisation( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + status = + VL53L1_preset_mode_histogram_ranging( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + + if (status == VL53L1_ERROR_NONE) { + + + + + pstatic->debug__ctrl = 0x01; + psystem->power_management__go1_power_force = 0x01; + + pdynamic->system__sequence_config = + VL53L1_SEQUENCE_VHV_EN | + VL53L1_SEQUENCE_PHASECAL_EN | + VL53L1_SEQUENCE_RANGE_EN; + + psystem->system__mode_start = + VL53L1_DEVICESCHEDULERMODE_HISTOGRAM | + VL53L1_DEVICEREADOUTMODE_SPLIT_MANUAL | + VL53L1_DEVICEMEASUREMENTMODE_BACKTOBACK; + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_preset_mode_histogram_xtalk_planar( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + status = + VL53L1_preset_mode_histogram_multizone_long_range( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + + if (status == VL53L1_ERROR_NONE) { + + + + + + + status = + VL53L1_zone_preset_xtalk_planar( + pgeneral, + pzone_cfg); + + + + + + + + ptiming->range_config__vcsel_period_a = 0x09; + ptiming->range_config__vcsel_period_b = 0x09; + + + + + VL53L1_init_histogram_config_structure( + 7, 0, 1, 2, 3, 4, + 7, 0, 1, 2, 3, 4, + phistogram); + + + + + + + + VL53L1_init_histogram_multizone_config_structure( + 7, 0, 1, 2, 3, 4, + + 7, 0, 1, 2, 3, 4, + + &(pzone_cfg->multizone_hist_cfg)); + + + + + + + + + + + + if (status == VL53L1_ERROR_NONE) { + status = + VL53L1_set_histogram_multizone_initial_bin_config( + pzone_cfg, + phistogram, + &(pzone_cfg->multizone_hist_cfg)); + } + + + + + + + VL53L1_copy_hist_cfg_to_static_cfg( + phistogram, + pstatic, + pgeneral, + ptiming, + pdynamic); + + } + + LOG_FUNCTION_END(status); + + return status; +} + +VL53L1_Error VL53L1_preset_mode_histogram_xtalk_mm1( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + status = + VL53L1_preset_mode_histogram_ranging( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + + + + + + + + + + + if (status == VL53L1_ERROR_NONE) { + + + + + + + + + + VL53L1_init_histogram_config_structure( + 8+7, 8+0, 8+1, 8+2, 8+3, 8+4, + 8+7, 8+0, 8+1, 8+2, 8+3, 8+4, + phistogram); + + + + + + + VL53L1_init_histogram_multizone_config_structure( + 8+7, 8+0, 8+1, 8+2, 8+3, 8+4, + 8+7, 8+0, 8+1, 8+2, 8+3, 8+4, + &(pzone_cfg->multizone_hist_cfg)); + + + + + VL53L1_copy_hist_cfg_to_static_cfg( + phistogram, + pstatic, + pgeneral, + ptiming, + pdynamic); + + + + + + + ptiming->range_config__vcsel_period_a = 0x09; + ptiming->range_config__vcsel_period_b = 0x09; + + + + + + + ptiming->mm_config__timeout_macrop_a_hi = 0x00; + ptiming->mm_config__timeout_macrop_a_lo = 0x21; + ptiming->mm_config__timeout_macrop_b_hi = 0x00; + ptiming->mm_config__timeout_macrop_b_lo = 0x21; + + + + + ptiming->range_config__timeout_macrop_a_hi = 0x00; + ptiming->range_config__timeout_macrop_a_lo = 0x29; + ptiming->range_config__timeout_macrop_b_hi = 0x00; + ptiming->range_config__timeout_macrop_b_lo = 0x29; + + + + + pgeneral->cal_config__vcsel_start = 0x09; + + + + + + + + + + + + + + pgeneral->phasecal_config__timeout_macrop = 0xF5; + + + + + pdynamic->sd_config__woi_sd0 = 0x09; + pdynamic->sd_config__woi_sd1 = 0x09; + pdynamic->sd_config__initial_phase_sd0 = 0x09; + pdynamic->sd_config__initial_phase_sd1 = 0x06; + + pdynamic->system__sequence_config = + VL53L1_SEQUENCE_VHV_EN | + VL53L1_SEQUENCE_PHASECAL_EN | + VL53L1_SEQUENCE_DSS1_EN | + VL53L1_SEQUENCE_DSS2_EN | + VL53L1_SEQUENCE_MM1_EN | + VL53L1_SEQUENCE_RANGE_EN; + + + + + + psystem->system__mode_start = + VL53L1_DEVICESCHEDULERMODE_HISTOGRAM | + VL53L1_DEVICEREADOUTMODE_DUAL_SD | + VL53L1_DEVICEMEASUREMENTMODE_BACKTOBACK; + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_preset_mode_histogram_xtalk_mm2( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + status = + VL53L1_preset_mode_histogram_xtalk_mm1( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + pdynamic->system__sequence_config = + VL53L1_SEQUENCE_VHV_EN | + VL53L1_SEQUENCE_PHASECAL_EN | + VL53L1_SEQUENCE_DSS1_EN | + VL53L1_SEQUENCE_DSS2_EN | + VL53L1_SEQUENCE_MM2_EN | + VL53L1_SEQUENCE_RANGE_EN; + + + + LOG_FUNCTION_END(status); + + return status; +} + + + + +VL53L1_Error VL53L1_preset_mode_histogram_multizone( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + status = + VL53L1_preset_mode_histogram_medium_range( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + + if (status == VL53L1_ERROR_NONE) { + + + + + + + status = + VL53L1_init_zone_config_structure( + 4, 8, 2, + + 4, 8, 2, + + 7, 7, + + pzone_cfg); + + pgeneral->global_config__stream_divider = + pzone_cfg->active_zones + 1; + + + + + + + if (status == VL53L1_ERROR_NONE) { + status = + VL53L1_set_histogram_multizone_initial_bin_config( + pzone_cfg, + phistogram, + &(pzone_cfg->multizone_hist_cfg)); + } + + VL53L1_copy_hist_cfg_to_static_cfg( + phistogram, + pstatic, + pgeneral, + ptiming, + pdynamic); + } + + LOG_FUNCTION_END(status); + + return status; +} + +VL53L1_Error VL53L1_preset_mode_histogram_multizone_short_range( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + status = + VL53L1_preset_mode_histogram_short_range( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + + if (status == VL53L1_ERROR_NONE) { + + + + + + + status = + VL53L1_init_zone_config_structure( + 4, 8, 2, + + 4, 8, 2, + + 7, 7, + + pzone_cfg); + + pgeneral->global_config__stream_divider = + pzone_cfg->active_zones + 1; + + + + + + + if (status == VL53L1_ERROR_NONE) { + status = + VL53L1_set_histogram_multizone_initial_bin_config( + pzone_cfg, + phistogram, + &(pzone_cfg->multizone_hist_cfg) + ); + } + + + + + VL53L1_copy_hist_cfg_to_static_cfg( + phistogram, + pstatic, + pgeneral, + ptiming, + pdynamic); + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_preset_mode_histogram_multizone_long_range( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + status = + VL53L1_preset_mode_histogram_long_range( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + + if (status == VL53L1_ERROR_NONE) { + + + + + + + status = + VL53L1_init_zone_config_structure( + 4, 8, 2, + + 4, 8, 2, + + 7, 7, + + pzone_cfg); + + pgeneral->global_config__stream_divider = + pzone_cfg->active_zones + 1; + + + + + + + if (status == VL53L1_ERROR_NONE) { + status = + VL53L1_set_histogram_multizone_initial_bin_config( + pzone_cfg, + phistogram, + &(pzone_cfg->multizone_hist_cfg)); + } + + + + + VL53L1_copy_hist_cfg_to_static_cfg( + phistogram, + pstatic, + pgeneral, + ptiming, + pdynamic); + } + + LOG_FUNCTION_END(status); + + return status; +} + + + + +VL53L1_Error VL53L1_preset_mode_olt( + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + status = VL53L1_preset_mode_standard_ranging( + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + + if (status == VL53L1_ERROR_NONE) + + + psystem->system__stream_count_ctrl = 0x01; + + LOG_FUNCTION_END(status); + + return status; +} + + +void VL53L1_copy_hist_cfg_to_static_cfg( + VL53L1_histogram_config_t *phistogram, + VL53L1_static_config_t *pstatic, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic) +{ + + + + + + + LOG_FUNCTION_START(""); + + SUPPRESS_UNUSED_WARNING(pgeneral); + + pstatic->sigma_estimator__effective_pulse_width_ns = + phistogram->histogram_config__high_amb_even_bin_0_1; + pstatic->sigma_estimator__effective_ambient_width_ns = + phistogram->histogram_config__high_amb_even_bin_2_3; + pstatic->sigma_estimator__sigma_ref_mm = + phistogram->histogram_config__high_amb_even_bin_4_5; + + pstatic->algo__crosstalk_compensation_valid_height_mm = + phistogram->histogram_config__high_amb_odd_bin_0_1; + + pstatic->spare_host_config__static_config_spare_0 = + phistogram->histogram_config__high_amb_odd_bin_2_3; + pstatic->spare_host_config__static_config_spare_1 = + phistogram->histogram_config__high_amb_odd_bin_4_5; + + pstatic->algo__range_ignore_threshold_mcps = + (((uint16_t)phistogram->histogram_config__mid_amb_even_bin_0_1) + << 8) + + (uint16_t)phistogram->histogram_config__mid_amb_even_bin_2_3; + + pstatic->algo__range_ignore_valid_height_mm = + phistogram->histogram_config__mid_amb_even_bin_4_5; + pstatic->algo__range_min_clip = + phistogram->histogram_config__mid_amb_odd_bin_0_1; + pstatic->algo__consistency_check__tolerance = + phistogram->histogram_config__mid_amb_odd_bin_2; + + pstatic->spare_host_config__static_config_spare_2 = + phistogram->histogram_config__mid_amb_odd_bin_3_4; + pstatic->sd_config__reset_stages_msb = + phistogram->histogram_config__mid_amb_odd_bin_5; + + pstatic->sd_config__reset_stages_lsb = + phistogram->histogram_config__user_bin_offset; + + ptiming->range_config__sigma_thresh = + (((uint16_t)phistogram->histogram_config__low_amb_even_bin_0_1) + << 8) + + (uint16_t)phistogram->histogram_config__low_amb_even_bin_2_3; + + ptiming->range_config__min_count_rate_rtn_limit_mcps = + (((uint16_t)phistogram->histogram_config__low_amb_even_bin_4_5) + << 8) + + (uint16_t)phistogram->histogram_config__low_amb_odd_bin_0_1; + + ptiming->range_config__valid_phase_low = + phistogram->histogram_config__low_amb_odd_bin_2_3; + ptiming->range_config__valid_phase_high = + phistogram->histogram_config__low_amb_odd_bin_4_5; + + pdynamic->system__thresh_high = + phistogram->histogram_config__amb_thresh_low; + + pdynamic->system__thresh_low = + phistogram->histogram_config__amb_thresh_high; + + pdynamic->system__enable_xtalk_per_quadrant = + phistogram->histogram_config__spad_array_selection; + + LOG_FUNCTION_END(0); + +} + +void VL53L1_copy_hist_bins_to_static_cfg( + VL53L1_histogram_config_t *phistogram, + VL53L1_static_config_t *pstatic, + VL53L1_timing_config_t *ptiming) +{ + + + + + + + LOG_FUNCTION_START(""); + + pstatic->sigma_estimator__effective_pulse_width_ns = + phistogram->histogram_config__high_amb_even_bin_0_1; + pstatic->sigma_estimator__effective_ambient_width_ns = + phistogram->histogram_config__high_amb_even_bin_2_3; + pstatic->sigma_estimator__sigma_ref_mm = + phistogram->histogram_config__high_amb_even_bin_4_5; + + pstatic->algo__crosstalk_compensation_valid_height_mm = + phistogram->histogram_config__high_amb_odd_bin_0_1; + + pstatic->spare_host_config__static_config_spare_0 = + phistogram->histogram_config__high_amb_odd_bin_2_3; + pstatic->spare_host_config__static_config_spare_1 = + phistogram->histogram_config__high_amb_odd_bin_4_5; + + pstatic->algo__range_ignore_threshold_mcps = + (((uint16_t)phistogram->histogram_config__mid_amb_even_bin_0_1) + << 8) + + (uint16_t)phistogram->histogram_config__mid_amb_even_bin_2_3; + + pstatic->algo__range_ignore_valid_height_mm = + phistogram->histogram_config__mid_amb_even_bin_4_5; + pstatic->algo__range_min_clip = + phistogram->histogram_config__mid_amb_odd_bin_0_1; + pstatic->algo__consistency_check__tolerance = + phistogram->histogram_config__mid_amb_odd_bin_2; + + pstatic->spare_host_config__static_config_spare_2 = + phistogram->histogram_config__mid_amb_odd_bin_3_4; + pstatic->sd_config__reset_stages_msb = + phistogram->histogram_config__mid_amb_odd_bin_5; + + ptiming->range_config__sigma_thresh = + (((uint16_t)phistogram->histogram_config__low_amb_even_bin_0_1) + << 8) + + (uint16_t)phistogram->histogram_config__low_amb_even_bin_2_3; + + ptiming->range_config__min_count_rate_rtn_limit_mcps = + (((uint16_t)phistogram->histogram_config__low_amb_even_bin_4_5) + << 8) + + (uint16_t)phistogram->histogram_config__low_amb_odd_bin_0_1; + + ptiming->range_config__valid_phase_low = + phistogram->histogram_config__low_amb_odd_bin_2_3; + ptiming->range_config__valid_phase_high = + phistogram->histogram_config__low_amb_odd_bin_4_5; + + LOG_FUNCTION_END(0); + +} + + +VL53L1_Error VL53L1_preset_mode_histogram_ranging_ref( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + status = + VL53L1_preset_mode_histogram_ranging( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + + if (status == VL53L1_ERROR_NONE) { + + + + + phistogram->histogram_config__spad_array_selection = 0x01; + + + + + VL53L1_copy_hist_cfg_to_static_cfg( + phistogram, + pstatic, + pgeneral, + ptiming, + pdynamic); + } + + LOG_FUNCTION_END(status); + + return status; +} + + + + + diff --git a/drivers/input/misc/vl53L1/lito/src/vl53l1_api_strings.c b/drivers/input/misc/vl53L1/lito/src/vl53l1_api_strings.c new file mode 100644 index 000000000000..70266e4418a7 --- /dev/null +++ b/drivers/input/misc/vl53L1/lito/src/vl53l1_api_strings.c @@ -0,0 +1,334 @@ + +/******************************************************************************* + * Copyright (c) 2017, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#include "vl53l1_api_core.h" +#include "vl53l1_api_strings.h" +#include "vl53l1_error_codes.h" +#include "vl53l1_error_strings.h" + +#define LOG_FUNCTION_START(fmt, ...) \ + _LOG_FUNCTION_START(VL53L1_TRACE_MODULE_API, fmt, ##__VA_ARGS__) +#define LOG_FUNCTION_END(status, ...) \ + _LOG_FUNCTION_END(VL53L1_TRACE_MODULE_API, status, ##__VA_ARGS__) +#define LOG_FUNCTION_END_FMT(status, fmt, ...) \ + _LOG_FUNCTION_END_FMT(VL53L1_TRACE_MODULE_API, status, fmt, \ + ##__VA_ARGS__) + + +VL53L1_Error VL53L1_get_range_status_string( + uint8_t RangeStatus, + char *pRangeStatusString) +{ + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + +#ifdef VL53L1_USE_EMPTY_STRING + VL53L1_COPYSTRING(pRangeStatusString, ""); +#else + switch (RangeStatus) { + case 0: + VL53L1_COPYSTRING(pRangeStatusString, + VL53L1_STRING_RANGESTATUS_RANGEVALID); + break; + case 1: + VL53L1_COPYSTRING(pRangeStatusString, + VL53L1_STRING_RANGESTATUS_SIGMA); + break; + case 2: + VL53L1_COPYSTRING(pRangeStatusString, + VL53L1_STRING_RANGESTATUS_SIGNAL); + break; + case 3: + VL53L1_COPYSTRING(pRangeStatusString, + VL53L1_STRING_RANGESTATUS_MINRANGE); + break; + case 4: + VL53L1_COPYSTRING(pRangeStatusString, + VL53L1_STRING_RANGESTATUS_PHASE); + break; + case 5: + VL53L1_COPYSTRING(pRangeStatusString, + VL53L1_STRING_RANGESTATUS_HW); + break; + + default: + + VL53L1_COPYSTRING(pRangeStatusString, + VL53L1_STRING_RANGESTATUS_NONE); + } +#endif + + LOG_FUNCTION_END(status); + return status; +} + + +VL53L1_Error VL53L1_get_pal_state_string( + VL53L1_State PalStateCode, + char *pPalStateString) +{ + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + +#ifdef VL53L1_USE_EMPTY_STRING + VL53L1_COPYSTRING(pPalStateString, ""); +#else + switch (PalStateCode) { + case VL53L1_STATE_POWERDOWN: + VL53L1_COPYSTRING(pPalStateString, + VL53L1_STRING_STATE_POWERDOWN); + break; + case VL53L1_STATE_WAIT_STATICINIT: + VL53L1_COPYSTRING(pPalStateString, + VL53L1_STRING_STATE_WAIT_STATICINIT); + break; + case VL53L1_STATE_STANDBY: + VL53L1_COPYSTRING(pPalStateString, + VL53L1_STRING_STATE_STANDBY); + break; + case VL53L1_STATE_IDLE: + VL53L1_COPYSTRING(pPalStateString, + VL53L1_STRING_STATE_IDLE); + break; + case VL53L1_STATE_RUNNING: + VL53L1_COPYSTRING(pPalStateString, + VL53L1_STRING_STATE_RUNNING); + break; + case VL53L1_STATE_RESET: + VL53L1_COPYSTRING(pPalStateString, + VL53L1_STRING_STATE_RESET); + break; + case VL53L1_STATE_UNKNOWN: + VL53L1_COPYSTRING(pPalStateString, + VL53L1_STRING_STATE_UNKNOWN); + break; + case VL53L1_STATE_ERROR: + VL53L1_COPYSTRING(pPalStateString, + VL53L1_STRING_STATE_ERROR); + break; + + default: + VL53L1_COPYSTRING(pPalStateString, + VL53L1_STRING_STATE_UNKNOWN); + } +#endif + + LOG_FUNCTION_END(status); + return status; +} + +VL53L1_Error VL53L1_get_sequence_steps_info( + VL53L1_SequenceStepId SequenceStepId, + char *pSequenceStepsString) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + +#ifdef VL53L1_USE_EMPTY_STRING + VL53L1_COPYSTRING(pSequenceStepsString, ""); +#else + switch (SequenceStepId) { + case VL53L1_SEQUENCESTEP_VHV: + VL53L1_COPYSTRING(pSequenceStepsString, + VL53L1_STRING_SEQUENCESTEP_VHV); + break; + case VL53L1_SEQUENCESTEP_PHASECAL: + VL53L1_COPYSTRING(pSequenceStepsString, + VL53L1_STRING_SEQUENCESTEP_PHASECAL); + break; + case VL53L1_SEQUENCESTEP_REFPHASE: + VL53L1_COPYSTRING(pSequenceStepsString, + VL53L1_STRING_SEQUENCESTEP_DSS1); + break; + case VL53L1_SEQUENCESTEP_DSS1: + VL53L1_COPYSTRING(pSequenceStepsString, + VL53L1_STRING_SEQUENCESTEP_DSS1); + break; + case VL53L1_SEQUENCESTEP_DSS2: + VL53L1_COPYSTRING(pSequenceStepsString, + VL53L1_STRING_SEQUENCESTEP_DSS2); + break; + case VL53L1_SEQUENCESTEP_MM1: + VL53L1_COPYSTRING(pSequenceStepsString, + VL53L1_STRING_SEQUENCESTEP_MM1); + break; + case VL53L1_SEQUENCESTEP_MM2: + VL53L1_COPYSTRING(pSequenceStepsString, + VL53L1_STRING_SEQUENCESTEP_MM2); + break; + case VL53L1_SEQUENCESTEP_RANGE: + VL53L1_COPYSTRING(pSequenceStepsString, + VL53L1_STRING_SEQUENCESTEP_RANGE); + break; + default: + Status = VL53L1_ERROR_INVALID_PARAMS; + } +#endif + + LOG_FUNCTION_END(Status); + + return Status; +} + +VL53L1_Error VL53L1_get_limit_check_info(uint16_t LimitCheckId, + char *pLimitCheckString) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + +#ifdef VL53L1_USE_EMPTY_STRING + VL53L1_COPYSTRING(pLimitCheckString, ""); +#else + switch (LimitCheckId) { + case VL53L1_CHECKENABLE_SIGMA_FINAL_RANGE: + VL53L1_COPYSTRING(pLimitCheckString, + VL53L1_STRING_CHECKENABLE_SIGMA_FINAL_RANGE); + break; + case VL53L1_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE: + VL53L1_COPYSTRING(pLimitCheckString, + VL53L1_STRING_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE); + break; + default: + VL53L1_COPYSTRING(pLimitCheckString, + VL53L1_STRING_UNKNOW_ERROR_CODE); + } +#endif + + LOG_FUNCTION_END(Status); + return Status; +} + + diff --git a/drivers/input/misc/vl53L1/lito/src/vl53l1_core.c b/drivers/input/misc/vl53L1/lito/src/vl53l1_core.c new file mode 100644 index 000000000000..b7abb5c78b73 --- /dev/null +++ b/drivers/input/misc/vl53L1/lito/src/vl53l1_core.c @@ -0,0 +1,5888 @@ + +/******************************************************************************* + * Copyright (c) 2017, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#include "vl53l1_ll_def.h" +#include "vl53l1_ll_device.h" +#include "vl53l1_platform.h" +#include "vl53l1_register_map.h" +#include "vl53l1_register_funcs.h" +#include "vl53l1_register_settings.h" +#include "vl53l1_hist_structs.h" +#include "vl53l1_api_preset_modes.h" +#include "vl53l1_core.h" +#include "vl53l1_tuning_parm_defaults.h" + + + + + + + +#define LOG_FUNCTION_START(fmt, ...) \ + _LOG_FUNCTION_START(VL53L1_TRACE_MODULE_CORE, fmt, ##__VA_ARGS__) +#define LOG_FUNCTION_END(status, ...) \ + _LOG_FUNCTION_END(VL53L1_TRACE_MODULE_CORE, status, ##__VA_ARGS__) +#define LOG_FUNCTION_END_FMT(status, fmt, ...) \ + _LOG_FUNCTION_END_FMT(VL53L1_TRACE_MODULE_CORE, \ + status, fmt, ##__VA_ARGS__) + +#define trace_print(level, ...) \ + _LOG_TRACE_PRINT(VL53L1_TRACE_MODULE_CORE, \ + level, VL53L1_TRACE_FUNCTION_NONE, ##__VA_ARGS__) + + +void VL53L1_init_version( + VL53L1_DEV Dev) +{ + + + + + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + pdev->version.ll_major = VL53L1_LL_API_IMPLEMENTATION_VER_MAJOR; + pdev->version.ll_minor = VL53L1_LL_API_IMPLEMENTATION_VER_MINOR; + pdev->version.ll_build = VL53L1_LL_API_IMPLEMENTATION_VER_SUB; + pdev->version.ll_revision = VL53L1_LL_API_IMPLEMENTATION_VER_REVISION; +} + + +void VL53L1_init_ll_driver_state( + VL53L1_DEV Dev, + VL53L1_DeviceState device_state) +{ + + + + + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_ll_driver_state_t *pstate = &(pdev->ll_state); + + pstate->cfg_device_state = device_state; + pstate->cfg_stream_count = 0; + pstate->cfg_gph_id = VL53L1_GROUPEDPARAMETERHOLD_ID_MASK; + pstate->cfg_timing_status = 0; + pstate->cfg_zone_id = 0; + + pstate->rd_device_state = device_state; + pstate->rd_stream_count = 0; + pstate->rd_gph_id = VL53L1_GROUPEDPARAMETERHOLD_ID_MASK; + pstate->rd_timing_status = 0; + pstate->rd_zone_id = 0; + +} + + +VL53L1_Error VL53L1_update_ll_driver_rd_state( + VL53L1_DEV Dev) +{ + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_ll_driver_state_t *pstate = &(pdev->ll_state); + + + + + LOG_FUNCTION_START(""); + + + + + + if ((pdev->sys_ctrl.system__mode_start & + VL53L1_DEVICEMEASUREMENTMODE_MODE_MASK) == 0x00) { + + pstate->rd_device_state = VL53L1_DEVICESTATE_SW_STANDBY; + pstate->rd_stream_count = 0; + pstate->rd_internal_stream_count = 0; + pstate->rd_internal_stream_count_val = 0; + pstate->rd_gph_id = VL53L1_GROUPEDPARAMETERHOLD_ID_MASK; + pstate->rd_timing_status = 0; + pstate->rd_zone_id = 0; + + } else { + + + + + + + if (pstate->rd_stream_count == 0xFF) + pstate->rd_stream_count = 0x80; + else + pstate->rd_stream_count++; + + + + + + status = VL53L1_update_internal_stream_counters(Dev, + pstate->rd_stream_count, + &(pstate->rd_internal_stream_count), + &(pstate->rd_internal_stream_count_val)); + + + + + + + pstate->rd_gph_id ^= VL53L1_GROUPEDPARAMETERHOLD_ID_MASK; + + + + + switch (pstate->rd_device_state) { + + case VL53L1_DEVICESTATE_SW_STANDBY: + + if ((pdev->dyn_cfg.system__grouped_parameter_hold & + VL53L1_GROUPEDPARAMETERHOLD_ID_MASK) > 0) { + pstate->rd_device_state = + VL53L1_DEVICESTATE_RANGING_WAIT_GPH_SYNC; + } else { + if (pstate->rd_zone_id >= + pdev->zone_cfg.active_zones) + pstate->rd_device_state = + VL53L1_DEVICESTATE_RANGING_OUTPUT_DATA; + else + pstate->rd_device_state = + VL53L1_DEVICESTATE_RANGING_GATHER_DATA; + } + + pstate->rd_stream_count = 0; + pstate->rd_internal_stream_count = 0; + pstate->rd_internal_stream_count_val = 0; + pstate->rd_timing_status = 0; + pstate->rd_zone_id = 0; + + break; + + case VL53L1_DEVICESTATE_RANGING_WAIT_GPH_SYNC: + pstate->rd_stream_count = 0; + pstate->rd_internal_stream_count = 0; + pstate->rd_internal_stream_count_val = 0; + pstate->rd_zone_id = 0; + if (pstate->rd_zone_id >= + pdev->zone_cfg.active_zones) + pstate->rd_device_state = + VL53L1_DEVICESTATE_RANGING_OUTPUT_DATA; + else + pstate->rd_device_state = + VL53L1_DEVICESTATE_RANGING_GATHER_DATA; + + break; + + case VL53L1_DEVICESTATE_RANGING_GATHER_DATA: + pstate->rd_zone_id++; + if (pstate->rd_zone_id >= + pdev->zone_cfg.active_zones) + pstate->rd_device_state = + VL53L1_DEVICESTATE_RANGING_OUTPUT_DATA; + else + pstate->rd_device_state = + VL53L1_DEVICESTATE_RANGING_GATHER_DATA; + + break; + + case VL53L1_DEVICESTATE_RANGING_OUTPUT_DATA: + pstate->rd_zone_id = 0; + pstate->rd_timing_status ^= 0x01; + + if (pstate->rd_zone_id >= + pdev->zone_cfg.active_zones) + pstate->rd_device_state = + VL53L1_DEVICESTATE_RANGING_OUTPUT_DATA; + else + pstate->rd_device_state = + VL53L1_DEVICESTATE_RANGING_GATHER_DATA; + break; + + default: + pstate->rd_device_state = + VL53L1_DEVICESTATE_SW_STANDBY; + pstate->rd_stream_count = 0; + pstate->rd_internal_stream_count = 0; + pstate->rd_internal_stream_count_val = 0; + pstate->rd_gph_id = VL53L1_GROUPEDPARAMETERHOLD_ID_MASK; + pstate->rd_timing_status = 0; + pstate->rd_zone_id = 0; + break; + } + } + + + + + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_check_ll_driver_rd_state( + VL53L1_DEV Dev) +{ + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_LLDriverResults_t *pres = + VL53L1DevStructGetLLResultsHandle(Dev); + + VL53L1_ll_driver_state_t *pstate = &(pdev->ll_state); + VL53L1_system_results_t *psys_results = &(pdev->sys_results); + VL53L1_histogram_bin_data_t *phist_data = &(pdev->hist_data); + VL53L1_zone_private_dyn_cfgs_t *pZ = &(pres->zone_dyn_cfgs); + + uint8_t device_range_status = 0; + uint8_t device_stream_count = 0; + uint8_t device_gph_id = 0; + uint8_t histogram_mode = 0; + uint8_t expected_stream_count = 0; + uint8_t expected_gph_id = 0; + + LOG_FUNCTION_START(""); + + + + + + device_range_status = + psys_results->result__range_status & + VL53L1_RANGE_STATUS__RANGE_STATUS_MASK; + + device_stream_count = psys_results->result__stream_count; + + + + + histogram_mode = + (pdev->sys_ctrl.system__mode_start & + VL53L1_DEVICESCHEDULERMODE_HISTOGRAM) == + VL53L1_DEVICESCHEDULERMODE_HISTOGRAM; + + + + device_gph_id = (psys_results->result__interrupt_status & + VL53L1_INTERRUPT_STATUS__GPH_ID_INT_STATUS_MASK) >> 4; + + if (histogram_mode) + device_gph_id = (phist_data->result__interrupt_status & + VL53L1_INTERRUPT_STATUS__GPH_ID_INT_STATUS_MASK) >> 4; + + + + + if (!((pdev->sys_ctrl.system__mode_start & + VL53L1_DEVICEMEASUREMENTMODE_BACKTOBACK) == + VL53L1_DEVICEMEASUREMENTMODE_BACKTOBACK)) + goto ENDFUNC; + + + + + + + + + + + + + + + if (pstate->rd_device_state == + VL53L1_DEVICESTATE_RANGING_WAIT_GPH_SYNC) { + + if (histogram_mode == 0) { + if (device_range_status != + VL53L1_DEVICEERROR_GPHSTREAMCOUNT0READY) + status = + VL53L1_ERROR_GPH_SYNC_CHECK_FAIL; + + } + } else { + if (pstate->rd_stream_count != device_stream_count) + status = VL53L1_ERROR_STREAM_COUNT_CHECK_FAIL; + + + + + + if (pstate->rd_gph_id != device_gph_id) + status = VL53L1_ERROR_GPH_ID_CHECK_FAIL; + + + + + + + + + + + + + + + + + + + + + + expected_stream_count = + pZ->VL53L1_p_002[pstate->rd_zone_id].expected_stream_count; + expected_gph_id = + pZ->VL53L1_p_002[pstate->rd_zone_id].expected_gph_id; + + + + + + + if (expected_stream_count != device_stream_count) { + + + + + + if (!((pdev->zone_cfg.active_zones == 0) && + (device_stream_count == 255))) + status = + VL53L1_ERROR_ZONE_STREAM_COUNT_CHECK_FAIL; + + + + + + + + + + + + + + + + + + + } + + + + + + + if (expected_gph_id != device_gph_id) + status = VL53L1_ERROR_ZONE_GPH_ID_CHECK_FAIL; + + + + + + + + + + + } + + + + + + + + + + + + + + +ENDFUNC: + LOG_FUNCTION_END(status); + return status; +} + + +VL53L1_Error VL53L1_update_ll_driver_cfg_state( + VL53L1_DEV Dev) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_LLDriverResults_t *pres = + VL53L1DevStructGetLLResultsHandle(Dev); + + VL53L1_ll_driver_state_t *pstate = &(pdev->ll_state); + VL53L1_zone_private_dyn_cfgs_t *pZ = &(pres->zone_dyn_cfgs); + + uint8_t prev_cfg_zone_id; + uint8_t prev_cfg_gph_id; + uint8_t prev_cfg_stream_count; + + LOG_FUNCTION_START(""); + + + + + + + + + if ((pdev->sys_ctrl.system__mode_start & + VL53L1_DEVICEMEASUREMENTMODE_MODE_MASK) == 0x00) { + + pstate->cfg_device_state = VL53L1_DEVICESTATE_SW_STANDBY; + pstate->cfg_stream_count = 0; + pstate->cfg_internal_stream_count = 0; + pstate->cfg_internal_stream_count_val = 0; + pstate->cfg_gph_id = VL53L1_GROUPEDPARAMETERHOLD_ID_MASK; + pstate->cfg_timing_status = 0; + pstate->cfg_zone_id = 0; + prev_cfg_zone_id = 0; + prev_cfg_gph_id = 0; + prev_cfg_stream_count = 0; + + } else { + + + + + prev_cfg_gph_id = pstate->cfg_gph_id; + prev_cfg_zone_id = pstate->cfg_zone_id; + prev_cfg_stream_count = pstate->cfg_stream_count; + + + + + + + if (pstate->cfg_stream_count == 0xFF) + pstate->cfg_stream_count = 0x80; + else + pstate->cfg_stream_count++; + + + + + + status = VL53L1_update_internal_stream_counters( + Dev, + pstate->cfg_stream_count, + &(pstate->cfg_internal_stream_count), + &(pstate->cfg_internal_stream_count_val)); + + + + + + + pstate->cfg_gph_id ^= VL53L1_GROUPEDPARAMETERHOLD_ID_MASK; + + + + + + + switch (pstate->cfg_device_state) { + + case VL53L1_DEVICESTATE_SW_STANDBY: + pstate->cfg_zone_id = 1; + if (pstate->cfg_zone_id > + pdev->zone_cfg.active_zones) { + pstate->cfg_zone_id = 0; + pstate->cfg_timing_status ^= 0x01; + } + pstate->cfg_stream_count = 1; + + if (pdev->gen_cfg.global_config__stream_divider == 0) { + pstate->cfg_internal_stream_count = 1; + pstate->cfg_internal_stream_count_val = 0; + } else { + pstate->cfg_internal_stream_count = 0; + pstate->cfg_internal_stream_count_val = 1; + } + pstate->cfg_device_state = + VL53L1_DEVICESTATE_RANGING_DSS_AUTO; + break; + + case VL53L1_DEVICESTATE_RANGING_DSS_AUTO: + pstate->cfg_zone_id++; + if (pstate->cfg_zone_id > + pdev->zone_cfg.active_zones) { + + pstate->cfg_zone_id = 0; + pstate->cfg_timing_status ^= 0x01; + + + + + + + if (pdev->zone_cfg.active_zones > 0) { + pstate->cfg_device_state = + VL53L1_DEVICESTATE_RANGING_DSS_MANUAL; + } + } + break; + + case VL53L1_DEVICESTATE_RANGING_DSS_MANUAL: + pstate->cfg_zone_id++; + if (pstate->cfg_zone_id > + pdev->zone_cfg.active_zones) { + pstate->cfg_zone_id = 0; + pstate->cfg_timing_status ^= 0x01; + } + break; + + default: + pstate->cfg_device_state = + VL53L1_DEVICESTATE_SW_STANDBY; + pstate->cfg_stream_count = 0; + pstate->cfg_internal_stream_count = 0; + pstate->cfg_internal_stream_count_val = 0; + pstate->cfg_gph_id = + VL53L1_GROUPEDPARAMETERHOLD_ID_MASK; + pstate->cfg_timing_status = 0; + pstate->cfg_zone_id = 0; + break; + } + } + + + + + + if (pdev->zone_cfg.active_zones == 0) { + + + + + + pZ->VL53L1_p_002[prev_cfg_zone_id].expected_stream_count + = prev_cfg_stream_count - 1; + + pZ->VL53L1_p_002[pstate->rd_zone_id].expected_gph_id = + prev_cfg_gph_id ^ VL53L1_GROUPEDPARAMETERHOLD_ID_MASK; + } else { + pZ->VL53L1_p_002[prev_cfg_zone_id].expected_stream_count + = prev_cfg_stream_count; + pZ->VL53L1_p_002[prev_cfg_zone_id].expected_gph_id = + prev_cfg_gph_id; + } + + + + + + LOG_FUNCTION_END(status); + + return status; +} + + +void VL53L1_copy_rtn_good_spads_to_buffer( + VL53L1_nvm_copy_data_t *pdata, + uint8_t *pbuffer) +{ + + + + + + *(pbuffer + 0) = pdata->global_config__spad_enables_rtn_0; + *(pbuffer + 1) = pdata->global_config__spad_enables_rtn_1; + *(pbuffer + 2) = pdata->global_config__spad_enables_rtn_2; + *(pbuffer + 3) = pdata->global_config__spad_enables_rtn_3; + *(pbuffer + 4) = pdata->global_config__spad_enables_rtn_4; + *(pbuffer + 5) = pdata->global_config__spad_enables_rtn_5; + *(pbuffer + 6) = pdata->global_config__spad_enables_rtn_6; + *(pbuffer + 7) = pdata->global_config__spad_enables_rtn_7; + *(pbuffer + 8) = pdata->global_config__spad_enables_rtn_8; + *(pbuffer + 9) = pdata->global_config__spad_enables_rtn_9; + *(pbuffer + 10) = pdata->global_config__spad_enables_rtn_10; + *(pbuffer + 11) = pdata->global_config__spad_enables_rtn_11; + *(pbuffer + 12) = pdata->global_config__spad_enables_rtn_12; + *(pbuffer + 13) = pdata->global_config__spad_enables_rtn_13; + *(pbuffer + 14) = pdata->global_config__spad_enables_rtn_14; + *(pbuffer + 15) = pdata->global_config__spad_enables_rtn_15; + *(pbuffer + 16) = pdata->global_config__spad_enables_rtn_16; + *(pbuffer + 17) = pdata->global_config__spad_enables_rtn_17; + *(pbuffer + 18) = pdata->global_config__spad_enables_rtn_18; + *(pbuffer + 19) = pdata->global_config__spad_enables_rtn_19; + *(pbuffer + 20) = pdata->global_config__spad_enables_rtn_20; + *(pbuffer + 21) = pdata->global_config__spad_enables_rtn_21; + *(pbuffer + 22) = pdata->global_config__spad_enables_rtn_22; + *(pbuffer + 23) = pdata->global_config__spad_enables_rtn_23; + *(pbuffer + 24) = pdata->global_config__spad_enables_rtn_24; + *(pbuffer + 25) = pdata->global_config__spad_enables_rtn_25; + *(pbuffer + 26) = pdata->global_config__spad_enables_rtn_26; + *(pbuffer + 27) = pdata->global_config__spad_enables_rtn_27; + *(pbuffer + 28) = pdata->global_config__spad_enables_rtn_28; + *(pbuffer + 29) = pdata->global_config__spad_enables_rtn_29; + *(pbuffer + 30) = pdata->global_config__spad_enables_rtn_30; + *(pbuffer + 31) = pdata->global_config__spad_enables_rtn_31; +} + + +void VL53L1_init_system_results( + VL53L1_system_results_t *pdata) +{ + + + + + + + pdata->result__interrupt_status = 0xFF; + pdata->result__range_status = 0xFF; + pdata->result__report_status = 0xFF; + pdata->result__stream_count = 0xFF; + + pdata->result__dss_actual_effective_spads_sd0 = 0xFFFF; + pdata->result__peak_signal_count_rate_mcps_sd0 = 0xFFFF; + pdata->result__ambient_count_rate_mcps_sd0 = 0xFFFF; + pdata->result__sigma_sd0 = 0xFFFF; + pdata->result__phase_sd0 = 0xFFFF; + pdata->result__final_crosstalk_corrected_range_mm_sd0 = 0xFFFF; + pdata->result__peak_signal_count_rate_crosstalk_corrected_mcps_sd0 = + 0xFFFF; + pdata->result__mm_inner_actual_effective_spads_sd0 = 0xFFFF; + pdata->result__mm_outer_actual_effective_spads_sd0 = 0xFFFF; + pdata->result__avg_signal_count_rate_mcps_sd0 = 0xFFFF; + + pdata->result__dss_actual_effective_spads_sd1 = 0xFFFF; + pdata->result__peak_signal_count_rate_mcps_sd1 = 0xFFFF; + pdata->result__ambient_count_rate_mcps_sd1 = 0xFFFF; + pdata->result__sigma_sd1 = 0xFFFF; + pdata->result__phase_sd1 = 0xFFFF; + pdata->result__final_crosstalk_corrected_range_mm_sd1 = 0xFFFF; + pdata->result__spare_0_sd1 = 0xFFFF; + pdata->result__spare_1_sd1 = 0xFFFF; + pdata->result__spare_2_sd1 = 0xFFFF; + pdata->result__spare_3_sd1 = 0xFF; + +} + + +void V53L1_init_zone_results_structure( + uint8_t active_zones, + VL53L1_zone_results_t *pdata) +{ + + + + + uint8_t z = 0; + VL53L1_zone_objects_t *pobjects; + + pdata->max_zones = VL53L1_MAX_USER_ZONES; + pdata->active_zones = active_zones; + + for (z = 0; z < pdata->max_zones; z++) { + pobjects = &(pdata->VL53L1_p_002[z]); + pobjects->cfg_device_state = VL53L1_DEVICESTATE_SW_STANDBY; + pobjects->rd_device_state = VL53L1_DEVICESTATE_SW_STANDBY; + pobjects->max_objects = VL53L1_MAX_RANGE_RESULTS; + pobjects->active_objects = 0; + } +} + +void V53L1_init_zone_dss_configs( + VL53L1_DEV Dev) +{ + + + + + VL53L1_LLDriverResults_t *pres = + VL53L1DevStructGetLLResultsHandle(Dev); + uint8_t z = 0; + uint8_t max_zones = VL53L1_MAX_USER_ZONES; + VL53L1_zone_private_dyn_cfgs_t *pdata = &(pres->zone_dyn_cfgs); + + for (z = 0; z < max_zones; z++) { + pdata->VL53L1_p_002[z].dss_mode = + VL53L1_DSS_CONTROL__MODE_TARGET_RATE; + pdata->VL53L1_p_002[z].dss_requested_effective_spad_count = 0; + } +} + + +void VL53L1_init_histogram_config_structure( + uint8_t even_bin0, + uint8_t even_bin1, + uint8_t even_bin2, + uint8_t even_bin3, + uint8_t even_bin4, + uint8_t even_bin5, + uint8_t odd_bin0, + uint8_t odd_bin1, + uint8_t odd_bin2, + uint8_t odd_bin3, + uint8_t odd_bin4, + uint8_t odd_bin5, + VL53L1_histogram_config_t *pdata) +{ + + + + + + + pdata->histogram_config__low_amb_even_bin_0_1 = + (even_bin1 << 4) + even_bin0; + pdata->histogram_config__low_amb_even_bin_2_3 = + (even_bin3 << 4) + even_bin2; + pdata->histogram_config__low_amb_even_bin_4_5 = + (even_bin5 << 4) + even_bin4; + + pdata->histogram_config__low_amb_odd_bin_0_1 = + (odd_bin1 << 4) + odd_bin0; + pdata->histogram_config__low_amb_odd_bin_2_3 = + (odd_bin3 << 4) + odd_bin2; + pdata->histogram_config__low_amb_odd_bin_4_5 = + (odd_bin5 << 4) + odd_bin4; + + pdata->histogram_config__mid_amb_even_bin_0_1 = + pdata->histogram_config__low_amb_even_bin_0_1; + pdata->histogram_config__mid_amb_even_bin_2_3 = + pdata->histogram_config__low_amb_even_bin_2_3; + pdata->histogram_config__mid_amb_even_bin_4_5 = + pdata->histogram_config__low_amb_even_bin_4_5; + + pdata->histogram_config__mid_amb_odd_bin_0_1 = + pdata->histogram_config__low_amb_odd_bin_0_1; + pdata->histogram_config__mid_amb_odd_bin_2 = odd_bin2; + pdata->histogram_config__mid_amb_odd_bin_3_4 = + (odd_bin4 << 4) + odd_bin3; + pdata->histogram_config__mid_amb_odd_bin_5 = odd_bin5; + + pdata->histogram_config__user_bin_offset = 0x00; + + pdata->histogram_config__high_amb_even_bin_0_1 = + pdata->histogram_config__low_amb_even_bin_0_1; + pdata->histogram_config__high_amb_even_bin_2_3 = + pdata->histogram_config__low_amb_even_bin_2_3; + pdata->histogram_config__high_amb_even_bin_4_5 = + pdata->histogram_config__low_amb_even_bin_4_5; + + pdata->histogram_config__high_amb_odd_bin_0_1 = + pdata->histogram_config__low_amb_odd_bin_0_1; + pdata->histogram_config__high_amb_odd_bin_2_3 = + pdata->histogram_config__low_amb_odd_bin_2_3; + pdata->histogram_config__high_amb_odd_bin_4_5 = + pdata->histogram_config__low_amb_odd_bin_4_5; + + + + + pdata->histogram_config__amb_thresh_low = 0xFFFF; + pdata->histogram_config__amb_thresh_high = 0xFFFF; + + + + + pdata->histogram_config__spad_array_selection = 0x00; + +} + +void VL53L1_init_histogram_multizone_config_structure( + uint8_t even_bin0, + uint8_t even_bin1, + uint8_t even_bin2, + uint8_t even_bin3, + uint8_t even_bin4, + uint8_t even_bin5, + uint8_t odd_bin0, + uint8_t odd_bin1, + uint8_t odd_bin2, + uint8_t odd_bin3, + uint8_t odd_bin4, + uint8_t odd_bin5, + VL53L1_histogram_config_t *pdata) +{ + + + + + + + + pdata->histogram_config__low_amb_even_bin_0_1 = + (even_bin1 << 4) + even_bin0; + pdata->histogram_config__low_amb_even_bin_2_3 = + (even_bin3 << 4) + even_bin2; + pdata->histogram_config__low_amb_even_bin_4_5 = + (even_bin5 << 4) + even_bin4; + + pdata->histogram_config__low_amb_odd_bin_0_1 = + pdata->histogram_config__low_amb_even_bin_0_1; + pdata->histogram_config__low_amb_odd_bin_2_3 + = pdata->histogram_config__low_amb_even_bin_2_3; + pdata->histogram_config__low_amb_odd_bin_4_5 + = pdata->histogram_config__low_amb_even_bin_4_5; + + pdata->histogram_config__mid_amb_even_bin_0_1 = + pdata->histogram_config__low_amb_even_bin_0_1; + pdata->histogram_config__mid_amb_even_bin_2_3 + = pdata->histogram_config__low_amb_even_bin_2_3; + pdata->histogram_config__mid_amb_even_bin_4_5 + = pdata->histogram_config__low_amb_even_bin_4_5; + + pdata->histogram_config__mid_amb_odd_bin_0_1 + = pdata->histogram_config__low_amb_odd_bin_0_1; + pdata->histogram_config__mid_amb_odd_bin_2 = odd_bin2; + pdata->histogram_config__mid_amb_odd_bin_3_4 = + (odd_bin4 << 4) + odd_bin3; + pdata->histogram_config__mid_amb_odd_bin_5 = odd_bin5; + + pdata->histogram_config__user_bin_offset = 0x00; + + pdata->histogram_config__high_amb_even_bin_0_1 = + (odd_bin1 << 4) + odd_bin0; + pdata->histogram_config__high_amb_even_bin_2_3 = + (odd_bin3 << 4) + odd_bin2; + pdata->histogram_config__high_amb_even_bin_4_5 = + (odd_bin5 << 4) + odd_bin4; + + pdata->histogram_config__high_amb_odd_bin_0_1 + = pdata->histogram_config__high_amb_even_bin_0_1; + pdata->histogram_config__high_amb_odd_bin_2_3 + = pdata->histogram_config__high_amb_even_bin_2_3; + pdata->histogram_config__high_amb_odd_bin_4_5 + = pdata->histogram_config__high_amb_even_bin_4_5; + + + + + pdata->histogram_config__amb_thresh_low = 0xFFFF; + pdata->histogram_config__amb_thresh_high = 0xFFFF; + + + + + pdata->histogram_config__spad_array_selection = 0x00; +} + + +void VL53L1_init_xtalk_bin_data_struct( + uint32_t bin_value, + uint16_t VL53L1_p_024, + VL53L1_xtalk_histogram_shape_t *pdata) +{ + + + + + + + uint16_t i = 0; + + pdata->zone_id = 0; + pdata->time_stamp = 0; + + pdata->VL53L1_p_022 = 0; + pdata->VL53L1_p_023 = VL53L1_XTALK_HISTO_BINS; + pdata->VL53L1_p_024 = (uint8_t)VL53L1_p_024; + + pdata->phasecal_result__reference_phase = 0; + pdata->phasecal_result__vcsel_start = 0; + pdata->cal_config__vcsel_start = 0; + + pdata->vcsel_width = 0; + pdata->VL53L1_p_019 = 0; + + pdata->zero_distance_phase = 0; + + for (i = 0; i < VL53L1_XTALK_HISTO_BINS; i++) { + if (i < VL53L1_p_024) + pdata->bin_data[i] = bin_value; + else + pdata->bin_data[i] = 0; + } +} + + +void VL53L1_i2c_encode_uint16_t( + uint16_t ip_value, + uint16_t count, + uint8_t *pbuffer) +{ + + + + + + + uint16_t i = 0; + uint16_t VL53L1_p_002 = 0; + + VL53L1_p_002 = ip_value; + + for (i = 0; i < count; i++) { + pbuffer[count-i-1] = (uint8_t)(VL53L1_p_002 & 0x00FF); + VL53L1_p_002 = VL53L1_p_002 >> 8; + } +} + +uint16_t VL53L1_i2c_decode_uint16_t( + uint16_t count, + uint8_t *pbuffer) +{ + + + + + + + uint16_t value = 0x00; + + while (count-- > 0) + value = (value << 8) | (uint16_t)*pbuffer++; + + return value; +} + + +void VL53L1_i2c_encode_int16_t( + int16_t ip_value, + uint16_t count, + uint8_t *pbuffer) +{ + + + + + + + uint16_t i = 0; + int16_t VL53L1_p_002 = 0; + + VL53L1_p_002 = ip_value; + + for (i = 0; i < count; i++) { + pbuffer[count-i-1] = (uint8_t)(VL53L1_p_002 & 0x00FF); + VL53L1_p_002 = VL53L1_p_002 >> 8; + } +} + +int16_t VL53L1_i2c_decode_int16_t( + uint16_t count, + uint8_t *pbuffer) +{ + + + + + + + int16_t value = 0x00; + + + + if (*pbuffer >= 0x80) + value = 0xFFFF; + + while (count-- > 0) + value = (value << 8) | (int16_t)*pbuffer++; + + return value; +} + +void VL53L1_i2c_encode_uint32_t( + uint32_t ip_value, + uint16_t count, + uint8_t *pbuffer) +{ + + + + + + + uint16_t i = 0; + uint32_t VL53L1_p_002 = 0; + + VL53L1_p_002 = ip_value; + + for (i = 0; i < count; i++) { + pbuffer[count-i-1] = (uint8_t)(VL53L1_p_002 & 0x00FF); + VL53L1_p_002 = VL53L1_p_002 >> 8; + } +} + +uint32_t VL53L1_i2c_decode_uint32_t( + uint16_t count, + uint8_t *pbuffer) +{ + + + + + + + uint32_t value = 0x00; + + while (count-- > 0) + value = (value << 8) | (uint32_t)*pbuffer++; + + return value; +} + + +uint32_t VL53L1_i2c_decode_with_mask( + uint16_t count, + uint8_t *pbuffer, + uint32_t bit_mask, + uint32_t down_shift, + uint32_t offset) +{ + + + + + + + uint32_t value = 0x00; + + + + while (count-- > 0) + value = (value << 8) | (uint32_t)*pbuffer++; + + + + value = value & bit_mask; + if (down_shift > 0) + value = value >> down_shift; + + + + value = value + offset; + + return value; +} + + +void VL53L1_i2c_encode_int32_t( + int32_t ip_value, + uint16_t count, + uint8_t *pbuffer) +{ + + + + + + + uint16_t i = 0; + int32_t VL53L1_p_002 = 0; + + VL53L1_p_002 = ip_value; + + for (i = 0; i < count; i++) { + pbuffer[count-i-1] = (uint8_t)(VL53L1_p_002 & 0x00FF); + VL53L1_p_002 = VL53L1_p_002 >> 8; + } +} + +int32_t VL53L1_i2c_decode_int32_t( + uint16_t count, + uint8_t *pbuffer) +{ + + + + + + + int32_t value = 0x00; + + + + if (*pbuffer >= 0x80) + value = 0xFFFFFFFF; + + while (count-- > 0) + value = (value << 8) | (int32_t)*pbuffer++; + + return value; +} + + +VL53L1_Error VL53L1_start_test( + VL53L1_DEV Dev, + uint8_t test_mode__ctrl) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) { + + status = VL53L1_WrByte( + Dev, + VL53L1_TEST_MODE__CTRL, + test_mode__ctrl); + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_firmware_enable_register( + VL53L1_DEV Dev, + uint8_t value) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + pdev->sys_ctrl.firmware__enable = value; + + status = VL53L1_WrByte( + Dev, + VL53L1_FIRMWARE__ENABLE, + pdev->sys_ctrl.firmware__enable); + + return status; +} + +VL53L1_Error VL53L1_enable_firmware( + VL53L1_DEV Dev) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + status = VL53L1_set_firmware_enable_register(Dev, 0x01); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_disable_firmware( + VL53L1_DEV Dev) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + status = VL53L1_set_firmware_enable_register(Dev, 0x00); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_powerforce_register( + VL53L1_DEV Dev, + uint8_t value) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + pdev->sys_ctrl.power_management__go1_power_force = value; + + status = VL53L1_WrByte( + Dev, + VL53L1_POWER_MANAGEMENT__GO1_POWER_FORCE, + pdev->sys_ctrl.power_management__go1_power_force); + + return status; +} + + +VL53L1_Error VL53L1_enable_powerforce( + VL53L1_DEV Dev) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + status = VL53L1_set_powerforce_register(Dev, 0x01); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_disable_powerforce( + VL53L1_DEV Dev) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + status = VL53L1_set_powerforce_register(Dev, 0x00); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_clear_interrupt( + VL53L1_DEV Dev) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + pdev->sys_ctrl.system__interrupt_clear = VL53L1_CLEAR_RANGE_INT; + + status = VL53L1_WrByte( + Dev, + VL53L1_SYSTEM__INTERRUPT_CLEAR, + pdev->sys_ctrl.system__interrupt_clear); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_force_shadow_stream_count_to_zero( + VL53L1_DEV Dev) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_disable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) { + status = VL53L1_WrByte( + Dev, + VL53L1_SHADOW_RESULT__STREAM_COUNT, + 0x00); + } + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_firmware(Dev); + + return status; +} + + +uint32_t VL53L1_calc_macro_period_us( + uint16_t fast_osc_frequency, + uint8_t VL53L1_p_009) +{ + + + + + + + + + uint32_t pll_period_us = 0; + uint8_t VL53L1_p_031 = 0; + uint32_t macro_period_us = 0; + + LOG_FUNCTION_START(""); + + + + + + + pll_period_us = VL53L1_calc_pll_period_us(fast_osc_frequency); + + + + + + + VL53L1_p_031 = VL53L1_decode_vcsel_period(VL53L1_p_009); + + + + + + + + + + + + + + + macro_period_us = + (uint32_t)VL53L1_MACRO_PERIOD_VCSEL_PERIODS * + pll_period_us; + macro_period_us = macro_period_us >> 6; + + macro_period_us = macro_period_us * (uint32_t)VL53L1_p_031; + macro_period_us = macro_period_us >> 6; + + + + + + + + + + + + + + LOG_FUNCTION_END(0); + + return macro_period_us; +} + + +uint16_t VL53L1_calc_range_ignore_threshold( + uint32_t central_rate, + int16_t x_gradient, + int16_t y_gradient, + uint8_t rate_mult) +{ + + + + + + + + + + + + + + + + int32_t range_ignore_thresh_int = 0; + uint16_t range_ignore_thresh_kcps = 0; + int32_t central_rate_int = 0; + int16_t x_gradient_int = 0; + int16_t y_gradient_int = 0; + + LOG_FUNCTION_START(""); + + + + + central_rate_int = ((int32_t)central_rate * (1 << 4)) / (1000); + + if (x_gradient < 0) + x_gradient_int = x_gradient * -1; + + if (y_gradient < 0) + y_gradient_int = y_gradient * -1; + + + + + + + + + range_ignore_thresh_int = (8 * x_gradient_int * 4) + + (8 * y_gradient_int * 4); + + + + + range_ignore_thresh_int = range_ignore_thresh_int / 1000; + + + + + range_ignore_thresh_int = range_ignore_thresh_int + central_rate_int; + + + + + range_ignore_thresh_int = (int32_t)rate_mult * range_ignore_thresh_int; + + range_ignore_thresh_int = (range_ignore_thresh_int + (1<<4)) / (1<<5); + + + + + if (range_ignore_thresh_int > 0xFFFF) + range_ignore_thresh_kcps = 0xFFFF; + else + range_ignore_thresh_kcps = (uint16_t)range_ignore_thresh_int; + + + + + + + + LOG_FUNCTION_END(0); + + return range_ignore_thresh_kcps; +} + + +uint32_t VL53L1_calc_timeout_mclks( + uint32_t timeout_us, + uint32_t macro_period_us) +{ + + + + + + + + + + + uint32_t timeout_mclks = 0; + + LOG_FUNCTION_START(""); + + timeout_mclks = + ((timeout_us << 12) + (macro_period_us>>1)) / + macro_period_us; + + LOG_FUNCTION_END(0); + + return timeout_mclks; +} + + +uint16_t VL53L1_calc_encoded_timeout( + uint32_t timeout_us, + uint32_t macro_period_us) +{ + + + + + + + + + + + uint32_t timeout_mclks = 0; + uint16_t timeout_encoded = 0; + + LOG_FUNCTION_START(""); + + timeout_mclks = + VL53L1_calc_timeout_mclks(timeout_us, macro_period_us); + + timeout_encoded = + VL53L1_encode_timeout(timeout_mclks); + + + + + + + + + + + LOG_FUNCTION_END(0); + + return timeout_encoded; +} + + +uint32_t VL53L1_calc_timeout_us( + uint32_t timeout_mclks, + uint32_t macro_period_us) +{ + + + + + + + + + + + uint32_t timeout_us = 0; + uint64_t tmp = 0; + + LOG_FUNCTION_START(""); + + tmp = (uint64_t)timeout_mclks * (uint64_t)macro_period_us; + tmp += 0x00800; + tmp = tmp >> 12; + + timeout_us = (uint32_t)tmp; + + + + + + + + + + + + LOG_FUNCTION_END(0); + + return timeout_us; +} + +uint32_t VL53L1_calc_crosstalk_plane_offset_with_margin( + uint32_t plane_offset_kcps, + int16_t margin_offset_kcps) +{ + uint32_t plane_offset_with_margin = 0; + int32_t plane_offset_kcps_temp = 0; + + LOG_FUNCTION_START(""); + + plane_offset_kcps_temp = + (int32_t)plane_offset_kcps + + (int32_t)margin_offset_kcps; + + if (plane_offset_kcps_temp < 0) + plane_offset_kcps_temp = 0; + else + if (plane_offset_kcps_temp > 0x3FFFF) + plane_offset_kcps_temp = 0x3FFFF; + + plane_offset_with_margin = (uint32_t) plane_offset_kcps_temp; + + LOG_FUNCTION_END(0); + + return plane_offset_with_margin; + +} + +uint32_t VL53L1_calc_decoded_timeout_us( + uint16_t timeout_encoded, + uint32_t macro_period_us) +{ + + + + + + + + + + + uint32_t timeout_mclks = 0; + uint32_t timeout_us = 0; + + LOG_FUNCTION_START(""); + + timeout_mclks = + VL53L1_decode_timeout(timeout_encoded); + + timeout_us = + VL53L1_calc_timeout_us(timeout_mclks, macro_period_us); + + LOG_FUNCTION_END(0); + + return timeout_us; +} + + +uint16_t VL53L1_encode_timeout(uint32_t timeout_mclks) +{ + + + + + + uint16_t encoded_timeout = 0; + uint32_t ls_byte = 0; + uint16_t ms_byte = 0; + + if (timeout_mclks > 0) { + ls_byte = timeout_mclks - 1; + + while ((ls_byte & 0xFFFFFF00) > 0) { + ls_byte = ls_byte >> 1; + ms_byte++; + } + + encoded_timeout = (ms_byte << 8) + + (uint16_t) (ls_byte & 0x000000FF); + } + + return encoded_timeout; +} + + +uint32_t VL53L1_decode_timeout(uint16_t encoded_timeout) +{ + + + + + + + uint32_t timeout_macro_clks = 0; + + timeout_macro_clks = ((uint32_t) (encoded_timeout & 0x00FF) + << (uint32_t) ((encoded_timeout & 0xFF00) >> 8)) + 1; + + return timeout_macro_clks; +} + + +VL53L1_Error VL53L1_calc_timeout_register_values( + uint32_t phasecal_config_timeout_us, + uint32_t mm_config_timeout_us, + uint32_t range_config_timeout_us, + uint16_t fast_osc_frequency, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming) +{ + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + uint32_t macro_period_us = 0; + uint32_t timeout_mclks = 0; + uint16_t timeout_encoded = 0; + + LOG_FUNCTION_START(""); + + if (fast_osc_frequency == 0) { + status = VL53L1_ERROR_DIVISION_BY_ZERO; + } else { + + + macro_period_us = + VL53L1_calc_macro_period_us( + fast_osc_frequency, + ptiming->range_config__vcsel_period_a); + + + + timeout_mclks = + VL53L1_calc_timeout_mclks( + phasecal_config_timeout_us, + macro_period_us); + + + + if (timeout_mclks > 0xFF) + timeout_mclks = 0xFF; + + pgeneral->phasecal_config__timeout_macrop = + (uint8_t)timeout_mclks; + + + + timeout_encoded = + VL53L1_calc_encoded_timeout( + mm_config_timeout_us, + macro_period_us); + + ptiming->mm_config__timeout_macrop_a_hi = + (uint8_t)((timeout_encoded & 0xFF00) >> 8); + ptiming->mm_config__timeout_macrop_a_lo = + (uint8_t) (timeout_encoded & 0x00FF); + + + + timeout_encoded = + VL53L1_calc_encoded_timeout( + range_config_timeout_us, + macro_period_us); + + ptiming->range_config__timeout_macrop_a_hi = + (uint8_t)((timeout_encoded & 0xFF00) >> 8); + ptiming->range_config__timeout_macrop_a_lo = + (uint8_t) (timeout_encoded & 0x00FF); + + + + macro_period_us = + VL53L1_calc_macro_period_us( + fast_osc_frequency, + ptiming->range_config__vcsel_period_b); + + + + timeout_encoded = + VL53L1_calc_encoded_timeout( + mm_config_timeout_us, + macro_period_us); + + ptiming->mm_config__timeout_macrop_b_hi = + (uint8_t)((timeout_encoded & 0xFF00) >> 8); + ptiming->mm_config__timeout_macrop_b_lo = + (uint8_t) (timeout_encoded & 0x00FF); + + + + timeout_encoded = VL53L1_calc_encoded_timeout( + range_config_timeout_us, + macro_period_us); + + ptiming->range_config__timeout_macrop_b_hi = + (uint8_t)((timeout_encoded & 0xFF00) >> 8); + ptiming->range_config__timeout_macrop_b_lo = + (uint8_t) (timeout_encoded & 0x00FF); + } + + LOG_FUNCTION_END(0); + + return status; + +} + + +uint8_t VL53L1_encode_vcsel_period(uint8_t VL53L1_p_031) +{ + + + + + + + uint8_t vcsel_period_reg = 0; + + vcsel_period_reg = (VL53L1_p_031 >> 1) - 1; + + return vcsel_period_reg; +} + + +uint32_t VL53L1_decode_unsigned_integer( + uint8_t *pbuffer, + uint8_t no_of_bytes) +{ + + + + + + uint8_t i = 0; + uint32_t decoded_value = 0; + + for (i = 0; i < no_of_bytes; i++) + decoded_value = (decoded_value << 8) + (uint32_t)pbuffer[i]; + + return decoded_value; +} + + +void VL53L1_encode_unsigned_integer( + uint32_t ip_value, + uint8_t no_of_bytes, + uint8_t *pbuffer) +{ + + + + + + uint8_t i = 0; + uint32_t VL53L1_p_002 = 0; + + VL53L1_p_002 = ip_value; + for (i = 0; i < no_of_bytes; i++) { + pbuffer[no_of_bytes-i-1] = VL53L1_p_002 & 0x00FF; + VL53L1_p_002 = VL53L1_p_002 >> 8; + } +} + + +VL53L1_Error VL53L1_hist_copy_and_scale_ambient_info( + VL53L1_zone_hist_info_t *pidata, + VL53L1_histogram_bin_data_t *podata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + int64_t VL53L1_p_008 = 0; + int64_t tmpi = 0; + int64_t tmpo = 0; + + LOG_FUNCTION_START(""); + + + if (pidata->result__dss_actual_effective_spads == 0) { + status = VL53L1_ERROR_DIVISION_BY_ZERO; + } else { + if (pidata->number_of_ambient_bins > 0 && + podata->number_of_ambient_bins == 0) { + + + + + + + + + + + tmpo = 1 + (int64_t)podata->total_periods_elapsed; + tmpo *= + (int64_t)podata->result__dss_actual_effective_spads; + + tmpi = 1 + (int64_t)pidata->total_periods_elapsed; + tmpi *= + (int64_t)pidata->result__dss_actual_effective_spads; + + VL53L1_p_008 = tmpo * + (int64_t)pidata->ambient_events_sum; + VL53L1_p_008 += (tmpi/2); + + + + + VL53L1_p_008 = do_division_s(VL53L1_p_008, tmpi); + + podata->ambient_events_sum = (int32_t)VL53L1_p_008; + + + + + + + podata->VL53L1_p_004 = + podata->ambient_events_sum; + podata->VL53L1_p_004 += + ((int32_t)pidata->number_of_ambient_bins / 2); + podata->VL53L1_p_004 /= + (int32_t)pidata->number_of_ambient_bins; + } + } + + LOG_FUNCTION_END(0); + + return status; +} + + +void VL53L1_hist_get_bin_sequence_config( + VL53L1_DEV Dev, + VL53L1_histogram_bin_data_t *pdata) +{ + + + + + + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + int32_t amb_thresh_low = 0; + int32_t amb_thresh_high = 0; + + uint8_t i = 0; + + LOG_FUNCTION_START(""); + + + + + amb_thresh_low = 1024 * + (int32_t)pdev->hist_cfg.histogram_config__amb_thresh_low; + amb_thresh_high = 1024 * + (int32_t)pdev->hist_cfg.histogram_config__amb_thresh_high; + + + + + + + + + + + if ((pdev->ll_state.rd_stream_count & 0x01) == 0) { + + pdata->bin_seq[5] = + pdev->hist_cfg.histogram_config__mid_amb_even_bin_4_5 >> 4; + pdata->bin_seq[4] = + pdev->hist_cfg.histogram_config__mid_amb_even_bin_4_5 & 0x0F; + pdata->bin_seq[3] = + pdev->hist_cfg.histogram_config__mid_amb_even_bin_2_3 >> 4; + pdata->bin_seq[2] = + pdev->hist_cfg.histogram_config__mid_amb_even_bin_2_3 & 0x0F; + pdata->bin_seq[1] = + pdev->hist_cfg.histogram_config__mid_amb_even_bin_0_1 >> 4; + pdata->bin_seq[0] = + pdev->hist_cfg.histogram_config__mid_amb_even_bin_0_1 & 0x0F; + + if (pdata->ambient_events_sum > amb_thresh_high) { + pdata->bin_seq[5] = + pdev->hist_cfg.histogram_config__high_amb_even_bin_4_5 + >> 4; + pdata->bin_seq[4] = + pdev->hist_cfg.histogram_config__high_amb_even_bin_4_5 + & 0x0F; + pdata->bin_seq[3] = + pdev->hist_cfg.histogram_config__high_amb_even_bin_2_3 + >> 4; + pdata->bin_seq[2] = + pdev->hist_cfg.histogram_config__high_amb_even_bin_2_3 + & 0x0F; + pdata->bin_seq[1] = + pdev->hist_cfg.histogram_config__high_amb_even_bin_0_1 + >> 4; + pdata->bin_seq[0] = + pdev->hist_cfg.histogram_config__high_amb_even_bin_0_1 + & 0x0F; + } + + if (pdata->ambient_events_sum < amb_thresh_low) { + pdata->bin_seq[5] = + pdev->hist_cfg.histogram_config__low_amb_even_bin_4_5 + >> 4; + pdata->bin_seq[4] = + pdev->hist_cfg.histogram_config__low_amb_even_bin_4_5 + & 0x0F; + pdata->bin_seq[3] = + pdev->hist_cfg.histogram_config__low_amb_even_bin_2_3 + >> 4; + pdata->bin_seq[2] = + pdev->hist_cfg.histogram_config__low_amb_even_bin_2_3 + & 0x0F; + pdata->bin_seq[1] = + pdev->hist_cfg.histogram_config__low_amb_even_bin_0_1 + >> 4; + pdata->bin_seq[0] = + pdev->hist_cfg.histogram_config__low_amb_even_bin_0_1 + & 0x0F; + } + + } else { + pdata->bin_seq[5] = + pdev->hist_cfg.histogram_config__mid_amb_odd_bin_5 + & 0x0F; + pdata->bin_seq[4] = + pdev->hist_cfg.histogram_config__mid_amb_odd_bin_3_4 + & 0x0F; + pdata->bin_seq[3] = + pdev->hist_cfg.histogram_config__mid_amb_odd_bin_3_4 + >> 4; + pdata->bin_seq[2] = + pdev->hist_cfg.histogram_config__mid_amb_odd_bin_2 & + 0x0F; + pdata->bin_seq[1] = + pdev->hist_cfg.histogram_config__mid_amb_odd_bin_0_1 + >> 4; + pdata->bin_seq[0] = + pdev->hist_cfg.histogram_config__mid_amb_odd_bin_0_1 + & 0x0F; + + if (pdata->ambient_events_sum > amb_thresh_high) { + pdata->bin_seq[5] = + pdev->hist_cfg.histogram_config__high_amb_odd_bin_4_5 + >> 4; + pdata->bin_seq[4] = + pdev->hist_cfg.histogram_config__high_amb_odd_bin_4_5 + & 0x0F; + pdata->bin_seq[3] = + pdev->hist_cfg.histogram_config__high_amb_odd_bin_2_3 + >> 4; + pdata->bin_seq[2] = + pdev->hist_cfg.histogram_config__high_amb_odd_bin_2_3 + & 0x0F; + pdata->bin_seq[1] = + pdev->hist_cfg.histogram_config__high_amb_odd_bin_0_1 + >> 4; + pdata->bin_seq[0] = + pdev->hist_cfg.histogram_config__high_amb_odd_bin_0_1 + & 0x0F; + } + + if (pdata->ambient_events_sum < amb_thresh_low) { + pdata->bin_seq[5] = + pdev->hist_cfg.histogram_config__low_amb_odd_bin_4_5 + >> 4; + pdata->bin_seq[4] = + pdev->hist_cfg.histogram_config__low_amb_odd_bin_4_5 + & 0x0F; + pdata->bin_seq[3] = + pdev->hist_cfg.histogram_config__low_amb_odd_bin_2_3 + >> 4; + pdata->bin_seq[2] = + pdev->hist_cfg.histogram_config__low_amb_odd_bin_2_3 + & 0x0F; + pdata->bin_seq[1] = + pdev->hist_cfg.histogram_config__low_amb_odd_bin_0_1 + >> 4; + pdata->bin_seq[0] = + pdev->hist_cfg.histogram_config__low_amb_odd_bin_0_1 + & 0x0F; + } + } + + + + + for (i = 0; i < VL53L1_MAX_BIN_SEQUENCE_LENGTH; i++) + pdata->bin_rep[i] = 1; + + LOG_FUNCTION_END(0); + +} + + +VL53L1_Error VL53L1_hist_phase_consistency_check( + VL53L1_DEV Dev, + VL53L1_zone_hist_info_t *phist_prev, + VL53L1_zone_objects_t *prange_prev, + VL53L1_range_results_t *prange_curr) +{ + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + + uint8_t lc = 0; + uint8_t p = 0; + + uint16_t phase_delta = 0; + uint16_t phase_tolerance = 0; + + int32_t events_delta = 0; + int32_t events_tolerance = 0; + + + + uint8_t event_sigma; + uint16_t event_min_spad_count; + uint16_t min_max_tolerance; + uint8_t pht; + + VL53L1_DeviceError range_status = 0; + + LOG_FUNCTION_START(""); + + event_sigma = + pdev->histpostprocess.algo__consistency_check__event_sigma; + event_min_spad_count = + pdev->histpostprocess.algo__consistency_check__event_min_spad_count; + min_max_tolerance = + pdev->histpostprocess.algo__consistency_check__min_max_tolerance; + + + + pht = pdev->histpostprocess.algo__consistency_check__phase_tolerance; + phase_tolerance = (uint16_t)pht; + phase_tolerance = phase_tolerance << 8; + + + + + if (prange_prev->rd_device_state != + VL53L1_DEVICESTATE_RANGING_GATHER_DATA && + prange_prev->rd_device_state != + VL53L1_DEVICESTATE_RANGING_OUTPUT_DATA) + return status; + + + + + if (phase_tolerance == 0) + return status; + + for (lc = 0; lc < prange_curr->active_results; lc++) { + + if (!((prange_curr->VL53L1_p_002[lc].range_status == + VL53L1_DEVICEERROR_RANGECOMPLETE) || + (prange_curr->VL53L1_p_002[lc].range_status == + VL53L1_DEVICEERROR_RANGECOMPLETE_NO_WRAP_CHECK))) + continue; + + + + + + + + + if (prange_prev->active_objects == 0) + prange_curr->VL53L1_p_002[lc].range_status = + VL53L1_DEVICEERROR_PREV_RANGE_NO_TARGETS; + else + prange_curr->VL53L1_p_002[lc].range_status = + VL53L1_DEVICEERROR_PHASECONSISTENCY; + + + + + + + + + + + for (p = 0; p < prange_prev->active_objects; p++) { + + if (prange_curr->VL53L1_p_002[lc].VL53L1_p_014 > + prange_prev->VL53L1_p_002[p].VL53L1_p_014) { + phase_delta = + prange_curr->VL53L1_p_002[lc].VL53L1_p_014 - + prange_prev->VL53L1_p_002[p].VL53L1_p_014; + } else { + phase_delta = + prange_prev->VL53L1_p_002[p].VL53L1_p_014 - + prange_curr->VL53L1_p_002[lc].VL53L1_p_014; + } + + if (phase_delta < phase_tolerance) { + + + + + + + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_hist_events_consistency_check( + event_sigma, + event_min_spad_count, + phist_prev, + &(prange_prev->VL53L1_p_002[p]), + &(prange_curr->VL53L1_p_002[lc]), + &events_tolerance, + &events_delta, + &range_status); + + + + + + + + + + if (status == VL53L1_ERROR_NONE && + range_status == + VL53L1_DEVICEERROR_RANGECOMPLETE) + status = + VL53L1_hist_merged_pulse_check( + min_max_tolerance, + &(prange_curr->VL53L1_p_002[lc]), + &range_status); + + prange_curr->VL53L1_p_002[lc].range_status = + range_status; + } + } + + } + + LOG_FUNCTION_END(status); + + return status; +} + + + + +VL53L1_Error VL53L1_hist_events_consistency_check( + uint8_t event_sigma, + uint16_t min_effective_spad_count, + VL53L1_zone_hist_info_t *phist_prev, + VL53L1_object_data_t *prange_prev, + VL53L1_range_data_t *prange_curr, + int32_t *pevents_tolerance, + int32_t *pevents_delta, + VL53L1_DeviceError *prange_status) +{ + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + int64_t tmpp = 0; + int64_t tmpc = 0; + int64_t events_scaler = 0; + int64_t events_scaler_sq = 0; + int64_t c_signal_events = 0; + int64_t c_sig_noise_sq = 0; + int64_t c_amb_noise_sq = 0; + int64_t p_amb_noise_sq = 0; + + int32_t p_signal_events = 0; + uint32_t noise_sq_sum = 0; + + + + + if (event_sigma == 0) { + *prange_status = VL53L1_DEVICEERROR_RANGECOMPLETE; + return status; + } + + + + + tmpp = 1 + (int64_t)phist_prev->total_periods_elapsed; + tmpp *= (int64_t)phist_prev->result__dss_actual_effective_spads; + + + + + tmpc = 1 + (int64_t)prange_curr->total_periods_elapsed; + tmpc *= (int64_t)prange_curr->VL53L1_p_006; + + + + + events_scaler = tmpp * 4096; + events_scaler += (tmpc/2); + events_scaler = do_division_s(events_scaler, tmpc); + + events_scaler_sq = events_scaler * events_scaler; + events_scaler_sq += 2048; + events_scaler_sq /= 4096; + + + + + c_signal_events = (int64_t)prange_curr->VL53L1_p_021; + c_signal_events -= (int64_t)prange_curr->VL53L1_p_020; + c_signal_events *= (int64_t)events_scaler; + c_signal_events += 2048; + c_signal_events /= 4096; + + c_sig_noise_sq = (int64_t)events_scaler_sq; + c_sig_noise_sq *= (int64_t)prange_curr->VL53L1_p_021; + c_sig_noise_sq += 2048; + c_sig_noise_sq /= 4096; + + c_amb_noise_sq = (int64_t)events_scaler_sq; + c_amb_noise_sq *= (int64_t)prange_curr->VL53L1_p_020; + c_amb_noise_sq += 2048; + c_amb_noise_sq /= 4096; + + + + c_amb_noise_sq += 2; + c_amb_noise_sq /= 4; + + + + + + + + p_amb_noise_sq = + (int64_t)prange_prev->VL53L1_p_020; + + + + p_amb_noise_sq += 2; + p_amb_noise_sq /= 4; + + noise_sq_sum = + (uint32_t)prange_prev->VL53L1_p_021 + + (uint32_t)c_sig_noise_sq + + (uint32_t)p_amb_noise_sq + + (uint32_t)c_amb_noise_sq; + + *pevents_tolerance = + (int32_t)VL53L1_isqrt(noise_sq_sum * 16); + + *pevents_tolerance *= (int32_t)event_sigma; + *pevents_tolerance += 32; + *pevents_tolerance /= 64; + + p_signal_events = (int32_t)prange_prev->VL53L1_p_021; + p_signal_events -= (int32_t)prange_prev->VL53L1_p_020; + + if ((int32_t)c_signal_events > p_signal_events) + *pevents_delta = + (int32_t)c_signal_events - p_signal_events; + else + *pevents_delta = + p_signal_events - (int32_t)c_signal_events; + + if (*pevents_delta > *pevents_tolerance && + prange_curr->VL53L1_p_006 > min_effective_spad_count) + *prange_status = VL53L1_DEVICEERROR_EVENTCONSISTENCY; + else + *prange_status = VL53L1_DEVICEERROR_RANGECOMPLETE; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + return status; +} + + + + + +VL53L1_Error VL53L1_hist_merged_pulse_check( + int16_t min_max_tolerance_mm, + VL53L1_range_data_t *pdata, + VL53L1_DeviceError *prange_status) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + int16_t delta_mm = 0; + + if (pdata->max_range_mm > pdata->min_range_mm) + delta_mm = + pdata->max_range_mm - pdata->min_range_mm; + else + delta_mm = + pdata->min_range_mm - pdata->max_range_mm; + + if (min_max_tolerance_mm > 0 && + delta_mm > min_max_tolerance_mm) + *prange_status = VL53L1_DEVICEERROR_RANGECOMPLETE_MERGED_PULSE; + else + *prange_status = VL53L1_DEVICEERROR_RANGECOMPLETE; + + return status; +} + + + + + +VL53L1_Error VL53L1_hist_xmonitor_consistency_check( + VL53L1_DEV Dev, + VL53L1_zone_hist_info_t *phist_prev, + VL53L1_zone_objects_t *prange_prev, + VL53L1_range_data_t *prange_curr) +{ + + + + + + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + + int32_t events_delta = 0; + int32_t events_tolerance = 0; + uint8_t event_sigma; + uint16_t min_spad_count; + + event_sigma = pdev->histpostprocess.algo__crosstalk_detect_event_sigma; + min_spad_count = + pdev->histpostprocess.algo__consistency_check__event_min_spad_count; + + if (prange_curr->range_status == VL53L1_DEVICEERROR_RANGECOMPLETE || + prange_curr->range_status == + VL53L1_DEVICEERROR_RANGECOMPLETE_NO_WRAP_CHECK || + prange_curr->range_status == + VL53L1_DEVICEERROR_EVENTCONSISTENCY) { + + if (prange_prev->xmonitor.range_status == + VL53L1_DEVICEERROR_RANGECOMPLETE || + prange_prev->xmonitor.range_status == + VL53L1_DEVICEERROR_RANGECOMPLETE_NO_WRAP_CHECK || + prange_prev->xmonitor.range_status == + VL53L1_DEVICEERROR_EVENTCONSISTENCY) { + + prange_curr->range_status = + VL53L1_DEVICEERROR_RANGECOMPLETE; + + status = + VL53L1_hist_events_consistency_check( + event_sigma, + min_spad_count, + phist_prev, + &(prange_prev->xmonitor), + prange_curr, + &events_tolerance, + &events_delta, + &(prange_curr->range_status)); + + } + } + + return status; +} + + + + + +VL53L1_Error VL53L1_hist_wrap_dmax( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_histogram_bin_data_t *pcurrent, + int16_t *pwrap_dmax_mm) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + uint32_t pll_period_mm = 0; + uint32_t wrap_dmax_phase = 0; + uint32_t range_mm = 0; + + LOG_FUNCTION_START(""); + + *pwrap_dmax_mm = 0; + + + if (pcurrent->VL53L1_p_019 != 0) { + + + + + pll_period_mm = + VL53L1_calc_pll_period_mm( + pcurrent->VL53L1_p_019); + + + + + wrap_dmax_phase = + (uint32_t)phistpostprocess->valid_phase_high << 8; + + + + + + range_mm = wrap_dmax_phase * pll_period_mm; + range_mm = (range_mm + (1<<14)) >> 15; + + *pwrap_dmax_mm = (int16_t)range_mm; + } + + LOG_FUNCTION_END(status); + + return status; +} + + +void VL53L1_hist_combine_mm1_mm2_offsets( + int16_t mm1_offset_mm, + int16_t mm2_offset_mm, + uint8_t encoded_mm_roi_centre, + uint8_t encoded_mm_roi_size, + uint8_t encoded_zone_centre, + uint8_t encoded_zone_size, + VL53L1_additional_offset_cal_data_t *pcal_data, + uint8_t *pgood_spads, + uint16_t aperture_attenuation, + int16_t *prange_offset_mm) +{ + + + + + + + + + + + + + + + + uint16_t max_mm_inner_effective_spads = 0; + uint16_t max_mm_outer_effective_spads = 0; + uint16_t mm_inner_effective_spads = 0; + uint16_t mm_outer_effective_spads = 0; + + uint32_t scaled_mm1_peak_rate_mcps = 0; + uint32_t scaled_mm2_peak_rate_mcps = 0; + + int32_t tmp0 = 0; + int32_t tmp1 = 0; + + + + + VL53L1_calc_mm_effective_spads( + encoded_mm_roi_centre, + encoded_mm_roi_size, + 0xC7, + + 0xFF, + pgood_spads, + aperture_attenuation, + &max_mm_inner_effective_spads, + &max_mm_outer_effective_spads); + + + + + VL53L1_calc_mm_effective_spads( + encoded_mm_roi_centre, + encoded_mm_roi_size, + encoded_zone_centre, + encoded_zone_size, + pgood_spads, + aperture_attenuation, + &mm_inner_effective_spads, + &mm_outer_effective_spads); + + + + + scaled_mm1_peak_rate_mcps = + (uint32_t)pcal_data->result__mm_inner_peak_signal_count_rtn_mcps; + scaled_mm1_peak_rate_mcps *= (uint32_t)mm_inner_effective_spads; + scaled_mm1_peak_rate_mcps /= (uint32_t)max_mm_inner_effective_spads; + + scaled_mm2_peak_rate_mcps = + (uint32_t)pcal_data->result__mm_outer_peak_signal_count_rtn_mcps; + scaled_mm2_peak_rate_mcps *= (uint32_t)mm_outer_effective_spads; + scaled_mm2_peak_rate_mcps /= (uint32_t)max_mm_outer_effective_spads; + + + + + tmp0 = ((int32_t)mm1_offset_mm * (int32_t)scaled_mm1_peak_rate_mcps); + tmp0 += ((int32_t)mm2_offset_mm * (int32_t)scaled_mm2_peak_rate_mcps); + + tmp1 = (int32_t)scaled_mm1_peak_rate_mcps + + (int32_t)scaled_mm2_peak_rate_mcps; + + + + + + + if (tmp1 != 0) + tmp0 = (tmp0 * 4) / tmp1; + + *prange_offset_mm = (int16_t)tmp0; + +} + + +VL53L1_Error VL53L1_hist_xtalk_extract_calc_window( + int16_t target_distance_mm, + uint16_t target_width_oversize, + VL53L1_histogram_bin_data_t *phist_bins, + VL53L1_hist_xtalk_extract_data_t *pxtalk_data) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + pxtalk_data->pll_period_mm = + VL53L1_calc_pll_period_mm(phist_bins->VL53L1_p_019); + + + + pxtalk_data->xtalk_width_phase = + (int32_t)phist_bins->vcsel_width * 128; + pxtalk_data->target_width_phase = + pxtalk_data->xtalk_width_phase + + (int32_t)target_width_oversize * 128; + + + + + + + + pxtalk_data->xtalk_start_phase = + (int32_t)phist_bins->zero_distance_phase - + (pxtalk_data->xtalk_width_phase / 2); + pxtalk_data->xtalk_end_phase = + (int32_t)pxtalk_data->xtalk_start_phase + + pxtalk_data->xtalk_width_phase; + + if (pxtalk_data->xtalk_start_phase < 0) + pxtalk_data->xtalk_start_phase = 0; + + + + + + + + + pxtalk_data->VL53L1_p_015 = + (uint8_t)(pxtalk_data->xtalk_start_phase / 2048); + + + + pxtalk_data->VL53L1_p_016 = + (uint8_t)((pxtalk_data->xtalk_end_phase + 2047) / 2048); + + + + + + + + pxtalk_data->target_start_phase = + (int32_t)target_distance_mm * 2048 * 16; + pxtalk_data->target_start_phase += + ((int32_t)pxtalk_data->pll_period_mm / 2); + pxtalk_data->target_start_phase /= (int32_t)pxtalk_data->pll_period_mm; + pxtalk_data->target_start_phase += + (int32_t)phist_bins->zero_distance_phase; + + + + + + + pxtalk_data->target_start_phase -= + (pxtalk_data->target_width_phase / 2); + pxtalk_data->target_end_phase = + (int32_t)pxtalk_data->target_start_phase + + pxtalk_data->target_width_phase; + + if (pxtalk_data->target_start_phase < 0) + pxtalk_data->target_start_phase = 0; + + + + pxtalk_data->target_start = + (uint8_t)(pxtalk_data->target_start_phase / 2048); + + + + if (pxtalk_data->VL53L1_p_016 > (pxtalk_data->target_start-1)) + pxtalk_data->VL53L1_p_016 = pxtalk_data->target_start-1; + + + + pxtalk_data->effective_width = + (2048 * ((int32_t)pxtalk_data->VL53L1_p_016+1)); + pxtalk_data->effective_width -= pxtalk_data->xtalk_start_phase; + + + + + + if (pxtalk_data->effective_width > pxtalk_data->xtalk_width_phase) + pxtalk_data->effective_width = pxtalk_data->xtalk_width_phase; + + if (pxtalk_data->effective_width < 1) + pxtalk_data->effective_width = 1; + + + + pxtalk_data->event_scaler = pxtalk_data->xtalk_width_phase * 1000; + pxtalk_data->event_scaler += (pxtalk_data->effective_width / 2); + pxtalk_data->event_scaler /= pxtalk_data->effective_width; + + + + + + if (pxtalk_data->event_scaler < 1000) + pxtalk_data->event_scaler = 1000; + + if (pxtalk_data->event_scaler > 4000) + pxtalk_data->event_scaler = 4000; + + + + pxtalk_data->event_scaler_sum += pxtalk_data->event_scaler; + + + + pxtalk_data->peak_duration_us_sum += + (uint32_t)phist_bins->peak_duration_us; + + + + pxtalk_data->effective_spad_count_sum += + (uint32_t)phist_bins->result__dss_actual_effective_spads; + + + + pxtalk_data->zero_distance_phase_sum += + (uint32_t)phist_bins->zero_distance_phase; + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_hist_xtalk_extract_calc_event_sums( + VL53L1_histogram_bin_data_t *phist_bins, + VL53L1_hist_xtalk_extract_data_t *pxtalk_data) +{ + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + uint8_t lb = 0; + uint8_t i = 0; + + LOG_FUNCTION_START(""); + + + + + for (lb = pxtalk_data->VL53L1_p_015; + lb <= pxtalk_data->VL53L1_p_016; + lb++) { + + + + i = (lb + phist_bins->number_of_ambient_bins + + phist_bins->VL53L1_p_024) % + phist_bins->VL53L1_p_024; + + + + pxtalk_data->signal_events_sum += phist_bins->bin_data[i]; + pxtalk_data->signal_events_sum -= + phist_bins->VL53L1_p_004; + } + + + + + for (lb = 0; lb < VL53L1_XTALK_HISTO_BINS && + lb < phist_bins->VL53L1_p_024; lb++) { + + + + i = (lb + phist_bins->number_of_ambient_bins + + phist_bins->VL53L1_p_024) % + phist_bins->VL53L1_p_024; + + + + pxtalk_data->bin_data_sums[lb] += phist_bins->bin_data[i]; + pxtalk_data->bin_data_sums[lb] -= + phist_bins->VL53L1_p_004; + } + + pxtalk_data->sample_count += 1; + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_hist_xtalk_extract_calc_rate_per_spad( + VL53L1_hist_xtalk_extract_data_t *pxtalk_data) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + uint64_t tmp64_0 = 0; + uint64_t tmp64_1 = 0; + uint64_t xtalk_per_spad = 0; + + LOG_FUNCTION_START(""); + + + + + + + + + + + + + + + + + + tmp64_0 = + ((uint64_t)pxtalk_data->signal_events_sum * + (uint64_t)pxtalk_data->sample_count * + (uint64_t)pxtalk_data->event_scaler_avg * 256U) << 9U; + tmp64_1 = + (uint64_t)pxtalk_data->effective_spad_count_sum * + (uint64_t)pxtalk_data->peak_duration_us_sum; + + + + + if (tmp64_1 > 0U) { + + + tmp64_0 = tmp64_0 + (tmp64_1 >> 1U); + xtalk_per_spad = do_division_u(tmp64_0, tmp64_1); + } else { + xtalk_per_spad = (uint64_t)tmp64_0; + } + + pxtalk_data->xtalk_rate_kcps_per_spad = (uint32_t)xtalk_per_spad; + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_hist_xtalk_extract_calc_shape( + VL53L1_hist_xtalk_extract_data_t *pxtalk_data, + VL53L1_xtalk_histogram_shape_t *pxtalk_shape) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + int32_t lb = 0; + uint64_t total_events = 0U; + uint64_t tmp64_0 = 0U; + int32_t remaining_area = 1024; + + LOG_FUNCTION_START(""); + + + + + pxtalk_shape->VL53L1_p_022 = 0; + pxtalk_shape->VL53L1_p_023 = VL53L1_XTALK_HISTO_BINS; + pxtalk_shape->VL53L1_p_024 = VL53L1_XTALK_HISTO_BINS; + + pxtalk_shape->zero_distance_phase = + (uint16_t)pxtalk_data->zero_distance_phase_avg; + pxtalk_shape->phasecal_result__reference_phase = + (uint16_t)pxtalk_data->zero_distance_phase_avg + (3*2048); + + + + + if (pxtalk_data->signal_events_sum > 0) + total_events = + (uint64_t)pxtalk_data->signal_events_sum * + (uint64_t)pxtalk_data->event_scaler_avg; + else + total_events = 1; + + + + remaining_area = 1024; + pxtalk_data->max_shape_value = 0; + + for (lb = 0; lb < VL53L1_XTALK_HISTO_BINS; lb++) { + + if ((lb < (int32_t)pxtalk_data->VL53L1_p_015 || + lb > (int32_t)pxtalk_data->VL53L1_p_016) || + pxtalk_data->bin_data_sums[lb] < 0) { + + + + + + + if (remaining_area > 0 && remaining_area < 1024) { + if (remaining_area > + pxtalk_data->max_shape_value) { + pxtalk_shape->bin_data[lb] = + (uint32_t)pxtalk_data->max_shape_value; + remaining_area -= + pxtalk_data->max_shape_value; + } else { + pxtalk_shape->bin_data[lb] = + (uint32_t)remaining_area; + remaining_area = 0; + } + } else { + pxtalk_shape->bin_data[lb] = 0; + } + + } else { + + + + + tmp64_0 = + (uint64_t)pxtalk_data->bin_data_sums[lb] + * 1024U * 1000U; + tmp64_0 += (total_events >> 1); + tmp64_0 = do_division_u(tmp64_0, total_events); + if (tmp64_0 > 0xFFFFU) + tmp64_0 = 0xFFFFU; + + pxtalk_shape->bin_data[lb] = (uint32_t)tmp64_0; + + + + + + if ((int32_t)pxtalk_shape->bin_data[lb] > + pxtalk_data->max_shape_value) + pxtalk_data->max_shape_value = + (int32_t)pxtalk_shape->bin_data[lb]; + + remaining_area -= (int32_t)pxtalk_shape->bin_data[lb]; + } + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_hist_xtalk_shape_model( + uint16_t events_per_bin, + uint16_t pulse_centre, + uint16_t pulse_width, + VL53L1_xtalk_histogram_shape_t *pxtalk_shape) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + uint32_t phase_start = 0; + uint32_t phase_stop = 0; + uint32_t phase_bin = 0; + + uint32_t bin_start = 0; + uint32_t bin_stop = 0; + + uint32_t lb = 0; + uint16_t VL53L1_p_008 = 0; + + LOG_FUNCTION_START(""); + + + + + pxtalk_shape->VL53L1_p_022 = 0; + pxtalk_shape->VL53L1_p_023 = VL53L1_XTALK_HISTO_BINS; + pxtalk_shape->VL53L1_p_024 = VL53L1_XTALK_HISTO_BINS; + + pxtalk_shape->zero_distance_phase = pulse_centre; + pxtalk_shape->phasecal_result__reference_phase = + pulse_centre + (3*2048); + + + + if (pulse_centre > (pulse_width >> 1)) + phase_start = (uint32_t)pulse_centre - + ((uint32_t)pulse_width >> 1); + else + phase_start = 0; + + phase_stop = (uint32_t)pulse_centre + + ((uint32_t)pulse_width >> 1); + + + + bin_start = (phase_start / 2048); + bin_stop = (phase_stop / 2048); + + for (lb = 0; lb < VL53L1_XTALK_HISTO_BINS; lb++) { + VL53L1_p_008 = 0; + + + + if (lb == bin_start && lb == bin_stop) { + VL53L1_p_008 = + VL53L1_hist_xtalk_shape_model_interp( + events_per_bin, + phase_stop - phase_start); + + } else if (lb > bin_start && lb < bin_stop) { + + + + VL53L1_p_008 = events_per_bin; + + } else if (lb == bin_start) { + + + + phase_bin = (lb + 1) * 2048; + VL53L1_p_008 = + VL53L1_hist_xtalk_shape_model_interp( + events_per_bin, + (phase_bin - phase_start)); + + } else if (lb == bin_stop) { + + + + phase_bin = lb * 2048; + VL53L1_p_008 = + VL53L1_hist_xtalk_shape_model_interp( + events_per_bin, + (phase_stop - phase_bin)); + } + + pxtalk_shape->bin_data[lb] = VL53L1_p_008; + } + + LOG_FUNCTION_END(status); + + return status; +} + + +uint16_t VL53L1_hist_xtalk_shape_model_interp( + uint16_t events_per_bin, + uint32_t phase_delta) +{ + + + + + + + + + + uint32_t VL53L1_p_008 = 0; + + LOG_FUNCTION_START(""); + + + + VL53L1_p_008 = (uint32_t)events_per_bin * phase_delta; + VL53L1_p_008 += 1024; + VL53L1_p_008 /= 2048; + + + + if (VL53L1_p_008 > 0xFFFFU) + VL53L1_p_008 = 0xFFFFU; + + LOG_FUNCTION_END(0); + + return (uint16_t)VL53L1_p_008; +} + + +void VL53L1_spad_number_to_byte_bit_index( + uint8_t spad_number, + uint8_t *pbyte_index, + uint8_t *pbit_index, + uint8_t *pbit_mask) +{ + + + + + + + + + + + *pbyte_index = spad_number >> 3; + *pbit_index = spad_number & 0x07; + *pbit_mask = 0x01 << *pbit_index; + +} + + +void VL53L1_encode_row_col( + uint8_t row, + uint8_t col, + uint8_t *pspad_number) +{ + + + + + + if (row > 7) + *pspad_number = 128 + (col << 3) + (15-row); + else + *pspad_number = ((15-col) << 3) + row; + +} + + +void VL53L1_decode_zone_size( + uint8_t encoded_xy_size, + uint8_t *pwidth, + uint8_t *pheight) +{ + + + + + + + + + + + + *pheight = encoded_xy_size >> 4; + *pwidth = encoded_xy_size & 0x0F; + +} + + +void VL53L1_encode_zone_size( + uint8_t width, + uint8_t height, + uint8_t *pencoded_xy_size) +{ + + + + + + + + + + + *pencoded_xy_size = (height << 4) + width; + +} + + +void VL53L1_decode_zone_limits( + uint8_t encoded_xy_centre, + uint8_t encoded_xy_size, + int16_t *px_ll, + int16_t *py_ll, + int16_t *px_ur, + int16_t *py_ur) +{ + + + + + + + + + + uint8_t x_centre = 0; + uint8_t y_centre = 0; + uint8_t width = 0; + uint8_t height = 0; + + + + + VL53L1_decode_row_col( + encoded_xy_centre, + &y_centre, + &x_centre); + + VL53L1_decode_zone_size( + encoded_xy_size, + &width, + &height); + + + + + *px_ll = (int16_t)x_centre - ((int16_t)width + 1) / 2; + if (*px_ll < 0) + *px_ll = 0; + + *px_ur = *px_ll + (int16_t)width; + if (*px_ur > (VL53L1_SPAD_ARRAY_WIDTH-1)) + *px_ur = VL53L1_SPAD_ARRAY_WIDTH-1; + + *py_ll = (int16_t)y_centre - ((int16_t)height + 1) / 2; + if (*py_ll < 0) + *py_ll = 0; + + *py_ur = *py_ll + (int16_t)height; + if (*py_ur > (VL53L1_SPAD_ARRAY_HEIGHT-1)) + *py_ur = VL53L1_SPAD_ARRAY_HEIGHT-1; +} + + +uint8_t VL53L1_is_aperture_location( + uint8_t row, + uint8_t col) +{ + + + + + + uint8_t is_aperture = 0; + uint8_t mod_row = row % 4; + uint8_t mod_col = col % 4; + + if (mod_row == 0 && mod_col == 2) + is_aperture = 1; + + if (mod_row == 2 && mod_col == 0) + is_aperture = 1; + + return is_aperture; +} + + +void VL53L1_calc_max_effective_spads( + uint8_t encoded_zone_centre, + uint8_t encoded_zone_size, + uint8_t *pgood_spads, + uint16_t aperture_attenuation, + uint16_t *pmax_effective_spads) +{ + + + + + + + int16_t x = 0; + int16_t y = 0; + + int16_t zone_x_ll = 0; + int16_t zone_y_ll = 0; + int16_t zone_x_ur = 0; + int16_t zone_y_ur = 0; + + uint8_t spad_number = 0; + uint8_t byte_index = 0; + uint8_t bit_index = 0; + uint8_t bit_mask = 0; + + uint8_t is_aperture = 0; + + + + + VL53L1_decode_zone_limits( + encoded_zone_centre, + encoded_zone_size, + &zone_x_ll, + &zone_y_ll, + &zone_x_ur, + &zone_y_ur); + + + + + + + + *pmax_effective_spads = 0; + + for (y = zone_y_ll; y <= zone_y_ur; y++) { + for (x = zone_x_ll; x <= zone_x_ur; x++) { + + + + + VL53L1_encode_row_col( + (uint8_t)y, + (uint8_t)x, + &spad_number); + + + + + + + + + VL53L1_spad_number_to_byte_bit_index( + spad_number, + &byte_index, + &bit_index, + &bit_mask); + + + + + if ((pgood_spads[byte_index] & bit_mask) > 0) { + + + + is_aperture = VL53L1_is_aperture_location( + (uint8_t)y, + (uint8_t)x); + + if (is_aperture > 0) + *pmax_effective_spads += + aperture_attenuation; + else + *pmax_effective_spads += 0x0100; + + } + } + } +} + + +void VL53L1_calc_mm_effective_spads( + uint8_t encoded_mm_roi_centre, + uint8_t encoded_mm_roi_size, + uint8_t encoded_zone_centre, + uint8_t encoded_zone_size, + uint8_t *pgood_spads, + uint16_t aperture_attenuation, + uint16_t *pmm_inner_effective_spads, + uint16_t *pmm_outer_effective_spads) +{ + + + + + + + + int16_t x = 0; + int16_t y = 0; + + int16_t mm_x_ll = 0; + int16_t mm_y_ll = 0; + int16_t mm_x_ur = 0; + int16_t mm_y_ur = 0; + + int16_t zone_x_ll = 0; + int16_t zone_y_ll = 0; + int16_t zone_x_ur = 0; + int16_t zone_y_ur = 0; + + uint8_t spad_number = 0; + uint8_t byte_index = 0; + uint8_t bit_index = 0; + uint8_t bit_mask = 0; + + uint8_t is_aperture = 0; + uint16_t spad_attenuation = 0; + + + + + VL53L1_decode_zone_limits( + encoded_mm_roi_centre, + encoded_mm_roi_size, + &mm_x_ll, + &mm_y_ll, + &mm_x_ur, + &mm_y_ur); + + VL53L1_decode_zone_limits( + encoded_zone_centre, + encoded_zone_size, + &zone_x_ll, + &zone_y_ll, + &zone_x_ur, + &zone_y_ur); + + + + + + + + + + *pmm_inner_effective_spads = 0; + *pmm_outer_effective_spads = 0; + + for (y = zone_y_ll; y <= zone_y_ur; y++) { + for (x = zone_x_ll; x <= zone_x_ur; x++) { + + + + + VL53L1_encode_row_col( + (uint8_t)y, + (uint8_t)x, + &spad_number); + + + + + + + + + VL53L1_spad_number_to_byte_bit_index( + spad_number, + &byte_index, + &bit_index, + &bit_mask); + + + + + if ((pgood_spads[byte_index] & bit_mask) > 0) { + + + + is_aperture = VL53L1_is_aperture_location( + (uint8_t)y, + (uint8_t)x); + + if (is_aperture > 0) + spad_attenuation = aperture_attenuation; + else + spad_attenuation = 0x0100; + + + + + + + + if (x >= mm_x_ll && x <= mm_x_ur && + y >= mm_y_ll && y <= mm_y_ur) + *pmm_inner_effective_spads += + spad_attenuation; + else + *pmm_outer_effective_spads += + spad_attenuation; + } + } + } +} + + +void VL53L1_hist_copy_results_to_sys_and_core( + VL53L1_histogram_bin_data_t *pbins, + VL53L1_range_results_t *phist, + VL53L1_system_results_t *psys, + VL53L1_core_results_t *pcore) +{ + + + + + + uint8_t i = 0; + + VL53L1_range_data_t *pdata; + + LOG_FUNCTION_START(""); + + + + + VL53L1_init_system_results(psys); + + + + + psys->result__interrupt_status = pbins->result__interrupt_status; + psys->result__range_status = phist->active_results; + psys->result__report_status = pbins->result__report_status; + psys->result__stream_count = pbins->result__stream_count; + + pdata = &(phist->VL53L1_p_002[0]); + + for (i = 0; i < phist->active_results; i++) { + + switch (i) { + case 0: + psys->result__dss_actual_effective_spads_sd0 = + pdata->VL53L1_p_006; + psys->result__peak_signal_count_rate_mcps_sd0 = + pdata->peak_signal_count_rate_mcps; + psys->result__avg_signal_count_rate_mcps_sd0 = + pdata->avg_signal_count_rate_mcps; + psys->result__ambient_count_rate_mcps_sd0 = + pdata->ambient_count_rate_mcps; + + psys->result__sigma_sd0 = pdata->VL53L1_p_005; + psys->result__phase_sd0 = pdata->VL53L1_p_014; + + psys->result__final_crosstalk_corrected_range_mm_sd0 = + (uint16_t)pdata->median_range_mm; + + psys->result__phase_sd1 = pdata->zero_distance_phase; + + pcore->result_core__ranging_total_events_sd0 = + pdata->VL53L1_p_021; + pcore->result_core__signal_total_events_sd0 = + pdata->VL53L1_p_013; + pcore->result_core__total_periods_elapsed_sd0 = + pdata->total_periods_elapsed; + pcore->result_core__ambient_window_events_sd0 = + pdata->VL53L1_p_020; + + break; + case 1: + psys->result__dss_actual_effective_spads_sd1 = + pdata->VL53L1_p_006; + psys->result__peak_signal_count_rate_mcps_sd1 = + pdata->peak_signal_count_rate_mcps; + psys->result__ambient_count_rate_mcps_sd1 = + pdata->ambient_count_rate_mcps; + + psys->result__sigma_sd1 = pdata->VL53L1_p_005; + psys->result__phase_sd1 = pdata->VL53L1_p_014; + + psys->result__final_crosstalk_corrected_range_mm_sd1 = + (uint16_t)pdata->median_range_mm; + + pcore->result_core__ranging_total_events_sd1 = + pdata->VL53L1_p_021; + pcore->result_core__signal_total_events_sd1 = + pdata->VL53L1_p_013; + pcore->result_core__total_periods_elapsed_sd1 = + pdata->total_periods_elapsed; + pcore->result_core__ambient_window_events_sd1 = + pdata->VL53L1_p_020; + break; + } + + pdata++; + } + + LOG_FUNCTION_END(0); + +} + + +VL53L1_Error VL53L1_sum_histogram_data( + VL53L1_histogram_bin_data_t *phist_input, + VL53L1_histogram_bin_data_t *phist_output) +{ + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + uint8_t i = 0; + uint8_t smallest_bin_num = 0; + + LOG_FUNCTION_START(""); + + + + + if (status == VL53L1_ERROR_NONE) { + + if (phist_output->VL53L1_p_024 >= + phist_input->VL53L1_p_024) + smallest_bin_num = phist_input->VL53L1_p_024; + else + smallest_bin_num = phist_output->VL53L1_p_024; + } + + + + + + + + + if (status == VL53L1_ERROR_NONE) + + for (i = 0; i < smallest_bin_num; i++) + + + phist_output->bin_data[i] += phist_input->bin_data[i]; + + if (status == VL53L1_ERROR_NONE) + + phist_output->VL53L1_p_004 += + phist_input->VL53L1_p_004; + + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_avg_histogram_data( + uint8_t no_of_samples, + VL53L1_histogram_bin_data_t *phist_sum, + VL53L1_histogram_bin_data_t *phist_avg) +{ + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + uint8_t i = 0; + + LOG_FUNCTION_START(""); + + + + + + + + + if (status == VL53L1_ERROR_NONE) { + + for (i = 0; i < phist_sum->VL53L1_p_024; i++) { + + + + + if (no_of_samples > 0) + phist_avg->bin_data[i] = + phist_sum->bin_data[i] / + (int32_t)no_of_samples; + else + phist_avg->bin_data[i] = phist_sum->bin_data[i]; + } + } + + if (status == VL53L1_ERROR_NONE) { + + if (no_of_samples > 0) + phist_avg->VL53L1_p_004 = + phist_sum->VL53L1_p_004 / + (int32_t)no_of_samples; + else + phist_avg->VL53L1_p_004 = + phist_sum->VL53L1_p_004; + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_save_cfg_data( + VL53L1_DEV Dev) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_LLDriverResults_t *pres = + VL53L1DevStructGetLLResultsHandle(Dev); + + VL53L1_zone_private_dyn_cfg_t *pzone_dyn_cfg; + VL53L1_dynamic_config_t *pdynamic = &(pdev->dyn_cfg); + + LOG_FUNCTION_START(""); + + pzone_dyn_cfg = + &(pres->zone_dyn_cfgs.VL53L1_p_002[pdev->ll_state.cfg_zone_id]); + + pzone_dyn_cfg->expected_stream_count = + pdev->ll_state.cfg_stream_count; + + pzone_dyn_cfg->expected_gph_id = + pdev->ll_state.cfg_gph_id; + + pzone_dyn_cfg->roi_config__user_roi_centre_spad = + pdynamic->roi_config__user_roi_centre_spad; + + pzone_dyn_cfg->roi_config__user_roi_requested_global_xy_size = + pdynamic->roi_config__user_roi_requested_global_xy_size; + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_dynamic_zone_update( + VL53L1_DEV Dev, + VL53L1_range_results_t *presults) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_LLDriverResults_t *pres = + VL53L1DevStructGetLLResultsHandle(Dev); + VL53L1_zone_private_dyn_cfgs_t *pZ = &(pres->zone_dyn_cfgs); + + uint8_t zone_id = pdev->ll_state.rd_zone_id; + uint8_t i; + uint16_t max_total_rate_per_spads; + uint16_t target_rate = + pdev->stat_cfg.dss_config__target_total_rate_mcps; + uint32_t temp = 0xFFFF; +#ifdef VL53L1_LOG_ENABLE + uint16_t eff_spad_cnt = + pZ->VL53L1_p_002[zone_id].dss_requested_effective_spad_count; +#endif + + LOG_FUNCTION_START(""); + + pZ->VL53L1_p_002[zone_id].dss_requested_effective_spad_count = 0; + + trace_print(VL53L1_TRACE_LEVEL_DEBUG, + " DYNZONEUPDATE: peak signal count rate mcps:"); + + trace_print(VL53L1_TRACE_LEVEL_DEBUG, + "%u actual effective spads: %u\n", + presults->VL53L1_p_002[0].peak_signal_count_rate_mcps, + presults->VL53L1_p_002[0].VL53L1_p_006); + + trace_print(VL53L1_TRACE_LEVEL_DEBUG, + " DYNZONEUPDATE: active results: %u\n", + presults->active_results); + + max_total_rate_per_spads = + presults->VL53L1_p_002[0].total_rate_per_spad_mcps; + + trace_print(VL53L1_TRACE_LEVEL_DEBUG, + " DYNZONEUPDATE: max total rate per spad at start: %u\n", + max_total_rate_per_spads); + + for (i = 1; i < presults->active_results; i++) { + trace_print(VL53L1_TRACE_LEVEL_DEBUG, + " DYNZONEUPDATE: zone total rate per spad: zone_id: %u,", + i); + + trace_print(VL53L1_TRACE_LEVEL_DEBUG, + "total rate per spad: %u\n", + presults->VL53L1_p_002[i].total_rate_per_spad_mcps); + + if (presults->VL53L1_p_002[i].total_rate_per_spad_mcps > + max_total_rate_per_spads) + max_total_rate_per_spads = + presults->VL53L1_p_002[i].total_rate_per_spad_mcps; + + } + + if (max_total_rate_per_spads == 0) { + + + + + + temp = 0xFFFF; + } else { + + + + + + temp = target_rate << 14; + trace_print(VL53L1_TRACE_LEVEL_DEBUG, + " DYNZONEUPDATE: 1: temp: %u\n", + temp); + + + + + + temp = temp / max_total_rate_per_spads; + + trace_print(VL53L1_TRACE_LEVEL_DEBUG, + " DYNZONEUPDATE: 2: temp: %u\n", + temp); + + + + + + if (temp > 0xFFFF) + temp = 0xFFFF; + + trace_print(VL53L1_TRACE_LEVEL_DEBUG, + " DYNZONEUPDATE: 3: temp: %u\n", + temp); + } + + pZ->VL53L1_p_002[zone_id].dss_requested_effective_spad_count = + (uint16_t)temp; + + trace_print(VL53L1_TRACE_LEVEL_DEBUG, + " DYNZONEUPDATE: zone_id: %u, target_rate: %u,", + zone_id, + target_rate); + + trace_print(VL53L1_TRACE_LEVEL_DEBUG, + "max_total_rate_per_spads: %u, requested_spads: %u\n", + max_total_rate_per_spads, + eff_spad_cnt); + + LOG_FUNCTION_END(status); + + return status; +} + +VL53L1_Error VL53L1_multizone_hist_bins_update( + VL53L1_DEV Dev) +{ + + + + + + + + + + + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_ll_driver_state_t *pstate = &(pdev->ll_state); + VL53L1_zone_config_t *pzone_cfg = &(pdev->zone_cfg); + VL53L1_histogram_config_t *phist_cfg = &(pdev->hist_cfg); + VL53L1_histogram_config_t *pmulti_hist = + &(pzone_cfg->multizone_hist_cfg); + + uint8_t next_range_is_odd_timing = (pstate->cfg_stream_count) % 2; + + LOG_FUNCTION_START(""); + + + + + + if (pzone_cfg->bin_config[pdev->ll_state.cfg_zone_id] == + VL53L1_ZONECONFIG_BINCONFIG__LOWAMB) { + if (!next_range_is_odd_timing) { + trace_print (VL53L1_TRACE_LEVEL_DEBUG, + " HISTBINCONFIGUPDATE: Setting LOWAMB EVEN timing\n"); + phist_cfg->histogram_config__low_amb_even_bin_0_1 = + pmulti_hist->histogram_config__low_amb_even_bin_0_1; + phist_cfg->histogram_config__low_amb_even_bin_2_3 = + pmulti_hist->histogram_config__low_amb_even_bin_2_3; + phist_cfg->histogram_config__low_amb_even_bin_4_5 = + pmulti_hist->histogram_config__low_amb_even_bin_4_5; + } + + if (next_range_is_odd_timing) { + trace_print (VL53L1_TRACE_LEVEL_DEBUG, + " HISTBINCONFIGUPDATE: Setting LOWAMB ODD timing\n"); + phist_cfg->histogram_config__low_amb_odd_bin_0_1 = + pmulti_hist->histogram_config__low_amb_even_bin_0_1; + phist_cfg->histogram_config__low_amb_odd_bin_2_3 = + pmulti_hist->histogram_config__low_amb_even_bin_2_3; + phist_cfg->histogram_config__low_amb_odd_bin_4_5 = + pmulti_hist->histogram_config__low_amb_even_bin_4_5; + } + } else if (pzone_cfg->bin_config[pdev->ll_state.cfg_zone_id] == + VL53L1_ZONECONFIG_BINCONFIG__MIDAMB) { + + trace_print (VL53L1_TRACE_LEVEL_DEBUG, + " HISTBINCONFIGUPDATE: Setting MIDAMB timing\n"); + if (!next_range_is_odd_timing) { + trace_print(VL53L1_TRACE_LEVEL_DEBUG, + " HISTBINCONFIGUPDATE: Setting MIDAMB EVEN timing\n"); + phist_cfg->histogram_config__low_amb_even_bin_0_1 = + pmulti_hist->histogram_config__mid_amb_even_bin_0_1; + phist_cfg->histogram_config__low_amb_even_bin_2_3 = + pmulti_hist->histogram_config__mid_amb_even_bin_2_3; + phist_cfg->histogram_config__low_amb_even_bin_4_5 = + pmulti_hist->histogram_config__mid_amb_even_bin_4_5; + } + + if (next_range_is_odd_timing) { + trace_print (VL53L1_TRACE_LEVEL_DEBUG, + " HISTBINCONFIGUPDATE: Setting MIDAMB ODD timing\n"); + phist_cfg->histogram_config__low_amb_odd_bin_0_1 = + pmulti_hist->histogram_config__mid_amb_even_bin_0_1; + phist_cfg->histogram_config__low_amb_odd_bin_2_3 = + pmulti_hist->histogram_config__mid_amb_even_bin_2_3; + phist_cfg->histogram_config__low_amb_odd_bin_4_5 = + pmulti_hist->histogram_config__mid_amb_even_bin_4_5; + } + } else if (pzone_cfg->bin_config[pdev->ll_state.cfg_zone_id] == + VL53L1_ZONECONFIG_BINCONFIG__HIGHAMB) { + if (!next_range_is_odd_timing) { + trace_print (VL53L1_TRACE_LEVEL_DEBUG, + " HISTBINCONFIGUPDATE: Setting HIGHAMB EVEN timing\n" + ); + phist_cfg->histogram_config__low_amb_even_bin_0_1 = + pmulti_hist->histogram_config__high_amb_even_bin_0_1; + phist_cfg->histogram_config__low_amb_even_bin_2_3 = + pmulti_hist->histogram_config__high_amb_even_bin_2_3; + phist_cfg->histogram_config__low_amb_even_bin_4_5 = + pmulti_hist->histogram_config__high_amb_even_bin_4_5; + } + + if (next_range_is_odd_timing) { + trace_print (VL53L1_TRACE_LEVEL_DEBUG, + " HISTBINCONFIGUPDATE: Setting HIGHAMB ODD timing\n"); + phist_cfg->histogram_config__low_amb_odd_bin_0_1 = + pmulti_hist->histogram_config__high_amb_even_bin_0_1; + phist_cfg->histogram_config__low_amb_odd_bin_2_3 = + pmulti_hist->histogram_config__high_amb_even_bin_2_3; + phist_cfg->histogram_config__low_amb_odd_bin_4_5 = + pmulti_hist->histogram_config__high_amb_even_bin_4_5; + } + } + + + + + + + if (status == VL53L1_ERROR_NONE) { + + VL53L1_copy_hist_bins_to_static_cfg( + phist_cfg, + &(pdev->stat_cfg), + &(pdev->tim_cfg)); + } + + LOG_FUNCTION_END(status); + + return status; +} + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_update_internal_stream_counters( + VL53L1_DEV Dev, + uint8_t external_stream_count, + uint8_t *pinternal_stream_count, + uint8_t *pinternal_stream_count_val) +{ + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t stream_divider; + + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + stream_divider = pdev->gen_cfg.global_config__stream_divider; + + if (stream_divider == 0) { + + + + + + + *pinternal_stream_count = external_stream_count; + + } else if (*pinternal_stream_count_val == (stream_divider-1)) { + + + + + + if (*pinternal_stream_count == 0xFF) + *pinternal_stream_count = 0x80; + else + *pinternal_stream_count = *pinternal_stream_count + 1; + + + + + + *pinternal_stream_count_val = 0; + + } else { + + + + + + *pinternal_stream_count_val = *pinternal_stream_count_val + 1; + } + + trace_print(VL53L1_TRACE_LEVEL_DEBUG, + "UPDINTSTREAMCOUNT internal_steam_count: %d,", + *pinternal_stream_count); + + trace_print(VL53L1_TRACE_LEVEL_DEBUG, + "internal_stream_count_val: %d, divider: %d\n", + *pinternal_stream_count_val, + stream_divider); + + LOG_FUNCTION_END(status); + + return status; +} + + + + + + + +VL53L1_Error VL53L1_set_histogram_multizone_initial_bin_config( + VL53L1_zone_config_t *pzone_cfg, + VL53L1_histogram_config_t *phist_cfg, + VL53L1_histogram_config_t *pmulti_hist) +{ + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + + if (pzone_cfg->bin_config[0] == + VL53L1_ZONECONFIG_BINCONFIG__LOWAMB) { + phist_cfg->histogram_config__low_amb_even_bin_0_1 = + pmulti_hist->histogram_config__low_amb_even_bin_0_1; + phist_cfg->histogram_config__low_amb_even_bin_2_3 = + pmulti_hist->histogram_config__low_amb_even_bin_2_3; + phist_cfg->histogram_config__low_amb_even_bin_4_5 = + pmulti_hist->histogram_config__low_amb_even_bin_4_5; + + phist_cfg->histogram_config__low_amb_odd_bin_0_1 = + pmulti_hist->histogram_config__low_amb_even_bin_0_1; + phist_cfg->histogram_config__low_amb_odd_bin_2_3 = + pmulti_hist->histogram_config__low_amb_even_bin_2_3; + phist_cfg->histogram_config__low_amb_odd_bin_4_5 = + pmulti_hist->histogram_config__low_amb_even_bin_4_5; + } else if (pzone_cfg->bin_config[0] == + VL53L1_ZONECONFIG_BINCONFIG__MIDAMB) { + + phist_cfg->histogram_config__low_amb_even_bin_0_1 = + pmulti_hist->histogram_config__mid_amb_even_bin_0_1; + phist_cfg->histogram_config__low_amb_even_bin_2_3 = + pmulti_hist->histogram_config__mid_amb_even_bin_2_3; + phist_cfg->histogram_config__low_amb_even_bin_4_5 = + pmulti_hist->histogram_config__mid_amb_even_bin_4_5; + + phist_cfg->histogram_config__low_amb_odd_bin_0_1 = + pmulti_hist->histogram_config__mid_amb_even_bin_0_1; + phist_cfg->histogram_config__low_amb_odd_bin_2_3 = + pmulti_hist->histogram_config__mid_amb_even_bin_2_3; + phist_cfg->histogram_config__low_amb_odd_bin_4_5 = + pmulti_hist->histogram_config__mid_amb_even_bin_4_5; + } else if (pzone_cfg->bin_config[0] == + VL53L1_ZONECONFIG_BINCONFIG__HIGHAMB) { + phist_cfg->histogram_config__low_amb_even_bin_0_1 = + pmulti_hist->histogram_config__high_amb_even_bin_0_1; + phist_cfg->histogram_config__low_amb_even_bin_2_3 = + pmulti_hist->histogram_config__high_amb_even_bin_2_3; + phist_cfg->histogram_config__low_amb_even_bin_4_5 = + pmulti_hist->histogram_config__high_amb_even_bin_4_5; + phist_cfg->histogram_config__low_amb_odd_bin_0_1 = + pmulti_hist->histogram_config__high_amb_even_bin_0_1; + phist_cfg->histogram_config__low_amb_odd_bin_2_3 = + pmulti_hist->histogram_config__high_amb_even_bin_2_3; + phist_cfg->histogram_config__low_amb_odd_bin_4_5 = + pmulti_hist->histogram_config__high_amb_even_bin_4_5; + } + + LOG_FUNCTION_END(status); + return status; +} + + + + + + +uint8_t VL53L1_encode_GPIO_interrupt_config( + VL53L1_GPIO_interrupt_config_t *pintconf) +{ + uint8_t system__interrupt_config; + + system__interrupt_config = pintconf->intr_mode_distance; + system__interrupt_config |= ((pintconf->intr_mode_rate) << 2); + system__interrupt_config |= ((pintconf->intr_new_measure_ready) << 5); + system__interrupt_config |= ((pintconf->intr_no_target) << 6); + system__interrupt_config |= ((pintconf->intr_combined_mode) << 7); + + return system__interrupt_config; +} + + + + + + +VL53L1_GPIO_interrupt_config_t VL53L1_decode_GPIO_interrupt_config( + uint8_t system__interrupt_config) +{ + VL53L1_GPIO_interrupt_config_t intconf; + + intconf.intr_mode_distance = system__interrupt_config & 0x03; + intconf.intr_mode_rate = (system__interrupt_config >> 2) & 0x03; + intconf.intr_new_measure_ready = (system__interrupt_config >> 5) & 0x01; + intconf.intr_no_target = (system__interrupt_config >> 6) & 0x01; + intconf.intr_combined_mode = (system__interrupt_config >> 7) & 0x01; + + + + intconf.threshold_rate_low = 0; + intconf.threshold_rate_high = 0; + intconf.threshold_distance_low = 0; + intconf.threshold_distance_high = 0; + + return intconf; +} + + + + + + +VL53L1_Error VL53L1_set_GPIO_distance_threshold( + VL53L1_DEV Dev, + uint16_t threshold_high, + uint16_t threshold_low) +{ + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + pdev->dyn_cfg.system__thresh_high = threshold_high; + pdev->dyn_cfg.system__thresh_low = threshold_low; + + LOG_FUNCTION_END(status); + return status; +} + + + + + + +VL53L1_Error VL53L1_set_GPIO_rate_threshold( + VL53L1_DEV Dev, + uint16_t threshold_high, + uint16_t threshold_low) +{ + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + pdev->gen_cfg.system__thresh_rate_high = threshold_high; + pdev->gen_cfg.system__thresh_rate_low = threshold_low; + + LOG_FUNCTION_END(status); + return status; +} + + + + + + +VL53L1_Error VL53L1_set_GPIO_thresholds_from_struct( + VL53L1_DEV Dev, + VL53L1_GPIO_interrupt_config_t *pintconf) +{ + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + status = VL53L1_set_GPIO_distance_threshold( + Dev, + pintconf->threshold_distance_high, + pintconf->threshold_distance_low); + + if (status == VL53L1_ERROR_NONE) { + status = + VL53L1_set_GPIO_rate_threshold( + Dev, + pintconf->threshold_rate_high, + pintconf->threshold_rate_low); + } + + LOG_FUNCTION_END(status); + return status; +} + + +VL53L1_Error VL53L1_set_ref_spad_char_config( + VL53L1_DEV Dev, + uint8_t vcsel_period_a, + uint32_t phasecal_timeout_us, + uint16_t total_rate_target_mcps, + uint16_t max_count_rate_rtn_limit_mcps, + uint16_t min_count_rate_rtn_limit_mcps, + uint16_t fast_osc_frequency) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + uint8_t buffer[2]; + + uint32_t macro_period_us = 0; + uint32_t timeout_mclks = 0; + + LOG_FUNCTION_START(""); + + + + + + macro_period_us = + VL53L1_calc_macro_period_us( + fast_osc_frequency, + vcsel_period_a); + + + + + + + timeout_mclks = phasecal_timeout_us << 12; + timeout_mclks = timeout_mclks + (macro_period_us>>1); + timeout_mclks = timeout_mclks / macro_period_us; + + if (timeout_mclks > 0xFF) + pdev->gen_cfg.phasecal_config__timeout_macrop = 0xFF; + else + pdev->gen_cfg.phasecal_config__timeout_macrop = + (uint8_t)timeout_mclks; + + pdev->tim_cfg.range_config__vcsel_period_a = vcsel_period_a; + + + + + + + if (status == VL53L1_ERROR_NONE) + + status = + VL53L1_WrByte( + Dev, + VL53L1_PHASECAL_CONFIG__TIMEOUT_MACROP, + pdev->gen_cfg.phasecal_config__timeout_macrop); + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_WrByte( + Dev, + VL53L1_RANGE_CONFIG__VCSEL_PERIOD_A, + pdev->tim_cfg.range_config__vcsel_period_a); + + + + + + + + buffer[0] = pdev->tim_cfg.range_config__vcsel_period_a; + buffer[1] = pdev->tim_cfg.range_config__vcsel_period_a; + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_WriteMulti( + Dev, + VL53L1_SD_CONFIG__WOI_SD0, + buffer, + 2); + + + + + + + + pdev->customer.ref_spad_char__total_rate_target_mcps = + total_rate_target_mcps; + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_WrWord( + Dev, + VL53L1_REF_SPAD_CHAR__TOTAL_RATE_TARGET_MCPS, + total_rate_target_mcps); + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_WrWord( + Dev, + VL53L1_RANGE_CONFIG__SIGMA_THRESH, + max_count_rate_rtn_limit_mcps); + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_WrWord( + Dev, + VL53L1_RANGE_CONFIG__MIN_COUNT_RATE_RTN_LIMIT_MCPS, + min_count_rate_rtn_limit_mcps); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_ssc_config( + VL53L1_DEV Dev, + VL53L1_ssc_config_t *pssc_cfg, + uint16_t fast_osc_frequency) +{ + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t buffer[5]; + + uint32_t macro_period_us = 0; + uint16_t timeout_encoded = 0; + + LOG_FUNCTION_START(""); + + + + + + macro_period_us = + VL53L1_calc_macro_period_us( + fast_osc_frequency, + pssc_cfg->VL53L1_p_009); + + + + + + timeout_encoded = + VL53L1_calc_encoded_timeout( + pssc_cfg->timeout_us, + macro_period_us); + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_WrByte( + Dev, + VL53L1_CAL_CONFIG__VCSEL_START, + pssc_cfg->vcsel_start); + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_WrByte( + Dev, + VL53L1_GLOBAL_CONFIG__VCSEL_WIDTH, + pssc_cfg->vcsel_width); + + + + + buffer[0] = (uint8_t)((timeout_encoded & 0x0000FF00) >> 8); + buffer[1] = (uint8_t) (timeout_encoded & 0x000000FF); + buffer[2] = pssc_cfg->VL53L1_p_009; + buffer[3] = (uint8_t)((pssc_cfg->rate_limit_mcps & 0x0000FF00) >> 8); + buffer[4] = (uint8_t) (pssc_cfg->rate_limit_mcps & 0x000000FF); + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_WriteMulti( + Dev, + VL53L1_RANGE_CONFIG__TIMEOUT_MACROP_B_HI, + buffer, + 5); + + + + + + + + buffer[0] = pssc_cfg->VL53L1_p_009; + buffer[1] = pssc_cfg->VL53L1_p_009; + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_WriteMulti( + Dev, + VL53L1_SD_CONFIG__WOI_SD0, + buffer, + 2); + + + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_WrByte( + Dev, + VL53L1_NVM_BIST__CTRL, + pssc_cfg->array_select); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_spad_rate_data( + VL53L1_DEV Dev, + VL53L1_spad_rate_data_t *pspad_rates) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + int i = 0; + + uint8_t VL53L1_p_002[512]; + uint8_t *pdata = &VL53L1_p_002[0]; + + LOG_FUNCTION_START(""); + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_disable_firmware(Dev); + + + + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_ReadMulti( + Dev, + VL53L1_PRIVATE__PATCH_BASE_ADDR_RSLV, + pdata, + 512); + + + + pdata = &VL53L1_p_002[0]; + for (i = 0; i < VL53L1_NO_OF_SPAD_ENABLES; i++) { + pspad_rates->rate_data[i] = + (uint16_t)VL53L1_decode_unsigned_integer(pdata, 2); + pdata += 2; + } + + + + + pspad_rates->VL53L1_p_023 = VL53L1_NO_OF_SPAD_ENABLES; + pspad_rates->no_of_values = VL53L1_NO_OF_SPAD_ENABLES; + pspad_rates->fractional_bits = 15; + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_firmware(Dev); + + LOG_FUNCTION_END(status); + + return status; +} + + + + +VL53L1_Error VL53L1_dynamic_xtalk_correction_calc_required_samples( + VL53L1_DEV Dev + ) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_LLDriverResults_t *pres = VL53L1DevStructGetLLResultsHandle(Dev); + VL53L1_smudge_corrector_config_t *pconfig = + &(pdev->smudge_correct_config); + VL53L1_smudge_corrector_internals_t *pint = + &(pdev->smudge_corrector_internals); + + VL53L1_range_results_t *presults = &(pres->range_results); + VL53L1_range_data_t *pxmonitor = &(presults->xmonitor); + + uint32_t peak_duration_us = pxmonitor->peak_duration_us; + + uint64_t temp64a; + uint64_t temp64z; + + LOG_FUNCTION_START(""); + + temp64a = (uint64_t)(pxmonitor->VL53L1_p_021 + + pxmonitor->VL53L1_p_020); + temp64a = do_division_u((temp64a * 1000), peak_duration_us); + temp64a = do_division_u((temp64a * 1000), peak_duration_us); + + temp64z = (uint64_t)pconfig->noise_margin * pxmonitor->VL53L1_p_006; + temp64a = temp64a * 1000 * 256; + temp64a = do_division_u(temp64a, temp64z); + temp64a = temp64a * 1000 * 256; + temp64a = do_division_u(temp64a, temp64z); + + pint->required_samples = (uint32_t)temp64a; + + + + if (pint->required_samples < 2) + pint->required_samples = 2; + + LOG_FUNCTION_END(status); + + return status; +} + +VL53L1_Error VL53L1_dynamic_xtalk_correction_calc_new_xtalk( + VL53L1_DEV Dev, + uint32_t xtalk_offset_out, + VL53L1_smudge_corrector_config_t *pconfig, + VL53L1_smudge_corrector_data_t *pout, + uint8_t add_smudge, + uint8_t soft_update + ) +{ + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + int16_t x_gradient_scaler; + int16_t y_gradient_scaler; + uint32_t orig_xtalk_offset; + int16_t orig_x_gradient; + int16_t orig_y_gradient; + int32_t itemp32; + VL53L1_xtalk_config_t *pX = &(pdev->xtalk_cfg); + VL53L1_xtalk_calibration_results_t *pC = &(pdev->xtalk_cal); + + LOG_FUNCTION_START(""); + + + + if (add_smudge == 1) { + pout->algo__crosstalk_compensation_plane_offset_kcps = + (uint32_t)xtalk_offset_out + + (uint32_t)pconfig->smudge_margin; + } else { + pout->algo__crosstalk_compensation_plane_offset_kcps = + (uint32_t)xtalk_offset_out; + } + + + + orig_xtalk_offset = + pX->nvm_default__crosstalk_compensation_plane_offset_kcps; + + orig_x_gradient = + pX->nvm_default__crosstalk_compensation_x_plane_gradient_kcps; + + orig_y_gradient = + pX->nvm_default__crosstalk_compensation_y_plane_gradient_kcps; + + if (((pconfig->user_scaler_set == 0) + || (pconfig->scaler_calc_method == 1)) && + (pC->algo__crosstalk_compensation_plane_offset_kcps + != 0)) { + + + orig_xtalk_offset = + pC->algo__crosstalk_compensation_plane_offset_kcps; + + orig_x_gradient = + pC->algo__crosstalk_compensation_x_plane_gradient_kcps; + + orig_y_gradient = + pC->algo__crosstalk_compensation_y_plane_gradient_kcps; + } + + + + if ((pconfig->user_scaler_set == 0) && (orig_x_gradient == 0)) + pout->gradient_zero_flag |= 0x01; + + if ((pconfig->user_scaler_set == 0) && (orig_y_gradient == 0)) + pout->gradient_zero_flag |= 0x02; + + + + + + + if (orig_xtalk_offset == 0) + orig_xtalk_offset = 1; + + + + + if (pconfig->user_scaler_set == 1) { + x_gradient_scaler = pconfig->x_gradient_scaler; + y_gradient_scaler = pconfig->y_gradient_scaler; + } else { + + + + + x_gradient_scaler = (int16_t)do_division_s( + (((int32_t)orig_x_gradient) << 6), + orig_xtalk_offset); + pconfig->x_gradient_scaler = x_gradient_scaler; + y_gradient_scaler = (int16_t)do_division_s( + (((int32_t)orig_y_gradient) << 6), + orig_xtalk_offset); + pconfig->y_gradient_scaler = y_gradient_scaler; + } + + + + + if (pconfig->scaler_calc_method == 0) { + + + + + + + itemp32 = (int32_t)( + pout->algo__crosstalk_compensation_plane_offset_kcps * + x_gradient_scaler); + itemp32 = itemp32 >> 6; + if (itemp32 > 0xFFFF) + itemp32 = 0xFFFF; + + pout->algo__crosstalk_compensation_x_plane_gradient_kcps = + (int16_t)itemp32; + + itemp32 = (int32_t)( + pout->algo__crosstalk_compensation_plane_offset_kcps * + y_gradient_scaler); + itemp32 = itemp32 >> 6; + if (itemp32 > 0xFFFF) + itemp32 = 0xFFFF; + + pout->algo__crosstalk_compensation_y_plane_gradient_kcps = + (int16_t)itemp32; + } else if (pconfig->scaler_calc_method == 1) { + + + + + + itemp32 = (int32_t)(orig_xtalk_offset - + pout->algo__crosstalk_compensation_plane_offset_kcps); + itemp32 = (int32_t)(do_division_s(itemp32, 16)); + itemp32 = itemp32 << 2; + itemp32 = itemp32 + (int32_t)(orig_x_gradient); + if (itemp32 > 0xFFFF) + itemp32 = 0xFFFF; + + pout->algo__crosstalk_compensation_x_plane_gradient_kcps = + (int16_t)itemp32; + + itemp32 = (int32_t)(orig_xtalk_offset - + pout->algo__crosstalk_compensation_plane_offset_kcps); + itemp32 = (int32_t)(do_division_s(itemp32, 80)); + itemp32 = itemp32 << 2; + itemp32 = itemp32 + (int32_t)(orig_y_gradient); + if (itemp32 > 0xFFFF) + itemp32 = 0xFFFF; + + pout->algo__crosstalk_compensation_y_plane_gradient_kcps = + (int16_t)itemp32; + } + + + + if (pconfig->smudge_corr_apply_enabled == 1 && + (soft_update != 1) + ) { + + + pout->new_xtalk_applied_flag = 1; + + + + pX->algo__crosstalk_compensation_plane_offset_kcps = + pout->algo__crosstalk_compensation_plane_offset_kcps; + pX->algo__crosstalk_compensation_x_plane_gradient_kcps = + pout->algo__crosstalk_compensation_x_plane_gradient_kcps; + pX->algo__crosstalk_compensation_y_plane_gradient_kcps = + pout->algo__crosstalk_compensation_y_plane_gradient_kcps; + + + + if (pconfig->smudge_corr_single_apply == 1) { + + + pconfig->smudge_corr_apply_enabled = 0; + pconfig->smudge_corr_single_apply = 0; + } + } + + + + if (soft_update != 1) + pout->smudge_corr_valid = 1; + + LOG_FUNCTION_END(status); + + return status; +} + +#define CONT_CONTINUE 0 +#define CONT_NEXT_LOOP 1 +#define CONT_RESET 2 +VL53L1_Error VL53L1_dynamic_xtalk_correction_corrector( + VL53L1_DEV Dev + ) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_LLDriverResults_t *pres = VL53L1DevStructGetLLResultsHandle(Dev); + VL53L1_smudge_corrector_config_t *pconfig = + &(pdev->smudge_correct_config); + VL53L1_smudge_corrector_internals_t *pint = + &(pdev->smudge_corrector_internals); + VL53L1_smudge_corrector_data_t *pout = + &(pres->range_results.smudge_corrector_data); + VL53L1_range_results_t *pR = &(pres->range_results); + VL53L1_xtalk_config_t *pX = &(pdev->xtalk_cfg); + + uint8_t run_smudge_detection = 0; + uint8_t run_nodetect = 0; + uint8_t ambient_check = 0; + int32_t itemp32 = 0; + uint64_t utemp64 = 0; + uint8_t continue_processing = CONT_CONTINUE; + uint32_t xtalk_offset_out = 0; + uint32_t xtalk_offset_in = 0; + uint32_t current_xtalk = 0; + uint32_t smudge_margin_adjusted = 0; + uint8_t i = 0; + uint8_t nodetect_index = 0; + uint16_t amr; + + uint32_t cco; + + + + LOG_FUNCTION_START(""); + + + + VL53L1_dynamic_xtalk_correction_output_init(pres); + + + + ambient_check = (pconfig->smudge_corr_ambient_threshold == 0) || + (pconfig->smudge_corr_ambient_threshold > + ((uint32_t)pR->xmonitor.ambient_count_rate_mcps)); + + + + + run_smudge_detection = (pconfig->smudge_corr_enabled == 1) && + ambient_check && + (pR->xmonitor.range_status + == VL53L1_DEVICEERROR_RANGECOMPLETE); + + + + + if ((pR->xmonitor.range_status + != VL53L1_DEVICEERROR_RANGECOMPLETE) && + (pconfig->smudge_corr_enabled == 1)) { + + + run_nodetect = 2; + for (i = 0; i < pR->active_results; i++) { + if (pR->VL53L1_p_002[i].range_status == + VL53L1_DEVICEERROR_RANGECOMPLETE) { + if (pR->VL53L1_p_002[i].median_range_mm + <= + pconfig->nodetect_min_range_mm) { + run_nodetect = 0; + } else { + if (run_nodetect == 2) { + run_nodetect = 1; + nodetect_index = i; + } + } + } + } + + if (run_nodetect == 2) + + + run_nodetect = 0; + + amr = + pR->VL53L1_p_002[nodetect_index].ambient_count_rate_mcps; + + if (run_nodetect == 1) { + + + + + + + + utemp64 = 1000 * ((uint64_t)amr); + + + + utemp64 = utemp64 << 9; + + + + if (utemp64 < pconfig->nodetect_ambient_threshold) + run_nodetect = 1; + else + run_nodetect = 0; + + } + } + + + if (run_smudge_detection == 1) { + + + pint->nodetect_counter = 0; + + + + VL53L1_dynamic_xtalk_correction_calc_required_samples(Dev); + + + + xtalk_offset_in = + pR->xmonitor.VL53L1_p_012; + + + + cco = pX->algo__crosstalk_compensation_plane_offset_kcps; + current_xtalk = ((uint32_t)cco) << 2; + + + + smudge_margin_adjusted = + ((uint32_t)(pconfig->smudge_margin)) << 2; + + + + itemp32 = xtalk_offset_in - current_xtalk + + smudge_margin_adjusted; + + if (itemp32 < 0) + itemp32 = itemp32 * (-1); + + + if (itemp32 > ((int32_t)pconfig->single_xtalk_delta)) { + if ((int32_t)xtalk_offset_in > + ((int32_t)current_xtalk - + (int32_t)smudge_margin_adjusted)) { + pout->single_xtalk_delta_flag = 1; + } else { + pout->single_xtalk_delta_flag = 2; + } + } + + + + pint->current_samples = pint->current_samples + 1; + + + + if (pint->current_samples > pconfig->sample_limit) { + pout->sample_limit_exceeded_flag = 1; + continue_processing = CONT_RESET; + } else { + + pint->accumulator = pint->accumulator + + xtalk_offset_in; + } + + if (pint->current_samples < pint->required_samples) + continue_processing = CONT_NEXT_LOOP; + + + + xtalk_offset_out = + (uint32_t)(do_division_u(pint->accumulator, + pint->current_samples)); + + + + itemp32 = xtalk_offset_out - current_xtalk + + smudge_margin_adjusted; + + if (itemp32 < 0) + itemp32 = itemp32 * (-1); + + if (continue_processing == CONT_CONTINUE && + (itemp32 >= ((int32_t)(pconfig->averaged_xtalk_delta))) + ) { + if ((int32_t)xtalk_offset_out > + ((int32_t)current_xtalk - + (int32_t)smudge_margin_adjusted)) + pout->averaged_xtalk_delta_flag = 1; + else + pout->averaged_xtalk_delta_flag = 2; + } + + if (continue_processing == CONT_CONTINUE && + (itemp32 < ((int32_t)(pconfig->averaged_xtalk_delta))) + ) + + + continue_processing = CONT_RESET; + + + + + pout->smudge_corr_clipped = 0; + if ((continue_processing == CONT_CONTINUE) && + (pconfig->smudge_corr_clip_limit != 0)) { + if (xtalk_offset_out > + pconfig->smudge_corr_clip_limit) { + pout->smudge_corr_clipped = 1; + continue_processing = CONT_RESET; + } + } + + + + + + if (pconfig->user_xtalk_offset_limit_hi && + (xtalk_offset_out > + pconfig->user_xtalk_offset_limit)) + xtalk_offset_out = + pconfig->user_xtalk_offset_limit; + + + + + if ((pconfig->user_xtalk_offset_limit_hi == 0) && + (xtalk_offset_out < + pconfig->user_xtalk_offset_limit)) + xtalk_offset_out = + pconfig->user_xtalk_offset_limit; + + + + + xtalk_offset_out = xtalk_offset_out >> 2; + if (xtalk_offset_out > 0x3FFFF) + xtalk_offset_out = 0x3FFFF; + + + + if (continue_processing == CONT_CONTINUE) { + + + VL53L1_dynamic_xtalk_correction_calc_new_xtalk( + Dev, + xtalk_offset_out, + pconfig, + pout, + 1, + + 0 + + ); + + + + continue_processing = CONT_RESET; + } else { + + + VL53L1_dynamic_xtalk_correction_calc_new_xtalk( + Dev, + xtalk_offset_out, + pconfig, + pout, + 1, + + 1 + + ); + } + + + + if (continue_processing == CONT_RESET) { + pint->accumulator = 0; + pint->current_samples = 0; + pint->nodetect_counter = 0; + } + + } + + continue_processing = CONT_CONTINUE; + if (run_nodetect == 1) { + + + pint->nodetect_counter += 1; + + + + if (pint->nodetect_counter < pconfig->nodetect_sample_limit) + continue_processing = CONT_NEXT_LOOP; + + + + xtalk_offset_out = (uint32_t)(pconfig->nodetect_xtalk_offset); + + if (continue_processing == CONT_CONTINUE) { + + + VL53L1_dynamic_xtalk_correction_calc_new_xtalk( + Dev, + xtalk_offset_out, + pconfig, + pout, + 0, + + 0 + + ); + + + + pout->smudge_corr_valid = 2; + + + + continue_processing = CONT_RESET; + } else { + + + VL53L1_dynamic_xtalk_correction_calc_new_xtalk( + Dev, + xtalk_offset_out, + pconfig, + pout, + 0, + + 1 + + ); + } + + + + if (continue_processing == CONT_RESET) { + pint->accumulator = 0; + pint->current_samples = 0; + pint->nodetect_counter = 0; + } + } + + LOG_FUNCTION_END(status); + + return status; +} + +VL53L1_Error VL53L1_dynamic_xtalk_correction_data_init( + VL53L1_DEV Dev + ) +{ + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_LLDriverResults_t *pres = VL53L1DevStructGetLLResultsHandle(Dev); + + LOG_FUNCTION_START(""); + + + + + pdev->smudge_correct_config.smudge_corr_enabled = 1; + pdev->smudge_correct_config.smudge_corr_apply_enabled = 1; + pdev->smudge_correct_config.smudge_corr_single_apply = + VL53L1_TUNINGPARM_DYNXTALK_SMUDGE_COR_SINGLE_APPLY_DEFAULT; + + pdev->smudge_correct_config.smudge_margin = + VL53L1_TUNINGPARM_DYNXTALK_SMUDGE_MARGIN_DEFAULT; + pdev->smudge_correct_config.noise_margin = + VL53L1_TUNINGPARM_DYNXTALK_NOISE_MARGIN_DEFAULT; + pdev->smudge_correct_config.user_xtalk_offset_limit = + VL53L1_TUNINGPARM_DYNXTALK_XTALK_OFFSET_LIMIT_DEFAULT; + pdev->smudge_correct_config.user_xtalk_offset_limit_hi = + VL53L1_TUNINGPARM_DYNXTALK_XTALK_OFFSET_LIMIT_HI_DEFAULT; + pdev->smudge_correct_config.sample_limit = + VL53L1_TUNINGPARM_DYNXTALK_SAMPLE_LIMIT_DEFAULT; + pdev->smudge_correct_config.single_xtalk_delta = + VL53L1_TUNINGPARM_DYNXTALK_SINGLE_XTALK_DELTA_DEFAULT; + pdev->smudge_correct_config.averaged_xtalk_delta = + VL53L1_TUNINGPARM_DYNXTALK_AVERAGED_XTALK_DELTA_DEFAULT; + pdev->smudge_correct_config.smudge_corr_clip_limit = + VL53L1_TUNINGPARM_DYNXTALK_CLIP_LIMIT_DEFAULT; + pdev->smudge_correct_config.smudge_corr_ambient_threshold = + VL53L1_TUNINGPARM_DYNXTALK_XTALK_AMB_THRESHOLD_DEFAULT; + pdev->smudge_correct_config.scaler_calc_method = + 0; + + pdev->smudge_correct_config.x_gradient_scaler = + VL53L1_TUNINGPARM_DYNXTALK_XGRADIENT_SCALER_DEFAULT; + pdev->smudge_correct_config.y_gradient_scaler = + VL53L1_TUNINGPARM_DYNXTALK_YGRADIENT_SCALER_DEFAULT; + pdev->smudge_correct_config.user_scaler_set = + VL53L1_TUNINGPARM_DYNXTALK_USER_SCALER_SET_DEFAULT; + pdev->smudge_correct_config.nodetect_ambient_threshold = + VL53L1_TUNINGPARM_DYNXTALK_NODETECT_AMB_THRESHOLD_KCPS_DEFAULT; + pdev->smudge_correct_config.nodetect_sample_limit = + VL53L1_TUNINGPARM_DYNXTALK_NODETECT_SAMPLE_LIMIT_DEFAULT; + pdev->smudge_correct_config.nodetect_xtalk_offset = + VL53L1_TUNINGPARM_DYNXTALK_NODETECT_XTALK_OFFSET_KCPS_DEFAULT; + pdev->smudge_correct_config.nodetect_min_range_mm = + VL53L1_TUNINGPARM_DYNXTALK_NODETECT_MIN_RANGE_MM_DEFAULT; + + + + pdev->smudge_corrector_internals.current_samples = 0; + pdev->smudge_corrector_internals.required_samples = 0; + pdev->smudge_corrector_internals.accumulator = 0; + pdev->smudge_corrector_internals.nodetect_counter = 0; + + + + VL53L1_dynamic_xtalk_correction_output_init(pres); + + LOG_FUNCTION_END(status); + + return status; +} + +VL53L1_Error VL53L1_dynamic_xtalk_correction_output_init( + VL53L1_LLDriverResults_t *pres + ) +{ + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_smudge_corrector_data_t *pdata; + + LOG_FUNCTION_START(""); + + + + pdata = &(pres->range_results.smudge_corrector_data); + + pdata->smudge_corr_valid = 0; + pdata->smudge_corr_clipped = 0; + pdata->single_xtalk_delta_flag = 0; + pdata->averaged_xtalk_delta_flag = 0; + pdata->sample_limit_exceeded_flag = 0; + pdata->gradient_zero_flag = 0; + pdata->new_xtalk_applied_flag = 0; + + pdata->algo__crosstalk_compensation_plane_offset_kcps = 0; + pdata->algo__crosstalk_compensation_x_plane_gradient_kcps = 0; + pdata->algo__crosstalk_compensation_y_plane_gradient_kcps = 0; + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_xtalk_cal_data_init( + VL53L1_DEV Dev + ) +{ + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + + + + pdev->xtalk_cal.algo__crosstalk_compensation_plane_offset_kcps = 0; + pdev->xtalk_cal.algo__crosstalk_compensation_x_plane_gradient_kcps = 0; + pdev->xtalk_cal.algo__crosstalk_compensation_y_plane_gradient_kcps = 0; + + LOG_FUNCTION_END(status); + + return status; +} + + + + + + + + +VL53L1_Error VL53L1_low_power_auto_data_init( + VL53L1_DEV Dev + ) +{ + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + pdev->low_power_auto_data.vhv_loop_bound = + VL53L1_TUNINGPARM_LOWPOWERAUTO_VHV_LOOP_BOUND_DEFAULT; + pdev->low_power_auto_data.is_low_power_auto_mode = 0; + pdev->low_power_auto_data.low_power_auto_range_count = 0; + pdev->low_power_auto_data.saved_interrupt_config = 0; + pdev->low_power_auto_data.saved_vhv_init = 0; + pdev->low_power_auto_data.saved_vhv_timeout = 0; + pdev->low_power_auto_data.first_run_phasecal_result = 0; + pdev->low_power_auto_data.dss__total_rate_per_spad_mcps = 0; + pdev->low_power_auto_data.dss__required_spads = 0; + + LOG_FUNCTION_END(status); + + return status; +} + +VL53L1_Error VL53L1_low_power_auto_data_stop_range( + VL53L1_DEV Dev + ) +{ + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + + + + + pdev->low_power_auto_data.low_power_auto_range_count = 0xFF; + + pdev->low_power_auto_data.first_run_phasecal_result = 0; + pdev->low_power_auto_data.dss__total_rate_per_spad_mcps = 0; + pdev->low_power_auto_data.dss__required_spads = 0; + + + + if (pdev->low_power_auto_data.saved_vhv_init != 0) + pdev->stat_nvm.vhv_config__init = + pdev->low_power_auto_data.saved_vhv_init; + if (pdev->low_power_auto_data.saved_vhv_timeout != 0) + pdev->stat_nvm.vhv_config__timeout_macrop_loop_bound = + pdev->low_power_auto_data.saved_vhv_timeout; + + + + pdev->gen_cfg.phasecal_config__override = 0x00; + + LOG_FUNCTION_END(status); + + return status; +} + +VL53L1_Error VL53L1_config_low_power_auto_mode( + VL53L1_general_config_t *pgeneral, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_low_power_auto_data_t *plpadata + ) +{ + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + plpadata->is_low_power_auto_mode = 1; + + + + plpadata->low_power_auto_range_count = 0; + + + + pdynamic->system__sequence_config = + VL53L1_SEQUENCE_VHV_EN | + VL53L1_SEQUENCE_PHASECAL_EN | + VL53L1_SEQUENCE_DSS1_EN | + + + + + + + VL53L1_SEQUENCE_RANGE_EN; + + + + pgeneral->dss_config__manual_effective_spads_select = 200 << 8; + pgeneral->dss_config__roi_mode_control = + VL53L1_DEVICEDSSMODE__REQUESTED_EFFFECTIVE_SPADS; + + LOG_FUNCTION_END(status); + + return status; +} + +VL53L1_Error VL53L1_low_power_auto_setup_manual_calibration( + VL53L1_DEV Dev) +{ + + + + + + + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + pdev->low_power_auto_data.saved_vhv_init = + pdev->stat_nvm.vhv_config__init; + pdev->low_power_auto_data.saved_vhv_timeout = + pdev->stat_nvm.vhv_config__timeout_macrop_loop_bound; + + + + pdev->stat_nvm.vhv_config__init &= 0x7F; + + + pdev->stat_nvm.vhv_config__timeout_macrop_loop_bound = + (pdev->stat_nvm.vhv_config__timeout_macrop_loop_bound & 0x03) + + (pdev->low_power_auto_data.vhv_loop_bound << 2); + + + pdev->gen_cfg.phasecal_config__override = 0x01; + pdev->low_power_auto_data.first_run_phasecal_result = + pdev->dbg_results.phasecal_result__vcsel_start; + pdev->gen_cfg.cal_config__vcsel_start = + pdev->low_power_auto_data.first_run_phasecal_result; + + LOG_FUNCTION_END(status); + + return status; +} + +VL53L1_Error VL53L1_low_power_auto_update_DSS( + VL53L1_DEV Dev) +{ + + + + + + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + VL53L1_system_results_t *pS = &(pdev->sys_results); + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + uint32_t utemp32a; + + LOG_FUNCTION_START(""); + + + + + + + utemp32a = + pS->result__peak_signal_count_rate_crosstalk_corrected_mcps_sd0 + + pS->result__ambient_count_rate_mcps_sd0; + + + + if (utemp32a > 0xFFFF) + utemp32a = 0xFFFF; + + + + + + utemp32a = utemp32a << 16; + + + + if (pdev->sys_results.result__dss_actual_effective_spads_sd0 == 0) + status = VL53L1_ERROR_DIVISION_BY_ZERO; + else { + + + utemp32a = utemp32a / + pdev->sys_results.result__dss_actual_effective_spads_sd0; + + + pdev->low_power_auto_data.dss__total_rate_per_spad_mcps = + utemp32a; + + + + + utemp32a = pdev->stat_cfg.dss_config__target_total_rate_mcps << + 16; + + + + if (pdev->low_power_auto_data.dss__total_rate_per_spad_mcps + == 0) + status = VL53L1_ERROR_DIVISION_BY_ZERO; + else { + + + + utemp32a = utemp32a / + pdev->low_power_auto_data.dss__total_rate_per_spad_mcps; + + + + if (utemp32a > 0xFFFF) + utemp32a = 0xFFFF; + + + + pdev->low_power_auto_data.dss__required_spads = + (uint16_t)utemp32a; + + + + pdev->gen_cfg.dss_config__manual_effective_spads_select + = pdev->low_power_auto_data.dss__required_spads; + pdev->gen_cfg.dss_config__roi_mode_control = + VL53L1_DEVICEDSSMODE__REQUESTED_EFFFECTIVE_SPADS; + } + + } + + if (status == VL53L1_ERROR_DIVISION_BY_ZERO) { + + + + + + + pdev->low_power_auto_data.dss__required_spads = 0x8000; + + + + pdev->gen_cfg.dss_config__manual_effective_spads_select = + pdev->low_power_auto_data.dss__required_spads; + pdev->gen_cfg.dss_config__roi_mode_control = + VL53L1_DEVICEDSSMODE__REQUESTED_EFFFECTIVE_SPADS; + + + + status = VL53L1_ERROR_NONE; + } + + LOG_FUNCTION_END(status); + + return status; +} + + + + + diff --git a/drivers/input/misc/vl53L1/lito/src/vl53l1_core_support.c b/drivers/input/misc/vl53L1/lito/src/vl53l1_core_support.c new file mode 100644 index 000000000000..8a8947b6cfe2 --- /dev/null +++ b/drivers/input/misc/vl53L1/lito/src/vl53l1_core_support.c @@ -0,0 +1,938 @@ + +/******************************************************************************* + * Copyright (c) 2017, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#include "vl53l1_ll_def.h" +#include "vl53l1_ll_device.h" +#include "vl53l1_platform_log.h" +#include "vl53l1_core_support.h" +#include "vl53l1_platform_user_data.h" +#include "vl53l1_platform_user_defines.h" + + + + + + +#define LOG_FUNCTION_START(fmt, ...) \ + _LOG_FUNCTION_START(VL53L1_TRACE_MODULE_CORE, fmt, ##__VA_ARGS__) +#define LOG_FUNCTION_END(status, ...) \ + _LOG_FUNCTION_END(VL53L1_TRACE_MODULE_CORE, status, ##__VA_ARGS__) +#define LOG_FUNCTION_END_FMT(status, fmt, ...) \ + _LOG_FUNCTION_END_FMT(VL53L1_TRACE_MODULE_CORE, \ + status, fmt, ##__VA_ARGS__) + +#define trace_print(level, ...) \ + _LOG_TRACE_PRINT(VL53L1_TRACE_MODULE_CORE, \ + level, VL53L1_TRACE_FUNCTION_NONE, ##__VA_ARGS__) + + +uint32_t VL53L1_calc_pll_period_us( + uint16_t fast_osc_frequency) +{ + + + + + + + + + + + + + + + uint32_t pll_period_us = 0; + + LOG_FUNCTION_START(""); + + pll_period_us = (0x01 << 30) / fast_osc_frequency; + + + + + + + + LOG_FUNCTION_END(0); + + return pll_period_us; +} + + +uint32_t VL53L1_duration_maths( + uint32_t pll_period_us, + uint32_t vcsel_parm_pclks, + uint32_t window_vclks, + uint32_t elapsed_mclks) +{ + + + + + + + + + + + uint64_t tmp_long_int = 0; + uint32_t duration_us = 0; + + + + + + + duration_us = window_vclks * pll_period_us; + + + + + + duration_us = duration_us >> 12; + + + + tmp_long_int = (uint64_t)duration_us; + + + + + + + duration_us = elapsed_mclks * vcsel_parm_pclks; + + + + + + duration_us = duration_us >> 4; + + + + + + tmp_long_int = tmp_long_int * (uint64_t)duration_us; + + + + + + tmp_long_int = tmp_long_int >> 12; + + + + if (tmp_long_int > 0xFFFFFFFF) + tmp_long_int = 0xFFFFFFFF; + + duration_us = (uint32_t)tmp_long_int; + + return duration_us; +} + + +uint32_t VL53L1_events_per_spad_maths( + int32_t VL53L1_p_013, + uint16_t num_spads, + uint32_t duration) +{ + uint64_t total_hist_counts = 0; + uint64_t xtalk_per_spad = 0; + uint32_t rate_per_spad_kcps = 0; + + + + + + + + + + + + + + + + + + uint64_t dividend = ((uint64_t)VL53L1_p_013 + * 1000 * 256); + + total_hist_counts = do_division_u(dividend, (uint64_t)num_spads); + + + + + if (duration > 0) { + + + + + + + + + uint64_t dividend = (((uint64_t)(total_hist_counts << 11)) + + ((uint64_t)duration / 2)); + + xtalk_per_spad = do_division_u(dividend, (uint64_t)duration); + } else { + xtalk_per_spad = (uint64_t)(total_hist_counts << 11); + } + + rate_per_spad_kcps = (uint32_t)xtalk_per_spad; + + return rate_per_spad_kcps; +} + + +uint32_t VL53L1_isqrt(uint32_t num) +{ + + + + + + + + + uint32_t res = 0; + uint32_t bit = 1 << 30; + + + + + while (bit > num) + bit >>= 2; + + while (bit != 0) { + if (num >= res + bit) { + num -= res + bit; + res = (res >> 1) + bit; + } else { + res >>= 1; + } + bit >>= 2; + } + + return res; +} + + +void VL53L1_hist_calc_zero_distance_phase( + VL53L1_histogram_bin_data_t *pdata) +{ + + + + + + + uint32_t period = 0; + uint32_t VL53L1_p_017 = 0; + + LOG_FUNCTION_START(""); + + period = 2048 * + (uint32_t)VL53L1_decode_vcsel_period(pdata->VL53L1_p_009); + + VL53L1_p_017 = period; + VL53L1_p_017 += (uint32_t)pdata->phasecal_result__reference_phase; + VL53L1_p_017 += (2048 * (uint32_t)pdata->phasecal_result__vcsel_start); + VL53L1_p_017 -= (2048 * (uint32_t)pdata->cal_config__vcsel_start); + + VL53L1_p_017 = VL53L1_p_017 % period; + + pdata->zero_distance_phase = (uint16_t)VL53L1_p_017; + + LOG_FUNCTION_END(0); +} + + +void VL53L1_hist_estimate_ambient_from_thresholded_bins( + int32_t ambient_threshold_sigma, + VL53L1_histogram_bin_data_t *pdata) +{ + + + + + + + + + + uint8_t bin = 0; + int32_t VL53L1_p_032 = 0; + + LOG_FUNCTION_START(""); + + + + + + + VL53L1_hist_find_min_max_bin_values(pdata); + + + + + + + + VL53L1_p_032 = + (int32_t)VL53L1_isqrt((uint32_t)pdata->min_bin_value); + VL53L1_p_032 *= ambient_threshold_sigma; + VL53L1_p_032 += 0x07; + VL53L1_p_032 = VL53L1_p_032 >> 4; + VL53L1_p_032 += pdata->min_bin_value; + + + + + + + pdata->number_of_ambient_samples = 0; + pdata->ambient_events_sum = 0; + + for (bin = 0; bin < pdata->VL53L1_p_024; bin++) + if (pdata->bin_data[bin] < VL53L1_p_032) { + pdata->ambient_events_sum += pdata->bin_data[bin]; + pdata->number_of_ambient_samples++; + } + + + + + + + if (pdata->number_of_ambient_samples > 0) { + pdata->VL53L1_p_004 = + pdata->ambient_events_sum; + pdata->VL53L1_p_004 += + ((int32_t)pdata->number_of_ambient_samples/2); + pdata->VL53L1_p_004 /= + (int32_t)pdata->number_of_ambient_samples; + } + + LOG_FUNCTION_END(0); +} + + +void VL53L1_hist_remove_ambient_bins( + VL53L1_histogram_bin_data_t *pdata) +{ + + + + + + + + uint8_t bin = 0; + uint8_t lc = 0; + uint8_t i = 0; + + + + + if ((pdata->bin_seq[0] & 0x07) == 0x07) { + + i = 0; + for (lc = 0; lc < VL53L1_MAX_BIN_SEQUENCE_LENGTH; lc++) { + if ((pdata->bin_seq[lc] & 0x07) != 0x07) { + pdata->bin_seq[i] = pdata->bin_seq[lc]; + pdata->bin_rep[i] = pdata->bin_rep[lc]; + i++; + } + } + + + + + + + for (lc = i; lc < VL53L1_MAX_BIN_SEQUENCE_LENGTH; lc++) { + pdata->bin_seq[lc] = VL53L1_MAX_BIN_SEQUENCE_CODE + 1; + pdata->bin_rep[lc] = 0; + } + } + + if (pdata->number_of_ambient_bins > 0) { + + + + for (bin = pdata->number_of_ambient_bins; + bin < pdata->VL53L1_p_023; bin++) { + pdata->bin_data[bin-pdata->number_of_ambient_bins] = + pdata->bin_data[bin]; + } + + + + pdata->VL53L1_p_024 = + pdata->VL53L1_p_024 - + pdata->number_of_ambient_bins; + pdata->number_of_ambient_bins = 0; + } +} + + +uint32_t VL53L1_calc_pll_period_mm( + uint16_t fast_osc_frequency) +{ + + + + + + + uint32_t pll_period_us = 0; + uint32_t pll_period_mm = 0; + + LOG_FUNCTION_START(""); + + + + + + + pll_period_us = VL53L1_calc_pll_period_us(fast_osc_frequency); + + + + + + + + + + + + + pll_period_mm = + VL53L1_SPEED_OF_LIGHT_IN_AIR_DIV_8 * + (pll_period_us >> 2); + + + + pll_period_mm = (pll_period_mm + (0x01<<15)) >> 16; + + LOG_FUNCTION_END(0); + + return pll_period_mm; +} + + +uint16_t VL53L1_rate_maths( + int32_t VL53L1_p_008, + uint32_t time_us) +{ + + + + + + + + + + + + + uint32_t tmp_int = 0; + uint32_t frac_bits = 7; + uint16_t rate_mcps = 0; + + + + + + + + if (VL53L1_p_008 > VL53L1_SPAD_TOTAL_COUNT_MAX) + tmp_int = VL53L1_SPAD_TOTAL_COUNT_MAX; + else if (VL53L1_p_008 > 0) + tmp_int = (uint32_t)VL53L1_p_008; + + + + + + + + + if (VL53L1_p_008 > VL53L1_SPAD_TOTAL_COUNT_RES_THRES) + frac_bits = 3; + else + frac_bits = 7; + + + + + + + + if (time_us > 0) + tmp_int = ((tmp_int << frac_bits) + (time_us / 2)) / time_us; + + + + + + if (VL53L1_p_008 > VL53L1_SPAD_TOTAL_COUNT_RES_THRES) + tmp_int = tmp_int << 4; + + + + + + + + if (tmp_int > 0xFFFF) + tmp_int = 0xFFFF; + + rate_mcps = (uint16_t)tmp_int; + + return rate_mcps; +} + + +uint16_t VL53L1_rate_per_spad_maths( + uint32_t frac_bits, + uint32_t peak_count_rate, + uint16_t num_spads, + uint32_t max_output_value) +{ + + uint32_t tmp_int = 0; + + + + uint16_t rate_per_spad = 0; + + + + + + + + + + if (num_spads > 0) { + tmp_int = (peak_count_rate << 8) << frac_bits; + tmp_int = (tmp_int + + ((uint32_t)num_spads / 2)) / + (uint32_t)num_spads; + } else { + tmp_int = ((peak_count_rate) << frac_bits); + } + + + + + if (tmp_int > max_output_value) + tmp_int = max_output_value; + + rate_per_spad = (uint16_t)tmp_int; + + return rate_per_spad; +} + + +int32_t VL53L1_range_maths( + uint16_t fast_osc_frequency, + uint16_t VL53L1_p_017, + uint16_t zero_distance_phase, + uint8_t fractional_bits, + int32_t gain_factor, + int32_t range_offset_mm) +{ + + + + + + uint32_t pll_period_us = 0; + + int64_t tmp_long_int = 0; + int32_t range_mm = 0; + int32_t range_mm_10 = 0; + + + + + pll_period_us = VL53L1_calc_pll_period_us(fast_osc_frequency); + + + + + + + + + + + tmp_long_int = (int64_t)VL53L1_p_017 - (int64_t)zero_distance_phase; + + + + + + + + + + + tmp_long_int = tmp_long_int * (int64_t)pll_period_us; + + + + + + + tmp_long_int = tmp_long_int / (0x01 << 9); + + + + + + + + + + + + tmp_long_int = tmp_long_int * VL53L1_SPEED_OF_LIGHT_IN_AIR_DIV_8; + + + + + + + tmp_long_int = tmp_long_int / (0x01 << 22); + + + + range_mm = (int32_t)tmp_long_int + range_offset_mm; + + + + range_mm *= gain_factor; + range_mm += 0x0400; + range_mm /= 0x0800; + + + + if (fractional_bits == 0) { + range_mm_10 = range_mm * 10; + range_mm_10 = range_mm_10 / (0x01 << 2); + if ((range_mm_10 % 10) < 5) + range_mm = (int16_t)(range_mm_10 / 10); + else + range_mm = (int16_t)(range_mm_10 / 10 + 1); + } else if (fractional_bits == 1) + range_mm = range_mm / (0x01 << 1); + + return range_mm; +} + + +uint8_t VL53L1_decode_vcsel_period(uint8_t vcsel_period_reg) +{ + + + + + + + uint8_t VL53L1_p_031 = 0; + + VL53L1_p_031 = (vcsel_period_reg + 1) << 1; + + return VL53L1_p_031; +} + + +void VL53L1_copy_xtalk_bin_data_to_histogram_data_struct( + VL53L1_xtalk_histogram_shape_t *pxtalk, + VL53L1_histogram_bin_data_t *phist) +{ + + + + + + + phist->cal_config__vcsel_start = + pxtalk->cal_config__vcsel_start; + phist->VL53L1_p_019 = + pxtalk->VL53L1_p_019; + phist->VL53L1_p_022 = + pxtalk->VL53L1_p_022; + + phist->phasecal_result__reference_phase = + pxtalk->phasecal_result__reference_phase; + phist->phasecal_result__vcsel_start = + pxtalk->phasecal_result__vcsel_start; + + phist->vcsel_width = + pxtalk->vcsel_width; + phist->zero_distance_phase = + pxtalk->zero_distance_phase; + + phist->zone_id = pxtalk->zone_id; + phist->VL53L1_p_023 = pxtalk->VL53L1_p_023; + phist->time_stamp = pxtalk->time_stamp; +} + + +void VL53L1_init_histogram_bin_data_struct( + int32_t bin_value, + uint16_t VL53L1_p_024, + VL53L1_histogram_bin_data_t *pdata) +{ + + + + + + + uint16_t i = 0; + + pdata->cfg_device_state = VL53L1_DEVICESTATE_SW_STANDBY; + pdata->rd_device_state = VL53L1_DEVICESTATE_SW_STANDBY; + + pdata->zone_id = 0; + pdata->time_stamp = 0; + + pdata->VL53L1_p_022 = 0; + pdata->VL53L1_p_023 = VL53L1_HISTOGRAM_BUFFER_SIZE; + pdata->VL53L1_p_024 = (uint8_t)VL53L1_p_024; + pdata->number_of_ambient_bins = 0; + + pdata->result__interrupt_status = 0; + pdata->result__range_status = 0; + pdata->result__report_status = 0; + pdata->result__stream_count = 0; + + pdata->result__dss_actual_effective_spads = 0; + pdata->phasecal_result__reference_phase = 0; + pdata->phasecal_result__vcsel_start = 0; + pdata->cal_config__vcsel_start = 0; + + pdata->vcsel_width = 0; + pdata->VL53L1_p_009 = 0; + pdata->VL53L1_p_019 = 0; + pdata->total_periods_elapsed = 0; + + pdata->min_bin_value = 0; + pdata->max_bin_value = 0; + + pdata->zero_distance_phase = 0; + pdata->number_of_ambient_samples = 0; + pdata->ambient_events_sum = 0; + pdata->VL53L1_p_004 = 0; + + for (i = 0; i < VL53L1_MAX_BIN_SEQUENCE_LENGTH; i++) + pdata->bin_seq[i] = (uint8_t)i; + + for (i = 0; i < VL53L1_MAX_BIN_SEQUENCE_LENGTH; i++) + pdata->bin_rep[i] = 1; + + + for (i = 0; i < VL53L1_HISTOGRAM_BUFFER_SIZE; i++) + if (i < VL53L1_p_024) + pdata->bin_data[i] = bin_value; + else + pdata->bin_data[i] = 0; + + +} + + +void VL53L1_decode_row_col( + uint8_t spad_number, + uint8_t *prow, + uint8_t *pcol) +{ + + + + + + + + if (spad_number > 127) { + *prow = 8 + ((255-spad_number) & 0x07); + *pcol = (spad_number-128) >> 3; + } else { + *prow = spad_number & 0x07; + *pcol = (127-spad_number) >> 3; + } +} + + +void VL53L1_hist_find_min_max_bin_values( + VL53L1_histogram_bin_data_t *pdata) +{ + + + + + + uint8_t bin = 0; + + LOG_FUNCTION_START(""); + + for (bin = 0; bin < pdata->VL53L1_p_024; bin++) { + + if (bin == 0 || pdata->min_bin_value >= pdata->bin_data[bin]) + pdata->min_bin_value = pdata->bin_data[bin]; + + if (bin == 0 || pdata->max_bin_value <= pdata->bin_data[bin]) + pdata->max_bin_value = pdata->bin_data[bin]; + + } + + LOG_FUNCTION_END(0); + +} + + +void VL53L1_hist_estimate_ambient_from_ambient_bins( + VL53L1_histogram_bin_data_t *pdata) +{ + + + + + + + uint8_t bin = 0; + + LOG_FUNCTION_START(""); + + if (pdata->number_of_ambient_bins > 0) { + + pdata->number_of_ambient_samples = + pdata->number_of_ambient_bins; + + + + + pdata->ambient_events_sum = 0; + for (bin = 0; bin < pdata->number_of_ambient_bins; bin++) + pdata->ambient_events_sum += pdata->bin_data[bin]; + + pdata->VL53L1_p_004 = pdata->ambient_events_sum; + pdata->VL53L1_p_004 += + ((int32_t)pdata->number_of_ambient_bins / 2); + pdata->VL53L1_p_004 /= + (int32_t)pdata->number_of_ambient_bins; + + } + + LOG_FUNCTION_END(0); +} + + diff --git a/drivers/input/misc/vl53L1/lito/src/vl53l1_error_strings.c b/drivers/input/misc/vl53L1/lito/src/vl53l1_error_strings.c new file mode 100644 index 000000000000..e8e9920e4a36 --- /dev/null +++ b/drivers/input/misc/vl53L1/lito/src/vl53l1_error_strings.c @@ -0,0 +1,334 @@ + +/******************************************************************************* + * Copyright (c) 2017, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#include "vl53l1_error_codes.h" +#include "vl53l1_error_strings.h" +#include "vl53l1_platform_log.h" +#include "vl53l1_ll_def.h" + +#define LOG_FUNCTION_START(fmt, ...) \ + _LOG_FUNCTION_START(VL53L1_TRACE_MODULE_API, fmt, ##__VA_ARGS__) +#define LOG_FUNCTION_END(status, ...) \ + _LOG_FUNCTION_END(VL53L1_TRACE_MODULE_API, status, ##__VA_ARGS__) +#define LOG_FUNCTION_END_FMT(status, fmt, ...) \ + _LOG_FUNCTION_END_FMT(VL53L1_TRACE_MODULE_API, \ + status, fmt, ##__VA_ARGS__) + + +VL53L1_Error VL53L1_get_pal_error_string( +#ifndef VL53L1_USE_EMPTY_STRING + VL53L1_Error PalErrorCode, +#endif + char *pPalErrorString) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + +#ifdef VL53L1_USE_EMPTY_STRING + SUPPRESS_UNUSED_WARNING(PalErrorCode); +#endif + + LOG_FUNCTION_START(""); + +#ifdef VL53L1_USE_EMPTY_STRING + VL53L1_COPYSTRING(pPalErrorString, ""); +#else + + switch (PalErrorCode) { + case VL53L1_ERROR_NONE: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_NONE); + break; + case VL53L1_ERROR_CALIBRATION_WARNING: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_CALIBRATION_WARNING); + break; + case VL53L1_ERROR_MIN_CLIPPED: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_MIN_CLIPPED); + break; + case VL53L1_ERROR_UNDEFINED: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_UNDEFINED); + break; + case VL53L1_ERROR_INVALID_PARAMS: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_INVALID_PARAMS); + break; + case VL53L1_ERROR_NOT_SUPPORTED: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_NOT_SUPPORTED); + break; + case VL53L1_ERROR_RANGE_ERROR: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_RANGE_ERROR); + break; + case VL53L1_ERROR_TIME_OUT: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_TIME_OUT); + break; + case VL53L1_ERROR_MODE_NOT_SUPPORTED: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_MODE_NOT_SUPPORTED); + break; + case VL53L1_ERROR_BUFFER_TOO_SMALL: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_BUFFER_TOO_SMALL); + break; + case VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_COMMS_BUFFER_TOO_SMALL); + break; + case VL53L1_ERROR_GPIO_NOT_EXISTING: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_GPIO_NOT_EXISTING); + break; + case VL53L1_ERROR_GPIO_FUNCTIONALITY_NOT_SUPPORTED: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_GPIO_FUNCTIONALITY_NOT_SUPPORTED); + break; + case VL53L1_ERROR_CONTROL_INTERFACE: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_CONTROL_INTERFACE); + break; + case VL53L1_ERROR_INVALID_COMMAND: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_INVALID_COMMAND); + break; + case VL53L1_ERROR_DIVISION_BY_ZERO: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_DIVISION_BY_ZERO); + break; + case VL53L1_ERROR_REF_SPAD_INIT: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_REF_SPAD_INIT); + break; + case VL53L1_ERROR_GPH_SYNC_CHECK_FAIL: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_GPH_SYNC_CHECK_FAIL); + break; + case VL53L1_ERROR_STREAM_COUNT_CHECK_FAIL: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_STREAM_COUNT_CHECK_FAIL); + break; + case VL53L1_ERROR_GPH_ID_CHECK_FAIL: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_GPH_ID_CHECK_FAIL); + break; + case VL53L1_ERROR_ZONE_STREAM_COUNT_CHECK_FAIL: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_ZONE_STREAM_COUNT_CHECK_FAIL); + break; + case VL53L1_ERROR_ZONE_GPH_ID_CHECK_FAIL: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_ZONE_GPH_ID_CHECK_FAIL); + break; + + case VL53L1_ERROR_XTALK_EXTRACTION_NO_SAMPLE_FAIL: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_XTALK_EXTRACTION_NO_SAMPLES_FAIL); + break; + case VL53L1_ERROR_XTALK_EXTRACTION_SIGMA_LIMIT_FAIL: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_XTALK_EXTRACTION_SIGMA_LIMIT_FAIL); + break; + + case VL53L1_ERROR_OFFSET_CAL_NO_SAMPLE_FAIL: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_OFFSET_CAL_NO_SAMPLE_FAIL); + break; + case VL53L1_ERROR_OFFSET_CAL_NO_SPADS_ENABLED_FAIL: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_OFFSET_CAL_NO_SPADS_ENABLED_FAIL); + break; + case VL53L1_ERROR_ZONE_CAL_NO_SAMPLE_FAIL: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_ZONE_CAL_NO_SAMPLE_FAIL); + break; + + case VL53L1_WARNING_OFFSET_CAL_MISSING_SAMPLES: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_WARNING_OFFSET_CAL_MISSING_SAMPLES); + break; + case VL53L1_WARNING_OFFSET_CAL_SIGMA_TOO_HIGH: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_WARNING_OFFSET_CAL_SIGMA_TOO_HIGH); + break; + case VL53L1_WARNING_OFFSET_CAL_RATE_TOO_HIGH: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_WARNING_OFFSET_CAL_RATE_TOO_HIGH); + break; + case VL53L1_WARNING_OFFSET_CAL_SPAD_COUNT_TOO_LOW: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_WARNING_OFFSET_CAL_SPAD_COUNT_TOO_LOW); + break; + + case VL53L1_WARNING_ZONE_CAL_MISSING_SAMPLES: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_WARNING_ZONE_CAL_MISSING_SAMPLES); + break; + case VL53L1_WARNING_ZONE_CAL_SIGMA_TOO_HIGH: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_WARNING_ZONE_CAL_SIGMA_TOO_HIGH); + break; + case VL53L1_WARNING_ZONE_CAL_RATE_TOO_HIGH: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_WARNING_ZONE_CAL_RATE_TOO_HIGH); + break; + + case VL53L1_WARNING_REF_SPAD_CHAR_NOT_ENOUGH_SPADS: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_WARNING_REF_SPAD_CHAR_NOT_ENOUGH_SPADS); + break; + case VL53L1_WARNING_REF_SPAD_CHAR_RATE_TOO_HIGH: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_WARNING_REF_SPAD_CHAR_RATE_TOO_HIGH); + break; + case VL53L1_WARNING_REF_SPAD_CHAR_RATE_TOO_LOW: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_WARNING_REF_SPAD_CHAR_RATE_TOO_LOW); + break; + + case VL53L1_WARNING_XTALK_MISSING_SAMPLES: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_WARNING_XTALK_MISSING_SAMPLES); + break; + case VL53L1_WARNING_XTALK_NO_SAMPLES_FOR_GRADIENT: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_WARNING_XTALK_NO_SAMPLES_FOR_GRADIENT); + break; + case VL53L1_WARNING_XTALK_SIGMA_LIMIT_FOR_GRADIENT: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_WARNING_XTALK_SIGMA_LIMIT_FOR_GRADIENT); + break; + + case VL53L1_ERROR_DEVICE_FIRMWARE_TOO_OLD: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_DEVICE_FIRMWARE_TOO_OLD); + break; + case VL53L1_ERROR_DEVICE_FIRMWARE_TOO_NEW: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_DEVICE_FIRMWARE_TOO_NEW); + break; + case VL53L1_ERROR_UNIT_TEST_FAIL: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_UNIT_TEST_FAIL); + break; + case VL53L1_ERROR_FILE_READ_FAIL: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_FILE_READ_FAIL); + break; + case VL53L1_ERROR_FILE_WRITE_FAIL: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_FILE_WRITE_FAIL); + break; + case VL53L1_ERROR_NOT_IMPLEMENTED: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_NOT_IMPLEMENTED); + break; + default: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_UNKNOW_ERROR_CODE); + } + +#endif + + LOG_FUNCTION_END(Status); + + return Status; +} + diff --git a/drivers/input/misc/vl53L1/lito/src/vl53l1_hist_char.c b/drivers/input/misc/vl53L1/lito/src/vl53l1_hist_char.c new file mode 100644 index 000000000000..5f13482e28e5 --- /dev/null +++ b/drivers/input/misc/vl53L1/lito/src/vl53l1_hist_char.c @@ -0,0 +1,282 @@ + +/******************************************************************************* + * Copyright (c) 2017, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#include + +#include + + + + + + + +#include "vl53l1_core.h" +#include "vl53l1_register_settings.h" +#include "vl53l1_hist_char.h" + +#define LOG_FUNCTION_START(fmt, ...) \ + _LOG_FUNCTION_START(VL53L1_TRACE_MODULE_HISTOGRAM, fmt, ##__VA_ARGS__) +#define LOG_FUNCTION_END(status, ...) \ + _LOG_FUNCTION_END(VL53L1_TRACE_MODULE_HISTOGRAM, status, ##__VA_ARGS__) +#define LOG_FUNCTION_END_FMT(status, fmt, ...) \ + _LOG_FUNCTION_END_FMT(VL53L1_TRACE_MODULE_HISTOGRAM,\ + status, fmt, ##__VA_ARGS__) + + +VL53L1_Error VL53L1_set_calib_config( + VL53L1_DEV Dev, + uint8_t vcsel_delay__a0, + uint8_t calib_1, + uint8_t calib_2, + uint8_t calib_3, + uint8_t calib_2__a0, + uint8_t spad_readout) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[3]; + + LOG_FUNCTION_START(""); + + + + + status = VL53L1_enable_powerforce(Dev); + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_disable_firmware(Dev); + + + + + + if (status == VL53L1_ERROR_NONE) { + status = VL53L1_WrByte( + Dev, + VL53L1_RANGING_CORE__VCSEL_DELAY__A0, + vcsel_delay__a0); + } + + + + + if (status == VL53L1_ERROR_NONE) { + + + + + + + + comms_buffer[0] = calib_1; + comms_buffer[1] = calib_2; + comms_buffer[2] = calib_3; + + status = VL53L1_WriteMulti( + Dev, + VL53L1_RANGING_CORE__CALIB_1, + comms_buffer, + 3); + } + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WrByte( + Dev, + VL53L1_RANGING_CORE__CALIB_2__A0, + calib_2__a0); + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WrByte( + Dev, + VL53L1_RANGING_CORE__SPAD_READOUT, + spad_readout); + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_firmware(Dev); + + LOG_FUNCTION_END(status); + + return status; +} + + + +VL53L1_Error VL53L1_set_hist_calib_pulse_delay( + VL53L1_DEV Dev, + uint8_t calib_delay) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + status = + VL53L1_set_calib_config( + Dev, + 0x01, + + calib_delay, + + 0x04, + + 0x08, + + 0x14, + + VL53L1_RANGING_CORE__SPAD_READOUT__CALIB_PULSES); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_disable_calib_pulse_delay( + VL53L1_DEV Dev) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + status = + VL53L1_set_calib_config( + Dev, + 0x00, + + 0x00, + + 0x00, + + 0x00, + + 0x00, + + VL53L1_RANGING_CORE__SPAD_READOUT__STANDARD); + + LOG_FUNCTION_END(status); + + return status; +} + + diff --git a/drivers/input/misc/vl53L1/lito/src/vl53l1_nvm.c b/drivers/input/misc/vl53L1/lito/src/vl53l1_nvm.c new file mode 100644 index 000000000000..1a0175fa6a3f --- /dev/null +++ b/drivers/input/misc/vl53L1/lito/src/vl53l1_nvm.c @@ -0,0 +1,1751 @@ + +/******************************************************************************* + * Copyright (c) 2017, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#ifdef _MSC_VER +#define snprintf _snprintf +#endif + + + + + + +#include "vl53l1_ll_def.h" +#include "vl53l1_platform.h" +#include "vl53l1_platform_log.h" +#include "vl53l1_register_map.h" +#include "vl53l1_core.h" +#include "vl53l1_nvm_structs.h" +#include "vl53l1_nvm_map.h" +#include "vl53l1_nvm.h" + + + + + +#define LOG_FUNCTION_START(fmt, ...) \ + _LOG_FUNCTION_START(VL53L1_TRACE_MODULE_NVM, fmt, ##__VA_ARGS__) +#define LOG_FUNCTION_END(status, ...) \ + _LOG_FUNCTION_END(VL53L1_TRACE_MODULE_NVM, status, ##__VA_ARGS__) +#define LOG_FUNCTION_END_FMT(status, fmt, ...) \ + _LOG_FUNCTION_END_FMT(VL53L1_TRACE_MODULE_NVM,\ + status, fmt, ##__VA_ARGS__) + +#define trace_print(level, ...) \ + _LOG_TRACE_PRINT(VL53L1_TRACE_MODULE_NVM, \ + level, VL53L1_TRACE_FUNCTION_NONE, ##__VA_ARGS__) + + +VL53L1_Error VL53L1_nvm_enable( + VL53L1_DEV Dev, + uint16_t nvm_ctrl_pulse_width, + int32_t nvm_power_up_delay_us) +{ + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_disable_firmware(Dev); + + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_powerforce(Dev); + + + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WaitUs( + Dev, + VL53L1_ENABLE_POWERFORCE_SETTLING_TIME_US); + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WrByte( + Dev, + VL53L1_RANGING_CORE__NVM_CTRL__PDN, + 0x01); + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WrByte( + Dev, + VL53L1_RANGING_CORE__CLK_CTRL1, + 0x05); + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WaitUs( + Dev, + nvm_power_up_delay_us); + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WrByte( + Dev, + VL53L1_RANGING_CORE__NVM_CTRL__MODE, + 0x01); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WrWord( + Dev, + VL53L1_RANGING_CORE__NVM_CTRL__PULSE_WIDTH_MSB, + nvm_ctrl_pulse_width); + + LOG_FUNCTION_END(status); + + return status; + +} + + +VL53L1_Error VL53L1_nvm_read( + VL53L1_DEV Dev, + uint8_t start_address, + uint8_t count, + uint8_t *pdata) +{ + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t nvm_addr = 0; + + LOG_FUNCTION_START(""); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%-12s = 0x%02X (%3u)\n", + "nvm_addr", nvm_addr, nvm_addr); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%-12s = 0x%02X (%3u)\n", + "count", count, count); + + for (nvm_addr = start_address; + nvm_addr < (start_address+count) ; nvm_addr++) { + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WrByte( + Dev, + VL53L1_RANGING_CORE__NVM_CTRL__ADDR, + nvm_addr); + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WrByte( + Dev, + VL53L1_RANGING_CORE__NVM_CTRL__READN, + 0x00); + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WaitUs( + Dev, + VL53L1_NVM_READ_TRIGGER_DELAY_US); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WrByte( + Dev, + VL53L1_RANGING_CORE__NVM_CTRL__READN, + 0x01); + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_ReadMulti( + Dev, + VL53L1_RANGING_CORE__NVM_CTRL__DATAOUT_MMM, + pdata, + 4); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "NVM address : 0x%02X = 0x%02X%02X%02X%02X\n", + nvm_addr, *pdata, *(pdata+1), *(pdata+2), *(pdata+3)); + + + + + pdata = pdata + 4; + + + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_nvm_disable( + VL53L1_DEV Dev) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_WrByte( + Dev, + VL53L1_RANGING_CORE__NVM_CTRL__READN, + 0x01); + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WrByte( + Dev, + VL53L1_RANGING_CORE__NVM_CTRL__PDN, + 0x00); + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_disable_powerforce(Dev); + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_firmware(Dev); + + LOG_FUNCTION_END(status); + + return status; + +} + + +VL53L1_Error VL53L1_nvm_format_decode( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_decoded_nvm_data_t *pdata) +{ + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + uint8_t i = 0; + uint8_t *ptmp = NULL; + int pptmp[VL53L1_NVM_MAX_FMT_RANGE_DATA]; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_NVM_SIZE_IN_BYTES) + return VL53L1_ERROR_BUFFER_TOO_SMALL; + + pdata->nvm__identification_model_id = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__IDENTIFICATION__MODEL_ID, + 0x000000FF, + 0, + 0); + pdata->nvm__identification_module_type = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__IDENTIFICATION__MODULE_TYPE, + 0x000000FF, + 0, + 0); + pdata->nvm__identification_revision_id = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__IDENTIFICATION__REVISION_ID, + 0x0000000F, + 0, + 0); + pdata->nvm__identification_module_id = + (uint16_t)VL53L1_i2c_decode_with_mask( + 2, + pbuffer + VL53L1_NVM__IDENTIFICATION__MODULE_ID, + 0x0000FFFF, + 0, + 0); + pdata->nvm__i2c_valid = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__I2C_VALID, + 0x000000FF, + 0, + 0); + pdata->nvm__i2c_device_address_ews = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__I2C_SLAVE__DEVICE_ADDRESS, + 0x000000FF, + 0, + 0); + pdata->nvm__ews__fast_osc_frequency = + (uint16_t)VL53L1_i2c_decode_with_mask( + 2, + pbuffer + + VL53L1_NVM__EWS__OSC_MEASURED__FAST_OSC_FREQUENCY, + 0x0000FFFF, + 0, + 0); + pdata->nvm__ews__fast_osc_trim_max = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__EWS__FAST_OSC_TRIM_MAX, + 0x0000007F, + 0, + 0); + pdata->nvm__ews__fast_osc_freq_set = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__EWS__FAST_OSC_FREQ_SET, + 0x00000007, + 0, + 0); + pdata->nvm__ews__slow_osc_calibration = + (uint16_t)VL53L1_i2c_decode_with_mask( + 2, + pbuffer + VL53L1_NVM__EWS__SLOW_OSC_CALIBRATION, + 0x000003FF, + 0, + 0); + pdata->nvm__fmt__fast_osc_frequency = + (uint16_t)VL53L1_i2c_decode_with_mask( + 2, + pbuffer + + VL53L1_NVM__FMT__OSC_MEASURED__FAST_OSC_FREQUENCY, + 0x0000FFFF, + 0, + 0); + pdata->nvm__fmt__fast_osc_trim_max = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__FAST_OSC_TRIM_MAX, + 0x0000007F, + 0, + 0); + pdata->nvm__fmt__fast_osc_freq_set = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__FAST_OSC_FREQ_SET, + 0x00000007, + 0, + 0); + pdata->nvm__fmt__slow_osc_calibration = + (uint16_t)VL53L1_i2c_decode_with_mask( + 2, + pbuffer + VL53L1_NVM__FMT__SLOW_OSC_CALIBRATION, + 0x000003FF, + 0, + 0); + pdata->nvm__vhv_config_unlock = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__VHV_CONFIG_UNLOCK, + 0x000000FF, + 0, + 0); + pdata->nvm__ref_selvddpix = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__REF_SELVDDPIX, + 0x0000000F, + 0, + 0); + pdata->nvm__ref_selvquench = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__REF_SELVQUENCH, + 0x00000078, + 3, + 0); + pdata->nvm__regavdd1v2_sel = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__REGAVDD1V2_SEL_REGDVDD1V2_SEL, + 0x0000000C, + 2, + 0); + pdata->nvm__regdvdd1v2_sel = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__REGAVDD1V2_SEL_REGDVDD1V2_SEL, + 0x00000003, + 0, + 0); + pdata->nvm__vhv_timeout__macrop = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + + VL53L1_NVM__VHV_CONFIG__TIMEOUT_MACROP_LOOP_BOUND, + 0x00000003, + 0, + 0); + pdata->nvm__vhv_loop_bound = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + + VL53L1_NVM__VHV_CONFIG__TIMEOUT_MACROP_LOOP_BOUND, + 0x000000FC, + 2, + 0); + pdata->nvm__vhv_count_threshold = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__VHV_CONFIG__COUNT_THRESH, + 0x000000FF, + 0, + 0); + pdata->nvm__vhv_offset = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__VHV_CONFIG__OFFSET, + 0x0000003F, + 0, + 0); + pdata->nvm__vhv_init_enable = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__VHV_CONFIG__INIT, + 0x00000080, + 7, + 0); + pdata->nvm__vhv_init_value = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__VHV_CONFIG__INIT, + 0x0000003F, + 0, + 0); + pdata->nvm__laser_safety_vcsel_trim_ll = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__LASER_SAFETY__VCSEL_TRIM_LL, + 0x00000007, + 0, + 0); + pdata->nvm__laser_safety_vcsel_selion_ll = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__LASER_SAFETY__VCSEL_SELION_LL, + 0x0000003F, + 0, + 0); + pdata->nvm__laser_safety_vcsel_selion_max_ll = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__LASER_SAFETY__VCSEL_SELION_MAX_LL, + 0x0000003F, + 0, + 0); + pdata->nvm__laser_safety_mult_ll = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__LASER_SAFETY__MULT_LL, + 0x0000003F, + 0, + 0); + pdata->nvm__laser_safety_clip_ll = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__LASER_SAFETY__CLIP_LL, + 0x0000003F, + 0, + 0); + pdata->nvm__laser_safety_vcsel_trim_ld = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__LASER_SAFETY__VCSEL_TRIM_LD, + 0x00000007, + 0, + 0); + pdata->nvm__laser_safety_vcsel_selion_ld = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__LASER_SAFETY__VCSEL_SELION_LD, + 0x0000003F, + 0, + 0); + pdata->nvm__laser_safety_vcsel_selion_max_ld = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__LASER_SAFETY__VCSEL_SELION_MAX_LD, + 0x0000003F, + 0, + 0); + pdata->nvm__laser_safety_mult_ld = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__LASER_SAFETY__MULT_LD, + 0x0000003F, + 0, + 0); + pdata->nvm__laser_safety_clip_ld = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__LASER_SAFETY__CLIP_LD, + 0x0000003F, + 0, + 0); + pdata->nvm__laser_safety_lock_byte = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__LASER_SAFETY_LOCK_BYTE, + 0x000000FF, + 0, + 0); + pdata->nvm__laser_safety_unlock_byte = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__LASER_SAFETY_UNLOCK_BYTE, + 0x000000FF, + 0, + 0); + + + + + ptmp = pbuffer + VL53L1_NVM__EWS__SPAD_ENABLES_RTN_0_; + for (i = 0 ; i < VL53L1_RTN_SPAD_BUFFER_SIZE ; i++) + pdata->nvm__ews__spad_enables_rtn[i] = *ptmp++; + + ptmp = pbuffer + VL53L1_NVM__EWS__SPAD_ENABLES_REF__LOC1_0_; + for (i = 0 ; i < VL53L1_REF_SPAD_BUFFER_SIZE ; i++) + pdata->nvm__ews__spad_enables_ref__loc1[i] = *ptmp++; + + ptmp = pbuffer + VL53L1_NVM__EWS__SPAD_ENABLES_REF__LOC2_0_; + for (i = 0 ; i < VL53L1_REF_SPAD_BUFFER_SIZE ; i++) + pdata->nvm__ews__spad_enables_ref__loc2[i] = *ptmp++; + + ptmp = pbuffer + VL53L1_NVM__EWS__SPAD_ENABLES_REF__LOC3_0_; + for (i = 0 ; i < VL53L1_REF_SPAD_BUFFER_SIZE ; i++) + pdata->nvm__ews__spad_enables_ref__loc3[i] = *ptmp++; + + + + + ptmp = pbuffer + VL53L1_NVM__FMT__SPAD_ENABLES_RTN_0_; + for (i = 0 ; i < VL53L1_RTN_SPAD_BUFFER_SIZE ; i++) + pdata->nvm__fmt__spad_enables_rtn[i] = *ptmp++; + + ptmp = pbuffer + VL53L1_NVM__FMT__SPAD_ENABLES_REF__LOC1_0_; + for (i = 0 ; i < VL53L1_REF_SPAD_BUFFER_SIZE ; i++) + pdata->nvm__fmt__spad_enables_ref__loc1[i] = *ptmp++; + + ptmp = pbuffer + VL53L1_NVM__FMT__SPAD_ENABLES_REF__LOC2_0_; + for (i = 0 ; i < VL53L1_REF_SPAD_BUFFER_SIZE ; i++) + pdata->nvm__fmt__spad_enables_ref__loc2[i] = *ptmp++; + + ptmp = pbuffer + VL53L1_NVM__FMT__SPAD_ENABLES_REF__LOC3_0_; + for (i = 0 ; i < VL53L1_REF_SPAD_BUFFER_SIZE ; i++) + pdata->nvm__fmt__spad_enables_ref__loc3[i] = *ptmp++; + + + pdata->nvm__fmt__roi_config__mode_roi_centre_spad = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + + VL53L1_NVM__FMT__ROI_CONFIG__MODE_ROI_CENTRE_SPAD, + 0x000000FF, + 0, + 0); + pdata->nvm__fmt__roi_config__mode_roi_x_size = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + + VL53L1_NVM__FMT__ROI_CONFIG__MODE_ROI_XY_SIZE, + 0x000000F0, + 4, + 0); + pdata->nvm__fmt__roi_config__mode_roi_y_size = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__ROI_CONFIG__MODE_ROI_XY_SIZE, + 0x0000000F, + 0, + 0); + pdata->nvm__fmt__ref_spad_apply__num_requested_ref_spad = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + + VL53L1_NVM__FMT__REF_SPAD_APPLY__NUM_REQUESTED_REF_SPAD, + 0x000000FF, + 0, + 0); + pdata->nvm__fmt__ref_spad_man__ref_location = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__REF_SPAD_MAN__REF_LOCATION, + 0x00000003, + 0, + 0); + pdata->nvm__fmt__mm_config__inner_offset_mm = + (uint16_t)VL53L1_i2c_decode_with_mask( + 2, + pbuffer + VL53L1_NVM__FMT__MM_CONFIG__INNER_OFFSET_MM, + 0x0000FFFF, + 0, + 0); + pdata->nvm__fmt__mm_config__outer_offset_mm = + (uint16_t)VL53L1_i2c_decode_with_mask( + 2, + pbuffer + VL53L1_NVM__FMT__MM_CONFIG__OUTER_OFFSET_MM, + 0x0000FFFF, + 0, + 0); + pdata->nvm__fmt__algo_part_to_part_range_offset_mm = + (uint16_t)VL53L1_i2c_decode_with_mask( + 2, + pbuffer + + VL53L1_NVM__FMT__ALGO__PART_TO_PART_RANGE_OFFSET_MM, + 0x00000FFF, + 0, + 0); + pdata->nvm__fmt__algo__crosstalk_compensation_plane_offset_kcps = + (uint16_t)VL53L1_i2c_decode_with_mask( + 2, + pbuffer + + VL53L1_NVM__FMT__ALGO__CROSSTALK_COMPENSATION_PLANE_OFFSET_KCPS, + 0x0000FFFF, + 0, + 0); + pdata->nvm__fmt__algo__crosstalk_compensation_x_plane_gradient_kcps = + (uint16_t)VL53L1_i2c_decode_with_mask( + 2, + pbuffer + + VL53L1_NVM__FMT__ALGO__CROSSTALK_COMPENSATION_X_PLANE_GRADIENT_KCPS, + 0x0000FFFF, + 0, + 0); + pdata->nvm__fmt__algo__crosstalk_compensation_y_plane_gradient_kcps = + (uint16_t)VL53L1_i2c_decode_with_mask( + 2, + pbuffer + + VL53L1_NVM__FMT__ALGO__CROSSTALK_COMPENSATION_Y_PLANE_GRADIENT_KCPS, + 0x0000FFFF, + 0, + 0); + pdata->nvm__fmt__spare__host_config__nvm_config_spare_0 = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + + VL53L1_NVM__FMT__SPARE_HOST_CONFIG__NVM_CONFIG_SPARE_0, + 0x000000FF, + 0, + 0); + pdata->nvm__fmt__spare__host_config__nvm_config_spare_1 = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + + VL53L1_NVM__FMT__SPARE_HOST_CONFIG__NVM_CONFIG_SPARE_1, + 0x000000FF, + 0, + 0); + pdata->nvm__customer_space_programmed = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__CUSTOMER_NVM_SPACE_PROGRAMMED, + 0x000000FF, + 0, + 0); + pdata->nvm__cust__i2c_device_address = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__CUST__I2C_SLAVE__DEVICE_ADDRESS, + 0x000000FF, + 0, + 0); + pdata->nvm__cust__ref_spad_apply__num_requested_ref_spad = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + + VL53L1_NVM__CUST__REF_SPAD_APPLY__NUM_REQUESTED_REF_SPAD, + 0x000000FF, + 0, + 0); + pdata->nvm__cust__ref_spad_man__ref_location = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__CUST__REF_SPAD_MAN__REF_LOCATION, + 0x00000003, + 0, + 0); + pdata->nvm__cust__mm_config__inner_offset_mm = + (uint16_t)VL53L1_i2c_decode_with_mask( + 2, + pbuffer + VL53L1_NVM__CUST__MM_CONFIG__INNER_OFFSET_MM, + 0x0000FFFF, + 0, + 0); + pdata->nvm__cust__mm_config__outer_offset_mm = + (uint16_t)VL53L1_i2c_decode_with_mask( + 2, + pbuffer + VL53L1_NVM__CUST__MM_CONFIG__OUTER_OFFSET_MM, + 0x0000FFFF, + 0, + 0); + pdata->nvm__cust__algo_part_to_part_range_offset_mm = + (uint16_t)VL53L1_i2c_decode_with_mask( + 2, + pbuffer + + VL53L1_NVM__CUST__ALGO__PART_TO_PART_RANGE_OFFSET_MM, + 0x00000FFF, + 0, + 0); + pdata->nvm__cust__algo__crosstalk_compensation_plane_offset_kcps = + (uint16_t)VL53L1_i2c_decode_with_mask( + 2, + pbuffer + + VL53L1_NVM__CUST__ALGO__CROSSTALK_COMPENSATION_PLANE_OFFSET_KCPS, + 0x0000FFFF, + 0, + 0); + pdata->nvm__cust__algo__crosstalk_compensation_x_plane_gradient_kcps = + (uint16_t)VL53L1_i2c_decode_with_mask( + 2, + pbuffer + + VL53L1_NVM__CUST__ALGO__CROSSTALK_COMPENSATION_X_PLANE_GRADIENT_KCPS, + 0x0000FFFF, + 0, + 0); + pdata->nvm__cust__algo__crosstalk_compensation_y_plane_gradient_kcps = + (uint16_t)VL53L1_i2c_decode_with_mask( + 2, + pbuffer + + VL53L1_NVM__CUST__ALGO__CROSSTALK_COMPENSATION_Y_PLANE_GRADIENT_KCPS, + 0x0000FFFF, + 0, + 0); + pdata->nvm__cust__spare__host_config__nvm_config_spare_0 = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__CUST__SPARE_HOST_CONFIG__NVM_CONFIG_SPARE_0, + 0x000000FF, + 0, + 0); + pdata->nvm__cust__spare__host_config__nvm_config_spare_1 = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + + VL53L1_NVM__CUST__SPARE_HOST_CONFIG__NVM_CONFIG_SPARE_1, + 0x000000FF, + 0, + 0); + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_nvm_decode_optical_centre( + buf_size, + pbuffer + VL53L1_NVM__FMT__OPTICAL_CENTRE_DATA_INDEX, + &(pdata->fmt_optical_centre)); + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_nvm_decode_cal_peak_rate_map( + buf_size, + pbuffer + VL53L1_NVM__FMT__CAL_PEAK_RATE_MAP_DATA_INDEX, + &(pdata->fmt_peak_rate_map)); + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_nvm_decode_additional_offset_cal_data( + buf_size, + pbuffer + + VL53L1_NVM__FMT__ADDITIONAL_OFFSET_CAL_DATA_INDEX, + &(pdata->fmt_add_offset_data)); + + + + + pptmp[0] = VL53L1_NVM__FMT__RANGE_RESULTS__140MM_MM_PRE_RANGE; + pptmp[1] = VL53L1_NVM__FMT__RANGE_RESULTS__140MM_DARK; + pptmp[2] = VL53L1_NVM__FMT__RANGE_RESULTS__400MM_DARK; + pptmp[3] = VL53L1_NVM__FMT__RANGE_RESULTS__400MM_AMBIENT; + + for (i = 0 ; i < VL53L1_NVM_MAX_FMT_RANGE_DATA ; i++) { + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_nvm_decode_fmt_range_results_data( + buf_size, + pbuffer + pptmp[i], + &(pdata->fmt_range_data[i])); + } + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_nvm_decode_fmt_info( + buf_size, + pbuffer, + &(pdata->fmt_info)); + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_nvm_decode_ews_info( + buf_size, + pbuffer, + &(pdata->ews_info)); + + LOG_FUNCTION_END(status); + + return status; + +} + + +VL53L1_Error VL53L1_nvm_decode_optical_centre( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_optical_centre_t *pdata) +{ + + VL53L1_Error status = VL53L1_ERROR_NONE; + + uint16_t tmp = 0; + + if (buf_size < VL53L1_NVM__FMT__OPTICAL_CENTRE_DATA_SIZE) + return VL53L1_ERROR_BUFFER_TOO_SMALL; + + + + + + tmp = 0x0100; + tmp -= (uint16_t)*(pbuffer + 2); + if (tmp > 0x0FF) + tmp = 0; + + pdata->x_centre = (uint8_t)tmp; + pdata->y_centre = *(pbuffer + 3); + + return status; +} + + +VL53L1_Error VL53L1_nvm_decode_cal_peak_rate_map( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_cal_peak_rate_map_t *pdata) +{ + + VL53L1_Error status = VL53L1_ERROR_NONE; + + uint8_t *ptmp = NULL; + uint8_t i = 0; + + if (buf_size < VL53L1_NVM__FMT__CAL_PEAK_RATE_MAP_DATA_SIZE) + return VL53L1_ERROR_BUFFER_TOO_SMALL; + + pdata->cal_distance_mm = + (uint16_t)VL53L1_i2c_decode_uint16_t(2, pbuffer); + + pdata->cal_reflectance_pc = + (uint16_t)VL53L1_i2c_decode_uint16_t(2, pbuffer + 2); + pdata->cal_reflectance_pc = + pdata->cal_reflectance_pc >> 6; + + pdata->max_samples = VL53L1_NVM_PEAK_RATE_MAP_SAMPLES; + pdata->width = VL53L1_NVM_PEAK_RATE_MAP_WIDTH; + pdata->height = VL53L1_NVM_PEAK_RATE_MAP_HEIGHT; + + ptmp = pbuffer + 4; + for (i = 0 ; i < VL53L1_NVM_PEAK_RATE_MAP_SAMPLES ; i++) { + pdata->peak_rate_mcps[i] = + (uint16_t)VL53L1_i2c_decode_uint16_t(2, ptmp); + ptmp += 2; + } + + return status; +} + + +VL53L1_Error VL53L1_nvm_decode_additional_offset_cal_data( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_additional_offset_cal_data_t *pdata) +{ + + VL53L1_Error status = VL53L1_ERROR_NONE; + + if (buf_size < VL53L1_NVM__FMT__ADDITIONAL_OFFSET_CAL_DATA_SIZE) + return VL53L1_ERROR_BUFFER_TOO_SMALL; + + pdata->result__mm_inner_actual_effective_spads = + (uint16_t)VL53L1_i2c_decode_uint16_t(2, pbuffer); + + pdata->result__mm_outer_actual_effective_spads = + (uint16_t)VL53L1_i2c_decode_uint16_t(2, pbuffer + 2); + + pdata->result__mm_inner_peak_signal_count_rtn_mcps = + (uint16_t)VL53L1_i2c_decode_uint16_t(2, pbuffer + 4); + + pdata->result__mm_outer_peak_signal_count_rtn_mcps = + (uint16_t)VL53L1_i2c_decode_uint16_t(2, pbuffer + 6); + + return status; +} + + +VL53L1_Error VL53L1_nvm_decode_fmt_range_results_data( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_decoded_nvm_fmt_range_data_t *pdata) +{ + + VL53L1_Error status = VL53L1_ERROR_NONE; + + if (buf_size < VL53L1_NVM__FMT__RANGE_RESULTS__SIZE_BYTES) + return VL53L1_ERROR_BUFFER_TOO_SMALL; + + pdata->result__actual_effective_rtn_spads = + (uint16_t)VL53L1_i2c_decode_uint16_t(2, pbuffer); + + pdata->ref_spad_array__num_requested_ref_spads = + *(pbuffer+2); + + pdata->ref_spad_array__ref_location = + *(pbuffer+3); + + pdata->result__peak_signal_count_rate_rtn_mcps = + (uint16_t)VL53L1_i2c_decode_uint16_t(2, pbuffer + 4); + + pdata->result__ambient_count_rate_rtn_mcps = + (uint16_t)VL53L1_i2c_decode_uint16_t(2, pbuffer + 6); + + pdata->result__peak_signal_count_rate_ref_mcps = + (uint16_t)VL53L1_i2c_decode_uint16_t(2, pbuffer + 8); + + pdata->result__ambient_count_rate_ref_mcps = + (uint16_t)VL53L1_i2c_decode_uint16_t(2, pbuffer + 10); + + pdata->measured_distance_mm = + (uint16_t)VL53L1_i2c_decode_uint16_t(2, pbuffer + 12); + + pdata->measured_distance_stdev_mm = + (uint16_t)VL53L1_i2c_decode_uint16_t(2, pbuffer + 14); + + return status; +} + + +VL53L1_Error VL53L1_nvm_decode_fmt_info( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_decoded_nvm_fmt_info_t *pdata) +{ + + VL53L1_Error status = VL53L1_ERROR_NONE; + + if (buf_size < VL53L1_NVM_SIZE_IN_BYTES) + return VL53L1_ERROR_BUFFER_TOO_SMALL; + + pdata->nvm__fmt__fgc[0] = + (char)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__FGC__BYTE_0, + 0x000000FE, + 1, + 0); + pdata->nvm__fmt__fgc[1] = + (char)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__FGC__BYTE_1, + 0x000001FC, + 2, + 0); + pdata->nvm__fmt__fgc[2] = + (char)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__FGC__BYTE_2 - 1, + 0x000003F8, + 3, + 0); + pdata->nvm__fmt__fgc[3] = + (char)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__FGC__BYTE_3 - 1, + 0x000007F0, + 4, + 0); + pdata->nvm__fmt__fgc[4] = + (char)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__FGC__BYTE_4 - 1, + 0x00000FE0, + 5, + 0); + pdata->nvm__fmt__fgc[5] = + (char)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__FGC__BYTE_5 - 1, + 0x00001FC0, + 6, + 0); + pdata->nvm__fmt__fgc[6] = + (char)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__FGC__BYTE_6 - 1, + 0x00003F80, + 7, + 0); + pdata->nvm__fmt__fgc[7] = + (char)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__FGC__BYTE_6, + 0x0000007F, + 0, + 0); + pdata->nvm__fmt__fgc[8] = + (char)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__FGC__BYTE_7, + 0x000000FE, + 1, + 0); + pdata->nvm__fmt__fgc[9] = + (char)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__FGC__BYTE_8, + 0x000001FC, + 2, + 0); + pdata->nvm__fmt__fgc[10] = + (char)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__FGC__BYTE_9 - 1, + 0x000003F8, + 3, + 0); + pdata->nvm__fmt__fgc[11] = + (char)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__FGC__BYTE_10 - 1, + 0x000007F0, + 4, + 0); + pdata->nvm__fmt__fgc[12] = + (char)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__FGC__BYTE_11 - 1, + 0x00000FE0, + 5, + 0); + pdata->nvm__fmt__fgc[13] = + (char)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__FGC__BYTE_12 - 1, + 0x00001FC0, + 6, + 0); + pdata->nvm__fmt__fgc[14] = + (char)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__FGC__BYTE_13 - 1, + 0x00003F80, + 7, + 0); + pdata->nvm__fmt__fgc[15] = + (char)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__FGC__BYTE_13, + 0x0000007F, + 0, + 0); + pdata->nvm__fmt__fgc[16] = + (char)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__FGC__BYTE_14, + 0x000000FE, + 1, + 0); + pdata->nvm__fmt__fgc[17] = + (char)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__FGC__BYTE_15, + 0x000001FC, + 2, + 0); + pdata->nvm__fmt__fgc[18] = 0x00; + + pdata->nvm__fmt__test_program_major = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__TEST_PROGRAM_MAJOR_MINOR, + 0x000000E0, + 5, + 0); + pdata->nvm__fmt__test_program_minor = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__TEST_PROGRAM_MAJOR_MINOR, + 0x0000001F, + 0, + 0); + pdata->nvm__fmt__map_major = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__MAP_MAJOR_MINOR, + 0x000000E0, + 5, + 0); + pdata->nvm__fmt__map_minor = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__MAP_MAJOR_MINOR, + 0x0000001F, + 0, + 0); + pdata->nvm__fmt__year = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__YEAR_MONTH, + 0x000000F0, + 4, + 0); + pdata->nvm__fmt__month = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__YEAR_MONTH, + 0x0000000F, + 0, + 0); + pdata->nvm__fmt__day = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__DAY_MODULE_DATE_PHASE, + 0x000000F8, + 3, + 0); + pdata->nvm__fmt__module_date_phase = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__DAY_MODULE_DATE_PHASE, + 0x00000007, + 0, + 0); + pdata->nvm__fmt__time = + (uint16_t)VL53L1_i2c_decode_with_mask( + 2, + pbuffer + VL53L1_NVM__FMT__TIME, + 0x0000FFFF, + 0, + 0); + pdata->nvm__fmt__tester_id = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__TESTER_ID, + 0x000000FF, + 0, + 0); + pdata->nvm__fmt__site_id = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__SITE_ID, + 0x000000FF, + 0, + 0); + + return status; +} + + +VL53L1_Error VL53L1_nvm_decode_ews_info( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_decoded_nvm_ews_info_t *pdata) +{ + + VL53L1_Error status = VL53L1_ERROR_NONE; + + if (buf_size < VL53L1_NVM_SIZE_IN_BYTES) + return VL53L1_ERROR_BUFFER_TOO_SMALL; + + pdata->nvm__ews__test_program_major = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__EWS__TEST_PROGRAM_MAJOR_MINOR, + 0x000000E0, + 5, + 0); + pdata->nvm__ews__test_program_minor = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__EWS__TEST_PROGRAM_MAJOR_MINOR, + 0x0000001F, + 0, + 0); + pdata->nvm__ews__probe_card_major = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__EWS__PROBE_CARD_MAJOR_MINOR, + 0x000000F0, + 4, + 0); + pdata->nvm__ews__probe_card_minor = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__EWS__PROBE_CARD_MAJOR_MINOR, + 0x0000000F, + 0, + 0); + pdata->nvm__ews__tester_id = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__EWS__TESTER_ID, + 0x000000FF, + 0, + 0); + pdata->nvm__ews__lot[0] = + (char)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__EWS__LOT__BYTE_0, + 0x000000FC, + 2, + 32); + pdata->nvm__ews__lot[1] = + (char)VL53L1_i2c_decode_with_mask( + 2, + pbuffer + VL53L1_NVM__EWS__LOT__BYTE_1 - 1, + 0x000003F0, + 4, + 32); + pdata->nvm__ews__lot[2] = + (char)VL53L1_i2c_decode_with_mask( + 2, + pbuffer + VL53L1_NVM__EWS__LOT__BYTE_2 - 1, + 0x00000FC0, + 6, + 32); + pdata->nvm__ews__lot[3] = + (char)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__EWS__LOT__BYTE_2, + 0x0000003F, + 0, + 32); + pdata->nvm__ews__lot[4] = + (char)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__EWS__LOT__BYTE_3, + 0x000000FC, + 2, + 32); + pdata->nvm__ews__lot[5] = + (char)VL53L1_i2c_decode_with_mask( + 2, + pbuffer + VL53L1_NVM__EWS__LOT__BYTE_4 - 1, + 0x000003F0, + 4, + 32); + pdata->nvm__ews__lot[6] = + (char)VL53L1_i2c_decode_with_mask( + 2, + pbuffer + VL53L1_NVM__EWS__LOT__BYTE_5 - 1, + 0x00000FC0, + 6, + 32); + + pdata->nvm__ews__lot[7] = 0x00; + + pdata->nvm__ews__wafer = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__EWS__WAFER, + 0x0000001F, + 0, + 0); + pdata->nvm__ews__xcoord = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__EWS__XCOORD, + 0x000000FF, + 0, + 0); + pdata->nvm__ews__ycoord = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__EWS__YCOORD, + 0x000000FF, + 0, + 0); + + return status; + +} + + +void VL53L1_nvm_format_encode( + VL53L1_decoded_nvm_data_t *pnvm_info, + uint8_t *pnvm_data) +{ + SUPPRESS_UNUSED_WARNING(pnvm_info); + SUPPRESS_UNUSED_WARNING(pnvm_data); +} + + +VL53L1_Error VL53L1_read_nvm_raw_data( + VL53L1_DEV Dev, + uint8_t start_address, + uint8_t count, + uint8_t *pnvm_raw_data) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_nvm_enable( + Dev, + 0x0004, + VL53L1_NVM_POWER_UP_DELAY_US); + + + + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_nvm_read( + Dev, + start_address, + count, + pnvm_raw_data); + + + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_nvm_disable(Dev); + + LOG_FUNCTION_END(status); + + return status; + +} + + +VL53L1_Error VL53L1_read_nvm( + VL53L1_DEV Dev, + uint8_t nvm_format, + VL53L1_decoded_nvm_data_t *pnvm_info) +{ + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + + + uint8_t nvm_data[2*VL53L1_NVM_SIZE_IN_BYTES]; + + LOG_FUNCTION_START(""); + + SUPPRESS_UNUSED_WARNING(nvm_format); + + + + + status = VL53L1_read_nvm_raw_data( + Dev, + 0, + VL53L1_NVM_SIZE_IN_BYTES >> 2, + nvm_data); + + + + + + + + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_nvm_format_decode( + VL53L1_NVM_SIZE_IN_BYTES, + nvm_data, + pnvm_info); + + LOG_FUNCTION_END(status); + + return status; + +} + + +VL53L1_Error VL53L1_read_nvm_optical_centre( + VL53L1_DEV Dev, + VL53L1_optical_centre_t *pcentre) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + + + uint8_t nvm_data[2*VL53L1_NVM__FMT__OPTICAL_CENTRE_DATA_SIZE]; + + LOG_FUNCTION_START(""); + + + + + status = + VL53L1_read_nvm_raw_data( + Dev, + (uint8_t)(VL53L1_NVM__FMT__OPTICAL_CENTRE_DATA_INDEX + >> 2), + (uint8_t)(VL53L1_NVM__FMT__OPTICAL_CENTRE_DATA_SIZE + >> 2), + nvm_data); + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_nvm_decode_optical_centre( + VL53L1_NVM__FMT__OPTICAL_CENTRE_DATA_SIZE, + nvm_data, + pcentre); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_read_nvm_cal_peak_rate_map( + VL53L1_DEV Dev, + VL53L1_cal_peak_rate_map_t *pcal_data) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + + + uint8_t nvm_data[2*VL53L1_NVM__FMT__CAL_PEAK_RATE_MAP_DATA_SIZE]; + + LOG_FUNCTION_START(""); + + + + + status = + VL53L1_read_nvm_raw_data( + Dev, + (uint8_t)(VL53L1_NVM__FMT__CAL_PEAK_RATE_MAP_DATA_INDEX + >> 2), + (uint8_t)(VL53L1_NVM__FMT__CAL_PEAK_RATE_MAP_DATA_SIZE + >> 2), + nvm_data); + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_nvm_decode_cal_peak_rate_map( + VL53L1_NVM__FMT__CAL_PEAK_RATE_MAP_DATA_SIZE, + nvm_data, + pcal_data); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_read_nvm_additional_offset_cal_data( + VL53L1_DEV Dev, + VL53L1_additional_offset_cal_data_t *pcal_data) +{ + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + + + uint8_t nvm_data[2*VL53L1_NVM__FMT__ADDITIONAL_OFFSET_CAL_DATA_SIZE]; + + LOG_FUNCTION_START(""); + + + + + status = + VL53L1_read_nvm_raw_data( + Dev, + (uint8_t)( + VL53L1_NVM__FMT__ADDITIONAL_OFFSET_CAL_DATA_INDEX >> 2), + (uint8_t)( + VL53L1_NVM__FMT__ADDITIONAL_OFFSET_CAL_DATA_SIZE >> 2), + nvm_data); + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_nvm_decode_additional_offset_cal_data( + VL53L1_NVM__FMT__ADDITIONAL_OFFSET_CAL_DATA_SIZE, + nvm_data, + pcal_data); + + LOG_FUNCTION_END(status); + + return status; + +} + + +VL53L1_Error VL53L1_read_nvm_fmt_range_results_data( + VL53L1_DEV Dev, + uint16_t range_results_select, + VL53L1_decoded_nvm_fmt_range_data_t *prange_data) +{ + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + + + uint8_t nvm_data[2*VL53L1_NVM__FMT__RANGE_RESULTS__SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + + + + status = VL53L1_read_nvm_raw_data( + Dev, + (uint8_t)(range_results_select >> 2), + (uint8_t)(VL53L1_NVM__FMT__RANGE_RESULTS__SIZE_BYTES >> 2), + nvm_data); + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_nvm_decode_fmt_range_results_data( + VL53L1_NVM__FMT__RANGE_RESULTS__SIZE_BYTES, + nvm_data, + prange_data); + + LOG_FUNCTION_END(status); + + return status; + +} + + diff --git a/drivers/input/misc/vl53L1/lito/src/vl53l1_nvm_debug.c b/drivers/input/misc/vl53L1/lito/src/vl53l1_nvm_debug.c new file mode 100644 index 000000000000..b1acfd144577 --- /dev/null +++ b/drivers/input/misc/vl53L1/lito/src/vl53l1_nvm_debug.c @@ -0,0 +1,1126 @@ + +/******************************************************************************* + * Copyright (c) 2017, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#include "vl53l1_ll_def.h" +#include "vl53l1_platform.h" +#include "vl53l1_platform_log.h" +#include "vl53l1_register_map.h" +#include "vl53l1_api_debug.h" +#include "vl53l1_nvm_structs.h" +#include "vl53l1_nvm_debug.h" + +#define LOG_FUNCTION_START(fmt, ...) \ + _LOG_FUNCTION_START(VL53L1_TRACE_MODULE_NVM, fmt, ##__VA_ARGS__) +#define LOG_FUNCTION_END(status, ...) \ + _LOG_FUNCTION_END(VL53L1_TRACE_MODULE_NVM, status, ##__VA_ARGS__) +#define LOG_FUNCTION_END_FMT(status, fmt, ...) \ + _LOG_FUNCTION_END_FMT(VL53L1_TRACE_MODULE_NVM,\ + status, fmt, ##__VA_ARGS__) + +#define trace_print(level, ...) \ + _LOG_TRACE_PRINT(trace_flags, \ + level, VL53L1_TRACE_FUNCTION_NONE, ##__VA_ARGS__) + +#ifdef VL53L1_LOG_ENABLE + +void VL53L1_print_nvm_raw_data( + uint8_t *pnvm_raw_data, + uint32_t trace_flags) +{ + + + + + + int i = 0; + + LOG_FUNCTION_START(""); + + for (i = 0 ; i < VL53L1_NVM_SIZE_IN_BYTES ; i++) { + if (i % 4 == 0) + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "\n NVM Addr 0x%02X : 0x", + i/4); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%02X", + *pnvm_raw_data++); + } + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "\n"); + + LOG_FUNCTION_END(0); +} + + +void VL53L1_print_decoded_nvm_data( + VL53L1_decoded_nvm_data_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + char fp_text[VL53L1_MAX_STRING_LENGTH]; + char pre_text[VL53L1_MAX_STRING_LENGTH]; + char *ppre_text = &(pre_text[0]); + + uint8_t i = 0; + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__identification_model_id", + pdata->nvm__identification_model_id); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__identification_module_type", + pdata->nvm__identification_module_type); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__identification_revision_id", + pdata->nvm__identification_revision_id); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__identification_module_id", + pdata->nvm__identification_module_id); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__i2c_valid", + pdata->nvm__i2c_valid); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__i2c_device_address_ews", + pdata->nvm__i2c_device_address_ews); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->nvm__ews__fast_osc_frequency, + 12, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "nvm__ews__fast_osc_frequency", + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__ews__fast_osc_trim_max", + pdata->nvm__ews__fast_osc_trim_max); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__ews__fast_osc_freq_set", + pdata->nvm__ews__fast_osc_freq_set); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__ews__slow_osc_calibration", + pdata->nvm__ews__slow_osc_calibration); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->nvm__fmt__fast_osc_frequency, + 12, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "nvm__fmt__fast_osc_frequency", + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__fmt__fast_osc_trim_max", + pdata->nvm__fmt__fast_osc_trim_max); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__fmt__fast_osc_freq_set", + pdata->nvm__fmt__fast_osc_freq_set); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__fmt__slow_osc_calibration", + pdata->nvm__fmt__slow_osc_calibration); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__vhv_config_unlock", + pdata->nvm__vhv_config_unlock); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__ref_selvddpix", + pdata->nvm__ref_selvddpix); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__ref_selvquench", + pdata->nvm__ref_selvquench); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__regavdd1v2_sel", + pdata->nvm__regavdd1v2_sel); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__regdvdd1v2_sel", + pdata->nvm__regdvdd1v2_sel); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__vhv_timeout__macrop", + pdata->nvm__vhv_timeout__macrop); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__vhv_loop_bound", + pdata->nvm__vhv_loop_bound); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__vhv_count_threshold", + pdata->nvm__vhv_count_threshold); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__vhv_offset", + pdata->nvm__vhv_offset); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__vhv_init_enable", + pdata->nvm__vhv_init_enable); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__vhv_init_value", + pdata->nvm__vhv_init_value); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__laser_safety_vcsel_trim_ll", + pdata->nvm__laser_safety_vcsel_trim_ll); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__laser_safety_vcsel_selion_ll", + pdata->nvm__laser_safety_vcsel_selion_ll); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__laser_safety_vcsel_selion_max_ll", + pdata->nvm__laser_safety_vcsel_selion_max_ll); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__laser_safety_mult_ll", + pdata->nvm__laser_safety_mult_ll); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__laser_safety_clip_ll", + pdata->nvm__laser_safety_clip_ll); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__laser_safety_vcsel_trim_ld", + pdata->nvm__laser_safety_vcsel_trim_ld); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__laser_safety_vcsel_selion_ld", + pdata->nvm__laser_safety_vcsel_selion_ld); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__laser_safety_vcsel_selion_max_ld", + pdata->nvm__laser_safety_vcsel_selion_max_ld); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__laser_safety_mult_ld", + pdata->nvm__laser_safety_mult_ld); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__laser_safety_clip_ld", + pdata->nvm__laser_safety_clip_ld); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__laser_safety_lock_byte", + pdata->nvm__laser_safety_lock_byte); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__laser_safety_unlock_byte", + pdata->nvm__laser_safety_unlock_byte); + + + + + for (i = 0 ; i < VL53L1_RTN_SPAD_BUFFER_SIZE ; i++) { + sprintf( + ppre_text, + "%snvm__ews__spad_enables_rtn[%u]", + pprefix, i); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s = %u\n", + ppre_text, + pdata->nvm__ews__spad_enables_rtn[i]); + } + + for (i = 0 ; i < VL53L1_REF_SPAD_BUFFER_SIZE ; i++) { + sprintf( + ppre_text, + "%snvm__ews__spad_enables_ref__loc1[%u]", + pprefix, i); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s = %u\n", + ppre_text, + pdata->nvm__ews__spad_enables_ref__loc1[i]); + } + + for (i = 0 ; i < VL53L1_REF_SPAD_BUFFER_SIZE ; i++) { + sprintf( + ppre_text, + "%snvm__ews__spad_enables_ref__loc2[%u]", + pprefix, i); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s = %u\n", + ppre_text, + pdata->nvm__ews__spad_enables_ref__loc2[i]); + } + + for (i = 0 ; i < VL53L1_REF_SPAD_BUFFER_SIZE ; i++) { + sprintf( + ppre_text, + "%snvm__ews__spad_enables_ref__loc3[%u]", + pprefix, i); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s = %u\n", + ppre_text, + pdata->nvm__ews__spad_enables_ref__loc3[i]); + } + + + + + + for (i = 0 ; i < VL53L1_RTN_SPAD_BUFFER_SIZE ; i++) { + sprintf( + ppre_text, + "%snvm__fmt__spad_enables_rtn[%u]", + pprefix, i); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s = %u\n", + ppre_text, + pdata->nvm__fmt__spad_enables_rtn[i]); + } + + for (i = 0 ; i < VL53L1_REF_SPAD_BUFFER_SIZE ; i++) { + sprintf( + ppre_text, + "%snvm__fmt__spad_enables_ref__loc1[%u]", + pprefix, i); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s = %u\n", + ppre_text, + pdata->nvm__fmt__spad_enables_ref__loc1[i]); + } + + for (i = 0 ; i < VL53L1_REF_SPAD_BUFFER_SIZE ; i++) { + sprintf( + ppre_text, + "%snvm__fmt__spad_enables_ref__loc2[%u]", + pprefix, i); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s = %u\n", + ppre_text, + pdata->nvm__fmt__spad_enables_ref__loc2[i]); + } + + for (i = 0 ; i < VL53L1_REF_SPAD_BUFFER_SIZE ; i++) { + sprintf( + ppre_text, + "%snvm__fmt__spad_enables_ref__loc3[%u]", + pprefix, i); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s = %u\n", + ppre_text, + pdata->nvm__fmt__spad_enables_ref__loc3[i]); + } + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__fmt__roi_config__mode_roi_centre_spad", + pdata->nvm__fmt__roi_config__mode_roi_centre_spad); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__fmt__roi_config__mode_roi_x_size", + pdata->nvm__fmt__roi_config__mode_roi_x_size); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__fmt__roi_config__mode_roi_y_size", + pdata->nvm__fmt__roi_config__mode_roi_y_size); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__fmt__ref_spad_apply__num_requested_ref_spad", + pdata->nvm__fmt__ref_spad_apply__num_requested_ref_spad); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__fmt__ref_spad_man__ref_location", + pdata->nvm__fmt__ref_spad_man__ref_location); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %d\n", + pprefix, + "nvm__fmt__mm_config__inner_offset_mm", + pdata->nvm__fmt__mm_config__inner_offset_mm); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %d\n", + pprefix, + "nvm__fmt__mm_config__outer_offset_mm", + pdata->nvm__fmt__mm_config__outer_offset_mm); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->nvm__fmt__algo_part_to_part_range_offset_mm, + 2, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "nvm__fmt__algo_part_to_part_range_offset_mm", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)( + pdata->nvm__fmt__algo__crosstalk_compensation_plane_offset_kcps), + 9, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "nvm__fmt__algo__crosstalk_compensation_plane_offset_kcps", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)( + pdata->nvm__fmt__algo__crosstalk_compensation_x_plane_gradient_kcps), + 11, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "nvm__fmt__algo__crosstalk_compensation_x_plane_gradient_kcps", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)( + pdata->nvm__fmt__algo__crosstalk_compensation_y_plane_gradient_kcps), + 11, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "nvm__fmt__algo__crosstalk_compensation_y_plane_gradient_kcps", + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__fmt__spare__host_config__nvm_config_spare_0", + pdata->nvm__fmt__spare__host_config__nvm_config_spare_0); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__fmt__spare__host_config__nvm_config_spare_1", + pdata->nvm__fmt__spare__host_config__nvm_config_spare_1); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__customer_space_programmed", + pdata->nvm__customer_space_programmed); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__cust__i2c_device_address", + pdata->nvm__cust__i2c_device_address); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__cust__ref_spad_apply__num_requested_ref_spad", + pdata->nvm__cust__ref_spad_apply__num_requested_ref_spad); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__cust__ref_spad_man__ref_location", + pdata->nvm__cust__ref_spad_man__ref_location); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %d\n", + pprefix, + "nvm__cust__mm_config__inner_offset_mm", + pdata->nvm__cust__mm_config__inner_offset_mm); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %d\n", + pprefix, + "nvm__cust__mm_config__outer_offset_mm", + pdata->nvm__cust__mm_config__outer_offset_mm); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->nvm__cust__algo_part_to_part_range_offset_mm, + 2, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "nvm__cust__algo_part_to_part_range_offset_mm", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (uint32_t)( + pdata->nvm__cust__algo__crosstalk_compensation_plane_offset_kcps), + 9, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "nvm__cust__algo__crosstalk_compensation_plane_offset_kcps", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)( + pdata->nvm__cust__algo__crosstalk_compensation_x_plane_gradient_kcps), + 11, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "nvm__cust__algo__crosstalk_compensation_x_plane_gradient_kcps", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)( + pdata->nvm__cust__algo__crosstalk_compensation_y_plane_gradient_kcps), + 11, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "nvm__cust__algo__crosstalk_compensation_y_plane_gradient_kcps", + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__cust__spare__host_config__nvm_config_spare_0", + pdata->nvm__cust__spare__host_config__nvm_config_spare_0); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__cust__spare__host_config__nvm_config_spare_1", + pdata->nvm__cust__spare__host_config__nvm_config_spare_1); + + + + + sprintf( + ppre_text, + "%sfmt_optical_centre.", pprefix); + + VL53L1_print_optical_centre( + &(pdata->fmt_optical_centre), + ppre_text, + VL53L1_TRACE_MODULE_NVM_DATA); + + + + + sprintf( + ppre_text, + "%sfmt_peak_rate_map.", pprefix); + + VL53L1_print_cal_peak_rate_map( + &(pdata->fmt_peak_rate_map), + ppre_text, + VL53L1_TRACE_MODULE_NVM_DATA); + + + + + sprintf( + ppre_text, + "%sfmt_add_offset_data.", + pprefix); + + VL53L1_print_additional_offset_cal_data( + &(pdata->fmt_add_offset_data), + ppre_text, + VL53L1_TRACE_MODULE_NVM_DATA); + + + + + for (i = 0 ; i < VL53L1_NVM_MAX_FMT_RANGE_DATA ; i++) { + sprintf( + ppre_text, + "%sfmt_range_data[%u].", + pprefix, i); + + VL53L1_print_decoded_nvm_fmt_range_data( + &(pdata->fmt_range_data[i]), + ppre_text, + trace_flags); + } + + sprintf( + ppre_text, + "%sfmt_info.", + pprefix); + + VL53L1_print_decoded_nvm_fmt_info( + &(pdata->fmt_info), + ppre_text, + trace_flags); + + sprintf( + ppre_text, + "%sews_info.", + pprefix); + + VL53L1_print_decoded_nvm_ews_info( + &(pdata->ews_info), + ppre_text, + trace_flags); +} + + +void VL53L1_print_decoded_nvm_fmt_range_data( + VL53L1_decoded_nvm_fmt_range_data_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + char fp_text[VL53L1_MAX_STRING_LENGTH]; + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->result__actual_effective_rtn_spads, + 8, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "result__actual_effective_rtn_spads", + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "ref_spad_array__num_requested_ref_spads", + pdata->ref_spad_array__num_requested_ref_spads); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "ref_spad_array__ref_location", + pdata->ref_spad_array__ref_location); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->result__peak_signal_count_rate_rtn_mcps, + 7, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "result__peak_signal_count_rate_rtn_mcps", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->result__ambient_count_rate_rtn_mcps, + 7, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "result__ambient_count_rate_rtn_mcps", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->result__peak_signal_count_rate_ref_mcps, + 7, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "result__peak_signal_count_rate_ref_mcps", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->result__ambient_count_rate_ref_mcps, + 7, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "result__ambient_count_rate_ref_mcps", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->measured_distance_mm, + 4, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "measured_distance_mm", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (uint32_t)pdata->measured_distance_stdev_mm, + 4, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "measured_distance_stdev_mm", + fp_text); +} + + +void VL53L1_print_decoded_nvm_fmt_info( + VL53L1_decoded_nvm_fmt_info_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + trace_print(VL53L1_TRACE_LEVEL_INFO, + "%s%s = \"%s\"\n", + pprefix, + "nvm__fmt__fgc", + pdata->nvm__fmt__fgc); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__fmt__test_program_major", + pdata->nvm__fmt__test_program_major); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__fmt__test_program_minor", + pdata->nvm__fmt__test_program_minor); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__fmt__map_major", + pdata->nvm__fmt__map_major); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__fmt__map_minor", + pdata->nvm__fmt__map_minor); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__fmt__year", + pdata->nvm__fmt__year); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__fmt__month", + pdata->nvm__fmt__month); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__fmt__day", + pdata->nvm__fmt__day); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__fmt__module_date_phase", + pdata->nvm__fmt__module_date_phase); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__fmt__time", + pdata->nvm__fmt__time); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__fmt__tester_id", + pdata->nvm__fmt__tester_id); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__fmt__site_id", + pdata->nvm__fmt__site_id); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__ews__test_program_major", + pdata->nvm__ews__test_program_major); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__ews__test_program_minor", + pdata->nvm__ews__test_program_minor); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__ews__probe_card_major", + pdata->nvm__ews__probe_card_major); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__ews__probe_card_minor", + pdata->nvm__ews__probe_card_minor); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__ews__tester_id", + pdata->nvm__ews__tester_id); +} + + +void VL53L1_print_decoded_nvm_ews_info( + VL53L1_decoded_nvm_ews_info_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + trace_print(VL53L1_TRACE_LEVEL_INFO, + "%s%s = \"%s\"\n", + pprefix, + "nvm__ews__lot", + pdata->nvm__ews__lot); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__ews__wafer", + pdata->nvm__ews__wafer); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__ews__xcoord", + pdata->nvm__ews__xcoord); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__ews__ycoord", + pdata->nvm__ews__ycoord); +} + +#endif + + + diff --git a/drivers/input/misc/vl53L1/lito/src/vl53l1_register_funcs.c b/drivers/input/misc/vl53L1/lito/src/vl53l1_register_funcs.c new file mode 100644 index 000000000000..21d886e8ae77 --- /dev/null +++ b/drivers/input/misc/vl53L1/lito/src/vl53l1_register_funcs.c @@ -0,0 +1,4596 @@ + +/******************************************************************************* + * Copyright (c) 2017, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#include "vl53l1_ll_def.h" +#include "vl53l1_platform.h" +#include "vl53l1_platform_log.h" +#include "vl53l1_core.h" +#include "vl53l1_register_map.h" +#include "vl53l1_register_structs.h" +#include "vl53l1_register_funcs.h" + +#define LOG_FUNCTION_START(fmt, ...) \ + _LOG_FUNCTION_START(VL53L1_TRACE_MODULE_REGISTERS, fmt, ##__VA_ARGS__) +#define LOG_FUNCTION_END(status, ...) \ + _LOG_FUNCTION_END(VL53L1_TRACE_MODULE_REGISTERS, status, ##__VA_ARGS__) +#define LOG_FUNCTION_END_FMT(status, fmt, ...) \ + _LOG_FUNCTION_END_FMT(VL53L1_TRACE_MODULE_REGISTERS,\ + status, fmt, ##__VA_ARGS__) + + +VL53L1_Error VL53L1_i2c_encode_static_nvm_managed( + VL53L1_static_nvm_managed_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_STATIC_NVM_MANAGED_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + *(pbuffer + 0) = + pdata->i2c_slave__device_address & 0x7F; + *(pbuffer + 1) = + pdata->ana_config__vhv_ref_sel_vddpix & 0xF; + *(pbuffer + 2) = + pdata->ana_config__vhv_ref_sel_vquench & 0x7F; + *(pbuffer + 3) = + pdata->ana_config__reg_avdd1v2_sel & 0x3; + *(pbuffer + 4) = + pdata->ana_config__fast_osc__trim & 0x7F; + VL53L1_i2c_encode_uint16_t( + pdata->osc_measured__fast_osc__frequency, + 2, + pbuffer + 5); + *(pbuffer + 7) = + pdata->vhv_config__timeout_macrop_loop_bound; + *(pbuffer + 8) = + pdata->vhv_config__count_thresh; + *(pbuffer + 9) = + pdata->vhv_config__offset & 0x3F; + *(pbuffer + 10) = + pdata->vhv_config__init; + LOG_FUNCTION_END(status); + + + return status; +} + + +VL53L1_Error VL53L1_i2c_decode_static_nvm_managed( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_static_nvm_managed_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_STATIC_NVM_MANAGED_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + pdata->i2c_slave__device_address = + (*(pbuffer + 0)) & 0x7F; + pdata->ana_config__vhv_ref_sel_vddpix = + (*(pbuffer + 1)) & 0xF; + pdata->ana_config__vhv_ref_sel_vquench = + (*(pbuffer + 2)) & 0x7F; + pdata->ana_config__reg_avdd1v2_sel = + (*(pbuffer + 3)) & 0x3; + pdata->ana_config__fast_osc__trim = + (*(pbuffer + 4)) & 0x7F; + pdata->osc_measured__fast_osc__frequency = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 5)); + pdata->vhv_config__timeout_macrop_loop_bound = + (*(pbuffer + 7)); + pdata->vhv_config__count_thresh = + (*(pbuffer + 8)); + pdata->vhv_config__offset = + (*(pbuffer + 9)) & 0x3F; + pdata->vhv_config__init = + (*(pbuffer + 10)); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_static_nvm_managed( + VL53L1_DEV Dev, + VL53L1_static_nvm_managed_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_STATIC_NVM_MANAGED_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_i2c_encode_static_nvm_managed( + pdata, + VL53L1_STATIC_NVM_MANAGED_I2C_SIZE_BYTES, + comms_buffer); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WriteMulti( + Dev, + VL53L1_I2C_SLAVE__DEVICE_ADDRESS, + comms_buffer, + VL53L1_STATIC_NVM_MANAGED_I2C_SIZE_BYTES); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_static_nvm_managed( + VL53L1_DEV Dev, + VL53L1_static_nvm_managed_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_STATIC_NVM_MANAGED_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_ReadMulti( + Dev, + VL53L1_I2C_SLAVE__DEVICE_ADDRESS, + comms_buffer, + VL53L1_STATIC_NVM_MANAGED_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_i2c_decode_static_nvm_managed( + VL53L1_STATIC_NVM_MANAGED_I2C_SIZE_BYTES, + comms_buffer, + pdata); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_i2c_encode_customer_nvm_managed( + VL53L1_customer_nvm_managed_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_CUSTOMER_NVM_MANAGED_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + *(pbuffer + 0) = + pdata->global_config__spad_enables_ref_0; + *(pbuffer + 1) = + pdata->global_config__spad_enables_ref_1; + *(pbuffer + 2) = + pdata->global_config__spad_enables_ref_2; + *(pbuffer + 3) = + pdata->global_config__spad_enables_ref_3; + *(pbuffer + 4) = + pdata->global_config__spad_enables_ref_4; + *(pbuffer + 5) = + pdata->global_config__spad_enables_ref_5 & 0xF; + *(pbuffer + 6) = + pdata->global_config__ref_en_start_select; + *(pbuffer + 7) = + pdata->ref_spad_man__num_requested_ref_spads & 0x3F; + *(pbuffer + 8) = + pdata->ref_spad_man__ref_location & 0x3; + VL53L1_i2c_encode_uint16_t( + pdata->algo__crosstalk_compensation_plane_offset_kcps, + 2, + pbuffer + 9); + VL53L1_i2c_encode_int16_t( + pdata->algo__crosstalk_compensation_x_plane_gradient_kcps, + 2, + pbuffer + 11); + VL53L1_i2c_encode_int16_t( + pdata->algo__crosstalk_compensation_y_plane_gradient_kcps, + 2, + pbuffer + 13); + VL53L1_i2c_encode_uint16_t( + pdata->ref_spad_char__total_rate_target_mcps, + 2, + pbuffer + 15); + VL53L1_i2c_encode_int16_t( + pdata->algo__part_to_part_range_offset_mm & 0x1FFF, + 2, + pbuffer + 17); + VL53L1_i2c_encode_int16_t( + pdata->mm_config__inner_offset_mm, + 2, + pbuffer + 19); + VL53L1_i2c_encode_int16_t( + pdata->mm_config__outer_offset_mm, + 2, + pbuffer + 21); + LOG_FUNCTION_END(status); + + + return status; +} + + +VL53L1_Error VL53L1_i2c_decode_customer_nvm_managed( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_customer_nvm_managed_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_CUSTOMER_NVM_MANAGED_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + pdata->global_config__spad_enables_ref_0 = + (*(pbuffer + 0)); + pdata->global_config__spad_enables_ref_1 = + (*(pbuffer + 1)); + pdata->global_config__spad_enables_ref_2 = + (*(pbuffer + 2)); + pdata->global_config__spad_enables_ref_3 = + (*(pbuffer + 3)); + pdata->global_config__spad_enables_ref_4 = + (*(pbuffer + 4)); + pdata->global_config__spad_enables_ref_5 = + (*(pbuffer + 5)) & 0xF; + pdata->global_config__ref_en_start_select = + (*(pbuffer + 6)); + pdata->ref_spad_man__num_requested_ref_spads = + (*(pbuffer + 7)) & 0x3F; + pdata->ref_spad_man__ref_location = + (*(pbuffer + 8)) & 0x3; + pdata->algo__crosstalk_compensation_plane_offset_kcps = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 9)); + pdata->algo__crosstalk_compensation_x_plane_gradient_kcps = + (VL53L1_i2c_decode_int16_t(2, pbuffer + 11)); + pdata->algo__crosstalk_compensation_y_plane_gradient_kcps = + (VL53L1_i2c_decode_int16_t(2, pbuffer + 13)); + pdata->ref_spad_char__total_rate_target_mcps = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 15)); + pdata->algo__part_to_part_range_offset_mm = + (VL53L1_i2c_decode_int16_t(2, pbuffer + 17)) & 0x1FFF; + pdata->mm_config__inner_offset_mm = + (VL53L1_i2c_decode_int16_t(2, pbuffer + 19)); + pdata->mm_config__outer_offset_mm = + (VL53L1_i2c_decode_int16_t(2, pbuffer + 21)); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_customer_nvm_managed( + VL53L1_DEV Dev, + VL53L1_customer_nvm_managed_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_CUSTOMER_NVM_MANAGED_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_i2c_encode_customer_nvm_managed( + pdata, + VL53L1_CUSTOMER_NVM_MANAGED_I2C_SIZE_BYTES, + comms_buffer); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WriteMulti( + Dev, + VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_REF_0, + comms_buffer, + VL53L1_CUSTOMER_NVM_MANAGED_I2C_SIZE_BYTES); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_customer_nvm_managed( + VL53L1_DEV Dev, + VL53L1_customer_nvm_managed_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_CUSTOMER_NVM_MANAGED_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_ReadMulti( + Dev, + VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_REF_0, + comms_buffer, + VL53L1_CUSTOMER_NVM_MANAGED_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_i2c_decode_customer_nvm_managed( + VL53L1_CUSTOMER_NVM_MANAGED_I2C_SIZE_BYTES, + comms_buffer, + pdata); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_i2c_encode_static_config( + VL53L1_static_config_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_STATIC_CONFIG_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + VL53L1_i2c_encode_uint16_t( + pdata->dss_config__target_total_rate_mcps, + 2, + pbuffer + 0); + *(pbuffer + 2) = + pdata->debug__ctrl & 0x1; + *(pbuffer + 3) = + pdata->test_mode__ctrl & 0xF; + *(pbuffer + 4) = + pdata->clk_gating__ctrl & 0xF; + *(pbuffer + 5) = + pdata->nvm_bist__ctrl & 0x1F; + *(pbuffer + 6) = + pdata->nvm_bist__num_nvm_words & 0x7F; + *(pbuffer + 7) = + pdata->nvm_bist__start_address & 0x7F; + *(pbuffer + 8) = + pdata->host_if__status & 0x1; + *(pbuffer + 9) = + pdata->pad_i2c_hv__config; + *(pbuffer + 10) = + pdata->pad_i2c_hv__extsup_config & 0x1; + *(pbuffer + 11) = + pdata->gpio_hv_pad__ctrl & 0x3; + *(pbuffer + 12) = + pdata->gpio_hv_mux__ctrl & 0x1F; + *(pbuffer + 13) = + pdata->gpio__tio_hv_status & 0x3; + *(pbuffer + 14) = + pdata->gpio__fio_hv_status & 0x3; + *(pbuffer + 15) = + pdata->ana_config__spad_sel_pswidth & 0x7; + *(pbuffer + 16) = + pdata->ana_config__vcsel_pulse_width_offset & 0x1F; + *(pbuffer + 17) = + pdata->ana_config__fast_osc__config_ctrl & 0x1; + *(pbuffer + 18) = + pdata->sigma_estimator__effective_pulse_width_ns; + *(pbuffer + 19) = + pdata->sigma_estimator__effective_ambient_width_ns; + *(pbuffer + 20) = + pdata->sigma_estimator__sigma_ref_mm; + *(pbuffer + 21) = + pdata->algo__crosstalk_compensation_valid_height_mm; + *(pbuffer + 22) = + pdata->spare_host_config__static_config_spare_0; + *(pbuffer + 23) = + pdata->spare_host_config__static_config_spare_1; + VL53L1_i2c_encode_uint16_t( + pdata->algo__range_ignore_threshold_mcps, + 2, + pbuffer + 24); + *(pbuffer + 26) = + pdata->algo__range_ignore_valid_height_mm; + *(pbuffer + 27) = + pdata->algo__range_min_clip; + *(pbuffer + 28) = + pdata->algo__consistency_check__tolerance & 0xF; + *(pbuffer + 29) = + pdata->spare_host_config__static_config_spare_2; + *(pbuffer + 30) = + pdata->sd_config__reset_stages_msb & 0xF; + *(pbuffer + 31) = + pdata->sd_config__reset_stages_lsb; + LOG_FUNCTION_END(status); + + + return status; +} + + +VL53L1_Error VL53L1_i2c_decode_static_config( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_static_config_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_STATIC_CONFIG_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + pdata->dss_config__target_total_rate_mcps = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 0)); + pdata->debug__ctrl = + (*(pbuffer + 2)) & 0x1; + pdata->test_mode__ctrl = + (*(pbuffer + 3)) & 0xF; + pdata->clk_gating__ctrl = + (*(pbuffer + 4)) & 0xF; + pdata->nvm_bist__ctrl = + (*(pbuffer + 5)) & 0x1F; + pdata->nvm_bist__num_nvm_words = + (*(pbuffer + 6)) & 0x7F; + pdata->nvm_bist__start_address = + (*(pbuffer + 7)) & 0x7F; + pdata->host_if__status = + (*(pbuffer + 8)) & 0x1; + pdata->pad_i2c_hv__config = + (*(pbuffer + 9)); + pdata->pad_i2c_hv__extsup_config = + (*(pbuffer + 10)) & 0x1; + pdata->gpio_hv_pad__ctrl = + (*(pbuffer + 11)) & 0x3; + pdata->gpio_hv_mux__ctrl = + (*(pbuffer + 12)) & 0x1F; + pdata->gpio__tio_hv_status = + (*(pbuffer + 13)) & 0x3; + pdata->gpio__fio_hv_status = + (*(pbuffer + 14)) & 0x3; + pdata->ana_config__spad_sel_pswidth = + (*(pbuffer + 15)) & 0x7; + pdata->ana_config__vcsel_pulse_width_offset = + (*(pbuffer + 16)) & 0x1F; + pdata->ana_config__fast_osc__config_ctrl = + (*(pbuffer + 17)) & 0x1; + pdata->sigma_estimator__effective_pulse_width_ns = + (*(pbuffer + 18)); + pdata->sigma_estimator__effective_ambient_width_ns = + (*(pbuffer + 19)); + pdata->sigma_estimator__sigma_ref_mm = + (*(pbuffer + 20)); + pdata->algo__crosstalk_compensation_valid_height_mm = + (*(pbuffer + 21)); + pdata->spare_host_config__static_config_spare_0 = + (*(pbuffer + 22)); + pdata->spare_host_config__static_config_spare_1 = + (*(pbuffer + 23)); + pdata->algo__range_ignore_threshold_mcps = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 24)); + pdata->algo__range_ignore_valid_height_mm = + (*(pbuffer + 26)); + pdata->algo__range_min_clip = + (*(pbuffer + 27)); + pdata->algo__consistency_check__tolerance = + (*(pbuffer + 28)) & 0xF; + pdata->spare_host_config__static_config_spare_2 = + (*(pbuffer + 29)); + pdata->sd_config__reset_stages_msb = + (*(pbuffer + 30)) & 0xF; + pdata->sd_config__reset_stages_lsb = + (*(pbuffer + 31)); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_static_config( + VL53L1_DEV Dev, + VL53L1_static_config_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_STATIC_CONFIG_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_i2c_encode_static_config( + pdata, + VL53L1_STATIC_CONFIG_I2C_SIZE_BYTES, + comms_buffer); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WriteMulti( + Dev, + VL53L1_DSS_CONFIG__TARGET_TOTAL_RATE_MCPS, + comms_buffer, + VL53L1_STATIC_CONFIG_I2C_SIZE_BYTES); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_static_config( + VL53L1_DEV Dev, + VL53L1_static_config_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_STATIC_CONFIG_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_ReadMulti( + Dev, + VL53L1_DSS_CONFIG__TARGET_TOTAL_RATE_MCPS, + comms_buffer, + VL53L1_STATIC_CONFIG_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_i2c_decode_static_config( + VL53L1_STATIC_CONFIG_I2C_SIZE_BYTES, + comms_buffer, + pdata); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_i2c_encode_general_config( + VL53L1_general_config_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_GENERAL_CONFIG_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + *(pbuffer + 0) = + pdata->gph_config__stream_count_update_value; + *(pbuffer + 1) = + pdata->global_config__stream_divider; + *(pbuffer + 2) = + pdata->system__interrupt_config_gpio; + *(pbuffer + 3) = + pdata->cal_config__vcsel_start & 0x7F; + VL53L1_i2c_encode_uint16_t( + pdata->cal_config__repeat_rate & 0xFFF, + 2, + pbuffer + 4); + *(pbuffer + 6) = + pdata->global_config__vcsel_width & 0x7F; + *(pbuffer + 7) = + pdata->phasecal_config__timeout_macrop; + *(pbuffer + 8) = + pdata->phasecal_config__target; + *(pbuffer + 9) = + pdata->phasecal_config__override & 0x1; + *(pbuffer + 11) = + pdata->dss_config__roi_mode_control & 0x7; + VL53L1_i2c_encode_uint16_t( + pdata->system__thresh_rate_high, + 2, + pbuffer + 12); + VL53L1_i2c_encode_uint16_t( + pdata->system__thresh_rate_low, + 2, + pbuffer + 14); + VL53L1_i2c_encode_uint16_t( + pdata->dss_config__manual_effective_spads_select, + 2, + pbuffer + 16); + *(pbuffer + 18) = + pdata->dss_config__manual_block_select; + *(pbuffer + 19) = + pdata->dss_config__aperture_attenuation; + *(pbuffer + 20) = + pdata->dss_config__max_spads_limit; + *(pbuffer + 21) = + pdata->dss_config__min_spads_limit; + LOG_FUNCTION_END(status); + + + return status; +} + + +VL53L1_Error VL53L1_i2c_decode_general_config( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_general_config_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_GENERAL_CONFIG_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + pdata->gph_config__stream_count_update_value = + (*(pbuffer + 0)); + pdata->global_config__stream_divider = + (*(pbuffer + 1)); + pdata->system__interrupt_config_gpio = + (*(pbuffer + 2)); + pdata->cal_config__vcsel_start = + (*(pbuffer + 3)) & 0x7F; + pdata->cal_config__repeat_rate = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 4)) & 0xFFF; + pdata->global_config__vcsel_width = + (*(pbuffer + 6)) & 0x7F; + pdata->phasecal_config__timeout_macrop = + (*(pbuffer + 7)); + pdata->phasecal_config__target = + (*(pbuffer + 8)); + pdata->phasecal_config__override = + (*(pbuffer + 9)) & 0x1; + pdata->dss_config__roi_mode_control = + (*(pbuffer + 11)) & 0x7; + pdata->system__thresh_rate_high = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 12)); + pdata->system__thresh_rate_low = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 14)); + pdata->dss_config__manual_effective_spads_select = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 16)); + pdata->dss_config__manual_block_select = + (*(pbuffer + 18)); + pdata->dss_config__aperture_attenuation = + (*(pbuffer + 19)); + pdata->dss_config__max_spads_limit = + (*(pbuffer + 20)); + pdata->dss_config__min_spads_limit = + (*(pbuffer + 21)); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_general_config( + VL53L1_DEV Dev, + VL53L1_general_config_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_GENERAL_CONFIG_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_i2c_encode_general_config( + pdata, + VL53L1_GENERAL_CONFIG_I2C_SIZE_BYTES, + comms_buffer); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WriteMulti( + Dev, + VL53L1_GPH_CONFIG__STREAM_COUNT_UPDATE_VALUE, + comms_buffer, + VL53L1_GENERAL_CONFIG_I2C_SIZE_BYTES); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_general_config( + VL53L1_DEV Dev, + VL53L1_general_config_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_GENERAL_CONFIG_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_ReadMulti( + Dev, + VL53L1_GPH_CONFIG__STREAM_COUNT_UPDATE_VALUE, + comms_buffer, + VL53L1_GENERAL_CONFIG_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_i2c_decode_general_config( + VL53L1_GENERAL_CONFIG_I2C_SIZE_BYTES, + comms_buffer, + pdata); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_i2c_encode_timing_config( + VL53L1_timing_config_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_TIMING_CONFIG_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + *(pbuffer + 0) = + pdata->mm_config__timeout_macrop_a_hi & 0xF; + *(pbuffer + 1) = + pdata->mm_config__timeout_macrop_a_lo; + *(pbuffer + 2) = + pdata->mm_config__timeout_macrop_b_hi & 0xF; + *(pbuffer + 3) = + pdata->mm_config__timeout_macrop_b_lo; + *(pbuffer + 4) = + pdata->range_config__timeout_macrop_a_hi & 0xF; + *(pbuffer + 5) = + pdata->range_config__timeout_macrop_a_lo; + *(pbuffer + 6) = + pdata->range_config__vcsel_period_a & 0x3F; + *(pbuffer + 7) = + pdata->range_config__timeout_macrop_b_hi & 0xF; + *(pbuffer + 8) = + pdata->range_config__timeout_macrop_b_lo; + *(pbuffer + 9) = + pdata->range_config__vcsel_period_b & 0x3F; + VL53L1_i2c_encode_uint16_t( + pdata->range_config__sigma_thresh, + 2, + pbuffer + 10); + VL53L1_i2c_encode_uint16_t( + pdata->range_config__min_count_rate_rtn_limit_mcps, + 2, + pbuffer + 12); + *(pbuffer + 14) = + pdata->range_config__valid_phase_low; + *(pbuffer + 15) = + pdata->range_config__valid_phase_high; + VL53L1_i2c_encode_uint32_t( + pdata->system__intermeasurement_period, + 4, + pbuffer + 18); + *(pbuffer + 22) = + pdata->system__fractional_enable & 0x1; + LOG_FUNCTION_END(status); + + + return status; +} + + +VL53L1_Error VL53L1_i2c_decode_timing_config( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_timing_config_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_TIMING_CONFIG_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + pdata->mm_config__timeout_macrop_a_hi = + (*(pbuffer + 0)) & 0xF; + pdata->mm_config__timeout_macrop_a_lo = + (*(pbuffer + 1)); + pdata->mm_config__timeout_macrop_b_hi = + (*(pbuffer + 2)) & 0xF; + pdata->mm_config__timeout_macrop_b_lo = + (*(pbuffer + 3)); + pdata->range_config__timeout_macrop_a_hi = + (*(pbuffer + 4)) & 0xF; + pdata->range_config__timeout_macrop_a_lo = + (*(pbuffer + 5)); + pdata->range_config__vcsel_period_a = + (*(pbuffer + 6)) & 0x3F; + pdata->range_config__timeout_macrop_b_hi = + (*(pbuffer + 7)) & 0xF; + pdata->range_config__timeout_macrop_b_lo = + (*(pbuffer + 8)); + pdata->range_config__vcsel_period_b = + (*(pbuffer + 9)) & 0x3F; + pdata->range_config__sigma_thresh = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 10)); + pdata->range_config__min_count_rate_rtn_limit_mcps = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 12)); + pdata->range_config__valid_phase_low = + (*(pbuffer + 14)); + pdata->range_config__valid_phase_high = + (*(pbuffer + 15)); + pdata->system__intermeasurement_period = + (VL53L1_i2c_decode_uint32_t(4, pbuffer + 18)); + pdata->system__fractional_enable = + (*(pbuffer + 22)) & 0x1; + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_timing_config( + VL53L1_DEV Dev, + VL53L1_timing_config_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_TIMING_CONFIG_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_i2c_encode_timing_config( + pdata, + VL53L1_TIMING_CONFIG_I2C_SIZE_BYTES, + comms_buffer); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WriteMulti( + Dev, + VL53L1_MM_CONFIG__TIMEOUT_MACROP_A_HI, + comms_buffer, + VL53L1_TIMING_CONFIG_I2C_SIZE_BYTES); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_timing_config( + VL53L1_DEV Dev, + VL53L1_timing_config_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_TIMING_CONFIG_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_ReadMulti( + Dev, + VL53L1_MM_CONFIG__TIMEOUT_MACROP_A_HI, + comms_buffer, + VL53L1_TIMING_CONFIG_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_i2c_decode_timing_config( + VL53L1_TIMING_CONFIG_I2C_SIZE_BYTES, + comms_buffer, + pdata); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_i2c_encode_dynamic_config( + VL53L1_dynamic_config_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_DYNAMIC_CONFIG_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + *(pbuffer + 0) = + pdata->system__grouped_parameter_hold_0 & 0x3; + VL53L1_i2c_encode_uint16_t( + pdata->system__thresh_high, + 2, + pbuffer + 1); + VL53L1_i2c_encode_uint16_t( + pdata->system__thresh_low, + 2, + pbuffer + 3); + *(pbuffer + 5) = + pdata->system__enable_xtalk_per_quadrant & 0x1; + *(pbuffer + 6) = + pdata->system__seed_config & 0x7; + *(pbuffer + 7) = + pdata->sd_config__woi_sd0; + *(pbuffer + 8) = + pdata->sd_config__woi_sd1; + *(pbuffer + 9) = + pdata->sd_config__initial_phase_sd0 & 0x7F; + *(pbuffer + 10) = + pdata->sd_config__initial_phase_sd1 & 0x7F; + *(pbuffer + 11) = + pdata->system__grouped_parameter_hold_1 & 0x3; + *(pbuffer + 12) = + pdata->sd_config__first_order_select & 0x3; + *(pbuffer + 13) = + pdata->sd_config__quantifier & 0xF; + *(pbuffer + 14) = + pdata->roi_config__user_roi_centre_spad; + *(pbuffer + 15) = + pdata->roi_config__user_roi_requested_global_xy_size; + *(pbuffer + 16) = + pdata->system__sequence_config; + *(pbuffer + 17) = + pdata->system__grouped_parameter_hold & 0x3; + LOG_FUNCTION_END(status); + + + return status; +} + + +VL53L1_Error VL53L1_i2c_decode_dynamic_config( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_dynamic_config_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_DYNAMIC_CONFIG_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + pdata->system__grouped_parameter_hold_0 = + (*(pbuffer + 0)) & 0x3; + pdata->system__thresh_high = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 1)); + pdata->system__thresh_low = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 3)); + pdata->system__enable_xtalk_per_quadrant = + (*(pbuffer + 5)) & 0x1; + pdata->system__seed_config = + (*(pbuffer + 6)) & 0x7; + pdata->sd_config__woi_sd0 = + (*(pbuffer + 7)); + pdata->sd_config__woi_sd1 = + (*(pbuffer + 8)); + pdata->sd_config__initial_phase_sd0 = + (*(pbuffer + 9)) & 0x7F; + pdata->sd_config__initial_phase_sd1 = + (*(pbuffer + 10)) & 0x7F; + pdata->system__grouped_parameter_hold_1 = + (*(pbuffer + 11)) & 0x3; + pdata->sd_config__first_order_select = + (*(pbuffer + 12)) & 0x3; + pdata->sd_config__quantifier = + (*(pbuffer + 13)) & 0xF; + pdata->roi_config__user_roi_centre_spad = + (*(pbuffer + 14)); + pdata->roi_config__user_roi_requested_global_xy_size = + (*(pbuffer + 15)); + pdata->system__sequence_config = + (*(pbuffer + 16)); + pdata->system__grouped_parameter_hold = + (*(pbuffer + 17)) & 0x3; + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_dynamic_config( + VL53L1_DEV Dev, + VL53L1_dynamic_config_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_DYNAMIC_CONFIG_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_i2c_encode_dynamic_config( + pdata, + VL53L1_DYNAMIC_CONFIG_I2C_SIZE_BYTES, + comms_buffer); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WriteMulti( + Dev, + VL53L1_SYSTEM__GROUPED_PARAMETER_HOLD_0, + comms_buffer, + VL53L1_DYNAMIC_CONFIG_I2C_SIZE_BYTES); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_dynamic_config( + VL53L1_DEV Dev, + VL53L1_dynamic_config_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_DYNAMIC_CONFIG_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_ReadMulti( + Dev, + VL53L1_SYSTEM__GROUPED_PARAMETER_HOLD_0, + comms_buffer, + VL53L1_DYNAMIC_CONFIG_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_i2c_decode_dynamic_config( + VL53L1_DYNAMIC_CONFIG_I2C_SIZE_BYTES, + comms_buffer, + pdata); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_i2c_encode_system_control( + VL53L1_system_control_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_SYSTEM_CONTROL_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + *(pbuffer + 0) = + pdata->power_management__go1_power_force & 0x1; + *(pbuffer + 1) = + pdata->system__stream_count_ctrl & 0x1; + *(pbuffer + 2) = + pdata->firmware__enable & 0x1; + *(pbuffer + 3) = + pdata->system__interrupt_clear & 0x3; + *(pbuffer + 4) = + pdata->system__mode_start; + LOG_FUNCTION_END(status); + + + return status; +} + + +VL53L1_Error VL53L1_i2c_decode_system_control( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_system_control_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_SYSTEM_CONTROL_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + pdata->power_management__go1_power_force = + (*(pbuffer + 0)) & 0x1; + pdata->system__stream_count_ctrl = + (*(pbuffer + 1)) & 0x1; + pdata->firmware__enable = + (*(pbuffer + 2)) & 0x1; + pdata->system__interrupt_clear = + (*(pbuffer + 3)) & 0x3; + pdata->system__mode_start = + (*(pbuffer + 4)); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_system_control( + VL53L1_DEV Dev, + VL53L1_system_control_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_SYSTEM_CONTROL_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_i2c_encode_system_control( + pdata, + VL53L1_SYSTEM_CONTROL_I2C_SIZE_BYTES, + comms_buffer); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WriteMulti( + Dev, + VL53L1_POWER_MANAGEMENT__GO1_POWER_FORCE, + comms_buffer, + VL53L1_SYSTEM_CONTROL_I2C_SIZE_BYTES); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_system_control( + VL53L1_DEV Dev, + VL53L1_system_control_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_SYSTEM_CONTROL_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_ReadMulti( + Dev, + VL53L1_POWER_MANAGEMENT__GO1_POWER_FORCE, + comms_buffer, + VL53L1_SYSTEM_CONTROL_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_i2c_decode_system_control( + VL53L1_SYSTEM_CONTROL_I2C_SIZE_BYTES, + comms_buffer, + pdata); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_i2c_encode_system_results( + VL53L1_system_results_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_SYSTEM_RESULTS_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + *(pbuffer + 0) = + pdata->result__interrupt_status & 0x3F; + *(pbuffer + 1) = + pdata->result__range_status; + *(pbuffer + 2) = + pdata->result__report_status & 0xF; + *(pbuffer + 3) = + pdata->result__stream_count; + VL53L1_i2c_encode_uint16_t( + pdata->result__dss_actual_effective_spads_sd0, + 2, + pbuffer + 4); + VL53L1_i2c_encode_uint16_t( + pdata->result__peak_signal_count_rate_mcps_sd0, + 2, + pbuffer + 6); + VL53L1_i2c_encode_uint16_t( + pdata->result__ambient_count_rate_mcps_sd0, + 2, + pbuffer + 8); + VL53L1_i2c_encode_uint16_t( + pdata->result__sigma_sd0, + 2, + pbuffer + 10); + VL53L1_i2c_encode_uint16_t( + pdata->result__phase_sd0, + 2, + pbuffer + 12); + VL53L1_i2c_encode_uint16_t( + pdata->result__final_crosstalk_corrected_range_mm_sd0, + 2, + pbuffer + 14); + VL53L1_i2c_encode_uint16_t( + pdata->result__peak_signal_count_rate_crosstalk_corrected_mcps_sd0, + 2, + pbuffer + 16); + VL53L1_i2c_encode_uint16_t( + pdata->result__mm_inner_actual_effective_spads_sd0, + 2, + pbuffer + 18); + VL53L1_i2c_encode_uint16_t( + pdata->result__mm_outer_actual_effective_spads_sd0, + 2, + pbuffer + 20); + VL53L1_i2c_encode_uint16_t( + pdata->result__avg_signal_count_rate_mcps_sd0, + 2, + pbuffer + 22); + VL53L1_i2c_encode_uint16_t( + pdata->result__dss_actual_effective_spads_sd1, + 2, + pbuffer + 24); + VL53L1_i2c_encode_uint16_t( + pdata->result__peak_signal_count_rate_mcps_sd1, + 2, + pbuffer + 26); + VL53L1_i2c_encode_uint16_t( + pdata->result__ambient_count_rate_mcps_sd1, + 2, + pbuffer + 28); + VL53L1_i2c_encode_uint16_t( + pdata->result__sigma_sd1, + 2, + pbuffer + 30); + VL53L1_i2c_encode_uint16_t( + pdata->result__phase_sd1, + 2, + pbuffer + 32); + VL53L1_i2c_encode_uint16_t( + pdata->result__final_crosstalk_corrected_range_mm_sd1, + 2, + pbuffer + 34); + VL53L1_i2c_encode_uint16_t( + pdata->result__spare_0_sd1, + 2, + pbuffer + 36); + VL53L1_i2c_encode_uint16_t( + pdata->result__spare_1_sd1, + 2, + pbuffer + 38); + VL53L1_i2c_encode_uint16_t( + pdata->result__spare_2_sd1, + 2, + pbuffer + 40); + *(pbuffer + 42) = + pdata->result__spare_3_sd1; + *(pbuffer + 43) = + pdata->result__thresh_info; + LOG_FUNCTION_END(status); + + + return status; +} + + +VL53L1_Error VL53L1_i2c_decode_system_results( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_system_results_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_SYSTEM_RESULTS_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + pdata->result__interrupt_status = + (*(pbuffer + 0)) & 0x3F; + pdata->result__range_status = + (*(pbuffer + 1)); + pdata->result__report_status = + (*(pbuffer + 2)) & 0xF; + pdata->result__stream_count = + (*(pbuffer + 3)); + pdata->result__dss_actual_effective_spads_sd0 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 4)); + pdata->result__peak_signal_count_rate_mcps_sd0 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 6)); + pdata->result__ambient_count_rate_mcps_sd0 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 8)); + pdata->result__sigma_sd0 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 10)); + pdata->result__phase_sd0 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 12)); + pdata->result__final_crosstalk_corrected_range_mm_sd0 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 14)); + pdata->result__peak_signal_count_rate_crosstalk_corrected_mcps_sd0 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 16)); + pdata->result__mm_inner_actual_effective_spads_sd0 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 18)); + pdata->result__mm_outer_actual_effective_spads_sd0 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 20)); + pdata->result__avg_signal_count_rate_mcps_sd0 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 22)); + pdata->result__dss_actual_effective_spads_sd1 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 24)); + pdata->result__peak_signal_count_rate_mcps_sd1 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 26)); + pdata->result__ambient_count_rate_mcps_sd1 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 28)); + pdata->result__sigma_sd1 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 30)); + pdata->result__phase_sd1 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 32)); + pdata->result__final_crosstalk_corrected_range_mm_sd1 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 34)); + pdata->result__spare_0_sd1 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 36)); + pdata->result__spare_1_sd1 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 38)); + pdata->result__spare_2_sd1 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 40)); + pdata->result__spare_3_sd1 = + (*(pbuffer + 42)); + pdata->result__thresh_info = + (*(pbuffer + 43)); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_system_results( + VL53L1_DEV Dev, + VL53L1_system_results_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_SYSTEM_RESULTS_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_i2c_encode_system_results( + pdata, + VL53L1_SYSTEM_RESULTS_I2C_SIZE_BYTES, + comms_buffer); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WriteMulti( + Dev, + VL53L1_RESULT__INTERRUPT_STATUS, + comms_buffer, + VL53L1_SYSTEM_RESULTS_I2C_SIZE_BYTES); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_system_results( + VL53L1_DEV Dev, + VL53L1_system_results_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_SYSTEM_RESULTS_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_ReadMulti( + Dev, + VL53L1_RESULT__INTERRUPT_STATUS, + comms_buffer, + VL53L1_SYSTEM_RESULTS_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_i2c_decode_system_results( + VL53L1_SYSTEM_RESULTS_I2C_SIZE_BYTES, + comms_buffer, + pdata); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_i2c_encode_core_results( + VL53L1_core_results_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_CORE_RESULTS_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + VL53L1_i2c_encode_uint32_t( + pdata->result_core__ambient_window_events_sd0, + 4, + pbuffer + 0); + VL53L1_i2c_encode_uint32_t( + pdata->result_core__ranging_total_events_sd0, + 4, + pbuffer + 4); + VL53L1_i2c_encode_int32_t( + pdata->result_core__signal_total_events_sd0, + 4, + pbuffer + 8); + VL53L1_i2c_encode_uint32_t( + pdata->result_core__total_periods_elapsed_sd0, + 4, + pbuffer + 12); + VL53L1_i2c_encode_uint32_t( + pdata->result_core__ambient_window_events_sd1, + 4, + pbuffer + 16); + VL53L1_i2c_encode_uint32_t( + pdata->result_core__ranging_total_events_sd1, + 4, + pbuffer + 20); + VL53L1_i2c_encode_int32_t( + pdata->result_core__signal_total_events_sd1, + 4, + pbuffer + 24); + VL53L1_i2c_encode_uint32_t( + pdata->result_core__total_periods_elapsed_sd1, + 4, + pbuffer + 28); + *(pbuffer + 32) = + pdata->result_core__spare_0; + LOG_FUNCTION_END(status); + + + return status; +} + + +VL53L1_Error VL53L1_i2c_decode_core_results( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_core_results_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_CORE_RESULTS_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + pdata->result_core__ambient_window_events_sd0 = + (VL53L1_i2c_decode_uint32_t(4, pbuffer + 0)); + pdata->result_core__ranging_total_events_sd0 = + (VL53L1_i2c_decode_uint32_t(4, pbuffer + 4)); + pdata->result_core__signal_total_events_sd0 = + (VL53L1_i2c_decode_int32_t(4, pbuffer + 8)); + pdata->result_core__total_periods_elapsed_sd0 = + (VL53L1_i2c_decode_uint32_t(4, pbuffer + 12)); + pdata->result_core__ambient_window_events_sd1 = + (VL53L1_i2c_decode_uint32_t(4, pbuffer + 16)); + pdata->result_core__ranging_total_events_sd1 = + (VL53L1_i2c_decode_uint32_t(4, pbuffer + 20)); + pdata->result_core__signal_total_events_sd1 = + (VL53L1_i2c_decode_int32_t(4, pbuffer + 24)); + pdata->result_core__total_periods_elapsed_sd1 = + (VL53L1_i2c_decode_uint32_t(4, pbuffer + 28)); + pdata->result_core__spare_0 = + (*(pbuffer + 32)); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_core_results( + VL53L1_DEV Dev, + VL53L1_core_results_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_CORE_RESULTS_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_i2c_encode_core_results( + pdata, + VL53L1_CORE_RESULTS_I2C_SIZE_BYTES, + comms_buffer); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_disable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WriteMulti( + Dev, + VL53L1_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD0, + comms_buffer, + VL53L1_CORE_RESULTS_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_firmware(Dev); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_core_results( + VL53L1_DEV Dev, + VL53L1_core_results_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_CORE_RESULTS_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_ReadMulti( + Dev, + VL53L1_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD0, + comms_buffer, + VL53L1_CORE_RESULTS_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_i2c_decode_core_results( + VL53L1_CORE_RESULTS_I2C_SIZE_BYTES, + comms_buffer, + pdata); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_i2c_encode_debug_results( + VL53L1_debug_results_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_DEBUG_RESULTS_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + VL53L1_i2c_encode_uint16_t( + pdata->phasecal_result__reference_phase, + 2, + pbuffer + 0); + *(pbuffer + 2) = + pdata->phasecal_result__vcsel_start & 0x7F; + *(pbuffer + 3) = + pdata->ref_spad_char_result__num_actual_ref_spads & 0x3F; + *(pbuffer + 4) = + pdata->ref_spad_char_result__ref_location & 0x3; + *(pbuffer + 5) = + pdata->vhv_result__coldboot_status & 0x1; + *(pbuffer + 6) = + pdata->vhv_result__search_result & 0x3F; + *(pbuffer + 7) = + pdata->vhv_result__latest_setting & 0x3F; + VL53L1_i2c_encode_uint16_t( + pdata->result__osc_calibrate_val & 0x3FF, + 2, + pbuffer + 8); + *(pbuffer + 10) = + pdata->ana_config__powerdown_go1 & 0x3; + *(pbuffer + 11) = + pdata->ana_config__ref_bg_ctrl & 0x3; + *(pbuffer + 12) = + pdata->ana_config__regdvdd1v2_ctrl & 0xF; + *(pbuffer + 13) = + pdata->ana_config__osc_slow_ctrl & 0x7; + *(pbuffer + 14) = + pdata->test_mode__status & 0x1; + *(pbuffer + 15) = + pdata->firmware__system_status & 0x3; + *(pbuffer + 16) = + pdata->firmware__mode_status; + *(pbuffer + 17) = + pdata->firmware__secondary_mode_status; + VL53L1_i2c_encode_uint16_t( + pdata->firmware__cal_repeat_rate_counter & 0xFFF, + 2, + pbuffer + 18); + VL53L1_i2c_encode_uint16_t( + pdata->gph__system__thresh_high, + 2, + pbuffer + 22); + VL53L1_i2c_encode_uint16_t( + pdata->gph__system__thresh_low, + 2, + pbuffer + 24); + *(pbuffer + 26) = + pdata->gph__system__enable_xtalk_per_quadrant & 0x1; + *(pbuffer + 27) = + pdata->gph__spare_0 & 0x7; + *(pbuffer + 28) = + pdata->gph__sd_config__woi_sd0; + *(pbuffer + 29) = + pdata->gph__sd_config__woi_sd1; + *(pbuffer + 30) = + pdata->gph__sd_config__initial_phase_sd0 & 0x7F; + *(pbuffer + 31) = + pdata->gph__sd_config__initial_phase_sd1 & 0x7F; + *(pbuffer + 32) = + pdata->gph__sd_config__first_order_select & 0x3; + *(pbuffer + 33) = + pdata->gph__sd_config__quantifier & 0xF; + *(pbuffer + 34) = + pdata->gph__roi_config__user_roi_centre_spad; + *(pbuffer + 35) = + pdata->gph__roi_config__user_roi_requested_global_xy_size; + *(pbuffer + 36) = + pdata->gph__system__sequence_config; + *(pbuffer + 37) = + pdata->gph__gph_id & 0x1; + *(pbuffer + 38) = + pdata->system__interrupt_set & 0x3; + *(pbuffer + 39) = + pdata->interrupt_manager__enables & 0x1F; + *(pbuffer + 40) = + pdata->interrupt_manager__clear & 0x1F; + *(pbuffer + 41) = + pdata->interrupt_manager__status & 0x1F; + *(pbuffer + 42) = + pdata->mcu_to_host_bank__wr_access_en & 0x1; + *(pbuffer + 43) = + pdata->power_management__go1_reset_status & 0x1; + *(pbuffer + 44) = + pdata->pad_startup_mode__value_ro & 0x3; + *(pbuffer + 45) = + pdata->pad_startup_mode__value_ctrl & 0x3F; + VL53L1_i2c_encode_uint32_t( + pdata->pll_period_us & 0x3FFFF, + 4, + pbuffer + 46); + VL53L1_i2c_encode_uint32_t( + pdata->interrupt_scheduler__data_out, + 4, + pbuffer + 50); + *(pbuffer + 54) = + pdata->nvm_bist__complete & 0x1; + *(pbuffer + 55) = + pdata->nvm_bist__status & 0x1; + LOG_FUNCTION_END(status); + + + return status; +} + + +VL53L1_Error VL53L1_i2c_decode_debug_results( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_debug_results_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_DEBUG_RESULTS_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + pdata->phasecal_result__reference_phase = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 0)); + pdata->phasecal_result__vcsel_start = + (*(pbuffer + 2)) & 0x7F; + pdata->ref_spad_char_result__num_actual_ref_spads = + (*(pbuffer + 3)) & 0x3F; + pdata->ref_spad_char_result__ref_location = + (*(pbuffer + 4)) & 0x3; + pdata->vhv_result__coldboot_status = + (*(pbuffer + 5)) & 0x1; + pdata->vhv_result__search_result = + (*(pbuffer + 6)) & 0x3F; + pdata->vhv_result__latest_setting = + (*(pbuffer + 7)) & 0x3F; + pdata->result__osc_calibrate_val = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 8)) & 0x3FF; + pdata->ana_config__powerdown_go1 = + (*(pbuffer + 10)) & 0x3; + pdata->ana_config__ref_bg_ctrl = + (*(pbuffer + 11)) & 0x3; + pdata->ana_config__regdvdd1v2_ctrl = + (*(pbuffer + 12)) & 0xF; + pdata->ana_config__osc_slow_ctrl = + (*(pbuffer + 13)) & 0x7; + pdata->test_mode__status = + (*(pbuffer + 14)) & 0x1; + pdata->firmware__system_status = + (*(pbuffer + 15)) & 0x3; + pdata->firmware__mode_status = + (*(pbuffer + 16)); + pdata->firmware__secondary_mode_status = + (*(pbuffer + 17)); + pdata->firmware__cal_repeat_rate_counter = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 18)) & 0xFFF; + pdata->gph__system__thresh_high = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 22)); + pdata->gph__system__thresh_low = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 24)); + pdata->gph__system__enable_xtalk_per_quadrant = + (*(pbuffer + 26)) & 0x1; + pdata->gph__spare_0 = + (*(pbuffer + 27)) & 0x7; + pdata->gph__sd_config__woi_sd0 = + (*(pbuffer + 28)); + pdata->gph__sd_config__woi_sd1 = + (*(pbuffer + 29)); + pdata->gph__sd_config__initial_phase_sd0 = + (*(pbuffer + 30)) & 0x7F; + pdata->gph__sd_config__initial_phase_sd1 = + (*(pbuffer + 31)) & 0x7F; + pdata->gph__sd_config__first_order_select = + (*(pbuffer + 32)) & 0x3; + pdata->gph__sd_config__quantifier = + (*(pbuffer + 33)) & 0xF; + pdata->gph__roi_config__user_roi_centre_spad = + (*(pbuffer + 34)); + pdata->gph__roi_config__user_roi_requested_global_xy_size = + (*(pbuffer + 35)); + pdata->gph__system__sequence_config = + (*(pbuffer + 36)); + pdata->gph__gph_id = + (*(pbuffer + 37)) & 0x1; + pdata->system__interrupt_set = + (*(pbuffer + 38)) & 0x3; + pdata->interrupt_manager__enables = + (*(pbuffer + 39)) & 0x1F; + pdata->interrupt_manager__clear = + (*(pbuffer + 40)) & 0x1F; + pdata->interrupt_manager__status = + (*(pbuffer + 41)) & 0x1F; + pdata->mcu_to_host_bank__wr_access_en = + (*(pbuffer + 42)) & 0x1; + pdata->power_management__go1_reset_status = + (*(pbuffer + 43)) & 0x1; + pdata->pad_startup_mode__value_ro = + (*(pbuffer + 44)) & 0x3; + pdata->pad_startup_mode__value_ctrl = + (*(pbuffer + 45)) & 0x3F; + pdata->pll_period_us = + (VL53L1_i2c_decode_uint32_t(4, pbuffer + 46)) & 0x3FFFF; + pdata->interrupt_scheduler__data_out = + (VL53L1_i2c_decode_uint32_t(4, pbuffer + 50)); + pdata->nvm_bist__complete = + (*(pbuffer + 54)) & 0x1; + pdata->nvm_bist__status = + (*(pbuffer + 55)) & 0x1; + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_debug_results( + VL53L1_DEV Dev, + VL53L1_debug_results_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_DEBUG_RESULTS_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_i2c_encode_debug_results( + pdata, + VL53L1_DEBUG_RESULTS_I2C_SIZE_BYTES, + comms_buffer); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_disable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WriteMulti( + Dev, + VL53L1_PHASECAL_RESULT__REFERENCE_PHASE, + comms_buffer, + VL53L1_DEBUG_RESULTS_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_firmware(Dev); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_debug_results( + VL53L1_DEV Dev, + VL53L1_debug_results_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_DEBUG_RESULTS_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_ReadMulti( + Dev, + VL53L1_PHASECAL_RESULT__REFERENCE_PHASE, + comms_buffer, + VL53L1_DEBUG_RESULTS_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_i2c_decode_debug_results( + VL53L1_DEBUG_RESULTS_I2C_SIZE_BYTES, + comms_buffer, + pdata); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_i2c_encode_nvm_copy_data( + VL53L1_nvm_copy_data_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_NVM_COPY_DATA_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + *(pbuffer + 0) = + pdata->identification__model_id; + *(pbuffer + 1) = + pdata->identification__module_type; + *(pbuffer + 2) = + pdata->identification__revision_id; + VL53L1_i2c_encode_uint16_t( + pdata->identification__module_id, + 2, + pbuffer + 3); + *(pbuffer + 5) = + pdata->ana_config__fast_osc__trim_max & 0x7F; + *(pbuffer + 6) = + pdata->ana_config__fast_osc__freq_set & 0x7; + *(pbuffer + 7) = + pdata->ana_config__vcsel_trim & 0x7; + *(pbuffer + 8) = + pdata->ana_config__vcsel_selion & 0x3F; + *(pbuffer + 9) = + pdata->ana_config__vcsel_selion_max & 0x3F; + *(pbuffer + 10) = + pdata->protected_laser_safety__lock_bit & 0x1; + *(pbuffer + 11) = + pdata->laser_safety__key & 0x7F; + *(pbuffer + 12) = + pdata->laser_safety__key_ro & 0x1; + *(pbuffer + 13) = + pdata->laser_safety__clip & 0x3F; + *(pbuffer + 14) = + pdata->laser_safety__mult & 0x3F; + *(pbuffer + 15) = + pdata->global_config__spad_enables_rtn_0; + *(pbuffer + 16) = + pdata->global_config__spad_enables_rtn_1; + *(pbuffer + 17) = + pdata->global_config__spad_enables_rtn_2; + *(pbuffer + 18) = + pdata->global_config__spad_enables_rtn_3; + *(pbuffer + 19) = + pdata->global_config__spad_enables_rtn_4; + *(pbuffer + 20) = + pdata->global_config__spad_enables_rtn_5; + *(pbuffer + 21) = + pdata->global_config__spad_enables_rtn_6; + *(pbuffer + 22) = + pdata->global_config__spad_enables_rtn_7; + *(pbuffer + 23) = + pdata->global_config__spad_enables_rtn_8; + *(pbuffer + 24) = + pdata->global_config__spad_enables_rtn_9; + *(pbuffer + 25) = + pdata->global_config__spad_enables_rtn_10; + *(pbuffer + 26) = + pdata->global_config__spad_enables_rtn_11; + *(pbuffer + 27) = + pdata->global_config__spad_enables_rtn_12; + *(pbuffer + 28) = + pdata->global_config__spad_enables_rtn_13; + *(pbuffer + 29) = + pdata->global_config__spad_enables_rtn_14; + *(pbuffer + 30) = + pdata->global_config__spad_enables_rtn_15; + *(pbuffer + 31) = + pdata->global_config__spad_enables_rtn_16; + *(pbuffer + 32) = + pdata->global_config__spad_enables_rtn_17; + *(pbuffer + 33) = + pdata->global_config__spad_enables_rtn_18; + *(pbuffer + 34) = + pdata->global_config__spad_enables_rtn_19; + *(pbuffer + 35) = + pdata->global_config__spad_enables_rtn_20; + *(pbuffer + 36) = + pdata->global_config__spad_enables_rtn_21; + *(pbuffer + 37) = + pdata->global_config__spad_enables_rtn_22; + *(pbuffer + 38) = + pdata->global_config__spad_enables_rtn_23; + *(pbuffer + 39) = + pdata->global_config__spad_enables_rtn_24; + *(pbuffer + 40) = + pdata->global_config__spad_enables_rtn_25; + *(pbuffer + 41) = + pdata->global_config__spad_enables_rtn_26; + *(pbuffer + 42) = + pdata->global_config__spad_enables_rtn_27; + *(pbuffer + 43) = + pdata->global_config__spad_enables_rtn_28; + *(pbuffer + 44) = + pdata->global_config__spad_enables_rtn_29; + *(pbuffer + 45) = + pdata->global_config__spad_enables_rtn_30; + *(pbuffer + 46) = + pdata->global_config__spad_enables_rtn_31; + *(pbuffer + 47) = + pdata->roi_config__mode_roi_centre_spad; + *(pbuffer + 48) = + pdata->roi_config__mode_roi_xy_size; + LOG_FUNCTION_END(status); + + + return status; +} + + +VL53L1_Error VL53L1_i2c_decode_nvm_copy_data( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_nvm_copy_data_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_NVM_COPY_DATA_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + pdata->identification__model_id = + (*(pbuffer + 0)); + pdata->identification__module_type = + (*(pbuffer + 1)); + pdata->identification__revision_id = + (*(pbuffer + 2)); + pdata->identification__module_id = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 3)); + pdata->ana_config__fast_osc__trim_max = + (*(pbuffer + 5)) & 0x7F; + pdata->ana_config__fast_osc__freq_set = + (*(pbuffer + 6)) & 0x7; + pdata->ana_config__vcsel_trim = + (*(pbuffer + 7)) & 0x7; + pdata->ana_config__vcsel_selion = + (*(pbuffer + 8)) & 0x3F; + pdata->ana_config__vcsel_selion_max = + (*(pbuffer + 9)) & 0x3F; + pdata->protected_laser_safety__lock_bit = + (*(pbuffer + 10)) & 0x1; + pdata->laser_safety__key = + (*(pbuffer + 11)) & 0x7F; + pdata->laser_safety__key_ro = + (*(pbuffer + 12)) & 0x1; + pdata->laser_safety__clip = + (*(pbuffer + 13)) & 0x3F; + pdata->laser_safety__mult = + (*(pbuffer + 14)) & 0x3F; + pdata->global_config__spad_enables_rtn_0 = + (*(pbuffer + 15)); + pdata->global_config__spad_enables_rtn_1 = + (*(pbuffer + 16)); + pdata->global_config__spad_enables_rtn_2 = + (*(pbuffer + 17)); + pdata->global_config__spad_enables_rtn_3 = + (*(pbuffer + 18)); + pdata->global_config__spad_enables_rtn_4 = + (*(pbuffer + 19)); + pdata->global_config__spad_enables_rtn_5 = + (*(pbuffer + 20)); + pdata->global_config__spad_enables_rtn_6 = + (*(pbuffer + 21)); + pdata->global_config__spad_enables_rtn_7 = + (*(pbuffer + 22)); + pdata->global_config__spad_enables_rtn_8 = + (*(pbuffer + 23)); + pdata->global_config__spad_enables_rtn_9 = + (*(pbuffer + 24)); + pdata->global_config__spad_enables_rtn_10 = + (*(pbuffer + 25)); + pdata->global_config__spad_enables_rtn_11 = + (*(pbuffer + 26)); + pdata->global_config__spad_enables_rtn_12 = + (*(pbuffer + 27)); + pdata->global_config__spad_enables_rtn_13 = + (*(pbuffer + 28)); + pdata->global_config__spad_enables_rtn_14 = + (*(pbuffer + 29)); + pdata->global_config__spad_enables_rtn_15 = + (*(pbuffer + 30)); + pdata->global_config__spad_enables_rtn_16 = + (*(pbuffer + 31)); + pdata->global_config__spad_enables_rtn_17 = + (*(pbuffer + 32)); + pdata->global_config__spad_enables_rtn_18 = + (*(pbuffer + 33)); + pdata->global_config__spad_enables_rtn_19 = + (*(pbuffer + 34)); + pdata->global_config__spad_enables_rtn_20 = + (*(pbuffer + 35)); + pdata->global_config__spad_enables_rtn_21 = + (*(pbuffer + 36)); + pdata->global_config__spad_enables_rtn_22 = + (*(pbuffer + 37)); + pdata->global_config__spad_enables_rtn_23 = + (*(pbuffer + 38)); + pdata->global_config__spad_enables_rtn_24 = + (*(pbuffer + 39)); + pdata->global_config__spad_enables_rtn_25 = + (*(pbuffer + 40)); + pdata->global_config__spad_enables_rtn_26 = + (*(pbuffer + 41)); + pdata->global_config__spad_enables_rtn_27 = + (*(pbuffer + 42)); + pdata->global_config__spad_enables_rtn_28 = + (*(pbuffer + 43)); + pdata->global_config__spad_enables_rtn_29 = + (*(pbuffer + 44)); + pdata->global_config__spad_enables_rtn_30 = + (*(pbuffer + 45)); + pdata->global_config__spad_enables_rtn_31 = + (*(pbuffer + 46)); + pdata->roi_config__mode_roi_centre_spad = + (*(pbuffer + 47)); + pdata->roi_config__mode_roi_xy_size = + (*(pbuffer + 48)); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_nvm_copy_data( + VL53L1_DEV Dev, + VL53L1_nvm_copy_data_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_NVM_COPY_DATA_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_i2c_encode_nvm_copy_data( + pdata, + VL53L1_NVM_COPY_DATA_I2C_SIZE_BYTES, + comms_buffer); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_disable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WriteMulti( + Dev, + VL53L1_IDENTIFICATION__MODEL_ID, + comms_buffer, + VL53L1_NVM_COPY_DATA_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_firmware(Dev); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_nvm_copy_data( + VL53L1_DEV Dev, + VL53L1_nvm_copy_data_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_NVM_COPY_DATA_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_ReadMulti( + Dev, + VL53L1_IDENTIFICATION__MODEL_ID, + comms_buffer, + VL53L1_NVM_COPY_DATA_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_i2c_decode_nvm_copy_data( + VL53L1_NVM_COPY_DATA_I2C_SIZE_BYTES, + comms_buffer, + pdata); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_i2c_encode_prev_shadow_system_results( + VL53L1_prev_shadow_system_results_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_PREV_SHADOW_SYSTEM_RESULTS_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + *(pbuffer + 0) = + pdata->prev_shadow_result__interrupt_status & 0x3F; + *(pbuffer + 1) = + pdata->prev_shadow_result__range_status; + *(pbuffer + 2) = + pdata->prev_shadow_result__report_status & 0xF; + *(pbuffer + 3) = + pdata->prev_shadow_result__stream_count; + VL53L1_i2c_encode_uint16_t( + pdata->prev_shadow_result__dss_actual_effective_spads_sd0, + 2, + pbuffer + 4); + VL53L1_i2c_encode_uint16_t( + pdata->prev_shadow_result__peak_signal_count_rate_mcps_sd0, + 2, + pbuffer + 6); + VL53L1_i2c_encode_uint16_t( + pdata->prev_shadow_result__ambient_count_rate_mcps_sd0, + 2, + pbuffer + 8); + VL53L1_i2c_encode_uint16_t( + pdata->prev_shadow_result__sigma_sd0, + 2, + pbuffer + 10); + VL53L1_i2c_encode_uint16_t( + pdata->prev_shadow_result__phase_sd0, + 2, + pbuffer + 12); + VL53L1_i2c_encode_uint16_t( + pdata->prev_shadow_result__final_crosstalk_corrected_range_mm_sd0, + 2, + pbuffer + 14); + VL53L1_i2c_encode_uint16_t( + pdata->psr__peak_signal_count_rate_crosstalk_corrected_mcps_sd0, + 2, + pbuffer + 16); + VL53L1_i2c_encode_uint16_t( + pdata->prev_shadow_result__mm_inner_actual_effective_spads_sd0, + 2, + pbuffer + 18); + VL53L1_i2c_encode_uint16_t( + pdata->prev_shadow_result__mm_outer_actual_effective_spads_sd0, + 2, + pbuffer + 20); + VL53L1_i2c_encode_uint16_t( + pdata->prev_shadow_result__avg_signal_count_rate_mcps_sd0, + 2, + pbuffer + 22); + VL53L1_i2c_encode_uint16_t( + pdata->prev_shadow_result__dss_actual_effective_spads_sd1, + 2, + pbuffer + 24); + VL53L1_i2c_encode_uint16_t( + pdata->prev_shadow_result__peak_signal_count_rate_mcps_sd1, + 2, + pbuffer + 26); + VL53L1_i2c_encode_uint16_t( + pdata->prev_shadow_result__ambient_count_rate_mcps_sd1, + 2, + pbuffer + 28); + VL53L1_i2c_encode_uint16_t( + pdata->prev_shadow_result__sigma_sd1, + 2, + pbuffer + 30); + VL53L1_i2c_encode_uint16_t( + pdata->prev_shadow_result__phase_sd1, + 2, + pbuffer + 32); + VL53L1_i2c_encode_uint16_t( + pdata->prev_shadow_result__final_crosstalk_corrected_range_mm_sd1, + 2, + pbuffer + 34); + VL53L1_i2c_encode_uint16_t( + pdata->prev_shadow_result__spare_0_sd1, + 2, + pbuffer + 36); + VL53L1_i2c_encode_uint16_t( + pdata->prev_shadow_result__spare_1_sd1, + 2, + pbuffer + 38); + VL53L1_i2c_encode_uint16_t( + pdata->prev_shadow_result__spare_2_sd1, + 2, + pbuffer + 40); + VL53L1_i2c_encode_uint16_t( + pdata->prev_shadow_result__spare_3_sd1, + 2, + pbuffer + 42); + LOG_FUNCTION_END(status); + + + return status; +} + + +VL53L1_Error VL53L1_i2c_decode_prev_shadow_system_results( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_prev_shadow_system_results_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_PREV_SHADOW_SYSTEM_RESULTS_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + pdata->prev_shadow_result__interrupt_status = + (*(pbuffer + 0)) & 0x3F; + pdata->prev_shadow_result__range_status = + (*(pbuffer + 1)); + pdata->prev_shadow_result__report_status = + (*(pbuffer + 2)) & 0xF; + pdata->prev_shadow_result__stream_count = + (*(pbuffer + 3)); + pdata->prev_shadow_result__dss_actual_effective_spads_sd0 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 4)); + pdata->prev_shadow_result__peak_signal_count_rate_mcps_sd0 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 6)); + pdata->prev_shadow_result__ambient_count_rate_mcps_sd0 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 8)); + pdata->prev_shadow_result__sigma_sd0 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 10)); + pdata->prev_shadow_result__phase_sd0 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 12)); + pdata->prev_shadow_result__final_crosstalk_corrected_range_mm_sd0 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 14)); + pdata->psr__peak_signal_count_rate_crosstalk_corrected_mcps_sd0 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 16)); + pdata->prev_shadow_result__mm_inner_actual_effective_spads_sd0 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 18)); + pdata->prev_shadow_result__mm_outer_actual_effective_spads_sd0 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 20)); + pdata->prev_shadow_result__avg_signal_count_rate_mcps_sd0 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 22)); + pdata->prev_shadow_result__dss_actual_effective_spads_sd1 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 24)); + pdata->prev_shadow_result__peak_signal_count_rate_mcps_sd1 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 26)); + pdata->prev_shadow_result__ambient_count_rate_mcps_sd1 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 28)); + pdata->prev_shadow_result__sigma_sd1 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 30)); + pdata->prev_shadow_result__phase_sd1 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 32)); + pdata->prev_shadow_result__final_crosstalk_corrected_range_mm_sd1 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 34)); + pdata->prev_shadow_result__spare_0_sd1 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 36)); + pdata->prev_shadow_result__spare_1_sd1 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 38)); + pdata->prev_shadow_result__spare_2_sd1 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 40)); + pdata->prev_shadow_result__spare_3_sd1 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 42)); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_prev_shadow_system_results( + VL53L1_DEV Dev, + VL53L1_prev_shadow_system_results_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_PREV_SHADOW_SYSTEM_RESULTS_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_i2c_encode_prev_shadow_system_results( + pdata, + VL53L1_PREV_SHADOW_SYSTEM_RESULTS_I2C_SIZE_BYTES, + comms_buffer); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_disable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WriteMulti( + Dev, + VL53L1_PREV_SHADOW_RESULT__INTERRUPT_STATUS, + comms_buffer, + VL53L1_PREV_SHADOW_SYSTEM_RESULTS_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_firmware(Dev); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_prev_shadow_system_results( + VL53L1_DEV Dev, + VL53L1_prev_shadow_system_results_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_PREV_SHADOW_SYSTEM_RESULTS_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_disable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_ReadMulti( + Dev, + VL53L1_PREV_SHADOW_RESULT__INTERRUPT_STATUS, + comms_buffer, + VL53L1_PREV_SHADOW_SYSTEM_RESULTS_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_i2c_decode_prev_shadow_system_results( + VL53L1_PREV_SHADOW_SYSTEM_RESULTS_I2C_SIZE_BYTES, + comms_buffer, + pdata); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_i2c_encode_prev_shadow_core_results( + VL53L1_prev_shadow_core_results_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_PREV_SHADOW_CORE_RESULTS_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + VL53L1_i2c_encode_uint32_t( + pdata->prev_shadow_result_core__ambient_window_events_sd0, + 4, + pbuffer + 0); + VL53L1_i2c_encode_uint32_t( + pdata->prev_shadow_result_core__ranging_total_events_sd0, + 4, + pbuffer + 4); + VL53L1_i2c_encode_int32_t( + pdata->prev_shadow_result_core__signal_total_events_sd0, + 4, + pbuffer + 8); + VL53L1_i2c_encode_uint32_t( + pdata->prev_shadow_result_core__total_periods_elapsed_sd0, + 4, + pbuffer + 12); + VL53L1_i2c_encode_uint32_t( + pdata->prev_shadow_result_core__ambient_window_events_sd1, + 4, + pbuffer + 16); + VL53L1_i2c_encode_uint32_t( + pdata->prev_shadow_result_core__ranging_total_events_sd1, + 4, + pbuffer + 20); + VL53L1_i2c_encode_int32_t( + pdata->prev_shadow_result_core__signal_total_events_sd1, + 4, + pbuffer + 24); + VL53L1_i2c_encode_uint32_t( + pdata->prev_shadow_result_core__total_periods_elapsed_sd1, + 4, + pbuffer + 28); + *(pbuffer + 32) = + pdata->prev_shadow_result_core__spare_0; + LOG_FUNCTION_END(status); + + + return status; +} + + +VL53L1_Error VL53L1_i2c_decode_prev_shadow_core_results( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_prev_shadow_core_results_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_PREV_SHADOW_CORE_RESULTS_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + pdata->prev_shadow_result_core__ambient_window_events_sd0 = + (VL53L1_i2c_decode_uint32_t(4, pbuffer + 0)); + pdata->prev_shadow_result_core__ranging_total_events_sd0 = + (VL53L1_i2c_decode_uint32_t(4, pbuffer + 4)); + pdata->prev_shadow_result_core__signal_total_events_sd0 = + (VL53L1_i2c_decode_int32_t(4, pbuffer + 8)); + pdata->prev_shadow_result_core__total_periods_elapsed_sd0 = + (VL53L1_i2c_decode_uint32_t(4, pbuffer + 12)); + pdata->prev_shadow_result_core__ambient_window_events_sd1 = + (VL53L1_i2c_decode_uint32_t(4, pbuffer + 16)); + pdata->prev_shadow_result_core__ranging_total_events_sd1 = + (VL53L1_i2c_decode_uint32_t(4, pbuffer + 20)); + pdata->prev_shadow_result_core__signal_total_events_sd1 = + (VL53L1_i2c_decode_int32_t(4, pbuffer + 24)); + pdata->prev_shadow_result_core__total_periods_elapsed_sd1 = + (VL53L1_i2c_decode_uint32_t(4, pbuffer + 28)); + pdata->prev_shadow_result_core__spare_0 = + (*(pbuffer + 32)); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_prev_shadow_core_results( + VL53L1_DEV Dev, + VL53L1_prev_shadow_core_results_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_PREV_SHADOW_CORE_RESULTS_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_i2c_encode_prev_shadow_core_results( + pdata, + VL53L1_PREV_SHADOW_CORE_RESULTS_I2C_SIZE_BYTES, + comms_buffer); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_disable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WriteMulti( + Dev, + VL53L1_PREV_SHADOW_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD0, + comms_buffer, + VL53L1_PREV_SHADOW_CORE_RESULTS_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_firmware(Dev); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_prev_shadow_core_results( + VL53L1_DEV Dev, + VL53L1_prev_shadow_core_results_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_PREV_SHADOW_CORE_RESULTS_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_disable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_ReadMulti( + Dev, + VL53L1_PREV_SHADOW_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD0, + comms_buffer, + VL53L1_PREV_SHADOW_CORE_RESULTS_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_i2c_decode_prev_shadow_core_results( + VL53L1_PREV_SHADOW_CORE_RESULTS_I2C_SIZE_BYTES, + comms_buffer, + pdata); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_i2c_encode_patch_debug( + VL53L1_patch_debug_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_PATCH_DEBUG_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + *(pbuffer + 0) = + pdata->result__debug_status; + *(pbuffer + 1) = + pdata->result__debug_stage; + LOG_FUNCTION_END(status); + + + return status; +} + + +VL53L1_Error VL53L1_i2c_decode_patch_debug( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_patch_debug_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_PATCH_DEBUG_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + pdata->result__debug_status = + (*(pbuffer + 0)); + pdata->result__debug_stage = + (*(pbuffer + 1)); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_patch_debug( + VL53L1_DEV Dev, + VL53L1_patch_debug_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_PATCH_DEBUG_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_i2c_encode_patch_debug( + pdata, + VL53L1_PATCH_DEBUG_I2C_SIZE_BYTES, + comms_buffer); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_disable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WriteMulti( + Dev, + VL53L1_RESULT__DEBUG_STATUS, + comms_buffer, + VL53L1_PATCH_DEBUG_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_firmware(Dev); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_patch_debug( + VL53L1_DEV Dev, + VL53L1_patch_debug_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_PATCH_DEBUG_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_disable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_ReadMulti( + Dev, + VL53L1_RESULT__DEBUG_STATUS, + comms_buffer, + VL53L1_PATCH_DEBUG_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_i2c_decode_patch_debug( + VL53L1_PATCH_DEBUG_I2C_SIZE_BYTES, + comms_buffer, + pdata); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_i2c_encode_gph_general_config( + VL53L1_gph_general_config_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_GPH_GENERAL_CONFIG_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + VL53L1_i2c_encode_uint16_t( + pdata->gph__system__thresh_rate_high, + 2, + pbuffer + 0); + VL53L1_i2c_encode_uint16_t( + pdata->gph__system__thresh_rate_low, + 2, + pbuffer + 2); + *(pbuffer + 4) = + pdata->gph__system__interrupt_config_gpio; + LOG_FUNCTION_END(status); + + + return status; +} + + +VL53L1_Error VL53L1_i2c_decode_gph_general_config( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_gph_general_config_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_GPH_GENERAL_CONFIG_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + pdata->gph__system__thresh_rate_high = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 0)); + pdata->gph__system__thresh_rate_low = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 2)); + pdata->gph__system__interrupt_config_gpio = + (*(pbuffer + 4)); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_gph_general_config( + VL53L1_DEV Dev, + VL53L1_gph_general_config_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_GPH_GENERAL_CONFIG_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_i2c_encode_gph_general_config( + pdata, + VL53L1_GPH_GENERAL_CONFIG_I2C_SIZE_BYTES, + comms_buffer); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_disable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WriteMulti( + Dev, + VL53L1_GPH__SYSTEM__THRESH_RATE_HIGH, + comms_buffer, + VL53L1_GPH_GENERAL_CONFIG_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_firmware(Dev); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_gph_general_config( + VL53L1_DEV Dev, + VL53L1_gph_general_config_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_GPH_GENERAL_CONFIG_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_disable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_ReadMulti( + Dev, + VL53L1_GPH__SYSTEM__THRESH_RATE_HIGH, + comms_buffer, + VL53L1_GPH_GENERAL_CONFIG_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_i2c_decode_gph_general_config( + VL53L1_GPH_GENERAL_CONFIG_I2C_SIZE_BYTES, + comms_buffer, + pdata); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_i2c_encode_gph_static_config( + VL53L1_gph_static_config_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_GPH_STATIC_CONFIG_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + *(pbuffer + 0) = + pdata->gph__dss_config__roi_mode_control & 0x7; + VL53L1_i2c_encode_uint16_t( + pdata->gph__dss_config__manual_effective_spads_select, + 2, + pbuffer + 1); + *(pbuffer + 3) = + pdata->gph__dss_config__manual_block_select; + *(pbuffer + 4) = + pdata->gph__dss_config__max_spads_limit; + *(pbuffer + 5) = + pdata->gph__dss_config__min_spads_limit; + LOG_FUNCTION_END(status); + + + return status; +} + + +VL53L1_Error VL53L1_i2c_decode_gph_static_config( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_gph_static_config_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_GPH_STATIC_CONFIG_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + pdata->gph__dss_config__roi_mode_control = + (*(pbuffer + 0)) & 0x7; + pdata->gph__dss_config__manual_effective_spads_select = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 1)); + pdata->gph__dss_config__manual_block_select = + (*(pbuffer + 3)); + pdata->gph__dss_config__max_spads_limit = + (*(pbuffer + 4)); + pdata->gph__dss_config__min_spads_limit = + (*(pbuffer + 5)); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_gph_static_config( + VL53L1_DEV Dev, + VL53L1_gph_static_config_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_GPH_STATIC_CONFIG_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_i2c_encode_gph_static_config( + pdata, + VL53L1_GPH_STATIC_CONFIG_I2C_SIZE_BYTES, + comms_buffer); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_disable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WriteMulti( + Dev, + VL53L1_GPH__DSS_CONFIG__ROI_MODE_CONTROL, + comms_buffer, + VL53L1_GPH_STATIC_CONFIG_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_firmware(Dev); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_gph_static_config( + VL53L1_DEV Dev, + VL53L1_gph_static_config_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_GPH_STATIC_CONFIG_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_disable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_ReadMulti( + Dev, + VL53L1_GPH__DSS_CONFIG__ROI_MODE_CONTROL, + comms_buffer, + VL53L1_GPH_STATIC_CONFIG_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_i2c_decode_gph_static_config( + VL53L1_GPH_STATIC_CONFIG_I2C_SIZE_BYTES, + comms_buffer, + pdata); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_i2c_encode_gph_timing_config( + VL53L1_gph_timing_config_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_GPH_TIMING_CONFIG_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + *(pbuffer + 0) = + pdata->gph__mm_config__timeout_macrop_a_hi & 0xF; + *(pbuffer + 1) = + pdata->gph__mm_config__timeout_macrop_a_lo; + *(pbuffer + 2) = + pdata->gph__mm_config__timeout_macrop_b_hi & 0xF; + *(pbuffer + 3) = + pdata->gph__mm_config__timeout_macrop_b_lo; + *(pbuffer + 4) = + pdata->gph__range_config__timeout_macrop_a_hi & 0xF; + *(pbuffer + 5) = + pdata->gph__range_config__timeout_macrop_a_lo; + *(pbuffer + 6) = + pdata->gph__range_config__vcsel_period_a & 0x3F; + *(pbuffer + 7) = + pdata->gph__range_config__vcsel_period_b & 0x3F; + *(pbuffer + 8) = + pdata->gph__range_config__timeout_macrop_b_hi & 0xF; + *(pbuffer + 9) = + pdata->gph__range_config__timeout_macrop_b_lo; + VL53L1_i2c_encode_uint16_t( + pdata->gph__range_config__sigma_thresh, + 2, + pbuffer + 10); + VL53L1_i2c_encode_uint16_t( + pdata->gph__range_config__min_count_rate_rtn_limit_mcps, + 2, + pbuffer + 12); + *(pbuffer + 14) = + pdata->gph__range_config__valid_phase_low; + *(pbuffer + 15) = + pdata->gph__range_config__valid_phase_high; + LOG_FUNCTION_END(status); + + + return status; +} + + +VL53L1_Error VL53L1_i2c_decode_gph_timing_config( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_gph_timing_config_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_GPH_TIMING_CONFIG_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + pdata->gph__mm_config__timeout_macrop_a_hi = + (*(pbuffer + 0)) & 0xF; + pdata->gph__mm_config__timeout_macrop_a_lo = + (*(pbuffer + 1)); + pdata->gph__mm_config__timeout_macrop_b_hi = + (*(pbuffer + 2)) & 0xF; + pdata->gph__mm_config__timeout_macrop_b_lo = + (*(pbuffer + 3)); + pdata->gph__range_config__timeout_macrop_a_hi = + (*(pbuffer + 4)) & 0xF; + pdata->gph__range_config__timeout_macrop_a_lo = + (*(pbuffer + 5)); + pdata->gph__range_config__vcsel_period_a = + (*(pbuffer + 6)) & 0x3F; + pdata->gph__range_config__vcsel_period_b = + (*(pbuffer + 7)) & 0x3F; + pdata->gph__range_config__timeout_macrop_b_hi = + (*(pbuffer + 8)) & 0xF; + pdata->gph__range_config__timeout_macrop_b_lo = + (*(pbuffer + 9)); + pdata->gph__range_config__sigma_thresh = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 10)); + pdata->gph__range_config__min_count_rate_rtn_limit_mcps = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 12)); + pdata->gph__range_config__valid_phase_low = + (*(pbuffer + 14)); + pdata->gph__range_config__valid_phase_high = + (*(pbuffer + 15)); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_gph_timing_config( + VL53L1_DEV Dev, + VL53L1_gph_timing_config_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_GPH_TIMING_CONFIG_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_i2c_encode_gph_timing_config( + pdata, + VL53L1_GPH_TIMING_CONFIG_I2C_SIZE_BYTES, + comms_buffer); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_disable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WriteMulti( + Dev, + VL53L1_GPH__MM_CONFIG__TIMEOUT_MACROP_A_HI, + comms_buffer, + VL53L1_GPH_TIMING_CONFIG_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_firmware(Dev); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_gph_timing_config( + VL53L1_DEV Dev, + VL53L1_gph_timing_config_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_GPH_TIMING_CONFIG_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_disable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_ReadMulti( + Dev, + VL53L1_GPH__MM_CONFIG__TIMEOUT_MACROP_A_HI, + comms_buffer, + VL53L1_GPH_TIMING_CONFIG_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_i2c_decode_gph_timing_config( + VL53L1_GPH_TIMING_CONFIG_I2C_SIZE_BYTES, + comms_buffer, + pdata); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_i2c_encode_fw_internal( + VL53L1_fw_internal_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_FW_INTERNAL_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + *(pbuffer + 0) = + pdata->firmware__internal_stream_count_div; + *(pbuffer + 1) = + pdata->firmware__internal_stream_counter_val; + LOG_FUNCTION_END(status); + + + return status; +} + + +VL53L1_Error VL53L1_i2c_decode_fw_internal( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_fw_internal_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_FW_INTERNAL_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + pdata->firmware__internal_stream_count_div = + (*(pbuffer + 0)); + pdata->firmware__internal_stream_counter_val = + (*(pbuffer + 1)); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_fw_internal( + VL53L1_DEV Dev, + VL53L1_fw_internal_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_FW_INTERNAL_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_i2c_encode_fw_internal( + pdata, + VL53L1_FW_INTERNAL_I2C_SIZE_BYTES, + comms_buffer); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_disable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WriteMulti( + Dev, + VL53L1_FIRMWARE__INTERNAL_STREAM_COUNT_DIV, + comms_buffer, + VL53L1_FW_INTERNAL_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_firmware(Dev); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_fw_internal( + VL53L1_DEV Dev, + VL53L1_fw_internal_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_FW_INTERNAL_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_disable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_ReadMulti( + Dev, + VL53L1_FIRMWARE__INTERNAL_STREAM_COUNT_DIV, + comms_buffer, + VL53L1_FW_INTERNAL_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_i2c_decode_fw_internal( + VL53L1_FW_INTERNAL_I2C_SIZE_BYTES, + comms_buffer, + pdata); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_i2c_encode_patch_results( + VL53L1_patch_results_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_PATCH_RESULTS_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + *(pbuffer + 0) = + pdata->dss_calc__roi_ctrl & 0x3; + *(pbuffer + 1) = + pdata->dss_calc__spare_1; + *(pbuffer + 2) = + pdata->dss_calc__spare_2; + *(pbuffer + 3) = + pdata->dss_calc__spare_3; + *(pbuffer + 4) = + pdata->dss_calc__spare_4; + *(pbuffer + 5) = + pdata->dss_calc__spare_5; + *(pbuffer + 6) = + pdata->dss_calc__spare_6; + *(pbuffer + 7) = + pdata->dss_calc__spare_7; + *(pbuffer + 8) = + pdata->dss_calc__user_roi_spad_en_0; + *(pbuffer + 9) = + pdata->dss_calc__user_roi_spad_en_1; + *(pbuffer + 10) = + pdata->dss_calc__user_roi_spad_en_2; + *(pbuffer + 11) = + pdata->dss_calc__user_roi_spad_en_3; + *(pbuffer + 12) = + pdata->dss_calc__user_roi_spad_en_4; + *(pbuffer + 13) = + pdata->dss_calc__user_roi_spad_en_5; + *(pbuffer + 14) = + pdata->dss_calc__user_roi_spad_en_6; + *(pbuffer + 15) = + pdata->dss_calc__user_roi_spad_en_7; + *(pbuffer + 16) = + pdata->dss_calc__user_roi_spad_en_8; + *(pbuffer + 17) = + pdata->dss_calc__user_roi_spad_en_9; + *(pbuffer + 18) = + pdata->dss_calc__user_roi_spad_en_10; + *(pbuffer + 19) = + pdata->dss_calc__user_roi_spad_en_11; + *(pbuffer + 20) = + pdata->dss_calc__user_roi_spad_en_12; + *(pbuffer + 21) = + pdata->dss_calc__user_roi_spad_en_13; + *(pbuffer + 22) = + pdata->dss_calc__user_roi_spad_en_14; + *(pbuffer + 23) = + pdata->dss_calc__user_roi_spad_en_15; + *(pbuffer + 24) = + pdata->dss_calc__user_roi_spad_en_16; + *(pbuffer + 25) = + pdata->dss_calc__user_roi_spad_en_17; + *(pbuffer + 26) = + pdata->dss_calc__user_roi_spad_en_18; + *(pbuffer + 27) = + pdata->dss_calc__user_roi_spad_en_19; + *(pbuffer + 28) = + pdata->dss_calc__user_roi_spad_en_20; + *(pbuffer + 29) = + pdata->dss_calc__user_roi_spad_en_21; + *(pbuffer + 30) = + pdata->dss_calc__user_roi_spad_en_22; + *(pbuffer + 31) = + pdata->dss_calc__user_roi_spad_en_23; + *(pbuffer + 32) = + pdata->dss_calc__user_roi_spad_en_24; + *(pbuffer + 33) = + pdata->dss_calc__user_roi_spad_en_25; + *(pbuffer + 34) = + pdata->dss_calc__user_roi_spad_en_26; + *(pbuffer + 35) = + pdata->dss_calc__user_roi_spad_en_27; + *(pbuffer + 36) = + pdata->dss_calc__user_roi_spad_en_28; + *(pbuffer + 37) = + pdata->dss_calc__user_roi_spad_en_29; + *(pbuffer + 38) = + pdata->dss_calc__user_roi_spad_en_30; + *(pbuffer + 39) = + pdata->dss_calc__user_roi_spad_en_31; + *(pbuffer + 40) = + pdata->dss_calc__user_roi_0; + *(pbuffer + 41) = + pdata->dss_calc__user_roi_1; + *(pbuffer + 42) = + pdata->dss_calc__mode_roi_0; + *(pbuffer + 43) = + pdata->dss_calc__mode_roi_1; + *(pbuffer + 44) = + pdata->sigma_estimator_calc__spare_0; + VL53L1_i2c_encode_uint16_t( + pdata->vhv_result__peak_signal_rate_mcps, + 2, + pbuffer + 46); + VL53L1_i2c_encode_uint32_t( + pdata->vhv_result__signal_total_events_ref, + 4, + pbuffer + 48); + VL53L1_i2c_encode_uint16_t( + pdata->phasecal_result__phase_output_ref, + 2, + pbuffer + 52); + VL53L1_i2c_encode_uint16_t( + pdata->dss_result__total_rate_per_spad, + 2, + pbuffer + 54); + *(pbuffer + 56) = + pdata->dss_result__enabled_blocks; + VL53L1_i2c_encode_uint16_t( + pdata->dss_result__num_requested_spads, + 2, + pbuffer + 58); + VL53L1_i2c_encode_uint16_t( + pdata->mm_result__inner_intersection_rate, + 2, + pbuffer + 62); + VL53L1_i2c_encode_uint16_t( + pdata->mm_result__outer_complement_rate, + 2, + pbuffer + 64); + VL53L1_i2c_encode_uint16_t( + pdata->mm_result__total_offset, + 2, + pbuffer + 66); + VL53L1_i2c_encode_uint32_t( + pdata->xtalk_calc__xtalk_for_enabled_spads & 0xFFFFFF, + 4, + pbuffer + 68); + VL53L1_i2c_encode_uint32_t( + pdata->xtalk_result__avg_xtalk_user_roi_kcps & 0xFFFFFF, + 4, + pbuffer + 72); + VL53L1_i2c_encode_uint32_t( + pdata->xtalk_result__avg_xtalk_mm_inner_roi_kcps & 0xFFFFFF, + 4, + pbuffer + 76); + VL53L1_i2c_encode_uint32_t( + pdata->xtalk_result__avg_xtalk_mm_outer_roi_kcps & 0xFFFFFF, + 4, + pbuffer + 80); + VL53L1_i2c_encode_uint32_t( + pdata->range_result__accum_phase, + 4, + pbuffer + 84); + VL53L1_i2c_encode_uint16_t( + pdata->range_result__offset_corrected_range, + 2, + pbuffer + 88); + LOG_FUNCTION_END(status); + + + return status; +} + + +VL53L1_Error VL53L1_i2c_decode_patch_results( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_patch_results_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_PATCH_RESULTS_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + pdata->dss_calc__roi_ctrl = + (*(pbuffer + 0)) & 0x3; + pdata->dss_calc__spare_1 = + (*(pbuffer + 1)); + pdata->dss_calc__spare_2 = + (*(pbuffer + 2)); + pdata->dss_calc__spare_3 = + (*(pbuffer + 3)); + pdata->dss_calc__spare_4 = + (*(pbuffer + 4)); + pdata->dss_calc__spare_5 = + (*(pbuffer + 5)); + pdata->dss_calc__spare_6 = + (*(pbuffer + 6)); + pdata->dss_calc__spare_7 = + (*(pbuffer + 7)); + pdata->dss_calc__user_roi_spad_en_0 = + (*(pbuffer + 8)); + pdata->dss_calc__user_roi_spad_en_1 = + (*(pbuffer + 9)); + pdata->dss_calc__user_roi_spad_en_2 = + (*(pbuffer + 10)); + pdata->dss_calc__user_roi_spad_en_3 = + (*(pbuffer + 11)); + pdata->dss_calc__user_roi_spad_en_4 = + (*(pbuffer + 12)); + pdata->dss_calc__user_roi_spad_en_5 = + (*(pbuffer + 13)); + pdata->dss_calc__user_roi_spad_en_6 = + (*(pbuffer + 14)); + pdata->dss_calc__user_roi_spad_en_7 = + (*(pbuffer + 15)); + pdata->dss_calc__user_roi_spad_en_8 = + (*(pbuffer + 16)); + pdata->dss_calc__user_roi_spad_en_9 = + (*(pbuffer + 17)); + pdata->dss_calc__user_roi_spad_en_10 = + (*(pbuffer + 18)); + pdata->dss_calc__user_roi_spad_en_11 = + (*(pbuffer + 19)); + pdata->dss_calc__user_roi_spad_en_12 = + (*(pbuffer + 20)); + pdata->dss_calc__user_roi_spad_en_13 = + (*(pbuffer + 21)); + pdata->dss_calc__user_roi_spad_en_14 = + (*(pbuffer + 22)); + pdata->dss_calc__user_roi_spad_en_15 = + (*(pbuffer + 23)); + pdata->dss_calc__user_roi_spad_en_16 = + (*(pbuffer + 24)); + pdata->dss_calc__user_roi_spad_en_17 = + (*(pbuffer + 25)); + pdata->dss_calc__user_roi_spad_en_18 = + (*(pbuffer + 26)); + pdata->dss_calc__user_roi_spad_en_19 = + (*(pbuffer + 27)); + pdata->dss_calc__user_roi_spad_en_20 = + (*(pbuffer + 28)); + pdata->dss_calc__user_roi_spad_en_21 = + (*(pbuffer + 29)); + pdata->dss_calc__user_roi_spad_en_22 = + (*(pbuffer + 30)); + pdata->dss_calc__user_roi_spad_en_23 = + (*(pbuffer + 31)); + pdata->dss_calc__user_roi_spad_en_24 = + (*(pbuffer + 32)); + pdata->dss_calc__user_roi_spad_en_25 = + (*(pbuffer + 33)); + pdata->dss_calc__user_roi_spad_en_26 = + (*(pbuffer + 34)); + pdata->dss_calc__user_roi_spad_en_27 = + (*(pbuffer + 35)); + pdata->dss_calc__user_roi_spad_en_28 = + (*(pbuffer + 36)); + pdata->dss_calc__user_roi_spad_en_29 = + (*(pbuffer + 37)); + pdata->dss_calc__user_roi_spad_en_30 = + (*(pbuffer + 38)); + pdata->dss_calc__user_roi_spad_en_31 = + (*(pbuffer + 39)); + pdata->dss_calc__user_roi_0 = + (*(pbuffer + 40)); + pdata->dss_calc__user_roi_1 = + (*(pbuffer + 41)); + pdata->dss_calc__mode_roi_0 = + (*(pbuffer + 42)); + pdata->dss_calc__mode_roi_1 = + (*(pbuffer + 43)); + pdata->sigma_estimator_calc__spare_0 = + (*(pbuffer + 44)); + pdata->vhv_result__peak_signal_rate_mcps = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 46)); + pdata->vhv_result__signal_total_events_ref = + (VL53L1_i2c_decode_uint32_t(4, pbuffer + 48)); + pdata->phasecal_result__phase_output_ref = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 52)); + pdata->dss_result__total_rate_per_spad = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 54)); + pdata->dss_result__enabled_blocks = + (*(pbuffer + 56)); + pdata->dss_result__num_requested_spads = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 58)); + pdata->mm_result__inner_intersection_rate = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 62)); + pdata->mm_result__outer_complement_rate = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 64)); + pdata->mm_result__total_offset = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 66)); + pdata->xtalk_calc__xtalk_for_enabled_spads = + (VL53L1_i2c_decode_uint32_t(4, pbuffer + 68)) & 0xFFFFFF; + pdata->xtalk_result__avg_xtalk_user_roi_kcps = + (VL53L1_i2c_decode_uint32_t(4, pbuffer + 72)) & 0xFFFFFF; + pdata->xtalk_result__avg_xtalk_mm_inner_roi_kcps = + (VL53L1_i2c_decode_uint32_t(4, pbuffer + 76)) & 0xFFFFFF; + pdata->xtalk_result__avg_xtalk_mm_outer_roi_kcps = + (VL53L1_i2c_decode_uint32_t(4, pbuffer + 80)) & 0xFFFFFF; + pdata->range_result__accum_phase = + (VL53L1_i2c_decode_uint32_t(4, pbuffer + 84)); + pdata->range_result__offset_corrected_range = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 88)); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_patch_results( + VL53L1_DEV Dev, + VL53L1_patch_results_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_PATCH_RESULTS_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_i2c_encode_patch_results( + pdata, + VL53L1_PATCH_RESULTS_I2C_SIZE_BYTES, + comms_buffer); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_disable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WriteMulti( + Dev, + VL53L1_DSS_CALC__ROI_CTRL, + comms_buffer, + VL53L1_PATCH_RESULTS_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_firmware(Dev); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_patch_results( + VL53L1_DEV Dev, + VL53L1_patch_results_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_PATCH_RESULTS_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_disable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_ReadMulti( + Dev, + VL53L1_DSS_CALC__ROI_CTRL, + comms_buffer, + VL53L1_PATCH_RESULTS_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_i2c_decode_patch_results( + VL53L1_PATCH_RESULTS_I2C_SIZE_BYTES, + comms_buffer, + pdata); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_i2c_encode_shadow_system_results( + VL53L1_shadow_system_results_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_SHADOW_SYSTEM_RESULTS_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + *(pbuffer + 0) = + pdata->shadow_phasecal_result__vcsel_start; + *(pbuffer + 2) = + pdata->shadow_result__interrupt_status & 0x3F; + *(pbuffer + 3) = + pdata->shadow_result__range_status; + *(pbuffer + 4) = + pdata->shadow_result__report_status & 0xF; + *(pbuffer + 5) = + pdata->shadow_result__stream_count; + VL53L1_i2c_encode_uint16_t( + pdata->shadow_result__dss_actual_effective_spads_sd0, + 2, + pbuffer + 6); + VL53L1_i2c_encode_uint16_t( + pdata->shadow_result__peak_signal_count_rate_mcps_sd0, + 2, + pbuffer + 8); + VL53L1_i2c_encode_uint16_t( + pdata->shadow_result__ambient_count_rate_mcps_sd0, + 2, + pbuffer + 10); + VL53L1_i2c_encode_uint16_t( + pdata->shadow_result__sigma_sd0, + 2, + pbuffer + 12); + VL53L1_i2c_encode_uint16_t( + pdata->shadow_result__phase_sd0, + 2, + pbuffer + 14); + VL53L1_i2c_encode_uint16_t( + pdata->shadow_result__final_crosstalk_corrected_range_mm_sd0, + 2, + pbuffer + 16); + VL53L1_i2c_encode_uint16_t( + pdata->shr__peak_signal_count_rate_crosstalk_corrected_mcps_sd0, + 2, + pbuffer + 18); + VL53L1_i2c_encode_uint16_t( + pdata->shadow_result__mm_inner_actual_effective_spads_sd0, + 2, + pbuffer + 20); + VL53L1_i2c_encode_uint16_t( + pdata->shadow_result__mm_outer_actual_effective_spads_sd0, + 2, + pbuffer + 22); + VL53L1_i2c_encode_uint16_t( + pdata->shadow_result__avg_signal_count_rate_mcps_sd0, + 2, + pbuffer + 24); + VL53L1_i2c_encode_uint16_t( + pdata->shadow_result__dss_actual_effective_spads_sd1, + 2, + pbuffer + 26); + VL53L1_i2c_encode_uint16_t( + pdata->shadow_result__peak_signal_count_rate_mcps_sd1, + 2, + pbuffer + 28); + VL53L1_i2c_encode_uint16_t( + pdata->shadow_result__ambient_count_rate_mcps_sd1, + 2, + pbuffer + 30); + VL53L1_i2c_encode_uint16_t( + pdata->shadow_result__sigma_sd1, + 2, + pbuffer + 32); + VL53L1_i2c_encode_uint16_t( + pdata->shadow_result__phase_sd1, + 2, + pbuffer + 34); + VL53L1_i2c_encode_uint16_t( + pdata->shadow_result__final_crosstalk_corrected_range_mm_sd1, + 2, + pbuffer + 36); + VL53L1_i2c_encode_uint16_t( + pdata->shadow_result__spare_0_sd1, + 2, + pbuffer + 38); + VL53L1_i2c_encode_uint16_t( + pdata->shadow_result__spare_1_sd1, + 2, + pbuffer + 40); + VL53L1_i2c_encode_uint16_t( + pdata->shadow_result__spare_2_sd1, + 2, + pbuffer + 42); + *(pbuffer + 44) = + pdata->shadow_result__spare_3_sd1; + *(pbuffer + 45) = + pdata->shadow_result__thresh_info; + *(pbuffer + 80) = + pdata->shadow_phasecal_result__reference_phase_hi; + *(pbuffer + 81) = + pdata->shadow_phasecal_result__reference_phase_lo; + LOG_FUNCTION_END(status); + + + return status; +} + + +VL53L1_Error VL53L1_i2c_decode_shadow_system_results( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_shadow_system_results_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_SHADOW_SYSTEM_RESULTS_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + pdata->shadow_phasecal_result__vcsel_start = + (*(pbuffer + 0)); + pdata->shadow_result__interrupt_status = + (*(pbuffer + 2)) & 0x3F; + pdata->shadow_result__range_status = + (*(pbuffer + 3)); + pdata->shadow_result__report_status = + (*(pbuffer + 4)) & 0xF; + pdata->shadow_result__stream_count = + (*(pbuffer + 5)); + pdata->shadow_result__dss_actual_effective_spads_sd0 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 6)); + pdata->shadow_result__peak_signal_count_rate_mcps_sd0 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 8)); + pdata->shadow_result__ambient_count_rate_mcps_sd0 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 10)); + pdata->shadow_result__sigma_sd0 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 12)); + pdata->shadow_result__phase_sd0 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 14)); + pdata->shadow_result__final_crosstalk_corrected_range_mm_sd0 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 16)); + pdata->shr__peak_signal_count_rate_crosstalk_corrected_mcps_sd0 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 18)); + pdata->shadow_result__mm_inner_actual_effective_spads_sd0 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 20)); + pdata->shadow_result__mm_outer_actual_effective_spads_sd0 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 22)); + pdata->shadow_result__avg_signal_count_rate_mcps_sd0 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 24)); + pdata->shadow_result__dss_actual_effective_spads_sd1 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 26)); + pdata->shadow_result__peak_signal_count_rate_mcps_sd1 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 28)); + pdata->shadow_result__ambient_count_rate_mcps_sd1 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 30)); + pdata->shadow_result__sigma_sd1 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 32)); + pdata->shadow_result__phase_sd1 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 34)); + pdata->shadow_result__final_crosstalk_corrected_range_mm_sd1 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 36)); + pdata->shadow_result__spare_0_sd1 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 38)); + pdata->shadow_result__spare_1_sd1 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 40)); + pdata->shadow_result__spare_2_sd1 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 42)); + pdata->shadow_result__spare_3_sd1 = + (*(pbuffer + 44)); + pdata->shadow_result__thresh_info = + (*(pbuffer + 45)); + pdata->shadow_phasecal_result__reference_phase_hi = + (*(pbuffer + 80)); + pdata->shadow_phasecal_result__reference_phase_lo = + (*(pbuffer + 81)); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_shadow_system_results( + VL53L1_DEV Dev, + VL53L1_shadow_system_results_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_SHADOW_SYSTEM_RESULTS_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_i2c_encode_shadow_system_results( + pdata, + VL53L1_SHADOW_SYSTEM_RESULTS_I2C_SIZE_BYTES, + comms_buffer); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_disable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WriteMulti( + Dev, + VL53L1_SHADOW_PHASECAL_RESULT__VCSEL_START, + comms_buffer, + VL53L1_SHADOW_SYSTEM_RESULTS_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_firmware(Dev); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_shadow_system_results( + VL53L1_DEV Dev, + VL53L1_shadow_system_results_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_SHADOW_SYSTEM_RESULTS_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_disable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_ReadMulti( + Dev, + VL53L1_SHADOW_PHASECAL_RESULT__VCSEL_START, + comms_buffer, + VL53L1_SHADOW_SYSTEM_RESULTS_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_i2c_decode_shadow_system_results( + VL53L1_SHADOW_SYSTEM_RESULTS_I2C_SIZE_BYTES, + comms_buffer, + pdata); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_i2c_encode_shadow_core_results( + VL53L1_shadow_core_results_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_SHADOW_CORE_RESULTS_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + VL53L1_i2c_encode_uint32_t( + pdata->shadow_result_core__ambient_window_events_sd0, + 4, + pbuffer + 0); + VL53L1_i2c_encode_uint32_t( + pdata->shadow_result_core__ranging_total_events_sd0, + 4, + pbuffer + 4); + VL53L1_i2c_encode_int32_t( + pdata->shadow_result_core__signal_total_events_sd0, + 4, + pbuffer + 8); + VL53L1_i2c_encode_uint32_t( + pdata->shadow_result_core__total_periods_elapsed_sd0, + 4, + pbuffer + 12); + VL53L1_i2c_encode_uint32_t( + pdata->shadow_result_core__ambient_window_events_sd1, + 4, + pbuffer + 16); + VL53L1_i2c_encode_uint32_t( + pdata->shadow_result_core__ranging_total_events_sd1, + 4, + pbuffer + 20); + VL53L1_i2c_encode_int32_t( + pdata->shadow_result_core__signal_total_events_sd1, + 4, + pbuffer + 24); + VL53L1_i2c_encode_uint32_t( + pdata->shadow_result_core__total_periods_elapsed_sd1, + 4, + pbuffer + 28); + *(pbuffer + 32) = + pdata->shadow_result_core__spare_0; + LOG_FUNCTION_END(status); + + + return status; +} + + +VL53L1_Error VL53L1_i2c_decode_shadow_core_results( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_shadow_core_results_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_SHADOW_CORE_RESULTS_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + pdata->shadow_result_core__ambient_window_events_sd0 = + (VL53L1_i2c_decode_uint32_t(4, pbuffer + 0)); + pdata->shadow_result_core__ranging_total_events_sd0 = + (VL53L1_i2c_decode_uint32_t(4, pbuffer + 4)); + pdata->shadow_result_core__signal_total_events_sd0 = + (VL53L1_i2c_decode_int32_t(4, pbuffer + 8)); + pdata->shadow_result_core__total_periods_elapsed_sd0 = + (VL53L1_i2c_decode_uint32_t(4, pbuffer + 12)); + pdata->shadow_result_core__ambient_window_events_sd1 = + (VL53L1_i2c_decode_uint32_t(4, pbuffer + 16)); + pdata->shadow_result_core__ranging_total_events_sd1 = + (VL53L1_i2c_decode_uint32_t(4, pbuffer + 20)); + pdata->shadow_result_core__signal_total_events_sd1 = + (VL53L1_i2c_decode_int32_t(4, pbuffer + 24)); + pdata->shadow_result_core__total_periods_elapsed_sd1 = + (VL53L1_i2c_decode_uint32_t(4, pbuffer + 28)); + pdata->shadow_result_core__spare_0 = + (*(pbuffer + 32)); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_shadow_core_results( + VL53L1_DEV Dev, + VL53L1_shadow_core_results_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_SHADOW_CORE_RESULTS_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_i2c_encode_shadow_core_results( + pdata, + VL53L1_SHADOW_CORE_RESULTS_I2C_SIZE_BYTES, + comms_buffer); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_disable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WriteMulti( + Dev, + VL53L1_SHADOW_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD0, + comms_buffer, + VL53L1_SHADOW_CORE_RESULTS_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_firmware(Dev); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_shadow_core_results( + VL53L1_DEV Dev, + VL53L1_shadow_core_results_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_SHADOW_CORE_RESULTS_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_disable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_ReadMulti( + Dev, + VL53L1_SHADOW_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD0, + comms_buffer, + VL53L1_SHADOW_CORE_RESULTS_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_i2c_decode_shadow_core_results( + VL53L1_SHADOW_CORE_RESULTS_I2C_SIZE_BYTES, + comms_buffer, + pdata); + + LOG_FUNCTION_END(status); + + return status; +} + + diff --git a/drivers/input/misc/vl53L1/lito/src/vl53l1_silicon_core.c b/drivers/input/misc/vl53L1/lito/src/vl53l1_silicon_core.c new file mode 100644 index 000000000000..2c3112b841bd --- /dev/null +++ b/drivers/input/misc/vl53L1/lito/src/vl53l1_silicon_core.c @@ -0,0 +1,187 @@ + +/******************************************************************************* + * Copyright (c) 2017, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#include "vl53l1_ll_def.h" +#include "vl53l1_platform.h" +#include "vl53l1_register_map.h" +#include "vl53l1_core.h" +#include "vl53l1_silicon_core.h" + + +#define LOG_FUNCTION_START(fmt, ...) \ + _LOG_FUNCTION_START(VL53L1_TRACE_MODULE_CORE, fmt, ##__VA_ARGS__) +#define LOG_FUNCTION_END(status, ...) \ + _LOG_FUNCTION_END(VL53L1_TRACE_MODULE_CORE, status, ##__VA_ARGS__) +#define LOG_FUNCTION_END_FMT(status, fmt, ...) \ + _LOG_FUNCTION_END_FMT(VL53L1_TRACE_MODULE_CORE,\ + status, fmt, ##__VA_ARGS__) + + +VL53L1_Error VL53L1_is_firmware_ready_silicon( + VL53L1_DEV Dev, + uint8_t *pready) +{ + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + uint8_t comms_buffer[5]; + + LOG_FUNCTION_START(""); + + + + + status = VL53L1_ReadMulti( + Dev, + VL53L1_INTERRUPT_MANAGER__ENABLES, + comms_buffer, + 5); + + if (status != VL53L1_ERROR_NONE) + goto ENDFUNC; + + pdev->dbg_results.interrupt_manager__enables = + comms_buffer[0]; + pdev->dbg_results.interrupt_manager__clear = + comms_buffer[1]; + pdev->dbg_results.interrupt_manager__status = + comms_buffer[2]; + pdev->dbg_results.mcu_to_host_bank__wr_access_en = + comms_buffer[3]; + pdev->dbg_results.power_management__go1_reset_status = + comms_buffer[4]; + + if ((pdev->sys_ctrl.power_management__go1_power_force & 0x01) + == 0x01) { + + if (((pdev->dbg_results.interrupt_manager__enables & + 0x1F) == 0x1F) && + ((pdev->dbg_results.interrupt_manager__clear + & 0x1F) == 0x1F)) + *pready = 0x01; + else + *pready = 0x00; + + } else { + + + + if ((pdev->dbg_results.power_management__go1_reset_status + & 0x01) == 0x00) + *pready = 0x01; + else + *pready = 0x00; + } + + +ENDFUNC: + LOG_FUNCTION_END(status); + + return status; +} + diff --git a/drivers/input/misc/vl53L1/lito/src/vl53l1_wait.c b/drivers/input/misc/vl53L1/lito/src/vl53l1_wait.c new file mode 100644 index 000000000000..083e53d584a3 --- /dev/null +++ b/drivers/input/misc/vl53L1/lito/src/vl53l1_wait.c @@ -0,0 +1,621 @@ + +/******************************************************************************* + * Copyright (c) 2017, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#include "vl53l1_ll_def.h" +#include "vl53l1_ll_device.h" +#include "vl53l1_platform.h" +#include "vl53l1_core.h" +#include "vl53l1_silicon_core.h" +#include "vl53l1_wait.h" +#include "vl53l1_register_settings.h" + + +#define LOG_FUNCTION_START(fmt, ...) \ + _LOG_FUNCTION_START(VL53L1_TRACE_MODULE_CORE, fmt, ##__VA_ARGS__) +#define LOG_FUNCTION_END(status, ...) \ + _LOG_FUNCTION_END(VL53L1_TRACE_MODULE_CORE, status, ##__VA_ARGS__) +#define LOG_FUNCTION_END_FMT(status, fmt, ...) \ + _LOG_FUNCTION_END_FMT(VL53L1_TRACE_MODULE_CORE, status, \ + fmt, ##__VA_ARGS__) + + +VL53L1_Error VL53L1_wait_for_boot_completion( + VL53L1_DEV Dev) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + uint8_t fw_ready = 0; + + LOG_FUNCTION_START(""); + + if (pdev->wait_method == VL53L1_WAIT_METHOD_BLOCKING) { + + + + + status = + VL53L1_poll_for_boot_completion( + Dev, + VL53L1_BOOT_COMPLETION_POLLING_TIMEOUT_MS); + + } else { + + + + + fw_ready = 0; + while (fw_ready == 0x00 && status == VL53L1_ERROR_NONE) { + status = VL53L1_is_boot_complete( + Dev, + &fw_ready); + + if (status == VL53L1_ERROR_NONE) { + status = VL53L1_WaitMs( + Dev, + VL53L1_POLLING_DELAY_MS); + } + } + } + + LOG_FUNCTION_END(status); + + return status; + +} + + +VL53L1_Error VL53L1_wait_for_firmware_ready( + VL53L1_DEV Dev) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + uint8_t fw_ready = 0; + uint8_t mode_start = 0; + + LOG_FUNCTION_START(""); + + + + + + mode_start = + pdev->sys_ctrl.system__mode_start & + VL53L1_DEVICEMEASUREMENTMODE_MODE_MASK; + + + + + + + + if ((mode_start == VL53L1_DEVICEMEASUREMENTMODE_TIMED) || + (mode_start == VL53L1_DEVICEMEASUREMENTMODE_SINGLESHOT)) { + + if (pdev->wait_method == VL53L1_WAIT_METHOD_BLOCKING) { + + + + + status = + VL53L1_poll_for_firmware_ready( + Dev, + VL53L1_RANGE_COMPLETION_POLLING_TIMEOUT_MS); + + } else { + + + + + fw_ready = 0; + while (fw_ready == 0x00 && status == + VL53L1_ERROR_NONE) { + status = VL53L1_is_firmware_ready( + Dev, + &fw_ready); + + if (status == VL53L1_ERROR_NONE) { + status = VL53L1_WaitMs( + Dev, + VL53L1_POLLING_DELAY_MS); + } + } + } + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_wait_for_range_completion( + VL53L1_DEV Dev) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + uint8_t data_ready = 0; + + LOG_FUNCTION_START(""); + + if (pdev->wait_method == VL53L1_WAIT_METHOD_BLOCKING) { + + + + + status = + VL53L1_poll_for_range_completion( + Dev, + VL53L1_RANGE_COMPLETION_POLLING_TIMEOUT_MS); + + } else { + + + + + data_ready = 0; + while (data_ready == 0x00 && status == VL53L1_ERROR_NONE) { + status = VL53L1_is_new_data_ready( + Dev, + &data_ready); + + if (status == VL53L1_ERROR_NONE) { + status = VL53L1_WaitMs( + Dev, + VL53L1_POLLING_DELAY_MS); + } + } + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_wait_for_test_completion( + VL53L1_DEV Dev) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + uint8_t data_ready = 0; + + LOG_FUNCTION_START(""); + + if (pdev->wait_method == VL53L1_WAIT_METHOD_BLOCKING) { + + + + + status = + VL53L1_poll_for_range_completion( + Dev, + VL53L1_TEST_COMPLETION_POLLING_TIMEOUT_MS); + + } else { + + + + + data_ready = 0; + while (data_ready == 0x00 && status == VL53L1_ERROR_NONE) { + status = VL53L1_is_new_data_ready( + Dev, + &data_ready); + + if (status == VL53L1_ERROR_NONE) { + status = VL53L1_WaitMs( + Dev, + VL53L1_POLLING_DELAY_MS); + } + } + } + + LOG_FUNCTION_END(status); + + return status; +} + + + + +VL53L1_Error VL53L1_is_boot_complete( + VL53L1_DEV Dev, + uint8_t *pready) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t firmware__system_status = 0; + + LOG_FUNCTION_START(""); + + + + + status = + VL53L1_RdByte( + Dev, + VL53L1_FIRMWARE__SYSTEM_STATUS, + &firmware__system_status); + + + + + + + if ((firmware__system_status & 0x01) == 0x01) { + *pready = 0x01; + VL53L1_init_ll_driver_state( + Dev, + VL53L1_DEVICESTATE_SW_STANDBY); + } else { + *pready = 0x00; + VL53L1_init_ll_driver_state( + Dev, + VL53L1_DEVICESTATE_FW_COLDBOOT); + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_is_firmware_ready( + VL53L1_DEV Dev, + uint8_t *pready) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + status = VL53L1_is_firmware_ready_silicon( + Dev, + pready); + + pdev->fw_ready = *pready; + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_is_new_data_ready( + VL53L1_DEV Dev, + uint8_t *pready) +{ + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + uint8_t gpio__mux_active_high_hv = 0; + uint8_t gpio__tio_hv_status = 0; + uint8_t interrupt_ready = 0; + + LOG_FUNCTION_START(""); + + gpio__mux_active_high_hv = + pdev->stat_cfg.gpio_hv_mux__ctrl & + VL53L1_DEVICEINTERRUPTLEVEL_ACTIVE_MASK; + + if (gpio__mux_active_high_hv == VL53L1_DEVICEINTERRUPTLEVEL_ACTIVE_HIGH) + interrupt_ready = 0x01; + else + interrupt_ready = 0x00; + + + + + status = VL53L1_RdByte( + Dev, + VL53L1_GPIO__TIO_HV_STATUS, + &gpio__tio_hv_status); + + + + + if ((gpio__tio_hv_status & 0x01) == interrupt_ready) + *pready = 0x01; + else + *pready = 0x00; + + LOG_FUNCTION_END(status); + + return status; +} + + + + +VL53L1_Error VL53L1_poll_for_boot_completion( + VL53L1_DEV Dev, + uint32_t timeout_ms) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + + + + + status = VL53L1_WaitUs( + Dev, + VL53L1_FIRMWARE_BOOT_TIME_US); + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_WaitValueMaskEx( + Dev, + timeout_ms, + VL53L1_FIRMWARE__SYSTEM_STATUS, + 0x01, + 0x01, + VL53L1_POLLING_DELAY_MS); + + if (status == VL53L1_ERROR_NONE) + VL53L1_init_ll_driver_state(Dev, VL53L1_DEVICESTATE_SW_STANDBY); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_poll_for_firmware_ready( + VL53L1_DEV Dev, + uint32_t timeout_ms) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + uint32_t start_time_ms = 0; + uint32_t current_time_ms = 0; + int32_t poll_delay_ms = VL53L1_POLLING_DELAY_MS; + uint8_t fw_ready = 0; + + + + + VL53L1_GetTickCount(&start_time_ms); + + pdev->fw_ready_poll_duration_ms = 0; + + + + + while ((status == VL53L1_ERROR_NONE) && + (pdev->fw_ready_poll_duration_ms < timeout_ms) && + (fw_ready == 0)) { + + status = VL53L1_is_firmware_ready( + Dev, + &fw_ready); + + if (status == VL53L1_ERROR_NONE && + fw_ready == 0 && + poll_delay_ms > 0) { + status = VL53L1_WaitMs( + Dev, + poll_delay_ms); + } + + + + + + + VL53L1_GetTickCount(¤t_time_ms); + + pdev->fw_ready_poll_duration_ms = + current_time_ms - start_time_ms; + } + + if (fw_ready == 0 && status == VL53L1_ERROR_NONE) + status = VL53L1_ERROR_TIME_OUT; + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_poll_for_range_completion( + VL53L1_DEV Dev, + uint32_t timeout_ms) +{ + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + uint8_t gpio__mux_active_high_hv = 0; + uint8_t interrupt_ready = 0; + + LOG_FUNCTION_START(""); + + gpio__mux_active_high_hv = + pdev->stat_cfg.gpio_hv_mux__ctrl & + VL53L1_DEVICEINTERRUPTLEVEL_ACTIVE_MASK; + + if (gpio__mux_active_high_hv == VL53L1_DEVICEINTERRUPTLEVEL_ACTIVE_HIGH) + interrupt_ready = 0x01; + else + interrupt_ready = 0x00; + + status = + VL53L1_WaitValueMaskEx( + Dev, + timeout_ms, + VL53L1_GPIO__TIO_HV_STATUS, + interrupt_ready, + 0x01, + VL53L1_POLLING_DELAY_MS); + + LOG_FUNCTION_END(status); + + return status; +} + + diff --git a/drivers/input/misc/vl53L1/lito/src/vl53l1_zone_presets.c b/drivers/input/misc/vl53L1/lito/src/vl53l1_zone_presets.c new file mode 100644 index 000000000000..e35f395a233f --- /dev/null +++ b/drivers/input/misc/vl53L1/lito/src/vl53l1_zone_presets.c @@ -0,0 +1,253 @@ + +/******************************************************************************* + * Copyright (c) 2017, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#include "vl53l1_ll_def.h" +#include "vl53l1_ll_device.h" +#include "vl53l1_platform_log.h" +#include "vl53l1_zone_presets.h" + + +#define LOG_FUNCTION_START(fmt, ...) \ + _LOG_FUNCTION_START(VL53L1_TRACE_MODULE_CORE, fmt, ##__VA_ARGS__) +#define LOG_FUNCTION_END(status, ...) \ + _LOG_FUNCTION_END(VL53L1_TRACE_MODULE_CORE, status, ##__VA_ARGS__) +#define LOG_FUNCTION_END_FMT(status, fmt, ...) \ + _LOG_FUNCTION_END_FMT(VL53L1_TRACE_MODULE_CORE,\ + status, fmt, ##__VA_ARGS__) + + +VL53L1_Error VL53L1_init_zone_config_structure( + uint8_t x_off, + uint8_t x_inc, + uint8_t x_zones, + uint8_t y_off, + uint8_t y_inc, + uint8_t y_zones, + uint8_t width, + uint8_t height, + VL53L1_zone_config_t *pdata) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + uint8_t x = 0; + uint8_t y = 0; + uint16_t i = 0; + + LOG_FUNCTION_START(""); + + pdata->max_zones = VL53L1_MAX_USER_ZONES; + + i = 0; + + for (x = 0 ; x < x_zones ; x++) { + for (y = 0 ; y < y_zones ; y++) { + + if (i < VL53L1_MAX_USER_ZONES) { + + pdata->active_zones = (uint8_t)i; + pdata->user_zones[i].height = height; + pdata->user_zones[i].width = width; + pdata->user_zones[i].x_centre = + x_off + (x * x_inc); + pdata->user_zones[i].y_centre = + y_off + (y * y_inc); + } + + i++; + } + } + + status = VL53L1_init_zone_config_histogram_bins(pdata); + + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_zone_preset_xtalk_planar( + VL53L1_general_config_t *pgeneral, + VL53L1_zone_config_t *pzone_cfg) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + + + pgeneral->global_config__stream_divider = 0x05; + + + + pzone_cfg->active_zones = 0x04; + + pzone_cfg->user_zones[0].height = 15; + pzone_cfg->user_zones[0].width = 7; + pzone_cfg->user_zones[0].x_centre = 4; + pzone_cfg->user_zones[0].y_centre = 8; + + pzone_cfg->user_zones[1].height = 15; + pzone_cfg->user_zones[1].width = 7; + pzone_cfg->user_zones[1].x_centre = 12; + pzone_cfg->user_zones[1].y_centre = 8; + + pzone_cfg->user_zones[2].height = 7; + pzone_cfg->user_zones[2].width = 15; + pzone_cfg->user_zones[2].x_centre = 8; + pzone_cfg->user_zones[2].y_centre = 4; + + pzone_cfg->user_zones[3].height = 7; + pzone_cfg->user_zones[3].width = 15; + pzone_cfg->user_zones[3].x_centre = 8; + pzone_cfg->user_zones[3].y_centre = 12; + + + + + pzone_cfg->user_zones[4].height = 15; + pzone_cfg->user_zones[4].width = 15; + pzone_cfg->user_zones[4].x_centre = 8; + pzone_cfg->user_zones[4].y_centre = 8; + + status = VL53L1_init_zone_config_histogram_bins(pzone_cfg); + + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_init_zone_config_histogram_bins( + VL53L1_zone_config_t *pdata) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + uint8_t i; + + LOG_FUNCTION_START(""); + + for (i = 0; i < pdata->max_zones; i++) + pdata->bin_config[i] = VL53L1_ZONECONFIG_BINCONFIG__LOWAMB; + + LOG_FUNCTION_END(status); + + return status; +} + diff --git a/drivers/input/misc/vl53L1/lito/st,stmvl53l1.txt b/drivers/input/misc/vl53L1/lito/st,stmvl53l1.txt new file mode 100644 index 000000000000..3f81932590c2 --- /dev/null +++ b/drivers/input/misc/vl53L1/lito/st,stmvl53l1.txt @@ -0,0 +1,26 @@ +StMicroelectronis vl53l1 + +Requires properties: +- compatible: must be "st,stmvl53l1". +- reg: I2C address of the chip. +- xsdn-gpio: gpio number connected to vl53l1 reset pin. + +Optional properties: +- intr-gpio: gpio number connected to vl53l1 irq pin. +- vdd: a phandle for the regulator supplying power for vl53l1. +- pwren-gpio: gpio number use to control vl53l1 power. + +Example: + &i2c1 { + /* ... */ + + stmvl53l1: stmvl53l1@29 { + compatible = "st,stmvl53l1"; + reg = <0x29>; + xsdn-gpio = <19>; + pwren-gpio = <12>; + intr-gpio = <16>; + }; + + /* ... */ + }; diff --git a/drivers/input/misc/vl53L1/lito/stmvl53l1-i2c.h b/drivers/input/misc/vl53L1/lito/stmvl53l1-i2c.h new file mode 100644 index 000000000000..dd08ac59eaad --- /dev/null +++ b/drivers/input/misc/vl53L1/lito/stmvl53l1-i2c.h @@ -0,0 +1,116 @@ +/************************************************************************** + * Copyright (c) 2016, STMicroelectronics - All Rights Reserved + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ****************************************************************************/ + +/** @file stmvl53l1-i2c.h + * Linux kernel i2c/cci wrapper for ST VL53L1 sensor i2c interface + **/ + +#ifndef STMVL53L1_I2C_H +#define STMVL53L1_I2C_H +#include +#include "stmvl53l1.h" + +struct i2c_data { + struct i2c_client *client; + /** back link to driver for interrupt and clean-up */ + struct stmvl53l1_data *vl53l1_data; + + /* reference counter */ + struct kref ref; + + /*!< if null no regulator use for power ctrl */ + struct regulator *vdd; + + struct regulator *xsd; + + /*!< power enable gpio number + * + * if -1 no gpio if vdd not avl pwr is not controllable + */ + int pwren_gpio; + + /*!< xsdn reset (low active) gpio number to device + * + * -1 mean none assume no "resetable" + */ + int xsdn_gpio; + + /*!< intr gpio number to device + * + * intr is active/low negative edge by default + * + * -1 mean none assume use polling + * @warning if the dev tree and intr gpio is require please adapt code + */ + int intr_gpio; + + /*!< device boot i2c register address + * + * boot_reg is the value of device i2c address after it is bring out + * of reset. + */ + int boot_reg; + + /*!< is set if above irq gpio got acquired */ + struct i2d_data_flags_t { + unsigned pwr_owned:1; /*!< set if pwren gpio is owned*/ + unsigned xsdn_owned:1; /*!< set if sxdn gpio is owned*/ + unsigned intr_owned:1; /*!< set if intr gpio is owned*/ + unsigned intr_started:1; /*!< set if irq is hanlde */ + } io_flag; + + /** the irq vectore assigned to gpio + * -1 if no irq hanled + */ + int irq; + + struct msgtctrl_t { + unsigned unhandled_irq_vec:1; + } msg_flag; +}; + +#ifdef USE_CAMERA_CCI +int __init stmvl53l1_init_cci(void); +void __exit stmvl53l1_exit_cci(void*); +#else +int stmvl53l1_init_i2c(void); +void __exit stmvl53l1_exit_i2c(void *arg); +#endif +int stmvl53l1_power_up_i2c(void *arg); +int stmvl53l1_power_down_i2c(void *arg); +int stmvl53l1_reset_release_i2c(void *arg); +int stmvl53l1_reset_hold_i2c(void *arg); +void stmvl53l1_clean_up_i2c(void); +int stmvl53l1_start_intr(void *object, int *poll_mode); +void *stmvl53l1_get(void *arg); +void stmvl53l1_put(void *arg); + +#endif /* STMVL53L1_I2C_H */ diff --git a/drivers/input/misc/vl53L1/lito/stmvl53l1.h b/drivers/input/misc/vl53L1/lito/stmvl53l1.h new file mode 100644 index 000000000000..9970597b26e8 --- /dev/null +++ b/drivers/input/misc/vl53L1/lito/stmvl53l1.h @@ -0,0 +1,391 @@ +/************************************************************************** + * Copyright (c) 2016, STMicroelectronics - All Rights Reserved + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ****************************************************************************/ +/** + * @file stmvl53l1.h header for vl53l1 sensor driver + */ +#ifndef STMVL53L1_H +#define STMVL53L1_H + +#include +#include +#include +#include +#include + +#include "vl53l1_api.h" + +/** + * IPP adapt + */ +#ifdef DEBUG +# define IPP_PRINT(...) printk(__VA_ARGS__) +#else +# define IPP_PRINT(...) (void)0 +#endif + +#include "stmvl53l1_ipp.h" +#include "stmvl53l1_if.h" + +/** + * Configure the Netlink-id use + */ +#define STMVL531_CFG_NETLINK_USER 31 + +#define STMVL53L1_MAX_CCI_XFER_SZ 256 +#define STMVL53L1_DRV_NAME "stmvl53l1" + +/** + * configure usage of regulator device from device tree info + * to enable/disable sensor power + * see module-i2c or module-cci file + */ +/* define CFG_STMVL53L1_HAVE_REGULATOR */ + +#define DRIVER_VERSION "13.0.1" + +/** @ingroup vl53l1_config + * @{ + */ +/** + * Configure max number of device the driver can support + */ +#define STMVL53L1_CFG_MAX_DEV 2 +/** @} */ /* ingroup vl53l1_config */ + +/** @ingroup vl53l1_mod_dbg + * @{ + */ +#if 0 +#define DEBUG 1 +#endif +#if 1 +#define FORCE_CONSOLE_DEBUG +#endif + +extern int stmvl53l1_enable_debug; + +#ifdef DEBUG +#ifdef FORCE_CONSOLE_DEBUG +#define vl53l1_dbgmsg(str, ...) do { \ + if (stmvl53l1_enable_debug) \ + pr_info("%s: " str, __func__, ##__VA_ARGS__); \ +} while (0) +#else +#define vl53l1_dbgmsg(str, ...) do { \ + if (stmvl53l1_enable_debug) \ + pr_info("%s: " str, __func__, ##__VA_ARGS__); \ +} while (0) +#endif +#else +#define vl53l1_dbgmsg(...) (void)0 +#endif + +/** + * set to 0 1 activate or not debug from work (data interrupt/polling) + */ +#define WORK_DEBUG 0 +#if WORK_DEBUG +# define work_dbg(msg, ...)\ + printk("[D WK53L1] :" msg "\n", ##__VA_ARGS__) +#else +# define work_dbg(...) (void)0 +#endif + +#define vl53l1_info(str, args...) \ + pr_info("%s: " str "\n", __func__, ##args) + +#define vl53l1_errmsg(str, args...) \ + pr_err("%s: " str, __func__, ##args) + +#define vl53l1_wanrmsg(str, args...) \ + pr_warn("%s: " str, __func__, ##args) + +/* turn off poll log if not defined */ +#ifndef STMVL53L1_LOG_POLL_TIMING +# define STMVL53L1_LOG_POLL_TIMING 0 +#endif +/* turn off cci log timing if not defined */ +#ifndef STMVL53L1_LOG_CCI_TIMING +# define STMVL53L1_LOG_CCI_TIMING 0 +#endif + +/**@} */ /* ingroup mod_dbg*/ + +#include +#include +#include + +/** if set to 1 enable ipp execution timing (if debug enabled) + * @ingroup vl53l1_mod_dbg + */ +#define IPP_LOG_TIMING 1 + +struct ipp_data_t { + struct ipp_work_t work; + struct ipp_work_t work_out; + int test_n; + /*!< buzy state 0 is idle + *any other value do not try to use (state value defined in source) + */ + int buzy; + int waited_xfer_id; + /*!< when buzy is set that is the id we are expecting + * note that value 0 is reserved and stand for "not waiting" + * as such never id 0 will be in any round trip exchange + * it's ok for daemon to use 0 in "ping" when it identify himself + */ + int status; /** if that is not 0 do not look at out work data */ + wait_queue_head_t waitq; + /*!< ipp caller are put in that queue wait while job is posted to user + * @warning ipp and dev mutex will be released before waiting + * see @ref ipp_abort + */ +#if IPP_LOG_TIMING + struct timeval start_tv, stop_tv; +#endif +}; + +struct stmvl53l1_waiters { + struct list_head list; + pid_t pid; +}; + +/* + * driver data structs + */ +struct stmvl53l1_data { + int id; /*!< multiple device id 0 based*/ + char name[64]; /*!< misc device name */ + + VL53L1_DevData_t stdev; /*!ipp.stop_tv) +# define stmvl531_ipp_tim_start(data)\ + do_gettimeofday(&data->ipp.start_tv) +# define stmvl531_ipp_time(data)\ + stmvl53l1_tv_dif(&data->ipp.start_tv, &data->ipp.stop_tv) +# define stmvl531_ipp_stat(data, fmt, ...)\ + vl53l1_dbgmsg("IPPSTAT " fmt "\n", ##__VA_ARGS__) +#else +# define stmvl531_ipp_tim_stop(data) (void)0 +# define stmvl531_ipp_tim_start(data) (void)0 +# define stmvl531_ipp_stat(...) (void)0 +#endif +}; + + +/** + * timeval diff in us + * + * @param pstart_tv + * @param pstop_tv + */ +long stmvl53l1_tv_dif(struct timeval *pstart_tv, struct timeval *pstop_tv); + + +/** + * The device table list table is update as device get added + * we do not support adding removing device mutiple time ! + * use for clean "unload" purpose + */ +extern struct stmvl53l1_data *stmvl53l1_dev_table[]; + +int stmvl53l1_setup(struct stmvl53l1_data *data); +void stmvl53l1_cleanup(struct stmvl53l1_data *data); +#ifdef CONFIG_PM_SLEEP +void stmvl53l1_pm_suspend_stop(struct stmvl53l1_data *data); +#endif +int stmvl53l1_intr_handler(struct stmvl53l1_data *data); + + +/** + * request ipp to abort or stop + * + * require dev work_mutex held + * + * @warning because the "waiting" work can't be aborted we must wake it up + * it will happen and at some later time not earlier than release of lock + * if after lock release we have a new request to start the race may not be + * handled correctly + * + * @param data the device + * @return 0 if no ipp got canceled, @warning this is maybe not grant we + * can't re-sched "dev work" and re-run the worker back + */ +int stmvl53l1_ipp_stop(struct stmvl53l1_data *data); + +int stmvl53l1_ipp_do(struct stmvl53l1_data *data, struct ipp_work_t *work_in, + struct ipp_work_t *work_out); + +/** + * per device netlink init + * @param data + * @return + */ +int stmvl53l1_ipp_setup(struct stmvl53l1_data *data); +/** + * per device ipp netlink cleaning + * @param data + * @return + */ +void stmvl53l1_ipp_cleanup(struct stmvl53l1_data *data); + +/** + * Module init for netlink + * @return 0 on success + */ +int stmvl53l1_ipp_init(void); + +/** + * Module exit for netlink + * @return 0 on success + */ +void stmvl53l1_ipp_exit(void); + +/** + * enable and start ipp exhange + * @param n_dev number of device to run on + * @param data dev struct + * @return 0 on success + */ +int stmvl53l1_ipp_enable(int n_dev, struct stmvl53l1_data *data); + + +/* + * function pointer structs + */ + + + +#endif /* STMVL53L1_H */ diff --git a/drivers/input/misc/vl53L1/lito/stmvl53l1_i2c.c b/drivers/input/misc/vl53L1/lito/stmvl53l1_i2c.c new file mode 100644 index 000000000000..17e9420f6eb8 --- /dev/null +++ b/drivers/input/misc/vl53L1/lito/stmvl53l1_i2c.c @@ -0,0 +1,406 @@ +/************************************************************************** + * Copyright (c) 2016, STMicroelectronics - All Rights Reserved + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ****************************************************************************/ + +/** + * @file stmvl53l1_i2c.c vl53l1 linux native i2c interface + * + */ +#include "stmvl53l1.h" +#include "stmvl53l1-i2c.h" +#include +#include "cam_cci_ctrl_interface.h" + + +#if STMVL53L1_LOG_POLL_TIMING +/** + * helper to elapse time in polling + * @param ptv pointer to start time_val + + */ +# define poll_timing_log(ptv) \ + vl53l1_dbgmsg("poll in %d us\n", tv_elapsed_us(ptv)) +#else +# define poll_timing_log(...) (void)0 +#endif + +#if STMVL53L1_LOG_CCI_TIMING +/** + * compute elapsed time in in micro sec based on do_gettimeofday + * @param tv pointer to start time_val + * @return time elapsed in micro seconde + */ + +/** + * compute elapsed time in in micro sec based on do_gettimeofday + * @param tv pointer to start time_val + * @return time elapsed in micro seconde + */ +static uint32_t tv_elapsed_us(struct timeval *tv) +{ + struct timeval now; + + do_gettimeofday(&now); + return (now.tv_sec - tv->tv_sec) * 1000000 + (now.tv_usec - + tv->tv_usec); +} + +# define cci_access_var struct timeval cci_log_start_tv +# define cci_access_start()\ + do_gettimeofday(&cci_log_start_tv) +# define cci_access_over(fmt, ...) \ + vl53l1_dbgmsg("cci_timing %d us" fmt "\n", \ + tv_elapsed_us(&cci_log_start_tv), ##__VA_ARGS__) +#else +# define cci_access_var +# define cci_access_start(...) (void)0 +# define cci_access_over(...) (void)0 +#endif + +#ifdef STMVL53L1_DEBUG_I2C +# define i2c_debug(fmt, ...) vl53l1_dbgmsg(fmt, ##__VA_ARGS__) +#else +# define i2c_debug(fmt, ...) (void)0 +#endif + +VL53L1_Error VL53L1_GetTickCount(uint32_t *ptime_ms) +{ + (void)ptime_ms; + BUG_ON(1); +} + +/** + * compute elapsed time in in milli sec based on do_gettimeofday + * @param tv pointer to start time_val + * @return time elapsed in milli seconde + */ +static uint32_t tv_elapsed_ms(struct timeval *tv) +{ + struct timeval now; + + do_gettimeofday(&now); + return (now.tv_sec - tv->tv_sec) * 1000 + + (now.tv_usec - tv->tv_usec) / 1000; +} + +#ifndef USE_CAMERA_CCI +static int cci_write(struct stmvl53l1_data *dev, int index, + uint8_t *data, uint16_t len) +{ + uint8_t buffer[STMVL53L1_MAX_CCI_XFER_SZ + 2]; + struct i2c_msg msg; + struct i2c_data *i2c_client_obj = (struct i2c_data *)dev->client_object; + struct i2c_client *client = (struct i2c_client *)i2c_client_obj->client; + int rc; + + cci_access_var; + if (len > STMVL53L1_MAX_CCI_XFER_SZ || len == 0) { + vl53l1_errmsg("invalid len %d\n", len); + return -1; + } + cci_access_start(); + /* build up little endian index in buffer */ + buffer[0] = (index >> 8) & 0xFF; + buffer[1] = (index >> 0) & 0xFF; + /* copy write data to buffer after index */ + memcpy(buffer + 2, data, len); + /* set i2c msg */ + msg.addr = client->addr; + msg.flags = client->flags; + msg.buf = buffer; + msg.len = len + 2; + + rc = i2c_transfer(client->adapter, &msg, 1); + if (rc != 1) { + vl53l1_errmsg("wr i2c_transfer err:%d, index 0x%x len %d\n", + rc, index, len); + } + cci_access_over("rd status %d long %d ", rc != 1, len); + return rc != 1; +} + +static int cci_read(struct stmvl53l1_data *dev, int index, + uint8_t *data, uint16_t len) +{ + uint8_t buffer[2]; + struct i2c_msg msg[2]; + struct i2c_data *i2c_client_obj = (struct i2c_data *)dev->client_object; + struct i2c_client *client = (struct i2c_client *)i2c_client_obj->client; + int rc; + + cci_access_var; + if (len > STMVL53L1_MAX_CCI_XFER_SZ || len == 0) { + vl53l1_errmsg("invalid len %d\n", len); + return -1; + } + cci_access_start(); + + /* build up little endian index in buffer */ + buffer[0] = (index >> 8) & 0xFF; + buffer[1] = (index >> 0) & 0xFF; + + msg[0].addr = client->addr; + msg[0].flags = client->flags; /* Write */ + msg[0].buf = buffer; + msg[0].len = 2; + /* read part of the i2c transaction */ + msg[1].addr = client->addr; + msg[1].flags = I2C_M_RD | client->flags; + msg[1].buf = data; + msg[1].len = len; + + rc = i2c_transfer(client->adapter, msg, 2); + if (rc != 2) { + pr_err("%s: i2c_transfer :%d, @%x index 0x%x len %d\n", + __func__, rc, client->addr, index, len); + + } + cci_access_over(" wr len %d status %d", rc != 2, len); + return rc != 2; +} +#endif +VL53L1_Error VL53L1_WrByte(VL53L1_DEV pdev, uint16_t index, uint8_t data) +{ + struct stmvl53l1_data *dev; +#ifdef USE_CAMERA_CCI + struct camera_cci_transfer ccit; +#endif + dev = (struct stmvl53l1_data *)container_of(pdev, + struct stmvl53l1_data, stdev); +#ifdef USE_CAMERA_CCI + memset(&ccit,0,sizeof(ccit)); + ccit.cmd = CAMERA_CCI_WRITE; + ccit.addr = index; + ccit.data = &data; + ccit.count = 1; + return cam_cci_control_interface(&ccit); +#else + return cci_write(dev, index, &data, 1); +#endif +} + +VL53L1_Error VL53L1_RdByte(VL53L1_DEV pdev, uint16_t index, uint8_t *pdata) +{ + struct stmvl53l1_data *dev; +#ifdef USE_CAMERA_CCI + struct camera_cci_transfer ccit; +#endif + dev = (struct stmvl53l1_data *) container_of(pdev, + struct stmvl53l1_data, stdev); +#ifdef USE_CAMERA_CCI + memset(&ccit,0,sizeof(ccit)); + ccit.cmd = CAMERA_CCI_READ; + ccit.addr = index; + ccit.data = pdata; + ccit.count = 1; + return cam_cci_control_interface(&ccit); +#else + return cci_read(dev, index, pdata, 1) ? + VL53L1_ERROR_CONTROL_INTERFACE : VL53L1_ERROR_NONE; +#endif +} + +VL53L1_Error VL53L1_WrWord(VL53L1_DEV pdev, uint16_t index, uint16_t data) +{ + VL53L1_Error status; + uint8_t buffer[2]; + + /* Split 16-bit word into MS and L* stmvl53l1 FlightSense sensor */ + + buffer[0] = (uint8_t) (data >> 8); + buffer[1] = (uint8_t) (data & 0x00FF); + i2c_debug(" @%x d= %x => [ %x , %x ] ", index, data, buffer[0], + buffer[1]); + status = VL53L1_WriteMulti(pdev, index, buffer, 2); + + return status; +} + +VL53L1_Error VL53L1_RdWord(VL53L1_DEV pdev, uint16_t index, uint16_t *pdata) +{ + VL53L1_Error status; + uint8_t buffer[2]; + + status = VL53L1_ReadMulti(pdev, index, buffer, 2); + + *pdata = ((uint16_t) buffer[0] << 8) + (uint16_t) buffer[1]; + + return status; +} + +VL53L1_Error VL53L1_WrDWord(VL53L1_DEV pdev, uint16_t index, uint32_t data) +{ + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t buffer[4]; + + /* Split 32-bit word into MS ... LS bytes */ + buffer[0] = (uint8_t) (data >> 24); + buffer[1] = (uint8_t) ((data & 0x00FF0000) >> 16); + buffer[2] = (uint8_t) ((data & 0x0000FF00) >> 8); + buffer[3] = (uint8_t) (data & 0x000000FF); + + status = VL53L1_WriteMulti(pdev, index, buffer, 4); + + return status; +} + +VL53L1_Error VL53L1_RdDWord(VL53L1_DEV pdev, uint16_t index, uint32_t *pdata) +{ + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t buffer[4]; + + status = VL53L1_ReadMulti(pdev, index, buffer, 4); + + *pdata = ((uint32_t) buffer[0] << 24) + ((uint32_t) buffer[1] << 16) + + ((uint32_t) buffer[2] << 8) + (uint32_t) buffer[3]; + + return status; +} + +VL53L1_Error VL53L1_WriteMulti(VL53L1_DEV pdev, uint16_t index, + uint8_t *pdata, uint32_t count) +{ + struct stmvl53l1_data *dev; +#ifdef USE_CAMERA_CCI + struct camera_cci_transfer ccit; +#endif + + dev = (struct stmvl53l1_data *) container_of(pdev, + struct stmvl53l1_data, stdev); +#ifdef USE_CAMERA_CCI + memset(&ccit,0,sizeof(ccit)); + ccit.cmd = CAMERA_CCI_WRITE; + ccit.addr = index; + ccit.data = pdata; + ccit.count = count; + return cam_cci_control_interface(&ccit); +#else + return cci_write(dev, index, pdata, count) ? + VL53L1_ERROR_CONTROL_INTERFACE : VL53L1_ERROR_NONE; +#endif +} + +VL53L1_Error VL53L1_ReadMulti(VL53L1_DEV pdev, uint16_t index, + uint8_t *pdata, uint32_t count) +{ + struct stmvl53l1_data *dev; +#ifdef USE_CAMERA_CCI + struct camera_cci_transfer ccit; +#endif + dev = (struct stmvl53l1_data *) container_of(pdev, + struct stmvl53l1_data, stdev); +#ifdef USE_CAMERA_CCI + memset(&ccit,0,sizeof(ccit)); + ccit.cmd = CAMERA_CCI_READ; + ccit.addr = index; + ccit.data = pdata; + ccit.count = count; + return cam_cci_control_interface(&ccit); +#else + return cci_read(dev, index, pdata, count) ? + VL53L1_ERROR_CONTROL_INTERFACE : VL53L1_ERROR_NONE; +#endif +} + +static int is_time_over(struct timeval *tv, uint32_t msec) +{ + return tv_elapsed_ms(tv) >= msec; +} + +VL53L1_Error VL53L1_WaitValueMaskEx(VL53L1_DEV pdev, + uint32_t timeout_ms, + uint16_t index, + uint8_t value, + uint8_t mask, uint32_t poll_delay_ms) +{ + struct timeval start_tv; + struct stmvl53l1_data *dev; + int rc, time_over; + uint8_t rd_val; +#ifdef USE_CAMERA_CCI + struct camera_cci_transfer ccit; +#endif + dev = (struct stmvl53l1_data *) container_of(pdev, + struct stmvl53l1_data, stdev); + + do_gettimeofday(&start_tv); + do { +#ifdef USE_CAMERA_CCI + memset(&ccit,0,sizeof(ccit)); + ccit.cmd = CAMERA_CCI_READ; + ccit.addr = index; + ccit.data = &rd_val; + ccit.count = 1; + rc = cam_cci_control_interface(&ccit); +#else + rc = cci_read(dev, index, &rd_val, 1); +#endif + if (rc) + return VL53L1_ERROR_CONTROL_INTERFACE; + if ((rd_val & mask) == value) { + poll_timing_log(&start_tv); + return VL53L1_ERROR_NONE; + } + vl53l1_dbgmsg("poll @%x %x & %d != %x", index, + rd_val, mask, value); + time_over = is_time_over(&start_tv, timeout_ms); + if (!time_over) + msleep(poll_delay_ms); + } while (!time_over); + vl53l1_errmsg("time over %d ms", timeout_ms); + return VL53L1_ERROR_TIME_OUT; +} + +VL53L1_Error VL53L1_WaitUs(VL53L1_DEV pdev, int32_t wait_us) +{ + struct stmvl53l1_data *data; + + data = (struct stmvl53l1_data *)container_of(pdev, + struct stmvl53l1_data, + stdev); + + if (!data->is_delay_allowed) + return VL53L1_ERROR_PLATFORM_SPECIFIC_START; + + /* follow Documentation/timers/timers-howto.txt recommendations */ + if (wait_us < 10) + udelay(wait_us); + else if (wait_us < 20000) + usleep_range(wait_us, wait_us + 1); + else + msleep(wait_us / 1000); + + return VL53L1_ERROR_NONE; +} + +VL53L1_Error VL53L1_WaitMs(VL53L1_DEV pdev, int32_t wait_ms) +{ + return VL53L1_WaitUs(pdev, wait_ms * 1000); +} diff --git a/drivers/input/misc/vl53L1/lito/stmvl53l1_if.h b/drivers/input/misc/vl53L1/lito/stmvl53l1_if.h new file mode 100644 index 000000000000..1e3fe3586255 --- /dev/null +++ b/drivers/input/misc/vl53L1/lito/stmvl53l1_if.h @@ -0,0 +1,671 @@ +/************************************************************************** + * Copyright (c) 2016, STMicroelectronics - All Rights Reserved + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ****************************************************************************/ + + +/** + * @file stmvl53l1_if.h vl53l1 kernel driver user interface + * + * @note to use this header in a user space application it requires + * all st bare/ll driver platform wrapper files (for data struct def) + * this files (types etc ..) shall be same or compliant with bar driver version + * used in the kernel module + */ + +#ifndef STMVL53L1_IF_H +#define STMVL53L1_IF_H + + +#include "vl53l1_def.h" +/** + * @addtogroup vl53l1_ioctl + * @{ + */ + +/** + * misc device name for ioctl device + * + * for mutli instance all device 2nd and next instance are basic name +"1"+"2" + * @li stmvl53l1_ranging + * @li stmvl53l1_ranging1 + * @li stmvl53l1_ranging2 + */ +#define VL53L1_MISC_DEV_NAME "stmvl53l1_ranging" +/** + * register data use for simple/single ranging data @ref VL53L1_IOCTL_GETDATAS + * + * @warning this definition is subject to change ! + */ +#define stmvl531_range_data_t VL53L1_RangingMeasurementData_t + +/** + * parameter name in @ref stmvl53l1_parameter when using + * @ref VL53L1_IOCTL_PARAMETER + */ +enum __stmv53l1_parameter_name_e { + VL53L1_XTALKENABLE_PAR = 2, + /*!< VL53L1_XTALKENABLE_PAR enable/disable crosstalk compensation\n + * valid value : + * @li 0 disable crosstalk compensation + * @li 1 enable crosstalk compensation + * + * @warning mode can only be set while not ranging + */ + + VL53L1_DEVICEMODE_PAR = 6, + /*!< DEVICEMODE_PAR set ranging mode  \n + * valid mode value : + * @li 1 @a VL53L1_PRESETMODE_RANGING default ranging + * @li 2 @a VL53L1_PRESETMODE_MULTIZONES_SCANNING multiple zone + * @li 3 @a VL53L1_PRESETMODE_AUTONOMOUS autonomous mode + * @li 4 @a VL53L1_PRESETMODE_LITE_RANGING low mips ranging mode + * @li 8 @a VL53L1_PRESETMODE_LOWPOWER_AUTONOMOUS low power autonomous + * mode + * + * @warning mode can only be set while not ranging + */ + + VL53L1_POLLDELAY_PAR = 10, + /*!< set the polling delay (msec)\n + * + * @note apply only when operates in polling mode as no effect + * otherwise + */ + VL53L1_TIMINGBUDGET_PAR = 11, + /*!< VL53L1_TIMINGBUDGET_PAR + * @ref stmvl53l1_parameter.value field is timing budget in micro second + */ + + VL53L1_DISTANCEMODE_PAR = 12, + /*!< VL53L1_DISTANCEMODE_PAR + * valid distance mode value : + * @li 1 @a VL53L1_DISTANCEMODE_SHORT + * @li 2 @a VL53L1_DISTANCEMODE_MEDIUM + * @li 3 @a VL53L1_DISTANCEMODE_LONG + * + * @warning distance mode can only be set while not ranging + */ + + VL53L1_OUTPUTMODE_PAR = 13, + /*!< VL53L1_OUTPUTMODE_PAR + * valid output mode value : + * @li 1 @a VL53L1_OUTPUTMODE_NEAREST + * @li 2 @a VL53L1_OUTPUTMODE_STRONGEST + * + * @warning distance mode can only be set while not ranging + */ + + VL53L1_FORCEDEVICEONEN_PAR = 14, + /*!< VL53L1_FORCEDEVICEONEN_PAR + * This parameter will control if device is put under reset when + * stopped. + * valid force device on value : + * @li 0 feature is disable. Device is put under reset when stopped. + * @li 1 feature is enable. Device is not put under reset when stopped. + */ + + VL53L1_LASTERROR_PAR = 15, + /*!< VL53L1_LASTERROR_PAR + * This is a read only parameter. It will return last device internal + * error. It's valid only after an ioctl/sysfs return an -EIO error. + */ + + VL53L1_OFFSETCORRECTIONMODE_PAR = 16, + /*!< VL53L1_OFFSETCORRECTIONMODE_PAR + * This parameter will define which mode to use for the offset + * correction. + * valid force device on value : + * @li 1 @a VL53L1_OFFSETCORRECTIONMODE_STANDARD + * @li 2 @a VL53L1_OFFSETCORRECTIONMODE_PERZONE + * + * @warning offset correction mode can only be set while not ranging + */ + + VL53L1_OPTICALCENTER_PAR = 17, + /*!< VL53L1_OPTICALCENTER_PAR + * This is a read only parameter. It will return optical center issued + * from the nvm set at FTM stage. value will contain X position of + * center. value2 will contain Y position of center. + * Return values have FixPoint1616_t type. + */ + + VL53L1_DMAXREFLECTANCE_PAR = 18, + /*!< VL53L1_DMAXREFLECTANCE_PAR + * This parameter will define target reflectance @ 940nm used to + * calculate the ambient DMAX. Parameter is of type FixPoint1616_t. + * + * @warning dmax reflectance can only be be set while not ranging + */ + + VL53L1_DMAXMODE_PAR = 19, + /*!< VL53L1_DMAXMODE_PAR + * This parameter will select Dmax mode. + * valid Dmax mode value : + * @li 1 @a VL53L1_DMAXMODE_FMT_CAL_DATA + * @li 2 @a VL53L1_DMAXMODE_CUSTCAL_DATA + * @li 3 @a VL53L1_DMAXMODE_PER_ZONE_CAL_DATA + * + * @warning Dmax mode can only be set while not ranging + */ + + VL53L1_TUNING_PAR = 20, + /*!< VL53L1_DMAXMODE_PAR + * This parameter is a write only parameter. It will allow to provide + * low level layer with a configuration parameter. + * value will be use as a key parameter. + * value2 will be use as value parameter. + * + * @warning those configuration parameter settings are only allowed + * before device is start once. + */ + + VL53L1_SMUDGECORRECTIONMODE_PAR = 21, + /*!< VL53L1_SMUDGECORRECTIONMODE_PAR + * This parameter will control if smudge correction is enable and how + * crosstalk values are updated. + * @li 0 @a VL53L1_SMUDGE_CORRECTION_NONE + * @li 1 @a VL53L1_SMUDGE_CORRECTION_CONTINUOUS + * @li 2 @a VL53L1_SMUDGE_CORRECTION_SINGLE + * @li 3 @a VL53L1_SMUDGE_CORRECTION_DEBUG + */ + + VL53L1_ISXTALKVALUECHANGED_PAR = 22, + /*!< VL53L1_ISXTALKCHANGED_PAR + * This is a read only parameter. It will return if Xtalk value has + * been updated while ranging. This parameter is reset each time device + * start to range. + * @li 0 Xtalk values has not been changed. + * @li 1 Xtalk values has been changed. + */ +}; +#define stmv53l1_parameter_name_e enum __stmv53l1_parameter_name_e + +/** + * parameter structure use in @ref VL53L1_IOCTL_PARAMETER + */ +struct stmvl53l1_parameter { + uint32_t is_read; /*!< [in] 1: Get 0: Set*/ + /*!< [in] parameter to set/get + * see @ref stmv53l1_parameter_name_e + */ + stmv53l1_parameter_name_e name; + int32_t value; /*!< [in/out] value to set /get */ + int32_t value2; /*!< [in/out] optional 2nd value */ + int32_t status; /*!< [out] status of the operation */ +}; + + +/** + * roi structure use as @ref VL53L1_IOCTL_ROI arg + * + * see @ref stmvl53l1_roi_full_t for easy to use type variable declaration + * required + */ +struct stmvl53l1_roi_t { + int32_t is_read; + /*!< specify roi transfer direction \n + * @li 0 to get roi + * @li !0 to set roi + */ + /*! roi data and count type use in @ VL53L1_IOCTL_ROI */ + struct roi_cfg_t { + uint8_t NumberOfRoi; + /*!< [in/out] Number of Rois to set/get + * + * on set :\n + * [in] number of roi to set + * @note 0 set can be used to return to device default roi usage + * + * on get :\n + * [in] max number provided\n + * [out] number of ROI copied back to user\n + * @warning 0 will not return any roi datas! + */ + VL53L1_UserRoi_t UserRois[1]; + /*!< roi data array length definition is 1 but + * NumberOfRoi+ FirstRoiToScan in array are required + * and will be effectively copy to/from user space + * + * @sa stmvl53l1_roi_full_t + */ + } roi_cfg /*! [in/out] roi data and count */; +}; + +/** + * full roi struct use in @ref VL53L1_IOCTL_ROI arg + * + * this definition make easier variable declaration with the max roi storage + * capabilities. + * + * @sa stmvl53l1_roi_t for field details + */ +struct stmvl53l1_roi_full_t { + int32_t is_read; + /*!< specify roi transfer direction \n + * @li 0 to get roi + * @li !0 to set roi + */ + VL53L1_RoiConfig_t roi_cfg; + /*!< roi data array of max length but only requested copy to/from user + * space effectively used + * see @a stmvl53l1_roi_t::roi_cfg for details + */ +}; + +/** + * parameter structure use in @ref VL53L1_IOCTL_CALIBRATION_DATA + */ +struct stmvl53l1_ioctl_calibration_data_t { + int32_t is_read; /*!< [in] 1: Get 0: Set*/ + VL53L1_CalibrationData_t data; + /*!< [in/out] data to set /get. Caller + * should consider this structure as an opaque one + */ +}; + +/** + * Opaque structure use to hold content of zone offset calibration result. + */ +#define stmvl531_zone_calibration_data_t \ + struct _stmvl531_zone_calibration_data_t + +struct _stmvl531_zone_calibration_data_t { + uint32_t id; + VL53L1_ZoneCalibrationData_t data; +}; + +/** + * parameter structure use in @ref VL53L1_IOCTL_ZONE_CALIBRATION_DATA + */ +struct stmvl53l1_ioctl_zone_calibration_data_t { + int32_t is_read; /*!< [in] 1: Get 0: Set*/ + stmvl531_zone_calibration_data_t data; + /*!< [in/out] data to set /get. Caller + * should consider this structure as an opaque one + */ +}; + +/** Select reference spad calibration in @ref VL53L1_IOCTL_PERFORM_CALIBRATION. + * + * param1, param2 and param3 not use + */ +#define VL53L1_CALIBRATION_REF_SPAD 0 + +/** Select crosstalk calibration in @ref VL53L1_IOCTL_PERFORM_CALIBRATION. + * + * param1 is calibration method. param2 and param3 not use. + * @li VL53L1_XTALKCALIBRATIONMODE_NO_TARGET + * @li VL53L1_XTALKCALIBRATIONMODE_SINGLE_TARGET + * @li VL53L1_XTALKCALIBRATIONMODE_FULL_ROI + */ +#define VL53L1_CALIBRATION_CROSSTALK 1 + +/** Select offset calibration @ref VL53L1_IOCTL_PERFORM_CALIBRATION. + * param1 is offset calibration mode. Parameter is either: + * - VL53L1_OFFSETCALIBRATIONMODE_STANDARD + * - VL53L1_OFFSETCALIBRATIONMODE_PRERANGE_ONLY + * - VL53L1_OFFSETCALIBRATIONMODE_MULTI_ZONE (deprecated) + * param2 is target distance in mm. + * param3 is target reflectance in percent. Parameter is of type FixPoint1616_t. + * + * Note that VL53L1_OFFSETCALIBRATIONMODE_MULTI_ZONE usage is deprecated. Per + * zone offset calibration should use VL53L1_CALIBRATION_OFFSET_PER_ZONE + * instead. + */ +#define VL53L1_CALIBRATION_OFFSET 2 + +/** Select offset calibration per zone @ref VL53L1_IOCTL_PERFORM_CALIBRATION. + * param1 is offset calibration mode. Parameter is: + * - VL53L1_OFFSETCALIBRATIONMODE_MULTI_ZONE + * param2 is target distance in mm. + * param3 is target reflectance in percent. Parameter is of type FixPoint1616_t. + * + * Note that region of interest should be defined by a prior call to + * VL53L1_IOCTL_ROI before calling VL53L1_IOCTL_PERFORM_CALIBRATION / + * VL53L1_CALIBRATION_OFFSET combinaison. + */ +#define VL53L1_CALIBRATION_OFFSET_PER_ZONE 3 + +/** Select simple offset calibration @ref VL53L1_IOCTL_PERFORM_CALIBRATION. + * param1 is target distance in mm. + * param2 and param3 are not used + */ +#define VL53L1_CALIBRATION_OFFSET_SIMPLE 4 + +/** + * parameter structure use in @ref VL53L1_IOCTL_PERFORM_CALIBRATION + */ +struct stmvl53l1_ioctl_perform_calibration_t { + uint32_t calibration_type; + /*!< [in] select which calibration to do : + * @li @ref VL53L1_CALIBRATION_REF_SPAD + * @li @ref VL53L1_CALIBRATION_CROSSTALK + * @li @ref VL53L1_CALIBRATION_OFFSET + * @li @ref VL53L1_CALIBRATION_OFFSET_SIMPLE + * @li @ref VL53L1_CALIBRATION_OFFSET_PER_ZONE + */ + uint32_t param1; + /*!< [in] first param. Usage depends on calibration_type */ + uint32_t param2; + /*!< [in] second param. Usage depends on calibration_type */ + uint32_t param3; + /*!< [in] third param. Usage depends on calibration_type */ +}; + +/** + * parameter structure use in @ref VL53L1_IOCTL_AUTONOMOUS_CONFIG + */ +struct stmvl53l1_autonomous_config_t { + int32_t is_read; + /*!< [in] 1: Get 0: Set*/ + uint32_t pollingTimeInMs; + /*!< [in/out] interval between two measure in ms */ + VL53L1_DetectionConfig_t config; + /*!< [int/out] autonomous mode configuration structure */ +}; + +/* + * IOCTL definitions + */ + + +/** + * Start ranging (no argument) + * + * @note sysfs and ioctl control are assumed mutual exclusive use + * control from ioctl execute with no consideration of sysfs path. + * + * @return : + * @li 0 on success + * @li -EBUSY if already started + * @li -ENXIO failed to change i2c address change after reset release + * @li -EIO. Read last_error to get device error code + * @li -ENODEV. Device has been removed. + * + * example user land : + @code + int smtvl53l1_start(int fd){error + int rc; + rc= ioctl(fd, VL53L1_IOCTL_START,NULL); + if( rc ){ + if( errno == EBUSY){ + //the device is already started + ioctl_warn("already started"); + return EBUSY; + } + } + if( rc ){ + ioctl_error("%d %s", rc,strerror(errno)); + } + return rc; +} + @endcode +*/ + +#define VL53L1_IOCTL_START _IO('p', 0x01) + +/** + * stop ranging (no argument) + + * @note sysfs and ioctl control are assumed mutual exclusive use + * control from ioctl execute action with no consideration of sysfs path. + * + * @return + * @li 0 on success + * @li -EBUSY if it was already + * @li -EIO. Read last_error to get device error code + * @li -ENODEV. Device has been removed. + * + * c example userland : + @code +int smtvl53l1_stop(int fd){ + int rc; + rc= ioctl(fd, VL53L1_IOCTL_STOP,NULL); + if( rc ){ + if( errno == EBUSY ){ + ioctl_warn("already stopped"); + return errno; + } + ioctl_error("%d %s", rc,strerror(errno)); + } + return rc; +} +@endcode + */ +#define VL53L1_IOCTL_STOP _IO('p', 0x05) + +/** + * get single ranging data @sa for multi zone/objet + * + * retrieve the last range data available form the device + * + * @param in/out data struct ptr of type @ref stmvl531_range_data_t + * it may come in but is out as of now + * + * @return 0 on success else o, error check errno + * @li -EFAULT fault in cpy to f/m user out range data not copied + * @li -ENODEV. Device has been removed. + * + * @warning this ioctl will not wait for a new range sample acquisition + * it will return what available at time it get called . Hence same data maybe + * returned many time when doing fast polling.\n + * End user must inspect the data structure (time stamp etc )to find about it\n + * Despite it's non "waiting" nature this ioctl may still block/sleep shortly + * to ensure race free usage acquiring mutex and/or locks. + */ +#define VL53L1_IOCTL_GETDATAS \ + _IOWR('p', 0x0b, stmvl531_range_data_t) + +/** + * set or get parameter + * + * @param parameter in/out @ref stmvl53l1_parameter + * @sa stmv53l1_parameter_name_e + * + * for get if ioctl fail do not check for out params it is not valid + * for set theirs not copy back only see ioctl status, errno to get error case + * + * @return 0 on success else o, error check errno + * @li -ENODEV. Device has been removed. + * + * @note a set parameter may not be absorbed straight aways ! + */ +#define VL53L1_IOCTL_PARAMETER \ + _IOWR('p', 0x0d, struct stmvl53l1_parameter) + + +/** + * set/get roi + * + * shall only be use while device is stopped (EBUSY error otherwise) + * setting 0 rois stand for "disable user define roi usage, use device default" + * + * @param roi_cfg [in/out] type @ref stmvl53l1_roi_t and + * @ref stmvl53l1_roi_full_t + * @note when getting roi the returned roi cnt is set to available number + * of roi in driver but at most requested number or available one + * will be set in returned structure + * @warning the coordinate system is not usual image x,y (y down)but traditional + * ecludian x,y (y up) + * + * @warning once defined the user roi is kept alive until unset by user . + * User shall update roi when required (mode change etc ..)\n + * To return to default unset roi by setting none, device will return to default + * at next start + * + * @note roi validity is only checked at start ranging , as such invalid roi set + * can make start to fail + * + * @return 0 on success , see errno for error detail + * @li EBUSY when trying to set roi while ranging + * @li ENODEV never device get started and trying to get more rois than set + * @li other errno code could be ll driver specific + */ +#define VL53L1_IOCTL_ROI\ + _IOWR('p', 0x0e, struct stmvl53l1_roi_t) + +/** + * Get multi object/zone ranging data + * + * this call is non blocking and will return what available internally + * in all case (veen error) + * + * @param [out] multi zone range @ref VL53L1_MultiRangingData_t always update + * but -EFAULT error case + * + * @return 0 on success else o, error check errno + * @li -EFAULT fault in cpy to f/m user out range data not copyed + * @li -ENOEXEC active mode is not mutli-zone + * @li -ENODEV device is not ranging or device has been removed. + * as in that case MZ data may not be fully valid + */ +#define VL53L1_IOCTL_MZ_DATA\ + _IOR('p', 0x0f, VL53L1_MultiRangingData_t) + +/** + * get single ranging data @sa for multi zone/objet + * + * this call is equivalent to VL53L1_IOCTL_GETDATAS but will block until + * new data are available since previous call. + * + * @param in/out data struct ptr of type @ref stmvl531_range_data_t + * it may come in but is out as of now + * + * @return 0 on success else o, error check errno + * @li -EFAULT fault in cpy to f/m user out range data not copied + * @li -ENODEV device is not ranging or device has been removed. + * @li -ERESTARTSYS interrupt while sleeping. + */ +#define VL53L1_IOCTL_GETDATAS_BLOCKING\ + _IOWR('p', 0x10, stmvl531_range_data_t) + +/** + * Get multi object/zone ranging data + * + * this call is equivalent to VL53L1_IOCTL_MZ_DATA but will block until + * new data are available since previous call. + * + * @param [out] multi zone range @ref VL53L1_MultiRangingData_t always update + * but -EFAULT error case + * + * @return 0 on success else o, error check errno + * @li -EFAULT fault in cpy to f/m user out range data not copyed + * @li -ENOEXEC active mode is not mutli-zone + * @li -ENODEV device is not ranging or device has been removed. + * @li -ERESTARTSYS interrupt while sleeping. + * as in that case MZ data may not be fully valid + */ +#define VL53L1_IOCTL_MZ_DATA_BLOCKING\ + _IOR('p', 0x11, VL53L1_MultiRangingData_t) + +/** + * Get / set calibration data + * + * this call allow client to either read calibration data after calibration + * has been performed to store them in the host filesystem or push calibration + * data before ranging at each start-up. + * + * @param [in/out] data struct ptr of type + * @ref stmvl53l1_ioctl_calibration_data_t. Caller should consider it as an + * opaque structure. + * + * use this after either VL53L1_CALIBRATION_REF_SPAD, + * VL53L1_CALIBRATION_CROSSTALK or VL53L1_CALIBRATION_OFFSET. + * + * @return 0 on success else o, error check errno + * @li -EFAULT fault in cpy to f/m user out range data not copied + * @li -EBUSY when trying to set calibration data while ranging + * @li -EIO. Read last_error to get device error code + * @li -ENODEV. Device has been removed. + */ +#define VL53L1_IOCTL_CALIBRATION_DATA\ + _IOWR('p', 0x12, struct stmvl53l1_ioctl_calibration_data_t) + +/** + * Get / set zone calibration data + * + * this call allow client to either read zone calibration data after calibration + * has been performed to store them in the host filesystem or push zone + * calibration data before ranging at each start-up. + * + * use this after VL53L1_CALIBRATION_OFFSET_PER_ZONE calibration. + * + * @param [in/out] data struct ptr of type + * @ref stmvl53l1_ioctl_zone_calibration_data_t. Caller should consider it as an + * opaque structure. + * + * @return 0 on success else o, error check errno + * @li -EFAULT fault in cpy to f/m user out range data not copied + * @li -EBUSY when trying to set calibration data while ranging + * @li -EIO. Read last_error to get device error code + * @li -ENODEV. Device has been removed. + */ +#define VL53L1_IOCTL_ZONE_CALIBRATION_DATA\ + _IOWR('p', 0x12, struct stmvl53l1_ioctl_zone_calibration_data_t) + +/** + * perform calibration squence according to calibration_type + * + * this call is attended to be used during factory calibration. You select + * calibration to issue using calibration_type. + * + * @param [in] data struct ptr of type + * @ref stmvl53l1_ioctl_perform_calibration_t. + * + * @return 0 on success else o, error check errno + * @li -EFAULT fault in cpy to f/m user out range data not copied + * @li -EBUSY when trying to perform calibration data while ranging + * @li -EIO. Read last_error to get device error code + * @li -ENODEV. Device has been removed. + */ +#define VL53L1_IOCTL_PERFORM_CALIBRATION\ + _IOW('p', 0x13, struct stmvl53l1_ioctl_perform_calibration_t) + +/** + * set/get configure autonomous mode parameters + * + * Allow to get or set autonomous configuration. Change it only when device + * is stopped otherwise you will receive an EBUSY error. + * + * @param stmvl53l1_autonomous_config_t [in/out] + * + * @note autonomous config validity is only checked at start ranging , as such + * invalid autonomous config set can make start to fail. + * + * @return 0 on success , see errno for error detail + * @li -EFAULT failed to copy from/to configuration. + * @li -EBUSY when trying to change configuration while ranging. + * @li -ENODEV. Device has been removed. + */ +#define VL53L1_IOCTL_AUTONOMOUS_CONFIG\ + _IOWR('p', 0x14, struct stmvl53l1_autonomous_config_t) + +/** @} */ /* ioctl group */ +#endif /* STMVL53L1_IF_H */ diff --git a/drivers/input/misc/vl53L1/lito/stmvl53l1_internal_if.h b/drivers/input/misc/vl53L1/lito/stmvl53l1_internal_if.h new file mode 100644 index 000000000000..5a4c004c1ffd --- /dev/null +++ b/drivers/input/misc/vl53L1/lito/stmvl53l1_internal_if.h @@ -0,0 +1,120 @@ +/************************************************************************** + * Copyright (c) 2016, STMicroelectronics - All Rights Reserved + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ****************************************************************************/ + +#ifndef STMVL53L1_INTERNAL_IF_H +#define STMVL53L1_INTERNAL_IF_H + +#include "vl53l1_def.h" + +/* interface definition move in this file is not supposed to be use by a normal + * client. It's only here for internal testing purpose. + */ + +/* structure and ioctl that allow raw access to vl53l1 register */ +struct stmvl53l1_register { + uint32_t is_read; /*!< type of the access 1: read 0: write*/ + uint32_t index; /*!< register index */ + uint32_t cnt; /*!< register size shall be 1 to n */ + int32_t status; /*!< operation status 0 ok else error */ + + union reg_data_t { + uint8_t b; /*!< single data byte*/ + uint16_t w; /*!< single data word (16 bits)*/ + uint32_t dw; /*!< single data dword (32 bits)*/ + /*!< any size byte array + * @note only effectively used array size is needed and will be + * set/used another possible register definition is + * @ref stmvl53l1_register_flexi + */ + uint8_t bytes[256]; + /*!< data only *@warning device is big endian and + * no endianess adaptation is performed by + * @ref VL53L1_IOCTL_REGISTER + */ + } data; +}; + +struct stmvl53l1_register_flexi { + uint32_t is_read; /*!< [in] type of the access 1: read 0: write*/ + uint32_t index; /*!< [in] register index */ + uint32_t cnt; /*!< [în] register size shall be 1 to n */ + int32_t status; /*!< [out] operation status 0 ok else error */ + uint8_t data[]; /*!< [in/out] flexible array size data */ + /*!< data only *@warning device is big endian and + * no endianess adaptation is performed by @ref VL53L1_IOCTL_REGISTER + */ +}; + +#define VL53L1_IOCTL_REGISTER _IOWR('p', 0x0c, struct stmvl53l1_register) + +struct stmvl53l1_data_with_additional { + VL53L1_MultiRangingData_t data; + VL53L1_AdditionalData_t additional_data; +}; + +/** + * Get multi object/zone ranging data with additional data for debug + * + * this call is non blocking and will return what available internally + * in all case (veen error) + * + * @param [out] multi zone range @ref VL53L1_MultiRangingData_t always update + * but -EFAULT error case + * + * @return 0 on success else o, error check errno + * @li -EFAULT fault in cpy to f/m user out range data not copyed + * @li -ENOEXEC active mode is not mutli-zone + * @li -ENODEV device is not ranging or device has been removed. + * as in that case MZ data may not be fully valid + */ +#define VL53L1_IOCTL_MZ_DATA_ADDITIONAL\ + _IOR('p', 0x15, struct stmvl53l1_data_with_additional) + +/** + * Get multi object/zone ranging data + * + * this call is equivalent to VL53L1_IOCTL_MZ_DATA_ADDITIONAL but will block + * until new data are available since previous call. + * + * @param [out] multi zone range @ref VL53L1_MultiRangingData_t always update + * but -EFAULT error case + * + * @return 0 on success else o, error check errno + * @li -EFAULT fault in cpy to f/m user out range data not copyed + * @li -ENOEXEC active mode is not mutli-zone + * @li -ENODEV device is not ranging or device has been removed. + * @li -ERESTARTSYS interrupt while sleeping. + * as in that case MZ data may not be fully valid + */ +#define VL53L1_IOCTL_MZ_DATA_ADDITIONAL_BLOCKING\ + _IOR('p', 0x16, struct stmvl53l1_data_with_additional) + +#endif diff --git a/drivers/input/misc/vl53L1/lito/stmvl53l1_ipp.h b/drivers/input/misc/vl53L1/lito/stmvl53l1_ipp.h new file mode 100644 index 000000000000..31e75a196deb --- /dev/null +++ b/drivers/input/misc/vl53L1/lito/stmvl53l1_ipp.h @@ -0,0 +1,386 @@ +/************************************************************************** + * Copyright (c) 2016, STMicroelectronics - All Rights Reserved + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ****************************************************************************/ + +/** + * @file stmvl53l1_ipp.h + * + * helper to serialize de-serialize data in ipp exchange between user/kernel + * + * @date Sep 2, 2016 + * @author imaging + */ + +#ifndef _STMVL53L1_IPP_H_ +#define _STMVL53L1_IPP_H_ + +#include "vl53l1_types.h" + + +/** @ingroup ipp_dev + * @{ + */ + +/** + * @defgroup ipp_serialize ST IPP serialization helper + * + * to use the dump help you lust define first a few extra "specific" + * + * @li IPP_PRINT(fmt,..) with typical printf/printk interface + */ + /** @{ */ +/** + * generic data type to serialized scalar and offset for pointer + * + * serialized data can be seen as a first array of n ipp_art_t + * where each input are arg value for scaler type + * and an offset with respect to the ipp_arg base array where the data + * + * @note if all ipp argument can fit on 32 bit then ipp_arg_t is best set as + * a 32 bit base type '(i e uint32_t) to save space + * on 64 bit cpu it can remain 64 bit type to get better alignment + */ +typedef uint64_t ipp_arg_t; + +/** + * set to the cpu structure alignment and packing constrain + * + * all serialized argument passed by pointer will be stored with + * this memory align constrain + * + * + * @note if target cpu is ok to access unaligned data or less constrain ie 64 + * bit data align 32 are ok then it can be set to 4 to save space in data + * packing and copy\n + * We may be over constraining in many cases as a struct is only required to + * be aligned on i'st biggest item size + * + * @warning it must be a 2 power of 2 (& operation instead of mudulo used in + * align calculation) + * @warning using 8 byte constrain require that the @a ipp_arg_t is already + * aligned on that constrain + */ +#define IPP_ALIGN_REQ 8 + +/** + * set x to it's nearest aligned offset (not that 0 is fine as a valid offset + * than will not be up aligned to next align chunk ) + */ +#define IPP_ALIGN_OFFSET(x) (((x)+(IPP_ALIGN_REQ-1)) & (~(IPP_ALIGN_REQ-1))) + +/** + * declare variable needed for ipp serialization + */ +#define IPP_SERIALIZE_VAR int ipp_offset +/** + * Put in function start to init the serialization coding + * + * @param ipp_args buffer for data serialization + * @param n_args is the total number of argument scalar and ptr to serialized + * dot not count out only arg that will be returned + * + * it define local var "ipp_offset" used to accumulate all input args that must + * be serialize. It reserve header room in the buffer to place for scalar args + * and offset for args ptr copy + * + * args pass by pointer must be serialized by @ref IPP_SET_ARG_PTR in order they + * are declare\n + * scalar args can be serialized in any order with @ref IPP_SET_ARG + * + * scalar args that can't be cast to basic @ref ipp_arg_t shall be serialized + * Manually or using a macro similar to ptr that can be pass by copy + * + *@note @ref IPP_SERIALIZE_VAR must be use first + * @code + * int ipp_to _ser(int arg0, struct st_t *pdata1){ + * char *local var; + * ipp_arg_t args[256]; + * IPP_SERIALIZE_START(2); + * IPP_SET_ARG(args, 0, arg0); + * IPP_SET_ARG_PTR(args, 1, pdata); + * do_one_ipp(args); + * } + * @endcode + * + */ +#define IPP_SERIALIZE_START(ipp_args, n_args)\ + (ipp_offset = IPP_ALIGN_OFFSET((char *)(&ipp_args[n_args]) - \ + (char *)ipp_args)) + +/** + * @brief Serialize scalar argument + * + * serialized arg number n into ipp_args\n + * can be used in any order + * + * @param ipp_args the args buffer + * @param n 0 base arg number + * @param v the scalar argument variable + * @warning usable only for scalar type that can be copy on a ipp_arg_t + */ +#define IPP_SET_ARG(ipp_args, n, v) memcpy(&ipp_args[n], &v, sizeof(v)) + +/** + * @brief Serialize an arg passed by pointer + * + * @param ipp_args the arg ptr array + * @param n the arg number to serialize + * @param pdata argument it must be a type like struct x_t * int [n] etc ... + * that size is given by size of and and be copied by a single memcpy + */ +#define IPP_SET_ARG_PTR(ipp_args, n, pdata)\ + do {\ + ipp_args[n] = ipp_offset;\ + memcpy(((char *)ipp_args) + ipp_offset, pdata, sizeof(*pdata));\ + ipp_offset = IPP_ALIGN_OFFSET(ipp_offset + sizeof(*pdata));\ + } while (0) + +/** + * serialize out get ptr for pdata + * + * @note it does not cpy data just set ptr and update the offset + * @warning to be use in order + * + * @param ipp_args the arg ptr array + * @param n the arg number to serialize (unused) + * @param pdata init to ptr in ipp_args type is used for offset computation + * @warning to use sequential in order agr are serialized + */ +#define IPP_OUT_ARG_PTR(ipp_args, n, pdata)\ + do {\ + pdata = (void *)(((char *)ipp_args) + ipp_offset);\ + ipp_offset = IPP_ALIGN_OFFSET(ipp_offset + \ + (int)sizeof(*pdata));\ + } while (0) + + +/** + * @brief ipp get payload + * + * @return paylaod at time used \n + * when all done it's overall out payload + * + * require @ref IPP_SERIALIZE_VAR and @ref IPP_SERIALIZE_START used first\n + * best use after all @ref IPP_OUT_ARG_PTR or @ref IPP_SET_ARG_PTR done to get + * full payload + **/ +#define IPP_SERIALIZE_PAYLAOD() (ipp_offset + IPP_WORK_HDR_SIZE) + +/** + * de-serialize and argument that was passed by value + * @param ipp_args the args array + * @param n the 0 base argument number + * @param v argument it must be exact type + * + * + * @code + * f_deserialize(ipp_arg_t args[]) + * { + * // f_ser is like (uint16_t arg0, struct s_arg_t * arg1, int arg2) + * uint16_t arg0; + * void * parg1; + * int arg2; + * + * IPP_GET_ARG( args, 0, arg0) + * IPP_GET_ARG( args, 2, arg2) + * } + * @endcode + */ +#define IPP_GET_ARG(ipp_args, n, v) memcpy(&v, &ipp_args[n], sizeof(v)) + + +/** + * de-serialize an argument passed by pointer + * + * @param ipp_args the serialized argument array + * @param n 0 base argument number + * @param p ptr to arg to be set + * + * @note unlike serializing de-serializing pointer args data can be done in any + * order + * + * @code + * struct some_struct_t *parg2; + * IPP_GET_ARG_PTR(args,2,parg2); + * @endcode + */ +#define IPP_GET_ARG_PTR(ipp_args, n, p) (p = (void *)((char *)ipp_args + \ + ipp_args[n])) + + + + +/** + * debug macro to pint out all serialized args + * + * Implementation shall define IPP_PRINT_FUNC function to use + */ +#define IPP_PRINT_ARGS(ipp_args, n) \ + do {\ + int i;\ + for (i = 0; i < n; i++)\ + IPP_PRINT("arg#%d/%d is %8d 0x%08x\n", i, n,\ + ipp_args[i], ipp_args[i]);\ + IPP_PRINT("used data size %d\n", ipp_offset);\ + } while (0) + + +/** + * processing code type of proccesing + * + * used in @a ipp_work_t::process_no + */ +enum stmvl53l1_ipp_proccesing_e { + stmvl53l1_ipp_ping = 0, + /*!< stmvl53l1_ipp_ping + * @li can be sent by driver to check client is alive + * @li daemon sent it to identify and register himself to the driver + */ + stmvl53l1_ipp_cal_hist = 1, + /*!< stmvl53l1_ipp_cal_hist process cal hist*/ + + stmvl53l1_ipp_xtalk_calibration = 2, + /*!< stmvl53l1_ipp_xtalk_calibration process crosstalk calibration data + */ + + stmvl53l1_ipp_hist_ambient_dmax = 3, + /*!< stmvl53l1_ipp_hist_ambient_dmax process ambient dmac calculation + * from histogram + */ + + stmvl53l1_ipp_generate_dual_reflectance_xtalk_samples = 4, + /*!< stmvl53l1_ipp_generate_dual_reflectance_xtalk_samples process + * Xtalk data from dual reflectance histogram data + */ + + /** keep last*/ + stmvl53l1_ipp_max /*!< stmvl53l1_ipp_max */ +}; + +/** + * status use on @a ipp_work_t::status + */ +enum stmvl53l1_ipp_status_e { + stmvl53l1_ipp_status_ok = 0, /*!< ok work done */ + stmvl53l1_ipp_status_inv_id, /*!< dev id not supported or invalid */ + stmvl53l1_ipp_status_inv_proc, + /*!< process_no asked not supported or not implemented */ + stmvl53l1_ipp_status_inv_payload, + /*!< data payload for asked processing incorrect*/ + + stmvl53l1_ipp_status_proc_code = 0x100, + /*!< the lowest 8 bit is the error code form the processing */ +}; + +/** + * Ipp work (job) struct + * + * containing header with sequenc control information plus serialized data + */ +struct ipp_work_t { + int8_t dev_id; /*!< [in]/[out] device id */ + /*!< Identify the work do be run see @a stmvl53l1_ipp_proccesing_e */ + uint8_t process_no; + /*!< [out] status from daemon */ + int16_t status; + /*!< [in/out] unique xfer id */ + uint32_t xfer_id; + /*!< [in/out] effective data length including header*/ + uint32_t payload; + +/** max IPP data payload (not including header) + * + * we substract size of of item above + * must be lesss than one netlink packet + */ +#define MAX_IPP_DATA ((4096-4*3)/8) + ipp_arg_t data[MAX_IPP_DATA]; /*!< [in][out] */ +}; + +/** + * size of header only message ( no payload) + * require \#include in user land + */ +#define IPP_WORK_HDR_SIZE (offsetof(struct ipp_work_t, data[0])) +/** + * max payload per ipp transfer + */ +#define IPP_WORK_MAX_PAYLOAD sizeof(struct ipp_work_t) + +/** copy ipp header from src to dest + * + * used to prepare return work using incoming work header + * @param dest dest work ptr + * @param src src work ptr + */ +#define IPP_CPY_HEADER(dest, src) memcpy(dest, src, IPP_WORK_HDR_SIZE) + +/** + * dump in human readble way ipp struct + * + * @note require IPP_PRINT macro + * + * @param pw ipp_work struct to dump + * @param max_data max amount of data to be dump + * @param max_dev max number of dev (for check) + */ +static inline void ipp_dump_work(struct ipp_work_t *pw, uint32_t max_data, + int max_dev) +{ + uint32_t data_cnt; + uint32_t i; + uint8_t *pbdata; + + (void)max_dev; /* avoid warning when not used */ + (void)pbdata; /*avoid warning in case no print no use*/ + + IPP_PRINT("dev #%d (%s)\n", pw->dev_id, pw->dev_id < max_dev ? + "ok" : "bad"); + IPP_PRINT("process #%d (%s)\n", pw->process_no, + pw->process_no < stmvl53l1_ipp_max ? "ok" : "bad"); + IPP_PRINT("status %d\n", pw->status); + IPP_PRINT("Xfer id 0x%08X payload %d bytes (%s)\n", pw->xfer_id, + pw->payload, + pw->payload > IPP_WORK_MAX_PAYLOAD ? "invalid" : "ok"); + data_cnt = pw->payload > IPP_WORK_MAX_PAYLOAD ? + IPP_WORK_MAX_PAYLOAD : pw->payload; + data_cnt = data_cnt > max_data ? max_data : data_cnt; + for (i = 0, pbdata = (uint8_t *)pw->data; i < data_cnt; i++) { + if (i%16 == 0) + IPP_PRINT("\n%4X\t", i); + IPP_PRINT("%02X ", pbdata[i]); + } + IPP_PRINT("\n"); +} + +/** @} */ /* ingroup helper */ + +/** @} */ /* ingroup ipp_dev */ +#endif /* _STMVL53L1_IPP_H_ */ diff --git a/drivers/input/misc/vl53L1/lito/stmvl53l1_ipp_nl.c b/drivers/input/misc/vl53L1/lito/stmvl53l1_ipp_nl.c new file mode 100644 index 000000000000..aea6fe21fc4c --- /dev/null +++ b/drivers/input/misc/vl53L1/lito/stmvl53l1_ipp_nl.c @@ -0,0 +1,384 @@ +/************************************************************************** + * Copyright (c) 2016, STMicroelectronics - All Rights Reserved + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ****************************************************************************/ + +/** + * @file stmvl53l1_ipp_nl.c vl53l1 ipp proxy over netlink kernel side + */ +#include +#include +#include +#include +#include + +#include "stmvl53l1.h" + +#include "vl53l1_platform_ipp.h" +#include "stmvl53l1_ipp.h" + +#define IPP_DEBUG 1 +#ifndef IPP_DEBUG +# define _ipp_dump_work(...) (void)0 +#else +# define _ipp_dump_work(...) ipp_dump_work(__VA_ARGS__) +#endif + +#define IPP_STATE_PENDING 1 +#define IPP_STATE_COMPLETED 2 +#define IPP_STATE_CANCELED 4 + +#define IPP_TIMEOUT_MS 100 + +/** the single netlink strut use by all instance + * @note is NULL until set + */ +static struct sock *nl_sk; + +static DEFINE_MUTEX(ipp_mutex); + +/** + * current registered daemon pid + * @note default value 0 or later 1 is kind of invalid and will require + * user space to connect before we can send any packet + */ +static int daemon_pid; + +/** + * next xfer_id (shared other all dev) + * no direct us used @@ref get_next_xfer_id (will get lock) + * @note default to 0 what is "reserved" + */ +static int next_xfer_id; + + +#define ipp_err(fmt, ...) pr_err("STMVL53L1 IPP Err in %s %d :" fmt "\n", \ + __func__, __LINE__, ##__VA_ARGS__) + +#define ipp_warn(fmt, ...) pr_warn("STMVL53L1 IPP wng in %s %d : "fmt"\n",\ + __func__, __LINE__, ##__VA_ARGS__) + +#if 0 +# define ipp_dbg(fmt, ...) pr_info("IPP %s %d " fmt "\n",\ + __func__, __LINE__, ##__VA_ARGS__) +#else +# define ipp_dbg(...) (void)0 +#endif + +/** + * get and managed increment of next xfer_id + * @note will get ipp_mutex + * @return the xfer_id to be used + */ +static int get_next_xfer_id(void) +{ + mutex_lock(&ipp_mutex); + next_xfer_id++; + /*0 is reserved skip it*/ + if (next_xfer_id == 0) + next_xfer_id = 1; + mutex_unlock(&ipp_mutex); + + return next_xfer_id; +} + +static int send_client_msg(void *msg_data, int msg_size) +{ + int rc; + struct sk_buff *skb_out; + struct nlmsghdr *nlh; + void *nl_data = NULL; + + ipp_dbg("to send %d byte", msg_size); + skb_out = nlmsg_new(msg_size, 0); + if (!skb_out) { + ipp_err("nlmsg_new fail\n"); + return -1; + } + + nlh = nlmsg_put(skb_out, 0, 0, NLMSG_DONE, msg_size, 0); + NETLINK_CB(skb_out).dst_group = 0; /* not in mcast group */ + nl_data = nlmsg_data(nlh); /*get data ptr from header*/ + + if ((nl_data != NULL) && (msg_data != NULL) && (msg_size > 0)) { + memcpy(nl_data, msg_data, msg_size); + } + /* FIXME do we real need to lock to send a data other nl_sk ? */ + mutex_lock(&ipp_mutex); + rc = nlmsg_unicast(nl_sk, skb_out, daemon_pid); + if (rc < 0) + ipp_err("fail to send data size %d to pid %d\n", + msg_size, daemon_pid); + /* stat can be done here in else case */ + mutex_unlock(&ipp_mutex); + + return rc; +} + +/* + * ipp lock is held ping already handled + */ +int ipp_in_process(struct ipp_work_t *pwork) +{ + struct stmvl53l1_data *data; + + ipp_dbg("enter"); + _ipp_dump_work(pwork, IPP_WORK_MAX_PAYLOAD, STMVL53L1_CFG_MAX_DEV); + + /* work id check already done */ + data = stmvl53l1_dev_table[pwork->dev_id]; + ipp_dbg("to lock "); + /* Release now useless ipp_mutex for below work since we may deadlock + * with irq path. + */ + mutex_unlock(&ipp_mutex); + mutex_lock(&data->work_mutex); + if (data->ipp.buzy == IPP_STATE_PENDING) { + /* if it was already handled ignore it */ + if (data->ipp.waited_xfer_id == pwork->xfer_id) { + /* ok that is what we are expecting back */ + memcpy(&data->ipp.work_out, pwork, pwork->payload); + data->ipp.buzy |= IPP_STATE_COMPLETED; + ipp_dbg("to wake ipp waiter as buzy state %d", + data->ipp.buzy); + wake_up(&data->ipp.waitq); + goto done_lock; + } + } + /* either not waiting any more or not the expected id drop it */ + ipp_err("dev #%d ippp buzy %d xfer id %d rcv id %d droping it", + data->id, data->ipp.buzy, data->ipp.waited_xfer_id, + pwork->xfer_id); +done_lock: + mutex_unlock(&data->work_mutex); + mutex_lock(&ipp_mutex); + + return 0; +} + +int stmvl53l1_ipp_stop(struct stmvl53l1_data *data) +{ + int rc; + + rc = data->ipp.buzy; + ipp_dbg("#%d to stop buzy %d", data->id, data->ipp.buzy); + if (data->ipp.buzy) { + /* set invalid wait id to discard canceled job when back */ + data->ipp.waited_xfer_id = 0; + data->ipp.buzy |= IPP_STATE_CANCELED|IPP_STATE_COMPLETED; + ipp_dbg("#%dto wake up worker", data->id); + /* wake up worker or abort the thread */ + wake_up(&data->ipp.waitq); + } + + return rc; +} + +/* + * ipp and dev lock are held + * release and re-grabbed here + */ +int stmvl53l1_ipp_do(struct stmvl53l1_data *data, + struct ipp_work_t *pin, struct ipp_work_t *pout) +{ + int xfer_id; + int rc; + bool has_timeout; + + ipp_dbg("enter"); + + xfer_id = get_next_xfer_id(); + /* set xfer and device dependent part of the work */ + pin->dev_id = data->id; + pin->xfer_id = xfer_id; + data->ipp.waited_xfer_id = xfer_id; + /* try to do it */ + rc = send_client_msg(pin, pin->payload); + /* shall we retry if fail to send for some time or number of try ? */ + if (rc < 0) { + rc = -1; + ipp_err("fail to send msg %d", rc); + } else if (data->ipp.buzy == 0) { + /* send ok put the ipp on buzy state while locked */ + data->ipp.buzy = IPP_STATE_PENDING; + /* unlock now that state is marked buzy */ + mutex_unlock(&data->work_mutex); + + /* put task to wait for completion */ + ipp_dbg("to wait"); + has_timeout = !wait_event_timeout(data->ipp.waitq, + (data->ipp.buzy != IPP_STATE_PENDING), + msecs_to_jiffies(IPP_TIMEOUT_MS)); + + /* relock the main lock */ + mutex_lock(&data->work_mutex); + + rc = (data->ipp.buzy & IPP_STATE_CANCELED) || has_timeout ? + -1 : 0; + if (rc) { + ipp_dbg("waking up with from canceled/timeout ipp"); + } else { + /* return status from the ipp itself */ + ipp_dbg("ip back with status %d", data->ipp.status); + rc = data->ipp.status; + } + data->ipp.buzy = 0;/* buzy clear but locked so safe */ + } else { + ipp_dbg("buzy still not zero %d", data->ipp.buzy); + rc = -1; + } + + +/* done_lock: */ + return rc; +} + + +static void stmvl53l1_nl_recv_msg(struct sk_buff *skb_in) +{ + int pid_chg = 0; + int pid; + struct nlmsghdr *nlh; + struct ipp_work_t *pwork; + + ipp_dbg("Entering"); + + nlh = (struct nlmsghdr *)skb_in->data; + pid = nlh->nlmsg_pid; /*pid of sending process */ + + pwork = nlmsg_data(nlh); + if (pwork->payload < IPP_WORK_HDR_SIZE || + pwork->payload > IPP_WORK_MAX_PAYLOAD){ + /* invalid header size */ + ipp_err("invalid msg header size %d", pwork->payload); + _ipp_dump_work(pwork, IPP_WORK_MAX_PAYLOAD, + STMVL53L1_CFG_MAX_DEV); + return; + } + + mutex_lock(&ipp_mutex); + + if ((pwork->dev_id >= STMVL53L1_CFG_MAX_DEV) || (pwork->dev_id < 0)) { + ipp_err("invalid dev id on msg %d", pwork->dev_id); + _ipp_dump_work(pwork, IPP_WORK_MAX_PAYLOAD, + STMVL53L1_CFG_MAX_DEV); + goto done_locked; + } + + if (pwork->process_no == stmvl53l1_ipp_ping) { + /* in that case the payload must be exact status size only + * if not it is a badly format message or bad message + */ + if (pwork->payload != IPP_WORK_HDR_SIZE) { + ipp_err("invalid ping msg size %d!=%zu ", + pwork->payload, IPP_WORK_HDR_SIZE); + _ipp_dump_work(pwork, IPP_WORK_MAX_PAYLOAD, + STMVL53L1_CFG_MAX_DEV); + goto done_locked; + } + /* if pid was not set or change resent all ongoing ipp */ + if (pid != daemon_pid) + ipp_warn("pid chg %d => %d\n", daemon_pid, pid); + else + ipp_dbg("got ping fm pid %d\n", daemon_pid); + daemon_pid = pid; + pid_chg = 1; + } else { + ipp_in_process(pwork); + } + done_locked: + mutex_unlock(&ipp_mutex); +} + +int stmvl53l1_ipp_setup(struct stmvl53l1_data *data) +{ + int rc; + + mutex_lock(&ipp_mutex); + + data->ipp.buzy = 0; + init_waitqueue_head(&data->ipp.waitq); + ipp_dbg("now %d dev daemon pid is %d", STMVL53L1_CFG_MAX_DEV, + daemon_pid); + rc = 0; + + mutex_unlock(&ipp_mutex); + + return rc; +} + +void stmvl53l1_ipp_cleanup(struct stmvl53l1_data *data) +{ + /* nothink to do */ +} + +#if !defined(OLD_NETLINK_API) +struct netlink_kernel_cfg cfg = { + .input = stmvl53l1_nl_recv_msg +}; +#endif + +static int netlink_protocol_type = STMVL531_CFG_NETLINK_USER; + +module_param(netlink_protocol_type, int, 0444); +MODULE_PARM_DESC(netlink_protocol_type, + "select netlink protocol type for ipp communications"); + +int stmvl53l1_ipp_init(void) +{ + mutex_init(&ipp_mutex); + daemon_pid = 1; /* pid 1 is safe should not be use for user space */ + +#if defined(OLD_NETLINK_API) + nl_sk = netlink_kernel_create(&init_net, + netlink_protocol_type, + 0, + stmvl53l1_nl_recv_msg, + NULL, + THIS_MODULE); +#else + nl_sk = netlink_kernel_create(&init_net, + netlink_protocol_type, + &cfg); +#endif + + return nl_sk ? 0 : -1; +} + + +void stmvl53l1_ipp_exit(void) +{ + if (nl_sk != NULL) { + vl53l1_dbgmsg("releasing netlink socket"); + netlink_kernel_release(nl_sk); + nl_sk = NULL; + } +} + + diff --git a/drivers/input/misc/vl53L1/lito/stmvl53l1_log.c b/drivers/input/misc/vl53L1/lito/stmvl53l1_log.c new file mode 100644 index 000000000000..ecedcb446dda --- /dev/null +++ b/drivers/input/misc/vl53L1/lito/stmvl53l1_log.c @@ -0,0 +1,78 @@ +/************************************************************************** + * Copyright (c) 2016, STMicroelectronics - All Rights Reserved + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ****************************************************************************/ +/** + * @file /stmvl53l1_module.c vl53l1_module ST VL53L1 linux kernel module + * + * This is implementation of low level driver trace support + */ +#include +#include + +#include "stmvl53l1.h" + +#ifdef VL53L1_LOG_ENABLE + +static bool trace_function; +static int trace_module; +static int trace_level; + +module_param(trace_function, bool, 0644); +MODULE_PARM_DESC(trace_function, + "allow tracing of low level function entry and exit"); + +module_param(trace_module, int, 0644); +MODULE_PARM_DESC(trace_module, + "control tracing of low level per module"); + +module_param(trace_level, int, 0644); +MODULE_PARM_DESC(trace_level, + "control tracing of low level per level"); + +void log_trace_print(uint32_t module, uint32_t level, uint32_t function, + const char *format, ...) +{ + va_list args; + + if (function && !trace_function) + return; + + if (!(module & trace_module)) + return; + + if (level > trace_level) + return; + + va_start(args, format); + vprintk(format, args); + va_end(args); +} + +#endif diff --git a/drivers/input/misc/vl53L1/lito/stmvl53l1_module-cci.c b/drivers/input/misc/vl53L1/lito/stmvl53l1_module-cci.c new file mode 100644 index 000000000000..d6cf5fb45704 --- /dev/null +++ b/drivers/input/misc/vl53L1/lito/stmvl53l1_module-cci.c @@ -0,0 +1,273 @@ +/* +* Copyright (c) 2016, STMicroelectronics - All Rights Reserved +* +* License terms: BSD 3-clause "New" or "Revised" License. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* +* 1. Redistributions of source code must retain the above copyright notice, this +* list of conditions and the following disclaimer. +* +* 2. Redistributions in binary form must reproduce the above copyright notice, +* this list of conditions and the following disclaimer in the documentation +* and/or other materials provided with the distribution. +* +* 3. Neither the name of the copyright holder nor the names of its contributors +* may be used to endorse or promote products derived from this software +* without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/** + * @file stmvl53l1_module-i2c.c + * + * implement STM VL53L1 module interface i2c wrapper + control + * using linux native i2c + gpio + reg api + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * power specific includes + */ +#include +#include +#include +#include +#include +#include + +#include "stmvl53l1-i2c.h" +#include "stmvl53l1.h" + + +extern int stmvl53l1_parse_tree(struct device *dev, struct i2c_data *i2c_data); +extern void stmvl53l1_release_gpios(struct i2c_data *i2c_data); + +/* +static struct stmvl53l1_pinctrl_info stmvl53l1_pinctrl; + + +static int stmvl53l1_request_pinctrl(struct device *dev) +{ + struct stmvl53l1_pinctrl_info *device_pctrl = &stmvl53l1_pinctrl; + device_pctrl->pinctrl = devm_pinctrl_get(dev); + if (IS_ERR_OR_NULL(device_pctrl->pinctrl)) { + vl53l1_errmsg("Pinctrl not available"); + device_pctrl->pinctrl = NULL; + return 0; + } + device_pctrl->gpio_state_active = + pinctrl_lookup_state(device_pctrl->pinctrl, + "laser_default"); + if (IS_ERR_OR_NULL(device_pctrl->gpio_state_active)) { + vl53l1_errmsg("Failed to get the active state pinctrl handle"); + device_pctrl->gpio_state_active = NULL; + return -EINVAL; + } + device_pctrl->gpio_state_suspend + = pinctrl_lookup_state(device_pctrl->pinctrl, + "laser_suspend"); + if (IS_ERR_OR_NULL(device_pctrl->gpio_state_suspend)) { + vl53l1_errmsg("Failed to get the suspend state pinctrl handle"); + device_pctrl->gpio_state_suspend = NULL; + return -EINVAL; + } + return 0; +} + +int stmvl53l1_enable_pinctrl(struct device *dev) +{ + int rc = 0; + + if (stmvl53l1_pinctrl.pinctrl && + stmvl53l1_pinctrl.gpio_state_active) { + rc = pinctrl_select_state(stmvl53l1_pinctrl.pinctrl, + stmvl53l1_pinctrl.gpio_state_active); + vl53l1_dbgmsg("enable pinctrl rc=%d\n", rc); + } + + return rc; +} + +int stmvl53l1_disable_pinctrl(struct device *dev) +{ + int rc = 0; + + if (stmvl53l1_pinctrl.pinctrl && + stmvl53l1_pinctrl.gpio_state_suspend) { + rc = pinctrl_select_state(stmvl53l1_pinctrl.pinctrl, + stmvl53l1_pinctrl.gpio_state_suspend); + vl53l1_dbgmsg("disable pinctrl rc=%d\n", rc); + } + + return rc; + +} + +int stmvl53l1_release_pinctrl(struct device *dev) +{ + if (stmvl53l1_pinctrl.pinctrl) + devm_pinctrl_put(stmvl53l1_pinctrl.pinctrl); + stmvl53l1_pinctrl.pinctrl = NULL; + + return 0; +} +*/ +static int32_t stmvl53l1_probe_cci( + struct platform_device *pdev) +{ + int rc = 0; + struct stmvl53l1_data *vl53l1_data = NULL; + struct i2c_data *i2c_data = NULL; + + vl53l1_dbgmsg("Enter %s : 0x%02x\n", pdev->name, pdev->id); + + + vl53l1_data = kzalloc(sizeof(struct stmvl53l1_data), GFP_KERNEL); + if (!vl53l1_data) { + rc = -ENOMEM; + return rc; + } + if (vl53l1_data) { + vl53l1_data->client_object = + kzalloc(sizeof(struct i2c_data), GFP_KERNEL); + if (!vl53l1_data->client_object) + goto done_freemem; + i2c_data = (struct i2c_data *)vl53l1_data->client_object; + } + //i2c_data->client = client; + i2c_data->vl53l1_data = vl53l1_data; + i2c_data->irq = -1 ; + rc = stmvl53l1_parse_tree(&(pdev->dev), i2c_data); + if (rc) + goto done_freemem; +/* + rc = stmvl53l1_request_pinctrl(&(pdev->dev)); + if (rc){ + vl53l1_errmsg("fail to request pinctrl,rc = %d", rc); + goto done_freemem; + } + rc = stmvl53l1_enable_pinctrl(&(pdev->dev)); + if (rc){ + vl53l1_errmsg("fail to enable pinctrl,rc = %d", rc); + goto release_gpios; + } +*/ + platform_set_drvdata(pdev, vl53l1_data); + //vl53l1_data->plat_dev = pdev; + + rc = stmvl53l1_setup(vl53l1_data); + if (rc) + goto release_gpios; + vl53l1_dbgmsg("End\n"); + + kref_init(&i2c_data->ref); + + return rc; + +release_gpios: + stmvl53l1_release_gpios(i2c_data); + +done_freemem: + kfree(vl53l1_data); + kfree(i2c_data); + + return 0; +} + + +static int32_t stmvl53l1_remove_cci(struct platform_device *pdev) +{ + struct stmvl53l1_data *data = platform_get_drvdata(pdev); + struct i2c_data *i2c_data = (struct i2c_data *)data->client_object; + + vl53l1_dbgmsg("Enter\n"); + mutex_lock(&data->work_mutex); + /* main driver cleanup */ + stmvl53l1_cleanup(data); + /* + rc = stmvl53l1_disable_pinctrl(&(pdev->dev)); + if (rc){ + vl53l1_errmsg("fatal,fail to disable pinctrl,rc = %d", rc); + } + rc = stmvl53l1_release_pinctrl(&(pdev->dev)); + if (rc){ + vl53l1_errmsg("fatal,fail to release pinctrl,rc = %d", rc); + } + */ + /* release gpios */ + stmvl53l1_release_gpios(i2c_data); + + mutex_unlock(&data->work_mutex); + + stmvl53l1_put(data->client_object); + + vl53l1_dbgmsg("End\n"); + + return 0; +} + + +static const struct of_device_id stmvl53l1_driver_dt_match[] = { + {.compatible = "st,stmvl53l1"}, + {} +}; + +MODULE_DEVICE_TABLE(of, stmvl53l1_driver_dt_match); + +static struct platform_driver stmvl53l1_platform_driver = { + .probe = stmvl53l1_probe_cci, + .driver = { + .name = "st,stmvl53l1", + .owner = THIS_MODULE, + .of_match_table = stmvl53l1_driver_dt_match, + }, + .remove = stmvl53l1_remove_cci, +}; + +int __init stmvl53l1_init_cci(void) +{ + int32_t rc = 0; + vl53l1_dbgmsg("enter\n"); + rc = platform_driver_register(&stmvl53l1_platform_driver); + if (rc < 0) { + vl53l1_dbgmsg("platform_driver_register fail\n"); + return rc; + } + + return rc; +} + +void __exit stmvl53l1_exit_cci(void* obj) +{ + vl53l1_dbgmsg("enter\n"); + platform_driver_unregister(&stmvl53l1_platform_driver); +} + diff --git a/drivers/input/misc/vl53L1/lito/stmvl53l1_module-i2c.c b/drivers/input/misc/vl53L1/lito/stmvl53l1_module-i2c.c new file mode 100644 index 000000000000..9e7c8cf18851 --- /dev/null +++ b/drivers/input/misc/vl53L1/lito/stmvl53l1_module-i2c.c @@ -0,0 +1,1027 @@ +/************************************************************************** + * Copyright (c) 2016, STMicroelectronics - All Rights Reserved + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ****************************************************************************/ + +/** + * @file stmvl53l1_module-i2c.c + * + * implement STM VL53L1 module interface i2c wrapper + control + * using linux native i2c + gpio + reg api + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * power specific includes + */ +#include +#include +#include +#include +#include +#include + +#include "stmvl53l1-i2c.h" +#include "stmvl53l1.h" +#include "cam_cci_ctrl_interface.h" + +#define STMVL53L1_SLAVE_ADDR (0x52>>1) +#define IGNORE_IRQ 0 //songyt add +/** @ingroup drv_port + * @{ + */ + +/** + * control specific debug message echo + * + * Set to 0/1 do not remove + * + * most dbg warn err messages goes true main driver macro + * this one permit some specific debug without activating all main dbg + */ +#define MODI2C_DEBUG 0 + +/* + * mutex to handle device i2c address changes. It allow to avoid multiple + * device active with same i2c addresses at the same time. Note that we don't + * support case where boot_reg has the same value as a final i2c address of + * another device. + */ +static DEFINE_MUTEX(dev_addr_change_mutex); + +/** + * i2c client assigned to our driver + * + * this is use for stm test purpose as we fake client create and regstration + * we stores the i2c client for release in clean-up overwise we wan't reload + * the module multiple time + * + * in a normal dev tree prod system this is not required + */ +static struct i2c_client *stm_test_i2c_client; + +/* + * pi3: + * insmod stmvl53l1.ko force_device=1 adapter_nb=1 xsdn_gpio_nb=19 + * intr_gpio_nb=16 pwren_gpio_nb=12 + * + * panda + * insmod stmvl53l1.ko force_device=1 adapter_nb=4 xsdn_gpio_nb=56 + * intr_gpio_nb=59 pwren_gpio_nb=55 +*/ + +static int force_device; +static int adapter_nb = -1; +static int xsdn_gpio_nb = -1; +static int pwren_gpio_nb = -1; +static int intr_gpio_nb = -1; + +module_param(force_device, int, 0000); +MODULE_PARM_DESC(force_device, "force device insertion at module init"); + +module_param(adapter_nb, int, 0000); +MODULE_PARM_DESC(adapter_nb, "i2c adapter to use"); + +module_param(xsdn_gpio_nb, int, 0000); +MODULE_PARM_DESC(xsdn_gpio_nb, "select gpio numer to use for vl53l1 reset"); + +module_param(pwren_gpio_nb, int, 0000); +MODULE_PARM_DESC(pwren_gpio_nb, "select gpio numer to use for vl53l1 power"); + +module_param(intr_gpio_nb, int, 0000); +MODULE_PARM_DESC(intr_gpio_nb, "select gpio numer to use for vl53l1 interrupt"); + +/** + * warn message + * + * @warning use only in scope where i2c_data ptr is present + **/ +#define modi2c_warn(fmt, ...)\ + dev_WARN(&i2c_data->client->dev, fmt, ##__VA_ARGS__) + +/** + * err message + * + * @warning use only in scope where i2c_data ptr is present + */ +#define modi2c_err(fmt, ...)\ + dev_err(&i2c_data->client->dev, fmt, ##__VA_ARGS__) + + +struct stmvl53l1_pinctrl_info { + struct pinctrl *pinctrl; + struct pinctrl_state *gpio_state_active; + struct pinctrl_state *gpio_state_suspend; +}; +extern unsigned const char* get_PCB_Version(void); + +static struct stmvl53l1_pinctrl_info stmvl53l1_pinctrl; + + + +static int stmvl53l1_request_pinctrl(struct device *dev) +{ + struct stmvl53l1_pinctrl_info *device_pctrl = &stmvl53l1_pinctrl; + device_pctrl->pinctrl = devm_pinctrl_get(dev); + if (IS_ERR_OR_NULL(device_pctrl->pinctrl)) { + vl53l1_errmsg("Pinctrl not available"); + device_pctrl->pinctrl = NULL; + return 0; + } + device_pctrl->gpio_state_active = + pinctrl_lookup_state(device_pctrl->pinctrl, + "laser_default"); + if (IS_ERR_OR_NULL(device_pctrl->gpio_state_active)) { + vl53l1_errmsg("Failed to get the active state pinctrl handle"); + device_pctrl->gpio_state_active = NULL; + return -EINVAL; + } + device_pctrl->gpio_state_suspend + = pinctrl_lookup_state(device_pctrl->pinctrl, + "laser_suspend"); + if (IS_ERR_OR_NULL(device_pctrl->gpio_state_suspend)) { + vl53l1_errmsg("Failed to get the suspend state pinctrl handle"); + device_pctrl->gpio_state_suspend = NULL; + return -EINVAL; + } + return 0; +} + +static int stmvl53l1_enable_pinctrl(struct device *dev) +{ + int rc = 0; + + if (stmvl53l1_pinctrl.pinctrl && + stmvl53l1_pinctrl.gpio_state_active) { + rc = pinctrl_select_state(stmvl53l1_pinctrl.pinctrl, + stmvl53l1_pinctrl.gpio_state_active); + vl53l1_dbgmsg("enable pinctrl rc=%d\n", rc); + } + + return rc; +} + +int stmvl53l1_disable_pinctrl(struct device *dev) +{ + int rc = 0; + + if (stmvl53l1_pinctrl.pinctrl && + stmvl53l1_pinctrl.gpio_state_suspend) { + rc = pinctrl_select_state(stmvl53l1_pinctrl.pinctrl, + stmvl53l1_pinctrl.gpio_state_suspend); + vl53l1_dbgmsg("disable pinctrl rc=%d\n", rc); + } + + return rc; + +} + +int stmvl53l1_release_pinctrl(struct device *dev) +{ + if (stmvl53l1_pinctrl.pinctrl) + devm_pinctrl_put(stmvl53l1_pinctrl.pinctrl); + stmvl53l1_pinctrl.pinctrl = NULL; + + return 0; +} + + + + +#if MODI2C_DEBUG +# define modi2c_dbg(fmt, ...)\ + pr_devel("%s "fmt"\n", __func__, ##__VA_ARGS__) +#else +# define modi2c_dbg(...) (void)0 +#endif + +static int insert_device(void) +{ + int ret = 0; + struct i2c_adapter *adapter; + struct i2c_board_info info = { + .type = "stmvl53l1", + .addr = STMVL53L1_SLAVE_ADDR, + }; + + memset(&info, 0, sizeof(info)); + strcpy(info.type, "stmvl53l1"); + info.addr = STMVL53L1_SLAVE_ADDR; + adapter = i2c_get_adapter(adapter_nb); + if (!adapter) { + ret = -EINVAL; + goto done; + } + stm_test_i2c_client = i2c_new_device(adapter, &info); + if (!stm_test_i2c_client) + ret = -EINVAL; + +done: + return ret; +} + +static int get_xsdn(struct device *dev, struct i2c_data *i2c_data) +{ + int rc = 0; + + i2c_data->io_flag.xsdn_owned = 0; + if (i2c_data->xsdn_gpio == -1) { + vl53l1_errmsg("reset gpio is required"); + rc = -ENODEV; + goto no_gpio; + } + + vl53l1_dbgmsg("request xsdn_gpio %d", i2c_data->xsdn_gpio); + rc = gpio_request(i2c_data->xsdn_gpio, "vl53l1_xsdn"); + if (rc) { + vl53l1_errmsg("fail to acquire xsdn %d", rc); + goto request_failed; + } + + rc = gpio_direction_output(i2c_data->xsdn_gpio, 0); + if (rc) { + vl53l1_errmsg("fail to configure xsdn as output %d", rc); + goto direction_failed; + } + i2c_data->io_flag.xsdn_owned = 1; + + return rc; + +direction_failed: + gpio_free(i2c_data->xsdn_gpio); + +request_failed: +no_gpio: + return rc; +} + +static void put_xsdn(struct i2c_data *i2c_data) +{ + if (i2c_data->io_flag.xsdn_owned) { + vl53l1_dbgmsg("release xsdn_gpio %d", i2c_data->xsdn_gpio); + gpio_free(i2c_data->xsdn_gpio); + i2c_data->io_flag.xsdn_owned = 0; + i2c_data->xsdn_gpio = -1; + } + i2c_data->xsdn_gpio = -1; +} + +static int get_pwren(struct device *dev, struct i2c_data *i2c_data) +{ + int rc = 0; + + i2c_data->io_flag.pwr_owned = 0; + if (i2c_data->pwren_gpio == -1) { + vl53l1_wanrmsg("pwren gpio disable"); + goto no_gpio; + } + + vl53l1_dbgmsg("request pwren_gpio %d", i2c_data->pwren_gpio); + rc = gpio_request(i2c_data->pwren_gpio, "vl53l1_pwren"); + if (rc) { + vl53l1_errmsg("fail to acquire pwren %d", rc); + goto request_failed; + } + + rc = gpio_direction_output(i2c_data->pwren_gpio, 0); + if (rc) { + vl53l1_errmsg("fail to configure pwren as output %d", rc); + goto direction_failed; + } + i2c_data->io_flag.pwr_owned = 1; + + return rc; + +direction_failed: + gpio_free(i2c_data->xsdn_gpio); + +request_failed: +no_gpio: + return rc; +} + +static void put_pwren(struct i2c_data *i2c_data) +{ + if (i2c_data->io_flag.pwr_owned) { + vl53l1_dbgmsg("release pwren_gpio %d", i2c_data->pwren_gpio); + gpio_free(i2c_data->pwren_gpio); + i2c_data->io_flag.pwr_owned = 0; + i2c_data->pwren_gpio = -1; + } + i2c_data->pwren_gpio = -1; +} + +static int get_intr(struct device *dev, struct i2c_data *i2c_data) +{ + int rc = 0; + + i2c_data->io_flag.intr_owned = 0; + if (i2c_data->intr_gpio == -1) { + vl53l1_wanrmsg("no interrupt gpio"); + goto no_gpio; + } + + vl53l1_dbgmsg("request intr_gpio %d", i2c_data->intr_gpio); + rc = gpio_request(i2c_data->intr_gpio, "vl53l1_intr"); + if (rc) { + vl53l1_errmsg("fail to acquire intr %d", rc); + goto request_failed; + } + + rc = gpio_direction_input(i2c_data->intr_gpio); + if (rc) { + vl53l1_errmsg("fail to configure intr as input %d", rc); + goto direction_failed; + } + + i2c_data->irq = gpio_to_irq(i2c_data->intr_gpio); + if (i2c_data->irq < 0) { + vl53l1_errmsg("fail to map GPIO: %d to interrupt:%d\n", + i2c_data->intr_gpio, i2c_data->irq); + goto irq_failed; + } + i2c_data->io_flag.intr_owned = 1; + + return rc; + +irq_failed: +direction_failed: + gpio_free(i2c_data->intr_gpio); + +request_failed: +no_gpio: + return rc; +} + +static void put_intr(struct i2c_data *i2c_data) +{ + if (i2c_data->io_flag.intr_owned) { + if (i2c_data->io_flag.intr_started) { + free_irq(i2c_data->irq, i2c_data); + i2c_data->io_flag.intr_started = 0; + } + vl53l1_dbgmsg("release intr_gpio %d", i2c_data->intr_gpio); + gpio_free(i2c_data->intr_gpio); + i2c_data->io_flag.intr_owned = 0; + } + i2c_data->intr_gpio = -1; +} + +/** + * parse dev tree for all platform specific input + */ +int stmvl53l1_parse_tree(struct device *dev, struct i2c_data *i2c_data) +{ + int rc = 0; + enum of_gpio_flags flags; + /* if force device is in use then gpio nb comes from module param else + * we use devicetree. + */ + i2c_data->vdd = NULL; + i2c_data->xsd = NULL; + i2c_data->pwren_gpio = -1; + i2c_data->xsdn_gpio = -1; + i2c_data->intr_gpio = -1; + i2c_data->boot_reg = STMVL53L1_SLAVE_ADDR; + if (force_device) { + i2c_data->xsdn_gpio = xsdn_gpio_nb; + i2c_data->pwren_gpio = pwren_gpio_nb; + i2c_data->intr_gpio = intr_gpio_nb; + } else if (dev->of_node) { + /* power : either vdd or pwren_gpio. try reulator first */ + + #if 0 + if ((strcmp(get_PCB_Version(),"T0") == 0) || (strcmp(get_PCB_Version(),"EVB") == 0) || + (strcmp(get_PCB_Version(),"T1") == 0) || (strcmp(get_PCB_Version(),"T2") == 0) || + (strcmp(get_PCB_Version(),"T3") == 0) || (strcmp(get_PCB_Version(),"T4") == 0) || + (strcmp(get_PCB_Version(),"EVT0") == 0) || (strcmp(get_PCB_Version(),"EVT1") == 0)) + { + i2c_data->vdd = regulator_get(dev, "laser_vdd"); + } + else + { + i2c_data->vdd = regulator_get(dev, "laser_vdd_sec"); + } + #endif + + i2c_data->vdd = regulator_get(dev, "laser_vdd_sec"); + + if (IS_ERR(i2c_data->vdd) || i2c_data->vdd == NULL) { + i2c_data->vdd = NULL; + vl53l1_wanrmsg( + "no laser_vdd, fatal."); + } + i2c_data->xsd = regulator_get(dev, "laser_xsd"); + if (IS_ERR(i2c_data->xsd) || i2c_data->xsd == NULL) { + i2c_data->xsd = NULL; + vl53l1_wanrmsg( + "no laser_xsd, fatal."); + } + i2c_data->pwren_gpio = of_get_named_gpio_flags(dev->of_node, "pwren-gpio", 0, + &flags); + if (gpio_is_valid(i2c_data->pwren_gpio)) { + vl53l1_dbgmsg("pwren-gpio %d", + i2c_data->pwren_gpio); + } else { + vl53l1_wanrmsg( + "no regulator, nor power gpio => power ctrl disabled"); + i2c_data->pwren_gpio = -1; + } + i2c_data->xsdn_gpio = of_get_named_gpio_flags(dev->of_node, "xsdn-gpio", 0, + &flags); + if (gpio_is_valid(i2c_data->xsdn_gpio)) { + vl53l1_dbgmsg("xsdn-gpio %d", + i2c_data->xsdn_gpio); + } else { + vl53l1_wanrmsg("Unable to find xsdn-gpio %d", + i2c_data->xsdn_gpio); + i2c_data->xsdn_gpio = -1; + } +#if IGNORE_IRQ + i2c_data->intr_gpio = -1; + vl53l1_dbgmsg("do not use intr-gpio!"); +#else + i2c_data->intr_gpio = of_get_named_gpio_flags(dev->of_node, "intr-gpio", 0,&flags); + if (gpio_is_valid(i2c_data->intr_gpio)) { + vl53l1_dbgmsg("intr-gpio %d", + i2c_data->intr_gpio); + } else { + vl53l1_wanrmsg("Unable to find intr-gpio %d", + i2c_data->intr_gpio); + i2c_data->intr_gpio = -1; + } +#endif + } + + /* configure gpios */ + rc = get_xsdn(dev, i2c_data); + if (rc) + goto no_xsdn; + if(i2c_data->pwren_gpio != -1){ + rc = get_pwren(dev, i2c_data); + if (rc) + goto no_pwren; + } + rc = get_intr(dev, i2c_data); + if (rc){ + vl53l1_errmsg("get_intr failed."); + goto no_intr; + } + return rc; + +no_intr: +#if IGNORE_IRQ + return 0; +#else + if (i2c_data->vdd) { + regulator_put(i2c_data->vdd); + i2c_data->vdd = NULL; + } + put_pwren(i2c_data); +#endif +no_pwren: + if (i2c_data->xsd) { + regulator_put(i2c_data->xsd); + i2c_data->xsd = NULL; + } + + put_xsdn(i2c_data); +no_xsdn: + return rc; +} + +void stmvl53l1_release_gpios(struct i2c_data *i2c_data) +{ + if (i2c_data->xsd) { + regulator_put(i2c_data->xsd); + i2c_data->xsd = NULL; + } + put_xsdn(i2c_data); + if (i2c_data->vdd) { + regulator_put(i2c_data->vdd); + i2c_data->vdd = NULL; + } + put_pwren(i2c_data); + put_intr(i2c_data); +} + +static int stmvl53l1_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int rc = 0; + struct stmvl53l1_data *vl53l1_data = NULL; + struct i2c_data *i2c_data = NULL; + + vl53l1_dbgmsg("Enter %s : 0x%02x\n", client->name, client->addr); + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE)) { + rc = -EIO; + return rc; + } + + vl53l1_data = kzalloc(sizeof(struct stmvl53l1_data), GFP_KERNEL); + if (!vl53l1_data) { + rc = -ENOMEM; + return rc; + } + if (vl53l1_data) { + vl53l1_data->client_object = + kzalloc(sizeof(struct i2c_data), GFP_KERNEL); + if (!vl53l1_data) + goto done_freemem; + i2c_data = (struct i2c_data *)vl53l1_data->client_object; + } + i2c_data->client = client; + i2c_data->vl53l1_data = vl53l1_data; + i2c_data->irq = -1 ; /* init to no irq */ + + /* parse and configure hardware */ + rc = stmvl53l1_parse_tree(&i2c_data->client->dev, i2c_data); + if (rc) + goto done_freemem; + + /* setup device name */ + /* vl53l1_data->dev_name = dev_name(&client->dev); */ + + /* setup client data */ + i2c_set_clientdata(client, vl53l1_data); + + /*request gpio and set gpio status*/ + rc = stmvl53l1_request_pinctrl(&client->dev); + if (rc){ + vl53l1_errmsg("fail to request pinctrl,rc = %d", rc); + goto done_freemem; + } + rc = stmvl53l1_enable_pinctrl(&client->dev); + if (rc){ + vl53l1_errmsg("fail to enable pinctrl,rc = %d", rc); + goto release_gpios; + } + + + /* end up by core driver setup */ + rc = stmvl53l1_setup(vl53l1_data); + if (rc) + goto release_gpios; + vl53l1_dbgmsg("End\n"); + + kref_init(&i2c_data->ref); + + return rc; + +release_gpios: + stmvl53l1_release_gpios(i2c_data); + +done_freemem: + /* kfree safe against NULL */ + kfree(vl53l1_data); + kfree(i2c_data); + + return -1; +} + +static int stmvl53l1_remove(struct i2c_client *client) +{ + struct stmvl53l1_data *data = i2c_get_clientdata(client); + struct i2c_data *i2c_data = (struct i2c_data *)data->client_object; + int rc = 0; + + vl53l1_dbgmsg("Enter\n"); + mutex_lock(&data->work_mutex); + /* main driver cleanup */ + stmvl53l1_cleanup(data); + + rc = stmvl53l1_disable_pinctrl(&(client->dev)); + if (rc){ + vl53l1_errmsg("fatal,fail to disable pinctrl,rc = %d", rc); + } + rc = stmvl53l1_release_pinctrl(&(client->dev)); + if (rc){ + vl53l1_errmsg("fatal,fail to release pinctrl,rc = %d", rc); + } + + /* release gpios */ + stmvl53l1_release_gpios(i2c_data); + + mutex_unlock(&data->work_mutex); + + stmvl53l1_put(data->client_object); + + vl53l1_dbgmsg("End\n"); + + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int stmvl53l1_suspend(struct device *dev) +{ + struct stmvl53l1_data *data = i2c_get_clientdata(to_i2c_client(dev)); + + vl53l1_dbgmsg("Enter\n"); + mutex_lock(&data->work_mutex); + /* Stop ranging */ + stmvl53l1_pm_suspend_stop(data); + + mutex_unlock(&data->work_mutex); + + vl53l1_dbgmsg("End\n"); + + return 0; +} + +static int stmvl53l1_resume(struct device *dev) +{ +#if 0 + struct stmvl53l1_data *data = i2c_get_clientdata(to_i2c_client(dev)); + + vl53l1_dbgmsg("Enter\n"); + + mutex_lock(&data->work_mutex); + + /* do nothing user will restart measurements */ + + mutex_unlock(&data->work_mutex); + + vl53l1_dbgmsg("End\n"); +#else + vl53l1_dbgmsg("Enter\n"); + vl53l1_dbgmsg("End\n"); +#endif + return 0; +} +#endif + + +static SIMPLE_DEV_PM_OPS(stmvl53l1_pm_ops, stmvl53l1_suspend, stmvl53l1_resume); + +static const struct i2c_device_id stmvl53l1_id[] = { + { STMVL53L1_DRV_NAME, 0 }, + { }, +}; +MODULE_DEVICE_TABLE(i2c, stmvl53l1_id); + +static const struct of_device_id st_stmvl53l1_dt_match[] = { + { .compatible = "st,"STMVL53L1_DRV_NAME, }, + { }, +}; + +static struct i2c_driver stmvl53l1_driver = { + .driver = { + .name = STMVL53L1_DRV_NAME, + .owner = THIS_MODULE, + .of_match_table = st_stmvl53l1_dt_match, + .pm = &stmvl53l1_pm_ops, + }, + .probe = stmvl53l1_probe, + .remove = stmvl53l1_remove, + .id_table = stmvl53l1_id, + +}; + +/** + * give power to device + * + * @param object the i2c layer object + * @return + */ +int stmvl53l1_power_up_i2c(void *object) +{ + int rc = 0; + struct i2c_data *data = (struct i2c_data *) object; + + vl53l1_dbgmsg("Enter\n"); + + /* turn on power */ + if (data->vdd) { + rc = regulator_enable(data->vdd); + if (rc) { + vl53l1_errmsg("fail to turn on regulator"); + return rc; + } + } + if (data->pwren_gpio != -1) { + gpio_set_value(data->pwren_gpio, 1); + vl53l1_info("slow power on"); + } else + vl53l1_wanrmsg("no power control"); + + if (data->xsd) { + rc = regulator_enable(data->xsd); + if (rc) { + vl53l1_errmsg("fail to turn on regulator"); + return rc; + } + } + if (data->xsdn_gpio != -1) { + gpio_set_value(data->xsdn_gpio, 1); + vl53l1_info("slow power on"); + } else + vl53l1_wanrmsg("no power control"); + + + return rc; +} + +/** + * remove power to device (reset it) + * + * @param i2c_object the i2c layer object + * @return 0 on success + */ +int stmvl53l1_power_down_i2c(void *i2c_object) +{ + struct i2c_data *data = (struct i2c_data *) i2c_object; + int rc = 0; + + vl53l1_dbgmsg("Enter\n"); + + /* turn off power */ + if (data->vdd) { + rc = regulator_disable(data->vdd); + if (rc) + vl53l1_errmsg("reg disable failed. rc=%d\n", + rc); + } + if (data->pwren_gpio != -1) { + gpio_set_value(data->pwren_gpio, 0); + } + + if (data->xsd) { + rc = regulator_disable(data->xsd); + if (rc) + vl53l1_errmsg("reg disable failed. rc=%d\n", + rc); + } + if (data->xsdn_gpio != -1) { + gpio_set_value(data->xsdn_gpio, 0); + } + + vl53l1_dbgmsg("power off"); + + vl53l1_dbgmsg("End\n"); + + return rc; +} + +static int handle_i2c_address_device_change_lock(struct i2c_data *data) +{ + return 0; +} + +/* reset release will also handle device address change. It will avoid state + * where multiple stm53l1 are bring out of reset at the same time with the + * same boot address. + * Note that we don't manage case where boot_reg has the same value as a final + * i2c address of another device. This case is not supported and will lead + * to unpredictable behavior. + */ +static int release_reset(struct i2c_data *data) +{ + //struct i2c_client *client = (struct i2c_client *) data->client; + int rc = 0; + bool is_address_change = false;//client->addr != data->boot_reg;//songyt modify + + if (is_address_change) + mutex_lock(&dev_addr_change_mutex); + //vl53l1_dbgmsg("reset xsdn pin to 1\n"); + gpio_set_value(data->xsdn_gpio, 1); + if (is_address_change) { + rc = handle_i2c_address_device_change_lock(data); + if (rc){ + gpio_set_value(data->xsdn_gpio, 0); + //vl53l1_dbgmsg("reset xsdn pin to 0\n"); + } + } + + if (is_address_change) + mutex_unlock(&dev_addr_change_mutex); + + return rc; +} + +/** + * release device reset + * + * @param i2c_object the i2c layer object + * @return 0 on success + */ +int stmvl53l1_reset_release_i2c(void *i2c_object) +{ + int rc; + struct i2c_data *data = (struct i2c_data *) i2c_object; + + vl53l1_dbgmsg("Enter\n"); + + rc = release_reset(data); + if (rc) + goto error; + + /* and now wait for device end of boot */ + data->vl53l1_data->is_delay_allowed = true; + rc = VL53L1_WaitDeviceBooted(&data->vl53l1_data->stdev); + data->vl53l1_data->is_delay_allowed = false; + if (rc) { + gpio_set_value(data->xsdn_gpio, 0); + vl53l1_errmsg("boot fail with error %d,change xsdn pin to 0", rc); + data->vl53l1_data->last_error = rc; + rc = -EIO; + } + +error: + vl53l1_dbgmsg("End\n"); + + return rc; +} + +/** + * put device under reset + * + * @param i2c_object the i2c layer object + * @return 0 on success + */ +int stmvl53l1_reset_hold_i2c(void *i2c_object) +{ + struct i2c_data *data = (struct i2c_data *) i2c_object; + + vl53l1_dbgmsg("Enter\n"); + + gpio_set_value(data->xsdn_gpio, 0); + + vl53l1_dbgmsg("End\n"); + + return 0; +} + +int stmvl53l1_init_i2c(void) +{ + int ret = 0; + + vl53l1_dbgmsg("Enter\n"); + + /* register as a i2c client device */ + ret = i2c_add_driver(&stmvl53l1_driver); + if (ret) + vl53l1_errmsg("%d erro ret:%d\n", __LINE__, ret); + + if (!ret && force_device) + ret = insert_device(); + + if (ret) + i2c_del_driver(&stmvl53l1_driver); + + vl53l1_dbgmsg("End with rc:%d\n", ret); + + return ret; +} + + +void stmvl53l1_clean_up_i2c(void) +{ + if (stm_test_i2c_client) { + vl53l1_dbgmsg("to unregister i2c client\n"); + i2c_unregister_device(stm_test_i2c_client); + } +} + +static irqreturn_t stmvl53l1_irq_handler_i2c(int vec, void *info) +{ + struct i2c_data *i2c_data = (struct i2c_data *)info; + + if (i2c_data->irq == vec) { + modi2c_dbg("irq"); + stmvl53l1_intr_handler(i2c_data->vl53l1_data); + modi2c_dbg("over"); + } else { + if (!i2c_data->msg_flag.unhandled_irq_vec) { + modi2c_warn("unmatching vec %d != %d\n", + vec, i2c_data->irq); + i2c_data->msg_flag.unhandled_irq_vec = 1; + } + } + + return IRQ_HANDLED; +} + +/** + * enable and start intr handling + * + * @param object our i2c_data specific object + * @param poll_mode [in/out] set to force mode clear to use irq + * @return 0 on success and set ->poll_mode if it faill ranging wan't start + */ +int stmvl53l1_start_intr(void *object, int *poll_mode) +{ + struct i2c_data *i2c_data; + int rc; + + i2c_data = (struct i2c_data *)object; + /* irq and gpio acquire config done in parse_tree */ + if (i2c_data->irq < 0) { + /* the i2c tree as no intr force polling mode */ + *poll_mode = -1; + return 0; + } + /* clear irq warning report enabe it again for this session */ + i2c_data->msg_flag.unhandled_irq_vec = 0; + /* if started do no nothing */ + if (i2c_data->io_flag.intr_started) { + /* nothing to do */ + *poll_mode = 0; + return 0; + } + + vl53l1_dbgmsg("to register_irq:%d\n", i2c_data->irq); + rc = request_threaded_irq(i2c_data->irq, NULL, + stmvl53l1_irq_handler_i2c, + IRQF_TRIGGER_FALLING|IRQF_ONESHOT, + "vl53l1_interrupt", + (void *)i2c_data); + if (rc) { + vl53l1_errmsg("fail to req threaded irq rc=%d\n", rc); + *poll_mode = 0; + } else { + vl53l1_dbgmsg("irq %d now handled\n", i2c_data->irq); + i2c_data->io_flag.intr_started = 1; + *poll_mode = 0; + } + return rc; +} + +void *stmvl53l1_get(void *object) +{ + struct i2c_data *data = (struct i2c_data *) object; + + vl53l1_dbgmsg("Enter\n"); + kref_get(&data->ref); + vl53l1_dbgmsg("End\n"); + + return object; +} + +static void memory_release(struct kref *kref) +{ + struct i2c_data *data = container_of(kref, struct i2c_data, ref); + + vl53l1_dbgmsg("Enter\n"); + kfree(data->vl53l1_data); + kfree(data); + vl53l1_dbgmsg("End\n"); +} + +void stmvl53l1_put(void *object) +{ + struct i2c_data *data = (struct i2c_data *) object; + + vl53l1_dbgmsg("Enter\n"); + kref_put(&data->ref, memory_release); + vl53l1_dbgmsg("End\n"); +} + +void __exit stmvl53l1_exit_i2c(void *i2c_object) +{ + vl53l1_dbgmsg("Enter\n"); + i2c_del_driver(&stmvl53l1_driver); + vl53l1_dbgmsg("End\n"); +} diff --git a/drivers/input/misc/vl53L1/lito/stmvl53l1_module.c b/drivers/input/misc/vl53L1/lito/stmvl53l1_module.c new file mode 100644 index 000000000000..470c4822b338 --- /dev/null +++ b/drivers/input/misc/vl53L1/lito/stmvl53l1_module.c @@ -0,0 +1,4354 @@ +/************************************************************************** + * Copyright (c) 2016, STMicroelectronics - All Rights Reserved + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ****************************************************************************/ +/** + * @file /stmvl53l1_module.c vl53l1_module ST VL53L1 linux kernel module + * + * main file + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * API includes + */ + +#include "stmvl53l1.h" +#include "cam_cci_ctrl_interface.h" +#include "stmvl53l1-i2c.h" +#include "stmvl53l1_ipp.h" + +#include "stmvl53l1_if.h" /* our device interface to user space */ +#include "stmvl53l1_internal_if.h" + +/* + * include default tuning file + */ +#include "stmvl53l1_tunings.h" + +/** @ingroup vl53l1_config + * @{ + */ +/** + * default polling period delay in millisecond + * + * It can be set at run time via @ref vl53l1_ioctl or @ref sysfs_attrib + * + * @note apply only for device operating in polling mode only + */ +#define STMVL53L1_CFG_POLL_DELAY_MS 30 + +/** + * default timing budget in microsecond + * + * Can be change at run time via @ref vl53l1_ioctl or @ref sysfs_attrib + */ +#define STMVL53L1_CFG_TIMING_BUDGET_US 30000 + +/** default preset ranging mode */ +//#define STMVL53L1_CFG_DEFAULT_MODE VL53L1_PRESETMODE_RANGING + +/** default distance mode */ +#define STMVL53L1_CFG_DEFAULT_DISTANCE_MODE VL53L1_DISTANCEMODE_LONG + +/** default crosstalk enable */ +#define STMVL53L1_CFG_DEFAULT_CROSSTALK_ENABLE 0 + +/** default output mode */ +#define STMVL53L1_CFG_DEFAULT_OUTPUT_MODE VL53L1_OUTPUTMODE_NEAREST + +#define STMVL53L1_CFG_DEFAULT_OFFSET_CORRECTION_MODE \ + VL53L1_OFFSETCORRECTIONMODE_STANDARD + +/** default Dmax mode */ +#define STMVL53L1_CFG_DEFAULT_DMAX_MODE VL53L1_DMAXMODE_FMT_CAL_DATA + +/** default smudge correction enable value */ +#define STMVL53L1_CFG_DEFAULT_SMUDGE_CORRECTION_MODE \ + VL53L1_SMUDGE_CORRECTION_NONE + +/** @} */ /* ingroup vl53l1_config */ + +/** @ingroup vl53l1_mod_dbg + * @{ + */ + +/** + * activate dump of roi in roi ctrl operation + * + * @note uses @a vl53l1_dbgmsg for output so make sure to enable debug + * to get roi dump + */ +#define STMVL53L1_CFG_ROI_DEBUG 0 //songyt 0 to 1 + +/** @} */ /* ingroup vl53l1_mod_dbg*/ + +/* #define DEBUG_TIME_LOG */ + + +#ifdef DEBUG_TIME_LOG +struct timeval start_tv, stop_tv; +#endif + +/* Set default value to 1 to allow to see module insertion debug messages */ +int stmvl53l1_enable_debug = 0; + +#define VL53L1_INPUT_DEVICE_NAME "STM VL53L1 proximity sensor" + +static long stmvl53l1_ioctl(struct file *file, + unsigned int cmd, unsigned long arg); +static int stmvl53l1_open(struct inode *inode, struct file *file); +static int stmvl53l1_release(struct inode *inode, struct file *file); +static int ctrl_start(struct stmvl53l1_data *data); +static int ctrl_stop(struct stmvl53l1_data *data); + +static bool force_device_on_en_default = false;//songyt change true to false + +module_param(force_device_on_en_default, bool, 0444); +MODULE_PARM_DESC(force_device_on_en_default, + "select whether force_device_on_en is true or false by default"); + +/* boilerplate for integer parameter */ +#define IMPLEMENT_PARAMETER_INTEGER(sysfs_name, info_name)\ +static ssize_t stmvl53l1_show_##sysfs_name(struct device *dev, \ + struct device_attribute *attr, char *buf) \ +{ \ + struct stmvl53l1_data *data = dev_get_drvdata(dev); \ + int param; \ +\ + mutex_lock(&data->work_mutex); \ + param = data->sysfs_name; \ + mutex_unlock(&data->work_mutex);; \ +\ + return scnprintf(buf, PAGE_SIZE, "%d\n", param); \ +} \ +\ +static ssize_t stmvl53l1_store_##sysfs_name(struct device *dev, \ + struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + struct stmvl53l1_data *data = dev_get_drvdata(dev); \ + int rc; \ + int param; \ +\ + mutex_lock(&data->work_mutex); \ +\ + if (kstrtoint(buf, 0, ¶m)) { \ + vl53l1_errmsg("invalid syntax in %s", buf); \ + rc = -EINVAL; \ + } else \ + rc = stmvl53l1_set_##sysfs_name(data, param); \ +\ + mutex_unlock(&data->work_mutex); \ +\ + return rc ? rc : count; \ +} \ +\ +static int ctrl_param_##sysfs_name(struct stmvl53l1_data *data, \ + struct stmvl53l1_parameter *param) \ +{ \ + int rc; \ +\ + if (param->is_read) { \ + param->value = data->sysfs_name; \ + param->status = 0; \ + vl53l1_dbgmsg("get " info_name " %d", param->value); \ + rc = 0; \ + } else { \ + rc = stmvl53l1_set_##sysfs_name(data, param->value); \ + vl53l1_dbgmsg("rc %d req %d now %d", rc, \ + param->value, data->sysfs_name); \ + } \ +\ + return rc; \ +} + +/** + * module interface struct + * interface to platform speficic device handling , concern power/reset ... + */ +struct stmvl53l1_module_fn_t { + int (*init)(void); /*!< init */ + /** + * clean up job + * @param data module specific data ptr + */ + void (*deinit)(void *data); + /** + * give device power + * @param data specific module storage ptr + * @return 0 on sucess + */ + int (*power_up)(void *data); + /** + * power down TOFO also stop intr + */ + int (*power_down)(void *data); + /* + * release reset so device start. + */ + int (*reset_release)(void *data); + /* + * put device under reset. + */ + int (*reset_hold)(void *data); + + /** + * enable interrupt + * + * @param object : interface speficic ptr + * @note "module specfic ptr is data->client_object + * @return 0 on success else error then drievr wan't start ranging! + * if no interrupt or it can't be hooked but still to operated in poll + * mode then return 0 and force data->poll_mode + * might have to clear poll_mode exlplcilty if to operate in real intr + * mode as pool mode + * is the default + */ + int (*start_intr)(void *object, int *poll_mode); + + void (*clean_up)(void); /*!< optional can be void */ + + /* increment reference counter */ + void *(*get)(void *object); + + /* decrement reference counter and deallocate memory when zero */ + void (*put)(void *object); +}; + +/** i2c module interface*/ +static struct stmvl53l1_module_fn_t stmvl53l1_module_func_tbl = { +#ifdef USE_CAMERA_CCI + .init = stmvl53l1_init_cci, + .deinit = stmvl53l1_exit_cci, +#else + .init = stmvl53l1_init_i2c, + .deinit = stmvl53l1_exit_i2c, +#endif + .power_up = stmvl53l1_power_up_i2c, + .power_down = stmvl53l1_power_down_i2c, + .reset_release = stmvl53l1_reset_release_i2c, + .reset_hold = stmvl53l1_reset_hold_i2c, + .clean_up = stmvl53l1_clean_up_i2c, + .start_intr = stmvl53l1_start_intr, + .get = stmvl53l1_get, + .put = stmvl53l1_put, +}; +static bool ipp_inited = false; + + +#ifndef MIN +# define MIN(a, b) ((a) < (b) ? (a) : (b)) +#endif + +/* + * INPUT Subsys interface + */ + +static void stmvl53l1_input_push_data(struct stmvl53l1_data *data); + +/* + * Mutex to handle device id add/removal + */ +static DEFINE_MUTEX(dev_table_mutex); + +/** + * in-used device LUT + * we need this as the message reception from netlink message can't + * associate directly to a device instance that is as we look up id + * to device data structure + */ +struct stmvl53l1_data *stmvl53l1_dev_table[STMVL53L1_CFG_MAX_DEV]; + +/** + * Misc device device operations + */ +static const struct file_operations stmvl53l1_ranging_fops = { + .owner = THIS_MODULE, + .unlocked_ioctl = stmvl53l1_ioctl, + .open = stmvl53l1_open, + .release = stmvl53l1_release, + /* .flush = stmvl53l0_flush, */ +}; + +static int store_last_error(struct stmvl53l1_data *data, int rc) +{ + data->last_error = rc; + + return -EIO; +} + +static int allocate_dev_id(void) +{ + int i; + + mutex_lock(&dev_table_mutex); + + for (i = 0; i < STMVL53L1_CFG_MAX_DEV; i++) + if (!stmvl53l1_dev_table[i]) + break; + i = i < STMVL53L1_CFG_MAX_DEV ? i : -1; + + mutex_unlock(&dev_table_mutex); + + return i; +} + +static void deallocate_dev_id(int id) +{ + mutex_lock(&dev_table_mutex); + + stmvl53l1_dev_table[id] = NULL; + + mutex_unlock(&dev_table_mutex); +} + +/* helpers to manage reader list for blockint ioctl */ +/* call them with lock */ +static void empty_and_free_list(struct list_head *head) +{ + struct stmvl53l1_waiters *waiter; + struct stmvl53l1_waiters *tmp; + + list_for_each_entry_safe(waiter, tmp, head, list) { + list_del(&waiter->list); + kfree(waiter); + } +} + +static int add_reader(pid_t pid, struct list_head *head) +{ + struct stmvl53l1_waiters *new_waiter; + + new_waiter = kmalloc(sizeof(struct stmvl53l1_waiters), GFP_KERNEL); + if (!new_waiter) + return -ENOMEM; + new_waiter->pid = pid; + list_add(&new_waiter->list, head); + + return 0; +} + +static bool is_pid_in_list(pid_t pid, struct list_head *head) +{ + struct stmvl53l1_waiters *waiter; + + list_for_each_entry(waiter, head, list) + if (waiter->pid == pid) + return true; + + return false; +} + +static void wake_up_data_waiters(struct stmvl53l1_data *data) +{ + empty_and_free_list(&data->simple_data_reader_list); + empty_and_free_list(&data->mz_data_reader_list); + wake_up(&data->waiter_for_data); +} + +static void stmvl53l1_insert_flush_events_lock(struct stmvl53l1_data *data) +{ + while (data->flush_todo_counter) { + data->flushCount++; + input_report_abs(data->input_dev_ps, ABS_GAS, data->flushCount); + input_sync(data->input_dev_ps); + vl53l1_dbgmsg("Sensor HAL Flush Count = %u\n", + data->flushCount); + data->flush_todo_counter--; + } +} + +static int reset_release(struct stmvl53l1_data *data) +{ + int rc; +#ifdef USE_CAMERA_CCI + struct camera_cci_transfer ccit; +#endif + + if (!data->reset_state) + return 0; +#ifdef USE_CAMERA_CCI + memset(&ccit,0,sizeof(ccit)); + ccit.cmd = CAMERA_CCI_INIT; + cam_cci_control_interface(&ccit); +#endif + + rc = stmvl53l1_module_func_tbl.reset_release(data->client_object); + if (rc){ + vl53l1_errmsg("reset release fail rc=%d try to release cci\n", rc); +#ifdef USE_CAMERA_CCI + memset(&ccit,0,sizeof(ccit)); + ccit.cmd = CAMERA_CCI_RELEASE; + cam_cci_control_interface(&ccit); +#endif + }else + data->reset_state = 0; + + return rc; +} + +static int reset_hold(struct stmvl53l1_data *data) +{ + int rc; +#ifdef USE_CAMERA_CCI + struct camera_cci_transfer ccit; +#endif + if (data->reset_state) + return 0; + + if (data->force_device_on_en) + return 0; + + rc = stmvl53l1_module_func_tbl.reset_hold(data->client_object); + if (!rc) + data->reset_state = 1; +#ifdef USE_CAMERA_CCI + memset(&ccit,0,sizeof(ccit)); + ccit.cmd = CAMERA_CCI_RELEASE; + cam_cci_control_interface(&ccit); +#endif + + return rc; +} + +#ifdef DEBUG_TIME_LOG +static void stmvl53l0_DebugTimeGet(struct timeval *ptv) +{ + do_gettimeofday(ptv); +} + +#endif + +/** + * + * @param pstart_tv time val starting point + * @param pstop_tv time val end point + * @return time dif in usec + */ +long stmvl53l1_tv_dif(struct timeval *pstart_tv, struct timeval *pstop_tv) +{ + long total_sec, total_usec; + + total_sec = pstop_tv->tv_sec - pstart_tv->tv_sec; + total_usec = (pstop_tv->tv_usec - pstart_tv->tv_usec); + + return total_sec*1000000+total_usec; +} + +#if STMVL53L1_CFG_ROI_DEBUG +static void dump_roi(VL53L1_UserRoi_t *rois, uint32_t n) +{ + uint32_t i; + + vl53l1_dbgmsg("roi dump %d roi:\n", n); + for (i = 0; i < n ; i++) { + vl53l1_dbgmsg("ROI#%02d %2d %2d %2d %2d\n", (int)i, + (int)rois[i].TopLeftX, (int)rois[i].TopLeftY, + (int)rois[i].BotRightX, (int)rois[i].BotRightY); + } +} +#else +# define dump_roi(...) (void)0 +#endif + +static int setup_tunings(struct stmvl53l1_data *data) +{ + int rc = 0; + int i, size; + size = (int)ARRAY_SIZE(tunings); + if (size > 0) { + for (i = 0; i < size; i++) { + rc = VL53L1_SetTuningParameter(&data->stdev, tunings[i][0], + tunings[i][1]); + if (rc) { + rc = store_last_error(data, rc); + break; + } + } + } + return rc; +} + +/** + * + * @param data device data + * @return non 0 if current "preset mode" is a multi zone one + */ +static int is_mz_mode(struct stmvl53l1_data *data) +{ + return data->preset_mode == VL53L1_PRESETMODE_RANGING || + data->preset_mode == VL53L1_PRESETMODE_MULTIZONES_SCANNING; +} + +static void kill_mz_data(VL53L1_MultiRangingData_t *pdata) +{ + int i; + + memset(pdata, 0, sizeof(*pdata)); + for (i = 0; i < VL53L1_MAX_RANGE_RESULTS; i++) + pdata->RangeData[i].RangeStatus = VL53L1_RANGESTATUS_NONE; + pdata->RoiStatus = VL53L1_ROISTATUS_NOT_VALID; +} + +static void stmvl53l1_setup_auto_config(struct stmvl53l1_data *data) +{ + /* default config is detect object below 300mm with 1s period */ + data->auto_pollingTimeInMs = 1000; + data->auto_config.DetectionMode = VL53L1_DETECTION_DISTANCE_ONLY; + data->auto_config.IntrNoTarget = 0; + data->auto_config.Distance.CrossMode = VL53L1_THRESHOLD_CROSSED_LOW; + data->auto_config.Distance.High = 1000; + data->auto_config.Distance.Low = 300; + data->auto_config.Rate.CrossMode = VL53L1_THRESHOLD_CROSSED_LOW; + data->auto_config.Rate.High = 0; + data->auto_config.Rate.Low = 0; +} + +static uint32_t stmvl53l1_compute_hash(VL53L1_RoiConfig_t *roi_cfg) +{ + return jhash(roi_cfg->UserRois, + roi_cfg->NumberOfRoi * sizeof(VL53L1_UserRoi_t), + roi_cfg->NumberOfRoi); +} + +static int stmvl53l1_check_calibration_id(struct stmvl53l1_data *data) +{ + uint32_t roi_id; + int rc; + + if (data->offset_correction_mode != VL53L1_OFFSETCORRECTIONMODE_PERZONE) + return 0; + if (data->current_roi_id == 0) + return 0; + + roi_id = stmvl53l1_compute_hash(&data->roi_cfg); + rc = roi_id == data->current_roi_id ? 0 : -EINVAL; + + if (rc) + vl53l1_errmsg( + "Mismatch in zone calibration data 0x%08x != 0x%08x", + roi_id, data->current_roi_id); + + return rc; +} + +/** + * send params to sensor + * + * @warning must be used if only stopped + * @param data device data + * @return 0 on sucess + */ +static int stmvl53l1_sendparams(struct stmvl53l1_data *data) +{ + int rc; + + /* activated stored or last request defined mode */ + rc = VL53L1_SetPresetMode(&data->stdev, data->preset_mode); + if (rc) { + vl53l1_errmsg("VL53L1_SetPresetMode %d fail %d", + data->preset_mode, rc); + rc = store_last_error(data, rc); + goto done; + } + + rc = VL53L1_SetXTalkCompensationEnable(&data->stdev, + data->crosstalk_enable); + if (rc) { + vl53l1_errmsg("VL53L1_SetXTalkCompensationEnable %d fail %d", + data->crosstalk_enable, rc); + rc = store_last_error(data, rc); + goto done; + } + + /* apply distance mode only in lite and standard ranging */ + rc = VL53L1_SetDistanceMode(&data->stdev, data->distance_mode); + if (rc) { + vl53l1_errmsg("VL53L1_SetDistanceMode %d fail %d", + data->distance_mode, rc); + rc = store_last_error(data, rc); + goto done; + } + + /* apply timing budget */ + rc = VL53L1_SetMeasurementTimingBudgetMicroSeconds(&data->stdev, + data->timing_budget); + if (rc) { + vl53l1_errmsg("SetTimingBudget %d fail %d", + data->timing_budget, rc); + rc = store_last_error(data, rc); + goto done; + } + vl53l1_dbgmsg("timing budget @%d\n", data->timing_budget); + + /* apply offset correction mode */ + rc = VL53L1_SetOffsetCorrectionMode(&data->stdev, + data->offset_correction_mode); + if (rc) { + vl53l1_errmsg("offset correction mode %d fail %d", + data->offset_correction_mode, rc); + rc = store_last_error(data, rc); + goto done; + } + vl53l1_dbgmsg("offset correction mode @%d\n", + data->offset_correction_mode); + + /* check zone calibration vs roi */ + rc = stmvl53l1_check_calibration_id(data); + if (rc) + goto done; + + /* apply Dmax reflectance */ + rc = VL53L1_SetDmaxReflectance(&data->stdev, data->dmax_reflectance); + if (rc) { + vl53l1_errmsg("dmax relectance %d fail %d", + data->dmax_reflectance, rc); + rc = store_last_error(data, rc); + goto done; + } + vl53l1_dbgmsg("dmax reflectance @%d\n", data->dmax_reflectance); + + /* apply Dmax mode */ + rc = VL53L1_SetDmaxMode(&data->stdev, data->dmax_mode); + if (rc) { + vl53l1_errmsg("dmax mode %d fail %d", data->dmax_mode, rc); + rc = store_last_error(data, rc); + goto done; + } + vl53l1_dbgmsg("dmax mode @%d\n", data->dmax_mode); + + /* apply smudge correction enable */ + rc = VL53L1_SmudgeCorrectionEnable(&data->stdev, + data->smudge_correction_mode); + if (rc) { + vl53l1_errmsg("smudge correction mode %d fail %d", + data->smudge_correction_mode, rc); + rc = store_last_error(data, rc); + goto done; + } + vl53l1_dbgmsg("smudge correction mode @%d\n", + data->smudge_correction_mode); + + /* apply roi if any set */ + //songyt add default range roi + if(data->preset_mode == VL53L1_PRESETMODE_MULTIZONES_SCANNING + /*|| data->preset_mode == VL53L1_PRESETMODE_RANGING*/){ + data->roi_cfg.NumberOfRoi = 4; + data->roi_cfg.UserRois[0].TopLeftX = 0; + data->roi_cfg.UserRois[0].TopLeftY = 15; + data->roi_cfg.UserRois[0].BotRightX = 7; + data->roi_cfg.UserRois[0].BotRightY = 8; + + data->roi_cfg.UserRois[1].TopLeftX = 8; + data->roi_cfg.UserRois[1].TopLeftY = 15; + data->roi_cfg.UserRois[1].BotRightX = 15; + data->roi_cfg.UserRois[1].BotRightY = 8; + + data->roi_cfg.UserRois[2].TopLeftX = 0; + data->roi_cfg.UserRois[2].TopLeftY = 7; + data->roi_cfg.UserRois[2].BotRightX = 7; + data->roi_cfg.UserRois[2].BotRightY = 0; + + data->roi_cfg.UserRois[3].TopLeftX = 8; + data->roi_cfg.UserRois[3].TopLeftY = 7; + data->roi_cfg.UserRois[3].BotRightX = 15; + data->roi_cfg.UserRois[3].BotRightY = 0; + }else{ + data->roi_cfg.NumberOfRoi = 0; + } + //end + dump_roi(data->roi_cfg.UserRois, data->roi_cfg.NumberOfRoi); + if (data->roi_cfg.NumberOfRoi) { + rc = VL53L1_SetROI(&data->stdev, &data->roi_cfg); + if (rc) { + vl53l1_errmsg("VL53L1_SetROI fail %d\n", rc); + rc = store_last_error(data, rc); + goto done; + } + vl53l1_dbgmsg("#%d custom ROI set status\n", + data->roi_cfg.NumberOfRoi); + } else { + vl53l1_dbgmsg("using default ROI\n"); + } + + /* set autonomous mode configuration */ + if ((data->preset_mode == VL53L1_PRESETMODE_AUTONOMOUS) || + (data->preset_mode == VL53L1_PRESETMODE_LOWPOWER_AUTONOMOUS)) { + rc = VL53L1_SetInterMeasurementPeriodMilliSeconds(&data->stdev, + data->auto_pollingTimeInMs); + if (rc) { + vl53l1_errmsg("Fail to set auto period %d\n", rc); + rc = store_last_error(data, rc); + goto done; + } + rc = VL53L1_SetThresholdConfig(&data->stdev, + &data->auto_config); + if (rc) { + vl53l1_errmsg("Fail to set auto config %d\n", rc); + rc = store_last_error(data, rc); + goto done; + } + } + +done: + + return rc; +} + +/** + * start sensor + * + * @warning must be used if only stopped + * @param data device data + * @return 0 on sucess + */ +static int stmvl53l1_start(struct stmvl53l1_data *data) +{ + int rc; + + data->is_first_irq = true; + data->is_data_valid = false; + data->is_xtalk_value_changed = false; + stmvl53l1_module_func_tbl.power_up(data->client_object); + rc = reset_release(data); + if (rc) + goto done; + + /* full setup when out of reset or power up */ + rc = VL53L1_StaticInit(&data->stdev); + if (rc) { + vl53l1_errmsg("VL53L1_StaticInit @%d fail %d\n", + __LINE__, rc); + rc = store_last_error(data, rc); + goto done; + } + + rc = stmvl53l1_sendparams(data); + if (rc) + goto done; + + /* init the timing */ + do_gettimeofday(&data->start_tv); + data->meas.start_tv = data->start_tv; + /* init the ranging data => kill the previous ranging mz data */ + kill_mz_data(&data->meas.multi_range_data); + /* kill the single ranging data */ + memset(&data->meas.single_range_data, 0, + sizeof(VL53L1_RangingMeasurementData_t)); + + data->allow_hidden_start_stop = false; + /* kick off ranging */ + rc = VL53L1_StartMeasurement(&data->stdev); + if (rc) { + vl53l1_errmsg("VL53L1_StartMeasurement @%d fail %d", + __LINE__, rc); + rc = store_last_error(data, rc); + goto done; + } + + data->meas.cnt = 0; + data->meas.err_cnt = 0; + data->meas.err_tot = 0; + data->meas.poll_cnt = 0; + data->meas.intr = 0; + data->enable_sensor = 1; + if (data->poll_mode) { + /* kick off the periodical polling work */ + schedule_delayed_work(&data->dwork, + msecs_to_jiffies(data->poll_delay_ms)); + } +done: + data->is_first_start_done = true; + + return rc; +} + +/** + * stop sensor + * + * work lock must be held + * @warning to be used if only started! + */ +static int stmvl53l1_stop(struct stmvl53l1_data *data) +{ + int rc; + + rc = VL53L1_StopMeasurement(&data->stdev); + if (rc) { + vl53l1_errmsg("VL53L1_StopMeasurement @%d fail %d", + __LINE__, rc); + rc = store_last_error(data, rc); + } + /* put device under reset */ + /* do we ask explicit intr stop or just use stop */ + reset_hold(data); + + data->enable_sensor = 0; + if (data->poll_mode) { + /* cancel periodical polling work */ + cancel_delayed_work(&data->dwork); + } + + /* if we are in ipp waiting mode then abort it */ + stmvl53l1_ipp_stop(data); + /* wake up all waiters */ + /* they will receive -ENODEV error */ + wake_up_data_waiters(data); + stmvl53l1_module_func_tbl.power_down(data->client_object); + + return rc; +} + +/* + * SysFS support + */ +static ssize_t stmvl53l1_show_enable_ps_sensor(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct stmvl53l1_data *data = dev_get_drvdata(dev); + + return snprintf(buf, 5, "%d\n", data->enable_sensor); +} + +static ssize_t stmvl53l1_store_enable_ps_sensor(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) +{ + struct stmvl53l1_data *data = dev_get_drvdata(dev); + int rc = 0; + unsigned long val; + + rc = kstrtoul(buf, 10, &val); + if (rc) { + vl53l1_errmsg("enable sensor syntax in %s\n", buf); + return -EINVAL; + } + if (val == 1) { + rc = ctrl_start(data); + } else if (val == 0) { + rc = ctrl_stop(data); + } else { + //TODO: Remove this workaround after investigation + //see Codex - 479397 for details + vl53l1_dbgmsg("Unclog Input sub-system\n"); + /* Unclog the input device sub-system */ + input_report_abs(data->input_dev_ps, ABS_HAT0X, -1); + input_report_abs(data->input_dev_ps, ABS_HAT0Y, -1); + input_report_abs(data->input_dev_ps, ABS_HAT1X, -1); + input_report_abs(data->input_dev_ps, ABS_HAT1Y, -1); + input_report_abs(data->input_dev_ps, ABS_HAT2X, -1); + input_report_abs(data->input_dev_ps, ABS_HAT2Y, -1); + input_report_abs(data->input_dev_ps, ABS_HAT3X, -1); + input_report_abs(data->input_dev_ps, ABS_HAT3Y, -1); + input_report_abs(data->input_dev_ps, ABS_WHEEL, -1); + input_report_abs(data->input_dev_ps, ABS_BRAKE, -1); + input_report_abs(data->input_dev_ps, ABS_GAS, -1); + input_report_abs(data->input_dev_ps, ABS_TILT_X, -1); + input_report_abs(data->input_dev_ps, ABS_TILT_Y, -1); + input_report_abs(data->input_dev_ps, ABS_TOOL_WIDTH, -1); + input_report_abs(data->input_dev_ps, ABS_DISTANCE, -1); + input_report_abs(data->input_dev_ps, ABS_THROTTLE, -1); + input_report_abs(data->input_dev_ps, ABS_RUDDER, -1); + input_report_abs(data->input_dev_ps, ABS_MISC, -1); + input_report_abs(data->input_dev_ps, ABS_VOLUME, + -1); + input_sync(data->input_dev_ps); + vl53l1_dbgmsg("Unclog the input sub-system\n"); + rc = 0; + } + + vl53l1_dbgmsg("End\n"); + + return rc ? rc : count; +} + +/** + * sysfs attribute "enable_ps_sensor" [rd/wr] + * + * @li read show the current enable state + * @li write set the new state value "0" put sensor off "1" put it on + * + * @return 0 on success , EINVAL if fail to start + * + * @warning their's no check and assume exclusive usage of sysfs and ioctl\n + * Sensor will be put on/off disregard of any setup done by the ioctl channel. + * + * @ingroup sysfs_attrib + */ +static DEVICE_ATTR(enable_ps_sensor, 0664/*S_IWUGO | S_IRUGO*/, + stmvl53l1_show_enable_ps_sensor, + stmvl53l1_store_enable_ps_sensor); + +static int stmvl53l1_set_poll_delay_ms(struct stmvl53l1_data *data, int delay) +{ + int rc = 0; + + if (delay <= 0) + rc = -EINVAL; + else + data->poll_delay_ms = delay; + + return rc; +} + +IMPLEMENT_PARAMETER_INTEGER(poll_delay_ms, "poll delay ms") + +/** + * sysfs attribute "poll_delay_ms" [rd/wr] + * + * @li read show the current polling delay in millisecond + * @li write set the new polling delay in millisecond + * + * @note apply only if device is in polling mode\n + * for best performances (minimal delay and cpu load ) set it to the device + * period operating period +1 millis + + * @ingroup sysfs_attrib + */ +static DEVICE_ATTR(set_delay_ms, 0660/*S_IWUGO | S_IRUGO*/, + stmvl53l1_show_poll_delay_ms, + stmvl53l1_store_poll_delay_ms); + +/* Timing Budget */ +static int stmvl53l1_set_timing_budget(struct stmvl53l1_data *data, int timing) +{ + int rc = 0; + + if (timing <= 0) { + vl53l1_errmsg("invalid timing valid %d\n", timing); + rc = -EINVAL; + } else if (data->enable_sensor) { + rc = VL53L1_SetMeasurementTimingBudgetMicroSeconds(&data->stdev, + timing); + if (rc) { + vl53l1_errmsg("SetTimingBudget %d fail %d", timing, rc); + rc = store_last_error(data, rc); + } else + data->timing_budget = timing; + } else + data->timing_budget = timing; + + return rc; +} + +IMPLEMENT_PARAMETER_INTEGER(timing_budget, "timing budget") + +/** + * sysfs "timing_budget" [rd/wr] + * + * set or get the ranging timing budget in microsecond + * + * @ingroup sysfs_attrib + */ +static DEVICE_ATTR(timing_budget, 0660/*S_IWUGO | S_IRUGO*/, + stmvl53l1_show_timing_budget, + stmvl53l1_store_timing_budget); + + +static ssize_t stmvl53l1_show_roi(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct stmvl53l1_data *data = dev_get_drvdata(dev); + int i; + int n; + + + mutex_lock(&data->work_mutex); + if (data->roi_cfg.NumberOfRoi == 0) { + /* none define by user */ + /* we could get what stored but may not even be default */ + n = scnprintf(buf, PAGE_SIZE, "device default\n"); + } else { + for (i = 0, n = 0; i < data->roi_cfg.NumberOfRoi; i++) { + n += scnprintf(buf+n, PAGE_SIZE-n, "%d %d %d %d%c", + data->roi_cfg.UserRois[i].TopLeftX, + data->roi_cfg.UserRois[i].TopLeftY, + data->roi_cfg.UserRois[i].BotRightX, + data->roi_cfg.UserRois[i].BotRightY, + i == data->roi_cfg.NumberOfRoi-1 ? + '\n' : ','); + } + } + mutex_unlock(&data->work_mutex); + return n; +} + + +static const char str_roi_ranging[] = "ERROR can't set roi while ranging\n"; + +static ssize_t stmvl53l1_store_roi(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct stmvl53l1_data *data = dev_get_drvdata(dev); + VL53L1_UserRoi_t rois[VL53L1_MAX_USER_ZONES]; + int rc; + + mutex_lock(&data->work_mutex); + if (data->enable_sensor) { + vl53l1_errmsg(" cant set roi now\n"); + rc = -EBUSY; + } else { + int n, n_roi = 0; + const char *pc = buf; + int tlx, tly, brx, bry; + + while (n_roi < VL53L1_MAX_USER_ZONES && pc != NULL + && *pc != 0 && *pc != '\n') { + n = sscanf(pc, "%d %d %d %d", &tlx, &tly, &brx, &bry); + if (n == 4) { + rois[n_roi].TopLeftX = tlx; + rois[n_roi].TopLeftY = tly; + rois[n_roi].BotRightX = brx; + rois[n_roi].BotRightY = bry; + n_roi++; + } else { + vl53l1_errmsg( +"wrong roi #%d syntax around %s of %s", n_roi, pc, buf); + n_roi = -1; + break; + } + /* find next roi separator */ + pc = strchr(pc, ','); + if (pc) + pc++; + } + /*if any set them */ + if (n_roi >= 0) { + if (n_roi) + memcpy(data->roi_cfg.UserRois, rois, + n_roi*sizeof(rois[0])); + data->roi_cfg.NumberOfRoi = n_roi; + dump_roi(data->roi_cfg.UserRois, + data->roi_cfg.NumberOfRoi); + rc = count; + } else { + rc = -EINVAL; + } + } + mutex_unlock(&data->work_mutex); + vl53l1_dbgmsg("ret %d count %d\n", rc, (int)count); + + return rc; +} + +/** + * sysfs attribute "roi" [rd/wr] + * + * @li read show the current user customized roi setting + * @li write set user custom roi, it can only be done while not ranging. + * + * syntax for set input roi + * @li "[tlx tly brx bry,]\n" repeat n time require will set the n roi + * @li "\n" will reset + * + * @warning roi coordinate is not image x,y(down) but euclidian x,y(up) + * + * @warning roi validity is only check at next range start + * @warning user is responsible to set appropriate number an roi before each + * mode change + * @note roi can be return to default by setting none "" + * + *@code + * >#to set 2x roi + * >echo "0 15 15 0, 0 8 8 0" > /sys/class/input6/roi + * >echo $? + * 0 + * >cat /sys/class/input6/roi + * "0 15 15 0,0 8 8 0" + * #to cancel user define roi" + * >echo "" > /sys/class/input1/roi + * >echo $? + * 0 + * >echo "1" > /sys/class/input6/enable_ps_senspor + * #try to set roi while ranging + * >echo "0 15 15 0, 0 8 8 0" > /sys/class/input6/roi + * [58451.912109] stmvl53l1_store_roi: cant set roi now + * >echo $? + * 1 + *@endcode + * @ingroup sysfs_attrib + */ +static DEVICE_ATTR(roi, 0660/*S_IWUGO | S_IRUGO*/, + stmvl53l1_show_roi, + stmvl53l1_store_roi); + + +static int stmvl53l1_set_preset_mode(struct stmvl53l1_data *data, int mode) +{ + int rc = 0; + + if (data->enable_sensor) { + vl53l1_errmsg("can't change mode while ranging\n"); + rc = -EBUSY; + } else { + switch (mode) { + case VL53L1_PRESETMODE_RANGING: + case VL53L1_PRESETMODE_MULTIZONES_SCANNING: + case VL53L1_PRESETMODE_LITE_RANGING: + case VL53L1_PRESETMODE_AUTONOMOUS: + case VL53L1_PRESETMODE_LOWPOWER_AUTONOMOUS: + data->preset_mode = mode; + vl53l1_dbgmsg("preset mode %d\n", mode); + break; + default: + vl53l1_errmsg("invalid mode %d\n", mode); + rc = -EINVAL; + break; + } + } + + return rc; +} + +IMPLEMENT_PARAMETER_INTEGER(preset_mode, "preset mode") + +/** + * sysfs attribute "mode " [rd/wr] + * + * set the mode value can only be used while: not ranging + * @li 1 @a VL53L1_PRESETMODE_RANGING default ranging + * @li 2 @a VL53L1_PRESETMODE_MULTIZONES_SCANNING multiple zone + * @li 3 @a VL53L1_PRESETMODE_AUTONOMOUS autonomous mode + * @li 4 @a VL53L1_PRESETMODE_LOWPOWER_AUTONOMOUS low Power autonomous mode + * @li 5 @a VL53L1_PRESETMODE_LITE_RANGING low mips ranging mode + * + * @ingroup sysfs_attrib + */ +static DEVICE_ATTR(mode, 0660/*S_IWUGO | S_IRUGO*/, + stmvl53l1_show_preset_mode, + stmvl53l1_store_preset_mode); + +static int stmvl53l1_set_distance_mode(struct stmvl53l1_data *data, + int distance_mode) +{ + int rc = 0; + + if (data->enable_sensor) { + vl53l1_errmsg("can't change distance mode while ranging\n"); + rc = -EBUSY; + } else { + switch (distance_mode) { + case VL53L1_DISTANCEMODE_SHORT: + case VL53L1_DISTANCEMODE_MEDIUM: + case VL53L1_DISTANCEMODE_LONG: + data->distance_mode = distance_mode; + vl53l1_dbgmsg("distance mode %d\n",distance_mode); + break; + default: + vl53l1_errmsg("invalid distance mode %d\n", + distance_mode); + rc = -EINVAL; + break; + } + } + + return rc; +} + +IMPLEMENT_PARAMETER_INTEGER(distance_mode, "distance mode") + +/** + * sysfs attribute " distance mode" [rd/wr] + * + * set the distance mode value can only be used while: not ranging + * @li 1 @a VL53L1_DISTANCEMODE_SHORT + * @li 2 @a VL53L1_DISTANCEMODE_MEDIUM + * @li 3 @a VL53L1_DISTANCEMODE_LONG + * + * @ingroup sysfs_attrib + */ +static DEVICE_ATTR(distance_mode, 0660/*S_IWUGO | S_IRUGO*/, + stmvl53l1_show_distance_mode, + stmvl53l1_store_distance_mode); + +static int stmvl53l1_set_crosstalk_enable(struct stmvl53l1_data *data, + int crosstalk_enable) +{ + int rc = 0; + + if (data->enable_sensor) { + vl53l1_errmsg("can't change crosstalk enable while ranging\n"); + rc = -EBUSY; + } else if (crosstalk_enable == 0 || crosstalk_enable == 1) { + data->crosstalk_enable = crosstalk_enable; + } else { + vl53l1_errmsg("invalid crosstalk enable %d\n", + crosstalk_enable); + rc = -EINVAL; + } + + return rc; +} + +IMPLEMENT_PARAMETER_INTEGER(crosstalk_enable, "crosstalk enable") + +/** + * sysfs attribute " crosstalk enable" [rd/wr] + * + * control if crosstalk compensation is eanble or not + * @li 0 disable crosstalk compensation + * @li 1 enable crosstalk compensation + * + * @ingroup sysfs_attrib + */ +static DEVICE_ATTR(crosstalk_enable, 0660/*S_IWUGO | S_IRUGO*/, + stmvl53l1_show_crosstalk_enable, + stmvl53l1_store_crosstalk_enable); + +static int stmvl53l1_set_output_mode(struct stmvl53l1_data *data, + int output_mode) +{ + int rc = 0; + + if (data->enable_sensor) { + vl53l1_errmsg("can't change output mode while ranging\n"); + rc = -EBUSY; + } else { + switch (output_mode) { + case VL53L1_OUTPUTMODE_NEAREST: + case VL53L1_OUTPUTMODE_STRONGEST: + data->output_mode = output_mode; + vl53l1_dbgmsg("output mode %d\n", output_mode); + break; + default: + vl53l1_errmsg("invalid output mode %d\n", output_mode); + rc = -EINVAL; + break; + } + } + + return rc; +} + +IMPLEMENT_PARAMETER_INTEGER(output_mode, "output mode") + +/** + * sysfs attribute " output mode" [rd/wr] + * + * set the output mode value can only be used while: not ranging + * @li 1 @a VL53L1_OUTPUTMODE_NEAREST + * @li 2 @a VL53L1_OUTPUTMODE_STRONGEST + * + * @ingroup sysfs_attrib + */ +static DEVICE_ATTR(output_mode, 0660/*S_IWUGO | S_IRUGO*/, + stmvl53l1_show_output_mode, + stmvl53l1_store_output_mode); + + +static int stmvl53l1_set_force_device_on_en(struct stmvl53l1_data *data, + int force_device_on_en) +{ + int rc; + + if (force_device_on_en != 0 && force_device_on_en != 1) { + vl53l1_errmsg("invalid force_device_on_en mode %d\n", + force_device_on_en); + return -EINVAL; + } + + data->force_device_on_en = force_device_on_en; + + /* don't update reset if sensor is enable */ + if (data->enable_sensor) + return 0; + + /* ok update reset according force_device_on_en value */ + if (force_device_on_en){ + rc = reset_release(data); + vl53l1_dbgmsg("force_device_on_en.\n"); + }else{ + vl53l1_dbgmsg("force_device_on_en disable.\n"); + rc = reset_hold(data); + } + + return rc; +} + +IMPLEMENT_PARAMETER_INTEGER(force_device_on_en, "force device on enable") + +/** + * sysfs attribute " force_device_on_enable" [rd/wr] + * + * Control if device is put under reset when stopped. + * @li 0 feature is disable. Device is put under reset when stopped. + * @li 1 feature is enable. Device is not put under reset when stopped. + * + * @ingroup sysfs_attrib + */ +static DEVICE_ATTR(force_device_on_enable, 0660/*S_IWUGO | S_IRUGO*/, + stmvl53l1_show_force_device_on_en, + stmvl53l1_store_force_device_on_en); + +static int stmvl53l1_set_offset_correction_mode(struct stmvl53l1_data *data, + int offset_correction_mode) +{ + int rc = 0; + + if (data->enable_sensor) { + vl53l1_errmsg( + "can't change offset correction mode while ranging\n"); + rc = -EBUSY; + } else { + switch (offset_correction_mode) { + case VL53L1_OFFSETCORRECTIONMODE_STANDARD: + case VL53L1_OFFSETCORRECTIONMODE_PERZONE: + data->offset_correction_mode = offset_correction_mode; + break; + default: + vl53l1_errmsg("invalid offset correction mode %d\n", + offset_correction_mode); + rc = -EINVAL; + break; + } + } + + return rc; +} + +IMPLEMENT_PARAMETER_INTEGER(offset_correction_mode, "offset correction mode") + +/** + * sysfs attribute " offset_correction_mode" [rd/wr] + * + * Control which offset correction is apply on result. can only be used + * while: not ranging + * @li 1 @a VL53L1_OFFSETCORRECTIONMODE_STANDARD + * @li 2 @a VL53L1_OFFSETCORRECTIONMODE_PERZONE + * + * @ingroup sysfs_attrib + */ +static DEVICE_ATTR(offset_correction_mode, 0660/*S_IWUGO | S_IRUGO*/, + stmvl53l1_show_offset_correction_mode, + stmvl53l1_store_offset_correction_mode); + +static ssize_t stmvl53l1_do_flush(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct stmvl53l1_data *data = dev_get_drvdata(dev); + + mutex_lock(&data->work_mutex); + + data->flush_todo_counter++; + if (data->enable_sensor == 0) + stmvl53l1_insert_flush_events_lock(data); + + mutex_unlock(&data->work_mutex); + + return count; +} + +static DEVICE_ATTR(do_flush, 0660/*S_IWUGO | S_IRUGO*/, + NULL, + stmvl53l1_do_flush); + +static ssize_t stmvl53l1_show_enable_debug(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return scnprintf(buf, PAGE_SIZE, "%d\n", stmvl53l1_enable_debug); +} + +static ssize_t stmvl53l1_store_enable_debug(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int enable_debug; + int rc = 0; + + if (kstrtoint(buf, 0, &enable_debug)) { + vl53l1_errmsg("invalid syntax in %s", buf); + rc = -EINVAL; + } else + stmvl53l1_enable_debug = enable_debug; + + return rc ? rc : count; +} + +/** + * sysfs attribute " debug enable" [rd/wr] + * + * dynamic control of vl53l1_dbgmsg messages. Note that in any case your code + * must be enable with DEBUG in stmvl53l1.h at compile time. + * @li 0 disable vl53l1_dbgmsg messages + * @li 1 enable vl53l1_dbgmsg messages + * + * @ingroup sysfs_attrib + */ +static DEVICE_ATTR(enable_debug, 0660/*S_IWUGO | S_IRUGO*/, + stmvl53l1_show_enable_debug, + stmvl53l1_store_enable_debug); + +static ssize_t display_FixPoint1616(char *buf, size_t size, FixPoint1616_t fix) +{ + uint32_t msb = fix >> 16; + uint32_t lsb = fix & 0xffff; + + lsb = (lsb * 1000000ULL + 32768) / 65536; + + return scnprintf(buf, size, "%d.%06d", msb, (uint32_t) lsb); +} + +static ssize_t stmvl53l1_show_autonomous_config(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct stmvl53l1_data *data = dev_get_drvdata(dev); + ssize_t res = 0; + + res += scnprintf(&buf[res], PAGE_SIZE, "%d %d %d %d %d %d %d ", + data->auto_pollingTimeInMs, + data->auto_config.DetectionMode, + data->auto_config.IntrNoTarget, + data->auto_config.Distance.CrossMode, + data->auto_config.Distance.High, + data->auto_config.Distance.Low, + data->auto_config.Rate.CrossMode); + + res += display_FixPoint1616(&buf[res], PAGE_SIZE - res, + data->auto_config.Rate.High); + + res += scnprintf(&buf[res], PAGE_SIZE - res, " "); + + res += display_FixPoint1616(&buf[res], PAGE_SIZE - res, + data->auto_config.Rate.Low); + + res += scnprintf(&buf[res], PAGE_SIZE - res, "\n"); + + return res; +} + +static const char *parse_integer(const char *buf, int *res) +{ + int rc; + + while (*buf == ' ') + buf++; + rc = sscanf(buf, "%d ", res); + if (!rc) + return NULL; + + return strchr(buf, ' '); +} + +static bool is_float_format(const char *buf, bool is_last) +{ + char *dot = strchr(buf, '.'); + char *space_or_eos = strchr(buf, is_last ? '\0' : ' '); + + if (!space_or_eos) + return !!dot; + if (!dot) + return false; + + return dot < space_or_eos ? true : false; +} + +static int parse_FixPoint16x16_lsb(const char *lsb_char) +{ + int lsb = 0; + int digit_nb = 0; + + /* parse at most 6 digits */ + lsb_char++; + while (isdigit(*lsb_char) && digit_nb < 6) { + lsb = lsb * 10 + (*lsb_char - '0'); + lsb_char++; + digit_nb++; + } + while (digit_nb++ < 6) + lsb = lsb * 10; + + return div64_s64(lsb * 65536ULL + 500000, 1000000); +} + +/* parse next fix point value and return a pointer to next blank or newline + * character according to is_last parameter. + * parse string must have digit for integer part (something like '.125' will + * return an error) or an error will be return. Only the first 6 digit of the + * decimal part will be parsed. + */ +static const char *parse_FixPoint16x16(const char *buf, FixPoint1616_t *res, + bool is_last) +{ + bool is_float; + int msb; + int lsb = 0; + int rc; + + while (*buf == ' ') + buf++; + is_float = is_float_format(buf, is_last); + + /* scan msb */ + rc = sscanf(buf, "%d ", &msb); + if (!rc) + return NULL; + /* then lsb if present */ + if (is_float) + lsb = parse_FixPoint16x16_lsb(strchr(buf, '.')); + *res = (msb << 16) + lsb; + + return strchr(buf, is_last ? '\0' : ' '); +} + +static ssize_t stmvl53l1_store_autonomous_config(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct stmvl53l1_data *data = dev_get_drvdata(dev); + int pollingTimeInMs, DetectionMode, IntrNoTarget; + int d_CrossMode, d_High, d_Low; + int r_CrossMode; + FixPoint1616_t r_High, r_Low; + const char *buf_ori = buf; + int rc; + + mutex_lock(&data->work_mutex); + + if (data->enable_sensor) + goto busy; + + buf = parse_integer(buf, &pollingTimeInMs); + if (!buf) + goto invalid; + buf = parse_integer(buf, &DetectionMode); + if (!buf) + goto invalid; + buf = parse_integer(buf, &IntrNoTarget); + if (!buf) + goto invalid; + buf = parse_integer(buf, &d_CrossMode); + if (!buf) + goto invalid; + buf = parse_integer(buf, &d_High); + if (!buf) + goto invalid; + buf = parse_integer(buf, &d_Low); + if (!buf) + goto invalid; + buf = parse_integer(buf, &r_CrossMode); + if (!buf) + goto invalid; + buf = parse_FixPoint16x16(buf, &r_High, false); + if (!buf) + goto invalid; + buf = parse_FixPoint16x16(buf, &r_Low, true); + if (!buf) + goto invalid; + + data->auto_pollingTimeInMs = pollingTimeInMs; + data->auto_config.DetectionMode = DetectionMode; + data->auto_config.IntrNoTarget = IntrNoTarget; + data->auto_config.Distance.CrossMode = d_CrossMode; + data->auto_config.Distance.High = d_High; + data->auto_config.Distance.Low = d_Low; + data->auto_config.Rate.CrossMode = r_CrossMode; + data->auto_config.Rate.High = r_High; + data->auto_config.Rate.Low = r_Low; + + mutex_unlock(&data->work_mutex); + + return count; + +busy: + vl53l1_errmsg("can't change config while ranging"); + rc = -EBUSY; + goto error; + +invalid: + vl53l1_errmsg("invalid syntax in %s", buf_ori); + rc = -EINVAL; + goto error; + +error: + mutex_unlock(&data->work_mutex); + + return rc; +} + +/** + * sysfs attribute " autonomous_config" [rd/wr] + * + * Will set/get autonomous configuration using sysfs. + * + * format is the following : + * + * + * + *@code + * > echo "1000 1 0 0 1000 300 0 2.2 1.001" > autonomous_config + *@endcode + * + * @ingroup sysfs_attrib + */ +static DEVICE_ATTR(autonomous_config, 0660/*S_IWUGO | S_IRUGO*/, + stmvl53l1_show_autonomous_config, + stmvl53l1_store_autonomous_config); + +static ssize_t stmvl53l1_show_last_error_config(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct stmvl53l1_data *data = dev_get_drvdata(dev); + + return scnprintf(buf, PAGE_SIZE, "%d\n", data->last_error); +} + +/** + * sysfs attribute " last_error" [rd] + * + * Will get last internal error using sysfs. + * + * @ingroup sysfs_attrib + */ +static DEVICE_ATTR(last_error, 0440/*S_IRUGO*/, + stmvl53l1_show_last_error_config, + NULL); + +static ssize_t stmvl53l1_show_optical_center_config(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct stmvl53l1_data *data = dev_get_drvdata(dev); + ssize_t res = 0; + + res += display_FixPoint1616(&buf[res], PAGE_SIZE - res, + data->optical_offset_x); + res += scnprintf(&buf[res], PAGE_SIZE - res, " "); + res += display_FixPoint1616(&buf[res], PAGE_SIZE - res, + data->optical_offset_y); + + res += scnprintf(&buf[res], PAGE_SIZE - res, "\n"); + + return res; +} + +/** + * sysfs attribute " optical_center" [rd] + * + * Will get optical_center using sysfs. + * + * @ingroup sysfs_attrib + */ +static DEVICE_ATTR(optical_center, 0440/*S_IRUGO*/, + stmvl53l1_show_optical_center_config, + NULL); + +static int stmvl53l1_set_dmax_reflectance(struct stmvl53l1_data *data, + int dmax_reflectance) +{ + int rc = 0; + + if (data->enable_sensor) { + vl53l1_errmsg( + "can't change dmax reflectance while ranging\n"); + rc = -EBUSY; + } else + data->dmax_reflectance = dmax_reflectance; + + return rc; +} + +static ssize_t stmvl53l1_show_dmax_reflectance(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct stmvl53l1_data *data = dev_get_drvdata(dev); + ssize_t res = 0; + + res += display_FixPoint1616(&buf[res], PAGE_SIZE - res, + data->dmax_reflectance); + + res += scnprintf(&buf[res], PAGE_SIZE - res, "\n"); + + return res; +} + +static ssize_t stmvl53l1_store_dmax_reflectance(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct stmvl53l1_data *data = dev_get_drvdata(dev); + FixPoint1616_t dmax_reflectance; + const char *buf_ori = buf; + int rc; + + mutex_lock(&data->work_mutex); + + buf = parse_FixPoint16x16(buf, &dmax_reflectance, true); + if (!buf) + goto invalid; + rc = stmvl53l1_set_dmax_reflectance(data, dmax_reflectance); + if (rc) + goto error; + + mutex_unlock(&data->work_mutex); + + return count; + +invalid: + vl53l1_errmsg("invalid syntax in %s", buf_ori); + rc = -EINVAL; + goto error; + +error: + mutex_unlock(&data->work_mutex); + + return rc; +} + +/** + * sysfs attribute "dmax_reflectance" [rd/wr] + * + * target reflectance use for calculate the ambient DMAX. can only be used + * while: not ranging + * + * @ingroup sysfs_attrib + */ +static DEVICE_ATTR(dmax_reflectance, 0660/*S_IWUGO | S_IRUGO*/, + stmvl53l1_show_dmax_reflectance, + stmvl53l1_store_dmax_reflectance); + +static int stmvl53l1_set_dmax_mode(struct stmvl53l1_data *data, + int dmax_mode) +{ + int rc = 0; + + if (data->enable_sensor) { + vl53l1_errmsg("can't change dmax mode while ranging\n"); + rc = -EBUSY; + } else { + switch (dmax_mode) { + case VL53L1_DMAXMODE_FMT_CAL_DATA: + case VL53L1_DMAXMODE_CUSTCAL_DATA: + case VL53L1_DMAXMODE_PER_ZONE_CAL_DATA: + data->dmax_mode = dmax_mode; + break; + default: + vl53l1_errmsg("invalid dmax mode %d\n", dmax_mode); + rc = -EINVAL; + break; + } + } + + return rc; +} + +IMPLEMENT_PARAMETER_INTEGER(dmax_mode, "dmax mode") + +/** + * sysfs attribute " dmax mode" [rd/wr] + * + * set the dmax mode value can only be used while: not ranging + * @li 1 @a VL53L1_DMAXMODE_FMT_CAL_DATA + * @li 2 @a VL53L1_DMAXMODE_CUSTCAL_DATA + * @li 3 @a VL53L1_DMAXMODE_PER_ZONE_CAL_DATA + * + * @ingroup sysfs_attrib + */ +static DEVICE_ATTR(dmax_mode, 0660/*S_IWUGO | S_IRUGO*/, + stmvl53l1_show_dmax_mode, + stmvl53l1_store_dmax_mode); + +static int stmvl53l1_set_tuning(struct stmvl53l1_data *data, int key, + int value) +{ + int rc; + + if (data->enable_sensor) { + vl53l1_errmsg("can't change tuning params while ranging\n"); + return -EBUSY; + } + + if (data->is_calibrating) { + vl53l1_errmsg("can't change tuning params while calibrating\n"); + return -EBUSY; + } + + if (key & ~0xffff) + return -EINVAL; + + vl53l1_dbgmsg("trying to set %d with key %d", value, key); + + rc = VL53L1_SetTuningParameter(&data->stdev, key, value); + if (rc) + rc = store_last_error(data, rc); + + return rc; +} + +static ssize_t stmvl53l1_store_tuning(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct stmvl53l1_data *data = dev_get_drvdata(dev); + int key; + int value; + int n; + int rc; + + mutex_lock(&data->work_mutex); + + n = sscanf(buf, "%d %d", &key, &value); + if (n != 2) { + rc = -EINVAL; + goto error; + } + rc = stmvl53l1_set_tuning(data, key, value); + if (rc) + goto error; + + mutex_unlock(&data->work_mutex); + + return count; + +error: + mutex_unlock(&data->work_mutex); + + return rc; +} + +/** + * sysfs attribute "tuning" [wr] + * + * write a tuning parameter. Two integer parameters are given. First one + * is a key that specify which tuning parameter is update. Other one is the + * value which is write. + * + * writing a tuning parameter is only allowed before the first start. + * + * @ingroup sysfs_attrib + */ +static DEVICE_ATTR(tuning, 0220/*S_IWUGO */, + NULL, + stmvl53l1_store_tuning); + +static int stmvl53l1_display_tuning_key(struct stmvl53l1_data *data, char *buf, + int *pos, int key) +{ + int rc = 0; + int value = 0; + int sz; + + rc = VL53L1_GetTuningParameter(&data->stdev, key, &value); + if (rc) + return 0; + + sz = snprintf(&buf[*pos], PAGE_SIZE - *pos, "%d %d\n", key, value); + if (sz >= PAGE_SIZE - *pos) + return -ENOSPC; /* FIXME : another better error ? */ + + *pos += sz; + + return 0; +} + +static ssize_t stmvl53l1_show_tuning_status(struct device *dev, + struct device_attribute *attr, char *buf) +{ + const int max_tuning_key = 65535; + struct stmvl53l1_data *data = dev_get_drvdata(dev); + int rc; + int i; + int pos = 0; + + mutex_lock(&data->work_mutex); + + for (i = 0; i < max_tuning_key; ++i) { + rc = stmvl53l1_display_tuning_key(data, buf, &pos, i); + if (rc) + break; + } + + mutex_unlock(&data->work_mutex); + + return rc ? rc : pos; +} + +/** + * sysfs attribute "tuning_status" [rd] + * + * write a tuning parameter. Two integer parameters are given. First one + * is a key that specify which tuning parameter is update. Other one is the + * value which is write. + * + * writing a tuning parameter is only allowed before the first start. + * + * @ingroup sysfs_attrib + */ +static DEVICE_ATTR(tuning_status, 0440/*S_IRUGO */, + stmvl53l1_show_tuning_status, + NULL); + +static int stmvl53l1_set_smudge_correction_mode(struct stmvl53l1_data *data, + int smudge_correction_mode) +{ + int rc = 0; + + if (data->enable_sensor) { + vl53l1_errmsg("can't change smudge corr mode while ranging\n"); + rc = -EBUSY; + } else { + switch (smudge_correction_mode) { + case VL53L1_SMUDGE_CORRECTION_NONE: + case VL53L1_SMUDGE_CORRECTION_CONTINUOUS: + case VL53L1_SMUDGE_CORRECTION_SINGLE: + case VL53L1_SMUDGE_CORRECTION_DEBUG: + data->smudge_correction_mode = smudge_correction_mode; + break; + default: + vl53l1_errmsg("invalid smudge correction mode %d\n", + smudge_correction_mode); + rc = -EINVAL; + break; + } + } + + return rc; +} + +IMPLEMENT_PARAMETER_INTEGER(smudge_correction_mode, "smudge correction mode") + +/** + * sysfs attribute " smudge_correction_mode" [rd/wr] + * + * This parameter will control if smudge correction is enable and how crosstalk + * values are updated. + * @li 0 @a VL53L1_SMUDGE_CORRECTION_NONE + * @li 1 @a VL53L1_SMUDGE_CORRECTION_CONTINUOUS + * @li 2 @a VL53L1_SMUDGE_CORRECTION_SINGLE + * @li 3 @a VL53L1_SMUDGE_CORRECTION_DEBUG + * + * @ingroup sysfs_attrib + */ +static DEVICE_ATTR(smudge_correction_mode, 0660/*S_IWUGO | S_IRUGO*/, + stmvl53l1_show_smudge_correction_mode, + stmvl53l1_store_smudge_correction_mode); + +static ssize_t stmvl53l1_show_is_xtalk_value_changed_config(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct stmvl53l1_data *data = dev_get_drvdata(dev); + int param; + + mutex_lock(&data->work_mutex); + param = data->is_xtalk_value_changed; + mutex_unlock(&data->work_mutex); + + return scnprintf(buf, PAGE_SIZE, "%d\n", param); +} + +/** + * sysfs attribute " optical_center" [rd] + * + * Will get optical_center using sysfs. + * + * @ingroup sysfs_attrib + */ +static DEVICE_ATTR(is_xtalk_value_changed, 0440/*S_IRUGO*/, + stmvl53l1_show_is_xtalk_value_changed_config, + NULL); + +static struct attribute *stmvl53l1_attributes[] = { + &dev_attr_enable_ps_sensor.attr, + &dev_attr_set_delay_ms.attr, + &dev_attr_timing_budget.attr, + &dev_attr_roi.attr, + &dev_attr_mode.attr, + &dev_attr_do_flush.attr, + &dev_attr_distance_mode.attr, + &dev_attr_crosstalk_enable.attr, + &dev_attr_enable_debug.attr, + &dev_attr_output_mode.attr, + &dev_attr_force_device_on_enable.attr, + &dev_attr_autonomous_config.attr, + &dev_attr_last_error.attr, + &dev_attr_offset_correction_mode.attr, + &dev_attr_optical_center.attr, + &dev_attr_dmax_reflectance.attr, + &dev_attr_dmax_mode.attr, + &dev_attr_tuning.attr, + &dev_attr_tuning_status.attr, + &dev_attr_smudge_correction_mode.attr, + &dev_attr_is_xtalk_value_changed.attr, + NULL +}; + +static const struct attribute_group stmvl53l1_attr_group = { + .attrs = stmvl53l1_attributes, +}; + +static ssize_t stmvl53l1_calib_data_read(struct file *filp, + struct kobject *kobj, struct bin_attribute *attr, + char *buf, loff_t off, size_t count) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct stmvl53l1_data *data = dev_get_drvdata(dev); + VL53L1_CalibrationData_t calib; + int rc; + void *src = (void *) &calib; + + mutex_lock(&data->work_mutex); + + vl53l1_dbgmsg("off = %lld / count = %d", off, (int)count); + + /* sanity check */ + if (off < 0 || off > sizeof(VL53L1_CalibrationData_t)) + goto invalid; + + /* got current calibration data */ + memset(&calib, 0, sizeof(calib)); + rc = VL53L1_GetCalibrationData(&data->stdev, &calib); + if (rc) { + vl53l1_errmsg("VL53L1_GetCalibrationData fail %d", rc); + rc = store_last_error(data, rc); + goto error; + } + + /* copy to buffer */ + if (off + count > sizeof(VL53L1_CalibrationData_t)) + count = sizeof(VL53L1_CalibrationData_t) - off; + if (count > 0) { + memcpy(buf, src + off, count); + } + mutex_unlock(&data->work_mutex); + + return count; + +invalid: + vl53l1_errmsg("invalid syntax"); + rc = -EINVAL; + goto error; + +error: + mutex_unlock(&data->work_mutex); + + return rc; +} + +static ssize_t stmvl53l1_calib_data_write(struct file *filp, + struct kobject *kobj, struct bin_attribute *attr, + char *buf, loff_t off, size_t count) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct stmvl53l1_data *data = dev_get_drvdata(dev); + int rc; + + mutex_lock(&data->work_mutex); + + vl53l1_dbgmsg("off = %lld / count = %d", off, (int)count); + + if (data->enable_sensor) { + rc = -EBUSY; + vl53l1_errmsg("can't set calib data while ranging\n"); + goto error; + } + + /* we only support one time write */ + if (off != 0 || count != sizeof(VL53L1_CalibrationData_t)) + goto invalid; + + rc = VL53L1_SetCalibrationData(&data->stdev, + (VL53L1_CalibrationData_t *) buf); + if (rc) { + vl53l1_errmsg("VL53L1_SetCalibrationData fail %d", rc); + rc = store_last_error(data, rc); + goto error; + } + + mutex_unlock(&data->work_mutex); + + return count; + +invalid: + vl53l1_errmsg("invalid syntax"); + rc = -EINVAL; + goto error; + +error: + mutex_unlock(&data->work_mutex); + + return rc; +} + +static struct bin_attribute stmvl53l1_calib_data_attr = { + .attr = { + .name = "calibration_data", + .mode = 0660/*S_IWUGO | S_IRUGO*/, + }, + .size = sizeof(VL53L1_CalibrationData_t), + .read = stmvl53l1_calib_data_read, + .write = stmvl53l1_calib_data_write, +}; + +static ssize_t stmvl53l1_zone_calib_data_read(struct file *filp, + struct kobject *kobj, struct bin_attribute *attr, + char *buf, loff_t off, size_t count) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct stmvl53l1_data *data = dev_get_drvdata(dev); + int rc; + void *src = (void *) &data->calib.data; + + mutex_lock(&data->work_mutex); + + vl53l1_dbgmsg("off = %lld / count = %d", off, (int)count); + + /* sanity check */ + if (off < 0 || off > sizeof(stmvl531_zone_calibration_data_t)) + goto invalid; + + /* got current zone calibration data */ + rc = VL53L1_GetZoneCalibrationData(&data->stdev, + &data->calib.data.data); + if (rc) { + vl53l1_errmsg("VL53L1_GetZoneCalibrationData fail %d", rc); + rc = store_last_error(data, rc); + goto error; + } + data->calib.data.id = data->current_roi_id; + + /* copy to buffer */ + if (off + count > sizeof(stmvl531_zone_calibration_data_t)) + count = sizeof(stmvl531_zone_calibration_data_t) - off; + if (count > 0) { + memcpy(buf, src + off, count); + } + mutex_unlock(&data->work_mutex); + + return count; + +invalid: + vl53l1_errmsg("invalid syntax"); + rc = -EINVAL; + goto error; + +error: + mutex_unlock(&data->work_mutex); + + return rc; +} + +static ssize_t stmvl53l1_zone_calib_data_write(struct file *filp, + struct kobject *kobj, struct bin_attribute *attr, + char *buf, loff_t off, size_t count) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct stmvl53l1_data *data = dev_get_drvdata(dev); + int rc; + void *dst = &data->calib.data; + + mutex_lock(&data->work_mutex); + + vl53l1_dbgmsg("off = %lld / count = %d", off, (int)count); + + /* implementation if quite fragile. We suppose successive access. We + * trigger set on last byte write if amount is exact. + */ + if (off < 0 || off > sizeof(stmvl531_zone_calibration_data_t)) + goto invalid; + if (off + count > sizeof(stmvl531_zone_calibration_data_t)) + goto invalid; + if (count > 0) { + memcpy(dst + off, buf, count); + } + if (off + count == sizeof(stmvl531_zone_calibration_data_t)) { + vl53l1_dbgmsg("trigger zone calib setting"); + rc = VL53L1_SetZoneCalibrationData(&data->stdev, + &data->calib.data.data); + if (rc) { + vl53l1_errmsg("VL53L1_SetZoneCalibrationData fail %d", + rc); + rc = store_last_error(data, rc); + goto error; + } + data->current_roi_id = data->calib.data.id; + } + + mutex_unlock(&data->work_mutex); + + return count; + +invalid: + vl53l1_errmsg("invalid syntax"); + rc = -EINVAL; + goto error; + +error: + mutex_unlock(&data->work_mutex); + + return rc; +} + +static struct bin_attribute stmvl53l1_zone_calib_data_attr = { + .attr = { + .name = "zone_calibration_data", + .mode = 0660/*S_IWUGO | S_IRUGO*/, + }, + .size = sizeof(stmvl531_zone_calibration_data_t), + .read = stmvl53l1_zone_calib_data_read, + .write = stmvl53l1_zone_calib_data_write, +}; + +static int ctrl_reg_access(struct stmvl53l1_data *data, void *p) +{ + struct stmvl53l1_register reg; + size_t total_byte; + int rc; + + if (data->is_device_remove) + return -ENODEV; + + total_byte = offsetof(struct stmvl53l1_register, data.b); + if (copy_from_user(®, p, total_byte)) { + vl53l1_errmsg("%d, fail\n", __LINE__); + return -EFAULT; + } + + if (reg.cnt > STMVL53L1_MAX_CCI_XFER_SZ) { + vl53l1_errmsg("reg len %d > size limit\n", reg.cnt); + return -EINVAL; + } + + total_byte = offsetof(struct stmvl53l1_register, data.bytes[reg.cnt]); + /* for write get the effective data part of the structure */ + if (!reg.is_read) { + if (copy_from_user(®, p, total_byte)) { + vl53l1_errmsg(" data cpy fail\n"); + return -EFAULT; + } + } + + /* put back to user only needed amount of data */ + if (!reg.is_read) { + rc = VL53L1_WriteMulti(&data->stdev, (uint16_t)reg.index, + reg.data.bytes, reg.cnt); + reg.status = rc; + /* for write only write back status no data */ + total_byte = offsetof(struct stmvl53l1_register, data.b); + vl53l1_dbgmsg("wr %x %d bytes statu %d\n", + reg.index, reg.cnt, rc); + if (rc) + rc = store_last_error(data, rc); + } else { + rc = VL53L1_ReadMulti(&data->stdev, (uint16_t)reg.index, + reg.data.bytes, reg.cnt); + reg.status = rc; + vl53l1_dbgmsg("rd %x %d bytes status %d\n", + reg.index, reg.cnt, rc); + /* if fail do not copy back data only status */ + if (rc) { + total_byte = offsetof(struct stmvl53l1_register, + data.b); + rc = store_last_error(data, rc); + } + /* else the total byte is already the full pay-load with data */ + } + + if (copy_to_user(p, ®, total_byte)) { + vl53l1_errmsg("%d, fail\n", __LINE__); + return -EFAULT; + } + return rc; +} + + +/* + * + */ +static int ctrl_start(struct stmvl53l1_data *data) +{ + int rc = 0; + + mutex_lock(&data->work_mutex); + + if (data->is_device_remove) { + rc = -ENODEV; + goto done; + } + + vl53l1_dbgmsg(" state = %d\n", data->enable_sensor); + + /* turn on tof sensor only if it's not already started */ + if (data->enable_sensor == 0 && !data->is_calibrating) { + /* to start */ + rc = stmvl53l1_start(data); + } else{ + rc = -EBUSY; + } + vl53l1_dbgmsg(" final state = %d\n", data->enable_sensor); + +done: + mutex_unlock(&data->work_mutex); + + return rc; +} + +/** + * no lock version of ctrl_stop (mutex shall be held) + * + * @warning exist only for use in device exit to ensure "locked and started" + * may also beuse in soem erro handling when mutex is already locked + * @return 0 on success and was running >0 if already off <0 on error + */ +static int _ctrl_stop(struct stmvl53l1_data *data) +{ + int rc = 0; + + vl53l1_dbgmsg("enter state = %d\n", data->enable_sensor); + /* be sure waiters are woken */ + data->is_data_valid = true; + /* turn on tof sensor only if it's not enabled by other client */ + if (data->enable_sensor == 1) { + /* to stop */ + rc = stmvl53l1_stop(data); + } else { + vl53l1_dbgmsg("already off did nothing\n"); + rc = 0; + } + stmvl53l1_insert_flush_events_lock(data); + vl53l1_dbgmsg(" final state = %d\n", data->enable_sensor); + + return rc; +} + +/** + * get work lock and stop sensor + * + * see @ref _ctrl_stop + * + * @param data device + * @return 0 on success EBUSY if arleady off + */ +static int ctrl_stop(struct stmvl53l1_data *data) +{ + int rc; + + mutex_lock(&data->work_mutex); + + if (data->is_device_remove) { + rc = -ENODEV; + goto done; + } + if (data->enable_sensor) + rc = _ctrl_stop(data); + else + rc = -EBUSY; + +done: + mutex_unlock(&data->work_mutex); + + return rc; +} + +static int ctrl_getdata(struct stmvl53l1_data *data, void __user *p) +{ + int rc; + + mutex_lock(&data->work_mutex); + + if (data->is_device_remove) { + rc = -ENODEV; + goto done; + } + rc = copy_to_user(p, + &data->meas.single_range_data, + sizeof(stmvl531_range_data_t)); + if (rc) { + vl53l1_dbgmsg("copy to user fail %d", rc); + rc = -EFAULT; + } + +done: + mutex_unlock(&data->work_mutex); + + return rc; +} + +static bool is_new_data_for_me(struct stmvl53l1_data *data, pid_t pid, + struct list_head *head) +{ + return data->is_data_valid && !is_pid_in_list(pid, head); +} + +static bool sleep_for_data_condition(struct stmvl53l1_data *data, pid_t pid, + struct list_head *head) +{ + bool res; + + mutex_lock(&data->work_mutex); + res = is_new_data_for_me(data, pid, head); + mutex_unlock(&data->work_mutex); + + return res; +} + +static int sleep_for_data(struct stmvl53l1_data *data, pid_t pid, + struct list_head *head) +{ + int rc; + + mutex_unlock(&data->work_mutex); + #ifndef VENDOR_EDIT + if(data->preset_mode == VL53L1_PRESETMODE_LITE_RANGING){ + #else + if (1) { + #endif + rc = wait_event_killable(data->waiter_for_data, + sleep_for_data_condition(data, pid, head)); + }else{ + rc = wait_event_killable_timeout(data->waiter_for_data, + sleep_for_data_condition(data, pid, head),2*HZ); + } + mutex_lock(&data->work_mutex); + + return data->enable_sensor ? rc : -ENODEV; +} + +static int ctrl_getdata_blocking(struct stmvl53l1_data *data, void __user *p) +{ + int rc = 0; + pid_t pid = current->pid; + + mutex_lock(&data->work_mutex); + /* If device not ranging then exit on error */ + if (data->is_device_remove || !data->enable_sensor) { + rc = -ENODEV; + goto done; + } + /* sleep if data already read */ + if (!is_new_data_for_me(data, pid, &data->simple_data_reader_list)) + rc = sleep_for_data(data, pid, &data->simple_data_reader_list); + if (rc) + goto done; + + /* unless we got interrupted we return data to user and note read */ + rc = copy_to_user(p, &data->meas.single_range_data, + sizeof(stmvl531_range_data_t)); + if (rc) + goto done; + rc = add_reader(pid, &data->simple_data_reader_list); + +done: + mutex_unlock(&data->work_mutex); + + return rc; +} + +static int ctrl_mz_data_common(struct stmvl53l1_data *data, void __user *p, + bool is_additional) +{ + struct stmvl53l1_data_with_additional __user *d = p; + int rc; + + mutex_lock(&data->work_mutex); + if (data->is_device_remove) { + rc = -ENODEV; + goto done; + } + rc = copy_to_user(&d->data, &data->meas.multi_range_data, + sizeof(VL53L1_MultiRangingData_t)); + if (rc) { + vl53l1_dbgmsg("copy to user fail %d", rc); + rc = -EFAULT; + goto done; + } + if (is_additional) { + rc = copy_to_user(&d->additional_data, + &data->meas.additional_data, + sizeof(VL53L1_AdditionalData_t)); + if (rc) { + vl53l1_dbgmsg("copy to user fail %d", rc); + rc = -EFAULT; + goto done; + } + } + if (!data->enable_sensor) + rc = -ENODEV; + else if (!is_mz_mode(data)) + rc = -ENOEXEC; + +done: + mutex_unlock(&data->work_mutex); + + return rc; +} + +static int ctrl_mz_data_blocking_common(struct stmvl53l1_data *data, + void __user *p, bool is_additional) +{ + int rc = 0; + struct stmvl53l1_data_with_additional __user *d = p; + pid_t pid = current->pid; + + mutex_lock(&data->work_mutex); + if (data->is_device_remove) { + rc = -ENODEV; + goto done; + } + /* mode 2 or 3 */ + if (!is_mz_mode(data)) { + rc = -ENOEXEC; + goto done; + } + /* If device not ranging then exit on error */ + if (!data->enable_sensor) { + rc = -ENODEV; + goto done; + } + /* sleep if data already read */ + if (!is_new_data_for_me(data, pid, &data->mz_data_reader_list)) + rc = sleep_for_data(data, pid, &data->mz_data_reader_list);//songyt test + if (rc) + goto done; + + /* unless we got interrupted we return data to user and note read */ + rc = copy_to_user(&d->data, &data->meas.multi_range_data, + sizeof(VL53L1_MultiRangingData_t)); + if (rc) + goto done; + if (is_additional) { + rc = copy_to_user(&d->additional_data, + &data->meas.additional_data, + sizeof(VL53L1_AdditionalData_t)); + if (rc) + goto done; + } + rc = add_reader(pid, &data->mz_data_reader_list); + +done: + mutex_unlock(&data->work_mutex); + + return rc; +} + +/** + * Get multi zone data + * @param data + * @param p [out] user ptr to @ref VL53L1_MultiRangingData_t structure\n + * is always set but on EFAULT error + * + * @return + * @li 0 on success + * @li ENODEV if not ranging + * @li ENOEXEC not in multi zone mode + * @li EFAULT copy to user error + */ +static int ctrl_mz_data(struct stmvl53l1_data *data, void __user *p) +{ + return ctrl_mz_data_common(data, p, false); +} + +static int ctrl_mz_data_blocking(struct stmvl53l1_data *data, void __user *p) +{ + return ctrl_mz_data_blocking_common(data, p, false); +} + +/** + * Get multi zone data with histogram debug data + * @param data + * @param p [out] user ptr to @ref struct stmvl53l1_data_with_additional + * structure is always set but on EFAULT error + * + * @return + * @li 0 on success + * @li ENODEV if not ranging + * @li ENOEXEC not in multi zone mode + * @li EFAULT copy to user error + */ +static int ctrl_mz_data_additional(struct stmvl53l1_data *data, void __user *p) +{ + return ctrl_mz_data_common(data, p, true); +} + +static int ctrl_mz_data_blocking_additional(struct stmvl53l1_data *data, + void __user *p) +{ + return ctrl_mz_data_blocking_common(data, p, true); +} + +static int ctrl_param_last_error(struct stmvl53l1_data *data, + struct stmvl53l1_parameter *param) +{ + int rc; + + if (param->is_read) { + param->value = data->last_error; + param->status = 0; + vl53l1_dbgmsg("get last error %d", param->value); + rc = 0; + } else { + rc = -EINVAL; + } + + return rc; +} + +static int ctrl_param_optical_center(struct stmvl53l1_data *data, + struct stmvl53l1_parameter *param) +{ + if (!param->is_read) + return -EINVAL; + + param->value = data->optical_offset_x; + param->value2 = data->optical_offset_y; + + return 0; +} + +static int ctrl_param_dmax_reflectance(struct stmvl53l1_data *data, + struct stmvl53l1_parameter *param) +{ + int rc; + + if (param->is_read) { + param->value = data->dmax_reflectance; + param->status = 0; + vl53l1_dbgmsg("get dmax reflectance %d", param->value); + rc = 0; + } else { + rc = stmvl53l1_set_dmax_reflectance(data, param->value); + vl53l1_dbgmsg("rc %d req %d now %d", rc, + param->value, data->dmax_reflectance); + } + + return rc; +} + +static int ctrl_param_tuning(struct stmvl53l1_data *data, + struct stmvl53l1_parameter *param) +{ + if (param->is_read) + return -EINVAL; + + return stmvl53l1_set_tuning(data, param->value, param->value2); +} + +static int ctrl_param_is_xtalk_value_changed(struct stmvl53l1_data *data, + struct stmvl53l1_parameter *param) +{ + if (!param->is_read) + return -EINVAL; + + param->value = data->is_xtalk_value_changed; + + return 0; +} + +/** + * handle ioctl set param mode + * + * @param data + * @param p + * @return 0 on success + */ +static int ctrl_params(struct stmvl53l1_data *data, void __user *p) +{ + int rc, rc2; + struct stmvl53l1_parameter param; + + mutex_lock(&data->work_mutex); + + if (data->is_device_remove) { + rc = -ENODEV; + goto done; + } + rc = copy_from_user(¶m, p, sizeof(param)); + param.status = 0; + if (rc) { + rc = -EFAULT; + goto done; /* no need for status in user struct */ + } + switch (param.name) { + case VL53L1_POLLDELAY_PAR: + rc = ctrl_param_poll_delay_ms(data, ¶m); + break; + case VL53L1_TIMINGBUDGET_PAR: + rc = ctrl_param_timing_budget(data, ¶m); + break; + case VL53L1_DEVICEMODE_PAR: + rc = ctrl_param_preset_mode(data, ¶m); + break; + case VL53L1_DISTANCEMODE_PAR: + rc = ctrl_param_distance_mode(data, ¶m); + break; + case VL53L1_XTALKENABLE_PAR: + rc = ctrl_param_crosstalk_enable(data, ¶m); + break; + case VL53L1_OUTPUTMODE_PAR: + rc = ctrl_param_output_mode(data, ¶m); + break; + case VL53L1_FORCEDEVICEONEN_PAR: + rc = ctrl_param_force_device_on_en(data, ¶m); + break; + case VL53L1_LASTERROR_PAR: + rc = ctrl_param_last_error(data, ¶m); + break; + case VL53L1_OFFSETCORRECTIONMODE_PAR: + rc = ctrl_param_offset_correction_mode(data, ¶m); + break; + case VL53L1_OPTICALCENTER_PAR: + rc = ctrl_param_optical_center(data, ¶m); + break; + case VL53L1_DMAXREFLECTANCE_PAR: + rc = ctrl_param_dmax_reflectance(data, ¶m); + break; + case VL53L1_DMAXMODE_PAR: + rc = ctrl_param_dmax_mode(data, ¶m); + break; + case VL53L1_TUNING_PAR: + rc = ctrl_param_tuning(data, ¶m); + break; + case VL53L1_SMUDGECORRECTIONMODE_PAR: + rc = ctrl_param_smudge_correction_mode(data, ¶m); + break; + case VL53L1_ISXTALKVALUECHANGED_PAR: + rc = ctrl_param_is_xtalk_value_changed(data, ¶m); + break; + default: + vl53l1_errmsg("unknown or unsupported %d\n", param.name); + rc = -EINVAL; + } + /* copy back (status at least ) to user */ + if (param.is_read && rc == 0) { + rc2 = copy_to_user(p, ¶m, sizeof(param)); + if (rc2) { + rc = -EFAULT; /* kill prev status if that fail */ + vl53l1_errmsg("copy to user fail %d\n", rc); + } + } +done: + mutex_unlock(&data->work_mutex); + return rc; +} + +/** + * implement set/get roi ioctl + * @param data device + * @param p user space ioctl arg ptr + * @return 0 on success <0 errno code + * @li -EINVAL invalid number of roi + * @li -EBUSY when trying to set roi while ranging + * @li -EFAULT if cpy to/fm user fail for requested number of roi + */ +static int ctrl_roi(struct stmvl53l1_data *data, void __user *p) +{ + int rc; + int roi_cnt; + struct stmvl53l1_roi_full_t rois; + + mutex_lock(&data->work_mutex); + if (data->is_device_remove) { + rc = -ENODEV; + goto done; + } + /* copy fixed part of args at first */ + rc = copy_from_user(&rois, p, + offsetof(struct stmvl53l1_roi_full_t, + roi_cfg.UserRois[0])); + if (rc) { + rc = -EFAULT; + goto done; + } + /* check no of roi limit is ok */ + roi_cnt = rois.roi_cfg.NumberOfRoi; + if (roi_cnt > VL53L1_MAX_USER_ZONES) { + vl53l1_errmsg("invalid roi spec cnt=%d > %d", + rois.roi_cfg.NumberOfRoi, + VL53L1_MAX_USER_ZONES); + rc = -EINVAL; + goto done; + } + + if (rois.is_read) { + int cpy_size; + + roi_cnt = MIN(rois.roi_cfg.NumberOfRoi, + data->roi_cfg.NumberOfRoi); + cpy_size = offsetof(VL53L1_RoiConfig_t, UserRois[roi_cnt]); + /* copy from local to user only effective part requested */ + rc = copy_to_user(&((struct stmvl53l1_roi_full_t *)p)->roi_cfg, + &data->roi_cfg, cpy_size); + vl53l1_dbgmsg("return %d of %d\n", roi_cnt, + data->roi_cfg.NumberOfRoi); + } else { + /* SET check cnt roi is ok */ + if (data->enable_sensor) { + rc = -EBUSY; + vl53l1_errmsg("can't set roi while ranging\n"); + goto done; + } + /* get full data that required from user */ + rc = copy_from_user(&rois, p, + offsetof(struct stmvl53l1_roi_full_t, + roi_cfg.UserRois[roi_cnt])); + if (rc) { + vl53l1_errmsg("get %d roi fm user fail", roi_cnt); + rc = -EFAULT; + goto done; + } + dump_roi(data->roi_cfg.UserRois, data->roi_cfg.NumberOfRoi); + /* we may ask ll driver to check but check is mode dependent + * and so we could get erroneous error back + */ + memcpy(&data->roi_cfg, &rois.roi_cfg, sizeof(data->roi_cfg)); + } +done: + mutex_unlock(&data->work_mutex); + return rc; +} + +static int ctrl_autonomous_config(struct stmvl53l1_data *data, void __user *p) +{ + int rc = 0; + struct stmvl53l1_autonomous_config_t full; + + mutex_lock(&data->work_mutex); + if (data->is_device_remove) { + rc = -ENODEV; + goto done; + } + /* first copy all data */ + rc = copy_from_user(&full, p, sizeof(full)); + if (rc) { + rc = -EFAULT; + goto done; + } + + if (full.is_read) { + full.pollingTimeInMs = data->auto_pollingTimeInMs; + full.config = data->auto_config; + rc = copy_to_user(p, &full, sizeof(full)); + if (rc) + rc = -EFAULT; + } else { + if (data->enable_sensor) { + rc = -EBUSY; + vl53l1_errmsg("can't change config while ranging\n"); + goto done; + } + data->auto_pollingTimeInMs = full.pollingTimeInMs; + data->auto_config = full.config; + } + +done: + mutex_unlock(&data->work_mutex); + + return rc; +} + +static int ctrl_calibration_data(struct stmvl53l1_data *data, void __user *p) +{ + int rc; + struct stmvl53l1_ioctl_calibration_data_t calib; + int data_offset = offsetof(struct stmvl53l1_ioctl_calibration_data_t, + data); + + mutex_lock(&data->work_mutex); + + if (data->is_device_remove) { + rc = -ENODEV; + goto done; + } + rc = copy_from_user(&calib, p, data_offset); + if (rc) { + vl53l1_errmsg("fail to detect read or write %d", rc); + rc = -EFAULT; + goto done; + } + + if (calib.is_read) { + memset(&calib.data, 0, sizeof(calib.data)); + rc = VL53L1_GetCalibrationData(&data->stdev, &calib.data); + if (rc) { + vl53l1_errmsg("VL53L1_GetCalibrationData fail %d", rc); + rc = store_last_error(data, rc); + goto done; + } + rc = copy_to_user(p + data_offset, &calib.data, + sizeof(calib.data)); + } else { + if (data->enable_sensor) { + rc = -EBUSY; + vl53l1_errmsg("can't set calib data while ranging\n"); + goto done; + } + rc = copy_from_user(&calib.data, p + data_offset, + sizeof(calib.data)); + if (rc) { + vl53l1_errmsg("fail to copy calib data"); + rc = -EFAULT; + goto done; + } + rc = VL53L1_SetCalibrationData(&data->stdev, &calib.data); + if (rc) { + vl53l1_errmsg("VL53L1_SetCalibrationData fail %d", rc); + rc = store_last_error(data, rc); + } + } + +done: + mutex_unlock(&data->work_mutex); + + return rc; +} + +static int ctrl_zone_calibration_data(struct stmvl53l1_data *data, + void __user *p) +{ + int rc; + struct stmvl53l1_ioctl_zone_calibration_data_t *calib; + int data_offset = + offsetof(struct stmvl53l1_ioctl_zone_calibration_data_t, data); + + mutex_lock(&data->work_mutex); + + calib = &data->calib; + if (data->is_device_remove) { + rc = -ENODEV; + goto done; + } + rc = copy_from_user(calib, p, data_offset); + if (rc) { + vl53l1_errmsg("fail to detect read or write %d", rc); + rc = -EFAULT; + goto done; + } + + if (calib->is_read) { + memset(&calib->data, 0, sizeof(calib->data)); + rc = VL53L1_GetZoneCalibrationData(&data->stdev, + &calib->data.data); + if (rc) { + vl53l1_errmsg("VL53L1_GetZoneCalibrationData fail %d", + rc); + rc = store_last_error(data, rc); + goto done; + } + calib->data.id = data->current_roi_id; + rc = copy_to_user(p + data_offset, &calib->data, + sizeof(calib->data)); + } else { + if (data->enable_sensor) { + rc = -EBUSY; + vl53l1_errmsg("can't set calib data while ranging\n"); + goto done; + } + rc = copy_from_user(&calib->data, p + data_offset, + sizeof(calib->data)); + if (rc) { + vl53l1_errmsg("fail to copy calib data"); + rc = -EFAULT; + goto done; + } + rc = VL53L1_SetZoneCalibrationData(&data->stdev, + &calib->data.data); + if (rc) { + vl53l1_errmsg("VL53L1_SetZoneCalibrationData fail %d", + rc); + rc = store_last_error(data, rc); + goto done; + } + data->current_roi_id = calib->data.id; + } + +done: + mutex_unlock(&data->work_mutex); + + return rc; +} + +static int ctrl_perform_calibration_ref_spad_lock(struct stmvl53l1_data *data, + struct stmvl53l1_ioctl_perform_calibration_t *calib) +{ + int rc = VL53L1_PerformRefSpadManagement(&data->stdev); + + if (rc) { + vl53l1_errmsg("VL53L1_PerformRefSpadManagement fail => %d", rc); + rc = store_last_error(data, rc); + } + + return rc; +} + +static int ctrl_perform_calibration_crosstalk_lock(struct stmvl53l1_data *data, + struct stmvl53l1_ioctl_perform_calibration_t *calib) +{ + int rc = 0; + + rc = stmvl53l1_sendparams(data); + if (rc) + goto done; + + rc = VL53L1_PerformXTalkCalibration(&data->stdev, calib->param1); + if (rc) { + vl53l1_errmsg("VL53L1_PerformXTalkCalibration fail => %d", rc); + rc = store_last_error(data, rc); + } + +done: + return rc; +} + +static int ctrl_perform_zone_calibration_offset_lock( + struct stmvl53l1_data *data, + struct stmvl53l1_ioctl_perform_calibration_t *calib) +{ + int rc; + + /* first sanity check */ + if (calib->param1 != VL53L1_OFFSETCALIBRATIONMODE_MULTI_ZONE) { + vl53l1_errmsg("invalid param1"); + rc = -EINVAL; + goto done; + } + + /* setup offset calibration mode */ + rc = VL53L1_SetOffsetCalibrationMode(&data->stdev, calib->param1); + if (rc) { + vl53l1_errmsg("VL53L1_SetOffsetCalibrationMode fail => %d", rc); + rc = store_last_error(data, rc); + goto done; + } + + /* set mode to multi zone to allow roi settings */ + rc = VL53L1_SetPresetMode(&data->stdev, + VL53L1_PRESETMODE_MULTIZONES_SCANNING); + if (rc) { + vl53l1_errmsg("VL53L1_SetPresetMode fail => %d", rc); + rc = store_last_error(data, rc); + goto done; + } + + /* setup roi */ + rc = VL53L1_SetROI(&data->stdev, &data->roi_cfg); + if (rc) { + vl53l1_errmsg("VL53L1_SetROI fail => %d", rc); + rc = store_last_error(data, rc); + goto done; + } + + /* finally perform calibration */ + /* allow delay add after stop in VL53L1_run__calibration */ + data->is_delay_allowed = 1; + rc = VL53L1_PerformOffsetCalibration(&data->stdev, calib->param2, + calib->param3); + data->is_delay_allowed = 0; + if (rc) { + vl53l1_errmsg("VL53L1_PerformOffsetCalibration fail => %d", rc); + rc = store_last_error(data, rc); + } + + /* save roi hash for later use */ + data->current_roi_id = stmvl53l1_compute_hash(&data->roi_cfg); + +done: + return rc; +} + +static int ctrl_perform_calibration_offset_lock(struct stmvl53l1_data *data, + struct stmvl53l1_ioctl_perform_calibration_t *calib) +{ + int rc; + + /* for legacy purpose we still support mz */ + if (calib->param1 == VL53L1_OFFSETCALIBRATIONMODE_MULTI_ZONE) + return ctrl_perform_zone_calibration_offset_lock(data, calib); + + /* setup offset calibration mode */ + rc = VL53L1_SetOffsetCalibrationMode(&data->stdev, calib->param1); + if (rc) { + vl53l1_errmsg("VL53L1_SetOffsetCalibrationMode fail => %d", rc); + rc = store_last_error(data, rc); + goto done; + } + + /* finally perform calibration */ + /* allow delay add after stop in VL53L1_run__calibration */ + data->is_delay_allowed = 1; + rc = VL53L1_PerformOffsetCalibration(&data->stdev, calib->param2, + calib->param3); + data->is_delay_allowed = 0; + if (rc) { + vl53l1_errmsg("VL53L1_PerformOffsetCalibration fail => %d", rc); + rc = store_last_error(data, rc); + } + +done: + return rc; +} + +static int ctrl_perform_simple_calibration_offset_lock( + struct stmvl53l1_data *data, + struct stmvl53l1_ioctl_perform_calibration_t *calib) +{ + int rc; + + /* finally perform calibration */ + /* allow delay add after stop in VL53L1_run__calibration */ + data->is_delay_allowed = 1; + + rc = stmvl53l1_sendparams(data); + if (rc) + goto done; + + rc = VL53L1_PerformOffsetSimpleCalibration(&data->stdev, calib->param1); + data->is_delay_allowed = 0; + if (rc) { + vl53l1_errmsg( + "VL53L1_PerformOffsetSimpleCalibration fail => %d", rc); + rc = store_last_error(data, rc); + } + +done: + return rc; +} + +static int ctrl_perform_calibration(struct stmvl53l1_data *data, void __user *p) +{ + int rc; + struct stmvl53l1_ioctl_perform_calibration_t calib; + + mutex_lock(&data->work_mutex); + + if (data->is_device_remove) { + rc = -ENODEV; + goto done; + } + data->is_calibrating = true; + rc = copy_from_user(&calib, p, sizeof(calib)); + if (rc) { + rc = -EFAULT; + goto done; + } + if (data->enable_sensor) { + rc = -EBUSY; + vl53l1_errmsg("can't perform calibration while ranging\n"); + goto done; + } + vl53l1_info("cali power on");//songyt add + stmvl53l1_module_func_tbl.power_up(data->client_object); + + rc = reset_release(data); + if (rc) + goto done; + + rc = VL53L1_StaticInit(&data->stdev); + if (rc) { + vl53l1_errmsg("VL53L1_StaticInit fail => %d", rc); + rc = store_last_error(data, rc); + goto done; + } + + switch (calib.calibration_type) { + case VL53L1_CALIBRATION_REF_SPAD: + rc = ctrl_perform_calibration_ref_spad_lock(data, + &calib); + break; + case VL53L1_CALIBRATION_CROSSTALK: + rc = ctrl_perform_calibration_crosstalk_lock(data, + &calib); + break; + case VL53L1_CALIBRATION_OFFSET: + rc = ctrl_perform_calibration_offset_lock(data, + &calib); + break; + case VL53L1_CALIBRATION_OFFSET_SIMPLE: + rc = ctrl_perform_simple_calibration_offset_lock(data, + &calib); + break; + case VL53L1_CALIBRATION_OFFSET_PER_ZONE: + rc = ctrl_perform_zone_calibration_offset_lock(data, + &calib); + break; + default: + rc = -EINVAL; + break; + } + + reset_hold(data); + vl53l1_info("cali power down");//songyt add + stmvl53l1_module_func_tbl.power_down(data->client_object); + +done: + data->is_calibrating = false; + data->is_first_start_done = true; + mutex_unlock(&data->work_mutex); + + return rc; +} + +static int stmvl53l1_ioctl_handler( + struct stmvl53l1_data *data, + unsigned int cmd, unsigned long arg, + void __user *p) +{ + int rc = 0; + + if (!data) + return -EINVAL; + + switch (cmd) { + + case VL53L1_IOCTL_START: + vl53l1_dbgmsg("VL53L1_IOCTL_START\n"); + rc = ctrl_start(data); + break; + + case VL53L1_IOCTL_STOP: + vl53l1_dbgmsg("VL53L1_IOCTL_STOP\n"); + rc = ctrl_stop(data); + break; + + case VL53L1_IOCTL_GETDATAS: + /* vl53l1_dbgmsg("VL53L1_IOCTL_GETDATAS\n"); */ + rc = ctrl_getdata(data, p); + break; + + case VL53L1_IOCTL_GETDATAS_BLOCKING: + /* vl53l1_dbgmsg("VL53L1_IOCTL_GETDATAS_BLOCKING\n"); */ + rc = ctrl_getdata_blocking(data, p); + break; + + /* Register tool */ + case VL53L1_IOCTL_REGISTER: + vl53l1_dbgmsg("VL53L1_IOCTL_REGISTER\n"); + rc = ctrl_reg_access(data, p); + break; + + case VL53L1_IOCTL_PARAMETER: + vl53l1_dbgmsg("VL53L1_IOCTL_PARAMETER\n"); + rc = ctrl_params(data, p); + break; + + case VL53L1_IOCTL_ROI: + vl53l1_dbgmsg("VL53L1_IOCTL_ROI\n"); + rc = ctrl_roi(data, p); + break; + case VL53L1_IOCTL_MZ_DATA: + /* vl53l1_dbgmsg("VL53L1_IOCTL_MZ_DATA\n"); */ + rc = ctrl_mz_data(data, p); + break; + case VL53L1_IOCTL_MZ_DATA_BLOCKING: + /* vl53l1_dbgmsg("VL53L1_IOCTL_MZ_DATA_BLOCKING\n"); */ + rc = ctrl_mz_data_blocking(data, p); + break; + case VL53L1_IOCTL_CALIBRATION_DATA: + vl53l1_dbgmsg("VL53L1_IOCTL_CALIBRATION_DATA\n"); + rc = ctrl_calibration_data(data, p); + break; + case VL53L1_IOCTL_PERFORM_CALIBRATION: + vl53l1_dbgmsg("VL53L1_IOCTL_PERFORM_CALIBRATION\n"); + rc = ctrl_perform_calibration(data, p); + { + /*Workaround for abnormal xTalk value*/ + int iRange = 0; + VL53L1_xtalk_calibration_results_t xtalk1; + + ctrl_start(data); + for(iRange=0; iRange<3; iRange++) + { + pid_t pid = current->pid; + mutex_lock(&data->work_mutex); + if (data->is_device_remove) { + printk("vl53l1:---no device\n"); + break; + } + if (!is_mz_mode(data)) { + printk("-vl53l1:---not mz mode\n"); + break; + } + if (!data->enable_sensor) { + printk("-vl53l1:---not start\n"); + break; + } + /* sleep if data already read */ + if (!is_new_data_for_me(data, pid, &data->mz_data_reader_list)) + rc = sleep_for_data(data, pid, &data->mz_data_reader_list); + if (rc) + { + printk("-vl53l1:---wait data error\n"); + break; + } + add_reader(pid, &data->mz_data_reader_list); + mutex_unlock(&data->work_mutex); + printk("vl53l1:-New data ready-----%d\n", iRange); + } + ctrl_stop(data); + VL53L1_get_current_xtalk_settings(&data->stdev, &xtalk1); + printk("vl53l1:-xTalk value: %d\n", xtalk1.algo__crosstalk_compensation_plane_offset_kcps); + if(xtalk1.algo__crosstalk_compensation_plane_offset_kcps>0xFFFF) + { + rc = ctrl_perform_calibration(data, p); + VL53L1_get_current_xtalk_settings(&data->stdev, &xtalk1); + printk("vl53l1:-the 2nd xTalk value: %d\n",xtalk1.algo__crosstalk_compensation_plane_offset_kcps); + } + + } + break; + case VL53L1_IOCTL_AUTONOMOUS_CONFIG: + vl53l1_dbgmsg("VL53L1_IOCTL_AUTONOMOUS_CONFIG\n"); + rc = ctrl_autonomous_config(data, p); + break; + case VL53L1_IOCTL_ZONE_CALIBRATION_DATA: + vl53l1_dbgmsg("VL53L1_IOCTL_ZONE_CALIBRATION_DATA\n"); + rc = ctrl_zone_calibration_data(data, p); + break; + case VL53L1_IOCTL_MZ_DATA_ADDITIONAL: + /* vl53l1_dbgmsg("VL53L1_IOCTL_MZ_DATA_ADDITIONAL\n"); */ + rc = ctrl_mz_data_additional(data, p); + break; + case VL53L1_IOCTL_MZ_DATA_ADDITIONAL_BLOCKING: + /* vl53l1_dbgmsg("VL53L1_IOCTL_MZ_DATA_ADDITIONAL_BLOCKING\n"); + */ + rc = ctrl_mz_data_blocking_additional(data, p); + break; + default: + rc = -EINVAL; + break; + } + + return rc; +} + + + +static int stmvl53l1_open(struct inode *inode, struct file *file) +{ + struct stmvl53l1_data *data = container_of(file->private_data, + struct stmvl53l1_data, miscdev); + + vl53l1_dbgmsg("Start\n"); + stmvl53l1_module_func_tbl.get(data->client_object); + vl53l1_dbgmsg("End\n"); + + return 0; +} + +static int stmvl53l1_release(struct inode *inode, struct file *file) +{ + struct stmvl53l1_data *data = container_of(file->private_data, + struct stmvl53l1_data, miscdev); + + vl53l1_dbgmsg("Start\n"); + stmvl53l1_module_func_tbl.put(data->client_object); + vl53l1_dbgmsg("End\n"); + + return 0; +} + + +/** max number or error per measure too abort */ +#define stvm531_get_max_meas_err(...) 3 +/** max number or error per stream too abort */ +#define stvm531_get_max_stream_err(...) 6 + +static void detect_xtalk_value_change(struct stmvl53l1_data *data, + VL53L1_MultiRangingData_t *meas) +{ + data->is_xtalk_value_changed = meas->HasXtalkValueChanged ? true : + data->is_xtalk_value_changed; +} + +/** + * handle data retrieval and dispatch + * + * work lock must be held + * + * called form work or interrupt thread it must be a blocable context ! + * @param data the device + */ +static void stmvl53l1_on_newdata_event(struct stmvl53l1_data *data) +{ + int rc; + VL53L1_RangingMeasurementData_t *pmsinglerange; + VL53L1_MultiRangingData_t *pmrange; + VL53L1_MultiRangingData_t *tmprange; + VL53L1_TargetRangeData_t RangeData[VL53L1_MAX_RANGE_RESULTS]; + VL53L1_RangingMeasurementData_t singledata; + long ts_msec; + int i; + + do_gettimeofday(&data->meas.comp_tv); + ts_msec = stmvl53l1_tv_dif(&data->start_tv, &data->meas.comp_tv)/1000; + + pmrange = &data->meas.multi_range_data; + tmprange = &data->meas.tmp_range_data; + pmsinglerange = &data->meas.single_range_data; + + memcpy(&singledata, pmsinglerange, + sizeof(VL53L1_RangingMeasurementData_t)); + for (i = 0; i < VL53L1_MAX_RANGE_RESULTS; i++) + memcpy(&RangeData[i], &pmrange->RangeData[i], + sizeof(VL53L1_TargetRangeData_t)); + + data->meas.intr++; + + /* use get data method based on active mode */ + switch (data->preset_mode) { + case VL53L1_PRESETMODE_LITE_RANGING: + case VL53L1_PRESETMODE_AUTONOMOUS: + case VL53L1_PRESETMODE_LOWPOWER_AUTONOMOUS: + rc = VL53L1_GetRangingMeasurementData(&data->stdev, + pmsinglerange); + /* In case of VL53L1_RANGESTATUS_NONE we prefer to return + * the previous ranging values along that error status + */ + if (pmsinglerange->RangeStatus == VL53L1_RANGESTATUS_NONE) { + memcpy(pmsinglerange, &singledata, + sizeof(VL53L1_RangingMeasurementData_t)); + pmsinglerange->RangeStatus = VL53L1_RANGESTATUS_NONE; + } + break; + case VL53L1_PRESETMODE_RANGING: + case VL53L1_PRESETMODE_MULTIZONES_SCANNING: + /* IMPORTANT : during VL53L1_GetMultiRangingData() call + * work_mutex is release during ipp. This is why we use + * tmp_range_data which is not access somewhere else. When we are + * back we then copy tmp_range_data in multi_range_data. + */ + + rc = VL53L1_GetMultiRangingData(&data->stdev, + &data->meas.tmp_range_data); + + /* be sure we got VL53L1_RANGESTATUS_NONE for object 0 if we got + * invalid roi or no object. So if client read data using + * VL53L1_IOCTL_GETDATAS we got correct status. + */ + if (tmprange->RoiStatus == VL53L1_ROISTATUS_NOT_VALID || + tmprange->NumberOfObjectsFound == 0) + tmprange->RangeData[0].RangeStatus = + VL53L1_RANGESTATUS_NONE; + + memcpy(pmrange, tmprange, sizeof(VL53L1_MultiRangingData_t)); + + /* In case of VL53L1_RANGESTATUS_NONE we prefer to return + * the previous ranging values along that error status + */ + #ifdef VENDOR_EDIT + #endif + /* got histogram debug data in case user want it later on */ + if (!rc) + rc = VL53L1_GetAdditionalData(&data->stdev, + &data->meas.additional_data); + detect_xtalk_value_change(data, pmrange); + break; + default: + /* that must be some bug or data corruption stop now */ + rc = -1; + vl53l1_errmsg("unsorted mode %d=>stop\n", data->preset_mode); + _ctrl_stop(data); + } + /* check if not stopped yet + * as we may have been unlocked we must re-check + */ + if (data->enable_sensor == 0) { + vl53l1_dbgmsg("at meas #%d we got stopped\n", data->meas.cnt); + return; + } + if (rc) { + vl53l1_errmsg("VL53L1_GetRangingMeasurementData @%d %d", + __LINE__, rc); + data->meas.err_cnt++; + data->meas.err_tot++; + if (data->meas.err_cnt > stvm531_get_max_meas_err(data) || + data->meas.err_tot > stvm531_get_max_stream_err(data)) { + vl53l1_errmsg("on #%d %d err %d tot stop", + data->meas.cnt, data->meas.err_cnt, + data->meas.err_tot); + _ctrl_stop(data); + } + return; + } + + /* FIXME: remove when implemented by ll or bare driver */ + pmrange->TimeStamp = ts_msec; + pmsinglerange->TimeStamp = ts_msec; + for (i = 1; i < pmrange->NumberOfObjectsFound; i++) + pmrange->TimeStamp = ts_msec; + + data->meas.cnt++; + vl53l1_dbgmsg("vl53l1: status=%d obj cnt=%d distance=%d sr=%d ar=%d\n", + pmrange->RangeData[0].RangeStatus, + pmrange->NumberOfObjectsFound, + (int)pmrange->RangeData[0].RangeMilliMeter, + (int)pmrange->RangeData[0].SignalRateRtnMegaCps, + (int)pmrange->RangeData[0].AmbientRateRtnMegaCps); + vl53l1_dbgmsg("#%3d %2d poll ts %5d status=%d obj cnt=%d\n", + data->meas.cnt, + data->meas.poll_cnt, + pmrange->TimeStamp, + pmrange->RangeData[0].RangeStatus, + pmrange->NumberOfObjectsFound); +#if 0 + vl53l1_dbgmsg( +"meas m#%04d i#%04d p#%04d in %d ms data range status %d range %d\n", + (int)data->meas.cnt, + (int)data->meas.intr, + (int)data->meas.poll_cnt, + (int)stmvl53l1_tv_dif(&data->meas.start_tv, + &data->meas.comp_tv)/1000, + (int)data->meas.range_data.RangeStatus, + (int)data->meas.range_data.RangeMilliMeter); +#endif + /* ready that is not always on each new data event */ + + /* mark data as valid from now */ + data->is_data_valid = true; + + /* wake up sleeping client */ + wake_up_data_waiters(data); + + /* push data to input subsys and only and make val for ioctl*/ + stmvl53l1_input_push_data(data); + stmvl53l1_insert_flush_events_lock(data); + + /* roll time now data got used */ + data->meas.start_tv = data->meas.comp_tv; + data->meas.poll_cnt = 0; + data->meas.err_cnt = 0; +} + + +/** + * * handle interrupt/pusdo irq by polling handling + * + * work lock must be held + * + * @param data driver + * @return 0 on success + */ +static int stmvl53l1_intr_process(struct stmvl53l1_data *data) +{ + uint8_t data_rdy; + int rc = 0; + struct timeval tv_now; + + if (!data->enable_sensor) + goto done; + + data->meas.poll_cnt++; + rc = VL53L1_GetMeasurementDataReady(&data->stdev, &data_rdy); + if (rc) { + vl53l1_errmsg("GetMeasurementDataReady @%d %d, fail\n", + __LINE__, rc); + /* too many successive fail => stop but do not try to do any new + * i/o + */ + goto stop_io; + } + + if (!data_rdy) { + /* FIXME this part to completely skip + * if using interrupt and sure we have + * no false interrupt to handle or no to do any timing check + */ + long poll_us; + + do_gettimeofday(&tv_now); + poll_us = stmvl53l1_tv_dif(&data->meas.start_tv, &tv_now); + if (poll_us > data->timing_budget*4) { + vl53l1_errmsg("we're polling %ld ms too long\n", + poll_us/1000); + /* fixme stop or just warn ? */ + goto stop_io; + } + /* keep trying it could be intr with no processing */ + work_dbg("intr with no data rdy"); + goto done; + } + /* we have data to handle */ + /* first irq after reset has no data so we skip it */ + if (data->is_first_irq) { + data->is_first_irq = false; + + if (data->preset_mode == + VL53L1_PRESETMODE_LOWPOWER_AUTONOMOUS) { + /* + * If VL53L1_GetRangingMeasurementData() + * is not called after + * for the first ranging measurement, + * the thresholds do not seem + * to work for ALP mode + */ + VL53L1_RangingMeasurementData_t RangingMeasurementData; + + /* printk("Test Workaround for ALP mode\n"); */ + VL53L1_GetRangingMeasurementData(&data->stdev, + &RangingMeasurementData); + } + + } else + stmvl53l1_on_newdata_event(data); + /* enable_sensor could change on event handling check again */ + if (data->enable_sensor) { + /* clear interrupt and continue ranging */ + work_dbg("intr clr"); + /* In autonomous mode, bare driver will trigger stop/start + * sequence. In that case it wall call platform delay functions. + * So allow delay in VL53L1_ClearInterruptAndStartMeasurement() + * call. + */ + data->is_delay_allowed = data->allow_hidden_start_stop; + rc = VL53L1_ClearInterruptAndStartMeasurement(&data->stdev); + data->is_delay_allowed = 0; + if (rc) { + /* go to stop but stop any new i/o for dbg */ + vl53l1_errmsg("Cltr intr restart fail %d\n", rc); + goto stop_io; + } + } +done: + return rc; +stop_io: + /* too many successive fail take action => stop but do not try to do + * any new i/o + */ + vl53l1_errmsg("GetDatardy fail stop\n"); + _ctrl_stop(data); + return rc; + +} + +static void stmvl53l1_work_handler(struct work_struct *work) +{ + struct stmvl53l1_data *data; + + data = container_of(work, struct stmvl53l1_data, dwork.work); + work_dbg("enter"); + mutex_lock(&data->work_mutex); + stmvl53l1_intr_process(data); + if (data->poll_mode && data->enable_sensor) { + /* re-sched ourself */ + schedule_delayed_work(&data->dwork, + msecs_to_jiffies(data->poll_delay_ms)); + } + mutex_unlock(&data->work_mutex); +} + +static void stmvl53l1_input_push_data_singleobject(struct stmvl53l1_data *data) +{ + struct input_dev *input = data->input_dev_ps; + VL53L1_RangingMeasurementData_t *meas = &data->meas.single_range_data; + /* + FixPoint1616_t LimitCheckCurrent; + VL53L1_Error st = VL53L1_ERROR_NONE; + */ + vl53l1_dbgmsg("******* FIXME!!! ************\n"); + vl53l1_dbgmsg("Sensor HAL in Lite ranging mode not yet updated\n"); + vl53l1_dbgmsg("******* FIXME!!! ************\n"); + if (meas->TimeStamp > 0 && input != NULL) { + vl53l1_dbgmsg("******* TimeStamp:%d ************\n", meas->TimeStamp); + } + /* Do not send the events till this if fixed properly */ + return; + /* + input_report_abs(input, ABS_DISTANCE, (meas->RangeMilliMeter + 5) / 10); + input_report_abs(input, ABS_HAT0X, meas->TimeStamp / 1000); + input_report_abs(input, ABS_HAT0Y, (meas->TimeStamp % 1000) * 1000); + input_report_abs(input, ABS_HAT1X, meas->RangeMilliMeter); + input_report_abs(input, ABS_HAT1Y, meas->RangeStatus); + input_report_abs(input, ABS_HAT2X, meas->SignalRateRtnMegaCps); + input_report_abs(input, ABS_HAT2Y, meas->AmbientRateRtnMegaCps); + input_report_abs(input, ABS_HAT3X, meas->SigmaMilliMeter); + st = VL53L1_GetLimitCheckCurrent(&data->stdev, + VL53L1_CHECKENABLE_SIGMA_FINAL_RANGE, &LimitCheckCurrent); + if (st == VL53L1_ERROR_NONE) + input_report_abs(input, ABS_WHEEL, LimitCheckCurrent); + input_report_abs(input, ABS_TILT_Y, meas->EffectiveSpadRtnCount); + input_report_abs(input, ABS_TOOL_WIDTH, meas->RangeQualityLevel); + + input_sync(input); + */ +} + +static void stmvl53l1_input_push_data_multiobject(struct stmvl53l1_data *data) +{ + VL53L1_MultiRangingData_t *mmeas = &data->meas.multi_range_data; + int i; + int rc; + VL53L1_TargetRangeData_t *meas_array[4]; + VL53L1_CalibrationData_t calibration_data; + struct timeval tv; + struct input_dev *input = data->input_dev_ps; + + do_gettimeofday(&tv); + + for (i = 0; i < 4; i++) + meas_array[i] = &mmeas->RangeData[i]; + + /************************************************************* + * INPUT EVENT CODE L1/L3 Data + ABS_HAT0X Time in Sec(32) + ABS_HAT0Y Time in uSec(32) + ABS_HAT1X Obj0_Distance(16) : Obj0_Sigma(16) + ABS_HAT1Y Obj0_MinRange(16) : Obj0_MaxRange(16) + ABS_HAT2X Obj1_Distance(16) : Obj1_Sigma(16) + ABS_HAT2Y Obj1_ MinRange (16) : Obj1_ MaxRange (16) + ABS_HAT3X Obj0_SignalRate_Spad(32) + ABS_HAT3Y Obj1_SignalRate_Spad(32) + ABS_WHEEL AmbientRate(32) + ABS_BRAKE EffectiveSpadRtnCount(16):RangeStatus_1(8): + Range_status_0(8) + ABS_TILT_X XtalkChange(8) :StreamCount(8) : + NumberofObjects(2) : RoiNumber(4) : + RoiStatus(2) + ABS_TILT_Y DMAX + ABS_TOOL_WIDTH XtalkValue + ABS_DISTANCE + ABS_THROTTLE + ABS_RUDDER + ABS_MISC + ABS_VOLUME + ************************************************************/ + + rc = VL53L1_GetCalibrationData(&data->stdev, &calibration_data); + if (rc) { + //This should not happen + vl53l1_errmsg("%d error:%d\n", __LINE__, rc); + return; + } + + //ABS_HAT0X - Time in Sec(32) + + input_report_abs(input, ABS_HAT0X, tv.tv_sec); + //vl53l1_dbgmsg("ABS_HAT0X : %ld, %zu\n", tv.tv_sec, sizeof(tv.tv_sec)); + //ABS_HAT0Y - Time in uSec(32) + //REVISIT : The following code may cause loss of data due to + //8 bytes to 32 bits conversion + input_report_abs(input, ABS_HAT0Y, tv.tv_usec); + //vl53l1_dbgmsg("ABS_HAT0Y : %ld\n", tv.tv_usec); + + if (mmeas->NumberOfObjectsFound == 0) { + //ABS_TILT_X XtalkChange(8) :StreamCount(8) : + //Number of Objects(2) : RoiNumber(4) : RoiStatus(2) + input_report_abs(input, ABS_TILT_X, + (mmeas->HasXtalkValueChanged << 16) + | (mmeas->StreamCount << 8) + | ((mmeas->NumberOfObjectsFound & 0x3) << 6) + | ((mmeas->RoiNumber & 0xF) << 2) + | (mmeas->RoiStatus & 0x3)); + /*vl53l1_dbgmsg("ABS_TILT_X :(%d):(%d):(%d):(%d):(%d)\n\n", + mmeas->HasXtalkValueChanged, + mmeas->StreamCount, + mmeas->NumberOfObjectsFound, + mmeas->RoiNumber, + mmeas->RoiStatus + );*/ + + + //ABS_TILT_Y DMAX + input_report_abs(input, ABS_TILT_Y, mmeas->DmaxMilliMeter); + //vl53l1_dbgmsg("ABS_TILT_Y DMAX = %d\n", mmeas->DmaxMilliMeter); + + //ABS_TOOL_WIDTH + input_report_abs(input, ABS_TOOL_WIDTH, + calibration_data.customer.algo__crosstalk_compensation_plane_offset_kcps); + //vl53l1_dbgmsg("ABS_TOOL_WIDTH Xtalk = %d\n", + // calibration_data.customer.algo__crosstalk_compensation_plane_offset_kcps); + + + input_sync(input); + return; + } + + //ABS_HAT1X - Obj0_Distance(16) : Obj0_Sigma(16) + input_report_abs(input, ABS_HAT1X, meas_array[0]->RangeMilliMeter << 16 + | (meas_array[0]->SigmaMilliMeter/65536)); + /*vl53l1_dbgmsg("ABS_HAT1X : 0x%X(%d:%d)\n", + meas_array[0]->RangeMilliMeter << 16 + | (meas_array[0]->SigmaMilliMeter/65536), + meas_array[0]->RangeMilliMeter, + (meas_array[0]->SigmaMilliMeter/65536));*/ + + //ABS_HAT1Y - Obj0_MinRange(16) : Obj0_MaxRange(16) + input_report_abs(input, ABS_HAT1Y, + meas_array[0]->RangeMinMilliMeter << 16 + | meas_array[0]->RangeMaxMilliMeter); + + /*vl53l1_dbgmsg("ABS_HAT1Y : 0x%X(%d:%d)\n", + meas_array[0]->RangeMinMilliMeter << 16 + | meas_array[0]->RangeMaxMilliMeter, + meas_array[0]->RangeMinMilliMeter, + meas_array[0]->RangeMaxMilliMeter);*/ + + if (mmeas->NumberOfObjectsFound > 1) { + //ABS_HAT2X - Obj1_Distance(16) : Obj1_Sigma(16) + input_report_abs(input, ABS_HAT2X, + meas_array[1]->RangeMilliMeter << 16 + | (meas_array[1]->SigmaMilliMeter/65536)); + /*vl53l1_dbgmsg("ABS_HAT2X : 0x%x(%d:%d)\n", + meas_array[1]->RangeMilliMeter << 16 + | (meas_array[1]->SigmaMilliMeter/65536), + meas_array[1]->RangeMilliMeter, + (meas_array[1]->SigmaMilliMeter/65536));*/ + + //ABS_HAT2Y - Obj1_ MinRange (16) : Obj1_ MaxRange (16) + input_report_abs(input, ABS_HAT2Y, + meas_array[1]->RangeMinMilliMeter << 16 + | meas_array[1]->RangeMaxMilliMeter); + + /*vl53l1_dbgmsg("ABS_HAT1Y : 0x%X(%d:%d)\n", + meas_array[1]->RangeMinMilliMeter << 16 + | meas_array[1]->RangeMaxMilliMeter, + meas_array[1]->RangeMinMilliMeter, + meas_array[1]->RangeMaxMilliMeter);*/ + + } + + // ABS_HAT3X - Obj0_SignalRate_Spad(32) + input_report_abs(input, ABS_HAT3X, + meas_array[0]->SignalRateRtnMegaCps); + //vl53l1_dbgmsg("ABS_HAT3X : SignalRateRtnMegaCps_0(%d)\n", + // meas_array[0]->SignalRateRtnMegaCps); + if (mmeas->NumberOfObjectsFound > 1) { + //ABS_HAT3Y - Obj1_SignalRate_Spad(32) + input_report_abs(input, ABS_HAT3Y, + meas_array[1]->SignalRateRtnMegaCps); + // vl53l1_dbgmsg("ABS_HAT3Y : SignalRateRtnMegaCps_1(%d)\n", + // meas_array[1]->SignalRateRtnMegaCps); + } + //ABS_WHEEL - AmbientRate(32) + input_report_abs(input, ABS_WHEEL, + meas_array[0]->AmbientRateRtnMegaCps); + //vl53l1_dbgmsg("ABS_WHEEL : AmbRate = %d\n", + // meas_array[0]->AmbientRateRtnMegaCps); + + + //ABS_BRAKE - EffectiveSpadRtnCount(16):RangeStatus_3(1): + //Range_status_2(0) + input_report_abs(input, ABS_BRAKE, + mmeas->EffectiveSpadRtnCount << 16 + | ((meas_array[1]->RangeStatus) << 8) + | meas_array[0]->RangeStatus); + + /*vl53l1_dbgmsg("ABS_BRAKE : (%d):(%d):(%d)\n", + mmeas->EffectiveSpadRtnCount, + meas_array[1]->RangeStatus, + meas_array[0]->RangeStatus); + + vl53l1_dbgmsg("ABS_BRAKE : 0x%X\n", + (mmeas->EffectiveSpadRtnCount & 0xFFFF) << 16 + | ((meas_array[1]->RangeStatus) << 8) + | meas_array[0]->RangeStatus);*/ + //ABS_TILT_X XtalkChange(8) :StreamCount(8) : + //Number of Objects(2) : RoiNumber(4) : RoiStatus(2) + //On maint2 driver, the max possible range status value is 14. + //Revisit If this changes in future + input_report_abs(input, ABS_TILT_X, + (mmeas->HasXtalkValueChanged << 16) + | (mmeas->StreamCount << 8) + | ((mmeas->NumberOfObjectsFound & 0x3) << 6) + | ((mmeas->RoiNumber & 0xF) << 2) + | (mmeas->RoiStatus & 0x3)); + /*vl53l1_dbgmsg("ABS_TILT_X :(%d):(%d):(%d):(%d):(%d)\n", + mmeas->HasXtalkValueChanged, + mmeas->StreamCount, + mmeas->NumberOfObjectsFound, + mmeas->RoiNumber, + mmeas->RoiStatus + );*/ + //ABS_TILT_Y DMAX + input_report_abs(input, ABS_TILT_Y, mmeas->DmaxMilliMeter); + //vl53l1_dbgmsg("ABS_TILT_Y DMAX = %d\n", mmeas->DmaxMilliMeter); + + //ABS_TOOL_WIDTH + input_report_abs(input, ABS_TOOL_WIDTH, + calibration_data.customer.algo__crosstalk_compensation_plane_offset_kcps); + //vl53l1_dbgmsg("ABS_TOOL_WIDTH Xtalk = %d\n\n", + // calibration_data.customer.algo__crosstalk_compensation_plane_offset_kcps); + input_sync(input); +} + +static void stmvl53l1_input_push_data(struct stmvl53l1_data *data) +{ + /* use get data method based on active mode */ + switch (data->preset_mode) { + case VL53L1_PRESETMODE_LITE_RANGING: + case VL53L1_PRESETMODE_AUTONOMOUS: + case VL53L1_PRESETMODE_LOWPOWER_AUTONOMOUS: + stmvl53l1_input_push_data_singleobject(data); + break; + default: + /* VL53L1_PRESETMODE_RANGING: + * VL53L1_PRESETMODE_MULTIZONES_SCANNING: + */ + stmvl53l1_input_push_data_multiobject(data); + } +} + +static int stmvl53l1_input_setup(struct stmvl53l1_data *data) +{ + int rc; + struct input_dev *idev; + /* Register to Input Device */ + idev = input_allocate_device(); + if (idev == NULL) { + rc = -ENOMEM; + vl53l1_errmsg("%d error:%d\n", __LINE__, rc); + goto exit_err; + } + /* setup all event */ + set_bit(EV_ABS, idev->evbit); + + input_set_abs_params(idev, ABS_DISTANCE, 0, 0xff, 0, 0); + + input_set_abs_params(idev, ABS_HAT0X, 0, 0xffffffff, 0, 0); + input_set_abs_params(idev, ABS_HAT0Y, 0, 0xffffffff, 0, 0); + input_set_abs_params(idev, ABS_HAT1X, 0, 0xffffffff, 0, 0); + input_set_abs_params(idev, ABS_HAT1Y, 0, 0xffffffff, 0, 0); + input_set_abs_params(idev, ABS_HAT2X, 0, 0xffffffff, 0, 0); + input_set_abs_params(idev, ABS_HAT2Y, 0, 0xffffffff, 0, 0); + input_set_abs_params(idev, ABS_HAT3X, 0, 0xffffffff, 0, 0); + input_set_abs_params(idev, ABS_HAT3Y, 0, 0xffffffff, 0, 0); + input_set_abs_params(idev, ABS_WHEEL, 0, 0xffffffff, 0, 0); + + input_set_abs_params(idev, ABS_TILT_Y, 0, 0xffffffff, 0, 0); + + input_set_abs_params(idev, ABS_BRAKE, 0, 0xffffffff, 0, 0); + input_set_abs_params(idev, ABS_TILT_X, 0, 0xffffffff, 0, 0); + input_set_abs_params(idev, ABS_TOOL_WIDTH, 0, 0xffffffff, 0, 0); + + input_set_abs_params(idev, ABS_THROTTLE, 0, 0xffffffff, 0, 0); + input_set_abs_params(idev, ABS_RUDDER, 0, 0xffffffff, 0, 0); + input_set_abs_params(idev, ABS_MISC, 0, 0xffffffff, 0, 0); + + input_set_abs_params(idev, ABS_VOLUME, 0, 0xffffffff, 0, 0); + input_set_abs_params(idev, ABS_GAS, 0, 0xffffffff, 0, 0); + + idev->name = "STM VL53L1 proximity sensor"; + rc = input_register_device(idev); + if (rc) { + rc = -ENOMEM; + vl53l1_errmsg("%d error:%d\n", __LINE__, rc); + goto exit_free_dev_ps; + } + /* setup drv data */ + input_set_drvdata(idev, data); + data->input_dev_ps = idev; + return 0; + + +exit_free_dev_ps: + input_free_device(data->input_dev_ps); +exit_err: + return rc; +} + +/** + * handler to be called by interface module on interrupt + * + * managed poll/irq filtering in case poll/irq can be soft forced + * and the module side still fire interrupt + * + * @param data + * @return 0 if all ok else for error + */ +int stmvl53l1_intr_handler(struct stmvl53l1_data *data) +{ + int rc; + + mutex_lock(&data->work_mutex); + + /* handle it only if if we are not stopped */ + if (data->enable_sensor) { + rc = stmvl53l1_intr_process(data); + } else { + /* it's likely race/last unhandled interrupt after + * stop. + * Such dummy irq also occured during offset and crosstalk + * calibration procedures. + */ + //vl53l1_dbgmsg("got intr but not on (dummy or calibration)\n"); + rc = 0; + } + + mutex_unlock(&data->work_mutex); + return rc; +} + + +/** + * One time device setup + * + * call by bus (i2c/cci) level probe to finalize non bus related device setup + * + * @param data The device data + * @return 0 on success + */ +int stmvl53l1_setup(struct stmvl53l1_data *data) +{ + int rc = 0; + VL53L1_DeviceInfo_t dev_info; + + vl53l1_dbgmsg("Enter\n"); + + /* acquire an id */ + data->id = allocate_dev_id(); + if (data->id < 0) { + vl53l1_errmsg("too many device already created"); + return -1; + } + vl53l1_dbgmsg("Dev id %d is @%p\n", data->id, data); + stmvl53l1_dev_table[data->id] = data; + + /* init mutex */ + /* mutex_init(&data->update_lock); */ + mutex_init(&data->work_mutex); + + /* init work handler */ + INIT_DELAYED_WORK(&data->dwork, stmvl53l1_work_handler); + + /* init ipp side */ + stmvl53l1_ipp_setup(data); + + data->force_device_on_en = force_device_on_en_default; + data->reset_state = 1; + data->is_calibrating = false; + data->last_error = VL53L1_ERROR_NONE; + data->is_device_remove = false; + + rc = stmvl53l1_module_func_tbl.power_up(data->client_object); + if (rc) { + vl53l1_errmsg("%d,error rc %d\n", __LINE__, rc); + goto exit_ipp_cleanup; + } + rc = reset_release(data); + if (rc) + goto exit_ipp_cleanup; + + rc = stmvl53l1_input_setup(data); + if (rc) + goto exit_ipp_cleanup; + + /* init blocking ioctl stuff */ + INIT_LIST_HEAD(&data->simple_data_reader_list); + INIT_LIST_HEAD(&data->mz_data_reader_list); + init_waitqueue_head(&data->waiter_for_data); + data->is_data_valid = false; + + /* Register sysfs hooks under input dev */ + rc = sysfs_create_group(&data->input_dev_ps->dev.kobj, + &stmvl53l1_attr_group); + if (rc) { + rc = -ENOMEM; + vl53l1_errmsg("%d error:%d\n", __LINE__, rc); + goto exit_unregister_dev_ps; + } + rc = sysfs_create_bin_file(&data->input_dev_ps->dev.kobj, + &stmvl53l1_calib_data_attr); + if (rc) { + rc = -ENOMEM; + vl53l1_errmsg("%d error:%d\n", __LINE__, rc); + goto exit_unregister_dev_ps; + } + rc = sysfs_create_bin_file(&data->input_dev_ps->dev.kobj, + &stmvl53l1_zone_calib_data_attr); + if (rc) { + rc = -ENOMEM; + vl53l1_errmsg("%d error:%d\n", __LINE__, rc); + goto exit_unregister_dev_ps; + } + + data->enable_sensor = 0; + + data->poll_delay_ms = STMVL53L1_CFG_POLL_DELAY_MS; + data->timing_budget = STMVL53L1_CFG_TIMING_BUDGET_US; + data->preset_mode = STMVL53L1_CFG_DEFAULT_MODE; + //songyt add default range roi + if(data->preset_mode == VL53L1_PRESETMODE_MULTIZONES_SCANNING + /*|| data->preset_mode == VL53L1_PRESETMODE_RANGING*/){ + data->roi_cfg.NumberOfRoi = 4; + data->roi_cfg.UserRois[0].TopLeftX = 0; + data->roi_cfg.UserRois[0].TopLeftY = 15; + data->roi_cfg.UserRois[0].BotRightX = 7; + data->roi_cfg.UserRois[0].BotRightY = 8; + + data->roi_cfg.UserRois[1].TopLeftX = 8; + data->roi_cfg.UserRois[1].TopLeftY = 15; + data->roi_cfg.UserRois[1].BotRightX = 15; + data->roi_cfg.UserRois[1].BotRightY = 8; + + data->roi_cfg.UserRois[2].TopLeftX = 0; + data->roi_cfg.UserRois[2].TopLeftY = 7; + data->roi_cfg.UserRois[2].BotRightX = 7; + data->roi_cfg.UserRois[2].BotRightY = 0; + + data->roi_cfg.UserRois[3].TopLeftX = 8; + data->roi_cfg.UserRois[3].TopLeftY = 7; + data->roi_cfg.UserRois[3].BotRightX = 15; + data->roi_cfg.UserRois[3].BotRightY = 0; + }else{ + data->roi_cfg.NumberOfRoi = 0; + } + //end + data->distance_mode = STMVL53L1_CFG_DEFAULT_DISTANCE_MODE; + data->crosstalk_enable = STMVL53L1_CFG_DEFAULT_CROSSTALK_ENABLE; + data->output_mode = STMVL53L1_CFG_DEFAULT_OUTPUT_MODE; + data->offset_correction_mode = + STMVL53L1_CFG_DEFAULT_OFFSET_CORRECTION_MODE; + stmvl53l1_setup_auto_config(data); + data->dmax_mode = STMVL53L1_CFG_DEFAULT_DMAX_MODE; + data->smudge_correction_mode = + STMVL53L1_CFG_DEFAULT_SMUDGE_CORRECTION_MODE; + data->current_roi_id = 0; + data->is_xtalk_value_changed = false; + + data->is_delay_allowed = true; + /* need to be done once */ + rc = VL53L1_DataInit(&data->stdev); + data->is_delay_allowed = false; + if (rc) { + vl53l1_errmsg("VL53L1_DataInit %d\n", rc); + goto exit_unregister_dev_ps; + } + + rc = VL53L1_GetDeviceInfo(&data->stdev, &dev_info); + if (rc) { + vl53l1_errmsg("VL53L1_GetDeviceInfo %d\n", rc); + goto exit_unregister_dev_ps; + } + vl53l1_errmsg("device name %s\ntype %s\n", + dev_info.Name, dev_info.Type); + + /* get managed data here */ + rc = VL53L1_GetDmaxReflectance(&data->stdev, &data->dmax_reflectance); + if (rc) { + vl53l1_errmsg("VL53L1_GetDmaxReflectance %d\n", rc); + goto exit_unregister_dev_ps; + } + rc = VL53L1_GetOpticalCenter(&data->stdev, &data->optical_offset_x, + &data->optical_offset_y); + if (rc) { + vl53l1_errmsg("VL53L1_GetOpticalCenter %d\n", rc); + goto exit_unregister_dev_ps; + } + + /* set tuning from stmvl53l1_tunings.h */ + rc = setup_tunings(data); + if (rc) { + vl53l1_errmsg("setup_tunings %d\n", rc); + goto exit_unregister_dev_ps; + } + + /* if working in interrupt ask intr to enable and hook the handler */ + data->poll_mode = 0; + rc = stmvl53l1_module_func_tbl.start_intr(data->client_object, + &data->poll_mode); + if (rc < 0) { + vl53l1_errmsg("can't start no intr\n"); + goto exit_unregister_dev_ps; + } + + data->is_first_irq = true; + data->is_first_start_done = false; + data->is_delay_allowed = false; + + /* to register as a misc device */ + data->miscdev.minor = MISC_DYNAMIC_MINOR; + /* multiple dev name use id in name but 1st */ + if (data->id == 0) + strcpy(data->name, VL53L1_MISC_DEV_NAME); + else + sprintf(data->name, "%s%d", VL53L1_MISC_DEV_NAME, data->id); + + data->miscdev.name = data->name; + data->miscdev.fops = &stmvl53l1_ranging_fops; + vl53l1_errmsg("Misc device registration name:%s\n", data->miscdev.name); + rc = misc_register(&data->miscdev); + if (rc != 0) { + vl53l1_errmsg("misc dev reg fail\n"); + goto exit_unregister_dev_ps; + } + /* bring back device under reset */ + reset_hold(data); + rc = stmvl53l1_module_func_tbl.power_down(data->client_object); + if (rc) { + vl53l1_errmsg("%d,error1 power_down rc %d\n", __LINE__, rc); + } + + return 0; + +exit_unregister_dev_ps: + sysfs_remove_bin_file(&data->input_dev_ps->dev.kobj, + &stmvl53l1_zone_calib_data_attr); + sysfs_remove_bin_file(&data->input_dev_ps->dev.kobj, + &stmvl53l1_calib_data_attr); + sysfs_remove_group(&data->input_dev_ps->dev.kobj, + &stmvl53l1_attr_group); + input_unregister_device(data->input_dev_ps); +exit_ipp_cleanup: + stmvl53l1_ipp_cleanup(data); + rc = stmvl53l1_module_func_tbl.power_down(data->client_object); + if (rc) { + vl53l1_errmsg("%d,error2 power_down rc %d\n", __LINE__, rc); + } + + return rc; +} + + +void stmvl53l1_cleanup(struct stmvl53l1_data *data) +{ + int rc; + + vl53l1_dbgmsg("enter\n"); + rc = _ctrl_stop(data); + if (rc < 0) + vl53l1_errmsg("stop failed %d aborting anyway\n", rc); + + if (data->input_dev_ps) { + vl53l1_dbgmsg("to remove sysfs group\n"); + sysfs_remove_group(&data->input_dev_ps->dev.kobj, + &stmvl53l1_attr_group); + sysfs_remove_bin_file(&data->input_dev_ps->dev.kobj, + &stmvl53l1_calib_data_attr); + sysfs_remove_bin_file(&data->input_dev_ps->dev.kobj, + &stmvl53l1_zone_calib_data_attr); + + vl53l1_dbgmsg("to unregister input dev\n"); + input_unregister_device(data->input_dev_ps); + } + + if (!IS_ERR(data->miscdev.this_device) && + data->miscdev.this_device != NULL) { + vl53l1_dbgmsg("to unregister misc dev\n"); + misc_deregister(&data->miscdev); + } + stmvl53l1_ipp_cleanup(data); + /* be sure device is put under reset */ + data->force_device_on_en = false; + reset_hold(data); + stmvl53l1_module_func_tbl.power_down(data->client_object); + vl53l1_dbgmsg("done\n"); + deallocate_dev_id(data->id); + data->is_device_remove = true; +} + +#ifdef CONFIG_PM_SLEEP +void stmvl53l1_pm_suspend_stop(struct stmvl53l1_data *data) +{ + int rc; + + vl53l1_dbgmsg("Enter\n"); + + rc = _ctrl_stop(data); + if (rc < 0) + vl53l1_errmsg("stop failed %d aborting anyway\n", rc); + + vl53l1_dbgmsg("done\n"); +} +#endif + +static long stmvl53l1_ioctl(struct file *file, + unsigned int cmd, unsigned long arg) +{ + long ret; + struct stmvl53l1_data *data = + container_of(file->private_data, + struct stmvl53l1_data, miscdev); + ret = stmvl53l1_ioctl_handler(data, cmd, arg, (void __user *)arg); + return ret; +} + +static int __init stmvl53l1_init(void) +{ + int rc = 0; + rc = stmvl53l1_ipp_init(); + vl53l1_dbgmsg("Enter,rc=%d\n",rc); + if (rc){ + stmvl53l1_ipp_exit(); + return rc; + } + ipp_inited = true; + return rc; +} + +static int __init stmvl53l1_late_init(void) +{ + int rc = 0; + + vl53l1_dbgmsg("Enter,rc=%d\n",rc); + rc = 0; + /* + if (rc) + goto done; + */ + /* i2c/cci client specific init function */ + rc = stmvl53l1_module_func_tbl.init(); + if (rc){ + if(ipp_inited) + stmvl53l1_ipp_exit(); + ipp_inited = false; + } +/* +done: +*/ + vl53l1_dbgmsg("End %d\n", rc); + + return rc; +} + +static void __exit stmvl53l1_exit(void) +{ + vl53l1_dbgmsg("Enter\n"); + stmvl53l1_module_func_tbl.deinit(NULL); + if (stmvl53l1_module_func_tbl.clean_up != NULL) + stmvl53l1_module_func_tbl.clean_up(); + if(ipp_inited) + stmvl53l1_ipp_exit(); + vl53l1_dbgmsg("End\n"); +} + +/* MODULE_DEVICE_TABLE(i2c, stmvl53l1_id); */ +MODULE_AUTHOR("STMicroelectronics Imaging Division"); +MODULE_DESCRIPTION("ST FlightSense Time-of-Flight sensor driver"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(DRIVER_VERSION); + +module_init(stmvl53l1_init); +late_initcall(stmvl53l1_late_init); +module_exit(stmvl53l1_exit); diff --git a/drivers/input/misc/vl53L1/lito/stmvl53l1_tunings.h b/drivers/input/misc/vl53L1/lito/stmvl53l1_tunings.h new file mode 100644 index 000000000000..6a92a3b2c3c2 --- /dev/null +++ b/drivers/input/misc/vl53L1/lito/stmvl53l1_tunings.h @@ -0,0 +1,42 @@ +/************************************************************************** + * Copyright (c) 2016, STMicroelectronics - All Rights Reserved + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ****************************************************************************/ + +/* + * THIS IS A GENERATED FILE + */ + +#ifndef STMVL53L1_TUNINGS_H +#define STMVL53L1_TUNINGS_H + +static const int tunings[][2] = { +}; + +#endif /* STMVL53L1_TUNINGS_H */ diff --git a/drivers/input/misc/vl53L1/lito/vl53l1_platform.h b/drivers/input/misc/vl53L1/lito/vl53l1_platform.h new file mode 100644 index 000000000000..742e25aa66da --- /dev/null +++ b/drivers/input/misc/vl53L1/lito/vl53l1_platform.h @@ -0,0 +1,444 @@ +/************************************************************************** + * Copyright (c) 2016, STMicroelectronics - All Rights Reserved + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ****************************************************************************/ + + +#ifndef _VL53L1_PLATFORM_H_ +#define _VL53L1_PLATFORM_H_ + +#include "vl53l1_ll_def.h" +#include "vl53l1_platform_log.h" + +#define VL53L1_IPP_API +#include "vl53l1_platform_ipp_imports.h" +#include "vl53l1_platform_user_data.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +/** + * @file vl53l1_platform.h + * + * @brief All end user OS/platform/application porting + */ + + + +/** + * @brief Initialise platform comms. + * + * @param[in] pdev : pointer to device structure (device handle) + * @param[in] comms_type : selects between I2C and SPI + * @param[in] comms_speed_khz : unsigned short containing the I2C speed in kHz + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_CommsInitialise( + VL53L1_Dev_t *pdev, + uint8_t comms_type, + uint16_t comms_speed_khz); + + +/** + * @brief Close platform comms. + * + * @param[in] pdev : pointer to device structure (device handle) + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_CommsClose( + VL53L1_Dev_t *pdev); + + +/** + * @brief Writes the supplied byte buffer to the device + * + * @param[in] pdev : pointer to device structure (device handle) + * @param[in] index : uint16_t register index value + * @param[in] pdata : pointer to uint8_t (byte) buffer containing the data + * to be written + * @param[in] count : number of bytes in the supplied byte buffer + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_WriteMulti( + VL53L1_Dev_t *pdev, + uint16_t index, + uint8_t *pdata, + uint32_t count); + + +/** + * @brief Reads the requested number of bytes from the device + * + * @param[in] pdev : pointer to device structure (device handle) + * @param[in] index : uint16_t register index value + * @param[out] pdata : pointer to the uint8_t (byte) buffer to store read + * data + * @param[in] count : number of bytes to read + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_ReadMulti( + VL53L1_Dev_t *pdev, + uint16_t index, + uint8_t *pdata, + uint32_t count); + + +/** + * @brief Writes a single byte to the device + * + * @param[in] pdev : pointer to device structure (device handle) + * @param[in] index : uint16_t register index value + * @param[in] data : uint8_t data value to write + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_WrByte( + VL53L1_Dev_t *pdev, + uint16_t index, + uint8_t data); + + +/** + * @brief Writes a single word (16-bit unsigned) to the device + * + * Manages the big-endian nature of the device register map + * (first byte written is the MS byte). + * + * @param[in] pdev : pointer to device structure (device handle) + * @param[in] index : uint16_t register index value + * @param[in] data : uin16_t data value write + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_WrWord( + VL53L1_Dev_t *pdev, + uint16_t index, + uint16_t data); + + +/** + * @brief Writes a single dword (32-bit unsigned) to the device + * + * Manages the big-endian nature of the device register map + * (first byte written is the MS byte). + * + * @param[in] pdev : pointer to device structure (device handle) + * @param[in] index : uint16_t register index value + * @param[in] data : uint32_t data value to write + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_WrDWord( + VL53L1_Dev_t *pdev, + uint16_t index, + uint32_t data); + + + +/** + * @brief Reads a single byte from the device + * + * @param[in] pdev : pointer to device structure (device handle) + * @param[in] index : uint16_t register index + * @param[out] pdata : pointer to uint8_t data value + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + * + */ + +VL53L1_Error VL53L1_RdByte( + VL53L1_Dev_t *pdev, + uint16_t index, + uint8_t *pdata); + + +/** + * @brief Reads a single word (16-bit unsigned) from the device + * + * Manages the big-endian nature of the device (first byte read is the MS byte). + * + * @param[in] pdev : pointer to device structure (device handle) + * @param[in] index : uint16_t register index value + * @param[out] pdata : pointer to uint16_t data value + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_RdWord( + VL53L1_Dev_t *pdev, + uint16_t index, + uint16_t *pdata); + + +/** + * @brief Reads a single dword (32-bit unsigned) from the device + * + * Manages the big-endian nature of the device (first byte read is the MS byte). + * + * @param[in] pdev : pointer to device structure (device handle) + * @param[in] index : uint16_t register index value + * @param[out] pdata : pointer to uint32_t data value + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_RdDWord( + VL53L1_Dev_t *pdev, + uint16_t index, + uint32_t *pdata); + + + +/** + * @brief Implements a programmable wait in us + * + * @param[in] pdev : pointer to device structure (device handle) + * @param[in] wait_us : integer wait in micro seconds + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_WaitUs( + VL53L1_Dev_t *pdev, + int32_t wait_us); + + +/** + * @brief Implements a programmable wait in ms + * + * @param[in] pdev : pointer to device structure (device handle) + * @param[in] wait_ms : integer wait in milliseconds + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_WaitMs( + VL53L1_Dev_t *pdev, + int32_t wait_ms); + + +/** + * @brief Get the frequency of the timer used for ranging results time stamps + * + * @param[out] ptimer_freq_hz : pointer for timer frequency + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_GetTimerFrequency(int32_t *ptimer_freq_hz); + +/** + * @brief Get the timer value in units of timer_freq_hz (see + * VL53L1_get_timestamp_frequency()) + * + * @param[out] ptimer_count : pointer for timer count value + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_GetTimerValue(int32_t *ptimer_count); + + +/** + * @brief Set the mode of a specified GPIO pin + * + * @param pin - an identifier specifying the pin being modified - defined per + * platform + * + * @param mode - an identifier specifying the requested mode - defined per + * platform + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_GpioSetMode(uint8_t pin, uint8_t mode); + + +/** + * @brief Set the value of a specified GPIO pin + * + * @param pin - an identifier specifying the pin being modified - defined per + * platform + * + * @param value - a value to set on the GPIO pin - typically 0 or 1 + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_GpioSetValue(uint8_t pin, uint8_t value); + + +/** + * @brief Get the value of a specified GPIO pin + * + * @param pin - an identifier specifying the pin being modified - defined per + * platform + * + * @param pvalue - a value retrieved from the GPIO pin - typically 0 or 1 + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_GpioGetValue(uint8_t pin, uint8_t *pvalue); + + +/** + * @brief Sets and clears the XShutdown pin on the Ewok + * + * @param value - the value for xshutdown - 0 = in reset, 1 = operational + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_GpioXshutdown(uint8_t value); + + +/** + * @brief Sets and clears the Comms Mode pin (NCS) on the Ewok + * + * @param value - the value for comms select - 0 = I2C, 1 = SPI + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_GpioCommsSelect(uint8_t value); + + +/** + * @brief Enables and disables the power to the Ewok module + * + * @param value - the state of the power supply - 0 = power off, 1 = power on + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_GpioPowerEnable(uint8_t value); + +/** + * @brief Enables callbacks to the supplied funtion pointer when Ewok interrupts + * ocurr + * + * @param function - a function callback supplies by the caller, for interrupt + * notification + * @param edge_type - falling edge or rising edge interrupt detection + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_GpioInterruptEnable(void (*function)(void), + uint8_t edge_type); + + +/** + * @brief Disables the callback on Ewok interrupts + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_GpioInterruptDisable(void); + + +/* + * @brief Gets current system tick count in [ms] + * + * @return time_ms : current time in [ms] + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_GetTickCount( + uint32_t *ptime_ms); + + +/** + * @brief Register "wait for value" polling routine + * + * Port of the V2WReg Script function WaitValueMaskEx() + * + * @param[in] pdev : pointer to device structure (device handle) + * @param[in] timeout_ms : timeout in [ms] + * @param[in] index : uint16_t register index value + * @param[in] value : value to wait for + * @param[in] mask : mask to be applied before comparison with value + * @param[in] poll_delay_ms : polling delay been each read transaction in [ms] + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_WaitValueMaskEx( + VL53L1_Dev_t *pdev, + uint32_t timeout_ms, + uint16_t index, + uint8_t value, + uint8_t mask, + uint32_t poll_delay_ms); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/drivers/input/misc/vl53L1/lito/vl53l1_platform_ipp.h b/drivers/input/misc/vl53L1/lito/vl53l1_platform_ipp.h new file mode 100644 index 000000000000..b187272fe7b3 --- /dev/null +++ b/drivers/input/misc/vl53L1/lito/vl53l1_platform_ipp.h @@ -0,0 +1,188 @@ +/************************************************************************** + * Copyright (c) 2016, STMicroelectronics - All Rights Reserved + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ****************************************************************************/ + + +#ifndef _VL53L1_PLATFORM_IPP_H_ +#define _VL53L1_PLATFORM_IPP_H_ + +#include "vl53l1_ll_def.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +/** + * @file vl53l1_platform_ipp.h + * + * @brief EwokPlus25 IPP Wrapper Functions + */ + +/** + * @brief IPP Wrapper call for histogram post processing + * + * + * @param[in] Dev : Device handle + * @param[in] pdmax_cal : DMAX calibration data + * @param[in] pdmax_cfg : DMAX configuration data + * @param[in] ppost_cfg : VL53L1_hist_post_process_config_t + * @param[in] pbins : Input histogram raw bin data + * @param[in] pxtalk : Cross talk histogram data + * @param[out] presults : Output VL53L1_range_results_t + * structure + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_ipp_hist_process_data( + VL53L1_DEV Dev, + VL53L1_dmax_calibration_data_t *pdmax_cal, + VL53L1_hist_gen3_dmax_config_t *pdmax_cfg, + VL53L1_hist_post_process_config_t *ppost_cfg, + VL53L1_histogram_bin_data_t *pbins, + VL53L1_xtalk_histogram_data_t *pxtalk, + VL53L1_range_results_t *presults); + + +/** + * @brief IPP Wrapper call for histogram ambient dmax calc + * + * The target reflectance in percent for the DMAX calculation + * is set by target_reflectance input + * + * The fixed point format is 7.2 + * + * @param[in] Dev : Device handle + * @param[in] target_reflectance : target reflectance to report ambient DMAX + * Percentage in 7.2 fixed point format + * @param[in] pdmax_cal : DMAX calibration data + * @param[in] pdmax_cfg : DMAX configuration data + * @param[in] pbins : Input histogram raw bin data + * @param[out] pambient_dmax_mm : Output ambient DMAX distance in [mm] + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_ipp_hist_ambient_dmax( + VL53L1_DEV Dev, + uint16_t target_reflectance, + VL53L1_dmax_calibration_data_t *pdmax_cal, + VL53L1_hist_gen3_dmax_config_t *pdmax_cfg, + VL53L1_histogram_bin_data_t *pbins, + int16_t *pambient_dmax_mm); + + +/** + * @brief IPP Wrapper call for xtalk calibration post processing + * + * @param[in] Dev : Device handle + * @param[in] pxtalk_ranges : Input VL53L1_xtalk_range_results_t + * Must contain 5 ranges, 4 quadrants + 1 + * full FoV + * @param[out] pxtalk_shape : Output normalised Cross talk histogram + * shape + * @param[out] pxtalk_cal : Output VL53L1_xtalk_calibration_results_t + * structure + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_ipp_xtalk_calibration_process_data( + VL53L1_DEV Dev, + VL53L1_xtalk_range_results_t *pxtalk_ranges, + VL53L1_xtalk_histogram_data_t *pxtalk_shape, + VL53L1_xtalk_calibration_results_t *pxtalk_cal); + + +/** + * @brief IPP Wrapper call for applying histogram xtalk correction + * + * @param[in] Dev : Device handle + * @param[in] pcustomer : Pointer to input customer data structure + * @param[in] pdyn_cfg : Pointer to input dynamic parameters + * structure + * @param[in] pxtalk_shape : Pointer to input normalised xtalk + * histogram shape + * @param[in] pip_hist_data : Pointer to input histogram data struct + * @param[out] pop_hist_data : Pointer to output xtalk corrected + * histogram data struct + * @param[out] pxtalk_count_data : Pointer to output xtalk histogram + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_ipp_hist_xtalk_correction( + VL53L1_DEV Dev, + VL53L1_customer_nvm_managed_t *pcustomer, + VL53L1_dynamic_config_t *pdyn_cfg, + VL53L1_xtalk_histogram_data_t *pxtalk_shape, + VL53L1_histogram_bin_data_t *pip_hist_data, + VL53L1_histogram_bin_data_t *pop_hist_data, + VL53L1_histogram_bin_data_t *pxtalk_count_data); + +/** + * @brief IPP Wrapper call for Generating Xtalk data from dual reflectance + * histogram data + * + * @param[in] Dev : Device handle + * @param[in] pxtalk_results : Pointer to xtalk_results structure + * containing dual reflectance + * histogram data + * @param[in] expected_target_distance_mm : User input of true target distance + * @param[in] higher_reflectance : User input detailing which + * histogram data 1 or 2 has the + * highest reflectance. + * @param[out] pxtalk_avg_samples : Pointer to output xtalk histogram + * data + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_ipp_generate_dual_reflectance_xtalk_samples( + VL53L1_DEV Dev, + VL53L1_xtalk_range_results_t *pxtalk_results, + uint16_t expected_target_distance_mm, + uint8_t higher_reflectance, + VL53L1_histogram_bin_data_t *pxtalk_avg_samples); + + + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/drivers/input/misc/vl53L1/lito/vl53l1_platform_ipp_imports.h b/drivers/input/misc/vl53L1/lito/vl53l1_platform_ipp_imports.h new file mode 100644 index 000000000000..b7700a919089 --- /dev/null +++ b/drivers/input/misc/vl53L1/lito/vl53l1_platform_ipp_imports.h @@ -0,0 +1,36 @@ +/************************************************************************** + * Copyright (c) 2016, STMicroelectronics - All Rights Reserved + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ****************************************************************************/ + + +#ifndef _VL53L1_PLATFORM_IPP_IMPORTS_H_ +#define _VL53L1_PLATFORM_IPP_IMPORTS_H_ + +#endif diff --git a/drivers/input/misc/vl53L1/lito/vl53l1_platform_log.h b/drivers/input/misc/vl53L1/lito/vl53l1_platform_log.h new file mode 100644 index 000000000000..357e0abb9773 --- /dev/null +++ b/drivers/input/misc/vl53L1/lito/vl53l1_platform_log.h @@ -0,0 +1,177 @@ +/************************************************************************** + * Copyright (c) 2016, STMicroelectronics - All Rights Reserved + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ****************************************************************************/ + +/** + * @file vl53l1_platform_log.h + * + * @brief EwokPlus25 platform logging function definition + */ + + +#ifndef _VL53L1_PLATFORM_LOG_H_ +#define _VL53L1_PLATFORM_LOG_H_ + +#include + +#ifdef VL53L1_LOG_ENABLE + #include "vl53l1_platform_user_config.h" + + #ifdef _MSC_VER + # define EWOKPLUS_EXPORTS __declspec(dllexport) + #else + # define EWOKPLUS_EXPORTS + #endif + + #include "vl53l1_types.h" + + #ifdef __cplusplus + extern "C" { + #endif + + #include + + /** + * @brief Set the level, output and specific functions for module + * logging. + * + * + * @param filename - full path of output log file, NULL for print to + * stdout + * + * @param modules - Module or None or All to trace + * VL53L1_TRACE_MODULE_NONE + * VL53L1_TRACE_MODULE_API + * VL53L1_TRACE_MODULE_CORE + * VL53L1_TRACE_MODULE_TUNING + * VL53L1_TRACE_MODULE_CHARACTERISATION + * VL53L1_TRACE_MODULE_PLATFORM + * VL53L1_TRACE_MODULE_ALL + * + * @param level - trace level + * VL53L1_TRACE_LEVEL_NONE + * VL53L1_TRACE_LEVEL_ERRORS + * VL53L1_TRACE_LEVEL_WARNING + * VL53L1_TRACE_LEVEL_INFO + * VL53L1_TRACE_LEVEL_DEBUG + * VL53L1_TRACE_LEVEL_ALL + * VL53L1_TRACE_LEVEL_IGNORE + * + * @param functions - function level to trace; + * VL53L1_TRACE_FUNCTION_NONE + * VL53L1_TRACE_FUNCTION_I2C + * VL53L1_TRACE_FUNCTION_ALL + * + * @return status - always VL53L1_ERROR_NONE + * + */ + + #define VL53L1_TRACE_LEVEL_NONE 0x00000000 + #define VL53L1_TRACE_LEVEL_ERRORS 0x00000001 + #define VL53L1_TRACE_LEVEL_WARNING 0x00000002 + #define VL53L1_TRACE_LEVEL_INFO 0x00000004 + #define VL53L1_TRACE_LEVEL_DEBUG 0x00000008 + #define VL53L1_TRACE_LEVEL_ALL 0x00000010 + #define VL53L1_TRACE_LEVEL_IGNORE 0x00000020 + + #define VL53L1_TRACE_FUNCTION_NONE 0x00000000 + #define VL53L1_TRACE_FUNCTION_I2C 0x00000001 + #define VL53L1_TRACE_FUNCTION_ALL 0x7fffffff + + #define VL53L1_TRACE_MODULE_NONE 0x00000000 + #define VL53L1_TRACE_MODULE_API 0x00000001 + #define VL53L1_TRACE_MODULE_CORE 0x00000002 + #define VL53L1_TRACE_MODULE_PROTECTED 0x00000004 + #define VL53L1_TRACE_MODULE_HISTOGRAM 0x00000008 + #define VL53L1_TRACE_MODULE_REGISTERS 0x00000010 + #define VL53L1_TRACE_MODULE_PLATFORM 0x00000020 + #define VL53L1_TRACE_MODULE_NVM 0x00000040 + #define VL53L1_TRACE_MODULE_CALIBRATION_DATA 0x00000080 + #define VL53L1_TRACE_MODULE_NVM_DATA 0x00000100 + #define VL53L1_TRACE_MODULE_HISTOGRAM_DATA 0x00000200 + #define VL53L1_TRACE_MODULE_RANGE_RESULTS_DATA 0x00000400 + #define VL53L1_TRACE_MODULE_XTALK_DATA 0x00000800 + #define VL53L1_TRACE_MODULE_OFFSET_DATA 0x00001000 + #define VL53L1_TRACE_MODULE_DATA_INIT 0x00002000 + #define VL53L1_TRACE_MODULE_REF_SPAD_CHAR 0x00004000 + #define VL53L1_TRACE_MODULE_SPAD_RATE_MAP 0x00008000 + #ifdef PAL_EXTENDED + #define VL53L1_TRACE_MODULE_SPAD 0x01000000 + #define VL53L1_TRACE_MODULE_FMT 0x02000000 + #define VL53L1_TRACE_MODULE_UTILS 0x04000000 + #define VL53L1_TRACE_MODULE_BENCH_FUNCS 0x08000000 + #endif + #define VL53L1_TRACE_MODULE_CUSTOMER_API 0x40000000 + #define VL53L1_TRACE_MODULE_ALL 0x7fffffff + + extern void log_trace_print(uint32_t module, uint32_t level, + uint32_t function, const char *format, ...); + + #define _LOG_TRACE_PRINT_FMT(module, level, function, format, ...) \ + log_trace_print(module, level, function, \ + KERN_INFO " " format, ##__VA_ARGS__) + #define _LOG_TRACE_PRINT(module, level, function, ...) \ + _LOG_TRACE_PRINT_FMT(module, level, function, ##__VA_ARGS__) + #define _LOG_FUNCTION_START(module, fmt, ...) \ + log_trace_print(module, VL53L1_TRACE_LEVEL_NONE, \ + VL53L1_TRACE_FUNCTION_ALL, \ + KERN_INFO " %s "fmt"\n", __func__, ##__VA_ARGS__) + #define _LOG_FUNCTION_END(module, status, ...) \ + log_trace_print(module, VL53L1_TRACE_LEVEL_NONE, \ + VL53L1_TRACE_FUNCTION_ALL, \ + KERN_INFO " %s %d\n", __func__, status) + #define _LOG_FUNCTION_END_FMT(module, status, fmt, ...) \ + log_trace_print(module, VL53L1_TRACE_LEVEL_NONE, \ + VL53L1_TRACE_FUNCTION_ALL, \ + KERN_INFO " %s %d"fmt"\n", __func__, status, \ + ##__VA_ARGS__) + #define _LOG_GET_TRACE_FUNCTIONS() 0 + #define _LOG_SET_TRACE_FUNCTIONS(functions) + + #define _LOG_STRING_BUFFER(x) char x[VL53L1_MAX_STRING_LENGTH] + + #ifdef __cplusplus + } + #endif + +#else /* VL53L1_LOG_ENABLE - no logging */ + #include "vl53l1_platform_user_config.h" + + #define _LOG_TRACE_PRINT(module, level, function, ...) + #define _LOG_FUNCTION_START(module, fmt, ...) + #define _LOG_FUNCTION_END(module, status, ...) + #define _LOG_FUNCTION_END_FMT(module, status, fmt, ...) + #define _LOG_GET_TRACE_FUNCTIONS() 0 + #define _LOG_SET_TRACE_FUNCTIONS(functions) + #define _LOG_STRING_BUFFER(x) + +#endif /* VL53L1_LOG_ENABLE */ + +#endif /* _VL53L1_PLATFORM_LOG_H_ */ diff --git a/drivers/input/misc/vl53L1/lito/vl53l1_platform_user_config.h b/drivers/input/misc/vl53L1/lito/vl53l1_platform_user_config.h new file mode 100644 index 000000000000..396d25762a5d --- /dev/null +++ b/drivers/input/misc/vl53L1/lito/vl53l1_platform_user_config.h @@ -0,0 +1,117 @@ +/************************************************************************** + * Copyright (c) 2016, STMicroelectronics - All Rights Reserved + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ****************************************************************************/ + +/** + * @file vl53l1_platform_user_config.h + * + * @brief EwokPlus compile time user modifiable configuration + */ + + +#ifndef _VL53L1_PLATFORM_USER_CONFIG_H_ +#define _VL53L1_PLATFORM_USER_CONFIG_H_ + +#define VL53L1_BYTES_PER_WORD 2 +#define VL53L1_BYTES_PER_DWORD 4 + +/* Define polling delays */ +#define VL53L1_BOOT_COMPLETION_POLLING_TIMEOUT_MS 500 +#define VL53L1_RANGE_COMPLETION_POLLING_TIMEOUT_MS 2000 +#define VL53L1_TEST_COMPLETION_POLLING_TIMEOUT_MS 60000 + +#define VL53L1_POLLING_DELAY_MS 1 + +/* Define LLD TuningParms Page Base Address + * - Part of Patch_AddedTuningParms_11761 + */ +#define VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS 0x8000 +#define VL53L1_TUNINGPARM_PRIVATE_PAGE_BASE_ADDRESS 0xC000 + +#define VL53L1_GAIN_FACTOR__STANDARD_DEFAULT 0x0800 + /*!< Default standard ranging gain correction factor + * 1.11 format. 1.0 = 0x0800, 0.980 = 0x07D7 + */ +#define VL53L1_GAIN_FACTOR__HISTOGRAM_DEFAULT 0x0800 + /*!< Default histogram ranging gain correction factor + * 1.11 format. 1.0 = 0x0800, 0.975 = 0x07CC + */ + + +#define VL53L1_OFFSET_CAL_MIN_EFFECTIVE_SPADS 0x0500 + /*!< Lower Limit for the MM1 effective SPAD count during offset + * calibration Format 8.8 0x0500 -> 5.0 effective SPADs + */ + +#define VL53L1_OFFSET_CAL_MAX_PRE_PEAK_RATE_MCPS 0x1900 + /*!< Max Limit for the pre range preak rate during offset + * calibration Format 9.7 0x1900 -> 50.0 Mcps. + * If larger then in pile up + */ + +#define VL53L1_OFFSET_CAL_MAX_SIGMA_MM 0x0040 + /*!< Max sigma estimate limit during offset calibration + * Check applies to pre-range, mm1 and mm2 ranges + * Format 14.2 0x0040 -> 16.0mm. + */ + + +#define VL53L1_ZONE_CAL_MAX_PRE_PEAK_RATE_MCPS 0x1900 + /*!< Max Peak Rate Limit for the during zone calibration + * Format 9.7 0x1900 -> 50.0 Mcps. + * If larger then in pile up + */ + +#define VL53L1_ZONE_CAL_MAX_SIGMA_MM 0x0040 + /*!< Max sigma estimate limit during zone calibration + * Format 14.2 0x0040 -> 16.0mm. + */ + + +#define VL53L1_XTALK_EXTRACT_MAX_SIGMA_MM 0x008C + /*!< Max Sigma value allowed for a successful xtalk extraction + * Format 14.2 0x008C -> 35.0 mm. + */ + + +#define VL53L1_MAX_USER_ZONES 169 + /*!< Max number of user Zones - maximal limitation from + * FW stream divide - value of 254 + */ + +#define VL53L1_MAX_RANGE_RESULTS 4 + /*!< Sets the maximum number of targets distances the histogram + * post processing can generate + */ + +#define VL53L1_MAX_STRING_LENGTH 512 + +#endif /* _VL53L1_PLATFORM_USER_CONFIG_H_ */ + diff --git a/drivers/input/misc/vl53L1/lito/vl53l1_platform_user_data.h b/drivers/input/misc/vl53L1/lito/vl53l1_platform_user_data.h new file mode 100644 index 000000000000..41da1dda1235 --- /dev/null +++ b/drivers/input/misc/vl53L1/lito/vl53l1_platform_user_data.h @@ -0,0 +1,63 @@ +/************************************************************************** + * Copyright (c) 2016, STMicroelectronics - All Rights Reserved + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ****************************************************************************/ + + +#ifndef _VL53L1_PLATFORM_USER_DATA_H_ +#define _VL53L1_PLATFORM_USER_DATA_H_ + +#include "vl53l1_ll_def.h" + +#include +#include "vl53l1_def.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include + +#define VL53L1_Dev_t VL53L1_DevData_t +#define VL53L1_DEV VL53L1_DevData_t * + +#define VL53L1DevDataGet(Dev, field) (Dev->field) +#define VL53L1DevDataSet(Dev, field, data) ((Dev->field) = (data)) + +#define VL53L1DevStructGetLLDriverHandle(Dev) (&VL53L1DevDataGet(Dev, LLData)) +#define VL53L1DevStructGetLLResultsHandle(Dev) (&VL53L1DevDataGet(Dev,\ + llresults)) + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/drivers/input/misc/vl53L1/lito/vl53l1_platform_user_defines.h b/drivers/input/misc/vl53L1/lito/vl53l1_platform_user_defines.h new file mode 100644 index 000000000000..731c48341756 --- /dev/null +++ b/drivers/input/misc/vl53L1/lito/vl53l1_platform_user_defines.h @@ -0,0 +1,92 @@ +/************************************************************************** + * Copyright (c) 2016, STMicroelectronics - All Rights Reserved + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ****************************************************************************/ + + +#ifndef _VL53L1_PLATFORM_USER_DEFINES_H_ +#define _VL53L1_PLATFORM_USER_DEFINES_H_ + +#ifdef __cplusplus +extern "C" +{ +#endif + +#ifdef __KERNEL__ +#include +#endif + +/** + * @file vl53l1_platform_user_defines.h + * + * @brief All end user OS/platform/application definitions + */ + + +/** + * @def do_division_u + * @brief customer supplied division operation - 64-bit unsigned + * + * @param dividend unsigned 64-bit numerator + * @param divisor unsigned 64-bit denominator + */ +#ifdef __KERNEL__ +#define do_division_u(dividend, divisor) div64_u64(dividend, divisor) +#else +#define do_division_u(dividend, divisor) (dividend / divisor) +#endif + +/** + * @def do_division_s + * @brief customer supplied division operation - 64-bit signed + * + * @param dividend signed 64-bit numerator + * @param divisor signed 64-bit denominator + */ +#ifdef __KERNEL__ +#define do_division_s(dividend, divisor) div64_s64(dividend, divisor) +#else +#define do_division_s(dividend, divisor) (dividend / divisor) +#endif + +#define WARN_OVERRIDE_STATUS(__X__)\ + trace_print(VL53L1_TRACE_LEVEL_WARNING, #__X__) + + +#define DISABLE_WARNINGS() +#define ENABLE_WARNINGS() + + + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/drivers/input/misc/vl53L1/lito/vl53l1_types.h b/drivers/input/misc/vl53L1/lito/vl53l1_types.h new file mode 100644 index 000000000000..3d78e2559204 --- /dev/null +++ b/drivers/input/misc/vl53L1/lito/vl53l1_types.h @@ -0,0 +1,46 @@ +/************************************************************************** + * Copyright (c) 2016, STMicroelectronics - All Rights Reserved + + License terms: BSD 3-clause "New" or "Revised" License. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ****************************************************************************/ +/** + * @file vl53l1_types.h + * @brief VL53L1 types definition + */ + +#ifndef _VL53L1_TYPES_H_ +#define _VL53L1_TYPES_H_ + +#include +/** use where fractional values are expected + * + * Given a floating point value f it's .16 bit point is (int)(f*(1<<16)) + */ +typedef uint32_t FixPoint1616_t; + +#endif /* VL53L1_TYPES_H_ */ diff --git a/drivers/input/oplus_fp_drivers b/drivers/input/oplus_fp_drivers new file mode 120000 index 000000000000..e8532fbc2b7d --- /dev/null +++ b/drivers/input/oplus_fp_drivers @@ -0,0 +1 @@ +../../../../vendor/oplus/secure/biometrics/fingerprints/bsp/drivers/ \ No newline at end of file diff --git a/drivers/input/oplus_secure_drivers b/drivers/input/oplus_secure_drivers new file mode 120000 index 000000000000..51c29eda8312 --- /dev/null +++ b/drivers/input/oplus_secure_drivers @@ -0,0 +1 @@ +../../../../vendor/oplus/secure/common/bsp/drivers/ \ No newline at end of file diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index 3ee51c5d49a7..4205fc403d8f 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -1324,6 +1324,10 @@ config TOUCHSCREEN_ST source "drivers/input/touchscreen/st/Kconfig" +#ifdef OPLUS_FEATURE_TP_BASIC +source "drivers/input/touchscreen/oplus_touchscreen/Kconfig" +#endif + config TOUCHSCREEN_SYNAPTICS_DSX bool "Synaptics DSX Touchscreen Driver" depends on I2C @@ -1350,9 +1354,7 @@ config TOUCHSCREEN_SYNAPTICS_TCM To compile this driver as a module, choose M here: the module will be called synaptics_tcm. -source "drivers/input/touchscreen/synaptics_tcm/Kconfig" - -source "drivers/input/touchscreen/focaltech_touch/Kconfig" +#source "drivers/input/touchscreen/synaptics_tcm/Kconfig" source "drivers/input/touchscreen/nt36xxx/Kconfig" diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index 8b766e754948..6e844092d737 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -109,8 +109,12 @@ obj-$(CONFIG_TOUCHSCREEN_ZET6223) += zet6223.o obj-$(CONFIG_TOUCHSCREEN_ZFORCE) += zforce_ts.o obj-$(CONFIG_TOUCHSCREEN_COLIBRI_VF50) += colibri-vf50-ts.o obj-$(CONFIG_TOUCHSCREEN_ROHM_BU21023) += rohm_bu21023.o +#ifdef OPLUS_FEATURE_TP_BASIC +obj-$(CONFIG_TOUCHPANEL_OPLUS) += oplus_touchscreen/ +obj-$(CONFIG_TOUCHPANEL_OPLUS) += touch.o +#endif obj-$(CONFIG_TOUCHSCREEN_ST) += st/ obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX) += synaptics_dsx/ obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_TCM) += synaptics_tcm/ obj-$(CONFIG_TOUCHSCREEN_FTS) += focaltech_touch/ -obj-$(CONFIG_TOUCHSCREEN_NT36XXX) += nt36xxx/ +#obj-$(CONFIG_TOUCHSCREEN_NT36XXX) += nt36xxx/ diff --git a/drivers/input/touchscreen/oplus_touchscreen b/drivers/input/touchscreen/oplus_touchscreen new file mode 120000 index 000000000000..bda284a5cf2c --- /dev/null +++ b/drivers/input/touchscreen/oplus_touchscreen @@ -0,0 +1 @@ +../../../../../vendor/oplus/kernel/touchpanel/oplus_touchscreen \ No newline at end of file diff --git a/drivers/input/touchscreen/touch.c b/drivers/input/touchscreen/touch.c new file mode 100644 index 000000000000..b226e9af0af5 --- /dev/null +++ b/drivers/input/touchscreen/touch.c @@ -0,0 +1,239 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2018-2020 Oplus. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include "oplus_touchscreen/tp_devices.h" +#include "oplus_touchscreen/touchpanel_common.h" +#include +#include +#include "touch.h" + +#define MAX_LIMIT_DATA_LENGTH 100 +extern char *saved_command_line; +/*if can not compile success, please update vendor/oplus_touchsreen*/ +struct tp_dev_name tp_dev_names[] = { + {TP_OFILM, "OFILM"}, + {TP_BIEL, "BIEL"}, + {TP_TRULY, "TRULY"}, + {TP_BOE, "BOE"}, + {TP_G2Y, "G2Y"}, + {TP_TPK, "TPK"}, + {TP_JDI, "JDI"}, + {TP_TIANMA, "TIANMA"}, + {TP_SAMSUNG, "SAMSUNG"}, + {TP_DSJM, "DSJM"}, + {TP_BOE_B8, "BOEB8"}, + {TP_UNKNOWN, "UNKNOWN"}, +}; +int g_tp_prj_id = 0; +int g_tp_dev_vendor = TP_UNKNOWN; +char *g_tp_ext_prj_name = NULL; +typedef enum { + TP_INDEX_NULL, + SAMSUNG_Y791, + BOE_S3908, + SAMSUNG_Y771, + ili7807s_boe +} TP_USED_INDEX; +TP_USED_INDEX tp_used_index = TP_INDEX_NULL; + + + +#define GET_TP_DEV_NAME(tp_type) ((tp_dev_names[tp_type].type == (tp_type))?tp_dev_names[tp_type].name:"UNMATCH") + +bool __init tp_judge_ic_match(char *tp_ic_name) +{ + return true; +} + +bool tp_judge_ic_match_commandline(struct panel_info *panel_data) +{ + int prj_id = 0; + int i = 0; + prj_id = get_project(); + pr_err("[TP] boot_command_line = %s \n", saved_command_line); + for(i = 0; i < panel_data->project_num; i++) { + if(prj_id == panel_data->platform_support_project[i]) { + g_tp_prj_id = panel_data->platform_support_project_dir[i]; + g_tp_ext_prj_name = panel_data->platform_support_external_name[i]; + if(strstr(saved_command_line, panel_data->platform_support_commandline[i]) || strstr("default_commandline", panel_data->platform_support_commandline[i])) { + pr_err("[TP] Driver match the project\n"); + return true; + } + else { + break; + } + } + } + pr_err("[TP] Driver does not match the project\n"); + pr_err("Lcd module not found\n"); + return false; +} + + +int tp_util_get_vendor(struct hw_resource *hw_res, struct panel_info *panel_data) +{ + char *vendor; + int prj_id = 0; + + panel_data->test_limit_name = kzalloc(MAX_LIMIT_DATA_LENGTH, GFP_KERNEL); + if (panel_data->test_limit_name == NULL) { + pr_err("[TP]panel_data.test_limit_name kzalloc error\n"); + } + + prj_id = g_tp_prj_id; + if (panel_data->tp_type == TP_SAMSUNG) { + memcpy(panel_data->manufacture_info.version, "SL", 2); + } else if (panel_data->tp_type == TP_BOE) { + memcpy(panel_data->manufacture_info.version, "BS", 2); + } else { + memcpy(panel_data->manufacture_info.version, "0x", 2); + } + if (prj_id == 19795) { + memcpy(panel_data->manufacture_info.version, "goodix_", 7); + } + if (prj_id == 19015 || prj_id == 19016) { + memcpy(panel_data->manufacture_info.version, "0xbd3180000", 11); + } + if (prj_id == 19125) { + memcpy(panel_data->manufacture_info.version, "0xbd2830000", 11); + } + if (prj_id == 20801) { + memcpy(panel_data->manufacture_info.version, "0x504000000", 11); + } + if (prj_id == 21623) { + memcpy(panel_data->manufacture_info.version, "focalt_", sizeof("focalt_")); + } + if (g_tp_ext_prj_name) { + if (NULL != panel_data->manufacture_info.version) { + strncpy(panel_data->manufacture_info.version + strlen(panel_data->manufacture_info.version), + g_tp_ext_prj_name, 7); + panel_data->manufacture_info.version[strlen(panel_data->manufacture_info.version)] = '\0'; + } + } + if (panel_data->tp_type == TP_UNKNOWN) { + pr_err("[TP]%s type is unknown\n", __func__); + return 0; + } + + vendor = GET_TP_DEV_NAME(panel_data->tp_type); + + strcpy(panel_data->manufacture_info.manufacture, vendor); + snprintf(panel_data->fw_name, MAX_FW_NAME_LENGTH, + "tp/%d/FW_%s_%s.img", + prj_id, panel_data->chip_name, vendor); + + if (panel_data->test_limit_name) { + snprintf(panel_data->test_limit_name, MAX_LIMIT_DATA_LENGTH, + "tp/%d/LIMIT_%s_%s.img", + prj_id, panel_data->chip_name, vendor); + } + + panel_data->manufacture_info.fw_path = panel_data->fw_name; + + if (prj_id == 20669 || prj_id == 20751) { + snprintf(panel_data->fw_name, MAX_FW_NAME_LENGTH, + "tp/20669/FW_%s_%s.img", panel_data->chip_name, vendor); + + if (panel_data->test_limit_name) { + snprintf(panel_data->test_limit_name, MAX_LIMIT_DATA_LENGTH, + "tp/20669/LIMIT_%s_%s.img", panel_data->chip_name, vendor); + } + pr_info("panel_data->tp_type = %d\n", panel_data->tp_type); + if (panel_data->tp_type == TP_JDI) { + memcpy(panel_data->manufacture_info.version, "AA869_DS_NT_", 12); + panel_data->firmware_headfile.firmware_data = FW_17951_NT36672C_JDI; + panel_data->firmware_headfile.firmware_size = sizeof(FW_17951_NT36672C_JDI); + } else { + memcpy(panel_data->manufacture_info.version, "AA869_BOE_ILI_", 14); + panel_data->firmware_headfile.firmware_data = FW_20669_ILI7807S; + panel_data->firmware_headfile.firmware_size = sizeof(FW_20669_ILI7807S); + } + } + if (prj_id == 21027) { + strcpy(panel_data->manufacture_info.manufacture, "BOE"); + memcpy(panel_data->manufacture_info.version, "BSFA26105", 9); + panel_data->firmware_headfile.firmware_data = FW_21027_NT36523_BOE; + panel_data->firmware_headfile.firmware_size = sizeof(FW_21027_NT36523_BOE); + snprintf(panel_data->fw_name, MAX_FW_NAME_LENGTH, + "tp/%d/FW_%s_%s.bin", + prj_id, panel_data->chip_name, vendor); + + if (panel_data->test_limit_name) { + snprintf(panel_data->test_limit_name, MAX_LIMIT_DATA_LENGTH, + "tp/%d/LIMIT_%s_%s.img", + prj_id, panel_data->chip_name, vendor); + } + } + if (prj_id == 0x2065C) { + snprintf(panel_data->fw_name, MAX_FW_NAME_LENGTH, + "tp/%s/FW_%s_%s.img", + "2065C", panel_data->chip_name, vendor); + + if (panel_data->test_limit_name) { + snprintf(panel_data->test_limit_name, MAX_LIMIT_DATA_LENGTH, + "tp/%s/LIMIT_%s_%s.img", + "2065C", panel_data->chip_name, vendor); + } + memcpy(panel_data->manufacture_info.version, "focalt_0000", 11); + panel_data->manufacture_info.fw_path = panel_data->fw_name; + } + + pr_info("[TP]vendor:%s fw:%s limit:%s\n", + vendor, + panel_data->fw_name, + panel_data->test_limit_name == NULL?"NO Limit":panel_data->test_limit_name); + return 0; +} + +int preconfig_power_control(struct touchpanel_data *ts) +{ + return 0; +} +EXPORT_SYMBOL(preconfig_power_control); + +int reconfig_power_control(struct touchpanel_data *ts) +{ + int ret = 0; + int prj_id = 0; + prj_id = get_project(); + + if ((prj_id == 20135 || prj_id == 20137 || prj_id == 20139 || prj_id == 20235) && !strstr(saved_command_line, "20135samsung_amb655xl08_1080_2400_cmd_dvt")) { + pr_err("[TP]pcb is old version, need to reconfig the regulator.\n"); + if (!IS_ERR_OR_NULL(ts->hw_res.vdd_2v8)) { + regulator_put(ts->hw_res.vdd_2v8); + ts->hw_res.vdd_2v8 = NULL; + } + ts->hw_res.vdd_2v8 = regulator_get(ts->dev, "vdd_dvt_2v8"); + if (IS_ERR_OR_NULL(ts->hw_res.vdd_2v8)) { + pr_err("[TP]Regulator vdd2v8 get failed, ret = %d\n", ret); + } else { + if (regulator_count_voltages(ts->hw_res.vdd_2v8) > 0) { + pr_err("[TP]set avdd voltage to %d uV\n", ts->hw_res.vdd_volt); + if (ts->hw_res.vdd_volt) { + ret = regulator_set_voltage(ts->hw_res.vdd_2v8, ts->hw_res.vdd_volt, ts->hw_res.vdd_volt); + } else { + ret = regulator_set_voltage(ts->hw_res.vdd_2v8, 3100000, 3100000); + } + if (ret) { + dev_err(ts->dev, "Regulator set_vtg failed vdd rc = %d\n", ret); + } + ret = regulator_set_load(ts->hw_res.vdd_2v8, 200000); + if (ret < 0) { + dev_err(ts->dev, "Failed to set vdd_2v8 mode(rc:%d)\n", ret); + } + } + } + } + + return 0; +} +EXPORT_SYMBOL(reconfig_power_control); diff --git a/drivers/input/touchscreen/touch.h b/drivers/input/touchscreen/touch.h new file mode 100644 index 000000000000..a77e180be1c4 --- /dev/null +++ b/drivers/input/touchscreen/touch.h @@ -0,0 +1,29255 @@ +/*************************************************** + * File:touch.h + * Copyright (c) 2008- 2030 Oplus Mobile communication Corp.ltd. + * Description: + * tp dev + * Version:1.0: + * Date : 2019/09/19 + * TAG: BSP.TP.Init + ***************************************************/ + +/* 19751 NT36525C NF BOE 0x0000003 8721*/ + +static const uint8_t FW_21027_NT36523_BOE[] = +{ + 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4B, 0x6E, 0x01, 0x00, 0x00, 0x20, 0x02, 0x00, + 0x00, 0x00, 0x02, 0x00, 0x27, 0xB9, 0x00, 0x00, 0xD5, 0x95, 0xF1, 0x0F, 0x44, 0xB0, 0x56, 0xB2, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x02, 0x00, 0xDF, 0xD4, 0xCD, 0x59, + 0x00, 0x0A, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2A, 0x02, 0x00, 0xC4, 0x64, 0x19, 0x02, + 0x00, 0x32, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x52, 0x02, 0x00, 0x0C, 0x52, 0x00, 0x68, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x28, 0xB9, 0x02, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x50, 0xF4, 0x58, + 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4B, 0x6E, 0x01, 0x00, 0x00, 0x20, 0x02, 0x00, + 0x00, 0x00, 0x02, 0x00, 0x27, 0xB9, 0x00, 0x00, 0xD5, 0x95, 0xF1, 0x0F, 0x44, 0xB0, 0x56, 0xB2, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x02, 0x00, 0xDF, 0xD4, 0xCD, 0x59, + 0x00, 0x4A, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6A, 0x02, 0x00, 0xC4, 0x64, 0x19, 0x02, + 0x00, 0x72, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x92, 0x02, 0x00, 0x0C, 0x52, 0x00, 0x68, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x28, 0xBA, 0x02, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x55, 0x9E, 0xE1, 0xCC, + 0x48, 0x00, 0x01, 0xA2, 0xEA, 0xA9, 0x00, 0x00, 0xEA, 0xA9, 0x00, 0x00, 0xEA, 0xA9, 0x00, 0x00, + 0xEA, 0xA9, 0x00, 0x00, 0xEA, 0xA9, 0x00, 0x00, 0xEA, 0xA9, 0x00, 0x00, 0xEA, 0xA9, 0x00, 0x00, + 0x48, 0x00, 0x00, 0x00, 0xDD, 0x4E, 0x00, 0x00, 0xEA, 0xA5, 0x00, 0x00, 0xEA, 0xA5, 0x00, 0x00, + 0xDD, 0x4E, 0x00, 0x00, 0xEA, 0xA5, 0x00, 0x00, 0xDD, 0x4E, 0x00, 0x00, 0xDD, 0x4E, 0x00, 0x00, + 0xDD, 0x4E, 0x00, 0x00, 0xDD, 0x4E, 0x00, 0x00, 0xDD, 0x4E, 0x00, 0x00, 0xDD, 0x4E, 0x00, 0x00, + 0xDD, 0x4E, 0x00, 0x00, 0xDD, 0x4E, 0x00, 0x00, 0xDD, 0x4E, 0x00, 0x00, 0xDD, 0x4E, 0x00, 0x00, + 0xEA, 0xA5, 0x00, 0x00, 0xEA, 0xA5, 0x00, 0x00, 0xDD, 0x4E, 0x00, 0x00, 0xDD, 0x4E, 0x00, 0x00, + 0xDD, 0x4E, 0x00, 0x00, 0xEA, 0xA5, 0x00, 0x00, 0xEA, 0xA5, 0x00, 0x00, 0xDD, 0x4E, 0x00, 0x00, + 0xDD, 0x4E, 0x00, 0x00, 0xDD, 0x4E, 0x00, 0x00, 0xDD, 0x4E, 0x00, 0x00, 0xDD, 0x4E, 0x00, 0x00, + 0xDD, 0x4E, 0x00, 0x00, 0xDD, 0x4E, 0x00, 0x00, 0xDD, 0x4E, 0x00, 0x00, 0xDD, 0x4E, 0x00, 0x00, + 0xDD, 0x4E, 0x00, 0x00, 0xDD, 0x4E, 0x00, 0x00, 0xDD, 0x4E, 0x00, 0x00, 0xDD, 0x4E, 0x00, 0x00, + 0xDD, 0x4E, 0x00, 0x00, 0xDD, 0x4E, 0x00, 0x00, 0xDD, 0x4E, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, + 0x48, 0x00, 0x00, 0x00, 0xDD, 0x4E, 0x00, 0x00, 0xDD, 0x4E, 0x00, 0x00, 0xDD, 0x4E, 0x00, 0x00, + 0xDD, 0x4E, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, + 0x48, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, + 0x48, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, + 0x48, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, + 0x48, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, + 0x48, 0x00, 0x00, 0x00, 0x10, 0x05, 0x00, 0x00, 0x10, 0x05, 0x00, 0x00, 0x7E, 0x07, 0x00, 0x00, + 0xD6, 0x13, 0x00, 0x00, 0xD6, 0x13, 0x00, 0x00, 0xD6, 0x13, 0x00, 0x00, 0xD6, 0x13, 0x00, 0x00, + 0xD6, 0x13, 0x00, 0x00, 0xD6, 0x13, 0x00, 0x00, 0xD6, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x3C, 0x09, 0x00, 0x00, 0x44, 0x09, 0x00, 0x00, 0x80, 0x09, 0x00, 0x00, 0xFA, 0x09, 0x00, 0x00, + 0x42, 0x0A, 0x00, 0x00, 0xC4, 0x0A, 0x00, 0x00, 0x90, 0x0B, 0x00, 0x00, 0xAE, 0x0B, 0x00, 0x00, + 0xB6, 0x0B, 0x00, 0x00, 0xBE, 0x0B, 0x00, 0x00, 0xC6, 0x0B, 0x00, 0x00, 0xCE, 0x0B, 0x00, 0x00, + 0xE0, 0x0B, 0x00, 0x00, 0xE8, 0x0B, 0x00, 0x00, 0xF4, 0x0B, 0x00, 0x00, 0xF2, 0x10, 0x00, 0x00, + 0x06, 0x0C, 0x00, 0x00, 0xC8, 0x0C, 0x00, 0x00, 0x10, 0x0D, 0x00, 0x00, 0x18, 0x0D, 0x00, 0x00, + 0x56, 0x0D, 0x00, 0x00, 0x68, 0x0D, 0x00, 0x00, 0x7A, 0x0D, 0x00, 0x00, 0x9A, 0x0D, 0x00, 0x00, + 0xBC, 0x0E, 0x00, 0x00, 0xD2, 0x0E, 0x00, 0x00, 0xDA, 0x0E, 0x00, 0x00, 0xEC, 0x0E, 0x00, 0x00, + 0x62, 0x12, 0x00, 0x00, 0x64, 0x12, 0x00, 0x00, 0x88, 0x12, 0x00, 0x00, 0x90, 0x12, 0x00, 0x00, + 0x98, 0x12, 0x00, 0x00, 0xA4, 0x12, 0x00, 0x00, 0xA6, 0x12, 0x00, 0x00, 0xB2, 0x12, 0x00, 0x00, + 0xC0, 0x12, 0x00, 0x00, 0xD4, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xE0, 0x12, 0x00, 0x00, 0xF2, 0x12, 0x00, 0x00, 0x3C, 0x13, 0x00, 0x00, 0xC4, 0x13, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x3A, 0x0F, 0xEF, 0xFC, 0x42, 0x1E, 0x80, 0x20, 0x3A, 0x1F, 0x88, 0x3C, 0x64, 0x12, 0xA4, 0x02, + 0x64, 0x22, 0x04, 0x02, 0x3A, 0x1F, 0x88, 0x3C, 0x80, 0x3F, 0x64, 0x02, 0x64, 0x02, 0x92, 0x05, + 0x96, 0x37, 0x44, 0x20, 0x01, 0x2C, 0x38, 0x21, 0x02, 0x02, 0x64, 0x32, 0x00, 0x02, 0x9E, 0xD9, + 0x64, 0x32, 0x00, 0x03, 0xDD, 0x22, 0x64, 0x02, 0x00, 0x43, 0x64, 0x00, 0x00, 0x08, 0x3A, 0x1F, + 0x88, 0x04, 0x64, 0x12, 0xA4, 0x03, 0x64, 0x22, 0x04, 0x03, 0x3A, 0x1F, 0x88, 0x04, 0x42, 0x1E, + 0x80, 0x21, 0x3A, 0x0F, 0xEF, 0xC4, 0x64, 0x00, 0x00, 0x04, 0x3A, 0xFF, 0xEC, 0xBC, 0x3A, 0x0F, + 0x94, 0x3C, 0x42, 0x1E, 0x80, 0x20, 0x3A, 0x1F, 0x88, 0x3C, 0x64, 0x02, 0x64, 0x02, 0x92, 0x05, + 0x96, 0x37, 0x44, 0x20, 0x01, 0x2C, 0x38, 0x21, 0x02, 0x02, 0x8E, 0x09, 0xDD, 0x22, 0x3A, 0x1F, + 0x88, 0x04, 0x42, 0x1E, 0x80, 0x21, 0x3A, 0x0F, 0x94, 0x04, 0x3A, 0xFF, 0xEC, 0x84, 0x64, 0x00, + 0x00, 0x04, 0x3A, 0xFF, 0xEC, 0xBC, 0x3A, 0x0F, 0x94, 0x3C, 0x42, 0x1E, 0x80, 0x20, 0x3A, 0x1F, + 0x88, 0x3C, 0x64, 0x12, 0xA4, 0x02, 0x64, 0x22, 0x04, 0x02, 0x3A, 0x1F, 0x88, 0x3C, 0x64, 0x02, + 0x64, 0x02, 0x92, 0x05, 0x96, 0x37, 0x44, 0x20, 0x01, 0x2C, 0x38, 0x21, 0x02, 0x02, 0x8E, 0x09, + 0x64, 0x32, 0x00, 0x02, 0x9E, 0xD9, 0x64, 0x32, 0x00, 0x03, 0xDD, 0x22, 0x64, 0x02, 0x00, 0x43, + 0x64, 0x00, 0x00, 0x08, 0x3A, 0x1F, 0x88, 0x04, 0x64, 0x12, 0xA4, 0x03, 0x64, 0x22, 0x04, 0x03, + 0x3A, 0x1F, 0x88, 0x04, 0x42, 0x1E, 0x80, 0x21, 0x3A, 0x0F, 0x94, 0x04, 0x3A, 0xFF, 0xEC, 0x84, + 0x64, 0x00, 0x00, 0x04, 0x4F, 0xF2, 0x00, 0x22, 0x3A, 0x0F, 0xEF, 0xFC, 0x42, 0x1E, 0x80, 0x20, + 0x3A, 0x1F, 0x88, 0x3C, 0x45, 0xD2, 0xCC, 0x78, 0x80, 0x1F, 0x64, 0x12, 0x64, 0x02, 0x96, 0x5F, + 0x9E, 0x49, 0xC1, 0x05, 0x3C, 0xFD, 0x4D, 0x2B, 0x48, 0x00, 0x00, 0x04, 0x3C, 0xFD, 0x4D, 0x2C, + 0xE8, 0x0C, 0xDD, 0x2F, 0x4E, 0x03, 0x00, 0x0A, 0x3A, 0x1F, 0x88, 0x04, 0x42, 0x1E, 0x80, 0x21, + 0x3A, 0x0F, 0xEF, 0xC4, 0x64, 0x00, 0x00, 0x04, 0x64, 0x02, 0x24, 0x02, 0x44, 0x10, 0xC0, 0x00, + 0xFE, 0x0F, 0xFE, 0x0D, 0x64, 0x02, 0x24, 0x03, 0x64, 0x00, 0x00, 0x08, 0x45, 0xD2, 0xCC, 0x78, + 0x45, 0xF2, 0xFE, 0x00, 0x64, 0x00, 0x80, 0x02, 0x92, 0x18, 0x96, 0x04, 0xC0, 0x05, 0x44, 0x01, + 0x5D, 0xC0, 0x42, 0x0E, 0x00, 0x21, 0x44, 0xF0, 0x04, 0xE0, 0xE8, 0x02, 0xDD, 0x2F, 0x3C, 0xFD, + 0x4D, 0x2D, 0xDD, 0x2F, 0x64, 0x0F, 0xFF, 0xEA, 0xFC, 0x00, 0x44, 0x62, 0xE3, 0x7C, 0x44, 0x02, + 0xBB, 0x28, 0x84, 0x20, 0x9A, 0xB0, 0xEA, 0x2F, 0xEA, 0x34, 0xAE, 0x31, 0xFC, 0x80, 0xFC, 0x00, + 0x84, 0x00, 0x3C, 0x0F, 0xFC, 0x59, 0x44, 0x23, 0xF7, 0xEF, 0xEB, 0xAC, 0x3C, 0x0F, 0xFC, 0x69, + 0x3C, 0x0F, 0xFC, 0x6D, 0xEB, 0x1B, 0x3C, 0x0F, 0xFC, 0x7F, 0x3C, 0x0F, 0xFC, 0x63, 0x3C, 0x0F, + 0xFC, 0x6E, 0x3C, 0x0F, 0xFC, 0x6A, 0x3C, 0x0F, 0xFC, 0x77, 0x3C, 0x0F, 0xFC, 0x6B, 0x3C, 0x0F, + 0xFC, 0x67, 0x3C, 0x0F, 0xFC, 0x64, 0x3C, 0x0F, 0xFC, 0x5C, 0x3C, 0x0F, 0xFC, 0x7D, 0x3C, 0x0F, + 0xFC, 0x82, 0x3C, 0x0F, 0xFC, 0x75, 0x3C, 0x0F, 0xFC, 0x76, 0x3C, 0x0F, 0xFC, 0x73, 0x3C, 0x0F, + 0xFC, 0x57, 0x3C, 0x0F, 0xFC, 0x7E, 0x3C, 0x0F, 0xFC, 0x6C, 0x3C, 0x0F, 0xFC, 0x62, 0xEB, 0xD8, + 0xEA, 0x71, 0x3C, 0x0F, 0xFC, 0x5E, 0x3C, 0x0F, 0xFC, 0x61, 0x3C, 0x0F, 0xFC, 0x81, 0x3C, 0x0F, + 0xFC, 0x74, 0x3C, 0x0F, 0xFC, 0x7C, 0x3C, 0x0F, 0xFC, 0x68, 0x3C, 0x0F, 0xFC, 0x5D, 0x3C, 0x0F, + 0xFC, 0x71, 0x3C, 0x0F, 0xFC, 0x5F, 0xEB, 0x55, 0x3C, 0x0F, 0xFC, 0x78, 0xEB, 0x81, 0xA6, 0x50, + 0xEA, 0x5D, 0xAE, 0x50, 0x44, 0x23, 0xF7, 0xEE, 0xA6, 0x50, 0xEA, 0x5D, 0xAE, 0x50, 0x44, 0x23, + 0xF7, 0xCA, 0xA6, 0x50, 0xEA, 0x5D, 0xAE, 0x50, 0x44, 0x23, 0xF7, 0xC9, 0xA6, 0x50, 0xEA, 0x5D, + 0xAE, 0x50, 0x64, 0x03, 0x00, 0x03, 0xEA, 0x76, 0xEA, 0xF3, 0x64, 0x12, 0x24, 0x02, 0x96, 0x4C, + 0x80, 0x40, 0xC1, 0x03, 0x64, 0x03, 0x00, 0x03, 0x64, 0x22, 0x24, 0x03, 0x64, 0x02, 0x00, 0x02, + 0x66, 0x00, 0x00, 0x06, 0x64, 0x02, 0x00, 0x03, 0x64, 0x00, 0x00, 0x08, 0x64, 0x03, 0x04, 0x02, + 0x46, 0x02, 0x9C, 0x10, 0x50, 0x00, 0x00, 0x7E, 0xEA, 0x76, 0x64, 0x03, 0x08, 0x02, 0x44, 0x00, + 0x06, 0x33, 0xEA, 0xF3, 0x64, 0x02, 0x00, 0x02, 0xEA, 0x8C, 0x64, 0x02, 0x00, 0x03, 0xFC, 0x80, + 0x44, 0x03, 0xF0, 0xED, 0xA6, 0x40, 0x5A, 0x18, 0x01, 0x04, 0x84, 0x20, 0xAE, 0x40, 0x44, 0x13, + 0xF0, 0xDA, 0xA6, 0x08, 0x54, 0x00, 0x00, 0xF0, 0xAE, 0x08, 0x84, 0x04, 0xEA, 0x76, 0x84, 0x25, + 0x44, 0x03, 0xF0, 0x49, 0xAE, 0x40, 0x44, 0x10, 0x00, 0x53, 0xDD, 0x45, 0xAE, 0x40, 0xDD, 0x9E, + 0xDD, 0x9E, 0x44, 0x43, 0xF1, 0x14, 0xB4, 0x64, 0x92, 0x78, 0x40, 0x00, 0x0F, 0x04, 0xB6, 0x04, + 0x44, 0x03, 0xF1, 0x38, 0xAC, 0x40, 0x84, 0x20, 0x44, 0x03, 0xF1, 0x3A, 0xAE, 0x40, 0x44, 0x03, + 0xF1, 0x04, 0xB6, 0x40, 0x84, 0x21, 0x44, 0x03, 0xF1, 0x36, 0xAE, 0x40, 0xF8, 0x08, 0xA6, 0x40, + 0x96, 0x4C, 0xC1, 0x03, 0xAE, 0xD0, 0xD5, 0xFC, 0x44, 0x13, 0xF1, 0x34, 0xEA, 0x50, 0xEA, 0x48, + 0x83, 0xFF, 0xA6, 0x08, 0x96, 0x0E, 0xC8, 0x03, 0xAE, 0xD0, 0xD5, 0xFC, 0x44, 0x03, 0xF1, 0x34, + 0xA6, 0x00, 0x96, 0x04, 0xDD, 0x9E, 0x84, 0xA0, 0xD2, 0x07, 0x38, 0x30, 0x14, 0x00, 0x38, 0x30, + 0x94, 0x08, 0x8C, 0xA1, 0xD5, 0xFA, 0xDD, 0x9E, 0xFC, 0x00, 0xDD, 0x40, 0xC0, 0x0A, 0x84, 0x00, + 0xDD, 0x4F, 0x44, 0x12, 0xBA, 0x28, 0x84, 0x02, 0x80, 0x41, 0x44, 0x30, 0x01, 0x00, 0xDD, 0x42, + 0xFC, 0x80, 0xFC, 0x00, 0x80, 0xC0, 0xDD, 0x40, 0xC0, 0x12, 0x44, 0x1F, 0xFF, 0x9F, 0xEB, 0xD0, + 0xAE, 0x40, 0x96, 0x30, 0x44, 0x12, 0xFE, 0x61, 0xAE, 0x08, 0xEA, 0xF5, 0x44, 0x12, 0xFE, 0x62, + 0xAE, 0x08, 0xDD, 0x45, 0xDD, 0x47, 0xC6, 0x03, 0xAE, 0x40, 0xD5, 0xFE, 0xFC, 0x80, 0xFC, 0x40, + 0x3C, 0x7D, 0xFC, 0x1B, 0x81, 0x40, 0xDD, 0x40, 0xC0, 0x5B, 0x85, 0x23, 0x84, 0xC0, 0x3C, 0x2D, + 0xFC, 0x1B, 0x40, 0x21, 0x24, 0x80, 0xA0, 0x51, 0xC1, 0x08, 0xF8, 0x5C, 0x5A, 0x08, 0x01, 0x06, + 0x40, 0x10, 0x24, 0x0C, 0xFF, 0x8F, 0x97, 0xB1, 0x8D, 0x21, 0x5A, 0x98, 0x0F, 0xF2, 0xF8, 0x5F, + 0x5A, 0x08, 0x01, 0x04, 0x42, 0x63, 0x3C, 0x08, 0x83, 0x87, 0xB9, 0x7D, 0xB8, 0x7C, 0x8E, 0x24, + 0x96, 0x49, 0xBA, 0x7F, 0xF8, 0x5C, 0x5A, 0x08, 0x01, 0x05, 0x58, 0x63, 0x00, 0x01, 0xD5, 0x02, + 0xC6, 0x05, 0x5A, 0xA8, 0xAE, 0x04, 0x80, 0x06, 0xF8, 0x11, 0x84, 0x20, 0xEB, 0x11, 0xAE, 0x40, + 0x44, 0x02, 0xFE, 0x63, 0xA6, 0x40, 0x84, 0x20, 0xAE, 0x40, 0xA6, 0x81, 0xAE, 0x41, 0x49, 0x00, + 0x0E, 0x3E, 0x5A, 0x08, 0x01, 0x06, 0x58, 0x03, 0x00, 0x02, 0x49, 0xFF, 0xFF, 0xAC, 0xEA, 0x56, + 0xEA, 0x21, 0xDD, 0x5B, 0xA7, 0x80, 0x97, 0xB0, 0x5A, 0x60, 0x02, 0x04, 0xAE, 0x88, 0xD5, 0xFB, + 0x44, 0x72, 0xFE, 0xF1, 0xA6, 0x38, 0x5A, 0x00, 0x86, 0x08, 0x44, 0x00, 0x00, 0xC1, 0xDD, 0x4A, + 0xF8, 0x80, 0xAE, 0x40, 0xD5, 0xFF, 0x49, 0x00, 0x2D, 0xC8, 0x84, 0x00, 0x3E, 0x07, 0xF2, 0x01, + 0x80, 0x27, 0x80, 0x06, 0x44, 0x22, 0xBE, 0x79, 0x84, 0x61, 0xDD, 0x42, 0xFC, 0xC0, 0x5A, 0xA8, + 0xAE, 0x4C, 0x84, 0xE3, 0x80, 0xC0, 0x3C, 0x2D, 0xFC, 0x1B, 0x40, 0x21, 0x1C, 0x80, 0xA0, 0x51, + 0xC1, 0x0B, 0xB4, 0x02, 0x96, 0x49, 0xA0, 0x93, 0xF8, 0x12, 0x5A, 0x08, 0x01, 0x06, 0x40, 0x00, + 0x1C, 0x0C, 0xFF, 0x87, 0x97, 0xB1, 0x8C, 0xE1, 0x5A, 0x78, 0x0F, 0xEF, 0x3C, 0x2D, 0xFC, 0x1B, + 0x83, 0x82, 0xB9, 0x3D, 0xB8, 0x3C, 0x8E, 0x24, 0x96, 0x49, 0xBA, 0x3F, 0x49, 0xFF, 0xFF, 0x2B, + 0x5A, 0x08, 0x01, 0x06, 0x54, 0x63, 0x7F, 0xFF, 0x42, 0x63, 0x3C, 0x08, 0x84, 0x20, 0x44, 0x02, + 0xFE, 0x78, 0xAC, 0x40, 0x44, 0x12, 0xFE, 0xF1, 0xEA, 0x56, 0xC6, 0x19, 0x44, 0x2F, 0xFF, 0xEE, + 0xAE, 0x88, 0x84, 0x22, 0xAE, 0x40, 0x44, 0x12, 0xFE, 0x60, 0x44, 0x0F, 0xFF, 0x8F, 0xAE, 0x08, + 0x44, 0x22, 0xFE, 0x61, 0x96, 0x30, 0xAE, 0x10, 0xEA, 0xF5, 0x96, 0x00, 0x44, 0x22, 0xFE, 0x62, + 0xAE, 0x10, 0x84, 0x63, 0x80, 0x41, 0x84, 0x02, 0xDD, 0x42, 0xD5, 0x20, 0x44, 0x2F, 0xFF, 0x86, + 0xAE, 0x88, 0x84, 0x22, 0xD5, 0x07, 0x44, 0x1F, 0xFF, 0x86, 0xEB, 0x11, 0xAE, 0x40, 0x84, 0x22, + 0xEA, 0x56, 0xAE, 0x40, 0x44, 0x03, 0xF0, 0x07, 0xA6, 0x00, 0x44, 0x12, 0xFE, 0x63, 0x96, 0x00, + 0xAE, 0x08, 0x44, 0x03, 0xF0, 0x04, 0xA6, 0x00, 0x44, 0x22, 0xFE, 0x64, 0x96, 0x00, 0xAE, 0x10, + 0x84, 0x02, 0x80, 0x41, 0x80, 0x60, 0xDD, 0x42, 0x84, 0xC0, 0x44, 0x12, 0xFE, 0xF1, 0x80, 0x41, + 0x84, 0x61, 0x84, 0x02, 0xDD, 0x42, 0xEA, 0x29, 0x80, 0x41, 0x84, 0x02, 0x84, 0x61, 0xDD, 0x42, + 0xDD, 0x45, 0xDD, 0x47, 0x83, 0xFF, 0xC6, 0x03, 0xAE, 0x40, 0xD5, 0xFE, 0x44, 0x12, 0xFE, 0xF1, + 0xEA, 0x50, 0xEA, 0x48, 0xA6, 0x08, 0xC0, 0x03, 0xAE, 0xD0, 0xD5, 0xFD, 0xFC, 0xC0, 0x3A, 0x6F, + 0xA0, 0xBC, 0x84, 0x00, 0x80, 0x20, 0x49, 0x00, 0x7A, 0xF1, 0x84, 0x00, 0x64, 0x05, 0xE4, 0x03, + 0x44, 0x03, 0xF0, 0x0E, 0xA4, 0x40, 0x96, 0x66, 0x96, 0x49, 0xC1, 0x02, 0xD5, 0x00, 0x44, 0x22, + 0xFE, 0xF6, 0xAE, 0x50, 0xA4, 0x40, 0x96, 0x4E, 0xC9, 0x10, 0xA4, 0x40, 0x96, 0x56, 0xC9, 0x0D, + 0xA4, 0x40, 0x96, 0x5E, 0xC9, 0x0A, 0xA4, 0x40, 0x96, 0x66, 0xC9, 0x07, 0xA4, 0x40, 0x54, 0x10, + 0x81, 0x00, 0x96, 0x49, 0x4E, 0x12, 0x00, 0x85, 0x44, 0x13, 0xF0, 0x0E, 0xA4, 0x08, 0x96, 0x0E, + 0xC8, 0x06, 0xA5, 0x88, 0x54, 0x63, 0x01, 0x00, 0x97, 0xB1, 0xC6, 0x1F, 0x84, 0x00, 0xEA, 0x7F, + 0xA7, 0x88, 0xAC, 0x08, 0x44, 0x13, 0x8D, 0x20, 0xEB, 0x6D, 0xAE, 0x08, 0x44, 0x13, 0x8D, 0x21, + 0xAE, 0x08, 0x44, 0x13, 0x8D, 0x22, 0xAE, 0x08, 0x44, 0x13, 0x8D, 0x23, 0xAE, 0x08, 0x44, 0x13, + 0x8D, 0x24, 0xAE, 0x08, 0x44, 0x13, 0x8D, 0x25, 0xAE, 0x08, 0x44, 0x13, 0x8D, 0x26, 0xAE, 0x08, + 0x44, 0x13, 0x8D, 0x27, 0x97, 0xB0, 0xAE, 0x08, 0x49, 0xFF, 0xFD, 0xD8, 0x49, 0x00, 0x0A, 0xD9, + 0x44, 0x03, 0xF0, 0x0E, 0xA4, 0x40, 0x96, 0x4E, 0xC9, 0x08, 0xA4, 0x40, 0x96, 0x66, 0xC9, 0x05, + 0xA4, 0x00, 0x54, 0x00, 0x01, 0x00, 0xC0, 0x03, 0x49, 0x00, 0x2B, 0x19, 0xEB, 0xD0, 0x84, 0x20, + 0xAC, 0x40, 0x44, 0x72, 0xB9, 0x28, 0x84, 0x00, 0xEA, 0x71, 0x3C, 0x7F, 0xFC, 0x1B, 0xEB, 0xD8, + 0x3C, 0x0F, 0xFC, 0x79, 0xDD, 0x40, 0xC8, 0x05, 0x50, 0x73, 0x81, 0x00, 0x3C, 0x7F, 0xFC, 0x1B, + 0x49, 0xFF, 0xFE, 0x8C, 0x80, 0x06, 0x49, 0xFF, 0xFE, 0xAC, 0x84, 0x23, 0xEA, 0x56, 0xAE, 0x40, + 0x84, 0x01, 0x44, 0x13, 0xF7, 0xD3, 0xAE, 0x08, 0x44, 0x13, 0xF7, 0xD9, 0xAE, 0x08, 0xFA, 0x56, + 0xEB, 0x3D, 0x44, 0x12, 0xFE, 0x78, 0x49, 0xFF, 0xFE, 0x70, 0x3C, 0x0D, 0xFC, 0x1B, 0x44, 0x32, + 0xFE, 0x7C, 0x04, 0x00, 0x00, 0x09, 0x3E, 0x07, 0x33, 0xA5, 0x40, 0x10, 0x20, 0x09, 0x3E, 0x17, + 0x33, 0xA6, 0x40, 0x10, 0x40, 0x09, 0x92, 0x18, 0x3E, 0x17, 0x33, 0xA7, 0x3E, 0x07, 0x33, 0xA8, + 0x44, 0x22, 0xFE, 0x7D, 0xF8, 0x05, 0x44, 0x32, 0xFE, 0x7E, 0x44, 0x22, 0xFE, 0x7F, 0xA6, 0x18, + 0xA6, 0x50, 0x96, 0x02, 0x96, 0x4A, 0xAE, 0x58, 0xAE, 0x10, 0x83, 0xFF, 0xD5, 0x08, 0xA4, 0x00, + 0x54, 0x00, 0x02, 0x00, 0xC0, 0x04, 0x84, 0x02, 0x49, 0x00, 0x0D, 0x84, 0x44, 0x13, 0xF0, 0x29, + 0xA6, 0x08, 0x58, 0x00, 0x00, 0x08, 0xAE, 0x08, 0x84, 0x00, 0xEA, 0x65, 0x3C, 0x0D, 0xFA, 0xBB, + 0x44, 0x13, 0xF0, 0x0E, 0xA6, 0x48, 0x10, 0x10, 0x00, 0x3C, 0x44, 0x13, 0xF0, 0x0F, 0xA6, 0x48, + 0x10, 0x10, 0x00, 0x3D, 0x49, 0x00, 0x2B, 0x1C, 0x3C, 0x0F, 0xFC, 0x2D, 0xFA, 0x04, 0xF8, 0x02, + 0xFA, 0x04, 0x49, 0x00, 0x5C, 0x41, 0xEA, 0x46, 0x9E, 0x81, 0xE6, 0x48, 0xE8, 0x0B, 0x84, 0x21, + 0x40, 0x10, 0x88, 0x0C, 0x54, 0x10, 0x80, 0x8F, 0xC1, 0x05, 0x50, 0x00, 0x7F, 0xE0, 0x96, 0x00, + 0xDD, 0x4A, 0x49, 0x00, 0x05, 0xC4, 0x3A, 0x6F, 0xA0, 0x84, 0xDD, 0x9E, 0x84, 0x01, 0x3C, 0x0F, + 0xFC, 0x59, 0xDD, 0x9E, 0x3B, 0xFF, 0xFE, 0xBC, 0x3C, 0x0D, 0xFC, 0x65, 0x8C, 0x01, 0xEB, 0xAC, + 0x2E, 0x07, 0xF2, 0xE2, 0x5A, 0x08, 0x01, 0x13, 0x3C, 0x1D, 0xFC, 0x65, 0x2E, 0x07, 0xF2, 0xE1, + 0xE2, 0x20, 0xE8, 0x04, 0x49, 0x00, 0x7B, 0x73, 0xD5, 0x09, 0x49, 0x00, 0x7B, 0x77, 0x84, 0x00, + 0x49, 0x00, 0x79, 0x81, 0x84, 0x00, 0x3E, 0x07, 0xF2, 0xE2, 0x3B, 0xFF, 0xFE, 0x84, 0xDD, 0x9E, + 0x3B, 0xFF, 0xFE, 0xBC, 0x3C, 0x0D, 0xFC, 0x69, 0x8C, 0x01, 0x3C, 0x0F, 0xFC, 0x69, 0xDD, 0x41, + 0xA6, 0x00, 0x8E, 0x01, 0xE6, 0x02, 0xE8, 0x2D, 0x2E, 0x07, 0xEE, 0xF8, 0x5A, 0x08, 0x55, 0x0A, + 0x3C, 0x03, 0xF7, 0xC7, 0x8C, 0x01, 0x96, 0x01, 0xE6, 0x0A, 0xEB, 0x7E, 0xE9, 0x1D, 0xD5, 0x08, + 0xDD, 0x40, 0xC0, 0x18, 0x2E, 0x07, 0xEE, 0xE9, 0x5A, 0x08, 0x55, 0x15, 0xD5, 0xF2, 0x84, 0x04, + 0xDD, 0x4A, 0x84, 0x01, 0x3E, 0x07, 0xF3, 0x76, 0x84, 0x00, 0xEA, 0x30, 0xDD, 0x41, 0xA6, 0x00, + 0x5A, 0x08, 0x01, 0x05, 0xEA, 0x92, 0xEA, 0x69, 0xD5, 0x07, 0x8E, 0x02, 0xE6, 0x02, 0xE9, 0x00, + 0xD5, 0x03, 0x84, 0x00, 0xEB, 0x7E, 0xEA, 0x40, 0x3E, 0x07, 0xEE, 0xF8, 0xEA, 0x97, 0xD5, 0x03, + 0x84, 0x00, 0xEB, 0x7E, 0x3B, 0xFF, 0xFE, 0x84, 0xDD, 0x9E, 0x3A, 0x6F, 0x98, 0xBC, 0x44, 0x03, + 0xF0, 0x6B, 0xA6, 0x00, 0x3E, 0x07, 0xEF, 0x67, 0xDD, 0x43, 0xC8, 0x06, 0x2E, 0x07, 0xEF, 0x67, + 0x96, 0x1F, 0x5A, 0x00, 0x0F, 0x16, 0xFA, 0x10, 0xDD, 0x4A, 0x84, 0x01, 0x3C, 0x0F, 0xFC, 0x6D, + 0xEB, 0xBF, 0x49, 0x00, 0x7C, 0x16, 0xDD, 0x41, 0x84, 0x22, 0xDD, 0x53, 0x49, 0x00, 0x7C, 0x29, + 0x84, 0x20, 0x84, 0x02, 0x84, 0x46, 0x80, 0x61, 0x80, 0x81, 0x80, 0xA1, 0xDD, 0x56, 0xEA, 0x25, + 0xDD, 0x9E, 0x3A, 0x6F, 0x9E, 0xBC, 0x49, 0x00, 0x7A, 0x4C, 0xC0, 0x16, 0x84, 0x00, 0x49, 0x00, + 0x7A, 0x4C, 0xF8, 0x23, 0x80, 0xC0, 0x5A, 0x08, 0x01, 0x10, 0xDD, 0x43, 0x5A, 0x08, 0x02, 0x04, + 0x3C, 0x6F, 0xFC, 0x66, 0x44, 0x00, 0x00, 0x80, 0xDD, 0x4A, 0xDD, 0x41, 0xEB, 0x8D, 0xEA, 0xD7, + 0x84, 0x61, 0x49, 0x00, 0x1D, 0x0D, 0x49, 0x00, 0x7A, 0x2B, 0xC0, 0x09, 0x84, 0x01, 0x3C, 0x0F, + 0xFC, 0x7A, 0x84, 0x00, 0x49, 0x00, 0x7A, 0x28, 0x49, 0x00, 0x32, 0xCE, 0x49, 0x00, 0x7A, 0x59, + 0xC0, 0x0F, 0x84, 0x00, 0x49, 0x00, 0x7A, 0x59, 0x49, 0x00, 0x7A, 0xA4, 0x80, 0x60, 0x5A, 0x08, + 0x01, 0x08, 0xEA, 0x71, 0xEB, 0x8D, 0xDD, 0x41, 0xEA, 0xD7, 0x49, 0x00, 0x1C, 0xF1, 0x49, 0x00, + 0x7A, 0x3F, 0xC0, 0x06, 0x84, 0x00, 0x49, 0x00, 0x7A, 0x3F, 0x84, 0x01, 0xEB, 0xD8, 0x3A, 0x6F, + 0x9E, 0x84, 0xDD, 0x9E, 0x3B, 0xFF, 0xFE, 0xBC, 0x84, 0x01, 0xEB, 0x1B, 0xDD, 0x40, 0x3C, 0x2D, + 0xFC, 0x3F, 0x5A, 0x08, 0x01, 0x0E, 0xA6, 0x50, 0xC9, 0x0B, 0x2E, 0x17, 0xEE, 0xDE, 0xE6, 0x2C, + 0xE9, 0x07, 0xEA, 0x8B, 0x8E, 0x34, 0xE6, 0x22, 0xE8, 0x03, 0x3E, 0x07, 0xEE, 0xEB, 0x84, 0x01, + 0xAE, 0x10, 0xEA, 0x34, 0x44, 0x13, 0x8D, 0x43, 0x3E, 0x07, 0xEE, 0xF8, 0xA6, 0x08, 0x8C, 0x01, + 0xAE, 0x08, 0xDD, 0x41, 0xA6, 0x41, 0x54, 0x10, 0x80, 0xFD, 0x5A, 0x10, 0x04, 0x0B, 0x2E, 0x17, + 0xF2, 0xB5, 0xC1, 0x05, 0x84, 0x02, 0x3E, 0x07, 0xF2, 0xB5, 0xD5, 0x03, 0x84, 0x21, 0xDD, 0x53, + 0x49, 0x00, 0x7B, 0x8A, 0xC8, 0x0B, 0x3E, 0x07, 0xEE, 0xB1, 0x2E, 0x07, 0xEF, 0x3B, 0x96, 0x00, + 0x5A, 0x08, 0x01, 0x0E, 0x3E, 0x07, 0xEE, 0xB1, 0xD5, 0x0A, 0x84, 0x09, 0xDD, 0x4A, 0xFA, 0x18, + 0xEA, 0x39, 0x84, 0x03, 0xEA, 0x6D, 0x84, 0x01, 0x3E, 0x07, 0xEF, 0x26, 0x2E, 0x07, 0xF2, 0xD3, + 0x8C, 0x01, 0x96, 0x00, 0x3E, 0x07, 0xF2, 0xD3, 0xDD, 0x40, 0xC8, 0x05, 0x84, 0x01, 0x3E, 0x07, + 0xF2, 0xC0, 0xD5, 0x14, 0xDD, 0x43, 0x5A, 0x08, 0x02, 0x12, 0xDD, 0x48, 0x5A, 0x00, 0x01, 0x05, + 0xDD, 0x48, 0x5A, 0x08, 0x02, 0x0C, 0x84, 0x00, 0xEB, 0x8F, 0xEB, 0x13, 0x44, 0x0F, 0xFF, 0xAF, + 0xAE, 0x08, 0x80, 0x41, 0x84, 0x02, 0x84, 0x68, 0xDD, 0x42, 0x3B, 0xFF, 0xFE, 0x84, 0xDD, 0x9E, + 0x3A, 0x6F, 0x98, 0xBC, 0x84, 0x01, 0x3C, 0x0F, 0xFC, 0x7F, 0xFA, 0x11, 0xDD, 0x4A, 0x44, 0x03, + 0xF0, 0x82, 0xA6, 0x00, 0xC0, 0x03, 0xEA, 0x92, 0xEA, 0x69, 0xEA, 0x25, 0xDD, 0x9E, 0x84, 0x01, + 0x3C, 0x0F, 0xFC, 0x63, 0xDD, 0x9E, 0x84, 0x01, 0x3C, 0x0F, 0xFC, 0x6E, 0xDD, 0x9E, 0x84, 0x01, + 0x3C, 0x0F, 0xFC, 0x6A, 0xDD, 0x9E, 0x84, 0x01, 0x3C, 0x0F, 0xFC, 0x77, 0xDD, 0x9E, 0x3A, 0x6F, + 0x98, 0xBC, 0xFA, 0x12, 0xDD, 0x4A, 0x84, 0x01, 0x3C, 0x0F, 0xFC, 0x6B, 0xEA, 0x25, 0xDD, 0x9E, + 0x84, 0x01, 0x3C, 0x0F, 0xFC, 0x67, 0xDD, 0x9E, 0x3A, 0x6F, 0x98, 0xBC, 0xFA, 0x13, 0xDD, 0x4A, + 0xEA, 0x25, 0xDD, 0x9E, 0x3A, 0x6F, 0x98, 0xBC, 0xFA, 0x14, 0xDD, 0x4A, 0x84, 0x01, 0x3C, 0x0F, + 0xFC, 0x5C, 0xEA, 0x25, 0xDD, 0x9E, 0x3B, 0xFF, 0xFE, 0xBC, 0x3C, 0x0D, 0xFC, 0x7D, 0xC8, 0x24, + 0xEB, 0x74, 0xC8, 0x22, 0xDD, 0x40, 0xC8, 0x20, 0xEB, 0x42, 0x5C, 0xF0, 0x00, 0xA0, 0xE9, 0x12, + 0x2E, 0x07, 0xF2, 0xB6, 0x5A, 0x08, 0x02, 0x0F, 0x44, 0x12, 0xBF, 0x2E, 0x80, 0x41, 0x84, 0x61, + 0xDD, 0x42, 0x44, 0x03, 0x58, 0x90, 0x44, 0x13, 0x80, 0x68, 0x44, 0x20, 0x0C, 0x80, 0x49, 0x00, + 0x0B, 0x05, 0x2E, 0x07, 0xF2, 0xB6, 0xC8, 0x03, 0x84, 0x01, 0xD5, 0x04, 0x5A, 0x08, 0x01, 0x05, + 0x84, 0x02, 0x3E, 0x07, 0xF2, 0xB6, 0x49, 0x00, 0x12, 0x27, 0x3C, 0x0D, 0xFC, 0x7D, 0x8C, 0x01, + 0x3C, 0x0F, 0xFC, 0x7D, 0x3C, 0x0D, 0xFC, 0x71, 0x8C, 0x01, 0x3C, 0x0F, 0xFC, 0x71, 0xEB, 0x1D, + 0xA6, 0x40, 0xEB, 0x74, 0x88, 0x01, 0x8C, 0x01, 0x3E, 0x07, 0xEE, 0xDE, 0x84, 0x00, 0xEB, 0x8F, + 0xEB, 0x3B, 0xC8, 0x0C, 0x84, 0x21, 0x3E, 0x17, 0xEE, 0xD5, 0x3C, 0x0F, 0xFC, 0x55, 0x49, 0x00, + 0x09, 0x66, 0x3C, 0x0E, 0x03, 0xD1, 0x49, 0x00, 0x0A, 0x9A, 0xDD, 0x52, 0x2E, 0x07, 0xEF, 0x62, + 0x5A, 0x08, 0x01, 0x0B, 0x84, 0x02, 0x44, 0x12, 0xBC, 0x12, 0x80, 0x41, 0x80, 0x60, 0xDD, 0x42, + 0x84, 0x00, 0x3E, 0x07, 0xEF, 0x62, 0xEA, 0x43, 0xC8, 0x03, 0x84, 0x01, 0xD5, 0x02, 0x84, 0x00, + 0xEB, 0x8F, 0x3B, 0xFF, 0xFE, 0x84, 0xDD, 0x9E, 0x3A, 0x6F, 0x98, 0xBC, 0x84, 0x01, 0x3C, 0x0F, + 0xFC, 0x68, 0x3E, 0x07, 0xF2, 0xD6, 0x44, 0x03, 0xF0, 0x7E, 0xA6, 0x40, 0x5A, 0x10, 0x01, 0x0F, + 0xA6, 0x40, 0x5A, 0x10, 0x02, 0x0C, 0xA6, 0x40, 0x5A, 0x10, 0x03, 0x09, 0xA6, 0x40, 0x5A, 0x10, + 0x04, 0x06, 0xA6, 0x40, 0x5A, 0x10, 0x10, 0x03, 0xA6, 0x00, 0x84, 0x41, 0x84, 0x20, 0x80, 0x62, + 0x80, 0x82, 0x44, 0x00, 0xB1, 0x01, 0xEA, 0xA7, 0x49, 0x00, 0x21, 0xB9, 0xEA, 0x25, 0xDD, 0x9E, + 0x84, 0x01, 0x3C, 0x0F, 0xFC, 0x82, 0xDD, 0x9E, 0x84, 0x01, 0x3C, 0x0F, 0xFC, 0x75, 0x44, 0x03, + 0xF0, 0x64, 0xA6, 0x40, 0x96, 0x4C, 0xC9, 0x10, 0xA6, 0x40, 0x58, 0x10, 0x80, 0x01, 0xAE, 0x40, + 0xDD, 0x41, 0xA6, 0x00, 0x8E, 0x02, 0xE6, 0x02, 0xE9, 0x0E, 0x3A, 0x6F, 0x98, 0xBC, 0xEA, 0x40, + 0xEA, 0x69, 0xEA, 0x25, 0xD5, 0x08, 0xA6, 0x40, 0x96, 0x4C, 0xC1, 0x05, 0xA6, 0x40, 0xEA, 0x5D, + 0xAE, 0x40, 0xDD, 0x9E, 0xDD, 0x9E, 0x3A, 0x6F, 0x98, 0xBC, 0xFA, 0x15, 0xDD, 0x4A, 0x84, 0x01, + 0x3C, 0x0F, 0xFC, 0x76, 0xEA, 0x25, 0xDD, 0x9E, 0x3A, 0x6F, 0x98, 0xBC, 0xFA, 0x16, 0xDD, 0x4A, + 0x84, 0x01, 0x3C, 0x0F, 0xFC, 0x73, 0xEA, 0x25, 0xDD, 0x9E, 0x3A, 0x6F, 0x98, 0xBC, 0xFA, 0x17, + 0xDD, 0x4A, 0x84, 0x01, 0x3C, 0x0F, 0xFC, 0x57, 0xEB, 0xA6, 0x5A, 0x08, 0xA1, 0x04, 0xEA, 0x40, + 0xEA, 0x69, 0x84, 0x03, 0xEA, 0x6D, 0xEA, 0x25, 0xDD, 0x9E, 0x3A, 0x6F, 0x9E, 0xBC, 0xEF, 0xD0, + 0x44, 0x01, 0x65, 0xC0, 0x3B, 0x00, 0x54, 0x00, 0xB1, 0x86, 0x44, 0x01, 0x65, 0xD8, 0x3B, 0x03, + 0x54, 0x20, 0x3B, 0x00, 0x50, 0x00, 0x84, 0x01, 0x3C, 0x0F, 0xFC, 0x7C, 0xEB, 0x16, 0xB1, 0xC1, + 0x8C, 0x01, 0x3C, 0x0F, 0xFC, 0x7E, 0x2E, 0x07, 0xEF, 0x0B, 0x3B, 0x03, 0xD0, 0x20, 0x8C, 0x01, + 0x96, 0x00, 0x3E, 0x07, 0xEF, 0x0B, 0x2E, 0x07, 0xEF, 0x0E, 0xC8, 0x09, 0xDD, 0x52, 0x5A, 0x08, + 0x02, 0x06, 0x2E, 0x07, 0xEF, 0x23, 0x5A, 0x00, 0x01, 0x03, 0xDD, 0x40, 0xDD, 0x40, 0xC0, 0x23, + 0xDD, 0x55, 0x5A, 0x08, 0x20, 0x21, 0x2E, 0x07, 0xF2, 0xB6, 0x5A, 0x08, 0x02, 0x1D, 0xEB, 0x16, + 0x5A, 0x08, 0x01, 0x08, 0x44, 0x02, 0x98, 0x8C, 0xEA, 0xBD, 0x44, 0x20, 0x19, 0x00, 0xDD, 0x46, + 0xDD, 0x52, 0x5A, 0x00, 0x01, 0x07, 0x84, 0x01, 0x84, 0x20, 0x49, 0x00, 0x1B, 0xEB, 0xD5, 0x0B, + 0x84, 0x5F, 0x44, 0x52, 0x98, 0x8C, 0x80, 0x62, 0x44, 0x02, 0xB1, 0x8C, 0x3A, 0x22, 0x8C, 0x24, + 0xD8, 0xFE, 0xD5, 0xF2, 0xDD, 0x48, 0x5A, 0x08, 0x01, 0x09, 0xEB, 0x16, 0x5A, 0x00, 0x0A, 0x35, + 0xEB, 0x16, 0x5A, 0x08, 0x0B, 0x39, 0xD5, 0x30, 0xDD, 0x48, 0x5A, 0x00, 0x02, 0xF8, 0xDD, 0x48, + 0x5A, 0x00, 0x05, 0x05, 0xDD, 0x48, 0x5A, 0x08, 0x06, 0x0C, 0x84, 0x00, 0x3C, 0x5D, 0xFC, 0x7E, + 0x38, 0x13, 0x02, 0x02, 0xD1, 0x21, 0x8C, 0x01, 0x5A, 0x08, 0x06, 0xFA, 0xD5, 0x24, 0xDD, 0x48, + 0x5A, 0x00, 0x03, 0x05, 0xDD, 0x48, 0x5A, 0x08, 0x04, 0x09, 0xEB, 0x74, 0x5A, 0x08, 0x0A, 0x1C, + 0xEB, 0x16, 0x5A, 0x08, 0x08, 0x19, 0xD5, 0x10, 0xDD, 0x48, 0x5A, 0x00, 0x07, 0x05, 0xDD, 0x48, + 0x5A, 0x08, 0x08, 0x12, 0xEB, 0x74, 0x5A, 0x08, 0x0A, 0x0F, 0x84, 0x00, 0x3C, 0x5D, 0xFC, 0x7E, + 0x38, 0x13, 0x82, 0x02, 0xD9, 0x05, 0x84, 0x01, 0x3C, 0x0F, 0xFC, 0x60, 0xD5, 0x04, 0x8C, 0x01, + 0x5A, 0x08, 0x05, 0xF6, 0xEC, 0x30, 0x3A, 0x6F, 0x9E, 0x84, 0xDD, 0x9E, 0x3A, 0x6F, 0x98, 0xBC, + 0xFA, 0x18, 0xDD, 0x4A, 0x84, 0x01, 0x3C, 0x0F, 0xFC, 0x6C, 0xEA, 0x40, 0xEA, 0x69, 0xEA, 0x25, + 0xDD, 0x9E, 0x84, 0x01, 0x3C, 0x0F, 0xFC, 0x62, 0xDD, 0x9E, 0x44, 0x03, 0xF4, 0x03, 0xA6, 0x00, + 0x96, 0x00, 0x5A, 0x08, 0x01, 0x04, 0x3C, 0x0F, 0xFC, 0x5E, 0xDD, 0x9E, 0x84, 0x01, 0x3C, 0x0F, + 0xFC, 0x61, 0xDD, 0x9E, 0xFC, 0x00, 0x84, 0x00, 0x84, 0x21, 0x3C, 0x1F, 0xFC, 0x61, 0x3E, 0x17, + 0xF3, 0x0C, 0x3C, 0x0F, 0xFC, 0x71, 0x3C, 0x0B, 0xF9, 0x56, 0x3C, 0x0F, 0xFC, 0x5F, 0x3E, 0x07, + 0xF2, 0xB0, 0x3C, 0x0F, 0xFC, 0x60, 0x3C, 0x0F, 0xFC, 0x70, 0xEB, 0x51, 0x3E, 0x00, 0x0D, 0x74, + 0xDD, 0x40, 0xFA, 0x24, 0xC0, 0x06, 0x3C, 0x1F, 0xFA, 0xC3, 0x3C, 0x1F, 0xFA, 0xC1, 0xD5, 0x05, + 0x3C, 0x1F, 0xFA, 0xC2, 0x3C, 0x1F, 0xFA, 0xC0, 0xDD, 0x41, 0xA6, 0x41, 0x9E, 0x8B, 0xE6, 0x42, + 0xE9, 0x05, 0x5A, 0x10, 0x06, 0x04, 0x5A, 0x18, 0x0D, 0x3C, 0xDD, 0x51, 0xA6, 0x48, 0x5A, 0x18, + 0x01, 0x38, 0xEA, 0x3E, 0xDD, 0x41, 0xA6, 0x01, 0x5A, 0x00, 0x03, 0x04, 0x5A, 0x08, 0x0D, 0x16, + 0xEB, 0x84, 0xC8, 0x13, 0x2E, 0x07, 0xEF, 0x4F, 0xC8, 0x10, 0x2E, 0x07, 0xEE, 0xCB, 0xC8, 0x0D, + 0xDD, 0x48, 0x5A, 0x00, 0x02, 0x05, 0xDD, 0x48, 0x5A, 0x08, 0x04, 0x08, 0xEB, 0x76, 0x49, 0x00, + 0x7E, 0xE0, 0xEB, 0x76, 0x3E, 0x07, 0xF2, 0xB3, 0x3C, 0x5D, 0xFC, 0x2B, 0xEB, 0xF7, 0xD0, 0x0A, + 0xEB, 0xA6, 0x5A, 0x08, 0xA3, 0x08, 0x2E, 0x07, 0xEF, 0x02, 0x5A, 0x08, 0x01, 0x04, 0x49, 0x00, + 0x6C, 0xF2, 0xDD, 0x48, 0x5A, 0x00, 0x03, 0x0B, 0xDD, 0x48, 0x5A, 0x00, 0x04, 0x08, 0xDD, 0x48, + 0x5A, 0x00, 0x07, 0x05, 0xDD, 0x48, 0x5A, 0x08, 0x08, 0x04, 0x49, 0x00, 0x7E, 0x2F, 0xDD, 0x40, + 0xC0, 0x04, 0x49, 0x00, 0x0D, 0x31, 0xD5, 0x05, 0x3E, 0x07, 0xEF, 0x15, 0x3E, 0x07, 0xEF, 0x31, + 0xDD, 0x41, 0xA6, 0x41, 0x5A, 0x10, 0x0D, 0x07, 0x9E, 0x8A, 0xE6, 0x42, 0xE9, 0x03, 0x5A, 0x18, + 0x07, 0x3A, 0xA6, 0x80, 0x5A, 0x28, 0x01, 0x37, 0xEA, 0xAE, 0xC8, 0x49, 0xDD, 0x58, 0xA6, 0x00, + 0x5A, 0x08, 0x01, 0x06, 0xDD, 0x4B, 0xA6, 0x00, 0x5A, 0x00, 0x01, 0x06, 0x2E, 0x07, 0xEF, 0x47, + 0x5A, 0x08, 0x01, 0x3E, 0x2E, 0x67, 0xEE, 0xCB, 0x84, 0x00, 0x3C, 0x0F, 0xFC, 0x7E, 0x5A, 0x68, + 0x01, 0x08, 0x44, 0x02, 0xBB, 0xB7, 0x49, 0x00, 0x30, 0x63, 0x3E, 0x67, 0xEE, 0xCA, 0xDD, 0x41, + 0x84, 0x20, 0xDD, 0x53, 0x84, 0x01, 0xEA, 0x30, 0x2E, 0x07, 0xEF, 0x47, 0x5A, 0x00, 0x01, 0x0B, + 0x2E, 0x07, 0xEE, 0xD9, 0xC8, 0x04, 0xDD, 0x50, 0xAE, 0x08, 0xD5, 0x04, 0x84, 0x00, 0x3E, 0x07, + 0xEE, 0xD9, 0xDD, 0x58, 0x84, 0x20, 0xAE, 0x40, 0x84, 0x09, 0xEA, 0x60, 0x84, 0x01, 0xEA, 0x6F, + 0xD5, 0x16, 0x5A, 0x18, 0x04, 0x15, 0x2E, 0x67, 0xF2, 0xC6, 0xCE, 0x11, 0xDD, 0x50, 0xA6, 0x48, + 0x5A, 0x10, 0x02, 0x0E, 0x80, 0x26, 0xEA, 0xE9, 0xDD, 0x53, 0x84, 0x01, 0xEA, 0x30, 0xDD, 0x58, + 0xAF, 0x80, 0xDD, 0x4B, 0xAF, 0x80, 0x84, 0x01, 0x3E, 0x07, 0xF2, 0xC6, 0xFC, 0x80, 0xFC, 0x20, + 0xDD, 0x48, 0x5A, 0x00, 0x01, 0x09, 0xDD, 0x48, 0x5A, 0x00, 0x02, 0x06, 0x2E, 0x07, 0xEF, 0x4F, + 0x5A, 0x08, 0x01, 0x0D, 0xEA, 0xAE, 0xC8, 0x0A, 0xDD, 0x58, 0xA6, 0x00, 0x96, 0x00, 0xC8, 0x06, + 0xDD, 0x50, 0xA6, 0x88, 0x5A, 0x28, 0x01, 0x03, 0xAE, 0x08, 0x2E, 0x07, 0xEE, 0xE2, 0xC0, 0x21, + 0xDD, 0x48, 0x5A, 0x08, 0x01, 0x1F, 0x2E, 0x67, 0xEE, 0xB3, 0x84, 0x00, 0x97, 0xB0, 0x3E, 0x07, + 0xEE, 0xE2, 0xCE, 0x17, 0xDD, 0x58, 0xA6, 0x00, 0x5A, 0x08, 0x01, 0x14, 0xDD, 0x4B, 0xA7, 0xC0, + 0x97, 0xF8, 0x5A, 0x78, 0x01, 0x0F, 0xDD, 0x41, 0x80, 0x26, 0xEA, 0xE9, 0xDD, 0x53, 0x80, 0x07, + 0xEA, 0x30, 0xDD, 0x58, 0xAF, 0x80, 0x2E, 0x07, 0xEF, 0x26, 0xC8, 0x03, 0xDD, 0x50, 0xAE, 0x08, + 0xFC, 0xA0, 0x3A, 0x6F, 0x9E, 0xBC, 0x49, 0x00, 0x04, 0xFC, 0xDD, 0x40, 0xC8, 0x08, 0x2E, 0x07, + 0xEF, 0x69, 0x5A, 0x08, 0x01, 0x03, 0xF8, 0x0F, 0x84, 0x01, 0xEB, 0x81, 0x2E, 0x07, 0xEE, 0xCB, + 0x5A, 0x08, 0x01, 0x0C, 0x2E, 0x07, 0xEE, 0xCA, 0x5A, 0x08, 0x01, 0x08, 0x84, 0x00, 0x3E, 0x07, + 0xEE, 0xCA, 0xEB, 0x81, 0x48, 0x00, 0x00, 0x9C, 0x2E, 0x07, 0xEE, 0xEB, 0x5A, 0x08, 0x01, 0x07, + 0x3E, 0x07, 0xEE, 0xDC, 0x84, 0x00, 0x3E, 0x07, 0xEE, 0xEB, 0xF8, 0x46, 0xC0, 0x2A, 0xEA, 0x43, + 0x80, 0xC0, 0x5A, 0x08, 0x01, 0x27, 0xDD, 0x40, 0xC0, 0x0A, 0x3C, 0x1D, 0xFC, 0xD3, 0xDD, 0x54, + 0xAE, 0x40, 0x49, 0x00, 0x06, 0xC3, 0x84, 0x00, 0xEB, 0xE7, 0xD5, 0x1B, 0x44, 0x12, 0xBC, 0x84, + 0x80, 0x41, 0x84, 0x64, 0x84, 0x02, 0xDD, 0x42, 0x44, 0x13, 0x8D, 0x4F, 0x44, 0x23, 0xF3, 0x69, + 0x80, 0x66, 0x84, 0x02, 0xDD, 0x42, 0xEB, 0xA6, 0x5A, 0x08, 0xA3, 0x08, 0x44, 0x12, 0xBC, 0xE8, + 0x84, 0x02, 0x80, 0x41, 0x84, 0x66, 0xDD, 0x42, 0x84, 0x00, 0xEB, 0xE7, 0x49, 0x00, 0x04, 0x74, + 0xF8, 0x1B, 0xC0, 0x1A, 0xEA, 0x43, 0x5A, 0x08, 0x01, 0x18, 0x2E, 0x17, 0xEF, 0x1E, 0x5A, 0x18, + 0x0A, 0x14, 0x2E, 0x67, 0xEE, 0xDC, 0x5A, 0x68, 0x01, 0x0D, 0x49, 0x00, 0x0E, 0x6E, 0xDD, 0x41, + 0x84, 0x20, 0xDD, 0x53, 0x80, 0x06, 0xEA, 0x30, 0x84, 0x00, 0x3C, 0x0F, 0xFC, 0x7E, 0xD5, 0x04, + 0x84, 0x00, 0x49, 0x00, 0x0E, 0x62, 0x49, 0x00, 0x2D, 0xF9, 0xC0, 0x21, 0x84, 0x01, 0x3C, 0x0F, + 0xFC, 0x72, 0x3E, 0x07, 0xEE, 0xB6, 0xEA, 0x43, 0x5A, 0x08, 0x01, 0x0B, 0x49, 0xFF, 0xFE, 0x8C, + 0x2E, 0x07, 0xEE, 0xB7, 0x96, 0x00, 0xC0, 0x02, 0x84, 0x0A, 0x3E, 0x07, 0xEF, 0x1E, 0x2E, 0x07, + 0xEF, 0x12, 0x5A, 0x08, 0x01, 0x04, 0x49, 0x00, 0x10, 0xFD, 0xDD, 0x52, 0x5A, 0x08, 0x02, 0x04, + 0x84, 0x01, 0xD5, 0x02, 0x84, 0x00, 0x3E, 0x07, 0xEF, 0x23, 0xD5, 0x09, 0x84, 0x02, 0x3E, 0x07, + 0xEE, 0xB6, 0x49, 0xFF, 0xFF, 0x36, 0xDD, 0x58, 0xA6, 0x00, 0xF8, 0x5F, 0x84, 0x01, 0x3C, 0x0F, + 0xFC, 0x79, 0x84, 0x00, 0x3C, 0x0F, 0xFC, 0x7D, 0xDD, 0x40, 0xC8, 0x03, 0x49, 0x00, 0x34, 0x00, + 0xDD, 0x40, 0xC0, 0x11, 0x44, 0x03, 0xF3, 0x69, 0xA6, 0x00, 0x96, 0x16, 0xC0, 0x04, 0x44, 0x00, + 0x00, 0xC9, 0xDD, 0x4A, 0x44, 0x03, 0x8D, 0x4F, 0xA6, 0x00, 0x96, 0x16, 0xC0, 0x04, 0x44, 0x00, + 0x00, 0xCA, 0xDD, 0x4A, 0x84, 0x00, 0xEB, 0x81, 0x49, 0x00, 0x04, 0x6F, 0x3A, 0x6F, 0x9E, 0x84, + 0xDD, 0x9E, 0xDD, 0x9E, 0x3A, 0x6F, 0x98, 0xBC, 0xFA, 0x19, 0xDD, 0x4A, 0x84, 0x01, 0x3C, 0x0F, + 0xFC, 0x81, 0x49, 0x00, 0x71, 0xC3, 0xEA, 0x43, 0xC8, 0x04, 0x49, 0x00, 0x77, 0xEA, 0xD5, 0x03, + 0x49, 0x00, 0x71, 0x86, 0xEA, 0x25, 0xDD, 0x9E, 0x84, 0x01, 0x3C, 0x0F, 0xFC, 0x74, 0xDD, 0x9E, + 0x84, 0x01, 0x3C, 0x0F, 0xFC, 0x5D, 0xDD, 0x9E, 0x3A, 0x6F, 0x98, 0xBC, 0x84, 0x01, 0xEA, 0x6F, + 0xEA, 0x25, 0xDD, 0x9E, 0xDD, 0x9E, 0x3A, 0x6F, 0x98, 0xBC, 0x84, 0x01, 0xF8, 0x06, 0xEA, 0x25, + 0xDD, 0x9E, 0x3A, 0x6F, 0x98, 0xBC, 0x84, 0x00, 0x49, 0x00, 0x0B, 0xF6, 0xEA, 0x25, 0xDD, 0x9E, + 0x3A, 0x6F, 0x98, 0xBC, 0xFA, 0x1B, 0xDD, 0x4A, 0xDD, 0x40, 0xC0, 0x03, 0xEA, 0x92, 0xEA, 0x69, + 0xEA, 0x25, 0xDD, 0x9E, 0x3A, 0x6F, 0x98, 0xBC, 0x49, 0x00, 0x0B, 0xAF, 0xEA, 0x25, 0xDD, 0x9E, + 0x44, 0x13, 0xF7, 0xEE, 0xA6, 0x08, 0x96, 0x00, 0x96, 0x84, 0xC2, 0x03, 0xEA, 0x8F, 0xAE, 0x08, + 0xDD, 0x9E, 0x3A, 0x6F, 0x98, 0xBC, 0x84, 0x01, 0x3C, 0x0F, 0xFC, 0x78, 0x44, 0x13, 0xF7, 0xEF, + 0xA6, 0x08, 0xEA, 0x8F, 0xAE, 0x08, 0x2E, 0x07, 0xEE, 0xD2, 0x5A, 0x08, 0x01, 0x06, 0x84, 0x00, + 0x3E, 0x07, 0xEE, 0xD2, 0xD5, 0x0C, 0x2E, 0x07, 0xEF, 0x64, 0x5A, 0x08, 0x01, 0x07, 0x49, 0x00, + 0x07, 0x7B, 0x49, 0x00, 0x07, 0x54, 0xD5, 0x03, 0x49, 0x00, 0x0B, 0x0F, 0x2E, 0x07, 0xF2, 0xC0, + 0xC0, 0x04, 0x8E, 0x01, 0x3E, 0x07, 0xF2, 0xC0, 0xEA, 0x25, 0xDD, 0x9E, 0x3B, 0xFF, 0xFE, 0xBC, + 0xDD, 0x43, 0x5A, 0x08, 0x02, 0x04, 0x84, 0x01, 0xEB, 0x55, 0x2E, 0x07, 0xF2, 0xC3, 0x44, 0x13, + 0xF7, 0xC9, 0x8E, 0x01, 0xEB, 0x68, 0xA6, 0x08, 0xEA, 0x8F, 0xAE, 0x08, 0x44, 0x03, 0xF7, 0xF0, + 0xA6, 0x00, 0x96, 0x04, 0xC8, 0x03, 0x49, 0x00, 0x09, 0xBD, 0xDD, 0x40, 0xC0, 0x0D, 0xDD, 0x5F, + 0x5A, 0x08, 0x07, 0x0B, 0x2E, 0x00, 0x0D, 0xDD, 0x5A, 0x08, 0x01, 0x15, 0x84, 0x00, 0xEB, 0x51, + 0x84, 0x08, 0xEA, 0x4D, 0xD5, 0x0F, 0xDD, 0x40, 0xC8, 0x0D, 0x3C, 0x1D, 0xFA, 0xC0, 0x5A, 0x18, + 0x01, 0x0A, 0x2E, 0x10, 0x0D, 0x74, 0xC1, 0x06, 0x3E, 0x00, 0x0D, 0x74, 0x84, 0x02, 0x3C, 0x0F, + 0xFA, 0xC0, 0xDD, 0x40, 0xC8, 0x0D, 0xEA, 0xE6, 0xA6, 0x00, 0xC0, 0x0A, 0x44, 0x00, 0x00, 0x81, + 0xDD, 0x4A, 0xDD, 0x41, 0xEB, 0x8D, 0xEA, 0xD7, 0x84, 0x61, 0x49, 0x00, 0x18, 0x69, 0x3B, 0xFF, + 0xFE, 0x84, 0xDD, 0x9E, 0x44, 0x13, 0xF7, 0xCA, 0xA6, 0x08, 0x96, 0x00, 0x96, 0x84, 0xC2, 0x03, + 0xEA, 0x8F, 0xAE, 0x08, 0xDD, 0x9E, 0x3A, 0x6F, 0x98, 0xBC, 0x2E, 0x07, 0xEF, 0x6A, 0xC8, 0x04, + 0x84, 0x01, 0x3E, 0x07, 0xEF, 0x6A, 0xFA, 0x1A, 0xDD, 0x4A, 0xEA, 0x92, 0xEA, 0x69, 0xEA, 0x25, + 0xDD, 0x9E, 0xFC, 0x00, 0x49, 0x00, 0x3C, 0xCF, 0x2E, 0x07, 0xEF, 0x05, 0xC8, 0x5E, 0x84, 0x03, + 0xEB, 0xC3, 0xDD, 0x44, 0xEB, 0x30, 0x44, 0x12, 0xBC, 0x60, 0x49, 0x00, 0x47, 0x04, 0xDD, 0x55, + 0x5A, 0x08, 0x14, 0x0B, 0x84, 0x03, 0x44, 0x10, 0x00, 0xA6, 0xDD, 0x44, 0x3C, 0x0D, 0xFC, 0x23, + 0xEA, 0x8B, 0xF8, 0x47, 0xD5, 0x48, 0x2E, 0x00, 0x0F, 0x6E, 0xC8, 0x45, 0xEB, 0x30, 0x49, 0x00, + 0x46, 0xFD, 0x2E, 0x00, 0x0A, 0x90, 0x5A, 0x08, 0x01, 0x31, 0xEB, 0x30, 0x49, 0x00, 0x47, 0x13, + 0xDD, 0x55, 0x5A, 0x00, 0x15, 0x0E, 0x3C, 0x1C, 0x03, 0xDC, 0x5A, 0x10, 0x05, 0x03, 0xC9, 0x05, + 0x84, 0x20, 0x3C, 0x1E, 0x03, 0xD3, 0xD5, 0x04, 0x84, 0x22, 0x3C, 0x1E, 0x03, 0xD3, 0x8E, 0x14, + 0xE6, 0x02, 0xE9, 0x0C, 0x2E, 0x07, 0xEF, 0x00, 0xC8, 0x07, 0x3C, 0x00, 0x07, 0xF4, 0xC0, 0x06, + 0x8E, 0x01, 0xEA, 0x98, 0xD5, 0x03, 0xEA, 0x47, 0xEA, 0x98, 0x2E, 0x07, 0xEF, 0x40, 0x96, 0x00, + 0x5A, 0x00, 0x01, 0x05, 0x49, 0x00, 0x99, 0x9C, 0xD5, 0x08, 0x3E, 0x07, 0xEE, 0xE7, 0x2E, 0x07, + 0xEE, 0xE7, 0x5A, 0x00, 0x01, 0xFE, 0xD5, 0xF7, 0xDD, 0x55, 0x5A, 0x08, 0x15, 0x0D, 0x49, 0x00, + 0x47, 0x50, 0x84, 0x03, 0x44, 0x10, 0x00, 0xA8, 0xDD, 0x44, 0x3C, 0x0D, 0xFC, 0x23, 0xEA, 0x8B, + 0x49, 0x00, 0x36, 0x34, 0x84, 0x01, 0xEA, 0xAF, 0xFC, 0x80, 0xFC, 0x40, 0x49, 0x00, 0x32, 0xBA, + 0x5A, 0x00, 0x08, 0x13, 0x49, 0x00, 0x33, 0x2E, 0x2E, 0x07, 0xF3, 0x80, 0x44, 0x10, 0x00, 0xA0, + 0x8C, 0x01, 0x3E, 0x07, 0xF3, 0x80, 0x84, 0x03, 0xDD, 0x44, 0x49, 0x00, 0x33, 0x47, 0x84, 0x03, + 0x44, 0x10, 0x00, 0xA1, 0xDD, 0x44, 0x84, 0xE0, 0x85, 0x23, 0x85, 0x41, 0xEA, 0x2E, 0x5A, 0x08, + 0x01, 0x11, 0x2E, 0x07, 0xEF, 0x24, 0x5A, 0x08, 0x01, 0x0D, 0xDD, 0x43, 0x5A, 0x08, 0x02, 0x0A, + 0xDD, 0x41, 0xA6, 0x01, 0x5A, 0x00, 0x06, 0x06, 0x5A, 0x00, 0x0B, 0x04, 0x49, 0x00, 0x87, 0x22, + 0xDD, 0x40, 0x44, 0x10, 0x00, 0xA2, 0x4E, 0x02, 0x00, 0x7C, 0x84, 0x03, 0xDD, 0x44, 0x49, 0x00, + 0x33, 0x5E, 0x5A, 0x00, 0x03, 0xD1, 0x5A, 0x08, 0x02, 0x07, 0x84, 0x04, 0x44, 0x10, 0x00, 0x60, + 0xDD, 0x44, 0xD5, 0xCB, 0x5A, 0x00, 0x13, 0xDC, 0xF8, 0x7D, 0xF8, 0x81, 0x5A, 0x00, 0x02, 0xC6, + 0x5A, 0x00, 0x13, 0xD6, 0xEB, 0x53, 0x84, 0x03, 0xDD, 0x44, 0xDD, 0x50, 0xA7, 0x88, 0x97, 0xB0, + 0xCE, 0xCE, 0x2E, 0x27, 0xEF, 0x65, 0x5A, 0x28, 0x01, 0xCB, 0x3C, 0x0D, 0xFC, 0xD3, 0x8E, 0x01, + 0xE6, 0x02, 0xE8, 0x03, 0xAE, 0x88, 0xD5, 0xC3, 0x84, 0x03, 0xEB, 0xC3, 0xDD, 0x44, 0x3E, 0x67, + 0xF3, 0x7E, 0x49, 0x00, 0x34, 0x8E, 0xDD, 0x55, 0x5A, 0x08, 0x12, 0x09, 0xEA, 0x79, 0x84, 0x20, + 0xEA, 0x84, 0x5A, 0x08, 0x01, 0x04, 0x84, 0x00, 0xF8, 0x3E, 0xDD, 0x55, 0x5A, 0x08, 0x04, 0x0C, + 0x49, 0x00, 0x37, 0x94, 0x84, 0x00, 0xEA, 0x9A, 0x84, 0x03, 0x44, 0x10, 0x00, 0xA6, 0xDD, 0x44, + 0xF8, 0x31, 0xD5, 0x33, 0x5A, 0x08, 0x14, 0x0A, 0x84, 0x00, 0xEA, 0x9A, 0x84, 0x03, 0x44, 0x10, + 0x00, 0xA7, 0xDD, 0x44, 0xF8, 0x27, 0xD5, 0x29, 0x5A, 0x08, 0x19, 0x08, 0x84, 0x00, 0x80, 0x20, + 0x49, 0x00, 0x18, 0x18, 0x3E, 0xA7, 0xEE, 0xC2, 0x49, 0x00, 0x34, 0xA8, 0x49, 0x00, 0x38, 0x4E, + 0x5A, 0x08, 0x02, 0x04, 0x48, 0xFF, 0xFF, 0x7A, 0xDD, 0x55, 0x5A, 0x08, 0x05, 0x0C, 0x49, 0x00, + 0x37, 0x6C, 0x84, 0x00, 0xEA, 0x9A, 0x84, 0x03, 0x44, 0x10, 0x00, 0xA8, 0xDD, 0x44, 0xF8, 0x0A, + 0xD5, 0x0C, 0x5A, 0x08, 0x15, 0x0B, 0x84, 0x00, 0xEA, 0x9A, 0x84, 0x03, 0x44, 0x10, 0x00, 0xA9, + 0xDD, 0x44, 0xEA, 0x61, 0xEA, 0x28, 0xEA, 0x36, 0x49, 0x00, 0x37, 0x28, 0xF8, 0x4C, 0x84, 0x03, + 0xDD, 0x44, 0x49, 0x00, 0x3A, 0x95, 0x80, 0xC0, 0x84, 0x01, 0xEB, 0xF3, 0x5A, 0x08, 0x01, 0x04, + 0x48, 0xFF, 0xFF, 0x85, 0x5A, 0x68, 0x03, 0x04, 0x48, 0xFF, 0xFF, 0x4E, 0x5A, 0x68, 0x13, 0x03, + 0xF8, 0x3A, 0x84, 0x03, 0x44, 0x10, 0x00, 0xA3, 0xDD, 0x44, 0xEB, 0x6F, 0x49, 0x00, 0x3B, 0xE0, + 0x5A, 0x08, 0x13, 0x03, 0xF8, 0x30, 0x84, 0x03, 0xEB, 0x53, 0xDD, 0x44, 0xDD, 0x4B, 0xA6, 0x00, + 0xC8, 0x07, 0xDD, 0x41, 0xA6, 0x41, 0x5A, 0x18, 0x0D, 0x04, 0x10, 0x90, 0x00, 0x01, 0x44, 0x00, + 0x00, 0xA3, 0xEB, 0x98, 0x49, 0xFF, 0xFE, 0xC7, 0x2E, 0x07, 0xEF, 0x3A, 0x5A, 0x08, 0x05, 0x15, + 0xDD, 0x58, 0xA6, 0x00, 0x5A, 0x00, 0x01, 0x05, 0xEB, 0x3B, 0x5A, 0x08, 0x01, 0x0E, 0xEA, 0xB0, + 0x5A, 0x08, 0x09, 0x0B, 0x2E, 0x17, 0xF0, 0x8C, 0x2E, 0x27, 0xEF, 0x2F, 0x2E, 0x07, 0xEF, 0x3A, + 0x49, 0x00, 0x0A, 0x1A, 0xF8, 0x08, 0x2E, 0x07, 0xEF, 0x3A, 0x5A, 0x00, 0x06, 0x03, 0xF8, 0x03, + 0x3C, 0x7B, 0xF7, 0xCE, 0x48, 0xFF, 0xFF, 0x24, 0x3C, 0x0F, 0xFC, 0xF1, 0xDD, 0x9E, 0x3C, 0x0F, + 0xFC, 0xF0, 0xDD, 0x9E, 0xFC, 0x20, 0x3C, 0x6D, 0xFC, 0xF0, 0x84, 0xE1, 0xA7, 0x72, 0xA7, 0xB3, + 0xC2, 0x02, 0x84, 0xFF, 0xC9, 0x08, 0x9E, 0x69, 0xFF, 0x44, 0x42, 0x51, 0x04, 0x73, 0xB6, 0xA3, + 0x88, 0xA7, 0xD5, 0x0B, 0x9E, 0x71, 0xFE, 0x8C, 0x80, 0x20, 0x42, 0x11, 0x14, 0x73, 0x88, 0x47, + 0x42, 0x01, 0x14, 0x73, 0xB6, 0x23, 0x80, 0xA0, 0xB6, 0xA4, 0xFC, 0xA0, 0xFC, 0x63, 0x84, 0xC0, + 0x81, 0xA0, 0x81, 0x41, 0xF2, 0x81, 0x81, 0x83, 0x80, 0xE4, 0x81, 0x65, 0x81, 0x03, 0x81, 0x26, + 0xE2, 0xE8, 0xE9, 0x12, 0x80, 0x08, 0xF1, 0x12, 0xF2, 0x01, 0xB0, 0xC2, 0xB1, 0x03, 0x49, 0xFF, + 0xFF, 0xD3, 0xF0, 0x02, 0x8D, 0x01, 0x38, 0x06, 0x81, 0x11, 0x89, 0x20, 0xF0, 0x03, 0x38, 0x06, + 0x81, 0x11, 0x88, 0xC0, 0xD5, 0xEE, 0x8A, 0xEC, 0x84, 0x05, 0xFF, 0xFB, 0x42, 0x63, 0x80, 0x73, + 0x84, 0x41, 0x42, 0x23, 0x08, 0x00, 0x80, 0x0A, 0x80, 0x29, 0x49, 0x00, 0x53, 0xAC, 0x00, 0x25, + 0x80, 0x00, 0x5A, 0x20, 0xFF, 0x06, 0x8C, 0x41, 0x88, 0x40, 0x40, 0x01, 0x04, 0x09, 0xEB, 0x17, + 0xB0, 0x44, 0xB0, 0x85, 0x49, 0x00, 0x54, 0x69, 0xF0, 0x04, 0x38, 0x15, 0x01, 0x11, 0xF0, 0x05, + 0x38, 0x25, 0x01, 0x11, 0x84, 0x02, 0xEB, 0xE2, 0x42, 0x04, 0x88, 0x73, 0xEA, 0x9F, 0xFC, 0xE3, + 0xFC, 0x66, 0x81, 0x41, 0x3C, 0x1D, 0xFC, 0xF0, 0xF2, 0x82, 0x00, 0x20, 0x80, 0x32, 0xF2, 0x83, + 0x00, 0x20, 0x80, 0x33, 0xF2, 0x84, 0x20, 0x20, 0x80, 0x39, 0xF2, 0x85, 0x20, 0x80, 0x80, 0x3A, + 0xA6, 0x8A, 0xA6, 0x4B, 0x50, 0xE0, 0x00, 0x24, 0x96, 0x0A, 0xF0, 0x89, 0x9E, 0x12, 0xF0, 0x86, + 0x96, 0x12, 0xF0, 0x8A, 0x9E, 0x0A, 0x44, 0x92, 0xBF, 0xFC, 0x85, 0x60, 0x50, 0xC0, 0xFF, 0xFF, + 0x50, 0xD1, 0x7F, 0xFF, 0xF0, 0x87, 0x3C, 0x0D, 0xFC, 0xF0, 0x00, 0x00, 0x00, 0x09, 0xE3, 0x60, + 0x4E, 0xF2, 0x00, 0xF5, 0x04, 0x07, 0x7F, 0xF7, 0x4E, 0x02, 0x00, 0xDF, 0x8E, 0x04, 0xE6, 0x02, + 0x4E, 0xF3, 0x00, 0xDB, 0x04, 0x07, 0x00, 0x04, 0x5A, 0x08, 0x02, 0x04, 0x48, 0x00, 0x00, 0xD5, + 0x04, 0x67, 0x7F, 0xFF, 0xEB, 0x22, 0x95, 0xF2, 0x88, 0x07, 0xA6, 0xC0, 0xCB, 0x2A, 0xA6, 0x42, + 0xE6, 0x22, 0xE9, 0x02, 0x9E, 0xC9, 0xA7, 0x03, 0xF0, 0x07, 0xE0, 0x80, 0xE8, 0x03, 0x8C, 0x81, + 0xD5, 0x02, 0x80, 0x8C, 0x86, 0x40, 0x80, 0x52, 0xB7, 0xDF, 0xEB, 0x9D, 0x80, 0xAE, 0xF0, 0x02, + 0x15, 0x2F, 0x80, 0x0B, 0xF8, 0x93, 0xF0, 0x88, 0xF2, 0x05, 0xB6, 0x5F, 0x04, 0x05, 0x00, 0x06, + 0xEB, 0xC9, 0x05, 0x2F, 0x80, 0x0B, 0xF2, 0x08, 0x15, 0x2F, 0x80, 0x01, 0xEB, 0x71, 0xEB, 0xC6, + 0x80, 0x62, 0x84, 0x9F, 0xF5, 0x03, 0xF8, 0x90, 0x22, 0x17, 0x7F, 0xF0, 0xE0, 0x01, 0xD5, 0x30, + 0xA7, 0x41, 0x4C, 0x56, 0xC0, 0x33, 0xA6, 0xC2, 0xE6, 0x62, 0xE9, 0x03, 0x8E, 0x61, 0xD5, 0x02, + 0x84, 0x60, 0xA7, 0x03, 0xF0, 0x07, 0xE0, 0x80, 0xE8, 0x03, 0x8C, 0x81, 0xD5, 0x02, 0x80, 0x8C, + 0xEB, 0x9D, 0x86, 0x40, 0xB7, 0xDF, 0x50, 0x10, 0x80, 0xA2, 0x84, 0x41, 0x80, 0xAE, 0xF0, 0x02, + 0x15, 0x2F, 0x80, 0x0B, 0xF8, 0x63, 0xF0, 0x88, 0xF2, 0x05, 0xB6, 0x5F, 0x04, 0x05, 0x00, 0x06, + 0xEB, 0xC9, 0x05, 0x2F, 0x80, 0x0B, 0xF2, 0x08, 0x15, 0x2F, 0x80, 0x01, 0xEB, 0x71, 0xEB, 0xC6, + 0x80, 0x62, 0xF4, 0x0A, 0xF5, 0x03, 0xF8, 0x60, 0x22, 0x17, 0x7F, 0xF0, 0xE0, 0x20, 0x40, 0x10, + 0x3C, 0x1B, 0x12, 0x17, 0x7F, 0xF4, 0xD5, 0x07, 0x84, 0x1F, 0xEB, 0x77, 0x02, 0x07, 0x7F, 0xF0, + 0x12, 0x07, 0x7F, 0xF4, 0xEB, 0x22, 0x88, 0xE0, 0xA6, 0xFA, 0xCB, 0x27, 0xA6, 0x38, 0xE6, 0x02, + 0xE9, 0x02, 0x9E, 0xC1, 0xA7, 0x39, 0xF0, 0x06, 0xE0, 0x80, 0xE8, 0x03, 0x8C, 0x81, 0xD5, 0x02, + 0x80, 0x8D, 0xEB, 0x9D, 0x84, 0xE1, 0x50, 0x10, 0x81, 0x44, 0x84, 0x40, 0x40, 0x57, 0x1C, 0x00, + 0xB6, 0xFF, 0xF0, 0x02, 0xF8, 0x2B, 0xF0, 0x88, 0xEB, 0xC9, 0x04, 0x05, 0x00, 0x07, 0xF2, 0x08, + 0xB7, 0x1F, 0xF7, 0x81, 0xEB, 0x71, 0xEB, 0xC6, 0x80, 0x62, 0x84, 0x9F, 0xF5, 0x04, 0xF8, 0x2C, + 0x22, 0x17, 0x7F, 0xF1, 0xE0, 0x01, 0xD5, 0x2D, 0xA7, 0x7B, 0x4C, 0x56, 0x40, 0x30, 0xA6, 0xF8, + 0xE6, 0x62, 0xE9, 0x03, 0x8E, 0x61, 0xD5, 0x02, 0x84, 0x60, 0xA7, 0x39, 0xF0, 0x06, 0xE0, 0x80, + 0xE8, 0x03, 0x8C, 0x81, 0xD5, 0x02, 0x80, 0x8D, 0xEB, 0x9D, 0x84, 0xE1, 0x50, 0x10, 0x81, 0xE6, + 0x80, 0x47, 0x40, 0x57, 0x1C, 0x00, 0xB6, 0xFF, 0xF0, 0x02, 0x49, 0xFF, 0xFE, 0xD9, 0xF0, 0x88, + 0xEB, 0xC9, 0x04, 0x05, 0x00, 0x07, 0xF2, 0x08, 0xB7, 0x1F, 0xF7, 0x81, 0xEB, 0x71, 0xEB, 0xC6, + 0x80, 0x62, 0xF4, 0x09, 0xF5, 0x04, 0x49, 0x00, 0x53, 0xEB, 0x22, 0x17, 0x7F, 0xF1, 0xE0, 0x20, + 0x40, 0x10, 0x3C, 0x1B, 0x12, 0x17, 0x7F, 0xF5, 0xD5, 0x08, 0x84, 0x1F, 0x10, 0x07, 0x00, 0x01, + 0x02, 0x07, 0x7F, 0xF1, 0x12, 0x07, 0x7F, 0xF5, 0x22, 0x07, 0x7F, 0xF4, 0xEA, 0xBC, 0x22, 0x07, + 0x7F, 0xF5, 0xEB, 0xEA, 0xD5, 0x0D, 0x22, 0x04, 0x80, 0x00, 0x12, 0x07, 0x7F, 0xF4, 0x22, 0x04, + 0x80, 0x01, 0x12, 0x07, 0x7F, 0xF5, 0x84, 0x1F, 0xEB, 0x77, 0x10, 0x07, 0x00, 0x01, 0x8D, 0x61, + 0x8D, 0x24, 0x50, 0xE7, 0x00, 0x54, 0x48, 0xFF, 0xFF, 0x08, 0xFC, 0xE6, 0x5A, 0x00, 0x01, 0x05, + 0x44, 0x03, 0xF7, 0xDE, 0xD5, 0x03, 0x44, 0x03, 0xF7, 0xDD, 0x44, 0x10, 0x00, 0x69, 0xAE, 0x40, + 0xEA, 0x37, 0x84, 0x20, 0xAE, 0x40, 0xDD, 0x9E, 0x84, 0x01, 0xDD, 0x9E, 0xFC, 0x20, 0x44, 0x73, + 0xF0, 0x80, 0xA7, 0xB8, 0x97, 0xB0, 0x54, 0x33, 0x00, 0x1F, 0x58, 0x31, 0x80, 0xA0, 0xAE, 0xF8, + 0xDD, 0x46, 0xAF, 0xB8, 0xFC, 0xA0, 0xEA, 0x3A, 0x8E, 0x01, 0xEA, 0xB8, 0xDD, 0x9E, 0x44, 0x10, + 0x00, 0x55, 0xDD, 0x45, 0xAE, 0x40, 0x44, 0x13, 0xF7, 0xF1, 0xA6, 0x08, 0x96, 0x04, 0xC0, 0x03, + 0xEA, 0x37, 0xD5, 0xFC, 0xDD, 0x9E, 0x44, 0x10, 0x00, 0x55, 0xDD, 0x45, 0xAE, 0x40, 0x44, 0x13, + 0xF7, 0xF0, 0xA6, 0x08, 0x96, 0x04, 0xC0, 0x03, 0xEA, 0x37, 0xD5, 0xFC, 0xDD, 0x9E, 0x44, 0x43, + 0xF7, 0xFD, 0xA7, 0x20, 0x97, 0x20, 0x5A, 0x08, 0x01, 0x05, 0x58, 0x02, 0x00, 0x08, 0xD5, 0x03, + 0x54, 0x02, 0x00, 0xF7, 0x5A, 0x18, 0x01, 0x04, 0xEB, 0x1C, 0xD5, 0x03, 0x54, 0x00, 0x00, 0xFB, + 0x5A, 0x28, 0x01, 0x05, 0x58, 0x00, 0x00, 0x02, 0xD5, 0x02, 0xEB, 0xBA, 0x5A, 0x38, 0x01, 0x04, + 0xEA, 0x8C, 0xD5, 0x02, 0xEA, 0x8F, 0x44, 0x13, 0xF7, 0xFD, 0xAE, 0x08, 0xDD, 0x9E, 0x84, 0x00, + 0x44, 0x12, 0xD3, 0x38, 0x84, 0x5F, 0x38, 0x20, 0x80, 0x08, 0x8C, 0x01, 0x5A, 0x08, 0x17, 0xFD, + 0xDD, 0x9E, 0x92, 0x00, 0x84, 0x20, 0x44, 0x32, 0xD3, 0x38, 0x44, 0x43, 0x8D, 0x40, 0x38, 0x01, + 0x84, 0x00, 0x96, 0x88, 0x5A, 0x00, 0xFF, 0x30, 0xE6, 0x4D, 0xE8, 0x2D, 0x44, 0xF0, 0x1A, 0x9C, + 0x38, 0x27, 0x88, 0x00, 0x40, 0xF1, 0x3C, 0x00, 0x4A, 0x00, 0x3C, 0x00, 0x0E, 0x16, 0x1A, 0x1E, + 0x22, 0x2A, 0x34, 0x38, 0x48, 0x48, 0x48, 0x48, 0x3C, 0x00, 0x3C, 0x2D, 0xFC, 0x25, 0xAE, 0x10, + 0xD5, 0x1A, 0xEB, 0x43, 0xD5, 0x18, 0xAE, 0x20, 0xD5, 0x16, 0xEB, 0x37, 0xD5, 0x14, 0x40, 0x00, + 0x20, 0x08, 0xEA, 0xB1, 0xD5, 0x10, 0x3C, 0x23, 0xFB, 0x53, 0x88, 0x02, 0xEA, 0xB1, 0xD5, 0x0B, + 0xEB, 0x99, 0xD5, 0x09, 0xEB, 0xD4, 0xD5, 0x07, 0x96, 0x84, 0xEA, 0xEB, 0x3E, 0x27, 0xEE, 0xDC, + 0x3E, 0x07, 0xEF, 0x02, 0x8C, 0x21, 0x5A, 0x18, 0x0D, 0xCC, 0xDD, 0x9E, 0x92, 0x00, 0x44, 0x03, + 0xF7, 0xC0, 0xA6, 0x40, 0x44, 0x02, 0xE2, 0x84, 0xAE, 0x40, 0x44, 0x13, 0xF7, 0xC3, 0xA6, 0x48, + 0xAE, 0x43, 0x44, 0x13, 0xF7, 0xC6, 0xA6, 0x48, 0xAE, 0x46, 0xEB, 0xF5, 0xA6, 0x48, 0xAE, 0x41, + 0xEB, 0x90, 0xA6, 0x48, 0xAE, 0x44, 0xEB, 0xF1, 0xA6, 0x48, 0xAE, 0x47, 0x44, 0x13, 0xF7, 0xC2, + 0xA6, 0x48, 0xAE, 0x42, 0x44, 0x13, 0xF7, 0xC5, 0xA6, 0x48, 0xAE, 0x45, 0x44, 0x13, 0xF7, 0xC8, + 0xA6, 0x48, 0xEB, 0xDF, 0xDD, 0x9E, 0xFC, 0x00, 0xEA, 0x45, 0x44, 0x02, 0xE2, 0x84, 0xA6, 0x80, + 0x44, 0x13, 0xF7, 0xC0, 0xAE, 0x88, 0xA6, 0x83, 0x44, 0x13, 0xF7, 0xC3, 0xAE, 0x88, 0xA6, 0x86, + 0x44, 0x13, 0xF7, 0xC6, 0xAE, 0x88, 0xA6, 0x81, 0xEB, 0xF5, 0xAE, 0x88, 0xA6, 0x84, 0xEB, 0x90, + 0xAE, 0x88, 0xA6, 0x87, 0xEB, 0xF1, 0xAE, 0x88, 0xA6, 0x82, 0x44, 0x13, 0xF7, 0xC2, 0xAE, 0x88, + 0xA6, 0x85, 0x44, 0x13, 0xF7, 0xC5, 0xAE, 0x88, 0x00, 0x10, 0x00, 0x08, 0xEA, 0xD1, 0xAE, 0x40, + 0xFC, 0x80, 0xFC, 0x20, 0x44, 0x00, 0x00, 0xC6, 0xDD, 0x4A, 0xEB, 0xD9, 0xA6, 0x00, 0xDD, 0x4A, + 0x44, 0x03, 0xF7, 0xC1, 0xA6, 0x00, 0xDD, 0x4A, 0xEB, 0xDB, 0xA6, 0x00, 0xDD, 0x4A, 0xEB, 0x7F, + 0xA6, 0x00, 0xDD, 0x4A, 0x44, 0x03, 0xF7, 0xC4, 0xA6, 0x00, 0xDD, 0x4A, 0xEA, 0xFA, 0xA6, 0x00, + 0xDD, 0x4A, 0xEB, 0xCC, 0xA6, 0x00, 0xDD, 0x4A, 0x44, 0x03, 0xF7, 0xC7, 0xA6, 0x00, 0xDD, 0x4A, + 0xEA, 0xD1, 0xA6, 0x00, 0xDD, 0x4A, 0x44, 0x62, 0xFE, 0x50, 0x44, 0x72, 0xFE, 0x56, 0x08, 0x03, + 0x00, 0x01, 0xDD, 0x4A, 0x4C, 0x63, 0xFF, 0xFD, 0xEB, 0x1D, 0xA6, 0x00, 0xDD, 0x4A, 0x44, 0x00, + 0x00, 0xC7, 0xDD, 0x4A, 0xFC, 0xA0, 0xFC, 0x00, 0x44, 0x23, 0xF7, 0xF0, 0xC8, 0x03, 0x80, 0xA2, + 0xD5, 0x03, 0x44, 0x53, 0xF7, 0xF1, 0xA6, 0x68, 0x96, 0x48, 0xDA, 0x17, 0x54, 0x00, 0x80, 0x02, + 0x97, 0x80, 0xC6, 0x09, 0x44, 0x00, 0x00, 0xC3, 0xDD, 0x4A, 0xF8, 0x17, 0x84, 0x00, 0xF9, 0x14, + 0x84, 0x00, 0xFC, 0x80, 0x96, 0x56, 0xC1, 0x17, 0x44, 0x00, 0x00, 0xC4, 0xDD, 0x4A, 0xF8, 0x0D, + 0x80, 0x06, 0xF9, 0x0A, 0x80, 0x06, 0xFC, 0x80, 0x54, 0x60, 0x80, 0xFE, 0xC6, 0x0C, 0x44, 0x00, + 0x00, 0xC5, 0xDD, 0x4A, 0x80, 0x06, 0xDD, 0x4A, 0x49, 0xFF, 0xFF, 0xA5, 0x84, 0x01, 0xF8, 0xFC, + 0x84, 0x00, 0xFC, 0x80, 0x84, 0x01, 0xFC, 0x80, 0xFC, 0x21, 0x80, 0xE0, 0x84, 0x00, 0xEA, 0x57, + 0x84, 0x00, 0x80, 0x20, 0x84, 0x41, 0x80, 0x60, 0x50, 0x6F, 0x80, 0x07, 0xF8, 0x35, 0xC7, 0x03, + 0xEA, 0x34, 0xEA, 0x57, 0x84, 0x21, 0xEB, 0xD9, 0xAE, 0x40, 0x44, 0x2F, 0xFF, 0xE7, 0xEB, 0x7F, + 0xAE, 0x80, 0x96, 0xB0, 0xEB, 0xCC, 0xAE, 0x80, 0x84, 0x40, 0x44, 0x03, 0xF7, 0xC1, 0xAE, 0x80, + 0x84, 0x77, 0x44, 0x03, 0xF7, 0xC4, 0xAE, 0xC0, 0xEA, 0xF5, 0x96, 0x00, 0x44, 0x33, 0xF7, 0xC7, + 0xAE, 0x18, 0xEB, 0xDB, 0xAE, 0x80, 0x92, 0xD0, 0x84, 0x43, 0xEA, 0xFA, 0xAE, 0x80, 0x97, 0xB0, + 0xEA, 0xD1, 0xAF, 0x80, 0x44, 0x03, 0xF7, 0xCC, 0xAE, 0x40, 0xDD, 0x5B, 0xEA, 0x21, 0xA7, 0x80, + 0x97, 0xB0, 0xC6, 0x03, 0xAE, 0x88, 0xD5, 0xFC, 0x84, 0x01, 0x49, 0xFF, 0xFF, 0x96, 0x80, 0x06, + 0x80, 0x26, 0x80, 0x46, 0x80, 0x66, 0x49, 0xFF, 0xFE, 0xAC, 0xFC, 0xA1, 0xFC, 0x63, 0x80, 0xE1, + 0x54, 0x60, 0x00, 0x7F, 0x66, 0x10, 0x00, 0x7F, 0x40, 0x01, 0xA0, 0x09, 0x96, 0x00, 0xF0, 0x81, + 0x40, 0x03, 0xA0, 0x09, 0x96, 0x00, 0xF0, 0x82, 0x40, 0x01, 0x20, 0x09, 0x96, 0x00, 0xF0, 0x83, + 0x40, 0x01, 0xC0, 0x09, 0x96, 0x00, 0xF0, 0x84, 0x40, 0x03, 0xC0, 0x09, 0x96, 0x00, 0x96, 0x48, + 0xF0, 0x85, 0x40, 0x01, 0x40, 0x09, 0xFD, 0x51, 0xB6, 0x3F, 0xEB, 0x2D, 0x5A, 0x68, 0x01, 0x05, + 0x44, 0xC3, 0xF7, 0xCB, 0xD5, 0x03, 0x44, 0xC3, 0xF7, 0xCC, 0x54, 0xD3, 0x80, 0x7F, 0x44, 0xE3, + 0xF7, 0xCE, 0x44, 0x83, 0xF0, 0x4A, 0x45, 0xC0, 0x00, 0x55, 0x5A, 0xD8, 0x7F, 0x05, 0x44, 0x00, + 0x00, 0xC8, 0xDD, 0x4A, 0xEA, 0x45, 0x5A, 0x68, 0x01, 0x06, 0x84, 0x00, 0xF8, 0x3F, 0x84, 0x00, + 0xEB, 0x77, 0x54, 0x05, 0x80, 0xFF, 0x44, 0x13, 0xF7, 0xC0, 0xAE, 0x08, 0x96, 0x38, 0x44, 0x13, + 0xF7, 0xC3, 0xAE, 0x08, 0x54, 0x05, 0x00, 0xFF, 0x44, 0x13, 0xF7, 0xC6, 0xAE, 0x08, 0x00, 0x1F, + 0x80, 0x04, 0x44, 0x03, 0xF7, 0xC1, 0xAE, 0x40, 0x00, 0x1F, 0x80, 0x08, 0x44, 0x03, 0xF7, 0xC4, + 0xAE, 0x40, 0x00, 0x1F, 0x80, 0x0C, 0x44, 0x03, 0xF7, 0xC7, 0xAE, 0x40, 0x00, 0x1F, 0x80, 0x10, + 0xEB, 0xDB, 0xAE, 0x40, 0x00, 0x1F, 0x80, 0x14, 0xEA, 0xFA, 0xAE, 0x40, 0xEA, 0xD1, 0x10, 0x90, + 0x00, 0x00, 0x84, 0x01, 0x10, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0xC0, 0x04, 0x11, 0xC4, + 0x00, 0x00, 0xD5, 0xFB, 0x84, 0x01, 0x49, 0xFF, 0xFF, 0x20, 0x80, 0x20, 0xC8, 0x03, 0xB4, 0x1F, + 0xC8, 0xBD, 0x5A, 0x68, 0x01, 0x0C, 0x80, 0x06, 0xB6, 0x3F, 0x49, 0xFF, 0xFF, 0x47, 0x44, 0x2F, + 0xFF, 0xAA, 0x44, 0x03, 0xF7, 0xCE, 0xAE, 0x80, 0xB4, 0x3F, 0x80, 0x01, 0xFC, 0xE3, 0xFC, 0x40, + 0x44, 0x03, 0xF0, 0x2C, 0xA7, 0x80, 0x84, 0xE1, 0x44, 0x03, 0xF3, 0xEC, 0xAF, 0xC0, 0x84, 0x26, + 0x44, 0x03, 0xF3, 0xED, 0xAE, 0x40, 0x44, 0x03, 0xF3, 0xEE, 0xAF, 0xC0, 0x44, 0x03, 0xF3, 0xEF, + 0xAF, 0xC0, 0x84, 0x40, 0x44, 0x03, 0xF3, 0xF0, 0xAE, 0x80, 0x84, 0x24, 0x44, 0x03, 0xF3, 0xF1, + 0xAE, 0x40, 0x44, 0x13, 0xF3, 0xF2, 0x84, 0x02, 0xAE, 0x08, 0x97, 0xB0, 0xAE, 0x88, 0x44, 0x13, + 0xF3, 0xF3, 0xAF, 0xC8, 0x54, 0x93, 0x00, 0x01, 0x44, 0x13, 0xF3, 0xF4, 0xAF, 0xC8, 0x4E, 0x93, + 0x00, 0x3D, 0x54, 0x13, 0x00, 0x02, 0x40, 0x03, 0x84, 0x1B, 0x3E, 0x07, 0xF3, 0xCB, 0xEA, 0x45, + 0x84, 0x01, 0xF8, 0x02, 0x80, 0x09, 0x49, 0xFF, 0xFD, 0xBB, 0x54, 0x03, 0x00, 0x04, 0x97, 0x80, + 0xEA, 0x3A, 0x40, 0x63, 0x98, 0x1B, 0x3E, 0x67, 0xEB, 0x20, 0x5A, 0x08, 0x02, 0x07, 0x44, 0x13, + 0xF0, 0x2D, 0xA6, 0x08, 0xEA, 0x8C, 0xAE, 0x08, 0x44, 0x01, 0xE4, 0x80, 0x44, 0x12, 0x8E, 0x10, + 0x44, 0x20, 0x19, 0x20, 0x49, 0xFF, 0xFD, 0xB4, 0x44, 0x1F, 0xFF, 0x86, 0xEB, 0x11, 0xAE, 0x40, + 0x84, 0x20, 0xEA, 0x56, 0xAE, 0x40, 0x44, 0x10, 0x00, 0x40, 0x44, 0x03, 0xF6, 0xCA, 0xAE, 0x40, + 0xFA, 0x21, 0x44, 0x03, 0xF6, 0x97, 0xAE, 0x40, 0xFA, 0x2F, 0x44, 0x03, 0xF3, 0x84, 0xAE, 0x40, + 0x84, 0x21, 0x44, 0x03, 0xF3, 0x80, 0xAE, 0x40, 0xEA, 0x3A, 0x5A, 0x00, 0x01, 0x1E, 0x46, 0x05, + 0x55, 0x5A, 0x44, 0x12, 0xB7, 0x90, 0x50, 0x00, 0x0A, 0xAA, 0x3C, 0x0F, 0xFA, 0xC6, 0x80, 0x41, + 0x84, 0x02, 0x84, 0x64, 0xDD, 0x42, 0xDD, 0x45, 0xDD, 0x47, 0xAE, 0x40, 0x46, 0x05, 0xA5, 0xAA, + 0x50, 0x00, 0x05, 0xA5, 0x3C, 0x5D, 0xFA, 0xC7, 0xD8, 0xFE, 0x46, 0x01, 0x23, 0x45, 0x50, 0x00, + 0x06, 0x78, 0x3C, 0x0F, 0xFA, 0xC7, 0xFC, 0xC0, 0xFC, 0x00, 0x2E, 0x67, 0xEE, 0xDC, 0x97, 0xB4, + 0xEB, 0xA6, 0x5A, 0x00, 0xA3, 0x04, 0x84, 0x00, 0xD5, 0x02, 0x84, 0x02, 0xFF, 0x87, 0x49, 0xFF, + 0xFD, 0xB8, 0xDD, 0x4B, 0x97, 0xB2, 0xA6, 0x00, 0x3E, 0x00, 0x06, 0xC0, 0xDD, 0x54, 0xA6, 0x00, + 0x3E, 0x00, 0x06, 0xC2, 0x3C, 0x03, 0xFB, 0x53, 0x3E, 0x00, 0x06, 0xC5, 0x40, 0x10, 0x20, 0x09, + 0xEA, 0x8A, 0x3E, 0x00, 0x06, 0xC6, 0x2E, 0x07, 0xF2, 0xE3, 0x3E, 0x00, 0x06, 0xC1, 0x2E, 0x07, + 0xEE, 0xB4, 0x3E, 0x10, 0x06, 0xC4, 0x3E, 0x00, 0x06, 0xC7, 0x44, 0x12, 0xD3, 0x38, 0xEB, 0x76, + 0x3E, 0x00, 0x06, 0xC3, 0x80, 0x41, 0x84, 0x02, 0x84, 0x6D, 0x3E, 0x60, 0x06, 0xCC, 0xDD, 0x42, + 0x2E, 0x07, 0xEF, 0x2A, 0x5A, 0x08, 0x01, 0x0A, 0x84, 0x02, 0xEA, 0x7F, 0x80, 0x41, 0x80, 0x60, + 0xDD, 0x42, 0x84, 0x00, 0x3E, 0x07, 0xEF, 0x2A, 0xFC, 0x80, 0xFC, 0x00, 0xEA, 0x3A, 0x2E, 0x27, + 0xEE, 0xDE, 0x5A, 0x08, 0x01, 0x22, 0xDD, 0x52, 0x5A, 0x08, 0x02, 0x11, 0x2E, 0x17, 0xEF, 0x23, + 0x5A, 0x18, 0x01, 0x0D, 0x3C, 0x0D, 0xFC, 0x4A, 0xEB, 0xA1, 0xFE, 0x16, 0x84, 0x20, 0xE2, 0x20, + 0x3C, 0x0D, 0xFC, 0x14, 0xFE, 0x16, 0xEB, 0xFB, 0xD5, 0x2C, 0x84, 0x01, 0x40, 0x20, 0x08, 0x0C, + 0x3C, 0x0D, 0xFC, 0x56, 0x84, 0x20, 0xFE, 0x16, 0xE2, 0x20, 0x3C, 0x0D, 0xFC, 0x2A, 0xFE, 0x86, + 0x40, 0x00, 0x88, 0x06, 0xD5, 0x1E, 0xDD, 0x52, 0x5A, 0x08, 0x02, 0x11, 0x2E, 0x17, 0xEF, 0x23, + 0x5A, 0x18, 0x01, 0x0D, 0x3C, 0x0D, 0xFC, 0x4D, 0xEB, 0xA1, 0xFE, 0x16, 0x84, 0x20, 0xE2, 0x20, + 0x3C, 0x0D, 0xFC, 0x1A, 0xFE, 0x16, 0xEB, 0xFB, 0xD5, 0x0C, 0x84, 0x21, 0x3C, 0x0D, 0xFC, 0x49, + 0xEB, 0xA1, 0xFE, 0x16, 0x84, 0x20, 0xE2, 0x20, 0x3C, 0x0D, 0xFC, 0x3C, 0xFE, 0x16, 0xEB, 0xFB, + 0xC8, 0x05, 0xE9, 0x06, 0x44, 0x00, 0x03, 0x20, 0xD5, 0x05, 0x84, 0x00, 0xD5, 0x03, 0x44, 0x00, + 0x17, 0x70, 0xFC, 0x80, 0xFC, 0x62, 0x3A, 0x1F, 0x90, 0x20, 0x80, 0xC0, 0x22, 0x7F, 0x80, 0x00, + 0x81, 0x42, 0x81, 0x23, 0x81, 0x64, 0xDD, 0x43, 0x5A, 0x08, 0x02, 0x2C, 0xEB, 0xDA, 0x00, 0x13, + 0x00, 0x84, 0x8A, 0x01, 0x5A, 0x00, 0x08, 0x2D, 0xEB, 0xDA, 0xE6, 0x08, 0xF8, 0x15, 0xE8, 0x0C, + 0xAD, 0xC0, 0xF8, 0x12, 0x14, 0x90, 0x00, 0x02, 0xF8, 0x0F, 0x14, 0xA0, 0x00, 0x01, 0xF8, 0x0C, + 0x14, 0xB0, 0x00, 0x03, 0xD5, 0x0F, 0x12, 0x70, 0x7F, 0xC0, 0xF8, 0x06, 0x14, 0x90, 0x7F, 0xE2, + 0xF8, 0x03, 0x14, 0xA0, 0x7F, 0xE1, 0xEB, 0xDA, 0x40, 0x03, 0x00, 0x80, 0x83, 0xFF, 0x14, 0xB0, + 0x7F, 0xE3, 0xEB, 0xDA, 0x8C, 0x01, 0x96, 0x00, 0x10, 0x03, 0x00, 0x85, 0x84, 0x01, 0xFC, 0xE2, + 0x80, 0x2A, 0x80, 0x49, 0x80, 0x67, 0x84, 0x02, 0xDD, 0x42, 0x84, 0x01, 0xFC, 0xE2, 0x84, 0x00, + 0xFC, 0xE2, 0x00, 0x10, 0x00, 0x84, 0x8C, 0x21, 0x96, 0x48, 0x10, 0x10, 0x00, 0x84, 0x00, 0x10, + 0x00, 0x84, 0x5A, 0x18, 0x08, 0x0B, 0x84, 0x20, 0x10, 0x10, 0x00, 0x84, 0x00, 0x10, 0x00, 0x85, + 0x8E, 0x28, 0x96, 0x48, 0x10, 0x10, 0x00, 0x85, 0xDD, 0x9E, 0x3C, 0x1D, 0xFC, 0x55, 0x3C, 0x1D, + 0xFC, 0x55, 0x00, 0x20, 0x00, 0x84, 0x50, 0x10, 0x80, 0x91, 0x40, 0x00, 0x08, 0x80, 0x22, 0x20, + 0x00, 0x00, 0x84, 0x05, 0x42, 0x11, 0x00, 0x73, 0x80, 0x01, 0x3C, 0x1C, 0x03, 0xD1, 0xE2, 0x01, + 0xE8, 0x05, 0x3C, 0x0F, 0xFC, 0x55, 0x84, 0x01, 0xDD, 0x9E, 0x84, 0x00, 0xDD, 0x9E, 0x3C, 0x1D, + 0xFC, 0x55, 0x00, 0x50, 0x00, 0x85, 0x00, 0x10, 0x00, 0x84, 0xD1, 0x26, 0x2E, 0x17, 0xEE, 0xD5, + 0x5A, 0x18, 0x01, 0x23, 0x00, 0x30, 0x00, 0x84, 0x3C, 0x2D, 0xFC, 0x71, 0x40, 0x30, 0x0C, 0x80, + 0xA0, 0xDB, 0xEB, 0xA1, 0xFE, 0x9E, 0xC2, 0x16, 0x3C, 0x2D, 0xFC, 0x55, 0x00, 0x30, 0x00, 0x84, + 0x50, 0x21, 0x00, 0x91, 0x40, 0x00, 0x0C, 0x80, 0x22, 0x30, 0x00, 0x00, 0x84, 0x05, 0x42, 0x21, + 0x80, 0x73, 0x80, 0x02, 0x3C, 0x2C, 0x03, 0xD1, 0xE2, 0x02, 0xE8, 0x06, 0x3C, 0x0F, 0xFC, 0x55, + 0xD5, 0x04, 0x80, 0x22, 0xD5, 0x02, 0x84, 0x20, 0x80, 0x01, 0xDD, 0x9E, 0xFC, 0x40, 0x2E, 0x27, + 0xEF, 0x4B, 0x5A, 0x28, 0x01, 0x08, 0x2E, 0x10, 0x11, 0xB0, 0x44, 0x32, 0xDD, 0xA4, 0xF8, 0x06, + 0xD5, 0x0C, 0x2E, 0x10, 0x0F, 0x48, 0x44, 0x32, 0xDB, 0x3C, 0x40, 0x11, 0x84, 0x80, 0x22, 0x90, + 0x80, 0x00, 0xA1, 0xC9, 0xA1, 0x8A, 0x83, 0xFF, 0x66, 0x00, 0x00, 0x7F, 0x96, 0x00, 0x3E, 0x07, + 0xEF, 0x53, 0xC8, 0x08, 0x5A, 0x28, 0x01, 0x05, 0xEB, 0xAB, 0xF8, 0x67, 0xD5, 0x03, 0xEA, 0x62, + 0xF8, 0x64, 0xEA, 0x45, 0x54, 0x14, 0x80, 0xFF, 0xEB, 0xD9, 0xAE, 0x40, 0x96, 0x78, 0xEB, 0x7F, + 0xAE, 0x40, 0x96, 0x70, 0xEB, 0xCC, 0xAE, 0x40, 0x40, 0x04, 0xA0, 0x0A, 0x96, 0x00, 0xEB, 0xF5, + 0xAE, 0x08, 0x40, 0x03, 0xA0, 0x09, 0x96, 0x00, 0xEB, 0x90, 0xAE, 0x08, 0xEA, 0xF5, 0x96, 0x00, + 0xEB, 0xF1, 0xAE, 0x08, 0x40, 0x04, 0xC0, 0x0A, 0x96, 0x00, 0x44, 0x13, 0xF7, 0xC2, 0x92, 0xF0, + 0xAE, 0x08, 0x97, 0xF8, 0xEA, 0xFA, 0x92, 0xD0, 0xAF, 0xC0, 0x97, 0xB0, 0xEA, 0xD1, 0xAF, 0x80, + 0x84, 0x21, 0x44, 0x03, 0xF7, 0xCC, 0xAE, 0x40, 0xFC, 0xC0, 0xFC, 0x00, 0xEB, 0xAB, 0x49, 0xFF, + 0xFF, 0x80, 0x80, 0xC0, 0x5A, 0x08, 0x01, 0x09, 0x3E, 0x07, 0xEF, 0x4B, 0x84, 0x02, 0xF8, 0x11, + 0x3E, 0x67, 0xEF, 0x64, 0xD5, 0x17, 0x2E, 0x50, 0x0F, 0x49, 0x2E, 0x00, 0x0F, 0x48, 0xD0, 0x0F, + 0xEA, 0x62, 0x49, 0xFF, 0xFF, 0x54, 0xC0, 0x0C, 0x84, 0x00, 0x3E, 0x07, 0xEF, 0x4B, 0x84, 0x02, + 0x49, 0xFF, 0xFF, 0x96, 0x84, 0x01, 0x3E, 0x07, 0xEF, 0x64, 0xD5, 0x04, 0x84, 0x00, 0x3E, 0x07, + 0xEF, 0x64, 0xFC, 0x80, 0xFC, 0x00, 0x84, 0x01, 0x49, 0xFF, 0xFC, 0xE7, 0x5A, 0x08, 0x01, 0x10, + 0x2E, 0x07, 0xEF, 0x53, 0x5A, 0x08, 0x01, 0x0C, 0x2E, 0x07, 0xEF, 0x4B, 0x5A, 0x08, 0x01, 0x05, + 0xEB, 0xAB, 0xF8, 0x03, 0xD5, 0x04, 0xEA, 0x62, 0x49, 0xFF, 0xFF, 0x1D, 0x84, 0x00, 0x3E, 0x07, + 0xEE, 0xD5, 0x3E, 0x07, 0xEF, 0x4B, 0xFC, 0x80, 0xFC, 0x40, 0x81, 0x22, 0x80, 0xE0, 0x80, 0xC1, + 0xEA, 0x45, 0x54, 0x14, 0x80, 0xFF, 0xEB, 0xD9, 0xAE, 0x40, 0x96, 0x78, 0xEB, 0x7F, 0xAE, 0x40, + 0x96, 0x70, 0xEB, 0xCC, 0xAE, 0x40, 0x40, 0x04, 0xA0, 0x09, 0x96, 0x00, 0xEB, 0xF5, 0xAE, 0x08, + 0x40, 0x03, 0xA0, 0x09, 0x96, 0x00, 0xEB, 0x90, 0xAE, 0x08, 0xEA, 0xF5, 0x96, 0x00, 0xEB, 0xF1, + 0x40, 0x24, 0xC0, 0x09, 0xAE, 0x08, 0x96, 0x90, 0xEB, 0xDB, 0x92, 0xF0, 0xAE, 0x80, 0x97, 0xF8, + 0xEA, 0xFA, 0x92, 0xD0, 0xAF, 0xC0, 0x97, 0xB0, 0xEA, 0xD1, 0xAF, 0x80, 0x44, 0x13, 0xF7, 0xCC, + 0x84, 0x01, 0xAE, 0x08, 0x3E, 0x07, 0xEE, 0xD2, 0xFC, 0xC0, 0xFC, 0x41, 0xEA, 0x3A, 0x84, 0xC1, + 0x5A, 0x00, 0x01, 0x04, 0x48, 0x00, 0x00, 0x8B, 0x44, 0x13, 0xF7, 0xF1, 0xEA, 0x50, 0xEA, 0x48, + 0xA6, 0x08, 0x96, 0x04, 0xC0, 0x03, 0xAE, 0xD0, 0xD5, 0xFC, 0x3C, 0x6D, 0xFC, 0x1B, 0x44, 0x13, + 0xF1, 0x28, 0x9C, 0xB4, 0x84, 0x63, 0x84, 0x02, 0xDD, 0x42, 0x44, 0x13, 0xF1, 0x18, 0x50, 0x23, + 0x00, 0x08, 0x84, 0x63, 0x84, 0x02, 0xDD, 0x42, 0x44, 0x13, 0xF1, 0x00, 0x50, 0x23, 0x00, 0x18, + 0x84, 0x64, 0x84, 0x02, 0xDD, 0x42, 0x44, 0x13, 0xF1, 0x2C, 0x50, 0x23, 0x00, 0x10, 0x84, 0x63, + 0x84, 0x02, 0xDD, 0x42, 0x44, 0x13, 0xF1, 0x30, 0x50, 0x23, 0x00, 0x14, 0x84, 0x63, 0x84, 0x02, + 0xDD, 0x42, 0x44, 0x13, 0xF1, 0x04, 0x50, 0x23, 0x00, 0x1C, 0x84, 0x64, 0x84, 0x02, 0xDD, 0x42, + 0x84, 0x01, 0x44, 0x13, 0xF3, 0x0E, 0xEB, 0x0C, 0x80, 0x60, 0xDD, 0x42, 0x00, 0x1F, 0x80, 0x07, + 0x44, 0x0F, 0xFF, 0x80, 0xFE, 0x0F, 0xEA, 0x57, 0x44, 0x13, 0xF3, 0x0E, 0xEB, 0x0C, 0x84, 0x61, + 0x84, 0x02, 0xDD, 0x42, 0x44, 0x0F, 0xFF, 0xAE, 0xEA, 0x57, 0xEA, 0x7F, 0xEB, 0x0C, 0x84, 0x61, + 0x84, 0x02, 0xDD, 0x42, 0x84, 0x01, 0xEA, 0x57, 0x44, 0x13, 0xF1, 0x0D, 0x84, 0x02, 0xEB, 0x0C, + 0x84, 0x61, 0xDD, 0x42, 0xDD, 0x45, 0xDD, 0x47, 0xAE, 0x40, 0x46, 0x05, 0x55, 0x5A, 0x50, 0x00, + 0x0A, 0xAA, 0x3C, 0x5D, 0xFA, 0xC6, 0xD8, 0xFE, 0x46, 0x01, 0x23, 0x45, 0x50, 0x00, 0x06, 0x78, + 0x3C, 0x0F, 0xFA, 0xC6, 0xEB, 0x02, 0xEB, 0x27, 0x84, 0x0A, 0xEA, 0x39, 0x84, 0x01, 0xEB, 0x2F, + 0x44, 0x13, 0xF1, 0x33, 0xEB, 0x0C, 0x80, 0x60, 0xDD, 0x42, 0x00, 0x6F, 0x80, 0x07, 0x54, 0x03, + 0x00, 0x04, 0xC0, 0xF3, 0x97, 0x8F, 0xC6, 0x06, 0x44, 0x00, 0x00, 0xC2, 0xDD, 0x4A, 0x84, 0xC1, + 0xD5, 0x0D, 0x46, 0x05, 0xA5, 0xAA, 0x50, 0x00, 0x05, 0xA5, 0x44, 0x12, 0xB7, 0x94, 0x3C, 0x0F, + 0xFA, 0xC7, 0x80, 0x41, 0x84, 0x02, 0x84, 0x64, 0xDD, 0x42, 0x80, 0x06, 0xFC, 0xC1, 0xEA, 0x3A, + 0x5A, 0x00, 0x01, 0x05, 0x44, 0x02, 0x4A, 0x00, 0xDD, 0x9E, 0x44, 0x02, 0x0A, 0x00, 0xDD, 0x9E, + 0xFC, 0x40, 0x5A, 0x00, 0x02, 0x03, 0xF8, 0x17, 0x44, 0x03, 0xF3, 0x1C, 0xA6, 0x00, 0x5A, 0x08, + 0x01, 0x08, 0x44, 0x23, 0xF3, 0x3F, 0xA6, 0x10, 0x58, 0x00, 0x00, 0x80, 0xAE, 0x10, 0x44, 0x03, + 0xF3, 0x69, 0xA6, 0x00, 0x96, 0x04, 0xC0, 0x09, 0xFA, 0x22, 0xEA, 0x56, 0xAE, 0x40, 0x84, 0x20, + 0xEB, 0x11, 0xAE, 0x40, 0x48, 0x00, 0x00, 0xF1, 0x80, 0xC1, 0xEB, 0x5B, 0x2E, 0x07, 0xF3, 0xCA, + 0x5A, 0x10, 0x01, 0x04, 0x48, 0x00, 0x00, 0x86, 0xC8, 0x24, 0xDD, 0x43, 0xC8, 0x05, 0x44, 0x10, + 0x00, 0x5C, 0xEB, 0xE1, 0xAE, 0x40, 0x44, 0x13, 0xF3, 0x74, 0xA6, 0x08, 0x58, 0x00, 0x00, 0x03, + 0xAE, 0x08, 0xC6, 0x14, 0xDD, 0x41, 0xF8, 0x7E, 0x84, 0x01, 0xEB, 0xA8, 0x84, 0x05, 0xDD, 0x4F, + 0x2E, 0x07, 0xF3, 0xC9, 0x84, 0x40, 0x8C, 0x01, 0x3E, 0x07, 0xF3, 0xC9, 0x84, 0x23, 0x84, 0x02, + 0x84, 0x61, 0x80, 0x82, 0x80, 0xA2, 0xDD, 0x56, 0xD5, 0x04, 0x44, 0x00, 0x08, 0x98, 0xEA, 0x39, + 0x84, 0x00, 0xEB, 0xA8, 0xCE, 0x19, 0x44, 0x63, 0xF3, 0x6A, 0xA6, 0x30, 0xEB, 0xBA, 0xEB, 0x1C, + 0xAE, 0x30, 0x44, 0x00, 0x03, 0x84, 0xEA, 0x39, 0xEA, 0x29, 0xFA, 0x00, 0xAE, 0x08, 0x80, 0x41, + 0x84, 0x61, 0x84, 0x02, 0xDD, 0x42, 0xA6, 0x30, 0x44, 0x13, 0xF3, 0x69, 0xEA, 0x8C, 0xAE, 0x30, + 0xEA, 0x50, 0xEA, 0x48, 0xD5, 0x27, 0x84, 0x00, 0x49, 0x00, 0x6E, 0x00, 0xC0, 0x05, 0x84, 0x01, + 0xF8, 0x05, 0xEA, 0x39, 0xD5, 0x0B, 0xEA, 0x9E, 0x84, 0x01, 0x49, 0x00, 0x25, 0xD9, 0x44, 0x11, + 0x86, 0xA0, 0xFE, 0x0C, 0xEB, 0xD2, 0xEA, 0x9F, 0xEA, 0xFE, 0xEA, 0xB3, 0xFA, 0x03, 0x80, 0x26, + 0x80, 0x46, 0xAE, 0x30, 0x84, 0x61, 0x84, 0x02, 0xDD, 0x42, 0x84, 0x01, 0xEA, 0xC4, 0x84, 0x20, + 0xEB, 0xE1, 0xAE, 0x40, 0xDD, 0x5B, 0xEA, 0x21, 0xA6, 0x30, 0x5A, 0x00, 0x14, 0xC6, 0xAE, 0x88, + 0xD5, 0xFC, 0xA6, 0x08, 0x96, 0x04, 0xC8, 0x03, 0xAE, 0xD0, 0xD5, 0xFC, 0x44, 0x22, 0xFE, 0xF0, + 0x44, 0x33, 0xF0, 0x4A, 0xEB, 0x80, 0xA6, 0x10, 0xEA, 0x29, 0x5A, 0x00, 0x11, 0x04, 0xAF, 0x18, + 0xD5, 0xFB, 0xFA, 0x02, 0xAE, 0x08, 0x84, 0x40, 0xEB, 0x11, 0xAE, 0x80, 0x84, 0x02, 0x80, 0x41, + 0x80, 0x60, 0xDD, 0x42, 0x2E, 0x07, 0xF3, 0xC8, 0x8C, 0x01, 0x3E, 0x07, 0xF3, 0xC8, 0xD5, 0x64, + 0xC8, 0x16, 0xC6, 0x15, 0xDD, 0x43, 0xC8, 0x05, 0x44, 0x10, 0x00, 0x5C, 0xEB, 0xE1, 0xAE, 0x40, + 0xDD, 0x41, 0x49, 0x00, 0x25, 0x88, 0x84, 0x01, 0xEB, 0xA8, 0x84, 0x05, 0xDD, 0x4F, 0x84, 0x20, + 0x84, 0x02, 0x80, 0x41, 0x80, 0x61, 0x84, 0x83, 0x80, 0xA1, 0xDD, 0x56, 0x84, 0x00, 0xEB, 0xA8, + 0xC6, 0x21, 0x44, 0x72, 0xFE, 0xF0, 0x44, 0x93, 0xF0, 0x4A, 0x44, 0xA0, 0x00, 0x55, 0xA6, 0x38, + 0xEA, 0xB3, 0x5A, 0x00, 0x13, 0x0C, 0x84, 0x40, 0x84, 0x01, 0x10, 0xA4, 0x80, 0x00, 0x80, 0x20, + 0x80, 0x62, 0x84, 0x83, 0x80, 0xA2, 0xDD, 0x56, 0xD5, 0xF3, 0x84, 0x01, 0xEA, 0xC4, 0x84, 0x20, + 0xEB, 0xE1, 0xAE, 0x40, 0xFA, 0x04, 0xAE, 0x30, 0x80, 0x26, 0x84, 0x02, 0x80, 0x46, 0x84, 0x61, + 0xDD, 0x42, 0xEA, 0x29, 0xEA, 0x50, 0xEA, 0x48, 0xA6, 0x08, 0x5A, 0x00, 0x10, 0x04, 0xAE, 0xD0, + 0xD5, 0xFC, 0x44, 0x13, 0xF3, 0x6A, 0xA6, 0x08, 0xEA, 0x50, 0xEA, 0x8C, 0xAE, 0x08, 0xEA, 0x48, + 0x44, 0x13, 0xF3, 0x69, 0xA6, 0x08, 0x96, 0x04, 0xC8, 0x03, 0xAE, 0xD0, 0xD5, 0xFC, 0xEA, 0xB3, + 0xFA, 0x01, 0xAE, 0x30, 0x80, 0x26, 0x80, 0x46, 0x84, 0x02, 0x84, 0x61, 0xDD, 0x42, 0xEA, 0x21, + 0xDD, 0x5B, 0xA6, 0x30, 0x5A, 0x00, 0x12, 0x04, 0xAE, 0x88, 0xD5, 0xFC, 0x2E, 0x07, 0xF3, 0xC8, + 0x8C, 0x01, 0x3E, 0x07, 0xF3, 0xC8, 0xFC, 0xC0, 0x44, 0x23, 0xF0, 0x2B, 0xA6, 0x50, 0x2E, 0x37, + 0xF3, 0xCB, 0x96, 0x48, 0x5A, 0x38, 0x01, 0x09, 0xC0, 0x04, 0x58, 0x00, 0x80, 0x08, 0xD5, 0x0A, + 0x54, 0x00, 0x80, 0xF7, 0xD5, 0x07, 0xC0, 0x04, 0x58, 0x00, 0x80, 0x10, 0xD5, 0x03, 0x54, 0x00, + 0x80, 0xEF, 0xAE, 0x10, 0xDD, 0x9E, 0x44, 0x03, 0xF0, 0x2A, 0xA6, 0x00, 0xEB, 0x5B, 0x96, 0x00, + 0x5A, 0x18, 0x01, 0x05, 0x42, 0x00, 0x10, 0x0B, 0xDD, 0x9E, 0xEB, 0x8E, 0xDD, 0x9E, 0xC8, 0x05, + 0xFC, 0x00, 0x84, 0x01, 0xEA, 0x65, 0xFC, 0x80, 0xDD, 0x9E, 0xFC, 0x00, 0xEA, 0x43, 0x5A, 0x08, + 0x01, 0x09, 0x44, 0x03, 0xF7, 0xF0, 0xA6, 0x00, 0x56, 0x00, 0x00, 0x01, 0x96, 0x04, 0xFC, 0x80, + 0x84, 0x00, 0xFC, 0x80, 0xFC, 0x40, 0x97, 0x80, 0x84, 0x02, 0xDD, 0x4F, 0x80, 0x06, 0xDD, 0x4F, + 0x44, 0x12, 0xFE, 0xF2, 0x84, 0x01, 0xAE, 0x08, 0x44, 0x02, 0xFE, 0xF3, 0xAF, 0x80, 0x84, 0x02, + 0x80, 0x41, 0x80, 0x60, 0xDD, 0x42, 0xEA, 0xCC, 0xEB, 0x36, 0x44, 0x92, 0xFE, 0xF6, 0x49, 0xFF, + 0xFF, 0xCC, 0x5A, 0x00, 0x01, 0x0B, 0x84, 0x04, 0x44, 0x10, 0x00, 0xF2, 0xDD, 0x44, 0xEB, 0x6F, + 0xAF, 0xF0, 0xEA, 0x74, 0x5A, 0x08, 0xEC, 0xF5, 0x84, 0x03, 0xDD, 0x4F, 0x84, 0x00, 0x44, 0x12, + 0xFE, 0xF2, 0xAE, 0x08, 0x44, 0x12, 0xFE, 0xF3, 0xAE, 0x08, 0xFC, 0xC0, 0xEB, 0x58, 0xC8, 0x04, + 0x84, 0x01, 0x3E, 0x07, 0xEF, 0x5A, 0xDD, 0x9E, 0x2E, 0x17, 0xEF, 0x5E, 0xE6, 0x22, 0xE8, 0x08, + 0x44, 0x22, 0xBD, 0x58, 0x38, 0x01, 0x04, 0x08, 0x8C, 0x21, 0x3E, 0x17, 0xEF, 0x5E, 0xDD, 0x9E, + 0xFC, 0x00, 0xDD, 0x48, 0x5A, 0x00, 0x01, 0x05, 0xDD, 0x48, 0x5A, 0x08, 0x02, 0x4F, 0xEA, 0x3A, + 0x5A, 0x08, 0x01, 0x0E, 0x84, 0x00, 0x3E, 0x07, 0xF2, 0xD8, 0x3E, 0x07, 0xF2, 0xD7, 0xEA, 0x9C, + 0xA6, 0x02, 0x5A, 0x00, 0x01, 0x03, 0xF8, 0x72, 0x48, 0x00, 0x00, 0xDD, 0xDD, 0x41, 0xA6, 0x01, + 0x5A, 0x00, 0x03, 0x03, 0xF8, 0x6B, 0xEA, 0x9C, 0xA6, 0x00, 0x5A, 0x08, 0xAD, 0x2E, 0xEB, 0xE9, + 0x49, 0x00, 0x64, 0xEE, 0xF8, 0x86, 0x44, 0x1F, 0xAA, 0xAA, 0x4C, 0x00, 0x80, 0x1D, 0x2E, 0x17, + 0xEF, 0x7C, 0xE6, 0x22, 0xE8, 0x18, 0x44, 0x22, 0xE2, 0xD8, 0x2E, 0x37, 0xEF, 0x1F, 0x38, 0x01, + 0x07, 0x0A, 0x40, 0x01, 0x04, 0x60, 0x2E, 0x27, 0xEE, 0xCC, 0xAE, 0x84, 0x44, 0x22, 0xDD, 0x98, + 0x38, 0x21, 0x0C, 0x00, 0xAE, 0xC6, 0x8C, 0x21, 0x8C, 0x61, 0xAE, 0x85, 0x3E, 0x37, 0xEF, 0x1F, + 0x3E, 0x17, 0xEF, 0x7C, 0x2E, 0x07, 0xEF, 0x15, 0x5A, 0x08, 0x02, 0x05, 0x84, 0x00, 0x3E, 0x07, + 0xEF, 0x15, 0x84, 0x04, 0xEA, 0x60, 0xEA, 0xDA, 0x5A, 0x00, 0x13, 0x04, 0x48, 0x00, 0x00, 0x96, + 0x84, 0x01, 0x3E, 0x07, 0xEF, 0x37, 0xF8, 0x32, 0xDD, 0x48, 0x5A, 0x00, 0x03, 0x0D, 0xDD, 0x48, + 0x5A, 0x00, 0x04, 0x0A, 0xDD, 0x48, 0x5A, 0x00, 0x07, 0x07, 0xDD, 0x48, 0x5A, 0x00, 0x08, 0x04, + 0x48, 0x00, 0x00, 0x88, 0xEA, 0x3A, 0x5A, 0x08, 0x01, 0x1E, 0xDD, 0x48, 0x5A, 0x00, 0x07, 0x16, + 0xDD, 0x48, 0x5A, 0x00, 0x08, 0x13, 0xEA, 0x9C, 0xA6, 0x02, 0x5A, 0x08, 0x01, 0x0F, 0x2E, 0x17, + 0xEE, 0xDE, 0x84, 0x4C, 0x8E, 0x21, 0x44, 0x02, 0xB5, 0x8C, 0x42, 0x00, 0x88, 0x73, 0xA6, 0x00, + 0x5A, 0x08, 0x01, 0x04, 0x84, 0x06, 0xEA, 0x60, 0xDD, 0x52, 0x96, 0x00, 0x49, 0x00, 0x32, 0x6E, + 0xF8, 0x05, 0xEA, 0x9C, 0xA6, 0x00, 0x5A, 0x00, 0xAD, 0x04, 0x48, 0x00, 0x00, 0x77, 0xEA, 0xDA, + 0x44, 0x62, 0xB5, 0x8C, 0x8E, 0x01, 0x84, 0x2C, 0x80, 0x46, 0x42, 0x20, 0x04, 0x73, 0x00, 0x01, + 0x00, 0x08, 0x96, 0x04, 0xC0, 0x3E, 0x2E, 0x37, 0xEF, 0x31, 0x96, 0xDC, 0xCB, 0x0A, 0x44, 0x13, + 0x22, 0x60, 0x44, 0x20, 0x00, 0xC0, 0x44, 0x03, 0x20, 0xD0, 0xF8, 0x09, 0xF8, 0x0A, 0xD5, 0x0B, + 0x44, 0x13, 0x25, 0x80, 0xEA, 0xC8, 0x84, 0x60, 0x44, 0x03, 0x23, 0xF0, 0x49, 0x00, 0x64, 0x90, + 0x49, 0x00, 0x62, 0xC2, 0x2E, 0x17, 0xEF, 0x15, 0x5A, 0x18, 0x02, 0x05, 0x84, 0x20, 0x3E, 0x17, + 0xEF, 0x15, 0x44, 0x1F, 0xAA, 0xAA, 0x4C, 0x00, 0x80, 0x1D, 0x2E, 0x17, 0xEF, 0x7C, 0xE6, 0x22, + 0xE8, 0x18, 0x44, 0x22, 0xE2, 0xD8, 0x2E, 0x37, 0xEF, 0x1F, 0x38, 0x01, 0x07, 0x0A, 0x40, 0x01, + 0x04, 0x60, 0x2E, 0x27, 0xEE, 0xCC, 0xAE, 0x84, 0x44, 0x22, 0xDD, 0x98, 0x38, 0x21, 0x0C, 0x00, + 0xAE, 0xC6, 0x8C, 0x21, 0x8C, 0x61, 0xAE, 0x85, 0x3E, 0x37, 0xEF, 0x1F, 0x3E, 0x17, 0xEF, 0x7C, + 0xEA, 0xDA, 0x84, 0x2C, 0x8E, 0x01, 0x42, 0x60, 0x04, 0x73, 0x00, 0x03, 0x00, 0x09, 0x5A, 0x00, + 0x01, 0x03, 0xF8, 0x09, 0xF8, 0x20, 0xEA, 0xDA, 0x8E, 0x01, 0x96, 0x00, 0x49, 0xFF, 0xFF, 0x16, + 0x49, 0x00, 0x59, 0x5B, 0x48, 0xFF, 0xFF, 0x69, 0x5A, 0x08, 0x09, 0x18, 0x48, 0xFF, 0xFF, 0x6A, + 0xDD, 0x48, 0x5A, 0x00, 0x05, 0x05, 0xDD, 0x48, 0x5A, 0x08, 0x06, 0x08, 0xEA, 0x3A, 0x5A, 0x08, + 0x01, 0x0D, 0x84, 0x06, 0xEA, 0x60, 0xD5, 0x09, 0xDD, 0x48, 0x5A, 0x08, 0x0A, 0x07, 0xEA, 0x3A, + 0x5A, 0x00, 0x01, 0x04, 0x49, 0xFF, 0xFE, 0xF4, 0x84, 0x20, 0x84, 0x48, 0xEA, 0x9C, 0xEA, 0x2F, + 0xFC, 0x80, 0x2E, 0x17, 0xEF, 0x5E, 0xC1, 0x2F, 0x44, 0x02, 0xBD, 0x58, 0x88, 0x01, 0x00, 0x20, + 0x7F, 0xFF, 0x84, 0x6C, 0x44, 0x02, 0xB5, 0x8C, 0x42, 0x01, 0x0C, 0x73, 0x8E, 0x21, 0xA6, 0xC1, + 0x3E, 0x30, 0x0A, 0x8C, 0xA6, 0xC2, 0x3E, 0x30, 0x0A, 0x8D, 0xA6, 0xC3, 0x3E, 0x30, 0x0A, 0x8E, + 0xA6, 0xC4, 0x3E, 0x30, 0x0A, 0x8F, 0xA6, 0xC5, 0x3E, 0x30, 0x0A, 0x90, 0xA6, 0xC6, 0x00, 0x00, + 0x00, 0x0A, 0x3E, 0x30, 0x0A, 0x91, 0x3E, 0x20, 0x0A, 0x93, 0x44, 0x22, 0xB5, 0x80, 0x40, 0x01, + 0x00, 0x20, 0xA6, 0x01, 0x3E, 0x00, 0x0A, 0x92, 0xEA, 0x59, 0x3E, 0x17, 0xEF, 0x5E, 0x96, 0x00, + 0x3E, 0x07, 0xEE, 0xC5, 0xDD, 0x9E, 0xFC, 0x00, 0xDD, 0x48, 0x2E, 0x17, 0xEE, 0xDE, 0x5A, 0x00, + 0x01, 0x05, 0xDD, 0x48, 0x5A, 0x08, 0x02, 0x2D, 0xEA, 0x3A, 0x5A, 0x00, 0x01, 0x17, 0xEB, 0x3B, + 0xC8, 0x5D, 0x2E, 0x27, 0xEE, 0xB5, 0x5A, 0x28, 0x01, 0x5A, 0x40, 0x01, 0x04, 0x0C, 0x3C, 0x1D, + 0xFC, 0x3D, 0xFE, 0x46, 0xC1, 0x07, 0xEB, 0x13, 0xAE, 0x8A, 0x84, 0x02, 0x80, 0x41, 0x84, 0x68, + 0xDD, 0x42, 0x84, 0x00, 0xEB, 0x8F, 0xD5, 0x4A, 0x2E, 0x07, 0xEE, 0xB5, 0x5A, 0x08, 0x01, 0x47, + 0x40, 0x00, 0x04, 0x0C, 0x3C, 0x1D, 0xFB, 0xF9, 0xFE, 0x0E, 0xC0, 0xF4, 0xEB, 0x13, 0x44, 0x0F, + 0xFF, 0xAD, 0xAE, 0x08, 0x80, 0x41, 0x84, 0x68, 0x84, 0x02, 0xDD, 0x42, 0xD5, 0xEB, 0xDD, 0x48, + 0x5A, 0x00, 0x03, 0x05, 0xDD, 0x48, 0x5A, 0x08, 0x04, 0x27, 0xEA, 0x3A, 0x2E, 0x67, 0xEE, 0xDC, + 0x5A, 0x08, 0x01, 0x14, 0xCE, 0x2B, 0x2E, 0x07, 0xEE, 0xB5, 0x5A, 0x08, 0x01, 0x28, 0xDD, 0x41, + 0xA6, 0x01, 0x5A, 0x00, 0x03, 0x04, 0x5A, 0x08, 0x0D, 0x06, 0x44, 0x1F, 0xFF, 0xAD, 0xEA, 0x9C, + 0xAE, 0x40, 0x84, 0x02, 0xEB, 0x13, 0xD5, 0xCB, 0xCE, 0x19, 0x2E, 0x07, 0xEE, 0xB5, 0x5A, 0x08, + 0x01, 0x16, 0xEB, 0x13, 0xAE, 0x0A, 0x80, 0x41, 0x84, 0x02, 0x84, 0x68, 0xDD, 0x42, 0x3E, 0x67, + 0xEE, 0xB5, 0xD5, 0x0C, 0xDD, 0x48, 0x5A, 0x00, 0x05, 0x05, 0xDD, 0x48, 0x5A, 0x08, 0x06, 0x07, + 0xEA, 0x3A, 0x5A, 0x00, 0x01, 0x04, 0x84, 0x06, 0xEA, 0x60, 0x84, 0x20, 0x84, 0x48, 0xEA, 0x9C, + 0xEA, 0x2F, 0xFC, 0x80, 0x44, 0x03, 0x96, 0x80, 0xA6, 0x00, 0x96, 0x1F, 0x8E, 0x01, 0xE6, 0x01, + 0x3E, 0xF7, 0xEF, 0x59, 0xDD, 0x9E, 0xFC, 0x20, 0x2E, 0x07, 0xEF, 0x59, 0x97, 0x80, 0x5A, 0x68, + 0x01, 0x31, 0x44, 0x13, 0x96, 0x81, 0x44, 0x03, 0x96, 0x80, 0xA6, 0x00, 0xA6, 0x88, 0x44, 0x13, + 0x96, 0x82, 0xA6, 0x48, 0x40, 0x70, 0x10, 0x09, 0x40, 0x10, 0xA0, 0x08, 0x40, 0x10, 0x8A, 0x04, + 0x44, 0x23, 0x96, 0x83, 0xA6, 0x90, 0xFE, 0x57, 0x44, 0x23, 0x96, 0x84, 0xA6, 0xD0, 0x96, 0xD8, + 0x5A, 0x70, 0x01, 0x07, 0x5A, 0x78, 0x02, 0x0B, 0xF8, 0x03, 0x80, 0x06, 0xD5, 0x08, 0x80, 0x07, + 0x44, 0x23, 0x96, 0x90, 0xDD, 0x42, 0x80, 0x07, 0xD5, 0x02, 0x84, 0x03, 0x84, 0x20, 0x44, 0x23, + 0x96, 0x80, 0xAE, 0x50, 0x44, 0x23, 0x96, 0x8F, 0xAE, 0x10, 0x3E, 0x17, 0xEF, 0x59, 0xFC, 0xA0, + 0x84, 0x01, 0xFC, 0xA0, 0x2E, 0x07, 0xEF, 0x6B, 0xC0, 0x05, 0xFC, 0x00, 0x84, 0x03, 0xDD, 0x4F, + 0xFC, 0x80, 0xDD, 0x9E, 0xFC, 0x00, 0xC8, 0x02, 0x84, 0x26, 0x3E, 0x17, 0xEF, 0x3A, 0x49, 0x00, + 0x68, 0xC6, 0xFC, 0x80, 0x2E, 0x37, 0xF3, 0xCB, 0x5A, 0x38, 0x01, 0x04, 0x48, 0x00, 0x01, 0x69, + 0xFC, 0x40, 0x81, 0x20, 0x80, 0xE1, 0x84, 0x04, 0x80, 0x29, 0x81, 0x42, 0x3C, 0x6D, 0xFC, 0x7E, + 0xDD, 0x44, 0x5A, 0x90, 0x05, 0x08, 0x5A, 0x98, 0x06, 0x04, 0x48, 0x00, 0x01, 0x3E, 0x48, 0x00, + 0x01, 0x56, 0x3C, 0x43, 0xF7, 0xCE, 0x97, 0x21, 0x5A, 0x40, 0x09, 0x04, 0x48, 0x00, 0x01, 0x4F, + 0xEB, 0x1D, 0xA6, 0xC0, 0x96, 0xD8, 0x9E, 0x1A, 0xE6, 0x06, 0x4E, 0xF2, 0x01, 0x48, 0xE6, 0xF0, + 0x4E, 0xF2, 0x00, 0xC5, 0x84, 0x02, 0x44, 0x30, 0x01, 0x90, 0x44, 0x23, 0x73, 0xE8, 0x44, 0xF0, + 0x2B, 0x2C, 0x38, 0x77, 0x9D, 0x01, 0x40, 0xF3, 0xBC, 0x00, 0xDD, 0x0F, 0x20, 0x00, 0x20, 0x00, + 0x20, 0x00, 0x20, 0x00, 0xF0, 0x00, 0xF0, 0x00, 0x46, 0x01, 0x46, 0x01, 0x10, 0x01, 0x10, 0x01, + 0xF0, 0x00, 0xF0, 0x00, 0x46, 0x01, 0x46, 0x01, 0x10, 0x01, 0x10, 0x01, 0xEA, 0xB7, 0xDD, 0x42, + 0xEB, 0x2A, 0x44, 0x23, 0x75, 0x78, 0xDD, 0x59, 0x84, 0x02, 0xDD, 0x42, 0xEB, 0x20, 0xEB, 0x23, + 0xDD, 0x59, 0x84, 0x02, 0xDD, 0x42, 0xEA, 0xED, 0x44, 0x23, 0x78, 0x98, 0xDD, 0x59, 0x84, 0x02, + 0xDD, 0x42, 0xEA, 0xCD, 0x44, 0x23, 0x80, 0x68, 0xDD, 0x59, 0x84, 0x02, 0xDD, 0x42, 0xEB, 0x46, + 0x44, 0x23, 0x81, 0xF8, 0xDD, 0x59, 0x84, 0x02, 0xDD, 0x42, 0xEB, 0xCD, 0x44, 0x23, 0x83, 0x88, + 0xDD, 0x59, 0x84, 0x02, 0xDD, 0x42, 0xEB, 0xB1, 0x44, 0x23, 0x85, 0x18, 0xDD, 0x59, 0x84, 0x02, + 0xDD, 0x42, 0x44, 0x12, 0x98, 0x8A, 0x44, 0x23, 0x7A, 0x28, 0xDD, 0x59, 0x84, 0x02, 0xDD, 0x42, + 0x44, 0x12, 0x9A, 0x1A, 0x44, 0x23, 0x7B, 0xB8, 0xDD, 0x59, 0x84, 0x02, 0xDD, 0x42, 0x44, 0x12, + 0x9B, 0xAA, 0x44, 0x23, 0x7D, 0x48, 0xDD, 0x59, 0x84, 0x02, 0xDD, 0x42, 0x84, 0x02, 0x44, 0x12, + 0x9D, 0x3A, 0x44, 0x23, 0x7E, 0xD8, 0xDD, 0x59, 0xDD, 0x42, 0x5A, 0xA0, 0x15, 0x03, 0xF8, 0x1D, + 0x44, 0x12, 0xAB, 0x4A, 0x44, 0x23, 0x86, 0xA8, 0xDD, 0x59, 0x84, 0x02, 0xDD, 0x42, 0x44, 0x12, + 0xAB, 0xAE, 0x44, 0x23, 0x88, 0x38, 0xDD, 0x59, 0x84, 0x02, 0xDD, 0x42, 0x44, 0x12, 0xAC, 0x12, + 0x44, 0x23, 0x89, 0xC8, 0xDD, 0x59, 0x84, 0x02, 0xDD, 0x42, 0x44, 0x12, 0xAC, 0x76, 0x44, 0x23, + 0x8B, 0x58, 0xDD, 0x59, 0x84, 0x02, 0xDD, 0x42, 0x48, 0x00, 0x00, 0x89, 0xEA, 0xB7, 0xDD, 0x42, + 0xEB, 0x2A, 0x44, 0x23, 0x75, 0x78, 0xDD, 0x59, 0x84, 0x02, 0xDD, 0x42, 0xEB, 0x20, 0x84, 0x02, + 0xEB, 0x23, 0xDD, 0x59, 0xDD, 0x42, 0x84, 0x02, 0xEA, 0xED, 0xD5, 0x10, 0xEA, 0xCD, 0xDD, 0x42, + 0xEB, 0x46, 0x44, 0x23, 0x75, 0x78, 0xDD, 0x59, 0x84, 0x02, 0xDD, 0x42, 0xEB, 0xCD, 0x84, 0x02, + 0xEB, 0x23, 0xDD, 0x59, 0xDD, 0x42, 0x84, 0x02, 0xEB, 0xB1, 0x44, 0x23, 0x78, 0x98, 0xDD, 0x59, + 0xDD, 0x42, 0x44, 0x12, 0xAB, 0x4A, 0x44, 0x23, 0x7A, 0x28, 0xDD, 0x59, 0x84, 0x02, 0xDD, 0x42, + 0xD5, 0x5D, 0x44, 0x12, 0x98, 0x8A, 0xDD, 0x42, 0x44, 0x12, 0x9A, 0x1A, 0x44, 0x23, 0x75, 0x78, + 0xDD, 0x59, 0x84, 0x02, 0xDD, 0x42, 0x44, 0x12, 0x9B, 0xAA, 0x84, 0x02, 0xEB, 0x23, 0xDD, 0x59, + 0xDD, 0x42, 0x84, 0x02, 0x44, 0x12, 0x9D, 0x3A, 0xD5, 0xE1, 0x9E, 0x1C, 0x96, 0x00, 0xE6, 0x0F, + 0xE8, 0x45, 0x84, 0x21, 0x40, 0x00, 0x80, 0x0C, 0x54, 0x10, 0x44, 0x44, 0xC9, 0x27, 0x54, 0x00, + 0x11, 0x11, 0xC0, 0x3C, 0x5A, 0x38, 0x04, 0x0A, 0x84, 0x02, 0x44, 0x12, 0xBC, 0x14, 0x80, 0x41, + 0x80, 0x60, 0x3C, 0x4B, 0xF7, 0xCE, 0xDD, 0x42, 0x44, 0x13, 0x21, 0x98, 0x80, 0x41, 0xEA, 0x4F, + 0x84, 0x02, 0xDD, 0x42, 0x44, 0x13, 0x23, 0x28, 0x80, 0x41, 0xEA, 0x4F, 0x84, 0x02, 0xDD, 0x42, + 0x44, 0x13, 0x24, 0xB8, 0x80, 0x41, 0xEA, 0x4F, 0x84, 0x02, 0xDD, 0x42, 0x44, 0x13, 0x26, 0x48, + 0x80, 0x41, 0xEA, 0x4F, 0x84, 0x02, 0xDD, 0x42, 0xD5, 0x19, 0x44, 0x13, 0x27, 0xD8, 0x80, 0x41, + 0xEA, 0x4F, 0x84, 0x02, 0xDD, 0x42, 0x44, 0x13, 0x29, 0x68, 0x80, 0x41, 0xEA, 0x4F, 0x84, 0x02, + 0xDD, 0x42, 0x44, 0x13, 0x2A, 0xF8, 0x80, 0x41, 0xEA, 0x4F, 0x84, 0x02, 0xDD, 0x42, 0x44, 0x13, + 0x2C, 0x88, 0x84, 0x02, 0x80, 0x41, 0xEA, 0x4F, 0xDD, 0x42, 0x44, 0x12, 0xDB, 0xE8, 0x80, 0x41, + 0x44, 0x30, 0x00, 0xA8, 0x84, 0x02, 0xDD, 0x42, 0x44, 0x12, 0xDB, 0xC4, 0x80, 0x41, 0xFA, 0x74, + 0x84, 0x02, 0xDD, 0x42, 0x44, 0x13, 0x97, 0xDC, 0x80, 0x41, 0x84, 0x64, 0x84, 0x02, 0xDD, 0x42, + 0x84, 0x04, 0x44, 0x10, 0x00, 0xCE, 0xDD, 0x44, 0x49, 0x00, 0x03, 0x23, 0x84, 0x04, 0x44, 0x10, + 0x00, 0xCF, 0xDD, 0x44, 0xD5, 0x1B, 0x96, 0x30, 0x66, 0x10, 0x00, 0x08, 0x8E, 0x26, 0xE6, 0x22, + 0xE9, 0x08, 0x50, 0x10, 0x7F, 0xF6, 0xE6, 0x22, 0xE9, 0x04, 0x8E, 0x12, 0xE6, 0x02, 0xE8, 0x0E, + 0x44, 0x12, 0xDB, 0xE8, 0x80, 0x41, 0x44, 0x30, 0x00, 0xA8, 0x84, 0x02, 0xDD, 0x42, 0x44, 0x12, + 0xDB, 0xC4, 0x84, 0x02, 0x80, 0x41, 0xFA, 0x74, 0xDD, 0x42, 0x84, 0x01, 0xFC, 0xC0, 0x84, 0x01, + 0xDD, 0x9E, 0xFC, 0x00, 0x84, 0x85, 0x8E, 0x01, 0x40, 0x50, 0x10, 0x96, 0x84, 0xC6, 0x8C, 0xA1, + 0x38, 0x50, 0x96, 0x02, 0xFF, 0x34, 0x40, 0x42, 0x90, 0x0D, 0x97, 0x2F, 0xAF, 0x10, 0x04, 0x10, + 0x80, 0x11, 0x40, 0x00, 0x80, 0x0D, 0x96, 0x04, 0xAE, 0x18, 0x84, 0x00, 0xFC, 0x80, 0x04, 0x10, + 0x80, 0x12, 0xFA, 0x58, 0xFE, 0x14, 0xEA, 0x64, 0x40, 0x10, 0x04, 0x40, 0xEB, 0x3D, 0x88, 0x20, + 0x04, 0x00, 0x80, 0x08, 0x96, 0x00, 0xDD, 0x9E, 0xFC, 0x61, 0xF0, 0x81, 0x84, 0x00, 0x3E, 0x07, + 0xF2, 0xBD, 0xF1, 0x01, 0x84, 0x09, 0xF8, 0x3B, 0x3E, 0x00, 0x11, 0xBD, 0xEB, 0x87, 0x44, 0x02, + 0xD3, 0x50, 0x49, 0x00, 0x6D, 0x07, 0x3C, 0x8C, 0x01, 0xB6, 0x84, 0xC0, 0x44, 0x73, 0x97, 0x80, + 0x50, 0x94, 0x00, 0x04, 0x44, 0xA2, 0xDE, 0x64, 0x44, 0xB2, 0x00, 0x00, 0x44, 0xC2, 0xDE, 0x2C, + 0x04, 0x04, 0x00, 0x08, 0x96, 0x2F, 0xE0, 0xC0, 0xE8, 0x2E, 0x80, 0x06, 0x80, 0x29, 0x40, 0xD3, + 0x1C, 0x00, 0x49, 0x00, 0x6F, 0x42, 0x10, 0x06, 0x80, 0x00, 0x00, 0x06, 0x80, 0x00, 0xC0, 0x20, + 0x00, 0x06, 0x80, 0x00, 0xE6, 0x09, 0xE8, 0x1C, 0x04, 0x04, 0x00, 0x12, 0x92, 0x10, 0x54, 0x20, + 0x7F, 0xFF, 0x38, 0x05, 0x18, 0x00, 0x94, 0x04, 0x40, 0x00, 0x08, 0x40, 0x38, 0x00, 0x2C, 0x00, + 0x96, 0x26, 0xC0, 0x0E, 0x3C, 0x1C, 0x01, 0xB6, 0x00, 0x06, 0x80, 0x00, 0x49, 0xFF, 0xFF, 0xB1, + 0x2E, 0x17, 0xF2, 0xBD, 0x38, 0x06, 0x18, 0x08, 0x88, 0x01, 0x3E, 0x07, 0xF2, 0xBD, 0x8C, 0xC1, + 0x97, 0xB0, 0xD5, 0xCF, 0xFC, 0xE1, 0x44, 0x23, 0xF7, 0xDA, 0xA6, 0x50, 0x96, 0x48, 0xC0, 0x04, + 0x58, 0x10, 0x80, 0x20, 0xD5, 0x03, 0x54, 0x10, 0x80, 0xDF, 0xAE, 0x50, 0xDD, 0x9E, 0xFC, 0x40, + 0x84, 0x01, 0x49, 0x00, 0x66, 0xD4, 0x84, 0x01, 0x49, 0xFF, 0xFF, 0xEF, 0x2E, 0x17, 0xF2, 0xBD, + 0x46, 0x00, 0x8B, 0x3B, 0x88, 0x01, 0x44, 0x13, 0xF7, 0xF8, 0xB6, 0x01, 0x44, 0x73, 0xF7, 0xCD, + 0x84, 0x01, 0x44, 0x13, 0xF7, 0xFC, 0xAE, 0x08, 0xAE, 0x38, 0x84, 0x08, 0xEB, 0x9C, 0x84, 0x04, + 0xDD, 0x4F, 0x44, 0x60, 0x00, 0xC8, 0x44, 0x93, 0xF0, 0x4A, 0x44, 0xA0, 0x00, 0x55, 0xA6, 0x38, + 0x5A, 0x08, 0x01, 0x09, 0x8E, 0xC1, 0x10, 0xA4, 0x80, 0x00, 0x84, 0x0A, 0x97, 0xB1, 0xEA, 0x39, + 0xCE, 0xF7, 0x84, 0x05, 0xDD, 0x4F, 0x84, 0x00, 0x49, 0xFF, 0xFF, 0xC7, 0xFC, 0xC0, 0xFC, 0x40, + 0x80, 0xE0, 0xDD, 0x43, 0x80, 0x60, 0x5A, 0x08, 0x02, 0x4F, 0xEB, 0x5B, 0x5A, 0x18, 0x01, 0x29, + 0xF8, 0x31, 0x44, 0xA2, 0xFE, 0xFC, 0x44, 0x92, 0xFE, 0xFD, 0x00, 0x55, 0x00, 0x00, 0x44, 0x12, + 0xFE, 0xFC, 0xD7, 0x0F, 0x00, 0x15, 0x00, 0x00, 0x00, 0x64, 0x80, 0x00, 0x84, 0x0A, 0x97, 0xB0, + 0xDD, 0x44, 0x80, 0x26, 0x84, 0x0B, 0xDD, 0x44, 0x84, 0x0A, 0xEA, 0x39, 0xEA, 0x37, 0xD5, 0xEE, + 0xEA, 0x74, 0x5A, 0x08, 0xAA, 0xF1, 0x44, 0x00, 0x00, 0x46, 0xAE, 0x08, 0x84, 0x40, 0x44, 0x02, + 0xFE, 0xFD, 0xAE, 0x80, 0x84, 0x02, 0x80, 0x41, 0x80, 0x60, 0xDD, 0x42, 0xFC, 0xC0, 0x44, 0x62, + 0xFE, 0xFC, 0xAF, 0xF0, 0xEA, 0x8E, 0x44, 0x72, 0xFE, 0xFD, 0xAE, 0x78, 0x80, 0x46, 0x80, 0x26, + 0xDD, 0x42, 0xDD, 0x47, 0xDD, 0x45, 0xAE, 0x40, 0x83, 0xFF, 0xA6, 0x30, 0x96, 0x00, 0x5A, 0x00, + 0x46, 0x0C, 0xA6, 0x70, 0xA6, 0x38, 0xEB, 0x2D, 0x84, 0x0A, 0xDD, 0x44, 0x84, 0x0B, 0x80, 0x29, + 0xDD, 0x44, 0xEA, 0x37, 0xD5, 0xF3, 0x44, 0x12, 0xFE, 0xFC, 0xAE, 0x08, 0x44, 0x02, 0xFE, 0xFD, + 0x84, 0x20, 0xAE, 0x40, 0xFC, 0xC0, 0xFC, 0x00, 0x80, 0xC0, 0xDD, 0x43, 0x5A, 0x08, 0x02, 0x14, + 0x44, 0x23, 0xF4, 0x1C, 0xA6, 0x50, 0xEA, 0x48, 0xDD, 0x45, 0xAE, 0xC0, 0x96, 0x48, 0x3C, 0x3D, + 0xFC, 0x3F, 0xA6, 0x18, 0xC8, 0x06, 0xCE, 0x05, 0xA6, 0x50, 0x96, 0x48, 0xEA, 0x37, 0xD5, 0xFA, + 0x5A, 0x18, 0x02, 0xFC, 0xFC, 0x80, 0xFC, 0x21, 0xF0, 0x81, 0xEA, 0x3A, 0x5A, 0x08, 0x01, 0x1E, + 0xF8, 0x35, 0x44, 0x12, 0xFE, 0xF0, 0xA6, 0x08, 0xEA, 0xB3, 0x5A, 0x08, 0x50, 0xFE, 0xF8, 0x15, + 0x44, 0x00, 0x00, 0x51, 0xF8, 0x25, 0xF8, 0x2A, 0xA6, 0x30, 0x44, 0x72, 0xFE, 0xF0, 0x5A, 0x08, + 0x52, 0xFD, 0xF0, 0x01, 0xF8, 0x19, 0x44, 0x00, 0x00, 0x53, 0xAE, 0x38, 0x80, 0x27, 0x80, 0x47, + 0x84, 0x61, 0x84, 0x02, 0xDD, 0x42, 0xFC, 0xA1, 0x49, 0x00, 0x18, 0x4B, 0xEA, 0xB3, 0xEA, 0xEC, + 0xF8, 0x0F, 0x44, 0x03, 0xF0, 0x4A, 0xDD, 0x47, 0xAE, 0x40, 0x80, 0x06, 0xA6, 0x40, 0xEA, 0xB3, + 0x5A, 0x18, 0x51, 0xFE, 0xF0, 0x01, 0x49, 0x00, 0x7F, 0xAD, 0x44, 0x00, 0x00, 0x52, 0xAE, 0x30, + 0x80, 0x26, 0x84, 0x02, 0x80, 0x46, 0x84, 0x61, 0xDD, 0x42, 0xDD, 0x47, 0xDD, 0x45, 0xAE, 0x40, + 0x83, 0xFF, 0xA6, 0x30, 0x5A, 0x08, 0x53, 0xFF, 0xFC, 0xA1, 0xFC, 0x20, 0xEA, 0x3A, 0xEA, 0xCC, + 0xEB, 0x36, 0x5A, 0x08, 0x01, 0x13, 0xAF, 0xF0, 0xEA, 0x29, 0xA6, 0x08, 0x5A, 0x08, 0x52, 0xFF, + 0x84, 0x01, 0xEB, 0xBF, 0xDD, 0x47, 0xDD, 0x45, 0xAE, 0x40, 0xDD, 0x43, 0xC0, 0xFF, 0x44, 0x10, + 0x00, 0x53, 0xEA, 0x56, 0xAE, 0x40, 0xFC, 0xA0, 0x84, 0x01, 0xEB, 0xBF, 0xAF, 0xF0, 0xDD, 0x43, + 0xC0, 0xFF, 0xEA, 0x29, 0x44, 0x00, 0x00, 0x52, 0xAE, 0x08, 0x80, 0x41, 0x84, 0x61, 0x84, 0x02, + 0xDD, 0x42, 0xFC, 0xA0, 0x44, 0x03, 0xF7, 0xC9, 0xA6, 0x40, 0xC1, 0x03, 0x84, 0x20, 0xAE, 0x40, + 0xDD, 0x9E, 0xEB, 0x5B, 0x5A, 0x18, 0x01, 0x06, 0x44, 0x12, 0xBD, 0x14, 0xF8, 0x04, 0xDD, 0x9E, + 0x44, 0x12, 0xBC, 0x6C, 0x38, 0x00, 0x81, 0x01, 0x50, 0x00, 0x7F, 0x5B, 0xEA, 0xB8, 0x83, 0xFF, + 0xDD, 0x9E, 0xFC, 0x40, 0xDD, 0x47, 0x80, 0xC0, 0xDD, 0x45, 0xAE, 0x40, 0xEA, 0x7B, 0xA6, 0x08, + 0xC8, 0xFF, 0x2E, 0x37, 0xF3, 0xCB, 0x44, 0xA2, 0xBC, 0x6C, 0x44, 0x00, 0x00, 0xA5, 0x94, 0x71, + 0x50, 0x73, 0x7F, 0xA0, 0x44, 0x92, 0xBD, 0x14, 0x5A, 0x38, 0x01, 0x15, 0x88, 0x2A, 0x80, 0x41, + 0x38, 0x05, 0x19, 0x09, 0x84, 0x02, 0xDD, 0x42, 0xEA, 0x45, 0xF8, 0x14, 0x38, 0x04, 0x99, 0x01, + 0x5A, 0x08, 0xA5, 0xFE, 0xF8, 0x1B, 0x44, 0x12, 0xBD, 0x14, 0x38, 0x05, 0x19, 0x09, 0xEB, 0xAF, + 0xFC, 0xC0, 0x88, 0x29, 0x80, 0x41, 0x38, 0x04, 0x99, 0x09, 0x84, 0x61, 0x84, 0x02, 0xDD, 0x42, + 0xEA, 0x45, 0xDD, 0x45, 0xDD, 0x47, 0xAE, 0x40, 0x97, 0xF8, 0x44, 0x03, 0x8D, 0x44, 0xAF, 0xC0, + 0x83, 0xFF, 0x38, 0x05, 0x19, 0x01, 0x5A, 0x08, 0xA5, 0xFE, 0x50, 0x03, 0x7F, 0xB0, 0x96, 0x00, + 0x44, 0x13, 0x8D, 0x44, 0xAE, 0x08, 0x84, 0x00, 0x83, 0xFF, 0x44, 0x12, 0xBC, 0x6C, 0xEB, 0xAF, + 0x38, 0x04, 0x99, 0x09, 0xFC, 0xC0, 0xFC, 0x00, 0x2E, 0x27, 0xF3, 0xE9, 0x10, 0x20, 0x02, 0xC4, + 0x2E, 0x27, 0xF3, 0xE8, 0x10, 0x20, 0x02, 0xC2, 0x2E, 0x27, 0xF3, 0xE7, 0x10, 0x20, 0x02, 0xC3, + 0x2E, 0x27, 0xF3, 0xE6, 0x10, 0x20, 0x02, 0xC1, 0x2E, 0x27, 0xF3, 0xE5, 0x10, 0x20, 0x02, 0xF4, + 0x2E, 0x27, 0xF3, 0xE4, 0x10, 0x20, 0x02, 0xF5, 0x2E, 0x27, 0xF3, 0xE3, 0x10, 0x20, 0x02, 0xF6, + 0x2E, 0x27, 0xF3, 0xE2, 0x10, 0x20, 0x02, 0xF7, 0x2E, 0x27, 0xF3, 0xE1, 0x10, 0x20, 0x00, 0x8D, + 0x2E, 0x27, 0xF3, 0xE0, 0x10, 0x20, 0x00, 0x93, 0x2E, 0x27, 0xF3, 0xDF, 0x10, 0x20, 0x00, 0x82, + 0x00, 0x40, 0x00, 0x09, 0x50, 0x30, 0x02, 0x95, 0x84, 0x40, 0x44, 0x52, 0xC0, 0x48, 0xE2, 0x44, + 0xE8, 0x07, 0x38, 0x62, 0x88, 0x00, 0x18, 0x61, 0x80, 0x01, 0x8C, 0x41, 0xD5, 0xF9, 0x2E, 0x27, + 0xF3, 0xCE, 0x10, 0x20, 0x00, 0x8C, 0x2E, 0x27, 0xF3, 0xCD, 0xAE, 0x88, 0x84, 0x20, 0x10, 0x10, + 0x00, 0x9F, 0xDD, 0x4D, 0xEA, 0x4E, 0xFC, 0x80, 0xFC, 0x20, 0x84, 0x00, 0x44, 0x10, 0x00, 0xC1, + 0xDD, 0x44, 0xEA, 0xB0, 0xC8, 0x03, 0x84, 0x07, 0xEB, 0x08, 0xDD, 0x4D, 0x00, 0x70, 0x00, 0x51, + 0x00, 0x60, 0x00, 0x52, 0x80, 0x27, 0x84, 0x01, 0xDD, 0x44, 0x5A, 0x78, 0x02, 0x12, 0xEA, 0x47, + 0xEA, 0x98, 0xDD, 0x4D, 0xEB, 0x4C, 0x00, 0x00, 0x00, 0x53, 0xC8, 0x03, 0x84, 0x00, 0xD5, 0x3C, + 0x5A, 0x00, 0x01, 0x3B, 0x5A, 0x00, 0x02, 0x39, 0x5A, 0x08, 0x03, 0xFA, 0xD5, 0x35, 0x5A, 0x78, + 0x03, 0x37, 0x84, 0x02, 0xEA, 0x2D, 0xEA, 0x47, 0xEA, 0x98, 0xDD, 0x4D, 0x00, 0x10, 0x00, 0x53, + 0x00, 0x00, 0x00, 0x54, 0x96, 0x8C, 0x42, 0x10, 0x84, 0x0B, 0xC9, 0x14, 0xCA, 0x0A, 0xC8, 0x03, + 0x84, 0x04, 0xD5, 0x22, 0x5A, 0x08, 0x01, 0x04, 0x84, 0x06, 0xD5, 0x1E, 0x84, 0x08, 0xD5, 0x1C, + 0xC8, 0x03, 0x84, 0x05, 0xD5, 0x19, 0x5A, 0x08, 0x01, 0x04, 0x84, 0x07, 0xD5, 0x15, 0x84, 0x09, + 0xD5, 0x13, 0xCA, 0x0A, 0xC8, 0x03, 0x84, 0x0A, 0xD5, 0x0F, 0x5A, 0x08, 0x01, 0x04, 0x84, 0x0C, + 0xD5, 0x0B, 0x84, 0x0E, 0xD5, 0x09, 0xC8, 0x03, 0x84, 0x0B, 0xD5, 0x06, 0x5A, 0x08, 0x01, 0x04, + 0x84, 0x0D, 0xD5, 0x02, 0x84, 0x0F, 0x3C, 0x0F, 0xFC, 0x23, 0xD5, 0x29, 0x5A, 0x78, 0x04, 0x18, + 0x84, 0x00, 0x3E, 0x07, 0xEF, 0x12, 0x3E, 0x07, 0xF2, 0xEA, 0x2E, 0x00, 0x0F, 0x51, 0x3E, 0x00, + 0x0F, 0x50, 0x3C, 0x0C, 0x03, 0xD7, 0x3C, 0x0E, 0x03, 0xD5, 0x3C, 0x0C, 0x03, 0xD8, 0x3C, 0x0E, + 0x03, 0xD6, 0xDD, 0x40, 0xC8, 0x40, 0x84, 0x01, 0xEA, 0x2D, 0xD5, 0x0F, 0x5A, 0x78, 0x05, 0x10, + 0x84, 0x02, 0xEA, 0x2D, 0xEA, 0x47, 0xEA, 0x98, 0x84, 0x00, 0x3E, 0x07, 0xF2, 0xEA, 0x3E, 0x07, + 0xEF, 0x12, 0xDD, 0x40, 0xC8, 0x30, 0x84, 0x01, 0x84, 0x26, 0xD5, 0x2B, 0x5A, 0x60, 0xFF, 0x20, + 0x84, 0x01, 0x3E, 0x07, 0xF2, 0xEA, 0x2E, 0x00, 0x0F, 0x50, 0x3E, 0x00, 0x0F, 0x51, 0x3C, 0x0C, + 0x03, 0xD5, 0x3C, 0x0E, 0x03, 0xD7, 0x3C, 0x0C, 0x03, 0xD6, 0x3C, 0x0E, 0x03, 0xD8, 0x40, 0x03, + 0x10, 0x09, 0x5A, 0x00, 0x0F, 0x04, 0x3C, 0x0E, 0x03, 0xD5, 0x97, 0x9F, 0x5A, 0x60, 0x0F, 0x04, + 0x3C, 0x6E, 0x03, 0xD6, 0x84, 0x1F, 0x3E, 0x00, 0x0F, 0x50, 0xD5, 0x04, 0x84, 0x00, 0x3E, 0x07, + 0xF2, 0xEA, 0x84, 0x01, 0x3E, 0x07, 0xEF, 0x12, 0xDD, 0x40, 0xC8, 0x05, 0x84, 0x01, 0x84, 0x25, + 0x49, 0xFF, 0xFB, 0xB2, 0xFC, 0xA0, 0xFC, 0x21, 0x80, 0xC0, 0x84, 0x00, 0xEA, 0xAB, 0xDD, 0x40, + 0x80, 0xE0, 0xC8, 0x1D, 0x97, 0xB1, 0x9C, 0x31, 0x3C, 0x0B, 0xF7, 0xCD, 0x44, 0x12, 0xBC, 0x14, + 0x84, 0x02, 0x80, 0x41, 0x80, 0x60, 0x3C, 0x6B, 0xF7, 0xCE, 0xDD, 0x42, 0x12, 0x7F, 0x80, 0x03, + 0xEA, 0xA8, 0x5C, 0xF0, 0x00, 0x64, 0xE8, 0x08, 0x02, 0x1F, 0x80, 0x03, 0x8C, 0x21, 0x96, 0x49, + 0x12, 0x1F, 0x80, 0x03, 0xD5, 0xF6, 0x3C, 0x53, 0xF7, 0xCD, 0xDE, 0xF1, 0xFC, 0xA1, 0xFC, 0x00, + 0xDD, 0x40, 0xC0, 0x23, 0x84, 0x00, 0x3E, 0x07, 0xEF, 0x62, 0xEA, 0xB0, 0x5A, 0x00, 0x03, 0x0C, + 0xEA, 0xB0, 0x5A, 0x08, 0x0A, 0xFF, 0xEA, 0xB0, 0x96, 0x01, 0x3C, 0x0B, 0xF7, 0xCD, 0x84, 0x01, + 0x3E, 0x07, 0xEF, 0x62, 0xDD, 0x45, 0xDD, 0x47, 0xAE, 0x40, 0xEB, 0x3B, 0x5A, 0x08, 0x01, 0x05, + 0x2E, 0x07, 0xEF, 0x62, 0xD5, 0xFC, 0x84, 0x00, 0x44, 0x12, 0xBC, 0x14, 0xEB, 0x08, 0x84, 0x02, + 0x80, 0x41, 0x80, 0x60, 0xDD, 0x42, 0xD5, 0x04, 0x84, 0x0A, 0x49, 0xFF, 0xFF, 0xB6, 0xFC, 0x80, + 0xFC, 0x00, 0xDD, 0x40, 0xC8, 0x0A, 0xEA, 0xB0, 0x5A, 0x08, 0x08, 0x04, 0x84, 0x09, 0xD5, 0x04, + 0xEA, 0xB0, 0xC8, 0x03, 0x84, 0x07, 0xEB, 0x08, 0xFC, 0x80, 0x44, 0x02, 0xFE, 0x00, 0x84, 0x20, + 0x3C, 0x0F, 0xFC, 0xFD, 0x10, 0x10, 0x00, 0x50, 0xEA, 0x4E, 0xEB, 0x1A, 0x10, 0x10, 0x00, 0x53, + 0x10, 0x10, 0x00, 0x60, 0x10, 0x10, 0x00, 0x61, 0xDD, 0x9E, 0xFC, 0x00, 0xDD, 0x40, 0xC8, 0x25, + 0xEA, 0x31, 0x00, 0x10, 0x80, 0xF2, 0x5A, 0x18, 0x01, 0x21, 0xDD, 0x5B, 0xEA, 0x21, 0xAE, 0x88, + 0x3C, 0x2D, 0xFC, 0xFD, 0x00, 0x11, 0x00, 0xF2, 0xC9, 0x02, 0xD5, 0x00, 0x44, 0x12, 0xFE, 0xF3, + 0xA6, 0x48, 0x96, 0x48, 0x5A, 0x10, 0x04, 0x0C, 0x5A, 0x10, 0x03, 0x0A, 0x5A, 0x10, 0x06, 0x08, + 0x5A, 0x10, 0x0A, 0x06, 0x5A, 0x10, 0x09, 0x04, 0x5A, 0x18, 0x0B, 0x08, 0x3E, 0x17, 0xF2, 0xC5, + 0x10, 0x01, 0x00, 0xF2, 0x10, 0x01, 0x00, 0xF3, 0x84, 0x01, 0xFC, 0x80, 0x2E, 0x07, 0xF2, 0xD1, + 0xC8, 0x0E, 0xEA, 0x31, 0x3E, 0x07, 0xF2, 0xD3, 0x00, 0x20, 0x80, 0x51, 0x3E, 0x07, 0xF2, 0xD2, + 0xEB, 0xA7, 0x84, 0x01, 0x3E, 0x27, 0xF2, 0xD0, 0x3E, 0x07, 0xF2, 0xD1, 0xDD, 0x9E, 0x84, 0x60, + 0xAE, 0xC0, 0xB4, 0x02, 0x40, 0x30, 0x7C, 0x09, 0xB4, 0x01, 0x42, 0x00, 0x7C, 0x09, 0x40, 0x00, + 0x0F, 0xE4, 0xB6, 0x01, 0xB4, 0x02, 0x42, 0x30, 0x74, 0x0B, 0xB4, 0x01, 0x42, 0x00, 0x74, 0x09, + 0x40, 0x00, 0x0F, 0xA4, 0xB6, 0x01, 0xB4, 0x02, 0xEA, 0xD2, 0x5A, 0x08, 0x01, 0x06, 0xB4, 0x01, + 0x42, 0x00, 0x48, 0x08, 0xB6, 0x01, 0xB4, 0x02, 0xEA, 0xD2, 0xC8, 0x05, 0xB4, 0x01, 0x42, 0x00, + 0x48, 0x09, 0xB6, 0x01, 0xB4, 0x02, 0x42, 0x30, 0x78, 0x0B, 0xB4, 0x01, 0x42, 0x00, 0x78, 0x09, + 0x40, 0x00, 0x0F, 0xC4, 0xB6, 0x01, 0xB4, 0x02, 0x42, 0x30, 0x54, 0x0B, 0xB4, 0x01, 0x42, 0x00, + 0x54, 0x09, 0x40, 0x00, 0x0E, 0xA4, 0xB6, 0x01, 0xB4, 0x02, 0x42, 0x30, 0x5C, 0x0B, 0xB4, 0x01, + 0x42, 0x00, 0x5C, 0x09, 0x40, 0x00, 0x0E, 0xE4, 0xB6, 0x01, 0xB4, 0x02, 0x42, 0x20, 0x58, 0x0B, + 0xB4, 0x01, 0x42, 0x00, 0x58, 0x09, 0x40, 0x00, 0x0A, 0xC4, 0xB6, 0x01, 0xDD, 0x9E, 0xFC, 0x00, + 0x5A, 0x08, 0x06, 0x04, 0x84, 0x01, 0xD5, 0x04, 0x5A, 0x08, 0x07, 0x06, 0x84, 0x00, 0x3E, 0x07, + 0xEE, 0xC3, 0xD5, 0x1C, 0x5A, 0x08, 0x0D, 0x07, 0x84, 0x00, 0x3E, 0x07, 0xEE, 0xC3, 0x84, 0x21, + 0xD5, 0x07, 0x5A, 0x08, 0x0E, 0x0B, 0x84, 0x01, 0x3E, 0x07, 0xEE, 0xC3, 0x84, 0x20, 0x3E, 0x17, + 0xEF, 0x24, 0x3E, 0x07, 0xEF, 0x09, 0xD5, 0x0A, 0x5A, 0x08, 0x10, 0x04, 0x84, 0x01, 0xD5, 0x04, + 0x5A, 0x08, 0x11, 0x05, 0x84, 0x00, 0x3E, 0x07, 0xEE, 0xC0, 0xFC, 0x80, 0x8E, 0x01, 0xE6, 0x08, + 0xE8, 0x34, 0xFC, 0x00, 0x80, 0xC1, 0x44, 0xF0, 0x35, 0x90, 0xEA, 0x90, 0xEA, 0x3C, 0xDD, 0x0F, + 0x08, 0x12, 0x28, 0x30, 0x38, 0x42, 0x4A, 0x50, 0xB4, 0x01, 0x42, 0x00, 0x70, 0x08, 0xB6, 0x01, + 0xD5, 0x08, 0xB4, 0x01, 0x42, 0x00, 0x70, 0x09, 0xB6, 0x01, 0x49, 0x00, 0x11, 0x45, 0xEB, 0x92, + 0x80, 0x06, 0x49, 0x00, 0x54, 0xEF, 0xFC, 0x80, 0xB4, 0x01, 0x42, 0x00, 0x74, 0x08, 0xD5, 0x08, + 0xB4, 0x01, 0x42, 0x00, 0x74, 0x09, 0xD5, 0x04, 0xB4, 0x01, 0x42, 0x00, 0x78, 0x08, 0xB6, 0x06, + 0xFC, 0x80, 0xB4, 0x01, 0x42, 0x00, 0x78, 0x09, 0xD5, 0xFB, 0xB4, 0x01, 0xEB, 0xCF, 0xD5, 0xF8, + 0xB4, 0x01, 0x42, 0x00, 0x54, 0x09, 0xD5, 0xF4, 0x84, 0x02, 0xAE, 0x10, 0xDD, 0x9E, 0x92, 0x00, + 0xFC, 0x00, 0x2E, 0x07, 0xF2, 0xD2, 0xC8, 0x30, 0x2E, 0x07, 0xF2, 0xD0, 0x5A, 0x08, 0x10, 0x05, + 0x3C, 0x0C, 0x03, 0x22, 0xD5, 0x0A, 0x5A, 0x08, 0x11, 0x05, 0x3C, 0x0C, 0x03, 0x1C, 0xD5, 0x05, + 0x5A, 0x08, 0x12, 0x07, 0x3C, 0x0C, 0x03, 0x1E, 0x44, 0x13, 0x20, 0xD0, 0xDD, 0x5D, 0xEA, 0x28, + 0xDD, 0x4D, 0xC9, 0x03, 0xEB, 0x61, 0xD5, 0x03, 0x44, 0x1F, 0xFF, 0xA1, 0xEA, 0x4E, 0xEB, 0xD7, + 0xA6, 0x48, 0x5A, 0x18, 0x03, 0x05, 0x44, 0x1F, 0xFF, 0xB1, 0xD5, 0x03, 0x44, 0x1F, 0xFF, 0xB0, + 0xEB, 0x1A, 0xDD, 0x41, 0xA6, 0x01, 0x5A, 0x08, 0x04, 0x05, 0x84, 0x01, 0x3E, 0x07, 0xEF, 0x33, + 0x84, 0x01, 0x3E, 0x07, 0xF2, 0xD2, 0xDD, 0x4D, 0xEA, 0x52, 0x5A, 0x08, 0xBB, 0x1A, 0x2E, 0x07, + 0xF2, 0xD3, 0xE6, 0x14, 0xE8, 0x06, 0x2E, 0x07, 0xF2, 0xD3, 0xE6, 0x0A, 0xE9, 0x11, 0xD5, 0x0E, + 0xDD, 0x43, 0x5A, 0x08, 0x02, 0xFA, 0xEA, 0x31, 0x84, 0x00, 0xEB, 0xA7, 0x10, 0x00, 0x80, 0x52, + 0x3E, 0x07, 0xF2, 0xD3, 0x3E, 0x07, 0xF2, 0xD2, 0xD5, 0x03, 0xDD, 0x43, 0xC0, 0xF5, 0xFC, 0x80, + 0xFC, 0x40, 0x81, 0x20, 0xDD, 0x41, 0x2E, 0x27, 0xF2, 0xBE, 0xA6, 0x01, 0xE6, 0x41, 0x80, 0xE1, + 0x3E, 0xF7, 0xF2, 0xBE, 0xEA, 0xCC, 0x5A, 0x08, 0x03, 0x4C, 0x84, 0x08, 0x44, 0x10, 0x00, 0xB1, + 0xDD, 0x44, 0xEA, 0x40, 0xAE, 0x30, 0x44, 0xA3, 0x8D, 0x40, 0x84, 0xC9, 0xDD, 0x51, 0xA6, 0x08, + 0xC8, 0x13, 0x3C, 0x2D, 0xFC, 0x03, 0x5A, 0x28, 0x01, 0xFC, 0xEA, 0x67, 0x5A, 0x08, 0x06, 0xF9, + 0x3C, 0x6F, 0xFC, 0x3A, 0x2E, 0x07, 0xF2, 0xBE, 0xC0, 0xF3, 0x3E, 0x27, 0xEF, 0x65, 0xEB, 0x7C, + 0x49, 0x00, 0x16, 0x28, 0xD5, 0xEC, 0x84, 0x08, 0x44, 0x10, 0x00, 0xB2, 0xDD, 0x44, 0xDD, 0x40, + 0xC8, 0x0B, 0x2E, 0x07, 0xF2, 0xBE, 0xC8, 0x13, 0x84, 0x01, 0xEA, 0x2A, 0xDD, 0x54, 0xA6, 0x00, + 0x49, 0x00, 0x16, 0x18, 0xD5, 0x0C, 0xDD, 0x47, 0xDD, 0x45, 0xAE, 0x40, 0x2E, 0x17, 0xEE, 0xBA, + 0xEA, 0x67, 0x5A, 0x00, 0x06, 0xF0, 0x5A, 0x18, 0x01, 0xFD, 0xD5, 0xEC, 0x84, 0x08, 0x44, 0x10, + 0x00, 0xB3, 0xDD, 0x44, 0xDD, 0x52, 0x5A, 0x08, 0x02, 0x07, 0x2E, 0x07, 0xEF, 0x12, 0xC0, 0x03, + 0x49, 0xFF, 0xFE, 0x37, 0x84, 0x08, 0x44, 0x10, 0x00, 0xB4, 0xDD, 0x44, 0xD5, 0x08, 0xEA, 0x40, + 0xAE, 0x30, 0xDD, 0x51, 0xA6, 0x08, 0xC8, 0x03, 0xEA, 0x37, 0xD5, 0xFD, 0x84, 0x08, 0x44, 0x10, + 0x00, 0xB5, 0xDD, 0x44, 0x2E, 0x07, 0xF2, 0xD0, 0x3C, 0x2D, 0xFC, 0xFD, 0x8E, 0x10, 0xE6, 0x03, + 0x10, 0x91, 0x00, 0x53, 0xE8, 0x04, 0x49, 0xFF, 0xFF, 0x45, 0xD5, 0x48, 0xCF, 0x04, 0x44, 0x0F, + 0xFF, 0xA0, 0xD5, 0x03, 0x44, 0x0F, 0xFF, 0xA1, 0x10, 0x01, 0x00, 0x51, 0xDD, 0x54, 0xA6, 0x00, + 0x5A, 0x08, 0x03, 0x05, 0x44, 0x0F, 0xFF, 0xB1, 0xD5, 0x03, 0x44, 0x0F, 0xFF, 0xB0, 0x10, 0x01, + 0x00, 0x52, 0xDD, 0x41, 0xA6, 0x01, 0x5A, 0x08, 0x04, 0x05, 0x84, 0x01, 0x3E, 0x07, 0xEF, 0x33, + 0x44, 0x10, 0x00, 0xB6, 0x84, 0x08, 0xDD, 0x44, 0xEA, 0x21, 0xDD, 0x5B, 0xDD, 0x4D, 0xEA, 0x52, + 0x5A, 0x00, 0xBB, 0x04, 0xAE, 0x88, 0xD5, 0xFB, 0x84, 0x08, 0x44, 0x10, 0x00, 0xB7, 0xDD, 0x44, + 0xDD, 0x40, 0xC0, 0x0C, 0xEB, 0x3B, 0xC8, 0x07, 0xEA, 0x7F, 0x84, 0x02, 0x80, 0x41, 0x80, 0x60, + 0xDD, 0x42, 0xD5, 0x04, 0x84, 0x01, 0x3E, 0x07, 0xEF, 0x2A, 0x84, 0x00, 0xEA, 0x65, 0x44, 0x10, + 0x00, 0xB8, 0x84, 0x08, 0xDD, 0x44, 0x84, 0x00, 0xEA, 0x9A, 0xDD, 0x4D, 0x84, 0x20, 0xEA, 0x4E, + 0xEB, 0x1A, 0x84, 0x08, 0x44, 0x10, 0x00, 0xB9, 0xDD, 0x44, 0x84, 0x00, 0x3E, 0x07, 0xEE, 0xDC, + 0xFC, 0xC0, 0xEA, 0x31, 0x10, 0x00, 0x80, 0x60, 0xDD, 0x9E, 0xDD, 0x4D, 0x00, 0x00, 0x00, 0x60, + 0xDD, 0x9E, 0xEA, 0x31, 0x10, 0x00, 0x80, 0x61, 0x3C, 0x1D, 0xFA, 0xBB, 0x10, 0x00, 0x80, 0x3E, + 0xDD, 0x9E, 0xEA, 0x31, 0x00, 0x00, 0x80, 0x50, 0x50, 0x00, 0x7F, 0xDF, 0xE6, 0x02, 0xE9, 0x04, + 0x84, 0x00, 0x10, 0x00, 0x80, 0x50, 0xDD, 0x9E, 0xFC, 0x00, 0xDD, 0x4D, 0x44, 0x1F, 0xFF, 0xCC, + 0xEA, 0x4E, 0xDD, 0x5B, 0xEA, 0x21, 0xDD, 0x4D, 0xEA, 0x52, 0x5A, 0x00, 0xBB, 0x04, 0xAE, 0x88, + 0xD5, 0xFB, 0xEA, 0x47, 0xEA, 0x39, 0x84, 0x00, 0xEA, 0x71, 0xFC, 0x80, 0x84, 0x21, 0x3E, 0x17, + 0xEE, 0xDD, 0xEA, 0x31, 0x88, 0x01, 0x00, 0x20, 0x00, 0x52, 0x3C, 0x2B, 0xF7, 0xDD, 0x00, 0x10, + 0x00, 0x53, 0x40, 0x11, 0x05, 0x00, 0x3C, 0x1B, 0xF7, 0xDD, 0x00, 0x10, 0x00, 0x54, 0x3C, 0x1B, + 0xF7, 0xD9, 0x00, 0x00, 0x00, 0x55, 0xEB, 0x44, 0x3C, 0x0B, 0xF7, 0xD9, 0xDD, 0x9E, 0xFC, 0x00, + 0x84, 0x00, 0xEB, 0xEC, 0xEB, 0x32, 0x3C, 0x0B, 0xF7, 0xD1, 0xDD, 0x52, 0x5A, 0x08, 0x01, 0x06, + 0xDD, 0x4D, 0x00, 0x10, 0x00, 0x52, 0xD5, 0x06, 0xDD, 0x40, 0xEA, 0x31, 0x00, 0x10, 0x80, 0x52, + 0xC0, 0x03, 0x84, 0x0A, 0xD5, 0x02, 0xFA, 0x18, 0xFE, 0x0C, 0x3C, 0x0B, 0xF7, 0xCC, 0xDD, 0x4D, + 0xEA, 0x52, 0x5A, 0x08, 0xAB, 0x05, 0x84, 0x02, 0x49, 0xFF, 0xFF, 0xCA, 0xFC, 0x80, 0xFC, 0x00, + 0x80, 0xC0, 0x49, 0xFF, 0xFE, 0x2E, 0x84, 0x01, 0x5A, 0x68, 0x03, 0x05, 0x49, 0x00, 0x66, 0x01, + 0x80, 0x06, 0x50, 0x13, 0x7F, 0xF3, 0xE6, 0x22, 0xE9, 0x03, 0x5A, 0x68, 0x02, 0x1B, 0x84, 0x01, + 0xEA, 0xC0, 0xDD, 0x41, 0xA7, 0x81, 0x5A, 0x68, 0x03, 0x04, 0x84, 0x02, 0xD5, 0x12, 0x5A, 0x68, + 0x0A, 0x09, 0x84, 0x29, 0xAE, 0x41, 0x84, 0x20, 0xDD, 0x53, 0xDD, 0x41, 0xAF, 0x81, 0xD5, 0x03, + 0x84, 0x20, 0xDD, 0x53, 0xDD, 0x43, 0x5A, 0x08, 0x02, 0xF2, 0xDD, 0x5A, 0x84, 0x43, 0xAE, 0x89, + 0xFC, 0x80, 0xDD, 0x4D, 0x00, 0x00, 0x00, 0x50, 0x5A, 0x08, 0x13, 0x0E, 0xFC, 0x00, 0xDD, 0x43, + 0x5A, 0x00, 0x02, 0x09, 0xEA, 0x6E, 0xC8, 0x06, 0x84, 0x01, 0xEB, 0x6D, 0x44, 0x00, 0x00, 0x35, + 0xDD, 0x4A, 0xFC, 0x80, 0xDD, 0x9E, 0x40, 0x00, 0x04, 0x0E, 0x96, 0x04, 0xDD, 0x9E, 0xFC, 0x02, + 0xDD, 0x40, 0xC0, 0x1C, 0xDD, 0x4D, 0xEA, 0x8E, 0xEA, 0x4E, 0xDD, 0x4D, 0x00, 0x10, 0x00, 0x51, + 0x5A, 0x18, 0xAA, 0x0A, 0xEA, 0x47, 0xEA, 0x39, 0x84, 0x07, 0x44, 0x10, 0x00, 0x31, 0xDD, 0x44, + 0xEB, 0x6F, 0xD5, 0xF4, 0x50, 0x00, 0x00, 0x51, 0x84, 0x41, 0xF0, 0x82, 0xF0, 0x81, 0x12, 0x2F, + 0x80, 0x00, 0xEA, 0xC7, 0xEA, 0x62, 0xEA, 0x82, 0xD5, 0x0C, 0xDD, 0x4D, 0xEA, 0x52, 0xC8, 0x09, + 0xEA, 0x47, 0xEA, 0x39, 0x84, 0x07, 0x44, 0x10, 0x00, 0x31, 0xDD, 0x44, 0xEB, 0x6F, 0xD5, 0xF6, + 0x84, 0x07, 0xEA, 0xBE, 0xDD, 0x44, 0xDD, 0x4D, 0xEA, 0x52, 0x5A, 0x00, 0xDD, 0x04, 0x84, 0x01, + 0xD5, 0x02, 0x84, 0x03, 0xFC, 0x82, 0x5A, 0x08, 0x03, 0x1F, 0x00, 0x00, 0x80, 0x8A, 0x3E, 0x07, + 0xF3, 0xF1, 0x00, 0x00, 0x80, 0x89, 0x3E, 0x07, 0xF3, 0xF0, 0x00, 0x00, 0x80, 0x84, 0x3E, 0x07, + 0xF3, 0xEF, 0x00, 0x00, 0x80, 0x82, 0x3E, 0x07, 0xF3, 0xEE, 0x84, 0x41, 0x84, 0x00, 0x10, 0x00, + 0x80, 0x8A, 0x10, 0x00, 0x80, 0x89, 0x10, 0x00, 0x80, 0x84, 0x10, 0x00, 0x80, 0x82, 0x10, 0x20, + 0x80, 0x9E, 0xD5, 0x16, 0x5A, 0x08, 0x04, 0x17, 0x2E, 0x07, 0xF3, 0xF1, 0x10, 0x00, 0x80, 0x8A, + 0x2E, 0x07, 0xF3, 0xF0, 0x10, 0x00, 0x80, 0x89, 0x2E, 0x07, 0xF3, 0xEF, 0x10, 0x00, 0x80, 0x84, + 0x2E, 0x07, 0xF3, 0xEE, 0x10, 0x00, 0x80, 0x82, 0x84, 0x00, 0x10, 0x00, 0x80, 0x9E, 0xEA, 0x31, + 0xEB, 0xA7, 0xDD, 0x9E, 0xFC, 0x20, 0x80, 0x61, 0x5A, 0x08, 0x01, 0x6F, 0x00, 0x00, 0x82, 0xC4, + 0x3E, 0x07, 0xF3, 0xE9, 0x00, 0x00, 0x82, 0xC2, 0x3E, 0x07, 0xF3, 0xE8, 0x00, 0x00, 0x82, 0xC3, + 0x3E, 0x07, 0xF3, 0xE7, 0x00, 0x00, 0x82, 0xC1, 0x3E, 0x07, 0xF3, 0xE6, 0x00, 0x00, 0x82, 0xF4, + 0x3E, 0x07, 0xF3, 0xE5, 0x00, 0x00, 0x82, 0xF5, 0x3E, 0x07, 0xF3, 0xE4, 0x00, 0x00, 0x82, 0xF6, + 0x3E, 0x07, 0xF3, 0xE3, 0x00, 0x00, 0x82, 0xF7, 0x3E, 0x07, 0xF3, 0xE2, 0x00, 0x00, 0x80, 0x8D, + 0x3E, 0x07, 0xF3, 0xE1, 0x00, 0x00, 0x80, 0x93, 0x3E, 0x07, 0xF3, 0xE0, 0x50, 0x40, 0x82, 0x95, + 0x00, 0x00, 0x80, 0x82, 0x3E, 0x07, 0xF3, 0xDF, 0x00, 0x50, 0x80, 0x09, 0x84, 0x00, 0x80, 0x24, + 0x44, 0x62, 0xC0, 0x48, 0xE2, 0x05, 0xE8, 0x07, 0x08, 0x70, 0x80, 0x01, 0x38, 0x73, 0x00, 0x08, + 0x8C, 0x01, 0xD5, 0xF9, 0x00, 0x01, 0x80, 0x8C, 0x3E, 0x07, 0xF3, 0xCE, 0xA6, 0x10, 0x84, 0x21, + 0x3E, 0x07, 0xF3, 0xCD, 0x84, 0x00, 0x10, 0x11, 0x82, 0xC4, 0x10, 0x11, 0x82, 0xC2, 0x10, 0x11, + 0x82, 0xC3, 0x10, 0x01, 0x82, 0xC1, 0x10, 0x01, 0x82, 0xF4, 0x10, 0x01, 0x82, 0xF5, 0x10, 0x01, + 0x82, 0xF6, 0x10, 0x11, 0x82, 0xF7, 0x10, 0x01, 0x80, 0x8D, 0x10, 0x01, 0x80, 0x93, 0x10, 0x01, + 0x80, 0x82, 0x84, 0x2A, 0x84, 0x00, 0xE2, 0x05, 0xE8, 0x05, 0x18, 0x12, 0x00, 0x01, 0x8C, 0x01, + 0xD5, 0xFB, 0x84, 0x21, 0x10, 0x11, 0x80, 0x9F, 0xEA, 0x31, 0x84, 0x00, 0x10, 0x01, 0x80, 0x8C, + 0xAE, 0x10, 0xEB, 0xA7, 0xFC, 0xA0, 0x5A, 0x08, 0x02, 0x06, 0x80, 0x22, 0x80, 0x03, 0x49, 0xFF, + 0xFB, 0x2C, 0xFC, 0xA0, 0xFC, 0x01, 0x84, 0x0A, 0xEA, 0x57, 0x5A, 0x10, 0x01, 0x06, 0x5A, 0x10, + 0x02, 0x09, 0x48, 0x00, 0x00, 0x9B, 0xDD, 0x4D, 0x84, 0x20, 0xEA, 0x4E, 0x48, 0x00, 0x00, 0x9A, + 0x3C, 0x6D, 0xFC, 0xFD, 0x00, 0x03, 0x00, 0x52, 0x8E, 0x01, 0xE6, 0x09, 0x4E, 0xF2, 0x00, 0x8E, + 0x44, 0xF0, 0x3B, 0x4C, 0xEA, 0xA1, 0x40, 0xF0, 0x3C, 0x00, 0xDD, 0x0F, 0x12, 0x00, 0x20, 0x00, + 0x2C, 0x00, 0x66, 0x00, 0x0C, 0x01, 0x76, 0x00, 0xAE, 0x00, 0xCA, 0x00, 0xFC, 0x00, 0x84, 0x01, + 0xEA, 0xF8, 0x44, 0x22, 0xB5, 0x40, 0x49, 0xFF, 0xFF, 0x5F, 0xD5, 0x28, 0xEB, 0x3C, 0x44, 0x12, + 0xB5, 0x40, 0x49, 0xFF, 0xFA, 0xFA, 0xD5, 0x22, 0xEB, 0xDC, 0x3E, 0x07, 0xF3, 0xF1, 0x2E, 0x07, + 0x34, 0x11, 0x3E, 0x07, 0xF3, 0xF0, 0xEA, 0x2E, 0x3E, 0x07, 0xF3, 0xEF, 0x2E, 0x07, 0x34, 0x0A, + 0x3E, 0x07, 0xF3, 0xEE, 0x84, 0x21, 0x84, 0x00, 0x3E, 0x07, 0x34, 0x12, 0x3E, 0x07, 0x34, 0x11, + 0x3E, 0x07, 0x34, 0x0C, 0x3E, 0x07, 0x34, 0x0A, 0x3E, 0x17, 0x34, 0x26, 0x10, 0x03, 0x00, 0x51, + 0xD5, 0x06, 0x84, 0x04, 0xEA, 0xF8, 0x49, 0xFF, 0xFF, 0x00, 0x84, 0x00, 0x10, 0x03, 0x00, 0x52, + 0xD5, 0x50, 0x84, 0x00, 0xEB, 0xEE, 0x3E, 0x07, 0xEF, 0x09, 0x84, 0x00, 0x80, 0x40, 0xDD, 0x5A, + 0xEA, 0x5E, 0xEB, 0x3E, 0x84, 0xC0, 0x3C, 0x07, 0xF7, 0xE7, 0x3C, 0x6F, 0xFC, 0xD3, 0xF8, 0x19, + 0xDD, 0x54, 0xA6, 0x00, 0xEA, 0xF8, 0x44, 0x22, 0xBB, 0x81, 0xEB, 0x31, 0x3C, 0x4D, 0xFC, 0xFD, + 0xF8, 0x29, 0xDD, 0x4D, 0x10, 0x60, 0x00, 0x52, 0xD5, 0x34, 0x84, 0x01, 0xEB, 0xEE, 0x84, 0x00, + 0x80, 0x40, 0xDD, 0x5A, 0xEA, 0x5E, 0xEB, 0x3E, 0x84, 0x00, 0xEA, 0x49, 0x3C, 0x07, 0x9A, 0x39, + 0x49, 0x00, 0x6E, 0xCE, 0xD5, 0x0F, 0x84, 0x03, 0xEB, 0xEE, 0x00, 0x03, 0x00, 0x53, 0x44, 0x13, + 0x8D, 0x41, 0x8E, 0x01, 0xAE, 0x08, 0xDD, 0x4D, 0xEA, 0xF8, 0x00, 0x00, 0x00, 0x53, 0x49, 0x00, + 0x6E, 0x05, 0xDD, 0x54, 0xA6, 0x00, 0xEA, 0xF8, 0x44, 0x22, 0xBB, 0x81, 0xEB, 0x31, 0x3C, 0x4D, + 0xFC, 0xFD, 0x49, 0x00, 0x6E, 0x72, 0xD5, 0x0D, 0x44, 0x02, 0x00, 0xEA, 0x80, 0x26, 0x49, 0x00, + 0x6B, 0x50, 0x84, 0x01, 0xEA, 0x57, 0xD5, 0x05, 0x84, 0x01, 0xEA, 0x57, 0x84, 0x02, 0xAE, 0x10, + 0x00, 0x0F, 0x80, 0x07, 0x5A, 0x08, 0x0A, 0x0A, 0x49, 0xFF, 0xFE, 0x73, 0xDD, 0x51, 0xEA, 0x57, + 0x84, 0x01, 0xAE, 0x08, 0xDD, 0x50, 0xAE, 0x08, 0x00, 0x0F, 0x80, 0x07, 0xFC, 0x81, 0x5A, 0x00, + 0x01, 0x08, 0x5A, 0x08, 0x03, 0x0B, 0xB4, 0x01, 0x42, 0x00, 0x48, 0x08, 0xD5, 0x04, 0xB4, 0x01, + 0x42, 0x00, 0x48, 0x09, 0xB6, 0x01, 0xDD, 0x9E, 0x84, 0x02, 0xAE, 0x10, 0xDD, 0x9E, 0xFC, 0x00, + 0xDD, 0x4D, 0xEA, 0x52, 0x5A, 0x08, 0x04, 0x0C, 0xDD, 0x43, 0xC8, 0x09, 0xDD, 0x40, 0xC0, 0x04, + 0x84, 0x01, 0x3E, 0x07, 0xF3, 0xCC, 0xDD, 0x4D, 0x84, 0x20, 0xEA, 0x4E, 0xFC, 0x80, 0x92, 0x00, + 0xFC, 0x40, 0x9F, 0x01, 0xE6, 0x8F, 0x4E, 0xF2, 0x00, 0x97, 0x80, 0xC2, 0x80, 0x01, 0x44, 0xF0, + 0x3C, 0xDC, 0x38, 0x47, 0x91, 0x01, 0x40, 0xF2, 0x3C, 0x00, 0xDD, 0x0F, 0x22, 0x00, 0x2C, 0x00, + 0x38, 0x00, 0x96, 0x00, 0xBC, 0x00, 0xC2, 0x00, 0xD4, 0x00, 0xF2, 0x00, 0xFE, 0x00, 0x1E, 0x01, + 0x1E, 0x00, 0x0C, 0x01, 0x18, 0x01, 0x18, 0x01, 0x12, 0x01, 0xFA, 0x01, 0xF8, 0x0A, 0x84, 0x00, + 0x3E, 0x07, 0xF2, 0xD1, 0x84, 0x06, 0xF8, 0x05, 0x84, 0x00, 0x3E, 0x07, 0xF2, 0xD1, 0x84, 0x07, + 0x48, 0x00, 0x00, 0x76, 0xEB, 0x02, 0xEB, 0x27, 0xF8, 0x25, 0x80, 0xC0, 0x5A, 0x00, 0x02, 0x04, + 0xEB, 0x2F, 0xD5, 0xFB, 0x84, 0x01, 0xF8, 0x23, 0x49, 0x00, 0x09, 0x52, 0x3C, 0x0E, 0x04, 0x75, + 0x49, 0x00, 0x09, 0x57, 0x3C, 0x0E, 0x04, 0x76, 0x49, 0x00, 0x09, 0x64, 0x3E, 0x00, 0x11, 0xDD, + 0x49, 0x00, 0x09, 0x6A, 0x3E, 0x00, 0x11, 0xDC, 0x49, 0x00, 0x09, 0x61, 0x3E, 0x00, 0x11, 0xDE, + 0x84, 0x21, 0x44, 0x02, 0xDE, 0x4C, 0x49, 0x00, 0x5C, 0xA8, 0x80, 0x06, 0xF8, 0x08, 0xEA, 0xCC, + 0xEB, 0x36, 0x49, 0x00, 0x09, 0x5D, 0xC0, 0x03, 0xAF, 0xF0, 0xD5, 0xFC, 0x49, 0x00, 0x09, 0x6B, + 0xD5, 0x12, 0x84, 0x2E, 0xAE, 0x41, 0x84, 0x26, 0xAE, 0x40, 0xEA, 0x31, 0x84, 0x40, 0x10, 0x20, + 0x80, 0x50, 0x84, 0x21, 0xDD, 0x53, 0x84, 0x20, 0x84, 0x02, 0x80, 0x41, 0x84, 0x61, 0x80, 0x81, + 0x80, 0xA1, 0xDD, 0x56, 0x84, 0x01, 0xD5, 0x33, 0x84, 0x01, 0xAE, 0x10, 0xD5, 0x24, 0x84, 0x00, + 0x44, 0x10, 0x00, 0x66, 0xDD, 0x44, 0x84, 0x01, 0xAE, 0x30, 0xDD, 0x43, 0x84, 0x0E, 0xD5, 0x27, + 0xDD, 0x4D, 0xEB, 0x61, 0xEA, 0x4E, 0xFA, 0x41, 0x84, 0x20, 0xEB, 0x1A, 0x10, 0x20, 0x00, 0x53, + 0x10, 0x10, 0x00, 0x54, 0x10, 0x10, 0x00, 0x55, 0x84, 0x01, 0xAE, 0x18, 0xD5, 0xE4, 0x84, 0x01, + 0xAE, 0x10, 0x84, 0x01, 0xF8, 0x06, 0x84, 0x02, 0xD5, 0x12, 0x84, 0x01, 0xAE, 0x10, 0x84, 0x00, + 0x49, 0x00, 0x63, 0x91, 0x84, 0x0D, 0xD5, 0x0B, 0x84, 0x00, 0xEB, 0x8C, 0xD5, 0xD4, 0x49, 0xFF, + 0xFF, 0x58, 0xD5, 0xD1, 0x84, 0x02, 0xAE, 0x18, 0xD5, 0xCE, 0xFA, 0x00, 0xFC, 0xC0, 0x92, 0x00, + 0x8E, 0x07, 0xE6, 0x08, 0xE8, 0x1B, 0x44, 0xF0, 0x3E, 0x10, 0xEA, 0x90, 0xEA, 0x3C, 0xDD, 0x0F, + 0x08, 0x10, 0x2A, 0x2A, 0x2A, 0x2A, 0x18, 0x20, 0xB4, 0x02, 0x42, 0x00, 0x5C, 0x08, 0xD5, 0x0C, + 0xB4, 0x02, 0x42, 0x00, 0x5C, 0x09, 0xD5, 0x08, 0xB4, 0x02, 0x42, 0x00, 0x58, 0x08, 0xD5, 0x04, + 0xB4, 0x02, 0x42, 0x00, 0x58, 0x09, 0xB6, 0x02, 0xDD, 0x9E, 0x84, 0x02, 0xAE, 0x18, 0xDD, 0x9E, + 0xFC, 0x62, 0xF2, 0x81, 0xEB, 0x1D, 0xA6, 0x00, 0xA6, 0x09, 0x81, 0x41, 0x81, 0x63, 0x81, 0x84, + 0x5A, 0x08, 0x04, 0x05, 0x84, 0x00, 0x3E, 0x07, 0xEF, 0x33, 0xEA, 0x6E, 0xC8, 0x23, 0xDD, 0x40, + 0xC0, 0x07, 0xEA, 0x95, 0x5A, 0x08, 0xAA, 0x05, 0x2E, 0x07, 0xF1, 0x40, 0xD5, 0x04, 0xDD, 0x4D, + 0x00, 0x00, 0x00, 0x50, 0xC0, 0x03, 0x5A, 0x08, 0xFB, 0x16, 0xEB, 0x9A, 0xC8, 0x03, 0xEB, 0x42, + 0xC0, 0x06, 0x84, 0x00, 0xEB, 0x2B, 0xEB, 0x60, 0x84, 0x00, 0xEB, 0x8C, 0xF0, 0x01, 0xEA, 0xE2, + 0x49, 0x00, 0x11, 0x75, 0xEA, 0x40, 0xEB, 0x1E, 0x84, 0x00, 0xEB, 0x40, 0x84, 0x01, 0x48, 0x00, + 0x02, 0x98, 0xF0, 0x01, 0xEA, 0xE2, 0x49, 0x00, 0x11, 0x3E, 0x84, 0x00, 0xEB, 0xC8, 0xDD, 0x40, + 0xC0, 0x0C, 0xEA, 0x95, 0x5A, 0x08, 0xAA, 0x0A, 0x2E, 0x67, 0xF1, 0x40, 0x2E, 0x87, 0xF1, 0x41, + 0x40, 0x93, 0x10, 0x09, 0x97, 0x9F, 0xD5, 0x09, 0xDD, 0x4D, 0x00, 0x60, 0x00, 0x50, 0x00, 0x80, + 0x00, 0x51, 0x40, 0x93, 0x10, 0x09, 0x97, 0x9F, 0x84, 0x01, 0xEA, 0x53, 0x84, 0x00, 0xEB, 0xAC, + 0x00, 0x15, 0x00, 0x01, 0x5A, 0x18, 0x04, 0x1B, 0x2E, 0x17, 0xF2, 0xC4, 0xC1, 0x04, 0x3E, 0x07, + 0xF2, 0xC4, 0xD5, 0x50, 0x2E, 0x07, 0xEE, 0xD1, 0x5A, 0x08, 0x01, 0x03, 0xEB, 0xFA, 0x84, 0x20, + 0x80, 0x0A, 0xDD, 0x53, 0x84, 0x01, 0xEA, 0x30, 0xDD, 0x47, 0xDD, 0x45, 0xAE, 0x40, 0xEA, 0x43, + 0xC0, 0xFF, 0x84, 0x01, 0x3E, 0x07, 0xF2, 0xF2, 0xD5, 0x3D, 0xEB, 0x1D, 0xA7, 0xC0, 0xDD, 0x47, + 0xDD, 0x45, 0xAE, 0x40, 0x97, 0xF8, 0xDD, 0x40, 0xC0, 0x13, 0xDD, 0x43, 0x5A, 0x00, 0x02, 0x04, + 0xDD, 0x51, 0xD5, 0x0A, 0x8E, 0xE2, 0xE6, 0xE9, 0xE9, 0xFC, 0x44, 0x00, 0x00, 0x8A, 0xDD, 0x4A, + 0x84, 0x01, 0xEA, 0x71, 0xD5, 0x10, 0xA6, 0x08, 0xC8, 0x11, 0xEA, 0x37, 0xD5, 0xFD, 0xDD, 0x43, + 0x5A, 0x08, 0x02, 0x0D, 0x8E, 0xE2, 0xE6, 0xE9, 0xE9, 0x09, 0x44, 0x00, 0x00, 0x8B, 0xDD, 0x4A, + 0x84, 0x01, 0xEB, 0x55, 0xDD, 0x55, 0x48, 0x00, 0x02, 0x34, 0xDD, 0x40, 0xC0, 0x09, 0xEA, 0x95, + 0x5A, 0x08, 0x55, 0x07, 0xEA, 0x7F, 0x84, 0x02, 0x80, 0x41, 0x84, 0x66, 0xDD, 0x42, 0xDD, 0x58, + 0xA6, 0x00, 0x5A, 0x00, 0x02, 0x08, 0xDD, 0x4B, 0xA6, 0x40, 0x5A, 0x18, 0x02, 0x04, 0x84, 0x20, + 0xAE, 0x40, 0x2E, 0x07, 0xEF, 0x6D, 0x8C, 0x01, 0x3E, 0x07, 0xEF, 0x6D, 0x40, 0x03, 0x24, 0x84, + 0x8F, 0x21, 0xE7, 0x2C, 0x3E, 0x07, 0xEF, 0x6C, 0x4E, 0xF2, 0x01, 0xE9, 0x44, 0xF0, 0x3F, 0xBC, + 0x38, 0x97, 0xA5, 0x01, 0x40, 0xF4, 0xBC, 0x00, 0x4A, 0x00, 0x3C, 0x00, 0x18, 0x00, 0x4E, 0x00, + 0xB2, 0x01, 0xCA, 0x01, 0x5C, 0x03, 0x68, 0x03, 0x84, 0x03, 0xBE, 0x03, 0xBE, 0x03, 0xBE, 0x03, + 0x94, 0x03, 0xAE, 0x03, 0x44, 0x02, 0xBB, 0x28, 0xEB, 0x6B, 0x49, 0x00, 0x10, 0xE2, 0xF0, 0x01, + 0xEA, 0xE2, 0x49, 0x00, 0x10, 0xA0, 0x80, 0x06, 0x80, 0x28, 0x80, 0x4A, 0xEB, 0xC5, 0x84, 0x00, + 0xEA, 0x53, 0x5A, 0x60, 0x0F, 0x03, 0xEA, 0xCE, 0xDD, 0x4D, 0x84, 0xCC, 0x00, 0x00, 0x00, 0x50, + 0x5A, 0x00, 0xFB, 0x04, 0x48, 0x00, 0x01, 0xCE, 0xEA, 0xCE, 0x9E, 0x71, 0x84, 0x01, 0xE6, 0x26, + 0xEB, 0xC8, 0x4E, 0xF2, 0x00, 0xA5, 0x44, 0xF0, 0x40, 0x24, 0x38, 0x17, 0x85, 0x01, 0x40, 0xF0, + 0xBC, 0x00, 0xDD, 0x0F, 0x0C, 0x00, 0x0C, 0x00, 0x48, 0x00, 0x16, 0x01, 0x1C, 0x01, 0x4E, 0x00, + 0x84, 0x00, 0xEA, 0x53, 0x84, 0x01, 0xEB, 0x40, 0xFA, 0x31, 0x84, 0x04, 0xDD, 0x44, 0x2E, 0x07, + 0xEF, 0x12, 0xC8, 0x0C, 0x84, 0x04, 0xFA, 0x3A, 0xDD, 0x44, 0x5A, 0x60, 0x01, 0x04, 0x84, 0xC5, + 0xD5, 0x02, 0x84, 0xC4, 0x49, 0xFF, 0xFA, 0x14, 0xD5, 0x49, 0x84, 0x04, 0xFA, 0x3B, 0xDD, 0x44, + 0x5A, 0x60, 0x01, 0x04, 0xFA, 0xC5, 0xD5, 0x42, 0xFA, 0xC4, 0xD5, 0x40, 0xEB, 0x40, 0x84, 0xC2, + 0xF8, 0x94, 0xDD, 0x40, 0xEA, 0x31, 0xC0, 0x40, 0x84, 0x01, 0xEB, 0x40, 0x00, 0x00, 0x80, 0x52, + 0x84, 0xC0, 0x10, 0x6F, 0x80, 0x0F, 0x3E, 0x67, 0xEE, 0xC2, 0x5A, 0x08, 0xAA, 0x28, 0x49, 0x00, + 0x5F, 0x42, 0x84, 0x01, 0xEB, 0x8C, 0xDD, 0x4D, 0x00, 0x10, 0x00, 0x53, 0x00, 0x20, 0x00, 0x54, + 0x44, 0x0F, 0xFF, 0xA0, 0xFE, 0x0F, 0x5A, 0x28, 0x01, 0x11, 0xEB, 0x60, 0x44, 0x02, 0x98, 0x8C, + 0x3E, 0x67, 0xF2, 0xBB, 0x49, 0x00, 0x5F, 0xA2, 0x84, 0x03, 0x3E, 0x07, 0xF2, 0xB6, 0xDD, 0x4D, + 0x44, 0x1F, 0xFF, 0xBB, 0xEA, 0x4E, 0xD5, 0x07, 0xEB, 0x2B, 0xEA, 0xFD, 0x3E, 0x67, 0xF2, 0xBA, + 0x49, 0x00, 0x5F, 0x94, 0xDD, 0x4D, 0x84, 0x20, 0xEB, 0x1A, 0xEB, 0x9A, 0xC8, 0x06, 0xEB, 0x42, + 0x84, 0xC1, 0xC0, 0x04, 0xFA, 0xD0, 0xD5, 0x02, 0xFA, 0xC9, 0xEA, 0x88, 0x4E, 0x03, 0x01, 0x5A, + 0x84, 0x1F, 0xEA, 0x33, 0xF8, 0x52, 0x2E, 0x27, 0xF2, 0xBA, 0xC2, 0x02, 0xEA, 0x53, 0x00, 0x00, + 0x80, 0x52, 0x5A, 0x08, 0xAA, 0x18, 0x00, 0x20, 0x80, 0x54, 0x84, 0x00, 0x5A, 0x28, 0x01, 0x0E, + 0x00, 0x30, 0x80, 0x53, 0x44, 0x2F, 0xFF, 0xA0, 0xFE, 0x9F, 0xEA, 0x53, 0x3E, 0x27, 0xF2, 0xBA, + 0xEB, 0x2B, 0x3E, 0x07, 0xF2, 0xB6, 0xD5, 0x03, 0xEB, 0x60, 0xEB, 0x2B, 0x84, 0x00, 0x10, 0x00, + 0x80, 0x52, 0xEB, 0x42, 0x4E, 0x03, 0x01, 0x35, 0xD5, 0x19, 0xEA, 0x92, 0xEA, 0x69, 0xD5, 0x16, + 0x84, 0x00, 0xEA, 0x31, 0xEA, 0x53, 0x84, 0x01, 0xEB, 0x40, 0x00, 0x00, 0x80, 0x55, 0x00, 0x10, + 0x80, 0x54, 0xEB, 0x44, 0x3C, 0x0B, 0xF7, 0xCA, 0xFA, 0xC2, 0xF8, 0x1F, 0x84, 0x04, 0xFA, 0x3F, + 0xDD, 0x44, 0x84, 0x00, 0xEB, 0xC8, 0x84, 0x02, 0xEA, 0x53, 0x84, 0xC1, 0xF8, 0x16, 0x84, 0x02, + 0xEB, 0x25, 0x80, 0x26, 0x84, 0x01, 0xEB, 0x47, 0x49, 0xFF, 0xFC, 0xCE, 0x80, 0xC0, 0x84, 0x05, + 0xEB, 0x25, 0x48, 0x00, 0x01, 0x0F, 0x84, 0x00, 0x2E, 0x17, 0xEE, 0xBA, 0xEA, 0x53, 0x84, 0x01, + 0xEB, 0xC8, 0x5A, 0x18, 0x01, 0x05, 0x84, 0xC9, 0x48, 0x00, 0x01, 0x04, 0x3E, 0x07, 0xEE, 0xBA, + 0xEB, 0x25, 0x9E, 0x31, 0xE6, 0x0C, 0x4E, 0xF2, 0x00, 0xA1, 0x44, 0xF0, 0x41, 0xB8, 0xEA, 0xA1, + 0x40, 0xF0, 0x3C, 0x00, 0x4A, 0x00, 0x3C, 0x00, 0x18, 0x00, 0x30, 0x01, 0x84, 0x00, 0x30, 0x01, + 0x84, 0x00, 0x30, 0x01, 0xD0, 0x00, 0x30, 0x01, 0x1C, 0x01, 0x84, 0x00, 0x44, 0x00, 0x30, 0x00, + 0x84, 0x00, 0x44, 0x10, 0x00, 0x41, 0xDD, 0x44, 0x84, 0x01, 0x3E, 0x07, 0xEF, 0x2D, 0xDD, 0x52, + 0xEA, 0xD8, 0x84, 0x01, 0xEA, 0x2D, 0xF8, 0x09, 0x84, 0x00, 0xEB, 0xC7, 0xDD, 0x44, 0x84, 0x01, + 0x3E, 0x07, 0xEF, 0x2D, 0xDD, 0x52, 0xEA, 0xD8, 0x48, 0x00, 0x00, 0x7A, 0x84, 0x00, 0x44, 0x10, + 0x00, 0x4B, 0xDD, 0x44, 0xEA, 0x31, 0x84, 0x01, 0x00, 0x10, 0x80, 0x51, 0xDD, 0x44, 0x84, 0xC0, + 0x84, 0x01, 0x3E, 0x07, 0xEF, 0x5B, 0x3E, 0x67, 0xEE, 0xC3, 0xF8, 0x5A, 0xEA, 0xD5, 0xEB, 0x54, + 0xB4, 0x01, 0xEB, 0xCF, 0xB6, 0x01, 0x3C, 0x0D, 0xFC, 0x42, 0x3E, 0x67, 0xEE, 0xF0, 0xEB, 0xCF, + 0x3C, 0x0F, 0xFC, 0x42, 0x84, 0x00, 0xEA, 0x6C, 0xEA, 0x85, 0xD5, 0x59, 0xEA, 0x31, 0xDD, 0x52, + 0xEA, 0xD8, 0x00, 0x10, 0x80, 0x51, 0x84, 0x01, 0xEA, 0x2D, 0xDD, 0x44, 0xDD, 0x4D, 0x80, 0x26, + 0xEA, 0x52, 0xEB, 0x47, 0xF8, 0x38, 0xEB, 0x24, 0x5A, 0x00, 0x02, 0x4A, 0x3C, 0x2D, 0xFC, 0xFD, + 0x00, 0x01, 0x00, 0x55, 0x00, 0x31, 0x00, 0x54, 0x40, 0x31, 0x81, 0x00, 0x00, 0x11, 0x00, 0x52, + 0x42, 0x31, 0xC0, 0x08, 0x00, 0x01, 0x00, 0x51, 0x80, 0x46, 0x3E, 0x17, 0xEE, 0xF5, 0x3C, 0x3F, + 0xFC, 0x24, 0x49, 0x00, 0x17, 0x88, 0xD5, 0x33, 0x84, 0x00, 0x44, 0x10, 0x00, 0x47, 0xDD, 0x44, + 0xEA, 0x31, 0x84, 0x01, 0x00, 0x10, 0x80, 0x51, 0xDD, 0x44, 0xDD, 0x52, 0xEA, 0xD8, 0x00, 0x05, + 0x00, 0x01, 0x5A, 0x08, 0x03, 0x08, 0xDD, 0x54, 0xA6, 0x00, 0x5A, 0x00, 0x03, 0x04, 0x84, 0x02, + 0xD5, 0x02, 0x84, 0x01, 0xEA, 0x2D, 0x84, 0x01, 0x3E, 0x07, 0xEF, 0x20, 0xDD, 0x4D, 0x84, 0x27, + 0xEA, 0x52, 0xEB, 0x47, 0x49, 0x00, 0x17, 0x46, 0xEB, 0x24, 0x5A, 0x00, 0x02, 0x11, 0x49, 0xFF, + 0xFA, 0xE0, 0xD5, 0x0D, 0xEA, 0x31, 0x84, 0x01, 0x00, 0x10, 0x80, 0x52, 0xEA, 0x53, 0x3E, 0x17, + 0xEF, 0x29, 0x3E, 0x07, 0xEF, 0x49, 0xD5, 0x03, 0x84, 0x02, 0xEA, 0x53, 0xEB, 0x24, 0x5A, 0x00, + 0x02, 0x04, 0x48, 0xFF, 0xFF, 0x52, 0xDD, 0x4D, 0x84, 0xC0, 0x10, 0x60, 0x00, 0x51, 0x3E, 0x67, + 0xEF, 0x4A, 0x3E, 0x67, 0xEE, 0xBA, 0xDD, 0x43, 0x5A, 0x00, 0x02, 0x05, 0x3E, 0x67, 0xEF, 0x75, + 0xEA, 0xCE, 0x84, 0x05, 0xEB, 0x25, 0xEA, 0xCE, 0x80, 0x06, 0x80, 0x2B, 0xEB, 0x47, 0x49, 0xFF, + 0xFC, 0xB0, 0xD5, 0x1C, 0x84, 0x00, 0x44, 0x10, 0x00, 0x60, 0xDD, 0x44, 0x80, 0x06, 0x80, 0x2A, + 0x44, 0x22, 0xBB, 0xC2, 0x50, 0x3F, 0x80, 0x0F, 0x49, 0xFF, 0xFC, 0xC4, 0x97, 0x80, 0xD5, 0x31, + 0x80, 0x06, 0x80, 0x28, 0x80, 0x4B, 0x50, 0x3F, 0x80, 0x0F, 0x49, 0xFF, 0xFD, 0x5B, 0xD5, 0x06, + 0x80, 0x06, 0x80, 0x2B, 0xEB, 0x47, 0x49, 0xFF, 0xF9, 0x13, 0xEB, 0x24, 0x5A, 0x08, 0x02, 0x03, + 0xEA, 0xCE, 0xB4, 0x0B, 0xB6, 0x0C, 0x84, 0xCB, 0xD5, 0x1C, 0x5A, 0x60, 0x01, 0x04, 0x48, 0xFF, + 0xFE, 0xFC, 0x49, 0xFF, 0xF7, 0x43, 0xFA, 0xC3, 0xD5, 0x14, 0x84, 0x02, 0x84, 0xC1, 0xEA, 0x53, + 0x3E, 0x67, 0xEF, 0x21, 0xDD, 0x40, 0xC0, 0x07, 0x3E, 0x67, 0xEF, 0x21, 0x84, 0x0F, 0x44, 0x10, + 0x00, 0xFB, 0xD5, 0x04, 0x84, 0x0F, 0x44, 0x10, 0x00, 0xEB, 0xDD, 0x44, 0xEA, 0xCE, 0xFA, 0xD0, + 0xEB, 0x24, 0x84, 0x20, 0x5A, 0x00, 0x01, 0x05, 0x5A, 0x08, 0x02, 0x06, 0x84, 0x3B, 0xDD, 0x4D, + 0x10, 0x10, 0x00, 0x50, 0x2E, 0x07, 0xEF, 0x4A, 0xC8, 0x0A, 0x44, 0x02, 0xBB, 0x28, 0xEB, 0x6B, + 0x49, 0x00, 0x0E, 0xEF, 0xF0, 0x01, 0xEA, 0xE2, 0x49, 0x00, 0x0E, 0xD9, 0x80, 0x06, 0xFC, 0xE2, + 0x5A, 0x08, 0x07, 0x1E, 0x8E, 0x27, 0xE6, 0x28, 0xE8, 0x59, 0x44, 0xF0, 0x43, 0xE4, 0xEA, 0xD6, + 0xEA, 0x89, 0xDD, 0x0F, 0x08, 0x10, 0xA6, 0xA6, 0xA6, 0xA6, 0x18, 0x20, 0xB4, 0x03, 0x42, 0x00, + 0x5C, 0x08, 0xD5, 0x47, 0xB4, 0x03, 0x42, 0x00, 0x5C, 0x09, 0xD5, 0x43, 0xB4, 0x03, 0x42, 0x00, + 0x58, 0x08, 0xD5, 0x3F, 0xB4, 0x03, 0x42, 0x00, 0x58, 0x09, 0xD5, 0x3B, 0x5A, 0x08, 0x0B, 0x2D, + 0x8E, 0x21, 0xE6, 0x28, 0xE8, 0x38, 0x44, 0xF0, 0x44, 0x20, 0xEA, 0xD6, 0xEA, 0x89, 0xDD, 0x0F, + 0x08, 0x10, 0x18, 0x20, 0x28, 0x30, 0x38, 0x3E, 0xB4, 0x03, 0x42, 0x00, 0x70, 0x08, 0xD5, 0x29, + 0xB4, 0x03, 0x42, 0x00, 0x70, 0x09, 0xD5, 0x25, 0xB4, 0x03, 0x42, 0x00, 0x74, 0x08, 0xD5, 0x21, + 0xB4, 0x03, 0x42, 0x00, 0x74, 0x09, 0xD5, 0x1D, 0xB4, 0x03, 0x42, 0x00, 0x78, 0x08, 0xD5, 0x19, + 0xB4, 0x03, 0x42, 0x00, 0x78, 0x09, 0xD5, 0x15, 0xB4, 0x03, 0xEB, 0xCF, 0xD5, 0x12, 0xB4, 0x03, + 0x42, 0x00, 0x54, 0x09, 0xD5, 0x0E, 0x5A, 0x08, 0x05, 0x12, 0x5A, 0x10, 0x01, 0x08, 0x5A, 0x18, + 0x03, 0x0B, 0xB4, 0x03, 0x42, 0x00, 0x48, 0x08, 0xD5, 0x04, 0xB4, 0x03, 0x42, 0x00, 0x48, 0x09, + 0xB6, 0x03, 0xDD, 0x9E, 0x84, 0x3B, 0xEA, 0xE6, 0xAE, 0x40, 0xDD, 0x9E, 0xFC, 0x61, 0xB6, 0x1F, + 0xF2, 0x81, 0xEA, 0xE6, 0xA7, 0xC0, 0xA7, 0x80, 0x44, 0x02, 0xFE, 0x51, 0xA6, 0x00, 0x92, 0xE4, + 0x97, 0x9F, 0xEB, 0x2D, 0x5A, 0x70, 0x01, 0x04, 0x48, 0x00, 0x00, 0x7E, 0x9E, 0x31, 0xE6, 0x03, + 0x81, 0x43, 0xE9, 0x0E, 0x5A, 0x60, 0x05, 0x03, 0xF8, 0x16, 0xDD, 0x4D, 0x00, 0x00, 0x00, 0x60, + 0x5A, 0x00, 0xA1, 0x07, 0x2E, 0x07, 0xF3, 0x73, 0x5A, 0x08, 0x01, 0x03, 0xF8, 0x0C, 0x2E, 0x07, + 0xF2, 0xF1, 0x4E, 0x03, 0x00, 0x84, 0xEA, 0x95, 0x5A, 0x08, 0xAA, 0x03, 0xF8, 0x04, 0xDD, 0x43, + 0x5A, 0x00, 0x02, 0x04, 0x48, 0x00, 0x00, 0x7B, 0x4E, 0xA2, 0x00, 0x79, 0xDD, 0x40, 0xC0, 0x0A, + 0xDD, 0x41, 0xA6, 0x01, 0xEB, 0xBA, 0x5A, 0x08, 0x04, 0x06, 0x44, 0x00, 0x00, 0x88, 0xDD, 0x4A, + 0xFC, 0xE1, 0x44, 0x02, 0xBB, 0x28, 0xEB, 0x6B, 0x49, 0x00, 0x0E, 0x4B, 0x44, 0x02, 0xBB, 0x5D, + 0xEA, 0xE2, 0x49, 0x00, 0x0E, 0x08, 0x5A, 0x60, 0x05, 0x05, 0x84, 0x00, 0x49, 0x00, 0x5B, 0x82, + 0xEA, 0x7B, 0xEA, 0x50, 0xEA, 0x48, 0xA6, 0x08, 0x5A, 0x08, 0x01, 0x04, 0xAE, 0xD0, 0xD5, 0xFC, + 0xDD, 0x40, 0xC0, 0x29, 0xF8, 0x15, 0x44, 0x00, 0x00, 0x82, 0xDD, 0x4A, 0x44, 0x73, 0xF4, 0x1C, + 0x2E, 0x0F, 0xF2, 0xC3, 0x4E, 0x07, 0x00, 0x17, 0xA6, 0x38, 0x5A, 0x08, 0x02, 0x10, 0xEA, 0x7F, + 0x80, 0x41, 0x84, 0x66, 0x84, 0x02, 0xDD, 0x42, 0x44, 0x00, 0x00, 0x83, 0xDD, 0x4A, 0xDD, 0x47, + 0xDD, 0x45, 0xAE, 0x40, 0x83, 0xFF, 0xEA, 0x29, 0xD5, 0x0A, 0xDD, 0x43, 0x5A, 0x00, 0x02, 0xEA, + 0xD5, 0xEF, 0x2E, 0x0F, 0xF2, 0xC2, 0x4E, 0x06, 0xFF, 0xE9, 0xD5, 0xEA, 0xA6, 0x08, 0x5A, 0x08, + 0xE1, 0xFF, 0xD5, 0x0C, 0x44, 0x00, 0x00, 0x84, 0xDD, 0x4A, 0xEA, 0x29, 0x44, 0x0F, 0xFF, 0xE1, + 0xAE, 0x08, 0x80, 0x41, 0x84, 0x02, 0x84, 0x61, 0xDD, 0x42, 0x80, 0x06, 0x80, 0x29, 0xB4, 0x5F, + 0xEB, 0xC5, 0xFC, 0xE1, 0x81, 0x61, 0x5A, 0x70, 0x0B, 0x06, 0x54, 0x03, 0x80, 0x0D, 0x5A, 0x08, + 0x05, 0x16, 0xDD, 0x40, 0xC0, 0x13, 0xEA, 0x95, 0x5A, 0x00, 0xAA, 0x11, 0x44, 0xA2, 0xFE, 0x50, + 0x84, 0x00, 0xEA, 0x9D, 0x80, 0x26, 0x80, 0x07, 0x80, 0x49, 0xF3, 0x01, 0x49, 0xFF, 0xFF, 0x02, + 0xEB, 0x7C, 0x5A, 0x00, 0xFB, 0x04, 0x84, 0x01, 0xEB, 0x17, 0xFC, 0xE1, 0x44, 0x13, 0xF0, 0x4A, + 0xDD, 0x5B, 0xDD, 0x4D, 0xEA, 0x52, 0x5A, 0x00, 0xBB, 0x04, 0xAE, 0x88, 0xD5, 0xFB, 0xDD, 0x9E, + 0xFC, 0x00, 0x80, 0xC0, 0xDD, 0x4D, 0xEA, 0x52, 0x5A, 0x08, 0xBB, 0x22, 0x49, 0x00, 0x5C, 0x8B, + 0xDD, 0x4D, 0x00, 0x10, 0x00, 0x50, 0xC1, 0x03, 0x5A, 0x18, 0xFB, 0x10, 0x2E, 0x17, 0xF2, 0xBB, + 0xC9, 0x04, 0x2E, 0x17, 0xF2, 0xBA, 0xC1, 0x10, 0x84, 0x00, 0xEB, 0x2B, 0xEB, 0x60, 0x84, 0x00, + 0xEB, 0x8C, 0x84, 0x01, 0xEA, 0xC0, 0xD5, 0x17, 0xCE, 0x08, 0xEB, 0x9A, 0x5A, 0x08, 0xA0, 0x0A, + 0x44, 0x03, 0x0F, 0xA0, 0xD5, 0x0B, 0xC6, 0x09, 0xEB, 0x61, 0xD5, 0x0C, 0xC6, 0xF7, 0xD5, 0x0B, + 0x5A, 0x08, 0xA1, 0x04, 0xEA, 0x7C, 0xD5, 0x02, 0xEA, 0x3D, 0xEA, 0x86, 0xDD, 0x5D, 0xEB, 0x61, + 0xDD, 0x4D, 0xEA, 0x4E, 0xFC, 0x80, 0x3C, 0x0F, 0xFC, 0xFE, 0xDD, 0x9E, 0x3C, 0x1D, 0xFC, 0xFE, + 0x2E, 0x07, 0xEF, 0x11, 0xA6, 0x8E, 0xC8, 0x0C, 0xEA, 0x2E, 0x5A, 0x08, 0x01, 0x0A, 0x94, 0x11, + 0xAC, 0x09, 0xA6, 0x09, 0x8E, 0x01, 0xF8, 0x07, 0x94, 0x01, 0xF8, 0x0A, 0xD5, 0x10, 0xA6, 0x09, + 0xAC, 0x89, 0x8E, 0x01, 0xFE, 0x14, 0x84, 0x42, 0xEA, 0xC9, 0x8E, 0x01, 0x83, 0xFF, 0x96, 0x03, + 0x3C, 0x0B, 0xF7, 0xEA, 0xFE, 0x03, 0x3C, 0x0B, 0xF7, 0xE9, 0x83, 0xFF, 0x2E, 0x07, 0xF2, 0xE5, + 0x5A, 0x08, 0x01, 0x11, 0xA4, 0x89, 0x84, 0x03, 0xFE, 0x14, 0x90, 0x01, 0xAC, 0x09, 0x3C, 0x03, + 0xF7, 0xEA, 0x94, 0x03, 0x3C, 0x0B, 0xF7, 0xEA, 0x3C, 0x03, 0xF7, 0xE9, 0x94, 0x03, 0x3C, 0x0B, + 0xF7, 0xE9, 0xA6, 0x09, 0x3E, 0x07, 0xEF, 0x6F, 0x8C, 0x01, 0x3E, 0x07, 0xEF, 0x70, 0xDD, 0x9E, + 0xFC, 0x60, 0x51, 0xFF, 0xF3, 0x40, 0x84, 0xC0, 0x44, 0x92, 0x00, 0x00, 0x44, 0xB0, 0x00, 0x80, + 0x81, 0x80, 0x84, 0xE5, 0x80, 0x01, 0x84, 0x81, 0xF1, 0x8C, 0xF2, 0x8D, 0x85, 0x00, 0xF8, 0x09, + 0x80, 0xA4, 0xB6, 0xDF, 0xF8, 0x99, 0xF8, 0xBB, 0xF8, 0xC0, 0xF8, 0x8A, 0xF0, 0x0D, 0x84, 0x81, + 0xEA, 0x3B, 0xEB, 0xA3, 0xF7, 0x87, 0xEB, 0xB0, 0x80, 0x40, 0x83, 0xFF, 0x80, 0xA4, 0xB6, 0xDF, + 0xF8, 0x8B, 0xF8, 0xAD, 0xF8, 0xB2, 0xEA, 0x23, 0xEA, 0x63, 0xEA, 0x3B, 0x84, 0xE1, 0x8E, 0x81, + 0x40, 0x16, 0x0C, 0x20, 0xF8, 0x9C, 0xEB, 0xA3, 0x80, 0x0C, 0x80, 0xA7, 0xF7, 0x81, 0xF8, 0x9F, + 0xF7, 0x87, 0xF8, 0xA3, 0x44, 0x22, 0x55, 0xB8, 0x97, 0x20, 0xEA, 0x23, 0xF8, 0xA4, 0x44, 0xA2, + 0x55, 0xB8, 0x40, 0x21, 0x9C, 0x0C, 0xB1, 0x50, 0x84, 0x03, 0x8E, 0x82, 0xF8, 0x88, 0xEB, 0xA3, + 0xF0, 0x87, 0x80, 0x2A, 0x40, 0x01, 0x28, 0x00, 0xF7, 0x81, 0x88, 0x45, 0xF6, 0x84, 0x80, 0xA7, + 0xF8, 0x87, 0xF8, 0x8B, 0x97, 0x20, 0xEA, 0x23, 0x85, 0xA2, 0xB0, 0x50, 0xEA, 0x3B, 0x80, 0x0A, + 0xF8, 0x11, 0xF8, 0x7C, 0x14, 0xDF, 0x80, 0x07, 0xF8, 0x80, 0xEA, 0x23, 0x00, 0x24, 0x80, 0x03, + 0xEA, 0x3B, 0x8E, 0x42, 0x42, 0x01, 0x88, 0x24, 0xB0, 0x90, 0x98, 0x43, 0xEA, 0xD3, 0x40, 0x05, + 0x00, 0x20, 0x80, 0x41, 0x80, 0x87, 0x80, 0xA7, 0xB6, 0xDF, 0xF7, 0x81, 0xF6, 0x82, 0x83, 0xFF, + 0xF8, 0x65, 0x14, 0xDF, 0x80, 0x07, 0xF8, 0x69, 0xEA, 0x23, 0xEA, 0x3B, 0xB0, 0x10, 0xEA, 0x63, + 0xB6, 0x7F, 0x4E, 0x00, 0xFF, 0xAA, 0x80, 0xA7, 0xF6, 0x81, 0xF8, 0x6A, 0xF6, 0x8A, 0xF8, 0x3B, + 0x00, 0x34, 0x80, 0x02, 0x3C, 0x0D, 0xFC, 0xFE, 0xB6, 0x7F, 0xF8, 0x2E, 0xF6, 0x83, 0xF8, 0x1A, + 0xA4, 0x41, 0xB0, 0x10, 0x88, 0x2D, 0x96, 0x4B, 0xEA, 0x63, 0xF1, 0x88, 0x80, 0x40, 0xEB, 0xB0, + 0x80, 0xA7, 0xF6, 0x89, 0xF6, 0x8A, 0x12, 0x6F, 0x80, 0x1F, 0xEA, 0x23, 0x3C, 0x07, 0xF7, 0xE9, + 0xEA, 0x3B, 0xF0, 0x88, 0x3C, 0x07, 0xF7, 0xEA, 0xF8, 0x0F, 0xF0, 0x89, 0xEB, 0xB0, 0x80, 0x0C, + 0xF8, 0x11, 0xF6, 0x84, 0xF6, 0x85, 0xF7, 0x86, 0xF6, 0x87, 0x83, 0xFF, 0xF6, 0x8A, 0x12, 0x8F, + 0x80, 0x1F, 0xEA, 0x23, 0xEA, 0x3B, 0xEA, 0x63, 0xB6, 0x7F, 0xEB, 0xA3, 0x83, 0xFF, 0x80, 0x0A, + 0xEB, 0xB0, 0x80, 0x4A, 0x80, 0xA7, 0xF6, 0x81, 0xF6, 0x82, 0x83, 0xFF, 0xF8, 0x20, 0xF7, 0x87, + 0xF8, 0x24, 0x85, 0x68, 0x12, 0x7F, 0x80, 0x1F, 0xEA, 0x23, 0xF8, 0x0E, 0x80, 0x0A, 0xF8, 0x13, + 0xF8, 0x1A, 0xEA, 0x23, 0xF1, 0x0D, 0xF8, 0x1F, 0xB6, 0x7F, 0xB0, 0x10, 0x80, 0x41, 0x80, 0xA7, + 0xF8, 0x1E, 0xF7, 0x8A, 0xEA, 0x23, 0xEA, 0x3B, 0xB0, 0x50, 0xEA, 0x63, 0xB6, 0x7F, 0xF3, 0x82, + 0x83, 0xFF, 0x80, 0x0C, 0x80, 0x41, 0x80, 0xA7, 0xF7, 0x81, 0xF6, 0x83, 0xF6, 0x84, 0xF6, 0x85, + 0xF6, 0x86, 0x83, 0xFF, 0x14, 0xBF, 0x80, 0x07, 0xF6, 0x88, 0xF6, 0x89, 0xF6, 0x8A, 0x83, 0xFF, + 0xEA, 0x23, 0xF1, 0x0C, 0xEA, 0x3B, 0xEA, 0x63, 0x83, 0xFF, 0xB6, 0x7F, 0xF7, 0x81, 0xF6, 0x82, + 0xF6, 0x83, 0xF6, 0x84, 0xF6, 0x85, 0xF6, 0x86, 0xF6, 0x87, 0xF6, 0x88, 0xF6, 0x89, 0x83, 0xFF, + 0xF7, 0x8A, 0xB0, 0x10, 0x80, 0x41, 0x80, 0xA7, 0xEA, 0x23, 0x51, 0xFF, 0x8C, 0xC0, 0xFC, 0xE0, + 0xFC, 0x48, 0x80, 0xE0, 0x84, 0x00, 0x3E, 0x07, 0xEF, 0x34, 0x80, 0x5F, 0xA0, 0x3E, 0x80, 0xC1, + 0x49, 0xFF, 0xFF, 0x08, 0x84, 0x80, 0x3D, 0x2D, 0xFC, 0xFE, 0x2E, 0x07, 0xEF, 0x34, 0x3D, 0x0C, + 0x03, 0x22, 0x80, 0x26, 0x82, 0x64, 0x86, 0x23, 0xEA, 0x9B, 0xE2, 0x82, 0xE8, 0x64, 0x38, 0x3F, + 0x91, 0x11, 0x00, 0x29, 0x00, 0x04, 0xE0, 0x43, 0xE8, 0x08, 0xA4, 0x88, 0x96, 0x93, 0x40, 0x21, + 0x0C, 0x56, 0x96, 0x93, 0xAC, 0x88, 0xD5, 0x03, 0x13, 0x30, 0x80, 0x00, 0xA4, 0x88, 0x96, 0x93, + 0xEB, 0x65, 0x5E, 0xF7, 0x80, 0x8D, 0xE9, 0x02, 0x84, 0x01, 0x85, 0x20, 0x2E, 0x27, 0x33, 0x8B, + 0xE3, 0x22, 0xE8, 0x46, 0xEA, 0x96, 0x80, 0xA4, 0x42, 0x51, 0xA4, 0x73, 0xA4, 0x88, 0x96, 0xE9, + 0xA5, 0x48, 0x96, 0x93, 0x97, 0x6B, 0x94, 0xD9, 0x4E, 0x54, 0x00, 0x1B, 0xF8, 0x1C, 0x9B, 0x75, + 0x4E, 0x57, 0x00, 0x2D, 0x02, 0x25, 0x00, 0x00, 0x97, 0x53, 0xF8, 0x04, 0x9A, 0xAA, 0x4E, 0x27, + 0x00, 0x08, 0xA4, 0x88, 0x96, 0x93, 0x40, 0x21, 0x44, 0x56, 0x83, 0xFF, 0xD5, 0x1F, 0xA4, 0x88, + 0x96, 0x93, 0x5E, 0xF1, 0x7F, 0x6A, 0xE8, 0x17, 0xA4, 0x88, 0x96, 0x93, 0xD5, 0x17, 0xF8, 0x08, + 0x4E, 0x57, 0x00, 0x15, 0x40, 0xA8, 0x0C, 0x00, 0x02, 0x55, 0x00, 0x00, 0x97, 0xAB, 0xA5, 0x48, + 0x97, 0x6B, 0x83, 0xFF, 0x9B, 0x75, 0x4E, 0x54, 0x00, 0x0A, 0x02, 0x55, 0x00, 0x00, 0x97, 0x6B, + 0x4E, 0x57, 0x00, 0x05, 0x02, 0x25, 0x00, 0x00, 0x96, 0x93, 0xA1, 0x7D, 0xA1, 0xBE, 0x88, 0xA3, + 0x88, 0x66, 0xA4, 0xD8, 0x8D, 0x21, 0x9A, 0x9A, 0x96, 0x93, 0xAC, 0xA8, 0xD5, 0xB8, 0x8C, 0x81, + 0x8C, 0x22, 0xD5, 0x9B, 0x3E, 0x07, 0xEF, 0x34, 0xFC, 0xC8, 0xFC, 0x01, 0xB6, 0x1F, 0xF1, 0x81, + 0x49, 0xFF, 0xFE, 0x56, 0xB4, 0x1F, 0xF1, 0x01, 0x84, 0x40, 0x49, 0xFF, 0xFF, 0x7B, 0xFC, 0x81, + 0x3C, 0x0F, 0xFC, 0x85, 0xDD, 0x9E, 0x3C, 0x0F, 0xFC, 0x83, 0xDD, 0x9E, 0x3C, 0x0F, 0xFC, 0x84, + 0xDD, 0x9E, 0xFC, 0x00, 0xA6, 0x90, 0x3C, 0x43, 0x9A, 0x1D, 0xC2, 0x02, 0x84, 0x41, 0xA8, 0x82, + 0xA0, 0x82, 0xA0, 0x03, 0x96, 0x94, 0x3C, 0x5D, 0xFC, 0x84, 0x96, 0xD9, 0x96, 0x04, 0xCA, 0x0D, + 0xC8, 0x2A, 0xA6, 0xA8, 0x88, 0x44, 0x88, 0x43, 0xAC, 0x88, 0xEA, 0x9B, 0xE2, 0x02, 0xE8, 0x04, + 0xA6, 0xA8, 0xF8, 0x2A, 0xD5, 0xFB, 0xFC, 0x80, 0xC0, 0x13, 0xA6, 0x2A, 0x84, 0x40, 0x88, 0x04, + 0x88, 0x03, 0xAC, 0x08, 0x2E, 0x07, 0x33, 0x8A, 0xE2, 0x40, 0xE8, 0x09, 0xA6, 0x2A, 0xA1, 0x89, + 0x88, 0x04, 0x88, 0x03, 0x38, 0x03, 0x09, 0x09, 0x8C, 0x41, 0xD5, 0xF5, 0xFC, 0x80, 0xA6, 0xA9, + 0x88, 0x44, 0x88, 0x43, 0xAC, 0x88, 0xEA, 0x9B, 0xE2, 0x02, 0xE8, 0x04, 0xA6, 0xA9, 0xF8, 0x0C, + 0xD5, 0xFB, 0xFC, 0x80, 0xA6, 0x2B, 0x88, 0x04, 0x88, 0x03, 0xAC, 0x08, 0x80, 0x02, 0xEA, 0x9B, + 0xE2, 0x02, 0xE8, 0x0A, 0xA6, 0xAB, 0xA1, 0x89, 0x88, 0x44, 0x88, 0x43, 0x38, 0x23, 0x01, 0x09, + 0x8C, 0x01, 0x83, 0xFF, 0xD5, 0xF5, 0xFC, 0x80, 0xFC, 0x41, 0x80, 0xC0, 0x84, 0x00, 0x80, 0xE2, + 0xF8, 0x0D, 0x84, 0x63, 0xF8, 0x87, 0xEA, 0xA8, 0xB6, 0x07, 0xF8, 0x12, 0xA4, 0x70, 0x44, 0x92, + 0x00, 0x00, 0xF8, 0x12, 0x10, 0x13, 0x80, 0x10, 0x84, 0x1F, 0x50, 0x1F, 0x80, 0x06, 0xEA, 0xAB, + 0xFA, 0x50, 0xB4, 0x06, 0x83, 0xFF, 0x84, 0x64, 0xF8, 0x75, 0xEA, 0xA8, 0xA8, 0x39, 0x49, 0x00, + 0x55, 0x6E, 0xA4, 0x70, 0x84, 0x60, 0x8A, 0x01, 0x00, 0x14, 0x80, 0x02, 0x92, 0x01, 0x40, 0x00, + 0x04, 0x37, 0x83, 0xFF, 0x10, 0x13, 0x80, 0x11, 0xB4, 0x06, 0xA0, 0x72, 0xA0, 0xB6, 0x84, 0x81, + 0x49, 0x00, 0x0C, 0x98, 0xFC, 0xC1, 0xFC, 0x00, 0x49, 0xFF, 0xFF, 0xD0, 0xFC, 0x80, 0xFC, 0x68, + 0x81, 0x21, 0x84, 0x20, 0x81, 0x42, 0x80, 0xE4, 0x12, 0x1F, 0x80, 0x19, 0x5A, 0x48, 0x04, 0x1C, + 0x84, 0xC0, 0x12, 0x3F, 0x80, 0x19, 0x84, 0xA1, 0xA6, 0xD2, 0xA7, 0x13, 0xF6, 0x81, 0xF6, 0x82, + 0xF6, 0x83, 0xF6, 0x84, 0xF6, 0x85, 0xF6, 0x86, 0xF6, 0x88, 0xF6, 0x89, 0xF6, 0x8A, 0xB6, 0x7F, + 0xF5, 0x87, 0xA0, 0x06, 0x50, 0x1F, 0x80, 0x32, 0x44, 0x22, 0x55, 0xB8, 0xEA, 0x23, 0x44, 0x62, + 0x55, 0xB8, 0xD5, 0x02, 0xA1, 0x85, 0x02, 0x35, 0x02, 0xDE, 0x00, 0x55, 0x00, 0x02, 0x00, 0x05, + 0x00, 0x03, 0x50, 0xBF, 0x80, 0x34, 0x85, 0x40, 0x80, 0x83, 0xB6, 0x1F, 0x80, 0x26, 0x80, 0x06, + 0x84, 0x45, 0x14, 0xAF, 0x80, 0x01, 0x14, 0xAF, 0x80, 0x02, 0x14, 0xAF, 0x80, 0x03, 0x14, 0xBF, + 0x80, 0x04, 0x49, 0x00, 0x53, 0xF4, 0x02, 0x0F, 0x80, 0x1A, 0xEA, 0xBC, 0x02, 0x05, 0x80, 0x01, + 0xEB, 0xEA, 0x50, 0x1F, 0x80, 0x32, 0x80, 0x06, 0x80, 0x4A, 0x84, 0x63, 0xF8, 0x13, 0x02, 0x0F, + 0x80, 0x19, 0x5A, 0x78, 0x04, 0x05, 0x3C, 0x0B, 0xF7, 0xE5, 0xD5, 0x05, 0x5A, 0x78, 0x05, 0x04, + 0x3C, 0x0B, 0xF7, 0xE1, 0x12, 0x04, 0x80, 0x03, 0x50, 0x1F, 0x80, 0x32, 0x80, 0x06, 0x84, 0x40, + 0x84, 0x64, 0x49, 0x00, 0x0B, 0xFA, 0x02, 0x0F, 0x80, 0x19, 0x5A, 0x78, 0x04, 0x05, 0x3C, 0x0B, + 0xF7, 0xCB, 0xD5, 0x05, 0x5A, 0x78, 0x05, 0x04, 0x3C, 0x0B, 0xF7, 0xC3, 0x12, 0x04, 0x80, 0x02, + 0x5A, 0x70, 0x04, 0x12, 0x84, 0x00, 0x3E, 0x07, 0xEF, 0x0C, 0x22, 0x14, 0x80, 0x03, 0x3C, 0x03, + 0x9C, 0xA1, 0xE0, 0x20, 0xE8, 0x08, 0xEB, 0x50, 0xB4, 0x00, 0xEA, 0xD2, 0xC8, 0x04, 0x84, 0x01, + 0x3E, 0x07, 0xEF, 0x0C, 0xFC, 0xE8, 0x84, 0x20, 0x3E, 0x17, 0xF3, 0x7A, 0x22, 0x20, 0x00, 0x03, + 0x5E, 0xF1, 0x00, 0xB4, 0xE9, 0x09, 0x2E, 0x17, 0xF3, 0xFC, 0x5C, 0xF0, 0x80, 0x3C, 0xE8, 0x04, + 0x8C, 0x21, 0x3E, 0x17, 0xF3, 0xFC, 0xEA, 0xE5, 0x84, 0x27, 0xFE, 0x8C, 0x22, 0x30, 0x00, 0x02, + 0x84, 0x8A, 0x40, 0xF1, 0x11, 0xF6, 0xEA, 0xE3, 0xE0, 0x6F, 0xE9, 0x28, 0xA4, 0x40, 0x84, 0x45, + 0xFE, 0x54, 0xA4, 0xC1, 0xE4, 0x34, 0xE9, 0x04, 0x40, 0xF0, 0x91, 0xF6, 0xD5, 0x02, 0x85, 0xE1, + 0xE0, 0x6F, 0xE9, 0x1C, 0xFC, 0x00, 0x80, 0xC0, 0xDD, 0x43, 0x5A, 0x08, 0x02, 0x17, 0x22, 0xF3, + 0x00, 0x03, 0x5E, 0xF7, 0x80, 0xB4, 0xE8, 0x11, 0x2E, 0x07, 0xF3, 0xFC, 0xC0, 0x04, 0x8E, 0x01, + 0x3E, 0x07, 0xF3, 0xFC, 0x2E, 0x07, 0xF3, 0xFC, 0xC8, 0x08, 0x84, 0x01, 0x3E, 0x07, 0xF3, 0x7A, + 0x44, 0x00, 0x00, 0x3C, 0x3E, 0x07, 0xF3, 0xFC, 0xFC, 0x80, 0xDD, 0x9E, 0xFC, 0x6F, 0x50, 0xAF, + 0x80, 0x38, 0x81, 0x21, 0x81, 0x80, 0x81, 0x62, 0x84, 0x20, 0xEB, 0x63, 0x80, 0x0A, 0x84, 0xC0, + 0xEA, 0x2F, 0x84, 0xE1, 0xEA, 0x3B, 0xEA, 0x63, 0xB6, 0x7F, 0x04, 0x06, 0x00, 0x06, 0x80, 0x2B, + 0x44, 0x22, 0x55, 0xB8, 0x80, 0xA7, 0xF8, 0x25, 0xF6, 0x86, 0xF7, 0x87, 0xF6, 0x88, 0xF6, 0x89, + 0xF6, 0x8A, 0xEA, 0x23, 0x44, 0x00, 0x00, 0x80, 0xF0, 0x83, 0x44, 0x0F, 0xFF, 0xE7, 0xF0, 0x88, + 0xFA, 0x09, 0xEA, 0x3B, 0xF0, 0x89, 0xEA, 0xF9, 0x80, 0x40, 0xEA, 0x63, 0xB6, 0x7F, 0xEB, 0xFF, + 0x80, 0xA7, 0xF6, 0x81, 0xF6, 0x82, 0xF8, 0x10, 0xF7, 0x86, 0xF6, 0x87, 0xF6, 0x8A, 0x12, 0x6F, + 0x80, 0x1B, 0xEA, 0x23, 0xEA, 0x3B, 0x44, 0x00, 0x04, 0x00, 0xF0, 0x88, 0xB6, 0x7F, 0xEA, 0xF9, + 0xF7, 0x81, 0xF6, 0x82, 0xF6, 0x83, 0xF6, 0x84, 0xF6, 0x85, 0x83, 0xFF, 0xF6, 0x86, 0xF6, 0x87, + 0xF6, 0x89, 0xF7, 0x8A, 0x80, 0x2A, 0x80, 0x4A, 0xEA, 0xBF, 0x80, 0xA7, 0xEA, 0x23, 0x00, 0x04, + 0x80, 0x02, 0x96, 0x70, 0xE2, 0x20, 0xE8, 0x0D, 0x38, 0xF5, 0x99, 0x11, 0x42, 0xF7, 0x80, 0x03, + 0x5E, 0xF7, 0x80, 0x33, 0xE9, 0x04, 0x38, 0x15, 0x19, 0x01, 0xC1, 0x05, 0x8C, 0xC1, 0xD5, 0xF2, + 0x84, 0x00, 0xFC, 0xEF, 0x84, 0x01, 0xFC, 0xEF, 0xDD, 0x9E, 0xFC, 0x6F, 0x50, 0xAF, 0x80, 0x38, + 0x81, 0x21, 0x81, 0x80, 0x81, 0x62, 0x84, 0x20, 0xEB, 0x63, 0x80, 0x0A, 0x84, 0xC0, 0xEA, 0x2F, + 0x84, 0xE1, 0xEA, 0x3B, 0xEA, 0x63, 0xB6, 0x7F, 0x04, 0x06, 0x00, 0x06, 0x80, 0x2B, 0x44, 0x22, + 0x55, 0xB8, 0x80, 0xA7, 0xF8, 0x26, 0xF6, 0x86, 0xF7, 0x87, 0xF6, 0x88, 0xF6, 0x89, 0xF6, 0x8A, + 0xEA, 0x23, 0x44, 0x00, 0x00, 0x80, 0xF0, 0x83, 0x84, 0x16, 0xF0, 0x88, 0x84, 0x0A, 0xEA, 0x3B, + 0xF0, 0x89, 0xEA, 0xF9, 0x80, 0x40, 0xEA, 0x63, 0xB6, 0x7F, 0xEB, 0xFF, 0x80, 0xA7, 0xF6, 0x81, + 0xF6, 0x82, 0xF8, 0x12, 0xF7, 0x86, 0xF6, 0x87, 0xF6, 0x8A, 0x12, 0x6F, 0x80, 0x1B, 0xEA, 0x23, + 0xEA, 0x3B, 0x44, 0x00, 0x04, 0x00, 0xF0, 0x88, 0x80, 0x4A, 0xEA, 0xF9, 0xEA, 0xBF, 0xB6, 0x7F, + 0xF7, 0x81, 0xF6, 0x82, 0xF6, 0x83, 0xF6, 0x84, 0xF6, 0x85, 0x83, 0xFF, 0xF6, 0x86, 0xF6, 0x87, + 0xF6, 0x89, 0xF7, 0x8A, 0x80, 0x2A, 0x80, 0xA7, 0xEA, 0x23, 0x00, 0x24, 0x80, 0x02, 0x80, 0x06, + 0x80, 0x86, 0x96, 0x70, 0xE2, 0x22, 0xE8, 0x13, 0x38, 0x15, 0x19, 0x01, 0xE6, 0x24, 0xE8, 0x0D, + 0x38, 0x35, 0x99, 0x01, 0x50, 0x11, 0x81, 0x2B, 0x96, 0x49, 0x5C, 0xF0, 0x82, 0x57, 0xE8, 0x05, + 0x8C, 0x81, 0x88, 0x60, 0x97, 0x20, 0x96, 0x1B, 0x8C, 0xC1, 0xD5, 0xEC, 0xC4, 0x03, 0x40, 0x00, + 0x10, 0x16, 0xFC, 0xEF, 0xFC, 0x77, 0x50, 0xBF, 0x80, 0x38, 0x81, 0x20, 0xEB, 0x63, 0x81, 0x81, + 0x80, 0x0B, 0x84, 0x20, 0x50, 0xAF, 0x80, 0x78, 0x80, 0xE3, 0xEA, 0x2F, 0x84, 0x20, 0xEB, 0x63, + 0x80, 0x0A, 0xEA, 0x2F, 0x44, 0x00, 0x10, 0x00, 0x84, 0xC0, 0x84, 0xA1, 0xA6, 0xFA, 0xF0, 0x88, + 0x44, 0x0F, 0xF0, 0x00, 0xF0, 0x89, 0x80, 0x2B, 0x80, 0x4B, 0xB6, 0x7F, 0xF5, 0x81, 0xF6, 0x82, + 0xF6, 0x83, 0xF6, 0x84, 0xF6, 0x85, 0xF6, 0x86, 0xF6, 0x87, 0xF5, 0x8A, 0x04, 0x04, 0x80, 0x06, + 0xEA, 0xBF, 0xEA, 0x23, 0xA6, 0x7A, 0x44, 0x20, 0x00, 0x32, 0x96, 0x30, 0xE2, 0x01, 0xE8, 0x08, + 0x38, 0x05, 0x99, 0x11, 0xEA, 0xC9, 0x38, 0x05, 0x19, 0x09, 0x8C, 0xC1, 0xD5, 0xF7, 0x80, 0x09, + 0x80, 0x27, 0x80, 0x4A, 0x49, 0xFF, 0xFF, 0x04, 0x5A, 0x08, 0x01, 0x09, 0x44, 0x10, 0x00, 0x3C, + 0x3E, 0x17, 0xEF, 0x07, 0x3E, 0x07, 0xF2, 0xE5, 0xD5, 0x0A, 0x2E, 0x37, 0xEF, 0x07, 0xC3, 0x05, + 0x8E, 0x61, 0x3E, 0x37, 0xEF, 0x07, 0xD5, 0x03, 0x3E, 0x37, 0xF2, 0xE5, 0x80, 0x27, 0x80, 0x4A, + 0x80, 0x09, 0x49, 0xFF, 0xFF, 0x4C, 0xF0, 0x8D, 0x80, 0x2C, 0x80, 0x09, 0x80, 0x47, 0xF3, 0x0D, + 0x84, 0x84, 0x49, 0xFF, 0xFE, 0x26, 0x80, 0x0C, 0x49, 0xFF, 0xFE, 0x9F, 0x2E, 0x07, 0xEE, 0xC0, + 0x5A, 0x08, 0x01, 0x07, 0x22, 0x16, 0x00, 0x03, 0x44, 0x03, 0x95, 0xB4, 0xAC, 0x40, 0xFC, 0xF7, + 0xFC, 0x60, 0x84, 0xC0, 0xB6, 0xC3, 0x3D, 0x1D, 0xFC, 0x0B, 0x3D, 0x20, 0x06, 0x2A, 0x86, 0x81, + 0x45, 0x30, 0x00, 0x54, 0xFB, 0x29, 0x44, 0xA0, 0x01, 0xA1, 0x44, 0xB0, 0x01, 0xA6, 0x44, 0xC0, + 0x00, 0x64, 0x2E, 0x47, 0x33, 0x91, 0xE2, 0xC4, 0x4E, 0xF2, 0x00, 0x81, 0x82, 0x00, 0x43, 0x03, + 0x4C, 0x73, 0xB4, 0x90, 0x8E, 0x81, 0xE6, 0x83, 0xE8, 0x75, 0xB4, 0x91, 0x02, 0xE8, 0x00, 0x23, + 0x42, 0x42, 0x48, 0x0B, 0x5A, 0x40, 0x01, 0x09, 0x40, 0x87, 0x04, 0x09, 0x50, 0x44, 0x7F, 0xF6, + 0x40, 0x82, 0x00, 0x13, 0xD5, 0x02, 0x81, 0x12, 0x04, 0x58, 0x00, 0x08, 0xA1, 0x0D, 0x40, 0x42, + 0x14, 0x40, 0x01, 0x52, 0x00, 0x02, 0x01, 0x62, 0x00, 0x03, 0x81, 0xB5, 0x84, 0xE0, 0x40, 0xFB, + 0x34, 0x06, 0xA7, 0x60, 0x01, 0x72, 0x00, 0x01, 0xE9, 0x1A, 0x41, 0xC6, 0x94, 0x08, 0x87, 0x00, + 0x40, 0xFB, 0x94, 0x06, 0xE9, 0x0C, 0x40, 0xFE, 0x14, 0x00, 0x39, 0x91, 0x3D, 0x11, 0xE1, 0x19, + 0xE8, 0x03, 0x41, 0x8C, 0x64, 0x00, 0x8C, 0xA1, 0x97, 0x68, 0xD5, 0xF3, 0xE2, 0xF8, 0x50, 0x56, + 0x80, 0x01, 0x40, 0x7C, 0x3C, 0x1B, 0x54, 0xD2, 0x80, 0xFF, 0xD5, 0xE2, 0x84, 0x80, 0x40, 0xFB, + 0x94, 0x06, 0xE9, 0x19, 0x81, 0xB5, 0x87, 0x00, 0x40, 0xFB, 0x34, 0x06, 0xE9, 0x0E, 0x40, 0xF2, + 0xB4, 0xA0, 0x39, 0x91, 0x3D, 0x11, 0xE1, 0x19, 0xE8, 0x03, 0x41, 0x8C, 0x64, 0x00, 0x50, 0xD6, + 0x80, 0x01, 0x54, 0xD6, 0x80, 0xFF, 0xD5, 0xF1, 0xE2, 0x98, 0x8C, 0xA1, 0x40, 0x4C, 0x3C, 0x1B, + 0x97, 0x68, 0xD5, 0xE6, 0x4E, 0xE2, 0x00, 0x13, 0x42, 0x42, 0x28, 0x24, 0x42, 0x73, 0xAC, 0x24, + 0xE2, 0x87, 0x40, 0x72, 0x3C, 0x1A, 0x40, 0x43, 0xB8, 0x3C, 0x40, 0x42, 0x38, 0x97, 0x50, 0x42, + 0x00, 0x32, 0x40, 0x42, 0x30, 0x97, 0x41, 0x42, 0x00, 0x13, 0x04, 0x48, 0x00, 0x0A, 0xB4, 0xA3, + 0x43, 0x4A, 0x24, 0x01, 0xE2, 0x85, 0x13, 0x48, 0x00, 0x0C, 0x13, 0x48, 0x00, 0x0D, 0xE9, 0x02, + 0xB6, 0x83, 0x8C, 0xC1, 0x97, 0xB0, 0x48, 0xFF, 0xFF, 0x7E, 0xFC, 0xE0, 0x44, 0x03, 0x95, 0xB7, + 0xA6, 0x40, 0x44, 0x03, 0x95, 0xB6, 0xA6, 0x00, 0x40, 0x00, 0x05, 0x04, 0xDD, 0x9E, 0x44, 0x03, + 0x95, 0xB9, 0xA6, 0x00, 0x44, 0x13, 0x95, 0xB8, 0xA6, 0x48, 0x40, 0x00, 0x81, 0x04, 0x44, 0x1F, + 0x6A, 0x44, 0x88, 0x20, 0x5C, 0xF0, 0x80, 0x5A, 0xE9, 0x03, 0x44, 0x00, 0x95, 0xBC, 0xDD, 0x9E, + 0x44, 0x03, 0x95, 0xB4, 0xA6, 0x00, 0xEA, 0xEB, 0xDD, 0x9E, 0x44, 0x03, 0x95, 0xB4, 0xA6, 0x00, + 0xEB, 0x79, 0xDD, 0x9E, 0x44, 0x03, 0x95, 0xB5, 0xA6, 0x00, 0xDD, 0x9E, 0x44, 0x13, 0x95, 0xBA, + 0xA6, 0x08, 0x96, 0x00, 0xC0, 0x0E, 0xA6, 0x08, 0x96, 0x00, 0x5A, 0x00, 0x01, 0x0B, 0xA6, 0x08, + 0x96, 0x00, 0x5A, 0x00, 0x02, 0x07, 0xA6, 0x08, 0x96, 0x00, 0x5A, 0x00, 0x03, 0x03, 0x84, 0x00, + 0xDD, 0x9E, 0x96, 0x00, 0x44, 0x13, 0x95, 0xBB, 0xAE, 0x08, 0xDD, 0x9E, 0xFC, 0x00, 0x44, 0x63, + 0x95, 0xB4, 0xAE, 0x70, 0x44, 0x12, 0xDE, 0x4C, 0xB6, 0x01, 0x84, 0x01, 0xA9, 0x89, 0x10, 0x20, + 0x80, 0x09, 0x10, 0x00, 0x80, 0x08, 0x10, 0x30, 0x80, 0x0A, 0x10, 0x00, 0x80, 0x0B, 0x80, 0x01, + 0x80, 0x24, 0x49, 0x00, 0x53, 0x1A, 0xA6, 0x30, 0xFC, 0x80, 0xFC, 0x00, 0x84, 0x41, 0x44, 0x00, + 0xB1, 0x00, 0x84, 0x20, 0x80, 0x62, 0x80, 0x82, 0xEA, 0xA7, 0x84, 0x00, 0x3C, 0x0F, 0xFC, 0x68, + 0x3E, 0x07, 0xF2, 0xD6, 0xFC, 0x80, 0xFC, 0x40, 0x2E, 0x07, 0x33, 0x8A, 0x2E, 0x27, 0x33, 0xBA, + 0x2E, 0x37, 0x33, 0x8B, 0x42, 0x10, 0x08, 0x24, 0x3C, 0x1B, 0x99, 0xCD, 0x2E, 0x17, 0x33, 0xBB, + 0x92, 0x41, 0x42, 0x41, 0x84, 0x24, 0xFE, 0x1C, 0x92, 0x21, 0x3E, 0x27, 0x33, 0xC1, 0x3C, 0x4B, + 0x99, 0xCE, 0x3C, 0x0B, 0x99, 0xDE, 0x3E, 0x17, 0x33, 0xC2, 0x44, 0x02, 0xFE, 0x85, 0xA6, 0x40, + 0x84, 0x21, 0x84, 0xC0, 0xAE, 0x40, 0xA6, 0x41, 0xAF, 0x81, 0x3C, 0x6F, 0xFC, 0x0E, 0xEB, 0x18, + 0x50, 0x00, 0x00, 0x20, 0x49, 0x00, 0x59, 0xA3, 0xEA, 0xB5, 0x3C, 0x0F, 0xFC, 0x2B, 0x49, 0xFF, + 0xEE, 0x7D, 0x44, 0x13, 0x8D, 0x36, 0x44, 0x02, 0xFE, 0x5C, 0x44, 0x23, 0x8D, 0x34, 0xB6, 0xC0, + 0xAD, 0x90, 0xAD, 0x88, 0x3C, 0x1F, 0xFC, 0x1E, 0x44, 0x13, 0x8D, 0x30, 0x3C, 0x1F, 0xFC, 0x3F, + 0x44, 0x13, 0x8D, 0x31, 0x3C, 0x1F, 0xFC, 0x25, 0x44, 0x13, 0x8D, 0x32, 0x3C, 0x1F, 0xFC, 0x04, + 0x2E, 0x17, 0x34, 0x13, 0x3C, 0x0F, 0xFC, 0x0B, 0x3C, 0x2F, 0xFC, 0x15, 0x3E, 0x67, 0xEF, 0x09, + 0x5A, 0x18, 0x01, 0x07, 0xB4, 0x20, 0x42, 0x10, 0xF0, 0x08, 0xB6, 0x20, 0xD5, 0x05, 0xB4, 0x20, + 0x42, 0x10, 0xF0, 0x09, 0xB6, 0x20, 0xB4, 0x20, 0x84, 0xC0, 0x42, 0x10, 0xF4, 0x08, 0xB6, 0x20, + 0xB4, 0x20, 0x85, 0x21, 0x42, 0x10, 0xC8, 0x09, 0xB6, 0x20, 0xB4, 0x20, 0x85, 0x40, 0x42, 0x10, + 0xF8, 0x09, 0xB6, 0x20, 0xB4, 0x20, 0x84, 0xE0, 0x42, 0x10, 0xD4, 0x08, 0xB6, 0x20, 0xB4, 0x20, + 0x42, 0x10, 0xDC, 0x09, 0xB6, 0x20, 0xB4, 0x20, 0x42, 0x10, 0xD8, 0x09, 0xB6, 0x20, 0xB4, 0x00, + 0x3C, 0x0F, 0xFC, 0x42, 0x44, 0x03, 0x8D, 0x36, 0xA6, 0x40, 0xEB, 0xA0, 0xAE, 0x40, 0xA6, 0x40, + 0x66, 0x10, 0x80, 0x01, 0xAE, 0x40, 0xA6, 0x40, 0x66, 0x10, 0x80, 0x04, 0xAE, 0x40, 0xA6, 0x40, + 0x66, 0x10, 0x80, 0x08, 0xAE, 0x40, 0xA6, 0x40, 0x44, 0x03, 0x8D, 0x34, 0xAE, 0x40, 0x3E, 0x67, + 0xEF, 0x4E, 0x3E, 0x67, 0xEF, 0x34, 0x3C, 0x9F, 0xFC, 0xD7, 0x3C, 0xAB, 0xF7, 0xD3, 0x3E, 0xA7, + 0xEF, 0x5C, 0x3E, 0x67, 0xEF, 0x44, 0x3E, 0x67, 0xEE, 0xFA, 0x3E, 0x67, 0xF3, 0x7B, 0x3E, 0x67, + 0xEE, 0xB0, 0x2E, 0x07, 0x34, 0x18, 0x3E, 0x07, 0xEE, 0xE5, 0xEA, 0x34, 0x3E, 0x07, 0xEE, 0xEF, + 0xEA, 0x40, 0x3E, 0x07, 0xEE, 0xF8, 0xEA, 0x97, 0xEB, 0x1E, 0x3C, 0xAB, 0xF7, 0xC7, 0x3C, 0xAB, + 0xF7, 0xD7, 0x3E, 0x97, 0xEF, 0x2F, 0x3E, 0x97, 0xEE, 0xC6, 0x49, 0xFF, 0xF1, 0x08, 0xDD, 0x41, + 0x3E, 0x67, 0xEF, 0x76, 0x3C, 0xAB, 0xF7, 0xCA, 0x3E, 0x67, 0xEF, 0x77, 0xAF, 0x81, 0x3E, 0x67, + 0xEE, 0xC3, 0x3E, 0x97, 0xEF, 0x24, 0x3E, 0x67, 0xEE, 0xC0, 0xAF, 0x80, 0xDD, 0x51, 0x84, 0x02, + 0x3E, 0x67, 0xEE, 0xB3, 0x3C, 0x9E, 0x02, 0x04, 0x3E, 0x67, 0xEE, 0xFD, 0xEB, 0x54, 0x3E, 0x67, + 0xEE, 0xD1, 0x3E, 0x67, 0xF3, 0x71, 0xAE, 0x08, 0xDD, 0x50, 0xAE, 0x08, 0xEA, 0xAF, 0x44, 0x00, + 0x00, 0x8C, 0x3C, 0x08, 0x06, 0x2A, 0x3C, 0x08, 0x06, 0x2E, 0x44, 0x02, 0xDD, 0x78, 0x3C, 0x0E, + 0x03, 0x16, 0x44, 0x02, 0xDA, 0xD8, 0x3C, 0x0F, 0xFC, 0x33, 0x84, 0x0A, 0x3E, 0x07, 0xF0, 0x98, + 0x3E, 0x67, 0xEE, 0xD3, 0x3C, 0x7F, 0xFC, 0x20, 0x3E, 0x97, 0xEF, 0x10, 0x3C, 0x7B, 0xF7, 0xE6, + 0x3C, 0xAB, 0xF7, 0xDE, 0x3E, 0x67, 0xEE, 0xC1, 0x3E, 0x67, 0xF0, 0xC8, 0x3E, 0x67, 0xF0, 0x99, + 0x3E, 0x67, 0xF0, 0x9A, 0x2E, 0x07, 0x33, 0x8B, 0x3E, 0x07, 0x34, 0xA5, 0x80, 0x07, 0x3E, 0x67, + 0xF2, 0xE5, 0x3C, 0x7F, 0xFC, 0x4E, 0x3C, 0x7F, 0xFC, 0x40, 0x3C, 0x7F, 0xFC, 0x30, 0x3C, 0x7F, + 0xFC, 0x12, 0x3C, 0x7F, 0xFC, 0x35, 0x3C, 0x7F, 0xFC, 0x11, 0x3C, 0x7F, 0xFC, 0x53, 0x3C, 0x7F, + 0xFC, 0x36, 0x3C, 0x7F, 0xFB, 0xFC, 0x3C, 0x7F, 0xFC, 0x05, 0xF8, 0x02, 0x80, 0x09, 0x49, 0x00, + 0x84, 0x6C, 0x80, 0x07, 0xF8, 0x20, 0x3C, 0x0E, 0x02, 0x8D, 0x80, 0x09, 0xF8, 0x1C, 0x3C, 0x0E, + 0x02, 0x8E, 0x84, 0x02, 0xF8, 0x18, 0x3C, 0x0E, 0x02, 0x8F, 0x84, 0x03, 0xF8, 0x14, 0x3C, 0x0E, + 0x02, 0x90, 0x84, 0x04, 0xF8, 0x10, 0x3C, 0x0E, 0x02, 0x91, 0x84, 0x05, 0xF8, 0x0C, 0x3C, 0x0E, + 0x02, 0x92, 0x84, 0x06, 0xF8, 0x08, 0x3C, 0x0E, 0x02, 0x93, 0x84, 0x07, 0xF8, 0x04, 0x3C, 0x0E, + 0x02, 0x94, 0x84, 0x08, 0x49, 0x00, 0x84, 0x58, 0x3C, 0x0E, 0x02, 0x95, 0x3C, 0x03, 0x99, 0xCD, + 0x3C, 0x0B, 0x9A, 0xC6, 0x3C, 0x03, 0x99, 0xCE, 0x3C, 0x0B, 0x9A, 0xDD, 0x3C, 0x03, 0x9A, 0xC9, + 0x3C, 0x13, 0x9A, 0xC8, 0xEB, 0x72, 0x3C, 0x0B, 0x9A, 0xCA, 0x3C, 0x03, 0x9A, 0xE0, 0x3C, 0x13, + 0x9A, 0xDF, 0xEB, 0x72, 0x3C, 0x7F, 0xFC, 0xDB, 0x3C, 0x0B, 0x9A, 0xE1, 0x3E, 0x67, 0xF3, 0x68, + 0x49, 0x00, 0x7A, 0x0F, 0x3C, 0x0F, 0xFC, 0x47, 0x49, 0x00, 0x79, 0xE4, 0xEA, 0xCB, 0x3C, 0x0E, + 0x03, 0x6B, 0x44, 0x02, 0xDA, 0xE8, 0x3C, 0x0E, 0x03, 0x6E, 0x44, 0x02, 0xBD, 0x94, 0x3E, 0x67, + 0xF1, 0x21, 0x3E, 0x67, 0xF1, 0x20, 0x3E, 0x67, 0xF1, 0x22, 0x3E, 0x60, 0x0D, 0xA8, 0x3C, 0x7E, + 0x03, 0x6C, 0x3E, 0x60, 0x0D, 0xB4, 0x3C, 0x0F, 0xFC, 0x4F, 0x84, 0x5F, 0x3C, 0x0D, 0xFC, 0x47, + 0x84, 0x3F, 0x38, 0x20, 0x1C, 0x08, 0x8C, 0xE6, 0x5A, 0x78, 0x3C, 0xFA, 0x3C, 0x0D, 0xFC, 0x47, + 0x84, 0x5F, 0x10, 0x10, 0x00, 0x3C, 0x10, 0x10, 0x00, 0x3D, 0x84, 0x00, 0xEA, 0x33, 0xEA, 0xE1, + 0x3E, 0x07, 0xF3, 0x75, 0x3E, 0x07, 0xF3, 0x74, 0x3E, 0x07, 0xF3, 0x76, 0x3E, 0x07, 0xF3, 0x77, + 0x3E, 0x07, 0xF0, 0x08, 0x3E, 0x07, 0xF0, 0x0A, 0x3E, 0x07, 0xF0, 0x09, 0x44, 0x12, 0xD4, 0xBC, + 0x38, 0x20, 0x81, 0x09, 0x8C, 0x01, 0x5A, 0x08, 0x14, 0xFD, 0x84, 0xC0, 0xEA, 0xD0, 0x3E, 0x07, + 0xEF, 0x29, 0x3E, 0x67, 0xEF, 0x33, 0x3E, 0x67, 0xEF, 0x51, 0x3E, 0x67, 0xEE, 0xF0, 0x3E, 0x67, + 0xEF, 0x27, 0x3E, 0x67, 0xEF, 0x0E, 0x3E, 0x67, 0xEF, 0x2D, 0x3E, 0x67, 0xEE, 0xBA, 0x3E, 0x67, + 0xEF, 0x04, 0x3E, 0x67, 0xEF, 0x4F, 0x3E, 0x67, 0xEF, 0x20, 0x3E, 0x67, 0xEE, 0xCB, 0x3E, 0x67, + 0xEE, 0xCA, 0x3E, 0x67, 0xEF, 0x49, 0x3E, 0x67, 0xEF, 0x5B, 0x3E, 0x67, 0xEE, 0xE0, 0x3E, 0x67, + 0xEE, 0xFB, 0x3E, 0x67, 0xF3, 0x7A, 0x49, 0x00, 0x36, 0xB3, 0x3E, 0x67, 0xEE, 0xDB, 0x3E, 0x67, + 0xEF, 0x0C, 0x3E, 0x67, 0xEE, 0xDF, 0x3E, 0x67, 0xEF, 0x43, 0xEB, 0x18, 0x49, 0x00, 0x57, 0x71, + 0xDD, 0x54, 0xAF, 0x80, 0x84, 0x00, 0xEA, 0x49, 0xEA, 0x2E, 0x5A, 0x08, 0x01, 0x04, 0x49, 0x00, + 0x5D, 0x41, 0x84, 0x01, 0xEB, 0xCB, 0xEB, 0x0D, 0xEA, 0x24, 0x49, 0x00, 0x05, 0xD7, 0x84, 0xC1, + 0x49, 0x00, 0x05, 0xCD, 0x84, 0x40, 0xEB, 0xBC, 0xAE, 0x80, 0x3C, 0x6F, 0xFC, 0x03, 0xDD, 0x52, + 0xEA, 0xD8, 0x84, 0x0A, 0xEB, 0x9C, 0x84, 0x09, 0xEA, 0x60, 0x44, 0x07, 0x5F, 0xD6, 0x3C, 0x0F, + 0xFC, 0x56, 0x44, 0x05, 0x5D, 0x46, 0x3C, 0x0F, 0xFC, 0x4A, 0x44, 0x00, 0xBC, 0x2E, 0x84, 0x20, + 0x3C, 0x0F, 0xFC, 0x49, 0x44, 0x02, 0xBE, 0xBE, 0x3E, 0x27, 0xEF, 0x59, 0x3E, 0x27, 0xEE, 0xBC, + 0x3C, 0x1F, 0xFC, 0x55, 0x3E, 0x17, 0xEF, 0x4B, 0x3E, 0x10, 0x0F, 0x48, 0x3E, 0x27, 0xEE, 0xD2, + 0x3E, 0x10, 0x0F, 0x49, 0x3C, 0x0F, 0xFC, 0x4D, 0x3C, 0x1E, 0x03, 0xD1, 0x3C, 0x1F, 0xFC, 0x2A, + 0x3E, 0x10, 0x11, 0xB0, 0x3C, 0x1F, 0xFC, 0x14, 0x3E, 0x10, 0x11, 0xB1, 0x3C, 0x6F, 0xFC, 0x3C, + 0x3C, 0x1E, 0x04, 0x6B, 0x3C, 0x6F, 0xFC, 0x1A, 0x3E, 0x27, 0xEE, 0xC5, 0x3C, 0x1B, 0xF7, 0xCE, + 0xDD, 0x40, 0xC8, 0x05, 0x80, 0x06, 0x84, 0x26, 0x49, 0xFF, 0xEA, 0xEE, 0x84, 0x0D, 0x84, 0xC0, + 0x84, 0xE5, 0x3C, 0x0E, 0x03, 0xD9, 0x84, 0x01, 0x3C, 0x6B, 0xF7, 0xD0, 0x3E, 0x67, 0xEF, 0x12, + 0x3E, 0x67, 0xEF, 0x40, 0x3C, 0x7E, 0x03, 0xDA, 0x3E, 0x67, 0xEE, 0xE7, 0x3E, 0x67, 0xEF, 0xE8, + 0x3E, 0x07, 0xEF, 0xE9, 0x3E, 0x07, 0xEF, 0xEA, 0x3E, 0x07, 0xEF, 0xEB, 0x3E, 0x07, 0xEF, 0xEC, + 0x3E, 0x67, 0xEF, 0xED, 0x49, 0x00, 0x23, 0xAB, 0xEA, 0x47, 0xEA, 0x98, 0x44, 0x02, 0xFE, 0xFC, + 0x3E, 0x60, 0x0F, 0xD1, 0x3E, 0x67, 0xEE, 0xE4, 0xAF, 0x80, 0x44, 0x02, 0xFE, 0xFD, 0xAF, 0x80, + 0x49, 0x00, 0x12, 0x7D, 0x44, 0x03, 0x8D, 0x42, 0x3C, 0x6B, 0xF7, 0xC4, 0x3E, 0x67, 0xEF, 0x21, + 0x3C, 0x6B, 0xF7, 0xC8, 0x3E, 0x67, 0xEF, 0x61, 0x3C, 0x6B, 0xF7, 0xC0, 0x84, 0x20, 0xAF, 0x80, + 0x84, 0x46, 0x44, 0x02, 0xBC, 0x6C, 0xEA, 0x2F, 0x84, 0x20, 0x84, 0x46, 0x44, 0x02, 0xBD, 0x14, + 0xEA, 0x2F, 0x44, 0x02, 0x49, 0x60, 0x3C, 0x0F, 0xFC, 0x29, 0x44, 0x00, 0xA0, 0x28, 0x3C, 0x0F, + 0xFB, 0xF9, 0x44, 0x04, 0x01, 0x00, 0x3C, 0x0F, 0xFC, 0x3D, 0x84, 0x1E, 0x3E, 0x07, 0xEE, 0xCC, + 0x84, 0x1E, 0x3E, 0x67, 0xEE, 0xDC, 0x3E, 0x67, 0xEF, 0x2A, 0x3E, 0x67, 0xEF, 0x1B, 0x3E, 0x67, + 0xEF, 0x35, 0x3C, 0x0B, 0xF8, 0x8C, 0x3C, 0x0B, 0xF8, 0x8D, 0x3E, 0x67, 0xEF, 0x4D, 0x49, 0x00, + 0x4A, 0x6F, 0x3E, 0x77, 0xEE, 0xBB, 0x3E, 0x67, 0xEE, 0xD7, 0x3E, 0x67, 0xEA, 0xE0, 0x3C, 0x6B, + 0xF9, 0x56, 0x3E, 0x67, 0xF2, 0xB0, 0x44, 0x03, 0x90, 0xE5, 0x84, 0x41, 0xA6, 0x40, 0xAE, 0x80, + 0x84, 0x20, 0xA6, 0xC1, 0xAE, 0x41, 0x44, 0x03, 0x90, 0xE9, 0xA6, 0xC0, 0xAE, 0x80, 0xA6, 0x81, + 0xAE, 0x41, 0x44, 0x03, 0x94, 0x70, 0x3C, 0x0F, 0xFC, 0x41, 0xAC, 0x40, 0x3E, 0x67, 0xF2, 0x90, + 0x3E, 0x67, 0xF3, 0x04, 0x3C, 0x6B, 0xF7, 0xC6, 0xFC, 0xC0, 0xFC, 0x21, 0x44, 0x62, 0x00, 0xA0, + 0x80, 0x06, 0x49, 0x00, 0x55, 0x67, 0xEA, 0x35, 0xF0, 0x81, 0x49, 0xFF, 0xF9, 0xE3, 0x9C, 0x34, + 0x49, 0xFF, 0xF9, 0xE3, 0x50, 0x03, 0x00, 0x78, 0x49, 0xFF, 0xF8, 0x27, 0x50, 0x03, 0x00, 0xA8, + 0x49, 0xFF, 0xF9, 0xDE, 0x50, 0x03, 0x00, 0xC0, 0x49, 0x00, 0x82, 0xB9, 0xEA, 0x35, 0xF0, 0x81, + 0x49, 0x00, 0x82, 0xB8, 0x50, 0x03, 0x00, 0xB0, 0x49, 0x00, 0x1C, 0xA2, 0xEA, 0x35, 0xF0, 0x81, + 0x49, 0x00, 0x1C, 0xA1, 0xEA, 0x35, 0xF0, 0x81, 0x49, 0x00, 0x3C, 0x4F, 0x50, 0x03, 0x01, 0x0C, + 0x49, 0x00, 0x00, 0xF4, 0xEA, 0x35, 0xF0, 0x81, 0x49, 0x00, 0x00, 0xF3, 0x49, 0x00, 0x01, 0x0F, + 0x50, 0x03, 0x01, 0x20, 0x49, 0x00, 0x35, 0xDA, 0x50, 0x73, 0x02, 0x54, 0xEA, 0x35, 0xF0, 0x81, + 0x49, 0x00, 0x35, 0xD7, 0x80, 0x07, 0x49, 0x00, 0x35, 0xD7, 0xEA, 0x35, 0xF0, 0x81, 0x49, 0x00, + 0x6E, 0x83, 0x50, 0x03, 0x01, 0x64, 0x49, 0x00, 0x6F, 0x64, 0x50, 0x03, 0x01, 0xC4, 0x49, 0x00, + 0x7C, 0xAC, 0xEA, 0x35, 0xF0, 0x81, 0x49, 0x00, 0x7C, 0xAB, 0x50, 0x03, 0x02, 0x10, 0x49, 0x00, + 0x81, 0x7D, 0xEA, 0x35, 0xF0, 0x81, 0x49, 0x00, 0x81, 0x7C, 0x50, 0x03, 0x02, 0x20, 0x49, 0x00, + 0x70, 0x44, 0xEA, 0x35, 0xF0, 0x81, 0x49, 0x00, 0x70, 0x43, 0xEA, 0x35, 0xF0, 0x81, 0x49, 0x00, + 0x26, 0x49, 0x80, 0x07, 0x49, 0x00, 0x78, 0x28, 0xEA, 0x35, 0xF0, 0x81, 0x49, 0x00, 0x78, 0x27, + 0x50, 0x03, 0x02, 0x60, 0x49, 0x00, 0x42, 0x8A, 0xEA, 0x35, 0xF0, 0x81, 0x49, 0x00, 0x42, 0x83, + 0xEB, 0x50, 0x49, 0x00, 0x44, 0x5F, 0x50, 0x03, 0x02, 0x84, 0x49, 0xFF, 0xDF, 0xE7, 0xEA, 0x35, + 0xF0, 0x81, 0x49, 0xFF, 0xDF, 0xE6, 0x50, 0x03, 0x00, 0x48, 0x49, 0x00, 0x5E, 0xD7, 0xEA, 0x35, + 0xF0, 0x81, 0x49, 0x00, 0x0C, 0xDE, 0xEA, 0x35, 0xF0, 0x81, 0x49, 0x00, 0x35, 0x3E, 0x49, 0xFF, + 0xFB, 0x05, 0x49, 0x00, 0x2F, 0x3F, 0x49, 0x00, 0x26, 0x20, 0xFC, 0xA1, 0xFC, 0x00, 0xDD, 0x51, + 0x84, 0x02, 0x84, 0xC0, 0x3C, 0x6F, 0xFC, 0xD8, 0xAE, 0x08, 0xDD, 0x50, 0xAE, 0x08, 0x44, 0x00, + 0x00, 0xA2, 0xEB, 0x98, 0xDD, 0x41, 0xA6, 0x01, 0x5A, 0x08, 0x0D, 0x12, 0x80, 0x06, 0x84, 0x7F, + 0x3C, 0x2D, 0xFC, 0x47, 0x84, 0x3F, 0x38, 0x31, 0x00, 0x08, 0x8C, 0x06, 0x5A, 0x08, 0x3C, 0xFA, + 0x3C, 0x0D, 0xFC, 0x47, 0x10, 0x10, 0x00, 0x3C, 0x10, 0x10, 0x00, 0x3D, 0x49, 0x00, 0x00, 0x74, + 0xEB, 0x92, 0xEA, 0xD0, 0x84, 0xC0, 0xEB, 0x33, 0x3E, 0x67, 0xEE, 0xB0, 0x49, 0x00, 0x04, 0x33, + 0x84, 0x01, 0xEA, 0x78, 0x3E, 0x07, 0xEF, 0x17, 0xEA, 0x2A, 0x3E, 0x07, 0xF3, 0x52, 0x84, 0x1F, + 0x3C, 0x0B, 0xF7, 0xD5, 0xEA, 0x2E, 0x3E, 0x67, 0xEF, 0x28, 0x3E, 0x67, 0xEF, 0x02, 0x3E, 0x67, + 0xEE, 0xE6, 0x3E, 0x67, 0xEF, 0x48, 0x3E, 0x67, 0xEF, 0x7C, 0x3E, 0x67, 0xEF, 0x5E, 0x5A, 0x08, + 0x01, 0x03, 0xEA, 0x6F, 0xFC, 0x80, 0xFC, 0x45, 0x44, 0x01, 0x68, 0x34, 0xEB, 0x38, 0x50, 0x9F, + 0x80, 0x08, 0x44, 0x01, 0x68, 0x44, 0x3B, 0x04, 0xCC, 0x20, 0xEB, 0x38, 0xEA, 0x2E, 0xB1, 0xC6, + 0x3B, 0x03, 0xCC, 0x20, 0x5A, 0x08, 0x01, 0x2B, 0x2E, 0x67, 0xF3, 0x02, 0xCE, 0x19, 0xEB, 0x82, + 0x38, 0x13, 0x9A, 0x02, 0x8C, 0xC1, 0xDD, 0x5D, 0x5A, 0x68, 0x04, 0xFB, 0xDD, 0x54, 0xA6, 0x00, + 0x49, 0x00, 0x05, 0x75, 0x5A, 0x08, 0x01, 0x09, 0x2E, 0x07, 0xEF, 0x24, 0x5A, 0x08, 0x01, 0x05, + 0xEB, 0xD4, 0x84, 0x02, 0xFC, 0xC5, 0x84, 0x01, 0x3E, 0x07, 0xEE, 0xF9, 0xD5, 0x0F, 0x2E, 0x07, + 0xEE, 0xF9, 0xC8, 0x0C, 0x44, 0x63, 0x8D, 0x41, 0xA6, 0x30, 0x49, 0x00, 0x05, 0x64, 0xA6, 0x70, + 0x38, 0x04, 0x86, 0x02, 0x38, 0x13, 0x86, 0x02, 0xDD, 0x5D, 0x84, 0x01, 0xEB, 0x0D, 0xEA, 0xC5, + 0xEA, 0x7C, 0xDD, 0x5D, 0x84, 0x00, 0xEA, 0xAB, 0x3C, 0x1C, 0x03, 0x30, 0xEA, 0xCA, 0xFA, 0x50, + 0xEA, 0xF2, 0xEA, 0xFB, 0x84, 0x01, 0xFC, 0xC5, 0x3C, 0x0F, 0xFD, 0x05, 0xDD, 0x9E, 0x3C, 0x0F, + 0xFD, 0x04, 0xDD, 0x9E, 0xFC, 0x00, 0x84, 0x00, 0x84, 0x20, 0x3E, 0x07, 0xF4, 0x0E, 0x3E, 0x07, + 0xF4, 0x0B, 0x3E, 0x07, 0xF4, 0x0A, 0x3C, 0x1B, 0xFA, 0x04, 0x3C, 0x1B, 0xFA, 0x03, 0x3E, 0x17, + 0xF4, 0x0D, 0x3E, 0x07, 0xF4, 0x0C, 0x44, 0x10, 0x00, 0x40, 0x84, 0x00, 0x3E, 0x17, 0xEB, 0x22, + 0x3E, 0x17, 0xEB, 0x21, 0x3C, 0x0F, 0xFD, 0x06, 0xFC, 0x80, 0x3C, 0x0D, 0xFD, 0x05, 0xA4, 0x41, + 0x3C, 0x1B, 0xFA, 0x02, 0xA4, 0x44, 0xA6, 0x00, 0x3C, 0x1B, 0xFA, 0x01, 0x3E, 0x07, 0xF4, 0x00, + 0xDD, 0x9E, 0x3C, 0x43, 0xFA, 0x02, 0x3C, 0x2D, 0xFD, 0x05, 0x3C, 0x33, 0xFA, 0x01, 0xC0, 0x09, + 0xE6, 0x8F, 0xE9, 0x03, 0x8E, 0x85, 0xAD, 0x11, 0xE6, 0x6F, 0xE9, 0x05, 0x8E, 0x65, 0xD5, 0x02, + 0xAD, 0x11, 0xAC, 0xD4, 0xA6, 0x09, 0x5A, 0x08, 0x06, 0x04, 0x84, 0x01, 0xD5, 0x03, 0x2E, 0x07, + 0xF4, 0x00, 0xAE, 0x10, 0xDD, 0x9E, 0xFC, 0x60, 0x3C, 0x4D, 0xFD, 0x04, 0x85, 0x20, 0x00, 0xA2, + 0x00, 0x02, 0x00, 0xB2, 0x00, 0x03, 0x3D, 0x0D, 0xFD, 0x05, 0x40, 0xD5, 0x04, 0x08, 0x81, 0x00, + 0x80, 0xC9, 0x80, 0x89, 0x81, 0x89, 0x82, 0x49, 0x82, 0x69, 0x80, 0xA9, 0x4C, 0x55, 0x80, 0x35, + 0x80, 0xE8, 0x86, 0x20, 0x40, 0xE2, 0x80, 0x10, 0x4D, 0x15, 0x00, 0x2B, 0xEB, 0xF6, 0xEA, 0xE4, + 0xE1, 0x2F, 0xE8, 0x07, 0xA5, 0x38, 0x80, 0xCE, 0x40, 0x92, 0x00, 0x11, 0x40, 0x48, 0x80, 0x10, + 0xEB, 0xF6, 0x03, 0x48, 0x00, 0x02, 0xEA, 0xE4, 0x40, 0xFA, 0x3C, 0x07, 0xE9, 0x11, 0xEB, 0xF6, + 0x03, 0x48, 0x00, 0x01, 0xEA, 0xE4, 0x40, 0xFA, 0x3C, 0x07, 0xE9, 0x0C, 0xEB, 0xF6, 0x23, 0x48, + 0x00, 0x03, 0xEA, 0xE4, 0x40, 0xF7, 0xD0, 0x07, 0xE8, 0x06, 0x85, 0x81, 0xD5, 0x04, 0x86, 0x61, + 0xD5, 0x02, 0x86, 0x41, 0x8D, 0xA1, 0x55, 0x18, 0x80, 0xFF, 0x8C, 0xE2, 0xD5, 0xD6, 0x8C, 0xA1, + 0x97, 0x68, 0x89, 0x0D, 0xD5, 0xCC, 0x02, 0x88, 0x00, 0x01, 0xE1, 0x09, 0xE8, 0x17, 0x2E, 0x5F, + 0xEB, 0x22, 0x5A, 0x58, 0x40, 0x04, 0x48, 0x00, 0x01, 0x8B, 0x9B, 0x65, 0x42, 0x52, 0x80, 0x03, + 0x97, 0x6A, 0xE4, 0xA3, 0x2E, 0x7F, 0xEB, 0x21, 0xE8, 0x07, 0x9B, 0xF7, 0x42, 0x73, 0x80, 0x03, + 0x97, 0xFA, 0xE4, 0xE3, 0xE9, 0x0C, 0x84, 0xA1, 0xD5, 0x08, 0x44, 0x50, 0x00, 0x40, 0x3E, 0x57, + 0xEB, 0x22, 0x3E, 0x57, 0xEB, 0x21, 0x84, 0xA0, 0x3E, 0x57, 0xF4, 0x0D, 0x5B, 0x28, 0x01, 0x55, + 0x86, 0xA0, 0x4E, 0x47, 0x00, 0x05, 0x9F, 0x61, 0x55, 0x52, 0x80, 0xFF, 0x50, 0x55, 0x7F, 0xFF, + 0xE0, 0x85, 0xE8, 0x02, 0x9D, 0x61, 0x54, 0xE2, 0x80, 0xFF, 0x86, 0x20, 0x4E, 0x67, 0x00, 0x05, + 0x9F, 0x71, 0x55, 0x12, 0x80, 0xFF, 0x50, 0x55, 0xFF, 0xFF, 0xE0, 0xC5, 0xE8, 0x02, 0x9D, 0x71, + 0x55, 0x42, 0x80, 0xFF, 0x84, 0xA0, 0x80, 0xE5, 0x40, 0xFA, 0x44, 0x06, 0xE9, 0x1C, 0x43, 0x68, + 0xA8, 0x24, 0x81, 0xB5, 0x41, 0x73, 0xD4, 0x01, 0x40, 0x76, 0xDC, 0x00, 0x40, 0xF7, 0x34, 0x06, + 0x97, 0xF8, 0xE9, 0x0D, 0x40, 0x7B, 0x34, 0x00, 0x40, 0x70, 0x1C, 0x20, 0xA5, 0xF8, 0x88, 0xA7, + 0x50, 0x76, 0x80, 0x01, 0x97, 0x6B, 0x54, 0xD3, 0x80, 0xFF, 0xD5, 0xEF, 0x8D, 0xA1, 0x55, 0x18, + 0x80, 0xFF, 0xD5, 0xE3, 0x42, 0x43, 0x28, 0x73, 0x02, 0x68, 0x00, 0x05, 0x86, 0x29, 0xFF, 0xBC, + 0x40, 0x40, 0x10, 0x20, 0x40, 0xF3, 0x45, 0xF6, 0xA5, 0x20, 0xE0, 0xAF, 0x97, 0x23, 0xE9, 0x0E, + 0x02, 0x68, 0x00, 0x06, 0x8E, 0xE1, 0xFF, 0xBC, 0x8A, 0xA4, 0x40, 0x63, 0x44, 0xD6, 0x97, 0x6B, + 0x40, 0x42, 0x98, 0x07, 0xD5, 0x04, 0x84, 0x80, 0xD5, 0x02, 0x84, 0x81, 0x3C, 0x5D, 0xFD, 0x06, + 0x5A, 0x50, 0x01, 0x33, 0xC5, 0x05, 0x5A, 0x50, 0x02, 0x4F, 0x48, 0x00, 0x00, 0x87, 0x3C, 0x57, + 0xFA, 0x03, 0xE0, 0xA8, 0xE8, 0x03, 0x84, 0xA0, 0xD5, 0x06, 0x02, 0x68, 0x00, 0x02, 0xE0, 0xC5, + 0xE8, 0x04, 0x84, 0xA1, 0x3E, 0x57, 0xF4, 0x0C, 0x2E, 0x57, 0xF4, 0x0C, 0xCD, 0x1B, 0x5B, 0x28, + 0x01, 0x1A, 0x4F, 0x33, 0x00, 0x18, 0x4E, 0xC3, 0x00, 0x16, 0xCC, 0x14, 0x2E, 0x57, 0xF4, 0x0D, + 0x5A, 0x58, 0x01, 0x11, 0x2E, 0x57, 0xF4, 0x0B, 0x00, 0x68, 0x00, 0x00, 0x8C, 0xA1, 0x8C, 0xC1, + 0x97, 0x68, 0x90, 0xC1, 0xE0, 0xC5, 0x3E, 0x57, 0xF4, 0x0B, 0xE8, 0x5F, 0x3D, 0x2F, 0xFD, 0x06, + 0xD5, 0x1B, 0x84, 0x80, 0xD5, 0x19, 0x5B, 0x28, 0x01, 0x1B, 0x4F, 0x33, 0x00, 0x19, 0x4E, 0xC3, + 0x00, 0x17, 0xCC, 0x15, 0x2E, 0x57, 0xF4, 0x0D, 0x5A, 0x58, 0x01, 0x12, 0x2E, 0x57, 0xF4, 0x0B, + 0x00, 0x68, 0x00, 0x00, 0x8C, 0xA1, 0x97, 0x68, 0xE2, 0xC5, 0x3E, 0x57, 0xF4, 0x0B, 0xE8, 0x45, + 0x84, 0xA2, 0x3C, 0x5F, 0xFD, 0x06, 0x3E, 0x47, 0xF4, 0x0B, 0xD5, 0x3F, 0x84, 0x80, 0x3C, 0x4F, + 0xFD, 0x06, 0xD5, 0xFA, 0x02, 0x58, 0x00, 0x07, 0x5B, 0x30, 0x01, 0x06, 0x5A, 0xC0, 0x01, 0x04, + 0x5A, 0x48, 0x01, 0x20, 0x2E, 0x47, 0xF4, 0x0A, 0x00, 0x68, 0x00, 0x01, 0xE2, 0xC4, 0xE9, 0x04, + 0x8C, 0x81, 0x3E, 0x47, 0xF4, 0x0A, 0x3C, 0x43, 0xFA, 0x04, 0xE2, 0xA4, 0xE9, 0x04, 0x8C, 0x81, + 0x3C, 0x4B, 0xFA, 0x04, 0x2E, 0x47, 0xF4, 0x0A, 0xE2, 0xC4, 0xE9, 0x05, 0x3C, 0x43, 0xFA, 0x04, + 0xE2, 0xA4, 0xE8, 0x1B, 0x84, 0x80, 0x3C, 0x4F, 0xFD, 0x06, 0x3E, 0x47, 0xF4, 0x0A, 0xD5, 0x13, + 0x84, 0x80, 0x3E, 0x47, 0xF4, 0x0A, 0x84, 0x80, 0x5B, 0x20, 0x01, 0x05, 0x3C, 0x43, 0xFA, 0x04, + 0x8C, 0x81, 0x3C, 0x4B, 0xFA, 0x04, 0x3C, 0x43, 0xFA, 0x04, 0xE2, 0xA4, 0xE8, 0x06, 0x84, 0x80, + 0x3C, 0x4F, 0xFD, 0x06, 0x3C, 0x4B, 0xFA, 0x04, 0x3C, 0x4D, 0xFD, 0x06, 0x5A, 0x48, 0x02, 0x04, + 0x84, 0x81, 0xD5, 0x02, 0x84, 0x80, 0x3E, 0x47, 0xF4, 0x0E, 0x2E, 0x47, 0xF4, 0x0E, 0x5A, 0x40, + 0x01, 0x04, 0x48, 0x00, 0x00, 0x83, 0x81, 0xC2, 0x80, 0xE3, 0x02, 0x28, 0x00, 0x04, 0x80, 0x6E, + 0xFD, 0x60, 0xEB, 0xA4, 0x00, 0x07, 0x00, 0x00, 0xC0, 0x78, 0x51, 0x15, 0x7F, 0xFF, 0x8F, 0x61, + 0x3D, 0x0D, 0xFD, 0x05, 0x84, 0x60, 0x86, 0x49, 0x45, 0x3F, 0x80, 0x00, 0x54, 0x85, 0x80, 0xFF, + 0x55, 0x48, 0x80, 0xFF, 0x00, 0x07, 0x00, 0x00, 0xE2, 0x60, 0xE8, 0x67, 0x04, 0x16, 0x80, 0x01, + 0x94, 0x99, 0x88, 0x22, 0xA4, 0x08, 0x4C, 0x01, 0xC0, 0x58, 0x04, 0x46, 0x80, 0x03, 0x39, 0x72, + 0x0D, 0x01, 0xE2, 0xF7, 0xE9, 0x51, 0x04, 0x46, 0x80, 0x04, 0x88, 0x82, 0xA6, 0xA1, 0xA7, 0x20, + 0xC2, 0x05, 0x9F, 0x51, 0x55, 0x62, 0x80, 0xFF, 0xD5, 0x02, 0x82, 0xC2, 0xE0, 0x51, 0xE8, 0x05, + 0x8C, 0x41, 0x55, 0x51, 0x00, 0xFF, 0xD5, 0x02, 0x82, 0xB4, 0xC4, 0x04, 0x9E, 0xA1, 0x96, 0x90, + 0xD5, 0x02, 0x80, 0x44, 0xE0, 0x8B, 0xE8, 0x04, 0x8C, 0x81, 0x97, 0x60, 0xD5, 0x02, 0x80, 0xA8, + 0x87, 0x00, 0x80, 0x98, 0xE2, 0xA2, 0xE9, 0x1A, 0x43, 0x91, 0x28, 0x24, 0x80, 0xD6, 0x41, 0xE2, + 0x58, 0x01, 0x40, 0x43, 0x78, 0x00, 0x40, 0xFA, 0x98, 0x06, 0x97, 0x20, 0xE9, 0x0C, 0x40, 0x4C, + 0x98, 0x00, 0x40, 0x46, 0x10, 0x20, 0xA5, 0x20, 0x8C, 0xC1, 0x88, 0x98, 0x41, 0x82, 0x00, 0x11, + 0x97, 0xB0, 0xD5, 0xF0, 0x8C, 0x41, 0x96, 0x90, 0xD5, 0xE6, 0x02, 0x28, 0x00, 0x05, 0xFE, 0xA4, + 0x40, 0xF1, 0x49, 0xF6, 0x40, 0xFC, 0x3C, 0x07, 0xE9, 0x0C, 0x02, 0x28, 0x00, 0x06, 0x8E, 0x81, + 0xFF, 0x14, 0x40, 0x6C, 0x5C, 0x01, 0x40, 0xF2, 0x49, 0xF6, 0x97, 0xB3, 0xE0, 0xCF, 0xE8, 0x04, + 0x40, 0x00, 0x4C, 0x04, 0xAC, 0x08, 0x8C, 0x61, 0x96, 0xD8, 0xD5, 0x9D, 0x3E, 0x47, 0xEB, 0x22, + 0x3E, 0x67, 0xEB, 0x21, 0x48, 0xFF, 0xFE, 0x8C, 0x3C, 0x0D, 0xFD, 0x06, 0x3C, 0x9B, 0xFA, 0x03, + 0x8E, 0x02, 0xEA, 0xB8, 0xFC, 0xE0, 0xFC, 0x20, 0xA6, 0x40, 0x2E, 0x47, 0x33, 0x91, 0x5A, 0x10, + 0x01, 0x07, 0x84, 0x20, 0x44, 0x62, 0x00, 0x00, 0x80, 0xE1, 0xD5, 0x10, 0x44, 0x12, 0x02, 0x95, + 0x84, 0xA0, 0xD4, 0x08, 0x08, 0x60, 0x80, 0x01, 0x8C, 0xA1, 0x10, 0x60, 0xFF, 0xEA, 0x97, 0x68, + 0xD5, 0xF9, 0xA6, 0x00, 0x5A, 0x08, 0x01, 0x21, 0xD5, 0x09, 0x97, 0x48, 0xE2, 0xA4, 0xE8, 0xFA, + 0x99, 0x4E, 0x10, 0x72, 0x82, 0x80, 0x8C, 0x21, 0xD5, 0xF9, 0x2E, 0x07, 0xEF, 0x43, 0x8A, 0x40, + 0x4E, 0x27, 0x00, 0x0A, 0x5A, 0x38, 0x01, 0x08, 0x2E, 0x07, 0xF4, 0x1C, 0xC8, 0x07, 0x3E, 0x37, + 0xF4, 0x1C, 0xD5, 0x04, 0x84, 0x00, 0x3E, 0x07, 0xF4, 0x1C, 0x84, 0x00, 0x3E, 0x07, 0xEF, 0x43, + 0x3C, 0x00, 0x06, 0x2A, 0xD5, 0x02, 0x84, 0x00, 0x3C, 0x0B, 0x9B, 0x0B, 0xFC, 0xA0, 0xFC, 0x20, + 0x97, 0xC1, 0x2E, 0x07, 0xF2, 0xE4, 0x50, 0x63, 0x80, 0x7D, 0x97, 0xB1, 0x5A, 0x08, 0x01, 0x07, + 0xF8, 0x20, 0xE8, 0x06, 0x50, 0x63, 0x80, 0x64, 0xD5, 0x36, 0x5A, 0x00, 0x02, 0x06, 0x2E, 0x17, + 0xF2, 0xF0, 0x5A, 0x18, 0x02, 0x11, 0xF8, 0x15, 0xE8, 0x1D, 0x8E, 0x2A, 0xE6, 0x2F, 0xE8, 0x08, + 0x3C, 0x03, 0xF9, 0x76, 0x50, 0xF0, 0x7F, 0x37, 0x5C, 0xF7, 0x80, 0xC7, 0xE9, 0x22, 0x50, 0x63, + 0x80, 0x5A, 0xD5, 0x21, 0x5A, 0x00, 0x03, 0x06, 0x2E, 0x17, 0xF2, 0xF0, 0x5A, 0x18, 0x03, 0x0D, + 0x3C, 0x13, 0xF9, 0x77, 0x5C, 0xF0, 0x80, 0xC8, 0x83, 0xFF, 0xE8, 0x06, 0x50, 0x63, 0x80, 0x50, + 0xD5, 0x12, 0x5A, 0x08, 0x03, 0xF3, 0x8E, 0x04, 0xE6, 0x09, 0xE9, 0x06, 0x2E, 0x07, 0xF2, 0xF0, + 0x8E, 0x04, 0xE6, 0x09, 0xE8, 0x09, 0x3C, 0x03, 0xF9, 0x77, 0x5C, 0xF0, 0x00, 0xC8, 0xE8, 0x04, + 0x50, 0x63, 0x80, 0x46, 0x97, 0xB1, 0xEB, 0x50, 0xB4, 0x00, 0x42, 0x00, 0x5C, 0x0B, 0x5A, 0x08, + 0x01, 0x08, 0xDD, 0x43, 0x5A, 0x08, 0x02, 0x05, 0x50, 0x63, 0x80, 0x95, 0x97, 0xB1, 0x80, 0x06, + 0xFC, 0xA0, 0xFC, 0x00, 0x80, 0xC0, 0x3C, 0x03, 0x9A, 0x1D, 0xAC, 0x30, 0xAC, 0x34, 0xEA, 0x2E, + 0x5A, 0x08, 0x01, 0x0D, 0xDD, 0x54, 0xA6, 0x00, 0x8E, 0x03, 0xE6, 0x02, 0xE8, 0x07, 0x2E, 0x07, + 0x34, 0x92, 0xAC, 0x30, 0x2E, 0x07, 0x34, 0x92, 0xAC, 0x34, 0x2E, 0x07, 0x34, 0x23, 0x5A, 0x08, + 0x01, 0x12, 0x3C, 0x0D, 0xFC, 0x0E, 0xC8, 0x0E, 0x2E, 0x17, 0x34, 0x0C, 0x5A, 0x18, 0x01, 0x0B, + 0xEB, 0xD7, 0xA6, 0x48, 0x8E, 0x23, 0xE6, 0x22, 0xE8, 0x02, 0xFA, 0x0E, 0x49, 0xFF, 0xFF, 0x89, + 0xAC, 0x30, 0xEA, 0xD5, 0xB4, 0x01, 0x42, 0x00, 0x5C, 0x0B, 0x5A, 0x08, 0x01, 0x09, 0xB4, 0x01, + 0xEA, 0xD2, 0x5A, 0x08, 0x01, 0x05, 0x44, 0x00, 0x00, 0xA9, 0xAC, 0x30, 0xFC, 0x80, 0xFC, 0x40, + 0x80, 0xE0, 0x84, 0x00, 0xAE, 0x38, 0x84, 0x00, 0xAC, 0x08, 0x81, 0x21, 0xAC, 0x10, 0x80, 0x24, + 0xA0, 0x1D, 0x81, 0x42, 0x80, 0xC4, 0x44, 0x20, 0x00, 0x46, 0x80, 0x67, 0x84, 0x80, 0xEB, 0xA4, + 0x84, 0xA0, 0xA6, 0x38, 0xE2, 0xA0, 0xE8, 0x19, 0xA0, 0x31, 0x94, 0x69, 0x38, 0x00, 0x15, 0x01, + 0xD8, 0x12, 0xA0, 0x32, 0x02, 0x24, 0x80, 0x00, 0x38, 0x00, 0x15, 0x01, 0xE2, 0x40, 0xE8, 0x02, + 0xEA, 0xBC, 0xA0, 0x33, 0x38, 0x00, 0x04, 0x01, 0x02, 0x15, 0x00, 0x00, 0xE2, 0x20, 0xE8, 0x03, + 0x12, 0x05, 0x00, 0x00, 0x8C, 0xA1, 0xD5, 0xE6, 0xFC, 0xC0, 0xFC, 0x00, 0x3C, 0x1D, 0xFA, 0xBC, + 0xA6, 0x08, 0x8C, 0x01, 0xAE, 0x08, 0x3C, 0x1D, 0xFA, 0xBC, 0xA6, 0x08, 0x96, 0x04, 0xC8, 0x06, + 0x3C, 0x0D, 0xFA, 0xBE, 0x3C, 0x0F, 0xFA, 0xBB, 0xD5, 0x05, 0x3C, 0x0D, 0xFA, 0xBD, 0x3C, 0x0F, + 0xFA, 0xBB, 0x3C, 0x0D, 0xFA, 0xBB, 0xA6, 0x48, 0x10, 0x10, 0x00, 0x3F, 0x80, 0xA0, 0x84, 0x20, + 0xEB, 0xE8, 0x50, 0x00, 0x00, 0x3C, 0xEB, 0xE8, 0xD8, 0xFF, 0xFC, 0x80, 0x3C, 0x2D, 0xFA, 0xBB, + 0xA6, 0x50, 0x98, 0xD1, 0xAE, 0x19, 0x9C, 0x09, 0x96, 0x00, 0x5C, 0xF0, 0x00, 0x3B, 0xE9, 0x02, + 0x84, 0x00, 0xAE, 0x10, 0xA6, 0x10, 0x88, 0x40, 0x84, 0x1F, 0xAE, 0x11, 0xDD, 0x9E, 0xFC, 0x00, + 0xEA, 0xA4, 0x2E, 0x57, 0xF2, 0xCC, 0xD0, 0x0C, 0xC8, 0x05, 0x44, 0x00, 0x00, 0x52, 0xDD, 0x4A, + 0xD5, 0x04, 0x44, 0x00, 0x00, 0x51, 0xDD, 0x4A, 0xEA, 0xA4, 0x3E, 0x07, 0xF2, 0xCC, 0x2E, 0x07, + 0xF3, 0x54, 0x2E, 0x57, 0xF2, 0xCD, 0xD0, 0x0C, 0xC8, 0x04, 0xEA, 0xB2, 0xDD, 0x4A, 0xD5, 0x04, + 0x44, 0x00, 0x00, 0x53, 0xDD, 0x4A, 0x2E, 0x07, 0xF3, 0x54, 0x3E, 0x07, 0xF2, 0xCD, 0x2E, 0x07, + 0xF3, 0x55, 0x2E, 0x57, 0xF2, 0xCE, 0xD0, 0x0C, 0xC8, 0x05, 0x44, 0x00, 0x00, 0x56, 0xDD, 0x4A, + 0xD5, 0x03, 0xEA, 0x40, 0xDD, 0x4A, 0x2E, 0x07, 0xF3, 0x55, 0x3E, 0x07, 0xF2, 0xCE, 0x2E, 0x00, + 0x17, 0x05, 0x5A, 0x00, 0xAA, 0x04, 0x84, 0x07, 0xDD, 0x4A, 0xFC, 0x80, 0xFC, 0x00, 0x49, 0x00, + 0x4C, 0xB2, 0xFC, 0x80, 0x44, 0x10, 0x00, 0x55, 0xDD, 0x45, 0xAE, 0x40, 0xDD, 0x9E, 0xFC, 0x03, + 0xF0, 0x81, 0x80, 0x05, 0xF2, 0x83, 0xF1, 0x82, 0xF3, 0x84, 0xF4, 0x85, 0x49, 0x00, 0x4C, 0x1A, + 0xF0, 0x02, 0xF1, 0x03, 0x49, 0x00, 0x4F, 0x02, 0xDD, 0x47, 0xDD, 0x45, 0xAE, 0x40, 0xF0, 0x01, + 0xF1, 0x04, 0xF2, 0x05, 0x49, 0x00, 0x4E, 0x8A, 0xFC, 0x83, 0xFC, 0x20, 0x84, 0xC0, 0x80, 0xE0, + 0xE2, 0xC7, 0xE8, 0x0B, 0x84, 0x01, 0x84, 0x40, 0x80, 0x20, 0x80, 0x62, 0x80, 0x80, 0x80, 0xA2, + 0x8C, 0xC1, 0xDD, 0x56, 0x97, 0xB0, 0xD5, 0xF5, 0xFC, 0xA0, 0xFC, 0x00, 0x49, 0x00, 0x4F, 0xB8, + 0xFC, 0x80, 0xFC, 0x00, 0x49, 0x00, 0x4F, 0xA6, 0xFC, 0x80, 0xEB, 0x9A, 0xC8, 0x08, 0x2E, 0x17, + 0xF2, 0xBA, 0xC9, 0x07, 0xFC, 0x00, 0x49, 0x00, 0x4F, 0xB6, 0xFC, 0x80, 0x84, 0x00, 0xDD, 0x9E, + 0xDD, 0x9E, 0xFC, 0x00, 0xEB, 0x5A, 0xFC, 0x80, 0xEB, 0x84, 0xC8, 0x0A, 0xFC, 0x00, 0xEA, 0xD0, + 0xEB, 0x5A, 0xFA, 0x09, 0xEA, 0x39, 0xEA, 0xD0, 0xEB, 0x33, 0xEB, 0x5A, 0xFC, 0x80, 0xDD, 0x9E, + 0xDD, 0x9E, 0xFC, 0x00, 0x49, 0x00, 0x50, 0x7F, 0xFC, 0x80, 0xFC, 0x00, 0x49, 0x00, 0x50, 0x71, + 0xFC, 0x80, 0x44, 0x03, 0x3F, 0x90, 0xDD, 0x9E, 0x44, 0x13, 0x0F, 0xA0, 0xB6, 0x20, 0x44, 0x13, + 0x80, 0x68, 0xA8, 0x45, 0x44, 0x13, 0x73, 0xE8, 0xA8, 0x46, 0xEB, 0x45, 0xA8, 0x42, 0x44, 0x13, + 0x0C, 0x80, 0xA8, 0x44, 0x44, 0x13, 0x3F, 0x90, 0x50, 0x20, 0x00, 0x44, 0xB6, 0x22, 0x44, 0x12, + 0x32, 0x00, 0xA8, 0x51, 0x44, 0x12, 0x74, 0xF8, 0xA8, 0x53, 0xDD, 0x9E, 0xFC, 0x44, 0x80, 0xC0, + 0x44, 0x01, 0x68, 0x54, 0xEB, 0x38, 0x44, 0x01, 0x68, 0x64, 0x3B, 0x0F, 0xCC, 0x20, 0xB1, 0xC4, + 0xEB, 0x38, 0x3B, 0x03, 0xCC, 0x20, 0x49, 0x00, 0x40, 0x07, 0x38, 0x1F, 0x82, 0x02, 0x83, 0x86, + 0xB9, 0x8A, 0x38, 0x13, 0x82, 0x02, 0xB9, 0x8B, 0xEA, 0xC8, 0x44, 0x12, 0xD7, 0xD0, 0x42, 0x10, + 0x08, 0x73, 0x44, 0x03, 0x1F, 0x40, 0xB8, 0x89, 0x44, 0x03, 0x8D, 0xD4, 0x81, 0x3F, 0xB9, 0x93, + 0xB8, 0x8C, 0xFC, 0xC4, 0xFC, 0x20, 0x84, 0x2C, 0xAE, 0x41, 0x84, 0x00, 0x3C, 0x0F, 0xFC, 0x74, + 0xEA, 0xCC, 0x49, 0xFF, 0xE7, 0xEC, 0xEB, 0x36, 0x3C, 0x0D, 0xFC, 0x74, 0xC0, 0x0B, 0x84, 0x20, + 0x84, 0x61, 0x84, 0x02, 0x80, 0x41, 0x80, 0x83, 0x80, 0xA3, 0x3C, 0x1F, 0xFC, 0x74, 0xDD, 0x56, + 0xFC, 0xA0, 0x49, 0x00, 0x4C, 0x99, 0x5A, 0x08, 0x01, 0xF4, 0xAF, 0xF0, 0xD5, 0xEE, 0xFC, 0x00, + 0x49, 0x00, 0x4C, 0x89, 0x84, 0x01, 0x49, 0x00, 0x4C, 0x8B, 0xFC, 0x80, 0xA4, 0x40, 0x8C, 0x21, + 0x96, 0x49, 0x5C, 0xF0, 0x81, 0x90, 0xAC, 0x40, 0xE9, 0x09, 0xFC, 0x00, 0x84, 0x05, 0xDD, 0x4A, + 0x84, 0x00, 0xEA, 0x30, 0xEA, 0x92, 0xEA, 0x69, 0xFC, 0x80, 0xDD, 0x9E, 0xFC, 0x20, 0xFD, 0x30, + 0xDD, 0x40, 0xC0, 0x1F, 0xA7, 0x70, 0xDF, 0x0A, 0x8C, 0xA1, 0x97, 0x68, 0xE6, 0xA5, 0xE9, 0x02, + 0x84, 0xA0, 0xEA, 0x34, 0xAF, 0x70, 0xEA, 0x97, 0xD5, 0x0D, 0x84, 0x06, 0xDD, 0x4A, 0x44, 0x13, + 0x8D, 0x20, 0xA6, 0x08, 0x8C, 0x01, 0x96, 0x00, 0xAE, 0x08, 0x84, 0x00, 0xEA, 0x30, 0xEA, 0x40, + 0xEA, 0x69, 0x44, 0x03, 0x8D, 0x20, 0xA6, 0x00, 0xC0, 0x04, 0x84, 0x01, 0x3E, 0x07, 0xF3, 0x76, + 0xFC, 0xA0, 0xA6, 0x88, 0x5A, 0x28, 0xAA, 0x0A, 0xFC, 0x00, 0xA6, 0x80, 0xAE, 0x88, 0x84, 0x20, + 0xAE, 0x40, 0x49, 0x00, 0x4F, 0x73, 0xFC, 0x80, 0xDD, 0x9E, 0xFC, 0x00, 0xEA, 0x46, 0x5A, 0x00, + 0x04, 0x05, 0xEA, 0x6E, 0x5A, 0x08, 0x01, 0x1A, 0xDD, 0x43, 0x5A, 0x00, 0x02, 0x17, 0xEA, 0x6B, + 0x5A, 0x08, 0x01, 0x14, 0xDD, 0x41, 0x84, 0x2E, 0xAE, 0x41, 0x84, 0x00, 0x3E, 0x07, 0xEE, 0xB0, + 0x84, 0x00, 0xEB, 0x7E, 0xEA, 0xE2, 0x44, 0x02, 0xBB, 0x5D, 0x49, 0xFF, 0xFF, 0xDC, 0x84, 0x03, + 0x84, 0x20, 0x3C, 0x2D, 0xFC, 0x04, 0xEB, 0xC5, 0xFC, 0x80, 0xA6, 0x88, 0x5A, 0x20, 0xAA, 0x10, + 0xFC, 0x00, 0xAE, 0x80, 0x44, 0x2F, 0xFF, 0xAA, 0xAE, 0x88, 0xA6, 0x00, 0x5A, 0x08, 0x01, 0x05, + 0x49, 0x00, 0x4F, 0x3D, 0xFC, 0x80, 0x49, 0x00, 0x4F, 0x41, 0xFC, 0x80, 0xDD, 0x9E, 0x84, 0x40, + 0xAE, 0x80, 0x84, 0x00, 0xAC, 0x08, 0xDD, 0x9E, 0xFC, 0x00, 0x5A, 0x08, 0x01, 0x05, 0x49, 0x00, + 0x4D, 0x6B, 0xFC, 0x80, 0x49, 0x00, 0x4D, 0x69, 0xFC, 0x80, 0xFC, 0x00, 0x84, 0x20, 0x44, 0x03, + 0xF5, 0x60, 0xAE, 0x40, 0x84, 0x23, 0x44, 0x03, 0xF5, 0x61, 0xAE, 0x40, 0x84, 0x00, 0x80, 0x20, + 0x80, 0x40, 0x80, 0x60, 0xEA, 0x4B, 0xFC, 0x80, 0xFC, 0x00, 0x84, 0x23, 0x44, 0x03, 0xF5, 0x60, + 0xAE, 0x40, 0x84, 0x20, 0x44, 0x03, 0xF5, 0x61, 0xAE, 0x40, 0x84, 0x00, 0x80, 0x20, 0x80, 0x40, + 0x80, 0x60, 0xEA, 0x4B, 0xFC, 0x80, 0xFC, 0x00, 0x44, 0x02, 0xFE, 0x63, 0xA7, 0x40, 0x44, 0x03, + 0xF0, 0x07, 0xA6, 0x00, 0xD8, 0x08, 0x44, 0x02, 0xFE, 0x64, 0xA7, 0x40, 0x44, 0x03, 0xF0, 0x04, + 0xA6, 0x00, 0xD0, 0x06, 0x44, 0x1F, 0xFF, 0x8E, 0xEB, 0xD0, 0xAE, 0x40, 0xF8, 0x0A, 0x44, 0x03, + 0xF0, 0x07, 0xA6, 0x00, 0x5A, 0x00, 0x23, 0x11, 0x44, 0x1F, 0xFF, 0x9E, 0xEB, 0xD0, 0xAE, 0x40, + 0x84, 0x3F, 0x44, 0x02, 0xFE, 0x61, 0xAE, 0x40, 0x84, 0x20, 0x84, 0x02, 0x80, 0x41, 0x84, 0x61, + 0x80, 0x81, 0x80, 0xA1, 0xDD, 0x56, 0xFC, 0x80, 0xFC, 0x24, 0x44, 0x01, 0x68, 0x84, 0xEB, 0x38, + 0x44, 0x21, 0x68, 0x94, 0x3B, 0x0F, 0xCC, 0x20, 0xB0, 0x04, 0xEB, 0xC1, 0x3B, 0x00, 0x4C, 0x20, + 0x44, 0x23, 0x8D, 0x41, 0xA6, 0x90, 0x44, 0x11, 0xE4, 0x80, 0x40, 0x10, 0x88, 0x40, 0xA6, 0xC8, + 0x38, 0x50, 0x0A, 0x02, 0x84, 0x00, 0x38, 0x4F, 0x8A, 0x02, 0x96, 0xD8, 0x44, 0x62, 0x62, 0x38, + 0x80, 0xE0, 0x3C, 0x13, 0x99, 0xDE, 0xE2, 0x01, 0xE8, 0x18, 0x40, 0x23, 0x00, 0x20, 0x03, 0x01, + 0x00, 0x00, 0x38, 0x12, 0x80, 0x00, 0x42, 0x18, 0x04, 0x24, 0x39, 0x02, 0x01, 0x01, 0x40, 0x10, + 0x8C, 0x0E, 0x8A, 0x30, 0x96, 0x49, 0xAC, 0x50, 0xA4, 0x50, 0x96, 0x4B, 0x4E, 0x14, 0x00, 0x03, + 0xAD, 0xD0, 0x8C, 0x01, 0x96, 0x01, 0xD5, 0xE6, 0xFC, 0xA4, 0xFC, 0x00, 0xDD, 0x43, 0x84, 0x00, + 0xFC, 0x80, 0xFC, 0x00, 0x84, 0x21, 0x49, 0x00, 0x3B, 0x6D, 0xFC, 0x80, 0xFC, 0x01, 0xF0, 0x81, + 0x94, 0x91, 0x80, 0x01, 0xF1, 0x01, 0xDD, 0x46, 0xFC, 0x81, 0xFC, 0x06, 0x44, 0x22, 0x00, 0x00, + 0xFA, 0xD0, 0xA6, 0xD2, 0xA7, 0x13, 0x84, 0xA1, 0x84, 0x40, 0xF6, 0x85, 0x84, 0xC2, 0xF2, 0x83, + 0xF2, 0x84, 0xF2, 0x86, 0xF2, 0x88, 0xF2, 0x89, 0xB6, 0x7F, 0xF5, 0x81, 0xF3, 0x82, 0xF6, 0x87, + 0xF5, 0x8A, 0x80, 0x41, 0xEA, 0x54, 0xFC, 0x86, 0xFC, 0x00, 0xC8, 0x05, 0xEA, 0x4A, 0xEA, 0x86, + 0xDD, 0x5D, 0xFC, 0x80, 0x49, 0xFF, 0xDB, 0x5A, 0x80, 0xA0, 0xC8, 0xF9, 0xEA, 0x4A, 0x44, 0x13, + 0x00, 0x02, 0x44, 0x22, 0x62, 0x38, 0xEA, 0x96, 0xEA, 0xAD, 0x49, 0x00, 0x48, 0xE7, 0xFC, 0x80, + 0xFC, 0x00, 0xDD, 0x5A, 0x80, 0xC0, 0xA6, 0x49, 0x49, 0xFF, 0xFF, 0xE8, 0x5A, 0x68, 0x03, 0x06, + 0xEB, 0x84, 0xC8, 0x03, 0x49, 0xFF, 0xFF, 0x82, 0xFC, 0x80, 0xFC, 0x26, 0x97, 0xD0, 0xFA, 0x50, + 0x84, 0xC0, 0x84, 0xA1, 0xF2, 0x85, 0x84, 0x42, 0x97, 0x18, 0xF2, 0x87, 0xB6, 0xFF, 0xF5, 0x81, + 0xF7, 0x82, 0xF6, 0x83, 0xF6, 0x84, 0xF6, 0x86, 0xF6, 0x88, 0xF6, 0x89, 0xF5, 0x8A, 0x80, 0x41, + 0x80, 0x67, 0xEA, 0x54, 0xFC, 0xA6, 0xFC, 0x06, 0x44, 0x42, 0x00, 0x00, 0xA7, 0xA2, 0x84, 0xA0, + 0xA7, 0x23, 0xF5, 0x81, 0xF5, 0x82, 0xF5, 0x83, 0xF5, 0x84, 0xF5, 0x86, 0xF5, 0x88, 0xF5, 0x89, + 0x84, 0xA1, 0xF2, 0x85, 0xF3, 0x87, 0xB6, 0xDF, 0xF5, 0x8A, 0x80, 0x41, 0x80, 0x66, 0xEA, 0x54, + 0xFC, 0x86, 0xFC, 0x07, 0xF3, 0x8D, 0xFA, 0x70, 0x84, 0xA0, 0x80, 0x82, 0xF3, 0x85, 0x84, 0x41, + 0x84, 0x62, 0xF2, 0x81, 0xF4, 0x82, 0xF3, 0x87, 0xF2, 0x8A, 0x80, 0x64, 0xB6, 0xBF, 0xF5, 0x83, + 0xF5, 0x84, 0xF5, 0x86, 0xF5, 0x88, 0xF5, 0x89, 0x80, 0x41, 0xF4, 0x0D, 0xEA, 0x54, 0xFC, 0x87, + 0xFC, 0x01, 0xEA, 0xFD, 0xEB, 0x45, 0xDD, 0x5D, 0xEA, 0x7C, 0xEA, 0xC5, 0xDD, 0x5D, 0x84, 0x00, + 0xEA, 0xAB, 0x3C, 0x1C, 0x03, 0x30, 0xEA, 0xCA, 0xFA, 0x50, 0xEA, 0xF2, 0xEA, 0xFB, 0xFC, 0x81, + 0xFC, 0x08, 0xF1, 0x8E, 0xF0, 0x8D, 0x80, 0x23, 0xF2, 0x8F, 0xEA, 0x96, 0xC4, 0x04, 0xEA, 0xAD, + 0x80, 0x03, 0xD5, 0x03, 0x80, 0x04, 0x84, 0x81, 0x84, 0xA1, 0xB6, 0x1F, 0xF0, 0x82, 0x84, 0x00, + 0xF0, 0x83, 0xF1, 0x84, 0xF0, 0x85, 0xF0, 0x86, 0xF0, 0x88, 0xF0, 0x89, 0xF0, 0x8A, 0xF5, 0x81, + 0xF5, 0x87, 0xF0, 0x0D, 0xF1, 0x0E, 0xF2, 0x0F, 0xEA, 0x54, 0xFC, 0x88, 0xFC, 0x06, 0x00, 0x6F, + 0x80, 0x40, 0xB6, 0xDF, 0x00, 0x6F, 0x80, 0x44, 0xF6, 0x81, 0x00, 0x6F, 0x80, 0x48, 0xF6, 0x82, + 0x00, 0x6F, 0x80, 0x4C, 0xF6, 0x83, 0x00, 0x6F, 0x80, 0x50, 0xF6, 0x84, 0x00, 0x6F, 0x80, 0x54, + 0xF6, 0x85, 0x02, 0x6F, 0x80, 0x2C, 0xF6, 0x86, 0x00, 0x6F, 0x80, 0x5C, 0xF6, 0x87, 0x22, 0x6F, + 0x80, 0x30, 0xF6, 0x88, 0x22, 0x6F, 0x80, 0x32, 0xF6, 0x89, 0x00, 0x6F, 0x80, 0x68, 0xF6, 0x8A, + 0xEA, 0x54, 0xFC, 0x86, 0xFC, 0x25, 0x44, 0x62, 0x00, 0x00, 0xA7, 0xF2, 0xA7, 0xB3, 0xF3, 0x81, + 0xB0, 0xC7, 0xF3, 0x84, 0x84, 0x60, 0xF4, 0x82, 0xF5, 0x83, 0xB6, 0xDF, 0x80, 0x83, 0x80, 0xA7, + 0x49, 0x00, 0x47, 0x4D, 0xFC, 0xA5, 0xFC, 0x00, 0x84, 0x01, 0x84, 0x20, 0x49, 0x00, 0x4C, 0x6E, + 0x44, 0x00, 0x0C, 0xD5, 0x49, 0x00, 0x4C, 0x72, 0xFC, 0x80, 0x44, 0x03, 0xF0, 0x1F, 0x44, 0x23, + 0xF3, 0x02, 0xA6, 0x00, 0xA6, 0x50, 0x54, 0x00, 0x00, 0xE0, 0x96, 0x67, 0x8C, 0x22, 0x5E, 0xF0, + 0x80, 0x20, 0xE8, 0x07, 0xA6, 0x50, 0x96, 0x67, 0x88, 0x01, 0x8C, 0x02, 0x96, 0x00, 0xD5, 0x03, + 0x8C, 0x1F, 0x96, 0x00, 0x44, 0x13, 0xF0, 0x1F, 0xAE, 0x08, 0xDD, 0x9E, 0xFC, 0x00, 0x84, 0x00, + 0x80, 0x20, 0x49, 0x00, 0x49, 0x63, 0x49, 0x00, 0x4D, 0x61, 0x49, 0x00, 0x51, 0xC5, 0x49, 0xFF, + 0xFF, 0xD4, 0x49, 0xFF, 0xFF, 0xDC, 0x49, 0x00, 0x4B, 0xC6, 0x49, 0x00, 0x47, 0x40, 0x49, 0x00, + 0x4D, 0xBA, 0x49, 0x00, 0x48, 0xAD, 0x49, 0x00, 0x48, 0x56, 0x84, 0x01, 0x44, 0x13, 0xF5, 0x72, + 0xAE, 0x08, 0x44, 0x13, 0xF5, 0x73, 0xAE, 0x08, 0x44, 0x13, 0xF3, 0x80, 0xAE, 0x08, 0x49, 0xFF, + 0xCF, 0x60, 0xFC, 0x80, 0xFC, 0x43, 0x44, 0x11, 0x68, 0xA4, 0xB1, 0x82, 0x3B, 0x00, 0xCC, 0x00, + 0x81, 0x20, 0x3B, 0x03, 0x4C, 0x20, 0xDD, 0x40, 0x5A, 0x08, 0x01, 0x06, 0x84, 0x02, 0xEA, 0x49, + 0x84, 0x06, 0xEB, 0x43, 0xDD, 0x4B, 0x84, 0x21, 0xAE, 0x40, 0x49, 0x00, 0x54, 0xD6, 0x44, 0x73, + 0x8D, 0x40, 0x85, 0x45, 0xA6, 0x38, 0x5A, 0x08, 0x02, 0x0E, 0x49, 0x00, 0x5E, 0xFB, 0xDD, 0x40, + 0xC0, 0xFA, 0x3C, 0x1D, 0xFC, 0xD3, 0x5A, 0x10, 0x03, 0x03, 0xC9, 0xF5, 0x3E, 0xA7, 0xF2, 0xE3, + 0xD5, 0xF2, 0xDD, 0x40, 0x5A, 0x00, 0x01, 0x09, 0x84, 0x00, 0xEA, 0x5E, 0xAE, 0x18, 0xEA, 0x74, + 0x5A, 0x08, 0x01, 0x26, 0xD5, 0x0E, 0x84, 0x00, 0xEA, 0xAB, 0x84, 0xE0, 0xEA, 0xFC, 0x38, 0x03, + 0x1E, 0x02, 0x84, 0x20, 0x94, 0x91, 0x8C, 0xE1, 0xEA, 0x2F, 0x5A, 0x78, 0x04, 0xF9, 0xD5, 0xED, + 0x84, 0x03, 0xDD, 0x5A, 0x84, 0x40, 0xEB, 0x3E, 0xDD, 0x40, 0x5A, 0x08, 0x01, 0x11, 0x44, 0x00, + 0x03, 0x20, 0xEA, 0xAB, 0xEB, 0x45, 0xEA, 0xCA, 0xEA, 0x9B, 0x2E, 0x37, 0x33, 0x8B, 0xEA, 0xFB, + 0xEA, 0xCA, 0xEA, 0xC5, 0xEA, 0x9B, 0x2E, 0x37, 0x33, 0x8B, 0xEA, 0xFB, 0xDD, 0x47, 0xDD, 0x45, + 0xAE, 0x40, 0x84, 0x00, 0xFC, 0xC3, 0x3C, 0x03, 0xF5, 0x92, 0x3C, 0x1D, 0xFA, 0xCA, 0x44, 0x23, + 0xF5, 0x40, 0xB4, 0x42, 0x38, 0x20, 0x82, 0x0A, 0x44, 0x23, 0xF5, 0x44, 0xB4, 0x62, 0x9C, 0x81, + 0x96, 0x91, 0xEA, 0xDC, 0x44, 0x23, 0xF5, 0x48, 0xB4, 0x62, 0x9C, 0x82, 0x96, 0x91, 0xEA, 0xDC, + 0x44, 0x23, 0xF5, 0x4C, 0xB4, 0x62, 0x9C, 0x83, 0x96, 0x91, 0xEA, 0xDC, 0x44, 0x23, 0xF5, 0x50, + 0xB4, 0x62, 0x9C, 0x84, 0x96, 0x91, 0xEA, 0xDC, 0x44, 0x23, 0xF5, 0x54, 0xB4, 0x62, 0x9C, 0x85, + 0x96, 0x91, 0xEA, 0xDC, 0x44, 0x23, 0xF5, 0x58, 0xB4, 0x62, 0x9C, 0x86, 0x96, 0x91, 0xEA, 0xDC, + 0x50, 0x20, 0x00, 0x08, 0x3C, 0x2B, 0xF5, 0x92, 0x8C, 0x07, 0x44, 0x23, 0xF5, 0x5C, 0xB4, 0x42, + 0x96, 0x01, 0x38, 0x20, 0x82, 0x0A, 0xDD, 0x9E, 0xFC, 0x01, 0x5A, 0x08, 0x01, 0x16, 0x3C, 0x0D, + 0xCC, 0xFF, 0xB6, 0x1F, 0x3C, 0x0D, 0xCD, 0x00, 0xF0, 0x81, 0x3C, 0x1D, 0xCC, 0xFA, 0x3C, 0x0D, + 0xCC, 0xF9, 0x3C, 0x2D, 0xCC, 0xFB, 0x3C, 0x3D, 0xCC, 0xFC, 0x3C, 0x4D, 0xCC, 0xFD, 0x3C, 0x5D, + 0xCC, 0xFE, 0xF8, 0x15, 0xD5, 0x16, 0xC8, 0x15, 0x3C, 0x0D, 0xCC, 0xF7, 0xB6, 0x1F, 0x3C, 0x0D, + 0xCC, 0xF8, 0xF0, 0x81, 0x3C, 0x1D, 0xCC, 0xF2, 0x3C, 0x0D, 0xCC, 0xF1, 0x3C, 0x2D, 0xCC, 0xF3, + 0x3C, 0x3D, 0xCC, 0xF4, 0x3C, 0x4D, 0xCC, 0xF5, 0x3C, 0x5D, 0xCC, 0xF6, 0x49, 0x00, 0x49, 0xA0, + 0xEA, 0xEA, 0x5A, 0x08, 0x01, 0x09, 0x3C, 0x03, 0xF5, 0x92, 0x5C, 0xF0, 0x00, 0x80, 0xE8, 0x03, + 0x49, 0xFF, 0xFF, 0x93, 0x84, 0x00, 0x80, 0x20, 0x80, 0x40, 0x80, 0x60, 0x49, 0x00, 0x47, 0x8C, + 0x49, 0x00, 0x47, 0x66, 0xFC, 0x81, 0x44, 0x23, 0xF0, 0x77, 0xA6, 0x50, 0x96, 0x04, 0xEA, 0x5D, + 0xFE, 0x0F, 0xAE, 0x10, 0xDD, 0x9E, 0x92, 0x00, 0xFC, 0x20, 0x80, 0xE0, 0x80, 0xC1, 0xDD, 0x43, + 0xA6, 0xB9, 0xC8, 0x06, 0x50, 0x01, 0x7F, 0xF6, 0xE6, 0x02, 0x84, 0x09, 0xE9, 0x02, 0x80, 0x02, + 0xDD, 0x5B, 0xEA, 0x21, 0xAE, 0x88, 0x44, 0x23, 0xF3, 0x80, 0xA6, 0x50, 0x5A, 0x10, 0x01, 0xFF, + 0x4E, 0x63, 0x00, 0x73, 0x8E, 0x01, 0xE6, 0x0E, 0x4E, 0xF2, 0x00, 0xD5, 0x44, 0xF0, 0x67, 0x18, + 0xEA, 0xA1, 0x40, 0xF0, 0x3C, 0x00, 0xDD, 0x0F, 0x1C, 0x00, 0x9A, 0x01, 0x22, 0x00, 0x66, 0x00, + 0x22, 0x00, 0x66, 0x00, 0x66, 0x00, 0x28, 0x00, 0x28, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x66, 0x00, + 0x22, 0x00, 0xC2, 0x00, 0x84, 0x03, 0xEA, 0x6D, 0xF8, 0x55, 0x84, 0x00, 0xF8, 0xA1, 0xF8, 0x52, + 0x84, 0x01, 0x49, 0x00, 0x48, 0x1E, 0x2E, 0x67, 0xEF, 0x71, 0xCE, 0x12, 0x80, 0x06, 0xEA, 0xB4, + 0xEA, 0x88, 0x5A, 0x08, 0x01, 0x06, 0x44, 0x00, 0x08, 0x8E, 0xEA, 0x39, 0xD5, 0x0C, 0x84, 0x01, + 0x84, 0x24, 0x80, 0x46, 0x80, 0x66, 0x80, 0x86, 0x80, 0xA0, 0xDD, 0x56, 0xD5, 0x04, 0x84, 0x00, + 0x3E, 0x07, 0xEF, 0x71, 0x84, 0x01, 0xEA, 0xC4, 0x84, 0x01, 0xF8, 0x8E, 0xEB, 0xB3, 0x84, 0x00, + 0xEA, 0x6D, 0xF8, 0x30, 0xEA, 0xBB, 0xC0, 0x05, 0xEA, 0xEA, 0xC0, 0x03, 0x84, 0x00, 0xEB, 0x6E, + 0x84, 0x01, 0xF8, 0x82, 0x2E, 0x67, 0xEF, 0x71, 0xCE, 0x12, 0x80, 0x06, 0xEA, 0xB4, 0xEA, 0x88, + 0x5A, 0x08, 0x01, 0x06, 0x44, 0x00, 0x08, 0x8E, 0xEA, 0x39, 0xD5, 0x0C, 0x84, 0x01, 0x84, 0x24, + 0x80, 0x46, 0x80, 0x66, 0x80, 0x86, 0x80, 0xA0, 0xDD, 0x56, 0xD5, 0x04, 0x84, 0x00, 0x3E, 0x07, + 0xEF, 0x71, 0xEB, 0xB3, 0x84, 0x00, 0xF8, 0x5C, 0xEA, 0xBB, 0x4E, 0x02, 0x00, 0x74, 0xEA, 0xEA, + 0x4E, 0x03, 0x00, 0x71, 0x84, 0x01, 0xEB, 0x6E, 0xF8, 0x05, 0x84, 0x01, 0xEA, 0xC4, 0x84, 0x00, + 0xEA, 0x6D, 0x48, 0x00, 0x00, 0x68, 0x5A, 0x68, 0x01, 0x60, 0x8E, 0x03, 0xE6, 0x0C, 0xE8, 0x62, + 0x44, 0xF0, 0x67, 0xFC, 0xEA, 0x90, 0x40, 0xF0, 0x3C, 0x00, 0xDD, 0x0F, 0x0C, 0x12, 0x0C, 0x12, + 0x12, 0x18, 0x18, 0x70, 0x70, 0xB6, 0x0C, 0x8C, 0x84, 0x01, 0xF8, 0x3A, 0xD5, 0x53, 0x84, 0x01, + 0xEA, 0x6D, 0xD5, 0x50, 0xEA, 0xBB, 0xC0, 0x11, 0xEA, 0xEA, 0xC0, 0x0F, 0x84, 0x00, 0xEB, 0x6E, + 0x3E, 0x07, 0xF3, 0xCC, 0x3C, 0x03, 0xF5, 0x92, 0x3C, 0x1D, 0xFA, 0xCA, 0x8E, 0x01, 0x94, 0x02, + 0xB6, 0x01, 0x84, 0x01, 0x3C, 0x0B, 0xF5, 0x92, 0xEA, 0xBB, 0xC8, 0x0D, 0x84, 0x01, 0xEA, 0xB4, + 0x84, 0x01, 0xEA, 0x6D, 0x44, 0x00, 0x00, 0x37, 0xEA, 0x39, 0x84, 0x00, 0xF8, 0x25, 0x84, 0x00, + 0xF8, 0x28, 0xD5, 0x30, 0xEA, 0xEA, 0xC8, 0xF3, 0x3C, 0x5D, 0xFA, 0xCA, 0x84, 0x21, 0x3E, 0x17, + 0xF4, 0x1D, 0x50, 0x12, 0x82, 0x00, 0xAA, 0x29, 0xD9, 0xFF, 0xD5, 0xE9, 0xEA, 0xEA, 0xC0, 0x05, + 0xEA, 0xBB, 0xC0, 0x03, 0x84, 0x00, 0xEB, 0x6E, 0x84, 0x01, 0xEA, 0xB4, 0x84, 0x01, 0x49, 0x00, + 0x49, 0xB2, 0xEA, 0xBB, 0xC8, 0xA5, 0xD5, 0x16, 0x84, 0x01, 0xEA, 0xB4, 0x49, 0xFF, 0xFC, 0x97, + 0x84, 0x01, 0xEA, 0x6D, 0x84, 0x00, 0x49, 0xFF, 0xFF, 0x18, 0x84, 0x00, 0xEA, 0xC4, 0x84, 0x00, + 0x49, 0x00, 0x47, 0x6F, 0xD5, 0x07, 0x5A, 0x68, 0x02, 0x06, 0x84, 0x01, 0xEA, 0x6D, 0x84, 0x00, + 0xEA, 0xC4, 0xFC, 0xA0, 0xFC, 0x41, 0x84, 0xC0, 0x3E, 0x67, 0xEE, 0xB4, 0x3E, 0x67, 0xEF, 0x02, + 0x84, 0xE1, 0x44, 0x93, 0x8D, 0x40, 0x44, 0xA3, 0x8D, 0x41, 0xFA, 0x00, 0xDD, 0x4A, 0x49, 0x00, + 0x4C, 0xFD, 0x3E, 0x67, 0xEF, 0x13, 0x3E, 0x77, 0xEE, 0xCE, 0x3E, 0x77, 0xF2, 0xE3, 0x3E, 0x67, + 0xF3, 0x02, 0x3E, 0x67, 0xEE, 0xF9, 0x3E, 0x67, 0xEE, 0xFC, 0x10, 0x64, 0x80, 0x00, 0xDD, 0x43, + 0xDD, 0x5A, 0x5A, 0x08, 0x02, 0x0B, 0x84, 0x04, 0xAE, 0x09, 0x80, 0x01, 0x84, 0x20, 0xDD, 0x53, + 0xDD, 0x41, 0x84, 0x2D, 0xAE, 0x41, 0xD5, 0x0B, 0x84, 0x09, 0xAE, 0x09, 0x80, 0x01, 0x84, 0x20, + 0xDD, 0x53, 0xDD, 0x41, 0x84, 0x2A, 0xAE, 0x41, 0x10, 0x64, 0x80, 0x00, 0xDD, 0x58, 0xAF, 0xC0, + 0xEA, 0x2E, 0x5A, 0x08, 0x01, 0x0C, 0xEA, 0x74, 0x3E, 0x07, 0xEF, 0x19, 0xEB, 0x7C, 0x3E, 0x07, + 0xEE, 0xC4, 0x2E, 0x07, 0xEF, 0x24, 0xC8, 0x02, 0xEB, 0x99, 0xDD, 0x41, 0xA6, 0x01, 0x3E, 0x07, + 0xEF, 0x3D, 0x84, 0x06, 0xDD, 0x57, 0xDD, 0x41, 0xEA, 0x3E, 0x2E, 0x07, 0x34, 0x16, 0x5A, 0x08, + 0x01, 0x04, 0x49, 0x00, 0x36, 0xA8, 0x84, 0x0A, 0xDD, 0x57, 0x49, 0x00, 0x37, 0xDF, 0xEA, 0x2E, + 0xC0, 0x4E, 0xDD, 0x43, 0x5A, 0x08, 0x02, 0x4C, 0x84, 0x0B, 0xDD, 0x57, 0xEA, 0x2E, 0x5A, 0x08, + 0x01, 0x0E, 0xEA, 0x8A, 0x5A, 0x00, 0x01, 0x05, 0x2E, 0x07, 0xEE, 0xF9, 0xC8, 0x07, 0x44, 0x02, + 0xBF, 0x7A, 0x50, 0x1F, 0x80, 0x07, 0x49, 0xFF, 0xFD, 0xCF, 0xEA, 0x2E, 0x3E, 0x67, 0xF3, 0x02, + 0x5A, 0x08, 0x01, 0x2F, 0x44, 0x00, 0x00, 0xF5, 0xDD, 0x4A, 0xEA, 0x8A, 0xC8, 0x0A, 0x44, 0x00, + 0x00, 0x66, 0xDD, 0x57, 0x49, 0x00, 0x38, 0x40, 0xEB, 0xD4, 0x5A, 0x08, 0x01, 0x09, 0xF8, 0x58, + 0x44, 0x00, 0x00, 0x67, 0xDD, 0x57, 0xEB, 0x7C, 0x49, 0x00, 0x38, 0xE3, 0x44, 0x00, 0x00, 0xF6, + 0xDD, 0x4A, 0x44, 0x00, 0x00, 0x68, 0xDD, 0x57, 0xDD, 0x40, 0xC0, 0x08, 0xEA, 0x67, 0x5A, 0x08, + 0x06, 0xFF, 0xEA, 0x4A, 0xEA, 0x86, 0xDD, 0x5D, 0xD5, 0x05, 0xDD, 0x51, 0xA6, 0x08, 0x5A, 0x08, + 0x01, 0xFF, 0xDD, 0x51, 0x84, 0x02, 0xAE, 0x08, 0xDD, 0x50, 0xAE, 0x08, 0xD5, 0x08, 0xDD, 0x40, + 0xC0, 0x06, 0xEA, 0x92, 0xDD, 0x57, 0xEA, 0x74, 0x49, 0xFF, 0xFC, 0x9C, 0x3E, 0x67, 0xF2, 0xE3, + 0xDD, 0x43, 0xDD, 0x5A, 0x2E, 0x27, 0xEF, 0x3D, 0x5A, 0x08, 0x02, 0x08, 0x9E, 0x12, 0xE6, 0x02, + 0xE8, 0x06, 0x84, 0x0D, 0xAE, 0x09, 0xD5, 0x07, 0x5A, 0x20, 0x02, 0x04, 0xAE, 0x89, 0xD5, 0x03, + 0x84, 0x0B, 0xAE, 0x09, 0xDD, 0x41, 0xEA, 0x3E, 0x44, 0x00, 0x00, 0x6A, 0x3E, 0x67, 0xEF, 0x51, + 0x3E, 0x67, 0xF3, 0x7B, 0x3E, 0x67, 0xEE, 0xD3, 0x3E, 0x67, 0xEE, 0xCE, 0xDD, 0x57, 0xDD, 0x40, + 0xC0, 0x03, 0x49, 0xFF, 0xF6, 0xAA, 0xDD, 0x4B, 0xAF, 0xC0, 0x49, 0x00, 0x52, 0x56, 0xEA, 0x8A, + 0xC8, 0x09, 0x2E, 0x07, 0xEE, 0xB4, 0x5A, 0x08, 0x01, 0x06, 0xFA, 0x03, 0xDD, 0x4A, 0x48, 0xFF, + 0xFF, 0x36, 0x84, 0xC1, 0x3E, 0x67, 0xEE, 0xEC, 0xDD, 0x43, 0xC8, 0x03, 0x3E, 0x67, 0xF2, 0xE0, + 0x44, 0x00, 0x00, 0x6F, 0xDD, 0x57, 0xFC, 0xC1, 0xFC, 0x40, 0xEA, 0x46, 0x80, 0xC1, 0x5A, 0x08, + 0x04, 0x08, 0xEA, 0x6B, 0xC0, 0x05, 0xDD, 0x43, 0x5A, 0x08, 0x02, 0x34, 0xD5, 0x15, 0x44, 0x93, + 0x8D, 0x30, 0xDD, 0x43, 0x5A, 0x00, 0x02, 0xF9, 0x2E, 0x77, 0xEE, 0xEE, 0xCF, 0xF5, 0x84, 0x01, + 0xDD, 0x57, 0x84, 0x61, 0x12, 0x74, 0x80, 0x00, 0x84, 0x02, 0x80, 0x27, 0x80, 0x47, 0x80, 0x83, + 0x80, 0xA3, 0xDD, 0x56, 0xD5, 0xEF, 0x84, 0x20, 0x49, 0xFF, 0xDC, 0x94, 0xDD, 0x40, 0xC8, 0x0D, + 0xFA, 0x01, 0xDD, 0x57, 0x44, 0x1F, 0xFF, 0xA5, 0x44, 0x03, 0xF4, 0x38, 0xAE, 0x40, 0x84, 0x20, + 0x44, 0x03, 0xF4, 0x39, 0xAE, 0x40, 0xD5, 0x0D, 0x44, 0x1F, 0xFF, 0xE3, 0x44, 0x03, 0xF4, 0x3A, + 0xAE, 0x40, 0xDD, 0x5B, 0xEA, 0x21, 0xAE, 0x88, 0xA6, 0x40, 0x5A, 0x18, 0xFF, 0xFF, 0xD5, 0xE9, + 0x84, 0x02, 0xDD, 0x57, 0x84, 0x41, 0x44, 0x00, 0x01, 0xA0, 0x44, 0x10, 0x00, 0x30, 0x80, 0x62, + 0x80, 0x82, 0xEA, 0xA7, 0x84, 0x20, 0x84, 0x61, 0x44, 0x00, 0x01, 0xA0, 0x80, 0x41, 0x80, 0x83, + 0xEA, 0xA7, 0x5A, 0x00, 0x30, 0x0E, 0x84, 0x41, 0x44, 0x10, 0x00, 0x30, 0x80, 0x62, 0x80, 0x82, + 0x44, 0x00, 0x01, 0xA0, 0xEA, 0xA7, 0x44, 0x00, 0x00, 0xD7, 0xDD, 0x4A, 0xD5, 0xEC, 0xEA, 0x46, + 0x5A, 0x08, 0x04, 0x10, 0xDD, 0x43, 0x5A, 0x00, 0x02, 0x0D, 0x2E, 0x77, 0x34, 0x0B, 0x5A, 0x78, + 0x01, 0x09, 0x80, 0x07, 0x49, 0x00, 0x47, 0x44, 0x84, 0x00, 0xEA, 0x30, 0x80, 0x07, 0xEB, 0xBF, + 0xEB, 0x02, 0xEB, 0x27, 0x3C, 0x0D, 0xFC, 0x74, 0xC0, 0x07, 0x84, 0x04, 0xDD, 0x57, 0xEA, 0x46, + 0x5A, 0x08, 0x04, 0x0E, 0xD5, 0x09, 0x49, 0x00, 0x47, 0x37, 0x5A, 0x08, 0x01, 0xF8, 0x84, 0x03, + 0xDD, 0x57, 0xEB, 0x2F, 0xD5, 0xF0, 0xDD, 0x43, 0x5A, 0x08, 0x02, 0x06, 0xEA, 0x6E, 0x5A, 0x08, + 0x01, 0x14, 0xD5, 0x04, 0xEA, 0x6B, 0x5A, 0x08, 0x01, 0xFB, 0x84, 0x00, 0x49, 0xFF, 0xE2, 0x25, + 0x44, 0x1F, 0xFF, 0xC3, 0x44, 0x03, 0xF4, 0x29, 0xAE, 0x40, 0xDD, 0x41, 0x84, 0x20, 0xDD, 0x53, + 0x84, 0x02, 0xAE, 0x31, 0xD5, 0x0F, 0x80, 0x46, 0x84, 0x05, 0x84, 0x20, 0xEB, 0xC5, 0xDD, 0x41, + 0x84, 0x20, 0xDD, 0x53, 0x84, 0x02, 0xAE, 0x31, 0x84, 0x01, 0x49, 0x00, 0x48, 0x33, 0x84, 0x05, + 0xDD, 0x57, 0xFC, 0xC0, 0xFC, 0x00, 0xDD, 0x58, 0xA7, 0x80, 0x97, 0xB0, 0x5A, 0x68, 0x01, 0xFE, + 0xDD, 0x41, 0x84, 0x29, 0xAE, 0x41, 0x84, 0x20, 0xDD, 0x53, 0xDD, 0x41, 0xEA, 0x3E, 0xDD, 0x40, + 0x5A, 0x08, 0x01, 0x07, 0xEB, 0xCE, 0xC0, 0xFF, 0x84, 0x00, 0xEA, 0x5F, 0xD5, 0x0F, 0xEB, 0x59, + 0x44, 0x12, 0xBC, 0xE8, 0x80, 0x41, 0x84, 0x66, 0x84, 0x02, 0xDD, 0x42, 0x84, 0x02, 0xEB, 0x01, + 0x80, 0x41, 0x80, 0x60, 0x3C, 0x6B, 0xF7, 0xDF, 0xDD, 0x42, 0x49, 0x00, 0x3E, 0xBC, 0x84, 0x01, + 0x3E, 0x07, 0xF2, 0xB5, 0x84, 0x01, 0xEA, 0x30, 0xEA, 0x43, 0xC0, 0xFF, 0xDD, 0x41, 0x84, 0x2A, + 0xAE, 0x41, 0xEA, 0x3E, 0xDD, 0x40, 0x5A, 0x08, 0x01, 0x07, 0xEB, 0xCE, 0xC0, 0xFF, 0x84, 0x00, + 0xEA, 0x5F, 0xD5, 0x0E, 0x44, 0x13, 0x31, 0x38, 0x80, 0x41, 0xEA, 0x4F, 0x84, 0x02, 0xDD, 0x42, + 0x84, 0x01, 0xEA, 0x5F, 0xEB, 0x01, 0x84, 0x02, 0x80, 0x41, 0x80, 0x60, 0xDD, 0x42, 0xFC, 0x80, + 0xFC, 0x00, 0xEA, 0xAE, 0x5A, 0x00, 0x01, 0x04, 0x48, 0x00, 0x00, 0x6B, 0xDD, 0x43, 0x4E, 0x03, + 0x00, 0x68, 0xDD, 0x58, 0xA6, 0x40, 0x5A, 0x18, 0x01, 0xFF, 0xA6, 0x00, 0x5A, 0x08, 0x01, 0x61, + 0xDD, 0x4B, 0xA6, 0x00, 0x5A, 0x08, 0x01, 0x5D, 0x2E, 0x07, 0xF2, 0xB5, 0x5A, 0x08, 0x02, 0x06, + 0x84, 0x00, 0x3E, 0x07, 0xF2, 0xB5, 0xD5, 0x09, 0xDD, 0x41, 0x84, 0x29, 0xAE, 0x41, 0x84, 0x20, + 0xDD, 0x53, 0xDD, 0x41, 0x84, 0x2A, 0xAE, 0x41, 0xDD, 0x40, 0x80, 0xC0, 0xDD, 0x58, 0xC6, 0x0D, + 0x84, 0x20, 0xAE, 0x40, 0xDD, 0x4B, 0xAE, 0x40, 0x84, 0x01, 0xEA, 0x30, 0x84, 0x08, 0xEB, 0x9C, + 0x2E, 0x07, 0xF2, 0xBD, 0xEB, 0x68, 0xD5, 0x3C, 0xAF, 0x80, 0xDD, 0x4B, 0xAF, 0x80, 0x84, 0x01, + 0xEA, 0x30, 0x44, 0x02, 0xFE, 0xF2, 0xAF, 0x80, 0xDD, 0x47, 0xDD, 0x45, 0xAE, 0x40, 0xEA, 0x43, + 0xC0, 0xFF, 0x49, 0xFF, 0xE0, 0xE6, 0xEA, 0x29, 0xEB, 0x07, 0xAE, 0x08, 0x80, 0x41, 0x84, 0x61, + 0x84, 0x02, 0xDD, 0x42, 0xDD, 0x41, 0xEB, 0xFE, 0xEB, 0x4E, 0x5A, 0x08, 0x01, 0x10, 0x2E, 0x07, + 0xEF, 0x20, 0x5A, 0x08, 0x01, 0x0C, 0xEB, 0x21, 0xC0, 0x09, 0xEA, 0x38, 0x5A, 0x08, 0x01, 0x06, + 0x84, 0x03, 0xEA, 0x26, 0x49, 0x00, 0x39, 0xAA, 0xEA, 0x75, 0xDD, 0x4B, 0x84, 0x21, 0xAE, 0x40, + 0x84, 0x01, 0xEB, 0xF3, 0x5A, 0x00, 0x01, 0x0D, 0xEA, 0x6B, 0x5A, 0x08, 0x01, 0x08, 0xDD, 0x41, + 0xA6, 0x01, 0x5A, 0x08, 0x0A, 0x04, 0x49, 0x00, 0x39, 0x4C, 0x84, 0x00, 0xEA, 0x65, 0xFC, 0x80, + 0xFC, 0x00, 0xEA, 0xAE, 0x5A, 0x08, 0x01, 0x1F, 0xDD, 0x43, 0xC8, 0x1C, 0xDD, 0x58, 0xA6, 0x40, + 0x5A, 0x18, 0x01, 0xFF, 0xA6, 0x00, 0x5A, 0x08, 0x01, 0x16, 0xDD, 0x4B, 0xA7, 0x80, 0x97, 0xB0, + 0x5A, 0x68, 0x01, 0x11, 0xDD, 0x41, 0x84, 0x29, 0xAE, 0x41, 0x84, 0x20, 0xDD, 0x53, 0xDD, 0x41, + 0x84, 0x2A, 0xAE, 0x41, 0xDD, 0x51, 0x84, 0x00, 0xAE, 0x08, 0xDD, 0x50, 0xAE, 0x08, 0x80, 0x06, + 0xEA, 0x30, 0xFC, 0x80, 0xFC, 0x00, 0xDD, 0x41, 0xA6, 0x41, 0x5A, 0x10, 0x06, 0x1C, 0x2E, 0x17, + 0xEE, 0xCB, 0xC9, 0x18, 0x2E, 0x67, 0xEF, 0x4F, 0xCE, 0x15, 0xDD, 0x51, 0xA6, 0x48, 0x5A, 0x18, + 0x01, 0x12, 0xDD, 0x50, 0xA6, 0x48, 0x5A, 0x18, 0x01, 0x0E, 0x80, 0x26, 0xEA, 0xE9, 0xDD, 0x53, + 0xDD, 0x58, 0xAF, 0x80, 0x2E, 0x07, 0xEF, 0x26, 0xC8, 0x03, 0xDD, 0x50, 0xAE, 0x08, 0x84, 0x01, + 0xEA, 0x30, 0xFC, 0x80, 0x84, 0x01, 0xDD, 0x9E, 0x84, 0x01, 0xDD, 0x9E, 0xFC, 0x40, 0x80, 0xC2, + 0x81, 0x20, 0x80, 0xE1, 0x49, 0x00, 0x49, 0x4A, 0x49, 0x00, 0x49, 0x6C, 0x44, 0x20, 0x19, 0x00, + 0xFE, 0x14, 0xE2, 0x06, 0xE8, 0x13, 0x8A, 0xC0, 0x44, 0x21, 0x86, 0xA0, 0x40, 0x23, 0x08, 0x57, + 0x10, 0x24, 0x80, 0x00, 0x44, 0x0E, 0x79, 0x60, 0x96, 0x90, 0x42, 0x61, 0x00, 0x73, 0x44, 0x00, + 0x13, 0x88, 0x40, 0x63, 0x00, 0xD7, 0xAF, 0xB8, 0xFC, 0xC0, 0x84, 0x20, 0x10, 0x14, 0x80, 0x00, + 0xAE, 0x78, 0xFC, 0xC0, 0xFC, 0x00, 0x49, 0x00, 0x49, 0x29, 0x49, 0x00, 0x49, 0x20, 0xFC, 0x80, + 0xFC, 0x01, 0x80, 0xC0, 0x80, 0x01, 0xF2, 0x81, 0x49, 0x00, 0x49, 0x06, 0xF0, 0x01, 0xF8, 0x2E, + 0x84, 0x01, 0x3E, 0x07, 0xF2, 0xE2, 0xA6, 0x30, 0x3E, 0x07, 0xF2, 0xE1, 0x84, 0x00, 0xEB, 0xAC, + 0x84, 0x01, 0x49, 0x00, 0x47, 0x20, 0xEA, 0x9E, 0x2E, 0x07, 0xF2, 0xE2, 0x5A, 0x08, 0x01, 0x09, + 0x84, 0x40, 0x80, 0x20, 0x80, 0x62, 0x80, 0x80, 0x80, 0xA2, 0xDD, 0x56, 0xD5, 0xF6, 0xFC, 0x81, + 0xFC, 0x00, 0x80, 0xC0, 0x80, 0x01, 0xA6, 0x48, 0xC1, 0x05, 0x84, 0x21, 0x44, 0x20, 0x00, 0xCD, + 0xF8, 0x07, 0xA6, 0x30, 0xC0, 0x07, 0x80, 0x06, 0x84, 0x24, 0x44, 0x20, 0x00, 0x82, 0x49, 0xFF, + 0xFF, 0xD1, 0x84, 0x07, 0x49, 0x00, 0x48, 0xD8, 0x84, 0x00, 0x49, 0x00, 0x49, 0x0E, 0x84, 0x00, + 0x49, 0x00, 0x46, 0xF9, 0xFC, 0x80, 0xFC, 0x20, 0xA7, 0x80, 0x80, 0xE0, 0xE6, 0xCB, 0xE9, 0x06, + 0x8E, 0xCA, 0x84, 0x0A, 0x97, 0xB0, 0xAE, 0x38, 0xD5, 0x02, 0x84, 0xC0, 0xA6, 0x38, 0xC0, 0x03, + 0x8C, 0x01, 0xAE, 0x38, 0xA6, 0x38, 0xE6, 0x03, 0xE9, 0x03, 0x8C, 0x01, 0xAE, 0x38, 0xA6, 0x38, + 0xC8, 0x03, 0x84, 0x01, 0xAE, 0x38, 0xA6, 0x08, 0xC0, 0x04, 0xEA, 0xBE, 0xFE, 0x0C, 0xEA, 0x39, + 0xC6, 0x05, 0x94, 0x31, 0xEA, 0x8F, 0x49, 0xFF, 0xF8, 0x5A, 0xA6, 0x78, 0xC1, 0x07, 0x84, 0x40, + 0x84, 0x02, 0x84, 0x61, 0x84, 0x83, 0x80, 0xA2, 0xDD, 0x56, 0xFC, 0xA0, 0xFC, 0x02, 0xF0, 0x81, + 0x80, 0xC1, 0xF8, 0x0C, 0xF2, 0x01, 0xF8, 0x6E, 0x5A, 0x68, 0x02, 0x09, 0x84, 0x01, 0x3E, 0x07, + 0xF2, 0xDC, 0xEA, 0xDF, 0xEA, 0xE8, 0xF8, 0x5E, 0xD5, 0x05, 0xEA, 0xE8, 0xEA, 0xDF, 0x83, 0xFF, + 0xF8, 0x65, 0xEA, 0x9E, 0xFC, 0x82, 0xFC, 0x01, 0x80, 0xC0, 0xF2, 0x81, 0xDD, 0x43, 0xC8, 0x28, + 0x5A, 0x60, 0x01, 0x08, 0xC6, 0x04, 0x5A, 0x60, 0x02, 0x09, 0xFC, 0x81, 0xEA, 0x9E, 0xFC, 0x81, + 0xF8, 0x06, 0xF1, 0x01, 0xF8, 0x1B, 0xFC, 0x81, 0x2E, 0x17, 0xF2, 0xDB, 0xEB, 0x19, 0xEA, 0xF4, + 0x83, 0xFF, 0x2E, 0x27, 0xF2, 0xDA, 0xC9, 0x02, 0xC2, 0x10, 0x44, 0x3F, 0xE7, 0x00, 0x42, 0x00, + 0x8C, 0x73, 0x44, 0x11, 0x86, 0xA0, 0xFE, 0x54, 0x84, 0x4A, 0xEB, 0x52, 0x8A, 0x01, 0x84, 0x20, + 0x3E, 0x17, 0xF2, 0xDA, 0x3E, 0x17, 0xF2, 0xDB, 0xF1, 0x01, 0x49, 0xFF, 0xFF, 0xC1, 0xFC, 0x81, + 0xFC, 0x20, 0x80, 0xE0, 0x80, 0xC1, 0xDD, 0x43, 0x5A, 0x08, 0x02, 0x0A, 0xCF, 0x1A, 0xDD, 0x41, + 0xA6, 0x41, 0x5A, 0x10, 0x04, 0x13, 0x49, 0xFF, 0xFE, 0xFF, 0xD5, 0x13, 0xDD, 0x41, 0xA6, 0x41, + 0x5A, 0x10, 0x0B, 0x10, 0x5A, 0x60, 0x04, 0x06, 0x80, 0x06, 0x84, 0x43, 0x49, 0xFF, 0xFF, 0xBD, + 0xDD, 0x41, 0xA6, 0x41, 0x5A, 0x18, 0x09, 0x04, 0xEB, 0xF2, 0xD5, 0x03, 0x49, 0xFF, 0xFE, 0xCA, + 0xFC, 0xA0, 0xFC, 0x02, 0xF0, 0x81, 0xEA, 0xDF, 0xEA, 0xE8, 0xF2, 0x01, 0xF8, 0x0B, 0xEA, 0xE8, + 0xEA, 0xDF, 0x49, 0xFF, 0xFF, 0x6A, 0xFC, 0x82, 0xFC, 0x02, 0xF0, 0x81, 0xEA, 0xDF, 0xEA, 0xE8, + 0xF2, 0x01, 0x49, 0xFF, 0xFE, 0xFD, 0xEA, 0xE8, 0xEA, 0xDF, 0x49, 0xFF, 0xFF, 0x43, 0xFC, 0x82, + 0xFC, 0x00, 0x46, 0x00, 0x00, 0xD6, 0x50, 0x00, 0x0D, 0x80, 0xF8, 0x0D, 0xFC, 0x80, 0xFC, 0x00, + 0xEA, 0x9E, 0xFC, 0x80, 0xFC, 0x00, 0xEA, 0x9E, 0xFC, 0x80, 0xFC, 0x00, 0x46, 0x00, 0x00, 0xD6, + 0x50, 0x00, 0x0D, 0x80, 0x49, 0xFF, 0xFF, 0xD7, 0xFC, 0x80, 0xFC, 0x00, 0xEB, 0x19, 0xEA, 0xF4, + 0xEA, 0xFE, 0xFC, 0x80, 0xFC, 0x00, 0xEA, 0x9E, 0xFC, 0x80, 0xFC, 0x00, 0xEB, 0x19, 0xEA, 0xF4, + 0xEA, 0xFE, 0xFC, 0x80, 0xFC, 0x00, 0xEA, 0x9E, 0xFC, 0x80, 0xFC, 0x00, 0xEB, 0x19, 0xEA, 0xF4, + 0xEA, 0xFE, 0xFC, 0x80, 0xFC, 0x00, 0x2E, 0x07, 0xF2, 0xD7, 0x5A, 0x08, 0x01, 0x10, 0xDD, 0x52, + 0x84, 0xC0, 0x3E, 0x67, 0xF2, 0xD7, 0x5A, 0x08, 0x02, 0x0D, 0x2E, 0x07, 0xF2, 0xD8, 0x5A, 0x08, + 0x02, 0x09, 0xEB, 0x6C, 0x3E, 0x67, 0xF2, 0xD8, 0xD5, 0x04, 0xEA, 0xD0, 0xEB, 0x33, 0xEB, 0x5A, + 0xFC, 0x80, 0xFC, 0x00, 0x80, 0xC0, 0xDD, 0x43, 0xC8, 0x09, 0xA6, 0x71, 0x8E, 0x29, 0xE6, 0x23, + 0xE8, 0x05, 0xEA, 0xB4, 0x84, 0x01, 0x3E, 0x07, 0xEF, 0x71, 0xFC, 0x80, 0xE6, 0x0C, 0xE9, 0x08, + 0x44, 0x10, 0x13, 0x88, 0x8E, 0x0C, 0xFE, 0x0C, 0x50, 0x00, 0x27, 0x10, 0xDD, 0x9E, 0xE6, 0x04, + 0xE8, 0x05, 0x44, 0x10, 0x01, 0xF4, 0xFE, 0x0C, 0xDD, 0x9E, 0xEB, 0xD2, 0x8E, 0x02, 0xFE, 0x0C, + 0xDD, 0x9E, 0x5A, 0x08, 0x04, 0x08, 0xFC, 0x00, 0xEA, 0x61, 0xEA, 0x28, 0xEA, 0x36, 0xF8, 0x02, + 0xFC, 0x80, 0xDD, 0x50, 0x84, 0x01, 0xAE, 0x08, 0xEA, 0xAF, 0x83, 0xFF, 0xDD, 0x9E, 0xFC, 0x00, + 0x3C, 0x0F, 0xFD, 0x09, 0xDD, 0x40, 0xC8, 0x05, 0xF8, 0x07, 0x3C, 0x0F, 0xFC, 0x88, 0xD5, 0x0E, + 0xF8, 0x03, 0x3C, 0x0F, 0xFC, 0x89, 0x49, 0xFF, 0xF7, 0x96, 0x3C, 0x1D, 0xFD, 0x09, 0xA6, 0x8A, + 0xA6, 0x4B, 0x42, 0x01, 0x04, 0x73, 0x3C, 0x0F, 0xFC, 0x87, 0xFC, 0x80, 0xFC, 0x00, 0x44, 0x13, + 0xF6, 0x92, 0x80, 0xC0, 0x84, 0x03, 0xAE, 0x08, 0xFA, 0x4F, 0x44, 0x13, 0xF6, 0xAE, 0xAE, 0x88, + 0x44, 0x13, 0xF6, 0xAF, 0xAE, 0x08, 0x44, 0x23, 0xF6, 0xA0, 0x84, 0x20, 0x44, 0x03, 0xF6, 0xA1, + 0xAE, 0x50, 0xAE, 0x40, 0x44, 0x03, 0xF6, 0xA2, 0xAE, 0x40, 0x44, 0x03, 0xF6, 0xA3, 0xAE, 0x40, + 0x44, 0x03, 0xF6, 0xA4, 0xAE, 0x40, 0x44, 0x03, 0xF6, 0xA5, 0xAE, 0x40, 0x44, 0x03, 0xF6, 0xA6, + 0xAE, 0x40, 0xA6, 0xF0, 0x40, 0x11, 0x0C, 0x7C, 0xA6, 0x08, 0x54, 0x21, 0x80, 0x07, 0x84, 0x61, + 0x40, 0x21, 0x88, 0x0C, 0xFE, 0x87, 0x84, 0x00, 0xAE, 0x88, 0xFA, 0x6F, 0x80, 0x20, 0x80, 0x40, + 0xEA, 0x4B, 0xA6, 0x70, 0x5C, 0xF0, 0x80, 0x32, 0xE8, 0x03, 0x8C, 0x21, 0xAE, 0x70, 0xFC, 0x80, + 0xFC, 0x00, 0x8E, 0x23, 0x96, 0x48, 0xE6, 0x28, 0xE8, 0x1C, 0x84, 0x61, 0x40, 0x11, 0x84, 0x0C, + 0x54, 0x30, 0x80, 0xB1, 0xCB, 0x04, 0x96, 0x56, 0xC9, 0x0F, 0xFC, 0x80, 0x50, 0x00, 0x00, 0x56, + 0x96, 0x00, 0xE6, 0x02, 0xE9, 0x0E, 0x84, 0x01, 0x80, 0xC2, 0x3E, 0x07, 0xEF, 0x21, 0xDD, 0x40, + 0x84, 0x02, 0xAE, 0x30, 0xFC, 0x80, 0x50, 0x00, 0x00, 0x56, 0x96, 0x00, 0xE6, 0x05, 0xD5, 0xF3, + 0xFC, 0x80, 0xFC, 0x41, 0x81, 0x20, 0xF3, 0x81, 0x84, 0x00, 0x84, 0x61, 0x80, 0xC1, 0x80, 0xE2, + 0x3E, 0x37, 0xEF, 0x0E, 0x3E, 0x07, 0xEF, 0x5F, 0x3E, 0x07, 0xEF, 0x3F, 0x3E, 0x07, 0xEF, 0x1A, + 0x3E, 0x37, 0xEF, 0x65, 0x5A, 0x28, 0x03, 0x05, 0x3E, 0x37, 0xEE, 0xCB, 0xD5, 0x07, 0x3E, 0x37, + 0xEF, 0x4F, 0x5A, 0x98, 0xAD, 0x04, 0x3E, 0x37, 0xEF, 0x1A, 0x50, 0x04, 0x80, 0x55, 0x96, 0x00, + 0xE6, 0x02, 0xE8, 0x06, 0x84, 0x04, 0x49, 0xFF, 0xE3, 0x43, 0x3E, 0x97, 0xEF, 0x73, 0x54, 0x03, + 0x00, 0x02, 0xC0, 0x17, 0x5A, 0x78, 0x03, 0x0A, 0xDD, 0x40, 0xC0, 0x04, 0x44, 0x02, 0x32, 0x20, + 0xD5, 0x21, 0x44, 0x02, 0x72, 0x20, 0xD5, 0x1E, 0xDD, 0x40, 0xC0, 0x04, 0x44, 0x02, 0x32, 0x24, + 0xD5, 0x03, 0x44, 0x02, 0x72, 0x24, 0xF8, 0x16, 0x84, 0x00, 0x3E, 0x07, 0xEF, 0x74, 0xD5, 0x14, + 0xDD, 0x40, 0x49, 0xFF, 0xE3, 0x13, 0xCE, 0x0B, 0x5A, 0x70, 0x03, 0xE8, 0xDD, 0x40, 0xC0, 0x04, + 0x44, 0x02, 0x32, 0x24, 0xD5, 0x07, 0x44, 0x02, 0x72, 0x24, 0xD5, 0x04, 0x5A, 0x68, 0x01, 0x05, + 0xF0, 0x01, 0x49, 0x00, 0x49, 0x61, 0xDD, 0x4B, 0x84, 0x21, 0xAE, 0x40, 0xFC, 0xC1, 0xFC, 0x00, + 0xEA, 0x68, 0x2E, 0x17, 0xEF, 0x5B, 0x5A, 0x18, 0x01, 0x07, 0x84, 0x40, 0x3E, 0x27, 0xEF, 0x33, + 0x3E, 0x17, 0xEE, 0xC3, 0x84, 0x20, 0x3E, 0x17, 0xEE, 0xBA, 0x3E, 0x17, 0xEF, 0x2D, 0x3E, 0x17, + 0xEF, 0x56, 0x3E, 0x17, 0xEE, 0xCB, 0x3E, 0x17, 0xEF, 0x5B, 0x3E, 0x17, 0xEF, 0x1A, 0x3E, 0x17, + 0xEF, 0x4F, 0x3E, 0x17, 0xEF, 0x25, 0x3E, 0x17, 0xEF, 0x20, 0x3E, 0x17, 0xEF, 0x49, 0x3E, 0x17, + 0xEF, 0x04, 0x3E, 0x17, 0xEE, 0xE0, 0x10, 0x10, 0x00, 0x50, 0xFC, 0x80, 0xFC, 0x20, 0x80, 0xC0, + 0xEA, 0x68, 0x80, 0xE0, 0x2E, 0x07, 0xEF, 0x5F, 0xEB, 0x4F, 0xE9, 0x5F, 0x84, 0x00, 0xEA, 0x9A, + 0x84, 0x00, 0x3E, 0x07, 0xEF, 0x5F, 0x3E, 0x07, 0xEF, 0x3F, 0xDD, 0x40, 0xC8, 0x08, 0xEB, 0x7A, + 0xEA, 0x91, 0xDD, 0x40, 0xC8, 0x26, 0xEA, 0x21, 0xDD, 0x5B, 0xD5, 0x27, 0xEB, 0xF7, 0x3C, 0x4D, + 0xFD, 0x09, 0xEB, 0xB5, 0xEB, 0x3D, 0x92, 0x30, 0xEA, 0x64, 0x40, 0x10, 0x04, 0x40, 0xB4, 0x41, + 0x84, 0x00, 0x92, 0x4A, 0x96, 0xB7, 0x44, 0x53, 0x00, 0x00, 0xFB, 0x88, 0x02, 0x12, 0x00, 0x1A, + 0xE2, 0x01, 0xE8, 0xE6, 0x94, 0xC1, 0x98, 0x5D, 0xA4, 0x48, 0xB5, 0xA6, 0x42, 0x10, 0xC0, 0x24, + 0x88, 0x71, 0x40, 0x10, 0x88, 0x37, 0x8C, 0x01, 0x96, 0x49, 0xAC, 0x58, 0x96, 0x01, 0xD5, 0xEF, + 0xEA, 0x61, 0xEA, 0x28, 0xEA, 0x36, 0xD5, 0x07, 0x00, 0x03, 0x80, 0x51, 0x5A, 0x00, 0xBB, 0x04, + 0xAE, 0x88, 0xD5, 0xFB, 0xDD, 0x4B, 0x84, 0x21, 0xAE, 0x40, 0x84, 0x00, 0x44, 0x13, 0xF6, 0x92, + 0xAE, 0x08, 0x44, 0x13, 0xF6, 0xAE, 0xAE, 0x08, 0x44, 0x13, 0xF6, 0xAF, 0xAE, 0x08, 0x84, 0x00, + 0x80, 0x20, 0x80, 0x40, 0xFA, 0x6F, 0xEA, 0x4B, 0xEA, 0x75, 0xDD, 0x40, 0xC0, 0x07, 0xEA, 0x7C, + 0xEB, 0xD3, 0xDD, 0x5D, 0xEA, 0x7C, 0xB4, 0x26, 0xDD, 0x5D, 0x84, 0x00, 0x3E, 0x07, 0xEF, 0x0E, + 0x84, 0x01, 0xEA, 0x2D, 0xEA, 0x2A, 0xF8, 0x75, 0xFC, 0xA0, 0xFC, 0x20, 0x80, 0xC0, 0xEA, 0x68, + 0x80, 0xE0, 0x2E, 0x07, 0xEF, 0x5F, 0x5A, 0x08, 0x02, 0x0E, 0xDD, 0x40, 0x4E, 0x02, 0x00, 0x6C, + 0xDD, 0x47, 0xDD, 0x45, 0xAE, 0x40, 0xEB, 0x6A, 0xC0, 0xFF, 0xEA, 0x4A, 0xB4, 0x26, 0xDD, 0x5D, + 0xD5, 0x62, 0xE6, 0x03, 0xE9, 0x60, 0x84, 0x00, 0xEA, 0x9A, 0xDD, 0x40, 0xC8, 0x04, 0xDD, 0x40, + 0xC8, 0x1C, 0xD5, 0x13, 0x3C, 0x0D, 0xFD, 0x09, 0x84, 0xA0, 0x02, 0x00, 0x00, 0x1A, 0x44, 0x33, + 0x00, 0x00, 0x92, 0x01, 0x94, 0x01, 0xD0, 0xF4, 0x98, 0xAB, 0xB4, 0x26, 0xA4, 0x90, 0x88, 0x25, + 0x96, 0x91, 0xAC, 0x88, 0x8C, 0xA2, 0xD5, 0xF8, 0x44, 0x00, 0x00, 0x42, 0xEA, 0x91, 0xDD, 0x40, + 0xC8, 0x24, 0xEA, 0x21, 0xDD, 0x5B, 0xD5, 0x25, 0xEB, 0xF7, 0x44, 0x2F, 0xFE, 0x01, 0xEB, 0xB5, + 0x44, 0x02, 0x00, 0x60, 0x92, 0x30, 0xEA, 0x64, 0x40, 0x10, 0x04, 0x40, 0xB4, 0x21, 0x3C, 0x0D, + 0xFD, 0x09, 0x92, 0x2A, 0x96, 0x77, 0xFE, 0x54, 0x02, 0x40, 0x00, 0x1A, 0x96, 0x49, 0x84, 0x40, + 0x96, 0x11, 0xE2, 0x04, 0xE8, 0xE2, 0xB4, 0x66, 0x40, 0x31, 0x88, 0x20, 0xA4, 0x18, 0x8C, 0x41, + 0x88, 0x01, 0x96, 0x01, 0xAC, 0x18, 0xD5, 0xF5, 0xEA, 0x61, 0xEA, 0x28, 0xEA, 0x36, 0xD5, 0x07, + 0x00, 0x03, 0x80, 0x51, 0x5A, 0x00, 0xBB, 0x04, 0xAE, 0x88, 0xD5, 0xFB, 0xDD, 0x4B, 0x84, 0x21, + 0xAE, 0x40, 0xEA, 0x75, 0xDD, 0x40, 0xC0, 0x07, 0xEA, 0x7C, 0xEB, 0xD3, 0xDD, 0x5D, 0xEA, 0x7C, + 0xB4, 0x26, 0xDD, 0x5D, 0x84, 0x00, 0x3E, 0x07, 0xEF, 0x0E, 0x84, 0x01, 0xEA, 0x2D, 0xEA, 0x2A, + 0x49, 0xFF, 0xE1, 0xF1, 0x84, 0x01, 0xFC, 0xA0, 0xFC, 0x00, 0x2E, 0x07, 0xEE, 0xCB, 0x5A, 0x08, + 0x01, 0x06, 0xEA, 0x24, 0x49, 0xFF, 0xFF, 0x1C, 0xD5, 0x08, 0x2E, 0x07, 0xEF, 0x4F, 0x5A, 0x08, + 0x01, 0x0E, 0xEA, 0x24, 0x49, 0xFF, 0xFF, 0x7B, 0xDD, 0x55, 0xF9, 0x83, 0x2E, 0x07, 0xEF, 0x5F, + 0x8C, 0x01, 0x3E, 0x07, 0xEF, 0x5F, 0xFA, 0x03, 0xFC, 0x80, 0x84, 0x01, 0xFC, 0x80, 0xFC, 0x43, + 0x81, 0x20, 0x2E, 0x17, 0xEF, 0x5B, 0x3C, 0x0D, 0xFD, 0x09, 0x04, 0x64, 0x80, 0x05, 0x02, 0x70, + 0x00, 0x1A, 0x5A, 0x18, 0x01, 0x07, 0x2E, 0x77, 0x33, 0x8B, 0x04, 0x64, 0x80, 0x0C, 0x95, 0xFA, + 0x3C, 0x03, 0xF7, 0xD1, 0x3C, 0x23, 0xF7, 0xCC, 0xE2, 0x02, 0x4E, 0xF2, 0x00, 0x8A, 0x8C, 0x01, + 0x3C, 0x0B, 0xF7, 0xD1, 0x84, 0x00, 0x3E, 0x07, 0xF4, 0x23, 0xDD, 0x40, 0x4E, 0x02, 0x00, 0xD0, + 0x3C, 0x03, 0xF7, 0xD1, 0xE6, 0x03, 0xE9, 0x04, 0x80, 0x26, 0x84, 0x00, 0xD5, 0x5F, 0xEB, 0xF8, + 0xA6, 0x40, 0x96, 0x48, 0x3E, 0x17, 0xF4, 0x22, 0x96, 0x67, 0x58, 0x10, 0x80, 0xA0, 0xAE, 0x40, + 0xEB, 0x3C, 0x49, 0xFF, 0xFD, 0xE6, 0x84, 0x00, 0x44, 0x2F, 0xFF, 0x80, 0x44, 0x30, 0x00, 0x7F, + 0x96, 0x41, 0xE2, 0x27, 0xE8, 0x0B, 0x3C, 0x1D, 0xFC, 0x89, 0x38, 0x20, 0x80, 0x08, 0x3C, 0x1D, + 0xFC, 0x87, 0x38, 0x30, 0x80, 0x08, 0x8C, 0x01, 0xD5, 0xF4, 0xEA, 0x38, 0x5A, 0x08, 0x01, 0x18, + 0x3C, 0x2D, 0xFD, 0x09, 0x3C, 0x3C, 0x03, 0x26, 0x3C, 0x4C, 0x03, 0x25, 0x84, 0x00, 0x00, 0x11, + 0x00, 0x10, 0x94, 0x4A, 0xE0, 0x01, 0x4E, 0xF2, 0x00, 0x9B, 0x94, 0x41, 0x99, 0x59, 0x88, 0x24, + 0xA4, 0x48, 0x8C, 0x01, 0x96, 0x49, 0xAC, 0x68, 0x96, 0x01, 0xD5, 0xF2, 0x3C, 0x0C, 0x03, 0x1C, + 0x3C, 0x1C, 0x03, 0x1E, 0xDD, 0x5D, 0x48, 0x00, 0x00, 0x8B, 0x3C, 0x5D, 0xFC, 0x89, 0x3C, 0x2D, + 0xFC, 0x87, 0x2E, 0x47, 0xEF, 0x5B, 0x88, 0xA0, 0x20, 0x32, 0x80, 0x00, 0x38, 0x21, 0x00, 0x10, + 0x5A, 0x48, 0x01, 0x06, 0xA5, 0x08, 0x97, 0x23, 0x90, 0x82, 0xAD, 0x08, 0xA5, 0x08, 0x97, 0x23, + 0xE0, 0x64, 0xE9, 0x10, 0xA5, 0x08, 0x97, 0x23, 0xE0, 0x82, 0xE9, 0x17, 0xAE, 0xE8, 0x3C, 0x3D, + 0xFC, 0x87, 0x8C, 0x22, 0x38, 0x21, 0x80, 0x08, 0x8C, 0x01, 0x96, 0x81, 0xE2, 0x47, 0xE9, 0xDE, + 0xD5, 0x66, 0xA4, 0xC8, 0x96, 0xDB, 0x5E, 0xF1, 0x80, 0x80, 0xE8, 0x04, 0xA4, 0xC8, 0x96, 0xDB, + 0xD5, 0xEA, 0x44, 0x30, 0x00, 0x7F, 0xD5, 0xE7, 0xA4, 0x88, 0x96, 0x93, 0x5E, 0xF1, 0x7F, 0x81, + 0xE9, 0x04, 0xA4, 0x88, 0x96, 0x93, 0xD5, 0xE3, 0x44, 0x2F, 0xFF, 0x81, 0xD5, 0xE0, 0xDD, 0x52, + 0x5A, 0x00, 0x01, 0x04, 0x5A, 0x18, 0x01, 0x29, 0xDD, 0x40, 0xC0, 0x0B, 0xEA, 0x38, 0x5A, 0x00, + 0x01, 0x06, 0xDD, 0x41, 0xA6, 0x01, 0x5A, 0x08, 0x0A, 0x20, 0x84, 0x01, 0xEB, 0x32, 0xD5, 0x1C, + 0xEB, 0x12, 0x5A, 0x00, 0x01, 0x0B, 0x84, 0x01, 0xEB, 0x32, 0x84, 0x02, 0x12, 0x0F, 0x80, 0x04, + 0xB0, 0x42, 0x44, 0x02, 0xBC, 0x08, 0xD5, 0x1B, 0x2E, 0x07, 0xF4, 0x23, 0x8C, 0x01, 0x96, 0x00, + 0xE6, 0x02, 0x3E, 0x07, 0xF4, 0x23, 0xE8, 0x05, 0xDD, 0x58, 0xA6, 0x00, 0x5A, 0x08, 0x01, 0x28, + 0x84, 0x01, 0xEB, 0xEC, 0xD5, 0x21, 0xEB, 0x21, 0x5A, 0x00, 0x01, 0x11, 0x84, 0x01, 0xEB, 0xEC, + 0x84, 0x02, 0x12, 0x0F, 0x80, 0x04, 0xB0, 0x42, 0x44, 0x02, 0xBC, 0x00, 0xF0, 0x84, 0xA8, 0x09, + 0x3A, 0x10, 0x90, 0x00, 0xEA, 0x62, 0xEA, 0x82, 0xD5, 0x12, 0x2E, 0x07, 0xF4, 0x23, 0x8C, 0x01, + 0x96, 0x00, 0xE6, 0x02, 0x3E, 0x07, 0xF4, 0x23, 0xE8, 0x05, 0xDD, 0x58, 0xA6, 0x00, 0x5A, 0x08, + 0x01, 0x07, 0x84, 0x01, 0xEB, 0x32, 0x84, 0x00, 0x3E, 0x07, 0xF4, 0x23, 0xEB, 0x21, 0xC0, 0x56, + 0xEB, 0x12, 0xC0, 0x54, 0x84, 0x00, 0xEA, 0x9A, 0xDD, 0x40, 0xC0, 0x1D, 0x3C, 0x4D, 0xFC, 0x89, + 0x3C, 0x5D, 0xFC, 0x87, 0x84, 0x20, 0x96, 0x09, 0xE2, 0x07, 0xE8, 0x11, 0x38, 0x02, 0x04, 0x10, + 0x38, 0x22, 0x84, 0x00, 0x80, 0xC9, 0xA0, 0xF5, 0x40, 0x21, 0x01, 0x04, 0x94, 0x09, 0x88, 0x60, + 0xAC, 0x98, 0xA0, 0xF6, 0x8C, 0x21, 0x88, 0x03, 0xAC, 0x80, 0xD5, 0xEE, 0x2E, 0x17, 0xF4, 0x22, + 0xEB, 0xF8, 0xAE, 0x40, 0xEA, 0x38, 0x5A, 0x00, 0x01, 0x05, 0x44, 0x00, 0x00, 0x43, 0xEA, 0x91, + 0xEA, 0x61, 0xEA, 0x28, 0xEA, 0x36, 0xEA, 0x38, 0x5A, 0x08, 0x01, 0x25, 0xDD, 0x43, 0x5A, 0x08, + 0x02, 0x07, 0x84, 0x03, 0xEA, 0x26, 0x49, 0x00, 0x34, 0xC9, 0xD5, 0x1C, 0x2E, 0x67, 0x34, 0x0B, + 0x5A, 0x68, 0x01, 0x19, 0xDD, 0x41, 0xA6, 0x01, 0x5A, 0x08, 0x09, 0x15, 0xEA, 0x26, 0x84, 0x05, + 0xDD, 0x4F, 0xEA, 0x45, 0xEB, 0x10, 0x84, 0x06, 0xDD, 0x4F, 0xEA, 0x75, 0xDD, 0x41, 0x49, 0x00, + 0x34, 0x25, 0xF0, 0x81, 0x84, 0x40, 0x84, 0x02, 0xF1, 0x01, 0x80, 0x66, 0x80, 0x86, 0x80, 0xA2, + 0xDD, 0x56, 0xEA, 0x75, 0x84, 0x01, 0xEA, 0x2D, 0xD5, 0x29, 0x2E, 0x67, 0xEF, 0x5B, 0x5A, 0x68, + 0x01, 0x26, 0xDD, 0x43, 0x5A, 0x08, 0x02, 0x09, 0x84, 0x04, 0xEA, 0x26, 0xDD, 0x41, 0x80, 0x26, + 0xDD, 0x53, 0xEB, 0x41, 0xD5, 0x1B, 0x2E, 0x67, 0x34, 0x0B, 0x5A, 0x68, 0x01, 0x18, 0xDD, 0x41, + 0xA6, 0x01, 0x5A, 0x08, 0x09, 0x14, 0xEA, 0x26, 0x84, 0x05, 0xDD, 0x4F, 0xEA, 0x45, 0xEB, 0x10, + 0x84, 0x06, 0xDD, 0x4F, 0xDD, 0x41, 0x49, 0x00, 0x33, 0xF9, 0xF0, 0x81, 0x84, 0x40, 0x84, 0x02, + 0xF1, 0x01, 0x80, 0x66, 0x80, 0x86, 0x80, 0xA2, 0xDD, 0x56, 0xFC, 0xC3, 0xFC, 0x00, 0x2E, 0x07, + 0xEF, 0x2D, 0x5A, 0x08, 0x01, 0x0A, 0x84, 0x00, 0xEA, 0x9A, 0x49, 0x00, 0x30, 0x4D, 0xDD, 0x55, + 0x49, 0xFF, 0xFC, 0x91, 0xD5, 0x0F, 0xEA, 0x38, 0x5A, 0x08, 0x01, 0x0F, 0x2E, 0x17, 0xEE, 0xE0, + 0x5A, 0x18, 0x01, 0x0C, 0x84, 0x00, 0xEA, 0x42, 0x84, 0x00, 0xEA, 0x6C, 0xEA, 0x85, 0xEA, 0x24, + 0xF9, 0x20, 0xFA, 0x03, 0xD5, 0x02, 0x84, 0x01, 0xFC, 0x80, 0xFC, 0x22, 0xEA, 0x68, 0x80, 0xC0, + 0x3C, 0x13, 0xF7, 0xCC, 0x3C, 0x03, 0xF7, 0xD1, 0xE2, 0x01, 0x4E, 0xF2, 0x00, 0xB0, 0x8C, 0x01, + 0x96, 0x01, 0x84, 0x20, 0x3C, 0x0B, 0xF7, 0xD1, 0x3E, 0x17, 0xF4, 0x21, 0x5A, 0x08, 0x01, 0x3B, + 0xEB, 0xF8, 0xA6, 0x40, 0x96, 0x48, 0x3E, 0x17, 0xF4, 0x20, 0x96, 0x67, 0x58, 0x10, 0x80, 0xA0, + 0xAE, 0x40, 0xEB, 0x3C, 0x49, 0xFF, 0xFC, 0x6D, 0x3C, 0x1D, 0xFC, 0x88, 0x84, 0x40, 0x80, 0x01, + 0x80, 0x61, 0x80, 0xE2, 0x44, 0x5F, 0x80, 0x00, 0x44, 0x40, 0x7F, 0xFF, 0x5C, 0xF1, 0x00, 0xC0, + 0xE8, 0x09, 0xAD, 0x58, 0x12, 0x41, 0x83, 0x20, 0x12, 0x51, 0x81, 0x90, 0x12, 0x41, 0x84, 0xB0, + 0xD5, 0x08, 0xAD, 0xC0, 0x12, 0x70, 0x03, 0x20, 0x12, 0x70, 0x01, 0x90, 0x12, 0x70, 0x04, 0xB0, + 0x8C, 0x41, 0x96, 0x91, 0x12, 0x50, 0x80, 0xC8, 0x12, 0x40, 0x83, 0xE8, 0x12, 0x50, 0x82, 0x58, + 0x12, 0x40, 0x85, 0x78, 0x8C, 0x62, 0x8C, 0x22, 0x8C, 0x02, 0x5A, 0x28, 0xC8, 0xE1, 0x48, 0x00, + 0x00, 0x8E, 0x3C, 0x1D, 0xFC, 0x88, 0x84, 0x00, 0x80, 0x41, 0x45, 0x02, 0xA5, 0x0A, 0x44, 0x7F, + 0x80, 0x00, 0x45, 0x12, 0xA8, 0x2A, 0x40, 0x50, 0x40, 0x00, 0xA5, 0x68, 0x22, 0x31, 0x03, 0x20, + 0x97, 0x6B, 0x22, 0x41, 0x00, 0x00, 0xE0, 0xA3, 0x42, 0x42, 0x90, 0x00, 0xE8, 0x06, 0xDF, 0x04, + 0x44, 0x3F, 0x80, 0x01, 0xD5, 0x02, 0x80, 0x65, 0xAD, 0x10, 0x12, 0x31, 0x03, 0x20, 0x40, 0x50, + 0x44, 0x00, 0xA5, 0x68, 0x22, 0x31, 0x04, 0xB0, 0x97, 0x6B, 0x22, 0x41, 0x01, 0x90, 0xE0, 0xA3, + 0x42, 0x42, 0x90, 0x00, 0xE8, 0x06, 0xDF, 0x04, 0x44, 0x3F, 0x80, 0x01, 0xD5, 0x02, 0x80, 0x65, + 0x8C, 0x02, 0x12, 0x41, 0x01, 0x90, 0x12, 0x31, 0x04, 0xB0, 0x8C, 0x42, 0x5A, 0x09, 0x80, 0xD5, + 0x84, 0x00, 0x44, 0x72, 0xA6, 0x9A, 0x44, 0x4F, 0x80, 0x00, 0x45, 0x02, 0xA9, 0xBA, 0x99, 0x47, + 0xA5, 0x68, 0x22, 0x20, 0x83, 0xE8, 0x97, 0x6B, 0x22, 0x30, 0x80, 0xC8, 0xE0, 0xA2, 0x42, 0x32, + 0x8C, 0x00, 0xE8, 0x06, 0xDC, 0x04, 0x44, 0x2F, 0x80, 0x01, 0xD5, 0x02, 0x80, 0x45, 0x12, 0x30, + 0x80, 0xC8, 0x12, 0x20, 0x83, 0xE8, 0x40, 0x50, 0x40, 0x00, 0xA5, 0x68, 0x22, 0x20, 0x85, 0x78, + 0x97, 0x6B, 0x22, 0x30, 0x82, 0x58, 0xE0, 0xA2, 0x42, 0x32, 0x8C, 0x00, 0xE8, 0x06, 0xDC, 0x04, + 0x44, 0x2F, 0x80, 0x01, 0xD5, 0x02, 0x80, 0x45, 0x8C, 0x02, 0x12, 0x30, 0x82, 0x58, 0x12, 0x20, + 0x85, 0x78, 0x8C, 0x22, 0x5A, 0x09, 0x90, 0xD5, 0xD5, 0x21, 0xEB, 0x12, 0x5A, 0x00, 0x01, 0x0E, + 0x84, 0x01, 0xEB, 0x32, 0x84, 0x02, 0xEB, 0x00, 0x44, 0x02, 0xBC, 0x08, 0xF0, 0x82, 0xF0, 0x81, + 0xEA, 0xC7, 0xEA, 0x62, 0xEA, 0x82, 0xD5, 0x12, 0x2E, 0x07, 0xF4, 0x21, 0x8C, 0x01, 0x96, 0x00, + 0xE6, 0x05, 0x3E, 0x07, 0xF4, 0x21, 0xE8, 0x05, 0xDD, 0x58, 0xA6, 0x00, 0x5A, 0x08, 0x01, 0x07, + 0x84, 0x01, 0xEB, 0xEC, 0x84, 0x00, 0x3E, 0x07, 0xF4, 0x21, 0xEB, 0x21, 0xC0, 0x27, 0xEB, 0x12, + 0xC0, 0x25, 0x84, 0x00, 0xEA, 0x9A, 0xEA, 0xCD, 0x3C, 0x2D, 0xFC, 0x88, 0x44, 0x30, 0x06, 0x40, + 0x84, 0x02, 0xDD, 0x42, 0x3C, 0x2D, 0xFC, 0x88, 0xEA, 0xB7, 0x50, 0x21, 0x06, 0x40, 0x44, 0x30, + 0x06, 0x40, 0x84, 0x02, 0xDD, 0x42, 0x44, 0x00, 0x00, 0x43, 0xEA, 0x91, 0xEA, 0x21, 0xDD, 0x5B, + 0x00, 0x03, 0x00, 0x51, 0x5A, 0x00, 0xBB, 0x04, 0xAE, 0x88, 0xD5, 0xFB, 0xEB, 0xF8, 0x2E, 0x17, + 0xF4, 0x20, 0xAE, 0x40, 0xEA, 0x75, 0x84, 0x01, 0xEA, 0x2D, 0xFC, 0xA2, 0x2E, 0x07, 0xEF, 0x20, + 0x5A, 0x08, 0x01, 0x0B, 0xEA, 0x7D, 0x5A, 0x08, 0x01, 0x0A, 0xFC, 0x00, 0xEA, 0x24, 0x49, 0xFF, + 0xFE, 0xF6, 0xF8, 0x04, 0xFC, 0x80, 0x84, 0x01, 0xDD, 0x9E, 0x84, 0x01, 0xEA, 0xAF, 0xFA, 0x03, + 0x83, 0xFF, 0xDD, 0x9E, 0xFC, 0x00, 0x2E, 0x67, 0xEF, 0x20, 0x5A, 0x68, 0x01, 0x16, 0xEA, 0x24, + 0x49, 0xFF, 0xFD, 0x57, 0x84, 0x00, 0xEA, 0x2A, 0xDD, 0x4B, 0xAF, 0x80, 0xDD, 0x43, 0x5A, 0x00, + 0x02, 0x21, 0xEA, 0x6B, 0x5A, 0x08, 0x01, 0x1E, 0xDD, 0x41, 0xA6, 0x01, 0x5A, 0x08, 0x0A, 0x1A, + 0x49, 0x00, 0x32, 0xE7, 0xD5, 0x16, 0x2E, 0x07, 0xEF, 0x49, 0x5A, 0x08, 0x01, 0x15, 0xEA, 0x75, + 0x2E, 0x07, 0xEF, 0x29, 0x49, 0xFF, 0xF2, 0xDF, 0xDD, 0x40, 0xC0, 0x04, 0xEA, 0x61, 0xEA, 0x28, + 0xEA, 0x36, 0xEA, 0xD0, 0xEB, 0x33, 0x49, 0xFF, 0xF2, 0xD6, 0xDD, 0x4B, 0x84, 0x21, 0xAE, 0x40, + 0xFA, 0x03, 0xD5, 0x02, 0x84, 0x01, 0xFC, 0x80, 0xDD, 0x9E, 0xDD, 0x9E, 0xDD, 0x9E, 0xDD, 0x9E, + 0xFC, 0x00, 0x49, 0xFF, 0xDB, 0x39, 0xEA, 0x46, 0x9E, 0x46, 0xE6, 0x22, 0xE9, 0x0A, 0x50, 0x10, + 0x7F, 0xF7, 0xE6, 0x25, 0xE9, 0x06, 0x5A, 0x00, 0x11, 0x05, 0x84, 0x01, 0x48, 0x00, 0x00, 0x69, + 0x49, 0xFF, 0xDF, 0x69, 0xDD, 0x41, 0xA6, 0x01, 0x5A, 0x08, 0x04, 0x07, 0xDD, 0x41, 0xA6, 0x00, + 0x5A, 0x08, 0x02, 0x13, 0xD5, 0x0B, 0x8E, 0x08, 0xE6, 0x04, 0xE9, 0xF9, 0xDD, 0x43, 0x5A, 0x08, + 0x02, 0xF7, 0xFA, 0x31, 0xEA, 0x56, 0xAE, 0x40, 0xD5, 0x28, 0x2E, 0x07, 0xF2, 0xF1, 0xC0, 0x04, + 0x84, 0x00, 0x3E, 0x07, 0xF2, 0xF1, 0x44, 0x10, 0x00, 0xBD, 0x84, 0x04, 0xDD, 0x44, 0x44, 0x00, + 0x00, 0xD0, 0xDD, 0x57, 0xDD, 0x40, 0x80, 0xC0, 0xC0, 0x0F, 0x84, 0x00, 0x49, 0xFF, 0xD5, 0xD1, + 0xEA, 0x29, 0xEA, 0x50, 0xEA, 0x48, 0xA6, 0x08, 0x5A, 0x00, 0x21, 0x04, 0xAE, 0xD0, 0xD5, 0xFC, + 0x84, 0x00, 0xEA, 0x65, 0xD5, 0x0A, 0xEA, 0x29, 0xFA, 0x11, 0xAE, 0x08, 0x80, 0x41, 0x84, 0x02, + 0x84, 0x61, 0xDD, 0x42, 0x3E, 0x67, 0xF2, 0xC5, 0x49, 0x00, 0x3E, 0x88, 0x44, 0x00, 0x00, 0xD1, + 0xDD, 0x57, 0xDD, 0x43, 0x9E, 0x42, 0x84, 0xC0, 0x84, 0x02, 0x40, 0x13, 0x04, 0x06, 0x49, 0xFF, + 0xD4, 0x81, 0xDD, 0x43, 0x5A, 0x08, 0x01, 0x0B, 0x80, 0x06, 0x49, 0x00, 0x40, 0x7D, 0x80, 0x06, + 0x49, 0x00, 0x40, 0x98, 0x80, 0x06, 0x49, 0x00, 0x40, 0x8B, 0x44, 0x00, 0x00, 0xD2, 0xDD, 0x57, + 0xDD, 0x41, 0xEB, 0xBD, 0x3C, 0x2D, 0xFC, 0x0B, 0x44, 0x32, 0xBD, 0x80, 0x49, 0x00, 0x55, 0xCB, + 0x80, 0xC0, 0x5A, 0x08, 0x08, 0x9C, 0x44, 0x00, 0x00, 0xD3, 0xDD, 0x57, 0x80, 0x06, 0xFC, 0x80, + 0xFC, 0x00, 0x84, 0x01, 0xEA, 0x9A, 0x49, 0xFF, 0xEA, 0xB8, 0x49, 0xFF, 0xF4, 0xD9, 0xDD, 0x41, + 0x84, 0x21, 0xAE, 0x41, 0x49, 0xFF, 0xED, 0x5B, 0x44, 0x00, 0x00, 0xA0, 0xEB, 0x98, 0xEB, 0x8B, + 0xDD, 0x5A, 0x49, 0xFF, 0xF7, 0x9B, 0xFC, 0x80, 0xFC, 0x00, 0x84, 0x0F, 0xDD, 0x4A, 0x84, 0x04, + 0x44, 0x10, 0x00, 0x62, 0xDD, 0x44, 0xDD, 0x47, 0xDD, 0x45, 0xAE, 0x40, 0xEA, 0x7B, 0xA6, 0x08, + 0xC8, 0xFF, 0x84, 0x01, 0xEB, 0xE7, 0xFC, 0x80, 0xFC, 0x00, 0x84, 0x04, 0x44, 0x10, 0x00, 0x61, + 0xDD, 0x44, 0x44, 0x10, 0x00, 0x67, 0x84, 0x04, 0xDD, 0x44, 0x84, 0x04, 0xEB, 0x25, 0x44, 0x00, + 0x00, 0xA1, 0xEB, 0x98, 0xDD, 0x41, 0xEB, 0x8D, 0xEA, 0xD7, 0x84, 0x60, 0x49, 0xFF, 0xE4, 0x80, + 0xEA, 0x81, 0x5A, 0x08, 0x01, 0x09, 0x44, 0x02, 0xBB, 0x28, 0xEB, 0x6B, 0x49, 0xFF, 0xF3, 0x01, + 0x49, 0x00, 0x42, 0x3C, 0xDD, 0x51, 0x84, 0x02, 0xAE, 0x08, 0xDD, 0x50, 0xAE, 0x08, 0x49, 0xFF, + 0xFF, 0xCD, 0x84, 0x04, 0x44, 0x10, 0x00, 0x68, 0xDD, 0x44, 0x49, 0xFF, 0xF6, 0x7D, 0xEA, 0x81, + 0x5A, 0x08, 0x01, 0x04, 0x49, 0x00, 0x42, 0x23, 0x49, 0xFF, 0xED, 0xA2, 0x84, 0x02, 0xDD, 0x4A, + 0x84, 0x04, 0x44, 0x10, 0x00, 0x69, 0xDD, 0x44, 0xFC, 0x80, 0xFC, 0x40, 0xEA, 0x68, 0x80, 0xE0, + 0x84, 0x0C, 0xDD, 0x57, 0xDD, 0x47, 0xDD, 0x45, 0xAE, 0x40, 0x84, 0x09, 0x44, 0x10, 0x00, 0xA1, + 0xDD, 0x44, 0x49, 0xFF, 0xF2, 0xA4, 0x84, 0x09, 0x44, 0x10, 0x00, 0xA2, 0xDD, 0x44, 0x84, 0x09, + 0x44, 0x10, 0x00, 0xA3, 0xDD, 0x44, 0xDD, 0x41, 0xA6, 0x41, 0x5A, 0x18, 0x0D, 0x0C, 0x84, 0x09, + 0xEB, 0x53, 0xDD, 0x44, 0x2E, 0x07, 0xEE, 0xD3, 0x5A, 0x08, 0x01, 0x04, 0x48, 0x00, 0x00, 0x64, + 0xD5, 0x0F, 0x2E, 0x17, 0xF3, 0x70, 0xC9, 0xF4, 0x44, 0x12, 0xBB, 0xCF, 0x44, 0x22, 0xBF, 0xCC, + 0x49, 0x00, 0x56, 0x68, 0xEA, 0xDD, 0x5A, 0x08, 0x01, 0xEC, 0x84, 0x01, 0xF8, 0x55, 0x84, 0x09, + 0xEB, 0xC3, 0xDD, 0x44, 0xDD, 0x41, 0xA6, 0x01, 0x5A, 0x00, 0x0A, 0x51, 0x84, 0xC0, 0x2E, 0x07, + 0xF2, 0xBE, 0x4E, 0x03, 0x00, 0x71, 0xDD, 0x55, 0x5A, 0x08, 0x19, 0x04, 0x48, 0x00, 0x00, 0x78, + 0x84, 0x00, 0x3E, 0x07, 0xEE, 0xFF, 0x2E, 0x07, 0xEF, 0x65, 0x4E, 0x02, 0x00, 0x7D, 0x2E, 0x07, + 0xEF, 0x4E, 0x5A, 0x08, 0x01, 0x08, 0x44, 0x02, 0xBB, 0xC6, 0xEA, 0xD5, 0xEA, 0xD7, 0x49, 0xFF, + 0xDC, 0x10, 0xDD, 0x40, 0x4E, 0x03, 0x00, 0x82, 0x3C, 0x0D, 0xFC, 0x58, 0x5A, 0x00, 0x01, 0x03, + 0xF8, 0x22, 0xDD, 0x58, 0xA6, 0x00, 0x5A, 0x00, 0x01, 0x03, 0xF8, 0x1D, 0x84, 0x00, 0xEA, 0x71, + 0xEA, 0x95, 0x5A, 0x00, 0x55, 0x04, 0x48, 0x00, 0x00, 0x9E, 0x2E, 0x07, 0xF2, 0xBF, 0x4E, 0x02, + 0x00, 0x81, 0x84, 0x01, 0xEA, 0x71, 0xEA, 0xC0, 0xDD, 0x55, 0x49, 0xFF, 0xDE, 0x0A, 0x96, 0x00, + 0x3E, 0x07, 0xEE, 0xC6, 0xDD, 0x4F, 0x2E, 0x07, 0xEE, 0xC6, 0x5A, 0x08, 0x03, 0x03, 0xF8, 0x0C, + 0x5A, 0x00, 0x02, 0x04, 0x48, 0x00, 0x00, 0x8B, 0xDD, 0x47, 0xDD, 0x45, 0xAE, 0x40, 0xDD, 0x51, + 0xA6, 0x08, 0xC0, 0xFF, 0x84, 0x02, 0x48, 0x00, 0x00, 0xD3, 0xDD, 0x43, 0xC8, 0xB0, 0x2E, 0x67, + 0xF3, 0x52, 0xCE, 0xAD, 0xDD, 0x43, 0xC8, 0x04, 0x49, 0xFF, 0xF9, 0x73, 0x84, 0xC1, 0x49, 0xFF, + 0xF7, 0x63, 0x2E, 0x97, 0xEE, 0xD7, 0x4E, 0x93, 0xFF, 0xA4, 0xDD, 0x41, 0x44, 0x12, 0xD9, 0xD0, + 0x49, 0x00, 0x33, 0x82, 0xEB, 0xE9, 0x44, 0x12, 0xD7, 0x60, 0x3E, 0x97, 0xEE, 0xBB, 0x49, 0x00, + 0x10, 0x03, 0x4E, 0x02, 0xFF, 0x96, 0x84, 0x01, 0x3E, 0x07, 0xEE, 0xD7, 0x3C, 0x9B, 0xF7, 0xC9, + 0x48, 0xFF, 0xFF, 0x8F, 0xEA, 0xE6, 0xA6, 0x40, 0x5A, 0x10, 0x21, 0x06, 0xA6, 0x00, 0x5A, 0x00, + 0x22, 0x03, 0xF8, 0x03, 0x84, 0x01, 0xEA, 0x2A, 0x48, 0xFF, 0xFF, 0x87, 0x2E, 0x07, 0xEE, 0xC2, + 0x5A, 0x00, 0x01, 0x03, 0xF8, 0x06, 0x49, 0xFF, 0xE4, 0x43, 0x84, 0x00, 0x3E, 0x07, 0xEE, 0xC2, + 0x48, 0xFF, 0xFF, 0x80, 0xEA, 0x67, 0x5A, 0x00, 0x06, 0x03, 0xF8, 0x0D, 0x84, 0x09, 0xEA, 0x60, + 0xDD, 0x5A, 0x84, 0x01, 0xEA, 0x2A, 0x3E, 0x07, 0xEE, 0xFF, 0xDD, 0x54, 0xA6, 0x00, 0xA6, 0x49, + 0x49, 0xFF, 0xF2, 0xC4, 0x48, 0xFF, 0xFF, 0x75, 0x84, 0x0C, 0x00, 0x13, 0x80, 0x50, 0xDD, 0x44, + 0x84, 0x0D, 0x00, 0x13, 0x80, 0x51, 0xDD, 0x44, 0x84, 0x0E, 0x00, 0x13, 0x80, 0x52, 0xDD, 0x44, + 0xEB, 0x4E, 0x5A, 0x00, 0x01, 0x03, 0xF8, 0x03, 0x84, 0x00, 0xEA, 0x71, 0x48, 0xFF, 0xFF, 0x6E, + 0x2E, 0x07, 0xEF, 0x3B, 0x5A, 0x08, 0x01, 0x04, 0x48, 0xFF, 0xFF, 0x7D, 0xEA, 0xE6, 0xA6, 0x00, + 0x5A, 0x08, 0x13, 0x05, 0x44, 0x00, 0x00, 0x86, 0xDD, 0x4A, 0xEB, 0x8B, 0xDD, 0x5A, 0x44, 0x22, + 0xBB, 0x5D, 0x3C, 0x3D, 0xFC, 0x0B, 0x44, 0x42, 0xBD, 0x80, 0x49, 0xFF, 0xE0, 0x33, 0xEA, 0xC0, + 0xF8, 0x03, 0xEA, 0x40, 0xEB, 0x1E, 0x48, 0xFF, 0xFF, 0x69, 0xDD, 0x51, 0xA6, 0x08, 0x5A, 0x08, + 0x02, 0x06, 0xDD, 0x4B, 0xA6, 0x00, 0x5A, 0x00, 0x02, 0x05, 0xEB, 0xB7, 0x5A, 0x08, 0x01, 0x18, + 0x84, 0x01, 0xAE, 0x08, 0xDD, 0x50, 0xAE, 0x08, 0xEB, 0xB7, 0x5A, 0x08, 0x01, 0x0D, 0x3C, 0x1D, + 0xFC, 0x3A, 0x5A, 0x18, 0x06, 0x09, 0x84, 0x29, 0x3C, 0x1F, 0xFC, 0x3A, 0x84, 0x20, 0x3E, 0x17, + 0xF3, 0x52, 0xEB, 0x0D, 0xDD, 0x43, 0xC8, 0x03, 0x49, 0xFF, 0xF8, 0xF9, 0xDD, 0x41, 0xA6, 0x01, + 0x5A, 0x08, 0x0A, 0x09, 0xDD, 0x43, 0xC8, 0x04, 0xCE, 0x03, 0x49, 0xFF, 0xF8, 0xD2, 0x49, 0xFF, + 0xF7, 0x09, 0x2E, 0x07, 0xEE, 0xFF, 0x5A, 0x08, 0x01, 0x0D, 0xDD, 0x54, 0xA6, 0x00, 0x5A, 0x08, + 0x03, 0x09, 0xEB, 0x84, 0xC8, 0x06, 0x84, 0x02, 0x3E, 0x07, 0xEE, 0xFF, 0x49, 0xFF, 0xF1, 0xF6, + 0xDD, 0x55, 0x5A, 0x08, 0x04, 0x04, 0x49, 0x00, 0x4A, 0xAC, 0x2E, 0x07, 0xEF, 0x48, 0x5A, 0x00, + 0x01, 0x04, 0x48, 0xFF, 0xFE, 0xE4, 0x84, 0x00, 0x3E, 0x07, 0xEF, 0x48, 0xDD, 0x50, 0xA6, 0x08, + 0x96, 0x00, 0xC8, 0xFE, 0x84, 0x41, 0xAE, 0x88, 0xEA, 0x2A, 0xFA, 0x03, 0xFC, 0xC0, 0xFC, 0x01, + 0xEA, 0x81, 0x5A, 0x08, 0x01, 0x06, 0x44, 0x02, 0xBB, 0x28, 0x84, 0x20, 0xEB, 0x0E, 0xEA, 0x2E, + 0x5A, 0x08, 0x01, 0x04, 0x49, 0x00, 0x4B, 0xFC, 0xDD, 0x54, 0xA6, 0x00, 0x5A, 0x08, 0x03, 0x0D, + 0xEA, 0x2E, 0x5A, 0x08, 0x01, 0x0A, 0x49, 0x00, 0x49, 0xA9, 0x84, 0x02, 0x3C, 0x1D, 0xFC, 0x08, + 0x49, 0xFF, 0xF0, 0x91, 0xD5, 0x08, 0x49, 0x00, 0x41, 0x00, 0xF0, 0x81, 0xF1, 0x01, 0x84, 0x00, + 0x49, 0xFF, 0xF0, 0x89, 0xDD, 0x41, 0xA6, 0x41, 0x5A, 0x18, 0x0D, 0x04, 0x84, 0x23, 0xAE, 0x41, + 0x44, 0x00, 0x00, 0xA3, 0xEB, 0x98, 0x84, 0x01, 0x3E, 0x07, 0xEF, 0x02, 0x2E, 0x07, 0x34, 0x0D, + 0x5A, 0x08, 0x01, 0x0B, 0xDD, 0x41, 0xA6, 0x00, 0x5A, 0x08, 0x01, 0x07, 0xDD, 0x54, 0xA6, 0x00, + 0x49, 0x00, 0x41, 0x2C, 0xD5, 0x04, 0xEA, 0xFD, 0xEA, 0xC5, 0xDD, 0x5D, 0xEA, 0x24, 0xEB, 0xE3, + 0xEB, 0xC2, 0x49, 0xFF, 0xE5, 0xDA, 0xFC, 0x81, 0xFC, 0x00, 0xEA, 0x24, 0xEB, 0xE3, 0xEB, 0xC2, + 0xEB, 0x67, 0x44, 0x42, 0xD8, 0xCC, 0x49, 0xFF, 0xE7, 0x57, 0x2E, 0x07, 0x34, 0x0E, 0x5A, 0x08, + 0x01, 0x08, 0xEA, 0x24, 0x44, 0x12, 0xD3, 0xA4, 0x49, 0xFF, 0xE5, 0x39, 0xD5, 0x06, 0x3C, 0x0C, + 0x03, 0x22, 0x3C, 0x1C, 0x03, 0x21, 0xDD, 0x5D, 0x2E, 0x07, 0x34, 0x23, 0x5A, 0x08, 0x01, 0x0E, + 0x44, 0x02, 0xBF, 0x68, 0x44, 0x12, 0xBF, 0x66, 0x44, 0x22, 0xBF, 0x64, 0x44, 0x32, 0xD8, 0xE8, + 0x44, 0x42, 0xD6, 0xAC, 0x49, 0xFF, 0xEF, 0x55, 0xEA, 0xD5, 0xB4, 0x01, 0xEA, 0xD2, 0x5A, 0x00, + 0x01, 0x03, 0x84, 0x00, 0x3C, 0x0F, 0xFC, 0x0E, 0x2E, 0x07, 0x34, 0x23, 0x5A, 0x08, 0x01, 0x18, + 0x2E, 0x07, 0xF2, 0xE4, 0xE6, 0x05, 0x3C, 0x03, 0xF9, 0x76, 0xE8, 0x05, 0x5C, 0xF0, 0x02, 0x26, + 0xE9, 0x05, 0xD5, 0x0A, 0x5C, 0xF0, 0x01, 0x2C, 0xE8, 0x07, 0x5C, 0xF0, 0x00, 0x47, 0xE9, 0x04, + 0xB4, 0x01, 0xEA, 0xD2, 0xC0, 0x02, 0x84, 0x01, 0x3C, 0x0F, 0xFC, 0x0E, 0x84, 0x01, 0x3E, 0x07, + 0xF3, 0x7E, 0xDD, 0x55, 0x5A, 0x08, 0x12, 0x09, 0xEA, 0x79, 0x84, 0x21, 0xEA, 0x84, 0x5A, 0x08, + 0x01, 0x04, 0xEA, 0x28, 0xEA, 0x36, 0x2E, 0x17, 0xEE, 0xE5, 0x5A, 0x18, 0x01, 0x05, 0x44, 0x02, + 0xBB, 0x28, 0xEB, 0x0E, 0xDD, 0x55, 0x5A, 0x08, 0x12, 0x0A, 0xEA, 0x79, 0x84, 0x22, 0xEA, 0x84, + 0x5A, 0x08, 0x01, 0x05, 0x84, 0x02, 0xEA, 0x28, 0xEA, 0x36, 0xDD, 0x43, 0x5A, 0x08, 0x02, 0x05, + 0xEA, 0x24, 0x49, 0x00, 0x0B, 0xA2, 0xFC, 0x80, 0xFC, 0x00, 0xC0, 0x46, 0xEA, 0x3D, 0xDD, 0x5C, + 0x5A, 0x18, 0x14, 0x14, 0xEA, 0xBD, 0xDD, 0x46, 0xEB, 0xAE, 0xF8, 0x14, 0x44, 0x12, 0x9E, 0xCA, + 0xF8, 0x16, 0x44, 0x12, 0xA1, 0xEA, 0xF8, 0x18, 0xF8, 0x1B, 0x44, 0x12, 0x19, 0xA0, 0xDD, 0x5C, + 0x44, 0x03, 0x7D, 0x48, 0xDD, 0x46, 0xFC, 0x80, 0x44, 0x13, 0x58, 0x90, 0xDD, 0x46, 0x44, 0x13, + 0x5B, 0xB0, 0xDD, 0x5C, 0x44, 0x03, 0x77, 0x08, 0xDD, 0x46, 0xEA, 0xB7, 0xDD, 0x5C, 0x44, 0x03, + 0x80, 0x68, 0xDD, 0x46, 0xEB, 0x20, 0xDD, 0x5C, 0x44, 0x03, 0x83, 0x88, 0xDD, 0x46, 0xEB, 0x89, + 0xDD, 0x5C, 0x44, 0x03, 0x7A, 0x28, 0xDD, 0x46, 0x44, 0x12, 0x19, 0xA0, 0x44, 0x03, 0x7D, 0x48, + 0xDD, 0x5C, 0xDD, 0x46, 0x44, 0x13, 0x86, 0xA8, 0x44, 0x02, 0xAB, 0x4A, 0xF8, 0x4C, 0xF8, 0x06, + 0x44, 0x02, 0xAC, 0x12, 0x44, 0x13, 0x89, 0xC8, 0xF8, 0x46, 0x3B, 0x00, 0x54, 0x00, 0x3B, 0x00, + 0xD4, 0x20, 0x83, 0xFF, 0xFC, 0x80, 0x44, 0x03, 0x75, 0x78, 0xEA, 0x27, 0x5A, 0x18, 0x14, 0x0F, + 0xEB, 0x1F, 0xDD, 0x46, 0xEB, 0xAA, 0xF8, 0x0F, 0x44, 0x12, 0xA0, 0x5A, 0xF8, 0x11, 0x44, 0x12, + 0xA3, 0x7A, 0xF8, 0x13, 0xF8, 0x16, 0xF8, 0x1A, 0xFC, 0x80, 0x44, 0x13, 0x5A, 0x20, 0xDD, 0x46, + 0x44, 0x13, 0x5D, 0x40, 0xEA, 0x27, 0x44, 0x03, 0x78, 0x98, 0xDD, 0x46, 0xEB, 0x2A, 0xEA, 0x27, + 0x44, 0x03, 0x81, 0xF8, 0xDD, 0x46, 0xEA, 0xED, 0xEA, 0x27, 0x44, 0x03, 0x85, 0x18, 0xDD, 0x46, + 0xEB, 0xEF, 0xEA, 0x27, 0x44, 0x03, 0x7B, 0xB8, 0xDD, 0x46, 0x44, 0x12, 0x1B, 0x30, 0xEA, 0x27, + 0x44, 0x03, 0x7E, 0xD8, 0xDD, 0x46, 0x44, 0x23, 0x88, 0x38, 0x80, 0x22, 0x44, 0x02, 0xAB, 0xAE, + 0xEB, 0x4A, 0x44, 0x23, 0x8B, 0x58, 0xEA, 0xDB, 0xF8, 0x06, 0xF8, 0x08, 0x44, 0x02, 0xAC, 0x76, + 0x80, 0x22, 0xF8, 0x01, 0xEB, 0x4A, 0xEA, 0xDB, 0x83, 0xFF, 0x3B, 0x00, 0x50, 0x00, 0x3B, 0x00, + 0xD0, 0x20, 0x83, 0xFF, 0xFC, 0x80, 0x92, 0x00, 0xFC, 0x20, 0x3C, 0x23, 0xF7, 0xCE, 0x5A, 0x20, + 0x07, 0x04, 0x48, 0x00, 0x01, 0x99, 0xE6, 0x10, 0x4E, 0xF2, 0x01, 0x96, 0x80, 0xC1, 0x44, 0xF0, + 0x81, 0x38, 0xEA, 0xA1, 0xEA, 0x3C, 0xDD, 0x0F, 0x20, 0x00, 0x2A, 0x00, 0x34, 0x00, 0x3E, 0x00, + 0x68, 0x00, 0x9E, 0x00, 0xD2, 0x00, 0x06, 0x01, 0x38, 0x01, 0x76, 0x01, 0xB2, 0x01, 0xE8, 0x01, + 0x1C, 0x02, 0x4E, 0x02, 0x80, 0x02, 0xCC, 0x02, 0xEA, 0x2B, 0x5A, 0x00, 0x0B, 0x03, 0xF9, 0x17, + 0xD5, 0x0F, 0xEA, 0x2B, 0x5A, 0x00, 0x0C, 0x03, 0xF9, 0x12, 0xD5, 0x0A, 0xEA, 0x2B, 0x5A, 0x00, + 0x0D, 0x03, 0xF9, 0x0D, 0xD5, 0x05, 0xEA, 0x2B, 0x5A, 0x00, 0x0E, 0x03, 0xF9, 0x08, 0xEA, 0xA6, + 0x96, 0x00, 0x5A, 0x08, 0x01, 0x04, 0x80, 0x26, 0xF8, 0x07, 0xEA, 0x7D, 0x5A, 0x00, 0x01, 0x03, + 0xF8, 0xFE, 0x84, 0x00, 0x80, 0x26, 0x49, 0xFF, 0xFF, 0x31, 0x84, 0x08, 0xEB, 0x08, 0xF8, 0xF7, + 0xEA, 0xA6, 0x5A, 0x00, 0x01, 0x03, 0xF8, 0xF3, 0xEA, 0x2B, 0x84, 0xE0, 0x8E, 0x0C, 0x96, 0x00, + 0xE6, 0x03, 0xE8, 0x04, 0x44, 0x11, 0x68, 0xE0, 0xEA, 0x7A, 0xEA, 0xE0, 0xEA, 0x3D, 0xEB, 0xD5, + 0xDD, 0x5C, 0x5A, 0x68, 0x14, 0x05, 0xEA, 0xBD, 0xDD, 0x46, 0xF8, 0x04, 0x44, 0x13, 0x58, 0x90, + 0xDD, 0x46, 0x48, 0x00, 0x00, 0x67, 0xEA, 0x7D, 0x5A, 0x00, 0x01, 0x03, 0xF8, 0xD8, 0xEA, 0x2B, + 0x84, 0xE0, 0x8E, 0x0C, 0x96, 0x00, 0xE6, 0x03, 0xE8, 0x04, 0x44, 0x11, 0x68, 0xDC, 0xEA, 0x7A, + 0xEA, 0x27, 0xEA, 0x3D, 0xEB, 0x0F, 0x5A, 0x68, 0x14, 0x05, 0xEB, 0x1F, 0xDD, 0x46, 0xF8, 0x04, + 0x44, 0x13, 0x5A, 0x20, 0xDD, 0x46, 0x48, 0x00, 0x00, 0x6B, 0xEA, 0xA6, 0x5A, 0x00, 0x01, 0x03, + 0xF8, 0xBE, 0xEA, 0x2B, 0x84, 0xC0, 0x8E, 0x0C, 0x96, 0x00, 0xE6, 0x03, 0xE8, 0x04, 0x44, 0x11, + 0x68, 0xD8, 0xEB, 0xA2, 0xEA, 0xE0, 0xEA, 0x3D, 0x42, 0x03, 0x04, 0x73, 0xDD, 0x5C, 0xEB, 0x89, + 0xDD, 0x46, 0xEA, 0x3F, 0xEA, 0x80, 0xEB, 0x57, 0x44, 0x02, 0xAB, 0x4A, 0xF8, 0x37, 0xEA, 0x7D, + 0x5A, 0x00, 0x01, 0x03, 0xF8, 0xA4, 0xEA, 0x2B, 0x84, 0xC0, 0x8E, 0x0C, 0x96, 0x00, 0xE6, 0x03, + 0xE8, 0x04, 0x44, 0x11, 0x68, 0xD4, 0xEB, 0xA2, 0xEA, 0x27, 0xEA, 0x3D, 0xEB, 0xEF, 0x42, 0x03, + 0x08, 0x73, 0xDD, 0x46, 0xEA, 0x3F, 0xEA, 0x80, 0xEB, 0x57, 0x44, 0x02, 0xAB, 0xAE, 0xF8, 0x3C, + 0xEA, 0xA6, 0x5A, 0x00, 0x01, 0x03, 0xF8, 0x8B, 0xEA, 0x2B, 0x84, 0xE0, 0x8E, 0x0C, 0x96, 0x00, + 0xE6, 0x03, 0xE8, 0x04, 0x44, 0x11, 0x68, 0xD0, 0xEA, 0x7A, 0xEA, 0xE0, 0xEA, 0x3D, 0xEB, 0xD5, + 0xDD, 0x5C, 0x5A, 0x68, 0x14, 0x05, 0xEA, 0xCD, 0xDD, 0x46, 0xD5, 0x03, 0xEA, 0xB7, 0xDD, 0x46, + 0xEA, 0x3F, 0xEA, 0x80, 0xEB, 0x5D, 0x44, 0x02, 0xAB, 0x4A, 0x48, 0x00, 0x00, 0xA3, 0xEA, 0x7D, + 0x5A, 0x00, 0x01, 0x03, 0xF8, 0x6C, 0xEA, 0x2B, 0x84, 0xE0, 0x8E, 0x0C, 0x96, 0x00, 0xE6, 0x03, + 0xE8, 0x04, 0x44, 0x11, 0x68, 0xCC, 0xEA, 0x7A, 0xEA, 0x27, 0xEA, 0x3D, 0xEB, 0x0F, 0x5A, 0x68, + 0x14, 0x05, 0xEB, 0x46, 0xDD, 0x46, 0xD5, 0x03, 0xEB, 0x2A, 0xDD, 0x46, 0xEA, 0x3F, 0xEA, 0x80, + 0xEB, 0x5D, 0x44, 0x02, 0xAB, 0xAE, 0x48, 0x00, 0x00, 0xAA, 0xEA, 0xA6, 0x5A, 0x00, 0x01, 0x03, + 0xF8, 0x4E, 0xEA, 0x2B, 0x84, 0xE0, 0x8E, 0x0C, 0x96, 0x00, 0xE6, 0x03, 0xE8, 0x04, 0x44, 0x11, + 0x68, 0xC8, 0xEA, 0x7A, 0xEA, 0xE0, 0xEA, 0x3D, 0xEB, 0xD5, 0xDD, 0x5C, 0x5A, 0x68, 0x14, 0x05, + 0xEB, 0xAE, 0xDD, 0x46, 0xF8, 0x04, 0x44, 0x13, 0x5B, 0xB0, 0xDD, 0x46, 0x48, 0x00, 0x00, 0x65, + 0xEA, 0x7D, 0x5A, 0x00, 0x01, 0x03, 0xF8, 0x33, 0xEA, 0x2B, 0x84, 0xE0, 0x8E, 0x0C, 0x96, 0x00, + 0xE6, 0x03, 0xE8, 0x04, 0x44, 0x11, 0x68, 0xC4, 0xEA, 0x7A, 0xEA, 0x27, 0xEA, 0x3D, 0xEB, 0x0F, + 0x5A, 0x68, 0x14, 0x05, 0xEB, 0xAA, 0xDD, 0x46, 0xF8, 0x04, 0x44, 0x13, 0x5D, 0x40, 0xDD, 0x46, + 0x48, 0x00, 0x00, 0x70, 0xEA, 0xA6, 0x5A, 0x00, 0x01, 0x03, 0xF8, 0x19, 0xEA, 0x2B, 0x84, 0xC0, + 0x8E, 0x0C, 0x96, 0x00, 0xE6, 0x03, 0xE8, 0x04, 0x44, 0x11, 0x68, 0xC0, 0xEB, 0xA2, 0xEA, 0xE0, + 0xEA, 0x3D, 0x42, 0x03, 0x04, 0x73, 0xDD, 0x5C, 0x44, 0x12, 0x19, 0xA0, 0xDD, 0x46, 0xEA, 0x80, + 0xEA, 0x3F, 0xEB, 0x57, 0xD5, 0x34, 0xEA, 0x7D, 0x5A, 0x00, 0x01, 0x04, 0x48, 0x00, 0x00, 0x64, + 0xEA, 0x2B, 0x84, 0xC0, 0x8E, 0x0C, 0x96, 0x00, 0xE6, 0x03, 0xE8, 0x04, 0x44, 0x11, 0x68, 0xBC, + 0xEB, 0xA2, 0xEA, 0x27, 0xEA, 0x3D, 0x44, 0x12, 0x1B, 0x30, 0x42, 0x03, 0x08, 0x73, 0xDD, 0x46, + 0xEA, 0x80, 0xEA, 0x3F, 0xEB, 0x57, 0xD5, 0x40, 0xEA, 0xA6, 0x5A, 0x08, 0x01, 0x4D, 0xEA, 0x2B, + 0x84, 0xE0, 0x8E, 0x0C, 0x96, 0x00, 0xE6, 0x03, 0xE8, 0x04, 0x44, 0x11, 0x68, 0xB8, 0xEA, 0x7A, + 0xEA, 0xE0, 0xEA, 0x3D, 0xEB, 0xD5, 0xDD, 0x5C, 0x5A, 0x68, 0x14, 0x05, 0xEB, 0xCD, 0xDD, 0x46, + 0xD5, 0x03, 0xEB, 0x20, 0xDD, 0x46, 0xEA, 0x80, 0xEA, 0x3F, 0xEB, 0x5D, 0x44, 0x02, 0xAC, 0x12, + 0xEB, 0x4A, 0xEA, 0xDB, 0x3B, 0x00, 0x54, 0x00, 0x3B, 0x00, 0xD4, 0x20, 0xEA, 0x2B, 0x5A, 0x08, + 0x0E, 0x2B, 0xD5, 0x27, 0xEA, 0x7D, 0x5A, 0x08, 0x01, 0x27, 0xEA, 0x2B, 0x84, 0xE0, 0x8E, 0x0C, + 0x96, 0x00, 0xE6, 0x03, 0xE8, 0x04, 0x44, 0x11, 0x68, 0xB4, 0xEA, 0x7A, 0xEA, 0x27, 0xEA, 0x3D, + 0xEB, 0x0F, 0x5A, 0x68, 0x14, 0x05, 0xEB, 0xB1, 0xDD, 0x46, 0xD5, 0x03, 0xEA, 0xED, 0xDD, 0x46, + 0xEA, 0x80, 0xEA, 0x3F, 0xEB, 0x5D, 0x44, 0x02, 0xAC, 0x76, 0xEB, 0x4A, 0xEA, 0xDB, 0xEB, 0x4A, + 0xEA, 0xDB, 0x3B, 0x00, 0x50, 0x00, 0x3B, 0x00, 0xD0, 0x20, 0xEA, 0x2B, 0x5A, 0x08, 0x0E, 0x04, + 0x84, 0x08, 0xEB, 0x08, 0xFC, 0xA0, 0x92, 0x00, 0xFC, 0x00, 0x2E, 0x07, 0xEE, 0xE6, 0xC8, 0x03, + 0xEA, 0x2A, 0xD5, 0x06, 0x84, 0x01, 0xEA, 0x2A, 0x84, 0x00, 0x3E, 0x07, 0xEE, 0xE6, 0xDD, 0x55, + 0x5A, 0x08, 0x12, 0x0A, 0xEA, 0x79, 0x84, 0x2F, 0xEA, 0x84, 0x5A, 0x08, 0x01, 0x05, 0x84, 0x0F, + 0xEA, 0x28, 0xEA, 0x36, 0xDD, 0x4B, 0x84, 0x21, 0xAE, 0x40, 0xDD, 0x43, 0x5A, 0x08, 0x02, 0x0B, + 0xEA, 0x43, 0x5A, 0x08, 0x01, 0x08, 0x3C, 0x1D, 0xFC, 0x3A, 0x5A, 0x18, 0x09, 0x04, 0x3E, 0x07, + 0xEE, 0xD9, 0xEA, 0x6B, 0x5A, 0x08, 0x01, 0x08, 0xDD, 0x41, 0xA6, 0x01, 0x5A, 0x08, 0x0A, 0x04, + 0x49, 0x00, 0x2D, 0x87, 0xFC, 0x80, 0xDD, 0x9E, 0xDD, 0x9E, 0xFC, 0x00, 0x44, 0x02, 0xFE, 0xFC, + 0xA6, 0x40, 0x5A, 0x18, 0xA5, 0x0B, 0x84, 0x21, 0x3E, 0x17, 0xF3, 0x7B, 0x3E, 0x17, 0xEF, 0x5C, + 0x84, 0x20, 0xAE, 0x40, 0x84, 0x02, 0xD5, 0x5A, 0x2E, 0x07, 0xEF, 0x09, 0xC8, 0x31, 0xEA, 0xA4, + 0xC8, 0x1B, 0x2E, 0x07, 0xEF, 0x57, 0xC8, 0x18, 0x2E, 0x07, 0xEF, 0x5C, 0xC8, 0x15, 0x49, 0x00, + 0x1C, 0x86, 0x5A, 0x08, 0x02, 0x08, 0xFA, 0x02, 0xDD, 0x4A, 0x84, 0x01, 0x3E, 0x07, 0xEF, 0x5C, + 0xD5, 0x0B, 0x44, 0x02, 0xD9, 0xD0, 0x3C, 0x13, 0x9A, 0x2E, 0x44, 0x22, 0xBB, 0xBC, 0x49, 0x00, + 0x25, 0x98, 0x5A, 0x00, 0x02, 0xF2, 0xDD, 0x41, 0xA6, 0x41, 0x2E, 0x07, 0xEF, 0x5C, 0x5A, 0x10, + 0x06, 0x04, 0x5A, 0x18, 0x0B, 0x10, 0x5A, 0x00, 0x01, 0x09, 0x2E, 0x07, 0xF3, 0x7A, 0x5A, 0x00, + 0x01, 0x05, 0x2E, 0x07, 0xEF, 0x44, 0xC0, 0x04, 0x84, 0x01, 0xEA, 0x42, 0xEA, 0x78, 0x84, 0x01, + 0xD5, 0x25, 0x5A, 0x00, 0x01, 0x0A, 0x2E, 0x07, 0xF3, 0x7A, 0x5A, 0x00, 0x01, 0x06, 0x2E, 0x07, + 0xEF, 0x28, 0x5A, 0x08, 0x01, 0xF6, 0xDD, 0x47, 0xDD, 0x45, 0xAE, 0x40, 0xDD, 0x51, 0xA6, 0x08, + 0xC0, 0xFF, 0x84, 0x00, 0x3E, 0x07, 0xEF, 0x5C, 0x3E, 0x07, 0xF3, 0x7A, 0x84, 0x01, 0x3E, 0x07, + 0xF3, 0x7B, 0xDD, 0x55, 0x5A, 0x08, 0x12, 0x0A, 0xEA, 0x79, 0x84, 0x25, 0xEA, 0x84, 0x5A, 0x08, + 0x01, 0x05, 0x84, 0x05, 0xEA, 0x28, 0xEA, 0x36, 0x84, 0x02, 0xFC, 0x80, 0xFC, 0x00, 0xEA, 0x2E, + 0x5A, 0x08, 0x01, 0x0A, 0x44, 0x02, 0x02, 0x94, 0x50, 0x10, 0x00, 0x28, 0x50, 0x20, 0x00, 0x58, + 0x49, 0x00, 0x47, 0x7F, 0xDD, 0x41, 0xEB, 0xBD, 0x2E, 0x27, 0xEF, 0x57, 0x2E, 0x37, 0xEF, 0x0C, + 0x2E, 0x47, 0xEE, 0xDB, 0x49, 0xFF, 0xEB, 0x69, 0xEA, 0x6B, 0x5A, 0x08, 0x01, 0x0B, 0xEB, 0xE4, + 0x5A, 0x08, 0x01, 0x08, 0xEB, 0x0B, 0x49, 0x00, 0x1E, 0x2A, 0xC8, 0x03, 0x49, 0x00, 0x1E, 0x64, + 0xFC, 0x80, 0xFC, 0x00, 0xDD, 0x41, 0xA6, 0x01, 0x5A, 0x00, 0x03, 0x05, 0xF8, 0x3D, 0xE6, 0x03, + 0xE9, 0x06, 0xDD, 0x55, 0x5A, 0x00, 0x05, 0x04, 0x5A, 0x08, 0x12, 0x0A, 0x84, 0x00, 0x3E, 0x07, + 0xF1, 0x20, 0x3E, 0x07, 0xF1, 0x21, 0x3E, 0x07, 0xF1, 0x22, 0xD5, 0x36, 0x3C, 0x0D, 0xFC, 0x5B, + 0x5A, 0x08, 0x01, 0x08, 0x84, 0x00, 0xEB, 0xD8, 0x44, 0x02, 0xBD, 0x94, 0x49, 0x00, 0x60, 0xAC, + 0x44, 0x02, 0xDA, 0x20, 0x44, 0x12, 0xBD, 0xB4, 0x49, 0x00, 0x64, 0xAC, 0x3E, 0x07, 0xF1, 0x22, + 0xF8, 0x1B, 0x5A, 0x08, 0x03, 0x07, 0x84, 0x00, 0x3E, 0x07, 0xF1, 0x20, 0x3E, 0x07, 0xF1, 0x21, + 0x49, 0x00, 0x60, 0xB5, 0x80, 0xC0, 0x5A, 0x08, 0x01, 0x10, 0xF8, 0x0E, 0x5A, 0x08, 0x03, 0x07, + 0x80, 0x06, 0xEB, 0x7D, 0x44, 0x00, 0x00, 0x61, 0xDD, 0x4A, 0xF8, 0x06, 0x5A, 0x08, 0x04, 0x0D, + 0x84, 0x01, 0xEB, 0x7D, 0xD5, 0x09, 0x49, 0x00, 0x60, 0x9F, 0x5A, 0x08, 0x03, 0x06, 0x84, 0x00, + 0xEA, 0x33, 0x84, 0x01, 0xEA, 0x78, 0xFC, 0x80, 0xFC, 0x00, 0xEA, 0x81, 0x5A, 0x08, 0x01, 0x06, + 0x44, 0x02, 0xBB, 0x28, 0x84, 0x22, 0xEB, 0x0E, 0x2E, 0x07, 0x34, 0x0F, 0x5A, 0x08, 0x01, 0x0C, + 0x44, 0x02, 0xD4, 0x78, 0x44, 0x12, 0xD8, 0xCC, 0x44, 0x22, 0xBB, 0xCF, 0x2E, 0x37, 0xEF, 0x01, + 0x49, 0xFF, 0xE1, 0xA1, 0xEA, 0x2E, 0x5A, 0x08, 0x01, 0x06, 0x44, 0x02, 0xD8, 0xCC, 0x49, 0x00, + 0x4E, 0xB9, 0xEB, 0xDC, 0x5A, 0x08, 0x01, 0x08, 0xEA, 0x24, 0xEB, 0xBD, 0x44, 0x22, 0xD6, 0xAC, + 0x49, 0x00, 0x24, 0x16, 0x44, 0x02, 0xD8, 0xCC, 0x49, 0xFF, 0xEB, 0x75, 0xEA, 0x6B, 0x5A, 0x08, + 0x01, 0x0D, 0xEB, 0xE4, 0x5A, 0x08, 0x01, 0x0A, 0xEB, 0x0B, 0x49, 0x00, 0x1D, 0xA8, 0xC8, 0x05, + 0x44, 0x02, 0xD8, 0xCC, 0x49, 0x00, 0x1D, 0xF1, 0xEA, 0x24, 0x44, 0x12, 0xBC, 0xA8, 0x44, 0x22, + 0x00, 0x00, 0x84, 0x60, 0x84, 0x85, 0x49, 0xFF, 0xE1, 0xF4, 0xDD, 0x55, 0x5A, 0x08, 0x12, 0x0A, + 0xEA, 0x79, 0x84, 0x23, 0xEA, 0x84, 0x5A, 0x08, 0x01, 0x05, 0x84, 0x03, 0xEA, 0x28, 0xEA, 0x36, + 0x84, 0x00, 0x44, 0x22, 0x01, 0xAC, 0x3E, 0x07, 0xEF, 0x30, 0xEB, 0xBD, 0x44, 0x02, 0xBC, 0xA8, + 0x50, 0x31, 0x00, 0x14, 0x49, 0x00, 0x1B, 0x03, 0xEB, 0xDC, 0x5A, 0x08, 0x01, 0x0B, 0x2E, 0x07, + 0xF3, 0x54, 0x5A, 0x08, 0x01, 0x07, 0xEB, 0x88, 0xC0, 0x04, 0xEA, 0x24, 0x49, 0x00, 0x24, 0x7B, + 0xEB, 0x88, 0xC8, 0x06, 0xEB, 0x0B, 0x44, 0x12, 0xD8, 0xE8, 0x49, 0x00, 0x1B, 0x0A, 0xEB, 0x88, + 0xC0, 0x48, 0x84, 0x00, 0x3E, 0x07, 0xEF, 0x0F, 0xDD, 0x55, 0x5A, 0x08, 0x12, 0x0A, 0xEA, 0x79, + 0x84, 0x24, 0xEA, 0x84, 0x5A, 0x08, 0x01, 0x05, 0x84, 0x04, 0xEA, 0x28, 0xEA, 0x36, 0xEA, 0x2E, + 0x5A, 0x00, 0x01, 0x05, 0xEB, 0xDC, 0x5A, 0x08, 0x01, 0x06, 0x44, 0x02, 0x01, 0x78, 0x49, 0x00, + 0x47, 0xE2, 0x3C, 0x0C, 0x03, 0x21, 0xEB, 0x5C, 0x3C, 0x20, 0x06, 0x2A, 0x44, 0x32, 0xBB, 0x7B, + 0x84, 0x81, 0xEB, 0xA4, 0x2E, 0x07, 0x34, 0x11, 0x5A, 0x08, 0x01, 0x1E, 0xEB, 0x50, 0xB4, 0x00, + 0x42, 0x00, 0x74, 0x0B, 0x5A, 0x00, 0x01, 0x08, 0x3C, 0x0D, 0xFC, 0x1E, 0xA6, 0x00, 0x96, 0x04, + 0x5A, 0x08, 0x01, 0x12, 0xEB, 0x3A, 0xC8, 0x0F, 0x2E, 0x07, 0xF2, 0xE5, 0xC8, 0x0C, 0x44, 0x02, + 0xD6, 0xAC, 0x44, 0x12, 0xD8, 0xE8, 0x44, 0x22, 0xBB, 0x7B, 0x49, 0x00, 0x05, 0x26, 0x3E, 0x07, + 0xF3, 0x56, 0xD5, 0x13, 0x84, 0x00, 0x3E, 0x07, 0xF3, 0x56, 0x49, 0x00, 0x03, 0xE3, 0xD5, 0x0D, + 0xEA, 0xA4, 0x5A, 0x08, 0x01, 0x06, 0x49, 0x00, 0x03, 0xD1, 0x3E, 0x07, 0xF3, 0x56, 0x84, 0x00, + 0x3E, 0x07, 0xEF, 0x03, 0x3E, 0x07, 0xEE, 0xDB, 0xEA, 0x81, 0x5A, 0x08, 0x01, 0x06, 0x44, 0x02, + 0xBB, 0x28, 0x84, 0x23, 0xEB, 0x0E, 0x2E, 0x07, 0x34, 0x13, 0x5A, 0x08, 0x01, 0x2D, 0xEB, 0x50, + 0x3C, 0x1D, 0xFC, 0x1E, 0xB4, 0x00, 0x42, 0x00, 0x70, 0x0B, 0x5A, 0x00, 0x01, 0x06, 0xA6, 0x08, + 0xEA, 0xEB, 0x5A, 0x08, 0x01, 0x21, 0xA6, 0x08, 0xEB, 0x8E, 0xC8, 0x1D, 0x2E, 0x07, 0xF3, 0x72, + 0xDD, 0x5A, 0x49, 0xFF, 0xE8, 0x30, 0xDD, 0x41, 0xA6, 0x01, 0x5A, 0x00, 0x03, 0x04, 0x5A, 0x08, + 0x06, 0x10, 0x2E, 0x07, 0xEF, 0x11, 0xC0, 0x0C, 0x3C, 0x0C, 0x03, 0x21, 0xEB, 0x5C, 0x44, 0x22, + 0xBB, 0x7B, 0x3C, 0x30, 0x06, 0x2A, 0x49, 0xFF, 0xE8, 0x38, 0xEB, 0x92, 0xD5, 0x04, 0x49, 0xFF, + 0xE7, 0xF3, 0xEB, 0x92, 0x2E, 0x17, 0xEF, 0x03, 0x2E, 0x07, 0xEF, 0x57, 0x3E, 0x07, 0xF2, 0xE4, + 0xC9, 0x04, 0x3E, 0x17, 0xEF, 0x57, 0xD5, 0x09, 0x44, 0x02, 0xD6, 0xAC, 0x44, 0x22, 0xDA, 0x78, + 0x44, 0x32, 0xBB, 0xCF, 0x49, 0x00, 0x55, 0xCF, 0x2E, 0x17, 0xEF, 0x57, 0xC1, 0x46, 0x2E, 0x37, + 0x33, 0xBA, 0x2E, 0x47, 0x33, 0xBB, 0x92, 0x61, 0x92, 0x81, 0x44, 0x02, 0xDA, 0x78, 0x84, 0x40, + 0xE2, 0x41, 0xE8, 0x0B, 0xA5, 0x40, 0x8C, 0x41, 0x88, 0xA3, 0xAD, 0x40, 0xA5, 0x41, 0x8C, 0x08, + 0x88, 0xA4, 0x12, 0x50, 0x7F, 0xFD, 0xD5, 0xF5, 0x2E, 0x07, 0x34, 0x15, 0x5A, 0x08, 0x01, 0x06, + 0x44, 0x02, 0xDA, 0x78, 0x49, 0x00, 0x56, 0x62, 0x84, 0x00, 0xEA, 0x33, 0xEA, 0xE1, 0x3E, 0x07, + 0xEF, 0x44, 0x3E, 0x07, 0xF2, 0xF3, 0xDD, 0x41, 0xA6, 0x01, 0x5A, 0x08, 0x03, 0x17, 0xEA, 0x32, + 0x5A, 0x08, 0x04, 0x11, 0xEA, 0x88, 0xC8, 0x05, 0xDD, 0x55, 0x8E, 0x04, 0xE6, 0x02, 0xE9, 0x05, + 0x2E, 0x07, 0xEF, 0x27, 0x5A, 0x08, 0x01, 0x07, 0x84, 0x04, 0xEA, 0x66, 0xD5, 0x6A, 0x5A, 0x08, + 0x04, 0x69, 0x84, 0x00, 0xEA, 0x66, 0xD5, 0x65, 0x5A, 0x08, 0x0A, 0x64, 0xEA, 0x32, 0x5A, 0x08, + 0x05, 0xF8, 0x84, 0x01, 0xEA, 0x66, 0xD5, 0x5D, 0xEA, 0xA4, 0xC8, 0x5B, 0x2E, 0x17, 0xF3, 0x02, + 0x3E, 0x07, 0xEF, 0x03, 0x3E, 0x07, 0xEF, 0x57, 0xEB, 0xF9, 0x3C, 0x0F, 0xFC, 0xDB, 0x5A, 0x10, + 0x01, 0x09, 0x3C, 0x0D, 0xFC, 0xD8, 0x44, 0x20, 0xEA, 0x60, 0xE2, 0x40, 0xE9, 0x03, 0x8C, 0x01, + 0xEA, 0x33, 0xDD, 0x52, 0x5A, 0x08, 0x02, 0x04, 0x84, 0x00, 0xEA, 0x33, 0x3C, 0x0D, 0xFC, 0xD9, + 0x44, 0x20, 0xEA, 0x60, 0xE2, 0x40, 0xE9, 0x0D, 0x3C, 0x23, 0xF9, 0x7E, 0x3C, 0x33, 0xF7, 0xE8, + 0xE2, 0x62, 0xE8, 0x02, 0xC1, 0x04, 0x8C, 0x01, 0xEA, 0xE1, 0xD5, 0x03, 0x3C, 0x1F, 0xFC, 0xD9, + 0xEA, 0x88, 0x5A, 0x08, 0x01, 0x0F, 0x84, 0x20, 0x3C, 0x1F, 0xFC, 0xD8, 0x2E, 0x17, 0xF2, 0xF3, + 0xEA, 0x42, 0x5C, 0xF0, 0x80, 0x32, 0xE8, 0x0A, 0x8C, 0x21, 0x3E, 0x17, 0xF2, 0xF3, 0xD5, 0x06, + 0x84, 0x20, 0x3E, 0x17, 0xEE, 0xF0, 0x3E, 0x17, 0xF2, 0xF3, 0x2E, 0x17, 0x34, 0x0C, 0x5A, 0x18, + 0x01, 0x19, 0xDD, 0x5A, 0xA6, 0x49, 0x5A, 0x10, 0x03, 0x04, 0x5A, 0x18, 0x0A, 0x13, 0x2E, 0x17, + 0xF2, 0xF4, 0x5A, 0x18, 0x01, 0x09, 0x3C, 0x1D, 0xFC, 0xD9, 0xE6, 0x22, 0xE8, 0x04, 0xC8, 0x03, + 0x3E, 0x07, 0xF2, 0xF4, 0x84, 0x00, 0xEB, 0xCB, 0x49, 0x00, 0x46, 0x3D, 0x84, 0x01, 0xEB, 0xCB, + 0xDD, 0x52, 0x5A, 0x08, 0x02, 0x07, 0x49, 0x00, 0x5E, 0xDB, 0xC0, 0x03, 0x84, 0x00, 0xEA, 0x33, + 0x49, 0xFF, 0xFD, 0x75, 0x5A, 0x08, 0x02, 0x04, 0x48, 0x00, 0x00, 0x89, 0xEA, 0xA4, 0x5A, 0x08, + 0x01, 0x05, 0x84, 0x00, 0xEA, 0x33, 0xEA, 0xE1, 0x49, 0xFF, 0xFD, 0xD2, 0x44, 0x02, 0xDA, 0x78, + 0x2E, 0x17, 0xEF, 0x57, 0x44, 0x22, 0xDE, 0xC4, 0x44, 0x32, 0xD6, 0xAC, 0x49, 0x00, 0x62, 0xF3, + 0xDD, 0x55, 0x5A, 0x08, 0x12, 0x0A, 0xEA, 0x79, 0x84, 0x26, 0xEA, 0x84, 0x5A, 0x08, 0x01, 0x05, + 0x84, 0x06, 0xEA, 0x28, 0xEA, 0x36, 0xEA, 0x81, 0x5A, 0x08, 0x01, 0x06, 0x44, 0x02, 0xBB, 0x28, + 0x84, 0x24, 0xEB, 0x0E, 0x2E, 0x07, 0x34, 0x1B, 0x5A, 0x00, 0x01, 0x07, 0x2E, 0x27, 0x33, 0x91, + 0xEA, 0xCB, 0x84, 0x20, 0xD5, 0x11, 0xEA, 0xCB, 0xEB, 0x5C, 0x3C, 0x2C, 0x03, 0x21, 0x49, 0xFF, + 0xC6, 0x99, 0xD5, 0x0C, 0xB4, 0x60, 0xC3, 0x05, 0xA4, 0xC2, 0xAC, 0xC6, 0xA4, 0xC3, 0xAC, 0xC7, + 0x8C, 0x21, 0x50, 0x00, 0x00, 0x54, 0xE2, 0x22, 0xE9, 0xF6, 0xEA, 0xCB, 0x2E, 0x17, 0x35, 0xED, + 0x49, 0x00, 0x67, 0x9A, 0xEA, 0xCB, 0x49, 0x00, 0x5D, 0x91, 0xDD, 0x55, 0x5A, 0x08, 0x12, 0x0A, + 0xEA, 0x79, 0x84, 0x27, 0xEA, 0x84, 0x5A, 0x08, 0x01, 0x05, 0x84, 0x07, 0xEA, 0x28, 0xEA, 0x36, + 0xEA, 0x6B, 0x5A, 0x00, 0x01, 0x05, 0xEB, 0x34, 0x5A, 0x08, 0x01, 0x1D, 0xEB, 0xE4, 0x5A, 0x00, + 0x01, 0x05, 0xEB, 0x34, 0x5A, 0x08, 0x01, 0x17, 0xEB, 0x0B, 0x49, 0x00, 0x1B, 0xC0, 0xC8, 0x12, + 0x44, 0x02, 0xD6, 0xAC, 0x44, 0x12, 0xDE, 0xC4, 0x2E, 0x27, 0xEF, 0x57, 0x44, 0x32, 0xBC, 0x80, + 0x49, 0x00, 0x1C, 0x8E, 0x49, 0x00, 0x1B, 0xED, 0x5A, 0x08, 0x01, 0x05, 0xEB, 0x0B, 0x49, 0x00, + 0x2A, 0x73, 0xEA, 0xCB, 0xEB, 0x5C, 0x3C, 0x2C, 0x03, 0x21, 0x44, 0x32, 0xBF, 0x70, 0x49, 0xFF, + 0xE1, 0xE9, 0x49, 0xFF, 0xE9, 0xFE, 0xDD, 0x52, 0x5A, 0x00, 0x02, 0x05, 0xF8, 0xFC, 0x84, 0x01, + 0xD5, 0x05, 0xDD, 0x43, 0x5A, 0x08, 0x02, 0xFC, 0x84, 0x01, 0xFC, 0x80, 0xFC, 0x01, 0x49, 0x00, + 0x3A, 0xEC, 0xF0, 0x81, 0xF1, 0x01, 0x84, 0x00, 0x49, 0xFF, 0xEA, 0x75, 0xEA, 0xFD, 0xEA, 0xC5, + 0xDD, 0x5D, 0xEA, 0x24, 0xEB, 0xE3, 0xEB, 0xC2, 0x49, 0xFF, 0xDF, 0xDF, 0xEA, 0x24, 0xEB, 0xE3, + 0xEB, 0xC2, 0xEB, 0x67, 0x44, 0x42, 0xD8, 0xCC, 0x49, 0xFF, 0xE1, 0x5E, 0x2E, 0x07, 0x34, 0x0E, + 0x5A, 0x08, 0x01, 0x08, 0xEA, 0x24, 0x44, 0x12, 0xD3, 0xA4, 0x49, 0xFF, 0xDF, 0x40, 0xFC, 0x81, + 0x3C, 0x0C, 0x03, 0x22, 0x3C, 0x1C, 0x03, 0x21, 0xDD, 0x5D, 0xFC, 0x81, 0xFC, 0x00, 0xEA, 0x68, + 0x80, 0xC0, 0x84, 0x0C, 0xDD, 0x57, 0xDD, 0x47, 0xDD, 0x45, 0xAE, 0x40, 0x84, 0x09, 0x44, 0x10, + 0x00, 0xA1, 0xDD, 0x44, 0x49, 0xFF, 0xEA, 0xF3, 0x84, 0x09, 0x44, 0x10, 0x00, 0xA2, 0xDD, 0x44, + 0xDD, 0x41, 0xA6, 0x41, 0x5A, 0x18, 0x0D, 0x0E, 0x84, 0x09, 0x44, 0x10, 0x00, 0xA3, 0xDD, 0x44, + 0x2E, 0x07, 0xEE, 0xD3, 0x5A, 0x08, 0x01, 0x19, 0xDD, 0x47, 0xDD, 0x45, 0xAE, 0x40, 0xD5, 0x0E, + 0x2E, 0x17, 0xF3, 0x70, 0xC9, 0xF2, 0x44, 0x12, 0xBB, 0xCF, 0x44, 0x22, 0xBF, 0xCC, 0x49, 0x00, + 0x4E, 0xB9, 0xEA, 0xDD, 0x5A, 0x08, 0x01, 0xEA, 0xF8, 0x05, 0x84, 0x01, 0xEB, 0xF3, 0xC0, 0xFE, + 0x84, 0x02, 0x48, 0x00, 0x00, 0x8A, 0x84, 0x09, 0xEB, 0x53, 0xDD, 0x44, 0xDD, 0x41, 0xA6, 0x01, + 0x5A, 0x08, 0x0A, 0x08, 0xDD, 0x43, 0xC8, 0x05, 0xEB, 0xB7, 0xC8, 0x03, 0x49, 0xFF, 0xF0, 0x04, + 0x44, 0x02, 0xFE, 0xF2, 0xA6, 0x00, 0xC0, 0x07, 0xDD, 0x41, 0xA6, 0x41, 0x5A, 0x18, 0x03, 0x04, + 0x49, 0xFF, 0xD4, 0x2D, 0x84, 0x09, 0xEB, 0xC3, 0xDD, 0x44, 0x2E, 0x07, 0xEF, 0x4E, 0x5A, 0x08, + 0x01, 0x08, 0x44, 0x02, 0xBB, 0xC6, 0xEA, 0xD5, 0xEA, 0xD7, 0x49, 0xFF, 0xD4, 0x5A, 0x84, 0x0C, + 0x00, 0x13, 0x00, 0x50, 0xDD, 0x44, 0x84, 0x0D, 0x00, 0x13, 0x00, 0x51, 0xDD, 0x44, 0x84, 0x0E, + 0x00, 0x13, 0x00, 0x52, 0xDD, 0x44, 0x3C, 0x0D, 0xFC, 0x6F, 0xC0, 0x35, 0x84, 0x0B, 0x44, 0x10, + 0x00, 0x87, 0xDD, 0x44, 0x84, 0x00, 0xEA, 0x71, 0xEB, 0x55, 0xEA, 0x95, 0x5A, 0x08, 0x55, 0x0E, + 0xEB, 0x8B, 0xDD, 0x5A, 0x44, 0x22, 0xBB, 0x5D, 0x3C, 0x3D, 0xFC, 0x0B, 0x44, 0x42, 0xBD, 0x80, + 0x49, 0xFF, 0xD9, 0x08, 0xEA, 0xC0, 0xD5, 0x03, 0xEA, 0x40, 0xEB, 0x1E, 0xDD, 0x55, 0x49, 0xFF, + 0xD6, 0x48, 0x96, 0x00, 0x3E, 0x07, 0xEE, 0xC6, 0x5A, 0x00, 0x03, 0x37, 0x5A, 0x08, 0x02, 0x14, + 0xDD, 0x47, 0xDD, 0x45, 0xAE, 0x40, 0xDD, 0x51, 0xA6, 0x08, 0xC0, 0xFF, 0xDD, 0x43, 0x5A, 0x08, + 0x02, 0x03, 0xF8, 0x07, 0xDD, 0x47, 0xDD, 0x45, 0xAE, 0x40, 0x84, 0x01, 0xEB, 0xF3, 0xC0, 0xFE, + 0x48, 0xFF, 0xFF, 0x98, 0x84, 0x09, 0x44, 0x10, 0x00, 0xA6, 0xDD, 0x44, 0xDD, 0x51, 0xA6, 0x08, + 0x5A, 0x08, 0x02, 0x06, 0xDD, 0x4B, 0xA6, 0x00, 0x5A, 0x00, 0x02, 0x05, 0xEB, 0xB7, 0x5A, 0x08, + 0x01, 0x09, 0x84, 0x01, 0xAE, 0x08, 0xDD, 0x50, 0xAE, 0x08, 0x84, 0x00, 0x3E, 0x07, 0xF3, 0x52, + 0xDD, 0x41, 0xA6, 0x01, 0x5A, 0x00, 0x0B, 0x04, 0x49, 0xFF, 0xEF, 0xD4, 0x84, 0x09, 0x44, 0x10, + 0x00, 0xA7, 0xDD, 0x44, 0x84, 0x01, 0xFC, 0x80, 0xFC, 0x00, 0x5A, 0x08, 0x02, 0x16, 0x2E, 0x00, + 0x0E, 0x95, 0xC0, 0x17, 0x5A, 0x00, 0x01, 0x03, 0x84, 0x00, 0x3E, 0x07, 0xF2, 0xD8, 0x84, 0x00, + 0x3E, 0x00, 0x0E, 0x95, 0x49, 0xFF, 0xFC, 0x7F, 0x49, 0x00, 0x5D, 0x52, 0xC0, 0x0A, 0x84, 0x00, + 0xEA, 0x33, 0xEA, 0xE1, 0xD5, 0x06, 0x84, 0x00, 0x3E, 0x07, 0xF2, 0xD8, 0x3E, 0x07, 0xF2, 0xD7, + 0xFC, 0x80, 0x2E, 0x27, 0xF3, 0x04, 0x5A, 0x28, 0x01, 0x4D, 0xFC, 0x42, 0x84, 0x40, 0x3E, 0x27, + 0xF3, 0x04, 0x3C, 0x23, 0xF8, 0x88, 0x3C, 0x2B, 0xF9, 0x52, 0x3C, 0x23, 0xF8, 0x89, 0x3C, 0x2B, + 0xF9, 0x53, 0x3C, 0x23, 0xF8, 0x8A, 0x3C, 0x2B, 0xF9, 0x54, 0x3C, 0x23, 0xF8, 0x8B, 0x3C, 0x2B, + 0xF9, 0x55, 0x44, 0x42, 0xBF, 0x0C, 0x84, 0x60, 0x44, 0x72, 0xBF, 0x1C, 0x44, 0x60, 0x00, 0x64, + 0x45, 0x00, 0x00, 0x4F, 0x45, 0x10, 0x00, 0x50, 0x45, 0x20, 0x07, 0x6C, 0xFB, 0xE4, 0xA2, 0xA1, + 0x38, 0x53, 0x8D, 0x01, 0x40, 0x91, 0x19, 0x37, 0xE3, 0x25, 0xE8, 0x08, 0x42, 0x22, 0xC8, 0x73, + 0x40, 0x21, 0x4C, 0x57, 0x14, 0x22, 0x7F, 0xFF, 0xD5, 0x09, 0x42, 0x21, 0x40, 0x24, 0x42, 0x22, + 0x98, 0x73, 0x40, 0x21, 0x44, 0x57, 0x14, 0x22, 0x7F, 0xFF, 0x8C, 0x61, 0x5A, 0x38, 0x04, 0xE9, + 0x84, 0x40, 0xAC, 0x80, 0x84, 0x02, 0xEB, 0x00, 0x44, 0x03, 0x94, 0x70, 0xF0, 0x82, 0xF0, 0x81, + 0x44, 0x00, 0xFF, 0xFF, 0xF0, 0x83, 0xAC, 0x88, 0xEA, 0x62, 0xEA, 0xC7, 0xEA, 0x82, 0xFC, 0xC2, + 0xDD, 0x9E, 0xFC, 0x00, 0x2E, 0x07, 0xEF, 0x7C, 0xC8, 0x0D, 0xEB, 0x58, 0x5A, 0x00, 0x01, 0x17, + 0x2E, 0x07, 0xEF, 0x54, 0x5A, 0x00, 0x01, 0x13, 0x2E, 0x07, 0xEF, 0x37, 0x5A, 0x08, 0x01, 0x27, + 0xD5, 0x0D, 0x44, 0x12, 0xE2, 0xD8, 0x8E, 0x01, 0x40, 0x00, 0x80, 0x60, 0x49, 0x00, 0x2C, 0xA3, + 0x2E, 0x07, 0xEF, 0x7C, 0x8E, 0x01, 0x3E, 0x07, 0xEF, 0x7C, 0x2E, 0x07, 0xEF, 0x37, 0x5A, 0x08, + 0x01, 0x07, 0x84, 0x00, 0x3E, 0x07, 0xEF, 0x37, 0x49, 0x00, 0x2C, 0x9C, 0xEB, 0x58, 0x5A, 0x08, + 0x01, 0x08, 0x84, 0x00, 0xEA, 0xAF, 0x3E, 0x07, 0xEF, 0x5A, 0x49, 0xFF, 0xCD, 0x7C, 0x3C, 0x0D, + 0xFC, 0x41, 0x44, 0x12, 0xBC, 0x04, 0x49, 0xFF, 0xFF, 0x7E, 0xFC, 0x80, 0xFC, 0x40, 0xEA, 0x68, + 0x2E, 0x67, 0xEF, 0x61, 0x81, 0x20, 0x5A, 0x68, 0x01, 0x34, 0xDD, 0x52, 0xEA, 0xD8, 0xDD, 0x40, + 0x80, 0xE0, 0x44, 0x10, 0x00, 0x6A, 0xC0, 0x16, 0x84, 0x04, 0xDD, 0x44, 0x3C, 0x03, 0xF7, 0xC0, + 0x5A, 0x00, 0x01, 0x03, 0xF8, 0x2D, 0x84, 0xE0, 0x84, 0x04, 0x44, 0x10, 0x00, 0x6B, 0xDD, 0x44, + 0x10, 0x74, 0x80, 0x50, 0x3E, 0x77, 0xEF, 0x61, 0x49, 0xFF, 0xF5, 0xF9, 0x3E, 0x77, 0xF2, 0xBF, + 0xF8, 0x1F, 0x84, 0x02, 0xEA, 0x2D, 0x84, 0x04, 0xDD, 0x44, 0x3C, 0x03, 0xF7, 0xC0, 0x5A, 0x00, + 0x01, 0x03, 0xF8, 0x16, 0x84, 0x04, 0x44, 0x10, 0x00, 0x6B, 0xDD, 0x44, 0x10, 0x74, 0x80, 0x50, + 0x3E, 0x77, 0xEF, 0x61, 0x49, 0xFF, 0xF5, 0xE3, 0x3C, 0x78, 0x07, 0xF4, 0xF8, 0x09, 0x2E, 0x67, + 0xEE, 0xBA, 0x5A, 0x60, 0x01, 0x08, 0x84, 0x00, 0x3E, 0x07, 0xEE, 0xFB, 0x84, 0xC1, 0x48, 0x00, + 0x00, 0x75, 0x84, 0x04, 0x44, 0x10, 0x00, 0x40, 0xDD, 0x44, 0x2E, 0x07, 0xEE, 0xFB, 0xC8, 0x05, + 0x84, 0x08, 0xDD, 0x4A, 0x3E, 0x67, 0xEE, 0xFB, 0x84, 0x04, 0x44, 0x10, 0x00, 0x4A, 0xDD, 0x44, + 0xEB, 0x6F, 0x49, 0xFF, 0xF4, 0x5D, 0x5A, 0x00, 0x02, 0x60, 0x5A, 0x00, 0x13, 0x2C, 0x84, 0x04, + 0x44, 0x10, 0x00, 0x4B, 0xDD, 0x44, 0xDD, 0x52, 0x5A, 0x08, 0x01, 0x27, 0x84, 0x04, 0x44, 0x10, + 0x00, 0xAA, 0xDD, 0x44, 0xDD, 0x4B, 0xA7, 0x80, 0x97, 0xB0, 0xCE, 0x1C, 0x84, 0x04, 0xEB, 0xC7, + 0xDD, 0x44, 0x3E, 0x67, 0xF3, 0x7E, 0x49, 0xFF, 0xF2, 0xB9, 0x5A, 0x00, 0x13, 0x14, 0x84, 0x04, + 0x44, 0x10, 0x00, 0x4D, 0xDD, 0x44, 0xDD, 0x40, 0xC0, 0x06, 0x2E, 0x07, 0xEF, 0x65, 0x5A, 0x08, + 0x01, 0x0A, 0xF8, 0x1D, 0xF8, 0x1E, 0x5A, 0x00, 0x13, 0x06, 0x84, 0x04, 0x44, 0x10, 0x00, 0x4E, + 0xDD, 0x44, 0xFA, 0xC3, 0xD5, 0x32, 0x84, 0x04, 0x44, 0x10, 0x00, 0xBB, 0xDD, 0x44, 0x84, 0x00, + 0x3E, 0x07, 0xF3, 0x7E, 0xDD, 0x40, 0xC0, 0x17, 0xDD, 0x4B, 0xA6, 0x00, 0xC8, 0xF3, 0x2E, 0x07, + 0xEF, 0x65, 0x5A, 0x08, 0x01, 0xF0, 0x84, 0x04, 0xEB, 0xC7, 0xDD, 0x44, 0x49, 0xFF, 0xFD, 0xE0, + 0x49, 0xFF, 0xF5, 0x4A, 0x5A, 0x00, 0x13, 0xE7, 0x84, 0x04, 0x44, 0x10, 0x00, 0x4D, 0xDD, 0x44, + 0xFA, 0xC3, 0xD5, 0x13, 0x49, 0xFF, 0xFF, 0x27, 0x2E, 0x07, 0xEF, 0x05, 0xC0, 0x03, 0xEB, 0x12, + 0xC0, 0xD9, 0x84, 0x04, 0xEB, 0xC7, 0xDD, 0x44, 0x49, 0x00, 0x09, 0xCE, 0x49, 0xFF, 0xF5, 0x20, + 0x5A, 0x08, 0x13, 0xEC, 0xD5, 0xCF, 0x80, 0xC0, 0x80, 0x06, 0xFC, 0xC0, 0x3C, 0x0F, 0xFC, 0x8B, + 0xDD, 0x9E, 0x3C, 0x0F, 0xFC, 0x8A, 0xDD, 0x9E, 0x2E, 0x07, 0xF4, 0x29, 0xC0, 0x03, 0x8E, 0x01, + 0xEB, 0x7B, 0x2E, 0x07, 0xF4, 0x29, 0xC8, 0x02, 0xEB, 0xD6, 0x2E, 0x07, 0xF4, 0x28, 0xDD, 0x9E, + 0x84, 0x1F, 0x3C, 0x0F, 0xFA, 0xCB, 0x84, 0x00, 0xEB, 0x7B, 0xEB, 0xD6, 0xDD, 0x9E, 0xFC, 0x63, + 0xA1, 0x05, 0x40, 0x22, 0x08, 0x40, 0x01, 0x31, 0x00, 0x00, 0x00, 0x91, 0x00, 0x01, 0x00, 0xA1, + 0x00, 0x02, 0x00, 0xB1, 0x00, 0x03, 0x86, 0x20, 0xE1, 0xA3, 0x4E, 0xF2, 0x00, 0xDE, 0xA0, 0x81, + 0x38, 0x51, 0x45, 0x01, 0x4C, 0x58, 0xC0, 0xD6, 0xA1, 0x05, 0x41, 0x58, 0x88, 0x08, 0x88, 0x95, + 0xA7, 0xA0, 0xE4, 0xC3, 0xE9, 0x03, 0x8E, 0xC3, 0xD5, 0x02, 0x84, 0xC0, 0xA7, 0x61, 0xEA, 0x9B, + 0x8C, 0xA3, 0xE0, 0xA2, 0xE9, 0x02, 0x9F, 0x51, 0xA6, 0xA2, 0xE4, 0x43, 0xE9, 0x03, 0x8E, 0x43, + 0xD5, 0x02, 0x84, 0x40, 0xA7, 0x23, 0x2E, 0x77, 0x33, 0x8B, 0x8C, 0x83, 0xE0, 0x87, 0xE9, 0x02, + 0x9F, 0x39, 0xE1, 0x26, 0x4E, 0xF3, 0x00, 0xB6, 0xE0, 0xB3, 0x4E, 0xF3, 0x00, 0xB3, 0xE1, 0x62, + 0x4E, 0xF3, 0x00, 0xB0, 0xE0, 0x8A, 0x4E, 0xF3, 0x00, 0xAD, 0x42, 0x63, 0x4C, 0x00, 0x42, 0x52, + 0xA4, 0x01, 0x42, 0x42, 0x2C, 0x01, 0xF6, 0x81, 0xF5, 0x82, 0x42, 0x21, 0x28, 0x00, 0xF4, 0x83, + 0xF4, 0x03, 0xE0, 0x82, 0x4E, 0xF3, 0x00, 0x9E, 0xE4, 0x44, 0x85, 0xA0, 0xE9, 0x03, 0x50, 0xD1, + 0x7F, 0xFD, 0x9D, 0x13, 0xF7, 0x01, 0xF4, 0x85, 0xF4, 0x02, 0xE0, 0x87, 0x4E, 0xF3, 0x00, 0x8F, + 0xEB, 0x80, 0x44, 0x53, 0xF0, 0x4A, 0xAF, 0x28, 0x3C, 0x4D, 0xFC, 0x8A, 0x80, 0xA7, 0x00, 0x82, + 0x00, 0x02, 0x05, 0x60, 0x00, 0x00, 0x42, 0x51, 0x20, 0x73, 0x38, 0x5B, 0x15, 0x00, 0x5A, 0x50, + 0xFF, 0x7B, 0x05, 0x70, 0x00, 0x01, 0x38, 0x5B, 0x95, 0x11, 0x4E, 0x54, 0x00, 0x75, 0xE4, 0xE4, + 0x84, 0xC0, 0xE9, 0x02, 0x9F, 0xBB, 0x05, 0x80, 0x00, 0x05, 0xA7, 0x63, 0x41, 0x0C, 0x54, 0x00, + 0x00, 0xE8, 0x00, 0x01, 0x40, 0xF7, 0x18, 0x07, 0xE9, 0x66, 0x9D, 0x3B, 0x51, 0x24, 0x7F, 0xFF, + 0x83, 0xC4, 0x42, 0x42, 0x48, 0x01, 0x01, 0x28, 0x00, 0x00, 0xE0, 0x92, 0xE9, 0x5C, 0x00, 0xC8, + 0x00, 0x03, 0x40, 0xF6, 0x34, 0x07, 0xE9, 0x57, 0x04, 0xFF, 0x80, 0x05, 0x8E, 0xA1, 0x01, 0x08, + 0x00, 0x02, 0x42, 0x57, 0x94, 0x01, 0xE0, 0xB0, 0xE9, 0x4E, 0x43, 0xE2, 0x38, 0x01, 0x3C, 0x40, + 0x06, 0x2A, 0x43, 0x06, 0xC0, 0x00, 0x83, 0x84, 0x42, 0x48, 0x20, 0x24, 0x43, 0x23, 0x48, 0x00, + 0x42, 0x52, 0xB0, 0x01, 0xF4, 0x84, 0x86, 0x80, 0xE0, 0xB0, 0xE9, 0x3D, 0xF4, 0x04, 0x81, 0xD2, + 0x88, 0x94, 0x88, 0x92, 0x95, 0x21, 0x40, 0xFF, 0x38, 0x07, 0xE9, 0x31, 0x38, 0x6B, 0x10, 0x00, + 0x5A, 0x60, 0xFF, 0x2A, 0x41, 0x9B, 0x98, 0x20, 0x02, 0xCC, 0x80, 0x00, 0x40, 0xF6, 0x00, 0x11, + 0x4E, 0xF5, 0x00, 0x22, 0x04, 0xF0, 0x80, 0x05, 0x40, 0xF7, 0x90, 0x00, 0x02, 0xF7, 0x80, 0x00, + 0xEA, 0xE4, 0x40, 0xF7, 0xF0, 0x07, 0xE9, 0x17, 0x44, 0x2F, 0x80, 0x00, 0x40, 0x26, 0x08, 0x04, + 0x12, 0x2C, 0x80, 0x00, 0x40, 0x6C, 0x18, 0x40, 0xA6, 0xB0, 0x43, 0x39, 0x88, 0x01, 0xA6, 0xB1, + 0x42, 0x94, 0x88, 0x00, 0xA6, 0xB2, 0x42, 0xA5, 0x08, 0x01, 0xA6, 0xB3, 0x42, 0xB5, 0x88, 0x00, + 0x48, 0xFF, 0xFF, 0x33, 0x50, 0xE7, 0x00, 0x01, 0x8C, 0x82, 0xD5, 0xCE, 0x8D, 0x81, 0x41, 0x4A, + 0x20, 0x00, 0xD5, 0xC3, 0x8C, 0xE1, 0x48, 0xFF, 0xFF, 0x71, 0x8C, 0x41, 0x48, 0xFF, 0xFF, 0x62, + 0x8D, 0xA1, 0x48, 0xFF, 0xFF, 0x23, 0xFC, 0xE3, 0xFC, 0x20, 0xA6, 0x12, 0xC0, 0x03, 0x8E, 0x01, + 0xAE, 0x12, 0x3C, 0x7D, 0xFC, 0x8A, 0xA7, 0x53, 0xA6, 0x3B, 0x8E, 0x01, 0xD0, 0x03, 0x8C, 0xA1, + 0xAF, 0x53, 0xA6, 0x10, 0xC0, 0x03, 0x8E, 0x01, 0xAE, 0x10, 0xA6, 0x3A, 0xA7, 0x51, 0x8E, 0x01, + 0xD0, 0x03, 0x8C, 0xA1, 0xAF, 0x51, 0x84, 0x00, 0xA7, 0x50, 0x01, 0x11, 0x00, 0x01, 0x80, 0x60, + 0xE3, 0xA5, 0xE9, 0x23, 0xA7, 0x92, 0x01, 0x21, 0x00, 0x03, 0xE3, 0xC6, 0xE9, 0x1C, 0xA7, 0x3A, + 0x81, 0xE5, 0x42, 0xF3, 0x10, 0x73, 0x05, 0x00, 0x80, 0x05, 0x40, 0x48, 0x3C, 0x20, 0x03, 0x02, + 0x00, 0x00, 0x41, 0x08, 0x00, 0x11, 0xE5, 0x9A, 0xE9, 0x0C, 0x03, 0x02, 0x00, 0x00, 0x02, 0xF2, + 0x00, 0x00, 0x41, 0x08, 0x00, 0x11, 0xEA, 0xE4, 0xE0, 0x6F, 0x88, 0x10, 0xE8, 0x02, 0xA4, 0xE0, + 0x8C, 0xC1, 0xD5, 0xE4, 0x8C, 0xA1, 0xD5, 0xDD, 0xC3, 0x06, 0x44, 0x10, 0x01, 0xF4, 0xFE, 0x0C, + 0x40, 0x00, 0x0C, 0x17, 0xFC, 0xA0, 0xFC, 0x42, 0xF1, 0x81, 0x3C, 0x1D, 0xFC, 0x8B, 0x80, 0xC0, + 0x84, 0x1F, 0x3C, 0x0F, 0xFA, 0xCB, 0xA6, 0x0B, 0x81, 0x22, 0x5C, 0xF0, 0x00, 0x42, 0xE9, 0x03, + 0xEB, 0x7A, 0xAE, 0x0B, 0xA6, 0x08, 0x5C, 0xF0, 0x00, 0x42, 0xE9, 0x03, 0xEB, 0x7A, 0xAE, 0x08, + 0x2E, 0x27, 0xF3, 0x56, 0x44, 0x00, 0x03, 0xE8, 0x5A, 0x28, 0x01, 0x07, 0xA7, 0xCC, 0xA6, 0x4D, + 0xFF, 0xC4, 0x97, 0xF9, 0xD5, 0x05, 0xA7, 0xCB, 0xA6, 0x48, 0xFF, 0xC4, 0x97, 0xF9, 0xFE, 0x0C, + 0x00, 0x24, 0x80, 0x00, 0x40, 0xA0, 0x00, 0x13, 0xC2, 0x27, 0x84, 0x20, 0x3C, 0x0D, 0xFA, 0xCB, + 0x80, 0xA1, 0xE0, 0xA2, 0xE8, 0x0E, 0xA0, 0xF1, 0x38, 0x31, 0x95, 0x01, 0xDB, 0x08, 0xA0, 0xF2, + 0x38, 0x31, 0x95, 0x01, 0xE2, 0x23, 0x40, 0x02, 0xBC, 0x1B, 0xEB, 0xA5, 0x8C, 0xA1, 0xD5, 0xF2, + 0x3C, 0x1B, 0xF7, 0xCF, 0xA0, 0x75, 0x3C, 0x0F, 0xFA, 0xCB, 0xEA, 0xC3, 0x3A, 0x00, 0x00, 0x00, + 0xB0, 0x43, 0x3A, 0x00, 0x80, 0x20, 0xF1, 0x01, 0x80, 0x06, 0xB0, 0x83, 0xF8, 0x59, 0xE3, 0x40, + 0xE9, 0x5B, 0xE2, 0xE0, 0xE9, 0x03, 0x84, 0x20, 0xD5, 0x6C, 0x3C, 0x7D, 0xFA, 0xCB, 0x44, 0x2F, + 0x80, 0x00, 0x84, 0x00, 0xFE, 0xBF, 0x00, 0x34, 0x80, 0x00, 0xE0, 0x03, 0xE8, 0x08, 0xA0, 0x71, + 0xEB, 0xB2, 0xA5, 0x48, 0xDF, 0x02, 0xAC, 0x88, 0x8C, 0x01, 0xD5, 0xF6, 0x80, 0x06, 0xF1, 0x01, + 0x96, 0xB8, 0x49, 0xFF, 0xFE, 0x66, 0xA0, 0x35, 0x40, 0x10, 0x1C, 0x40, 0xEA, 0xCF, 0xB0, 0x83, + 0x3A, 0x11, 0x04, 0x20, 0x00, 0x34, 0x80, 0x00, 0x8C, 0x03, 0x84, 0x20, 0xE0, 0x23, 0xE8, 0x2D, + 0xA0, 0xB1, 0x38, 0x51, 0x05, 0x01, 0x96, 0xAB, 0x4E, 0x24, 0x00, 0x25, 0x54, 0x52, 0xFF, 0xFF, + 0xD7, 0x21, 0xD9, 0x20, 0x00, 0x20, 0x7F, 0xFD, 0x00, 0x4F, 0x80, 0x0C, 0xE2, 0x82, 0xE9, 0x03, + 0x10, 0x2F, 0x80, 0x0C, 0x00, 0x20, 0x7F, 0xFE, 0x00, 0x4F, 0x80, 0x0D, 0xE2, 0x44, 0xE9, 0x03, + 0x10, 0x2F, 0x80, 0x0D, 0x00, 0x20, 0x7F, 0xFF, 0x00, 0x4F, 0x80, 0x0E, 0xE2, 0x82, 0xE9, 0x03, + 0x10, 0x2F, 0x80, 0x0E, 0xA6, 0x80, 0x00, 0x4F, 0x80, 0x0F, 0xE2, 0x44, 0xE9, 0x03, 0x10, 0x2F, + 0x80, 0x0F, 0x8C, 0x21, 0x8C, 0x04, 0xD5, 0xD3, 0x80, 0x06, 0xF1, 0x01, 0xB0, 0x83, 0x49, 0xFF, + 0xFF, 0x15, 0xE3, 0x40, 0xE8, 0x09, 0x84, 0x01, 0xEB, 0xD6, 0x3C, 0x0D, 0xFC, 0x8B, 0x84, 0x21, + 0xA6, 0x01, 0xEB, 0x7B, 0xD5, 0x0E, 0x84, 0x00, 0x00, 0x14, 0x80, 0x00, 0xE0, 0x01, 0xE8, 0x9C, + 0xA0, 0x71, 0xEB, 0xB2, 0xA4, 0x88, 0x8C, 0x01, 0x54, 0x21, 0x7F, 0xFF, 0xAC, 0x88, 0xD5, 0xF5, + 0x2E, 0x07, 0xF4, 0x29, 0xC0, 0x0B, 0x5A, 0x18, 0x01, 0x05, 0x3E, 0x17, 0xF4, 0x28, 0xD5, 0x06, + 0x8E, 0x01, 0x96, 0x00, 0xEB, 0x7B, 0xC8, 0x02, 0xEB, 0xD6, 0x2E, 0x07, 0xF4, 0x28, 0x5A, 0x08, + 0x01, 0x05, 0x84, 0x20, 0x10, 0x14, 0x80, 0x00, 0xFC, 0xC2, 0xB4, 0x20, 0xC1, 0x21, 0x8E, 0x24, + 0xE6, 0x22, 0xE9, 0x1E, 0x04, 0x10, 0x00, 0x1C, 0x5A, 0x10, 0x02, 0x1B, 0xC3, 0x0C, 0x22, 0x20, + 0x00, 0x02, 0x22, 0x10, 0x00, 0x03, 0xAC, 0x86, 0xAC, 0x47, 0x3C, 0x2B, 0xFA, 0x18, 0x3C, 0x1B, + 0xFA, 0x19, 0xDD, 0x9E, 0x22, 0x20, 0x00, 0x04, 0x22, 0x10, 0x00, 0x05, 0x12, 0x20, 0x00, 0x08, + 0x12, 0x10, 0x00, 0x09, 0x3C, 0x2B, 0xFA, 0x16, 0x3C, 0x1B, 0xFA, 0x17, 0xDD, 0x9E, 0xC3, 0x08, + 0x3C, 0x13, 0xFA, 0x18, 0xAC, 0x46, 0x3C, 0x13, 0xFA, 0x19, 0xAC, 0x47, 0xD5, 0x09, 0x3C, 0x13, + 0xFA, 0x16, 0x12, 0x10, 0x00, 0x08, 0x3C, 0x13, 0xFA, 0x17, 0x12, 0x10, 0x00, 0x09, 0x84, 0x3F, + 0x10, 0x10, 0x00, 0x74, 0x10, 0x10, 0x00, 0x75, 0x10, 0x10, 0x00, 0x76, 0x10, 0x10, 0x00, 0x77, + 0xDD, 0x9E, 0xFC, 0x41, 0x80, 0xC1, 0x81, 0x23, 0xCC, 0x0F, 0x5A, 0x58, 0x01, 0x05, 0x04, 0x00, + 0x00, 0x18, 0xD5, 0x03, 0x04, 0x00, 0x00, 0x1A, 0xC2, 0x0F, 0x02, 0x70, 0x00, 0x1F, 0x02, 0x20, + 0x00, 0x1E, 0x97, 0xFB, 0xD5, 0x12, 0x5A, 0x58, 0x01, 0x05, 0x04, 0x00, 0x00, 0x19, 0xD5, 0x03, + 0x04, 0x00, 0x00, 0x1B, 0xCA, 0x05, 0xA5, 0xC0, 0xA4, 0x81, 0x97, 0xFB, 0xD5, 0x06, 0x02, 0x70, + 0x00, 0x31, 0x02, 0x20, 0x00, 0x30, 0x97, 0xFB, 0x96, 0x93, 0xCA, 0x02, 0x84, 0x41, 0x80, 0x27, + 0x80, 0x06, 0x49, 0x00, 0x15, 0x75, 0x00, 0x14, 0x80, 0x00, 0x5A, 0x10, 0xFF, 0x05, 0x8C, 0x21, + 0x88, 0x01, 0x92, 0x01, 0xEA, 0x94, 0x80, 0x3F, 0xB0, 0x81, 0x49, 0x00, 0x15, 0xCE, 0xB4, 0x1F, + 0x38, 0x13, 0x01, 0x11, 0xF0, 0x01, 0x38, 0x23, 0x01, 0x11, 0x84, 0x02, 0xEB, 0xE2, 0xEB, 0x0F, + 0xEA, 0x9F, 0xFC, 0xC1, 0xFC, 0x00, 0xA6, 0x08, 0x80, 0xC1, 0x5A, 0x08, 0x01, 0x07, 0x3C, 0x0C, + 0x02, 0xCA, 0x3C, 0x1C, 0x02, 0xCE, 0xF8, 0x10, 0xA6, 0x31, 0x5A, 0x08, 0x01, 0x07, 0x3C, 0x0C, + 0x02, 0xCB, 0x3C, 0x1C, 0x02, 0xCF, 0xF8, 0x11, 0xA6, 0x32, 0x5A, 0x08, 0x01, 0x08, 0x3C, 0x0C, + 0x02, 0xCC, 0x3C, 0x1C, 0x02, 0xD0, 0xDD, 0x5C, 0xDD, 0x46, 0xA6, 0x33, 0x5A, 0x08, 0x01, 0x08, + 0x3C, 0x0C, 0x02, 0xCD, 0x3C, 0x1C, 0x02, 0xD1, 0xEA, 0x27, 0xDD, 0x46, 0xFC, 0x80, 0xFC, 0x00, + 0x44, 0x53, 0x90, 0xE5, 0xA6, 0xE8, 0xA6, 0xA9, 0x44, 0x43, 0x90, 0xE9, 0x40, 0x21, 0x89, 0x04, + 0xA7, 0xA0, 0xA6, 0xE1, 0x96, 0x93, 0x40, 0x33, 0x0D, 0x04, 0x96, 0xDB, 0xE0, 0x62, 0xE8, 0x04, + 0xA6, 0xE8, 0xA6, 0xA9, 0xD5, 0x03, 0xA6, 0xE0, 0xA6, 0xA1, 0x40, 0x21, 0x89, 0x04, 0x96, 0x93, + 0x5E, 0xF1, 0x09, 0xC4, 0xE9, 0x07, 0x44, 0x20, 0x05, 0x14, 0xAC, 0x80, 0x44, 0x20, 0x00, 0x46, + 0xD5, 0x17, 0x50, 0x21, 0x7E, 0xD4, 0x96, 0xD1, 0x5C, 0xF1, 0x88, 0x98, 0xE8, 0x0F, 0x44, 0x30, + 0x05, 0x14, 0xFE, 0xD4, 0x44, 0x40, 0x08, 0x98, 0x40, 0x31, 0x90, 0x76, 0xAC, 0xC0, 0x44, 0x30, + 0x00, 0x46, 0xFE, 0x9C, 0x40, 0x21, 0x10, 0x56, 0xD5, 0x03, 0x84, 0x40, 0xAC, 0x80, 0xAC, 0x88, + 0x22, 0x10, 0x80, 0x00, 0x22, 0x20, 0x00, 0x00, 0xE0, 0x41, 0xE8, 0x02, 0xAC, 0x40, 0xFC, 0x80, + 0xFC, 0x60, 0x44, 0x33, 0x90, 0xE5, 0xF8, 0x06, 0x4E, 0x46, 0x00, 0x03, 0xF8, 0x0B, 0x44, 0x33, + 0x90, 0xE9, 0xA7, 0x58, 0xA7, 0x19, 0x40, 0x42, 0x91, 0x04, 0x97, 0x23, 0x83, 0xFF, 0x4E, 0x46, + 0x00, 0x09, 0xA7, 0x18, 0x84, 0x81, 0xAF, 0x18, 0xA7, 0x19, 0x84, 0x80, 0xAF, 0x19, 0x83, 0xFF, + 0xA6, 0xC0, 0x5A, 0x38, 0x01, 0x2F, 0x44, 0x62, 0xA5, 0x0A, 0x44, 0xB0, 0xE8, 0xCA, 0x45, 0x13, + 0x90, 0xE5, 0x85, 0x20, 0x44, 0xA2, 0xA5, 0x4A, 0x51, 0x33, 0x01, 0x80, 0x82, 0x06, 0x80, 0xF0, + 0x38, 0x43, 0xAC, 0x05, 0xA4, 0xF8, 0x00, 0x58, 0x80, 0x00, 0x00, 0x78, 0x80, 0x01, 0x23, 0x21, + 0x00, 0x00, 0x40, 0x72, 0x9D, 0x04, 0x22, 0x50, 0x80, 0x00, 0x96, 0xDB, 0x8A, 0xB2, 0xFE, 0xEC, + 0x97, 0xFB, 0x97, 0x23, 0x40, 0x31, 0x9C, 0x76, 0x8A, 0x92, 0x9A, 0xE3, 0x96, 0xDB, 0x42, 0x31, + 0xA4, 0x00, 0x1A, 0x38, 0x00, 0x20, 0x4D, 0x09, 0xFF, 0xE4, 0x8C, 0xC2, 0x4C, 0x65, 0x7F, 0xDE, + 0xA6, 0x01, 0x5A, 0x08, 0x01, 0x30, 0x44, 0x52, 0xA6, 0x9A, 0x44, 0xA0, 0xE8, 0xBA, 0x45, 0x03, + 0x90, 0xE9, 0x86, 0x60, 0x44, 0x92, 0xA6, 0xA2, 0x51, 0x22, 0x81, 0x90, 0x80, 0xE5, 0x80, 0xC7, + 0x38, 0x33, 0x28, 0x05, 0xA4, 0x30, 0x00, 0x48, 0x00, 0x00, 0x00, 0x68, 0x00, 0x01, 0x23, 0x11, + 0x00, 0x00, 0x40, 0x62, 0x19, 0x04, 0x22, 0x40, 0x80, 0x00, 0x96, 0x03, 0x8A, 0x91, 0xFE, 0x24, + 0x97, 0xB3, 0x96, 0xDB, 0x40, 0x00, 0x18, 0x16, 0x8A, 0x71, 0x9A, 0x18, 0x96, 0x03, 0x42, 0x00, + 0x4C, 0x00, 0x1A, 0x03, 0x80, 0x04, 0x4C, 0x79, 0x7F, 0xE4, 0x8C, 0xA2, 0x4C, 0x54, 0xFF, 0xDE, + 0xFC, 0xE0, 0xFC, 0xE0, 0xFC, 0x02, 0x84, 0x00, 0x10, 0x0F, 0x80, 0x04, 0x10, 0x0F, 0x80, 0x05, + 0x10, 0x0F, 0x80, 0x06, 0xEA, 0x57, 0x10, 0x0F, 0x80, 0x08, 0x10, 0x0F, 0x80, 0x09, 0x10, 0x0F, + 0x80, 0x0A, 0xEA, 0xDA, 0x10, 0x0F, 0x80, 0x0B, 0x2E, 0x67, 0x33, 0xAC, 0x84, 0x01, 0x10, 0x0F, + 0x80, 0x0C, 0x50, 0x1F, 0x80, 0x02, 0x80, 0x1F, 0x84, 0x60, 0x3C, 0x23, 0xF7, 0xC6, 0xF8, 0x38, + 0x94, 0x71, 0x44, 0x02, 0xA0, 0x5A, 0x44, 0x53, 0x30, 0x70, 0x44, 0x33, 0x31, 0x38, 0xF8, 0x09, + 0x96, 0x93, 0xAC, 0x81, 0x88, 0x01, 0xDB, 0xFC, 0x44, 0x02, 0xA0, 0x5E, 0x44, 0x33, 0x32, 0x00, + 0xA4, 0xA8, 0x8C, 0xA4, 0x96, 0x93, 0xAC, 0x80, 0x02, 0x22, 0xFF, 0xFF, 0x83, 0xFF, 0x96, 0x93, + 0xAC, 0x81, 0x88, 0x01, 0xDB, 0xF6, 0x84, 0x00, 0x10, 0x0F, 0x80, 0x04, 0x84, 0x01, 0xB0, 0x41, + 0x10, 0x0F, 0x80, 0x05, 0x44, 0x02, 0xD3, 0xA4, 0x49, 0xFF, 0xFE, 0xDE, 0xB0, 0x01, 0x49, 0x00, + 0x01, 0x3A, 0xB0, 0x01, 0x80, 0x3F, 0x50, 0x2F, 0x80, 0x02, 0xF8, 0x10, 0xFC, 0x82, 0xFC, 0x02, + 0x3C, 0x23, 0xF7, 0xC6, 0xF0, 0x81, 0x50, 0x1F, 0x80, 0x0E, 0xB0, 0x03, 0x84, 0x61, 0x49, 0xFF, + 0xFE, 0xF0, 0xF0, 0x01, 0xB0, 0x43, 0x50, 0x2F, 0x80, 0x0E, 0x49, 0xFF, 0xFF, 0x2B, 0xFC, 0x82, + 0xFC, 0x02, 0xEB, 0x00, 0x44, 0x00, 0xFF, 0xFF, 0xF0, 0x83, 0xF1, 0x82, 0xF2, 0x81, 0xEA, 0xC7, + 0xEA, 0x62, 0xEA, 0x82, 0xFC, 0x82, 0xFC, 0x67, 0x81, 0x40, 0xEA, 0x38, 0x5A, 0x08, 0x01, 0x07, + 0x84, 0x00, 0x3C, 0x0B, 0xF9, 0x56, 0x48, 0x00, 0x00, 0xB8, 0x3C, 0x03, 0xF9, 0x56, 0x5A, 0x08, + 0x01, 0x04, 0x48, 0x00, 0x00, 0xB8, 0x84, 0x20, 0xDD, 0x5C, 0x44, 0x03, 0x8D, 0xD4, 0x44, 0x73, + 0x90, 0xE5, 0xEA, 0x2F, 0x84, 0x20, 0xEA, 0x27, 0x44, 0x03, 0x8F, 0x54, 0xEA, 0x2F, 0x80, 0x07, + 0x84, 0x20, 0x84, 0x48, 0xEA, 0x2F, 0x84, 0x21, 0xA6, 0x38, 0x84, 0xC0, 0xAE, 0x78, 0xA6, 0x39, + 0xAF, 0xB9, 0x44, 0x03, 0x90, 0xE9, 0xA6, 0x80, 0xAE, 0x40, 0xA6, 0x81, 0x81, 0x66, 0xAF, 0x81, + 0x80, 0xE6, 0x44, 0xE3, 0x8D, 0xD4, 0x81, 0x21, 0x44, 0x8F, 0x80, 0x01, 0x44, 0xD0, 0x00, 0x32, + 0x2E, 0x47, 0x33, 0xAD, 0xEA, 0x96, 0xE2, 0xE4, 0xE8, 0x2B, 0x5A, 0x70, 0x02, 0x05, 0x85, 0x88, + 0x5A, 0x78, 0x05, 0x03, 0x85, 0x89, 0x84, 0x40, 0x40, 0x17, 0x2C, 0x20, 0xEB, 0x22, 0x40, 0x00, + 0x18, 0x20, 0xF2, 0x82, 0xF2, 0x83, 0xF2, 0x84, 0xF2, 0x85, 0xF2, 0x86, 0xF2, 0x87, 0xB6, 0x7F, + 0x14, 0x9F, 0x80, 0x01, 0x14, 0x8F, 0x80, 0x08, 0x14, 0xDF, 0x80, 0x09, 0x14, 0x9F, 0x80, 0x0A, + 0x80, 0x41, 0x80, 0x8C, 0x84, 0xA1, 0xEA, 0x23, 0x2E, 0x07, 0x33, 0x8A, 0x8C, 0xE1, 0x42, 0x66, + 0x00, 0x73, 0x88, 0x0B, 0x97, 0xB1, 0x40, 0xB0, 0x00, 0x13, 0x97, 0xF9, 0xD5, 0xD2, 0x84, 0xC0, + 0x84, 0xE1, 0xEB, 0xFF, 0x84, 0x00, 0x85, 0x23, 0x80, 0x41, 0x12, 0x0F, 0x80, 0x1B, 0xB6, 0x7F, + 0x44, 0x03, 0x8D, 0xD4, 0xF8, 0x27, 0xF8, 0x2E, 0xEA, 0x54, 0x02, 0x1F, 0x80, 0x1B, 0x44, 0x03, + 0x90, 0xE5, 0xF8, 0x35, 0x2E, 0x07, 0x33, 0xAC, 0xEA, 0xAD, 0x84, 0x68, 0xFF, 0x04, 0x44, 0x0F, + 0x80, 0x01, 0x44, 0x13, 0x8F, 0x54, 0xF0, 0x88, 0xEB, 0x07, 0x80, 0x41, 0xB6, 0x7F, 0xF0, 0x89, + 0x97, 0x20, 0xEB, 0x22, 0x80, 0xA7, 0xF6, 0x81, 0xF7, 0x82, 0xF8, 0x0F, 0xF6, 0x87, 0xF7, 0x8A, + 0xEA, 0x23, 0x2E, 0x37, 0x33, 0xAC, 0xEB, 0xFF, 0x80, 0x41, 0xEA, 0xAD, 0xB6, 0x7F, 0x44, 0x03, + 0x8F, 0x54, 0x80, 0xA7, 0xF6, 0x81, 0xF6, 0x82, 0xF6, 0x83, 0xF6, 0x84, 0xF6, 0x85, 0xF6, 0x86, + 0x83, 0xFF, 0x14, 0x9F, 0x80, 0x07, 0xF6, 0x88, 0xF6, 0x89, 0xF7, 0x8A, 0x83, 0xFF, 0x12, 0x6F, + 0x80, 0x1B, 0xEA, 0x54, 0x02, 0x1F, 0x80, 0x1B, 0x44, 0x03, 0x90, 0xE9, 0x96, 0x88, 0xA6, 0xC0, + 0x92, 0x28, 0xAE, 0x80, 0xA6, 0x81, 0xAE, 0x41, 0x83, 0xFF, 0x44, 0x13, 0x8D, 0xD4, 0x80, 0x41, + 0x44, 0x00, 0x01, 0x80, 0x3C, 0x7B, 0xF9, 0x56, 0xF8, 0x0B, 0x44, 0x13, 0x8F, 0x54, 0x44, 0x00, + 0x01, 0x99, 0x80, 0x41, 0xF8, 0x05, 0x44, 0x12, 0xBF, 0x24, 0x84, 0x02, 0x80, 0x41, 0x49, 0xFF, + 0xFF, 0x31, 0xFC, 0xE7, 0xFC, 0x06, 0xA7, 0x40, 0x80, 0xC0, 0x97, 0x68, 0x5A, 0x58, 0x01, 0x0B, + 0xF8, 0x1B, 0x3C, 0x0C, 0x02, 0xBE, 0x3C, 0x1C, 0x02, 0xC2, 0x3C, 0x2C, 0x02, 0xCE, 0x84, 0x86, + 0xEA, 0x54, 0xA7, 0x71, 0x97, 0x68, 0x5A, 0x58, 0x01, 0x0C, 0x84, 0x20, 0x84, 0x64, 0xF8, 0x0E, + 0x3C, 0x0C, 0x02, 0xBF, 0x3C, 0x1C, 0x02, 0xC3, 0x3C, 0x2C, 0x02, 0xCF, 0xF8, 0x30, 0xA7, 0x72, + 0x97, 0x68, 0x5A, 0x58, 0x01, 0x18, 0x84, 0x20, 0xFA, 0x70, 0xF1, 0x83, 0xF1, 0x84, 0xF1, 0x85, + 0xF1, 0x86, 0xF1, 0x88, 0xF1, 0x89, 0xF1, 0x8A, 0xB6, 0x7F, 0xF5, 0x81, 0xF3, 0x82, 0xF5, 0x87, + 0x83, 0xFF, 0x3C, 0x0C, 0x02, 0xC0, 0x3C, 0x1C, 0x02, 0xC4, 0x3C, 0x2C, 0x02, 0xD0, 0x84, 0x86, + 0xEA, 0x54, 0xA7, 0x73, 0x97, 0x68, 0x5A, 0x58, 0x01, 0x15, 0x84, 0x00, 0x84, 0x64, 0xF0, 0x83, + 0xF0, 0x84, 0xF0, 0x85, 0xF0, 0x86, 0xF0, 0x88, 0xF0, 0x89, 0xF0, 0x8A, 0x4E, 0x00, 0xFF, 0xE6, + 0x3C, 0x0C, 0x02, 0xC1, 0x3C, 0x1C, 0x02, 0xC5, 0x3C, 0x2C, 0x02, 0xD1, 0xEA, 0xBF, 0xEA, 0x54, + 0xFC, 0x86, 0xFC, 0x20, 0xA6, 0x40, 0x5A, 0x10, 0x01, 0x09, 0xA6, 0x42, 0x5A, 0x10, 0x01, 0x06, + 0xA6, 0x41, 0x5A, 0x18, 0x01, 0x1E, 0xD5, 0x1F, 0x3C, 0x7C, 0x02, 0xCA, 0x3C, 0x5C, 0x02, 0xCC, + 0x84, 0x60, 0x44, 0x61, 0x6A, 0x74, 0x99, 0x3B, 0xA4, 0x60, 0x38, 0x23, 0x0C, 0x11, 0x96, 0x4B, + 0xFE, 0x54, 0x90, 0x27, 0x96, 0x4B, 0xAC, 0x60, 0x99, 0x2B, 0xA4, 0x60, 0x8C, 0x62, 0x96, 0x4B, + 0xFE, 0x8C, 0x90, 0x47, 0x96, 0x93, 0xAC, 0xA0, 0x5A, 0x39, 0x80, 0xEF, 0xD5, 0xE2, 0xA6, 0x03, + 0x5A, 0x08, 0x01, 0x1C, 0x3C, 0x6C, 0x02, 0xCB, 0x3C, 0x4C, 0x02, 0xCD, 0x84, 0x40, 0x44, 0x51, + 0x68, 0xE4, 0x98, 0xF2, 0xA4, 0x18, 0x38, 0x12, 0x88, 0x11, 0x96, 0x03, 0xFE, 0x0C, 0x90, 0x07, + 0x96, 0x03, 0xAC, 0x18, 0x98, 0xE2, 0xA4, 0x18, 0x8C, 0x42, 0x96, 0x03, 0xFE, 0x44, 0x90, 0x27, + 0x96, 0x4B, 0xAC, 0x58, 0x5A, 0x29, 0x90, 0xEF, 0xFC, 0xA0, 0xFC, 0x26, 0x80, 0xC0, 0xA6, 0x00, + 0x5A, 0x08, 0x01, 0x30, 0x84, 0x00, 0x3C, 0x1C, 0x02, 0xD2, 0x80, 0x40, 0xEA, 0x96, 0xE2, 0x03, + 0xE8, 0x03, 0xF8, 0x94, 0xD5, 0xFC, 0xF8, 0x4B, 0x3D, 0x0C, 0x02, 0xCA, 0x80, 0xE5, 0x80, 0x45, + 0x4C, 0x29, 0x00, 0x07, 0xF8, 0x50, 0xE8, 0x02, 0xF8, 0x56, 0x8C, 0x41, 0xD5, 0xFA, 0x40, 0x52, + 0x8C, 0xB6, 0x97, 0xE9, 0xC7, 0x04, 0x9E, 0xA9, 0x96, 0x90, 0xD5, 0x02, 0x80, 0x47, 0xFE, 0x9C, + 0x96, 0x90, 0xC7, 0x05, 0x8E, 0x81, 0xD4, 0x03, 0x84, 0x83, 0xD5, 0x02, 0x84, 0x82, 0x84, 0xE0, + 0x84, 0xA1, 0x44, 0x0F, 0xFE, 0x0C, 0xF0, 0x88, 0xB6, 0x7F, 0xF8, 0x59, 0xF7, 0x89, 0xF8, 0x61, + 0xA6, 0x31, 0x5A, 0x08, 0x01, 0x19, 0x84, 0x00, 0x3C, 0x1C, 0x02, 0xD3, 0x80, 0x40, 0xEA, 0xAD, + 0xE2, 0x04, 0xE8, 0x03, 0xF8, 0x63, 0xD5, 0xFC, 0x84, 0x00, 0x84, 0xA1, 0x44, 0x2F, 0xFC, 0x18, + 0x2E, 0x37, 0x33, 0xAC, 0xF8, 0x62, 0xF2, 0x88, 0xF8, 0x6E, 0xF5, 0x82, 0xF5, 0x8A, 0x3C, 0x0C, + 0x02, 0xCB, 0xF8, 0x48, 0xA6, 0x32, 0x5A, 0x08, 0x01, 0x48, 0x84, 0x00, 0x3C, 0x1C, 0x02, 0xD4, + 0x80, 0x40, 0xEA, 0x96, 0xE2, 0x03, 0xE8, 0x03, 0xF8, 0x49, 0xD5, 0xFC, 0x2E, 0x47, 0x33, 0xAD, + 0x84, 0xA0, 0x43, 0x21, 0x90, 0x24, 0x83, 0xFF, 0x3D, 0x0C, 0x02, 0xCC, 0x80, 0xE5, 0x80, 0x45, + 0x4C, 0x29, 0x00, 0x11, 0x41, 0x18, 0x08, 0x20, 0x02, 0x08, 0x80, 0x00, 0x96, 0x03, 0xE0, 0xE0, + 0x83, 0xFF, 0xE8, 0x06, 0x02, 0x78, 0x80, 0x00, 0x97, 0x51, 0x97, 0xFB, 0x83, 0xFF, 0x8C, 0x41, + 0xD5, 0xF0, 0x40, 0x52, 0x8C, 0xB6, 0x97, 0xE9, 0xC7, 0x04, 0x9E, 0xA9, 0x96, 0x90, 0xD5, 0x02, + 0x80, 0x47, 0xFE, 0x9C, 0x96, 0x90, 0xC7, 0x05, 0x8E, 0x81, 0xD4, 0x03, 0x84, 0x83, 0xD5, 0x02, + 0x84, 0x82, 0x44, 0x0F, 0xFE, 0x0C, 0x84, 0xE0, 0x84, 0xA1, 0xF8, 0x2B, 0x40, 0x08, 0x08, 0x20, + 0xF5, 0x81, 0xF7, 0x82, 0xF7, 0x83, 0xF7, 0x84, 0xF7, 0x85, 0xF7, 0x86, 0xF7, 0x87, 0x83, 0xFF, + 0xF5, 0x8A, 0x80, 0x41, 0xEA, 0x23, 0xA6, 0x33, 0x5A, 0x08, 0x01, 0x27, 0x84, 0x00, 0x3C, 0x1C, + 0x02, 0xD5, 0x80, 0x40, 0xEA, 0xAD, 0xE2, 0x04, 0xE8, 0x07, 0x40, 0x30, 0x80, 0x20, 0xAC, 0x98, + 0x8C, 0x01, 0x83, 0xFF, 0xD5, 0xF8, 0x84, 0x00, 0xF0, 0x81, 0xF0, 0x83, 0xF0, 0x84, 0xF0, 0x85, + 0xF0, 0x86, 0xF0, 0x87, 0x83, 0xFF, 0x44, 0x0F, 0xFC, 0x18, 0x84, 0xA1, 0x2E, 0x37, 0x33, 0xAC, + 0xF0, 0x88, 0xEA, 0xEC, 0xF0, 0x89, 0xB6, 0x7F, 0x83, 0xFF, 0xF5, 0x82, 0xF5, 0x8A, 0x3C, 0x0C, + 0x02, 0xCD, 0x4E, 0x00, 0xFF, 0xD8, 0xFC, 0xA6, 0xFC, 0x4D, 0x84, 0x20, 0x81, 0x20, 0xEB, 0x95, + 0xB0, 0x01, 0xEA, 0x2F, 0x00, 0x04, 0x80, 0x02, 0x5A, 0x00, 0x01, 0x0A, 0x00, 0x04, 0x80, 0x03, + 0x5A, 0x08, 0x01, 0x74, 0x3C, 0x7C, 0x02, 0xD5, 0x84, 0x00, 0xD5, 0x39, 0x3D, 0x0C, 0x02, 0xD4, + 0x84, 0x20, 0x40, 0x08, 0x04, 0x00, 0xA4, 0x00, 0xB0, 0x81, 0x38, 0x01, 0x04, 0x09, 0x8C, 0x22, + 0x5A, 0x18, 0x40, 0xF9, 0x02, 0x1F, 0x80, 0x03, 0x02, 0x0F, 0x80, 0x02, 0x02, 0x2F, 0x80, 0x20, + 0x40, 0x10, 0x04, 0x20, 0x02, 0x0F, 0x80, 0x21, 0x84, 0x63, 0x40, 0x20, 0x08, 0x20, 0xF8, 0x32, + 0xB1, 0x81, 0x84, 0xA0, 0x80, 0xE3, 0xCD, 0x04, 0x12, 0x18, 0x00, 0x00, 0xD5, 0x13, 0x5A, 0x58, + 0x1F, 0x05, 0x12, 0x28, 0x00, 0x1F, 0xD5, 0x0E, 0x02, 0x03, 0x7F, 0xFF, 0xA4, 0xF0, 0xA5, 0x31, + 0x88, 0x60, 0x88, 0x64, 0x40, 0x31, 0x9C, 0x76, 0x41, 0x18, 0x14, 0x20, 0x96, 0xDB, 0x12, 0x38, + 0x80, 0x00, 0x8C, 0xA1, 0x8C, 0xC2, 0x5A, 0x58, 0x20, 0xE8, 0xD5, 0xC1, 0x98, 0x78, 0xA4, 0x48, + 0xB0, 0x81, 0x38, 0x11, 0x00, 0x09, 0x8C, 0x02, 0x5A, 0x08, 0x64, 0xFA, 0xEA, 0xA8, 0x02, 0x1F, + 0x80, 0x02, 0xEB, 0xB2, 0x02, 0x0F, 0x80, 0x32, 0x02, 0x2F, 0x80, 0x33, 0x84, 0x63, 0x40, 0x21, + 0x00, 0x20, 0x40, 0x10, 0x8C, 0x36, 0x40, 0x21, 0x0C, 0x56, 0x96, 0x4B, 0x96, 0x93, 0x83, 0xFF, + 0xB0, 0x01, 0x84, 0xA0, 0x80, 0xC3, 0xCD, 0x03, 0xAC, 0x78, 0xD5, 0x13, 0x5A, 0x58, 0x31, 0x05, + 0x12, 0x23, 0x80, 0x31, 0xD5, 0x0E, 0x02, 0x40, 0x7F, 0xFF, 0xA4, 0xC0, 0x41, 0x03, 0x94, 0x20, + 0x88, 0x64, 0xA5, 0x01, 0x88, 0x64, 0x40, 0x31, 0x98, 0x76, 0x96, 0xDB, 0x12, 0x38, 0x00, 0x00, + 0x8C, 0xA1, 0x8C, 0x02, 0x5A, 0x58, 0x32, 0xE9, 0xFC, 0xCD, 0x44, 0x02, 0xD7, 0x60, 0xEA, 0xBD, + 0xB6, 0x20, 0xEB, 0x1F, 0xA8, 0x41, 0xEB, 0xAE, 0xA8, 0x42, 0xEB, 0xAA, 0xA8, 0x43, 0x44, 0x13, + 0x58, 0x90, 0xA8, 0x44, 0x44, 0x13, 0x5A, 0x20, 0xA8, 0x45, 0x44, 0x13, 0x5B, 0xB0, 0xA8, 0x46, + 0x44, 0x13, 0x5D, 0x40, 0xA8, 0x47, 0xEB, 0x89, 0x14, 0x10, 0x00, 0x08, 0xEB, 0xEF, 0x14, 0x10, + 0x00, 0x09, 0x44, 0x12, 0x19, 0xA0, 0x14, 0x10, 0x00, 0x0A, 0x44, 0x12, 0x1B, 0x30, 0x14, 0x10, + 0x00, 0x0B, 0x44, 0x13, 0x5E, 0xD0, 0x14, 0x10, 0x00, 0x0C, 0x44, 0x13, 0x60, 0x60, 0x14, 0x10, + 0x00, 0x0D, 0x44, 0x13, 0x61, 0xF0, 0x14, 0x10, 0x00, 0x0E, 0x44, 0x13, 0x63, 0x80, 0x14, 0x10, + 0x00, 0x0F, 0xEA, 0xB7, 0x14, 0x10, 0x00, 0x10, 0xEB, 0x2A, 0x14, 0x10, 0x00, 0x11, 0xEB, 0x20, + 0x14, 0x10, 0x00, 0x12, 0xEA, 0xED, 0x14, 0x10, 0x00, 0x13, 0xEA, 0xCD, 0x14, 0x10, 0x00, 0x14, + 0xEB, 0x46, 0x14, 0x10, 0x00, 0x15, 0xEB, 0xCD, 0x14, 0x10, 0x00, 0x16, 0xEB, 0xB1, 0x14, 0x10, + 0x00, 0x17, 0x44, 0x12, 0xAB, 0x4A, 0x14, 0x10, 0x00, 0x18, 0x44, 0x12, 0xAB, 0xAE, 0x14, 0x10, + 0x00, 0x19, 0x44, 0x12, 0xAC, 0x12, 0x14, 0x10, 0x00, 0x1A, 0x44, 0x12, 0xAC, 0x76, 0x14, 0x10, + 0x00, 0x1B, 0xDD, 0x9E, 0xFC, 0x21, 0xA4, 0xC0, 0x84, 0x20, 0x96, 0xDB, 0x12, 0x1F, 0x80, 0x03, + 0x84, 0x80, 0x84, 0xAF, 0x44, 0x60, 0x01, 0xEA, 0x96, 0x61, 0x5C, 0xF0, 0x80, 0x64, 0xE8, 0x09, + 0x40, 0x20, 0x84, 0x09, 0xA5, 0xC0, 0xA4, 0x40, 0x52, 0x21, 0x00, 0x31, 0x96, 0x4B, 0xD5, 0x09, + 0xA5, 0xC0, 0x50, 0x22, 0x7F, 0x9C, 0xA4, 0x40, 0x90, 0x41, 0x96, 0x4B, 0x52, 0x21, 0x00, 0x31, + 0xFE, 0xAC, 0x96, 0x91, 0xFE, 0x54, 0x40, 0x10, 0x98, 0x36, 0x88, 0x27, 0x96, 0x4B, 0xAC, 0x40, + 0xA4, 0x40, 0x96, 0x4B, 0xE0, 0x61, 0xE8, 0x03, 0xA4, 0xC0, 0x96, 0xDB, 0x8C, 0x81, 0x8C, 0x02, + 0x5A, 0x48, 0xC8, 0xDC, 0x12, 0x3F, 0x80, 0x03, 0xEA, 0xA8, 0xEB, 0xD2, 0x96, 0x03, 0x3C, 0x3B, + 0xF7, 0xC1, 0x40, 0x00, 0x80, 0x07, 0xFC, 0xA1, 0xFC, 0x60, 0xE0, 0x61, 0xE8, 0x06, 0x4E, 0x36, + 0x00, 0x0C, 0x42, 0x02, 0x14, 0x24, 0xD5, 0x3E, 0xE0, 0x23, 0xE8, 0x06, 0x4E, 0x16, 0x00, 0x05, + 0x9C, 0x21, 0xFE, 0x2C, 0xD5, 0x37, 0x81, 0x41, 0x81, 0xA0, 0x80, 0x01, 0x84, 0x2A, 0x81, 0x22, + 0xFD, 0x32, 0x81, 0x63, 0xF8, 0x08, 0x81, 0x80, 0x84, 0x2A, 0x80, 0x09, 0xF8, 0x04, 0x81, 0x20, + 0x84, 0x2A, 0x80, 0x0B, 0x49, 0x00, 0x11, 0x74, 0x42, 0x23, 0x1C, 0x24, 0x40, 0x60, 0x30, 0x01, + 0x4E, 0xD3, 0x00, 0x11, 0xE1, 0x6A, 0x40, 0xC0, 0x3C, 0x1B, 0xFF, 0xBC, 0x40, 0x04, 0xB0, 0x01, + 0x40, 0xF3, 0x01, 0xF6, 0x40, 0x07, 0x9C, 0x00, 0x9D, 0x41, 0x84, 0x02, 0x40, 0x02, 0x80, 0x16, + 0xD5, 0x10, 0x40, 0x34, 0x84, 0x08, 0x42, 0x13, 0x1C, 0x24, 0x40, 0x91, 0xB0, 0x01, 0x40, 0x64, + 0x80, 0x01, 0x40, 0x60, 0x98, 0xD6, 0x98, 0x37, 0x8C, 0x01, 0x84, 0xC2, 0x40, 0x00, 0x18, 0x16, + 0x88, 0x02, 0x96, 0x03, 0xFC, 0xE0, 0xFC, 0x60, 0x51, 0xFF, 0xFC, 0x28, 0x80, 0xC0, 0x81, 0x41, + 0x80, 0xE2, 0xEB, 0x69, 0xEA, 0xB9, 0x80, 0x1F, 0x81, 0x23, 0x81, 0x64, 0xDD, 0x46, 0xEB, 0x69, + 0xEA, 0xB9, 0xB0, 0x29, 0xDD, 0x46, 0xEB, 0x69, 0xEA, 0xB9, 0x50, 0x0F, 0x81, 0x48, 0xDD, 0x46, + 0xEB, 0x69, 0xEA, 0xB9, 0x50, 0x0F, 0x81, 0xEC, 0xDD, 0x46, 0x44, 0x11, 0x6C, 0x98, 0xEA, 0xB9, + 0x50, 0x0F, 0x82, 0x90, 0xDD, 0x46, 0x50, 0x0F, 0x83, 0x34, 0x44, 0x11, 0x6C, 0x98, 0xEA, 0xB9, + 0xDD, 0x46, 0xA4, 0x30, 0x4E, 0x02, 0x01, 0x35, 0xA4, 0x31, 0x4E, 0x02, 0x01, 0x32, 0x2E, 0x07, + 0xF3, 0x05, 0x4E, 0x03, 0x01, 0x2E, 0xA0, 0x37, 0x5E, 0xF0, 0x04, 0xB1, 0x4E, 0xF3, 0x01, 0x29, + 0x04, 0x03, 0x00, 0x08, 0x5E, 0xF0, 0x04, 0xB1, 0x4E, 0xF3, 0x01, 0x23, 0x84, 0x01, 0xEA, 0x94, + 0x00, 0x93, 0x00, 0x11, 0x84, 0x1F, 0x04, 0x13, 0x80, 0x18, 0x3E, 0x07, 0xF4, 0x37, 0x40, 0x04, + 0x84, 0x08, 0x98, 0x88, 0xA4, 0x90, 0x40, 0xC1, 0x00, 0x11, 0x4E, 0x93, 0x00, 0x0D, 0x80, 0x07, + 0x80, 0x3F, 0x80, 0x49, 0x44, 0x32, 0xC0, 0xAF, 0x80, 0x89, 0x84, 0xA1, 0xF8, 0xE7, 0x40, 0xD0, + 0x00, 0x11, 0xD5, 0x07, 0x8E, 0x02, 0x88, 0x01, 0xA4, 0x40, 0x85, 0x21, 0x40, 0xD0, 0x80, 0x11, + 0x00, 0x03, 0x00, 0x11, 0x5A, 0x08, 0x1F, 0x0D, 0x84, 0x41, 0x80, 0x07, 0xB0, 0x69, 0x44, 0x32, + 0xC0, 0xAF, 0x84, 0x80, 0x80, 0xA2, 0xF8, 0xD2, 0x96, 0x03, 0x85, 0x20, 0xD5, 0x07, 0x8C, 0x01, + 0x04, 0x13, 0x80, 0x18, 0xEB, 0x72, 0xA4, 0xC0, 0x96, 0x1B, 0x50, 0x30, 0x00, 0xE6, 0x50, 0x16, + 0x80, 0xE6, 0x50, 0x26, 0x00, 0xE6, 0x84, 0x00, 0x96, 0x4B, 0x96, 0x93, 0x96, 0xDB, 0x00, 0x43, + 0x00, 0x11, 0xEB, 0xD1, 0xF8, 0x4C, 0x12, 0x05, 0x00, 0x00, 0x4E, 0x92, 0x00, 0x05, 0x84, 0x1F, + 0x3E, 0x07, 0xF4, 0x37, 0x00, 0x93, 0x00, 0x10, 0x84, 0x1F, 0x04, 0x13, 0x80, 0x19, 0x3E, 0x07, + 0xF4, 0x36, 0x40, 0x04, 0x84, 0x08, 0x98, 0x88, 0xA4, 0x90, 0x40, 0xC1, 0x00, 0x11, 0x4E, 0x93, + 0x00, 0x0E, 0x84, 0x81, 0x80, 0x07, 0x50, 0x1F, 0x81, 0x48, 0x80, 0x49, 0x44, 0x32, 0xC0, 0xAE, + 0x80, 0xA4, 0xF8, 0x9C, 0x40, 0xD0, 0x00, 0x11, 0xD5, 0x07, 0x8E, 0x02, 0x88, 0x01, 0xA4, 0x40, + 0x85, 0x21, 0x40, 0xD0, 0x80, 0x11, 0x00, 0x03, 0x00, 0x10, 0x5A, 0x08, 0x31, 0x0E, 0x84, 0x41, + 0x80, 0x07, 0x50, 0x1F, 0x81, 0xEC, 0x44, 0x32, 0xC0, 0xAE, 0x80, 0x82, 0x80, 0xA2, 0xF8, 0x86, + 0x96, 0x03, 0x85, 0x20, 0xD5, 0x07, 0x8C, 0x01, 0x04, 0x13, 0x80, 0x19, 0xEB, 0x72, 0xA4, 0xC0, + 0x96, 0x1B, 0x50, 0x30, 0x00, 0xE6, 0x50, 0x16, 0x80, 0xE6, 0x50, 0x26, 0x00, 0xE6, 0x84, 0x00, + 0x96, 0x4B, 0x96, 0x93, 0x96, 0xDB, 0x00, 0x43, 0x00, 0x10, 0xEB, 0xD1, 0x49, 0xFF, 0xFE, 0xEE, + 0x12, 0x05, 0x00, 0x01, 0x4E, 0x92, 0x00, 0x05, 0x84, 0x3F, 0x3E, 0x17, 0xF4, 0x36, 0x00, 0x25, + 0x80, 0x05, 0x96, 0x90, 0x5A, 0x20, 0x01, 0x04, 0x48, 0x00, 0x00, 0x81, 0x04, 0x13, 0x00, 0x0B, + 0x5E, 0xF0, 0x84, 0x7F, 0x4E, 0xF3, 0x00, 0x75, 0x04, 0x13, 0x00, 0x0C, 0x5E, 0xF0, 0x84, 0x7F, + 0xE9, 0x6F, 0x00, 0x93, 0x00, 0x13, 0x84, 0x1F, 0x3E, 0x07, 0xF4, 0x35, 0x4E, 0x93, 0x00, 0x10, + 0x50, 0x1F, 0x82, 0x90, 0x80, 0x07, 0x80, 0x49, 0x44, 0x32, 0xC0, 0xAD, 0x80, 0x89, 0x80, 0xA9, + 0xF8, 0x45, 0x04, 0x13, 0x00, 0x09, 0x96, 0x03, 0x8A, 0x20, 0xD5, 0x10, 0x5A, 0x98, 0x1F, 0x15, + 0x84, 0x80, 0x50, 0x1F, 0x82, 0x90, 0x80, 0x07, 0x44, 0x32, 0xC0, 0xAD, 0x80, 0xA4, 0xF8, 0x36, + 0x96, 0x03, 0x04, 0x13, 0x00, 0x09, 0x42, 0x10, 0x24, 0x73, 0x50, 0x23, 0x00, 0x24, 0xB6, 0x22, + 0xA0, 0x52, 0x88, 0x01, 0xA8, 0x12, 0x04, 0x13, 0x00, 0x09, 0xEA, 0x47, 0xFE, 0x0C, 0x04, 0x13, + 0x00, 0x0B, 0xEA, 0x9F, 0x50, 0x00, 0x00, 0x3C, 0x12, 0x05, 0x00, 0x02, 0x00, 0x93, 0x00, 0x12, + 0x84, 0x1F, 0x3E, 0x07, 0xF4, 0x34, 0x4E, 0x93, 0x00, 0x10, 0x50, 0x1F, 0x83, 0x34, 0x80, 0x07, + 0x80, 0x49, 0x44, 0x32, 0xC0, 0xAC, 0x84, 0x81, 0x80, 0xA9, 0xF8, 0x10, 0x04, 0x13, 0x00, 0x0A, + 0x96, 0x03, 0x8A, 0x20, 0xD5, 0x12, 0x5A, 0x98, 0x31, 0x17, 0x84, 0x41, 0x50, 0x1F, 0x83, 0x34, + 0x80, 0x07, 0x44, 0x32, 0xC0, 0xAC, 0x80, 0x82, 0x84, 0xA0, 0x49, 0xFF, 0xF9, 0xC4, 0x96, 0x03, + 0x04, 0x13, 0x00, 0x0A, 0x42, 0x10, 0x24, 0x73, 0x50, 0x23, 0x00, 0x28, 0xB6, 0x22, 0xA0, 0x52, + 0x88, 0x01, 0xA8, 0x12, 0x04, 0x13, 0x00, 0x0A, 0xEA, 0x47, 0xFE, 0x0C, 0x04, 0x13, 0x00, 0x0C, + 0xEA, 0x9F, 0x50, 0x00, 0x00, 0x3C, 0x12, 0x05, 0x00, 0x03, 0x84, 0x01, 0xD5, 0x0B, 0x02, 0x15, + 0x00, 0x00, 0x12, 0x15, 0x00, 0x02, 0x12, 0x05, 0x00, 0x03, 0x84, 0x00, 0xD5, 0x03, 0x84, 0x00, + 0xEA, 0x94, 0x3E, 0x07, 0xF2, 0xE9, 0x51, 0xFF, 0x83, 0xD8, 0xFC, 0xE0, 0x44, 0x10, 0x00, 0xA8, + 0x42, 0x01, 0x84, 0x73, 0x00, 0x21, 0x00, 0x0A, 0x00, 0x10, 0x00, 0x42, 0xCA, 0x32, 0xC1, 0x04, + 0x9E, 0x8D, 0xE6, 0x42, 0xE8, 0x08, 0x84, 0x21, 0xEB, 0x56, 0x2E, 0x17, 0xE8, 0xD4, 0x3E, 0x17, + 0xF4, 0x3A, 0xD5, 0x12, 0x5A, 0x18, 0x01, 0x0B, 0xEB, 0xE6, 0xC1, 0x04, 0x8E, 0x21, 0x3E, 0x17, + 0xF4, 0x3A, 0xEB, 0xE6, 0xC9, 0x09, 0x84, 0x22, 0xD5, 0x06, 0x5A, 0x10, 0x02, 0x04, 0x5A, 0x18, + 0x04, 0x04, 0x84, 0x23, 0xEB, 0x56, 0x00, 0x20, 0x00, 0x42, 0x00, 0x10, 0x00, 0x43, 0x8E, 0x42, + 0xE6, 0x43, 0x10, 0x10, 0x00, 0x47, 0x84, 0x40, 0xE9, 0x02, 0x84, 0x41, 0x10, 0x20, 0x00, 0x43, + 0x00, 0x20, 0x00, 0x43, 0xCA, 0x26, 0x5A, 0x18, 0x01, 0x25, 0x10, 0x10, 0x00, 0x7D, 0xDD, 0x9E, + 0xE6, 0x22, 0xE9, 0x03, 0x5A, 0x18, 0x05, 0x04, 0x84, 0x26, 0xD5, 0xE5, 0x9E, 0x8A, 0xE6, 0x42, + 0xE8, 0x0D, 0x84, 0x24, 0xEB, 0x56, 0x00, 0x10, 0x00, 0x81, 0xE6, 0x22, 0xE8, 0x04, 0x2E, 0x17, + 0xE8, 0xD5, 0xD5, 0xC6, 0x2E, 0x17, 0xE8, 0xD6, 0xD5, 0xC3, 0x5A, 0x18, 0x04, 0xD6, 0xEB, 0xE6, + 0xC1, 0x04, 0x8E, 0x21, 0x3E, 0x17, 0xF4, 0x3A, 0xEB, 0xE6, 0xC9, 0xCE, 0x84, 0x25, 0xD5, 0xCB, + 0xDD, 0x9E, 0xA4, 0x54, 0x00, 0x20, 0x00, 0x62, 0x96, 0x8E, 0x96, 0x90, 0xCA, 0x05, 0x00, 0x30, + 0x00, 0x42, 0x5A, 0x38, 0x04, 0x08, 0x02, 0x10, 0x00, 0x27, 0x84, 0x45, 0x94, 0x4A, 0xEB, 0x52, + 0xD5, 0x23, 0x00, 0x40, 0x00, 0x43, 0xCC, 0x22, 0x5A, 0x38, 0x03, 0x22, 0x02, 0x20, 0x00, 0x27, + 0xC1, 0x09, 0x9A, 0xCA, 0xEA, 0xE3, 0xEA, 0xC1, 0xFE, 0xE4, 0xEA, 0xF0, 0x96, 0xD9, 0xE6, 0x7E, + 0xE8, 0x07, 0xFA, 0x6F, 0x42, 0x20, 0x8C, 0x73, 0x80, 0x22, 0x90, 0x25, 0xD5, 0x0D, 0x5C, 0xF1, + 0x80, 0x46, 0xE8, 0x05, 0x40, 0x11, 0x04, 0x80, 0x90, 0x24, 0xD5, 0x06, 0x84, 0x67, 0x42, 0x20, + 0x8C, 0x73, 0x80, 0x22, 0x90, 0x23, 0x96, 0x49, 0xD5, 0x02, 0x80, 0x22, 0x12, 0x10, 0x00, 0x28, + 0xDD, 0x9E, 0xFC, 0x01, 0xF0, 0x81, 0x49, 0x00, 0x05, 0xE9, 0xF0, 0x01, 0x49, 0x00, 0x07, 0x5D, + 0xF0, 0x01, 0x49, 0xFF, 0xFB, 0x51, 0xFC, 0x81, 0xFC, 0x01, 0xF0, 0x81, 0xF1, 0x01, 0x44, 0x02, + 0xD3, 0xA4, 0x49, 0xFF, 0xF9, 0x39, 0xEB, 0x4E, 0xC8, 0x04, 0xF0, 0x01, 0x49, 0xFF, 0xFB, 0x93, + 0xEB, 0x4E, 0xC8, 0x04, 0xF0, 0x01, 0x49, 0xFF, 0xFA, 0x5C, 0xF0, 0x01, 0x49, 0xFF, 0xFB, 0xCF, + 0xF0, 0x01, 0x49, 0xFF, 0xFC, 0x8B, 0xF0, 0x01, 0xEA, 0xDE, 0xEB, 0xB9, 0x49, 0x00, 0x0B, 0xEA, + 0xFC, 0x81, 0xFC, 0x00, 0x80, 0xC0, 0x80, 0x80, 0x44, 0x02, 0xD9, 0x9C, 0x44, 0x12, 0xDB, 0x10, + 0xEB, 0xB9, 0x44, 0x32, 0xBB, 0x78, 0x49, 0xFF, 0xFD, 0xD8, 0xEA, 0x5B, 0x44, 0x12, 0xD4, 0xE8, + 0x2E, 0x27, 0xEF, 0x00, 0x44, 0x32, 0xD9, 0x9C, 0x49, 0x00, 0x0A, 0x58, 0xEA, 0x5B, 0xEA, 0xDE, + 0x2E, 0x27, 0xEF, 0x00, 0x44, 0x32, 0xDB, 0x10, 0x49, 0x00, 0x09, 0x79, 0xEA, 0x5B, 0xEA, 0xDE, + 0x44, 0x22, 0xD4, 0xE8, 0x84, 0x60, 0x49, 0xFF, 0xFF, 0x23, 0xEA, 0x5B, 0xEA, 0xDE, 0xEB, 0xB9, + 0x84, 0x61, 0xF8, 0x08, 0xA6, 0x35, 0x5A, 0x08, 0x01, 0x0F, 0xEA, 0x5B, 0xEA, 0xDE, 0xEB, 0xB9, + 0x84, 0x60, 0x49, 0xFF, 0xF8, 0x74, 0xEA, 0x5B, 0x84, 0x20, 0x49, 0x00, 0x09, 0x01, 0xEA, 0x5B, + 0x49, 0x00, 0x07, 0x7B, 0x84, 0x20, 0xEA, 0x5B, 0x49, 0x00, 0x08, 0x76, 0xEA, 0x5B, 0x49, 0x00, + 0x04, 0xFF, 0xEA, 0x5B, 0xEA, 0xDE, 0x44, 0x22, 0xD4, 0xE8, 0x84, 0x60, 0x49, 0xFF, 0xFF, 0x5B, + 0x84, 0x01, 0xFC, 0x80, 0xFC, 0x00, 0x44, 0x62, 0xD7, 0x04, 0x80, 0x06, 0x49, 0x00, 0x05, 0x76, + 0x80, 0x06, 0x44, 0x12, 0xBC, 0x60, 0x49, 0xFF, 0xFF, 0x86, 0x80, 0x06, 0x49, 0xFF, 0xFF, 0x8E, + 0xFC, 0x80, 0xFC, 0x00, 0x49, 0xFF, 0xF9, 0xA8, 0xEB, 0xE9, 0x44, 0x12, 0xD7, 0x60, 0x49, 0xFF, + 0xFD, 0x03, 0xC0, 0x05, 0xFA, 0x18, 0xEA, 0x98, 0x84, 0x03, 0xFC, 0x80, 0x84, 0x21, 0x3E, 0x07, + 0xEE, 0xD4, 0x3E, 0x07, 0xEF, 0x38, 0x3E, 0x17, 0xEF, 0x16, 0x84, 0x01, 0xFC, 0x80, 0xDD, 0x9E, + 0x3C, 0x0F, 0xFD, 0x49, 0xDD, 0x9E, 0x44, 0x02, 0xB5, 0x50, 0x3C, 0x0F, 0xFD, 0x4A, 0xDD, 0x9E, + 0xFC, 0x41, 0xF4, 0x81, 0x41, 0x22, 0x00, 0x11, 0x41, 0x12, 0x40, 0x0A, 0x00, 0x40, 0x00, 0x62, + 0x22, 0x60, 0x80, 0x00, 0x97, 0x24, 0xEA, 0x99, 0x86, 0x01, 0xC4, 0x0C, 0x3C, 0x6B, 0xFA, 0x80, + 0x3C, 0x1B, 0xFA, 0x7F, 0x3C, 0x6F, 0xFD, 0x3E, 0x3C, 0x1F, 0xFD, 0x3D, 0x3F, 0x07, 0xF4, 0xFC, + 0xD5, 0x45, 0xB4, 0x80, 0x5A, 0x48, 0x03, 0x0C, 0x2E, 0x77, 0xF4, 0xFC, 0x8C, 0xE1, 0x97, 0xF8, + 0xE6, 0xEF, 0x40, 0x78, 0x3C, 0x1A, 0x3E, 0x77, 0xF4, 0xFC, 0xD5, 0x34, 0x5A, 0x48, 0x01, 0x33, + 0x3C, 0x4D, 0xFD, 0x4A, 0x3D, 0x37, 0xFA, 0x80, 0xA7, 0xE0, 0x3D, 0x07, 0xFA, 0x7F, 0x5A, 0x78, + 0x01, 0x5C, 0x40, 0x79, 0x98, 0x01, 0x42, 0xF3, 0x80, 0x03, 0x40, 0x78, 0x04, 0x01, 0x42, 0x73, + 0x80, 0x03, 0x02, 0x92, 0x00, 0x04, 0x88, 0xEF, 0xE3, 0x27, 0xE8, 0x4E, 0xA5, 0x23, 0xE1, 0xE4, + 0xE8, 0x03, 0xE0, 0xC4, 0xE8, 0x17, 0x3C, 0x9D, 0xFD, 0x49, 0x02, 0x74, 0x80, 0x09, 0x8E, 0xE1, + 0x8A, 0xE4, 0xE0, 0xF3, 0xE8, 0x03, 0xE0, 0xE6, 0xE8, 0x0D, 0xE1, 0x84, 0xE8, 0x03, 0xE0, 0x24, + 0xE8, 0x09, 0x02, 0x74, 0x80, 0x0A, 0x8E, 0xE1, 0x8A, 0xE4, 0xE0, 0xF0, 0xE8, 0x35, 0xE0, 0xE1, + 0xE9, 0x33, 0x3C, 0x6F, 0xFD, 0x3E, 0x3C, 0x1F, 0xFD, 0x3D, 0x5A, 0x58, 0x01, 0x27, 0x00, 0x00, + 0x00, 0x42, 0x5A, 0x08, 0x02, 0x23, 0x5C, 0xF1, 0x83, 0xE8, 0xE8, 0x1F, 0x3C, 0x1D, 0xFD, 0x3E, + 0x3C, 0x0D, 0xFD, 0x3D, 0x40, 0x30, 0xC8, 0x01, 0x42, 0xF1, 0x80, 0x03, 0x40, 0x30, 0x44, 0x01, + 0xEA, 0xE3, 0x88, 0x6F, 0xE4, 0x7E, 0xE8, 0x11, 0x84, 0x8F, 0x42, 0x19, 0x10, 0x73, 0x42, 0x08, + 0x90, 0x73, 0xFA, 0x60, 0x8C, 0x28, 0x8C, 0x08, 0x40, 0x10, 0x8C, 0x36, 0x40, 0x00, 0x0C, 0x16, + 0x3C, 0x1F, 0xFD, 0x3E, 0x3C, 0x0F, 0xFD, 0x3D, 0x3C, 0x0D, 0xFD, 0x3E, 0xAC, 0x10, 0x3C, 0x0D, + 0xFD, 0x3D, 0xAC, 0x11, 0xFC, 0xC1, 0x2E, 0x47, 0xF4, 0xFC, 0x8C, 0x81, 0x3E, 0x47, 0xF4, 0xFC, + 0xD5, 0xC9, 0xFC, 0x20, 0xB5, 0xC0, 0x44, 0x72, 0xC1, 0x68, 0x66, 0x59, 0x00, 0x02, 0x45, 0x02, + 0xC1, 0x64, 0x44, 0x62, 0xC1, 0x14, 0x45, 0x12, 0xC1, 0x10, 0x5A, 0x50, 0x01, 0x06, 0x00, 0x00, + 0x00, 0x42, 0x5A, 0x08, 0x02, 0x16, 0x84, 0x00, 0x38, 0x03, 0x8C, 0x08, 0xFA, 0xA4, 0x84, 0x01, + 0xFF, 0x5C, 0xEB, 0xDE, 0x22, 0x00, 0x80, 0x00, 0x38, 0x03, 0x16, 0x09, 0xEA, 0x99, 0x40, 0x53, + 0x14, 0x40, 0xFA, 0x8E, 0xAC, 0x69, 0x38, 0x48, 0x8C, 0x08, 0x48, 0x00, 0x00, 0x88, 0x38, 0x08, + 0x0C, 0x00, 0xE6, 0x14, 0xE8, 0x03, 0x8C, 0x01, 0xEB, 0xDE, 0x38, 0x03, 0x8C, 0x00, 0x44, 0x52, + 0xC1, 0x68, 0xE6, 0x13, 0xE9, 0x03, 0x84, 0x00, 0xD5, 0x02, 0x8C, 0x01, 0x38, 0x02, 0x8C, 0x08, + 0xFA, 0xA4, 0xFF, 0x5C, 0x38, 0x73, 0x8C, 0x00, 0x03, 0x30, 0x80, 0x00, 0x98, 0x3D, 0x39, 0x33, + 0x02, 0x09, 0xA4, 0x49, 0x40, 0x03, 0x00, 0x40, 0x5E, 0xF2, 0x00, 0xFA, 0xAC, 0x41, 0xE8, 0x10, + 0x5E, 0xF2, 0x00, 0x8D, 0xE9, 0x0F, 0x44, 0x0F, 0xFF, 0x7E, 0x50, 0x42, 0x7F, 0x74, 0xFF, 0x04, + 0x44, 0x00, 0x00, 0x6E, 0x40, 0x42, 0x00, 0x96, 0x50, 0x42, 0x00, 0xA0, 0xD5, 0x05, 0xFA, 0x8E, + 0xD5, 0x03, 0x44, 0x40, 0x00, 0xA0, 0x5B, 0x28, 0x04, 0x04, 0x38, 0x48, 0x8C, 0x00, 0x38, 0x18, + 0x8C, 0x00, 0x84, 0x03, 0x81, 0xE1, 0x42, 0xF2, 0x00, 0x73, 0x45, 0x22, 0xC1, 0x10, 0x80, 0x0F, + 0x8C, 0x02, 0x90, 0x02, 0xE0, 0x20, 0xE8, 0x05, 0x8C, 0x21, 0xE0, 0x20, 0x40, 0x00, 0xBC, 0x1B, + 0x38, 0x18, 0x0C, 0x00, 0x38, 0x09, 0x0C, 0x08, 0x84, 0x0A, 0x38, 0x48, 0x8C, 0x00, 0xFE, 0x44, + 0x42, 0x10, 0x90, 0x01, 0x84, 0x80, 0x41, 0x00, 0x82, 0x16, 0x80, 0x64, 0x80, 0x04, 0x4C, 0x48, + 0x00, 0x12, 0x41, 0x13, 0x94, 0x00, 0x39, 0x23, 0x46, 0x11, 0x41, 0x13, 0x44, 0x40, 0x23, 0x18, + 0x80, 0x01, 0x88, 0x12, 0x88, 0x71, 0xC7, 0x03, 0x8E, 0xE1, 0xD5, 0x02, 0xFA, 0xE3, 0x8C, 0x81, + 0xD5, 0xEF, 0x86, 0x0A, 0x42, 0x00, 0x40, 0x24, 0x42, 0x41, 0xC0, 0x24, 0x40, 0x30, 0xC1, 0xF6, + 0xE8, 0x0C, 0x88, 0xA7, 0x38, 0x33, 0x16, 0x11, 0x40, 0x53, 0x14, 0x40, 0x42, 0x07, 0x8C, 0x73, + 0x22, 0x32, 0x80, 0x01, 0x42, 0x47, 0x8C, 0x73, 0x40, 0x30, 0x84, 0x0A, 0x88, 0x03, 0x88, 0x64, + 0xEA, 0x9F, 0x40, 0x11, 0x84, 0x36, 0x96, 0x03, 0x96, 0x4B, 0xAC, 0x10, 0xAC, 0x51, 0xFC, 0xA0, + 0xFC, 0x20, 0xB4, 0xC0, 0x45, 0x02, 0xC1, 0x0C, 0x44, 0x72, 0xC1, 0x08, 0x66, 0x63, 0x00, 0x02, + 0x23, 0x20, 0x80, 0x00, 0x23, 0x30, 0x80, 0x01, 0x38, 0x53, 0x8E, 0x02, 0x38, 0x18, 0x0E, 0x02, + 0x45, 0x12, 0xC1, 0x04, 0x5A, 0x60, 0x01, 0x06, 0x00, 0x00, 0x00, 0x42, 0x5A, 0x08, 0x02, 0x0A, + 0xEA, 0x3F, 0x39, 0x28, 0x0E, 0x0A, 0x39, 0x33, 0x8E, 0x0A, 0x38, 0x08, 0x8E, 0x0A, 0xD5, 0x39, + 0x5E, 0xF2, 0x00, 0x3D, 0xE9, 0x0E, 0x5E, 0xF2, 0x00, 0x64, 0xE8, 0x0D, 0x50, 0x42, 0x7F, 0xC4, + 0x44, 0x60, 0x00, 0x4B, 0xFF, 0x34, 0xFA, 0x18, 0x40, 0x02, 0x00, 0x16, 0x8C, 0x19, 0xD5, 0x04, + 0xFA, 0x09, 0xD5, 0x02, 0xEA, 0x3F, 0x38, 0x48, 0x8E, 0x02, 0x84, 0xC3, 0x42, 0x40, 0x18, 0x73, + 0x84, 0x04, 0x8C, 0x82, 0x40, 0x42, 0x00, 0x96, 0x38, 0x48, 0x8E, 0x0A, 0x97, 0x6B, 0x53, 0x12, + 0x00, 0x64, 0x96, 0x0B, 0x42, 0x58, 0x94, 0x24, 0x42, 0x18, 0x80, 0x24, 0x42, 0x52, 0x4C, 0x73, + 0x42, 0x12, 0x48, 0x73, 0x44, 0x60, 0x00, 0x64, 0x50, 0x52, 0x80, 0x32, 0x50, 0x10, 0x80, 0x32, + 0x40, 0x52, 0x98, 0xB6, 0x40, 0x10, 0x98, 0x36, 0x38, 0x53, 0x8E, 0x0A, 0x38, 0x18, 0x0E, 0x0A, + 0x38, 0x08, 0x0E, 0x02, 0xAC, 0x10, 0x38, 0x03, 0x8E, 0x02, 0xAC, 0x11, 0xFC, 0xA0, 0x22, 0x20, + 0x00, 0x00, 0xE0, 0x22, 0xE8, 0x15, 0x3C, 0x4D, 0xFD, 0x49, 0x02, 0x32, 0x00, 0x09, 0x8E, 0x61, + 0x8A, 0x61, 0xE0, 0x43, 0xE8, 0x0D, 0x22, 0x20, 0x00, 0x01, 0xE0, 0x22, 0xE8, 0x09, 0x02, 0x02, + 0x00, 0x0A, 0x8E, 0x01, 0x8A, 0x01, 0xE0, 0x40, 0x56, 0x07, 0x80, 0x01, 0xDD, 0x9E, 0x84, 0x01, + 0xDD, 0x9E, 0xFC, 0x01, 0x96, 0x43, 0x5E, 0xF0, 0x83, 0x21, 0x90, 0x10, 0xE9, 0x04, 0x52, 0x10, + 0x86, 0x40, 0x96, 0x4B, 0x5E, 0xF0, 0x05, 0x15, 0xE9, 0x04, 0x52, 0x00, 0x0A, 0x28, 0x96, 0x03, + 0x42, 0x00, 0x04, 0x01, 0xFC, 0x81, 0x00, 0x00, 0x00, 0x81, 0x5A, 0x00, 0x06, 0x04, 0x5A, 0x08, + 0x09, 0x0A, 0x88, 0x23, 0xA6, 0x08, 0xC0, 0x04, 0x8E, 0x01, 0xAE, 0x08, 0xDD, 0x9E, 0x38, 0x01, + 0x0E, 0x0A, 0xDD, 0x9E, 0xFC, 0x01, 0xF3, 0x81, 0xF3, 0x07, 0x88, 0x43, 0xA7, 0x10, 0xE6, 0x85, + 0xE8, 0x20, 0x00, 0x60, 0x00, 0x43, 0xCE, 0x03, 0x8C, 0x81, 0xAF, 0x10, 0x84, 0x80, 0x94, 0xDA, + 0x10, 0x40, 0x00, 0x81, 0x88, 0x23, 0x44, 0x40, 0x03, 0x84, 0xB6, 0x81, 0xA6, 0x90, 0x5A, 0x28, + 0x05, 0x11, 0x84, 0x41, 0x10, 0x20, 0x00, 0x81, 0xF0, 0x06, 0x88, 0x60, 0xB0, 0x01, 0x3A, 0x00, + 0x00, 0x00, 0x3A, 0x01, 0x80, 0x20, 0x44, 0x00, 0x00, 0xE1, 0xB6, 0x01, 0x84, 0x00, 0xB6, 0x05, + 0xFC, 0x81, 0xFC, 0x01, 0x95, 0x6A, 0xF0, 0x81, 0x88, 0x85, 0x22, 0x22, 0x00, 0x00, 0x22, 0xFF, + 0x80, 0x02, 0xE0, 0x4F, 0xE8, 0x04, 0x52, 0x01, 0x06, 0x3F, 0x96, 0x83, 0x22, 0x02, 0x00, 0x01, + 0x22, 0xFF, 0x80, 0x03, 0xE0, 0x0F, 0xE8, 0x04, 0x52, 0x00, 0x0A, 0x27, 0x96, 0x03, 0x42, 0x00, + 0x08, 0x01, 0x88, 0x25, 0x42, 0x30, 0x00, 0x24, 0xB4, 0x41, 0xE2, 0x62, 0xE8, 0x0D, 0xE4, 0x06, + 0xE9, 0x04, 0x8E, 0x05, 0xFE, 0x04, 0xB6, 0x01, 0xB4, 0x01, 0x5C, 0xF0, 0x00, 0xE1, 0xE8, 0x04, + 0x44, 0x00, 0x00, 0xE1, 0xB6, 0x01, 0xFC, 0x81, 0x44, 0x30, 0x00, 0xA8, 0x42, 0x01, 0x0C, 0x73, + 0x00, 0x30, 0x00, 0x83, 0xCB, 0x07, 0x00, 0x30, 0x00, 0x43, 0x5A, 0x38, 0x01, 0x04, 0x10, 0x30, + 0x00, 0x83, 0x00, 0x30, 0x00, 0x83, 0x5A, 0x38, 0x01, 0x12, 0x40, 0x10, 0x88, 0x40, 0xB4, 0x41, + 0x5C, 0xF1, 0x0E, 0x10, 0xE8, 0x04, 0x44, 0x20, 0x0E, 0x10, 0xB6, 0x41, 0x00, 0x00, 0x00, 0x81, + 0x5A, 0x08, 0x01, 0x05, 0x44, 0x00, 0x00, 0xE1, 0xB6, 0x01, 0xDD, 0x9E, 0xFC, 0x41, 0x80, 0x40, + 0xF0, 0x81, 0xB6, 0x3F, 0x80, 0x01, 0x80, 0x22, 0x81, 0x44, 0x81, 0x25, 0xF6, 0x0A, 0xF7, 0x0C, + 0xF9, 0xD8, 0x5C, 0xF0, 0x02, 0x71, 0xE8, 0x13, 0xE7, 0x59, 0xE8, 0x0E, 0x98, 0x37, 0xA6, 0x40, + 0xC9, 0x07, 0xB0, 0x41, 0x40, 0x74, 0x9C, 0x40, 0xEA, 0xCF, 0x3A, 0x13, 0x84, 0x20, 0xA6, 0x40, + 0x8C, 0x21, 0xAE, 0x40, 0xFC, 0xC1, 0x84, 0x00, 0x38, 0x03, 0x1C, 0x08, 0xFC, 0xC1, 0xFC, 0x01, + 0xF0, 0x81, 0x00, 0x00, 0x80, 0x87, 0xF4, 0x07, 0xC8, 0x1D, 0x22, 0x50, 0x80, 0x0A, 0xC5, 0x0E, + 0x3C, 0x6D, 0xFD, 0x49, 0x02, 0x03, 0x00, 0x09, 0x8E, 0x01, 0xD0, 0x08, 0x22, 0x50, 0x80, 0x0B, + 0xC5, 0x05, 0x02, 0x03, 0x00, 0x0A, 0x8E, 0x01, 0xD8, 0x0D, 0x84, 0x02, 0x10, 0x00, 0x80, 0x87, + 0x84, 0x06, 0x38, 0x01, 0x90, 0x08, 0x44, 0x30, 0x19, 0x00, 0x38, 0x31, 0x12, 0x0A, 0x10, 0x00, + 0x80, 0x81, 0xFC, 0x81, 0xFC, 0x21, 0xF6, 0x08, 0xF4, 0x81, 0x95, 0x32, 0x88, 0x44, 0xB4, 0xE2, + 0xE2, 0xE1, 0xE8, 0x30, 0x84, 0x2F, 0x10, 0x10, 0x00, 0x86, 0xB0, 0x41, 0xEA, 0xCF, 0x88, 0x85, + 0x3A, 0x12, 0x04, 0x20, 0x84, 0x20, 0xB6, 0x22, 0x38, 0x11, 0x98, 0x08, 0x00, 0x10, 0x00, 0x81, + 0xE6, 0x2E, 0xE8, 0x20, 0x44, 0xF0, 0xA8, 0xB0, 0xEA, 0xD6, 0x40, 0xF0, 0xBC, 0x00, 0xDD, 0x0F, + 0x0E, 0x12, 0x32, 0x32, 0x1A, 0x32, 0x1E, 0x32, 0x32, 0x16, 0x32, 0x22, 0x32, 0x26, 0x84, 0x23, + 0xD5, 0x0C, 0x84, 0x22, 0xD5, 0x0A, 0x84, 0x2A, 0xD5, 0x08, 0x84, 0x25, 0xD5, 0x06, 0x84, 0x27, + 0xD5, 0x04, 0x84, 0x2C, 0xD5, 0x02, 0x84, 0x2E, 0x10, 0x10, 0x00, 0x81, 0x84, 0x21, 0x10, 0x10, + 0x00, 0x84, 0xFC, 0xA1, 0xFC, 0x20, 0x84, 0x80, 0x82, 0x20, 0x80, 0x60, 0x82, 0x04, 0x84, 0x01, + 0x9A, 0x58, 0xE2, 0x61, 0x40, 0x52, 0x40, 0x01, 0x4C, 0x57, 0x80, 0x1B, 0x98, 0x58, 0xE2, 0x23, + 0x40, 0x22, 0x40, 0x00, 0x88, 0x4F, 0x92, 0x21, 0x40, 0x10, 0x8B, 0xE4, 0x92, 0x41, 0x42, 0x51, + 0x04, 0x24, 0x42, 0x60, 0x84, 0x69, 0x40, 0x53, 0x94, 0x20, 0xCD, 0x07, 0xCD, 0x03, 0xE3, 0xA6, + 0xE9, 0x04, 0x80, 0x01, 0x82, 0x02, 0xD5, 0xE5, 0x80, 0x61, 0x80, 0x82, 0xD5, 0xE2, 0xE6, 0x22, + 0xE8, 0xE6, 0xFC, 0xA0, 0xFC, 0x60, 0x81, 0x80, 0x00, 0x01, 0x80, 0x62, 0x81, 0x64, 0x96, 0x04, + 0x80, 0xC5, 0x44, 0xD2, 0xC1, 0x7C, 0x40, 0xA2, 0x88, 0x08, 0xC0, 0x09, 0x84, 0x03, 0x38, 0x01, + 0x14, 0x08, 0x84, 0x00, 0x38, 0x00, 0x94, 0x08, 0x84, 0x00, 0xD5, 0x2E, 0x40, 0x90, 0x94, 0x00, + 0xEA, 0x74, 0xE6, 0x04, 0xE8, 0x03, 0x8C, 0x01, 0xEA, 0x94, 0x99, 0xD6, 0xA6, 0x38, 0xE6, 0x03, + 0xE9, 0x03, 0x84, 0x00, 0xD5, 0x02, 0x8C, 0x01, 0xAE, 0x38, 0x02, 0x25, 0x80, 0x01, 0xEB, 0xED, + 0x40, 0x10, 0x8A, 0x04, 0x38, 0x06, 0x9A, 0x02, 0xF9, 0x14, 0xEB, 0x78, 0xFE, 0x0C, 0xEB, 0x86, + 0xA6, 0x78, 0x84, 0x40, 0x88, 0x2A, 0x38, 0x06, 0x06, 0x0A, 0xEA, 0x74, 0x40, 0xC6, 0x18, 0x80, + 0x80, 0x22, 0xE2, 0x40, 0xE8, 0x06, 0x38, 0x36, 0x0A, 0x02, 0x8C, 0x41, 0x88, 0x23, 0xD5, 0xFA, + 0x40, 0x10, 0x80, 0x3C, 0xEB, 0xE2, 0xEB, 0xED, 0x38, 0x16, 0x9A, 0x09, 0x89, 0x4D, 0x02, 0x15, + 0x80, 0x01, 0x12, 0x15, 0x00, 0x01, 0xFC, 0xE0, 0xFC, 0x61, 0xF0, 0x81, 0x00, 0x01, 0x80, 0x84, + 0x81, 0x22, 0x81, 0x63, 0x80, 0xE5, 0x04, 0xDF, 0x80, 0x0E, 0xF6, 0x0F, 0x5A, 0x08, 0x01, 0x4A, + 0x00, 0x01, 0x80, 0x81, 0x9E, 0x82, 0xE6, 0x42, 0xE9, 0x10, 0x54, 0x20, 0x00, 0xFD, 0x5A, 0x20, + 0x05, 0x0A, 0x5A, 0x00, 0x0A, 0x0B, 0x85, 0x00, 0x5A, 0x28, 0x0C, 0x0A, 0x44, 0x80, 0x00, 0x78, + 0xD5, 0x06, 0x44, 0x80, 0x00, 0x32, 0xD5, 0x03, 0x44, 0x80, 0x00, 0x5A, 0x84, 0x40, 0x44, 0x02, + 0xC0, 0xBC, 0x40, 0xA3, 0x08, 0x08, 0x38, 0x20, 0x19, 0x09, 0x40, 0xC0, 0xA8, 0x00, 0x40, 0x06, + 0xA8, 0x00, 0x3A, 0x16, 0x04, 0x00, 0xEB, 0x70, 0xF0, 0x01, 0x49, 0xFF, 0xFE, 0x4C, 0xE2, 0x08, + 0xE8, 0x04, 0x38, 0x03, 0x99, 0x09, 0xD5, 0x03, 0x38, 0x83, 0x99, 0x09, 0x40, 0x03, 0x98, 0x20, + 0xA4, 0x40, 0xC9, 0x03, 0x84, 0x21, 0xAC, 0x40, 0x40, 0x14, 0xA8, 0x00, 0xA4, 0xC8, 0x02, 0x06, + 0x00, 0x00, 0x44, 0x22, 0xC0, 0xB8, 0x8A, 0x03, 0xA4, 0x49, 0x38, 0x01, 0x1A, 0x09, 0x02, 0x06, + 0x00, 0x01, 0x89, 0x42, 0x8A, 0x01, 0x12, 0x05, 0x00, 0x01, 0x84, 0x02, 0x10, 0x05, 0x80, 0x84, + 0x00, 0x05, 0x80, 0x86, 0x5A, 0x08, 0x0F, 0x52, 0x00, 0x05, 0x80, 0x84, 0x44, 0xC2, 0xC0, 0xBC, + 0x40, 0xA3, 0x08, 0x08, 0x5A, 0x08, 0x03, 0x0C, 0xB0, 0x41, 0x40, 0x04, 0xA8, 0x00, 0xEA, 0xCF, + 0xEB, 0x70, 0x38, 0x03, 0x99, 0x01, 0x38, 0x06, 0x19, 0x09, 0xD5, 0x20, 0x40, 0x06, 0xA8, 0x00, + 0xA4, 0x81, 0x38, 0x16, 0x9A, 0x01, 0x40, 0x10, 0x8A, 0x04, 0xF0, 0x01, 0xF8, 0x82, 0xEB, 0x86, + 0x38, 0x16, 0x19, 0x01, 0x96, 0x01, 0xE2, 0x20, 0x3C, 0x0B, 0xFA, 0x1E, 0xE8, 0x03, 0x38, 0x06, + 0x19, 0x09, 0x38, 0x03, 0x99, 0x01, 0x38, 0x16, 0x19, 0x01, 0xE2, 0x20, 0xE9, 0x07, 0x44, 0x12, + 0xC0, 0xBC, 0xEB, 0xAF, 0x84, 0x03, 0x10, 0x05, 0x80, 0x84, 0x40, 0x73, 0x98, 0x20, 0xA5, 0x38, + 0x38, 0x06, 0x19, 0x01, 0x44, 0x32, 0xC0, 0xB8, 0x38, 0x11, 0x9A, 0x11, 0x9A, 0xA0, 0xFE, 0x54, + 0x02, 0x2F, 0x80, 0x02, 0x40, 0x10, 0x90, 0x36, 0x89, 0x2A, 0x9A, 0x51, 0x12, 0x14, 0x80, 0x00, + 0xA4, 0xB8, 0x89, 0x43, 0x22, 0x35, 0x00, 0x01, 0x9A, 0x50, 0x42, 0x01, 0x84, 0x24, 0x02, 0x1F, + 0x80, 0x03, 0xEA, 0xC9, 0x9A, 0x08, 0xEB, 0xEA, 0xFC, 0xE1, 0xFC, 0x63, 0x80, 0xC0, 0x22, 0x00, + 0x80, 0x00, 0x3C, 0x0B, 0xFA, 0x44, 0x22, 0x00, 0x80, 0x01, 0x3C, 0x0B, 0xFA, 0x45, 0xB4, 0x06, + 0x81, 0x82, 0xEA, 0xA0, 0x80, 0xE3, 0x2E, 0x97, 0xEF, 0x00, 0x44, 0xB2, 0xC0, 0xF0, 0x44, 0xA2, + 0xC0, 0xE0, 0x5A, 0x00, 0x01, 0x06, 0x00, 0x03, 0x00, 0x42, 0x5A, 0x08, 0x02, 0x2F, 0x85, 0x20, + 0x44, 0x02, 0xC0, 0xFC, 0x38, 0x90, 0x1C, 0x08, 0x44, 0x02, 0xC0, 0xF8, 0x38, 0x90, 0x1C, 0x08, + 0x44, 0x10, 0x03, 0x84, 0x44, 0x02, 0xC0, 0xF4, 0x38, 0x10, 0x1E, 0x0A, 0x84, 0x01, 0x10, 0x03, + 0x00, 0x85, 0x3C, 0x8D, 0xFD, 0x22, 0x10, 0x93, 0x00, 0x81, 0x10, 0x93, 0x00, 0x82, 0x10, 0x93, + 0x00, 0x83, 0x10, 0x93, 0x00, 0x84, 0x44, 0x02, 0xC1, 0x00, 0xEA, 0xBE, 0x38, 0x85, 0x9E, 0x0A, + 0x49, 0xFF, 0xFD, 0x7F, 0x10, 0x03, 0x00, 0x87, 0x44, 0x02, 0xC0, 0xE4, 0x38, 0x90, 0x1C, 0x08, + 0x38, 0x85, 0x1E, 0x0A, 0x48, 0x00, 0x00, 0x8B, 0x3C, 0x1D, 0xFD, 0x22, 0x38, 0x05, 0x8E, 0x02, + 0x49, 0x00, 0x0A, 0x4E, 0x00, 0x13, 0x00, 0x81, 0x80, 0x80, 0xF0, 0x85, 0xE6, 0x22, 0xFA, 0x00, + 0x10, 0x03, 0x00, 0x86, 0xE8, 0x21, 0xB1, 0x45, 0x80, 0x06, 0x3C, 0x3D, 0xFD, 0x22, 0x44, 0x42, + 0xC0, 0xD0, 0xB7, 0x7F, 0xF7, 0x81, 0x44, 0x12, 0xC0, 0xF4, 0x44, 0x22, 0xC0, 0xFC, 0x49, 0xFF, + 0xFD, 0x93, 0x80, 0x06, 0x80, 0x47, 0x44, 0x12, 0xC0, 0xF4, 0x49, 0xFF, 0xFD, 0xDF, 0xEB, 0xEB, + 0x44, 0x12, 0xC0, 0xF4, 0x44, 0x22, 0xC0, 0xEC, 0x44, 0x32, 0xC0, 0xE8, 0x80, 0x8B, 0x80, 0xA7, + 0x49, 0xFF, 0xFD, 0xA9, 0xD5, 0x36, 0x9E, 0x0A, 0xE6, 0x02, 0xE9, 0x08, 0x5A, 0x10, 0x05, 0x07, + 0x9E, 0x0F, 0xE6, 0x02, 0xE9, 0x03, 0x5A, 0x18, 0x0A, 0x2D, 0x00, 0x03, 0x00, 0x84, 0x5A, 0x08, + 0x03, 0x05, 0x84, 0x08, 0x10, 0x03, 0x00, 0x81, 0xB4, 0x06, 0x5A, 0x08, 0x02, 0x05, 0x84, 0x00, + 0x10, 0x03, 0x00, 0x85, 0x44, 0x02, 0xC0, 0xE4, 0xB6, 0x1F, 0x14, 0x9F, 0x80, 0x01, 0xF7, 0x82, + 0xEB, 0xEB, 0x38, 0x15, 0x1E, 0x02, 0x80, 0x46, 0x44, 0x32, 0xC0, 0xF4, 0x44, 0x52, 0xC0, 0xCC, + 0x49, 0xFF, 0xFD, 0xCE, 0xB7, 0x7F, 0xF7, 0x81, 0xEB, 0xEB, 0x80, 0x26, 0x44, 0x22, 0xC0, 0xF4, + 0x44, 0x32, 0xC0, 0xF8, 0x44, 0x42, 0xC0, 0xEC, 0x44, 0x52, 0xC0, 0xE8, 0x49, 0xFF, 0xFD, 0xE1, + 0x80, 0x06, 0x44, 0x12, 0xC0, 0xF8, 0x44, 0x22, 0xC0, 0xF4, 0x80, 0x67, 0x49, 0xFF, 0xFD, 0x35, + 0x80, 0x06, 0xF1, 0x05, 0x44, 0x22, 0xC0, 0xF4, 0x44, 0x32, 0xC0, 0xF8, 0x3C, 0x4D, 0xFD, 0x22, + 0x44, 0x52, 0xC0, 0xF0, 0xB6, 0xFF, 0x49, 0xFF, 0xFD, 0xEF, 0x44, 0x02, 0xC0, 0xC0, 0xB6, 0x1F, + 0xF7, 0x81, 0xEB, 0xEB, 0x44, 0x12, 0xC0, 0xC8, 0x44, 0x22, 0xC0, 0xE0, 0x80, 0x66, 0x44, 0x42, + 0xC0, 0xF4, 0x44, 0x52, 0xC0, 0xC4, 0x49, 0xFF, 0xFE, 0x89, 0x38, 0x05, 0x1E, 0x11, 0x40, 0xA5, + 0x1C, 0x40, 0x12, 0x06, 0x00, 0x00, 0x22, 0x05, 0x00, 0x01, 0x12, 0x06, 0x00, 0x01, 0x3C, 0x1D, + 0xFD, 0x22, 0x44, 0x02, 0xC0, 0xC8, 0x38, 0x10, 0x1E, 0x0A, 0xFC, 0xE3, 0xFC, 0x22, 0x80, 0xC0, + 0x3C, 0x0D, 0xFA, 0xCC, 0x5C, 0xF0, 0x03, 0xE8, 0xE8, 0x04, 0x8C, 0x01, 0x3C, 0x0F, 0xFA, 0xCC, + 0xB4, 0x06, 0xC0, 0x6B, 0x5A, 0x00, 0x05, 0x6A, 0x02, 0x03, 0x00, 0x0A, 0x12, 0x0F, 0x80, 0x06, + 0x02, 0x03, 0x00, 0x0B, 0x12, 0x0F, 0x80, 0x07, 0x44, 0x12, 0xC1, 0x88, 0x44, 0x22, 0xC1, 0x84, + 0x80, 0x66, 0xB1, 0x03, 0x84, 0xA0, 0x44, 0x02, 0xC1, 0x8C, 0x49, 0xFF, 0xFE, 0x0D, 0x3C, 0x7D, + 0xFD, 0x4A, 0xB0, 0x43, 0xF0, 0x81, 0x80, 0x41, 0x80, 0x06, 0x3C, 0x3D, 0xFA, 0xCC, 0x3C, 0x4D, + 0xFD, 0x42, 0xA7, 0x79, 0x49, 0xFF, 0xFB, 0x0E, 0xA6, 0x3B, 0xC0, 0x08, 0xB0, 0x43, 0x80, 0x06, + 0x80, 0x41, 0x84, 0x60, 0xF4, 0x01, 0x49, 0xFF, 0xFB, 0x96, 0xA6, 0x3C, 0xC0, 0x08, 0xB0, 0x43, + 0x80, 0x06, 0x80, 0x41, 0x84, 0x60, 0xF4, 0x01, 0x49, 0xFF, 0xFC, 0x3C, 0xA6, 0x3A, 0xC0, 0x07, + 0xB0, 0x43, 0x80, 0x06, 0x80, 0x41, 0x84, 0x60, 0x49, 0xFF, 0xFE, 0xD9, 0xB0, 0x43, 0x80, 0x06, + 0x80, 0x41, 0x84, 0x60, 0x49, 0x00, 0x04, 0xF7, 0x22, 0x0F, 0x80, 0x06, 0x4E, 0x04, 0x00, 0x05, + 0x84, 0x00, 0x12, 0x0F, 0x80, 0x06, 0x22, 0xFF, 0x80, 0x06, 0x5E, 0xF7, 0x8F, 0x00, 0xE9, 0x05, + 0x44, 0x00, 0x0E, 0xFF, 0x12, 0x0F, 0x80, 0x06, 0x22, 0x0F, 0x80, 0x07, 0x4E, 0x04, 0x00, 0x05, + 0x84, 0x00, 0x12, 0x0F, 0x80, 0x07, 0x22, 0xFF, 0x80, 0x07, 0x5E, 0xF7, 0x97, 0x70, 0xE9, 0x05, + 0x44, 0x00, 0x17, 0x6F, 0x12, 0x0F, 0x80, 0x07, 0x02, 0x0F, 0x80, 0x06, 0x12, 0x03, 0x00, 0x0C, + 0x02, 0x0F, 0x80, 0x07, 0x12, 0x03, 0x00, 0x0D, 0x00, 0x03, 0x00, 0x42, 0x5A, 0x08, 0x05, 0x0D, + 0x02, 0x03, 0x00, 0x0C, 0x3C, 0x0B, 0xFA, 0x84, 0x02, 0x03, 0x00, 0x0D, 0x3C, 0x0B, 0xFA, 0x85, + 0x84, 0x00, 0x3C, 0x0F, 0xFA, 0xCC, 0xFC, 0xA2, 0xFC, 0x62, 0x81, 0x40, 0xA6, 0x40, 0x2E, 0x47, + 0x33, 0x8A, 0x2E, 0x07, 0x33, 0xAD, 0x2E, 0x97, 0x33, 0xAC, 0x2E, 0x77, 0x33, 0x8B, 0x5A, 0x10, + 0x01, 0x04, 0x48, 0x00, 0x00, 0xE9, 0x40, 0x52, 0x04, 0x09, 0xFF, 0x04, 0x84, 0x40, 0x90, 0x81, + 0x80, 0x22, 0x44, 0xC3, 0x20, 0xD0, 0x44, 0xD3, 0x22, 0x60, 0x44, 0xE3, 0x27, 0x10, 0x44, 0x83, + 0x28, 0xA0, 0x45, 0x33, 0x4C, 0x10, 0x44, 0xB3, 0x4F, 0x30, 0xE0, 0x24, 0xE8, 0x2E, 0x40, 0x30, + 0x94, 0x17, 0x96, 0x00, 0x94, 0xC9, 0xC8, 0x02, 0x96, 0x98, 0x40, 0x01, 0xB0, 0x00, 0xA4, 0x00, + 0x8C, 0x21, 0x41, 0x20, 0x00, 0x11, 0x40, 0x01, 0xB4, 0x00, 0xA4, 0x00, 0x96, 0x48, 0x41, 0x10, + 0x00, 0x11, 0x40, 0x01, 0xB8, 0x00, 0xA4, 0x00, 0x88, 0x68, 0xA5, 0x98, 0x94, 0xD1, 0x41, 0x00, + 0x00, 0x11, 0x40, 0x01, 0xCC, 0x00, 0x13, 0x20, 0x00, 0x00, 0x98, 0x15, 0x94, 0x01, 0x41, 0x20, + 0x4C, 0x00, 0x97, 0xB3, 0x88, 0x6B, 0x88, 0x0B, 0x8C, 0x41, 0x13, 0x19, 0x00, 0x00, 0x96, 0x90, + 0x13, 0x01, 0x80, 0x00, 0xAD, 0x80, 0xD5, 0xD2, 0xF8, 0xEC, 0x4E, 0xF3, 0x00, 0xA5, 0x5A, 0x00, + 0xA0, 0x08, 0x5A, 0x00, 0xA1, 0x0A, 0x44, 0x62, 0xA1, 0xEA, 0xEA, 0xCD, 0xD5, 0x08, 0x44, 0x63, + 0x4F, 0x30, 0xEA, 0xBD, 0xD5, 0x04, 0x44, 0x62, 0x19, 0xA0, 0xEB, 0x89, 0x3C, 0x04, 0x04, 0x3C, + 0x44, 0xB3, 0x97, 0xDC, 0x12, 0x05, 0x80, 0x00, 0xEA, 0x59, 0x5A, 0x08, 0x0B, 0x24, 0x44, 0x83, + 0x73, 0xE8, 0xDD, 0x5C, 0x80, 0x08, 0xDD, 0x46, 0x80, 0x26, 0x44, 0x03, 0x75, 0x78, 0xF8, 0x60, + 0x44, 0x10, 0x00, 0xC1, 0x44, 0x03, 0x75, 0x72, 0xAC, 0x40, 0xEB, 0xED, 0x44, 0x03, 0x75, 0x74, + 0x96, 0x4B, 0xAC, 0x40, 0x44, 0x03, 0x97, 0xDE, 0xA4, 0x40, 0x44, 0x03, 0x75, 0x76, 0x96, 0x4B, + 0xAC, 0x40, 0xF8, 0x62, 0x80, 0x3F, 0x14, 0x8F, 0x80, 0x02, 0x44, 0x03, 0x4C, 0x10, 0x48, 0x00, + 0x00, 0x66, 0xEA, 0x59, 0x5A, 0x08, 0x0C, 0x1D, 0xDD, 0x5C, 0x44, 0x03, 0x7A, 0x28, 0xDD, 0x46, + 0x80, 0x26, 0x44, 0x03, 0x7B, 0xB8, 0xF8, 0x3C, 0x44, 0x10, 0x00, 0xC2, 0x44, 0x03, 0x7B, 0xB2, + 0xAC, 0x40, 0xEB, 0xCA, 0x44, 0x13, 0x7B, 0xB4, 0xF8, 0x3D, 0x44, 0x13, 0x7B, 0xB6, 0xF8, 0x42, + 0x44, 0x03, 0x77, 0x08, 0xF0, 0x82, 0x80, 0x3F, 0x44, 0x03, 0x4F, 0x30, 0xD5, 0x47, 0xEA, 0x59, + 0x5A, 0x08, 0x0D, 0x1D, 0xDD, 0x5C, 0x44, 0x03, 0x80, 0x68, 0xDD, 0x46, 0x80, 0x26, 0x44, 0x03, + 0x81, 0xF8, 0xF8, 0x1E, 0x44, 0x10, 0x00, 0xC3, 0x44, 0x03, 0x81, 0xF2, 0xAC, 0x40, 0xEB, 0xCA, + 0x44, 0x13, 0x81, 0xF4, 0xF8, 0x1F, 0x44, 0x13, 0x81, 0xF6, 0xF8, 0x24, 0x44, 0x03, 0x7A, 0x28, + 0xF0, 0x82, 0x80, 0x3F, 0x44, 0x03, 0x52, 0x50, 0xD5, 0x29, 0xEA, 0x59, 0x5A, 0x08, 0x0E, 0x2C, + 0xDD, 0x5C, 0x44, 0x03, 0x86, 0xA8, 0xDD, 0x46, 0x80, 0x26, 0x44, 0x03, 0x88, 0x38, 0xDD, 0x5C, + 0xDD, 0x46, 0x44, 0x10, 0x00, 0xC4, 0x44, 0x03, 0x88, 0x32, 0xAC, 0x40, 0xEB, 0xCA, 0x44, 0x13, + 0x88, 0x34, 0x96, 0x03, 0xAC, 0x08, 0x44, 0x03, 0x97, 0xDE, 0xA4, 0x00, 0x83, 0xFF, 0x44, 0x13, + 0x88, 0x36, 0x96, 0x03, 0xAC, 0x08, 0x44, 0x00, 0x03, 0x20, 0xEB, 0x00, 0x83, 0xFF, 0x44, 0x03, + 0x7D, 0x48, 0xF0, 0x82, 0x80, 0x3F, 0x44, 0x03, 0x55, 0x70, 0xA8, 0x09, 0x3A, 0x10, 0x90, 0x00, + 0xEA, 0x62, 0xEA, 0x82, 0x00, 0x05, 0x00, 0x01, 0x5A, 0x00, 0x01, 0x04, 0x48, 0x00, 0x00, 0x7C, + 0x42, 0x74, 0x9C, 0x24, 0x84, 0x20, 0x41, 0x14, 0x84, 0x09, 0x90, 0xE1, 0x80, 0x01, 0x44, 0x93, + 0x23, 0xF0, 0x44, 0xA3, 0x25, 0x80, 0x44, 0xB3, 0x2A, 0x30, 0x44, 0xC3, 0x2B, 0xC0, 0x45, 0x23, + 0x4D, 0xA0, 0x45, 0x33, 0x50, 0xC0, 0xE0, 0x07, 0xE8, 0x2C, 0x40, 0x20, 0x44, 0x77, 0x96, 0xD8, + 0x94, 0x81, 0xCB, 0x02, 0x96, 0x50, 0x40, 0x31, 0x24, 0x00, 0xA4, 0xD8, 0x8C, 0x01, 0x41, 0x01, + 0x80, 0x11, 0x40, 0x31, 0x28, 0x00, 0xA5, 0x98, 0x40, 0x31, 0x2C, 0x00, 0xA5, 0x58, 0x88, 0x4C, + 0x94, 0xC9, 0xA5, 0x10, 0x40, 0x21, 0xC8, 0x00, 0x13, 0x01, 0x00, 0x00, 0x40, 0x20, 0xC4, 0x00, + 0x94, 0x91, 0x41, 0x01, 0x48, 0x00, 0x97, 0xB3, 0x97, 0x6B, 0x97, 0x23, 0x88, 0x73, 0x88, 0x53, + 0x8C, 0x21, 0x12, 0x68, 0x00, 0x00, 0x96, 0x48, 0xAD, 0x58, 0x96, 0x00, 0xAD, 0x10, 0xD5, 0xD4, + 0xEB, 0x42, 0x5C, 0xF0, 0x00, 0xA0, 0x83, 0xFF, 0xE9, 0x36, 0x5A, 0x00, 0xA0, 0x08, 0x5A, 0x00, + 0xA1, 0x0A, 0x44, 0x62, 0xA3, 0x7A, 0xEB, 0x46, 0xD5, 0x08, 0x44, 0x63, 0x50, 0xC0, 0xEB, 0x1F, + 0xD5, 0x04, 0x44, 0x62, 0x1B, 0x30, 0xEB, 0xEF, 0xEA, 0x59, 0x5A, 0x08, 0x0B, 0x08, 0x44, 0x03, + 0x77, 0x08, 0xF8, 0x1F, 0x44, 0x03, 0x78, 0x98, 0xD5, 0x1B, 0xEA, 0x59, 0x5A, 0x08, 0x0C, 0x08, + 0x44, 0x03, 0x7D, 0x48, 0xF8, 0x16, 0x44, 0x03, 0x7E, 0xD8, 0xD5, 0x12, 0xEA, 0x59, 0x5A, 0x08, + 0x0D, 0x08, 0x44, 0x03, 0x83, 0x88, 0xF8, 0x0D, 0x44, 0x03, 0x85, 0x18, 0xD5, 0x09, 0xEA, 0x59, + 0x5A, 0x08, 0x0E, 0x0A, 0x44, 0x03, 0x89, 0xC8, 0xF8, 0x04, 0x44, 0x03, 0x8B, 0x58, 0x80, 0x26, + 0xEA, 0x27, 0xDD, 0x46, 0xFC, 0xE2, 0xFC, 0x00, 0x80, 0xC0, 0xA6, 0x00, 0x5A, 0x08, 0x01, 0x08, + 0x3C, 0x0C, 0x02, 0xBE, 0x3C, 0x1C, 0x02, 0xBA, 0xDD, 0x5C, 0xDD, 0x46, 0xA6, 0x31, 0x5A, 0x08, + 0x01, 0x07, 0x3C, 0x0C, 0x02, 0xBF, 0x3C, 0x1C, 0x02, 0xBB, 0xF8, 0x11, 0xA6, 0x32, 0x5A, 0x08, + 0x01, 0x08, 0x3C, 0x0C, 0x02, 0xC0, 0x3C, 0x1C, 0x02, 0xBC, 0xDD, 0x5C, 0xDD, 0x46, 0xA6, 0x33, + 0x5A, 0x08, 0x01, 0x08, 0x3C, 0x0C, 0x02, 0xC1, 0x3C, 0x1C, 0x02, 0xBD, 0xEA, 0x27, 0xDD, 0x46, + 0xFC, 0x80, 0x44, 0x02, 0xBC, 0x60, 0x84, 0x21, 0x84, 0x40, 0xAE, 0x80, 0xAE, 0x41, 0xAE, 0x42, + 0xAE, 0x43, 0xAE, 0x44, 0xAE, 0x85, 0xDD, 0x9E, 0xFC, 0x20, 0x80, 0xE0, 0xA6, 0x00, 0x80, 0xC1, + 0x5A, 0x08, 0x01, 0x0C, 0xA6, 0x09, 0xC0, 0x09, 0xEA, 0xBD, 0x44, 0x02, 0x16, 0x80, 0xF8, 0x0D, + 0xA6, 0x71, 0x8E, 0x21, 0x96, 0x48, 0xAE, 0x71, 0xA6, 0x3A, 0x5A, 0x08, 0x01, 0x0D, 0xA6, 0x33, + 0xC0, 0x0A, 0xEB, 0xAE, 0x44, 0x02, 0x19, 0xA0, 0xDD, 0x5C, 0xDD, 0x46, 0xA6, 0x73, 0x8E, 0x21, + 0x96, 0x48, 0xAE, 0x73, 0xA6, 0x39, 0x5A, 0x08, 0x01, 0x0C, 0xA6, 0x32, 0xC0, 0x09, 0xEB, 0x1F, + 0x44, 0x02, 0x18, 0x10, 0xF8, 0x0D, 0xA6, 0x72, 0x8E, 0x21, 0x96, 0x48, 0xAE, 0x72, 0xA6, 0x3B, + 0x5A, 0x08, 0x01, 0x0D, 0xA6, 0x34, 0xC0, 0x0A, 0x44, 0x02, 0x1B, 0x30, 0xEB, 0xAA, 0xEA, 0x27, + 0xDD, 0x46, 0xA6, 0x34, 0x8E, 0x01, 0x96, 0x00, 0xAE, 0x34, 0xA6, 0x31, 0xC8, 0x0C, 0xA6, 0x32, + 0xC8, 0x0A, 0xA6, 0x33, 0xC8, 0x08, 0xA6, 0x34, 0x96, 0x00, 0xC8, 0x05, 0x84, 0x21, 0xAE, 0x70, + 0x3E, 0x00, 0x0F, 0x6E, 0xFC, 0xA0, 0xFC, 0x41, 0x2E, 0x17, 0xF2, 0xE9, 0x22, 0x20, 0x00, 0x1A, + 0x22, 0x50, 0x00, 0x16, 0x22, 0x30, 0x00, 0x1B, 0x22, 0x40, 0x00, 0x17, 0xC1, 0x06, 0x8A, 0x45, + 0x9A, 0x5C, 0x96, 0x93, 0x96, 0x4B, 0xD5, 0x02, 0x80, 0x41, 0x50, 0x31, 0x01, 0x45, 0x96, 0xD9, + 0x5C, 0xF1, 0x82, 0x8B, 0x4E, 0xF2, 0x00, 0xE7, 0x50, 0x30, 0x81, 0x45, 0x96, 0xD9, 0x5C, 0xF1, + 0x82, 0x8B, 0x4E, 0xF2, 0x00, 0xE0, 0x00, 0x30, 0x00, 0x7E, 0x5A, 0x38, 0x01, 0x07, 0x84, 0x60, + 0x3E, 0x37, 0xF5, 0xB1, 0x3E, 0x37, 0xF5, 0xB0, 0x2E, 0x37, 0xF5, 0xB0, 0x44, 0x52, 0xC1, 0xE8, + 0x38, 0x12, 0x8D, 0x09, 0x2E, 0x17, 0xF5, 0xB1, 0x44, 0x62, 0xC2, 0x08, 0x38, 0x23, 0x0D, 0x09, + 0xC1, 0x15, 0x85, 0x20, 0x80, 0x29, 0x80, 0xE9, 0x38, 0x23, 0x25, 0x01, 0x88, 0xE2, 0x38, 0x22, + 0xA5, 0x01, 0x8D, 0x21, 0x88, 0x22, 0x97, 0xFB, 0x96, 0x4B, 0x5A, 0x98, 0x10, 0xF7, 0x8C, 0xE8, + 0x40, 0x73, 0xA4, 0xF6, 0x8C, 0x28, 0x97, 0xFB, 0xD5, 0x19, 0x80, 0x41, 0x80, 0xE1, 0x80, 0x81, + 0x38, 0x13, 0x11, 0x01, 0x88, 0xE1, 0x38, 0x12, 0x91, 0x01, 0x8C, 0x81, 0x97, 0x20, 0x88, 0x22, + 0xE2, 0x64, 0x97, 0xFB, 0x96, 0x8B, 0xE8, 0xF5, 0x50, 0x91, 0x80, 0x01, 0x40, 0x14, 0x84, 0x0A, + 0x88, 0xE1, 0x40, 0x73, 0xA4, 0xF6, 0x88, 0x22, 0x97, 0xFB, 0x40, 0x10, 0xA4, 0x36, 0x40, 0x90, + 0x80, 0x11, 0x80, 0xC0, 0x42, 0x04, 0xA4, 0x24, 0x42, 0x03, 0x9C, 0x73, 0xEB, 0x86, 0x44, 0x10, + 0x67, 0xC9, 0x42, 0x10, 0x00, 0x75, 0x84, 0x01, 0x42, 0x00, 0x80, 0x00, 0xEB, 0x86, 0xF0, 0x81, + 0x42, 0x13, 0x80, 0x03, 0x4E, 0x77, 0x00, 0x04, 0xF8, 0x0E, 0xD5, 0x04, 0xF8, 0x0C, 0xFE, 0x02, + 0x96, 0x03, 0x12, 0x03, 0x00, 0x0E, 0x42, 0x14, 0x80, 0x03, 0xF0, 0x01, 0x4E, 0x97, 0x00, 0x04, + 0xF8, 0x02, 0xD5, 0x05, 0x49, 0x00, 0x06, 0xC7, 0xFE, 0x02, 0x96, 0x03, 0x2E, 0x27, 0xF2, 0xE9, + 0x12, 0x03, 0x00, 0x0F, 0x22, 0x13, 0x00, 0x0E, 0xCA, 0x03, 0x80, 0x02, 0x80, 0x22, 0x2E, 0x47, + 0xF5, 0xB0, 0x2E, 0x27, 0xF5, 0xB1, 0x45, 0x02, 0xC1, 0xC8, 0x44, 0x72, 0xC1, 0xA8, 0x38, 0x18, + 0x11, 0x09, 0x38, 0x03, 0x91, 0x09, 0xC2, 0x15, 0x84, 0x00, 0x80, 0x40, 0x80, 0x20, 0x38, 0x38, + 0x01, 0x01, 0x88, 0x23, 0x38, 0x33, 0x81, 0x01, 0x8C, 0x01, 0x88, 0x43, 0x96, 0x4B, 0x96, 0x93, + 0x5A, 0x08, 0x10, 0xF7, 0x8C, 0x28, 0x40, 0x10, 0x80, 0x36, 0x8C, 0x48, 0x96, 0x4B, 0xD5, 0x18, + 0x80, 0x62, 0x80, 0x22, 0x80, 0xA2, 0x38, 0x08, 0x15, 0x01, 0x38, 0x23, 0x95, 0x01, 0x8C, 0xA1, + 0x97, 0x68, 0x88, 0x20, 0x88, 0x43, 0xE2, 0x85, 0x96, 0x4B, 0x96, 0xD3, 0xE8, 0xF5, 0x9C, 0x21, + 0x40, 0x20, 0x04, 0x0A, 0x88, 0x22, 0x40, 0x10, 0x80, 0x36, 0x88, 0x43, 0x96, 0x4B, 0x40, 0x01, + 0x00, 0x16, 0x96, 0x03, 0x5A, 0x40, 0x0F, 0x06, 0x8C, 0x81, 0x3E, 0x47, 0xF5, 0xB0, 0xD5, 0x07, + 0x84, 0x40, 0x3E, 0x27, 0xF5, 0xB0, 0x84, 0x41, 0x3E, 0x27, 0xF5, 0xB1, 0x00, 0x23, 0x00, 0x7E, + 0x5A, 0x28, 0x01, 0x06, 0x3C, 0x1B, 0xFA, 0x97, 0x3C, 0x0B, 0xFA, 0x96, 0x3C, 0x47, 0xFA, 0x96, + 0x3C, 0x27, 0xFA, 0x97, 0x84, 0x63, 0x42, 0x02, 0x0C, 0x73, 0x42, 0x11, 0x0C, 0x73, 0x8C, 0x02, + 0x84, 0x44, 0x8C, 0x22, 0xEA, 0xC9, 0xEB, 0x52, 0x96, 0x03, 0x96, 0x4B, 0x3C, 0x0B, 0xFA, 0x96, + 0x12, 0x03, 0x00, 0x11, 0x84, 0x00, 0x3C, 0x1B, 0xFA, 0x97, 0x12, 0x13, 0x00, 0x10, 0x10, 0x03, + 0x00, 0x7E, 0xFC, 0xC1, 0xFC, 0x23, 0x3C, 0x4D, 0xA8, 0x31, 0x44, 0x21, 0x6D, 0x40, 0x3B, 0x01, + 0x44, 0x00, 0x02, 0x60, 0x00, 0x16, 0x02, 0x20, 0x00, 0x1A, 0x02, 0x50, 0x00, 0x17, 0x9B, 0x96, + 0x97, 0xB3, 0x02, 0x20, 0x00, 0x1B, 0xB6, 0x9F, 0xF4, 0x81, 0x42, 0x33, 0x00, 0x03, 0x92, 0x98, + 0x51, 0x2F, 0x80, 0x08, 0xB1, 0xC4, 0x9B, 0x55, 0xE0, 0x64, 0x3B, 0x09, 0x44, 0x20, 0x3B, 0x03, + 0xC4, 0x20, 0x97, 0x6B, 0xE9, 0x04, 0x22, 0x29, 0x00, 0x03, 0xD5, 0x23, 0x00, 0x2F, 0x80, 0x00, + 0xE0, 0x62, 0xE9, 0x1E, 0x84, 0x80, 0x39, 0x0F, 0x90, 0x00, 0x51, 0x12, 0x00, 0x01, 0xE0, 0x70, + 0xE9, 0x14, 0x40, 0x2F, 0x90, 0x00, 0xA6, 0x91, 0xE0, 0x62, 0xE8, 0x0F, 0x39, 0x39, 0x11, 0x01, + 0x40, 0x41, 0xC0, 0x01, 0x38, 0x39, 0x45, 0x01, 0x8A, 0x50, 0x8A, 0x73, 0xFE, 0xE4, 0x40, 0x21, + 0x88, 0x56, 0x88, 0x53, 0x96, 0x93, 0xD5, 0x05, 0x80, 0x91, 0x5B, 0x18, 0x03, 0xE6, 0x84, 0x40, + 0x4E, 0x65, 0x00, 0x04, 0xFE, 0x92, 0x96, 0x93, 0x44, 0x30, 0x00, 0xA8, 0x42, 0x00, 0x8C, 0x73, + 0xB1, 0x81, 0xA4, 0x46, 0x88, 0x41, 0xA6, 0x73, 0x12, 0x20, 0x00, 0x0A, 0x42, 0x22, 0x80, 0x03, + 0xE0, 0x41, 0xE9, 0x04, 0x22, 0x13, 0x80, 0x03, 0xD5, 0x21, 0x00, 0x1F, 0x80, 0x04, 0xE0, 0x41, + 0xE9, 0x1C, 0x84, 0x60, 0x38, 0x13, 0x0C, 0x00, 0x51, 0x01, 0x80, 0x01, 0xE0, 0x41, 0xE9, 0x12, + 0x99, 0x33, 0xA7, 0x21, 0xE0, 0x44, 0xE8, 0x0E, 0x38, 0x63, 0x8D, 0x01, 0x9A, 0xD1, 0x38, 0x23, + 0xC1, 0x01, 0x8A, 0x81, 0x8A, 0x46, 0xFE, 0x9C, 0x40, 0x11, 0x10, 0x36, 0x88, 0x26, 0x96, 0x4B, + 0xD5, 0x05, 0x80, 0x70, 0x5B, 0x08, 0x03, 0xE8, 0x84, 0x20, 0x4E, 0x55, 0x00, 0x04, 0xFE, 0x4A, + 0x96, 0x4B, 0xA4, 0x87, 0x88, 0x22, 0x12, 0x10, 0x00, 0x0B, 0xFC, 0xA3, 0xFC, 0x20, 0x2E, 0x27, + 0xF2, 0xE9, 0xCA, 0x03, 0x10, 0x20, 0x00, 0x7F, 0x00, 0x30, 0x00, 0x7F, 0xCB, 0x13, 0x5A, 0x28, + 0x01, 0x12, 0x10, 0x20, 0x00, 0x7F, 0x10, 0x20, 0x00, 0x7E, 0xA4, 0x86, 0x12, 0x20, 0x00, 0x18, + 0xA4, 0x87, 0x12, 0x20, 0x00, 0x19, 0xA4, 0x84, 0x12, 0x20, 0x00, 0x1C, 0xA4, 0x85, 0x12, 0x20, + 0x00, 0x1D, 0x44, 0x20, 0x00, 0xA8, 0x42, 0x00, 0x88, 0x73, 0xFA, 0xCF, 0x22, 0x70, 0x00, 0x19, + 0x22, 0x30, 0x00, 0x07, 0x42, 0x33, 0x98, 0x73, 0x22, 0x70, 0x00, 0x1C, 0x22, 0x20, 0x00, 0x04, + 0x22, 0x50, 0x00, 0x18, 0x42, 0x23, 0x98, 0x73, 0x22, 0x70, 0x00, 0x1D, 0x22, 0x10, 0x00, 0x05, + 0x22, 0x40, 0x00, 0x06, 0x42, 0x42, 0x98, 0x73, 0x42, 0x13, 0x98, 0x73, 0xFA, 0xB0, 0x8C, 0x90, + 0x8C, 0x70, 0x8C, 0x50, 0x8C, 0x30, 0x40, 0x42, 0x14, 0x96, 0x40, 0x31, 0x94, 0x76, 0x40, 0x21, + 0x14, 0x56, 0x40, 0x10, 0x94, 0x36, 0x97, 0x23, 0x96, 0xDB, 0x96, 0x93, 0x96, 0x4B, 0x12, 0x40, + 0x00, 0x18, 0x12, 0x30, 0x00, 0x19, 0x12, 0x20, 0x00, 0x1C, 0x12, 0x10, 0x00, 0x1D, 0x12, 0x40, + 0x00, 0x16, 0x12, 0x30, 0x00, 0x17, 0x12, 0x20, 0x00, 0x1A, 0x12, 0x10, 0x00, 0x1B, 0xFC, 0xA0, + 0x44, 0x02, 0xB5, 0x44, 0x3C, 0x0F, 0xFD, 0x7D, 0xDD, 0x9E, 0xFC, 0x68, 0x23, 0x11, 0x80, 0x00, + 0x23, 0x21, 0x80, 0x01, 0x00, 0x30, 0x80, 0x11, 0x04, 0x80, 0x80, 0x07, 0x05, 0x30, 0x80, 0x08, + 0xC3, 0x0B, 0x5A, 0x30, 0x1F, 0x0A, 0x00, 0x50, 0x80, 0x10, 0xC5, 0x06, 0x50, 0x52, 0xFF, 0xCF, + 0x5C, 0x52, 0x80, 0x01, 0xD5, 0x02, 0x84, 0xA1, 0x84, 0x60, 0x3E, 0x37, 0xF5, 0xDE, 0x3C, 0x6D, + 0xFD, 0x76, 0x44, 0x32, 0xC2, 0x2C, 0xC2, 0x31, 0xC6, 0x04, 0x85, 0x60, 0x5A, 0x68, 0x05, 0x08, + 0x3C, 0x7D, 0xFD, 0x7D, 0x85, 0x61, 0xA7, 0xF9, 0x3E, 0x77, 0xF5, 0xDC, 0x3C, 0x77, 0xFA, 0xE6, + 0x41, 0x08, 0x9C, 0x01, 0x3C, 0x77, 0xFA, 0xE7, 0x40, 0x79, 0x1C, 0x01, 0xFF, 0xFC, 0x42, 0x78, + 0x40, 0x73, 0x5A, 0x60, 0x03, 0x07, 0xC6, 0x05, 0x5A, 0x60, 0x05, 0x04, 0x48, 0x00, 0x00, 0x98, + 0x3C, 0x4D, 0xFD, 0x7D, 0xA5, 0xA1, 0xA5, 0x08, 0xE2, 0xC4, 0x2E, 0x47, 0xF5, 0xDC, 0xE8, 0x07, + 0xA4, 0x49, 0xE2, 0xC1, 0xE8, 0x04, 0xC4, 0x03, 0x8E, 0x81, 0x97, 0x20, 0x84, 0xC3, 0x4E, 0x43, + 0x00, 0x88, 0x84, 0xC1, 0x48, 0x00, 0x00, 0x85, 0x9E, 0x71, 0xE6, 0x22, 0xE8, 0x05, 0x3C, 0x1D, + 0xFD, 0x7D, 0xA6, 0x48, 0xD5, 0x09, 0x5A, 0x68, 0x03, 0x04, 0x3E, 0x27, 0xF5, 0xDC, 0x2E, 0x17, + 0xF5, 0xDC, 0xC1, 0x04, 0x8E, 0x21, 0x3E, 0x17, 0xF5, 0xDC, 0x2E, 0x47, 0xF5, 0xDC, 0x5A, 0x48, + 0x01, 0x06, 0x84, 0x28, 0x3E, 0x17, 0xF5, 0xDE, 0xD5, 0x03, 0x84, 0x25, 0xC4, 0x02, 0x84, 0x24, + 0x3C, 0x1F, 0xFD, 0x76, 0x80, 0xC3, 0xB0, 0x41, 0x3B, 0x03, 0x64, 0x04, 0xEA, 0xDB, 0x3B, 0x03, + 0x50, 0x00, 0x3B, 0x00, 0xD0, 0x20, 0x3C, 0x7D, 0xFD, 0x6D, 0x3C, 0xAD, 0xFD, 0x6E, 0x80, 0xD9, + 0x3C, 0x9D, 0xFD, 0x6F, 0x3C, 0xC7, 0xFA, 0xE4, 0x3C, 0xD7, 0xFA, 0xE5, 0x3D, 0x17, 0xFA, 0xE6, + 0x3D, 0x27, 0xFA, 0xE7, 0x2E, 0xB7, 0xF5, 0xDE, 0x2E, 0x57, 0xF5, 0xE9, 0x3C, 0x8D, 0xFD, 0x7B, + 0x84, 0x20, 0xB6, 0x20, 0x5A, 0x60, 0x05, 0x21, 0xF7, 0x81, 0x14, 0xAF, 0x80, 0x02, 0x14, 0x9F, + 0x80, 0x03, 0x12, 0xCF, 0x80, 0x0C, 0x12, 0xDF, 0x80, 0x0D, 0x13, 0x1F, 0x80, 0x0E, 0x13, 0x2F, + 0x80, 0x0F, 0xF6, 0x8A, 0x10, 0x4F, 0x80, 0x2C, 0x10, 0xBF, 0x80, 0x2E, 0x10, 0x5F, 0x80, 0x39, + 0x14, 0x8F, 0x80, 0x0F, 0xB0, 0x41, 0x3B, 0x00, 0xE4, 0x04, 0x3B, 0x01, 0xE4, 0x24, 0x3B, 0x00, + 0xD0, 0x00, 0x3B, 0x01, 0xD0, 0x20, 0x3C, 0x10, 0x07, 0x4E, 0xAC, 0x44, 0x3C, 0x10, 0x07, 0x4F, + 0x3E, 0x27, 0xF5, 0xF0, 0xB6, 0xC0, 0x10, 0xB0, 0x00, 0x62, 0x12, 0xC0, 0x00, 0x02, 0x12, 0xD0, + 0x00, 0x03, 0xAC, 0x45, 0x83, 0x80, 0xBF, 0x99, 0x14, 0xA0, 0x00, 0x1A, 0x14, 0x90, 0x00, 0x1B, + 0xBA, 0x9C, 0x14, 0x80, 0x00, 0x22, 0x5A, 0x68, 0x01, 0x07, 0x12, 0xC0, 0x00, 0x12, 0x12, 0xD0, + 0x00, 0x13, 0xFC, 0xE8, 0xCE, 0x09, 0x84, 0x26, 0xEB, 0x56, 0xFC, 0xE8, 0x84, 0xC2, 0x89, 0x13, + 0x81, 0xB2, 0x81, 0x91, 0xD5, 0xB6, 0xFC, 0xE8, 0x2E, 0x07, 0xF3, 0x05, 0x5A, 0x08, 0x01, 0x0A, + 0x2E, 0x07, 0xE8, 0xCC, 0xE6, 0x11, 0xE8, 0x0D, 0xFA, 0x01, 0x3E, 0x07, 0xE8, 0xCC, 0xDD, 0x9E, + 0x84, 0x05, 0x3E, 0x07, 0xE8, 0xCC, 0x84, 0x03, 0x3E, 0x07, 0xE8, 0xD5, 0x3E, 0x07, 0xE8, 0xD6, + 0xDD, 0x9E, 0xFC, 0x20, 0x00, 0x40, 0x00, 0x42, 0x5A, 0x48, 0x02, 0x1D, 0x84, 0xA0, 0x44, 0x42, + 0xC2, 0x98, 0x38, 0x52, 0x0C, 0x08, 0x84, 0xC1, 0x44, 0x42, 0xC2, 0x94, 0x38, 0x62, 0x0C, 0x08, + 0xA5, 0x88, 0xEB, 0x26, 0xA4, 0x49, 0x38, 0x62, 0x0E, 0x09, 0x40, 0x42, 0x0C, 0x40, 0xAC, 0x61, + 0x44, 0x12, 0xC2, 0x8C, 0x38, 0x50, 0x8C, 0x08, 0x44, 0x12, 0xC2, 0x88, 0x38, 0x50, 0x8C, 0x08, + 0xF8, 0x95, 0x9F, 0x63, 0xE6, 0xA2, 0xE8, 0x44, 0x44, 0x72, 0xC2, 0x94, 0x38, 0x53, 0x8C, 0x00, + 0x44, 0x62, 0xC2, 0x8C, 0x44, 0x42, 0xC2, 0x88, 0x5A, 0x58, 0x01, 0x0A, 0x84, 0xA0, 0x38, 0x53, + 0x0C, 0x08, 0x38, 0x52, 0x0C, 0x08, 0x38, 0x53, 0x8C, 0x08, 0xD5, 0x16, 0x38, 0x52, 0x0C, 0x00, + 0xE6, 0xA2, 0xE8, 0x03, 0x8C, 0xA1, 0xD5, 0x02, 0x84, 0xA0, 0x38, 0x52, 0x0C, 0x08, 0x38, 0x53, + 0x0C, 0x00, 0xCD, 0x0A, 0x38, 0x52, 0x0C, 0x00, 0x5A, 0x58, 0x02, 0x07, 0x84, 0xC1, 0x44, 0x52, + 0xC2, 0x8C, 0x38, 0x62, 0x8C, 0x08, 0x38, 0x52, 0x0C, 0x00, 0x23, 0x00, 0x80, 0x00, 0x99, 0x1D, + 0x44, 0x52, 0xC2, 0x90, 0x38, 0x62, 0x8E, 0x01, 0x45, 0x12, 0xC2, 0x7C, 0x40, 0x68, 0x18, 0x01, + 0x38, 0x68, 0x92, 0x09, 0x40, 0x62, 0x8C, 0x40, 0x22, 0x70, 0x80, 0x01, 0xA4, 0x71, 0x40, 0x48, + 0x90, 0x40, 0x9A, 0x79, 0xAC, 0x61, 0x39, 0x02, 0x8E, 0x09, 0xAD, 0xF1, 0xF8, 0x4F, 0x5A, 0x40, + 0x05, 0x03, 0xF8, 0x4C, 0x44, 0x42, 0xC2, 0x8C, 0x38, 0x72, 0x0C, 0x00, 0x84, 0x20, 0x44, 0x62, + 0xC2, 0x78, 0x45, 0x12, 0xC2, 0x74, 0x38, 0x13, 0x0E, 0x0A, 0x38, 0x18, 0x8E, 0x0A, 0x44, 0x52, + 0xC2, 0x88, 0x44, 0x42, 0xC2, 0x7C, 0x5A, 0x70, 0x01, 0x05, 0x39, 0x22, 0x8C, 0x00, 0xD5, 0x38, + 0x39, 0x32, 0x8C, 0x00, 0x40, 0x42, 0x0C, 0x40, 0x80, 0xE1, 0x80, 0xA1, 0x86, 0x01, 0x4C, 0x59, + 0xC0, 0x03, 0x86, 0x02, 0x23, 0x22, 0x00, 0x00, 0x8C, 0xA1, 0x42, 0x18, 0x48, 0x73, 0x23, 0x22, + 0x00, 0x01, 0x97, 0x68, 0x42, 0x78, 0x48, 0x73, 0x8C, 0x84, 0x5A, 0x58, 0x03, 0xF1, 0x84, 0x84, + 0x40, 0x10, 0x90, 0x36, 0x40, 0x73, 0x90, 0xF6, 0x38, 0x13, 0x0E, 0x0A, 0x38, 0x78, 0x8E, 0x0A, + 0x44, 0x72, 0xC2, 0x70, 0x41, 0x01, 0x88, 0x08, 0x84, 0x20, 0x40, 0x43, 0xC0, 0x00, 0x38, 0x13, + 0x8E, 0x09, 0x39, 0x18, 0x8E, 0x02, 0xAC, 0x61, 0x38, 0x43, 0x0E, 0x02, 0x42, 0x18, 0x80, 0x03, + 0x42, 0x62, 0x00, 0x03, 0x99, 0x71, 0xE4, 0xAB, 0xE8, 0x26, 0x48, 0x00, 0x00, 0x77, 0x99, 0x59, + 0x38, 0x72, 0x16, 0x11, 0x39, 0x03, 0x0E, 0x02, 0x40, 0x52, 0x14, 0x40, 0x89, 0x87, 0x8C, 0x21, + 0x22, 0x72, 0x80, 0x01, 0x38, 0x58, 0x8E, 0x02, 0x96, 0x48, 0x88, 0xA7, 0xE3, 0xC1, 0x39, 0x03, + 0x0E, 0x0A, 0x38, 0x58, 0x8E, 0x0A, 0xE8, 0xEC, 0x8D, 0xC1, 0x44, 0x12, 0xC2, 0x78, 0x41, 0x08, + 0x4A, 0x16, 0x39, 0x00, 0x8E, 0x0A, 0x40, 0x52, 0xC8, 0xB6, 0x44, 0x12, 0xC2, 0x74, 0x38, 0x50, + 0x8E, 0x0A, 0xD5, 0xC7, 0x4E, 0x47, 0x00, 0x0A, 0xEB, 0x26, 0x38, 0x42, 0x0E, 0x11, 0x44, 0x50, + 0x00, 0x64, 0x52, 0x42, 0x0E, 0xFF, 0xD5, 0x06, 0xC4, 0x0A, 0xEB, 0x26, 0x38, 0x52, 0x0E, 0x11, + 0xEA, 0xC1, 0xFF, 0x2C, 0x40, 0x62, 0x18, 0xD6, 0x97, 0xB1, 0xD5, 0x03, 0x44, 0x60, 0xFF, 0xFF, + 0x4F, 0x17, 0x00, 0x0B, 0xEB, 0x26, 0x88, 0x90, 0x22, 0x42, 0x00, 0x01, 0x44, 0x50, 0x00, 0x64, + 0x52, 0x42, 0x17, 0x6F, 0xD5, 0x08, 0x4F, 0x12, 0x00, 0x0C, 0xEB, 0x26, 0x88, 0x90, 0x22, 0x52, + 0x00, 0x01, 0xEA, 0xC1, 0xFF, 0x2C, 0x40, 0x12, 0x04, 0x36, 0x96, 0x49, 0xD5, 0x03, 0x44, 0x10, + 0xFF, 0xFF, 0x42, 0x10, 0x98, 0x01, 0x5C, 0xF0, 0x80, 0x96, 0x44, 0x42, 0xC2, 0x98, 0xE8, 0x08, + 0x84, 0xA0, 0x38, 0x53, 0x8E, 0x09, 0x88, 0xF0, 0xAC, 0x79, 0x84, 0x21, 0xD5, 0x14, 0x5C, 0xF0, + 0x81, 0x2C, 0xE8, 0x09, 0x92, 0x21, 0x50, 0x50, 0xFF, 0xF6, 0x38, 0x53, 0x8E, 0x09, 0x8C, 0x2A, + 0x88, 0xF0, 0xD5, 0x07, 0xEB, 0x78, 0x38, 0x13, 0x8E, 0x09, 0x88, 0xF0, 0x44, 0x10, 0x00, 0x6E, + 0xAC, 0x79, 0x84, 0x22, 0x38, 0x12, 0x0C, 0x08, 0x00, 0x60, 0x00, 0x62, 0x45, 0x12, 0xC2, 0x98, + 0x38, 0xF8, 0x8C, 0x00, 0x54, 0x63, 0x00, 0xFD, 0x10, 0x60, 0x00, 0x62, 0xE8, 0x31, 0x52, 0x17, + 0x80, 0x02, 0x44, 0x42, 0xC2, 0x70, 0x40, 0x10, 0x8C, 0x20, 0x38, 0x12, 0x05, 0x01, 0x44, 0x42, + 0xC2, 0x78, 0x38, 0x52, 0x0E, 0x02, 0x44, 0x72, 0xC2, 0x90, 0xFF, 0x4C, 0x45, 0x20, 0x00, 0x64, + 0x38, 0x43, 0x8E, 0x01, 0x40, 0x52, 0xC8, 0xB6, 0x88, 0xA4, 0x44, 0x42, 0xC2, 0x74, 0x38, 0x42, + 0x0E, 0x02, 0x97, 0x6B, 0xFE, 0x64, 0x38, 0x53, 0x8E, 0x09, 0x40, 0x73, 0x8C, 0x40, 0xA5, 0x39, + 0x40, 0x10, 0xC8, 0x36, 0x88, 0x24, 0x96, 0x4B, 0x58, 0x63, 0x00, 0x02, 0x50, 0xF7, 0xFF, 0xFF, + 0x10, 0x60, 0x00, 0x62, 0xAC, 0x79, 0xAD, 0x50, 0xAC, 0x51, 0x38, 0xF8, 0x8C, 0x08, 0xFC, 0xA0, + 0xFC, 0x20, 0xA6, 0xC0, 0x5A, 0x38, 0x01, 0x56, 0x84, 0x60, 0x84, 0x9F, 0x10, 0x40, 0x80, 0x11, + 0x10, 0x40, 0x80, 0x08, 0xA8, 0xCD, 0xA8, 0xCF, 0x10, 0x30, 0x80, 0x09, 0x80, 0x83, 0x04, 0x51, + 0x00, 0x18, 0xF8, 0xB1, 0xE8, 0x05, 0xA5, 0x28, 0x10, 0x30, 0x80, 0x11, 0x97, 0x23, 0x8C, 0x61, + 0x5A, 0x38, 0x20, 0xF7, 0x84, 0x60, 0x80, 0x83, 0x82, 0x03, 0x04, 0x51, 0x00, 0x18, 0xF8, 0xB6, + 0x4E, 0x77, 0x00, 0x28, 0x00, 0x70, 0x80, 0x11, 0x50, 0xF3, 0xFF, 0xFD, 0xE0, 0x6F, 0xE9, 0x21, + 0x8C, 0xE3, 0xE0, 0xE3, 0xE9, 0x1E, 0xA5, 0xE8, 0xA1, 0x4D, 0x97, 0xFB, 0x42, 0x51, 0x9C, 0x73, + 0xA9, 0x4D, 0x00, 0x50, 0x80, 0x08, 0x8C, 0x81, 0x97, 0x23, 0x5A, 0x58, 0xFF, 0x04, 0x10, 0x30, + 0x80, 0x08, 0x00, 0x50, 0x80, 0x09, 0xE0, 0x65, 0xE9, 0x03, 0x10, 0x30, 0x80, 0x09, 0x04, 0x51, + 0x00, 0x18, 0x88, 0xC5, 0xA5, 0x70, 0xA1, 0x8F, 0x97, 0x6B, 0x88, 0xA6, 0xA9, 0x4F, 0xD5, 0x03, + 0x13, 0x02, 0x80, 0x00, 0x8C, 0x61, 0x5A, 0x38, 0x20, 0xD2, 0x84, 0x60, 0x4E, 0x47, 0x00, 0x09, + 0x00, 0x30, 0x80, 0x11, 0x04, 0x41, 0x00, 0x18, 0x40, 0x32, 0x0C, 0x20, 0xA4, 0xD8, 0xAC, 0xC8, + 0xA6, 0xC1, 0x5A, 0x38, 0x01, 0x58, 0x84, 0x60, 0x84, 0x9F, 0x10, 0x40, 0x80, 0x10, 0x10, 0x40, + 0x80, 0x0A, 0xA8, 0xCE, 0x14, 0x30, 0x80, 0x08, 0x10, 0x30, 0x80, 0x0B, 0x80, 0x83, 0x04, 0x51, + 0x00, 0x19, 0xF8, 0x59, 0xE8, 0x05, 0xA5, 0x28, 0x10, 0x30, 0x80, 0x10, 0x97, 0x23, 0x8C, 0x61, + 0x5A, 0x38, 0x32, 0xF7, 0x84, 0x60, 0x80, 0x83, 0x82, 0x03, 0x04, 0x51, 0x00, 0x19, 0xF8, 0x5E, + 0x4E, 0x77, 0x00, 0x29, 0x00, 0x70, 0x80, 0x10, 0x50, 0xF3, 0xFF, 0xFD, 0xE0, 0x6F, 0xE9, 0x22, + 0x8C, 0xE3, 0xE0, 0xE3, 0xE9, 0x1F, 0xA5, 0xE8, 0xA1, 0x4E, 0x97, 0xFB, 0x42, 0x51, 0x9C, 0x73, + 0xA9, 0x4E, 0x00, 0x50, 0x80, 0x0A, 0x8C, 0x81, 0x97, 0x23, 0x5A, 0x58, 0xFF, 0x04, 0x10, 0x30, + 0x80, 0x0A, 0x00, 0x50, 0x80, 0x0B, 0xE0, 0x65, 0xE9, 0x03, 0x10, 0x30, 0x80, 0x0B, 0x04, 0x51, + 0x00, 0x19, 0x88, 0xC5, 0xA5, 0x70, 0x83, 0x81, 0xBE, 0x08, 0x97, 0x6B, 0x88, 0xA6, 0xBD, 0x88, + 0xD5, 0x03, 0x13, 0x02, 0x80, 0x00, 0x8C, 0x61, 0x5A, 0x38, 0x32, 0xD1, 0x84, 0x60, 0x4E, 0x47, + 0x00, 0x09, 0x00, 0x30, 0x80, 0x10, 0x04, 0x41, 0x00, 0x19, 0x40, 0x32, 0x0C, 0x20, 0xA4, 0xD8, + 0xAC, 0xC9, 0xA6, 0xC2, 0x5A, 0x38, 0x01, 0x62, 0x84, 0x60, 0x84, 0x9F, 0x10, 0x40, 0x80, 0x13, + 0x10, 0x40, 0x80, 0x0C, 0x83, 0x81, 0xBB, 0x89, 0xBB, 0x8B, 0x10, 0x30, 0x80, 0x0D, 0x80, 0x83, + 0x04, 0x51, 0x00, 0x1A, 0x40, 0x52, 0x8C, 0x20, 0xA5, 0xA8, 0x97, 0xB3, 0xE0, 0x86, 0x83, 0xFF, + 0xE8, 0x05, 0xA5, 0x28, 0x10, 0x30, 0x80, 0x13, 0x97, 0x23, 0x8C, 0x61, 0x5A, 0x38, 0x20, 0xF2, + 0x84, 0x60, 0x80, 0x83, 0x82, 0x03, 0x04, 0x51, 0x00, 0x1A, 0x95, 0x99, 0x88, 0xA6, 0xA5, 0xE8, + 0x97, 0xFB, 0x83, 0xFF, 0x4E, 0x77, 0x00, 0x2A, 0x00, 0x70, 0x80, 0x13, 0x50, 0xF3, 0xFF, 0xFA, + 0xE0, 0x6F, 0xE9, 0x23, 0x8C, 0xE6, 0xE0, 0xE3, 0xE9, 0x20, 0xA5, 0xE8, 0x83, 0x81, 0xBD, 0x09, + 0x97, 0xFB, 0x42, 0x51, 0x9C, 0x73, 0xBD, 0x89, 0x00, 0x50, 0x80, 0x0C, 0x8C, 0x81, 0x97, 0x23, + 0x5A, 0x58, 0xFF, 0x04, 0x10, 0x30, 0x80, 0x0C, 0x00, 0x50, 0x80, 0x0D, 0xE0, 0x65, 0xE9, 0x03, + 0x10, 0x30, 0x80, 0x0D, 0x04, 0x51, 0x00, 0x1A, 0x88, 0xC5, 0xA5, 0x70, 0x83, 0x81, 0xBE, 0x0B, + 0x97, 0x6B, 0x88, 0xA6, 0xBD, 0x8B, 0xD5, 0x03, 0x13, 0x02, 0x80, 0x00, 0x8C, 0x61, 0x5A, 0x38, + 0x20, 0xCC, 0x84, 0x60, 0x4E, 0x47, 0x00, 0x09, 0x00, 0x30, 0x80, 0x13, 0x04, 0x41, 0x00, 0x1A, + 0x40, 0x32, 0x0C, 0x20, 0xA4, 0xD8, 0xAC, 0xCA, 0xA6, 0x03, 0x5A, 0x08, 0x01, 0x5F, 0x84, 0x00, + 0x84, 0x7F, 0x10, 0x30, 0x80, 0x12, 0x10, 0x30, 0x80, 0x0E, 0x83, 0x81, 0xB8, 0x8A, 0xB8, 0x8C, + 0x10, 0x00, 0x80, 0x0F, 0x80, 0x60, 0x04, 0x41, 0x00, 0x1B, 0x40, 0x42, 0x00, 0x20, 0xA5, 0x60, + 0x97, 0x6B, 0xE0, 0x65, 0xE8, 0x05, 0xA4, 0xE0, 0x10, 0x00, 0x80, 0x12, 0x96, 0xDB, 0x8C, 0x01, + 0x5A, 0x08, 0x32, 0xF3, 0x84, 0x00, 0x80, 0x60, 0x80, 0xE0, 0x04, 0x41, 0x00, 0x1B, 0x95, 0x41, + 0x88, 0x85, 0xA5, 0xA0, 0x97, 0xB3, 0x4E, 0x67, 0x00, 0x2A, 0x00, 0x60, 0x80, 0x12, 0x50, 0xF3, + 0x7F, 0xFA, 0xE0, 0x0F, 0xE9, 0x23, 0x8C, 0xC6, 0xE0, 0xC0, 0xE9, 0x20, 0xA5, 0xA0, 0x83, 0x81, + 0xBC, 0x0A, 0x97, 0xB3, 0x42, 0x40, 0x18, 0x73, 0xBC, 0x8A, 0x00, 0x40, 0x80, 0x0E, 0x8C, 0x61, + 0x96, 0xDB, 0x5A, 0x48, 0xFF, 0x04, 0x10, 0x00, 0x80, 0x0E, 0x00, 0x40, 0x80, 0x0F, 0xE0, 0x04, + 0xE9, 0x03, 0x10, 0x00, 0x80, 0x0F, 0x04, 0x41, 0x00, 0x1B, 0x88, 0xA4, 0xA5, 0x28, 0x83, 0x81, + 0xBD, 0x0C, 0x97, 0x23, 0x88, 0x85, 0xBC, 0x8C, 0xD5, 0x02, 0xAD, 0xE0, 0x8C, 0x01, 0x5A, 0x08, + 0x32, 0xCE, 0x84, 0x00, 0x4E, 0x37, 0x00, 0x09, 0x00, 0x00, 0x80, 0x12, 0x04, 0x21, 0x00, 0x1B, + 0x40, 0x01, 0x00, 0x20, 0xA4, 0x00, 0xAC, 0x0B, 0xFC, 0xA0, 0xA6, 0x49, 0x5A, 0x18, 0x01, 0x04, + 0xA6, 0x52, 0xD5, 0x02, 0xEA, 0xBE, 0x2E, 0x27, 0xF3, 0x70, 0x5A, 0x28, 0x01, 0x03, 0xA6, 0x5C, + 0x22, 0xF0, 0x00, 0x03, 0xE0, 0x2F, 0xE9, 0x05, 0x2E, 0x07, 0xEF, 0x34, 0x5A, 0x08, 0x01, 0x08, + 0x84, 0x01, 0x3E, 0x07, 0xEF, 0x30, 0x84, 0x00, 0x3E, 0x07, 0xEF, 0x0F, 0xDD, 0x9E, 0x3C, 0x2D, + 0xFC, 0x04, 0x2E, 0x47, 0x34, 0x2E, 0xA6, 0x91, 0x5A, 0x20, 0x06, 0x04, 0x97, 0x21, 0xD5, 0x03, + 0x2E, 0x47, 0x34, 0x30, 0xA6, 0x01, 0x5A, 0x08, 0x01, 0x04, 0x2E, 0x47, 0x34, 0x2F, 0x2E, 0x07, + 0xEF, 0x36, 0x2E, 0x27, 0x34, 0x35, 0xE2, 0x02, 0xE8, 0x06, 0x8C, 0x01, 0x3C, 0x43, 0x9A, 0x1B, + 0x3E, 0x07, 0xEF, 0x36, 0x2E, 0x27, 0xEF, 0x0F, 0x2E, 0x07, 0x34, 0x34, 0x2E, 0x37, 0x34, 0x2D, + 0xE2, 0x40, 0xE9, 0x2F, 0x2E, 0x07, 0xEF, 0x10, 0x5A, 0x08, 0x01, 0x30, 0xFC, 0x20, 0x40, 0x00, + 0x0C, 0x0C, 0x8A, 0x04, 0x96, 0x01, 0x84, 0xE0, 0xEA, 0xFC, 0xE2, 0xE2, 0xE8, 0x21, 0xA1, 0x8A, + 0xB4, 0x41, 0x94, 0xF9, 0x88, 0xC3, 0x88, 0x43, 0x03, 0x03, 0x00, 0x00, 0x04, 0x50, 0x80, 0x14, + 0xA4, 0x90, 0x88, 0xA3, 0xFE, 0xA4, 0xA4, 0xE8, 0x42, 0x20, 0x40, 0x73, 0x8C, 0xE1, 0x88, 0x43, + 0x2E, 0x37, 0x34, 0x2D, 0x40, 0x31, 0x0C, 0x0D, 0x96, 0xD9, 0xAC, 0xF0, 0xA4, 0xF0, 0x2E, 0x67, + 0x34, 0x2D, 0x40, 0x31, 0x98, 0x0C, 0x8A, 0x43, 0x96, 0x91, 0xAC, 0xA8, 0xD5, 0xDE, 0xFC, 0xA0, + 0x8C, 0x41, 0x3E, 0x27, 0xEF, 0x0F, 0xDD, 0x9E, 0xDD, 0x9E, 0x2E, 0x17, 0x34, 0x17, 0x5A, 0x10, + 0x01, 0x04, 0x84, 0x01, 0xDD, 0x9E, 0x2E, 0x27, 0xF2, 0xE5, 0xCA, 0xFC, 0xEB, 0x88, 0xC8, 0x3E, + 0x44, 0x32, 0x6E, 0xB8, 0x3C, 0x13, 0x99, 0xDE, 0xE2, 0x01, 0xE8, 0x1D, 0x3C, 0x1C, 0x03, 0x21, + 0xEB, 0xB2, 0xA4, 0x88, 0x3C, 0x13, 0x9A, 0x1E, 0x96, 0x93, 0xFE, 0x4A, 0xE0, 0x41, 0xE8, 0x10, + 0x98, 0x83, 0xA6, 0x50, 0x8C, 0x21, 0x96, 0x48, 0xAE, 0x50, 0xA6, 0x90, 0x3C, 0x13, 0x9A, 0x19, + 0xE2, 0x41, 0xE9, 0x06, 0x3C, 0x13, 0xF7, 0xD3, 0x8C, 0x21, 0x3C, 0x1B, 0xF7, 0xD3, 0x8C, 0x01, + 0x96, 0x01, 0xD5, 0xE1, 0x3C, 0x03, 0xF7, 0xD3, 0x3C, 0x13, 0x9A, 0x1F, 0xE2, 0x20, 0xE8, 0xD2, + 0x84, 0x20, 0x3C, 0x1B, 0xF7, 0xD3, 0x84, 0x00, 0x44, 0x32, 0x6E, 0xB8, 0xEA, 0xFC, 0xE2, 0x02, + 0xE8, 0x06, 0x98, 0x83, 0x8C, 0x01, 0xAE, 0x50, 0x96, 0x01, 0xD5, 0xF9, 0x2E, 0x07, 0xF3, 0x74, + 0x8C, 0x01, 0x3E, 0x07, 0xF3, 0x74, 0x84, 0x02, 0xDD, 0x9E, 0x3C, 0x2B, 0xF7, 0xD3, 0x80, 0x01, + 0xDD, 0x9E, 0xFC, 0x20, 0x44, 0x40, 0x27, 0x10, 0x80, 0xC0, 0xFE, 0x64, 0x22, 0x00, 0x00, 0x28, + 0x40, 0x20, 0x88, 0x56, 0xFE, 0x24, 0x22, 0x13, 0x00, 0x50, 0x22, 0x33, 0x00, 0x00, 0x40, 0x10, + 0x04, 0x36, 0xE0, 0x22, 0xE8, 0x4E, 0x40, 0xF0, 0x0D, 0xF6, 0xE0, 0x4F, 0xE8, 0x4C, 0xEB, 0xD1, + 0xFA, 0x78, 0x80, 0x24, 0x99, 0x1D, 0x40, 0x02, 0x04, 0x0A, 0x5C, 0xF0, 0x00, 0x51, 0xE9, 0x04, + 0x52, 0x40, 0x00, 0xA0, 0xD5, 0x04, 0x80, 0x80, 0x5A, 0x00, 0x28, 0x05, 0x52, 0x70, 0x00, 0x78, + 0xD5, 0x03, 0x44, 0x70, 0x00, 0x50, 0x38, 0x43, 0x11, 0x11, 0x38, 0x73, 0x1D, 0x11, 0xFF, 0x0C, + 0x40, 0x42, 0x1C, 0x96, 0xE0, 0x44, 0xE8, 0x03, 0x9F, 0x41, 0xD5, 0x04, 0xE0, 0x82, 0xE8, 0x2E, + 0x9C, 0xC1, 0xE0, 0xA3, 0xE8, 0xE0, 0x4C, 0x01, 0x80, 0x03, 0x80, 0xA3, 0x5C, 0xF2, 0x80, 0x51, + 0xE9, 0x04, 0x52, 0x12, 0x80, 0xA0, 0xD5, 0x02, 0x80, 0x25, 0x50, 0x72, 0x80, 0x28, 0x5C, 0xF3, + 0x80, 0x51, 0xE9, 0x03, 0x52, 0x72, 0x80, 0x78, 0x38, 0x13, 0x05, 0x11, 0x44, 0x30, 0x27, 0x10, + 0xFE, 0xCC, 0x38, 0x13, 0x1D, 0x11, 0x8A, 0x82, 0xEA, 0xF0, 0x9A, 0x9A, 0xEB, 0x96, 0xEA, 0xE5, + 0xE0, 0x82, 0xE9, 0x0C, 0xE0, 0x44, 0xE9, 0x09, 0xE2, 0x05, 0x40, 0x02, 0xBC, 0x1A, 0xFC, 0xA0, + 0xFA, 0x18, 0xFC, 0xA0, 0xEA, 0x47, 0xFC, 0xA0, 0x80, 0x05, 0xFC, 0xA0, 0xFC, 0x20, 0x44, 0x40, + 0x27, 0x10, 0x80, 0xC0, 0xFE, 0x64, 0x22, 0x00, 0x00, 0x28, 0x40, 0x20, 0x88, 0x56, 0xFE, 0x24, + 0x22, 0x13, 0x00, 0x50, 0x22, 0x33, 0x00, 0x00, 0x40, 0x10, 0x04, 0x36, 0xE0, 0x22, 0xE8, 0x4E, + 0x40, 0xF0, 0x0D, 0xF6, 0xE0, 0x4F, 0xE8, 0x4C, 0xEB, 0xD1, 0xFA, 0x78, 0x80, 0x24, 0x99, 0x1D, + 0x40, 0x02, 0x04, 0x0A, 0x5C, 0xF0, 0x00, 0x51, 0xE9, 0x04, 0x52, 0x40, 0x00, 0xA0, 0xD5, 0x04, + 0x80, 0x80, 0x5A, 0x00, 0x28, 0x05, 0x52, 0x70, 0x00, 0x78, 0xD5, 0x03, 0x44, 0x70, 0x00, 0x50, + 0x38, 0x43, 0x11, 0x11, 0x38, 0x73, 0x1D, 0x11, 0xFF, 0x0C, 0x40, 0x42, 0x1C, 0x96, 0xE0, 0x44, + 0xE8, 0x03, 0x9F, 0x41, 0xD5, 0x04, 0xE0, 0x82, 0xE8, 0x2E, 0x9C, 0xC1, 0xE0, 0xA3, 0xE8, 0xE0, + 0x4C, 0x01, 0x80, 0x03, 0x80, 0xA3, 0x5C, 0xF2, 0x80, 0x51, 0xE9, 0x04, 0x52, 0x12, 0x80, 0xA0, + 0xD5, 0x02, 0x80, 0x25, 0x50, 0x72, 0x80, 0x28, 0x5C, 0xF3, 0x80, 0x51, 0xE9, 0x03, 0x52, 0x72, + 0x80, 0x78, 0x38, 0x13, 0x05, 0x11, 0x44, 0x30, 0x27, 0x10, 0xFE, 0xCC, 0x38, 0x13, 0x1D, 0x11, + 0x8A, 0x82, 0xEA, 0xF0, 0x9A, 0x9A, 0xEB, 0x96, 0xEA, 0xE5, 0xE0, 0x82, 0xE9, 0x0C, 0xE0, 0x44, + 0xE9, 0x09, 0xE2, 0x05, 0x40, 0x02, 0xBC, 0x1A, 0xFC, 0xA0, 0xFA, 0x18, 0xFC, 0xA0, 0xEA, 0x47, + 0xFC, 0xA0, 0x80, 0x05, 0xFC, 0xA0, 0x5C, 0xF0, 0x00, 0x51, 0xE9, 0x05, 0x52, 0x30, 0x00, 0xA0, + 0xB6, 0x61, 0xD5, 0x02, 0xB6, 0x01, 0x50, 0x10, 0x7F, 0xD8, 0x5C, 0xF0, 0x80, 0x51, 0xE9, 0x05, + 0x52, 0x00, 0x00, 0xC8, 0xB6, 0x02, 0xDD, 0x9E, 0xB6, 0x22, 0xDD, 0x9E, 0xFC, 0x01, 0x96, 0xCB, + 0x96, 0x83, 0x90, 0x30, 0x90, 0x10, 0x8A, 0x01, 0x8A, 0x43, 0xFE, 0x04, 0x42, 0x01, 0x08, 0x73, + 0xFC, 0x81, 0xFC, 0x04, 0x44, 0x31, 0x6D, 0x48, 0x3B, 0x01, 0xD8, 0x04, 0x80, 0x9F, 0x3B, 0x02, + 0x58, 0x24, 0xA4, 0xD8, 0xAC, 0xE0, 0x84, 0x80, 0x80, 0x5F, 0x40, 0x00, 0x28, 0x08, 0x40, 0x10, + 0xA8, 0x08, 0x80, 0x64, 0x40, 0x50, 0x90, 0x0E, 0x40, 0x60, 0x10, 0x0E, 0x4E, 0x17, 0x00, 0x08, + 0x8A, 0x26, 0x38, 0x61, 0x11, 0x11, 0x88, 0x05, 0x88, 0x66, 0xD5, 0x06, 0x88, 0x26, 0x38, 0x61, + 0x11, 0x11, 0x8A, 0x05, 0x8A, 0x66, 0x8C, 0x81, 0x5A, 0x48, 0x0F, 0xEE, 0x50, 0x31, 0x80, 0x80, + 0x44, 0x00, 0x01, 0x00, 0x40, 0x01, 0x80, 0x16, 0x96, 0x03, 0xFC, 0x84, 0xFC, 0x20, 0x84, 0x41, + 0x40, 0x21, 0x04, 0x0C, 0x41, 0x21, 0x00, 0x11, 0x96, 0x91, 0x9D, 0xD5, 0x40, 0x69, 0x04, 0x08, + 0x8E, 0x45, 0xE4, 0x02, 0x97, 0x13, 0x97, 0xB3, 0x97, 0xFB, 0x40, 0x20, 0x04, 0x0C, 0xE9, 0x25, + 0x84, 0x60, 0x90, 0x01, 0x8C, 0x61, 0x5A, 0x08, 0x01, 0xFE, 0x40, 0x21, 0x0C, 0x0E, 0x40, 0x01, + 0x84, 0x0C, 0x86, 0x20, 0xE0, 0x44, 0xE9, 0x03, 0xE0, 0xE2, 0xE8, 0x18, 0x80, 0x71, 0xE0, 0x46, + 0xE8, 0x07, 0xFE, 0x94, 0x8C, 0x61, 0x40, 0x21, 0x04, 0x0E, 0x96, 0xD8, 0xD5, 0xF9, 0x82, 0x23, + 0x82, 0x12, 0x84, 0xA0, 0xD3, 0x05, 0x8C, 0xA1, 0x91, 0x81, 0x97, 0x68, 0xD5, 0xFC, 0xE6, 0xB4, + 0x88, 0x10, 0x90, 0x41, 0xE9, 0xE8, 0xD5, 0x02, 0x84, 0x00, 0xFC, 0xA0, 0xFC, 0x20, 0x20, 0x7F, + 0x80, 0x1C, 0xF6, 0x06, 0x42, 0x02, 0x08, 0x73, 0x88, 0x61, 0x5A, 0x78, 0x01, 0x15, 0x5A, 0x4F, + 0xFF, 0x08, 0x44, 0x20, 0x00, 0x32, 0xFE, 0x14, 0x40, 0x30, 0x0C, 0x76, 0xD5, 0x0F, 0x5A, 0x48, + 0x32, 0x0B, 0x44, 0x20, 0x00, 0x34, 0xFE, 0x14, 0xFA, 0x38, 0x42, 0x01, 0x84, 0x75, 0x40, 0x30, + 0x0C, 0x77, 0xD5, 0x04, 0xFF, 0x44, 0x40, 0x32, 0x8C, 0x76, 0x88, 0xC3, 0x84, 0x00, 0x42, 0x03, + 0x00, 0x00, 0x96, 0x03, 0xFC, 0xA0, 0x3C, 0x0F, 0xFD, 0x89, 0xDD, 0x9E, 0x44, 0x02, 0xE2, 0x90, + 0x84, 0x20, 0xAE, 0x40, 0xAE, 0x41, 0xAE, 0x42, 0xAE, 0x43, 0xAE, 0x44, 0xAE, 0x45, 0xAE, 0x46, + 0xAE, 0x47, 0xDD, 0x9E, 0xFC, 0x01, 0xF0, 0x81, 0xF8, 0x07, 0x40, 0x00, 0x00, 0x09, 0xF0, 0x01, + 0x9E, 0x41, 0xF1, 0x81, 0xC8, 0xFB, 0xDD, 0x45, 0xDD, 0x47, 0xAE, 0x40, 0x83, 0xFF, 0xFC, 0x81, + 0xFC, 0x02, 0xF0, 0x81, 0xF0, 0x01, 0xEB, 0xD2, 0xFE, 0x0C, 0x50, 0x10, 0x7C, 0x5E, 0x46, 0x03, + 0xA1, 0x96, 0x50, 0x00, 0x0B, 0x1F, 0x42, 0x00, 0x80, 0x69, 0x40, 0x00, 0x94, 0x09, 0xF0, 0x83, + 0xEA, 0x37, 0xF0, 0x03, 0x9E, 0x41, 0xF1, 0x83, 0xC8, 0xFC, 0xDD, 0x45, 0xDD, 0x47, 0xAE, 0x40, + 0xFC, 0x82, 0xFC, 0x02, 0xF0, 0x81, 0x84, 0x00, 0xF0, 0x83, 0xD5, 0x0A, 0xDD, 0x45, 0xDD, 0x47, + 0xAE, 0x40, 0x44, 0x00, 0x03, 0xE8, 0xEA, 0x39, 0xF0, 0x03, 0x8C, 0x01, 0xF0, 0x83, 0xF1, 0x03, + 0xF0, 0x01, 0xE2, 0x20, 0xE9, 0xF4, 0xFC, 0x82, 0x3C, 0x0F, 0xFD, 0x96, 0xDD, 0x9E, 0x3C, 0x0F, + 0xFD, 0x95, 0xDD, 0x9E, 0x3C, 0x0F, 0xFD, 0x94, 0xDD, 0x9E, 0x3C, 0x1D, 0xFD, 0x96, 0xA0, 0x03, + 0xA4, 0x4C, 0xE2, 0x01, 0xE9, 0x06, 0x84, 0x00, 0x3E, 0x07, 0xF3, 0x70, 0x84, 0x02, 0xDD, 0x9E, + 0x84, 0x00, 0xDD, 0x9E, 0xFC, 0x00, 0x84, 0x00, 0x44, 0x12, 0xBC, 0x80, 0x44, 0x2F, 0xFF, 0xAA, + 0xAE, 0x08, 0xAE, 0x0A, 0xAE, 0x89, 0x84, 0x20, 0x3C, 0x1F, 0xFD, 0xA0, 0x3C, 0x1F, 0xFD, 0x9F, + 0x3E, 0x17, 0xF6, 0x89, 0x3C, 0x1B, 0xFB, 0x42, 0x84, 0x21, 0x3E, 0x27, 0xEB, 0x38, 0xEB, 0x03, + 0x3E, 0x07, 0xF6, 0x88, 0x3C, 0x1F, 0xFA, 0xCD, 0x3E, 0x07, 0xF6, 0x87, 0x3E, 0x07, 0xF6, 0x8B, + 0x3E, 0x07, 0xF6, 0x86, 0x3E, 0x07, 0xF6, 0x63, 0x3E, 0x07, 0xF6, 0x62, 0x3E, 0x07, 0xF6, 0x61, + 0x3E, 0x07, 0xF6, 0x60, 0xFC, 0x80, 0x3C, 0x0D, 0xFD, 0x96, 0xA4, 0x04, 0xDD, 0x9E, 0x2E, 0x07, + 0xF6, 0x8B, 0xDD, 0x9E, 0x2E, 0x17, 0x33, 0x91, 0x84, 0x00, 0xEB, 0x67, 0x84, 0x81, 0x96, 0x80, + 0xE2, 0x41, 0xE8, 0x06, 0x98, 0x83, 0x10, 0x41, 0x02, 0x80, 0x8C, 0x01, 0xD5, 0xF9, 0xEA, 0x3F, + 0x3C, 0x0B, 0x9B, 0x0B, 0xDD, 0x9E, 0x3C, 0x13, 0x9A, 0xA6, 0xAC, 0x40, 0xDD, 0x9E, 0xFC, 0x00, + 0xEB, 0x80, 0x44, 0x33, 0xF0, 0x4A, 0x8E, 0x41, 0xAF, 0x18, 0x84, 0xA0, 0xE0, 0x45, 0xE9, 0x1A, + 0x98, 0xEA, 0x90, 0x61, 0xDA, 0x05, 0x38, 0x40, 0x0E, 0x02, 0x4C, 0x40, 0x80, 0x12, 0x38, 0x60, + 0x0E, 0x02, 0x95, 0x1A, 0xE2, 0x26, 0xE9, 0x08, 0x88, 0x80, 0xA1, 0x21, 0xE2, 0x24, 0xE8, 0x06, + 0x4C, 0x60, 0x80, 0x07, 0xD5, 0x07, 0x9E, 0x99, 0xD5, 0xEA, 0x9D, 0x59, 0xD5, 0xE8, 0x80, 0x03, + 0xFC, 0x80, 0x84, 0x1F, 0xFC, 0x80, 0x8E, 0x21, 0x94, 0x49, 0x40, 0x20, 0x04, 0x0D, 0x8E, 0x22, + 0x40, 0x00, 0x04, 0x0D, 0x96, 0x8F, 0x96, 0x0F, 0xCA, 0x04, 0x5A, 0x08, 0x02, 0x10, 0xD5, 0x0C, + 0x5A, 0x28, 0x01, 0x04, 0xC8, 0x0B, 0xD5, 0x08, 0x5A, 0x28, 0x02, 0x05, 0x5A, 0x08, 0x03, 0x07, + 0xD5, 0x03, 0x5A, 0x08, 0x01, 0x04, 0xFA, 0x00, 0xDD, 0x9E, 0xFA, 0x10, 0xDD, 0x9E, 0x84, 0x00, + 0x44, 0x12, 0xD4, 0xBC, 0x84, 0x5F, 0x38, 0x20, 0x81, 0x09, 0x8C, 0x01, 0x5A, 0x08, 0x14, 0xFD, + 0xDD, 0x9E, 0xFC, 0x20, 0x9C, 0x81, 0x96, 0x94, 0x2E, 0x67, 0xF6, 0x89, 0x40, 0x50, 0x04, 0x09, + 0x84, 0x20, 0x84, 0x61, 0x44, 0x42, 0xD4, 0xBC, 0xE2, 0xC3, 0xE9, 0x1C, 0xC5, 0x0E, 0x5A, 0x58, + 0x01, 0x17, 0x41, 0x01, 0x04, 0x20, 0x40, 0x71, 0x0C, 0x20, 0x39, 0x02, 0x41, 0x01, 0x38, 0x72, + 0x1D, 0x01, 0xE3, 0x87, 0xEB, 0xA5, 0xD5, 0x0B, 0x40, 0x71, 0x04, 0x20, 0x41, 0x01, 0x0C, 0x20, + 0x38, 0x72, 0x1D, 0x01, 0x39, 0x02, 0x41, 0x01, 0xE3, 0x87, 0xEB, 0xA5, 0x8C, 0x61, 0x96, 0xD8, + 0xD5, 0xE4, 0x94, 0xC1, 0x94, 0x49, 0x96, 0x04, 0x99, 0x9A, 0x44, 0x52, 0xD4, 0xBC, 0x88, 0x60, + 0x88, 0x41, 0x88, 0x01, 0x44, 0x42, 0xE2, 0xB8, 0x38, 0x22, 0x89, 0x01, 0x38, 0x02, 0x81, 0x01, + 0x38, 0x22, 0x19, 0x09, 0x38, 0x02, 0x0D, 0x09, 0xFC, 0xA0, 0x92, 0x00, 0xFC, 0x62, 0xB1, 0xC1, + 0x80, 0xC1, 0x84, 0x4A, 0x84, 0x20, 0x85, 0xC0, 0x81, 0x60, 0x80, 0x07, 0x81, 0x43, 0x81, 0x2E, + 0xEA, 0x2F, 0x3C, 0x4D, 0xFD, 0x96, 0x80, 0x46, 0x80, 0x2E, 0x84, 0x05, 0xB4, 0x62, 0xC3, 0x0F, + 0x8E, 0x64, 0xE6, 0x62, 0xE9, 0x0C, 0x04, 0x51, 0x00, 0x08, 0x04, 0x35, 0x80, 0x02, 0x38, 0x31, + 0x95, 0x01, 0xA7, 0x66, 0xE2, 0xA3, 0xE8, 0x03, 0xEA, 0x7E, 0x85, 0xC1, 0xB4, 0x62, 0x9F, 0x59, + 0xE6, 0xA2, 0xE9, 0x03, 0x5A, 0x38, 0x04, 0x08, 0x50, 0x34, 0x80, 0x01, 0x38, 0x13, 0xA4, 0x08, + 0x54, 0x91, 0x80, 0xFF, 0x8C, 0x21, 0x96, 0x48, 0x50, 0x21, 0x00, 0x54, 0x5A, 0x18, 0x0A, 0xE0, + 0x4E, 0x93, 0x00, 0x0B, 0x10, 0x95, 0x00, 0x02, 0x81, 0x69, 0x81, 0x09, 0x81, 0xA9, 0x81, 0x89, + 0x80, 0xC9, 0x80, 0xE9, 0xD5, 0x3F, 0x2E, 0x07, 0xF6, 0x8A, 0x5A, 0x98, 0x01, 0x24, 0x8E, 0x01, + 0xE6, 0x02, 0x2E, 0x57, 0xF6, 0x86, 0xE8, 0x08, 0x00, 0x7F, 0x80, 0x04, 0xD7, 0x05, 0xEB, 0x49, + 0x3E, 0x77, 0xF6, 0x86, 0xD5, 0x07, 0x5A, 0x58, 0xFF, 0x06, 0x00, 0x0F, 0x80, 0x04, 0x3E, 0x07, + 0xF6, 0x86, 0x2E, 0x17, 0xF6, 0x86, 0xEA, 0xB2, 0x42, 0x60, 0x80, 0x73, 0x85, 0x60, 0x84, 0x01, + 0x22, 0x73, 0x00, 0x04, 0x81, 0x0B, 0x22, 0x63, 0x00, 0x05, 0x81, 0xAB, 0xEA, 0x7E, 0x81, 0x8B, + 0xD5, 0x19, 0x5A, 0x00, 0x06, 0x03, 0xEB, 0x49, 0x00, 0x1F, 0x80, 0x04, 0xEA, 0xB2, 0x80, 0x46, + 0x42, 0x20, 0x80, 0x73, 0xA6, 0x79, 0x22, 0xC1, 0x00, 0x04, 0x42, 0x60, 0x80, 0x73, 0x84, 0x03, + 0x22, 0x83, 0x00, 0x04, 0x22, 0xB3, 0x00, 0x05, 0x84, 0xC0, 0x22, 0xD1, 0x00, 0x05, 0x80, 0xE6, + 0xEA, 0x7E, 0xEA, 0xA4, 0x5A, 0x00, 0x01, 0x04, 0x5A, 0xE8, 0x01, 0x04, 0x84, 0x05, 0xEA, 0x7E, + 0x00, 0x05, 0x00, 0x02, 0x5A, 0x08, 0x01, 0x55, 0x3C, 0x2D, 0xFD, 0x94, 0xA6, 0x50, 0x5A, 0x18, + 0x01, 0x09, 0x3C, 0x1D, 0xFD, 0x95, 0x02, 0x10, 0x80, 0x09, 0x8E, 0x21, 0x9B, 0xCF, 0x97, 0xFB, + 0xA6, 0x51, 0x5A, 0x18, 0x01, 0x09, 0x3C, 0x1D, 0xFD, 0x95, 0x02, 0x10, 0x80, 0x0A, 0x8E, 0x21, + 0x9B, 0x8E, 0x97, 0xB3, 0xA6, 0x53, 0x00, 0xF1, 0x00, 0x02, 0x5A, 0x18, 0x01, 0x35, 0x3C, 0x2D, + 0xFD, 0x95, 0x02, 0x41, 0x00, 0x09, 0x8E, 0x81, 0xE9, 0x18, 0xA5, 0x52, 0x84, 0x22, 0x40, 0x32, + 0x04, 0x76, 0x8E, 0xA1, 0x42, 0x33, 0x94, 0x73, 0x40, 0x71, 0x90, 0xF7, 0x02, 0x31, 0x00, 0x0A, + 0xA4, 0x93, 0x8E, 0x61, 0x8E, 0x41, 0x40, 0x11, 0x84, 0x36, 0x42, 0x13, 0x08, 0x73, 0x97, 0xFB, + 0x40, 0x60, 0x8C, 0xD7, 0x97, 0xB3, 0xD5, 0x1C, 0xA5, 0x53, 0x84, 0x22, 0x40, 0x32, 0x04, 0x76, + 0x8E, 0xA1, 0x42, 0x33, 0x94, 0x73, 0x40, 0x71, 0x90, 0xF7, 0x02, 0x31, 0x00, 0x0A, 0xA4, 0x92, + 0x8E, 0x61, 0x8E, 0x41, 0x40, 0x11, 0x84, 0x36, 0x42, 0x13, 0x08, 0x73, 0x97, 0xFB, 0x40, 0x60, + 0x8C, 0xD7, 0x97, 0xB3, 0x5A, 0xF8, 0x01, 0x05, 0x80, 0x27, 0x80, 0xE6, 0x80, 0xC1, 0x2E, 0x17, + 0xF6, 0x8A, 0xE6, 0x27, 0x4E, 0xF2, 0x00, 0xEB, 0x44, 0xF0, 0xC5, 0x98, 0x38, 0x17, 0x85, 0x01, + 0x40, 0xF0, 0xBC, 0x00, 0x4A, 0x00, 0x3C, 0x00, 0x0E, 0x00, 0xA6, 0x00, 0xBA, 0x00, 0xD8, 0x00, + 0xB6, 0x01, 0xC2, 0x01, 0xDE, 0x00, 0x5A, 0x08, 0x01, 0x04, 0x48, 0x00, 0x00, 0xD9, 0x5A, 0x00, + 0x03, 0x04, 0x48, 0x00, 0x00, 0xD4, 0x84, 0x00, 0x3E, 0x07, 0xF6, 0x3D, 0x3E, 0x07, 0xF6, 0x3C, + 0x5A, 0x98, 0x02, 0x3B, 0x84, 0x00, 0xEB, 0x75, 0xF9, 0x06, 0x3C, 0x0D, 0xFD, 0x96, 0x3C, 0xCB, + 0xFB, 0x24, 0x02, 0x30, 0x00, 0x11, 0x3C, 0xDB, 0xFB, 0x25, 0x40, 0xF6, 0x0C, 0x07, 0x3C, 0x8B, + 0xFB, 0x26, 0x3C, 0xBB, 0xFB, 0x27, 0x3C, 0xCB, 0xFB, 0x20, 0x3C, 0xDB, 0xFB, 0x21, 0x3C, 0x8B, + 0xFB, 0x22, 0x3C, 0xBB, 0xFB, 0x23, 0x3C, 0xC8, 0x04, 0x22, 0x3C, 0xD8, 0x04, 0x23, 0x3C, 0x88, + 0x04, 0x24, 0x3C, 0xB8, 0x04, 0x25, 0xE9, 0x45, 0x02, 0x20, 0x00, 0x12, 0xE0, 0x4C, 0xE9, 0x41, + 0x02, 0x10, 0x00, 0x13, 0x40, 0xF6, 0x84, 0x07, 0xE9, 0x3C, 0x02, 0x00, 0x00, 0x14, 0xE0, 0x0D, + 0xE9, 0x38, 0xE1, 0x03, 0xE9, 0x36, 0xE0, 0x48, 0xE9, 0x34, 0xE1, 0x61, 0xE9, 0x32, 0xE0, 0x0B, + 0xE9, 0x30, 0x48, 0x00, 0x00, 0x8C, 0xF8, 0xCF, 0x84, 0x04, 0x48, 0x00, 0x00, 0x91, 0x5A, 0x08, + 0x01, 0x04, 0x48, 0x00, 0x00, 0x88, 0x4E, 0x02, 0x00, 0x88, 0x5A, 0x08, 0x03, 0x23, 0x48, 0x00, + 0x00, 0x86, 0x5A, 0x08, 0x01, 0x04, 0x48, 0x00, 0x00, 0x7E, 0x4E, 0x02, 0x00, 0x7E, 0x5A, 0x08, + 0x03, 0x19, 0x3C, 0x03, 0xFB, 0x42, 0xE6, 0x0A, 0xE8, 0x14, 0xEB, 0x49, 0x84, 0x00, 0xD5, 0x77, + 0xE6, 0x02, 0xE9, 0x74, 0xD5, 0x0E, 0xE7, 0x23, 0xE8, 0x09, 0x5A, 0x98, 0x02, 0x06, 0x2E, 0x17, + 0xF6, 0x3C, 0x5A, 0x10, 0x01, 0x04, 0x5A, 0x08, 0x05, 0x07, 0x84, 0x00, 0x3E, 0x07, 0xF6, 0x3C, + 0x84, 0x04, 0xD5, 0x65, 0xC8, 0x2F, 0x3C, 0x27, 0xFB, 0x21, 0x3C, 0x37, 0xFB, 0x25, 0x9A, 0x53, + 0x5E, 0xF0, 0x82, 0x1D, 0xE9, 0x23, 0x3C, 0x17, 0xFB, 0x23, 0x3C, 0x57, 0xFB, 0x27, 0x9B, 0x0D, + 0x5E, 0xF2, 0x02, 0x1D, 0xE9, 0x1B, 0x50, 0x41, 0x00, 0x34, 0x8A, 0x83, 0x4E, 0x45, 0x00, 0x17, + 0x50, 0x30, 0x80, 0x34, 0x8A, 0x65, 0x4E, 0x35, 0x00, 0x12, 0x84, 0x61, 0x3E, 0x37, 0xF6, 0x3D, + 0x3C, 0x28, 0x04, 0x27, 0x3C, 0x33, 0xFB, 0x20, 0x3C, 0x23, 0xFB, 0x22, 0x3C, 0x38, 0x04, 0x26, + 0x3C, 0x28, 0x04, 0x28, 0x3C, 0x18, 0x04, 0x29, 0xD5, 0x3A, 0x49, 0xFF, 0xFE, 0x2A, 0x84, 0x00, + 0xD5, 0x36, 0x5A, 0x98, 0x02, 0x28, 0x3C, 0x07, 0xFB, 0x25, 0x3C, 0xCB, 0xFB, 0x20, 0x8A, 0x0D, + 0x42, 0x10, 0x00, 0x03, 0x3C, 0x07, 0xFB, 0x27, 0x3C, 0xDB, 0xFB, 0x21, 0x8A, 0x0B, 0xEB, 0x39, + 0x42, 0x00, 0x80, 0x00, 0xFA, 0x33, 0xFE, 0x0C, 0x3C, 0x17, 0xFB, 0x24, 0x92, 0x07, 0x8A, 0x2C, + 0x42, 0xF0, 0x80, 0x03, 0xE2, 0x0F, 0x3C, 0x8B, 0xFB, 0x22, 0x3C, 0xBB, 0xFB, 0x23, 0xE9, 0xB1, + 0x3C, 0x17, 0xFB, 0x26, 0x40, 0x80, 0xA0, 0x01, 0x42, 0xF4, 0x00, 0x03, 0xE2, 0x0F, 0xE9, 0xA9, + 0xD5, 0x05, 0x5A, 0x98, 0x01, 0x04, 0x3E, 0x97, 0xF6, 0x3C, 0x84, 0x06, 0xD5, 0x08, 0xC8, 0xA1, + 0xD5, 0x06, 0x84, 0x02, 0xD5, 0x04, 0x84, 0x03, 0xD5, 0x02, 0x84, 0x00, 0xEB, 0x03, 0x8E, 0x01, + 0xE6, 0x06, 0x4E, 0xF2, 0x03, 0x0A, 0x44, 0xF0, 0xC7, 0x70, 0xEA, 0xA1, 0xEA, 0x3C, 0xDD, 0x0F, + 0x0C, 0x00, 0x72, 0x00, 0xDC, 0x01, 0x02, 0x06, 0x06, 0x06, 0x0A, 0x06, 0x84, 0x20, 0x3C, 0x1F, + 0xFD, 0xA0, 0x3C, 0x1F, 0xFD, 0x9F, 0x84, 0x21, 0x84, 0x00, 0x3C, 0x1F, 0xFA, 0xCD, 0xEA, 0x8E, + 0xEB, 0x75, 0x3E, 0x07, 0xF6, 0x89, 0x3E, 0x07, 0xF6, 0x88, 0x3E, 0x07, 0xF6, 0x87, 0xEA, 0x70, + 0x3C, 0x7B, 0xFB, 0x3C, 0x3C, 0x6B, 0xFB, 0x3D, 0x3C, 0x7B, 0xFB, 0x3A, 0x3C, 0x6B, 0xFB, 0x3B, + 0x3C, 0x7B, 0xFB, 0x38, 0x3C, 0x6B, 0xFB, 0x39, 0x3C, 0x7B, 0xFB, 0x36, 0x3C, 0x6B, 0xFB, 0x37, + 0x3C, 0x7B, 0xFB, 0x34, 0x3C, 0x6B, 0xFB, 0x35, 0x3E, 0x07, 0xF6, 0x62, 0x3E, 0x07, 0xF6, 0x60, + 0x3E, 0x07, 0xF6, 0x3D, 0x49, 0xFF, 0xFD, 0xB5, 0x3C, 0x78, 0x04, 0x22, 0x3C, 0x68, 0x04, 0x23, + 0xF8, 0xB4, 0x3C, 0x07, 0xFB, 0x3B, 0xFA, 0x33, 0x9A, 0xF0, 0xEA, 0xE3, 0x3C, 0x27, 0xFB, 0x3A, + 0x42, 0x51, 0x84, 0x24, 0x9B, 0x3A, 0xEB, 0x96, 0x92, 0xA7, 0xE2, 0xA4, 0x3C, 0x7B, 0xFB, 0x38, + 0x3C, 0x6B, 0xFB, 0x39, 0xE8, 0x04, 0x84, 0xA1, 0x3E, 0x57, 0xF6, 0x65, 0xFE, 0x64, 0x92, 0x27, + 0xE2, 0x23, 0xE8, 0x04, 0x84, 0x21, 0x3E, 0x17, 0xF6, 0x64, 0x3C, 0x3D, 0xFD, 0x96, 0x2E, 0x17, + 0xF6, 0x62, 0x02, 0x41, 0x80, 0x1A, 0xE2, 0x24, 0xE8, 0x04, 0x8C, 0x21, 0x3E, 0x17, 0xF6, 0x62, + 0x8A, 0x47, 0x8A, 0x06, 0xEA, 0xE5, 0xEB, 0x39, 0x02, 0x11, 0x80, 0x19, 0x88, 0x02, 0xE0, 0x20, + 0xE8, 0x04, 0x84, 0x01, 0x3E, 0x07, 0xF6, 0x60, 0x3C, 0xF7, 0xFB, 0x34, 0xE0, 0xEF, 0xE8, 0x04, + 0x3C, 0x7B, 0xFB, 0x34, 0xD5, 0x07, 0x3C, 0x07, 0xFB, 0x36, 0xE0, 0x07, 0xE8, 0x03, 0x3C, 0x7B, + 0xFB, 0x36, 0xEB, 0x4D, 0xE0, 0xCF, 0xE8, 0x04, 0x3C, 0x6B, 0xFB, 0x35, 0xD5, 0x07, 0x3C, 0x07, + 0xFB, 0x37, 0xE0, 0x06, 0xE8, 0x03, 0x3C, 0x6B, 0xFB, 0x37, 0x3D, 0x07, 0xFB, 0x3C, 0x3C, 0x47, + 0xFB, 0x3D, 0x40, 0x08, 0x1C, 0x01, 0x9A, 0x66, 0xEB, 0x39, 0xEA, 0x93, 0xA5, 0x5D, 0x98, 0x88, + 0xE2, 0xA2, 0x4E, 0xF2, 0x02, 0x74, 0xA4, 0x9E, 0xE2, 0x02, 0x4E, 0xF3, 0x02, 0x70, 0xA4, 0x9F, + 0xE2, 0x22, 0x4E, 0xF3, 0x02, 0x6C, 0xE1, 0x87, 0x2E, 0x37, 0xF6, 0x87, 0xE8, 0x05, 0x58, 0x51, + 0x80, 0x02, 0x84, 0x40, 0xD5, 0x03, 0x97, 0x5C, 0x84, 0x41, 0xE0, 0xC4, 0xE8, 0x04, 0x58, 0x52, + 0x80, 0x01, 0xD5, 0x05, 0x97, 0x4E, 0x8C, 0x41, 0x97, 0x68, 0x96, 0x90, 0x3D, 0x1D, 0xFD, 0x9F, + 0x88, 0x31, 0x3C, 0x1F, 0xFD, 0x9F, 0x3C, 0x1D, 0xFD, 0xA0, 0x88, 0x01, 0x3C, 0x0F, 0xFD, 0xA0, + 0x5A, 0x28, 0x02, 0x0E, 0x2E, 0x07, 0xF6, 0x89, 0xC8, 0x0A, 0x84, 0x01, 0x3E, 0x07, 0xF6, 0x89, + 0x3C, 0x0D, 0xFA, 0xCD, 0x94, 0x02, 0x3C, 0x0F, 0xFA, 0xCD, 0xD5, 0x23, 0xD3, 0x22, 0x2E, 0x07, + 0xF6, 0x89, 0xE6, 0x07, 0xE8, 0x19, 0x3C, 0x1D, 0xFA, 0xCD, 0x8C, 0x01, 0x40, 0x12, 0x84, 0x44, + 0x96, 0x00, 0x3C, 0x1F, 0xFA, 0xCD, 0x3E, 0x07, 0xF6, 0x89, 0x3E, 0x57, 0xF6, 0x87, 0x5A, 0x00, + 0x01, 0x11, 0x8E, 0x01, 0x94, 0x01, 0x44, 0x12, 0xD4, 0xBC, 0x39, 0x00, 0x81, 0x09, 0x8C, 0x01, + 0x38, 0x40, 0x81, 0x09, 0xD5, 0x06, 0x2E, 0x07, 0xF6, 0x88, 0x8C, 0x01, 0x3E, 0x07, 0xF6, 0x88, + 0x3C, 0x7B, 0xFB, 0x3C, 0x3C, 0x6B, 0xFB, 0x3D, 0x48, 0x00, 0x02, 0x19, 0x2E, 0x87, 0xF6, 0x89, + 0x3C, 0x23, 0xFB, 0x38, 0x3C, 0x13, 0xFB, 0x39, 0x4E, 0x82, 0x00, 0x0C, 0x40, 0x04, 0x04, 0x08, + 0x44, 0x32, 0xD4, 0xBC, 0x38, 0x21, 0x81, 0x09, 0x8C, 0x01, 0x38, 0x11, 0x81, 0x09, 0xD5, 0x05, + 0x3C, 0x28, 0x04, 0x24, 0x3C, 0x18, 0x04, 0x25, 0x3C, 0x6D, 0xFD, 0x96, 0x3C, 0xDD, 0xFD, 0xA0, + 0x3C, 0xCD, 0xFD, 0x9F, 0x02, 0x13, 0x00, 0x10, 0x40, 0x06, 0x34, 0x00, 0xE2, 0x20, 0x4E, 0xF2, + 0x01, 0x0E, 0x2E, 0x07, 0xEB, 0x38, 0x5A, 0x00, 0xAA, 0x04, 0x48, 0x00, 0x01, 0x08, 0x3C, 0x77, + 0xFB, 0x3A, 0x02, 0x03, 0x00, 0x11, 0xE0, 0xE0, 0x4E, 0xF3, 0x00, 0xFF, 0x02, 0x03, 0x00, 0x12, + 0xE0, 0x07, 0x4E, 0xF3, 0x00, 0xFA, 0x3C, 0xB7, 0xFB, 0x3B, 0x02, 0x03, 0x00, 0x13, 0xE1, 0x60, + 0x4E, 0xF3, 0x00, 0xF3, 0x02, 0x03, 0x00, 0x14, 0xE0, 0x0B, 0x4E, 0xF3, 0x00, 0xEE, 0x44, 0x02, + 0xB7, 0xB4, 0x3C, 0x1D, 0xFA, 0xCD, 0x44, 0x20, 0x00, 0x57, 0x49, 0xFF, 0xFC, 0x72, 0x5A, 0x0F, + 0xFF, 0x04, 0x48, 0x00, 0x00, 0xDD, 0x44, 0x11, 0x6D, 0xA8, 0x38, 0x10, 0x80, 0x00, 0xEA, 0x70, + 0x5A, 0x18, 0x21, 0x1B, 0x3C, 0x17, 0xFB, 0x39, 0xE0, 0x2B, 0xE8, 0x04, 0x84, 0x26, 0xEA, 0x70, + 0xD5, 0x68, 0x40, 0x15, 0x84, 0x01, 0xEA, 0x93, 0xEA, 0xE7, 0x42, 0x20, 0x8C, 0x24, 0xEB, 0x4D, + 0xEB, 0xBB, 0x8A, 0x2F, 0xEA, 0xFF, 0x00, 0x23, 0x00, 0x2B, 0x96, 0x4B, 0xE0, 0x41, 0xE8, 0xEF, + 0x84, 0x20, 0xEA, 0x70, 0xD5, 0x56, 0x5A, 0x18, 0x22, 0x2B, 0x3C, 0x17, 0xFB, 0x38, 0xE0, 0x27, + 0xE9, 0xE6, 0x9A, 0x79, 0xEA, 0x93, 0xEA, 0xE7, 0x42, 0x20, 0x8C, 0x24, 0x3C, 0xF7, 0xFB, 0x34, + 0x3C, 0x17, 0xFB, 0x36, 0x8A, 0x2F, 0xEA, 0xFF, 0x00, 0x23, 0x00, 0x2D, 0x96, 0x4B, 0xE0, 0x41, + 0xE9, 0x13, 0x3C, 0x17, 0xFB, 0x39, 0x3C, 0x27, 0xFB, 0x37, 0x40, 0x15, 0x84, 0x01, 0xEA, 0x93, + 0xFE, 0x5C, 0x3C, 0x37, 0xFB, 0x35, 0x9A, 0xD3, 0x40, 0x30, 0x8C, 0x76, 0x00, 0x13, 0x00, 0x2E, + 0x96, 0xDB, 0xE0, 0x23, 0xE8, 0xC4, 0x84, 0x27, 0xEA, 0x70, 0xD5, 0x2B, 0x5A, 0x10, 0x02, 0x04, + 0x5A, 0x18, 0x15, 0x28, 0x3C, 0x27, 0xFB, 0x34, 0x3C, 0x17, 0xFB, 0x36, 0xEA, 0xE7, 0x8A, 0x22, + 0xEA, 0x93, 0x42, 0x20, 0x8C, 0x24, 0xEB, 0x4D, 0xEB, 0xBB, 0x8A, 0x2F, 0xEA, 0xFF, 0x00, 0x23, + 0x00, 0x30, 0x96, 0x4B, 0xFE, 0xD4, 0xE0, 0x61, 0xE8, 0x04, 0xEA, 0x8E, 0xEA, 0x70, 0xD5, 0x11, + 0x3C, 0xF7, 0xFB, 0x39, 0x8B, 0x6F, 0x42, 0xF5, 0x80, 0x03, 0x5E, 0xF7, 0x81, 0xF5, 0xE8, 0xF6, + 0x3C, 0x17, 0xFB, 0x38, 0x9A, 0x79, 0x50, 0xF0, 0x80, 0x63, 0x5C, 0xF7, 0x80, 0xC7, 0xE9, 0xEE, + 0xEB, 0x04, 0xC1, 0x04, 0x8E, 0x33, 0xE6, 0x22, 0xE8, 0x22, 0x3C, 0x17, 0xFB, 0x36, 0x3C, 0x37, + 0xFB, 0x34, 0xEB, 0x4D, 0x9A, 0xCB, 0xEB, 0xBB, 0xEB, 0x95, 0x8A, 0x2F, 0xEA, 0x93, 0xFE, 0x54, + 0x95, 0x19, 0x40, 0xF0, 0x91, 0xF6, 0x00, 0x43, 0x00, 0x2C, 0xFF, 0x14, 0xE0, 0x8F, 0xE9, 0x0D, + 0x3C, 0xF7, 0xFB, 0x38, 0x00, 0x13, 0x00, 0x2A, 0x8A, 0xEF, 0x42, 0x73, 0x80, 0x03, 0xFF, 0xD4, + 0x40, 0xF3, 0x8D, 0xF6, 0xE0, 0x2F, 0xE8, 0x03, 0xEA, 0x8E, 0xEA, 0x70, 0xEB, 0x04, 0x5A, 0x18, + 0x05, 0x14, 0x66, 0x10, 0x00, 0x02, 0x5A, 0x18, 0x39, 0x10, 0x50, 0x14, 0x7F, 0xFF, 0x44, 0x22, + 0xD4, 0xBC, 0x3C, 0xF7, 0xFB, 0x38, 0x38, 0x11, 0x06, 0x01, 0x8A, 0x2F, 0x5E, 0xF0, 0x80, 0x41, + 0xE9, 0x03, 0xEA, 0x8E, 0xEA, 0x70, 0xEB, 0x04, 0x54, 0x10, 0x80, 0xFB, 0x5A, 0x18, 0x01, 0x12, + 0x3C, 0xF7, 0xFB, 0x34, 0x3C, 0x17, 0xFB, 0x36, 0x8A, 0x2F, 0x5E, 0xF0, 0x81, 0x40, 0xE9, 0x07, + 0xEB, 0x4D, 0xEB, 0xBB, 0x8A, 0x2F, 0x5E, 0xF0, 0x80, 0xA0, 0xE8, 0x03, 0xEA, 0x8E, 0xEA, 0x70, + 0x2E, 0x17, 0xF6, 0x88, 0xC1, 0x1B, 0xEB, 0x04, 0x5A, 0x18, 0x01, 0x19, 0x5A, 0x08, 0x54, 0x17, + 0x44, 0x02, 0xD4, 0xBC, 0x40, 0x00, 0x20, 0x40, 0x3C, 0xF7, 0xFB, 0x39, 0x02, 0x00, 0x7F, 0xFF, + 0x8A, 0x0F, 0x42, 0xF0, 0x00, 0x03, 0x5E, 0xF7, 0x80, 0x65, 0xE9, 0x08, 0xEA, 0x34, 0xE7, 0x03, + 0xEA, 0x55, 0xE9, 0x0A, 0xD5, 0x77, 0x84, 0x02, 0xEA, 0x7E, 0xE7, 0x03, 0xE8, 0x73, 0x2E, 0x07, + 0xEB, 0x38, 0x5A, 0x08, 0xAA, 0x70, 0x3C, 0x27, 0xFB, 0x3A, 0x02, 0x03, 0x00, 0x0C, 0xE0, 0x40, + 0xE9, 0x67, 0x02, 0x03, 0x00, 0x0D, 0xE0, 0x02, 0xE9, 0x63, 0x3C, 0x17, 0xFB, 0x3B, 0x02, 0x03, + 0x00, 0x0E, 0xE0, 0x20, 0xE9, 0x5D, 0x02, 0x03, 0x00, 0x0F, 0xE0, 0x01, 0xE9, 0x59, 0x3C, 0x47, + 0xFB, 0x39, 0x02, 0x33, 0x00, 0x0B, 0x9A, 0x21, 0xFF, 0x5A, 0xE0, 0x05, 0xE8, 0x15, 0x3C, 0x17, + 0xFB, 0x38, 0xFE, 0xC2, 0x8A, 0x22, 0xEA, 0x93, 0x94, 0x49, 0xE0, 0x61, 0xE9, 0x1F, 0x85, 0xE2, + 0x40, 0x00, 0x3C, 0x16, 0xFE, 0x02, 0xE2, 0x0D, 0xE9, 0x38, 0x2E, 0x07, 0xF6, 0x65, 0xC8, 0x35, + 0x84, 0x09, 0xEA, 0x55, 0xD5, 0x32, 0xE0, 0x60, 0xE8, 0x11, 0x02, 0x03, 0x00, 0x0A, 0x40, 0xF6, + 0x80, 0x06, 0xE8, 0x0C, 0x3C, 0x07, 0xFB, 0x35, 0x8E, 0x2A, 0xE0, 0x01, 0xE9, 0x07, 0x2E, 0x07, + 0xF6, 0x65, 0xC8, 0x04, 0x84, 0x0A, 0xEA, 0x55, 0xD5, 0x20, 0x3C, 0x07, 0xFB, 0x38, 0x02, 0x13, + 0x00, 0x08, 0x8A, 0x02, 0xFE, 0x8A, 0xE0, 0x02, 0xE8, 0x0C, 0x02, 0x03, 0x00, 0x09, 0x40, 0xF6, + 0x00, 0x06, 0xE8, 0x13, 0x2E, 0x07, 0xF6, 0x64, 0xC8, 0x10, 0x84, 0x0B, 0xEA, 0x55, 0xD5, 0x0D, + 0xE0, 0x20, 0xE8, 0x0B, 0x02, 0x03, 0x00, 0x09, 0x40, 0xF6, 0x00, 0x06, 0xE8, 0x06, 0x2E, 0x07, + 0xF6, 0x64, 0xC8, 0x03, 0x84, 0x0C, 0xEA, 0x55, 0x2E, 0x07, 0xEB, 0x38, 0x5A, 0x00, 0xAA, 0x0B, + 0x3C, 0x03, 0xFB, 0x38, 0x3C, 0x08, 0x04, 0x24, 0x3C, 0x48, 0x04, 0x25, 0xD5, 0x03, 0x84, 0x02, + 0xEA, 0x7E, 0x2E, 0x27, 0xEB, 0x38, 0xA4, 0x70, 0x5C, 0xF1, 0x00, 0x20, 0xA4, 0x31, 0xE8, 0x0B, + 0x40, 0x00, 0x06, 0x04, 0x52, 0x21, 0x00, 0x1F, 0x40, 0x00, 0x08, 0x0E, 0x96, 0x04, 0xC8, 0x03, + 0xEA, 0x34, 0xEA, 0x55, 0x42, 0x10, 0xB0, 0x0B, 0xC1, 0x57, 0x2E, 0x07, 0xF6, 0x63, 0x5A, 0x08, + 0x01, 0x25, 0x2E, 0x17, 0xF6, 0x62, 0x02, 0x03, 0x00, 0x1A, 0xE2, 0x20, 0xE8, 0x1E, 0x2E, 0x17, + 0xF6, 0x61, 0x02, 0x03, 0x00, 0x1B, 0xE2, 0x20, 0xE8, 0x18, 0x2E, 0x07, 0xF6, 0x60, 0xC8, 0x15, + 0x3C, 0xF7, 0xFB, 0x2E, 0x3C, 0x07, 0xFB, 0x38, 0x02, 0x13, 0x00, 0x19, 0x8A, 0x0F, 0xEB, 0x39, + 0xE0, 0x01, 0xE8, 0x0B, 0x3C, 0xF7, 0xFB, 0x2F, 0x3C, 0x07, 0xFB, 0x39, 0x8A, 0x0F, 0xEB, 0x39, + 0xE0, 0x01, 0xE8, 0x03, 0x84, 0x03, 0xEA, 0x55, 0xEB, 0x04, 0x84, 0x00, 0x3E, 0x07, 0xF6, 0x61, + 0x5A, 0x10, 0x03, 0x2B, 0x3E, 0x07, 0xF6, 0x63, 0x2E, 0x07, 0xF6, 0x60, 0xC8, 0x25, 0x3C, 0x07, + 0xFB, 0x39, 0x02, 0x13, 0x00, 0x1E, 0xE0, 0x01, 0xE9, 0x1D, 0x02, 0x13, 0x00, 0x1F, 0xE0, 0x20, + 0xE9, 0x19, 0x3C, 0x17, 0xFB, 0x38, 0x02, 0x23, 0x00, 0x1C, 0xE0, 0x22, 0xE9, 0x13, 0x02, 0x23, + 0x00, 0x1D, 0xE0, 0x41, 0xE9, 0x0F, 0x2E, 0x37, 0xF6, 0x62, 0x02, 0x23, 0x00, 0x1A, 0xE2, 0x62, + 0xE8, 0x0B, 0x84, 0x41, 0x3E, 0x27, 0xF6, 0x63, 0x3C, 0x1B, 0xFB, 0x2E, 0x3C, 0x0B, 0xFB, 0x2F, + 0xD5, 0x03, 0x84, 0x02, 0xEA, 0x7E, 0x84, 0x00, 0x3E, 0x07, 0xF6, 0x65, 0x3E, 0x07, 0xF6, 0x64, + 0xD5, 0x05, 0xEB, 0x49, 0xD5, 0x03, 0x84, 0x00, 0xEB, 0x03, 0x84, 0x00, 0x3E, 0x07, 0xF6, 0x8B, + 0x3C, 0x2D, 0xFD, 0x96, 0x3C, 0x03, 0xFB, 0x42, 0x4E, 0x93, 0x00, 0x06, 0x2E, 0x17, 0xF3, 0x56, + 0x5A, 0x18, 0x01, 0x0F, 0xA4, 0x54, 0xE2, 0x01, 0xE8, 0x04, 0x8C, 0x01, 0xEB, 0x75, 0xD5, 0x1F, + 0x84, 0x01, 0x3E, 0x07, 0xF6, 0x8B, 0x84, 0x04, 0xEA, 0x7E, 0xEB, 0x03, 0xD5, 0x18, 0x2E, 0x17, + 0xF6, 0x63, 0x5A, 0x18, 0x01, 0x0E, 0x2E, 0x17, 0xF6, 0x61, 0x02, 0x31, 0x00, 0x1B, 0xE2, 0x23, + 0xE8, 0x05, 0x8C, 0x21, 0x3E, 0x17, 0xF6, 0x61, 0xD5, 0x03, 0x3E, 0x97, 0xF6, 0x63, 0xA4, 0x54, + 0xE2, 0x01, 0xE9, 0x03, 0xEA, 0x34, 0xEA, 0x55, 0x84, 0x00, 0xEB, 0x75, 0x2E, 0x07, 0xF6, 0x3D, + 0xC0, 0x06, 0xFA, 0x06, 0xEA, 0x55, 0x84, 0x00, 0x3E, 0x07, 0xF6, 0x3D, 0xEB, 0x34, 0x5A, 0x08, + 0x01, 0x07, 0x84, 0x0D, 0xEA, 0x55, 0x84, 0x00, 0x3E, 0x07, 0xEE, 0xD7, 0x2E, 0x67, 0xEB, 0x38, + 0x9E, 0x35, 0xE6, 0x02, 0xE9, 0x03, 0x5A, 0x68, 0x01, 0x47, 0x2E, 0x07, 0xF6, 0x89, 0x44, 0x72, + 0xD4, 0xBC, 0x94, 0x01, 0x38, 0xB3, 0x81, 0x01, 0x8C, 0x01, 0x38, 0x93, 0x81, 0x01, 0x84, 0x00, + 0xF8, 0x06, 0x84, 0x01, 0xF8, 0x04, 0x84, 0x02, 0xF8, 0x02, 0x84, 0x03, 0x49, 0xFF, 0xFA, 0x93, + 0x5A, 0x68, 0x06, 0x20, 0x84, 0x00, 0x44, 0x22, 0xE2, 0xB8, 0x98, 0x78, 0x38, 0x31, 0x00, 0x01, + 0xAC, 0xCA, 0x98, 0xC2, 0xA4, 0xD9, 0x8C, 0x04, 0xAC, 0xCB, 0x5A, 0x08, 0x10, 0xF8, 0x3C, 0x0D, + 0xFA, 0xCD, 0x2E, 0x17, 0xF6, 0x89, 0x3C, 0xB8, 0x04, 0x2C, 0x3C, 0x98, 0x04, 0x2D, 0x49, 0xFF, + 0xFA, 0x54, 0x40, 0x00, 0x20, 0x08, 0x58, 0x00, 0x00, 0xFF, 0x3C, 0x08, 0x04, 0x35, 0xD5, 0x16, + 0x5A, 0x68, 0x05, 0x09, 0x3C, 0x00, 0x0B, 0x21, 0x3C, 0x08, 0x04, 0x25, 0x3C, 0x08, 0x04, 0x29, + 0xD5, 0x0D, 0x5A, 0x68, 0x01, 0x09, 0x3C, 0x00, 0x0B, 0x25, 0x3C, 0x08, 0x04, 0x25, 0x3C, 0x08, + 0x04, 0x29, 0xD5, 0x04, 0x5C, 0xF3, 0x00, 0x20, 0xE8, 0x1B, 0x50, 0x23, 0x00, 0x0C, 0x96, 0x90, + 0x84, 0x01, 0xE6, 0x5E, 0xEA, 0x9D, 0x10, 0x25, 0x00, 0x01, 0x84, 0x01, 0xE9, 0x04, 0xFA, 0x2E, + 0xF8, 0x03, 0xD5, 0x04, 0x80, 0x22, 0x49, 0x00, 0x3C, 0x66, 0x84, 0x03, 0xEB, 0x7D, 0x84, 0x00, + 0xEB, 0x03, 0xEA, 0x34, 0xEA, 0x55, 0x44, 0x00, 0x00, 0x60, 0xDD, 0x4A, 0xD5, 0x03, 0x84, 0x00, + 0xEA, 0x9D, 0xFC, 0xE2, 0x92, 0x00, 0x3C, 0x0F, 0xFC, 0x8D, 0xDD, 0x9E, 0xFC, 0x61, 0x80, 0xC2, + 0x84, 0x40, 0x81, 0x40, 0x81, 0x21, 0x2E, 0x07, 0x34, 0xF8, 0xEB, 0x67, 0x80, 0x82, 0x96, 0x50, + 0xE2, 0x20, 0xE8, 0x06, 0x98, 0x53, 0x10, 0x40, 0x81, 0x68, 0x8C, 0x41, 0xD5, 0xF9, 0xEB, 0x22, + 0xFA, 0x4E, 0xEB, 0x31, 0x84, 0x80, 0x80, 0x26, 0xEB, 0xA4, 0x84, 0x60, 0x00, 0x2F, 0x80, 0x07, + 0x80, 0x03, 0x84, 0x9F, 0x96, 0x58, 0xE2, 0x22, 0xE8, 0x10, 0xA1, 0x71, 0x96, 0x59, 0x38, 0x52, + 0x8D, 0x01, 0xD9, 0x09, 0xA0, 0x72, 0x38, 0x10, 0x8D, 0x01, 0xE2, 0x01, 0x40, 0x00, 0xBC, 0x1B, + 0x40, 0x41, 0xBC, 0x1B, 0x8C, 0x61, 0xD5, 0xEF, 0x5A, 0x47, 0xFF, 0x1B, 0xA0, 0x36, 0x95, 0x62, + 0x38, 0x10, 0x12, 0x02, 0xA0, 0x37, 0x3C, 0x7D, 0xFC, 0x8D, 0x38, 0x30, 0x12, 0x02, 0x04, 0x03, + 0x00, 0x08, 0x38, 0x20, 0x12, 0x02, 0xC2, 0x3D, 0x00, 0x03, 0x80, 0x32, 0xFE, 0x0C, 0x40, 0x10, + 0x08, 0x37, 0x00, 0x03, 0x80, 0x33, 0xFE, 0xC4, 0x40, 0x31, 0x88, 0x77, 0xD5, 0x34, 0x84, 0x60, + 0x80, 0x23, 0x80, 0x43, 0x80, 0x03, 0xD5, 0x0E, 0xC2, 0x53, 0x00, 0x43, 0x80, 0x32, 0x42, 0x48, + 0x10, 0x24, 0x40, 0x02, 0x08, 0x17, 0x00, 0x43, 0x80, 0x33, 0x42, 0x48, 0x90, 0x24, 0x40, 0x22, + 0x08, 0x57, 0x00, 0x44, 0x80, 0x00, 0x5A, 0x40, 0x01, 0x05, 0x44, 0x40, 0x00, 0x50, 0xD5, 0x02, + 0xEA, 0xBF, 0x9A, 0x08, 0x42, 0xF0, 0x00, 0x03, 0xE2, 0x8F, 0xE9, 0x05, 0x9A, 0x9A, 0xEB, 0x65, + 0xE2, 0x8F, 0xE8, 0x06, 0xEA, 0x47, 0x3E, 0x07, 0xF6, 0x8C, 0x84, 0x01, 0xD5, 0x08, 0x2E, 0x07, + 0xF6, 0x8C, 0xC0, 0x05, 0x8E, 0x01, 0x3E, 0x07, 0xF6, 0x8C, 0xFC, 0xE1, 0xEA, 0x94, 0xFC, 0xE1, + 0x80, 0x62, 0x80, 0x22, 0xA0, 0x35, 0x84, 0x40, 0x88, 0xA0, 0xA7, 0xAA, 0xA6, 0x2B, 0x82, 0x22, + 0x82, 0x02, 0xE2, 0x06, 0xE9, 0xCA, 0xA7, 0x28, 0x01, 0x32, 0x80, 0x01, 0xE3, 0xE4, 0xE9, 0x16, + 0x01, 0x23, 0x80, 0x02, 0x81, 0x64, 0x42, 0xB3, 0x48, 0x73, 0x82, 0x4B, 0x04, 0xB5, 0x00, 0x05, + 0x41, 0x25, 0xC8, 0x20, 0x03, 0x29, 0x00, 0x00, 0x41, 0x29, 0x00, 0x11, 0xE5, 0xDE, 0xE9, 0x04, + 0x89, 0x84, 0x89, 0xA6, 0x8C, 0x41, 0x8C, 0x81, 0xD5, 0xEA, 0x8C, 0xC1, 0xD5, 0xE3, 0x80, 0x02, + 0xD5, 0xB9, 0xFC, 0x00, 0x80, 0xC0, 0xA0, 0x46, 0xA0, 0x05, 0x84, 0x44, 0x84, 0x6F, 0x84, 0x85, + 0x84, 0xA0, 0x49, 0xFF, 0xCA, 0x21, 0xA0, 0x36, 0xA0, 0x75, 0xDD, 0x5D, 0xFC, 0x80, 0xFC, 0x00, + 0x2E, 0x57, 0x34, 0x20, 0x5A, 0x50, 0x01, 0x04, 0x84, 0x01, 0xFC, 0x80, 0x3C, 0x3D, 0xFC, 0x04, + 0xA6, 0xD9, 0x5A, 0x30, 0x09, 0x04, 0x5A, 0x38, 0x04, 0x19, 0x3C, 0x33, 0x9A, 0x2D, 0x99, 0x4B, + 0xE2, 0x23, 0x97, 0x69, 0xE8, 0x04, 0x9A, 0x59, 0x96, 0x49, 0xD5, 0x02, 0x84, 0x20, 0x2E, 0x47, + 0xEE, 0xFE, 0xA0, 0xC2, 0xA0, 0x03, 0x40, 0x31, 0x90, 0x77, 0x40, 0x00, 0x10, 0x17, 0x96, 0xD9, + 0x96, 0x01, 0x2E, 0x47, 0x34, 0x67, 0xD5, 0x1B, 0x44, 0x33, 0x8D, 0x40, 0xA7, 0x18, 0xCC, 0xDD, + 0x3C, 0x33, 0x9A, 0x2C, 0x99, 0x4B, 0xE2, 0x23, 0x97, 0x69, 0xE8, 0x04, 0x9A, 0x59, 0x96, 0x49, + 0xD5, 0x02, 0x80, 0x24, 0x2E, 0x67, 0xEE, 0xDA, 0xB4, 0x60, 0xA0, 0x01, 0x40, 0x31, 0x98, 0x77, + 0x40, 0x00, 0x18, 0x17, 0x2E, 0x47, 0x34, 0x66, 0x96, 0xD9, 0x96, 0x01, 0x44, 0xF0, 0x02, 0x00, + 0x42, 0x52, 0xBC, 0x01, 0xE2, 0xA3, 0xE8, 0x05, 0xA6, 0x10, 0x8C, 0x01, 0xAE, 0x10, 0xD5, 0x05, + 0xE2, 0x01, 0xE9, 0xFB, 0x84, 0x00, 0xAE, 0x10, 0xDD, 0x41, 0xA6, 0x01, 0x5A, 0x08, 0x04, 0x04, + 0x84, 0x00, 0xAE, 0x10, 0xA6, 0x10, 0xE2, 0x80, 0xE8, 0xB0, 0x84, 0x00, 0xAE, 0x10, 0x2E, 0x07, + 0xF3, 0x75, 0x8C, 0x01, 0x3E, 0x07, 0xF3, 0x75, 0x84, 0x02, 0xFC, 0x80, 0xFC, 0x20, 0x05, 0x00, + 0x80, 0x13, 0x00, 0x6F, 0x80, 0x18, 0x01, 0x1F, 0x80, 0x1C, 0x55, 0x08, 0x7F, 0xFF, 0xCA, 0x10, + 0x83, 0x81, 0xBE, 0x12, 0x44, 0x22, 0x01, 0x68, 0xB9, 0x13, 0x54, 0x63, 0x7F, 0xFF, 0x40, 0x61, + 0x18, 0x40, 0x54, 0x20, 0xFF, 0xFF, 0xA6, 0x74, 0x96, 0x48, 0xCB, 0x16, 0xD5, 0x24, 0x44, 0x72, + 0x00, 0x00, 0x41, 0x03, 0xC0, 0x40, 0x45, 0x20, 0x00, 0x64, 0xE2, 0xD1, 0xE8, 0xEA, 0x80, 0xF0, + 0x42, 0x73, 0x48, 0x73, 0x51, 0x33, 0x80, 0x64, 0x18, 0x23, 0x80, 0x01, 0x4C, 0x79, 0xFF, 0xFE, + 0x8C, 0xC1, 0x97, 0xB0, 0xD5, 0xF3, 0x44, 0x60, 0x00, 0x64, 0xFE, 0x74, 0x40, 0x10, 0x88, 0x40, + 0x44, 0x62, 0x00, 0x64, 0x44, 0x22, 0x00, 0x00, 0x88, 0x41, 0x88, 0x26, 0x18, 0x31, 0x00, 0x01, + 0x4C, 0x20, 0xFF, 0xFE, 0xAD, 0x00, 0xAD, 0x41, 0xFC, 0xA0, 0xFC, 0x60, 0x81, 0xA0, 0xF0, 0x0E, + 0x81, 0x22, 0x81, 0x83, 0x81, 0x64, 0x81, 0x45, 0x5A, 0x00, 0x01, 0x1C, 0x80, 0xC1, 0xDD, 0x43, + 0x5A, 0x08, 0x02, 0x0F, 0x3C, 0x5C, 0x01, 0xB6, 0x4C, 0x56, 0x80, 0x0B, 0x44, 0x02, 0xD6, 0x08, + 0x38, 0x20, 0x18, 0x00, 0x44, 0x02, 0xD4, 0x8C, 0x38, 0x00, 0x18, 0x00, 0xD5, 0x0C, 0x44, 0x02, + 0xD9, 0x5C, 0x38, 0x20, 0x18, 0x00, 0x44, 0x02, 0xD6, 0x28, 0x38, 0x00, 0x18, 0x00, 0xD5, 0x03, + 0x84, 0x02, 0x84, 0x49, 0x83, 0x8D, 0xB9, 0x12, 0xBF, 0x14, 0x54, 0x60, 0xFF, 0xFF, 0xFA, 0x38, + 0xFE, 0x54, 0x44, 0x32, 0x00, 0x00, 0x40, 0x10, 0x98, 0x40, 0x40, 0x63, 0xC0, 0x09, 0x88, 0x23, + 0x54, 0x73, 0x7F, 0xFF, 0x44, 0x60, 0x00, 0x60, 0xFF, 0x84, 0xA6, 0x0F, 0x10, 0x06, 0x00, 0x00, + 0xA6, 0x0E, 0xEB, 0x17, 0xA6, 0x0C, 0xEA, 0x9D, 0x02, 0x06, 0x80, 0x30, 0x02, 0x20, 0x80, 0x0D, + 0x40, 0x63, 0x1C, 0x40, 0x88, 0x40, 0xF0, 0x0C, 0x40, 0x21, 0x88, 0x20, 0xB6, 0x40, 0x02, 0x06, + 0x80, 0x30, 0x02, 0x10, 0x80, 0x0C, 0x88, 0xC3, 0x88, 0x01, 0xF1, 0x0D, 0xEB, 0x9F, 0xB6, 0x01, + 0xB4, 0x06, 0x92, 0x0A, 0x96, 0x37, 0xEA, 0x94, 0xFC, 0xE0, 0xFC, 0x40, 0x83, 0x80, 0xBD, 0x14, + 0xB8, 0x14, 0x44, 0x60, 0x00, 0x48, 0x54, 0x52, 0xFF, 0xFF, 0xEA, 0x87, 0xFE, 0xF4, 0xFF, 0x34, + 0x40, 0x42, 0x00, 0x40, 0x40, 0x31, 0x94, 0x40, 0x44, 0x52, 0x00, 0x00, 0x88, 0xA4, 0x84, 0x00, + 0x8A, 0x64, 0x38, 0x61, 0x94, 0x00, 0x38, 0x60, 0x81, 0x09, 0x08, 0x62, 0x80, 0x01, 0x38, 0x61, + 0x01, 0x09, 0x8C, 0x01, 0x5A, 0x08, 0x32, 0xF7, 0x44, 0x02, 0x00, 0x34, 0x88, 0x80, 0x84, 0xA0, + 0x85, 0x23, 0x39, 0x31, 0x90, 0x02, 0x41, 0x10, 0x94, 0x00, 0x0D, 0x22, 0x00, 0x01, 0x41, 0x01, + 0x14, 0x00, 0x84, 0xE0, 0x42, 0x03, 0xA4, 0x24, 0x02, 0xA8, 0x80, 0x00, 0x40, 0x69, 0x80, 0x0D, + 0x97, 0x97, 0x40, 0x65, 0x19, 0x00, 0x1A, 0x68, 0x80, 0x01, 0x40, 0x09, 0x00, 0x0D, 0x02, 0x68, + 0x00, 0x00, 0x96, 0x17, 0x40, 0x03, 0x01, 0x00, 0x8C, 0xE1, 0x1A, 0x08, 0x00, 0x01, 0x5A, 0x78, + 0x0A, 0xEB, 0x8C, 0xB4, 0x5A, 0x58, 0x64, 0xDF, 0xFC, 0xC0, 0x04, 0x00, 0x00, 0x13, 0xEA, 0xC1, + 0xFE, 0xE4, 0xEA, 0x87, 0x40, 0x01, 0x80, 0x40, 0x44, 0x32, 0x00, 0x00, 0x88, 0x60, 0x84, 0x00, + 0x99, 0x08, 0xA7, 0x61, 0x38, 0x40, 0x80, 0x00, 0x40, 0x42, 0x40, 0x08, 0x40, 0x42, 0x17, 0x00, + 0x99, 0x50, 0xA7, 0x69, 0x40, 0x42, 0x15, 0x00, 0x38, 0x51, 0x00, 0x00, 0x8C, 0x02, 0x88, 0x85, + 0xAB, 0x19, 0x5A, 0x08, 0x32, 0xEF, 0xDD, 0x9E, 0x04, 0x00, 0x00, 0x13, 0xEA, 0xC1, 0xEA, 0x87, + 0xFE, 0xE4, 0x40, 0x31, 0x80, 0x40, 0xEB, 0x3D, 0x88, 0x60, 0x84, 0x00, 0xA5, 0x19, 0x38, 0x40, + 0x80, 0x08, 0xA7, 0x5B, 0x99, 0x08, 0xAF, 0x61, 0xB4, 0x83, 0x38, 0x41, 0x00, 0x08, 0xA3, 0x19, + 0x99, 0x50, 0x92, 0x88, 0x8C, 0x02, 0xAF, 0x29, 0x5A, 0x08, 0x32, 0xF2, 0xDD, 0x9E, 0xE2, 0x01, + 0xE8, 0x0A, 0xA6, 0x10, 0xE2, 0x60, 0xE8, 0x04, 0x9A, 0xC3, 0xAE, 0xD0, 0xDD, 0x9E, 0x84, 0x00, + 0xAE, 0x10, 0xDD, 0x9E, 0xE2, 0x20, 0xE8, 0x0B, 0xA6, 0x10, 0x52, 0xF1, 0x80, 0xFF, 0xE0, 0x0F, + 0xE8, 0x04, 0x88, 0x60, 0xAE, 0xD0, 0xDD, 0x9E, 0x84, 0x1F, 0xAE, 0x10, 0xDD, 0x9E, 0xFC, 0x60, + 0xEE, 0xA8, 0x80, 0xE0, 0x81, 0x41, 0xF2, 0x84, 0x81, 0x23, 0x5A, 0x38, 0x01, 0x05, 0x3C, 0x80, + 0x0B, 0x29, 0xD5, 0x0A, 0xDD, 0x43, 0x5A, 0x00, 0x02, 0x06, 0x5A, 0x78, 0x08, 0x04, 0x48, 0x00, + 0x00, 0xA5, 0x3C, 0x80, 0x0B, 0x28, 0x2E, 0x27, 0xEF, 0x79, 0x84, 0xC1, 0xE6, 0x42, 0xE9, 0x05, + 0x8E, 0x41, 0x40, 0x63, 0x08, 0x0C, 0x97, 0xB0, 0x40, 0x63, 0x28, 0x0E, 0x97, 0xB0, 0xCE, 0x02, + 0x84, 0xC1, 0xB0, 0x0A, 0x50, 0xBF, 0x80, 0x24, 0x50, 0x5F, 0x80, 0x21, 0xF0, 0x81, 0x14, 0x9F, + 0x80, 0x02, 0xF0, 0x04, 0x80, 0x27, 0xB0, 0x88, 0x50, 0x3F, 0x80, 0x22, 0x50, 0x4F, 0x80, 0x23, + 0xB7, 0x7F, 0x49, 0xFF, 0xFE, 0xDC, 0xF0, 0x04, 0xB0, 0x64, 0xB0, 0xBD, 0x00, 0x3F, 0x80, 0x22, + 0x00, 0x4F, 0x80, 0x23, 0x49, 0xFF, 0xFF, 0x2B, 0xF8, 0x6F, 0x49, 0xFF, 0xFF, 0x8F, 0xB0, 0x24, + 0x81, 0x20, 0xB0, 0x0B, 0x83, 0x80, 0x85, 0x80, 0x44, 0xD0, 0x00, 0x32, 0x38, 0x55, 0xB2, 0x02, + 0x44, 0x00, 0x65, 0x10, 0x99, 0x28, 0x44, 0x00, 0x73, 0xE8, 0x40, 0xE2, 0x80, 0x00, 0x42, 0x06, + 0x34, 0x24, 0xF0, 0x85, 0x84, 0xE0, 0x39, 0x04, 0x9D, 0x01, 0x5C, 0xF8, 0x07, 0xFF, 0xE8, 0x49, + 0x2E, 0x17, 0xEF, 0x7A, 0x39, 0x32, 0xC1, 0x01, 0x00, 0x3F, 0x80, 0x20, 0x8E, 0x21, 0x40, 0x28, + 0x04, 0x08, 0x40, 0x09, 0x8C, 0x16, 0x4C, 0xA0, 0xC0, 0x15, 0x88, 0x44, 0xA4, 0x50, 0x8A, 0x08, + 0x40, 0x30, 0x8C, 0x76, 0x8A, 0x68, 0xEA, 0xE3, 0x42, 0xF0, 0x00, 0x03, 0xE0, 0x6F, 0xE9, 0x04, + 0x13, 0x31, 0x00, 0x00, 0xD5, 0x2E, 0x38, 0x07, 0x41, 0x01, 0x38, 0x0E, 0x1C, 0x08, 0xD5, 0x29, + 0x4E, 0xA3, 0x00, 0x06, 0x39, 0x32, 0x41, 0x09, 0xF8, 0x10, 0xD5, 0x16, 0x88, 0x44, 0xA4, 0x50, + 0x40, 0x30, 0x8C, 0x76, 0x40, 0x10, 0x20, 0x01, 0x8A, 0x68, 0xEA, 0xE3, 0x42, 0xF0, 0x80, 0x03, + 0xE0, 0x6F, 0xE9, 0x0A, 0x13, 0x31, 0x00, 0x00, 0x38, 0x14, 0x9D, 0x01, 0x38, 0x2E, 0x1C, 0x00, + 0x38, 0x27, 0x05, 0x09, 0x83, 0xFF, 0xF1, 0x05, 0xB0, 0xCB, 0x98, 0xB9, 0x88, 0x43, 0x96, 0x01, + 0x80, 0x28, 0x80, 0x66, 0xF4, 0x87, 0xF5, 0x86, 0x49, 0xFF, 0xFF, 0x4B, 0xF4, 0x07, 0xF5, 0x06, + 0x8C, 0xE1, 0x5A, 0x78, 0x32, 0xB2, 0x50, 0x94, 0x80, 0x64, 0x51, 0xCE, 0x00, 0x32, 0x5A, 0xC0, + 0x01, 0x04, 0x85, 0x81, 0xD5, 0x9C, 0xF0, 0x04, 0xB0, 0x4B, 0x50, 0x2F, 0x80, 0x5E, 0x00, 0x3F, + 0x80, 0x21, 0x83, 0xFF, 0x49, 0xFF, 0xFE, 0xFB, 0xED, 0x58, 0xFC, 0xE0, 0xFC, 0x61, 0xB6, 0x1F, + 0x84, 0x01, 0xF1, 0x81, 0x81, 0x82, 0x80, 0xE3, 0xEA, 0x6F, 0xDD, 0x43, 0x5A, 0x00, 0x02, 0x07, + 0x84, 0x01, 0x49, 0x00, 0x13, 0xA9, 0x84, 0x00, 0xEA, 0x65, 0xDD, 0x51, 0x84, 0x01, 0xAE, 0x08, + 0xDD, 0x50, 0xAE, 0x08, 0x84, 0x00, 0x3C, 0x0F, 0xFC, 0x7C, 0x2E, 0x07, 0xF3, 0x7B, 0x5A, 0x08, + 0x01, 0x06, 0x84, 0x07, 0x3E, 0x07, 0xEF, 0x79, 0xD5, 0x0C, 0x5A, 0x78, 0x01, 0x07, 0x2E, 0x07, + 0x34, 0x61, 0x3E, 0x07, 0xEF, 0x79, 0xD5, 0x05, 0x2E, 0x07, 0x34, 0x60, 0x3E, 0x07, 0xEF, 0x79, + 0x2E, 0x07, 0xEF, 0x79, 0x8C, 0x01, 0x3E, 0x07, 0xEF, 0x7A, 0x44, 0x00, 0x00, 0x60, 0xDD, 0x57, + 0xDD, 0x43, 0x5A, 0x08, 0x02, 0x6E, 0x5A, 0x78, 0x01, 0x07, 0x44, 0x13, 0xF4, 0x23, 0xEA, 0x50, + 0xEA, 0x48, 0xD5, 0x04, 0x44, 0xA2, 0xB7, 0x38, 0xD5, 0x08, 0xA6, 0x08, 0x5A, 0x00, 0x02, 0x04, + 0xAE, 0xD0, 0xD5, 0xFC, 0x44, 0xA2, 0xBB, 0x93, 0x44, 0x00, 0x00, 0x61, 0xDD, 0x57, 0x84, 0xC0, + 0x44, 0xE3, 0xF0, 0x4A, 0x85, 0x01, 0x2E, 0x07, 0xEF, 0x7A, 0xE2, 0xC0, 0x4E, 0xF2, 0x00, 0x97, + 0x84, 0x00, 0x3E, 0x07, 0xEF, 0x0B, 0xEA, 0x40, 0xEB, 0x77, 0x5A, 0x70, 0x01, 0x08, 0x44, 0x00, + 0x00, 0x62, 0x85, 0x20, 0xDD, 0x57, 0x80, 0x09, 0xD5, 0x25, 0x80, 0x07, 0xEA, 0x30, 0xEA, 0x43, + 0xC0, 0xFF, 0xD5, 0xF6, 0xC1, 0x37, 0x2E, 0x27, 0xEF, 0x0B, 0xE3, 0x22, 0xE8, 0xFC, 0x40, 0xB5, + 0x00, 0x00, 0x00, 0x15, 0x80, 0x00, 0x50, 0xD0, 0x00, 0x01, 0xE6, 0x25, 0xE8, 0x16, 0x50, 0x24, + 0x80, 0x01, 0x54, 0x91, 0x00, 0xFF, 0xC9, 0x0A, 0xE6, 0x0F, 0xE9, 0x69, 0x8E, 0x0E, 0x96, 0x00, + 0x80, 0x26, 0x3C, 0x2D, 0xFC, 0x20, 0x80, 0x67, 0xF8, 0x66, 0xC7, 0x0D, 0x54, 0x06, 0x80, 0xFF, + 0xC7, 0x11, 0x40, 0x10, 0x30, 0x06, 0xD5, 0xDF, 0x5C, 0xF0, 0x00, 0x20, 0xE8, 0xF7, 0x54, 0x06, + 0x80, 0xFF, 0xD5, 0xDE, 0xEB, 0xB8, 0x5A, 0x08, 0x01, 0xF3, 0x80, 0x06, 0x49, 0x00, 0x26, 0xE3, + 0xD5, 0xEE, 0x5A, 0x08, 0x0D, 0xF0, 0xDD, 0x50, 0x8C, 0xC1, 0x10, 0x80, 0x80, 0x00, 0x97, 0xB0, + 0xD5, 0xE9, 0xDD, 0x4B, 0x8C, 0xC1, 0x97, 0xB0, 0x10, 0x80, 0x00, 0x00, 0xD5, 0xAD, 0x46, 0xA0, + 0x01, 0x24, 0x84, 0xC0, 0x44, 0xB3, 0xF0, 0x4A, 0x44, 0x80, 0x00, 0x55, 0x85, 0xA1, 0x50, 0xA5, + 0x0F, 0x80, 0x2E, 0x07, 0xEF, 0x7A, 0xE2, 0xC0, 0xE8, 0x39, 0x10, 0x85, 0x80, 0x00, 0x49, 0xFF, + 0xCC, 0xF3, 0x44, 0x00, 0x00, 0x61, 0xDD, 0x57, 0x5A, 0x78, 0x01, 0x05, 0xB4, 0x1F, 0xEB, 0xF2, + 0xD5, 0x06, 0xDD, 0x41, 0x84, 0x20, 0xDD, 0x53, 0x49, 0x00, 0x29, 0x2D, 0x44, 0x00, 0x00, 0x62, + 0xDD, 0x57, 0x85, 0x20, 0x4C, 0x96, 0x00, 0x0C, 0x80, 0x09, 0x80, 0x26, 0xF2, 0x01, 0x80, 0x67, + 0xF8, 0x1A, 0x50, 0x54, 0x80, 0x01, 0x54, 0x92, 0x80, 0xFF, 0xD5, 0xF5, 0xDD, 0x4B, 0x8C, 0xC1, + 0x54, 0x93, 0x00, 0xFF, 0x10, 0xD0, 0x00, 0x00, 0x5A, 0x78, 0x01, 0x06, 0x2E, 0x67, 0xEF, 0x7A, + 0x4C, 0x93, 0x3F, 0xD1, 0x80, 0x0A, 0xEA, 0xFE, 0x80, 0xC9, 0xD5, 0xCC, 0x80, 0x26, 0x3C, 0x2D, + 0xFC, 0x20, 0x80, 0x67, 0x49, 0xFF, 0xFE, 0x65, 0xD5, 0x99, 0x84, 0x00, 0xEA, 0x6F, 0x84, 0x00, + 0xFC, 0xE1, 0xFC, 0x21, 0x2E, 0x07, 0xF3, 0x7B, 0xC8, 0x06, 0x3C, 0x23, 0x9A, 0x31, 0x3C, 0x33, + 0x9A, 0x32, 0xD5, 0x04, 0x44, 0x30, 0x00, 0x80, 0x80, 0x43, 0x2E, 0x07, 0x33, 0xB7, 0x84, 0xC0, + 0xEB, 0x48, 0x3C, 0x43, 0x9A, 0x2C, 0x3C, 0x53, 0x9A, 0x2D, 0xF0, 0x81, 0x96, 0x90, 0x44, 0x02, + 0xE2, 0xC8, 0x96, 0xD8, 0xB6, 0xDF, 0x49, 0xFF, 0xFD, 0x13, 0xDD, 0x43, 0x80, 0xE0, 0xEB, 0x48, + 0xDD, 0x41, 0x5A, 0x78, 0x02, 0x19, 0xFA, 0x4C, 0x80, 0x66, 0xF8, 0x22, 0xEB, 0x99, 0x5A, 0x00, + 0x01, 0x49, 0xDD, 0x41, 0x84, 0x25, 0xAE, 0x41, 0x84, 0x21, 0x3E, 0x17, 0xF2, 0xC6, 0x3E, 0x77, + 0xF2, 0xE3, 0xEA, 0x3E, 0x84, 0x41, 0xDD, 0x41, 0xEB, 0x48, 0x80, 0x62, 0xF8, 0x11, 0x3E, 0x67, + 0xF2, 0xC6, 0xD5, 0x1A, 0x2E, 0x27, 0x33, 0xB7, 0x80, 0x66, 0xF8, 0x0A, 0xDD, 0x41, 0x84, 0x29, + 0xAE, 0x41, 0xEB, 0x54, 0xEA, 0x3E, 0x84, 0x41, 0xEB, 0x48, 0x80, 0x62, 0xDD, 0x41, 0x49, 0xFF, + 0xFE, 0xCF, 0xDD, 0x41, 0x80, 0x26, 0xDD, 0x53, 0xDD, 0x41, 0x84, 0x2A, 0xAE, 0x41, 0x84, 0x21, + 0x3E, 0x17, 0xF3, 0x70, 0xEA, 0x3E, 0x84, 0x03, 0xEB, 0x43, 0x84, 0x07, 0xDD, 0x57, 0x84, 0x00, + 0x3E, 0x07, 0xF3, 0x7B, 0xDD, 0x43, 0x5A, 0x08, 0x02, 0x06, 0xDD, 0x41, 0x84, 0x2D, 0xAE, 0x41, + 0xD5, 0x0B, 0xDD, 0x41, 0x84, 0x20, 0xDD, 0x53, 0x2E, 0x17, 0xEF, 0x3D, 0xDD, 0x41, 0x5A, 0x18, + 0x02, 0x03, 0x84, 0x2A, 0xAE, 0x41, 0xDD, 0x41, 0xEA, 0x3E, 0x44, 0x00, 0x00, 0x6F, 0xDD, 0x57, + 0xFC, 0xA1, 0xFC, 0x20, 0xEE, 0xB0, 0xB0, 0xC8, 0xB1, 0x87, 0x50, 0x5F, 0x80, 0x19, 0xF3, 0x81, + 0xF2, 0x82, 0x50, 0x3F, 0x80, 0x1A, 0xB0, 0x86, 0x50, 0x4F, 0x80, 0x1B, 0xB6, 0xDF, 0xF0, 0x85, + 0x49, 0xFF, 0xFC, 0xED, 0x00, 0x4F, 0x80, 0x1B, 0xF0, 0x05, 0xB0, 0x62, 0xB0, 0xBB, 0x00, 0x3F, + 0x80, 0x1A, 0x49, 0xFF, 0xFD, 0x3C, 0xF0, 0x05, 0x00, 0x3F, 0x80, 0x19, 0xB0, 0x49, 0x50, 0x2F, + 0x80, 0x56, 0x49, 0xFF, 0xFD, 0x9B, 0x84, 0x00, 0xEA, 0xE7, 0xEA, 0xBF, 0xB0, 0x49, 0x42, 0x10, + 0x10, 0x73, 0xB1, 0xE2, 0x82, 0x01, 0x38, 0x53, 0x02, 0x02, 0x42, 0x70, 0x0C, 0x73, 0x84, 0x20, + 0x38, 0x23, 0x85, 0x01, 0x5C, 0xF1, 0x07, 0xFF, 0xE8, 0x05, 0x39, 0x18, 0x04, 0x00, 0x39, 0x12, + 0x89, 0x09, 0x8C, 0x21, 0x5A, 0x18, 0x32, 0xF6, 0x5A, 0x00, 0x01, 0x04, 0x84, 0x01, 0xD5, 0xE7, + 0xED, 0x50, 0xFC, 0xA0, 0xFC, 0x61, 0xEA, 0x68, 0x81, 0x20, 0xFA, 0x21, 0x84, 0x04, 0xDD, 0x44, + 0x84, 0x04, 0xFA, 0x22, 0xDD, 0x44, 0xEA, 0xB5, 0x3C, 0xBD, 0xFC, 0x2B, 0x3C, 0x0F, 0xFC, 0x2B, + 0xDD, 0x40, 0xC0, 0x04, 0x44, 0x00, 0x00, 0x40, 0xEA, 0x91, 0x84, 0x04, 0xFA, 0x23, 0xDD, 0x44, + 0x84, 0xC0, 0x3C, 0xAC, 0x01, 0xB6, 0x9D, 0xF1, 0x97, 0xF8, 0x50, 0x2F, 0x80, 0x06, 0x80, 0x07, + 0x80, 0x2A, 0xEB, 0x31, 0x49, 0xFF, 0xAA, 0xAF, 0x00, 0x2F, 0x80, 0x06, 0x8E, 0x41, 0xE6, 0x48, + 0xE9, 0x05, 0x80, 0xC7, 0x5A, 0x78, 0x20, 0xF1, 0xD5, 0x09, 0x80, 0x0A, 0x80, 0x26, 0x84, 0x40, + 0xF8, 0x08, 0x00, 0x0F, 0x80, 0x06, 0x5A, 0x08, 0x08, 0xF6, 0xEB, 0xAD, 0x84, 0x20, 0x84, 0x41, + 0x49, 0xFF, 0xFF, 0x89, 0x84, 0x04, 0xFA, 0x24, 0xDD, 0x44, 0xDD, 0x40, 0xC8, 0x1B, 0xEB, 0xD3, + 0x80, 0x41, 0x44, 0x30, 0x0C, 0x80, 0x84, 0x02, 0xDD, 0x42, 0x44, 0x13, 0x1F, 0x40, 0x80, 0x41, + 0xDD, 0x59, 0x84, 0x02, 0xDD, 0x42, 0x44, 0x00, 0x00, 0x40, 0xEA, 0x91, 0x84, 0x02, 0x44, 0x12, + 0x98, 0x8A, 0x44, 0x22, 0x16, 0x80, 0x44, 0x30, 0x06, 0x40, 0xDD, 0x42, 0x44, 0x00, 0x00, 0x44, + 0xEA, 0x91, 0x84, 0x04, 0xFA, 0x25, 0xDD, 0x44, 0xDD, 0x40, 0xC0, 0x0E, 0xEA, 0x4A, 0x44, 0x13, + 0x73, 0xE8, 0xDD, 0x5D, 0x44, 0x03, 0x1F, 0x40, 0x44, 0x13, 0x8D, 0xD4, 0xEA, 0xC8, 0xEA, 0x73, + 0x44, 0x00, 0x00, 0x44, 0xEA, 0x91, 0x84, 0x04, 0xFA, 0x26, 0xDD, 0x44, 0x3C, 0xBF, 0xFC, 0x2B, + 0xDD, 0x40, 0xC8, 0x04, 0xEA, 0x21, 0xDD, 0x5B, 0xD5, 0x05, 0xEA, 0x61, 0xEA, 0x28, 0xEA, 0x36, + 0xD5, 0x07, 0x00, 0x04, 0x80, 0x51, 0x5A, 0x00, 0xBB, 0x04, 0xAE, 0x88, 0xD5, 0xFB, 0xEA, 0x75, + 0xDD, 0x40, 0xC0, 0x04, 0xEA, 0x7C, 0xEB, 0xD3, 0xDD, 0x5D, 0xDD, 0x40, 0xC8, 0x05, 0x10, 0x04, + 0x80, 0x50, 0x84, 0x01, 0xEA, 0xAF, 0xFC, 0xE1, 0xFC, 0x00, 0xDD, 0x43, 0x5A, 0x08, 0x02, 0x2E, + 0x49, 0xFF, 0xEC, 0x01, 0x84, 0x09, 0xEA, 0x60, 0x84, 0x01, 0xEA, 0x6F, 0xDD, 0x47, 0xDD, 0x45, + 0xAE, 0x40, 0xDD, 0x51, 0xA6, 0x08, 0xC8, 0xFF, 0x84, 0x04, 0xEB, 0x43, 0xDD, 0x4B, 0x84, 0x21, + 0xAE, 0x40, 0xDD, 0x51, 0xA6, 0x08, 0x5A, 0x08, 0x01, 0xFF, 0xDD, 0x40, 0xC0, 0x0D, 0xDD, 0x47, + 0xDD, 0x45, 0xAE, 0x40, 0xEA, 0x67, 0x5A, 0x08, 0x06, 0xFF, 0xEA, 0x4A, 0xEB, 0x45, 0xFA, 0x50, + 0xEA, 0xF2, 0xF8, 0x19, 0xD5, 0x04, 0xDD, 0x51, 0xA6, 0x08, 0xC8, 0xFF, 0xDD, 0x4B, 0x84, 0x22, + 0xAE, 0x40, 0x84, 0x00, 0xEA, 0x6F, 0xD5, 0x11, 0xEB, 0x19, 0xEA, 0xF4, 0xEA, 0xFE, 0x49, 0xFF, + 0xCB, 0x4B, 0xDD, 0x41, 0x84, 0x20, 0xDD, 0x53, 0x49, 0x00, 0x27, 0x8D, 0xEA, 0x4A, 0xEB, 0x45, + 0xFA, 0x50, 0xEA, 0xF2, 0x49, 0xFF, 0xC4, 0xDB, 0x44, 0x00, 0x00, 0x65, 0xDD, 0x57, 0xFC, 0x80, + 0xFC, 0x24, 0x44, 0x21, 0x6E, 0x00, 0xEB, 0xC1, 0x44, 0x41, 0x6E, 0x10, 0xB0, 0x84, 0x3B, 0x0F, + 0xCC, 0x20, 0x3B, 0x02, 0x4C, 0x00, 0x3B, 0x01, 0x4C, 0x20, 0x39, 0x01, 0x02, 0x02, 0x44, 0x21, + 0xE4, 0x80, 0x40, 0x21, 0x00, 0x40, 0xA7, 0x90, 0x80, 0xE1, 0x97, 0xB0, 0x38, 0x1F, 0x82, 0x02, + 0x84, 0x80, 0x45, 0x13, 0x65, 0x10, 0x45, 0x22, 0x62, 0x38, 0xEA, 0xFC, 0xE2, 0x82, 0xE8, 0x19, + 0x94, 0xE1, 0x40, 0x21, 0xC4, 0x00, 0x03, 0x31, 0x00, 0x00, 0x40, 0x21, 0xC8, 0x00, 0x99, 0x4B, + 0xA4, 0x90, 0x38, 0x38, 0x10, 0x00, 0x8C, 0x81, 0xFE, 0x9C, 0xA4, 0xE8, 0x40, 0x21, 0x18, 0x0E, + 0x8A, 0x53, 0x96, 0x93, 0x40, 0x21, 0x1C, 0x56, 0x88, 0x43, 0xAC, 0xA8, 0x97, 0x21, 0xD5, 0xE6, + 0x44, 0x20, 0x0C, 0x80, 0x44, 0x31, 0xB2, 0x80, 0x42, 0x30, 0x08, 0x73, 0x80, 0x03, 0x49, 0xFF, + 0x9F, 0xD7, 0xFC, 0xA4, 0xFC, 0x62, 0x3C, 0x0D, 0xA8, 0x6A, 0x84, 0xC0, 0xF0, 0x83, 0x84, 0x01, + 0xEA, 0xE9, 0x3E, 0x67, 0xEE, 0xF0, 0x81, 0x66, 0xEA, 0x6F, 0x81, 0x46, 0x81, 0x26, 0x85, 0x05, + 0x85, 0x87, 0x50, 0xDF, 0x80, 0x0C, 0x97, 0xF0, 0x5A, 0x78, 0x03, 0x0D, 0x84, 0x00, 0x80, 0x40, + 0xDD, 0x5A, 0xEA, 0x5E, 0x3E, 0xC7, 0xF2, 0xE3, 0xEB, 0x3E, 0x84, 0x00, 0xEA, 0x49, 0x85, 0xC1, + 0xD5, 0x0E, 0x80, 0x07, 0x3E, 0x87, 0xF2, 0xE3, 0xF8, 0x45, 0x9C, 0xB9, 0x81, 0xC0, 0xDD, 0x5A, + 0x84, 0x03, 0x96, 0x90, 0xEA, 0x5E, 0xEB, 0x3E, 0x84, 0x03, 0xEA, 0x49, 0xDD, 0x4B, 0x84, 0x21, + 0x40, 0x77, 0x24, 0x00, 0xAE, 0x40, 0x97, 0xF8, 0x4C, 0x93, 0x80, 0x2C, 0xDD, 0x58, 0xA6, 0x40, + 0xC9, 0xFF, 0xE3, 0x49, 0xE8, 0x0F, 0x80, 0x0B, 0xF8, 0x2D, 0xF0, 0x81, 0x50, 0x05, 0x00, 0x01, + 0x54, 0xA0, 0x00, 0xFF, 0xDD, 0x40, 0x5A, 0x08, 0x01, 0x06, 0x80, 0x0B, 0xF1, 0x01, 0x49, 0xFF, + 0xFF, 0x79, 0xDD, 0x40, 0xC0, 0x07, 0xEA, 0x67, 0x5A, 0x08, 0x06, 0xFF, 0xEA, 0x4A, 0xEA, 0x86, + 0xDD, 0x5D, 0xDD, 0x51, 0xA6, 0x08, 0x96, 0x00, 0x5A, 0x08, 0x01, 0xFE, 0xDD, 0x50, 0xAE, 0x08, + 0x49, 0x00, 0x1A, 0x13, 0x50, 0x04, 0x80, 0x01, 0x38, 0xB3, 0x34, 0x00, 0xEB, 0x2D, 0xD5, 0xD5, + 0x8C, 0xC1, 0x5A, 0x68, 0x04, 0xB2, 0xDD, 0x51, 0xA6, 0x08, 0xC8, 0xFF, 0xE3, 0x47, 0xE8, 0x0C, + 0x80, 0x0B, 0x49, 0x00, 0x20, 0x2A, 0xF0, 0x81, 0xDD, 0x40, 0x5A, 0x08, 0x01, 0x06, 0x80, 0x0B, + 0xF1, 0x01, 0x49, 0xFF, 0xFF, 0x4F, 0xDD, 0x51, 0xA6, 0x08, 0x5A, 0x08, 0x01, 0xFF, 0x84, 0x00, + 0xEA, 0x6F, 0x84, 0x00, 0xFC, 0xE2, 0xFC, 0x45, 0x44, 0x21, 0x6E, 0x24, 0x44, 0x72, 0x00, 0x00, + 0xEB, 0xC1, 0xB0, 0x42, 0x44, 0x21, 0x6E, 0x34, 0x3B, 0x00, 0xCC, 0x20, 0xEB, 0xC1, 0xA6, 0xBA, + 0x81, 0x20, 0x84, 0x00, 0xB1, 0x86, 0xEA, 0xAB, 0x38, 0x10, 0xA6, 0x02, 0xEA, 0xCA, 0xA6, 0xFB, + 0x92, 0x41, 0x3B, 0x03, 0x4C, 0x20, 0xEA, 0xFB, 0xEA, 0xCA, 0x38, 0x13, 0x26, 0x02, 0xA6, 0xBA, + 0xA6, 0xFB, 0xEA, 0xFB, 0xFC, 0xC5, 0xDD, 0x41, 0xA6, 0x01, 0x5A, 0x08, 0x0D, 0x11, 0x2E, 0x07, + 0xEF, 0xE8, 0xC8, 0x0D, 0xFC, 0x00, 0x49, 0xFF, 0xA6, 0xBE, 0xEB, 0x30, 0x49, 0xFF, 0xE9, 0x3E, + 0xEB, 0x30, 0x44, 0x12, 0xBC, 0x60, 0x49, 0xFF, 0xEA, 0xE1, 0xFC, 0x80, 0xDD, 0x9E, 0xFC, 0x41, + 0xDD, 0x50, 0x84, 0xC0, 0xF0, 0x81, 0x84, 0x01, 0xEA, 0xE9, 0x80, 0xE6, 0x3C, 0x6F, 0xFC, 0x79, + 0x81, 0x20, 0xAE, 0x08, 0xDD, 0x51, 0xA6, 0x08, 0xC8, 0xFF, 0xE2, 0xC7, 0xE8, 0x07, 0x8C, 0xC1, + 0xF0, 0x01, 0x84, 0x24, 0x97, 0xB0, 0x49, 0xFF, 0xFE, 0xFD, 0xDD, 0x51, 0xA6, 0x08, 0x5A, 0x08, + 0x01, 0xFF, 0xDD, 0x40, 0xC0, 0x07, 0xEA, 0x67, 0x5A, 0x08, 0x06, 0xFF, 0xEA, 0x4A, 0xEA, 0x86, + 0xDD, 0x5D, 0x8C, 0xE1, 0xDD, 0x4B, 0x97, 0xF8, 0x10, 0x90, 0x00, 0x00, 0x5A, 0x78, 0x04, 0xE4, + 0xFC, 0xC1, 0x3C, 0x0F, 0xFC, 0x8E, 0xDD, 0x9E, 0x3C, 0x0F, 0xFC, 0x90, 0xDD, 0x9E, 0xFC, 0x01, + 0xF0, 0x81, 0xDD, 0x43, 0x5A, 0x00, 0x02, 0x1F, 0xEB, 0xA6, 0x5A, 0x00, 0xA1, 0x1C, 0xDD, 0x41, + 0xEA, 0x3E, 0xDD, 0x40, 0x5A, 0x08, 0x01, 0x07, 0xEB, 0xCE, 0xC0, 0xFF, 0x84, 0x00, 0xEA, 0x5F, + 0xD5, 0x0F, 0xEB, 0x59, 0x44, 0x12, 0xBC, 0xE8, 0x80, 0x41, 0x84, 0x66, 0x84, 0x02, 0xDD, 0x42, + 0x84, 0x01, 0xEA, 0x5F, 0xEB, 0x01, 0x84, 0x02, 0x80, 0x41, 0x80, 0x60, 0xDD, 0x42, 0x49, 0x00, + 0x06, 0xB2, 0xF0, 0x01, 0x84, 0x20, 0xDD, 0x53, 0xDD, 0x51, 0x84, 0x00, 0xAE, 0x08, 0xDD, 0x50, + 0xAE, 0x08, 0xDD, 0x40, 0x5A, 0x08, 0x01, 0x05, 0x2E, 0x00, 0x11, 0xBD, 0xEB, 0x68, 0x84, 0x01, + 0xEA, 0x30, 0x84, 0x01, 0x84, 0x40, 0x84, 0x2A, 0x80, 0x80, 0x80, 0x62, 0x80, 0xA2, 0xDD, 0x56, + 0xDD, 0x47, 0xDD, 0x45, 0xAE, 0x40, 0xEA, 0x43, 0xC8, 0x04, 0x3C, 0x0D, 0xFC, 0x7B, 0xC0, 0xFC, + 0xDD, 0x40, 0xC0, 0x15, 0x84, 0x01, 0xDD, 0x4F, 0xDD, 0x47, 0xDD, 0x45, 0xAE, 0x40, 0xEB, 0x6A, + 0xC0, 0xFF, 0x84, 0x02, 0xDD, 0x4F, 0xDD, 0x43, 0x5A, 0x00, 0x02, 0x20, 0xEA, 0x29, 0xEB, 0x07, + 0xAE, 0x08, 0x80, 0x41, 0x84, 0x61, 0x84, 0x02, 0xDD, 0x42, 0xD5, 0x17, 0xDD, 0x43, 0x5A, 0x00, + 0x02, 0x0B, 0xEB, 0xA6, 0x5A, 0x00, 0xA1, 0x08, 0x44, 0x13, 0x31, 0x38, 0x84, 0x02, 0x80, 0x41, + 0xEA, 0x4F, 0xDD, 0x42, 0xDD, 0x43, 0x5A, 0x00, 0x02, 0x09, 0xDD, 0x47, 0xDD, 0x45, 0xAE, 0x40, + 0xEA, 0x29, 0xA6, 0x08, 0x5A, 0x08, 0x32, 0xFF, 0xDD, 0x43, 0x5A, 0x08, 0x02, 0x07, 0x2E, 0x07, + 0xEE, 0xE8, 0x8C, 0x01, 0x3E, 0x07, 0xEE, 0xE8, 0xFC, 0x81, 0x80, 0xA0, 0x3C, 0x0D, 0xFC, 0x8E, + 0x3C, 0x3C, 0x03, 0x28, 0xA6, 0x83, 0x92, 0x22, 0xE2, 0xA2, 0xE8, 0x27, 0xCD, 0x09, 0xA4, 0x19, + 0x96, 0x49, 0xF8, 0x29, 0xF8, 0x19, 0x4E, 0xF2, 0x00, 0x92, 0x48, 0x00, 0x00, 0x8E, 0xF8, 0x5B, + 0x9F, 0x11, 0x88, 0x05, 0xDC, 0x08, 0xF8, 0x46, 0x96, 0x03, 0xE0, 0x20, 0xF8, 0x0A, 0x4E, 0xF3, + 0x00, 0x84, 0xDD, 0x9E, 0xF8, 0x67, 0x4E, 0xF3, 0x00, 0x80, 0x8C, 0x04, 0x88, 0x03, 0xF8, 0x70, + 0x4E, 0xF3, 0x00, 0x7B, 0x88, 0x45, 0x40, 0x21, 0x88, 0x20, 0xA4, 0x10, 0x96, 0x03, 0xE0, 0x20, + 0x83, 0xFF, 0x4E, 0xF3, 0x00, 0x72, 0xDD, 0x9E, 0x84, 0x83, 0xFF, 0x14, 0xE2, 0xA4, 0xE9, 0x26, + 0xDC, 0x0D, 0xF8, 0x27, 0x96, 0x03, 0xE0, 0x20, 0x4E, 0xF3, 0x00, 0x67, 0x83, 0xFF, 0x9A, 0xAA, + 0x4E, 0x00, 0xFF, 0xEB, 0x4E, 0xF3, 0x00, 0x61, 0xDD, 0x9E, 0x95, 0x12, 0xF8, 0x2C, 0x8E, 0x81, + 0x88, 0x05, 0xDC, 0x05, 0xF8, 0x17, 0xF8, 0x0D, 0xF8, 0x08, 0xDD, 0x9E, 0xF8, 0x3B, 0xE9, 0x54, + 0x8C, 0x04, 0x88, 0x03, 0xA4, 0x00, 0xF8, 0x05, 0x9A, 0xAA, 0x40, 0x21, 0x88, 0x20, 0xA4, 0x10, + 0x96, 0x03, 0xE0, 0x20, 0xE9, 0x49, 0x83, 0xFF, 0xDD, 0x9E, 0xD2, 0x03, 0x94, 0x11, 0xD8, 0x11, + 0x9C, 0x29, 0xEB, 0x9F, 0xA4, 0x00, 0x96, 0x49, 0x83, 0xFF, 0x4E, 0x00, 0xFF, 0xF3, 0x9A, 0x2A, + 0xEB, 0x9F, 0xA4, 0x00, 0x4E, 0x00, 0xFF, 0xEE, 0x88, 0x45, 0x4E, 0x00, 0xFF, 0xE8, 0xDD, 0x9E, + 0xFC, 0x00, 0x9F, 0x81, 0x46, 0x07, 0xFF, 0xFF, 0x50, 0x00, 0x0F, 0xFF, 0x83, 0xFF, 0x88, 0x05, + 0xD6, 0x03, 0x8E, 0x81, 0xDC, 0x0F, 0x4E, 0x00, 0xFF, 0xE6, 0x96, 0x03, 0xE0, 0x20, 0xE8, 0x04, + 0x84, 0x01, 0xEA, 0x42, 0xFC, 0x80, 0xF8, 0x12, 0xE9, 0xFC, 0x4E, 0x00, 0xFF, 0xA5, 0xE9, 0xF9, + 0xFC, 0x80, 0x94, 0x01, 0x99, 0x18, 0xA5, 0x20, 0x96, 0x49, 0x97, 0x23, 0xE0, 0x24, 0x83, 0xFF, + 0xE9, 0xF0, 0x8C, 0x04, 0x88, 0x03, 0xF8, 0x04, 0xE9, 0xEC, 0x9A, 0x2A, 0xEB, 0x9F, 0xA4, 0x00, + 0x96, 0x03, 0xE0, 0x20, 0x83, 0xFF, 0xE9, 0xE5, 0x98, 0x2A, 0x40, 0x21, 0x80, 0x20, 0x4E, 0x00, + 0xFF, 0x8E, 0xE9, 0xDF, 0xFC, 0x80, 0x84, 0x01, 0xEA, 0x42, 0xDD, 0x9E, 0xEB, 0x83, 0x96, 0x48, + 0xC1, 0x0A, 0xEB, 0x83, 0x2E, 0x27, 0x36, 0xA6, 0xE2, 0x41, 0x84, 0x20, 0xE9, 0x04, 0xEB, 0x83, + 0x8E, 0x21, 0x96, 0x48, 0x44, 0x22, 0xE2, 0x54, 0x38, 0x31, 0x05, 0x01, 0xE2, 0x60, 0xE9, 0x2B, + 0xFC, 0x20, 0x84, 0x00, 0x38, 0x01, 0x05, 0x09, 0xEA, 0x85, 0x84, 0x20, 0x84, 0xA3, 0x3C, 0x3C, + 0x03, 0x26, 0x3C, 0x0C, 0x03, 0x27, 0x3C, 0x4C, 0x03, 0x2F, 0x94, 0x89, 0x88, 0x62, 0x88, 0x02, + 0x88, 0x81, 0xA5, 0x98, 0xA5, 0xC0, 0xA6, 0x20, 0x88, 0x07, 0x42, 0x03, 0x14, 0x73, 0x40, 0x40, + 0x08, 0x09, 0x97, 0x21, 0xAD, 0x18, 0x3C, 0x4C, 0x03, 0x26, 0x3C, 0x3C, 0x03, 0x2F, 0x88, 0x44, + 0xA4, 0x90, 0x88, 0x61, 0x40, 0x00, 0x08, 0x41, 0x96, 0x00, 0x8C, 0x21, 0xAE, 0x18, 0x5A, 0x18, + 0xC8, 0xE0, 0xFC, 0xA0, 0xDD, 0x9E, 0xFC, 0x00, 0x84, 0x00, 0xEA, 0x6C, 0xEA, 0x85, 0xEA, 0x42, + 0xDD, 0x41, 0xA6, 0x01, 0x5A, 0x08, 0x04, 0x0F, 0x44, 0x02, 0xD7, 0xD0, 0x84, 0x20, 0xEA, 0xC8, + 0xEA, 0x2F, 0xEA, 0x38, 0xC8, 0x04, 0x84, 0x04, 0xEA, 0x66, 0xD5, 0x09, 0x84, 0x01, 0xEA, 0x66, + 0xD5, 0x06, 0x2E, 0x07, 0xEA, 0xFC, 0xC8, 0xF6, 0x84, 0x02, 0xEA, 0x66, 0xEA, 0x32, 0x5A, 0x08, + 0x02, 0x05, 0x84, 0x00, 0x3E, 0x07, 0xEF, 0x7B, 0x84, 0x00, 0x80, 0x80, 0x44, 0x52, 0xDC, 0x90, + 0x3C, 0x3C, 0x03, 0x25, 0x94, 0x41, 0x88, 0x61, 0xA4, 0xD8, 0x3C, 0x2C, 0x03, 0x27, 0x96, 0xD9, + 0x88, 0x41, 0xAC, 0xD0, 0x3C, 0x2C, 0x03, 0x26, 0x3C, 0x3C, 0x03, 0x27, 0x88, 0x41, 0x88, 0x23, + 0xA4, 0x48, 0x96, 0x49, 0xAC, 0x50, 0x3C, 0x1C, 0x03, 0x2F, 0x88, 0x20, 0xAF, 0x08, 0x38, 0x42, + 0x80, 0x08, 0x8C, 0x01, 0x5A, 0x08, 0xC8, 0xE6, 0xFC, 0x80, 0xFC, 0x00, 0x5A, 0x08, 0x01, 0x13, + 0x2E, 0x10, 0x12, 0x0D, 0x2E, 0x00, 0x12, 0x0C, 0x5A, 0x18, 0x01, 0x05, 0x8E, 0x03, 0x96, 0x00, + 0xD5, 0x03, 0x8E, 0x02, 0x96, 0x00, 0x84, 0x40, 0x80, 0x20, 0x80, 0x62, 0x49, 0x00, 0x0C, 0x45, + 0xFC, 0x80, 0x49, 0x00, 0x0C, 0x53, 0xFC, 0x80, 0xA6, 0x41, 0xEA, 0xA2, 0x5A, 0x18, 0x04, 0x11, + 0x2E, 0x17, 0xEE, 0xD1, 0xC9, 0x03, 0xA6, 0x02, 0xD5, 0x02, 0xA6, 0x03, 0x2E, 0x17, 0xEF, 0x55, + 0x5A, 0x18, 0x02, 0x08, 0xE6, 0x04, 0xE9, 0x05, 0x8E, 0x03, 0x96, 0x00, 0xDD, 0x9E, 0xA6, 0x04, + 0xDD, 0x9E, 0x54, 0x00, 0x00, 0xFD, 0x5A, 0x08, 0x04, 0x05, 0x3C, 0x03, 0xFB, 0x48, 0xDD, 0x9E, + 0xEA, 0xA2, 0x02, 0x00, 0x00, 0x09, 0xDD, 0x9E, 0x5A, 0x08, 0x04, 0x05, 0x3C, 0x03, 0xFB, 0x47, + 0xDD, 0x9E, 0xEA, 0xA2, 0x02, 0x00, 0x00, 0x0A, 0xDD, 0x9E, 0xEA, 0xA2, 0xA4, 0x00, 0xDD, 0x9E, + 0xB4, 0x00, 0xEA, 0xA2, 0xA4, 0x47, 0x02, 0x00, 0x00, 0x08, 0x3C, 0x1B, 0xFB, 0x48, 0x3C, 0x0B, + 0xFB, 0x47, 0xDD, 0x9E, 0x2E, 0x17, 0xEE, 0xC3, 0xC9, 0x0A, 0x84, 0x42, 0x3E, 0x17, 0xEA, 0xFC, + 0x3E, 0x27, 0xEF, 0x17, 0x3E, 0x17, 0xEE, 0xF0, 0x10, 0x10, 0x00, 0x1C, 0xDD, 0x9E, 0xFC, 0x00, + 0xDD, 0x47, 0xDD, 0x45, 0xAE, 0x40, 0x3C, 0x0D, 0xFC, 0x7B, 0xC8, 0x10, 0xEA, 0x81, 0x5A, 0x08, + 0x01, 0x06, 0x44, 0x02, 0xBC, 0x26, 0x49, 0xFF, 0xC0, 0x73, 0x84, 0x01, 0x84, 0x40, 0x80, 0x20, + 0x80, 0x62, 0x80, 0x80, 0x80, 0xA2, 0xDD, 0x56, 0xD5, 0xEF, 0x84, 0x06, 0xDD, 0x4F, 0xDD, 0x40, + 0xC0, 0x18, 0xEA, 0x29, 0xEA, 0x50, 0xEA, 0x48, 0xA6, 0x08, 0x5A, 0x00, 0x32, 0x04, 0xAE, 0xD0, + 0xD5, 0xFC, 0x84, 0x06, 0x44, 0x12, 0xBD, 0x98, 0xEA, 0x60, 0x80, 0x41, 0x84, 0x02, 0x84, 0x61, + 0xDD, 0x42, 0xEB, 0xE4, 0xC0, 0x04, 0x84, 0x0A, 0xEA, 0x26, 0xD5, 0x03, 0x84, 0x09, 0xEA, 0x26, + 0xEA, 0x56, 0x44, 0x10, 0x00, 0x33, 0xAE, 0x40, 0x2E, 0x07, 0xF1, 0x20, 0xC8, 0x10, 0xEB, 0xA6, + 0x5A, 0x00, 0xA1, 0x0E, 0xDD, 0x40, 0x80, 0x20, 0xC8, 0x07, 0x84, 0x02, 0x80, 0x41, 0x80, 0x61, + 0x84, 0x83, 0x80, 0xA1, 0xDD, 0x56, 0x49, 0xFF, 0xC7, 0xC5, 0xFC, 0x80, 0x84, 0x0E, 0x49, 0xFF, + 0xBF, 0x96, 0xFC, 0x80, 0x84, 0x00, 0xDD, 0x9E, 0xFC, 0x20, 0xDD, 0x41, 0x84, 0x23, 0x3C, 0x7D, + 0xFC, 0x03, 0x84, 0xC1, 0xAE, 0x41, 0x3C, 0x6F, 0xFC, 0x03, 0xEA, 0x3E, 0xDD, 0x54, 0xA6, 0x00, + 0x84, 0x23, 0x97, 0xF8, 0x49, 0x00, 0x14, 0xF0, 0xEB, 0x4C, 0xEB, 0x5E, 0xC8, 0x0A, 0x2E, 0x07, + 0xEF, 0x22, 0xC8, 0x07, 0x84, 0x09, 0xDD, 0x4F, 0x3E, 0x67, 0xEF, 0x39, 0x3E, 0x67, 0xEE, 0xE2, + 0x84, 0x1F, 0xEA, 0x51, 0xDD, 0x41, 0xEA, 0x3E, 0xDD, 0x51, 0x84, 0x00, 0x3E, 0x07, 0xEF, 0x22, + 0x84, 0x01, 0xAE, 0x08, 0xDD, 0x50, 0xAE, 0x08, 0xEA, 0x32, 0x5A, 0x00, 0x04, 0x04, 0x84, 0x05, + 0xEA, 0x66, 0x2E, 0x17, 0xEF, 0x06, 0x2E, 0x07, 0xEF, 0x44, 0x5A, 0x18, 0x01, 0x0A, 0xC8, 0x10, + 0x3C, 0x1D, 0xFC, 0x90, 0xA4, 0x48, 0xE6, 0x26, 0xE9, 0x0C, 0x9E, 0x0E, 0xD5, 0x0A, 0xC8, 0x08, + 0x3C, 0x1D, 0xFC, 0x90, 0xA4, 0x48, 0xE6, 0x22, 0xE9, 0x04, 0x9E, 0x0A, 0xD5, 0x02, 0x84, 0x00, + 0xEA, 0x33, 0x84, 0x01, 0x3E, 0x07, 0xEF, 0x48, 0x84, 0x00, 0xEA, 0xAA, 0xFC, 0xA0, 0xFC, 0x00, + 0x84, 0xC0, 0x3C, 0x6F, 0xFC, 0x5E, 0xEA, 0xE9, 0xEB, 0xFA, 0x84, 0x01, 0xEA, 0x30, 0xDD, 0x58, + 0xAF, 0x80, 0xEB, 0xFA, 0xFC, 0x80, 0xFC, 0x00, 0xDD, 0x41, 0xA6, 0x01, 0xEB, 0xBA, 0x5A, 0x08, + 0x09, 0x13, 0xEB, 0x34, 0xC8, 0x10, 0xEA, 0x32, 0x5A, 0x00, 0x04, 0x04, 0x84, 0x05, 0xEA, 0x66, + 0x2E, 0x07, 0xEF, 0x44, 0xC8, 0x08, 0xF8, 0x03, 0xE6, 0x02, 0xE9, 0x05, 0x49, 0xFF, 0xF0, 0xAD, + 0x8E, 0x02, 0xD5, 0x02, 0x84, 0x00, 0xEA, 0x33, 0xF8, 0x17, 0x49, 0xFF, 0xC7, 0x52, 0xDD, 0x41, + 0x84, 0x29, 0xAE, 0x41, 0x84, 0x20, 0xDD, 0x53, 0xDD, 0x41, 0x84, 0x2A, 0xAE, 0x41, 0xEA, 0x3E, + 0x49, 0x00, 0x23, 0xA9, 0x84, 0x00, 0x84, 0x21, 0xEA, 0x2A, 0x3E, 0x17, 0xF3, 0x70, 0xEA, 0xAA, + 0xEB, 0x49, 0x49, 0x00, 0x3B, 0x5A, 0x49, 0xFF, 0xC7, 0x4A, 0xFC, 0x80, 0xEA, 0xA2, 0x3C, 0x3C, + 0x03, 0x28, 0xA5, 0x03, 0x84, 0x20, 0x84, 0x01, 0x98, 0x99, 0xA4, 0x90, 0x96, 0x93, 0xE0, 0x82, + 0xE8, 0x02, 0x84, 0x00, 0x8C, 0x22, 0x5A, 0x19, 0x90, 0xF9, 0xDD, 0x9E, 0xFC, 0x20, 0x2E, 0x17, + 0xEF, 0x17, 0x5A, 0x18, 0x02, 0x0B, 0x2E, 0x17, 0xEA, 0xFC, 0xC9, 0x07, 0x2E, 0x17, 0xEF, 0x51, + 0x8E, 0x22, 0x5C, 0x10, 0x80, 0x01, 0xD5, 0x02, 0x84, 0x20, 0x3C, 0x6D, 0xFC, 0x8E, 0x3C, 0x4D, + 0xFB, 0x26, 0x3C, 0x7C, 0x03, 0x27, 0x84, 0xA0, 0x84, 0x61, 0x86, 0x43, 0x53, 0x30, 0x00, 0x00, + 0xA6, 0xB3, 0x51, 0x13, 0x80, 0x02, 0x51, 0x01, 0x7F, 0xFF, 0x4C, 0x58, 0x00, 0x1D, 0x41, 0x01, + 0x04, 0x08, 0x8F, 0x81, 0x4C, 0x58, 0x00, 0x18, 0x43, 0x01, 0x48, 0x24, 0x8F, 0x81, 0x4C, 0x58, + 0x00, 0x13, 0x94, 0x92, 0x8E, 0x41, 0xD2, 0x0F, 0xA4, 0xB8, 0x02, 0x78, 0x80, 0x00, 0x8A, 0x47, + 0x96, 0x93, 0xE0, 0x02, 0x38, 0x22, 0x15, 0x09, 0xE9, 0x03, 0xE0, 0x53, 0xE8, 0x04, 0x5A, 0x18, + 0x01, 0x03, 0x84, 0x62, 0x8C, 0xA1, 0x80, 0xF1, 0x5A, 0x58, 0xC7, 0xDC, 0x5A, 0x18, 0x01, 0x1C, + 0x40, 0x10, 0x04, 0x09, 0x84, 0x40, 0xFF, 0x4A, 0x38, 0x72, 0x09, 0x11, 0xE0, 0x27, 0xE8, 0x07, + 0xA6, 0x33, 0x88, 0x02, 0x38, 0xF2, 0x01, 0x11, 0xE0, 0x2F, 0xE9, 0x09, 0xE0, 0xE5, 0xE8, 0x08, + 0xA6, 0x33, 0x88, 0x02, 0x38, 0x02, 0x01, 0x11, 0xE0, 0x05, 0xE8, 0x02, 0x84, 0x62, 0x8C, 0x41, + 0x5A, 0x28, 0x95, 0xEC, 0x80, 0x03, 0xFC, 0xA0, 0x84, 0x20, 0x44, 0x22, 0xE2, 0x54, 0x38, 0x01, + 0x05, 0x09, 0x8C, 0x21, 0x5A, 0x18, 0x08, 0xFD, 0xDD, 0x9E, 0xFC, 0x20, 0x80, 0xE0, 0xA6, 0x00, + 0x80, 0xC2, 0x5A, 0x08, 0x05, 0x1C, 0x84, 0x01, 0xAE, 0x38, 0xDD, 0x41, 0xA6, 0x01, 0xEA, 0xC2, + 0xF8, 0x16, 0x3C, 0x13, 0xF7, 0xEC, 0xE6, 0x2A, 0xE8, 0x05, 0x8C, 0x21, 0x3C, 0x1B, 0xF7, 0xEC, + 0xD5, 0x14, 0x84, 0x00, 0x3C, 0x0B, 0xF7, 0xEC, 0xA4, 0x70, 0xE6, 0x39, 0xE8, 0x04, 0xAE, 0x38, + 0x84, 0x00, 0xF8, 0x05, 0x84, 0x00, 0xAC, 0x30, 0xD5, 0x08, 0x84, 0x00, 0x49, 0xFF, 0xFF, 0xD6, + 0x84, 0x00, 0xAC, 0x30, 0x3C, 0x0B, 0xF7, 0xEC, 0xFC, 0xA0, 0xFC, 0x01, 0xDD, 0x41, 0xA6, 0x01, + 0xEA, 0xC2, 0xF0, 0x81, 0xF1, 0x01, 0x44, 0x02, 0xBB, 0xC9, 0x44, 0x22, 0xBC, 0x3E, 0x49, 0xFF, + 0xFF, 0xCE, 0x2E, 0x17, 0xEF, 0x51, 0x84, 0x00, 0xEA, 0x6C, 0x3E, 0x07, 0xEE, 0xFA, 0xC9, 0x03, + 0x3E, 0x07, 0xEE, 0xFC, 0x84, 0x00, 0x3E, 0x07, 0xEE, 0xBE, 0xEA, 0x34, 0xEA, 0x97, 0xFC, 0x81, + 0xFC, 0x20, 0x84, 0x07, 0xDD, 0x4F, 0x84, 0xC0, 0xDD, 0x41, 0x3E, 0x67, 0xF2, 0xC6, 0xEA, 0x3E, + 0xDD, 0x4B, 0x84, 0x21, 0x3E, 0x67, 0xEE, 0xE8, 0xAE, 0x40, 0x84, 0x00, 0xEA, 0x5F, 0x84, 0x00, + 0x3C, 0x0F, 0xFC, 0x72, 0xEA, 0xCC, 0xEB, 0x36, 0x3C, 0x2D, 0xFC, 0x72, 0xCA, 0x09, 0x84, 0x01, + 0xAF, 0xF0, 0x80, 0x20, 0x80, 0x62, 0x80, 0x80, 0x80, 0xA2, 0xDD, 0x56, 0xD5, 0xF6, 0xDD, 0x47, + 0xDD, 0x45, 0xAE, 0x40, 0xEA, 0x43, 0xC8, 0x0B, 0x3C, 0x2D, 0xFC, 0x7B, 0xCA, 0x08, 0x84, 0x01, + 0x84, 0x27, 0x80, 0x62, 0x80, 0x80, 0x80, 0xA2, 0xDD, 0x56, 0xD5, 0xF5, 0x84, 0x21, 0xDD, 0x41, + 0xDD, 0x53, 0xDD, 0x40, 0xEA, 0x21, 0xDD, 0x5B, 0xAE, 0x88, 0xC0, 0x17, 0x3C, 0x23, 0xF7, 0xDF, + 0x96, 0x91, 0xCA, 0x08, 0x84, 0x01, 0x80, 0x20, 0x80, 0x62, 0x80, 0x80, 0x80, 0xA2, 0xDD, 0x56, + 0xD5, 0xF6, 0x84, 0x00, 0xEA, 0x5F, 0x3E, 0x07, 0xEF, 0x06, 0xDD, 0x52, 0x5A, 0x08, 0x02, 0x2F, + 0x84, 0x01, 0x3E, 0x07, 0xEF, 0x06, 0xD5, 0x2A, 0x2E, 0x27, 0xEF, 0x5A, 0x96, 0x90, 0xCA, 0x08, + 0x84, 0x01, 0x80, 0x20, 0x80, 0x62, 0x80, 0x80, 0x80, 0xA2, 0xDD, 0x56, 0xD5, 0xF6, 0x49, 0xFF, + 0xDF, 0xC2, 0x3C, 0x0E, 0x03, 0xD3, 0x5A, 0x08, 0x03, 0x05, 0x84, 0x02, 0xEA, 0x2D, 0xD5, 0x03, + 0x84, 0x01, 0xEA, 0x2D, 0x84, 0x00, 0x3E, 0x07, 0xEF, 0x5A, 0x84, 0x01, 0xEA, 0xAF, 0xEB, 0x59, + 0x44, 0x12, 0xBC, 0x84, 0x84, 0x01, 0x80, 0x41, 0xEA, 0x5F, 0x84, 0x61, 0x84, 0x02, 0xDD, 0x42, + 0x84, 0x02, 0xEB, 0x01, 0x80, 0x41, 0x80, 0x60, 0xDD, 0x42, 0x84, 0x01, 0xEA, 0x2D, 0x84, 0x08, + 0xDD, 0x4F, 0xDD, 0x41, 0xEA, 0x3E, 0xFC, 0xA0, 0xFC, 0x40, 0x80, 0xE1, 0x84, 0x20, 0x3E, 0x17, + 0xEE, 0xF0, 0x40, 0x90, 0x08, 0x08, 0x84, 0xC0, 0xE0, 0xC9, 0xE8, 0x14, 0x3C, 0x2C, 0x03, 0x28, + 0x40, 0x21, 0x18, 0x20, 0xA4, 0x90, 0x96, 0x93, 0xE0, 0xE2, 0xE8, 0x09, 0xFD, 0x03, 0x49, 0xFF, + 0xFC, 0x66, 0xEA, 0xAC, 0xC0, 0x04, 0x3E, 0x67, 0xF2, 0x3C, 0xFC, 0xC0, 0x8C, 0xC1, 0x97, 0xB0, + 0xD5, 0xEC, 0xFC, 0xC0, 0xFC, 0x60, 0x44, 0x20, 0xFF, 0xFF, 0x84, 0xA0, 0x3C, 0x7D, 0xFC, 0x90, + 0xA9, 0x4A, 0xA8, 0x8B, 0x00, 0x23, 0x80, 0x16, 0xE6, 0x50, 0xE8, 0x04, 0x52, 0x51, 0x00, 0x10, + 0x97, 0x68, 0x84, 0xC0, 0xFB, 0x80, 0x43, 0x01, 0x40, 0x01, 0x3D, 0x3D, 0xFC, 0x8E, 0x3C, 0x9C, + 0x03, 0x27, 0x3C, 0xAC, 0x03, 0x25, 0x3C, 0xBC, 0x03, 0x28, 0x3C, 0x8C, 0x03, 0x26, 0x2E, 0xC7, + 0xEA, 0xFC, 0x2E, 0xD7, 0xEF, 0x51, 0x2F, 0x27, 0xEF, 0x7B, 0x80, 0x46, 0x45, 0x12, 0xDC, 0x90, + 0x81, 0xC6, 0x00, 0x39, 0x80, 0x03, 0x95, 0x1A, 0xE0, 0x44, 0xE8, 0x58, 0x95, 0x91, 0x40, 0x44, + 0x98, 0x00, 0xA4, 0xE0, 0x40, 0xF5, 0x18, 0x00, 0x02, 0xF7, 0x80, 0x00, 0xFE, 0xEC, 0x42, 0x37, + 0xC0, 0x73, 0x40, 0xF5, 0x98, 0x00, 0x92, 0x64, 0x96, 0xD9, 0xAC, 0xE0, 0x88, 0xC8, 0xA4, 0xE0, + 0x03, 0x43, 0x00, 0x00, 0x8A, 0x74, 0x96, 0xDB, 0x12, 0x37, 0x80, 0x00, 0x02, 0x37, 0x80, 0x00, + 0x40, 0xF1, 0x80, 0x11, 0xA4, 0xFD, 0xFE, 0xDA, 0x40, 0xF7, 0x8C, 0x07, 0xE8, 0x1C, 0x5A, 0xC0, + 0x01, 0x04, 0x5A, 0xD8, 0x02, 0x19, 0x38, 0x38, 0x88, 0x00, 0x8C, 0x61, 0x96, 0xD8, 0x38, 0x38, + 0x88, 0x08, 0x02, 0xF3, 0x80, 0x06, 0x40, 0xF7, 0x8C, 0x06, 0xE8, 0x13, 0xA4, 0xE0, 0x86, 0x41, + 0x96, 0xD9, 0xAC, 0xF0, 0x2E, 0x37, 0xF2, 0x3D, 0x38, 0xE8, 0x88, 0x08, 0x8C, 0x61, 0x3E, 0x37, + 0xF2, 0x3D, 0xD5, 0x07, 0x38, 0x38, 0x88, 0x00, 0xC3, 0x04, 0x8E, 0x61, 0x38, 0x38, 0x88, 0x08, + 0xA5, 0xA0, 0xA0, 0xCA, 0xE2, 0x66, 0xE8, 0x03, 0xA4, 0xE0, 0xA8, 0xCA, 0xA5, 0xA0, 0xA0, 0xCB, + 0xE2, 0xC3, 0xE8, 0x03, 0xA4, 0xE0, 0xA8, 0xCB, 0xA6, 0xC1, 0x5A, 0x38, 0x09, 0x04, 0xA5, 0xBB, + 0xD5, 0x02, 0xA5, 0xBC, 0x8C, 0x41, 0x96, 0x90, 0xD5, 0xA5, 0x80, 0x03, 0x80, 0x26, 0x3F, 0x27, + 0xEF, 0x7B, 0x49, 0xFF, 0xFF, 0x5B, 0xDD, 0x41, 0xA6, 0x01, 0x5A, 0x08, 0x09, 0x07, 0x80, 0x06, + 0x49, 0xFF, 0xFE, 0x2E, 0x3E, 0x07, 0xEF, 0x17, 0xFC, 0xE0, 0xFC, 0x40, 0x80, 0xC0, 0xA6, 0x01, + 0x80, 0xE1, 0x5A, 0x08, 0x04, 0x22, 0x9E, 0x0C, 0xE6, 0x04, 0xE9, 0x25, 0x5A, 0x10, 0x0C, 0x24, + 0xEA, 0x32, 0x5A, 0x00, 0x04, 0x21, 0xEA, 0x38, 0x5A, 0x00, 0x01, 0x13, 0xEA, 0xF6, 0x5A, 0x00, + 0x01, 0x10, 0x2E, 0x07, 0xF2, 0xF2, 0xC0, 0x05, 0x84, 0x00, 0x3E, 0x07, 0xF2, 0xF2, 0xD5, 0x13, + 0x2E, 0x07, 0xEE, 0xD1, 0x5A, 0x08, 0x01, 0x03, 0xEB, 0xFA, 0x80, 0x06, 0xEB, 0xF2, 0xEA, 0x24, + 0xEB, 0xBE, 0xEB, 0x85, 0xD5, 0x08, 0xEA, 0x32, 0x5A, 0x00, 0x04, 0x06, 0x49, 0xFF, 0xC5, 0x2C, + 0x80, 0x06, 0xEB, 0xF2, 0xDD, 0x40, 0x4E, 0x02, 0x00, 0x93, 0x3C, 0x03, 0xF7, 0xE3, 0x44, 0x12, + 0xD9, 0xD0, 0x8C, 0x01, 0xEA, 0x85, 0x3C, 0x03, 0xF7, 0xC9, 0x8C, 0x01, 0xEA, 0x6C, 0x80, 0x06, + 0x49, 0xFF, 0xFF, 0x32, 0xDD, 0x43, 0x5A, 0x00, 0x02, 0x18, 0x2E, 0x97, 0xEE, 0xD7, 0x4E, 0x93, + 0x00, 0x14, 0xA6, 0x31, 0x5A, 0x08, 0x09, 0x11, 0xEB, 0xE9, 0x44, 0x12, 0xD7, 0x60, 0x3E, 0x97, + 0xEE, 0xD7, 0x3E, 0x97, 0xEE, 0xBB, 0x49, 0xFF, 0xDB, 0xA7, 0xC0, 0x06, 0x84, 0x01, 0x3E, 0x07, + 0xEE, 0xD7, 0x3C, 0x9B, 0xF7, 0xC9, 0x44, 0x03, 0x8D, 0x42, 0xA6, 0x00, 0xC0, 0x05, 0x84, 0x01, + 0xEA, 0x42, 0x84, 0x00, 0xEA, 0x33, 0xEA, 0xAC, 0x5A, 0x08, 0x01, 0x15, 0x84, 0x00, 0x3E, 0x07, + 0xEE, 0xFA, 0x84, 0x00, 0x2E, 0x17, 0x36, 0xA6, 0x44, 0x32, 0xE2, 0x54, 0x80, 0x80, 0x96, 0x80, + 0xE2, 0x41, 0xE8, 0x05, 0x38, 0x41, 0x81, 0x09, 0x8C, 0x01, 0xD5, 0xFA, 0xEA, 0xEC, 0xDD, 0x4A, + 0xD5, 0x18, 0x2E, 0x97, 0xEA, 0xFC, 0x5A, 0x98, 0x01, 0x15, 0x9E, 0x3C, 0xE6, 0x02, 0xE9, 0x11, + 0x44, 0x02, 0xD9, 0xD0, 0x3C, 0x13, 0x9A, 0x2F, 0x44, 0x22, 0xBB, 0x72, 0x49, 0xFF, 0xF5, 0x01, + 0x5A, 0x08, 0x02, 0x08, 0xFA, 0x01, 0xDD, 0x4A, 0x3E, 0x97, 0xEE, 0xF0, 0x3E, 0x97, 0xEF, 0x5C, + 0x2E, 0x07, 0xEA, 0xFC, 0xC8, 0x34, 0xA6, 0x30, 0x5A, 0x08, 0x02, 0x32, 0xEA, 0x32, 0x5A, 0x00, + 0x01, 0x0F, 0x2E, 0x07, 0xEF, 0x7B, 0x5A, 0x08, 0x01, 0x06, 0x2E, 0x07, 0xEF, 0x17, 0x5A, 0x00, + 0x01, 0x07, 0x3C, 0xF7, 0xF8, 0x03, 0x5E, 0xF7, 0x80, 0x64, 0xE8, 0x18, 0x49, 0xFF, 0xFD, 0x78, + 0xC8, 0x09, 0x3C, 0xF7, 0xF8, 0x03, 0x5E, 0xF7, 0x80, 0x64, 0xE9, 0x04, 0xEA, 0x42, 0xEA, 0x85, + 0xD5, 0x0D, 0x84, 0x01, 0x84, 0xC0, 0xEA, 0x78, 0x3E, 0x67, 0xF3, 0x56, 0x49, 0xFF, 0xD4, 0x7A, + 0xEA, 0x32, 0x5A, 0x08, 0x02, 0x04, 0x3E, 0x67, 0xEF, 0x51, 0xEA, 0x32, 0x5A, 0x08, 0x02, 0x08, + 0x2E, 0x07, 0xEF, 0x17, 0x5A, 0x08, 0x02, 0x04, 0x84, 0x00, 0xEA, 0x42, 0xEA, 0x34, 0xEA, 0x97, + 0x9E, 0x3C, 0xE6, 0x02, 0xE8, 0x0C, 0xDD, 0x40, 0xC0, 0x04, 0xEA, 0x61, 0xEA, 0x28, 0xEA, 0x36, + 0x84, 0x00, 0xEA, 0x42, 0x84, 0x00, 0xEA, 0x6C, 0xEA, 0x85, 0xD5, 0x05, 0x5A, 0x78, 0x02, 0x04, + 0x84, 0x01, 0xEA, 0x42, 0xEA, 0xF6, 0x5A, 0x00, 0x01, 0x05, 0xEA, 0x38, 0x5A, 0x08, 0x01, 0x05, + 0x84, 0x01, 0x3E, 0x07, 0xEE, 0xE0, 0xEA, 0x88, 0x5A, 0x08, 0x01, 0x04, 0xEA, 0x42, 0xEA, 0x78, + 0xFC, 0xC0, 0xFC, 0x00, 0x49, 0x00, 0x04, 0x42, 0x84, 0x00, 0x3E, 0x07, 0xF2, 0xD5, 0xFC, 0x80, + 0xFC, 0x00, 0x49, 0x00, 0x03, 0xF7, 0xEB, 0x59, 0xEA, 0x8B, 0x3C, 0x0E, 0x03, 0xD3, 0x8E, 0x34, + 0xE6, 0x22, 0xE9, 0x07, 0x2E, 0x17, 0xEF, 0x12, 0xC9, 0x04, 0x2E, 0x17, 0xEE, 0xC3, 0xC1, 0x07, + 0x2E, 0x17, 0xF2, 0xBA, 0xC9, 0x04, 0x2E, 0x17, 0xF2, 0xBB, 0xC1, 0x11, 0x8E, 0x02, 0xE6, 0x02, + 0xE8, 0x05, 0x84, 0x02, 0xEA, 0x2D, 0x84, 0x01, 0xD5, 0x07, 0x3C, 0x00, 0x07, 0xF4, 0xC8, 0x12, + 0x84, 0x21, 0x3C, 0x1F, 0xFC, 0x03, 0x3E, 0x00, 0x08, 0x7D, 0xD5, 0x0C, 0xEA, 0x88, 0x5A, 0x08, + 0x01, 0x0A, 0x3C, 0x1D, 0xFC, 0x03, 0x5A, 0x18, 0x02, 0x06, 0x3C, 0x10, 0x07, 0xF4, 0xC9, 0x02, + 0xEA, 0x2D, 0xFC, 0x80, 0x44, 0x22, 0xE3, 0x1C, 0xA4, 0x50, 0x44, 0x02, 0xE2, 0xE8, 0x94, 0xCD, + 0xA5, 0x11, 0xAE, 0xC0, 0x40, 0x30, 0x8C, 0x09, 0xAE, 0xC1, 0x54, 0x10, 0x98, 0x00, 0x94, 0xE2, + 0x40, 0x11, 0x85, 0x75, 0xA4, 0xD2, 0xAE, 0x42, 0x54, 0x42, 0x1F, 0xC0, 0x94, 0x5F, 0x40, 0x40, + 0x90, 0xD5, 0x40, 0x11, 0x84, 0x09, 0xAE, 0x44, 0xA4, 0x53, 0xAF, 0x03, 0x54, 0x31, 0x9E, 0x00, + 0x95, 0x0C, 0x40, 0x32, 0x0D, 0x35, 0xAE, 0xC5, 0x40, 0x30, 0x90, 0x09, 0xAE, 0xC6, 0xA4, 0xD4, + 0x42, 0x10, 0xB0, 0x0B, 0x40, 0x10, 0x8C, 0x24, 0xAE, 0x47, 0xA4, 0x55, 0x54, 0x31, 0x9F, 0x80, + 0x95, 0x0E, 0x40, 0x32, 0x0C, 0xF5, 0xA4, 0x96, 0x10, 0x30, 0x00, 0x08, 0x40, 0x30, 0x88, 0x09, + 0x10, 0x30, 0x00, 0x09, 0x54, 0x10, 0x9C, 0x00, 0x94, 0xD3, 0x40, 0x11, 0x85, 0x55, 0x92, 0x45, + 0x10, 0x10, 0x00, 0x0A, 0x10, 0x20, 0x00, 0x0B, 0xDD, 0x9E, 0x44, 0x22, 0xBC, 0xE8, 0xA6, 0x10, + 0xA4, 0x51, 0x96, 0x17, 0x40, 0x00, 0x05, 0x24, 0xA6, 0x51, 0x96, 0x6F, 0x40, 0x00, 0x04, 0x64, + 0xA6, 0x54, 0x96, 0x67, 0x40, 0x00, 0x07, 0x24, 0x3C, 0x0F, 0xFC, 0x91, 0xDD, 0x9E, 0x84, 0x20, + 0x44, 0x22, 0xE3, 0x1C, 0x44, 0x30, 0x1F, 0x35, 0x44, 0x40, 0x00, 0xCA, 0x97, 0x44, 0xC5, 0x04, + 0x38, 0x41, 0x05, 0x09, 0xD5, 0x03, 0x38, 0x31, 0x05, 0x09, 0x8C, 0x21, 0x92, 0x01, 0x5A, 0x18, + 0x20, 0xF7, 0xDD, 0x9E, 0xC8, 0x05, 0xFC, 0x00, 0x49, 0xFF, 0xFF, 0x96, 0xFC, 0x80, 0x8E, 0x01, + 0x96, 0x00, 0x84, 0x2D, 0xFE, 0x44, 0x94, 0x03, 0x8C, 0x07, 0x44, 0x22, 0xE3, 0x1C, 0x96, 0x00, + 0x38, 0x31, 0x01, 0x01, 0x8C, 0x2C, 0x44, 0x52, 0xE2, 0xE8, 0x96, 0x48, 0x9D, 0x01, 0x38, 0x32, + 0x84, 0x08, 0x38, 0x41, 0x11, 0x01, 0x54, 0x31, 0x9F, 0x00, 0x90, 0x68, 0x88, 0x25, 0x40, 0x31, + 0x90, 0xA4, 0xAE, 0xC9, 0x40, 0x32, 0x0C, 0x09, 0xAE, 0xCA, 0x9C, 0xC2, 0x38, 0x31, 0x0D, 0x01, + 0x54, 0x42, 0x18, 0x00, 0x95, 0x5A, 0x40, 0x42, 0x91, 0x75, 0xAF, 0x0B, 0x9D, 0x03, 0x38, 0x41, + 0x11, 0x01, 0x54, 0x31, 0x9F, 0xC0, 0x95, 0x67, 0x40, 0x32, 0x8C, 0xD5, 0xAE, 0xCC, 0x40, 0x32, + 0x04, 0x09, 0xAE, 0xCD, 0x9C, 0xC4, 0x38, 0x31, 0x0D, 0x01, 0x54, 0x42, 0x1E, 0x00, 0x95, 0x5C, + 0x40, 0x42, 0x91, 0x35, 0xAF, 0x0E, 0x40, 0x41, 0x90, 0x09, 0xAF, 0x0F, 0x9D, 0x05, 0x38, 0x41, + 0x11, 0x01, 0x42, 0x31, 0xB0, 0x0B, 0x40, 0x31, 0x90, 0x24, 0x10, 0x30, 0x80, 0x08, 0x9C, 0xC6, + 0x38, 0x31, 0x0D, 0x01, 0x8C, 0x07, 0x95, 0x5E, 0x38, 0x01, 0x01, 0x01, 0x54, 0x42, 0x1F, 0x80, + 0x40, 0x42, 0x90, 0xF5, 0x94, 0x83, 0x10, 0x40, 0x80, 0x09, 0x40, 0x41, 0x88, 0x09, 0x54, 0x31, + 0x9C, 0x00, 0x40, 0x31, 0x0D, 0x55, 0x92, 0x05, 0x10, 0x40, 0x80, 0x0A, 0x10, 0x30, 0x80, 0x0B, + 0x10, 0x00, 0x80, 0x0C, 0xDD, 0x9E, 0xFC, 0x00, 0x3C, 0x0D, 0xFC, 0x91, 0x49, 0xFF, 0xFF, 0x81, + 0x49, 0xFF, 0xFF, 0x2A, 0x84, 0x01, 0xF8, 0x04, 0x84, 0x02, 0xF8, 0x02, 0x84, 0x03, 0x49, 0xFF, + 0xFF, 0x8B, 0xFC, 0x80, 0xFC, 0x00, 0xEB, 0x48, 0x94, 0x06, 0x04, 0x10, 0x80, 0x16, 0x2E, 0x30, + 0x16, 0x70, 0xEA, 0x64, 0x40, 0x00, 0x04, 0x40, 0x44, 0x12, 0x00, 0x06, 0x88, 0x20, 0xA6, 0x88, + 0x80, 0xA1, 0x96, 0xA7, 0xFE, 0x9F, 0x3E, 0x20, 0x16, 0x70, 0x44, 0x22, 0x00, 0x38, 0x88, 0x40, + 0x44, 0x6D, 0xFF, 0xFA, 0x44, 0x42, 0xE2, 0xE8, 0x9A, 0xE8, 0x88, 0x66, 0x38, 0x32, 0x0C, 0x00, + 0x18, 0x32, 0x80, 0x01, 0xDA, 0xFA, 0x2E, 0x00, 0x16, 0xA2, 0x96, 0x27, 0x10, 0x00, 0x80, 0x32, + 0xFC, 0x80, 0xFC, 0x00, 0x44, 0x62, 0xBC, 0xE8, 0xA6, 0x31, 0xA4, 0x71, 0x94, 0x03, 0x40, 0x00, + 0x05, 0x24, 0xA6, 0x70, 0xFE, 0x0F, 0x49, 0x00, 0x01, 0xBC, 0xAE, 0x34, 0x49, 0xFF, 0xFF, 0x2F, + 0x49, 0xFF, 0xFF, 0xBB, 0x84, 0x01, 0x49, 0xFF, 0xFF, 0xC7, 0xFC, 0x80, 0x54, 0x00, 0x80, 0x7F, + 0x42, 0x10, 0x9C, 0x0B, 0x3E, 0x07, 0xEE, 0xC7, 0x3E, 0x17, 0xEE, 0xB8, 0xDD, 0x9E, 0x44, 0x22, + 0xBD, 0xA4, 0xEA, 0x5A, 0xDD, 0x9E, 0x54, 0x00, 0x80, 0x0F, 0x54, 0x10, 0x80, 0xF0, 0x90, 0x24, + 0x3E, 0x07, 0xEF, 0x60, 0x3E, 0x17, 0xEF, 0x32, 0xDD, 0x9E, 0x44, 0x22, 0xBC, 0x9C, 0xEA, 0x5A, + 0xDD, 0x9E, 0x44, 0x22, 0xE2, 0x48, 0xEA, 0x5A, 0x3C, 0x00, 0x0A, 0xE8, 0x42, 0x10, 0x38, 0x0B, + 0x42, 0x20, 0x34, 0x0B, 0x94, 0x4A, 0x54, 0x30, 0x0F, 0xFF, 0x40, 0x10, 0x88, 0x24, 0x42, 0x00, + 0x30, 0x0B, 0xFE, 0x0F, 0x3E, 0x00, 0x08, 0x7B, 0x3C, 0x38, 0x04, 0x3C, 0x84, 0x01, 0xC3, 0x02, + 0x84, 0x00, 0x3E, 0x00, 0x08, 0x7A, 0xDD, 0x9E, 0x3C, 0x1B, 0xF7, 0xDB, 0xDD, 0x9E, 0xDD, 0x9E, + 0x44, 0x22, 0xDE, 0xA4, 0xEA, 0x5A, 0xDD, 0x9E, 0x44, 0x22, 0xDE, 0xB4, 0xEA, 0x5A, 0xDD, 0x9E, + 0x44, 0x02, 0xBC, 0x74, 0xAE, 0x40, 0x92, 0x28, 0xAE, 0x41, 0xDD, 0x9E, 0x44, 0x22, 0xBD, 0x3C, + 0xEA, 0x5A, 0xDD, 0x9E, 0x3E, 0x17, 0xEE, 0xF7, 0x92, 0x28, 0x3E, 0x17, 0xEE, 0xF6, 0xDD, 0x9E, + 0x44, 0x02, 0xBD, 0x34, 0xAE, 0x40, 0x92, 0x28, 0xAE, 0x41, 0xDD, 0x9E, 0x44, 0x22, 0xD6, 0xF0, + 0xEA, 0x5A, 0xDD, 0x9E, 0x44, 0x22, 0xBC, 0xB4, 0xEA, 0x5A, 0xDD, 0x9E, 0x44, 0x22, 0xD4, 0x6C, + 0xEA, 0x5A, 0xDD, 0x9E, 0x44, 0x22, 0xD8, 0xD8, 0xEA, 0x5A, 0xDD, 0x9E, 0x44, 0x02, 0xD4, 0xF8, + 0x44, 0x10, 0xE9, 0xAC, 0xB6, 0x20, 0x44, 0x10, 0xE9, 0xBE, 0xA8, 0x41, 0x44, 0x10, 0xE9, 0xC6, + 0xA8, 0x42, 0x44, 0x10, 0xE9, 0xDA, 0xA8, 0x43, 0x44, 0x10, 0xE9, 0xE2, 0xA8, 0x44, 0x44, 0x10, + 0xEA, 0x18, 0xA8, 0x45, 0x44, 0x10, 0xEA, 0x1E, 0xA8, 0x46, 0x44, 0x10, 0xEA, 0x20, 0xA8, 0x47, + 0x44, 0x10, 0xEA, 0x28, 0x14, 0x10, 0x00, 0x08, 0x44, 0x10, 0xEA, 0x30, 0x14, 0x10, 0x00, 0x09, + 0x44, 0x10, 0xEA, 0x3C, 0x14, 0x10, 0x00, 0x0A, 0x44, 0x10, 0xEA, 0x44, 0x14, 0x10, 0x00, 0x0B, + 0x44, 0x10, 0xEA, 0x50, 0x14, 0x10, 0x00, 0x0C, 0x44, 0x10, 0xEA, 0x5C, 0x14, 0x10, 0x00, 0x0D, + 0x44, 0x10, 0xEA, 0x64, 0x14, 0x10, 0x00, 0x0E, 0x44, 0x10, 0xEA, 0x6C, 0x14, 0x10, 0x00, 0x33, + 0x44, 0x10, 0xEA, 0x74, 0x14, 0x10, 0x00, 0x34, 0xDD, 0x9E, 0x96, 0x57, 0x96, 0xCF, 0x40, 0x30, + 0x8D, 0x04, 0x94, 0x93, 0x44, 0x52, 0xBC, 0xE8, 0x40, 0x41, 0x91, 0x44, 0x96, 0x90, 0xAE, 0x28, + 0xFF, 0x17, 0x84, 0x03, 0xAE, 0x29, 0xAD, 0x29, 0xDD, 0x9E, 0x3E, 0x07, 0xF0, 0x70, 0x44, 0x00, + 0x00, 0x3F, 0xEA, 0xBA, 0x54, 0x00, 0x80, 0x3F, 0x40, 0x00, 0x08, 0xE4, 0x3C, 0x0B, 0xF8, 0x39, + 0x84, 0x00, 0x3E, 0x17, 0xEE, 0xCC, 0x44, 0x32, 0xDD, 0x98, 0x80, 0x20, 0x97, 0x14, 0xC4, 0x05, + 0x38, 0x11, 0x80, 0x08, 0x8C, 0x01, 0x96, 0x00, 0x8C, 0x21, 0x96, 0x48, 0x92, 0x41, 0x5A, 0x18, + 0x09, 0xF7, 0x3E, 0x07, 0xEE, 0xD0, 0xDD, 0x9E, 0x94, 0x4B, 0x44, 0x32, 0xBC, 0xE8, 0x96, 0x48, + 0xAE, 0x18, 0x40, 0x20, 0x89, 0x84, 0xFA, 0x00, 0xAE, 0x19, 0xAC, 0x99, 0xDD, 0x9E, 0x44, 0x32, + 0xBC, 0xE8, 0x96, 0x4D, 0xAE, 0x18, 0x40, 0x20, 0x89, 0x64, 0xFA, 0x03, 0xAE, 0x19, 0xAC, 0x99, + 0xDD, 0x9E, 0xFC, 0x00, 0x44, 0x62, 0xBC, 0xE8, 0xAE, 0x30, 0xFA, 0x04, 0xAE, 0x31, 0x97, 0x0F, + 0x84, 0x07, 0x40, 0x52, 0xB4, 0x08, 0x40, 0x42, 0x91, 0x64, 0xFE, 0x46, 0xFE, 0x67, 0xFE, 0xC6, + 0x94, 0x93, 0x40, 0x30, 0x8D, 0x04, 0x96, 0x90, 0xFE, 0xD7, 0xAC, 0xF1, 0xFC, 0x80, 0x96, 0xCF, + 0x40, 0x42, 0x34, 0x08, 0x40, 0x32, 0x0D, 0x64, 0x96, 0x97, 0x94, 0x4B, 0x44, 0x52, 0xBC, 0xE8, + 0x40, 0x21, 0x89, 0x04, 0x96, 0x48, 0xAE, 0x28, 0xFE, 0x57, 0xFA, 0x05, 0xAE, 0x29, 0xAC, 0x69, + 0xDD, 0x9E, 0xFC, 0x00, 0x80, 0xC0, 0x80, 0x01, 0xCE, 0x2E, 0xDD, 0x43, 0x5A, 0x00, 0x02, 0x08, + 0xFA, 0x04, 0xEA, 0xBA, 0xEB, 0xA9, 0x44, 0x0F, 0xA0, 0x61, 0xD5, 0x1A, 0x2E, 0x10, 0x0F, 0x6C, + 0x5A, 0x18, 0x02, 0x08, 0xFA, 0x04, 0xEA, 0xBA, 0xEB, 0xA9, 0x44, 0x00, 0x49, 0xF1, 0xD5, 0x10, + 0x5A, 0x18, 0x03, 0x08, 0xFA, 0x04, 0xEA, 0xBA, 0xEB, 0xA9, 0x44, 0x00, 0x69, 0xC1, 0xD5, 0x08, + 0x5A, 0x18, 0x01, 0x0A, 0xFA, 0x04, 0xEA, 0xBA, 0xEB, 0xA9, 0x44, 0x0F, 0x89, 0x99, 0x3C, 0x0B, + 0xF8, 0x39, 0xD5, 0x41, 0xC9, 0x40, 0xFA, 0x04, 0xEA, 0xBA, 0x3E, 0x17, 0xF0, 0x70, 0x44, 0x0F, + 0xA9, 0x61, 0xD5, 0xF6, 0x5A, 0x18, 0x01, 0x1A, 0x2E, 0x20, 0x0F, 0x6D, 0x5A, 0x28, 0x02, 0x05, + 0xFA, 0x2E, 0x84, 0x44, 0xD5, 0x0F, 0x5A, 0x28, 0x03, 0x05, 0xFA, 0x28, 0x84, 0x46, 0xD5, 0x0A, + 0x5A, 0x28, 0x01, 0x06, 0x80, 0x02, 0xFA, 0x23, 0x84, 0x48, 0xD5, 0x04, 0xCA, 0x24, 0x84, 0x2C, + 0x84, 0x4A, 0x49, 0xFF, 0xFF, 0x7B, 0xD5, 0x1F, 0x2E, 0x40, 0x0F, 0x6C, 0x5A, 0x48, 0x02, 0x05, + 0x84, 0x01, 0xFA, 0x2E, 0xD5, 0x05, 0x5A, 0x48, 0x03, 0x07, 0x84, 0x01, 0xFA, 0x28, 0x80, 0x40, + 0x80, 0x60, 0xD5, 0x0F, 0x5A, 0x48, 0x01, 0x08, 0x80, 0x04, 0x80, 0x44, 0x80, 0x64, 0xFA, 0x23, + 0x84, 0x84, 0xD5, 0x07, 0xCC, 0x08, 0x84, 0x01, 0x84, 0x2C, 0x80, 0x40, 0x80, 0x60, 0x84, 0x85, + 0x49, 0xFF, 0xFF, 0x87, 0x2E, 0x07, 0xEB, 0x14, 0xC8, 0x07, 0x84, 0x01, 0x3E, 0x07, 0xEB, 0x14, + 0x3E, 0x07, 0xF3, 0x50, 0xD5, 0x09, 0x5A, 0x08, 0x01, 0x08, 0x84, 0x00, 0x3E, 0x07, 0xF3, 0x50, + 0x84, 0x02, 0x3E, 0x07, 0xEB, 0x14, 0xFC, 0x80, 0xFC, 0x20, 0x84, 0x81, 0x9F, 0x89, 0x40, 0x62, + 0x18, 0x0C, 0x9B, 0x0B, 0x40, 0x21, 0x10, 0x0C, 0x84, 0x80, 0x4C, 0x40, 0x80, 0x0A, 0x40, 0x70, + 0x18, 0x02, 0xC7, 0x02, 0xFE, 0x15, 0x8C, 0x81, 0x94, 0x01, 0x97, 0x20, 0xD5, 0xF7, 0x52, 0x31, + 0x80, 0x01, 0x88, 0x64, 0x40, 0x00, 0x0C, 0x0D, 0x96, 0x00, 0xFE, 0x2D, 0xFC, 0xA0, 0xFC, 0x00, + 0xFA, 0x20, 0xFA, 0x49, 0x84, 0x65, 0x84, 0x80, 0x84, 0xAF, 0xF8, 0x09, 0xFC, 0x80, 0xFC, 0x00, + 0x84, 0x80, 0xFA, 0x29, 0x44, 0x20, 0x00, 0x39, 0x84, 0x66, 0x80, 0xA4, 0x49, 0xFF, 0xFF, 0xD6, + 0xFC, 0x80, 0xFC, 0x00, 0x44, 0x10, 0xFF, 0xFF, 0x4C, 0x00, 0x80, 0x44, 0x3C, 0x53, 0xF8, 0x8C, + 0x84, 0x60, 0x3E, 0x37, 0xEF, 0x63, 0xD0, 0x05, 0x3C, 0x23, 0xF8, 0x8D, 0x4C, 0x01, 0x40, 0x0F, + 0xEB, 0x5F, 0xC0, 0x08, 0x2E, 0x07, 0xF6, 0x94, 0xC8, 0x05, 0x84, 0x21, 0x3E, 0x17, 0xF6, 0x94, + 0xD5, 0x31, 0x84, 0x00, 0x3E, 0x07, 0xF6, 0x94, 0xD5, 0x2A, 0x2E, 0x17, 0xF6, 0x94, 0xE6, 0x23, + 0xE8, 0x0E, 0x3C, 0x53, 0xFB, 0x49, 0xC5, 0x05, 0xD0, 0x04, 0x3E, 0x37, 0xF6, 0x94, 0xD5, 0x04, + 0x8C, 0x21, 0x3E, 0x17, 0xF6, 0x94, 0x3C, 0x0B, 0xFB, 0x49, 0xD5, 0x1B, 0x2E, 0x17, 0xEF, 0x4D, + 0xE6, 0x22, 0xE8, 0x09, 0x44, 0x22, 0xBD, 0x90, 0x38, 0x01, 0x05, 0x09, 0x8C, 0x21, 0x3E, 0x17, + 0xEF, 0x4D, 0xD5, 0x07, 0x5A, 0x18, 0x02, 0x06, 0x3C, 0x2B, 0xF8, 0x8C, 0x3C, 0x0B, 0xF8, 0x8D, + 0x84, 0x00, 0x3E, 0x07, 0xF6, 0x94, 0x84, 0x00, 0x3C, 0x0B, 0xFB, 0x49, 0x84, 0x01, 0xD5, 0x02, + 0x84, 0x00, 0xFC, 0x80, 0xFC, 0x00, 0x2E, 0x17, 0xEF, 0x31, 0x44, 0x20, 0xFF, 0xEE, 0x8C, 0x21, + 0x3E, 0x17, 0xEF, 0x31, 0x2E, 0x17, 0xEF, 0x15, 0xC9, 0x0D, 0x3E, 0x17, 0xEE, 0xCF, 0x84, 0x21, + 0x3C, 0x0F, 0xFC, 0x54, 0x3E, 0x17, 0xEF, 0x15, 0x4C, 0x01, 0x40, 0x1C, 0x3E, 0x17, 0xEE, 0xCF, + 0xD5, 0x18, 0x4C, 0x01, 0x40, 0x08, 0x2E, 0x27, 0xEE, 0xCF, 0x8C, 0x41, 0x3E, 0x27, 0xEE, 0xCF, + 0xD5, 0x07, 0x3C, 0x2D, 0xFC, 0x54, 0x40, 0x01, 0x01, 0x44, 0x3C, 0x0F, 0xFC, 0x54, 0x8C, 0x21, + 0x3E, 0x17, 0xEF, 0x15, 0x2E, 0x17, 0xEE, 0xCF, 0xC1, 0x06, 0x44, 0x00, 0xFF, 0xEE, 0xD5, 0x03, + 0x44, 0x0F, 0xAA, 0xAA, 0xFC, 0x80, 0x92, 0x00, 0xFC, 0x00, 0x2E, 0x07, 0xEF, 0x35, 0xE6, 0x05, + 0xE8, 0x5A, 0x44, 0xF0, 0xEE, 0x2C, 0xEA, 0x90, 0xEA, 0x3C, 0xDD, 0x0F, 0x06, 0x7E, 0xA8, 0x88, + 0x9A, 0x00, 0x84, 0x1E, 0x2E, 0x67, 0xF2, 0xB4, 0x3E, 0x07, 0xEE, 0xCC, 0x84, 0x1F, 0x3C, 0x0B, + 0xF7, 0xD5, 0xCE, 0x0C, 0x80, 0x06, 0x2E, 0x17, 0xF3, 0x50, 0x2E, 0x20, 0x0F, 0x6C, 0x2E, 0x30, + 0x0F, 0x6D, 0x49, 0xFF, 0xFE, 0xC0, 0x84, 0x01, 0xD5, 0x26, 0x5A, 0x68, 0x01, 0x15, 0xDD, 0x43, + 0x5A, 0x08, 0x02, 0x07, 0x84, 0x00, 0x44, 0x10, 0x06, 0xE4, 0xFA, 0x4C, 0xD5, 0x05, 0x84, 0x00, + 0x44, 0x10, 0x01, 0x72, 0x80, 0x46, 0x49, 0xFF, 0xFE, 0x7C, 0x2E, 0x07, 0xEF, 0x63, 0xC0, 0x13, + 0x84, 0x02, 0xD5, 0x11, 0x5A, 0x68, 0x02, 0x2A, 0x84, 0x00, 0x84, 0x61, 0x80, 0x20, 0xFA, 0x4E, + 0x80, 0x83, 0x80, 0xA6, 0x49, 0xFF, 0xFE, 0x77, 0x2E, 0x07, 0xEF, 0x63, 0x8E, 0x01, 0x3E, 0x07, + 0xEF, 0x63, 0x84, 0x00, 0x3E, 0x07, 0xF2, 0xB4, 0xD5, 0x18, 0x84, 0x01, 0x80, 0x20, 0x80, 0x40, + 0xF8, 0x0E, 0xD5, 0x11, 0x84, 0x01, 0x84, 0x60, 0x80, 0x20, 0x80, 0x40, 0x80, 0x83, 0x49, 0xFF, + 0xFE, 0x1E, 0x84, 0xC3, 0xD5, 0x0B, 0x84, 0x01, 0x84, 0x20, 0x80, 0x40, 0x49, 0xFF, 0xFE, 0x27, + 0x84, 0xC2, 0xD5, 0x04, 0x84, 0xC0, 0xD5, 0x02, 0x84, 0xC1, 0x2E, 0x07, 0xF0, 0x71, 0x3C, 0x13, + 0xF8, 0x39, 0x94, 0x03, 0x40, 0x00, 0x05, 0x24, 0x2E, 0x17, 0xF0, 0x70, 0xFE, 0x0F, 0x49, 0xFF, + 0xFF, 0x10, 0x3E, 0x07, 0xF0, 0x74, 0x84, 0x00, 0x3E, 0x07, 0xEF, 0x1F, 0x80, 0x06, 0xFC, 0x80, + 0xFC, 0x00, 0x3C, 0x0D, 0xFC, 0x3B, 0xC8, 0x2B, 0x2E, 0x07, 0xEF, 0x35, 0xE6, 0x05, 0xE8, 0x21, + 0x44, 0xF0, 0xEF, 0x1C, 0xEA, 0x90, 0xEA, 0x3C, 0x4A, 0x00, 0x3C, 0x00, 0x06, 0x16, 0x34, 0x1E, + 0x26, 0x00, 0x3C, 0x03, 0xF7, 0xD5, 0x49, 0xFF, 0xFE, 0xFE, 0x5A, 0x08, 0x01, 0x2E, 0x84, 0x03, + 0xD5, 0x14, 0x2E, 0x07, 0xEE, 0xF3, 0xC0, 0xFC, 0xD5, 0x27, 0x84, 0x04, 0xEB, 0x64, 0x84, 0x00, + 0xD5, 0x05, 0x2E, 0x07, 0xF3, 0x51, 0xC8, 0x20, 0x84, 0x01, 0x3E, 0x07, 0xF3, 0x51, 0xD5, 0x1C, + 0xEA, 0x59, 0xE6, 0x0D, 0xE9, 0x19, 0x84, 0x00, 0xEB, 0x64, 0xD5, 0x16, 0x2E, 0x10, 0x0A, 0x92, + 0xE6, 0x2D, 0xE9, 0x12, 0x2E, 0x17, 0xEF, 0x35, 0x5A, 0x18, 0x04, 0x0B, 0x5C, 0xF0, 0x00, 0x3D, + 0xE9, 0x0B, 0x84, 0x00, 0xEB, 0x64, 0xFA, 0x18, 0x3E, 0x07, 0xEF, 0x63, 0xD5, 0x05, 0x5A, 0x18, + 0x03, 0x04, 0xE6, 0x09, 0xD5, 0xE8, 0xFC, 0x80, 0xFC, 0x40, 0x80, 0xE0, 0x84, 0x01, 0x3E, 0x07, + 0xEF, 0x14, 0xB4, 0xA7, 0x44, 0x10, 0xFF, 0xEE, 0xD9, 0x18, 0x2E, 0x07, 0xEF, 0x35, 0xC8, 0x03, + 0xA6, 0x3E, 0xC8, 0x06, 0x3C, 0x0D, 0xFC, 0x3B, 0x8C, 0x01, 0x3C, 0x0F, 0xFC, 0x3B, 0x3C, 0x0D, + 0xFC, 0x3B, 0xE6, 0x05, 0xE9, 0x06, 0x84, 0x00, 0x3C, 0x2C, 0x02, 0x24, 0x80, 0x20, 0xDD, 0x22, + 0x84, 0x00, 0x3E, 0x00, 0x08, 0x7D, 0xD5, 0x61, 0x3E, 0x00, 0x08, 0x7D, 0xB4, 0xC7, 0x85, 0x20, + 0x40, 0x03, 0x40, 0x09, 0x54, 0xA0, 0x00, 0x0F, 0x46, 0x00, 0x00, 0x8A, 0x50, 0x00, 0x0A, 0x55, + 0x3C, 0x9F, 0xFC, 0x3B, 0x4C, 0x60, 0x00, 0x52, 0x80, 0x06, 0x49, 0xFF, 0xFE, 0x8A, 0x4C, 0x05, + 0x40, 0x48, 0x2E, 0x07, 0xEE, 0xCC, 0x5A, 0x00, 0xFE, 0x17, 0xA6, 0x7C, 0x44, 0x02, 0xD4, 0xF8, + 0x38, 0x20, 0x06, 0x02, 0xA6, 0x3D, 0x96, 0x71, 0xDD, 0x22, 0x2E, 0x07, 0xEE, 0xD0, 0xA6, 0x7E, + 0x8E, 0x01, 0xE0, 0x20, 0xE9, 0x05, 0x84, 0x1E, 0x3E, 0x07, 0xEE, 0xCC, 0xD5, 0x36, 0x3E, 0x97, + 0xEF, 0x14, 0xD5, 0x33, 0x2E, 0x17, 0xEF, 0x35, 0xA6, 0x3E, 0xC1, 0x21, 0xC8, 0x09, 0x3C, 0x03, + 0xF8, 0x39, 0x4C, 0x60, 0x00, 0x2B, 0x84, 0x01, 0x3C, 0x0F, 0xFC, 0x3B, 0xD5, 0x26, 0xEB, 0x5F, + 0xC8, 0x05, 0x3E, 0x07, 0xF2, 0xD4, 0x96, 0x71, 0xD5, 0x0E, 0x2E, 0x17, 0xF2, 0xD4, 0x8C, 0x21, + 0x96, 0x48, 0xE6, 0x25, 0xE8, 0x04, 0x3E, 0x17, 0xF2, 0xD4, 0xD5, 0x17, 0x3E, 0x97, 0xF2, 0xD4, + 0x80, 0x09, 0x80, 0x29, 0x3C, 0x2C, 0x02, 0x24, 0xDD, 0x22, 0xD5, 0x0F, 0xC8, 0x0E, 0x97, 0xB1, + 0x3C, 0x6B, 0xF7, 0xD5, 0x3C, 0x6E, 0x02, 0x1C, 0x3C, 0x0E, 0x02, 0x1D, 0xD5, 0x06, 0x2E, 0x07, + 0xEE, 0xF3, 0x8C, 0x01, 0x3E, 0x07, 0xEE, 0xF3, 0xFC, 0xC0, 0xFC, 0x31, 0x84, 0x20, 0xB0, 0xC1, + 0xB0, 0x8C, 0xA5, 0x00, 0x38, 0x41, 0x85, 0x09, 0xA5, 0x01, 0x38, 0x41, 0x05, 0x09, 0x8C, 0x21, + 0x8C, 0x10, 0x5A, 0x18, 0x0B, 0xF8, 0x84, 0x00, 0xB1, 0x17, 0x82, 0x20, 0x86, 0x01, 0x98, 0x58, + 0x22, 0x50, 0x80, 0x01, 0x98, 0x50, 0x22, 0x70, 0x80, 0x01, 0x38, 0x11, 0x00, 0x11, 0x38, 0x61, + 0x80, 0x11, 0x42, 0xF3, 0x84, 0x24, 0xFE, 0x4A, 0xFE, 0x7C, 0x42, 0x13, 0x14, 0x75, 0x42, 0xF2, + 0x98, 0x73, 0xE0, 0x2F, 0x80, 0x30, 0x40, 0x18, 0xBC, 0x1A, 0x38, 0x12, 0x00, 0x09, 0x8C, 0x02, + 0x5A, 0x08, 0x14, 0xE7, 0x84, 0x20, 0x80, 0x01, 0x98, 0xA1, 0x02, 0x21, 0x00, 0x09, 0x8E, 0x22, + 0x96, 0x94, 0x40, 0x01, 0x00, 0x24, 0x5A, 0x1F, 0xEC, 0xF9, 0xFC, 0xB1, 0x84, 0x20, 0x80, 0x81, + 0x80, 0x41, 0x40, 0x30, 0x04, 0x20, 0xA4, 0xD8, 0x96, 0xDB, 0xE0, 0x43, 0xE8, 0x03, 0x97, 0x09, + 0x80, 0x43, 0x8C, 0x21, 0x5A, 0x18, 0xC8, 0xF7, 0x84, 0x20, 0x5E, 0xF1, 0x01, 0xC2, 0xAC, 0x40, + 0xE9, 0x13, 0xFC, 0x00, 0x5E, 0xF1, 0x03, 0xE8, 0xE8, 0x05, 0xEB, 0x5F, 0x8C, 0x01, 0x3E, 0x07, + 0xF2, 0xD5, 0x5C, 0xF2, 0x00, 0x64, 0xE8, 0x04, 0x44, 0x02, 0x46, 0x00, 0xD5, 0x03, 0x44, 0x02, + 0x46, 0xB0, 0xF8, 0x36, 0xFC, 0x80, 0x44, 0x00, 0xFF, 0xEE, 0xDD, 0x9E, 0xFC, 0x00, 0x84, 0x80, + 0x92, 0x41, 0x80, 0x64, 0x80, 0xA4, 0xD2, 0x0C, 0x0A, 0x60, 0x00, 0x01, 0x97, 0xB1, 0xE2, 0x66, + 0x40, 0x42, 0xBC, 0x1B, 0x8C, 0xA1, 0x40, 0x33, 0x3C, 0x1B, 0x97, 0x69, 0xD5, 0xF5, 0x84, 0xA0, + 0x96, 0x29, 0xE2, 0x02, 0xE8, 0x0C, 0x40, 0x60, 0x94, 0x20, 0xA5, 0xB0, 0x97, 0xB1, 0xE2, 0x66, + 0xE8, 0x04, 0x99, 0x02, 0x97, 0x21, 0x80, 0x66, 0x8C, 0xA1, 0xD5, 0xF3, 0x5C, 0xF1, 0x81, 0xC2, + 0xE9, 0x12, 0x5C, 0xF1, 0x83, 0xE8, 0xE8, 0x05, 0xEB, 0x5F, 0x8C, 0x01, 0x3E, 0x07, 0xF2, 0xD5, + 0xE2, 0x82, 0xE8, 0x04, 0x44, 0x02, 0x46, 0x00, 0xD5, 0x03, 0x44, 0x02, 0x46, 0xB0, 0x49, 0xFF, + 0xFF, 0x6E, 0xFC, 0x80, 0x44, 0x00, 0xFF, 0xEE, 0xFC, 0x80, 0x92, 0x00, 0xE6, 0x06, 0xE8, 0x6E, + 0x44, 0xF0, 0xF1, 0xCC, 0xEA, 0x90, 0xEA, 0x3C, 0x4A, 0x00, 0x3C, 0x00, 0x06, 0x24, 0x40, 0xCE, + 0x60, 0x96, 0x84, 0x01, 0xEA, 0xF1, 0xAE, 0x08, 0x44, 0x23, 0xF2, 0x49, 0x84, 0x22, 0xAE, 0x50, + 0x44, 0x23, 0xF2, 0x4A, 0xAE, 0x10, 0x44, 0x23, 0xF2, 0x4B, 0xAE, 0x50, 0x84, 0x64, 0xD5, 0x2D, + 0x84, 0x1F, 0xEA, 0xF1, 0xAE, 0x08, 0x44, 0x13, 0xF2, 0x49, 0xAE, 0x08, 0x44, 0x13, 0xF2, 0x4A, + 0xAE, 0x08, 0x44, 0x13, 0xF2, 0x4B, 0xAE, 0x08, 0x84, 0x48, 0xD5, 0x39, 0x84, 0x01, 0xEA, 0xF1, + 0xAE, 0x08, 0x44, 0x13, 0xF2, 0x49, 0xAE, 0x08, 0x44, 0x13, 0xF2, 0x4A, 0xAE, 0x08, 0x44, 0x13, + 0xF2, 0x4B, 0xAE, 0x08, 0x44, 0x13, 0xF2, 0x4C, 0xAE, 0x08, 0xD5, 0x2C, 0x84, 0x01, 0xEA, 0xF1, + 0xAE, 0x08, 0x44, 0x23, 0xF2, 0x49, 0x84, 0x24, 0xAE, 0x50, 0x44, 0x23, 0xF2, 0x4A, 0xAE, 0x10, + 0x44, 0x23, 0xF2, 0x4B, 0xAE, 0x50, 0x84, 0x6C, 0x44, 0x23, 0xF2, 0x4C, 0xAE, 0xD0, 0x44, 0x23, + 0xF2, 0x4D, 0xAE, 0x50, 0x44, 0x23, 0xF2, 0x4E, 0xAE, 0x10, 0x44, 0x23, 0xF2, 0x4F, 0xAE, 0x50, + 0xD5, 0x1A, 0x84, 0x00, 0xEA, 0xF1, 0xAE, 0x08, 0x44, 0x13, 0xF2, 0x49, 0xAE, 0x08, 0x44, 0x13, + 0xF2, 0x4A, 0xAE, 0x08, 0x44, 0x13, 0xF2, 0x4B, 0xAE, 0x08, 0x84, 0x41, 0x44, 0x13, 0xF2, 0x4C, + 0xAE, 0x88, 0x44, 0x13, 0xF2, 0x4D, 0xAE, 0x08, 0x44, 0x13, 0xF2, 0x4E, 0xAE, 0x08, 0x44, 0x13, + 0xF2, 0x4F, 0xAE, 0x08, 0x44, 0x13, 0xF2, 0x50, 0xAE, 0x08, 0xDD, 0x9E, 0x92, 0x00, 0xC1, 0x03, + 0x58, 0x00, 0x00, 0x10, 0x96, 0x00, 0x44, 0x13, 0xF2, 0x51, 0xAE, 0x08, 0xDD, 0x9E, 0x40, 0x00, + 0x3C, 0x08, 0x92, 0x10, 0x44, 0x23, 0xF2, 0x44, 0x40, 0x10, 0xBC, 0x08, 0xAC, 0x10, 0x92, 0x30, + 0x44, 0x03, 0xF2, 0x46, 0xAC, 0x40, 0xDD, 0x9E, 0x84, 0x21, 0x44, 0x03, 0xF2, 0x40, 0xAE, 0x40, + 0xDD, 0x5B, 0xEA, 0x21, 0xAE, 0x88, 0xA6, 0x40, 0x5A, 0x10, 0x01, 0xFF, 0xDD, 0x9E, 0x44, 0x13, + 0xF2, 0x58, 0xA4, 0x48, 0xAC, 0x40, 0x44, 0x13, 0xF2, 0x5A, 0xA4, 0x48, 0xAC, 0x41, 0x44, 0x13, + 0xF2, 0x5C, 0xA4, 0x48, 0xAC, 0x42, 0x44, 0x13, 0xF2, 0x5E, 0xA4, 0x48, 0xAC, 0x43, 0x44, 0x13, + 0xF2, 0x60, 0xA6, 0x48, 0xEB, 0xDF, 0xDD, 0x9E, 0xFC, 0x02, 0xF0, 0x81, 0x80, 0x02, 0xF3, 0x83, + 0xF1, 0x82, 0x49, 0xFF, 0xFF, 0x55, 0xF0, 0x01, 0xF1, 0x02, 0x49, 0xFF, 0xFF, 0xCA, 0x49, 0xFF, + 0xFF, 0xD5, 0xF0, 0x03, 0x49, 0xFF, 0xFF, 0xDD, 0xFC, 0x82, 0xFC, 0x02, 0xF0, 0x81, 0x44, 0x03, + 0xF2, 0x42, 0xF1, 0x82, 0xF2, 0x83, 0xAF, 0x40, 0x00, 0x1F, 0x80, 0x20, 0x44, 0x03, 0xF2, 0x43, + 0xAE, 0x40, 0x44, 0x03, 0xF2, 0x52, 0xAC, 0xC0, 0x44, 0x03, 0xF2, 0x54, 0xAD, 0x00, 0x84, 0x21, + 0x44, 0x03, 0xF2, 0x56, 0xAC, 0x40, 0x00, 0x1F, 0x80, 0x24, 0x44, 0x03, 0xF2, 0x41, 0xAE, 0x40, + 0x00, 0x0F, 0x80, 0x28, 0x00, 0x1F, 0x80, 0x2C, 0x49, 0xFF, 0xFF, 0x9B, 0xF0, 0x01, 0xF1, 0x02, + 0xF2, 0x03, 0xF3, 0x0C, 0x49, 0xFF, 0xFF, 0xCA, 0xFC, 0x82, 0x44, 0x03, 0x8C, 0xF0, 0x3C, 0x0F, + 0xFC, 0x92, 0x44, 0x1F, 0xC6, 0x78, 0x44, 0x03, 0xF1, 0x42, 0xAC, 0x40, 0x84, 0x00, 0x44, 0x13, + 0x8D, 0x08, 0xB6, 0x01, 0x3C, 0x1D, 0xFC, 0x92, 0xA8, 0x0F, 0x3C, 0x1D, 0xFC, 0x92, 0x14, 0x00, + 0x80, 0x08, 0xDD, 0x9E, 0x84, 0x20, 0x3C, 0x0F, 0xFC, 0x21, 0xAC, 0x43, 0xDD, 0x9E, 0x3C, 0x3D, + 0xFC, 0x21, 0x92, 0x01, 0x92, 0x21, 0x92, 0x41, 0xAC, 0x18, 0xAC, 0x59, 0xAC, 0x9A, 0xDD, 0x9E, + 0x3C, 0x1D, 0xFC, 0x21, 0xA6, 0x82, 0x10, 0x20, 0x80, 0x0C, 0xA6, 0x83, 0x10, 0x20, 0x80, 0x0D, + 0xA6, 0x80, 0xA6, 0x01, 0x10, 0x20, 0x80, 0x0E, 0x10, 0x00, 0x80, 0x0F, 0xDD, 0x9E, 0x3C, 0x1D, + 0xFC, 0x21, 0xA6, 0x82, 0x10, 0x20, 0x80, 0x10, 0xA6, 0x83, 0x10, 0x20, 0x80, 0x11, 0xA6, 0x80, + 0xA6, 0x01, 0x10, 0x20, 0x80, 0x12, 0x10, 0x00, 0x80, 0x13, 0xDD, 0x9E, 0x3C, 0x1D, 0xFC, 0x21, + 0xA6, 0x82, 0x10, 0x20, 0x80, 0x14, 0xA6, 0x83, 0x10, 0x20, 0x80, 0x15, 0xA6, 0x80, 0xA6, 0x01, + 0x10, 0x20, 0x80, 0x16, 0x10, 0x00, 0x80, 0x17, 0xDD, 0x9E, 0xFC, 0x01, 0xB6, 0x3F, 0xF2, 0x81, + 0x49, 0xFF, 0xFF, 0xD0, 0xB4, 0x1F, 0x49, 0xFF, 0xFF, 0xDC, 0xF0, 0x01, 0x49, 0xFF, 0xFF, 0xE8, + 0xFC, 0x81, 0xFC, 0x24, 0x00, 0x7F, 0x80, 0x60, 0xF0, 0x81, 0xF1, 0x82, 0xF2, 0x83, 0x00, 0x1F, + 0x80, 0x3C, 0x00, 0x2F, 0x80, 0x38, 0x00, 0x0F, 0x80, 0x40, 0x00, 0x6F, 0x80, 0x4C, 0x10, 0x5F, + 0x80, 0x16, 0x10, 0x3F, 0x80, 0x14, 0x10, 0x2F, 0x80, 0x17, 0x10, 0x4F, 0x80, 0x15, 0x10, 0x1F, + 0x80, 0x1A, 0x10, 0x3F, 0x80, 0x18, 0x10, 0x0F, 0x80, 0x1B, 0x10, 0x4F, 0x80, 0x19, 0xCF, 0x08, + 0x10, 0x5F, 0x80, 0x1E, 0x10, 0x3F, 0x80, 0x1C, 0x10, 0x2F, 0x80, 0x1F, 0xD5, 0x07, 0x10, 0x1F, + 0x80, 0x1E, 0x10, 0x3F, 0x80, 0x1C, 0x10, 0x0F, 0x80, 0x1F, 0x3C, 0x0D, 0xFC, 0x92, 0x10, 0x4F, + 0x80, 0x1D, 0xF8, 0x55, 0xB0, 0x05, 0xB0, 0x46, 0xB0, 0x87, 0xF8, 0x56, 0xF0, 0x01, 0xF1, 0x02, + 0xF2, 0x03, 0xF8, 0x57, 0x3C, 0x0D, 0xFC, 0x21, 0x02, 0x1F, 0x80, 0x28, 0xAC, 0x44, 0x00, 0x1F, + 0x80, 0x54, 0x00, 0x2F, 0x80, 0x44, 0xFE, 0x77, 0x52, 0x63, 0x00, 0x20, 0x40, 0x60, 0x98, 0x24, + 0x00, 0x1F, 0x80, 0x48, 0x10, 0x60, 0x00, 0x0A, 0x58, 0x10, 0x80, 0x40, 0xFE, 0x57, 0x10, 0x10, + 0x00, 0x0B, 0x22, 0x1F, 0x80, 0x2C, 0x12, 0x10, 0x00, 0x0C, 0x22, 0x1F, 0x80, 0x2E, 0x12, 0x10, + 0x00, 0x0D, 0xDD, 0x47, 0xDD, 0x45, 0xAE, 0x40, 0x44, 0x03, 0xF1, 0x40, 0x84, 0x21, 0xAE, 0x40, + 0xA6, 0x40, 0x5A, 0x10, 0x01, 0xFF, 0xFC, 0xA4, 0xFC, 0x04, 0xF0, 0x81, 0x94, 0x19, 0x96, 0x00, + 0xF1, 0x82, 0x10, 0x0F, 0x80, 0x17, 0x84, 0x22, 0x10, 0x0F, 0x80, 0x1B, 0x84, 0xC1, 0x3C, 0x0D, + 0xFC, 0x92, 0x10, 0x3F, 0x80, 0x14, 0x10, 0x4F, 0x80, 0x15, 0x10, 0x3F, 0x80, 0x18, 0x10, 0x4F, + 0x80, 0x19, 0x10, 0x3F, 0x80, 0x1C, 0x10, 0x3F, 0x80, 0x1F, 0x10, 0x4F, 0x80, 0x1D, 0xF2, 0x83, + 0x10, 0x1F, 0x80, 0x16, 0x10, 0x1F, 0x80, 0x1A, 0x10, 0x6F, 0x80, 0x1E, 0x49, 0xFF, 0xFF, 0x34, + 0xB0, 0x05, 0xB0, 0x46, 0xB0, 0x87, 0x49, 0xFF, 0xFF, 0x6A, 0xF0, 0x01, 0xF1, 0x02, 0xF2, 0x03, + 0x49, 0xFF, 0xFF, 0x2F, 0x3C, 0x0D, 0xFC, 0x21, 0x84, 0x20, 0x84, 0x49, 0xAC, 0x44, 0x10, 0x10, + 0x00, 0x0B, 0x10, 0x20, 0x00, 0x0A, 0xDD, 0x47, 0xDD, 0x45, 0xAE, 0x40, 0x44, 0x03, 0xF1, 0x40, + 0xAF, 0x80, 0xA6, 0x40, 0x5A, 0x10, 0x01, 0xFF, 0xFC, 0x84, 0x44, 0x03, 0xF1, 0x48, 0xA6, 0x40, + 0x44, 0x03, 0xF1, 0x49, 0xA6, 0x00, 0xEB, 0x44, 0x96, 0x01, 0xDD, 0x9E, 0x44, 0x10, 0x00, 0x55, + 0xDD, 0x45, 0xAE, 0x40, 0xEA, 0x7B, 0xA6, 0x08, 0x5A, 0x00, 0x01, 0xFF, 0x84, 0x21, 0x44, 0x03, + 0xF3, 0x80, 0xAE, 0x40, 0xDD, 0x5B, 0xEA, 0x21, 0xAE, 0x88, 0xA6, 0x40, 0x5A, 0x10, 0x01, 0xFF, + 0xDD, 0x9E, 0xFC, 0x00, 0x44, 0x13, 0xF3, 0x81, 0xA6, 0x08, 0x54, 0x00, 0x00, 0xF0, 0xAE, 0x08, + 0x84, 0x00, 0x44, 0x13, 0xF3, 0x84, 0xAE, 0x08, 0x44, 0x13, 0xF5, 0x6B, 0xAE, 0x08, 0x49, 0xFF, + 0xFF, 0xDF, 0xFC, 0x80, 0x44, 0x53, 0xF3, 0x81, 0xA7, 0x28, 0x96, 0xD8, 0x54, 0x42, 0x00, 0xF0, + 0xFE, 0xA7, 0x40, 0x11, 0x04, 0x44, 0x96, 0x88, 0x40, 0x01, 0x00, 0xE4, 0x96, 0x80, 0x44, 0x03, + 0xF3, 0x84, 0xAE, 0xA8, 0xAE, 0xC0, 0xDD, 0x9E, 0x84, 0x00, 0x44, 0x13, 0xF3, 0x86, 0xAE, 0x08, + 0x44, 0x13, 0xF3, 0x87, 0xAE, 0x08, 0xDD, 0x9E, 0xFC, 0x60, 0x44, 0x03, 0xF3, 0x84, 0x96, 0xD8, + 0xAE, 0xC0, 0x49, 0xFF, 0xFF, 0xBD, 0xDD, 0x47, 0xDD, 0x45, 0xAE, 0x40, 0x44, 0x13, 0xF3, 0x80, + 0xA6, 0x08, 0x5A, 0x00, 0x01, 0xFF, 0x44, 0x73, 0xF3, 0x86, 0x44, 0x63, 0xF3, 0x87, 0x44, 0x93, + 0xF0, 0x4A, 0x44, 0xA0, 0x00, 0x55, 0x44, 0xB3, 0xF3, 0x80, 0xA6, 0x38, 0x5A, 0x08, 0x01, 0x0C, + 0x49, 0xFF, 0xFF, 0xDC, 0x49, 0xFF, 0xFF, 0xA4, 0x10, 0xA4, 0x80, 0x00, 0xEB, 0xB8, 0x5A, 0x00, + 0x01, 0xFF, 0xD5, 0xF4, 0xA6, 0x30, 0x5A, 0x00, 0x01, 0xF5, 0xFC, 0xE0, 0xDD, 0x9E, 0x44, 0x1E, + 0x00, 0x00, 0x88, 0x01, 0x92, 0x02, 0x96, 0x01, 0x44, 0x13, 0xF3, 0xCA, 0xAC, 0x08, 0xDD, 0x9E, + 0x44, 0x13, 0xF2, 0x80, 0xA6, 0x08, 0xEA, 0x8C, 0xAE, 0x08, 0xDD, 0x9E, 0x44, 0x23, 0xF2, 0x80, + 0xA6, 0x50, 0x40, 0x00, 0x80, 0xA4, 0x96, 0x00, 0xAE, 0x10, 0xDD, 0x9E, 0x44, 0x1E, 0x00, 0x00, + 0x88, 0x01, 0x96, 0x81, 0x44, 0x13, 0xF2, 0x86, 0xAC, 0x88, 0x42, 0x00, 0x40, 0x0B, 0x44, 0x13, + 0xF2, 0x88, 0xAE, 0x08, 0xDD, 0x9E, 0xFC, 0x60, 0x00, 0x20, 0x00, 0x09, 0x44, 0x73, 0xF2, 0x80, + 0x96, 0xD4, 0xA6, 0xB8, 0x80, 0xC0, 0x66, 0x21, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0A, 0x40, 0x21, + 0x0C, 0x24, 0x3C, 0x7F, 0xFC, 0x94, 0xAE, 0xB8, 0x96, 0x84, 0xA6, 0x38, 0x81, 0x21, 0x66, 0x00, + 0x00, 0x04, 0x40, 0x00, 0x08, 0x44, 0xAE, 0x38, 0xA4, 0x70, 0x44, 0x03, 0xF2, 0x84, 0xAC, 0x40, + 0xA0, 0x31, 0x49, 0xFF, 0xFF, 0xD5, 0x00, 0x13, 0x00, 0x08, 0x44, 0x03, 0xF2, 0x83, 0xAE, 0x40, + 0x44, 0xA3, 0xF0, 0x4A, 0x44, 0xB0, 0x00, 0x55, 0x00, 0x03, 0x00, 0x0B, 0x49, 0xFF, 0xFF, 0xC0, + 0x49, 0xFF, 0xFF, 0xB8, 0xA6, 0x38, 0x96, 0x04, 0xC0, 0x04, 0x10, 0xB5, 0x00, 0x00, 0xD5, 0xFB, + 0x44, 0x03, 0xF2, 0x81, 0x3C, 0x0F, 0xFC, 0x93, 0x5A, 0x98, 0x03, 0x07, 0xA6, 0x40, 0x42, 0x10, + 0x88, 0x0B, 0xC1, 0xEB, 0xD5, 0x08, 0x5A, 0x98, 0x01, 0x05, 0xA6, 0x00, 0xEB, 0x79, 0xD5, 0x05, + 0x5A, 0x98, 0x02, 0x05, 0xA6, 0x00, 0xEB, 0x8E, 0xC0, 0xE0, 0xFC, 0xE0, 0xC8, 0x08, 0x44, 0x13, + 0x8D, 0x25, 0xA6, 0x08, 0x8C, 0x01, 0x96, 0x00, 0xAE, 0x08, 0xD5, 0x0E, 0x44, 0x23, 0x8D, 0x26, + 0xA6, 0x50, 0x8C, 0x21, 0x96, 0x48, 0xAE, 0x50, 0x5A, 0x08, 0x01, 0x07, 0x44, 0x13, 0xF0, 0x60, + 0xA6, 0x08, 0xEB, 0x1C, 0xD5, 0x06, 0x44, 0x13, 0xF0, 0x60, 0xA6, 0x08, 0x54, 0x00, 0x00, 0xFB, + 0xAE, 0x08, 0xDD, 0x9E, 0x96, 0x00, 0x44, 0x13, 0xF0, 0x68, 0xAE, 0x08, 0xDD, 0x9E, 0x44, 0x23, + 0xF0, 0x53, 0xA6, 0x50, 0x96, 0x04, 0xEA, 0x5D, 0x88, 0x01, 0x96, 0x00, 0xAE, 0x10, 0xDD, 0x9E, + 0x44, 0x13, 0xF0, 0x6A, 0xA6, 0x88, 0x96, 0x04, 0x54, 0x21, 0x00, 0xFE, 0xAE, 0x88, 0xA6, 0x88, + 0x88, 0x02, 0x96, 0x00, 0xAE, 0x08, 0xDD, 0x9E, 0x44, 0x23, 0xF0, 0x54, 0xAC, 0x10, 0x44, 0x03, + 0xF0, 0x56, 0xAC, 0x40, 0xDD, 0x9E, 0x40, 0x31, 0xC8, 0x08, 0x40, 0x21, 0x89, 0x80, 0x88, 0x02, + 0x40, 0x10, 0x04, 0xC0, 0x84, 0xA5, 0x44, 0x43, 0xF0, 0x6D, 0x44, 0x03, 0xF0, 0x6E, 0xAF, 0x60, + 0x3C, 0x1F, 0xFC, 0x95, 0xEB, 0x70, 0xDD, 0x9E, 0x84, 0x20, 0x44, 0x03, 0xF0, 0x6D, 0xAE, 0x40, + 0xDD, 0x9E, 0x44, 0x03, 0xF0, 0x61, 0xA6, 0x00, 0xEB, 0x79, 0xDD, 0x9E, 0x44, 0x03, 0xF0, 0x61, + 0xA6, 0x00, 0x92, 0x07, 0xDD, 0x9E, 0xFC, 0x00, 0x49, 0xFF, 0xFF, 0xFA, 0xC8, 0x07, 0x49, 0xFF, + 0xFF, 0xF2, 0x5A, 0x00, 0x01, 0x06, 0x84, 0x01, 0xFC, 0x80, 0x84, 0x00, 0xFC, 0x80, 0x84, 0x02, + 0xFC, 0x80, 0x40, 0x00, 0x80, 0x84, 0x96, 0x00, 0x44, 0x13, 0xF4, 0x81, 0xAE, 0x08, 0xDD, 0x9E, + 0x96, 0x81, 0x44, 0x13, 0xF4, 0x83, 0x96, 0xD0, 0xA7, 0x08, 0x92, 0x48, 0xAE, 0xC8, 0xA6, 0xC9, + 0xAE, 0x89, 0xEB, 0x09, 0x88, 0x01, 0x92, 0x10, 0x96, 0x00, 0x44, 0x13, 0xF4, 0x85, 0xAE, 0x08, + 0xDD, 0x9E, 0x96, 0x81, 0x44, 0x13, 0xF4, 0x86, 0xAC, 0x88, 0xEB, 0x09, 0x88, 0x01, 0x92, 0x10, + 0x96, 0x00, 0x44, 0x13, 0xF4, 0x88, 0xAE, 0x08, 0xDD, 0x9E, 0x96, 0x81, 0x44, 0x13, 0xF4, 0x89, + 0x96, 0xD0, 0xA7, 0x08, 0x92, 0x48, 0xAE, 0xC8, 0xA6, 0xC9, 0xAE, 0x89, 0xEB, 0x09, 0x88, 0x01, + 0x92, 0x10, 0x96, 0x00, 0x44, 0x13, 0xF4, 0x8B, 0xAE, 0x08, 0xDD, 0x9E, 0x96, 0x00, 0x44, 0x13, + 0xF4, 0x8C, 0xAE, 0x08, 0xDD, 0x9E, 0x44, 0x03, 0xF4, 0x82, 0xA6, 0x40, 0xDD, 0x5B, 0xEA, 0x5D, + 0x58, 0x10, 0x80, 0x01, 0xAE, 0x40, 0xEA, 0x21, 0xAE, 0x88, 0xA6, 0x40, 0x96, 0x4C, 0xC9, 0xFE, + 0xDD, 0x9E, 0xFC, 0x00, 0x44, 0x63, 0xF0, 0x0E, 0xA4, 0x30, 0x42, 0x00, 0x20, 0x0B, 0xC0, 0x07, + 0x44, 0x13, 0x8D, 0x24, 0xF8, 0x1D, 0x84, 0x08, 0x48, 0x00, 0x00, 0x7D, 0xA4, 0x30, 0xEA, 0xEB, + 0xC8, 0x5B, 0xA4, 0x30, 0xEB, 0x8E, 0xC0, 0x06, 0x44, 0x13, 0x8D, 0x23, 0xF8, 0x11, 0x84, 0x03, + 0xD5, 0x71, 0xA4, 0x30, 0xEB, 0x79, 0xC0, 0x06, 0x44, 0x13, 0x8D, 0x22, 0xF8, 0x09, 0x84, 0x02, + 0xD5, 0x69, 0xA4, 0x30, 0x42, 0x00, 0x10, 0x0B, 0xC0, 0x0A, 0x44, 0x13, 0x8D, 0x21, 0xA6, 0x08, + 0x8C, 0x01, 0x96, 0x00, 0xAE, 0x08, 0x83, 0xFF, 0x84, 0x04, 0xD5, 0x5C, 0xA4, 0x30, 0x96, 0x04, + 0xC0, 0x4F, 0x49, 0xFF, 0x85, 0x6E, 0xA4, 0x30, 0x42, 0x00, 0x18, 0x0B, 0xC8, 0x37, 0xA4, 0x30, + 0x42, 0x00, 0x14, 0x0B, 0xC8, 0x35, 0xA4, 0x30, 0x42, 0x00, 0x1C, 0x0B, 0xC8, 0x33, 0xA4, 0x30, + 0x42, 0x00, 0x24, 0x0B, 0xC0, 0x0B, 0x44, 0x03, 0xF0, 0x64, 0xA6, 0x40, 0x96, 0x4C, 0xC1, 0x2C, + 0xA6, 0x40, 0xEA, 0x5D, 0xAE, 0x40, 0x84, 0x09, 0xD5, 0x3D, 0x44, 0x03, 0xF0, 0x0E, 0xA4, 0x40, + 0x42, 0x10, 0xA8, 0x0B, 0xC9, 0x23, 0xA4, 0x40, 0x42, 0x10, 0xAC, 0x0B, 0xC9, 0x21, 0xA4, 0x40, + 0x42, 0x10, 0xB0, 0x0B, 0xC9, 0x1F, 0xA4, 0x40, 0x42, 0x10, 0xB4, 0x0B, 0xC9, 0x1D, 0xA4, 0x40, + 0x42, 0x10, 0xB8, 0x0B, 0xC9, 0x1B, 0xA4, 0x00, 0x92, 0x0F, 0xC0, 0x1A, 0x84, 0x01, 0x3E, 0x07, + 0xF2, 0xD6, 0x84, 0x0F, 0xD5, 0x1F, 0x84, 0x01, 0xD5, 0x1D, 0x84, 0x06, 0xD5, 0x1B, 0x84, 0x05, + 0xD5, 0x19, 0x84, 0x07, 0xD5, 0x17, 0x84, 0x09, 0xD5, 0x15, 0x84, 0x0A, 0xD5, 0x13, 0x84, 0x0B, + 0xD5, 0x11, 0x84, 0x0C, 0xD5, 0x0F, 0x84, 0x0D, 0xD5, 0x0D, 0x84, 0x0E, 0xD5, 0x0B, 0x44, 0x03, + 0xF0, 0x1A, 0xA4, 0x00, 0xEA, 0xEB, 0xC0, 0x05, 0x49, 0xFF, 0x85, 0x1B, 0xFA, 0x01, 0xD5, 0x02, + 0xFA, 0x08, 0x84, 0x20, 0x44, 0x23, 0xF0, 0x0E, 0xAC, 0x50, 0x44, 0x23, 0xF0, 0x1A, 0xAC, 0x50, + 0xFC, 0x80, 0x84, 0x21, 0x44, 0x03, 0xF3, 0x22, 0xAE, 0x40, 0xDD, 0x9E, 0x44, 0x13, 0xF3, 0x23, + 0xAE, 0x08, 0xDD, 0x9E, 0x44, 0x03, 0xF3, 0x23, 0xA6, 0x00, 0xDD, 0x9E, 0xFC, 0x00, 0x44, 0x63, + 0xF5, 0x40, 0xB6, 0x06, 0x44, 0x03, 0xF5, 0x44, 0xB6, 0x20, 0x44, 0x03, 0xF5, 0x48, 0xB6, 0x40, + 0x44, 0x03, 0xF5, 0x4C, 0xB6, 0x60, 0x44, 0x03, 0xF5, 0x50, 0xB6, 0x80, 0x44, 0x03, 0xF5, 0x54, + 0xB6, 0xA0, 0xF1, 0x04, 0x44, 0x03, 0xF5, 0x58, 0xB6, 0x20, 0xF1, 0x05, 0x44, 0x03, 0xF5, 0x5C, + 0xB6, 0x20, 0xFC, 0x80, 0xFC, 0x00, 0x44, 0x33, 0xF5, 0x04, 0x44, 0x23, 0xF5, 0x02, 0x44, 0x13, + 0xF5, 0x03, 0x3C, 0x3F, 0xFC, 0x97, 0x44, 0x33, 0xF5, 0x05, 0x80, 0xC0, 0x3C, 0x2F, 0xFC, 0x9A, + 0x3C, 0x1F, 0xFC, 0x99, 0x3C, 0x3F, 0xFC, 0x96, 0x5A, 0x00, 0x03, 0x04, 0x48, 0x00, 0x00, 0x7D, + 0xDD, 0x40, 0x44, 0x13, 0xF5, 0x1A, 0xC0, 0x04, 0x84, 0x01, 0xAE, 0x08, 0xD5, 0x02, 0xAE, 0x08, + 0x84, 0x20, 0x44, 0x03, 0xF5, 0x78, 0xAE, 0x40, 0xEA, 0x8E, 0x44, 0x03, 0xF5, 0x79, 0xAE, 0x40, + 0x84, 0x21, 0x44, 0x03, 0xF5, 0x00, 0xAE, 0x40, 0x84, 0x00, 0x80, 0x20, 0x80, 0x40, 0x80, 0x60, + 0xEA, 0x4B, 0x84, 0x23, 0x44, 0x03, 0xF5, 0x01, 0xAE, 0x40, 0x84, 0x00, 0x80, 0x20, 0x80, 0x40, + 0x80, 0x60, 0xEA, 0x4B, 0xEB, 0x3F, 0xA6, 0x08, 0x58, 0x00, 0x00, 0x02, 0xAE, 0x08, 0x84, 0x00, + 0x80, 0x20, 0x80, 0x40, 0x80, 0x60, 0xEA, 0x4B, 0x44, 0x00, 0x08, 0x02, 0xEA, 0x39, 0x3C, 0x1D, + 0xFC, 0x99, 0xA6, 0x08, 0x58, 0x00, 0x00, 0x02, 0xAE, 0x08, 0x84, 0x00, 0x80, 0x20, 0x80, 0x40, + 0x80, 0x60, 0xEA, 0x4B, 0x44, 0x00, 0x04, 0x1A, 0xEA, 0x39, 0xDD, 0x47, 0x44, 0x03, 0xF5, 0x09, + 0xAE, 0x40, 0x84, 0x00, 0x80, 0x20, 0x80, 0x40, 0x80, 0x60, 0xEA, 0x4B, 0xEB, 0x3F, 0xA6, 0x08, + 0xEA, 0x8C, 0xAE, 0x08, 0x3C, 0x0D, 0xFC, 0x99, 0xA6, 0x80, 0x58, 0x21, 0x00, 0x01, 0xAE, 0x80, + 0xA6, 0x88, 0x58, 0x21, 0x00, 0x04, 0xAE, 0x88, 0xA6, 0x80, 0x58, 0x21, 0x00, 0x04, 0xAE, 0x80, + 0xA6, 0x88, 0x58, 0x21, 0x00, 0x08, 0xAE, 0x88, 0xA6, 0x80, 0x58, 0x21, 0x00, 0x08, 0xAE, 0x80, + 0xA6, 0x88, 0x58, 0x21, 0x00, 0x10, 0xAE, 0x88, 0xA6, 0x40, 0x58, 0x10, 0x80, 0x10, 0xAE, 0x40, + 0x84, 0x00, 0x80, 0x20, 0x80, 0x40, 0x80, 0x60, 0xEA, 0x4B, 0x44, 0x00, 0x05, 0xAA, 0xEA, 0x39, + 0xEB, 0x3F, 0xA6, 0x08, 0x66, 0x00, 0x00, 0x10, 0xAE, 0x08, 0x3C, 0x1D, 0xFC, 0x99, 0xA6, 0x08, + 0x66, 0x00, 0x00, 0x10, 0xD5, 0x50, 0xC8, 0x31, 0x84, 0x41, 0x44, 0x13, 0xF5, 0x00, 0xAE, 0x88, + 0x84, 0x43, 0x44, 0x13, 0xF5, 0x01, 0xAE, 0x88, 0x3C, 0x2D, 0xFC, 0x9A, 0x80, 0x60, 0xA6, 0x50, + 0x58, 0x10, 0x80, 0x02, 0xAE, 0x50, 0x3C, 0x2D, 0xFC, 0x99, 0xA6, 0x50, 0x58, 0x10, 0x80, 0x02, + 0xAE, 0x50, 0x80, 0x20, 0x80, 0x40, 0xEA, 0x4B, 0xEB, 0x3F, 0x80, 0x66, 0xA6, 0x08, 0xEB, 0x1C, + 0xAE, 0x08, 0x3C, 0x0D, 0xFC, 0x99, 0xA6, 0x80, 0x58, 0x21, 0x00, 0x04, 0xAE, 0x80, 0xA6, 0x88, + 0x58, 0x21, 0x00, 0x08, 0xAE, 0x88, 0xA6, 0x40, 0x80, 0x46, 0x58, 0x10, 0x80, 0x08, 0xAE, 0x40, + 0x80, 0x06, 0x80, 0x26, 0xEA, 0x4B, 0xD5, 0x25, 0x5A, 0x08, 0x01, 0x24, 0xA6, 0xD0, 0xA6, 0x08, + 0x54, 0x31, 0x80, 0xF3, 0x54, 0x00, 0x00, 0xF3, 0xAE, 0xD0, 0xAE, 0x08, 0x84, 0x00, 0x80, 0x20, + 0x80, 0x40, 0x80, 0x60, 0xEA, 0x4B, 0x84, 0x00, 0x44, 0x13, 0xF5, 0x00, 0xAE, 0x08, 0x44, 0x13, + 0xF5, 0x01, 0xAE, 0x08, 0xEB, 0x3F, 0xA6, 0x08, 0xEA, 0xA0, 0xAE, 0x08, 0x3C, 0x1D, 0xFC, 0x99, + 0xA6, 0x08, 0xEA, 0xA0, 0xAE, 0x08, 0x84, 0x00, 0x80, 0x20, 0x80, 0x40, 0x80, 0x60, 0xEA, 0x4B, + 0xFC, 0x80, 0xDD, 0x9E, 0x46, 0x10, 0x80, 0x00, 0xEB, 0x2E, 0xEA, 0xEE, 0x42, 0x10, 0xEC, 0x09, + 0x40, 0x00, 0x83, 0x64, 0xEA, 0x76, 0xDD, 0x9E, 0x46, 0x10, 0x08, 0x00, 0xEB, 0x2E, 0xEA, 0xEE, + 0x42, 0x10, 0xDC, 0x09, 0x40, 0x00, 0x82, 0xE4, 0xEA, 0x76, 0xDD, 0x9E, 0x44, 0x11, 0x00, 0x00, + 0xEB, 0x2E, 0xEA, 0xEE, 0x42, 0x10, 0xC0, 0x09, 0x40, 0x00, 0x82, 0x04, 0xEA, 0x76, 0xDD, 0x9E, + 0x44, 0x10, 0x80, 0x00, 0xEB, 0x2E, 0xEA, 0xEE, 0x42, 0x10, 0xBC, 0x09, 0x40, 0x00, 0x81, 0xE4, + 0xEA, 0x76, 0xDD, 0x9E, 0x84, 0x24, 0x64, 0x13, 0x28, 0x03, 0x64, 0x13, 0x08, 0x02, 0x66, 0x10, + 0x80, 0x04, 0x40, 0x00, 0x80, 0x44, 0xEA, 0xF3, 0xDD, 0x9E, 0x44, 0x10, 0x02, 0x00, 0x64, 0x13, + 0x28, 0x03, 0x64, 0x13, 0x08, 0x02, 0x66, 0x10, 0x82, 0x00, 0x40, 0x00, 0x81, 0x24, 0xEA, 0xF3, + 0x44, 0x13, 0xF7, 0xEF, 0xA6, 0x08, 0x96, 0x00, 0x96, 0x84, 0xC2, 0x03, 0xEA, 0x8F, 0xAE, 0x08, + 0xDD, 0x9E, 0x84, 0x22, 0xEB, 0x2E, 0xEA, 0xEE, 0xEB, 0xA0, 0x40, 0x00, 0x80, 0x24, 0xEA, 0x76, + 0xDD, 0x9E, 0xDD, 0x9E, 0xDD, 0x9E, 0xDD, 0x9E, 0xFC, 0x40, 0x80, 0xE0, 0x44, 0x03, 0xF0, 0x40, + 0xA7, 0x80, 0x81, 0x21, 0x81, 0x42, 0x54, 0x63, 0x00, 0x1C, 0x5A, 0x78, 0x02, 0x22, 0xDD, 0x40, + 0xC0, 0x14, 0x44, 0x22, 0xFE, 0xF6, 0x44, 0x33, 0xF0, 0x4A, 0xEB, 0x80, 0xA6, 0x10, 0x44, 0x12, + 0xFE, 0xF6, 0x5A, 0x00, 0xEC, 0x04, 0xAF, 0x18, 0xD5, 0xFA, 0x84, 0x00, 0xAE, 0x08, 0x80, 0x41, + 0x84, 0x61, 0x84, 0x02, 0xDD, 0x42, 0xD5, 0x0A, 0x44, 0x12, 0xFE, 0xF6, 0x44, 0x0F, 0xFF, 0xEC, + 0xAE, 0x08, 0x80, 0x41, 0x80, 0x07, 0x84, 0x61, 0xDD, 0x42, 0x84, 0x00, 0xEA, 0x65, 0x84, 0x00, + 0x44, 0x13, 0xF0, 0x0E, 0xAC, 0x08, 0xFF, 0xBF, 0x44, 0x13, 0xF0, 0x1A, 0xAC, 0x08, 0x97, 0xB0, + 0x44, 0x03, 0xF0, 0x40, 0xAF, 0x80, 0xDD, 0x47, 0xDD, 0x45, 0xAE, 0x40, 0x5A, 0x78, 0x02, 0x1C, + 0x44, 0x10, 0x00, 0x5A, 0xAE, 0x40, 0x49, 0x00, 0x01, 0x0E, 0xC8, 0xFE, 0x2E, 0x17, 0xF2, 0xB1, + 0x5A, 0x18, 0x01, 0x07, 0x44, 0x13, 0xF3, 0x74, 0x3E, 0x07, 0xF2, 0xB1, 0xAE, 0x08, 0x84, 0x00, + 0xEA, 0x76, 0xEA, 0xF3, 0xDD, 0x43, 0xC8, 0x04, 0x44, 0x13, 0xF0, 0x46, 0xAE, 0x08, 0xFA, 0x30, + 0xEA, 0x56, 0xAE, 0x40, 0x44, 0x13, 0xF0, 0xDA, 0xA6, 0x08, 0x54, 0x00, 0x00, 0xF0, 0x40, 0x25, + 0x00, 0x04, 0x96, 0x90, 0xAE, 0x88, 0x44, 0x03, 0xF0, 0xED, 0x54, 0x14, 0x80, 0xFF, 0xAE, 0x40, + 0xDD, 0x47, 0x44, 0x03, 0xF0, 0x41, 0xAE, 0x40, 0xEA, 0x37, 0xEA, 0x37, 0xEA, 0x37, 0xEA, 0x37, + 0xEA, 0x37, 0xEA, 0x37, 0xEA, 0x37, 0xFC, 0xC0, 0x40, 0x00, 0x04, 0xA4, 0x44, 0x23, 0xF0, 0x42, + 0x96, 0x00, 0xA6, 0xD0, 0xAE, 0x10, 0xDD, 0x9E, 0x96, 0x5F, 0x96, 0x04, 0x40, 0x00, 0x80, 0x84, + 0x44, 0x13, 0xF0, 0x43, 0xAE, 0x08, 0xDD, 0x9E, 0x44, 0x13, 0xF0, 0x44, 0xAC, 0x08, 0xDD, 0x9E, + 0x54, 0x00, 0x00, 0xFD, 0x44, 0x13, 0xF0, 0x46, 0xAE, 0x08, 0xDD, 0x9E, 0x40, 0x00, 0x3C, 0x08, + 0x92, 0x10, 0x44, 0x33, 0xF2, 0x00, 0x40, 0x10, 0xBC, 0x08, 0xAC, 0x18, 0x92, 0x30, 0x44, 0x03, + 0xF2, 0x02, 0x40, 0x21, 0x3C, 0x08, 0xAC, 0x40, 0x92, 0x50, 0x44, 0x03, 0xF2, 0x04, 0xAC, 0x80, + 0xDD, 0x9E, 0x44, 0x03, 0xF2, 0x0A, 0xA6, 0x40, 0xDD, 0x5B, 0xEA, 0x5D, 0x58, 0x10, 0x80, 0x01, + 0xAE, 0x40, 0xEA, 0x21, 0xAE, 0x88, 0xA6, 0x40, 0x96, 0x4C, 0xC9, 0xFE, 0xDD, 0x9E, 0x96, 0x00, + 0x44, 0x23, 0xF2, 0x06, 0xAE, 0x10, 0x96, 0x48, 0x44, 0x03, 0xF2, 0x07, 0xAE, 0x40, 0xDD, 0x9E, + 0xFC, 0x00, 0xDD, 0x40, 0xC0, 0x03, 0xEA, 0xF9, 0xFC, 0x80, 0x44, 0x02, 0x15, 0xB8, 0xFC, 0x80, + 0xFC, 0x00, 0xDD, 0x40, 0xC0, 0x04, 0x44, 0x02, 0x4A, 0x00, 0xFC, 0x80, 0x44, 0x02, 0x0A, 0x00, + 0xFC, 0x80, 0x44, 0x03, 0xF2, 0x0B, 0xA6, 0x00, 0xDD, 0x9E, 0x44, 0x13, 0xF2, 0x08, 0xAC, 0x08, + 0xDD, 0x9E, 0x44, 0x23, 0xF2, 0x0A, 0xA6, 0x50, 0x96, 0x4C, 0x40, 0x00, 0x80, 0x24, 0x96, 0x00, + 0xAE, 0x10, 0xDD, 0x9E, 0xE6, 0x08, 0xE8, 0x23, 0x44, 0xF0, 0xFE, 0x44, 0xEA, 0x90, 0xEA, 0x3C, + 0x4A, 0x00, 0x3C, 0x00, 0x08, 0x0E, 0x14, 0x1A, 0x20, 0x26, 0x2C, 0x32, 0x44, 0x03, 0xF2, 0x0C, + 0xD5, 0x15, 0x44, 0x03, 0xF2, 0x0E, 0xD5, 0x12, 0x44, 0x03, 0xF2, 0x10, 0xD5, 0x0F, 0x44, 0x03, + 0xF2, 0x12, 0xD5, 0x0C, 0x44, 0x03, 0xF2, 0x14, 0xD5, 0x09, 0x44, 0x03, 0xF2, 0x16, 0xD5, 0x06, + 0x44, 0x03, 0xF2, 0x18, 0xD5, 0x03, 0x44, 0x03, 0xF2, 0x1A, 0xAE, 0x40, 0xDD, 0x9E, 0x92, 0x00, + 0xE6, 0x08, 0xE8, 0x23, 0x44, 0xF0, 0xFE, 0x90, 0xEA, 0x90, 0xEA, 0x3C, 0x4A, 0x00, 0x3C, 0x00, + 0x08, 0x0E, 0x14, 0x1A, 0x20, 0x26, 0x2C, 0x32, 0x44, 0x03, 0xF2, 0x0D, 0xD5, 0x15, 0x44, 0x03, + 0xF2, 0x0F, 0xD5, 0x12, 0x44, 0x03, 0xF2, 0x11, 0xD5, 0x0F, 0x44, 0x03, 0xF2, 0x13, 0xD5, 0x0C, + 0x44, 0x03, 0xF2, 0x15, 0xD5, 0x09, 0x44, 0x03, 0xF2, 0x17, 0xD5, 0x06, 0x44, 0x03, 0xF2, 0x19, + 0xD5, 0x03, 0x44, 0x03, 0xF2, 0x1B, 0xAE, 0x40, 0xDD, 0x9E, 0x92, 0x00, 0x44, 0x03, 0xF0, 0xC4, + 0xA6, 0x00, 0xDD, 0x9E, 0x96, 0x00, 0x44, 0x13, 0xF0, 0xC4, 0xAE, 0x08, 0xDD, 0x9E, 0x44, 0x03, + 0xF0, 0xC3, 0xA6, 0x00, 0xDD, 0x9E, 0x96, 0x00, 0x44, 0x13, 0xF0, 0xC3, 0xAE, 0x08, 0xDD, 0x9E, + 0x44, 0x03, 0xF0, 0xCE, 0xA4, 0x00, 0x44, 0x13, 0xF0, 0xD0, 0xA6, 0x48, 0x40, 0x00, 0x80, 0xE4, + 0x44, 0x1D, 0x02, 0x00, 0x88, 0x01, 0x5C, 0x00, 0x00, 0x80, 0xDD, 0x9E, 0x44, 0x02, 0xFE, 0x00, + 0xDD, 0x9E, 0x84, 0x21, 0x44, 0x03, 0xF0, 0xF5, 0xAE, 0x40, 0xDD, 0x47, 0xDD, 0x45, 0xAE, 0x40, + 0xDD, 0x9E, 0x44, 0x03, 0xF0, 0xF4, 0xA6, 0x00, 0x92, 0x04, 0xDD, 0x9E, 0x44, 0x03, 0xF0, 0xF7, + 0xA6, 0x00, 0xDD, 0x9E, 0x96, 0x00, 0x44, 0x13, 0xF0, 0xF7, 0xAE, 0x08, 0xDD, 0x9E, 0x44, 0x03, + 0xF0, 0xF6, 0xA6, 0x00, 0xDD, 0x9E, 0x96, 0x00, 0x44, 0x13, 0xF0, 0xF6, 0xAE, 0x08, 0xDD, 0x9E, + 0x44, 0x52, 0xFE, 0x00, 0x44, 0x12, 0xFE, 0x3E, 0x18, 0x02, 0x80, 0x01, 0xD9, 0xFE, 0xDD, 0x9E, + 0xFC, 0x40, 0x44, 0x00, 0x00, 0xFD, 0x49, 0xFF, 0xFF, 0xF5, 0x44, 0x63, 0xF0, 0x68, 0xEB, 0x02, + 0xEB, 0x27, 0xF8, 0x03, 0xFA, 0x09, 0xEA, 0x39, 0xA6, 0x30, 0xEB, 0x33, 0xEB, 0x5A, 0x44, 0x00, + 0x04, 0x92, 0xEA, 0x39, 0xEB, 0x2F, 0xD5, 0xF6, 0xFC, 0x00, 0x49, 0xFF, 0xFF, 0xEB, 0x92, 0x00, + 0x44, 0x23, 0xF0, 0xC7, 0xA6, 0x50, 0x96, 0x48, 0x5A, 0x08, 0x01, 0x05, 0x58, 0x10, 0x80, 0xC0, + 0xD5, 0x02, 0x96, 0x6F, 0xAE, 0x50, 0xDD, 0x9E, 0xFC, 0x00, 0x44, 0x10, 0x05, 0xFC, 0x44, 0x03, + 0xF0, 0xCE, 0xAC, 0x40, 0x84, 0x20, 0x44, 0x03, 0xF0, 0xD0, 0xAE, 0x40, 0x84, 0x01, 0x49, 0xFF, + 0xFF, 0xE9, 0xFC, 0x80, 0x44, 0x23, 0xF0, 0xEC, 0xA6, 0x50, 0x96, 0x04, 0x54, 0x10, 0x80, 0xFB, + 0x40, 0x00, 0x80, 0x44, 0xAE, 0x10, 0xDD, 0x9E, 0xFC, 0x00, 0x49, 0xFF, 0xFF, 0xF5, 0xFC, 0x80, + 0x44, 0x03, 0xF0, 0xCE, 0xA4, 0x00, 0x44, 0x13, 0xF0, 0xD0, 0xA6, 0x48, 0x40, 0x00, 0x80, 0xE4, + 0xEA, 0x7F, 0xFE, 0x0D, 0xEA, 0xB8, 0xDD, 0x9E, 0x44, 0x1E, 0x00, 0x00, 0x88, 0x01, 0x92, 0x02, + 0x96, 0x01, 0x44, 0x13, 0xF0, 0xE6, 0xAC, 0x08, 0xDD, 0x9E, 0x44, 0x13, 0xF0, 0x50, 0xA6, 0x08, + 0x58, 0x00, 0x00, 0x80, 0xAE, 0x08, 0xDD, 0x9E, 0x44, 0x13, 0xF0, 0x50, 0xA6, 0x08, 0x96, 0x37, + 0xAE, 0x08, 0xDD, 0x9E, 0x44, 0x23, 0xF0, 0x50, 0xA6, 0x50, 0x96, 0x17, 0x54, 0x10, 0x80, 0xF8, + 0xFE, 0x47, 0xAE, 0x50, 0xDD, 0x9E, 0x44, 0x23, 0xF0, 0x50, 0xA6, 0x50, 0x96, 0x17, 0x54, 0x10, + 0x80, 0x8F, 0x40, 0x00, 0x80, 0x84, 0xAE, 0x10, 0xDD, 0x9E, 0x44, 0x13, 0xF0, 0x50, 0xA6, 0x08, + 0x58, 0x00, 0x00, 0x08, 0xAE, 0x08, 0xDD, 0x9E, 0x44, 0x13, 0xF0, 0x50, 0xA6, 0x08, 0x54, 0x00, + 0x00, 0xF7, 0xAE, 0x08, 0xDD, 0x9E, 0x44, 0x13, 0xF0, 0x51, 0xA6, 0x08, 0xEA, 0x8C, 0xAE, 0x08, + 0xDD, 0x9E, 0xFC, 0x00, 0x84, 0x07, 0x49, 0xFF, 0xFF, 0xD7, 0x84, 0x20, 0x44, 0x03, 0xF0, 0x4C, + 0xAE, 0x40, 0x84, 0x07, 0x49, 0xFF, 0xFF, 0xD9, 0x84, 0x21, 0x44, 0x03, 0xF0, 0x4E, 0xAE, 0x40, + 0x49, 0xFF, 0xFF, 0xEB, 0xFC, 0x80, 0x96, 0x00, 0x44, 0x13, 0xF0, 0x4C, 0xAE, 0x08, 0xDD, 0x9E, + 0x44, 0x03, 0xF0, 0x4D, 0xA6, 0x00, 0xDD, 0x9E, 0xC0, 0x03, 0x84, 0x07, 0xD5, 0x02, 0x84, 0x03, + 0x44, 0x13, 0xF0, 0x50, 0xA6, 0x88, 0x84, 0x21, 0x40, 0x00, 0x80, 0x0C, 0xFE, 0x16, 0xDD, 0x9E, + 0x3C, 0x0F, 0xFD, 0xA6, 0xDD, 0x9E, 0x3C, 0x0D, 0xFD, 0xA6, 0xA6, 0x00, 0xDD, 0x9E, 0x44, 0x03, + 0x0F, 0xA0, 0xEA, 0x86, 0x3C, 0x0F, 0xFC, 0x36, 0x3C, 0x1F, 0xFB, 0xFC, 0x3C, 0x0F, 0xFC, 0x05, + 0xDD, 0x9E, 0xC0, 0x04, 0x5A, 0x00, 0x02, 0x09, 0xDD, 0x9E, 0x3C, 0x0D, 0xFD, 0xA6, 0xA6, 0x00, + 0x3C, 0x0F, 0xFB, 0x27, 0xDD, 0x9E, 0x3C, 0x1F, 0xFB, 0x27, 0xDD, 0x9E, 0x40, 0x00, 0x3C, 0x08, + 0x92, 0x10, 0x44, 0x33, 0xF1, 0xC4, 0x40, 0x10, 0xBC, 0x08, 0xAC, 0x18, 0x92, 0x30, 0x44, 0x03, + 0xF1, 0xC6, 0x40, 0x21, 0x3C, 0x08, 0xAC, 0x40, 0x92, 0x50, 0x44, 0x03, 0xF1, 0xC8, 0xAC, 0x80, + 0xDD, 0x9E, 0xFC, 0x00, 0xEB, 0x3C, 0xA6, 0x82, 0xA6, 0x43, 0x44, 0x03, 0xF1, 0xC2, 0xAE, 0x80, + 0x44, 0x03, 0xF1, 0xC3, 0xAE, 0x40, 0x3C, 0x0D, 0xFC, 0x36, 0x3C, 0x1D, 0xFB, 0xFC, 0x3C, 0x2D, + 0xFC, 0x05, 0x49, 0xFF, 0xFF, 0xDD, 0xFC, 0x80, 0x84, 0x00, 0x3C, 0x0F, 0xFC, 0x77, 0x84, 0x21, + 0x44, 0x03, 0xF1, 0xC0, 0xAE, 0x40, 0xDD, 0x9E, 0xFC, 0x06, 0x49, 0xFF, 0xFF, 0xE4, 0x3C, 0x0D, + 0xFB, 0x27, 0x5A, 0x00, 0x0F, 0x11, 0x96, 0x00, 0x44, 0x13, 0xF1, 0xC1, 0xAE, 0x08, 0x49, 0xFF, + 0xFF, 0xED, 0xDD, 0x47, 0xDD, 0x45, 0xAE, 0x40, 0x44, 0x13, 0xF1, 0xC0, 0xA6, 0x08, 0x5A, 0x00, + 0x01, 0xFF, 0xFC, 0x86, 0xFA, 0x30, 0xF1, 0x85, 0x84, 0x22, 0x84, 0x00, 0xEA, 0x96, 0x84, 0xA1, + 0xF1, 0x87, 0xEA, 0xC5, 0xF0, 0x83, 0xF0, 0x84, 0xF0, 0x86, 0xF0, 0x88, 0xF0, 0x89, 0xEA, 0xAD, + 0xB6, 0x7F, 0xF5, 0x81, 0xF3, 0x82, 0xF5, 0x8A, 0xEA, 0xFD, 0x80, 0x41, 0xEA, 0x54, 0xFC, 0x86, + 0xEB, 0xF0, 0x44, 0x12, 0x03, 0xC0, 0x04, 0x00, 0x00, 0x14, 0x92, 0x10, 0xEA, 0x87, 0xEA, 0xC3, + 0x84, 0x26, 0xAE, 0x44, 0xDD, 0x9E, 0xFC, 0x00, 0xDD, 0x41, 0xA6, 0x01, 0x9E, 0x44, 0xE6, 0x22, + 0xE9, 0x07, 0x5A, 0x00, 0x09, 0x06, 0xDD, 0x54, 0xA6, 0x00, 0xE6, 0x02, 0xE8, 0x05, 0x84, 0x05, + 0xF8, 0x11, 0xAE, 0x08, 0xD5, 0x16, 0xEB, 0xBC, 0xA6, 0x00, 0xC8, 0x05, 0x84, 0x01, 0xF8, 0x0A, + 0xAE, 0x08, 0xD5, 0x0F, 0x5A, 0x00, 0x01, 0x06, 0x5A, 0x00, 0x02, 0x04, 0x5A, 0x08, 0x03, 0x0A, + 0x84, 0x00, 0x44, 0x13, 0xF5, 0x72, 0xAE, 0x08, 0x44, 0x13, 0xF5, 0x73, 0x83, 0xFF, 0xAE, 0x08, + 0x84, 0x00, 0x80, 0x20, 0x80, 0x40, 0x80, 0x60, 0xEA, 0x4B, 0xFC, 0x80, 0x84, 0x00, 0xEB, 0x1B, + 0x84, 0x21, 0x44, 0x03, 0xF4, 0x03, 0xAE, 0x40, 0xDD, 0x9E, 0x44, 0x03, 0xF4, 0x03, 0xA6, 0x00, + 0xEA, 0xB8, 0xDD, 0x9E, 0x44, 0x03, 0xF4, 0x0C, 0xA6, 0x00, 0x96, 0x00, 0xC8, 0x07, 0x44, 0x13, + 0xF3, 0xCF, 0xA6, 0x48, 0x40, 0x00, 0x04, 0x06, 0xDD, 0x9E, 0x84, 0x01, 0xDD, 0x9E, 0x84, 0x00, + 0xEA, 0x7B, 0xEB, 0x1B, 0xAE, 0x08, 0xDD, 0x9E, 0xFC, 0x00, 0x5A, 0x08, 0x01, 0x0F, 0x49, 0xFF, + 0xFF, 0xB4, 0x49, 0xFF, 0xFF, 0xDD, 0x84, 0x00, 0x84, 0x2A, 0x3C, 0x0B, 0xF7, 0xD7, 0x3C, 0x1F, + 0xFC, 0x37, 0x3E, 0x07, 0xEF, 0x26, 0xFC, 0x80, 0x49, 0xFF, 0xFF, 0xEB, 0xFC, 0x80, 0x44, 0x03, + 0xF0, 0x1D, 0xA6, 0x80, 0xA6, 0x41, 0xA6, 0xC0, 0x40, 0x11, 0x05, 0x04, 0x58, 0x10, 0x84, 0x00, + 0x96, 0x88, 0xAE, 0x80, 0x92, 0x28, 0xA6, 0x81, 0xAE, 0x41, 0xDD, 0x5B, 0x44, 0x13, 0xF4, 0x21, + 0xF8, 0x06, 0x50, 0x21, 0x00, 0x01, 0x4C, 0x21, 0xFF, 0xFE, 0x84, 0x40, 0xAE, 0x88, 0x44, 0x20, + 0x00, 0x00, 0x44, 0x30, 0x00, 0x0A, 0x83, 0xFF, 0x50, 0x21, 0x00, 0x01, 0x4C, 0x21, 0xFF, 0xFE, + 0xA6, 0x40, 0x96, 0x48, 0xAE, 0x40, 0xDD, 0x9E, 0xFC, 0x00, 0xDD, 0x43, 0x44, 0x22, 0xD9, 0x5C, + 0x44, 0x12, 0xD6, 0x28, 0x5A, 0x08, 0x02, 0x0B, 0x84, 0x00, 0x44, 0x52, 0xD6, 0xD0, 0x44, 0x42, + 0xDB, 0x1C, 0xF8, 0x09, 0x5A, 0x08, 0x20, 0xFF, 0xFC, 0x80, 0x84, 0x00, 0x44, 0x52, 0xDA, 0x34, + 0x44, 0x42, 0xD6, 0x6C, 0x38, 0x32, 0x80, 0x00, 0x38, 0x31, 0x00, 0x08, 0x38, 0x32, 0x00, 0x00, + 0x38, 0x30, 0x80, 0x08, 0x8C, 0x01, 0x83, 0xFF, 0x5A, 0x08, 0x20, 0xF6, 0xFC, 0x80, 0xA6, 0x40, + 0x3E, 0x10, 0x12, 0x0C, 0xA6, 0x41, 0x3E, 0x10, 0x12, 0x0D, 0xA6, 0x42, 0x3E, 0x10, 0x12, 0x0E, + 0xA6, 0x43, 0x3E, 0x10, 0x12, 0x0F, 0xA6, 0x45, 0xA6, 0x84, 0x40, 0x21, 0x05, 0x00, 0xA6, 0x47, + 0xA6, 0xC6, 0x40, 0x11, 0x85, 0x00, 0x00, 0x30, 0x00, 0x09, 0x00, 0x40, 0x00, 0x08, 0xEA, 0xD9, + 0x3C, 0x38, 0x09, 0x0A, 0x00, 0x30, 0x00, 0x0B, 0x00, 0x40, 0x00, 0x0A, 0xEA, 0xD9, 0x3C, 0x38, + 0x09, 0x0B, 0x00, 0x30, 0x00, 0x0C, 0x3E, 0x30, 0x12, 0x18, 0x00, 0x30, 0x00, 0x0D, 0x3E, 0x30, + 0x12, 0x19, 0xEB, 0xDD, 0x96, 0x93, 0x96, 0xDC, 0x3E, 0x30, 0x12, 0x1A, 0xEB, 0xDD, 0x96, 0x4B, + 0x42, 0x31, 0x84, 0x0B, 0x3E, 0x30, 0x12, 0x1B, 0xEB, 0xDD, 0x3C, 0x28, 0x09, 0x08, 0x42, 0x31, + 0x88, 0x0B, 0x3E, 0x30, 0x12, 0x1C, 0xEB, 0xDD, 0x3C, 0x18, 0x09, 0x09, 0x42, 0x31, 0x8C, 0x0B, + 0x3E, 0x30, 0x12, 0x1D, 0x00, 0x30, 0x00, 0x0F, 0x96, 0xDF, 0x3E, 0x30, 0x12, 0x1E, 0x00, 0x30, + 0x00, 0x0F, 0x92, 0x64, 0x3E, 0x30, 0x12, 0x1F, 0x00, 0x30, 0x00, 0x11, 0x00, 0x40, 0x00, 0x10, + 0xEA, 0xD9, 0x3C, 0x38, 0x09, 0x10, 0x00, 0x30, 0x00, 0x13, 0x00, 0x40, 0x00, 0x12, 0xEA, 0xD9, + 0x3C, 0x38, 0x09, 0x11, 0x00, 0x30, 0x00, 0x15, 0x00, 0x40, 0x00, 0x14, 0x96, 0xCF, 0xEA, 0xD9, + 0x3C, 0x38, 0x09, 0x12, 0x00, 0x30, 0x00, 0x15, 0x92, 0x62, 0x3E, 0x30, 0x12, 0x26, 0x00, 0x30, + 0x00, 0x17, 0x00, 0x40, 0x00, 0x16, 0x96, 0xCF, 0xEA, 0xD9, 0x3C, 0x38, 0x09, 0x14, 0x00, 0x30, + 0x00, 0x17, 0x92, 0x62, 0x3E, 0x30, 0x12, 0x2A, 0x00, 0x00, 0x00, 0x1E, 0x96, 0x2F, 0x3E, 0x00, + 0x12, 0x2B, 0x42, 0x01, 0x2C, 0x0B, 0xC0, 0x06, 0x44, 0x0F, 0xF0, 0x00, 0xFE, 0x87, 0x3C, 0x28, + 0x09, 0x08, 0x42, 0x00, 0xAC, 0x0B, 0xC0, 0x06, 0x44, 0x0F, 0xF0, 0x00, 0xFE, 0x47, 0x3C, 0x18, + 0x09, 0x09, 0x84, 0x0D, 0x3E, 0x00, 0x12, 0x1E, 0xDD, 0x9E, 0xA4, 0xC0, 0x44, 0x22, 0x00, 0x00, + 0x44, 0x12, 0xD3, 0x50, 0xEA, 0x2C, 0xB6, 0x61, 0xA4, 0xC0, 0xEA, 0x2C, 0xA8, 0xC9, 0xA4, 0xC6, + 0xEA, 0x2C, 0xA8, 0xCA, 0xA8, 0xCB, 0x02, 0x30, 0x00, 0x0A, 0xEA, 0x2C, 0xA8, 0xCC, 0x02, 0x30, + 0x00, 0x1A, 0xEA, 0x2C, 0xA8, 0xCD, 0x02, 0x30, 0x00, 0x0C, 0xEA, 0x2C, 0xA8, 0xCE, 0x02, 0x30, + 0x00, 0x20, 0xEA, 0x2C, 0xA8, 0xCF, 0xA4, 0xC2, 0xEA, 0x2C, 0x14, 0x30, 0x80, 0x08, 0x02, 0x30, + 0x00, 0x14, 0xEA, 0x2C, 0x14, 0x30, 0x80, 0x09, 0x02, 0x30, 0x00, 0x08, 0xEA, 0x2C, 0x14, 0x30, + 0x80, 0x0A, 0x02, 0x30, 0x00, 0x18, 0xEA, 0x2C, 0x14, 0x30, 0x80, 0x0B, 0x02, 0x30, 0x00, 0x0E, + 0xEA, 0x2C, 0x14, 0x30, 0x80, 0x0C, 0x02, 0x30, 0x00, 0x22, 0xEA, 0x2C, 0x14, 0x30, 0x80, 0x0D, + 0x02, 0x30, 0x00, 0x10, 0xEA, 0x2C, 0x14, 0x30, 0x80, 0x0E, 0x02, 0x30, 0x00, 0x24, 0xEA, 0x2C, + 0x14, 0x30, 0x80, 0x0F, 0xA4, 0xC4, 0xEA, 0x2C, 0x14, 0x30, 0x80, 0x10, 0x02, 0x30, 0x00, 0x1C, + 0xEA, 0x2C, 0x14, 0x30, 0x80, 0x11, 0x02, 0x30, 0x00, 0x12, 0xEA, 0x2C, 0x14, 0x30, 0x80, 0x13, + 0x02, 0x00, 0x00, 0x1E, 0x40, 0x21, 0x00, 0x40, 0x14, 0x20, 0x80, 0x14, 0xDD, 0x9E, 0xFC, 0x00, + 0xEB, 0x18, 0x3C, 0x2C, 0x01, 0xB6, 0xEB, 0x09, 0x88, 0x22, 0x92, 0x22, 0x96, 0x49, 0x12, 0x10, + 0x00, 0x10, 0xFC, 0x80, 0xA4, 0x00, 0x44, 0x12, 0x00, 0x00, 0xEA, 0xC3, 0x3C, 0x0E, 0x01, 0xC8, + 0xDD, 0x9E, 0xFC, 0x00, 0x44, 0x23, 0xF6, 0xAC, 0x44, 0x13, 0xF6, 0xAD, 0x5A, 0x08, 0x01, 0x06, + 0xAE, 0x10, 0x84, 0x07, 0xAE, 0x08, 0xD5, 0x04, 0x84, 0x00, 0xAE, 0x10, 0xAE, 0x08, 0x84, 0x00, + 0x80, 0x20, 0x80, 0x40, 0xFA, 0x6F, 0xEA, 0x4B, 0xFC, 0x80, 0x2E, 0x07, 0xEF, 0x0E, 0x5A, 0x00, + 0x01, 0x43, 0xEA, 0xAE, 0x3C, 0x5D, 0xFC, 0x20, 0xC8, 0x38, 0xEA, 0xB5, 0xD0, 0x3E, 0x3C, 0x0C, + 0x01, 0xB7, 0xD0, 0x3B, 0xEB, 0x97, 0xD0, 0x39, 0x3C, 0x0C, 0x01, 0xB8, 0xD0, 0x38, 0x3C, 0x0C, + 0x01, 0xB9, 0xD0, 0x35, 0xEB, 0xAD, 0xD0, 0x35, 0x3C, 0x0C, 0x01, 0xC7, 0xD0, 0x34, 0x3C, 0x0C, + 0x01, 0xBA, 0xD0, 0x33, 0x3C, 0x0C, 0x01, 0xBB, 0xD0, 0x30, 0x3C, 0x0C, 0x01, 0xBC, 0xD0, 0x2F, + 0x3C, 0x0C, 0x01, 0xBD, 0xD0, 0x2C, 0x3C, 0x0C, 0x01, 0xBE, 0xD0, 0x2B, 0x3C, 0x0C, 0x01, 0xBF, + 0xD0, 0x28, 0x3C, 0x0C, 0x01, 0xC0, 0xD0, 0x27, 0x3C, 0x0C, 0x01, 0xC1, 0xD0, 0x24, 0x3C, 0x0C, + 0x01, 0xC2, 0xD0, 0x23, 0x3C, 0x0C, 0x01, 0xC3, 0xD0, 0x20, 0x3C, 0x0C, 0x01, 0xC4, 0xD0, 0x1F, + 0x3C, 0x0C, 0x01, 0xC5, 0xD8, 0x20, 0xD5, 0x1B, 0xEB, 0x97, 0xD0, 0x1B, 0xEB, 0xAD, 0xD8, 0x1B, + 0x84, 0x0C, 0xDD, 0x9E, 0x84, 0x0D, 0xDD, 0x9E, 0x84, 0x01, 0xDD, 0x9E, 0x84, 0x02, 0xDD, 0x9E, + 0x84, 0x09, 0xDD, 0x9E, 0x84, 0x0A, 0xDD, 0x9E, 0x84, 0x05, 0xDD, 0x9E, 0x84, 0x06, 0xDD, 0x9E, + 0x84, 0x03, 0xDD, 0x9E, 0x84, 0x04, 0xDD, 0x9E, 0x84, 0x07, 0xDD, 0x9E, 0x84, 0x08, 0xDD, 0x9E, + 0x84, 0x0B, 0xDD, 0x9E, 0x84, 0x0E, 0xDD, 0x9E, 0xFC, 0x20, 0x84, 0x1F, 0x2E, 0x27, 0xEF, 0x0E, + 0xEA, 0x51, 0x84, 0x00, 0x80, 0xE4, 0x80, 0xC5, 0x3E, 0x07, 0xEE, 0xB7, 0x3E, 0x07, 0xEE, 0xC9, + 0x5A, 0x28, 0x01, 0x05, 0xEB, 0xF7, 0xB6, 0x05, 0xD5, 0x5B, 0x9E, 0x8C, 0xE6, 0x42, 0x50, 0x20, + 0xFF, 0xF8, 0xE9, 0x04, 0x96, 0xD0, 0xE6, 0x62, 0xE8, 0x17, 0x96, 0x90, 0xE6, 0x42, 0xE8, 0x0A, + 0xEB, 0xA6, 0x5A, 0x00, 0xA1, 0x23, 0x3C, 0x0C, 0x01, 0xCA, 0xB6, 0x06, 0x3C, 0x0F, 0xFC, 0x20, + 0xD5, 0x47, 0x2E, 0x07, 0xF2, 0xC6, 0xC8, 0x19, 0xDD, 0x43, 0x5A, 0x08, 0x02, 0x17, 0x3C, 0x0C, + 0x01, 0xC7, 0xB6, 0x06, 0xD5, 0x3D, 0x5A, 0x18, 0x0D, 0x31, 0x2E, 0x17, 0xF2, 0xE3, 0x8E, 0x21, + 0xE6, 0x27, 0xE8, 0x23, 0x44, 0xF1, 0x06, 0x60, 0xEA, 0xD6, 0xEA, 0x89, 0x4A, 0x00, 0x3C, 0x00, + 0x44, 0x08, 0x0E, 0x16, 0x42, 0x30, 0x24, 0x00, 0xEB, 0xAD, 0xB6, 0x06, 0xD5, 0x29, 0x3C, 0x0C, + 0x01, 0xBE, 0xB6, 0x05, 0xD5, 0x25, 0x3C, 0x0C, 0x01, 0xBF, 0xB6, 0x05, 0x84, 0x01, 0x3E, 0x07, + 0xEE, 0xB7, 0xD5, 0x1E, 0xEA, 0x51, 0x3E, 0x07, 0xEE, 0xCD, 0x3E, 0x07, 0xEF, 0x3B, 0xD5, 0x18, + 0x3C, 0x0C, 0x01, 0xBC, 0xB6, 0x05, 0xD5, 0x14, 0xDD, 0x54, 0xA6, 0x00, 0xC0, 0x04, 0x5A, 0x08, + 0x03, 0x10, 0x84, 0x02, 0xEA, 0x51, 0xD5, 0x0C, 0x8E, 0x2A, 0xE6, 0x22, 0xE8, 0x04, 0xEB, 0x97, + 0xB6, 0x05, 0xD5, 0x06, 0xDD, 0x54, 0xA6, 0x00, 0x49, 0x00, 0x07, 0x77, 0xB6, 0x06, 0x2E, 0x07, + 0xEF, 0x58, 0x5A, 0x00, 0xFF, 0x21, 0x2E, 0x57, 0xEE, 0xCD, 0xD0, 0x04, 0x84, 0x20, 0x3E, 0x17, + 0xEF, 0x3B, 0x2E, 0x17, 0xEF, 0x3B, 0x44, 0x22, 0xD3, 0x50, 0x96, 0x48, 0xC9, 0x0A, 0x38, 0x21, + 0x02, 0x02, 0xB6, 0x46, 0x84, 0x41, 0x3E, 0x27, 0xEF, 0x3B, 0x3E, 0x17, 0xEE, 0xB7, 0xD5, 0x0B, + 0x9C, 0x41, 0x38, 0x11, 0x06, 0x02, 0xB6, 0x26, 0x84, 0x20, 0x3E, 0x17, 0xEF, 0x3B, 0x84, 0x21, + 0x3E, 0x17, 0xEE, 0xB7, 0x3E, 0x07, 0xEE, 0xCD, 0xB4, 0x06, 0x3C, 0x0F, 0xFC, 0x20, 0xEB, 0x18, + 0xB4, 0x46, 0xEB, 0x09, 0x88, 0x22, 0x92, 0x22, 0x96, 0x49, 0x12, 0x10, 0x00, 0x10, 0xEB, 0x18, + 0x44, 0x1E, 0x00, 0x20, 0x88, 0x01, 0x92, 0x02, 0x96, 0x01, 0x44, 0x13, 0xF4, 0x00, 0xAC, 0x08, + 0x97, 0xF8, 0x44, 0x03, 0xF4, 0x02, 0xAF, 0xC0, 0x49, 0xFF, 0xFE, 0xF9, 0x3E, 0x07, 0xEE, 0xF4, + 0x84, 0x00, 0x3E, 0x07, 0xEF, 0x47, 0x2E, 0x07, 0xEE, 0xB7, 0x5A, 0x08, 0x01, 0x28, 0xDD, 0x48, + 0x5A, 0x00, 0x01, 0x05, 0xDD, 0x48, 0x5A, 0x08, 0x02, 0x06, 0x84, 0x0E, 0x3E, 0x07, 0xEE, 0xC9, + 0xD5, 0x0A, 0xDD, 0x48, 0x5A, 0x00, 0x03, 0x05, 0xDD, 0x48, 0x5A, 0x08, 0x04, 0x05, 0x84, 0x0C, + 0x3E, 0x07, 0xEE, 0xC9, 0x2E, 0x07, 0xEE, 0xB1, 0x5A, 0x08, 0x01, 0x11, 0xDD, 0x48, 0x5A, 0x00, + 0x03, 0x0B, 0xDD, 0x48, 0x5A, 0x00, 0x04, 0x08, 0xDD, 0x48, 0x5A, 0x00, 0x07, 0x05, 0xDD, 0x48, + 0x5A, 0x08, 0x08, 0x05, 0x84, 0x01, 0x3E, 0x07, 0xEF, 0x47, 0xFC, 0xA0, 0x92, 0x00, 0xB4, 0x40, + 0x84, 0xA0, 0x8C, 0x44, 0x9C, 0x2D, 0xA2, 0xD1, 0x96, 0x00, 0x5A, 0x58, 0x20, 0x06, 0x80, 0xA0, + 0x5A, 0x08, 0x23, 0xFA, 0xDD, 0x9E, 0x54, 0x41, 0x80, 0x3F, 0x38, 0x40, 0x94, 0x08, 0x8C, 0xA1, + 0x97, 0x68, 0x92, 0x66, 0xD8, 0xF3, 0xD5, 0xF4, 0xFC, 0x20, 0xB4, 0x80, 0x84, 0x60, 0x8C, 0x84, + 0x84, 0xE5, 0xB4, 0x04, 0x5A, 0x38, 0x06, 0x05, 0x66, 0x00, 0x0F, 0xFF, 0xD5, 0x04, 0x92, 0x1E, + 0x40, 0x00, 0x78, 0x08, 0x42, 0x21, 0x9C, 0x24, 0x84, 0xA0, 0x96, 0x90, 0x5A, 0x20, 0x20, 0x0C, + 0x38, 0x60, 0x88, 0x00, 0x8C, 0x41, 0x40, 0x63, 0x14, 0x0C, 0x8C, 0xA6, 0x88, 0x06, 0x96, 0x90, + 0x5A, 0x58, 0x1E, 0xF6, 0x8C, 0x61, 0x96, 0xD8, 0xAA, 0x21, 0x5A, 0x38, 0x07, 0xE4, 0xFC, 0xA0, + 0xFC, 0x20, 0xB4, 0x60, 0x84, 0x00, 0x50, 0x31, 0x80, 0x24, 0x95, 0x83, 0xA3, 0x19, 0x97, 0xB0, + 0x84, 0x40, 0x99, 0x56, 0x8C, 0x41, 0x54, 0x72, 0x00, 0x0F, 0x97, 0x68, 0x96, 0x90, 0x38, 0x70, + 0x94, 0x08, 0x92, 0x84, 0x5A, 0x28, 0x08, 0xF7, 0x8C, 0x01, 0x96, 0x00, 0x5A, 0x08, 0x04, 0xEF, + 0xFC, 0xA0, 0xFC, 0x20, 0xB4, 0x60, 0x84, 0x00, 0x50, 0x31, 0x80, 0x34, 0x95, 0x83, 0xA3, 0x19, + 0x97, 0xB0, 0x84, 0x40, 0x99, 0x56, 0x8C, 0x41, 0x54, 0x72, 0x00, 0x0F, 0x97, 0x68, 0x96, 0x90, + 0x38, 0x70, 0x94, 0x08, 0x92, 0x84, 0x5A, 0x28, 0x08, 0xF7, 0x8C, 0x01, 0x96, 0x00, 0x5A, 0x08, + 0x04, 0xEF, 0xFC, 0xA0, 0xFC, 0x00, 0xEA, 0xB5, 0x3C, 0x0F, 0xFC, 0x20, 0x84, 0x23, 0x44, 0x03, + 0xF4, 0x0B, 0xAE, 0x40, 0x84, 0x26, 0x44, 0x03, 0xF4, 0x04, 0xAE, 0x40, 0x84, 0x01, 0x44, 0x13, + 0xF4, 0x07, 0xAE, 0x08, 0x44, 0x13, 0xF4, 0x08, 0xAE, 0x08, 0x84, 0x40, 0x44, 0x13, 0xF0, 0x1E, + 0xAE, 0x88, 0x44, 0x13, 0xF4, 0x20, 0xAE, 0x08, 0xEA, 0x2E, 0x5A, 0x08, 0x01, 0x05, 0xEA, 0xB5, + 0x49, 0x00, 0x05, 0xC1, 0x44, 0x02, 0xD3, 0x50, 0x44, 0x12, 0xD6, 0xD0, 0xF8, 0x24, 0x44, 0x02, + 0xD3, 0x50, 0xEB, 0x87, 0x49, 0xFF, 0xFF, 0xA6, 0x44, 0x02, 0xD3, 0x58, 0x44, 0x12, 0xDA, 0x00, + 0x49, 0xFF, 0xFF, 0xA0, 0x44, 0x02, 0xD3, 0x54, 0x44, 0x12, 0xD6, 0x08, 0xF8, 0x14, 0x44, 0x02, + 0xD3, 0x54, 0x44, 0x12, 0xD4, 0x8C, 0xF8, 0x15, 0x44, 0x12, 0xDB, 0x1C, 0x44, 0x02, 0xD3, 0x50, + 0xF8, 0x10, 0x49, 0x00, 0x06, 0xE3, 0xEB, 0x3C, 0x49, 0x00, 0x07, 0x42, 0x44, 0x02, 0xD3, 0x9C, + 0x44, 0x12, 0xDA, 0x34, 0x49, 0xFF, 0xFF, 0x4D, 0x44, 0x02, 0xD3, 0x9C, 0x44, 0x12, 0xD6, 0x6C, + 0x49, 0xFF, 0xFF, 0x99, 0xFC, 0x80, 0xFC, 0x00, 0xB4, 0x80, 0x84, 0x40, 0x50, 0x42, 0x00, 0x24, + 0x84, 0x00, 0x80, 0xA0, 0x98, 0xD0, 0x96, 0xD8, 0x38, 0x30, 0x8C, 0x00, 0x95, 0x82, 0x96, 0xDF, + 0x40, 0x31, 0x98, 0x0C, 0x8C, 0x01, 0x88, 0xA3, 0x5A, 0x08, 0x08, 0xF6, 0x8C, 0x48, 0x96, 0x90, + 0xAB, 0x61, 0x5A, 0x28, 0x20, 0xEF, 0xFC, 0x80, 0xFC, 0x04, 0xA6, 0x49, 0xB4, 0x40, 0x5A, 0x10, + 0x03, 0x04, 0x5A, 0x18, 0x0D, 0x0E, 0xEB, 0xD7, 0xA6, 0x48, 0xC9, 0x04, 0xEB, 0x87, 0xEA, 0x77, + 0xFC, 0x84, 0x5A, 0x18, 0x03, 0x25, 0x44, 0x12, 0xDA, 0x00, 0xEA, 0x77, 0xFC, 0x84, 0x5A, 0x18, + 0x04, 0x07, 0xF8, 0x16, 0x58, 0x00, 0x00, 0x03, 0xB8, 0x89, 0xFC, 0x84, 0x50, 0x30, 0xFF, 0xF6, + 0xE6, 0x62, 0xE8, 0x0B, 0x84, 0x20, 0x84, 0x46, 0x38, 0x20, 0xFC, 0x08, 0x8C, 0x21, 0x5A, 0x18, + 0x20, 0xFD, 0x80, 0x3F, 0xEA, 0x77, 0xFC, 0x84, 0x8E, 0x28, 0xE6, 0x22, 0xE8, 0x08, 0x83, 0x82, + 0xB8, 0x09, 0x66, 0x00, 0x00, 0x0F, 0x83, 0xFF, 0xEB, 0x1C, 0xB8, 0x89, 0xFC, 0x84, 0xFC, 0x00, + 0xA6, 0x81, 0x80, 0xC0, 0x5A, 0x20, 0x03, 0x14, 0x5A, 0x20, 0x06, 0x12, 0x9E, 0x14, 0xE6, 0x02, + 0xE9, 0x0E, 0x50, 0x01, 0x7F, 0xF8, 0xE6, 0x02, 0xE9, 0x0D, 0x50, 0x01, 0x7F, 0xF6, 0xE6, 0x02, + 0xE9, 0x09, 0x5A, 0x28, 0x0D, 0x1C, 0xDD, 0x43, 0x5A, 0x08, 0x02, 0x05, 0x84, 0x00, 0xEB, 0x73, + 0xD5, 0x03, 0x84, 0x01, 0xEB, 0x73, 0xEA, 0xAE, 0xA6, 0x71, 0x2E, 0x27, 0xEE, 0xD1, 0x84, 0x81, + 0x2E, 0x37, 0xEE, 0xFD, 0x44, 0x52, 0xBD, 0x24, 0x49, 0xFF, 0xFD, 0xF8, 0xDD, 0x43, 0x5A, 0x00, + 0x02, 0x06, 0xEA, 0x58, 0x80, 0x26, 0x49, 0xFF, 0xFF, 0xA1, 0xFC, 0x80, 0xFC, 0x00, 0xB4, 0x80, + 0x84, 0x40, 0x50, 0x42, 0x00, 0x34, 0x84, 0x00, 0x80, 0xA0, 0x98, 0xD0, 0x96, 0xD8, 0x38, 0x30, + 0x8C, 0x00, 0x95, 0x82, 0x96, 0xDF, 0x40, 0x31, 0x98, 0x0C, 0x8C, 0x01, 0x88, 0xA3, 0x5A, 0x08, + 0x08, 0xF6, 0x8C, 0x48, 0x96, 0x90, 0xAB, 0x61, 0x5A, 0x28, 0x20, 0xEF, 0xFC, 0x80, 0xFC, 0x01, + 0x44, 0x12, 0xD9, 0x5C, 0xF0, 0x81, 0x49, 0xFF, 0xFE, 0xC1, 0xF0, 0x01, 0x44, 0x12, 0xD6, 0x28, + 0xF9, 0xC2, 0xFC, 0x81, 0xFC, 0x24, 0x80, 0xC0, 0xEB, 0xF0, 0x84, 0xA0, 0xEB, 0x0A, 0x45, 0x12, + 0xD6, 0x28, 0x50, 0x42, 0x80, 0x08, 0x97, 0x20, 0x80, 0x60, 0xA7, 0xD8, 0x44, 0x22, 0xD6, 0x28, + 0x97, 0xDF, 0x38, 0x78, 0x94, 0x08, 0x09, 0x01, 0x80, 0x01, 0x9D, 0xE9, 0x8C, 0xA2, 0x97, 0xF8, + 0x93, 0x84, 0x97, 0x68, 0x39, 0x08, 0x9C, 0x08, 0xDC, 0xF1, 0x8C, 0x04, 0x5A, 0x58, 0x20, 0xEB, + 0x2E, 0x00, 0x12, 0x1E, 0x44, 0x42, 0xD9, 0x5C, 0x2E, 0x30, 0x12, 0x0D, 0x5A, 0x18, 0x06, 0x4D, + 0x84, 0x29, 0x38, 0x12, 0x00, 0x08, 0xE6, 0x62, 0x84, 0x22, 0x38, 0x11, 0x00, 0x08, 0xE9, 0x2C, + 0xDD, 0x43, 0x5A, 0x08, 0x02, 0x2A, 0x2E, 0x20, 0x12, 0x1E, 0x44, 0x02, 0xDE, 0x64, 0x38, 0x30, + 0x08, 0x00, 0x80, 0x20, 0x5A, 0x30, 0x05, 0x21, 0x84, 0x00, 0x5A, 0x68, 0x03, 0x12, 0x2E, 0x10, + 0x12, 0x0D, 0x84, 0x00, 0x8E, 0x22, 0xE2, 0x01, 0x44, 0x42, 0xDA, 0x00, 0xF8, 0x54, 0x5A, 0x08, + 0x20, 0xFF, 0xC2, 0x0B, 0x40, 0x0F, 0x88, 0x00, 0x10, 0xF0, 0x7F, 0xFF, 0xD5, 0x06, 0x38, 0x30, + 0x80, 0x00, 0xF8, 0x4B, 0x5A, 0x08, 0x20, 0xFD, 0x84, 0x09, 0x38, 0x0F, 0x88, 0x08, 0x80, 0x3F, + 0xEA, 0x58, 0xEA, 0x77, 0xF8, 0x11, 0x84, 0x00, 0x5A, 0x68, 0x03, 0x11, 0x44, 0x22, 0xDA, 0x00, + 0xF8, 0x68, 0x5A, 0x08, 0x20, 0xFF, 0x2E, 0x00, 0x12, 0x1E, 0x84, 0x23, 0x38, 0x1F, 0x80, 0x08, + 0xEA, 0x58, 0x80, 0x3F, 0xEA, 0x77, 0x48, 0x00, 0x00, 0x66, 0x44, 0x22, 0xDE, 0x64, 0xF8, 0x59, + 0x5A, 0x08, 0x20, 0xFF, 0xD5, 0xF1, 0x84, 0x20, 0x38, 0x12, 0x00, 0x08, 0x5A, 0x68, 0x03, 0x05, + 0x38, 0x61, 0x00, 0x08, 0xD5, 0x04, 0x84, 0x21, 0x38, 0x11, 0x00, 0x08, 0xE6, 0x62, 0xE9, 0x36, + 0xDD, 0x43, 0x5A, 0x08, 0x02, 0x34, 0x2E, 0x10, 0x12, 0x1E, 0x44, 0x02, 0xDE, 0x64, 0x38, 0x30, + 0x04, 0x00, 0x80, 0x40, 0x5A, 0x30, 0x03, 0x2B, 0x5A, 0x30, 0x05, 0x29, 0x84, 0x00, 0x5A, 0x68, + 0x03, 0x19, 0x2E, 0x00, 0x12, 0x0D, 0x84, 0x48, 0x5A, 0x08, 0x02, 0x03, 0x84, 0x47, 0x84, 0x00, + 0x44, 0x42, 0xDA, 0x00, 0x38, 0x32, 0x00, 0x00, 0x38, 0x3F, 0x80, 0x08, 0x8C, 0x01, 0x83, 0xFF, + 0x5A, 0x08, 0x20, 0xFA, 0xC1, 0x0C, 0x40, 0x0F, 0x84, 0x00, 0x10, 0x20, 0x7F, 0xFF, 0xD5, 0x07, + 0x38, 0x31, 0x00, 0x00, 0x4E, 0x00, 0xFF, 0xF2, 0x5A, 0x08, 0x20, 0xFC, 0x84, 0x02, 0x38, 0x0F, + 0x84, 0x08, 0xEA, 0x58, 0x80, 0x3F, 0xEA, 0x77, 0xD5, 0x1D, 0x84, 0x00, 0x5A, 0x68, 0x03, 0x10, + 0x44, 0x22, 0xDA, 0x00, 0xF8, 0x0E, 0x5A, 0x08, 0x20, 0xFF, 0x2E, 0x00, 0x12, 0x1E, 0x84, 0x25, + 0x38, 0x1F, 0x80, 0x08, 0xEA, 0x58, 0x80, 0x3F, 0xEA, 0x77, 0xD5, 0x0C, 0x44, 0x22, 0xDE, 0x64, + 0x38, 0x11, 0x00, 0x00, 0x38, 0x1F, 0x80, 0x08, 0x8C, 0x01, 0x83, 0xFF, 0x5A, 0x08, 0x20, 0xFA, + 0xD5, 0xED, 0xEA, 0x58, 0x49, 0xFF, 0xFF, 0x25, 0xFC, 0xA4, 0xDD, 0x48, 0x5A, 0x00, 0x03, 0x0C, + 0xDD, 0x48, 0x5A, 0x00, 0x04, 0x09, 0xDD, 0x48, 0x5A, 0x00, 0x07, 0x06, 0xDD, 0x48, 0x8E, 0x08, + 0xEA, 0xB8, 0xDD, 0x9E, 0x84, 0x01, 0xDD, 0x9E, 0x3C, 0x5D, 0xFC, 0x20, 0xEB, 0x97, 0x4C, 0x50, + 0x00, 0x4B, 0xFC, 0x00, 0x49, 0xFF, 0xFF, 0xEB, 0xC0, 0x45, 0x2E, 0x10, 0x0F, 0x6C, 0xEB, 0xF0, + 0xC9, 0x04, 0xF8, 0x0F, 0x84, 0x46, 0xD5, 0x16, 0x5A, 0x18, 0x01, 0x05, 0xF8, 0x0A, 0x84, 0x47, + 0xD5, 0x11, 0x5A, 0x18, 0x03, 0x05, 0xF8, 0x05, 0x84, 0x4B, 0xD5, 0x0C, 0x5A, 0x18, 0x02, 0x14, + 0xEB, 0xB5, 0x44, 0x22, 0x04, 0x20, 0x92, 0x30, 0xEA, 0x64, 0x40, 0x11, 0x04, 0x40, 0x83, 0xFF, + 0x84, 0x4A, 0xAE, 0x8C, 0xEB, 0xB5, 0x44, 0x32, 0x03, 0xC0, 0x92, 0x30, 0xEA, 0x64, 0x40, 0x11, + 0x84, 0x40, 0xAE, 0x8C, 0x2E, 0x10, 0x0F, 0x6D, 0xC9, 0x05, 0xF8, 0x12, 0x84, 0x26, 0xAE, 0x46, + 0xFC, 0x80, 0x5A, 0x18, 0x01, 0x06, 0xF8, 0x0C, 0x84, 0x27, 0xAE, 0x46, 0xFC, 0x80, 0x5A, 0x18, + 0x03, 0x06, 0xF8, 0x06, 0x84, 0x2B, 0xAE, 0x46, 0xFC, 0x80, 0x5A, 0x18, 0x02, 0x0C, 0x04, 0x00, + 0x00, 0x14, 0x44, 0x12, 0x04, 0x20, 0x92, 0x10, 0xEA, 0x87, 0xEA, 0xC3, 0x83, 0xFF, 0x84, 0x2A, + 0xAE, 0x46, 0xFC, 0x80, 0xDD, 0x9E, 0x84, 0x45, 0x40, 0x30, 0x08, 0x17, 0x84, 0x86, 0x96, 0xD8, + 0xFE, 0x24, 0x38, 0x10, 0x8E, 0x02, 0x40, 0x00, 0x80, 0x0D, 0x96, 0x2F, 0xDD, 0x9E, 0xFC, 0x00, + 0xEB, 0x8A, 0x5A, 0x10, 0x01, 0x09, 0xEB, 0x8A, 0x5A, 0x10, 0x02, 0x06, 0xEB, 0x8A, 0x5A, 0x18, + 0x03, 0x13, 0xD5, 0x14, 0xF8, 0x13, 0x44, 0x52, 0xB7, 0x38, 0x44, 0x62, 0xD6, 0x28, 0xF8, 0x18, + 0xE8, 0xF6, 0x98, 0xA9, 0x38, 0x21, 0x10, 0x00, 0xCA, 0x03, 0x38, 0x03, 0x04, 0x08, 0x8C, 0x21, + 0x96, 0x48, 0xD5, 0xF6, 0xEB, 0x8A, 0x5A, 0x18, 0x04, 0x1B, 0x3C, 0x3D, 0xFC, 0x20, 0x2E, 0x47, + 0xEE, 0xC9, 0x84, 0x20, 0x83, 0xFF, 0x44, 0x52, 0xB7, 0x18, 0x44, 0x62, 0xD6, 0x28, 0x04, 0x21, + 0x80, 0x08, 0x96, 0xAF, 0xE0, 0x22, 0x83, 0xFF, 0xE8, 0x0A, 0x98, 0xA9, 0x38, 0x21, 0x10, 0x00, + 0xCA, 0x03, 0x38, 0x03, 0x04, 0x08, 0x8C, 0x21, 0x96, 0x48, 0xD5, 0xF2, 0xFC, 0x80, 0xFC, 0x01, + 0xF0, 0x81, 0xEB, 0xF0, 0x84, 0xA0, 0xEB, 0x0A, 0x44, 0x62, 0xD6, 0x28, 0x50, 0x22, 0x80, 0x08, + 0x96, 0x90, 0x80, 0x20, 0xA6, 0xC8, 0x96, 0xDF, 0x38, 0x33, 0x14, 0x08, 0x08, 0x40, 0x80, 0x01, + 0x9C, 0xE9, 0x8C, 0xA2, 0x96, 0xD8, 0x92, 0x84, 0x97, 0x68, 0x38, 0x43, 0x0C, 0x08, 0x44, 0x32, + 0xD6, 0x28, 0xDA, 0xF1, 0x8C, 0x04, 0x5A, 0x58, 0x20, 0xEB, 0xDD, 0x54, 0xA6, 0x00, 0x84, 0x43, + 0xC8, 0x02, 0x84, 0x41, 0xDD, 0x48, 0x5A, 0x00, 0x01, 0x05, 0xDD, 0x48, 0x5A, 0x08, 0x02, 0x18, + 0x3C, 0x4D, 0xFC, 0x20, 0x2E, 0x57, 0xEE, 0xC9, 0x84, 0x00, 0x44, 0x62, 0xB7, 0x38, 0x04, 0x12, + 0x00, 0x08, 0x96, 0x6F, 0xE0, 0x01, 0xE8, 0x11, 0x98, 0x70, 0x38, 0x10, 0x94, 0x00, 0x5A, 0x18, + 0x01, 0x04, 0x38, 0x21, 0x80, 0x08, 0x8C, 0x01, 0x96, 0x00, 0xD5, 0xF2, 0xDD, 0x48, 0x5A, 0x00, + 0x03, 0x0E, 0xDD, 0x48, 0x5A, 0x00, 0x04, 0x0B, 0xF0, 0x01, 0x49, 0xFF, 0xFF, 0x82, 0xEA, 0x58, + 0x44, 0x12, 0xD6, 0x28, 0x49, 0xFF, 0xFE, 0x1C, 0xFC, 0x81, 0x3C, 0x4D, 0xFC, 0x20, 0x2E, 0x57, + 0xEE, 0xC9, 0x84, 0x00, 0x44, 0x62, 0xB7, 0x18, 0x04, 0x12, 0x00, 0x08, 0x96, 0x6F, 0xE0, 0x01, + 0xE8, 0xEC, 0x98, 0x70, 0x38, 0x10, 0x94, 0x00, 0x5A, 0x18, 0x01, 0x04, 0x38, 0x21, 0x80, 0x08, + 0x8C, 0x01, 0x96, 0x00, 0xD5, 0xF2, 0x44, 0x13, 0x8D, 0x40, 0xAE, 0x08, 0xAE, 0x98, 0x44, 0x02, + 0xB7, 0x88, 0x38, 0x00, 0x08, 0x00, 0xEB, 0x37, 0xDD, 0x9E, 0xFC, 0x01, 0x80, 0xC0, 0xDD, 0x54, + 0xF1, 0x81, 0xAF, 0x80, 0xF0, 0x01, 0xEA, 0x3E, 0x5A, 0x68, 0x03, 0x0A, 0xEB, 0xBC, 0xA6, 0x00, + 0x44, 0x12, 0xB7, 0x88, 0x38, 0x00, 0x80, 0x00, 0xEB, 0x37, 0xD5, 0x03, 0x84, 0x00, 0xEB, 0x37, + 0xF8, 0x03, 0xF0, 0x01, 0xEA, 0x3E, 0xEB, 0x76, 0x49, 0xFF, 0xFF, 0x7B, 0xF0, 0x01, 0xEA, 0x3E, + 0xFC, 0x81, 0xFC, 0x60, 0xDD, 0x5A, 0x84, 0x00, 0xEB, 0x73, 0x84, 0x03, 0x00, 0xA0, 0x80, 0x01, + 0x44, 0x73, 0x8D, 0x41, 0xAE, 0x09, 0x44, 0x63, 0x8D, 0x40, 0x84, 0x1F, 0x00, 0x93, 0x80, 0x00, + 0x00, 0xB3, 0x00, 0x00, 0x3E, 0x07, 0xEE, 0xCD, 0x84, 0x00, 0x80, 0x40, 0x80, 0x67, 0xEB, 0x93, + 0xEA, 0x58, 0x44, 0x12, 0xD6, 0xD0, 0x49, 0xFF, 0xFC, 0xA1, 0x84, 0x03, 0xDD, 0x5A, 0x80, 0x49, + 0x80, 0x67, 0xEB, 0x93, 0xE7, 0x62, 0x84, 0x03, 0xE8, 0x02, 0x84, 0x00, 0xAE, 0x30, 0x44, 0x12, + 0xD6, 0xD0, 0xEA, 0x58, 0x49, 0xFF, 0xFC, 0x92, 0xA6, 0x30, 0xDD, 0x5A, 0x80, 0x49, 0xEA, 0x5E, + 0xEB, 0x93, 0xA6, 0x30, 0x3E, 0x07, 0xEF, 0x19, 0xDD, 0x41, 0x10, 0xA0, 0x00, 0x01, 0xFC, 0xE0, + 0x84, 0x00, 0xEB, 0xD7, 0xAE, 0x08, 0x44, 0x10, 0x00, 0xC8, 0x3C, 0x1B, 0xF7, 0xF0, 0x44, 0x12, + 0xC3, 0x24, 0x3E, 0x07, 0xEF, 0x19, 0xAE, 0x08, 0xAE, 0x09, 0xAE, 0x0A, 0xAE, 0x0B, 0xDD, 0x9E, + 0xFC, 0x02, 0xEB, 0x00, 0x44, 0x00, 0xFF, 0xFF, 0xF0, 0x83, 0xF1, 0x82, 0xF2, 0x81, 0xEA, 0xC7, + 0xEA, 0x62, 0xEA, 0x82, 0xFC, 0x82, 0xFC, 0x00, 0xDD, 0x43, 0x5A, 0x08, 0x02, 0x0E, 0x84, 0x00, + 0x3E, 0x07, 0xF3, 0x0C, 0xEA, 0x21, 0xDD, 0x5B, 0x2E, 0x07, 0xF3, 0x0C, 0x5A, 0x00, 0x01, 0x04, + 0xAE, 0x88, 0xD5, 0xFB, 0xFC, 0x80, 0xDD, 0x40, 0x5A, 0x08, 0x01, 0x1E, 0xEA, 0x8A, 0x44, 0x13, + 0x8D, 0x38, 0xAE, 0x08, 0x2E, 0x27, 0xEE, 0xB4, 0x44, 0x03, 0x8D, 0x39, 0xAE, 0x80, 0x2E, 0x27, + 0xF2, 0xE3, 0x44, 0x03, 0x8D, 0x3A, 0xAE, 0x80, 0x2E, 0x27, 0xEA, 0xE0, 0x44, 0x03, 0x8D, 0x3B, + 0xAE, 0x80, 0xDD, 0x5B, 0x44, 0x03, 0x8D, 0x3C, 0xAE, 0x80, 0x84, 0x68, 0x80, 0x41, 0x84, 0x02, + 0xDD, 0x42, 0xFC, 0x80, 0xDD, 0x47, 0xDD, 0x45, 0xAE, 0x40, 0x44, 0x13, 0x8D, 0x3C, 0xA6, 0x08, + 0x5A, 0x08, 0x55, 0xFF, 0x44, 0x13, 0x8D, 0x38, 0xA6, 0x08, 0xEB, 0x99, 0xA6, 0x09, 0xEB, 0xD4, + 0xA6, 0x0A, 0xEB, 0x43, 0xA6, 0x0B, 0xEB, 0x37, 0x84, 0x00, 0xAE, 0x08, 0x44, 0x13, 0x8D, 0x39, + 0xAE, 0x08, 0x44, 0x13, 0x8D, 0x3A, 0xAE, 0x08, 0x44, 0x13, 0x8D, 0x3B, 0xAE, 0x08, 0x44, 0x13, + 0x8D, 0x3C, 0xAE, 0x08, 0xFC, 0x80, 0x84, 0x00, 0x3C, 0x0B, 0xF7, 0xDA, 0x3C, 0x0B, 0xF7, 0xC2, + 0xDD, 0x54, 0xA6, 0x00, 0xC0, 0x04, 0x9E, 0x43, 0xE6, 0x22, 0xE8, 0x12, 0x44, 0x03, 0x73, 0x20, + 0xA6, 0x00, 0x3C, 0x0B, 0xF7, 0xC2, 0x44, 0x13, 0x73, 0x22, 0x44, 0x03, 0x73, 0x21, 0x44, 0x23, + 0x73, 0x23, 0xA6, 0x00, 0xA6, 0x48, 0xA6, 0x90, 0x3C, 0x2B, 0xF7, 0xDA, 0xD5, 0x26, 0x9E, 0x41, + 0xE6, 0x22, 0xE9, 0x03, 0x5A, 0x08, 0x05, 0x20, 0x84, 0x00, 0x44, 0x53, 0x73, 0x20, 0x80, 0x20, + 0x44, 0x33, 0x73, 0x34, 0xA7, 0x28, 0x3C, 0x23, 0xF7, 0xC2, 0x8C, 0xA4, 0x88, 0x44, 0x3C, 0x2B, + 0xF7, 0xC2, 0x00, 0x22, 0xFF, 0xFD, 0x88, 0x02, 0x00, 0x22, 0xFF, 0xFE, 0x00, 0x42, 0xFF, 0xFF, + 0x88, 0x22, 0x3C, 0x23, 0xF7, 0xDA, 0x96, 0x01, 0x88, 0x44, 0x96, 0x49, 0x3C, 0x2B, 0xF7, 0xDA, + 0xDB, 0xEA, 0xD5, 0x03, 0x84, 0x00, 0x80, 0x20, 0x3C, 0x23, 0xF7, 0xDA, 0x88, 0x22, 0x3C, 0x23, + 0xF7, 0xC2, 0x96, 0x49, 0x88, 0x02, 0x96, 0x01, 0x3C, 0x1B, 0xF7, 0xDA, 0x88, 0x20, 0x3C, 0x0B, + 0xF7, 0xC2, 0x3C, 0x1B, 0xF7, 0xD8, 0xDD, 0x9E, 0xFC, 0x02, 0xF0, 0x82, 0xF1, 0x83, 0xB6, 0x5F, + 0x80, 0x02, 0xF1, 0x02, 0x80, 0x43, 0xF3, 0x81, 0xEA, 0x73, 0xB4, 0x1F, 0xF1, 0x03, 0xF2, 0x01, + 0xEA, 0x73, 0xFC, 0x82, 0xFC, 0x00, 0x84, 0xA0, 0x40, 0x30, 0x8C, 0x20, 0x4C, 0x11, 0x80, 0x18, + 0xA5, 0x00, 0xA5, 0x88, 0xE2, 0xC4, 0xE8, 0x03, 0xA5, 0x00, 0xAD, 0x08, 0xA5, 0x80, 0xA5, 0x10, + 0xE2, 0xC4, 0xE8, 0x03, 0xA5, 0x00, 0xAD, 0x10, 0x0A, 0x40, 0x80, 0x01, 0x0A, 0x61, 0x00, 0x01, + 0x8A, 0x86, 0xE0, 0xA4, 0xE8, 0x02, 0x97, 0x61, 0x8C, 0x02, 0xD5, 0xE9, 0x80, 0x05, 0xFC, 0x80, + 0xFC, 0x00, 0x84, 0xA0, 0x40, 0x30, 0x8C, 0x20, 0x4C, 0x11, 0x80, 0x18, 0xA5, 0x00, 0xA5, 0x88, + 0xE2, 0xC4, 0xE8, 0x03, 0xA5, 0x00, 0xAD, 0x08, 0xA5, 0x80, 0xA5, 0x10, 0xE2, 0xC4, 0xE8, 0x03, + 0xA5, 0x00, 0xAD, 0x10, 0x0A, 0x40, 0x80, 0x01, 0x0A, 0x61, 0x00, 0x01, 0x8A, 0x86, 0xE0, 0xA4, + 0xE8, 0x02, 0x97, 0x61, 0x8C, 0x02, 0xD5, 0xE9, 0x80, 0x05, 0xFC, 0x80, 0xFC, 0x20, 0x44, 0x60, + 0x03, 0x20, 0x80, 0xE1, 0xFF, 0x84, 0xDD, 0x40, 0xC0, 0x04, 0xEA, 0x4A, 0x88, 0x06, 0xD5, 0x04, + 0x44, 0x03, 0x01, 0x90, 0x88, 0x06, 0x44, 0x13, 0x73, 0xE8, 0xEB, 0x23, 0xEA, 0xE7, 0xF8, 0x21, + 0xAC, 0x38, 0xFC, 0xA0, 0xFC, 0x00, 0x51, 0xFF, 0xF9, 0xB8, 0xF0, 0x81, 0x84, 0x00, 0xDD, 0x59, + 0x3C, 0x0B, 0xF9, 0x7E, 0x50, 0x1F, 0x83, 0x28, 0xB0, 0x02, 0x44, 0x23, 0x1C, 0x20, 0x49, 0xFF, + 0xFF, 0x95, 0xDD, 0x40, 0xEA, 0xE7, 0xC0, 0x09, 0xF0, 0x01, 0xB0, 0x42, 0x50, 0x2F, 0x83, 0x28, + 0xF8, 0x08, 0x3C, 0x0B, 0xF9, 0xA5, 0xD5, 0x09, 0xF0, 0x01, 0xB0, 0x42, 0x50, 0x2F, 0x83, 0x28, + 0x49, 0xFF, 0xFF, 0xB0, 0x3C, 0x0B, 0xF9, 0xA4, 0x51, 0xFF, 0x86, 0x48, 0xFC, 0x80, 0x80, 0xA0, + 0x40, 0x10, 0x04, 0x20, 0x84, 0x00, 0xD1, 0x08, 0xA4, 0xA8, 0xE2, 0x02, 0xE8, 0x03, 0xA4, 0x28, + 0x96, 0x01, 0x8C, 0xA2, 0xD5, 0xF9, 0xDD, 0x9E, 0x80, 0xA0, 0x40, 0x10, 0x04, 0x20, 0x44, 0x00, + 0xFF, 0xFF, 0xD1, 0x08, 0xA4, 0xA8, 0xE2, 0x40, 0xE8, 0x03, 0xA4, 0x28, 0x96, 0x01, 0x8C, 0xA2, + 0xD5, 0xF9, 0xDD, 0x9E, 0xFC, 0x60, 0x44, 0x63, 0x01, 0x90, 0x81, 0x61, 0x44, 0x10, 0x03, 0x20, + 0x42, 0x60, 0x04, 0x73, 0x81, 0x43, 0x81, 0x22, 0x44, 0x73, 0x73, 0xE8, 0x44, 0xC3, 0x75, 0x78, + 0xDD, 0x40, 0xEA, 0xBE, 0xC0, 0x0D, 0x50, 0xD3, 0x7E, 0x70, 0x80, 0x0D, 0x49, 0xFF, 0xFF, 0xD1, + 0x02, 0x14, 0x80, 0x00, 0xE2, 0x20, 0xE8, 0x02, 0xEA, 0xBC, 0x80, 0x0D, 0xD5, 0x0A, 0x80, 0x06, + 0x49, 0xFF, 0xFF, 0xC7, 0x02, 0x14, 0x80, 0x00, 0xE2, 0x20, 0xE8, 0x02, 0xEA, 0xBC, 0x80, 0x06, + 0xEA, 0xBE, 0x49, 0xFF, 0xFF, 0xCB, 0x02, 0x15, 0x00, 0x00, 0xE2, 0x01, 0xE8, 0x03, 0x12, 0x05, + 0x00, 0x00, 0xDD, 0x40, 0x50, 0x23, 0x83, 0x20, 0xC0, 0x04, 0x50, 0x03, 0x7E, 0x70, 0xD5, 0x02, + 0x80, 0x06, 0x80, 0x27, 0xEA, 0xF2, 0x49, 0xFF, 0xFF, 0x37, 0xEB, 0xED, 0xE2, 0x20, 0xE8, 0x03, + 0x12, 0x05, 0x80, 0x00, 0x50, 0x73, 0x80, 0x64, 0x8D, 0x62, 0x50, 0x63, 0x00, 0x64, 0x8D, 0x42, + 0x8D, 0x22, 0x4C, 0x76, 0x7F, 0xC7, 0xFC, 0xE0, 0xFC, 0x00, 0x2E, 0x07, 0xF2, 0xE4, 0x2E, 0x17, + 0xF3, 0x72, 0xC0, 0x20, 0x3C, 0x0D, 0xCD, 0x81, 0x5A, 0x18, 0x01, 0x05, 0x92, 0x01, 0x96, 0x01, + 0xD5, 0x03, 0x92, 0x02, 0x96, 0x01, 0x3C, 0x2D, 0xFC, 0xBE, 0xE2, 0x40, 0x2E, 0x07, 0xF3, 0x09, + 0xE8, 0x06, 0xE6, 0x1E, 0xE8, 0x0F, 0x8C, 0x01, 0xEB, 0xF9, 0xD5, 0x0C, 0xC0, 0x0B, 0x5C, 0xF1, + 0x0E, 0x10, 0xE9, 0x06, 0xE6, 0x0F, 0xE9, 0x04, 0x8E, 0x05, 0xEB, 0xF9, 0xD5, 0x03, 0x8E, 0x01, + 0xEB, 0xF9, 0x5A, 0x18, 0x01, 0x11, 0x2E, 0x07, 0xF3, 0x09, 0x5A, 0x08, 0x1E, 0x05, 0x84, 0x05, + 0xEB, 0xE5, 0xD5, 0x0C, 0xE6, 0x14, 0xE9, 0x04, 0x84, 0x06, 0xEB, 0xE5, 0xD5, 0x07, 0x84, 0x07, + 0xEB, 0xE5, 0xD5, 0x04, 0x49, 0xFF, 0xF7, 0x29, 0xEB, 0xE5, 0xFC, 0x80, 0x3C, 0x33, 0xFB, 0x53, + 0x5C, 0xF1, 0x80, 0x33, 0xE9, 0x13, 0xFC, 0x00, 0x84, 0x80, 0x84, 0xC3, 0xE2, 0x82, 0xE8, 0x0D, + 0x40, 0x30, 0x10, 0x20, 0xA5, 0x58, 0xA4, 0xC8, 0x8C, 0x81, 0xFE, 0xF4, 0x90, 0x62, 0x40, 0x31, + 0x94, 0x5C, 0x1A, 0x30, 0x80, 0x01, 0xD5, 0xF3, 0xFC, 0x80, 0xDD, 0x9E, 0x84, 0x00, 0xEB, 0x9B, + 0x84, 0x00, 0xEA, 0xB1, 0xDD, 0x9E, 0xFC, 0x00, 0x3C, 0x03, 0xFB, 0x53, 0x5C, 0xF0, 0x00, 0x33, + 0xE9, 0x05, 0xF8, 0xAE, 0x84, 0x00, 0x3C, 0x0B, 0xF7, 0xEF, 0x3C, 0x03, 0xFB, 0x52, 0x5C, 0xF0, + 0x00, 0x33, 0xE9, 0x03, 0x84, 0x00, 0xEB, 0xC4, 0xFC, 0x80, 0xB4, 0x61, 0xAE, 0x18, 0x5A, 0x28, + 0x02, 0x04, 0x92, 0x08, 0xAE, 0x19, 0xB4, 0x01, 0x88, 0x40, 0xB6, 0x41, 0xDD, 0x9E, 0xFC, 0x44, + 0x81, 0x40, 0xB6, 0x1F, 0x81, 0x21, 0x84, 0x00, 0xB1, 0xC1, 0x38, 0x15, 0x00, 0x00, 0x38, 0x10, + 0x1C, 0x08, 0x8C, 0x01, 0x5A, 0x08, 0x1A, 0xFB, 0x44, 0x00, 0x19, 0x00, 0xF8, 0x28, 0x3C, 0x1C, + 0x01, 0xB8, 0xB4, 0x1F, 0xA6, 0x88, 0xAE, 0x80, 0xB4, 0x1F, 0x9C, 0x81, 0xB6, 0x5F, 0x04, 0x20, + 0x80, 0x1E, 0x80, 0x3F, 0x92, 0x50, 0x96, 0xAF, 0xAE, 0x81, 0xB4, 0x1F, 0x84, 0x42, 0x8C, 0x01, + 0xB6, 0x1F, 0x44, 0x00, 0x02, 0x80, 0xF8, 0x15, 0xEA, 0xB5, 0x80, 0x3F, 0x04, 0x60, 0x00, 0x14, + 0xEB, 0x3D, 0x92, 0xD0, 0x54, 0x63, 0x7F, 0xFF, 0x40, 0x60, 0x18, 0x40, 0x83, 0x86, 0xB8, 0x0E, + 0x84, 0x42, 0x92, 0x10, 0x96, 0x05, 0xF8, 0x05, 0x02, 0x03, 0x00, 0x16, 0x80, 0x3F, 0x84, 0x42, + 0x49, 0xFF, 0xFF, 0xBD, 0xB8, 0x0B, 0x80, 0x3F, 0x92, 0x10, 0x54, 0x00, 0x0F, 0xFF, 0x4E, 0x00, + 0xFF, 0xF8, 0xB4, 0x1F, 0x00, 0x13, 0x00, 0x28, 0xAE, 0x40, 0xB4, 0x1F, 0xEA, 0x21, 0x8C, 0x01, + 0xB6, 0x1F, 0xEA, 0x34, 0x10, 0x04, 0x80, 0x51, 0xDD, 0x5B, 0x00, 0x04, 0x80, 0x51, 0x5A, 0x00, + 0xCC, 0x04, 0xAE, 0x88, 0xD5, 0xFB, 0xDD, 0x40, 0xC0, 0x07, 0x44, 0x12, 0xFE, 0x51, 0x84, 0x02, + 0x80, 0x41, 0x84, 0x61, 0xDD, 0x42, 0x84, 0x40, 0x38, 0x03, 0x88, 0x00, 0x38, 0x05, 0x08, 0x08, + 0x8C, 0x41, 0x5A, 0x28, 0x1A, 0xFB, 0x84, 0x00, 0x10, 0x04, 0x80, 0x51, 0xFC, 0xC4, 0xFC, 0x00, + 0xDD, 0x54, 0xA6, 0x00, 0x54, 0x00, 0x00, 0xFB, 0xC8, 0x06, 0xF8, 0x05, 0x44, 0x20, 0x00, 0x64, + 0xEA, 0x73, 0xFC, 0x80, 0xEA, 0xF7, 0x3C, 0x1C, 0x03, 0x20, 0x83, 0xFF, 0xEA, 0xC8, 0xEA, 0x73, + 0xFC, 0x80, 0x2E, 0x07, 0xEE, 0xEC, 0x8E, 0x01, 0xE6, 0x02, 0xE8, 0x11, 0xFC, 0x01, 0xEA, 0x27, + 0x3C, 0x2F, 0xFC, 0xA1, 0xF2, 0x81, 0xDD, 0x40, 0xF2, 0x01, 0xEA, 0xA3, 0xC0, 0x04, 0xEA, 0xF7, + 0xEA, 0x73, 0xFC, 0x81, 0x44, 0x03, 0x0E, 0x10, 0xEA, 0x73, 0xFC, 0x81, 0xDD, 0x9E, 0xFC, 0x00, + 0xDD, 0x40, 0xC0, 0x03, 0x49, 0xFF, 0xFF, 0x51, 0x2E, 0x07, 0xEE, 0xEC, 0xC0, 0x0A, 0x49, 0xFF, + 0xFF, 0x47, 0xDD, 0x54, 0xA6, 0x00, 0x49, 0xFF, 0xFF, 0xDE, 0x84, 0x00, 0x3E, 0x07, 0xEE, 0xEC, + 0xFC, 0x80, 0xFC, 0x00, 0x04, 0x00, 0x00, 0x14, 0x44, 0x12, 0x00, 0x60, 0x92, 0x10, 0xEA, 0x87, + 0xEA, 0xC3, 0x2E, 0x17, 0x34, 0x98, 0x10, 0x10, 0x00, 0x18, 0x2E, 0x17, 0x34, 0x99, 0x10, 0x10, + 0x00, 0x19, 0x2E, 0x17, 0x34, 0x96, 0x10, 0x10, 0x00, 0x1B, 0x2E, 0x17, 0x34, 0x97, 0x10, 0x10, + 0x00, 0x1A, 0xA0, 0x45, 0x42, 0x10, 0xF0, 0x08, 0xA8, 0x45, 0xA0, 0x45, 0x42, 0x10, 0xF4, 0x08, + 0xA8, 0x45, 0xA0, 0x45, 0x42, 0x10, 0xFC, 0x08, 0xA8, 0x45, 0xA0, 0x45, 0x42, 0x10, 0xF8, 0x08, + 0xA8, 0x45, 0xDD, 0x40, 0xC0, 0x05, 0x44, 0x03, 0x73, 0x20, 0xF8, 0x04, 0xFC, 0x80, 0x44, 0x03, + 0x73, 0x84, 0x49, 0xFF, 0xF0, 0xE6, 0xFC, 0x80, 0x3C, 0x0F, 0xFD, 0xAE, 0xDD, 0x9E, 0x2E, 0x37, + 0xF3, 0x72, 0x5A, 0x38, 0x01, 0x18, 0x00, 0x30, 0x00, 0x10, 0x3E, 0x37, 0x35, 0xED, 0xA0, 0xC5, + 0x84, 0x0A, 0xFE, 0x1C, 0x3C, 0x0F, 0xCD, 0x7C, 0xA4, 0x12, 0x3C, 0x0B, 0x9B, 0x34, 0xA4, 0x13, + 0x3C, 0x0B, 0x9B, 0x35, 0xA6, 0x0A, 0x3E, 0x07, 0x36, 0x38, 0xA6, 0x0B, 0x3E, 0x07, 0x36, 0x39, + 0xDD, 0x9E, 0xA6, 0xC0, 0x3E, 0x37, 0x35, 0xED, 0xA0, 0x03, 0x3C, 0x0F, 0xCD, 0x7C, 0xA6, 0x08, + 0x3E, 0x07, 0x36, 0x38, 0xA6, 0x09, 0x3E, 0x07, 0x36, 0x39, 0xA4, 0x10, 0x3C, 0x0B, 0x9B, 0x34, + 0xA4, 0x11, 0x3C, 0x0B, 0x9B, 0x35, 0xDD, 0x9E, 0x5A, 0x00, 0x01, 0x05, 0x44, 0x12, 0x81, 0x78, + 0xD5, 0x02, 0xEA, 0xA3, 0x50, 0x40, 0x83, 0x20, 0x80, 0xA1, 0x84, 0x00, 0x1A, 0x02, 0x80, 0x01, + 0xDC, 0xFE, 0xFC, 0x20, 0x44, 0x53, 0x00, 0x00, 0x44, 0x63, 0x0C, 0x80, 0x80, 0x01, 0x80, 0x65, + 0x0A, 0x21, 0x80, 0x01, 0xA5, 0xC0, 0x40, 0x23, 0x88, 0x5C, 0x1A, 0x20, 0x00, 0x01, 0x4C, 0x02, + 0x7F, 0xF9, 0x50, 0x52, 0x83, 0x20, 0xDE, 0xF3, 0xFC, 0xA0, 0xFC, 0x60, 0x84, 0x80, 0x84, 0xFF, + 0x84, 0xC1, 0x82, 0x67, 0x80, 0xA4, 0x82, 0x24, 0x44, 0x92, 0xC3, 0x24, 0x81, 0x66, 0x81, 0x04, + 0x03, 0x00, 0x00, 0x00, 0x55, 0x22, 0x00, 0xFF, 0xE3, 0x82, 0x81, 0x40, 0xE8, 0x0E, 0x03, 0x00, + 0x80, 0x00, 0xE3, 0x83, 0xE8, 0x0A, 0x38, 0x84, 0x90, 0x08, 0xA5, 0x80, 0xE2, 0xD3, 0xE8, 0x08, + 0x82, 0x66, 0x82, 0x32, 0x84, 0xC0, 0xD5, 0x05, 0x38, 0xB4, 0x90, 0x08, 0xD5, 0x02, 0x84, 0xC0, + 0x0B, 0x00, 0x80, 0x01, 0x02, 0xA5, 0x00, 0x00, 0x8C, 0x81, 0x89, 0x8A, 0xE3, 0x87, 0x8C, 0x02, + 0x40, 0x78, 0x3C, 0x1B, 0x40, 0x59, 0x3C, 0x1B, 0x5A, 0x48, 0x04, 0xDC, 0x5A, 0x60, 0x01, 0x03, + 0x80, 0xB1, 0x80, 0x05, 0xFC, 0xE0, 0xFC, 0x00, 0x2E, 0x17, 0xEF, 0x39, 0x3C, 0x6C, 0x01, 0xB6, + 0xC1, 0x0B, 0x84, 0x00, 0x3E, 0x07, 0xEF, 0x39, 0x44, 0x10, 0x00, 0xE6, 0x84, 0x06, 0x3C, 0x6C, + 0x01, 0xC9, 0xDD, 0x44, 0xD5, 0x35, 0xC8, 0x0B, 0x3C, 0x1D, 0xFC, 0x03, 0x5A, 0x10, 0x01, 0x30, + 0xDD, 0x52, 0x5A, 0x08, 0x02, 0x2E, 0x84, 0x08, 0xEA, 0x51, 0xD5, 0x2A, 0x5A, 0x08, 0x03, 0x0E, + 0xDD, 0x52, 0x5A, 0x08, 0x01, 0x05, 0x84, 0x02, 0xEA, 0x51, 0xD5, 0x22, 0xDD, 0x52, 0x5A, 0x08, + 0x02, 0x20, 0x84, 0x0A, 0xEA, 0x51, 0xD5, 0x1C, 0x5A, 0x08, 0x01, 0x0E, 0xDD, 0x52, 0x5A, 0x08, + 0x01, 0x05, 0x84, 0x04, 0xEA, 0x51, 0xD5, 0x14, 0xDD, 0x52, 0x5A, 0x08, 0x02, 0x12, 0x84, 0x0C, + 0xEA, 0x51, 0xD5, 0x0E, 0x5A, 0x08, 0x02, 0x0D, 0xDD, 0x52, 0x5A, 0x08, 0x01, 0x05, 0x84, 0x06, + 0xEA, 0x51, 0xD5, 0x06, 0xDD, 0x52, 0x5A, 0x08, 0x02, 0x04, 0x84, 0x0E, 0xEA, 0x51, 0x80, 0x06, + 0xFC, 0x80, 0xFC, 0x00, 0x2E, 0x07, 0xEF, 0x11, 0xC8, 0x29, 0x3C, 0x0D, 0xFC, 0xD9, 0xEB, 0x4F, + 0xE9, 0x04, 0x2E, 0x07, 0xF2, 0xF4, 0xC0, 0x05, 0x2E, 0x07, 0xF2, 0xF3, 0xEB, 0x4F, 0xE9, 0x1E, + 0x84, 0x20, 0x3C, 0x1B, 0xF7, 0xD3, 0x84, 0x00, 0x44, 0x32, 0x6E, 0xB8, 0xEA, 0xFC, 0xE2, 0x02, + 0xE8, 0x06, 0x98, 0x83, 0x8C, 0x01, 0xAE, 0x50, 0x96, 0x01, 0xD5, 0xF9, 0x3C, 0x0C, 0x03, 0x1C, + 0x3C, 0x1C, 0x03, 0x1E, 0xDD, 0x5D, 0x44, 0x00, 0x00, 0x33, 0xEA, 0xB1, 0xEA, 0xA3, 0xEB, 0x05, + 0xEA, 0x27, 0x49, 0xFF, 0xFD, 0xFD, 0x84, 0x01, 0xEB, 0x0D, 0xFC, 0x80, 0x40, 0x30, 0x0C, 0x20, + 0x4C, 0x01, 0x80, 0x05, 0x1A, 0x20, 0x00, 0x01, 0xD5, 0xFC, 0xDD, 0x9E, 0x44, 0x03, 0x8D, 0x40, + 0xA6, 0x40, 0x2E, 0x07, 0xEF, 0x2C, 0xC1, 0x06, 0x2E, 0x17, 0xEF, 0x2B, 0x5A, 0x18, 0x01, 0x03, + 0x8C, 0x01, 0x3E, 0x07, 0x34, 0x38, 0xDD, 0x9E, 0x3C, 0x1C, 0x01, 0xB6, 0x44, 0x22, 0x00, 0xC0, + 0x04, 0x00, 0x80, 0x14, 0x92, 0x10, 0xEA, 0x87, 0x40, 0x01, 0x00, 0x40, 0xB4, 0x00, 0x92, 0x0A, + 0x96, 0x37, 0x3E, 0x07, 0xEE, 0xFE, 0x04, 0x00, 0x80, 0x14, 0x44, 0x12, 0x00, 0x00, 0x92, 0x10, + 0xEA, 0x87, 0xEA, 0xC3, 0xB4, 0x20, 0x00, 0x00, 0x00, 0x28, 0x92, 0x2A, 0x96, 0x77, 0x3E, 0x17, + 0xEE, 0xDA, 0x3E, 0x07, 0xEF, 0x0A, 0xDD, 0x9E, 0xFC, 0x00, 0x84, 0x00, 0xEB, 0x1B, 0xDD, 0x4B, + 0x84, 0x21, 0xAE, 0x40, 0xDD, 0x45, 0xDD, 0x47, 0xAE, 0x40, 0x3C, 0x2D, 0xFC, 0x25, 0xA6, 0x50, + 0x5A, 0x10, 0x01, 0xFF, 0xDD, 0x47, 0xAE, 0x40, 0xEA, 0x7B, 0xA6, 0x08, 0x96, 0x00, 0xC8, 0xFE, + 0xDD, 0x50, 0x84, 0x41, 0x3C, 0x0F, 0xFC, 0x60, 0xAE, 0x88, 0xEA, 0xE1, 0x3E, 0x07, 0xF2, 0xF3, + 0xFC, 0x80, 0xFC, 0x20, 0x44, 0x42, 0x00, 0x00, 0x2E, 0x67, 0x34, 0xF8, 0x84, 0x20, 0x44, 0x33, + 0x8D, 0x40, 0x80, 0xE4, 0x96, 0x88, 0xE2, 0x46, 0xE8, 0x19, 0xA7, 0x58, 0x98, 0x81, 0xC5, 0x04, + 0x00, 0x51, 0x00, 0x20, 0xD5, 0x03, 0x38, 0x50, 0x04, 0x00, 0x41, 0x02, 0x04, 0x00, 0x10, 0x58, + 0x01, 0x60, 0xA7, 0x58, 0xC5, 0x04, 0x00, 0x21, 0x00, 0x28, 0xD5, 0x03, 0x00, 0x21, 0x00, 0x08, + 0x99, 0x79, 0x10, 0x22, 0x81, 0x68, 0x8C, 0x21, 0xD5, 0xE6, 0xFC, 0xA0, 0x44, 0x22, 0xD3, 0x50, + 0xB4, 0x62, 0x44, 0x42, 0x00, 0x00, 0x04, 0x11, 0x80, 0x14, 0xA0, 0x92, 0x92, 0x30, 0xEA, 0x64, + 0x40, 0x12, 0x04, 0x40, 0x04, 0x10, 0x80, 0x0A, 0x92, 0x32, 0x54, 0x10, 0x8F, 0xFF, 0x96, 0x4B, + 0x12, 0x10, 0x00, 0x75, 0x3C, 0x1B, 0xF7, 0xE7, 0x04, 0x11, 0x80, 0x14, 0x04, 0x21, 0x00, 0x15, + 0x92, 0x30, 0x44, 0x32, 0x01, 0x80, 0xEA, 0x64, 0x40, 0x11, 0x84, 0x40, 0x54, 0x21, 0x7F, 0xFF, + 0x44, 0x32, 0x00, 0x0C, 0x40, 0x21, 0x88, 0x40, 0x02, 0x30, 0x80, 0x1F, 0x10, 0x30, 0x00, 0xEC, + 0x02, 0x30, 0x80, 0x1F, 0x92, 0x68, 0x10, 0x30, 0x00, 0xED, 0x02, 0x30, 0x80, 0x1E, 0x10, 0x30, + 0x00, 0xEE, 0x02, 0x30, 0x80, 0x1E, 0x92, 0x68, 0x10, 0x30, 0x00, 0xEF, 0xA4, 0xD3, 0x10, 0x30, + 0x00, 0xF0, 0xA4, 0xD3, 0x92, 0x68, 0x10, 0x30, 0x00, 0xF1, 0xA4, 0xD1, 0x10, 0x30, 0x00, 0xF2, + 0xA4, 0xD1, 0x92, 0x68, 0x10, 0x30, 0x00, 0xF3, 0xA1, 0x12, 0x84, 0x61, 0x92, 0x98, 0x54, 0x52, + 0x00, 0x3F, 0x04, 0x40, 0x80, 0x11, 0x40, 0x41, 0x90, 0x3E, 0x40, 0x42, 0x90, 0xE4, 0x10, 0x40, + 0x00, 0xF4, 0xA0, 0x92, 0x04, 0x10, 0x80, 0x11, 0x92, 0x48, 0x96, 0xAF, 0xFE, 0xCE, 0x40, 0x31, + 0x0C, 0xE4, 0x10, 0x30, 0x00, 0xF5, 0xDD, 0x9E, 0xFC, 0x20, 0x80, 0xE0, 0x80, 0xC1, 0xDD, 0x40, + 0xC0, 0x0B, 0x50, 0x13, 0x00, 0xEC, 0x80, 0x41, 0x84, 0x6A, 0x84, 0x02, 0xDD, 0x42, 0xEA, 0x45, + 0x84, 0x02, 0xEB, 0xE7, 0xD5, 0x03, 0x84, 0x02, 0xEB, 0xE7, 0x3C, 0x0C, 0x01, 0xB8, 0x44, 0x22, + 0x01, 0x80, 0x83, 0x80, 0xB9, 0x14, 0xBB, 0x15, 0x92, 0x30, 0x44, 0x02, 0x00, 0x0C, 0x54, 0x31, + 0xFF, 0xFF, 0x40, 0x30, 0x0C, 0x40, 0xEA, 0x64, 0x00, 0x03, 0x00, 0xED, 0x40, 0x11, 0x04, 0x40, + 0x00, 0x23, 0x00, 0xEC, 0x40, 0x01, 0x01, 0x00, 0x96, 0x01, 0x12, 0x00, 0x80, 0x1F, 0x00, 0x03, + 0x00, 0xEF, 0x00, 0x23, 0x00, 0xEE, 0x40, 0x01, 0x01, 0x00, 0x96, 0x01, 0x12, 0x00, 0x80, 0x1E, + 0x00, 0x03, 0x00, 0xF4, 0x40, 0x20, 0x1C, 0x09, 0x50, 0x40, 0x80, 0x44, 0xB4, 0x04, 0xEA, 0xA0, + 0x40, 0x00, 0x08, 0x24, 0xB6, 0x04, 0xB4, 0x04, 0x00, 0x23, 0x00, 0xF5, 0x66, 0x00, 0x00, 0x01, + 0x40, 0x00, 0x08, 0xF5, 0xB6, 0x04, 0x00, 0x03, 0x00, 0xF1, 0x00, 0x13, 0x00, 0xF0, 0xEB, 0x44, + 0x96, 0x01, 0xAC, 0x1B, 0x00, 0x03, 0x00, 0xF3, 0x00, 0x13, 0x00, 0xF2, 0xEB, 0x44, 0x96, 0x01, + 0xAC, 0x19, 0x00, 0x03, 0x00, 0xF4, 0xA0, 0x9A, 0x54, 0x10, 0x00, 0x3F, 0x46, 0x0C, 0x0F, 0xFF, + 0x50, 0x00, 0x0F, 0xFF, 0xFE, 0x16, 0x40, 0x00, 0x07, 0x04, 0xA8, 0x1A, 0x00, 0x03, 0x00, 0xF5, + 0x54, 0x10, 0x00, 0x3F, 0xA0, 0x1A, 0x66, 0x00, 0x3F, 0x00, 0x40, 0x00, 0x05, 0x04, 0xA8, 0x1A, + 0xC7, 0x03, 0x8E, 0xE1, 0x97, 0xF8, 0x84, 0x03, 0xDD, 0x5A, 0x80, 0x47, 0xEA, 0x5E, 0xEB, 0x93, + 0x84, 0x03, 0xEA, 0x49, 0xFC, 0xA0, 0xFC, 0x60, 0x81, 0x21, 0x81, 0x62, 0x81, 0x43, 0x80, 0xC4, + 0xDD, 0x51, 0xA6, 0x08, 0x96, 0x00, 0x5A, 0x08, 0x01, 0xFE, 0xDD, 0x50, 0xAE, 0x08, 0x80, 0x20, + 0x49, 0xFF, 0xAB, 0x10, 0xDD, 0x58, 0xA6, 0x40, 0xC9, 0xFF, 0xA6, 0x40, 0x5A, 0x18, 0x01, 0xFF, + 0x84, 0x00, 0x3E, 0x07, 0xEF, 0x13, 0xDD, 0x40, 0xC0, 0x20, 0xEA, 0x67, 0x5A, 0x08, 0x06, 0xFF, + 0xEA, 0x4A, 0xEA, 0x86, 0xDD, 0x5D, 0xDD, 0x4B, 0x84, 0x21, 0xAE, 0x40, 0x00, 0x74, 0x81, 0x16, + 0xCF, 0x05, 0xF8, 0x08, 0x3E, 0x77, 0xEF, 0x13, 0xD5, 0x10, 0x00, 0x73, 0x00, 0x51, 0x97, 0xFC, + 0xCF, 0x06, 0x49, 0xFF, 0xA5, 0x27, 0x10, 0x74, 0x80, 0x86, 0xD5, 0x05, 0x84, 0x00, 0xEB, 0xEE, + 0x49, 0xFF, 0xA4, 0x5C, 0x84, 0x01, 0xEB, 0x17, 0x84, 0x0A, 0xEA, 0x9D, 0x84, 0x00, 0x10, 0x03, + 0x00, 0x51, 0x10, 0x03, 0x00, 0x52, 0x10, 0x03, 0x00, 0x53, 0xFC, 0xE0, 0x3C, 0x1C, 0x01, 0xB6, + 0x44, 0x22, 0x00, 0x00, 0x04, 0x10, 0x80, 0x14, 0x46, 0x3C, 0x00, 0x3F, 0x92, 0x30, 0xEA, 0x64, + 0x40, 0x11, 0x04, 0x40, 0x04, 0x20, 0x80, 0x0A, 0x50, 0x31, 0x8F, 0xFF, 0x54, 0x00, 0x0F, 0xFF, + 0xFE, 0x9E, 0x40, 0x21, 0x02, 0x44, 0x14, 0x20, 0x80, 0x0A, 0xDD, 0x9E, 0xFC, 0x42, 0x80, 0xC2, + 0x81, 0x20, 0x80, 0xE1, 0xFA, 0x40, 0x84, 0x20, 0x80, 0x1F, 0xEA, 0x2F, 0x98, 0x7E, 0x2E, 0x27, + 0xF6, 0xA8, 0x44, 0x32, 0xBF, 0x00, 0xEA, 0x74, 0x96, 0x49, 0x38, 0x01, 0x88, 0x08, 0x80, 0x83, + 0x44, 0x62, 0xE3, 0x5C, 0xC1, 0x04, 0x38, 0x13, 0x09, 0x09, 0xD5, 0x04, 0x84, 0x01, 0x38, 0x03, + 0x09, 0x09, 0x84, 0x20, 0x9C, 0x11, 0x45, 0x01, 0x6E, 0x44, 0x45, 0x10, 0x0B, 0xB8, 0x99, 0x41, + 0x97, 0x57, 0x38, 0x72, 0x14, 0x00, 0x5A, 0x70, 0xFF, 0x0F, 0x38, 0x38, 0x04, 0x00, 0x38, 0x53, + 0x15, 0x01, 0x42, 0x31, 0xC4, 0x24, 0x40, 0x31, 0x94, 0x76, 0x38, 0x5F, 0x9E, 0x02, 0x88, 0x65, + 0x38, 0x3F, 0x9E, 0x0A, 0x8C, 0x21, 0x5A, 0x18, 0x08, 0xEC, 0x84, 0x20, 0x80, 0x61, 0x80, 0x81, + 0x38, 0x5F, 0x86, 0x02, 0x97, 0x88, 0xE2, 0x85, 0x8C, 0x21, 0x40, 0x33, 0x3C, 0x1B, 0x40, 0x42, + 0xBC, 0x1B, 0x5A, 0x18, 0x04, 0xF7, 0xE6, 0x47, 0xE9, 0x02, 0x84, 0x00, 0x3E, 0x07, 0xF6, 0xA8, + 0x10, 0x34, 0x80, 0x00, 0xFC, 0xC2, 0xFC, 0x21, 0x80, 0xC0, 0x84, 0x00, 0x80, 0xE1, 0x3C, 0x0B, + 0xF9, 0x7E, 0xDD, 0x43, 0x3C, 0x1D, 0xFD, 0xAE, 0x5A, 0x00, 0x02, 0x08, 0x02, 0x00, 0x80, 0x0F, + 0x84, 0x43, 0xFE, 0x84, 0x96, 0x91, 0xD5, 0x03, 0x02, 0x20, 0x80, 0x0F, 0x80, 0x62, 0x80, 0x27, + 0x80, 0x06, 0x49, 0xFF, 0xFD, 0x4C, 0x38, 0x13, 0x01, 0x01, 0xEA, 0x57, 0x38, 0x23, 0x81, 0x01, + 0x50, 0x0F, 0x80, 0x07, 0x49, 0xFF, 0xFF, 0x94, 0x44, 0x43, 0x8D, 0x41, 0xA6, 0x20, 0x38, 0x03, + 0x01, 0x01, 0x3C, 0x0B, 0xF9, 0x7E, 0xA6, 0x60, 0x00, 0x0F, 0x80, 0x07, 0x38, 0x23, 0x85, 0x01, + 0x38, 0x33, 0x05, 0x01, 0x88, 0x62, 0x38, 0x23, 0x01, 0x01, 0x38, 0x03, 0x81, 0x01, 0x88, 0x40, + 0xE0, 0x43, 0xE8, 0x06, 0x9A, 0x9A, 0x5C, 0xF1, 0x00, 0xC8, 0xE8, 0x05, 0xD5, 0x02, 0x84, 0x40, + 0x10, 0x1F, 0x80, 0x07, 0x94, 0x51, 0x44, 0x30, 0x01, 0xF4, 0x40, 0x10, 0x8C, 0x37, 0xE6, 0x23, + 0xA6, 0x20, 0xE8, 0x07, 0xC9, 0x07, 0x44, 0x10, 0x00, 0xC7, 0x40, 0x10, 0x88, 0x06, 0xD5, 0x02, + 0x84, 0x23, 0x00, 0x2F, 0x80, 0x07, 0x2E, 0x57, 0xF6, 0xB1, 0xDA, 0x07, 0x2E, 0x37, 0xF6, 0xA9, + 0x88, 0x61, 0x3E, 0x37, 0xF6, 0xA9, 0xD5, 0x03, 0x3E, 0x17, 0xF6, 0xA9, 0x2E, 0x37, 0xF6, 0xA9, + 0xE6, 0x63, 0xE8, 0x03, 0x5A, 0x18, 0x03, 0x06, 0x84, 0x00, 0x3E, 0x07, 0xF6, 0xA9, 0x80, 0x02, + 0x3E, 0x27, 0xF6, 0xB1, 0xFC, 0xA1, 0x84, 0x01, 0xDD, 0x9E, 0x5A, 0x08, 0x01, 0x07, 0x84, 0x01, + 0xAE, 0x08, 0x84, 0x00, 0xAC, 0x10, 0xDD, 0x9E, 0x3C, 0x0D, 0xFD, 0xAE, 0x02, 0x00, 0x00, 0x0F, + 0x42, 0x42, 0x00, 0x01, 0xE2, 0x83, 0xE9, 0xF4, 0xA4, 0x10, 0xE6, 0x1E, 0xE8, 0x04, 0x8C, 0x01, + 0xAC, 0x10, 0xDD, 0x9E, 0x84, 0x00, 0xAE, 0x08, 0xDD, 0x9E, 0xFC, 0x40, 0x81, 0x22, 0x84, 0x40, + 0x3C, 0x2B, 0xF9, 0x7E, 0x10, 0x91, 0x80, 0x00, 0x80, 0xC3, 0x81, 0x44, 0x49, 0xFF, 0xFF, 0x75, + 0x80, 0xE0, 0x44, 0x02, 0xC3, 0x24, 0x38, 0x10, 0x24, 0x00, 0x81, 0x20, 0x5A, 0x18, 0x01, 0x0E, + 0xEB, 0x3A, 0xE6, 0x02, 0xE8, 0x03, 0x8C, 0x01, 0xEB, 0x9B, 0x84, 0x01, 0x3E, 0x07, 0xF3, 0x72, + 0x84, 0x00, 0x3C, 0x0B, 0xF7, 0xEE, 0xD5, 0x30, 0x44, 0x12, 0xBF, 0xEA, 0x84, 0x00, 0x44, 0x22, + 0xBC, 0x54, 0x3C, 0x33, 0xF9, 0x7E, 0x3C, 0x43, 0xF7, 0xE8, 0x49, 0xFF, 0xFF, 0xC0, 0x2E, 0x17, + 0xF3, 0x08, 0xC1, 0x04, 0x8E, 0x21, 0x3E, 0x17, 0xF3, 0x08, 0x5A, 0xA8, 0x01, 0x13, 0x84, 0x40, + 0x80, 0x22, 0x38, 0x04, 0x88, 0x00, 0xC8, 0x03, 0x8C, 0x21, 0x96, 0x49, 0x8C, 0x41, 0x5A, 0x28, + 0x04, 0xFA, 0x5A, 0x18, 0x04, 0x07, 0x3C, 0x03, 0xFB, 0x52, 0x8C, 0x01, 0xEB, 0xC4, 0xD5, 0x03, + 0x84, 0x00, 0xEB, 0xC4, 0x3C, 0x13, 0xFB, 0x53, 0x44, 0x00, 0xEA, 0x5F, 0xE2, 0x01, 0xE9, 0x04, + 0x8C, 0x21, 0x3C, 0x1B, 0xFB, 0x53, 0x84, 0x00, 0xEA, 0xD4, 0xEB, 0x3A, 0xC0, 0x04, 0x84, 0x01, + 0xEA, 0xD4, 0xAF, 0xF0, 0xFC, 0xC0, 0xFC, 0x20, 0xDD, 0x54, 0xA6, 0x80, 0x2E, 0x17, 0xEE, 0xDA, + 0x2E, 0x07, 0xEF, 0x0A, 0x2E, 0x37, 0xEE, 0xBF, 0x2E, 0x50, 0x12, 0x2B, 0xCA, 0x05, 0x80, 0x40, + 0x82, 0x01, 0x80, 0x03, 0xD5, 0x04, 0x82, 0x05, 0x80, 0x43, 0x80, 0xA1, 0x42, 0x71, 0x40, 0x24, + 0x3D, 0x1C, 0x03, 0x1E, 0x42, 0x20, 0x14, 0x24, 0x84, 0x80, 0x45, 0x23, 0x33, 0x10, 0x3C, 0x03, + 0x99, 0xDE, 0xE2, 0x80, 0xE8, 0x14, 0x95, 0xA1, 0x40, 0x03, 0x48, 0x00, 0xA4, 0xC0, 0xA4, 0x40, + 0x88, 0xD1, 0xA4, 0x30, 0xFE, 0x6C, 0x42, 0x31, 0xC0, 0x24, 0x9A, 0x08, 0xFE, 0x3C, 0x8C, 0x81, + 0xEA, 0xC9, 0x9A, 0x18, 0x96, 0x01, 0xAC, 0x30, 0x97, 0x21, 0xD5, 0xEA, 0x3C, 0x0C, 0x03, 0x1E, + 0x3C, 0x1C, 0x03, 0x1C, 0xDD, 0x5D, 0xFC, 0xA0, 0x44, 0x53, 0x1C, 0x20, 0x44, 0x20, 0x03, 0xE8, + 0x44, 0x33, 0x1C, 0xE8, 0x5A, 0x08, 0x05, 0x0B, 0xA5, 0x28, 0x02, 0x12, 0x91, 0xB8, 0xFE, 0x64, + 0x40, 0x10, 0x88, 0x37, 0x96, 0x49, 0xAC, 0x68, 0xD5, 0x0B, 0x5A, 0x08, 0x01, 0x0A, 0xA4, 0x68, + 0x02, 0x42, 0x91, 0xB8, 0xFE, 0x54, 0x40, 0x10, 0x90, 0x37, 0x96, 0x49, 0xAC, 0x68, 0x8C, 0xA2, + 0xDB, 0xEA, 0xDD, 0x9E, 0xFC, 0x60, 0x80, 0xE0, 0xDD, 0x54, 0x80, 0xC1, 0x81, 0x82, 0x81, 0x63, + 0x81, 0x44, 0x00, 0x90, 0x00, 0x00, 0x5A, 0x78, 0x01, 0x16, 0xC1, 0x03, 0x8E, 0xC1, 0x97, 0xB0, + 0xEB, 0xBC, 0xA7, 0x40, 0xD6, 0x07, 0xEA, 0x8A, 0x5A, 0x08, 0x01, 0x05, 0x80, 0x06, 0x49, 0xFF, + 0xDF, 0x0C, 0x84, 0x03, 0xDD, 0x5A, 0x80, 0x46, 0xEA, 0x5E, 0xEB, 0x3E, 0x84, 0x03, 0xEA, 0x49, + 0xD5, 0x0F, 0x5A, 0x78, 0x02, 0x0E, 0x5A, 0x98, 0x04, 0x05, 0x84, 0x01, 0x49, 0xFF, 0xFF, 0xBE, + 0x84, 0x00, 0xDD, 0x5A, 0x80, 0x46, 0xEA, 0x5E, 0xEB, 0x3E, 0x84, 0x00, 0xEA, 0x49, 0xDD, 0x51, + 0xA6, 0x08, 0x96, 0x00, 0x5A, 0x08, 0x01, 0xFE, 0xDD, 0x50, 0xAE, 0x08, 0x80, 0x20, 0x49, 0xFF, + 0xA9, 0x11, 0xDD, 0x58, 0xA6, 0x40, 0xC9, 0xFF, 0xA6, 0x40, 0x5A, 0x18, 0x01, 0xFF, 0xDD, 0x40, + 0xC0, 0x07, 0xEA, 0x67, 0x5A, 0x08, 0x06, 0xFF, 0xEA, 0x4A, 0xEA, 0x86, 0xDD, 0x5D, 0xDD, 0x54, + 0xA6, 0x00, 0xC8, 0x04, 0x5A, 0x98, 0x04, 0x09, 0xD5, 0x05, 0x5A, 0x08, 0x04, 0x06, 0x4E, 0x93, + 0x00, 0x04, 0x49, 0xFF, 0xFF, 0x5A, 0x5A, 0x78, 0x01, 0x09, 0x84, 0x00, 0x10, 0x76, 0x00, 0x00, + 0x10, 0x75, 0x80, 0x00, 0xEA, 0x9D, 0xD5, 0x09, 0x5A, 0x78, 0x02, 0x08, 0x84, 0x00, 0x10, 0x06, + 0x00, 0x00, 0xEB, 0x17, 0x84, 0x01, 0xEA, 0x9D, 0xFC, 0xE0, 0xFC, 0x20, 0xEA, 0x3D, 0xEA, 0xA3, + 0x84, 0x40, 0xF8, 0x06, 0x44, 0x03, 0x77, 0x08, 0xEA, 0xA3, 0x44, 0x20, 0xFF, 0xFF, 0xEA, 0x4F, + 0x49, 0xFF, 0xFC, 0x6E, 0x84, 0x00, 0x45, 0x02, 0xBF, 0xB8, 0x80, 0x20, 0x44, 0x72, 0xBF, 0xB0, + 0x44, 0x62, 0xBF, 0xA8, 0x84, 0x5F, 0x44, 0x52, 0xBF, 0xA0, 0x44, 0x42, 0xBF, 0x98, 0x44, 0x32, + 0xBF, 0x90, 0x38, 0x18, 0x01, 0x09, 0x38, 0x13, 0x81, 0x09, 0x38, 0x23, 0x01, 0x09, 0x38, 0x12, + 0x81, 0x09, 0x38, 0x12, 0x01, 0x09, 0x38, 0x21, 0x81, 0x09, 0x8C, 0x01, 0x5A, 0x08, 0x04, 0xF3, + 0xFC, 0xA0, 0xFC, 0x00, 0x3C, 0x2D, 0xFD, 0xAE, 0xE2, 0x20, 0x02, 0x31, 0x00, 0x0E, 0x2E, 0x27, + 0xEE, 0xDA, 0x40, 0x10, 0x3C, 0x1B, 0x40, 0x10, 0x88, 0x3C, 0xEB, 0x52, 0x96, 0x49, 0xE2, 0x61, + 0x3C, 0x1B, 0xF9, 0x7E, 0xE8, 0x04, 0x84, 0x02, 0xEB, 0x9B, 0xD5, 0x14, 0xEB, 0x3A, 0xC0, 0x03, + 0x8E, 0x01, 0xEB, 0x9B, 0x3C, 0x03, 0xF7, 0xE8, 0xE2, 0x01, 0xE9, 0x0A, 0x3C, 0x03, 0xFB, 0x53, + 0x44, 0x10, 0xEA, 0x5F, 0xE2, 0x20, 0xE9, 0x06, 0x8C, 0x01, 0xEA, 0xB1, 0xD5, 0x03, 0x84, 0x00, + 0xEA, 0xB1, 0xEB, 0x3A, 0xE6, 0x02, 0xE9, 0x04, 0x84, 0x01, 0xEA, 0xD4, 0xD5, 0x03, 0x84, 0x00, + 0xEA, 0xD4, 0xFC, 0x80, 0xFC, 0x60, 0xEA, 0xC8, 0x40, 0x21, 0x04, 0x56, 0x81, 0x61, 0x54, 0xA1, + 0x00, 0xFF, 0x40, 0x91, 0x04, 0x08, 0x80, 0xE0, 0x84, 0xC0, 0x44, 0xC2, 0xBF, 0x98, 0x44, 0xD2, + 0xBF, 0x90, 0x44, 0xE2, 0xBF, 0xB0, 0x44, 0x82, 0xBF, 0xA8, 0x4C, 0x65, 0x80, 0x1A, 0xDD, 0x40, + 0xC0, 0x08, 0xF8, 0x07, 0x38, 0x07, 0x19, 0x09, 0xF8, 0x0A, 0x38, 0x04, 0x19, 0x09, 0xD5, 0x0D, + 0x80, 0x2A, 0x80, 0x07, 0x49, 0xFF, 0xF9, 0x55, 0x38, 0x06, 0x19, 0x09, 0x80, 0x2A, 0x80, 0x07, + 0x49, 0xFF, 0xF9, 0x5C, 0x38, 0x06, 0x99, 0x09, 0x8C, 0xC1, 0x88, 0xE9, 0xD5, 0xE7, 0xFC, 0xE0, + 0xFC, 0x00, 0xDD, 0x40, 0xC0, 0x13, 0xDD, 0x5F, 0xC8, 0x11, 0x49, 0xFF, 0xFA, 0xAA, 0xEA, 0xEC, + 0x3C, 0x0B, 0xF7, 0xE8, 0x84, 0x00, 0xEA, 0xD4, 0xDD, 0x40, 0x80, 0x20, 0xC0, 0x0C, 0xEB, 0x05, + 0x84, 0x20, 0xEB, 0x91, 0x84, 0x07, 0xEA, 0x4D, 0xD5, 0x16, 0xDD, 0x40, 0xC8, 0x14, 0xEA, 0x41, + 0xC0, 0xED, 0xD5, 0x11, 0xEB, 0x05, 0x50, 0x00, 0x01, 0x90, 0xEB, 0x91, 0x3C, 0x03, 0xF9, 0xA4, + 0x3C, 0x08, 0x06, 0xEF, 0xEB, 0x29, 0x84, 0x01, 0xEB, 0x51, 0x80, 0x41, 0xFA, 0x14, 0xEA, 0xEF, + 0xFA, 0x04, 0xEA, 0x83, 0xDD, 0x40, 0xC0, 0x1A, 0xDD, 0x5F, 0x5A, 0x08, 0x08, 0x18, 0x3C, 0x10, + 0x06, 0xEF, 0x3C, 0x03, 0xF9, 0xA5, 0x3C, 0x23, 0xF7, 0xE8, 0x49, 0xFF, 0xFF, 0x6C, 0x2E, 0x67, + 0xF2, 0xFE, 0x5A, 0x68, 0x01, 0x0A, 0x84, 0x02, 0xEA, 0x49, 0x84, 0x00, 0xEB, 0x0D, 0xEB, 0x7A, + 0xDD, 0x4A, 0xDD, 0x4B, 0xAF, 0x80, 0xFA, 0x04, 0xEA, 0x4D, 0xFC, 0x80, 0xFC, 0x40, 0xDD, 0x40, + 0xC0, 0x0A, 0xDD, 0x5F, 0xC8, 0x08, 0xF9, 0x8E, 0xDD, 0x40, 0x84, 0x21, 0xC0, 0x09, 0x3C, 0x1F, + 0xFA, 0xC3, 0xD5, 0x08, 0xDD, 0x40, 0xC8, 0x06, 0xEA, 0x41, 0xC0, 0xF6, 0xD5, 0x03, 0x3C, 0x1F, + 0xFA, 0xC2, 0xDD, 0x40, 0xC0, 0x19, 0xDD, 0x5F, 0xC0, 0x17, 0xDD, 0x5F, 0xE6, 0x06, 0xE8, 0x14, + 0xDD, 0x5F, 0xEB, 0xFC, 0x8E, 0x01, 0x96, 0x00, 0x44, 0x22, 0xBF, 0xB0, 0x44, 0x32, 0xBF, 0xA8, + 0xF8, 0x1C, 0xDD, 0x5F, 0xE6, 0x05, 0xE8, 0x05, 0xDD, 0x5F, 0x8C, 0x01, 0xEA, 0x4D, 0xD5, 0x46, + 0x84, 0x07, 0xEA, 0x4D, 0xD5, 0x43, 0xDD, 0x40, 0x80, 0xC0, 0xC8, 0x40, 0xEA, 0x41, 0xC0, 0x3E, + 0xEA, 0x41, 0xE6, 0x06, 0xE8, 0x3B, 0xEA, 0x41, 0x44, 0x12, 0xBF, 0xA0, 0x8E, 0x01, 0x96, 0x00, + 0x44, 0x22, 0xBF, 0x98, 0x44, 0x32, 0xBF, 0x90, 0x49, 0xFF, 0xF8, 0xDE, 0xEA, 0x41, 0xE6, 0x05, + 0xE8, 0x05, 0xEA, 0x41, 0x8C, 0x01, 0xEA, 0x83, 0xD5, 0x29, 0x80, 0x06, 0x44, 0x22, 0xDA, 0x54, + 0x44, 0x62, 0xBF, 0xA0, 0x44, 0x52, 0xBF, 0x98, 0x44, 0x42, 0xBF, 0x90, 0x9C, 0x44, 0x38, 0x33, + 0x01, 0x01, 0xEA, 0xD3, 0xAC, 0xCA, 0x50, 0x10, 0x00, 0x08, 0x38, 0x32, 0x81, 0x01, 0xEA, 0xD3, + 0xAC, 0xCA, 0x50, 0x10, 0x00, 0x0C, 0x38, 0x32, 0x01, 0x01, 0xEA, 0xD3, 0x8C, 0x01, 0xAC, 0xCA, + 0x5A, 0x08, 0x04, 0xEE, 0xEB, 0x29, 0x84, 0xC1, 0xFA, 0x14, 0x80, 0x41, 0x3E, 0x60, 0x0D, 0xDD, + 0xEA, 0xEF, 0xFA, 0x04, 0xEA, 0x83, 0xDD, 0x4B, 0xAF, 0x80, 0xDD, 0x40, 0x4E, 0x02, 0x00, 0x69, + 0xDD, 0x5F, 0x5A, 0x08, 0x08, 0x66, 0x44, 0x52, 0xBF, 0xB8, 0x44, 0x62, 0xDA, 0x54, 0x45, 0x02, + 0xBF, 0xB0, 0x45, 0x12, 0xBF, 0xA8, 0x84, 0x00, 0x80, 0xE6, 0x81, 0x25, 0x81, 0x50, 0x82, 0x71, + 0x45, 0x22, 0xBF, 0x88, 0x9C, 0xC4, 0x40, 0x33, 0x0C, 0x20, 0x38, 0x12, 0x81, 0x01, 0xA5, 0x1A, + 0x94, 0x81, 0xE2, 0x81, 0xE9, 0x03, 0xA4, 0x5A, 0x96, 0x49, 0x50, 0x30, 0x00, 0x08, 0x40, 0x33, + 0x8C, 0x20, 0x38, 0x14, 0x88, 0x09, 0xA5, 0x1A, 0x38, 0x18, 0x08, 0x01, 0xE2, 0x81, 0xE9, 0x03, + 0xA4, 0x5A, 0x96, 0x49, 0x50, 0x40, 0x00, 0x0C, 0x40, 0x43, 0x90, 0x20, 0x38, 0x38, 0x88, 0x01, + 0x02, 0xF2, 0x00, 0x02, 0x38, 0x15, 0x08, 0x09, 0xE2, 0x6F, 0xE9, 0x03, 0xA4, 0xE2, 0x96, 0xD9, + 0x8A, 0x23, 0x8C, 0x01, 0x38, 0x39, 0x88, 0x09, 0x38, 0x19, 0x08, 0x09, 0x5A, 0x08, 0x04, 0xD4, + 0x44, 0x20, 0x01, 0x2C, 0x44, 0x02, 0xBF, 0x88, 0xEB, 0xFC, 0x80, 0x62, 0x49, 0xFF, 0xFA, 0x47, + 0x80, 0xC0, 0x2E, 0x07, 0xF2, 0xE3, 0x5A, 0x08, 0x06, 0x05, 0xEA, 0x8A, 0x40, 0x60, 0x00, 0x1A, + 0xDD, 0x5A, 0x84, 0x02, 0x80, 0x46, 0xEA, 0x5E, 0xEB, 0x3E, 0x84, 0x03, 0xEA, 0x49, 0x50, 0x03, + 0x00, 0x44, 0x96, 0x00, 0xDD, 0x4A, 0x2E, 0x17, 0xF2, 0xE3, 0x84, 0x01, 0xEB, 0xCB, 0x5A, 0x10, + 0x06, 0x04, 0xF9, 0x30, 0xD5, 0x03, 0xDD, 0x50, 0xAE, 0x08, 0xFA, 0x04, 0xEA, 0x4D, 0xFC, 0xC0, + 0xFC, 0x41, 0xDD, 0x40, 0xC0, 0x0C, 0xDD, 0x5F, 0xC8, 0x0A, 0xDD, 0x40, 0x80, 0xC0, 0xC0, 0x0C, + 0xEB, 0x05, 0x84, 0x24, 0xF8, 0x0D, 0x84, 0x07, 0xEA, 0x4D, 0xD5, 0x2A, 0xDD, 0x40, 0xC8, 0x28, + 0xEA, 0x41, 0xC0, 0xF4, 0xD5, 0x25, 0xEB, 0x05, 0x84, 0x24, 0x50, 0x00, 0x01, 0x90, 0x49, 0xFF, + 0xFE, 0x9B, 0x80, 0x06, 0x44, 0x52, 0xBF, 0x98, 0x44, 0x22, 0xDA, 0x54, 0x44, 0x42, 0xBF, 0x90, + 0x50, 0x10, 0x00, 0x08, 0x38, 0x32, 0x81, 0x01, 0xEA, 0xD3, 0xAC, 0xCA, 0x50, 0x10, 0x00, 0x0C, + 0x38, 0x32, 0x01, 0x01, 0xEA, 0xD3, 0x8C, 0x01, 0xAC, 0xCA, 0x5A, 0x08, 0x04, 0xF3, 0x84, 0x01, + 0xEB, 0x29, 0xEB, 0x51, 0x80, 0x41, 0xFA, 0x14, 0xEA, 0xEF, 0xFA, 0x04, 0xEA, 0x83, 0xDD, 0x40, + 0x4E, 0x02, 0x00, 0x7B, 0xDD, 0x5F, 0x5A, 0x00, 0x08, 0x04, 0x48, 0x00, 0x00, 0x76, 0x84, 0x00, + 0x44, 0x52, 0xBF, 0xB0, 0x44, 0x62, 0xDA, 0x54, 0x44, 0x72, 0xBF, 0xA8, 0x81, 0x26, 0x81, 0x45, + 0x82, 0x67, 0x45, 0x22, 0xBF, 0x88, 0x45, 0x02, 0xBF, 0xB8, 0x82, 0x20, 0x50, 0x20, 0x00, 0x08, + 0x40, 0x23, 0x08, 0x20, 0x38, 0x12, 0x81, 0x01, 0xA5, 0x12, 0x94, 0xC1, 0xE2, 0x81, 0xE9, 0x03, + 0xA4, 0x52, 0x96, 0x49, 0x50, 0x40, 0x00, 0x0C, 0x40, 0x44, 0x90, 0x20, 0x38, 0x23, 0x8C, 0x01, + 0x02, 0xF2, 0x00, 0x02, 0x38, 0x15, 0x0C, 0x09, 0xE2, 0x4F, 0xE9, 0x03, 0xA4, 0xA2, 0x96, 0x91, + 0x8A, 0x22, 0x8C, 0x01, 0x38, 0x29, 0x8C, 0x09, 0x38, 0x19, 0x0C, 0x09, 0x39, 0x18, 0x0C, 0x09, + 0x5A, 0x08, 0x04, 0xDE, 0xEA, 0x8A, 0x5A, 0x08, 0x01, 0x09, 0x3C, 0x4D, 0xFC, 0xD9, 0x44, 0x00, + 0x00, 0x31, 0x40, 0x40, 0x10, 0x06, 0xD5, 0x07, 0x84, 0x80, 0xC8, 0x05, 0x2E, 0x47, 0xEF, 0x03, + 0x40, 0x40, 0x10, 0x06, 0x44, 0x73, 0x8D, 0x41, 0x44, 0x02, 0xBF, 0x88, 0xEB, 0xFC, 0xA6, 0xB8, + 0xEB, 0x31, 0x49, 0xFF, 0xFC, 0xBC, 0x2E, 0x07, 0xF2, 0xFE, 0x5A, 0x08, 0x01, 0x19, 0x2E, 0x97, + 0xEE, 0xF9, 0x5A, 0x98, 0x01, 0x15, 0x00, 0x2F, 0x80, 0x07, 0xA7, 0x78, 0xD2, 0x1B, 0x84, 0xC0, + 0x84, 0x03, 0xDD, 0x5A, 0x80, 0x67, 0x3E, 0x67, 0xF3, 0x73, 0xEB, 0x3E, 0x3E, 0x67, 0xEF, 0x11, + 0x3E, 0x67, 0xF2, 0xF3, 0x3E, 0x97, 0xF3, 0x73, 0xF8, 0x85, 0xD5, 0x0C, 0x3C, 0x03, 0xFB, 0x52, + 0xEB, 0x4F, 0xE9, 0x08, 0x84, 0x00, 0xEB, 0xC4, 0x84, 0x01, 0xEA, 0x49, 0x44, 0x00, 0x00, 0x42, + 0xDD, 0x4A, 0xFA, 0x04, 0xEA, 0x4D, 0xFC, 0xC1, 0xFC, 0x00, 0xDD, 0x40, 0xC0, 0x0B, 0xDD, 0x5F, + 0xC8, 0x09, 0x49, 0xFF, 0xFD, 0x9C, 0xDD, 0x40, 0x84, 0x21, 0xC0, 0x09, 0x3C, 0x1F, 0xFA, 0xC3, + 0xD5, 0x08, 0xDD, 0x40, 0xC8, 0x06, 0xEA, 0x41, 0xC0, 0xF5, 0xD5, 0x03, 0x3C, 0x1F, 0xFA, 0xC2, + 0xDD, 0x40, 0xC0, 0x15, 0xDD, 0x5F, 0xC0, 0x13, 0xDD, 0x5F, 0xE6, 0x06, 0xE8, 0x10, 0xDD, 0x5F, + 0xEB, 0xFC, 0x8E, 0x01, 0x96, 0x00, 0xF8, 0x17, 0xDD, 0x5F, 0xE6, 0x05, 0xE8, 0x05, 0xDD, 0x5F, + 0x8C, 0x01, 0xEA, 0x4D, 0xD5, 0x2C, 0x84, 0x07, 0xEA, 0x4D, 0xD5, 0x29, 0xDD, 0x40, 0xC8, 0x27, + 0xEA, 0x41, 0xC0, 0x25, 0xEA, 0x41, 0xE6, 0x06, 0xE8, 0x22, 0xEA, 0x41, 0x44, 0x12, 0xBF, 0xA0, + 0x8E, 0x01, 0x96, 0x00, 0x49, 0xFF, 0xF7, 0x04, 0xEA, 0x41, 0xE6, 0x05, 0xE8, 0x05, 0xEA, 0x41, + 0x8C, 0x01, 0xEA, 0x83, 0xD5, 0x14, 0xFA, 0x04, 0xEA, 0x83, 0x3C, 0x03, 0xF9, 0x94, 0x3C, 0x08, + 0x06, 0xF4, 0xDD, 0x54, 0xA6, 0x00, 0xEB, 0x29, 0x3E, 0x00, 0x0D, 0xDC, 0x84, 0xC1, 0xFA, 0x14, + 0x80, 0x41, 0x3E, 0x60, 0x0D, 0xDD, 0xEA, 0xEF, 0xDD, 0x4B, 0xAF, 0x80, 0xDD, 0x40, 0xC0, 0x28, + 0xDD, 0x5F, 0x5A, 0x08, 0x08, 0x26, 0x3C, 0x03, 0xF9, 0xA0, 0x3C, 0x10, 0x06, 0xF4, 0xE2, 0x20, + 0xE9, 0x04, 0x3C, 0x00, 0x06, 0xF4, 0x96, 0x01, 0xEB, 0x4F, 0x3C, 0x0B, 0xF9, 0xA0, 0xE8, 0x0D, + 0x84, 0xC0, 0x44, 0x00, 0x00, 0x40, 0x3C, 0x6F, 0xFC, 0xD3, 0xDD, 0x4A, 0x84, 0x01, 0x49, 0xFF, + 0xF8, 0xE5, 0x3E, 0x67, 0xEF, 0x11, 0xD5, 0x03, 0x84, 0x03, 0xEA, 0x49, 0x84, 0xC1, 0x3E, 0x67, + 0xF3, 0x73, 0x49, 0xFF, 0xF9, 0xDB, 0xFA, 0x04, 0xEA, 0x4D, 0xDD, 0x4B, 0xAF, 0x80, 0xFC, 0x80, + 0xFC, 0x00, 0x3C, 0x0D, 0xFC, 0x60, 0xC8, 0x07, 0xDD, 0x40, 0xC0, 0x2B, 0xDD, 0x5F, 0x5A, 0x08, + 0x08, 0x29, 0xD5, 0x13, 0x84, 0xC0, 0x3C, 0x6F, 0xFC, 0x60, 0xDD, 0x40, 0xC0, 0x07, 0xDD, 0x5F, + 0x5A, 0x08, 0x14, 0x05, 0x3C, 0x6F, 0xFA, 0xC3, 0xD5, 0x08, 0xDD, 0x40, 0xC8, 0x06, 0x3C, 0x1D, + 0xFA, 0xC2, 0x5A, 0x18, 0x14, 0x03, 0xEA, 0x83, 0xDD, 0x54, 0xA6, 0x00, 0xC8, 0x04, 0x49, 0xFF, + 0xFD, 0x91, 0xD5, 0x0F, 0x5A, 0x08, 0x02, 0x05, 0x49, 0xFF, 0xFD, 0xD2, 0xD5, 0x0A, 0x5A, 0x08, + 0x03, 0x05, 0x49, 0xFF, 0xFE, 0xA7, 0xD5, 0x05, 0x5A, 0x08, 0x01, 0x04, 0x49, 0xFF, 0xFF, 0x56, + 0xFC, 0x80, 0xFC, 0x00, 0xC8, 0x0C, 0xDD, 0x40, 0xEB, 0x95, 0xEA, 0xA3, 0xC0, 0x04, 0xEA, 0xF7, + 0xEA, 0x73, 0xD5, 0x24, 0x44, 0x03, 0x0E, 0x10, 0xEA, 0x73, 0xD5, 0x20, 0x49, 0xFF, 0xF5, 0xE5, + 0xDD, 0x40, 0x80, 0x20, 0xC0, 0x0C, 0xEA, 0xF7, 0x84, 0x20, 0xEB, 0x91, 0xEA, 0xF7, 0xEA, 0xA3, + 0xEB, 0x95, 0x49, 0xFF, 0xF7, 0x4D, 0x84, 0x07, 0xEA, 0x4D, 0xD5, 0x10, 0x44, 0x03, 0x0E, 0x10, + 0xEB, 0x91, 0x3C, 0x03, 0xF9, 0xA4, 0x3C, 0x08, 0x06, 0xEF, 0xEB, 0x29, 0x84, 0x01, 0xEB, 0x51, + 0x80, 0x41, 0xFA, 0x14, 0xEA, 0xEF, 0xFA, 0x04, 0xEA, 0x83, 0x84, 0x00, 0xEA, 0xD4, 0xFC, 0x80, + 0x2E, 0x17, 0xF3, 0x72, 0x5A, 0x18, 0x01, 0x05, 0x2E, 0x17, 0x34, 0x92, 0xD5, 0x03, 0x3C, 0x13, + 0x9A, 0x1D, 0x2E, 0x27, 0xEF, 0x11, 0xCA, 0x05, 0x2E, 0x27, 0x34, 0x94, 0x88, 0x22, 0x96, 0x49, + 0xAC, 0x40, 0x2E, 0x17, 0x34, 0x92, 0xAC, 0x44, 0xDD, 0x9E, 0xFC, 0x20, 0x2E, 0x67, 0xEF, 0x27, + 0x3C, 0x73, 0xF7, 0xC9, 0xA6, 0x01, 0x49, 0xFF, 0xDD, 0x99, 0x8E, 0xC1, 0xE2, 0xE0, 0x5C, 0x63, + 0x00, 0x01, 0xE9, 0x04, 0xEB, 0x5E, 0xC0, 0x02, 0x84, 0xC1, 0x80, 0x06, 0xFC, 0xA0, 0xFC, 0x00, + 0xDD, 0x41, 0xA6, 0x41, 0x5A, 0x10, 0x04, 0x05, 0x84, 0x24, 0xAE, 0x41, 0xEA, 0x3E, 0x84, 0x0A, + 0x44, 0x10, 0x00, 0xB5, 0xDD, 0x44, 0xEB, 0x5E, 0xC8, 0x05, 0xDD, 0x55, 0x8E, 0x04, 0xE6, 0x02, + 0xE8, 0x03, 0x49, 0xFF, 0xDF, 0x2F, 0x84, 0x0A, 0x44, 0x10, 0x00, 0xB6, 0xDD, 0x44, 0xDD, 0x40, + 0xC0, 0x18, 0xDD, 0x55, 0x8E, 0x04, 0xE6, 0x02, 0xE8, 0x0C, 0x44, 0x10, 0x00, 0x3F, 0x84, 0x01, + 0x3E, 0x07, 0xEC, 0xA0, 0x80, 0x41, 0x84, 0x08, 0x80, 0x61, 0x49, 0xFF, 0xE9, 0x86, 0xD5, 0x0B, + 0x84, 0x08, 0x44, 0x20, 0x00, 0x3F, 0x80, 0x20, 0x80, 0x62, 0x49, 0xFF, 0xE9, 0x7E, 0xD5, 0x03, + 0x49, 0xFF, 0xE9, 0x8C, 0xEA, 0x45, 0xEB, 0x10, 0xDD, 0x4B, 0x84, 0x21, 0xAE, 0x40, 0x84, 0x20, + 0x84, 0x02, 0x80, 0x41, 0x84, 0x61, 0x80, 0x81, 0x80, 0xA1, 0xDD, 0x56, 0xFC, 0x80, 0xFC, 0x41, + 0x81, 0x20, 0xEA, 0x34, 0xEA, 0x97, 0x84, 0x06, 0x3C, 0x7D, 0xFC, 0x03, 0x10, 0x04, 0x80, 0x01, + 0x84, 0xC1, 0xDD, 0x41, 0x3C, 0x6F, 0xFC, 0x03, 0xEA, 0x3E, 0xDD, 0x54, 0xA6, 0x00, 0x84, 0x26, + 0x49, 0xFF, 0xF2, 0xAA, 0x84, 0x00, 0xEA, 0x6C, 0xDD, 0x58, 0x97, 0xF8, 0xEB, 0x4C, 0x3E, 0x67, + 0xEF, 0x55, 0xAF, 0x80, 0xDD, 0x4B, 0xAF, 0x80, 0x2E, 0x67, 0xEE, 0xD1, 0x97, 0xB0, 0x5A, 0x68, + 0x01, 0x10, 0x80, 0x26, 0xDD, 0x41, 0xDD, 0x53, 0x80, 0x09, 0x49, 0xFF, 0xDD, 0x07, 0xF0, 0x81, + 0x84, 0x40, 0x84, 0x02, 0xF1, 0x01, 0x80, 0x66, 0x80, 0x82, 0x80, 0xA2, 0xDD, 0x56, 0xFC, 0xC1, + 0xFC, 0x20, 0x80, 0xC0, 0xDD, 0x47, 0xDD, 0x45, 0xAE, 0x40, 0x44, 0x72, 0xFE, 0xF2, 0x2E, 0x07, + 0xF2, 0xC5, 0xC8, 0x19, 0x84, 0x04, 0x44, 0x10, 0x00, 0xF3, 0xDD, 0x44, 0xEB, 0x6F, 0x84, 0x01, + 0xEB, 0xF3, 0x5A, 0x08, 0x01, 0x03, 0xF8, 0x32, 0xA6, 0xB8, 0x96, 0x90, 0xC2, 0x05, 0xDD, 0x41, + 0x49, 0xFF, 0x87, 0x5D, 0xD5, 0xED, 0x84, 0x01, 0x80, 0x20, 0x80, 0x62, 0x80, 0x80, 0x80, 0xA2, + 0xDD, 0x56, 0xD5, 0xE6, 0x84, 0x01, 0xEA, 0x65, 0x84, 0x0A, 0xDD, 0x4F, 0x2E, 0x07, 0xF2, 0xC5, + 0xDD, 0x4F, 0xEA, 0x38, 0x5A, 0x08, 0x01, 0x08, 0xEA, 0xDD, 0x5A, 0x08, 0x01, 0x05, 0xEB, 0x21, + 0xC0, 0x02, 0xEA, 0x75, 0x2E, 0x27, 0xF2, 0xC5, 0x5A, 0x28, 0x03, 0x13, 0xEA, 0x38, 0x5A, 0x08, + 0x01, 0x06, 0xEA, 0xDD, 0x5A, 0x08, 0x01, 0x03, 0xEA, 0x75, 0x84, 0x01, 0xEA, 0x2A, 0x49, 0xFF, + 0xDD, 0x4D, 0x84, 0x00, 0xEA, 0x65, 0x84, 0x00, 0xEA, 0xB6, 0x48, 0x00, 0x00, 0x6B, 0x5A, 0x28, + 0x04, 0x09, 0xDD, 0x41, 0x84, 0x21, 0xDD, 0x53, 0xEB, 0x41, 0x84, 0x00, 0xEA, 0xB6, 0xD5, 0x61, + 0x5A, 0x28, 0x06, 0x0D, 0x80, 0x06, 0x49, 0xFF, 0xFF, 0x7C, 0x84, 0x01, 0x3E, 0x07, 0xF2, 0xBF, + 0x84, 0x00, 0xEA, 0x65, 0x84, 0x00, 0xEA, 0xB6, 0xD5, 0x54, 0x5A, 0x28, 0x0A, 0x12, 0xA6, 0x31, + 0x84, 0xC1, 0x5A, 0x08, 0x0A, 0x06, 0x84, 0x00, 0xEB, 0x54, 0xEA, 0xB6, 0xD5, 0x4A, 0xEA, 0xC6, + 0xDD, 0x4B, 0x3E, 0x67, 0xEA, 0xFC, 0xAF, 0x80, 0x84, 0x00, 0xEA, 0xB6, 0xD5, 0x42, 0x5A, 0x28, + 0x09, 0x2C, 0xA6, 0x31, 0x84, 0xE0, 0x5A, 0x08, 0x0A, 0x09, 0x84, 0x02, 0x3E, 0x77, 0xF3, 0x70, + 0x3E, 0x77, 0xF2, 0xC5, 0xAE, 0x30, 0xD5, 0x35, 0x5A, 0x08, 0x0B, 0x14, 0xAE, 0xB1, 0xDD, 0x41, + 0x3E, 0x77, 0xF2, 0xC5, 0xEA, 0x3E, 0xDD, 0x41, 0x84, 0x21, 0xDD, 0x53, 0x84, 0x00, 0xEA, 0x33, + 0x3E, 0x77, 0xF3, 0x70, 0x49, 0xFF, 0xA4, 0xDB, 0x84, 0x01, 0x3E, 0x07, 0xF2, 0xD9, 0xD5, 0x21, + 0x84, 0x05, 0xDD, 0x4F, 0xEA, 0x45, 0xEB, 0x10, 0x84, 0x06, 0xDD, 0x4F, 0x3E, 0x77, 0xF2, 0xC5, + 0x84, 0x02, 0x84, 0x20, 0xD5, 0x11, 0x5A, 0x28, 0x0B, 0x15, 0x84, 0x20, 0x3C, 0x1F, 0xFC, 0xD8, + 0xAE, 0xB1, 0x3C, 0x2D, 0xFC, 0x25, 0x84, 0x01, 0xEA, 0xAA, 0x3C, 0x1B, 0xF7, 0xC9, 0x3E, 0x17, + 0xF2, 0xC5, 0xAE, 0x10, 0x84, 0x02, 0x80, 0x41, 0x84, 0x61, 0x80, 0x81, 0x80, 0xA1, 0xDD, 0x56, + 0xFC, 0xA0, 0xFC, 0x61, 0x80, 0xC0, 0xA6, 0x01, 0xB6, 0x5F, 0xF3, 0x81, 0x5A, 0x08, 0x04, 0x08, + 0xA6, 0x30, 0x5A, 0x08, 0x01, 0x05, 0x84, 0x00, 0x49, 0xFF, 0xDC, 0x29, 0x2E, 0x07, 0xEF, 0x4E, + 0x5A, 0x08, 0x01, 0x08, 0x44, 0x02, 0xBB, 0xC6, 0xB4, 0x3F, 0xF2, 0x01, 0x49, 0xFF, 0x86, 0xE9, + 0x84, 0x00, 0x3E, 0x07, 0xF2, 0xF2, 0xEA, 0x34, 0xEB, 0x1E, 0xDD, 0x40, 0xC8, 0x05, 0xEA, 0x29, + 0xEA, 0x50, 0xEA, 0x48, 0xD5, 0x52, 0x84, 0xE0, 0x44, 0xB2, 0xFE, 0x50, 0x44, 0xC2, 0xBD, 0xB8, + 0x44, 0xDD, 0x01, 0xB0, 0x44, 0xA2, 0xFE, 0x56, 0x3B, 0x05, 0xC0, 0x00, 0x3B, 0x06, 0x40, 0x20, + 0x44, 0x02, 0xFE, 0x54, 0xA6, 0x40, 0x3E, 0x17, 0xF1, 0x44, 0xA6, 0x01, 0x3E, 0x07, 0xF1, 0x45, + 0xEA, 0x7F, 0x84, 0x02, 0x44, 0x22, 0xBD, 0xB8, 0x84, 0x66, 0xDD, 0x42, 0x44, 0x52, 0xFE, 0x50, + 0x44, 0x12, 0xBD, 0xB8, 0x80, 0x05, 0x38, 0x20, 0x34, 0x04, 0x38, 0x00, 0x80, 0x00, 0x4C, 0x01, + 0x00, 0x0C, 0x9C, 0x39, 0xE6, 0xE5, 0xEB, 0x2D, 0xE8, 0x06, 0x44, 0x00, 0x00, 0x89, 0xDD, 0x4A, + 0x80, 0xE9, 0xD5, 0xDB, 0x80, 0xE9, 0x8C, 0xA1, 0x4C, 0x55, 0x7F, 0xEE, 0xEA, 0x6E, 0xC0, 0x0E, + 0x44, 0x13, 0x8D, 0x30, 0xEA, 0x34, 0xAE, 0x08, 0x44, 0x2F, 0xFF, 0xBB, 0x44, 0x03, 0x8D, 0x31, + 0xAE, 0x80, 0x84, 0x02, 0x80, 0x41, 0x80, 0x60, 0xDD, 0x42, 0xEA, 0x29, 0xFA, 0x12, 0xAE, 0x08, + 0x80, 0x41, 0x84, 0x02, 0x84, 0x61, 0xDD, 0x42, 0x2E, 0x07, 0xF1, 0x40, 0x5A, 0x08, 0x13, 0x24, + 0x44, 0x00, 0x00, 0x85, 0xDD, 0x4A, 0xD5, 0x1F, 0xA6, 0x08, 0x5A, 0x00, 0x22, 0x04, 0xAE, 0xD0, + 0xD5, 0xFC, 0xDD, 0x43, 0x5A, 0x00, 0x02, 0x11, 0x44, 0x23, 0x8D, 0x30, 0xA6, 0x10, 0x5A, 0x08, + 0xAA, 0x0C, 0x44, 0x03, 0x8D, 0x31, 0xA6, 0x40, 0x5A, 0x18, 0xBB, 0x07, 0x84, 0x20, 0xAE, 0x50, + 0xAE, 0x40, 0x84, 0x01, 0xEB, 0x6D, 0x44, 0x00, 0x00, 0x94, 0xDD, 0x4A, 0xEA, 0xE6, 0xA6, 0x00, + 0x5A, 0x00, 0x13, 0xE0, 0xDD, 0x5A, 0x44, 0x22, 0xBB, 0x5D, 0xB4, 0x7F, 0xF4, 0x01, 0xEB, 0x8B, + 0x49, 0xFF, 0x8B, 0x38, 0x96, 0x00, 0xEA, 0xC0, 0x49, 0xFF, 0x86, 0xAB, 0xDD, 0x55, 0x5A, 0x00, + 0x01, 0x09, 0x84, 0xE1, 0x3C, 0x7F, 0xFC, 0x58, 0xDD, 0x40, 0xC8, 0x03, 0x3C, 0x7F, 0xFC, 0x6F, + 0xA6, 0x31, 0x5A, 0x08, 0x08, 0x12, 0xA6, 0x30, 0x5A, 0x08, 0x02, 0x41, 0xEA, 0x46, 0x5A, 0x00, + 0x06, 0x3C, 0x5A, 0x00, 0x09, 0x06, 0xEA, 0x46, 0x5A, 0x08, 0x11, 0x30, 0xD5, 0x14, 0xDD, 0x43, + 0x5A, 0x08, 0x02, 0xFB, 0xD5, 0x31, 0x54, 0x10, 0x00, 0xFD, 0x5A, 0x18, 0x09, 0x10, 0xA6, 0x70, + 0x5A, 0x18, 0x02, 0x0D, 0x84, 0x01, 0xEA, 0x6F, 0xEA, 0x46, 0x9E, 0x46, 0xE6, 0x22, 0xE9, 0x24, + 0x5A, 0x08, 0x11, 0x1C, 0xDD, 0x40, 0xC0, 0x20, 0xD5, 0x18, 0x5A, 0x08, 0x0A, 0x07, 0xA6, 0x30, + 0x8E, 0x02, 0xE6, 0x02, 0xE8, 0x1B, 0xD5, 0x18, 0x9E, 0x43, 0xE6, 0x22, 0xE8, 0x0B, 0xA7, 0xB0, + 0x5A, 0x68, 0x01, 0x15, 0x80, 0x06, 0x49, 0xFF, 0xE9, 0xE5, 0x80, 0x06, 0xEA, 0x6F, 0x84, 0x08, + 0xD5, 0x0E, 0x5A, 0x00, 0x06, 0xF6, 0xD5, 0x0A, 0x84, 0x40, 0x84, 0x61, 0x84, 0x02, 0xFA, 0x25, + 0x80, 0x83, 0x80, 0xA2, 0xDD, 0x56, 0x84, 0x08, 0xD5, 0x02, 0x84, 0x01, 0xFC, 0xE1, 0xFC, 0x00, + 0x84, 0x00, 0x3C, 0x0F, 0xFC, 0x79, 0xDD, 0x47, 0xDD, 0x45, 0xAE, 0x40, 0x3C, 0x2D, 0xFC, 0x79, + 0xCA, 0x08, 0x84, 0x01, 0x80, 0x20, 0x80, 0x62, 0x80, 0x80, 0x80, 0xA2, 0xDD, 0x56, 0xD5, 0xF7, + 0xFC, 0x80, 0xFC, 0x00, 0xDD, 0x58, 0x84, 0xC0, 0xAF, 0x80, 0xDD, 0x4B, 0xAF, 0x80, 0x84, 0x01, + 0xEA, 0x30, 0xDD, 0x40, 0xC0, 0x03, 0xEA, 0x56, 0xAF, 0x80, 0x84, 0x08, 0xEB, 0x9C, 0x2E, 0x07, + 0xF2, 0xBD, 0xEB, 0x68, 0xDD, 0x47, 0xDD, 0x45, 0xAE, 0x40, 0xEA, 0x7B, 0xA6, 0x08, 0x5A, 0x00, + 0x01, 0xFF, 0xDD, 0x40, 0xC0, 0x0A, 0xEA, 0x29, 0xA6, 0x08, 0x5A, 0x08, 0x32, 0xFF, 0x84, 0x06, + 0xEA, 0x60, 0x84, 0x01, 0xDD, 0x4F, 0xD5, 0x0C, 0x49, 0xFF, 0x82, 0xDB, 0xEA, 0x29, 0xEB, 0x07, + 0xAE, 0x08, 0x80, 0x41, 0x84, 0x02, 0x84, 0x61, 0xDD, 0x42, 0x84, 0x02, 0xDD, 0x4F, 0xFC, 0x80, + 0xFC, 0x61, 0x80, 0xC0, 0x81, 0x61, 0x84, 0x06, 0xA6, 0x71, 0x80, 0xE2, 0x85, 0x20, 0xDD, 0x44, + 0x85, 0x49, 0x44, 0xC3, 0xF0, 0x4A, 0x44, 0x80, 0x00, 0x55, 0xA6, 0x31, 0x3E, 0x97, 0xF2, 0xD9, + 0x8E, 0x03, 0xE6, 0x09, 0x4E, 0xF2, 0x03, 0x35, 0x44, 0xF1, 0x29, 0x34, 0xEA, 0xA1, 0x40, 0xF0, + 0x3C, 0x00, 0xDD, 0x0F, 0x12, 0x00, 0x84, 0x01, 0x5A, 0x06, 0x96, 0x02, 0x5A, 0x06, 0xBE, 0x03, + 0x26, 0x04, 0x10, 0x05, 0x78, 0x05, 0xDD, 0x40, 0xDD, 0x54, 0xA6, 0x00, 0xC0, 0x03, 0x5A, 0x08, + 0x03, 0x65, 0x2E, 0x07, 0x34, 0x0A, 0xC8, 0x09, 0xDD, 0x47, 0xDD, 0x45, 0xAE, 0x40, 0x84, 0x09, + 0x44, 0x10, 0x00, 0x91, 0xDD, 0x44, 0xD5, 0x20, 0x5A, 0x08, 0x01, 0x58, 0x04, 0x93, 0x80, 0x03, + 0xF8, 0x62, 0xE3, 0x20, 0xE9, 0xF2, 0xD5, 0x51, 0xDD, 0x58, 0xA6, 0x00, 0xC8, 0x2E, 0xDD, 0x4B, + 0xA6, 0x00, 0x5A, 0x08, 0x01, 0x2B, 0x2E, 0x07, 0xEE, 0xE4, 0xC0, 0x24, 0xDD, 0x52, 0x5A, 0x08, + 0x02, 0x22, 0xEA, 0xDA, 0xE6, 0x13, 0xE9, 0x0B, 0x3C, 0x0D, 0xFC, 0x60, 0x5A, 0x00, 0x01, 0x20, + 0xDD, 0x5F, 0x5A, 0x00, 0x08, 0x1D, 0xDD, 0x40, 0xC8, 0xE8, 0xD5, 0x17, 0x2E, 0x07, 0xEF, 0x23, + 0xE6, 0x02, 0xE8, 0xF3, 0xEA, 0x81, 0x5A, 0x08, 0x01, 0x06, 0x44, 0x02, 0xBC, 0x26, 0x49, 0xFF, + 0x9B, 0x7F, 0x84, 0x40, 0x84, 0x01, 0x84, 0x2A, 0x80, 0x62, 0x80, 0x80, 0x80, 0xA2, 0xDD, 0x56, + 0xD5, 0xE4, 0xDD, 0x52, 0x5A, 0x00, 0x01, 0xDF, 0xDD, 0x40, 0xC0, 0x06, 0x84, 0x09, 0x44, 0x10, + 0x00, 0x92, 0xDD, 0x44, 0xD5, 0x1A, 0xDD, 0x58, 0xA6, 0x00, 0xC8, 0xF9, 0xEB, 0x4E, 0x5A, 0x00, + 0x01, 0xF7, 0x2E, 0x07, 0xEF, 0x05, 0x5A, 0x08, 0x01, 0xF3, 0x2E, 0x07, 0xEF, 0x7C, 0xC8, 0xEF, + 0xEB, 0x58, 0x5A, 0x00, 0x01, 0xED, 0x2E, 0x07, 0xEF, 0x54, 0x5A, 0x00, 0x01, 0xE9, 0x2E, 0x07, + 0xEF, 0x37, 0x5A, 0x08, 0x01, 0xC0, 0xD5, 0xE3, 0x2E, 0x07, 0x34, 0x0A, 0x5A, 0x00, 0x01, 0x03, + 0xDD, 0x5E, 0xDD, 0x40, 0xC0, 0x22, 0x44, 0x03, 0x8D, 0x42, 0xA6, 0x00, 0xC0, 0x03, 0x84, 0x00, + 0xEA, 0x33, 0xA1, 0xFB, 0x49, 0xFF, 0xDA, 0xAB, 0xE2, 0xE0, 0xE8, 0x05, 0xEA, 0x38, 0x5A, 0x08, + 0x01, 0x07, 0xD5, 0x19, 0x49, 0x00, 0x0E, 0x99, 0xC8, 0xFA, 0xD5, 0x15, 0xEA, 0xF6, 0x5A, 0x00, + 0x01, 0x13, 0xEA, 0x88, 0xC8, 0x05, 0xDD, 0x55, 0x8E, 0x04, 0xE6, 0x02, 0xE9, 0x0C, 0x2E, 0x07, + 0xEF, 0x27, 0x5A, 0x00, 0x01, 0x09, 0xDD, 0x5E, 0x2E, 0x17, 0xF2, 0xC5, 0x5A, 0x10, 0x04, 0x03, + 0xDD, 0x5E, 0xEA, 0xB6, 0xDD, 0x47, 0xDD, 0x45, 0xAE, 0x40, 0xDD, 0x51, 0xA6, 0x08, 0xC0, 0xFF, + 0xDD, 0x40, 0xC8, 0x11, 0x84, 0x04, 0xAE, 0x31, 0xDD, 0x41, 0x84, 0xC0, 0x3E, 0x67, 0xF2, 0xC6, + 0xEA, 0x3E, 0x49, 0xFF, 0xDC, 0x0C, 0x3E, 0x67, 0xEF, 0x06, 0xDD, 0x40, 0xC0, 0x07, 0x84, 0x04, + 0xEA, 0x26, 0xD5, 0x06, 0xEB, 0x6A, 0xC0, 0xFF, 0xD5, 0xEE, 0x84, 0x01, 0xEA, 0x65, 0x84, 0x02, + 0x3E, 0x07, 0xEE, 0xE8, 0xEB, 0x41, 0xDD, 0x5E, 0x84, 0x0B, 0x44, 0x10, 0x00, 0xBA, 0xDD, 0x44, + 0x84, 0xE1, 0xDD, 0x41, 0x3E, 0x77, 0xF2, 0xC6, 0xEA, 0x3E, 0xDD, 0x40, 0xC8, 0x1F, 0x84, 0x0B, + 0x44, 0x10, 0x00, 0xBB, 0xDD, 0x44, 0x80, 0x06, 0xEA, 0x8B, 0xF9, 0x6C, 0x84, 0x05, 0xDD, 0x4F, + 0xEA, 0xF6, 0x5A, 0x00, 0x01, 0x05, 0xEA, 0x38, 0x5A, 0x08, 0x01, 0x09, 0x84, 0x08, 0x44, 0x10, + 0x00, 0xD2, 0xDD, 0x44, 0x84, 0x01, 0x3E, 0x07, 0xEE, 0xE0, 0x84, 0x04, 0x44, 0x10, 0x00, 0xF1, + 0xDD, 0x44, 0xEB, 0x6F, 0x80, 0x06, 0xEB, 0xFE, 0xDD, 0x5E, 0x84, 0x0B, 0x44, 0x10, 0x00, 0xBC, + 0xDD, 0x44, 0xEA, 0x32, 0xC8, 0x39, 0x84, 0x01, 0xDD, 0x4F, 0xDD, 0x55, 0x9E, 0x44, 0xE6, 0x24, + 0xE9, 0x0E, 0x5A, 0x00, 0x0C, 0x0D, 0xEA, 0x32, 0x5A, 0x00, 0x04, 0x0A, 0xEA, 0x38, 0x5A, 0x00, + 0x01, 0x07, 0xEA, 0xF6, 0x5A, 0x00, 0x01, 0x04, 0x80, 0x06, 0xEB, 0xF2, 0x49, 0xFF, 0xDA, 0x8C, + 0xEB, 0x83, 0x4C, 0x00, 0xC0, 0x06, 0xEA, 0x24, 0xEB, 0xBE, 0xEB, 0x85, 0xF9, 0x1B, 0xEA, 0x34, + 0xEA, 0x97, 0xDD, 0x55, 0x8E, 0x04, 0xE6, 0x02, 0xE8, 0x09, 0xEA, 0x61, 0xEA, 0x28, 0xEA, 0x36, + 0x84, 0x00, 0xEA, 0x42, 0x84, 0x00, 0xEA, 0x6C, 0xEA, 0x85, 0xEA, 0x32, 0x5A, 0x00, 0x04, 0x11, + 0x44, 0x10, 0x00, 0xD2, 0x84, 0x06, 0xDD, 0x44, 0x84, 0x04, 0xEA, 0x26, 0xDD, 0x41, 0x84, 0x21, + 0xDD, 0x53, 0xEB, 0x41, 0xD5, 0x05, 0x5A, 0x08, 0x04, 0x04, 0x3E, 0x77, 0xEF, 0x51, 0x84, 0x00, + 0xEA, 0xAA, 0xEA, 0x8B, 0x80, 0x06, 0xF9, 0x0E, 0xEA, 0xDD, 0x5A, 0x08, 0x01, 0x03, 0xDD, 0x5E, + 0x84, 0x01, 0xEA, 0x2A, 0xEA, 0xAC, 0x5A, 0x08, 0x01, 0x03, 0xF8, 0x04, 0xEA, 0x32, 0x5A, 0x08, + 0x04, 0x04, 0x48, 0x00, 0x01, 0xC6, 0x2E, 0x07, 0xEF, 0x06, 0x5A, 0x00, 0x01, 0x03, 0xF8, 0x04, + 0xEB, 0x5E, 0x4E, 0x03, 0x01, 0xBE, 0x48, 0x00, 0x01, 0xC3, 0x2E, 0x77, 0xEF, 0x55, 0x5A, 0x78, + 0x01, 0x15, 0x49, 0xFF, 0xDA, 0x8E, 0x84, 0x02, 0xDD, 0x50, 0xEA, 0xAA, 0x84, 0x00, 0xAE, 0x08, + 0xEA, 0x2A, 0x84, 0x05, 0xDD, 0x4F, 0xDD, 0x40, 0xC0, 0x05, 0xEA, 0x67, 0x5A, 0x08, 0x06, 0xFF, + 0xDD, 0x5E, 0x3E, 0x77, 0xEF, 0x18, 0xDD, 0x5E, 0x5A, 0x70, 0x02, 0x03, 0xDD, 0x5E, 0xDD, 0x40, + 0xC0, 0x33, 0xEA, 0x24, 0xEB, 0xBE, 0xEB, 0x85, 0xDD, 0x41, 0x44, 0x12, 0xD9, 0xD0, 0x49, 0xFF, + 0xDC, 0x03, 0xEA, 0xAC, 0xC8, 0x06, 0xDD, 0x41, 0xA6, 0x01, 0xEA, 0xC2, 0x49, 0xFF, 0xD8, 0xF8, + 0x84, 0x06, 0xDD, 0x4F, 0xDD, 0x45, 0xDD, 0x47, 0xAE, 0x40, 0x80, 0xC0, 0xEB, 0x6A, 0xC0, 0xFF, + 0xEA, 0x40, 0xAE, 0x30, 0xEB, 0xCE, 0xC0, 0xFF, 0x84, 0x00, 0xEA, 0x5F, 0xDD, 0x52, 0x5A, 0x08, + 0x02, 0x05, 0x84, 0x01, 0x3E, 0x07, 0xEF, 0x06, 0x84, 0x01, 0x2E, 0x67, 0xEF, 0x27, 0xEA, 0x2D, + 0x84, 0x00, 0x3E, 0x07, 0xF2, 0xBF, 0x5A, 0x68, 0x01, 0x3C, 0xDD, 0x41, 0x84, 0x20, 0xDD, 0x53, + 0x3E, 0x67, 0xEF, 0x55, 0xDD, 0x5E, 0x2E, 0x97, 0xEF, 0x18, 0x5A, 0x98, 0x01, 0x25, 0x49, 0xFF, + 0xBB, 0x52, 0x3C, 0x0E, 0x03, 0xD3, 0x5A, 0x08, 0x03, 0x04, 0xEB, 0x4C, 0xD5, 0x03, 0x3C, 0x9F, + 0xFC, 0x03, 0xDD, 0x47, 0xDD, 0x45, 0xAE, 0x40, 0x44, 0x93, 0xF7, 0xF1, 0xEA, 0x43, 0x80, 0xE0, + 0x5A, 0x08, 0x01, 0xFE, 0xEA, 0x74, 0x96, 0x04, 0xC8, 0xFA, 0xEB, 0x59, 0x44, 0x12, 0xBC, 0x84, + 0x80, 0x41, 0x80, 0x67, 0x84, 0x02, 0xDD, 0x42, 0x84, 0x02, 0xEB, 0x01, 0x80, 0x41, 0x80, 0x60, + 0xDD, 0x42, 0xEB, 0x4C, 0x84, 0xE0, 0x3E, 0x77, 0xEF, 0x18, 0x44, 0x02, 0xFE, 0xF2, 0xA6, 0x00, + 0x4E, 0x02, 0x01, 0x67, 0x80, 0x06, 0xEB, 0xFE, 0x3E, 0x77, 0xF2, 0xBF, 0xDD, 0x5E, 0xEB, 0xB8, + 0x4E, 0x03, 0x01, 0x39, 0xEA, 0xAC, 0x4E, 0x03, 0x01, 0x36, 0x2E, 0x07, 0xEF, 0x06, 0x4E, 0x03, + 0x01, 0x32, 0x44, 0x10, 0x00, 0xD4, 0x84, 0x06, 0xDD, 0x44, 0x84, 0x04, 0xEA, 0x26, 0xEB, 0x41, + 0xDD, 0x5E, 0xEA, 0x46, 0x5A, 0x08, 0x06, 0x10, 0x84, 0x00, 0xEA, 0x66, 0xEA, 0xAA, 0xEB, 0xBE, + 0xEA, 0x24, 0xEB, 0x85, 0xDD, 0x43, 0xC0, 0x0C, 0xEA, 0xA2, 0x02, 0x00, 0x00, 0x10, 0x49, 0xFF, + 0x81, 0x64, 0xD5, 0x06, 0x5A, 0x08, 0x11, 0x15, 0xDD, 0x40, 0xC0, 0xEF, 0xD5, 0x11, 0x84, 0x00, + 0xEA, 0x5F, 0xEB, 0x64, 0x49, 0xFF, 0xEA, 0x46, 0x84, 0x03, 0xDD, 0x4A, 0xEA, 0xC6, 0xDD, 0x50, + 0x84, 0x01, 0xEA, 0x2A, 0xEA, 0x78, 0xAE, 0x08, 0x84, 0x0F, 0xDD, 0x4F, 0xDD, 0x5E, 0xEA, 0x46, + 0x5A, 0x00, 0x09, 0x03, 0xDD, 0x5E, 0xDD, 0x43, 0x5A, 0x00, 0x02, 0x03, 0xDD, 0x5E, 0xDD, 0x41, + 0x84, 0x20, 0xDD, 0x53, 0x84, 0x03, 0xAE, 0x31, 0xDD, 0x5E, 0x84, 0x01, 0xDD, 0x4F, 0xDD, 0x40, + 0xC8, 0x09, 0x80, 0x06, 0xEA, 0x8B, 0xF8, 0x26, 0x84, 0x05, 0xDD, 0x4F, 0x80, 0x06, 0xEB, 0xFE, + 0xDD, 0x5E, 0xEA, 0x32, 0xC8, 0x17, 0x84, 0x02, 0xDD, 0x4F, 0x49, 0xFF, 0xA1, 0x35, 0x80, 0x06, + 0xEB, 0xF2, 0x49, 0xFF, 0xD8, 0x82, 0xDD, 0x4B, 0x84, 0x21, 0xAE, 0x40, 0xEA, 0x32, 0x5A, 0x00, + 0x04, 0x0E, 0x84, 0x09, 0xEA, 0x26, 0x84, 0x03, 0xDD, 0x4F, 0xDD, 0x40, 0xC0, 0x07, 0xF8, 0x3E, + 0xD5, 0x05, 0x5A, 0x08, 0x04, 0x04, 0x84, 0x01, 0xEA, 0x66, 0x84, 0x04, 0xDD, 0x4F, 0x80, 0x06, + 0xEA, 0x8B, 0x49, 0xFF, 0xDB, 0xC4, 0xEA, 0xDD, 0x5A, 0x08, 0x01, 0x03, 0xDD, 0x5E, 0xEA, 0xAC, + 0x85, 0x21, 0x3E, 0x97, 0xEF, 0x65, 0x5A, 0x00, 0x01, 0x08, 0xEB, 0x34, 0x5A, 0x00, 0x01, 0x05, + 0xEA, 0x32, 0x5A, 0x08, 0x04, 0x0A, 0x84, 0x0A, 0xEA, 0x26, 0xEA, 0xC6, 0xDD, 0x50, 0x84, 0x01, + 0xEA, 0x78, 0xAE, 0x08, 0xDD, 0x5E, 0xA6, 0x31, 0xEA, 0xC2, 0x49, 0xFF, 0xD8, 0x11, 0x3C, 0xA3, + 0xF7, 0xC9, 0xA6, 0x31, 0x49, 0xFF, 0xD8, 0xC2, 0xE3, 0x40, 0xE9, 0x13, 0x84, 0x0B, 0xEA, 0x26, + 0x84, 0x00, 0x84, 0x2B, 0xA8, 0x3B, 0xAE, 0x71, 0xEA, 0x6C, 0xDD, 0x4B, 0x3E, 0x97, 0xEF, 0x55, + 0x10, 0x90, 0x00, 0x00, 0xDD, 0x40, 0x4E, 0x02, 0x00, 0xBC, 0x49, 0xFF, 0xA0, 0xE8, 0xDD, 0x5E, + 0x84, 0x09, 0xEA, 0x26, 0x84, 0x05, 0xDD, 0x4F, 0xEA, 0x45, 0xEB, 0x10, 0x84, 0x06, 0xDD, 0x4F, + 0xDD, 0x40, 0x80, 0x20, 0xC8, 0xF3, 0x84, 0x02, 0x80, 0x41, 0x84, 0x61, 0x80, 0x81, 0x80, 0xA1, + 0xDD, 0x56, 0xDD, 0x5E, 0xDD, 0x40, 0xC8, 0x02, 0xEA, 0x78, 0xA6, 0x30, 0x5A, 0x08, 0x02, 0x1F, + 0x10, 0x86, 0x00, 0x00, 0xDD, 0x51, 0xA6, 0x08, 0xC0, 0xFF, 0xA6, 0x31, 0xEA, 0xC2, 0xF0, 0x81, + 0x85, 0xA0, 0x44, 0x02, 0xBB, 0xC9, 0xF1, 0x01, 0x44, 0x22, 0xBC, 0x3E, 0x49, 0xFF, 0xD9, 0xF7, + 0x3C, 0xDB, 0xF7, 0xC9, 0x10, 0xA3, 0x00, 0x01, 0xDD, 0x41, 0xEA, 0x3E, 0x84, 0x00, 0x10, 0xD3, + 0x80, 0x1C, 0xA8, 0x3B, 0x3E, 0xD7, 0xEF, 0x55, 0xF8, 0x52, 0xEA, 0x46, 0x5A, 0x08, 0x07, 0x0C, + 0x84, 0x09, 0xAE, 0x31, 0xEA, 0xC6, 0xDD, 0x50, 0x84, 0x01, 0xEA, 0x78, 0xAE, 0x08, 0xFA, 0x08, + 0x3C, 0x0F, 0xFC, 0x2D, 0x84, 0x00, 0x10, 0x03, 0x80, 0x1C, 0xDD, 0x5E, 0x2E, 0x07, 0xEF, 0x55, + 0x5A, 0x08, 0x01, 0x19, 0xDD, 0x41, 0xEA, 0x3E, 0x49, 0xFF, 0xA0, 0xA6, 0xDD, 0x41, 0x84, 0x29, + 0xAE, 0x41, 0x84, 0x20, 0xDD, 0x53, 0xDD, 0x41, 0x84, 0x2B, 0xAE, 0x41, 0x49, 0xFF, 0xFC, 0xEB, + 0x84, 0x02, 0xDD, 0x50, 0xEA, 0xAA, 0x84, 0x00, 0xAE, 0x08, 0xEA, 0x2A, 0x84, 0x03, 0xDD, 0x4F, + 0xD5, 0x57, 0x5A, 0x08, 0x02, 0x56, 0x84, 0x04, 0xDD, 0x4F, 0x3E, 0x97, 0xEF, 0x55, 0xDD, 0x40, + 0xC8, 0x08, 0x80, 0x06, 0xEB, 0xFE, 0x2E, 0x07, 0xF2, 0xD9, 0x4E, 0x03, 0xFD, 0x10, 0xD5, 0x48, + 0xEB, 0xB8, 0xC8, 0x03, 0xEA, 0xAC, 0xC0, 0x04, 0x2E, 0x07, 0xEA, 0xFC, 0xC8, 0x12, 0x84, 0x09, + 0xEA, 0x26, 0x10, 0xA3, 0x00, 0x01, 0xDD, 0x41, 0xEA, 0x3E, 0xDD, 0x41, 0x84, 0x21, 0xDD, 0x53, + 0x84, 0x00, 0x10, 0x93, 0x80, 0x1C, 0xA8, 0x3B, 0x49, 0xFF, 0xA0, 0x71, 0x48, 0xFF, 0xFC, 0xF7, + 0x84, 0x0A, 0xEA, 0x26, 0xEA, 0xC6, 0xDD, 0x4B, 0x84, 0x21, 0xAE, 0x40, 0xD5, 0x29, 0x84, 0x02, + 0xDD, 0x4F, 0x84, 0x03, 0xEA, 0x26, 0x49, 0xFF, 0xD8, 0x89, 0xD5, 0x22, 0x84, 0x03, 0xDD, 0x4F, + 0xA6, 0x31, 0xEA, 0xC2, 0x49, 0xFF, 0xD7, 0x5C, 0xDD, 0x41, 0x49, 0xFF, 0xFA, 0x70, 0xC0, 0x0E, + 0x84, 0x04, 0xDD, 0x4F, 0x84, 0x01, 0x3E, 0x07, 0xF2, 0xBF, 0x84, 0x06, 0xEA, 0x26, 0x80, 0x06, + 0x49, 0xFF, 0xFA, 0xB7, 0x84, 0x05, 0xDD, 0x4F, 0xD5, 0x0B, 0x44, 0x10, 0x00, 0xD3, 0x84, 0x06, + 0xDD, 0x44, 0x84, 0x04, 0xEA, 0x26, 0xDD, 0x41, 0x84, 0x21, 0xDD, 0x53, 0xEB, 0x41, 0xFC, 0xE1, + 0xFC, 0x40, 0xC0, 0x02, 0xF9, 0x54, 0x44, 0x60, 0x00, 0x65, 0xEB, 0x02, 0xEB, 0x27, 0xDD, 0x43, + 0xC0, 0x0E, 0x8E, 0xC1, 0xC6, 0x0C, 0x84, 0x21, 0x80, 0x41, 0x80, 0x61, 0x84, 0x80, 0x44, 0x00, + 0x4F, 0x00, 0xEA, 0xA7, 0xEA, 0x3F, 0xEA, 0x39, 0xEB, 0x2F, 0xD5, 0xF2, 0x84, 0x00, 0xEB, 0xBF, + 0xFC, 0xC0, 0x44, 0x10, 0x00, 0x55, 0xDD, 0x45, 0xAE, 0x40, 0xEA, 0x7B, 0xA6, 0x08, 0x5A, 0x00, + 0x01, 0xFF, 0xDD, 0x9E, 0xFC, 0x60, 0x81, 0x20, 0x80, 0xE2, 0xEA, 0x68, 0x80, 0xC0, 0x49, 0xFF, + 0xFF, 0xF2, 0x50, 0x04, 0xFF, 0xFF, 0xE6, 0x0C, 0x4E, 0xF2, 0x01, 0xC3, 0x44, 0xF1, 0x2F, 0xF8, + 0xEA, 0xA1, 0x40, 0xF0, 0x3C, 0x00, 0xDD, 0x0F, 0xE0, 0x00, 0x18, 0x00, 0xE0, 0x00, 0xAE, 0x02, + 0x58, 0x00, 0x76, 0x03, 0x76, 0x03, 0x76, 0x03, 0x76, 0x03, 0xD0, 0x02, 0x04, 0x03, 0x58, 0x03, + 0x84, 0x04, 0xFA, 0x22, 0xDD, 0x44, 0x84, 0x0E, 0xAE, 0x39, 0x84, 0x06, 0xAE, 0x38, 0x84, 0x00, + 0xEA, 0x6A, 0x80, 0xA6, 0x50, 0x03, 0x00, 0x4F, 0x84, 0x3F, 0xEB, 0xE8, 0xD8, 0xFF, 0x80, 0x07, + 0x84, 0x21, 0xDD, 0x53, 0xDD, 0x43, 0x5A, 0x00, 0x02, 0x05, 0x84, 0x01, 0x3E, 0x07, 0xF2, 0xB1, + 0x84, 0x20, 0x84, 0x02, 0x80, 0x41, 0x84, 0x61, 0x80, 0x81, 0x80, 0xA1, 0xDD, 0x56, 0xF9, 0x2A, + 0xFA, 0x25, 0x84, 0x04, 0xDD, 0x44, 0x44, 0x00, 0x00, 0x31, 0xDD, 0x4A, 0x84, 0x00, 0x44, 0x13, + 0xF4, 0x29, 0xAE, 0x08, 0x84, 0x21, 0xEB, 0x73, 0xAE, 0x78, 0xEA, 0x6A, 0xA6, 0x79, 0xEA, 0xAE, + 0x84, 0x81, 0x2E, 0x27, 0xEE, 0xD1, 0x44, 0x52, 0xBD, 0x24, 0x2E, 0x37, 0xEE, 0xFD, 0x49, 0xFF, + 0xEA, 0xB5, 0xDD, 0x54, 0xA6, 0x00, 0xC8, 0x05, 0xEA, 0x58, 0xEB, 0x87, 0xEA, 0x77, 0xD5, 0x07, + 0x5A, 0x08, 0x03, 0x06, 0xEA, 0x58, 0x44, 0x12, 0xDA, 0x00, 0xEA, 0x77, 0x84, 0x00, 0x3E, 0x07, + 0xF3, 0x70, 0x2E, 0x17, 0xF3, 0x73, 0x84, 0x00, 0xEA, 0x33, 0x84, 0x01, 0x3E, 0x07, 0xEE, 0xD3, + 0x5A, 0x10, 0x01, 0x04, 0x3E, 0x07, 0xEE, 0xEC, 0x84, 0x00, 0xEA, 0x6F, 0xDD, 0x51, 0x84, 0x02, + 0xAE, 0x08, 0xDD, 0x50, 0xAE, 0x08, 0xA6, 0x39, 0x8E, 0x08, 0xE6, 0x04, 0x4E, 0xF2, 0x01, 0x53, + 0x80, 0x07, 0x49, 0xFF, 0x97, 0xD1, 0xF8, 0xE6, 0x84, 0x04, 0xFA, 0x23, 0xDD, 0x44, 0x5A, 0x98, + 0x01, 0x06, 0x44, 0x00, 0x00, 0x30, 0xDD, 0x4A, 0xD5, 0x0D, 0xDD, 0x43, 0xC8, 0x06, 0xEA, 0x6A, + 0x44, 0x00, 0x00, 0x36, 0xDD, 0x4A, 0xF8, 0xD6, 0xEB, 0x07, 0xDD, 0x4A, 0x84, 0x01, 0x3E, 0x07, + 0xF2, 0xF1, 0xDD, 0x50, 0x84, 0x02, 0xAE, 0x08, 0xAE, 0x38, 0xA6, 0x39, 0x9E, 0x43, 0xE6, 0x24, + 0xE9, 0x0C, 0x5A, 0x00, 0x0D, 0x0B, 0x5A, 0x00, 0x0E, 0x05, 0xEA, 0x6E, 0xC8, 0x06, 0xD5, 0x08, + 0xEB, 0xB3, 0x84, 0x00, 0x49, 0xFF, 0x98, 0x42, 0x84, 0x08, 0xAE, 0x39, 0xD5, 0x03, 0x84, 0x09, + 0xAE, 0x39, 0x85, 0x40, 0x10, 0xA3, 0x00, 0x50, 0x3E, 0xA7, 0xEE, 0xFA, 0x49, 0xFF, 0xEE, 0x8B, + 0xDD, 0x41, 0xEA, 0x3E, 0x44, 0xB0, 0x00, 0x55, 0x3E, 0xA7, 0xEF, 0x75, 0x44, 0xA3, 0xF0, 0x4A, + 0xDD, 0x43, 0x5A, 0x08, 0x02, 0x06, 0xEB, 0x6F, 0x10, 0xB5, 0x00, 0x00, 0xD5, 0xFA, 0x84, 0x01, + 0xEA, 0xC4, 0x44, 0x13, 0xF3, 0xD1, 0xA6, 0x08, 0xEA, 0x8F, 0xAE, 0x08, 0x44, 0x1F, 0xFF, 0xC3, + 0x44, 0x03, 0xF4, 0x29, 0xAE, 0x40, 0xDD, 0x43, 0xC0, 0x08, 0x84, 0x21, 0x44, 0x00, 0x5A, 0xF0, + 0x80, 0x41, 0x80, 0x61, 0x80, 0x81, 0xEA, 0xA7, 0xEA, 0x6E, 0xC0, 0x32, 0x44, 0x00, 0x00, 0x37, + 0xDD, 0x4A, 0x84, 0x02, 0x84, 0x20, 0x49, 0xFF, 0x79, 0x25, 0xDD, 0x40, 0xC8, 0x1D, 0x44, 0x00, + 0x00, 0x38, 0xDD, 0x4A, 0x44, 0x1F, 0xFF, 0xA5, 0x44, 0x03, 0xF4, 0x38, 0xAE, 0x40, 0x84, 0x20, + 0x44, 0x03, 0xF4, 0x39, 0xAE, 0x40, 0x84, 0x01, 0xEB, 0xE7, 0x44, 0x00, 0x00, 0x39, 0xDD, 0x4A, + 0x84, 0x41, 0x84, 0x28, 0x80, 0x62, 0x80, 0x82, 0x44, 0x00, 0x3A, 0xF0, 0xEA, 0xA7, 0x44, 0x00, + 0x00, 0x3A, 0xDD, 0x4A, 0xD5, 0x0D, 0x44, 0x1F, 0xFF, 0xE3, 0x44, 0x03, 0xF4, 0x3A, 0xAE, 0x40, + 0xDD, 0x5B, 0xEA, 0x21, 0xAE, 0x88, 0xA6, 0x40, 0x5A, 0x18, 0xFF, 0xFF, 0xD5, 0xD9, 0x84, 0x00, + 0x3E, 0x07, 0xF3, 0x70, 0x2E, 0x17, 0xF3, 0x73, 0x84, 0x00, 0xEA, 0x33, 0x84, 0x01, 0x3E, 0x07, + 0xEE, 0xD3, 0x5A, 0x10, 0x01, 0x04, 0x3E, 0x07, 0xEE, 0xEC, 0x84, 0x00, 0xEA, 0x6F, 0x84, 0x00, + 0x49, 0xFF, 0xE4, 0xEA, 0x80, 0x07, 0x84, 0x20, 0xDD, 0x53, 0x44, 0x00, 0x00, 0x33, 0xDD, 0x4A, + 0xEA, 0x46, 0x5A, 0x08, 0x04, 0x06, 0x44, 0x00, 0x01, 0xF4, 0xEA, 0x39, 0xD5, 0x0A, 0x5A, 0x00, + 0x07, 0xFC, 0xDD, 0x43, 0xC0, 0xF9, 0xEA, 0x6E, 0xC8, 0xF7, 0xEA, 0xEC, 0x49, 0xFF, 0xC7, 0xD3, + 0xDD, 0x43, 0xC0, 0x04, 0x84, 0x00, 0x49, 0xFF, 0x7E, 0xC8, 0xEB, 0xB3, 0x44, 0x00, 0x00, 0x34, + 0xDD, 0x4A, 0x5A, 0x98, 0x01, 0x12, 0x84, 0x0E, 0xAE, 0x39, 0x84, 0x05, 0xAE, 0x38, 0x80, 0x29, + 0x80, 0x07, 0xDD, 0x53, 0x84, 0x20, 0x84, 0x02, 0x80, 0x41, 0x80, 0x69, 0x80, 0x81, 0x80, 0xA1, + 0x3E, 0x97, 0xF2, 0xB1, 0xDD, 0x56, 0xEA, 0x6E, 0xC0, 0x04, 0x84, 0x00, 0xEA, 0x6A, 0xEB, 0x6D, + 0x84, 0x00, 0xEA, 0xC4, 0xDD, 0x40, 0x80, 0x20, 0x84, 0x8F, 0x84, 0x02, 0xC1, 0x07, 0x84, 0x40, + 0x80, 0x20, 0x80, 0x62, 0x80, 0xA2, 0xDD, 0x56, 0xF8, 0x05, 0x80, 0x41, 0x80, 0x61, 0x80, 0xA1, + 0xDD, 0x56, 0x48, 0x00, 0x00, 0x68, 0x84, 0x04, 0xFA, 0x24, 0xDD, 0x44, 0x84, 0x20, 0xDD, 0x41, + 0xDD, 0x53, 0x84, 0x0A, 0xAE, 0x39, 0x84, 0x03, 0xAE, 0x38, 0x84, 0x00, 0xEA, 0x6A, 0xDD, 0x41, + 0xEA, 0x3E, 0x84, 0x01, 0xEB, 0x7D, 0xD5, 0x56, 0x84, 0x04, 0xFA, 0x2A, 0xDD, 0x44, 0x84, 0x0E, + 0xAE, 0x39, 0x84, 0x06, 0xAE, 0x38, 0x80, 0xA6, 0x50, 0x03, 0x00, 0x4F, 0x84, 0x3F, 0xEB, 0xE8, + 0xD8, 0xFF, 0x80, 0x07, 0x84, 0x21, 0xDD, 0x53, 0x84, 0x20, 0x84, 0x00, 0x84, 0x61, 0xEA, 0x6A, + 0x80, 0x41, 0x84, 0x02, 0x80, 0x83, 0x80, 0xA1, 0xDD, 0x56, 0xD5, 0x3C, 0xFA, 0x2B, 0x84, 0x04, + 0xDD, 0x44, 0xDD, 0x43, 0xDD, 0x5A, 0x5A, 0x08, 0x02, 0x0D, 0xA6, 0x09, 0x5A, 0x00, 0x03, 0x13, + 0x80, 0x01, 0x84, 0x20, 0xDD, 0x53, 0x49, 0xFF, 0xD6, 0xA1, 0x84, 0x01, 0xEA, 0x2A, 0xD5, 0x0A, + 0xA6, 0x09, 0x5A, 0x00, 0x0A, 0x08, 0x80, 0x01, 0x84, 0x20, 0xDD, 0x53, 0xEA, 0xC6, 0x84, 0x01, + 0xEA, 0x2A, 0x00, 0x03, 0x00, 0x51, 0x00, 0x13, 0x00, 0x52, 0x44, 0x22, 0xBB, 0x81, 0x44, 0x32, + 0xBB, 0x3B, 0x44, 0x42, 0xBB, 0x9C, 0x49, 0xFF, 0xF4, 0xC7, 0x84, 0x00, 0xEA, 0x6A, 0xD5, 0x12, + 0x84, 0x04, 0xFA, 0x2C, 0xDD, 0x44, 0x00, 0x03, 0x00, 0x51, 0x5A, 0x00, 0x01, 0x05, 0x5A, 0x08, + 0x02, 0x05, 0x84, 0x00, 0x3E, 0x07, 0xEF, 0x27, 0x84, 0x00, 0xEA, 0x6A, 0xD5, 0x03, 0x84, 0x1B, + 0xEA, 0x6A, 0xFC, 0xE0, 0x3C, 0x0F, 0xFD, 0xAF, 0xDD, 0x9E, 0xFC, 0x40, 0x3C, 0x9D, 0xFD, 0xAF, + 0x51, 0x11, 0x80, 0x02, 0x45, 0x20, 0x00, 0x34, 0x80, 0x61, 0xFB, 0xF8, 0x44, 0xA0, 0x00, 0x32, + 0x9B, 0x19, 0xE2, 0x82, 0xE8, 0x3E, 0x08, 0x51, 0x80, 0x01, 0xA1, 0xC6, 0x04, 0x60, 0x00, 0x08, + 0x38, 0x73, 0x96, 0x02, 0x01, 0x04, 0x80, 0x32, 0x38, 0x63, 0x16, 0x02, 0x42, 0x78, 0x1C, 0x24, + 0xA1, 0x07, 0x40, 0x73, 0x98, 0xF7, 0x38, 0x42, 0x16, 0x02, 0x12, 0x78, 0xFF, 0xFF, 0xA1, 0xC5, + 0x40, 0x53, 0x94, 0x40, 0xA7, 0xEA, 0xA7, 0x6B, 0xE6, 0xF4, 0xE8, 0x08, 0xE6, 0xB4, 0xE8, 0x0D, + 0x42, 0x52, 0x28, 0x24, 0x40, 0x42, 0x98, 0x97, 0xD5, 0x19, 0xE6, 0xB4, 0xE9, 0x06, 0x42, 0x42, + 0x48, 0x24, 0x42, 0x43, 0x4C, 0x75, 0xD5, 0x10, 0x41, 0x02, 0x9C, 0x01, 0x52, 0x73, 0x80, 0x14, + 0x42, 0x73, 0xCC, 0x24, 0x42, 0x52, 0x48, 0x24, 0x40, 0x48, 0x04, 0x09, 0x42, 0x43, 0x98, 0x73, + 0x40, 0x42, 0x40, 0x97, 0x9B, 0x2C, 0x40, 0x42, 0x18, 0x97, 0x1A, 0x48, 0x80, 0x04, 0xD5, 0xC1, + 0xFC, 0xC0, 0xFC, 0x61, 0x81, 0xA1, 0x3C, 0x1D, 0xFC, 0x03, 0x81, 0x60, 0x84, 0x00, 0x81, 0x82, + 0x80, 0xC3, 0xAE, 0x18, 0x5A, 0x18, 0x02, 0x5E, 0x84, 0xE0, 0x44, 0x20, 0x06, 0x40, 0x44, 0x9F, + 0xF1, 0x00, 0x44, 0xAF, 0xE8, 0x90, 0x44, 0x32, 0xC3, 0x38, 0xE2, 0xED, 0xE8, 0x73, 0x04, 0x05, + 0x80, 0x01, 0x38, 0x50, 0x1D, 0x01, 0xDF, 0x4B, 0x04, 0x05, 0x80, 0x08, 0x3C, 0x5D, 0xFD, 0xAF, + 0x38, 0x40, 0x1E, 0x02, 0x04, 0x05, 0x80, 0x06, 0x00, 0x12, 0x80, 0x32, 0x38, 0x00, 0x1E, 0x02, + 0x00, 0x52, 0x80, 0x33, 0xFE, 0x0C, 0x40, 0x80, 0x11, 0x17, 0x04, 0x05, 0x80, 0x07, 0x38, 0x00, + 0x1E, 0x02, 0xFE, 0x2C, 0x40, 0xE0, 0x11, 0xD7, 0x3C, 0x44, 0x07, 0x3A, 0x44, 0x00, 0x0A, 0x28, + 0xFF, 0x14, 0x40, 0x42, 0x24, 0x96, 0x88, 0x88, 0x42, 0xF2, 0x00, 0x03, 0x3C, 0x44, 0x07, 0x3B, + 0xFF, 0x04, 0x40, 0x42, 0x28, 0x96, 0x88, 0x8E, 0xEB, 0x96, 0x88, 0x8F, 0x5E, 0xF2, 0x00, 0x64, + 0xE9, 0x17, 0xA6, 0x30, 0x3C, 0x4D, 0xFD, 0xAF, 0x38, 0x86, 0x03, 0x09, 0xA6, 0x30, 0x40, 0x06, + 0x00, 0x60, 0x12, 0xE0, 0x00, 0x01, 0xA6, 0x30, 0x38, 0x71, 0x80, 0x08, 0xA6, 0x30, 0x8C, 0x01, + 0x96, 0x00, 0xAE, 0x30, 0x00, 0x42, 0x00, 0x19, 0xE2, 0x04, 0xE9, 0x09, 0xD5, 0x2B, 0xF3, 0x81, + 0xB6, 0x5F, 0x49, 0x00, 0x09, 0x55, 0xB4, 0x5F, 0xF3, 0x01, 0xC0, 0xE4, 0x8C, 0xE1, 0xD5, 0xAE, + 0x3C, 0x1D, 0xFD, 0xAF, 0x84, 0x00, 0x44, 0x22, 0xC3, 0x38, 0xE2, 0x0D, 0xE8, 0x11, 0x04, 0x35, + 0x80, 0x01, 0x38, 0x51, 0x81, 0x01, 0xD8, 0x14, 0xA6, 0xF0, 0x38, 0x01, 0x0C, 0x08, 0xA7, 0x30, + 0x8C, 0x81, 0x97, 0x20, 0xAF, 0x30, 0x00, 0x30, 0x80, 0x19, 0xE2, 0x83, 0xE9, 0x09, 0x80, 0x0B, + 0x44, 0x12, 0xC3, 0x38, 0xA6, 0xB0, 0x80, 0x6C, 0x49, 0xFF, 0xFF, 0x31, 0xD5, 0x03, 0x8C, 0x01, + 0xD5, 0xE5, 0x84, 0x00, 0x44, 0x22, 0xC3, 0x38, 0xA6, 0x70, 0xE2, 0x01, 0xE8, 0x08, 0x40, 0x16, + 0x00, 0x60, 0x38, 0x31, 0x00, 0x00, 0xA8, 0xC9, 0x8C, 0x01, 0xD5, 0xF7, 0xFC, 0xE1, 0x3C, 0x0F, + 0xFD, 0xB5, 0xDD, 0x9E, 0xFC, 0x20, 0x84, 0x80, 0x8E, 0x41, 0x84, 0xC2, 0xE0, 0x44, 0xE9, 0x11, + 0x98, 0xE2, 0x40, 0x31, 0x98, 0x76, 0x38, 0x70, 0x0D, 0x01, 0x95, 0x59, 0xE0, 0x27, 0xE9, 0x07, + 0x88, 0xA0, 0xA5, 0x29, 0xE0, 0x24, 0xE9, 0x07, 0x9D, 0x19, 0xD5, 0xF1, 0x9E, 0x99, 0xD5, 0xEF, + 0x84, 0x1F, 0xFC, 0xA0, 0x80, 0x03, 0xFC, 0xA0, 0xFC, 0x60, 0x3C, 0x7D, 0xFD, 0xB5, 0x81, 0x41, + 0x50, 0xB3, 0x80, 0x0A, 0x50, 0xC3, 0x80, 0x38, 0x50, 0xD0, 0x00, 0x02, 0x85, 0x00, 0x85, 0x3E, + 0xE3, 0x0A, 0x4E, 0xF2, 0x00, 0xC9, 0x22, 0x66, 0xFF, 0xFF, 0xA4, 0x3D, 0xE0, 0x06, 0xE8, 0x48, + 0x02, 0xE3, 0x80, 0x04, 0x40, 0x03, 0xB8, 0x20, 0xA4, 0x04, 0x50, 0x27, 0x7F, 0xFF, 0xE0, 0xC0, + 0xE9, 0x04, 0xA5, 0xB8, 0x8E, 0xC1, 0xD5, 0x3D, 0x80, 0x0B, 0x80, 0x26, 0xF8, 0x52, 0x80, 0x40, + 0x5A, 0x07, 0xFF, 0x38, 0xA5, 0x3B, 0x95, 0x41, 0xE2, 0x04, 0xA4, 0x39, 0xE8, 0x07, 0x88, 0xA7, + 0x03, 0x02, 0x80, 0x05, 0xA4, 0x6E, 0xF8, 0x56, 0xD5, 0x2C, 0xF8, 0x63, 0x03, 0x03, 0x80, 0x00, + 0xA4, 0x7A, 0xE9, 0x13, 0x88, 0xA7, 0x03, 0x12, 0x80, 0x05, 0x98, 0xE1, 0x52, 0x31, 0x80, 0x01, + 0x88, 0x62, 0x8A, 0xD1, 0xFF, 0x84, 0xFE, 0xC4, 0x8B, 0x80, 0xA4, 0x2E, 0x40, 0x31, 0x90, 0x77, + 0xF8, 0x69, 0x88, 0x70, 0x88, 0xC3, 0xD5, 0x15, 0xF8, 0x6F, 0xA4, 0xED, 0x42, 0x42, 0x40, 0x24, + 0x8E, 0x21, 0x40, 0x42, 0x04, 0x97, 0x8A, 0xC3, 0x42, 0x68, 0x18, 0x24, 0x88, 0x80, 0xA4, 0x2E, + 0x40, 0x13, 0x04, 0x36, 0x9B, 0x83, 0x40, 0x60, 0x98, 0xD6, 0x88, 0xC4, 0xD5, 0x02, 0x84, 0xC0, + 0x12, 0x66, 0xFF, 0xFF, 0x02, 0x03, 0x80, 0x1C, 0x22, 0x66, 0x80, 0x00, 0xE0, 0x06, 0xE8, 0x6D, + 0x02, 0xE3, 0x80, 0x1B, 0x50, 0x07, 0x00, 0x1B, 0x38, 0x03, 0x81, 0x01, 0x50, 0x27, 0x7F, 0xFF, + 0xE0, 0xC0, 0xE9, 0x05, 0x02, 0x63, 0x80, 0x17, 0x8E, 0xC1, 0xD5, 0x60, 0x80, 0x0C, 0x80, 0x26, + 0x49, 0xFF, 0xFF, 0x72, 0x80, 0x40, 0x5A, 0x07, 0xFF, 0x5A, 0x02, 0x43, 0x80, 0x1A, 0x95, 0x41, + 0xE2, 0x04, 0x02, 0x03, 0x80, 0x18, 0xE8, 0x15, 0x88, 0xA7, 0x03, 0x02, 0x80, 0x1C, 0x02, 0x12, + 0x80, 0x1D, 0x40, 0x33, 0x40, 0x01, 0xFE, 0xC4, 0xFE, 0x14, 0x40, 0x31, 0x90, 0x76, 0x40, 0x60, + 0xC0, 0x01, 0x40, 0x11, 0x98, 0x36, 0x40, 0x40, 0x10, 0x97, 0x99, 0x8C, 0x83, 0xFF, 0xD5, 0x3E, + 0x40, 0x17, 0x10, 0x01, 0x8E, 0x21, 0xE2, 0x41, 0x83, 0xFF, 0x03, 0x03, 0x80, 0x17, 0x02, 0x33, + 0x80, 0x19, 0xE9, 0x1A, 0x88, 0xA7, 0x03, 0x12, 0x80, 0x1C, 0x98, 0x63, 0x52, 0x10, 0x80, 0x01, + 0x88, 0x22, 0x8A, 0xD1, 0xFF, 0x84, 0xFE, 0x44, 0x8B, 0x80, 0x02, 0x02, 0x80, 0x1D, 0x40, 0x10, + 0x90, 0x37, 0x40, 0x43, 0x10, 0x96, 0x40, 0x60, 0x44, 0x01, 0x40, 0x62, 0x18, 0xD6, 0x83, 0xFF, + 0x88, 0x30, 0x88, 0xC1, 0xD5, 0x1B, 0x43, 0x00, 0x24, 0x73, 0x88, 0xA7, 0x9B, 0x14, 0x83, 0xFF, + 0x02, 0x12, 0x80, 0x1C, 0x42, 0x42, 0x40, 0x24, 0x8E, 0x61, 0x40, 0x42, 0x0C, 0x97, 0x8A, 0xC1, + 0x42, 0x68, 0x18, 0x24, 0x88, 0x80, 0x02, 0x02, 0x80, 0x1D, 0x40, 0x33, 0x0C, 0x76, 0x9B, 0x81, + 0x40, 0x61, 0x98, 0xD6, 0x88, 0xC4, 0xD5, 0x02, 0x84, 0xC0, 0x1A, 0x66, 0x80, 0x04, 0x8D, 0x01, + 0x48, 0xFF, 0xFF, 0x38, 0xFC, 0xE0, 0x3C, 0x0E, 0x00, 0x5F, 0xDD, 0x9E, 0x3C, 0x0E, 0x00, 0x5E, + 0xDD, 0x9E, 0x22, 0x20, 0x00, 0x00, 0x22, 0x30, 0x80, 0x00, 0x22, 0x00, 0x00, 0x01, 0xEA, 0x99, + 0x8A, 0x43, 0x8A, 0x01, 0xFE, 0x04, 0x42, 0x01, 0x08, 0x73, 0xDD, 0x9E, 0x80, 0x60, 0x80, 0x40, + 0x84, 0x01, 0x9A, 0x50, 0xE6, 0x22, 0xE9, 0x0B, 0x98, 0x50, 0x92, 0x21, 0x42, 0xF0, 0x84, 0x24, + 0xE2, 0x6F, 0x40, 0x00, 0xBC, 0x1A, 0x40, 0x20, 0xBC, 0x1B, 0xD5, 0xF4, 0xDD, 0x9E, 0xFC, 0x60, + 0x81, 0x41, 0xEB, 0x28, 0x42, 0x01, 0x04, 0x73, 0x80, 0xC2, 0xB4, 0x20, 0x44, 0xC2, 0xCD, 0xE0, + 0x44, 0xB2, 0xCD, 0xD0, 0x95, 0xD2, 0x44, 0x92, 0xCD, 0x94, 0xC1, 0x0D, 0x00, 0x00, 0x00, 0x1C, + 0x96, 0x04, 0xC0, 0x09, 0x84, 0x03, 0x38, 0x06, 0x08, 0x08, 0x84, 0x00, 0x38, 0x05, 0x88, 0x08, + 0x84, 0x00, 0xD5, 0x38, 0x38, 0x05, 0x98, 0x00, 0xE6, 0x04, 0xE8, 0x06, 0x8C, 0x01, 0x44, 0x12, + 0xCD, 0xD0, 0x38, 0x00, 0x98, 0x08, 0x38, 0x06, 0x18, 0x00, 0x44, 0x12, 0xCD, 0xE0, 0xE6, 0x03, + 0xE9, 0x03, 0x84, 0x00, 0xD5, 0x02, 0x8C, 0x01, 0x38, 0x00, 0x98, 0x08, 0x80, 0x2A, 0x40, 0x04, + 0x9C, 0x00, 0xEB, 0xB4, 0xEB, 0x78, 0xFE, 0x0C, 0xEB, 0x15, 0x44, 0x21, 0x00, 0x00, 0x38, 0x16, + 0x18, 0x00, 0xE2, 0x40, 0x40, 0x01, 0x3C, 0x1B, 0x88, 0x27, 0x44, 0x42, 0xCD, 0x1C, 0x84, 0x60, + 0x38, 0x02, 0x05, 0x09, 0x80, 0x43, 0x38, 0x05, 0x98, 0x00, 0xE2, 0x60, 0xE8, 0x07, 0x98, 0x5F, + 0x38, 0x12, 0x05, 0x01, 0x8C, 0x61, 0x88, 0x41, 0xD5, 0xF9, 0x40, 0x21, 0x00, 0x3C, 0x40, 0x01, + 0x00, 0x16, 0x22, 0x15, 0x00, 0x00, 0x38, 0x14, 0x9A, 0x09, 0x88, 0xE9, 0x22, 0x15, 0x00, 0x01, + 0xAC, 0x79, 0xFC, 0xE0, 0xFC, 0x61, 0x80, 0xC3, 0x81, 0x62, 0x44, 0x20, 0x00, 0x54, 0x42, 0x01, + 0x88, 0x73, 0xF5, 0x81, 0x00, 0x20, 0x00, 0x1C, 0x40, 0xD2, 0x80, 0x11, 0x96, 0x94, 0x40, 0xC2, + 0xC0, 0x0A, 0x22, 0x30, 0x80, 0x00, 0x81, 0x44, 0x01, 0x0F, 0x80, 0x38, 0xEA, 0x99, 0x84, 0xA1, + 0x44, 0x92, 0xCC, 0x8C, 0x44, 0x72, 0xCC, 0x50, 0xC2, 0x11, 0x44, 0x22, 0xCC, 0xF8, 0x38, 0x31, + 0x19, 0x09, 0x44, 0x22, 0xCC, 0xD8, 0x38, 0x11, 0x19, 0x09, 0x38, 0x13, 0x9A, 0x0A, 0x44, 0x12, + 0xCC, 0xC8, 0xEB, 0x4B, 0x38, 0x50, 0x98, 0x08, 0xD5, 0x57, 0xB4, 0x40, 0x5A, 0x28, 0x03, 0x1D, + 0x38, 0x24, 0x9A, 0x02, 0x44, 0x42, 0xCC, 0xC8, 0x88, 0x62, 0x38, 0x23, 0x9A, 0x02, 0xEB, 0x4B, + 0x88, 0x41, 0x38, 0x12, 0x18, 0x00, 0x38, 0x23, 0x9A, 0x0A, 0x8C, 0x21, 0x96, 0x48, 0xE6, 0x2F, + 0x38, 0x12, 0x18, 0x08, 0xE9, 0x41, 0xEA, 0xF0, 0xEA, 0xFF, 0xEB, 0x4B, 0x38, 0x13, 0x9A, 0x0A, + 0x38, 0x52, 0x18, 0x08, 0xD5, 0x39, 0x5A, 0x28, 0x01, 0x35, 0x44, 0x22, 0xCC, 0xF8, 0x3C, 0x4C, + 0x00, 0x5F, 0x39, 0x11, 0x19, 0x11, 0x44, 0x22, 0xCC, 0xD8, 0x38, 0x51, 0x19, 0x11, 0xA6, 0xA0, + 0x5A, 0x28, 0x01, 0x61, 0x40, 0x28, 0x8C, 0x01, 0xEB, 0x65, 0x9A, 0xA9, 0xEA, 0xE5, 0x03, 0x22, + 0x00, 0x04, 0x88, 0x4F, 0xE3, 0xC2, 0xE8, 0x56, 0xA4, 0xA3, 0xE1, 0xA2, 0xE8, 0x03, 0xE0, 0x62, + 0xE8, 0x63, 0x3D, 0x2C, 0x00, 0x5E, 0x02, 0x49, 0x00, 0x09, 0x8E, 0x81, 0x8A, 0x82, 0xE0, 0x91, + 0xE8, 0x03, 0xE0, 0x83, 0xE8, 0x59, 0xE0, 0xA2, 0xE8, 0x03, 0xE0, 0x22, 0xE8, 0x55, 0x02, 0x49, + 0x00, 0x0A, 0x8E, 0x81, 0x8A, 0x82, 0xE0, 0x85, 0xE8, 0x3D, 0xE0, 0x81, 0xE8, 0x4D, 0xD5, 0x3A, + 0xEB, 0x4B, 0x38, 0x13, 0x9A, 0x0A, 0x5B, 0x08, 0x01, 0x2E, 0xB4, 0x00, 0x5A, 0x08, 0x01, 0x2B, + 0xDD, 0x43, 0x5A, 0x08, 0x02, 0x28, 0x3C, 0x1C, 0x00, 0x5F, 0xA4, 0x0D, 0xE3, 0x40, 0xE8, 0x22, + 0xEB, 0x82, 0x38, 0x33, 0x9A, 0x02, 0x40, 0x20, 0x34, 0x01, 0xEB, 0x65, 0x40, 0x21, 0xB0, 0x01, + 0xEA, 0xE5, 0xA5, 0x0E, 0x88, 0x4F, 0xE0, 0x44, 0xE8, 0x15, 0xA4, 0x8F, 0x44, 0x52, 0xCC, 0x8C, + 0x9F, 0x11, 0x42, 0x02, 0x34, 0x73, 0x40, 0x11, 0x04, 0x09, 0x42, 0x32, 0x30, 0x73, 0x88, 0x01, + 0xEA, 0xC9, 0x88, 0x23, 0x38, 0x02, 0x9A, 0x0A, 0xEB, 0x52, 0x44, 0x02, 0xCC, 0x50, 0x38, 0x10, + 0x1A, 0x0A, 0xEB, 0x82, 0x12, 0x05, 0x80, 0x00, 0x38, 0x03, 0x9A, 0x02, 0x12, 0x05, 0x80, 0x01, + 0xFC, 0xE1, 0x38, 0x24, 0x9A, 0x02, 0x44, 0x52, 0xCC, 0xC8, 0x38, 0x42, 0x98, 0x00, 0x88, 0x62, + 0x38, 0x23, 0x9A, 0x02, 0x8C, 0x81, 0x88, 0x41, 0x96, 0x60, 0xEA, 0xF0, 0x38, 0x12, 0x98, 0x08, + 0xEB, 0x4B, 0xEA, 0xFF, 0xD5, 0xB7, 0x39, 0x14, 0x9A, 0x0A, 0x38, 0x53, 0x9A, 0x0A, 0xD5, 0xB4, + 0xFC, 0x60, 0x44, 0x60, 0x00, 0x54, 0x42, 0x01, 0x98, 0x73, 0x3D, 0x3C, 0x00, 0x5F, 0xB4, 0x00, + 0x22, 0x50, 0x80, 0x00, 0xEA, 0xA0, 0xEA, 0x99, 0x01, 0x09, 0x80, 0x1C, 0x00, 0xA9, 0x80, 0x1D, + 0x45, 0x12, 0xCC, 0x40, 0x45, 0x22, 0xCC, 0x30, 0x95, 0xDC, 0x44, 0x62, 0xC8, 0x70, 0x44, 0x92, + 0xC8, 0x60, 0x5A, 0x08, 0x01, 0x10, 0x84, 0x80, 0x38, 0x53, 0x1E, 0x09, 0x40, 0x63, 0x0C, 0xC0, + 0x38, 0x48, 0x8C, 0x08, 0x38, 0x09, 0x0C, 0x08, 0xAC, 0x71, 0x39, 0x04, 0x8C, 0x08, 0x48, 0x00, + 0x00, 0x92, 0x38, 0x09, 0x0C, 0x00, 0xE6, 0x10, 0xE8, 0x04, 0x8C, 0x01, 0x38, 0x09, 0x0C, 0x08, + 0x38, 0x08, 0x8C, 0x00, 0x44, 0xB2, 0xCC, 0x40, 0xE6, 0x0F, 0xE9, 0x03, 0x84, 0x00, 0xD5, 0x02, + 0x8C, 0x01, 0x38, 0x05, 0x8C, 0x08, 0x39, 0x18, 0x8C, 0x00, 0x40, 0x08, 0x9C, 0x00, 0x38, 0x53, + 0x02, 0x09, 0x40, 0x03, 0x00, 0x40, 0xAC, 0x41, 0x02, 0x19, 0x80, 0x10, 0xE0, 0x81, 0xE8, 0x10, + 0x02, 0x59, 0x80, 0x0F, 0xE0, 0xA4, 0xE8, 0x0B, 0x40, 0x08, 0x28, 0x01, 0x8A, 0x85, 0xFE, 0x24, + 0x41, 0x00, 0x94, 0x01, 0x41, 0x00, 0x42, 0x16, 0x89, 0x8A, 0xD5, 0x02, 0x82, 0x0A, 0x38, 0x44, + 0x8C, 0x00, 0x84, 0x03, 0x80, 0x24, 0x42, 0x18, 0x00, 0x73, 0x84, 0x04, 0x8C, 0x22, 0xEB, 0xE2, + 0xE0, 0x80, 0x44, 0x52, 0xC8, 0x60, 0xE8, 0x05, 0x8C, 0x81, 0xE0, 0x80, 0x40, 0x02, 0x3C, 0x1B, + 0x38, 0x02, 0x8C, 0x08, 0x38, 0x19, 0x0C, 0x00, 0x38, 0x44, 0x8C, 0x00, 0x84, 0x6A, 0xFE, 0x5C, + 0xE0, 0x24, 0xE9, 0x04, 0xE2, 0x83, 0x80, 0x24, 0xEB, 0xA5, 0x84, 0xA0, 0x86, 0x0A, 0x41, 0x00, + 0xC2, 0x16, 0x80, 0x05, 0x80, 0x65, 0x4C, 0x58, 0x00, 0x13, 0x40, 0x48, 0x9C, 0x00, 0x39, 0x23, + 0x12, 0x11, 0x40, 0x43, 0x10, 0x40, 0x22, 0x42, 0x00, 0x01, 0x88, 0x72, 0x88, 0x04, 0x4F, 0x12, + 0x00, 0x04, 0x8F, 0xA1, 0xD5, 0x02, 0x86, 0x2F, 0x8C, 0xA1, 0xD5, 0xEE, 0x84, 0x8A, 0xFE, 0xE4, + 0xFE, 0x24, 0x40, 0x40, 0x90, 0xB6, 0xC5, 0x0C, 0x88, 0xF1, 0x38, 0x43, 0x1E, 0x11, 0x40, 0x73, + 0x1C, 0x40, 0x42, 0x32, 0x90, 0x73, 0x22, 0x43, 0x80, 0x01, 0x42, 0x02, 0x90, 0x73, 0x4E, 0x35, + 0x00, 0x06, 0x40, 0x50, 0x84, 0x0A, 0x88, 0xA3, 0xD5, 0x05, 0x84, 0xA2, 0x40, 0x50, 0x94, 0xB6, + 0x9B, 0x5D, 0x40, 0x52, 0x84, 0xB6, 0x97, 0x6B, 0x4E, 0x05, 0x00, 0x06, 0x40, 0x30, 0x84, 0x0A, + 0x88, 0x03, 0xD5, 0x05, 0x84, 0x62, 0x40, 0x30, 0x8C, 0x76, 0x8A, 0x03, 0x40, 0x10, 0x04, 0x36, + 0x96, 0x4B, 0xAD, 0x50, 0xAC, 0x51, 0xFC, 0xE0, 0xFC, 0x20, 0x44, 0x60, 0x00, 0x54, 0x42, 0x01, + 0x98, 0x73, 0x22, 0x50, 0x80, 0x00, 0xB4, 0x00, 0xEA, 0x99, 0xEA, 0xA0, 0x44, 0x62, 0xC8, 0x24, + 0x95, 0xDA, 0x45, 0x02, 0xC8, 0x14, 0x5A, 0x08, 0x01, 0x09, 0x98, 0x37, 0xAC, 0x41, 0xEA, 0x3F, + 0x38, 0x53, 0x0E, 0x09, 0xEB, 0xDE, 0xD5, 0x43, 0x5E, 0xF2, 0x00, 0x29, 0xE9, 0x0F, 0x5E, 0xF2, + 0x00, 0xFA, 0xE8, 0x0E, 0x44, 0x00, 0x00, 0x4B, 0x50, 0x42, 0x7F, 0xD8, 0xFF, 0x04, 0x44, 0x00, + 0x00, 0xD2, 0x40, 0x42, 0x00, 0x96, 0x8C, 0x99, 0xD5, 0x04, 0xFA, 0x89, 0xD5, 0x02, 0xEA, 0xC1, + 0x38, 0x08, 0x0C, 0x00, 0x86, 0x23, 0x42, 0x02, 0x44, 0x73, 0x39, 0x23, 0x0E, 0x11, 0x8C, 0x02, + 0x90, 0x02, 0x99, 0x37, 0xEB, 0xDE, 0x23, 0x12, 0x00, 0x01, 0x53, 0x00, 0x00, 0x64, 0x42, 0x40, + 0x14, 0x24, 0x42, 0x48, 0x48, 0x73, 0x44, 0x50, 0x00, 0x64, 0x4E, 0x45, 0x00, 0x05, 0x50, 0x42, + 0x00, 0x32, 0xD5, 0x03, 0x50, 0x42, 0x7F, 0xCE, 0xFE, 0x0C, 0x42, 0x08, 0x44, 0x73, 0x40, 0x42, + 0x14, 0x96, 0x38, 0x43, 0x0E, 0x09, 0xEB, 0x78, 0x4E, 0x05, 0x00, 0x05, 0x50, 0x00, 0x00, 0x32, + 0xD5, 0x03, 0x50, 0x00, 0x7F, 0xCE, 0xEA, 0x9F, 0x98, 0x77, 0xAC, 0x09, 0x38, 0x03, 0x0E, 0x01, + 0x88, 0xC7, 0xAC, 0x10, 0xA4, 0x31, 0xAC, 0x11, 0xFC, 0xA0, 0xFC, 0x60, 0x22, 0x40, 0x80, 0x00, + 0x22, 0x50, 0x80, 0x01, 0xEB, 0x28, 0x42, 0x01, 0x84, 0x73, 0x44, 0x72, 0xC5, 0xE4, 0xB4, 0x20, + 0x41, 0x11, 0x88, 0x08, 0xEB, 0xA0, 0x3C, 0x6C, 0x00, 0x5F, 0x5A, 0x18, 0x01, 0x12, 0xAD, 0x10, + 0xAD, 0x51, 0xA6, 0x35, 0xF8, 0xDB, 0x5A, 0x00, 0x01, 0x04, 0x48, 0x00, 0x00, 0xE4, 0x44, 0x72, + 0xC5, 0xA8, 0x84, 0x00, 0x38, 0x03, 0x8E, 0x09, 0x88, 0xF1, 0xAC, 0x39, 0xFC, 0xE0, 0x01, 0x23, + 0x00, 0x05, 0x01, 0x30, 0x00, 0x1C, 0x5B, 0x28, 0x01, 0x3E, 0x54, 0x09, 0x80, 0x02, 0xC0, 0x3A, + 0x44, 0x02, 0xC5, 0xA8, 0x38, 0x60, 0x0E, 0x11, 0x88, 0x11, 0x22, 0x00, 0x00, 0x01, 0xCE, 0x05, + 0xC0, 0x31, 0x38, 0x43, 0x8E, 0x11, 0xD5, 0x2E, 0xC8, 0x06, 0x40, 0x03, 0xC4, 0x00, 0x22, 0x50, + 0x00, 0x01, 0xD5, 0x28, 0x40, 0x13, 0xC4, 0x00, 0xEA, 0x99, 0x53, 0x03, 0x00, 0x00, 0xFF, 0x8C, + 0x38, 0x13, 0x8E, 0x11, 0x81, 0x44, 0x42, 0x60, 0x04, 0x75, 0x42, 0x48, 0x40, 0x24, 0x42, 0x10, + 0x00, 0x24, 0x42, 0xB0, 0x40, 0x24, 0x40, 0x90, 0x90, 0x00, 0x42, 0x42, 0x28, 0x24, 0x42, 0x45, + 0x94, 0x75, 0x42, 0x40, 0x18, 0x75, 0xFE, 0x02, 0x42, 0x00, 0x40, 0x24, 0xFE, 0x6C, 0x42, 0x10, + 0x28, 0x73, 0x42, 0x18, 0x18, 0x75, 0x40, 0x42, 0x24, 0x96, 0x40, 0x10, 0xA4, 0x36, 0x97, 0x23, + 0x97, 0x4B, 0x54, 0x09, 0x80, 0x02, 0xC0, 0x7B, 0xEB, 0x06, 0x80, 0x24, 0x02, 0x60, 0x00, 0x09, + 0xE0, 0x86, 0xE9, 0x08, 0x39, 0x33, 0x8E, 0x11, 0xE1, 0xE6, 0xE8, 0x0F, 0x51, 0x33, 0x7F, 0xFF, + 0xD5, 0x0C, 0x4E, 0x44, 0x00, 0x08, 0x39, 0x33, 0x8E, 0x11, 0x4F, 0x35, 0x00, 0x07, 0x86, 0x60, + 0xD5, 0x04, 0x82, 0x64, 0x85, 0x20, 0xD5, 0x02, 0x85, 0x21, 0x03, 0x00, 0x00, 0x0A, 0x80, 0x05, + 0xE0, 0xB0, 0xE9, 0x0A, 0x40, 0x93, 0xC4, 0x00, 0x22, 0x94, 0x80, 0x01, 0xE1, 0x30, 0xE8, 0x11, + 0x50, 0x98, 0x7F, 0xFF, 0xD5, 0x0E, 0x4E, 0x54, 0x00, 0x0A, 0x40, 0x93, 0xC4, 0x00, 0x22, 0xA4, + 0x80, 0x01, 0x85, 0x20, 0x42, 0x95, 0x24, 0x01, 0xD5, 0x04, 0x5A, 0x98, 0x01, 0x49, 0x81, 0x25, + 0x38, 0xA3, 0x8E, 0x11, 0x40, 0xB3, 0xC4, 0x00, 0x22, 0xB5, 0x80, 0x01, 0x40, 0xD2, 0x28, 0x01, + 0x40, 0xC2, 0xAC, 0x01, 0x4E, 0xD2, 0x00, 0x0C, 0x84, 0x02, 0x40, 0xE9, 0xA8, 0x01, 0x40, 0x06, + 0x80, 0x16, 0x42, 0x07, 0x30, 0x73, 0x40, 0x00, 0x34, 0x16, 0x88, 0x0B, 0x4E, 0xC2, 0x00, 0x0C, + 0x84, 0x22, 0x40, 0xE4, 0xAC, 0x01, 0x40, 0x16, 0x04, 0x36, 0x42, 0x17, 0x34, 0x73, 0x40, 0x10, + 0xB0, 0x36, 0x88, 0x2A, 0x4C, 0x95, 0x80, 0x3B, 0xE0, 0x26, 0xE9, 0x05, 0x52, 0x63, 0x00, 0x01, + 0x88, 0xC1, 0xD5, 0x04, 0x4E, 0x14, 0x00, 0x33, 0xFF, 0x8A, 0x4D, 0x35, 0x00, 0x0D, 0xE0, 0x10, + 0xE9, 0x05, 0x53, 0x08, 0x00, 0x01, 0x89, 0x80, 0xD5, 0x07, 0x4E, 0x04, 0x00, 0x05, 0x53, 0x00, + 0x00, 0x00, 0xD5, 0x02, 0x86, 0x00, 0xE1, 0x86, 0xE8, 0x05, 0x40, 0x49, 0x80, 0x11, 0x97, 0x43, + 0xD5, 0x06, 0xE0, 0xD0, 0xE8, 0x04, 0x97, 0x0B, 0x40, 0x54, 0x80, 0x11, 0x5B, 0x28, 0x01, 0x0F, + 0x38, 0x13, 0x8E, 0x01, 0x44, 0x02, 0xC5, 0xA8, 0x9A, 0x61, 0x38, 0x10, 0x0E, 0x09, 0x40, 0x13, + 0xC4, 0x00, 0xA4, 0x49, 0x88, 0x11, 0x9A, 0x69, 0xAC, 0x41, 0x38, 0x43, 0x8E, 0x09, 0x88, 0xF1, + 0xAD, 0x79, 0x83, 0xFF, 0xAD, 0x10, 0xAD, 0x51, 0xFC, 0xE0, 0x4D, 0x35, 0x3F, 0xE9, 0x84, 0xC0, + 0xD5, 0xCF, 0xFC, 0xE0, 0x44, 0x40, 0x00, 0x54, 0x42, 0x01, 0x90, 0x73, 0x00, 0x00, 0x00, 0x4C, + 0x5A, 0x00, 0x06, 0x04, 0x5A, 0x08, 0x09, 0x0B, 0x88, 0x23, 0xA6, 0x08, 0xC0, 0x04, 0x8E, 0x01, + 0xAE, 0x08, 0xDD, 0x9E, 0xFA, 0x0E, 0x38, 0x01, 0x0E, 0x0A, 0xDD, 0x9E, 0xFC, 0x21, 0xF3, 0x81, + 0xF3, 0x08, 0x88, 0x43, 0xA7, 0x90, 0xE6, 0xC6, 0xE8, 0x2A, 0x8C, 0xC1, 0xAF, 0x90, 0x44, 0x60, + 0x00, 0x54, 0x42, 0x01, 0x98, 0x73, 0x84, 0xC0, 0x10, 0x60, 0x00, 0x4C, 0x3C, 0x6D, 0xFC, 0x0B, + 0x44, 0x70, 0x00, 0x78, 0xB4, 0xC6, 0x38, 0x70, 0x8E, 0x0A, 0xA6, 0x90, 0x42, 0x63, 0x58, 0x0B, + 0x5A, 0x28, 0x06, 0x16, 0x84, 0x41, 0x10, 0x20, 0x00, 0x4C, 0xB0, 0x01, 0x40, 0x52, 0x8C, 0x40, + 0x3A, 0x00, 0x00, 0x00, 0xE4, 0x9F, 0x3A, 0x02, 0x80, 0x20, 0xE9, 0x05, 0x8C, 0x9E, 0x38, 0x40, + 0x8E, 0x0A, 0xFC, 0xA1, 0x44, 0x00, 0x00, 0x3C, 0x38, 0x00, 0x8E, 0x0A, 0xFC, 0xA1, 0xFC, 0x01, + 0x94, 0xDA, 0xF0, 0x81, 0x88, 0x43, 0x22, 0x41, 0x00, 0x00, 0x22, 0xFF, 0x80, 0x02, 0xE0, 0x8F, + 0xE8, 0x09, 0xEB, 0x06, 0x02, 0x50, 0x00, 0x09, 0xFE, 0x23, 0x84, 0x8A, 0x42, 0x02, 0x90, 0x73, + 0x97, 0x03, 0x22, 0x01, 0x00, 0x01, 0x22, 0xFF, 0x80, 0x03, 0xE0, 0x0F, 0xE8, 0x0A, 0x3C, 0x2C, + 0x00, 0x5E, 0xFE, 0x03, 0x02, 0x51, 0x00, 0x0A, 0x84, 0x4A, 0x42, 0x02, 0x88, 0x73, 0x96, 0x03, + 0x88, 0x23, 0xB4, 0x41, 0x42, 0x00, 0x10, 0x01, 0xE0, 0x02, 0xE8, 0x0D, 0x5E, 0xF0, 0x00, 0x33, + 0xE9, 0x04, 0x50, 0x00, 0x7F, 0xCE, 0xB6, 0x01, 0xB4, 0x01, 0x5E, 0xF0, 0x00, 0x64, 0xE8, 0x03, + 0xEA, 0x3F, 0xB6, 0x01, 0xFC, 0x81, 0x44, 0x30, 0x00, 0x54, 0x42, 0x01, 0x0C, 0x73, 0x00, 0x30, + 0x00, 0x4E, 0xCB, 0x0D, 0x04, 0x40, 0x00, 0x08, 0x3C, 0x3C, 0x02, 0x95, 0x38, 0x31, 0x92, 0x02, + 0x5E, 0xF1, 0x97, 0x71, 0xE9, 0x04, 0x84, 0x61, 0x10, 0x30, 0x00, 0x4E, 0x00, 0x30, 0x00, 0x4E, + 0x5A, 0x38, 0x01, 0x0E, 0x40, 0x20, 0x88, 0x40, 0xB4, 0x22, 0x5E, 0xF0, 0x81, 0x2C, 0xE8, 0x07, + 0x00, 0x00, 0x00, 0x4C, 0xC8, 0x04, 0x44, 0x00, 0x01, 0x2C, 0xB6, 0x02, 0xDD, 0x9E, 0xFC, 0x01, + 0xF0, 0x06, 0xEB, 0x28, 0x42, 0x20, 0x04, 0x73, 0x00, 0x11, 0x00, 0x4C, 0x5A, 0x18, 0x08, 0x2B, + 0x00, 0x11, 0x00, 0x4F, 0x88, 0xA0, 0x5A, 0x18, 0x03, 0x17, 0x5E, 0xF2, 0x00, 0x33, 0xE9, 0x13, + 0xA6, 0x68, 0x5C, 0xF0, 0x80, 0x64, 0xE8, 0x03, 0x8C, 0x21, 0xAE, 0x68, 0xA6, 0x68, 0xE6, 0x35, + 0xE9, 0x19, 0x40, 0x01, 0x80, 0x40, 0xB4, 0x20, 0x50, 0x20, 0xFF, 0xF5, 0xE6, 0x54, 0xE8, 0x12, + 0x8E, 0x21, 0xD5, 0x0F, 0xA6, 0x68, 0xC1, 0x04, 0x8E, 0x21, 0xAE, 0x68, 0xFC, 0x81, 0x40, 0x01, + 0x80, 0x40, 0xB4, 0x20, 0x8A, 0x81, 0x4E, 0x44, 0x00, 0x06, 0xE4, 0x3E, 0xE8, 0x03, 0x8C, 0x21, + 0xB6, 0x20, 0xFC, 0x81, 0x22, 0x20, 0x00, 0x00, 0xE0, 0x22, 0xE8, 0x19, 0xFC, 0x00, 0x3C, 0x4C, + 0x00, 0x5E, 0x84, 0x6A, 0x02, 0x52, 0x00, 0x09, 0xFF, 0x8B, 0x42, 0x62, 0x8C, 0x73, 0xE0, 0x46, + 0xE8, 0x10, 0x22, 0x20, 0x00, 0x01, 0xE0, 0x22, 0xE8, 0x0C, 0x02, 0x02, 0x00, 0x0A, 0xFE, 0x4B, + 0x42, 0x10, 0x0C, 0x73, 0xE0, 0x41, 0x56, 0x07, 0x80, 0x01, 0xFC, 0x80, 0x84, 0x01, 0xDD, 0x9E, + 0x84, 0x01, 0xFC, 0x80, 0xFC, 0x00, 0x44, 0x30, 0x00, 0x54, 0x42, 0x11, 0x0C, 0x73, 0x80, 0xC1, + 0x44, 0x10, 0x01, 0xF4, 0x49, 0xFF, 0xFF, 0xD8, 0x10, 0x03, 0x00, 0x52, 0xFC, 0x80, 0xFC, 0x01, + 0xF0, 0x81, 0x40, 0x10, 0x88, 0x40, 0x22, 0x30, 0x80, 0x00, 0x22, 0xFF, 0x80, 0x02, 0xE0, 0x6F, + 0xE8, 0x09, 0xEB, 0x06, 0xFE, 0xDB, 0x02, 0x20, 0x00, 0x09, 0x84, 0x0A, 0x42, 0x31, 0x00, 0x73, + 0x96, 0xDB, 0x22, 0x00, 0x80, 0x01, 0x22, 0xFF, 0x80, 0x03, 0xE0, 0x0F, 0xE8, 0x0A, 0x3C, 0x1C, + 0x00, 0x5E, 0xFE, 0x03, 0x02, 0x20, 0x80, 0x0A, 0x84, 0x2A, 0x42, 0x01, 0x04, 0x73, 0x96, 0x03, + 0x42, 0x00, 0x0C, 0x01, 0xFC, 0x81, 0xFC, 0x21, 0xF0, 0x81, 0xEA, 0xB2, 0x42, 0x12, 0x00, 0x73, + 0x00, 0x00, 0x80, 0x52, 0xC8, 0x21, 0x22, 0x70, 0x80, 0x04, 0xC7, 0x12, 0x3C, 0x6C, 0x00, 0x5E, + 0x84, 0x0A, 0x02, 0x53, 0x00, 0x09, 0xFF, 0x44, 0x8E, 0xA1, 0x4C, 0x72, 0x80, 0x0A, 0x22, 0x50, + 0x80, 0x05, 0xC5, 0x06, 0x02, 0x63, 0x00, 0x0A, 0xFE, 0x34, 0x8E, 0x01, 0xD8, 0x0D, 0x84, 0x02, + 0x10, 0x00, 0x80, 0x52, 0x84, 0x06, 0x38, 0x01, 0x90, 0x08, 0x44, 0x30, 0x03, 0x20, 0x38, 0x31, + 0x12, 0x0A, 0x10, 0x00, 0x80, 0x4C, 0xFC, 0xA1, 0xFC, 0x21, 0xF6, 0x08, 0xF4, 0x81, 0x95, 0x32, + 0x88, 0x44, 0xB4, 0xE2, 0xE0, 0xE1, 0xE8, 0x30, 0xEB, 0x28, 0x42, 0x03, 0x04, 0x73, 0x84, 0x2F, + 0xEA, 0x4E, 0xB0, 0x41, 0x88, 0x85, 0xEA, 0xCF, 0xE4, 0xFF, 0x3A, 0x12, 0x04, 0x20, 0xE9, 0x03, + 0xFA, 0x2E, 0xB6, 0x22, 0x84, 0x20, 0x38, 0x11, 0x98, 0x08, 0x00, 0x10, 0x00, 0x4C, 0xE6, 0x2A, + 0xE8, 0x1B, 0x44, 0xF1, 0x40, 0xD0, 0xEA, 0xD6, 0x40, 0xF0, 0xBC, 0x00, 0x4A, 0x00, 0x3C, 0x00, + 0x0A, 0x0E, 0x26, 0x26, 0x16, 0x26, 0x1A, 0x26, 0x26, 0x12, 0x84, 0x23, 0xD5, 0x08, 0x84, 0x22, + 0xD5, 0x06, 0x84, 0x2A, 0xD5, 0x04, 0x84, 0x25, 0xD5, 0x02, 0x84, 0x27, 0x10, 0x10, 0x00, 0x4C, + 0x84, 0x21, 0x10, 0x10, 0x00, 0x4F, 0xFC, 0xA1, 0x44, 0x20, 0x00, 0x54, 0x42, 0x00, 0x88, 0x73, + 0x00, 0x10, 0x00, 0x4F, 0x5A, 0x18, 0x03, 0x05, 0x84, 0x28, 0x10, 0x10, 0x00, 0x4C, 0xDD, 0x9E, + 0xFC, 0x61, 0x80, 0xE2, 0x81, 0x21, 0x80, 0x45, 0x80, 0x24, 0x80, 0xC5, 0xF0, 0x81, 0x81, 0x63, + 0x81, 0x44, 0xF8, 0x5F, 0xEB, 0x28, 0x42, 0x73, 0x04, 0x73, 0x00, 0x13, 0x80, 0x51, 0x5A, 0x18, + 0x0F, 0x20, 0x38, 0x25, 0x99, 0x01, 0x50, 0xF1, 0x00, 0x96, 0xE2, 0x0F, 0xE8, 0x04, 0x84, 0x00, + 0x10, 0x03, 0x80, 0x4D, 0x00, 0x03, 0x80, 0x4D, 0x5A, 0x08, 0x01, 0x13, 0x95, 0xB2, 0x89, 0x26, + 0xB0, 0x01, 0x80, 0x29, 0xEB, 0xB4, 0x5C, 0xF0, 0x01, 0x90, 0xE8, 0x07, 0x88, 0xCA, 0x3A, 0x04, + 0x80, 0x00, 0x3A, 0x03, 0x00, 0x20, 0xFC, 0xE1, 0x84, 0x00, 0x10, 0x03, 0x80, 0x4D, 0xFC, 0xE1, + 0xFC, 0x61, 0xF6, 0x10, 0xF0, 0x81, 0xEA, 0xB2, 0x42, 0x33, 0x00, 0x73, 0x80, 0xE2, 0x00, 0x21, + 0x80, 0x4F, 0x81, 0x24, 0x81, 0x45, 0x04, 0xBF, 0x80, 0x0E, 0x04, 0x8F, 0x80, 0x0F, 0x81, 0xA3, + 0x5A, 0x28, 0x01, 0x50, 0x00, 0x01, 0x80, 0x4C, 0x5A, 0x08, 0x02, 0x05, 0x10, 0x21, 0x80, 0x4D, + 0xD5, 0x0F, 0x5A, 0x00, 0x03, 0x0E, 0x5A, 0x08, 0x05, 0x07, 0x10, 0x21, 0x80, 0x4D, 0x44, 0xC0, + 0x01, 0x2C, 0xD5, 0x08, 0x5A, 0x00, 0x07, 0x05, 0x85, 0x80, 0x5A, 0x08, 0x0A, 0x04, 0x44, 0xC0, + 0x01, 0xF4, 0x84, 0x40, 0x44, 0x02, 0xC3, 0xCC, 0x40, 0xE3, 0x08, 0x08, 0x38, 0x20, 0x19, 0x09, + 0x88, 0x2E, 0x40, 0x04, 0x38, 0x00, 0xEA, 0xCF, 0xEB, 0x70, 0xF0, 0x01, 0x80, 0x28, 0x80, 0x46, + 0x49, 0xFF, 0xFF, 0x07, 0xE2, 0x0C, 0xE8, 0x08, 0x96, 0x01, 0x40, 0x15, 0x98, 0x20, 0xC8, 0x02, + 0x84, 0x01, 0xAC, 0x08, 0xD5, 0x03, 0x38, 0xC5, 0x99, 0x09, 0x40, 0x33, 0xB8, 0x00, 0xA4, 0x58, + 0x02, 0x0F, 0x80, 0x02, 0xA4, 0xD9, 0x9A, 0x41, 0xEA, 0xA8, 0x96, 0x4B, 0x44, 0x22, 0xC3, 0x90, + 0x8A, 0x03, 0x38, 0x11, 0x1A, 0x09, 0x96, 0x03, 0x88, 0x4E, 0xAC, 0x11, 0xFE, 0x04, 0x42, 0x00, + 0x84, 0x73, 0xEB, 0x15, 0x44, 0x12, 0xC3, 0x54, 0x38, 0x00, 0x9A, 0x0A, 0x84, 0x02, 0xEB, 0xC0, + 0x00, 0x16, 0x80, 0x51, 0x00, 0x06, 0x80, 0x4F, 0x5A, 0x10, 0x0F, 0x04, 0x48, 0x00, 0x00, 0xB2, + 0x44, 0xE2, 0xC3, 0xCC, 0x40, 0xC3, 0x08, 0x08, 0x45, 0xC2, 0xC3, 0x54, 0x5A, 0x08, 0x03, 0x0A, + 0x84, 0x00, 0x38, 0x0E, 0x1A, 0x0A, 0x38, 0x05, 0x99, 0x01, 0x38, 0x07, 0x19, 0x09, 0xD5, 0x34, + 0x00, 0x06, 0x80, 0x4D, 0xC8, 0x0F, 0x40, 0x14, 0x30, 0x00, 0xB0, 0x01, 0xEB, 0xB4, 0xEB, 0x15, + 0x38, 0x17, 0x19, 0x01, 0x96, 0x01, 0xE2, 0x20, 0x3C, 0x0B, 0xFB, 0x6C, 0xE8, 0x03, 0x38, 0x07, + 0x19, 0x09, 0x40, 0xB5, 0x98, 0x20, 0xEB, 0xCA, 0x38, 0x17, 0x19, 0x01, 0xE2, 0x20, 0xE9, 0x06, + 0x44, 0x12, 0xC3, 0xCC, 0xEB, 0xAF, 0x84, 0x03, 0xEB, 0xC0, 0x40, 0x24, 0xB0, 0x00, 0x38, 0x0E, + 0x1A, 0x02, 0xB4, 0x22, 0xE0, 0x20, 0xE8, 0x10, 0x02, 0x35, 0x80, 0x00, 0x38, 0x17, 0x19, 0x01, + 0x9A, 0x59, 0xFE, 0x0C, 0x40, 0x00, 0x0C, 0x16, 0xE4, 0x1E, 0xB6, 0x02, 0xE8, 0x05, 0x84, 0x03, + 0xEB, 0xC0, 0xFA, 0x0E, 0xB6, 0x02, 0x38, 0x14, 0x9A, 0x02, 0x84, 0x05, 0xFE, 0x0C, 0xE2, 0x0A, + 0xE8, 0x08, 0x88, 0xEC, 0x02, 0x0F, 0x80, 0x02, 0xAC, 0x38, 0xEA, 0xA8, 0xAC, 0x39, 0xFC, 0xE1, + 0xE1, 0x41, 0xE9, 0x73, 0x40, 0xB3, 0xB0, 0x00, 0x22, 0xD5, 0x80, 0x00, 0x22, 0x0F, 0x80, 0x02, + 0x22, 0xC5, 0x80, 0x01, 0x8A, 0x0D, 0x22, 0x5F, 0x80, 0x03, 0x42, 0x40, 0x00, 0x03, 0x8A, 0xAC, + 0xC4, 0x08, 0x42, 0x32, 0x80, 0x03, 0x84, 0x4A, 0xFE, 0x9C, 0x40, 0x91, 0x11, 0x36, 0xD5, 0x02, + 0x81, 0x24, 0x42, 0x60, 0x04, 0x24, 0xFE, 0x6C, 0x40, 0x63, 0x28, 0xD6, 0x40, 0xA0, 0xA9, 0x56, + 0x9B, 0x86, 0x8A, 0xAA, 0x84, 0x05, 0xFF, 0x84, 0xFE, 0x2C, 0x84, 0xE4, 0x40, 0x63, 0x1C, 0xD6, + 0x40, 0x70, 0x1C, 0xF6, 0x42, 0x03, 0x9C, 0x24, 0x42, 0x03, 0x18, 0x73, 0xEB, 0x15, 0x50, 0x14, + 0xFF, 0xFB, 0xE6, 0x30, 0xE8, 0x18, 0xE4, 0x0B, 0xE9, 0x23, 0x8F, 0x29, 0xE7, 0x23, 0xE8, 0x22, + 0xE4, 0x0F, 0xE8, 0x20, 0x42, 0x03, 0x00, 0x03, 0x42, 0x13, 0x80, 0x03, 0xE0, 0x20, 0xE8, 0x05, + 0xFF, 0xC4, 0x40, 0x73, 0x84, 0xF6, 0xD5, 0x16, 0xE0, 0x01, 0xE8, 0x14, 0xFF, 0x8C, 0x40, 0x63, + 0x00, 0xD6, 0xD5, 0x10, 0xE4, 0x0A, 0xE8, 0x03, 0x84, 0xE0, 0x80, 0xC7, 0x9C, 0x35, 0xE6, 0x0B, + 0xE8, 0x02, 0x84, 0xC0, 0x9C, 0x3D, 0xE6, 0x0B, 0xE8, 0x05, 0x84, 0xE0, 0xD5, 0x03, 0x84, 0xE0, + 0x80, 0xC7, 0x88, 0xCD, 0x88, 0xEC, 0x12, 0x65, 0x80, 0x00, 0x12, 0x75, 0x80, 0x01, 0xFC, 0xE1, + 0x5A, 0x08, 0x02, 0x14, 0xE5, 0x5F, 0xE8, 0x11, 0x44, 0x12, 0xC3, 0x54, 0x38, 0x00, 0x9A, 0x02, + 0x8E, 0x01, 0x38, 0x00, 0x9A, 0x0A, 0x40, 0x64, 0x98, 0x40, 0xB4, 0x06, 0x8E, 0x01, 0xE4, 0x1E, + 0xB6, 0x06, 0xE8, 0x03, 0x84, 0x03, 0xEB, 0xC0, 0xFC, 0xE1, 0xFC, 0x63, 0xF0, 0x84, 0x22, 0x00, + 0x80, 0x00, 0x3C, 0x0B, 0xFC, 0x96, 0x22, 0x00, 0x80, 0x01, 0x3C, 0x0B, 0xFC, 0x97, 0xF7, 0x04, + 0xEA, 0xB2, 0x42, 0x71, 0x80, 0x73, 0x81, 0x82, 0xB4, 0x27, 0x80, 0xC3, 0xEB, 0xA0, 0x44, 0x92, + 0xC5, 0x0C, 0x40, 0xA1, 0x88, 0x08, 0x44, 0xB2, 0xC4, 0x84, 0x5A, 0x18, 0x01, 0x30, 0x84, 0x00, + 0x44, 0x22, 0xC5, 0x94, 0x38, 0x01, 0x0C, 0x08, 0x10, 0x13, 0x80, 0x50, 0x44, 0x22, 0xC5, 0x84, + 0xEA, 0xD5, 0x38, 0x01, 0x0C, 0x08, 0x10, 0x03, 0x80, 0x4C, 0x3C, 0x2D, 0xFE, 0x4B, 0x10, 0x03, + 0x80, 0x4D, 0x10, 0x03, 0x80, 0x4E, 0x10, 0x03, 0x80, 0x4F, 0x44, 0x32, 0xC5, 0x48, 0xB4, 0x21, + 0x38, 0x21, 0x9A, 0x0A, 0x38, 0x24, 0x9A, 0x0A, 0xEB, 0x66, 0x44, 0x20, 0x00, 0x78, 0x38, 0x20, + 0x9A, 0x0A, 0x44, 0x12, 0xC4, 0xC0, 0x38, 0x00, 0x98, 0x08, 0x80, 0x46, 0x44, 0x02, 0xC5, 0xA4, + 0xF1, 0x04, 0x49, 0xFF, 0xFD, 0xC1, 0x48, 0x00, 0x00, 0x86, 0x44, 0x12, 0xC5, 0xA4, 0x40, 0x05, + 0xA8, 0x00, 0xEB, 0xB4, 0xEB, 0x15, 0xF0, 0x85, 0xFA, 0x00, 0x10, 0x03, 0x80, 0x51, 0x00, 0x03, + 0x80, 0x4C, 0xE6, 0x02, 0xE8, 0x1A, 0xF0, 0x04, 0x3C, 0x3D, 0xFE, 0x4B, 0xF4, 0x05, 0x44, 0x52, + 0xC5, 0x48, 0xB6, 0xDF, 0xEB, 0x66, 0x44, 0x22, 0xC5, 0x94, 0x49, 0xFF, 0xFC, 0xC9, 0xF0, 0x04, + 0x80, 0x46, 0xEB, 0x66, 0x49, 0xFF, 0xFD, 0x29, 0xEB, 0x35, 0xEB, 0x66, 0x44, 0x22, 0xC5, 0x48, + 0x80, 0x66, 0x49, 0xFF, 0xFC, 0xEE, 0xD5, 0x24, 0x9E, 0x42, 0xE6, 0x22, 0xE9, 0x08, 0x5A, 0x00, + 0x05, 0x07, 0x9E, 0x47, 0xE6, 0x22, 0xE9, 0x03, 0x5A, 0x08, 0x0A, 0x1B, 0xF0, 0x04, 0x80, 0x26, + 0x49, 0xFF, 0xFE, 0x1C, 0xEB, 0x35, 0xF1, 0x04, 0x44, 0x22, 0xC4, 0xD0, 0x44, 0x32, 0xC5, 0x84, + 0x80, 0x86, 0x49, 0xFF, 0xFD, 0xB2, 0xB6, 0xDF, 0xEB, 0x35, 0x38, 0x14, 0x9A, 0x02, 0xF2, 0x04, + 0x44, 0x32, 0xC4, 0xD0, 0xF4, 0x05, 0x44, 0x52, 0xC4, 0xC0, 0x49, 0xFF, 0xFD, 0x22, 0xF0, 0x04, + 0x44, 0x12, 0xC5, 0x84, 0x44, 0x22, 0xC4, 0xD0, 0x80, 0x66, 0x49, 0xFF, 0xFC, 0x7D, 0x44, 0x82, + 0xC4, 0x28, 0xF0, 0x04, 0xF1, 0x05, 0x44, 0x22, 0xC4, 0xD0, 0x44, 0x32, 0xC5, 0x84, 0x3C, 0x4D, + 0xFE, 0x4B, 0x44, 0x52, 0xC5, 0x48, 0x44, 0x72, 0xC3, 0xEC, 0xB6, 0xDF, 0x49, 0xFF, 0xFD, 0xB6, + 0xEB, 0x35, 0x44, 0x12, 0xC4, 0x48, 0xF2, 0x04, 0x80, 0x68, 0x80, 0x87, 0x80, 0xA6, 0x49, 0xFF, + 0xFD, 0xF1, 0xEB, 0x35, 0x44, 0x12, 0xC4, 0x48, 0xB7, 0x1F, 0xF7, 0x81, 0xF6, 0x82, 0x44, 0x22, + 0xC4, 0x84, 0xF3, 0x04, 0x44, 0x42, 0xC4, 0xD0, 0xF5, 0x05, 0x49, 0xFF, 0xFE, 0x13, 0x38, 0x05, + 0x9A, 0x01, 0x40, 0x15, 0xA8, 0x00, 0x38, 0x04, 0x9A, 0x09, 0xA4, 0x49, 0x40, 0x04, 0xA8, 0x00, + 0xAC, 0x41, 0x38, 0x04, 0x9A, 0x01, 0x89, 0x49, 0x12, 0x06, 0x00, 0x00, 0x02, 0x05, 0x00, 0x01, + 0x12, 0x06, 0x00, 0x01, 0x3C, 0x1D, 0xFE, 0x4B, 0x44, 0x02, 0xC4, 0x48, 0x38, 0x10, 0x1A, 0x0A, + 0xEB, 0x82, 0x38, 0x05, 0x9A, 0x0A, 0xFC, 0xE3, 0xFC, 0x63, 0x3C, 0x1C, 0x00, 0x5F, 0x80, 0xC0, + 0xA4, 0x4D, 0x3C, 0x0D, 0xFB, 0x29, 0xE2, 0x01, 0xE8, 0x04, 0x8C, 0x01, 0x3C, 0x0F, 0xFB, 0x29, + 0x84, 0xE0, 0x50, 0x93, 0x00, 0x08, 0x85, 0x4A, 0x85, 0x6A, 0x81, 0x07, 0xEB, 0x06, 0x00, 0x30, + 0x00, 0x09, 0xE2, 0xE3, 0x4E, 0xF2, 0x00, 0x89, 0x04, 0x04, 0xFF, 0xFE, 0x4E, 0x02, 0x00, 0x80, + 0x5A, 0x08, 0x05, 0x04, 0x48, 0x00, 0x00, 0x7C, 0x02, 0x04, 0x80, 0x02, 0x12, 0x0F, 0x80, 0x0A, + 0x02, 0x04, 0x80, 0x03, 0xEB, 0x9E, 0xB0, 0x45, 0x80, 0x47, 0x80, 0x06, 0x49, 0xFF, 0xF8, 0xC9, + 0xF0, 0x83, 0x3C, 0x0C, 0x00, 0x5F, 0xB0, 0x45, 0xA6, 0x01, 0xB6, 0x1F, 0x80, 0x41, 0x80, 0x06, + 0x80, 0x67, 0x3C, 0x4D, 0xFB, 0x29, 0x3C, 0x5C, 0x00, 0x28, 0x49, 0xFF, 0xF9, 0x15, 0x02, 0x0F, + 0x80, 0x0A, 0x3C, 0xCC, 0x00, 0x5F, 0x42, 0x00, 0x28, 0x24, 0x12, 0x0F, 0x80, 0x0A, 0x02, 0x0F, + 0x80, 0x0B, 0x42, 0x00, 0x28, 0x24, 0xEB, 0x9E, 0x00, 0x06, 0x00, 0x03, 0xC0, 0x08, 0xB0, 0x45, + 0x80, 0x06, 0x80, 0x41, 0x80, 0x67, 0xF4, 0x03, 0x49, 0xFF, 0xF9, 0xCC, 0x00, 0x06, 0x00, 0x04, + 0xC0, 0x08, 0xB0, 0x45, 0x80, 0x06, 0x80, 0x41, 0x80, 0x67, 0xF4, 0x03, 0x49, 0xFF, 0xFA, 0x7E, + 0x00, 0x06, 0x00, 0x02, 0xC0, 0x07, 0xB0, 0x45, 0x80, 0x06, 0x80, 0x41, 0x80, 0x67, 0x49, 0xFF, + 0xFE, 0xBE, 0x22, 0x0F, 0x80, 0x0A, 0xB0, 0x45, 0x8C, 0x05, 0x40, 0x00, 0x2C, 0x16, 0x12, 0x0F, + 0x80, 0x0A, 0x22, 0x0F, 0x80, 0x0B, 0x80, 0x41, 0x8C, 0x05, 0x40, 0x00, 0x2C, 0x16, 0xEB, 0x9E, + 0x80, 0x67, 0x80, 0x06, 0x49, 0xFF, 0xFA, 0xC3, 0x22, 0x0F, 0x80, 0x0A, 0x4E, 0x04, 0x00, 0x04, + 0x12, 0x8F, 0x80, 0x0A, 0xEB, 0x06, 0x22, 0xFF, 0x80, 0x0A, 0x02, 0x10, 0x00, 0x09, 0xE0, 0x2F, + 0xE8, 0x03, 0x12, 0x1F, 0x80, 0x0A, 0x22, 0x1F, 0x80, 0x0B, 0x4E, 0x14, 0x00, 0x04, 0x12, 0x8F, + 0x80, 0x0B, 0x02, 0x00, 0x00, 0x0A, 0x22, 0xFF, 0x80, 0x0B, 0xE0, 0x0F, 0xE8, 0x02, 0xEB, 0x9E, + 0x02, 0x0F, 0x80, 0x0A, 0xEA, 0xBC, 0x02, 0x0F, 0x80, 0x0B, 0xEB, 0xEA, 0x8C, 0xE1, 0x50, 0x94, + 0x80, 0x54, 0x48, 0xFF, 0xFF, 0x75, 0x44, 0x40, 0x00, 0x54, 0x80, 0xA6, 0x42, 0x61, 0x90, 0x73, + 0x3C, 0x24, 0x00, 0x50, 0x3C, 0x14, 0x00, 0x51, 0x3C, 0x0D, 0xFB, 0x29, 0x80, 0x66, 0xD3, 0x0C, + 0xB4, 0x85, 0x5A, 0x48, 0x05, 0x07, 0x22, 0x22, 0x80, 0x04, 0x22, 0x12, 0x80, 0x05, 0x84, 0x00, + 0x50, 0x52, 0x80, 0x54, 0xD5, 0xF5, 0x3C, 0x28, 0x00, 0x50, 0x3C, 0x18, 0x00, 0x51, 0x3C, 0x0F, + 0xFB, 0x29, 0xFC, 0xE3, 0x3C, 0x0E, 0x00, 0x99, 0xDD, 0x9E, 0x3C, 0x0E, 0x00, 0x98, 0xDD, 0x9E, + 0x44, 0x02, 0xCE, 0x88, 0x84, 0x21, 0x3C, 0x0E, 0x00, 0x6D, 0x84, 0x00, 0x3E, 0x00, 0x01, 0xB8, + 0x3E, 0x00, 0x01, 0xB9, 0x3E, 0x00, 0x01, 0xBA, 0x3E, 0x00, 0x01, 0xBB, 0x3E, 0x00, 0x01, 0xBC, + 0xEB, 0xFD, 0x3E, 0x00, 0x01, 0xBE, 0x3E, 0x00, 0x01, 0x85, 0x3E, 0x00, 0x01, 0x84, 0x3E, 0x00, + 0x01, 0x86, 0x3C, 0x1F, 0xFB, 0x2A, 0x3E, 0x07, 0xF1, 0x23, 0x44, 0x12, 0xCE, 0x38, 0x84, 0x00, + 0x84, 0x5F, 0x38, 0x20, 0x80, 0x08, 0x8C, 0x01, 0x5A, 0x08, 0x4F, 0xFD, 0xDD, 0x9E, 0xFC, 0x00, + 0xEA, 0x68, 0xFC, 0x80, 0xFC, 0x00, 0x80, 0xC0, 0x49, 0xFF, 0x8C, 0x1D, 0xC0, 0x04, 0x84, 0x00, + 0xAE, 0x34, 0xAE, 0x35, 0xFC, 0x80, 0x2E, 0x00, 0x01, 0x8C, 0xDD, 0x9E, 0x2E, 0x00, 0x01, 0x81, + 0xDD, 0x9E, 0x44, 0x32, 0xCD, 0xFC, 0xAE, 0x18, 0xAE, 0x59, 0xAE, 0x9A, 0xDD, 0x9E, 0x3C, 0x0F, + 0xFB, 0x2A, 0xDD, 0x9E, 0x3C, 0x0D, 0xFB, 0x2A, 0xDD, 0x9E, 0x3C, 0x0D, 0xFC, 0x48, 0x46, 0x5F, + 0xF0, 0x0F, 0x50, 0x52, 0x8F, 0x00, 0xFF, 0x46, 0x46, 0x00, 0x10, 0x00, 0xD8, 0x06, 0x84, 0x00, + 0x3E, 0x07, 0xF1, 0x23, 0x84, 0x01, 0xDD, 0x9E, 0x84, 0x00, 0xDD, 0x9E, 0xFC, 0x02, 0x3C, 0x0C, + 0x03, 0xDC, 0x3C, 0x0E, 0x03, 0x9C, 0x3C, 0x0C, 0x03, 0xE2, 0x3C, 0x0E, 0x03, 0x9D, 0x3C, 0x0C, + 0x03, 0xE4, 0x3C, 0x0E, 0x03, 0xA3, 0x2E, 0x00, 0x0F, 0xEA, 0x3E, 0x00, 0x0E, 0x78, 0x2E, 0x00, + 0x0F, 0xB3, 0x3E, 0x00, 0x0E, 0x88, 0x3C, 0x00, 0x07, 0xE0, 0x3C, 0x08, 0x07, 0x3D, 0x2E, 0x00, + 0x08, 0x7B, 0x84, 0x20, 0xE2, 0x20, 0x3E, 0x10, 0x0E, 0x8A, 0x3C, 0x1C, 0x02, 0x1D, 0x3C, 0x1E, + 0x03, 0xA1, 0x2E, 0x10, 0x0A, 0x92, 0x3E, 0xF0, 0x0E, 0x89, 0x3C, 0x0C, 0x02, 0x1C, 0x3C, 0x0E, + 0x03, 0xA0, 0x44, 0x02, 0xDA, 0xE8, 0x5A, 0x18, 0x0E, 0x04, 0x84, 0x22, 0xD5, 0x02, 0x84, 0x21, + 0x3E, 0x10, 0x0E, 0x95, 0x44, 0x22, 0x8B, 0xA0, 0x2E, 0x17, 0xF2, 0xE7, 0xFA, 0x78, 0x80, 0x82, + 0x42, 0x40, 0x8C, 0x73, 0x3B, 0x00, 0x64, 0x00, 0x3B, 0x02, 0x64, 0x20, 0x2E, 0x47, 0xF2, 0xE7, + 0xF0, 0x81, 0x42, 0x22, 0x0C, 0x73, 0x84, 0x1F, 0xF0, 0x83, 0x12, 0x3F, 0x80, 0x00, 0xF2, 0x82, + 0xEB, 0xAB, 0xEA, 0xC7, 0xEA, 0x82, 0x84, 0x01, 0x3E, 0x07, 0xEF, 0x5D, 0x2E, 0x07, 0xF2, 0xE7, + 0xE6, 0x03, 0xE9, 0x03, 0x84, 0x00, 0xD5, 0x02, 0x8C, 0x01, 0x3E, 0x07, 0xF2, 0xE7, 0xFC, 0x82, + 0x2E, 0x10, 0x01, 0xBA, 0x2E, 0x50, 0x01, 0xBB, 0x3C, 0x0C, 0x00, 0x99, 0x4C, 0x12, 0xC0, 0x10, + 0x2E, 0x20, 0x01, 0xB8, 0x5A, 0x28, 0x01, 0x0C, 0xA6, 0x05, 0x9D, 0x49, 0x40, 0x02, 0x80, 0xB6, + 0x97, 0x68, 0x3E, 0x50, 0x01, 0xBA, 0x3E, 0x50, 0x01, 0xBB, 0xDD, 0x9E, 0xA6, 0x05, 0x8C, 0xA1, + 0x40, 0x02, 0x80, 0xB6, 0x97, 0x68, 0x3E, 0x50, 0x01, 0xBB, 0xD9, 0x04, 0x84, 0x01, 0x3E, 0x00, + 0x01, 0xB8, 0xDD, 0x9E, 0x2E, 0x50, 0x01, 0xBA, 0x2E, 0x10, 0x01, 0xBB, 0xD9, 0x04, 0x2E, 0x00, + 0x01, 0xB8, 0xC0, 0x10, 0x3C, 0x0C, 0x00, 0x99, 0x8C, 0xA1, 0xA6, 0x05, 0x40, 0x02, 0x80, 0xB6, + 0x97, 0x68, 0x3E, 0x50, 0x01, 0xBA, 0x4C, 0x12, 0xC0, 0x05, 0x84, 0x00, 0x3E, 0x00, 0x01, 0xB8, + 0x84, 0x01, 0xDD, 0x9E, 0x2E, 0x50, 0x01, 0xBA, 0x2E, 0x00, 0x01, 0xBB, 0xD8, 0x07, 0x2E, 0x00, + 0x01, 0xB8, 0x84, 0x20, 0x8E, 0x01, 0xEB, 0xFB, 0xDD, 0x9E, 0x84, 0x01, 0xDD, 0x9E, 0x2E, 0x50, + 0x01, 0xBA, 0x2E, 0x00, 0x01, 0xBB, 0xD8, 0x07, 0x2E, 0x10, 0x01, 0xB8, 0x84, 0x00, 0x40, 0x00, + 0x04, 0x06, 0xDD, 0x9E, 0x84, 0x01, 0xDD, 0x9E, 0xFC, 0x00, 0x84, 0xA0, 0x8C, 0x81, 0xE2, 0xA4, + 0xE8, 0x07, 0x38, 0x60, 0x08, 0x04, 0x38, 0x60, 0x8C, 0x0C, 0x8C, 0xA1, 0xD5, 0xF9, 0xFC, 0x80, + 0x80, 0x60, 0x3C, 0x0D, 0xFB, 0x2A, 0x9E, 0x41, 0xE6, 0x22, 0xE8, 0x26, 0x3C, 0x2C, 0x00, 0x98, + 0x84, 0x20, 0x00, 0x41, 0x00, 0x0A, 0xE2, 0x24, 0xE8, 0x09, 0xA1, 0x59, 0x38, 0x52, 0x87, 0x02, + 0x5A, 0x58, 0x01, 0x03, 0x84, 0x02, 0x8C, 0x21, 0xD5, 0xF7, 0xFC, 0x00, 0x84, 0x20, 0x00, 0x41, + 0x00, 0x09, 0x44, 0x50, 0x00, 0x54, 0xE2, 0x24, 0xE8, 0x0C, 0xB4, 0x43, 0x42, 0x20, 0x94, 0x73, + 0xB4, 0x42, 0x9F, 0x91, 0xE6, 0xC2, 0xE9, 0x06, 0x5A, 0x20, 0x04, 0x05, 0x8C, 0x21, 0xD5, 0xF4, + 0xFC, 0x80, 0x84, 0x01, 0xFC, 0x80, 0xDD, 0x9E, 0xFC, 0x61, 0x81, 0x41, 0xB4, 0xC1, 0x84, 0x3F, + 0x10, 0x1F, 0x80, 0x07, 0x2E, 0x17, 0x34, 0x08, 0x81, 0x60, 0xC1, 0x08, 0x2E, 0x10, 0x01, 0x8C, + 0xC9, 0x05, 0x49, 0xFF, 0xFF, 0xC7, 0x3C, 0x0F, 0xFB, 0x2A, 0x2E, 0x77, 0xF2, 0xD8, 0x4E, 0x73, + 0x01, 0x11, 0x3C, 0x3D, 0xFB, 0x2A, 0x5A, 0x30, 0x01, 0x04, 0x48, 0x00, 0x00, 0xAB, 0x3C, 0x0C, + 0x00, 0x98, 0x3D, 0x1C, 0x00, 0x99, 0x82, 0x03, 0x86, 0x7F, 0x44, 0xC0, 0x00, 0x54, 0x81, 0xA7, + 0x81, 0xC7, 0x85, 0x26, 0x86, 0x42, 0x50, 0x18, 0x7F, 0xFF, 0x00, 0x40, 0x00, 0x09, 0x96, 0x48, + 0xE2, 0x24, 0x84, 0x5F, 0x4E, 0xF2, 0x00, 0x91, 0xB4, 0xAB, 0x42, 0x50, 0xB0, 0x73, 0xB4, 0x25, + 0x9E, 0x89, 0xE6, 0x42, 0xE9, 0x05, 0x5A, 0x10, 0x04, 0x04, 0x48, 0x00, 0x00, 0x80, 0x00, 0x18, + 0x80, 0x00, 0x22, 0x22, 0x80, 0x04, 0xC1, 0x05, 0x02, 0x10, 0x00, 0x09, 0x8E, 0x21, 0x9A, 0x8A, + 0x00, 0x18, 0x80, 0x01, 0x22, 0x42, 0x80, 0x05, 0xC1, 0x05, 0x02, 0x10, 0x00, 0x0A, 0x8E, 0x21, + 0x9B, 0x0C, 0x00, 0x18, 0x80, 0x03, 0x02, 0x80, 0x00, 0x02, 0x03, 0x40, 0x00, 0x03, 0xC1, 0x23, + 0x02, 0x10, 0x00, 0x09, 0x00, 0xF8, 0x80, 0x02, 0x8E, 0x21, 0xE9, 0x0A, 0x51, 0x54, 0x7F, 0xFF, + 0x40, 0xF0, 0xC9, 0xF6, 0x42, 0xF1, 0x54, 0x73, 0x40, 0x27, 0x84, 0x56, 0xD5, 0x14, 0x51, 0x5A, + 0x7F, 0xFF, 0x40, 0xF0, 0xC9, 0xF6, 0x42, 0xF1, 0x54, 0x73, 0x51, 0x54, 0x7F, 0xFF, 0x40, 0x27, + 0x84, 0x56, 0x02, 0x10, 0x00, 0x0A, 0x8E, 0x21, 0x40, 0xF0, 0xC9, 0xF6, 0x42, 0xF2, 0x54, 0x73, + 0x40, 0x47, 0x84, 0x96, 0xE0, 0x48, 0xE9, 0x03, 0x50, 0x24, 0x7F, 0xFF, 0xE0, 0x94, 0x42, 0x21, + 0x34, 0x00, 0xE9, 0x03, 0x50, 0x4A, 0x7F, 0xFF, 0x80, 0x26, 0x42, 0x13, 0xA4, 0x73, 0x85, 0x02, + 0x40, 0x84, 0x40, 0x64, 0x10, 0x80, 0x80, 0x00, 0x01, 0x48, 0x80, 0x02, 0x42, 0x42, 0x38, 0x00, + 0x40, 0x81, 0x10, 0x0A, 0x40, 0xF2, 0x10, 0x0A, 0x4F, 0x43, 0x00, 0x0A, 0x97, 0x1F, 0x10, 0x80, + 0x80, 0x01, 0x10, 0xF0, 0x80, 0x02, 0x40, 0x22, 0x08, 0x84, 0xD5, 0x08, 0x96, 0x9F, 0x10, 0xF0, + 0x80, 0x01, 0x10, 0x80, 0x80, 0x02, 0x40, 0x21, 0x10, 0x84, 0xAE, 0x8B, 0x02, 0x12, 0x80, 0x0C, + 0xC1, 0x03, 0x96, 0x48, 0xD5, 0x02, 0x84, 0x21, 0x80, 0x46, 0x42, 0x23, 0xA4, 0x73, 0xAE, 0x54, + 0x02, 0x12, 0x80, 0x0D, 0xC1, 0x03, 0x96, 0x48, 0xD5, 0x02, 0x84, 0x21, 0x8C, 0xE1, 0xAE, 0x55, + 0x97, 0xF8, 0x11, 0x33, 0x00, 0x3C, 0x11, 0x33, 0x00, 0x3D, 0x50, 0x18, 0x00, 0x01, 0x55, 0x00, + 0x80, 0xFF, 0x48, 0xFF, 0xFF, 0x6A, 0x10, 0x23, 0x00, 0x3E, 0x10, 0x23, 0x00, 0x3F, 0xD5, 0x2D, + 0x2E, 0x20, 0x01, 0x84, 0xC2, 0x14, 0x2E, 0x00, 0x01, 0x85, 0xA6, 0x70, 0xE6, 0x1E, 0xE8, 0x05, + 0x96, 0x57, 0x40, 0x00, 0x80, 0x64, 0xD5, 0x03, 0x44, 0x00, 0x00, 0xF0, 0xAE, 0x30, 0x2E, 0x00, + 0x01, 0x86, 0xAE, 0x32, 0x84, 0x01, 0xAE, 0xB1, 0x3E, 0x00, 0x01, 0x8C, 0x5A, 0x30, 0x03, 0x04, + 0x84, 0xE0, 0xD5, 0x13, 0x84, 0x00, 0x44, 0x42, 0xD4, 0xBC, 0xB4, 0x2A, 0x38, 0x22, 0x00, 0x01, + 0x88, 0x20, 0xAE, 0x8B, 0x38, 0x22, 0x00, 0x01, 0xB4, 0x2A, 0x92, 0x48, 0x88, 0x20, 0x8C, 0x02, + 0xAE, 0x8C, 0x5A, 0x08, 0x28, 0xF4, 0xD5, 0xED, 0x2E, 0x00, 0x01, 0x8C, 0x5A, 0x00, 0xFF, 0x0D, + 0xC0, 0x0B, 0xCF, 0x0A, 0x84, 0x1F, 0x3E, 0x00, 0x01, 0x8C, 0x3C, 0x0C, 0x00, 0x62, 0x8C, 0x01, + 0x3C, 0x0E, 0x00, 0x62, 0xD5, 0x03, 0x3E, 0x70, 0x01, 0x8C, 0x5A, 0x38, 0x01, 0x15, 0x3C, 0x0C, + 0x00, 0x98, 0x00, 0x40, 0x00, 0x09, 0xE2, 0xE4, 0xE8, 0x0E, 0x84, 0x26, 0x84, 0x06, 0xFE, 0x7C, + 0x8A, 0x87, 0xB4, 0x4A, 0xFF, 0x04, 0x96, 0x48, 0x88, 0x22, 0x50, 0x0F, 0x80, 0x07, 0x84, 0x40, + 0x8E, 0x81, 0xF9, 0x66, 0xB4, 0x0A, 0x84, 0x20, 0x80, 0xA0, 0x50, 0x20, 0x00, 0x40, 0x08, 0x32, + 0x80, 0x01, 0x88, 0x23, 0x96, 0x48, 0xDA, 0xFC, 0xFE, 0x4A, 0x10, 0x10, 0x00, 0x40, 0xD5, 0x02, + 0x84, 0xE0, 0x2E, 0x97, 0xF2, 0xD7, 0x4E, 0x93, 0x01, 0x14, 0x05, 0x05, 0x80, 0x03, 0xB4, 0x10, + 0x9E, 0x41, 0xE6, 0x22, 0xE9, 0x05, 0x5A, 0x00, 0x04, 0x04, 0x48, 0x00, 0x00, 0xDB, 0x3C, 0x4C, + 0x00, 0x99, 0x84, 0x00, 0xA6, 0x60, 0x3E, 0x00, 0x01, 0x80, 0x22, 0x08, 0x00, 0x02, 0xC1, 0x04, + 0x52, 0x50, 0x0E, 0xFF, 0xD5, 0x02, 0x80, 0xA0, 0xA6, 0x21, 0x22, 0x28, 0x00, 0x03, 0xC0, 0x03, + 0x52, 0x21, 0x17, 0x6F, 0xA6, 0x23, 0xC0, 0x22, 0xA6, 0x22, 0x44, 0x30, 0x0E, 0xFF, 0xC8, 0x0D, + 0x44, 0x10, 0x0C, 0x7F, 0x42, 0x02, 0x84, 0x24, 0x44, 0x10, 0x13, 0xFF, 0x50, 0x00, 0x07, 0x7F, + 0x40, 0x50, 0x0C, 0xB6, 0xFE, 0x8C, 0xD5, 0x0C, 0x44, 0x10, 0x13, 0xFF, 0x42, 0x02, 0x84, 0x24, + 0x50, 0x00, 0x07, 0x7F, 0x40, 0x50, 0x0C, 0xB6, 0x44, 0x00, 0x0C, 0x7F, 0xFE, 0x84, 0x50, 0x21, + 0x0B, 0xB7, 0x44, 0x00, 0x17, 0x6F, 0x40, 0x21, 0x00, 0x56, 0x5E, 0xF2, 0x8C, 0x80, 0xE8, 0x05, + 0x84, 0x00, 0x42, 0x52, 0x80, 0x00, 0xD5, 0x03, 0x44, 0x50, 0x0C, 0x7F, 0x5E, 0xF1, 0x14, 0x00, + 0xE8, 0x05, 0x84, 0x00, 0x42, 0x21, 0x00, 0x00, 0xD5, 0x03, 0x44, 0x20, 0x13, 0xFF, 0x00, 0x08, + 0x00, 0x08, 0x84, 0x61, 0x5A, 0x08, 0x01, 0x04, 0x44, 0x30, 0x00, 0xF0, 0x10, 0x33, 0x00, 0x41, + 0x04, 0x15, 0x80, 0x03, 0x5A, 0x38, 0xF0, 0x2C, 0x84, 0x00, 0x10, 0x00, 0x80, 0x08, 0x04, 0x15, + 0x80, 0x03, 0x44, 0x20, 0xFF, 0x00, 0xA0, 0x0C, 0xA0, 0xCD, 0x40, 0x10, 0x08, 0x02, 0x92, 0x28, + 0x10, 0x13, 0x00, 0x42, 0x40, 0x10, 0x60, 0x09, 0x10, 0x13, 0x00, 0x44, 0x46, 0x10, 0x0F, 0xF0, + 0x10, 0x03, 0x00, 0x43, 0xFE, 0x0E, 0x92, 0x10, 0xFE, 0x9E, 0xFE, 0x5E, 0x10, 0x03, 0x00, 0x45, + 0x92, 0x48, 0x40, 0x01, 0xE0, 0x09, 0x92, 0x30, 0x10, 0x23, 0x00, 0x46, 0x10, 0x33, 0x00, 0x47, + 0x10, 0x03, 0x00, 0x48, 0x10, 0x13, 0x00, 0x49, 0x84, 0x89, 0xD5, 0x4E, 0xA6, 0x22, 0x40, 0x32, + 0xA0, 0x0A, 0x40, 0x41, 0x20, 0x0A, 0xC8, 0x0A, 0x10, 0x33, 0x00, 0x42, 0x10, 0x53, 0x00, 0x43, + 0x10, 0x43, 0x00, 0x44, 0x10, 0x23, 0x00, 0x45, 0xD5, 0x09, 0x10, 0x43, 0x00, 0x42, 0x10, 0x23, + 0x00, 0x43, 0x10, 0x33, 0x00, 0x44, 0x10, 0x53, 0x00, 0x45, 0x00, 0x00, 0x80, 0x18, 0x5A, 0x08, + 0x01, 0x06, 0x84, 0x00, 0x10, 0x03, 0x00, 0x46, 0xD5, 0x06, 0xA4, 0x0D, 0x40, 0x20, 0x20, 0x09, + 0x10, 0x23, 0x00, 0x46, 0x10, 0x03, 0x00, 0x47, 0x02, 0x00, 0x80, 0x0E, 0x10, 0x03, 0x00, 0x48, + 0x84, 0x60, 0x02, 0x00, 0x80, 0x0F, 0x10, 0x03, 0x00, 0x49, 0x10, 0x33, 0x00, 0x4A, 0x00, 0x00, + 0x80, 0x18, 0x10, 0x03, 0x00, 0x4B, 0x00, 0x00, 0x80, 0x19, 0x84, 0x8D, 0x96, 0x84, 0x00, 0x03, + 0x00, 0x4C, 0x66, 0x00, 0x00, 0x01, 0xFE, 0x17, 0x10, 0x03, 0x00, 0x4C, 0x00, 0x00, 0x80, 0x1A, + 0x10, 0x33, 0x00, 0x4D, 0x96, 0x44, 0x00, 0x03, 0x00, 0x4C, 0xEA, 0xA0, 0x40, 0x00, 0x04, 0x24, + 0x96, 0x0F, 0x10, 0x03, 0x00, 0x4C, 0xB4, 0x4A, 0x50, 0x12, 0x00, 0x41, 0x88, 0x22, 0x50, 0x0F, + 0x80, 0x07, 0x84, 0x40, 0x84, 0x61, 0x52, 0x42, 0x00, 0x0D, 0xF8, 0x72, 0x84, 0x41, 0xD5, 0x0B, + 0xB4, 0x2A, 0x80, 0x49, 0x50, 0x0F, 0x80, 0x07, 0x50, 0x10, 0x80, 0x41, 0x84, 0x61, 0x84, 0x8D, + 0xF8, 0x67, 0x80, 0x49, 0xB4, 0x2A, 0x84, 0x00, 0x50, 0x50, 0x80, 0x41, 0x50, 0x30, 0x80, 0x4E, + 0x08, 0x42, 0x80, 0x01, 0x88, 0x04, 0x96, 0x00, 0xDB, 0xFC, 0xFE, 0x02, 0x10, 0x00, 0x80, 0x4E, + 0x2E, 0x00, 0x01, 0x81, 0x5A, 0x00, 0xFF, 0x0F, 0xC8, 0x05, 0x2E, 0x00, 0x01, 0x80, 0x5A, 0x08, + 0x01, 0x0A, 0xCA, 0x08, 0x84, 0x1F, 0x3E, 0x00, 0x01, 0x81, 0x84, 0x02, 0x3E, 0x00, 0x01, 0x80, + 0xD5, 0x07, 0x3E, 0x20, 0x01, 0x81, 0xCF, 0x05, 0xCA, 0x04, 0x84, 0x01, 0xD5, 0x03, 0xC7, 0xFE, + 0x84, 0x00, 0x3E, 0x00, 0x01, 0xBE, 0xFC, 0xE1, 0xFC, 0x00, 0x84, 0x41, 0x80, 0x62, 0x44, 0x40, + 0x00, 0x4E, 0xF8, 0x36, 0xFC, 0x80, 0xA6, 0x00, 0x92, 0x03, 0x8C, 0x15, 0x96, 0x27, 0x5C, 0x00, + 0x00, 0x14, 0xDD, 0x9E, 0xFC, 0x40, 0x80, 0xE0, 0x84, 0x00, 0xEB, 0xFD, 0xA6, 0x38, 0x80, 0xC1, + 0xC0, 0x04, 0x2E, 0x07, 0xF2, 0xD8, 0xC0, 0x07, 0x00, 0x03, 0x80, 0x08, 0xC0, 0x31, 0x2E, 0x07, + 0xF2, 0xD7, 0xC8, 0x2E, 0x2E, 0x00, 0x01, 0xB9, 0x5A, 0x08, 0x01, 0x0C, 0x2E, 0x10, 0x01, 0xBC, + 0x3E, 0x10, 0x01, 0xBA, 0x3E, 0x10, 0x01, 0xBB, 0x84, 0x20, 0x3E, 0x10, 0x01, 0xB8, 0xEB, 0xFD, + 0x49, 0xFF, 0xFD, 0x08, 0x2E, 0x90, 0x01, 0xBB, 0x3C, 0x1C, 0x00, 0x6D, 0x44, 0x20, 0x00, 0x4F, + 0x42, 0x14, 0x88, 0x73, 0x84, 0x41, 0xA0, 0x39, 0x80, 0x62, 0x44, 0x40, 0x00, 0x4E, 0x49, 0xFF, + 0xFD, 0x4D, 0x2E, 0x00, 0x01, 0xBE, 0x5A, 0x08, 0x01, 0x06, 0x3E, 0x00, 0x01, 0xB9, 0x3E, 0x90, + 0x01, 0xBC, 0x2E, 0x00, 0x01, 0x82, 0x5A, 0x00, 0xFF, 0x07, 0x8C, 0x01, 0xD5, 0x02, 0x84, 0x00, + 0x3E, 0x00, 0x01, 0x82, 0x2E, 0x10, 0x01, 0xBD, 0xB4, 0x06, 0x5A, 0x18, 0x01, 0x2A, 0xA6, 0x05, + 0xC8, 0x14, 0xF8, 0x35, 0xC8, 0x0D, 0x2E, 0x30, 0x01, 0xBC, 0xB4, 0x26, 0x44, 0x20, 0x00, 0x4F, + 0x3C, 0x0C, 0x00, 0x6D, 0x42, 0x01, 0x88, 0x73, 0xB4, 0x21, 0xF8, 0x39, 0xD5, 0x08, 0x49, 0xFF, + 0x88, 0x3B, 0xF8, 0x25, 0xC8, 0xFF, 0xD5, 0xF0, 0xF8, 0x22, 0xC8, 0x02, 0xEB, 0x6C, 0xB4, 0x26, + 0x84, 0x00, 0xEB, 0xFD, 0x3E, 0x00, 0x01, 0xB9, 0x84, 0x01, 0xAE, 0x0D, 0xB4, 0x26, 0xAE, 0x0C, + 0xB4, 0xC6, 0xB4, 0x06, 0xF8, 0x34, 0x5A, 0x08, 0x01, 0x3C, 0xAE, 0x37, 0xD5, 0x39, 0xA6, 0x44, + 0xC9, 0x04, 0xF8, 0x67, 0xC0, 0x35, 0xD5, 0x0B, 0xA6, 0x05, 0x5A, 0x08, 0x01, 0x06, 0xF8, 0x07, + 0xC8, 0x2F, 0xEB, 0x6C, 0xD5, 0x2D, 0x49, 0xFF, 0xFC, 0xE7, 0xC8, 0xFA, 0x49, 0xFF, 0x88, 0x47, + 0x80, 0xE0, 0xC8, 0x26, 0x49, 0xFF, 0xFC, 0xC8, 0x2E, 0x90, 0x01, 0xBA, 0xB4, 0x26, 0x3C, 0x0C, + 0x00, 0x6D, 0x44, 0x20, 0x00, 0x4F, 0xB4, 0x21, 0x42, 0x04, 0x88, 0x73, 0x49, 0xFF, 0xFF, 0x66, + 0x2E, 0x10, 0x01, 0xB9, 0x5A, 0x18, 0x01, 0x11, 0x2E, 0x50, 0x01, 0xBC, 0x4C, 0x54, 0xC0, 0x0D, + 0xB4, 0x06, 0x3E, 0x70, 0x01, 0xB9, 0xAE, 0x45, 0xB4, 0xE6, 0xB4, 0x07, 0x49, 0xFF, 0xFF, 0x5D, + 0x5A, 0x08, 0x01, 0x03, 0xAE, 0x3F, 0xEB, 0x6C, 0xB4, 0x06, 0x84, 0x21, 0xAE, 0x44, 0xFC, 0xC0, + 0xFC, 0x20, 0x80, 0x40, 0x80, 0xE1, 0x44, 0x02, 0xCE, 0x1C, 0xA0, 0x51, 0xB6, 0x20, 0x2E, 0x10, + 0x01, 0x8C, 0xEB, 0xDF, 0xA0, 0x52, 0xA8, 0x41, 0x2E, 0x10, 0x01, 0x81, 0x10, 0x10, 0x00, 0x09, + 0xA0, 0x54, 0x44, 0x62, 0xCE, 0x38, 0xA8, 0x43, 0x44, 0x12, 0xCE, 0x18, 0x3C, 0x6E, 0x00, 0x68, + 0x49, 0xFF, 0xFC, 0xF4, 0x44, 0x02, 0xCE, 0x0C, 0x2E, 0x10, 0x01, 0x8C, 0xAE, 0x40, 0x2E, 0x10, + 0x01, 0x81, 0xEB, 0xDF, 0xB4, 0x27, 0x3C, 0x1E, 0x00, 0x64, 0x44, 0x12, 0xCE, 0x08, 0xA9, 0x81, + 0x49, 0xFF, 0xFF, 0x32, 0x84, 0x20, 0x44, 0x02, 0xCD, 0xFC, 0xAE, 0x40, 0xAE, 0x41, 0xAE, 0x42, + 0x49, 0xFF, 0xFC, 0x97, 0xFC, 0xA0, 0x3C, 0x0E, 0x01, 0x5F, 0xDD, 0x9E, 0x3C, 0x0E, 0x01, 0x5E, + 0xDD, 0x9E, 0xFC, 0x60, 0x51, 0xFF, 0xF8, 0x40, 0xF3, 0x86, 0x50, 0x6F, 0x81, 0x30, 0x84, 0x60, + 0xF1, 0x82, 0xF2, 0x85, 0x3C, 0x5C, 0x01, 0x5E, 0x80, 0x26, 0x86, 0x01, 0x82, 0x23, 0xF2, 0x02, + 0xF2, 0x83, 0xE2, 0x62, 0xE8, 0x28, 0x22, 0x40, 0x00, 0x00, 0x22, 0x20, 0x00, 0x01, 0xAD, 0x0E, + 0x12, 0x40, 0x80, 0x08, 0xF4, 0x06, 0xAC, 0x8F, 0x12, 0x20, 0x80, 0x09, 0xA0, 0x81, 0xA1, 0x24, + 0x14, 0x20, 0x80, 0x09, 0x40, 0x22, 0x08, 0x20, 0xA7, 0xD1, 0xC7, 0x0B, 0xA7, 0x2A, 0x8E, 0x81, + 0x4C, 0x72, 0x00, 0x08, 0xA7, 0x10, 0xC4, 0x05, 0xA6, 0xAB, 0x8E, 0x41, 0x4C, 0x41, 0x40, 0x05, + 0x11, 0x00, 0x80, 0x2D, 0xD5, 0x03, 0x11, 0x10, 0x80, 0x2D, 0x8C, 0x61, 0x50, 0x10, 0x80, 0x34, + 0x8C, 0x08, 0xD5, 0xD6, 0x2E, 0x10, 0x05, 0x74, 0x84, 0x00, 0xF1, 0x81, 0x50, 0xEF, 0x80, 0x40, + 0x80, 0x40, 0x51, 0x2F, 0x80, 0x7C, 0x51, 0x1F, 0x80, 0xB8, 0x51, 0x0F, 0x80, 0xF4, 0x44, 0x70, + 0x00, 0x34, 0x44, 0x42, 0xCE, 0xE0, 0x42, 0x30, 0x1C, 0x24, 0x38, 0x27, 0x02, 0x0A, 0x99, 0x73, + 0x38, 0x29, 0x02, 0x0A, 0x38, 0x28, 0x82, 0x0A, 0x38, 0x28, 0x02, 0x0A, 0x88, 0x64, 0x8C, 0x01, + 0x10, 0x22, 0x80, 0x22, 0x10, 0x21, 0x80, 0x22, 0x44, 0xC2, 0xCE, 0xE0, 0x5A, 0x08, 0x0F, 0xED, + 0x3C, 0x3C, 0x01, 0x5F, 0x84, 0x00, 0x44, 0x50, 0x00, 0x54, 0x44, 0x70, 0x00, 0x34, 0xE2, 0x01, + 0xE8, 0x11, 0xF2, 0x05, 0x42, 0x20, 0x14, 0x73, 0x00, 0x21, 0x00, 0x1C, 0x96, 0x96, 0xC2, 0x08, + 0xA7, 0x19, 0x80, 0x4C, 0x42, 0x20, 0x1C, 0x73, 0x8C, 0x81, 0x10, 0x41, 0x00, 0x20, 0x8C, 0x01, + 0xD5, 0xEF, 0x44, 0x00, 0x00, 0x3C, 0xFE, 0x0C, 0xF0, 0x84, 0xF0, 0x02, 0x51, 0x1F, 0x84, 0x3C, + 0xE2, 0x01, 0x82, 0x06, 0x85, 0x60, 0x14, 0xFF, 0x80, 0x07, 0x86, 0xFF, 0x47, 0xE1, 0x00, 0x00, + 0x86, 0xCA, 0x47, 0x99, 0x00, 0x00, 0x45, 0x50, 0x00, 0x64, 0xF0, 0x02, 0xE3, 0x60, 0x4E, 0xF2, + 0x00, 0xE1, 0x84, 0x01, 0x38, 0x07, 0x2E, 0x0A, 0x84, 0xE0, 0x44, 0x02, 0xCE, 0xE0, 0xF2, 0x04, + 0x4C, 0x71, 0x00, 0xD2, 0xF2, 0x07, 0x22, 0x48, 0x00, 0x08, 0xC2, 0x09, 0x22, 0x20, 0x00, 0x0A, + 0x22, 0x50, 0x00, 0x0B, 0x8A, 0x82, 0x22, 0x28, 0x00, 0x09, 0xD5, 0x08, 0x22, 0x20, 0x00, 0x08, + 0x22, 0x50, 0x00, 0x09, 0x8A, 0x82, 0x22, 0x28, 0x00, 0x09, 0x8A, 0x45, 0xFE, 0x94, 0x42, 0x22, + 0x10, 0x73, 0x23, 0x88, 0x00, 0x08, 0x22, 0x40, 0x00, 0x08, 0x23, 0x48, 0x00, 0x09, 0x41, 0x3C, + 0x10, 0x01, 0x22, 0x40, 0x00, 0x09, 0x04, 0x80, 0x00, 0x07, 0x40, 0x9A, 0x10, 0x01, 0x42, 0x54, + 0xA4, 0x24, 0x42, 0x59, 0xCC, 0x73, 0xB4, 0x80, 0x5A, 0x88, 0x04, 0x07, 0x01, 0x20, 0x00, 0x20, + 0x5B, 0x28, 0x01, 0x03, 0xF8, 0x91, 0x04, 0xF0, 0x00, 0x0A, 0xE9, 0x5D, 0x05, 0x21, 0x80, 0x01, + 0xE2, 0xB2, 0x4E, 0xF3, 0x00, 0x8C, 0x02, 0xF1, 0x80, 0x01, 0x42, 0xF2, 0x3C, 0x24, 0xE2, 0xAF, + 0xE8, 0x33, 0x05, 0x21, 0x80, 0x02, 0xE2, 0xB2, 0xE8, 0x0C, 0x22, 0x40, 0x00, 0x05, 0x22, 0xA0, + 0x00, 0x04, 0x42, 0x44, 0x90, 0x24, 0x42, 0x49, 0xA8, 0x73, 0x4E, 0x46, 0x00, 0x78, 0xD5, 0x24, + 0x05, 0x21, 0x80, 0x03, 0xE2, 0xB2, 0xE8, 0x20, 0x23, 0x20, 0x00, 0x05, 0x22, 0xA0, 0x00, 0x04, + 0x43, 0x24, 0xC8, 0x24, 0x43, 0x29, 0xA8, 0x73, 0x44, 0x90, 0x27, 0x10, 0x43, 0x39, 0x54, 0x24, + 0x41, 0x39, 0x92, 0x77, 0x43, 0x39, 0xCC, 0x24, 0x43, 0x39, 0x90, 0x24, 0x40, 0xF9, 0xA5, 0xF7, + 0x00, 0x91, 0x80, 0x27, 0x42, 0x92, 0xA4, 0x24, 0x40, 0x94, 0xD5, 0x37, 0xE3, 0x2F, 0xE8, 0x04, + 0x4F, 0x27, 0x00, 0x03, 0xCC, 0x53, 0x00, 0x40, 0x00, 0x21, 0x01, 0x21, 0x80, 0x00, 0xE3, 0xC4, + 0xE8, 0x04, 0xA1, 0x1C, 0xE2, 0xA4, 0xE9, 0x4A, 0x00, 0x41, 0x80, 0x26, 0x4E, 0x42, 0x02, 0xF9, + 0xA1, 0x1B, 0xFF, 0x24, 0xE2, 0xA4, 0x4E, 0xF2, 0x02, 0xF4, 0x5A, 0x88, 0x04, 0x03, 0xF8, 0x3C, + 0x00, 0x48, 0x00, 0x2D, 0x4E, 0x43, 0x02, 0xED, 0x00, 0x40, 0x00, 0x2D, 0x4E, 0x43, 0x02, 0xE9, + 0x88, 0x59, 0xD5, 0x3A, 0x5A, 0xF0, 0x02, 0x03, 0xF8, 0x2F, 0x5A, 0x88, 0x04, 0x03, 0xF8, 0x2C, + 0x04, 0xF1, 0x80, 0x01, 0x22, 0xA0, 0x00, 0x0A, 0xE2, 0xAF, 0x22, 0xD0, 0x00, 0x04, 0x22, 0x40, + 0x00, 0x0B, 0x23, 0x20, 0x00, 0x05, 0xE9, 0x22, 0x00, 0x51, 0x80, 0x28, 0x88, 0x92, 0x42, 0x86, + 0x94, 0x24, 0x42, 0x59, 0x14, 0x24, 0x40, 0x84, 0x59, 0x16, 0x40, 0x52, 0xD8, 0xB6, 0x40, 0x4A, + 0x10, 0x01, 0x89, 0x4D, 0x40, 0xAC, 0x28, 0x01, 0xFF, 0x24, 0xFF, 0x6C, 0x42, 0x45, 0x28, 0x73, + 0x42, 0x54, 0x20, 0x73, 0xE0, 0x85, 0x4E, 0xF2, 0x02, 0xBC, 0x42, 0x44, 0xC8, 0x24, 0x42, 0x49, + 0xB4, 0x73, 0x4E, 0x46, 0x02, 0xBA, 0x48, 0x00, 0x02, 0xB4, 0x5A, 0x88, 0x03, 0x06, 0x00, 0x40, + 0x00, 0x2C, 0xCC, 0x02, 0x88, 0x5E, 0x38, 0x28, 0x9C, 0x0A, 0x50, 0x73, 0x80, 0x3C, 0xEB, 0x0A, + 0x48, 0xFF, 0xFF, 0x2F, 0x8D, 0x61, 0x8D, 0xA4, 0x51, 0x08, 0x00, 0x34, 0x48, 0xFF, 0xFF, 0x1F, + 0x84, 0x00, 0x84, 0x41, 0xE2, 0x01, 0xE8, 0x06, 0xB0, 0xDF, 0x38, 0x21, 0x82, 0x0A, 0x8C, 0x01, + 0xD5, 0xFA, 0xF0, 0x02, 0xE6, 0x0B, 0xE8, 0x0B, 0xE6, 0x2B, 0xE8, 0x09, 0x80, 0x4E, 0xB0, 0xDF, + 0x50, 0x4F, 0x84, 0x3C, 0xB1, 0x48, 0x49, 0x00, 0x02, 0xDF, 0xD5, 0x09, 0xF0, 0x02, 0x80, 0x4E, + 0xB0, 0xDF, 0x50, 0x4F, 0x84, 0x3C, 0xB1, 0x48, 0x49, 0x00, 0x02, 0x93, 0x47, 0xE8, 0xFF, 0xFF, + 0x50, 0x3F, 0x0F, 0xFF, 0x84, 0x20, 0x44, 0x20, 0x00, 0x34, 0x3C, 0x4C, 0x01, 0x5F, 0x82, 0x61, + 0x44, 0xD2, 0xCE, 0xE0, 0x86, 0xEF, 0xF3, 0x84, 0x82, 0x82, 0x51, 0x9F, 0x80, 0xF4, 0x85, 0x01, + 0x51, 0x8F, 0x80, 0xB8, 0x86, 0xA2, 0x87, 0xC3, 0xE3, 0xE0, 0x44, 0xB2, 0xCE, 0xE0, 0x4E, 0xF2, + 0x01, 0x02, 0xB0, 0xC8, 0x40, 0x31, 0xCC, 0x20, 0xA6, 0xD9, 0x80, 0xAD, 0x42, 0x51, 0x88, 0x73, + 0x04, 0x52, 0x80, 0x0A, 0x5A, 0x58, 0x02, 0x12, 0xB1, 0x48, 0x38, 0x52, 0xCD, 0x00, 0x42, 0x51, + 0xDC, 0x73, 0x50, 0x7F, 0x84, 0x3C, 0x38, 0x53, 0x96, 0x02, 0x4E, 0x55, 0x00, 0x07, 0xB1, 0x5F, + 0x38, 0x82, 0x8E, 0x0A, 0x48, 0x00, 0x00, 0xE4, 0x80, 0xEC, 0x42, 0x71, 0x88, 0x73, 0xB1, 0x48, + 0x38, 0x52, 0xCD, 0x00, 0x01, 0x13, 0x80, 0x2E, 0x80, 0xE6, 0x42, 0x72, 0x88, 0x73, 0x04, 0xAF, + 0x80, 0x06, 0x51, 0x03, 0x80, 0x28, 0x50, 0x73, 0x80, 0x20, 0x04, 0x93, 0x80, 0x01, 0x05, 0x25, + 0x00, 0x03, 0x11, 0x18, 0x00, 0x06, 0x38, 0xF9, 0x25, 0x01, 0x02, 0x92, 0x00, 0x15, 0xE3, 0x2F, + 0xE8, 0x0C, 0x4F, 0x13, 0x00, 0x0B, 0x01, 0x13, 0x80, 0x02, 0x59, 0x18, 0x80, 0x01, 0x11, 0x13, + 0x80, 0x02, 0x84, 0xE1, 0x10, 0x78, 0x00, 0x06, 0x81, 0x26, 0x42, 0x92, 0x88, 0x73, 0x81, 0x4C, + 0x42, 0xA1, 0x88, 0x73, 0x50, 0xF4, 0x80, 0x10, 0x22, 0x77, 0x80, 0x01, 0x23, 0x05, 0x00, 0x09, + 0x23, 0x14, 0x80, 0x08, 0x40, 0xB3, 0xC0, 0x01, 0x97, 0xF9, 0x41, 0x03, 0xC0, 0x01, 0x23, 0x25, + 0x00, 0x08, 0x41, 0x08, 0x00, 0x13, 0x88, 0xF0, 0x41, 0x68, 0xC8, 0x01, 0x12, 0x77, 0x80, 0x03, + 0x42, 0xB5, 0xAC, 0x24, 0x80, 0xE5, 0x42, 0xBB, 0x58, 0x73, 0x41, 0x18, 0x80, 0x13, 0x82, 0xC9, + 0x42, 0x71, 0xDC, 0x73, 0x1C, 0xBB, 0x00, 0x02, 0x41, 0x28, 0xC8, 0x01, 0x50, 0xBF, 0x84, 0x3C, + 0x41, 0x29, 0x00, 0x13, 0x38, 0x75, 0x9E, 0x02, 0x04, 0xBF, 0x80, 0x04, 0x89, 0xB2, 0x13, 0x17, + 0x80, 0x02, 0xE3, 0x67, 0x13, 0x24, 0x80, 0x04, 0x13, 0x0B, 0x00, 0x01, 0xE8, 0x0D, 0x8D, 0x48, + 0x02, 0x75, 0x00, 0x02, 0x12, 0x7B, 0x00, 0x02, 0x02, 0x75, 0x00, 0x03, 0x15, 0x54, 0x80, 0x0A, + 0x12, 0x7B, 0x00, 0x03, 0xD5, 0x04, 0x84, 0xE0, 0x14, 0x74, 0x80, 0x0A, 0x80, 0xE6, 0x82, 0x0C, + 0x42, 0x72, 0x88, 0x73, 0x43, 0x01, 0x88, 0x73, 0x50, 0x93, 0x80, 0x08, 0x51, 0x28, 0x00, 0x08, + 0x02, 0xA9, 0x00, 0x02, 0x03, 0x14, 0x80, 0x02, 0x03, 0x29, 0x00, 0x03, 0x8B, 0xAA, 0x13, 0x13, + 0x80, 0x02, 0x03, 0x14, 0x80, 0x03, 0x8B, 0xB2, 0x01, 0x28, 0x00, 0x18, 0x11, 0x23, 0x80, 0x18, + 0x05, 0x28, 0x00, 0x07, 0x13, 0x13, 0x80, 0x03, 0x51, 0x13, 0x80, 0x18, 0x5B, 0x28, 0x03, 0x17, + 0x01, 0x13, 0x80, 0x2E, 0x01, 0x08, 0x00, 0x20, 0x5B, 0x18, 0x01, 0x03, 0x8F, 0x81, 0x11, 0x03, + 0x80, 0x20, 0x80, 0xE6, 0x42, 0x72, 0x88, 0x73, 0x81, 0x28, 0x01, 0x03, 0x80, 0x20, 0x8C, 0xF8, + 0x40, 0x9F, 0x40, 0x1B, 0x14, 0x93, 0x80, 0x01, 0xD5, 0x03, 0x15, 0x58, 0x80, 0x01, 0x80, 0xED, + 0x42, 0x71, 0x88, 0x73, 0x00, 0x73, 0x80, 0x2C, 0x5C, 0xF3, 0x80, 0xC8, 0xE8, 0x03, 0x8C, 0xE1, + 0x97, 0xF8, 0x82, 0x26, 0x43, 0x12, 0xD0, 0x73, 0x10, 0x78, 0x80, 0x2C, 0x80, 0xEC, 0x42, 0x71, + 0xD0, 0x73, 0x51, 0x08, 0x80, 0x20, 0xA0, 0xE5, 0xB5, 0xB1, 0x00, 0x73, 0x80, 0x21, 0xE2, 0x71, + 0x10, 0x78, 0x00, 0x01, 0xE8, 0x05, 0xE6, 0xEA, 0xE8, 0x0A, 0x8C, 0xE1, 0xD5, 0x06, 0xA0, 0xE6, + 0xE3, 0xA3, 0xE8, 0x05, 0xC7, 0x04, 0x8E, 0xE1, 0x10, 0x78, 0x00, 0x01, 0x80, 0x66, 0x42, 0x32, + 0x88, 0x73, 0x38, 0x8C, 0x16, 0x0A, 0x00, 0x31, 0x80, 0x18, 0x8C, 0x21, 0x38, 0x8C, 0x8E, 0x0A, + 0xF3, 0x03, 0x8E, 0x61, 0xF3, 0x83, 0xF3, 0x01, 0x8E, 0x61, 0xF3, 0x81, 0x8D, 0xE1, 0x48, 0xFF, + 0xFE, 0xFD, 0x84, 0x60, 0xB0, 0x9F, 0x80, 0x0B, 0xF3, 0x84, 0x81, 0x43, 0xB1, 0xEE, 0x44, 0xC0, + 0x00, 0x34, 0x85, 0x21, 0x85, 0xA5, 0x85, 0x04, 0x2E, 0x30, 0x05, 0x74, 0xF5, 0x04, 0xE2, 0xA3, + 0x3C, 0x3C, 0x01, 0x5E, 0xE8, 0x03, 0xF5, 0x01, 0xCD, 0x0A, 0x84, 0x40, 0x86, 0x01, 0x80, 0x06, + 0x81, 0x42, 0x82, 0x22, 0x81, 0x10, 0x85, 0x83, 0x48, 0x00, 0x00, 0x90, 0x00, 0xF1, 0x80, 0x09, + 0xE2, 0x2F, 0xE8, 0xF4, 0x0D, 0x01, 0x00, 0x01, 0x5B, 0x08, 0x01, 0x76, 0x05, 0x00, 0x00, 0x07, + 0x5B, 0x08, 0x03, 0x08, 0xF3, 0x01, 0x14, 0xA1, 0x7F, 0xFF, 0x8E, 0x61, 0xF3, 0x81, 0xD5, 0x6B, + 0x8F, 0x81, 0xE7, 0x82, 0xE8, 0x0C, 0x05, 0x00, 0x00, 0x0A, 0x5B, 0x08, 0x02, 0x06, 0x84, 0xA0, + 0x10, 0x50, 0x00, 0x20, 0xD5, 0x09, 0x01, 0x02, 0x00, 0x01, 0xD5, 0x04, 0x01, 0x00, 0x00, 0x20, + 0x8F, 0x81, 0x11, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x20, 0x5B, 0x08, 0x01, 0x08, 0x01, 0x10, + 0x00, 0x22, 0x59, 0x18, 0x80, 0x08, 0x11, 0x10, 0x00, 0x22, 0x00, 0x31, 0x80, 0x19, 0x87, 0xC0, + 0x40, 0xFF, 0x0C, 0x06, 0xE8, 0x22, 0x38, 0xF3, 0xFA, 0x02, 0xE9, 0x1C, 0x38, 0xF7, 0x7A, 0x02, + 0xE9, 0x19, 0x80, 0x68, 0x40, 0x36, 0xC0, 0x1A, 0xA8, 0xC7, 0x81, 0xE0, 0x80, 0x66, 0x3B, 0x07, + 0xE4, 0x04, 0x42, 0x3F, 0x30, 0x73, 0x3B, 0x01, 0xE4, 0x24, 0x3B, 0x07, 0xC8, 0x00, 0x3B, 0x01, + 0xC8, 0x20, 0x00, 0x30, 0x00, 0x18, 0xB1, 0x7D, 0x38, 0x92, 0x8E, 0x0A, 0x38, 0x93, 0xFA, 0x0A, + 0xD5, 0x24, 0x51, 0xEF, 0x00, 0x01, 0xD5, 0xDD, 0x85, 0xE0, 0xD5, 0x03, 0x50, 0xF7, 0x80, 0x01, + 0x4C, 0xF1, 0x80, 0x22, 0x38, 0x53, 0xBE, 0x02, 0xCD, 0xFA, 0x80, 0x68, 0x40, 0x36, 0xC0, 0x1A, + 0xA8, 0xC7, 0x83, 0xC0, 0x80, 0x66, 0x3B, 0x0F, 0x64, 0x04, 0x42, 0x37, 0xB0, 0x73, 0x3B, 0x01, + 0xE4, 0x24, 0x3B, 0x0F, 0x48, 0x00, 0x3B, 0x01, 0xC8, 0x20, 0x00, 0x30, 0x00, 0x18, 0xB1, 0x7D, + 0x38, 0x92, 0x8E, 0x0A, 0x38, 0x93, 0xBE, 0x0A, 0xF3, 0x01, 0x14, 0xA1, 0x7F, 0xFF, 0x8E, 0x61, + 0xF3, 0x81, 0x8C, 0x21, 0xF3, 0x04, 0xEB, 0x0A, 0x8C, 0x61, 0xF3, 0x84, 0x48, 0xFF, 0xFF, 0x6E, + 0xF5, 0x03, 0xC5, 0x6E, 0x01, 0x21, 0x80, 0x09, 0xE2, 0x32, 0xE8, 0x6A, 0x38, 0x57, 0x0A, 0x02, + 0x5A, 0x50, 0x01, 0x08, 0x8C, 0x41, 0xEB, 0x0A, 0xF5, 0x02, 0xE2, 0x45, 0xE9, 0xF2, 0xD5, 0x60, + 0xB1, 0x6E, 0x38, 0x52, 0x8A, 0x02, 0xCD, 0xF7, 0xB1, 0xFD, 0x38, 0x73, 0x96, 0x02, 0xCF, 0x54, + 0xB6, 0xE0, 0xAD, 0xC2, 0xAD, 0xC3, 0xAD, 0xC4, 0xAD, 0xC5, 0x02, 0x70, 0x00, 0x08, 0x12, 0x70, + 0x00, 0x0A, 0x02, 0x70, 0x00, 0x09, 0x12, 0x70, 0x00, 0x0B, 0x99, 0xE1, 0x04, 0x9F, 0x80, 0x06, + 0x00, 0x73, 0x80, 0x1C, 0x05, 0x34, 0x80, 0x03, 0x10, 0x50, 0x00, 0x18, 0x10, 0x70, 0x00, 0x20, + 0x04, 0x90, 0x00, 0x09, 0x03, 0x22, 0x00, 0x15, 0xCF, 0x0D, 0x38, 0x79, 0xA5, 0x01, 0xE3, 0xC7, + 0xE8, 0x04, 0x15, 0x00, 0x00, 0x07, 0xD5, 0x0F, 0x14, 0xC0, 0x00, 0x07, 0x10, 0x80, 0x00, 0x20, + 0xD5, 0x0A, 0x38, 0xF9, 0xA5, 0x01, 0x14, 0xC0, 0x00, 0x07, 0xE3, 0xCF, 0xE9, 0x04, 0x8C, 0xE1, + 0x10, 0x70, 0x00, 0x20, 0x38, 0x79, 0xA5, 0x01, 0x11, 0x10, 0x00, 0x2C, 0xE3, 0xC7, 0x80, 0xE8, + 0x40, 0x78, 0xBC, 0x1A, 0x10, 0x70, 0x00, 0x2E, 0x00, 0x70, 0x00, 0x22, 0x11, 0x10, 0x00, 0x21, + 0x58, 0x73, 0x80, 0x01, 0x10, 0x70, 0x00, 0x22, 0xB1, 0xFD, 0x39, 0x03, 0x96, 0x0A, 0xB1, 0x6E, + 0x39, 0x02, 0x8A, 0x0A, 0xF5, 0x03, 0x14, 0xA0, 0x00, 0x0A, 0x8E, 0xA1, 0x38, 0xA7, 0x0A, 0x0A, + 0xF5, 0x83, 0x8C, 0x21, 0xD5, 0xA0, 0x8C, 0xA1, 0xE2, 0xB2, 0xE9, 0xA7, 0xD5, 0x9C, 0x84, 0x00, + 0x44, 0x20, 0x00, 0x54, 0x80, 0x80, 0x00, 0x11, 0x80, 0x09, 0xE2, 0x01, 0xE8, 0x08, 0x42, 0x10, + 0x08, 0x24, 0xF5, 0x05, 0x8C, 0x01, 0x38, 0x42, 0x84, 0x0A, 0xD5, 0xF6, 0x84, 0x00, 0x3E, 0x00, + 0x05, 0x74, 0x84, 0x20, 0x50, 0x9F, 0x80, 0xB8, 0x44, 0xA0, 0x00, 0x54, 0x44, 0xC0, 0x00, 0x34, + 0x00, 0x01, 0x80, 0x19, 0xE2, 0x20, 0xE8, 0x45, 0x38, 0x04, 0x86, 0x02, 0x5A, 0x08, 0x01, 0x35, + 0xA1, 0xF7, 0x5A, 0x70, 0x05, 0x13, 0x2E, 0x20, 0x05, 0x74, 0x80, 0x0B, 0x80, 0xA6, 0x3B, 0x02, + 0xE4, 0x04, 0x42, 0x01, 0x30, 0x73, 0x8C, 0x41, 0x3B, 0x00, 0x64, 0x24, 0x3B, 0x02, 0xC8, 0x00, + 0x3B, 0x00, 0x48, 0x20, 0x3E, 0x20, 0x05, 0x74, 0x00, 0x03, 0x00, 0x18, 0xF2, 0x05, 0x42, 0x20, + 0x28, 0x73, 0x80, 0x02, 0xB6, 0xE2, 0x00, 0x23, 0x00, 0x22, 0x10, 0x20, 0x00, 0x1C, 0xA4, 0xB6, + 0xAC, 0x82, 0xA4, 0xB7, 0xAC, 0x83, 0x04, 0x23, 0x00, 0x09, 0x50, 0x40, 0x00, 0x20, 0xB6, 0x44, + 0xB4, 0x46, 0xA8, 0xA2, 0xA4, 0xB2, 0x12, 0x20, 0x00, 0x16, 0xA4, 0xB3, 0x12, 0x20, 0x00, 0x17, + 0x04, 0x23, 0x00, 0x0A, 0xA8, 0xA5, 0x8C, 0x21, 0x50, 0x63, 0x00, 0x34, 0xD5, 0xC2, 0x39, 0x78, + 0x9C, 0x0A, 0x48, 0xFF, 0xFD, 0x54, 0x46, 0x48, 0x00, 0x00, 0x88, 0x44, 0x48, 0xFF, 0xFD, 0x4D, + 0x51, 0xFF, 0x87, 0xC0, 0xFC, 0xE0, 0x84, 0x00, 0x3E, 0x00, 0x05, 0x74, 0xDD, 0x9E, 0xFC, 0x60, + 0x81, 0x60, 0x82, 0x20, 0x84, 0x00, 0x82, 0x41, 0x81, 0x20, 0x82, 0x60, 0x84, 0xE1, 0x81, 0x00, + 0x44, 0xE0, 0x00, 0x3C, 0x4F, 0x12, 0x00, 0x37, 0x4F, 0x22, 0x00, 0x35, 0x5A, 0x78, 0x01, 0x33, + 0x84, 0xC0, 0x80, 0xE6, 0x85, 0x5E, 0x4C, 0x65, 0x80, 0x1E, 0x39, 0x01, 0x1A, 0x02, 0x5B, 0x08, + 0x01, 0x18, 0x41, 0x42, 0x18, 0x40, 0x86, 0x00, 0x4D, 0x00, 0x80, 0x13, 0x38, 0xD1, 0xC2, 0x02, + 0x5A, 0xD8, 0x01, 0x0D, 0x42, 0xC8, 0x38, 0x24, 0x38, 0xCA, 0x30, 0x02, 0x40, 0xF6, 0x28, 0x06, + 0xE8, 0x05, 0x81, 0x30, 0x82, 0x66, 0x80, 0xED, 0x81, 0x4C, 0x8D, 0x81, 0xD5, 0xEE, 0x8C, 0xC1, + 0xD5, 0xE3, 0xC7, 0xD9, 0x40, 0x62, 0x80, 0x20, 0x11, 0x33, 0x00, 0x00, 0x10, 0x93, 0x00, 0x01, + 0x9D, 0x81, 0x38, 0x81, 0x4E, 0x0A, 0x96, 0x30, 0x38, 0x81, 0xA6, 0x0A, 0x8F, 0xA1, 0x8F, 0xC1, + 0xD5, 0xCA, 0xFC, 0xE0, 0xFC, 0x60, 0x51, 0xFF, 0xFB, 0x98, 0x80, 0xC0, 0xC0, 0x6A, 0xC1, 0x68, + 0xE2, 0x20, 0xE8, 0x30, 0x80, 0xE1, 0x45, 0x10, 0x00, 0x3C, 0x86, 0x5F, 0x82, 0x04, 0x43, 0x03, + 0xC4, 0x73, 0x84, 0x00, 0x39, 0x28, 0x02, 0x0A, 0x8C, 0x01, 0x4C, 0x03, 0x7F, 0xFD, 0x8C, 0xE1, + 0x4C, 0x73, 0x7F, 0xF6, 0x80, 0x01, 0x81, 0xC1, 0x80, 0x26, 0x81, 0xA5, 0x81, 0x44, 0x81, 0x83, + 0x81, 0x62, 0x49, 0xFF, 0xCF, 0x98, 0xB0, 0x39, 0x49, 0xFF, 0xCF, 0x9C, 0x80, 0x0A, 0x49, 0xFF, + 0xCF, 0xAA, 0x80, 0x1F, 0x49, 0xFF, 0xCF, 0xB3, 0x81, 0x26, 0x84, 0x0F, 0x84, 0xC0, 0x49, 0xFF, + 0xCF, 0xBF, 0x49, 0xFF, 0xCF, 0xC2, 0x80, 0xA6, 0x86, 0x2F, 0x44, 0x30, 0x00, 0x3C, 0x80, 0x46, + 0xD5, 0x20, 0xE2, 0x01, 0xE8, 0xE0, 0x84, 0xE0, 0x45, 0x10, 0x00, 0x3C, 0x86, 0x5F, 0x82, 0x04, + 0x43, 0x03, 0xC4, 0x73, 0x80, 0x06, 0x39, 0x28, 0x02, 0x0A, 0x8C, 0x01, 0x4C, 0x00, 0xFF, 0xFD, + 0x8C, 0xE1, 0x4C, 0x70, 0xFF, 0xF6, 0xD5, 0xCF, 0x40, 0x08, 0x10, 0x00, 0x38, 0x0F, 0x80, 0x00, + 0x5A, 0x00, 0x01, 0x0F, 0x8D, 0x81, 0x4D, 0x04, 0xFF, 0xF9, 0x8C, 0xA1, 0x4C, 0x57, 0x00, 0x1A, + 0x80, 0x2A, 0x42, 0x42, 0xC4, 0x24, 0x42, 0x12, 0x8C, 0x73, 0x86, 0x00, 0xD5, 0xEE, 0x38, 0x00, + 0xC2, 0x02, 0x5A, 0x07, 0xFF, 0xF1, 0x40, 0x06, 0x98, 0x20, 0x9D, 0xF1, 0x11, 0x00, 0x00, 0x00, + 0xAF, 0x41, 0x97, 0xB8, 0x38, 0x25, 0xC2, 0x0A, 0x38, 0x26, 0x16, 0x0A, 0xD5, 0xE4, 0x80, 0xC1, + 0x80, 0x06, 0x51, 0xFF, 0x84, 0x68, 0xFC, 0xE0, 0x3C, 0x0E, 0x01, 0xAB, 0xDD, 0x9E, 0x3C, 0x0E, + 0x01, 0xAA, 0xDD, 0x9E, 0xFC, 0x60, 0x50, 0xB0, 0xFF, 0xFF, 0x85, 0x42, 0x3C, 0xCC, 0x01, 0xAA, + 0x3C, 0x4C, 0x01, 0x96, 0x3C, 0x2C, 0x01, 0x95, 0x3D, 0x0C, 0x01, 0xAB, 0x40, 0xA5, 0xA9, 0x56, + 0x45, 0x32, 0xD3, 0x10, 0x8C, 0x0C, 0x44, 0x32, 0xD2, 0xD4, 0x44, 0x62, 0xD2, 0xAC, 0x45, 0x22, + 0xD2, 0xBC, 0x86, 0x20, 0x85, 0x01, 0x44, 0x92, 0xD1, 0xF8, 0x85, 0xAF, 0x85, 0xC4, 0x00, 0x16, + 0x00, 0x09, 0xE3, 0xA1, 0x4E, 0xF2, 0x00, 0xD6, 0x04, 0x70, 0x7F, 0xFD, 0x4E, 0x72, 0x00, 0xC9, + 0x00, 0x10, 0x00, 0x10, 0x97, 0x4C, 0xC5, 0x0B, 0x10, 0x89, 0x80, 0x00, 0x22, 0x10, 0x00, 0x00, + 0xAC, 0x58, 0x22, 0x10, 0x00, 0x01, 0xAC, 0x59, 0x48, 0x00, 0x00, 0xBB, 0x5A, 0x70, 0x04, 0x04, + 0x48, 0x00, 0x00, 0x86, 0x00, 0x29, 0x80, 0x00, 0xCA, 0x3B, 0x00, 0x49, 0x00, 0x00, 0x5A, 0x40, + 0x01, 0x06, 0xA7, 0xF0, 0x80, 0x82, 0x80, 0xA2, 0xD5, 0x1E, 0x01, 0x53, 0x00, 0x00, 0x40, 0x74, + 0xC4, 0x40, 0x80, 0x82, 0x80, 0xA2, 0x85, 0xE1, 0x4C, 0x5A, 0xC0, 0x03, 0x85, 0xE2, 0x23, 0x43, + 0x80, 0x00, 0x8C, 0xA1, 0x42, 0x47, 0xD0, 0x73, 0x23, 0x43, 0x80, 0x01, 0x97, 0x68, 0x42, 0x27, + 0xD0, 0x73, 0x50, 0x73, 0x80, 0x3C, 0x5A, 0x58, 0x03, 0xF0, 0x40, 0x42, 0x38, 0x96, 0x40, 0x21, + 0x38, 0x56, 0xD5, 0x18, 0x81, 0xF1, 0x42, 0xF2, 0xB4, 0x73, 0x8C, 0xA1, 0x39, 0x44, 0xBE, 0x11, + 0x40, 0xF4, 0xBC, 0x40, 0x22, 0xF7, 0x80, 0x01, 0x97, 0x68, 0x88, 0x4F, 0xE2, 0xE5, 0x88, 0x94, + 0xE8, 0xF2, 0x8C, 0xE1, 0x40, 0x42, 0x1C, 0x96, 0x40, 0x21, 0x1C, 0x56, 0xD5, 0x03, 0x80, 0x45, + 0x80, 0x85, 0x42, 0x51, 0x00, 0x03, 0x42, 0x72, 0x00, 0x03, 0x88, 0xE5, 0x04, 0x58, 0x00, 0x01, + 0xE2, 0xA7, 0xE8, 0x6E, 0x54, 0x70, 0x80, 0x08, 0x00, 0x58, 0x00, 0x00, 0x01, 0x68, 0x00, 0x02, + 0xC7, 0x0F, 0xFF, 0x64, 0xA5, 0xD8, 0x40, 0x52, 0xD8, 0xB6, 0x88, 0xA7, 0xAD, 0x58, 0x00, 0x58, + 0x00, 0x01, 0x00, 0x78, 0x00, 0x03, 0xFF, 0x54, 0x40, 0x52, 0x9C, 0xB6, 0xD5, 0x1A, 0x40, 0x7B, + 0x28, 0x00, 0x40, 0x73, 0xAC, 0xF6, 0x01, 0x48, 0x00, 0x03, 0x42, 0x53, 0x94, 0x01, 0xFF, 0x64, + 0x40, 0xFA, 0x28, 0x00, 0x01, 0x58, 0x00, 0x01, 0x40, 0x52, 0xD8, 0xB6, 0xA5, 0xD8, 0x40, 0xF7, + 0xAD, 0xF6, 0x88, 0xE5, 0x42, 0x57, 0xD4, 0x01, 0xFF, 0x54, 0xAD, 0xD8, 0x40, 0x52, 0xD0, 0xB6, + 0xA5, 0xD9, 0x58, 0x10, 0x80, 0x02, 0x88, 0xA7, 0xAD, 0x59, 0x22, 0x51, 0x80, 0x00, 0xAD, 0x40, + 0x22, 0x51, 0x80, 0x01, 0xAD, 0x41, 0x10, 0x10, 0x00, 0x10, 0xD5, 0x32, 0x5A, 0x70, 0x05, 0x31, + 0x00, 0x19, 0x80, 0x00, 0x5A, 0x18, 0x01, 0x08, 0x10, 0x59, 0x00, 0x00, 0xAF, 0x70, 0x10, 0x59, + 0x80, 0x00, 0xD5, 0x10, 0xA6, 0x70, 0xE6, 0x22, 0xE8, 0x04, 0x8C, 0x21, 0xAE, 0x70, 0xD5, 0x02, + 0xAF, 0x70, 0x00, 0x19, 0x00, 0x00, 0xC9, 0x06, 0xA6, 0x70, 0x5A, 0x18, 0x02, 0x04, 0x10, 0x89, + 0x00, 0x00, 0xA6, 0x70, 0x80, 0xB1, 0x42, 0x50, 0xB4, 0x73, 0x22, 0xF0, 0x00, 0x00, 0x80, 0x25, + 0xA5, 0x58, 0x40, 0x57, 0x94, 0x01, 0x38, 0x54, 0x86, 0x09, 0x22, 0x70, 0x00, 0x01, 0xA5, 0x59, + 0x40, 0x14, 0x84, 0x40, 0x9B, 0x7D, 0xAD, 0x49, 0x12, 0xF1, 0x80, 0x00, 0xAD, 0xD9, 0x8D, 0xA1, + 0x8D, 0xE1, 0x50, 0x00, 0x00, 0x54, 0x8C, 0x64, 0x8C, 0xC1, 0x8D, 0xC1, 0x48, 0xFF, 0xFF, 0x29, + 0x3C, 0x4E, 0x01, 0x96, 0x3C, 0x2E, 0x01, 0x95, 0xFC, 0xE0, 0x3C, 0x0E, 0x01, 0xAD, 0xDD, 0x9E, + 0x3C, 0x0E, 0x01, 0xAC, 0xDD, 0x9E, 0xFC, 0x00, 0xC0, 0x04, 0x5A, 0x00, 0x01, 0x08, 0xFC, 0x80, + 0x49, 0xFF, 0xD1, 0x28, 0x3C, 0x0E, 0x01, 0xAE, 0xFC, 0x80, 0x49, 0xFF, 0xD1, 0x2B, 0x3C, 0x0E, + 0x01, 0xAF, 0xFC, 0x80, 0x80, 0x20, 0xE6, 0x09, 0x3C, 0x0C, 0x01, 0xAF, 0xE8, 0x23, 0x44, 0xF1, + 0x5B, 0xC8, 0xEA, 0xD6, 0xEA, 0x89, 0xDD, 0x0F, 0x0A, 0x3C, 0x10, 0x16, 0x1C, 0x22, 0x28, 0x2E, + 0x34, 0x00, 0x3C, 0x0C, 0x01, 0xAE, 0xDD, 0x9E, 0x50, 0x00, 0x00, 0xF0, 0xDD, 0x9E, 0x50, 0x00, + 0x01, 0xE0, 0xDD, 0x9E, 0x50, 0x00, 0x02, 0xD0, 0xDD, 0x9E, 0x50, 0x00, 0x03, 0xC0, 0xDD, 0x9E, + 0x50, 0x00, 0x05, 0xA0, 0xDD, 0x9E, 0x50, 0x00, 0x07, 0x80, 0xDD, 0x9E, 0x50, 0x00, 0x09, 0x60, + 0xDD, 0x9E, 0x84, 0x00, 0xDD, 0x9E, 0x92, 0x00, 0xFC, 0x40, 0x80, 0xC2, 0x80, 0xE1, 0x3C, 0x2C, + 0x01, 0xAF, 0x3C, 0x1C, 0x01, 0xAE, 0x81, 0x23, 0x81, 0x44, 0x49, 0xFF, 0xD0, 0xC1, 0x3C, 0x1C, + 0x01, 0xAC, 0xA6, 0x0A, 0xA6, 0x4B, 0x49, 0xFF, 0xD0, 0xDC, 0xEA, 0x61, 0x42, 0x03, 0x00, 0x01, + 0x49, 0xFF, 0xD0, 0xF5, 0x84, 0xC0, 0x3C, 0x1C, 0x01, 0xAD, 0x00, 0x00, 0x80, 0x10, 0xE2, 0xC0, + 0xE8, 0x10, 0x80, 0x06, 0x38, 0x10, 0x98, 0x00, 0x49, 0xFF, 0xD0, 0xF6, 0x3C, 0x0C, 0x01, 0xAD, + 0x98, 0x46, 0x00, 0x10, 0x80, 0x08, 0x80, 0x06, 0x49, 0xFF, 0xD1, 0x14, 0x8C, 0xC1, 0xD5, 0xEC, + 0x84, 0x00, 0xF8, 0x0B, 0xF8, 0x0C, 0x84, 0x01, 0xF8, 0x08, 0xF8, 0x09, 0x5A, 0xA8, 0x01, 0x05, + 0x84, 0x02, 0xF8, 0x03, 0xF8, 0x04, 0x84, 0x03, 0x49, 0xFF, 0xD0, 0xD5, 0x49, 0xFF, 0xD0, 0xA3, + 0x49, 0xFF, 0xD0, 0xC9, 0xEA, 0x94, 0x84, 0x00, 0x00, 0x14, 0x80, 0x00, 0xE2, 0x01, 0xE8, 0x29, + 0xA0, 0x79, 0x38, 0x50, 0x81, 0x01, 0xD0, 0x23, 0xA0, 0x7D, 0x94, 0x82, 0x95, 0x6A, 0x98, 0xCA, + 0x88, 0x25, 0xA6, 0xDA, 0xA7, 0x0A, 0xE2, 0x64, 0xE8, 0x02, 0xAE, 0xCA, 0xA0, 0x7D, 0x98, 0xCA, + 0x88, 0x25, 0xA6, 0xDB, 0xA7, 0x0B, 0xE2, 0x83, 0xE8, 0x02, 0xAE, 0xCB, 0xA0, 0x7D, 0x38, 0x30, + 0x88, 0x00, 0x88, 0x25, 0xA7, 0x08, 0xE2, 0x64, 0xE8, 0x02, 0xAE, 0xC8, 0xA0, 0xFD, 0x88, 0x43, + 0x88, 0xA3, 0xA6, 0x51, 0xA6, 0xA9, 0xE2, 0x41, 0xE8, 0x02, 0xAE, 0x69, 0x8C, 0x01, 0xD5, 0xD5, + 0xFC, 0xC0, 0x92, 0x00, 0x80, 0x60, 0xE6, 0x44, 0xE9, 0x28, 0x54, 0x41, 0x80, 0x03, 0x54, 0x50, + 0x80, 0x03, 0xC5, 0x0B, 0x52, 0x52, 0x80, 0x04, 0x9A, 0x95, 0x99, 0x69, 0x08, 0x40, 0x80, 0x01, + 0x18, 0x41, 0x80, 0x01, 0x4C, 0x12, 0xFF, 0xFC, 0x40, 0x51, 0x14, 0x09, 0xC5, 0x0A, 0x95, 0x6D, + 0x99, 0x69, 0x96, 0xA7, 0x3B, 0x00, 0xDC, 0x04, 0x3B, 0x01, 0xDC, 0x24, 0x4C, 0x12, 0xFF, 0xFC, + 0x40, 0x51, 0x08, 0x09, 0xC5, 0x0A, 0x95, 0x6A, 0x99, 0x69, 0x96, 0x8F, 0x3A, 0x40, 0x90, 0x04, + 0x3A, 0x41, 0x90, 0x24, 0x4C, 0x12, 0xFF, 0xFC, 0xC2, 0x08, 0x99, 0x4A, 0x08, 0x40, 0x80, 0x01, + 0x18, 0x41, 0x80, 0x01, 0x4C, 0x12, 0xFF, 0xFC, 0xDD, 0x9E, 0x92, 0x00, 0x80, 0x60, 0xE6, 0x44, + 0xE9, 0x30, 0x54, 0x51, 0x80, 0x03, 0xC5, 0x09, 0x52, 0x52, 0x80, 0x04, 0x9A, 0x95, 0x99, 0x68, + 0x18, 0x11, 0x80, 0x01, 0x4C, 0x32, 0xFF, 0xFE, 0x96, 0x48, 0x40, 0x40, 0xA0, 0x08, 0xFE, 0x67, + 0x40, 0x40, 0xC0, 0x08, 0xFE, 0x67, 0x40, 0x51, 0x14, 0x09, 0x4E, 0x52, 0x00, 0x11, 0x95, 0x6D, + 0x99, 0x6B, 0x96, 0xA7, 0x82, 0x01, 0x82, 0x21, 0x82, 0x41, 0x82, 0x61, 0x82, 0x81, 0x82, 0xA1, + 0x82, 0xC1, 0x82, 0xE1, 0x3B, 0x01, 0xDC, 0x24, 0x4C, 0x32, 0xFF, 0xFE, 0x40, 0x51, 0x08, 0x09, + 0xC5, 0x08, 0x95, 0x6A, 0x99, 0x6B, 0x96, 0x8F, 0x3A, 0x11, 0x84, 0x24, 0x4C, 0x32, 0xFF, 0xFE, + 0xC2, 0x06, 0x99, 0x5A, 0x18, 0x11, 0x80, 0x01, 0x4C, 0x32, 0xFF, 0xFE, 0xDD, 0x9E, 0x92, 0x00, + 0x49, 0x00, 0x0C, 0xF3, 0x3C, 0x0D, 0xFC, 0x04, 0x49, 0x00, 0x0E, 0x66, 0x49, 0x00, 0x7B, 0xFB, + 0x49, 0x00, 0x3D, 0x14, 0x44, 0x03, 0xF0, 0x4A, 0x49, 0x00, 0xAE, 0x72, 0x44, 0x10, 0x00, 0x55, + 0x2E, 0x07, 0xEE, 0xF4, 0x49, 0x00, 0x3D, 0x14, 0x49, 0x00, 0x2F, 0x56, 0x3C, 0x0D, 0xFC, 0x25, + 0x49, 0x00, 0x2F, 0x56, 0x3C, 0x0D, 0xFC, 0xFD, 0x48, 0x00, 0x01, 0x55, 0x49, 0x00, 0x2F, 0xF0, + 0x3C, 0x1D, 0xFC, 0x25, 0x3C, 0x1D, 0xFC, 0x3F, 0x3C, 0x0D, 0xFC, 0x03, 0x49, 0x00, 0x33, 0x6C, + 0x44, 0x03, 0x8D, 0x40, 0x2E, 0x07, 0xEF, 0x2F, 0x49, 0x00, 0x2F, 0xA7, 0x49, 0x00, 0x1C, 0x09, + 0x3C, 0x0D, 0xFC, 0x3F, 0x44, 0x30, 0x01, 0x90, 0x3C, 0x1D, 0xFC, 0x04, 0x44, 0x20, 0x00, 0x55, + 0x44, 0x20, 0x01, 0x80, 0x49, 0x00, 0x31, 0x6D, 0x48, 0x00, 0x97, 0xC7, 0x3C, 0x0D, 0xFA, 0xC3, + 0x49, 0x00, 0x7B, 0xFB, 0x44, 0x13, 0xF0, 0x4A, 0x49, 0x00, 0x0C, 0xF3, 0x49, 0x00, 0x32, 0x16, + 0x44, 0x02, 0xD8, 0xE8, 0x3A, 0x6F, 0x98, 0x84, 0x49, 0x00, 0x13, 0x32, 0x44, 0x20, 0x01, 0x90, + 0x2E, 0x17, 0xF3, 0x7E, 0x44, 0x12, 0xFE, 0xF0, 0x3E, 0x07, 0xEF, 0x65, 0x2E, 0x07, 0xEE, 0xC5, + 0x40, 0x31, 0x0C, 0x40, 0x3C, 0x0F, 0xFC, 0x03, 0x2E, 0x07, 0x34, 0x0C, 0x49, 0x00, 0xAE, 0xA6, + 0x49, 0x00, 0x81, 0x2C, 0x3C, 0x1D, 0xFC, 0xFD, 0x2E, 0x07, 0xEF, 0x51, 0x3C, 0x0F, 0xFC, 0xD8, + 0x44, 0x0F, 0xFF, 0xAA, 0x50, 0x03, 0x7F, 0x60, 0x49, 0x00, 0x1B, 0x48, 0x40, 0x00, 0x00, 0x09, + 0x2E, 0x07, 0xEF, 0x5B, 0x49, 0x00, 0x60, 0xD8, 0x2E, 0x07, 0xF3, 0xCB, 0x00, 0x34, 0x80, 0x02, + 0x40, 0xF0, 0x3C, 0x00, 0x44, 0x03, 0x73, 0xE8, 0x49, 0x00, 0x84, 0xD7, 0x44, 0x00, 0x00, 0x64, + 0x44, 0x00, 0x00, 0x55, 0x3C, 0x0D, 0xFA, 0xC2, 0x3E, 0x07, 0xEE, 0xF0, 0x49, 0x00, 0x81, 0x15, + 0x49, 0x00, 0x84, 0xD7, 0x49, 0x00, 0x0C, 0xF7, 0x3C, 0x0D, 0xFC, 0x2D, 0x44, 0x00, 0x00, 0x78, + 0x44, 0x30, 0x00, 0x55, 0x3C, 0x0F, 0xFC, 0xD3, 0x44, 0x03, 0x00, 0x00, 0x49, 0x00, 0x7B, 0x04, + 0x49, 0x00, 0x0E, 0x66, 0x3C, 0x0F, 0xFA, 0xC3, 0x10, 0x10, 0x00, 0x51, 0x44, 0x30, 0x00, 0xC8, + 0x44, 0x23, 0xF0, 0x4A, 0x3E, 0x07, 0xEF, 0x58, 0x00, 0x00, 0x00, 0x51, 0x10, 0x0F, 0x80, 0x0F, + 0x49, 0x00, 0x7A, 0x19, 0x3E, 0x07, 0xEB, 0x38, 0x44, 0x02, 0xFE, 0xF0, 0x10, 0x0F, 0x80, 0x07, + 0x44, 0x02, 0xBD, 0x24, 0x2E, 0x00, 0x0A, 0x92, 0x38, 0x11, 0x01, 0x09, 0x44, 0x02, 0xDB, 0xE8, + 0x49, 0x00, 0x33, 0x6C, 0x54, 0x10, 0x80, 0xFE, 0x44, 0x33, 0x8D, 0x41, 0x3C, 0x0B, 0xF7, 0xDF, + 0x3C, 0x0F, 0xFC, 0x3A, 0x44, 0x00, 0x00, 0xFF, 0x44, 0x02, 0xDB, 0x3C, 0x00, 0x44, 0x80, 0x03, + 0x54, 0x10, 0xFF, 0xFF, 0x49, 0x00, 0x12, 0xFC, 0x3E, 0x07, 0xEF, 0x51, 0x3C, 0x0D, 0xFC, 0x3A, + 0x49, 0x00, 0x2F, 0xCD, 0x49, 0x00, 0x7F, 0xC4, 0x10, 0x03, 0x00, 0x50, 0x2E, 0x07, 0x34, 0x0B, + 0x3C, 0x0B, 0xF7, 0xC9, 0x49, 0x00, 0x7D, 0x0A, 0x2E, 0x07, 0xEE, 0xEE, 0x49, 0x00, 0x7D, 0xFC, + 0x3E, 0x17, 0xEB, 0x38, 0x3C, 0x0F, 0xFC, 0x58, 0x49, 0x00, 0x2F, 0xF0, 0x49, 0x00, 0x31, 0x66, + 0x00, 0x04, 0x80, 0x00, 0x49, 0x00, 0x39, 0x1F, 0x64, 0x03, 0x04, 0x03, 0x49, 0x00, 0x84, 0x8B, + 0x3E, 0x07, 0xEA, 0xFC, 0x3C, 0x03, 0xF7, 0xCA, 0x38, 0x70, 0x80, 0x00, 0x44, 0x13, 0xF4, 0x03, + 0x44, 0x03, 0x65, 0x10, 0x2E, 0x00, 0x0A, 0x8D, 0x10, 0x05, 0x00, 0x02, 0x44, 0x12, 0xFE, 0x50, + 0x44, 0x13, 0x7A, 0x28, 0x2E, 0x07, 0xEE, 0xE5, 0x49, 0x00, 0x0F, 0xFA, 0x3C, 0x0F, 0xFA, 0xC2, + 0x49, 0x00, 0x1C, 0xA3, 0x3C, 0x0B, 0xF7, 0xE3, 0x44, 0x12, 0x62, 0x38, 0x54, 0x00, 0x7F, 0xFF, + 0x2E, 0x07, 0xEE, 0xC3, 0x40, 0xF0, 0xBC, 0x00, 0x2E, 0x07, 0xF3, 0x02, 0x2E, 0x17, 0xEF, 0x2F, + 0x58, 0x00, 0x00, 0x01, 0x49, 0x00, 0x60, 0xD8, 0x44, 0x1F, 0xFF, 0xAA, 0x54, 0x00, 0x00, 0xFE, + 0x38, 0x07, 0x80, 0x00, 0x49, 0x00, 0x17, 0x7F, 0x44, 0x00, 0x00, 0x69, 0x42, 0x10, 0x80, 0x03, + 0x10, 0x04, 0x80, 0x00, 0x2E, 0x07, 0xEF, 0x45, 0x2E, 0x37, 0x33, 0x8A, 0x3E, 0x07, 0xEE, 0xE9, + 0x3C, 0x08, 0x07, 0xF4, 0x22, 0x10, 0x80, 0x01, 0x49, 0x00, 0x17, 0xD3, 0x2E, 0x27, 0x33, 0x8A, + 0x44, 0x03, 0x8D, 0x28, 0x10, 0x05, 0x00, 0x00, 0x49, 0x00, 0x37, 0x02, 0x40, 0x00, 0x04, 0x16, + 0x66, 0x00, 0x00, 0x02, 0x38, 0x07, 0x81, 0x01, 0x3C, 0x0D, 0xFC, 0x90, 0x44, 0x13, 0x1C, 0x20, + 0x2E, 0x07, 0xF3, 0x56, 0x48, 0x00, 0x01, 0x71, 0x2E, 0x00, 0x0A, 0x8C, 0x49, 0x00, 0x28, 0x26, + 0x02, 0x0F, 0x80, 0x03, 0x48, 0x00, 0x01, 0x28, 0x3E, 0x07, 0xEF, 0x55, 0x12, 0x0F, 0x80, 0x03, + 0x2E, 0x07, 0xEE, 0xF0, 0x2E, 0x47, 0x33, 0x8B, 0x2E, 0x07, 0xEE, 0xB3, 0x3E, 0x07, 0xEF, 0x05, + 0x3C, 0x03, 0xF7, 0xCE, 0x3C, 0x0B, 0xFB, 0x53, 0x44, 0x00, 0x00, 0x54, 0x44, 0x62, 0xFE, 0xF0, + 0x49, 0x00, 0x33, 0x24, 0x3C, 0x0C, 0x01, 0xB6, 0x3E, 0x07, 0xF2, 0xC5, 0x44, 0x12, 0xA5, 0x0A, + 0x5C, 0x00, 0x00, 0x01, 0x44, 0x20, 0x00, 0xA2, 0x3E, 0x07, 0xF0, 0x71, 0x2E, 0x07, 0xF3, 0xCC, + 0x12, 0x04, 0x80, 0x00, 0x44, 0x13, 0x4C, 0x10, 0x44, 0x10, 0x00, 0x32, 0x44, 0x40, 0x00, 0x32, + 0x3E, 0x07, 0xEF, 0x2F, 0x44, 0x40, 0x00, 0x64, 0x49, 0x00, 0x6F, 0xB1, 0x40, 0x00, 0x80, 0x40, + 0x49, 0x00, 0x7E, 0xC8, 0x44, 0x13, 0x0F, 0xA0, 0x49, 0x00, 0x70, 0x83, 0x3A, 0x1F, 0x90, 0x00, + 0x44, 0x20, 0x00, 0xC8, 0x40, 0x00, 0x08, 0x16, 0x50, 0x0F, 0x80, 0x06, 0x44, 0x02, 0xDE, 0xC4, + 0x44, 0x63, 0xF0, 0x4A, 0x44, 0x12, 0x9E, 0xCA, 0x48, 0x00, 0x20, 0xB5, 0x3A, 0x10, 0x84, 0x00, + 0x2E, 0x07, 0x33, 0x93, 0x44, 0x03, 0xF7, 0xC8, 0x42, 0x00, 0x48, 0x0B, 0x40, 0x11, 0x04, 0x20, + 0x3E, 0x07, 0xF2, 0xFE, 0x3C, 0x1D, 0xFC, 0x0B, 0x38, 0x17, 0x84, 0x00, 0x44, 0x22, 0xBD, 0x80, + 0x3C, 0x0F, 0xFC, 0x43, 0x40, 0x32, 0x0D, 0x00, 0x2E, 0x07, 0xEE, 0xDE, 0x3B, 0x00, 0xE4, 0x24, + 0x38, 0x30, 0x8A, 0x0A, 0x2E, 0x07, 0xEE, 0xE0, 0x44, 0x12, 0xD9, 0x9C, 0x50, 0x1F, 0x80, 0x0F, + 0x44, 0x10, 0x01, 0x90, 0x3C, 0x0F, 0xFC, 0xD9, 0x44, 0x12, 0xBB, 0x67, 0x42, 0x31, 0x80, 0x03, + 0x40, 0xF7, 0x80, 0x11, 0x42, 0x21, 0x00, 0x03, 0x44, 0x02, 0xFE, 0x50, 0x44, 0x30, 0x00, 0x64, + 0x50, 0x0F, 0x80, 0x0E, 0x3C, 0x6F, 0xFC, 0x7E, 0x2E, 0x07, 0xF4, 0x1D, 0x42, 0x00, 0x04, 0x0B, + 0x44, 0x00, 0x00, 0x50, 0x44, 0x12, 0xA9, 0xBA, 0x64, 0x13, 0x04, 0x02, 0x49, 0x00, 0x87, 0x70, + 0x40, 0x31, 0x84, 0x76, 0x44, 0x13, 0xF2, 0x48, 0x44, 0x30, 0x00, 0x32, 0x64, 0x03, 0x08, 0x03, + 0x50, 0x00, 0x0F, 0x80, 0x40, 0x03, 0x20, 0x09, 0x2E, 0x07, 0xEF, 0x04, 0x44, 0x03, 0x0C, 0x80, + 0x44, 0x12, 0x00, 0x00, 0x44, 0x02, 0x55, 0xB8, 0x44, 0x03, 0xF7, 0xC5, 0x49, 0x00, 0x31, 0xD1, + 0x3C, 0x23, 0x99, 0xDE, 0x44, 0x02, 0x62, 0x38, 0x49, 0x00, 0x37, 0xDC, 0x40, 0x11, 0x04, 0x36, + 0x12, 0x0F, 0x80, 0x00, 0x44, 0x12, 0xBC, 0x36, 0x44, 0x73, 0xF0, 0x4A, 0x3E, 0x07, 0xF6, 0x8A, + 0x2E, 0x17, 0xEB, 0x38, 0x3C, 0x0C, 0x03, 0x20, 0x3C, 0x0C, 0x00, 0x5E, 0x44, 0x00, 0x00, 0x32, + 0x3C, 0x0B, 0xF7, 0xCE, 0x44, 0x1E, 0x00, 0x00, 0x50, 0x00, 0x00, 0x34, 0x44, 0x02, 0xBF, 0xCC, + 0x50, 0x2F, 0x80, 0x07, 0x3E, 0x07, 0xEF, 0x11, 0x49, 0x00, 0x30, 0x6E, 0x42, 0x03, 0x88, 0x73, + 0x49, 0x00, 0x0D, 0x03, 0x44, 0x02, 0xFE, 0xF1, 0x3C, 0x03, 0xF7, 0xC8, 0x44, 0x13, 0x8D, 0x28, + 0x49, 0x00, 0x2F, 0xA7, 0x49, 0x00, 0x9B, 0xA6, 0x3C, 0x0D, 0xFC, 0x7E, 0x10, 0x05, 0x80, 0x00, + 0x49, 0x00, 0x11, 0xE7, 0x46, 0x00, 0x01, 0x24, 0x10, 0x10, 0x00, 0x52, 0x3C, 0x0F, 0xFC, 0x7B, + 0x58, 0x00, 0x00, 0x04, 0x44, 0x03, 0xF4, 0x1C, 0x3E, 0x07, 0xEF, 0x45, 0x44, 0x13, 0x4D, 0xA0, + 0x44, 0x12, 0xA8, 0x2A, 0x3C, 0x03, 0xF7, 0xC4, 0x04, 0x05, 0x00, 0x05, 0x44, 0x23, 0x77, 0x08, + 0x00, 0x0F, 0x80, 0x0F, 0x3E, 0x07, 0xEF, 0x75, 0x44, 0x42, 0xC2, 0x90, 0x44, 0x90, 0x00, 0x55, + 0x44, 0x10, 0x00, 0x54, 0x44, 0x12, 0xDA, 0x54, 0x44, 0x12, 0xA6, 0x9A, 0x3E, 0x07, 0xF2, 0xBB, + 0x49, 0x00, 0x31, 0x6D, 0x54, 0x90, 0x00, 0xFF, 0x64, 0x13, 0x24, 0x03, 0x10, 0x93, 0x80, 0x00, + 0x44, 0x02, 0xD7, 0x04, 0x50, 0x3F, 0x80, 0x07, 0x3C, 0x0B, 0xF7, 0xC8, 0x52, 0x00, 0x00, 0x01, + 0x2E, 0x07, 0xEE, 0xD7, 0x3C, 0x0D, 0xFE, 0x4B, 0x44, 0x70, 0x00, 0x55, 0x3E, 0x07, 0xEA, 0xE0, + 0x3B, 0x00, 0x4C, 0x00, 0x42, 0x00, 0x00, 0x03, 0x2E, 0x07, 0xF3, 0x08, 0x2E, 0x07, 0xEE, 0xDC, + 0x44, 0x02, 0x00, 0x00, 0x44, 0x02, 0x00, 0x00, 0x49, 0x00, 0x87, 0x03, 0x3C, 0x1D, 0xFC, 0x9A, + 0x3E, 0x07, 0xEF, 0x2E, 0x49, 0x00, 0x92, 0x2F, 0x2E, 0x07, 0xF2, 0xBA, 0x3E, 0x07, 0xF2, 0xE3, + 0x40, 0x00, 0x81, 0x00, 0x44, 0x13, 0x65, 0x10, 0x44, 0x12, 0xA0, 0x5A, 0x50, 0x2F, 0x80, 0x0F, + 0x3C, 0x1D, 0xFC, 0x2B, 0x49, 0x00, 0x61, 0x1A, 0x3B, 0x00, 0x64, 0x04, 0x38, 0x34, 0x9A, 0x0A, + 0x3C, 0x7F, 0xFC, 0x03, 0x3C, 0xF7, 0xFB, 0x35, 0x2E, 0x07, 0xEE, 0xBA, 0x5C, 0xF0, 0x00, 0x32, + 0x3C, 0x0D, 0xFC, 0x0B, 0x3E, 0x00, 0x0D, 0xDD, 0x40, 0x10, 0x88, 0x36, 0x44, 0x10, 0x00, 0xA4, + 0x3E, 0x67, 0xF3, 0x70, 0x3C, 0x0F, 0xFC, 0x6F, 0x10, 0x10, 0x00, 0x42, 0x42, 0x13, 0x00, 0x73, + 0x2E, 0x07, 0xEF, 0x5A, 0x49, 0x00, 0x77, 0x0C, 0x49, 0x00, 0x7B, 0xBA, 0x2E, 0x17, 0xF3, 0xCB, + 0x44, 0x12, 0xD6, 0xAC, 0x42, 0x13, 0x80, 0x73, 0x49, 0x00, 0x36, 0xDA, 0x2E, 0x07, 0xF2, 0xD5, + 0x3E, 0x07, 0xF2, 0xBA, 0x44, 0x1F, 0xFF, 0xA0, 0x49, 0x00, 0x7D, 0xFC, 0x44, 0x20, 0x00, 0x40, + 0x3E, 0x07, 0xEF, 0x35, 0x42, 0xF1, 0x00, 0x03, 0x44, 0x12, 0xC4, 0xD0, 0x44, 0x32, 0x00, 0x00, + 0x3E, 0x07, 0xF2, 0xC3, 0x44, 0x11, 0x6B, 0xF4, 0x49, 0x00, 0x13, 0x25, 0x44, 0x12, 0xBC, 0x06, + 0x49, 0x00, 0x2F, 0xE4, 0x3E, 0x07, 0xEE, 0xEE, 0x3E, 0x07, 0xF4, 0x1D, 0x49, 0x00, 0x3D, 0x17, + 0x3A, 0x10, 0x04, 0x20, 0x38, 0x10, 0x9A, 0x02, 0x40, 0x00, 0x80, 0x20, 0x3E, 0x07, 0xEE, 0xB3, + 0x2E, 0x07, 0xEF, 0x1E, 0x3C, 0x0B, 0xFB, 0x42, 0x2E, 0x07, 0xEA, 0xE0, 0x10, 0x07, 0x00, 0x00, + 0x44, 0x10, 0x00, 0x64, 0x42, 0x00, 0x08, 0x0B, 0x44, 0x00, 0x00, 0x41, 0x3E, 0x07, 0xF4, 0x29, + 0x00, 0x05, 0x00, 0x00, 0x49, 0x00, 0xA3, 0xC7, 0x3C, 0x0B, 0xF7, 0xC7, 0x44, 0x03, 0xF7, 0xC3, + 0x44, 0x40, 0x00, 0x55, 0x3E, 0x07, 0xEF, 0x69, 0x38, 0x04, 0x9A, 0x02, 0x2E, 0x17, 0xEE, 0xBE, + 0x2E, 0x07, 0x34, 0x9E, 0x49, 0x00, 0x30, 0x16, 0x49, 0x00, 0x54, 0x72, 0x44, 0x12, 0xDE, 0x64, + 0x2E, 0x07, 0xEF, 0x30, 0x44, 0x12, 0x16, 0x80, 0x2E, 0x17, 0xEE, 0xF4, 0x44, 0x02, 0xBC, 0xB0, + 0x49, 0x00, 0x7F, 0xEC, 0x44, 0x12, 0xBB, 0xC6, 0x42, 0x00, 0x0C, 0x0B, 0x3E, 0x07, 0xEE, 0xB5, + 0x44, 0x13, 0xF7, 0xC4, 0x49, 0x00, 0x88, 0x7A, 0x3E, 0x07, 0xF3, 0x55, 0x49, 0x00, 0x87, 0x0D, + 0x49, 0x00, 0x17, 0xD3, 0x44, 0x20, 0x00, 0x64, 0x42, 0x42, 0x00, 0x03, 0x3C, 0x0C, 0x01, 0xC9, + 0x49, 0x00, 0x1C, 0x01, 0x3E, 0x07, 0xF3, 0x02, 0x2E, 0x07, 0xF2, 0xBB, 0x3E, 0x07, 0xF3, 0x08, + 0x3C, 0x0F, 0xFC, 0x37, 0x3C, 0x1D, 0xFC, 0xF1, 0x12, 0x0F, 0x80, 0x0B, 0x40, 0x01, 0x80, 0x20, + 0x66, 0x10, 0x80, 0x02, 0x40, 0x20, 0x88, 0x0C, 0x38, 0x60, 0x80, 0x00, 0x14, 0xBF, 0x80, 0x03, + 0x49, 0x00, 0xAE, 0x04, 0x40, 0x11, 0xBC, 0x1B, 0x49, 0x00, 0x1C, 0x05, 0x10, 0x00, 0x80, 0x51, + 0x3E, 0x07, 0xF3, 0xCA, 0x3E, 0x67, 0xF0, 0x70, 0x44, 0x13, 0x50, 0xC0, 0x44, 0x02, 0xDD, 0xA4, + 0x3C, 0x0F, 0xFC, 0x65, 0x3C, 0x0C, 0x01, 0xC6, 0x44, 0x13, 0x4F, 0x30, 0x38, 0x00, 0x99, 0x09, + 0x50, 0x1F, 0x80, 0x3E, 0x44, 0x12, 0xA3, 0x7A, 0x40, 0x10, 0x80, 0x20, 0x49, 0x00, 0x30, 0xEC, + 0x49, 0x00, 0x9B, 0x99, 0x04, 0x10, 0x00, 0x14, 0x49, 0x00, 0x1C, 0x05, 0x2E, 0x07, 0xF3, 0x52, + 0x00, 0x05, 0x80, 0x00, 0x44, 0x22, 0xD7, 0x60, 0x54, 0x00, 0x00, 0xFD, 0x3C, 0x17, 0xFB, 0x37, + 0x44, 0x03, 0x8D, 0x41, 0x44, 0x12, 0xBF, 0xCC, 0x44, 0x12, 0xBB, 0x36, 0x49, 0x00, 0x7B, 0x9E, + 0x10, 0x06, 0x80, 0x4F, 0x3B, 0x01, 0x4C, 0x00, 0x44, 0x22, 0xD9, 0xD0, 0x44, 0x10, 0x00, 0xA5, + 0x3C, 0x0B, 0xFB, 0x52, 0x49, 0x00, 0x97, 0xEA, 0x38, 0x00, 0x1A, 0x02, 0x44, 0x10, 0x00, 0x4C, + 0x3E, 0x07, 0xEF, 0x4A, 0x04, 0x15, 0x00, 0x08, 0x02, 0x05, 0x80, 0x00, 0x3E, 0x07, 0xF3, 0x73, + 0x44, 0x03, 0xF7, 0xC6, 0x44, 0x12, 0xA1, 0xEA, 0x3C, 0x03, 0xF7, 0xDF, 0x42, 0x00, 0x54, 0x08, + 0x44, 0x02, 0xFE, 0x60, 0x44, 0x50, 0x00, 0x78, 0x44, 0x10, 0x03, 0xE8, 0x44, 0x13, 0x00, 0x00, + 0x3E, 0x07, 0xEE, 0xB4, 0x42, 0x03, 0x84, 0x73, 0x3E, 0x07, 0xF4, 0x28, 0x44, 0x13, 0x8D, 0x40, + 0x3C, 0x0F, 0xFC, 0x5B, 0x44, 0x03, 0xF7, 0xC0, 0x00, 0x03, 0x00, 0x85, 0x44, 0x03, 0xF7, 0xC2, + 0x2E, 0x07, 0x34, 0x12, 0x00, 0x30, 0x00, 0x0E, 0x38, 0x08, 0x0C, 0x08, 0x10, 0x10, 0x00, 0x08, + 0x49, 0x00, 0x3D, 0x17, 0x44, 0x03, 0xF3, 0x66, 0x40, 0x00, 0x80, 0x16, 0x44, 0x12, 0xBC, 0x78, + 0x2E, 0x07, 0xF3, 0x70, 0x3C, 0x0F, 0xFC, 0x08, 0x2E, 0x17, 0xF4, 0x3A, 0x49, 0x00, 0x18, 0x69, + 0x18, 0x12, 0x80, 0x01, 0x44, 0x03, 0x30, 0x70, 0x12, 0x04, 0x80, 0x01, 0x3C, 0x0D, 0xFD, 0x22, + 0x3C, 0x0B, 0xF7, 0xC4, 0x02, 0x15, 0x80, 0x00, 0x3E, 0x07, 0x34, 0x9E, 0x44, 0x12, 0x18, 0x10, + 0x3C, 0x0D, 0xFC, 0x2B, 0x44, 0x13, 0xF7, 0xC7, 0x49, 0x00, 0x6D, 0xEF, 0x49, 0x00, 0x18, 0x59, + 0x49, 0x00, 0x87, 0x03, 0x44, 0x13, 0xF7, 0xC1, 0x02, 0xF3, 0x80, 0x00, 0x3C, 0x0C, 0x01, 0xC8, + 0x44, 0x03, 0xF0, 0x80, 0x3E, 0x07, 0xF3, 0x09, 0x49, 0x00, 0x94, 0x3F, 0x40, 0x00, 0x80, 0x06, + 0x44, 0x12, 0xBF, 0xB8, 0x3E, 0x00, 0x01, 0xBD, 0x49, 0x00, 0x92, 0xA0, 0x50, 0x1F, 0x80, 0x36, + 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x2C, 0x01, 0x00, 0x00, + 0x30, 0x01, 0x00, 0x00, 0x34, 0x01, 0x00, 0x00, 0x38, 0x01, 0x00, 0x00, 0x3C, 0x01, 0x00, 0x00, + 0x40, 0x01, 0x00, 0x00, 0x44, 0x01, 0x00, 0x00, 0x48, 0x01, 0x00, 0x00, 0x4C, 0x01, 0x00, 0x00, + 0x50, 0x01, 0x00, 0x00, 0x54, 0x01, 0x00, 0x00, 0x58, 0x01, 0x00, 0x00, 0x5C, 0x01, 0x00, 0x00, + 0x60, 0x01, 0x00, 0x00, 0x64, 0x01, 0x00, 0x00, 0x68, 0x01, 0x00, 0x00, 0x6C, 0x01, 0x00, 0x00, + 0x70, 0x01, 0x00, 0x00, 0x74, 0x01, 0x00, 0x00, 0x78, 0x01, 0x00, 0x00, 0x7C, 0x01, 0x00, 0x00, + 0x80, 0x01, 0x00, 0x00, 0x84, 0x01, 0x00, 0x00, 0x88, 0x01, 0x00, 0x00, 0x8C, 0x01, 0x00, 0x00, + 0x90, 0x01, 0x00, 0x00, 0x94, 0x01, 0x00, 0x00, 0x98, 0x01, 0x00, 0x00, 0x9C, 0x01, 0x00, 0x00, + 0xA0, 0x01, 0x00, 0x00, 0xA4, 0x01, 0x00, 0x00, 0xA8, 0x01, 0x00, 0x00, 0xAC, 0x01, 0x00, 0x00, + 0xB0, 0x01, 0x00, 0x00, 0xB4, 0x01, 0x00, 0x00, 0xB8, 0x01, 0x00, 0x00, 0xBC, 0x01, 0x00, 0x00, + 0xC0, 0x01, 0x00, 0x00, 0xC4, 0x01, 0x00, 0x00, 0xC8, 0x01, 0x00, 0x00, 0xCC, 0x01, 0x00, 0x00, + 0xD0, 0x01, 0x00, 0x00, 0xD4, 0x01, 0x00, 0x00, 0xD8, 0x01, 0x00, 0x00, 0xDC, 0x01, 0x00, 0x00, + 0xE0, 0x01, 0x00, 0x00, 0xE4, 0x01, 0x00, 0x00, 0xE8, 0x01, 0x00, 0x00, 0xEC, 0x01, 0x00, 0x00, + 0xF0, 0x01, 0x00, 0x00, 0xF4, 0x01, 0x00, 0x00, 0xF8, 0x01, 0x00, 0x00, 0xFC, 0x01, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x00, 0x04, 0x02, 0x00, 0x00, 0x08, 0x02, 0x00, 0x00, 0x0C, 0x02, 0x00, 0x00, + 0x10, 0x02, 0x00, 0x00, 0x14, 0x02, 0x00, 0x00, 0x18, 0x02, 0x00, 0x00, 0x1C, 0x02, 0x00, 0x00, + 0x20, 0x02, 0x00, 0x00, 0x24, 0x02, 0x00, 0x00, 0x28, 0x02, 0x00, 0x00, 0x2C, 0x02, 0x00, 0x00, + 0x30, 0x02, 0x00, 0x00, 0x34, 0x02, 0x00, 0x00, 0x38, 0x02, 0x00, 0x00, 0x3C, 0x02, 0x00, 0x00, + 0x40, 0x02, 0x00, 0x00, 0x44, 0x02, 0x00, 0x00, 0x48, 0x02, 0x00, 0x00, 0x4C, 0x02, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00, + 0x30, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, + 0x40, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x4C, 0x00, 0x00, 0x00, + 0x50, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x5C, 0x00, 0x00, 0x00, + 0x60, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x6C, 0x00, 0x00, 0x00, + 0x70, 0x00, 0x00, 0x00, 0x74, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0x8C, 0x00, 0x00, 0x00, + 0x90, 0x00, 0x00, 0x00, 0x94, 0x00, 0x00, 0x00, 0x98, 0x00, 0x00, 0x00, 0x9C, 0x00, 0x00, 0x00, + 0xA0, 0x00, 0x00, 0x00, 0xA4, 0x00, 0x00, 0x00, 0xA8, 0x00, 0x00, 0x00, 0xAC, 0x00, 0x00, 0x00, + 0xB0, 0x00, 0x00, 0x00, 0xB4, 0x00, 0x00, 0x00, 0xB8, 0x00, 0x00, 0x00, 0xBC, 0x00, 0x00, 0x00, + 0xC0, 0x00, 0x00, 0x00, 0xC4, 0x00, 0x00, 0x00, 0xC8, 0x00, 0x00, 0x00, 0xCC, 0x00, 0x00, 0x00, + 0xD0, 0x00, 0x00, 0x00, 0xD4, 0x00, 0x00, 0x00, 0xD8, 0x00, 0x00, 0x00, 0xDC, 0x00, 0x00, 0x00, + 0xE0, 0x00, 0x00, 0x00, 0xE4, 0x00, 0x00, 0x00, 0xE8, 0x00, 0x00, 0x00, 0xEC, 0x00, 0x00, 0x00, + 0xF0, 0x00, 0x00, 0x00, 0xF4, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x04, 0x01, 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x0C, 0x01, 0x00, 0x00, + 0x10, 0x01, 0x00, 0x00, 0x14, 0x01, 0x00, 0x00, 0x18, 0x01, 0x00, 0x00, 0x1C, 0x01, 0x00, 0x00, + 0x20, 0x01, 0x00, 0x00, 0xE8, 0x73, 0x03, 0x00, 0xF8, 0x74, 0x02, 0x00, 0xA0, 0x0F, 0x03, 0x00, + 0x68, 0x80, 0x03, 0x00, 0x10, 0x33, 0x03, 0x00, 0x90, 0x3F, 0x03, 0x00, 0x10, 0x4C, 0x03, 0x00, + 0x90, 0x58, 0x03, 0x00, 0x84, 0x92, 0x03, 0x00, 0x14, 0x94, 0x03, 0x00, 0xFA, 0xAF, 0x02, 0x00, + 0x8A, 0xB1, 0x02, 0x00, 0x64, 0x8F, 0x03, 0x00, 0xF4, 0x90, 0x03, 0x00, 0xDA, 0xAC, 0x02, 0x00, + 0x6A, 0xAE, 0x02, 0x00, 0x10, 0x33, 0x03, 0x00, 0x90, 0x3F, 0x03, 0x00, 0x10, 0x4C, 0x03, 0x00, + 0x90, 0x58, 0x03, 0x00, 0x80, 0xB2, 0x01, 0x00, 0x00, 0xBF, 0x01, 0x00, 0x80, 0xCB, 0x01, 0x00, + 0x00, 0xD8, 0x01, 0x00, 0x90, 0xE4, 0x01, 0x00, 0xD0, 0xEA, 0x01, 0x00, 0x10, 0xF1, 0x01, 0x00, + 0x50, 0xF7, 0x01, 0x00, 0xE8, 0x73, 0x03, 0x00, 0xF8, 0x74, 0x02, 0x00, 0xA0, 0x0F, 0x03, 0x00, + 0x68, 0x80, 0x03, 0x00, 0x01, 0x02, 0x03, 0x00, 0x01, 0x02, 0x03, 0x00, 0x01, 0x02, 0x03, 0x00, + 0x01, 0x02, 0x03, 0x00, 0x01, 0x02, 0x03, 0x00, 0x01, 0x02, 0x03, 0x00, 0x01, 0x02, 0x03, 0x00, + 0x01, 0x02, 0x03, 0x00, 0x01, 0x02, 0x03, 0x00, 0x01, 0x02, 0x03, 0x00, 0x01, 0x02, 0x03, 0x00, + 0x01, 0x02, 0x03, 0x00, 0xE3, 0x00, 0x02, 0x01, 0x36, 0x01, 0x1B, 0x01, 0xE4, 0x00, 0xFC, 0x00, + 0x1C, 0x01, 0x09, 0x01, 0xDD, 0x00, 0xEE, 0x00, 0x0C, 0x01, 0x00, 0x01, 0xE6, 0x00, 0xEA, 0x00, + 0x00, 0x01, 0xFF, 0x00, 0xE1, 0x00, 0xEE, 0x00, 0x11, 0x01, 0xFE, 0x00, 0xE5, 0x00, 0xEA, 0x00, + 0x05, 0x01, 0xEE, 0x00, 0xDC, 0x00, 0xDD, 0x00, 0x08, 0x01, 0x04, 0x01, 0xDB, 0x00, 0xE9, 0x00, + 0x04, 0x01, 0x03, 0x01, 0xDB, 0x00, 0xE0, 0x00, 0x03, 0x01, 0xF3, 0x00, 0xD2, 0x00, 0xE1, 0x00, + 0xF7, 0x00, 0xF3, 0x00, 0xD0, 0x00, 0xE0, 0x00, 0xF5, 0x00, 0xE8, 0x00, 0xC2, 0x00, 0xD5, 0x00, + 0xEA, 0x00, 0xE6, 0x00, 0xC9, 0x00, 0xDA, 0x00, 0xDD, 0x00, 0xDD, 0x00, 0xC8, 0x00, 0xDC, 0x00, + 0xD8, 0x00, 0xD1, 0x00, 0xCA, 0x00, 0xE2, 0x00, 0xD5, 0x00, 0xDD, 0x00, 0xC5, 0x00, 0xE4, 0x00, + 0xDB, 0x00, 0xD5, 0x00, 0xBF, 0x00, 0xDF, 0x00, 0xDC, 0x00, 0xD6, 0x00, 0xC4, 0x00, 0xDE, 0x00, + 0xDF, 0x00, 0xD1, 0x00, 0xC5, 0x00, 0xE7, 0x00, 0xEA, 0x00, 0xD3, 0x00, 0xC4, 0x00, 0xE8, 0x00, + 0xE6, 0x00, 0xDF, 0x00, 0xB2, 0x00, 0xD3, 0x00, 0xE1, 0x00, 0xDA, 0x00, 0xB5, 0x00, 0xD0, 0x00, + 0xE8, 0x00, 0xD0, 0x00, 0xB4, 0x00, 0xD1, 0x00, 0xCD, 0x00, 0xCC, 0x00, 0xC3, 0x00, 0xDD, 0x00, + 0xE1, 0x00, 0xD0, 0x00, 0xC0, 0x00, 0xD5, 0x00, 0xE0, 0x00, 0xCE, 0x00, 0xB4, 0x00, 0xCB, 0x00, + 0xE1, 0x00, 0xCA, 0x00, 0xB3, 0x00, 0xDE, 0x00, 0xE2, 0x00, 0xC1, 0x00, 0xB3, 0x00, 0xD4, 0x00, + 0xE2, 0x00, 0xC4, 0x00, 0xC0, 0x00, 0xDC, 0x00, 0xD8, 0x00, 0xBC, 0x00, 0xB9, 0x00, 0xDE, 0x00, + 0xDD, 0x00, 0xB8, 0x00, 0xB1, 0x00, 0xC3, 0x00, 0xD3, 0x00, 0xB1, 0x00, 0xAF, 0x00, 0xBE, 0x00, + 0xD0, 0x00, 0xBC, 0x00, 0xA7, 0x00, 0xAC, 0x00, 0xCC, 0x00, 0xBB, 0x00, 0x92, 0x00, 0xB1, 0x00, + 0xC9, 0x00, 0xB4, 0x00, 0x98, 0x00, 0xA8, 0x00, 0xCA, 0x00, 0xAF, 0x00, 0x97, 0x00, 0xA6, 0x00, + 0xC7, 0x00, 0xB1, 0x00, 0x98, 0x00, 0x9D, 0x00, 0xC8, 0x00, 0xA7, 0x00, 0x96, 0x00, 0x96, 0x00, + 0xA5, 0x00, 0xA1, 0x00, 0x99, 0x00, 0x99, 0x00, 0xA8, 0x00, 0xA7, 0x00, 0x95, 0x00, 0x92, 0x00, + 0xA4, 0x00, 0xA0, 0x00, 0x8D, 0x00, 0x91, 0x00, 0xAC, 0x00, 0x9C, 0x00, 0x8C, 0x00, 0x8F, 0x00, + 0xAF, 0x00, 0x98, 0x00, 0x92, 0x00, 0x95, 0x00, 0xB1, 0x00, 0x99, 0x00, 0x91, 0x00, 0x9B, 0x00, + 0xB0, 0x00, 0x94, 0x00, 0x8D, 0x00, 0x9B, 0x00, 0x95, 0x00, 0x85, 0x00, 0x9B, 0x00, 0xA5, 0x00, + 0x92, 0x00, 0x88, 0x00, 0xA3, 0x00, 0xA6, 0x00, 0x90, 0x00, 0x80, 0x00, 0xB7, 0x00, 0xB0, 0x00, + 0x95, 0x00, 0x87, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, + 0x80, 0x00, 0x80, 0x00, 0x14, 0x01, 0x1F, 0x01, 0x29, 0x01, 0x3D, 0x01, 0x32, 0x01, 0x3E, 0x01, + 0x47, 0x01, 0x5B, 0x01, 0xE4, 0x01, 0xAD, 0x01, 0x84, 0x01, 0x5A, 0x01, 0x16, 0x01, 0xD0, 0x00, + 0x05, 0x01, 0x3E, 0x01, 0xF3, 0x00, 0xFB, 0x00, 0x05, 0x01, 0x18, 0x01, 0x12, 0x01, 0x23, 0x01, + 0x36, 0x01, 0x50, 0x01, 0xE8, 0x01, 0xC8, 0x01, 0x90, 0x01, 0x71, 0x01, 0x3D, 0x01, 0x01, 0x01, + 0x3D, 0x01, 0x97, 0x01, 0xDF, 0x00, 0xE4, 0x00, 0xFB, 0x00, 0x13, 0x01, 0x13, 0x01, 0x41, 0x01, + 0x48, 0x01, 0x49, 0x01, 0xCD, 0x01, 0x9D, 0x01, 0x8B, 0x01, 0x5F, 0x01, 0x15, 0x01, 0xD5, 0x00, + 0x08, 0x01, 0x46, 0x01, 0xD9, 0x00, 0xFB, 0x00, 0x20, 0x01, 0x49, 0x01, 0x32, 0x01, 0x3D, 0x01, + 0x46, 0x01, 0x58, 0x01, 0xDC, 0x01, 0xA7, 0x01, 0x82, 0x01, 0x54, 0x01, 0x18, 0x01, 0xF0, 0x00, + 0x17, 0x01, 0x63, 0x01, 0xAC, 0x00, 0xBE, 0x00, 0xC7, 0x00, 0xD3, 0x00, 0xEC, 0x00, 0xFC, 0x00, + 0x14, 0x01, 0x17, 0x01, 0x84, 0x01, 0x4A, 0x01, 0x35, 0x01, 0x0B, 0x01, 0xE6, 0x00, 0xBB, 0x00, + 0xF1, 0x00, 0x2B, 0x01, 0xB6, 0x00, 0xD9, 0x00, 0xEB, 0x00, 0xFA, 0x00, 0x11, 0x01, 0x22, 0x01, + 0x3B, 0x01, 0x45, 0x01, 0xB5, 0x01, 0x71, 0x01, 0x53, 0x01, 0x2A, 0x01, 0x01, 0x01, 0xD2, 0x00, + 0x0E, 0x01, 0x59, 0x01, 0xA8, 0x00, 0xB4, 0x00, 0xC5, 0x00, 0xCC, 0x00, 0xEC, 0x00, 0xF3, 0x00, + 0x07, 0x01, 0x0A, 0x01, 0x6F, 0x01, 0x46, 0x01, 0x21, 0x01, 0xFE, 0x00, 0xD1, 0x00, 0xB5, 0x00, + 0xE3, 0x00, 0x21, 0x01, 0xA8, 0x00, 0xBC, 0x00, 0xCC, 0x00, 0xE3, 0x00, 0xF1, 0x00, 0xEF, 0x00, + 0x1D, 0x01, 0x25, 0x01, 0x7D, 0x01, 0x56, 0x01, 0x2F, 0x01, 0xFE, 0x00, 0xD4, 0x00, 0xB8, 0x00, + 0xE8, 0x00, 0x38, 0x01, 0xB3, 0x00, 0xBF, 0x00, 0xD9, 0x00, 0xD6, 0x00, 0xFD, 0x00, 0x0C, 0x01, + 0x25, 0x01, 0x27, 0x01, 0x6F, 0x01, 0x41, 0x01, 0x1C, 0x01, 0xE1, 0x00, 0xC4, 0x00, 0xAA, 0x00, + 0xE0, 0x00, 0x0C, 0x01, 0x9D, 0x00, 0xA3, 0x00, 0xBF, 0x00, 0xC6, 0x00, 0xE5, 0x00, 0xE1, 0x00, + 0x01, 0x01, 0x03, 0x01, 0x43, 0x01, 0x18, 0x01, 0x01, 0x01, 0xD0, 0x00, 0xB0, 0x00, 0x91, 0x00, + 0xBE, 0x00, 0xEF, 0x00, 0xC8, 0x00, 0xC3, 0x00, 0xEA, 0x00, 0xE4, 0x00, 0xFD, 0x00, 0x05, 0x01, + 0x15, 0x01, 0x12, 0x01, 0x59, 0x01, 0x1B, 0x01, 0xF2, 0x00, 0xB7, 0x00, 0x88, 0x00, 0x9D, 0x00, + 0xCD, 0x00, 0xF6, 0x00, 0x80, 0x00, 0x8A, 0x00, 0xAF, 0x00, 0xB8, 0x00, 0xD2, 0x00, 0xD4, 0x00, + 0xFB, 0x00, 0x00, 0x01, 0x59, 0x01, 0x1D, 0x01, 0xF1, 0x00, 0xAC, 0x00, 0x85, 0x00, 0x8B, 0x00, + 0xB1, 0x00, 0xE4, 0x00, 0x36, 0x00, 0x3D, 0x00, 0x44, 0x00, 0x4C, 0x00, 0x56, 0x00, 0x60, 0x00, + 0x6B, 0x00, 0x77, 0x00, 0x85, 0x00, 0x93, 0x00, 0xA4, 0x00, 0xB5, 0x00, 0xC9, 0x00, 0xDE, 0x00, + 0xF5, 0x00, 0x0E, 0x01, 0x29, 0x01, 0x46, 0x01, 0x65, 0x01, 0x87, 0x01, 0xAC, 0x01, 0xD4, 0x01, + 0xFE, 0x01, 0x2B, 0x02, 0x5B, 0x02, 0x8F, 0x02, 0xC6, 0x02, 0x01, 0x03, 0x3F, 0x03, 0x80, 0x03, + 0xC6, 0x03, 0x0F, 0x04, 0x5D, 0x04, 0xAE, 0x04, 0x03, 0x05, 0x5D, 0x05, 0xBA, 0x05, 0x1B, 0x06, + 0x81, 0x06, 0xEA, 0x06, 0x57, 0x07, 0xC9, 0x07, 0x3D, 0x08, 0xB6, 0x08, 0x31, 0x09, 0xB0, 0x09, + 0x32, 0x0A, 0xB7, 0x0A, 0x3E, 0x0B, 0xC7, 0x0B, 0x52, 0x0C, 0xDF, 0x0C, 0x6D, 0x0D, 0xFC, 0x0D, + 0x8B, 0x0E, 0x1A, 0x0F, 0xA8, 0x0F, 0x36, 0x10, 0xC3, 0x10, 0x4D, 0x11, 0xD6, 0x11, 0x5B, 0x12, + 0xDE, 0x12, 0x5C, 0x13, 0xD7, 0x13, 0x4D, 0x14, 0xBD, 0x14, 0x28, 0x15, 0x8D, 0x15, 0xEC, 0x15, + 0x44, 0x16, 0x95, 0x16, 0xDE, 0x16, 0x1F, 0x17, 0x58, 0x17, 0x89, 0x17, 0xB1, 0x17, 0xD1, 0x17, + 0xE7, 0x17, 0xF5, 0x17, 0xFA, 0x17, 0x00, 0x00, 0x1E, 0x00, 0x23, 0x00, 0x27, 0x00, 0x2D, 0x00, + 0x33, 0x00, 0x3A, 0x00, 0x42, 0x00, 0x4A, 0x00, 0x54, 0x00, 0x5F, 0x00, 0x6B, 0x00, 0x78, 0x00, + 0x87, 0x00, 0x97, 0x00, 0xA9, 0x00, 0xBC, 0x00, 0xD2, 0x00, 0xE9, 0x00, 0x03, 0x01, 0x1F, 0x01, + 0x3E, 0x01, 0x60, 0x01, 0x84, 0x01, 0xAB, 0x01, 0xD6, 0x01, 0x04, 0x02, 0x35, 0x02, 0x6A, 0x02, + 0xA3, 0x02, 0xE0, 0x02, 0x21, 0x03, 0x67, 0x03, 0xB1, 0x03, 0xFF, 0x03, 0x52, 0x04, 0xAA, 0x04, + 0x07, 0x05, 0x68, 0x05, 0xCF, 0x05, 0x3A, 0x06, 0xAA, 0x06, 0x1F, 0x07, 0x99, 0x07, 0x17, 0x08, + 0x9A, 0x08, 0x22, 0x09, 0xAD, 0x09, 0x3D, 0x0A, 0xD0, 0x0A, 0x66, 0x0B, 0xFF, 0x0B, 0x9B, 0x0C, + 0x3A, 0x0D, 0xDA, 0x0D, 0x7B, 0x0E, 0x1D, 0x0F, 0xC0, 0x0F, 0x62, 0x10, 0x04, 0x11, 0xA4, 0x11, + 0x42, 0x12, 0xDE, 0x12, 0x76, 0x13, 0x0B, 0x14, 0x9B, 0x14, 0x26, 0x15, 0xAB, 0x15, 0x2B, 0x16, + 0xA3, 0x16, 0x14, 0x17, 0x7D, 0x17, 0xDE, 0x17, 0x36, 0x18, 0x84, 0x18, 0xC9, 0x18, 0x04, 0x19, + 0x35, 0x19, 0x5B, 0x19, 0x76, 0x19, 0x87, 0x19, 0x8C, 0x19, 0x00, 0x00, 0x0F, 0x2A, 0x55, 0xAA, + 0x00, 0x00, 0x05, 0x00, 0x0A, 0x00, 0x14, 0x00, 0x00, 0x2D, 0x91, 0x1A, 0x09, 0x0E, 0x20, 0x07, + 0x94, 0x03, 0xCA, 0x01, 0xE5, 0x00, 0x73, 0x00, 0x39, 0x00, 0x1D, 0x00, 0x0E, 0x00, 0x07, 0x00, + 0x04, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x0A, 0x00, 0x0F, 0x00, + 0x15, 0x00, 0x1A, 0x00, 0x20, 0x00, 0x26, 0x00, 0x2C, 0x00, 0x32, 0x00, 0x39, 0x00, 0x40, 0x00, + 0x48, 0x00, 0x50, 0x00, 0x5A, 0x00, 0x64, 0x00, 0x6F, 0x00, 0x7B, 0x00, 0x89, 0x00, 0x99, 0x00, + 0xAD, 0x00, 0xC4, 0x00, 0xE0, 0x00, 0x04, 0x01, 0x33, 0x01, 0x75, 0x01, 0xD6, 0x01, 0x77, 0x02, + 0xB9, 0x03, 0x79, 0x07, 0x62, 0x16, 0x00, 0x00, 0x02, 0x14, 0x02, 0x15, 0x15, 0x14, 0x13, 0x02, + 0x02, 0x15, 0x13, 0x15, 0x02, 0x08, 0x14, 0x15, 0x15, 0x02, 0x04, 0x04, 0x02, 0x04, 0x04, 0x15, + 0x15, 0x06, 0x08, 0x06, 0x01, 0x08, 0x21, 0x05, 0x06, 0x06, 0x04, 0x07, 0x01, 0x04, 0x04, 0x06, + 0x01, 0x04, 0x05, 0x22, 0x06, 0x04, 0x04, 0x05, 0x06, 0x06, 0x01, 0x01, 0x08, 0x06, 0x06, 0x05, + 0x06, 0x07, 0x01, 0x01, 0x22, 0x04, 0x04, 0x01, 0x05, 0x22, 0x06, 0x04, 0x05, 0x05, 0x05, 0x01, + 0x06, 0x01, 0x01, 0x06, 0x05, 0x05, 0x01, 0x07, 0x01, 0x01, 0x04, 0x05, 0x01, 0x01, 0x05, 0x00, + 0xE8, 0x73, 0x03, 0x00, 0xF8, 0x74, 0x02, 0x00, 0xA0, 0x0F, 0x03, 0x00, 0x68, 0x80, 0x03, 0x00, + 0x90, 0xE4, 0x01, 0x00, 0xD0, 0xEA, 0x01, 0x00, 0x10, 0xF1, 0x01, 0x00, 0x50, 0xF7, 0x01, 0x00, + 0x00, 0x01, 0x02, 0x03, 0x20, 0x8E, 0x02, 0x00, 0x60, 0x94, 0x02, 0x00, 0xA0, 0x9A, 0x02, 0x00, + 0xE0, 0xA0, 0x02, 0x00, 0x10, 0x33, 0x03, 0x00, 0x90, 0x3F, 0x03, 0x00, 0x10, 0x4C, 0x03, 0x00, + 0x90, 0x58, 0x03, 0x00, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x05, 0xFA, 0x20, 0x32, 0x40, 0x06, 0x00, 0x0A, 0x0E, 0x0A, 0x00, 0x01, 0x01, 0x01, 0x08, 0x10, + 0x32, 0x00, 0x40, 0x06, 0x28, 0x0A, 0x00, 0x00, 0x00, 0x0C, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x03, 0x76, 0x5F, 0x04, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x01, 0x09, + 0x00, 0x01, 0x32, 0x34, 0x40, 0x06, 0x00, 0x00, 0x28, 0x19, 0x1A, 0x00, 0x00, 0x06, 0x30, 0x00, + 0x00, 0x06, 0x30, 0x00, 0x00, 0x06, 0x30, 0x00, 0x00, 0x06, 0x30, 0x00, 0x00, 0x06, 0x30, 0x00, + 0x00, 0x06, 0x30, 0x00, 0x00, 0x06, 0x30, 0x00, 0x00, 0x06, 0x30, 0x00, 0x80, 0xFF, 0x3F, 0x00, + 0x00, 0x06, 0x30, 0x00, 0x00, 0x06, 0x30, 0x00, 0x00, 0x06, 0x30, 0x00, 0x80, 0xFF, 0x3F, 0x00, + 0x00, 0x06, 0x30, 0x00, 0x00, 0x06, 0x30, 0x00, 0x00, 0x06, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, + 0x01, 0x01, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x0F, 0x00, 0x00, 0x00, 0x01, 0x07, 0x01, 0x03, 0x02, 0x03, 0x14, 0x00, 0x0A, 0x0A, 0x40, 0x00, + 0x02, 0x00, 0x8C, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xC8, 0x00, 0xC8, 0x00, 0x96, 0x00, 0xC8, 0x00, 0x07, 0x07, 0x80, 0x00, 0x80, 0x00, 0x05, 0x05, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x01, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, + 0x30, 0x00, 0x47, 0x00, 0x10, 0x00, 0x14, 0x00, 0xF9, 0xFF, 0xC4, 0xFF, 0xFF, 0x7F, 0xFF, 0x7F, + 0xFF, 0x7F, 0xFF, 0x7F, 0xC8, 0x00, 0x2C, 0x01, 0x32, 0x00, 0xFA, 0x00, 0x0A, 0x04, 0xB4, 0xB4, + 0x32, 0x32, 0x23, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x0D, 0x00, 0x00, 0x32, 0x0D, 0x00, + 0x00, 0x00, 0x00, 0x20, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, + 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x05, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x0F, 0x01, 0x14, 0x12, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0F, 0x23, 0x32, 0x46, 0x50, 0x00, 0x00, 0x00, 0x6A, 0x64, 0x50, 0x46, 0x3C, 0x3C, 0x3C, 0x3C, + 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x23, 0x32, 0x46, 0x50, 0x00, 0x00, 0x00, + 0x6A, 0x64, 0x50, 0x46, 0x3C, 0x3C, 0x3C, 0x3C, 0x0F, 0x14, 0x1E, 0x28, 0x00, 0x00, 0x00, 0x00, + 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0C, 0x19, 0x2D, 0x41, 0x50, 0x00, 0x00, 0x00, + 0x46, 0x55, 0x4B, 0x46, 0x46, 0x46, 0x46, 0x46, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x03, 0x14, 0x00, + 0x5F, 0x00, 0xF1, 0xFF, 0x14, 0x00, 0x0F, 0x00, 0x0A, 0x00, 0xBC, 0x02, 0x00, 0x00, 0x00, 0x00, + 0x78, 0x76, 0x00, 0x1E, 0x64, 0x00, 0x19, 0x00, 0x90, 0x01, 0x28, 0x00, 0x0F, 0x00, 0x0F, 0x00, + 0x68, 0x01, 0x2C, 0x01, 0xF4, 0x01, 0xF8, 0x02, 0x00, 0x00, 0x3F, 0x06, 0x00, 0x00, 0xFF, 0x09, + 0xF4, 0x01, 0x00, 0x00, 0x3F, 0x06, 0x00, 0x00, 0xFF, 0x09, 0x32, 0x14, 0x02, 0x1E, 0x1E, 0x32, + 0x02, 0x00, 0x64, 0x00, 0x46, 0x00, 0x1E, 0x00, 0x0A, 0x00, 0x35, 0x06, 0x0A, 0x00, 0xF5, 0x09, + 0x00, 0x00, 0x00, 0x00, 0x40, 0x06, 0x30, 0x00, 0x10, 0x00, 0x01, 0x00, 0x12, 0x00, 0x00, 0x00, + 0x3A, 0x00, 0x52, 0x00, 0x70, 0x00, 0x8F, 0x00, 0x6E, 0x01, 0x8E, 0x01, 0xAD, 0x01, 0xCE, 0x01, + 0xEC, 0x01, 0xAC, 0x02, 0xCC, 0x02, 0xEB, 0x02, 0x0B, 0x03, 0x2B, 0x03, 0xE7, 0x03, 0xFF, 0x03, + 0x37, 0x04, 0x28, 0x0A, 0x30, 0x00, 0x30, 0x00, 0x01, 0x00, 0x32, 0x00, 0x00, 0x00, 0x3C, 0x00, + 0x43, 0x00, 0x66, 0x00, 0x85, 0x00, 0xA9, 0x00, 0xC8, 0x00, 0xE9, 0x00, 0x09, 0x01, 0x2A, 0x01, + 0x6B, 0x01, 0x89, 0x01, 0xAB, 0x01, 0xC9, 0x01, 0xEB, 0x01, 0x09, 0x02, 0x2B, 0x02, 0x4A, 0x02, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x20, 0x00, 0x19, 0x45, 0x00, 0x00, 0xF1, 0x6C, 0x00, 0x00, + 0x84, 0xD9, 0x06, 0x00, 0x29, 0xB1, 0x01, 0x00, 0x10, 0x27, 0x00, 0x00, 0xC4, 0x09, 0x00, 0x00, + 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x01, 0x4B, 0x0F, 0x00, 0xB4, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, + 0x19, 0x45, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0xA4, 0x6B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x14, 0x14, 0x0A, 0x0A, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x14, 0x14, 0x14, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x40, 0x00, 0x32, 0x00, 0xE8, 0x03, 0x0F, 0x00, 0x08, 0x00, + 0xE1, 0x00, 0x64, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x0A, 0x00, 0x14, 0x0A, 0x1E, 0x3C, 0x28, 0x00, + 0xB4, 0x00, 0xFA, 0x00, 0x28, 0x64, 0x19, 0x64, 0x00, 0x00, 0x00, 0x00, 0xB4, 0x00, 0xFA, 0x00, + 0x1C, 0x02, 0x84, 0x03, 0x00, 0x00, 0x00, 0x01, 0x4F, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x78, 0x00, 0x0D, 0x0D, 0x0C, 0x0E, 0x46, 0x00, 0x32, 0x00, 0x64, 0x00, 0x0A, 0x00, 0x32, 0x00, + 0x64, 0x00, 0x32, 0x00, 0x64, 0x00, 0x0F, 0x02, 0xE8, 0xE8, 0xF8, 0x00, 0xF8, 0x00, 0x02, 0x00, + 0x19, 0x00, 0x00, 0x00, 0xA5, 0x00, 0xB3, 0x00, 0xC3, 0x00, 0xD4, 0x00, 0xE7, 0x00, 0xFA, 0x00, + 0x0F, 0x01, 0x26, 0x01, 0x3E, 0x01, 0x57, 0x01, 0x72, 0x01, 0x8F, 0x01, 0xAE, 0x01, 0xCF, 0x01, + 0xF1, 0x01, 0x16, 0x02, 0x3C, 0x02, 0x65, 0x02, 0x90, 0x02, 0xBD, 0x02, 0xED, 0x02, 0x1E, 0x03, + 0x52, 0x03, 0x89, 0x03, 0xC2, 0x03, 0xFE, 0x03, 0x3C, 0x04, 0x7C, 0x04, 0xBF, 0x04, 0x05, 0x05, + 0x4D, 0x05, 0x98, 0x05, 0xE5, 0x05, 0x35, 0x06, 0x87, 0x06, 0xDB, 0x06, 0x32, 0x07, 0x8A, 0x07, + 0xE5, 0x07, 0x42, 0x08, 0xA1, 0x08, 0x01, 0x09, 0x63, 0x09, 0xC7, 0x09, 0x2C, 0x0A, 0x92, 0x0A, + 0xF9, 0x0A, 0x60, 0x0B, 0xC8, 0x0B, 0x31, 0x0C, 0x9A, 0x0C, 0x02, 0x0D, 0x6B, 0x0D, 0xD2, 0x0D, + 0x39, 0x0E, 0x9F, 0x0E, 0x04, 0x0F, 0x67, 0x0F, 0xC8, 0x0F, 0x27, 0x10, 0x84, 0x10, 0xDE, 0x10, + 0x35, 0x11, 0x89, 0x11, 0xDA, 0x11, 0x28, 0x12, 0x71, 0x12, 0xB7, 0x12, 0xF8, 0x12, 0x35, 0x13, + 0x6D, 0x13, 0xA0, 0x13, 0xCF, 0x13, 0xF8, 0x13, 0x1C, 0x14, 0x3B, 0x14, 0x54, 0x14, 0x68, 0x14, + 0x76, 0x14, 0x7E, 0x14, 0x81, 0x14, 0xA5, 0x00, 0xB3, 0x00, 0xC3, 0x00, 0xD4, 0x00, 0xE7, 0x00, + 0xFA, 0x00, 0x0F, 0x01, 0x26, 0x01, 0x3E, 0x01, 0x57, 0x01, 0x72, 0x01, 0x8F, 0x01, 0xAE, 0x01, + 0xCF, 0x01, 0xF1, 0x01, 0x16, 0x02, 0x3C, 0x02, 0x65, 0x02, 0x90, 0x02, 0xBD, 0x02, 0xED, 0x02, + 0x1E, 0x03, 0x52, 0x03, 0x89, 0x03, 0xC2, 0x03, 0xFE, 0x03, 0x3C, 0x04, 0x7C, 0x04, 0xBF, 0x04, + 0x05, 0x05, 0x4D, 0x05, 0x98, 0x05, 0xE5, 0x05, 0x35, 0x06, 0x87, 0x06, 0xDB, 0x06, 0x32, 0x07, + 0x8A, 0x07, 0xE5, 0x07, 0x42, 0x08, 0xA1, 0x08, 0x01, 0x09, 0x63, 0x09, 0xC7, 0x09, 0x2C, 0x0A, + 0x92, 0x0A, 0xF9, 0x0A, 0x60, 0x0B, 0xC8, 0x0B, 0x31, 0x0C, 0x9A, 0x0C, 0x02, 0x0D, 0x6B, 0x0D, + 0xD2, 0x0D, 0x39, 0x0E, 0x9F, 0x0E, 0x04, 0x0F, 0x67, 0x0F, 0xC8, 0x0F, 0x27, 0x10, 0x84, 0x10, + 0xDE, 0x10, 0x35, 0x11, 0x89, 0x11, 0xDA, 0x11, 0x28, 0x12, 0x71, 0x12, 0xB7, 0x12, 0xF8, 0x12, + 0x35, 0x13, 0x6D, 0x13, 0xA0, 0x13, 0xCF, 0x13, 0xF8, 0x13, 0x1C, 0x14, 0x3B, 0x14, 0x54, 0x14, + 0x68, 0x14, 0x76, 0x14, 0x7E, 0x14, 0x81, 0x14, 0xA5, 0x00, 0xB3, 0x00, 0xC3, 0x00, 0xD4, 0x00, + 0xE7, 0x00, 0xFA, 0x00, 0x0F, 0x01, 0x26, 0x01, 0x3E, 0x01, 0x57, 0x01, 0x72, 0x01, 0x8F, 0x01, + 0xAE, 0x01, 0xCF, 0x01, 0xF1, 0x01, 0x16, 0x02, 0x3C, 0x02, 0x65, 0x02, 0x90, 0x02, 0xBD, 0x02, + 0xED, 0x02, 0x1E, 0x03, 0x52, 0x03, 0x89, 0x03, 0xC2, 0x03, 0xFE, 0x03, 0x3C, 0x04, 0x7C, 0x04, + 0xBF, 0x04, 0x05, 0x05, 0x4D, 0x05, 0x98, 0x05, 0xE5, 0x05, 0x35, 0x06, 0x87, 0x06, 0xDB, 0x06, + 0x32, 0x07, 0x8A, 0x07, 0xE5, 0x07, 0x42, 0x08, 0xA1, 0x08, 0x01, 0x09, 0x63, 0x09, 0xC7, 0x09, + 0x2C, 0x0A, 0x92, 0x0A, 0xF9, 0x0A, 0x60, 0x0B, 0xC8, 0x0B, 0x31, 0x0C, 0x9A, 0x0C, 0x02, 0x0D, + 0x6B, 0x0D, 0xD2, 0x0D, 0x39, 0x0E, 0x9F, 0x0E, 0x04, 0x0F, 0x67, 0x0F, 0xC8, 0x0F, 0x27, 0x10, + 0x84, 0x10, 0xDE, 0x10, 0x35, 0x11, 0x89, 0x11, 0xDA, 0x11, 0x28, 0x12, 0x71, 0x12, 0xB7, 0x12, + 0xF8, 0x12, 0x35, 0x13, 0x6D, 0x13, 0xA0, 0x13, 0xCF, 0x13, 0xF8, 0x13, 0x1C, 0x14, 0x3B, 0x14, + 0x54, 0x14, 0x68, 0x14, 0x76, 0x14, 0x7E, 0x14, 0x81, 0x14, 0xA5, 0x00, 0xB3, 0x00, 0xC3, 0x00, + 0xD4, 0x00, 0xE7, 0x00, 0xFA, 0x00, 0x0F, 0x01, 0x26, 0x01, 0x3E, 0x01, 0x57, 0x01, 0x72, 0x01, + 0x8F, 0x01, 0xAE, 0x01, 0xCF, 0x01, 0xF1, 0x01, 0x16, 0x02, 0x3C, 0x02, 0x65, 0x02, 0x90, 0x02, + 0xBD, 0x02, 0xED, 0x02, 0x1E, 0x03, 0x52, 0x03, 0x89, 0x03, 0xC2, 0x03, 0xFE, 0x03, 0x3C, 0x04, + 0x7C, 0x04, 0xBF, 0x04, 0x05, 0x05, 0x4D, 0x05, 0x98, 0x05, 0xE5, 0x05, 0x35, 0x06, 0x87, 0x06, + 0xDB, 0x06, 0x32, 0x07, 0x8A, 0x07, 0xE5, 0x07, 0x42, 0x08, 0xA1, 0x08, 0x01, 0x09, 0x63, 0x09, + 0xC7, 0x09, 0x2C, 0x0A, 0x92, 0x0A, 0xF9, 0x0A, 0x60, 0x0B, 0xC8, 0x0B, 0x31, 0x0C, 0x9A, 0x0C, + 0x02, 0x0D, 0x6B, 0x0D, 0xD2, 0x0D, 0x39, 0x0E, 0x9F, 0x0E, 0x04, 0x0F, 0x67, 0x0F, 0xC8, 0x0F, + 0x27, 0x10, 0x84, 0x10, 0xDE, 0x10, 0x35, 0x11, 0x89, 0x11, 0xDA, 0x11, 0x28, 0x12, 0x71, 0x12, + 0xB7, 0x12, 0xF8, 0x12, 0x35, 0x13, 0x6D, 0x13, 0xA0, 0x13, 0xCF, 0x13, 0xF8, 0x13, 0x1C, 0x14, + 0x3B, 0x14, 0x54, 0x14, 0x68, 0x14, 0x76, 0x14, 0x7E, 0x14, 0x81, 0x14, 0x55, 0x00, 0x55, 0x00, + 0x45, 0x00, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB4, 0x00, 0x18, 0x01, 0x32, 0x00, 0x05, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32, 0x05, 0x10, 0x3E, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x9D, 0x02, 0x00, 0x00, 0xC0, 0x02, 0x00, 0x00, 0xE3, 0x02, 0x00, 0x00, 0x06, 0x03, 0x00, 0x00, + 0x29, 0x03, 0x00, 0x00, 0x4C, 0x03, 0x00, 0x00, 0x6F, 0x03, 0x00, 0x00, 0x92, 0x03, 0x00, 0x00, + 0xB5, 0x03, 0x00, 0x00, 0xD8, 0x03, 0x00, 0x00, 0xFB, 0x03, 0x00, 0x00, 0x1E, 0x04, 0x00, 0x00, + 0x41, 0x04, 0x00, 0x00, 0x64, 0x04, 0x00, 0x00, 0x87, 0x04, 0x00, 0x00, 0xAA, 0x04, 0x00, 0x00, + 0xCD, 0x04, 0x00, 0x00, 0xF0, 0x04, 0x00, 0x00, 0x13, 0x05, 0x00, 0x00, 0x36, 0x05, 0x00, 0x00, + 0x59, 0x05, 0x00, 0x00, 0x20, 0x03, 0x00, 0x00, 0x14, 0x39, 0x2E, 0x01, 0x42, 0x39, 0x10, 0x05, + 0xC6, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0xDC, 0x55, 0x20, 0x05, 0x02, 0x02, 0x52, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xB0, 0x00, 0x0B, 0x00, 0x00, 0x10, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x7C, 0x05, 0x16, 0x07, + 0x4E, 0x07, 0x48, 0x08, 0xC1, 0x0A, 0x6C, 0x08, 0xEC, 0x09, 0x31, 0x0A, 0x51, 0x0A, 0x7E, 0x17, + 0x07, 0xB8, 0xC3, 0x07, 0x00, 0x80, 0x00, 0x00, 0x20, 0x83, 0x00, 0x00, 0x00, 0x80, 0x32, 0x80, + 0x64, 0x80, 0x96, 0x80, 0x2D, 0xB4, 0x04, 0x0F, 0x11, 0x0C, 0x0F, 0x0F, 0x10, 0x00, 0x0F, 0x13, + 0xA5, 0xBB, 0x83, 0x1E, 0x18, 0xC8, 0x0F, 0x00, 0x15, 0x10, 0x15, 0x10, 0x10, 0x43, 0x10, 0x43, + 0x20, 0x03, 0x00, 0x00, 0x14, 0x39, 0x32, 0x0A, 0x4D, 0x20, 0x38, 0x03, 0xC4, 0x03, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0C, 0x00, 0x00, 0x00, 0xDC, 0x55, 0x55, 0x20, 0x05, 0x52, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xF8, 0xB0, 0xB9, 0x00, 0x0B, 0xB0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x7C, 0x05, 0x16, 0x07, 0x4E, 0x07, 0x48, 0x08, + 0xC1, 0x0A, 0x6C, 0x08, 0xEC, 0x09, 0x31, 0x0A, 0x51, 0x0A, 0x7E, 0x17, 0x07, 0xB8, 0xC3, 0x07, + 0x00, 0x80, 0x00, 0x00, 0x20, 0x83, 0x00, 0x00, 0x00, 0x80, 0x32, 0x80, 0x64, 0x80, 0x96, 0x80, + 0x2D, 0xB4, 0x04, 0x0F, 0x11, 0x0C, 0x0F, 0x0F, 0x10, 0x00, 0x0F, 0x13, 0xA5, 0xBB, 0x83, 0x1E, + 0x18, 0xC8, 0x0F, 0x00, 0x15, 0x10, 0x15, 0x10, 0x10, 0x43, 0x10, 0x43, 0x20, 0x03, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x7C, 0x05, 0x16, 0x07, 0x4E, 0x07, 0x48, 0x08, 0xC1, 0x0A, 0x6C, 0x08, + 0xEC, 0x09, 0x31, 0x0A, 0x51, 0x0A, 0x7E, 0x17, 0x07, 0xB8, 0xC3, 0x07, 0x00, 0x80, 0x00, 0x00, + 0x20, 0x83, 0x00, 0x00, 0x00, 0x80, 0x32, 0x80, 0x64, 0x80, 0x96, 0x80, 0x2D, 0xB4, 0x04, 0x0F, + 0x11, 0x0C, 0x0F, 0x0F, 0x10, 0x00, 0x0F, 0x13, 0xA5, 0xBB, 0x83, 0x1E, 0x18, 0xC8, 0x0F, 0x00, + 0x15, 0x10, 0x15, 0x10, 0x10, 0x43, 0x10, 0x43, 0x20, 0x03, 0x00, 0x00, 0x14, 0x39, 0x2E, 0x01, + 0x42, 0x39, 0x10, 0x05, 0xC6, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0xDC, 0x55, 0x27, 0x75, + 0x72, 0x72, 0x52, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xB0, 0x66, 0x6B, + 0x66, 0x66, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x7C, 0x05, 0x16, 0x07, 0x4E, 0x07, 0x48, 0x08, 0xC1, 0x0A, 0x6C, 0x08, 0xEC, 0x09, 0x31, 0x0A, + 0x51, 0x0A, 0x7E, 0x17, 0x07, 0xB8, 0xC3, 0x07, 0x00, 0x80, 0x00, 0x00, 0x20, 0x83, 0x00, 0x00, + 0x00, 0x80, 0x32, 0x80, 0x64, 0x80, 0x96, 0x80, 0x2D, 0xB4, 0x04, 0x0F, 0x11, 0x0C, 0x0F, 0x0F, + 0x10, 0x00, 0x0F, 0x13, 0xA5, 0xBB, 0x83, 0x1E, 0x18, 0xC8, 0x0F, 0x00, 0x15, 0x10, 0x15, 0x10, + 0x10, 0x43, 0x10, 0x43, 0x20, 0x03, 0x00, 0x00, 0x14, 0x39, 0x32, 0x0A, 0x4D, 0x20, 0x38, 0x03, + 0xC4, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0xDC, 0x55, 0x55, 0x27, 0x75, 0x52, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xB0, 0xB9, 0x66, 0x6B, 0xB6, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x7C, 0x05, 0x16, 0x07, + 0x4E, 0x07, 0x48, 0x08, 0xC1, 0x0A, 0x6C, 0x08, 0xEC, 0x09, 0x31, 0x0A, 0x51, 0x0A, 0x7E, 0x17, + 0x07, 0xB8, 0xC3, 0x07, 0x00, 0x80, 0x00, 0x00, 0x20, 0x83, 0x00, 0x00, 0x00, 0x80, 0x32, 0x80, + 0x64, 0x80, 0x96, 0x80, 0x2D, 0xB4, 0x04, 0x0F, 0x11, 0x0C, 0x0F, 0x0F, 0x10, 0x00, 0x0F, 0x13, + 0xA5, 0xBB, 0x83, 0x1E, 0x18, 0xC8, 0x0F, 0x00, 0x15, 0x10, 0x15, 0x10, 0x10, 0x43, 0x10, 0x43, + 0x20, 0x03, 0x00, 0x00, 0x14, 0x39, 0x2E, 0x0A, 0x65, 0x65, 0x5D, 0x18, 0x19, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0B, 0x00, 0x00, 0x00, 0xDC, 0x55, 0x55, 0x20, 0x20, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xF8, 0xB0, 0xB9, 0x11, 0x11, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x7C, 0x05, 0x16, 0x07, 0x4E, 0x07, 0x48, 0x08, + 0xC1, 0x0A, 0x6C, 0x08, 0xEC, 0x09, 0x31, 0x0A, 0x51, 0x0A, 0x7E, 0x17, 0x07, 0xB8, 0xC3, 0x07, + 0x00, 0x80, 0x00, 0x00, 0x20, 0x83, 0x00, 0x00, 0x00, 0x80, 0x32, 0x80, 0x64, 0x80, 0x96, 0x80, + 0x2D, 0xB4, 0x04, 0x0F, 0x11, 0x0C, 0x0F, 0x0F, 0x10, 0x00, 0x0F, 0x13, 0xA5, 0xBB, 0x83, 0x1E, + 0x18, 0xC8, 0x0F, 0x00, 0x15, 0x10, 0x15, 0x10, 0x10, 0x43, 0x10, 0x43, 0x20, 0x03, 0x00, 0x00, + 0x14, 0x39, 0x2E, 0x0A, 0x65, 0x65, 0x5D, 0x18, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, + 0xDC, 0x55, 0x55, 0x27, 0x27, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xF8, 0xB0, 0xB9, 0x33, 0x33, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x7C, 0x05, 0x16, 0x07, 0x4E, 0x07, 0x48, 0x08, 0xC1, 0x0A, 0x6C, 0x08, + 0xEC, 0x09, 0x31, 0x0A, 0x51, 0x0A, 0x7E, 0x17, 0x07, 0xB8, 0xC3, 0x07, 0x00, 0x80, 0x00, 0x00, + 0x20, 0x83, 0x00, 0x00, 0x00, 0x80, 0x32, 0x80, 0x64, 0x80, 0x96, 0x80, 0x2D, 0xB4, 0x04, 0x0F, + 0x11, 0x0C, 0x0F, 0x0F, 0x10, 0x00, 0x0F, 0x13, 0xA5, 0xBB, 0x83, 0x1E, 0x18, 0xC8, 0x0F, 0x00, + 0x15, 0x10, 0x15, 0x10, 0x10, 0x43, 0x10, 0x43, 0x20, 0x03, 0x00, 0x00, 0x14, 0x39, 0x32, 0x15, + 0x56, 0x73, 0x61, 0x0E, 0xD9, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0xDC, 0x55, 0x20, 0x05, + 0x52, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xB0, 0x11, 0x1B, + 0xB1, 0xB1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x7C, 0x05, 0x16, 0x07, 0x4E, 0x07, 0x48, 0x08, 0xC1, 0x0A, 0x6C, 0x08, 0xEC, 0x09, 0x31, 0x0A, + 0x51, 0x0A, 0x7E, 0x17, 0x07, 0xB8, 0xC3, 0x07, 0x00, 0x80, 0x00, 0x00, 0x20, 0x83, 0x00, 0x00, + 0x00, 0x80, 0x32, 0x80, 0x64, 0x80, 0x96, 0x80, 0x2D, 0xB4, 0x04, 0x0F, 0x11, 0x0C, 0x0F, 0x0F, + 0x10, 0x00, 0x0F, 0x13, 0xA5, 0xBB, 0x83, 0x1E, 0x18, 0xC8, 0x0F, 0x00, 0x15, 0x10, 0x15, 0x10, + 0x10, 0x43, 0x10, 0x43, 0x20, 0x03, 0x00, 0x00, 0x14, 0x39, 0x32, 0x15, 0x56, 0x73, 0x61, 0x0E, + 0xD9, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0xDC, 0x55, 0x27, 0x75, 0x52, 0x55, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xB0, 0x33, 0x3B, 0xB3, 0xB3, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x7C, 0x05, 0x16, 0x07, + 0x4E, 0x07, 0x48, 0x08, 0xC1, 0x0A, 0x6C, 0x08, 0xEC, 0x09, 0x31, 0x0A, 0x51, 0x0A, 0x7E, 0x17, + 0x07, 0xB8, 0xC3, 0x07, 0x00, 0x80, 0x00, 0x00, 0x20, 0x83, 0x00, 0x00, 0x00, 0x80, 0x32, 0x80, + 0x64, 0x80, 0x96, 0x80, 0x2D, 0xB4, 0x04, 0x0F, 0x11, 0x0C, 0x0F, 0x0F, 0x10, 0x00, 0x0F, 0x13, + 0xA5, 0xBB, 0x83, 0x1E, 0x18, 0xC8, 0x0F, 0x00, 0x15, 0x10, 0x15, 0x10, 0x10, 0x43, 0x10, 0x43, + 0x20, 0x03, 0x00, 0x00, 0x81, 0x30, 0x10, 0x05, 0xC6, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0x05, 0x16, 0x07, 0x4E, 0x07, 0x48, 0x08, + 0xC1, 0x0A, 0x6C, 0x08, 0xEC, 0x09, 0x31, 0x0A, 0x51, 0x0A, 0x7E, 0x17, 0x07, 0xB8, 0xC3, 0x07, + 0x00, 0x80, 0x00, 0x00, 0x20, 0x83, 0x00, 0x00, 0x00, 0x80, 0x32, 0x80, 0x64, 0x80, 0x96, 0x80, + 0x2D, 0xB4, 0x04, 0x0F, 0x11, 0x0C, 0x0F, 0x0F, 0x10, 0x00, 0x0F, 0x13, 0xA5, 0xBB, 0x83, 0x1E, + 0x18, 0xC8, 0x0F, 0x00, 0x15, 0x10, 0x15, 0x10, 0x10, 0x43, 0x10, 0x43, 0x20, 0x03, 0x00, 0x00, + 0x14, 0x39, 0x32, 0x05, 0x46, 0x73, 0x20, 0x0E, 0xC0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, + 0xDC, 0x55, 0x20, 0x05, 0x52, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xF8, 0xB0, 0x00, 0x0B, 0xB0, 0xB1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x7C, 0x05, 0x16, 0x07, 0x4E, 0x07, 0x48, 0x08, 0xC1, 0x0A, 0x6C, 0x08, + 0xEC, 0x09, 0x31, 0x0A, 0x51, 0x0A, 0x7E, 0x17, 0x07, 0xB8, 0xC3, 0x07, 0x00, 0x80, 0x00, 0x00, + 0x20, 0x83, 0x00, 0x00, 0x00, 0x80, 0x32, 0x80, 0x64, 0x80, 0x96, 0x80, 0x2D, 0xB4, 0x04, 0x0F, + 0x11, 0x0C, 0x0F, 0x0F, 0x10, 0x00, 0x0F, 0x13, 0xA5, 0xBB, 0x83, 0x1E, 0x18, 0xC8, 0x0F, 0x00, + 0x15, 0x10, 0x15, 0x10, 0x10, 0x43, 0x10, 0x43, 0x20, 0x03, 0x00, 0x00, 0x81, 0x30, 0x10, 0x05, + 0xC6, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, + 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x7C, 0x05, 0x16, 0x07, 0x4E, 0x07, 0x48, 0x08, 0xC1, 0x0A, 0x6C, 0x08, 0xEC, 0x09, 0x31, 0x0A, + 0x51, 0x0A, 0x7E, 0x17, 0x07, 0xB8, 0xC3, 0x07, 0x00, 0x80, 0x00, 0x00, 0x20, 0x83, 0x00, 0x00, + 0x00, 0x80, 0x32, 0x80, 0x64, 0x80, 0x96, 0x80, 0x2D, 0xB4, 0x04, 0x0F, 0x11, 0x0C, 0x0F, 0x0F, + 0x10, 0x00, 0x0F, 0x13, 0xA5, 0xBB, 0x83, 0x1E, 0x18, 0xC8, 0x0F, 0x00, 0x15, 0x10, 0x15, 0x10, + 0x10, 0x43, 0x10, 0x43, 0x20, 0x03, 0x00, 0x00, 0x14, 0x39, 0x32, 0x05, 0x46, 0x73, 0x20, 0x0E, + 0xC0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0xDC, 0x55, 0x27, 0x75, 0x52, 0x55, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xB0, 0x66, 0x6B, 0xB6, 0xB3, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x7C, 0x05, 0x16, 0x07, + 0x4E, 0x07, 0x48, 0x08, 0xC1, 0x0A, 0x6C, 0x08, 0xEC, 0x09, 0x31, 0x0A, 0x51, 0x0A, 0x7E, 0x17, + 0x07, 0xB8, 0xC3, 0x07, 0x00, 0x80, 0x00, 0x00, 0x20, 0x83, 0x00, 0x00, 0x00, 0x80, 0x32, 0x80, + 0x64, 0x80, 0x96, 0x80, 0x2D, 0xB4, 0x04, 0x0F, 0x11, 0x0C, 0x0F, 0x0F, 0x10, 0x00, 0x0F, 0x13, + 0xA5, 0xBB, 0x83, 0x1E, 0x18, 0xC8, 0x0F, 0x00, 0x15, 0x10, 0x15, 0x10, 0x10, 0x43, 0x10, 0x43, + 0x20, 0x03, 0x00, 0x00, 0x14, 0x39, 0x2E, 0x0A, 0x65, 0x65, 0x5D, 0x18, 0x19, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0B, 0x00, 0x00, 0x00, 0xDC, 0x55, 0x55, 0x20, 0x20, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xF8, 0xB0, 0xB9, 0x11, 0x11, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x7C, 0x05, 0x16, 0x07, 0x4E, 0x07, 0x48, 0x08, + 0xC1, 0x0A, 0x6C, 0x08, 0xEC, 0x09, 0x31, 0x0A, 0x51, 0x0A, 0x7E, 0x17, 0x07, 0xB8, 0xC3, 0x07, + 0x00, 0x80, 0x00, 0x00, 0x20, 0x83, 0x00, 0x00, 0x00, 0x80, 0x32, 0x80, 0x64, 0x80, 0x96, 0x80, + 0x2D, 0xB4, 0x04, 0x0F, 0x11, 0x0C, 0x0F, 0x0F, 0x10, 0x00, 0x0F, 0x13, 0xA5, 0xBB, 0x83, 0x1E, + 0x18, 0xC8, 0x0F, 0x00, 0x15, 0x10, 0x15, 0x10, 0x10, 0x43, 0x10, 0x43, 0x20, 0x03, 0x00, 0x00, + 0x14, 0x39, 0x2E, 0x23, 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0xDC, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xF8, 0xB0, 0xB0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x00, 0x00, 0x7C, 0x05, 0x16, 0x07, 0x4E, 0x07, 0x48, 0x08, 0xC1, 0x0A, 0x6C, 0x08, + 0xEC, 0x09, 0x31, 0x0A, 0x51, 0x0A, 0x7E, 0x17, 0x07, 0xB8, 0xC3, 0x07, 0x00, 0x80, 0x00, 0x00, + 0x20, 0x83, 0x00, 0x00, 0x00, 0x80, 0x32, 0x80, 0x64, 0x80, 0x96, 0x80, 0x2D, 0xB4, 0x04, 0x0F, + 0x11, 0x0C, 0x0F, 0x0F, 0x10, 0x00, 0x0F, 0x13, 0xA5, 0xBB, 0x83, 0x1E, 0x18, 0xC8, 0x0F, 0x00, + 0x15, 0x10, 0x15, 0x10, 0x10, 0x43, 0x10, 0x43, 0x20, 0x03, 0x00, 0x00, 0x09, 0x45, 0x8E, 0x23, + 0xE3, 0x38, 0x8E, 0x23, 0xE3, 0x38, 0x8E, 0x23, 0xE3, 0x38, 0x8E, 0x23, 0xE3, 0xB8, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0xB4, 0x6D, 0x66, 0x66, + 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x06, 0x00, 0x00, 0x00, 0x00, 0x82, 0x0F, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x3F, 0x00, + 0x7C, 0x05, 0x16, 0x07, 0x4E, 0x07, 0x48, 0x08, 0xC1, 0x0A, 0x6C, 0x08, 0xEC, 0x09, 0x31, 0x0A, + 0x51, 0x0A, 0x7E, 0x17, 0x07, 0xB8, 0xC3, 0x07, 0x00, 0x80, 0x00, 0x00, 0x20, 0x83, 0x00, 0x00, + 0x00, 0x80, 0x32, 0x80, 0x64, 0x80, 0x96, 0x80, 0x2D, 0xB4, 0x04, 0x0F, 0x11, 0x0C, 0x0F, 0x0F, + 0x10, 0x00, 0x0F, 0x13, 0xA5, 0xBB, 0x83, 0x1E, 0x18, 0xC8, 0x0F, 0x00, 0x15, 0x10, 0x15, 0x10, + 0x10, 0x43, 0x10, 0x43, 0x20, 0x03, 0x00, 0x00, 0x14, 0x39, 0x2E, 0x0A, 0x65, 0x65, 0x5D, 0x18, + 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0xDC, 0x55, 0x55, 0x27, 0x27, 0x05, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xB0, 0xB9, 0x33, 0x33, 0x03, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x7C, 0x05, 0x16, 0x07, + 0x4E, 0x07, 0x48, 0x08, 0xC1, 0x0A, 0x6C, 0x08, 0xEC, 0x09, 0x31, 0x0A, 0x51, 0x0A, 0x7E, 0x17, + 0x07, 0xB8, 0xC3, 0x07, 0x00, 0x80, 0x00, 0x00, 0x20, 0x83, 0x00, 0x00, 0x00, 0x80, 0x32, 0x80, + 0x64, 0x80, 0x96, 0x80, 0x2D, 0xB4, 0x04, 0x0F, 0x11, 0x0C, 0x0F, 0x0F, 0x10, 0x00, 0x0F, 0x13, + 0xA5, 0xBB, 0x83, 0x1E, 0x18, 0xC8, 0x0F, 0x00, 0x15, 0x10, 0x15, 0x10, 0x10, 0x43, 0x10, 0x43, + 0x20, 0x03, 0x00, 0x00, 0x14, 0x39, 0x32, 0x15, 0x56, 0x73, 0x61, 0x0E, 0xD9, 0x03, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0C, 0x00, 0x00, 0x00, 0xDC, 0x55, 0x20, 0x05, 0x52, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xF8, 0xB0, 0x11, 0x1B, 0xB1, 0xB1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x7C, 0x05, 0x16, 0x07, 0x4E, 0x07, 0x48, 0x08, + 0xC1, 0x0A, 0x6C, 0x08, 0xEC, 0x09, 0x31, 0x0A, 0x51, 0x0A, 0x7E, 0x17, 0x07, 0xB8, 0xC3, 0x07, + 0x00, 0x80, 0x00, 0x00, 0x20, 0x83, 0x00, 0x00, 0x00, 0x80, 0x32, 0x80, 0x64, 0x80, 0x96, 0x80, + 0x2D, 0xB4, 0x04, 0x0F, 0x11, 0x0C, 0x0F, 0x0F, 0x10, 0x00, 0x0F, 0x13, 0xA5, 0xBB, 0x83, 0x1E, + 0x18, 0xC8, 0x0F, 0x00, 0x15, 0x10, 0x15, 0x10, 0x10, 0x43, 0x10, 0x43, 0x20, 0x03, 0x00, 0x00, + 0x14, 0x39, 0x32, 0x15, 0x56, 0x73, 0x61, 0x0E, 0xD9, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, + 0xDC, 0x55, 0x27, 0x75, 0x52, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xF8, 0xB0, 0x33, 0x3B, 0xB3, 0xB3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x7C, 0x05, 0x16, 0x07, 0x4E, 0x07, 0x48, 0x08, 0xC1, 0x0A, 0x6C, 0x08, + 0xEC, 0x09, 0x31, 0x0A, 0x51, 0x0A, 0x7E, 0x17, 0x07, 0xB8, 0xC3, 0x07, 0x00, 0x80, 0x00, 0x00, + 0x20, 0x83, 0x00, 0x00, 0x00, 0x80, 0x32, 0x80, 0x64, 0x80, 0x96, 0x80, 0x2D, 0xB4, 0x04, 0x0F, + 0x11, 0x0C, 0x0F, 0x0F, 0x10, 0x00, 0x0F, 0x13, 0xA5, 0xBB, 0x83, 0x1E, 0x18, 0xC8, 0x0F, 0x00, + 0x15, 0x10, 0x15, 0x10, 0x10, 0x43, 0x10, 0x43, 0x20, 0x03, 0x00, 0x00, 0x14, 0x39, 0x2E, 0x01, + 0xA5, 0x60, 0x0E, 0x04, 0x85, 0x71, 0x00, 0x08, 0x81, 0x30, 0x10, 0x05, 0xC6, 0x01, 0x20, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0xDC, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0xF8, 0xA0, 0xA0, 0xA0, + 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x7C, 0x05, 0x16, 0x07, 0x4E, 0x07, 0x48, 0x08, 0xC1, 0x0A, 0x6C, 0x08, 0xEC, 0x09, 0x31, 0x0A, + 0x51, 0x0A, 0x7E, 0x17, 0x07, 0xB8, 0xC3, 0x07, 0x00, 0x80, 0x00, 0x00, 0x20, 0x83, 0x00, 0x00, + 0x00, 0x80, 0x32, 0x80, 0x64, 0x80, 0x96, 0x80, 0x2D, 0xB4, 0x04, 0x0F, 0x11, 0x0C, 0x0F, 0x0F, + 0x10, 0x00, 0x0F, 0x13, 0xA5, 0xBA, 0x83, 0x0A, 0x18, 0xC8, 0x0F, 0x00, 0x15, 0x10, 0x15, 0x10, + 0x10, 0x43, 0x10, 0x43, 0x20, 0x03, 0x00, 0x00, 0x14, 0x39, 0x32, 0x0A, 0x4D, 0x60, 0x0A, 0x0E, + 0xC3, 0x43, 0x9C, 0x05, 0x90, 0x11, 0x1D, 0x28, 0x80, 0x84, 0x4C, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0xDC, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xB0, 0xB9, 0xA0, 0xB0, 0xB0, 0xA0, 0xB0, + 0xB0, 0xA0, 0xB1, 0xB0, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x7C, 0x05, 0x16, 0x07, + 0x4E, 0x07, 0x48, 0x08, 0xC1, 0x0A, 0x6C, 0x08, 0xEC, 0x09, 0x31, 0x0A, 0x51, 0x0A, 0x7E, 0x17, + 0x07, 0xB8, 0xC3, 0x07, 0x00, 0x80, 0x00, 0x00, 0x20, 0x83, 0x00, 0x00, 0x00, 0x80, 0x32, 0x80, + 0x64, 0x80, 0x96, 0x80, 0x2D, 0xB4, 0x04, 0x0F, 0x11, 0x0C, 0x0F, 0x0F, 0x10, 0x00, 0x0F, 0x13, + 0xA5, 0xBA, 0x83, 0x0A, 0x18, 0xC8, 0x0F, 0x00, 0x15, 0x10, 0x15, 0x10, 0x10, 0x43, 0x10, 0x43, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xFC, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x0D, 0x00, 0x40, 0x06, 0x59, 0x06, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x55, 0xB4, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x03, 0x02, + 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x0D, 0x00, + 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xB0, 0xB3, 0x00, 0x00, 0x00, 0x00, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x03, 0x02, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFC, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x0D, 0x00, 0x01, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x08, 0xB0, 0xB3, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0x03, 0x02, + 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x0D, 0x00, + 0x02, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xD8, 0xB3, 0x00, 0x00, 0x00, 0x00, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x04, 0x04, 0x03, 0x02, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFC, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x0D, 0x00, 0x03, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x08, 0xD8, 0xB3, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x05, 0x05, 0x03, 0x02, + 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x0D, 0x00, + 0x04, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0xB4, 0x00, 0x00, 0x00, 0x00, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x03, 0x02, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFC, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x0D, 0x00, 0x05, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x08, 0x00, 0xB4, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x07, 0x07, 0x03, 0x02, + 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x0D, 0x00, + 0x06, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x28, 0xB4, 0x00, 0x00, 0x00, 0x00, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x03, 0x02, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0xFC, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x0D, 0x00, 0x07, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x08, 0x28, 0xB4, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x0D, 0x00, + 0xA0, 0x0F, 0xB9, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x01, 0x50, 0xB4, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xFC, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x0D, 0x00, 0xC1, 0x16, 0xA8, 0x16, 0x00, 0x00, 0x00, 0x00, + 0x01, 0xAA, 0xB4, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x17, + 0x01, 0x00, 0x03, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x0D, 0x00, + 0x38, 0x18, 0x39, 0x18, 0x00, 0x00, 0x80, 0x11, 0x02, 0x9B, 0xB4, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x16, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00, 0xFD, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x0D, 0x00, 0x68, 0x10, 0x70, 0x10, 0x00, 0x00, 0x80, 0x11, + 0x02, 0x73, 0xB4, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x17, + 0x02, 0x00, 0x03, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x0D, 0x00, + 0xF8, 0x11, 0xF9, 0x11, 0x00, 0x00, 0x80, 0x11, 0x02, 0x87, 0xB4, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x16, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, 0xFD, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x0D, 0x00, 0x68, 0x10, 0x70, 0x10, 0x00, 0x00, 0x80, 0x11, + 0x03, 0x73, 0xB4, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x17, + 0x04, 0x00, 0x03, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x0D, 0x00, + 0xF8, 0x11, 0xF9, 0x11, 0x00, 0x00, 0x80, 0x11, 0x03, 0x87, 0xB4, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x16, 0x06, 0x00, 0x03, 0x00, 0x00, 0x00, 0xFD, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x0D, 0x00, 0x68, 0x10, 0x70, 0x10, 0x00, 0x00, 0x80, 0x11, + 0x03, 0x73, 0xB4, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x17, + 0x05, 0x00, 0x03, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x0D, 0x00, + 0xF8, 0x11, 0xF9, 0x11, 0x00, 0x00, 0x80, 0x11, 0x03, 0x87, 0xB4, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x16, 0x08, 0x00, 0x03, 0x00, 0x00, 0x00, 0xFD, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x0D, 0x00, 0x68, 0x10, 0x70, 0x10, 0x00, 0x00, 0x80, 0x11, + 0x03, 0x73, 0xB4, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x17, + 0x07, 0x00, 0x03, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x0D, 0x00, + 0xF8, 0x11, 0xF9, 0x11, 0x00, 0x00, 0x80, 0x11, 0x03, 0x87, 0xB4, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x14, 0x14, 0x09, 0x00, 0x03, 0x00, 0x00, 0x00, 0xFC, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x97, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x0D, 0x00, + 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x5A, 0xB4, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xFC, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x0D, 0x00, 0x90, 0x01, 0xA9, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x5A, 0xB4, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x0D, 0x00, + 0x20, 0x03, 0x39, 0x03, 0x00, 0x00, 0x00, 0x00, 0x01, 0x64, 0xB4, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xFC, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x0D, 0x00, 0xB0, 0x04, 0xC9, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x64, 0xB4, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x0D, 0x00, + 0x40, 0x06, 0x59, 0x06, 0x00, 0x00, 0x00, 0x00, 0x01, 0x6E, 0xB4, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xFC, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x0D, 0x00, 0x68, 0x10, 0x81, 0x10, 0x00, 0x00, 0x00, 0x00, + 0x01, 0xA5, 0xB4, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x0D, 0x00, + 0xF8, 0x11, 0x11, 0x12, 0x00, 0x00, 0x00, 0x00, 0x01, 0xAA, 0xB4, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xFC, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x0D, 0x00, 0x88, 0x13, 0xA1, 0x13, 0x00, 0x00, 0x00, 0x00, + 0x01, 0xAF, 0xB4, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x0D, 0x00, + 0x18, 0x15, 0x31, 0x15, 0x00, 0x00, 0x00, 0x00, 0x01, 0xB4, 0xB4, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xFC, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x0D, 0x00, 0xA8, 0x16, 0xC1, 0x16, 0x00, 0x00, 0x00, 0x00, + 0x01, 0xB9, 0xB4, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x09, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x97, 0x03, 0x06, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x14, 0x14, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xFC, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x97, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x14, 0x14, + 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x0C, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x97, 0x03, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x15, 0x15, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xCC, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x97, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x0D, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x97, 0x03, 0x06, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x14, 0x14, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xFC, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x97, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x17, + 0x02, 0x00, 0x03, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x0D, 0x00, + 0x38, 0x18, 0x39, 0x18, 0x00, 0x00, 0x80, 0x11, 0x02, 0x9B, 0xB4, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x17, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, 0xFC, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x0D, 0x00, 0x38, 0x18, 0x39, 0x18, 0x00, 0x00, 0x80, 0x11, + 0x02, 0x9B, 0xB4, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x17, + 0x06, 0x00, 0x03, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x0D, 0x00, + 0x38, 0x18, 0x39, 0x18, 0x00, 0x00, 0x80, 0x11, 0x02, 0x9B, 0xB4, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x17, 0x09, 0x00, 0x03, 0x00, 0x00, 0x00, 0xFC, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x0D, 0x00, 0x38, 0x18, 0x39, 0x18, 0x00, 0x00, 0x80, 0x11, + 0x02, 0x9B, 0xB4, 0x00, 0x04, 0x00, 0x00, 0x00, 0x4F, 0x00, 0x00, 0x00, 0x01, 0xF4, 0x04, 0x00, + 0x68, 0x93, 0x1B, 0x00, 0x60, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x01, 0x00, 0x04, 0x00, + 0x14, 0x28, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x2D, 0x00, 0x84, 0x00, + 0x14, 0x28, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x73, 0x00, 0x00, 0x00, 0x2D, 0xF4, 0x84, 0x00, + 0x68, 0x93, 0x1B, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x2D, 0xF4, 0x84, 0x00, + 0x68, 0x93, 0x1B, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x73, 0x00, 0x00, 0x00, 0x2D, 0xF4, 0x84, 0x00, + 0x68, 0x93, 0x1B, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x2D, 0xF4, 0x84, 0x00, + 0x68, 0x93, 0x1B, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x4F, 0x00, 0x00, 0x00, 0x1E, 0xF4, 0x04, 0x00, + 0x68, 0x93, 0x1B, 0x00, 0xE0, 0x00, 0x01, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x01, 0x00, 0x04, 0x00, + 0x14, 0x28, 0x00, 0x00, 0xE0, 0x00, 0x01, 0x00, 0x30, 0x00, 0x00, 0x00, 0x2D, 0x00, 0x84, 0x00, + 0x14, 0x28, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x2D, 0xF4, 0x84, 0x00, + 0x68, 0x93, 0x1B, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x02, 0xF4, 0x00, 0x00, + 0x68, 0x93, 0x1B, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x63, 0x00, 0x00, 0x00, 0x02, 0xF4, 0x00, 0x00, + 0x68, 0x93, 0x1B, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x23, 0x00, 0x84, 0x00, + 0x09, 0x12, 0x1B, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x30, 0x30, 0x30, 0x2F, + 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x2F, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x2F, 0x30, 0x30, 0x2F, 0x2F, 0x30, 0x30, 0x31, 0x2F, 0x2F, 0x30, 0x30, 0x2F, 0x30, + 0x2F, 0x30, 0x2F, 0x2E, 0x30, 0x30, 0x30, 0x2F, 0x30, 0x32, 0x2F, 0x30, 0x31, 0x30, 0x2F, 0x2F, + 0x31, 0x30, 0x2F, 0x2F, 0x2F, 0x30, 0x30, 0x2F, 0x2F, 0x30, 0x2F, 0x2E, 0x30, 0x30, 0x2F, 0x2F, + 0x30, 0x2F, 0x2E, 0x31, 0x2F, 0x2E, 0x2E, 0x30, 0x30, 0x30, 0x2F, 0x2F, 0x30, 0x30, 0x30, 0x2F, + 0x2F, 0x2F, 0x2F, 0x2F, 0x30, 0x30, 0x30, 0x2F, 0x2F, 0x30, 0x2F, 0x31, 0x2C, 0x2B, 0x2B, 0x2B, + 0x30, 0x30, 0x2F, 0x2F, 0x30, 0x30, 0x2F, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x2F, + 0x30, 0x2F, 0x30, 0x30, 0x2F, 0x30, 0x2F, 0x30, 0x30, 0x2F, 0x2F, 0x30, 0x30, 0x30, 0x2F, 0x2F, + 0x30, 0x2F, 0x2F, 0x30, 0x2E, 0x2F, 0x30, 0x2E, 0x2F, 0x30, 0x30, 0x2F, 0x2F, 0x32, 0x2F, 0x30, + 0x30, 0x2F, 0x2F, 0x2F, 0x30, 0x2F, 0x2F, 0x2F, 0x2F, 0x30, 0x30, 0x2F, 0x2F, 0x30, 0x2F, 0x2E, + 0x30, 0x30, 0x2F, 0x2F, 0x30, 0x2F, 0x2E, 0x31, 0x2F, 0x2E, 0x2E, 0x30, 0x30, 0x2F, 0x2F, 0x2E, + 0x30, 0x2F, 0x30, 0x2F, 0x2F, 0x2F, 0x2E, 0x2F, 0x30, 0x2F, 0x30, 0x2E, 0x2F, 0x2F, 0x2F, 0x30, + 0x2B, 0x2A, 0x2B, 0x2B, 0x2F, 0x30, 0x2F, 0x2F, 0x30, 0x30, 0x2F, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x2F, 0x30, 0x30, 0x30, 0x30, 0x2F, 0x30, 0x2F, 0x30, 0x30, 0x2F, 0x2F, 0x30, + 0x30, 0x31, 0x2F, 0x2F, 0x30, 0x30, 0x2F, 0x30, 0x2F, 0x30, 0x30, 0x2E, 0x30, 0x30, 0x30, 0x2F, + 0x2F, 0x31, 0x2F, 0x30, 0x30, 0x2F, 0x2F, 0x2F, 0x30, 0x2F, 0x2F, 0x2F, 0x2F, 0x30, 0x30, 0x2F, + 0x2F, 0x30, 0x2F, 0x2E, 0x30, 0x30, 0x2F, 0x2F, 0x30, 0x2F, 0x2E, 0x31, 0x2F, 0x2E, 0x2E, 0x30, + 0x30, 0x2F, 0x2F, 0x2F, 0x30, 0x2F, 0x30, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x30, 0x2F, 0x30, 0x2E, + 0x2F, 0x30, 0x2F, 0x30, 0x2B, 0x2B, 0x2B, 0x2B, 0x2F, 0x30, 0x2F, 0x2F, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x2F, 0x30, 0x30, 0x30, 0x30, 0x2F, 0x30, 0x2F, 0x30, + 0x30, 0x2F, 0x2F, 0x30, 0x30, 0x31, 0x2F, 0x2F, 0x30, 0x30, 0x2F, 0x30, 0x2F, 0x30, 0x30, 0x2E, + 0x2F, 0x30, 0x30, 0x2F, 0x2F, 0x31, 0x2F, 0x30, 0x2F, 0x2F, 0x2F, 0x2F, 0x30, 0x2F, 0x2F, 0x2F, + 0x2F, 0x30, 0x30, 0x2F, 0x2F, 0x30, 0x2F, 0x2E, 0x30, 0x30, 0x2F, 0x2F, 0x30, 0x30, 0x2E, 0x31, + 0x30, 0x2E, 0x2E, 0x30, 0x30, 0x2F, 0x2F, 0x2E, 0x30, 0x2F, 0x30, 0x2F, 0x2F, 0x2F, 0x2E, 0x2F, + 0x30, 0x2F, 0x30, 0x2E, 0x2F, 0x2F, 0x2F, 0x30, 0x2B, 0x2A, 0x2B, 0x2B, 0x2F, 0x30, 0x2F, 0x2F, + 0x30, 0x30, 0x2F, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x2F, 0x30, 0x30, 0x30, 0x30, + 0x2F, 0x30, 0x2F, 0x30, 0x30, 0x2F, 0x2F, 0x30, 0x30, 0x31, 0x30, 0x2F, 0x30, 0x30, 0x2F, 0x30, + 0x2F, 0x30, 0x30, 0x2E, 0x2F, 0x30, 0x30, 0x2F, 0x2F, 0x31, 0x2F, 0x30, 0x30, 0x2F, 0x2F, 0x2F, + 0x30, 0x2F, 0x2F, 0x2F, 0x2F, 0x30, 0x30, 0x2F, 0x2F, 0x30, 0x2F, 0x2E, 0x30, 0x30, 0x2F, 0x2F, + 0x31, 0x30, 0x2E, 0x31, 0x31, 0x30, 0x2E, 0x30, 0x30, 0x30, 0x2F, 0x2F, 0x30, 0x30, 0x30, 0x2F, + 0x2F, 0x2F, 0x2E, 0x2F, 0x30, 0x2F, 0x30, 0x2F, 0x2F, 0x30, 0x2F, 0x30, 0x2B, 0x2B, 0x2B, 0x2B, + 0x2F, 0x30, 0x2F, 0x2F, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x2F, + 0x30, 0x30, 0x30, 0x30, 0x2F, 0x30, 0x2F, 0x30, 0x30, 0x2F, 0x2F, 0x30, 0x30, 0x31, 0x2F, 0x2F, + 0x30, 0x30, 0x2F, 0x30, 0x2F, 0x30, 0x30, 0x2E, 0x2F, 0x30, 0x30, 0x2F, 0x2F, 0x31, 0x2F, 0x30, + 0x2F, 0x2F, 0x2F, 0x2F, 0x30, 0x2F, 0x2F, 0x2F, 0x2F, 0x30, 0x30, 0x2F, 0x2F, 0x30, 0x2F, 0x2E, + 0x30, 0x31, 0x2F, 0x2F, 0x31, 0x30, 0x2E, 0x31, 0x30, 0x30, 0x2E, 0x30, 0x30, 0x30, 0x2F, 0x2E, + 0x30, 0x2F, 0x30, 0x2F, 0x2F, 0x2F, 0x2E, 0x2F, 0x30, 0x2F, 0x30, 0x2E, 0x2F, 0x2F, 0x2F, 0x30, + 0x2B, 0x2A, 0x2B, 0x2B, 0x2F, 0x30, 0x2F, 0x2F, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x2F, 0x30, 0x30, 0x30, 0x30, 0x2F, 0x30, 0x2F, 0x30, 0x30, 0x2F, 0x2F, 0x30, + 0x30, 0x31, 0x30, 0x2F, 0x30, 0x30, 0x2F, 0x30, 0x2F, 0x30, 0x30, 0x2E, 0x30, 0x30, 0x30, 0x2F, + 0x2F, 0x31, 0x2F, 0x30, 0x30, 0x2F, 0x2F, 0x2F, 0x30, 0x2F, 0x2F, 0x2F, 0x2F, 0x30, 0x30, 0x2F, + 0x2F, 0x30, 0x2F, 0x2E, 0x30, 0x30, 0x2F, 0x2F, 0x31, 0x31, 0x2E, 0x31, 0x31, 0x30, 0x2E, 0x30, + 0x30, 0x30, 0x2F, 0x2F, 0x30, 0x30, 0x30, 0x2F, 0x2F, 0x2F, 0x2E, 0x2F, 0x30, 0x2F, 0x30, 0x2F, + 0x2F, 0x30, 0x2F, 0x30, 0x2B, 0x2B, 0x2B, 0x2B, 0x30, 0x30, 0x2F, 0x2F, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x2F, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x2F, 0x30, + 0x30, 0x2F, 0x2F, 0x30, 0x30, 0x31, 0x30, 0x2F, 0x30, 0x30, 0x2F, 0x30, 0x2F, 0x30, 0x30, 0x2E, + 0x30, 0x30, 0x30, 0x2F, 0x30, 0x31, 0x2F, 0x30, 0x2F, 0x2F, 0x2F, 0x2F, 0x30, 0x2F, 0x2F, 0x2F, + 0x2F, 0x30, 0x30, 0x2F, 0x2F, 0x30, 0x2F, 0x2F, 0x30, 0x30, 0x2F, 0x2F, 0x31, 0x30, 0x2E, 0x31, + 0x31, 0x2F, 0x2E, 0x30, 0x30, 0x30, 0x2F, 0x2F, 0x30, 0x30, 0x30, 0x2F, 0x2F, 0x2F, 0x2E, 0x2F, + 0x30, 0x2F, 0x30, 0x2F, 0x2F, 0x30, 0x2F, 0x30, 0x2B, 0x2B, 0x2B, 0x2B, 0x71, 0x6D, 0x6D, 0x6B, + 0x6D, 0x6B, 0x6D, 0x6B, 0x63, 0x69, 0x65, 0x63, 0x65, 0x63, 0x6A, 0x5F, 0x63, 0x5D, 0x5F, 0x5B, + 0x5F, 0x5D, 0x5D, 0x65, 0x5D, 0x5B, 0x5D, 0x61, 0x5D, 0x59, 0x59, 0x5D, 0x5F, 0x5B, 0x59, 0x5D, + 0x55, 0x5D, 0x59, 0x57, 0x59, 0x57, 0x59, 0x55, 0x59, 0x55, 0x55, 0x55, 0x53, 0x53, 0x53, 0x4D, + 0x53, 0x51, 0x53, 0x53, 0x51, 0x53, 0x51, 0x53, 0x51, 0x55, 0x4F, 0x4F, 0x4F, 0x51, 0x4B, 0x51, + 0x51, 0x51, 0x51, 0x4F, 0x4D, 0x4B, 0x4F, 0x4F, 0x4F, 0x49, 0x4F, 0x49, 0x4B, 0x4D, 0x4D, 0x4B, + 0x49, 0x4B, 0x4B, 0x49, 0x4D, 0x47, 0x4B, 0x49, 0x4B, 0x4F, 0x47, 0x49, 0x47, 0x45, 0x47, 0x45, + 0x92, 0x24, 0x92, 0x24, 0x92, 0x00, 0x92, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB6, 0x6D, 0xB6, 0x6D, + 0xB6, 0x00, 0xB6, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB6, 0x6D, 0xB6, 0x6D, 0x96, 0x01, 0x96, 0x01, + 0x00, 0x00, 0x00, 0x00, 0xB6, 0x6D, 0xB6, 0x6D, 0xB2, 0x01, 0xB2, 0x01, 0x00, 0x00, 0x00, 0x00, + 0xB6, 0x2D, 0xB6, 0x2D, 0xB6, 0x01, 0xB6, 0x01, 0x00, 0x00, 0x00, 0x00, 0xB6, 0x65, 0xB6, 0x65, + 0xB6, 0x01, 0xB6, 0x01, 0x00, 0x00, 0x00, 0x00, 0xB6, 0x6C, 0xB6, 0x6C, 0xB6, 0x01, 0xB6, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x96, 0x6D, 0x96, 0x6D, 0xB6, 0x01, 0xB6, 0x01, 0x00, 0x00, 0x00, 0x00, + 0xB2, 0x6D, 0xB2, 0x6D, 0xB6, 0x01, 0xB6, 0x01, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x7F, 0xFF, 0x7F, + 0xFF, 0x01, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0xB6, 0x6D, 0xB6, 0x6D, 0xB6, 0x01, 0xB6, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x92, 0x24, 0x92, 0x24, 0x92, 0x00, 0x92, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3D, 0xDB, + 0x38, 0xD4, 0xFC, 0x02, 0x02, 0x00, 0xAA, 0x00, 0x6C, 0x76, 0x8A, 0x94, 0x00, 0x01, 0x06, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xDB, 0x06, 0x00, 0x00, 0x04, 0x0C, 0x00, 0x00, 0x3C, 0x05, 0x6E, 0x40, + 0x41, 0x4D, 0x39, 0x03, 0x01, 0x00, 0x00, 0x9A, 0xC8, 0x04, 0x4D, 0x61, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x10, 0xC4, 0x0C, 0x50, 0x03, 0x90, 0xBB, 0xBB, 0x80, 0x44, 0x22, 0x78, + 0x64, 0x11, 0x64, 0x11, 0x8A, 0x39, 0x89, 0x39, 0x85, 0xE0, 0x0F, 0xE0, 0x66, 0x12, 0x64, 0x12, + 0x01, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3D, 0xDB, + 0x38, 0xD4, 0xFC, 0x02, 0x02, 0x00, 0xAA, 0x00, 0x6C, 0x76, 0x8A, 0x94, 0x00, 0x01, 0x06, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xDB, 0x06, 0x00, 0x00, 0x04, 0x0C, 0x00, 0x00, 0x3C, 0x05, 0x6E, 0x40, + 0x41, 0x4D, 0x39, 0x03, 0x01, 0x00, 0x00, 0x9A, 0xC8, 0x04, 0x4D, 0x61, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x10, 0xC4, 0x0C, 0x10, 0xE3, 0x9E, 0xBB, 0xBB, 0x80, 0x55, 0x22, 0x78, + 0x64, 0x11, 0x64, 0x11, 0x8A, 0x39, 0x89, 0x39, 0x85, 0xE0, 0x0F, 0xE0, 0x66, 0x12, 0x64, 0x12, + 0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0xAA, 0x00, 0x6C, 0x76, 0x8A, 0x94, 0x00, 0x01, 0x06, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xDB, 0x06, 0x00, 0x00, 0x04, 0x0C, 0x00, 0x00, 0x38, 0x06, 0x6E, 0x40, + 0x41, 0x8C, 0x39, 0x03, 0x01, 0x00, 0x00, 0x9A, 0xC4, 0x05, 0x8C, 0x61, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x10, 0xC4, 0x0C, 0x50, 0x03, 0x90, 0xBB, 0xBB, 0x80, 0x44, 0x22, 0x78, + 0x64, 0x11, 0x64, 0x11, 0x8A, 0x39, 0x89, 0x39, 0x85, 0xE0, 0x0F, 0xE0, 0x66, 0x12, 0x64, 0x12, + 0xAF, 0x04, 0x02, 0x00, 0x01, 0x02, 0x03, 0x04, 0x52, 0xF5, 0x54, 0xFD, 0x8E, 0x27, 0xE0, 0x93, + 0xCF, 0x03, 0x04, 0x02, 0x1E, 0x00, 0x00, 0x03, 0x6C, 0x76, 0x8A, 0x94, 0x00, 0x01, 0x06, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xDB, 0x06, 0x00, 0x00, 0x01, 0x46, 0x00, 0x00, 0xD1, 0x16, 0x00, 0x40, + 0x00, 0x6B, 0x39, 0x03, 0x41, 0x00, 0x02, 0x9A, 0x00, 0x00, 0x6B, 0x61, 0x64, 0x78, 0x79, 0x2B, + 0xCF, 0x8A, 0x00, 0x80, 0x1C, 0x54, 0x11, 0x98, 0x00, 0x80, 0xBB, 0xBB, 0x00, 0x57, 0x22, 0x78, + 0x64, 0x11, 0x64, 0x11, 0x8A, 0x39, 0x89, 0x39, 0x85, 0xF0, 0x0F, 0xF0, 0x66, 0x12, 0x64, 0x12, + 0xAF, 0x04, 0x02, 0x00, 0x01, 0x01, 0x01, 0x01, 0x52, 0xF5, 0x54, 0xFD, 0x8E, 0x27, 0xE0, 0x93, + 0xCF, 0x03, 0x04, 0x02, 0x02, 0x00, 0x00, 0x00, 0x6C, 0x76, 0x8A, 0x94, 0x00, 0x01, 0x06, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xDB, 0x06, 0x00, 0x00, 0x01, 0x46, 0x00, 0x00, 0xD1, 0x16, 0x00, 0x40, + 0x00, 0x6B, 0x39, 0x03, 0x41, 0x00, 0x02, 0x9A, 0x00, 0x00, 0x6B, 0x61, 0xBB, 0x7D, 0xFC, 0x17, + 0xFF, 0xFF, 0x00, 0x80, 0x1C, 0x54, 0x11, 0x98, 0x03, 0x80, 0xBB, 0xBB, 0x80, 0x46, 0x22, 0x78, + 0x64, 0x11, 0x64, 0x11, 0x8A, 0x39, 0x89, 0x39, 0x85, 0xF0, 0x0F, 0xF0, 0x66, 0x12, 0x64, 0x12, + 0xAF, 0x04, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x52, 0xF5, 0x54, 0xFD, 0x8E, 0x27, 0xE0, 0x93, + 0xCF, 0x03, 0x04, 0x02, 0x02, 0x00, 0x00, 0x00, 0x6C, 0x76, 0x8A, 0x94, 0x00, 0x01, 0x06, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xDB, 0x06, 0x00, 0x00, 0x01, 0x46, 0x00, 0x00, 0xD1, 0x16, 0x00, 0x40, + 0x00, 0x6B, 0x39, 0x03, 0x41, 0x00, 0x02, 0x9A, 0x00, 0x00, 0x6B, 0x61, 0x0F, 0x7E, 0x34, 0x16, + 0xFF, 0xFF, 0x00, 0x80, 0x1C, 0x54, 0x11, 0x98, 0x03, 0x80, 0xBB, 0xBB, 0x80, 0x46, 0x22, 0x78, + 0x64, 0x11, 0x64, 0x11, 0x8A, 0x39, 0x89, 0x39, 0x85, 0xF0, 0x0F, 0xF0, 0x66, 0x12, 0x64, 0x12, + 0xAF, 0x04, 0x02, 0x00, 0x03, 0x03, 0x03, 0x03, 0x52, 0xF5, 0x54, 0xFD, 0x8E, 0x27, 0xE0, 0x93, + 0xCF, 0x03, 0x04, 0x02, 0x02, 0x00, 0x00, 0x00, 0x6C, 0x76, 0x8A, 0x94, 0x00, 0x01, 0x06, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xDB, 0x06, 0x00, 0x00, 0x01, 0x46, 0x00, 0x00, 0xD1, 0x16, 0x00, 0x40, + 0x00, 0x6B, 0x39, 0x03, 0x41, 0x00, 0x02, 0x9A, 0x00, 0x00, 0x6B, 0x61, 0xB1, 0x7E, 0x3C, 0x12, + 0xFF, 0xFF, 0x00, 0x80, 0x1C, 0x54, 0x11, 0x98, 0x03, 0x80, 0xBB, 0xBB, 0x80, 0x46, 0x22, 0x78, + 0x64, 0x11, 0x64, 0x11, 0x8A, 0x39, 0x89, 0x39, 0x85, 0xF0, 0x0F, 0xF0, 0x66, 0x12, 0x64, 0x12, + 0xAF, 0x04, 0x02, 0x00, 0x04, 0x04, 0x04, 0x04, 0x52, 0xF5, 0x54, 0xFD, 0x8E, 0x27, 0xE0, 0x93, + 0xCF, 0x03, 0x04, 0x02, 0x02, 0x00, 0x00, 0x00, 0x6C, 0x76, 0x8A, 0x94, 0x00, 0x01, 0x06, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xDB, 0x06, 0x00, 0x00, 0x01, 0x46, 0x00, 0x00, 0xD1, 0x16, 0x00, 0x40, + 0x00, 0x6B, 0x39, 0x03, 0x41, 0x00, 0x02, 0x9A, 0x00, 0x00, 0x6B, 0x61, 0x1C, 0x7F, 0x0B, 0x0F, + 0xFF, 0xFF, 0x00, 0x80, 0x1C, 0x54, 0x11, 0x98, 0x03, 0x80, 0xBB, 0xBB, 0x80, 0x46, 0x22, 0x78, + 0x64, 0x11, 0x64, 0x11, 0x8A, 0x39, 0x89, 0x39, 0x85, 0xF0, 0x0F, 0xF0, 0x66, 0x12, 0x64, 0x12, + 0x01, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0xCC, 0xF5, 0x7A, 0xFD, 0xED, 0x20, 0xBF, 0x8F, + 0xCF, 0x03, 0x04, 0x02, 0x02, 0x06, 0x00, 0x00, 0x6C, 0x76, 0x8A, 0x94, 0x00, 0x01, 0x06, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xDB, 0x06, 0x00, 0x00, 0x01, 0x06, 0x00, 0x00, 0x09, 0x11, 0x00, 0x40, + 0x00, 0x6B, 0x39, 0x03, 0x41, 0x00, 0x02, 0x9A, 0x00, 0x00, 0x6B, 0x61, 0x64, 0x78, 0x79, 0x2B, + 0xCF, 0x8A, 0x00, 0x80, 0x1C, 0xC4, 0x10, 0x18, 0x03, 0x80, 0xAB, 0xAA, 0x00, 0xC6, 0x22, 0x78, + 0x64, 0x11, 0x64, 0x11, 0x80, 0x39, 0x80, 0x39, 0x0F, 0x00, 0x0F, 0x00, 0x55, 0x0D, 0x55, 0x0D, + 0x1D, 0x04, 0x02, 0x00, 0x05, 0x07, 0x08, 0x09, 0x5E, 0x6A, 0x4E, 0x99, 0x30, 0xF1, 0x72, 0x8F, + 0x8F, 0x33, 0x18, 0x02, 0x1E, 0x06, 0x00, 0x03, 0x6C, 0x76, 0x8A, 0x94, 0x00, 0x01, 0x06, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xDB, 0x06, 0x00, 0x00, 0x01, 0x46, 0x00, 0x00, 0xFF, 0x03, 0x00, 0x40, + 0x00, 0x6B, 0x39, 0x03, 0x41, 0x00, 0x02, 0x9A, 0x00, 0x00, 0x6B, 0x61, 0x64, 0x78, 0x79, 0x2B, + 0xCF, 0x8A, 0x00, 0x80, 0x1C, 0x54, 0x11, 0x98, 0x00, 0x80, 0xBB, 0xBB, 0x00, 0x57, 0x22, 0x18, + 0x64, 0x11, 0x64, 0x11, 0x8A, 0x39, 0x89, 0x39, 0xB5, 0xF0, 0x3F, 0xF0, 0x66, 0x12, 0x64, 0x12, + 0x76, 0x05, 0x02, 0x00, 0x06, 0x06, 0x06, 0x06, 0xFA, 0xB5, 0x6B, 0xFF, 0x2C, 0x07, 0xFE, 0x44, + 0xCF, 0x03, 0x0C, 0x02, 0x02, 0x06, 0x01, 0x00, 0x6C, 0x76, 0x8A, 0x94, 0x00, 0x22, 0x16, 0x01, + 0x00, 0x00, 0x00, 0x00, 0xDB, 0x06, 0x00, 0x00, 0x01, 0x46, 0x00, 0x00, 0x78, 0x30, 0x00, 0x40, + 0x00, 0x6B, 0x39, 0x03, 0x41, 0x00, 0x02, 0x9A, 0x00, 0x00, 0x6B, 0x61, 0x64, 0x78, 0x79, 0x2B, + 0xCF, 0x8A, 0x00, 0x80, 0x1C, 0x54, 0x11, 0x98, 0x00, 0x80, 0xBB, 0xBB, 0x00, 0x57, 0x22, 0x18, + 0x64, 0x11, 0x64, 0x11, 0x8A, 0x39, 0x89, 0x39, 0xB5, 0xF0, 0x3F, 0xF0, 0x66, 0x12, 0x64, 0x12, + 0x76, 0x05, 0x02, 0x00, 0x07, 0x06, 0x05, 0x0A, 0xFA, 0xB5, 0x6B, 0xFF, 0x2C, 0x07, 0xFE, 0x44, + 0xCF, 0x03, 0x0C, 0x02, 0x0A, 0x06, 0x01, 0x00, 0x6C, 0x76, 0x8A, 0x94, 0x00, 0x22, 0x16, 0x01, + 0x00, 0x00, 0x00, 0x00, 0xDB, 0x06, 0x00, 0x00, 0x01, 0x46, 0x00, 0x00, 0x78, 0x30, 0x00, 0x40, + 0x00, 0x6B, 0x39, 0x03, 0x41, 0x00, 0x02, 0x9A, 0x00, 0x00, 0x6B, 0x61, 0x93, 0x67, 0xCB, 0xB4, + 0x00, 0x00, 0x00, 0x80, 0x12, 0x54, 0x11, 0x98, 0x00, 0x80, 0xBB, 0xBB, 0x00, 0x56, 0x22, 0x18, + 0x64, 0x11, 0x64, 0x11, 0x8A, 0x39, 0x89, 0x39, 0xB5, 0xF0, 0x3F, 0xF0, 0x66, 0x12, 0x64, 0x12, + 0x60, 0x05, 0x02, 0x00, 0x0C, 0x07, 0x0A, 0x0B, 0x27, 0xAC, 0x58, 0xFF, 0x84, 0x38, 0x51, 0x49, + 0xCF, 0x03, 0x0C, 0x02, 0x0A, 0x06, 0x01, 0x00, 0x6C, 0x76, 0x8A, 0x94, 0x00, 0x20, 0x16, 0x01, + 0x00, 0x00, 0x00, 0x00, 0xDB, 0x06, 0x00, 0x00, 0x01, 0x46, 0x00, 0x00, 0xA2, 0x2D, 0x00, 0x40, + 0x00, 0x6B, 0x39, 0x03, 0x41, 0x00, 0x02, 0x9A, 0x00, 0x00, 0x6B, 0x61, 0x55, 0x73, 0x7B, 0xC8, + 0x00, 0x00, 0x00, 0x80, 0x12, 0x54, 0x11, 0x98, 0x00, 0x80, 0xBB, 0xBB, 0x00, 0x56, 0x22, 0x18, + 0x64, 0x11, 0x64, 0x11, 0x8A, 0x39, 0x89, 0x39, 0xB5, 0xF0, 0x3F, 0xF0, 0x66, 0x12, 0x64, 0x12, + 0x3F, 0x05, 0x02, 0x00, 0x10, 0x09, 0x0E, 0x0C, 0x4E, 0x99, 0x33, 0xFF, 0x72, 0x8F, 0xEC, 0x50, + 0xCF, 0x03, 0x0C, 0x02, 0x0A, 0x06, 0x01, 0x00, 0x6C, 0x76, 0x8A, 0x94, 0x00, 0x1D, 0x16, 0x01, + 0x00, 0x00, 0x00, 0x00, 0xDB, 0x06, 0x00, 0x00, 0x01, 0x46, 0x00, 0x00, 0x61, 0x29, 0x00, 0x40, + 0x00, 0x6B, 0x39, 0x03, 0x41, 0x00, 0x02, 0x9A, 0x00, 0x00, 0x6B, 0x61, 0xD9, 0x77, 0x0E, 0xD3, + 0x00, 0x00, 0x00, 0x80, 0x12, 0x54, 0x11, 0x98, 0x00, 0x80, 0xBB, 0xBB, 0x00, 0x56, 0x22, 0x18, + 0x64, 0x11, 0x64, 0x11, 0x8A, 0x39, 0x89, 0x39, 0xB5, 0xF0, 0x3F, 0xF0, 0x66, 0x12, 0x64, 0x12, + 0x76, 0x05, 0x02, 0x00, 0x10, 0x0A, 0x0C, 0x06, 0xFA, 0xB5, 0x6B, 0xFF, 0x2C, 0x07, 0xFE, 0x44, + 0xCF, 0x03, 0x0C, 0x02, 0x0A, 0x06, 0x01, 0x00, 0x6C, 0x76, 0x8A, 0x94, 0x00, 0x22, 0x16, 0x01, + 0x00, 0x00, 0x00, 0x00, 0xDB, 0x06, 0x00, 0x00, 0x01, 0x46, 0x00, 0x00, 0x78, 0x30, 0x00, 0x40, + 0x00, 0x6B, 0x39, 0x03, 0x41, 0x00, 0x02, 0x9A, 0x00, 0x00, 0x6B, 0x61, 0xBD, 0x79, 0x77, 0xD8, + 0x00, 0x00, 0x00, 0x80, 0x12, 0x54, 0x11, 0x98, 0x00, 0x80, 0xBB, 0xBB, 0x00, 0x56, 0x22, 0x18, + 0x64, 0x11, 0x64, 0x11, 0x8A, 0x39, 0x89, 0x39, 0xB5, 0xF0, 0x3F, 0xF0, 0x66, 0x12, 0x64, 0x12, + 0x01, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0xCC, 0xF5, 0x7A, 0xFD, 0xED, 0x20, 0xBF, 0x8F, + 0xCF, 0x03, 0x04, 0x02, 0x02, 0x06, 0x00, 0x00, 0x6C, 0x76, 0x8A, 0x94, 0x01, 0x01, 0x06, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xDB, 0x06, 0x00, 0x00, 0x01, 0x06, 0x00, 0x00, 0xCE, 0x66, 0x00, 0x40, + 0x00, 0x6B, 0x39, 0x03, 0x41, 0x00, 0x02, 0x9A, 0x00, 0x00, 0x6B, 0x61, 0x64, 0x78, 0x79, 0x2B, + 0xCF, 0x8A, 0x00, 0x80, 0x1C, 0xC4, 0x10, 0x18, 0x03, 0x80, 0xAB, 0xAA, 0x00, 0xC6, 0x22, 0x78, + 0x64, 0x11, 0x64, 0x11, 0x80, 0x39, 0x80, 0x39, 0x0F, 0x00, 0x0F, 0x00, 0x55, 0x0D, 0x55, 0x0D, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x56, 0xCE, + 0x00, 0x00, 0x99, 0x10, 0x10, 0x0E, 0x00, 0x06, 0x00, 0x00, 0xFD, 0xF9, 0x00, 0x00, 0x6F, 0xA1, + 0x10, 0x0E, 0x00, 0x05, 0x00, 0x00, 0x46, 0x4F, 0x00, 0x00, 0x29, 0xA6, 0x10, 0x0F, 0x00, 0x04, + 0x00, 0x00, 0xAD, 0x87, 0x00, 0x00, 0x7D, 0xD9, 0x10, 0x0F, 0x00, 0x03, 0x00, 0x00, 0xE0, 0x86, + 0x00, 0x00, 0x9F, 0x8B, 0x00, 0x0D, 0x10, 0x08, 0x00, 0x00, 0x56, 0xCF, 0x00, 0x00, 0x72, 0xCB, + 0x00, 0x0B, 0x10, 0x0A, 0x00, 0x00, 0xFF, 0x9E, 0x00, 0x00, 0xBE, 0xC8, 0x00, 0x09, 0x10, 0x0C, + 0x00, 0x00, 0x2A, 0xDF, 0x00, 0x00, 0xFE, 0x72, 0x00, 0x06, 0x10, 0x0E, 0x00, 0x00, 0xD1, 0x57, + 0x00, 0x00, 0x37, 0x66, 0x00, 0x04, 0x10, 0x0F, 0x00, 0x00, 0x8E, 0xBE, 0x00, 0x00, 0x93, 0x36, + 0x00, 0x0E, 0x10, 0x06, 0x00, 0x00, 0x4F, 0x50, 0x00, 0x00, 0x4E, 0x50, 0x00, 0x0B, 0x10, 0x0B, + 0x00, 0x00, 0xEC, 0xAF, 0x00, 0x00, 0xAD, 0x6F, 0x00, 0x08, 0x10, 0x0D, 0x00, 0x00, 0x79, 0x1F, + 0x00, 0x00, 0x35, 0xC8, 0x00, 0x06, 0x10, 0x0E, 0x00, 0x00, 0xC1, 0x87, 0x00, 0x00, 0xD3, 0xB2, + 0x00, 0x0E, 0x10, 0x06, 0x00, 0x00, 0x7C, 0xE8, 0x00, 0x00, 0x3F, 0x74, 0x00, 0x0C, 0x10, 0x09, + 0x00, 0x00, 0x22, 0x64, 0x00, 0x00, 0xA0, 0x2A, 0x00, 0x0A, 0x10, 0x0C, 0x00, 0x00, 0xD8, 0x8A, + 0x00, 0x00, 0x58, 0x1C, 0x00, 0x07, 0x10, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x24, 0x02, 0x00, 0x00, 0xD4, 0x5B, 0x06, 0xA7, 0x15, 0xD2, 0x7C, 0xEC, + 0x0A, 0x69, 0x3E, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xC0, 0x22, 0xC0, 0x22, 0xDC, 0x0C, 0x00, 0x00, 0x69, 0x3E, 0xB6, 0xE6, 0xD7, 0xFC, 0x9A, 0x5F, + 0xF3, 0x6B, 0xBE, 0x32, 0xA8, 0xF9, 0xCA, 0xA0, 0xE6, 0x2B, 0x83, 0x9A, 0x5F, 0xF3, 0x6B, 0x7E, + 0xCD, 0x57, 0x06, 0xCA, 0xA0, 0xE6, 0x2B, 0x83, 0x9A, 0x5F, 0xF3, 0x95, 0x41, 0xCD, 0x57, 0x06, + 0x35, 0x5F, 0x19, 0xD4, 0x7C, 0x65, 0xA0, 0x0C, 0x94, 0x41, 0xCD, 0x07, 0x00, 0x00, 0x00, 0x00, + 0xED, 0x22, 0xED, 0x22, 0xDC, 0x0C, 0x00, 0x00, 0x69, 0x3E, 0xB6, 0xE6, 0xD7, 0xFC, 0x9A, 0xAF, + 0x0C, 0x94, 0x41, 0xCD, 0xAF, 0xF9, 0xCA, 0xA0, 0xE6, 0x2B, 0x83, 0x9A, 0xAF, 0x0C, 0x94, 0x81, + 0x32, 0x50, 0x06, 0x35, 0xBF, 0xE6, 0x2B, 0x83, 0x9A, 0xAF, 0x0C, 0x6A, 0x7E, 0xCD, 0x57, 0x06, + 0x35, 0xBF, 0xE6, 0xD7, 0x7C, 0x65, 0x50, 0xF3, 0x95, 0x81, 0x32, 0x00, 0xD4, 0x7C, 0x65, 0x00, + 0xED, 0x22, 0xED, 0x22, 0xDC, 0x0C, 0x00, 0x00, 0x69, 0x3E, 0x56, 0x19, 0xD4, 0xFC, 0x9A, 0xAF, + 0x0C, 0x94, 0x41, 0xCD, 0xAF, 0xF9, 0x35, 0xBF, 0xE6, 0x2B, 0x83, 0x9A, 0x5F, 0xF3, 0x6B, 0xBE, + 0x32, 0xA8, 0xF9, 0x35, 0xBF, 0xE6, 0x2B, 0x83, 0x9A, 0x5F, 0xF3, 0x95, 0x41, 0xCD, 0xAF, 0xF9, + 0x35, 0xBF, 0xE6, 0xD7, 0xFC, 0x9A, 0xAF, 0x0C, 0x94, 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xED, 0x22, 0xED, 0x22, 0xDC, 0x0C, 0x00, 0x00, 0x69, 0x3E, 0x56, 0x19, 0xD4, 0xFC, 0x9A, 0xAF, + 0x0C, 0x94, 0x41, 0xCD, 0xAF, 0xF9, 0x35, 0xBF, 0xE6, 0xD7, 0xFC, 0x9A, 0x5F, 0xF3, 0x6B, 0x7E, + 0xCD, 0xAF, 0xF9, 0xCA, 0xA0, 0xE6, 0x2B, 0x83, 0x9A, 0x5F, 0xF3, 0x6B, 0x7E, 0xCD, 0xAF, 0xF9, + 0x35, 0xBF, 0xE6, 0x2B, 0x83, 0x9A, 0x5F, 0xF3, 0x6B, 0x7E, 0xCD, 0x07, 0xD4, 0x7C, 0x65, 0x00, + 0xED, 0x22, 0xED, 0x22, 0xDC, 0x0C, 0x00, 0x00, 0x69, 0x3E, 0x56, 0x19, 0xD4, 0xFC, 0x9A, 0x5F, + 0xF3, 0x6B, 0x7E, 0xCD, 0xAF, 0xF9, 0xCA, 0xA0, 0xE6, 0xD7, 0xFC, 0x9A, 0x5F, 0xF3, 0x6B, 0xBE, + 0x32, 0x50, 0x06, 0xCA, 0x40, 0x19, 0xD4, 0xFC, 0x9A, 0x5F, 0xF3, 0x6B, 0x7E, 0xCD, 0x57, 0x06, + 0x35, 0xBF, 0xE6, 0x2B, 0x03, 0x65, 0xA0, 0x0C, 0x94, 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xED, 0x22, 0xED, 0x22, 0xDC, 0x0C, 0x00, 0x00, 0x69, 0x3E, 0x56, 0x19, 0xD4, 0xFC, 0x9A, 0xAF, + 0x0C, 0x6A, 0x7E, 0xCD, 0xAF, 0xF9, 0xCA, 0xA0, 0xE6, 0xD7, 0xFC, 0x9A, 0x5F, 0xF3, 0x6B, 0xBE, + 0x32, 0xA8, 0xF9, 0x35, 0xBF, 0xE6, 0x2B, 0x03, 0x65, 0x50, 0xF3, 0x6B, 0x7E, 0xCD, 0xAF, 0xF9, + 0x35, 0xBF, 0xE6, 0xD7, 0xFC, 0x9A, 0xAF, 0x0C, 0x6A, 0xBE, 0x32, 0x00, 0xD4, 0x7C, 0x65, 0x00, + 0xED, 0x22, 0xED, 0x22, 0x31, 0x30, 0x2F, 0x2E, 0x2D, 0x2C, 0x2B, 0x2A, 0x29, 0x28, 0x27, 0x26, + 0x25, 0x24, 0x23, 0x22, 0x21, 0x20, 0x1F, 0x1E, 0x1D, 0x1C, 0x1B, 0x1A, 0x19, 0x18, 0x17, 0x16, + 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x0F, 0x0E, 0x0D, 0x0C, 0x0B, 0x0A, 0x09, 0x08, 0x07, 0x06, + 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4A, 0x49, 0x48, 0x47, + 0x46, 0x45, 0x44, 0x43, 0x42, 0x41, 0x40, 0x3F, 0x3E, 0x3D, 0x3C, 0x3B, 0x3A, 0x39, 0x38, 0x37, + 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x30, 0x2F, 0x2E, 0x2D, 0x2C, 0x2B, 0x2A, 0x29, 0x28, 0x27, + 0x26, 0x25, 0x24, 0x23, 0x22, 0x21, 0x20, 0x1F, 0x1E, 0x1D, 0x1C, 0x1B, 0x1A, 0x19, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0xE0, 0xC0, 0xA0, 0x80, 0x60, 0x40, 0x20, 0x00, 0xE0, 0xC0, + 0xA0, 0x80, 0x60, 0x40, 0x20, 0x00, 0xE0, 0xC0, 0xA0, 0x80, 0x60, 0x40, 0x20, 0x00, 0xE0, 0xC0, + 0xA0, 0x80, 0x60, 0x40, 0x20, 0x00, 0xE0, 0xC0, 0xA0, 0x80, 0x60, 0x40, 0x20, 0x00, 0xE0, 0xC0, + 0xA0, 0x80, 0x60, 0x40, 0x20, 0x00, 0x00, 0x00, 0x76, 0xDB, 0xB6, 0x2D, 0x24, 0x49, 0x92, 0x1B, + 0xDB, 0xB6, 0x49, 0x12, 0x92, 0x94, 0x24, 0x09, 0x09, 0x00, 0x00, 0x00, 0x20, 0x00, 0xE0, 0xC0, + 0xA0, 0x80, 0x60, 0x40, 0x20, 0x00, 0xE0, 0xC0, 0xA0, 0x80, 0x60, 0x40, 0x20, 0x00, 0xE0, 0xC0, + 0xA0, 0x80, 0x60, 0x40, 0x20, 0x00, 0xE0, 0xC0, 0xA0, 0x80, 0x60, 0x40, 0x20, 0x00, 0xE0, 0xC0, + 0xA0, 0x80, 0x60, 0x40, 0x20, 0x00, 0xE0, 0xC0, 0xA0, 0x80, 0x60, 0x40, 0x20, 0x00, 0x00, 0x00, + 0x76, 0xDB, 0xB6, 0x2D, 0x24, 0x49, 0x92, 0x1B, 0xDB, 0xB6, 0x49, 0x12, 0x92, 0x94, 0x24, 0x09, + 0x09, 0x00, 0x00, 0x00, 0x20, 0x21, 0xE0, 0xE1, 0xA0, 0xA1, 0x60, 0x61, 0x20, 0x21, 0xE0, 0xE1, + 0xA0, 0xA1, 0x60, 0x61, 0x20, 0x21, 0xE0, 0xE1, 0xA0, 0xA1, 0x60, 0x61, 0x20, 0x21, 0xE0, 0xE1, + 0xA0, 0xA1, 0x60, 0x61, 0x20, 0x21, 0xE0, 0xE1, 0xA0, 0xA1, 0x60, 0x61, 0x20, 0x21, 0xE0, 0xE1, + 0xA0, 0xA1, 0x60, 0x61, 0x20, 0x21, 0x00, 0x00, 0x76, 0xDB, 0xB6, 0x2D, 0x24, 0x49, 0x92, 0x1B, + 0xDB, 0xB6, 0x49, 0x12, 0x92, 0x94, 0x24, 0x09, 0x09, 0x00, 0x00, 0x00, 0x01, 0x00, 0xC1, 0xC0, + 0x81, 0x80, 0x41, 0x40, 0x01, 0x00, 0xC1, 0xC0, 0x81, 0x80, 0x41, 0x40, 0x01, 0x00, 0xC1, 0xC0, + 0x81, 0x80, 0x41, 0x40, 0x01, 0x00, 0xC1, 0xC0, 0x81, 0x80, 0x41, 0x40, 0x01, 0x00, 0xC1, 0xC0, + 0x81, 0x80, 0x41, 0x40, 0x01, 0x00, 0xC1, 0xC0, 0x81, 0x80, 0x41, 0x40, 0x01, 0x00, 0x00, 0x00, + 0x76, 0xDB, 0xB6, 0x2D, 0x24, 0x49, 0x92, 0x1B, 0xDB, 0xB6, 0x49, 0x12, 0x92, 0x94, 0x24, 0x09, + 0x09, 0x00, 0x00, 0x00, 0x21, 0x20, 0xE1, 0xE0, 0xA1, 0xA0, 0x61, 0x60, 0x21, 0x20, 0xE1, 0xE0, + 0xA1, 0xA0, 0x61, 0x60, 0x21, 0x20, 0xE1, 0xE0, 0xA1, 0xA0, 0x61, 0x60, 0x21, 0x20, 0xE1, 0xE0, + 0xA1, 0xA0, 0x61, 0x60, 0x21, 0x20, 0xE1, 0xE0, 0xA1, 0xA0, 0x61, 0x60, 0x21, 0x20, 0xE1, 0xE0, + 0xA1, 0xA0, 0x61, 0x60, 0x21, 0x20, 0x00, 0x00, 0x76, 0xDB, 0xB6, 0x2D, 0x24, 0x49, 0x92, 0x1B, + 0xDB, 0xB6, 0x49, 0x12, 0x92, 0x94, 0x24, 0x09, 0x09, 0x00, 0x00, 0x00, 0x63, 0x43, 0x23, 0x03, + 0xE2, 0xC2, 0xA2, 0x82, 0x62, 0x42, 0x22, 0x02, 0xE2, 0xC2, 0xA2, 0x82, 0x62, 0x42, 0x22, 0x02, + 0xE2, 0xC2, 0xA2, 0x82, 0x62, 0x42, 0x22, 0x02, 0xE2, 0xC2, 0xA2, 0x82, 0x62, 0x42, 0x22, 0x02, + 0xE2, 0xC2, 0xA2, 0x82, 0x62, 0x42, 0x22, 0x02, 0xE2, 0xC2, 0xA2, 0x82, 0x62, 0x42, 0x00, 0x00, + 0x00, 0xD0, 0xB6, 0x2D, 0x2D, 0x49, 0x92, 0x24, 0xDB, 0xB6, 0x6D, 0x12, 0x92, 0x24, 0x25, 0x09, + 0x49, 0x02, 0x00, 0x00, 0x2C, 0x0C, 0xEC, 0xCC, 0xAC, 0x8C, 0x6C, 0x4C, 0x2C, 0x0C, 0xEC, 0xCC, + 0xAC, 0x8C, 0x6C, 0x4C, 0x2C, 0x0C, 0xEC, 0xCC, 0xAC, 0x8C, 0x6C, 0x4C, 0x2C, 0x0C, 0xEC, 0xCC, + 0xAC, 0x8C, 0x6C, 0x4C, 0x2C, 0x0C, 0xEC, 0xCC, 0xAC, 0x8C, 0x6C, 0x4C, 0x2C, 0x0C, 0xEB, 0xCB, + 0xAB, 0x8B, 0x6B, 0x4B, 0x2B, 0x0B, 0x00, 0x00, 0x2D, 0x49, 0x92, 0x24, 0xDB, 0xB6, 0x6D, 0x12, + 0x92, 0x24, 0x25, 0x09, 0x49, 0x02, 0x00, 0x00, 0x40, 0xDB, 0xB6, 0x2D, 0xA4, 0x84, 0x64, 0x44, + 0x24, 0x04, 0xE3, 0xC3, 0xA3, 0x83, 0x63, 0x43, 0x23, 0x03, 0xE3, 0xC3, 0xA3, 0x83, 0x63, 0x43, + 0x23, 0x03, 0xE3, 0xC3, 0xA3, 0x83, 0x63, 0x43, 0x23, 0x03, 0xE3, 0xC3, 0xA3, 0x83, 0x63, 0x43, + 0x23, 0x03, 0xE3, 0xC3, 0xA3, 0x83, 0x63, 0x43, 0x23, 0x03, 0xE3, 0xC3, 0xA3, 0x83, 0x00, 0x00, + 0x00, 0x00, 0xB4, 0x2D, 0x6D, 0x4B, 0x92, 0x24, 0xE4, 0xB6, 0x6D, 0x1B, 0x92, 0x24, 0x49, 0x09, + 0x49, 0x92, 0x00, 0x00, 0xEB, 0xCB, 0xAB, 0x8B, 0x6B, 0x4B, 0x2B, 0x0B, 0xEB, 0xCB, 0xAB, 0x8B, + 0x6B, 0x4B, 0x2B, 0x0B, 0xEB, 0xCB, 0xAB, 0x8B, 0x6B, 0x4B, 0x2B, 0x0B, 0xEB, 0xCB, 0xAB, 0x8B, + 0x6B, 0x4B, 0x2B, 0x0B, 0xEB, 0xCB, 0xAB, 0x8B, 0x6B, 0x4B, 0x2B, 0x0B, 0xEA, 0xCA, 0xAA, 0x8A, + 0x6A, 0x4A, 0x2A, 0x0A, 0xEA, 0xCA, 0x00, 0x00, 0x24, 0x49, 0x92, 0x1B, 0xDB, 0xB6, 0x49, 0x12, + 0x92, 0x94, 0x24, 0x09, 0x09, 0x00, 0x00, 0x00, 0x6D, 0xDB, 0xB6, 0x24, 0xE5, 0xC5, 0xA5, 0x85, + 0x65, 0x45, 0x25, 0x05, 0xE4, 0xC4, 0xA4, 0x84, 0x64, 0x44, 0x24, 0x04, 0xE4, 0xC4, 0xA4, 0x84, + 0x64, 0x44, 0x24, 0x04, 0xE4, 0xC4, 0xA4, 0x84, 0x64, 0x44, 0x24, 0x04, 0xE4, 0xC4, 0xA4, 0x84, + 0x64, 0x44, 0x24, 0x04, 0xE4, 0xC4, 0xA4, 0x84, 0x64, 0x44, 0x24, 0x04, 0xE4, 0xC4, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x2D, 0x6D, 0xDB, 0x92, 0x24, 0x24, 0xB9, 0x6D, 0x1B, 0x9B, 0x24, 0x49, 0x12, + 0x49, 0x92, 0x24, 0x00, 0xAA, 0x8A, 0x6A, 0x4A, 0x2A, 0x0A, 0xEA, 0xCA, 0xAA, 0x8A, 0x6A, 0x4A, + 0x2A, 0x0A, 0xEA, 0xCA, 0xAA, 0x8A, 0x6A, 0x4A, 0x2A, 0x0A, 0xEA, 0xCA, 0xAA, 0x8A, 0x6A, 0x4A, + 0x2A, 0x0A, 0xEA, 0xCA, 0xAA, 0x8A, 0x6A, 0x4A, 0x2A, 0x0A, 0xE9, 0xC9, 0xA9, 0x89, 0x69, 0x49, + 0x29, 0x09, 0xE9, 0xC9, 0xA9, 0x89, 0x00, 0x00, 0x24, 0x49, 0x6E, 0x1B, 0xDB, 0x26, 0x49, 0x12, + 0x52, 0x92, 0x24, 0x09, 0x00, 0x00, 0x00, 0x2D, 0x6D, 0xDB, 0x92, 0x24, 0x26, 0x06, 0xE6, 0xC6, + 0xA6, 0x86, 0x66, 0x46, 0x26, 0x06, 0xE5, 0xC5, 0xA5, 0x85, 0x65, 0x45, 0x25, 0x05, 0xE5, 0xC5, + 0xA5, 0x85, 0x65, 0x45, 0x25, 0x05, 0xE5, 0xC5, 0xA5, 0x85, 0x65, 0x45, 0x25, 0x05, 0xE5, 0xC5, + 0xA5, 0x85, 0x65, 0x45, 0x25, 0x05, 0xE5, 0xC5, 0xA5, 0x85, 0x65, 0x45, 0x25, 0x05, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x6D, 0xDB, 0xB6, 0x24, 0x24, 0x49, 0x6E, 0x1B, 0xDB, 0x26, 0x49, 0x12, + 0x52, 0x92, 0x24, 0x09, 0x69, 0x49, 0x29, 0x09, 0xE9, 0xC9, 0xA9, 0x89, 0x69, 0x49, 0x29, 0x09, + 0xE9, 0xC9, 0xA9, 0x89, 0x69, 0x49, 0x29, 0x09, 0xE9, 0xC9, 0xA9, 0x89, 0x69, 0x49, 0x29, 0x09, + 0xE9, 0xC9, 0xA9, 0x89, 0x69, 0x49, 0x29, 0x09, 0xE8, 0xC8, 0xA8, 0x88, 0x68, 0x48, 0x28, 0x08, + 0xE8, 0xC8, 0xA8, 0x88, 0x68, 0x48, 0x00, 0x00, 0x24, 0xB9, 0x6D, 0x1B, 0x9B, 0x24, 0x49, 0x12, + 0x49, 0x92, 0x24, 0x00, 0x00, 0x00, 0xB4, 0x2D, 0x6D, 0x4B, 0x92, 0x24, 0x67, 0x47, 0x27, 0x07, + 0xE7, 0xC7, 0xA7, 0x87, 0x67, 0x47, 0x27, 0x07, 0xE6, 0xC6, 0xA6, 0x86, 0x66, 0x46, 0x26, 0x06, + 0xE6, 0xC6, 0xA6, 0x86, 0x66, 0x46, 0x26, 0x06, 0xE6, 0xC6, 0xA6, 0x86, 0x66, 0x46, 0x26, 0x06, + 0xE6, 0xC6, 0xA6, 0x86, 0x66, 0x46, 0x26, 0x06, 0xE6, 0xC6, 0xA6, 0x86, 0x66, 0x46, 0x00, 0x00, + 0x49, 0x02, 0x00, 0x00, 0x40, 0xDB, 0xB6, 0x2D, 0x24, 0x49, 0x92, 0x1B, 0xDB, 0xB6, 0x49, 0x12, + 0x92, 0x94, 0x24, 0x09, 0x28, 0x08, 0xE8, 0xC8, 0xA8, 0x88, 0x68, 0x48, 0x28, 0x08, 0xE8, 0xC8, + 0xA8, 0x88, 0x68, 0x48, 0x28, 0x08, 0xE8, 0xC8, 0xA8, 0x88, 0x68, 0x48, 0x28, 0x08, 0xE8, 0xC8, + 0xA8, 0x88, 0x68, 0x48, 0x28, 0x08, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xE4, 0xB6, 0x6D, 0x1B, 0x92, 0x24, 0x49, 0x09, + 0x49, 0x92, 0x00, 0x00, 0x00, 0xF0, 0xFF, 0x3F, 0xFF, 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE7, 0xC7, 0xA7, 0x87, 0x67, 0x47, + 0x27, 0x07, 0xE7, 0xC7, 0xA7, 0x87, 0x67, 0x47, 0x27, 0x07, 0xE7, 0xC7, 0xA7, 0x87, 0x67, 0x47, + 0x27, 0x07, 0xE7, 0xC7, 0xA7, 0x87, 0x67, 0x47, 0x27, 0x07, 0xE7, 0xC7, 0xA7, 0x87, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0x3F, 0xFF, 0xDF, 0xB6, 0x2D, 0x2D, 0x49, 0x92, 0x24, 0xDB, 0xB6, 0x6D, 0x12, + 0x92, 0x24, 0x25, 0x09, 0x63, 0x62, 0x61, 0x60, 0x5F, 0x5E, 0x5D, 0x5C, 0x5B, 0x5A, 0x59, 0x58, + 0x57, 0x56, 0x55, 0x54, 0x53, 0x52, 0x51, 0x50, 0x4F, 0x4E, 0x4D, 0x4C, 0x4B, 0x4A, 0x49, 0x48, + 0x47, 0x46, 0x45, 0x44, 0x43, 0x42, 0x41, 0x40, 0x3F, 0x3E, 0x3D, 0x3C, 0x3B, 0x3A, 0x39, 0x38, + 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x31, 0x30, 0x2F, 0x2E, + 0x2D, 0x2C, 0x2B, 0x2A, 0x29, 0x28, 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21, 0x20, 0x1F, 0x1E, + 0x1D, 0x1C, 0x1B, 0x1A, 0x19, 0x18, 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x0F, 0x0E, + 0x0D, 0x0C, 0x0B, 0x0A, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0xFF, 0x3F, + 0xFF, 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0xFF, 0x3F, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x57, 0x47, 0x37, 0x27, 0x17, 0x07, 0x56, 0x46, 0x36, 0x26, 0x16, 0x06, + 0x55, 0x45, 0x35, 0x25, 0x15, 0x05, 0x54, 0x44, 0x34, 0x24, 0x14, 0x04, 0x53, 0x43, 0x33, 0x23, + 0x13, 0x03, 0x52, 0x42, 0x32, 0x22, 0x12, 0x02, 0x51, 0x41, 0x31, 0x21, 0x11, 0x01, 0x50, 0x40, + 0x30, 0x20, 0x10, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x62, 0x60, 0x5E, 0x5C, + 0x5A, 0x58, 0x56, 0x54, 0x52, 0x50, 0x4E, 0x4C, 0x4A, 0x48, 0x46, 0x44, 0x42, 0x40, 0x3E, 0x3C, + 0x3A, 0x38, 0x36, 0x34, 0x32, 0x30, 0x2E, 0x2C, 0x2A, 0x28, 0x26, 0x24, 0x22, 0x20, 0x1E, 0x1C, + 0x1A, 0x18, 0x16, 0x14, 0x12, 0x10, 0x0E, 0x0C, 0x0A, 0x08, 0x06, 0x04, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x08, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32, 0x02, 0x10, 0x00, + 0x00, 0x00, 0x76, 0x5F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x8C, 0x0C, 0x00, 0x00, 0xAF, 0x0C, 0x00, 0x00, 0xD2, 0x0C, 0x00, 0x00, 0xF5, 0x0C, 0x00, 0x00, + 0x20, 0x03, 0x00, 0x00, 0x41, 0x10, 0x08, 0x03, 0x44, 0x61, 0x1C, 0x08, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0A, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x56, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x18, 0x0D, 0xD6, 0x0D, 0x06, 0x0E, 0x1F, 0x0E, + 0x53, 0x0F, 0x58, 0x0E, 0x30, 0x0F, 0x42, 0x0F, 0x43, 0x0F, 0x7E, 0x17, 0x07, 0xB8, 0xC3, 0x07, + 0x00, 0x80, 0x00, 0x00, 0x20, 0x83, 0x00, 0x00, 0x00, 0x80, 0x32, 0x80, 0x64, 0x80, 0x96, 0x80, + 0x2D, 0xB4, 0x04, 0x0F, 0x11, 0x0C, 0x0F, 0x0F, 0x10, 0x00, 0x0F, 0x13, 0xA5, 0xBA, 0x03, 0x0A, + 0x18, 0xC8, 0x0F, 0x00, 0x15, 0x10, 0x15, 0x10, 0x10, 0x43, 0x10, 0x43, 0x20, 0x03, 0x00, 0x00, + 0xCB, 0xB2, 0x30, 0x0D, 0xCE, 0x03, 0x45, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, + 0x66, 0x66, 0x66, 0x66, 0x56, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, + 0x03, 0x00, 0x00, 0x00, 0x18, 0x0D, 0xD6, 0x0D, 0x06, 0x0E, 0x1F, 0x0E, 0x53, 0x0F, 0x58, 0x0E, + 0x30, 0x0F, 0x42, 0x0F, 0x43, 0x0F, 0x7E, 0x17, 0x07, 0xB8, 0x07, 0x33, 0x00, 0x80, 0x00, 0x00, + 0x20, 0x83, 0x00, 0x00, 0x00, 0x80, 0x32, 0x80, 0x64, 0x80, 0x96, 0x80, 0x2D, 0xB4, 0x04, 0x0F, + 0x11, 0x0C, 0x0F, 0x0F, 0x90, 0x00, 0x0F, 0x13, 0xA5, 0xBA, 0x83, 0x0A, 0x18, 0xC8, 0x0F, 0x00, + 0x15, 0x10, 0x15, 0x10, 0x10, 0x43, 0x10, 0x43, 0x45, 0x09, 0x7E, 0x17, 0x07, 0xB8, 0xC3, 0x07, + 0x00, 0x80, 0x00, 0x80, 0x20, 0xF3, 0x00, 0x0C, 0x00, 0x80, 0x32, 0x80, 0x64, 0x80, 0x96, 0xFE, + 0x2D, 0xB4, 0xFF, 0xFF, 0x11, 0xFD, 0xFF, 0xFF, 0xD0, 0xFF, 0x0F, 0x13, 0xA5, 0xBA, 0x83, 0x0A, + 0x18, 0xC8, 0x0F, 0x00, 0x13, 0x0F, 0x13, 0x0F, 0x0F, 0x41, 0x0F, 0x41, 0x1F, 0x03, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x8D, 0xD6, 0x8D, 0x06, 0x8E, 0x1F, 0x8E, 0x53, 0x8F, 0x58, 0x8E, 0x30, 0x8F, 0x42, 0x8F, + 0x43, 0x8F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xE6, 0x00, 0x00, 0xEC, 0x04, 0x54, 0xE7, 0xE4, 0x07, 0x7E, 0xE7, 0x55, 0x09, 0xA2, 0x07, + 0x0A, 0x09, 0x25, 0x09, 0x45, 0x09, 0x7E, 0x17, 0x07, 0xB8, 0xC3, 0x07, 0x00, 0x80, 0x00, 0x00, + 0x20, 0x83, 0x00, 0x00, 0x00, 0x80, 0x32, 0x80, 0x64, 0x80, 0x96, 0x80, 0x2D, 0xB4, 0x04, 0x8F, + 0x11, 0xFD, 0xFF, 0xFF, 0xD0, 0xFF, 0x0F, 0x93, 0xA5, 0xBA, 0x83, 0x0A, 0x18, 0xE8, 0x0F, 0xE0, + 0x13, 0x0F, 0x13, 0xFF, 0x0F, 0x41, 0x0F, 0x41, 0x1F, 0x03, 0x00, 0x00, 0xD4, 0xB8, 0x04, 0x02, + 0x03, 0x51, 0x18, 0x87, 0x48, 0xF0, 0x0C, 0x0C, 0x85, 0x01, 0x1C, 0x08, 0x18, 0x8D, 0xD6, 0x8D, + 0x06, 0x8E, 0x1F, 0x8E, 0x53, 0x8F, 0x58, 0x8E, 0x30, 0x8F, 0x42, 0x8F, 0x43, 0x8F, 0x55, 0x55, + 0x55, 0x55, 0x55, 0xD5, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x08, 0x6A, 0x66, 0x66, + 0x66, 0x66, 0x66, 0x66, 0x36, 0x66, 0x00, 0x27, 0x00, 0x00, 0x00, 0x00, 0x02, 0xE6, 0x00, 0x80, + 0xEC, 0x0C, 0x54, 0xEF, 0xE4, 0x87, 0x7E, 0xE7, 0x55, 0x09, 0xA2, 0x07, 0x0A, 0xE9, 0x25, 0xE9, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x28, 0x02, 0x00, 0x00, 0x00, 0xFC, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x0D, 0x00, 0x59, 0x06, 0x40, 0x06, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x55, 0x97, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x02, + 0x00, 0x28, 0x00, 0x00, 0x80, 0x02, 0xFC, 0x00, 0xFF, 0xFF, 0xFF, 0x01, 0x0D, 0x00, 0x0D, 0x00, + 0x07, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xB0, 0xB3, 0x00, 0x00, 0x00, 0x00, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x00, 0x28, 0x00, 0x00, 0x80, 0x02, 0xFC, 0x00, + 0xFF, 0xFF, 0xFF, 0x01, 0x0D, 0x00, 0x0D, 0x00, 0x06, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x04, 0xC4, 0xB3, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x02, 0x02, + 0x00, 0x28, 0x00, 0x00, 0x80, 0x02, 0xFC, 0x00, 0xFF, 0xFF, 0xFF, 0x01, 0x0D, 0x00, 0x0D, 0x00, + 0x05, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xD8, 0xB3, 0x00, 0x00, 0x00, 0x00, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x02, 0x02, 0x00, 0x28, 0x00, 0x00, 0x80, 0x02, 0xFC, 0x00, + 0xFF, 0xFF, 0xFF, 0x01, 0x0D, 0x00, 0x0D, 0x00, 0x04, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x04, 0xEC, 0xB3, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x02, 0x02, + 0x00, 0x28, 0x00, 0x00, 0x80, 0x02, 0xFC, 0x00, 0xFF, 0xFF, 0xFF, 0x01, 0x0D, 0x00, 0x0D, 0x00, + 0x03, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0xB4, 0x00, 0x00, 0x00, 0x00, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x02, 0x02, 0x00, 0x28, 0x00, 0x00, 0x80, 0x02, 0xFC, 0x00, + 0xFF, 0xFF, 0xFF, 0x01, 0x0D, 0x00, 0x0D, 0x00, 0x02, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x14, 0xB4, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x02, 0x02, + 0x00, 0x28, 0x00, 0x00, 0x80, 0x02, 0xFC, 0x00, 0xFF, 0xFF, 0xFF, 0x01, 0x0D, 0x00, 0x0D, 0x00, + 0x01, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x28, 0xB4, 0x00, 0x00, 0x00, 0x00, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x02, 0x02, 0x00, 0x28, 0x04, 0x00, 0x80, 0x02, 0xFC, 0x00, + 0xFF, 0xFF, 0xFF, 0x01, 0x0D, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x20, 0xB0, 0xB3, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x28, 0x06, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x0D, 0x00, + 0xD2, 0x0F, 0xA0, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x01, 0x50, 0x97, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x02, 0x00, 0x00, 0x00, 0xFC, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x0D, 0x00, 0xC1, 0x16, 0xA8, 0x16, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x8C, 0x97, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x02, 0x02, + 0x00, 0x28, 0x00, 0x00, 0x80, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x0D, 0x00, + 0x07, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xB0, 0xB3, 0x00, 0x00, 0x00, 0x00, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x02, 0x02, 0x00, 0x28, 0x00, 0x00, 0x80, 0x00, 0xFC, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x0D, 0x00, 0x06, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x04, 0xC4, 0xB3, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x02, 0x02, + 0x00, 0x28, 0x00, 0x00, 0x80, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x0D, 0x00, + 0x05, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xD8, 0xB3, 0x00, 0x00, 0x00, 0x00, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x02, 0x02, 0x00, 0x28, 0x00, 0x00, 0x80, 0x00, 0xFC, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x0D, 0x00, 0x04, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x04, 0xEC, 0xB3, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x02, 0x02, + 0x00, 0x28, 0x00, 0x00, 0x80, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x0D, 0x00, + 0x03, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0xB4, 0x00, 0x00, 0x00, 0x00, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x02, 0x02, 0x00, 0x28, 0x00, 0x00, 0x80, 0x00, 0xFC, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x0D, 0x00, 0x02, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x14, 0xB4, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x02, 0x02, + 0x00, 0x28, 0x00, 0x00, 0x80, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x0D, 0x00, + 0x01, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x28, 0xB4, 0x00, 0x00, 0x00, 0x00, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x02, 0x02, 0x00, 0x28, 0x04, 0x00, 0x80, 0x00, 0xFC, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x20, 0xB0, 0xB3, 0x00, 0x00, 0x00, 0x00, 0x10, 0x4F, 0x00, 0x00, 0x00, 0x01, 0xF4, 0x04, 0x00, + 0x68, 0x93, 0x1B, 0x00, 0x60, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x01, 0x00, 0x04, 0x00, + 0x14, 0x28, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x2D, 0x00, 0x84, 0x00, + 0x14, 0x28, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x73, 0x00, 0x00, 0x00, 0x2D, 0xF4, 0x84, 0x00, + 0x68, 0x93, 0x1B, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x2D, 0xF4, 0x84, 0x00, + 0x68, 0x93, 0x1B, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x73, 0x00, 0x00, 0x00, 0x2D, 0xF4, 0x84, 0x00, + 0x68, 0x93, 0x1B, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x63, 0x00, 0x00, 0x00, 0x2D, 0xF4, 0x84, 0x00, + 0x68, 0x93, 0x1B, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x4F, 0x00, 0x00, 0x00, 0x01, 0xF4, 0x04, 0x00, + 0x68, 0x93, 0x1B, 0x00, 0xE0, 0x00, 0x01, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x01, 0x00, 0x04, 0x00, + 0x14, 0x28, 0x00, 0x00, 0xE0, 0x00, 0x01, 0x00, 0x30, 0x00, 0x00, 0x00, 0x2D, 0x00, 0x84, 0x00, + 0x14, 0x28, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x2D, 0xF4, 0x84, 0x00, + 0x68, 0x93, 0x1B, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x92, 0x24, 0x92, 0x24, + 0x92, 0x00, 0x92, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x49, 0x24, 0x49, 0x24, 0x01, 0xA4, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x14, 0x49, 0x24, 0x49, 0x24, 0x01, 0x14, 0x01, 0x00, 0x00, 0x00, 0x00, + 0xA4, 0x48, 0x24, 0x49, 0x24, 0x01, 0x22, 0x01, 0x00, 0x00, 0x00, 0x00, 0x24, 0x45, 0x24, 0x29, + 0x24, 0x01, 0x24, 0x01, 0x00, 0x00, 0x00, 0x00, 0x24, 0x29, 0x24, 0x45, 0x24, 0x01, 0x24, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x24, 0x49, 0xA4, 0x48, 0x22, 0x01, 0x24, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x24, 0x49, 0x14, 0x49, 0x14, 0x01, 0x24, 0x01, 0x00, 0x00, 0x00, 0x00, 0x24, 0x49, 0x22, 0x49, + 0xA4, 0x00, 0x24, 0x01, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x7F, 0xFF, 0x7F, 0xFF, 0x01, 0xFF, 0x01, + 0x00, 0x00, 0x00, 0x00, 0xB6, 0x6D, 0xB6, 0x6D, 0xB6, 0x01, 0xB6, 0x01, 0x00, 0x00, 0x00, 0x00, + 0xB2, 0x6D, 0xB6, 0x6D, 0xB6, 0x01, 0xB6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x96, 0x6D, 0xB6, 0x6D, + 0xB6, 0x01, 0x96, 0x01, 0x00, 0x00, 0x00, 0x00, 0xB6, 0x6C, 0xB6, 0x6D, 0xB6, 0x01, 0xB2, 0x01, + 0x00, 0x00, 0x00, 0x00, 0xB6, 0x65, 0xB6, 0x2D, 0xB6, 0x01, 0xB6, 0x01, 0x00, 0x00, 0x00, 0x00, + 0xB6, 0x2D, 0xB6, 0x65, 0xB6, 0x01, 0xB6, 0x01, 0x00, 0x00, 0x00, 0x00, 0xB6, 0x6D, 0xB6, 0x6C, + 0xB2, 0x01, 0xB6, 0x01, 0x00, 0x00, 0x00, 0x00, 0xB6, 0x6D, 0x96, 0x6D, 0x96, 0x01, 0xB6, 0x01, + 0x00, 0x00, 0x00, 0x00, 0xB6, 0x6D, 0xB2, 0x6D, 0xB6, 0x00, 0xB6, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x02, 0x02, 0x06, 0xAA, 0x00, 0x6C, 0x76, 0x8A, 0x94, 0x00, 0x01, 0x06, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xDB, 0x06, 0x00, 0x00, 0x01, 0x06, 0x00, 0x00, 0x91, 0x01, 0x6E, 0x40, + 0x41, 0x8C, 0x39, 0x03, 0x01, 0x00, 0x00, 0x9A, 0x1D, 0x01, 0x8C, 0x61, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x0D, 0x10, 0x03, 0x90, 0xBB, 0xBB, 0x8E, 0x5A, 0x22, 0x18, + 0x64, 0x11, 0x64, 0x11, 0x8A, 0x39, 0x89, 0x39, 0x85, 0xE0, 0x0F, 0xE0, 0x66, 0x12, 0x64, 0x12, + 0x01, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x02, 0x02, 0x06, 0xAA, 0x00, 0x6C, 0x76, 0x8A, 0x94, 0x00, 0x01, 0x06, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xDB, 0x06, 0x00, 0x00, 0x01, 0x06, 0x00, 0x00, 0x91, 0x01, 0x6E, 0x40, + 0x41, 0x8C, 0x39, 0x03, 0x01, 0x00, 0x00, 0x9A, 0x1D, 0x01, 0x8C, 0x61, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x0C, 0x10, 0x03, 0x80, 0xAB, 0xAA, 0x80, 0x44, 0x22, 0x78, + 0x64, 0x11, 0x64, 0x11, 0x8A, 0x39, 0x89, 0x39, 0x85, 0xE0, 0x05, 0xE0, 0x66, 0x12, 0x64, 0x12, + 0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0xAA, 0x00, 0x6C, 0x76, 0x8A, 0x94, 0x00, 0x01, 0x06, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xDB, 0x06, 0x00, 0x00, 0x04, 0x0C, 0x00, 0x00, 0x38, 0x06, 0x6E, 0x20, + 0x41, 0x8C, 0x39, 0x03, 0x01, 0x00, 0x00, 0x84, 0xC4, 0x05, 0x8C, 0x61, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x10, 0xC4, 0x0C, 0x50, 0x03, 0x90, 0xBB, 0xBB, 0x80, 0x44, 0x22, 0x78, + 0x64, 0x11, 0x64, 0x11, 0x8A, 0x39, 0x89, 0x39, 0x85, 0xE0, 0x0F, 0xE0, 0x66, 0x12, 0x64, 0x12, + 0xD0, 0x04, 0x02, 0x00, 0x01, 0x02, 0x03, 0x04, 0xCC, 0xF5, 0x7A, 0xFD, 0xED, 0x20, 0xBF, 0x8F, + 0xCF, 0x03, 0x04, 0x02, 0x1E, 0x06, 0x00, 0x03, 0x6C, 0x76, 0x8A, 0x94, 0x00, 0x01, 0x06, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xDB, 0x06, 0x00, 0x00, 0x01, 0x46, 0x00, 0x00, 0x12, 0x1B, 0x00, 0x20, + 0x00, 0x6B, 0x39, 0x03, 0x41, 0x00, 0x02, 0x84, 0x00, 0x00, 0x6B, 0x61, 0x64, 0x78, 0x79, 0x2B, + 0xCF, 0x8A, 0x00, 0x80, 0x1C, 0x54, 0x11, 0x98, 0x00, 0x80, 0xBB, 0xBB, 0x00, 0x57, 0x22, 0x78, + 0x64, 0x11, 0x64, 0x11, 0x8A, 0x39, 0x89, 0x39, 0x85, 0xE0, 0x0F, 0xE0, 0x66, 0x12, 0x64, 0x12, + 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0xCC, 0xF5, 0x7A, 0xFD, 0xED, 0x20, 0xBF, 0x8F, + 0xCF, 0x03, 0x04, 0x02, 0x02, 0x06, 0x00, 0x00, 0x6C, 0x76, 0x8A, 0x94, 0x00, 0x01, 0x06, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xDB, 0x06, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x40, 0x1A, 0x00, 0x20, + 0x41, 0x00, 0x38, 0x03, 0x41, 0x00, 0x02, 0x84, 0x00, 0x00, 0x00, 0x60, 0x64, 0x78, 0x79, 0x2B, + 0xCF, 0x8A, 0x00, 0x80, 0x1C, 0x54, 0x10, 0x18, 0x03, 0x80, 0xBB, 0xBB, 0x80, 0x46, 0x22, 0x78, + 0x64, 0x11, 0x64, 0x11, 0x8A, 0x39, 0x89, 0x39, 0x85, 0xE0, 0x0F, 0xE0, 0x66, 0x12, 0x64, 0x12, + 0xD0, 0x04, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0xCC, 0xF5, 0x7A, 0xFD, 0xED, 0x20, 0xBF, 0x8F, + 0xCF, 0x03, 0x04, 0x02, 0x02, 0x06, 0x00, 0x00, 0x6C, 0x76, 0x8A, 0x94, 0x00, 0x01, 0x06, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xDB, 0x06, 0x00, 0x00, 0x01, 0x46, 0x00, 0x00, 0x12, 0x1B, 0x00, 0x20, + 0x00, 0x6B, 0x39, 0x03, 0x41, 0x00, 0x02, 0x84, 0x00, 0x00, 0x6B, 0x61, 0x64, 0x78, 0x79, 0x2B, + 0xCF, 0x8A, 0x00, 0x80, 0x1C, 0x54, 0x11, 0x98, 0x03, 0x80, 0xBB, 0xBB, 0x80, 0x46, 0x22, 0x78, + 0x64, 0x11, 0x64, 0x11, 0x8A, 0x39, 0x89, 0x39, 0x85, 0xE0, 0x0F, 0xE0, 0x66, 0x12, 0x64, 0x12, + 0x01, 0x00, 0x00, 0x00, 0x03, 0x03, 0x03, 0x03, 0xCC, 0xF5, 0x7A, 0xFD, 0xED, 0x20, 0xBF, 0x8F, + 0xCF, 0x03, 0x04, 0x02, 0x02, 0x06, 0x00, 0x00, 0x6C, 0x76, 0x8A, 0x94, 0x00, 0x01, 0x06, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xDB, 0x06, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x40, 0x1A, 0x00, 0x20, + 0x41, 0x00, 0x38, 0x03, 0x41, 0x00, 0x02, 0x84, 0x00, 0x00, 0x00, 0x60, 0x64, 0x78, 0x79, 0x2B, + 0xCF, 0x8A, 0x00, 0x80, 0x1C, 0x54, 0x10, 0x18, 0x03, 0x80, 0xBB, 0xBB, 0x80, 0x46, 0x22, 0x78, + 0x64, 0x11, 0x64, 0x11, 0x8A, 0x39, 0x89, 0x39, 0x85, 0xE0, 0x0F, 0xE0, 0x66, 0x12, 0x64, 0x12, + 0xD0, 0x04, 0x02, 0x00, 0x04, 0x04, 0x04, 0x04, 0xCC, 0xF5, 0x7A, 0xFD, 0xED, 0x20, 0xBF, 0x8F, + 0xCF, 0x03, 0x04, 0x02, 0x02, 0x06, 0x00, 0x00, 0x6C, 0x76, 0x8A, 0x94, 0x00, 0x01, 0x06, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xDB, 0x06, 0x00, 0x00, 0x01, 0x46, 0x00, 0x00, 0x12, 0x1B, 0x00, 0x20, + 0x00, 0x6B, 0x39, 0x03, 0x41, 0x00, 0x02, 0x84, 0x00, 0x00, 0x6B, 0x61, 0x64, 0x78, 0x79, 0x2B, + 0xCF, 0x8A, 0x00, 0x80, 0x1C, 0x54, 0x11, 0x98, 0x03, 0x80, 0xBB, 0xBB, 0x80, 0x46, 0x22, 0x78, + 0x64, 0x11, 0x64, 0x11, 0x8A, 0x39, 0x89, 0x39, 0x85, 0xE0, 0x0F, 0xE0, 0x66, 0x12, 0x64, 0x12, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCC, 0xF5, 0x7A, 0xFD, 0xED, 0x20, 0xBF, 0x8F, + 0xCF, 0x03, 0x04, 0x02, 0x02, 0x06, 0x00, 0x00, 0x6C, 0x76, 0x8A, 0x94, 0x00, 0x01, 0x06, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xDB, 0x06, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0xFF, 0x3B, 0x00, 0x20, + 0x41, 0x00, 0x38, 0x03, 0x41, 0x00, 0x02, 0x84, 0x00, 0x00, 0x00, 0x60, 0x64, 0x78, 0x79, 0x2B, + 0xCF, 0x8A, 0x00, 0x80, 0x1C, 0xC4, 0x10, 0x18, 0x03, 0x00, 0x00, 0x00, 0x00, 0xC6, 0x22, 0x78, + 0x64, 0x11, 0x64, 0x11, 0x80, 0x39, 0x80, 0x39, 0x05, 0x00, 0x0F, 0x00, 0x55, 0x10, 0x55, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x92, 0xCD, + 0x00, 0x00, 0xC1, 0x80, 0x10, 0x0F, 0x00, 0x02, 0x00, 0x00, 0x87, 0x37, 0x00, 0x00, 0xBB, 0xF1, + 0x10, 0x0F, 0x00, 0x04, 0x00, 0x00, 0x90, 0x41, 0x00, 0x00, 0x8B, 0x43, 0x10, 0x0E, 0x00, 0x07, + 0x00, 0x00, 0xBB, 0xF1, 0x00, 0x00, 0x91, 0x67, 0x10, 0x0C, 0x00, 0x09, 0x00, 0x00, 0x1D, 0xFB, + 0x00, 0x00, 0x70, 0x9E, 0x10, 0x0E, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0xC8, 0x06, 0x00, 0x00, + 0xBA, 0xF1, 0x59, 0x42, 0xBA, 0xF1, 0x59, 0x42, 0x45, 0x0E, 0xA6, 0x3D, 0x11, 0x22, 0x33, 0x44, + 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x69, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x22, 0xC0, 0x22, 0x31, 0x30, 0x2F, 0x2E, + 0x2D, 0x2C, 0x2B, 0x2A, 0x29, 0x28, 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21, 0x20, 0x1F, 0x1E, + 0x1D, 0x1C, 0x1B, 0x1A, 0x19, 0x18, 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x0F, 0x0E, + 0x0D, 0x0C, 0x0B, 0x0A, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x4A, 0x49, 0x48, 0x47, 0x46, 0x45, 0x44, 0x43, 0x42, 0x41, 0x40, 0x3F, + 0x3E, 0x3D, 0x3C, 0x3B, 0x3A, 0x39, 0x38, 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x30, 0x2F, + 0x2E, 0x2D, 0x2C, 0x2B, 0x2A, 0x29, 0x28, 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21, 0x20, 0x1F, + 0x1E, 0x1D, 0x1C, 0x1B, 0x1A, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0xE0, 0xC0, + 0xA0, 0x80, 0x60, 0x40, 0x20, 0x00, 0xE0, 0xC0, 0xA0, 0x80, 0x60, 0x40, 0x20, 0x00, 0xE0, 0xC0, + 0xA0, 0x80, 0x60, 0x40, 0x20, 0x00, 0xE0, 0xC0, 0xA0, 0x80, 0x60, 0x40, 0x20, 0x00, 0xE0, 0xC0, + 0xA0, 0x80, 0x60, 0x40, 0x20, 0x00, 0xE0, 0xC0, 0xA0, 0x80, 0x60, 0x40, 0x20, 0x00, 0x00, 0x00, + 0x76, 0xDB, 0xB6, 0x2D, 0x24, 0x49, 0x92, 0x1B, 0xDB, 0xB6, 0x49, 0x12, 0x92, 0x94, 0x24, 0x09, + 0x09, 0x00, 0x00, 0x00, 0x20, 0x00, 0xE0, 0xC0, 0xA0, 0x80, 0x60, 0x40, 0x20, 0x00, 0xE0, 0xC0, + 0xA0, 0x80, 0x60, 0x40, 0x20, 0x00, 0xE0, 0xC0, 0xA0, 0x80, 0x60, 0x40, 0x20, 0x00, 0xE0, 0xC0, + 0xA0, 0x80, 0x60, 0x40, 0x20, 0x00, 0xE0, 0xC0, 0xA0, 0x80, 0x60, 0x40, 0x20, 0x00, 0xE0, 0xC0, + 0xA0, 0x80, 0x60, 0x40, 0x20, 0x00, 0x00, 0x00, 0x76, 0xDB, 0xB6, 0x2D, 0x24, 0x49, 0x92, 0x1B, + 0xDB, 0xB6, 0x49, 0x12, 0x92, 0x94, 0x24, 0x09, 0x09, 0x00, 0x00, 0x00, 0x20, 0x21, 0xE0, 0xE1, + 0xA0, 0xA1, 0x60, 0x61, 0x20, 0x21, 0xE0, 0xE1, 0xA0, 0xA1, 0x60, 0x61, 0x20, 0x21, 0xE0, 0xE1, + 0xA0, 0xA1, 0x60, 0x61, 0x20, 0x21, 0xE0, 0xE1, 0xA0, 0xA1, 0x60, 0x61, 0x20, 0x21, 0xE0, 0xE1, + 0xA0, 0xA1, 0x60, 0x61, 0x20, 0x21, 0xE0, 0xE1, 0xA0, 0xA1, 0x60, 0x61, 0x20, 0x21, 0x00, 0x00, + 0x76, 0xDB, 0xB6, 0x2D, 0x24, 0x49, 0x92, 0x1B, 0xDB, 0xB6, 0x49, 0x12, 0x92, 0x94, 0x24, 0x09, + 0x09, 0x00, 0x00, 0x00, 0x01, 0x00, 0xC1, 0xC0, 0x81, 0x80, 0x41, 0x40, 0x01, 0x00, 0xC1, 0xC0, + 0x81, 0x80, 0x41, 0x40, 0x01, 0x00, 0xC1, 0xC0, 0x81, 0x80, 0x41, 0x40, 0x01, 0x00, 0xC1, 0xC0, + 0x81, 0x80, 0x41, 0x40, 0x01, 0x00, 0xC1, 0xC0, 0x81, 0x80, 0x41, 0x40, 0x01, 0x00, 0xC1, 0xC0, + 0x81, 0x80, 0x41, 0x40, 0x01, 0x00, 0x00, 0x00, 0x76, 0xDB, 0xB6, 0x2D, 0x24, 0x49, 0x92, 0x1B, + 0xDB, 0xB6, 0x49, 0x12, 0x92, 0x94, 0x24, 0x09, 0x09, 0x00, 0x00, 0x00, 0x21, 0x20, 0xE1, 0xE0, + 0xA1, 0xA0, 0x61, 0x60, 0x21, 0x20, 0xE1, 0xE0, 0xA1, 0xA0, 0x61, 0x60, 0x21, 0x20, 0xE1, 0xE0, + 0xA1, 0xA0, 0x61, 0x60, 0x21, 0x20, 0xE1, 0xE0, 0xA1, 0xA0, 0x61, 0x60, 0x21, 0x20, 0xE1, 0xE0, + 0xA1, 0xA0, 0x61, 0x60, 0x21, 0x20, 0xE1, 0xE0, 0xA1, 0xA0, 0x61, 0x60, 0x21, 0x20, 0x00, 0x00, + 0x76, 0xDB, 0xB6, 0x2D, 0x24, 0x49, 0x92, 0x1B, 0xDB, 0xB6, 0x49, 0x12, 0x92, 0x94, 0x24, 0x09, + 0x09, 0x00, 0x00, 0x00, 0x63, 0x43, 0x23, 0x03, 0xE2, 0xC2, 0xA2, 0x82, 0x62, 0x42, 0x22, 0x02, + 0xE2, 0xC2, 0xA2, 0x82, 0x62, 0x42, 0x22, 0x02, 0xE2, 0xC2, 0xA2, 0x82, 0x62, 0x42, 0x22, 0x02, + 0xE2, 0xC2, 0xA2, 0x82, 0x62, 0x42, 0x22, 0x02, 0xE2, 0xC2, 0xA2, 0x82, 0x62, 0x42, 0x22, 0x02, + 0xE2, 0xC2, 0xA2, 0x82, 0x62, 0x42, 0x00, 0x00, 0x00, 0xD0, 0xB6, 0x2D, 0x2D, 0x49, 0x92, 0x24, + 0xDB, 0xB6, 0x6D, 0x12, 0x92, 0x24, 0x25, 0x09, 0x49, 0x02, 0x00, 0x00, 0x2C, 0x0C, 0xEC, 0xCC, + 0xAC, 0x8C, 0x6C, 0x4C, 0x2C, 0x0C, 0xEC, 0xCC, 0xAC, 0x8C, 0x6C, 0x4C, 0x2C, 0x0C, 0xEC, 0xCC, + 0xAC, 0x8C, 0x6C, 0x4C, 0x2C, 0x0C, 0xEC, 0xCC, 0xAC, 0x8C, 0x6C, 0x4C, 0x2C, 0x0C, 0xEC, 0xCC, + 0xAC, 0x8C, 0x6C, 0x4C, 0x2C, 0x0C, 0xEB, 0xCB, 0xAB, 0x8B, 0x6B, 0x4B, 0x2B, 0x0B, 0x00, 0x00, + 0x2D, 0x49, 0x92, 0x24, 0xDB, 0xB6, 0x6D, 0x12, 0x92, 0x24, 0x25, 0x09, 0x49, 0x02, 0x00, 0x00, + 0x40, 0xDB, 0xB6, 0x2D, 0xA4, 0x84, 0x64, 0x44, 0x24, 0x04, 0xE3, 0xC3, 0xA3, 0x83, 0x63, 0x43, + 0x23, 0x03, 0xE3, 0xC3, 0xA3, 0x83, 0x63, 0x43, 0x23, 0x03, 0xE3, 0xC3, 0xA3, 0x83, 0x63, 0x43, + 0x23, 0x03, 0xE3, 0xC3, 0xA3, 0x83, 0x63, 0x43, 0x23, 0x03, 0xE3, 0xC3, 0xA3, 0x83, 0x63, 0x43, + 0x23, 0x03, 0xE3, 0xC3, 0xA3, 0x83, 0x00, 0x00, 0x00, 0x00, 0xB4, 0x2D, 0x6D, 0x4B, 0x92, 0x24, + 0xE4, 0xB6, 0x6D, 0x1B, 0x92, 0x24, 0x49, 0x09, 0x49, 0x92, 0x00, 0x00, 0xEB, 0xCB, 0xAB, 0x8B, + 0x6B, 0x4B, 0x2B, 0x0B, 0xEB, 0xCB, 0xAB, 0x8B, 0x6B, 0x4B, 0x2B, 0x0B, 0xEB, 0xCB, 0xAB, 0x8B, + 0x6B, 0x4B, 0x2B, 0x0B, 0xEB, 0xCB, 0xAB, 0x8B, 0x6B, 0x4B, 0x2B, 0x0B, 0xEB, 0xCB, 0xAB, 0x8B, + 0x6B, 0x4B, 0x2B, 0x0B, 0xEA, 0xCA, 0xAA, 0x8A, 0x6A, 0x4A, 0x2A, 0x0A, 0xEA, 0xCA, 0x00, 0x00, + 0x24, 0x49, 0x92, 0x1B, 0xDB, 0xB6, 0x49, 0x12, 0x92, 0x94, 0x24, 0x09, 0x09, 0x00, 0x00, 0x00, + 0x6D, 0xDB, 0xB6, 0x24, 0xE5, 0xC5, 0xA5, 0x85, 0x65, 0x45, 0x25, 0x05, 0xE4, 0xC4, 0xA4, 0x84, + 0x64, 0x44, 0x24, 0x04, 0xE4, 0xC4, 0xA4, 0x84, 0x64, 0x44, 0x24, 0x04, 0xE4, 0xC4, 0xA4, 0x84, + 0x64, 0x44, 0x24, 0x04, 0xE4, 0xC4, 0xA4, 0x84, 0x64, 0x44, 0x24, 0x04, 0xE4, 0xC4, 0xA4, 0x84, + 0x64, 0x44, 0x24, 0x04, 0xE4, 0xC4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2D, 0x6D, 0xDB, 0x92, 0x24, + 0x24, 0xB9, 0x6D, 0x1B, 0x9B, 0x24, 0x49, 0x12, 0x49, 0x92, 0x24, 0x00, 0xAA, 0x8A, 0x6A, 0x4A, + 0x2A, 0x0A, 0xEA, 0xCA, 0xAA, 0x8A, 0x6A, 0x4A, 0x2A, 0x0A, 0xEA, 0xCA, 0xAA, 0x8A, 0x6A, 0x4A, + 0x2A, 0x0A, 0xEA, 0xCA, 0xAA, 0x8A, 0x6A, 0x4A, 0x2A, 0x0A, 0xEA, 0xCA, 0xAA, 0x8A, 0x6A, 0x4A, + 0x2A, 0x0A, 0xE9, 0xC9, 0xA9, 0x89, 0x69, 0x49, 0x29, 0x09, 0xE9, 0xC9, 0xA9, 0x89, 0x00, 0x00, + 0x24, 0x49, 0x6E, 0x1B, 0xDB, 0x26, 0x49, 0x12, 0x52, 0x92, 0x24, 0x09, 0x00, 0x00, 0x00, 0x2D, + 0x6D, 0xDB, 0x92, 0x24, 0x26, 0x06, 0xE6, 0xC6, 0xA6, 0x86, 0x66, 0x46, 0x26, 0x06, 0xE5, 0xC5, + 0xA5, 0x85, 0x65, 0x45, 0x25, 0x05, 0xE5, 0xC5, 0xA5, 0x85, 0x65, 0x45, 0x25, 0x05, 0xE5, 0xC5, + 0xA5, 0x85, 0x65, 0x45, 0x25, 0x05, 0xE5, 0xC5, 0xA5, 0x85, 0x65, 0x45, 0x25, 0x05, 0xE5, 0xC5, + 0xA5, 0x85, 0x65, 0x45, 0x25, 0x05, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x6D, 0xDB, 0xB6, 0x24, + 0x24, 0x49, 0x6E, 0x1B, 0xDB, 0x26, 0x49, 0x12, 0x52, 0x92, 0x24, 0x09, 0x69, 0x49, 0x29, 0x09, + 0xE9, 0xC9, 0xA9, 0x89, 0x69, 0x49, 0x29, 0x09, 0xE9, 0xC9, 0xA9, 0x89, 0x69, 0x49, 0x29, 0x09, + 0xE9, 0xC9, 0xA9, 0x89, 0x69, 0x49, 0x29, 0x09, 0xE9, 0xC9, 0xA9, 0x89, 0x69, 0x49, 0x29, 0x09, + 0xE8, 0xC8, 0xA8, 0x88, 0x68, 0x48, 0x28, 0x08, 0xE8, 0xC8, 0xA8, 0x88, 0x68, 0x48, 0x00, 0x00, + 0x24, 0xB9, 0x6D, 0x1B, 0x9B, 0x24, 0x49, 0x12, 0x49, 0x92, 0x24, 0x00, 0x00, 0x00, 0xB4, 0x2D, + 0x6D, 0x4B, 0x92, 0x24, 0x67, 0x47, 0x27, 0x07, 0xE7, 0xC7, 0xA7, 0x87, 0x67, 0x47, 0x27, 0x07, + 0xE6, 0xC6, 0xA6, 0x86, 0x66, 0x46, 0x26, 0x06, 0xE6, 0xC6, 0xA6, 0x86, 0x66, 0x46, 0x26, 0x06, + 0xE6, 0xC6, 0xA6, 0x86, 0x66, 0x46, 0x26, 0x06, 0xE6, 0xC6, 0xA6, 0x86, 0x66, 0x46, 0x26, 0x06, + 0xE6, 0xC6, 0xA6, 0x86, 0x66, 0x46, 0x00, 0x00, 0x49, 0x02, 0x00, 0x00, 0x40, 0xDB, 0xB6, 0x2D, + 0x24, 0x49, 0x92, 0x1B, 0xDB, 0xB6, 0x49, 0x12, 0x92, 0x94, 0x24, 0x09, 0x28, 0x08, 0xE8, 0xC8, + 0xA8, 0x88, 0x68, 0x48, 0x28, 0x08, 0xE8, 0xC8, 0xA8, 0x88, 0x68, 0x48, 0x28, 0x08, 0xE8, 0xC8, + 0xA8, 0x88, 0x68, 0x48, 0x28, 0x08, 0xE8, 0xC8, 0xA8, 0x88, 0x68, 0x48, 0x28, 0x08, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, + 0xE4, 0xB6, 0x6D, 0x1B, 0x92, 0x24, 0x49, 0x09, 0x49, 0x92, 0x00, 0x00, 0x00, 0xF0, 0xFF, 0x3F, + 0xFF, 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xE7, 0xC7, 0xA7, 0x87, 0x67, 0x47, 0x27, 0x07, 0xE7, 0xC7, 0xA7, 0x87, 0x67, 0x47, + 0x27, 0x07, 0xE7, 0xC7, 0xA7, 0x87, 0x67, 0x47, 0x27, 0x07, 0xE7, 0xC7, 0xA7, 0x87, 0x67, 0x47, + 0x27, 0x07, 0xE7, 0xC7, 0xA7, 0x87, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x3F, 0xFF, 0xDF, 0xB6, 0x2D, + 0x2D, 0x49, 0x92, 0x24, 0xDB, 0xB6, 0x6D, 0x12, 0x92, 0x24, 0x25, 0x09, 0x63, 0x62, 0x61, 0x60, + 0x5F, 0x5E, 0x5D, 0x5C, 0x5B, 0x5A, 0x59, 0x58, 0x57, 0x56, 0x55, 0x54, 0x53, 0x52, 0x51, 0x50, + 0x4F, 0x4E, 0x4D, 0x4C, 0x4B, 0x4A, 0x49, 0x48, 0x47, 0x46, 0x45, 0x44, 0x43, 0x42, 0x41, 0x40, + 0x3F, 0x3E, 0x3D, 0x3C, 0x3B, 0x3A, 0x39, 0x38, 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x31, 0x30, 0x2F, 0x2E, 0x2D, 0x2C, 0x2B, 0x2A, 0x29, 0x28, 0x27, 0x26, + 0x25, 0x24, 0x23, 0x22, 0x21, 0x20, 0x1F, 0x1E, 0x1D, 0x1C, 0x1B, 0x1A, 0x19, 0x18, 0x17, 0x16, + 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x0F, 0x0E, 0x0D, 0x0C, 0x0B, 0x0A, 0x09, 0x08, 0x07, 0x06, + 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32, 0x05, 0x10, 0x3E, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x9D, 0x12, 0x00, 0x00, 0xC0, 0x12, 0x00, 0x00, 0xE3, 0x12, 0x00, 0x00, 0x06, 0x13, 0x00, 0x00, + 0x29, 0x13, 0x00, 0x00, 0x4C, 0x13, 0x00, 0x00, 0x6F, 0x13, 0x00, 0x00, 0x92, 0x13, 0x00, 0x00, + 0xB5, 0x13, 0x00, 0x00, 0xD8, 0x13, 0x00, 0x00, 0xFB, 0x13, 0x00, 0x00, 0x1E, 0x14, 0x00, 0x00, + 0x41, 0x14, 0x00, 0x00, 0x64, 0x14, 0x00, 0x00, 0x87, 0x14, 0x00, 0x00, 0xAA, 0x14, 0x00, 0x00, + 0xCD, 0x14, 0x00, 0x00, 0xF0, 0x14, 0x00, 0x00, 0x13, 0x15, 0x00, 0x00, 0x36, 0x15, 0x00, 0x00, + 0x59, 0x15, 0x00, 0x00, 0x20, 0x03, 0x00, 0x00, 0x14, 0x39, 0x2E, 0x01, 0x42, 0x39, 0x10, 0x05, + 0xC6, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0xDC, 0x55, 0x20, 0x05, 0x02, 0x02, 0x52, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xB0, 0x00, 0x0B, 0x00, 0x00, 0x10, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x7C, 0x15, 0x16, 0x17, + 0x4E, 0x17, 0x48, 0x18, 0xC1, 0x1A, 0x6C, 0x18, 0xEC, 0x19, 0x31, 0x1A, 0x51, 0x1A, 0x7E, 0x17, + 0x07, 0xB8, 0xC3, 0x07, 0x00, 0x80, 0x00, 0x00, 0x20, 0x83, 0x00, 0x00, 0x00, 0x80, 0x32, 0x80, + 0x64, 0x80, 0x96, 0x80, 0x2D, 0xB4, 0x04, 0x0F, 0x11, 0x0C, 0x0F, 0x0F, 0x10, 0x00, 0x0F, 0x13, + 0xA5, 0xBB, 0x83, 0x1E, 0x18, 0xC8, 0x0F, 0x00, 0x15, 0x10, 0x15, 0x10, 0x10, 0x43, 0x10, 0x43, + 0x20, 0x03, 0x00, 0x00, 0x14, 0x39, 0x32, 0x0A, 0x4D, 0x20, 0x38, 0x03, 0xC4, 0x03, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0C, 0x00, 0x00, 0x00, 0xDC, 0x55, 0x55, 0x20, 0x05, 0x52, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xF8, 0xB0, 0xB9, 0x00, 0x0B, 0xB0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x7C, 0x15, 0x16, 0x17, 0x4E, 0x17, 0x48, 0x18, + 0xC1, 0x1A, 0x6C, 0x18, 0xEC, 0x19, 0x31, 0x1A, 0x51, 0x1A, 0x7E, 0x17, 0x07, 0xB8, 0xC3, 0x07, + 0x00, 0x80, 0x00, 0x00, 0x20, 0x83, 0x00, 0x00, 0x00, 0x80, 0x32, 0x80, 0x64, 0x80, 0x96, 0x80, + 0x2D, 0xB4, 0x04, 0x0F, 0x11, 0x0C, 0x0F, 0x0F, 0x10, 0x00, 0x0F, 0x13, 0xA5, 0xBB, 0x83, 0x1E, + 0x18, 0xC8, 0x0F, 0x00, 0x15, 0x10, 0x15, 0x10, 0x10, 0x43, 0x10, 0x43, 0x20, 0x03, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x7C, 0x15, 0x16, 0x17, 0x4E, 0x17, 0x48, 0x18, 0xC1, 0x1A, 0x6C, 0x18, + 0xEC, 0x19, 0x31, 0x1A, 0x51, 0x1A, 0x7E, 0x17, 0x07, 0xB8, 0xC3, 0x07, 0x00, 0x80, 0x00, 0x00, + 0x20, 0x83, 0x00, 0x00, 0x00, 0x80, 0x32, 0x80, 0x64, 0x80, 0x96, 0x80, 0x2D, 0xB4, 0x04, 0x0F, + 0x11, 0x0C, 0x0F, 0x0F, 0x10, 0x00, 0x0F, 0x13, 0xA5, 0xBB, 0x83, 0x1E, 0x18, 0xC8, 0x0F, 0x00, + 0x15, 0x10, 0x15, 0x10, 0x10, 0x43, 0x10, 0x43, 0x20, 0x03, 0x00, 0x00, 0x14, 0x39, 0x2E, 0x01, + 0x42, 0x39, 0x10, 0x05, 0xC6, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0xDC, 0x55, 0x27, 0x75, + 0x72, 0x72, 0x52, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xB0, 0x66, 0x6B, + 0x66, 0x66, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x7C, 0x15, 0x16, 0x17, 0x4E, 0x17, 0x48, 0x18, 0xC1, 0x1A, 0x6C, 0x18, 0xEC, 0x19, 0x31, 0x1A, + 0x51, 0x1A, 0x7E, 0x17, 0x07, 0xB8, 0xC3, 0x07, 0x00, 0x80, 0x00, 0x00, 0x20, 0x83, 0x00, 0x00, + 0x00, 0x80, 0x32, 0x80, 0x64, 0x80, 0x96, 0x80, 0x2D, 0xB4, 0x04, 0x0F, 0x11, 0x0C, 0x0F, 0x0F, + 0x10, 0x00, 0x0F, 0x13, 0xA5, 0xBB, 0x83, 0x1E, 0x18, 0xC8, 0x0F, 0x00, 0x15, 0x10, 0x15, 0x10, + 0x10, 0x43, 0x10, 0x43, 0x20, 0x03, 0x00, 0x00, 0x14, 0x39, 0x32, 0x0A, 0x4D, 0x20, 0x38, 0x03, + 0xC4, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0xDC, 0x55, 0x55, 0x27, 0x75, 0x52, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xB0, 0xB9, 0x66, 0x6B, 0xB6, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x7C, 0x15, 0x16, 0x17, + 0x4E, 0x17, 0x48, 0x18, 0xC1, 0x1A, 0x6C, 0x18, 0xEC, 0x19, 0x31, 0x1A, 0x51, 0x1A, 0x7E, 0x17, + 0x07, 0xB8, 0xC3, 0x07, 0x00, 0x80, 0x00, 0x00, 0x20, 0x83, 0x00, 0x00, 0x00, 0x80, 0x32, 0x80, + 0x64, 0x80, 0x96, 0x80, 0x2D, 0xB4, 0x04, 0x0F, 0x11, 0x0C, 0x0F, 0x0F, 0x10, 0x00, 0x0F, 0x13, + 0xA5, 0xBB, 0x83, 0x1E, 0x18, 0xC8, 0x0F, 0x00, 0x15, 0x10, 0x15, 0x10, 0x10, 0x43, 0x10, 0x43, + 0x20, 0x03, 0x00, 0x00, 0x14, 0x39, 0x2E, 0x0A, 0x65, 0x65, 0x5D, 0x18, 0x19, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0B, 0x00, 0x00, 0x00, 0xDC, 0x55, 0x55, 0x20, 0x20, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xF8, 0xB0, 0xB9, 0x11, 0x11, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x7C, 0x15, 0x16, 0x17, 0x4E, 0x17, 0x48, 0x18, + 0xC1, 0x1A, 0x6C, 0x18, 0xEC, 0x19, 0x31, 0x1A, 0x51, 0x1A, 0x7E, 0x17, 0x07, 0xB8, 0xC3, 0x07, + 0x00, 0x80, 0x00, 0x00, 0x20, 0x83, 0x00, 0x00, 0x00, 0x80, 0x32, 0x80, 0x64, 0x80, 0x96, 0x80, + 0x2D, 0xB4, 0x04, 0x0F, 0x11, 0x0C, 0x0F, 0x0F, 0x10, 0x00, 0x0F, 0x13, 0xA5, 0xBB, 0x83, 0x1E, + 0x18, 0xC8, 0x0F, 0x00, 0x15, 0x10, 0x15, 0x10, 0x10, 0x43, 0x10, 0x43, 0x20, 0x03, 0x00, 0x00, + 0x14, 0x39, 0x2E, 0x0A, 0x65, 0x65, 0x5D, 0x18, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, + 0xDC, 0x55, 0x55, 0x27, 0x27, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xF8, 0xB0, 0xB9, 0x33, 0x33, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x7C, 0x15, 0x16, 0x17, 0x4E, 0x17, 0x48, 0x18, 0xC1, 0x1A, 0x6C, 0x18, + 0xEC, 0x19, 0x31, 0x1A, 0x51, 0x1A, 0x7E, 0x17, 0x07, 0xB8, 0xC3, 0x07, 0x00, 0x80, 0x00, 0x00, + 0x20, 0x83, 0x00, 0x00, 0x00, 0x80, 0x32, 0x80, 0x64, 0x80, 0x96, 0x80, 0x2D, 0xB4, 0x04, 0x0F, + 0x11, 0x0C, 0x0F, 0x0F, 0x10, 0x00, 0x0F, 0x13, 0xA5, 0xBB, 0x83, 0x1E, 0x18, 0xC8, 0x0F, 0x00, + 0x15, 0x10, 0x15, 0x10, 0x10, 0x43, 0x10, 0x43, 0x20, 0x03, 0x00, 0x00, 0x14, 0x39, 0x32, 0x15, + 0x56, 0x73, 0x61, 0x0E, 0xD9, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0xDC, 0x55, 0x20, 0x05, + 0x52, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xB0, 0x11, 0x1B, + 0xB1, 0xB1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x7C, 0x15, 0x16, 0x17, 0x4E, 0x17, 0x48, 0x18, 0xC1, 0x1A, 0x6C, 0x18, 0xEC, 0x19, 0x31, 0x1A, + 0x51, 0x1A, 0x7E, 0x17, 0x07, 0xB8, 0xC3, 0x07, 0x00, 0x80, 0x00, 0x00, 0x20, 0x83, 0x00, 0x00, + 0x00, 0x80, 0x32, 0x80, 0x64, 0x80, 0x96, 0x80, 0x2D, 0xB4, 0x04, 0x0F, 0x11, 0x0C, 0x0F, 0x0F, + 0x10, 0x00, 0x0F, 0x13, 0xA5, 0xBB, 0x83, 0x1E, 0x18, 0xC8, 0x0F, 0x00, 0x15, 0x10, 0x15, 0x10, + 0x10, 0x43, 0x10, 0x43, 0x20, 0x03, 0x00, 0x00, 0x14, 0x39, 0x32, 0x15, 0x56, 0x73, 0x61, 0x0E, + 0xD9, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0xDC, 0x55, 0x27, 0x75, 0x52, 0x55, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xB0, 0x33, 0x3B, 0xB3, 0xB3, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x7C, 0x15, 0x16, 0x17, + 0x4E, 0x17, 0x48, 0x18, 0xC1, 0x1A, 0x6C, 0x18, 0xEC, 0x19, 0x31, 0x1A, 0x51, 0x1A, 0x7E, 0x17, + 0x07, 0xB8, 0xC3, 0x07, 0x00, 0x80, 0x00, 0x00, 0x20, 0x83, 0x00, 0x00, 0x00, 0x80, 0x32, 0x80, + 0x64, 0x80, 0x96, 0x80, 0x2D, 0xB4, 0x04, 0x0F, 0x11, 0x0C, 0x0F, 0x0F, 0x10, 0x00, 0x0F, 0x13, + 0xA5, 0xBB, 0x83, 0x1E, 0x18, 0xC8, 0x0F, 0x00, 0x15, 0x10, 0x15, 0x10, 0x10, 0x43, 0x10, 0x43, + 0x20, 0x03, 0x00, 0x00, 0x81, 0x30, 0x10, 0x05, 0xC6, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0x15, 0x16, 0x17, 0x4E, 0x17, 0x48, 0x18, + 0xC1, 0x1A, 0x6C, 0x18, 0xEC, 0x19, 0x31, 0x1A, 0x51, 0x1A, 0x7E, 0x17, 0x07, 0xB8, 0xC3, 0x07, + 0x00, 0x80, 0x00, 0x00, 0x20, 0x83, 0x00, 0x00, 0x00, 0x80, 0x32, 0x80, 0x64, 0x80, 0x96, 0x80, + 0x2D, 0xB4, 0x04, 0x0F, 0x11, 0x0C, 0x0F, 0x0F, 0x10, 0x00, 0x0F, 0x13, 0xA5, 0xBB, 0x83, 0x1E, + 0x18, 0xC8, 0x0F, 0x00, 0x15, 0x10, 0x15, 0x10, 0x10, 0x43, 0x10, 0x43, 0x20, 0x03, 0x00, 0x00, + 0x14, 0x39, 0x32, 0x05, 0x46, 0x73, 0x20, 0x0E, 0xC0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, + 0xDC, 0x55, 0x20, 0x05, 0x52, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xF8, 0xB0, 0x00, 0x0B, 0xB0, 0xB1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x7C, 0x15, 0x16, 0x17, 0x4E, 0x17, 0x48, 0x18, 0xC1, 0x1A, 0x6C, 0x18, + 0xEC, 0x19, 0x31, 0x1A, 0x51, 0x1A, 0x7E, 0x17, 0x07, 0xB8, 0xC3, 0x07, 0x00, 0x80, 0x00, 0x00, + 0x20, 0x83, 0x00, 0x00, 0x00, 0x80, 0x32, 0x80, 0x64, 0x80, 0x96, 0x80, 0x2D, 0xB4, 0x04, 0x0F, + 0x11, 0x0C, 0x0F, 0x0F, 0x10, 0x00, 0x0F, 0x13, 0xA5, 0xBB, 0x83, 0x1E, 0x18, 0xC8, 0x0F, 0x00, + 0x15, 0x10, 0x15, 0x10, 0x10, 0x43, 0x10, 0x43, 0x20, 0x03, 0x00, 0x00, 0x81, 0x30, 0x10, 0x05, + 0xC6, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, + 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x7C, 0x15, 0x16, 0x17, 0x4E, 0x17, 0x48, 0x18, 0xC1, 0x1A, 0x6C, 0x18, 0xEC, 0x19, 0x31, 0x1A, + 0x51, 0x1A, 0x7E, 0x17, 0x07, 0xB8, 0xC3, 0x07, 0x00, 0x80, 0x00, 0x00, 0x20, 0x83, 0x00, 0x00, + 0x00, 0x80, 0x32, 0x80, 0x64, 0x80, 0x96, 0x80, 0x2D, 0xB4, 0x04, 0x0F, 0x11, 0x0C, 0x0F, 0x0F, + 0x10, 0x00, 0x0F, 0x13, 0xA5, 0xBB, 0x83, 0x1E, 0x18, 0xC8, 0x0F, 0x00, 0x15, 0x10, 0x15, 0x10, + 0x10, 0x43, 0x10, 0x43, 0x20, 0x03, 0x00, 0x00, 0x14, 0x39, 0x32, 0x05, 0x46, 0x73, 0x20, 0x0E, + 0xC0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0xDC, 0x55, 0x27, 0x75, 0x52, 0x55, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xB0, 0x66, 0x6B, 0xB6, 0xB3, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x7C, 0x15, 0x16, 0x17, + 0x4E, 0x17, 0x48, 0x18, 0xC1, 0x1A, 0x6C, 0x18, 0xEC, 0x19, 0x31, 0x1A, 0x51, 0x1A, 0x7E, 0x17, + 0x07, 0xB8, 0xC3, 0x07, 0x00, 0x80, 0x00, 0x00, 0x20, 0x83, 0x00, 0x00, 0x00, 0x80, 0x32, 0x80, + 0x64, 0x80, 0x96, 0x80, 0x2D, 0xB4, 0x04, 0x0F, 0x11, 0x0C, 0x0F, 0x0F, 0x10, 0x00, 0x0F, 0x13, + 0xA5, 0xBB, 0x83, 0x1E, 0x18, 0xC8, 0x0F, 0x00, 0x15, 0x10, 0x15, 0x10, 0x10, 0x43, 0x10, 0x43, + 0x20, 0x03, 0x00, 0x00, 0x14, 0x39, 0x2E, 0x0A, 0x65, 0x65, 0x5D, 0x18, 0x19, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0B, 0x00, 0x00, 0x00, 0xDC, 0x55, 0x55, 0x20, 0x20, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xF8, 0xB0, 0xB9, 0x11, 0x11, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x7C, 0x15, 0x16, 0x17, 0x4E, 0x17, 0x48, 0x18, + 0xC1, 0x1A, 0x6C, 0x18, 0xEC, 0x19, 0x31, 0x1A, 0x51, 0x1A, 0x7E, 0x17, 0x07, 0xB8, 0xC3, 0x07, + 0x00, 0x80, 0x00, 0x00, 0x20, 0x83, 0x00, 0x00, 0x00, 0x80, 0x32, 0x80, 0x64, 0x80, 0x96, 0x80, + 0x2D, 0xB4, 0x04, 0x0F, 0x11, 0x0C, 0x0F, 0x0F, 0x10, 0x00, 0x0F, 0x13, 0xA5, 0xBB, 0x83, 0x1E, + 0x18, 0xC8, 0x0F, 0x00, 0x15, 0x10, 0x15, 0x10, 0x10, 0x43, 0x10, 0x43, 0x20, 0x03, 0x00, 0x00, + 0x14, 0x39, 0x2E, 0x23, 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0xDC, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xF8, 0xB0, 0xB0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x00, 0x00, 0x7C, 0x15, 0x16, 0x17, 0x4E, 0x17, 0x48, 0x18, 0xC1, 0x1A, 0x6C, 0x18, + 0xEC, 0x19, 0x31, 0x1A, 0x51, 0x1A, 0x7E, 0x17, 0x07, 0xB8, 0xC3, 0x07, 0x00, 0x80, 0x00, 0x00, + 0x20, 0x83, 0x00, 0x00, 0x00, 0x80, 0x32, 0x80, 0x64, 0x80, 0x96, 0x80, 0x2D, 0xB4, 0x04, 0x0F, + 0x11, 0x0C, 0x0F, 0x0F, 0x10, 0x00, 0x0F, 0x13, 0xA5, 0xBB, 0x83, 0x1E, 0x18, 0xC8, 0x0F, 0x00, + 0x15, 0x10, 0x15, 0x10, 0x10, 0x43, 0x10, 0x43, 0x20, 0x03, 0x00, 0x00, 0x09, 0x45, 0x8E, 0x23, + 0xE3, 0x38, 0x8E, 0x23, 0xE3, 0x38, 0x8E, 0x23, 0xE3, 0x38, 0x8E, 0x23, 0xE3, 0xB8, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0xB4, 0x6D, 0x66, 0x66, + 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x06, 0x00, 0x00, 0x00, 0x00, 0x82, 0x0F, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x3F, 0x00, + 0x7C, 0x15, 0x16, 0x17, 0x4E, 0x17, 0x48, 0x18, 0xC1, 0x1A, 0x6C, 0x18, 0xEC, 0x19, 0x31, 0x1A, + 0x51, 0x1A, 0x7E, 0x17, 0x07, 0xB8, 0xC3, 0x07, 0x00, 0x80, 0x00, 0x00, 0x20, 0x83, 0x00, 0x00, + 0x00, 0x80, 0x32, 0x80, 0x64, 0x80, 0x96, 0x80, 0x2D, 0xB4, 0x04, 0x0F, 0x11, 0x0C, 0x0F, 0x0F, + 0x10, 0x00, 0x0F, 0x13, 0xA5, 0xBB, 0x83, 0x1E, 0x18, 0xC8, 0x0F, 0x00, 0x15, 0x10, 0x15, 0x10, + 0x10, 0x43, 0x10, 0x43, 0x20, 0x03, 0x00, 0x00, 0x14, 0x39, 0x2E, 0x0A, 0x65, 0x65, 0x5D, 0x18, + 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0xDC, 0x55, 0x55, 0x27, 0x27, 0x05, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xB0, 0xB9, 0x33, 0x33, 0x03, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x7C, 0x15, 0x16, 0x17, + 0x4E, 0x17, 0x48, 0x18, 0xC1, 0x1A, 0x6C, 0x18, 0xEC, 0x19, 0x31, 0x1A, 0x51, 0x1A, 0x7E, 0x17, + 0x07, 0xB8, 0xC3, 0x07, 0x00, 0x80, 0x00, 0x00, 0x20, 0x83, 0x00, 0x00, 0x00, 0x80, 0x32, 0x80, + 0x64, 0x80, 0x96, 0x80, 0x2D, 0xB4, 0x04, 0x0F, 0x11, 0x0C, 0x0F, 0x0F, 0x10, 0x00, 0x0F, 0x13, + 0xA5, 0xBB, 0x83, 0x1E, 0x18, 0xC8, 0x0F, 0x00, 0x15, 0x10, 0x15, 0x10, 0x10, 0x43, 0x10, 0x43, + 0x20, 0x03, 0x00, 0x00, 0x14, 0x39, 0x32, 0x15, 0x56, 0x73, 0x61, 0x0E, 0xD9, 0x03, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0C, 0x00, 0x00, 0x00, 0xDC, 0x55, 0x20, 0x05, 0x52, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xF8, 0xB0, 0x11, 0x1B, 0xB1, 0xB1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x7C, 0x15, 0x16, 0x17, 0x4E, 0x17, 0x48, 0x18, + 0xC1, 0x1A, 0x6C, 0x18, 0xEC, 0x19, 0x31, 0x1A, 0x51, 0x1A, 0x7E, 0x17, 0x07, 0xB8, 0xC3, 0x07, + 0x00, 0x80, 0x00, 0x00, 0x20, 0x83, 0x00, 0x00, 0x00, 0x80, 0x32, 0x80, 0x64, 0x80, 0x96, 0x80, + 0x2D, 0xB4, 0x04, 0x0F, 0x11, 0x0C, 0x0F, 0x0F, 0x10, 0x00, 0x0F, 0x13, 0xA5, 0xBB, 0x83, 0x1E, + 0x18, 0xC8, 0x0F, 0x00, 0x15, 0x10, 0x15, 0x10, 0x10, 0x43, 0x10, 0x43, 0x20, 0x03, 0x00, 0x00, + 0x14, 0x39, 0x32, 0x15, 0x56, 0x73, 0x61, 0x0E, 0xD9, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, + 0xDC, 0x55, 0x27, 0x75, 0x52, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xF8, 0xB0, 0x33, 0x3B, 0xB3, 0xB3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x7C, 0x15, 0x16, 0x17, 0x4E, 0x17, 0x48, 0x18, 0xC1, 0x1A, 0x6C, 0x18, + 0xEC, 0x19, 0x31, 0x1A, 0x51, 0x1A, 0x7E, 0x17, 0x07, 0xB8, 0xC3, 0x07, 0x00, 0x80, 0x00, 0x00, + 0x20, 0x83, 0x00, 0x00, 0x00, 0x80, 0x32, 0x80, 0x64, 0x80, 0x96, 0x80, 0x2D, 0xB4, 0x04, 0x0F, + 0x11, 0x0C, 0x0F, 0x0F, 0x10, 0x00, 0x0F, 0x13, 0xA5, 0xBB, 0x83, 0x1E, 0x18, 0xC8, 0x0F, 0x00, + 0x15, 0x10, 0x15, 0x10, 0x10, 0x43, 0x10, 0x43, 0x20, 0x03, 0x00, 0x00, 0x14, 0x39, 0x2E, 0x01, + 0xA5, 0x60, 0x0E, 0x04, 0x85, 0x71, 0x00, 0x08, 0x81, 0x30, 0x10, 0x05, 0xC6, 0x01, 0x20, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0xDC, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0xF8, 0xA0, 0xA0, 0xA0, + 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x7C, 0x15, 0x16, 0x17, 0x4E, 0x17, 0x48, 0x18, 0xC1, 0x1A, 0x6C, 0x18, 0xEC, 0x19, 0x31, 0x1A, + 0x51, 0x1A, 0x7E, 0x17, 0x07, 0xB8, 0xC3, 0x07, 0x00, 0x80, 0x00, 0x00, 0x20, 0x83, 0x00, 0x00, + 0x00, 0x80, 0x32, 0x80, 0x64, 0x80, 0x96, 0x80, 0x2D, 0xB4, 0x04, 0x0F, 0x11, 0x0C, 0x0F, 0x0F, + 0x10, 0x00, 0x0F, 0x13, 0xA5, 0xBA, 0x83, 0x0A, 0x18, 0xC8, 0x0F, 0x00, 0x15, 0x10, 0x15, 0x10, + 0x10, 0x43, 0x10, 0x43, 0x20, 0x03, 0x00, 0x00, 0x14, 0x39, 0x32, 0x0A, 0x4D, 0x60, 0x0A, 0x0E, + 0xC3, 0x43, 0x9C, 0x05, 0x90, 0x11, 0x1D, 0x28, 0x80, 0x84, 0x4C, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0xDC, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xB0, 0xB9, 0xA0, 0xB0, 0xB0, 0xA0, 0xB0, + 0xB0, 0xA0, 0xB1, 0xB0, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x7C, 0x15, 0x16, 0x17, + 0x4E, 0x17, 0x48, 0x18, 0xC1, 0x1A, 0x6C, 0x18, 0xEC, 0x19, 0x31, 0x1A, 0x51, 0x1A, 0x7E, 0x17, + 0x07, 0xB8, 0xC3, 0x07, 0x00, 0x80, 0x00, 0x00, 0x20, 0x83, 0x00, 0x00, 0x00, 0x80, 0x32, 0x80, + 0x64, 0x80, 0x96, 0x80, 0x2D, 0xB4, 0x04, 0x0F, 0x11, 0x0C, 0x0F, 0x0F, 0x10, 0x00, 0x0F, 0x13, + 0xA5, 0xBA, 0x83, 0x0A, 0x18, 0xC8, 0x0F, 0x00, 0x15, 0x10, 0x15, 0x10, 0x10, 0x43, 0x10, 0x43, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xFC, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x0D, 0x00, 0x08, 0x07, 0x21, 0x07, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x55, 0xB4, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x03, 0x02, + 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x0D, 0x00, + 0x10, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xB0, 0xB3, 0x00, 0x00, 0x00, 0x00, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x03, 0x02, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFC, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x0D, 0x00, 0x11, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x08, 0xB0, 0xB3, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0x03, 0x02, + 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x0D, 0x00, + 0x12, 0x00, 0x1D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xD8, 0xB3, 0x00, 0x00, 0x00, 0x00, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x04, 0x04, 0x03, 0x02, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFC, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x0D, 0x00, 0x13, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x08, 0xD8, 0xB3, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x05, 0x05, 0x03, 0x02, + 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x0D, 0x00, + 0x14, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0xB4, 0x00, 0x00, 0x00, 0x00, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x03, 0x02, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFC, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x0D, 0x00, 0x15, 0x00, 0x1A, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x08, 0x00, 0xB4, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x07, 0x07, 0x03, 0x02, + 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x0D, 0x00, + 0x16, 0x00, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x28, 0xB4, 0x00, 0x00, 0x00, 0x00, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x03, 0x02, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0xFC, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x0D, 0x00, 0x17, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x08, 0x28, 0xB4, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x0D, 0x00, + 0x04, 0x10, 0x1D, 0x10, 0x00, 0x00, 0x00, 0x00, 0x01, 0x50, 0xB4, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xFC, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x0D, 0x00, 0x89, 0x17, 0x70, 0x17, 0x00, 0x00, 0x00, 0x00, + 0x01, 0xAA, 0xB4, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x17, + 0x01, 0x00, 0x03, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x0D, 0x00, + 0x9C, 0x18, 0x9D, 0x18, 0x00, 0x00, 0xAC, 0x11, 0x02, 0x9B, 0xB4, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x16, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00, 0xFD, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x0D, 0x00, 0x30, 0x11, 0x38, 0x11, 0x00, 0x00, 0xAC, 0x11, + 0x02, 0x73, 0xB4, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x17, + 0x02, 0x00, 0x03, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x0D, 0x00, + 0xC0, 0x12, 0xC1, 0x12, 0x00, 0x00, 0xAC, 0x11, 0x02, 0x87, 0xB4, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x16, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, 0xFD, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x0D, 0x00, 0x30, 0x11, 0x38, 0x11, 0x00, 0x00, 0xAC, 0x11, + 0x03, 0x73, 0xB4, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x17, + 0x04, 0x00, 0x03, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x0D, 0x00, + 0xC0, 0x12, 0xC1, 0x12, 0x00, 0x00, 0xAC, 0x11, 0x03, 0x87, 0xB4, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x16, 0x06, 0x00, 0x03, 0x00, 0x00, 0x00, 0xFD, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x0D, 0x00, 0x30, 0x11, 0x38, 0x11, 0x00, 0x00, 0xAC, 0x11, + 0x03, 0x73, 0xB4, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x17, + 0x05, 0x00, 0x03, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x0D, 0x00, + 0xC0, 0x12, 0xC1, 0x12, 0x00, 0x00, 0xAC, 0x11, 0x03, 0x87, 0xB4, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x16, 0x08, 0x00, 0x03, 0x00, 0x00, 0x00, 0xFD, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x0D, 0x00, 0x30, 0x11, 0x38, 0x11, 0x00, 0x00, 0xAC, 0x11, + 0x03, 0x73, 0xB4, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x17, + 0x07, 0x00, 0x03, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x0D, 0x00, + 0xC0, 0x12, 0xC1, 0x12, 0x00, 0x00, 0xAC, 0x11, 0x03, 0x87, 0xB4, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x14, 0x14, 0x09, 0x00, 0x03, 0x00, 0x00, 0x00, 0xFC, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x97, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x0D, 0x00, + 0xC8, 0x00, 0xE1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x5A, 0xB4, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xFC, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x0D, 0x00, 0x58, 0x02, 0x71, 0x02, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x5A, 0xB4, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x0D, 0x00, + 0xE8, 0x03, 0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01, 0x64, 0xB4, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xFC, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x0D, 0x00, 0x78, 0x05, 0x91, 0x05, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x64, 0xB4, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x0D, 0x00, + 0x08, 0x07, 0x21, 0x07, 0x00, 0x00, 0x00, 0x00, 0x01, 0x6E, 0xB4, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xFC, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x0D, 0x00, 0x30, 0x11, 0x49, 0x11, 0x00, 0x00, 0x00, 0x00, + 0x01, 0xA5, 0xB4, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x0D, 0x00, + 0xC0, 0x12, 0xD9, 0x12, 0x00, 0x00, 0x00, 0x00, 0x01, 0xAA, 0xB4, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xFC, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x0D, 0x00, 0x50, 0x14, 0x69, 0x14, 0x00, 0x00, 0x00, 0x00, + 0x01, 0xAF, 0xB4, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x0D, 0x00, + 0xE0, 0x15, 0xF9, 0x15, 0x00, 0x00, 0x00, 0x00, 0x01, 0xB4, 0xB4, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xFC, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x0D, 0x00, 0x70, 0x17, 0x89, 0x17, 0x00, 0x00, 0x00, 0x00, + 0x01, 0xB9, 0xB4, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x09, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x97, 0x03, 0x06, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x14, 0x14, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xFC, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x97, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x14, 0x14, + 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x0C, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x97, 0x03, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x15, 0x15, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xCC, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x97, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x0D, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x97, 0x03, 0x06, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x14, 0x14, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xFC, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x97, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x17, + 0x02, 0x00, 0x03, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x0D, 0x00, + 0x9C, 0x18, 0x9D, 0x18, 0x00, 0x00, 0xAC, 0x11, 0x02, 0x9B, 0xB4, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x17, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, 0xFC, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x0D, 0x00, 0x9C, 0x18, 0x9D, 0x18, 0x00, 0x00, 0xAC, 0x11, + 0x02, 0x9B, 0xB4, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x17, + 0x06, 0x00, 0x03, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x0D, 0x00, + 0x9C, 0x18, 0x9D, 0x18, 0x00, 0x00, 0xAC, 0x11, 0x02, 0x9B, 0xB4, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x17, 0x09, 0x00, 0x03, 0x00, 0x00, 0x00, 0xFC, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x0D, 0x00, 0x9C, 0x18, 0x9D, 0x18, 0x00, 0x00, 0xAC, 0x11, + 0x02, 0x9B, 0xB4, 0x00, 0x04, 0x00, 0x00, 0x00, 0x4F, 0x00, 0x00, 0x00, 0x01, 0xF4, 0x04, 0x00, + 0x68, 0x93, 0x1B, 0x00, 0x60, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x01, 0x00, 0x04, 0x00, + 0x14, 0x28, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x2D, 0x00, 0x84, 0x00, + 0x14, 0x28, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x73, 0x00, 0x00, 0x00, 0x2D, 0xF4, 0x84, 0x00, + 0x68, 0x93, 0x1B, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x2D, 0xF4, 0x84, 0x00, + 0x68, 0x93, 0x1B, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x73, 0x00, 0x00, 0x00, 0x2D, 0xF4, 0x84, 0x00, + 0x68, 0x93, 0x1B, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x2D, 0xF4, 0x84, 0x00, + 0x68, 0x93, 0x1B, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x4F, 0x00, 0x00, 0x00, 0x1E, 0xF4, 0x04, 0x00, + 0x68, 0x93, 0x1B, 0x00, 0xE0, 0x00, 0x01, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x01, 0x00, 0x04, 0x00, + 0x14, 0x28, 0x00, 0x00, 0xE0, 0x00, 0x01, 0x00, 0x30, 0x00, 0x00, 0x00, 0x2D, 0x00, 0x84, 0x00, + 0x14, 0x28, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x2D, 0xF4, 0x84, 0x00, + 0x68, 0x93, 0x1B, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x02, 0xF4, 0x00, 0x00, + 0x68, 0x93, 0x1B, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x63, 0x00, 0x00, 0x00, 0x02, 0xF4, 0x00, 0x00, + 0x68, 0x93, 0x1B, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x23, 0x00, 0x84, 0x00, + 0x09, 0x12, 0x1B, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x2F, 0x2F, 0x2F, 0x2F, + 0x30, 0x2F, 0x30, 0x30, 0x30, 0x30, 0x2F, 0x2F, 0x30, 0x2F, 0x2F, 0x2F, 0x30, 0x30, 0x30, 0x2F, + 0x30, 0x30, 0x2F, 0x31, 0x30, 0x31, 0x2F, 0x2F, 0x30, 0x2F, 0x2F, 0x2F, 0x30, 0x30, 0x2F, 0x30, + 0x2E, 0x30, 0x30, 0x2F, 0x2F, 0x30, 0x30, 0x2F, 0x2F, 0x30, 0x2F, 0x30, 0x30, 0x2E, 0x2F, 0x2F, + 0x2F, 0x2F, 0x2F, 0x2F, 0x30, 0x30, 0x2F, 0x2F, 0x2F, 0x2F, 0x2E, 0x30, 0x30, 0x30, 0x30, 0x2F, + 0x2F, 0x30, 0x2F, 0x30, 0x30, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x30, 0x2F, 0x30, 0x2F, 0x2F, 0x30, + 0x2E, 0x30, 0x30, 0x2F, 0x30, 0x30, 0x30, 0x2F, 0x2E, 0x30, 0x2F, 0x31, 0x2D, 0x2C, 0x2C, 0x2C, + 0x2F, 0x2F, 0x2E, 0x2F, 0x30, 0x2F, 0x2F, 0x30, 0x30, 0x30, 0x2F, 0x2F, 0x30, 0x2F, 0x2F, 0x2F, + 0x30, 0x30, 0x2F, 0x2F, 0x30, 0x30, 0x2F, 0x30, 0x30, 0x30, 0x2F, 0x2F, 0x30, 0x2F, 0x2F, 0x2F, + 0x30, 0x30, 0x2F, 0x30, 0x2E, 0x30, 0x30, 0x2F, 0x2F, 0x30, 0x30, 0x2F, 0x2F, 0x30, 0x2F, 0x30, + 0x2F, 0x2E, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x30, 0x30, 0x2F, 0x2F, 0x2F, 0x2F, 0x2E, 0x30, + 0x30, 0x30, 0x30, 0x2F, 0x2F, 0x30, 0x2F, 0x30, 0x30, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x30, 0x2F, + 0x30, 0x2E, 0x2F, 0x30, 0x2E, 0x2F, 0x2F, 0x2F, 0x30, 0x2F, 0x2F, 0x2F, 0x2E, 0x30, 0x2E, 0x2F, + 0x2C, 0x2B, 0x2B, 0x2C, 0x2F, 0x2F, 0x2E, 0x2F, 0x30, 0x2F, 0x2F, 0x30, 0x30, 0x30, 0x2F, 0x2F, + 0x30, 0x2F, 0x2F, 0x2F, 0x30, 0x30, 0x2F, 0x2F, 0x30, 0x30, 0x2F, 0x30, 0x30, 0x31, 0x2F, 0x2F, + 0x30, 0x2F, 0x2F, 0x2F, 0x30, 0x30, 0x2F, 0x30, 0x2E, 0x30, 0x30, 0x2F, 0x30, 0x30, 0x30, 0x2F, + 0x2F, 0x30, 0x2F, 0x30, 0x2F, 0x2E, 0x2F, 0x2F, 0x30, 0x2F, 0x2F, 0x2F, 0x30, 0x30, 0x2F, 0x2F, + 0x2F, 0x2F, 0x2E, 0x30, 0x30, 0x30, 0x30, 0x2F, 0x2F, 0x30, 0x2F, 0x30, 0x30, 0x2F, 0x2F, 0x2F, + 0x2F, 0x2F, 0x30, 0x2F, 0x30, 0x2F, 0x2F, 0x30, 0x2E, 0x30, 0x30, 0x2F, 0x30, 0x30, 0x2F, 0x2F, + 0x2E, 0x30, 0x2E, 0x30, 0x2D, 0x2B, 0x2B, 0x2C, 0x2F, 0x2F, 0x2E, 0x2F, 0x30, 0x2F, 0x2F, 0x30, + 0x30, 0x30, 0x2F, 0x2F, 0x30, 0x2F, 0x2F, 0x2F, 0x30, 0x30, 0x2F, 0x2F, 0x30, 0x30, 0x2F, 0x31, + 0x30, 0x31, 0x2F, 0x2F, 0x30, 0x2F, 0x2F, 0x2F, 0x30, 0x30, 0x2F, 0x30, 0x2E, 0x30, 0x30, 0x2F, + 0x30, 0x30, 0x30, 0x2F, 0x2F, 0x30, 0x2F, 0x30, 0x2F, 0x2E, 0x2F, 0x2F, 0x30, 0x2F, 0x2F, 0x2F, + 0x30, 0x30, 0x2F, 0x2F, 0x2F, 0x2F, 0x2E, 0x30, 0x30, 0x30, 0x30, 0x2F, 0x2F, 0x30, 0x2F, 0x30, + 0x30, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x30, 0x2F, 0x30, 0x2E, 0x2F, 0x30, 0x2E, 0x30, 0x2F, 0x2F, + 0x30, 0x2F, 0x2F, 0x2E, 0x2E, 0x30, 0x2E, 0x2F, 0x2C, 0x2B, 0x2B, 0x2B, 0x2F, 0x2F, 0x2E, 0x2F, + 0x30, 0x2F, 0x2F, 0x30, 0x30, 0x30, 0x2F, 0x2F, 0x30, 0x2F, 0x30, 0x2F, 0x30, 0x30, 0x30, 0x2F, + 0x30, 0x30, 0x2F, 0x31, 0x30, 0x31, 0x2F, 0x2F, 0x30, 0x2F, 0x2F, 0x2F, 0x30, 0x30, 0x2F, 0x30, + 0x2E, 0x30, 0x30, 0x2F, 0x30, 0x30, 0x30, 0x2F, 0x2F, 0x30, 0x2F, 0x30, 0x2F, 0x2E, 0x2F, 0x2F, + 0x30, 0x2F, 0x2F, 0x2F, 0x30, 0x30, 0x2F, 0x2F, 0x2F, 0x2F, 0x2E, 0x30, 0x30, 0x30, 0x30, 0x2F, + 0x2F, 0x30, 0x2F, 0x30, 0x30, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x30, 0x2F, 0x30, 0x2F, 0x2F, 0x30, + 0x2E, 0x30, 0x30, 0x2F, 0x30, 0x30, 0x2F, 0x2F, 0x2E, 0x30, 0x2E, 0x2F, 0x2D, 0x2B, 0x2B, 0x2C, + 0x2F, 0x2F, 0x2E, 0x2F, 0x30, 0x2F, 0x2F, 0x30, 0x30, 0x30, 0x2F, 0x2F, 0x30, 0x2F, 0x30, 0x2F, + 0x30, 0x30, 0x30, 0x2F, 0x30, 0x30, 0x2F, 0x31, 0x30, 0x31, 0x2F, 0x2F, 0x30, 0x2F, 0x2F, 0x2F, + 0x30, 0x30, 0x2F, 0x30, 0x2E, 0x30, 0x30, 0x2F, 0x30, 0x30, 0x30, 0x2F, 0x2F, 0x30, 0x2F, 0x30, + 0x2F, 0x2E, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x30, 0x30, 0x2F, 0x2F, 0x2F, 0x2F, 0x2E, 0x30, + 0x30, 0x30, 0x30, 0x2F, 0x2F, 0x30, 0x2F, 0x30, 0x30, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x30, 0x2F, + 0x30, 0x2E, 0x2F, 0x30, 0x2E, 0x30, 0x2F, 0x2F, 0x30, 0x2F, 0x2F, 0x2E, 0x2E, 0x30, 0x2E, 0x2F, + 0x2C, 0x2B, 0x2B, 0x2B, 0x2F, 0x2F, 0x2E, 0x2F, 0x30, 0x2F, 0x2F, 0x30, 0x30, 0x30, 0x2F, 0x2F, + 0x30, 0x2F, 0x30, 0x2F, 0x30, 0x30, 0x30, 0x2F, 0x30, 0x30, 0x2F, 0x31, 0x30, 0x31, 0x2F, 0x2F, + 0x30, 0x2F, 0x2F, 0x2F, 0x30, 0x30, 0x2F, 0x30, 0x2E, 0x30, 0x30, 0x2F, 0x30, 0x30, 0x30, 0x2F, + 0x2F, 0x30, 0x2F, 0x30, 0x2F, 0x2E, 0x2F, 0x2F, 0x30, 0x2F, 0x2F, 0x2F, 0x30, 0x30, 0x2F, 0x2F, + 0x2F, 0x2F, 0x2E, 0x30, 0x30, 0x30, 0x30, 0x2F, 0x2F, 0x30, 0x2F, 0x30, 0x30, 0x2F, 0x2F, 0x2F, + 0x2F, 0x2F, 0x30, 0x2F, 0x30, 0x2F, 0x2F, 0x30, 0x2E, 0x30, 0x30, 0x2F, 0x30, 0x30, 0x2F, 0x2F, + 0x2E, 0x30, 0x2E, 0x30, 0x2D, 0x2B, 0x2B, 0x2C, 0x30, 0x2F, 0x2E, 0x2F, 0x30, 0x2F, 0x2F, 0x30, + 0x30, 0x30, 0x2F, 0x2F, 0x30, 0x2F, 0x30, 0x2F, 0x30, 0x30, 0x2F, 0x2F, 0x30, 0x30, 0x2F, 0x31, + 0x30, 0x31, 0x2F, 0x2F, 0x30, 0x2F, 0x2F, 0x2F, 0x30, 0x30, 0x2F, 0x30, 0x2F, 0x30, 0x30, 0x2F, + 0x30, 0x30, 0x30, 0x2F, 0x2F, 0x30, 0x2F, 0x30, 0x2F, 0x2E, 0x2F, 0x2F, 0x30, 0x2F, 0x2F, 0x2F, + 0x30, 0x30, 0x2F, 0x2F, 0x2F, 0x2F, 0x2E, 0x30, 0x30, 0x30, 0x30, 0x2F, 0x2F, 0x30, 0x2F, 0x30, + 0x30, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x30, 0x2F, 0x30, 0x2E, 0x2F, 0x30, 0x2E, 0x30, 0x30, 0x2F, + 0x30, 0x2F, 0x2F, 0x2F, 0x2E, 0x30, 0x2E, 0x30, 0x2D, 0x2B, 0x2B, 0x2C, 0x73, 0x69, 0x6B, 0x67, + 0x67, 0x63, 0x69, 0x67, 0x63, 0x65, 0x66, 0x5F, 0x5F, 0x5B, 0x61, 0x63, 0x5F, 0x5F, 0x62, 0x61, + 0x5B, 0x5B, 0x5B, 0x5D, 0x59, 0x59, 0x5B, 0x5B, 0x55, 0x55, 0x5B, 0x5D, 0x53, 0x57, 0x59, 0x57, + 0x53, 0x53, 0x59, 0x57, 0x55, 0x53, 0x57, 0x53, 0x53, 0x4F, 0x55, 0x55, 0x50, 0x4F, 0x55, 0x55, + 0x55, 0x4F, 0x57, 0x51, 0x4F, 0x4F, 0x53, 0x4F, 0x4D, 0x4F, 0x51, 0x4F, 0x49, 0x4D, 0x4D, 0x53, + 0x47, 0x4B, 0x4F, 0x4D, 0x4B, 0x49, 0x4F, 0x4D, 0x4D, 0x49, 0x51, 0x51, 0x49, 0x47, 0x4B, 0x51, + 0x45, 0x46, 0x4B, 0x4B, 0x4B, 0x49, 0x49, 0x47, 0x49, 0x47, 0x4B, 0x4B, 0x49, 0x41, 0x47, 0x41, + 0x92, 0x24, 0x92, 0x24, 0x92, 0x00, 0x92, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB6, 0x6D, 0xB6, 0x6D, + 0xB6, 0x00, 0xB6, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB6, 0x6D, 0xB6, 0x6D, 0x96, 0x01, 0x96, 0x01, + 0x00, 0x00, 0x00, 0x00, 0xB6, 0x6D, 0xB6, 0x6D, 0xB2, 0x01, 0xB2, 0x01, 0x00, 0x00, 0x00, 0x00, + 0xB6, 0x2D, 0xB6, 0x2D, 0xB6, 0x01, 0xB6, 0x01, 0x00, 0x00, 0x00, 0x00, 0xB6, 0x65, 0xB6, 0x65, + 0xB6, 0x01, 0xB6, 0x01, 0x00, 0x00, 0x00, 0x00, 0xB6, 0x6C, 0xB6, 0x6C, 0xB6, 0x01, 0xB6, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x96, 0x6D, 0x96, 0x6D, 0xB6, 0x01, 0xB6, 0x01, 0x00, 0x00, 0x00, 0x00, + 0xB2, 0x6D, 0xB2, 0x6D, 0xB6, 0x01, 0xB6, 0x01, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x7F, 0xFF, 0x7F, + 0xFF, 0x01, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0xB6, 0x6D, 0xB6, 0x6D, 0xB6, 0x01, 0xB6, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x92, 0x24, 0x92, 0x24, 0x92, 0x00, 0x92, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3D, 0xDB, + 0x38, 0xD4, 0xFC, 0x02, 0x02, 0x00, 0xAA, 0x00, 0x6C, 0x76, 0x8A, 0x94, 0x00, 0x01, 0x06, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xDB, 0x06, 0x00, 0x00, 0x04, 0x0C, 0x00, 0x00, 0x3C, 0x05, 0x6E, 0x40, + 0x41, 0x4D, 0x39, 0x03, 0x01, 0x00, 0x00, 0x9A, 0xC8, 0x04, 0x4D, 0x61, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x10, 0xC4, 0x0C, 0x50, 0x03, 0x90, 0xBB, 0xBB, 0x80, 0x44, 0x22, 0x78, + 0x64, 0x11, 0x64, 0x11, 0x89, 0x39, 0x89, 0x39, 0x0F, 0xE0, 0x0F, 0xE0, 0x64, 0x12, 0x64, 0x12, + 0x01, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3D, 0xDB, + 0x38, 0xD4, 0xFC, 0x02, 0x02, 0x00, 0xAA, 0x00, 0x6C, 0x76, 0x8A, 0x94, 0x00, 0x01, 0x06, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xDB, 0x06, 0x00, 0x00, 0x04, 0x0C, 0x00, 0x00, 0x3C, 0x05, 0x6E, 0x40, + 0x41, 0x4D, 0x39, 0x03, 0x01, 0x00, 0x00, 0x9A, 0xC8, 0x04, 0x4D, 0x61, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x10, 0xC4, 0x0C, 0x10, 0xE3, 0x9E, 0xBB, 0xBB, 0x80, 0x55, 0x22, 0x78, + 0x64, 0x11, 0x64, 0x11, 0x89, 0x39, 0x89, 0x39, 0x0F, 0xE0, 0x0F, 0xE0, 0x64, 0x12, 0x64, 0x12, + 0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0xAA, 0x00, 0x6C, 0x76, 0x8A, 0x94, 0x00, 0x01, 0x06, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xDB, 0x06, 0x00, 0x00, 0x04, 0x0C, 0x00, 0x00, 0x38, 0x06, 0x6E, 0x40, + 0x41, 0x8C, 0x39, 0x03, 0x01, 0x00, 0x00, 0x9A, 0xC4, 0x05, 0x8C, 0x61, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x10, 0xC4, 0x0C, 0x50, 0x03, 0x90, 0xBB, 0xBB, 0x80, 0x44, 0x22, 0x78, + 0x64, 0x11, 0x64, 0x11, 0x89, 0x39, 0x89, 0x39, 0x0F, 0xE0, 0x0F, 0xE0, 0x64, 0x12, 0x64, 0x12, + 0xAF, 0x04, 0x02, 0x00, 0x01, 0x02, 0x03, 0x04, 0x52, 0xF5, 0x54, 0xFD, 0x8E, 0x27, 0xE0, 0x93, + 0xCF, 0x03, 0x04, 0x02, 0x1E, 0x00, 0x00, 0x03, 0x6C, 0x76, 0x8A, 0x94, 0x00, 0x01, 0x06, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xDB, 0x06, 0x00, 0x00, 0x01, 0x46, 0x00, 0x00, 0xD1, 0x16, 0x00, 0x40, + 0x00, 0x6B, 0x39, 0x03, 0x41, 0x00, 0x02, 0x9A, 0x00, 0x00, 0x6B, 0x61, 0x64, 0x78, 0x79, 0x2B, + 0xCF, 0x8A, 0x00, 0x80, 0x1C, 0x54, 0x11, 0x98, 0x00, 0x80, 0xBB, 0xBB, 0x00, 0x57, 0x22, 0x78, + 0x64, 0x11, 0x64, 0x11, 0x89, 0x39, 0x89, 0x39, 0x0F, 0xF0, 0x0F, 0xF0, 0x64, 0x12, 0x64, 0x12, + 0xAF, 0x04, 0x02, 0x00, 0x01, 0x01, 0x01, 0x01, 0x52, 0xF5, 0x54, 0xFD, 0x8E, 0x27, 0xE0, 0x93, + 0xCF, 0x03, 0x04, 0x02, 0x02, 0x00, 0x00, 0x00, 0x6C, 0x76, 0x8A, 0x94, 0x00, 0x01, 0x06, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xDB, 0x06, 0x00, 0x00, 0x01, 0x46, 0x00, 0x00, 0xD1, 0x16, 0x00, 0x40, + 0x00, 0x6B, 0x39, 0x03, 0x41, 0x00, 0x02, 0x9A, 0x00, 0x00, 0x6B, 0x61, 0xBB, 0x7D, 0xFC, 0x17, + 0xFF, 0xFF, 0x00, 0x80, 0x1C, 0x54, 0x11, 0x98, 0x03, 0x80, 0xBB, 0xBB, 0x80, 0x46, 0x22, 0x78, + 0x64, 0x11, 0x64, 0x11, 0x89, 0x39, 0x89, 0x39, 0x0F, 0xF0, 0x0F, 0xF0, 0x64, 0x12, 0x64, 0x12, + 0xAF, 0x04, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x52, 0xF5, 0x54, 0xFD, 0x8E, 0x27, 0xE0, 0x93, + 0xCF, 0x03, 0x04, 0x02, 0x02, 0x00, 0x00, 0x00, 0x6C, 0x76, 0x8A, 0x94, 0x00, 0x01, 0x06, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xDB, 0x06, 0x00, 0x00, 0x01, 0x46, 0x00, 0x00, 0xD1, 0x16, 0x00, 0x40, + 0x00, 0x6B, 0x39, 0x03, 0x41, 0x00, 0x02, 0x9A, 0x00, 0x00, 0x6B, 0x61, 0x0F, 0x7E, 0x34, 0x16, + 0xFF, 0xFF, 0x00, 0x80, 0x1C, 0x54, 0x11, 0x98, 0x03, 0x80, 0xBB, 0xBB, 0x80, 0x46, 0x22, 0x78, + 0x64, 0x11, 0x64, 0x11, 0x89, 0x39, 0x89, 0x39, 0x0F, 0xF0, 0x0F, 0xF0, 0x64, 0x12, 0x64, 0x12, + 0xAF, 0x04, 0x02, 0x00, 0x03, 0x03, 0x03, 0x03, 0x52, 0xF5, 0x54, 0xFD, 0x8E, 0x27, 0xE0, 0x93, + 0xCF, 0x03, 0x04, 0x02, 0x02, 0x00, 0x00, 0x00, 0x6C, 0x76, 0x8A, 0x94, 0x00, 0x01, 0x06, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xDB, 0x06, 0x00, 0x00, 0x01, 0x46, 0x00, 0x00, 0xD1, 0x16, 0x00, 0x40, + 0x00, 0x6B, 0x39, 0x03, 0x41, 0x00, 0x02, 0x9A, 0x00, 0x00, 0x6B, 0x61, 0xB1, 0x7E, 0x3C, 0x12, + 0xFF, 0xFF, 0x00, 0x80, 0x1C, 0x54, 0x11, 0x98, 0x03, 0x80, 0xBB, 0xBB, 0x80, 0x46, 0x22, 0x78, + 0x64, 0x11, 0x64, 0x11, 0x89, 0x39, 0x89, 0x39, 0x0F, 0xF0, 0x0F, 0xF0, 0x64, 0x12, 0x64, 0x12, + 0xAF, 0x04, 0x02, 0x00, 0x04, 0x04, 0x04, 0x04, 0x52, 0xF5, 0x54, 0xFD, 0x8E, 0x27, 0xE0, 0x93, + 0xCF, 0x03, 0x04, 0x02, 0x02, 0x00, 0x00, 0x00, 0x6C, 0x76, 0x8A, 0x94, 0x00, 0x01, 0x06, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xDB, 0x06, 0x00, 0x00, 0x01, 0x46, 0x00, 0x00, 0xD1, 0x16, 0x00, 0x40, + 0x00, 0x6B, 0x39, 0x03, 0x41, 0x00, 0x02, 0x9A, 0x00, 0x00, 0x6B, 0x61, 0x1C, 0x7F, 0x0B, 0x0F, + 0xFF, 0xFF, 0x00, 0x80, 0x1C, 0x54, 0x11, 0x98, 0x03, 0x80, 0xBB, 0xBB, 0x80, 0x46, 0x22, 0x78, + 0x64, 0x11, 0x64, 0x11, 0x89, 0x39, 0x89, 0x39, 0x0F, 0xF0, 0x0F, 0xF0, 0x64, 0x12, 0x64, 0x12, + 0x01, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0xCC, 0xF5, 0x7A, 0xFD, 0xED, 0x20, 0xBF, 0x8F, + 0xCF, 0x03, 0x04, 0x02, 0x02, 0x06, 0x00, 0x00, 0x6C, 0x76, 0x8A, 0x94, 0x00, 0x01, 0x06, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xDB, 0x06, 0x00, 0x00, 0x01, 0x06, 0x00, 0x00, 0x09, 0x11, 0x00, 0x40, + 0x00, 0x6B, 0x39, 0x03, 0x41, 0x00, 0x02, 0x9A, 0x00, 0x00, 0x6B, 0x61, 0x64, 0x78, 0x79, 0x2B, + 0xCF, 0x8A, 0x00, 0x80, 0x1C, 0xC4, 0x10, 0x18, 0x03, 0x80, 0xAB, 0xAA, 0x00, 0xC6, 0x22, 0x78, + 0x64, 0x11, 0x64, 0x11, 0x80, 0x39, 0x80, 0x39, 0x0F, 0x00, 0x0F, 0x00, 0x55, 0x0D, 0x55, 0x0D, + 0x1D, 0x04, 0x02, 0x00, 0x05, 0x07, 0x08, 0x09, 0x5E, 0x6A, 0x4E, 0x99, 0x30, 0xF1, 0x72, 0x8F, + 0x8F, 0x33, 0x18, 0x02, 0x1E, 0x06, 0x00, 0x03, 0x6C, 0x76, 0x8A, 0x94, 0x00, 0x01, 0x06, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xDB, 0x06, 0x00, 0x00, 0x01, 0x46, 0x00, 0x00, 0xFF, 0x03, 0x00, 0x40, + 0x00, 0x6B, 0x39, 0x03, 0x41, 0x00, 0x02, 0x9A, 0x00, 0x00, 0x6B, 0x61, 0x64, 0x78, 0x79, 0x2B, + 0xCF, 0x8A, 0x00, 0x80, 0x1C, 0x54, 0x11, 0x98, 0x00, 0x80, 0xBB, 0xBB, 0x00, 0x57, 0x22, 0x18, + 0x64, 0x11, 0x64, 0x11, 0x89, 0x39, 0x89, 0x39, 0x3F, 0xF0, 0x3F, 0xF0, 0x64, 0x12, 0x64, 0x12, + 0x76, 0x05, 0x02, 0x00, 0x06, 0x06, 0x06, 0x06, 0xFA, 0xB5, 0x6B, 0xFF, 0x2C, 0x07, 0xFE, 0x44, + 0xCF, 0x03, 0x0C, 0x02, 0x02, 0x06, 0x01, 0x00, 0x6C, 0x76, 0x8A, 0x94, 0x00, 0x22, 0x16, 0x01, + 0x00, 0x00, 0x00, 0x00, 0xDB, 0x06, 0x00, 0x00, 0x01, 0x46, 0x00, 0x00, 0x78, 0x30, 0x00, 0x40, + 0x00, 0x6B, 0x39, 0x03, 0x41, 0x00, 0x02, 0x9A, 0x00, 0x00, 0x6B, 0x61, 0x64, 0x78, 0x79, 0x2B, + 0xCF, 0x8A, 0x00, 0x80, 0x1C, 0x54, 0x11, 0x98, 0x00, 0x80, 0xBB, 0xBB, 0x00, 0x57, 0x22, 0x18, + 0x64, 0x11, 0x64, 0x11, 0x89, 0x39, 0x89, 0x39, 0x3F, 0xF0, 0x3F, 0xF0, 0x64, 0x12, 0x64, 0x12, + 0x76, 0x05, 0x02, 0x00, 0x07, 0x06, 0x05, 0x0A, 0xFA, 0xB5, 0x6B, 0xFF, 0x2C, 0x07, 0xFE, 0x44, + 0xCF, 0x03, 0x0C, 0x02, 0x0A, 0x06, 0x01, 0x00, 0x6C, 0x76, 0x8A, 0x94, 0x00, 0x22, 0x16, 0x01, + 0x00, 0x00, 0x00, 0x00, 0xDB, 0x06, 0x00, 0x00, 0x01, 0x46, 0x00, 0x00, 0x78, 0x30, 0x00, 0x40, + 0x00, 0x6B, 0x39, 0x03, 0x41, 0x00, 0x02, 0x9A, 0x00, 0x00, 0x6B, 0x61, 0x93, 0x67, 0xCB, 0xB4, + 0x00, 0x00, 0x00, 0x80, 0x12, 0x54, 0x11, 0x98, 0x00, 0x80, 0xBB, 0xBB, 0x00, 0x56, 0x22, 0x18, + 0x64, 0x11, 0x64, 0x11, 0x89, 0x39, 0x89, 0x39, 0x3F, 0xF0, 0x3F, 0xF0, 0x64, 0x12, 0x64, 0x12, + 0x60, 0x05, 0x02, 0x00, 0x0C, 0x07, 0x0A, 0x0B, 0x27, 0xAC, 0x58, 0xFF, 0x84, 0x38, 0x51, 0x49, + 0xCF, 0x03, 0x0C, 0x02, 0x0A, 0x06, 0x01, 0x00, 0x6C, 0x76, 0x8A, 0x94, 0x00, 0x20, 0x16, 0x01, + 0x00, 0x00, 0x00, 0x00, 0xDB, 0x06, 0x00, 0x00, 0x01, 0x46, 0x00, 0x00, 0xA2, 0x2D, 0x00, 0x40, + 0x00, 0x6B, 0x39, 0x03, 0x41, 0x00, 0x02, 0x9A, 0x00, 0x00, 0x6B, 0x61, 0x55, 0x73, 0x7B, 0xC8, + 0x00, 0x00, 0x00, 0x80, 0x12, 0x54, 0x11, 0x98, 0x00, 0x80, 0xBB, 0xBB, 0x00, 0x56, 0x22, 0x18, + 0x64, 0x11, 0x64, 0x11, 0x89, 0x39, 0x89, 0x39, 0x3F, 0xF0, 0x3F, 0xF0, 0x64, 0x12, 0x64, 0x12, + 0x3F, 0x05, 0x02, 0x00, 0x10, 0x09, 0x0E, 0x0C, 0x4E, 0x99, 0x33, 0xFF, 0x72, 0x8F, 0xEC, 0x50, + 0xCF, 0x03, 0x0C, 0x02, 0x0A, 0x06, 0x01, 0x00, 0x6C, 0x76, 0x8A, 0x94, 0x00, 0x1D, 0x16, 0x01, + 0x00, 0x00, 0x00, 0x00, 0xDB, 0x06, 0x00, 0x00, 0x01, 0x46, 0x00, 0x00, 0x61, 0x29, 0x00, 0x40, + 0x00, 0x6B, 0x39, 0x03, 0x41, 0x00, 0x02, 0x9A, 0x00, 0x00, 0x6B, 0x61, 0xD9, 0x77, 0x0E, 0xD3, + 0x00, 0x00, 0x00, 0x80, 0x12, 0x54, 0x11, 0x98, 0x00, 0x80, 0xBB, 0xBB, 0x00, 0x56, 0x22, 0x18, + 0x64, 0x11, 0x64, 0x11, 0x89, 0x39, 0x89, 0x39, 0x3F, 0xF0, 0x3F, 0xF0, 0x64, 0x12, 0x64, 0x12, + 0x76, 0x05, 0x02, 0x00, 0x10, 0x0A, 0x0C, 0x06, 0xFA, 0xB5, 0x6B, 0xFF, 0x2C, 0x07, 0xFE, 0x44, + 0xCF, 0x03, 0x0C, 0x02, 0x0A, 0x06, 0x01, 0x00, 0x6C, 0x76, 0x8A, 0x94, 0x00, 0x22, 0x16, 0x01, + 0x00, 0x00, 0x00, 0x00, 0xDB, 0x06, 0x00, 0x00, 0x01, 0x46, 0x00, 0x00, 0x78, 0x30, 0x00, 0x40, + 0x00, 0x6B, 0x39, 0x03, 0x41, 0x00, 0x02, 0x9A, 0x00, 0x00, 0x6B, 0x61, 0xBD, 0x79, 0x77, 0xD8, + 0x00, 0x00, 0x00, 0x80, 0x12, 0x54, 0x11, 0x98, 0x00, 0x80, 0xBB, 0xBB, 0x00, 0x56, 0x22, 0x18, + 0x64, 0x11, 0x64, 0x11, 0x89, 0x39, 0x89, 0x39, 0x3F, 0xF0, 0x3F, 0xF0, 0x64, 0x12, 0x64, 0x12, + 0x01, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0xCC, 0xF5, 0x7A, 0xFD, 0xED, 0x20, 0xBF, 0x8F, + 0xCF, 0x03, 0x04, 0x02, 0x02, 0x06, 0x00, 0x00, 0x6C, 0x76, 0x8A, 0x94, 0x01, 0x01, 0x06, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xDB, 0x06, 0x00, 0x00, 0x01, 0x06, 0x00, 0x00, 0xCE, 0x66, 0x00, 0x40, + 0x00, 0x6B, 0x39, 0x03, 0x41, 0x00, 0x02, 0x9A, 0x00, 0x00, 0x6B, 0x61, 0x64, 0x78, 0x79, 0x2B, + 0xCF, 0x8A, 0x00, 0x80, 0x1C, 0xC4, 0x10, 0x18, 0x03, 0x80, 0xAB, 0xAA, 0x00, 0xC6, 0x22, 0x78, + 0x64, 0x11, 0x64, 0x11, 0x80, 0x39, 0x80, 0x39, 0x0F, 0x00, 0x0F, 0x00, 0x55, 0x0D, 0x55, 0x0D, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x56, 0xCE, + 0x00, 0x00, 0x99, 0x10, 0x10, 0x0E, 0x00, 0x06, 0x00, 0x00, 0xFD, 0xF9, 0x00, 0x00, 0x6F, 0xA1, + 0x10, 0x0E, 0x00, 0x05, 0x00, 0x00, 0x46, 0x4F, 0x00, 0x00, 0x29, 0xA6, 0x10, 0x0F, 0x00, 0x04, + 0x00, 0x00, 0xAD, 0x87, 0x00, 0x00, 0x7D, 0xD9, 0x10, 0x0F, 0x00, 0x03, 0x00, 0x00, 0xE0, 0x86, + 0x00, 0x00, 0x9F, 0x8B, 0x00, 0x0D, 0x10, 0x08, 0x00, 0x00, 0x56, 0xCF, 0x00, 0x00, 0x72, 0xCB, + 0x00, 0x0B, 0x10, 0x0A, 0x00, 0x00, 0xFF, 0x9E, 0x00, 0x00, 0xBE, 0xC8, 0x00, 0x09, 0x10, 0x0C, + 0x00, 0x00, 0x2A, 0xDF, 0x00, 0x00, 0xFE, 0x72, 0x00, 0x06, 0x10, 0x0E, 0x00, 0x00, 0xD1, 0x57, + 0x00, 0x00, 0x37, 0x66, 0x00, 0x04, 0x10, 0x0F, 0x00, 0x00, 0x8E, 0xBE, 0x00, 0x00, 0x93, 0x36, + 0x00, 0x0E, 0x10, 0x06, 0x00, 0x00, 0x4F, 0x50, 0x00, 0x00, 0x4E, 0x50, 0x00, 0x0B, 0x10, 0x0B, + 0x00, 0x00, 0xEC, 0xAF, 0x00, 0x00, 0xAD, 0x6F, 0x00, 0x08, 0x10, 0x0D, 0x00, 0x00, 0x79, 0x1F, + 0x00, 0x00, 0x35, 0xC8, 0x00, 0x06, 0x10, 0x0E, 0x00, 0x00, 0xC1, 0x87, 0x00, 0x00, 0xD3, 0xB2, + 0x00, 0x0E, 0x10, 0x06, 0x00, 0x00, 0x7C, 0xE8, 0x00, 0x00, 0x3F, 0x74, 0x00, 0x0C, 0x10, 0x09, + 0x00, 0x00, 0x22, 0x64, 0x00, 0x00, 0xA0, 0x2A, 0x00, 0x0A, 0x10, 0x0C, 0x00, 0x00, 0xD8, 0x8A, + 0x00, 0x00, 0x58, 0x1C, 0x00, 0x07, 0x10, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x24, 0x02, 0x00, 0x00, 0xD4, 0x5B, 0x06, 0xA7, 0x15, 0xD2, 0x7C, 0xEC, + 0x0A, 0x69, 0x3E, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xC0, 0x22, 0xC0, 0x22, 0xDC, 0x0C, 0x00, 0x00, 0x69, 0x3E, 0xB6, 0xE6, 0xD7, 0xFC, 0x9A, 0x5F, + 0xF3, 0x6B, 0xBE, 0x32, 0xA8, 0xF9, 0xCA, 0xA0, 0xE6, 0x2B, 0x83, 0x9A, 0x5F, 0xF3, 0x6B, 0x7E, + 0xCD, 0x57, 0x06, 0xCA, 0xA0, 0xE6, 0x2B, 0x83, 0x9A, 0x5F, 0xF3, 0x95, 0x41, 0xCD, 0x57, 0x06, + 0x35, 0x5F, 0x19, 0xD4, 0x7C, 0x65, 0xA0, 0x0C, 0x94, 0x41, 0xCD, 0x07, 0x00, 0x00, 0x00, 0x00, + 0xED, 0x22, 0xED, 0x22, 0xDC, 0x0C, 0x00, 0x00, 0x69, 0x3E, 0xB6, 0xE6, 0xD7, 0xFC, 0x9A, 0xAF, + 0x0C, 0x94, 0x41, 0xCD, 0xAF, 0xF9, 0xCA, 0xA0, 0xE6, 0x2B, 0x83, 0x9A, 0xAF, 0x0C, 0x94, 0x81, + 0x32, 0x50, 0x06, 0x35, 0xBF, 0xE6, 0x2B, 0x83, 0x9A, 0xAF, 0x0C, 0x6A, 0x7E, 0xCD, 0x57, 0x06, + 0x35, 0xBF, 0xE6, 0xD7, 0x7C, 0x65, 0x50, 0xF3, 0x95, 0x81, 0x32, 0x00, 0xD4, 0x7C, 0x65, 0x00, + 0xED, 0x22, 0xED, 0x22, 0xDC, 0x0C, 0x00, 0x00, 0x69, 0x3E, 0x56, 0x19, 0xD4, 0xFC, 0x9A, 0xAF, + 0x0C, 0x94, 0x41, 0xCD, 0xAF, 0xF9, 0x35, 0xBF, 0xE6, 0x2B, 0x83, 0x9A, 0x5F, 0xF3, 0x6B, 0xBE, + 0x32, 0xA8, 0xF9, 0x35, 0xBF, 0xE6, 0x2B, 0x83, 0x9A, 0x5F, 0xF3, 0x95, 0x41, 0xCD, 0xAF, 0xF9, + 0x35, 0xBF, 0xE6, 0xD7, 0xFC, 0x9A, 0xAF, 0x0C, 0x94, 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xED, 0x22, 0xED, 0x22, 0xDC, 0x0C, 0x00, 0x00, 0x69, 0x3E, 0x56, 0x19, 0xD4, 0xFC, 0x9A, 0xAF, + 0x0C, 0x94, 0x41, 0xCD, 0xAF, 0xF9, 0x35, 0xBF, 0xE6, 0xD7, 0xFC, 0x9A, 0x5F, 0xF3, 0x6B, 0x7E, + 0xCD, 0xAF, 0xF9, 0xCA, 0xA0, 0xE6, 0x2B, 0x83, 0x9A, 0x5F, 0xF3, 0x6B, 0x7E, 0xCD, 0xAF, 0xF9, + 0x35, 0xBF, 0xE6, 0x2B, 0x83, 0x9A, 0x5F, 0xF3, 0x6B, 0x7E, 0xCD, 0x07, 0xD4, 0x7C, 0x65, 0x00, + 0xED, 0x22, 0xED, 0x22, 0xDC, 0x0C, 0x00, 0x00, 0x69, 0x3E, 0x56, 0x19, 0xD4, 0xFC, 0x9A, 0x5F, + 0xF3, 0x6B, 0x7E, 0xCD, 0xAF, 0xF9, 0xCA, 0xA0, 0xE6, 0xD7, 0xFC, 0x9A, 0x5F, 0xF3, 0x6B, 0xBE, + 0x32, 0x50, 0x06, 0xCA, 0x40, 0x19, 0xD4, 0xFC, 0x9A, 0x5F, 0xF3, 0x6B, 0x7E, 0xCD, 0x57, 0x06, + 0x35, 0xBF, 0xE6, 0x2B, 0x03, 0x65, 0xA0, 0x0C, 0x94, 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xED, 0x22, 0xED, 0x22, 0xDC, 0x0C, 0x00, 0x00, 0x69, 0x3E, 0x56, 0x19, 0xD4, 0xFC, 0x9A, 0xAF, + 0x0C, 0x6A, 0x7E, 0xCD, 0xAF, 0xF9, 0xCA, 0xA0, 0xE6, 0xD7, 0xFC, 0x9A, 0x5F, 0xF3, 0x6B, 0xBE, + 0x32, 0xA8, 0xF9, 0x35, 0xBF, 0xE6, 0x2B, 0x03, 0x65, 0x50, 0xF3, 0x6B, 0x7E, 0xCD, 0xAF, 0xF9, + 0x35, 0xBF, 0xE6, 0xD7, 0xFC, 0x9A, 0xAF, 0x0C, 0x6A, 0xBE, 0x32, 0x00, 0xD4, 0x7C, 0x65, 0x00, + 0xED, 0x22, 0xED, 0x22, 0x31, 0x30, 0x2F, 0x2E, 0x2D, 0x2C, 0x2B, 0x2A, 0x29, 0x28, 0x27, 0x26, + 0x25, 0x24, 0x23, 0x22, 0x21, 0x20, 0x1F, 0x1E, 0x1D, 0x1C, 0x1B, 0x1A, 0x19, 0x18, 0x17, 0x16, + 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x0F, 0x0E, 0x0D, 0x0C, 0x0B, 0x0A, 0x09, 0x08, 0x07, 0x06, + 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4A, 0x49, 0x48, 0x47, + 0x46, 0x45, 0x44, 0x43, 0x42, 0x41, 0x40, 0x3F, 0x3E, 0x3D, 0x3C, 0x3B, 0x3A, 0x39, 0x38, 0x37, + 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x30, 0x2F, 0x2E, 0x2D, 0x2C, 0x2B, 0x2A, 0x29, 0x28, 0x27, + 0x26, 0x25, 0x24, 0x23, 0x22, 0x21, 0x20, 0x1F, 0x1E, 0x1D, 0x1C, 0x1B, 0x1A, 0x19, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0xE0, 0xC0, 0xA0, 0x80, 0x60, 0x40, 0x20, 0x00, 0xE0, 0xC0, + 0xA0, 0x80, 0x60, 0x40, 0x20, 0x00, 0xE0, 0xC0, 0xA0, 0x80, 0x60, 0x40, 0x20, 0x00, 0xE0, 0xC0, + 0xA0, 0x80, 0x60, 0x40, 0x20, 0x00, 0xE0, 0xC0, 0xA0, 0x80, 0x60, 0x40, 0x20, 0x00, 0xE0, 0xC0, + 0xA0, 0x80, 0x60, 0x40, 0x20, 0x00, 0x00, 0x00, 0x76, 0xDB, 0xB6, 0x2D, 0x24, 0x49, 0x92, 0x1B, + 0xDB, 0xB6, 0x49, 0x12, 0x92, 0x94, 0x24, 0x09, 0x09, 0x00, 0x00, 0x00, 0x20, 0x00, 0xE0, 0xC0, + 0xA0, 0x80, 0x60, 0x40, 0x20, 0x00, 0xE0, 0xC0, 0xA0, 0x80, 0x60, 0x40, 0x20, 0x00, 0xE0, 0xC0, + 0xA0, 0x80, 0x60, 0x40, 0x20, 0x00, 0xE0, 0xC0, 0xA0, 0x80, 0x60, 0x40, 0x20, 0x00, 0xE0, 0xC0, + 0xA0, 0x80, 0x60, 0x40, 0x20, 0x00, 0xE0, 0xC0, 0xA0, 0x80, 0x60, 0x40, 0x20, 0x00, 0x00, 0x00, + 0x76, 0xDB, 0xB6, 0x2D, 0x24, 0x49, 0x92, 0x1B, 0xDB, 0xB6, 0x49, 0x12, 0x92, 0x94, 0x24, 0x09, + 0x09, 0x00, 0x00, 0x00, 0x20, 0x21, 0xE0, 0xE1, 0xA0, 0xA1, 0x60, 0x61, 0x20, 0x21, 0xE0, 0xE1, + 0xA0, 0xA1, 0x60, 0x61, 0x20, 0x21, 0xE0, 0xE1, 0xA0, 0xA1, 0x60, 0x61, 0x20, 0x21, 0xE0, 0xE1, + 0xA0, 0xA1, 0x60, 0x61, 0x20, 0x21, 0xE0, 0xE1, 0xA0, 0xA1, 0x60, 0x61, 0x20, 0x21, 0xE0, 0xE1, + 0xA0, 0xA1, 0x60, 0x61, 0x20, 0x21, 0x00, 0x00, 0x76, 0xDB, 0xB6, 0x2D, 0x24, 0x49, 0x92, 0x1B, + 0xDB, 0xB6, 0x49, 0x12, 0x92, 0x94, 0x24, 0x09, 0x09, 0x00, 0x00, 0x00, 0x01, 0x00, 0xC1, 0xC0, + 0x81, 0x80, 0x41, 0x40, 0x01, 0x00, 0xC1, 0xC0, 0x81, 0x80, 0x41, 0x40, 0x01, 0x00, 0xC1, 0xC0, + 0x81, 0x80, 0x41, 0x40, 0x01, 0x00, 0xC1, 0xC0, 0x81, 0x80, 0x41, 0x40, 0x01, 0x00, 0xC1, 0xC0, + 0x81, 0x80, 0x41, 0x40, 0x01, 0x00, 0xC1, 0xC0, 0x81, 0x80, 0x41, 0x40, 0x01, 0x00, 0x00, 0x00, + 0x76, 0xDB, 0xB6, 0x2D, 0x24, 0x49, 0x92, 0x1B, 0xDB, 0xB6, 0x49, 0x12, 0x92, 0x94, 0x24, 0x09, + 0x09, 0x00, 0x00, 0x00, 0x21, 0x20, 0xE1, 0xE0, 0xA1, 0xA0, 0x61, 0x60, 0x21, 0x20, 0xE1, 0xE0, + 0xA1, 0xA0, 0x61, 0x60, 0x21, 0x20, 0xE1, 0xE0, 0xA1, 0xA0, 0x61, 0x60, 0x21, 0x20, 0xE1, 0xE0, + 0xA1, 0xA0, 0x61, 0x60, 0x21, 0x20, 0xE1, 0xE0, 0xA1, 0xA0, 0x61, 0x60, 0x21, 0x20, 0xE1, 0xE0, + 0xA1, 0xA0, 0x61, 0x60, 0x21, 0x20, 0x00, 0x00, 0x76, 0xDB, 0xB6, 0x2D, 0x24, 0x49, 0x92, 0x1B, + 0xDB, 0xB6, 0x49, 0x12, 0x92, 0x94, 0x24, 0x09, 0x09, 0x00, 0x00, 0x00, 0x73, 0x53, 0x33, 0x13, + 0xF2, 0xD2, 0xB2, 0x92, 0x72, 0x52, 0x32, 0x12, 0xF2, 0xD2, 0xB2, 0x92, 0x72, 0x52, 0x32, 0x12, + 0xF2, 0xD2, 0xB2, 0x92, 0x72, 0x52, 0x32, 0x12, 0xF2, 0xD2, 0xB2, 0x92, 0x72, 0x52, 0x32, 0x12, + 0xF2, 0xD2, 0xB2, 0x92, 0x72, 0x52, 0x32, 0x12, 0xF2, 0xD2, 0xB2, 0x92, 0x72, 0x52, 0x00, 0x00, + 0x00, 0xD0, 0xB6, 0x2D, 0x2D, 0x49, 0x92, 0x24, 0xDB, 0xB6, 0x6D, 0x12, 0x92, 0x24, 0x25, 0x09, + 0x49, 0x02, 0x00, 0x00, 0x3C, 0x1C, 0xFC, 0xDC, 0xBC, 0x9C, 0x7C, 0x5C, 0x3C, 0x1C, 0xFC, 0xDC, + 0xBC, 0x9C, 0x7C, 0x5C, 0x3C, 0x1C, 0xFC, 0xDC, 0xBC, 0x9C, 0x7C, 0x5C, 0x3C, 0x1C, 0xFC, 0xDC, + 0xBC, 0x9C, 0x7C, 0x5C, 0x3C, 0x1C, 0xFC, 0xDC, 0xBC, 0x9C, 0x7C, 0x5C, 0x3C, 0x1C, 0xFB, 0xDB, + 0xBB, 0x9B, 0x7B, 0x5B, 0x3B, 0x1B, 0x00, 0x00, 0x2D, 0x49, 0x92, 0x24, 0xDB, 0xB6, 0x6D, 0x12, + 0x92, 0x24, 0x25, 0x09, 0x49, 0x02, 0x00, 0x00, 0x40, 0xDB, 0xB6, 0x2D, 0xB4, 0x94, 0x74, 0x54, + 0x34, 0x14, 0xF3, 0xD3, 0xB3, 0x93, 0x73, 0x53, 0x33, 0x13, 0xF3, 0xD3, 0xB3, 0x93, 0x73, 0x53, + 0x33, 0x13, 0xF3, 0xD3, 0xB3, 0x93, 0x73, 0x53, 0x33, 0x13, 0xF3, 0xD3, 0xB3, 0x93, 0x73, 0x53, + 0x33, 0x13, 0xF3, 0xD3, 0xB3, 0x93, 0x73, 0x53, 0x33, 0x13, 0xF3, 0xD3, 0xB3, 0x93, 0x00, 0x00, + 0x00, 0x00, 0xB4, 0x2D, 0x6D, 0x4B, 0x92, 0x24, 0xE4, 0xB6, 0x6D, 0x1B, 0x92, 0x24, 0x49, 0x09, + 0x49, 0x92, 0x00, 0x00, 0xFB, 0xDB, 0xBB, 0x9B, 0x7B, 0x5B, 0x3B, 0x1B, 0xFB, 0xDB, 0xBB, 0x9B, + 0x7B, 0x5B, 0x3B, 0x1B, 0xFB, 0xDB, 0xBB, 0x9B, 0x7B, 0x5B, 0x3B, 0x1B, 0xFB, 0xDB, 0xBB, 0x9B, + 0x7B, 0x5B, 0x3B, 0x1B, 0xFB, 0xDB, 0xBB, 0x9B, 0x7B, 0x5B, 0x3B, 0x1B, 0xFA, 0xDA, 0xBA, 0x9A, + 0x7A, 0x5A, 0x3A, 0x1A, 0xFA, 0xDA, 0x00, 0x00, 0x24, 0x49, 0x92, 0x1B, 0xDB, 0xB6, 0x49, 0x12, + 0x92, 0x94, 0x24, 0x09, 0x09, 0x00, 0x00, 0x00, 0x6D, 0xDB, 0xB6, 0x24, 0xF5, 0xD5, 0xB5, 0x95, + 0x75, 0x55, 0x35, 0x15, 0xF4, 0xD4, 0xB4, 0x94, 0x74, 0x54, 0x34, 0x14, 0xF4, 0xD4, 0xB4, 0x94, + 0x74, 0x54, 0x34, 0x14, 0xF4, 0xD4, 0xB4, 0x94, 0x74, 0x54, 0x34, 0x14, 0xF4, 0xD4, 0xB4, 0x94, + 0x74, 0x54, 0x34, 0x14, 0xF4, 0xD4, 0xB4, 0x94, 0x74, 0x54, 0x34, 0x14, 0xF4, 0xD4, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x2D, 0x6D, 0xDB, 0x92, 0x24, 0x24, 0xB9, 0x6D, 0x1B, 0x9B, 0x24, 0x49, 0x12, + 0x49, 0x92, 0x24, 0x00, 0xBA, 0x9A, 0x7A, 0x5A, 0x3A, 0x1A, 0xFA, 0xDA, 0xBA, 0x9A, 0x7A, 0x5A, + 0x3A, 0x1A, 0xFA, 0xDA, 0xBA, 0x9A, 0x7A, 0x5A, 0x3A, 0x1A, 0xFA, 0xDA, 0xBA, 0x9A, 0x7A, 0x5A, + 0x3A, 0x1A, 0xFA, 0xDA, 0xBA, 0x9A, 0x7A, 0x5A, 0x3A, 0x1A, 0xF9, 0xD9, 0xB9, 0x99, 0x79, 0x59, + 0x39, 0x19, 0xF9, 0xD9, 0xB9, 0x99, 0x00, 0x00, 0x24, 0x49, 0x6E, 0x1B, 0xDB, 0x26, 0x49, 0x12, + 0x52, 0x92, 0x24, 0x09, 0x00, 0x00, 0x00, 0x2D, 0x6D, 0xDB, 0x92, 0x24, 0x36, 0x16, 0xF6, 0xD6, + 0xB6, 0x96, 0x76, 0x56, 0x36, 0x16, 0xF5, 0xD5, 0xB5, 0x95, 0x75, 0x55, 0x35, 0x15, 0xF5, 0xD5, + 0xB5, 0x95, 0x75, 0x55, 0x35, 0x15, 0xF5, 0xD5, 0xB5, 0x95, 0x75, 0x55, 0x35, 0x15, 0xF5, 0xD5, + 0xB5, 0x95, 0x75, 0x55, 0x35, 0x15, 0xF5, 0xD5, 0xB5, 0x95, 0x75, 0x55, 0x35, 0x15, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x6D, 0xDB, 0xB6, 0x24, 0x24, 0x49, 0x6E, 0x1B, 0xDB, 0x26, 0x49, 0x12, + 0x52, 0x92, 0x24, 0x09, 0x79, 0x59, 0x39, 0x19, 0xF9, 0xD9, 0xB9, 0x99, 0x79, 0x59, 0x39, 0x19, + 0xF9, 0xD9, 0xB9, 0x99, 0x79, 0x59, 0x39, 0x19, 0xF9, 0xD9, 0xB9, 0x99, 0x79, 0x59, 0x39, 0x19, + 0xF9, 0xD9, 0xB9, 0x99, 0x79, 0x59, 0x39, 0x19, 0xF8, 0xD8, 0xB8, 0x98, 0x78, 0x58, 0x38, 0x18, + 0xF8, 0xD8, 0xB8, 0x98, 0x78, 0x58, 0x00, 0x00, 0x24, 0xB9, 0x6D, 0x1B, 0x9B, 0x24, 0x49, 0x12, + 0x49, 0x92, 0x24, 0x00, 0x00, 0x00, 0xB4, 0x2D, 0x6D, 0x4B, 0x92, 0x24, 0x77, 0x57, 0x37, 0x17, + 0xF7, 0xD7, 0xB7, 0x97, 0x77, 0x57, 0x37, 0x17, 0xF6, 0xD6, 0xB6, 0x96, 0x76, 0x56, 0x36, 0x16, + 0xF6, 0xD6, 0xB6, 0x96, 0x76, 0x56, 0x36, 0x16, 0xF6, 0xD6, 0xB6, 0x96, 0x76, 0x56, 0x36, 0x16, + 0xF6, 0xD6, 0xB6, 0x96, 0x76, 0x56, 0x36, 0x16, 0xF6, 0xD6, 0xB6, 0x96, 0x76, 0x56, 0x00, 0x00, + 0x49, 0x02, 0x00, 0x00, 0x40, 0xDB, 0xB6, 0x2D, 0x24, 0x49, 0x92, 0x1B, 0xDB, 0xB6, 0x49, 0x12, + 0x92, 0x94, 0x24, 0x09, 0x38, 0x18, 0xF8, 0xD8, 0xB8, 0x98, 0x78, 0x58, 0x38, 0x18, 0xF8, 0xD8, + 0xB8, 0x98, 0x78, 0x58, 0x38, 0x18, 0xF8, 0xD8, 0xB8, 0x98, 0x78, 0x58, 0x38, 0x18, 0xF8, 0xD8, + 0xB8, 0x98, 0x78, 0x58, 0x38, 0x18, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xE4, 0xB6, 0x6D, 0x1B, 0x92, 0x24, 0x49, 0x09, + 0x49, 0x92, 0x00, 0x00, 0x00, 0xF0, 0xFF, 0x3F, 0xFF, 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF7, 0xD7, 0xB7, 0x97, 0x77, 0x57, + 0x37, 0x17, 0xF7, 0xD7, 0xB7, 0x97, 0x77, 0x57, 0x37, 0x17, 0xF7, 0xD7, 0xB7, 0x97, 0x77, 0x57, + 0x37, 0x17, 0xF7, 0xD7, 0xB7, 0x97, 0x77, 0x57, 0x37, 0x17, 0xF7, 0xD7, 0xB7, 0x97, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0x3F, 0xFF, 0xDF, 0xB6, 0x2D, 0x2D, 0x49, 0x92, 0x24, 0xDB, 0xB6, 0x6D, 0x12, + 0x92, 0x24, 0x25, 0x09, 0x63, 0x62, 0x61, 0x60, 0x5F, 0x5E, 0x5D, 0x5C, 0x5B, 0x5A, 0x59, 0x58, + 0x57, 0x56, 0x55, 0x54, 0x53, 0x52, 0x51, 0x50, 0x4F, 0x4E, 0x4D, 0x4C, 0x4B, 0x4A, 0x49, 0x48, + 0x47, 0x46, 0x45, 0x44, 0x43, 0x42, 0x41, 0x40, 0x3F, 0x3E, 0x3D, 0x3C, 0x3B, 0x3A, 0x39, 0x38, + 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x31, 0x30, 0x2F, 0x2E, + 0x2D, 0x2C, 0x2B, 0x2A, 0x29, 0x28, 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21, 0x20, 0x1F, 0x1E, + 0x1D, 0x1C, 0x1B, 0x1A, 0x19, 0x18, 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x0F, 0x0E, + 0x0D, 0x0C, 0x0B, 0x0A, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0xFF, 0x3F, + 0xFF, 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0xFF, 0x3F, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x57, 0x47, 0x37, 0x27, 0x17, 0x07, 0x56, 0x46, 0x36, 0x26, 0x16, 0x06, + 0x55, 0x45, 0x35, 0x25, 0x15, 0x05, 0x54, 0x44, 0x34, 0x24, 0x14, 0x04, 0x53, 0x43, 0x33, 0x23, + 0x13, 0x03, 0x52, 0x42, 0x32, 0x22, 0x12, 0x02, 0x51, 0x41, 0x31, 0x21, 0x11, 0x01, 0x50, 0x40, + 0x30, 0x20, 0x10, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x62, 0x60, 0x5E, 0x5C, + 0x5A, 0x58, 0x56, 0x54, 0x52, 0x50, 0x4E, 0x4C, 0x4A, 0x48, 0x46, 0x44, 0x42, 0x40, 0x3E, 0x3C, + 0x3A, 0x38, 0x36, 0x34, 0x32, 0x30, 0x2E, 0x2C, 0x2A, 0x28, 0x26, 0x24, 0x22, 0x20, 0x1E, 0x1C, + 0x1A, 0x18, 0x16, 0x14, 0x12, 0x10, 0x0E, 0x0C, 0x0A, 0x08, 0x06, 0x04, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x08, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32, 0x02, 0x10, 0x00, + 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x8C, 0x1C, 0x00, 0x00, 0xAF, 0x1C, 0x00, 0x00, 0xD2, 0x1C, 0x00, 0x00, 0xF5, 0x1C, 0x00, 0x00, + 0x20, 0x03, 0x00, 0x00, 0x41, 0x10, 0x08, 0x03, 0x44, 0x61, 0x1C, 0x08, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0A, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x56, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x18, 0x1D, 0xD6, 0x1D, 0x06, 0x1E, 0x1F, 0x1E, + 0x53, 0x1F, 0x58, 0x1E, 0x30, 0x1F, 0x42, 0x1F, 0x43, 0x1F, 0x7E, 0x17, 0x07, 0xB8, 0xC3, 0x07, + 0x00, 0x80, 0x00, 0x00, 0x20, 0x83, 0x00, 0x00, 0x00, 0x80, 0x32, 0x80, 0x64, 0x80, 0x96, 0x80, + 0x2D, 0xB4, 0x04, 0x0F, 0x11, 0x0C, 0x0F, 0x0F, 0x10, 0x00, 0x0F, 0x13, 0xA5, 0xBA, 0x03, 0x0A, + 0x18, 0xC8, 0x0F, 0x00, 0x15, 0x10, 0x15, 0x10, 0x10, 0x43, 0x10, 0x43, 0x20, 0x03, 0x00, 0x00, + 0xCB, 0xB2, 0x30, 0x0D, 0xCE, 0x03, 0x45, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, + 0x66, 0x66, 0x66, 0x66, 0x56, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, + 0x03, 0x00, 0x00, 0x00, 0x18, 0x1D, 0xD6, 0x1D, 0x06, 0x1E, 0x1F, 0x1E, 0x53, 0x1F, 0x58, 0x1E, + 0x30, 0x1F, 0x42, 0x1F, 0x43, 0x1F, 0x7E, 0x17, 0x07, 0xB8, 0x07, 0x33, 0x00, 0x80, 0x00, 0x00, + 0x20, 0x83, 0x00, 0x00, 0x00, 0x80, 0x32, 0x80, 0x64, 0x80, 0x96, 0x80, 0x2D, 0xB4, 0x04, 0x0F, + 0x11, 0x0C, 0x0F, 0x0F, 0x90, 0x00, 0x0F, 0x13, 0xA5, 0xBA, 0x83, 0x0A, 0x18, 0xC8, 0x0F, 0x00, + 0x15, 0x10, 0x15, 0x10, 0x10, 0x43, 0x10, 0x43, 0x45, 0x09, 0x7E, 0x17, 0x07, 0xB8, 0xC3, 0x07, + 0x00, 0x80, 0x00, 0x80, 0x20, 0xF3, 0x00, 0x0C, 0x00, 0x80, 0x32, 0x80, 0x64, 0x80, 0x96, 0xFE, + 0x2D, 0xB4, 0xFF, 0xFF, 0x11, 0xFD, 0xFF, 0xFF, 0xD0, 0xFF, 0x0F, 0x13, 0xA5, 0xBA, 0x83, 0x0A, + 0x18, 0xC8, 0x0F, 0x00, 0x13, 0x0F, 0x13, 0x0F, 0x0F, 0x41, 0x0F, 0x41, 0x1F, 0x03, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x9D, 0xD6, 0x9D, 0x06, 0x9E, 0x1F, 0x9E, 0x53, 0x9F, 0x58, 0x9E, 0x30, 0x9F, 0x42, 0x9F, + 0x43, 0x9F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xE6, 0x00, 0x00, 0xEC, 0x04, 0x54, 0xE7, 0xE4, 0x07, 0x7E, 0xE7, 0x55, 0x09, 0xA2, 0x07, + 0x0A, 0x09, 0x25, 0x09, 0x45, 0x09, 0x7E, 0x17, 0x07, 0xB8, 0xC3, 0x07, 0x00, 0x80, 0x00, 0x00, + 0x20, 0x83, 0x00, 0x00, 0x00, 0x80, 0x32, 0x80, 0x64, 0x80, 0x96, 0x80, 0x2D, 0xB4, 0x04, 0x8F, + 0x11, 0xFD, 0xFF, 0xFF, 0xD0, 0xFF, 0x0F, 0x93, 0xA5, 0xBA, 0x83, 0x0A, 0x18, 0xE8, 0x0F, 0xE0, + 0x13, 0x0F, 0x13, 0xFF, 0x0F, 0x41, 0x0F, 0x41, 0x1F, 0x03, 0x00, 0x00, 0xD4, 0xB8, 0x04, 0x02, + 0x03, 0x51, 0x18, 0x87, 0x48, 0xF0, 0x0C, 0x0C, 0x85, 0x01, 0x1C, 0x08, 0x18, 0x9D, 0xD6, 0x9D, + 0x06, 0x9E, 0x1F, 0x9E, 0x53, 0x9F, 0x58, 0x9E, 0x30, 0x9F, 0x42, 0x9F, 0x43, 0x9F, 0x55, 0x55, + 0x55, 0x55, 0x55, 0xD5, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x08, 0x6A, 0x66, 0x66, + 0x66, 0x66, 0x66, 0x66, 0x36, 0x66, 0x00, 0x27, 0x00, 0x00, 0x00, 0x00, 0x02, 0xE6, 0x00, 0x80, + 0xEC, 0x0C, 0x54, 0xEF, 0xE4, 0x87, 0x7E, 0xE7, 0x55, 0x09, 0xA2, 0x07, 0x0A, 0xE9, 0x25, 0xE9, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x28, 0x02, 0x00, 0x00, 0x00, 0xFC, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x0D, 0x00, 0x59, 0x06, 0x40, 0x06, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x55, 0x97, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x02, + 0x00, 0x28, 0x00, 0x00, 0x80, 0x02, 0xFC, 0x00, 0xFF, 0xFF, 0xFF, 0x01, 0x0D, 0x00, 0x0D, 0x00, + 0x17, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xB0, 0xB3, 0x00, 0x00, 0x00, 0x00, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x00, 0x28, 0x00, 0x00, 0x80, 0x02, 0xFC, 0x00, + 0xFF, 0xFF, 0xFF, 0x01, 0x0D, 0x00, 0x0D, 0x00, 0x16, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x04, 0xC4, 0xB3, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x02, 0x02, + 0x00, 0x28, 0x00, 0x00, 0x80, 0x02, 0xFC, 0x00, 0xFF, 0xFF, 0xFF, 0x01, 0x0D, 0x00, 0x0D, 0x00, + 0x15, 0x00, 0x1D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xD8, 0xB3, 0x00, 0x00, 0x00, 0x00, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x02, 0x02, 0x00, 0x28, 0x00, 0x00, 0x80, 0x02, 0xFC, 0x00, + 0xFF, 0xFF, 0xFF, 0x01, 0x0D, 0x00, 0x0D, 0x00, 0x14, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x04, 0xEC, 0xB3, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x02, 0x02, + 0x00, 0x28, 0x00, 0x00, 0x80, 0x02, 0xFC, 0x00, 0xFF, 0xFF, 0xFF, 0x01, 0x0D, 0x00, 0x0D, 0x00, + 0x13, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0xB4, 0x00, 0x00, 0x00, 0x00, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x02, 0x02, 0x00, 0x28, 0x00, 0x00, 0x80, 0x02, 0xFC, 0x00, + 0xFF, 0xFF, 0xFF, 0x01, 0x0D, 0x00, 0x0D, 0x00, 0x12, 0x00, 0x1A, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x14, 0xB4, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x02, 0x02, + 0x00, 0x28, 0x00, 0x00, 0x80, 0x02, 0xFC, 0x00, 0xFF, 0xFF, 0xFF, 0x01, 0x0D, 0x00, 0x0D, 0x00, + 0x11, 0x00, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x28, 0xB4, 0x00, 0x00, 0x00, 0x00, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x02, 0x02, 0x00, 0x28, 0x04, 0x00, 0x80, 0x02, 0xFC, 0x00, + 0xFF, 0xFF, 0xFF, 0x01, 0x0D, 0x00, 0x0D, 0x00, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x20, 0xB0, 0xB3, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x28, 0x06, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x0D, 0x00, + 0xD2, 0x0F, 0xA0, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x01, 0x50, 0x97, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x02, 0x00, 0x00, 0x00, 0xFC, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x0D, 0x00, 0xC1, 0x16, 0xA8, 0x16, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x8C, 0x97, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x02, 0x02, + 0x00, 0x28, 0x00, 0x00, 0x80, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x0D, 0x00, + 0x17, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xB0, 0xB3, 0x00, 0x00, 0x00, 0x00, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x02, 0x02, 0x00, 0x28, 0x00, 0x00, 0x80, 0x00, 0xFC, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x0D, 0x00, 0x16, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x04, 0xC4, 0xB3, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x02, 0x02, + 0x00, 0x28, 0x00, 0x00, 0x80, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x0D, 0x00, + 0x15, 0x00, 0x1D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xD8, 0xB3, 0x00, 0x00, 0x00, 0x00, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x02, 0x02, 0x00, 0x28, 0x00, 0x00, 0x80, 0x00, 0xFC, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x0D, 0x00, 0x14, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x04, 0xEC, 0xB3, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x02, 0x02, + 0x00, 0x28, 0x00, 0x00, 0x80, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x0D, 0x00, + 0x13, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0xB4, 0x00, 0x00, 0x00, 0x00, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x02, 0x02, 0x00, 0x28, 0x00, 0x00, 0x80, 0x00, 0xFC, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x0D, 0x00, 0x12, 0x00, 0x1A, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x14, 0xB4, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x02, 0x02, + 0x00, 0x28, 0x00, 0x00, 0x80, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x0D, 0x00, + 0x11, 0x00, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x28, 0xB4, 0x00, 0x00, 0x00, 0x00, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x02, 0x02, 0x00, 0x28, 0x04, 0x00, 0x80, 0x00, 0xFC, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x0D, 0x00, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x20, 0xB0, 0xB3, 0x00, 0x00, 0x00, 0x00, 0x10, 0x4F, 0x00, 0x00, 0x00, 0x01, 0xF4, 0x04, 0x00, + 0x68, 0x93, 0x1B, 0x00, 0x60, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x01, 0x00, 0x04, 0x00, + 0x14, 0x28, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x2D, 0x00, 0x84, 0x00, + 0x14, 0x28, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x73, 0x00, 0x00, 0x00, 0x2D, 0xF4, 0x84, 0x00, + 0x68, 0x93, 0x1B, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x2D, 0xF4, 0x84, 0x00, + 0x68, 0x93, 0x1B, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x73, 0x00, 0x00, 0x00, 0x2D, 0xF4, 0x84, 0x00, + 0x68, 0x93, 0x1B, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x63, 0x00, 0x00, 0x00, 0x2D, 0xF4, 0x84, 0x00, + 0x68, 0x93, 0x1B, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x4F, 0x00, 0x00, 0x00, 0x01, 0xF4, 0x04, 0x00, + 0x68, 0x93, 0x1B, 0x00, 0xE0, 0x00, 0x01, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x01, 0x00, 0x04, 0x00, + 0x14, 0x28, 0x00, 0x00, 0xE0, 0x00, 0x01, 0x00, 0x30, 0x00, 0x00, 0x00, 0x2D, 0x00, 0x84, 0x00, + 0x14, 0x28, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x2D, 0xF4, 0x84, 0x00, + 0x68, 0x93, 0x1B, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x92, 0x24, 0x92, 0x24, + 0x92, 0x00, 0x92, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x49, 0x24, 0x49, 0x24, 0x01, 0xA4, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x14, 0x49, 0x24, 0x49, 0x24, 0x01, 0x14, 0x01, 0x00, 0x00, 0x00, 0x00, + 0xA4, 0x48, 0x24, 0x49, 0x24, 0x01, 0x22, 0x01, 0x00, 0x00, 0x00, 0x00, 0x24, 0x45, 0x24, 0x29, + 0x24, 0x01, 0x24, 0x01, 0x00, 0x00, 0x00, 0x00, 0x24, 0x29, 0x24, 0x45, 0x24, 0x01, 0x24, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x24, 0x49, 0xA4, 0x48, 0x22, 0x01, 0x24, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x24, 0x49, 0x14, 0x49, 0x14, 0x01, 0x24, 0x01, 0x00, 0x00, 0x00, 0x00, 0x24, 0x49, 0x22, 0x49, + 0xA4, 0x00, 0x24, 0x01, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x7F, 0xFF, 0x7F, 0xFF, 0x01, 0xFF, 0x01, + 0x00, 0x00, 0x00, 0x00, 0xB6, 0x6D, 0xB6, 0x6D, 0xB6, 0x01, 0xB6, 0x01, 0x00, 0x00, 0x00, 0x00, + 0xB2, 0x6D, 0xB6, 0x6D, 0xB6, 0x01, 0xB6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x96, 0x6D, 0xB6, 0x6D, + 0xB6, 0x01, 0x96, 0x01, 0x00, 0x00, 0x00, 0x00, 0xB6, 0x6C, 0xB6, 0x6D, 0xB6, 0x01, 0xB2, 0x01, + 0x00, 0x00, 0x00, 0x00, 0xB6, 0x65, 0xB6, 0x2D, 0xB6, 0x01, 0xB6, 0x01, 0x00, 0x00, 0x00, 0x00, + 0xB6, 0x2D, 0xB6, 0x65, 0xB6, 0x01, 0xB6, 0x01, 0x00, 0x00, 0x00, 0x00, 0xB6, 0x6D, 0xB6, 0x6C, + 0xB2, 0x01, 0xB6, 0x01, 0x00, 0x00, 0x00, 0x00, 0xB6, 0x6D, 0x96, 0x6D, 0x96, 0x01, 0xB6, 0x01, + 0x00, 0x00, 0x00, 0x00, 0xB6, 0x6D, 0xB2, 0x6D, 0xB6, 0x00, 0xB6, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x02, 0x02, 0x06, 0xAA, 0x00, 0x6C, 0x76, 0x8A, 0x94, 0x00, 0x01, 0x06, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xDB, 0x06, 0x00, 0x00, 0x01, 0x06, 0x00, 0x00, 0x91, 0x01, 0x6E, 0x40, + 0x41, 0x8C, 0x39, 0x03, 0x01, 0x00, 0x00, 0x9A, 0x1D, 0x01, 0x8C, 0x61, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x0D, 0x10, 0x03, 0x90, 0xBB, 0xBB, 0x8E, 0x5A, 0x22, 0x18, + 0x64, 0x11, 0x64, 0x11, 0x89, 0x39, 0x89, 0x39, 0x0A, 0xE0, 0x0F, 0xE0, 0x64, 0x12, 0x64, 0x12, + 0x01, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x02, 0x02, 0x06, 0xAA, 0x00, 0x6C, 0x76, 0x8A, 0x94, 0x00, 0x01, 0x06, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xDB, 0x06, 0x00, 0x00, 0x01, 0x06, 0x00, 0x00, 0x91, 0x01, 0x6E, 0x40, + 0x41, 0x8C, 0x39, 0x03, 0x01, 0x00, 0x00, 0x9A, 0x1D, 0x01, 0x8C, 0x61, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x0C, 0x10, 0x03, 0x80, 0xAB, 0xAA, 0x80, 0x44, 0x22, 0x78, + 0x64, 0x11, 0x64, 0x11, 0x89, 0x39, 0x89, 0x39, 0x05, 0xE0, 0x05, 0xE0, 0x64, 0x12, 0x64, 0x12, + 0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0xAA, 0x00, 0x6C, 0x76, 0x8A, 0x94, 0x00, 0x01, 0x06, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xDB, 0x06, 0x00, 0x00, 0x04, 0x0C, 0x00, 0x00, 0x38, 0x06, 0x6E, 0x20, + 0x41, 0x8C, 0x39, 0x03, 0x01, 0x00, 0x00, 0x84, 0xC4, 0x05, 0x8C, 0x61, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x10, 0xC4, 0x0C, 0x50, 0x03, 0x90, 0xBB, 0xBB, 0x80, 0x44, 0x22, 0x78, + 0x64, 0x11, 0x64, 0x11, 0x8A, 0x39, 0x89, 0x39, 0x05, 0xE0, 0x0F, 0xE0, 0x64, 0x12, 0x64, 0x12, + 0xD0, 0x04, 0x02, 0x00, 0x01, 0x02, 0x03, 0x04, 0xCC, 0xF5, 0x7A, 0xFD, 0xED, 0x20, 0xBF, 0x8F, + 0xCF, 0x03, 0x04, 0x02, 0x1E, 0x06, 0x00, 0x03, 0x6C, 0x76, 0x8A, 0x94, 0x00, 0x01, 0x06, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xDB, 0x06, 0x00, 0x00, 0x01, 0x46, 0x00, 0x00, 0x12, 0x1B, 0x00, 0x20, + 0x00, 0x6B, 0x39, 0x03, 0x41, 0x00, 0x02, 0x84, 0x00, 0x00, 0x6B, 0x61, 0x64, 0x78, 0x79, 0x2B, + 0xCF, 0x8A, 0x00, 0x80, 0x1C, 0x54, 0x11, 0x98, 0x00, 0x80, 0xBB, 0xBB, 0x00, 0x57, 0x22, 0x78, + 0x64, 0x11, 0x64, 0x11, 0x8A, 0x39, 0x89, 0x39, 0x05, 0xE0, 0x0F, 0xE0, 0x64, 0x12, 0x64, 0x12, + 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0xCC, 0xF5, 0x7A, 0xFD, 0xED, 0x20, 0xBF, 0x8F, + 0xCF, 0x03, 0x04, 0x02, 0x02, 0x06, 0x00, 0x00, 0x6C, 0x76, 0x8A, 0x94, 0x00, 0x01, 0x06, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xDB, 0x06, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x40, 0x1A, 0x00, 0x20, + 0x41, 0x00, 0x38, 0x03, 0x41, 0x00, 0x02, 0x84, 0x00, 0x00, 0x00, 0x60, 0x64, 0x78, 0x79, 0x2B, + 0xCF, 0x8A, 0x00, 0x80, 0x1C, 0x54, 0x10, 0x18, 0x03, 0x80, 0xBB, 0xBB, 0x80, 0x46, 0x22, 0x78, + 0x64, 0x11, 0x64, 0x11, 0x8A, 0x39, 0x89, 0x39, 0x05, 0xE0, 0x0F, 0xE0, 0x64, 0x12, 0x64, 0x12, + 0xD0, 0x04, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0xCC, 0xF5, 0x7A, 0xFD, 0xED, 0x20, 0xBF, 0x8F, + 0xCF, 0x03, 0x04, 0x02, 0x02, 0x06, 0x00, 0x00, 0x6C, 0x76, 0x8A, 0x94, 0x00, 0x01, 0x06, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xDB, 0x06, 0x00, 0x00, 0x01, 0x46, 0x00, 0x00, 0x12, 0x1B, 0x00, 0x20, + 0x00, 0x6B, 0x39, 0x03, 0x41, 0x00, 0x02, 0x84, 0x00, 0x00, 0x6B, 0x61, 0x64, 0x78, 0x79, 0x2B, + 0xCF, 0x8A, 0x00, 0x80, 0x1C, 0x54, 0x11, 0x98, 0x03, 0x80, 0xBB, 0xBB, 0x80, 0x46, 0x22, 0x78, + 0x64, 0x11, 0x64, 0x11, 0x8A, 0x39, 0x89, 0x39, 0x05, 0xE0, 0x0F, 0xE0, 0x64, 0x12, 0x64, 0x12, + 0x01, 0x00, 0x00, 0x00, 0x03, 0x03, 0x03, 0x03, 0xCC, 0xF5, 0x7A, 0xFD, 0xED, 0x20, 0xBF, 0x8F, + 0xCF, 0x03, 0x04, 0x02, 0x02, 0x06, 0x00, 0x00, 0x6C, 0x76, 0x8A, 0x94, 0x00, 0x01, 0x06, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xDB, 0x06, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x40, 0x1A, 0x00, 0x20, + 0x41, 0x00, 0x38, 0x03, 0x41, 0x00, 0x02, 0x84, 0x00, 0x00, 0x00, 0x60, 0x64, 0x78, 0x79, 0x2B, + 0xCF, 0x8A, 0x00, 0x80, 0x1C, 0x54, 0x10, 0x18, 0x03, 0x80, 0xBB, 0xBB, 0x80, 0x46, 0x22, 0x78, + 0x64, 0x11, 0x64, 0x11, 0x8A, 0x39, 0x89, 0x39, 0x05, 0xE0, 0x0F, 0xE0, 0x64, 0x12, 0x64, 0x12, + 0xD0, 0x04, 0x02, 0x00, 0x04, 0x04, 0x04, 0x04, 0xCC, 0xF5, 0x7A, 0xFD, 0xED, 0x20, 0xBF, 0x8F, + 0xCF, 0x03, 0x04, 0x02, 0x02, 0x06, 0x00, 0x00, 0x6C, 0x76, 0x8A, 0x94, 0x00, 0x01, 0x06, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xDB, 0x06, 0x00, 0x00, 0x01, 0x46, 0x00, 0x00, 0x12, 0x1B, 0x00, 0x20, + 0x00, 0x6B, 0x39, 0x03, 0x41, 0x00, 0x02, 0x84, 0x00, 0x00, 0x6B, 0x61, 0x64, 0x78, 0x79, 0x2B, + 0xCF, 0x8A, 0x00, 0x80, 0x1C, 0x54, 0x11, 0x98, 0x03, 0x80, 0xBB, 0xBB, 0x80, 0x46, 0x22, 0x78, + 0x64, 0x11, 0x64, 0x11, 0x8A, 0x39, 0x89, 0x39, 0x05, 0xE0, 0x0F, 0xE0, 0x64, 0x12, 0x64, 0x12, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCC, 0xF5, 0x7A, 0xFD, 0xED, 0x20, 0xBF, 0x8F, + 0xCF, 0x03, 0x04, 0x02, 0x02, 0x06, 0x00, 0x00, 0x6C, 0x76, 0x8A, 0x94, 0x00, 0x01, 0x06, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xDB, 0x06, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0xFF, 0x3B, 0x00, 0x20, + 0x41, 0x00, 0x38, 0x03, 0x41, 0x00, 0x02, 0x84, 0x00, 0x00, 0x00, 0x60, 0x64, 0x78, 0x79, 0x2B, + 0xCF, 0x8A, 0x00, 0x80, 0x1C, 0xC4, 0x10, 0x18, 0x03, 0x00, 0x00, 0x00, 0x00, 0xC6, 0x22, 0x78, + 0x64, 0x11, 0x64, 0x11, 0x80, 0x39, 0x80, 0x39, 0x05, 0x00, 0x0F, 0x00, 0x55, 0x10, 0x55, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x92, 0xCD, + 0x00, 0x00, 0xC1, 0x80, 0x10, 0x0F, 0x00, 0x02, 0x00, 0x00, 0x87, 0x37, 0x00, 0x00, 0xBB, 0xF1, + 0x10, 0x0F, 0x00, 0x04, 0x00, 0x00, 0x90, 0x41, 0x00, 0x00, 0x8B, 0x43, 0x10, 0x0E, 0x00, 0x07, + 0x00, 0x00, 0xBB, 0xF1, 0x00, 0x00, 0x91, 0x67, 0x10, 0x0C, 0x00, 0x09, 0x00, 0x00, 0x1D, 0xFB, + 0x00, 0x00, 0x70, 0x9E, 0x10, 0x0E, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0xC8, 0x06, 0x00, 0x00, + 0xBA, 0xF1, 0x59, 0x42, 0xBA, 0xF1, 0x59, 0x42, 0x45, 0x0E, 0xA6, 0x3D, 0x11, 0x22, 0x33, 0x44, + 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x69, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x22, 0xC0, 0x22, 0x31, 0x30, 0x2F, 0x2E, + 0x2D, 0x2C, 0x2B, 0x2A, 0x29, 0x28, 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21, 0x20, 0x1F, 0x1E, + 0x1D, 0x1C, 0x1B, 0x1A, 0x19, 0x18, 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x0F, 0x0E, + 0x0D, 0x0C, 0x0B, 0x0A, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x4A, 0x49, 0x48, 0x47, 0x46, 0x45, 0x44, 0x43, 0x42, 0x41, 0x40, 0x3F, + 0x3E, 0x3D, 0x3C, 0x3B, 0x3A, 0x39, 0x38, 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x30, 0x2F, + 0x2E, 0x2D, 0x2C, 0x2B, 0x2A, 0x29, 0x28, 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21, 0x20, 0x1F, + 0x1E, 0x1D, 0x1C, 0x1B, 0x1A, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0xE0, 0xC0, + 0xA0, 0x80, 0x60, 0x40, 0x20, 0x00, 0xE0, 0xC0, 0xA0, 0x80, 0x60, 0x40, 0x20, 0x00, 0xE0, 0xC0, + 0xA0, 0x80, 0x60, 0x40, 0x20, 0x00, 0xE0, 0xC0, 0xA0, 0x80, 0x60, 0x40, 0x20, 0x00, 0xE0, 0xC0, + 0xA0, 0x80, 0x60, 0x40, 0x20, 0x00, 0xE0, 0xC0, 0xA0, 0x80, 0x60, 0x40, 0x20, 0x00, 0x00, 0x00, + 0x76, 0xDB, 0xB6, 0x2D, 0x24, 0x49, 0x92, 0x1B, 0xDB, 0xB6, 0x49, 0x12, 0x92, 0x94, 0x24, 0x09, + 0x09, 0x00, 0x00, 0x00, 0x20, 0x00, 0xE0, 0xC0, 0xA0, 0x80, 0x60, 0x40, 0x20, 0x00, 0xE0, 0xC0, + 0xA0, 0x80, 0x60, 0x40, 0x20, 0x00, 0xE0, 0xC0, 0xA0, 0x80, 0x60, 0x40, 0x20, 0x00, 0xE0, 0xC0, + 0xA0, 0x80, 0x60, 0x40, 0x20, 0x00, 0xE0, 0xC0, 0xA0, 0x80, 0x60, 0x40, 0x20, 0x00, 0xE0, 0xC0, + 0xA0, 0x80, 0x60, 0x40, 0x20, 0x00, 0x00, 0x00, 0x76, 0xDB, 0xB6, 0x2D, 0x24, 0x49, 0x92, 0x1B, + 0xDB, 0xB6, 0x49, 0x12, 0x92, 0x94, 0x24, 0x09, 0x09, 0x00, 0x00, 0x00, 0x20, 0x21, 0xE0, 0xE1, + 0xA0, 0xA1, 0x60, 0x61, 0x20, 0x21, 0xE0, 0xE1, 0xA0, 0xA1, 0x60, 0x61, 0x20, 0x21, 0xE0, 0xE1, + 0xA0, 0xA1, 0x60, 0x61, 0x20, 0x21, 0xE0, 0xE1, 0xA0, 0xA1, 0x60, 0x61, 0x20, 0x21, 0xE0, 0xE1, + 0xA0, 0xA1, 0x60, 0x61, 0x20, 0x21, 0xE0, 0xE1, 0xA0, 0xA1, 0x60, 0x61, 0x20, 0x21, 0x00, 0x00, + 0x76, 0xDB, 0xB6, 0x2D, 0x24, 0x49, 0x92, 0x1B, 0xDB, 0xB6, 0x49, 0x12, 0x92, 0x94, 0x24, 0x09, + 0x09, 0x00, 0x00, 0x00, 0x01, 0x00, 0xC1, 0xC0, 0x81, 0x80, 0x41, 0x40, 0x01, 0x00, 0xC1, 0xC0, + 0x81, 0x80, 0x41, 0x40, 0x01, 0x00, 0xC1, 0xC0, 0x81, 0x80, 0x41, 0x40, 0x01, 0x00, 0xC1, 0xC0, + 0x81, 0x80, 0x41, 0x40, 0x01, 0x00, 0xC1, 0xC0, 0x81, 0x80, 0x41, 0x40, 0x01, 0x00, 0xC1, 0xC0, + 0x81, 0x80, 0x41, 0x40, 0x01, 0x00, 0x00, 0x00, 0x76, 0xDB, 0xB6, 0x2D, 0x24, 0x49, 0x92, 0x1B, + 0xDB, 0xB6, 0x49, 0x12, 0x92, 0x94, 0x24, 0x09, 0x09, 0x00, 0x00, 0x00, 0x21, 0x20, 0xE1, 0xE0, + 0xA1, 0xA0, 0x61, 0x60, 0x21, 0x20, 0xE1, 0xE0, 0xA1, 0xA0, 0x61, 0x60, 0x21, 0x20, 0xE1, 0xE0, + 0xA1, 0xA0, 0x61, 0x60, 0x21, 0x20, 0xE1, 0xE0, 0xA1, 0xA0, 0x61, 0x60, 0x21, 0x20, 0xE1, 0xE0, + 0xA1, 0xA0, 0x61, 0x60, 0x21, 0x20, 0xE1, 0xE0, 0xA1, 0xA0, 0x61, 0x60, 0x21, 0x20, 0x00, 0x00, + 0x76, 0xDB, 0xB6, 0x2D, 0x24, 0x49, 0x92, 0x1B, 0xDB, 0xB6, 0x49, 0x12, 0x92, 0x94, 0x24, 0x09, + 0x09, 0x00, 0x00, 0x00, 0x73, 0x53, 0x33, 0x13, 0xF2, 0xD2, 0xB2, 0x92, 0x72, 0x52, 0x32, 0x12, + 0xF2, 0xD2, 0xB2, 0x92, 0x72, 0x52, 0x32, 0x12, 0xF2, 0xD2, 0xB2, 0x92, 0x72, 0x52, 0x32, 0x12, + 0xF2, 0xD2, 0xB2, 0x92, 0x72, 0x52, 0x32, 0x12, 0xF2, 0xD2, 0xB2, 0x92, 0x72, 0x52, 0x32, 0x12, + 0xF2, 0xD2, 0xB2, 0x92, 0x72, 0x52, 0x00, 0x00, 0x00, 0xD0, 0xB6, 0x2D, 0x2D, 0x49, 0x92, 0x24, + 0xDB, 0xB6, 0x6D, 0x12, 0x92, 0x24, 0x25, 0x09, 0x49, 0x02, 0x00, 0x00, 0x3C, 0x1C, 0xFC, 0xDC, + 0xBC, 0x9C, 0x7C, 0x5C, 0x3C, 0x1C, 0xFC, 0xDC, 0xBC, 0x9C, 0x7C, 0x5C, 0x3C, 0x1C, 0xFC, 0xDC, + 0xBC, 0x9C, 0x7C, 0x5C, 0x3C, 0x1C, 0xFC, 0xDC, 0xBC, 0x9C, 0x7C, 0x5C, 0x3C, 0x1C, 0xFC, 0xDC, + 0xBC, 0x9C, 0x7C, 0x5C, 0x3C, 0x1C, 0xFB, 0xDB, 0xBB, 0x9B, 0x7B, 0x5B, 0x3B, 0x1B, 0x00, 0x00, + 0x2D, 0x49, 0x92, 0x24, 0xDB, 0xB6, 0x6D, 0x12, 0x92, 0x24, 0x25, 0x09, 0x49, 0x02, 0x00, 0x00, + 0x40, 0xDB, 0xB6, 0x2D, 0xB4, 0x94, 0x74, 0x54, 0x34, 0x14, 0xF3, 0xD3, 0xB3, 0x93, 0x73, 0x53, + 0x33, 0x13, 0xF3, 0xD3, 0xB3, 0x93, 0x73, 0x53, 0x33, 0x13, 0xF3, 0xD3, 0xB3, 0x93, 0x73, 0x53, + 0x33, 0x13, 0xF3, 0xD3, 0xB3, 0x93, 0x73, 0x53, 0x33, 0x13, 0xF3, 0xD3, 0xB3, 0x93, 0x73, 0x53, + 0x33, 0x13, 0xF3, 0xD3, 0xB3, 0x93, 0x00, 0x00, 0x00, 0x00, 0xB4, 0x2D, 0x6D, 0x4B, 0x92, 0x24, + 0xE4, 0xB6, 0x6D, 0x1B, 0x92, 0x24, 0x49, 0x09, 0x49, 0x92, 0x00, 0x00, 0xFB, 0xDB, 0xBB, 0x9B, + 0x7B, 0x5B, 0x3B, 0x1B, 0xFB, 0xDB, 0xBB, 0x9B, 0x7B, 0x5B, 0x3B, 0x1B, 0xFB, 0xDB, 0xBB, 0x9B, + 0x7B, 0x5B, 0x3B, 0x1B, 0xFB, 0xDB, 0xBB, 0x9B, 0x7B, 0x5B, 0x3B, 0x1B, 0xFB, 0xDB, 0xBB, 0x9B, + 0x7B, 0x5B, 0x3B, 0x1B, 0xFA, 0xDA, 0xBA, 0x9A, 0x7A, 0x5A, 0x3A, 0x1A, 0xFA, 0xDA, 0x00, 0x00, + 0x24, 0x49, 0x92, 0x1B, 0xDB, 0xB6, 0x49, 0x12, 0x92, 0x94, 0x24, 0x09, 0x09, 0x00, 0x00, 0x00, + 0x6D, 0xDB, 0xB6, 0x24, 0xF5, 0xD5, 0xB5, 0x95, 0x75, 0x55, 0x35, 0x15, 0xF4, 0xD4, 0xB4, 0x94, + 0x74, 0x54, 0x34, 0x14, 0xF4, 0xD4, 0xB4, 0x94, 0x74, 0x54, 0x34, 0x14, 0xF4, 0xD4, 0xB4, 0x94, + 0x74, 0x54, 0x34, 0x14, 0xF4, 0xD4, 0xB4, 0x94, 0x74, 0x54, 0x34, 0x14, 0xF4, 0xD4, 0xB4, 0x94, + 0x74, 0x54, 0x34, 0x14, 0xF4, 0xD4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2D, 0x6D, 0xDB, 0x92, 0x24, + 0x24, 0xB9, 0x6D, 0x1B, 0x9B, 0x24, 0x49, 0x12, 0x49, 0x92, 0x24, 0x00, 0xBA, 0x9A, 0x7A, 0x5A, + 0x3A, 0x1A, 0xFA, 0xDA, 0xBA, 0x9A, 0x7A, 0x5A, 0x3A, 0x1A, 0xFA, 0xDA, 0xBA, 0x9A, 0x7A, 0x5A, + 0x3A, 0x1A, 0xFA, 0xDA, 0xBA, 0x9A, 0x7A, 0x5A, 0x3A, 0x1A, 0xFA, 0xDA, 0xBA, 0x9A, 0x7A, 0x5A, + 0x3A, 0x1A, 0xF9, 0xD9, 0xB9, 0x99, 0x79, 0x59, 0x39, 0x19, 0xF9, 0xD9, 0xB9, 0x99, 0x00, 0x00, + 0x24, 0x49, 0x6E, 0x1B, 0xDB, 0x26, 0x49, 0x12, 0x52, 0x92, 0x24, 0x09, 0x00, 0x00, 0x00, 0x2D, + 0x6D, 0xDB, 0x92, 0x24, 0x36, 0x16, 0xF6, 0xD6, 0xB6, 0x96, 0x76, 0x56, 0x36, 0x16, 0xF5, 0xD5, + 0xB5, 0x95, 0x75, 0x55, 0x35, 0x15, 0xF5, 0xD5, 0xB5, 0x95, 0x75, 0x55, 0x35, 0x15, 0xF5, 0xD5, + 0xB5, 0x95, 0x75, 0x55, 0x35, 0x15, 0xF5, 0xD5, 0xB5, 0x95, 0x75, 0x55, 0x35, 0x15, 0xF5, 0xD5, + 0xB5, 0x95, 0x75, 0x55, 0x35, 0x15, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x6D, 0xDB, 0xB6, 0x24, + 0x24, 0x49, 0x6E, 0x1B, 0xDB, 0x26, 0x49, 0x12, 0x52, 0x92, 0x24, 0x09, 0x79, 0x59, 0x39, 0x19, + 0xF9, 0xD9, 0xB9, 0x99, 0x79, 0x59, 0x39, 0x19, 0xF9, 0xD9, 0xB9, 0x99, 0x79, 0x59, 0x39, 0x19, + 0xF9, 0xD9, 0xB9, 0x99, 0x79, 0x59, 0x39, 0x19, 0xF9, 0xD9, 0xB9, 0x99, 0x79, 0x59, 0x39, 0x19, + 0xF8, 0xD8, 0xB8, 0x98, 0x78, 0x58, 0x38, 0x18, 0xF8, 0xD8, 0xB8, 0x98, 0x78, 0x58, 0x00, 0x00, + 0x24, 0xB9, 0x6D, 0x1B, 0x9B, 0x24, 0x49, 0x12, 0x49, 0x92, 0x24, 0x00, 0x00, 0x00, 0xB4, 0x2D, + 0x6D, 0x4B, 0x92, 0x24, 0x77, 0x57, 0x37, 0x17, 0xF7, 0xD7, 0xB7, 0x97, 0x77, 0x57, 0x37, 0x17, + 0xF6, 0xD6, 0xB6, 0x96, 0x76, 0x56, 0x36, 0x16, 0xF6, 0xD6, 0xB6, 0x96, 0x76, 0x56, 0x36, 0x16, + 0xF6, 0xD6, 0xB6, 0x96, 0x76, 0x56, 0x36, 0x16, 0xF6, 0xD6, 0xB6, 0x96, 0x76, 0x56, 0x36, 0x16, + 0xF6, 0xD6, 0xB6, 0x96, 0x76, 0x56, 0x00, 0x00, 0x49, 0x02, 0x00, 0x00, 0x40, 0xDB, 0xB6, 0x2D, + 0x24, 0x49, 0x92, 0x1B, 0xDB, 0xB6, 0x49, 0x12, 0x92, 0x94, 0x24, 0x09, 0x38, 0x18, 0xF8, 0xD8, + 0xB8, 0x98, 0x78, 0x58, 0x38, 0x18, 0xF8, 0xD8, 0xB8, 0x98, 0x78, 0x58, 0x38, 0x18, 0xF8, 0xD8, + 0xB8, 0x98, 0x78, 0x58, 0x38, 0x18, 0xF8, 0xD8, 0xB8, 0x98, 0x78, 0x58, 0x38, 0x18, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, + 0xE4, 0xB6, 0x6D, 0x1B, 0x92, 0x24, 0x49, 0x09, 0x49, 0x92, 0x00, 0x00, 0x00, 0xF0, 0xFF, 0x3F, + 0xFF, 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xF7, 0xD7, 0xB7, 0x97, 0x77, 0x57, 0x37, 0x17, 0xF7, 0xD7, 0xB7, 0x97, 0x77, 0x57, + 0x37, 0x17, 0xF7, 0xD7, 0xB7, 0x97, 0x77, 0x57, 0x37, 0x17, 0xF7, 0xD7, 0xB7, 0x97, 0x77, 0x57, + 0x37, 0x17, 0xF7, 0xD7, 0xB7, 0x97, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x3F, 0xFF, 0xDF, 0xB6, 0x2D, + 0x2D, 0x49, 0x92, 0x24, 0xDB, 0xB6, 0x6D, 0x12, 0x92, 0x24, 0x25, 0x09, 0x63, 0x62, 0x61, 0x60, + 0x5F, 0x5E, 0x5D, 0x5C, 0x5B, 0x5A, 0x59, 0x58, 0x57, 0x56, 0x55, 0x54, 0x53, 0x52, 0x51, 0x50, + 0x4F, 0x4E, 0x4D, 0x4C, 0x4B, 0x4A, 0x49, 0x48, 0x47, 0x46, 0x45, 0x44, 0x43, 0x42, 0x41, 0x40, + 0x3F, 0x3E, 0x3D, 0x3C, 0x3B, 0x3A, 0x39, 0x38, 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x31, 0x30, 0x2F, 0x2E, 0x2D, 0x2C, 0x2B, 0x2A, 0x29, 0x28, 0x27, 0x26, + 0x25, 0x24, 0x23, 0x22, 0x21, 0x20, 0x1F, 0x1E, 0x1D, 0x1C, 0x1B, 0x1A, 0x19, 0x18, 0x17, 0x16, + 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x0F, 0x0E, 0x0D, 0x0C, 0x0B, 0x0A, 0x09, 0x08, 0x07, 0x06, + 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC8, 0x22, 0x08, 0x11, 0xE8, 0x22, 0x10, 0x0C, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xC0, 0x0B, 0xBC, 0x0D, 0xEE, 0x0B, 0x00, 0x00, 0x40, 0x0B, 0xBC, 0x0F, 0xEC, 0x0B, 0x04, 0x00, + 0xC0, 0x2A, 0xBC, 0x0F, 0xEA, 0x0B, 0x0C, 0x00, 0x40, 0x4A, 0xBC, 0x0F, 0xE8, 0x0B, 0x14, 0x00, + 0xC0, 0x69, 0xBC, 0x0F, 0xE6, 0x0B, 0x1C, 0x00, 0x40, 0x89, 0xBC, 0x0F, 0xE4, 0x0B, 0x24, 0x00, + 0xC0, 0xA8, 0xBC, 0x0F, 0xE2, 0x0B, 0x2C, 0x00, 0x40, 0xC8, 0xBC, 0x0C, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, + 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, + 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x06, 0xF0, 0xF1, 0x55, 0x06, 0xF0, 0xF1, 0x55, 0x06, 0xF0, 0xF1, 0x55, 0x06, 0xF0, 0xF1, 0x55, + 0x1A, 0x1A, 0x1A, 0x1B, 0x1B, 0x19, 0x19, 0x19, 0x1A, 0x19, 0x1A, 0x19, 0x1A, 0x19, 0x19, 0x19, + 0x19, 0x19, 0x19, 0x19, 0x19, 0x1A, 0x1A, 0x19, 0x1A, 0x1A, 0x1A, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, + 0x1A, 0x1A, 0x1A, 0x1A, 0x1B, 0x19, 0x19, 0x19, 0x1A, 0x19, 0x19, 0x19, 0x19, 0x19, 0x1A, 0x19, + 0x19, 0x19, 0x19, 0x19, 0x19, 0x1B, 0x1A, 0x1A, 0x1A, 0x1A, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1C, + 0x1A, 0x1A, 0x1A, 0x1A, 0x1B, 0x19, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x19, 0x1A, 0x19, 0x1A, 0x19, + 0x19, 0x19, 0x19, 0x1A, 0x19, 0x1B, 0x1B, 0x1A, 0x19, 0x19, 0x1B, 0x1C, 0x1B, 0x1B, 0x1C, 0x1C, + 0x1A, 0x1A, 0x1A, 0x1A, 0x1B, 0x19, 0x1A, 0x1A, 0x1A, 0x1A, 0x19, 0x19, 0x1B, 0x1A, 0x1A, 0x1A, + 0x19, 0x19, 0x19, 0x1A, 0x19, 0x1B, 0x1B, 0x19, 0x19, 0x19, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1C, + 0x1A, 0x19, 0x1A, 0x1A, 0x1B, 0x1A, 0x19, 0x1A, 0x19, 0x19, 0x19, 0x19, 0x1A, 0x19, 0x19, 0x19, + 0x19, 0x19, 0x19, 0x19, 0x19, 0x1A, 0x1A, 0x19, 0x19, 0x1A, 0x1B, 0x1B, 0x1B, 0x1B, 0x1C, 0x1C, + 0x19, 0x19, 0x1A, 0x1A, 0x1A, 0x1A, 0x19, 0x1A, 0x1B, 0x19, 0x1A, 0x19, 0x19, 0x18, 0x19, 0x1A, + 0x18, 0x18, 0x18, 0x19, 0x18, 0x19, 0x19, 0x19, 0x1B, 0x1A, 0x1A, 0x1A, 0x1B, 0x1B, 0x1B, 0x1B, + 0x19, 0x19, 0x19, 0x19, 0x19, 0x18, 0x19, 0x18, 0x19, 0x18, 0x1A, 0x18, 0x18, 0x18, 0x18, 0x19, + 0x19, 0x17, 0x18, 0x18, 0x19, 0x1A, 0x19, 0x19, 0x1A, 0x19, 0x19, 0x1A, 0x19, 0x1A, 0x1A, 0x1A, + 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x18, 0x19, 0x19, 0x18, 0x1A, 0x19, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x19, 0x19, 0x19, 0x1A, 0x19, 0x19, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, + 0x18, 0x18, 0x18, 0x18, 0x19, 0x19, 0x18, 0x19, 0x19, 0x19, 0x18, 0x19, 0x19, 0x18, 0x18, 0x19, + 0x19, 0x18, 0x18, 0x1A, 0x18, 0x1A, 0x19, 0x18, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1B, + 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x18, 0x19, 0x19, 0x19, 0x19, 0x1A, 0x19, 0x19, 0x19, 0x19, + 0x18, 0x18, 0x19, 0x19, 0x19, 0x1A, 0x1A, 0x18, 0x1A, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x18, + 0x18, 0x19, 0x19, 0x19, 0x19, 0x19, 0x18, 0x19, 0x19, 0x19, 0x19, 0x19, 0x18, 0x18, 0x18, 0x19, + 0x19, 0x19, 0x19, 0x19, 0x19, 0x1A, 0x1A, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, + 0x18, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x18, 0x18, 0x19, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x17, 0x17, 0x18, 0x17, 0x19, 0x18, 0x17, 0x17, 0x18, 0x19, 0x18, 0x19, 0x19, 0x19, 0x18, 0x19, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x19, 0x18, 0x17, 0x18, 0x17, 0x18, 0x19, 0x18, 0x18, 0x19, 0x19, + 0x18, 0x17, 0x17, 0x18, 0x19, 0x19, 0x17, 0x19, 0x19, 0x19, 0x19, 0x19, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x17, 0x17, 0x18, 0x18, 0x19, 0x18, 0x17, 0x18, 0x17, 0x18, 0x18, 0x18, 0x18, 0x17, 0x18, + 0x18, 0x17, 0x17, 0x18, 0x17, 0x18, 0x18, 0x18, 0x19, 0x19, 0x19, 0x18, 0x18, 0x18, 0x18, 0x19, + 0x17, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x17, 0x19, 0x18, 0x17, 0x18, 0x19, 0x18, + 0x18, 0x18, 0x17, 0x18, 0x18, 0x18, 0x18, 0x19, 0x18, 0x18, 0x19, 0x18, 0x18, 0x18, 0x18, 0x19, + 0x17, 0x17, 0x17, 0x17, 0x18, 0x18, 0x17, 0x17, 0x18, 0x17, 0x18, 0x18, 0x17, 0x18, 0x17, 0x17, + 0x18, 0x18, 0x17, 0x18, 0x18, 0x17, 0x17, 0x18, 0x18, 0x18, 0x1A, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x17, 0x17, 0x17, 0x18, 0x18, 0x17, 0x17, 0x18, 0x19, 0x18, 0x18, 0x17, 0x18, 0x18, 0x17, + 0x17, 0x16, 0x17, 0x17, 0x18, 0x18, 0x17, 0x17, 0x18, 0x19, 0x1A, 0x19, 0x19, 0x19, 0x19, 0x19, + 0x17, 0x17, 0x17, 0x17, 0x18, 0x18, 0x18, 0x17, 0x18, 0x18, 0x18, 0x18, 0x17, 0x17, 0x17, 0x17, + 0x18, 0x18, 0x18, 0x18, 0x17, 0x18, 0x17, 0x18, 0x19, 0x18, 0x19, 0x18, 0x18, 0x18, 0x18, 0x19, + 0x17, 0x17, 0x17, 0x17, 0x17, 0x18, 0x17, 0x17, 0x18, 0x17, 0x18, 0x18, 0x18, 0x17, 0x17, 0x17, + 0x17, 0x17, 0x17, 0x17, 0x16, 0x16, 0x17, 0x17, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x17, 0x17, 0x17, 0x17, 0x17, 0x18, 0x18, 0x17, 0x19, 0x17, 0x18, 0x18, 0x17, 0x17, 0x18, 0x17, + 0x17, 0x17, 0x17, 0x16, 0x17, 0x17, 0x16, 0x16, 0x18, 0x18, 0x19, 0x17, 0x17, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x17, 0x17, 0x18, 0x17, 0x17, 0x18, 0x18, 0x17, 0x18, 0x18, + 0x18, 0x17, 0x17, 0x18, 0x17, 0x17, 0x17, 0x18, 0x17, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x17, 0x17, 0x17, 0x18, 0x18, 0x19, 0x16, 0x17, 0x17, 0x18, 0x16, 0x17, 0x17, 0x16, 0x17, 0x17, + 0x17, 0x16, 0x16, 0x16, 0x16, 0x17, 0x16, 0x16, 0x18, 0x17, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x17, 0x17, 0x17, 0x17, 0x18, 0x18, 0x16, 0x17, 0x18, 0x17, 0x18, 0x17, 0x17, 0x18, 0x17, 0x17, + 0x17, 0x17, 0x16, 0x16, 0x16, 0x17, 0x17, 0x16, 0x17, 0x18, 0x18, 0x17, 0x18, 0x18, 0x17, 0x18, + 0x17, 0x17, 0x17, 0x17, 0x17, 0x18, 0x17, 0x16, 0x17, 0x16, 0x18, 0x17, 0x17, 0x18, 0x17, 0x18, + 0x16, 0x17, 0x17, 0x17, 0x16, 0x17, 0x17, 0x17, 0x17, 0x17, 0x18, 0x18, 0x17, 0x18, 0x18, 0x18, + 0x16, 0x16, 0x16, 0x16, 0x16, 0x17, 0x15, 0x15, 0x18, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, + 0x17, 0x16, 0x16, 0x15, 0x16, 0x16, 0x16, 0x16, 0x17, 0x16, 0x17, 0x18, 0x17, 0x17, 0x17, 0x18, + 0x17, 0x17, 0x17, 0x17, 0x17, 0x18, 0x16, 0x17, 0x17, 0x17, 0x17, 0x16, 0x17, 0x18, 0x17, 0x17, + 0x17, 0x17, 0x16, 0x17, 0x16, 0x15, 0x16, 0x16, 0x17, 0x17, 0x18, 0x17, 0x17, 0x17, 0x18, 0x18, + 0x17, 0x16, 0x17, 0x17, 0x17, 0x18, 0x15, 0x16, 0x17, 0x17, 0x17, 0x17, 0x16, 0x16, 0x17, 0x17, + 0x16, 0x16, 0x16, 0x16, 0x16, 0x15, 0x16, 0x16, 0x17, 0x17, 0x16, 0x17, 0x17, 0x17, 0x18, 0x18, + 0x16, 0x16, 0x16, 0x16, 0x16, 0x17, 0x16, 0x16, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, + 0x17, 0x16, 0x15, 0x16, 0x16, 0x16, 0x16, 0x16, 0x17, 0x17, 0x17, 0x17, 0x16, 0x16, 0x16, 0x17, + 0x16, 0x16, 0x16, 0x17, 0x17, 0x16, 0x16, 0x15, 0x17, 0x16, 0x17, 0x17, 0x17, 0x17, 0x16, 0x16, + 0x17, 0x16, 0x16, 0x15, 0x16, 0x16, 0x16, 0x16, 0x17, 0x17, 0x17, 0x18, 0x17, 0x17, 0x17, 0x18, + 0x16, 0x16, 0x16, 0x16, 0x17, 0x17, 0x16, 0x15, 0x18, 0x16, 0x17, 0x17, 0x16, 0x17, 0x17, 0x17, + 0x17, 0x16, 0x16, 0x15, 0x16, 0x15, 0x16, 0x16, 0x17, 0x16, 0x16, 0x18, 0x17, 0x17, 0x17, 0x18, + 0x17, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x15, 0x16, 0x16, + 0x16, 0x16, 0x15, 0x15, 0x16, 0x17, 0x17, 0x16, 0x16, 0x16, 0x16, 0x17, 0x16, 0x16, 0x17, 0x17, + 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x14, 0x15, 0x17, 0x16, 0x16, 0x16, 0x17, 0x17, 0x16, 0x17, + 0x16, 0x16, 0x15, 0x15, 0x16, 0x15, 0x16, 0x16, 0x16, 0x16, 0x16, 0x17, 0x17, 0x17, 0x17, 0x17, + 0x16, 0x16, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x16, 0x15, 0x16, 0x16, 0x16, 0x16, 0x15, 0x17, + 0x16, 0x16, 0x15, 0x16, 0x17, 0x15, 0x15, 0x16, 0x17, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x17, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x16, 0x16, 0x15, 0x16, 0x15, 0x17, 0x16, 0x16, 0x16, 0x15, 0x16, + 0x15, 0x16, 0x15, 0x15, 0x15, 0x15, 0x15, 0x14, 0x15, 0x15, 0x15, 0x16, 0x16, 0x16, 0x16, 0x16, + 0x16, 0x16, 0x15, 0x15, 0x15, 0x16, 0x15, 0x15, 0x17, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, + 0x16, 0x16, 0x15, 0x15, 0x16, 0x16, 0x16, 0x16, 0x17, 0x16, 0x15, 0x17, 0x17, 0x16, 0x17, 0x17, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x16, 0x15, 0x14, 0x16, 0x15, 0x16, 0x14, 0x16, 0x15, 0x15, 0x16, + 0x16, 0x15, 0x14, 0x14, 0x15, 0x15, 0x15, 0x15, 0x16, 0x15, 0x16, 0x17, 0x16, 0x16, 0x16, 0x16, + 0x15, 0x15, 0x15, 0x14, 0x14, 0x16, 0x15, 0x14, 0x16, 0x15, 0x15, 0x16, 0x15, 0x15, 0x15, 0x16, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x14, 0x14, 0x15, 0x15, 0x15, 0x15, 0x16, 0x15, 0x15, 0x16, 0x16, + 0x15, 0x15, 0x15, 0x14, 0x14, 0x15, 0x14, 0x14, 0x16, 0x15, 0x16, 0x15, 0x15, 0x16, 0x15, 0x15, + 0x14, 0x13, 0x14, 0x14, 0x15, 0x14, 0x14, 0x14, 0x16, 0x15, 0x15, 0x16, 0x16, 0x16, 0x16, 0x17, + 0x15, 0x15, 0x14, 0x15, 0x15, 0x15, 0x14, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x15, 0x14, 0x15, 0x14, 0x14, 0x14, 0x14, 0x14, 0x15, 0x14, 0x14, 0x16, 0x16, 0x16, 0x16, 0x16, + 0x15, 0x15, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x15, 0x15, 0x15, 0x15, 0x14, 0x15, 0x14, 0x16, + 0x15, 0x15, 0x14, 0x14, 0x16, 0x13, 0x14, 0x14, 0x15, 0x14, 0x15, 0x15, 0x15, 0x16, 0x15, 0x16, + 0x15, 0x15, 0x14, 0x15, 0x15, 0x14, 0x15, 0x14, 0x15, 0x14, 0x15, 0x14, 0x14, 0x16, 0x15, 0x15, + 0x14, 0x14, 0x15, 0x14, 0x14, 0x14, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x16, 0x16, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x14, 0x15, 0x15, 0x15, 0x15, 0x15, 0x14, 0x15, 0x15, + 0x14, 0x13, 0x13, 0x13, 0x13, 0x13, 0x14, 0x14, 0x14, 0x14, 0x14, 0x15, 0x15, 0x15, 0x15, 0x16, + 0x15, 0x15, 0x15, 0x14, 0x15, 0x15, 0x14, 0x14, 0x15, 0x15, 0x15, 0x15, 0x14, 0x15, 0x15, 0x16, + 0x15, 0x15, 0x14, 0x14, 0x14, 0x14, 0x15, 0x14, 0x15, 0x14, 0x15, 0x16, 0x16, 0x16, 0x16, 0x16, + 0x15, 0x14, 0x14, 0x14, 0x15, 0x15, 0x15, 0x14, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x14, 0x15, + 0x15, 0x15, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x15, 0x15, 0x15, 0x14, 0x15, 0x15, 0x15, 0x16, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x14, 0x15, 0x14, 0x14, 0x15, 0x15, 0x14, 0x14, 0x15, 0x14, 0x15, + 0x15, 0x14, 0x13, 0x13, 0x14, 0x13, 0x14, 0x14, 0x16, 0x15, 0x14, 0x15, 0x14, 0x15, 0x15, 0x16, + 0x15, 0x15, 0x14, 0x14, 0x15, 0x14, 0x15, 0x14, 0x15, 0x15, 0x15, 0x15, 0x15, 0x16, 0x15, 0x15, + 0x16, 0x15, 0x15, 0x15, 0x14, 0x14, 0x15, 0x14, 0x15, 0x15, 0x15, 0x15, 0x16, 0x15, 0x16, 0x16, + 0x14, 0x15, 0x14, 0x14, 0x15, 0x14, 0x14, 0x14, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x16, 0x18, + 0x18, 0x17, 0x14, 0x14, 0x15, 0x14, 0x14, 0x14, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x16, 0x15, + 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x13, 0x14, 0x14, 0x15, 0x15, 0x17, 0x17, 0x17, 0x17, + 0x17, 0x17, 0x14, 0x14, 0x14, 0x15, 0x14, 0x14, 0x15, 0x14, 0x15, 0x15, 0x15, 0x15, 0x16, 0x16, + 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x13, 0x14, 0x14, 0x14, 0x14, 0x16, 0x16, 0x16, 0x16, + 0x16, 0x16, 0x14, 0x14, 0x14, 0x15, 0x14, 0x14, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x13, 0x14, 0x14, 0x14, 0x14, 0x16, 0x16, 0x16, 0x15, + 0x15, 0x15, 0x13, 0x14, 0x14, 0x14, 0x13, 0x13, 0x14, 0x14, 0x14, 0x14, 0x14, 0x15, 0x15, 0x15, + 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x19, 0x1A, 0x1A, + 0x1A, 0x1A, 0x1A, 0x1A, 0x19, 0x1B, 0x1A, 0x1A, 0x1A, 0x1A, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, + 0x1B, 0x1B, 0x1A, 0x1A, 0x1B, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1B, 0x1A, + 0x1A, 0x1A, 0x1A, 0x19, 0x19, 0x1C, 0x1B, 0x1A, 0x1A, 0x1A, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, + 0x1B, 0x1B, 0x1B, 0x1B, 0x1C, 0x1A, 0x1A, 0x1B, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1B, 0x1A, 0x1A, + 0x1A, 0x1A, 0x1A, 0x1A, 0x19, 0x1C, 0x1B, 0x1A, 0x19, 0x1A, 0x1C, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, + 0x1B, 0x1B, 0x1B, 0x1B, 0x1C, 0x1A, 0x1B, 0x1A, 0x1A, 0x1A, 0x1A, 0x1B, 0x1A, 0x1B, 0x1A, 0x1A, + 0x19, 0x1A, 0x1A, 0x19, 0x19, 0x1B, 0x1B, 0x1A, 0x19, 0x1A, 0x1B, 0x1A, 0x1B, 0x1B, 0x1B, 0x1B, + 0x1B, 0x1A, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1B, 0x1A, 0x1A, + 0x19, 0x1A, 0x1A, 0x19, 0x19, 0x1A, 0x1A, 0x19, 0x19, 0x19, 0x1C, 0x1B, 0x1B, 0x1B, 0x1B, 0x1C, + 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1C, 0x1B, 0x1B, 0x1C, 0x19, 0x1B, 0x1A, 0x1B, 0x1A, 0x19, 0x1B, + 0x1A, 0x1C, 0x1A, 0x1B, 0x1B, 0x1B, 0x1A, 0x1A, 0x1B, 0x1B, 0x1B, 0x1A, 0x1B, 0x1B, 0x1B, 0x1A, + 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x19, 0x1A, 0x1A, 0x19, 0x1A, 0x1A, 0x1A, 0x1A, 0x19, 0x1A, + 0x19, 0x1B, 0x19, 0x1A, 0x1A, 0x1B, 0x19, 0x1A, 0x1B, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, + 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x19, 0x19, 0x1A, 0x19, 0x1A, 0x1A, 0x1A, 0x19, 0x19, 0x19, + 0x19, 0x19, 0x1A, 0x19, 0x19, 0x1A, 0x19, 0x1A, 0x1A, 0x1B, 0x1B, 0x1A, 0x1A, 0x1A, 0x1A, 0x1B, + 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x1A, 0x1A, 0x1A, 0x1A, 0x19, 0x19, 0x1A, + 0x1A, 0x1A, 0x19, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1B, 0x1A, 0x1B, 0x19, 0x19, 0x19, 0x19, 0x1A, + 0x19, 0x19, 0x19, 0x1A, 0x1A, 0x19, 0x1A, 0x19, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, + 0x19, 0x1A, 0x19, 0x1A, 0x1A, 0x1A, 0x19, 0x19, 0x1B, 0x1A, 0x1B, 0x19, 0x19, 0x19, 0x19, 0x19, + 0x19, 0x19, 0x19, 0x19, 0x1A, 0x1A, 0x1A, 0x1A, 0x19, 0x19, 0x1B, 0x19, 0x1A, 0x1A, 0x19, 0x1A, + 0x19, 0x1A, 0x19, 0x1A, 0x1A, 0x1B, 0x19, 0x1A, 0x1A, 0x19, 0x1A, 0x19, 0x19, 0x19, 0x19, 0x19, + 0x19, 0x19, 0x19, 0x19, 0x1A, 0x1B, 0x19, 0x19, 0x18, 0x1A, 0x1A, 0x19, 0x19, 0x19, 0x1A, 0x1A, + 0x18, 0x18, 0x19, 0x1A, 0x1B, 0x19, 0x19, 0x19, 0x19, 0x1A, 0x1A, 0x19, 0x19, 0x19, 0x19, 0x19, + 0x19, 0x19, 0x18, 0x19, 0x19, 0x1A, 0x19, 0x18, 0x19, 0x19, 0x19, 0x1A, 0x19, 0x19, 0x19, 0x1A, + 0x1A, 0x18, 0x1A, 0x19, 0x1A, 0x1A, 0x19, 0x19, 0x1A, 0x1A, 0x19, 0x19, 0x18, 0x18, 0x18, 0x19, + 0x18, 0x18, 0x18, 0x18, 0x19, 0x1A, 0x19, 0x17, 0x19, 0x18, 0x19, 0x19, 0x19, 0x1A, 0x19, 0x1A, + 0x19, 0x19, 0x19, 0x19, 0x18, 0x1A, 0x19, 0x19, 0x1A, 0x1A, 0x1A, 0x19, 0x18, 0x18, 0x18, 0x19, + 0x18, 0x19, 0x18, 0x18, 0x18, 0x1A, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x18, 0x19, 0x1A, 0x1A, + 0x19, 0x19, 0x19, 0x1A, 0x1A, 0x18, 0x19, 0x1A, 0x19, 0x1A, 0x1B, 0x19, 0x19, 0x19, 0x19, 0x19, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x1A, 0x19, 0x18, 0x18, 0x18, 0x18, 0x19, 0x18, 0x18, 0x19, 0x19, + 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x1A, 0x18, 0x18, 0x19, 0x19, 0x19, + 0x19, 0x18, 0x18, 0x18, 0x18, 0x1A, 0x18, 0x18, 0x19, 0x1A, 0x1A, 0x19, 0x18, 0x19, 0x19, 0x19, + 0x18, 0x17, 0x18, 0x18, 0x19, 0x18, 0x18, 0x18, 0x19, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x19, 0x19, 0x19, 0x18, 0x19, 0x18, 0x18, 0x18, 0x19, 0x19, 0x18, + 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x1A, 0x1A, 0x19, 0x1A, 0x19, 0x19, 0x19, 0x19, 0x19, + 0x18, 0x18, 0x17, 0x17, 0x18, 0x18, 0x18, 0x17, 0x18, 0x18, 0x19, 0x19, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x17, 0x17, 0x18, 0x18, 0x18, 0x19, 0x19, 0x18, 0x19, 0x1A, 0x19, 0x19, 0x18, 0x18, 0x19, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x1A, 0x19, 0x18, 0x19, 0x19, 0x19, 0x19, 0x18, 0x19, 0x19, 0x19, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x19, 0x18, 0x19, 0x19, 0x19, 0x18, 0x18, 0x18, 0x19, 0x19, + 0x19, 0x18, 0x18, 0x18, 0x19, 0x19, 0x19, 0x17, 0x18, 0x19, 0x18, 0x19, 0x18, 0x19, 0x1A, 0x19, + 0x19, 0x18, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x1A, 0x18, 0x18, 0x19, 0x18, 0x19, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x1A, 0x18, 0x18, 0x18, 0x1A, 0x19, 0x19, 0x18, 0x17, 0x18, 0x18, + 0x18, 0x18, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x18, 0x18, 0x1A, 0x19, 0x19, 0x19, 0x19, 0x19, + 0x18, 0x17, 0x18, 0x18, 0x18, 0x18, 0x17, 0x18, 0x19, 0x19, 0x18, 0x18, 0x18, 0x19, 0x18, 0x19, + 0x19, 0x18, 0x17, 0x17, 0x17, 0x18, 0x18, 0x18, 0x18, 0x19, 0x1A, 0x17, 0x18, 0x18, 0x18, 0x19, + 0x18, 0x17, 0x17, 0x17, 0x18, 0x19, 0x18, 0x17, 0x19, 0x19, 0x19, 0x1A, 0x18, 0x19, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x17, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x19, 0x18, 0x18, 0x18, 0x19, 0x19, + 0x17, 0x17, 0x17, 0x17, 0x17, 0x19, 0x17, 0x16, 0x19, 0x18, 0x19, 0x19, 0x18, 0x19, 0x19, 0x18, + 0x18, 0x18, 0x17, 0x16, 0x17, 0x17, 0x18, 0x18, 0x17, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x19, + 0x18, 0x18, 0x17, 0x17, 0x18, 0x18, 0x17, 0x18, 0x17, 0x19, 0x19, 0x17, 0x18, 0x18, 0x19, 0x19, + 0x18, 0x18, 0x18, 0x18, 0x17, 0x17, 0x17, 0x18, 0x18, 0x18, 0x18, 0x17, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x17, 0x17, 0x18, 0x19, 0x19, 0x17, 0x18, 0x17, 0x18, 0x18, + 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x18, 0x17, 0x18, 0x18, 0x18, 0x18, 0x19, 0x19, + 0x18, 0x17, 0x18, 0x17, 0x17, 0x18, 0x17, 0x17, 0x18, 0x18, 0x19, 0x17, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x18, 0x17, 0x17, 0x17, 0x17, 0x17, 0x18, + 0x18, 0x17, 0x17, 0x18, 0x18, 0x18, 0x17, 0x17, 0x19, 0x18, 0x1A, 0x18, 0x19, 0x18, 0x18, 0x17, + 0x18, 0x18, 0x17, 0x17, 0x17, 0x17, 0x18, 0x17, 0x18, 0x18, 0x17, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x17, 0x17, 0x17, 0x17, 0x18, 0x18, 0x16, 0x17, 0x19, 0x17, 0x19, 0x18, 0x18, 0x18, 0x19, 0x17, + 0x18, 0x17, 0x18, 0x17, 0x17, 0x16, 0x18, 0x16, 0x19, 0x18, 0x17, 0x18, 0x17, 0x18, 0x18, 0x18, + 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x16, 0x17, 0x18, 0x18, 0x17, 0x17, 0x16, 0x18, 0x17, + 0x17, 0x17, 0x16, 0x17, 0x17, 0x18, 0x17, 0x16, 0x18, 0x18, 0x17, 0x17, 0x17, 0x17, 0x17, 0x18, + 0x17, 0x17, 0x17, 0x17, 0x17, 0x18, 0x15, 0x18, 0x18, 0x18, 0x18, 0x16, 0x18, 0x17, 0x18, 0x17, + 0x17, 0x16, 0x16, 0x16, 0x17, 0x16, 0x17, 0x17, 0x17, 0x18, 0x17, 0x18, 0x18, 0x17, 0x18, 0x18, + 0x17, 0x17, 0x17, 0x16, 0x17, 0x17, 0x16, 0x17, 0x18, 0x17, 0x19, 0x17, 0x17, 0x17, 0x18, 0x18, + 0x16, 0x17, 0x16, 0x17, 0x17, 0x16, 0x18, 0x17, 0x18, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x18, + 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x16, 0x17, 0x18, 0x17, 0x18, 0x17, 0x18, 0x18, 0x18, 0x18, + 0x16, 0x18, 0x17, 0x17, 0x17, 0x16, 0x17, 0x16, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, + 0x17, 0x17, 0x17, 0x16, 0x16, 0x17, 0x16, 0x17, 0x18, 0x18, 0x18, 0x16, 0x17, 0x17, 0x19, 0x17, + 0x17, 0x17, 0x17, 0x16, 0x16, 0x17, 0x18, 0x16, 0x18, 0x17, 0x17, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x17, 0x17, 0x16, 0x16, 0x17, 0x16, 0x16, 0x16, 0x16, 0x16, 0x17, 0x16, 0x17, 0x17, 0x17, 0x18, + 0x17, 0x16, 0x16, 0x16, 0x17, 0x17, 0x17, 0x16, 0x17, 0x16, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, + 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x17, 0x18, 0x16, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, + 0x17, 0x16, 0x16, 0x17, 0x17, 0x17, 0x16, 0x16, 0x17, 0x18, 0x17, 0x16, 0x16, 0x16, 0x16, 0x17, + 0x16, 0x16, 0x16, 0x16, 0x16, 0x15, 0x15, 0x16, 0x17, 0x17, 0x17, 0x16, 0x16, 0x17, 0x16, 0x17, + 0x15, 0x15, 0x15, 0x16, 0x16, 0x15, 0x16, 0x16, 0x17, 0x18, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, + 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x15, 0x16, 0x17, 0x16, 0x17, 0x17, 0x16, 0x16, 0x17, 0x17, + 0x15, 0x15, 0x16, 0x16, 0x16, 0x16, 0x16, 0x15, 0x16, 0x16, 0x16, 0x17, 0x17, 0x17, 0x16, 0x17, + 0x16, 0x16, 0x16, 0x16, 0x16, 0x15, 0x15, 0x16, 0x17, 0x16, 0x17, 0x16, 0x16, 0x15, 0x16, 0x17, + 0x15, 0x16, 0x15, 0x15, 0x16, 0x15, 0x16, 0x15, 0x16, 0x15, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, + 0x17, 0x16, 0x16, 0x16, 0x17, 0x15, 0x16, 0x16, 0x17, 0x16, 0x17, 0x16, 0x16, 0x17, 0x18, 0x17, + 0x16, 0x17, 0x16, 0x16, 0x17, 0x16, 0x16, 0x16, 0x17, 0x17, 0x17, 0x16, 0x16, 0x16, 0x16, 0x17, + 0x17, 0x16, 0x16, 0x16, 0x17, 0x15, 0x15, 0x16, 0x17, 0x16, 0x16, 0x16, 0x16, 0x16, 0x17, 0x17, + 0x16, 0x15, 0x15, 0x15, 0x15, 0x15, 0x16, 0x16, 0x15, 0x15, 0x15, 0x16, 0x16, 0x16, 0x16, 0x17, + 0x16, 0x16, 0x16, 0x16, 0x16, 0x15, 0x15, 0x16, 0x16, 0x16, 0x17, 0x16, 0x16, 0x16, 0x16, 0x16, + 0x16, 0x16, 0x16, 0x15, 0x15, 0x16, 0x15, 0x15, 0x16, 0x16, 0x16, 0x17, 0x17, 0x17, 0x17, 0x17, + 0x16, 0x16, 0x15, 0x15, 0x16, 0x15, 0x16, 0x15, 0x17, 0x16, 0x17, 0x17, 0x17, 0x16, 0x16, 0x16, + 0x16, 0x16, 0x16, 0x15, 0x15, 0x15, 0x15, 0x15, 0x16, 0x16, 0x16, 0x15, 0x16, 0x16, 0x16, 0x16, + 0x16, 0x16, 0x16, 0x17, 0x17, 0x15, 0x16, 0x16, 0x16, 0x16, 0x17, 0x16, 0x16, 0x16, 0x17, 0x17, + 0x16, 0x16, 0x15, 0x15, 0x16, 0x16, 0x16, 0x15, 0x17, 0x17, 0x16, 0x16, 0x16, 0x16, 0x16, 0x17, + 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x15, 0x15, 0x16, 0x16, 0x17, 0x16, 0x16, 0x16, 0x16, 0x16, + 0x16, 0x16, 0x16, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x16, 0x16, 0x16, 0x16, 0x16, 0x17, 0x16, + 0x16, 0x16, 0x15, 0x16, 0x16, 0x15, 0x15, 0x15, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x17, 0x18, + 0x19, 0x17, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x16, 0x15, 0x16, 0x16, 0x16, 0x16, + 0x16, 0x16, 0x16, 0x15, 0x16, 0x15, 0x15, 0x15, 0x15, 0x16, 0x16, 0x16, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x17, 0x17, + 0x15, 0x15, 0x16, 0x15, 0x16, 0x14, 0x14, 0x14, 0x15, 0x15, 0x15, 0x15, 0x17, 0x17, 0x17, 0x17, + 0x17, 0x17, 0x15, 0x15, 0x14, 0x15, 0x15, 0x15, 0x15, 0x15, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, + 0x15, 0x15, 0x15, 0x15, 0x16, 0x14, 0x14, 0x14, 0x15, 0x15, 0x15, 0x15, 0x17, 0x16, 0x17, 0x16, + 0x16, 0x16, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x15, 0x15, 0x15, 0x15, 0x16, 0x16, 0x16, 0x16, + 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1B, 0x1B, 0x1C, 0x1B, 0x1C, 0x1B, + 0x1A, 0x1B, 0x1A, 0x1B, 0x1A, 0x1D, 0x1C, 0x1B, 0x1C, 0x1B, 0x1D, 0x1D, 0x1C, 0x1E, 0x1E, 0x1F, + 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1B, 0x1C, 0x1B, 0x1B, 0x1B, 0x1B, 0x1C, 0x1A, + 0x1A, 0x1B, 0x1B, 0x1A, 0x1A, 0x1C, 0x1C, 0x1B, 0x1B, 0x1C, 0x1D, 0x1D, 0x1C, 0x1E, 0x1E, 0x1E, + 0x1D, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1D, 0x1C, 0x1B, 0x1C, 0x1B, 0x1B, 0x1C, 0x1C, 0x1B, 0x1B, + 0x1A, 0x1A, 0x1A, 0x1A, 0x19, 0x1C, 0x1B, 0x1B, 0x1B, 0x1B, 0x1D, 0x1D, 0x1C, 0x1D, 0x1E, 0x1E, + 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1B, 0x1D, 0x1C, 0x1B, 0x1C, 0x1B, 0x1B, 0x1C, 0x1C, 0x1B, 0x1B, + 0x19, 0x1A, 0x1A, 0x1A, 0x19, 0x1B, 0x1B, 0x1A, 0x1A, 0x1B, 0x1C, 0x1C, 0x1C, 0x1D, 0x1E, 0x1E, + 0x1C, 0x1C, 0x1C, 0x1C, 0x1D, 0x1C, 0x1D, 0x1D, 0x1C, 0x1C, 0x1C, 0x1C, 0x1D, 0x1E, 0x1C, 0x1D, + 0x1C, 0x1C, 0x1C, 0x1B, 0x1B, 0x1B, 0x1B, 0x1A, 0x1A, 0x1B, 0x1C, 0x1C, 0x1C, 0x1D, 0x1E, 0x1E, + 0x1C, 0x1C, 0x1B, 0x1B, 0x1B, 0x1E, 0x1D, 0x1D, 0x1E, 0x1C, 0x1D, 0x1D, 0x1D, 0x1D, 0x1C, 0x1E, + 0x1D, 0x1D, 0x1B, 0x1C, 0x1C, 0x1E, 0x1E, 0x1C, 0x1F, 0x1E, 0x1D, 0x1C, 0x1D, 0x1D, 0x1D, 0x1D, + 0x1B, 0x1C, 0x1B, 0x1B, 0x1C, 0x1C, 0x1B, 0x1A, 0x1B, 0x1A, 0x1C, 0x1B, 0x1C, 0x1B, 0x1B, 0x1B, + 0x1B, 0x1B, 0x1A, 0x1C, 0x1C, 0x1E, 0x1C, 0x1C, 0x1D, 0x1C, 0x1C, 0x1D, 0x1D, 0x1D, 0x1D, 0x1D, + 0x1C, 0x1B, 0x1B, 0x1B, 0x1B, 0x1C, 0x1B, 0x1B, 0x1C, 0x1A, 0x1D, 0x1C, 0x1B, 0x1B, 0x1C, 0x1D, + 0x1B, 0x1B, 0x1B, 0x1B, 0x1C, 0x1E, 0x1C, 0x1C, 0x1C, 0x1D, 0x1D, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, + 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1C, 0x1B, 0x1B, 0x1C, 0x1C, 0x1C, 0x1D, 0x1C, 0x1C, 0x1C, 0x1D, + 0x1D, 0x1B, 0x1C, 0x1D, 0x1C, 0x1E, 0x1D, 0x1B, 0x1D, 0x1D, 0x1D, 0x1B, 0x1B, 0x1B, 0x1C, 0x1D, + 0x1B, 0x1C, 0x1C, 0x1C, 0x1C, 0x1B, 0x1C, 0x1B, 0x1D, 0x1C, 0x1C, 0x1C, 0x1C, 0x1D, 0x1D, 0x1C, + 0x1B, 0x1B, 0x1C, 0x1D, 0x1D, 0x1E, 0x1B, 0x1C, 0x1D, 0x1D, 0x1D, 0x1B, 0x1B, 0x1B, 0x1C, 0x1C, + 0x1B, 0x1C, 0x1C, 0x1B, 0x1B, 0x1B, 0x1B, 0x1C, 0x1C, 0x1C, 0x1D, 0x1C, 0x1C, 0x1D, 0x1D, 0x1D, + 0x1C, 0x1C, 0x1B, 0x1C, 0x1C, 0x1E, 0x1C, 0x1B, 0x1B, 0x1C, 0x1D, 0x1B, 0x1C, 0x1C, 0x1C, 0x1D, + 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1B, 0x1C, 0x1B, 0x1C, 0x1B, 0x1B, 0x1C, 0x1C, + 0x1B, 0x1B, 0x1C, 0x1B, 0x1C, 0x1D, 0x1A, 0x1B, 0x1B, 0x1C, 0x1C, 0x1B, 0x1C, 0x1C, 0x1C, 0x1C, + 0x1C, 0x1C, 0x1B, 0x1C, 0x1C, 0x1B, 0x1B, 0x1B, 0x1C, 0x1B, 0x1C, 0x1C, 0x1B, 0x1C, 0x1D, 0x1C, + 0x1C, 0x1A, 0x1B, 0x1C, 0x1C, 0x1D, 0x1A, 0x1B, 0x1C, 0x1D, 0x1C, 0x1B, 0x1C, 0x1B, 0x1B, 0x1C, + 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1C, 0x1A, 0x1C, 0x1B, 0x1B, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, + 0x1B, 0x1C, 0x1B, 0x1D, 0x1A, 0x1C, 0x1B, 0x1C, 0x1C, 0x1B, 0x1C, 0x1B, 0x1C, 0x1B, 0x1B, 0x1C, + 0x1B, 0x1C, 0x1B, 0x1C, 0x1C, 0x1A, 0x1B, 0x1C, 0x1D, 0x1C, 0x1C, 0x1B, 0x1B, 0x1C, 0x1D, 0x1D, + 0x1B, 0x1C, 0x1B, 0x1C, 0x1C, 0x1C, 0x1B, 0x1D, 0x1C, 0x1C, 0x1C, 0x1B, 0x1C, 0x1C, 0x1C, 0x1C, + 0x1B, 0x1B, 0x1B, 0x1B, 0x1C, 0x1B, 0x1B, 0x1B, 0x1B, 0x1C, 0x1B, 0x1C, 0x1B, 0x1C, 0x1B, 0x1B, + 0x1C, 0x1B, 0x1B, 0x1B, 0x1C, 0x1B, 0x1A, 0x1C, 0x1A, 0x1B, 0x1C, 0x1A, 0x1B, 0x1B, 0x1B, 0x1C, + 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1C, 0x1C, 0x1C, 0x1C, 0x1B, 0x1B, 0x1B, 0x1B, 0x1C, + 0x1B, 0x1A, 0x1B, 0x1B, 0x1C, 0x1C, 0x1A, 0x1B, 0x1C, 0x1D, 0x1D, 0x1C, 0x1D, 0x1D, 0x1C, 0x1C, + 0x1B, 0x1B, 0x1C, 0x1B, 0x1C, 0x1B, 0x1C, 0x1C, 0x1B, 0x1D, 0x1C, 0x1C, 0x1B, 0x1B, 0x1C, 0x1B, + 0x1D, 0x1B, 0x1B, 0x1B, 0x1B, 0x1C, 0x1B, 0x1C, 0x1D, 0x1B, 0x1C, 0x1C, 0x1B, 0x1C, 0x1C, 0x1B, + 0x1A, 0x1A, 0x1A, 0x1A, 0x1B, 0x1A, 0x1B, 0x1A, 0x1B, 0x1C, 0x1C, 0x1C, 0x1C, 0x1B, 0x1C, 0x1B, + 0x1B, 0x1A, 0x1B, 0x1C, 0x1A, 0x1B, 0x1A, 0x1B, 0x1C, 0x1B, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, + 0x1A, 0x1A, 0x1A, 0x1B, 0x1B, 0x1B, 0x1C, 0x1A, 0x1C, 0x1C, 0x1B, 0x1B, 0x1B, 0x1C, 0x1C, 0x1C, + 0x1B, 0x1C, 0x1A, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1C, 0x1C, 0x1D, 0x1B, 0x1B, 0x1B, 0x1B, 0x1C, + 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1B, 0x1A, 0x1C, 0x1C, 0x1B, 0x1C, 0x1A, 0x1C, 0x1C, 0x1C, + 0x1C, 0x1B, 0x1C, 0x1C, 0x1C, 0x1B, 0x1C, 0x1B, 0x1B, 0x1C, 0x1D, 0x1C, 0x1C, 0x1C, 0x1C, 0x1D, + 0x1B, 0x1A, 0x1B, 0x1B, 0x1B, 0x1C, 0x1A, 0x1B, 0x1C, 0x1C, 0x1C, 0x1B, 0x1A, 0x1A, 0x1B, 0x1B, + 0x1A, 0x1A, 0x1A, 0x1A, 0x1B, 0x1A, 0x1B, 0x1B, 0x1C, 0x1A, 0x1D, 0x1B, 0x1B, 0x1B, 0x1B, 0x1C, + 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1C, 0x1C, 0x1C, 0x1C, 0x1B, 0x1B, 0x1D, 0x1B, 0x1C, + 0x1C, 0x1B, 0x1A, 0x1B, 0x1A, 0x1B, 0x1C, 0x1B, 0x1B, 0x1B, 0x1C, 0x1B, 0x1B, 0x1B, 0x1B, 0x1C, + 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1A, 0x1C, 0x1C, 0x1C, 0x1C, 0x1B, 0x1D, 0x1B, 0x1C, + 0x1B, 0x1B, 0x1C, 0x1B, 0x1B, 0x1D, 0x1C, 0x1B, 0x1C, 0x1B, 0x1D, 0x1B, 0x1B, 0x1B, 0x1C, 0x1C, + 0x1A, 0x1A, 0x19, 0x1A, 0x1A, 0x1A, 0x1A, 0x19, 0x1C, 0x1C, 0x1D, 0x1B, 0x1B, 0x1D, 0x1B, 0x1B, + 0x1B, 0x1A, 0x1A, 0x1A, 0x1A, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1D, 0x1B, 0x1B, 0x1B, 0x1B, 0x1C, + 0x1B, 0x1A, 0x1A, 0x1B, 0x1B, 0x1D, 0x1A, 0x1B, 0x1B, 0x1C, 0x1C, 0x1A, 0x1B, 0x1C, 0x1B, 0x1C, + 0x1B, 0x1B, 0x1B, 0x1B, 0x1A, 0x1A, 0x1A, 0x1B, 0x1B, 0x1A, 0x1C, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, + 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1C, 0x1A, 0x1B, 0x1B, 0x1C, 0x1C, 0x1B, 0x1B, 0x1B, 0x1C, 0x1C, + 0x1B, 0x1A, 0x1A, 0x1B, 0x1A, 0x1A, 0x1B, 0x1A, 0x1B, 0x1A, 0x1B, 0x1B, 0x1B, 0x1C, 0x1C, 0x1C, + 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1B, 0x19, 0x1A, 0x1C, 0x1C, 0x1D, 0x1B, 0x1B, 0x1B, 0x1B, 0x1C, + 0x1B, 0x1A, 0x19, 0x1B, 0x1A, 0x1B, 0x1A, 0x1B, 0x1A, 0x1A, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, + 0x1A, 0x1A, 0x1A, 0x1B, 0x1B, 0x1B, 0x1A, 0x1A, 0x1D, 0x1B, 0x1C, 0x1B, 0x1C, 0x1C, 0x1A, 0x1A, + 0x1B, 0x1A, 0x1A, 0x1A, 0x1A, 0x1B, 0x1A, 0x1B, 0x1C, 0x1B, 0x1B, 0x1C, 0x1C, 0x1B, 0x1B, 0x1C, + 0x1B, 0x1B, 0x1A, 0x1B, 0x1B, 0x1B, 0x19, 0x1A, 0x1D, 0x1B, 0x1D, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, + 0x1B, 0x1A, 0x1A, 0x1B, 0x1B, 0x1A, 0x1A, 0x1A, 0x1C, 0x1A, 0x1B, 0x1C, 0x1B, 0x1B, 0x1C, 0x1C, + 0x1B, 0x1A, 0x1A, 0x1A, 0x1A, 0x1B, 0x19, 0x1A, 0x1A, 0x1C, 0x1B, 0x1A, 0x1C, 0x1B, 0x1B, 0x1B, + 0x1A, 0x1B, 0x1A, 0x1A, 0x1A, 0x1C, 0x1B, 0x19, 0x1A, 0x1B, 0x1D, 0x1B, 0x1B, 0x1B, 0x1C, 0x1C, + 0x1B, 0x1A, 0x1A, 0x1A, 0x1B, 0x1B, 0x19, 0x1B, 0x1A, 0x1C, 0x1B, 0x1A, 0x1C, 0x1B, 0x1C, 0x1A, + 0x1B, 0x1A, 0x1A, 0x1A, 0x1B, 0x1B, 0x1B, 0x19, 0x1B, 0x1A, 0x1B, 0x1C, 0x1C, 0x1B, 0x1B, 0x1C, + 0x1B, 0x1A, 0x19, 0x1A, 0x1B, 0x1B, 0x19, 0x1A, 0x1A, 0x1B, 0x1B, 0x1A, 0x1A, 0x1B, 0x1A, 0x1B, + 0x1A, 0x19, 0x1A, 0x19, 0x1B, 0x19, 0x1B, 0x1A, 0x1C, 0x1C, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, + 0x19, 0x19, 0x19, 0x19, 0x1A, 0x1A, 0x19, 0x1A, 0x1B, 0x1B, 0x1C, 0x1B, 0x19, 0x1A, 0x1A, 0x1C, + 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x19, 0x1A, 0x1A, 0x1A, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, + 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x18, 0x1A, 0x1B, 0x1C, 0x1B, 0x1A, 0x1B, 0x1B, 0x1B, 0x1A, + 0x1B, 0x1A, 0x1A, 0x19, 0x1B, 0x1A, 0x1B, 0x1A, 0x1C, 0x1A, 0x1A, 0x1B, 0x1B, 0x1B, 0x1C, 0x1C, + 0x19, 0x19, 0x19, 0x19, 0x1A, 0x1B, 0x1A, 0x1A, 0x1A, 0x1A, 0x1B, 0x19, 0x1B, 0x1B, 0x1A, 0x1B, + 0x1A, 0x19, 0x18, 0x19, 0x1A, 0x1A, 0x1B, 0x19, 0x1A, 0x19, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, + 0x1A, 0x19, 0x19, 0x19, 0x19, 0x1A, 0x1A, 0x1A, 0x1B, 0x1A, 0x1A, 0x1B, 0x1A, 0x1B, 0x1B, 0x1A, + 0x1A, 0x19, 0x19, 0x1A, 0x19, 0x19, 0x1A, 0x18, 0x1A, 0x1A, 0x1B, 0x1A, 0x1A, 0x1A, 0x1A, 0x1B, + 0x1B, 0x1A, 0x1A, 0x19, 0x1A, 0x1A, 0x19, 0x19, 0x1A, 0x1A, 0x1A, 0x19, 0x1A, 0x1A, 0x1A, 0x1A, + 0x19, 0x18, 0x18, 0x19, 0x1A, 0x18, 0x1A, 0x19, 0x1B, 0x1A, 0x1A, 0x1B, 0x1B, 0x1B, 0x1B, 0x1C, + 0x19, 0x19, 0x19, 0x19, 0x1A, 0x1A, 0x17, 0x1A, 0x1A, 0x1A, 0x1B, 0x1A, 0x19, 0x19, 0x1A, 0x1B, + 0x19, 0x18, 0x19, 0x19, 0x19, 0x19, 0x1A, 0x19, 0x1B, 0x19, 0x1A, 0x1A, 0x1A, 0x1B, 0x1B, 0x1B, + 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x18, 0x19, 0x1A, 0x1A, 0x1B, 0x19, 0x19, 0x19, 0x19, 0x1B, + 0x18, 0x19, 0x18, 0x18, 0x19, 0x18, 0x1A, 0x18, 0x1A, 0x18, 0x19, 0x19, 0x19, 0x19, 0x1A, 0x1A, + 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x19, 0x19, 0x19, 0x1B, 0x1A, 0x1A, 0x1B, 0x1B, 0x1B, + 0x19, 0x19, 0x19, 0x19, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1B, 0x1A, 0x1B, + 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x19, 0x19, 0x1A, 0x1A, 0x1B, 0x19, 0x19, 0x1A, 0x1B, 0x1B, + 0x19, 0x18, 0x18, 0x19, 0x19, 0x18, 0x1A, 0x19, 0x19, 0x19, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1B, + 0x1A, 0x1A, 0x1A, 0x19, 0x1A, 0x19, 0x18, 0x19, 0x1A, 0x19, 0x1B, 0x19, 0x19, 0x1A, 0x1A, 0x1B, + 0x19, 0x19, 0x19, 0x19, 0x19, 0x18, 0x19, 0x19, 0x1B, 0x19, 0x1A, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, + 0x19, 0x19, 0x19, 0x19, 0x19, 0x18, 0x18, 0x18, 0x19, 0x1A, 0x1B, 0x19, 0x19, 0x19, 0x1A, 0x1A, + 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x18, 0x19, 0x19, 0x18, 0x19, 0x19, 0x19, 0x1A, 0x1A, + 0x1A, 0x1A, 0x1A, 0x1A, 0x1B, 0x18, 0x19, 0x1A, 0x19, 0x1A, 0x1A, 0x19, 0x19, 0x19, 0x1A, 0x1A, + 0x19, 0x18, 0x18, 0x19, 0x18, 0x19, 0x1A, 0x19, 0x1A, 0x19, 0x19, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, + 0x19, 0x19, 0x18, 0x19, 0x19, 0x18, 0x19, 0x18, 0x19, 0x19, 0x1A, 0x19, 0x19, 0x19, 0x19, 0x19, + 0x19, 0x18, 0x18, 0x18, 0x19, 0x18, 0x18, 0x19, 0x1A, 0x1A, 0x1A, 0x19, 0x1A, 0x1A, 0x1B, 0x1A, + 0x1A, 0x1A, 0x19, 0x19, 0x1A, 0x18, 0x18, 0x18, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x1B, 0x1C, + 0x1C, 0x1A, 0x17, 0x17, 0x17, 0x18, 0x18, 0x18, 0x18, 0x19, 0x1A, 0x19, 0x19, 0x19, 0x1A, 0x19, + 0x19, 0x19, 0x19, 0x18, 0x19, 0x18, 0x18, 0x18, 0x19, 0x18, 0x19, 0x19, 0x1B, 0x1B, 0x1B, 0x1C, + 0x1B, 0x1B, 0x18, 0x17, 0x17, 0x18, 0x18, 0x18, 0x19, 0x19, 0x1A, 0x19, 0x1A, 0x1A, 0x1A, 0x1A, + 0x18, 0x18, 0x18, 0x19, 0x19, 0x17, 0x18, 0x17, 0x18, 0x18, 0x18, 0x18, 0x1B, 0x1A, 0x1B, 0x1B, + 0x1A, 0x1A, 0x17, 0x18, 0x17, 0x18, 0x18, 0x18, 0x19, 0x19, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, + 0x18, 0x18, 0x18, 0x18, 0x19, 0x17, 0x17, 0x17, 0x18, 0x18, 0x18, 0x18, 0x1A, 0x1A, 0x1A, 0x1A, + 0x19, 0x19, 0x17, 0x17, 0x17, 0x18, 0x18, 0x18, 0x18, 0x19, 0x1A, 0x19, 0x19, 0x19, 0x19, 0x1A, + 0x1F, 0x1F, 0x1F, 0x20, 0x20, 0x20, 0x1F, 0x20, 0x21, 0x21, 0x1F, 0x20, 0x20, 0x21, 0x21, 0x20, + 0x21, 0x20, 0x20, 0x20, 0x20, 0x22, 0x20, 0x1E, 0x1E, 0x1E, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x20, + 0x20, 0x1F, 0x20, 0x20, 0x1F, 0x1F, 0x1F, 0x1F, 0x21, 0x21, 0x20, 0x21, 0x21, 0x21, 0x22, 0x20, + 0x20, 0x20, 0x21, 0x20, 0x1F, 0x22, 0x21, 0x1F, 0x1E, 0x1E, 0x20, 0x1F, 0x1F, 0x20, 0x20, 0x21, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x21, 0x20, 0x21, 0x21, 0x21, 0x20, 0x1F, + 0x1F, 0x20, 0x1F, 0x20, 0x1F, 0x22, 0x21, 0x1F, 0x1E, 0x1E, 0x21, 0x20, 0x20, 0x20, 0x20, 0x21, + 0x20, 0x20, 0x1F, 0x20, 0x21, 0x20, 0x21, 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x22, 0x22, 0x21, + 0x20, 0x21, 0x21, 0x21, 0x20, 0x22, 0x21, 0x1E, 0x1E, 0x1E, 0x21, 0x1F, 0x20, 0x20, 0x20, 0x21, + 0x20, 0x20, 0x20, 0x20, 0x21, 0x20, 0x21, 0x20, 0x21, 0x20, 0x21, 0x21, 0x22, 0x23, 0x22, 0x20, + 0x21, 0x21, 0x21, 0x21, 0x20, 0x21, 0x21, 0x1E, 0x1F, 0x1E, 0x21, 0x20, 0x20, 0x20, 0x20, 0x21, + 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x21, 0x1F, 0x20, 0x21, 0x1F, 0x22, 0x21, 0x23, 0x21, 0x21, 0x22, + 0x20, 0x20, 0x20, 0x1F, 0x21, 0x21, 0x1E, 0x20, 0x21, 0x21, 0x21, 0x1E, 0x1F, 0x20, 0x1F, 0x1F, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x1F, 0x20, 0x21, 0x20, 0x1F, 0x20, 0x20, 0x21, 0x1F, 0x1F, 0x20, + 0x1F, 0x20, 0x1F, 0x20, 0x1F, 0x21, 0x20, 0x20, 0x21, 0x20, 0x20, 0x21, 0x20, 0x20, 0x20, 0x21, + 0x20, 0x20, 0x1F, 0x20, 0x20, 0x20, 0x1F, 0x21, 0x20, 0x1F, 0x21, 0x22, 0x20, 0x1E, 0x1E, 0x1F, + 0x1F, 0x1F, 0x1E, 0x1F, 0x20, 0x21, 0x20, 0x1F, 0x21, 0x20, 0x22, 0x22, 0x22, 0x22, 0x22, 0x23, + 0x1F, 0x1F, 0x1F, 0x1F, 0x20, 0x20, 0x1F, 0x21, 0x1F, 0x20, 0x1F, 0x21, 0x20, 0x20, 0x20, 0x22, + 0x21, 0x21, 0x20, 0x21, 0x21, 0x21, 0x21, 0x20, 0x22, 0x22, 0x22, 0x22, 0x21, 0x22, 0x22, 0x22, + 0x20, 0x20, 0x20, 0x21, 0x21, 0x1F, 0x20, 0x21, 0x21, 0x20, 0x1F, 0x21, 0x21, 0x21, 0x22, 0x21, + 0x20, 0x20, 0x20, 0x21, 0x22, 0x22, 0x20, 0x22, 0x22, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x22, + 0x1F, 0x20, 0x1F, 0x20, 0x20, 0x20, 0x20, 0x22, 0x21, 0x21, 0x21, 0x21, 0x1F, 0x21, 0x20, 0x21, + 0x20, 0x1F, 0x1F, 0x20, 0x20, 0x22, 0x21, 0x21, 0x21, 0x1F, 0x21, 0x21, 0x21, 0x21, 0x20, 0x22, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x20, 0x1F, 0x20, 0x20, 0x21, 0x1F, 0x20, 0x1F, 0x20, + 0x1F, 0x1E, 0x1F, 0x20, 0x21, 0x21, 0x1F, 0x1F, 0x20, 0x20, 0x20, 0x21, 0x20, 0x20, 0x21, 0x21, + 0x20, 0x1F, 0x1F, 0x1F, 0x1F, 0x20, 0x20, 0x20, 0x21, 0x20, 0x21, 0x22, 0x21, 0x21, 0x21, 0x21, + 0x21, 0x1F, 0x20, 0x20, 0x20, 0x21, 0x1F, 0x20, 0x21, 0x20, 0x21, 0x21, 0x21, 0x20, 0x21, 0x21, + 0x1F, 0x1F, 0x1E, 0x1F, 0x1F, 0x20, 0x21, 0x20, 0x21, 0x20, 0x1F, 0x21, 0x20, 0x22, 0x21, 0x21, + 0x20, 0x20, 0x21, 0x20, 0x20, 0x22, 0x20, 0x20, 0x22, 0x20, 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, + 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x21, 0x20, 0x1F, 0x20, 0x20, 0x1E, 0x21, 0x22, 0x21, + 0x20, 0x20, 0x20, 0x21, 0x21, 0x20, 0x20, 0x20, 0x21, 0x22, 0x21, 0x1F, 0x1F, 0x21, 0x20, 0x21, + 0x1F, 0x1E, 0x1E, 0x1E, 0x1E, 0x20, 0x20, 0x1E, 0x20, 0x20, 0x1F, 0x20, 0x1E, 0x1F, 0x1F, 0x20, + 0x20, 0x1F, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x20, 0x1F, 0x1F, 0x20, 0x21, 0x21, + 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x20, 0x1F, 0x21, 0x20, 0x21, 0x21, 0x1F, 0x21, 0x20, 0x21, + 0x20, 0x20, 0x20, 0x20, 0x21, 0x20, 0x1F, 0x1F, 0x21, 0x22, 0x22, 0x20, 0x21, 0x21, 0x22, 0x22, + 0x1F, 0x1E, 0x1F, 0x1F, 0x1F, 0x21, 0x1F, 0x20, 0x21, 0x21, 0x20, 0x21, 0x20, 0x22, 0x21, 0x20, + 0x21, 0x21, 0x21, 0x21, 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20, 0x20, 0x20, 0x20, 0x22, + 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x21, 0x1F, 0x1F, 0x20, 0x1F, 0x20, 0x20, 0x20, 0x20, 0x22, 0x21, + 0x1F, 0x20, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x20, 0x21, 0x20, 0x21, 0x20, 0x20, 0x21, 0x21, 0x21, + 0x1F, 0x1E, 0x1E, 0x1E, 0x1E, 0x20, 0x20, 0x1F, 0x20, 0x21, 0x20, 0x21, 0x1F, 0x21, 0x20, 0x20, + 0x1F, 0x21, 0x20, 0x1F, 0x20, 0x1F, 0x20, 0x20, 0x21, 0x22, 0x22, 0x1F, 0x1F, 0x1F, 0x20, 0x21, + 0x1F, 0x1F, 0x1F, 0x1F, 0x20, 0x21, 0x21, 0x21, 0x20, 0x22, 0x1F, 0x21, 0x1F, 0x20, 0x21, 0x20, + 0x20, 0x1F, 0x20, 0x1F, 0x20, 0x1F, 0x20, 0x20, 0x20, 0x21, 0x21, 0x1F, 0x20, 0x20, 0x21, 0x21, + 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x20, 0x20, 0x21, 0x1F, 0x21, 0x20, 0x21, 0x1F, 0x20, 0x21, 0x21, + 0x1F, 0x20, 0x20, 0x20, 0x21, 0x20, 0x20, 0x1F, 0x21, 0x20, 0x21, 0x20, 0x20, 0x20, 0x20, 0x21, + 0x1E, 0x1E, 0x1F, 0x1E, 0x1F, 0x1F, 0x1F, 0x21, 0x21, 0x21, 0x20, 0x21, 0x21, 0x21, 0x21, 0x20, + 0x21, 0x20, 0x1F, 0x1F, 0x20, 0x20, 0x20, 0x20, 0x21, 0x21, 0x21, 0x1F, 0x20, 0x20, 0x20, 0x21, + 0x1E, 0x1E, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x20, 0x1F, 0x21, 0x20, 0x20, 0x22, 0x20, 0x21, + 0x20, 0x1F, 0x21, 0x20, 0x1F, 0x20, 0x20, 0x1F, 0x20, 0x21, 0x20, 0x20, 0x20, 0x21, 0x22, 0x21, + 0x1E, 0x1E, 0x1D, 0x1E, 0x1E, 0x20, 0x1F, 0x20, 0x22, 0x22, 0x22, 0x21, 0x20, 0x22, 0x20, 0x21, + 0x1F, 0x20, 0x1F, 0x1F, 0x20, 0x1F, 0x20, 0x20, 0x21, 0x21, 0x21, 0x20, 0x20, 0x20, 0x20, 0x21, + 0x1F, 0x1E, 0x1E, 0x1E, 0x1E, 0x20, 0x1F, 0x21, 0x20, 0x22, 0x21, 0x21, 0x22, 0x22, 0x22, 0x21, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x1F, 0x20, 0x20, 0x21, 0x20, 0x20, 0x1F, 0x20, 0x21, 0x21, 0x21, + 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1E, 0x1F, 0x20, 0x20, 0x21, 0x21, 0x21, 0x21, 0x22, 0x21, + 0x20, 0x1F, 0x20, 0x20, 0x20, 0x1F, 0x21, 0x1F, 0x21, 0x20, 0x1F, 0x20, 0x20, 0x21, 0x21, 0x21, + 0x1E, 0x1E, 0x1F, 0x1E, 0x1F, 0x1E, 0x20, 0x21, 0x22, 0x23, 0x23, 0x20, 0x20, 0x20, 0x21, 0x20, + 0x20, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x20, 0x20, 0x20, 0x20, 0x1F, 0x20, 0x20, 0x20, 0x20, 0x21, + 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x20, 0x20, 0x21, 0x20, 0x22, 0x22, 0x21, 0x20, + 0x1F, 0x20, 0x1F, 0x20, 0x21, 0x1F, 0x21, 0x20, 0x21, 0x21, 0x1F, 0x20, 0x20, 0x20, 0x20, 0x21, + 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1F, 0x1F, 0x21, 0x22, 0x21, 0x22, 0x20, 0x22, 0x21, 0x22, 0x21, + 0x21, 0x20, 0x1F, 0x20, 0x1F, 0x1F, 0x1F, 0x1E, 0x21, 0x20, 0x20, 0x21, 0x20, 0x20, 0x21, 0x20, + 0x1F, 0x1F, 0x1E, 0x1E, 0x1E, 0x1E, 0x1F, 0x1F, 0x20, 0x21, 0x20, 0x1F, 0x20, 0x1F, 0x20, 0x1F, + 0x1F, 0x1F, 0x1E, 0x1E, 0x1E, 0x20, 0x22, 0x1F, 0x20, 0x20, 0x1F, 0x20, 0x20, 0x20, 0x21, 0x21, + 0x1E, 0x1E, 0x1E, 0x1E, 0x1F, 0x21, 0x1E, 0x20, 0x20, 0x20, 0x20, 0x1F, 0x20, 0x20, 0x21, 0x20, + 0x1F, 0x1E, 0x1F, 0x1F, 0x20, 0x1F, 0x20, 0x1F, 0x1F, 0x21, 0x1E, 0x20, 0x20, 0x20, 0x21, 0x21, + 0x1F, 0x1E, 0x1E, 0x1E, 0x1E, 0x1F, 0x1E, 0x20, 0x1F, 0x1F, 0x21, 0x20, 0x21, 0x21, 0x21, 0x21, + 0x20, 0x20, 0x20, 0x21, 0x21, 0x20, 0x22, 0x21, 0x22, 0x22, 0x1F, 0x1F, 0x1F, 0x20, 0x20, 0x21, + 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1D, 0x1E, 0x20, 0x1F, 0x20, 0x1E, 0x20, 0x1F, 0x20, 0x20, + 0x1E, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x20, 0x1E, 0x1F, 0x1F, 0x1E, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x1F, 0x1F, 0x1F, 0x1E, 0x1F, 0x1F, 0x1D, 0x1E, 0x20, 0x1F, 0x1F, 0x1F, 0x1F, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x1F, 0x20, 0x20, 0x22, 0x20, 0x1E, 0x21, 0x21, 0x21, 0x21, 0x21, + 0x1E, 0x1F, 0x1E, 0x1E, 0x1E, 0x1E, 0x1F, 0x1F, 0x20, 0x21, 0x21, 0x1F, 0x21, 0x21, 0x20, 0x22, + 0x1F, 0x1F, 0x1F, 0x1F, 0x20, 0x20, 0x20, 0x1F, 0x20, 0x1F, 0x20, 0x21, 0x21, 0x21, 0x21, 0x22, + 0x1F, 0x1E, 0x1E, 0x1D, 0x1E, 0x1F, 0x1F, 0x1E, 0x20, 0x1F, 0x20, 0x1F, 0x1F, 0x1F, 0x20, 0x1F, + 0x1F, 0x1D, 0x1E, 0x1F, 0x1F, 0x1F, 0x1E, 0x1E, 0x1E, 0x20, 0x1E, 0x1F, 0x1F, 0x1F, 0x20, 0x20, + 0x1F, 0x1F, 0x1E, 0x1D, 0x1E, 0x1E, 0x1F, 0x20, 0x21, 0x21, 0x22, 0x21, 0x21, 0x21, 0x21, 0x21, + 0x1E, 0x1E, 0x1E, 0x1F, 0x1F, 0x1D, 0x1F, 0x1F, 0x21, 0x21, 0x1E, 0x20, 0x20, 0x20, 0x20, 0x21, + 0x1E, 0x1E, 0x1D, 0x1E, 0x1F, 0x1E, 0x1D, 0x1F, 0x20, 0x1F, 0x21, 0x21, 0x1F, 0x1E, 0x1F, 0x20, + 0x1E, 0x1D, 0x1F, 0x1E, 0x1F, 0x1F, 0x1E, 0x1F, 0x21, 0x1F, 0x1F, 0x21, 0x21, 0x20, 0x20, 0x21, + 0x1D, 0x1E, 0x1D, 0x1E, 0x1E, 0x1D, 0x1C, 0x1D, 0x1F, 0x1D, 0x1E, 0x1E, 0x1D, 0x1D, 0x1D, 0x1F, + 0x1E, 0x1E, 0x1D, 0x1F, 0x1F, 0x1E, 0x1F, 0x1D, 0x1F, 0x1E, 0x1E, 0x1F, 0x20, 0x20, 0x20, 0x20, + 0x1E, 0x1F, 0x1E, 0x1E, 0x1F, 0x1F, 0x1F, 0x20, 0x20, 0x20, 0x20, 0x1F, 0x20, 0x20, 0x21, 0x20, + 0x1F, 0x1F, 0x21, 0x1F, 0x21, 0x1F, 0x20, 0x21, 0x22, 0x21, 0x1F, 0x1F, 0x1F, 0x1F, 0x20, 0x20, + 0x1F, 0x1E, 0x1E, 0x1E, 0x1F, 0x1F, 0x1E, 0x1E, 0x20, 0x1F, 0x20, 0x21, 0x20, 0x21, 0x20, 0x20, + 0x1E, 0x1D, 0x1E, 0x1E, 0x1E, 0x1D, 0x1E, 0x1F, 0x1F, 0x1F, 0x1F, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x1F, 0x1F, 0x1E, 0x1E, 0x1E, 0x1F, 0x1E, 0x20, 0x20, 0x1F, 0x21, 0x20, 0x20, 0x21, 0x20, 0x21, + 0x20, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x21, 0x1F, 0x1F, 0x21, 0x22, 0x21, 0x22, 0x21, + 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1D, 0x1D, 0x1E, 0x1F, 0x1F, 0x20, 0x20, 0x1F, 0x1E, 0x1F, 0x1F, + 0x1E, 0x1D, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1F, 0x1E, 0x1F, 0x1F, 0x20, 0x21, 0x21, + 0x1F, 0x1F, 0x1F, 0x20, 0x20, 0x1E, 0x1E, 0x20, 0x1F, 0x1F, 0x20, 0x1E, 0x1F, 0x1E, 0x20, 0x21, + 0x21, 0x1F, 0x1E, 0x1D, 0x1E, 0x1E, 0x1F, 0x1F, 0x20, 0x20, 0x1F, 0x1F, 0x1F, 0x1F, 0x20, 0x20, + 0x1D, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x20, + 0x1F, 0x1E, 0x1E, 0x1E, 0x1E, 0x1D, 0x20, 0x1E, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x20, 0x21, 0x20, + 0x1F, 0x1E, 0x1E, 0x1E, 0x1F, 0x1E, 0x1E, 0x1E, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x20, 0x22, 0x23, + 0x21, 0x20, 0x1E, 0x1E, 0x1E, 0x1C, 0x1C, 0x1D, 0x1E, 0x1E, 0x1F, 0x1F, 0x1F, 0x20, 0x21, 0x20, + 0x1E, 0x1D, 0x1E, 0x1E, 0x1E, 0x1F, 0x1D, 0x1E, 0x1F, 0x1F, 0x1F, 0x1F, 0x22, 0x22, 0x22, 0x22, + 0x1F, 0x20, 0x1E, 0x1E, 0x1E, 0x1C, 0x1C, 0x1D, 0x1E, 0x1E, 0x1F, 0x20, 0x20, 0x20, 0x21, 0x21, + 0x1C, 0x1D, 0x1D, 0x1E, 0x1E, 0x1E, 0x1D, 0x1D, 0x1E, 0x1F, 0x1E, 0x1E, 0x21, 0x21, 0x21, 0x21, + 0x1F, 0x20, 0x1D, 0x1E, 0x1D, 0x1C, 0x1C, 0x1D, 0x1E, 0x1E, 0x1F, 0x20, 0x20, 0x20, 0x21, 0x20, + 0x1D, 0x1D, 0x1E, 0x1E, 0x1E, 0x1E, 0x1D, 0x1D, 0x1E, 0x1F, 0x1E, 0x1E, 0x21, 0x20, 0x21, 0x21, + 0x1F, 0x1F, 0x1D, 0x1E, 0x1D, 0x1C, 0x1C, 0x1D, 0x1E, 0x1E, 0x1F, 0x20, 0x20, 0x1F, 0x1F, 0x20, + 0x06, 0xF0, 0xF1, 0x55, 0x06, 0xF0, 0xF1, 0x55, 0x06, 0xF0, 0xF1, 0x55, 0x06, 0xF0, 0xF1, 0x55, + 0x40, 0x2C, 0x2B, 0x2B, 0x2A, 0x2F, 0x2F, 0x2C, 0x2C, 0x34, 0x33, 0x31, 0x31, 0x31, 0x31, 0x34, + 0x30, 0x40, 0x32, 0x2F, 0x2E, 0x2C, 0x2B, 0x2A, 0x2B, 0x2C, 0x2C, 0x31, 0x31, 0x30, 0x2F, 0x31, + 0x32, 0x31, 0x32, 0x2F, 0x32, 0x2C, 0x2C, 0x2C, 0x2B, 0x2B, 0x2B, 0x2C, 0x2C, 0x31, 0x33, 0x31, + 0x30, 0x33, 0x31, 0x31, 0x31, 0x2E, 0x31, 0x2B, 0x2C, 0x2C, 0x2B, 0x2B, 0x2A, 0x2B, 0x2B, 0x2F, + 0x31, 0x2F, 0x2F, 0x30, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x2C, 0x2B, 0x2A, 0x2A, 0x2A, 0x2A, 0x2B, + 0x2A, 0x2E, 0x2F, 0x30, 0x2F, 0x30, 0x2F, 0x2F, 0x2F, 0x2C, 0x2F, 0x2A, 0x2A, 0x28, 0x2A, 0x2A, + 0x29, 0x28, 0x2A, 0x2D, 0x30, 0x30, 0x30, 0x2F, 0x2F, 0x30, 0x31, 0x2D, 0x2C, 0x2C, 0x2B, 0x2A, + 0x2B, 0x2B, 0x2B, 0x2B, 0x28, 0x2F, 0x2C, 0x2E, 0x2F, 0x2D, 0x2F, 0x2E, 0x2C, 0x2E, 0x2C, 0x2B, + 0x2A, 0x29, 0x2A, 0x2B, 0x2A, 0x2B, 0x2A, 0x2F, 0x30, 0x2F, 0x2F, 0x2E, 0x2E, 0x2C, 0x2D, 0x2D, + 0x2B, 0x2B, 0x2B, 0x29, 0x2A, 0x2B, 0x2A, 0x2C, 0x2B, 0x33, 0x31, 0x30, 0x31, 0x2F, 0x2F, 0x2F, + 0x2D, 0x2B, 0x2B, 0x2A, 0x2A, 0x2A, 0x29, 0x29, 0x2A, 0x28, 0x2B, 0x2D, 0x2F, 0x2E, 0x2D, 0x2D, + 0x2E, 0x2D, 0x2C, 0x2C, 0x2D, 0x2B, 0x2C, 0x2C, 0x2D, 0x2B, 0x2B, 0x2C, 0x2C, 0x2D, 0x30, 0x30, + 0x2F, 0x2E, 0x2F, 0x2D, 0x2B, 0x2B, 0x2A, 0x2B, 0x2B, 0x2B, 0x2A, 0x2B, 0x2C, 0x2D, 0x2A, 0x30, + 0x2F, 0x30, 0x30, 0x2F, 0x2D, 0x2D, 0x2C, 0x2A, 0x2C, 0x2A, 0x2A, 0x29, 0x2A, 0x2A, 0x2A, 0x2C, + 0x2D, 0x2F, 0x2F, 0x2D, 0x2E, 0x2E, 0x2C, 0x2D, 0x2B, 0x2C, 0x2C, 0x29, 0x28, 0x2A, 0x28, 0x2A, + 0x2B, 0x2B, 0x2C, 0x2E, 0x2D, 0x2B, 0x2D, 0x2D, 0x2C, 0x2D, 0x2C, 0x2A, 0x2C, 0x29, 0x29, 0x28, + 0x28, 0x2B, 0x2D, 0x2C, 0x2B, 0x2E, 0x2E, 0x2E, 0x2D, 0x2D, 0x2C, 0x2B, 0x2C, 0x2B, 0x29, 0x26, + 0x29, 0x28, 0x29, 0x2A, 0x29, 0x28, 0x29, 0x2B, 0x2B, 0x2B, 0x2C, 0x2A, 0x2B, 0x2A, 0x2C, 0x2D, + 0x2C, 0x2A, 0x29, 0x29, 0x28, 0x28, 0x28, 0x29, 0x27, 0x29, 0x2B, 0x29, 0x2B, 0x2B, 0x2B, 0x2B, + 0x2A, 0x2C, 0x2B, 0x28, 0x27, 0x27, 0x28, 0x28, 0x2A, 0x29, 0x29, 0x2C, 0x2C, 0x2C, 0x2C, 0x2A, + 0x2C, 0x2B, 0x2C, 0x2E, 0x2A, 0x2A, 0x29, 0x28, 0x28, 0x29, 0x29, 0x29, 0x29, 0x2B, 0x2A, 0x29, + 0x28, 0x29, 0x29, 0x29, 0x2B, 0x2F, 0x2A, 0x2A, 0x2A, 0x29, 0x28, 0x28, 0x2A, 0x2A, 0x29, 0x29, + 0x29, 0x28, 0x28, 0x28, 0x28, 0x28, 0x2B, 0x2C, 0x29, 0x29, 0x29, 0x28, 0x27, 0x28, 0x29, 0x2B, + 0x2B, 0x2C, 0x2A, 0x29, 0x29, 0x29, 0x2A, 0x2A, 0x29, 0x2B, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x2A, 0x29, 0x29, 0x29, 0x28, 0x28, 0x29, 0x2A, 0x2C, 0x2A, 0x29, 0x28, 0x28, + 0x29, 0x29, 0x2A, 0x2B, 0x2A, 0x2C, 0x29, 0x28, 0x29, 0x28, 0x2A, 0x29, 0x28, 0x2C, 0x2A, 0x2A, + 0x29, 0x29, 0x28, 0x29, 0x29, 0x29, 0x29, 0x2A, 0x29, 0x29, 0x28, 0x29, 0x29, 0x29, 0x29, 0x2A, + 0x2A, 0x29, 0x27, 0x28, 0x29, 0x29, 0x29, 0x29, 0x2B, 0x2A, 0x2B, 0x2B, 0x2A, 0x29, 0x2A, 0x2A, + 0x2B, 0x2C, 0x29, 0x2A, 0x29, 0x28, 0x28, 0x29, 0x28, 0x29, 0x29, 0x29, 0x2A, 0x2A, 0x28, 0x2A, + 0x29, 0x2A, 0x2A, 0x2B, 0x29, 0x2A, 0x27, 0x28, 0x29, 0x28, 0x29, 0x28, 0x29, 0x28, 0x27, 0x27, + 0x29, 0x29, 0x29, 0x29, 0x2A, 0x2C, 0x25, 0x29, 0x28, 0x27, 0x26, 0x27, 0x28, 0x28, 0x27, 0x28, + 0x27, 0x28, 0x27, 0x27, 0x28, 0x27, 0x28, 0x2A, 0x28, 0x28, 0x27, 0x29, 0x27, 0x28, 0x27, 0x29, + 0x29, 0x26, 0x28, 0x2A, 0x29, 0x28, 0x27, 0x28, 0x27, 0x2B, 0x27, 0x28, 0x27, 0x26, 0x26, 0x27, + 0x26, 0x26, 0x26, 0x27, 0x27, 0x26, 0x26, 0x24, 0x27, 0x27, 0x27, 0x2B, 0x26, 0x29, 0x28, 0x26, + 0x26, 0x27, 0x28, 0x27, 0x27, 0x25, 0x29, 0x26, 0x28, 0x26, 0x26, 0x27, 0x28, 0x2A, 0x27, 0x29, + 0x28, 0x27, 0x27, 0x27, 0x27, 0x27, 0x28, 0x27, 0x26, 0x25, 0x27, 0x26, 0x26, 0x27, 0x27, 0x2A, + 0x27, 0x27, 0x27, 0x26, 0x27, 0x27, 0x28, 0x27, 0x28, 0x26, 0x28, 0x26, 0x27, 0x26, 0x26, 0x27, + 0x28, 0x29, 0x26, 0x27, 0x26, 0x26, 0x25, 0x24, 0x26, 0x26, 0x27, 0x27, 0x26, 0x26, 0x25, 0x25, + 0x26, 0x27, 0x27, 0x2A, 0x25, 0x27, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x25, 0x25, 0x25, + 0x25, 0x25, 0x25, 0x25, 0x26, 0x27, 0x40, 0x25, 0x26, 0x25, 0x24, 0x25, 0x25, 0x26, 0x27, 0x26, + 0x25, 0x23, 0x24, 0x25, 0x25, 0x25, 0x26, 0x40, 0x40, 0x2A, 0x2D, 0x2D, 0x2E, 0x2E, 0x2F, 0x2C, + 0x2C, 0x31, 0x32, 0x30, 0x30, 0x32, 0x31, 0x34, 0x32, 0x40, 0x30, 0x2F, 0x30, 0x31, 0x2E, 0x2F, + 0x2E, 0x2E, 0x2D, 0x32, 0x31, 0x31, 0x32, 0x32, 0x32, 0x34, 0x33, 0x32, 0x31, 0x2E, 0x2F, 0x2E, + 0x30, 0x2E, 0x2B, 0x2D, 0x2C, 0x32, 0x30, 0x31, 0x2F, 0x33, 0x33, 0x34, 0x34, 0x2F, 0x33, 0x2F, + 0x2F, 0x2C, 0x2C, 0x2C, 0x2B, 0x2C, 0x2B, 0x32, 0x31, 0x30, 0x31, 0x32, 0x34, 0x34, 0x35, 0x31, + 0x30, 0x2E, 0x2F, 0x2E, 0x2E, 0x2D, 0x2D, 0x2C, 0x2C, 0x31, 0x33, 0x31, 0x32, 0x34, 0x32, 0x32, + 0x31, 0x2F, 0x31, 0x2D, 0x2C, 0x2D, 0x2E, 0x2D, 0x2C, 0x2C, 0x2D, 0x2F, 0x33, 0x30, 0x30, 0x30, + 0x32, 0x32, 0x33, 0x30, 0x2D, 0x2F, 0x2F, 0x2F, 0x2D, 0x2F, 0x2E, 0x2D, 0x2D, 0x34, 0x31, 0x33, + 0x35, 0x33, 0x33, 0x32, 0x2F, 0x2E, 0x2E, 0x2D, 0x2F, 0x2E, 0x2E, 0x2E, 0x2E, 0x2C, 0x2F, 0x31, + 0x31, 0x30, 0x32, 0x32, 0x32, 0x30, 0x30, 0x2E, 0x2D, 0x2D, 0x2E, 0x2E, 0x2D, 0x2F, 0x2C, 0x2D, + 0x2F, 0x32, 0x32, 0x30, 0x32, 0x32, 0x31, 0x30, 0x2F, 0x2D, 0x2F, 0x2E, 0x2E, 0x2F, 0x2F, 0x2E, + 0x2E, 0x2E, 0x2F, 0x32, 0x31, 0x32, 0x31, 0x31, 0x30, 0x30, 0x30, 0x2F, 0x2E, 0x2F, 0x2D, 0x2E, + 0x2F, 0x2F, 0x2D, 0x2F, 0x2E, 0x2F, 0x32, 0x33, 0x32, 0x31, 0x31, 0x30, 0x2E, 0x2F, 0x2E, 0x2D, + 0x2E, 0x2E, 0x2C, 0x2D, 0x2F, 0x2F, 0x30, 0x31, 0x33, 0x32, 0x31, 0x30, 0x2F, 0x2F, 0x2D, 0x2C, + 0x31, 0x2D, 0x2E, 0x2C, 0x2D, 0x2F, 0x30, 0x2F, 0x30, 0x33, 0x30, 0x31, 0x32, 0x32, 0x31, 0x30, + 0x30, 0x2E, 0x2F, 0x2D, 0x2E, 0x2F, 0x2E, 0x2E, 0x2E, 0x2F, 0x2E, 0x31, 0x33, 0x30, 0x31, 0x30, + 0x2F, 0x31, 0x31, 0x2D, 0x30, 0x2D, 0x2F, 0x2F, 0x30, 0x30, 0x32, 0x33, 0x30, 0x34, 0x34, 0x30, + 0x30, 0x30, 0x2F, 0x2E, 0x2E, 0x2E, 0x2B, 0x2B, 0x2E, 0x2D, 0x2E, 0x2F, 0x2D, 0x2D, 0x2D, 0x2D, + 0x2F, 0x2C, 0x30, 0x2E, 0x30, 0x2D, 0x2F, 0x31, 0x31, 0x2E, 0x2E, 0x2D, 0x2F, 0x2D, 0x30, 0x2F, + 0x30, 0x33, 0x31, 0x32, 0x30, 0x30, 0x31, 0x32, 0x31, 0x30, 0x2F, 0x2D, 0x2D, 0x2E, 0x2D, 0x2E, + 0x2F, 0x2F, 0x30, 0x34, 0x31, 0x32, 0x31, 0x2F, 0x30, 0x2F, 0x2E, 0x32, 0x2F, 0x2D, 0x2D, 0x2D, + 0x2C, 0x2E, 0x2D, 0x2D, 0x2D, 0x30, 0x2F, 0x2D, 0x2F, 0x2F, 0x2E, 0x2E, 0x30, 0x31, 0x2D, 0x2E, + 0x2E, 0x2E, 0x2D, 0x2E, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x2E, 0x2F, 0x2E, 0x2F, 0x2E, 0x2D, 0x2F, + 0x2E, 0x2D, 0x2D, 0x2B, 0x2C, 0x2C, 0x30, 0x30, 0x30, 0x31, 0x2F, 0x2F, 0x2F, 0x2F, 0x2E, 0x2E, + 0x2F, 0x31, 0x2D, 0x2E, 0x2E, 0x2D, 0x2E, 0x2E, 0x2F, 0x2E, 0x2E, 0x2D, 0x2E, 0x2E, 0x2F, 0x2D, + 0x2F, 0x2D, 0x2E, 0x30, 0x2E, 0x2D, 0x2E, 0x2F, 0x30, 0x2F, 0x30, 0x31, 0x31, 0x2F, 0x2D, 0x2E, + 0x2F, 0x2D, 0x2E, 0x2D, 0x2C, 0x2E, 0x2E, 0x2E, 0x2D, 0x2D, 0x2E, 0x2F, 0x2F, 0x2E, 0x30, 0x30, + 0x2F, 0x30, 0x2D, 0x2E, 0x2D, 0x2E, 0x2F, 0x2F, 0x2E, 0x2D, 0x2D, 0x2E, 0x2D, 0x2E, 0x2E, 0x2E, + 0x2F, 0x2D, 0x2E, 0x2E, 0x2E, 0x2C, 0x2E, 0x2D, 0x2D, 0x30, 0x2D, 0x2D, 0x2D, 0x2C, 0x2D, 0x2E, + 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2F, 0x2E, 0x2F, 0x2F, 0x2F, 0x2E, 0x2D, 0x2E, 0x2E, 0x2D, + 0x2F, 0x30, 0x2D, 0x2F, 0x30, 0x2F, 0x2E, 0x2C, 0x2E, 0x2D, 0x2E, 0x2E, 0x2E, 0x30, 0x28, 0x2D, + 0x2E, 0x2B, 0x2C, 0x2C, 0x2D, 0x2C, 0x2D, 0x2C, 0x2E, 0x2E, 0x2D, 0x2C, 0x2E, 0x2D, 0x2C, 0x2E, + 0x2D, 0x2C, 0x2B, 0x2D, 0x2C, 0x2B, 0x2C, 0x2D, 0x2E, 0x2D, 0x2D, 0x2E, 0x2D, 0x2C, 0x2D, 0x2E, + 0x2D, 0x2F, 0x2B, 0x2E, 0x2C, 0x2B, 0x2B, 0x2C, 0x2C, 0x2D, 0x2E, 0x2D, 0x2C, 0x2C, 0x2C, 0x2A, + 0x2E, 0x2C, 0x2E, 0x2D, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2F, 0x2E, 0x2F, 0x2E, 0x2C, 0x2D, 0x2C, + 0x2B, 0x2B, 0x2E, 0x2E, 0x2C, 0x2D, 0x2C, 0x2E, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2F, 0x2C, + 0x2A, 0x2B, 0x2C, 0x2B, 0x2B, 0x2E, 0x2E, 0x30, 0x2B, 0x2D, 0x2C, 0x2C, 0x2C, 0x2B, 0x2C, 0x2B, + 0x2E, 0x2C, 0x2C, 0x2C, 0x2C, 0x2C, 0x2D, 0x2C, 0x2D, 0x2E, 0x2B, 0x2D, 0x2D, 0x2D, 0x2C, 0x2C, + 0x2E, 0x2C, 0x2D, 0x2B, 0x2B, 0x2D, 0x2B, 0x2C, 0x2C, 0x2E, 0x2C, 0x2E, 0x2A, 0x2D, 0x2C, 0x2C, + 0x2D, 0x2E, 0x2D, 0x2C, 0x2E, 0x2D, 0x2C, 0x2D, 0x2D, 0x2D, 0x2D, 0x2C, 0x2D, 0x2E, 0x40, 0x2D, + 0x2D, 0x2D, 0x2E, 0x2C, 0x2C, 0x2F, 0x32, 0x30, 0x2D, 0x2C, 0x2F, 0x2D, 0x2F, 0x2C, 0x2D, 0x40, + 0x40, 0x2D, 0x32, 0x31, 0x32, 0x33, 0x34, 0x31, 0x32, 0x34, 0x34, 0x33, 0x35, 0x34, 0x35, 0x38, + 0x34, 0x40, 0x30, 0x32, 0x33, 0x33, 0x33, 0x31, 0x32, 0x31, 0x30, 0x31, 0x33, 0x32, 0x35, 0x36, + 0x36, 0x35, 0x36, 0x35, 0x33, 0x32, 0x34, 0x32, 0x32, 0x31, 0x31, 0x31, 0x2F, 0x32, 0x34, 0x33, + 0x31, 0x36, 0x35, 0x36, 0x36, 0x35, 0x34, 0x32, 0x32, 0x32, 0x31, 0x31, 0x30, 0x32, 0x2F, 0x37, + 0x35, 0x35, 0x35, 0x36, 0x38, 0x36, 0x37, 0x35, 0x34, 0x33, 0x32, 0x32, 0x34, 0x33, 0x31, 0x32, + 0x30, 0x34, 0x34, 0x34, 0x36, 0x35, 0x36, 0x34, 0x35, 0x34, 0x34, 0x31, 0x30, 0x30, 0x32, 0x30, + 0x31, 0x2E, 0x31, 0x33, 0x35, 0x33, 0x34, 0x35, 0x34, 0x34, 0x35, 0x34, 0x32, 0x35, 0x34, 0x34, + 0x35, 0x34, 0x37, 0x33, 0x33, 0x35, 0x33, 0x36, 0x36, 0x36, 0x36, 0x35, 0x34, 0x35, 0x32, 0x33, + 0x33, 0x32, 0x32, 0x33, 0x32, 0x31, 0x34, 0x35, 0x36, 0x33, 0x36, 0x35, 0x35, 0x34, 0x34, 0x34, + 0x30, 0x31, 0x32, 0x33, 0x32, 0x33, 0x32, 0x33, 0x33, 0x36, 0x36, 0x36, 0x36, 0x36, 0x35, 0x33, + 0x34, 0x33, 0x31, 0x34, 0x34, 0x34, 0x34, 0x35, 0x36, 0x33, 0x38, 0x35, 0x34, 0x34, 0x36, 0x37, + 0x37, 0x35, 0x33, 0x33, 0x32, 0x33, 0x34, 0x34, 0x35, 0x34, 0x34, 0x33, 0x34, 0x36, 0x38, 0x37, + 0x35, 0x35, 0x36, 0x36, 0x34, 0x35, 0x30, 0x32, 0x34, 0x34, 0x34, 0x35, 0x34, 0x36, 0x37, 0x35, + 0x35, 0x35, 0x36, 0x35, 0x35, 0x34, 0x32, 0x2F, 0x35, 0x34, 0x33, 0x33, 0x34, 0x32, 0x33, 0x34, + 0x35, 0x37, 0x36, 0x34, 0x35, 0x39, 0x35, 0x35, 0x37, 0x34, 0x38, 0x34, 0x34, 0x34, 0x34, 0x36, + 0x38, 0x39, 0x37, 0x37, 0x37, 0x37, 0x35, 0x37, 0x37, 0x38, 0x35, 0x31, 0x33, 0x33, 0x35, 0x34, + 0x34, 0x35, 0x37, 0x35, 0x36, 0x37, 0x39, 0x36, 0x35, 0x37, 0x35, 0x35, 0x33, 0x33, 0x30, 0x2F, + 0x32, 0x32, 0x33, 0x33, 0x33, 0x33, 0x31, 0x35, 0x33, 0x36, 0x35, 0x34, 0x36, 0x34, 0x35, 0x34, + 0x34, 0x32, 0x34, 0x31, 0x32, 0x34, 0x35, 0x37, 0x34, 0x35, 0x35, 0x37, 0x36, 0x37, 0x37, 0x35, + 0x36, 0x35, 0x34, 0x31, 0x32, 0x32, 0x34, 0x33, 0x35, 0x35, 0x34, 0x36, 0x36, 0x38, 0x34, 0x36, + 0x35, 0x35, 0x35, 0x35, 0x32, 0x34, 0x34, 0x36, 0x36, 0x37, 0x36, 0x36, 0x33, 0x34, 0x37, 0x33, + 0x32, 0x36, 0x35, 0x34, 0x34, 0x36, 0x32, 0x32, 0x35, 0x35, 0x35, 0x34, 0x33, 0x37, 0x35, 0x35, + 0x35, 0x35, 0x33, 0x38, 0x35, 0x33, 0x33, 0x34, 0x34, 0x34, 0x34, 0x32, 0x34, 0x34, 0x38, 0x36, + 0x36, 0x36, 0x35, 0x35, 0x36, 0x35, 0x36, 0x34, 0x33, 0x33, 0x34, 0x34, 0x34, 0x34, 0x35, 0x34, + 0x36, 0x34, 0x36, 0x35, 0x37, 0x34, 0x33, 0x36, 0x34, 0x32, 0x34, 0x34, 0x33, 0x34, 0x34, 0x34, + 0x35, 0x36, 0x36, 0x38, 0x36, 0x36, 0x36, 0x35, 0x34, 0x36, 0x36, 0x35, 0x33, 0x34, 0x33, 0x34, + 0x33, 0x33, 0x35, 0x34, 0x33, 0x34, 0x34, 0x35, 0x36, 0x34, 0x36, 0x36, 0x33, 0x33, 0x33, 0x35, + 0x35, 0x35, 0x33, 0x35, 0x33, 0x39, 0x34, 0x39, 0x36, 0x35, 0x38, 0x34, 0x35, 0x36, 0x36, 0x34, + 0x34, 0x33, 0x34, 0x34, 0x36, 0x36, 0x35, 0x35, 0x35, 0x35, 0x36, 0x33, 0x33, 0x35, 0x35, 0x35, + 0x35, 0x35, 0x34, 0x32, 0x34, 0x34, 0x34, 0x33, 0x36, 0x35, 0x34, 0x37, 0x35, 0x37, 0x37, 0x34, + 0x36, 0x39, 0x36, 0x36, 0x34, 0x34, 0x30, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, + 0x34, 0x33, 0x34, 0x35, 0x36, 0x33, 0x33, 0x35, 0x33, 0x33, 0x33, 0x35, 0x37, 0x33, 0x35, 0x38, + 0x36, 0x33, 0x35, 0x33, 0x33, 0x35, 0x34, 0x34, 0x34, 0x34, 0x2F, 0x35, 0x35, 0x33, 0x36, 0x36, + 0x34, 0x35, 0x35, 0x35, 0x33, 0x31, 0x32, 0x32, 0x33, 0x33, 0x33, 0x35, 0x33, 0x35, 0x34, 0x34, + 0x34, 0x36, 0x35, 0x34, 0x33, 0x34, 0x35, 0x32, 0x34, 0x33, 0x34, 0x35, 0x33, 0x34, 0x33, 0x36, + 0x35, 0x34, 0x36, 0x35, 0x35, 0x37, 0x34, 0x34, 0x32, 0x32, 0x34, 0x34, 0x34, 0x35, 0x34, 0x35, + 0x33, 0x35, 0x33, 0x33, 0x33, 0x35, 0x34, 0x34, 0x34, 0x34, 0x35, 0x33, 0x34, 0x33, 0x34, 0x33, + 0x34, 0x35, 0x33, 0x34, 0x37, 0x34, 0x34, 0x35, 0x35, 0x33, 0x33, 0x34, 0x33, 0x32, 0x34, 0x34, + 0x33, 0x35, 0x36, 0x36, 0x37, 0x34, 0x34, 0x34, 0x34, 0x36, 0x37, 0x35, 0x34, 0x34, 0x36, 0x34, + 0x36, 0x34, 0x34, 0x34, 0x35, 0x34, 0x40, 0x3D, 0x37, 0x39, 0x37, 0x39, 0x3C, 0x46, 0x39, 0x35, + 0x36, 0x38, 0x33, 0x33, 0x39, 0x33, 0x33, 0x40, 0x40, 0x3A, 0x35, 0x36, 0x38, 0x36, 0x37, 0x36, + 0x34, 0x39, 0x3A, 0x37, 0x3A, 0x3A, 0x3A, 0x3D, 0x3D, 0x40, 0x3E, 0x3F, 0x3F, 0x3E, 0x37, 0x38, + 0x37, 0x36, 0x36, 0x38, 0x38, 0x37, 0x38, 0x3D, 0x3D, 0x3A, 0x3A, 0x39, 0x37, 0x38, 0x3A, 0x36, + 0x36, 0x35, 0x33, 0x35, 0x35, 0x38, 0x38, 0x37, 0x37, 0x3C, 0x3A, 0x3B, 0x3B, 0x39, 0x39, 0x37, + 0x38, 0x36, 0x37, 0x36, 0x36, 0x37, 0x35, 0x3A, 0x3B, 0x38, 0x38, 0x3B, 0x3B, 0x3A, 0x38, 0x38, + 0x39, 0x39, 0x39, 0x38, 0x39, 0x3B, 0x36, 0x39, 0x36, 0x39, 0x3D, 0x3B, 0x3C, 0x3B, 0x3C, 0x3A, + 0x3C, 0x38, 0x39, 0x35, 0x38, 0x38, 0x37, 0x37, 0x38, 0x35, 0x36, 0x36, 0x3B, 0x38, 0x39, 0x38, + 0x38, 0x3A, 0x39, 0x38, 0x35, 0x3A, 0x39, 0x3A, 0x39, 0x3B, 0x38, 0x37, 0x35, 0x3E, 0x39, 0x3F, + 0x3A, 0x3C, 0x3D, 0x3B, 0x38, 0x3A, 0x37, 0x37, 0x39, 0x39, 0x3A, 0x38, 0x38, 0x3A, 0x37, 0x3A, + 0x3A, 0x39, 0x3C, 0x3B, 0x3C, 0x3C, 0x3A, 0x38, 0x34, 0x37, 0x38, 0x37, 0x39, 0x3B, 0x38, 0x38, + 0x37, 0x3A, 0x3C, 0x3D, 0x3C, 0x3E, 0x3E, 0x3C, 0x3A, 0x35, 0x37, 0x39, 0x39, 0x3B, 0x39, 0x39, + 0x37, 0x38, 0x3B, 0x39, 0x3B, 0x39, 0x3B, 0x3E, 0x3B, 0x3B, 0x39, 0x3A, 0x37, 0x39, 0x39, 0x3B, + 0x39, 0x3A, 0x3A, 0x3B, 0x3D, 0x3A, 0x3F, 0x3D, 0x3D, 0x3B, 0x3C, 0x3B, 0x39, 0x3A, 0x35, 0x39, + 0x39, 0x3A, 0x3A, 0x3A, 0x39, 0x38, 0x39, 0x3A, 0x3C, 0x3C, 0x3B, 0x3C, 0x3C, 0x3A, 0x37, 0x36, + 0x3A, 0x39, 0x39, 0x3A, 0x38, 0x39, 0x3A, 0x3A, 0x3F, 0x3A, 0x3C, 0x3B, 0x3C, 0x3C, 0x3B, 0x3C, + 0x39, 0x38, 0x3B, 0x3A, 0x39, 0x3C, 0x3A, 0x3D, 0x3A, 0x3B, 0x3D, 0x3C, 0x3C, 0x3D, 0x3B, 0x3D, + 0x3E, 0x3B, 0x3C, 0x36, 0x3A, 0x39, 0x3C, 0x3A, 0x39, 0x3C, 0x3C, 0x3B, 0x3D, 0x3A, 0x3C, 0x3A, + 0x3D, 0x3B, 0x3D, 0x3D, 0x3C, 0x3A, 0x34, 0x37, 0x3B, 0x39, 0x3B, 0x3B, 0x39, 0x39, 0x38, 0x39, + 0x3B, 0x3B, 0x3B, 0x3C, 0x3E, 0x3B, 0x3A, 0x38, 0x3A, 0x39, 0x3A, 0x3A, 0x3B, 0x38, 0x37, 0x38, + 0x38, 0x3B, 0x3B, 0x38, 0x39, 0x3B, 0x3E, 0x3B, 0x38, 0x39, 0x3A, 0x38, 0x3A, 0x39, 0x3A, 0x38, + 0x37, 0x3A, 0x3C, 0x3C, 0x3B, 0x3D, 0x3D, 0x39, 0x3D, 0x3C, 0x38, 0x3A, 0x39, 0x3B, 0x3B, 0x3A, + 0x3C, 0x3D, 0x37, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3B, 0x3D, 0x3C, 0x3C, 0x3C, 0x3A, 0x39, 0x3A, + 0x3B, 0x3C, 0x3B, 0x3A, 0x39, 0x3C, 0x3C, 0x3B, 0x3A, 0x3B, 0x3D, 0x3B, 0x3E, 0x3A, 0x3B, 0x3A, + 0x39, 0x3A, 0x3A, 0x3A, 0x38, 0x3C, 0x3B, 0x3E, 0x3D, 0x3C, 0x3B, 0x3C, 0x3C, 0x3C, 0x3D, 0x3C, + 0x3B, 0x3A, 0x39, 0x3C, 0x3D, 0x3B, 0x3B, 0x3E, 0x3A, 0x3C, 0x3A, 0x3C, 0x3A, 0x39, 0x3C, 0x3B, + 0x3B, 0x3A, 0x3B, 0x3A, 0x3C, 0x3A, 0x3B, 0x3C, 0x3A, 0x3A, 0x3B, 0x3D, 0x40, 0x3C, 0x3D, 0x3E, + 0x3B, 0x3B, 0x3D, 0x3A, 0x3A, 0x3A, 0x39, 0x3A, 0x3B, 0x3B, 0x3A, 0x3A, 0x39, 0x3A, 0x39, 0x3A, + 0x39, 0x3A, 0x3B, 0x3E, 0x3C, 0x3C, 0x3B, 0x3B, 0x3C, 0x3C, 0x3A, 0x39, 0x3B, 0x3B, 0x3A, 0x3C, + 0x3D, 0x3E, 0x39, 0x3C, 0x3C, 0x3B, 0x3D, 0x3C, 0x39, 0x39, 0x3B, 0x3B, 0x3D, 0x3D, 0x3B, 0x3B, + 0x3A, 0x3B, 0x3D, 0x3A, 0x3A, 0x3A, 0x3B, 0x3B, 0x3B, 0x3A, 0x3B, 0x37, 0x3B, 0x3A, 0x3B, 0x3B, + 0x3E, 0x3B, 0x3A, 0x3D, 0x3A, 0x3B, 0x39, 0x3B, 0x3C, 0x3B, 0x3E, 0x3C, 0x3A, 0x3B, 0x35, 0x3D, + 0x3C, 0x38, 0x39, 0x38, 0x3A, 0x39, 0x36, 0x3C, 0x3C, 0x3A, 0x3C, 0x3C, 0x3D, 0x3B, 0x3B, 0x3C, + 0x3A, 0x3B, 0x3A, 0x3B, 0x3A, 0x39, 0x3B, 0x39, 0x3D, 0x39, 0x3A, 0x3E, 0x3C, 0x3B, 0x3A, 0x3C, + 0x3B, 0x39, 0x37, 0x3D, 0x3B, 0x3B, 0x38, 0x39, 0x3A, 0x38, 0x3B, 0x3A, 0x38, 0x38, 0x3C, 0x3A, + 0x3E, 0x3A, 0x3A, 0x3A, 0x37, 0x3E, 0x3D, 0x3C, 0x3C, 0x3C, 0x3C, 0x3F, 0x3B, 0x3B, 0x3C, 0x3B, + 0x3A, 0x3A, 0x3D, 0x3B, 0x3B, 0x3C, 0x3A, 0x3E, 0x3C, 0x3D, 0x3C, 0x3B, 0x3D, 0x3C, 0x3B, 0x3D, + 0x39, 0x39, 0x3B, 0x3B, 0x3B, 0x3B, 0x3C, 0x3D, 0x39, 0x3B, 0x3C, 0x39, 0x3E, 0x39, 0x3C, 0x3C, + 0x3D, 0x3B, 0x3A, 0x3C, 0x3C, 0x3A, 0x3C, 0x3D, 0x3B, 0x3A, 0x3A, 0x3D, 0x3A, 0x3D, 0x3B, 0x38, + 0x3E, 0x39, 0x3D, 0x3C, 0x3B, 0x3D, 0x3C, 0x3C, 0x3C, 0x3D, 0x3B, 0x3A, 0x39, 0x3D, 0x3F, 0x40, + 0x3F, 0x3E, 0x3D, 0x3C, 0x3E, 0x3B, 0x3B, 0x3C, 0x3E, 0x3F, 0x3F, 0x3D, 0x3D, 0x3B, 0x40, 0x41, + 0x40, 0x44, 0x44, 0x47, 0x40, 0x41, 0x40, 0x3F, 0x3E, 0x3D, 0x3D, 0x3D, 0x41, 0x3F, 0x3D, 0x40, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x48, 0x06, 0x10, 0x80, 0x00, 0x48, 0x86, 0x10, 0x80, 0x00, 0x48, 0x06, 0x1F, 0x80, 0x00, + 0x48, 0x86, 0x1F, 0x80, 0x00, 0x48, 0x06, 0x11, 0x80, 0x00, 0x48, 0x86, 0x11, 0x80, 0x00, 0x48, + 0x06, 0x1E, 0x80, 0x00, 0x48, 0x86, 0x1E, 0x80, 0x00, 0x48, 0x06, 0x12, 0x80, 0x00, 0x48, 0x86, + 0x12, 0x80, 0x00, 0x48, 0x06, 0x1D, 0x80, 0x00, 0x48, 0x86, 0x1D, 0x80, 0x00, 0x48, 0x06, 0x13, + 0x80, 0x00, 0x48, 0x86, 0x13, 0x80, 0x00, 0x48, 0x06, 0x1C, 0x80, 0x00, 0x48, 0x86, 0x1C, 0x80, + 0x00, 0x48, 0x06, 0x14, 0x80, 0x00, 0x48, 0x86, 0x14, 0x80, 0x00, 0x48, 0x06, 0x1B, 0x80, 0x00, + 0x48, 0x86, 0x1B, 0x80, 0x00, 0x48, 0x06, 0x15, 0x80, 0x00, 0x48, 0x86, 0x15, 0x80, 0x00, 0x48, + 0x06, 0x1A, 0x80, 0x00, 0x48, 0x86, 0x1A, 0x80, 0x00, 0x48, 0x06, 0x16, 0x80, 0x00, 0x48, 0x86, + 0x16, 0x80, 0x00, 0x48, 0x06, 0x19, 0x80, 0x00, 0x48, 0x86, 0x19, 0x80, 0x00, 0x48, 0x06, 0x17, + 0x80, 0x00, 0x48, 0x86, 0x17, 0x80, 0x00, 0x48, 0x06, 0x18, 0x80, 0x00, 0x48, 0x86, 0x18, 0x80, + 0x20, 0x00, 0x19, 0x04, 0x90, 0x20, 0x00, 0x32, 0x08, 0x87, 0x20, 0x00, 0x32, 0xC8, 0x80, 0x20, + 0x00, 0x32, 0x58, 0x82, 0x20, 0x00, 0x32, 0xE8, 0x83, 0x20, 0x00, 0x32, 0x78, 0x85, 0x20, 0x00, + 0x32, 0x08, 0x87, 0x20, 0x00, 0x19, 0x68, 0x90, 0x20, 0x00, 0x16, 0x00, 0x23, 0x20, 0x00, 0x19, + 0x88, 0x93, 0x20, 0x00, 0x10, 0xFC, 0x1E, 0x20, 0x00, 0x19, 0xF8, 0x91, 0x20, 0x00, 0x16, 0x00, + 0x23, 0x20, 0x00, 0x19, 0x18, 0x95, 0x20, 0x00, 0x10, 0xFC, 0x1E, 0x20, 0x00, 0x19, 0x38, 0x98, + 0x20, 0x00, 0x16, 0x00, 0x23, 0x20, 0x00, 0x10, 0xFC, 0x1E, 0x20, 0x00, 0x32, 0xA8, 0x96, 0x20, + 0x00, 0x32, 0x68, 0x90, 0x20, 0x00, 0x32, 0xF8, 0x91, 0x20, 0x00, 0x32, 0x88, 0x93, 0x20, 0x00, + 0x32, 0x18, 0x95, 0x20, 0x00, 0x32, 0xA8, 0x96, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0xE8, 0x03, 0x05, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0x03, 0x00, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x40, 0x00, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0x00, 0x00, 0x0B, 0x00, 0x0C, 0x00, 0x0D, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x01, 0x03, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x04, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x05, 0x06, 0x03, 0x04, 0x03, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x03, 0x05, 0x05, 0x06, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x01, 0x03, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x05, 0x05, 0x06, 0x02, 0x00, 0x00, 0x02, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x05, 0x05, 0x06, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x07, 0x07, 0x07, 0x07, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x94, 0x8D, 0x03, 0x00, 0x50, 0x8D, 0x03, 0x00, 0x94, 0x8D, 0x03, 0x00, + 0x54, 0x8D, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x04, 0x05, 0x06, 0x07, 0x02, 0x00, 0x00, 0x00, + 0x78, 0x56, 0x34, 0x12, 0x78, 0x56, 0x34, 0x12, 0x01, 0x40, 0x40, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x70, 0xAD, 0x02, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, + 0xAA, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x19, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x1D, 0x00, 0x00, 0x00, + 0x1E, 0x00, 0x00, 0x00, 0x47, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x4B, 0x00, 0x00, 0x00, + 0x52, 0x00, 0x00, 0x00, 0x5E, 0x00, 0x00, 0x00, 0x61, 0x00, 0x00, 0x00, 0x62, 0x00, 0x00, 0x00, + 0x63, 0x00, 0x00, 0x00, 0x6D, 0x00, 0x00, 0x00, 0x72, 0x00, 0x00, 0x00, 0x73, 0x00, 0x00, 0x00, + 0x74, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x1E, 0x01, 0x00, 0x00, 0x21, 0x01, 0x00, 0x00, + 0x2D, 0x01, 0x00, 0x00, 0x3B, 0x01, 0x00, 0x00, 0x48, 0x01, 0x00, 0x00, 0x4B, 0x01, 0x00, 0x00, + 0x6C, 0x01, 0x00, 0x00, 0x78, 0x01, 0x00, 0x00, 0x87, 0x01, 0x00, 0x00, 0x8B, 0x01, 0x00, 0x00, + 0x92, 0x01, 0x00, 0x00, 0x9B, 0x01, 0x00, 0x00, 0xB2, 0x01, 0x00, 0x00, 0xB3, 0x01, 0x00, 0x00, + 0xB4, 0x01, 0x00, 0x00, 0xBB, 0x01, 0x00, 0x00, 0xCB, 0x01, 0x00, 0x00, 0xCC, 0x01, 0x00, 0x00, + 0xD2, 0x01, 0x00, 0x00, 0xE1, 0x01, 0x00, 0x00, 0xE2, 0x01, 0x00, 0x00, 0xE3, 0x01, 0x00, 0x00, + 0xEE, 0x01, 0x00, 0x00, 0x78, 0x04, 0x00, 0x00, 0xB4, 0x04, 0x00, 0x00, 0xBB, 0x04, 0x00, 0x00, + 0xED, 0x04, 0x00, 0x00, 0x21, 0x05, 0x00, 0x00, 0x2D, 0x05, 0x00, 0x00, 0xE1, 0x05, 0x00, 0x00, + 0xEE, 0x05, 0x00, 0x00, 0x1E, 0x06, 0x00, 0x00, 0x4B, 0x06, 0x00, 0x00, 0x6D, 0x06, 0x00, 0x00, + 0xCB, 0x06, 0x00, 0x00, 0xD2, 0x06, 0x00, 0x00, 0xE2, 0x06, 0x00, 0x00, 0xE3, 0x06, 0x00, 0x00, + 0xED, 0x06, 0x00, 0x00, 0x38, 0x07, 0x00, 0x00, 0x4B, 0x07, 0x00, 0x00, 0x87, 0x07, 0x00, 0x00, + 0x8B, 0x07, 0x00, 0x00, 0x8C, 0x07, 0x00, 0x00, 0x8E, 0x07, 0x00, 0x00, 0xB8, 0x07, 0x00, 0x00, + 0xCB, 0x12, 0x00, 0x00, 0xD2, 0x12, 0x00, 0x00, 0xED, 0x12, 0x00, 0x00, 0x8B, 0x13, 0x00, 0x00, + 0x87, 0x17, 0x00, 0x00, 0x9E, 0x17, 0x00, 0x00, 0xB8, 0x17, 0x00, 0x00, 0xED, 0x19, 0x00, 0x00, + 0x4B, 0x1B, 0x00, 0x00, 0x6D, 0x1B, 0x00, 0x00, 0x79, 0x1B, 0x00, 0x00, 0x8B, 0x1B, 0x00, 0x00, + 0x38, 0x1E, 0x00, 0x00, 0x8B, 0x4B, 0x00, 0x00, 0xED, 0x6D, 0x00, 0x00, 0xE2, 0x78, 0x00, 0x00, + 0x10, 0x33, 0x03, 0x00, 0x07, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x05, 0xFA, 0x20, 0x32, 0x40, 0x06, 0x00, 0x0A, 0x0E, 0x0A, 0x00, 0x01, 0x01, 0x01, 0x08, 0x10, + 0x32, 0x00, 0x40, 0x06, 0x28, 0x0A, 0x00, 0x00, 0x00, 0x0C, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x03, 0x76, 0x5F, 0x04, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x01, 0x09, + 0x00, 0x01, 0x32, 0x34, 0x40, 0x06, 0x00, 0x00, 0x28, 0x19, 0x1A, 0x00, 0x00, 0x06, 0x30, 0x00, + 0x00, 0x06, 0x30, 0x00, 0x00, 0x06, 0x30, 0x00, 0x00, 0x06, 0x30, 0x00, 0x00, 0x06, 0x30, 0x00, + 0x00, 0x06, 0x30, 0x00, 0x00, 0x06, 0x30, 0x00, 0x00, 0x06, 0x30, 0x00, 0x80, 0xFF, 0x3F, 0x00, + 0x00, 0x06, 0x30, 0x00, 0x00, 0x06, 0x30, 0x00, 0x00, 0x06, 0x30, 0x00, 0x80, 0xFF, 0x3F, 0x00, + 0x00, 0x06, 0x30, 0x00, 0x00, 0x06, 0x30, 0x00, 0x00, 0x06, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, + 0x01, 0x01, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x0F, 0x00, 0x00, 0x00, 0x01, 0x07, 0x01, 0x03, 0x02, 0x03, 0x14, 0x00, 0x0A, 0x0A, 0x40, 0x00, + 0x02, 0x00, 0x8C, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xC8, 0x00, 0xC8, 0x00, 0x96, 0x00, 0xC8, 0x00, 0x07, 0x07, 0x80, 0x00, 0x80, 0x00, 0x05, 0x05, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x01, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, + 0x30, 0x00, 0x47, 0x00, 0x10, 0x00, 0x14, 0x00, 0xF9, 0xFF, 0xC4, 0xFF, 0xFF, 0x7F, 0xFF, 0x7F, + 0xFF, 0x7F, 0xFF, 0x7F, 0xC8, 0x00, 0x2C, 0x01, 0x32, 0x00, 0xFA, 0x00, 0x0A, 0x04, 0xB4, 0xB4, + 0x32, 0x32, 0x23, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x0D, 0x00, 0x00, 0x32, 0x0D, 0x00, + 0x00, 0x00, 0x00, 0x20, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, + 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x05, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x0F, 0x01, 0x14, 0x12, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0F, 0x23, 0x32, 0x46, 0x50, 0x00, 0x00, 0x00, 0x6A, 0x64, 0x50, 0x46, 0x3C, 0x3C, 0x3C, 0x3C, + 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x23, 0x32, 0x46, 0x50, 0x00, 0x00, 0x00, + 0x6A, 0x64, 0x50, 0x46, 0x3C, 0x3C, 0x3C, 0x3C, 0x0F, 0x14, 0x1E, 0x28, 0x00, 0x00, 0x00, 0x00, + 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0C, 0x19, 0x2D, 0x41, 0x50, 0x00, 0x00, 0x00, + 0x46, 0x55, 0x4B, 0x46, 0x46, 0x46, 0x46, 0x46, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x03, 0x14, 0x00, + 0x5F, 0x00, 0xF1, 0xFF, 0x14, 0x00, 0x0F, 0x00, 0x0A, 0x00, 0xBC, 0x02, 0x00, 0x00, 0x00, 0x00, + 0x78, 0x76, 0x00, 0x1E, 0x64, 0x00, 0x19, 0x00, 0x90, 0x01, 0x28, 0x00, 0x0F, 0x00, 0x0F, 0x00, + 0x68, 0x01, 0x2C, 0x01, 0xF4, 0x01, 0xF8, 0x02, 0x00, 0x00, 0x3F, 0x06, 0x00, 0x00, 0xFF, 0x09, + 0xF4, 0x01, 0x00, 0x00, 0x3F, 0x06, 0x00, 0x00, 0xFF, 0x09, 0x32, 0x14, 0x02, 0x1E, 0x1E, 0x32, + 0x02, 0x00, 0x64, 0x00, 0x46, 0x00, 0x1E, 0x00, 0x0A, 0x00, 0x35, 0x06, 0x0A, 0x00, 0xF5, 0x09, + 0x00, 0x00, 0x00, 0x00, 0x40, 0x06, 0x30, 0x00, 0x10, 0x00, 0x01, 0x00, 0x12, 0x00, 0x00, 0x00, + 0x3A, 0x00, 0x52, 0x00, 0x70, 0x00, 0x8F, 0x00, 0x6E, 0x01, 0x8E, 0x01, 0xAD, 0x01, 0xCE, 0x01, + 0xEC, 0x01, 0xAC, 0x02, 0xCC, 0x02, 0xEB, 0x02, 0x0B, 0x03, 0x2B, 0x03, 0xE7, 0x03, 0xFF, 0x03, + 0x37, 0x04, 0x28, 0x0A, 0x30, 0x00, 0x30, 0x00, 0x01, 0x00, 0x32, 0x00, 0x00, 0x00, 0x3C, 0x00, + 0x43, 0x00, 0x66, 0x00, 0x85, 0x00, 0xA9, 0x00, 0xC8, 0x00, 0xE9, 0x00, 0x09, 0x01, 0x2A, 0x01, + 0x6B, 0x01, 0x89, 0x01, 0xAB, 0x01, 0xC9, 0x01, 0xEB, 0x01, 0x09, 0x02, 0x2B, 0x02, 0x4A, 0x02, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x20, 0x00, 0x19, 0x45, 0x00, 0x00, 0xF1, 0x6C, 0x00, 0x00, + 0x84, 0xD9, 0x06, 0x00, 0x29, 0xB1, 0x01, 0x00, 0x10, 0x27, 0x00, 0x00, 0xC4, 0x09, 0x00, 0x00, + 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x01, 0x4B, 0x0F, 0x00, 0xB4, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, + 0x19, 0x45, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0xA4, 0x6B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x14, 0x14, 0x0A, 0x0A, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x14, 0x14, 0x14, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x40, 0x00, 0x32, 0x00, 0xE8, 0x03, 0x0F, 0x00, 0x08, 0x00, + 0xE1, 0x00, 0x64, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x0A, 0x00, 0x14, 0x0A, 0x1E, 0x3C, 0x28, 0x00, + 0xB4, 0x00, 0xFA, 0x00, 0x28, 0x64, 0x19, 0x64, 0x00, 0x00, 0x00, 0x00, 0xB4, 0x00, 0xFA, 0x00, + 0x1C, 0x02, 0x84, 0x03, 0x00, 0x00, 0x00, 0x01, 0x4F, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x78, 0x00, 0x0D, 0x0D, 0x0C, 0x0E, 0x46, 0x00, 0x32, 0x00, 0x64, 0x00, 0x0A, 0x00, 0x32, 0x00, + 0x64, 0x00, 0x32, 0x00, 0x64, 0x00, 0x0F, 0x02, 0xE8, 0xE8, 0xF8, 0x00, 0xF8, 0x00, 0x02, 0x00, + 0x19, 0x00, 0x00, 0x00, 0xA5, 0x00, 0xB3, 0x00, 0xC3, 0x00, 0xD4, 0x00, 0xE7, 0x00, 0xFA, 0x00, + 0x0F, 0x01, 0x26, 0x01, 0x3E, 0x01, 0x57, 0x01, 0x72, 0x01, 0x8F, 0x01, 0xAE, 0x01, 0xCF, 0x01, + 0xF1, 0x01, 0x16, 0x02, 0x3C, 0x02, 0x65, 0x02, 0x90, 0x02, 0xBD, 0x02, 0xED, 0x02, 0x1E, 0x03, + 0x52, 0x03, 0x89, 0x03, 0xC2, 0x03, 0xFE, 0x03, 0x3C, 0x04, 0x7C, 0x04, 0xBF, 0x04, 0x05, 0x05, + 0x4D, 0x05, 0x98, 0x05, 0xE5, 0x05, 0x35, 0x06, 0x87, 0x06, 0xDB, 0x06, 0x32, 0x07, 0x8A, 0x07, + 0xE5, 0x07, 0x42, 0x08, 0xA1, 0x08, 0x01, 0x09, 0x63, 0x09, 0xC7, 0x09, 0x2C, 0x0A, 0x92, 0x0A, + 0xF9, 0x0A, 0x60, 0x0B, 0xC8, 0x0B, 0x31, 0x0C, 0x9A, 0x0C, 0x02, 0x0D, 0x6B, 0x0D, 0xD2, 0x0D, + 0x39, 0x0E, 0x9F, 0x0E, 0x04, 0x0F, 0x67, 0x0F, 0xC8, 0x0F, 0x27, 0x10, 0x84, 0x10, 0xDE, 0x10, + 0x35, 0x11, 0x89, 0x11, 0xDA, 0x11, 0x28, 0x12, 0x71, 0x12, 0xB7, 0x12, 0xF8, 0x12, 0x35, 0x13, + 0x6D, 0x13, 0xA0, 0x13, 0xCF, 0x13, 0xF8, 0x13, 0x1C, 0x14, 0x3B, 0x14, 0x54, 0x14, 0x68, 0x14, + 0x76, 0x14, 0x7E, 0x14, 0x81, 0x14, 0xA5, 0x00, 0xB3, 0x00, 0xC3, 0x00, 0xD4, 0x00, 0xE7, 0x00, + 0xFA, 0x00, 0x0F, 0x01, 0x26, 0x01, 0x3E, 0x01, 0x57, 0x01, 0x72, 0x01, 0x8F, 0x01, 0xAE, 0x01, + 0xCF, 0x01, 0xF1, 0x01, 0x16, 0x02, 0x3C, 0x02, 0x65, 0x02, 0x90, 0x02, 0xBD, 0x02, 0xED, 0x02, + 0x1E, 0x03, 0x52, 0x03, 0x89, 0x03, 0xC2, 0x03, 0xFE, 0x03, 0x3C, 0x04, 0x7C, 0x04, 0xBF, 0x04, + 0x05, 0x05, 0x4D, 0x05, 0x98, 0x05, 0xE5, 0x05, 0x35, 0x06, 0x87, 0x06, 0xDB, 0x06, 0x32, 0x07, + 0x8A, 0x07, 0xE5, 0x07, 0x42, 0x08, 0xA1, 0x08, 0x01, 0x09, 0x63, 0x09, 0xC7, 0x09, 0x2C, 0x0A, + 0x92, 0x0A, 0xF9, 0x0A, 0x60, 0x0B, 0xC8, 0x0B, 0x31, 0x0C, 0x9A, 0x0C, 0x02, 0x0D, 0x6B, 0x0D, + 0xD2, 0x0D, 0x39, 0x0E, 0x9F, 0x0E, 0x04, 0x0F, 0x67, 0x0F, 0xC8, 0x0F, 0x27, 0x10, 0x84, 0x10, + 0xDE, 0x10, 0x35, 0x11, 0x89, 0x11, 0xDA, 0x11, 0x28, 0x12, 0x71, 0x12, 0xB7, 0x12, 0xF8, 0x12, + 0x35, 0x13, 0x6D, 0x13, 0xA0, 0x13, 0xCF, 0x13, 0xF8, 0x13, 0x1C, 0x14, 0x3B, 0x14, 0x54, 0x14, + 0x68, 0x14, 0x76, 0x14, 0x7E, 0x14, 0x81, 0x14, 0xA5, 0x00, 0xB3, 0x00, 0xC3, 0x00, 0xD4, 0x00, + 0xE7, 0x00, 0xFA, 0x00, 0x0F, 0x01, 0x26, 0x01, 0x3E, 0x01, 0x57, 0x01, 0x72, 0x01, 0x8F, 0x01, + 0xAE, 0x01, 0xCF, 0x01, 0xF1, 0x01, 0x16, 0x02, 0x3C, 0x02, 0x65, 0x02, 0x90, 0x02, 0xBD, 0x02, + 0xED, 0x02, 0x1E, 0x03, 0x52, 0x03, 0x89, 0x03, 0xC2, 0x03, 0xFE, 0x03, 0x3C, 0x04, 0x7C, 0x04, + 0xBF, 0x04, 0x05, 0x05, 0x4D, 0x05, 0x98, 0x05, 0xE5, 0x05, 0x35, 0x06, 0x87, 0x06, 0xDB, 0x06, + 0x32, 0x07, 0x8A, 0x07, 0xE5, 0x07, 0x42, 0x08, 0xA1, 0x08, 0x01, 0x09, 0x63, 0x09, 0xC7, 0x09, + 0x2C, 0x0A, 0x92, 0x0A, 0xF9, 0x0A, 0x60, 0x0B, 0xC8, 0x0B, 0x31, 0x0C, 0x9A, 0x0C, 0x02, 0x0D, + 0x6B, 0x0D, 0xD2, 0x0D, 0x39, 0x0E, 0x9F, 0x0E, 0x04, 0x0F, 0x67, 0x0F, 0xC8, 0x0F, 0x27, 0x10, + 0x84, 0x10, 0xDE, 0x10, 0x35, 0x11, 0x89, 0x11, 0xDA, 0x11, 0x28, 0x12, 0x71, 0x12, 0xB7, 0x12, + 0xF8, 0x12, 0x35, 0x13, 0x6D, 0x13, 0xA0, 0x13, 0xCF, 0x13, 0xF8, 0x13, 0x1C, 0x14, 0x3B, 0x14, + 0x54, 0x14, 0x68, 0x14, 0x76, 0x14, 0x7E, 0x14, 0x81, 0x14, 0xA5, 0x00, 0xB3, 0x00, 0xC3, 0x00, + 0xD4, 0x00, 0xE7, 0x00, 0xFA, 0x00, 0x0F, 0x01, 0x26, 0x01, 0x3E, 0x01, 0x57, 0x01, 0x72, 0x01, + 0x8F, 0x01, 0xAE, 0x01, 0xCF, 0x01, 0xF1, 0x01, 0x16, 0x02, 0x3C, 0x02, 0x65, 0x02, 0x90, 0x02, + 0xBD, 0x02, 0xED, 0x02, 0x1E, 0x03, 0x52, 0x03, 0x89, 0x03, 0xC2, 0x03, 0xFE, 0x03, 0x3C, 0x04, + 0x7C, 0x04, 0xBF, 0x04, 0x05, 0x05, 0x4D, 0x05, 0x98, 0x05, 0xE5, 0x05, 0x35, 0x06, 0x87, 0x06, + 0xDB, 0x06, 0x32, 0x07, 0x8A, 0x07, 0xE5, 0x07, 0x42, 0x08, 0xA1, 0x08, 0x01, 0x09, 0x63, 0x09, + 0xC7, 0x09, 0x2C, 0x0A, 0x92, 0x0A, 0xF9, 0x0A, 0x60, 0x0B, 0xC8, 0x0B, 0x31, 0x0C, 0x9A, 0x0C, + 0x02, 0x0D, 0x6B, 0x0D, 0xD2, 0x0D, 0x39, 0x0E, 0x9F, 0x0E, 0x04, 0x0F, 0x67, 0x0F, 0xC8, 0x0F, + 0x27, 0x10, 0x84, 0x10, 0xDE, 0x10, 0x35, 0x11, 0x89, 0x11, 0xDA, 0x11, 0x28, 0x12, 0x71, 0x12, + 0xB7, 0x12, 0xF8, 0x12, 0x35, 0x13, 0x6D, 0x13, 0xA0, 0x13, 0xCF, 0x13, 0xF8, 0x13, 0x1C, 0x14, + 0x3B, 0x14, 0x54, 0x14, 0x68, 0x14, 0x76, 0x14, 0x7E, 0x14, 0x81, 0x14, 0x55, 0x00, 0x55, 0x00, + 0x45, 0x00, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB4, 0x00, 0x18, 0x01, 0x32, 0x00, 0x05, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4E, 0x56, 0x54, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x1F, 0x49, 0xFF, +}; + +static const uint8_t FW_17951_NT36672C_JDI[] = +{ + 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC3, 0x32, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, + 0x40, 0x70, 0x02, 0x00, 0x6F, 0x44, 0x00, 0x00, 0x40, 0xD7, 0x31, 0xA7, 0x12, 0xB8, 0x8D, 0x7F, + 0x00, 0x00, 0x00, 0x00, 0xC0, 0x07, 0x55, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x70, 0x8F, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x9F, 0x01, 0x00, 0x6D, 0x99, 0x4B, 0x43, + 0x70, 0x7B, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x8B, 0x01, 0x00, 0xDF, 0xD4, 0xCD, 0x59, + 0x70, 0x99, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0xA9, 0x01, 0x00, 0xDF, 0xD4, 0xCD, 0x59, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xB0, 0xB4, 0x02, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x72, 0x0F, 0x05, 0xA4, + 0x48, 0x00, 0x01, 0xEA, 0x40, 0x00, 0x00, 0x09, 0x40, 0x00, 0x00, 0x09, 0x40, 0x00, 0x00, 0x09, + 0x3A, 0xFF, 0xBF, 0xFC, 0x3A, 0x0F, 0xA8, 0x3C, 0x44, 0x00, 0x00, 0x01, 0x48, 0x00, 0x01, 0x90, + 0x3A, 0xFF, 0xBF, 0xFC, 0x3A, 0x0F, 0xA8, 0x3C, 0x44, 0x00, 0x00, 0x02, 0x48, 0x00, 0x01, 0x88, + 0x3A, 0xFF, 0xBF, 0xFC, 0x3A, 0x0F, 0xA8, 0x3C, 0x44, 0x00, 0x00, 0x03, 0x48, 0x00, 0x01, 0x80, + 0x3A, 0xFF, 0xBF, 0xFC, 0x3A, 0x0F, 0xA8, 0x3C, 0x44, 0x00, 0x00, 0x04, 0x48, 0x00, 0x01, 0x78, + 0x3A, 0xFF, 0xBF, 0xFC, 0x3A, 0x0F, 0xA8, 0x3C, 0x44, 0x00, 0x00, 0x05, 0x48, 0x00, 0x01, 0x70, + 0x3A, 0xFF, 0xBF, 0xFC, 0x3A, 0x0F, 0xA8, 0x3C, 0x44, 0x00, 0x00, 0x06, 0x48, 0x00, 0x01, 0x68, + 0x3A, 0xFF, 0xBF, 0xFC, 0x3A, 0x0F, 0xA8, 0x3C, 0x44, 0x00, 0x00, 0x07, 0x48, 0x00, 0x01, 0x60, + 0x48, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x09, 0x40, 0x00, 0x00, 0x09, 0x40, 0x00, 0x00, 0x09, + 0x3A, 0xFF, 0xBC, 0xBC, 0x3A, 0x0F, 0x94, 0x3C, 0x44, 0x00, 0x00, 0x00, 0x48, 0x00, 0x01, 0x71, + 0x3A, 0xFF, 0xBC, 0xBC, 0x3A, 0x0F, 0x94, 0x3C, 0x44, 0x00, 0x00, 0x01, 0x48, 0x00, 0x01, 0x74, + 0x3A, 0xFF, 0xBC, 0xBC, 0x3A, 0x0F, 0x94, 0x3C, 0x44, 0x00, 0x00, 0x02, 0x48, 0x00, 0x01, 0x6C, + 0x3A, 0xFF, 0xBC, 0xBC, 0x3A, 0x0F, 0x94, 0x3C, 0x44, 0x00, 0x00, 0x03, 0x48, 0x00, 0x01, 0x59, + 0x3A, 0xFF, 0xBC, 0xBC, 0x3A, 0x0F, 0x94, 0x3C, 0x44, 0x00, 0x00, 0x04, 0x48, 0x00, 0x01, 0x5C, + 0x3A, 0xFF, 0xBC, 0xBC, 0x3A, 0x0F, 0x94, 0x3C, 0x44, 0x00, 0x00, 0x05, 0x48, 0x00, 0x01, 0x49, + 0x3A, 0xFF, 0xBC, 0xBC, 0x3A, 0x0F, 0x94, 0x3C, 0x44, 0x00, 0x00, 0x06, 0x48, 0x00, 0x01, 0x41, + 0x3A, 0xFF, 0xBC, 0xBC, 0x3A, 0x0F, 0x94, 0x3C, 0x44, 0x00, 0x00, 0x07, 0x48, 0x00, 0x01, 0x39, + 0x3A, 0xFF, 0xBC, 0xBC, 0x3A, 0x0F, 0x94, 0x3C, 0x44, 0x00, 0x00, 0x08, 0x48, 0x00, 0x01, 0x31, + 0x3A, 0xFF, 0xBC, 0xBC, 0x3A, 0x0F, 0x94, 0x3C, 0x44, 0x00, 0x00, 0x09, 0x48, 0x00, 0x01, 0x29, + 0x3A, 0xFF, 0xBC, 0xBC, 0x3A, 0x0F, 0x94, 0x3C, 0x44, 0x00, 0x00, 0x0A, 0x48, 0x00, 0x01, 0x21, + 0x3A, 0xFF, 0xBC, 0xBC, 0x3A, 0x0F, 0x94, 0x3C, 0x44, 0x00, 0x00, 0x0B, 0x48, 0x00, 0x01, 0x19, + 0x3A, 0xFF, 0xBC, 0xBC, 0x3A, 0x0F, 0x94, 0x3C, 0x44, 0x00, 0x00, 0x0C, 0x48, 0x00, 0x01, 0x11, + 0x3A, 0xFF, 0xBC, 0xBC, 0x3A, 0x0F, 0x94, 0x3C, 0x44, 0x00, 0x00, 0x0D, 0x48, 0x00, 0x01, 0x09, + 0x3A, 0xFF, 0xBC, 0xBC, 0x3A, 0x0F, 0x94, 0x3C, 0x44, 0x00, 0x00, 0x0E, 0x48, 0x00, 0x01, 0x01, + 0x3A, 0xFF, 0xBC, 0xBC, 0x3A, 0x0F, 0x94, 0x3C, 0x44, 0x00, 0x00, 0x0F, 0x48, 0x00, 0x01, 0x04, + 0x3A, 0xFF, 0xBC, 0xBC, 0x3A, 0x0F, 0x94, 0x3C, 0x44, 0x00, 0x00, 0x10, 0x48, 0x00, 0x00, 0xFC, + 0x3A, 0xFF, 0xBC, 0xBC, 0x3A, 0x0F, 0x94, 0x3C, 0x44, 0x00, 0x00, 0x11, 0x48, 0x00, 0x00, 0xE9, + 0x3A, 0xFF, 0xBC, 0xBC, 0x3A, 0x0F, 0x94, 0x3C, 0x44, 0x00, 0x00, 0x12, 0x48, 0x00, 0x00, 0xE1, + 0x3A, 0xFF, 0xBC, 0xBC, 0x3A, 0x0F, 0x94, 0x3C, 0x44, 0x00, 0x00, 0x13, 0x48, 0x00, 0x00, 0xD9, + 0x3A, 0xFF, 0xBC, 0xBC, 0x3A, 0x0F, 0x94, 0x3C, 0x44, 0x00, 0x00, 0x14, 0x48, 0x00, 0x00, 0xDC, + 0x3A, 0xFF, 0xBC, 0xBC, 0x3A, 0x0F, 0x94, 0x3C, 0x44, 0x00, 0x00, 0x15, 0x48, 0x00, 0x00, 0xD4, + 0x3A, 0xFF, 0xBC, 0xBC, 0x3A, 0x0F, 0x94, 0x3C, 0x44, 0x00, 0x00, 0x16, 0x48, 0x00, 0x00, 0xC1, + 0x3A, 0xFF, 0xBC, 0xBC, 0x3A, 0x0F, 0x94, 0x3C, 0x44, 0x00, 0x00, 0x17, 0x48, 0x00, 0x00, 0xB9, + 0x3A, 0xFF, 0xBC, 0xBC, 0x3A, 0x0F, 0x94, 0x3C, 0x44, 0x00, 0x00, 0x18, 0x48, 0x00, 0x00, 0xB1, + 0x3A, 0xFF, 0xBC, 0xBC, 0x3A, 0x0F, 0x94, 0x3C, 0x44, 0x00, 0x00, 0x19, 0x48, 0x00, 0x00, 0xA9, + 0x3A, 0xFF, 0xBC, 0xBC, 0x3A, 0x0F, 0x94, 0x3C, 0x44, 0x00, 0x00, 0x1A, 0x48, 0x00, 0x00, 0xA1, + 0x3A, 0xFF, 0xBC, 0xBC, 0x3A, 0x0F, 0x94, 0x3C, 0x44, 0x00, 0x00, 0x1B, 0x48, 0x00, 0x00, 0x99, + 0x3A, 0xFF, 0xBC, 0xBC, 0x3A, 0x0F, 0x94, 0x3C, 0x44, 0x00, 0x00, 0x1C, 0x48, 0x00, 0x00, 0x91, + 0x3A, 0xFF, 0xBC, 0xBC, 0x3A, 0x0F, 0x94, 0x3C, 0x44, 0x00, 0x00, 0x1D, 0x48, 0x00, 0x00, 0x89, + 0x3A, 0xFF, 0xBC, 0xBC, 0x3A, 0x0F, 0x94, 0x3C, 0x44, 0x00, 0x00, 0x1E, 0x48, 0x00, 0x00, 0x81, + 0x3A, 0xFF, 0xBC, 0xBC, 0x3A, 0x0F, 0x94, 0x3C, 0x44, 0x00, 0x00, 0x1F, 0x48, 0x00, 0x00, 0x79, + 0x80, 0x28, 0x01, 0x00, 0x80, 0x28, 0x01, 0x00, 0xDE, 0x28, 0x01, 0x00, 0x92, 0x2F, 0x01, 0x00, + 0x92, 0x2F, 0x01, 0x00, 0x92, 0x2F, 0x01, 0x00, 0x92, 0x2F, 0x01, 0x00, 0x92, 0x2F, 0x01, 0x00, + 0x92, 0x2F, 0x01, 0x00, 0x92, 0x2F, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC2, 0x2A, 0x01, 0x00, + 0xCA, 0x2A, 0x01, 0x00, 0xD6, 0x2A, 0x01, 0x00, 0x62, 0x2B, 0x01, 0x00, 0xA2, 0x2B, 0x01, 0x00, + 0x24, 0x2C, 0x01, 0x00, 0xA8, 0x2C, 0x01, 0x00, 0xD2, 0x2C, 0x01, 0x00, 0xDA, 0x2C, 0x01, 0x00, + 0xE2, 0x2C, 0x01, 0x00, 0xEA, 0x2C, 0x01, 0x00, 0xF2, 0x2C, 0x01, 0x00, 0x0C, 0x2D, 0x01, 0x00, + 0x14, 0x2D, 0x01, 0x00, 0x28, 0x2D, 0x01, 0x00, 0x4A, 0x2D, 0x01, 0x00, 0x92, 0x2D, 0x01, 0x00, + 0x9E, 0x2D, 0x01, 0x00, 0xEE, 0x2D, 0x01, 0x00, 0xF6, 0x2D, 0x01, 0x00, 0x48, 0x2E, 0x01, 0x00, + 0x62, 0x2E, 0x01, 0x00, 0x7C, 0x2E, 0x01, 0x00, 0xA6, 0x2E, 0x01, 0x00, 0xF0, 0x2E, 0x01, 0x00, + 0x38, 0x2F, 0x01, 0x00, 0x40, 0x2F, 0x01, 0x00, 0x42, 0x2F, 0x01, 0x00, 0x4A, 0x2F, 0x01, 0x00, + 0x4C, 0x2F, 0x01, 0x00, 0x82, 0x2F, 0x01, 0x00, 0x8A, 0x2F, 0x01, 0x00, 0x64, 0x12, 0xA4, 0x02, + 0x64, 0x22, 0x04, 0x02, 0x3A, 0x1F, 0x88, 0x3C, 0x80, 0x3F, 0x44, 0x20, 0x02, 0x98, 0x38, 0x21, + 0x02, 0x02, 0x64, 0x32, 0x00, 0x02, 0x9E, 0xD9, 0x64, 0x32, 0x00, 0x03, 0xDD, 0x22, 0x64, 0x02, + 0x00, 0x43, 0x64, 0x00, 0x00, 0x08, 0x3A, 0x1F, 0x88, 0x04, 0x64, 0x12, 0xA4, 0x03, 0x64, 0x22, + 0x04, 0x03, 0x3A, 0x0F, 0xA8, 0x04, 0x3A, 0xFF, 0xBF, 0xC4, 0x64, 0x00, 0x00, 0x04, 0x44, 0x20, + 0x02, 0xBC, 0x38, 0x21, 0x02, 0x02, 0xDD, 0x22, 0x3A, 0x0F, 0x94, 0x04, 0x3A, 0xFF, 0xBC, 0x84, + 0x64, 0x00, 0x00, 0x04, 0x64, 0x12, 0xA4, 0x02, 0x64, 0x22, 0x04, 0x02, 0x3A, 0x1F, 0x88, 0x3C, + 0x44, 0x20, 0x02, 0xBC, 0x38, 0x21, 0x02, 0x02, 0x64, 0x32, 0x00, 0x02, 0x9E, 0xD9, 0x64, 0x32, + 0x00, 0x03, 0xDD, 0x22, 0x64, 0x02, 0x00, 0x43, 0x64, 0x00, 0x00, 0x08, 0x3A, 0x1F, 0x88, 0x04, + 0x64, 0x12, 0xA4, 0x03, 0x64, 0x22, 0x04, 0x03, 0x3A, 0x0F, 0x94, 0x04, 0x3A, 0xFF, 0xBC, 0x84, + 0x64, 0x00, 0x00, 0x04, 0x4F, 0xF2, 0x00, 0x1D, 0x3A, 0x0F, 0xA8, 0x3C, 0x3A, 0xFF, 0xBF, 0xFC, + 0x45, 0xD2, 0xC8, 0xB8, 0x80, 0x1F, 0x64, 0x12, 0x64, 0x02, 0x96, 0x5F, 0x9E, 0x49, 0xC1, 0x05, + 0x3C, 0xFD, 0x4E, 0x76, 0x48, 0x00, 0x00, 0x04, 0x3C, 0xFD, 0x4E, 0x77, 0xE8, 0x09, 0xDD, 0x2F, + 0xC8, 0x07, 0x3A, 0xFF, 0xBF, 0xC4, 0x3A, 0x0F, 0xA8, 0x04, 0x64, 0x00, 0x00, 0x04, 0x64, 0x02, + 0x24, 0x02, 0x44, 0x1F, 0x3F, 0xFF, 0xFE, 0x0E, 0x58, 0x00, 0x40, 0x00, 0x64, 0x02, 0x24, 0x03, + 0x64, 0x00, 0x00, 0x08, 0x45, 0xD2, 0xC8, 0xB8, 0x45, 0xF3, 0x00, 0x00, 0x44, 0xF1, 0x28, 0x38, + 0x4E, 0xF2, 0x00, 0x03, 0xDD, 0x2F, 0x3C, 0xFD, 0x4E, 0x78, 0xDD, 0x2F, 0x64, 0x0F, 0xFF, 0xEA, + 0x3C, 0x0F, 0xFB, 0x8F, 0xDD, 0x9E, 0x3C, 0x0F, 0xFB, 0x8E, 0xDD, 0x9E, 0xFC, 0x00, 0xC0, 0x08, + 0x5A, 0x08, 0x01, 0x0B, 0x49, 0x00, 0x33, 0x1D, 0x3C, 0x0F, 0xFB, 0x91, 0xD5, 0x05, 0x49, 0x00, + 0x33, 0x15, 0x3C, 0x0F, 0xFB, 0x90, 0xFC, 0x80, 0x80, 0x20, 0xE6, 0x29, 0x3C, 0x0D, 0xFB, 0x91, + 0xE8, 0x25, 0x44, 0xF0, 0x04, 0x80, 0x38, 0x17, 0x84, 0x00, 0x40, 0xF0, 0xBC, 0x00, 0xDD, 0x0F, + 0x0A, 0x3C, 0x10, 0x16, 0x1C, 0x22, 0x28, 0x2E, 0x34, 0x00, 0x3C, 0x0D, 0xFB, 0x90, 0xDD, 0x9E, + 0x50, 0x00, 0x00, 0x50, 0xDD, 0x9E, 0x50, 0x00, 0x00, 0xA0, 0xDD, 0x9E, 0x50, 0x00, 0x00, 0xF0, + 0xDD, 0x9E, 0x50, 0x00, 0x01, 0x40, 0xDD, 0x9E, 0x50, 0x00, 0x01, 0xE0, 0xDD, 0x9E, 0x50, 0x00, + 0x02, 0x80, 0xDD, 0x9E, 0x50, 0x00, 0x03, 0x20, 0xDD, 0x9E, 0x84, 0x00, 0xDD, 0x9E, 0x92, 0x00, + 0xFC, 0x45, 0x81, 0x22, 0x80, 0xC1, 0x3C, 0x2D, 0xFB, 0x91, 0x3C, 0x1D, 0xFB, 0x90, 0xF0, 0x84, + 0x80, 0xE3, 0x81, 0x44, 0x49, 0x00, 0x32, 0xAD, 0x3C, 0x1D, 0xFB, 0x8E, 0xA6, 0x0A, 0xA6, 0x4B, + 0x49, 0x00, 0x32, 0xCB, 0x5C, 0xF4, 0x81, 0x00, 0x80, 0x09, 0xE9, 0x03, 0x44, 0x00, 0x00, 0xFF, + 0x96, 0x01, 0x49, 0x00, 0x32, 0xD5, 0x85, 0x20, 0x3C, 0x1D, 0xFB, 0x8F, 0x00, 0x00, 0x80, 0x10, + 0xE3, 0x20, 0xE8, 0x11, 0x80, 0x09, 0x38, 0x10, 0xA4, 0x00, 0x49, 0x00, 0x32, 0xD7, 0x3C, 0x0D, + 0xFB, 0x8F, 0x40, 0x10, 0x24, 0x00, 0x80, 0x09, 0x00, 0x10, 0x80, 0x08, 0x49, 0x00, 0x32, 0xF6, + 0x8D, 0x21, 0xD5, 0xEB, 0x84, 0x00, 0x49, 0x00, 0x32, 0xBF, 0x49, 0x00, 0x32, 0x95, 0x84, 0x01, + 0x49, 0x00, 0x32, 0xBA, 0x49, 0x00, 0x32, 0x90, 0x5A, 0xA8, 0x01, 0x07, 0x84, 0x02, 0x49, 0x00, + 0x32, 0xB3, 0x49, 0x00, 0x32, 0x89, 0x84, 0x03, 0x49, 0x00, 0x32, 0xAE, 0x49, 0x00, 0x32, 0x84, + 0x49, 0x00, 0x32, 0xA2, 0xAE, 0x38, 0x2E, 0x07, 0xC6, 0xBA, 0xF0, 0x81, 0x84, 0x00, 0x3E, 0x00, + 0x05, 0xA1, 0x2E, 0x00, 0x06, 0x2D, 0x5A, 0x00, 0x01, 0x05, 0x84, 0x00, 0x48, 0x00, 0x00, 0xD7, + 0xA6, 0x78, 0xE6, 0x22, 0xE9, 0xFB, 0x3C, 0x1C, 0x02, 0x13, 0x46, 0x27, 0xFF, 0xFF, 0xF1, 0x82, + 0x50, 0x21, 0x0F, 0xFF, 0x84, 0x20, 0x83, 0xC1, 0xF2, 0x87, 0x10, 0x0F, 0x80, 0x27, 0xA6, 0x38, + 0x40, 0xFF, 0x00, 0x06, 0xE8, 0xEB, 0x50, 0x0F, 0x00, 0x01, 0xF0, 0x85, 0x94, 0x09, 0xF0, 0x88, + 0xF0, 0x05, 0x04, 0x9F, 0x80, 0x05, 0x94, 0x01, 0xF0, 0x83, 0xA6, 0x38, 0xE3, 0x20, 0x4E, 0xF2, + 0x00, 0xAC, 0x04, 0x83, 0x00, 0x01, 0x38, 0x04, 0x04, 0x01, 0xF0, 0x86, 0x4C, 0x0F, 0x40, 0x9F, + 0xF0, 0x03, 0x89, 0x00, 0x02, 0x54, 0x00, 0x00, 0x4C, 0x54, 0xC0, 0x99, 0x4D, 0xE4, 0x80, 0x97, + 0xA0, 0xF4, 0xF2, 0x03, 0x40, 0xA1, 0x84, 0x00, 0x88, 0x62, 0x00, 0x05, 0x00, 0x01, 0xA6, 0x99, + 0x9B, 0x02, 0x4E, 0x44, 0x00, 0x03, 0xFF, 0x22, 0x97, 0x20, 0xE6, 0x83, 0xE8, 0x0F, 0x00, 0x05, + 0x00, 0x00, 0xA6, 0x98, 0x8A, 0x02, 0x4E, 0x04, 0x00, 0x03, 0xFE, 0x02, 0xE4, 0x03, 0xE8, 0x7E, + 0x02, 0x0F, 0x80, 0x0C, 0x12, 0x04, 0x00, 0x00, 0xD5, 0x79, 0xE6, 0x85, 0xE8, 0x77, 0xE2, 0x02, + 0xE8, 0x28, 0x00, 0x45, 0x00, 0x00, 0x04, 0x8F, 0x80, 0x01, 0x85, 0xE0, 0x42, 0x02, 0x20, 0x73, + 0xF4, 0x04, 0x8C, 0x01, 0x38, 0x42, 0x01, 0x11, 0x4E, 0x45, 0x00, 0x0A, 0x44, 0x00, 0x00, 0x64, + 0xFF, 0x04, 0xF0, 0x02, 0x38, 0x00, 0x04, 0x01, 0x40, 0xF2, 0x01, 0xF6, 0xA6, 0x18, 0xF4, 0x01, + 0x42, 0x20, 0x10, 0x73, 0xF0, 0x07, 0x88, 0x40, 0xF0, 0x04, 0x38, 0x00, 0x09, 0x11, 0x4E, 0x05, + 0x00, 0x37, 0x44, 0x20, 0x00, 0x64, 0xFE, 0x14, 0xF2, 0x02, 0x38, 0x21, 0x15, 0x01, 0xD5, 0x27, + 0xA7, 0x18, 0x04, 0x8F, 0x80, 0x01, 0x85, 0xE0, 0x42, 0x22, 0x20, 0x73, 0xF4, 0x04, 0x8C, 0x41, + 0x38, 0x42, 0x09, 0x11, 0x4E, 0x45, 0x00, 0x0A, 0x44, 0x20, 0x00, 0x64, 0xFF, 0x14, 0xF2, 0x02, + 0x38, 0x21, 0x15, 0x01, 0x40, 0xF2, 0x09, 0xF6, 0x00, 0x25, 0x00, 0x00, 0xF4, 0x01, 0x42, 0x01, + 0x10, 0x73, 0xF2, 0x07, 0x88, 0x02, 0xF2, 0x04, 0x38, 0x01, 0x01, 0x11, 0x4E, 0x05, 0x00, 0x10, + 0x44, 0x20, 0x00, 0x64, 0xFE, 0x14, 0xF2, 0x02, 0x38, 0x21, 0x04, 0x01, 0x5C, 0xF7, 0x80, 0x41, + 0x40, 0x00, 0x08, 0x16, 0xE9, 0x04, 0x5C, 0xF0, 0x00, 0x41, 0xE8, 0x20, 0xA0, 0x35, 0xF2, 0x08, + 0x95, 0x6A, 0x00, 0xA5, 0x00, 0x00, 0xA6, 0xD8, 0x99, 0x02, 0x88, 0xA0, 0x40, 0x35, 0x0C, 0x01, + 0xA6, 0xA1, 0xA6, 0x29, 0xA7, 0x20, 0xA7, 0x68, 0x4E, 0x34, 0x00, 0x03, 0xFE, 0xDA, 0xE4, 0x63, + 0xE8, 0x0D, 0x8A, 0x44, 0x96, 0x90, 0xE6, 0x43, 0xE9, 0x05, 0x8A, 0x05, 0x96, 0x00, 0xE6, 0x03, + 0xE8, 0x05, 0x00, 0x0F, 0x80, 0x27, 0x3E, 0x00, 0x05, 0xA1, 0xF0, 0x03, 0x8D, 0x21, 0x8C, 0x02, + 0xF0, 0x83, 0x48, 0xFF, 0xFF, 0x54, 0x8C, 0x22, 0x05, 0xEF, 0x80, 0x05, 0x48, 0xFF, 0xFF, 0x41, + 0xA0, 0x71, 0x38, 0x50, 0x81, 0x01, 0xD8, 0x06, 0x8C, 0x01, 0xA6, 0x78, 0xE2, 0x01, 0xE9, 0xF9, + 0xD5, 0x24, 0xA0, 0xB5, 0x94, 0x42, 0x95, 0x6A, 0x98, 0xD1, 0x88, 0x45, 0xA6, 0xDA, 0xA7, 0x12, + 0xE2, 0x64, 0xE8, 0x02, 0xAE, 0xD2, 0xA0, 0xB5, 0x98, 0xD1, 0x88, 0x45, 0xA6, 0xDB, 0xA7, 0x13, + 0xE2, 0x83, 0xE8, 0x02, 0xAE, 0xD3, 0xA0, 0xB5, 0x38, 0x31, 0x04, 0x00, 0x88, 0x45, 0xA7, 0x10, + 0xE2, 0x64, 0xE8, 0x02, 0xAE, 0xD0, 0xA0, 0xB5, 0x88, 0x22, 0x88, 0xA2, 0xA6, 0x49, 0xA6, 0xA9, + 0xE2, 0x41, 0xE8, 0xDB, 0xAE, 0x69, 0xD5, 0xD9, 0xFC, 0xC5, 0x3C, 0x0F, 0xFB, 0xDD, 0xDD, 0x9E, + 0x3C, 0x0F, 0xFB, 0xDC, 0xDD, 0x9E, 0xFC, 0x44, 0x8E, 0x21, 0xF1, 0x83, 0x3C, 0x2D, 0xFB, 0xDC, + 0xF3, 0x03, 0x84, 0x22, 0x40, 0x11, 0x84, 0x36, 0xF2, 0x87, 0x3C, 0x2D, 0xFB, 0xC8, 0xF1, 0x85, + 0x44, 0x12, 0xB8, 0x18, 0xB6, 0x5F, 0xF1, 0x81, 0x3C, 0x2D, 0xFB, 0xC7, 0x3D, 0xED, 0xFB, 0xDD, + 0x8C, 0x0C, 0x44, 0x12, 0xB7, 0xDC, 0x44, 0x62, 0xB7, 0xB4, 0x84, 0x80, 0xF3, 0x07, 0x00, 0x51, + 0x80, 0x09, 0xE2, 0x85, 0x4E, 0xF2, 0x01, 0x0C, 0x04, 0x70, 0x7F, 0xFD, 0x4E, 0x72, 0x00, 0xFE, + 0x00, 0x30, 0x00, 0x08, 0x54, 0x51, 0x80, 0x01, 0xF3, 0x82, 0xC5, 0x0C, 0xF3, 0x01, 0x84, 0xA1, + 0xAF, 0x58, 0x22, 0x50, 0x00, 0x00, 0xAD, 0x48, 0x22, 0x50, 0x00, 0x01, 0xAD, 0x49, 0x48, 0x00, + 0x00, 0xED, 0x5A, 0x70, 0x04, 0x04, 0x48, 0x00, 0x00, 0xAD, 0xF2, 0x01, 0xA6, 0x90, 0xCA, 0x49, + 0x44, 0x32, 0xB7, 0xC4, 0x38, 0x31, 0x90, 0x00, 0x5A, 0x30, 0x01, 0x08, 0xA6, 0xF0, 0x81, 0x22, + 0xB6, 0x7F, 0x80, 0xA2, 0x85, 0x4F, 0xD5, 0x1F, 0x44, 0x32, 0xB7, 0x00, 0x95, 0xE2, 0x88, 0xE3, + 0x00, 0x83, 0x00, 0x00, 0x80, 0x62, 0x80, 0xA2, 0x85, 0x21, 0x4C, 0x54, 0x40, 0x03, 0x85, 0x22, + 0x22, 0xA3, 0x80, 0x00, 0x8C, 0xA1, 0x42, 0x34, 0xA8, 0x73, 0x22, 0xA3, 0x80, 0x01, 0x97, 0x68, + 0x42, 0x24, 0xA8, 0x73, 0x50, 0x73, 0x80, 0x3C, 0x5A, 0x58, 0x03, 0xF0, 0x84, 0xA4, 0x40, 0x31, + 0x94, 0x76, 0xD5, 0x17, 0x80, 0xE4, 0x42, 0x72, 0xA8, 0x73, 0x44, 0x32, 0xB7, 0x00, 0x8C, 0xA1, + 0x38, 0x81, 0x9E, 0x11, 0x95, 0xFA, 0x88, 0xE3, 0xB4, 0x7F, 0x22, 0x73, 0x80, 0x01, 0x97, 0x68, + 0xE2, 0x65, 0x89, 0x28, 0x88, 0x47, 0xE8, 0xEF, 0x80, 0xA3, 0x8C, 0xA1, 0x40, 0x34, 0x94, 0x76, + 0xB6, 0x7F, 0xB4, 0xFF, 0x40, 0x21, 0x14, 0x56, 0x4E, 0x74, 0x00, 0x08, 0xFF, 0xFA, 0xD5, 0x05, + 0x80, 0x45, 0xB6, 0xBF, 0x80, 0xE5, 0xD5, 0x05, 0x80, 0xA2, 0x4E, 0x24, 0x00, 0x03, 0xFF, 0x52, + 0x88, 0xE5, 0x04, 0x5F, 0x00, 0x01, 0xE2, 0xA7, 0x4E, 0xF2, 0x00, 0x90, 0xF3, 0x02, 0x00, 0x9F, + 0x00, 0x00, 0x54, 0x51, 0x80, 0x04, 0x00, 0xAF, 0x00, 0x02, 0xC5, 0x15, 0xB4, 0x7F, 0xA5, 0x48, + 0x42, 0x71, 0xA4, 0x24, 0x40, 0xA3, 0xA9, 0x56, 0x89, 0x45, 0x12, 0xA0, 0x80, 0x00, 0x00, 0x7F, + 0x00, 0x01, 0x00, 0x5F, 0x00, 0x03, 0xFF, 0xD4, 0x40, 0x73, 0x94, 0xF6, 0xA5, 0x49, 0x88, 0xA7, + 0xAD, 0x49, 0xD5, 0x2B, 0xF3, 0x05, 0x00, 0x8F, 0x00, 0x01, 0x40, 0x75, 0x0C, 0x00, 0xF3, 0x03, + 0x40, 0x33, 0x8C, 0x76, 0xF3, 0x86, 0x00, 0x3F, 0x00, 0x03, 0xF7, 0x05, 0xF3, 0x84, 0x80, 0xA3, + 0xF3, 0x03, 0x88, 0xA7, 0x40, 0x52, 0x8C, 0xB6, 0xF3, 0x06, 0xE1, 0x23, 0x80, 0xE3, 0xB4, 0x7F, + 0x40, 0x74, 0xBC, 0x1B, 0xE1, 0x05, 0xFF, 0xDC, 0x40, 0x54, 0x3C, 0x1B, 0xF3, 0x04, 0xFF, 0x54, + 0x40, 0xA3, 0xA9, 0x56, 0x40, 0x82, 0x8D, 0x16, 0xA5, 0xC8, 0xA5, 0x49, 0x89, 0x47, 0x89, 0x05, + 0x12, 0xA0, 0x80, 0x00, 0x12, 0x80, 0x80, 0x01, 0x22, 0x50, 0x80, 0x00, 0xF3, 0x02, 0xAD, 0x40, + 0x22, 0x50, 0x80, 0x01, 0xAD, 0x41, 0x58, 0x51, 0x80, 0x02, 0x10, 0x50, 0x00, 0x08, 0xD5, 0x3D, + 0x5A, 0x70, 0x05, 0x3C, 0xF3, 0x01, 0xA7, 0xD8, 0x5A, 0x78, 0x01, 0x09, 0x44, 0x72, 0xB7, 0xC4, + 0xAF, 0x70, 0x38, 0x53, 0x90, 0x08, 0xAF, 0x58, 0xD5, 0x15, 0xA7, 0xF0, 0xE6, 0xE2, 0xE8, 0x04, + 0x8C, 0xE1, 0xAF, 0xF0, 0xD5, 0x02, 0xAF, 0x70, 0x44, 0x52, 0xB7, 0xC4, 0x38, 0x52, 0x90, 0x00, + 0xCD, 0x09, 0xA7, 0x70, 0x5A, 0x58, 0x02, 0x07, 0x44, 0x72, 0xB7, 0xC4, 0x84, 0xA1, 0x38, 0x53, + 0x90, 0x08, 0xA7, 0xF0, 0x84, 0xAF, 0x80, 0x64, 0x22, 0xA0, 0x00, 0x00, 0x42, 0x33, 0x94, 0x73, + 0xA5, 0xC8, 0x80, 0xA3, 0x44, 0x32, 0xB7, 0x00, 0x40, 0x75, 0x1C, 0x01, 0x38, 0x71, 0x96, 0x09, + 0x22, 0x90, 0x00, 0x01, 0xA5, 0xC9, 0x95, 0x6A, 0x88, 0xA3, 0x40, 0x74, 0x9C, 0x01, 0xAD, 0xE9, + 0x12, 0xA0, 0x80, 0x00, 0x12, 0x90, 0x80, 0x01, 0xF3, 0x01, 0x8C, 0x81, 0x8C, 0x61, 0xF3, 0x81, + 0x50, 0x00, 0x00, 0xE0, 0x8C, 0x24, 0x8C, 0xC1, 0x48, 0xFF, 0xFE, 0xF2, 0xB4, 0x1F, 0x3C, 0x2F, + 0xFB, 0xC7, 0x3C, 0x0F, 0xFB, 0xC8, 0xFC, 0xC4, 0x3C, 0x0F, 0xFC, 0xB2, 0xDD, 0x9E, 0x3C, 0x0F, + 0xFC, 0xB1, 0xDD, 0x9E, 0xFC, 0x40, 0x51, 0xFF, 0xF7, 0xE0, 0xF1, 0x83, 0xF3, 0x84, 0x50, 0x1F, + 0x81, 0x54, 0x84, 0x60, 0xF2, 0x86, 0x3C, 0x4D, 0xFC, 0xB1, 0xB6, 0x3F, 0x84, 0xA1, 0x80, 0xC3, + 0xF2, 0x03, 0xE2, 0x62, 0xF2, 0x85, 0xE8, 0x2B, 0x22, 0x70, 0x00, 0x00, 0x22, 0x20, 0x00, 0x01, + 0x12, 0x70, 0x80, 0x0A, 0x12, 0x70, 0x80, 0x0C, 0xF7, 0x04, 0x12, 0x20, 0x80, 0x0B, 0x12, 0x20, + 0x80, 0x0D, 0xA0, 0x81, 0xA1, 0xFC, 0x14, 0x20, 0x80, 0x0B, 0x94, 0x91, 0x88, 0x47, 0x00, 0xF1, + 0x00, 0x01, 0xE8, 0x0B, 0xA7, 0xE2, 0x8E, 0xE1, 0x4C, 0xF3, 0x80, 0x08, 0xA7, 0xD0, 0xC7, 0x05, + 0xA6, 0xA3, 0x8E, 0x41, 0x4C, 0x71, 0x40, 0x05, 0x10, 0x50, 0x80, 0x35, 0xD5, 0x03, 0x10, 0x60, + 0x80, 0x35, 0x8C, 0x61, 0x50, 0x10, 0x80, 0x38, 0x8C, 0x08, 0xD5, 0xD3, 0x2E, 0x07, 0xF2, 0xC0, + 0x50, 0xAF, 0x80, 0x64, 0xF0, 0x81, 0xF0, 0x82, 0x84, 0x00, 0x80, 0x20, 0x50, 0x9F, 0x80, 0xA0, + 0xB1, 0xF7, 0x50, 0x6F, 0x81, 0x18, 0x44, 0x50, 0x00, 0x38, 0x44, 0x32, 0xB8, 0x30, 0xB4, 0x9F, + 0x42, 0x20, 0x14, 0x24, 0x88, 0x82, 0x88, 0x43, 0x38, 0x15, 0x02, 0x0A, 0x38, 0x14, 0x82, 0x0A, + 0x38, 0x13, 0x82, 0x0A, 0x38, 0x13, 0x02, 0x0A, 0x8C, 0x01, 0x10, 0x12, 0x00, 0x2A, 0x10, 0x11, + 0x00, 0x2A, 0x5A, 0x08, 0x0F, 0xEE, 0xF1, 0x01, 0x44, 0x00, 0x00, 0x3C, 0xFE, 0x0C, 0xF0, 0x8E, + 0x84, 0x00, 0x3C, 0x3D, 0xFC, 0xB2, 0x50, 0x8F, 0x84, 0x9C, 0xB5, 0x5F, 0xF0, 0x87, 0xF0, 0x07, + 0xF1, 0x03, 0xE2, 0x01, 0x4E, 0xF2, 0x00, 0xF5, 0xF2, 0x07, 0xB0, 0x19, 0x84, 0x21, 0x38, 0x10, + 0x0A, 0x0A, 0xF1, 0x03, 0xF2, 0x01, 0x44, 0x02, 0xB8, 0x30, 0xE2, 0x22, 0x87, 0xC0, 0x14, 0xFF, + 0x80, 0x0F, 0xF1, 0x0E, 0x4D, 0xE0, 0x80, 0xDD, 0xF1, 0x0F, 0x22, 0x25, 0x00, 0x0C, 0xC1, 0x09, + 0x22, 0x10, 0x00, 0x0E, 0x22, 0x40, 0x00, 0x0F, 0x8A, 0x41, 0x22, 0x15, 0x00, 0x0D, 0xD5, 0x08, + 0x22, 0x10, 0x00, 0x0C, 0x22, 0x40, 0x00, 0x0D, 0x8A, 0x41, 0x22, 0x15, 0x00, 0x0D, 0x8A, 0x24, + 0xFE, 0x4C, 0x42, 0x11, 0x08, 0x73, 0x22, 0x75, 0x00, 0x0D, 0x22, 0x60, 0x00, 0x0D, 0xF1, 0x88, + 0x22, 0x50, 0x00, 0x0C, 0x22, 0x15, 0x00, 0x0C, 0x9B, 0xBE, 0x04, 0x90, 0x00, 0x09, 0x9B, 0x4D, + 0x42, 0x23, 0x18, 0x24, 0xF1, 0x8B, 0x42, 0x22, 0x94, 0x73, 0xB4, 0x20, 0x5A, 0x98, 0x04, 0x08, + 0x00, 0x40, 0x00, 0x28, 0x5A, 0x48, 0x01, 0x04, 0x48, 0x00, 0x03, 0xC9, 0x04, 0x40, 0x00, 0x0C, + 0xCC, 0x5E, 0x00, 0x40, 0x00, 0x20, 0x44, 0xF0, 0x00, 0xE0, 0xF7, 0x06, 0x42, 0x72, 0x3C, 0x73, + 0x04, 0x43, 0x80, 0x37, 0xE2, 0x44, 0x4E, 0xF3, 0x03, 0xA6, 0xA5, 0x19, 0xFF, 0x0C, 0xE2, 0x44, + 0xE8, 0x2C, 0xA1, 0x1A, 0xE2, 0x44, 0xE8, 0x09, 0xA1, 0x04, 0xA0, 0x43, 0xFF, 0x34, 0x42, 0x42, + 0x84, 0x73, 0x4E, 0x46, 0x03, 0x98, 0xD5, 0x21, 0xA1, 0x1B, 0xE2, 0x44, 0xE8, 0x1E, 0xA1, 0x04, + 0xA1, 0xC3, 0xFF, 0x34, 0x42, 0x42, 0x9C, 0x73, 0x44, 0x50, 0x00, 0x64, 0xFF, 0x64, 0x40, 0x52, + 0x84, 0xB7, 0xFF, 0x6C, 0xFF, 0x4C, 0x44, 0x60, 0x27, 0x10, 0x40, 0xF2, 0x99, 0xF7, 0x00, 0x61, + 0x80, 0x27, 0x44, 0x50, 0x00, 0x64, 0xFF, 0x94, 0x40, 0x63, 0x14, 0xD7, 0xE2, 0xCF, 0xE8, 0x05, + 0x4E, 0x47, 0x00, 0x04, 0x4E, 0x13, 0x03, 0x77, 0x00, 0x10, 0x00, 0x29, 0xA7, 0x18, 0xE2, 0x81, + 0xE8, 0x05, 0xA0, 0x5C, 0xE2, 0x41, 0x4E, 0xF3, 0x03, 0x6E, 0x00, 0x11, 0x80, 0x26, 0x4E, 0x12, + 0x03, 0x7E, 0xA0, 0x5B, 0xE2, 0x41, 0x4E, 0xF2, 0x03, 0x7A, 0x5A, 0x98, 0x04, 0x04, 0x48, 0x00, + 0x03, 0x76, 0x00, 0x15, 0x00, 0x35, 0x4E, 0x13, 0x03, 0x72, 0x00, 0x10, 0x00, 0x35, 0x4E, 0x13, + 0x03, 0x6E, 0xF1, 0x08, 0x46, 0x29, 0x00, 0x00, 0x48, 0x00, 0x03, 0x67, 0x5A, 0x40, 0x02, 0x04, + 0x48, 0x00, 0x03, 0x65, 0x5A, 0x98, 0x04, 0x04, 0x48, 0x00, 0x03, 0x61, 0x22, 0x10, 0x00, 0x0E, + 0x00, 0xF0, 0x00, 0x20, 0xF1, 0x8C, 0xA0, 0x43, 0xF4, 0x06, 0xF1, 0x89, 0x22, 0x10, 0x00, 0x0F, + 0xF1, 0x8D, 0xA0, 0x44, 0xF1, 0x8A, 0x44, 0x10, 0x00, 0xE0, 0x42, 0x47, 0x84, 0x73, 0x04, 0xF2, + 0x00, 0x37, 0xE2, 0x4F, 0x4E, 0xF3, 0x03, 0x37, 0x00, 0x21, 0x80, 0x28, 0xF1, 0x09, 0xF4, 0x0A, + 0x42, 0x90, 0x88, 0x24, 0x84, 0x2A, 0x40, 0x94, 0x85, 0x36, 0xF1, 0x0A, 0xFE, 0x8C, 0x84, 0x2A, + 0x40, 0x21, 0x04, 0x56, 0xF1, 0x0D, 0xFE, 0x94, 0x88, 0x24, 0x9A, 0x79, 0xF4, 0x09, 0xF7, 0x0C, + 0xFE, 0x4C, 0x88, 0xE4, 0xF4, 0x0B, 0x42, 0x24, 0xA4, 0x73, 0x8A, 0x87, 0x42, 0x12, 0x10, 0x73, + 0xE0, 0x22, 0x4E, 0xF2, 0x03, 0x2C, 0xF4, 0x0A, 0xF1, 0x09, 0xFF, 0x34, 0x42, 0x42, 0x84, 0x73, + 0x4E, 0x47, 0x03, 0x25, 0xF1, 0x08, 0x46, 0x28, 0x00, 0x00, 0x48, 0x00, 0x03, 0x1E, 0xF0, 0x07, + 0x8D, 0x04, 0x8C, 0x01, 0xF0, 0x87, 0x50, 0xA5, 0x00, 0x38, 0x48, 0xFF, 0xFF, 0x0A, 0x84, 0x00, + 0xB0, 0xE8, 0x84, 0x21, 0xF2, 0x01, 0xE2, 0x02, 0xE8, 0x05, 0x38, 0x11, 0x82, 0x0A, 0x8C, 0x01, + 0xD5, 0xFA, 0xF0, 0x03, 0xE6, 0x0B, 0xE8, 0x0C, 0xE6, 0x4B, 0xE8, 0x0A, 0x80, 0x22, 0xF0, 0x03, + 0xB0, 0x99, 0x50, 0x4F, 0x84, 0x9C, 0xB1, 0x51, 0x49, 0x00, 0x03, 0x53, 0xD5, 0x09, 0xF0, 0x03, + 0xF1, 0x01, 0xB0, 0x99, 0x50, 0x4F, 0x84, 0x9C, 0xB1, 0x51, 0x49, 0x00, 0x03, 0x01, 0x46, 0x18, + 0xFF, 0xFF, 0xF0, 0x88, 0x50, 0x10, 0x8F, 0xFF, 0x84, 0x00, 0xF0, 0x81, 0x81, 0x00, 0x3C, 0xAD, + 0xFC, 0xB2, 0x44, 0x42, 0xB8, 0x30, 0x44, 0x00, 0x00, 0x38, 0xF1, 0x8B, 0xF1, 0x08, 0xE3, 0x01, + 0x4E, 0xF2, 0x01, 0x09, 0xB0, 0x91, 0x40, 0x14, 0x04, 0x08, 0x88, 0x22, 0x80, 0x44, 0xA6, 0x49, + 0x42, 0x20, 0x80, 0x73, 0x04, 0x21, 0x00, 0x0C, 0x5A, 0x28, 0x02, 0x14, 0xB0, 0x91, 0x84, 0x6F, + 0x38, 0x21, 0x21, 0x00, 0x42, 0x20, 0x8C, 0x73, 0x50, 0x3F, 0x84, 0x9C, 0x38, 0x21, 0x8A, 0x02, + 0x4E, 0x25, 0x00, 0x08, 0xB0, 0xA8, 0x84, 0x61, 0x38, 0x31, 0x06, 0x0A, 0x48, 0x00, 0x00, 0xE8, + 0xB0, 0x91, 0x80, 0x64, 0x42, 0x30, 0x80, 0x73, 0x38, 0x21, 0x21, 0x00, 0x00, 0x61, 0x80, 0x36, + 0x50, 0x3F, 0x81, 0x54, 0x42, 0x31, 0x00, 0x73, 0xF7, 0x04, 0x50, 0x51, 0x80, 0x30, 0x50, 0x31, + 0x80, 0x28, 0xA1, 0xFB, 0x04, 0x91, 0x80, 0x01, 0xAF, 0xAE, 0x38, 0x73, 0xA5, 0x01, 0x02, 0x95, + 0x00, 0x15, 0xE3, 0x27, 0xE8, 0x08, 0xCE, 0x07, 0xA7, 0x9A, 0x58, 0x63, 0x00, 0x01, 0xAF, 0x9A, + 0x84, 0x61, 0xAE, 0xEE, 0x50, 0x3F, 0x81, 0x54, 0x42, 0x31, 0x00, 0x73, 0x22, 0x51, 0x80, 0x0C, + 0x50, 0x91, 0x80, 0x18, 0xF5, 0x89, 0x80, 0xA4, 0x42, 0x50, 0x80, 0x73, 0xF5, 0x87, 0x22, 0x72, + 0x80, 0x0C, 0x22, 0x54, 0x80, 0x01, 0xF6, 0x09, 0xF5, 0x8A, 0xF5, 0x07, 0x9B, 0xF7, 0x81, 0xE3, + 0x22, 0x62, 0x80, 0x0D, 0xF5, 0x0A, 0x9B, 0xAE, 0x43, 0xE3, 0x18, 0x24, 0x43, 0xE3, 0x9C, 0x73, + 0x1D, 0xE7, 0x80, 0x02, 0xF5, 0x09, 0x14, 0x77, 0x80, 0x01, 0x88, 0xE5, 0xF5, 0x0A, 0xA9, 0x9C, + 0x88, 0xC5, 0x12, 0x64, 0x80, 0x03, 0x80, 0xA2, 0x84, 0xCF, 0x42, 0x50, 0x98, 0x73, 0x80, 0xC5, + 0x50, 0x5F, 0x84, 0x9C, 0x51, 0xE1, 0x80, 0x10, 0x38, 0x62, 0x9A, 0x02, 0xF5, 0x0B, 0x12, 0x74, + 0x80, 0x02, 0xE2, 0xA6, 0xE8, 0x0D, 0xF5, 0x07, 0x84, 0xC2, 0x8C, 0xB0, 0x14, 0x61, 0x80, 0x0C, + 0xA4, 0xEA, 0x12, 0x3F, 0x00, 0x02, 0xA4, 0xEB, 0x12, 0x3F, 0x00, 0x03, 0xD5, 0x04, 0x84, 0xA0, + 0x14, 0x51, 0x80, 0x0C, 0x50, 0x3F, 0x81, 0x54, 0x80, 0xA4, 0x42, 0x31, 0x00, 0x73, 0x42, 0x50, + 0x80, 0x73, 0x50, 0x91, 0x80, 0x10, 0x50, 0x72, 0x80, 0x10, 0x22, 0x64, 0x80, 0x02, 0x22, 0xF3, + 0x80, 0x02, 0x22, 0x73, 0x80, 0x03, 0x8A, 0xCF, 0xA9, 0x99, 0x22, 0x64, 0x80, 0x03, 0x8A, 0xC7, + 0x00, 0x72, 0x80, 0x20, 0xA9, 0x9A, 0x10, 0x71, 0x80, 0x20, 0x04, 0x72, 0x80, 0x09, 0x50, 0x61, + 0x80, 0x20, 0x5A, 0x78, 0x03, 0x19, 0x00, 0x61, 0x80, 0x36, 0x00, 0x52, 0x80, 0x28, 0x5A, 0x68, + 0x01, 0x03, 0x8E, 0xA1, 0x10, 0x51, 0x80, 0x28, 0x50, 0x3F, 0x81, 0x54, 0x42, 0x31, 0x00, 0x73, + 0x00, 0x51, 0x80, 0x28, 0x50, 0x31, 0x80, 0x20, 0xCD, 0x03, 0x84, 0xA1, 0xD5, 0x02, 0x84, 0xA3, + 0xA9, 0x59, 0xD5, 0x03, 0x84, 0x62, 0xA8, 0xF1, 0x80, 0x64, 0x42, 0x30, 0x80, 0x73, 0x00, 0x31, + 0x80, 0x34, 0x5C, 0xF1, 0x80, 0xC8, 0xE8, 0x03, 0x8C, 0x61, 0x96, 0xD8, 0x44, 0x60, 0x00, 0x38, + 0x50, 0x5F, 0x81, 0x54, 0x42, 0x51, 0x18, 0x73, 0x10, 0x32, 0x80, 0x34, 0x44, 0x32, 0xB8, 0x30, + 0x42, 0x30, 0x98, 0x73, 0xB4, 0xC5, 0x00, 0x11, 0x80, 0x29, 0x50, 0x32, 0x80, 0x28, 0x04, 0x55, + 0x00, 0x05, 0xAE, 0x59, 0xE2, 0xA6, 0xE8, 0x05, 0xE6, 0x2A, 0xE8, 0x0A, 0x8C, 0x21, 0xD5, 0x07, + 0x04, 0x55, 0x00, 0x06, 0xE2, 0xC5, 0xE8, 0x04, 0xC1, 0x03, 0x8E, 0x21, 0xAE, 0x59, 0x50, 0x1F, + 0x81, 0x54, 0x42, 0x11, 0x00, 0x73, 0x00, 0x50, 0x80, 0x20, 0x50, 0x3F, 0x81, 0x18, 0x84, 0x21, + 0x38, 0x11, 0x96, 0x0A, 0xB0, 0xF7, 0x38, 0x11, 0x8A, 0x0A, 0xF1, 0x05, 0x8E, 0x21, 0xF1, 0x85, + 0xF1, 0x02, 0x8E, 0x21, 0xF1, 0x82, 0xF1, 0x01, 0x8C, 0x21, 0xF1, 0x81, 0x8D, 0x01, 0x48, 0xFF, + 0xFE, 0xF7, 0xF1, 0x06, 0xB1, 0xE8, 0x44, 0x02, 0xB8, 0x30, 0x51, 0xE0, 0x80, 0x5E, 0x84, 0xC0, + 0x50, 0x9F, 0x80, 0xDC, 0x2E, 0x17, 0xF2, 0xC0, 0x3C, 0xAD, 0xFC, 0xB1, 0xE2, 0xC1, 0xE8, 0x03, + 0xF1, 0x02, 0xC9, 0x0B, 0x84, 0x20, 0x3C, 0x4D, 0xFC, 0xB2, 0xB4, 0x1F, 0x83, 0xC1, 0x80, 0xC1, + 0x84, 0xA1, 0x85, 0x23, 0x48, 0x00, 0x00, 0xA6, 0x00, 0x15, 0x00, 0x09, 0xF2, 0x01, 0xE2, 0x41, + 0xE8, 0xF2, 0xA2, 0xB9, 0x5A, 0x20, 0x01, 0x04, 0x48, 0x00, 0x00, 0x86, 0x04, 0x10, 0x00, 0x09, + 0x5A, 0x18, 0x03, 0x09, 0x84, 0x20, 0x14, 0x13, 0xFF, 0xFF, 0xF1, 0x02, 0x8E, 0x21, 0xF1, 0x82, + 0xD5, 0x7A, 0x8E, 0x21, 0xE6, 0x22, 0xE8, 0x13, 0x04, 0x10, 0x00, 0x0C, 0x5A, 0x18, 0x02, 0x04, + 0x84, 0x20, 0xD5, 0x19, 0x44, 0x12, 0xD0, 0x84, 0x38, 0x10, 0x98, 0x00, 0xC9, 0x04, 0x10, 0x20, + 0x00, 0x28, 0xD5, 0x13, 0x3C, 0x1D, 0xFC, 0xB2, 0xA6, 0x49, 0xD5, 0x0D, 0x00, 0x1F, 0x00, 0x00, + 0xC1, 0x07, 0x84, 0x24, 0x10, 0x10, 0x00, 0x28, 0x84, 0x20, 0x10, 0x1F, 0x00, 0x00, 0x00, 0x10, + 0x00, 0x28, 0x8E, 0x21, 0x10, 0x10, 0x00, 0x28, 0x00, 0x10, 0x00, 0x28, 0x5A, 0x18, 0x01, 0x08, + 0x00, 0x20, 0x00, 0x2A, 0x58, 0x21, 0x00, 0x04, 0x10, 0x20, 0x00, 0x2A, 0x00, 0x25, 0x00, 0x19, + 0x85, 0x40, 0xE3, 0x42, 0xE8, 0x0A, 0x38, 0x34, 0xAA, 0x02, 0xCB, 0x05, 0xB0, 0xD9, 0x38, 0x31, + 0xAA, 0x02, 0xC3, 0x05, 0x8D, 0x41, 0xD5, 0xF6, 0x85, 0x40, 0xD5, 0x3B, 0xC1, 0x05, 0x84, 0x24, + 0x14, 0x10, 0x00, 0x09, 0xD5, 0x06, 0x84, 0x45, 0x14, 0x20, 0x00, 0x09, 0x3E, 0x10, 0x05, 0xF7, + 0x44, 0x10, 0x00, 0x38, 0x50, 0xFF, 0x81, 0x54, 0x42, 0xF5, 0x04, 0x73, 0x80, 0x20, 0x81, 0x0F, + 0x3A, 0x20, 0x94, 0x04, 0x3A, 0x24, 0x14, 0x24, 0x3A, 0x20, 0x94, 0x04, 0x3A, 0x24, 0x14, 0x24, + 0x81, 0xE8, 0x3A, 0x20, 0x94, 0x04, 0x3A, 0x27, 0x94, 0x24, 0x3A, 0x20, 0x8C, 0x00, 0x3A, 0x27, + 0x8C, 0x20, 0x00, 0x20, 0x00, 0x20, 0x50, 0x3F, 0x81, 0x18, 0x84, 0x21, 0x38, 0x11, 0x8A, 0x0A, + 0x38, 0x14, 0xAA, 0x0A, 0x84, 0x20, 0x14, 0x13, 0xFF, 0xFF, 0xF1, 0x02, 0x8E, 0x21, 0xF1, 0x82, + 0xF1, 0x01, 0x8C, 0x21, 0xF1, 0x81, 0xD5, 0x07, 0x38, 0x34, 0xAA, 0x02, 0xC3, 0xC8, 0x8D, 0x41, + 0x4C, 0xA1, 0x7F, 0xFC, 0x8C, 0xC1, 0x50, 0x00, 0x00, 0x38, 0x51, 0xEF, 0x00, 0xE0, 0x48, 0xFF, + 0xFF, 0x5B, 0xF2, 0x05, 0xC2, 0x7B, 0x00, 0x35, 0x00, 0x09, 0xF2, 0x01, 0xE2, 0x43, 0xE8, 0x76, + 0xB0, 0x99, 0x38, 0x21, 0x06, 0x02, 0x5A, 0x20, 0x01, 0x09, 0x8C, 0x21, 0x50, 0x00, 0x00, 0x38, + 0xF2, 0x03, 0xE2, 0x22, 0xE9, 0xEF, 0xD5, 0x6A, 0xB0, 0xB7, 0x38, 0x21, 0x06, 0x02, 0xCA, 0xF6, + 0x50, 0x7F, 0x81, 0x18, 0x38, 0x73, 0x8A, 0x02, 0xCF, 0x5D, 0x02, 0x30, 0x00, 0x0C, 0xB6, 0xE0, + 0x12, 0x30, 0x00, 0x0E, 0x02, 0x30, 0x00, 0x0D, 0xA9, 0xC1, 0x12, 0x30, 0x00, 0x0F, 0xF3, 0x01, + 0xA9, 0xC2, 0x88, 0x64, 0xA9, 0xC3, 0xA9, 0xC4, 0xF7, 0x04, 0x00, 0x31, 0x80, 0x1C, 0x10, 0x20, + 0x00, 0x20, 0x10, 0x30, 0x00, 0x28, 0xA1, 0xFB, 0x04, 0x80, 0x00, 0x0B, 0xCB, 0x0E, 0x38, 0x33, + 0xA1, 0x01, 0x02, 0x82, 0x00, 0x15, 0xE3, 0x03, 0xE8, 0x04, 0x14, 0x50, 0x00, 0x09, 0xD5, 0x11, + 0x14, 0x90, 0x00, 0x09, 0x84, 0x61, 0xD5, 0x0B, 0x38, 0x83, 0xA1, 0x01, 0x02, 0xF2, 0x00, 0x15, + 0x14, 0x90, 0x00, 0x09, 0x40, 0xF7, 0xA0, 0x06, 0xE9, 0x04, 0x8C, 0x61, 0x10, 0x30, 0x00, 0x28, + 0x04, 0x30, 0x00, 0x0B, 0x10, 0x60, 0x00, 0x34, 0x10, 0x60, 0x00, 0x29, 0x38, 0x33, 0x8D, 0x01, + 0x02, 0x72, 0x00, 0x15, 0x15, 0xE0, 0x00, 0x0C, 0xE2, 0xE3, 0x84, 0x61, 0x40, 0x33, 0x3C, 0x1A, + 0x10, 0x30, 0x00, 0x36, 0x00, 0x30, 0x00, 0x2A, 0x58, 0x31, 0x80, 0x01, 0x10, 0x30, 0x00, 0x2A, + 0x50, 0x3F, 0x81, 0x18, 0x38, 0x51, 0x8A, 0x0A, 0xB0, 0xB7, 0x38, 0x51, 0x06, 0x0A, 0xB0, 0x99, + 0x39, 0xE1, 0x06, 0x0A, 0xF2, 0x05, 0x8E, 0x41, 0xF2, 0x85, 0xF2, 0x01, 0x8C, 0x41, 0xF2, 0x81, + 0xD5, 0x95, 0x8C, 0x41, 0xE2, 0x43, 0xE9, 0x9D, 0xD5, 0x91, 0x84, 0x00, 0x3C, 0x9D, 0xFC, 0xB1, + 0x44, 0x20, 0x00, 0xE0, 0x80, 0x60, 0x00, 0x14, 0x80, 0x09, 0xE2, 0x01, 0xE8, 0x08, 0xF4, 0x06, + 0x42, 0x10, 0x08, 0x24, 0x8C, 0x01, 0x38, 0x32, 0x04, 0x0A, 0xD5, 0xF6, 0x84, 0x00, 0x3E, 0x07, + 0xF2, 0xC0, 0x84, 0xC0, 0x50, 0xAF, 0x80, 0xDC, 0x45, 0xE0, 0x00, 0x38, 0x00, 0x04, 0x80, 0x19, + 0xE2, 0xC0, 0x4E, 0xF2, 0x00, 0x96, 0x38, 0x05, 0x1A, 0x02, 0x5A, 0x08, 0x01, 0x75, 0xB4, 0x1F, + 0x04, 0x10, 0x00, 0x09, 0x5A, 0x10, 0x05, 0x1F, 0x2E, 0x87, 0xF2, 0xC0, 0x44, 0x02, 0xB8, 0x30, + 0x42, 0x04, 0x78, 0x73, 0x81, 0xE0, 0xB4, 0x1F, 0x80, 0xEF, 0x8D, 0x01, 0x3A, 0x20, 0x14, 0x04, + 0x3A, 0x23, 0x94, 0x24, 0x3A, 0x20, 0x14, 0x04, 0x3A, 0x23, 0x94, 0x24, 0x81, 0xE7, 0x3A, 0x20, + 0x14, 0x04, 0x3A, 0x27, 0x94, 0x24, 0x3A, 0x20, 0x0C, 0x00, 0x3A, 0x27, 0x8C, 0x20, 0x3E, 0x87, + 0xF2, 0xC0, 0xB4, 0x1F, 0x44, 0x20, 0x00, 0xE0, 0xB4, 0xBF, 0x00, 0x40, 0x00, 0x20, 0xF0, 0x06, + 0x42, 0x02, 0x08, 0x73, 0xB4, 0x5F, 0x50, 0x70, 0x00, 0x20, 0xB4, 0xA5, 0x00, 0x31, 0x00, 0x2A, + 0x02, 0x21, 0x00, 0x0A, 0x10, 0x30, 0x00, 0x14, 0xAC, 0x82, 0xB4, 0x5F, 0xB6, 0x20, 0x96, 0xC6, + 0x02, 0x21, 0x00, 0x0B, 0xAC, 0x83, 0xB4, 0x5F, 0x04, 0x21, 0x00, 0x0B, 0xA8, 0x86, 0xB6, 0xA7, + 0xB4, 0xBF, 0xA1, 0x69, 0xA9, 0x79, 0xB4, 0xBF, 0xA1, 0x6A, 0xA9, 0x7A, 0xB4, 0xBF, 0xA1, 0x6B, + 0xA9, 0x7B, 0xB4, 0xBF, 0xA1, 0x6C, 0xA9, 0x7C, 0xB4, 0xBF, 0x04, 0x52, 0x80, 0x0C, 0xA9, 0x7D, + 0xC3, 0x0A, 0x44, 0x30, 0x45, 0x19, 0x14, 0x30, 0x00, 0x37, 0x44, 0x32, 0xCE, 0xA4, 0x84, 0xA0, + 0x38, 0x51, 0x90, 0x08, 0x5A, 0x10, 0x04, 0x18, 0xF4, 0x04, 0x94, 0xD1, 0x8E, 0x21, 0xA1, 0x24, + 0xE6, 0x23, 0x88, 0x64, 0xA6, 0xD9, 0x10, 0x30, 0x00, 0x6D, 0xF3, 0x04, 0xA0, 0xDC, 0x38, 0x31, + 0x89, 0x00, 0x10, 0x30, 0x00, 0x6C, 0xE8, 0x07, 0xF1, 0x04, 0xA0, 0x4B, 0x38, 0x10, 0x89, 0x01, + 0x12, 0x10, 0x00, 0x1F, 0xB4, 0x1F, 0x8C, 0xC1, 0x50, 0x00, 0x00, 0x38, 0xB6, 0x1F, 0x48, 0xFF, + 0xFF, 0x7F, 0x5A, 0x98, 0x03, 0x09, 0x00, 0x10, 0x00, 0x34, 0xC9, 0x05, 0xF1, 0x08, 0x46, 0x21, + 0x00, 0x00, 0xD5, 0x0A, 0xF1, 0x08, 0x38, 0x14, 0x78, 0x0A, 0x50, 0x00, 0x00, 0x38, 0x51, 0xEF, + 0x00, 0x3C, 0x48, 0xFF, 0xFC, 0x08, 0x88, 0x22, 0xD5, 0xF7, 0x84, 0x3F, 0xD5, 0xF5, 0x51, 0xFF, + 0x88, 0x20, 0xFC, 0xC0, 0x84, 0x00, 0x3E, 0x07, 0xF2, 0xC0, 0xDD, 0x9E, 0xFC, 0x43, 0xF0, 0x81, + 0x81, 0x00, 0x84, 0x00, 0xF4, 0x84, 0xF1, 0x82, 0xF5, 0x85, 0x80, 0xE1, 0x83, 0x80, 0x81, 0x20, + 0x84, 0x81, 0x4E, 0x82, 0x00, 0x3D, 0xC7, 0x3B, 0x5A, 0x48, 0x01, 0x3A, 0x84, 0xA0, 0x80, 0x85, + 0x85, 0x5E, 0xF1, 0x01, 0xD1, 0x22, 0x38, 0x61, 0x16, 0x02, 0x5A, 0x68, 0x01, 0x1D, 0xF1, 0x04, + 0x95, 0xAA, 0x88, 0xC1, 0xF6, 0x83, 0x84, 0xC0, 0xF1, 0x02, 0x4C, 0x60, 0x80, 0x15, 0x39, 0xE1, + 0x9A, 0x02, 0x5B, 0xE8, 0x01, 0x0F, 0x44, 0x10, 0x00, 0x3C, 0x42, 0xF3, 0x04, 0x24, 0xF1, 0x03, + 0x38, 0x10, 0xBC, 0x02, 0xE2, 0x2A, 0xE8, 0x05, 0x83, 0x86, 0x81, 0x25, 0x80, 0x9E, 0x81, 0x41, + 0x8C, 0xC1, 0xD5, 0xEB, 0x8C, 0xA1, 0xD5, 0xDE, 0xC4, 0xD5, 0xF1, 0x05, 0x95, 0x41, 0x88, 0xA1, + 0x8C, 0x01, 0x84, 0x20, 0x10, 0x92, 0x80, 0x00, 0x11, 0xC2, 0x80, 0x01, 0x96, 0x00, 0x38, 0x11, + 0x26, 0x0A, 0x8F, 0x01, 0x38, 0x11, 0xF2, 0x0A, 0x8E, 0xE1, 0xD5, 0xC4, 0xFC, 0xC3, 0xC0, 0x6E, + 0xC1, 0x6F, 0xFC, 0x40, 0x51, 0xFF, 0xFB, 0x90, 0xE2, 0x20, 0xE8, 0x2F, 0x80, 0xE1, 0x44, 0xA0, + 0x00, 0x3C, 0x85, 0x1F, 0x81, 0x24, 0x42, 0x93, 0xA8, 0x73, 0x84, 0xC0, 0x38, 0x84, 0x9A, 0x0A, + 0x8C, 0xC1, 0x4C, 0x60, 0x7F, 0xFD, 0x8C, 0xE1, 0x4C, 0x70, 0x7F, 0xF6, 0x80, 0xC0, 0x83, 0x81, + 0x80, 0x01, 0x80, 0x26, 0x81, 0x24, 0x81, 0x05, 0xF2, 0x81, 0x81, 0x43, 0x49, 0x00, 0x28, 0xBA, + 0xB0, 0x3B, 0x49, 0x00, 0x28, 0xBE, 0x80, 0x09, 0x49, 0x00, 0x28, 0xC5, 0xB0, 0x02, 0x49, 0x00, + 0x28, 0xCC, 0x84, 0x0F, 0x49, 0x00, 0x28, 0xD3, 0x49, 0x00, 0x28, 0xD6, 0x84, 0x40, 0x80, 0xA2, + 0x45, 0xE0, 0x00, 0x3C, 0x80, 0x82, 0xD5, 0x14, 0xE2, 0x01, 0xE8, 0xE1, 0x84, 0xE0, 0x44, 0xA0, + 0x00, 0x3C, 0x85, 0x1F, 0x81, 0x24, 0x42, 0x93, 0xA8, 0x73, 0x80, 0xC0, 0x38, 0x84, 0x9A, 0x0A, + 0x8C, 0xC1, 0x4C, 0x60, 0xFF, 0xFD, 0x8C, 0xE1, 0x4C, 0x70, 0xFF, 0xF6, 0xD5, 0xD0, 0x84, 0x0F, + 0x81, 0xE9, 0x42, 0x12, 0x80, 0x24, 0x42, 0xF2, 0xF8, 0x73, 0x84, 0xE0, 0x98, 0xF9, 0xB0, 0x02, + 0x38, 0x30, 0x0C, 0x00, 0x5A, 0x38, 0x01, 0x11, 0x38, 0x37, 0x9E, 0x02, 0x5A, 0x37, 0xFF, 0x0D, + 0x94, 0xD1, 0x88, 0x68, 0x8C, 0x41, 0xAF, 0xD8, 0xAF, 0x59, 0xF3, 0x01, 0x96, 0x90, 0x38, 0x41, + 0x9E, 0x0A, 0x38, 0x45, 0x16, 0x0A, 0x8C, 0xE1, 0x4C, 0x73, 0x7F, 0xEA, 0x8C, 0xA1, 0x4C, 0x5E, + 0x7F, 0xE0, 0x80, 0x02, 0x51, 0xFF, 0x84, 0x70, 0xFC, 0xC0, 0x80, 0x40, 0xD5, 0x02, 0x80, 0x41, + 0x80, 0x02, 0xDD, 0x9E, 0x3C, 0x0F, 0xFC, 0xE4, 0xDD, 0x9E, 0x3C, 0x0F, 0xFC, 0xE3, 0xDD, 0x9E, + 0x44, 0x02, 0xBC, 0x00, 0x84, 0x21, 0x3C, 0x0F, 0xFC, 0xBE, 0x84, 0x00, 0x3E, 0x07, 0xF2, 0xFC, + 0x3E, 0x07, 0xF2, 0xFD, 0x3E, 0x07, 0xF2, 0xFE, 0x3E, 0x07, 0xF2, 0xFF, 0x3E, 0x07, 0xF3, 0x00, + 0x3E, 0x07, 0xF3, 0x01, 0x3E, 0x07, 0xF3, 0x02, 0x3E, 0x07, 0xF2, 0xD1, 0x3E, 0x07, 0xF2, 0xD0, + 0x3E, 0x07, 0xF2, 0xD2, 0x3C, 0x1F, 0xFA, 0x72, 0x3E, 0x07, 0xED, 0xA3, 0x44, 0x12, 0xBB, 0xBC, + 0x84, 0x00, 0x84, 0x5F, 0x38, 0x20, 0x80, 0x08, 0x8C, 0x01, 0x5A, 0x08, 0x41, 0xFD, 0xDD, 0x9E, + 0xFC, 0x00, 0x49, 0x00, 0x54, 0x1A, 0xFC, 0x80, 0xFC, 0x00, 0x80, 0xC0, 0x49, 0x00, 0x54, 0x17, + 0xC0, 0x04, 0x84, 0x00, 0xAE, 0x34, 0xAE, 0x35, 0xFC, 0x80, 0x2E, 0x07, 0xF2, 0xD8, 0xDD, 0x9E, + 0x44, 0x32, 0xBB, 0x88, 0xAE, 0x18, 0xAE, 0x59, 0xAE, 0x9A, 0xDD, 0x9E, 0x3C, 0x0F, 0xFA, 0x72, + 0xDD, 0x9E, 0x3C, 0x0D, 0xFA, 0x72, 0xDD, 0x9E, 0x3C, 0x0D, 0xFB, 0x68, 0x46, 0x5F, 0xF0, 0x0F, + 0x50, 0x52, 0x8F, 0x00, 0xFF, 0x46, 0x46, 0x00, 0x10, 0x00, 0xD8, 0x06, 0x84, 0x00, 0x3E, 0x07, + 0xED, 0xA3, 0x84, 0x01, 0xDD, 0x9E, 0x84, 0x00, 0xDD, 0x9E, 0x2E, 0x17, 0xF2, 0xFE, 0x2E, 0x57, + 0xF2, 0xFF, 0x3C, 0x0D, 0xFC, 0xE4, 0x4C, 0x12, 0xC0, 0x10, 0x2E, 0x27, 0xF2, 0xFC, 0x5A, 0x28, + 0x01, 0x0C, 0xA6, 0x05, 0x9D, 0x49, 0x40, 0x02, 0x80, 0xB6, 0x97, 0x68, 0x3E, 0x57, 0xF2, 0xFE, + 0x3E, 0x57, 0xF2, 0xFF, 0xDD, 0x9E, 0xA6, 0x05, 0x8C, 0xA1, 0x40, 0x02, 0x80, 0xB6, 0x97, 0x68, + 0x3E, 0x57, 0xF2, 0xFF, 0xD9, 0x04, 0x84, 0x01, 0x3E, 0x07, 0xF2, 0xFC, 0xDD, 0x9E, 0x2E, 0x57, + 0xF2, 0xFE, 0x2E, 0x17, 0xF2, 0xFF, 0xD9, 0x04, 0x2E, 0x07, 0xF2, 0xFC, 0xC0, 0x10, 0x3C, 0x0D, + 0xFC, 0xE4, 0x8C, 0xA1, 0xA6, 0x05, 0x40, 0x02, 0x80, 0xB6, 0x97, 0x68, 0x3E, 0x57, 0xF2, 0xFE, + 0x4C, 0x12, 0xC0, 0x05, 0x84, 0x00, 0x3E, 0x07, 0xF2, 0xFC, 0x84, 0x01, 0xDD, 0x9E, 0x2E, 0x57, + 0xF2, 0xFE, 0x2E, 0x07, 0xF2, 0xFF, 0xD8, 0x08, 0x2E, 0x07, 0xF2, 0xFC, 0x84, 0x20, 0x8E, 0x01, + 0x40, 0x00, 0x80, 0x06, 0xDD, 0x9E, 0x84, 0x01, 0xDD, 0x9E, 0x2E, 0x57, 0xF2, 0xFE, 0x2E, 0x07, + 0xF2, 0xFF, 0xD8, 0x07, 0x2E, 0x17, 0xF2, 0xFC, 0x84, 0x00, 0x40, 0x00, 0x04, 0x06, 0xDD, 0x9E, + 0x84, 0x01, 0xDD, 0x9E, 0xFC, 0x00, 0x84, 0xA0, 0x8C, 0x81, 0xE2, 0xA4, 0xE8, 0x07, 0x38, 0x60, + 0x08, 0x04, 0x38, 0x60, 0x8C, 0x0C, 0x8C, 0xA1, 0xD5, 0xF9, 0xFC, 0x80, 0x80, 0x60, 0x3C, 0x0D, + 0xFA, 0x72, 0x9E, 0x41, 0xE6, 0x22, 0xE8, 0x25, 0x3C, 0x2D, 0xFC, 0xE3, 0x84, 0x20, 0x00, 0x41, + 0x00, 0x0A, 0xE2, 0x24, 0xE8, 0x09, 0xA1, 0x59, 0x38, 0x52, 0x87, 0x02, 0x5A, 0x58, 0x01, 0x03, + 0x84, 0x02, 0x8C, 0x21, 0xD5, 0xF7, 0xFC, 0x00, 0x84, 0x20, 0x00, 0x41, 0x00, 0x09, 0x44, 0x50, + 0x00, 0xE0, 0xE2, 0x24, 0xE8, 0x0D, 0xB4, 0x43, 0x42, 0x20, 0x94, 0x73, 0xB4, 0x42, 0x9F, 0x91, + 0xE6, 0xC2, 0xE9, 0x05, 0x5A, 0x20, 0x04, 0x04, 0x8C, 0x21, 0xD5, 0xF4, 0x84, 0x01, 0xFC, 0x80, + 0xDD, 0x9E, 0xFC, 0x42, 0x81, 0x21, 0xB4, 0xE1, 0x84, 0x3F, 0x10, 0x1F, 0x80, 0x0F, 0x2E, 0x17, + 0xC7, 0x50, 0x81, 0x40, 0xC1, 0x08, 0x2E, 0x17, 0xF2, 0xD8, 0xC9, 0x05, 0x49, 0xFF, 0xFF, 0xC8, + 0x3C, 0x0F, 0xFA, 0x72, 0x3C, 0x2D, 0xFA, 0x72, 0x5A, 0x20, 0x01, 0x04, 0x48, 0x00, 0x00, 0xDA, + 0x3C, 0x1D, 0xFC, 0xE3, 0x3C, 0x4D, 0xFC, 0xE4, 0xB6, 0x5F, 0x84, 0xC0, 0xB4, 0x1F, 0x00, 0x30, + 0x80, 0x09, 0x8E, 0x01, 0x96, 0x00, 0xE2, 0x03, 0x84, 0x5F, 0x4E, 0xF2, 0x00, 0xC6, 0x44, 0x20, + 0x00, 0xE0, 0xFE, 0x14, 0xF0, 0x81, 0xF2, 0x01, 0xB4, 0x0A, 0x88, 0x02, 0xB4, 0x40, 0x9E, 0xD1, + 0xE6, 0x62, 0xE9, 0x05, 0x5A, 0x20, 0x04, 0x04, 0x48, 0x00, 0x00, 0xB1, 0xA6, 0xE0, 0x22, 0x20, + 0x00, 0x04, 0xC3, 0x05, 0x02, 0x30, 0x80, 0x09, 0x8E, 0x61, 0x9A, 0x9A, 0xA6, 0xE1, 0x22, 0x50, + 0x00, 0x05, 0xC3, 0x05, 0x02, 0x30, 0x80, 0x0A, 0x8E, 0x61, 0x9B, 0x5D, 0xA6, 0xE3, 0xC3, 0x30, + 0x02, 0x30, 0x80, 0x09, 0x00, 0xF2, 0x00, 0x02, 0x8E, 0x61, 0xE9, 0x12, 0x02, 0x80, 0x80, 0x02, + 0x51, 0xE4, 0x7F, 0xFF, 0x85, 0x02, 0x40, 0xF1, 0xA1, 0xF6, 0x42, 0xF1, 0x78, 0x73, 0x40, 0x27, + 0x8C, 0x56, 0x02, 0x30, 0x80, 0x0A, 0x02, 0xF0, 0x80, 0x03, 0x8E, 0x61, 0xD5, 0x11, 0x02, 0x80, + 0x80, 0x03, 0x51, 0xE4, 0x7F, 0xFF, 0x85, 0x02, 0x40, 0xF1, 0xA1, 0xF6, 0x42, 0xF1, 0x78, 0x73, + 0x40, 0x27, 0x8C, 0x56, 0x02, 0x30, 0x80, 0x0A, 0x02, 0xF0, 0x80, 0x02, 0x8E, 0x61, 0x50, 0xF7, + 0xFF, 0xFF, 0x40, 0x81, 0xA1, 0x16, 0x42, 0x82, 0xBC, 0x73, 0x40, 0x54, 0x0C, 0xB6, 0xA4, 0xCA, + 0xE0, 0x43, 0xE9, 0x02, 0x9E, 0x99, 0x4E, 0x24, 0x00, 0x03, 0x84, 0x40, 0xA4, 0xCB, 0xE0, 0xA3, + 0xE9, 0x02, 0x9F, 0x59, 0x4E, 0x55, 0x00, 0x08, 0x44, 0x30, 0x09, 0x2A, 0xDB, 0x05, 0x44, 0x50, + 0x09, 0x2B, 0xD5, 0x02, 0x84, 0xA0, 0x85, 0x06, 0x80, 0x67, 0x42, 0x33, 0x20, 0x73, 0xB5, 0x1F, + 0x40, 0xF2, 0x90, 0x0A, 0x40, 0x84, 0x0C, 0x08, 0x58, 0x84, 0x00, 0x02, 0x10, 0x81, 0x80, 0x00, + 0x01, 0xE2, 0x00, 0x02, 0x40, 0x81, 0x10, 0x0A, 0x4F, 0xE3, 0x00, 0x0F, 0x10, 0x81, 0x80, 0x01, + 0x94, 0x94, 0x54, 0x82, 0x80, 0x0F, 0x84, 0xB0, 0xFE, 0xAE, 0x40, 0x54, 0x08, 0x04, 0x10, 0xF1, + 0x80, 0x02, 0xAF, 0x5B, 0xD5, 0x0D, 0x10, 0x81, 0x80, 0x02, 0x95, 0x6C, 0x54, 0x81, 0x00, 0x0F, + 0x84, 0x50, 0xFF, 0x56, 0x40, 0x24, 0x14, 0x04, 0x10, 0xF1, 0x80, 0x01, 0xAE, 0x9B, 0x02, 0x20, + 0x00, 0x08, 0xC2, 0x03, 0x96, 0x90, 0xD5, 0x02, 0x84, 0x41, 0x80, 0x67, 0x84, 0xA6, 0x42, 0x33, + 0x14, 0x73, 0xAE, 0x9C, 0x02, 0x00, 0x00, 0x09, 0xC0, 0x03, 0x96, 0x00, 0xD5, 0x02, 0x84, 0x01, + 0xAE, 0x1D, 0x84, 0x1F, 0x10, 0x03, 0x80, 0x3C, 0x10, 0x03, 0x80, 0x3D, 0x00, 0x00, 0x80, 0x0C, + 0xE6, 0x02, 0xE9, 0x12, 0xB4, 0x0A, 0xF2, 0x01, 0x88, 0x02, 0x00, 0x00, 0x00, 0x39, 0xC8, 0x02, + 0x84, 0x01, 0x98, 0xBE, 0xF3, 0x01, 0x10, 0x01, 0x00, 0x46, 0xB4, 0x0A, 0x88, 0x03, 0x20, 0x00, + 0x00, 0x3A, 0x10, 0x01, 0x00, 0x6E, 0x8C, 0xC1, 0x97, 0xB0, 0xB4, 0x1F, 0x8C, 0x01, 0x96, 0x00, + 0xB6, 0x1F, 0x48, 0xFF, 0xFF, 0x35, 0x10, 0x23, 0x80, 0x3E, 0x10, 0x23, 0x80, 0x3F, 0xD5, 0x54, + 0x5A, 0x28, 0x02, 0x27, 0x84, 0x18, 0x10, 0x03, 0x80, 0x3C, 0x84, 0xC0, 0x84, 0x00, 0x10, 0x03, + 0x80, 0x3D, 0x3C, 0x3D, 0xFC, 0xE3, 0x80, 0x06, 0x00, 0x11, 0x80, 0x0A, 0xE2, 0x01, 0xE8, 0x13, + 0x04, 0x15, 0x00, 0x01, 0x38, 0x10, 0x83, 0x02, 0x5A, 0x18, 0x01, 0x0B, 0x00, 0x23, 0x80, 0x3D, + 0x40, 0x10, 0x80, 0x0C, 0xFE, 0x57, 0x8C, 0xC1, 0x10, 0x13, 0x80, 0x3D, 0x97, 0xB0, 0x8C, 0x01, + 0x96, 0x00, 0xD5, 0xEB, 0x00, 0x03, 0x80, 0x3D, 0x3E, 0x07, 0xF2, 0xD3, 0xD5, 0x2D, 0x2E, 0x37, + 0xF2, 0xD0, 0xC3, 0x14, 0x2E, 0x07, 0xF2, 0xD1, 0xA6, 0x78, 0xE6, 0x1E, 0xE8, 0x05, 0x94, 0x03, + 0x96, 0x57, 0xFE, 0x0F, 0xD5, 0x03, 0x44, 0x00, 0x00, 0xF0, 0xAE, 0x38, 0x2E, 0x07, 0xF2, 0xD2, + 0xAE, 0xF9, 0xAE, 0x3A, 0x84, 0x01, 0x3E, 0x07, 0xF2, 0xD8, 0x5A, 0x20, 0x03, 0x04, 0x84, 0xC0, + 0xD5, 0x13, 0x84, 0x00, 0x44, 0x32, 0xD0, 0x04, 0xB4, 0x29, 0x38, 0x21, 0x80, 0x01, 0x88, 0x20, + 0xAE, 0x8B, 0xB4, 0x29, 0x38, 0x21, 0x80, 0x01, 0x88, 0x20, 0x92, 0x48, 0x8C, 0x02, 0xAE, 0x8C, + 0x5A, 0x08, 0x28, 0xF4, 0xD5, 0xED, 0x2E, 0x07, 0xF2, 0xD8, 0x5A, 0x00, 0xFF, 0x0D, 0xC0, 0x0B, + 0xCE, 0x0A, 0x84, 0x1F, 0x3E, 0x07, 0xF2, 0xD8, 0x3C, 0x0D, 0xFC, 0xB5, 0x8C, 0x01, 0x3C, 0x0F, + 0xFC, 0xB5, 0xD5, 0x03, 0x3E, 0x67, 0xF2, 0xD8, 0x3C, 0x3D, 0xFA, 0x72, 0x5A, 0x38, 0x01, 0x16, + 0x3C, 0x0D, 0xFC, 0xE3, 0x00, 0x40, 0x00, 0x09, 0xE2, 0xC4, 0xE8, 0x0F, 0x84, 0x26, 0xB4, 0x49, + 0x84, 0x06, 0xFE, 0x74, 0x8A, 0x86, 0xFF, 0x04, 0x96, 0x48, 0x88, 0x22, 0x50, 0x0F, 0x80, 0x0F, + 0x84, 0x40, 0x8E, 0x81, 0x49, 0xFF, 0xFE, 0x60, 0xB4, 0x29, 0x84, 0x00, 0x10, 0x00, 0x80, 0x3E, + 0xB4, 0x29, 0x10, 0x00, 0x80, 0x3F, 0xB4, 0x29, 0x84, 0x00, 0x80, 0xA1, 0x50, 0x20, 0x80, 0x40, + 0x08, 0x32, 0x80, 0x01, 0x88, 0x03, 0x96, 0x00, 0xDA, 0xFC, 0xFE, 0x02, 0x10, 0x00, 0x80, 0x40, + 0x84, 0x01, 0xC6, 0x02, 0x84, 0x00, 0x3E, 0x07, 0xF3, 0x02, 0xFC, 0xC2, 0xFC, 0x20, 0x84, 0x41, + 0x80, 0x62, 0x44, 0x40, 0x00, 0x40, 0x80, 0xE0, 0x80, 0xC1, 0x49, 0xFF, 0xFE, 0x3D, 0x3C, 0x0D, + 0xFC, 0xE3, 0x00, 0x00, 0x00, 0x0C, 0xE6, 0x02, 0xE9, 0x10, 0x50, 0x53, 0x80, 0x46, 0x50, 0x13, + 0x00, 0x46, 0x50, 0x73, 0x80, 0x50, 0x08, 0x02, 0x80, 0x01, 0x18, 0x00, 0x80, 0x01, 0x20, 0x02, + 0x80, 0x27, 0x10, 0x00, 0x80, 0x27, 0xDF, 0xF8, 0xFC, 0xA0, 0xA6, 0x00, 0x92, 0x03, 0x8C, 0x15, + 0x96, 0x27, 0x5C, 0x00, 0x00, 0x14, 0xDD, 0x9E, 0xFC, 0x40, 0x80, 0xC1, 0xA6, 0x40, 0x84, 0x40, + 0x81, 0x20, 0x3E, 0x27, 0xF3, 0x01, 0xC1, 0x31, 0x2E, 0x07, 0xF2, 0xFD, 0x5A, 0x08, 0x01, 0x0C, + 0x2E, 0x17, 0xF3, 0x00, 0x3E, 0x27, 0xF2, 0xFC, 0x3E, 0x17, 0xF2, 0xFE, 0x3E, 0x17, 0xF2, 0xFF, + 0x3E, 0x07, 0xF3, 0x01, 0x49, 0xFF, 0xFD, 0xB3, 0x3C, 0x0D, 0xFC, 0xE4, 0x2E, 0x77, 0xF2, 0xFF, + 0x3C, 0x1D, 0xFC, 0xBE, 0xA7, 0x04, 0x84, 0x41, 0x04, 0x04, 0x80, 0x01, 0x42, 0x13, 0x90, 0x73, + 0x80, 0x62, 0x8E, 0x81, 0x49, 0xFF, 0xFD, 0xF8, 0x2E, 0x07, 0xF3, 0x02, 0x5A, 0x08, 0x01, 0x06, + 0x3E, 0x07, 0xF2, 0xFD, 0x3E, 0x77, 0xF3, 0x00, 0x2E, 0x07, 0xF2, 0xCC, 0x5A, 0x00, 0xFF, 0x08, + 0x8C, 0x01, 0x3E, 0x07, 0xF2, 0xCC, 0xD5, 0x03, 0x3E, 0x17, 0xF2, 0xCC, 0x2E, 0x17, 0xF3, 0x01, + 0xB4, 0x06, 0x5A, 0x18, 0x01, 0x32, 0xA6, 0x05, 0xC8, 0x18, 0x49, 0x00, 0x51, 0x81, 0xC8, 0x0F, + 0x3C, 0x0D, 0xFC, 0xE4, 0xB4, 0x26, 0x2E, 0x37, 0xF3, 0x00, 0xA6, 0x84, 0x3C, 0x0D, 0xFC, 0xBE, + 0x42, 0x01, 0x88, 0x73, 0xB4, 0x21, 0x49, 0xFF, 0xFF, 0x8B, 0xD5, 0x0A, 0x49, 0x00, 0x51, 0x5F, + 0x49, 0x00, 0x51, 0x6E, 0xC8, 0xFE, 0xD5, 0xED, 0x49, 0x00, 0x51, 0x6A, 0xC8, 0x03, 0x49, 0x00, + 0x51, 0x77, 0xB4, 0x26, 0x84, 0x00, 0x3E, 0x07, 0xF3, 0x01, 0x3E, 0x07, 0xF2, 0xFD, 0x84, 0x01, + 0xAE, 0x0D, 0xB4, 0x26, 0xAE, 0x0C, 0xB4, 0xC6, 0xB4, 0x06, 0x49, 0xFF, 0xFF, 0x90, 0x5A, 0x08, + 0x01, 0x41, 0xAE, 0x37, 0xD5, 0x3E, 0xA6, 0x44, 0xC9, 0x05, 0x49, 0xFF, 0xFD, 0xA0, 0xC0, 0x39, + 0xD5, 0x0D, 0xA6, 0x05, 0x5A, 0x08, 0x01, 0x08, 0x49, 0x00, 0x51, 0x4A, 0xC8, 0x32, 0x49, 0x00, + 0x51, 0x57, 0xD5, 0x2F, 0x49, 0xFF, 0xFD, 0x85, 0xC8, 0xF8, 0x49, 0x00, 0x51, 0x41, 0x80, 0xE0, + 0xC8, 0x28, 0x49, 0xFF, 0xFD, 0x66, 0x3C, 0x0D, 0xFC, 0xE4, 0xB4, 0x26, 0x2E, 0x97, 0xF2, 0xFE, + 0xA6, 0x84, 0x3C, 0x0D, 0xFC, 0xBE, 0xB4, 0x21, 0x42, 0x04, 0x88, 0x73, 0x49, 0xFF, 0xFF, 0x48, + 0x2E, 0x17, 0xF2, 0xFD, 0x5A, 0x18, 0x01, 0x11, 0x2E, 0x57, 0xF3, 0x00, 0x4C, 0x54, 0xC0, 0x0D, + 0xB4, 0x06, 0x3E, 0x77, 0xF2, 0xFD, 0xAE, 0x45, 0xB4, 0xE6, 0xB4, 0x07, 0x49, 0xFF, 0xFF, 0x57, + 0x5A, 0x08, 0x01, 0x03, 0xAE, 0x3F, 0x49, 0x00, 0x51, 0x2B, 0xB4, 0x06, 0x84, 0x21, 0xAE, 0x44, + 0xFC, 0xC0, 0xFC, 0x20, 0x80, 0x40, 0x80, 0xE1, 0x44, 0x02, 0xBB, 0xA4, 0xA0, 0x51, 0x44, 0x62, + 0xBB, 0xBC, 0xB6, 0x20, 0x2E, 0x17, 0xF2, 0xD8, 0x3C, 0x6F, 0xFC, 0xBA, 0x10, 0x10, 0x00, 0x08, + 0xA0, 0x52, 0xA8, 0x41, 0x44, 0x12, 0xBB, 0xA0, 0x49, 0xFF, 0xFD, 0x95, 0x44, 0x02, 0xBB, 0x98, + 0x2E, 0x17, 0xF2, 0xD8, 0xA9, 0x81, 0xAE, 0x40, 0xB4, 0x27, 0x3C, 0x1F, 0xFC, 0xB7, 0x44, 0x12, + 0xBB, 0x94, 0x49, 0xFF, 0xFF, 0x33, 0x44, 0x02, 0xBB, 0x88, 0x84, 0x20, 0xAE, 0x40, 0xAE, 0x41, + 0xAE, 0x42, 0x49, 0xFF, 0xFD, 0x3C, 0xFC, 0xA0, 0x3C, 0x0F, 0xFF, 0xDB, 0xDD, 0x9E, 0x3C, 0x0F, + 0xFF, 0xDA, 0xDD, 0x9E, 0xFC, 0x00, 0x44, 0x10, 0x00, 0xE0, 0x42, 0x01, 0x84, 0x73, 0xB4, 0x20, + 0x44, 0x52, 0xD0, 0x58, 0x5A, 0x18, 0x01, 0x1A, 0x44, 0x22, 0xD3, 0xD4, 0x84, 0x80, 0x38, 0x41, + 0x0C, 0x08, 0xA0, 0x86, 0x3C, 0x6C, 0x02, 0x14, 0x94, 0x91, 0x88, 0x46, 0xA7, 0x90, 0x5C, 0xF3, + 0x00, 0x22, 0xE9, 0x0B, 0xA6, 0x91, 0x8E, 0x42, 0xE6, 0x4C, 0xE9, 0x07, 0x44, 0x22, 0xD4, 0xB0, + 0x38, 0x12, 0x8C, 0x08, 0x38, 0x41, 0x0C, 0x08, 0x38, 0x22, 0x8C, 0x00, 0x5A, 0x28, 0x01, 0x34, + 0x44, 0x22, 0xD4, 0xB0, 0x38, 0x41, 0x0C, 0x00, 0x5C, 0xF2, 0x00, 0x32, 0xE8, 0x06, 0x5A, 0x10, + 0x04, 0x05, 0x8C, 0x81, 0x38, 0x41, 0x0C, 0x08, 0x38, 0x41, 0x0C, 0x00, 0x5A, 0x40, 0x32, 0x11, + 0x5A, 0x10, 0x04, 0x0F, 0xA0, 0x06, 0x3C, 0x2C, 0x02, 0x14, 0x94, 0x01, 0x88, 0x02, 0xA6, 0x80, + 0x8E, 0x43, 0xE6, 0x5E, 0xE9, 0x05, 0xA6, 0x01, 0x8E, 0x03, 0xE6, 0x0A, 0xE8, 0x14, 0x84, 0x00, + 0x38, 0x02, 0x8C, 0x08, 0x5A, 0x48, 0x32, 0x10, 0x44, 0x02, 0xD3, 0xD4, 0x84, 0x41, 0x38, 0x20, + 0x0C, 0x08, 0x5A, 0x18, 0x02, 0x11, 0x2E, 0x07, 0xEC, 0x5D, 0xC8, 0x0D, 0x84, 0x01, 0x3E, 0x07, + 0xEC, 0x5D, 0xD5, 0x09, 0x5A, 0x18, 0x02, 0x08, 0x44, 0x02, 0xD3, 0xD4, 0x38, 0x00, 0x0C, 0x00, + 0x5A, 0x00, 0x01, 0xF3, 0xFC, 0x80, 0xFC, 0x41, 0xF5, 0x81, 0x97, 0xAB, 0x41, 0xC2, 0xC0, 0x0A, + 0x44, 0x50, 0x00, 0xE0, 0x42, 0x01, 0x94, 0x73, 0x00, 0x50, 0x00, 0x14, 0xB6, 0xDF, 0x97, 0x46, + 0x22, 0x60, 0x80, 0x00, 0x85, 0x41, 0x22, 0x10, 0x80, 0x01, 0x44, 0x72, 0xC7, 0x40, 0x44, 0x92, + 0xC7, 0x04, 0xC5, 0x12, 0x44, 0x52, 0xC7, 0xAC, 0x38, 0x14, 0x8E, 0x0A, 0x38, 0x62, 0x8D, 0x09, + 0x44, 0x52, 0xC7, 0x8C, 0x38, 0x63, 0x8E, 0x0A, 0x38, 0x12, 0x8D, 0x09, 0x44, 0x12, 0xC7, 0x7C, + 0x38, 0xA0, 0x8C, 0x08, 0xD5, 0x66, 0xB4, 0xA0, 0x5A, 0x58, 0x03, 0x21, 0x38, 0x53, 0x8E, 0x02, + 0x44, 0x82, 0xC7, 0x7C, 0x88, 0xC5, 0x38, 0x54, 0x8E, 0x02, 0x38, 0x63, 0x8E, 0x0A, 0x88, 0x25, + 0x38, 0x54, 0x0C, 0x00, 0x38, 0x14, 0x8E, 0x0A, 0x8C, 0xA1, 0x97, 0x68, 0xE6, 0xAF, 0x38, 0x54, + 0x0C, 0x08, 0xE9, 0x4F, 0x40, 0x63, 0x14, 0xD6, 0x40, 0x10, 0x94, 0x36, 0x38, 0x63, 0x8E, 0x0A, + 0x38, 0x14, 0x8E, 0x0A, 0x38, 0xA4, 0x0C, 0x08, 0xD5, 0x44, 0x5A, 0x58, 0x01, 0x3F, 0x44, 0x52, + 0xC7, 0xAC, 0x3C, 0x9D, 0xFF, 0xDB, 0x38, 0x82, 0x8D, 0x11, 0x44, 0x52, 0xC7, 0x8C, 0x38, 0xA2, + 0x8D, 0x11, 0x00, 0x54, 0x80, 0x00, 0x5A, 0x58, 0x01, 0x75, 0x40, 0xF4, 0x18, 0x01, 0x4E, 0xF4, + 0x00, 0x04, 0x52, 0xF7, 0x80, 0x00, 0x40, 0x55, 0x04, 0x01, 0x4E, 0x54, 0x00, 0x03, 0xFF, 0x6A, + 0x88, 0xAF, 0x02, 0xF4, 0x80, 0x04, 0x40, 0xF7, 0x94, 0x06, 0xE8, 0x63, 0x02, 0x54, 0x80, 0x03, + 0xE1, 0x05, 0xE8, 0x03, 0xE0, 0xC5, 0xE8, 0x76, 0x3D, 0xED, 0xFF, 0xDA, 0x02, 0x9F, 0x00, 0x09, + 0x8F, 0x21, 0x8B, 0x25, 0xE1, 0x28, 0xE8, 0x03, 0xE1, 0x26, 0xE8, 0x6C, 0xE1, 0x45, 0xE8, 0x03, + 0xE0, 0x25, 0xE8, 0x68, 0x02, 0x9F, 0x00, 0x0A, 0x8F, 0x21, 0x40, 0x54, 0x94, 0x01, 0xE0, 0xAA, + 0xE8, 0x48, 0xE0, 0xA1, 0xE8, 0x5F, 0xD5, 0x45, 0x38, 0x63, 0x8E, 0x0A, 0x38, 0x14, 0x8E, 0x0A, + 0x00, 0x1F, 0x80, 0x28, 0x44, 0x62, 0xC7, 0x40, 0x44, 0x52, 0xC7, 0x04, 0x5A, 0x18, 0x01, 0x33, + 0xB4, 0x00, 0x5A, 0x08, 0x01, 0x30, 0x3C, 0x9D, 0xFF, 0xDB, 0x02, 0x04, 0x80, 0x05, 0xE2, 0x80, + 0xE8, 0x29, 0x38, 0x03, 0x0E, 0x02, 0xB4, 0x3F, 0x38, 0x72, 0x8E, 0x02, 0x9A, 0x41, 0x4E, 0x14, + 0x00, 0x03, 0xFE, 0x4A, 0x40, 0x43, 0xF0, 0x01, 0x4E, 0x44, 0x00, 0x03, 0xFF, 0x22, 0x88, 0x81, + 0x02, 0x14, 0x80, 0x06, 0xE0, 0x81, 0xE8, 0x16, 0x02, 0x44, 0x80, 0x07, 0xB5, 0x5F, 0x50, 0x92, + 0x7F, 0xFF, 0x40, 0x12, 0x04, 0x09, 0x42, 0x04, 0xA8, 0x73, 0x42, 0x74, 0xF0, 0x73, 0x88, 0x01, + 0x88, 0x27, 0x40, 0x00, 0x10, 0x16, 0x40, 0x10, 0x90, 0x36, 0x38, 0x03, 0x0E, 0x0A, 0x38, 0x12, + 0x8E, 0x0A, 0x38, 0x03, 0x0E, 0x02, 0xAC, 0x10, 0x38, 0x02, 0x8E, 0x02, 0xAC, 0x11, 0xFC, 0xC1, + 0x38, 0x53, 0x8E, 0x02, 0x44, 0x92, 0xC7, 0x04, 0x88, 0xC5, 0x44, 0xA2, 0xC7, 0x7C, 0x38, 0x54, + 0x8E, 0x02, 0x88, 0x25, 0x38, 0x55, 0x0C, 0x00, 0x8C, 0xA1, 0x97, 0x68, 0x40, 0x63, 0x14, 0xD6, + 0x38, 0x55, 0x0C, 0x08, 0x40, 0x50, 0x94, 0xB6, 0x38, 0x63, 0x8E, 0x0A, 0x38, 0x54, 0x8E, 0x0A, + 0xD5, 0xA8, 0x44, 0x12, 0xC7, 0x40, 0x38, 0x80, 0x8E, 0x0A, 0x44, 0x12, 0xC7, 0x04, 0x38, 0xA0, + 0x8E, 0x0A, 0xD5, 0x9F, 0xFC, 0x42, 0x22, 0x40, 0x80, 0x00, 0x22, 0x60, 0x80, 0x01, 0x44, 0x10, + 0x00, 0xE0, 0x42, 0x01, 0x84, 0x73, 0xB4, 0x20, 0x84, 0xFD, 0xFF, 0xCE, 0xF2, 0x82, 0x44, 0x12, + 0xC6, 0xC8, 0x95, 0x5A, 0x3C, 0x9D, 0xFF, 0xDB, 0x5A, 0x78, 0x01, 0x17, 0xAD, 0x10, 0xAD, 0x91, + 0x38, 0x40, 0x8E, 0x09, 0x00, 0x04, 0x80, 0x05, 0x88, 0x25, 0xAD, 0x89, 0x5A, 0x00, 0x01, 0x04, + 0x48, 0x00, 0x00, 0xF3, 0x44, 0x02, 0xC6, 0x8C, 0x88, 0xA0, 0x84, 0x20, 0x38, 0x10, 0x0E, 0x09, + 0xAC, 0x69, 0x48, 0x00, 0x00, 0xEA, 0x00, 0x24, 0x80, 0x05, 0x00, 0xA0, 0x00, 0x14, 0xF2, 0x83, + 0x5A, 0x28, 0x01, 0x40, 0x54, 0x05, 0x00, 0x02, 0xC0, 0x3C, 0x44, 0x02, 0xC6, 0x8C, 0x38, 0x70, + 0x0E, 0x11, 0xCF, 0x08, 0x88, 0xA0, 0x22, 0x02, 0x80, 0x01, 0xC0, 0x33, 0x38, 0x40, 0x8E, 0x11, + 0xD5, 0x30, 0x88, 0x05, 0x22, 0x00, 0x00, 0x01, 0xC8, 0x05, 0x88, 0xA1, 0x22, 0x62, 0x80, 0x01, + 0xD5, 0x28, 0x88, 0xA1, 0x81, 0xE4, 0x22, 0x42, 0x80, 0x01, 0x52, 0x93, 0x80, 0x00, 0xFF, 0xE4, + 0x38, 0x40, 0x8E, 0x11, 0x42, 0x50, 0x00, 0x24, 0x42, 0x70, 0x10, 0x75, 0x42, 0x44, 0xA4, 0x24, + 0x40, 0x82, 0x90, 0x00, 0x43, 0xC0, 0x24, 0x24, 0x42, 0x42, 0x3C, 0x24, 0x42, 0x4E, 0x18, 0x75, + 0x42, 0x40, 0x1C, 0x75, 0xFE, 0x02, 0x42, 0x00, 0x24, 0x24, 0xFF, 0xAC, 0x42, 0x60, 0x3C, 0x73, + 0x42, 0x64, 0x9C, 0x75, 0x40, 0x42, 0x20, 0x96, 0x40, 0x63, 0x20, 0xD6, 0x97, 0x23, 0x97, 0xB3, + 0x54, 0x05, 0x00, 0x02, 0x4E, 0x02, 0x00, 0x83, 0x3C, 0x0D, 0xFF, 0xDA, 0x80, 0xE4, 0x02, 0xA0, + 0x00, 0x09, 0xE0, 0x8A, 0xE9, 0x08, 0x38, 0x90, 0x8E, 0x11, 0xE1, 0x2A, 0xE8, 0x0F, 0x50, 0x95, + 0x7F, 0xFF, 0xD5, 0x0C, 0x4E, 0x44, 0x00, 0x08, 0x38, 0x90, 0x8E, 0x11, 0x4E, 0x95, 0x00, 0x07, + 0x85, 0x20, 0xD5, 0x04, 0x81, 0x24, 0x85, 0x00, 0xD5, 0x02, 0x85, 0x01, 0x02, 0x50, 0x00, 0x0A, + 0x41, 0xE1, 0x88, 0x08, 0xE0, 0xC5, 0x80, 0x06, 0xE9, 0x0A, 0x40, 0x80, 0xF8, 0x00, 0x22, 0x84, + 0x00, 0x01, 0xE1, 0x05, 0xE8, 0x10, 0x50, 0x82, 0xFF, 0xFF, 0xD5, 0x0D, 0x4E, 0x64, 0x00, 0x09, + 0x40, 0x80, 0xF8, 0x00, 0x22, 0x84, 0x00, 0x01, 0x4E, 0x84, 0x00, 0x69, 0xD5, 0x04, 0x5A, 0x88, + 0x01, 0x4E, 0x81, 0x06, 0x39, 0xC0, 0x8E, 0x11, 0x41, 0xE0, 0xF8, 0x00, 0x40, 0x22, 0x70, 0x01, + 0xB6, 0x5F, 0x22, 0x2F, 0x00, 0x01, 0xF2, 0x81, 0x40, 0xF3, 0x08, 0x01, 0xB4, 0x5F, 0xC2, 0x0C, + 0x84, 0x02, 0x40, 0x01, 0x00, 0x16, 0x41, 0xE4, 0xF0, 0x01, 0x42, 0x0F, 0x3C, 0x73, 0x40, 0x00, + 0x08, 0x16, 0xF2, 0x01, 0x88, 0x02, 0xE8, 0x0D, 0xF2, 0x01, 0x84, 0xE2, 0x41, 0xE4, 0x08, 0x01, + 0xB4, 0x5F, 0x40, 0x77, 0x9C, 0xF6, 0x42, 0x7F, 0x08, 0x73, 0x40, 0x73, 0xBC, 0xF6, 0x88, 0xFC, + 0xF2, 0x01, 0x4C, 0x81, 0x00, 0x3E, 0xE0, 0xEA, 0xE9, 0x05, 0x52, 0xA5, 0x00, 0x01, 0x89, 0x47, + 0xD5, 0x05, 0x4E, 0x74, 0x00, 0x36, 0x52, 0xA3, 0x80, 0x00, 0x4C, 0x9E, 0x00, 0x0C, 0xE0, 0x05, + 0xE9, 0x05, 0x52, 0x52, 0x80, 0x01, 0x88, 0xA0, 0xD5, 0x06, 0x4E, 0x04, 0x00, 0x04, 0xFF, 0x42, + 0xD5, 0x02, 0x84, 0xA0, 0xE0, 0xAA, 0xE8, 0x05, 0x40, 0x44, 0x80, 0x11, 0x97, 0x83, 0xD5, 0x06, + 0xE1, 0x45, 0xE8, 0x04, 0x97, 0x3B, 0x40, 0x64, 0x00, 0x11, 0xF2, 0x03, 0x94, 0x1A, 0x5A, 0x28, + 0x01, 0x0E, 0x38, 0x70, 0x8E, 0x01, 0x44, 0x52, 0xC6, 0x8C, 0x9B, 0xE7, 0x38, 0x72, 0x8E, 0x09, + 0x99, 0xC8, 0x88, 0xA0, 0xA5, 0xF9, 0x9B, 0xF7, 0xAD, 0xE9, 0x38, 0x40, 0x8E, 0x09, 0x88, 0x20, + 0xF0, 0x02, 0xAD, 0x89, 0xAD, 0x00, 0xAD, 0x81, 0xD5, 0x07, 0x85, 0x00, 0xD5, 0x9C, 0x85, 0x40, + 0x4C, 0x9E, 0x7F, 0xCF, 0xD5, 0xE3, 0xFC, 0xC2, 0xFC, 0x40, 0x44, 0x60, 0x00, 0xE0, 0x42, 0x01, + 0x98, 0x73, 0xB4, 0x00, 0x84, 0xDD, 0xFE, 0x36, 0x22, 0x50, 0x80, 0x00, 0x44, 0xA2, 0xC2, 0x68, + 0x22, 0x10, 0x80, 0x01, 0x44, 0x62, 0xC2, 0x58, 0x40, 0x91, 0x90, 0x08, 0x44, 0x72, 0xBE, 0x98, + 0x44, 0x82, 0xBE, 0x88, 0x5A, 0x08, 0x01, 0x14, 0x38, 0x03, 0x0C, 0x08, 0x3C, 0x0D, 0xFF, 0xDB, + 0x84, 0x80, 0x38, 0x45, 0x0C, 0x08, 0x95, 0x1E, 0x88, 0x87, 0x00, 0x00, 0x00, 0x1C, 0x38, 0x53, + 0xA6, 0x09, 0xAC, 0x61, 0x38, 0x04, 0x0C, 0x08, 0x48, 0x00, 0x00, 0xA1, 0x38, 0x03, 0x0C, 0x00, + 0xE6, 0x10, 0xE8, 0x04, 0x8C, 0x01, 0x38, 0x03, 0x0C, 0x08, 0x38, 0x05, 0x0C, 0x00, 0x45, 0xC2, + 0xC2, 0x68, 0xE6, 0x0F, 0xE9, 0x03, 0x84, 0x00, 0xD5, 0x02, 0x8C, 0x01, 0x38, 0x0E, 0x0C, 0x08, + 0x38, 0xA5, 0x0C, 0x00, 0x40, 0x05, 0x24, 0x00, 0x38, 0x53, 0x82, 0x09, 0x94, 0x02, 0x88, 0x07, + 0xAC, 0x41, 0x3C, 0x0D, 0xFF, 0xDB, 0x03, 0xC0, 0x00, 0x10, 0xE0, 0x9C, 0xE9, 0x04, 0x00, 0x50, + 0x00, 0x1C, 0xD5, 0x13, 0x03, 0xE0, 0x00, 0x0F, 0x00, 0x50, 0x00, 0x1D, 0x40, 0xFF, 0x10, 0x07, + 0xE8, 0x0C, 0x00, 0x00, 0x00, 0x1C, 0x40, 0x12, 0x78, 0x01, 0x8A, 0x05, 0xFE, 0x0C, 0x40, 0x4E, + 0x78, 0x01, 0x40, 0x40, 0x10, 0x96, 0x88, 0xA4, 0x39, 0xC4, 0x0C, 0x00, 0x84, 0x03, 0x80, 0x3C, + 0x42, 0x12, 0x80, 0x73, 0x8C, 0x22, 0x84, 0x04, 0x40, 0x00, 0x80, 0x16, 0x40, 0xFE, 0x00, 0x07, + 0x44, 0x42, 0xBE, 0x88, 0xE8, 0x06, 0x50, 0x1E, 0x00, 0x01, 0xE0, 0x20, 0x40, 0x00, 0xBC, 0x1B, + 0x38, 0x02, 0x0C, 0x08, 0x38, 0x13, 0x0C, 0x00, 0x38, 0x44, 0x0C, 0x00, 0x84, 0x6A, 0x42, 0x60, + 0x8C, 0x24, 0xE0, 0xC4, 0xE9, 0x05, 0xE2, 0x83, 0x40, 0x41, 0xBC, 0x1B, 0x80, 0xC4, 0x84, 0xA0, + 0x84, 0x2A, 0x40, 0x13, 0x04, 0x36, 0x80, 0x05, 0x80, 0x65, 0xD1, 0x12, 0x40, 0x45, 0x24, 0x00, + 0x38, 0x83, 0x92, 0x11, 0x95, 0x22, 0x88, 0x87, 0x88, 0x68, 0x22, 0x42, 0x00, 0x01, 0x88, 0x04, + 0x4E, 0xA2, 0x00, 0x04, 0x8F, 0x41, 0xD5, 0x02, 0x85, 0x4F, 0x8C, 0xA1, 0xD5, 0xEF, 0x84, 0x8A, + 0x40, 0x13, 0x10, 0xB6, 0xFE, 0xE4, 0xFE, 0x24, 0xC5, 0x0D, 0x40, 0x45, 0x24, 0x00, 0x38, 0x13, + 0x92, 0x11, 0x95, 0x22, 0x88, 0x87, 0x42, 0x32, 0x84, 0x73, 0x22, 0x12, 0x00, 0x01, 0x42, 0x02, + 0x84, 0x73, 0x4E, 0x35, 0x00, 0x06, 0x40, 0x53, 0x04, 0x0A, 0x88, 0xA3, 0xD5, 0x05, 0x84, 0xA2, + 0x40, 0x53, 0x14, 0xB6, 0x9B, 0x5D, 0x40, 0x52, 0x98, 0xB6, 0x97, 0x6B, 0x4E, 0x05, 0x00, 0x08, + 0x40, 0x13, 0x04, 0x0A, 0x88, 0x20, 0x40, 0x10, 0x98, 0x36, 0xD5, 0x07, 0x84, 0x22, 0x40, 0x13, + 0x04, 0x36, 0x8A, 0x01, 0x40, 0x10, 0x18, 0x36, 0x96, 0x4B, 0xAD, 0x50, 0xAC, 0x51, 0xFC, 0xC0, + 0xFC, 0x40, 0x22, 0x60, 0x80, 0x00, 0x22, 0x50, 0x80, 0x01, 0x44, 0x10, 0x00, 0xE0, 0x42, 0x01, + 0x84, 0x73, 0xB4, 0x00, 0x84, 0x3D, 0xFE, 0x0E, 0x44, 0x72, 0xBE, 0x4C, 0x40, 0x91, 0x88, 0x08, + 0x44, 0xA2, 0xBE, 0x3C, 0x5A, 0x08, 0x01, 0x0E, 0x40, 0x03, 0xA4, 0x00, 0x38, 0x63, 0x8E, 0x09, + 0xAD, 0x41, 0x3C, 0x0D, 0xFF, 0xDB, 0x00, 0x00, 0x00, 0x23, 0x38, 0x05, 0x0C, 0x08, 0xD5, 0x6B, + 0x2E, 0x00, 0x06, 0x2D, 0x5A, 0x08, 0x01, 0x12, 0x5E, 0xF2, 0x00, 0x44, 0xE9, 0x2B, 0x5E, 0xF2, + 0x00, 0xC8, 0xE8, 0x2A, 0x50, 0x42, 0x7F, 0xBD, 0xFA, 0x33, 0xFF, 0x0C, 0x44, 0x00, 0x00, 0x85, + 0x40, 0x42, 0x00, 0x96, 0x8C, 0x99, 0xD5, 0x22, 0x3D, 0xCD, 0xFF, 0xDB, 0x02, 0x8E, 0x00, 0x12, + 0xE1, 0x04, 0xE9, 0x04, 0x00, 0x4E, 0x00, 0x22, 0xD5, 0x19, 0x02, 0x1E, 0x00, 0x13, 0x00, 0x0E, + 0x00, 0x23, 0xE0, 0x81, 0xE9, 0x03, 0x80, 0x80, 0xD5, 0x11, 0x00, 0xFE, 0x00, 0x22, 0x8A, 0x88, + 0x8A, 0x0F, 0xFE, 0x24, 0x40, 0x40, 0xA0, 0x01, 0x40, 0x00, 0x10, 0x16, 0x40, 0x40, 0x3C, 0x00, + 0xD5, 0x05, 0xFA, 0x89, 0xD5, 0x03, 0x44, 0x40, 0x00, 0x3C, 0x38, 0x05, 0x0C, 0x00, 0x84, 0x23, + 0x42, 0x02, 0x04, 0x73, 0x8C, 0x02, 0x84, 0x24, 0x40, 0x00, 0x04, 0x16, 0x40, 0x13, 0xA4, 0x00, + 0x38, 0x05, 0x0C, 0x08, 0x96, 0x00, 0x38, 0xA3, 0x8E, 0x11, 0x22, 0x40, 0x80, 0x01, 0xFF, 0x84, + 0x52, 0x10, 0x00, 0x64, 0x42, 0x60, 0xA8, 0x73, 0x44, 0xA0, 0x00, 0x64, 0x4E, 0x65, 0x00, 0x05, + 0x50, 0x63, 0x00, 0x32, 0xD5, 0x03, 0x50, 0x63, 0x7F, 0xCE, 0xFF, 0x44, 0x40, 0x63, 0x28, 0xD6, + 0x42, 0x50, 0x90, 0x73, 0x38, 0x63, 0x8E, 0x09, 0x44, 0x00, 0x00, 0x64, 0x4E, 0x55, 0x00, 0x05, + 0x50, 0x52, 0x80, 0x32, 0xD5, 0x03, 0x50, 0x52, 0xFF, 0xCE, 0x40, 0x52, 0x80, 0xB6, 0x40, 0x03, + 0xA4, 0x00, 0xAD, 0x41, 0x38, 0x03, 0x8E, 0x01, 0x88, 0xE9, 0xAC, 0x10, 0xA4, 0x39, 0xAC, 0x11, + 0xFC, 0xC0, 0x80, 0x60, 0x80, 0x40, 0x84, 0x01, 0x9A, 0x50, 0xE6, 0x22, 0xE9, 0x0B, 0x98, 0x50, + 0x92, 0x21, 0x42, 0xF0, 0x84, 0x24, 0xE2, 0x6F, 0x40, 0x00, 0xBC, 0x1A, 0x40, 0x20, 0xBC, 0x1B, + 0xD5, 0xF4, 0xDD, 0x9E, 0x22, 0x20, 0x00, 0x00, 0x22, 0x30, 0x80, 0x00, 0x22, 0x00, 0x00, 0x01, + 0x22, 0x10, 0x80, 0x01, 0x8A, 0x43, 0x8A, 0x01, 0xFE, 0x04, 0x42, 0x01, 0x08, 0x73, 0xDD, 0x9E, + 0xFC, 0x40, 0x81, 0x21, 0x44, 0x10, 0x00, 0xE0, 0x42, 0x01, 0x04, 0x73, 0xB4, 0x20, 0x80, 0xC2, + 0x45, 0xC2, 0xC6, 0x7C, 0x44, 0x82, 0xC6, 0x6C, 0x95, 0xD2, 0x44, 0xA2, 0xC6, 0x30, 0xC1, 0x0D, + 0x00, 0x00, 0x00, 0x14, 0x96, 0x06, 0xC0, 0x09, 0x84, 0x03, 0x38, 0x0E, 0x08, 0x08, 0x84, 0x00, + 0x38, 0x04, 0x08, 0x08, 0x84, 0x00, 0xD5, 0x3C, 0x38, 0x04, 0x18, 0x00, 0xE6, 0x04, 0xE8, 0x06, + 0x44, 0x12, 0xC6, 0x6C, 0x8C, 0x01, 0x38, 0x00, 0x98, 0x08, 0x38, 0x0E, 0x18, 0x00, 0x44, 0x12, + 0xC6, 0x7C, 0xE6, 0x03, 0xE9, 0x03, 0x84, 0x00, 0xD5, 0x02, 0x8C, 0x01, 0x38, 0x00, 0x98, 0x08, + 0x80, 0x29, 0x40, 0x05, 0x1C, 0x00, 0x49, 0xFF, 0xFF, 0xBF, 0x44, 0x10, 0x00, 0x64, 0xFE, 0x0C, + 0x49, 0xFF, 0xFF, 0xA9, 0x38, 0x1E, 0x18, 0x00, 0x44, 0x21, 0x00, 0x00, 0x88, 0x27, 0xE2, 0x40, + 0x44, 0x32, 0xC5, 0xB8, 0x40, 0x01, 0x3C, 0x1B, 0x84, 0x40, 0x38, 0x01, 0x85, 0x09, 0x38, 0x14, + 0x18, 0x00, 0x80, 0x02, 0xE2, 0x41, 0xE8, 0x07, 0x99, 0x17, 0x8C, 0x41, 0x38, 0x41, 0x91, 0x01, + 0x88, 0x04, 0xD5, 0xF9, 0x40, 0x20, 0x84, 0x09, 0x88, 0x02, 0x40, 0x00, 0x04, 0x16, 0x22, 0x14, + 0x80, 0x00, 0x88, 0xEA, 0x38, 0x15, 0x1A, 0x09, 0x22, 0x14, 0x80, 0x01, 0xAC, 0x79, 0xFC, 0xC0, + 0x3C, 0x2D, 0xFF, 0xDA, 0x22, 0x10, 0x00, 0x00, 0x02, 0x31, 0x00, 0x09, 0x40, 0x41, 0x84, 0x09, + 0xE0, 0x81, 0xE8, 0x03, 0x9A, 0x59, 0x96, 0x4B, 0x02, 0x21, 0x00, 0x0A, 0x22, 0x00, 0x00, 0x01, + 0x40, 0x31, 0x04, 0x09, 0xE0, 0x60, 0xE8, 0x03, 0x9A, 0x10, 0x96, 0x03, 0xE0, 0x20, 0x40, 0x00, + 0xBC, 0x1B, 0x3C, 0x1D, 0xFF, 0xDB, 0x02, 0x10, 0x80, 0x0C, 0xE0, 0x20, 0xE9, 0x02, 0x96, 0x0B, + 0xDD, 0x9E, 0xFC, 0x40, 0x2E, 0x77, 0xEC, 0x2F, 0x44, 0x32, 0xC8, 0x00, 0x44, 0x62, 0xC7, 0xE0, + 0x5A, 0x78, 0x01, 0x54, 0xE6, 0x2C, 0xE9, 0x51, 0x5C, 0xF1, 0x00, 0x65, 0x22, 0x92, 0x00, 0x00, + 0x22, 0x72, 0x80, 0x00, 0x22, 0x42, 0x00, 0x01, 0x22, 0x12, 0x80, 0x01, 0xE9, 0x26, 0xFE, 0x64, + 0x42, 0x14, 0x9C, 0x73, 0x4E, 0x17, 0x00, 0x22, 0xF4, 0x09, 0xF5, 0x08, 0xFE, 0x4C, 0xFF, 0x2C, + 0x40, 0x10, 0x90, 0x37, 0xC1, 0x1A, 0x38, 0x11, 0x81, 0x01, 0xE6, 0x23, 0xE8, 0x04, 0x8C, 0x21, + 0x38, 0x11, 0x81, 0x09, 0x38, 0x31, 0x81, 0x01, 0x44, 0x12, 0xC8, 0x00, 0x5A, 0x38, 0x03, 0x16, + 0x5C, 0xF1, 0x06, 0x41, 0xE9, 0x06, 0x84, 0x40, 0x38, 0x20, 0x81, 0x09, 0x84, 0x21, 0xD5, 0x11, + 0x84, 0x42, 0x38, 0x20, 0x81, 0x09, 0xD5, 0x29, 0x38, 0x11, 0x81, 0x01, 0xC1, 0x06, 0x44, 0x32, + 0xC8, 0x00, 0x8E, 0x21, 0x38, 0x11, 0x81, 0x09, 0x5C, 0xF1, 0x06, 0x41, 0xE9, 0x1E, 0x84, 0x20, + 0x38, 0x23, 0x01, 0x01, 0xE6, 0x43, 0xE8, 0x06, 0x44, 0x32, 0xC7, 0xE0, 0x8C, 0x41, 0x38, 0x21, + 0x81, 0x09, 0x38, 0x23, 0x01, 0x01, 0x5A, 0x28, 0x03, 0x1A, 0x44, 0x12, 0xC7, 0xE0, 0x84, 0x40, + 0x38, 0x20, 0x81, 0x09, 0x84, 0x21, 0xD5, 0x12, 0x38, 0x11, 0x81, 0x01, 0xC1, 0x06, 0x44, 0x22, + 0xC8, 0x00, 0x8E, 0x21, 0x38, 0x11, 0x01, 0x09, 0x38, 0x13, 0x01, 0x01, 0xC1, 0x06, 0x44, 0x22, + 0xC7, 0xE0, 0x8E, 0x21, 0x38, 0x11, 0x01, 0x09, 0x84, 0x20, 0x80, 0x01, 0xFC, 0xC0, 0xFC, 0x41, + 0x80, 0xE1, 0xF3, 0x81, 0x80, 0xC2, 0x81, 0x24, 0x49, 0xFF, 0xFE, 0xED, 0xE2, 0x07, 0xF3, 0x01, + 0xE9, 0x07, 0x2E, 0x17, 0xEC, 0x2F, 0x5A, 0x18, 0x01, 0x0A, 0xE7, 0x2C, 0xE9, 0x07, 0xCB, 0x03, + 0x9A, 0x38, 0xD5, 0x13, 0x8A, 0xC7, 0x88, 0x06, 0xD5, 0x10, 0x3C, 0x0D, 0xFF, 0xDB, 0x00, 0x40, + 0x00, 0x1B, 0xE0, 0x87, 0xE8, 0x05, 0x80, 0x06, 0x40, 0x01, 0x8C, 0x1A, 0xD5, 0x06, 0xCB, 0x03, + 0x9A, 0x3C, 0xD5, 0x03, 0x9A, 0x37, 0x88, 0x04, 0xFC, 0xC1, 0xFC, 0x41, 0x22, 0x61, 0x00, 0x00, + 0x80, 0xE2, 0xF3, 0x81, 0x84, 0x40, 0x80, 0x62, 0x81, 0x00, 0xB6, 0x3F, 0x80, 0x01, 0xF4, 0x01, + 0x80, 0x26, 0x49, 0xFF, 0xFF, 0xCE, 0x3D, 0xCD, 0xFF, 0xDA, 0x81, 0x40, 0x84, 0x61, 0x02, 0x2E, + 0x00, 0x09, 0xF4, 0x01, 0x9A, 0x56, 0x96, 0x4B, 0xB4, 0x1F, 0x49, 0xFF, 0xFF, 0xC2, 0x22, 0x63, + 0x80, 0x01, 0x84, 0x40, 0x80, 0x62, 0x80, 0x26, 0xF4, 0x01, 0x81, 0x20, 0xB4, 0x1F, 0x49, 0xFF, + 0xFF, 0xB8, 0x02, 0x2E, 0x00, 0x0A, 0x80, 0xE0, 0x9A, 0x56, 0x96, 0x4B, 0xB4, 0x1F, 0x84, 0x61, + 0xF4, 0x01, 0x49, 0xFF, 0xFF, 0xAE, 0x80, 0x20, 0x22, 0x04, 0x00, 0x00, 0xE0, 0x0A, 0xE9, 0x0A, + 0xE1, 0x20, 0xE9, 0x08, 0x22, 0x04, 0x00, 0x01, 0xE0, 0x07, 0xE9, 0x04, 0x40, 0x00, 0x80, 0x07, + 0xD5, 0x02, 0x84, 0x01, 0xFC, 0xC1, 0xFC, 0x45, 0x22, 0x80, 0x80, 0x00, 0xF2, 0x84, 0x22, 0x20, + 0x80, 0x01, 0x44, 0x10, 0x00, 0xE0, 0x42, 0x01, 0x84, 0x73, 0x81, 0x20, 0xA0, 0x46, 0x3C, 0x0C, + 0x02, 0x12, 0x12, 0x8F, 0x80, 0x12, 0x12, 0x2F, 0x80, 0x13, 0x38, 0x40, 0x05, 0x01, 0xB4, 0x09, + 0x84, 0x3D, 0xFE, 0x0E, 0x80, 0xC3, 0x12, 0x44, 0x80, 0x08, 0x44, 0xA2, 0xC5, 0x7C, 0x44, 0x72, + 0xC5, 0x40, 0x44, 0x32, 0xC5, 0x04, 0x44, 0x52, 0xC4, 0x50, 0x5A, 0x08, 0x01, 0x5D, 0x44, 0x02, + 0xC7, 0xD0, 0x84, 0x20, 0x44, 0x22, 0xC4, 0xC8, 0x38, 0x10, 0x18, 0x08, 0x84, 0x00, 0x38, 0x01, + 0x1A, 0x0A, 0x44, 0x22, 0xC4, 0x8C, 0x38, 0x01, 0x9A, 0x0A, 0x38, 0x01, 0x1A, 0x09, 0x44, 0x32, + 0xC4, 0x8C, 0x94, 0xB2, 0x88, 0x62, 0x38, 0x02, 0x9A, 0x09, 0x88, 0xA2, 0x44, 0x22, 0xC4, 0x14, + 0xAC, 0x19, 0x38, 0x01, 0x1A, 0x0A, 0xAC, 0x29, 0x3C, 0x0D, 0xFB, 0x4D, 0xF1, 0x09, 0x44, 0x22, + 0xC3, 0xD8, 0xA4, 0x00, 0x38, 0x15, 0x1A, 0x0A, 0x92, 0x06, 0x96, 0x06, 0x38, 0x13, 0x9A, 0x0A, + 0xC8, 0x17, 0x44, 0x32, 0xC8, 0x00, 0x38, 0x01, 0x99, 0x09, 0x44, 0x32, 0xC7, 0xE0, 0x38, 0x01, + 0x99, 0x09, 0x2E, 0x07, 0xEC, 0x2F, 0x5A, 0x08, 0x01, 0x07, 0xE6, 0x8C, 0xE9, 0x04, 0x44, 0x00, + 0x7E, 0x90, 0xD5, 0x08, 0x3C, 0x0D, 0xFF, 0xDB, 0x02, 0x00, 0x00, 0x08, 0xD5, 0x03, 0x44, 0x00, + 0x03, 0x84, 0x38, 0x01, 0x1A, 0x0A, 0x44, 0x02, 0xC3, 0x9C, 0x38, 0x10, 0x1A, 0x0A, 0x38, 0x11, + 0x1A, 0x02, 0x44, 0x02, 0xC3, 0x60, 0x38, 0x10, 0x1A, 0x0A, 0x44, 0x02, 0xC3, 0x50, 0x84, 0x20, + 0x38, 0x10, 0x18, 0x08, 0x44, 0x02, 0xC3, 0x40, 0x38, 0x40, 0x18, 0x08, 0x84, 0x00, 0xF0, 0x82, + 0x48, 0x00, 0x01, 0xB6, 0x44, 0x02, 0xC3, 0x30, 0x38, 0x10, 0x18, 0x00, 0xE2, 0x24, 0xE8, 0x03, + 0x38, 0x40, 0x18, 0x08, 0x22, 0x14, 0x80, 0x16, 0x94, 0x32, 0x38, 0x12, 0x9A, 0x09, 0x88, 0xA0, + 0x88, 0x0A, 0xAC, 0x69, 0x04, 0x14, 0x80, 0x08, 0xF3, 0x87, 0xF1, 0x82, 0xB0, 0x49, 0xF4, 0x86, + 0xF2, 0x85, 0xF0, 0x83, 0x49, 0xFF, 0xFE, 0x08, 0xF3, 0x07, 0x80, 0xA0, 0xF2, 0x05, 0x38, 0x01, + 0x9A, 0x02, 0xF4, 0x06, 0x4E, 0x03, 0x00, 0x95, 0x44, 0x02, 0xC7, 0xD0, 0x38, 0x10, 0x18, 0x00, + 0xE6, 0x3E, 0xE8, 0x04, 0x8C, 0x21, 0x38, 0x10, 0x18, 0x08, 0x38, 0x10, 0x18, 0x00, 0x3C, 0x0D, + 0xFF, 0xDB, 0x00, 0x30, 0x00, 0x1A, 0xE2, 0x23, 0x44, 0x32, 0xC3, 0xD8, 0xE8, 0x25, 0x2E, 0x07, + 0xEC, 0x2F, 0x5A, 0x00, 0x01, 0x04, 0x48, 0x00, 0x00, 0x7C, 0xE6, 0x8C, 0x4E, 0xF3, 0x00, 0x79, + 0xE6, 0x24, 0x4E, 0xF2, 0x00, 0x76, 0x44, 0x02, 0xC3, 0x40, 0x38, 0x10, 0x18, 0x00, 0xE2, 0x24, + 0xE8, 0x6F, 0x44, 0x22, 0xC3, 0x60, 0x44, 0x10, 0x7E, 0x90, 0x38, 0x11, 0x1A, 0x0A, 0x38, 0x11, + 0x9A, 0x0A, 0x44, 0x22, 0xC3, 0x9C, 0xF1, 0x09, 0x38, 0x40, 0x18, 0x08, 0x38, 0x11, 0x1A, 0x0A, + 0x38, 0x15, 0x1A, 0x0A, 0xD5, 0x5D, 0x3C, 0xFD, 0xFB, 0x4D, 0x02, 0xF7, 0x80, 0x00, 0x40, 0xF7, + 0x98, 0x09, 0x54, 0xF7, 0x80, 0x01, 0x5A, 0xF8, 0x01, 0x0A, 0x44, 0x02, 0xC5, 0x04, 0x38, 0xF0, + 0x1A, 0x0A, 0xFA, 0x09, 0x38, 0x01, 0x9A, 0x0A, 0xD5, 0x47, 0x84, 0x6D, 0x85, 0xEA, 0xFE, 0xE4, + 0x40, 0x31, 0xBC, 0x76, 0x44, 0xF2, 0xC3, 0x30, 0x38, 0xF7, 0x98, 0x00, 0xE0, 0x6F, 0xE9, 0x05, + 0xE6, 0x8E, 0xE9, 0x03, 0x5A, 0x18, 0x1E, 0x3D, 0x2E, 0x17, 0xEC, 0x2F, 0x5A, 0x18, 0x01, 0x04, + 0xE6, 0x8C, 0xE8, 0x16, 0x50, 0x34, 0x7F, 0xB4, 0x96, 0xD9, 0x5C, 0xF1, 0x83, 0xA9, 0xE8, 0x13, + 0x50, 0x21, 0x7F, 0xB4, 0x96, 0x91, 0x5C, 0xF1, 0x08, 0xD5, 0xE8, 0x0D, 0x5A, 0x18, 0x01, 0x06, + 0x2E, 0x17, 0xEC, 0x48, 0x5A, 0x10, 0x01, 0x0B, 0x02, 0x00, 0x00, 0x09, 0xD5, 0x09, 0x44, 0x00, + 0x7E, 0x90, 0xD5, 0x06, 0x44, 0x00, 0x07, 0xE9, 0xD5, 0x03, 0x44, 0x00, 0x02, 0x71, 0x44, 0x22, + 0xC3, 0xD8, 0x38, 0x11, 0x1A, 0x02, 0xE2, 0x01, 0xE8, 0x08, 0x92, 0x21, 0xE2, 0x20, 0x40, 0x00, + 0xBC, 0x1A, 0x38, 0x01, 0x1A, 0x0A, 0xD5, 0x0C, 0x44, 0x12, 0xC5, 0x04, 0x84, 0x61, 0x38, 0x30, + 0x9A, 0x0A, 0x38, 0x01, 0x1A, 0x0A, 0xF0, 0x09, 0x84, 0xA0, 0x38, 0x05, 0x1A, 0x0A, 0x44, 0x02, + 0xC5, 0x04, 0x38, 0x80, 0x1A, 0x02, 0x5A, 0x80, 0x02, 0x18, 0x44, 0x12, 0xC3, 0x9C, 0x94, 0x32, + 0x88, 0x01, 0xB0, 0x49, 0xF4, 0x86, 0xF5, 0x85, 0x49, 0xFF, 0xFD, 0x5E, 0x44, 0x12, 0xC3, 0x60, + 0xF5, 0x05, 0x38, 0x10, 0x9A, 0x02, 0xF4, 0x06, 0xE2, 0x20, 0xE8, 0x06, 0x44, 0x02, 0xC3, 0x50, + 0x84, 0x21, 0x38, 0x10, 0x18, 0x08, 0x44, 0x02, 0xC3, 0xD8, 0x38, 0x10, 0x1A, 0x02, 0xE2, 0x25, + 0xE8, 0x0B, 0xF0, 0x09, 0x44, 0x12, 0xC3, 0xD8, 0x38, 0x05, 0x1A, 0x0A, 0x2E, 0x07, 0xEC, 0x2F, + 0x5A, 0x08, 0x01, 0x39, 0xD5, 0x2A, 0xF2, 0x03, 0x80, 0x64, 0xB0, 0x09, 0xF5, 0x85, 0xF4, 0x83, + 0x49, 0xFF, 0xFE, 0x5D, 0xF4, 0x03, 0xF5, 0x05, 0xC8, 0xED, 0x44, 0x02, 0xC4, 0x14, 0x40, 0xF3, + 0x08, 0x08, 0x38, 0x00, 0x1A, 0x02, 0x80, 0x24, 0xB6, 0x1F, 0x44, 0x42, 0xC4, 0x8C, 0xF0, 0x02, + 0x80, 0x45, 0x88, 0x8F, 0x80, 0xAF, 0x44, 0xF2, 0xC4, 0x50, 0xF0, 0x81, 0xF3, 0x02, 0x80, 0x06, + 0x88, 0xAF, 0x49, 0xFF, 0xFD, 0xB0, 0xC8, 0xD6, 0x44, 0x02, 0xC3, 0x50, 0x38, 0x00, 0x18, 0x00, + 0x5A, 0x00, 0x01, 0xD1, 0x85, 0x01, 0xD5, 0x26, 0x02, 0x04, 0x80, 0x08, 0xE6, 0x0C, 0xE9, 0x0A, + 0x3C, 0x0D, 0xFB, 0x4D, 0xA4, 0x00, 0x92, 0x06, 0x96, 0x06, 0xC8, 0x04, 0x44, 0x00, 0x00, 0x64, + 0xD5, 0x05, 0x3C, 0x0D, 0xFF, 0xDB, 0x02, 0x00, 0x00, 0x0A, 0x38, 0x00, 0x9A, 0x0A, 0x5A, 0x80, + 0x02, 0x0C, 0x44, 0x02, 0xC5, 0x04, 0x84, 0x22, 0x38, 0x10, 0x1A, 0x0A, 0x44, 0x02, 0xC4, 0xC8, + 0x84, 0x21, 0x38, 0x10, 0x1A, 0x0A, 0x44, 0x02, 0xC3, 0x50, 0x84, 0x20, 0x38, 0x10, 0x18, 0x08, + 0x85, 0x00, 0x44, 0x92, 0xC4, 0xC8, 0x40, 0xA3, 0x08, 0x08, 0x38, 0x04, 0x9A, 0x02, 0x5A, 0x08, + 0x01, 0x36, 0x3C, 0x0D, 0xFF, 0xDB, 0x44, 0x32, 0xC2, 0xD4, 0x84, 0x40, 0x02, 0x10, 0x00, 0x0B, + 0x44, 0x02, 0xC3, 0x10, 0xF1, 0x86, 0x38, 0x20, 0x19, 0x09, 0x40, 0x21, 0xA8, 0x00, 0x80, 0x02, + 0xF3, 0x85, 0xF2, 0x83, 0x49, 0xFF, 0xFD, 0x46, 0xF1, 0x06, 0xF3, 0x05, 0xE0, 0x01, 0x40, 0x10, + 0x3C, 0x1B, 0x44, 0x02, 0xC2, 0xB4, 0xF2, 0x03, 0x38, 0x10, 0x19, 0x09, 0x38, 0x01, 0x9A, 0x01, + 0x38, 0x33, 0x9A, 0x01, 0x44, 0x12, 0xC2, 0x78, 0x8A, 0x03, 0x38, 0x00, 0x9A, 0x09, 0x40, 0x30, + 0xA8, 0x00, 0x40, 0x13, 0xA8, 0x00, 0xA4, 0x11, 0xA4, 0x49, 0x8A, 0x01, 0xAC, 0x19, 0x84, 0x02, + 0x38, 0x04, 0x9A, 0x0A, 0x4E, 0x82, 0x00, 0x11, 0xD5, 0x4A, 0x4E, 0x83, 0x00, 0x49, 0x5A, 0x08, + 0x03, 0x0C, 0x02, 0x0F, 0x80, 0x12, 0x89, 0x47, 0x38, 0x03, 0x9A, 0x09, 0x02, 0x0F, 0x80, 0x13, + 0x12, 0x05, 0x00, 0x01, 0xD5, 0x3C, 0x44, 0x12, 0xC2, 0xD4, 0x88, 0x2A, 0xB0, 0x09, 0x49, 0xFF, + 0xFC, 0xA3, 0x49, 0xFF, 0xFC, 0x90, 0x44, 0x12, 0xC3, 0x10, 0x96, 0x01, 0x38, 0x20, 0x99, 0x01, + 0xE2, 0x40, 0xE8, 0x03, 0x38, 0x00, 0x99, 0x09, 0x44, 0x02, 0xC2, 0xB4, 0x38, 0x20, 0x19, 0x01, + 0x38, 0x00, 0x99, 0x01, 0xE2, 0x02, 0xE9, 0x08, 0x44, 0x02, 0xC3, 0x10, 0x38, 0x20, 0x19, 0x09, + 0x84, 0x03, 0x38, 0x04, 0x9A, 0x0A, 0x44, 0x32, 0xC2, 0x78, 0x38, 0x00, 0x99, 0x01, 0x38, 0x11, + 0x9A, 0x11, 0x9A, 0x10, 0xFE, 0x44, 0x02, 0x4F, 0x80, 0x12, 0x40, 0x10, 0x88, 0x36, 0x9A, 0x61, + 0x38, 0x13, 0x9A, 0x09, 0x40, 0x13, 0xA8, 0x00, 0x89, 0x43, 0x22, 0x35, 0x00, 0x01, 0xFE, 0x1C, + 0x40, 0x00, 0x08, 0x16, 0x02, 0x2F, 0x80, 0x13, 0x9A, 0x10, 0xAC, 0x09, 0xF1, 0x04, 0x38, 0x03, + 0x9A, 0x01, 0xF2, 0x04, 0xAC, 0x08, 0x94, 0x72, 0x88, 0xE1, 0x44, 0x32, 0xC4, 0x8C, 0xA4, 0x39, + 0xAC, 0x11, 0x44, 0x22, 0xC4, 0x50, 0x38, 0x01, 0x1A, 0x01, 0x38, 0x01, 0x9A, 0x09, 0x80, 0x03, + 0x88, 0x01, 0x88, 0x22, 0xA4, 0x49, 0xAC, 0x41, 0x44, 0x02, 0xC4, 0x14, 0xF1, 0x02, 0x38, 0x10, + 0x1A, 0x0A, 0x44, 0x02, 0xC4, 0xC8, 0x38, 0x00, 0x1A, 0x02, 0x8E, 0x01, 0xE6, 0x03, 0xE9, 0x06, + 0xF1, 0x09, 0x44, 0x02, 0xC2, 0xD4, 0x38, 0x10, 0x1A, 0x0A, 0xFC, 0xC5, 0xFC, 0x40, 0x44, 0x30, + 0x00, 0xE0, 0x42, 0x01, 0x0C, 0x73, 0xB4, 0x80, 0x94, 0xD2, 0x5A, 0x48, 0x01, 0x1F, 0xA1, 0x06, + 0x3C, 0x0C, 0x02, 0x18, 0x9D, 0x59, 0x38, 0x40, 0x12, 0x02, 0x44, 0x02, 0xBD, 0x9C, 0x38, 0x40, + 0x0E, 0x0A, 0x38, 0x40, 0x16, 0x0A, 0x9D, 0x5A, 0x38, 0x40, 0x16, 0x0A, 0x9D, 0x5B, 0x38, 0x40, + 0x16, 0x0A, 0x44, 0x42, 0xBD, 0x8C, 0x84, 0x00, 0x38, 0x02, 0x08, 0x08, 0x44, 0x42, 0xBD, 0x7C, + 0x38, 0x02, 0x08, 0x08, 0x48, 0x00, 0x00, 0x96, 0x5A, 0x48, 0x02, 0x64, 0x9D, 0x1A, 0x95, 0x22, + 0x44, 0x52, 0xBD, 0x9C, 0x88, 0x85, 0x84, 0xC3, 0x0C, 0x72, 0x7F, 0xFF, 0x8E, 0xC1, 0x97, 0xB0, + 0xA9, 0xE2, 0xCE, 0xFB, 0xA1, 0x86, 0x3C, 0x4C, 0x02, 0x18, 0x04, 0x70, 0x00, 0x18, 0x38, 0x42, + 0x1A, 0x02, 0x44, 0x62, 0xBD, 0x7C, 0x38, 0x42, 0x8E, 0x0A, 0x5A, 0x78, 0x01, 0x0E, 0x04, 0x70, + 0x00, 0x28, 0x5A, 0x78, 0x01, 0x0A, 0x44, 0x72, 0xD0, 0x84, 0x38, 0x73, 0x88, 0x00, 0x5A, 0x78, + 0x01, 0x04, 0x38, 0x73, 0x08, 0x08, 0x38, 0x93, 0x08, 0x00, 0x5A, 0x98, 0x01, 0x6B, 0x9D, 0x9B, + 0x38, 0x72, 0x9A, 0x02, 0x44, 0x60, 0x00, 0x50, 0xFF, 0xF4, 0x44, 0x60, 0x00, 0x64, 0xFF, 0x34, + 0xE2, 0x87, 0x44, 0x62, 0xBD, 0x8C, 0xE8, 0x07, 0x38, 0xF3, 0x08, 0x00, 0xE9, 0x04, 0x38, 0x93, + 0x08, 0x08, 0xD5, 0x57, 0x38, 0x63, 0x08, 0x00, 0x44, 0x92, 0xBD, 0x8C, 0x5A, 0x68, 0x01, 0x52, + 0x85, 0x40, 0xE2, 0x87, 0x38, 0xA4, 0x88, 0x08, 0xE8, 0x34, 0x9D, 0xD9, 0x38, 0x72, 0x9E, 0x02, + 0x44, 0x50, 0x00, 0x55, 0xFF, 0x7C, 0xE2, 0x85, 0xE8, 0x2C, 0x22, 0x40, 0x00, 0x06, 0x22, 0xF0, + 0x80, 0x01, 0x22, 0x00, 0x00, 0x07, 0x22, 0x50, 0x80, 0x00, 0x8A, 0x0F, 0x8A, 0x85, 0xFE, 0x04, + 0x42, 0x02, 0x10, 0x73, 0x5E, 0xF0, 0x10, 0x81, 0x38, 0x64, 0x88, 0x08, 0xE8, 0x32, 0xD5, 0x27, + 0x5A, 0x48, 0x04, 0x30, 0x44, 0x42, 0xBD, 0x8C, 0x38, 0x62, 0x08, 0x00, 0x5A, 0x68, 0x01, 0x2A, + 0x22, 0x50, 0x00, 0x06, 0x22, 0x40, 0x00, 0x07, 0x22, 0x00, 0x80, 0x01, 0x22, 0x70, 0x80, 0x00, + 0x9A, 0x20, 0x9B, 0xEF, 0xFE, 0x04, 0x42, 0x03, 0x9C, 0x73, 0x5E, 0xF0, 0x10, 0x81, 0xE9, 0x05, + 0x84, 0x00, 0x3E, 0x00, 0x05, 0xF7, 0xD5, 0x15, 0x8E, 0xA1, 0x97, 0x69, 0x5C, 0xF2, 0x84, 0x3F, + 0xE8, 0xF8, 0x8E, 0x81, 0x97, 0x21, 0x5C, 0xF2, 0x09, 0x6B, 0xE8, 0xF3, 0x44, 0x02, 0xBD, 0x40, + 0x3E, 0x60, 0x05, 0xF7, 0x38, 0x40, 0x0A, 0x01, 0x88, 0x03, 0xAD, 0x08, 0xA4, 0x01, 0xAC, 0x09, + 0x44, 0x02, 0xBD, 0x40, 0xA5, 0x08, 0x88, 0x60, 0x38, 0x40, 0x0A, 0x09, 0xA4, 0x09, 0xAC, 0x19, + 0xFC, 0xC0, 0xFC, 0x40, 0x44, 0x30, 0x00, 0xE0, 0x42, 0x01, 0x0C, 0x73, 0xB4, 0x00, 0x44, 0x72, + 0xBD, 0x20, 0x44, 0x62, 0xBD, 0x00, 0x5A, 0x08, 0x02, 0x25, 0x44, 0x92, 0xBC, 0xC4, 0x22, 0x40, + 0x80, 0x00, 0x38, 0x54, 0x8A, 0x02, 0x38, 0x03, 0x89, 0x11, 0x5C, 0xF2, 0x80, 0x67, 0x22, 0x30, + 0x80, 0x01, 0x38, 0xA3, 0x09, 0x11, 0xE9, 0x07, 0x44, 0x02, 0xCE, 0xA4, 0x84, 0x61, 0x38, 0x30, + 0x08, 0x08, 0xD5, 0x16, 0x8A, 0x80, 0x4E, 0x44, 0x00, 0x03, 0xFF, 0x22, 0x40, 0x01, 0xA8, 0x01, + 0x4E, 0x04, 0x00, 0x03, 0xFE, 0x02, 0x88, 0x04, 0x88, 0x05, 0x38, 0x04, 0x8A, 0x0A, 0xD5, 0x08, + 0x5A, 0x08, 0x01, 0x07, 0x44, 0x02, 0xBC, 0xC4, 0x84, 0x60, 0x38, 0x30, 0x0A, 0x0A, 0xA4, 0x08, + 0x38, 0x03, 0x89, 0x09, 0xA4, 0x09, 0x38, 0x03, 0x09, 0x09, 0xFC, 0xC0, 0xFC, 0x40, 0x44, 0x40, + 0x00, 0xE0, 0x42, 0x01, 0x90, 0x73, 0x22, 0xF0, 0x80, 0x01, 0x22, 0x40, 0x00, 0x33, 0x44, 0x62, + 0xD0, 0x84, 0x8A, 0x8F, 0x8C, 0x9E, 0x5C, 0xF2, 0x00, 0x3D, 0xE8, 0x52, 0x22, 0x50, 0x00, 0x32, + 0x22, 0x40, 0x80, 0x00, 0x9B, 0x2C, 0x50, 0xF2, 0x00, 0x96, 0x5C, 0xF7, 0x81, 0x2D, 0xE8, 0x48, + 0x5E, 0xF2, 0x80, 0xAB, 0xE9, 0x09, 0x3C, 0x4D, 0xFF, 0xDA, 0x02, 0x42, 0x00, 0x09, 0x50, 0xF2, + 0x7F, 0x56, 0xE0, 0xAF, 0xE9, 0x3D, 0x84, 0x80, 0x38, 0x43, 0x0C, 0x08, 0xB5, 0x20, 0x22, 0xA0, + 0x80, 0x00, 0x44, 0x62, 0xBC, 0x4C, 0x44, 0x72, 0xBC, 0x88, 0x95, 0x1A, 0x5A, 0x98, 0x04, 0x20, + 0x00, 0x90, 0x00, 0x14, 0x54, 0xF4, 0x80, 0x04, 0xE8, 0x1A, 0x8A, 0xAA, 0x4E, 0x54, 0x00, 0x03, + 0xFF, 0x6A, 0xE4, 0xAA, 0xE9, 0x14, 0x58, 0x94, 0x80, 0x02, 0x10, 0x90, 0x00, 0x14, 0x38, 0x03, + 0x0E, 0x01, 0x38, 0x13, 0x8E, 0x01, 0x88, 0xC4, 0x94, 0x02, 0x88, 0x01, 0x88, 0x87, 0xAC, 0x10, + 0xA4, 0x31, 0xA4, 0x61, 0x94, 0x02, 0x88, 0x01, 0xAC, 0x11, 0xD5, 0x15, 0x38, 0x03, 0x8E, 0x01, + 0x22, 0x10, 0x80, 0x01, 0x40, 0x05, 0x00, 0x01, 0x38, 0x03, 0x0E, 0x09, 0x88, 0xC4, 0x88, 0x87, + 0x38, 0xA3, 0x8E, 0x09, 0xA4, 0x21, 0xAC, 0x61, 0x9A, 0x08, 0xAC, 0x31, 0xD5, 0x04, 0x84, 0x01, + 0x38, 0x03, 0x0C, 0x08, 0xFC, 0xC0, 0xFC, 0x43, 0x3C, 0x9D, 0xFF, 0xDB, 0xF0, 0x82, 0x84, 0x00, + 0x3E, 0x07, 0xEC, 0x5D, 0x02, 0x14, 0x80, 0x05, 0x3C, 0x0D, 0xFA, 0x73, 0xE2, 0x01, 0xE8, 0x04, + 0x8C, 0x01, 0x3C, 0x0F, 0xFA, 0x73, 0xF0, 0x02, 0x84, 0xC0, 0x50, 0x70, 0x00, 0x08, 0x44, 0x82, + 0xCE, 0xA4, 0x3C, 0xAD, 0xFF, 0xDA, 0x00, 0x35, 0x00, 0x09, 0xE2, 0xC3, 0x4E, 0xF2, 0x00, 0x85, + 0x04, 0x03, 0xFF, 0xFE, 0xC0, 0x7C, 0x5A, 0x00, 0x05, 0x7B, 0xA4, 0x3A, 0xB0, 0x45, 0x12, 0x0F, + 0x80, 0x0A, 0xA4, 0x3B, 0x80, 0x46, 0x12, 0x0F, 0x80, 0x0B, 0xF0, 0x02, 0x49, 0xFF, 0xFA, 0xC2, + 0xF0, 0x83, 0x00, 0x04, 0x80, 0x01, 0xB0, 0x45, 0x80, 0x41, 0xB6, 0x1F, 0x80, 0x66, 0xF0, 0x02, + 0x3C, 0x4D, 0xFA, 0x73, 0x3C, 0x5D, 0xFF, 0xC5, 0x49, 0xFF, 0xF7, 0x37, 0xB0, 0x45, 0xF0, 0x02, + 0x80, 0x41, 0x80, 0x66, 0x49, 0xFF, 0xF6, 0xD0, 0x00, 0x04, 0x80, 0x02, 0xC0, 0x07, 0xB0, 0x45, + 0xF0, 0x02, 0x80, 0x41, 0x80, 0x66, 0x49, 0xFF, 0xFB, 0xF8, 0x00, 0x04, 0x80, 0x03, 0xC0, 0x08, + 0xB0, 0x45, 0xF0, 0x02, 0x80, 0x41, 0x80, 0x66, 0xF4, 0x03, 0x49, 0xFF, 0xF9, 0x1F, 0x00, 0x04, + 0x80, 0x04, 0xC0, 0x08, 0xB0, 0x45, 0xF0, 0x02, 0x80, 0x41, 0x80, 0x66, 0xF4, 0x03, 0x49, 0xFF, + 0xF9, 0xE1, 0xF0, 0x02, 0xB0, 0x45, 0x80, 0x46, 0x49, 0xFF, 0xFE, 0x3A, 0x38, 0x04, 0x18, 0x00, + 0xC8, 0x06, 0xF0, 0x02, 0xB0, 0x45, 0x80, 0x46, 0x49, 0xFF, 0xFE, 0xF5, 0xB0, 0x45, 0x80, 0x41, + 0xF0, 0x02, 0x80, 0x66, 0x49, 0xFF, 0xF7, 0xF0, 0xB0, 0x45, 0xF0, 0x02, 0x80, 0x41, 0x80, 0x66, + 0x49, 0xFF, 0xFF, 0x26, 0x22, 0x0F, 0x80, 0x0A, 0x4E, 0x04, 0x00, 0x05, 0x84, 0x00, 0x12, 0x0F, + 0x80, 0x0A, 0x02, 0x05, 0x00, 0x09, 0x22, 0xFF, 0x80, 0x0A, 0xE0, 0x0F, 0xE8, 0x03, 0x12, 0x0F, + 0x80, 0x0A, 0x22, 0x0F, 0x80, 0x0B, 0x4E, 0x04, 0x00, 0x05, 0x84, 0x00, 0x12, 0x0F, 0x80, 0x0B, + 0x02, 0x05, 0x00, 0x0A, 0x22, 0xFF, 0x80, 0x0B, 0xE0, 0x0F, 0xE8, 0x03, 0x12, 0x0F, 0x80, 0x0B, + 0x02, 0x0F, 0x80, 0x0A, 0xAC, 0x38, 0x02, 0x0F, 0x80, 0x0B, 0xAC, 0x39, 0x8C, 0xC1, 0x50, 0x73, + 0x80, 0xE0, 0x48, 0xFF, 0xFF, 0x78, 0xF5, 0x02, 0x44, 0x40, 0x00, 0xE0, 0x80, 0xC5, 0x42, 0x61, + 0x90, 0x73, 0x3C, 0x27, 0xFF, 0x8A, 0x3C, 0x17, 0xFF, 0x8B, 0x3C, 0x0D, 0xFA, 0x73, 0x80, 0x66, + 0xD3, 0x0C, 0xB4, 0x85, 0x5A, 0x48, 0x05, 0x07, 0x22, 0x22, 0x80, 0x04, 0x22, 0x12, 0x80, 0x05, + 0x84, 0x00, 0x50, 0x52, 0x80, 0xE0, 0xD5, 0xF5, 0x3C, 0x2B, 0xFF, 0x8A, 0x3C, 0x1B, 0xFF, 0x8B, + 0x3C, 0x0F, 0xFA, 0x73, 0xFC, 0xC3, 0x3C, 0x0F, 0xFF, 0xDC, 0xDD, 0x9E, 0xFC, 0x20, 0x84, 0x80, + 0x8E, 0x41, 0x84, 0xC2, 0xE0, 0x44, 0xE9, 0x11, 0x98, 0xE2, 0x40, 0x31, 0x98, 0x76, 0x38, 0x70, + 0x0D, 0x01, 0x95, 0x59, 0xE0, 0x27, 0xE9, 0x07, 0x88, 0xA0, 0xA5, 0x29, 0xE0, 0x24, 0xE9, 0x07, + 0x9D, 0x19, 0xD5, 0xF1, 0x9E, 0x99, 0xD5, 0xEF, 0x84, 0x1F, 0xD5, 0x02, 0x80, 0x03, 0xFC, 0xA0, + 0xFC, 0x4F, 0xF1, 0x84, 0xB1, 0x86, 0x44, 0x11, 0x31, 0x1C, 0x80, 0xE6, 0x3A, 0x20, 0x94, 0x04, + 0x3A, 0x23, 0x94, 0x24, 0x3A, 0x20, 0x94, 0x04, 0x3A, 0x23, 0x94, 0x24, 0x80, 0xA7, 0x3A, 0x20, + 0x90, 0x04, 0x3A, 0x22, 0x90, 0x24, 0xA4, 0x48, 0x50, 0x9F, 0x80, 0x48, 0xAC, 0x68, 0x44, 0x11, + 0x31, 0x4C, 0x80, 0xE9, 0x3A, 0x20, 0x94, 0x04, 0x3A, 0x23, 0x94, 0x24, 0x3A, 0x20, 0x94, 0x04, + 0x3A, 0x23, 0x94, 0x24, 0x80, 0xA7, 0x3A, 0x20, 0x90, 0x04, 0x3A, 0x22, 0x90, 0x24, 0xA4, 0x48, + 0x50, 0xA0, 0x00, 0x02, 0xAC, 0x68, 0x2E, 0x17, 0xEC, 0x5D, 0x3C, 0x9D, 0xFF, 0xDC, 0xF1, 0x81, + 0x50, 0x14, 0x80, 0x0A, 0xF1, 0x82, 0x50, 0x14, 0x80, 0xDC, 0xF1, 0x83, 0x85, 0x00, 0xF6, 0x85, + 0xF0, 0x04, 0xE3, 0x00, 0x4E, 0xF2, 0x00, 0xF8, 0x22, 0x65, 0x00, 0x00, 0x84, 0x00, 0x5E, 0xF3, + 0x07, 0xD1, 0xB0, 0x92, 0x40, 0x14, 0x80, 0x00, 0xE9, 0x07, 0xF3, 0x01, 0x5A, 0x38, 0x01, 0x05, + 0x38, 0x70, 0x08, 0x01, 0xD5, 0x04, 0xF3, 0x05, 0x38, 0x70, 0x0C, 0x01, 0x8C, 0x02, 0xAD, 0xCD, + 0x5A, 0x08, 0x2E, 0xF2, 0x22, 0x75, 0x7F, 0xFF, 0x02, 0x04, 0x80, 0x05, 0xE0, 0x07, 0xE8, 0x68, + 0x03, 0xC4, 0x80, 0x04, 0x50, 0x0E, 0x00, 0x03, 0x94, 0x01, 0x88, 0x09, 0x50, 0x2E, 0x7F, 0xFF, + 0xA4, 0x01, 0xE0, 0xE0, 0xE9, 0x05, 0x02, 0x74, 0x80, 0x00, 0x8E, 0xE1, 0xD5, 0x5A, 0xF0, 0x02, + 0x80, 0x27, 0x49, 0xFF, 0xFF, 0x7D, 0x5A, 0x07, 0xFF, 0x55, 0x02, 0x54, 0x80, 0x03, 0x02, 0x24, + 0x80, 0x01, 0xE2, 0x05, 0x94, 0x41, 0xE8, 0x12, 0x40, 0x34, 0x84, 0x00, 0xA4, 0x5D, 0x8A, 0xE1, + 0xFF, 0xD4, 0x41, 0xC3, 0x97, 0x96, 0xA5, 0xDE, 0x8A, 0xE1, 0x41, 0xCE, 0x1F, 0x96, 0x42, 0x70, + 0x08, 0x24, 0x40, 0x73, 0x94, 0xF7, 0x88, 0xFC, 0xD5, 0x3C, 0x40, 0x3E, 0x14, 0x01, 0x8E, 0x61, + 0xE2, 0x03, 0xE9, 0x1A, 0x40, 0x34, 0x84, 0x00, 0x02, 0x44, 0x80, 0x02, 0xA4, 0x5D, 0x88, 0x85, + 0x52, 0xF2, 0x00, 0x01, 0x88, 0x0F, 0x8A, 0xE1, 0xFF, 0xD4, 0xFE, 0x14, 0x40, 0x00, 0x14, 0x17, + 0x02, 0x44, 0x80, 0x00, 0x40, 0x53, 0x94, 0xB6, 0xA5, 0xDE, 0x8A, 0x82, 0x8A, 0xE1, 0x88, 0x04, + 0x40, 0x72, 0x9C, 0xF6, 0xD5, 0x1B, 0x85, 0xFE, 0x02, 0x34, 0x80, 0x00, 0x42, 0x31, 0x3C, 0x73, + 0x83, 0x83, 0x88, 0x29, 0x02, 0x34, 0x80, 0x02, 0x8A, 0x05, 0x9F, 0x19, 0xA4, 0xCD, 0x42, 0x00, + 0x70, 0x24, 0x8A, 0xE3, 0x42, 0x7E, 0x1C, 0x24, 0x40, 0xF3, 0x91, 0xF6, 0xA5, 0xCE, 0x40, 0x00, + 0x10, 0x17, 0x8A, 0xE3, 0x88, 0x02, 0x40, 0x77, 0x9C, 0xF6, 0x88, 0xE0, 0xD5, 0x02, 0x84, 0xE0, + 0x12, 0x75, 0x7F, 0xFF, 0x02, 0x04, 0x80, 0x6E, 0xE0, 0x06, 0xE8, 0x67, 0x02, 0x74, 0x80, 0x6D, + 0x50, 0x03, 0x80, 0x6B, 0x94, 0x01, 0x88, 0x09, 0x9E, 0xB9, 0xA4, 0x02, 0xE0, 0xC0, 0xE9, 0x05, + 0x02, 0x64, 0x80, 0x69, 0x8E, 0xC1, 0xD5, 0x5A, 0xF0, 0x03, 0x80, 0x26, 0x49, 0xFF, 0xFF, 0x10, + 0x5A, 0x07, 0xFF, 0x55, 0x02, 0x54, 0x80, 0x6C, 0x02, 0x24, 0x80, 0x6A, 0xE2, 0x05, 0x94, 0x41, + 0xE8, 0x12, 0x88, 0x29, 0xFE, 0x14, 0x02, 0x70, 0x80, 0x6E, 0x8A, 0xC7, 0xFF, 0x94, 0x40, 0xF3, + 0x15, 0xF6, 0x02, 0x60, 0x80, 0x6F, 0x40, 0x50, 0x14, 0xB7, 0x8A, 0xC7, 0x40, 0x67, 0x98, 0xD6, + 0x88, 0xC5, 0xD5, 0x3C, 0x8A, 0xE5, 0x8E, 0xE1, 0xE2, 0x07, 0xE9, 0x1B, 0x88, 0x29, 0x02, 0x34, + 0x80, 0x6B, 0x02, 0x70, 0x80, 0x6E, 0x88, 0x65, 0x52, 0xF1, 0x80, 0x01, 0x88, 0x0F, 0x8A, 0xC7, + 0xFF, 0x94, 0xFE, 0x14, 0x40, 0x00, 0x14, 0x17, 0x02, 0x34, 0x80, 0x69, 0x40, 0x53, 0x14, 0xB6, + 0x02, 0x60, 0x80, 0x6F, 0x8A, 0x62, 0x8A, 0xC7, 0x88, 0x03, 0x40, 0x62, 0x98, 0xD6, 0xD5, 0x1B, + 0x84, 0xFE, 0x88, 0x29, 0x02, 0x34, 0x80, 0x69, 0x42, 0x31, 0x1C, 0x73, 0x80, 0x83, 0x02, 0x30, + 0x80, 0x6E, 0x02, 0x74, 0x80, 0x6B, 0x8A, 0x05, 0x8A, 0xC3, 0x8E, 0xE1, 0xFF, 0xA4, 0xFE, 0x24, + 0x40, 0x00, 0x1C, 0x17, 0x40, 0x73, 0x1C, 0xF6, 0x02, 0x60, 0x80, 0x6F, 0x88, 0x02, 0x8A, 0xC3, + 0x40, 0x63, 0x98, 0xD6, 0x88, 0xC0, 0xD5, 0x02, 0x84, 0xC0, 0x1A, 0x65, 0x00, 0x04, 0x8D, 0x01, + 0x48, 0xFF, 0xFF, 0x08, 0xFC, 0xCF, 0x3C, 0x0F, 0xFF, 0xDD, 0xDD, 0x9E, 0xFC, 0x41, 0x81, 0x21, + 0x84, 0x20, 0x80, 0xE2, 0xAE, 0x58, 0x80, 0xC3, 0xF4, 0x81, 0x3C, 0x1D, 0xFF, 0xDD, 0x84, 0xA0, + 0x44, 0x22, 0xC8, 0x30, 0xE2, 0xA9, 0xE8, 0x10, 0xA0, 0xC1, 0x38, 0x31, 0x95, 0x01, 0x4C, 0x32, + 0xC0, 0x15, 0xA7, 0x30, 0x38, 0x51, 0x10, 0x08, 0x8C, 0x81, 0x97, 0x20, 0xAF, 0x30, 0x00, 0x30, + 0x80, 0x19, 0xE2, 0x83, 0xE9, 0x0A, 0x80, 0x47, 0xF1, 0x01, 0x80, 0x69, 0x49, 0x00, 0x79, 0x7C, + 0x84, 0x00, 0x44, 0x22, 0xC8, 0x30, 0xD5, 0x03, 0x8C, 0xA1, 0xD5, 0xE5, 0xA6, 0x70, 0xE2, 0x01, + 0xE8, 0x08, 0x94, 0x43, 0x38, 0x31, 0x00, 0x00, 0x88, 0x27, 0x8C, 0x01, 0xA8, 0xC9, 0xD5, 0xF7, + 0xFC, 0xC1, 0xFC, 0x20, 0x2E, 0x07, 0xEC, 0x49, 0xFD, 0x32, 0x5A, 0x08, 0x01, 0x05, 0x3C, 0x0C, + 0x01, 0xA7, 0xD5, 0x0E, 0x9E, 0x0C, 0xE6, 0x02, 0xE9, 0x04, 0x8E, 0x27, 0xE6, 0x22, 0xE8, 0x04, + 0x3C, 0x0C, 0x01, 0xA3, 0xD5, 0x05, 0x2E, 0x07, 0xEC, 0x66, 0x49, 0x00, 0x08, 0x56, 0xB6, 0x07, + 0xB4, 0x07, 0x3C, 0x1C, 0x01, 0xA1, 0x4C, 0x00, 0x80, 0x0A, 0x3C, 0x1C, 0x01, 0xA2, 0x4C, 0x00, + 0x80, 0x06, 0x3C, 0x1C, 0x01, 0xAE, 0x4C, 0x00, 0xC0, 0x04, 0x84, 0x21, 0xD5, 0x02, 0x84, 0x20, + 0x44, 0x5E, 0x00, 0x00, 0x88, 0xA0, 0x3C, 0x0F, 0xFB, 0x55, 0x92, 0xA2, 0x44, 0x02, 0x7B, 0x90, + 0x97, 0x69, 0x3E, 0x17, 0xEC, 0x25, 0xAD, 0x40, 0x44, 0x03, 0xF4, 0x00, 0x44, 0x10, 0x1E, 0xE4, + 0xAC, 0x40, 0x44, 0x03, 0xF4, 0x02, 0x97, 0xB0, 0xAF, 0x80, 0xFC, 0xA0, 0x84, 0x00, 0x3C, 0x0F, + 0xFB, 0x87, 0x44, 0x03, 0xF4, 0x03, 0x84, 0x21, 0xAE, 0x40, 0xDD, 0x9E, 0x44, 0x03, 0xF4, 0x03, + 0xA6, 0x00, 0x5C, 0x00, 0x00, 0x01, 0xDD, 0x9E, 0x44, 0x03, 0xF4, 0x0C, 0xA6, 0x00, 0x96, 0x00, + 0xC8, 0x07, 0x44, 0x13, 0xF3, 0xCF, 0xA6, 0x48, 0x40, 0x00, 0x04, 0x06, 0xDD, 0x9E, 0x84, 0x01, + 0xDD, 0x9E, 0x44, 0x13, 0xF4, 0x03, 0x84, 0x00, 0x3C, 0x0F, 0xFB, 0x87, 0xAE, 0x08, 0xDD, 0x9E, + 0xFC, 0x00, 0x5A, 0x08, 0x01, 0x13, 0x49, 0x00, 0x19, 0x4F, 0x5A, 0x08, 0x02, 0x07, 0x44, 0x03, + 0xF0, 0x10, 0x44, 0x1F, 0xFF, 0xAA, 0xAE, 0x40, 0x49, 0xFF, 0xFF, 0xD2, 0x84, 0x00, 0x3C, 0x0B, + 0xF6, 0x56, 0x3E, 0x07, 0xEC, 0x57, 0xD5, 0x03, 0x49, 0xFF, 0xFF, 0xE5, 0xFC, 0x80, 0x44, 0x03, + 0xF0, 0x1D, 0xA6, 0x80, 0xA6, 0x41, 0xA6, 0xC0, 0x40, 0x10, 0xA0, 0x08, 0xFE, 0x57, 0x58, 0x10, + 0x84, 0x00, 0x96, 0x88, 0xAE, 0x80, 0x92, 0x28, 0xA6, 0x81, 0xAE, 0x41, 0x44, 0x13, 0xF4, 0x21, + 0x44, 0x20, 0x00, 0x55, 0xAE, 0x88, 0x44, 0x20, 0x00, 0x00, 0x44, 0x30, 0x00, 0x0A, 0x50, 0x21, + 0x00, 0x01, 0x4C, 0x21, 0xFF, 0xFE, 0x84, 0x40, 0xAE, 0x88, 0x44, 0x20, 0x00, 0x00, 0x44, 0x30, + 0x00, 0x0A, 0x50, 0x21, 0x00, 0x01, 0x4C, 0x21, 0xFF, 0xFE, 0xA6, 0x40, 0x96, 0x48, 0xAE, 0x40, + 0xDD, 0x9E, 0x84, 0x00, 0x44, 0x42, 0xD3, 0xB4, 0x44, 0x52, 0xD1, 0x1C, 0x44, 0x12, 0xD0, 0x90, + 0x44, 0x32, 0xD4, 0x90, 0x38, 0x22, 0x80, 0x00, 0x38, 0x22, 0x00, 0x08, 0x38, 0x21, 0x80, 0x00, + 0x38, 0x20, 0x80, 0x08, 0x8C, 0x01, 0x5A, 0x08, 0x20, 0xF7, 0xDD, 0x9E, 0xA6, 0x40, 0xA7, 0x05, + 0x3E, 0x10, 0x0C, 0xF4, 0xA6, 0x41, 0xA6, 0xC7, 0x3E, 0x10, 0x0C, 0xF5, 0xA6, 0x42, 0x40, 0x42, + 0x20, 0x08, 0x3E, 0x10, 0x0C, 0xF6, 0xA6, 0x43, 0x40, 0x31, 0xA0, 0x08, 0x3E, 0x10, 0x0C, 0xF7, + 0xA6, 0x44, 0x00, 0x20, 0x00, 0x08, 0x88, 0x81, 0xA6, 0x46, 0x97, 0x23, 0x88, 0x61, 0x00, 0x10, + 0x00, 0x09, 0x96, 0xDB, 0x40, 0x10, 0xA0, 0x08, 0x88, 0x22, 0x3C, 0x18, 0x06, 0x7E, 0x00, 0x10, + 0x00, 0x0B, 0x00, 0x20, 0x00, 0x0A, 0x40, 0x10, 0xA0, 0x08, 0x88, 0x22, 0x3C, 0x18, 0x06, 0x7F, + 0x00, 0x10, 0x00, 0x0C, 0x3C, 0x48, 0x06, 0x7C, 0x3E, 0x10, 0x0D, 0x00, 0x00, 0x10, 0x00, 0x0D, + 0x3C, 0x38, 0x06, 0x7D, 0x3E, 0x10, 0x0D, 0x01, 0x00, 0x10, 0x00, 0x0E, 0x96, 0x46, 0x3E, 0x10, + 0x0D, 0x02, 0x00, 0x10, 0x00, 0x0E, 0x92, 0x21, 0x96, 0x46, 0x3E, 0x10, 0x0D, 0x03, 0x00, 0x10, + 0x00, 0x0E, 0x92, 0x22, 0x96, 0x46, 0x3E, 0x10, 0x0D, 0x04, 0x00, 0x10, 0x00, 0x0E, 0x92, 0x23, + 0x96, 0x46, 0x3E, 0x10, 0x0D, 0x05, 0x00, 0x10, 0x00, 0x0F, 0x96, 0x5F, 0x3E, 0x10, 0x0D, 0x06, + 0x00, 0x10, 0x00, 0x0F, 0x92, 0x24, 0x3E, 0x10, 0x0D, 0x07, 0x00, 0x10, 0x00, 0x11, 0x00, 0x20, + 0x00, 0x10, 0x40, 0x10, 0xA0, 0x08, 0x88, 0x22, 0x3C, 0x18, 0x06, 0x84, 0x00, 0x10, 0x00, 0x13, + 0x00, 0x20, 0x00, 0x12, 0x40, 0x10, 0xA0, 0x08, 0x88, 0x22, 0x3C, 0x18, 0x06, 0x85, 0x00, 0x20, + 0x00, 0x15, 0x00, 0x10, 0x00, 0x14, 0x96, 0x8F, 0x40, 0x21, 0x20, 0x08, 0x88, 0x41, 0x96, 0x93, + 0x3C, 0x28, 0x06, 0x86, 0x00, 0x10, 0x00, 0x15, 0x92, 0x22, 0x3E, 0x10, 0x0D, 0x0E, 0x00, 0x10, + 0x00, 0x17, 0x00, 0x50, 0x00, 0x16, 0x96, 0x4F, 0x40, 0x10, 0xA0, 0x08, 0x88, 0x25, 0x96, 0x4B, + 0x3C, 0x18, 0x06, 0x88, 0x00, 0x50, 0x00, 0x17, 0x92, 0xA2, 0x3E, 0x50, 0x0D, 0x12, 0x00, 0x00, + 0x00, 0x1E, 0x96, 0x2F, 0x3E, 0x00, 0x0D, 0x13, 0x40, 0x02, 0x2C, 0x0A, 0x96, 0x06, 0xC0, 0x06, + 0x44, 0x0F, 0xF0, 0x00, 0xFF, 0x07, 0x3C, 0x48, 0x06, 0x7C, 0x40, 0x01, 0xAC, 0x0A, 0x96, 0x06, + 0xC0, 0x06, 0x44, 0x0F, 0xF0, 0x00, 0xFE, 0xC7, 0x3C, 0x38, 0x06, 0x7D, 0x40, 0x01, 0x24, 0x0A, + 0xC0, 0x06, 0x44, 0x0F, 0xFC, 0x00, 0xFE, 0x87, 0x3C, 0x28, 0x06, 0x86, 0x40, 0x00, 0xA4, 0x0A, + 0xC0, 0x06, 0x44, 0x0F, 0xFC, 0x00, 0xFE, 0x47, 0x3C, 0x18, 0x06, 0x88, 0xDD, 0x9E, 0xA4, 0xC0, + 0x44, 0x22, 0xCF, 0x3C, 0x44, 0x12, 0x00, 0x00, 0x94, 0xDA, 0x88, 0x61, 0xB6, 0x62, 0xA4, 0xC2, + 0x50, 0x41, 0x00, 0x20, 0x94, 0xDA, 0x88, 0x61, 0xA8, 0xD2, 0xA4, 0xC4, 0x94, 0xDA, 0x88, 0x61, + 0xA8, 0xD1, 0xA4, 0xC6, 0x94, 0xDA, 0x88, 0x61, 0xB6, 0x64, 0x02, 0x30, 0x00, 0x08, 0x94, 0xDA, + 0x88, 0x61, 0xA8, 0xE1, 0xA4, 0xC4, 0x94, 0xDA, 0x88, 0x61, 0xA8, 0xE5, 0x02, 0x00, 0x00, 0x08, + 0x94, 0x02, 0x88, 0x20, 0xA8, 0x66, 0xDD, 0x9E, 0x3C, 0x1C, 0x01, 0xA1, 0x44, 0x0E, 0x00, 0x00, + 0x88, 0x01, 0x92, 0x02, 0x44, 0x12, 0x7B, 0x90, 0x96, 0x01, 0xAC, 0x08, 0xDD, 0x9E, 0xA4, 0x00, + 0x44, 0x12, 0x00, 0x00, 0x94, 0x02, 0x88, 0x01, 0x3C, 0x0E, 0x01, 0xA7, 0xDD, 0x9E, 0xFC, 0x00, + 0x44, 0x23, 0xF6, 0xA8, 0x44, 0x13, 0xF6, 0xA9, 0x5A, 0x08, 0x01, 0x05, 0xAE, 0x10, 0x84, 0x07, + 0xD5, 0x03, 0x84, 0x00, 0xAE, 0x10, 0xAE, 0x08, 0x84, 0x00, 0x80, 0x20, 0x80, 0x40, 0xFA, 0x6F, + 0x49, 0x00, 0x16, 0xD7, 0xFC, 0x80, 0xB4, 0x40, 0x84, 0xA0, 0x8C, 0x44, 0x9C, 0x2E, 0xA2, 0xD1, + 0x96, 0x00, 0x5A, 0x58, 0x20, 0x06, 0x80, 0xA0, 0x5A, 0x08, 0x24, 0xFA, 0xDD, 0x9E, 0x54, 0x41, + 0x80, 0x1F, 0x38, 0x40, 0x94, 0x08, 0x8C, 0xA1, 0x97, 0x68, 0x92, 0x65, 0xD8, 0xF3, 0xD5, 0xF4, + 0xFC, 0x20, 0xB4, 0x80, 0x84, 0x60, 0x8C, 0x84, 0x84, 0xE6, 0xB4, 0x04, 0x5A, 0x38, 0x05, 0x06, + 0x92, 0x0A, 0x40, 0x00, 0x28, 0x08, 0xD5, 0x04, 0x92, 0x1E, 0x40, 0x00, 0x78, 0x08, 0x42, 0x21, + 0x9C, 0x24, 0x96, 0x90, 0x84, 0xA0, 0x5A, 0x20, 0x20, 0x0C, 0x38, 0x60, 0x88, 0x00, 0x8C, 0x41, + 0x40, 0x63, 0x14, 0x0C, 0x8C, 0xA5, 0x88, 0x06, 0x96, 0x90, 0x5A, 0x58, 0x1E, 0xF6, 0x8C, 0x61, + 0x96, 0xD8, 0xAA, 0x21, 0x5A, 0x38, 0x06, 0xE3, 0xFC, 0xA0, 0xFC, 0x20, 0xB4, 0x60, 0x84, 0x00, + 0x8C, 0x7C, 0x95, 0x83, 0xA3, 0x19, 0x97, 0xB0, 0x84, 0x40, 0x99, 0x56, 0x97, 0x68, 0x8C, 0x41, + 0x54, 0x72, 0x00, 0x0F, 0x96, 0x90, 0x38, 0x70, 0x94, 0x08, 0x92, 0x84, 0x5A, 0x28, 0x08, 0xF7, + 0x8C, 0x01, 0x96, 0x00, 0x5A, 0x08, 0x04, 0xEF, 0xFC, 0xA0, 0xFC, 0x20, 0xB4, 0x60, 0x84, 0x00, + 0x50, 0x31, 0x80, 0x2C, 0x95, 0x83, 0xA3, 0x19, 0x97, 0xB0, 0x84, 0x40, 0x99, 0x56, 0x97, 0x68, + 0x8C, 0x41, 0x54, 0x72, 0x00, 0x0F, 0x96, 0x90, 0x38, 0x70, 0x94, 0x08, 0x92, 0x84, 0x5A, 0x28, + 0x08, 0xF7, 0x8C, 0x01, 0x96, 0x00, 0x5A, 0x08, 0x04, 0xEF, 0xFC, 0xA0, 0xFC, 0x00, 0x3C, 0x0C, + 0x01, 0xA1, 0x84, 0x23, 0x3C, 0x0F, 0xFB, 0x55, 0x44, 0x03, 0xF4, 0x0B, 0x84, 0x40, 0xAE, 0x40, + 0x44, 0x03, 0xF4, 0x04, 0x84, 0x26, 0xAE, 0x40, 0x44, 0x13, 0xF4, 0x07, 0x84, 0x01, 0xAE, 0x08, + 0x44, 0x13, 0xF4, 0x08, 0xAE, 0x08, 0x44, 0x13, 0xF0, 0x1E, 0xAE, 0x88, 0x44, 0x13, 0xF4, 0x20, + 0xAE, 0x08, 0x2E, 0x07, 0xC7, 0x54, 0x5A, 0x08, 0x01, 0x06, 0x3C, 0x0C, 0x01, 0xA1, 0x49, 0x00, + 0x04, 0xF4, 0x44, 0x02, 0xCF, 0x3C, 0x44, 0x12, 0xD1, 0x1C, 0x49, 0xFF, 0xFF, 0x6E, 0x44, 0x02, + 0xCF, 0x3C, 0x44, 0x12, 0xD5, 0x8C, 0x49, 0xFF, 0xFF, 0xA2, 0x44, 0x02, 0xCF, 0x40, 0x44, 0x12, + 0xD3, 0xF8, 0x49, 0xFF, 0xFF, 0x9C, 0x44, 0x12, 0xD4, 0x90, 0x44, 0x02, 0xCF, 0x3C, 0x49, 0xFF, + 0xFF, 0xAE, 0x49, 0x00, 0x06, 0x6C, 0x44, 0x02, 0x8F, 0x70, 0x49, 0x00, 0x06, 0xDC, 0xFC, 0x80, + 0xFC, 0x00, 0xB4, 0x80, 0x84, 0x40, 0x8C, 0x9C, 0x84, 0x00, 0x80, 0xA0, 0x98, 0xD0, 0x96, 0xD8, + 0x95, 0x82, 0x38, 0x30, 0x8C, 0x00, 0x8C, 0x01, 0x96, 0xDF, 0x40, 0x31, 0x98, 0x0C, 0x88, 0xA3, + 0x5A, 0x08, 0x08, 0xF6, 0x8C, 0x48, 0x96, 0x90, 0xAB, 0x61, 0x5A, 0x28, 0x20, 0xEF, 0xFC, 0x80, + 0xFC, 0x04, 0xA6, 0x49, 0xB4, 0x40, 0x5A, 0x10, 0x03, 0x04, 0x5A, 0x18, 0x0C, 0x11, 0x2E, 0x17, + 0xEC, 0x66, 0x54, 0x20, 0x80, 0xFB, 0xCA, 0x04, 0x44, 0x12, 0xD5, 0x8C, 0xD5, 0x05, 0x5A, 0x18, + 0x03, 0x25, 0x44, 0x12, 0xD3, 0xF8, 0x49, 0xFF, 0xFF, 0xD5, 0xD5, 0x1F, 0x5A, 0x18, 0x04, 0x08, + 0xA0, 0x57, 0x84, 0x10, 0xFE, 0x0E, 0x58, 0x00, 0x00, 0x03, 0xD5, 0x16, 0x50, 0x30, 0xFF, 0xF7, + 0xE6, 0x62, 0xE8, 0x0A, 0x84, 0x20, 0x84, 0x46, 0x38, 0x20, 0xFC, 0x08, 0x8C, 0x21, 0x5A, 0x18, + 0x20, 0xFD, 0x80, 0x3F, 0xD5, 0xE9, 0x8E, 0x27, 0xE6, 0x22, 0xE8, 0x07, 0xA0, 0x57, 0x84, 0x10, + 0xFE, 0x0E, 0x58, 0x00, 0x00, 0x04, 0xA8, 0x17, 0xFC, 0x84, 0xFC, 0x00, 0xA6, 0x81, 0x80, 0xC0, + 0x5A, 0x20, 0x03, 0x14, 0x5A, 0x20, 0x06, 0x12, 0x9E, 0x14, 0xE6, 0x02, 0xE9, 0x0E, 0x9E, 0x17, + 0xE6, 0x02, 0xE9, 0x0D, 0x50, 0x01, 0x7F, 0xF7, 0xE6, 0x02, 0xE9, 0x09, 0x5A, 0x28, 0x0C, 0x1C, + 0x49, 0x00, 0x16, 0xF2, 0x5A, 0x08, 0x02, 0x04, 0x84, 0x00, 0xD5, 0x02, 0x84, 0x01, 0x3E, 0x07, + 0xEC, 0x0B, 0x2E, 0x07, 0xEC, 0x0B, 0xA6, 0x71, 0x2E, 0x27, 0xEC, 0x1F, 0x84, 0x81, 0x2E, 0x37, + 0xEC, 0x3C, 0x44, 0x52, 0xB6, 0x24, 0x49, 0xFF, 0xFD, 0x2E, 0x44, 0x02, 0xB6, 0x24, 0x80, 0x26, + 0x49, 0xFF, 0xFF, 0xA0, 0xFC, 0x80, 0xFC, 0x00, 0xB4, 0x80, 0x84, 0x40, 0x50, 0x42, 0x00, 0x2C, + 0x84, 0x00, 0x80, 0xA0, 0x98, 0xD0, 0x96, 0xD8, 0x95, 0x82, 0x38, 0x30, 0x8C, 0x00, 0x8C, 0x01, + 0x96, 0xDF, 0x40, 0x31, 0x98, 0x0C, 0x88, 0xA3, 0x5A, 0x08, 0x08, 0xF6, 0x8C, 0x48, 0x96, 0x90, + 0xAB, 0x61, 0x5A, 0x28, 0x20, 0xEF, 0xFC, 0x80, 0xFC, 0x01, 0x44, 0x12, 0xD3, 0xB4, 0xF0, 0x81, + 0x49, 0xFF, 0xFE, 0xD0, 0xF0, 0x01, 0x44, 0x12, 0xD0, 0x90, 0x49, 0xFF, 0xFF, 0xDE, 0xFC, 0x81, + 0xFC, 0x44, 0x2E, 0x20, 0x0D, 0x06, 0x44, 0x72, 0xD5, 0x8C, 0x81, 0x20, 0x38, 0x63, 0x88, 0x00, + 0x44, 0x42, 0xD3, 0xB4, 0x8E, 0xC2, 0x5C, 0x63, 0x00, 0x01, 0x44, 0x02, 0xD0, 0x90, 0x2E, 0x30, + 0x0C, 0xF5, 0x5A, 0x18, 0x06, 0x44, 0x84, 0x2A, 0x38, 0x12, 0x08, 0x08, 0xE6, 0x62, 0x84, 0x22, + 0x38, 0x10, 0x08, 0x08, 0xE9, 0x73, 0x49, 0x00, 0x16, 0x97, 0x5A, 0x08, 0x02, 0x70, 0x84, 0x00, + 0x5A, 0x98, 0x03, 0x18, 0x2E, 0x10, 0x0C, 0xF5, 0x84, 0x00, 0x44, 0x32, 0xD3, 0xF8, 0x38, 0x21, + 0x80, 0x00, 0x38, 0x2F, 0x80, 0x08, 0x8C, 0x01, 0x5A, 0x08, 0x20, 0xFB, 0x2E, 0x00, 0x0D, 0x06, + 0xC0, 0x0F, 0x88, 0x1F, 0x8E, 0x22, 0x84, 0x40, 0xE2, 0x41, 0x10, 0xF0, 0x7F, 0xFF, 0xD5, 0x08, + 0x38, 0x13, 0x80, 0x00, 0x38, 0x1F, 0x80, 0x08, 0x8C, 0x01, 0x5A, 0x08, 0x20, 0xFB, 0x5A, 0x68, + 0x01, 0x06, 0x2E, 0x00, 0x0D, 0x06, 0x84, 0x29, 0xD5, 0x09, 0x3C, 0x00, 0x06, 0x84, 0x5C, 0xF0, + 0x03, 0x00, 0xE9, 0x06, 0x2E, 0x00, 0x0D, 0x06, 0x84, 0x2A, 0x38, 0x1F, 0x80, 0x08, 0x44, 0x02, + 0xB6, 0x24, 0x80, 0x3F, 0x49, 0xFF, 0xFF, 0x0E, 0xD5, 0x39, 0x84, 0x20, 0x38, 0x12, 0x08, 0x08, + 0x50, 0x14, 0xFF, 0xFD, 0xE6, 0x22, 0x84, 0x23, 0xE9, 0x02, 0x84, 0x21, 0xE6, 0x62, 0x38, 0x10, + 0x08, 0x08, 0xE9, 0x2C, 0x49, 0x00, 0x16, 0x50, 0x5A, 0x08, 0x02, 0x29, 0x84, 0x00, 0x5A, 0x98, + 0x03, 0x19, 0x2E, 0x00, 0x0C, 0xF5, 0x84, 0x28, 0x5A, 0x08, 0x02, 0x03, 0x84, 0x27, 0x84, 0x00, + 0x44, 0x32, 0xD3, 0xF8, 0x38, 0x21, 0x80, 0x00, 0x38, 0x2F, 0x80, 0x08, 0x8C, 0x01, 0x5A, 0x08, + 0x20, 0xFB, 0x2E, 0x00, 0x0D, 0x06, 0xC0, 0x0C, 0x88, 0x1F, 0x10, 0x10, 0x7F, 0xFF, 0xD5, 0x08, + 0x38, 0x13, 0x80, 0x00, 0x38, 0x1F, 0x80, 0x08, 0x8C, 0x01, 0x5A, 0x08, 0x20, 0xFB, 0x5A, 0x68, + 0x01, 0xC8, 0x2E, 0x00, 0x0D, 0x06, 0x84, 0x22, 0xD5, 0xC1, 0x44, 0x02, 0xB6, 0x24, 0x49, 0xFF, + 0xFF, 0x65, 0xFC, 0xC4, 0x3C, 0x4C, 0x01, 0xAE, 0x44, 0x22, 0x00, 0xFC, 0x54, 0x00, 0x0F, 0xFF, + 0x04, 0x12, 0x00, 0x12, 0x40, 0x00, 0x48, 0x08, 0x92, 0x30, 0x54, 0x10, 0xFF, 0xFF, 0x94, 0x4A, + 0x88, 0x22, 0x46, 0x2C, 0x00, 0x3F, 0x04, 0x30, 0x80, 0x08, 0x50, 0x21, 0x0F, 0xFF, 0xFE, 0xD6, + 0xFE, 0xC7, 0x14, 0x30, 0x80, 0x08, 0x04, 0x12, 0x00, 0x12, 0x44, 0x32, 0x01, 0x50, 0x92, 0x30, + 0x54, 0x10, 0xFF, 0xFF, 0x94, 0x4A, 0x88, 0x23, 0x04, 0x30, 0x80, 0x08, 0xFE, 0x9E, 0xFE, 0x87, + 0x14, 0x20, 0x80, 0x08, 0xDD, 0x9E, 0xFC, 0x00, 0x44, 0x12, 0x90, 0x74, 0x94, 0x01, 0x99, 0x81, + 0x22, 0x03, 0x00, 0x00, 0x49, 0xFF, 0xFF, 0xD0, 0xA4, 0x30, 0x3C, 0x0B, 0xF6, 0x5E, 0xFC, 0x80, + 0xFC, 0x41, 0x80, 0xC0, 0x81, 0x22, 0x3C, 0x0D, 0x9A, 0x31, 0xF0, 0x81, 0xCE, 0x04, 0xAF, 0x90, + 0x84, 0x41, 0xD5, 0x18, 0x80, 0xE1, 0x5A, 0x68, 0x04, 0x06, 0x80, 0x01, 0x49, 0xFF, 0xFF, 0xE5, + 0xD5, 0x0E, 0x3C, 0x0D, 0xFB, 0x4A, 0xA6, 0x01, 0x5A, 0x08, 0x03, 0x07, 0x50, 0x00, 0x80, 0x44, + 0x96, 0x00, 0x49, 0x00, 0x41, 0x5F, 0xB0, 0x01, 0x38, 0x60, 0x1C, 0x00, 0x10, 0x74, 0x80, 0x00, + 0x84, 0x43, 0x84, 0x00, 0x44, 0x32, 0xD0, 0x90, 0x38, 0x61, 0x80, 0x08, 0x8C, 0x01, 0x44, 0x12, + 0xD0, 0x90, 0x5A, 0x08, 0x20, 0xFB, 0x2E, 0x00, 0x0D, 0x06, 0x38, 0x20, 0x80, 0x08, 0x44, 0x02, + 0xB6, 0x24, 0x49, 0xFF, 0xFE, 0xE2, 0xFC, 0xC1, 0xFC, 0x01, 0x80, 0xC0, 0x3E, 0x07, 0xEC, 0x66, + 0x80, 0x01, 0xB6, 0x5F, 0xF3, 0x81, 0x49, 0xFF, 0xFE, 0xAA, 0x80, 0x06, 0xB4, 0x3F, 0xF2, 0x01, + 0x49, 0xFF, 0xFF, 0xC0, 0xFC, 0x81, 0xFC, 0x40, 0x84, 0x00, 0x3E, 0x07, 0xEC, 0x0B, 0x3C, 0x0D, + 0xFB, 0x4A, 0x84, 0x23, 0x2E, 0x67, 0xEC, 0x55, 0xA7, 0xC1, 0xAE, 0x41, 0x49, 0xFF, 0xFC, 0x8B, + 0x84, 0x00, 0x80, 0x40, 0x44, 0x32, 0xB5, 0x0D, 0x3C, 0x1D, 0xFB, 0x4A, 0x2E, 0x97, 0xEC, 0x66, + 0x49, 0xFF, 0xFF, 0xDC, 0x44, 0x02, 0xB6, 0x24, 0x44, 0x12, 0xD1, 0x1C, 0x49, 0xFF, 0xFD, 0xA2, + 0x84, 0x03, 0x3C, 0x1D, 0xFB, 0x4A, 0x80, 0x46, 0x44, 0x32, 0xB5, 0x0D, 0x49, 0xFF, 0xFF, 0xCE, + 0xE7, 0x22, 0x84, 0x03, 0xE8, 0x02, 0x84, 0x00, 0x3E, 0x07, 0xEC, 0x66, 0x44, 0x12, 0xD1, 0x1C, + 0x44, 0x02, 0xB6, 0x24, 0x49, 0xFF, 0xFD, 0x8E, 0x2E, 0x07, 0xEC, 0x66, 0x3C, 0x1D, 0xFB, 0x4A, + 0x80, 0x46, 0x44, 0x32, 0xB5, 0x0D, 0x49, 0xFF, 0xFF, 0xB9, 0x2E, 0x07, 0xEC, 0x66, 0x3E, 0x07, + 0xEC, 0x4F, 0x3C, 0x0D, 0xFB, 0x4A, 0xAF, 0xC1, 0xFC, 0xC0, 0xFC, 0x00, 0x44, 0x10, 0x00, 0x96, + 0x3C, 0x1B, 0xF6, 0x44, 0x44, 0x10, 0x05, 0xAA, 0x3C, 0x1B, 0xF4, 0xE8, 0x84, 0x21, 0x3E, 0x17, + 0xEB, 0xFB, 0x44, 0x12, 0xC8, 0x5C, 0x84, 0x00, 0x3E, 0x07, 0xEC, 0x66, 0x3E, 0x07, 0xEC, 0x4F, + 0xAE, 0x08, 0xAE, 0x09, 0xAE, 0x0A, 0xAE, 0x0B, 0xFC, 0x80, 0xFC, 0x00, 0x2E, 0x37, 0xFF, 0xAA, + 0x44, 0x20, 0x00, 0x90, 0x44, 0x12, 0x5F, 0x60, 0x42, 0x11, 0x88, 0x73, 0x44, 0x20, 0x00, 0x48, + 0x49, 0x00, 0x43, 0x80, 0x2E, 0x07, 0xFF, 0xAA, 0x84, 0x23, 0x8C, 0x01, 0x96, 0x00, 0x40, 0x20, + 0x04, 0x37, 0x96, 0x48, 0x40, 0x10, 0x04, 0x1B, 0x3E, 0x17, 0xFF, 0xAA, 0xFC, 0x80, 0x84, 0x00, + 0x3C, 0x0B, 0xF6, 0x59, 0x3C, 0x0B, 0xF6, 0x4B, 0x2E, 0x07, 0xEC, 0x66, 0x54, 0x10, 0x00, 0xFB, + 0xC9, 0x12, 0x44, 0x02, 0x28, 0x38, 0x44, 0x12, 0x28, 0x3A, 0xA6, 0x00, 0x44, 0x22, 0x28, 0x3B, + 0x3C, 0x0B, 0xF6, 0x4B, 0x44, 0x02, 0x28, 0x39, 0xA6, 0x00, 0xA6, 0x48, 0xA6, 0x90, 0x3C, 0x2B, + 0xF6, 0x59, 0xD5, 0x23, 0x5A, 0x08, 0x01, 0x20, 0x84, 0x00, 0x44, 0x52, 0x28, 0x38, 0x80, 0x20, + 0x44, 0x32, 0x28, 0x50, 0xA7, 0x28, 0x3C, 0x23, 0xF6, 0x4B, 0x8C, 0xA4, 0x88, 0x44, 0x3C, 0x2B, + 0xF6, 0x4B, 0x00, 0x22, 0xFF, 0xFD, 0x88, 0x02, 0x00, 0x22, 0xFF, 0xFE, 0x00, 0x42, 0xFF, 0xFF, + 0x88, 0x22, 0x3C, 0x23, 0xF6, 0x59, 0x96, 0x01, 0x88, 0x44, 0x96, 0x49, 0x3C, 0x2B, 0xF6, 0x59, + 0xDB, 0xEA, 0xD5, 0x03, 0x84, 0x00, 0x80, 0x20, 0x3C, 0x23, 0xF6, 0x59, 0x88, 0x22, 0x3C, 0x23, + 0xF6, 0x4B, 0x96, 0x49, 0x88, 0x02, 0x96, 0x01, 0x3C, 0x1B, 0xF6, 0x59, 0x88, 0x20, 0x3C, 0x0B, + 0xF6, 0x4B, 0x3C, 0x1B, 0xF6, 0x57, 0xDD, 0x9E, 0xFC, 0x02, 0xF0, 0x82, 0xF1, 0x83, 0xB6, 0x5F, + 0x80, 0x02, 0xF1, 0x02, 0x80, 0x43, 0xF3, 0x81, 0x49, 0x00, 0x43, 0x1C, 0xB4, 0x1F, 0xF1, 0x03, + 0xF2, 0x01, 0x49, 0x00, 0x43, 0x17, 0xFC, 0x82, 0xFC, 0x00, 0x94, 0xD9, 0x88, 0x61, 0x84, 0xA0, + 0x4C, 0x11, 0x80, 0x18, 0xA5, 0x00, 0xA5, 0x88, 0xE2, 0xC4, 0xE8, 0x03, 0xA5, 0x00, 0xAD, 0x08, + 0xA5, 0x80, 0xA5, 0x10, 0xE2, 0xC4, 0xE8, 0x03, 0xA5, 0x00, 0xAD, 0x10, 0x0A, 0x40, 0x80, 0x01, + 0x0A, 0x61, 0x00, 0x01, 0x8A, 0x86, 0xE0, 0xA4, 0xE8, 0x02, 0x97, 0x61, 0x8C, 0x02, 0xD5, 0xE9, + 0x80, 0x05, 0xFC, 0x80, 0xFC, 0x00, 0x44, 0x40, 0x01, 0x20, 0x80, 0xC1, 0x44, 0x12, 0x00, 0x00, + 0x42, 0x10, 0x10, 0x73, 0x80, 0x01, 0x80, 0x22, 0x80, 0x43, 0x44, 0x30, 0x00, 0x48, 0x49, 0xFF, + 0xFF, 0xD5, 0xAC, 0x30, 0xFC, 0x80, 0x94, 0x49, 0x88, 0x20, 0x44, 0x30, 0xFF, 0xFF, 0x84, 0x40, + 0x4C, 0x00, 0x80, 0x0E, 0xA5, 0x00, 0xE2, 0x44, 0xE8, 0x03, 0xA4, 0x80, 0x96, 0x91, 0xA5, 0x00, + 0xE2, 0x83, 0xE8, 0x03, 0xA4, 0xC0, 0x96, 0xD9, 0x8C, 0x02, 0xD5, 0xF3, 0x5C, 0xF1, 0x80, 0x97, + 0x80, 0x03, 0xE9, 0x03, 0x44, 0x00, 0x00, 0x96, 0x9A, 0x10, 0x96, 0x01, 0xDD, 0x9E, 0xFC, 0x40, + 0x44, 0x10, 0x02, 0x40, 0x42, 0x90, 0x04, 0x24, 0x44, 0x62, 0x00, 0x00, 0x88, 0xC9, 0x44, 0x12, + 0x00, 0x02, 0x80, 0x06, 0x88, 0x29, 0x80, 0xE2, 0x44, 0x30, 0x00, 0x90, 0x80, 0x46, 0x84, 0x81, + 0xFA, 0xA0, 0x49, 0x00, 0x12, 0xC3, 0x44, 0x02, 0x01, 0x20, 0x89, 0x20, 0xFA, 0x34, 0x80, 0x06, + 0x49, 0xFF, 0xFF, 0xCB, 0x0A, 0x13, 0x80, 0x01, 0xE2, 0x20, 0xE8, 0x03, 0x12, 0x03, 0xFF, 0xFF, + 0x50, 0x63, 0x00, 0x48, 0x4C, 0x64, 0xFF, 0xF4, 0xFC, 0xC0, 0xFC, 0x00, 0x2E, 0x00, 0x05, 0xFB, + 0x2E, 0x10, 0x06, 0x2D, 0xC0, 0x1E, 0x3C, 0x0D, 0xF2, 0xA8, 0x5A, 0x18, 0x01, 0x04, 0x92, 0x01, + 0xD5, 0x02, 0x92, 0x02, 0x3C, 0x2C, 0x01, 0x80, 0x96, 0x01, 0xE2, 0x40, 0x2E, 0x00, 0x06, 0x0B, + 0xE8, 0x05, 0xE6, 0x1E, 0xE8, 0x0E, 0x8C, 0x01, 0xD5, 0x0A, 0xC0, 0x0B, 0x5C, 0xF1, 0x0E, 0x10, + 0xE9, 0x05, 0xE6, 0x0F, 0xE9, 0x03, 0x8E, 0x05, 0xD5, 0x02, 0x8E, 0x01, 0x3E, 0x00, 0x06, 0x0B, + 0x5A, 0x10, 0x01, 0x06, 0x2E, 0x07, 0xEC, 0x2F, 0x5A, 0x08, 0x01, 0x0D, 0x2E, 0x00, 0x06, 0x0B, + 0x5A, 0x08, 0x1E, 0x04, 0x84, 0x05, 0xD5, 0x08, 0xE6, 0x14, 0x84, 0x06, 0xE8, 0x05, 0x84, 0x0D, + 0xD5, 0x03, 0x49, 0x00, 0x18, 0x3D, 0x3C, 0x0F, 0xFB, 0x4C, 0xFC, 0x80, 0x2E, 0x47, 0xEC, 0x66, + 0xC4, 0x03, 0xFA, 0x98, 0xD5, 0x03, 0x44, 0x40, 0x00, 0x32, 0x3C, 0x50, 0x03, 0x03, 0xE2, 0x85, + 0xE8, 0x05, 0x3C, 0x50, 0x03, 0x02, 0xE2, 0xA4, 0xE8, 0x09, 0x3C, 0x43, 0xFF, 0xCE, 0x44, 0x50, + 0xEA, 0x5F, 0xE2, 0xA4, 0xE9, 0x06, 0x8C, 0x81, 0xD5, 0x02, 0x84, 0x80, 0x3C, 0x4B, 0xFF, 0xCE, + 0x3C, 0x43, 0xFF, 0xCE, 0x5C, 0xF2, 0x00, 0x33, 0xE8, 0x03, 0x5A, 0x38, 0x01, 0x11, 0x94, 0x91, + 0x88, 0x41, 0x84, 0xA3, 0x4C, 0x11, 0x00, 0x0C, 0xA5, 0x08, 0x0A, 0x30, 0x00, 0x01, 0xFF, 0x2C, + 0x90, 0x82, 0x92, 0x62, 0x88, 0x64, 0x1A, 0x30, 0x80, 0x01, 0xD5, 0xF5, 0xDD, 0x9E, 0x84, 0x00, + 0x3E, 0x00, 0x06, 0x0A, 0x84, 0x00, 0x3C, 0x0B, 0xFF, 0xCE, 0xDD, 0x9E, 0xFC, 0x00, 0x3C, 0x03, + 0xFF, 0xCE, 0x5C, 0xF0, 0x00, 0x33, 0xE9, 0x06, 0x49, 0xFF, 0xFF, 0xF3, 0x84, 0x00, 0x3C, 0x0B, + 0xF6, 0x42, 0x3C, 0x03, 0xFF, 0xCD, 0x5C, 0xF0, 0x00, 0x33, 0xE9, 0x04, 0x84, 0x00, 0x3C, 0x0B, + 0xFF, 0xCD, 0xFC, 0x80, 0xFC, 0x00, 0x80, 0xC0, 0x84, 0x00, 0x3C, 0x0B, 0xF6, 0x57, 0x49, 0xFF, + 0xFE, 0xA8, 0x49, 0x00, 0x13, 0xD9, 0x5A, 0x00, 0x02, 0x0A, 0x3C, 0x03, 0xE3, 0xEC, 0x84, 0x23, + 0xFE, 0x44, 0x96, 0x49, 0xE2, 0xC1, 0xE9, 0x0E, 0xD5, 0x12, 0x3C, 0x0D, 0xFF, 0xEB, 0x00, 0x10, + 0x00, 0x2B, 0x3C, 0x03, 0xF4, 0xE8, 0xE2, 0xC0, 0xE8, 0x0A, 0x3C, 0x03, 0xF6, 0x57, 0xE2, 0x20, + 0xE9, 0x06, 0x84, 0x00, 0x3C, 0x0B, 0xFF, 0xCD, 0x84, 0x00, 0xD5, 0x02, 0x84, 0x01, 0xFC, 0x80, + 0xB4, 0x61, 0xAE, 0x18, 0x5A, 0x28, 0x02, 0x04, 0x92, 0x08, 0xAE, 0x19, 0xB4, 0x01, 0x88, 0x40, + 0xB6, 0x41, 0xDD, 0x9E, 0xFC, 0x44, 0x81, 0x20, 0xB6, 0x1F, 0x80, 0xC1, 0x84, 0x00, 0xB1, 0xC1, + 0x38, 0x14, 0x80, 0x00, 0x38, 0x10, 0x1C, 0x08, 0x8C, 0x01, 0x5A, 0x08, 0x1A, 0xFB, 0x44, 0x00, + 0x15, 0x54, 0x80, 0x3F, 0x84, 0x42, 0x49, 0xFF, 0xFF, 0xE5, 0x3C, 0x0C, 0x01, 0xA2, 0xB4, 0x3F, + 0x44, 0xA2, 0x00, 0x00, 0xA6, 0x80, 0xAE, 0x88, 0x04, 0x00, 0x00, 0x1C, 0xB4, 0x3F, 0x92, 0x10, + 0x9C, 0x89, 0x96, 0x2F, 0xB6, 0x5F, 0xAE, 0x09, 0xB4, 0x1F, 0x80, 0x3F, 0x8C, 0x01, 0xB6, 0x1F, + 0x84, 0x42, 0x44, 0x00, 0x1E, 0xDC, 0x49, 0xFF, 0xFF, 0xCD, 0x3C, 0x0C, 0x01, 0xA1, 0x80, 0x3F, + 0x04, 0x20, 0x00, 0x12, 0x92, 0x50, 0x54, 0x21, 0x7F, 0xFF, 0x94, 0x92, 0x89, 0x42, 0x83, 0x8A, + 0x84, 0x42, 0xB8, 0x0C, 0x92, 0x10, 0x54, 0x00, 0x07, 0xFF, 0x49, 0xFF, 0xFF, 0xBB, 0x02, 0x05, + 0x00, 0x12, 0x80, 0x3F, 0x84, 0x42, 0x49, 0xFF, 0xFF, 0xB5, 0xB8, 0x09, 0x80, 0x3F, 0x92, 0x10, + 0x54, 0x00, 0x0F, 0xFF, 0x84, 0x42, 0x49, 0xFF, 0xFF, 0xAD, 0xB4, 0x1F, 0x00, 0x15, 0x00, 0x20, + 0x44, 0xA2, 0x01, 0x50, 0xAE, 0x40, 0xB4, 0x1F, 0x9C, 0x41, 0xB6, 0x3F, 0x3C, 0x1C, 0x01, 0xAE, + 0x04, 0x20, 0x80, 0x12, 0x92, 0x50, 0x54, 0x21, 0x7F, 0xFF, 0x94, 0x92, 0x89, 0x42, 0x84, 0x42, + 0x00, 0x15, 0x00, 0x20, 0xAE, 0x41, 0xB4, 0x1F, 0x80, 0x3F, 0x8C, 0x01, 0xB6, 0x1F, 0x04, 0x05, + 0x00, 0x0C, 0x92, 0x10, 0x54, 0x00, 0x07, 0xFF, 0x49, 0xFF, 0xFF, 0x8C, 0x02, 0x05, 0x00, 0x12, + 0x80, 0x3F, 0x84, 0x42, 0x49, 0xFF, 0xFF, 0x86, 0x04, 0x05, 0x00, 0x09, 0x80, 0x3F, 0x92, 0x10, + 0x54, 0x00, 0x0F, 0xFF, 0x84, 0x42, 0x49, 0xFF, 0xFF, 0x7D, 0x44, 0x0F, 0xFF, 0xAA, 0x10, 0x03, + 0x00, 0x51, 0x44, 0x13, 0xF0, 0x4A, 0x44, 0x20, 0x00, 0x55, 0x00, 0x03, 0x00, 0x51, 0x5A, 0x00, + 0xCC, 0x04, 0xAE, 0x88, 0xD5, 0xFB, 0x84, 0x00, 0x38, 0x13, 0x80, 0x00, 0x38, 0x14, 0x80, 0x08, + 0x8C, 0x01, 0x5A, 0x08, 0x1A, 0xFB, 0x84, 0x00, 0x10, 0x03, 0x00, 0x51, 0xFC, 0xC4, 0xFC, 0x00, + 0x2E, 0x07, 0xEC, 0x66, 0x54, 0x00, 0x00, 0xFB, 0xC8, 0x0A, 0x44, 0x02, 0x0A, 0x20, 0x3C, 0x1C, + 0x02, 0xA6, 0x44, 0x20, 0x00, 0x48, 0x49, 0x00, 0x41, 0x4D, 0xD5, 0x0D, 0x44, 0x02, 0x0A, 0x20, + 0x44, 0x12, 0x0A, 0x22, 0x3C, 0x2C, 0x02, 0xA6, 0x44, 0x30, 0x00, 0x90, 0x84, 0x81, 0xFA, 0xA0, + 0x49, 0x00, 0x11, 0x4C, 0xFC, 0x80, 0xFC, 0x20, 0x54, 0x00, 0x00, 0xFB, 0xC0, 0x06, 0x44, 0x72, + 0x5C, 0x00, 0x44, 0x60, 0x00, 0x90, 0xD5, 0x05, 0x44, 0x72, 0x5F, 0x60, 0x44, 0x60, 0x00, 0x48, + 0x2E, 0x07, 0xEC, 0x2B, 0x8E, 0x01, 0xE6, 0x02, 0xE8, 0x08, 0x44, 0x02, 0x4B, 0x40, 0x44, 0x12, + 0x4A, 0x20, 0x80, 0x46, 0x49, 0x00, 0x41, 0x26, 0x2E, 0x07, 0xEC, 0x2B, 0x54, 0x00, 0x00, 0xFD, + 0x5A, 0x08, 0x01, 0x10, 0x95, 0xB1, 0x84, 0xA0, 0x44, 0x32, 0x4B, 0x40, 0x98, 0xAB, 0x98, 0x7D, + 0x84, 0x03, 0xA5, 0x10, 0x8E, 0x01, 0x38, 0x40, 0x98, 0x0D, 0xC8, 0xFC, 0x8C, 0xA2, 0xDE, 0xF7, + 0xFC, 0xA0, 0xFC, 0x00, 0x49, 0xFF, 0xFE, 0xDC, 0x49, 0xFF, 0xFF, 0xB3, 0x2E, 0x07, 0xEC, 0x2B, + 0xC0, 0x0A, 0x49, 0xFF, 0xFE, 0xCE, 0x2E, 0x07, 0xEC, 0x66, 0x49, 0xFF, 0xFF, 0xC6, 0x84, 0x00, + 0x3E, 0x07, 0xEC, 0x2B, 0x84, 0x00, 0x3E, 0x07, 0xEB, 0xFA, 0xFC, 0x80, 0x2E, 0x10, 0x06, 0x2D, + 0x5A, 0x18, 0x01, 0x05, 0x2E, 0x17, 0xC7, 0xDA, 0xD5, 0x03, 0x3C, 0x13, 0xE3, 0xC1, 0x2E, 0x27, + 0xEC, 0x4C, 0xCA, 0x05, 0x2E, 0x27, 0xC7, 0xDC, 0x88, 0x22, 0x96, 0x49, 0xAC, 0x40, 0x2E, 0x17, + 0xEC, 0x2F, 0x5A, 0x18, 0x01, 0x22, 0x2E, 0x20, 0x05, 0xFB, 0x5A, 0x28, 0x01, 0x12, 0x3C, 0x13, + 0xF6, 0x4C, 0x5C, 0xF0, 0x81, 0xE0, 0xE9, 0x06, 0x2E, 0x17, 0xC7, 0xDA, 0x50, 0x10, 0x80, 0x28, + 0xD5, 0x12, 0x5C, 0xF0, 0x80, 0x78, 0xE8, 0x04, 0x3C, 0x13, 0xE3, 0xC1, 0xD5, 0x0C, 0x2E, 0x37, + 0xEC, 0x56, 0x2E, 0x17, 0xC7, 0xDA, 0x5A, 0x38, 0x01, 0x06, 0xE6, 0x42, 0xE9, 0x03, 0x8E, 0x2A, + 0xD5, 0x02, 0x8C, 0x2A, 0xAC, 0x40, 0x3C, 0x10, 0x03, 0x99, 0x3C, 0x1B, 0xF6, 0x4C, 0x2E, 0x17, + 0xC7, 0xDA, 0xAC, 0x44, 0xDD, 0x9E, 0xFC, 0x00, 0x04, 0x00, 0x00, 0x12, 0x44, 0x12, 0x00, 0x54, + 0x92, 0x10, 0x54, 0x00, 0x7F, 0xFF, 0x94, 0x02, 0x88, 0x01, 0x44, 0x12, 0x8F, 0x70, 0x00, 0x20, + 0x81, 0x28, 0x10, 0x20, 0x00, 0x18, 0x00, 0x20, 0x81, 0x29, 0x10, 0x20, 0x00, 0x19, 0x00, 0x20, + 0x81, 0x26, 0x10, 0x20, 0x00, 0x1B, 0x00, 0x10, 0x81, 0x27, 0x10, 0x10, 0x00, 0x1A, 0xA0, 0x85, + 0x46, 0x11, 0x00, 0x00, 0xFE, 0x57, 0xA8, 0x45, 0xA0, 0x85, 0x46, 0x12, 0x00, 0x00, 0xFE, 0x57, + 0xA8, 0x45, 0xA0, 0x85, 0x46, 0x18, 0x00, 0x00, 0xFE, 0x57, 0xA8, 0x45, 0xA0, 0x85, 0x46, 0x14, + 0x00, 0x00, 0xFE, 0x57, 0xA8, 0x45, 0x44, 0x02, 0x28, 0x38, 0x49, 0x00, 0x11, 0x4E, 0xFC, 0x80, + 0x3C, 0x0F, 0xFF, 0xEB, 0xDD, 0x9E, 0x2E, 0x30, 0x06, 0x2D, 0x5A, 0x30, 0x01, 0x06, 0x2E, 0x37, + 0xEB, 0xFA, 0x5A, 0x38, 0x01, 0x2F, 0x00, 0x30, 0x00, 0x10, 0x3E, 0x37, 0xCA, 0x89, 0xA0, 0xC5, + 0x84, 0x0A, 0xFE, 0x1C, 0x3C, 0x0F, 0xF2, 0xA3, 0xA6, 0x0A, 0x3E, 0x07, 0xCA, 0xD4, 0xA6, 0x0B, + 0x3E, 0x07, 0xCA, 0xD5, 0x00, 0x01, 0x00, 0x0C, 0x3E, 0x07, 0xCB, 0x00, 0x00, 0x01, 0x00, 0x0D, + 0x3E, 0x07, 0xCB, 0x01, 0xA4, 0x17, 0x3C, 0x0B, 0xE5, 0x81, 0x02, 0x01, 0x00, 0x08, 0x3C, 0x0B, + 0xE5, 0x82, 0x00, 0x01, 0x00, 0x12, 0x3E, 0x07, 0xCB, 0x06, 0x00, 0x01, 0x00, 0x13, 0x3E, 0x07, + 0xCB, 0x07, 0x02, 0x01, 0x00, 0x0A, 0x3C, 0x0B, 0xE5, 0x84, 0x02, 0x01, 0x00, 0x0B, 0xD5, 0x29, + 0x2E, 0x30, 0x05, 0xA0, 0x5A, 0x38, 0x01, 0x04, 0x84, 0x62, 0xD5, 0x02, 0xA6, 0xC0, 0x3E, 0x37, + 0xCA, 0x89, 0xA0, 0x03, 0x3C, 0x0F, 0xF2, 0xA3, 0xA6, 0x08, 0x3E, 0x07, 0xCA, 0xD4, 0xA6, 0x09, + 0x3E, 0x07, 0xCA, 0xD5, 0xA6, 0x10, 0x3E, 0x07, 0xCB, 0x00, 0xA6, 0x11, 0x3E, 0x07, 0xCB, 0x01, + 0xA4, 0x11, 0x3C, 0x0B, 0xE5, 0x81, 0xA4, 0x12, 0x3C, 0x0B, 0xE5, 0x82, 0xA6, 0x16, 0x3E, 0x07, + 0xCB, 0x06, 0xA6, 0x17, 0x3E, 0x07, 0xCB, 0x07, 0xA4, 0x14, 0x3C, 0x0B, 0xE5, 0x84, 0xA4, 0x15, + 0x3C, 0x0B, 0xE5, 0x85, 0xDD, 0x9E, 0xFC, 0x40, 0x5A, 0x08, 0x01, 0x17, 0x2E, 0x20, 0x0C, 0xF5, + 0x2E, 0x00, 0x0D, 0x06, 0x84, 0xC6, 0x40, 0x10, 0x08, 0x17, 0x96, 0x00, 0x44, 0x10, 0x00, 0x90, + 0xFE, 0x0C, 0x40, 0x63, 0x08, 0xD6, 0xFE, 0x54, 0x44, 0x72, 0x5F, 0x60, 0x44, 0x42, 0x4A, 0x20, + 0x44, 0x30, 0x00, 0x48, 0xD5, 0x0A, 0x44, 0x72, 0x5C, 0x00, 0x80, 0x87, 0x44, 0x10, 0x01, 0x20, + 0x84, 0x00, 0x84, 0xC6, 0x44, 0x30, 0x00, 0x90, 0x84, 0x40, 0x81, 0x22, 0x38, 0x92, 0x09, 0x09, + 0x8C, 0x41, 0x97, 0x50, 0xE2, 0xA3, 0xE9, 0xFB, 0x94, 0x89, 0x94, 0x01, 0x84, 0x20, 0x45, 0xC2, + 0x00, 0x00, 0x4C, 0x13, 0x40, 0x05, 0x95, 0x99, 0x84, 0x20, 0xD5, 0x17, 0x81, 0x24, 0x84, 0xA0, + 0x40, 0xF0, 0x70, 0x00, 0x40, 0xA4, 0x90, 0x01, 0x02, 0x84, 0x80, 0x00, 0x38, 0xA5, 0x3C, 0x01, + 0x8C, 0xA1, 0x40, 0xA5, 0x19, 0x56, 0x89, 0x48, 0x97, 0x68, 0x1A, 0xA4, 0x80, 0x01, 0xDB, 0xF3, + 0x8C, 0x21, 0x96, 0x48, 0x88, 0x02, 0xD5, 0xE6, 0x94, 0x89, 0x88, 0x47, 0x84, 0x03, 0x38, 0x52, + 0x05, 0x01, 0x8E, 0x01, 0x96, 0x00, 0x38, 0x51, 0x18, 0x0D, 0xC8, 0xFA, 0x8C, 0x21, 0x96, 0x08, + 0xE2, 0x03, 0xE9, 0xF3, 0xFC, 0xC0, 0xFC, 0x42, 0x84, 0x80, 0x84, 0xFF, 0x84, 0xC1, 0xF2, 0x83, + 0x81, 0x47, 0x80, 0xA4, 0xF4, 0x81, 0x45, 0xE2, 0xC8, 0x5C, 0x81, 0x06, 0x83, 0x84, 0x96, 0xA0, + 0xF2, 0x82, 0x02, 0xF0, 0x00, 0x00, 0xF2, 0x03, 0x81, 0x20, 0x40, 0xF7, 0x88, 0x06, 0xE8, 0x0F, + 0x02, 0xF0, 0x80, 0x00, 0x40, 0xF7, 0x8C, 0x06, 0xE8, 0x0A, 0x39, 0xCF, 0x10, 0x08, 0xA5, 0x80, + 0xE2, 0xCA, 0xE8, 0x08, 0xF2, 0x02, 0x81, 0x46, 0xF2, 0x81, 0xD5, 0x04, 0x38, 0x8F, 0x10, 0x08, + 0xD5, 0x02, 0x84, 0xC0, 0x02, 0xF0, 0x00, 0x00, 0x80, 0x48, 0x5C, 0xF7, 0x81, 0x18, 0x40, 0x2E, + 0x3C, 0x1A, 0x81, 0xE2, 0x44, 0x22, 0xC8, 0x58, 0x8C, 0x02, 0x38, 0xF1, 0x10, 0x08, 0x02, 0x94, + 0x80, 0x00, 0x0A, 0xF0, 0x80, 0x01, 0x89, 0x2F, 0xF2, 0x02, 0xE3, 0x27, 0x40, 0x22, 0xBC, 0x1A, + 0x8C, 0x81, 0x40, 0x74, 0xBC, 0x1B, 0x80, 0xA2, 0x5A, 0x48, 0x04, 0xCB, 0x5A, 0x60, 0x01, 0x03, + 0xF5, 0x01, 0x80, 0x05, 0xFC, 0xC2, 0x80, 0x20, 0x3C, 0x0C, 0x01, 0xA1, 0xC1, 0x19, 0x5A, 0x18, + 0x01, 0x05, 0x3C, 0x0C, 0x01, 0xA9, 0xDD, 0x9E, 0x5A, 0x18, 0x03, 0x05, 0x3C, 0x0C, 0x01, 0xA2, + 0xDD, 0x9E, 0x5A, 0x18, 0x02, 0x05, 0x3C, 0x0C, 0x01, 0xAA, 0xDD, 0x9E, 0x5A, 0x18, 0x04, 0x05, + 0x3C, 0x0C, 0x01, 0xAE, 0xDD, 0x9E, 0x5A, 0x18, 0x05, 0x04, 0x3C, 0x0C, 0x01, 0xAF, 0xDD, 0x9E, + 0x2E, 0x07, 0xEC, 0x4C, 0xC8, 0x28, 0x3C, 0x1C, 0x01, 0x88, 0x5C, 0xF0, 0x80, 0x4B, 0xE9, 0x23, + 0x3C, 0x0B, 0xF6, 0x54, 0x44, 0x22, 0x25, 0xB0, 0x80, 0x60, 0x3C, 0x13, 0xE3, 0x76, 0xE2, 0x01, + 0xE8, 0x06, 0x98, 0x42, 0x8C, 0x01, 0xAE, 0xC8, 0x96, 0x01, 0xD5, 0xF8, 0xFC, 0x00, 0x3C, 0x0C, + 0x02, 0xA2, 0x3C, 0x1C, 0x02, 0xA4, 0x49, 0x00, 0x3F, 0x68, 0x3C, 0x0C, 0x02, 0xA6, 0x44, 0x12, + 0x4A, 0x20, 0x44, 0x20, 0x00, 0x48, 0x84, 0x61, 0x49, 0xFF, 0xFC, 0xDA, 0x84, 0x01, 0x3E, 0x07, + 0xEC, 0x4C, 0xFC, 0x80, 0xDD, 0x9E, 0x94, 0xD9, 0x88, 0x60, 0x4C, 0x01, 0x80, 0x05, 0x1A, 0x20, + 0x00, 0x01, 0xD5, 0xFC, 0xDD, 0x9E, 0x44, 0x03, 0xF0, 0x4A, 0x44, 0x10, 0x00, 0x55, 0xAE, 0x40, + 0x44, 0x13, 0xF4, 0x03, 0xA6, 0x08, 0xC8, 0xFF, 0xDD, 0x9E, 0x3C, 0x2C, 0x01, 0xA1, 0x44, 0x12, + 0x00, 0xA8, 0x04, 0x01, 0x00, 0x12, 0x92, 0x10, 0x54, 0x00, 0x7F, 0xFF, 0x94, 0x02, 0x88, 0x01, + 0x44, 0x12, 0x00, 0x00, 0xB4, 0x00, 0x92, 0x0A, 0x96, 0x37, 0x3E, 0x07, 0xEC, 0x3E, 0x04, 0x01, + 0x00, 0x12, 0x92, 0x10, 0x54, 0x00, 0x7F, 0xFF, 0x94, 0x02, 0x88, 0x01, 0xB4, 0x20, 0x00, 0x00, + 0x00, 0x20, 0x92, 0x2A, 0x96, 0x77, 0x3E, 0x17, 0xEC, 0x23, 0x3E, 0x07, 0xEC, 0x46, 0xDD, 0x9E, + 0xFC, 0x00, 0x84, 0x00, 0x3C, 0x0F, 0xFB, 0x87, 0x3C, 0x0D, 0xFB, 0x59, 0x84, 0x21, 0xAE, 0x40, + 0x49, 0x00, 0x42, 0xF7, 0x44, 0x03, 0xF0, 0x4A, 0x44, 0x10, 0x00, 0x55, 0xAE, 0x40, 0x3C, 0x2D, + 0xFB, 0x59, 0xA6, 0x50, 0x5A, 0x10, 0x01, 0xFF, 0x44, 0x10, 0x00, 0x55, 0xAE, 0x40, 0x44, 0x13, + 0xF4, 0x03, 0xA6, 0x08, 0x96, 0x00, 0xC8, 0xFE, 0x3C, 0x1D, 0xFB, 0x59, 0x84, 0x41, 0xAE, 0x88, + 0x3C, 0x0E, 0x01, 0x88, 0xFC, 0x80, 0xFC, 0x00, 0x80, 0xC0, 0x49, 0xFF, 0xFF, 0xAE, 0x3C, 0x0D, + 0xFB, 0x4A, 0x3E, 0x67, 0xEC, 0x66, 0x49, 0xFF, 0xF9, 0x9A, 0xFC, 0x80, 0xFC, 0x40, 0x44, 0x42, + 0x8F, 0x70, 0x2E, 0x67, 0xC8, 0x4C, 0x2E, 0x37, 0xEC, 0x66, 0x84, 0x20, 0x80, 0xE4, 0x96, 0x88, + 0xE2, 0x46, 0xE8, 0x17, 0x98, 0x81, 0xC3, 0x04, 0x00, 0x51, 0x00, 0x20, 0xD5, 0x03, 0x38, 0x50, + 0x04, 0x00, 0x40, 0x92, 0x04, 0x00, 0x10, 0x54, 0x81, 0x84, 0xC3, 0x04, 0x00, 0x21, 0x00, 0x28, + 0xD5, 0x03, 0x00, 0x21, 0x00, 0x08, 0x99, 0x79, 0x8C, 0x21, 0x10, 0x22, 0x81, 0x8C, 0xD5, 0xE8, + 0xFC, 0xC0, 0x44, 0x22, 0xCF, 0x3C, 0x44, 0x32, 0x00, 0x00, 0xB4, 0x82, 0xA0, 0x91, 0x84, 0xA1, + 0x04, 0x12, 0x00, 0x12, 0x92, 0x30, 0x54, 0x10, 0xFF, 0xFF, 0x94, 0x4A, 0x88, 0x23, 0x44, 0x32, + 0x01, 0x50, 0x04, 0x10, 0x80, 0x08, 0x94, 0x4A, 0x92, 0x34, 0x96, 0x4B, 0x12, 0x10, 0x00, 0x81, + 0x3C, 0x1B, 0xF6, 0x62, 0x04, 0x12, 0x00, 0x12, 0x04, 0x21, 0x00, 0x13, 0x92, 0x30, 0x54, 0x10, + 0xFF, 0xFF, 0x94, 0x4A, 0x88, 0x23, 0x54, 0x21, 0x7F, 0xFF, 0x44, 0x32, 0x00, 0x0C, 0x94, 0x92, + 0x88, 0x43, 0x02, 0x30, 0x80, 0x1B, 0x10, 0x30, 0x01, 0x04, 0x02, 0x30, 0x80, 0x1B, 0x92, 0x68, + 0x10, 0x30, 0x01, 0x05, 0x02, 0x30, 0x80, 0x1A, 0x10, 0x30, 0x01, 0x06, 0x02, 0x30, 0x80, 0x1A, + 0x92, 0x68, 0x10, 0x30, 0x01, 0x07, 0xA4, 0xD3, 0x10, 0x30, 0x01, 0x08, 0xA4, 0xD3, 0x92, 0x68, + 0x10, 0x30, 0x01, 0x09, 0xA4, 0xD1, 0x10, 0x30, 0x01, 0x0A, 0xA4, 0xD1, 0x92, 0x68, 0x10, 0x30, + 0x01, 0x0B, 0xA0, 0xD2, 0x92, 0x78, 0x54, 0x41, 0x80, 0x3F, 0x04, 0x30, 0x80, 0x0F, 0x92, 0x61, + 0xFE, 0xEE, 0x94, 0xDF, 0xFE, 0xE7, 0x10, 0x30, 0x01, 0x0C, 0xA0, 0x92, 0x04, 0x10, 0x80, 0x0F, + 0x92, 0x48, 0xFE, 0x6E, 0x96, 0xAF, 0x94, 0x4F, 0xFE, 0x57, 0x10, 0x10, 0x01, 0x0D, 0xDD, 0x9E, + 0xFC, 0x00, 0x80, 0x40, 0x3C, 0x0C, 0x01, 0xA2, 0x44, 0x32, 0x01, 0x50, 0x83, 0x80, 0x44, 0x02, + 0x00, 0x0C, 0xBC, 0x12, 0x00, 0x50, 0x81, 0x04, 0x92, 0x90, 0x54, 0x42, 0x7F, 0xFF, 0x95, 0x22, + 0x88, 0x83, 0xBB, 0x13, 0x50, 0xF2, 0x00, 0x3C, 0x54, 0x31, 0xFF, 0xFF, 0x94, 0xDA, 0x88, 0x60, + 0x00, 0x00, 0x81, 0x05, 0x40, 0x00, 0x20, 0x08, 0x88, 0x05, 0x96, 0x01, 0x12, 0x02, 0x00, 0x1B, + 0x00, 0x00, 0x81, 0x07, 0x00, 0x50, 0x81, 0x06, 0x40, 0x00, 0x20, 0x08, 0x88, 0x05, 0x96, 0x01, + 0x12, 0x02, 0x00, 0x1A, 0x00, 0x00, 0x81, 0x0C, 0xB4, 0xCF, 0x92, 0x07, 0x95, 0x41, 0x84, 0x1D, + 0xFE, 0x36, 0xFE, 0x2F, 0xB6, 0x0F, 0x00, 0x00, 0x81, 0x0D, 0xB4, 0xCF, 0x40, 0x50, 0x1C, 0x09, + 0x84, 0x1E, 0xFE, 0x36, 0xFE, 0x2F, 0xB6, 0x0F, 0x00, 0x00, 0x81, 0x09, 0x00, 0x40, 0x81, 0x08, + 0x40, 0x00, 0x20, 0x08, 0x88, 0x04, 0x96, 0x01, 0xAC, 0x1B, 0x00, 0x00, 0x81, 0x0B, 0x00, 0x40, + 0x81, 0x0A, 0x40, 0x00, 0x20, 0x08, 0x88, 0x04, 0x96, 0x01, 0xAC, 0x19, 0x00, 0x40, 0x81, 0x0C, + 0xA0, 0x1A, 0x97, 0x2F, 0x40, 0x52, 0x60, 0x08, 0x46, 0x4C, 0x0F, 0xFF, 0x50, 0x42, 0x0F, 0xFF, + 0xFF, 0x06, 0xFF, 0x2F, 0xA9, 0x1A, 0x00, 0x10, 0x81, 0x0D, 0x44, 0x0F, 0xC0, 0xFF, 0x96, 0x6F, + 0x40, 0x40, 0xA0, 0x08, 0xA0, 0x5A, 0xFE, 0x46, 0xFE, 0x67, 0xA8, 0x5A, 0xC2, 0x03, 0x8E, 0x41, + 0x96, 0x90, 0x84, 0x03, 0x3C, 0x1D, 0xFB, 0x4A, 0x44, 0x32, 0xB5, 0x0D, 0x49, 0xFF, 0xF9, 0xF6, + 0xFC, 0x80, 0x00, 0x10, 0x00, 0x53, 0xC9, 0x28, 0x3C, 0x1C, 0x01, 0xA2, 0x44, 0x22, 0x01, 0x50, + 0x04, 0x10, 0x80, 0x12, 0x92, 0x30, 0x54, 0x10, 0xFF, 0xFF, 0x94, 0x4A, 0x88, 0x22, 0x00, 0x20, + 0x00, 0x54, 0x5A, 0x28, 0x01, 0x07, 0xA0, 0xCD, 0x44, 0x2C, 0xFF, 0xFF, 0xFE, 0x9E, 0xD5, 0x0A, + 0x5A, 0x28, 0x02, 0x0A, 0xA0, 0xCD, 0x44, 0x2C, 0xFF, 0xFF, 0xFE, 0x9E, 0x44, 0x32, 0x00, 0x00, + 0xFE, 0x9F, 0xA8, 0x8D, 0x84, 0x20, 0x10, 0x10, 0x00, 0x52, 0x10, 0x10, 0x00, 0x53, 0x10, 0x10, + 0x00, 0x54, 0x84, 0x01, 0xDD, 0x9E, 0x84, 0x00, 0xDD, 0x9E, 0xFC, 0x41, 0x81, 0x21, 0xB6, 0x1F, + 0x81, 0x02, 0xF3, 0x81, 0x80, 0xC4, 0x3C, 0x1D, 0xFB, 0x64, 0xA6, 0x08, 0x96, 0x00, 0x5A, 0x08, + 0x01, 0xFE, 0x3C, 0x1D, 0xFB, 0x59, 0xAE, 0x08, 0x49, 0x00, 0x41, 0xA3, 0x3C, 0x0D, 0xFB, 0x64, + 0xA7, 0xC0, 0x97, 0xF8, 0x5A, 0x78, 0x01, 0xFE, 0xB4, 0x1F, 0x85, 0x40, 0x3E, 0xA7, 0xEC, 0x4D, + 0x49, 0x00, 0x3D, 0xF6, 0x3C, 0x0D, 0xFB, 0x59, 0xAF, 0xC0, 0x00, 0x74, 0x81, 0x2E, 0xCF, 0x06, + 0x49, 0x00, 0x3E, 0x02, 0x3E, 0x77, 0xEC, 0x4D, 0xD5, 0x11, 0x00, 0x73, 0x00, 0x51, 0x97, 0xC6, + 0xCF, 0x06, 0x49, 0x00, 0x3D, 0xF9, 0x10, 0x74, 0x80, 0x9E, 0xD5, 0x05, 0x3E, 0xA7, 0xC7, 0xE6, + 0x49, 0x00, 0x3D, 0x07, 0x84, 0x01, 0x10, 0x04, 0x00, 0x00, 0xF1, 0x01, 0x84, 0x0A, 0xAE, 0x08, + 0x44, 0x0F, 0xFF, 0xAA, 0x10, 0x03, 0x00, 0x51, 0x84, 0x00, 0x10, 0x03, 0x00, 0x52, 0x10, 0x03, + 0x00, 0x53, 0xFC, 0xC1, 0x3C, 0x1C, 0x01, 0xA1, 0x54, 0x00, 0x0F, 0xFF, 0x04, 0x20, 0x80, 0x12, + 0x04, 0x10, 0x80, 0x12, 0x44, 0x22, 0x00, 0x54, 0x92, 0x30, 0x54, 0x10, 0xFF, 0xFF, 0x94, 0x4A, + 0x88, 0x22, 0x40, 0x20, 0x48, 0x08, 0x04, 0x30, 0x80, 0x08, 0x46, 0x0C, 0x00, 0x3F, 0x50, 0x00, + 0x0F, 0xFF, 0xFE, 0x1E, 0xFE, 0x17, 0x14, 0x00, 0x80, 0x08, 0xDD, 0x9E, 0xFC, 0x42, 0xFA, 0x40, + 0x80, 0xE1, 0x80, 0xC0, 0x84, 0x20, 0x80, 0x1F, 0x49, 0x00, 0x75, 0x12, 0x44, 0x32, 0xC8, 0x48, + 0x44, 0x02, 0xC8, 0x40, 0x80, 0xA7, 0x80, 0x83, 0x8C, 0xE8, 0x80, 0x20, 0x44, 0x80, 0x00, 0x3F, + 0x85, 0x23, 0xA4, 0xA8, 0x0B, 0xC1, 0x80, 0x01, 0x40, 0xFE, 0x08, 0x06, 0x81, 0x45, 0xE8, 0x04, + 0x88, 0x5C, 0x90, 0x41, 0xD5, 0x04, 0x42, 0x2E, 0x20, 0x73, 0x90, 0x46, 0x12, 0x21, 0xFF, 0xFF, + 0x02, 0xF0, 0x00, 0x00, 0x02, 0x25, 0x00, 0x00, 0x42, 0x27, 0xA4, 0x73, 0x90, 0x42, 0x8C, 0xA2, + 0x1A, 0x20, 0x00, 0x01, 0xDF, 0xE7, 0x2E, 0x07, 0xEB, 0xFB, 0x5A, 0x00, 0x01, 0x09, 0x84, 0x00, + 0x46, 0x17, 0xFF, 0xFF, 0x80, 0x40, 0x50, 0x10, 0x8F, 0xFF, 0xD5, 0x0E, 0x84, 0x00, 0x38, 0x22, + 0x01, 0x01, 0x38, 0x30, 0x81, 0x01, 0x88, 0x43, 0x90, 0x41, 0x38, 0x2F, 0x82, 0x0A, 0x8C, 0x01, + 0x5A, 0x08, 0x04, 0xF7, 0xD5, 0xED, 0x38, 0x3F, 0x82, 0x02, 0x97, 0x00, 0xE2, 0x61, 0x8C, 0x01, + 0x40, 0x22, 0x3C, 0x1B, 0x40, 0x11, 0xBC, 0x1B, 0x5A, 0x08, 0x04, 0xF7, 0xAE, 0xB0, 0xFC, 0xC2, + 0xFC, 0x44, 0xB1, 0xC4, 0x81, 0x41, 0x84, 0x48, 0x84, 0x20, 0x81, 0x20, 0xB1, 0x86, 0x80, 0x07, + 0x49, 0x00, 0x74, 0xBE, 0x84, 0x20, 0x84, 0x48, 0x80, 0x06, 0x49, 0x00, 0x74, 0xB9, 0x84, 0x00, + 0x3C, 0x08, 0x03, 0x03, 0x44, 0x00, 0x00, 0x90, 0x40, 0x00, 0x28, 0x16, 0x96, 0x40, 0xB6, 0x3F, + 0x94, 0x81, 0x85, 0x00, 0x4C, 0x85, 0x00, 0x0D, 0x80, 0x09, 0xB4, 0x3F, 0xF2, 0x81, 0x49, 0xFF, + 0xFA, 0x04, 0xF2, 0x01, 0x38, 0x03, 0x21, 0x09, 0x89, 0x22, 0x8D, 0x01, 0xD5, 0xF4, 0x49, 0x00, + 0x0E, 0xA3, 0x3C, 0x1D, 0xFF, 0xEB, 0x02, 0x20, 0x80, 0x0F, 0x5A, 0x00, 0x02, 0x05, 0x84, 0x03, + 0xFE, 0x84, 0x96, 0x91, 0x80, 0x62, 0x80, 0x27, 0x80, 0x06, 0x49, 0xFF, 0xFD, 0x06, 0x10, 0x0F, + 0x80, 0x0F, 0x80, 0x26, 0x50, 0x0F, 0x80, 0x0F, 0x80, 0x47, 0x49, 0xFF, 0xFF, 0x71, 0x2E, 0x07, + 0xEC, 0x55, 0x00, 0x1F, 0x80, 0x0F, 0x38, 0x23, 0x01, 0x01, 0x38, 0x33, 0x81, 0x01, 0x3C, 0x28, + 0x03, 0x03, 0x88, 0x62, 0x38, 0x23, 0x05, 0x01, 0x38, 0x13, 0x85, 0x01, 0x88, 0x41, 0xE0, 0x43, + 0xE8, 0x06, 0x9A, 0x9A, 0x5C, 0xF1, 0x00, 0xC8, 0xE8, 0x05, 0xD5, 0x02, 0x84, 0x40, 0x10, 0x0F, + 0x80, 0x0F, 0x94, 0x51, 0x44, 0x30, 0x01, 0xF4, 0x40, 0x10, 0x8C, 0x37, 0xE6, 0x23, 0xE8, 0x07, + 0xC9, 0x07, 0x44, 0x10, 0x00, 0xC7, 0x40, 0x10, 0x88, 0x06, 0xD5, 0x02, 0x84, 0x23, 0x00, 0x2F, + 0x80, 0x0F, 0x2E, 0x57, 0xFF, 0xA8, 0xDA, 0x04, 0x2E, 0x37, 0xFF, 0x9F, 0x88, 0x23, 0x3E, 0x17, + 0xFF, 0x9F, 0x2E, 0x17, 0xFF, 0x9F, 0xE6, 0x23, 0xE9, 0x05, 0x84, 0x00, 0x3E, 0x07, 0xFF, 0x9F, + 0x80, 0x02, 0x3E, 0x27, 0xFF, 0xA8, 0xFC, 0xC4, 0x44, 0x12, 0xC8, 0x5C, 0x38, 0x00, 0x80, 0x00, + 0x5A, 0x08, 0x01, 0x05, 0x2E, 0x07, 0xC7, 0xDD, 0xDD, 0x9E, 0x84, 0x01, 0xDD, 0x9E, 0x44, 0x22, + 0xC8, 0x48, 0x44, 0x12, 0xC8, 0x40, 0x84, 0x00, 0xAC, 0x10, 0xAC, 0x08, 0xAC, 0x11, 0xAC, 0x09, + 0xAC, 0x12, 0xAC, 0x0A, 0xAC, 0x13, 0xAC, 0x0B, 0xDD, 0x9E, 0x2E, 0x47, 0xEC, 0x66, 0xCC, 0x07, + 0x44, 0x00, 0x00, 0x32, 0x3C, 0x0B, 0xF6, 0x63, 0xAF, 0x08, 0xDD, 0x9E, 0x5A, 0x40, 0x03, 0x04, + 0xFA, 0xB8, 0xD5, 0x03, 0x44, 0x50, 0x01, 0x2C, 0x3C, 0x4D, 0xFF, 0xEB, 0x02, 0x42, 0x00, 0x0F, + 0xE2, 0x85, 0x40, 0x42, 0xBC, 0x1A, 0x97, 0x61, 0x3C, 0x4B, 0xF6, 0x63, 0x5A, 0x08, 0x01, 0x06, + 0x84, 0x01, 0xAE, 0x08, 0x84, 0x00, 0xD5, 0x07, 0xE2, 0xA3, 0xE9, 0xFB, 0xA4, 0x10, 0xE6, 0x1E, + 0xE8, 0x04, 0x8C, 0x01, 0xAC, 0x10, 0xDD, 0x9E, 0x84, 0x00, 0xAE, 0x08, 0xDD, 0x9E, 0xFC, 0x40, + 0x81, 0x41, 0x84, 0x20, 0x3C, 0x18, 0x03, 0x03, 0x10, 0xA1, 0x00, 0x00, 0x84, 0x24, 0x81, 0x23, + 0x80, 0xC2, 0x49, 0xFF, 0xFF, 0x37, 0x80, 0xE0, 0x44, 0x02, 0xC8, 0x5C, 0x3C, 0x30, 0x03, 0x03, + 0x38, 0x00, 0x28, 0x00, 0x5A, 0x08, 0x01, 0x14, 0x2E, 0x00, 0x06, 0x0A, 0xE6, 0x02, 0xE8, 0x04, + 0x8C, 0x01, 0x3E, 0x00, 0x06, 0x0A, 0x84, 0x01, 0x44, 0x12, 0xCE, 0xE5, 0x44, 0x22, 0xB5, 0x3A, + 0x49, 0xFF, 0xFF, 0xB5, 0x84, 0x00, 0x3C, 0x0B, 0xFF, 0xCD, 0xD5, 0x31, 0x84, 0x00, 0x44, 0x12, + 0xCE, 0xE5, 0x44, 0x22, 0xB5, 0x3A, 0x49, 0xFF, 0xFF, 0xAA, 0x2E, 0x00, 0x06, 0x0A, 0xC0, 0x04, + 0x8E, 0x01, 0x3E, 0x00, 0x06, 0x0A, 0x5A, 0x98, 0x01, 0x17, 0x2E, 0x10, 0x06, 0x2D, 0xC9, 0x13, + 0x80, 0x61, 0x44, 0x02, 0xC8, 0x58, 0x38, 0x20, 0x04, 0x00, 0x5A, 0x28, 0x01, 0x04, 0x8C, 0x61, + 0x96, 0xD9, 0x8C, 0x21, 0x5A, 0x18, 0x04, 0xF9, 0x5A, 0x38, 0x04, 0x06, 0x3C, 0x03, 0xFF, 0xCD, + 0x8C, 0x01, 0xD5, 0x02, 0x84, 0x00, 0x3C, 0x0B, 0xFF, 0xCD, 0x3C, 0x03, 0xFF, 0xCE, 0x44, 0x10, + 0xEA, 0x5F, 0xE2, 0x20, 0xE9, 0x04, 0x8C, 0x01, 0x3C, 0x0B, 0xFF, 0xCE, 0x84, 0x00, 0x3E, 0x00, + 0x06, 0x08, 0x2E, 0x00, 0x06, 0x0A, 0xC0, 0x05, 0x84, 0x01, 0x3E, 0x00, 0x06, 0x08, 0xAF, 0xF0, + 0xFC, 0xC0, 0xFC, 0x40, 0x2E, 0x37, 0xEC, 0x66, 0x2E, 0x07, 0xEC, 0x46, 0x2E, 0x17, 0xEC, 0x23, + 0x2E, 0x27, 0xEC, 0x13, 0x2E, 0x40, 0x0D, 0x13, 0xCB, 0x04, 0x80, 0xA0, 0x80, 0xC1, 0xD5, 0x05, + 0x80, 0xA2, 0x80, 0xC4, 0x80, 0x40, 0x80, 0x81, 0x3C, 0x7C, 0x02, 0xA4, 0xFF, 0x74, 0xFE, 0xA4, + 0x84, 0x60, 0x44, 0x92, 0x11, 0x70, 0x3C, 0x03, 0xE3, 0x76, 0xE2, 0x60, 0xE8, 0x1A, 0x94, 0x19, + 0x40, 0x10, 0x24, 0x00, 0x40, 0xA3, 0x80, 0x00, 0x02, 0x80, 0x80, 0x00, 0xA4, 0x48, 0x02, 0x05, + 0x00, 0x00, 0xFE, 0x64, 0x9A, 0x08, 0xFE, 0x2C, 0x42, 0x84, 0x18, 0x24, 0x40, 0x00, 0x08, 0x16, + 0x40, 0x04, 0x00, 0x01, 0x96, 0x01, 0x8C, 0x61, 0x12, 0x05, 0x00, 0x00, 0x96, 0xD9, 0xD5, 0xE4, + 0x3C, 0x0C, 0x02, 0xA4, 0x3C, 0x1C, 0x02, 0xA2, 0x49, 0x00, 0x3B, 0xC7, 0xFC, 0xC0, 0x44, 0x52, + 0x4A, 0x20, 0x44, 0x20, 0x03, 0xE8, 0x44, 0x32, 0x4A, 0xB0, 0x5A, 0x08, 0x05, 0x09, 0xA5, 0x28, + 0x02, 0x12, 0x80, 0x48, 0xFE, 0x64, 0x40, 0x10, 0x88, 0x37, 0xD5, 0x09, 0x5A, 0x08, 0x01, 0x0A, + 0xA4, 0x68, 0x02, 0x42, 0x80, 0x48, 0xFE, 0x54, 0x40, 0x10, 0x90, 0x37, 0x96, 0x49, 0xAC, 0x68, + 0x8C, 0xA2, 0xDB, 0xEC, 0xDD, 0x9E, 0xFC, 0x41, 0x80, 0xC0, 0x80, 0xA1, 0x81, 0x02, 0x81, 0x43, + 0x81, 0x24, 0x2E, 0x77, 0xEC, 0x66, 0x5A, 0x08, 0x01, 0x15, 0xC1, 0x24, 0x9E, 0x89, 0x2E, 0x57, + 0xEC, 0x55, 0x96, 0x90, 0xD2, 0x0A, 0x2E, 0x00, 0x06, 0x09, 0x5A, 0x08, 0x01, 0x07, 0x80, 0x02, + 0xF2, 0x81, 0x49, 0x00, 0x17, 0x91, 0xF2, 0x01, 0x84, 0x03, 0x3C, 0x1D, 0xFB, 0x4A, 0xD5, 0x0E, + 0x5A, 0x08, 0x02, 0x11, 0x5A, 0x78, 0x04, 0x07, 0x84, 0x01, 0xF1, 0x81, 0x49, 0xFF, 0xFF, 0xC1, + 0xF5, 0x01, 0x84, 0x00, 0x3C, 0x1D, 0xFB, 0x4A, 0x80, 0x45, 0x44, 0x32, 0xB5, 0x0D, 0x49, 0xFF, + 0xF7, 0x6D, 0x3C, 0x1D, 0xFB, 0x64, 0xA6, 0x08, 0x96, 0x00, 0x5A, 0x08, 0x01, 0xFE, 0x3C, 0x1D, + 0xFB, 0x59, 0xAE, 0x08, 0x49, 0x00, 0x3F, 0x4D, 0x3C, 0x1D, 0xFB, 0x64, 0xA6, 0x08, 0x96, 0x00, + 0x5A, 0x08, 0x01, 0xFE, 0x3C, 0x1D, 0xFB, 0x59, 0xAE, 0x08, 0x2E, 0x07, 0xEC, 0x66, 0x49, 0x00, + 0x3B, 0x9F, 0x2E, 0x07, 0xEC, 0x66, 0xC8, 0x04, 0x5A, 0x78, 0x04, 0x08, 0xD5, 0x04, 0x5A, 0x08, + 0x04, 0x05, 0xCF, 0x03, 0x49, 0xFF, 0xFF, 0x57, 0x5A, 0x68, 0x01, 0x0A, 0x84, 0x00, 0x10, 0x64, + 0x00, 0x00, 0x10, 0x65, 0x00, 0x00, 0x10, 0x04, 0x80, 0x00, 0xD5, 0x0E, 0x5A, 0x68, 0x02, 0x0D, + 0x84, 0x00, 0x10, 0x04, 0x00, 0x00, 0x10, 0x05, 0x00, 0x00, 0x84, 0x01, 0x10, 0x04, 0x80, 0x00, + 0x84, 0x03, 0x3E, 0x07, 0xEC, 0x2B, 0xFC, 0xC1, 0xDD, 0x9E, 0xFC, 0x40, 0x2E, 0x20, 0x05, 0xEA, + 0xC2, 0x0C, 0x2E, 0x20, 0x05, 0xE9, 0x54, 0x31, 0x00, 0xFD, 0x5A, 0x30, 0x01, 0x05, 0x5A, 0x28, + 0x02, 0x05, 0xD5, 0x04, 0x84, 0x44, 0xD5, 0x02, 0x84, 0x41, 0x2E, 0x50, 0x06, 0x2D, 0x2E, 0x67, + 0xEC, 0x2F, 0x2E, 0x77, 0xEB, 0xFA, 0x2E, 0x90, 0x06, 0x08, 0x50, 0x10, 0x80, 0xDC, 0x84, 0x80, + 0x44, 0xA2, 0xCE, 0xA4, 0x5A, 0x50, 0x01, 0x08, 0x5A, 0x60, 0x01, 0x06, 0x5A, 0x70, 0x01, 0x04, + 0x5A, 0x98, 0x01, 0x09, 0x38, 0x85, 0x10, 0x00, 0xA0, 0xC5, 0x5A, 0x88, 0x01, 0x05, 0xFE, 0xD4, + 0xD5, 0x02, 0xA0, 0xC3, 0x8C, 0x81, 0xB6, 0x61, 0x50, 0x10, 0x80, 0xE0, 0x5A, 0x48, 0x0A, 0xEC, + 0xFC, 0xC0, 0xFC, 0x00, 0x2E, 0x17, 0xEC, 0x41, 0xC9, 0x04, 0x44, 0x00, 0x05, 0xAA, 0xD5, 0x46, + 0x2E, 0x07, 0xEC, 0x1E, 0x5A, 0x00, 0x01, 0xFB, 0x2E, 0x07, 0xEC, 0x66, 0x5A, 0x00, 0x01, 0xF7, + 0x84, 0x00, 0x3C, 0x4C, 0x02, 0x11, 0x3C, 0x5C, 0x02, 0x18, 0x80, 0x40, 0x96, 0xC0, 0xE2, 0x61, + 0xE8, 0x0B, 0x38, 0x62, 0x01, 0x01, 0x96, 0xC1, 0x4C, 0x61, 0xC0, 0x05, 0x38, 0x32, 0x82, 0x02, + 0x88, 0x43, 0x8C, 0x01, 0xD5, 0xF4, 0x2E, 0x07, 0xEB, 0xF9, 0xC0, 0x05, 0x2E, 0x00, 0x05, 0xE9, + 0x5A, 0x08, 0x03, 0x05, 0x3C, 0x2F, 0xFB, 0x33, 0xD5, 0x07, 0x3C, 0x0D, 0xFB, 0x33, 0x88, 0x02, + 0x92, 0x01, 0x3C, 0x0F, 0xFB, 0x33, 0x3C, 0x2D, 0xFB, 0x33, 0x5C, 0xF1, 0x2C, 0xEC, 0xE8, 0x14, + 0x5C, 0xF1, 0x04, 0xE3, 0xE9, 0xCB, 0x46, 0x0F, 0xFC, 0xA9, 0x50, 0x00, 0x08, 0x20, 0x44, 0x30, + 0x0A, 0xF0, 0x42, 0x01, 0x0C, 0x73, 0x44, 0x20, 0x28, 0x0A, 0x40, 0x00, 0x08, 0x17, 0x50, 0x00, + 0x05, 0xAA, 0x96, 0x01, 0xD5, 0x03, 0x44, 0x00, 0x10, 0x9A, 0x3C, 0x43, 0xF4, 0xE8, 0xE2, 0x04, + 0xE8, 0x1A, 0x2E, 0x27, 0xEC, 0x1E, 0x5A, 0x20, 0x01, 0x17, 0x2E, 0x27, 0xEC, 0x66, 0x5A, 0x20, + 0x01, 0x13, 0x2E, 0x37, 0xEB, 0xF8, 0x3C, 0x23, 0xF6, 0x43, 0xE6, 0x63, 0xE8, 0x09, 0x88, 0x02, + 0x8C, 0x61, 0x3C, 0x0B, 0xF6, 0x43, 0x3E, 0x37, 0xEB, 0xF8, 0x80, 0x04, 0xD5, 0x0A, 0x84, 0x03, + 0x40, 0x01, 0x00, 0x17, 0x84, 0x40, 0x3E, 0x27, 0xEB, 0xF8, 0x84, 0x40, 0x3C, 0x2B, 0xF6, 0x43, + 0x3C, 0x0B, 0xF4, 0xE8, 0x3E, 0x17, 0xEB, 0xF9, 0xFC, 0x80, 0xFC, 0x00, 0x84, 0x60, 0x80, 0xA0, + 0x80, 0x03, 0x97, 0x18, 0xE2, 0x82, 0xE8, 0x09, 0x38, 0x42, 0x8D, 0x01, 0x38, 0x60, 0x8D, 0x01, + 0x8C, 0x61, 0x8A, 0x86, 0x88, 0x04, 0xD5, 0xF6, 0xFC, 0x80, 0xFC, 0x40, 0xEE, 0xD0, 0xF0, 0x81, + 0x84, 0x00, 0x3C, 0x08, 0x03, 0x03, 0xB0, 0x68, 0xB0, 0x04, 0x44, 0x22, 0x4A, 0x20, 0x44, 0x30, + 0x00, 0x48, 0x49, 0xFF, 0xF7, 0x3B, 0x44, 0x62, 0x5F, 0x60, 0x44, 0x72, 0x61, 0x10, 0x80, 0x06, + 0xB0, 0x44, 0xB0, 0xA8, 0x44, 0x30, 0x00, 0x48, 0x49, 0xFF, 0xF7, 0x40, 0x50, 0x63, 0x00, 0x90, + 0x3C, 0x08, 0x03, 0x03, 0x4C, 0x63, 0xFF, 0xF5, 0x44, 0x30, 0x00, 0x48, 0xB0, 0x44, 0xB0, 0xA8, + 0xF0, 0x01, 0x49, 0xFF, 0xF7, 0x33, 0x3C, 0x08, 0x03, 0x03, 0x49, 0xFF, 0xFF, 0x54, 0xB0, 0x68, + 0x44, 0x20, 0x00, 0x48, 0xB0, 0x04, 0x49, 0xFF, 0xFF, 0xC2, 0x80, 0xE0, 0x84, 0x00, 0x12, 0x0F, + 0x80, 0x07, 0xB0, 0x44, 0x50, 0x0F, 0x80, 0x0E, 0x44, 0x20, 0x00, 0x48, 0x84, 0x61, 0x49, 0x00, + 0x3A, 0xD5, 0x84, 0x1F, 0x12, 0x0F, 0x80, 0x07, 0xB0, 0x68, 0x50, 0x0F, 0x80, 0x0E, 0x44, 0x20, + 0x00, 0x48, 0x84, 0x61, 0x49, 0x00, 0x3A, 0xCA, 0xB0, 0x44, 0xB0, 0xA8, 0x44, 0x30, 0x00, 0x48, + 0x44, 0x02, 0x5F, 0x60, 0x49, 0xFF, 0xF7, 0x0A, 0xB0, 0x44, 0xB0, 0xA8, 0x44, 0x30, 0x00, 0x48, + 0x44, 0x02, 0x5F, 0xF0, 0x49, 0xFF, 0xF7, 0x02, 0xB0, 0x44, 0xB0, 0xA8, 0x44, 0x30, 0x00, 0x48, + 0x44, 0x02, 0x60, 0x80, 0x49, 0xFF, 0xF6, 0xFA, 0xB0, 0x44, 0xB0, 0xA8, 0x44, 0x30, 0x00, 0x48, + 0xF0, 0x01, 0x49, 0xFF, 0xF6, 0xF3, 0x81, 0x20, 0x44, 0x12, 0x4A, 0x20, 0xF0, 0x01, 0x49, 0xFF, + 0xF6, 0x76, 0x2E, 0x07, 0xEC, 0x66, 0x5A, 0x08, 0x04, 0x16, 0x3C, 0x13, 0xF6, 0x44, 0x5C, 0xF0, + 0x80, 0x97, 0xE9, 0x0B, 0x9F, 0x89, 0x44, 0x0F, 0xFF, 0xCE, 0x50, 0x10, 0xFF, 0x6A, 0x40, 0x10, + 0x80, 0x36, 0x88, 0xC1, 0x97, 0xB1, 0xD5, 0x03, 0x44, 0x60, 0x00, 0x96, 0x3C, 0x6B, 0xF6, 0x44, + 0xD5, 0x03, 0x3C, 0x63, 0xF4, 0xE8, 0x49, 0x00, 0x0B, 0xA7, 0x5A, 0x00, 0x02, 0x08, 0x84, 0x03, + 0xFF, 0x84, 0x97, 0xB1, 0x44, 0x00, 0xFF, 0xFF, 0xD5, 0x05, 0x3C, 0x0D, 0xFF, 0xEB, 0x00, 0x00, + 0x00, 0x2A, 0xE2, 0xC7, 0x3C, 0x98, 0x03, 0x02, 0xE8, 0x03, 0x84, 0x02, 0xD5, 0x0B, 0x3C, 0x13, + 0xF6, 0x57, 0xE2, 0x01, 0x2E, 0x00, 0x06, 0x0A, 0xE8, 0x03, 0x8C, 0x01, 0xD5, 0x03, 0xC0, 0x04, + 0x8E, 0x01, 0x3E, 0x00, 0x06, 0x0A, 0x2E, 0x00, 0x06, 0x0A, 0xE6, 0x02, 0x84, 0x01, 0xE8, 0x02, + 0x84, 0x00, 0x3E, 0x00, 0x06, 0x08, 0xED, 0x30, 0xFC, 0xC0, 0xFC, 0x00, 0x80, 0xC0, 0xC8, 0x24, + 0x44, 0x02, 0x0A, 0x20, 0x44, 0x12, 0x5F, 0x60, 0x44, 0x20, 0x00, 0x48, 0x49, 0x00, 0x39, 0xB2, + 0x44, 0x02, 0x0A, 0x20, 0x44, 0x12, 0x5F, 0xF0, 0x44, 0x20, 0x00, 0x48, 0x49, 0x00, 0x39, 0xAA, + 0x44, 0x02, 0x0A, 0x20, 0x44, 0x12, 0x60, 0x80, 0x44, 0x20, 0x00, 0x48, 0x49, 0x00, 0x39, 0xA2, + 0x44, 0x02, 0x0A, 0x20, 0x44, 0x12, 0x4A, 0x20, 0x44, 0x20, 0x00, 0x48, 0x49, 0x00, 0x39, 0x9A, + 0x3E, 0x60, 0x06, 0x08, 0xD5, 0x11, 0x49, 0xFF, 0xF6, 0x24, 0x44, 0x02, 0x0A, 0x20, 0x84, 0x20, + 0x49, 0xFF, 0xFF, 0x25, 0x44, 0x02, 0x0A, 0x20, 0x44, 0x12, 0x4A, 0x20, 0x44, 0x20, 0x00, 0x48, + 0x84, 0x60, 0x49, 0xFF, 0xF7, 0x1D, 0x2E, 0x07, 0xEC, 0x54, 0xC8, 0x03, 0x3E, 0x00, 0x06, 0x08, + 0x2E, 0x00, 0x06, 0x08, 0xFC, 0x80, 0xFC, 0x40, 0x51, 0xFF, 0xFD, 0xB0, 0xB6, 0x1F, 0xF1, 0x81, + 0xB0, 0x04, 0x44, 0x12, 0x4A, 0x20, 0x81, 0x22, 0x80, 0xE3, 0x84, 0x40, 0x44, 0x30, 0x00, 0x90, + 0xF4, 0x82, 0x49, 0xFF, 0xFA, 0x32, 0x44, 0x20, 0xFF, 0xFF, 0x44, 0x30, 0x00, 0x90, 0x50, 0x0F, + 0x81, 0x30, 0x44, 0x12, 0x4A, 0x20, 0x49, 0xFF, 0xFA, 0x28, 0x3C, 0x0D, 0xFB, 0x59, 0x84, 0x21, + 0x84, 0xC0, 0xAE, 0x40, 0x84, 0x01, 0x3C, 0x6F, 0xFB, 0x88, 0x44, 0xA3, 0xF0, 0x4A, 0x49, 0x00, + 0x0D, 0x34, 0x44, 0x80, 0x00, 0x55, 0x49, 0xFF, 0xF7, 0x1C, 0xB4, 0x1F, 0x4C, 0x60, 0x00, 0x50, + 0x84, 0x00, 0x3E, 0x07, 0xEC, 0x6A, 0x84, 0x00, 0x3C, 0x0F, 0xFB, 0x8A, 0xF0, 0x83, 0x49, 0x00, + 0x3D, 0x40, 0x10, 0x85, 0x00, 0x00, 0x2E, 0x07, 0xEC, 0x6A, 0xF1, 0x01, 0xE2, 0x01, 0xE8, 0x34, + 0x2E, 0x17, 0xEC, 0x6A, 0x3C, 0x0D, 0xFB, 0x8A, 0xE2, 0x20, 0xE8, 0xF6, 0xF0, 0x03, 0x3C, 0x0F, + 0xFB, 0x88, 0x5A, 0x98, 0x02, 0x0C, 0x2E, 0x07, 0xEC, 0x6A, 0x80, 0x27, 0xF2, 0x02, 0xB0, 0xC4, + 0x50, 0x4F, 0x81, 0x30, 0x49, 0xFF, 0xF6, 0x65, 0xD5, 0x18, 0x5A, 0x98, 0x01, 0x17, 0x2E, 0x00, + 0x0C, 0xF5, 0x2E, 0x57, 0xEC, 0x6A, 0x40, 0x12, 0x80, 0xB7, 0x2E, 0x10, 0x0D, 0x06, 0x97, 0x68, + 0x40, 0x10, 0x80, 0x17, 0x96, 0x00, 0xD8, 0x09, 0x2E, 0x07, 0xEC, 0x6A, 0x80, 0x27, 0xB0, 0x84, + 0x50, 0x3F, 0x81, 0x30, 0x49, 0xFF, 0xF6, 0x20, 0x2E, 0x07, 0xEC, 0x6A, 0x8C, 0x01, 0x96, 0x00, + 0x3E, 0x07, 0xEC, 0x6A, 0xD5, 0xC9, 0x3C, 0x0D, 0xFB, 0x59, 0x84, 0x21, 0x8C, 0xC1, 0xAE, 0x40, + 0x44, 0x0F, 0xFF, 0xAA, 0x3E, 0x07, 0xEC, 0x2A, 0x97, 0xB0, 0xD5, 0xB0, 0x49, 0xFF, 0xF9, 0xCD, + 0x5A, 0x98, 0x01, 0x0C, 0x49, 0xFF, 0xFE, 0x0F, 0xB0, 0x04, 0x50, 0x1F, 0x81, 0x30, 0x44, 0x20, + 0x00, 0x48, 0x49, 0xFF, 0xFE, 0x7C, 0xAC, 0x38, 0x51, 0xFF, 0x82, 0x50, 0xFC, 0xC0, 0xFC, 0x03, + 0x84, 0x20, 0x84, 0x48, 0xB0, 0x02, 0x49, 0x00, 0x70, 0xAB, 0x84, 0x20, 0x84, 0x48, 0xB0, 0x04, + 0x49, 0x00, 0x70, 0xA6, 0x84, 0x02, 0x49, 0xFF, 0xFA, 0x00, 0xB0, 0xC2, 0xB1, 0x04, 0x84, 0x01, + 0x84, 0x26, 0x84, 0x42, 0x49, 0xFF, 0xFF, 0x61, 0xB0, 0x44, 0x84, 0x44, 0x84, 0x02, 0x49, 0x00, + 0x35, 0x85, 0x49, 0x00, 0x0A, 0x99, 0x3C, 0x1D, 0xFF, 0xEB, 0x02, 0x20, 0x80, 0x0F, 0x5A, 0x00, + 0x02, 0x05, 0x84, 0x03, 0xFE, 0x84, 0x96, 0x91, 0xB0, 0x42, 0x80, 0x62, 0xB0, 0x04, 0x49, 0xFF, + 0xF8, 0xFC, 0xF0, 0x81, 0x49, 0xFF, 0xFC, 0x45, 0x84, 0x02, 0x49, 0xFF, 0xF8, 0x9E, 0x49, 0xFF, + 0xF9, 0x8C, 0x2E, 0x00, 0x0D, 0x06, 0x49, 0x00, 0x10, 0xCD, 0xC8, 0x03, 0x49, 0x00, 0x0F, 0xF4, + 0xF0, 0x01, 0xFC, 0x83, 0xFC, 0x01, 0x80, 0xC0, 0x84, 0x01, 0x49, 0xFF, 0xF9, 0xCE, 0x84, 0x01, + 0x84, 0x26, 0x80, 0x40, 0xB0, 0xC1, 0x40, 0x4F, 0x84, 0x00, 0x49, 0xFF, 0xFF, 0x2E, 0x5A, 0x68, + 0x01, 0x05, 0x80, 0x06, 0x49, 0xFF, 0xF8, 0x81, 0x49, 0xFF, 0xF9, 0x6F, 0x84, 0x01, 0x3E, 0x07, + 0xEB, 0xFA, 0x02, 0x0F, 0x80, 0x02, 0x49, 0xFF, 0xF6, 0x7F, 0xFC, 0x81, 0xFC, 0x21, 0x49, 0xFF, + 0xF7, 0x8A, 0x2E, 0x00, 0x05, 0xEA, 0xC0, 0x05, 0x8E, 0x01, 0x3E, 0x00, 0x05, 0xEA, 0xD5, 0x03, + 0x3E, 0x00, 0x05, 0xE9, 0x2E, 0x67, 0xEC, 0x66, 0x54, 0x63, 0x00, 0xFB, 0xCE, 0x54, 0x3C, 0x0C, + 0x02, 0xA6, 0x80, 0x26, 0x49, 0xFF, 0xFE, 0x1B, 0x2E, 0x07, 0xEC, 0x66, 0x44, 0x12, 0xCE, 0xBE, + 0x84, 0x41, 0x49, 0x00, 0x35, 0x2B, 0x80, 0x06, 0x44, 0x12, 0xCE, 0xE5, 0x44, 0x22, 0xB5, 0x3A, + 0x3C, 0x30, 0x03, 0x03, 0x49, 0xFF, 0xFC, 0x03, 0x3C, 0x0C, 0x02, 0xA6, 0x44, 0x12, 0x4A, 0x20, + 0x44, 0x20, 0x00, 0x48, 0x80, 0x66, 0x49, 0xFF, 0xF6, 0x03, 0x2E, 0x07, 0xEC, 0x54, 0x5A, 0x00, + 0x01, 0x04, 0x48, 0x00, 0x00, 0xBE, 0x2E, 0x70, 0x06, 0x08, 0x5A, 0x70, 0x01, 0x04, 0x48, 0x00, + 0x00, 0xB8, 0x44, 0x00, 0x00, 0x43, 0x3E, 0x60, 0x06, 0x2E, 0x49, 0x00, 0x35, 0xAB, 0x49, 0xFF, + 0xFF, 0x68, 0x80, 0x40, 0x10, 0x0F, 0x80, 0x07, 0x3C, 0x1D, 0xFB, 0x4A, 0x84, 0x03, 0x44, 0x32, + 0xB5, 0x0D, 0x49, 0xFF, 0xF4, 0x5B, 0x80, 0x07, 0x44, 0x12, 0xCE, 0xE5, 0x44, 0x22, 0xB5, 0x3A, + 0x3C, 0x30, 0x03, 0x03, 0x3E, 0x70, 0x05, 0xEA, 0x3E, 0x70, 0x05, 0xE9, 0x49, 0xFF, 0xFB, 0xCF, + 0x3E, 0x67, 0xEC, 0x4C, 0x49, 0xFF, 0xF9, 0x36, 0x49, 0xFF, 0xF6, 0x03, 0x3E, 0x70, 0x06, 0x2E, + 0x48, 0x00, 0x00, 0x8F, 0x2E, 0x00, 0x06, 0x09, 0x5A, 0x08, 0x01, 0x07, 0x44, 0x00, 0x00, 0x31, + 0x3C, 0x3C, 0x01, 0x88, 0xD5, 0x05, 0x84, 0x60, 0xC8, 0x05, 0x2E, 0x37, 0xEC, 0x41, 0x40, 0x30, + 0x0C, 0x06, 0x3C, 0x0C, 0x02, 0xA6, 0x2E, 0x17, 0xEC, 0x55, 0x50, 0x2F, 0x80, 0x07, 0x49, 0xFF, + 0xFB, 0xD8, 0x2E, 0x07, 0xEC, 0x54, 0x5A, 0x08, 0x01, 0x74, 0x2E, 0x00, 0x06, 0x08, 0x5A, 0x08, + 0x01, 0x25, 0x2E, 0x67, 0xEC, 0x35, 0x5A, 0x68, 0x01, 0x21, 0x2E, 0x57, 0xEC, 0x55, 0x00, 0x0F, + 0x80, 0x07, 0xD0, 0x66, 0x84, 0x02, 0x84, 0xE0, 0x3E, 0x00, 0x05, 0xE9, 0x3E, 0x70, 0x06, 0x2E, + 0x3E, 0x60, 0x05, 0xEA, 0x49, 0xFF, 0xF8, 0xD1, 0x84, 0x03, 0x3C, 0x1D, 0xFB, 0x4A, 0x00, 0x2F, + 0x80, 0x07, 0x44, 0x32, 0xB5, 0x0D, 0x49, 0xFF, 0xF4, 0x09, 0x3E, 0x77, 0xEC, 0x4C, 0x49, 0xFF, + 0xF8, 0xF1, 0x3E, 0x60, 0x06, 0x2E, 0xD5, 0x4C, 0x3C, 0x03, 0xFF, 0xCD, 0xE6, 0x14, 0xE9, 0x48, + 0x44, 0x00, 0x00, 0x42, 0x49, 0x00, 0x35, 0x3E, 0x84, 0xE0, 0x84, 0x03, 0x84, 0xC1, 0x3E, 0x00, + 0x05, 0xE9, 0x3C, 0x7B, 0xFF, 0xCD, 0x3E, 0x60, 0x05, 0xEA, 0x49, 0xFF, 0xF8, 0xAE, 0x2E, 0x07, + 0xEC, 0x66, 0x49, 0x00, 0x38, 0x35, 0x84, 0x01, 0x49, 0xFF, 0xFF, 0x26, 0xC8, 0x28, 0x2E, 0x20, + 0x06, 0x09, 0xCA, 0x14, 0x3C, 0x1D, 0xFB, 0x4A, 0x44, 0x32, 0xB5, 0x0D, 0x49, 0xFF, 0xF3, 0xDE, + 0x44, 0x00, 0x00, 0x48, 0x3E, 0x77, 0xEC, 0x4C, 0x49, 0x00, 0x35, 0x1C, 0x49, 0x00, 0x01, 0x18, + 0x49, 0xFF, 0xF8, 0xC0, 0x49, 0xFF, 0xF5, 0x8D, 0xD5, 0x1B, 0x84, 0x03, 0x3C, 0x1D, 0xFB, 0x4A, + 0x2E, 0x27, 0xEC, 0x55, 0x44, 0x32, 0xB5, 0x0D, 0x49, 0xFF, 0xF3, 0xC8, 0x3C, 0x0C, 0x01, 0x88, + 0x5C, 0xF0, 0x00, 0x33, 0xE9, 0x0D, 0x3E, 0x67, 0xEC, 0x59, 0xD5, 0x0A, 0x84, 0x03, 0x3C, 0x1D, + 0xFB, 0x4A, 0x2E, 0x27, 0xEC, 0x55, 0x44, 0x32, 0xB5, 0x0D, 0x49, 0xFF, 0xF3, 0xB7, 0x3C, 0x1D, + 0xFF, 0xEB, 0x2E, 0x07, 0xEC, 0x66, 0x00, 0x10, 0x80, 0x2E, 0x3E, 0x07, 0xEC, 0x4F, 0xC1, 0x0B, + 0x3C, 0x20, 0x03, 0x03, 0x44, 0x12, 0x2D, 0x54, 0xAC, 0x88, 0x3C, 0x23, 0xF6, 0x5C, 0x44, 0x12, + 0x2D, 0x56, 0xAC, 0x88, 0xC8, 0x04, 0x2E, 0x07, 0xEC, 0x4C, 0xC8, 0x08, 0x3C, 0x0D, 0xFB, 0x4D, + 0xA4, 0x00, 0x92, 0x02, 0x96, 0x06, 0x5A, 0x00, 0x01, 0x03, 0x84, 0x00, 0x3E, 0x07, 0xEC, 0x2F, + 0xFC, 0xA1, 0xFC, 0x00, 0x2E, 0x00, 0x0D, 0x06, 0x3C, 0x1D, 0xFB, 0x8A, 0x8C, 0x01, 0xE2, 0x20, + 0xE8, 0x04, 0x49, 0xFF, 0xEF, 0xD5, 0xC0, 0x0C, 0x84, 0x00, 0x3C, 0x0B, 0xF6, 0x56, 0x49, 0xFF, + 0xEF, 0xD5, 0xC8, 0x17, 0x49, 0xFF, 0xF4, 0x05, 0x49, 0xFF, 0xFE, 0xDA, 0xD5, 0x12, 0x2E, 0x07, + 0xEC, 0x29, 0x5A, 0x08, 0x01, 0x06, 0x44, 0x02, 0xB5, 0x64, 0x49, 0x00, 0x36, 0x28, 0x84, 0x40, + 0x84, 0x01, 0x84, 0x2A, 0x80, 0x62, 0x80, 0x80, 0x80, 0xA2, 0x49, 0x00, 0x35, 0xAD, 0xD5, 0xDB, + 0xFC, 0x80, 0x3A, 0x6F, 0x9E, 0xBC, 0xEF, 0xF8, 0x80, 0xC0, 0x44, 0x0F, 0xFF, 0xAA, 0x3E, 0x07, + 0xEC, 0x6D, 0x2E, 0x07, 0xEC, 0x71, 0xB6, 0x5F, 0xF3, 0x81, 0x5A, 0x08, 0x01, 0x08, 0x80, 0x22, + 0x44, 0x02, 0xB5, 0x29, 0x80, 0x43, 0x49, 0x00, 0x5F, 0xCC, 0x3C, 0x1D, 0xFB, 0x4A, 0x44, 0x22, + 0xB4, 0xE1, 0xB4, 0x7F, 0xF4, 0x01, 0x44, 0x02, 0xB5, 0xF0, 0x49, 0x00, 0x64, 0x33, 0x96, 0x00, + 0x3E, 0x07, 0xEC, 0x5F, 0x49, 0x00, 0x60, 0x7A, 0x2E, 0x07, 0xEC, 0x5F, 0x5A, 0x00, 0x01, 0x05, + 0x84, 0x01, 0x3C, 0x0F, 0xFB, 0x6D, 0xA6, 0x31, 0x5A, 0x08, 0x07, 0x10, 0xA6, 0x30, 0x5A, 0x08, + 0x02, 0x62, 0x3C, 0x0D, 0xFB, 0x5C, 0x5A, 0x00, 0x06, 0x5C, 0x5A, 0x08, 0x09, 0x6A, 0x49, 0x00, + 0x08, 0xEB, 0x5A, 0x08, 0x02, 0x66, 0xD5, 0x54, 0x5A, 0x08, 0x08, 0x0B, 0xA6, 0x30, 0x5A, 0x08, + 0x02, 0x52, 0x3C, 0x0D, 0xFB, 0x5C, 0x8E, 0x06, 0xE6, 0x02, 0xE8, 0x5A, 0xD5, 0x49, 0x5A, 0x08, + 0x09, 0x07, 0xA6, 0x30, 0x8E, 0x02, 0xE6, 0x02, 0xE8, 0x45, 0xD5, 0x42, 0x5A, 0x08, 0x03, 0x0D, + 0xA7, 0xB0, 0x5A, 0x68, 0x01, 0x40, 0x80, 0x06, 0x49, 0x00, 0x0A, 0xF8, 0x80, 0x06, 0x49, 0x00, + 0x0A, 0xE4, 0x84, 0x08, 0xD5, 0x50, 0x54, 0x00, 0x00, 0xFD, 0x5A, 0x08, 0x04, 0x34, 0xA7, 0xF0, + 0x5A, 0x78, 0x01, 0x31, 0x80, 0x07, 0x49, 0x00, 0x0A, 0xE9, 0x80, 0x07, 0x49, 0x00, 0x0A, 0xD5, + 0x49, 0x00, 0x0E, 0x1C, 0x3E, 0x07, 0xEC, 0x3D, 0x49, 0x00, 0x08, 0x8A, 0x2E, 0x57, 0xEC, 0x53, + 0x84, 0x20, 0x3E, 0x07, 0xEC, 0x0D, 0x3E, 0x17, 0xEC, 0x1D, 0xD0, 0x03, 0x3E, 0x77, 0xEC, 0x1D, + 0xA7, 0xB1, 0x3E, 0x07, 0xEC, 0x53, 0x5A, 0x68, 0x06, 0x14, 0x84, 0x00, 0x3E, 0x07, 0xEC, 0x33, + 0x3C, 0x0D, 0xFB, 0x4A, 0x49, 0xFF, 0xF1, 0x9B, 0x2E, 0x07, 0xEC, 0x66, 0x80, 0x26, 0x49, 0xFF, + 0xF1, 0xE9, 0x84, 0x01, 0x3E, 0x07, 0xEC, 0x77, 0x84, 0x00, 0x3C, 0x0B, 0xF6, 0x4E, 0x84, 0x08, + 0xD5, 0x1A, 0x49, 0x00, 0x08, 0x91, 0x5A, 0x00, 0x02, 0x16, 0x84, 0x61, 0x84, 0x20, 0x84, 0x02, + 0x80, 0x41, 0x80, 0x83, 0x80, 0xA3, 0x49, 0x00, 0x35, 0x0F, 0x84, 0x01, 0xD5, 0x0C, 0x84, 0x40, + 0x84, 0x61, 0x84, 0x02, 0xFA, 0x25, 0x80, 0x83, 0x80, 0xA2, 0x49, 0x00, 0x35, 0x05, 0x84, 0x08, + 0xD5, 0x02, 0x84, 0x01, 0xEC, 0x08, 0x3A, 0x6F, 0x9E, 0x84, 0xDD, 0x9E, 0x3B, 0xFF, 0xFC, 0xBC, + 0xEF, 0xFC, 0x49, 0x00, 0x08, 0x71, 0x5A, 0x08, 0x02, 0x12, 0x44, 0x03, 0xF0, 0x4A, 0x44, 0x10, + 0x00, 0x55, 0xAE, 0x40, 0x3C, 0x2D, 0xFB, 0x85, 0xCA, 0x09, 0x84, 0x01, 0x80, 0x20, 0x80, 0x62, + 0x80, 0x80, 0x80, 0xA2, 0x49, 0x00, 0x34, 0xE8, 0xD5, 0xF6, 0xEC, 0x04, 0x3B, 0xFF, 0xFC, 0x84, + 0xDD, 0x9E, 0x3B, 0xFF, 0xFC, 0xBC, 0x84, 0x01, 0xEF, 0xFC, 0x49, 0xFF, 0xEF, 0x03, 0x44, 0x03, + 0xF0, 0x4A, 0x44, 0x10, 0x00, 0x55, 0xAE, 0x40, 0x44, 0x13, 0xF4, 0x03, 0xA6, 0x08, 0x5A, 0x00, + 0x01, 0xFF, 0xEC, 0x04, 0x3B, 0xFF, 0xFC, 0x84, 0xDD, 0x9E, 0x3A, 0x6F, 0xA8, 0xBC, 0xC0, 0x03, + 0x49, 0x00, 0x1F, 0xE6, 0x44, 0x60, 0x03, 0xE9, 0x44, 0x73, 0xF0, 0x4A, 0x44, 0x90, 0x00, 0x55, + 0x49, 0x00, 0x08, 0x3A, 0xC0, 0x12, 0x8E, 0xC1, 0xC6, 0x10, 0x84, 0x21, 0x80, 0x41, 0x80, 0x61, + 0x84, 0x80, 0x44, 0x00, 0x4F, 0x00, 0x49, 0x00, 0x43, 0x64, 0x44, 0x00, 0x00, 0x64, 0x49, 0x00, + 0x1F, 0x95, 0x10, 0x93, 0x80, 0x00, 0xD5, 0xED, 0x84, 0x00, 0x49, 0x00, 0x07, 0xC0, 0x44, 0x63, + 0xF0, 0x4A, 0x44, 0x70, 0x00, 0x55, 0x49, 0x00, 0x08, 0x1F, 0xC0, 0x03, 0xAF, 0xF0, 0xD5, 0xFC, + 0x3A, 0x6F, 0xA8, 0x84, 0xDD, 0x9E, 0x44, 0x03, 0xF0, 0x4A, 0x44, 0x10, 0x00, 0x55, 0xAE, 0x40, + 0x44, 0x13, 0xF4, 0x03, 0xA6, 0x08, 0x5A, 0x00, 0x01, 0xFF, 0xDD, 0x9E, 0x3A, 0x6F, 0xA8, 0xBC, + 0x81, 0x20, 0x80, 0xE2, 0x49, 0x00, 0x33, 0xF9, 0x80, 0xC0, 0x49, 0xFF, 0xFF, 0xEE, 0x50, 0x04, + 0xFF, 0xFF, 0xE6, 0x0F, 0x4E, 0xF2, 0x01, 0xBF, 0x44, 0xF0, 0x55, 0x28, 0x38, 0x07, 0x81, 0x01, + 0x40, 0xF0, 0x3C, 0x00, 0x4A, 0x00, 0x3C, 0x00, 0x1E, 0x00, 0x72, 0x00, 0xB2, 0x00, 0xFA, 0x01, + 0x24, 0x02, 0x6A, 0x03, 0x6A, 0x03, 0x6A, 0x03, 0x6A, 0x03, 0xC6, 0x02, 0xFE, 0x02, 0x50, 0x03, + 0x6A, 0x03, 0x6A, 0x03, 0x70, 0x03, 0x44, 0x00, 0x00, 0x30, 0x49, 0x00, 0x33, 0x73, 0x84, 0x0D, + 0xAE, 0x39, 0x84, 0x05, 0xAE, 0x38, 0x84, 0x00, 0x10, 0x03, 0x00, 0x50, 0x44, 0x90, 0x00, 0x55, + 0x44, 0x63, 0xF0, 0x4A, 0x49, 0x00, 0x07, 0xD8, 0x5A, 0x08, 0x02, 0x05, 0x10, 0x93, 0x00, 0x00, + 0xD5, 0xFA, 0x44, 0x03, 0xF0, 0x10, 0x84, 0x20, 0xAE, 0x40, 0x49, 0x00, 0x07, 0xCD, 0xC0, 0x20, + 0x84, 0x21, 0x80, 0x41, 0x80, 0x61, 0x80, 0x81, 0x44, 0x00, 0x5A, 0xF0, 0x49, 0x00, 0x42, 0xF9, + 0x44, 0x00, 0x00, 0x8C, 0x49, 0xFF, 0xFF, 0x7B, 0xD5, 0x13, 0x84, 0x0D, 0xAE, 0x39, 0x84, 0x06, + 0xAE, 0x38, 0x84, 0x00, 0x10, 0x03, 0x00, 0x50, 0x80, 0xA6, 0x50, 0x03, 0x00, 0x41, 0x84, 0x3F, + 0x18, 0x12, 0x80, 0x01, 0xD8, 0xFE, 0x44, 0x03, 0xF0, 0x10, 0x84, 0x20, 0xAE, 0x40, 0x80, 0x07, + 0x84, 0x21, 0x49, 0x00, 0x37, 0xE1, 0x84, 0x20, 0x84, 0x02, 0x80, 0x41, 0x84, 0x61, 0x80, 0x81, + 0x80, 0xA1, 0x3A, 0x6F, 0xA8, 0x84, 0x48, 0x00, 0x34, 0x27, 0x44, 0x00, 0x00, 0x32, 0x49, 0x00, + 0x33, 0x29, 0x3C, 0x1D, 0xFB, 0x59, 0x84, 0x02, 0xAE, 0x08, 0xAE, 0x38, 0x2E, 0x97, 0xEC, 0x2E, + 0x5A, 0x98, 0x01, 0x20, 0x49, 0x00, 0x34, 0x80, 0x3C, 0x0D, 0xFB, 0x4A, 0x84, 0x20, 0x10, 0x90, + 0x00, 0x01, 0x49, 0x00, 0x37, 0xC1, 0x3C, 0x0D, 0xFB, 0x4A, 0x84, 0x2D, 0xAE, 0x41, 0x44, 0x02, + 0xB4, 0xC2, 0x44, 0x12, 0xB5, 0x52, 0x49, 0x00, 0x35, 0x00, 0x44, 0x02, 0xB4, 0xE1, 0x44, 0x12, + 0xB4, 0xE8, 0x49, 0x00, 0x34, 0xB7, 0x84, 0x00, 0x3E, 0x07, 0xEC, 0x2E, 0x3E, 0x97, 0xEC, 0x20, + 0xA6, 0x39, 0x9E, 0x43, 0xE6, 0x24, 0xE9, 0x07, 0x5A, 0x00, 0x0C, 0x06, 0x5A, 0x08, 0x0D, 0x07, + 0x49, 0x00, 0x34, 0xFE, 0x84, 0x07, 0xAE, 0x39, 0xD5, 0x03, 0x84, 0x08, 0xAE, 0x39, 0x85, 0x20, + 0x10, 0x93, 0x00, 0x50, 0x49, 0xFF, 0xDF, 0x0E, 0x3E, 0x97, 0xEC, 0x36, 0x3E, 0x97, 0xEC, 0x1D, + 0x49, 0xFF, 0xF1, 0xB3, 0x3C, 0x0D, 0xFB, 0x4A, 0x49, 0xFF, 0xF0, 0x51, 0x44, 0x63, 0xF0, 0x4A, + 0x3E, 0x97, 0xEC, 0x00, 0x44, 0x90, 0x00, 0x55, 0x49, 0x00, 0x07, 0x4E, 0x5A, 0x08, 0x02, 0x05, + 0x10, 0x93, 0x00, 0x00, 0xD5, 0xFA, 0x44, 0x13, 0xF0, 0x10, 0x84, 0x00, 0xAE, 0x08, 0x44, 0x13, + 0xF4, 0x29, 0x44, 0x2F, 0xFF, 0xC3, 0xAE, 0x88, 0x44, 0x13, 0xF0, 0x1C, 0xAE, 0x08, 0x49, 0x00, + 0x07, 0x3B, 0xC0, 0x09, 0x84, 0x21, 0x44, 0x00, 0x5A, 0xF0, 0x80, 0x41, 0x80, 0x61, 0x80, 0x81, + 0x49, 0x00, 0x42, 0x67, 0x84, 0x00, 0x3E, 0x00, 0x06, 0x2C, 0x84, 0x00, 0x3C, 0x0E, 0x01, 0x87, + 0x44, 0x02, 0x3F, 0xF0, 0x44, 0x1F, 0xFD, 0xFD, 0xAC, 0x40, 0x2E, 0x10, 0x06, 0x2E, 0x84, 0x01, + 0x3E, 0x07, 0xEC, 0x20, 0x3E, 0x00, 0x06, 0x36, 0x5A, 0x10, 0x01, 0x04, 0x3E, 0x07, 0xEC, 0x2B, + 0x84, 0x00, 0x49, 0x00, 0x09, 0x32, 0x80, 0x07, 0x84, 0x20, 0x49, 0x00, 0x37, 0x4D, 0x3C, 0x0D, + 0xFB, 0x5C, 0x5A, 0x00, 0x04, 0x04, 0x5A, 0x08, 0x07, 0x0C, 0x84, 0x21, 0x84, 0x40, 0x84, 0x02, + 0x80, 0x62, 0x84, 0x8F, 0x80, 0xA1, 0x3A, 0x6F, 0xA8, 0x84, 0x48, 0x00, 0x33, 0x8D, 0x84, 0x40, + 0x84, 0x02, 0xFA, 0x25, 0x80, 0x62, 0x84, 0x8F, 0x84, 0xA1, 0x3A, 0x6F, 0xA8, 0x84, 0x48, 0x00, + 0x33, 0x83, 0x3C, 0x0D, 0xFB, 0x4A, 0x84, 0x20, 0x49, 0x00, 0x37, 0x2E, 0x84, 0x09, 0xAE, 0x39, + 0x84, 0x03, 0xAE, 0x38, 0x84, 0x00, 0x10, 0x03, 0x00, 0x50, 0x3C, 0x0D, 0xFB, 0x4A, 0x49, 0xFF, + 0xEF, 0xE6, 0x84, 0x01, 0x3A, 0x6F, 0xA8, 0x84, 0x48, 0xFF, 0xDE, 0xD2, 0x44, 0x00, 0x00, 0x31, + 0x49, 0x00, 0x32, 0x70, 0x44, 0x03, 0xF4, 0x29, 0x85, 0x20, 0x10, 0x90, 0x00, 0x00, 0x44, 0x03, + 0xF0, 0x1C, 0x85, 0x41, 0x10, 0xA0, 0x00, 0x00, 0x49, 0xFF, 0xF1, 0x2F, 0x3E, 0x97, 0xEC, 0x0B, + 0x10, 0xA3, 0x80, 0x00, 0x10, 0x93, 0x00, 0x50, 0x2E, 0x07, 0xEC, 0x0B, 0xA6, 0x79, 0x2E, 0x27, + 0xEC, 0x1F, 0x84, 0x81, 0x2E, 0x37, 0xEC, 0x3C, 0x44, 0x52, 0xB6, 0x24, 0x49, 0xFF, 0xED, 0x13, + 0x2E, 0x07, 0xEC, 0x66, 0x54, 0x10, 0x00, 0xFB, 0xC9, 0x08, 0x44, 0x02, 0xB6, 0x24, 0x44, 0x12, + 0xD5, 0x8C, 0x49, 0xFF, 0xEF, 0x67, 0xD5, 0x09, 0x5A, 0x08, 0x03, 0x08, 0x44, 0x02, 0xB6, 0x24, + 0x44, 0x12, 0xD3, 0xF8, 0x49, 0xFF, 0xEF, 0x5E, 0x84, 0x00, 0x3E, 0x00, 0x06, 0x2C, 0x2E, 0x10, + 0x06, 0x2E, 0x84, 0x00, 0x3C, 0x0E, 0x01, 0x87, 0x84, 0x01, 0x3E, 0x07, 0xEC, 0x20, 0x5A, 0x10, + 0x01, 0x04, 0x3E, 0x07, 0xEC, 0x2B, 0x84, 0x00, 0x49, 0x00, 0x08, 0xB7, 0xA6, 0x39, 0x8E, 0x07, + 0xE6, 0x04, 0xE8, 0x5B, 0x80, 0x07, 0x3A, 0x6F, 0xA8, 0x84, 0x48, 0x00, 0x33, 0x62, 0x84, 0x0D, + 0xAE, 0x39, 0x84, 0x06, 0xAE, 0x38, 0x80, 0xA6, 0x50, 0x03, 0x00, 0x41, 0x84, 0x3F, 0x18, 0x12, + 0x80, 0x01, 0xD8, 0xFE, 0x80, 0x07, 0x84, 0x21, 0x49, 0x00, 0x36, 0xBE, 0x84, 0x00, 0x10, 0x03, + 0x00, 0x50, 0x84, 0x20, 0x84, 0x61, 0x84, 0x02, 0x80, 0x41, 0x80, 0x83, 0x80, 0xA1, 0x3A, 0x6F, + 0xA8, 0x84, 0x48, 0x00, 0x33, 0x01, 0x49, 0x00, 0x06, 0x77, 0x3C, 0x1D, 0xFB, 0x4A, 0x5A, 0x08, + 0x02, 0x0C, 0xA6, 0x09, 0x5A, 0x00, 0x03, 0x12, 0x80, 0x01, 0x84, 0x20, 0x49, 0x00, 0x36, 0xA4, + 0x49, 0x00, 0x0C, 0x1C, 0xD5, 0x0A, 0xA6, 0x09, 0x5A, 0x00, 0x09, 0x08, 0x80, 0x01, 0x84, 0x20, + 0x49, 0x00, 0x36, 0x9A, 0x49, 0x00, 0x0C, 0x6E, 0x00, 0x03, 0x00, 0x51, 0x00, 0x13, 0x00, 0x52, + 0x44, 0x22, 0xB4, 0xFD, 0x44, 0x32, 0xB4, 0xCE, 0x44, 0x42, 0xB5, 0x0C, 0x49, 0xFF, 0xF9, 0x05, + 0x84, 0x00, 0x10, 0x03, 0x00, 0x50, 0xD5, 0x11, 0x00, 0x03, 0x00, 0x51, 0x5A, 0x00, 0x01, 0x05, + 0x5A, 0x08, 0x02, 0x05, 0x84, 0x00, 0x3E, 0x07, 0xEC, 0x58, 0x84, 0x00, 0x10, 0x03, 0x00, 0x50, + 0xD5, 0x04, 0x84, 0x1B, 0x10, 0x03, 0x00, 0x50, 0x3A, 0x6F, 0xA8, 0x84, 0xDD, 0x9E, 0x92, 0x00, + 0x2E, 0x07, 0xEC, 0x16, 0xC8, 0x07, 0x2E, 0x07, 0xEC, 0x5F, 0x8E, 0x04, 0x5C, 0x00, 0x00, 0x02, + 0xDD, 0x9E, 0x84, 0x00, 0xDD, 0x9E, 0x00, 0x00, 0xA6, 0xC1, 0x8E, 0x63, 0xE6, 0x68, 0x4E, 0xF2, + 0x02, 0xC1, 0x3A, 0x6F, 0xA4, 0xBC, 0xEF, 0xF4, 0x80, 0xE2, 0x80, 0xC0, 0x44, 0xF0, 0x58, 0xDC, + 0x38, 0x37, 0x8D, 0x01, 0x40, 0xF1, 0xBC, 0x00, 0x4A, 0x00, 0x3C, 0x00, 0x10, 0x00, 0x80, 0x01, + 0x5E, 0x05, 0xB8, 0x02, 0x72, 0x03, 0xD6, 0x03, 0x92, 0x04, 0xEA, 0x04, 0x3C, 0x0D, 0xFB, 0x5C, + 0x5A, 0x08, 0x09, 0x1E, 0x49, 0x00, 0x06, 0x10, 0x5A, 0x08, 0x02, 0x1A, 0x44, 0x02, 0xB4, 0xC2, + 0x44, 0x12, 0xB5, 0x52, 0x49, 0x00, 0x33, 0x89, 0x44, 0x02, 0xB4, 0xE1, 0x44, 0x12, 0xB4, 0xE8, + 0x49, 0x00, 0x33, 0x74, 0x84, 0x0B, 0xAE, 0x31, 0x3C, 0x0D, 0xFB, 0x4A, 0x84, 0x20, 0x49, 0x00, + 0x36, 0x33, 0x84, 0x03, 0xAE, 0x31, 0xFA, 0x00, 0x3C, 0x0F, 0xFB, 0x5C, 0x2E, 0x07, 0xC7, 0x52, + 0xC0, 0x0D, 0x5A, 0x00, 0x01, 0x07, 0x2E, 0x97, 0xEC, 0x60, 0x5A, 0x98, 0x02, 0x55, 0xD5, 0x36, + 0x3C, 0x03, 0xE5, 0x9A, 0xA0, 0x7B, 0xE2, 0x20, 0xE8, 0xF7, 0x44, 0x03, 0xF0, 0x4A, 0x44, 0x10, + 0x00, 0x55, 0xAE, 0x40, 0x44, 0x93, 0xF0, 0x4B, 0x3C, 0x0D, 0xFB, 0x64, 0xA6, 0x00, 0xC8, 0xEC, + 0x3C, 0x0D, 0xFB, 0x59, 0xA6, 0x00, 0x5A, 0x08, 0x01, 0xE8, 0x2E, 0x07, 0xEC, 0x29, 0x5A, 0x08, + 0x01, 0x06, 0x44, 0x02, 0xB5, 0x64, 0x49, 0x00, 0x32, 0xCA, 0x3C, 0x1D, 0xFB, 0x8A, 0x2E, 0x07, + 0xC6, 0xE7, 0xE2, 0x20, 0xE8, 0xEA, 0x00, 0x04, 0x80, 0x00, 0x44, 0x13, 0xF0, 0x4B, 0x5A, 0x00, + 0xFF, 0x05, 0x84, 0x1F, 0xAE, 0x08, 0xD5, 0xFF, 0x84, 0x40, 0x84, 0x01, 0x84, 0x2A, 0x80, 0x62, + 0x80, 0x80, 0x80, 0xA2, 0x49, 0x00, 0x32, 0x40, 0xD5, 0xD8, 0x84, 0x04, 0xAE, 0x31, 0x3C, 0x0D, + 0xFB, 0x4A, 0x49, 0xFF, 0xEE, 0xAC, 0x44, 0x13, 0xF0, 0x4B, 0xA6, 0x08, 0x5A, 0x00, 0xFF, 0x05, + 0x84, 0x1F, 0xAE, 0x08, 0xD5, 0xFF, 0x84, 0x01, 0x49, 0x00, 0x0A, 0x88, 0x80, 0x06, 0x49, 0x00, + 0x0A, 0x96, 0xF0, 0x81, 0x84, 0x40, 0x80, 0x09, 0xF1, 0x01, 0x84, 0x61, 0x80, 0x82, 0x80, 0xA2, + 0x49, 0x00, 0x32, 0x22, 0x2E, 0x07, 0xC7, 0x52, 0x5A, 0x00, 0x01, 0x04, 0x48, 0x00, 0x02, 0x27, + 0x3C, 0x03, 0xE5, 0x9A, 0xA0, 0x7B, 0xE2, 0x20, 0xE8, 0x05, 0x49, 0xFF, 0xFF, 0x53, 0xC8, 0x05, + 0xD5, 0x0C, 0x49, 0xFF, 0xDD, 0x6C, 0xC8, 0xFA, 0x44, 0x03, 0xF0, 0x4A, 0x44, 0x10, 0x00, 0x55, + 0xAE, 0x40, 0x3C, 0x1D, 0xFB, 0x64, 0xD5, 0x10, 0x2E, 0x07, 0xEC, 0x58, 0x5A, 0x00, 0x01, 0xF6, + 0x2E, 0x07, 0xEC, 0x7B, 0x5A, 0x00, 0x01, 0xF2, 0x2E, 0x07, 0xEC, 0x42, 0x5A, 0x00, 0x01, 0x04, + 0x48, 0x00, 0x02, 0x05, 0xD5, 0xEA, 0xA6, 0x08, 0xC0, 0xFF, 0x84, 0x06, 0xAE, 0x31, 0x84, 0x02, + 0x3E, 0x07, 0xEC, 0x77, 0x49, 0x00, 0x05, 0x3C, 0x3E, 0x07, 0xEC, 0x53, 0x49, 0x00, 0x0C, 0x00, + 0x3C, 0x0D, 0xFB, 0x59, 0x84, 0x20, 0xAE, 0x40, 0x48, 0x00, 0x01, 0xF1, 0x2E, 0x07, 0xEC, 0x75, + 0xC8, 0x26, 0x80, 0x06, 0x49, 0x00, 0x09, 0xE4, 0x2E, 0x07, 0xEC, 0x0E, 0xC8, 0x07, 0x44, 0x02, + 0xD3, 0x40, 0x49, 0x00, 0x31, 0x93, 0x49, 0x00, 0x0C, 0x85, 0x2E, 0x07, 0xEC, 0x75, 0x5A, 0x00, + 0x03, 0x1C, 0x84, 0x21, 0x3C, 0x0D, 0xFB, 0x4A, 0x49, 0x00, 0x35, 0x7E, 0x84, 0x01, 0x49, 0x00, + 0x0A, 0x25, 0x80, 0x06, 0x49, 0x00, 0x0A, 0x33, 0xF0, 0x81, 0x84, 0x40, 0x84, 0x02, 0xF1, 0x01, + 0x84, 0x61, 0x80, 0x82, 0x80, 0xA2, 0x49, 0x00, 0x31, 0xBF, 0xD5, 0x06, 0x5A, 0x08, 0x03, 0x05, + 0x84, 0x01, 0x3E, 0x07, 0xEC, 0x75, 0x80, 0x06, 0x2E, 0x17, 0xEC, 0x5F, 0x49, 0x00, 0x0D, 0xA8, + 0x2E, 0x07, 0xEC, 0x7A, 0x5A, 0x08, 0x01, 0x04, 0x48, 0x00, 0x01, 0xB9, 0x2E, 0x17, 0xEC, 0x60, + 0x5A, 0x18, 0x02, 0x08, 0x2E, 0x07, 0xEC, 0x31, 0x52, 0x00, 0x00, 0x01, 0x3E, 0x07, 0xEC, 0x31, + 0x2E, 0x07, 0xEC, 0x31, 0x5A, 0x00, 0x01, 0x08, 0x2E, 0x07, 0xEC, 0x75, 0x5A, 0x08, 0x03, 0x0A, + 0x48, 0x00, 0x00, 0xAA, 0x49, 0x00, 0x31, 0x1C, 0x49, 0xFF, 0xFC, 0x9A, 0x48, 0x00, 0x00, 0xA4, + 0x5A, 0x10, 0x02, 0x07, 0xA6, 0x31, 0x49, 0x00, 0x0A, 0x0B, 0x49, 0x00, 0x09, 0xAC, 0x3C, 0x73, + 0xF6, 0x4E, 0xA6, 0x31, 0x49, 0x00, 0x0A, 0x0E, 0xE2, 0xE0, 0xE8, 0x05, 0x2E, 0x07, 0xEC, 0x58, + 0x5A, 0x08, 0x01, 0x23, 0x2E, 0x77, 0xEC, 0x1F, 0x44, 0x0F, 0xFF, 0xAA, 0x3E, 0x07, 0xEC, 0x2A, + 0x97, 0xF8, 0x84, 0x06, 0xAE, 0x31, 0x5A, 0x78, 0x01, 0x13, 0x80, 0x27, 0x3C, 0x0D, 0xFB, 0x4A, + 0x49, 0x00, 0x35, 0x22, 0x80, 0x06, 0x49, 0x00, 0x09, 0xDA, 0xF0, 0x81, 0x84, 0x40, 0x84, 0x02, + 0xF1, 0x01, 0x80, 0x67, 0x80, 0x82, 0x80, 0xA2, 0x49, 0x00, 0x31, 0x66, 0x44, 0x03, 0xF0, 0x6D, + 0x84, 0x24, 0xAE, 0x40, 0xD5, 0x09, 0x3C, 0x0D, 0xFB, 0x4A, 0x84, 0x21, 0x49, 0x00, 0x35, 0x0C, + 0x84, 0x01, 0x49, 0x00, 0x09, 0xB3, 0x80, 0x06, 0x49, 0x00, 0x09, 0xC1, 0xF0, 0x81, 0xF1, 0x01, + 0xEC, 0x0C, 0x84, 0x40, 0x84, 0x02, 0x84, 0x61, 0x80, 0x82, 0x80, 0xA2, 0x3A, 0x6F, 0xA4, 0x84, + 0x48, 0x00, 0x31, 0x4A, 0x2E, 0x07, 0xEC, 0x77, 0x5A, 0x08, 0x01, 0x22, 0x49, 0x00, 0x0A, 0x9A, + 0x2E, 0x07, 0xEC, 0x60, 0x5A, 0x08, 0x02, 0x08, 0x2E, 0x07, 0xEC, 0x31, 0x52, 0x00, 0x00, 0x01, + 0x3E, 0x07, 0xEC, 0x31, 0x2E, 0x07, 0xEC, 0x31, 0x5A, 0x08, 0x01, 0x0B, 0x2E, 0x67, 0xEC, 0x58, + 0xCE, 0x07, 0x49, 0x00, 0x0A, 0x5B, 0x3E, 0x67, 0xEC, 0x6E, 0x48, 0x00, 0x01, 0x38, 0x3C, 0x0D, + 0xFB, 0x4A, 0x84, 0x21, 0x49, 0x00, 0x34, 0xD8, 0x48, 0x00, 0x01, 0x01, 0x5A, 0x00, 0x02, 0x04, + 0x48, 0x00, 0x01, 0x2D, 0x2E, 0x77, 0xEC, 0x58, 0x5A, 0x78, 0x01, 0x0B, 0x3C, 0x0D, 0xFB, 0x4A, + 0x84, 0x20, 0x49, 0x00, 0x34, 0xC9, 0x3E, 0x77, 0xEC, 0x77, 0x48, 0x00, 0x01, 0x20, 0x2E, 0x07, + 0xEC, 0x60, 0x5A, 0x00, 0x02, 0x13, 0xA6, 0x08, 0xC8, 0x04, 0x2E, 0x07, 0xEC, 0x31, 0xC0, 0x0D, + 0x49, 0xFF, 0xFE, 0x48, 0x80, 0xE0, 0xC8, 0x09, 0x2E, 0x07, 0xEC, 0x7B, 0x5A, 0x00, 0x01, 0x06, + 0x2E, 0x07, 0xEC, 0x42, 0x5A, 0x08, 0x01, 0x09, 0x84, 0x04, 0xAE, 0x31, 0x3C, 0x0D, 0xFB, 0x4A, + 0x49, 0xFF, 0xED, 0x6D, 0xD5, 0x9E, 0x49, 0xFF, 0xFB, 0xFB, 0x3C, 0x0D, 0xFB, 0x4A, 0x80, 0x27, + 0x49, 0x00, 0x34, 0xA2, 0xEC, 0x0C, 0x3A, 0x6F, 0xA4, 0x84, 0x48, 0x00, 0x0A, 0x17, 0x3C, 0x0D, + 0xFB, 0x5C, 0x5A, 0x08, 0x06, 0x1D, 0x84, 0x00, 0x3E, 0x07, 0xEC, 0x75, 0x3E, 0x07, 0xEC, 0x3D, + 0x3E, 0x07, 0xEC, 0x1C, 0x44, 0x02, 0xD3, 0x40, 0x49, 0x00, 0x30, 0x98, 0x49, 0x00, 0x04, 0x54, + 0xC0, 0x07, 0x49, 0x00, 0x31, 0x41, 0x3C, 0x03, 0xE5, 0xAA, 0x49, 0xFF, 0xFC, 0x08, 0x84, 0x03, + 0x49, 0x00, 0x2F, 0xD8, 0x84, 0x08, 0xAE, 0x31, 0x48, 0x00, 0x00, 0xD9, 0x5A, 0x00, 0x09, 0x04, + 0x48, 0x00, 0x00, 0xD5, 0x49, 0x00, 0x04, 0x40, 0x5A, 0x00, 0x02, 0x04, 0x48, 0x00, 0x00, 0xCF, + 0x3C, 0x0D, 0xFB, 0x4A, 0x84, 0x20, 0x49, 0x00, 0x34, 0x6F, 0x84, 0x03, 0xAE, 0x31, 0x48, 0x00, + 0x00, 0xC6, 0x2E, 0x97, 0xEC, 0x75, 0x4E, 0x93, 0x00, 0x1B, 0x49, 0x00, 0x08, 0xB9, 0x49, 0x00, + 0x0B, 0x61, 0x3C, 0x0D, 0xFB, 0x59, 0x84, 0x21, 0xAE, 0x40, 0x2E, 0x07, 0xEC, 0x75, 0x5A, 0x00, + 0x03, 0x14, 0x80, 0x06, 0x49, 0x00, 0x09, 0x13, 0xF0, 0x81, 0x84, 0x61, 0x84, 0x02, 0xF1, 0x01, + 0x80, 0x49, 0x80, 0x83, 0x80, 0xA9, 0x49, 0x00, 0x30, 0x9F, 0xD5, 0x06, 0x5A, 0x98, 0x03, 0x05, + 0x84, 0x01, 0x3E, 0x07, 0xEC, 0x75, 0x80, 0x06, 0x2E, 0x17, 0xEC, 0x5F, 0x49, 0x00, 0x0C, 0x88, + 0x2E, 0x07, 0xEC, 0x7A, 0x5A, 0x08, 0x01, 0x04, 0x48, 0x00, 0x00, 0x99, 0x2E, 0x07, 0xEC, 0x31, + 0x5A, 0x00, 0x01, 0x06, 0x2E, 0x07, 0xEC, 0x75, 0x5A, 0x08, 0x03, 0x07, 0xEC, 0x0C, 0x3A, 0x6F, + 0xA4, 0x84, 0x48, 0x00, 0x0A, 0x07, 0xA6, 0x31, 0x49, 0x00, 0x08, 0xFA, 0x49, 0x00, 0x08, 0x9B, + 0x3C, 0x93, 0xF6, 0x4E, 0xA6, 0x31, 0x49, 0x00, 0x08, 0xFD, 0xE3, 0x20, 0xE9, 0x11, 0x85, 0x20, + 0x3C, 0x0D, 0xFB, 0x4A, 0x14, 0x93, 0x80, 0x03, 0x80, 0x29, 0x49, 0x00, 0x34, 0x1D, 0x84, 0x0A, + 0xAE, 0x31, 0x84, 0x01, 0x3E, 0x07, 0xEC, 0x77, 0x3C, 0x9B, 0xF6, 0x4E, 0xD5, 0x6F, 0x80, 0x06, + 0x49, 0x00, 0x08, 0xCD, 0xF0, 0x81, 0xF1, 0x01, 0x84, 0x02, 0x84, 0x40, 0xD5, 0x5F, 0x3C, 0x03, + 0xE4, 0x52, 0xA0, 0x53, 0xE2, 0x20, 0xE8, 0x08, 0x2E, 0x07, 0xEC, 0x2C, 0xC0, 0x05, 0x2E, 0x07, + 0xEC, 0x7B, 0x5A, 0x08, 0x01, 0x5C, 0x44, 0x03, 0xF0, 0x4A, 0x44, 0x10, 0x00, 0x55, 0xAE, 0x40, + 0x3C, 0x1D, 0xFB, 0x64, 0xA6, 0x08, 0xC0, 0xFF, 0xA6, 0x31, 0x49, 0x00, 0x08, 0xC1, 0xF0, 0x81, + 0xF1, 0x01, 0x44, 0x02, 0xB5, 0x2D, 0x44, 0x22, 0xB5, 0x76, 0x49, 0x00, 0x0A, 0x25, 0x84, 0x00, + 0x84, 0x2A, 0x3C, 0x0B, 0xF6, 0x4E, 0xAE, 0x71, 0x84, 0x22, 0x3E, 0x17, 0xEC, 0x77, 0x3C, 0x1D, + 0xFB, 0x59, 0xAE, 0x08, 0xD5, 0x3B, 0x2E, 0x07, 0xEC, 0x77, 0x5A, 0x08, 0x01, 0x10, 0x3C, 0x0D, + 0xFB, 0x4A, 0x49, 0xFF, 0xEC, 0x9C, 0x49, 0xFF, 0xFB, 0x46, 0x84, 0x02, 0x3E, 0x07, 0xEC, 0x77, + 0x3C, 0x0D, 0xFB, 0x59, 0x84, 0x20, 0xAE, 0x40, 0xD5, 0x29, 0x5A, 0x08, 0x02, 0x28, 0xA6, 0x08, + 0xC8, 0x04, 0x2E, 0x07, 0xEC, 0x31, 0xC0, 0x08, 0x2E, 0x07, 0xEC, 0x2C, 0xC0, 0x05, 0x2E, 0x07, + 0xEC, 0x7B, 0x5A, 0x08, 0x01, 0x8D, 0x84, 0x08, 0xAE, 0x31, 0x3C, 0x0D, 0xFB, 0x4A, 0x49, 0xFF, + 0xEC, 0x7E, 0x3C, 0x0D, 0xFB, 0x4A, 0x84, 0x21, 0x49, 0x00, 0x33, 0xB6, 0x84, 0x00, 0x84, 0x40, + 0x10, 0x03, 0x80, 0x1C, 0xA8, 0xBB, 0x84, 0x02, 0xFA, 0x26, 0xEC, 0x0C, 0x84, 0x61, 0x80, 0x83, + 0x80, 0xA2, 0x3A, 0x6F, 0xA4, 0x84, 0x48, 0x00, 0x2F, 0xF7, 0xEC, 0x0C, 0x3A, 0x6F, 0xA4, 0x84, + 0xDD, 0x9E, 0x92, 0x00, 0xE6, 0x06, 0xE8, 0x75, 0x44, 0xF0, 0x5E, 0x58, 0x38, 0x07, 0x80, 0x00, + 0x40, 0xF0, 0x3C, 0x00, 0x4A, 0x00, 0x3C, 0x00, 0x06, 0x26, 0x44, 0xD8, 0x66, 0x9E, 0x44, 0x13, + 0xF2, 0x48, 0x84, 0x01, 0x44, 0x23, 0xF2, 0x49, 0xAE, 0x08, 0x84, 0x22, 0xAE, 0x50, 0x44, 0x23, + 0xF2, 0x4A, 0x84, 0x64, 0xAE, 0x10, 0x44, 0x23, 0xF2, 0x4B, 0xAE, 0x50, 0xD5, 0x30, 0x44, 0x13, + 0xF2, 0x48, 0x84, 0x1F, 0xAE, 0x08, 0x44, 0x13, 0xF2, 0x49, 0x84, 0x48, 0xAE, 0x08, 0x44, 0x13, + 0xF2, 0x4A, 0xAE, 0x08, 0x44, 0x13, 0xF2, 0x4B, 0xAE, 0x08, 0xD5, 0x3C, 0x44, 0x13, 0xF2, 0x48, + 0x84, 0x01, 0xAE, 0x08, 0x44, 0x13, 0xF2, 0x49, 0xAE, 0x08, 0x44, 0x13, 0xF2, 0x4A, 0xAE, 0x08, + 0x44, 0x13, 0xF2, 0x4B, 0xAE, 0x08, 0x44, 0x13, 0xF2, 0x4C, 0xAE, 0x08, 0xD5, 0x2E, 0x44, 0x13, + 0xF2, 0x48, 0x84, 0x01, 0x44, 0x23, 0xF2, 0x49, 0xAE, 0x08, 0x84, 0x24, 0xAE, 0x50, 0x44, 0x23, + 0xF2, 0x4A, 0x84, 0x6C, 0xAE, 0x10, 0x44, 0x23, 0xF2, 0x4B, 0xAE, 0x50, 0x44, 0x23, 0xF2, 0x4C, + 0xAE, 0xD0, 0x44, 0x23, 0xF2, 0x4D, 0xAE, 0x50, 0x44, 0x23, 0xF2, 0x4E, 0xAE, 0x10, 0x44, 0x23, + 0xF2, 0x4F, 0xAE, 0x50, 0xD5, 0x1B, 0x44, 0x13, 0xF2, 0x48, 0x84, 0x00, 0xAE, 0x08, 0x44, 0x13, + 0xF2, 0x49, 0x84, 0x41, 0xAE, 0x08, 0x44, 0x13, 0xF2, 0x4A, 0xAE, 0x08, 0x44, 0x13, 0xF2, 0x4B, + 0xAE, 0x08, 0x44, 0x13, 0xF2, 0x4C, 0xAE, 0x88, 0x44, 0x13, 0xF2, 0x4D, 0xAE, 0x08, 0x44, 0x13, + 0xF2, 0x4E, 0xAE, 0x08, 0x44, 0x13, 0xF2, 0x4F, 0xAE, 0x08, 0x44, 0x13, 0xF2, 0x50, 0xAE, 0x08, + 0xDD, 0x9E, 0x92, 0x00, 0xC1, 0x03, 0x58, 0x00, 0x00, 0x10, 0x44, 0x13, 0xF2, 0x51, 0x96, 0x00, + 0xAE, 0x08, 0xDD, 0x9E, 0x40, 0x00, 0x3C, 0x08, 0x44, 0x23, 0xF2, 0x44, 0x92, 0x10, 0xAC, 0x10, + 0x40, 0x10, 0xBC, 0x08, 0x44, 0x03, 0xF2, 0x46, 0x92, 0x30, 0xAC, 0x40, 0xDD, 0x9E, 0x44, 0x03, + 0xF2, 0x40, 0x84, 0x21, 0xAE, 0x40, 0x44, 0x13, 0xF0, 0x4A, 0x44, 0x20, 0x00, 0x55, 0xAE, 0x88, + 0xA6, 0x40, 0x5A, 0x10, 0x01, 0xFF, 0xDD, 0x9E, 0x44, 0x13, 0xF2, 0x58, 0xA4, 0x48, 0xAC, 0x40, + 0x44, 0x13, 0xF2, 0x5A, 0xA4, 0x48, 0xAC, 0x41, 0x44, 0x13, 0xF2, 0x5C, 0xA4, 0x48, 0xAC, 0x42, + 0x44, 0x13, 0xF2, 0x5E, 0xA4, 0x48, 0xAC, 0x43, 0x44, 0x13, 0xF2, 0x60, 0xA6, 0x48, 0x10, 0x10, + 0x00, 0x08, 0xDD, 0x9E, 0xFC, 0x02, 0xF0, 0x81, 0x80, 0x02, 0xF3, 0x83, 0xF1, 0x82, 0x49, 0xFF, + 0xFF, 0x4B, 0xF0, 0x01, 0xF1, 0x02, 0x49, 0xFF, 0xFF, 0xC7, 0x49, 0xFF, 0xFF, 0xD2, 0xF0, 0x03, + 0x49, 0xFF, 0xFF, 0xDC, 0xFC, 0x82, 0xFC, 0x02, 0xF0, 0x81, 0x44, 0x03, 0xF2, 0x42, 0xF1, 0x82, + 0xF2, 0x83, 0xAF, 0x40, 0x00, 0x1F, 0x80, 0x20, 0x44, 0x03, 0xF2, 0x43, 0xAE, 0x40, 0x44, 0x03, + 0xF2, 0x52, 0x84, 0x21, 0xAC, 0xC0, 0x44, 0x03, 0xF2, 0x54, 0xAD, 0x00, 0x44, 0x03, 0xF2, 0x56, + 0xAC, 0x40, 0x00, 0x1F, 0x80, 0x24, 0x44, 0x03, 0xF2, 0x41, 0xAE, 0x40, 0x00, 0x0F, 0x80, 0x28, + 0x00, 0x1F, 0x80, 0x2C, 0x49, 0xFF, 0xFF, 0x98, 0xF0, 0x01, 0xF1, 0x02, 0xF2, 0x03, 0xF3, 0x0C, + 0x49, 0xFF, 0xFF, 0xCA, 0xFC, 0x82, 0x3C, 0x0D, 0xFB, 0x56, 0x02, 0x00, 0x00, 0x11, 0xDD, 0x9E, + 0x44, 0x02, 0x51, 0x70, 0x3C, 0x0F, 0xFB, 0x35, 0x44, 0x03, 0xF1, 0x42, 0x44, 0x10, 0x28, 0xB8, + 0xAC, 0x40, 0x44, 0x12, 0x51, 0x88, 0x84, 0x00, 0xB6, 0x01, 0x3C, 0x1D, 0xFB, 0x35, 0xA8, 0x0F, + 0x3C, 0x1D, 0xFB, 0x35, 0x14, 0x00, 0x80, 0x08, 0xDD, 0x9E, 0x84, 0x20, 0x3C, 0x0F, 0xFB, 0x56, + 0xAC, 0x43, 0xDD, 0x9E, 0x3C, 0x3D, 0xFB, 0x56, 0x92, 0x01, 0x92, 0x21, 0x92, 0x41, 0xAC, 0x18, + 0xAC, 0x59, 0xAC, 0x9A, 0xDD, 0x9E, 0x3C, 0x1D, 0xFB, 0x56, 0xA6, 0x82, 0x10, 0x20, 0x80, 0x0C, + 0xA6, 0x83, 0x10, 0x20, 0x80, 0x0D, 0xA6, 0x80, 0xA6, 0x01, 0x10, 0x20, 0x80, 0x0E, 0x10, 0x00, + 0x80, 0x0F, 0xDD, 0x9E, 0x3C, 0x1D, 0xFB, 0x56, 0xA6, 0x82, 0x10, 0x20, 0x80, 0x10, 0xA6, 0x83, + 0x10, 0x20, 0x80, 0x11, 0xA6, 0x80, 0xA6, 0x01, 0x10, 0x20, 0x80, 0x12, 0x10, 0x00, 0x80, 0x13, + 0xDD, 0x9E, 0x3C, 0x1D, 0xFB, 0x56, 0xA6, 0x82, 0x10, 0x20, 0x80, 0x14, 0xA6, 0x83, 0x10, 0x20, + 0x80, 0x15, 0xA6, 0x80, 0xA6, 0x01, 0x10, 0x20, 0x80, 0x16, 0x10, 0x00, 0x80, 0x17, 0xDD, 0x9E, + 0xFC, 0x01, 0xB6, 0x3F, 0xF2, 0x81, 0x49, 0xFF, 0xFF, 0xD0, 0xB4, 0x1F, 0x49, 0xFF, 0xFF, 0xDC, + 0xF0, 0x01, 0x49, 0xFF, 0xFF, 0xE8, 0xFC, 0x81, 0xFC, 0x24, 0xF0, 0x81, 0xF1, 0x82, 0xF2, 0x83, + 0x00, 0x1F, 0x80, 0x3C, 0x00, 0x2F, 0x80, 0x38, 0x00, 0x0F, 0x80, 0x40, 0x00, 0x7F, 0x80, 0x60, + 0x00, 0x6F, 0x80, 0x4C, 0x10, 0x5F, 0x80, 0x16, 0x10, 0x3F, 0x80, 0x14, 0x10, 0x2F, 0x80, 0x17, + 0x10, 0x4F, 0x80, 0x15, 0x10, 0x1F, 0x80, 0x1A, 0x10, 0x3F, 0x80, 0x18, 0x10, 0x0F, 0x80, 0x1B, + 0x10, 0x4F, 0x80, 0x19, 0xCF, 0x08, 0x10, 0x5F, 0x80, 0x1E, 0x10, 0x3F, 0x80, 0x1C, 0x10, 0x2F, + 0x80, 0x1F, 0xD5, 0x07, 0x10, 0x1F, 0x80, 0x1E, 0x10, 0x3F, 0x80, 0x1C, 0x10, 0x0F, 0x80, 0x1F, + 0x3C, 0x0D, 0xFB, 0x35, 0x10, 0x4F, 0x80, 0x1D, 0x49, 0xFF, 0xFF, 0x89, 0xB0, 0x05, 0xB0, 0x46, + 0xB0, 0x87, 0x49, 0xFF, 0xFF, 0xBF, 0xF0, 0x01, 0xF1, 0x02, 0xF2, 0x03, 0x49, 0xFF, 0xFF, 0x84, + 0x3C, 0x0D, 0xFB, 0x56, 0x02, 0x1F, 0x80, 0x28, 0x00, 0x2F, 0x80, 0x44, 0xAC, 0x44, 0x00, 0x1F, + 0x80, 0x54, 0xFE, 0x77, 0x52, 0x63, 0x00, 0x10, 0x95, 0xB1, 0xFF, 0x8F, 0x00, 0x1F, 0x80, 0x48, + 0x10, 0x60, 0x00, 0x0A, 0x58, 0x10, 0x80, 0x40, 0xFE, 0x57, 0x10, 0x10, 0x00, 0x0B, 0x22, 0x1F, + 0x80, 0x2C, 0x12, 0x10, 0x00, 0x0C, 0x22, 0x1F, 0x80, 0x2E, 0x12, 0x10, 0x00, 0x0D, 0x44, 0x03, + 0xF0, 0x4A, 0x44, 0x10, 0x00, 0x55, 0xAE, 0x40, 0x44, 0x03, 0xF1, 0x40, 0x84, 0x21, 0xAE, 0x40, + 0xA6, 0x40, 0x5A, 0x10, 0x01, 0xFF, 0xFC, 0xA4, 0xFC, 0x04, 0xF0, 0x81, 0x94, 0x19, 0x96, 0x00, + 0xF1, 0x82, 0x10, 0x0F, 0x80, 0x17, 0x84, 0x22, 0x10, 0x0F, 0x80, 0x1B, 0x84, 0xC1, 0x3C, 0x0D, + 0xFB, 0x35, 0x10, 0x3F, 0x80, 0x14, 0x10, 0x4F, 0x80, 0x15, 0x10, 0x3F, 0x80, 0x18, 0x10, 0x4F, + 0x80, 0x19, 0x10, 0x3F, 0x80, 0x1C, 0x10, 0x3F, 0x80, 0x1F, 0x10, 0x4F, 0x80, 0x1D, 0xF2, 0x83, + 0x10, 0x1F, 0x80, 0x16, 0x10, 0x1F, 0x80, 0x1A, 0x10, 0x6F, 0x80, 0x1E, 0x49, 0xFF, 0xFF, 0x2F, + 0xB0, 0x05, 0xB0, 0x46, 0xB0, 0x87, 0x49, 0xFF, 0xFF, 0x65, 0xF0, 0x01, 0xF1, 0x02, 0xF2, 0x03, + 0x49, 0xFF, 0xFF, 0x2A, 0x3C, 0x0D, 0xFB, 0x56, 0x84, 0x20, 0x84, 0x49, 0xAC, 0x44, 0x10, 0x10, + 0x00, 0x0B, 0x10, 0x20, 0x00, 0x0A, 0x44, 0x03, 0xF0, 0x4A, 0x44, 0x10, 0x00, 0x55, 0xAE, 0x40, + 0x44, 0x03, 0xF1, 0x40, 0xAF, 0x80, 0xA6, 0x40, 0x5A, 0x10, 0x01, 0xFF, 0xFC, 0x84, 0x44, 0x03, + 0xF0, 0x4A, 0x44, 0x10, 0x00, 0x55, 0xAE, 0x40, 0x44, 0x13, 0xF4, 0x03, 0xA6, 0x08, 0x5A, 0x00, + 0x01, 0xFF, 0x44, 0x03, 0xF3, 0x80, 0x84, 0x21, 0xAE, 0x40, 0x44, 0x13, 0xF0, 0x4A, 0x44, 0x20, + 0x00, 0x55, 0xAE, 0x88, 0xA6, 0x40, 0x5A, 0x10, 0x01, 0xFF, 0xDD, 0x9E, 0xFC, 0x00, 0x44, 0x13, + 0xF3, 0x81, 0xA6, 0x08, 0x54, 0x00, 0x00, 0xF0, 0xAE, 0x08, 0x44, 0x13, 0xF3, 0x84, 0x84, 0x00, + 0xAE, 0x08, 0x44, 0x13, 0xF5, 0x6B, 0xAE, 0x08, 0x44, 0x13, 0xF5, 0x72, 0xAE, 0x08, 0x44, 0x13, + 0xF5, 0x73, 0xAE, 0x08, 0x49, 0xFF, 0xFF, 0xD5, 0xFC, 0x80, 0x44, 0x53, 0xF3, 0x81, 0x94, 0x4A, + 0xA7, 0x28, 0x94, 0x07, 0x54, 0x42, 0x00, 0xF0, 0xFE, 0xA7, 0xFE, 0x57, 0x96, 0x48, 0xFE, 0x0F, + 0x96, 0x00, 0xAE, 0x28, 0x44, 0x03, 0xF3, 0x84, 0x96, 0xD8, 0xAE, 0xC0, 0xDD, 0x9E, 0x44, 0x13, + 0xF3, 0x86, 0x84, 0x00, 0xAE, 0x08, 0x44, 0x13, 0xF3, 0x87, 0xAE, 0x08, 0xDD, 0x9E, 0xFC, 0x00, + 0x44, 0x03, 0xF3, 0x84, 0x96, 0xD8, 0xAE, 0xC0, 0x49, 0xFF, 0xFF, 0xB3, 0x44, 0x03, 0xF0, 0x4A, + 0x44, 0x10, 0x00, 0x55, 0xAE, 0x40, 0x44, 0x13, 0xF3, 0x80, 0xA6, 0x08, 0x5A, 0x00, 0x01, 0xFF, + 0x44, 0x63, 0xF3, 0x80, 0x44, 0x03, 0xF3, 0x86, 0xA6, 0x00, 0x5A, 0x08, 0x01, 0x0F, 0x49, 0xFF, + 0xFF, 0xE0, 0x49, 0xFF, 0xFF, 0x9E, 0x44, 0x03, 0xF0, 0x4A, 0x44, 0x10, 0x00, 0x55, 0xAE, 0x40, + 0xA6, 0x30, 0x5A, 0x00, 0x01, 0xFF, 0xD5, 0xEF, 0x44, 0x03, 0xF3, 0x87, 0xA6, 0x00, 0x5A, 0x00, + 0x01, 0xF0, 0xFC, 0x80, 0xDD, 0x9E, 0x44, 0x1E, 0x00, 0x00, 0x88, 0x01, 0x92, 0x02, 0x44, 0x13, + 0xF3, 0xCA, 0x96, 0x01, 0xAC, 0x08, 0xDD, 0x9E, 0x44, 0x13, 0xF2, 0x80, 0xA6, 0x08, 0x58, 0x00, + 0x00, 0x01, 0xAE, 0x08, 0xDD, 0x9E, 0x44, 0x23, 0xF2, 0x80, 0x94, 0x05, 0xA6, 0x50, 0xFE, 0x47, + 0x96, 0x48, 0xAE, 0x50, 0xDD, 0x9E, 0x44, 0x1E, 0x00, 0x00, 0x88, 0x01, 0x44, 0x13, 0xF2, 0x86, + 0x96, 0x81, 0xAC, 0x88, 0x92, 0x10, 0x44, 0x13, 0xF2, 0x88, 0x96, 0x06, 0xAE, 0x08, 0xDD, 0x9E, + 0xFC, 0x40, 0xFD, 0x30, 0xA4, 0x40, 0x44, 0x03, 0xF2, 0x84, 0x44, 0x93, 0xF4, 0x18, 0xAC, 0x40, + 0xA0, 0x31, 0x49, 0xFF, 0xFF, 0xEA, 0x00, 0x13, 0x00, 0x08, 0x44, 0x03, 0xF2, 0x83, 0xAE, 0x40, + 0x00, 0x03, 0x00, 0x09, 0x44, 0x43, 0xF2, 0x80, 0x96, 0x06, 0x94, 0x41, 0xA6, 0x20, 0x00, 0x23, + 0x00, 0x0A, 0x54, 0x00, 0x00, 0xFD, 0xFE, 0x0F, 0x3C, 0x4F, 0xFB, 0x37, 0x96, 0x86, 0xAE, 0x20, + 0x94, 0xD2, 0xA6, 0xA0, 0x54, 0x21, 0x00, 0xFB, 0xFE, 0x9F, 0xAE, 0xA0, 0x00, 0x03, 0x00, 0x0B, + 0x49, 0xFF, 0xFF, 0xC3, 0x44, 0x03, 0xF0, 0x4A, 0x44, 0x10, 0x00, 0x55, 0xAE, 0x40, 0x02, 0x04, + 0x80, 0x00, 0x5C, 0xF0, 0x00, 0xC8, 0xE9, 0x11, 0x02, 0x04, 0x80, 0x00, 0x5C, 0xF0, 0x07, 0x81, + 0xE8, 0x0C, 0x44, 0x03, 0xF2, 0x91, 0x84, 0x21, 0xAE, 0x40, 0x49, 0xFF, 0xFF, 0xA7, 0x44, 0xA3, + 0xF2, 0x80, 0x44, 0x83, 0xF0, 0x4A, 0xD5, 0x0A, 0x49, 0x00, 0x00, 0x96, 0x5A, 0x00, 0x02, 0xE9, + 0xD5, 0xF1, 0x44, 0x00, 0x00, 0x55, 0x10, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x96, 0x06, + 0xC0, 0x0B, 0x49, 0x00, 0x00, 0x89, 0xC8, 0xF6, 0x44, 0x13, 0xF2, 0x80, 0xAE, 0x08, 0x44, 0x13, + 0xF2, 0x91, 0xAE, 0x08, 0xD5, 0x1A, 0x44, 0x13, 0xF2, 0x91, 0xAE, 0x08, 0x44, 0x03, 0xF2, 0x81, + 0x3C, 0x0F, 0xFB, 0x36, 0x5A, 0x78, 0x03, 0x07, 0xA6, 0x40, 0x92, 0x22, 0x96, 0x46, 0xC1, 0xA9, + 0xD5, 0x08, 0x5A, 0x78, 0x01, 0x05, 0xA6, 0x00, 0x92, 0x02, 0xD5, 0x05, 0x5A, 0x78, 0x02, 0x06, + 0xA6, 0x00, 0x92, 0x03, 0x96, 0x06, 0xC0, 0x9D, 0xFC, 0xC0, 0xC8, 0x08, 0x44, 0x12, 0x2C, 0xF5, + 0xA6, 0x08, 0x8C, 0x01, 0x96, 0x00, 0xAE, 0x08, 0xD5, 0x0F, 0x44, 0x22, 0x2C, 0xF6, 0xA6, 0x50, + 0x8C, 0x21, 0x96, 0x48, 0xAE, 0x50, 0x5A, 0x08, 0x01, 0x08, 0x44, 0x13, 0xF0, 0x60, 0xA6, 0x08, + 0x58, 0x00, 0x00, 0x04, 0xD5, 0x06, 0x44, 0x13, 0xF0, 0x60, 0xA6, 0x08, 0x54, 0x00, 0x00, 0xFB, + 0xAE, 0x08, 0xDD, 0x9E, 0x44, 0x13, 0xF0, 0x68, 0x96, 0x00, 0xAE, 0x08, 0xDD, 0x9E, 0x44, 0x03, + 0xF0, 0x53, 0xA6, 0x00, 0xDD, 0x9E, 0x44, 0x13, 0xF0, 0x6A, 0x96, 0x06, 0xA6, 0x88, 0x54, 0x21, + 0x00, 0xFE, 0xAE, 0x88, 0xA6, 0x88, 0x88, 0x02, 0x96, 0x00, 0xAE, 0x08, 0xDD, 0x9E, 0x44, 0x23, + 0xF0, 0x54, 0xAC, 0x10, 0x44, 0x03, 0xF0, 0x56, 0xAC, 0x40, 0xDD, 0x9E, 0x44, 0x03, 0xF0, 0x61, + 0xA6, 0x00, 0x96, 0x0F, 0xDD, 0x9E, 0x44, 0x23, 0xF0, 0x6D, 0xC9, 0x03, 0x84, 0x25, 0xD5, 0x02, + 0x84, 0x24, 0xAE, 0x50, 0x94, 0x44, 0xFE, 0x0F, 0x44, 0x13, 0xF0, 0x6E, 0x96, 0x00, 0xAE, 0x08, + 0x44, 0x13, 0xF0, 0x6F, 0xAE, 0x08, 0xDD, 0x9E, 0x44, 0x03, 0xF0, 0x6D, 0x84, 0x20, 0xAE, 0x40, + 0xDD, 0x9E, 0x44, 0x03, 0xF0, 0x61, 0xA6, 0x00, 0x92, 0x03, 0x96, 0x06, 0xDD, 0x9E, 0x44, 0x03, + 0xF0, 0x61, 0xA6, 0x00, 0x92, 0x02, 0x96, 0x06, 0xDD, 0x9E, 0x44, 0x03, 0xF0, 0x61, 0xA6, 0x00, + 0x92, 0x07, 0xDD, 0x9E, 0xFC, 0x00, 0x49, 0xFF, 0xFF, 0xFA, 0xC8, 0x07, 0x49, 0xFF, 0xFF, 0xF1, + 0x5A, 0x00, 0x01, 0x06, 0x84, 0x01, 0xD5, 0x04, 0x84, 0x00, 0xD5, 0x02, 0x84, 0x02, 0xFC, 0x80, + 0x94, 0x04, 0xFE, 0x47, 0x96, 0x08, 0x44, 0x13, 0xF4, 0x81, 0xAE, 0x08, 0xDD, 0x9E, 0x44, 0x13, + 0xF4, 0x83, 0x96, 0x01, 0x96, 0x80, 0xA6, 0xC8, 0x92, 0x08, 0xAE, 0x88, 0xA6, 0x89, 0xAE, 0x09, + 0xDD, 0x9E, 0x44, 0x13, 0xF4, 0x85, 0x96, 0x01, 0x96, 0x80, 0xA6, 0xC8, 0x92, 0x08, 0xAE, 0x88, + 0xA6, 0x89, 0xAE, 0x09, 0xDD, 0x9E, 0x44, 0x13, 0xF4, 0x87, 0x96, 0x80, 0xAE, 0x88, 0x92, 0x08, + 0x44, 0x13, 0xF4, 0x88, 0x96, 0x00, 0xAE, 0x08, 0xDD, 0x9E, 0x44, 0x13, 0xF4, 0x89, 0x96, 0x00, + 0xAE, 0x08, 0xDD, 0x9E, 0x44, 0x03, 0xF4, 0x82, 0x44, 0x20, 0x00, 0x55, 0xA6, 0x40, 0x54, 0x10, + 0x80, 0xFE, 0x58, 0x10, 0x80, 0x01, 0xAE, 0x40, 0x44, 0x13, 0xF0, 0x4A, 0xAE, 0x88, 0xA6, 0x40, + 0x96, 0x46, 0xC9, 0xFE, 0xDD, 0x9E, 0x3A, 0x6F, 0x9E, 0xBC, 0x84, 0x00, 0x44, 0x63, 0xF0, 0x0E, + 0x3E, 0x00, 0x05, 0xFA, 0xA4, 0x30, 0x54, 0x00, 0x01, 0x00, 0xC0, 0x09, 0x44, 0x12, 0x2C, 0xF4, + 0xA6, 0x08, 0x8C, 0x01, 0x96, 0x00, 0xAE, 0x08, 0x84, 0x08, 0xD5, 0x7A, 0xA4, 0x30, 0x96, 0x0E, + 0xC8, 0x74, 0xA4, 0x30, 0x96, 0x1E, 0xC0, 0x09, 0x44, 0x12, 0x2C, 0xF3, 0xA6, 0x08, 0x8C, 0x01, + 0x96, 0x00, 0xAE, 0x08, 0x84, 0x03, 0xD5, 0x6C, 0xA4, 0x30, 0x96, 0x16, 0xC0, 0x09, 0x44, 0x12, + 0x2C, 0xF2, 0xA6, 0x08, 0x8C, 0x01, 0x96, 0x00, 0xAE, 0x08, 0x84, 0x02, 0xD5, 0x61, 0xA4, 0x30, + 0x96, 0x26, 0xC0, 0x09, 0x44, 0x12, 0x2C, 0xF1, 0xA6, 0x08, 0x8C, 0x01, 0x96, 0x00, 0xAE, 0x08, + 0x84, 0x04, 0xD5, 0x56, 0xA4, 0x30, 0x96, 0x06, 0xC0, 0x52, 0x49, 0x00, 0x60, 0xA9, 0xA4, 0x30, + 0x96, 0x36, 0xC8, 0x34, 0xA4, 0x30, 0x96, 0x2E, 0xC8, 0x33, 0xA4, 0x30, 0x96, 0x3E, 0xC8, 0x32, + 0xA4, 0x30, 0x54, 0x00, 0x02, 0x00, 0xC0, 0x0C, 0x44, 0x03, 0xF0, 0x64, 0xA6, 0x40, 0x96, 0x46, + 0xC1, 0x2B, 0xA6, 0x40, 0x54, 0x10, 0x80, 0xFE, 0xAE, 0x40, 0x84, 0x09, 0xD5, 0x32, 0x44, 0x03, + 0xF0, 0x0E, 0xA4, 0x40, 0x54, 0x10, 0x84, 0x00, 0xC9, 0x21, 0xA4, 0x40, 0x54, 0x10, 0x88, 0x00, + 0xC9, 0x1F, 0xA4, 0x40, 0x54, 0x10, 0x90, 0x00, 0xC9, 0x1D, 0xA4, 0x40, 0x54, 0x10, 0xA0, 0x00, + 0xC9, 0x1B, 0xA4, 0x40, 0x54, 0x10, 0xC0, 0x00, 0xC9, 0x19, 0xA4, 0x00, 0x92, 0x0F, 0xC0, 0x18, + 0x84, 0x01, 0x3E, 0x00, 0x05, 0xF9, 0x84, 0x0F, 0xD5, 0x14, 0x84, 0x06, 0xD5, 0x12, 0x84, 0x05, + 0xD5, 0x10, 0x84, 0x07, 0xD5, 0x0E, 0x84, 0x09, 0xD5, 0x0C, 0x84, 0x0A, 0xD5, 0x0A, 0x84, 0x0B, + 0xD5, 0x08, 0x84, 0x0C, 0xD5, 0x06, 0x84, 0x0D, 0xD5, 0x04, 0x84, 0x0E, 0xD5, 0x02, 0xFA, 0x00, + 0x84, 0x21, 0x3E, 0x10, 0x05, 0xFA, 0xD5, 0x04, 0x84, 0x01, 0xD5, 0x02, 0xFA, 0x00, 0x44, 0x13, + 0xF0, 0x0E, 0x84, 0x40, 0xAC, 0x88, 0x3A, 0x6F, 0x9E, 0x84, 0xDD, 0x9E, 0x44, 0x03, 0xF3, 0x22, + 0x84, 0x21, 0xAE, 0x40, 0xDD, 0x9E, 0x44, 0x13, 0xF3, 0x23, 0xAE, 0x08, 0xDD, 0x9E, 0x44, 0x03, + 0xF3, 0x23, 0xA6, 0x00, 0xDD, 0x9E, 0x3A, 0x6F, 0x9C, 0x3C, 0x44, 0x63, 0xF5, 0x40, 0xB6, 0x06, + 0x44, 0x03, 0xF5, 0x44, 0xB6, 0x20, 0x44, 0x03, 0xF5, 0x48, 0xB6, 0x40, 0x44, 0x03, 0xF5, 0x4C, + 0xB6, 0x60, 0x44, 0x03, 0xF5, 0x50, 0xB6, 0x80, 0x44, 0x03, 0xF5, 0x54, 0xB6, 0xA0, 0xF1, 0x02, + 0x44, 0x03, 0xF5, 0x58, 0xB6, 0x20, 0xF1, 0x03, 0x44, 0x03, 0xF5, 0x5C, 0x3A, 0x6F, 0x9C, 0x04, + 0xB6, 0x20, 0xDD, 0x9E, 0x3A, 0x6F, 0x98, 0xBC, 0x44, 0x21, 0x31, 0x80, 0xEF, 0xF8, 0x3A, 0x21, + 0x0C, 0x00, 0x3A, 0x2F, 0x8C, 0x20, 0x44, 0x23, 0xF5, 0x04, 0x44, 0x43, 0xF5, 0x02, 0x44, 0x33, + 0xF5, 0x03, 0x3C, 0x2F, 0xFB, 0x39, 0x44, 0x23, 0xF5, 0x05, 0x80, 0xC0, 0x80, 0x3F, 0x3C, 0x4F, + 0xFB, 0x3C, 0x3C, 0x3F, 0xFB, 0x3B, 0x3C, 0x2F, 0xFB, 0x38, 0x5A, 0x00, 0x02, 0x04, 0x48, 0x00, + 0x00, 0x89, 0x44, 0x53, 0xF5, 0x00, 0x44, 0x3C, 0x0B, 0x00, 0x44, 0x03, 0xF5, 0x08, 0x98, 0xAB, + 0x38, 0x20, 0x88, 0x00, 0x18, 0x22, 0x80, 0x01, 0xD8, 0xFB, 0x44, 0x03, 0xF5, 0x07, 0x44, 0x10, + 0x00, 0x45, 0xAE, 0x40, 0x44, 0x03, 0xF5, 0x00, 0x84, 0xC1, 0xAF, 0x80, 0x84, 0x00, 0x80, 0x20, + 0x80, 0x40, 0x80, 0x60, 0x49, 0xFF, 0xFD, 0x95, 0x44, 0x03, 0xF5, 0x01, 0x84, 0x23, 0xAE, 0x40, + 0x84, 0x00, 0x80, 0x20, 0x80, 0x40, 0x80, 0x60, 0x49, 0xFF, 0xFD, 0x8B, 0x3C, 0x1D, 0xFB, 0x3C, + 0xA6, 0x08, 0x58, 0x00, 0x00, 0x02, 0xAE, 0x08, 0x84, 0x00, 0x80, 0x20, 0x80, 0x40, 0x80, 0x60, + 0x49, 0xFF, 0xFD, 0x7F, 0x44, 0x00, 0x07, 0xD0, 0x49, 0x00, 0x16, 0x10, 0x3C, 0x1D, 0xFB, 0x3B, + 0xA6, 0x08, 0x58, 0x00, 0x00, 0x02, 0xAE, 0x08, 0x84, 0x00, 0x80, 0x20, 0x80, 0x40, 0x80, 0x60, + 0x49, 0xFF, 0xFD, 0x6F, 0x44, 0x00, 0x03, 0xE8, 0x49, 0x00, 0x16, 0x00, 0x84, 0x00, 0x80, 0x20, + 0x80, 0x40, 0x80, 0x60, 0x49, 0xFF, 0xFD, 0x65, 0x3C, 0x3D, 0xFB, 0x3C, 0x3C, 0x2D, 0xFB, 0x3B, + 0xA6, 0x58, 0xA6, 0x10, 0x58, 0x10, 0x80, 0x1D, 0x58, 0x00, 0x00, 0x1D, 0xAE, 0x58, 0xAE, 0x10, + 0x84, 0x00, 0x80, 0x20, 0x80, 0x40, 0x80, 0x60, 0x49, 0xFF, 0xFD, 0x53, 0x2E, 0x07, 0xEC, 0x51, + 0xC8, 0x1B, 0x3C, 0x0D, 0xFB, 0x4A, 0x3E, 0x67, 0xEC, 0x51, 0xA7, 0x81, 0x49, 0xFF, 0xFE, 0x74, + 0x3C, 0x1D, 0xFB, 0x4A, 0x5A, 0x08, 0x02, 0x05, 0x84, 0x04, 0xAE, 0x09, 0xD5, 0x03, 0x84, 0x08, + 0xAE, 0x09, 0x3C, 0x0D, 0xFB, 0x4A, 0x49, 0xFF, 0xE7, 0x62, 0x84, 0x01, 0x49, 0xFF, 0xE5, 0x12, + 0x3C, 0x0D, 0xFB, 0x4A, 0xAF, 0x81, 0x44, 0x00, 0x05, 0xAA, 0x49, 0x00, 0x15, 0xC7, 0x49, 0xFF, + 0xE4, 0xEF, 0xC0, 0xFE, 0x3C, 0x2D, 0xFB, 0x3C, 0x44, 0x0F, 0xFF, 0xEF, 0xA6, 0x50, 0xD5, 0x46, + 0xC8, 0x28, 0x44, 0x13, 0xF5, 0x00, 0x84, 0x41, 0xAE, 0x88, 0x44, 0x13, 0xF5, 0x01, 0x84, 0x43, + 0xAE, 0x88, 0x3C, 0x2D, 0xFB, 0x3C, 0x80, 0x60, 0xA6, 0x50, 0x58, 0x10, 0x80, 0x02, 0xAE, 0x50, + 0x3C, 0x2D, 0xFB, 0x3B, 0xA6, 0x50, 0x58, 0x10, 0x80, 0x02, 0xAE, 0x50, 0x80, 0x20, 0x80, 0x40, + 0x49, 0xFF, 0xFD, 0x0F, 0x3C, 0x3D, 0xFB, 0x3C, 0x3C, 0x2D, 0xFB, 0x3B, 0xA6, 0x58, 0xA6, 0x10, + 0x58, 0x10, 0x80, 0x0C, 0x58, 0x00, 0x00, 0x0C, 0xAE, 0x58, 0xAE, 0x10, 0x80, 0x06, 0xD5, 0x26, + 0x5A, 0x08, 0x01, 0x2D, 0xA6, 0x20, 0xA7, 0x58, 0x84, 0x5B, 0xFE, 0x16, 0x84, 0x37, 0xFE, 0x0E, + 0xFE, 0xAE, 0xAE, 0x20, 0xFE, 0x56, 0x84, 0x00, 0xAE, 0x58, 0x80, 0x40, 0x80, 0x20, 0x80, 0x60, + 0x49, 0xFF, 0xFC, 0xEF, 0x44, 0x13, 0xF5, 0x00, 0x84, 0x00, 0xAE, 0x08, 0x44, 0x13, 0xF5, 0x01, + 0xAE, 0x08, 0x3C, 0x2D, 0xFB, 0x3C, 0x84, 0x1D, 0xA6, 0x50, 0xFE, 0x46, 0xAE, 0x50, 0x3C, 0x1D, + 0xFB, 0x3B, 0xA6, 0x88, 0xFE, 0x16, 0xAE, 0x08, 0x84, 0x00, 0xEC, 0x08, 0x80, 0x20, 0x80, 0x40, + 0x80, 0x60, 0x3A, 0x6F, 0x98, 0x84, 0x48, 0xFF, 0xFC, 0xD4, 0xEC, 0x08, 0x3A, 0x6F, 0x98, 0x84, + 0xDD, 0x9E, 0xDD, 0x9E, 0x46, 0x10, 0x80, 0x00, 0x64, 0x13, 0x24, 0x03, 0x64, 0x23, 0x04, 0x02, + 0x46, 0x1F, 0x7F, 0xFF, 0x50, 0x10, 0x8F, 0xFF, 0xFE, 0x56, 0x40, 0x00, 0x6C, 0x08, 0xFE, 0x0F, + 0x64, 0x03, 0x04, 0x03, 0xDD, 0x9E, 0x46, 0x10, 0x08, 0x00, 0x64, 0x13, 0x24, 0x03, 0x64, 0x23, + 0x04, 0x02, 0x46, 0x1F, 0xF7, 0xFF, 0x50, 0x10, 0x8F, 0xFF, 0xFE, 0x56, 0x40, 0x00, 0x5C, 0x08, + 0xFE, 0x0F, 0x64, 0x03, 0x04, 0x03, 0xDD, 0x9E, 0x44, 0x10, 0x80, 0x00, 0x64, 0x13, 0x24, 0x03, + 0x64, 0x23, 0x04, 0x02, 0x44, 0x1F, 0x7F, 0xFF, 0xFE, 0x56, 0x40, 0x00, 0x3C, 0x08, 0xFE, 0x0F, + 0x64, 0x03, 0x04, 0x03, 0xDD, 0x9E, 0xDD, 0x9E, 0xFC, 0x20, 0x80, 0xC1, 0x44, 0x13, 0xF0, 0x40, + 0x80, 0xE2, 0xA6, 0xC8, 0x44, 0x23, 0xF0, 0x0E, 0x54, 0x31, 0x80, 0x1C, 0xFE, 0xC7, 0x84, 0x80, + 0x96, 0xD8, 0xAD, 0x10, 0xAE, 0xC8, 0x44, 0x13, 0xF0, 0x4A, 0x44, 0x20, 0x00, 0x55, 0xAE, 0x88, + 0x5A, 0x08, 0x02, 0x07, 0x49, 0x00, 0x01, 0x14, 0xC8, 0xFE, 0x64, 0x03, 0x04, 0x03, 0x44, 0x13, + 0xF0, 0xDA, 0x97, 0xB0, 0xA6, 0x08, 0x54, 0x00, 0x00, 0xF0, 0x40, 0x23, 0x80, 0x04, 0x96, 0x90, + 0x44, 0x03, 0xF0, 0xED, 0xAE, 0x88, 0x44, 0x13, 0xF0, 0x4A, 0xAF, 0x80, 0x44, 0x00, 0x00, 0x55, + 0xAE, 0x08, 0x44, 0x13, 0xF0, 0x41, 0xAE, 0x08, 0x40, 0x00, 0x00, 0x09, 0x40, 0x00, 0x00, 0x09, + 0x40, 0x00, 0x00, 0x09, 0x40, 0x00, 0x00, 0x09, 0x40, 0x00, 0x00, 0x09, 0xFC, 0xA0, 0x94, 0x4D, + 0x44, 0x23, 0xF0, 0x42, 0xFE, 0x0F, 0x96, 0x00, 0xA6, 0xD0, 0xAE, 0x10, 0xDD, 0x9E, 0x96, 0x06, + 0x94, 0x04, 0x96, 0x5F, 0xFE, 0x47, 0x44, 0x03, 0xF0, 0x43, 0xAE, 0x40, 0xDD, 0x9E, 0x44, 0x13, + 0xF0, 0x44, 0xAC, 0x08, 0xDD, 0x9E, 0x44, 0x13, 0xF0, 0x46, 0xAE, 0x08, 0xDD, 0x9E, 0x40, 0x00, + 0x3C, 0x08, 0x44, 0x33, 0xF2, 0x00, 0x92, 0x10, 0xAC, 0x18, 0x40, 0x10, 0xBC, 0x08, 0x44, 0x03, + 0xF2, 0x02, 0x92, 0x30, 0xAC, 0x40, 0x40, 0x21, 0x3C, 0x08, 0x44, 0x03, 0xF2, 0x04, 0x92, 0x50, + 0xAC, 0x80, 0xDD, 0x9E, 0x44, 0x03, 0xF2, 0x0A, 0x44, 0x20, 0x00, 0x55, 0xA6, 0x40, 0x54, 0x10, + 0x80, 0xFE, 0x58, 0x10, 0x80, 0x01, 0xAE, 0x40, 0x44, 0x13, 0xF0, 0x4A, 0xAE, 0x88, 0xA6, 0x40, + 0x96, 0x46, 0xC9, 0xFE, 0xDD, 0x9E, 0x44, 0x23, 0xF2, 0x06, 0x96, 0x00, 0xAE, 0x10, 0x44, 0x03, + 0xF2, 0x07, 0x96, 0x48, 0xAE, 0x40, 0xDD, 0x9E, 0x44, 0x02, 0x32, 0xE8, 0xDD, 0x9E, 0x44, 0x02, + 0x2F, 0x00, 0xDD, 0x9E, 0x44, 0x03, 0xF2, 0x0B, 0xA6, 0x00, 0xDD, 0x9E, 0x44, 0x13, 0xF2, 0x08, + 0xAC, 0x08, 0xDD, 0x9E, 0x44, 0x23, 0xF2, 0x0A, 0x94, 0x01, 0xA6, 0x50, 0x96, 0x46, 0xFE, 0x47, + 0x96, 0x48, 0xAE, 0x50, 0xDD, 0x9E, 0x00, 0x00, 0xE6, 0x08, 0xE8, 0x25, 0x44, 0xF0, 0x6A, 0xCC, + 0x38, 0x07, 0x80, 0x00, 0x40, 0xF0, 0x3C, 0x00, 0x4A, 0x00, 0x3C, 0x00, 0x08, 0x0E, 0x14, 0x1A, + 0x20, 0x26, 0x2C, 0x32, 0x44, 0x03, 0xF2, 0x0C, 0xD5, 0x15, 0x44, 0x03, 0xF2, 0x0E, 0xD5, 0x12, + 0x44, 0x03, 0xF2, 0x10, 0xD5, 0x0F, 0x44, 0x03, 0xF2, 0x12, 0xD5, 0x0C, 0x44, 0x03, 0xF2, 0x14, + 0xD5, 0x09, 0x44, 0x03, 0xF2, 0x16, 0xD5, 0x06, 0x44, 0x03, 0xF2, 0x18, 0xD5, 0x03, 0x44, 0x03, + 0xF2, 0x1A, 0xAE, 0x40, 0xDD, 0x9E, 0x92, 0x00, 0xE6, 0x08, 0xE8, 0x25, 0x44, 0xF0, 0x6B, 0x1C, + 0x38, 0x07, 0x80, 0x00, 0x40, 0xF0, 0x3C, 0x00, 0x4A, 0x00, 0x3C, 0x00, 0x08, 0x0E, 0x14, 0x1A, + 0x20, 0x26, 0x2C, 0x32, 0x44, 0x03, 0xF2, 0x0D, 0xD5, 0x15, 0x44, 0x03, 0xF2, 0x0F, 0xD5, 0x12, + 0x44, 0x03, 0xF2, 0x11, 0xD5, 0x0F, 0x44, 0x03, 0xF2, 0x13, 0xD5, 0x0C, 0x44, 0x03, 0xF2, 0x15, + 0xD5, 0x09, 0x44, 0x03, 0xF2, 0x17, 0xD5, 0x06, 0x44, 0x03, 0xF2, 0x19, 0xD5, 0x03, 0x44, 0x03, + 0xF2, 0x1B, 0xAE, 0x40, 0xDD, 0x9E, 0x92, 0x00, 0x44, 0x03, 0xF0, 0xC4, 0xA6, 0x00, 0xDD, 0x9E, + 0x44, 0x13, 0xF0, 0xC4, 0x96, 0x00, 0xAE, 0x08, 0xDD, 0x9E, 0x44, 0x03, 0xF0, 0xC3, 0xA6, 0x00, + 0xDD, 0x9E, 0x44, 0x13, 0xF0, 0xC3, 0x96, 0x00, 0xAE, 0x08, 0xDD, 0x9E, 0x44, 0x03, 0xF0, 0xCE, + 0x44, 0x13, 0xF0, 0xD0, 0xA4, 0x00, 0xA6, 0x48, 0x94, 0x07, 0xFE, 0x0F, 0x44, 0x1D, 0xD3, 0x00, + 0x88, 0x01, 0x5C, 0x00, 0x00, 0x80, 0xDD, 0x9E, 0x44, 0x03, 0xF0, 0xCE, 0x44, 0x13, 0xF0, 0xD0, + 0xA4, 0x00, 0xA6, 0x48, 0x94, 0x07, 0xFE, 0x0F, 0x44, 0x1D, 0xD2, 0xB0, 0x88, 0x01, 0x5C, 0x00, + 0x00, 0x01, 0xDD, 0x9E, 0x44, 0x02, 0x2D, 0x00, 0xDD, 0x9E, 0x44, 0x13, 0xF0, 0xE6, 0xAC, 0x08, + 0xDD, 0x9E, 0x44, 0x03, 0xF0, 0xF5, 0x84, 0x21, 0xAE, 0x40, 0x44, 0x13, 0xF0, 0x4A, 0x44, 0x20, + 0x00, 0x55, 0xAE, 0x88, 0xA6, 0x40, 0x5A, 0x10, 0x01, 0xFF, 0xDD, 0x9E, 0x44, 0x03, 0xF0, 0xF4, + 0xA6, 0x00, 0x92, 0x04, 0xDD, 0x9E, 0x44, 0x03, 0xF0, 0xF7, 0xA6, 0x00, 0xDD, 0x9E, 0x44, 0x13, + 0xF0, 0xF7, 0x96, 0x00, 0xAE, 0x08, 0xDD, 0x9E, 0x44, 0x03, 0xF0, 0xF6, 0xA6, 0x00, 0xDD, 0x9E, + 0x44, 0x13, 0xF0, 0xF6, 0x96, 0x00, 0xAE, 0x08, 0xDD, 0x9E, 0x44, 0x52, 0x2D, 0x00, 0x44, 0x12, + 0x2D, 0x3E, 0x18, 0x02, 0x80, 0x01, 0xD9, 0xFE, 0xDD, 0x9E, 0x3A, 0x6F, 0xA8, 0xBC, 0x44, 0x00, + 0x00, 0xFD, 0x49, 0xFF, 0xFF, 0xF4, 0x44, 0x03, 0xF0, 0x4B, 0x84, 0x3F, 0xAE, 0x40, 0x80, 0xC0, + 0x80, 0xE1, 0x44, 0x93, 0xF0, 0x68, 0xAF, 0xF0, 0x00, 0x04, 0x80, 0x00, 0x52, 0x00, 0x00, 0x01, + 0x49, 0xFF, 0xFC, 0x22, 0xFA, 0x09, 0x49, 0x00, 0x13, 0xD1, 0x00, 0x04, 0x80, 0x00, 0x52, 0x00, + 0x00, 0x01, 0x49, 0xFF, 0xFC, 0x19, 0x44, 0x00, 0x04, 0x92, 0x49, 0x00, 0x13, 0xC7, 0xD5, 0xEC, + 0x3B, 0xFF, 0xFC, 0xBC, 0xEF, 0xFC, 0x49, 0xFF, 0xFF, 0xDA, 0x92, 0x00, 0x44, 0x23, 0xF0, 0xC7, + 0xA6, 0x50, 0x96, 0x48, 0x5A, 0x08, 0x01, 0x05, 0x58, 0x10, 0x80, 0xC0, 0xD5, 0x02, 0x96, 0x6F, + 0xAE, 0x50, 0xDD, 0x9E, 0x44, 0x03, 0xF0, 0xCE, 0x44, 0x10, 0x04, 0x5A, 0xAC, 0x40, 0x44, 0x03, + 0xF0, 0xD0, 0x84, 0x20, 0xAE, 0x40, 0x84, 0x01, 0x48, 0xFF, 0xFF, 0xEA, 0x44, 0x23, 0xF0, 0xEC, + 0x96, 0x06, 0xA6, 0x50, 0x94, 0x02, 0x54, 0x10, 0x80, 0xFB, 0xFE, 0x0F, 0xAE, 0x10, 0xDD, 0x9E, + 0x48, 0xFF, 0xFF, 0xF6, 0x44, 0x13, 0xF0, 0x50, 0xA6, 0x08, 0x58, 0x00, 0x00, 0x80, 0xAE, 0x08, + 0xDD, 0x9E, 0x44, 0x13, 0xF0, 0x50, 0xA6, 0x08, 0x96, 0x37, 0xAE, 0x08, 0xDD, 0x9E, 0x44, 0x23, + 0xF0, 0x50, 0x96, 0x17, 0xA6, 0x50, 0x54, 0x10, 0x80, 0xF8, 0xFE, 0x47, 0xAE, 0x50, 0xDD, 0x9E, + 0x44, 0x23, 0xF0, 0x50, 0x96, 0x17, 0xA6, 0x50, 0x94, 0x04, 0x54, 0x10, 0x80, 0x8F, 0xFE, 0x47, + 0xAE, 0x50, 0xDD, 0x9E, 0x44, 0x13, 0xF0, 0x51, 0xA6, 0x08, 0x58, 0x00, 0x00, 0x01, 0xAE, 0x08, + 0xDD, 0x9E, 0xFC, 0x00, 0x84, 0x07, 0x49, 0xFF, 0xFF, 0xE4, 0x44, 0x03, 0xF0, 0x4C, 0x84, 0x20, + 0xAE, 0x40, 0x84, 0x07, 0x49, 0xFF, 0xFF, 0xE6, 0x44, 0x03, 0xF0, 0x4E, 0x84, 0x21, 0xAE, 0x40, + 0x49, 0xFF, 0xFF, 0xEA, 0xFC, 0x80, 0x3C, 0x0F, 0xFF, 0xEC, 0xDD, 0x9E, 0x3C, 0x0D, 0xFF, 0xEC, + 0xA6, 0x00, 0xDD, 0x9E, 0x44, 0x02, 0x40, 0x00, 0x44, 0x12, 0x45, 0x10, 0x3C, 0x0F, 0xFB, 0x63, + 0x3C, 0x1F, 0xFB, 0x48, 0x3C, 0x0F, 0xFB, 0x4B, 0xDD, 0x9E, 0xC0, 0x04, 0x5A, 0x00, 0x02, 0x09, + 0xDD, 0x9E, 0x3C, 0x0D, 0xFF, 0xEC, 0xA6, 0x00, 0x3C, 0x0F, 0xFA, 0x75, 0xDD, 0x9E, 0x3C, 0x1F, + 0xFA, 0x75, 0xDD, 0x9E, 0x40, 0x00, 0x3C, 0x08, 0x44, 0x33, 0xF1, 0xC4, 0x92, 0x10, 0xAC, 0x18, + 0x40, 0x10, 0xBC, 0x08, 0x44, 0x03, 0xF1, 0xC6, 0x92, 0x30, 0xAC, 0x40, 0x40, 0x21, 0x3C, 0x08, + 0x44, 0x03, 0xF1, 0xC8, 0x92, 0x50, 0xAC, 0x80, 0xDD, 0x9E, 0xFC, 0x00, 0x44, 0x02, 0x8F, 0x70, + 0x00, 0x20, 0x00, 0x0F, 0x00, 0x10, 0x00, 0x10, 0x44, 0x03, 0xF1, 0xC2, 0xAE, 0x80, 0x44, 0x03, + 0xF1, 0xC3, 0xAE, 0x40, 0x3C, 0x0D, 0xFB, 0x63, 0x3C, 0x1D, 0xFB, 0x48, 0x3C, 0x2D, 0xFB, 0x4B, + 0x49, 0xFF, 0xFF, 0xDA, 0xFC, 0x80, 0x84, 0x00, 0x3C, 0x0F, 0xFB, 0x84, 0x44, 0x03, 0xF1, 0xC0, + 0x84, 0x21, 0xAE, 0x40, 0xDD, 0x9E, 0xFC, 0x06, 0x49, 0xFF, 0xFF, 0xE1, 0x3C, 0x0D, 0xFA, 0x75, + 0x5A, 0x00, 0x0F, 0x13, 0x44, 0x13, 0xF1, 0xC1, 0x96, 0x00, 0xAE, 0x08, 0x49, 0xFF, 0xFF, 0xED, + 0x44, 0x03, 0xF0, 0x4A, 0x44, 0x10, 0x00, 0x55, 0xAE, 0x40, 0x44, 0x13, 0xF1, 0xC0, 0xA6, 0x08, + 0x5A, 0x00, 0x01, 0xFF, 0xD5, 0x1B, 0xFA, 0x20, 0x2E, 0x37, 0xC6, 0xC7, 0xF1, 0x85, 0x84, 0x22, + 0x84, 0x00, 0x84, 0xA1, 0xF1, 0x87, 0x44, 0x12, 0x40, 0x00, 0xF0, 0x83, 0xF0, 0x84, 0xF0, 0x86, + 0xF0, 0x88, 0xF0, 0x89, 0x2E, 0x47, 0xC6, 0xC8, 0xB6, 0x7F, 0xF5, 0x81, 0xF3, 0x82, 0xF5, 0x8A, + 0x44, 0x02, 0x45, 0x10, 0x80, 0x41, 0x49, 0xFF, 0xF9, 0x59, 0xFC, 0x86, 0xFC, 0x00, 0x84, 0x20, + 0x49, 0x00, 0x2B, 0xAA, 0x84, 0x01, 0x49, 0xFF, 0xE2, 0x1D, 0x84, 0x01, 0x84, 0x40, 0x84, 0x2A, + 0x80, 0x80, 0x80, 0x62, 0x80, 0xA2, 0x49, 0x00, 0x27, 0xEF, 0x44, 0x03, 0xF0, 0x4A, 0x44, 0x10, + 0x00, 0x55, 0xAE, 0x40, 0x49, 0xFF, 0xE1, 0xF4, 0xC8, 0x04, 0x3C, 0x0D, 0xFB, 0x87, 0xC0, 0xFB, + 0xFC, 0x80, 0x2E, 0x17, 0xEC, 0x1C, 0x5A, 0x10, 0xFF, 0x38, 0x44, 0x22, 0xDE, 0xEC, 0x38, 0x31, + 0x05, 0x01, 0xE2, 0x60, 0xE9, 0x31, 0xFC, 0x20, 0x84, 0x00, 0x38, 0x01, 0x05, 0x09, 0x3C, 0x0B, + 0xF6, 0x5F, 0x84, 0x20, 0x84, 0x83, 0x2E, 0x07, 0xC6, 0xBB, 0x94, 0x01, 0xE0, 0x20, 0xE8, 0x23, + 0x3C, 0x3C, 0x02, 0xAC, 0x3C, 0x0C, 0x02, 0xAD, 0x3C, 0x5C, 0x02, 0xB5, 0x94, 0x89, 0x88, 0x62, + 0x88, 0x02, 0x88, 0xA1, 0xA5, 0x98, 0xA5, 0xC0, 0xA6, 0x28, 0x88, 0x07, 0x42, 0x03, 0x10, 0x73, + 0x40, 0x50, 0x08, 0x09, 0x97, 0x69, 0xAD, 0x58, 0x3C, 0x5C, 0x02, 0xAC, 0x3C, 0x3C, 0x02, 0xB5, + 0x88, 0x45, 0x88, 0x61, 0xA4, 0x90, 0x8C, 0x21, 0x94, 0x92, 0x8A, 0x02, 0x96, 0x00, 0xAE, 0x18, + 0x96, 0x48, 0xD5, 0xDA, 0xFC, 0xA0, 0xDD, 0x9E, 0xFC, 0x00, 0x5A, 0x08, 0x01, 0x0D, 0x2E, 0x10, + 0x0D, 0x06, 0x2E, 0x00, 0x0C, 0xF5, 0x40, 0x00, 0x80, 0x17, 0x5C, 0x10, 0x80, 0x03, 0x49, 0xFF, + 0xFA, 0xEC, 0xD5, 0x03, 0x49, 0xFF, 0xFA, 0xFA, 0xFC, 0x80, 0xFC, 0x00, 0x49, 0xFF, 0xFB, 0x0C, + 0x5A, 0x08, 0x02, 0x0B, 0x2E, 0x07, 0xEC, 0x1F, 0xC8, 0x04, 0x2E, 0x07, 0xCB, 0x36, 0xD5, 0x06, + 0x2E, 0x07, 0xCB, 0x37, 0xD5, 0x03, 0x2E, 0x07, 0xCB, 0x38, 0xFC, 0x80, 0x54, 0x00, 0x00, 0xFD, + 0x5A, 0x08, 0x04, 0x05, 0x3C, 0x03, 0xFF, 0xDB, 0xDD, 0x9E, 0x3C, 0x03, 0xE5, 0xA3, 0xDD, 0x9E, + 0x5A, 0x08, 0x04, 0x05, 0x3C, 0x03, 0xFF, 0xDA, 0xDD, 0x9E, 0x3C, 0x03, 0xE5, 0xA4, 0xDD, 0x9E, + 0xA4, 0x00, 0x92, 0x0C, 0x96, 0x06, 0x5A, 0x08, 0x01, 0x0C, 0x2E, 0x07, 0xC7, 0x5B, 0x5A, 0x08, + 0x01, 0x08, 0x44, 0x00, 0x00, 0x96, 0x3C, 0x0B, 0xFF, 0xDB, 0x84, 0x03, 0xD5, 0x07, 0x3C, 0x03, + 0xE5, 0xA1, 0x3C, 0x0B, 0xFF, 0xDB, 0x3C, 0x03, 0xE5, 0xA2, 0x3C, 0x0B, 0xFF, 0xDA, 0xDD, 0x9E, + 0x2E, 0x17, 0xEC, 0x16, 0xC9, 0x07, 0x3E, 0x17, 0xEC, 0x2C, 0x3E, 0x17, 0xEC, 0x31, 0x10, 0x10, + 0x00, 0x1C, 0xDD, 0x9E, 0xFC, 0x00, 0x44, 0x03, 0xF0, 0x4A, 0x44, 0x10, 0x00, 0x55, 0xAE, 0x40, + 0x3C, 0x0D, 0xFB, 0x87, 0xC8, 0x12, 0x2E, 0x07, 0xEC, 0x29, 0x5A, 0x08, 0x01, 0x06, 0x44, 0x02, + 0xB5, 0x64, 0x49, 0x00, 0x27, 0xB4, 0x84, 0x01, 0x84, 0x40, 0x80, 0x20, 0x80, 0x62, 0x80, 0x80, + 0x80, 0xA2, 0x49, 0x00, 0x27, 0x39, 0xD5, 0xED, 0x2E, 0x27, 0xED, 0xA0, 0xCA, 0x0A, 0x84, 0x02, + 0x2E, 0x17, 0xCB, 0x39, 0x84, 0x61, 0x84, 0x83, 0x80, 0xA2, 0x49, 0x00, 0x27, 0x2D, 0xD5, 0x04, + 0x84, 0x0E, 0x49, 0x00, 0x27, 0x5A, 0xFC, 0x80, 0xFC, 0x00, 0x49, 0xFF, 0xFA, 0x9D, 0x5A, 0x08, + 0x02, 0x0E, 0x44, 0x03, 0xF4, 0x22, 0x2E, 0x17, 0xCB, 0x52, 0xA6, 0x00, 0x96, 0x1F, 0xE2, 0x20, + 0xE9, 0x07, 0xC0, 0x06, 0x8E, 0x01, 0x96, 0x00, 0xD5, 0x05, 0x84, 0x00, 0xD5, 0x03, 0x44, 0x00, + 0x00, 0xFF, 0xFC, 0x80, 0x2E, 0x07, 0xEC, 0x1C, 0x5A, 0x00, 0xFF, 0x2F, 0x2E, 0x07, 0xEC, 0x0E, + 0x5A, 0x00, 0x01, 0x2B, 0xFC, 0x20, 0x44, 0x02, 0xD3, 0x40, 0x49, 0x00, 0x26, 0xBF, 0x2E, 0x17, + 0xEC, 0x1C, 0x84, 0x01, 0x40, 0x00, 0x04, 0x0C, 0x2E, 0x17, 0xEC, 0x3A, 0x3C, 0x4C, 0x02, 0xAC, + 0xFE, 0x0F, 0x3E, 0x07, 0xEC, 0x3A, 0x3C, 0x5C, 0x02, 0xAB, 0x3C, 0x6C, 0x02, 0xAD, 0x84, 0x00, + 0x2E, 0x17, 0xC6, 0xBB, 0x94, 0x49, 0xE0, 0x01, 0xE8, 0x0E, 0x94, 0x41, 0x98, 0xE9, 0x99, 0xE1, + 0xA4, 0x98, 0x88, 0x26, 0x96, 0x91, 0xAC, 0xB8, 0xA4, 0x98, 0x8C, 0x01, 0x96, 0x91, 0xAC, 0x88, + 0x96, 0x00, 0xD5, 0xEF, 0xFC, 0xA0, 0xDD, 0x9E, 0x2E, 0x07, 0xEC, 0x1C, 0x84, 0x20, 0x50, 0x00, + 0x7F, 0x01, 0x40, 0x00, 0x80, 0x06, 0xDD, 0x9E, 0xFC, 0x00, 0x3C, 0x0D, 0xFB, 0x4A, 0x84, 0x23, + 0xAE, 0x41, 0x49, 0xFF, 0xE3, 0x44, 0x2E, 0x07, 0xEC, 0x66, 0x84, 0x23, 0x49, 0xFF, 0xE3, 0x92, + 0x3C, 0x1D, 0xFB, 0x64, 0x84, 0x01, 0xAE, 0x08, 0x3C, 0x1D, 0xFB, 0x59, 0xAE, 0x08, 0x2E, 0x07, + 0xEC, 0x75, 0x5A, 0x00, 0x03, 0x08, 0x2E, 0x07, 0xEC, 0x1D, 0xC8, 0x04, 0x84, 0x04, 0x3E, 0x07, + 0xEC, 0x75, 0x2E, 0x07, 0xEC, 0x6C, 0xC8, 0x06, 0x3C, 0x03, 0xE5, 0x9A, 0xC0, 0x04, 0x8E, 0x01, + 0xD5, 0x02, 0x84, 0x00, 0x3C, 0x0E, 0x01, 0x87, 0x84, 0x01, 0x3E, 0x07, 0xEC, 0x6E, 0xFC, 0x80, + 0xFC, 0x00, 0x84, 0x00, 0x3C, 0x0F, 0xFB, 0x8A, 0x3C, 0x0F, 0xFB, 0x85, 0x84, 0x01, 0x49, 0xFF, + 0xE0, 0xC9, 0x44, 0x03, 0xF0, 0x4A, 0x44, 0x10, 0x00, 0x55, 0xAE, 0x40, 0x2E, 0x00, 0x0D, 0x06, + 0x3C, 0x1D, 0xFB, 0x8A, 0x8C, 0x01, 0xE2, 0x20, 0xE8, 0x0A, 0x84, 0x01, 0x84, 0x40, 0x80, 0x20, + 0x80, 0x62, 0x80, 0x80, 0x80, 0xA2, 0x49, 0x00, 0x26, 0x8F, 0xD5, 0xF1, 0x44, 0x03, 0xF0, 0x4A, + 0x44, 0x10, 0x00, 0x55, 0xAE, 0x40, 0x49, 0xFF, 0xE0, 0x93, 0x80, 0x40, 0xC8, 0x09, 0x84, 0x01, + 0x80, 0x20, 0x80, 0x62, 0x80, 0x80, 0x80, 0xA2, 0x49, 0x00, 0x26, 0x7E, 0xD5, 0xF5, 0xFC, 0x80, + 0xFC, 0x00, 0x3C, 0x0D, 0xFB, 0x4A, 0xA6, 0x01, 0x54, 0x00, 0x00, 0xFD, 0x5A, 0x08, 0x08, 0x11, + 0x2E, 0x07, 0xEC, 0x75, 0x5A, 0x00, 0x03, 0x05, 0x84, 0x04, 0x3E, 0x07, 0xEC, 0x75, 0x2E, 0x07, + 0xEC, 0x6C, 0xC8, 0x06, 0x3C, 0x03, 0xE4, 0x52, 0xC0, 0x04, 0x8E, 0x01, 0xD5, 0x02, 0x84, 0x00, + 0x3C, 0x0E, 0x01, 0x87, 0x84, 0x01, 0x3E, 0x00, 0x06, 0x2C, 0x3E, 0x07, 0xEC, 0x2C, 0x49, 0x00, + 0x0A, 0x4A, 0x49, 0xFF, 0xD0, 0xB9, 0x3C, 0x0D, 0xFB, 0x4A, 0xA6, 0x41, 0x5A, 0x18, 0x07, 0x07, + 0x84, 0x29, 0xAE, 0x41, 0x49, 0xFF, 0xE2, 0xC3, 0xD5, 0x0F, 0x84, 0x20, 0x49, 0x00, 0x29, 0xFC, + 0x3C, 0x0D, 0xFB, 0x4A, 0x84, 0x29, 0xAE, 0x41, 0x49, 0xFF, 0xE2, 0xB9, 0x49, 0xFF, 0xF1, 0x63, + 0x84, 0x0E, 0x49, 0x00, 0x26, 0x72, 0x3C, 0x0D, 0xFB, 0x59, 0x84, 0x21, 0xAE, 0x40, 0xFC, 0x80, + 0x5C, 0x00, 0x00, 0x03, 0xDD, 0x9E, 0x2E, 0x27, 0xC6, 0xBB, 0x3C, 0x4C, 0x02, 0xAE, 0x94, 0x91, + 0x3C, 0x53, 0xE5, 0x9D, 0x84, 0x01, 0x84, 0x20, 0xE0, 0x22, 0xE8, 0x0B, 0x94, 0xC9, 0x88, 0x64, + 0xA4, 0xD8, 0x96, 0xDB, 0xE0, 0xA3, 0xE8, 0x02, 0x84, 0x00, 0x8C, 0x21, 0x96, 0x48, 0xD5, 0xF5, + 0xDD, 0x9E, 0x84, 0x20, 0x44, 0x22, 0xDE, 0xEC, 0x38, 0x01, 0x05, 0x09, 0x8C, 0x21, 0x5A, 0x18, + 0x08, 0xFD, 0xDD, 0x9E, 0xFC, 0x20, 0x80, 0xE0, 0xA6, 0x00, 0x80, 0xC2, 0x5A, 0x08, 0x04, 0x20, + 0x84, 0x01, 0xAE, 0x38, 0x3C, 0x0D, 0xFB, 0x4A, 0xA6, 0x01, 0x49, 0xFF, 0xFE, 0x89, 0x49, 0xFF, + 0xFF, 0xEA, 0x3C, 0x13, 0xF6, 0x45, 0xE6, 0x2A, 0xE8, 0x05, 0x8C, 0x21, 0x3C, 0x1B, 0xF6, 0x45, + 0xD5, 0x15, 0x84, 0x00, 0x3C, 0x0B, 0xF6, 0x45, 0xA4, 0x70, 0xE6, 0x39, 0xE8, 0x05, 0xAE, 0x38, + 0x84, 0x00, 0x49, 0xFF, 0xFF, 0xD8, 0x84, 0x00, 0xAC, 0x30, 0xD5, 0x08, 0x84, 0x00, 0x49, 0xFF, + 0xFF, 0xD2, 0x84, 0x00, 0xAC, 0x30, 0x3C, 0x0B, 0xF6, 0x45, 0xFC, 0xA0, 0xFC, 0x01, 0x3C, 0x0D, + 0xFB, 0x4A, 0xA6, 0x01, 0x49, 0xFF, 0xFE, 0x64, 0xF0, 0x81, 0xF1, 0x01, 0x44, 0x02, 0xB5, 0x2D, + 0x44, 0x22, 0xB5, 0x76, 0x49, 0xFF, 0xFF, 0xC8, 0x2E, 0x17, 0xEC, 0x75, 0x84, 0x00, 0x3C, 0x0B, + 0xF6, 0x4E, 0x3E, 0x07, 0xEC, 0x36, 0xC9, 0x03, 0x3E, 0x07, 0xEC, 0x3A, 0x84, 0x00, 0x3E, 0x07, + 0xEC, 0x3D, 0x3E, 0x07, 0xEC, 0x1C, 0x3E, 0x07, 0xEC, 0x33, 0x44, 0x0F, 0xFF, 0xAA, 0x3E, 0x07, + 0xEC, 0x2A, 0x3C, 0x0D, 0xFB, 0x59, 0x84, 0x21, 0xAE, 0x40, 0xFC, 0x81, 0xFC, 0x20, 0x2E, 0x07, + 0xEC, 0x0E, 0x80, 0xC1, 0x2E, 0x77, 0xEC, 0x1C, 0x5A, 0x08, 0x01, 0x18, 0x49, 0xFF, 0xF9, 0x34, + 0x5A, 0x08, 0x02, 0x14, 0x84, 0x00, 0x2E, 0x17, 0xC6, 0xBB, 0x94, 0x49, 0xE0, 0x01, 0xE8, 0x17, + 0x83, 0x86, 0x94, 0x41, 0xBA, 0x09, 0xBB, 0x0B, 0x88, 0x41, 0x88, 0x23, 0x8C, 0x01, 0xA4, 0x48, + 0x96, 0x00, 0x96, 0x49, 0xAC, 0x50, 0xD5, 0xF0, 0x44, 0x02, 0xDE, 0xEC, 0x44, 0x10, 0xFF, 0xFF, + 0x38, 0x50, 0x1D, 0x01, 0xD1, 0x04, 0x8C, 0xA1, 0x38, 0x50, 0x1D, 0x09, 0x2E, 0x17, 0xEC, 0x3A, + 0x40, 0x00, 0x9C, 0x0E, 0x96, 0x06, 0xC8, 0x1D, 0x2E, 0x27, 0xC6, 0xBB, 0x94, 0x91, 0xE0, 0x02, + 0xE8, 0x12, 0x83, 0x86, 0x94, 0x81, 0xBB, 0x0A, 0x8C, 0x01, 0x99, 0x1A, 0xBB, 0x09, 0x96, 0x00, + 0x88, 0x62, 0xA5, 0x58, 0x97, 0x69, 0xAD, 0x60, 0xBC, 0x0B, 0xA4, 0xD8, 0x88, 0x44, 0x96, 0xD9, + 0xAC, 0xD0, 0xD5, 0xEB, 0x84, 0x01, 0x40, 0x00, 0x1C, 0x0C, 0xFE, 0x0F, 0x3E, 0x07, 0xEC, 0x3A, + 0xFC, 0xA0, 0xFC, 0x00, 0x2E, 0x27, 0xCB, 0x52, 0x44, 0x10, 0x00, 0xFF, 0x40, 0x20, 0x88, 0x0C, + 0x44, 0x13, 0xF4, 0x22, 0xFE, 0x93, 0xA6, 0x48, 0x96, 0x90, 0x96, 0x5F, 0xC1, 0x03, 0x8E, 0x21, + 0x96, 0x48, 0xA7, 0x80, 0x84, 0xA1, 0x40, 0x42, 0x84, 0x0C, 0xFF, 0x37, 0x97, 0x22, 0x96, 0xE0, + 0xAE, 0xC0, 0x4C, 0x61, 0x80, 0x0D, 0x4C, 0x31, 0x00, 0x0B, 0x88, 0x25, 0x40, 0x52, 0x84, 0x0C, + 0xFF, 0x67, 0x97, 0x68, 0xFF, 0x5D, 0x5C, 0x02, 0x80, 0x01, 0xD5, 0x02, 0x80, 0x05, 0xFC, 0x80, + 0xFC, 0x01, 0x84, 0x00, 0x3C, 0x0B, 0xF6, 0x4E, 0x3C, 0x0B, 0xF6, 0x5F, 0x12, 0x0F, 0x80, 0x03, + 0x3E, 0x07, 0xEC, 0x31, 0x3C, 0x0D, 0xFB, 0x4A, 0xA6, 0x01, 0x5A, 0x08, 0x04, 0x1F, 0x2E, 0x07, + 0xEC, 0x75, 0xC8, 0x21, 0x44, 0x02, 0xB4, 0xF2, 0x49, 0xFF, 0xFF, 0xC5, 0x80, 0x60, 0x5A, 0x08, + 0x01, 0x1B, 0x2E, 0x17, 0xCB, 0x52, 0x2E, 0x27, 0xC6, 0xC8, 0x50, 0x0F, 0x80, 0x06, 0xFE, 0x8C, + 0x96, 0x90, 0x44, 0x12, 0xD1, 0x84, 0x49, 0x00, 0x27, 0x89, 0x2E, 0x07, 0xEC, 0x7B, 0xC8, 0x03, + 0x84, 0x03, 0xD5, 0x07, 0x84, 0x01, 0xD5, 0x05, 0x2E, 0x07, 0xEC, 0x2C, 0xC8, 0xF7, 0x84, 0x02, + 0x3E, 0x07, 0xEC, 0x75, 0x2E, 0x07, 0xEC, 0x75, 0x5A, 0x08, 0x02, 0x05, 0x84, 0x00, 0x3E, 0x07, + 0xEB, 0xFC, 0x84, 0x00, 0x80, 0x60, 0x44, 0x42, 0xD1, 0x3C, 0x2E, 0x17, 0xC6, 0xBB, 0x94, 0x49, + 0xE0, 0x01, 0xE8, 0x1D, 0x3C, 0x5C, 0x02, 0xAB, 0x94, 0x41, 0x88, 0xA1, 0x3C, 0x2C, 0x02, 0xAD, + 0xA5, 0x68, 0x88, 0x41, 0x97, 0x69, 0xAD, 0x50, 0x3C, 0x2C, 0x02, 0xAC, 0x3C, 0x5C, 0x02, 0xAD, + 0x88, 0x41, 0x88, 0x25, 0xA4, 0x48, 0x96, 0x49, 0xAC, 0x50, 0x3C, 0x1C, 0x02, 0xB5, 0x88, 0x20, + 0xAE, 0xC8, 0x38, 0x32, 0x00, 0x08, 0x8C, 0x01, 0x96, 0x00, 0xD5, 0xE0, 0xFC, 0x81, 0xFC, 0x40, + 0x3C, 0x6C, 0x02, 0xAE, 0x40, 0x70, 0x88, 0x09, 0x40, 0x90, 0x04, 0x08, 0x2E, 0x57, 0xEC, 0x31, + 0x84, 0x40, 0x50, 0xA0, 0x7F, 0xFF, 0xE0, 0x49, 0xE8, 0x30, 0x94, 0xD1, 0x99, 0x33, 0xA5, 0x20, + 0x97, 0x23, 0xE0, 0x24, 0xE8, 0x27, 0xE2, 0x40, 0x84, 0x9F, 0xE8, 0x02, 0x84, 0x81, 0x81, 0x02, + 0x42, 0x80, 0x10, 0x73, 0x80, 0x88, 0x95, 0x21, 0x88, 0x86, 0xA5, 0x20, 0x97, 0x23, 0xE0, 0xE4, + 0xE8, 0x02, 0x84, 0xA1, 0x40, 0x81, 0x00, 0x97, 0x97, 0x20, 0xE0, 0x8A, 0xE8, 0x0B, 0x50, 0x81, + 0x80, 0x02, 0x89, 0x06, 0x02, 0xF4, 0x00, 0x00, 0x40, 0xF7, 0x80, 0x11, 0xE0, 0xEF, 0xE8, 0x02, + 0x84, 0xA1, 0xC4, 0x08, 0x8E, 0x62, 0x88, 0x66, 0xA4, 0xD8, 0x96, 0xDB, 0xE0, 0xE3, 0xE8, 0x02, + 0x84, 0xA1, 0x8C, 0x41, 0x96, 0x90, 0xD5, 0xD0, 0x3E, 0x57, 0xEC, 0x31, 0xFC, 0xC0, 0x2E, 0x27, + 0xEC, 0x1C, 0x5A, 0x28, 0xFF, 0x04, 0x48, 0x00, 0x00, 0xA2, 0xFC, 0x43, 0x80, 0xC1, 0x80, 0xE0, + 0x44, 0x12, 0xD3, 0x40, 0x44, 0x02, 0xB4, 0xF5, 0x49, 0xFF, 0xFE, 0xE2, 0x84, 0x60, 0x44, 0x00, + 0xFF, 0xFF, 0xA8, 0xF2, 0xA8, 0x33, 0x2E, 0x17, 0xCB, 0x4A, 0xE6, 0x30, 0xE8, 0x04, 0x52, 0x30, + 0x80, 0x10, 0x96, 0xD8, 0xE6, 0x31, 0x80, 0x01, 0xE9, 0x02, 0xFA, 0x00, 0x55, 0xC0, 0x00, 0xFF, + 0xA6, 0x39, 0x5A, 0x08, 0x08, 0x05, 0x3C, 0x13, 0xE5, 0x9D, 0xD5, 0x03, 0x3C, 0x13, 0xE5, 0x9E, + 0x3C, 0x0C, 0x02, 0xAD, 0x84, 0x40, 0xF0, 0x81, 0x3C, 0x0C, 0x02, 0xAB, 0x3C, 0x8C, 0x02, 0xAC, + 0xF0, 0x82, 0x3C, 0x0C, 0x02, 0xAE, 0x2E, 0x97, 0xEB, 0xFC, 0xF0, 0x83, 0x2E, 0x07, 0xEC, 0x2C, + 0x44, 0x52, 0xD1, 0x3C, 0xF0, 0x84, 0x2E, 0x07, 0xEC, 0x75, 0x83, 0xC2, 0xF0, 0x85, 0x2E, 0x07, + 0xC6, 0xBB, 0x95, 0x01, 0xE0, 0x44, 0xE8, 0x54, 0xF0, 0x01, 0x95, 0x11, 0x04, 0xAF, 0x80, 0x02, + 0x88, 0x04, 0x89, 0x44, 0xA5, 0xC0, 0x02, 0xA5, 0x00, 0x00, 0xFF, 0xDC, 0x42, 0x75, 0x70, 0x73, + 0x92, 0xE4, 0x97, 0xF9, 0xAD, 0xC0, 0xF7, 0x03, 0x40, 0xA3, 0x90, 0x00, 0x88, 0x88, 0xA5, 0xC0, + 0x02, 0xF2, 0x00, 0x00, 0x8A, 0xEF, 0x97, 0xFB, 0x12, 0x75, 0x00, 0x00, 0x2E, 0x77, 0xC7, 0x61, + 0x5A, 0x78, 0x01, 0x28, 0x02, 0x75, 0x00, 0x00, 0x40, 0xA3, 0x80, 0x11, 0x3C, 0x73, 0xE5, 0x9F, + 0xFF, 0xFA, 0xE1, 0x47, 0xE8, 0x18, 0xF7, 0x04, 0x5A, 0x70, 0x01, 0x05, 0xF7, 0x05, 0x5A, 0x78, + 0x02, 0x13, 0x38, 0x72, 0x88, 0x00, 0x3C, 0xA3, 0xE5, 0xA0, 0x8C, 0xE1, 0x97, 0xF8, 0xE3, 0x47, + 0x38, 0x72, 0x88, 0x08, 0xE8, 0x0E, 0xA5, 0xC0, 0x85, 0x21, 0x97, 0xF9, 0xAD, 0xE0, 0x39, 0xE2, + 0x88, 0x08, 0xD5, 0x07, 0x38, 0x42, 0x88, 0x00, 0xC4, 0x04, 0x8E, 0x81, 0x38, 0x42, 0x88, 0x08, + 0xA5, 0xC0, 0xA1, 0x32, 0xE2, 0x87, 0xE8, 0x03, 0xA5, 0x00, 0xA9, 0x32, 0xA5, 0xC0, 0xA1, 0x33, + 0xE2, 0xE4, 0xE8, 0x03, 0xA4, 0x00, 0xA8, 0x33, 0x8C, 0x41, 0x96, 0x90, 0xD5, 0xA9, 0x3E, 0x97, + 0xEB, 0xFC, 0x49, 0xFF, 0xFF, 0x26, 0x2E, 0x07, 0xEC, 0x1D, 0x5A, 0x08, 0x01, 0x07, 0x3E, 0x07, + 0xEC, 0x31, 0x84, 0x00, 0x3E, 0x07, 0xEC, 0x75, 0xFC, 0xC3, 0xDD, 0x9E, 0xFC, 0x40, 0x80, 0xE1, + 0x2E, 0x17, 0xEC, 0x75, 0x80, 0xC0, 0x5A, 0x10, 0x03, 0x18, 0xA6, 0x41, 0x5A, 0x18, 0x04, 0x13, + 0x2E, 0x07, 0xEC, 0x1F, 0x5A, 0x08, 0x01, 0x07, 0x84, 0x00, 0x3C, 0x0F, 0xFB, 0x85, 0x49, 0xFF, + 0xEE, 0xFF, 0x80, 0x06, 0x49, 0xFF, 0xFB, 0xFC, 0x44, 0x02, 0xD3, 0x40, 0x49, 0x00, 0x23, 0xAE, + 0xD5, 0x03, 0x49, 0xFF, 0xFB, 0xF5, 0x3C, 0x03, 0xF6, 0x5F, 0x44, 0x12, 0xD3, 0xE4, 0x8C, 0x01, + 0x3C, 0x0B, 0xF6, 0x5F, 0x3C, 0x03, 0xF6, 0x4E, 0x8C, 0x01, 0x3C, 0x0B, 0xF6, 0x4E, 0x80, 0x06, + 0x49, 0xFF, 0xFF, 0x2F, 0x49, 0xFF, 0xF7, 0x58, 0x5A, 0x08, 0x02, 0x15, 0x49, 0xFF, 0xFC, 0xB6, + 0xC8, 0x11, 0x2E, 0x17, 0xEC, 0x72, 0xC1, 0x0E, 0x3E, 0x07, 0xEC, 0x22, 0x49, 0x00, 0x10, 0xD8, + 0x2E, 0x07, 0xEC, 0x37, 0x5A, 0x08, 0x01, 0x04, 0x3E, 0x07, 0xEC, 0x11, 0x84, 0x00, 0x3E, 0x07, + 0xEC, 0x72, 0x2E, 0x07, 0xEC, 0x31, 0x5A, 0x08, 0x01, 0x17, 0x84, 0x00, 0x84, 0x40, 0x3E, 0x07, + 0xEC, 0x36, 0x44, 0x32, 0xDE, 0xEC, 0x2E, 0x07, 0xCB, 0x52, 0x80, 0x82, 0x96, 0x50, 0xE2, 0x20, + 0xE8, 0x05, 0x38, 0x41, 0x89, 0x09, 0x8C, 0x41, 0xD5, 0xFA, 0x44, 0x00, 0x00, 0x50, 0x49, 0x00, + 0x22, 0xB9, 0xD5, 0x1F, 0x2E, 0x07, 0xEC, 0x60, 0xC8, 0x1C, 0x3C, 0x03, 0xF6, 0x5D, 0xC8, 0x19, + 0x2E, 0x97, 0xEC, 0x2C, 0x5A, 0x98, 0x01, 0x16, 0x9E, 0x3C, 0xE6, 0x02, 0xE9, 0x12, 0x44, 0x02, + 0xD3, 0xE4, 0x3C, 0x13, 0xE3, 0xD3, 0x44, 0x22, 0xB4, 0xEE, 0x49, 0x00, 0x01, 0xE8, 0x5A, 0x08, + 0x02, 0x09, 0xFA, 0x01, 0x49, 0x00, 0x22, 0x9E, 0x3E, 0x97, 0xEC, 0x31, 0x3E, 0x97, 0xEC, 0x7C, + 0x2E, 0x07, 0xEC, 0x2C, 0xC8, 0x31, 0xA6, 0x30, 0x5A, 0x08, 0x02, 0x2F, 0x2E, 0x07, 0xEC, 0x75, + 0x5A, 0x00, 0x01, 0x0A, 0x2E, 0x07, 0xEB, 0xFC, 0x5A, 0x08, 0x01, 0x1C, 0x2E, 0x07, 0xEC, 0x4E, + 0x5A, 0x08, 0x01, 0x18, 0x49, 0xFF, 0xFD, 0x49, 0xC8, 0x06, 0x3E, 0x07, 0xEC, 0x31, 0x3C, 0x0B, + 0xF6, 0x5F, 0xD5, 0x0F, 0x84, 0x01, 0x84, 0xC0, 0x3E, 0x07, 0xEC, 0x2C, 0x3E, 0x60, 0x06, 0x12, + 0x49, 0x00, 0x13, 0xB3, 0x2E, 0x07, 0xEC, 0x75, 0x5A, 0x08, 0x02, 0x04, 0x3E, 0x67, 0xEC, 0x75, + 0x2E, 0x07, 0xEC, 0x75, 0x5A, 0x08, 0x02, 0x09, 0x2E, 0x07, 0xEC, 0x4E, 0x5A, 0x08, 0x02, 0x05, + 0x84, 0x00, 0x3E, 0x07, 0xEC, 0x31, 0x44, 0x0F, 0xFF, 0xAA, 0x3E, 0x07, 0xEC, 0x2A, 0x9E, 0x3C, + 0xE6, 0x02, 0xE8, 0x10, 0x44, 0x00, 0x00, 0xFF, 0x2E, 0x10, 0x06, 0x39, 0x49, 0x00, 0x4E, 0x6D, + 0x84, 0x00, 0x3E, 0x07, 0xEC, 0x31, 0x84, 0x00, 0x3C, 0x0B, 0xF6, 0x4E, 0x3C, 0x0B, 0xF6, 0x5F, + 0xD5, 0x06, 0x5A, 0x78, 0x02, 0x05, 0x84, 0x01, 0x3E, 0x07, 0xEC, 0x31, 0x2E, 0x07, 0xEC, 0x7B, + 0x5A, 0x08, 0x01, 0x04, 0x3E, 0x07, 0xEC, 0x7A, 0x2E, 0x07, 0xEC, 0x16, 0x5A, 0x08, 0x01, 0x06, + 0x3E, 0x07, 0xEC, 0x31, 0x3E, 0x07, 0xEC, 0x2C, 0xFC, 0xC0, 0xFC, 0x46, 0x44, 0x31, 0x31, 0x88, + 0x81, 0x42, 0x3A, 0x21, 0x94, 0x00, 0x3A, 0x2F, 0x94, 0x20, 0x44, 0x31, 0x31, 0x98, 0xB1, 0xC4, + 0x3A, 0x21, 0x94, 0x00, 0x3A, 0x23, 0x94, 0x20, 0x44, 0x31, 0x31, 0xA8, 0x50, 0x9F, 0x80, 0x20, + 0x3A, 0x21, 0x94, 0x00, 0x80, 0xDF, 0x3A, 0x24, 0x94, 0x20, 0x5A, 0xA8, 0x01, 0x05, 0x38, 0x24, + 0x82, 0x02, 0xD5, 0x03, 0x38, 0x23, 0x82, 0x02, 0x38, 0x53, 0x02, 0x02, 0x44, 0x32, 0x71, 0x40, + 0x94, 0x02, 0x88, 0x03, 0x2E, 0x47, 0xEC, 0x23, 0xA7, 0x80, 0x44, 0x0F, 0xFF, 0x38, 0xFF, 0x04, + 0x97, 0xB0, 0x97, 0x21, 0x84, 0x60, 0x44, 0x71, 0x22, 0x88, 0x98, 0x1F, 0x94, 0x01, 0x02, 0x90, + 0x00, 0x00, 0x38, 0x01, 0x94, 0x00, 0x8C, 0x61, 0x42, 0x04, 0x80, 0x24, 0x40, 0x00, 0x18, 0x0E, + 0x88, 0x04, 0x02, 0x91, 0x00, 0x00, 0x96, 0x03, 0x40, 0x00, 0x04, 0x16, 0x88, 0x09, 0x1A, 0x01, + 0x00, 0x01, 0x5A, 0x3A, 0x88, 0xEC, 0xFC, 0xC6, 0xFC, 0x42, 0x84, 0xC0, 0x3C, 0x0D, 0x9A, 0x40, + 0x3C, 0x6F, 0xFB, 0x8A, 0xF0, 0x83, 0x84, 0x01, 0x3E, 0x67, 0xEC, 0x31, 0x81, 0x06, 0x49, 0xFF, + 0xF8, 0x74, 0x81, 0x46, 0x3C, 0x6F, 0xFB, 0x85, 0x81, 0x26, 0x80, 0xE6, 0x5A, 0x68, 0x04, 0x11, + 0x2E, 0x07, 0xEC, 0x66, 0x84, 0x23, 0x49, 0xFF, 0xDF, 0x9D, 0x84, 0x00, 0x3C, 0x1D, 0xFB, 0x4A, + 0x80, 0x40, 0x44, 0x32, 0xB5, 0x0D, 0x49, 0xFF, 0xE0, 0x91, 0x84, 0x81, 0xD5, 0x16, 0xB0, 0x03, + 0x38, 0xA3, 0x00, 0x00, 0x80, 0x0A, 0x49, 0xFF, 0xE7, 0xF1, 0xB6, 0x1F, 0x3C, 0x1D, 0xFB, 0x4A, + 0x84, 0x03, 0x80, 0x4A, 0x44, 0x32, 0xB5, 0x0D, 0x49, 0xFF, 0xE0, 0x80, 0x2E, 0x07, 0xEC, 0x66, + 0x84, 0x26, 0x49, 0xFF, 0xDF, 0x7F, 0xB4, 0x9F, 0x88, 0x87, 0x96, 0x20, 0xB6, 0x1F, 0xB4, 0x1F, + 0x4C, 0x70, 0x00, 0x4A, 0x49, 0xFF, 0xED, 0xB4, 0x49, 0x00, 0x28, 0x5B, 0xE3, 0x27, 0xE8, 0x0E, + 0x80, 0x08, 0x49, 0xFF, 0xE7, 0xD3, 0xF0, 0x81, 0x50, 0x04, 0x80, 0x01, 0x54, 0x90, 0x00, 0xFF, + 0xF1, 0x01, 0x80, 0x08, 0x84, 0x40, 0x49, 0xFF, 0xFF, 0x6A, 0x44, 0x03, 0xF0, 0x4A, 0x44, 0x10, + 0x00, 0x55, 0xAE, 0x40, 0x2E, 0x17, 0xEC, 0x66, 0x3C, 0x0D, 0xFB, 0x64, 0x5A, 0x18, 0x03, 0x21, + 0x84, 0x20, 0x3E, 0x17, 0xEC, 0x31, 0xA6, 0x40, 0x5A, 0x18, 0x01, 0xFF, 0x44, 0x02, 0x00, 0x00, + 0x44, 0x12, 0x00, 0x02, 0x44, 0x22, 0x45, 0x10, 0xFA, 0x62, 0xFA, 0x94, 0xFA, 0xA0, 0x49, 0xFF, + 0xF4, 0x45, 0x2E, 0x07, 0xEC, 0x31, 0x5A, 0x08, 0x01, 0x0F, 0x2E, 0x87, 0xEC, 0x54, 0x5A, 0x88, + 0x01, 0x0B, 0x2E, 0x07, 0xEC, 0x66, 0x84, 0x23, 0x49, 0xFF, 0xDF, 0x3C, 0xD5, 0x13, 0xA6, 0x40, + 0x5A, 0x18, 0x01, 0xFF, 0x3C, 0x0D, 0xFB, 0x59, 0x8C, 0xE1, 0x84, 0x21, 0x97, 0xF8, 0xAE, 0x40, + 0x81, 0x0A, 0xD5, 0xB6, 0x8C, 0xC1, 0x5A, 0x68, 0x05, 0x8B, 0x84, 0x00, 0x49, 0xFF, 0xF7, 0xF5, + 0x85, 0x00, 0x80, 0x08, 0xFC, 0xC2, 0xFC, 0x41, 0x84, 0xC0, 0x3C, 0x6F, 0xFB, 0x8A, 0xB6, 0x1F, + 0xF1, 0x81, 0x3C, 0x6F, 0xFB, 0x85, 0x80, 0xE6, 0x49, 0x00, 0x28, 0x03, 0xE2, 0xC7, 0xE8, 0x08, + 0x8C, 0xC1, 0xB4, 0x1F, 0x84, 0x24, 0xF2, 0x01, 0x97, 0xB0, 0x49, 0xFF, 0xFF, 0x18, 0x3C, 0x1D, + 0xFB, 0x64, 0xA6, 0x08, 0x54, 0x90, 0x00, 0xFF, 0x5A, 0x98, 0x01, 0xFD, 0x44, 0x02, 0x00, 0x00, + 0x44, 0x12, 0x00, 0x02, 0x44, 0x22, 0x45, 0x10, 0xFA, 0x62, 0xFA, 0x94, 0xFA, 0xA0, 0x49, 0xFF, + 0xF3, 0xFD, 0x3C, 0x0D, 0xFB, 0x59, 0x8C, 0xE1, 0x97, 0xF8, 0x10, 0x90, 0x00, 0x00, 0x5A, 0x78, + 0x04, 0xDD, 0xFC, 0xC1, 0xFC, 0x45, 0x44, 0x21, 0x31, 0x88, 0xB0, 0x42, 0x3A, 0x21, 0x14, 0x00, + 0x3A, 0x20, 0x94, 0x20, 0x44, 0x21, 0x31, 0xA8, 0x44, 0x72, 0x8F, 0x70, 0xB1, 0x86, 0x3A, 0x21, + 0x14, 0x00, 0x3A, 0x23, 0x14, 0x20, 0x81, 0x20, 0x00, 0x23, 0x80, 0x0F, 0x84, 0x00, 0x12, 0x0F, + 0x80, 0x03, 0x38, 0x10, 0xA6, 0x02, 0x50, 0x0F, 0x80, 0x06, 0x00, 0x33, 0x80, 0x10, 0x92, 0x41, + 0x49, 0x00, 0x24, 0x6C, 0x50, 0x0F, 0x80, 0x06, 0x38, 0x13, 0x26, 0x02, 0x00, 0x23, 0x80, 0x0F, + 0x00, 0x33, 0x80, 0x10, 0x49, 0x00, 0x24, 0x62, 0xFC, 0xC5, 0xFC, 0x02, 0x44, 0x01, 0x31, 0xA8, + 0x80, 0xDF, 0x3A, 0x20, 0x14, 0x00, 0x44, 0x02, 0x3F, 0xF0, 0x3A, 0x2F, 0x94, 0x20, 0xA5, 0x40, + 0x44, 0x00, 0xAA, 0x55, 0xD8, 0x1C, 0x84, 0x00, 0x3C, 0x33, 0xE3, 0x76, 0x80, 0x20, 0x38, 0x53, + 0x02, 0x02, 0x84, 0x40, 0x97, 0x11, 0xE2, 0x83, 0xE8, 0x06, 0x38, 0x42, 0x89, 0x01, 0x8C, 0x41, + 0x88, 0x24, 0xD5, 0xF9, 0x8C, 0x01, 0x5A, 0x08, 0x04, 0xF4, 0x44, 0x02, 0x3F, 0xF2, 0xFE, 0x4A, + 0xA4, 0x00, 0x96, 0x49, 0xFE, 0x45, 0x5C, 0x00, 0x80, 0x01, 0xD5, 0x02, 0x84, 0x00, 0xFC, 0x82, + 0xFC, 0x02, 0x44, 0x01, 0x31, 0xA8, 0x84, 0x20, 0x3A, 0x20, 0x14, 0x00, 0x3A, 0x2F, 0x94, 0x20, + 0x80, 0xDF, 0x3C, 0x33, 0xE3, 0x76, 0x80, 0x01, 0x38, 0x53, 0x06, 0x02, 0x84, 0x40, 0x97, 0x11, + 0xE2, 0x83, 0xE8, 0x06, 0x38, 0x42, 0x89, 0x01, 0x8C, 0x41, 0x88, 0x04, 0xD5, 0xF9, 0x8C, 0x21, + 0x5A, 0x18, 0x04, 0xF4, 0x44, 0x12, 0x3F, 0xF2, 0xFE, 0x02, 0x96, 0x01, 0xAC, 0x08, 0x44, 0x02, + 0x3F, 0xF0, 0x44, 0x1F, 0xAA, 0x55, 0xAC, 0x40, 0xFC, 0x82, 0x2E, 0x37, 0xC7, 0x68, 0x5A, 0x38, + 0x01, 0x5C, 0xFC, 0x00, 0x3C, 0x3D, 0xFB, 0x4A, 0xA6, 0xD9, 0x5A, 0x30, 0x08, 0x04, 0x5A, 0x38, + 0x04, 0x0E, 0xA1, 0x02, 0x2E, 0x67, 0xEC, 0x3E, 0x3C, 0x33, 0xE3, 0xD1, 0x40, 0x42, 0x18, 0x97, + 0x2E, 0x57, 0xC7, 0xAF, 0x97, 0x21, 0xA0, 0x03, 0xD5, 0x1F, 0x2E, 0x47, 0xEC, 0x66, 0x3C, 0x33, + 0xE3, 0xD0, 0x5A, 0x48, 0x04, 0x11, 0x2E, 0x47, 0xEC, 0x13, 0x52, 0x31, 0x80, 0xFF, 0xFF, 0x1C, + 0x2E, 0x37, 0xEC, 0x46, 0x2E, 0x60, 0x0D, 0x13, 0x40, 0x42, 0x0C, 0x96, 0x52, 0x42, 0x00, 0xFF, + 0x96, 0xE1, 0xD5, 0x03, 0x2E, 0x67, 0xEC, 0x23, 0xB4, 0x80, 0x2E, 0x57, 0xC7, 0xAE, 0x40, 0x42, + 0x18, 0x97, 0x97, 0x21, 0xA0, 0x01, 0x40, 0x00, 0x18, 0x17, 0xE2, 0x23, 0x99, 0x99, 0x96, 0x01, + 0x97, 0xB1, 0xE8, 0x04, 0x8A, 0x61, 0x96, 0xD9, 0xD5, 0x02, 0x84, 0x60, 0x5C, 0xF3, 0x02, 0x01, + 0x80, 0x26, 0xE9, 0x03, 0x44, 0x10, 0x02, 0x00, 0x96, 0x49, 0xE2, 0x24, 0xE8, 0x04, 0xA6, 0x10, + 0x8C, 0x01, 0xD5, 0x04, 0xE2, 0x03, 0xE9, 0xFC, 0x84, 0x00, 0xAE, 0x10, 0xA6, 0x10, 0xE2, 0xA0, + 0x84, 0x01, 0xE8, 0x09, 0x84, 0x00, 0xAE, 0x10, 0x2E, 0x00, 0x06, 0x30, 0x8C, 0x01, 0x3E, 0x00, + 0x06, 0x30, 0x84, 0x02, 0xFC, 0x80, 0x84, 0x01, 0xDD, 0x9E, 0xFC, 0x40, 0x04, 0x50, 0x00, 0x11, + 0x54, 0x52, 0xFF, 0xFF, 0xC9, 0x1B, 0x83, 0x80, 0x44, 0x32, 0x00, 0xF0, 0xB9, 0x10, 0xB8, 0x11, + 0x54, 0x10, 0xFF, 0xFF, 0x94, 0x4A, 0x88, 0x23, 0x54, 0x00, 0x7F, 0xFF, 0xA6, 0x4C, 0x96, 0x48, + 0xC2, 0x24, 0x94, 0x02, 0x44, 0x30, 0x00, 0x48, 0x42, 0x00, 0x8C, 0x73, 0x44, 0x52, 0x00, 0x00, + 0x44, 0x12, 0x00, 0x48, 0x88, 0xA0, 0x88, 0x01, 0xD5, 0x15, 0x95, 0x6A, 0x44, 0x62, 0x00, 0x00, + 0x88, 0xC5, 0x44, 0x70, 0x00, 0x48, 0xE2, 0x64, 0xE8, 0xDF, 0x80, 0xA6, 0x42, 0x51, 0x9C, 0x73, + 0x50, 0x92, 0x80, 0x48, 0x18, 0x12, 0x80, 0x01, 0x4C, 0x54, 0xFF, 0xFE, 0x8C, 0x61, 0x96, 0xD8, + 0xD5, 0xF3, 0x18, 0x22, 0x80, 0x01, 0xD8, 0xFE, 0xFC, 0xC0, 0xFC, 0x40, 0x04, 0x9F, 0x80, 0x0A, + 0x5A, 0x90, 0x01, 0x0B, 0x44, 0x62, 0xD3, 0xB4, 0x44, 0x72, 0xD0, 0x90, 0x38, 0x63, 0x04, 0x00, + 0x38, 0x73, 0x84, 0x00, 0xD5, 0x03, 0x84, 0xE2, 0x84, 0xCA, 0x83, 0x80, 0xFB, 0x48, 0xB9, 0x10, + 0x54, 0x10, 0xFF, 0xFF, 0x94, 0x4A, 0x42, 0x13, 0x28, 0x73, 0x44, 0xA2, 0x00, 0x00, 0x88, 0x2A, + 0xBE, 0x12, 0x00, 0x80, 0x80, 0x07, 0x92, 0xD0, 0x10, 0x81, 0x80, 0x00, 0xA6, 0xCE, 0x54, 0x63, + 0x7F, 0xFF, 0xAE, 0xE0, 0xA6, 0xCC, 0xAE, 0xE8, 0x02, 0x30, 0x00, 0x2B, 0x02, 0x40, 0x80, 0x09, + 0x02, 0x00, 0x00, 0x2B, 0x02, 0x10, 0x80, 0x08, 0x88, 0x64, 0x88, 0x01, 0x94, 0x01, 0x94, 0xD9, + 0x88, 0x6A, 0xF4, 0x08, 0x89, 0x40, 0xF0, 0x09, 0xB6, 0x64, 0xB7, 0x40, 0x2E, 0x07, 0xEC, 0x66, + 0xC0, 0x03, 0x5A, 0x98, 0x01, 0x0E, 0x44, 0x10, 0x00, 0x54, 0x94, 0x32, 0x42, 0x03, 0x84, 0x73, + 0x44, 0x12, 0x00, 0x00, 0x88, 0x01, 0xB4, 0x00, 0x92, 0x0A, 0x96, 0x37, 0xD5, 0x03, 0x2E, 0x00, + 0x0D, 0x13, 0xAE, 0x10, 0xFC, 0xC0, 0xFC, 0x00, 0x83, 0x80, 0x44, 0x60, 0x00, 0x30, 0xBD, 0x12, + 0xB8, 0x12, 0x54, 0x52, 0xFF, 0xFF, 0x54, 0x00, 0x7F, 0xFF, 0x95, 0x6A, 0x94, 0x02, 0x42, 0x02, + 0x18, 0x73, 0x42, 0x51, 0x98, 0x73, 0x44, 0x42, 0x00, 0x00, 0x44, 0x62, 0x00, 0x30, 0x88, 0x80, + 0x88, 0xC0, 0x8A, 0xA0, 0x38, 0x32, 0x90, 0x02, 0x8C, 0x26, 0x54, 0x01, 0x83, 0xFF, 0x12, 0x00, + 0xFF, 0xFD, 0x40, 0x01, 0xA8, 0x09, 0x92, 0x74, 0x54, 0x31, 0x83, 0xFF, 0x12, 0x30, 0xFF, 0xFF, + 0x54, 0x00, 0x03, 0xFF, 0xA2, 0xE1, 0x12, 0x00, 0xFF, 0xFE, 0x54, 0x01, 0x83, 0xFF, 0xAC, 0x10, + 0x40, 0x01, 0xA8, 0x09, 0x92, 0x74, 0x54, 0x00, 0x03, 0xFF, 0x54, 0x31, 0x83, 0xFF, 0xAC, 0x11, + 0xAC, 0xD2, 0x8C, 0x46, 0x4C, 0x43, 0x7F, 0xE0, 0xFC, 0x80, 0x04, 0x00, 0x00, 0x11, 0x44, 0x40, + 0x00, 0x48, 0x54, 0x00, 0x7F, 0xFF, 0x94, 0x02, 0x42, 0x01, 0x90, 0x73, 0x44, 0x52, 0x00, 0x00, + 0x88, 0xA0, 0x84, 0x00, 0x98, 0xC8, 0xA6, 0xD9, 0x40, 0x41, 0xE0, 0x08, 0x38, 0x30, 0x80, 0x00, + 0x40, 0x31, 0xC0, 0x08, 0x88, 0x64, 0x99, 0x10, 0xA7, 0x21, 0x40, 0x42, 0x20, 0x08, 0x88, 0x64, + 0x38, 0x41, 0x00, 0x00, 0x8C, 0x02, 0x88, 0x64, 0xAA, 0xE9, 0x5A, 0x08, 0x24, 0xED, 0xDD, 0x9E, + 0x04, 0x00, 0x00, 0x11, 0x44, 0x40, 0x00, 0x48, 0x54, 0x00, 0x7F, 0xFF, 0x94, 0x02, 0x42, 0x01, + 0x90, 0x73, 0x80, 0x60, 0x44, 0x02, 0x00, 0x00, 0x88, 0x60, 0x84, 0x00, 0xA5, 0x19, 0x38, 0x40, + 0x80, 0x08, 0xA7, 0x5B, 0x99, 0x08, 0xAF, 0x61, 0xB4, 0x83, 0x99, 0x50, 0x38, 0x41, 0x00, 0x08, + 0xA3, 0x19, 0x92, 0x88, 0x8C, 0x02, 0xAF, 0x29, 0x5A, 0x08, 0x24, 0xF2, 0xDD, 0x9E, 0xFC, 0x40, + 0xEF, 0x00, 0x3C, 0x1D, 0xFB, 0x64, 0x84, 0x02, 0xAE, 0x08, 0x3C, 0x1D, 0xFB, 0x59, 0xAE, 0x08, + 0x44, 0x03, 0xF4, 0x03, 0xA7, 0x80, 0x97, 0xB0, 0xCE, 0xFE, 0x3C, 0x0D, 0xFB, 0x5B, 0x84, 0x26, + 0xF0, 0x85, 0x3C, 0x0C, 0x01, 0xA1, 0x44, 0x80, 0x00, 0x48, 0x3C, 0x0F, 0xFB, 0x5B, 0x2E, 0x07, + 0xEC, 0x66, 0x49, 0xFF, 0xDC, 0xFF, 0x3C, 0x9C, 0x01, 0xA1, 0x2E, 0x07, 0xC6, 0xE7, 0xE2, 0xC0, + 0xE8, 0x3F, 0xB0, 0x09, 0x50, 0xAF, 0x80, 0x20, 0x84, 0xE0, 0x50, 0x5F, 0x80, 0x1B, 0xF0, 0x81, + 0x80, 0x26, 0x80, 0x09, 0x50, 0x2F, 0x80, 0x1A, 0xB0, 0xC7, 0x50, 0x4F, 0x80, 0x1D, 0xB7, 0x5F, + 0xF7, 0x82, 0x49, 0xFF, 0xFF, 0x04, 0x80, 0x09, 0xB0, 0x5C, 0xB0, 0xAE, 0x00, 0x3F, 0x80, 0x1C, + 0x00, 0x4F, 0x80, 0x1D, 0x49, 0xFF, 0xFF, 0x49, 0xB0, 0x93, 0x80, 0x09, 0xB0, 0x4A, 0x00, 0x3F, + 0x80, 0x1B, 0x49, 0xFF, 0xFF, 0x9F, 0xFA, 0x54, 0xB1, 0x1C, 0xB1, 0x4A, 0x38, 0x35, 0x1E, 0x02, + 0x42, 0x43, 0xA0, 0x73, 0x42, 0x53, 0x88, 0x73, 0x84, 0x00, 0x38, 0x12, 0x01, 0x01, 0x5A, 0x13, + 0xFF, 0x06, 0x38, 0xF2, 0x80, 0x00, 0x38, 0xF1, 0x85, 0x09, 0x8C, 0x01, 0x5A, 0x08, 0x24, 0xF7, + 0x5A, 0x70, 0x01, 0x04, 0x84, 0xE1, 0xD5, 0xE9, 0x8C, 0xC1, 0x97, 0xB0, 0xD5, 0xBF, 0x44, 0x02, + 0x00, 0x00, 0x44, 0x12, 0x0C, 0x60, 0x49, 0x00, 0x21, 0xC0, 0x44, 0x02, 0x00, 0x00, 0x44, 0x12, + 0x4C, 0x60, 0x49, 0x00, 0x21, 0xBA, 0x44, 0x20, 0x00, 0x48, 0x44, 0x02, 0x29, 0x00, 0x44, 0x12, + 0x2C, 0x60, 0x49, 0x00, 0x21, 0x97, 0x44, 0x02, 0x1B, 0x90, 0x44, 0x12, 0x00, 0x00, 0x49, 0x00, + 0x21, 0xAC, 0x2E, 0x07, 0xEC, 0x66, 0x84, 0x23, 0x49, 0xFF, 0xDC, 0x9C, 0x3C, 0x1D, 0xFB, 0x64, + 0xF0, 0x05, 0x84, 0xC0, 0x3C, 0x0F, 0xFB, 0x5B, 0x84, 0x01, 0xAE, 0x08, 0x3C, 0x1D, 0xFB, 0x59, + 0xAE, 0x08, 0x2E, 0x10, 0x06, 0x39, 0x44, 0x00, 0x00, 0xFF, 0x49, 0x00, 0x4A, 0xDE, 0x50, 0x0F, + 0x80, 0x1E, 0x44, 0x12, 0x0C, 0x60, 0x2E, 0x27, 0xC6, 0xC7, 0x2E, 0x37, 0xC6, 0xC8, 0x12, 0x6F, + 0x80, 0x0F, 0x49, 0x00, 0x22, 0x13, 0x50, 0x0F, 0x80, 0x1E, 0x44, 0x12, 0x4C, 0x60, 0x2E, 0x27, + 0xC6, 0xC7, 0x2E, 0x37, 0xC6, 0xC8, 0x49, 0x00, 0x22, 0x09, 0x2E, 0x07, 0xEC, 0x5B, 0x3E, 0x67, + 0xEC, 0x10, 0x5A, 0x08, 0x01, 0x04, 0x3E, 0x67, 0xEC, 0x5B, 0x2E, 0x07, 0xEC, 0x42, 0x5A, 0x08, + 0x01, 0x05, 0x84, 0x00, 0x3E, 0x07, 0xEC, 0x42, 0xED, 0x00, 0xFC, 0xC0, 0xE2, 0x01, 0xE8, 0x08, + 0xA4, 0x10, 0xE2, 0x80, 0xE8, 0x03, 0x8A, 0x04, 0xD5, 0x0D, 0x84, 0x00, 0xD5, 0x0B, 0xE2, 0x20, + 0xE8, 0x0A, 0xA4, 0x10, 0x52, 0xF2, 0x00, 0xFF, 0xE0, 0x0F, 0xE8, 0x03, 0x88, 0x04, 0xD5, 0x02, + 0x84, 0x1F, 0xAE, 0x18, 0xDD, 0x9E, 0xFC, 0x40, 0xEE, 0xE8, 0x5A, 0x38, 0x01, 0x07, 0x3C, 0xA0, + 0x03, 0x1F, 0x44, 0x40, 0x01, 0x20, 0xD5, 0x09, 0x2E, 0x50, 0x0D, 0x06, 0x4C, 0x50, 0x00, 0xBD, + 0x3C, 0xA0, 0x03, 0x1E, 0x44, 0x40, 0x0C, 0x60, 0x2E, 0x57, 0xEB, 0xFE, 0xF4, 0x87, 0xE6, 0xA2, + 0x84, 0x81, 0xE9, 0x05, 0x8E, 0xA1, 0x40, 0x42, 0x14, 0x0C, 0x97, 0x20, 0x40, 0x42, 0x04, 0x0E, + 0x97, 0x20, 0xF4, 0x86, 0xCC, 0x03, 0x84, 0x81, 0xF4, 0x86, 0xF1, 0x88, 0x80, 0x20, 0xB0, 0x0E, + 0xB6, 0x1F, 0xB0, 0x0F, 0x50, 0x5F, 0x80, 0x35, 0xF3, 0x89, 0xF2, 0x85, 0xF0, 0x81, 0xF3, 0x82, + 0x80, 0x02, 0x50, 0x3F, 0x80, 0x36, 0xB0, 0x8D, 0x50, 0x4F, 0x80, 0x37, 0x49, 0xFF, 0xFE, 0x37, + 0xF0, 0x05, 0xB0, 0x62, 0xB0, 0xB4, 0x00, 0x3F, 0x80, 0x36, 0x00, 0x4F, 0x80, 0x37, 0x49, 0xFF, + 0xFE, 0x7C, 0xF0, 0x05, 0xB0, 0x50, 0xB0, 0x99, 0x00, 0x3F, 0x80, 0x35, 0x49, 0xFF, 0xFE, 0xD2, + 0xB0, 0x22, 0x81, 0x20, 0xB1, 0xD0, 0x87, 0x80, 0xB0, 0x0E, 0x38, 0x00, 0x72, 0x02, 0xF0, 0x84, + 0xF0, 0x09, 0x5A, 0x08, 0x01, 0x06, 0xF0, 0x04, 0x50, 0x80, 0x00, 0x90, 0xD5, 0x04, 0xF0, 0x04, + 0x50, 0x80, 0x1B, 0x90, 0xF0, 0x04, 0xF1, 0x07, 0x84, 0xC0, 0x99, 0x41, 0xFA, 0x14, 0x42, 0x0E, + 0x00, 0x24, 0xF0, 0x8A, 0x38, 0x34, 0x99, 0x01, 0x5A, 0x33, 0xFF, 0x55, 0xF0, 0x04, 0x2E, 0xF7, + 0xEB, 0xFF, 0x00, 0x4F, 0x80, 0x34, 0x38, 0x00, 0x0D, 0x01, 0xF1, 0x08, 0x50, 0xF7, 0xFF, 0xFF, + 0x94, 0x99, 0x41, 0xE0, 0x13, 0xD6, 0x4C, 0x17, 0xC0, 0x19, 0x88, 0x48, 0x02, 0xF1, 0x00, 0x00, + 0x40, 0x47, 0x90, 0x96, 0x8A, 0x8A, 0x4E, 0x44, 0x00, 0x03, 0xFF, 0x22, 0x40, 0x1F, 0x28, 0x01, + 0x4E, 0x14, 0x00, 0x03, 0xFE, 0x4A, 0xE0, 0x81, 0xE9, 0x03, 0xAC, 0x10, 0xD5, 0x33, 0x38, 0x02, + 0x8D, 0x01, 0x38, 0x03, 0x98, 0x08, 0xD5, 0x2E, 0xF1, 0x08, 0xC9, 0x04, 0x38, 0x04, 0x0D, 0x09, + 0xD5, 0x11, 0x88, 0x48, 0xA4, 0xD0, 0x40, 0x31, 0x90, 0x76, 0x8A, 0x6A, 0x4E, 0x34, 0x00, 0x03, + 0xFE, 0xDA, 0x40, 0x1F, 0x28, 0x01, 0x4E, 0x14, 0x00, 0x03, 0xFE, 0x4A, 0xE0, 0x61, 0xE9, 0x08, + 0xAC, 0x10, 0x38, 0x04, 0x99, 0x01, 0x38, 0x13, 0x98, 0x00, 0x38, 0x12, 0x81, 0x09, 0x38, 0x04, + 0x99, 0x01, 0xF1, 0x0A, 0x94, 0x81, 0x38, 0x04, 0x01, 0x01, 0x98, 0xF1, 0x40, 0x00, 0x10, 0x16, + 0xB1, 0x10, 0x88, 0x45, 0x88, 0x64, 0x80, 0x2A, 0xF4, 0x06, 0xF5, 0x8B, 0x49, 0xFF, 0xFF, 0x38, + 0xF5, 0x0B, 0x8C, 0xC1, 0x5A, 0x68, 0x24, 0xA8, 0x50, 0x94, 0x80, 0x48, 0x50, 0x73, 0x80, 0x24, + 0x5B, 0xC0, 0x01, 0x04, 0x87, 0x81, 0xD5, 0x89, 0xF0, 0x05, 0xB0, 0x50, 0xB0, 0x99, 0x00, 0x3F, + 0x80, 0x35, 0x49, 0xFF, 0xFE, 0x2C, 0xED, 0x18, 0xFC, 0xC0, 0xFC, 0x41, 0x84, 0x01, 0xB6, 0x3F, + 0xF2, 0x81, 0x80, 0xE3, 0x49, 0xFF, 0xF4, 0x49, 0x3C, 0x1D, 0xFB, 0x64, 0x84, 0x01, 0xAE, 0x08, + 0x3C, 0x1D, 0xFB, 0x59, 0xAE, 0x08, 0x84, 0x00, 0x3C, 0x0F, 0xFB, 0x88, 0x2E, 0x00, 0x06, 0x36, + 0x5A, 0x08, 0x01, 0x04, 0x84, 0x07, 0xD5, 0x0E, 0x2E, 0x07, 0xEB, 0xFD, 0x5A, 0x08, 0x01, 0x04, + 0x84, 0x02, 0xD5, 0x08, 0x5A, 0x78, 0x01, 0x05, 0x2E, 0x07, 0xC7, 0xA9, 0xD5, 0x03, 0x2E, 0x07, + 0xC7, 0xA8, 0x3E, 0x07, 0xEB, 0xFE, 0x2E, 0x07, 0xEB, 0xFE, 0x84, 0xC0, 0x8C, 0x01, 0x3E, 0x07, + 0xEB, 0xFF, 0x3C, 0x6F, 0xFB, 0x85, 0x44, 0x80, 0x00, 0x55, 0x2E, 0x07, 0xEB, 0xFF, 0xE2, 0xC0, + 0x84, 0x00, 0xE8, 0x43, 0x3C, 0x0F, 0xFB, 0x8A, 0xCF, 0x03, 0x49, 0xFF, 0xE9, 0x89, 0x49, 0x00, + 0x24, 0x30, 0x44, 0x03, 0xF0, 0x4A, 0x85, 0x40, 0x10, 0x80, 0x00, 0x00, 0xF0, 0x01, 0xE3, 0x40, + 0xE8, 0x2D, 0x3C, 0x0D, 0xFB, 0x8A, 0xE3, 0x40, 0xE8, 0x05, 0x2E, 0x07, 0xC7, 0x54, 0xC8, 0x06, + 0xD5, 0x1A, 0x49, 0xFF, 0xD8, 0x7D, 0xC8, 0xFA, 0xD5, 0xF2, 0x2E, 0x07, 0xC7, 0x66, 0xC0, 0x13, + 0x2E, 0x50, 0x0D, 0x06, 0x4C, 0x55, 0x40, 0x10, 0xCF, 0x0E, 0x2E, 0x00, 0x06, 0x09, 0xC8, 0x0B, + 0x80, 0x06, 0x49, 0xFF, 0xE6, 0x5C, 0x81, 0x20, 0x5A, 0x08, 0x01, 0x06, 0x49, 0xFF, 0xD8, 0x68, + 0xC0, 0xFE, 0xD5, 0x16, 0x80, 0x0A, 0x80, 0x26, 0xB4, 0x5F, 0x80, 0x67, 0x49, 0xFF, 0xFE, 0xCD, + 0x50, 0x45, 0x00, 0x01, 0x54, 0xA2, 0x00, 0xFF, 0xD5, 0xD2, 0x3C, 0x0D, 0xFB, 0x59, 0x8C, 0xC1, + 0x84, 0x21, 0x97, 0xB0, 0xAE, 0x40, 0xD5, 0xBA, 0x49, 0xFF, 0xF3, 0xD7, 0x85, 0x20, 0x80, 0x09, + 0xFC, 0xC1, 0xFC, 0x46, 0x04, 0x10, 0x00, 0x11, 0x81, 0x40, 0x54, 0x10, 0xFF, 0xFF, 0x44, 0x72, + 0x00, 0x00, 0x44, 0x92, 0x8F, 0x70, 0xFA, 0x40, 0x94, 0x4A, 0x84, 0x00, 0xFA, 0xD4, 0x84, 0xA1, + 0x88, 0x27, 0xF2, 0x85, 0x83, 0x8A, 0x84, 0x42, 0x00, 0x44, 0x80, 0x2D, 0xF5, 0x81, 0xF0, 0x83, + 0xF0, 0x84, 0xF0, 0x86, 0xF2, 0x87, 0xF0, 0x88, 0xF0, 0x89, 0xF5, 0x8A, 0x80, 0x41, 0x80, 0x66, + 0xB6, 0xDF, 0xF6, 0x82, 0x44, 0x02, 0x61, 0x10, 0x49, 0xFF, 0xEF, 0x78, 0xB8, 0x10, 0x44, 0x12, + 0x00, 0xF0, 0x54, 0x00, 0x7F, 0xFF, 0x94, 0x02, 0x88, 0x01, 0xB9, 0x11, 0xA6, 0x04, 0x54, 0x10, + 0xFF, 0xFF, 0x00, 0x34, 0x80, 0x2D, 0x44, 0x20, 0x00, 0x48, 0x94, 0x4A, 0x42, 0x10, 0x08, 0x73, + 0x44, 0x02, 0x61, 0x10, 0x42, 0x01, 0x88, 0x73, 0x88, 0x27, 0x80, 0x46, 0x49, 0x00, 0x1F, 0xBA, + 0xFC, 0xC6, 0xFC, 0x46, 0x81, 0x40, 0x04, 0x00, 0x00, 0x11, 0x84, 0x20, 0x44, 0x92, 0x8F, 0x70, + 0xFA, 0x40, 0x54, 0x00, 0x7F, 0xFF, 0xFA, 0xD4, 0x84, 0xA1, 0x44, 0x72, 0x00, 0x00, 0xF1, 0x83, + 0xF1, 0x84, 0xF2, 0x85, 0xF1, 0x86, 0xF1, 0x88, 0xF1, 0x89, 0x83, 0x8A, 0x44, 0x12, 0x61, 0x10, + 0x84, 0x42, 0x94, 0x02, 0x00, 0x44, 0x80, 0x2D, 0xF5, 0x81, 0xF2, 0x87, 0xF5, 0x8A, 0x88, 0x07, + 0x80, 0x41, 0x80, 0x66, 0xB6, 0xDF, 0xF6, 0x82, 0x49, 0xFF, 0xEF, 0x38, 0xB9, 0x10, 0x44, 0x02, + 0x00, 0xF0, 0x54, 0x10, 0xFF, 0xFF, 0x94, 0x4A, 0x88, 0x20, 0xB8, 0x11, 0xA6, 0x4C, 0x54, 0x00, + 0x7F, 0xFF, 0x44, 0x20, 0x00, 0x48, 0x00, 0x34, 0x80, 0x2D, 0x94, 0x02, 0x42, 0x00, 0x88, 0x73, + 0x44, 0x12, 0x61, 0x10, 0x42, 0x11, 0x88, 0x73, 0x88, 0x07, 0x80, 0x46, 0x49, 0x00, 0x1F, 0x7A, + 0xFC, 0xC6, 0x2E, 0x27, 0xC6, 0xE7, 0x44, 0x00, 0x00, 0x48, 0xFE, 0x84, 0x84, 0x00, 0x80, 0x20, + 0x44, 0x32, 0x61, 0x10, 0xE0, 0x22, 0xE8, 0x07, 0x38, 0x40, 0x8C, 0x00, 0x8C, 0x21, 0x88, 0x04, + 0x96, 0x49, 0xD5, 0xF9, 0x3C, 0x1D, 0xFB, 0x53, 0xA0, 0x4F, 0x96, 0x89, 0x92, 0x30, 0x88, 0x22, + 0x88, 0x01, 0xFE, 0x02, 0x44, 0x12, 0x63, 0xE2, 0x96, 0x01, 0xAC, 0x08, 0x44, 0x02, 0x63, 0xE0, + 0x44, 0x1F, 0xAA, 0x55, 0xAC, 0x40, 0xDD, 0x9E, 0x44, 0x02, 0x63, 0xE0, 0xA5, 0x40, 0x44, 0x00, + 0xAA, 0x55, 0xD8, 0x22, 0x2E, 0x27, 0xC6, 0xE7, 0x44, 0x00, 0x00, 0x48, 0x84, 0x20, 0xFE, 0x84, + 0x44, 0x32, 0x61, 0x10, 0x80, 0x01, 0xE0, 0x02, 0xE8, 0x07, 0x38, 0x40, 0x0C, 0x00, 0x8C, 0x01, + 0x88, 0x24, 0x96, 0x01, 0xD5, 0xF9, 0x3C, 0x0D, 0xFB, 0x53, 0xA0, 0x87, 0x44, 0x02, 0x63, 0xE2, + 0x96, 0xD1, 0x92, 0x50, 0x88, 0x43, 0x88, 0x22, 0xA4, 0x00, 0xFE, 0x4A, 0x96, 0x49, 0xFE, 0x45, + 0x5C, 0x00, 0x80, 0x01, 0xDD, 0x9E, 0x84, 0x00, 0xDD, 0x9E, 0xFC, 0x20, 0x2E, 0x00, 0x06, 0x36, + 0xC8, 0x06, 0x3C, 0x73, 0xE3, 0xD5, 0x3C, 0x63, 0xE3, 0xD6, 0xD5, 0x04, 0x44, 0x60, 0x00, 0x80, + 0x80, 0xE6, 0x2E, 0x17, 0xEC, 0x66, 0x3C, 0x03, 0xE3, 0xD0, 0x5A, 0x18, 0x04, 0x0D, 0x2E, 0x17, + 0xEC, 0x13, 0x52, 0x00, 0x00, 0xFF, 0xFE, 0x0C, 0x2E, 0x17, 0xEC, 0x46, 0x40, 0x00, 0x04, 0x16, + 0x52, 0x00, 0x00, 0xFF, 0x3C, 0x08, 0x03, 0x1E, 0x3C, 0x03, 0xE3, 0xD1, 0x3C, 0x08, 0x03, 0x1F, + 0x84, 0x00, 0x3E, 0x07, 0xEB, 0xFD, 0x2E, 0x00, 0x06, 0x09, 0xC8, 0x09, 0x49, 0xFF, 0xF0, 0xC4, + 0x5A, 0x08, 0x02, 0x06, 0x49, 0xFF, 0xFF, 0xAA, 0x3E, 0x07, 0xEB, 0xFD, 0x2E, 0x07, 0xEB, 0xFD, + 0x5A, 0x08, 0x01, 0x07, 0x3C, 0x0D, 0xFB, 0x5B, 0x49, 0xFF, 0xFE, 0xFD, 0xD5, 0x0A, 0x3C, 0x0D, + 0xFB, 0x5B, 0x96, 0x78, 0x96, 0xB0, 0x84, 0x60, 0x2E, 0x47, 0xC6, 0xE5, 0x49, 0xFF, 0xFB, 0xDF, + 0x3C, 0x0D, 0xFB, 0x4A, 0x3C, 0x1D, 0xFB, 0x5B, 0x2E, 0x27, 0xC6, 0xE7, 0x84, 0x60, 0x49, 0xFF, + 0xFE, 0x6E, 0x80, 0xC0, 0x5A, 0x08, 0x01, 0x08, 0xFA, 0x03, 0x49, 0x00, 0x1C, 0x2B, 0x3E, 0x60, + 0x06, 0x09, 0xD5, 0x3D, 0x49, 0xFF, 0xF0, 0x98, 0x3C, 0x1D, 0xFB, 0x4A, 0x5A, 0x08, 0x02, 0x04, + 0x84, 0x05, 0xD5, 0x02, 0x84, 0x08, 0xAE, 0x09, 0x3C, 0x0D, 0xFB, 0x4A, 0x49, 0xFF, 0xD9, 0x87, + 0x84, 0x41, 0x3C, 0x0D, 0xFB, 0x4A, 0x3C, 0x1D, 0xFB, 0x5B, 0x80, 0x62, 0x49, 0xFF, 0xFE, 0x4F, + 0x2E, 0x00, 0x06, 0x09, 0xC8, 0x0B, 0x49, 0xFF, 0xF0, 0x7F, 0x5A, 0x08, 0x02, 0x08, 0x3C, 0x0D, + 0xFB, 0x5B, 0x49, 0xFF, 0xFF, 0x00, 0x49, 0xFF, 0xFF, 0x3E, 0x84, 0x00, 0x44, 0x12, 0xCE, 0xBE, + 0x84, 0x41, 0x49, 0x00, 0x1B, 0x5B, 0x84, 0x07, 0x49, 0x00, 0x48, 0x7B, 0x49, 0xFF, 0xF0, 0x6C, + 0x5A, 0x00, 0x02, 0x07, 0x3C, 0x0D, 0xFB, 0x4A, 0x84, 0x20, 0x49, 0x00, 0x20, 0x9D, 0x3C, 0x0D, + 0xFB, 0x4A, 0x2E, 0x17, 0xEC, 0x67, 0xAE, 0x41, 0x49, 0xFF, 0xD9, 0x59, 0xFC, 0xA0, 0x3C, 0x0F, + 0xFB, 0x40, 0xDD, 0x9E, 0xFC, 0x42, 0x81, 0x20, 0x84, 0x00, 0x80, 0xE1, 0x80, 0xC2, 0x2E, 0x17, + 0xC8, 0x4C, 0x44, 0x32, 0x8F, 0x70, 0x80, 0x80, 0x96, 0x80, 0xE2, 0x41, 0xE8, 0x06, 0x98, 0x83, + 0x8C, 0x01, 0x10, 0x41, 0x01, 0x8C, 0xD5, 0xF9, 0x04, 0x04, 0x80, 0x05, 0x80, 0x26, 0xFA, 0x4E, + 0x84, 0x80, 0x50, 0x3F, 0x80, 0x0F, 0x49, 0xFF, 0xC0, 0x15, 0x84, 0x00, 0x00, 0x4F, 0x80, 0x0F, + 0x80, 0x40, 0x84, 0x3F, 0x96, 0xC0, 0xE2, 0x64, 0xE8, 0x10, 0xA1, 0x71, 0x96, 0xC1, 0x38, 0x52, + 0x81, 0x01, 0xDB, 0x09, 0xA0, 0xF2, 0x38, 0x31, 0x81, 0x01, 0xE2, 0x43, 0x40, 0x21, 0xBC, 0x1B, + 0x40, 0x10, 0x3C, 0x1B, 0x8C, 0x01, 0xD5, 0xEF, 0x5A, 0x17, 0xFF, 0x1C, 0xA0, 0x36, 0x95, 0x4A, + 0x38, 0x40, 0x06, 0x02, 0xA0, 0x37, 0x38, 0xA0, 0x06, 0x02, 0x04, 0x03, 0x00, 0x08, 0x38, 0x30, + 0x06, 0x02, 0x3C, 0x0D, 0xFB, 0x40, 0xC3, 0x42, 0x00, 0x20, 0x00, 0x32, 0x00, 0x10, 0x00, 0x33, + 0xFF, 0x14, 0x42, 0x15, 0x04, 0x24, 0x40, 0x42, 0x0C, 0x97, 0x40, 0x30, 0x8C, 0x77, 0xD5, 0x37, + 0x84, 0x60, 0x80, 0x83, 0x80, 0x43, 0x81, 0x03, 0xD5, 0x0E, 0xC2, 0x5A, 0x00, 0x10, 0x00, 0x32, + 0x00, 0x00, 0x00, 0x33, 0x42, 0x14, 0x04, 0x24, 0x42, 0x0E, 0x00, 0x24, 0x40, 0x80, 0x89, 0x17, + 0x40, 0x20, 0x08, 0x57, 0xA6, 0x38, 0x5A, 0x00, 0x01, 0x05, 0x44, 0x00, 0x00, 0x50, 0xD5, 0x03, + 0x44, 0x00, 0x00, 0x32, 0x8A, 0x88, 0x4E, 0x44, 0x00, 0x03, 0xFF, 0x22, 0xE2, 0x04, 0xE9, 0x07, + 0x9A, 0x9A, 0x4E, 0x24, 0x00, 0x03, 0xFE, 0x92, 0xE2, 0x02, 0xE8, 0x07, 0x44, 0x00, 0x00, 0x78, + 0x3E, 0x07, 0xFF, 0xB8, 0x84, 0x01, 0xD5, 0x08, 0x2E, 0x07, 0xFF, 0xB8, 0xC0, 0x05, 0x8E, 0x01, + 0x3E, 0x07, 0xFF, 0xB8, 0xD5, 0x2F, 0xAE, 0x38, 0xD5, 0x2D, 0x80, 0x83, 0xA0, 0x75, 0x84, 0x40, + 0x88, 0xA1, 0x83, 0x82, 0xA6, 0x6B, 0xA7, 0xAA, 0xF1, 0x81, 0x81, 0x02, 0xF1, 0x01, 0xE2, 0x26, + 0xE9, 0xC5, 0xA6, 0x68, 0x01, 0xE2, 0x80, 0x01, 0x40, 0xFF, 0x04, 0x06, 0xE9, 0x17, 0x00, 0xA0, + 0x00, 0x02, 0x81, 0xE1, 0x42, 0xF3, 0x28, 0x73, 0x40, 0xA7, 0x84, 0x08, 0x04, 0xF4, 0x80, 0x05, + 0x89, 0x4F, 0x02, 0xA5, 0x00, 0x00, 0x40, 0xA5, 0x00, 0x11, 0xE5, 0x5E, 0xE9, 0x05, 0x89, 0x01, + 0x41, 0xCE, 0x18, 0x00, 0x8C, 0x41, 0x8C, 0x21, 0xD5, 0xE8, 0x8C, 0xC1, 0xD5, 0xE0, 0x81, 0x02, + 0xD5, 0xB2, 0xFC, 0xC2, 0xFC, 0x00, 0x84, 0x44, 0x80, 0x20, 0x84, 0x61, 0x84, 0x85, 0x84, 0xA0, + 0x49, 0x00, 0x1F, 0x14, 0xFC, 0x80, 0x3C, 0x0F, 0xFF, 0xF6, 0xDD, 0x9E, 0x3C, 0x0F, 0xFF, 0xF5, + 0xDD, 0x9E, 0x3C, 0x0F, 0xFF, 0xF4, 0xDD, 0x9E, 0x3C, 0x1D, 0xFF, 0xF6, 0xA0, 0x03, 0xA4, 0x4C, + 0xE2, 0x01, 0xE9, 0x06, 0x84, 0x00, 0x3E, 0x00, 0x06, 0x2C, 0x84, 0x02, 0xDD, 0x9E, 0x84, 0x00, + 0xDD, 0x9E, 0x3B, 0xFF, 0xFE, 0x3C, 0xEF, 0xFC, 0x44, 0x12, 0xB5, 0xDC, 0x84, 0x00, 0x44, 0x2F, + 0xFF, 0xAA, 0xAE, 0x08, 0xAE, 0x0A, 0xAE, 0x89, 0x84, 0x20, 0x3C, 0x1E, 0x00, 0x00, 0x3C, 0x1F, + 0xFF, 0xFF, 0x3E, 0x10, 0x00, 0x09, 0x3C, 0x18, 0x00, 0x02, 0x84, 0x21, 0x3E, 0x27, 0xE9, 0xDC, + 0x3E, 0x00, 0x00, 0x0A, 0x3E, 0x00, 0x00, 0x08, 0x3C, 0x1F, 0xFA, 0x76, 0x3E, 0x00, 0x00, 0x07, + 0x3E, 0x00, 0x00, 0x0B, 0x3E, 0x00, 0x00, 0x06, 0x3E, 0x07, 0xFF, 0xE3, 0x3E, 0x07, 0xFF, 0xE2, + 0x3E, 0x07, 0xFF, 0xE1, 0x3E, 0x07, 0xFF, 0xE0, 0xEC, 0x04, 0x3B, 0xFF, 0xFE, 0x04, 0xDD, 0x9E, + 0x2E, 0x00, 0x00, 0x0B, 0xDD, 0x9E, 0x2E, 0x17, 0xC6, 0xC1, 0x84, 0x00, 0x44, 0x32, 0x8F, 0x70, + 0x84, 0x81, 0x96, 0x80, 0xE2, 0x41, 0xE8, 0x06, 0x98, 0x83, 0x8C, 0x01, 0x10, 0x41, 0x03, 0xEC, + 0xD5, 0xF9, 0x44, 0x00, 0x00, 0x5A, 0x3C, 0x0B, 0xE5, 0x59, 0xDD, 0x9E, 0x3C, 0x13, 0xE4, 0x50, + 0xAC, 0x40, 0xDD, 0x9E, 0x44, 0x33, 0xF0, 0x4A, 0x44, 0x40, 0x00, 0x55, 0x3A, 0x6F, 0x9C, 0x3C, + 0x8E, 0x41, 0xAF, 0x18, 0x84, 0xA0, 0xE0, 0x45, 0xE9, 0x1A, 0x98, 0xEA, 0x90, 0x61, 0xDA, 0x05, + 0x38, 0x40, 0x0E, 0x02, 0x4C, 0x40, 0x80, 0x12, 0x38, 0x60, 0x0E, 0x02, 0x95, 0x1A, 0xE2, 0x26, + 0xE9, 0x08, 0x88, 0x80, 0xA1, 0x21, 0xE2, 0x24, 0xE8, 0x06, 0x4C, 0x60, 0x80, 0x07, 0xD5, 0x07, + 0x9E, 0x99, 0xD5, 0xEA, 0x9D, 0x59, 0xD5, 0xE8, 0x80, 0x03, 0xD5, 0x02, 0x84, 0x1F, 0x3A, 0x6F, + 0x9C, 0x04, 0xDD, 0x9E, 0x8E, 0x21, 0x94, 0x49, 0x40, 0x20, 0x04, 0x0D, 0x8E, 0x22, 0x40, 0x00, + 0x04, 0x0D, 0x96, 0x8F, 0x96, 0x0F, 0xCA, 0x04, 0x5A, 0x08, 0x02, 0x10, 0xD5, 0x0C, 0x5A, 0x28, + 0x01, 0x04, 0xC8, 0x0B, 0xD5, 0x08, 0x5A, 0x28, 0x02, 0x05, 0x5A, 0x08, 0x03, 0x07, 0xD5, 0x03, + 0x5A, 0x08, 0x01, 0x04, 0xFA, 0x00, 0xDD, 0x9E, 0xFA, 0x10, 0xDD, 0x9E, 0x84, 0x00, 0x44, 0x12, + 0xD0, 0x04, 0x84, 0x5F, 0x38, 0x20, 0x81, 0x09, 0x8C, 0x01, 0x5A, 0x08, 0x14, 0xFD, 0xDD, 0x9E, + 0x9C, 0x81, 0x3A, 0x6F, 0xA4, 0x3C, 0x96, 0x86, 0x2E, 0x90, 0x00, 0x09, 0x40, 0x70, 0x04, 0x09, + 0x84, 0x20, 0x84, 0x61, 0x44, 0x42, 0xD0, 0x04, 0xE3, 0x23, 0xE9, 0x1E, 0xC7, 0x0F, 0x5A, 0x78, + 0x01, 0x19, 0x95, 0x89, 0x95, 0x59, 0x88, 0xC2, 0x88, 0xA2, 0x38, 0x62, 0x19, 0x01, 0x38, 0x52, + 0x15, 0x01, 0xE2, 0xC5, 0x40, 0x11, 0xBC, 0x1B, 0xD5, 0x0C, 0x95, 0x89, 0x95, 0x59, 0x88, 0xC2, + 0x88, 0xA2, 0x38, 0x62, 0x19, 0x01, 0x38, 0x52, 0x15, 0x01, 0xE2, 0xA6, 0x40, 0x11, 0xBC, 0x1B, + 0x8C, 0x61, 0x96, 0xD8, 0xD5, 0xE2, 0x94, 0xC1, 0x94, 0x49, 0x96, 0x06, 0x99, 0x9A, 0x44, 0x52, + 0xD0, 0x04, 0x88, 0x41, 0x88, 0x20, 0x44, 0x42, 0xCF, 0x04, 0x88, 0x60, 0x38, 0x22, 0x89, 0x01, + 0x38, 0x02, 0x85, 0x01, 0x38, 0x22, 0x19, 0x09, 0x38, 0x02, 0x0D, 0x09, 0x3A, 0x6F, 0xA4, 0x04, + 0xDD, 0x9E, 0x00, 0x00, 0x3A, 0x6F, 0xAA, 0xBC, 0xEF, 0xE4, 0xB1, 0xC3, 0x80, 0xC1, 0x84, 0x4A, + 0x84, 0x20, 0x81, 0x00, 0x80, 0x07, 0x81, 0x43, 0x49, 0x00, 0x54, 0xA2, 0x84, 0x80, 0x3C, 0x3D, + 0xFF, 0xF6, 0x80, 0x46, 0x81, 0x24, 0x80, 0x24, 0x84, 0xA5, 0xB4, 0x02, 0xC0, 0x12, 0x8E, 0x04, + 0xE6, 0x02, 0xE9, 0x0F, 0x04, 0xF1, 0x00, 0x06, 0x04, 0x04, 0x00, 0x02, 0x38, 0x00, 0x3D, 0x01, + 0x00, 0xF1, 0x80, 0x06, 0x40, 0xF7, 0x80, 0x06, 0xE8, 0x04, 0x10, 0x55, 0x00, 0x02, 0x84, 0x81, + 0xB4, 0x02, 0x50, 0xF0, 0x7F, 0xFF, 0x5C, 0xF7, 0x80, 0x02, 0xE9, 0x03, 0x5A, 0x08, 0x04, 0x08, + 0x50, 0x04, 0x80, 0x01, 0x38, 0x13, 0xA4, 0x08, 0x54, 0x90, 0x00, 0xFF, 0x8C, 0x21, 0x96, 0x48, + 0x50, 0x21, 0x00, 0xE0, 0x5A, 0x18, 0x0A, 0xDB, 0x4E, 0x93, 0x00, 0x0B, 0x10, 0x95, 0x00, 0x02, + 0x81, 0x09, 0x83, 0x89, 0x80, 0x69, 0x80, 0x49, 0x80, 0xC9, 0x80, 0xE9, 0xD5, 0x4A, 0x2E, 0x00, + 0x00, 0x0A, 0x5A, 0x98, 0x01, 0x29, 0x8E, 0x01, 0xE6, 0x02, 0x2E, 0x50, 0x00, 0x06, 0xE8, 0x0B, + 0x00, 0x7F, 0x80, 0x0C, 0xD7, 0x08, 0xB6, 0x9F, 0x49, 0xFF, 0xFE, 0xD5, 0x3E, 0x70, 0x00, 0x06, + 0xB4, 0x9F, 0xD5, 0x07, 0x5A, 0x58, 0xFF, 0x06, 0x00, 0x0F, 0x80, 0x0C, 0x3E, 0x00, 0x00, 0x06, + 0x2E, 0x10, 0x00, 0x06, 0x44, 0x00, 0x00, 0xE0, 0x42, 0x60, 0x80, 0x73, 0x85, 0x00, 0x84, 0x01, + 0x22, 0x73, 0x00, 0x04, 0x83, 0x88, 0x22, 0x63, 0x00, 0x05, 0x80, 0x68, 0x10, 0x05, 0x00, 0x02, + 0x80, 0x48, 0xD5, 0x1F, 0x5A, 0x00, 0x06, 0x06, 0xB6, 0x9F, 0x49, 0xFF, 0xFE, 0xB4, 0xB4, 0x9F, + 0x00, 0x1F, 0x80, 0x0C, 0x44, 0x00, 0x00, 0xE0, 0x80, 0x46, 0x42, 0x20, 0x80, 0x73, 0x80, 0x22, + 0x22, 0x21, 0x00, 0x04, 0x22, 0x30, 0x80, 0x05, 0xA6, 0x79, 0x42, 0x60, 0x80, 0x73, 0x84, 0x03, + 0x23, 0xC3, 0x00, 0x04, 0x22, 0x83, 0x00, 0x05, 0x84, 0xC0, 0x10, 0x05, 0x00, 0x02, 0x80, 0xE6, + 0x2E, 0x00, 0x06, 0x12, 0x5A, 0x00, 0x01, 0x04, 0x5A, 0x48, 0x01, 0x05, 0x84, 0x05, 0x10, 0x05, + 0x00, 0x02, 0x00, 0x05, 0x00, 0x02, 0x5A, 0x08, 0x01, 0x5D, 0x3C, 0x4D, 0xFF, 0xF4, 0xA6, 0x60, + 0x5A, 0x18, 0x01, 0x09, 0x3C, 0x1D, 0xFF, 0xF5, 0x02, 0x10, 0x80, 0x09, 0x8E, 0x21, 0x9B, 0xCF, + 0x97, 0xFB, 0xA6, 0x61, 0x5A, 0x18, 0x01, 0x09, 0x3C, 0x1D, 0xFF, 0xF5, 0x02, 0x10, 0x80, 0x0A, + 0x8E, 0x21, 0x9B, 0x8E, 0x97, 0xB3, 0xA6, 0x63, 0x01, 0xE2, 0x00, 0x02, 0x5A, 0x18, 0x01, 0x3D, + 0x3C, 0x4D, 0xFF, 0xF5, 0x4F, 0xE3, 0x00, 0x1E, 0x02, 0x12, 0x00, 0x09, 0x50, 0xF0, 0xFF, 0xFF, + 0xA4, 0x62, 0x51, 0xE0, 0xFF, 0xFF, 0x84, 0x22, 0x40, 0x57, 0x84, 0xB6, 0x42, 0x53, 0xF8, 0x73, + 0x40, 0x72, 0xBC, 0xF7, 0x02, 0x52, 0x00, 0x0A, 0xA5, 0x23, 0x8E, 0xA1, 0x8E, 0x81, 0x40, 0x12, + 0x84, 0x36, 0x42, 0x13, 0x10, 0x73, 0x40, 0x60, 0x94, 0xD7, 0x97, 0xFB, 0x97, 0xB3, 0xD5, 0x21, + 0x02, 0x52, 0x00, 0x09, 0xA4, 0x63, 0x50, 0xF2, 0xFF, 0xFF, 0x84, 0xA2, 0x8E, 0x21, 0x40, 0x57, + 0x94, 0xB6, 0x42, 0x53, 0x84, 0x73, 0x40, 0x72, 0xBC, 0xF7, 0x02, 0x52, 0x00, 0x0A, 0xA5, 0x22, + 0x8E, 0xA1, 0x84, 0x22, 0x8E, 0x81, 0x40, 0x12, 0x84, 0x36, 0x42, 0x13, 0x10, 0x73, 0x40, 0x60, + 0x94, 0xD7, 0x97, 0xFB, 0x97, 0xB3, 0x5B, 0xE8, 0x01, 0x05, 0x80, 0x27, 0x80, 0xE6, 0x80, 0xC1, + 0x2E, 0x10, 0x00, 0x0A, 0xE6, 0x27, 0x4E, 0xF2, 0x00, 0xF6, 0x44, 0xF0, 0x89, 0xB8, 0x38, 0x17, + 0x85, 0x01, 0x40, 0xF0, 0xBC, 0x00, 0xDD, 0x0F, 0x0E, 0x00, 0xB2, 0x00, 0xC6, 0x00, 0xE6, 0x00, + 0xCE, 0x01, 0xDA, 0x01, 0xEC, 0x00, 0x5A, 0x08, 0x01, 0x04, 0x48, 0x00, 0x00, 0xE5, 0x5A, 0x00, + 0x03, 0x04, 0x48, 0x00, 0x00, 0xE0, 0x84, 0x00, 0x3E, 0x07, 0xFF, 0xBD, 0x3E, 0x07, 0xFF, 0xBC, + 0x5A, 0x98, 0x02, 0x40, 0x84, 0x00, 0xF2, 0x81, 0xB6, 0x7F, 0x3C, 0x08, 0x00, 0x02, 0x49, 0xFF, + 0xFE, 0x97, 0x3C, 0x0D, 0xFF, 0xF6, 0xF2, 0x01, 0xB4, 0x7F, 0x02, 0x50, 0x00, 0x11, 0x3C, 0x2B, + 0xFF, 0xE4, 0xE0, 0x45, 0x3C, 0x3B, 0xFF, 0xE5, 0x3D, 0xCB, 0xFF, 0xE6, 0x3C, 0x8B, 0xFF, 0xE7, + 0x3C, 0x2B, 0xFF, 0xE0, 0x3C, 0x3B, 0xFF, 0xE1, 0x3D, 0xCB, 0xFF, 0xE2, 0x3C, 0x8B, 0xFF, 0xE3, + 0x3C, 0x28, 0x03, 0xA6, 0x3C, 0x38, 0x03, 0xA7, 0x3D, 0xC8, 0x03, 0xA8, 0x3C, 0x88, 0x03, 0xA9, + 0xE9, 0x47, 0x02, 0x40, 0x00, 0x12, 0xE0, 0x82, 0xE9, 0x43, 0x02, 0x10, 0x00, 0x13, 0xE0, 0x61, + 0xE9, 0x3F, 0x02, 0x00, 0x00, 0x14, 0xE0, 0x03, 0xE9, 0x3B, 0x40, 0xFE, 0x14, 0x07, 0xE9, 0x38, + 0xE0, 0x9C, 0xE9, 0x36, 0xE1, 0x01, 0xE9, 0x34, 0xE0, 0x08, 0xE9, 0x32, 0x48, 0x00, 0x00, 0x93, + 0x49, 0xFF, 0xFE, 0x5E, 0x84, 0x04, 0x48, 0x00, 0x00, 0x97, 0x5A, 0x08, 0x01, 0x04, 0x48, 0x00, + 0x00, 0x8E, 0x4E, 0x02, 0x00, 0x8E, 0x5A, 0x08, 0x03, 0x24, 0x48, 0x00, 0x00, 0x8C, 0x5A, 0x08, + 0x01, 0x04, 0x48, 0x00, 0x00, 0x84, 0x4E, 0x02, 0x00, 0x84, 0x5A, 0x08, 0x03, 0x1A, 0x3C, 0x00, + 0x00, 0x02, 0xE6, 0x0A, 0xE8, 0x15, 0x49, 0xFF, 0xFD, 0xB6, 0x84, 0x00, 0xD5, 0x7C, 0xE6, 0x02, + 0xE9, 0x79, 0xD5, 0x0E, 0xE7, 0x23, 0xE8, 0x09, 0x5A, 0x98, 0x02, 0x06, 0x2E, 0x17, 0xFF, 0xBC, + 0x5A, 0x10, 0x01, 0x04, 0x5A, 0x08, 0x05, 0x07, 0x84, 0x00, 0x3E, 0x07, 0xFF, 0xBC, 0x84, 0x04, + 0xD5, 0x6A, 0xC8, 0x2F, 0x3C, 0x27, 0xFF, 0xE1, 0x3C, 0x37, 0xFF, 0xE5, 0x9A, 0x53, 0x5E, 0xF0, + 0x82, 0x1D, 0xE9, 0x23, 0x3C, 0x17, 0xFF, 0xE3, 0x3C, 0x57, 0xFF, 0xE7, 0x9B, 0x0D, 0x5E, 0xF2, + 0x02, 0x1D, 0xE9, 0x1B, 0x50, 0x41, 0x00, 0x43, 0x8A, 0x83, 0x4E, 0x45, 0x00, 0x17, 0x50, 0x30, + 0x80, 0x43, 0x8A, 0x65, 0x4E, 0x35, 0x00, 0x12, 0x84, 0x61, 0x3E, 0x37, 0xFF, 0xBD, 0x3C, 0x28, + 0x03, 0xAB, 0x3C, 0x33, 0xFF, 0xE0, 0x3C, 0x23, 0xFF, 0xE2, 0x3C, 0x38, 0x03, 0xAA, 0x3C, 0x28, + 0x03, 0xAC, 0x3C, 0x18, 0x03, 0xAD, 0xD5, 0x3F, 0x49, 0xFF, 0xFE, 0x02, 0x84, 0x00, 0xD5, 0x3B, + 0x5A, 0x98, 0x02, 0x2D, 0x3C, 0x07, 0xFF, 0xE5, 0x3C, 0x3B, 0xFF, 0xE1, 0x9A, 0xC3, 0x3C, 0x2B, + 0xFF, 0xE0, 0x3D, 0xCB, 0xFF, 0xE2, 0x3C, 0x8B, 0xFF, 0xE3, 0x4E, 0x34, 0x00, 0x03, 0xFE, 0xDA, + 0x3C, 0x07, 0xFF, 0xE7, 0x8A, 0x08, 0x4E, 0x04, 0x00, 0x03, 0xFE, 0x02, 0xE0, 0x60, 0x40, 0x30, + 0x3C, 0x1B, 0xFA, 0x13, 0xFE, 0xC4, 0x3C, 0x07, 0xFF, 0xE4, 0x92, 0x67, 0x9A, 0x82, 0x4E, 0x24, + 0x00, 0x03, 0xFE, 0x92, 0xE2, 0x62, 0xE9, 0xAC, 0x3C, 0x07, 0xFF, 0xE6, 0x8A, 0x1C, 0x4E, 0x04, + 0x00, 0x03, 0xFE, 0x02, 0xE2, 0x60, 0xE9, 0xA4, 0xD5, 0x05, 0x5A, 0x98, 0x01, 0x04, 0x3E, 0x97, + 0xFF, 0xBC, 0x84, 0x06, 0xD5, 0x08, 0xC8, 0x9C, 0xD5, 0x06, 0x84, 0x02, 0xD5, 0x04, 0x84, 0x03, + 0xD5, 0x02, 0x84, 0x00, 0x3E, 0x00, 0x00, 0x0A, 0x8E, 0x01, 0xE6, 0x06, 0x4E, 0xF2, 0x03, 0x66, + 0x44, 0xF0, 0x8B, 0xB0, 0x38, 0x07, 0x81, 0x01, 0x40, 0xF0, 0x3C, 0x00, 0x4A, 0x00, 0x3C, 0x00, + 0x0C, 0x00, 0x7A, 0x00, 0x02, 0x02, 0xB2, 0x06, 0xB8, 0x06, 0xBE, 0x06, 0x84, 0x20, 0x3C, 0x1E, + 0x00, 0x00, 0x3C, 0x1F, 0xFF, 0xFF, 0x84, 0x21, 0x84, 0x00, 0x3C, 0x1F, 0xFA, 0x76, 0x44, 0x1F, + 0xFF, 0xAA, 0x3C, 0x08, 0x00, 0x02, 0x3E, 0x00, 0x00, 0x09, 0x3E, 0x00, 0x00, 0x08, 0x3E, 0x00, + 0x00, 0x07, 0x3E, 0x17, 0xE9, 0xDC, 0x3C, 0x7B, 0xFF, 0xFC, 0x3C, 0x6B, 0xFF, 0xFD, 0x3C, 0x7B, + 0xFF, 0xFA, 0x3C, 0x6B, 0xFF, 0xFB, 0x3C, 0x7B, 0xFF, 0xF8, 0x3C, 0x6B, 0xFF, 0xF9, 0x3C, 0x7B, + 0xFF, 0xF6, 0x3C, 0x6B, 0xFF, 0xF7, 0x3C, 0x7B, 0xFF, 0xF4, 0x3C, 0x6B, 0xFF, 0xF5, 0x3E, 0x07, + 0xFF, 0xE2, 0x3E, 0x07, 0xFF, 0xE0, 0x3E, 0x07, 0xFF, 0xBD, 0x49, 0xFF, 0xFD, 0x81, 0x3C, 0x78, + 0x03, 0xA6, 0x3C, 0x68, 0x03, 0xA7, 0x48, 0x00, 0x03, 0x24, 0x3C, 0x27, 0xFF, 0xFB, 0x3C, 0x7B, + 0xFF, 0xF8, 0x9A, 0x72, 0x3C, 0x6B, 0xFF, 0xF9, 0x4E, 0x14, 0x00, 0x03, 0xFE, 0x4A, 0x3C, 0x07, + 0xFF, 0xFA, 0xFA, 0x73, 0x9B, 0x38, 0xFE, 0xCC, 0x4E, 0x44, 0x00, 0x03, 0xFF, 0x22, 0x92, 0x67, + 0xE2, 0x64, 0xE8, 0x04, 0x84, 0x61, 0x3E, 0x37, 0xFF, 0xE5, 0xFA, 0x73, 0xFE, 0xE4, 0x92, 0x67, + 0xE2, 0x61, 0xE8, 0x04, 0x84, 0x21, 0x3E, 0x17, 0xFF, 0xE4, 0x3C, 0x4D, 0xFF, 0xF6, 0x2E, 0x17, + 0xFF, 0xE2, 0x02, 0x32, 0x00, 0x1A, 0xE2, 0x23, 0xE8, 0x04, 0x8C, 0x21, 0x3E, 0x17, 0xFF, 0xE2, + 0x9A, 0x47, 0x4E, 0x14, 0x00, 0x03, 0xFE, 0x4A, 0x9A, 0x16, 0x4E, 0x04, 0x00, 0x03, 0xFE, 0x02, + 0x88, 0x01, 0x02, 0x12, 0x00, 0x19, 0xE0, 0x20, 0xE8, 0x04, 0x84, 0x01, 0x3E, 0x07, 0xFF, 0xE0, + 0x3C, 0xF7, 0xFF, 0xF4, 0xE0, 0xEF, 0xE8, 0x04, 0x3C, 0x7B, 0xFF, 0xF4, 0xD5, 0x07, 0x3C, 0x07, + 0xFF, 0xF6, 0xE0, 0x07, 0xE8, 0x03, 0x3C, 0x7B, 0xFF, 0xF6, 0x3C, 0xF7, 0xFF, 0xF5, 0xE0, 0xCF, + 0xE8, 0x04, 0x3C, 0x6B, 0xFF, 0xF5, 0xD5, 0x07, 0x3C, 0x07, 0xFF, 0xF7, 0xE0, 0x06, 0xE8, 0x03, + 0x3C, 0x6B, 0xFF, 0xF7, 0x3C, 0x37, 0xFF, 0xFC, 0x9A, 0x1F, 0x4E, 0x04, 0x00, 0x03, 0xFE, 0x02, + 0x3C, 0x27, 0xFF, 0xFD, 0x9A, 0x56, 0x4E, 0x14, 0x00, 0x03, 0xFE, 0x4A, 0xA5, 0x65, 0x40, 0xF0, + 0x80, 0x00, 0xE2, 0xAF, 0x4E, 0xF2, 0x02, 0xBD, 0xA5, 0x66, 0xE2, 0x05, 0x4E, 0xF3, 0x02, 0xB9, + 0xA5, 0x27, 0xE2, 0x24, 0x4E, 0xF3, 0x02, 0xB5, 0xE0, 0x67, 0x2E, 0x80, 0x00, 0x07, 0xE8, 0x05, + 0x58, 0x54, 0x00, 0x02, 0x84, 0x80, 0xD5, 0x04, 0x54, 0x54, 0x00, 0x01, 0x84, 0x81, 0xE0, 0xC2, + 0xE8, 0x04, 0x58, 0x52, 0x80, 0x01, 0xD5, 0x05, 0x97, 0x4E, 0x8C, 0x81, 0x97, 0x68, 0x97, 0x20, + 0x3C, 0xFD, 0xFF, 0xFF, 0x88, 0x2F, 0x3C, 0x1F, 0xFF, 0xFF, 0x3C, 0x1C, 0x00, 0x00, 0x88, 0x01, + 0x3C, 0x0E, 0x00, 0x00, 0x5A, 0x48, 0x02, 0x0E, 0x2E, 0x00, 0x00, 0x09, 0xC8, 0x0A, 0x84, 0x01, + 0x3E, 0x00, 0x00, 0x09, 0x3C, 0x0D, 0xFA, 0x76, 0x94, 0x02, 0x3C, 0x0F, 0xFA, 0x76, 0xD5, 0x24, + 0x4C, 0x54, 0x00, 0x23, 0x2E, 0x00, 0x00, 0x09, 0xE6, 0x07, 0xE8, 0x19, 0x3C, 0x1D, 0xFA, 0x76, + 0x8C, 0x01, 0x94, 0x4A, 0xFE, 0x6F, 0x96, 0x00, 0x3C, 0x1F, 0xFA, 0x76, 0x3E, 0x00, 0x00, 0x09, + 0x3E, 0x50, 0x00, 0x07, 0x5A, 0x00, 0x01, 0x11, 0x8E, 0x01, 0x94, 0x01, 0x44, 0x12, 0xD0, 0x04, + 0x38, 0x30, 0x81, 0x09, 0x8C, 0x01, 0x38, 0x20, 0x81, 0x09, 0xD5, 0x06, 0x2E, 0x00, 0x00, 0x08, + 0x8C, 0x01, 0x3E, 0x00, 0x00, 0x08, 0x3C, 0x7B, 0xFF, 0xFC, 0x3C, 0x6B, 0xFF, 0xFD, 0x48, 0x00, + 0x02, 0x60, 0x2E, 0x30, 0x00, 0x09, 0x3C, 0x23, 0xFF, 0xF8, 0x3C, 0x13, 0xFF, 0xF9, 0xC3, 0x0A, + 0x94, 0x19, 0x44, 0x42, 0xD0, 0x04, 0x38, 0x22, 0x01, 0x09, 0x8C, 0x01, 0x38, 0x12, 0x01, 0x09, + 0xD5, 0x05, 0x3C, 0x28, 0x03, 0xA8, 0x3C, 0x18, 0x03, 0xA9, 0x3C, 0x6D, 0xFF, 0xF6, 0x3C, 0x4C, + 0x00, 0x00, 0x3D, 0xCD, 0xFF, 0xFF, 0x02, 0x13, 0x00, 0x10, 0x40, 0x0E, 0x10, 0x00, 0xE2, 0x20, + 0x4E, 0xF2, 0x01, 0x45, 0x2E, 0x07, 0xE9, 0xDC, 0x5A, 0x00, 0xAA, 0x04, 0x48, 0x00, 0x01, 0x3F, + 0x3C, 0x77, 0xFF, 0xFA, 0x02, 0x03, 0x00, 0x11, 0xE0, 0xE0, 0x4E, 0xF3, 0x01, 0x35, 0x02, 0x03, + 0x00, 0x12, 0xE0, 0x07, 0x4E, 0xF3, 0x01, 0x30, 0x3C, 0x87, 0xFF, 0xFB, 0x02, 0x03, 0x00, 0x13, + 0xE1, 0x00, 0x4E, 0xF3, 0x01, 0x29, 0x02, 0x03, 0x00, 0x14, 0xE0, 0x08, 0x4E, 0xF3, 0x01, 0x24, + 0x44, 0x02, 0xB2, 0x98, 0x3C, 0x1D, 0xFA, 0x76, 0x44, 0x20, 0x00, 0x57, 0xF4, 0x81, 0xB6, 0x7F, + 0x49, 0xFF, 0xFC, 0x2A, 0xB4, 0x7F, 0xF4, 0x01, 0x5A, 0x0F, 0xFF, 0x04, 0x48, 0x00, 0x01, 0x0D, + 0x44, 0x11, 0x31, 0xBC, 0x38, 0x10, 0x80, 0x00, 0x3E, 0x17, 0xE9, 0xDC, 0x5A, 0x18, 0x21, 0x24, + 0x3C, 0x17, 0xFF, 0xF9, 0xE0, 0x28, 0xE8, 0x06, 0x84, 0x26, 0x3E, 0x17, 0xE9, 0xDC, 0x48, 0x00, + 0x00, 0x82, 0x40, 0x14, 0x04, 0x01, 0x4E, 0x14, 0x00, 0x03, 0xFE, 0x4A, 0x44, 0x50, 0x00, 0x64, + 0x42, 0x20, 0x94, 0x24, 0x3C, 0xF7, 0xFF, 0xF5, 0x3C, 0x17, 0xFF, 0xF7, 0x8A, 0x2F, 0x40, 0x11, + 0x04, 0x36, 0x00, 0x23, 0x00, 0x2B, 0x96, 0x4B, 0xE0, 0x41, 0xE8, 0xE7, 0x84, 0x20, 0x3E, 0x17, + 0xE9, 0xDC, 0xD5, 0x68, 0x5A, 0x18, 0x22, 0x33, 0x3C, 0x17, 0xFF, 0xF8, 0xE0, 0x27, 0xE9, 0xDD, + 0x9A, 0x79, 0x4E, 0x14, 0x00, 0x03, 0xFE, 0x4A, 0x44, 0x20, 0x00, 0x64, 0x42, 0x50, 0x88, 0x24, + 0x3C, 0xF7, 0xFF, 0xF4, 0x3C, 0x17, 0xFF, 0xF6, 0x8A, 0x2F, 0x40, 0x12, 0x84, 0x36, 0x00, 0x53, + 0x00, 0x2D, 0x96, 0x4B, 0xE0, 0xA1, 0xE9, 0x16, 0x3C, 0x17, 0xFF, 0xF9, 0x40, 0x14, 0x04, 0x01, + 0x4E, 0x14, 0x00, 0x03, 0xFE, 0x4A, 0xFE, 0x8C, 0x3C, 0x87, 0xFF, 0xF5, 0x3C, 0x17, 0xFF, 0xF7, + 0x40, 0x80, 0xA0, 0x01, 0x40, 0x21, 0x20, 0x56, 0x00, 0x13, 0x00, 0x2E, 0x96, 0x93, 0xE0, 0x22, + 0xE8, 0xB4, 0x84, 0x27, 0x3E, 0x17, 0xE9, 0xDC, 0xD5, 0x35, 0x5A, 0x10, 0x02, 0x04, 0x5A, 0x18, + 0x15, 0x32, 0x3C, 0x17, 0xFF, 0xF6, 0x3C, 0xF7, 0xFF, 0xF4, 0x8A, 0x2F, 0x4E, 0x14, 0x00, 0x03, + 0xFE, 0x4A, 0x44, 0x50, 0x00, 0x64, 0x42, 0x20, 0x94, 0x24, 0x3C, 0xF7, 0xFF, 0xF5, 0x3C, 0x17, + 0xFF, 0xF7, 0x8A, 0x2F, 0x40, 0x11, 0x04, 0x36, 0x00, 0x23, 0x00, 0x30, 0x96, 0x4B, 0xFF, 0x54, + 0xE0, 0xA1, 0xE8, 0x06, 0x44, 0x1F, 0xFF, 0xAA, 0x3E, 0x17, 0xE9, 0xDC, 0xD5, 0x13, 0x3C, 0x17, + 0xFF, 0xF9, 0x40, 0x14, 0x04, 0x01, 0x4E, 0x14, 0x00, 0x03, 0xFE, 0x4A, 0x5E, 0xF0, 0x81, 0xF5, + 0xE8, 0xF2, 0x3C, 0x17, 0xFF, 0xF8, 0x9A, 0x79, 0x50, 0xF0, 0x80, 0x63, 0x5C, 0xF7, 0x80, 0xC7, + 0xE9, 0xEA, 0x2E, 0x17, 0xE9, 0xDC, 0xC1, 0x04, 0x8E, 0x33, 0xE6, 0x22, 0xE8, 0x2C, 0x3C, 0x17, + 0xFF, 0xF4, 0x3C, 0x27, 0xFF, 0xF6, 0x3C, 0xF7, 0xFF, 0xF5, 0x8A, 0x41, 0x3C, 0x17, 0xFF, 0xF7, + 0x8A, 0x2F, 0x4E, 0x14, 0x00, 0x03, 0xFE, 0x4A, 0x44, 0x50, 0x00, 0x64, 0xFE, 0x6C, 0x40, 0xF1, + 0x04, 0x08, 0x40, 0xF0, 0xBD, 0xF6, 0x00, 0x13, 0x00, 0x2C, 0xFE, 0x6C, 0xE0, 0x2F, 0x80, 0x25, + 0xE9, 0x0E, 0x3C, 0xF7, 0xFF, 0xF8, 0x8A, 0xEF, 0x4E, 0x74, 0x00, 0x03, 0xFF, 0xFA, 0xFF, 0xCC, + 0x00, 0x13, 0x00, 0x2A, 0x40, 0xF3, 0x89, 0xF6, 0xE0, 0x2F, 0xE8, 0x05, 0x44, 0x1F, 0xFF, 0xAA, + 0x3E, 0x17, 0xE9, 0xDC, 0x2E, 0x17, 0xE9, 0xDC, 0x5A, 0x18, 0x05, 0x15, 0x84, 0x3D, 0xFE, 0x46, + 0x5A, 0x18, 0x39, 0x11, 0x9E, 0x59, 0x44, 0x22, 0xD0, 0x04, 0x3C, 0xF7, 0xFF, 0xF8, 0x38, 0x11, + 0x06, 0x01, 0x8A, 0x2F, 0x5E, 0xF0, 0x80, 0x41, 0xE9, 0x05, 0x44, 0x1F, 0xFF, 0xAA, 0x3E, 0x17, + 0xE9, 0xDC, 0x2E, 0x17, 0xE9, 0xDC, 0x54, 0x10, 0x80, 0xFB, 0x5A, 0x18, 0x01, 0x16, 0x3C, 0xF7, + 0xFF, 0xF4, 0x3C, 0x17, 0xFF, 0xF6, 0x8A, 0x2F, 0x5E, 0xF0, 0x81, 0x40, 0xE9, 0x09, 0x3C, 0xF7, + 0xFF, 0xF5, 0x3C, 0x17, 0xFF, 0xF7, 0x8A, 0x2F, 0x5E, 0xF0, 0x80, 0xA0, 0xE8, 0x05, 0x44, 0x1F, + 0xFF, 0xAA, 0x3E, 0x17, 0xE9, 0xDC, 0x2E, 0x10, 0x00, 0x08, 0xC1, 0x20, 0x2E, 0x17, 0xE9, 0xDC, + 0x5A, 0x18, 0x01, 0x1D, 0x5A, 0x08, 0x54, 0x1B, 0x94, 0x19, 0x8E, 0x01, 0x44, 0x12, 0xD0, 0x04, + 0x3C, 0xF7, 0xFF, 0xF9, 0x38, 0x00, 0x81, 0x01, 0x8A, 0x0F, 0x4E, 0x04, 0x00, 0x03, 0xFE, 0x02, + 0x5E, 0xF0, 0x00, 0x65, 0xE9, 0x0B, 0x44, 0x0F, 0xFF, 0xAA, 0xE6, 0x63, 0x3E, 0x07, 0xE9, 0xDC, + 0xE9, 0x0B, 0xD5, 0x7E, 0x84, 0x02, 0x10, 0x05, 0x00, 0x02, 0xE6, 0x63, 0xE8, 0x79, 0x2E, 0x07, + 0xE9, 0xDC, 0x5A, 0x08, 0xAA, 0x76, 0x3C, 0x27, 0xFF, 0xFA, 0x02, 0x03, 0x00, 0x0C, 0xE0, 0x40, + 0xE9, 0x6C, 0x02, 0x03, 0x00, 0x0D, 0xE0, 0x02, 0xE9, 0x68, 0x3C, 0x07, 0xFF, 0xFB, 0x02, 0x13, + 0x00, 0x0E, 0xE0, 0x01, 0xE9, 0x62, 0x02, 0x13, 0x00, 0x0F, 0xE0, 0x20, 0xE9, 0x5E, 0x3C, 0x17, + 0xFF, 0xF9, 0x02, 0x53, 0x00, 0x0B, 0x9A, 0xC8, 0xFF, 0xEA, 0xE0, 0x67, 0xE8, 0x18, 0x3C, 0x07, + 0xFF, 0xF8, 0xFF, 0x5A, 0x8A, 0x02, 0x4E, 0x04, 0x00, 0x03, 0xFE, 0x02, 0x94, 0x01, 0xE0, 0xA0, + 0xE9, 0x20, 0x84, 0x02, 0x40, 0x01, 0x80, 0x16, 0xFE, 0x02, 0xE2, 0x04, 0xE9, 0x3B, 0x2E, 0x07, + 0xFF, 0xE5, 0xC8, 0x38, 0x84, 0x09, 0x3E, 0x07, 0xE9, 0xDC, 0xD5, 0x34, 0xE0, 0xA3, 0xE8, 0x11, + 0x02, 0x33, 0x00, 0x0A, 0xE2, 0x83, 0xE8, 0x0D, 0x3C, 0x37, 0xFF, 0xF5, 0x8E, 0x0A, 0xE0, 0x60, + 0xE9, 0x08, 0x2E, 0x07, 0xFF, 0xE5, 0xC8, 0x05, 0x84, 0x0A, 0x3E, 0x07, 0xE9, 0xDC, 0xD5, 0x22, + 0x3C, 0x07, 0xFF, 0xF8, 0x8A, 0x02, 0x02, 0x23, 0x00, 0x08, 0xFE, 0xD2, 0xE0, 0x03, 0xE8, 0x0D, + 0x02, 0x03, 0x00, 0x09, 0x40, 0xFE, 0x00, 0x06, 0xE8, 0x15, 0x2E, 0x07, 0xFF, 0xE4, 0xC8, 0x12, + 0x84, 0x0B, 0x3E, 0x07, 0xE9, 0xDC, 0xD5, 0x0E, 0xE0, 0x40, 0xE8, 0x0C, 0x02, 0x03, 0x00, 0x09, + 0x40, 0xFE, 0x00, 0x06, 0xE8, 0x07, 0x2E, 0x07, 0xFF, 0xE4, 0xC8, 0x04, 0x84, 0x0C, 0x3E, 0x07, + 0xE9, 0xDC, 0x2E, 0x07, 0xE9, 0xDC, 0x5A, 0x00, 0xAA, 0x0C, 0x3C, 0x03, 0xFF, 0xF8, 0x3C, 0x18, + 0x03, 0xA9, 0x3C, 0x08, 0x03, 0xA8, 0xD5, 0x04, 0x84, 0x02, 0x10, 0x05, 0x00, 0x02, 0x2E, 0x27, + 0xE9, 0xDC, 0xA4, 0x70, 0x5C, 0xF1, 0x00, 0x20, 0xA4, 0x31, 0xE8, 0x0E, 0x40, 0x30, 0xC0, 0x08, + 0xFE, 0x1F, 0x52, 0x21, 0x00, 0x1F, 0x40, 0x00, 0x08, 0x0E, 0x96, 0x06, 0xC8, 0x05, 0x44, 0x0F, + 0xFF, 0xAA, 0x3E, 0x07, 0xE9, 0xDC, 0x92, 0x2C, 0x96, 0x46, 0xC1, 0x5E, 0x2E, 0x07, 0xFF, 0xE3, + 0x5A, 0x08, 0x01, 0x2A, 0x2E, 0x17, 0xFF, 0xE2, 0x02, 0x03, 0x00, 0x1A, 0xE2, 0x20, 0xE8, 0x23, + 0x2E, 0x17, 0xFF, 0xE1, 0x02, 0x03, 0x00, 0x1B, 0xE2, 0x20, 0xE8, 0x1D, 0x2E, 0x07, 0xFF, 0xE0, + 0xC8, 0x1A, 0x3C, 0x07, 0xFF, 0xF8, 0x3C, 0xF7, 0xFF, 0xEE, 0x02, 0x13, 0x00, 0x19, 0x8A, 0x0F, + 0x4E, 0x04, 0x00, 0x03, 0xFE, 0x02, 0xE0, 0x01, 0xE8, 0x0E, 0x3C, 0x07, 0xFF, 0xF9, 0x3C, 0xF7, + 0xFF, 0xEF, 0x8A, 0x0F, 0x4E, 0x04, 0x00, 0x03, 0xFE, 0x02, 0xE0, 0x01, 0xE8, 0x04, 0x84, 0x03, + 0x3E, 0x07, 0xE9, 0xDC, 0x2E, 0x17, 0xE9, 0xDC, 0x84, 0x00, 0x3E, 0x07, 0xFF, 0xE1, 0x5A, 0x10, + 0x03, 0x2C, 0x3E, 0x07, 0xFF, 0xE3, 0x2E, 0x07, 0xFF, 0xE0, 0xC8, 0x26, 0x3C, 0x07, 0xFF, 0xF9, + 0x02, 0x13, 0x00, 0x1E, 0xE0, 0x01, 0xE9, 0x1D, 0x02, 0x13, 0x00, 0x1F, 0xE0, 0x20, 0xE9, 0x19, + 0x3C, 0x17, 0xFF, 0xF8, 0x02, 0x23, 0x00, 0x1C, 0xE0, 0x22, 0xE9, 0x13, 0x02, 0x23, 0x00, 0x1D, + 0xE0, 0x41, 0xE9, 0x0F, 0x2E, 0x37, 0xFF, 0xE2, 0x02, 0x23, 0x00, 0x1A, 0xE2, 0x62, 0xE8, 0x0C, + 0x84, 0x41, 0x3E, 0x27, 0xFF, 0xE3, 0x3C, 0x1B, 0xFF, 0xEE, 0x3C, 0x0B, 0xFF, 0xEF, 0xD5, 0x04, + 0x84, 0x02, 0x10, 0x05, 0x00, 0x02, 0x84, 0x00, 0x3E, 0x07, 0xFF, 0xE5, 0x3E, 0x07, 0xFF, 0xE4, + 0xD5, 0x07, 0x49, 0xFF, 0xF9, 0xD0, 0xD5, 0x04, 0x84, 0x00, 0x3E, 0x00, 0x00, 0x0A, 0x84, 0x00, + 0x3E, 0x00, 0x00, 0x0B, 0x3C, 0x2D, 0xFF, 0xF6, 0x3C, 0x00, 0x00, 0x02, 0x4E, 0x93, 0x00, 0x06, + 0x2E, 0x10, 0x06, 0x12, 0x5A, 0x18, 0x01, 0x12, 0xA4, 0x54, 0xE2, 0x01, 0xE8, 0x05, 0x8C, 0x01, + 0x3C, 0x08, 0x00, 0x02, 0xD5, 0x24, 0x84, 0x01, 0x3E, 0x00, 0x00, 0x0B, 0x84, 0x04, 0x10, 0x05, + 0x00, 0x02, 0x3E, 0x00, 0x00, 0x0A, 0xD5, 0x1B, 0x2E, 0x17, 0xFF, 0xE3, 0x5A, 0x18, 0x01, 0x0E, + 0x2E, 0x17, 0xFF, 0xE1, 0x02, 0x31, 0x00, 0x1B, 0xE2, 0x23, 0xE8, 0x05, 0x8C, 0x21, 0x3E, 0x17, + 0xFF, 0xE1, 0xD5, 0x03, 0x3E, 0x97, 0xFF, 0xE3, 0xA4, 0x54, 0xE2, 0x01, 0xE9, 0x05, 0x44, 0x0F, + 0xFF, 0xAA, 0x3E, 0x07, 0xE9, 0xDC, 0x84, 0x00, 0x3C, 0x08, 0x00, 0x02, 0x2E, 0x07, 0xFF, 0xBD, + 0xC0, 0x07, 0xFA, 0x06, 0x3E, 0x07, 0xE9, 0xDC, 0x84, 0x00, 0x3E, 0x07, 0xFF, 0xBD, 0x2E, 0x67, + 0xE9, 0xDC, 0x9E, 0x35, 0xE6, 0x02, 0xE9, 0x03, 0x5A, 0x68, 0x01, 0x4A, 0x2E, 0x00, 0x00, 0x09, + 0x44, 0x72, 0xD0, 0x04, 0x94, 0x01, 0x38, 0x83, 0x81, 0x01, 0x8C, 0x01, 0x38, 0x93, 0x81, 0x01, + 0x84, 0x00, 0x49, 0xFF, 0xFA, 0x0F, 0x84, 0x01, 0x49, 0xFF, 0xFA, 0x0C, 0x84, 0x02, 0x49, 0xFF, + 0xFA, 0x09, 0x84, 0x03, 0x49, 0xFF, 0xFA, 0x06, 0x5A, 0x68, 0x06, 0x20, 0x84, 0x00, 0x44, 0x22, + 0xCF, 0x04, 0x98, 0x78, 0x38, 0x31, 0x00, 0x01, 0xAC, 0xCA, 0x98, 0xC2, 0x8C, 0x04, 0xA4, 0xD9, + 0xAC, 0xCB, 0x5A, 0x08, 0x10, 0xF8, 0x3C, 0x0D, 0xFA, 0x76, 0x2E, 0x10, 0x00, 0x09, 0x3C, 0x88, + 0x03, 0xB0, 0x3C, 0x98, 0x03, 0xB1, 0x49, 0xFF, 0xF9, 0xC7, 0x40, 0x00, 0x20, 0x08, 0x58, 0x00, + 0x00, 0xFF, 0x3C, 0x08, 0x03, 0xB9, 0xD5, 0x16, 0x5A, 0x68, 0x05, 0x09, 0x3C, 0x00, 0x03, 0x27, + 0x3C, 0x08, 0x03, 0xA9, 0x3C, 0x08, 0x03, 0xAD, 0xD5, 0x0D, 0x5A, 0x68, 0x01, 0x09, 0x3C, 0x00, + 0x03, 0x2B, 0x3C, 0x08, 0x03, 0xA9, 0x3C, 0x08, 0x03, 0xAD, 0xD5, 0x04, 0x5C, 0xF3, 0x00, 0x20, + 0xE8, 0x24, 0x50, 0x23, 0x00, 0x0C, 0x96, 0x90, 0x84, 0x01, 0xE6, 0x5E, 0x10, 0x05, 0x00, 0x00, + 0x10, 0x25, 0x00, 0x01, 0x84, 0x01, 0xE9, 0x05, 0xFA, 0x2E, 0x49, 0xFF, 0xC0, 0x9B, 0xD5, 0x04, + 0x80, 0x22, 0x49, 0xFF, 0xC0, 0x97, 0x84, 0x03, 0x49, 0xFF, 0xC0, 0x9A, 0x84, 0x00, 0xEC, 0x1C, + 0x3E, 0x00, 0x00, 0x0A, 0x44, 0x0F, 0xFF, 0xAA, 0x3E, 0x07, 0xE9, 0xDC, 0x3A, 0x6F, 0xAA, 0x84, + 0x44, 0x00, 0x00, 0x60, 0x48, 0x00, 0x14, 0x2E, 0xEC, 0x1C, 0x84, 0x00, 0x10, 0x05, 0x00, 0x00, + 0x3A, 0x6F, 0xAA, 0x84, 0xDD, 0x9E, 0x92, 0x00, 0xEF, 0xF0, 0xF0, 0x81, 0xF0, 0x01, 0x44, 0x10, + 0x03, 0xE8, 0xFE, 0x0C, 0x50, 0x00, 0x7C, 0x61, 0x44, 0x10, 0x00, 0x93, 0x40, 0x00, 0x04, 0x37, + 0xF0, 0x83, 0x40, 0x00, 0x00, 0x09, 0xF0, 0x03, 0x9E, 0x41, 0xF1, 0x83, 0xC8, 0xFB, 0x44, 0x03, + 0xF0, 0x4A, 0x44, 0x10, 0x00, 0x55, 0xAE, 0x40, 0xEC, 0x10, 0xDD, 0x9E, 0xEF, 0xF0, 0xF0, 0x81, + 0xF1, 0x01, 0x46, 0x00, 0x00, 0xF4, 0x50, 0x00, 0x02, 0x40, 0xFE, 0x0C, 0x50, 0x00, 0x7D, 0x3A, + 0x44, 0x10, 0x02, 0x44, 0x40, 0x00, 0x04, 0x37, 0xF0, 0x83, 0xF0, 0x03, 0x44, 0x11, 0x86, 0xA0, + 0x40, 0x10, 0x04, 0x17, 0xC8, 0x06, 0x44, 0x03, 0xF0, 0x4A, 0x44, 0x10, 0x00, 0x55, 0xAE, 0x40, + 0xF0, 0x03, 0x9E, 0x41, 0xF1, 0x83, 0xC8, 0xF2, 0xEC, 0x10, 0xDD, 0x9E, 0x3B, 0xFF, 0xFC, 0xBC, + 0xEF, 0xF4, 0xF0, 0x81, 0xD5, 0x07, 0x84, 0x0A, 0x49, 0xFF, 0xFF, 0xDA, 0xF0, 0x01, 0x8E, 0x0A, + 0xF0, 0x81, 0xF0, 0x01, 0xE6, 0x0B, 0xE8, 0xF8, 0xF0, 0x01, 0x49, 0xFF, 0xFF, 0xD1, 0xEC, 0x0C, + 0x3B, 0xFF, 0xFC, 0x84, 0xDD, 0x9E, 0x3C, 0x0E, 0x00, 0x03, 0xDD, 0x9E, 0x44, 0x02, 0xCF, 0x14, + 0x84, 0x20, 0xAE, 0x40, 0xAE, 0x41, 0xAE, 0x42, 0xAE, 0x43, 0xAE, 0x44, 0xAE, 0x45, 0xAE, 0x46, + 0xAE, 0x47, 0xDD, 0x9E, 0xFC, 0x20, 0x44, 0x30, 0x27, 0x10, 0x80, 0xC0, 0xFE, 0x5C, 0x22, 0x00, + 0x00, 0x28, 0x40, 0x20, 0x88, 0x56, 0x22, 0x13, 0x00, 0x50, 0xFE, 0x1C, 0x40, 0x10, 0x04, 0x36, + 0xE0, 0x22, 0x22, 0x43, 0x00, 0x00, 0xE8, 0x53, 0x40, 0xF0, 0x11, 0xF6, 0xE0, 0x4F, 0xE8, 0x51, + 0x44, 0x50, 0x00, 0x78, 0xFA, 0x38, 0x80, 0x83, 0x98, 0x0D, 0x90, 0x01, 0x5C, 0xF0, 0x00, 0x51, + 0xE9, 0x04, 0x52, 0x30, 0x00, 0xA0, 0xD5, 0x04, 0x80, 0x60, 0x5A, 0x00, 0x28, 0x05, 0x52, 0x70, + 0x00, 0x78, 0xD5, 0x03, 0x44, 0x70, 0x00, 0x50, 0x38, 0x33, 0x0D, 0x11, 0x38, 0x73, 0x1D, 0x11, + 0xFE, 0xE4, 0x40, 0x31, 0x9C, 0x76, 0xE0, 0x43, 0xE8, 0x03, 0x9F, 0x41, 0xD5, 0x04, 0xE0, 0x62, + 0xE8, 0x34, 0x9C, 0x41, 0xE0, 0xA1, 0xE8, 0xE1, 0x4C, 0x00, 0x80, 0x03, 0x80, 0xA1, 0x5C, 0xF2, + 0x80, 0x51, 0xE9, 0x04, 0x52, 0x12, 0x80, 0xA0, 0xD5, 0x02, 0x80, 0x25, 0x50, 0x72, 0x80, 0x28, + 0x5C, 0xF3, 0x80, 0x51, 0xE9, 0x03, 0x52, 0x72, 0x80, 0x78, 0x8A, 0x62, 0x4E, 0x34, 0x00, 0x03, + 0xFE, 0xDA, 0x38, 0x13, 0x05, 0x11, 0x44, 0x40, 0x27, 0x10, 0xFF, 0x0C, 0x38, 0x13, 0x1D, 0x11, + 0x40, 0x42, 0x04, 0x96, 0x9A, 0xA2, 0x4E, 0x24, 0x00, 0x03, 0xFE, 0x92, 0xE0, 0x62, 0xE9, 0x0D, + 0xE0, 0x43, 0xE9, 0x0A, 0xE2, 0x05, 0x40, 0x02, 0xBC, 0x1A, 0xD5, 0x07, 0xFA, 0x18, 0xD5, 0x05, + 0x44, 0x00, 0x00, 0x78, 0xD5, 0x02, 0x80, 0x05, 0xFC, 0xA0, 0x5C, 0xF0, 0x00, 0x51, 0xE9, 0x05, + 0x52, 0x30, 0x00, 0xA0, 0xB6, 0x61, 0xD5, 0x02, 0xB6, 0x01, 0x50, 0x10, 0x7F, 0xD8, 0x5C, 0xF0, + 0x80, 0x51, 0xE9, 0x05, 0x52, 0x00, 0x00, 0xC8, 0xB6, 0x02, 0xDD, 0x9E, 0xB6, 0x22, 0xDD, 0x9E, + 0x3A, 0x6F, 0x9E, 0xBC, 0x80, 0xE0, 0xA6, 0x09, 0x3C, 0x63, 0xE6, 0xF9, 0x5A, 0x00, 0x01, 0x04, + 0x97, 0xB0, 0xD5, 0x02, 0xA7, 0x92, 0x2E, 0x00, 0x06, 0x2C, 0x5A, 0x08, 0x01, 0x03, 0xA7, 0x9C, + 0x49, 0xFF, 0xE7, 0xAA, 0x5A, 0x08, 0x02, 0x1C, 0x2E, 0x00, 0x06, 0x12, 0x5A, 0x08, 0x01, 0x0B, + 0x44, 0x00, 0x09, 0x60, 0x3C, 0x0B, 0xF6, 0x51, 0x44, 0x00, 0x00, 0xF0, 0x3C, 0x0B, 0xF6, 0x5D, + 0xD5, 0x13, 0x3C, 0x13, 0xF6, 0x51, 0xC1, 0x04, 0x8E, 0x21, 0x3C, 0x1B, 0xF6, 0x51, 0x3C, 0x13, + 0xF6, 0x5D, 0xC1, 0x0A, 0x8E, 0x21, 0x3C, 0x1B, 0xF6, 0x5D, 0xD5, 0x06, 0x84, 0x00, 0x3C, 0x0B, + 0xF6, 0x51, 0x3C, 0x0B, 0xF6, 0x5D, 0x22, 0xF3, 0x80, 0x03, 0xE0, 0xCF, 0xE9, 0x08, 0x3C, 0x03, + 0xF6, 0x51, 0xC8, 0x05, 0x2E, 0x07, 0xEC, 0x62, 0x5A, 0x08, 0x01, 0x08, 0x84, 0x01, 0x3E, 0x07, + 0xEC, 0x5E, 0x84, 0x00, 0x3E, 0x07, 0xEC, 0x4A, 0x3A, 0x6F, 0x9E, 0x84, 0xDD, 0x9E, 0x3C, 0x2D, + 0xFB, 0x4A, 0x2E, 0x57, 0xC7, 0x76, 0xA6, 0x91, 0x5A, 0x20, 0x06, 0x04, 0x97, 0x69, 0xD5, 0x03, + 0x2E, 0x57, 0xC7, 0x78, 0xA6, 0x01, 0x5A, 0x08, 0x01, 0x04, 0x2E, 0x57, 0xC7, 0x77, 0x2E, 0x27, + 0xC7, 0x7D, 0x2E, 0x07, 0xEC, 0x64, 0xE2, 0x02, 0x2E, 0x20, 0x05, 0xE8, 0xE9, 0x03, 0x5A, 0x28, + 0x01, 0x0D, 0x3C, 0x53, 0xE3, 0xBF, 0x5A, 0x28, 0x01, 0x06, 0x84, 0x00, 0x3E, 0x07, 0xEC, 0x64, + 0xD5, 0x04, 0x8C, 0x01, 0x3E, 0x07, 0xEC, 0x64, 0x2E, 0x27, 0xEC, 0x4A, 0x2E, 0x07, 0xC7, 0x7C, + 0x2E, 0x47, 0xC7, 0x75, 0xE2, 0x40, 0xE9, 0x30, 0x2E, 0x07, 0xEC, 0x4B, 0x5A, 0x08, 0x01, 0x33, + 0x40, 0x40, 0x10, 0x0C, 0x8A, 0x85, 0x3A, 0x6F, 0xA4, 0x3C, 0x97, 0x21, 0x84, 0xE0, 0x3C, 0x03, + 0xE3, 0x76, 0xE2, 0xE0, 0xE8, 0x25, 0xA1, 0x8A, 0xB4, 0x01, 0x94, 0xB9, 0x88, 0xC2, 0x04, 0x30, + 0x80, 0x14, 0x88, 0x02, 0x02, 0x93, 0x00, 0x00, 0x88, 0x62, 0xA4, 0x00, 0xA4, 0x98, 0xFE, 0x2C, + 0x42, 0x02, 0x24, 0x73, 0x88, 0x02, 0x2E, 0x27, 0xC7, 0x75, 0x8C, 0xE1, 0x40, 0x20, 0x08, 0x0D, + 0x96, 0x91, 0xAC, 0xB0, 0xA4, 0xB0, 0x2E, 0x67, 0xC7, 0x75, 0x40, 0x21, 0x18, 0x0C, 0x8A, 0x02, + 0x96, 0x01, 0xAC, 0x18, 0xD5, 0xDD, 0x8C, 0x41, 0x3E, 0x27, 0xEC, 0x4A, 0xDD, 0x9E, 0x3A, 0x6F, + 0xA4, 0x04, 0xDD, 0x9E, 0x2E, 0x07, 0xC7, 0x5F, 0x5A, 0x08, 0x01, 0x6E, 0x2E, 0x17, 0xEC, 0x5E, + 0xC9, 0x51, 0x3A, 0x6F, 0xA4, 0x3C, 0xEF, 0xF0, 0x80, 0x01, 0x44, 0x92, 0x25, 0xB0, 0x80, 0xDF, + 0x44, 0x71, 0x32, 0x14, 0x3C, 0x13, 0xE3, 0x76, 0xE2, 0x01, 0xE8, 0x27, 0x3C, 0x2C, 0x02, 0xA7, + 0x94, 0x41, 0x88, 0x22, 0x3C, 0x23, 0xE3, 0xC2, 0xA4, 0xC8, 0xFE, 0x92, 0x96, 0xDB, 0xE0, 0x62, + 0xE8, 0x0D, 0x3A, 0x23, 0x94, 0x00, 0x3A, 0x23, 0x14, 0x20, 0x84, 0x20, 0x38, 0x53, 0x05, 0x01, + 0xD0, 0x11, 0x8C, 0x21, 0x5A, 0x18, 0x08, 0xFC, 0xD5, 0x31, 0xA4, 0x48, 0x96, 0x4B, 0x4E, 0x17, + 0x00, 0x0A, 0x40, 0x20, 0x24, 0x00, 0xA6, 0x50, 0xC1, 0x05, 0xA6, 0x50, 0x8E, 0x21, 0x96, 0x48, + 0xAE, 0x50, 0x8C, 0x01, 0x96, 0x01, 0xD5, 0xD7, 0x3C, 0x03, 0xF6, 0x54, 0x3C, 0x13, 0xE3, 0xC3, + 0xE2, 0x20, 0x84, 0x01, 0xE8, 0x2C, 0x84, 0x20, 0x3C, 0x1B, 0xF6, 0x54, 0x84, 0x00, 0x44, 0x32, + 0x25, 0xB0, 0x3C, 0x23, 0xE3, 0x76, 0xE2, 0x02, 0xE8, 0x06, 0x98, 0x83, 0x8C, 0x01, 0xAE, 0x50, + 0x96, 0x01, 0xD5, 0xF8, 0x2E, 0x00, 0x06, 0x2F, 0x8C, 0x01, 0x3E, 0x00, 0x06, 0x2F, 0x84, 0x02, + 0xD5, 0x16, 0x84, 0x20, 0x3C, 0x1B, 0xF6, 0x54, 0xDD, 0x9E, 0x40, 0x20, 0x24, 0x00, 0xA6, 0x50, + 0x8C, 0x21, 0x96, 0x48, 0xAE, 0x50, 0xA6, 0x90, 0x3C, 0x13, 0xE3, 0xBD, 0xE2, 0x41, 0xE9, 0xD2, + 0x3C, 0x13, 0xF6, 0x54, 0x8C, 0x21, 0x3C, 0x1B, 0xF6, 0x54, 0xD5, 0xCC, 0xEC, 0x10, 0x3A, 0x6F, + 0xA4, 0x04, 0xDD, 0x9E, 0x84, 0x01, 0xDD, 0x9E, 0xFC, 0x00, 0x84, 0x00, 0x44, 0x10, 0x00, 0x7F, + 0x3E, 0x07, 0xEC, 0x11, 0x3E, 0x07, 0xEC, 0x37, 0x3E, 0x07, 0xEC, 0x1A, 0x3E, 0x07, 0xEC, 0x65, + 0x3E, 0x07, 0xEC, 0x61, 0x3E, 0x17, 0xEC, 0x63, 0x3E, 0x07, 0xEC, 0x22, 0x3E, 0x07, 0xEC, 0x72, + 0xFC, 0x80, 0xFC, 0x00, 0x84, 0x20, 0x84, 0x61, 0x80, 0x41, 0x80, 0x83, 0x44, 0x00, 0x56, 0x40, + 0x49, 0x00, 0x21, 0xB7, 0x54, 0x10, 0x00, 0x7F, 0x84, 0x41, 0x58, 0x10, 0x80, 0x80, 0x80, 0x62, + 0x80, 0x82, 0x44, 0x00, 0x56, 0x40, 0x49, 0x00, 0x21, 0xAC, 0xFC, 0x80, 0xFC, 0x00, 0x84, 0x20, + 0x84, 0x61, 0x80, 0x41, 0x44, 0x00, 0xDA, 0xE0, 0x80, 0x83, 0x49, 0x00, 0x21, 0xA2, 0x44, 0x10, + 0x02, 0x71, 0xFE, 0x0C, 0x44, 0x10, 0x03, 0xE8, 0x40, 0x00, 0x04, 0x16, 0x2E, 0x1F, 0xEC, 0x63, + 0x50, 0x00, 0x7F, 0xD8, 0x96, 0x02, 0x5A, 0x18, 0x7F, 0x04, 0x3E, 0x07, 0xEC, 0x63, 0x2E, 0x1F, + 0xEC, 0x63, 0x5A, 0x10, 0x7F, 0x1A, 0x8A, 0x01, 0x4E, 0x04, 0x00, 0x03, 0xFE, 0x02, 0xE4, 0x0F, + 0xE9, 0x13, 0x84, 0x21, 0xE4, 0x19, 0x3E, 0x17, 0xEC, 0x37, 0xE9, 0x09, 0x5E, 0xF0, 0x00, 0x3C, + 0x3E, 0x17, 0xEC, 0x1A, 0xE9, 0x07, 0x3E, 0x17, 0xEC, 0x65, 0xD5, 0x0D, 0x84, 0x00, 0x3E, 0x07, + 0xEC, 0x1A, 0x84, 0x00, 0xD5, 0x06, 0x84, 0x00, 0x3E, 0x07, 0xEC, 0x37, 0x3E, 0x07, 0xEC, 0x1A, + 0x3E, 0x07, 0xEC, 0x65, 0xFC, 0x80, 0xFC, 0x40, 0x2E, 0x07, 0xEC, 0x65, 0x5A, 0x00, 0x01, 0x0A, + 0x2E, 0x07, 0xEC, 0x1A, 0x5A, 0x08, 0x01, 0x0B, 0xFA, 0xF1, 0x44, 0x60, 0x00, 0xC8, 0xD5, 0x09, + 0x44, 0x70, 0x00, 0x32, 0x44, 0x60, 0x01, 0x2C, 0xD5, 0x04, 0xFA, 0xE9, 0x44, 0x60, 0x00, 0x96, + 0x94, 0xD9, 0x44, 0x02, 0xC8, 0xDC, 0x88, 0x60, 0x50, 0xA0, 0x84, 0x80, 0x85, 0x20, 0x84, 0xA0, + 0x81, 0x01, 0x80, 0x05, 0x5A, 0x50, 0x07, 0x18, 0x22, 0x44, 0x00, 0x00, 0x22, 0xF4, 0x00, 0x01, + 0x40, 0xF2, 0x3C, 0x01, 0x4E, 0xF4, 0x00, 0x04, 0x52, 0xF7, 0x80, 0x00, 0x40, 0xF7, 0x9C, 0x07, + 0xE8, 0x23, 0x4E, 0x44, 0x00, 0x03, 0xFF, 0x22, 0xE0, 0x86, 0xE8, 0x1E, 0x38, 0xF1, 0x15, 0x01, + 0xA5, 0x18, 0xD5, 0x16, 0x22, 0x40, 0x80, 0x07, 0x22, 0xF0, 0x80, 0x06, 0x40, 0xF2, 0x3C, 0x01, + 0x4E, 0xF4, 0x00, 0x04, 0x52, 0xF7, 0x80, 0x00, 0x40, 0xF7, 0x9C, 0x07, 0xE8, 0x0D, 0x4E, 0x44, + 0x00, 0x03, 0xFF, 0x22, 0xE0, 0x86, 0xE8, 0x08, 0x02, 0xF1, 0x80, 0x00, 0xA5, 0x17, 0x88, 0x8F, + 0x8C, 0x01, 0xAD, 0x18, 0x96, 0x00, 0x8C, 0xA1, 0x8D, 0x02, 0x5A, 0x58, 0x08, 0xCD, 0xC8, 0x09, + 0x50, 0x10, 0x80, 0x20, 0x50, 0x21, 0x00, 0x20, 0x8C, 0x62, 0x4C, 0x15, 0x7F, 0xC2, 0xFC, 0xC0, + 0x22, 0x41, 0x80, 0x00, 0xE6, 0x06, 0x40, 0x42, 0x00, 0x96, 0xAD, 0x18, 0xE9, 0xF2, 0x80, 0xA2, + 0x50, 0xF1, 0x00, 0x10, 0x2A, 0x82, 0x80, 0x01, 0x40, 0x04, 0x10, 0x01, 0x4E, 0x85, 0x00, 0x05, + 0x4E, 0x04, 0x00, 0x08, 0xD5, 0x03, 0x4E, 0x07, 0x00, 0x05, 0x12, 0x92, 0xFF, 0xFF, 0xD5, 0x03, + 0x12, 0x02, 0xFF, 0xFF, 0x4C, 0x57, 0xFF, 0xF0, 0xD5, 0xDC, 0xC8, 0x11, 0x3E, 0x07, 0xEC, 0x61, + 0x44, 0x32, 0xC9, 0x6C, 0x80, 0x80, 0x44, 0x12, 0xC8, 0xDC, 0x80, 0x40, 0x38, 0x41, 0x80, 0x08, + 0x38, 0x20, 0x81, 0x09, 0x8C, 0x01, 0x5A, 0x08, 0x48, 0xFB, 0xDD, 0x9E, 0xFC, 0x00, 0x80, 0x61, + 0xA0, 0x4E, 0x5A, 0x08, 0x01, 0x05, 0xA0, 0x9D, 0x84, 0x60, 0xD5, 0x05, 0xA0, 0x9D, 0x8C, 0x30, + 0x8C, 0x50, 0xFA, 0x74, 0x49, 0xFF, 0xFF, 0x69, 0xFC, 0x80, 0xFC, 0x42, 0x00, 0xA1, 0x80, 0x03, + 0xA7, 0xDA, 0x50, 0x55, 0x7F, 0xFD, 0x40, 0x83, 0x84, 0x0A, 0x97, 0x68, 0x42, 0x62, 0x9C, 0x24, + 0x84, 0x60, 0x95, 0xB1, 0x80, 0x83, 0x4C, 0x43, 0x80, 0x11, 0x04, 0x90, 0x00, 0x05, 0x89, 0x26, + 0x02, 0x94, 0x80, 0x00, 0x40, 0x94, 0x80, 0x11, 0xE5, 0x35, 0xE9, 0x03, 0x8C, 0x61, 0x96, 0xD8, + 0x8C, 0x81, 0x97, 0x20, 0x8C, 0xC2, 0xD5, 0xF0, 0xE0, 0x68, 0xE8, 0x06, 0x8C, 0xA1, 0x97, 0x68, + 0x4C, 0x55, 0x7F, 0xE6, 0x84, 0xA0, 0x2E, 0x47, 0xEC, 0x56, 0x44, 0x3F, 0xFF, 0xD8, 0xFE, 0xE4, + 0x50, 0x31, 0x80, 0x64, 0x96, 0x19, 0xF0, 0x81, 0x44, 0x0F, 0xFF, 0xC4, 0xFE, 0x24, 0x50, 0x00, + 0x00, 0x82, 0x96, 0x01, 0x9F, 0x29, 0xF0, 0x82, 0x2E, 0x60, 0x05, 0xDA, 0x2E, 0x90, 0x05, 0xDB, + 0x44, 0x32, 0xCE, 0x88, 0x50, 0x10, 0x80, 0x6C, 0x84, 0x00, 0x45, 0xC2, 0xCE, 0x64, 0x44, 0x72, + 0xCE, 0x70, 0x44, 0x82, 0xCE, 0x7C, 0xF4, 0x83, 0x04, 0xA0, 0xFF, 0xE5, 0x5A, 0xA8, 0x01, 0x0F, + 0x84, 0x80, 0x38, 0x4E, 0x00, 0x08, 0x38, 0x43, 0x80, 0x08, 0x00, 0xF0, 0x80, 0x00, 0x5C, 0xF7, + 0x80, 0x21, 0x40, 0x45, 0x3C, 0x1A, 0x38, 0x44, 0x00, 0x08, 0x50, 0x45, 0x7F, 0xFF, 0xE6, 0x82, + 0xE8, 0x5B, 0x5A, 0xA8, 0x02, 0x08, 0xA7, 0x18, 0x5A, 0x48, 0x01, 0x05, 0x44, 0xF0, 0x00, 0x22, + 0xD5, 0x03, 0x44, 0xF0, 0x00, 0x23, 0x38, 0xA4, 0x00, 0x00, 0x84, 0x80, 0xAF, 0x18, 0x5A, 0xA8, + 0x01, 0x4C, 0xA7, 0x08, 0xCD, 0x1A, 0x5A, 0x48, 0x23, 0x3A, 0x04, 0x40, 0xFF, 0xEB, 0x05, 0xE1, + 0x00, 0x05, 0x95, 0x22, 0x88, 0x9E, 0xA7, 0x22, 0xE2, 0x8F, 0xE9, 0x30, 0xF4, 0x02, 0x05, 0xEF, + 0x80, 0x01, 0x22, 0xF0, 0xFF, 0xE9, 0x40, 0x4F, 0x18, 0x1A, 0x40, 0xF7, 0x90, 0x07, 0xE8, 0x26, + 0x10, 0xA1, 0x80, 0x00, 0x80, 0xCA, 0xD5, 0x20, 0xE2, 0x85, 0xE9, 0x20, 0x04, 0x40, 0xFF, 0xEB, + 0x04, 0xA1, 0x00, 0x05, 0x95, 0x22, 0x88, 0x8A, 0x04, 0xFF, 0x80, 0x03, 0x00, 0xA2, 0x00, 0x02, + 0xE1, 0x4F, 0xE9, 0x14, 0xA7, 0x23, 0x5C, 0xF2, 0x00, 0x22, 0xE9, 0x10, 0x22, 0xA0, 0xFF, 0xE9, + 0xCE, 0x04, 0x44, 0xF0, 0x00, 0x8C, 0xD5, 0x03, 0x44, 0xF0, 0x00, 0xAA, 0xE1, 0x4F, 0xE8, 0x06, + 0x84, 0x81, 0xAF, 0x18, 0x84, 0xC1, 0x44, 0x90, 0x00, 0x5A, 0xA7, 0x18, 0x5A, 0x48, 0x01, 0x04, + 0x84, 0x82, 0xD5, 0x08, 0x38, 0x43, 0x80, 0x00, 0xC4, 0x07, 0x85, 0x41, 0x10, 0xA1, 0x80, 0x00, + 0x8E, 0x81, 0x38, 0x43, 0x80, 0x08, 0x8C, 0x01, 0x8C, 0x61, 0x50, 0x10, 0x80, 0xE0, 0x5A, 0x08, + 0x0A, 0x8D, 0x3E, 0x60, 0x05, 0xDA, 0x3E, 0x90, 0x05, 0xDB, 0xFC, 0xC2, 0xFC, 0x44, 0xF0, 0x84, + 0x2E, 0x00, 0x05, 0xE6, 0xC8, 0x03, 0x3C, 0x0E, 0x00, 0x60, 0x83, 0xC0, 0x2E, 0x00, 0x05, 0xE7, + 0x2E, 0x27, 0xEC, 0x66, 0xF0, 0x83, 0x2E, 0x00, 0x06, 0x08, 0xF2, 0x86, 0xF0, 0x87, 0x3C, 0x8C, + 0x00, 0x60, 0x44, 0x92, 0xC9, 0xDC, 0x50, 0x10, 0x80, 0xD8, 0x84, 0x00, 0x44, 0x22, 0xCE, 0x94, + 0x84, 0x60, 0x38, 0x31, 0x00, 0x08, 0x04, 0x20, 0xFF, 0xCA, 0x9F, 0x11, 0xE6, 0x82, 0xE9, 0x06, + 0x5A, 0x20, 0x04, 0x04, 0x48, 0x00, 0x01, 0x20, 0xD5, 0x0F, 0x5A, 0x28, 0x01, 0x0E, 0xAE, 0xC8, + 0x00, 0x30, 0xFF, 0x94, 0x5C, 0xF1, 0x80, 0x21, 0xE9, 0x02, 0xAE, 0x88, 0x44, 0x32, 0xCE, 0x64, + 0x84, 0x40, 0x38, 0x21, 0x80, 0x08, 0x00, 0x20, 0xFF, 0x95, 0xC2, 0x07, 0x9E, 0xD1, 0x96, 0xD8, + 0xB6, 0x7F, 0x5A, 0x20, 0x0F, 0x07, 0xD5, 0x02, 0xB6, 0x5F, 0x8C, 0x41, 0x96, 0x90, 0xD5, 0x03, + 0x84, 0x6E, 0xB6, 0x7F, 0x00, 0x50, 0xFF, 0x94, 0xF2, 0x81, 0xC5, 0x06, 0x9E, 0xA9, 0x96, 0x90, + 0x5A, 0x50, 0x23, 0x08, 0xD5, 0x02, 0x80, 0x45, 0x9C, 0xE9, 0x96, 0xD8, 0xF3, 0x82, 0xD5, 0x03, + 0xFA, 0x52, 0xF5, 0x82, 0x84, 0xC0, 0xB5, 0x5F, 0x80, 0x86, 0xF3, 0x01, 0xE2, 0x6A, 0xE9, 0x28, + 0x80, 0xE2, 0x87, 0x80, 0xF3, 0x02, 0xE2, 0x67, 0xE9, 0x1B, 0x04, 0xFF, 0x80, 0x04, 0x94, 0xFC, + 0x88, 0x6A, 0x04, 0xF7, 0x80, 0x05, 0x94, 0xD9, 0x88, 0x6F, 0x02, 0xF1, 0x80, 0x00, 0x40, 0xF7, + 0x80, 0x11, 0x4E, 0xF7, 0x00, 0x0B, 0x02, 0xF1, 0x80, 0x00, 0xA4, 0xD8, 0x40, 0xF7, 0x80, 0x11, + 0x96, 0xDB, 0x88, 0x8F, 0x41, 0xCE, 0x0C, 0x00, 0x8C, 0xE1, 0x97, 0xF8, 0xD5, 0xE4, 0xE2, 0xDC, + 0x50, 0x35, 0x00, 0x01, 0x40, 0x6E, 0x3C, 0x1B, 0x54, 0xA1, 0x80, 0xFF, 0xD5, 0xD7, 0x84, 0x60, + 0xF7, 0x02, 0xE2, 0xE2, 0xE9, 0x28, 0x95, 0xD4, 0xF7, 0x85, 0x87, 0x80, 0xB4, 0xFF, 0x04, 0xAF, + 0x80, 0x01, 0xE3, 0x47, 0xE9, 0x1A, 0x04, 0xFF, 0x80, 0x04, 0x04, 0xAF, 0x80, 0x05, 0x04, 0xF7, + 0x80, 0x05, 0x89, 0x47, 0x40, 0xA5, 0x04, 0x08, 0x89, 0x4F, 0x02, 0xF5, 0x00, 0x00, 0x40, 0xF7, + 0x80, 0x11, 0x4E, 0xF7, 0x00, 0x08, 0x02, 0xA5, 0x00, 0x00, 0x40, 0xA5, 0x00, 0x11, 0x41, 0xCE, + 0x28, 0x00, 0x8C, 0xE1, 0x97, 0xF8, 0xD5, 0xE4, 0xE2, 0x7C, 0x8C, 0x41, 0x40, 0x3E, 0x3C, 0x1B, + 0x96, 0x90, 0xD5, 0xD7, 0xA6, 0x88, 0xE2, 0x66, 0x40, 0x33, 0x3C, 0x1B, 0x5A, 0x20, 0x01, 0x06, + 0x5A, 0x20, 0x02, 0x21, 0x48, 0x00, 0x00, 0x90, 0xF2, 0x06, 0xC2, 0x04, 0x44, 0x20, 0x04, 0x38, + 0xD5, 0x03, 0x44, 0x20, 0x03, 0x84, 0x5B, 0xE0, 0x01, 0x05, 0xE2, 0x44, 0x4E, 0xF2, 0x00, 0x84, + 0x84, 0x42, 0xAE, 0x88, 0x44, 0x22, 0xCA, 0x10, 0x38, 0x41, 0x02, 0x0A, 0x44, 0x22, 0xC9, 0xE8, + 0x38, 0x31, 0x02, 0x0A, 0x84, 0x4F, 0x5B, 0xE0, 0x01, 0x04, 0x48, 0x00, 0x00, 0x75, 0x48, 0x00, + 0x00, 0x71, 0x44, 0x62, 0xCA, 0x10, 0x94, 0x82, 0x38, 0x63, 0x02, 0x02, 0xE2, 0xC4, 0xE8, 0x05, + 0x44, 0x62, 0xCA, 0x10, 0x38, 0x43, 0x02, 0x0A, 0x44, 0x62, 0xC9, 0xE8, 0x38, 0x63, 0x08, 0x02, + 0xE2, 0xC3, 0xE8, 0x05, 0x44, 0x62, 0xC9, 0xE8, 0x38, 0x33, 0x08, 0x0A, 0x44, 0x62, 0xCA, 0x10, + 0xFA, 0xFD, 0x38, 0x63, 0x08, 0x02, 0xFF, 0xBC, 0x44, 0x70, 0x00, 0x64, 0x40, 0x63, 0x1C, 0xD6, + 0xE2, 0xC8, 0x40, 0x64, 0x3C, 0x1B, 0x5C, 0xF3, 0x02, 0x59, 0xE9, 0x03, 0x44, 0x60, 0x02, 0x58, + 0x44, 0x72, 0xC9, 0xB4, 0x5C, 0xF2, 0x80, 0x21, 0x38, 0x63, 0x88, 0x0A, 0xE9, 0x3E, 0x04, 0x50, + 0xFF, 0xD2, 0x5C, 0xF2, 0x85, 0x35, 0xE8, 0x39, 0x5B, 0xE8, 0x01, 0x0A, 0x44, 0x50, 0x00, 0x8C, + 0xFF, 0x74, 0x44, 0xF0, 0x00, 0x64, 0x40, 0xF2, 0xBD, 0xF7, 0xD5, 0x02, 0x81, 0xE6, 0xE2, 0x8F, + 0xE8, 0x2C, 0x44, 0x42, 0xC9, 0xE8, 0x44, 0xF0, 0x00, 0x64, 0x38, 0x42, 0x08, 0x02, 0xFA, 0x5D, + 0xFE, 0xA4, 0x40, 0xF1, 0x3D, 0xF6, 0xE2, 0x6F, 0xE8, 0x20, 0x00, 0x24, 0x80, 0x00, 0xE6, 0x4F, + 0xE8, 0x04, 0x8C, 0x41, 0x10, 0x24, 0x80, 0x00, 0x00, 0x44, 0x80, 0x00, 0x50, 0x3F, 0x00, 0x01, + 0x84, 0x4F, 0x40, 0xF1, 0x0D, 0xF6, 0xE0, 0x8F, 0xE9, 0x16, 0xF2, 0x07, 0xE3, 0x06, 0x40, 0x83, + 0x3C, 0x1B, 0xCA, 0x06, 0x44, 0x32, 0xCE, 0x94, 0x84, 0x41, 0x38, 0x21, 0x80, 0x08, 0x44, 0x20, + 0x00, 0x5A, 0xF2, 0x83, 0x87, 0xC1, 0xD5, 0x07, 0x00, 0x24, 0x80, 0x00, 0xC2, 0x04, 0x8E, 0x41, + 0x10, 0x24, 0x80, 0x00, 0x8C, 0x01, 0x8D, 0x21, 0x50, 0x10, 0x80, 0xE0, 0x5A, 0x00, 0x0A, 0x04, + 0x48, 0xFF, 0xFE, 0xCE, 0x00, 0x0F, 0x80, 0x0C, 0x3F, 0xE0, 0x05, 0xE6, 0x3C, 0x8E, 0x00, 0x60, + 0x3E, 0x00, 0x05, 0xE7, 0xFC, 0xC4, 0xFC, 0x00, 0x3C, 0x1D, 0xFB, 0x4D, 0xA4, 0x48, 0x92, 0x26, + 0x96, 0x46, 0xC9, 0x1A, 0x2E, 0x10, 0x05, 0xFC, 0xC9, 0x17, 0xFA, 0x70, 0x8C, 0x21, 0x96, 0x48, + 0x5A, 0x10, 0x24, 0x1D, 0x5C, 0xF0, 0x80, 0x21, 0xE9, 0x0C, 0xA1, 0x45, 0x84, 0x40, 0x99, 0x13, + 0x88, 0x85, 0xA5, 0x20, 0x97, 0x23, 0xE4, 0x95, 0xE8, 0x21, 0x8C, 0x42, 0x5A, 0x28, 0x20, 0xF9, + 0x50, 0x31, 0x80, 0x20, 0xD5, 0xEC, 0x84, 0x00, 0x3E, 0x00, 0x05, 0xE6, 0x3E, 0x00, 0x05, 0xE7, + 0x3E, 0x00, 0x05, 0xDA, 0x3E, 0x00, 0x05, 0xDB, 0xD5, 0x11, 0x2E, 0x00, 0x05, 0xE7, 0xC0, 0x05, + 0x8E, 0x01, 0x3E, 0x00, 0x05, 0xE7, 0xD5, 0x03, 0x3E, 0x00, 0x05, 0xE6, 0x2E, 0x00, 0x05, 0xDB, + 0xC0, 0x03, 0x8E, 0x01, 0xD5, 0xF0, 0x3E, 0x00, 0x05, 0xDA, 0xFC, 0x80, 0x3C, 0x0F, 0xFB, 0x42, + 0xDD, 0x9E, 0x3C, 0x0F, 0xFB, 0x41, 0xDD, 0x9E, 0x2E, 0x10, 0x01, 0x85, 0x84, 0x00, 0x3E, 0x00, + 0x01, 0x84, 0xC1, 0x08, 0x84, 0x21, 0x3E, 0x07, 0xEC, 0x60, 0x3E, 0x17, 0xEC, 0x31, 0x3E, 0x00, + 0x01, 0x85, 0x84, 0x00, 0xDD, 0x9E, 0x84, 0x1F, 0x3C, 0x0F, 0xFA, 0xCF, 0x84, 0x00, 0x3E, 0x00, + 0x01, 0x85, 0x3E, 0x00, 0x01, 0x84, 0xDD, 0x9E, 0xFC, 0x4A, 0xF1, 0x92, 0xA0, 0x45, 0x94, 0x92, + 0x88, 0x41, 0xF3, 0x93, 0xA6, 0x53, 0x01, 0xC1, 0x00, 0x00, 0xA7, 0xD1, 0x01, 0xE1, 0x00, 0x02, + 0xF1, 0x82, 0x84, 0x20, 0xF1, 0x81, 0xF1, 0x01, 0xF2, 0x13, 0xE0, 0x22, 0x4E, 0xF2, 0x01, 0x0B, + 0xA0, 0x41, 0xF2, 0x01, 0x38, 0x50, 0x89, 0x01, 0x4C, 0x51, 0x41, 0x01, 0x94, 0x52, 0xA0, 0x85, + 0xF1, 0x8A, 0x88, 0x41, 0xA7, 0x10, 0xE4, 0x83, 0xE9, 0x03, 0x8E, 0x83, 0xD5, 0x02, 0x84, 0x80, + 0xA6, 0xD1, 0x2E, 0x17, 0xC6, 0xBA, 0x8C, 0x63, 0xE0, 0x61, 0xE9, 0x02, 0x9E, 0xC9, 0xA6, 0x52, + 0xE4, 0x23, 0xE9, 0x03, 0x8E, 0x23, 0xD5, 0x02, 0x84, 0x20, 0xA6, 0x93, 0x2E, 0x57, 0xC6, 0xBB, + 0x8C, 0x43, 0xE0, 0x45, 0xE9, 0x02, 0x9E, 0xA9, 0xE0, 0xE4, 0x4E, 0xF3, 0x00, 0xE0, 0xE0, 0x7C, + 0x4E, 0xF3, 0x00, 0xDD, 0xF5, 0x02, 0xE0, 0xA1, 0x4E, 0xF3, 0x00, 0xD9, 0xE0, 0x5E, 0x4E, 0xF3, + 0x00, 0xD6, 0xE0, 0x9C, 0x40, 0x4E, 0x3C, 0x1B, 0xE0, 0xE3, 0x40, 0x33, 0xBC, 0x1B, 0xE0, 0x3E, + 0x40, 0x1F, 0x3C, 0x1B, 0xE0, 0xA2, 0x40, 0x22, 0xBC, 0x1B, 0xF4, 0x8C, 0xF3, 0x8D, 0xF2, 0x8E, + 0xF2, 0x0E, 0xE0, 0x41, 0x4E, 0xF3, 0x00, 0xC3, 0xE4, 0x24, 0x84, 0x40, 0xE9, 0x02, 0x9E, 0x8B, + 0xF2, 0x84, 0x9C, 0x8B, 0xF4, 0x0C, 0xF2, 0x8B, 0xF2, 0x0D, 0xE0, 0x44, 0x4E, 0xF3, 0x00, 0xB4, + 0x44, 0x23, 0xF0, 0x4A, 0x44, 0x30, 0x00, 0x55, 0xAE, 0xD0, 0xB4, 0x40, 0xF2, 0x86, 0x3C, 0x2D, + 0xFB, 0x41, 0xA6, 0xD2, 0xF3, 0x83, 0xF5, 0x03, 0x80, 0x64, 0x42, 0x30, 0x94, 0x73, 0xF5, 0x06, + 0x38, 0x32, 0x8D, 0x00, 0x5A, 0x38, 0xFF, 0x04, 0x48, 0x00, 0x00, 0x9B, 0xA1, 0x41, 0xF5, 0x87, + 0x38, 0x32, 0x8D, 0x11, 0x4E, 0x34, 0x00, 0x95, 0xE4, 0x84, 0x84, 0xA0, 0xE9, 0x02, 0x9F, 0x63, + 0xA0, 0xC5, 0xF6, 0x0A, 0xF3, 0x88, 0x88, 0x66, 0xA6, 0x93, 0x00, 0xA1, 0x80, 0x01, 0xE1, 0x45, + 0x4E, 0xF3, 0x00, 0x87, 0x04, 0x9F, 0x80, 0x03, 0x9D, 0xA3, 0x8F, 0x21, 0xE1, 0x26, 0x00, 0x81, + 0x80, 0x00, 0x40, 0x93, 0x3C, 0x1A, 0xE1, 0x28, 0x14, 0x9F, 0x80, 0x05, 0xE9, 0x79, 0x00, 0x91, + 0x80, 0x03, 0x04, 0xFF, 0x80, 0x04, 0xE1, 0x2F, 0xE9, 0x73, 0x04, 0xFF, 0x80, 0x0B, 0x8E, 0x41, + 0xF6, 0x0B, 0xE0, 0x4F, 0xA6, 0xDA, 0x40, 0x23, 0x3C, 0x1A, 0xE0, 0x43, 0xE9, 0x69, 0xE0, 0xA8, + 0x40, 0x82, 0xBC, 0x1A, 0xF5, 0x05, 0x14, 0x8F, 0x80, 0x09, 0xE1, 0x45, 0x40, 0xA2, 0xBC, 0x1A, + 0xF5, 0x04, 0x14, 0xAF, 0x80, 0x0F, 0xE0, 0xA3, 0x40, 0x32, 0xBC, 0x1A, 0xE1, 0x22, 0x40, 0x91, + 0x3C, 0x1A, 0x3C, 0x20, 0x05, 0x3E, 0x14, 0x9F, 0x80, 0x10, 0xF2, 0x91, 0xF2, 0x03, 0x42, 0x51, + 0x88, 0x24, 0xF2, 0x10, 0xE0, 0x43, 0xE9, 0x4C, 0xF2, 0x09, 0x99, 0x95, 0x95, 0xB1, 0x81, 0x42, + 0xF2, 0x0F, 0xE0, 0x4A, 0xE9, 0x41, 0xF2, 0x06, 0x38, 0x21, 0x18, 0x00, 0x5A, 0x20, 0xFF, 0x3A, + 0x04, 0x8F, 0x80, 0x07, 0x40, 0x91, 0x04, 0x08, 0x89, 0x28, 0x02, 0x84, 0x80, 0x00, 0x14, 0x8F, + 0x80, 0x05, 0x22, 0x8F, 0x80, 0x0A, 0x4E, 0x85, 0x00, 0x2D, 0x04, 0x8F, 0x80, 0x12, 0x04, 0xFF, + 0x80, 0x11, 0x04, 0x84, 0x00, 0x05, 0x89, 0x06, 0x02, 0x84, 0x00, 0x00, 0x40, 0x84, 0x00, 0x11, + 0xE1, 0x0F, 0xE9, 0x1F, 0xF3, 0x05, 0x44, 0x1F, 0x80, 0x00, 0xFE, 0xCF, 0xF1, 0x08, 0x94, 0x92, + 0x88, 0x22, 0x12, 0x34, 0x80, 0x00, 0x80, 0x41, 0xA6, 0x48, 0xE0, 0x3C, 0x41, 0xC0, 0xBC, 0x1B, + 0xA6, 0x51, 0xE0, 0xE1, 0x40, 0x70, 0xBC, 0x1B, 0xA6, 0x52, 0xE0, 0x3E, 0x41, 0xE0, 0xBC, 0x1B, + 0xA6, 0x53, 0xF2, 0x02, 0xE0, 0x41, 0x40, 0x20, 0xBC, 0x1B, 0xF2, 0x82, 0x48, 0xFF, 0xFF, 0x03, + 0x8D, 0x41, 0x8C, 0xC2, 0xD5, 0xBE, 0xF2, 0x03, 0x8C, 0x61, 0x88, 0xA2, 0xD5, 0xB3, 0x8C, 0x81, + 0x48, 0xFF, 0xFF, 0x4C, 0x8C, 0x21, 0x48, 0xFF, 0xFF, 0x3D, 0xF1, 0x01, 0x8C, 0x21, 0x48, 0xFF, + 0xFE, 0xF3, 0xFC, 0xCA, 0xFC, 0x40, 0xA6, 0x12, 0xC0, 0x03, 0x8E, 0x01, 0xAE, 0x12, 0x3C, 0x7D, + 0xFB, 0x41, 0xA7, 0x53, 0xA6, 0x3B, 0x8E, 0x01, 0xD0, 0x03, 0x8C, 0xA1, 0xAF, 0x53, 0xA6, 0x10, + 0xC0, 0x03, 0x8E, 0x01, 0xAE, 0x10, 0xA6, 0x3A, 0xA7, 0x51, 0x8E, 0x01, 0xD0, 0x03, 0x8C, 0xA1, + 0xAF, 0x51, 0x84, 0x00, 0xA7, 0x50, 0x00, 0xA1, 0x00, 0x01, 0x80, 0x80, 0xE3, 0x45, 0xE9, 0x25, + 0xA7, 0x92, 0x00, 0x81, 0x00, 0x03, 0xE3, 0x06, 0xE9, 0x1E, 0xA6, 0xFA, 0x81, 0x25, 0x42, 0x93, + 0x0C, 0x73, 0x80, 0x69, 0x04, 0x90, 0x80, 0x05, 0x94, 0xD9, 0x88, 0x69, 0x02, 0x91, 0x80, 0x00, + 0x40, 0x94, 0x80, 0x11, 0xE5, 0x3A, 0xE9, 0x0D, 0x02, 0x91, 0x80, 0x00, 0x02, 0xF1, 0x80, 0x00, + 0x40, 0x94, 0x80, 0x11, 0x40, 0xF7, 0x80, 0x11, 0xE0, 0x8F, 0x88, 0x09, 0xE8, 0x02, 0xA5, 0x18, + 0x8C, 0xC1, 0xD5, 0xE2, 0x8C, 0xA1, 0xD5, 0xDB, 0xC4, 0x06, 0x44, 0x10, 0x01, 0xF4, 0xFE, 0x0C, + 0x40, 0x00, 0x10, 0x17, 0xFC, 0xC0, 0xFC, 0x4C, 0xB6, 0x3F, 0x3C, 0x1D, 0xFB, 0x42, 0x80, 0xE0, + 0x84, 0x1F, 0x3C, 0x0F, 0xFA, 0xCF, 0xA6, 0x0B, 0x81, 0x42, 0x5C, 0xF0, 0x00, 0x42, 0xE9, 0x04, + 0x44, 0x00, 0x00, 0x41, 0xAE, 0x0B, 0xA6, 0x08, 0x5C, 0xF0, 0x00, 0x42, 0xE9, 0x04, 0x44, 0x00, + 0x00, 0x41, 0xAE, 0x08, 0x2E, 0x20, 0x06, 0x12, 0x44, 0x00, 0x03, 0xE8, 0x5A, 0x28, 0x01, 0x08, + 0xA6, 0x8C, 0xA7, 0x8D, 0xFE, 0x84, 0x40, 0x91, 0x00, 0x13, 0xD5, 0x06, 0xA6, 0x8B, 0xA7, 0x88, + 0xFE, 0x84, 0x40, 0x91, 0x00, 0x13, 0x00, 0x25, 0x00, 0x00, 0xFF, 0x84, 0x97, 0xB1, 0xCA, 0x06, + 0x3C, 0x8D, 0xFA, 0xCF, 0x5A, 0x8F, 0xFF, 0x20, 0xD5, 0x1B, 0x84, 0x00, 0x3C, 0x1D, 0xFA, 0xCF, + 0x80, 0xA0, 0xB1, 0x04, 0xE0, 0xA2, 0xE8, 0x11, 0xA0, 0xF9, 0x38, 0x31, 0x95, 0x01, 0x38, 0x32, + 0x15, 0x09, 0xDB, 0x09, 0xA0, 0xFA, 0x38, 0x31, 0x95, 0x01, 0xE2, 0x03, 0x40, 0x12, 0xBC, 0x1B, + 0x40, 0x01, 0xBC, 0x1B, 0x8C, 0xA1, 0xD5, 0xEF, 0x3C, 0x1F, 0xFA, 0xCF, 0xD5, 0xE2, 0x84, 0x20, + 0x48, 0x00, 0x00, 0x92, 0x40, 0x04, 0x08, 0x08, 0xF0, 0x81, 0xF2, 0x01, 0xA0, 0x7D, 0xB0, 0x03, + 0x88, 0x22, 0x84, 0x44, 0x49, 0x00, 0x47, 0x62, 0x80, 0x07, 0xB4, 0x3F, 0xB0, 0x83, 0x49, 0xFF, + 0xFF, 0x5B, 0xE2, 0xC0, 0xE8, 0x0B, 0x84, 0x01, 0x3E, 0x00, 0x01, 0x84, 0x3C, 0x0D, 0xFB, 0x42, + 0x84, 0x23, 0xA6, 0x01, 0x40, 0x00, 0x04, 0x17, 0xD5, 0x64, 0xE3, 0x20, 0xE8, 0xE1, 0x44, 0x2F, + 0x80, 0x00, 0x84, 0x20, 0x40, 0x24, 0x08, 0x04, 0x00, 0x35, 0x00, 0x00, 0xE0, 0x23, 0xE8, 0x0A, + 0xA0, 0xF9, 0x94, 0x09, 0x88, 0x03, 0xA5, 0x40, 0x4C, 0x54, 0x40, 0x03, 0xAC, 0x80, 0x8C, 0x21, + 0xD5, 0xF4, 0x80, 0x07, 0xB4, 0x3F, 0x54, 0x24, 0x00, 0xFF, 0x49, 0xFF, 0xFE, 0x17, 0x04, 0x93, + 0x80, 0x05, 0xF1, 0x01, 0xB0, 0x03, 0x88, 0x29, 0x84, 0x44, 0x49, 0x00, 0x47, 0x2F, 0x00, 0x35, + 0x00, 0x00, 0x50, 0x04, 0x80, 0x03, 0x84, 0x20, 0xE0, 0x23, 0xE8, 0x2E, 0xA0, 0xB9, 0x38, 0x51, + 0x05, 0x01, 0x96, 0xAB, 0x4E, 0x24, 0x00, 0x26, 0x54, 0x52, 0xFF, 0xFF, 0x4C, 0x54, 0x00, 0x22, + 0xD9, 0x20, 0x00, 0x20, 0x7F, 0xFD, 0x00, 0x5F, 0x80, 0x0C, 0xE2, 0xA2, 0xE9, 0x03, 0x10, 0x2F, + 0x80, 0x0C, 0x00, 0x20, 0x7F, 0xFE, 0x00, 0x5F, 0x80, 0x0D, 0xE2, 0x45, 0xE9, 0x03, 0x10, 0x2F, + 0x80, 0x0D, 0x00, 0x20, 0x7F, 0xFF, 0x00, 0x5F, 0x80, 0x0E, 0xE2, 0xA2, 0xE9, 0x03, 0x10, 0x2F, + 0x80, 0x0E, 0xA6, 0x80, 0x00, 0x5F, 0x80, 0x0F, 0xE2, 0x45, 0xE9, 0x03, 0x10, 0x2F, 0x80, 0x0F, + 0x8C, 0x21, 0x8C, 0x04, 0xD5, 0xD2, 0x80, 0x07, 0xB4, 0x3F, 0xB0, 0x83, 0x49, 0xFF, 0xFE, 0xF4, + 0xE2, 0xC0, 0xE8, 0x0B, 0x84, 0x01, 0x3E, 0x00, 0x01, 0x84, 0x3C, 0x0D, 0xFB, 0x42, 0xA6, 0x01, + 0x3E, 0x00, 0x01, 0x85, 0x84, 0x21, 0xD5, 0x0F, 0x84, 0x00, 0xB0, 0x84, 0x00, 0x15, 0x00, 0x00, + 0xE0, 0x01, 0x4E, 0xF2, 0xFF, 0x76, 0xA0, 0x79, 0x38, 0x31, 0x01, 0x01, 0x38, 0x30, 0x81, 0x09, + 0x8C, 0x01, 0xD5, 0xF5, 0x2E, 0x00, 0x01, 0x85, 0xC0, 0x0D, 0x5A, 0x18, 0x01, 0x05, 0x3E, 0x10, + 0x01, 0x84, 0xD5, 0x08, 0x8E, 0x01, 0x96, 0x00, 0x3E, 0x00, 0x01, 0x85, 0xC8, 0x03, 0x3E, 0x00, + 0x01, 0x84, 0x2E, 0x00, 0x01, 0x84, 0x5A, 0x08, 0x01, 0x05, 0x84, 0x20, 0x10, 0x15, 0x00, 0x00, + 0xFC, 0xCC, 0xFC, 0x22, 0x84, 0x20, 0x80, 0xC0, 0xFA, 0x40, 0x80, 0x1F, 0x49, 0x00, 0x46, 0xC8, + 0x84, 0x20, 0x44, 0x32, 0xB3, 0xF8, 0x44, 0x50, 0x00, 0x64, 0x98, 0x0B, 0x38, 0x21, 0x84, 0x01, + 0xA4, 0x02, 0x8C, 0x32, 0x94, 0x01, 0x88, 0x06, 0x22, 0x40, 0x00, 0x00, 0xFE, 0xA4, 0x40, 0x21, + 0x14, 0x56, 0xAC, 0x80, 0x44, 0x42, 0xB3, 0xF8, 0x5A, 0x18, 0x90, 0xF1, 0x80, 0x04, 0x84, 0x60, + 0xA4, 0x43, 0xC1, 0x10, 0xA5, 0x45, 0xA4, 0x84, 0x5A, 0x18, 0x01, 0x07, 0x38, 0x13, 0x15, 0x11, + 0xFE, 0x54, 0x90, 0x27, 0xD5, 0x06, 0x38, 0x13, 0x15, 0x11, 0xFE, 0x54, 0x90, 0x27, 0xFE, 0x4A, + 0x96, 0x4B, 0xA5, 0xC6, 0xC7, 0x0E, 0x02, 0x50, 0x00, 0x08, 0xA4, 0x87, 0x38, 0x53, 0x15, 0x11, + 0xFE, 0xAC, 0x90, 0x47, 0x5A, 0x78, 0x01, 0x04, 0x88, 0x22, 0xD5, 0x02, 0x8A, 0x22, 0x96, 0x4B, + 0x38, 0x1F, 0x8D, 0x09, 0x8C, 0x61, 0x8C, 0x12, 0x5A, 0x38, 0x08, 0xDC, 0x84, 0x20, 0xFA, 0xA2, + 0x80, 0x04, 0x42, 0x00, 0x94, 0x73, 0xA4, 0x02, 0x38, 0x2F, 0x85, 0x01, 0x94, 0x01, 0x88, 0x06, + 0x8C, 0x21, 0xA4, 0xC0, 0x88, 0x43, 0xAC, 0x80, 0x5A, 0x18, 0x08, 0xF4, 0xFC, 0xA2, 0xC1, 0x0B, + 0x40, 0x20, 0x84, 0x09, 0x44, 0x30, 0x00, 0x64, 0x42, 0x20, 0x0C, 0x73, 0x40, 0x11, 0x04, 0x36, + 0x96, 0x0B, 0xDD, 0x9E, 0x80, 0x01, 0xDD, 0x9E, 0xFC, 0x40, 0x84, 0xE0, 0x81, 0x20, 0x44, 0xA2, + 0xB3, 0xF8, 0x40, 0x13, 0xA8, 0x00, 0x8C, 0xF2, 0xA5, 0x8A, 0xA6, 0x4A, 0x95, 0xB1, 0x88, 0xC9, + 0x22, 0x03, 0x00, 0x00, 0x49, 0xFF, 0xFF, 0xE5, 0xAC, 0x30, 0x5A, 0x78, 0x90, 0xF4, 0xFC, 0xC0, + 0x3A, 0x6F, 0xAA, 0xBC, 0x84, 0x00, 0xEF, 0xF4, 0x3E, 0x00, 0x05, 0xA0, 0x47, 0xC7, 0xFF, 0xFF, + 0x2E, 0x07, 0xEC, 0x41, 0x84, 0x60, 0x50, 0x1E, 0x0F, 0xFF, 0xB6, 0x1F, 0x3C, 0x4C, 0x02, 0xA7, + 0x3C, 0x2C, 0x02, 0x13, 0x3D, 0xEC, 0x02, 0x15, 0x3C, 0x8C, 0x02, 0x11, 0x3C, 0x6C, 0x02, 0x14, + 0x80, 0x03, 0xF1, 0x81, 0xB4, 0x3F, 0xE2, 0x01, 0xE8, 0x6E, 0x0A, 0x54, 0x00, 0x01, 0xD8, 0x68, + 0xA6, 0x71, 0xA7, 0xF0, 0xC1, 0x11, 0x40, 0x93, 0x90, 0x08, 0x04, 0xAF, 0x80, 0x01, 0x89, 0x21, + 0x89, 0x2A, 0x40, 0x94, 0x84, 0x08, 0x89, 0x24, 0x02, 0xF4, 0x80, 0x00, 0x40, 0xF7, 0x80, 0x11, + 0x5A, 0x10, 0x0F, 0x11, 0xD5, 0x03, 0x38, 0xF1, 0x01, 0x11, 0x40, 0x93, 0x90, 0x08, 0x89, 0x21, + 0x8D, 0x21, 0x40, 0x94, 0x84, 0x08, 0x89, 0x24, 0x02, 0xA4, 0x80, 0x00, 0x40, 0xA5, 0x00, 0x11, + 0xD5, 0x03, 0x38, 0xA1, 0x01, 0x11, 0xC7, 0x10, 0x50, 0x93, 0xFF, 0xFF, 0x40, 0x94, 0x90, 0x08, + 0x89, 0x21, 0x40, 0x94, 0x84, 0x08, 0x89, 0x24, 0x02, 0x94, 0x80, 0x00, 0x40, 0x94, 0x80, 0x11, + 0x5A, 0x70, 0x23, 0x0D, 0xD5, 0x03, 0x38, 0x91, 0x15, 0x11, 0x8C, 0xE1, 0x95, 0xFC, 0x88, 0xE1, + 0x95, 0xF9, 0x88, 0xE4, 0xA5, 0xF8, 0x97, 0xFB, 0xD5, 0x03, 0x38, 0x71, 0x15, 0x11, 0x38, 0x11, + 0x15, 0x01, 0x87, 0x8A, 0x40, 0x10, 0xF0, 0x37, 0x40, 0xF7, 0x84, 0x07, 0xE8, 0x0F, 0xE1, 0x41, + 0xE8, 0x0D, 0x40, 0xA2, 0x88, 0x08, 0x40, 0xFF, 0x28, 0x00, 0x00, 0xA7, 0x80, 0x01, 0x00, 0xF7, + 0x80, 0x00, 0x8B, 0x4F, 0x8D, 0x41, 0xE5, 0x43, 0xE9, 0x0D, 0xE1, 0x21, 0xE8, 0x11, 0xE0, 0xE1, + 0xE8, 0x0F, 0x95, 0xEA, 0x88, 0xFE, 0xA6, 0x7B, 0xA7, 0xFA, 0x8A, 0x27, 0x8C, 0x21, 0xE4, 0x23, + 0xE8, 0x07, 0x44, 0x1F, 0x80, 0x00, 0xFF, 0x4F, 0x12, 0x54, 0x7F, 0xFF, 0x84, 0x61, 0x8C, 0x01, + 0x8C, 0xC2, 0xD5, 0x91, 0x3E, 0x30, 0x05, 0xA0, 0x5A, 0x38, 0x01, 0x09, 0xEC, 0x0C, 0x44, 0x00, + 0x00, 0x59, 0x3A, 0x6F, 0xAA, 0x84, 0x48, 0x00, 0x0B, 0x55, 0xEC, 0x0C, 0x3A, 0x6F, 0xAA, 0x84, + 0xDD, 0x9E, 0x3A, 0x6F, 0x9E, 0xBC, 0x49, 0xFF, 0xDF, 0xBF, 0x44, 0x13, 0xF0, 0x10, 0x5A, 0x08, + 0x02, 0x06, 0x44, 0x0F, 0xFF, 0xAA, 0xAE, 0x08, 0xD5, 0x03, 0x84, 0x00, 0xAE, 0x08, 0x2E, 0x60, + 0x05, 0xFA, 0x5A, 0x68, 0x01, 0x16, 0x3C, 0x0D, 0xFB, 0x5C, 0x5A, 0x08, 0x07, 0x04, 0x49, 0x00, + 0x38, 0x3F, 0x3C, 0x0D, 0xFB, 0x4A, 0x44, 0x12, 0xCE, 0xC8, 0x3C, 0x2D, 0xFB, 0x4D, 0x44, 0x32, + 0xB6, 0x50, 0x49, 0xFF, 0xD6, 0x80, 0x5A, 0x08, 0x08, 0x05, 0x80, 0xC0, 0xD5, 0x02, 0x84, 0xC1, + 0x80, 0x06, 0x3A, 0x6F, 0x9E, 0x84, 0xDD, 0x9E, 0x3B, 0xFF, 0xFC, 0xBC, 0xEF, 0xFC, 0x49, 0x00, + 0x16, 0xD1, 0x49, 0x00, 0x0F, 0xA2, 0x3C, 0x0D, 0xFB, 0x4A, 0x84, 0x21, 0xAE, 0x41, 0x49, 0x00, + 0x19, 0x43, 0x44, 0x00, 0x00, 0xA0, 0x49, 0x00, 0x37, 0x8A, 0x44, 0x02, 0xB5, 0xF0, 0x3C, 0x1D, + 0xFB, 0x4A, 0x49, 0x00, 0x10, 0xA1, 0x49, 0xFF, 0xDF, 0x7F, 0x5A, 0x08, 0x02, 0x07, 0xEC, 0x04, + 0x3B, 0xFF, 0xFC, 0x84, 0x48, 0xFF, 0xF8, 0xEF, 0xEC, 0x04, 0x3B, 0xFF, 0xFC, 0x84, 0xDD, 0x9E, + 0x3B, 0xFF, 0xFC, 0xBC, 0x84, 0x04, 0xEF, 0xFC, 0x3E, 0x07, 0xEC, 0x00, 0x44, 0x00, 0x00, 0xA1, + 0x49, 0x00, 0x37, 0x6D, 0x3C, 0x0D, 0xFB, 0x4A, 0x44, 0x12, 0xB5, 0x29, 0x44, 0x22, 0xB6, 0x50, + 0x49, 0x00, 0x3C, 0xC4, 0x2E, 0x07, 0xEC, 0x29, 0x5A, 0x08, 0x01, 0x0A, 0x44, 0x02, 0xB4, 0xC2, + 0x44, 0x12, 0xB5, 0x52, 0x49, 0x00, 0x0C, 0xD9, 0x49, 0xFF, 0xE3, 0x2D, 0x3C, 0x1D, 0xFB, 0x64, + 0x84, 0x02, 0xAE, 0x08, 0x3C, 0x1D, 0xFB, 0x59, 0xAE, 0x08, 0x49, 0x00, 0x11, 0xE6, 0x2E, 0x07, + 0xEC, 0x29, 0x5A, 0x08, 0x01, 0x04, 0x49, 0xFF, 0xE3, 0x17, 0x49, 0x00, 0x19, 0x8F, 0x49, 0xFF, + 0xF8, 0xA5, 0xEC, 0x04, 0x84, 0x02, 0x3B, 0xFF, 0xFC, 0x84, 0x48, 0x00, 0x0A, 0xCB, 0x2E, 0x07, + 0xEC, 0x29, 0x3B, 0xFF, 0xFC, 0xBC, 0xEF, 0xF4, 0x5A, 0x08, 0x01, 0x07, 0x44, 0x02, 0xB4, 0xC2, + 0x84, 0x20, 0x49, 0x00, 0x0C, 0x44, 0x2E, 0x07, 0xEC, 0x66, 0x8E, 0x03, 0xE6, 0x02, 0xE8, 0x0D, + 0x2E, 0x07, 0xC7, 0x54, 0x5A, 0x08, 0x01, 0x0A, 0x49, 0xFF, 0xCA, 0xC1, 0x84, 0x02, 0x3C, 0x1D, + 0xFB, 0x4C, 0x49, 0x00, 0x0B, 0x40, 0xD5, 0x08, 0x49, 0xFF, 0xE3, 0x2A, 0xF0, 0x81, 0xF1, 0x01, + 0x84, 0x00, 0x49, 0x00, 0x0B, 0x38, 0x3C, 0x0D, 0xFB, 0x4A, 0xA6, 0x41, 0x5A, 0x18, 0x0C, 0x04, + 0x84, 0x23, 0xAE, 0x41, 0x44, 0x00, 0x00, 0xA3, 0x49, 0x00, 0x37, 0x11, 0x2E, 0x07, 0xC7, 0x55, + 0x5A, 0x08, 0x01, 0x0C, 0x3C, 0x0D, 0xFB, 0x4A, 0xA6, 0x00, 0x5A, 0x08, 0x01, 0x07, 0x2E, 0x07, + 0xEC, 0x66, 0x49, 0xFF, 0xE3, 0x5A, 0xD5, 0x07, 0x44, 0x02, 0x45, 0x10, 0x44, 0x12, 0x40, 0x00, + 0x49, 0x00, 0x0D, 0x53, 0xEC, 0x0C, 0x44, 0x02, 0xD3, 0x40, 0x44, 0x12, 0xD3, 0xE4, 0x3B, 0xFF, + 0xFC, 0x84, 0x48, 0x00, 0x2E, 0x73, 0x3A, 0x6F, 0xA0, 0xBC, 0x49, 0xFF, 0xDE, 0xED, 0x5A, 0x08, + 0x02, 0x1F, 0x49, 0xFF, 0xE4, 0x4B, 0xC8, 0x1B, 0x3C, 0x0D, 0xFB, 0x4A, 0xA6, 0x01, 0x5A, 0x08, + 0x03, 0x07, 0x2E, 0x07, 0xEC, 0x22, 0x5A, 0x08, 0x14, 0x13, 0xD5, 0x03, 0x5A, 0x08, 0x06, 0x10, + 0x84, 0xC0, 0x3E, 0x67, 0xEC, 0x22, 0x49, 0xFF, 0xF8, 0x63, 0x2E, 0x07, 0xEC, 0x37, 0x5A, 0x08, + 0x01, 0x04, 0x3E, 0x07, 0xEC, 0x11, 0x3E, 0x67, 0xEC, 0x72, 0xD5, 0x10, 0x49, 0xFF, 0xDE, 0xCC, + 0x5A, 0x08, 0x02, 0x0D, 0x49, 0xFF, 0xE4, 0x2A, 0xC0, 0x09, 0x3C, 0x0D, 0xFB, 0x4A, 0xA6, 0x01, + 0x5A, 0x08, 0x06, 0x05, 0x84, 0x01, 0x3E, 0x07, 0xEC, 0x72, 0x2E, 0x07, 0xEC, 0x22, 0xE6, 0x14, + 0xE8, 0x04, 0x8C, 0x01, 0x3E, 0x07, 0xEC, 0x22, 0x3C, 0x0C, 0x02, 0xA8, 0x49, 0xFF, 0xFE, 0x46, + 0x44, 0x02, 0xD3, 0x40, 0x44, 0x12, 0xCF, 0xE4, 0x44, 0x22, 0xD3, 0xE4, 0x44, 0x32, 0x8F, 0x70, + 0x44, 0x42, 0xD3, 0x34, 0x49, 0x00, 0x30, 0x8F, 0x2E, 0x07, 0xC7, 0x56, 0x5A, 0x08, 0x01, 0x09, + 0x44, 0x02, 0xD3, 0x40, 0x44, 0x12, 0xCF, 0x78, 0x49, 0x00, 0x34, 0xF3, 0xD5, 0x07, 0x3C, 0x0C, + 0x02, 0xA8, 0x3C, 0x1C, 0x02, 0xA7, 0x49, 0x00, 0x0C, 0xF0, 0x2E, 0x77, 0xEC, 0x11, 0x5A, 0x78, + 0x01, 0x16, 0x49, 0xFF, 0xDE, 0x91, 0x80, 0xC0, 0x5A, 0x08, 0x02, 0x11, 0x84, 0x00, 0x44, 0x12, + 0xD3, 0x40, 0x49, 0xFF, 0xF8, 0xCC, 0x80, 0x07, 0x44, 0x12, 0xD3, 0x40, 0x49, 0xFF, 0xF8, 0xC7, + 0x80, 0x06, 0x44, 0x12, 0xD3, 0x40, 0x49, 0xFF, 0xF8, 0xC2, 0x84, 0x01, 0x3E, 0x00, 0x06, 0x39, + 0x2E, 0x07, 0xEC, 0x5F, 0x5A, 0x08, 0x12, 0x0D, 0x3C, 0x03, 0xF6, 0x4F, 0x84, 0x21, 0x49, 0x00, + 0x37, 0x17, 0x5A, 0x08, 0x01, 0x06, 0x2E, 0x10, 0x06, 0x39, 0x49, 0x00, 0x36, 0x0E, 0x2E, 0x17, + 0xEC, 0x29, 0x5A, 0x18, 0x01, 0x06, 0x44, 0x02, 0xB4, 0xC2, 0x49, 0x00, 0x0B, 0x78, 0x2E, 0x07, + 0xEC, 0x5F, 0x5A, 0x08, 0x12, 0x10, 0x3C, 0x03, 0xF6, 0x4F, 0x84, 0x22, 0x49, 0x00, 0x37, 0x00, + 0x5A, 0x08, 0x01, 0x09, 0x84, 0x02, 0x2E, 0x10, 0x06, 0x39, 0x3A, 0x6F, 0xA0, 0x84, 0x48, 0x00, + 0x35, 0xF4, 0x3A, 0x6F, 0xA0, 0x84, 0xDD, 0x9E, 0x2E, 0x07, 0xC7, 0x53, 0x5A, 0x08, 0x01, 0x09, + 0x3C, 0x0D, 0xFB, 0x4A, 0xA6, 0x01, 0x5A, 0x08, 0x09, 0x04, 0x48, 0xFF, 0xE3, 0x7D, 0xDD, 0x9E, + 0x2E, 0x07, 0xEC, 0x5F, 0x3B, 0xFF, 0xFC, 0xBC, 0xEF, 0xFC, 0x5A, 0x08, 0x12, 0x0E, 0x3C, 0x03, + 0xF6, 0x4F, 0x84, 0x2F, 0x49, 0x00, 0x36, 0xDC, 0x5A, 0x08, 0x01, 0x07, 0x84, 0x0F, 0x2E, 0x10, + 0x06, 0x39, 0x49, 0x00, 0x35, 0xD2, 0x3C, 0x0D, 0xFB, 0x59, 0x84, 0x21, 0xEC, 0x04, 0xAE, 0x40, + 0x3B, 0xFF, 0xFC, 0x84, 0x84, 0x00, 0x3C, 0x0F, 0xFB, 0x85, 0x48, 0xFF, 0xFF, 0xD7, 0xDD, 0x9E, + 0x3A, 0x6F, 0x9A, 0xBC, 0xEF, 0xFC, 0x2E, 0x07, 0xEC, 0x45, 0xC8, 0x3A, 0x2E, 0x00, 0x06, 0x12, + 0xC8, 0x20, 0x2E, 0x07, 0xEC, 0x78, 0xC8, 0x1D, 0x2E, 0x07, 0xEC, 0x7C, 0xC8, 0x1A, 0x2E, 0x07, + 0xEC, 0x11, 0x5A, 0x08, 0x01, 0x09, 0xFA, 0x02, 0x49, 0x00, 0x09, 0x9C, 0x84, 0x01, 0x3E, 0x07, + 0xEC, 0x7C, 0xD5, 0x0F, 0x49, 0xFF, 0xF6, 0xF8, 0x5A, 0x00, 0x02, 0xF7, 0x44, 0x02, 0xD3, 0xE4, + 0x3C, 0x13, 0xE3, 0xD2, 0x44, 0x22, 0xB5, 0x24, 0x49, 0xFF, 0xE8, 0xD1, 0x5A, 0x00, 0x02, 0xED, + 0x3C, 0x0D, 0xFB, 0x4A, 0xA6, 0x41, 0x2E, 0x07, 0xEC, 0x7C, 0x5A, 0x10, 0x06, 0x04, 0x5A, 0x18, + 0x0A, 0x12, 0x5A, 0x00, 0x01, 0x09, 0x2E, 0x00, 0x06, 0x35, 0x5A, 0x00, 0x01, 0x05, 0x2E, 0x07, + 0xEC, 0x6C, 0xC0, 0x06, 0x84, 0x01, 0x3E, 0x07, 0xEC, 0x31, 0x3E, 0x07, 0xEC, 0x2C, 0x84, 0x01, + 0xD5, 0x43, 0x5A, 0x00, 0x01, 0x0A, 0x2E, 0x00, 0x06, 0x35, 0x5A, 0x00, 0x01, 0x06, 0x2E, 0x07, + 0xEC, 0x59, 0x5A, 0x08, 0x01, 0xF6, 0x44, 0x03, 0xF0, 0x4A, 0x44, 0x10, 0x00, 0x55, 0xAE, 0x40, + 0x3C, 0x1D, 0xFB, 0x64, 0xA6, 0x08, 0xC0, 0xFF, 0x2E, 0x07, 0xEC, 0x7C, 0x5A, 0x00, 0x01, 0x06, + 0x2E, 0x00, 0x06, 0x35, 0x5A, 0x08, 0x01, 0x05, 0x2E, 0x07, 0xEC, 0x66, 0xC0, 0x05, 0x2E, 0x07, + 0xEC, 0x11, 0x5A, 0x08, 0x01, 0x07, 0x44, 0x02, 0x3F, 0xF0, 0x44, 0x1F, 0xFD, 0xFD, 0xAC, 0x40, + 0x84, 0x00, 0x3E, 0x07, 0xEC, 0x11, 0x3E, 0x07, 0xEC, 0x7C, 0x3E, 0x00, 0x06, 0x35, 0x84, 0x01, + 0x3E, 0x00, 0x06, 0x36, 0x2E, 0x07, 0xEC, 0x5F, 0x5A, 0x08, 0x12, 0x0E, 0x3C, 0x03, 0xF6, 0x4F, + 0x84, 0x25, 0x49, 0x00, 0x36, 0x4D, 0x5A, 0x08, 0x01, 0x07, 0x84, 0x05, 0x2E, 0x10, 0x06, 0x39, + 0x49, 0x00, 0x35, 0x43, 0x84, 0x02, 0xEC, 0x04, 0x3A, 0x6F, 0x9A, 0x84, 0xDD, 0x9E, 0x2E, 0x07, + 0xC7, 0x54, 0x3B, 0xFF, 0xFC, 0xBC, 0xEF, 0xFC, 0x5A, 0x08, 0x01, 0x0A, 0x44, 0x02, 0x93, 0x70, + 0x50, 0x10, 0x00, 0x28, 0x50, 0x20, 0x00, 0x58, 0x49, 0xFF, 0xCB, 0x47, 0x44, 0x02, 0x93, 0x70, + 0x44, 0x12, 0xD5, 0xF0, 0x49, 0xFF, 0xD0, 0xA3, 0x3C, 0x0D, 0xFB, 0x4A, 0x44, 0x12, 0xCE, 0xC8, + 0x2E, 0x27, 0xEC, 0x78, 0x2E, 0x37, 0xEC, 0x47, 0x2E, 0x47, 0xEC, 0x24, 0x49, 0x00, 0x11, 0x2A, + 0x2E, 0x07, 0xC7, 0x53, 0x5A, 0x08, 0x01, 0x10, 0x2E, 0x00, 0x06, 0x2C, 0x5A, 0x08, 0x01, 0x0C, + 0x44, 0x02, 0xCE, 0xC8, 0x49, 0xFF, 0xED, 0xDA, 0xC8, 0x06, 0xEC, 0x04, 0x3B, 0xFF, 0xFC, 0x84, + 0x48, 0xFF, 0xEE, 0x13, 0xEC, 0x04, 0x3B, 0xFF, 0xFC, 0x84, 0xDD, 0x9E, 0x3C, 0x0D, 0xFB, 0x4A, + 0x3A, 0x6F, 0x98, 0xBC, 0xA6, 0x01, 0x5A, 0x00, 0x03, 0x06, 0x49, 0xFF, 0xB5, 0x4C, 0xE6, 0x03, + 0xE9, 0x07, 0x2E, 0x07, 0xEC, 0x5F, 0x5A, 0x00, 0x05, 0x04, 0x5A, 0x08, 0x12, 0x0A, 0x84, 0x00, + 0x3E, 0x07, 0xED, 0xA0, 0x3E, 0x07, 0xED, 0xA1, 0x3E, 0x07, 0xED, 0xA2, 0xD5, 0x3F, 0x3C, 0x0D, + 0xFB, 0x6F, 0x5A, 0x08, 0x01, 0x09, 0x84, 0x00, 0x3C, 0x0F, 0xFB, 0x6F, 0x44, 0x02, 0xB6, 0x54, + 0x49, 0xFF, 0xB5, 0x1C, 0x2E, 0x00, 0x05, 0xF7, 0x5A, 0x08, 0x01, 0x06, 0x2E, 0x00, 0x05, 0xF6, + 0x5A, 0x00, 0x01, 0x0A, 0x44, 0x02, 0xD4, 0x18, 0x44, 0x12, 0xB6, 0x60, 0x49, 0xFF, 0xB8, 0x1B, + 0x3E, 0x07, 0xED, 0xA2, 0x49, 0xFF, 0xB5, 0x22, 0x80, 0xC0, 0x5A, 0x08, 0x01, 0x16, 0x49, 0xFF, + 0xB5, 0x1A, 0x5A, 0x08, 0x03, 0x09, 0x80, 0x06, 0x49, 0xFF, 0xB5, 0x12, 0x44, 0x00, 0x00, 0x61, + 0x49, 0x00, 0x08, 0xB0, 0x49, 0xFF, 0xB5, 0x0F, 0x5A, 0x08, 0x04, 0x11, 0x84, 0x01, 0x3A, 0x6F, + 0x98, 0x84, 0x48, 0xFF, 0xB5, 0x05, 0x49, 0xFF, 0xB5, 0x06, 0x5A, 0x08, 0x03, 0x08, 0x84, 0x00, + 0x3C, 0x0E, 0x01, 0x87, 0x84, 0x01, 0x3E, 0x07, 0xEC, 0x2C, 0x3A, 0x6F, 0x98, 0x84, 0xDD, 0x9E, + 0x3A, 0x6F, 0x9E, 0xBC, 0x84, 0x0C, 0x49, 0x00, 0x35, 0x14, 0x44, 0x03, 0xF0, 0x4A, 0x44, 0x10, + 0x00, 0x55, 0xAE, 0x40, 0x49, 0x00, 0x0A, 0x48, 0x3C, 0x0D, 0xFB, 0x4A, 0xA6, 0x41, 0x5A, 0x18, + 0x0C, 0x0B, 0x2E, 0x07, 0xEC, 0x20, 0x5A, 0x08, 0x01, 0x17, 0x3E, 0x00, 0x06, 0x36, 0x84, 0x02, + 0x48, 0x00, 0x00, 0x8A, 0x2E, 0x10, 0x06, 0x2C, 0xC9, 0xF5, 0x44, 0x12, 0xB5, 0x30, 0x44, 0x22, + 0xCE, 0xC8, 0x49, 0xFF, 0xD6, 0xBB, 0x2E, 0x07, 0xEC, 0x7A, 0x5A, 0x08, 0x01, 0xEC, 0x84, 0x01, + 0x48, 0x00, 0x00, 0x7A, 0x2E, 0x07, 0xEC, 0x0F, 0x5A, 0x08, 0x01, 0x06, 0x84, 0x00, 0x3E, 0x07, + 0xEC, 0x0F, 0xD5, 0x04, 0x49, 0xFF, 0xC3, 0x6C, 0xC0, 0xFE, 0x2E, 0x07, 0xEC, 0x5F, 0x5A, 0x08, + 0x19, 0x04, 0x49, 0x00, 0x34, 0xA5, 0x2E, 0x07, 0xEC, 0x7E, 0xC8, 0x08, 0x3C, 0x1D, 0xFB, 0x4A, + 0x2E, 0x07, 0xEC, 0x66, 0xA6, 0x49, 0x49, 0x00, 0x0B, 0x3F, 0x2E, 0x07, 0xEC, 0x71, 0x5A, 0x08, + 0x01, 0x0A, 0x44, 0x02, 0xB5, 0x29, 0x3C, 0x1D, 0xFB, 0x4D, 0x44, 0x22, 0xB6, 0x50, 0x49, 0x00, + 0x33, 0x78, 0x3C, 0x0D, 0xFB, 0x6D, 0x5A, 0x08, 0x01, 0x31, 0x84, 0x00, 0x3C, 0x0F, 0xFB, 0x6D, + 0x2E, 0x07, 0xEC, 0x6D, 0x5A, 0x08, 0x55, 0x11, 0x44, 0x02, 0xB5, 0xF0, 0x3C, 0x1D, 0xFB, 0x4A, + 0x44, 0x22, 0xB4, 0xE1, 0x3C, 0x3D, 0xFB, 0x4D, 0x44, 0x42, 0xB6, 0x50, 0x49, 0x00, 0x37, 0xD2, + 0x3E, 0x07, 0xEC, 0x5F, 0xD5, 0x05, 0x44, 0x00, 0x00, 0x55, 0x3E, 0x07, 0xEC, 0x6D, 0x2E, 0x07, + 0xEC, 0x5F, 0x49, 0x00, 0x35, 0x08, 0x96, 0x00, 0x3E, 0x07, 0xEC, 0x17, 0x5A, 0x00, 0x03, 0x2C, + 0x5A, 0x08, 0x02, 0x0C, 0x44, 0x13, 0xF0, 0x4A, 0x44, 0x20, 0x00, 0x55, 0xAE, 0x88, 0x3C, 0x2D, + 0xFB, 0x64, 0xA6, 0x50, 0xC1, 0xFF, 0xD5, 0x1F, 0x2E, 0x07, 0xEC, 0x5F, 0x5A, 0x08, 0x04, 0x04, + 0x49, 0xFF, 0xC9, 0x67, 0x49, 0x00, 0x0E, 0xB5, 0x2E, 0x07, 0xEC, 0x66, 0x5A, 0x08, 0x03, 0x07, + 0x2E, 0x07, 0xC7, 0xE6, 0xC8, 0x03, 0x49, 0x00, 0x0A, 0x34, 0x2E, 0x67, 0xEC, 0x6E, 0x5A, 0x68, + 0x01, 0x90, 0x84, 0x00, 0x3E, 0x07, 0xEC, 0x6E, 0x49, 0xFF, 0xFF, 0x0A, 0x3C, 0x0D, 0xFB, 0x59, + 0xAF, 0x80, 0xFA, 0x03, 0x3A, 0x6F, 0x9E, 0x84, 0xDD, 0x9E, 0x2E, 0x07, 0xC7, 0x5C, 0x5A, 0x00, + 0x01, 0x04, 0x48, 0x00, 0x00, 0x89, 0x3A, 0x6F, 0xA8, 0xBC, 0x3C, 0x0D, 0xFB, 0x4D, 0x49, 0x00, + 0x18, 0x53, 0x44, 0x02, 0xD5, 0xF0, 0x44, 0x12, 0xD0, 0xF8, 0x49, 0x00, 0x27, 0xC1, 0x44, 0x02, + 0xD5, 0xF0, 0x44, 0x12, 0xD0, 0xF8, 0x49, 0x00, 0x28, 0x7A, 0x44, 0x02, 0xD5, 0xF0, 0x44, 0x12, + 0xD0, 0xF8, 0x3C, 0x2C, 0x02, 0xA7, 0x49, 0x00, 0x1B, 0x98, 0x44, 0x12, 0xD0, 0xF8, 0x3C, 0x2C, + 0x02, 0xA7, 0x44, 0x02, 0xD5, 0xF0, 0x49, 0x00, 0x22, 0x79, 0x44, 0x02, 0xD5, 0xF0, 0x49, 0x00, + 0x29, 0xD5, 0x44, 0x02, 0xD5, 0xF0, 0x49, 0x00, 0x2A, 0x5E, 0x84, 0xC0, 0x84, 0xAA, 0x2E, 0x47, + 0xEC, 0x6B, 0x44, 0x02, 0xD5, 0xF0, 0x80, 0xE5, 0x81, 0x26, 0x81, 0x45, 0xB4, 0x20, 0xC1, 0x4B, + 0x5A, 0x10, 0x03, 0x4A, 0x00, 0x10, 0x00, 0x5C, 0xC9, 0x0F, 0x00, 0x10, 0x00, 0x5B, 0x5A, 0x18, + 0x01, 0x0C, 0x00, 0x20, 0x00, 0xCA, 0xCA, 0x08, 0x00, 0x20, 0x00, 0xD0, 0xCA, 0x05, 0x10, 0xA0, + 0x00, 0x5A, 0x10, 0x10, 0x00, 0x5C, 0x00, 0x30, 0x00, 0x5A, 0xC3, 0x24, 0x22, 0x20, 0x00, 0x32, + 0x22, 0x10, 0x00, 0x04, 0x52, 0x81, 0x80, 0x0A, 0xFE, 0x9C, 0x42, 0x24, 0x04, 0x73, 0x22, 0x10, + 0x00, 0x33, 0x22, 0xF0, 0x00, 0x05, 0xFE, 0x5C, 0x42, 0x14, 0x3C, 0x73, 0x40, 0x21, 0x1C, 0x56, + 0x40, 0x10, 0x9C, 0x36, 0x96, 0x93, 0x96, 0x4B, 0x8E, 0x61, 0xAC, 0x84, 0xAC, 0x45, 0x10, 0x30, + 0x00, 0x5A, 0x4E, 0x24, 0x00, 0x04, 0x12, 0x90, 0x00, 0x04, 0x4E, 0x14, 0x00, 0x04, 0x12, 0x90, + 0x00, 0x05, 0x04, 0x10, 0x00, 0x18, 0x5A, 0x18, 0x01, 0x0C, 0x04, 0x10, 0x00, 0x28, 0x5A, 0x18, + 0x01, 0x08, 0x00, 0x10, 0x00, 0xCA, 0xC9, 0x04, 0x00, 0x10, 0x00, 0xD0, 0xC1, 0x04, 0x8C, 0x81, + 0x97, 0x20, 0xB6, 0xC0, 0x8E, 0xA1, 0x50, 0x00, 0x00, 0xE0, 0xCD, 0xB1, 0x3E, 0x47, 0xEC, 0x6B, + 0x3A, 0x6F, 0xA8, 0x84, 0xDD, 0x9E, 0x3A, 0x6F, 0xAA, 0xBC, 0xEF, 0xFC, 0x3C, 0x0C, 0x02, 0xA7, + 0x49, 0xFF, 0xFB, 0x01, 0x44, 0x02, 0xD3, 0x40, 0x44, 0x12, 0x8F, 0x70, 0x49, 0x00, 0x2E, 0x97, + 0x44, 0x02, 0xD3, 0x40, 0x44, 0x12, 0xD0, 0x78, 0x44, 0x22, 0x8F, 0x70, 0x84, 0x60, 0x84, 0x85, + 0x49, 0x00, 0x2B, 0x46, 0x2E, 0x07, 0xEC, 0x29, 0x5A, 0x08, 0x01, 0x07, 0x44, 0x02, 0xB4, 0xC2, + 0x84, 0x22, 0x49, 0x00, 0x08, 0xCC, 0x2E, 0x07, 0xC7, 0x57, 0x5A, 0x08, 0x01, 0x0C, 0x44, 0x02, + 0xCF, 0xF0, 0x44, 0x12, 0xD3, 0x34, 0x44, 0x22, 0xB5, 0x30, 0x2E, 0x37, 0xEC, 0x40, 0x49, 0x00, + 0x2A, 0x8D, 0x2E, 0x07, 0xC7, 0x54, 0x5A, 0x08, 0x01, 0x06, 0x44, 0x02, 0xD3, 0x34, 0x49, 0xFF, + 0xC8, 0xE7, 0x2E, 0x07, 0xC7, 0x5A, 0x5A, 0x08, 0x01, 0x0A, 0x44, 0x02, 0xD3, 0x40, 0x44, 0x12, + 0xCE, 0xC8, 0x44, 0x22, 0xD0, 0xF8, 0x49, 0xFF, 0xEB, 0x3F, 0x2E, 0x07, 0xEC, 0x66, 0x2E, 0x10, + 0x05, 0xFB, 0x2E, 0x27, 0xEC, 0x47, 0x44, 0x32, 0xD3, 0x34, 0x49, 0x00, 0x0F, 0xB6, 0x2E, 0x07, + 0xC7, 0x53, 0x5A, 0x08, 0x01, 0x0F, 0x2E, 0x00, 0x06, 0x2C, 0x5A, 0x08, 0x01, 0x0B, 0x44, 0x02, + 0xCE, 0xC8, 0x49, 0xFF, 0xEB, 0xEB, 0xC8, 0x05, 0x44, 0x02, 0xD3, 0x34, 0x49, 0xFF, 0xEC, 0x38, + 0x2E, 0x07, 0xEC, 0x5F, 0x5A, 0x08, 0x12, 0x0E, 0x3C, 0x03, 0xF6, 0x4F, 0x84, 0x23, 0x49, 0x00, + 0x34, 0x17, 0x5A, 0x08, 0x01, 0x07, 0x84, 0x03, 0x2E, 0x10, 0x06, 0x39, 0x49, 0x00, 0x33, 0x0D, + 0x2E, 0x07, 0xC7, 0x5A, 0x5A, 0x08, 0x01, 0x0D, 0x2E, 0x00, 0x06, 0x10, 0x5A, 0x08, 0x01, 0x09, + 0x2E, 0x07, 0xEC, 0x5E, 0xC0, 0x05, 0x3C, 0x0C, 0x02, 0xA7, 0x49, 0xFF, 0xEB, 0xB5, 0x2E, 0x07, + 0xC7, 0x5C, 0x5A, 0x08, 0x01, 0x0A, 0x3C, 0x0C, 0x02, 0xA7, 0x44, 0x12, 0xD0, 0xF8, 0x3C, 0x20, + 0x05, 0x3E, 0x49, 0x00, 0x17, 0xFF, 0x84, 0x00, 0x44, 0x22, 0x91, 0x40, 0x3E, 0x07, 0xEC, 0x5E, + 0x44, 0x12, 0xCE, 0xC8, 0x44, 0x02, 0xD0, 0x78, 0x50, 0x31, 0x00, 0x14, 0x49, 0xFF, 0xF3, 0x8A, + 0x2E, 0x07, 0xEC, 0x5E, 0xC8, 0x07, 0x44, 0x02, 0xCE, 0xC8, 0x44, 0x12, 0xD3, 0x40, 0x49, 0xFF, + 0xF3, 0xC8, 0x2E, 0x07, 0xEC, 0x5E, 0x4E, 0x02, 0x00, 0x74, 0x2E, 0x07, 0xEC, 0x5F, 0x5A, 0x08, + 0x12, 0x0E, 0x3C, 0x03, 0xF6, 0x4F, 0x84, 0x24, 0x49, 0x00, 0x33, 0xD2, 0x5A, 0x08, 0x01, 0x07, + 0x84, 0x04, 0x2E, 0x10, 0x06, 0x39, 0x49, 0x00, 0x32, 0xC8, 0x2E, 0x07, 0xC7, 0x54, 0x5A, 0x00, + 0x01, 0x06, 0x2E, 0x07, 0xC7, 0x5A, 0x5A, 0x08, 0x01, 0x06, 0x44, 0x02, 0x91, 0x0C, 0x49, 0xFF, + 0xCA, 0x7F, 0x3C, 0x0C, 0x02, 0xA7, 0x44, 0x12, 0xD0, 0xF8, 0x3C, 0x20, 0x05, 0x3E, 0x44, 0x32, + 0xB4, 0xF9, 0x84, 0x81, 0x49, 0xFF, 0xAA, 0xE6, 0x49, 0xFF, 0xFA, 0xB4, 0x2E, 0x07, 0xC7, 0x59, + 0x5A, 0x08, 0x01, 0x1D, 0x3C, 0x0D, 0xFB, 0x4D, 0xA4, 0x00, 0x92, 0x0D, 0x96, 0x06, 0x5A, 0x00, + 0x01, 0x08, 0x3C, 0x0D, 0xFB, 0x54, 0xA6, 0x00, 0x96, 0x06, 0x5A, 0x08, 0x01, 0x10, 0x2E, 0x00, + 0x06, 0x0A, 0xC8, 0x0C, 0x44, 0x02, 0xD0, 0xF8, 0x44, 0x12, 0xD3, 0x40, 0x44, 0x22, 0xB4, 0xF9, + 0x49, 0xFF, 0xF9, 0x2B, 0x3E, 0x00, 0x06, 0x12, 0xD5, 0x06, 0x84, 0x00, 0x3E, 0x00, 0x06, 0x12, + 0x49, 0xFF, 0xF7, 0xB3, 0x2E, 0x00, 0x06, 0x12, 0x5A, 0x08, 0x01, 0x0D, 0x2E, 0x00, 0x06, 0x0D, + 0xC8, 0x09, 0x2E, 0x07, 0xEC, 0x60, 0xE6, 0x02, 0xE8, 0x08, 0x8C, 0x01, 0x3E, 0x07, 0xEC, 0x60, + 0xD5, 0x04, 0x84, 0x00, 0x3E, 0x07, 0xEC, 0x60, 0x2E, 0x00, 0x06, 0x2D, 0xC8, 0x0D, 0x3C, 0x1D, + 0xFB, 0x4D, 0xA4, 0x08, 0x92, 0x06, 0x96, 0x06, 0x5A, 0x00, 0x01, 0x07, 0xA4, 0x08, 0x92, 0x01, + 0x96, 0x06, 0x5A, 0x08, 0x01, 0x13, 0x84, 0x00, 0x3E, 0x07, 0xEC, 0x60, 0xD5, 0x0E, 0x2E, 0x00, + 0x06, 0x12, 0x5A, 0x08, 0x01, 0x06, 0x49, 0xFF, 0xF7, 0x79, 0x3E, 0x00, 0x06, 0x12, 0x84, 0x00, + 0x3E, 0x07, 0xEC, 0x41, 0x3E, 0x07, 0xEC, 0x24, 0x2E, 0x07, 0xEC, 0x29, 0x5A, 0x08, 0x01, 0x07, + 0x44, 0x02, 0xB4, 0xC2, 0x84, 0x23, 0x49, 0x00, 0x07, 0xC2, 0x2E, 0x07, 0xC7, 0x5B, 0x5A, 0x08, + 0x01, 0x37, 0x3C, 0x0D, 0xFB, 0x4D, 0x3C, 0x1D, 0xFB, 0x54, 0xA4, 0x00, 0x92, 0x0C, 0x96, 0x06, + 0x5A, 0x00, 0x01, 0x07, 0xA6, 0x08, 0x92, 0x01, 0x96, 0x06, 0x5A, 0x08, 0x01, 0x29, 0xA6, 0x08, + 0x92, 0x03, 0x96, 0x06, 0xC8, 0x24, 0x2E, 0x00, 0x06, 0x2D, 0x3C, 0x1D, 0xFB, 0x4A, 0x49, 0x00, + 0x0F, 0xCE, 0x3C, 0x0D, 0xFB, 0x4A, 0xA6, 0x01, 0x5A, 0x00, 0x03, 0x04, 0x5A, 0x08, 0x06, 0x14, + 0x2E, 0x07, 0xEC, 0x4C, 0xC0, 0x10, 0x44, 0x02, 0xD0, 0x78, 0x3C, 0x1C, 0x02, 0xA7, 0x44, 0x22, + 0xD0, 0xF8, 0x44, 0x32, 0xB4, 0xF9, 0x3C, 0x40, 0x05, 0x3E, 0x49, 0x00, 0x0F, 0xD2, 0x3E, 0x00, + 0x06, 0x11, 0xD5, 0x05, 0x49, 0x00, 0x0F, 0x8C, 0x3E, 0x00, 0x06, 0x11, 0x2E, 0x17, 0xEC, 0x41, + 0xC9, 0x04, 0x3E, 0x17, 0xEC, 0x78, 0xD5, 0x0B, 0x44, 0x02, 0xD0, 0xF8, 0x44, 0x22, 0xD4, 0x24, + 0x44, 0x32, 0xB5, 0x30, 0x3C, 0x4C, 0x02, 0xA7, 0x49, 0xFF, 0xC0, 0x82, 0x2E, 0x17, 0xEC, 0x78, + 0xC1, 0x4C, 0x2E, 0x37, 0xC6, 0xEA, 0x2E, 0x47, 0xC6, 0xEB, 0x92, 0x61, 0x92, 0x81, 0x44, 0x02, + 0xD4, 0x24, 0x84, 0x40, 0xE2, 0x41, 0xE8, 0x0B, 0xA5, 0x40, 0x8C, 0x41, 0x88, 0xA3, 0xAD, 0x40, + 0xA5, 0x41, 0x8C, 0x08, 0x88, 0xA4, 0x12, 0x50, 0x7F, 0xFD, 0xD5, 0xF5, 0x2E, 0x07, 0xC7, 0x5D, + 0x5A, 0x08, 0x01, 0x09, 0x2E, 0x00, 0x07, 0x74, 0xC8, 0x05, 0x44, 0x02, 0xD4, 0x24, 0x49, 0xFF, + 0xBF, 0x29, 0x84, 0x00, 0x3C, 0x0E, 0x01, 0x87, 0x3C, 0x0E, 0x01, 0x88, 0x3E, 0x07, 0xEC, 0x6C, + 0x3C, 0x0D, 0xFB, 0x4A, 0xA6, 0x01, 0x5A, 0x08, 0x03, 0x17, 0x2E, 0x07, 0xEC, 0x75, 0x5A, 0x08, + 0x03, 0x0F, 0x49, 0xFF, 0xD3, 0xF7, 0xC8, 0x05, 0x2E, 0x07, 0xEC, 0x58, 0x5A, 0x08, 0x01, 0x08, + 0x84, 0x03, 0x3E, 0x07, 0xEC, 0x75, 0xD5, 0x54, 0x5A, 0x08, 0x03, 0x53, 0x84, 0x00, 0x3E, 0x07, + 0xEC, 0x75, 0xD5, 0x4E, 0x5A, 0x08, 0x09, 0x4D, 0x2E, 0x07, 0xEC, 0x75, 0x5A, 0x08, 0x04, 0xF6, + 0x84, 0x01, 0x3E, 0x07, 0xEC, 0x75, 0xD5, 0x44, 0x2E, 0x00, 0x06, 0x12, 0xC8, 0x41, 0x2E, 0x10, + 0x06, 0x09, 0x3E, 0x07, 0xEC, 0x41, 0x3E, 0x07, 0xEC, 0x78, 0x3E, 0x00, 0x06, 0x0B, 0x3C, 0x0E, + 0x01, 0x8A, 0x5A, 0x10, 0x01, 0x09, 0x3C, 0x0C, 0x01, 0x87, 0x44, 0x20, 0xEA, 0x60, 0xE2, 0x40, + 0xE9, 0x04, 0x8C, 0x01, 0x3C, 0x0E, 0x01, 0x87, 0x3C, 0x0C, 0x01, 0x88, 0x44, 0x20, 0xEA, 0x60, + 0xE2, 0x40, 0xE9, 0x0E, 0x3C, 0x20, 0x03, 0x03, 0x3C, 0x33, 0xF6, 0x63, 0xE2, 0x62, 0xE8, 0x02, + 0xC1, 0x05, 0x8C, 0x01, 0x3C, 0x0E, 0x01, 0x88, 0xD5, 0x03, 0x3C, 0x1E, 0x01, 0x88, 0x2E, 0x07, + 0xEC, 0x16, 0x5A, 0x08, 0x01, 0x08, 0x3E, 0x07, 0xEC, 0x31, 0x84, 0x00, 0x3C, 0x0E, 0x01, 0x87, + 0xD5, 0x04, 0x84, 0x00, 0x3E, 0x07, 0xEC, 0x31, 0x2E, 0x67, 0xC7, 0x54, 0x5A, 0x68, 0x01, 0x09, + 0x84, 0x00, 0x3E, 0x00, 0x06, 0x2E, 0x49, 0xFF, 0xC8, 0xAD, 0x3E, 0x60, 0x06, 0x2E, 0x49, 0xFF, + 0xFB, 0xB1, 0x5A, 0x08, 0x02, 0x04, 0x48, 0x00, 0x01, 0x31, 0x2E, 0x00, 0x06, 0x12, 0x5A, 0x08, + 0x01, 0x07, 0x84, 0x00, 0x3C, 0x0E, 0x01, 0x87, 0x3C, 0x0E, 0x01, 0x88, 0x49, 0xFF, 0xFC, 0x29, + 0x44, 0x02, 0xD4, 0x24, 0x2E, 0x17, 0xEC, 0x78, 0x44, 0x22, 0xD5, 0xF0, 0x44, 0x32, 0xD0, 0xF8, + 0x49, 0xFF, 0xAC, 0x22, 0x2E, 0x07, 0xEC, 0x5F, 0x5A, 0x08, 0x12, 0x0E, 0x3C, 0x03, 0xF6, 0x4F, + 0x84, 0x26, 0x49, 0x00, 0x32, 0x55, 0x5A, 0x08, 0x01, 0x07, 0x84, 0x06, 0x2E, 0x10, 0x06, 0x39, + 0x49, 0x00, 0x31, 0x4B, 0x2E, 0x07, 0xEC, 0x29, 0x5A, 0x08, 0x01, 0x07, 0x44, 0x02, 0xB4, 0xC2, + 0x84, 0x24, 0x49, 0x00, 0x06, 0xB4, 0x2E, 0x07, 0xC7, 0x63, 0x5A, 0x00, 0x01, 0x08, 0x2E, 0x27, + 0xC6, 0xC1, 0x44, 0x02, 0xD5, 0xF0, 0x84, 0x20, 0xD5, 0x13, 0x44, 0x02, 0xD5, 0xF0, 0x44, 0x12, + 0xD0, 0xF8, 0x3C, 0x2C, 0x02, 0xA7, 0x49, 0x00, 0x37, 0x9B, 0xD5, 0x0C, 0xB4, 0x60, 0xC3, 0x05, + 0xA4, 0xC2, 0xAC, 0xC6, 0xA4, 0xC3, 0xAC, 0xC7, 0x8C, 0x21, 0x50, 0x00, 0x00, 0xE0, 0xE2, 0x22, + 0xE9, 0xF6, 0x44, 0x02, 0xD5, 0xF0, 0x2E, 0x17, 0xCA, 0x89, 0x49, 0xFF, 0xAA, 0xAE, 0x44, 0x02, + 0xD5, 0xF0, 0x49, 0xFF, 0xBD, 0x82, 0x2E, 0x07, 0xEC, 0x5F, 0x5A, 0x08, 0x12, 0x0E, 0x3C, 0x03, + 0xF6, 0x4F, 0x84, 0x27, 0x49, 0x00, 0x32, 0x14, 0x5A, 0x08, 0x01, 0x07, 0x84, 0x07, 0x2E, 0x10, + 0x06, 0x39, 0x49, 0x00, 0x31, 0x0A, 0x3C, 0x0D, 0xFB, 0x4D, 0xA4, 0x00, 0x92, 0x06, 0x96, 0x06, + 0xC8, 0x0C, 0x2E, 0x00, 0x05, 0xFC, 0xC8, 0x09, 0x44, 0x02, 0xD3, 0x40, 0x44, 0x12, 0xD5, 0xF0, + 0x44, 0x22, 0x8F, 0x70, 0x49, 0xFF, 0xF4, 0x7C, 0x3C, 0x0D, 0xFB, 0x4D, 0xA4, 0x00, 0x92, 0x06, + 0x96, 0x06, 0xC8, 0x0E, 0x2E, 0x00, 0x05, 0xFC, 0xC8, 0x0B, 0x44, 0x02, 0xD3, 0x40, 0x44, 0x12, + 0xD5, 0xF0, 0x44, 0x22, 0xD0, 0xF8, 0x44, 0x32, 0x8F, 0x70, 0x49, 0xFF, 0xF3, 0xA8, 0x2E, 0x00, + 0x05, 0xE6, 0x5A, 0x00, 0x01, 0x06, 0x2E, 0x00, 0x05, 0xDA, 0x5A, 0x08, 0x01, 0x06, 0x44, 0x02, + 0xD3, 0x40, 0x49, 0xFF, 0xF5, 0xB2, 0x49, 0xFF, 0xFC, 0xD2, 0x3C, 0x0D, 0xFB, 0x4D, 0xA4, 0x00, + 0x92, 0x06, 0x96, 0x06, 0xC0, 0x0A, 0x84, 0x00, 0x2E, 0x37, 0xC6, 0xC1, 0x80, 0x20, 0x44, 0x40, + 0x00, 0xE0, 0x44, 0x52, 0xD5, 0xF0, 0xD5, 0x40, 0x2E, 0x60, 0x05, 0xFC, 0xCE, 0xF5, 0x44, 0xA2, + 0xD5, 0xF0, 0x44, 0x72, 0xCE, 0x94, 0x44, 0x92, 0xCE, 0x88, 0x2E, 0x07, 0xC6, 0xC1, 0xE2, 0xC0, + 0xE8, 0xEB, 0xB4, 0x0A, 0x9E, 0x41, 0xE6, 0x22, 0xE9, 0x03, 0x5A, 0x08, 0x04, 0x24, 0x38, 0x03, + 0x98, 0x00, 0x5A, 0x08, 0x01, 0x0F, 0x44, 0x02, 0xCE, 0x64, 0x38, 0x00, 0x18, 0x00, 0xC8, 0x09, + 0x00, 0x05, 0x00, 0x5A, 0xC8, 0x06, 0xB6, 0x0A, 0x44, 0x00, 0x00, 0x57, 0x49, 0x00, 0x04, 0x92, + 0x38, 0x04, 0x98, 0x00, 0x5A, 0x08, 0x01, 0x0F, 0x44, 0x02, 0xCE, 0x64, 0x38, 0x00, 0x18, 0x00, + 0xC8, 0x09, 0x00, 0x05, 0x00, 0x5A, 0xC8, 0x06, 0xB6, 0x0A, 0x44, 0x00, 0x00, 0x58, 0x49, 0x00, + 0x04, 0x81, 0x8C, 0xC1, 0x50, 0xA5, 0x00, 0xE0, 0xD5, 0xD1, 0x42, 0x20, 0x90, 0x24, 0x38, 0x22, + 0x88, 0x02, 0xCA, 0x05, 0x8C, 0x21, 0xE2, 0x23, 0xE9, 0xF9, 0xD5, 0x06, 0x5A, 0x20, 0x05, 0xFC, + 0x8C, 0x01, 0x96, 0x00, 0xD5, 0xF8, 0x3E, 0x00, 0x05, 0xF6, 0x2E, 0x07, 0xC7, 0x53, 0x5A, 0x08, + 0x01, 0x1D, 0x2E, 0x00, 0x06, 0x2C, 0x5A, 0x08, 0x01, 0x19, 0x44, 0x02, 0xCE, 0xC8, 0x49, 0xFF, + 0xE9, 0x3D, 0xC8, 0x13, 0x44, 0x02, 0xD0, 0xF8, 0x44, 0x12, 0xD5, 0xF0, 0x2E, 0x27, 0xEC, 0x78, + 0x44, 0x32, 0xB5, 0xDC, 0x49, 0xFF, 0xEA, 0x18, 0x49, 0xFF, 0xE9, 0x6C, 0x5A, 0x08, 0x01, 0x06, + 0x44, 0x02, 0xCE, 0xC8, 0x49, 0xFF, 0xDD, 0xEE, 0x44, 0x02, 0xD5, 0xF0, 0x44, 0x12, 0xD0, 0xF8, + 0x3C, 0x2C, 0x02, 0xA7, 0x44, 0x32, 0xCE, 0xB8, 0x49, 0x00, 0x14, 0x11, 0x49, 0x00, 0x04, 0x53, + 0x49, 0xFF, 0xFB, 0x4E, 0x2E, 0x07, 0xEC, 0x78, 0x2E, 0x67, 0xC7, 0x54, 0x3E, 0x00, 0x05, 0xFB, + 0x5A, 0x68, 0x01, 0x0E, 0x3C, 0x0D, 0xFB, 0x4A, 0xA6, 0x01, 0x5A, 0x00, 0x06, 0x0A, 0x5A, 0x00, + 0x0A, 0x08, 0x49, 0xFF, 0xCF, 0x58, 0xD5, 0x04, 0x80, 0xC0, 0xD5, 0x02, 0x84, 0xC1, 0x80, 0x06, + 0xEC, 0x04, 0x3A, 0x6F, 0xAA, 0x84, 0xDD, 0x9E, 0x3B, 0xFF, 0xFC, 0xBC, 0xEF, 0xF4, 0x49, 0xFF, + 0xDC, 0x9F, 0xF0, 0x81, 0xF1, 0x01, 0x84, 0x00, 0x49, 0x00, 0x04, 0xAD, 0x44, 0x02, 0x45, 0x10, + 0x44, 0x12, 0x40, 0x00, 0x49, 0x00, 0x06, 0xE1, 0x44, 0x12, 0xD3, 0xE4, 0x44, 0x02, 0xD3, 0x40, + 0x49, 0x00, 0x28, 0x04, 0x3C, 0x0C, 0x02, 0xA8, 0x49, 0xFF, 0xF8, 0x10, 0x44, 0x02, 0xD3, 0x40, + 0x44, 0x12, 0xCF, 0xE4, 0x44, 0x22, 0xD3, 0xE4, 0x44, 0x32, 0x8F, 0x70, 0x44, 0x42, 0xD3, 0x34, + 0x49, 0x00, 0x2A, 0x59, 0x2E, 0x07, 0xC7, 0x56, 0x5A, 0x08, 0x01, 0x0B, 0xEC, 0x0C, 0x44, 0x02, + 0xD3, 0x40, 0x44, 0x12, 0xCF, 0x78, 0x3B, 0xFF, 0xFC, 0x84, 0x48, 0x00, 0x2E, 0xBA, 0xEC, 0x0C, + 0x3C, 0x0C, 0x02, 0xA8, 0x3C, 0x1C, 0x02, 0xA7, 0x3B, 0xFF, 0xFC, 0x84, 0x48, 0x00, 0x06, 0xB5, + 0x3A, 0x6F, 0x98, 0xBC, 0x2E, 0x67, 0xEC, 0x10, 0x5A, 0x60, 0x01, 0x07, 0x84, 0x00, 0x3E, 0x07, + 0xEC, 0x39, 0x84, 0x01, 0xD5, 0x1F, 0x2E, 0x07, 0xEC, 0x39, 0xC8, 0x06, 0x84, 0x08, 0x49, 0x00, + 0x03, 0xD9, 0x3E, 0x67, 0xEC, 0x39, 0x49, 0x00, 0x03, 0x58, 0x5A, 0x00, 0x02, 0x14, 0x5A, 0x00, + 0x13, 0x11, 0x3C, 0x0D, 0xFB, 0x59, 0xA6, 0x00, 0x96, 0x00, 0xC8, 0x0B, 0x3E, 0x00, 0x06, 0x39, + 0x49, 0x00, 0x03, 0x7D, 0x5A, 0x00, 0x13, 0x06, 0x49, 0xFF, 0xFF, 0xA0, 0x49, 0x00, 0x03, 0x91, + 0xFA, 0x03, 0x3A, 0x6F, 0x98, 0x84, 0xDD, 0x9E, 0xFC, 0x00, 0x84, 0x01, 0x84, 0x20, 0x84, 0x61, + 0x3E, 0x07, 0xEC, 0x05, 0x80, 0x41, 0x44, 0x00, 0x74, 0xA0, 0x80, 0x83, 0x49, 0x00, 0x13, 0x59, + 0x5A, 0x08, 0xAF, 0x39, 0x84, 0x21, 0x84, 0x00, 0x80, 0x41, 0x80, 0x61, 0x80, 0x81, 0x3E, 0x07, + 0xEC, 0x05, 0x44, 0x00, 0xFB, 0xA0, 0x49, 0x00, 0x13, 0x4C, 0x84, 0x41, 0x80, 0x62, 0x80, 0x82, + 0x44, 0x10, 0x00, 0xFA, 0x44, 0x00, 0x74, 0xA0, 0x49, 0x00, 0x13, 0x43, 0x84, 0x41, 0x80, 0x62, + 0x80, 0x82, 0x44, 0x10, 0x00, 0xFA, 0x44, 0x00, 0x2D, 0x10, 0x49, 0x00, 0x13, 0x3A, 0x84, 0x41, + 0x80, 0x62, 0x80, 0x82, 0x44, 0x10, 0x00, 0xFA, 0x44, 0x00, 0x80, 0x10, 0x49, 0x00, 0x13, 0x31, + 0x84, 0x41, 0x80, 0x62, 0x80, 0x82, 0x44, 0x10, 0x00, 0xFA, 0x44, 0x00, 0xD5, 0x10, 0x49, 0x00, + 0x13, 0x28, 0x84, 0x41, 0x44, 0x00, 0x15, 0xA0, 0x84, 0x20, 0x80, 0x62, 0x80, 0x82, 0x49, 0x00, + 0x13, 0x20, 0xFC, 0x80, 0x2E, 0x07, 0xEC, 0x05, 0xC8, 0x2F, 0xFC, 0x00, 0x84, 0x41, 0x80, 0x62, + 0x80, 0x82, 0x44, 0x10, 0x00, 0xAF, 0x44, 0x00, 0x74, 0xA0, 0x49, 0x00, 0x13, 0x12, 0x84, 0x41, + 0x80, 0x62, 0x80, 0x82, 0x44, 0x10, 0x00, 0xAF, 0x44, 0x00, 0x2D, 0x10, 0x49, 0x00, 0x13, 0x09, + 0x84, 0x41, 0x80, 0x62, 0x80, 0x82, 0x44, 0x10, 0x00, 0xAF, 0x44, 0x00, 0x80, 0x10, 0x49, 0x00, + 0x13, 0x00, 0x84, 0x41, 0x80, 0x62, 0x80, 0x82, 0x44, 0x10, 0x00, 0xAF, 0x44, 0x00, 0xD5, 0x10, + 0x49, 0x00, 0x12, 0xF7, 0x84, 0x21, 0x80, 0x41, 0x80, 0x61, 0x80, 0x81, 0x44, 0x00, 0x15, 0xA0, + 0x49, 0x00, 0x12, 0xEF, 0xFC, 0x80, 0xDD, 0x9E, 0xFC, 0x40, 0x44, 0x23, 0xF0, 0x4A, 0x44, 0x30, + 0x00, 0x55, 0x3C, 0x1D, 0xFB, 0x64, 0xA6, 0x48, 0xC9, 0x03, 0xAE, 0xD0, 0xD5, 0xFB, 0x2E, 0x17, + 0xEC, 0x7D, 0x5A, 0x18, 0x25, 0x62, 0x84, 0x20, 0x3E, 0x17, 0xEC, 0x7D, 0x3E, 0x17, 0xEC, 0x68, + 0x3C, 0x1C, 0x01, 0xA7, 0x44, 0x42, 0x00, 0x00, 0x3C, 0x6C, 0x00, 0x62, 0x04, 0x10, 0x80, 0x12, + 0x84, 0x40, 0x92, 0x30, 0x54, 0x10, 0xFF, 0xFF, 0x94, 0x4A, 0x88, 0x24, 0x80, 0xA4, 0xB4, 0x61, + 0xFA, 0xE8, 0x92, 0x6A, 0x96, 0xF7, 0x02, 0x13, 0x00, 0x1A, 0xE2, 0x41, 0xE8, 0x0E, 0x95, 0x11, + 0x98, 0x65, 0xB5, 0x20, 0xA4, 0x48, 0x88, 0x89, 0xFE, 0x7C, 0x40, 0x10, 0x8C, 0x37, 0x96, 0x49, + 0x8C, 0x41, 0xAC, 0x60, 0x96, 0x91, 0xD5, 0xF0, 0x49, 0xFF, 0xFF, 0x96, 0x44, 0x00, 0x00, 0xFF, + 0x2E, 0x10, 0x06, 0x39, 0x49, 0x00, 0x2F, 0x19, 0x44, 0x02, 0x1B, 0x90, 0x44, 0x12, 0x00, 0x00, + 0x49, 0x00, 0x05, 0xCB, 0x44, 0x02, 0x1B, 0x90, 0x44, 0x12, 0x40, 0x00, 0x49, 0x00, 0x05, 0xC5, + 0x44, 0x13, 0xF6, 0x92, 0x84, 0x00, 0x3E, 0x07, 0xEC, 0x10, 0x3E, 0x07, 0xEC, 0x1B, 0x3E, 0x07, + 0xEC, 0x49, 0xAE, 0x08, 0x84, 0x00, 0x80, 0x20, 0x80, 0x40, 0xFA, 0x6F, 0x49, 0xFF, 0xD6, 0x31, + 0x49, 0x00, 0x2F, 0x70, 0x84, 0x00, 0x49, 0xFF, 0xD9, 0x70, 0x3C, 0x1D, 0xFB, 0x4A, 0x2E, 0x07, + 0xEC, 0x0B, 0x84, 0x81, 0x2E, 0x27, 0xEC, 0x1F, 0xA6, 0x49, 0x2E, 0x37, 0xEC, 0x3C, 0x44, 0x52, + 0xB6, 0x24, 0x49, 0xFF, 0xBD, 0x98, 0xFC, 0xC0, 0xFC, 0x20, 0x80, 0x80, 0x44, 0x03, 0xF0, 0x4A, + 0x44, 0x10, 0x00, 0x55, 0xAE, 0x40, 0x3C, 0x1D, 0xFB, 0x64, 0xA6, 0x08, 0xC0, 0xFF, 0x2E, 0x07, + 0xEC, 0x7D, 0x5A, 0x08, 0x02, 0x2B, 0x2E, 0x07, 0xEC, 0x04, 0xC0, 0x21, 0x84, 0x20, 0x44, 0x52, + 0x00, 0x00, 0x2E, 0x07, 0xC6, 0xC7, 0x92, 0x01, 0xE2, 0x20, 0x4E, 0xF2, 0x00, 0x86, 0x84, 0x40, + 0x2E, 0x07, 0xC6, 0xC8, 0xE2, 0x40, 0xE8, 0x10, 0x2E, 0x07, 0xC6, 0xC7, 0x80, 0x61, 0x42, 0x31, + 0x00, 0x73, 0xB4, 0x04, 0x94, 0xD9, 0x88, 0x03, 0x88, 0x65, 0x8C, 0x41, 0xA4, 0xD8, 0x96, 0x90, + 0x96, 0xD9, 0xAC, 0xC0, 0xD5, 0xEE, 0x8C, 0x21, 0x96, 0x48, 0xD5, 0xE4, 0x44, 0x02, 0x00, 0x00, + 0xB4, 0x24, 0x49, 0x00, 0x05, 0x6A, 0xD5, 0x68, 0xE6, 0x03, 0xE9, 0x66, 0x3C, 0x0C, 0x01, 0xA7, + 0x44, 0x20, 0x01, 0xFF, 0x84, 0xA0, 0x04, 0x10, 0x00, 0x12, 0x44, 0x02, 0x00, 0x54, 0x92, 0x30, + 0x54, 0x10, 0xFF, 0xFF, 0x94, 0x4A, 0x88, 0x20, 0x44, 0x0F, 0xFE, 0x01, 0xB4, 0x21, 0xB4, 0xC4, + 0x92, 0x2A, 0x96, 0x77, 0xFE, 0x0C, 0xFE, 0x54, 0x84, 0x56, 0x96, 0x01, 0x40, 0x10, 0x88, 0x36, + 0x80, 0xE5, 0x44, 0x40, 0x05, 0x10, 0x98, 0xB5, 0xA4, 0xD0, 0x88, 0x60, 0x96, 0xD9, 0xAC, 0xD0, + 0xA4, 0xD0, 0x96, 0xDB, 0x4E, 0x34, 0x00, 0x07, 0xA4, 0xD0, 0x96, 0xDB, 0xE0, 0x23, 0xE8, 0x02, + 0xAD, 0xD0, 0x8C, 0xA2, 0xDC, 0xF1, 0x49, 0xFF, 0xFE, 0xF7, 0x44, 0x00, 0x00, 0xFF, 0x2E, 0x10, + 0x06, 0x39, 0x49, 0x00, 0x2E, 0x7A, 0x44, 0x02, 0x1B, 0x90, 0x44, 0x12, 0x00, 0x00, 0x49, 0x00, + 0x05, 0x2C, 0x44, 0x12, 0x40, 0x00, 0x44, 0x02, 0x1B, 0x90, 0x49, 0x00, 0x05, 0x26, 0x84, 0x00, + 0x3E, 0x07, 0xEC, 0x73, 0x3E, 0x07, 0xEC, 0x49, 0x3E, 0x07, 0xEC, 0x10, 0x84, 0x00, 0x49, 0xFF, + 0xD8, 0xCB, 0x44, 0x13, 0xF0, 0x4A, 0x44, 0x20, 0x00, 0x55, 0x3C, 0x0D, 0xFB, 0x64, 0xA6, 0x00, + 0xC8, 0x03, 0xAE, 0x88, 0xD5, 0xFB, 0x49, 0x00, 0x2E, 0xCD, 0x3C, 0x1D, 0xFB, 0x4A, 0x2E, 0x07, + 0xEC, 0x0B, 0x84, 0x81, 0x2E, 0x27, 0xEC, 0x1F, 0xA6, 0x49, 0x2E, 0x37, 0xEC, 0x3C, 0x44, 0x52, + 0xB6, 0x24, 0x49, 0xFF, 0xBC, 0xF8, 0xFC, 0xA0, 0xFC, 0x40, 0x2E, 0x17, 0xEC, 0x0E, 0x5A, 0x18, + 0x01, 0x04, 0x48, 0x00, 0x00, 0xBE, 0x84, 0x20, 0x3C, 0x6C, 0x00, 0x62, 0x3E, 0x17, 0xEC, 0x31, + 0x84, 0x20, 0x3C, 0x1B, 0xF6, 0x4E, 0x3C, 0x1B, 0xF6, 0x5F, 0x2E, 0x17, 0xEC, 0x7B, 0x02, 0x23, + 0x00, 0x1A, 0xA1, 0x45, 0x5A, 0x18, 0x01, 0x08, 0x2E, 0x27, 0xC6, 0xBB, 0x04, 0x40, 0x00, 0x0C, + 0x94, 0x91, 0xD5, 0x02, 0x80, 0x85, 0x3C, 0x13, 0xF6, 0x52, 0x3C, 0x33, 0xF6, 0x50, 0xE2, 0x23, + 0xE9, 0x07, 0x3C, 0x6D, 0xFB, 0x44, 0x3C, 0x7D, 0xFB, 0x43, 0x84, 0x20, 0xD5, 0x6F, 0x8C, 0x21, + 0x96, 0x49, 0x3C, 0x1B, 0xF6, 0x52, 0x5A, 0x10, 0x01, 0x05, 0x80, 0x04, 0x84, 0x20, 0xD5, 0x4C, + 0x84, 0x20, 0x44, 0x3F, 0xFF, 0x80, 0x44, 0x50, 0x00, 0x7F, 0x96, 0x09, 0xE2, 0x02, 0xE8, 0x0B, + 0x3C, 0x0D, 0xFB, 0x44, 0x38, 0x30, 0x04, 0x08, 0x3C, 0x0D, 0xFB, 0x43, 0x38, 0x50, 0x04, 0x08, + 0x8C, 0x21, 0xD5, 0xF4, 0x2E, 0x07, 0xEC, 0x7B, 0x5A, 0x08, 0x01, 0xE9, 0x3C, 0x5C, 0x02, 0xAC, + 0x3C, 0x7C, 0x02, 0xAB, 0x84, 0x20, 0x00, 0x03, 0x00, 0x10, 0x94, 0x01, 0xE0, 0x20, 0xE8, 0xDE, + 0x94, 0xC9, 0x40, 0x92, 0x8C, 0x00, 0x88, 0x67, 0x8C, 0x21, 0xA4, 0x18, 0x96, 0x49, 0x96, 0x01, + 0x12, 0x04, 0x80, 0x00, 0xD5, 0xF1, 0x3C, 0x6D, 0xFB, 0x44, 0x3C, 0x3D, 0xFB, 0x43, 0x88, 0xC1, + 0x2E, 0x57, 0xEC, 0x7B, 0x20, 0x43, 0x00, 0x00, 0x38, 0x31, 0x84, 0x10, 0x5A, 0x58, 0x01, 0x06, + 0xA5, 0x40, 0x97, 0x6B, 0x90, 0xA2, 0xAD, 0x40, 0xA5, 0x40, 0x97, 0x6B, 0xE0, 0x85, 0xE9, 0x10, + 0xA5, 0x40, 0x97, 0x6B, 0xE0, 0xA3, 0xE9, 0x17, 0xAF, 0x30, 0x3C, 0x4D, 0xFB, 0x43, 0x8C, 0x02, + 0x38, 0x32, 0x04, 0x08, 0x8C, 0x21, 0x96, 0xC9, 0xE2, 0x62, 0xE9, 0xDE, 0xD5, 0x41, 0xA5, 0x00, + 0x97, 0x23, 0x5E, 0xF2, 0x00, 0x80, 0xE8, 0x04, 0xA5, 0x00, 0x97, 0x23, 0xD5, 0xEA, 0x44, 0x40, + 0x00, 0x7F, 0xD5, 0xE7, 0xA4, 0xC0, 0x96, 0xDB, 0x5E, 0xF1, 0xFF, 0x81, 0xE9, 0x04, 0xA4, 0xC0, + 0x96, 0xDB, 0xD5, 0xE3, 0x44, 0x3F, 0xFF, 0x81, 0xD5, 0xE0, 0x96, 0xC9, 0xE2, 0x62, 0xE8, 0x13, + 0x38, 0x43, 0x04, 0x10, 0x38, 0x33, 0x84, 0x00, 0x40, 0x42, 0x20, 0x08, 0xFF, 0x1F, 0x94, 0xC9, + 0x40, 0x92, 0x8C, 0x00, 0x8C, 0x21, 0x12, 0x44, 0x80, 0x00, 0x04, 0x90, 0x00, 0x06, 0x88, 0x69, + 0xAD, 0x18, 0xD5, 0xEC, 0x84, 0xC0, 0x44, 0x00, 0x00, 0xFF, 0x2E, 0x10, 0x06, 0x39, 0x3E, 0x67, + 0xEC, 0x52, 0x3E, 0x67, 0xEC, 0x10, 0x49, 0x00, 0x2D, 0x90, 0x2E, 0x07, 0xEC, 0x7B, 0x5A, 0x08, + 0x01, 0x04, 0x3E, 0x07, 0xEC, 0x16, 0x3E, 0x67, 0xEC, 0x7B, 0x3E, 0x67, 0xEC, 0x7A, 0xFC, 0xC0, + 0x5A, 0x08, 0x04, 0x0E, 0xFC, 0x00, 0x44, 0x00, 0x00, 0xFF, 0x2E, 0x10, 0x06, 0x39, 0x49, 0x00, + 0x2D, 0x7C, 0x3C, 0x0D, 0xFB, 0x59, 0x84, 0x21, 0xAE, 0x40, 0xFC, 0x80, 0x3C, 0x0D, 0xFB, 0x59, + 0x84, 0x21, 0xAE, 0x40, 0xDD, 0x9E, 0xFC, 0x00, 0x3C, 0x0E, 0x00, 0x62, 0x49, 0x00, 0x01, 0xEF, + 0x3C, 0x0F, 0xFB, 0x44, 0x49, 0x00, 0x01, 0xEB, 0x3C, 0x1C, 0x00, 0x62, 0xA6, 0x8A, 0xA6, 0x4B, + 0x42, 0x01, 0x04, 0x73, 0x3C, 0x0F, 0xFB, 0x43, 0xFC, 0x80, 0xFC, 0x00, 0x44, 0x13, 0xF6, 0x9E, + 0x80, 0xC0, 0x44, 0x03, 0xF6, 0x9F, 0x84, 0x40, 0xAE, 0x88, 0xAE, 0x80, 0x44, 0x03, 0xF6, 0xA0, + 0xAE, 0x80, 0x44, 0x03, 0xF6, 0xA1, 0xAE, 0x80, 0x44, 0x03, 0xF6, 0xA2, 0xAE, 0x80, 0x44, 0x23, + 0xF6, 0x92, 0x84, 0x03, 0xAE, 0x10, 0xA6, 0xB0, 0x40, 0x31, 0x0C, 0x09, 0x88, 0x23, 0x96, 0x97, + 0x84, 0x61, 0x40, 0x21, 0x88, 0x0C, 0xA6, 0xC8, 0xFE, 0x9F, 0xAE, 0x88, 0x44, 0x13, 0xF6, 0xAA, + 0xFA, 0x4F, 0xAE, 0x88, 0x44, 0x13, 0xF6, 0xAB, 0xFA, 0x6F, 0xAE, 0x08, 0x84, 0x00, 0x80, 0x20, + 0x80, 0x40, 0x49, 0xFF, 0xD4, 0x66, 0xA6, 0x70, 0x5C, 0xF0, 0x80, 0x23, 0xE8, 0x03, 0x8C, 0x21, + 0xAE, 0x70, 0xFC, 0x80, 0x5A, 0x10, 0x05, 0x0E, 0x5A, 0x10, 0x07, 0x04, 0x5A, 0x18, 0x03, 0x0F, + 0x50, 0x00, 0x00, 0x56, 0x96, 0x00, 0xE6, 0x02, 0xE9, 0x09, 0x84, 0x02, 0xAE, 0x10, 0xDD, 0x9E, + 0x50, 0x00, 0x00, 0x56, 0x96, 0x00, 0xE6, 0x05, 0xD5, 0xF8, 0xDD, 0x9E, 0xFC, 0x41, 0x81, 0x40, + 0x84, 0xC1, 0x84, 0x00, 0x80, 0xE1, 0x81, 0x22, 0xF3, 0x81, 0x3E, 0x67, 0xEC, 0x49, 0x3E, 0x07, + 0xEC, 0x7D, 0x3E, 0x07, 0xEC, 0x68, 0x3E, 0x07, 0xEC, 0x50, 0x5A, 0x28, 0x03, 0x0A, 0x3E, 0x67, + 0xEC, 0x1B, 0x49, 0xFF, 0xFD, 0x33, 0x84, 0x01, 0x49, 0xFF, 0xD7, 0x77, 0xD5, 0x09, 0x3E, 0x67, + 0xEC, 0x73, 0x49, 0xFF, 0xFD, 0x2B, 0x5A, 0xA8, 0xAD, 0x04, 0x3E, 0x67, 0xEC, 0x50, 0x50, 0x05, + 0x00, 0x55, 0x96, 0x00, 0xE6, 0x02, 0xE8, 0x06, 0x84, 0x04, 0x49, 0x00, 0x2D, 0x8A, 0x3E, 0xA7, + 0xEC, 0x03, 0x54, 0x03, 0x80, 0x02, 0xC0, 0x0E, 0x5A, 0x98, 0x03, 0x05, 0x44, 0x02, 0x99, 0x90, + 0xD5, 0x14, 0x44, 0x02, 0x99, 0x94, 0x49, 0xFF, 0xBD, 0x24, 0x84, 0x00, 0x3E, 0x07, 0xEC, 0x04, + 0xD5, 0x0E, 0x49, 0x00, 0x2D, 0x5B, 0xCF, 0x06, 0x5A, 0x90, 0x03, 0xF2, 0x44, 0x02, 0x99, 0x94, + 0xD5, 0x04, 0x5A, 0x78, 0x01, 0x05, 0xF0, 0x01, 0x49, 0xFF, 0xBD, 0x13, 0x3C, 0x1D, 0xFB, 0x4A, + 0x2E, 0x07, 0xEC, 0x0B, 0x84, 0x81, 0x2E, 0x27, 0xEC, 0x1F, 0xA6, 0x49, 0x2E, 0x37, 0xEC, 0x3C, + 0x44, 0x52, 0xB6, 0x24, 0x49, 0xFF, 0xBB, 0x6F, 0x3C, 0x0D, 0xFB, 0x55, 0xA0, 0x06, 0x92, 0x0A, + 0x96, 0x2F, 0x3E, 0x07, 0xEC, 0x7F, 0xFC, 0xC1, 0xFC, 0x20, 0x80, 0xE1, 0x80, 0xC2, 0xC0, 0x0D, + 0x5A, 0x00, 0x04, 0x11, 0x84, 0x00, 0x3C, 0x0B, 0xF6, 0x57, 0x49, 0xFF, 0xBF, 0xDA, 0x44, 0x42, + 0x3F, 0xD8, 0x44, 0x32, 0x3F, 0xD6, 0xD5, 0x0A, 0x44, 0x42, 0x3F, 0xD2, 0x44, 0x32, 0x3F, 0xD0, + 0xD5, 0x05, 0x44, 0x42, 0x3F, 0xD8, 0x44, 0x32, 0x3F, 0xDC, 0x84, 0x00, 0x96, 0x80, 0xE2, 0x46, + 0xE8, 0x07, 0x38, 0x13, 0x81, 0x01, 0x38, 0x12, 0x01, 0x09, 0x8C, 0x01, 0xD5, 0xF8, 0x3C, 0x03, + 0xF6, 0x57, 0xAC, 0x18, 0xFC, 0xA0, 0xFC, 0x01, 0x2E, 0x07, 0xEC, 0x5B, 0x5A, 0x00, 0x01, 0x06, + 0x2E, 0x07, 0xEC, 0x42, 0x5A, 0x08, 0x01, 0x05, 0x49, 0xFF, 0xE1, 0x1B, 0xD5, 0x22, 0x2E, 0x67, + 0xEC, 0x7B, 0x5A, 0x68, 0x01, 0x21, 0x2E, 0x07, 0xEC, 0x7A, 0x5A, 0x08, 0x01, 0x1E, 0x44, 0x02, + 0xD3, 0x40, 0x49, 0xFF, 0xFE, 0x33, 0x80, 0x26, 0x3C, 0x0D, 0xFB, 0x4A, 0x49, 0x00, 0x05, 0x0C, + 0x80, 0x06, 0x49, 0xFF, 0xD9, 0xB3, 0x3C, 0x0D, 0xFB, 0x4A, 0x49, 0xFF, 0xD9, 0xC0, 0xF0, 0x81, + 0x84, 0x40, 0x84, 0x02, 0xF1, 0x01, 0x80, 0x66, 0x80, 0x82, 0x80, 0xA2, 0x49, 0x00, 0x01, 0x4C, + 0xFA, 0xC3, 0xD5, 0x02, 0x84, 0xC1, 0x80, 0x06, 0xFC, 0x81, 0xFC, 0x00, 0x2E, 0x07, 0xEC, 0x1B, + 0x5A, 0x08, 0x01, 0x07, 0x44, 0x02, 0xD3, 0x40, 0x49, 0xFF, 0xFD, 0x00, 0xD5, 0x09, 0x2E, 0x07, + 0xEC, 0x73, 0x5A, 0x08, 0x01, 0x0C, 0x44, 0x02, 0xD3, 0x40, 0x49, 0xFF, 0xFD, 0x67, 0x2E, 0x07, + 0xEC, 0x5F, 0x49, 0xFF, 0xFE, 0xC7, 0xFA, 0x03, 0xD5, 0x02, 0x84, 0x01, 0xFC, 0x80, 0xFC, 0x00, + 0x2E, 0x67, 0xEC, 0x52, 0x84, 0x01, 0x5A, 0x68, 0x01, 0x0A, 0x44, 0x02, 0xD3, 0x40, 0x49, 0xFF, + 0xFD, 0xF5, 0x3C, 0x0D, 0xFB, 0x59, 0xAF, 0x80, 0xFA, 0x03, 0xFC, 0x80, 0x3C, 0x1D, 0xFA, 0xFA, + 0xA6, 0x08, 0x8C, 0x01, 0xAE, 0x08, 0x3C, 0x1D, 0xFA, 0xFA, 0xA6, 0x08, 0x96, 0x06, 0xC8, 0x06, + 0x3C, 0x0D, 0xFA, 0xFC, 0x3C, 0x0F, 0xFA, 0xF9, 0xD5, 0x05, 0x3C, 0x0D, 0xFA, 0xFB, 0x3C, 0x0F, + 0xFA, 0xF9, 0x3C, 0x0D, 0xFA, 0xF9, 0xA6, 0x48, 0x80, 0xA0, 0x10, 0x10, 0x00, 0x3F, 0x84, 0x20, + 0x18, 0x12, 0x80, 0x01, 0x50, 0x00, 0x00, 0x3C, 0x18, 0x12, 0x80, 0x01, 0xD8, 0xFE, 0xDD, 0x9E, + 0x3C, 0x2D, 0xFA, 0xF9, 0xA6, 0x50, 0x98, 0xD1, 0xAE, 0x19, 0x9C, 0x09, 0x96, 0x00, 0x5C, 0xF0, + 0x00, 0x3B, 0xE9, 0x02, 0x84, 0x00, 0xAE, 0x10, 0xA6, 0x10, 0x88, 0x40, 0x84, 0x1F, 0xAE, 0x11, + 0xDD, 0x9E, 0x2E, 0x00, 0x06, 0x12, 0x2E, 0x50, 0x05, 0xA4, 0x3B, 0xFF, 0xFC, 0xBC, 0xEF, 0xFC, + 0xD0, 0x0F, 0xC8, 0x06, 0x44, 0x00, 0x00, 0x52, 0x49, 0xFF, 0xFF, 0xE4, 0xD5, 0x05, 0x44, 0x00, + 0x00, 0x51, 0x49, 0xFF, 0xFF, 0xDF, 0x2E, 0x00, 0x06, 0x12, 0x3E, 0x00, 0x05, 0xA4, 0x2E, 0x00, + 0x06, 0x10, 0x2E, 0x50, 0x05, 0xA5, 0xD0, 0x0F, 0xC8, 0x06, 0x44, 0x00, 0x00, 0x54, 0x49, 0xFF, + 0xFF, 0xD1, 0xD5, 0x05, 0x44, 0x00, 0x00, 0x53, 0x49, 0xFF, 0xFF, 0xCC, 0x2E, 0x00, 0x06, 0x10, + 0x3E, 0x00, 0x05, 0xA5, 0x2E, 0x00, 0x06, 0x11, 0x2E, 0x50, 0x05, 0xA6, 0xD0, 0x0F, 0xC8, 0x06, + 0x44, 0x00, 0x00, 0x56, 0x49, 0xFF, 0xFF, 0xBE, 0xD5, 0x05, 0x44, 0x00, 0x00, 0x55, 0x49, 0xFF, + 0xFF, 0xB9, 0x2E, 0x00, 0x06, 0x11, 0x3E, 0x00, 0x05, 0xA6, 0x2E, 0x00, 0x16, 0x45, 0x5A, 0x00, + 0xAA, 0x08, 0xEC, 0x04, 0x84, 0x07, 0x3B, 0xFF, 0xFC, 0x84, 0x48, 0xFF, 0xFF, 0xAB, 0xEC, 0x04, + 0x3B, 0xFF, 0xFC, 0x84, 0xDD, 0x9E, 0x48, 0xFF, 0xD4, 0x60, 0x44, 0x03, 0xF0, 0x4A, 0x44, 0x10, + 0x00, 0x55, 0xAE, 0x40, 0xDD, 0x9E, 0x48, 0xFF, 0xD7, 0x5F, 0x3B, 0xFF, 0xFC, 0xBC, 0xEF, 0xFC, + 0x49, 0xFF, 0xD7, 0x3E, 0xEC, 0x04, 0x3B, 0xFF, 0xFC, 0x84, 0xDD, 0x9E, 0x2E, 0x00, 0x06, 0x0D, + 0xC8, 0x0A, 0x3B, 0xFF, 0xFC, 0xBC, 0xEF, 0xFC, 0x49, 0xFF, 0xD7, 0x62, 0xEC, 0x04, 0x3B, 0xFF, + 0xFC, 0x84, 0xDD, 0x9E, 0x84, 0x00, 0xDD, 0x9E, 0x48, 0xFF, 0xD3, 0xAE, 0x3A, 0x6F, 0x98, 0xBC, + 0x44, 0x62, 0x8F, 0x70, 0x00, 0x03, 0x00, 0x0B, 0x49, 0xFF, 0xD3, 0xA6, 0xFA, 0x09, 0x49, 0xFF, + 0xEB, 0x55, 0x00, 0x03, 0x00, 0x0B, 0x3A, 0x6F, 0x98, 0x84, 0x52, 0x00, 0x00, 0x01, 0x48, 0xFF, + 0xD3, 0x9B, 0x48, 0xFF, 0xD7, 0xFC, 0x48, 0xFF, 0xD7, 0xEF, 0x44, 0x02, 0x37, 0xFC, 0xDD, 0x9E, + 0x44, 0x12, 0x40, 0x00, 0xB6, 0x20, 0x44, 0x12, 0x4C, 0x60, 0xA8, 0x45, 0x44, 0x12, 0x0C, 0x60, + 0xA8, 0x46, 0x44, 0x12, 0x1B, 0x90, 0xA8, 0x42, 0x44, 0x12, 0x4B, 0x40, 0xA8, 0x44, 0x44, 0x12, + 0x37, 0xFC, 0x14, 0x10, 0x00, 0x11, 0x44, 0x12, 0x99, 0x70, 0x14, 0x10, 0x00, 0x12, 0x44, 0x12, + 0x20, 0xA0, 0x14, 0x10, 0x00, 0x14, 0xDD, 0x9E, 0x3A, 0x6F, 0xA4, 0xBC, 0x80, 0xC0, 0x44, 0x01, + 0x32, 0x24, 0xEF, 0xDC, 0x3A, 0x20, 0x14, 0x00, 0x44, 0x01, 0x32, 0x34, 0xB1, 0xC4, 0x3A, 0x2F, + 0x94, 0x20, 0x3A, 0x20, 0x14, 0x00, 0x3A, 0x23, 0x94, 0x20, 0x49, 0xFF, 0xD9, 0x57, 0xC0, 0x1B, + 0x2E, 0x17, 0xEC, 0x1C, 0x44, 0x20, 0x00, 0x48, 0x38, 0x0F, 0x86, 0x02, 0x14, 0x03, 0x00, 0x0A, + 0x38, 0x03, 0x86, 0x02, 0x14, 0x03, 0x00, 0x0B, 0x44, 0x02, 0xD1, 0x84, 0x42, 0x00, 0x88, 0x73, + 0x14, 0x03, 0x00, 0x13, 0x44, 0x02, 0x29, 0x00, 0x14, 0x03, 0x00, 0x09, 0x44, 0x02, 0x2C, 0x60, + 0x14, 0x03, 0x00, 0x0C, 0xEC, 0x24, 0x3A, 0x6F, 0xA4, 0x84, 0xDD, 0x9E, 0x44, 0x13, 0xF0, 0x1F, + 0x44, 0x33, 0xF3, 0x02, 0xA6, 0x48, 0x54, 0x20, 0x80, 0xE0, 0xA6, 0x58, 0x96, 0x67, 0xE0, 0x01, + 0xE8, 0x06, 0xA6, 0x58, 0x96, 0x67, 0x88, 0x22, 0x9A, 0x08, 0x96, 0x80, 0x44, 0x03, 0xF0, 0x1F, + 0xAE, 0x80, 0xDD, 0x9E, 0x3A, 0x6F, 0x98, 0xBC, 0xEF, 0xF0, 0x80, 0xC0, 0x80, 0x05, 0xB6, 0x3F, + 0xF2, 0x81, 0xF3, 0x82, 0xF4, 0x83, 0x49, 0xFF, 0xD3, 0x30, 0xB4, 0x1F, 0xF1, 0x01, 0x49, 0xFF, + 0xD5, 0xE0, 0x44, 0x03, 0xF0, 0x4A, 0x44, 0x10, 0x00, 0x55, 0xAE, 0x40, 0x5A, 0x68, 0x02, 0x15, + 0x49, 0xFF, 0xD3, 0x62, 0x5A, 0x08, 0x02, 0x06, 0x84, 0x00, 0x49, 0xFF, 0xFF, 0xD1, 0xD5, 0x0C, + 0x2E, 0x07, 0xEC, 0x69, 0x5A, 0x08, 0x03, 0x06, 0x84, 0x09, 0x49, 0xFF, 0xFF, 0xC9, 0xD5, 0x04, + 0x84, 0x05, 0x49, 0xFF, 0xFF, 0xC5, 0xF1, 0x02, 0xF2, 0x03, 0xEC, 0x10, 0x80, 0x06, 0x3A, 0x6F, + 0x98, 0x84, 0x48, 0xFF, 0xD5, 0x83, 0x3A, 0x6F, 0xA0, 0xBC, 0x80, 0xE0, 0x84, 0xC0, 0xE2, 0xC7, + 0xE8, 0x0C, 0x84, 0x01, 0x84, 0x40, 0x80, 0x20, 0x80, 0x62, 0x80, 0x80, 0x80, 0xA2, 0x8C, 0xC1, + 0x49, 0xFF, 0xFF, 0xC2, 0x97, 0xB0, 0xD5, 0xF4, 0x3A, 0x6F, 0xA0, 0x84, 0xDD, 0x9E, 0x84, 0x2B, + 0x3A, 0x6F, 0xA0, 0xBC, 0xAE, 0x41, 0x84, 0x00, 0x3C, 0x0F, 0xFB, 0x81, 0x84, 0x01, 0x49, 0xFF, + 0xD2, 0xC6, 0x44, 0x63, 0xF0, 0x4A, 0x44, 0x70, 0x00, 0x55, 0x3C, 0x0D, 0xFB, 0x81, 0xC0, 0x0D, + 0x84, 0x20, 0x84, 0x61, 0x84, 0x02, 0x80, 0x41, 0x80, 0x83, 0x80, 0xA3, 0x3A, 0x6F, 0xA0, 0x84, + 0x3C, 0x1F, 0xFB, 0x81, 0x48, 0xFF, 0xFF, 0xA0, 0x49, 0xFF, 0xD3, 0xFB, 0x5A, 0x08, 0x01, 0xF2, + 0xAF, 0xF0, 0xD5, 0xEC, 0x3B, 0xFF, 0xFC, 0xBC, 0xEF, 0xFC, 0x49, 0xFF, 0xD3, 0xE9, 0xEC, 0x04, + 0x84, 0x01, 0x3B, 0xFF, 0xFC, 0x84, 0x48, 0xFF, 0xD3, 0xE8, 0xA4, 0x40, 0x8C, 0x21, 0x96, 0x49, + 0x5C, 0xF0, 0x81, 0x90, 0xAC, 0x40, 0xE9, 0x11, 0x3B, 0xFF, 0xFC, 0xBC, 0xEF, 0xFC, 0x84, 0x05, + 0x49, 0xFF, 0xFE, 0x88, 0x84, 0x00, 0x49, 0xFF, 0xB9, 0xA5, 0xEC, 0x04, 0x44, 0x00, 0x00, 0x69, + 0x3B, 0xFF, 0xFC, 0x84, 0x48, 0xFF, 0xD6, 0x96, 0xDD, 0x9E, 0x3B, 0xFF, 0xFC, 0xBC, 0xA7, 0x40, + 0xEF, 0xFC, 0xD9, 0x0C, 0x8C, 0xA1, 0x97, 0x68, 0xE6, 0xA5, 0xE9, 0x02, 0x84, 0xA0, 0xAF, 0x40, + 0x44, 0x0F, 0xFF, 0xAA, 0x3E, 0x07, 0xEC, 0x2A, 0xD5, 0x11, 0x84, 0x06, 0x49, 0xFF, 0xFE, 0x6A, + 0x44, 0x12, 0x2C, 0xF0, 0xA6, 0x08, 0x8C, 0x01, 0x96, 0x00, 0xAE, 0x08, 0x84, 0x00, 0x49, 0xFF, + 0xB9, 0x81, 0x44, 0x00, 0x00, 0x55, 0x49, 0xFF, 0xD6, 0x75, 0x44, 0x02, 0x2C, 0xF0, 0xA6, 0x00, + 0xC0, 0x04, 0x84, 0x01, 0x3E, 0x00, 0x06, 0x31, 0xEC, 0x04, 0x3B, 0xFF, 0xFC, 0x84, 0xDD, 0x9E, + 0xA6, 0x88, 0x5A, 0x28, 0xAA, 0x08, 0xA6, 0x80, 0xAE, 0x88, 0x84, 0x20, 0xAE, 0x40, 0x48, 0xFF, + 0xD6, 0x92, 0xDD, 0x9E, 0x3C, 0x0D, 0xFB, 0x5C, 0x5A, 0x08, 0x04, 0x27, 0x3B, 0xFF, 0xFC, 0xBC, + 0xEF, 0xFC, 0x49, 0xFF, 0xD2, 0xB1, 0x5A, 0x00, 0x02, 0x14, 0x2E, 0x07, 0xC7, 0x53, 0x5A, 0x08, + 0x01, 0x10, 0x84, 0x00, 0x3E, 0x07, 0xEC, 0x0A, 0x84, 0x00, 0x3C, 0x0B, 0xF6, 0x4D, 0x44, 0x12, + 0xB4, 0xE8, 0x44, 0x02, 0xB4, 0xE1, 0x49, 0xFF, 0xFF, 0xDD, 0x84, 0x03, 0xD5, 0x05, 0xFA, 0x00, + 0x3C, 0x0F, 0xFB, 0x5C, 0x84, 0x05, 0xEC, 0x04, 0x84, 0x20, 0x3C, 0x2D, 0xFB, 0x4A, 0x3B, 0xFF, + 0xFC, 0x84, 0x48, 0xFF, 0xCA, 0x85, 0xDD, 0x9E, 0xA6, 0x88, 0x5A, 0x20, 0xAA, 0x0D, 0xAE, 0x80, + 0x44, 0x2F, 0xFF, 0xAA, 0xAE, 0x88, 0xA6, 0x00, 0x5A, 0x08, 0x01, 0x04, 0x48, 0xFF, 0xD6, 0x54, + 0x48, 0xFF, 0xD6, 0x59, 0xDD, 0x9E, 0x84, 0x40, 0xAE, 0x80, 0x84, 0x00, 0xAC, 0x08, 0xDD, 0x9E, + 0x44, 0x03, 0xF5, 0x60, 0x84, 0x20, 0xAE, 0x40, 0x44, 0x03, 0xF5, 0x61, 0x84, 0x23, 0xAE, 0x40, + 0x84, 0x00, 0x80, 0x20, 0x80, 0x40, 0x80, 0x60, 0x48, 0xFF, 0xD1, 0x43, 0x44, 0x03, 0xF5, 0x60, + 0x84, 0x23, 0xAE, 0x40, 0x44, 0x03, 0xF5, 0x61, 0x84, 0x20, 0xAE, 0x40, 0x84, 0x00, 0x80, 0x20, + 0x80, 0x40, 0x80, 0x60, 0x48, 0xFF, 0xD1, 0x35, 0x44, 0x03, 0xF0, 0x07, 0xA6, 0x00, 0x5A, 0x08, + 0x72, 0x0A, 0x44, 0x03, 0xF0, 0x04, 0xA6, 0x40, 0x5A, 0x10, 0x0C, 0x12, 0xA6, 0x00, 0x5A, 0x00, + 0x0E, 0x0F, 0x44, 0x02, 0x2D, 0x60, 0x44, 0x1F, 0xFF, 0x9E, 0xAE, 0x40, 0x84, 0x20, 0x84, 0x02, + 0x80, 0x41, 0x84, 0x61, 0x80, 0x81, 0x80, 0xA1, 0x48, 0xFF, 0xFE, 0xCE, 0xDD, 0x9E, 0x3A, 0x6F, + 0xA8, 0x3C, 0x44, 0x01, 0x32, 0x44, 0xEF, 0xDC, 0x3A, 0x20, 0x14, 0x00, 0x3A, 0x2F, 0x94, 0x20, + 0x44, 0x21, 0x32, 0x54, 0xB0, 0x04, 0x3A, 0x21, 0x14, 0x00, 0x3A, 0x20, 0x14, 0x20, 0x2E, 0x27, + 0xEC, 0x55, 0x38, 0x40, 0x0A, 0x02, 0x2E, 0x07, 0xEC, 0x3F, 0xC8, 0x34, 0x84, 0x61, 0x3E, 0x37, + 0xEC, 0x3F, 0x95, 0x52, 0x44, 0x32, 0x71, 0x40, 0x44, 0x62, 0x45, 0x10, 0x38, 0x31, 0x94, 0x00, + 0x44, 0x72, 0xAD, 0x70, 0x96, 0xD8, 0x38, 0x5F, 0x8A, 0x02, 0x81, 0x20, 0x3C, 0x13, 0xE3, 0x76, + 0xE2, 0x01, 0xE8, 0x20, 0x94, 0x41, 0x40, 0xA0, 0x98, 0x00, 0x88, 0x27, 0x02, 0x85, 0x00, 0x00, + 0xA4, 0x48, 0x38, 0x22, 0x01, 0x01, 0x96, 0x4B, 0x8A, 0x22, 0x38, 0x22, 0x80, 0x00, 0x42, 0x24, + 0x08, 0x24, 0x40, 0x21, 0x0C, 0x0E, 0x88, 0x22, 0x96, 0x49, 0x12, 0x15, 0x00, 0x00, 0x02, 0x15, + 0x00, 0x00, 0x96, 0x4B, 0x4E, 0x14, 0x00, 0x04, 0x12, 0x95, 0x00, 0x00, 0x8C, 0x01, 0x96, 0x01, + 0xD5, 0xDE, 0xEC, 0x24, 0x3A, 0x6F, 0xA8, 0x04, 0xDD, 0x9E, 0x2E, 0x27, 0xEC, 0x23, 0x44, 0x0F, + 0xFF, 0x38, 0xFE, 0x84, 0x3A, 0x6F, 0x9C, 0x3C, 0x96, 0x91, 0x84, 0x20, 0x44, 0x52, 0x45, 0x10, + 0x44, 0x62, 0x1B, 0x90, 0x44, 0x72, 0xAD, 0x70, 0x3C, 0x03, 0xE3, 0x76, 0xE2, 0x20, 0xE8, 0x17, + 0x94, 0xC9, 0x99, 0x1E, 0x98, 0x1D, 0x88, 0x67, 0xA4, 0x00, 0x02, 0xF2, 0x00, 0x00, 0xA5, 0x20, + 0x8A, 0x0F, 0x88, 0x82, 0x97, 0x23, 0x96, 0x03, 0xAD, 0x18, 0x4E, 0x04, 0x00, 0x03, 0xFE, 0x02, + 0x5E, 0xF0, 0x00, 0x5B, 0xE8, 0x06, 0x8C, 0x21, 0x96, 0x49, 0xD5, 0xE7, 0x84, 0x00, 0xD5, 0x02, + 0x84, 0x01, 0x3A, 0x6F, 0x9C, 0x04, 0xDD, 0x9E, 0x84, 0x24, 0x84, 0x40, 0x48, 0xFF, 0xDB, 0x17, + 0x3B, 0xFF, 0xFC, 0xBC, 0xEF, 0xCC, 0x96, 0xD0, 0xFA, 0x40, 0x84, 0xA0, 0x84, 0x81, 0xF2, 0x85, + 0x84, 0x42, 0xF5, 0x83, 0xF5, 0x84, 0xF5, 0x86, 0xF2, 0x87, 0xF5, 0x88, 0xF5, 0x89, 0xB6, 0x7F, + 0xF4, 0x81, 0xF3, 0x82, 0xF4, 0x8A, 0x80, 0x41, 0x80, 0xA4, 0x49, 0xFF, 0xCF, 0x8F, 0xEC, 0x34, + 0x3B, 0xFF, 0xFC, 0x84, 0xDD, 0x9E, 0x3A, 0x6F, 0x98, 0xBC, 0x44, 0x22, 0x8F, 0x70, 0xEF, 0xD0, + 0x00, 0x31, 0x00, 0x0F, 0xFA, 0xC0, 0x00, 0x41, 0x00, 0x10, 0x84, 0xA1, 0x84, 0x40, 0xF6, 0x85, + 0x84, 0xC2, 0xF2, 0x83, 0xF2, 0x84, 0xF2, 0x86, 0xF6, 0x87, 0xF2, 0x88, 0xF2, 0x89, 0xB6, 0x7F, + 0xF5, 0x81, 0xF3, 0x82, 0xF5, 0x8A, 0x80, 0x41, 0x49, 0xFF, 0xCF, 0x70, 0xEC, 0x30, 0x3A, 0x6F, + 0x98, 0x84, 0xDD, 0x9E, 0x84, 0x21, 0x3E, 0x17, 0xEC, 0x7E, 0x54, 0x00, 0x00, 0xFB, 0x84, 0x20, + 0x3E, 0x17, 0xEC, 0x3F, 0xC8, 0x07, 0x44, 0x02, 0x00, 0x00, 0x44, 0x12, 0x45, 0x10, 0x48, 0xFF, + 0xFF, 0xD4, 0x44, 0x02, 0x00, 0x00, 0x44, 0x12, 0x00, 0x02, 0x44, 0x22, 0x45, 0x10, 0x2E, 0x37, + 0xC6, 0xC7, 0x2E, 0x47, 0xC6, 0xC8, 0x84, 0xA0, 0x48, 0xFF, 0xCF, 0xB8, 0x3C, 0x1D, 0xFB, 0x4A, + 0x3A, 0x6F, 0x98, 0xBC, 0xA6, 0x49, 0x80, 0xC0, 0x49, 0xFF, 0xFF, 0xDE, 0x5A, 0x68, 0x03, 0x09, + 0x2E, 0x07, 0xC7, 0xE6, 0xC8, 0x05, 0x3A, 0x6F, 0x98, 0x84, 0x48, 0xFF, 0xFF, 0x1A, 0x3A, 0x6F, + 0x98, 0x84, 0xDD, 0x9E, 0x3B, 0xFF, 0xFC, 0xBC, 0xEF, 0xFC, 0x44, 0x02, 0x45, 0x10, 0x44, 0x12, + 0x1B, 0x90, 0x49, 0xFF, 0xFF, 0xAA, 0x44, 0x02, 0x1B, 0x90, 0x44, 0x12, 0x40, 0x00, 0x49, 0xFF, + 0xFF, 0xA4, 0xEC, 0x04, 0x44, 0x02, 0x0A, 0x20, 0x44, 0x12, 0x4A, 0x20, 0x44, 0x20, 0x00, 0x48, + 0x3B, 0xFF, 0xFC, 0x84, 0x48, 0xFF, 0xFF, 0x7E, 0x48, 0xFF, 0xCE, 0xBF, 0x3A, 0x6F, 0x98, 0xBC, + 0x44, 0x42, 0x8F, 0x70, 0xEF, 0xD0, 0x00, 0x62, 0x00, 0x0F, 0x84, 0xA0, 0x00, 0x42, 0x00, 0x10, + 0xF5, 0x81, 0xF5, 0x82, 0xF5, 0x83, 0xF5, 0x84, 0xF5, 0x86, 0xF5, 0x88, 0xF5, 0x89, 0x84, 0xA1, + 0xB6, 0xDF, 0xF2, 0x85, 0xF3, 0x87, 0xF5, 0x8A, 0x80, 0x66, 0x80, 0x41, 0x49, 0xFF, 0xCF, 0x06, + 0xEC, 0x30, 0x3A, 0x6F, 0x98, 0x84, 0xDD, 0x9E, 0x3B, 0xFF, 0xFC, 0xBC, 0xEF, 0xC4, 0x84, 0xA0, + 0xF3, 0x8D, 0xFA, 0x60, 0x80, 0x82, 0xF3, 0x85, 0x84, 0x41, 0x84, 0x62, 0xF2, 0x81, 0xF4, 0x82, + 0xF3, 0x87, 0xF2, 0x8A, 0xB6, 0xBF, 0xF5, 0x83, 0xF5, 0x84, 0xF5, 0x86, 0xF5, 0x88, 0xF5, 0x89, + 0x80, 0x64, 0x80, 0x41, 0xF4, 0x0D, 0x49, 0xFF, 0xCE, 0xE9, 0xEC, 0x3C, 0x3B, 0xFF, 0xFC, 0x84, + 0xDD, 0x9E, 0x3B, 0xFF, 0xFC, 0xBC, 0x44, 0x42, 0x8F, 0x70, 0xEF, 0xCC, 0x00, 0x32, 0x00, 0x0F, + 0x84, 0xA0, 0x00, 0x42, 0x00, 0x10, 0xF2, 0x84, 0x84, 0x48, 0xF5, 0x81, 0xF5, 0x82, 0xF5, 0x83, + 0xF5, 0x85, 0xF5, 0x86, 0xF2, 0x87, 0xF5, 0x88, 0xF5, 0x89, 0xF5, 0x8A, 0xB6, 0x7F, 0x80, 0x40, + 0x84, 0xA1, 0x49, 0xFF, 0xCE, 0xCB, 0xEC, 0x34, 0x3B, 0xFF, 0xFC, 0x84, 0xDD, 0x9E, 0x3B, 0xFF, + 0xFC, 0xBC, 0xEF, 0xBC, 0xF1, 0x8E, 0xF0, 0x8D, 0x80, 0x23, 0xF2, 0x8F, 0x2E, 0x37, 0xC6, 0xC7, + 0xC4, 0x05, 0x2E, 0x47, 0xC6, 0xC8, 0x80, 0x03, 0xD5, 0x03, 0x80, 0x04, 0x84, 0x81, 0xB6, 0x1F, + 0x84, 0xA1, 0xF0, 0x82, 0x84, 0x00, 0xF0, 0x83, 0xF1, 0x84, 0xF0, 0x85, 0xF0, 0x86, 0xF0, 0x88, + 0xF0, 0x89, 0xF0, 0x8A, 0xF5, 0x81, 0xF5, 0x87, 0xF0, 0x0D, 0xF1, 0x0E, 0xF2, 0x0F, 0x49, 0xFF, + 0xCE, 0xA5, 0xEC, 0x44, 0x3B, 0xFF, 0xFC, 0x84, 0xDD, 0x9E, 0x3A, 0x6F, 0xAA, 0xBC, 0xEF, 0xFC, + 0x00, 0x6F, 0x80, 0x24, 0x01, 0xEF, 0x80, 0x20, 0xF6, 0x89, 0x02, 0x6F, 0x80, 0x1C, 0x00, 0xFF, + 0x80, 0x28, 0xF6, 0x8E, 0x00, 0x6F, 0x80, 0x3C, 0x00, 0x8F, 0x80, 0x2C, 0x00, 0xAF, 0x80, 0x30, + 0x00, 0x9F, 0x80, 0x34, 0xF6, 0x8F, 0x23, 0xCF, 0x80, 0x20, 0x22, 0x7F, 0x80, 0x22, 0x00, 0x6F, + 0x80, 0x48, 0x15, 0xEF, 0x80, 0x08, 0x14, 0xFF, 0x80, 0x0A, 0x14, 0x8F, 0x80, 0x0B, 0x14, 0xAF, + 0x80, 0x0C, 0x14, 0x9F, 0x80, 0x0D, 0x15, 0xCF, 0x80, 0x10, 0xF7, 0x91, 0xF6, 0x92, 0xEC, 0x04, + 0x3A, 0x6F, 0xAA, 0x84, 0x48, 0xFF, 0xCE, 0x72, 0x3A, 0x6F, 0x9C, 0xBC, 0xEF, 0xD4, 0x44, 0x62, + 0x8F, 0x70, 0x00, 0x73, 0x00, 0x0F, 0x00, 0x63, 0x00, 0x10, 0xF3, 0x81, 0xB0, 0xC7, 0xF3, 0x84, + 0x84, 0x60, 0xB6, 0xDF, 0xF4, 0x82, 0xF5, 0x83, 0x80, 0x83, 0x80, 0xA7, 0x49, 0xFF, 0xCD, 0xD5, + 0xEC, 0x2C, 0x3A, 0x6F, 0x9C, 0x84, 0xDD, 0x9E, 0x3A, 0x6F, 0xA0, 0xBC, 0x44, 0x73, 0xF4, 0x23, + 0xA7, 0x78, 0x97, 0xA8, 0x49, 0xFF, 0xD0, 0x5F, 0xC0, 0x04, 0x54, 0x53, 0x00, 0x1F, 0xD5, 0x05, + 0xA7, 0x78, 0x97, 0x67, 0x8E, 0xA1, 0x97, 0x68, 0x2E, 0x00, 0x0D, 0x06, 0x2E, 0x10, 0x0C, 0xF5, + 0x40, 0x00, 0x04, 0x17, 0xD8, 0x08, 0x49, 0xFF, 0xD6, 0x09, 0x8E, 0x01, 0x84, 0x20, 0x40, 0x00, + 0x80, 0x06, 0xD5, 0x02, 0x84, 0x01, 0x3A, 0x6F, 0xA0, 0x84, 0xDD, 0x9E, 0x3B, 0xFF, 0xFC, 0xBC, + 0xEF, 0xFC, 0x84, 0x01, 0x84, 0x20, 0x49, 0xFF, 0xD2, 0xCC, 0xEC, 0x04, 0x44, 0x00, 0x0C, 0xD5, + 0x3B, 0xFF, 0xFC, 0x84, 0x48, 0xFF, 0xD2, 0xCD, 0x44, 0x23, 0xF0, 0x1F, 0xA6, 0x10, 0x54, 0x10, + 0x00, 0xE0, 0x44, 0x03, 0xF3, 0x02, 0xA6, 0xC0, 0xA6, 0x00, 0x96, 0x27, 0x88, 0x01, 0x96, 0x00, + 0xAE, 0x10, 0xDD, 0x9E, 0x3B, 0xFF, 0xFC, 0xBC, 0xEF, 0xF4, 0x5A, 0x08, 0x01, 0x17, 0x3C, 0x0D, + 0xF1, 0xCB, 0x3C, 0x1D, 0xF1, 0xC6, 0xB6, 0x1F, 0x3C, 0x0D, 0xF1, 0xCC, 0x3C, 0x2D, 0xF1, 0xC7, + 0xF0, 0x81, 0x3C, 0x3D, 0xF1, 0xC8, 0x3C, 0x0D, 0xF1, 0xC5, 0x3C, 0x4D, 0xF1, 0xC9, 0x3C, 0x5D, + 0xF1, 0xCA, 0x49, 0xFF, 0xD1, 0x0A, 0xD5, 0x15, 0x3C, 0x0D, 0xF1, 0xC3, 0x3C, 0x1D, 0xF1, 0xBE, + 0xB6, 0x1F, 0x3C, 0x0D, 0xF1, 0xC4, 0x3C, 0x2D, 0xF1, 0xBF, 0xF0, 0x81, 0x3C, 0x3D, 0xF1, 0xC0, + 0x3C, 0x0D, 0xF1, 0xBD, 0x3C, 0x4D, 0xF1, 0xC1, 0x3C, 0x5D, 0xF1, 0xC2, 0x49, 0xFF, 0xD0, 0xF5, + 0x84, 0x00, 0x80, 0x20, 0x80, 0x40, 0x80, 0x60, 0x49, 0xFF, 0xCE, 0xC1, 0xEC, 0x0C, 0x3B, 0xFF, + 0xFC, 0x84, 0x48, 0xFF, 0xCE, 0x8E, 0x3B, 0xFF, 0xFC, 0xBC, 0xEF, 0xFC, 0x49, 0xFF, 0xD2, 0x35, + 0x44, 0x03, 0xF7, 0x05, 0x44, 0x1F, 0xFF, 0xA5, 0xAE, 0x40, 0xEC, 0x04, 0x84, 0x20, 0xAE, 0x40, + 0x3B, 0xFF, 0xFC, 0x84, 0xDD, 0x9E, 0x3B, 0xFF, 0xFC, 0xBC, 0x84, 0x00, 0xEF, 0xFC, 0x80, 0x20, + 0x49, 0xFF, 0xCF, 0xB7, 0x49, 0xFF, 0xD3, 0xA0, 0x49, 0xFF, 0xB8, 0x52, 0x49, 0xFF, 0xFF, 0x90, + 0x49, 0xFF, 0xFF, 0x9C, 0x49, 0xFF, 0xFF, 0xE1, 0x49, 0xFF, 0xCD, 0x64, 0x49, 0xFF, 0xD3, 0xD3, + 0x49, 0xFF, 0xCE, 0xDA, 0x49, 0xFF, 0xCE, 0x7C, 0xEC, 0x04, 0x3B, 0xFF, 0xFC, 0x84, 0x48, 0x00, + 0x30, 0xFF, 0x44, 0x23, 0xF0, 0x77, 0x96, 0x06, 0xA6, 0x50, 0x54, 0x10, 0x80, 0xFE, 0xFE, 0x0F, + 0xAE, 0x10, 0xDD, 0x9E, 0x3A, 0x6F, 0xA0, 0xBC, 0x80, 0xE0, 0x80, 0xC1, 0x49, 0xFF, 0xCF, 0xC4, + 0xA6, 0xB9, 0xC8, 0x06, 0x50, 0x01, 0x7F, 0xF7, 0xE6, 0x02, 0x84, 0x08, 0xE9, 0x02, 0x80, 0x02, + 0x44, 0x13, 0xF0, 0x4A, 0x44, 0x20, 0x00, 0x55, 0xAE, 0x88, 0x44, 0x23, 0xF3, 0x80, 0xA6, 0x50, + 0x5A, 0x10, 0x01, 0xFF, 0x4E, 0x63, 0x00, 0x86, 0x8E, 0x01, 0xE6, 0x0D, 0x4E, 0xF2, 0x00, 0xC9, + 0x44, 0xF0, 0xC5, 0xD0, 0x38, 0x07, 0x81, 0x01, 0x40, 0xF0, 0x3C, 0x00, 0x4A, 0x00, 0x3C, 0x00, + 0x1A, 0x00, 0x7E, 0x01, 0xC4, 0x00, 0x8E, 0x00, 0xC4, 0x00, 0x8E, 0x00, 0x24, 0x00, 0x24, 0x00, + 0x98, 0x00, 0x98, 0x00, 0x8E, 0x00, 0xC4, 0x00, 0xCE, 0x00, 0x84, 0x02, 0x3A, 0x6F, 0xA0, 0x84, + 0x48, 0xFF, 0xD0, 0x9A, 0x84, 0x01, 0x49, 0xFF, 0xCF, 0x4C, 0x84, 0x00, 0x49, 0xFF, 0xFF, 0x54, + 0x2E, 0x07, 0xEC, 0x16, 0x2E, 0x17, 0xCB, 0x4B, 0x5A, 0x00, 0x01, 0x0B, 0x2E, 0x07, 0xEC, 0x5F, + 0x8E, 0x04, 0xE6, 0x02, 0xE9, 0x05, 0x2E, 0x07, 0xEC, 0x7B, 0x5A, 0x08, 0x01, 0x0E, 0xE6, 0x24, + 0xE8, 0x05, 0x84, 0x02, 0x49, 0xFF, 0xE7, 0x1C, 0xD5, 0x15, 0xE6, 0x2D, 0xE8, 0x13, 0x9E, 0x0A, + 0x49, 0xFF, 0xE7, 0x16, 0xD5, 0x0F, 0xE6, 0x24, 0xE8, 0x04, 0x84, 0x01, 0x84, 0x24, 0xD5, 0x04, + 0xE6, 0x2D, 0xE8, 0x08, 0x84, 0x01, 0x84, 0x40, 0x80, 0x62, 0x80, 0x82, 0x80, 0xA0, 0x49, 0xFF, + 0xFB, 0xEB, 0x84, 0x01, 0x49, 0xFF, 0xD1, 0xE9, 0x84, 0x01, 0x49, 0xFF, 0xFF, 0x8C, 0x84, 0x00, + 0x3A, 0x6F, 0xA0, 0x84, 0x48, 0xFF, 0xD0, 0x60, 0x84, 0x01, 0x49, 0xFF, 0xFF, 0x84, 0x84, 0x00, + 0x49, 0xFF, 0xFF, 0x1A, 0x2E, 0x07, 0xEC, 0x16, 0x5A, 0x08, 0x01, 0x06, 0x84, 0x02, 0x49, 0xFF, + 0xE6, 0xEF, 0xD5, 0x09, 0x84, 0x40, 0x84, 0x01, 0x84, 0x24, 0x80, 0x62, 0x80, 0x82, 0x80, 0xA0, + 0x49, 0xFF, 0xFB, 0xCA, 0x84, 0x00, 0x3A, 0x6F, 0xA0, 0x84, 0x48, 0xFF, 0xD1, 0x44, 0x84, 0x40, + 0x84, 0x01, 0x80, 0xA0, 0x2E, 0x17, 0xCB, 0x4B, 0x80, 0x62, 0x80, 0x82, 0x49, 0xFF, 0xFB, 0xBC, + 0x84, 0x01, 0x49, 0xFF, 0xD1, 0xBA, 0x84, 0x00, 0x3A, 0x6F, 0xA0, 0x84, 0x48, 0xFF, 0xD0, 0x34, + 0x5A, 0x68, 0x01, 0x3D, 0x8E, 0x03, 0xE6, 0x0B, 0xE8, 0x43, 0x44, 0xF0, 0xC6, 0xD8, 0x38, 0x07, + 0x80, 0x00, 0x40, 0xF0, 0x3C, 0x00, 0xDD, 0x0F, 0x32, 0x0C, 0x32, 0x0C, 0x16, 0x16, 0x2C, 0x2C, + 0x76, 0x32, 0x3C, 0x00, 0x84, 0x01, 0x3A, 0x6F, 0xA0, 0x84, 0x48, 0xFF, 0xD0, 0x1D, 0x84, 0x01, + 0x49, 0xFF, 0xFE, 0xDA, 0x84, 0x01, 0x49, 0xFF, 0xD0, 0x17, 0x44, 0x00, 0x00, 0x37, 0x49, 0xFF, + 0xE6, 0x75, 0xD5, 0x11, 0x84, 0x01, 0x49, 0xFF, 0xFE, 0xCF, 0x84, 0x01, 0x3A, 0x6F, 0xA0, 0x84, + 0x48, 0xFF, 0xD1, 0x09, 0x84, 0x01, 0x49, 0xFF, 0xFE, 0xC7, 0x49, 0xFF, 0xFC, 0x83, 0x84, 0x01, + 0x49, 0xFF, 0xD0, 0x02, 0x84, 0x00, 0x49, 0xFF, 0xFF, 0x26, 0x84, 0x00, 0x49, 0xFF, 0xD1, 0x7D, + 0x84, 0x00, 0x3A, 0x6F, 0xA0, 0x84, 0x48, 0xFF, 0xCE, 0xAC, 0x5A, 0x68, 0x02, 0x0A, 0x84, 0x01, + 0x49, 0xFF, 0xCF, 0xF2, 0x84, 0x00, 0x3A, 0x6F, 0xA0, 0x84, 0x48, 0xFF, 0xD1, 0x6E, 0x3A, 0x6F, + 0xA0, 0x84, 0xDD, 0x9E, 0x3A, 0x6F, 0xA8, 0xBC, 0x2E, 0x60, 0x06, 0x0C, 0x80, 0xE1, 0x5A, 0x68, + 0x01, 0x1B, 0x84, 0x00, 0x84, 0x20, 0x3E, 0x00, 0x06, 0x0C, 0x80, 0x41, 0x44, 0x00, 0x46, 0xE0, + 0x80, 0x66, 0x80, 0x86, 0x49, 0x00, 0x0A, 0x05, 0x5A, 0x08, 0x07, 0x0E, 0x84, 0x20, 0x44, 0x00, + 0xCF, 0xF0, 0x80, 0x41, 0x80, 0x66, 0x80, 0x86, 0x49, 0x00, 0x09, 0xFB, 0xC8, 0x04, 0x84, 0x03, + 0x3E, 0x07, 0xEC, 0x69, 0x3C, 0x0D, 0xFB, 0x5C, 0x5A, 0x08, 0x04, 0x10, 0x2E, 0x07, 0xC7, 0x53, + 0xC0, 0x0C, 0x84, 0x02, 0x49, 0x00, 0x26, 0xC5, 0x49, 0xFF, 0xCE, 0xB6, 0x5A, 0x08, 0x02, 0x16, + 0x84, 0x0B, 0x49, 0xFF, 0xE6, 0x55, 0xD5, 0x11, 0x49, 0xFF, 0xCE, 0xAE, 0x5A, 0x00, 0x02, 0xF3, + 0x84, 0x01, 0x49, 0x00, 0x26, 0xB6, 0x84, 0x61, 0x84, 0x20, 0x84, 0x02, 0x80, 0x41, 0x80, 0x83, + 0x80, 0xA3, 0x49, 0xFF, 0xFB, 0x29, 0xD5, 0xF1, 0x3C, 0x0D, 0xFB, 0x5C, 0x5A, 0x08, 0x04, 0x13, + 0x49, 0xFF, 0xCE, 0x9A, 0x5A, 0x00, 0x02, 0x0F, 0x2E, 0x67, 0xC7, 0x53, 0x5A, 0x68, 0x01, 0x0B, + 0x80, 0x06, 0x49, 0xFF, 0xCF, 0x72, 0x84, 0x00, 0x49, 0xFF, 0xB5, 0x3C, 0x80, 0x06, 0x49, 0xFF, + 0xCE, 0x26, 0x44, 0x63, 0xF0, 0x4A, 0x44, 0x90, 0x00, 0x55, 0x3C, 0x0D, 0xFB, 0x81, 0xC0, 0x09, + 0x84, 0x04, 0x49, 0x00, 0x26, 0x8E, 0x3C, 0x0D, 0xFB, 0x5C, 0x5A, 0x08, 0x04, 0x2D, 0xD5, 0x0B, + 0x49, 0xFF, 0xCF, 0x5F, 0x5A, 0x08, 0x01, 0xF6, 0x84, 0x03, 0x49, 0x00, 0x26, 0x82, 0x10, 0x93, + 0x00, 0x00, 0xD5, 0xEC, 0x49, 0xFF, 0xCE, 0x70, 0x5A, 0x00, 0x02, 0x1E, 0x2E, 0x07, 0xC7, 0x53, + 0x5A, 0x08, 0x01, 0x1A, 0x49, 0xFF, 0xFB, 0x58, 0x44, 0x03, 0xF4, 0x29, 0x44, 0x1F, 0xFF, 0xC3, + 0xAE, 0x40, 0x44, 0x03, 0xF0, 0x1C, 0x84, 0x20, 0xAE, 0x40, 0x84, 0x00, 0x49, 0xFF, 0xC6, 0x17, + 0x3C, 0x0D, 0xFB, 0x4A, 0x84, 0x20, 0x49, 0xFF, 0xFE, 0x8F, 0x84, 0x02, 0xAE, 0x39, 0x3A, 0x6F, + 0xA8, 0x84, 0xDD, 0x9E, 0x80, 0x47, 0x84, 0x05, 0x84, 0x20, 0x49, 0xFF, 0xC6, 0x41, 0x3C, 0x0D, + 0xFB, 0x4A, 0x84, 0x20, 0x49, 0xFF, 0xFE, 0x80, 0x84, 0x02, 0xAE, 0x39, 0x84, 0x01, 0x49, 0xFF, + 0xD0, 0x6D, 0x84, 0x05, 0x3A, 0x6F, 0xA8, 0x84, 0x48, 0x00, 0x26, 0x4B, 0x2E, 0x07, 0xEC, 0x0B, + 0x5A, 0x08, 0x01, 0x28, 0x3A, 0x6F, 0x98, 0xBC, 0x49, 0xFF, 0xCE, 0x36, 0xC8, 0x20, 0x3C, 0x0D, + 0xFB, 0x64, 0xA6, 0x40, 0x5A, 0x18, 0x01, 0xFF, 0xA6, 0x00, 0x5A, 0x08, 0x01, 0x19, 0x3C, 0x0D, + 0xFB, 0x59, 0xA7, 0x80, 0x97, 0xB0, 0x5A, 0x68, 0x01, 0x13, 0x3C, 0x0D, 0xFB, 0x4A, 0x84, 0x20, + 0x49, 0xFF, 0xFE, 0x5A, 0x3C, 0x1D, 0xFB, 0x64, 0x84, 0x00, 0xAE, 0x08, 0x3C, 0x1D, 0xFB, 0x59, + 0xAE, 0x08, 0x80, 0x06, 0x3A, 0x6F, 0x98, 0x84, 0x48, 0xFF, 0xB4, 0xC4, 0x3A, 0x6F, 0x98, 0x84, + 0xDD, 0x9E, 0x3C, 0x0D, 0xFB, 0x4A, 0xA6, 0x01, 0x5A, 0x00, 0x06, 0x42, 0x2E, 0x07, 0xEC, 0x10, + 0x3B, 0xFF, 0xFC, 0xBC, 0xEF, 0xFC, 0x5A, 0x00, 0x01, 0x06, 0x2E, 0x07, 0xEC, 0x66, 0x5A, 0x08, + 0x03, 0x04, 0x49, 0xFF, 0xC5, 0x8D, 0x3C, 0x0D, 0xFB, 0x64, 0xA6, 0x00, 0x5A, 0x08, 0x01, 0x2D, + 0x3C, 0x0D, 0xFB, 0x59, 0xA6, 0x00, 0x5A, 0x08, 0x01, 0x28, 0x84, 0x00, 0x3C, 0x0F, 0xFB, 0x8A, + 0x2E, 0x07, 0xEC, 0x1B, 0x5A, 0x08, 0x01, 0x06, 0x44, 0x02, 0xB5, 0x20, 0x49, 0xFF, 0xF8, 0x2F, + 0x2E, 0x07, 0xEC, 0x73, 0xC0, 0x04, 0x2E, 0x07, 0xEC, 0x3D, 0xC8, 0x16, 0x3C, 0x0D, 0xFB, 0x4A, + 0x84, 0x20, 0x49, 0xFF, 0xFE, 0x19, 0x3C, 0x0D, 0xFB, 0x64, 0x84, 0x20, 0xAE, 0x40, 0x2E, 0x07, + 0xEC, 0x57, 0xC8, 0x04, 0x3C, 0x1D, 0xFB, 0x59, 0xAE, 0x08, 0xEC, 0x04, 0x84, 0x01, 0x3B, 0xFF, + 0xFC, 0x84, 0x48, 0xFF, 0xB4, 0x7F, 0xEC, 0x04, 0x3B, 0xFF, 0xFC, 0x84, 0xDD, 0x9E, 0x3B, 0xFF, + 0xFC, 0xBC, 0xEF, 0xFC, 0x49, 0xFF, 0xCD, 0xC8, 0x5A, 0x08, 0x02, 0x07, 0xEC, 0x04, 0x3B, 0xFF, + 0xFC, 0x84, 0x48, 0xFF, 0xFF, 0xB0, 0x3C, 0x0D, 0xFB, 0x4A, 0xA6, 0x01, 0x5A, 0x00, 0x0A, 0x07, + 0xEC, 0x04, 0x3B, 0xFF, 0xFC, 0x84, 0x48, 0xFF, 0xFF, 0x7B, 0xEC, 0x04, 0x3B, 0xFF, 0xFC, 0x84, + 0xDD, 0x9E, 0x3A, 0x6F, 0xA4, 0xBC, 0xEF, 0xDC, 0x44, 0x11, 0x32, 0x64, 0xB1, 0x84, 0x3A, 0x20, + 0x94, 0x00, 0x81, 0x20, 0x3A, 0x23, 0x14, 0x20, 0x49, 0xFF, 0xC5, 0x32, 0x49, 0xFF, 0xC2, 0xF1, + 0xF0, 0x81, 0x84, 0x00, 0x12, 0x0F, 0x80, 0x07, 0x84, 0xE0, 0x38, 0x13, 0x1E, 0x02, 0x50, 0x0F, + 0x80, 0x0E, 0x2E, 0x27, 0xC6, 0xC7, 0x2E, 0x37, 0xC6, 0xC8, 0x8C, 0xE1, 0x49, 0xFF, 0xFC, 0x76, + 0x5A, 0x78, 0x04, 0xF5, 0x00, 0x04, 0x80, 0x00, 0x5A, 0x08, 0x01, 0x1D, 0x84, 0x03, 0x3C, 0x1D, + 0xFB, 0x4A, 0xF2, 0x01, 0x44, 0x32, 0xB5, 0x0D, 0x49, 0xFF, 0xB7, 0xD0, 0x2E, 0x17, 0xEC, 0x23, + 0x44, 0x00, 0x00, 0xC8, 0xFE, 0x0C, 0x12, 0x0F, 0x80, 0x07, 0x44, 0x12, 0x1B, 0x90, 0x50, 0x0F, + 0x80, 0x0E, 0x2E, 0x27, 0xC6, 0xC7, 0x2E, 0x37, 0xC6, 0xC8, 0x49, 0xFF, 0xFC, 0x57, 0x49, 0xFF, + 0xFF, 0xA8, 0x44, 0x03, 0xF0, 0x4A, 0x44, 0x10, 0x00, 0x55, 0xEC, 0x24, 0xAE, 0x40, 0x3A, 0x6F, + 0xA4, 0x84, 0x84, 0x00, 0xDD, 0x9E, 0x3A, 0x6F, 0x9A, 0xBC, 0xEF, 0xF4, 0xFA, 0x00, 0x49, 0xFF, + 0xF8, 0xF1, 0x49, 0xFF, 0xB4, 0x50, 0x84, 0x00, 0x84, 0x21, 0x3E, 0x17, 0xEC, 0x1E, 0x3E, 0x07, + 0xEC, 0x4D, 0x3E, 0x00, 0x06, 0x09, 0x3E, 0x07, 0xEC, 0x35, 0x3E, 0x07, 0xEC, 0x3A, 0x49, 0xFF, + 0xCD, 0x53, 0x3C, 0x1D, 0xFB, 0x4A, 0x5A, 0x08, 0x02, 0x0D, 0x84, 0x04, 0xAE, 0x09, 0x80, 0x01, + 0x84, 0x20, 0x49, 0xFF, 0xFD, 0x81, 0x3C, 0x0D, 0xFB, 0x4A, 0x84, 0x2C, 0xAE, 0x41, 0xD5, 0x0B, + 0x84, 0x08, 0xAE, 0x09, 0x80, 0x01, 0x84, 0x20, 0x49, 0xFF, 0xFD, 0x76, 0x3C, 0x0D, 0xFB, 0x4A, + 0x84, 0x29, 0xAE, 0x41, 0x3C, 0x0D, 0xFB, 0x64, 0x84, 0x21, 0xAE, 0x40, 0x2E, 0x07, 0xC7, 0x54, + 0x5A, 0x08, 0x01, 0x12, 0x2E, 0x07, 0xEC, 0x66, 0x3E, 0x07, 0xEC, 0x4F, 0x2E, 0x07, 0xEC, 0x54, + 0xC8, 0x04, 0x3E, 0x07, 0xEC, 0x0C, 0xD5, 0x07, 0x2E, 0x07, 0xEC, 0x0C, 0x5A, 0x08, 0x01, 0x04, + 0x3E, 0x00, 0x06, 0x09, 0x3C, 0x0D, 0xFB, 0x4A, 0xA6, 0x01, 0x3E, 0x07, 0xEC, 0x67, 0x84, 0x06, + 0x49, 0x00, 0x25, 0x27, 0x2E, 0x00, 0x06, 0x09, 0xC8, 0x2C, 0x3C, 0x1D, 0xFB, 0x4A, 0x2E, 0x27, + 0xEC, 0x55, 0x44, 0x32, 0xB5, 0x0D, 0x49, 0xFF, 0xB7, 0x59, 0x3C, 0x07, 0xF6, 0x5E, 0x49, 0xFF, + 0xC0, 0x25, 0x2E, 0x07, 0xC7, 0x5E, 0x5A, 0x08, 0x01, 0x05, 0x49, 0xFF, 0xDC, 0x18, 0xD5, 0x16, + 0x3C, 0x1D, 0xFB, 0x64, 0x84, 0x01, 0xAE, 0x08, 0x3C, 0x1D, 0xFB, 0x59, 0xAE, 0x08, 0x49, 0xFF, + 0xC4, 0x87, 0x49, 0xFF, 0xFF, 0x2E, 0x3C, 0x1D, 0xFB, 0x64, 0xA6, 0x08, 0xC0, 0xFF, 0x44, 0x02, + 0x00, 0x00, 0x44, 0x12, 0x1B, 0x90, 0x49, 0xFF, 0xFB, 0x48, 0x84, 0x0B, 0x49, 0x00, 0x24, 0xF9, + 0x2E, 0x00, 0x06, 0x09, 0x5A, 0x08, 0x01, 0x13, 0x84, 0x00, 0x12, 0x0F, 0x80, 0x03, 0x44, 0x12, + 0xAD, 0x70, 0x50, 0x0F, 0x80, 0x06, 0x2E, 0x27, 0xC6, 0xC7, 0x2E, 0x37, 0xC6, 0xC8, 0x49, 0xFF, + 0xFB, 0xBD, 0x49, 0xFF, 0xD7, 0x5C, 0x3E, 0x07, 0xEC, 0x35, 0x2E, 0x07, 0xC7, 0x54, 0x5A, 0x08, + 0x01, 0x0D, 0x2E, 0x00, 0x06, 0x09, 0x5A, 0x00, 0x01, 0x05, 0x2E, 0x07, 0xEC, 0x35, 0xC8, 0x05, + 0x44, 0x02, 0xCE, 0xC1, 0x49, 0xFF, 0xFF, 0x17, 0x2E, 0x07, 0xC7, 0x54, 0x5A, 0x08, 0x01, 0x28, + 0x2E, 0x00, 0x06, 0x09, 0xC8, 0x0D, 0x49, 0xFF, 0xD6, 0x59, 0x80, 0xC0, 0x5A, 0x08, 0x01, 0x18, + 0xFA, 0x03, 0x49, 0xFF, 0xF8, 0x47, 0x3E, 0x67, 0xEC, 0x0C, 0x48, 0xFF, 0xFF, 0x51, 0x2E, 0x07, + 0xEC, 0x35, 0x5A, 0x08, 0x01, 0x08, 0x3C, 0x1D, 0xFB, 0x64, 0xA6, 0x08, 0x5A, 0x08, 0x01, 0xFF, + 0xD5, 0x06, 0x2E, 0x07, 0xEC, 0x55, 0x84, 0x20, 0x49, 0xFF, 0xD6, 0xCF, 0x3C, 0x1D, 0xFB, 0x4A, + 0x2E, 0x07, 0xEC, 0x66, 0xA6, 0x49, 0x49, 0xFF, 0xFB, 0x17, 0xD5, 0x05, 0x2E, 0x07, 0xEC, 0x66, + 0x49, 0xFF, 0xFB, 0x2E, 0x84, 0x00, 0x3E, 0x00, 0x06, 0x36, 0x2E, 0x07, 0xEC, 0x20, 0x5A, 0x08, + 0x01, 0x0A, 0x49, 0xFF, 0xCC, 0x91, 0x5A, 0x00, 0x02, 0x06, 0x3C, 0x03, 0xE4, 0x52, 0x3C, 0x0E, + 0x01, 0x87, 0x84, 0x00, 0x3E, 0x07, 0xEC, 0x75, 0x3E, 0x07, 0xEC, 0x20, 0x3E, 0x07, 0xEC, 0x1E, + 0x2E, 0x07, 0xC7, 0x7C, 0x84, 0x21, 0x3E, 0x07, 0xEC, 0x4A, 0x3C, 0x0D, 0xFB, 0x59, 0xAE, 0x40, + 0x49, 0xFF, 0xFE, 0xAF, 0x49, 0x00, 0x07, 0x06, 0x5A, 0x08, 0x02, 0x07, 0xFA, 0x03, 0x49, 0xFF, + 0xF8, 0x01, 0x48, 0xFF, 0xFF, 0x0D, 0x84, 0x00, 0x44, 0x22, 0x25, 0xB0, 0x80, 0x60, 0x44, 0x42, + 0x20, 0xA0, 0x80, 0xA0, 0x3C, 0x13, 0xE3, 0x76, 0xE2, 0x01, 0xE8, 0x09, 0x98, 0x42, 0xAE, 0xC8, + 0x94, 0x41, 0x88, 0x24, 0x8C, 0x01, 0xAD, 0x48, 0x96, 0x01, 0xD5, 0xF5, 0x84, 0x00, 0x3E, 0x07, + 0xEC, 0x64, 0x84, 0x01, 0x3E, 0x07, 0xEC, 0x2B, 0xEC, 0x0C, 0x3A, 0x6F, 0x9A, 0x84, 0xDD, 0x9E, + 0xFC, 0x40, 0xA7, 0x00, 0x2E, 0x77, 0xC6, 0xC1, 0x5A, 0x40, 0x01, 0x07, 0x84, 0x80, 0x44, 0x62, + 0x8F, 0x70, 0x81, 0x24, 0xD5, 0x17, 0x2E, 0x90, 0x05, 0xA1, 0x44, 0x42, 0x93, 0x71, 0x84, 0xA0, + 0xD7, 0x0B, 0xA7, 0xA0, 0x5A, 0x98, 0x01, 0x03, 0x8C, 0xC2, 0x8C, 0xA1, 0x10, 0x62, 0x7F, 0xEB, + 0x97, 0x68, 0x8C, 0x81, 0xD5, 0xF6, 0xA6, 0x00, 0x3C, 0x43, 0xE6, 0xF6, 0x5A, 0x08, 0x01, 0x59, + 0xD5, 0x09, 0x97, 0x60, 0xE2, 0xA7, 0xE8, 0xF8, 0x99, 0x66, 0x8C, 0x81, 0x10, 0x92, 0x83, 0xEC, + 0xD5, 0xF9, 0x2E, 0x07, 0xEC, 0x6B, 0x9A, 0x10, 0xE4, 0x02, 0xE9, 0x09, 0x5A, 0x38, 0x01, 0x08, + 0x2E, 0x00, 0x01, 0x8E, 0xC8, 0x08, 0x3E, 0x30, 0x01, 0x8E, 0xD5, 0x04, 0x84, 0x00, 0x3E, 0x00, + 0x01, 0x8E, 0x84, 0x60, 0x84, 0x00, 0x3E, 0x07, 0xEC, 0x6B, 0xA6, 0x09, 0xC8, 0x1C, 0x2E, 0x07, + 0xC7, 0x6B, 0x5A, 0x08, 0x01, 0x17, 0x5A, 0x30, 0x01, 0x08, 0x5A, 0x28, 0x01, 0x13, 0x3C, 0x00, + 0x03, 0xE0, 0xE6, 0x12, 0xE9, 0x0E, 0x2E, 0x07, 0xEC, 0x56, 0x5A, 0x08, 0x01, 0x05, 0x44, 0x00, + 0x00, 0x41, 0xD5, 0x04, 0x3C, 0x00, 0x05, 0x3E, 0x8C, 0x05, 0x3C, 0x0B, 0xE5, 0x59, 0xD5, 0x03, + 0x3C, 0x4B, 0xE5, 0x59, 0x3C, 0x1D, 0xFB, 0x4D, 0xA4, 0x08, 0x92, 0x07, 0x96, 0x06, 0x5A, 0x08, + 0x01, 0x05, 0x44, 0x00, 0x00, 0x73, 0xD5, 0x15, 0xA4, 0x08, 0x92, 0x06, 0x96, 0x06, 0x5A, 0x08, + 0x01, 0x13, 0x3C, 0x00, 0x05, 0x3E, 0x3C, 0x13, 0xE5, 0x59, 0x50, 0x20, 0x00, 0x19, 0xE0, 0x41, + 0xE8, 0x05, 0x8E, 0x34, 0x3C, 0x1B, 0xE5, 0x59, 0xD5, 0x06, 0x8C, 0x05, 0xD5, 0x02, 0x84, 0x00, + 0x3C, 0x0B, 0xE5, 0x59, 0xFC, 0xC0, 0xFC, 0x41, 0x3C, 0x0D, 0xFB, 0x4D, 0x81, 0x41, 0x81, 0x02, + 0xA4, 0x00, 0x80, 0xE3, 0x92, 0x02, 0x96, 0x06, 0x5A, 0x00, 0x01, 0x04, 0x84, 0x0C, 0xD5, 0x02, + 0x84, 0x0D, 0xB6, 0x1F, 0x84, 0x00, 0x3E, 0x07, 0xEC, 0x56, 0x3E, 0x07, 0xEC, 0x48, 0x3C, 0x03, + 0xE6, 0xFA, 0x3C, 0x93, 0xE6, 0xF9, 0xF0, 0x81, 0x2E, 0x07, 0xC7, 0x54, 0x5A, 0x00, 0x01, 0x06, + 0x2E, 0x07, 0xC7, 0x57, 0x5A, 0x08, 0x01, 0x04, 0xA5, 0xB8, 0xD5, 0x03, 0x3C, 0x63, 0xE3, 0xC1, + 0x3C, 0x04, 0x03, 0x99, 0x84, 0x42, 0x40, 0x20, 0x08, 0x56, 0x96, 0x91, 0xE2, 0x46, 0x40, 0x23, + 0x3C, 0x1A, 0x96, 0x11, 0xE2, 0x09, 0x40, 0x24, 0xBC, 0x1B, 0x3C, 0x0C, 0x02, 0xA7, 0x44, 0x12, + 0xD0, 0xF8, 0x96, 0x91, 0x84, 0x80, 0x44, 0x32, 0xB4, 0xF9, 0x49, 0xFF, 0x9B, 0x73, 0x84, 0x20, + 0x2E, 0x57, 0xEC, 0x41, 0x3C, 0x4C, 0x02, 0x11, 0x3D, 0xEC, 0x02, 0x12, 0x80, 0x41, 0x80, 0x01, + 0x96, 0xC8, 0xE2, 0x65, 0xE8, 0x10, 0x38, 0xF2, 0x05, 0x01, 0x96, 0xC9, 0x4C, 0xF1, 0xC0, 0x0A, + 0x38, 0x3F, 0x05, 0x01, 0xE2, 0x62, 0x88, 0x03, 0x40, 0x31, 0x3C, 0x1B, 0x96, 0x01, 0x80, 0x43, + 0x8C, 0x21, 0xD5, 0xEF, 0x4E, 0x83, 0x00, 0x05, 0x02, 0x1F, 0x80, 0x02, 0xD5, 0x0A, 0x4E, 0xA3, + 0x00, 0x05, 0x3C, 0xA8, 0x00, 0xC6, 0xD5, 0x07, 0x3C, 0x10, 0x00, 0xC6, 0xC1, 0x04, 0x8E, 0x21, + 0x3C, 0x18, 0x00, 0xC6, 0xB4, 0x3F, 0xE2, 0x22, 0xE8, 0x15, 0x3C, 0x1D, 0xFB, 0x4D, 0xA4, 0x48, + 0x92, 0x22, 0x96, 0x46, 0xC1, 0x05, 0x2E, 0x17, 0xEC, 0x2F, 0x5A, 0x18, 0x01, 0x0C, 0x2E, 0x17, + 0xEC, 0x66, 0xC1, 0x03, 0xFA, 0x6E, 0xD5, 0x02, 0xFA, 0x64, 0x84, 0x21, 0x3E, 0x17, 0xEC, 0x56, + 0xD5, 0x02, 0x84, 0x60, 0x2E, 0x17, 0xC6, 0xBB, 0x2E, 0x47, 0xC6, 0xBA, 0x8E, 0x21, 0x3C, 0x5C, + 0x02, 0xA7, 0xFE, 0x64, 0x94, 0x49, 0x87, 0xC0, 0x88, 0x25, 0x80, 0xBE, 0xD4, 0x10, 0x02, 0xF0, + 0x80, 0x00, 0x40, 0xF7, 0x80, 0x11, 0x5E, 0xF7, 0x80, 0x15, 0xE9, 0x05, 0x51, 0xEF, 0x00, 0x01, + 0x55, 0xEF, 0x00, 0xFF, 0x8C, 0xA1, 0x97, 0x68, 0x8C, 0x22, 0xD5, 0xF1, 0x90, 0xA1, 0xE0, 0xBE, + 0x84, 0x20, 0xE8, 0x02, 0x84, 0x21, 0x3E, 0x10, 0x05, 0xA8, 0xE6, 0x46, 0x84, 0x20, 0x3E, 0x17, + 0xEC, 0x48, 0xE8, 0x0E, 0x3C, 0x1D, 0xFB, 0x4D, 0xA4, 0x48, 0x92, 0x22, 0x96, 0x46, 0xC1, 0x05, + 0x2E, 0x17, 0xEC, 0x2F, 0x5A, 0x18, 0x01, 0x05, 0x84, 0x21, 0x3E, 0x17, 0xEC, 0x48, 0x4E, 0xA2, + 0x00, 0x0E, 0x4E, 0x82, 0x00, 0x0C, 0x3C, 0x10, 0x00, 0xC6, 0xC9, 0x08, 0x3C, 0x1D, 0xFB, 0x4D, + 0xA4, 0x48, 0x92, 0x22, 0x96, 0x46, 0x5A, 0x18, 0x01, 0x04, 0xAD, 0xB8, 0xD5, 0x17, 0x2E, 0x17, + 0xEC, 0x56, 0x5A, 0x18, 0x01, 0x0B, 0xE7, 0x42, 0xE9, 0x08, 0x9A, 0x30, 0x9A, 0xC3, 0xE0, 0x69, + 0x40, 0x34, 0xBC, 0x1B, 0xAC, 0xF8, 0xD5, 0x0A, 0x40, 0x14, 0x80, 0x00, 0xE0, 0x26, 0xE8, 0x04, + 0x9A, 0x30, 0xAC, 0x38, 0xD5, 0x03, 0x12, 0x93, 0x80, 0x00, 0x5A, 0x88, 0x01, 0x06, 0xE6, 0x5F, + 0xE9, 0x03, 0x12, 0x93, 0x80, 0x00, 0x2E, 0x07, 0xC7, 0x6B, 0xC8, 0x02, 0xAD, 0xB8, 0xFC, 0xC1, + 0x3C, 0x0E, 0x00, 0x69, 0xDD, 0x9E, 0x3C, 0x0E, 0x00, 0x68, 0xDD, 0x9E, 0xFC, 0x00, 0x84, 0x00, + 0x84, 0x20, 0x3E, 0x00, 0x01, 0x9E, 0x3E, 0x00, 0x01, 0x9B, 0x3E, 0x00, 0x01, 0x9A, 0x3C, 0x18, + 0x00, 0xCC, 0x3C, 0x18, 0x00, 0xCB, 0x3E, 0x10, 0x01, 0x9D, 0x3E, 0x00, 0x01, 0x9C, 0x44, 0x10, + 0x00, 0x40, 0x84, 0x00, 0x3E, 0x17, 0xEB, 0xD1, 0x3E, 0x17, 0xEB, 0xD0, 0x3C, 0x0E, 0x00, 0x6A, + 0xFC, 0x80, 0x3C, 0x0C, 0x00, 0x69, 0xA4, 0x41, 0x3C, 0x18, 0x00, 0xCA, 0xA4, 0x44, 0xA6, 0x00, + 0x3C, 0x18, 0x00, 0xC9, 0x3E, 0x00, 0x01, 0x90, 0xDD, 0x9E, 0x3C, 0x40, 0x00, 0xCA, 0x3C, 0x2C, + 0x00, 0x69, 0x3C, 0x30, 0x00, 0xC9, 0xC0, 0x09, 0xE6, 0x8F, 0xE9, 0x03, 0x8E, 0x85, 0xAD, 0x11, + 0xE6, 0x6F, 0xE9, 0x05, 0x8E, 0x65, 0xD5, 0x02, 0xAD, 0x11, 0xAC, 0xD4, 0xA6, 0x09, 0x5A, 0x08, + 0x06, 0x04, 0x84, 0x01, 0xD5, 0x03, 0x2E, 0x00, 0x01, 0x90, 0xAE, 0x10, 0xDD, 0x9E, 0xFC, 0x47, + 0x81, 0x41, 0x3C, 0x1C, 0x00, 0x68, 0xF2, 0x8A, 0x3C, 0x2C, 0x00, 0x69, 0x00, 0x80, 0x80, 0x02, + 0xA6, 0x4B, 0xF3, 0x8B, 0xF1, 0x85, 0x22, 0x10, 0x00, 0x03, 0xF4, 0x8C, 0xF1, 0x82, 0xF3, 0x02, + 0xA4, 0x52, 0x41, 0xE0, 0x8C, 0x07, 0xF1, 0x86, 0xA4, 0x51, 0x40, 0x50, 0x8C, 0x07, 0xF1, 0x87, + 0x22, 0x30, 0x00, 0x02, 0x22, 0x11, 0x00, 0x03, 0xA4, 0x04, 0xE0, 0x61, 0x40, 0x00, 0x20, 0x76, + 0x14, 0xFF, 0x80, 0x01, 0x97, 0xC2, 0x96, 0x5A, 0xC5, 0x19, 0x2E, 0x6F, 0xEB, 0xD1, 0x5A, 0x60, + 0x40, 0x1F, 0x9B, 0x8E, 0x2E, 0x4F, 0xEB, 0xD0, 0x4E, 0x64, 0x00, 0x03, 0xFF, 0xB2, 0x97, 0xB2, + 0xE4, 0xC3, 0xE8, 0x08, 0x9B, 0x3C, 0x4E, 0x44, 0x00, 0x03, 0xFF, 0x22, 0x97, 0x22, 0xE4, 0x83, + 0xE9, 0x12, 0x84, 0x81, 0x3E, 0x40, 0x01, 0x9D, 0xD5, 0x0E, 0x44, 0x00, 0x00, 0x40, 0x3E, 0x07, + 0xEB, 0xD1, 0x3E, 0x07, 0xEB, 0xD0, 0x3E, 0x50, 0x01, 0x9D, 0xD5, 0x5B, 0x3E, 0x17, 0xEB, 0xD1, + 0x3E, 0x77, 0xEB, 0xD0, 0x5A, 0x58, 0x01, 0x56, 0x85, 0x20, 0x4E, 0x17, 0x00, 0x05, 0x9F, 0x19, + 0x54, 0x92, 0x00, 0xFF, 0x50, 0x44, 0x7F, 0xFF, 0xE0, 0x24, 0xE8, 0x04, 0x8C, 0x61, 0x96, 0xD8, + 0xD5, 0x02, 0x96, 0xE0, 0xF3, 0x83, 0x84, 0x80, 0x4E, 0x77, 0x00, 0x04, 0x9F, 0x01, 0x97, 0x20, + 0xF3, 0x05, 0x8E, 0x61, 0xE0, 0xE3, 0xE8, 0x04, 0x8C, 0x01, 0x96, 0x00, 0xD5, 0x02, 0x96, 0x18, + 0x84, 0x60, 0xF0, 0x84, 0x80, 0x03, 0xF6, 0x04, 0xE2, 0xC4, 0xE9, 0x1C, 0x42, 0x62, 0x20, 0x24, + 0x8A, 0x09, 0xF6, 0x88, 0xF0, 0x8D, 0x80, 0xC9, 0xF0, 0x0D, 0x88, 0x06, 0x96, 0x00, 0xF0, 0x89, + 0xF0, 0x03, 0xE2, 0x06, 0xE9, 0x0B, 0xF0, 0x08, 0x88, 0x06, 0x94, 0x01, 0x88, 0x0A, 0x8C, 0xC1, + 0xA4, 0x00, 0x97, 0xB0, 0x88, 0x60, 0x96, 0xDB, 0xD5, 0xF0, 0x8C, 0x81, 0xF0, 0x09, 0x97, 0x20, + 0xD5, 0xE3, 0x42, 0x13, 0xA0, 0x73, 0x94, 0x49, 0xA5, 0x95, 0x88, 0x2A, 0xFF, 0x84, 0x84, 0x89, + 0xA4, 0x48, 0x40, 0xF3, 0x11, 0xF6, 0xE0, 0x6F, 0x96, 0x4B, 0xE9, 0x0D, 0x8A, 0x61, 0xA4, 0x56, + 0x8E, 0x01, 0xFE, 0x0C, 0x96, 0xDB, 0x40, 0x00, 0x10, 0x16, 0x40, 0x31, 0x80, 0x07, 0xD5, 0x04, + 0x84, 0x60, 0xD5, 0x02, 0x84, 0x61, 0x3C, 0x0C, 0x00, 0x6A, 0x5A, 0x00, 0x01, 0x32, 0xC0, 0x05, + 0x5A, 0x00, 0x02, 0x4F, 0x48, 0x00, 0x00, 0x86, 0x3C, 0x04, 0x00, 0xCB, 0xF1, 0x07, 0xE0, 0x01, + 0xE8, 0x03, 0x84, 0x00, 0xD5, 0x05, 0xF1, 0x06, 0xE0, 0x20, 0xE8, 0x04, 0x84, 0x01, 0x3E, 0x00, + 0x01, 0x9C, 0x2E, 0x00, 0x01, 0x9C, 0xC8, 0x1A, 0x5A, 0x58, 0x01, 0x19, 0x4F, 0xE3, 0x00, 0x17, + 0xF0, 0x01, 0xC8, 0x14, 0xCB, 0x13, 0x2E, 0x00, 0x01, 0x9D, 0x5A, 0x08, 0x01, 0x10, 0x2E, 0x00, + 0x01, 0x9B, 0xA6, 0x50, 0x8C, 0x01, 0x8C, 0x21, 0x96, 0x00, 0x90, 0x21, 0xE0, 0x20, 0x3E, 0x00, + 0x01, 0x9B, 0xE8, 0x5F, 0x3C, 0x5E, 0x00, 0x6A, 0xD5, 0x1A, 0x84, 0x00, 0xD5, 0x1E, 0x5A, 0x58, + 0x01, 0x1A, 0x4F, 0xE3, 0x00, 0x18, 0xF0, 0x01, 0xC8, 0x15, 0xCB, 0x14, 0x2E, 0x00, 0x01, 0x9D, + 0x5A, 0x08, 0x01, 0x11, 0x2E, 0x00, 0x01, 0x9B, 0xA6, 0x50, 0x8C, 0x01, 0x96, 0x00, 0xE2, 0x20, + 0x3E, 0x00, 0x01, 0x9B, 0xE8, 0x46, 0x84, 0x02, 0x3C, 0x0E, 0x00, 0x6A, 0x3E, 0x30, 0x01, 0x9B, + 0xD5, 0x40, 0x84, 0x00, 0x3C, 0x0E, 0x00, 0x6A, 0x3E, 0x00, 0x01, 0x9B, 0xD5, 0x3A, 0xA4, 0x17, + 0x5B, 0xE0, 0x01, 0x07, 0xF1, 0x01, 0x5A, 0x10, 0x01, 0x04, 0x5A, 0x38, 0x01, 0x1F, 0x2E, 0x10, + 0x01, 0x9A, 0xA6, 0x91, 0xE2, 0x41, 0xE9, 0x04, 0x8C, 0x21, 0x3E, 0x10, 0x01, 0x9A, 0x3C, 0x10, + 0x00, 0xCC, 0xE2, 0x01, 0xE9, 0x04, 0x8C, 0x21, 0x3C, 0x18, 0x00, 0xCC, 0x2E, 0x10, 0x01, 0x9A, + 0xE2, 0x41, 0xE9, 0x05, 0x3C, 0x10, 0x00, 0xCC, 0xE2, 0x01, 0xE8, 0x1B, 0x84, 0x00, 0x3C, 0x0E, + 0x00, 0x6A, 0x3E, 0x00, 0x01, 0x9A, 0xD5, 0x13, 0x84, 0x20, 0x3E, 0x10, 0x01, 0x9A, 0x84, 0x20, + 0x5A, 0x50, 0x01, 0x05, 0x3C, 0x10, 0x00, 0xCC, 0x8C, 0x21, 0x3C, 0x18, 0x00, 0xCC, 0x3C, 0x10, + 0x00, 0xCC, 0xE2, 0x01, 0xE8, 0x06, 0x84, 0x00, 0x3C, 0x0E, 0x00, 0x6A, 0x3C, 0x08, 0x00, 0xCC, + 0x3C, 0x0C, 0x00, 0x6A, 0x5A, 0x08, 0x02, 0x04, 0x84, 0x01, 0xD5, 0x02, 0x84, 0x00, 0x3E, 0x00, + 0x01, 0x9E, 0x2E, 0x00, 0x01, 0x9E, 0x5A, 0x00, 0x01, 0x04, 0x48, 0x00, 0x00, 0xA1, 0xF0, 0x0C, + 0x04, 0x9F, 0x80, 0x0A, 0xF0, 0x8D, 0xF0, 0x0B, 0xF0, 0x83, 0x49, 0xFF, 0xC9, 0x65, 0xC0, 0x0C, + 0x2E, 0x07, 0xC7, 0x5C, 0x5A, 0x08, 0x01, 0x09, 0x3C, 0x2C, 0x00, 0x69, 0x80, 0x0A, 0x80, 0x29, + 0xA4, 0x94, 0x49, 0x00, 0x06, 0x07, 0x3C, 0x2C, 0x00, 0x69, 0x80, 0x0A, 0x80, 0x29, 0xA4, 0x94, + 0xF3, 0x03, 0x84, 0x81, 0x49, 0xFF, 0x99, 0x26, 0xF0, 0x03, 0xA6, 0x00, 0x4E, 0x02, 0x00, 0x80, + 0x3C, 0x0C, 0x00, 0x69, 0x84, 0x20, 0xF0, 0x86, 0x50, 0x04, 0x7F, 0xFF, 0xF0, 0x87, 0xF0, 0x05, + 0x8E, 0x01, 0xF0, 0x88, 0x00, 0x0F, 0x80, 0x20, 0xF0, 0x8B, 0x00, 0x0F, 0x80, 0x1C, 0xF0, 0x8C, + 0xF0, 0x03, 0xA6, 0x00, 0xE2, 0x20, 0xE8, 0x6B, 0x04, 0x24, 0x80, 0x01, 0x94, 0x09, 0x41, 0xE1, + 0x00, 0x00, 0x02, 0x5F, 0x00, 0x00, 0xD9, 0x60, 0x04, 0x24, 0x80, 0x03, 0x38, 0x21, 0x05, 0x01, + 0xF2, 0x85, 0xF3, 0x05, 0xF2, 0x0D, 0xE2, 0x43, 0xE9, 0x57, 0x04, 0x24, 0x80, 0x04, 0x88, 0x02, + 0xA6, 0xC1, 0xA7, 0x00, 0xC3, 0x05, 0x9E, 0x19, 0x96, 0x00, 0xF0, 0x81, 0xD5, 0x02, 0xF3, 0x81, + 0xF0, 0x07, 0xE0, 0x60, 0xE8, 0x04, 0x8C, 0x61, 0x96, 0x18, 0xD5, 0x02, 0xF0, 0x0C, 0xF0, 0x84, + 0xC4, 0x04, 0x9F, 0xE1, 0x97, 0xF8, 0xD5, 0x02, 0x80, 0xE4, 0xF0, 0x08, 0xE0, 0x80, 0xE8, 0x04, + 0x8C, 0x81, 0x97, 0x20, 0xD5, 0x02, 0xF4, 0x0B, 0x84, 0xC0, 0x80, 0x06, 0xE2, 0x87, 0xE9, 0x1C, + 0x42, 0x23, 0xA0, 0x24, 0xF2, 0x8A, 0xF2, 0x01, 0x8A, 0x02, 0x80, 0x60, 0x80, 0x03, 0x88, 0x02, + 0x96, 0x00, 0xF0, 0x89, 0xF0, 0x04, 0xE2, 0x02, 0xE9, 0x0B, 0xF0, 0x0A, 0x88, 0x02, 0x94, 0x01, + 0x88, 0x0A, 0x8C, 0x41, 0xA4, 0x00, 0x96, 0x90, 0x88, 0xC0, 0x97, 0xB3, 0xD5, 0xF0, 0x8C, 0xE1, + 0xF0, 0x09, 0x97, 0xF8, 0xD5, 0xE4, 0xF2, 0x06, 0xA4, 0xD5, 0x84, 0x49, 0xFE, 0xC4, 0x40, 0xF1, + 0x89, 0xF6, 0xE0, 0xCF, 0xE9, 0x0C, 0xF3, 0x05, 0x8E, 0x01, 0x8A, 0xC3, 0xF3, 0x06, 0x97, 0xB3, + 0xA4, 0xDE, 0xFE, 0x1C, 0x40, 0xF0, 0x09, 0xF6, 0xE0, 0xCF, 0xE8, 0x06, 0x44, 0x0F, 0x80, 0x00, + 0xFF, 0x47, 0x12, 0x5F, 0x00, 0x00, 0x8C, 0x21, 0x96, 0x48, 0xD5, 0x93, 0x02, 0x0F, 0x80, 0x04, + 0x3C, 0x08, 0x00, 0xCB, 0x3C, 0x0C, 0x00, 0x6A, 0x8E, 0x02, 0x5C, 0x00, 0x00, 0x01, 0xFC, 0xC7, + 0x3A, 0x6F, 0xAA, 0xBC, 0xEF, 0xFC, 0x2E, 0x57, 0xC6, 0xBA, 0x2E, 0x27, 0xC6, 0xEA, 0x2E, 0x47, + 0xC6, 0xBB, 0x96, 0x29, 0x42, 0x10, 0x08, 0x24, 0x3C, 0x1B, 0xE3, 0x65, 0x96, 0xE1, 0x2E, 0x17, + 0xC6, 0xEB, 0xFE, 0x1C, 0x3C, 0x0B, 0xE3, 0x76, 0x42, 0x61, 0x84, 0x24, 0x44, 0x02, 0x2D, 0x85, + 0x92, 0x41, 0x92, 0x21, 0x3C, 0x6B, 0xE3, 0x66, 0x3E, 0x27, 0xC6, 0xF1, 0x3E, 0x17, 0xC6, 0xF2, + 0x3E, 0x57, 0xC6, 0xC7, 0x3E, 0x47, 0xC6, 0xC8, 0xA6, 0x40, 0x84, 0x21, 0x84, 0xC0, 0xAE, 0x40, + 0xA6, 0x41, 0xAF, 0x81, 0x44, 0x02, 0x7B, 0x90, 0x3C, 0x6F, 0xFB, 0x4E, 0x49, 0xFF, 0xB0, 0x49, + 0x3C, 0x0C, 0x01, 0xA1, 0x44, 0x12, 0x2C, 0xFE, 0x3C, 0x0F, 0xFB, 0x5B, 0x44, 0x22, 0x2C, 0xFC, + 0x44, 0x02, 0x2D, 0x5E, 0x84, 0xE0, 0xAF, 0x80, 0xAF, 0xC1, 0xAF, 0xC2, 0xAF, 0xC3, 0xAD, 0x90, + 0xAD, 0x88, 0x3C, 0x1F, 0xFB, 0x54, 0x44, 0x12, 0x2C, 0xF8, 0x3C, 0x1F, 0xFB, 0x64, 0x44, 0x12, + 0x2C, 0xF9, 0x3C, 0x1F, 0xFB, 0x59, 0x44, 0x12, 0x2C, 0xFA, 0x3C, 0x1F, 0xFB, 0x4A, 0x2E, 0x17, + 0xC7, 0x5B, 0x3C, 0x0F, 0xFB, 0x4D, 0x3C, 0x2F, 0xFB, 0x52, 0x3E, 0x67, 0xEC, 0x45, 0x5A, 0x18, + 0x01, 0x07, 0xA4, 0x40, 0x58, 0x10, 0x90, 0x00, 0xAC, 0x40, 0xD5, 0x06, 0xA4, 0x80, 0x44, 0x1F, + 0xEF, 0xFF, 0xFE, 0x56, 0xAC, 0x40, 0x44, 0x12, 0x2D, 0x5E, 0x85, 0x21, 0xA4, 0x08, 0x84, 0xC0, + 0x58, 0x00, 0x20, 0x00, 0xAC, 0x08, 0xA4, 0x88, 0x84, 0x1B, 0xFE, 0x86, 0xAC, 0x88, 0xA4, 0xC8, + 0x44, 0x2F, 0xBF, 0xFF, 0xFE, 0x9E, 0xAC, 0x88, 0xA4, 0x88, 0x85, 0x40, 0x58, 0x21, 0x00, 0x20, + 0xAC, 0x88, 0xA4, 0xC8, 0x84, 0x5D, 0xFE, 0xD6, 0xAC, 0xC8, 0xA4, 0xC8, 0x85, 0x01, 0x40, 0x31, + 0xA4, 0x04, 0xAC, 0xC8, 0xA5, 0x08, 0x44, 0x3F, 0xFF, 0xBF, 0xFE, 0xE6, 0xAC, 0xC8, 0xA4, 0x48, + 0x84, 0xE0, 0x3C, 0x1B, 0xF6, 0xCC, 0x44, 0x12, 0x2C, 0xFE, 0xA6, 0xC8, 0xFE, 0x9E, 0xAE, 0x88, + 0xA6, 0x88, 0x54, 0x21, 0x00, 0xFE, 0xAE, 0x88, 0xA6, 0x88, 0xFE, 0x16, 0xAE, 0x08, 0xA6, 0x08, + 0x54, 0x00, 0x00, 0xF7, 0xAE, 0x08, 0xA6, 0x48, 0x44, 0x02, 0x2C, 0xFC, 0xAE, 0x40, 0x3E, 0x67, + 0xEC, 0x71, 0x3E, 0x67, 0xEC, 0x62, 0x3C, 0x9E, 0x01, 0x86, 0x3C, 0xAB, 0xF6, 0x54, 0x3E, 0xA7, + 0xEC, 0x7C, 0x3E, 0x67, 0xEC, 0x6C, 0x3E, 0x67, 0xEC, 0x36, 0x3E, 0x60, 0x06, 0x36, 0x2E, 0x07, + 0xC7, 0x60, 0x3E, 0x67, 0xEC, 0x0A, 0x3E, 0x07, 0xEC, 0x29, 0x44, 0x0F, 0xFF, 0xAA, 0x3E, 0x07, + 0xEC, 0x30, 0x44, 0x00, 0x00, 0x55, 0x3E, 0x07, 0xEC, 0x34, 0x3E, 0x07, 0xEC, 0x2A, 0x3E, 0x07, + 0xEC, 0x6D, 0x3C, 0xAB, 0xF6, 0x4D, 0x3C, 0xAB, 0xF6, 0x56, 0x3E, 0x67, 0xEC, 0x38, 0x3E, 0x67, + 0xEC, 0x44, 0x3E, 0x87, 0xEC, 0x5F, 0x3E, 0x87, 0xEC, 0x17, 0x49, 0x00, 0x1E, 0x9F, 0x2E, 0x07, + 0xC7, 0x54, 0x3E, 0x67, 0xEC, 0x01, 0x3E, 0x07, 0xEC, 0x54, 0x3C, 0x0D, 0xFB, 0x4A, 0x3E, 0x67, + 0xEC, 0x02, 0x3C, 0xAB, 0xF6, 0x4F, 0x3E, 0x67, 0xEC, 0x16, 0xAF, 0x81, 0x3E, 0x67, 0xEC, 0x15, + 0xAF, 0x80, 0x3C, 0x1D, 0xFB, 0x64, 0x84, 0x02, 0x3E, 0x67, 0xEC, 0x0B, 0x3C, 0x9E, 0x01, 0xD2, + 0x3E, 0x67, 0xEC, 0x3C, 0x3E, 0x60, 0x06, 0x2C, 0x3E, 0x67, 0xEC, 0x1F, 0xAE, 0x08, 0x3C, 0x1D, + 0xFB, 0x59, 0xAE, 0x08, 0x84, 0x04, 0x3E, 0x07, 0xEC, 0x69, 0x44, 0x02, 0xCF, 0x9C, 0x3C, 0x0E, + 0x01, 0xEC, 0x44, 0x02, 0xD0, 0xB0, 0x3C, 0x0E, 0x01, 0xED, 0x44, 0x02, 0xD2, 0xA4, 0x3C, 0x0E, + 0x01, 0xEE, 0x44, 0x02, 0xD4, 0xE4, 0x3C, 0x0E, 0x01, 0xEF, 0x44, 0x00, 0x00, 0x3C, 0x3E, 0x67, + 0xEC, 0x20, 0x3C, 0x7F, 0xFB, 0x55, 0x3E, 0x67, 0xEC, 0x51, 0x3C, 0x7B, 0xF6, 0x4C, 0x3E, 0x67, + 0xEC, 0x2F, 0x3E, 0x67, 0xEC, 0x56, 0x3E, 0x67, 0xEC, 0x48, 0x3E, 0x87, 0xEC, 0x4B, 0x3C, 0xAB, + 0xF6, 0x61, 0x3C, 0xAB, 0xF6, 0x5B, 0x3C, 0x08, 0x05, 0x3E, 0x3C, 0x08, 0x05, 0x42, 0x44, 0x02, + 0xD4, 0xC0, 0x3C, 0x0E, 0x02, 0xA0, 0x44, 0x02, 0xD4, 0x84, 0x3C, 0x0F, 0xFB, 0x60, 0x84, 0x0A, + 0x3E, 0x07, 0xED, 0x68, 0x2E, 0x07, 0xC6, 0xBB, 0x3E, 0x67, 0xEC, 0x14, 0x3E, 0x07, 0xC7, 0xED, + 0x80, 0x07, 0x3E, 0x67, 0xED, 0x7C, 0x3E, 0x67, 0xED, 0x69, 0x3E, 0x67, 0xED, 0x6A, 0x3E, 0x60, + 0x05, 0xFC, 0x3C, 0x7F, 0xFB, 0x69, 0x3C, 0x7F, 0xFB, 0x65, 0x3C, 0x7F, 0xFB, 0x5E, 0x3C, 0x7F, + 0xFB, 0x50, 0x3C, 0x7F, 0xFB, 0x62, 0x3C, 0x7F, 0xFB, 0x4F, 0x3C, 0x7F, 0xFB, 0x6B, 0x3C, 0x7F, + 0xFB, 0x63, 0x3C, 0x7F, 0xFB, 0x48, 0x3C, 0x7F, 0xFB, 0x4B, 0x49, 0xFF, 0x97, 0x11, 0x80, 0x09, + 0x49, 0xFF, 0x97, 0x0E, 0x80, 0x07, 0x49, 0xFF, 0x97, 0x19, 0x3C, 0x0E, 0x02, 0x10, 0x80, 0x09, + 0x49, 0xFF, 0x97, 0x14, 0x3C, 0x0E, 0x02, 0x11, 0x84, 0x02, 0x49, 0xFF, 0x97, 0x0F, 0x3C, 0x0E, + 0x02, 0x12, 0x84, 0x03, 0x49, 0xFF, 0x97, 0x0A, 0x3C, 0x0E, 0x02, 0x13, 0x84, 0x04, 0x49, 0xFF, + 0x97, 0x05, 0x3C, 0x0E, 0x02, 0x14, 0x84, 0x05, 0x49, 0xFF, 0x97, 0x00, 0x3C, 0x0E, 0x02, 0x15, + 0x84, 0x06, 0x49, 0xFF, 0x96, 0xFB, 0x3C, 0x0E, 0x02, 0x16, 0x84, 0x07, 0x49, 0xFF, 0x96, 0xF6, + 0x3C, 0x0E, 0x02, 0x17, 0x84, 0x08, 0x49, 0xFF, 0x96, 0xF1, 0x3C, 0x0E, 0x02, 0x18, 0x3C, 0x03, + 0xE3, 0x65, 0x3C, 0x13, 0xE4, 0x72, 0x3C, 0x0B, 0xE4, 0x70, 0x3C, 0x03, 0xE3, 0x66, 0x3C, 0x7E, + 0x01, 0x8A, 0x3C, 0x0B, 0xE4, 0xD9, 0x3C, 0x03, 0xE4, 0x73, 0x3E, 0x60, 0x06, 0x24, 0x40, 0x00, + 0x24, 0x0C, 0x88, 0x01, 0x3C, 0x0B, 0xE4, 0x74, 0x3C, 0x03, 0xE4, 0xDC, 0x3C, 0x13, 0xE4, 0xDB, + 0x40, 0x00, 0x24, 0x0C, 0x88, 0x01, 0x3C, 0x0B, 0xE4, 0xDD, 0x49, 0xFF, 0x9E, 0xFB, 0x3C, 0x0F, + 0xFB, 0x67, 0x49, 0xFF, 0x9E, 0xCF, 0x44, 0x02, 0xD5, 0xF0, 0x3C, 0x0E, 0x02, 0xD9, 0x44, 0x02, + 0xB6, 0x54, 0x3C, 0x0F, 0xFB, 0x6A, 0x3E, 0x67, 0xED, 0xA1, 0x3E, 0x67, 0xED, 0xA0, 0x3E, 0x67, + 0xED, 0xA2, 0x3E, 0x60, 0x0B, 0x60, 0x3C, 0x7E, 0x02, 0xDA, 0x80, 0x07, 0x84, 0x7F, 0x3C, 0x1D, + 0xFB, 0x67, 0x38, 0x30, 0x9C, 0x08, 0x3C, 0x1D, 0xFB, 0x67, 0x38, 0x20, 0x9C, 0x00, 0x8C, 0xE1, + 0x88, 0x02, 0x96, 0x00, 0x5A, 0x78, 0x40, 0xF5, 0xFE, 0x02, 0x10, 0x00, 0x80, 0x40, 0x84, 0x00, + 0x3C, 0x0E, 0x01, 0x87, 0x3C, 0x0E, 0x01, 0x88, 0x3E, 0x00, 0x06, 0x30, 0x3E, 0x00, 0x06, 0x2F, + 0x3E, 0x00, 0x06, 0x31, 0x3E, 0x00, 0x06, 0x32, 0x3E, 0x07, 0xED, 0x24, 0x3E, 0x07, 0xED, 0x26, + 0x3E, 0x07, 0xED, 0x25, 0x44, 0x12, 0xD0, 0x04, 0x84, 0x5F, 0x38, 0x20, 0x81, 0x09, 0x8C, 0x01, + 0x5A, 0x08, 0x14, 0xFD, 0x84, 0xC0, 0x3E, 0x67, 0xEC, 0x75, 0x3E, 0x67, 0xEC, 0x31, 0x3E, 0x67, + 0xEC, 0x58, 0x3E, 0x67, 0xEC, 0x49, 0x3E, 0x67, 0xEC, 0x5B, 0x3E, 0x67, 0xEC, 0x10, 0x3E, 0x67, + 0xEC, 0x42, 0x3E, 0x67, 0xEC, 0x73, 0x3E, 0x67, 0xEC, 0x52, 0x3E, 0x67, 0xEC, 0x1B, 0x3E, 0x67, + 0xEC, 0x7B, 0x3E, 0x67, 0xEC, 0x7A, 0x3E, 0x67, 0xEC, 0x39, 0x3E, 0x60, 0x06, 0x35, 0x49, 0xFF, + 0xDE, 0x7F, 0x44, 0x10, 0x00, 0x64, 0x3C, 0x18, 0x05, 0x70, 0x44, 0x10, 0x00, 0x5A, 0x3C, 0x18, + 0x05, 0x72, 0x44, 0x10, 0x00, 0x96, 0x84, 0x00, 0x3C, 0x18, 0x05, 0x73, 0x3C, 0x18, 0x05, 0x78, + 0xFA, 0x38, 0xFA, 0x49, 0x3C, 0x08, 0x05, 0x71, 0x3C, 0x08, 0x05, 0x74, 0x3C, 0x08, 0x05, 0x75, + 0x3C, 0x08, 0x05, 0x77, 0x3C, 0x18, 0x05, 0x79, 0x3C, 0x08, 0x05, 0x7A, 0x84, 0x25, 0x3C, 0x08, + 0x05, 0x7C, 0x3E, 0x07, 0xEC, 0x24, 0x44, 0x02, 0x7B, 0x70, 0x3C, 0x28, 0x05, 0x76, 0x3C, 0x18, + 0x05, 0x7B, 0x3E, 0x60, 0x06, 0x33, 0x3E, 0x60, 0x0A, 0xDD, 0x3E, 0x60, 0x0A, 0xDE, 0x3E, 0x67, + 0xEC, 0x47, 0x3E, 0x67, 0xEC, 0x27, 0x3E, 0x67, 0xEC, 0x6B, 0x49, 0xFF, 0xAD, 0x91, 0x84, 0x00, + 0x44, 0x12, 0xD0, 0x84, 0x84, 0x41, 0x38, 0x20, 0x80, 0x08, 0x8C, 0x01, 0x5A, 0x08, 0x0A, 0xFD, + 0x2E, 0x07, 0xC7, 0x54, 0x5A, 0x08, 0x01, 0x04, 0x49, 0xFF, 0xB1, 0x19, 0x84, 0x01, 0x84, 0xC0, + 0x3E, 0x00, 0x06, 0x2E, 0x3E, 0x07, 0xEC, 0x4C, 0x44, 0x02, 0xD3, 0x40, 0x49, 0xFF, 0xF2, 0x9A, + 0x49, 0xFF, 0xF2, 0x93, 0x3E, 0x67, 0xEC, 0x55, 0x3E, 0x67, 0xEC, 0x0C, 0x49, 0xFF, 0xDF, 0xCE, + 0xFA, 0x04, 0x3E, 0x07, 0xEC, 0x79, 0x84, 0x00, 0x3C, 0x0B, 0xF6, 0x51, 0x3C, 0x0B, 0xF6, 0x5D, + 0x3E, 0x07, 0xEC, 0x18, 0x84, 0x00, 0x3E, 0x60, 0x05, 0xA1, 0x3E, 0x67, 0xEC, 0x3B, 0x44, 0x12, + 0xDE, 0xB0, 0x80, 0x40, 0x38, 0x20, 0x81, 0x09, 0x8C, 0x01, 0x5A, 0x08, 0x1E, 0xFD, 0x44, 0x52, + 0x2E, 0x00, 0x84, 0x20, 0x44, 0x02, 0x2F, 0x00, 0xAA, 0x69, 0xD8, 0xFF, 0xEC, 0x04, 0x3A, 0x6F, + 0xAA, 0x84, 0xDD, 0x9E, 0x3A, 0x6F, 0x9C, 0xBC, 0x44, 0x62, 0x90, 0x28, 0xEF, 0xF4, 0x80, 0x06, + 0x49, 0xFF, 0xCA, 0x4B, 0x50, 0x03, 0x7F, 0x48, 0xF0, 0x81, 0x49, 0x00, 0x15, 0x16, 0x9C, 0x34, + 0x49, 0x00, 0x15, 0x16, 0x50, 0x03, 0x00, 0x78, 0x49, 0x00, 0x1A, 0x33, 0x50, 0x03, 0x00, 0xA8, + 0x49, 0x00, 0x15, 0x11, 0x50, 0x03, 0x00, 0xCC, 0x49, 0xFF, 0x95, 0xC4, 0x50, 0x03, 0x7F, 0x48, + 0xF0, 0x81, 0x49, 0xFF, 0x95, 0xC2, 0x50, 0x03, 0x00, 0xB0, 0x49, 0xFF, 0xE2, 0xD9, 0x50, 0x03, + 0x7F, 0x48, 0xF0, 0x81, 0x49, 0xFF, 0xE2, 0xD7, 0x50, 0x03, 0x7F, 0x48, 0xF0, 0x81, 0x49, 0xFF, + 0xD5, 0xC0, 0x50, 0x03, 0x01, 0x18, 0x49, 0xFF, 0xFB, 0x25, 0x50, 0x03, 0x7F, 0x48, 0xF0, 0x81, + 0x49, 0xFF, 0xFB, 0x23, 0x49, 0xFF, 0xFB, 0x3F, 0x50, 0x03, 0x01, 0x2C, 0x49, 0xFF, 0xD6, 0x6D, + 0x50, 0x73, 0x03, 0xB8, 0x50, 0x03, 0x7F, 0x48, 0xF0, 0x81, 0x49, 0xFF, 0xD6, 0x69, 0x80, 0x07, + 0x49, 0xFF, 0xD6, 0x69, 0x50, 0x03, 0x7F, 0x48, 0xF0, 0x81, 0x49, 0xFF, 0xAC, 0x16, 0x50, 0x03, + 0x01, 0x70, 0x49, 0xFF, 0xAA, 0xC2, 0x50, 0x03, 0x03, 0x18, 0x49, 0xFF, 0x98, 0x57, 0x50, 0x03, + 0x7F, 0x48, 0xF0, 0x81, 0x49, 0xFF, 0x98, 0x55, 0x50, 0x03, 0x03, 0x64, 0x49, 0xFF, 0x97, 0x17, + 0x50, 0x03, 0x7F, 0x48, 0xF0, 0x81, 0x49, 0xFF, 0x97, 0x15, 0x50, 0x03, 0x03, 0x74, 0x49, 0xFF, + 0xA0, 0xF5, 0x50, 0x03, 0x7F, 0x48, 0xF0, 0x81, 0x49, 0xFF, 0xA0, 0xF3, 0x80, 0x07, 0x49, 0xFF, + 0x9D, 0x83, 0x50, 0x03, 0x7F, 0x48, 0xF0, 0x81, 0x49, 0xFF, 0x9D, 0x81, 0x3C, 0x0D, 0xFB, 0x4D, + 0x49, 0xFF, 0xCA, 0xE8, 0x50, 0x03, 0x03, 0xE8, 0x49, 0x00, 0x23, 0x70, 0x50, 0x03, 0x7F, 0x48, + 0xF0, 0x81, 0x49, 0x00, 0x23, 0x6E, 0x50, 0x03, 0x00, 0x48, 0x49, 0xFF, 0xB3, 0x7B, 0x50, 0x03, + 0x7F, 0x48, 0xF0, 0x81, 0x49, 0xFF, 0xEF, 0xF1, 0x50, 0x03, 0x7F, 0x48, 0xF0, 0x81, 0xEC, 0x0C, + 0x3A, 0x6F, 0x9C, 0x84, 0x48, 0xFF, 0xDD, 0x71, 0x44, 0x00, 0x00, 0xA2, 0x3A, 0x6F, 0x98, 0xBC, + 0x49, 0x00, 0x1D, 0xB5, 0x3C, 0x0D, 0xFB, 0x4A, 0xA6, 0x01, 0x5A, 0x08, 0x0C, 0x12, 0x84, 0x00, + 0x84, 0x7F, 0x3C, 0x2D, 0xFB, 0x67, 0x84, 0x3F, 0x38, 0x31, 0x00, 0x08, 0x8C, 0x06, 0x5A, 0x08, + 0x3C, 0xFA, 0x3C, 0x0D, 0xFB, 0x67, 0x10, 0x10, 0x00, 0x3C, 0x10, 0x10, 0x00, 0x3D, 0x49, 0xFF, + 0xFA, 0xAF, 0x3E, 0x00, 0x06, 0x11, 0x2E, 0x07, 0xC6, 0xC3, 0x84, 0xC0, 0x52, 0x00, 0x00, 0x01, + 0x3E, 0x67, 0xEC, 0x0A, 0x49, 0xFF, 0xF1, 0x9A, 0x84, 0x01, 0x3E, 0x07, 0xEC, 0x2C, 0x3E, 0x07, + 0xEC, 0x4E, 0x3E, 0x07, 0xEC, 0x0F, 0x3E, 0x67, 0xEC, 0x59, 0x3E, 0x67, 0xEC, 0x0C, 0x3E, 0x60, + 0x06, 0x12, 0x49, 0xFF, 0xE2, 0x4A, 0x2E, 0x07, 0xC7, 0x54, 0x3E, 0x67, 0xEC, 0x6E, 0x5A, 0x08, + 0x01, 0x06, 0x3A, 0x6F, 0x98, 0x84, 0x48, 0xFF, 0xC7, 0x90, 0x3A, 0x6F, 0x98, 0x84, 0xDD, 0x9E, + 0x3A, 0x6F, 0xA6, 0xBC, 0xEF, 0xE0, 0x44, 0x01, 0x32, 0x74, 0xB1, 0xC4, 0x3A, 0x20, 0x14, 0x00, + 0x44, 0x01, 0x32, 0x84, 0x3A, 0x2F, 0x94, 0x20, 0x3A, 0x20, 0x14, 0x00, 0x2E, 0x07, 0xC7, 0x54, + 0x81, 0x3F, 0x3A, 0x23, 0x94, 0x20, 0x5A, 0x08, 0x01, 0x38, 0x2E, 0x60, 0x06, 0x09, 0xCE, 0x25, + 0x2E, 0x07, 0xEC, 0x66, 0x49, 0xFF, 0xF3, 0x63, 0x5A, 0x08, 0x01, 0x0D, 0x2E, 0x07, 0xEC, 0x54, + 0x5A, 0x08, 0x01, 0x09, 0x3E, 0x07, 0xEC, 0x0C, 0x49, 0xFF, 0xAB, 0xE2, 0xC0, 0xFE, 0x84, 0x02, + 0xD5, 0x37, 0x38, 0x04, 0x9A, 0x02, 0x38, 0x13, 0x9A, 0x02, 0x8C, 0xC1, 0x49, 0xFF, 0xF3, 0x9D, + 0x5A, 0x68, 0x04, 0xF9, 0x49, 0xFF, 0xC5, 0x40, 0x5A, 0x08, 0x02, 0x04, 0x49, 0xFF, 0xCF, 0xEA, + 0x84, 0x01, 0x3E, 0x07, 0xEC, 0x35, 0xD5, 0x10, 0x2E, 0x07, 0xEC, 0x35, 0xC8, 0x0D, 0x2E, 0x07, + 0xEC, 0x55, 0x49, 0xFF, 0xF3, 0x6B, 0x2E, 0x17, 0xEC, 0x55, 0x38, 0x0F, 0x86, 0x02, 0x38, 0x13, + 0x86, 0x02, 0x49, 0xFF, 0xF3, 0x82, 0x44, 0x02, 0x1B, 0x90, 0x44, 0x12, 0x45, 0x10, 0x49, 0xFF, + 0xF3, 0x7C, 0x84, 0xC1, 0x44, 0x02, 0x1B, 0x90, 0x44, 0x12, 0x40, 0x00, 0x3E, 0x67, 0xEC, 0x4C, + 0x49, 0xFF, 0xF3, 0x73, 0x3E, 0x67, 0xEC, 0x3F, 0x3E, 0x67, 0xEC, 0x7E, 0x84, 0x01, 0xEC, 0x20, + 0x3A, 0x6F, 0xA6, 0x84, 0xDD, 0x9E, 0x44, 0x02, 0x51, 0x9B, 0x44, 0x12, 0x51, 0x9A, 0xA6, 0x00, + 0xA6, 0x48, 0x40, 0x00, 0x20, 0x08, 0xFE, 0x0F, 0xDD, 0x9E, 0x44, 0x02, 0x51, 0x9D, 0x44, 0x12, + 0x51, 0x9C, 0xA6, 0x00, 0xA6, 0x48, 0x40, 0x00, 0x20, 0x08, 0xFE, 0x0F, 0x44, 0x1F, 0xAE, 0x60, + 0x88, 0x20, 0x5C, 0xF0, 0x80, 0x5A, 0xE9, 0x03, 0x44, 0x00, 0x51, 0xA0, 0xDD, 0x9E, 0x44, 0x02, + 0x51, 0x98, 0xA6, 0x00, 0x92, 0x01, 0x96, 0x06, 0xDD, 0x9E, 0x44, 0x02, 0x51, 0x98, 0xA6, 0x00, + 0x92, 0x02, 0x96, 0x06, 0xDD, 0x9E, 0x44, 0x02, 0x51, 0x99, 0xA6, 0x00, 0xDD, 0x9E, 0x44, 0x12, + 0x51, 0x9E, 0xA6, 0x08, 0x96, 0x00, 0xC0, 0x0E, 0xA6, 0x08, 0x96, 0x00, 0x5A, 0x00, 0x01, 0x0B, + 0xA6, 0x08, 0x96, 0x00, 0x5A, 0x00, 0x02, 0x07, 0xA6, 0x08, 0x96, 0x00, 0x5A, 0x00, 0x03, 0x03, + 0x84, 0x00, 0xDD, 0x9E, 0x44, 0x12, 0x51, 0x9F, 0x96, 0x00, 0xAE, 0x08, 0xDD, 0x9E, 0xFC, 0x00, + 0x44, 0x62, 0x51, 0x98, 0xAE, 0x70, 0x44, 0x12, 0xD5, 0x74, 0xB6, 0x01, 0x84, 0x01, 0xA9, 0x89, + 0x10, 0x20, 0x80, 0x09, 0x10, 0x00, 0x80, 0x08, 0x10, 0x30, 0x80, 0x0A, 0x10, 0x00, 0x80, 0x0B, + 0x80, 0x01, 0x80, 0x24, 0x49, 0xFF, 0xC3, 0xDE, 0xA6, 0x30, 0xFC, 0x80, 0xFC, 0x00, 0x84, 0x41, + 0x84, 0x20, 0x80, 0x62, 0x80, 0x82, 0x44, 0x00, 0xB1, 0x00, 0x49, 0xFF, 0xFF, 0xE2, 0x84, 0x00, + 0x3C, 0x0F, 0xFB, 0x79, 0x3E, 0x00, 0x05, 0xF9, 0xFC, 0x80, 0x3A, 0x6F, 0xAA, 0xBC, 0xEF, 0xDC, + 0x84, 0x80, 0xF0, 0x86, 0x3C, 0x0D, 0xFB, 0x4D, 0xF1, 0x87, 0xF0, 0x83, 0x3C, 0x00, 0x05, 0x3E, + 0xB6, 0x83, 0xF0, 0x84, 0x2E, 0x07, 0xC6, 0xC1, 0xE2, 0x80, 0x4E, 0xF2, 0x00, 0x89, 0x44, 0x00, + 0x00, 0xE0, 0xF7, 0x06, 0x42, 0x72, 0x00, 0x73, 0xB4, 0x07, 0x8E, 0x01, 0xE6, 0x03, 0xE8, 0x7B, + 0xF0, 0x03, 0x03, 0xE3, 0x80, 0x1F, 0xA4, 0x00, 0x92, 0x02, 0x96, 0x06, 0x5A, 0x00, 0x01, 0x08, + 0x40, 0x0F, 0x04, 0x09, 0x8E, 0x0A, 0x40, 0x80, 0x00, 0x13, 0xD5, 0x03, 0x04, 0x8F, 0x80, 0x04, + 0xF0, 0x07, 0xA1, 0x7E, 0x84, 0xC0, 0xA0, 0x05, 0x95, 0x6A, 0x88, 0xA0, 0xA6, 0x2A, 0xB6, 0x1F, + 0xA6, 0x2B, 0xB5, 0x3F, 0xF0, 0x81, 0xF0, 0x01, 0xA6, 0x69, 0xE2, 0x09, 0xF1, 0x82, 0xA6, 0x28, + 0xE9, 0x1B, 0x40, 0x14, 0x90, 0x08, 0xF1, 0x85, 0x85, 0x40, 0xF1, 0x02, 0xE2, 0x20, 0xE9, 0x0C, + 0xF1, 0x05, 0x40, 0xF0, 0x80, 0x00, 0x39, 0xC1, 0x3D, 0x11, 0xE1, 0x1C, 0xE8, 0x02, 0x89, 0x5C, + 0x8C, 0x01, 0x96, 0x00, 0xD5, 0xF3, 0xE2, 0xCA, 0x50, 0x04, 0x80, 0x01, 0x40, 0x65, 0x3C, 0x1B, + 0x54, 0x90, 0x00, 0xFF, 0xD5, 0xE1, 0x84, 0xA0, 0xF1, 0x02, 0xE2, 0x20, 0xE9, 0x19, 0xB5, 0x3F, + 0x85, 0x40, 0xF1, 0x01, 0xE2, 0x29, 0xE9, 0x0E, 0x40, 0xF4, 0x90, 0x08, 0x40, 0xF7, 0x80, 0x00, + 0x39, 0xC1, 0x3D, 0x11, 0xE1, 0x1C, 0xE8, 0x02, 0x89, 0x5C, 0x8D, 0x21, 0x54, 0x94, 0x80, 0xFF, + 0xD5, 0xF1, 0xE2, 0xAA, 0x8C, 0x01, 0x40, 0x55, 0x3C, 0x1B, 0x96, 0x00, 0xD5, 0xE6, 0x44, 0x00, + 0x01, 0xA1, 0xFF, 0x44, 0x44, 0x00, 0x01, 0xA6, 0xFF, 0x84, 0xE2, 0xA6, 0x40, 0x62, 0xBC, 0x1A, + 0x40, 0x0F, 0x04, 0x09, 0x88, 0x06, 0x40, 0x00, 0x78, 0x17, 0x50, 0x00, 0x00, 0x32, 0x44, 0x10, + 0x00, 0x64, 0x40, 0x00, 0x04, 0x17, 0x96, 0x01, 0xE6, 0x1A, 0x80, 0xC0, 0xE9, 0x02, 0xFA, 0xC9, + 0x04, 0x03, 0x80, 0x08, 0xB4, 0xA3, 0x12, 0x63, 0x80, 0x08, 0xE2, 0x05, 0x12, 0x63, 0x80, 0x09, + 0xE9, 0x02, 0xB6, 0x03, 0x8C, 0x81, 0x97, 0x20, 0x48, 0xFF, 0xFF, 0x76, 0xEC, 0x24, 0x3A, 0x6F, + 0xAA, 0x84, 0xDD, 0x9E, 0xA4, 0x40, 0x92, 0x21, 0x96, 0x46, 0x5A, 0x18, 0x01, 0x08, 0xA4, 0x80, + 0x96, 0x86, 0xCA, 0x04, 0x3C, 0x1E, 0x01, 0x4A, 0xDD, 0x9E, 0xA4, 0x40, 0x92, 0x21, 0x96, 0x46, + 0x5A, 0x18, 0x01, 0x08, 0xA4, 0x00, 0x96, 0x06, 0x5A, 0x08, 0x01, 0x04, 0x84, 0x02, 0xD5, 0x02, + 0x84, 0x00, 0x3C, 0x0E, 0x01, 0x4A, 0xDD, 0x9E, 0xFC, 0x02, 0x80, 0xA1, 0xF2, 0x81, 0xB4, 0x21, + 0xA0, 0xA9, 0xF3, 0x82, 0xF4, 0x83, 0x49, 0xFF, 0xC6, 0x74, 0x84, 0x01, 0xF1, 0x01, 0x49, 0xFF, + 0xC6, 0x94, 0xF0, 0x02, 0x49, 0xFF, 0xC6, 0xA4, 0x84, 0xC0, 0x80, 0x06, 0x84, 0x20, 0x49, 0xFF, + 0xC6, 0xAD, 0x80, 0x06, 0xF1, 0x03, 0x8C, 0xC1, 0x49, 0xFF, 0xC6, 0xD0, 0x5A, 0x68, 0x08, 0xF7, + 0x84, 0x00, 0x49, 0xFF, 0xC6, 0x99, 0x49, 0xFF, 0xC6, 0x6F, 0x84, 0x01, 0x49, 0xFF, 0xC6, 0x94, + 0x49, 0xFF, 0xC6, 0x6A, 0x84, 0x03, 0x49, 0xFF, 0xC6, 0x8F, 0x49, 0xFF, 0xC6, 0x65, 0x49, 0xFF, + 0xC6, 0x83, 0xFC, 0x82, 0xFC, 0x40, 0xAE, 0x88, 0x84, 0x40, 0xA7, 0x08, 0xE2, 0x44, 0xE8, 0x1A, + 0xA1, 0x01, 0x38, 0x52, 0x09, 0x01, 0xD2, 0x14, 0xA1, 0x05, 0x95, 0x92, 0x95, 0x6A, 0x99, 0xE6, + 0x88, 0x85, 0xA7, 0xFA, 0x00, 0xF2, 0x00, 0x02, 0xE2, 0xEF, 0xE8, 0x02, 0xAF, 0xE2, 0xA1, 0xC5, + 0x88, 0xC7, 0x88, 0xA7, 0xA7, 0x33, 0xA7, 0xAB, 0xE2, 0xC4, 0xE8, 0x02, 0xAF, 0x2B, 0x8C, 0x41, + 0xD5, 0xE5, 0x9D, 0xD9, 0x84, 0xA0, 0x92, 0xE1, 0x50, 0x60, 0x80, 0x25, 0x81, 0x25, 0xD7, 0x36, + 0xA6, 0x88, 0xE2, 0xA2, 0xE8, 0x2E, 0xA0, 0x81, 0x38, 0x21, 0x15, 0x01, 0x4C, 0x22, 0xC0, 0x2A, + 0x50, 0xF0, 0x00, 0x14, 0xB5, 0x0F, 0x94, 0xAA, 0x89, 0x02, 0x99, 0x0D, 0x00, 0xA4, 0x00, 0x03, + 0x00, 0x84, 0x00, 0x02, 0x8D, 0x41, 0x8B, 0x48, 0x10, 0xA2, 0x00, 0x25, 0xB5, 0x4F, 0x89, 0x42, + 0x00, 0xA5, 0x00, 0x02, 0x10, 0xA2, 0x00, 0x37, 0xB5, 0x4F, 0x88, 0x4A, 0xA6, 0x93, 0x10, 0x22, + 0x00, 0x49, 0xA0, 0x83, 0x38, 0xA1, 0x15, 0x01, 0x50, 0x22, 0x80, 0x34, 0x94, 0x91, 0x88, 0x41, + 0x12, 0xA1, 0x00, 0x03, 0xA0, 0x84, 0x38, 0x21, 0x15, 0x00, 0x10, 0x22, 0x00, 0x5B, 0xD5, 0x03, + 0x10, 0x93, 0x00, 0x00, 0x8C, 0xA1, 0x8C, 0xC1, 0xD5, 0xCB, 0x8C, 0x21, 0x84, 0xA0, 0x84, 0x9F, + 0xD3, 0x0F, 0xB4, 0x40, 0x38, 0x21, 0x15, 0x00, 0x5A, 0x28, 0xFF, 0x04, 0xAF, 0x08, 0xD5, 0x05, + 0xA1, 0x81, 0x38, 0x23, 0x09, 0x01, 0xAE, 0x88, 0x8C, 0xA1, 0x8C, 0x21, 0xD5, 0xF2, 0xFC, 0xC0, + 0xFC, 0x4A, 0x2E, 0x77, 0xC6, 0xBB, 0xE6, 0x5F, 0x81, 0x20, 0xB6, 0x3F, 0x2E, 0x67, 0xC6, 0xBA, + 0x50, 0xA3, 0xFF, 0xFF, 0xE9, 0x09, 0xFA, 0x0E, 0x3C, 0x0B, 0xF6, 0x46, 0x40, 0x83, 0x04, 0x08, + 0x80, 0x29, 0x84, 0x00, 0xD5, 0x04, 0x3C, 0x2B, 0xF6, 0x46, 0xD5, 0xF9, 0xE2, 0x07, 0xE8, 0x08, + 0xB0, 0xC2, 0x38, 0x20, 0xA0, 0x05, 0x38, 0x21, 0x81, 0x09, 0x8C, 0x01, 0xD5, 0xF8, 0xB4, 0x3F, + 0x80, 0x47, 0x3C, 0x33, 0xF6, 0x46, 0x44, 0x40, 0x00, 0x55, 0xB0, 0x02, 0x49, 0xFF, 0xFF, 0x3E, + 0xF0, 0x81, 0x44, 0x12, 0xCD, 0x4C, 0xB4, 0x1F, 0xF2, 0x01, 0x80, 0x67, 0x49, 0xFF, 0xFF, 0x64, + 0x40, 0x14, 0xA0, 0x00, 0x84, 0x00, 0xE2, 0x07, 0xE8, 0x09, 0x02, 0x20, 0xFF, 0xFF, 0xB0, 0xC2, + 0x88, 0x28, 0x38, 0x21, 0x81, 0x09, 0x8C, 0x01, 0xD5, 0xF7, 0xB4, 0x3F, 0x80, 0x47, 0x3C, 0x33, + 0xF6, 0x46, 0x44, 0x40, 0x00, 0x55, 0xB0, 0x02, 0x49, 0xFF, 0xFF, 0x20, 0xF0, 0x81, 0x44, 0x12, + 0xCC, 0xB8, 0xB4, 0x1F, 0xF2, 0x01, 0x80, 0x67, 0x49, 0xFF, 0xFF, 0x46, 0x84, 0x00, 0xE2, 0x06, + 0xE8, 0x08, 0x38, 0x14, 0x81, 0x01, 0xB0, 0x82, 0x38, 0x11, 0x01, 0x09, 0x8C, 0x01, 0xD5, 0xF8, + 0xB4, 0x3F, 0x80, 0x46, 0x3C, 0x33, 0xF6, 0x46, 0x44, 0x40, 0x00, 0x32, 0xB0, 0x02, 0x49, 0xFF, + 0xFF, 0x05, 0xF0, 0x81, 0x44, 0x12, 0xCC, 0x24, 0xB4, 0x1F, 0xF2, 0x01, 0x80, 0x66, 0x49, 0xFF, + 0xFF, 0x2B, 0x42, 0x94, 0x28, 0x73, 0x84, 0x00, 0xE2, 0x06, 0xE8, 0x08, 0x38, 0x14, 0x81, 0x01, + 0xB0, 0x82, 0x38, 0x11, 0x01, 0x09, 0x8C, 0x01, 0xD5, 0xF8, 0xB4, 0x3F, 0x80, 0x46, 0x44, 0x40, + 0x00, 0x32, 0xB0, 0x02, 0x3C, 0x33, 0xF6, 0x46, 0x49, 0xFF, 0xFE, 0xE8, 0xF0, 0x81, 0x44, 0x12, + 0xCB, 0x90, 0xB4, 0x1F, 0xF2, 0x01, 0x80, 0x66, 0x49, 0xFF, 0xFF, 0x0E, 0xFC, 0xCA, 0xFC, 0x46, + 0x83, 0xC0, 0x2E, 0x07, 0xC6, 0xBA, 0xF3, 0x85, 0xF4, 0x86, 0xF0, 0x81, 0x2E, 0xA7, 0xC6, 0xBB, + 0xC9, 0x07, 0x40, 0x60, 0x88, 0x06, 0x84, 0x01, 0xC2, 0x09, 0x84, 0xFF, 0xD5, 0x08, 0xC2, 0x04, + 0x84, 0xC3, 0x84, 0x1F, 0xD5, 0xFB, 0x84, 0xC2, 0x84, 0x1F, 0x84, 0xE1, 0xF3, 0x01, 0xFE, 0xD4, + 0x80, 0x83, 0x88, 0x81, 0x95, 0x21, 0xF3, 0x84, 0x40, 0x3F, 0x10, 0x00, 0x3C, 0x43, 0xF6, 0x46, + 0x22, 0x91, 0x80, 0x00, 0xF3, 0x87, 0xE0, 0x89, 0x4E, 0xF2, 0x00, 0xF5, 0x97, 0x10, 0xF4, 0x88, + 0x97, 0x08, 0xF4, 0x89, 0xF3, 0x08, 0xF4, 0x05, 0x88, 0x83, 0xA6, 0xE1, 0xF3, 0x8A, 0xF4, 0x0A, + 0xF3, 0x05, 0x88, 0x83, 0x20, 0x32, 0x00, 0x25, 0xF4, 0x09, 0xF3, 0x82, 0xF3, 0x06, 0x88, 0x83, + 0xA6, 0xE1, 0xF3, 0x8B, 0xF4, 0x0B, 0xF3, 0x06, 0x88, 0x83, 0x20, 0x32, 0x00, 0x25, 0x38, 0x42, + 0x98, 0x00, 0xF3, 0x83, 0xC4, 0x04, 0x84, 0x84, 0x38, 0x42, 0x98, 0x08, 0xF3, 0x02, 0x42, 0x93, + 0x88, 0x24, 0xE0, 0x6A, 0xE9, 0x03, 0xF3, 0x02, 0x8E, 0x61, 0x89, 0x23, 0xF3, 0x01, 0x42, 0x43, + 0x88, 0x24, 0xFE, 0xFC, 0x04, 0x8F, 0x80, 0x01, 0x8C, 0x81, 0x41, 0xC1, 0x84, 0x08, 0x81, 0x41, + 0x42, 0x32, 0x1C, 0x24, 0x42, 0xA1, 0xA0, 0x73, 0x80, 0x6A, 0x94, 0xD9, 0x85, 0x00, 0x40, 0xAF, + 0x0C, 0x00, 0xB7, 0x1F, 0xE1, 0x24, 0xE9, 0x0B, 0x38, 0xF5, 0x20, 0x11, 0x4E, 0xF7, 0x00, 0x05, + 0xB4, 0x7F, 0x88, 0x6F, 0xB6, 0x7F, 0x8C, 0x81, 0x89, 0x1C, 0xD5, 0xF5, 0xB4, 0x7F, 0xCB, 0x03, + 0x84, 0x61, 0xB6, 0x7F, 0xF3, 0x03, 0xF4, 0x01, 0x42, 0xA0, 0x04, 0x24, 0xE0, 0x64, 0xE8, 0x03, + 0x89, 0x43, 0xD5, 0x04, 0xF4, 0x03, 0x8E, 0x81, 0x89, 0x44, 0x95, 0x01, 0x42, 0x90, 0x04, 0x24, + 0x8D, 0x21, 0x80, 0x64, 0xF4, 0x04, 0x42, 0x44, 0x80, 0x73, 0x95, 0x21, 0x87, 0x80, 0x40, 0x8F, + 0x10, 0x00, 0x80, 0x9C, 0xE1, 0x49, 0xE9, 0x0A, 0x38, 0xF4, 0x70, 0x11, 0x4E, 0xF7, 0x00, 0x03, + 0x88, 0x8F, 0x8D, 0x21, 0x41, 0xCE, 0x0C, 0x00, 0xD5, 0xF6, 0xCC, 0x02, 0x84, 0x81, 0xF3, 0x01, + 0x88, 0x47, 0xFE, 0x9C, 0x40, 0x80, 0x80, 0x00, 0x40, 0x91, 0x20, 0x00, 0x85, 0x4A, 0x39, 0xCF, + 0x25, 0x11, 0x3C, 0xFC, 0x01, 0x4A, 0xE9, 0x1F, 0xB4, 0x3F, 0xF2, 0x05, 0x42, 0x30, 0xA8, 0x24, + 0xF1, 0x0A, 0x40, 0x31, 0x90, 0x76, 0x50, 0x10, 0x80, 0x34, 0x94, 0x49, 0x88, 0x41, 0x44, 0x90, + 0x00, 0x5A, 0xA5, 0x13, 0xF2, 0x04, 0x44, 0x10, 0x00, 0x50, 0x88, 0x48, 0xFF, 0x0C, 0x42, 0x9E, + 0x24, 0x24, 0x44, 0x10, 0x00, 0x64, 0x40, 0x42, 0x04, 0x96, 0x38, 0x2F, 0x09, 0x11, 0x40, 0x94, + 0x85, 0x36, 0xD5, 0x20, 0xB4, 0x7F, 0x42, 0x42, 0x28, 0x24, 0x40, 0x32, 0x0C, 0x76, 0xF4, 0x0B, + 0x04, 0x9F, 0x80, 0x06, 0x50, 0x42, 0x00, 0x34, 0x95, 0x21, 0x89, 0x24, 0x88, 0x22, 0x02, 0xF4, + 0x80, 0x03, 0x44, 0x40, 0x00, 0x50, 0x38, 0x2F, 0x05, 0x11, 0x44, 0x10, 0x00, 0x5A, 0x44, 0x90, + 0x00, 0x64, 0x42, 0x47, 0x90, 0x24, 0x42, 0x1E, 0x04, 0x24, 0x40, 0x42, 0x24, 0x96, 0x40, 0x90, + 0xA5, 0x36, 0xF1, 0x07, 0x22, 0xF0, 0x80, 0x00, 0xE0, 0x8F, 0xE8, 0x40, 0xF1, 0x02, 0xE4, 0x23, + 0xE8, 0x04, 0xF1, 0x03, 0xE4, 0x23, 0xE9, 0x3A, 0xE1, 0x22, 0xE8, 0x38, 0xE4, 0x75, 0x38, 0x32, + 0x98, 0x00, 0xE8, 0x03, 0x5A, 0x38, 0x04, 0x33, 0xF1, 0x03, 0xF2, 0x09, 0x8E, 0x21, 0x42, 0x20, + 0x04, 0x73, 0x96, 0x52, 0xF2, 0x02, 0xF4, 0x08, 0x8E, 0x41, 0x42, 0x43, 0x88, 0x73, 0x85, 0x24, + 0x96, 0xA2, 0x38, 0x92, 0x98, 0x08, 0x99, 0x2E, 0xCB, 0x03, 0xAE, 0xA4, 0xD5, 0x10, 0x20, 0x32, + 0x00, 0x04, 0x42, 0xF3, 0x88, 0x24, 0xFF, 0xDC, 0xE0, 0xEF, 0xE8, 0x02, 0xAE, 0xA4, 0x20, 0x22, + 0x00, 0x08, 0x42, 0xF0, 0x04, 0x24, 0xFE, 0x14, 0xE0, 0x0F, 0xE8, 0x10, 0x10, 0x12, 0x00, 0x08, + 0xD5, 0x0D, 0x8E, 0x84, 0xE1, 0x24, 0x38, 0x02, 0x98, 0x00, 0xE8, 0x04, 0xC0, 0x07, 0x8E, 0x01, + 0xD5, 0x03, 0xC0, 0x04, 0x84, 0x04, 0x38, 0x02, 0x98, 0x08, 0xFC, 0xC6, 0xFC, 0x46, 0xF1, 0x89, + 0x2E, 0x17, 0xC6, 0xBB, 0x83, 0x83, 0xF1, 0x82, 0xF4, 0x8A, 0xF5, 0x8B, 0x2E, 0x37, 0xC6, 0xBA, + 0x84, 0x3F, 0xC8, 0x02, 0x84, 0x21, 0x94, 0xD9, 0x43, 0xE0, 0x80, 0x24, 0x3C, 0x43, 0xF6, 0x46, + 0xF3, 0x87, 0x42, 0x3F, 0x04, 0x24, 0xF3, 0x81, 0x8A, 0x60, 0x8E, 0x84, 0x94, 0xD9, 0xF4, 0x84, + 0xF3, 0x88, 0x95, 0x01, 0x85, 0x40, 0xF3, 0x02, 0xE1, 0x43, 0xE8, 0x62, 0xF3, 0x0A, 0x38, 0x31, + 0xA8, 0x00, 0x5A, 0x38, 0x01, 0x4D, 0xF3, 0x09, 0x88, 0x6A, 0xA6, 0xD9, 0x5A, 0x30, 0xFF, 0x34, + 0xB4, 0xBC, 0x38, 0x32, 0x90, 0x00, 0x5A, 0x30, 0xFF, 0x2F, 0xBE, 0x01, 0xBF, 0x05, 0xB6, 0xDF, + 0x38, 0x63, 0x0D, 0x01, 0x97, 0xAF, 0xC8, 0x05, 0x94, 0xF2, 0x88, 0x67, 0xA7, 0xD9, 0xD5, 0x03, + 0x38, 0x73, 0x9A, 0x00, 0x42, 0x33, 0x84, 0x24, 0xF3, 0x83, 0xF3, 0x08, 0x81, 0x3E, 0x88, 0x64, + 0x88, 0x65, 0xF3, 0x86, 0x84, 0xA0, 0x80, 0x60, 0xF7, 0x03, 0xE0, 0xE9, 0xE9, 0x15, 0xF7, 0x01, + 0x88, 0xE5, 0xF7, 0x85, 0xF7, 0x06, 0x38, 0xF3, 0x95, 0x00, 0xB4, 0xFF, 0x38, 0x83, 0xBD, 0x01, + 0x54, 0x84, 0x00, 0x3F, 0x4C, 0x83, 0x40, 0x05, 0x5A, 0xF0, 0xFF, 0x03, 0xF3, 0x05, 0x8D, 0x21, + 0x88, 0xA1, 0xD5, 0xEB, 0x80, 0x60, 0x20, 0x51, 0x00, 0x24, 0x42, 0x60, 0x8C, 0x24, 0xFF, 0x4C, + 0xE0, 0xC5, 0xE8, 0x09, 0xA7, 0x50, 0xE6, 0xA3, 0xE9, 0x03, 0x8E, 0xA1, 0xAF, 0x50, 0xA7, 0x50, + 0xE6, 0xA3, 0xE8, 0x11, 0x10, 0x31, 0x00, 0x24, 0x84, 0x64, 0xD5, 0x0C, 0xF3, 0x0B, 0x10, 0x01, + 0x00, 0x24, 0xF5, 0x04, 0x38, 0x31, 0x90, 0x11, 0xE0, 0x65, 0xE8, 0x05, 0xA6, 0xD0, 0xC3, 0x03, + 0x8E, 0x61, 0xAE, 0xD0, 0xF3, 0x07, 0x8D, 0x41, 0x8C, 0x41, 0x88, 0x83, 0xD5, 0x9D, 0xFC, 0xC6, + 0xFC, 0x42, 0x2E, 0xA7, 0xC6, 0xBA, 0xF2, 0x81, 0x2E, 0x77, 0xC6, 0xBB, 0xCD, 0x61, 0xB0, 0x83, + 0x81, 0x22, 0xB1, 0x81, 0xC0, 0x04, 0x51, 0xC0, 0x7F, 0xFF, 0xD5, 0x02, 0x83, 0x80, 0x9E, 0xBA, + 0xE2, 0x41, 0xE8, 0x03, 0x8E, 0xE1, 0xD5, 0x02, 0x9D, 0xC9, 0x44, 0x20, 0x00, 0x32, 0xFF, 0x14, + 0x44, 0x20, 0x00, 0x64, 0xF0, 0x83, 0x40, 0x42, 0x08, 0x97, 0x85, 0x00, 0xF5, 0x03, 0xE2, 0x25, + 0xE9, 0x10, 0x04, 0xF4, 0x80, 0x00, 0xB4, 0x46, 0x42, 0x25, 0x3C, 0x73, 0x38, 0xF1, 0x89, 0x11, + 0xE2, 0x8F, 0xE9, 0x03, 0xD0, 0x03, 0xD1, 0x02, 0x8D, 0x0A, 0x8C, 0xA1, 0xF5, 0x83, 0xD5, 0xEF, + 0xF0, 0x83, 0xB4, 0xA9, 0xB4, 0x46, 0x42, 0x25, 0x14, 0x73, 0x38, 0x21, 0x89, 0x11, 0x4E, 0x27, + 0x00, 0x04, 0xE2, 0x82, 0xE8, 0x02, 0x84, 0x40, 0x4C, 0x00, 0x80, 0x0F, 0xF1, 0x83, 0x04, 0xF4, + 0x80, 0x00, 0xB4, 0xA6, 0x42, 0x55, 0x3C, 0x73, 0x38, 0x51, 0x95, 0x11, 0x4E, 0x57, 0x00, 0x05, + 0xE2, 0x85, 0xE9, 0x02, 0x88, 0x45, 0x15, 0xCF, 0x80, 0x03, 0x4D, 0xC0, 0x00, 0x0C, 0xB4, 0xA9, + 0xB4, 0x06, 0x42, 0x05, 0x14, 0x73, 0x38, 0x01, 0x81, 0x11, 0xE4, 0x08, 0xE9, 0x03, 0x8E, 0x07, + 0x88, 0x40, 0xF7, 0x83, 0x4C, 0x70, 0x80, 0x12, 0xB4, 0x29, 0xB4, 0x06, 0x42, 0x05, 0x04, 0x73, + 0x38, 0x01, 0x81, 0x11, 0xE4, 0x08, 0xE9, 0x09, 0x8E, 0x07, 0x88, 0x40, 0xD5, 0x06, 0xB0, 0x81, + 0x80, 0xEA, 0x81, 0x22, 0xB1, 0x83, 0xD5, 0x9F, 0x84, 0x0A, 0xFE, 0x14, 0x40, 0x40, 0x10, 0x97, + 0x40, 0x02, 0x20, 0x00, 0xFC, 0xC2, 0xFC, 0x5E, 0xF0, 0x96, 0xF2, 0x81, 0x81, 0x01, 0xFA, 0x54, + 0x84, 0x20, 0xB0, 0x18, 0x49, 0x00, 0x26, 0xA4, 0x84, 0x20, 0xFA, 0x54, 0xB0, 0x21, 0x49, 0x00, + 0x26, 0x9F, 0x84, 0x20, 0xFA, 0x54, 0xB0, 0x2A, 0x49, 0x00, 0x26, 0x9A, 0xB0, 0x33, 0x84, 0x20, + 0xFA, 0x54, 0x49, 0x00, 0x26, 0x95, 0x2E, 0x07, 0xC6, 0xBB, 0x2E, 0x97, 0xC6, 0xBA, 0xF0, 0x8D, + 0x3C, 0x03, 0xE3, 0x65, 0xF0, 0x92, 0x2E, 0x07, 0xEB, 0xE0, 0x5C, 0xF0, 0x00, 0xC8, 0xE8, 0x04, + 0x8C, 0x01, 0x3E, 0x07, 0xEB, 0xE0, 0x2E, 0x07, 0xEB, 0xDF, 0x5C, 0xF0, 0x00, 0xC8, 0xE8, 0x04, + 0x8C, 0x01, 0x3E, 0x07, 0xEB, 0xDF, 0x2E, 0x07, 0xEB, 0xDE, 0x5C, 0xF0, 0x00, 0xC8, 0xE8, 0x04, + 0x8C, 0x01, 0x3E, 0x07, 0xEB, 0xDE, 0x2E, 0x07, 0xEB, 0xDD, 0x5C, 0xF0, 0x00, 0xC8, 0xE8, 0x04, + 0x8C, 0x01, 0x3E, 0x07, 0xEB, 0xDD, 0x84, 0x20, 0x80, 0x41, 0xF0, 0x01, 0x44, 0x32, 0xCD, 0x4C, + 0x44, 0x42, 0xCC, 0x24, 0x44, 0x52, 0xCA, 0x64, 0x49, 0xFF, 0xFD, 0x9B, 0xF0, 0x0D, 0x84, 0x20, + 0x9F, 0x81, 0x97, 0xB2, 0x80, 0x46, 0xF0, 0x01, 0x44, 0x32, 0xCD, 0x4C, 0x44, 0x42, 0xCB, 0x90, + 0x44, 0x52, 0xCA, 0x64, 0x49, 0xFF, 0xFD, 0x8D, 0x50, 0x04, 0xFF, 0xFF, 0x96, 0x02, 0xF0, 0x90, + 0xF1, 0x10, 0xF0, 0x01, 0x84, 0x40, 0x44, 0x32, 0xCC, 0xB8, 0x44, 0x42, 0xCC, 0x24, 0x44, 0x52, + 0xCA, 0x64, 0x49, 0xFF, 0xFD, 0x7E, 0xF0, 0x01, 0x80, 0x46, 0xF1, 0x10, 0x44, 0x32, 0xCC, 0xB8, + 0x44, 0x42, 0xCB, 0x90, 0x44, 0x52, 0xCA, 0x64, 0x49, 0xFF, 0xFD, 0x73, 0x44, 0x02, 0xCB, 0x48, + 0x85, 0x40, 0xF0, 0x85, 0xB0, 0x18, 0x14, 0xAF, 0x80, 0x02, 0x14, 0xAF, 0x80, 0x03, 0xF0, 0x87, + 0x44, 0x62, 0xCD, 0x4C, 0x14, 0xAF, 0x80, 0x06, 0x80, 0xE6, 0x50, 0x63, 0x00, 0x6E, 0x08, 0x03, + 0x80, 0x25, 0xF0, 0x88, 0x84, 0x00, 0xF0, 0x84, 0xF0, 0x04, 0xF1, 0x08, 0xE2, 0x01, 0xE8, 0x28, + 0x08, 0x03, 0x80, 0x01, 0xC0, 0x20, 0x00, 0x03, 0x80, 0x11, 0xF2, 0x06, 0xF0, 0x82, 0x00, 0x03, + 0x80, 0x23, 0xF3, 0x01, 0xF0, 0x83, 0xF1, 0x03, 0xF0, 0x02, 0xA5, 0x30, 0x84, 0xA0, 0x49, 0xFF, + 0xFE, 0xF1, 0x5C, 0xF0, 0x00, 0x5B, 0x4E, 0xF2, 0x00, 0xB7, 0xF0, 0x05, 0xF1, 0x02, 0x88, 0x01, + 0xF1, 0x05, 0xF2, 0x03, 0x9A, 0x41, 0xE2, 0x41, 0xE9, 0x06, 0x08, 0x10, 0x00, 0x01, 0xC1, 0xF9, + 0x48, 0x00, 0x00, 0xAA, 0xF0, 0x04, 0x8C, 0xC2, 0x8C, 0x01, 0xF0, 0x84, 0xD5, 0xD6, 0x5A, 0xA0, + 0x01, 0x0E, 0x50, 0x04, 0xFF, 0xFF, 0xF0, 0x86, 0xB0, 0x21, 0xF0, 0x87, 0x44, 0x02, 0xCB, 0x00, + 0x44, 0x62, 0xCC, 0xB8, 0xF0, 0x85, 0x85, 0x41, 0xD5, 0xC0, 0x84, 0x00, 0x44, 0x12, 0xCD, 0x4C, + 0x44, 0x22, 0xCB, 0x48, 0x80, 0x68, 0xB1, 0x18, 0xF5, 0x01, 0x49, 0xFF, 0xFE, 0x41, 0xF0, 0x10, + 0x44, 0x12, 0xCC, 0xB8, 0x44, 0x22, 0xCB, 0x00, 0x80, 0x68, 0xB1, 0x21, 0xF5, 0x01, 0x49, 0xFF, + 0xFE, 0x37, 0x40, 0x04, 0x84, 0x08, 0xF0, 0x95, 0x84, 0x00, 0xF0, 0x86, 0xF0, 0x88, 0xF0, 0x8B, + 0x2E, 0x27, 0xC6, 0xC1, 0xF0, 0x0B, 0x44, 0x10, 0x00, 0xE0, 0xE2, 0x02, 0xE8, 0x20, 0xF0, 0x0B, + 0xF6, 0x16, 0x42, 0x60, 0x04, 0x73, 0xB4, 0x06, 0xF0, 0x87, 0xC0, 0x16, 0x00, 0x03, 0x00, 0x14, + 0x54, 0x10, 0x00, 0x01, 0xC1, 0x07, 0xA4, 0x76, 0x12, 0x13, 0x00, 0x32, 0xA4, 0x77, 0x12, 0x13, + 0x00, 0x33, 0xF1, 0x07, 0x5A, 0x10, 0x05, 0x09, 0xF1, 0x07, 0x5A, 0x18, 0x04, 0x04, 0x48, 0x00, + 0x04, 0xDE, 0x5A, 0x18, 0x03, 0x64, 0xF0, 0x0B, 0x8C, 0x01, 0xD5, 0xDA, 0xF5, 0x16, 0x2E, 0x00, + 0x05, 0xF8, 0x80, 0x65, 0x42, 0x31, 0x04, 0x73, 0x80, 0x43, 0x84, 0x81, 0xB0, 0xF3, 0xB1, 0xAA, + 0xD2, 0x33, 0xB4, 0x25, 0x8E, 0x21, 0xE6, 0x22, 0xE8, 0x2C, 0x00, 0x12, 0x80, 0x6E, 0x5C, 0xF0, + 0x80, 0x28, 0x80, 0x01, 0xE8, 0x02, 0xFA, 0x18, 0x04, 0x12, 0x80, 0x18, 0x96, 0x00, 0x5A, 0x18, + 0x02, 0x06, 0x00, 0x12, 0x80, 0x51, 0xE2, 0x01, 0xD5, 0x03, 0x8E, 0x24, 0xE6, 0x22, 0xE8, 0x19, + 0x00, 0x12, 0x80, 0x18, 0x04, 0x74, 0x00, 0x05, 0x94, 0x4A, 0x88, 0x27, 0xA7, 0xCA, 0x00, 0x90, + 0x80, 0x03, 0xE3, 0x27, 0xE9, 0x0E, 0x04, 0x12, 0x80, 0x11, 0x5A, 0x18, 0x01, 0x05, 0x38, 0x13, + 0x98, 0x08, 0xD5, 0x05, 0x5A, 0x18, 0x02, 0x04, 0x38, 0x43, 0x8C, 0x08, 0x8C, 0xE1, 0xD5, 0xF2, + 0x50, 0x52, 0x80, 0xE0, 0xD5, 0xCE, 0x80, 0x68, 0xB1, 0x2A, 0xF5, 0x01, 0x3E, 0x00, 0x05, 0xF8, + 0x44, 0x12, 0xCD, 0x4C, 0x84, 0x00, 0x44, 0x22, 0xCA, 0xB8, 0x49, 0xFF, 0xFD, 0xC1, 0xF0, 0x10, + 0x44, 0x12, 0xCC, 0xB8, 0x44, 0x22, 0xCA, 0x70, 0x80, 0x68, 0xB1, 0x33, 0xF5, 0x01, 0x49, 0xFF, + 0xFD, 0xB7, 0xFC, 0xDE, 0xF0, 0x02, 0xF1, 0x03, 0xE0, 0x20, 0x4E, 0xF3, 0xFF, 0x55, 0xF1, 0x07, + 0x84, 0x41, 0x38, 0x20, 0x80, 0x08, 0x8C, 0x01, 0xD5, 0xF7, 0x80, 0x48, 0x00, 0x03, 0x00, 0x18, + 0xA0, 0x54, 0xF0, 0x8A, 0x94, 0x01, 0x88, 0x01, 0x04, 0x73, 0x00, 0x11, 0xA6, 0x41, 0x00, 0xA0, + 0x00, 0x00, 0xF1, 0x84, 0x00, 0x0F, 0x80, 0x10, 0x10, 0xA3, 0x00, 0x6C, 0x10, 0x03, 0x00, 0x6D, + 0xF0, 0x0A, 0xA0, 0x55, 0x94, 0x02, 0x88, 0x20, 0xF0, 0x93, 0xA6, 0x09, 0xF0, 0x94, 0xA6, 0x08, + 0xF0, 0x91, 0x50, 0x04, 0xFF, 0xFF, 0xCF, 0x0E, 0xF2, 0x11, 0xC2, 0x24, 0xF0, 0x85, 0x50, 0x04, + 0xFF, 0xFE, 0xF0, 0x8F, 0x44, 0x02, 0xCA, 0x70, 0xF0, 0x8C, 0x84, 0xFF, 0x44, 0x02, 0xCC, 0xB8, + 0xD5, 0x28, 0x5A, 0x70, 0x01, 0x0D, 0xF0, 0x85, 0x50, 0x04, 0xFF, 0xFE, 0xF0, 0x8F, 0x44, 0x02, + 0xCA, 0x70, 0xF0, 0x8C, 0x84, 0xFF, 0x44, 0x02, 0xCC, 0xB8, 0xD5, 0x09, 0x44, 0x02, 0xCA, 0xB8, + 0xF0, 0x8C, 0x84, 0x00, 0xF0, 0x85, 0xF7, 0x8F, 0x44, 0x02, 0xCD, 0x4C, 0xF2, 0x11, 0xCA, 0x11, + 0xD5, 0x0A, 0x44, 0x02, 0xCA, 0xB8, 0xF0, 0x8C, 0xF0, 0x11, 0x84, 0xE1, 0xF0, 0x85, 0xF7, 0x8F, + 0x44, 0x02, 0xCD, 0x4C, 0xF5, 0x14, 0x50, 0x24, 0xFF, 0xFF, 0xDA, 0x07, 0x48, 0x00, 0x00, 0x82, + 0xF5, 0x14, 0x50, 0x24, 0xFF, 0xFF, 0xDA, 0x7D, 0xA6, 0x8A, 0xF3, 0x05, 0x42, 0x34, 0x88, 0x73, + 0xA7, 0x4B, 0x94, 0xD9, 0x84, 0x20, 0xE2, 0xA2, 0xE9, 0x74, 0xB4, 0x88, 0x88, 0x81, 0x38, 0x42, + 0x0C, 0x00, 0x5A, 0x40, 0xFF, 0x24, 0x04, 0xF4, 0x00, 0x01, 0x38, 0xF7, 0x91, 0x01, 0x99, 0x02, + 0xA7, 0x21, 0x5A, 0x40, 0xFF, 0x1C, 0x05, 0xEF, 0x80, 0x0A, 0x4C, 0xFF, 0x40, 0x18, 0x80, 0x24, + 0x88, 0x20, 0xF4, 0x8E, 0x00, 0x20, 0x80, 0x5B, 0xF2, 0x89, 0x00, 0x20, 0x80, 0x37, 0x00, 0x10, + 0x80, 0x49, 0xF2, 0x82, 0xF1, 0x83, 0x50, 0x12, 0x00, 0x34, 0x94, 0x49, 0x88, 0x01, 0xA5, 0x03, + 0x80, 0x02, 0xC2, 0x08, 0xF0, 0x02, 0x8E, 0x01, 0xD5, 0x05, 0xF4, 0x15, 0x8C, 0x41, 0x88, 0x24, + 0xD5, 0xD3, 0xF0, 0x88, 0xF0, 0x0D, 0xF1, 0x03, 0x8E, 0x02, 0xE2, 0x01, 0xE8, 0x04, 0xF0, 0x0D, + 0x8E, 0x01, 0xD5, 0x03, 0xF0, 0x03, 0x8C, 0x01, 0xF0, 0x86, 0xF1, 0x03, 0xF2, 0x05, 0xF3, 0x01, + 0x84, 0xA0, 0xF0, 0x02, 0x49, 0xFF, 0xFD, 0x8E, 0xF1, 0x08, 0xF2, 0x05, 0x42, 0x10, 0xA4, 0x24, + 0x98, 0xCA, 0xF2, 0x01, 0x94, 0xD9, 0x88, 0x43, 0xF2, 0x97, 0xF2, 0x0F, 0xF5, 0x08, 0x88, 0x22, + 0xF2, 0x01, 0x94, 0x49, 0x41, 0xE1, 0x04, 0x00, 0x84, 0x40, 0x80, 0x22, 0x80, 0x82, 0xF3, 0x06, + 0xE0, 0x65, 0xE9, 0x10, 0xF3, 0x17, 0x38, 0xF1, 0x88, 0x11, 0x4E, 0xF7, 0x00, 0x03, 0x88, 0x8F, + 0x38, 0xFF, 0x08, 0x11, 0x4E, 0xF7, 0x00, 0x03, 0x88, 0x2F, 0xF3, 0x15, 0x8C, 0xA1, 0x88, 0x43, + 0xD5, 0xEF, 0x80, 0x43, 0xF3, 0x08, 0x8A, 0x43, 0xFE, 0x93, 0x84, 0x67, 0x42, 0x11, 0x0C, 0x73, + 0x4E, 0x16, 0x00, 0x03, 0x84, 0x21, 0x84, 0x4A, 0xFE, 0xA4, 0x40, 0x11, 0x04, 0x36, 0xD5, 0x09, + 0x84, 0x00, 0x44, 0x10, 0x00, 0xFF, 0xF1, 0x8E, 0x14, 0x03, 0x00, 0x11, 0xF0, 0x89, 0x80, 0x20, + 0xF2, 0x07, 0x5A, 0x20, 0x01, 0x04, 0x48, 0x00, 0x00, 0x80, 0x84, 0x4F, 0x10, 0x23, 0x00, 0x6E, + 0x04, 0x23, 0x00, 0x11, 0x84, 0x60, 0x10, 0x33, 0x00, 0xA5, 0xC2, 0x23, 0x00, 0x2F, 0x80, 0x1C, + 0x10, 0x33, 0x00, 0x5D, 0x10, 0x23, 0x00, 0x51, 0x84, 0x43, 0x14, 0x23, 0x00, 0x18, 0xF2, 0x02, + 0xC2, 0x05, 0xF2, 0x0D, 0xF5, 0x03, 0x8E, 0x41, 0xDA, 0x04, 0xFA, 0x49, 0x10, 0x23, 0x00, 0x6E, + 0x00, 0x2F, 0x80, 0x24, 0xF3, 0x09, 0x10, 0x23, 0x00, 0x81, 0xF2, 0x05, 0x42, 0x21, 0xA4, 0x73, + 0xF3, 0x01, 0x38, 0x21, 0x89, 0x11, 0x12, 0x03, 0x00, 0x2B, 0x12, 0x23, 0x00, 0x41, 0xD5, 0x10, + 0x44, 0x3F, 0xFF, 0xC8, 0x10, 0x33, 0x00, 0x51, 0xF3, 0x07, 0x12, 0x23, 0x00, 0x41, 0x14, 0x33, + 0x00, 0x18, 0x00, 0x3F, 0x80, 0x1C, 0x12, 0x23, 0x00, 0x2B, 0x10, 0x33, 0x00, 0x5D, 0x22, 0x33, + 0x00, 0x04, 0x50, 0x53, 0x00, 0x70, 0x84, 0x40, 0xA8, 0xE9, 0xB6, 0x25, 0x84, 0x80, 0x12, 0x33, + 0x00, 0x32, 0xA4, 0xF5, 0x10, 0x43, 0x00, 0x55, 0x10, 0x23, 0x00, 0x5A, 0x10, 0x23, 0x00, 0x5C, + 0x10, 0x23, 0x00, 0x5B, 0x12, 0x43, 0x00, 0x29, 0x12, 0x33, 0x00, 0x33, 0xF4, 0x0A, 0x04, 0x34, + 0x00, 0x03, 0x38, 0x31, 0x91, 0x01, 0x10, 0x23, 0x00, 0x5E, 0x12, 0x33, 0x00, 0x2C, 0x84, 0x60, + 0x10, 0x23, 0x00, 0x78, 0x10, 0x23, 0x00, 0x79, 0x10, 0x23, 0x00, 0x7A, 0x10, 0x23, 0x00, 0x7B, + 0x10, 0x23, 0x00, 0x7C, 0x10, 0x23, 0x00, 0x7D, 0x10, 0x23, 0x00, 0x7E, 0x10, 0x23, 0x00, 0x7F, + 0x10, 0x23, 0x00, 0x80, 0xA8, 0xED, 0x84, 0x61, 0x10, 0x33, 0x00, 0x88, 0x2E, 0x37, 0xEB, 0xE0, + 0xE6, 0x63, 0xE9, 0x6B, 0x2E, 0x37, 0xEB, 0xDF, 0xE6, 0x63, 0xE9, 0x67, 0x2E, 0x37, 0xEB, 0xDD, + 0xE6, 0x63, 0xE8, 0x64, 0xD5, 0x62, 0x04, 0x23, 0x00, 0x11, 0xC2, 0x1F, 0xF2, 0x02, 0xC2, 0x05, + 0xF2, 0x0D, 0xF5, 0x03, 0x8E, 0x41, 0xDA, 0x04, 0xFA, 0x49, 0x10, 0x23, 0x00, 0x6E, 0x00, 0x23, + 0x00, 0x81, 0xF3, 0x05, 0x42, 0x31, 0x24, 0x73, 0x80, 0x43, 0xF3, 0x01, 0x38, 0x21, 0x89, 0x11, + 0x22, 0x33, 0x00, 0x41, 0xE0, 0x62, 0xE8, 0x03, 0x12, 0x23, 0x00, 0x41, 0x02, 0x23, 0x00, 0x2B, + 0xE2, 0x40, 0xE8, 0x03, 0x12, 0x03, 0x00, 0x2B, 0x00, 0x23, 0x00, 0x51, 0x5C, 0xF1, 0x00, 0xC8, + 0xE8, 0x0E, 0x50, 0x43, 0x00, 0x70, 0x8C, 0x41, 0x10, 0x23, 0x00, 0x51, 0xB4, 0x44, 0xA0, 0xE1, + 0x88, 0x41, 0xB6, 0x44, 0x22, 0x23, 0x00, 0x04, 0x88, 0x43, 0xA8, 0xA1, 0xF3, 0x0A, 0x04, 0x24, + 0x00, 0x03, 0x38, 0x21, 0x0D, 0x01, 0x02, 0x33, 0x00, 0x2C, 0xE2, 0x62, 0xE8, 0x03, 0x12, 0x23, + 0x00, 0x2C, 0x22, 0x23, 0x00, 0x32, 0x22, 0x43, 0x00, 0x04, 0x9B, 0x14, 0x4E, 0x44, 0x00, 0x03, + 0xFF, 0x22, 0x22, 0x33, 0x00, 0x33, 0x22, 0x23, 0x00, 0x05, 0x9A, 0x9A, 0x4E, 0x24, 0x00, 0x03, + 0xFE, 0x92, 0x04, 0x33, 0x00, 0x21, 0x88, 0x44, 0xE2, 0x62, 0xE8, 0x03, 0x14, 0x23, 0x00, 0x21, + 0x2E, 0x27, 0xEB, 0xE0, 0xE6, 0x43, 0xE9, 0x09, 0x2E, 0x27, 0xEB, 0xDF, 0xE6, 0x43, 0xE9, 0x05, + 0x2E, 0x27, 0xEB, 0xDD, 0xE6, 0x43, 0xE8, 0x04, 0x84, 0x41, 0x10, 0x23, 0x00, 0x89, 0x3C, 0x3C, + 0x01, 0x4A, 0x84, 0x40, 0x10, 0x23, 0x00, 0x50, 0xCB, 0x23, 0x04, 0x23, 0x00, 0x11, 0xC2, 0x20, + 0x5A, 0x20, 0x01, 0x03, 0x84, 0x43, 0x44, 0x42, 0xCA, 0x64, 0x38, 0x52, 0x08, 0x00, 0xC5, 0x18, + 0x88, 0x44, 0xF5, 0x04, 0x20, 0x41, 0x00, 0x08, 0x42, 0xF3, 0x94, 0x24, 0xFF, 0xE4, 0xE0, 0xEF, + 0xE9, 0x0F, 0x20, 0x21, 0x00, 0x04, 0x52, 0x45, 0x00, 0x00, 0xFE, 0x92, 0xE0, 0x44, 0xE9, 0x08, + 0x02, 0x23, 0x00, 0x2B, 0xE6, 0x5F, 0xE9, 0x04, 0x84, 0x41, 0x10, 0x23, 0x00, 0x50, 0x00, 0x23, + 0x00, 0x50, 0xC2, 0x07, 0x04, 0x23, 0x00, 0x11, 0x4E, 0x23, 0x00, 0xB8, 0x48, 0x00, 0x01, 0x80, + 0x04, 0x23, 0x00, 0x11, 0xC2, 0x50, 0x04, 0x23, 0x00, 0x0D, 0x5A, 0x20, 0x02, 0x4D, 0xF2, 0x14, + 0xF4, 0x11, 0x8C, 0x41, 0x8A, 0x44, 0x04, 0x43, 0x00, 0x18, 0x96, 0x90, 0x5A, 0x48, 0x03, 0x07, + 0x04, 0x53, 0x00, 0x13, 0x4E, 0x52, 0x03, 0x7A, 0xD5, 0x0E, 0x5A, 0x48, 0x02, 0x3D, 0xE6, 0x42, + 0xE9, 0x3A, 0xE4, 0x28, 0xE8, 0x11, 0x42, 0xF0, 0x80, 0x24, 0x5C, 0xF7, 0x81, 0x3C, 0xE9, 0x22, + 0x5A, 0x48, 0x03, 0x07, 0x04, 0x43, 0x00, 0x13, 0xC4, 0x05, 0xCB, 0x04, 0xD5, 0x2C, 0x5A, 0x48, + 0x02, 0x2B, 0xE6, 0x42, 0xE9, 0x28, 0x5E, 0xF0, 0x80, 0x2E, 0xE8, 0x25, 0x42, 0xF0, 0x80, 0x24, + 0x5C, 0xF7, 0x87, 0xEA, 0xE8, 0x20, 0x02, 0x23, 0x00, 0x2B, 0x5C, 0xF1, 0x00, 0x2E, 0xE8, 0x1B, + 0x00, 0x23, 0x00, 0x51, 0xE6, 0x44, 0xE8, 0x17, 0x04, 0x23, 0x00, 0x12, 0x8E, 0x42, 0xE6, 0x42, + 0xE8, 0x12, 0x00, 0x23, 0x00, 0x5D, 0xCA, 0x07, 0x00, 0x23, 0x00, 0xA5, 0x5A, 0x28, 0x01, 0x04, + 0x10, 0x23, 0x00, 0x5B, 0x84, 0x41, 0x14, 0x23, 0x00, 0x18, 0x10, 0x23, 0x00, 0x5D, 0x84, 0x40, + 0x14, 0x23, 0x00, 0x11, 0x04, 0x23, 0x00, 0x11, 0xC2, 0xA6, 0x04, 0x23, 0x00, 0x0D, 0x5A, 0x20, + 0x02, 0xA3, 0x04, 0x23, 0x00, 0x18, 0x8E, 0x42, 0xE6, 0x42, 0xE8, 0x9D, 0x04, 0x53, 0x00, 0x12, + 0x22, 0x43, 0x00, 0x33, 0x22, 0x23, 0x00, 0x05, 0xC5, 0x96, 0x9A, 0xA2, 0x4E, 0x24, 0x00, 0x03, + 0xFE, 0x92, 0x02, 0x53, 0x00, 0x2B, 0x2E, 0x47, 0xC6, 0xEB, 0x44, 0xF0, 0x03, 0xE8, 0xFF, 0x2C, + 0x44, 0x50, 0x00, 0x32, 0xFF, 0x2C, 0x40, 0x42, 0x3C, 0x97, 0xE2, 0x82, 0xE8, 0x84, 0x5C, 0xF1, + 0x00, 0x51, 0x4E, 0xF3, 0xFF, 0x81, 0x00, 0x43, 0x00, 0x81, 0xF7, 0x01, 0xF5, 0x05, 0x42, 0x52, + 0x24, 0x73, 0x38, 0xF3, 0x95, 0x11, 0x22, 0x53, 0x00, 0x41, 0x84, 0xE2, 0x40, 0x52, 0x9C, 0xB6, + 0xE0, 0xAF, 0xE8, 0x0C, 0xF5, 0x08, 0xE0, 0x85, 0xE9, 0x05, 0xF5, 0x06, 0xE0, 0xA4, 0x4E, 0xF2, + 0xFF, 0x6B, 0x5C, 0xF1, 0x01, 0x2D, 0x4E, 0xF3, 0xFF, 0x67, 0x00, 0x23, 0x00, 0x5D, 0xCA, 0x07, + 0x00, 0x23, 0x00, 0xA5, 0x5A, 0x28, 0x01, 0x04, 0x10, 0x23, 0x00, 0x5B, 0x84, 0x41, 0xF4, 0x0C, + 0xF5, 0x08, 0x14, 0x23, 0x00, 0x18, 0x10, 0x23, 0x00, 0x5D, 0x84, 0x40, 0x14, 0x23, 0x00, 0x11, + 0x88, 0x85, 0xF5, 0x0C, 0xF7, 0x06, 0x9B, 0x65, 0xE2, 0xE5, 0x4E, 0xF3, 0xFF, 0x4D, 0x18, 0x22, + 0x00, 0x01, 0x10, 0x22, 0x00, 0x23, 0xD5, 0xF6, 0x04, 0x23, 0x00, 0x18, 0x5A, 0x20, 0x03, 0x04, + 0x48, 0x00, 0x00, 0xDF, 0x00, 0x43, 0x00, 0x51, 0x00, 0x23, 0x00, 0x6E, 0xE2, 0x44, 0xE9, 0x78, + 0x04, 0x53, 0x00, 0x12, 0xCD, 0x0B, 0x00, 0x23, 0x00, 0x55, 0x8C, 0x41, 0x10, 0x23, 0x00, 0x55, + 0x00, 0x23, 0x00, 0x7E, 0x8C, 0x41, 0x10, 0x23, 0x00, 0x7E, 0x00, 0x43, 0x00, 0x50, 0x5A, 0x48, + 0x01, 0x0C, 0x00, 0x23, 0x00, 0x55, 0x8C, 0x41, 0x10, 0x23, 0x00, 0x55, 0x00, 0x23, 0x00, 0x7F, + 0x8C, 0x41, 0x10, 0x23, 0x00, 0x7F, 0x5E, 0xF0, 0x81, 0x2D, 0xE8, 0x06, 0x42, 0xF0, 0x80, 0x24, + 0x5C, 0xF7, 0xB4, 0xBD, 0xE9, 0x0B, 0x00, 0x23, 0x00, 0x55, 0x8C, 0x41, 0x10, 0x23, 0x00, 0x55, + 0x00, 0x23, 0x00, 0x80, 0x8C, 0x41, 0x10, 0x23, 0x00, 0x80, 0xE6, 0xA2, 0xE8, 0x0B, 0x02, 0x23, + 0x00, 0x29, 0x8C, 0x41, 0x12, 0x23, 0x00, 0x29, 0x00, 0x23, 0x00, 0x78, 0x8C, 0x41, 0x10, 0x23, + 0x00, 0x78, 0x5A, 0x48, 0x01, 0x0C, 0x02, 0x23, 0x00, 0x29, 0x8C, 0x41, 0x12, 0x23, 0x00, 0x29, + 0x00, 0x23, 0x00, 0x79, 0x8C, 0x41, 0x10, 0x23, 0x00, 0x79, 0x5E, 0xF0, 0x80, 0x65, 0xE8, 0x05, + 0xFE, 0x0C, 0x5C, 0xF0, 0x11, 0x95, 0xE9, 0x0B, 0x02, 0x03, 0x00, 0x29, 0x8C, 0x01, 0x12, 0x03, + 0x00, 0x29, 0x00, 0x03, 0x00, 0x7A, 0x8C, 0x01, 0x10, 0x03, 0x00, 0x7A, 0x02, 0x03, 0x00, 0x2B, + 0x5C, 0xF0, 0x00, 0x47, 0xE9, 0x0C, 0xCB, 0x0B, 0x02, 0x03, 0x00, 0x29, 0x8C, 0x01, 0x12, 0x03, + 0x00, 0x29, 0x00, 0x03, 0x00, 0x7C, 0x8C, 0x01, 0x10, 0x03, 0x00, 0x7C, 0x04, 0x03, 0x00, 0x21, + 0x5C, 0xF0, 0x00, 0x65, 0xE9, 0x6D, 0xCB, 0x6C, 0x02, 0x03, 0x00, 0x29, 0x8C, 0x01, 0x12, 0x03, + 0x00, 0x29, 0x00, 0x03, 0x00, 0x7D, 0x8C, 0x01, 0x10, 0x03, 0x00, 0x7D, 0xD5, 0x61, 0x04, 0x23, + 0x00, 0x1C, 0x40, 0x21, 0x10, 0x57, 0x5C, 0xF1, 0x00, 0x74, 0xE8, 0x15, 0xFE, 0x14, 0x5C, 0xF0, + 0x14, 0x38, 0xE8, 0x11, 0x8A, 0x41, 0x8C, 0x4A, 0xE6, 0x55, 0xE8, 0x0D, 0x02, 0x03, 0x00, 0x2B, + 0x5C, 0xF0, 0x00, 0x33, 0xE8, 0x08, 0x02, 0x03, 0x00, 0x29, 0x00, 0x23, 0x00, 0x7A, 0x8A, 0x02, + 0x12, 0x03, 0x00, 0x29, 0x04, 0x03, 0x00, 0x1D, 0x40, 0x40, 0x10, 0x96, 0xE4, 0x9F, 0xE9, 0x0D, + 0xF0, 0x12, 0x50, 0xF0, 0x7F, 0xE1, 0xE0, 0x8F, 0xE8, 0x08, 0x02, 0x03, 0x00, 0x29, 0x00, 0x23, + 0x00, 0x78, 0x8A, 0x02, 0x12, 0x03, 0x00, 0x29, 0x02, 0x03, 0x00, 0x29, 0xE6, 0x06, 0xE9, 0x05, + 0x84, 0x02, 0x14, 0x03, 0x00, 0x18, 0xD5, 0x2C, 0x00, 0x03, 0x00, 0x5D, 0xC8, 0x07, 0x00, 0x03, + 0x00, 0xA5, 0x5A, 0x08, 0x01, 0x04, 0x10, 0x03, 0x00, 0x5B, 0x84, 0x01, 0x14, 0x03, 0x00, 0x18, + 0x10, 0x03, 0x00, 0x5D, 0x84, 0x00, 0x14, 0x03, 0x00, 0x11, 0xD5, 0x1A, 0x04, 0x03, 0x00, 0x0D, + 0x5A, 0x00, 0x02, 0x17, 0x04, 0x23, 0x00, 0x18, 0x9E, 0x12, 0xE6, 0x04, 0xE8, 0x11, 0x00, 0x03, + 0x00, 0x5D, 0xC8, 0x09, 0x00, 0x03, 0x00, 0xA5, 0x5A, 0x08, 0x01, 0x06, 0x5A, 0x20, 0x05, 0x04, + 0x10, 0x03, 0x00, 0x5B, 0x84, 0x01, 0x14, 0x03, 0x00, 0x18, 0x10, 0x03, 0x00, 0x5D, 0x04, 0x03, + 0x00, 0x11, 0xC0, 0x1A, 0x44, 0x02, 0xCB, 0x48, 0x38, 0x20, 0x28, 0x00, 0xC2, 0x08, 0x88, 0x0A, + 0xF2, 0x04, 0x20, 0x00, 0x00, 0x24, 0xE0, 0x02, 0x4E, 0xF2, 0x01, 0xDD, 0x44, 0x02, 0xCB, 0x00, + 0x38, 0x20, 0x28, 0x00, 0xC2, 0x4E, 0x88, 0x0A, 0x20, 0xF0, 0x00, 0x24, 0xF0, 0x04, 0xE0, 0x0F, + 0x4E, 0xF2, 0x01, 0xD1, 0xD5, 0x46, 0xF0, 0x0E, 0x5A, 0x00, 0xFF, 0x44, 0x44, 0x02, 0xCB, 0x48, + 0x38, 0x00, 0x28, 0x00, 0xC0, 0x0B, 0xF0, 0x04, 0xC8, 0x09, 0x04, 0x04, 0x00, 0x05, 0xF2, 0x13, + 0x88, 0x02, 0xA7, 0x41, 0x50, 0x04, 0xFF, 0xFF, 0xD8, 0x10, 0x44, 0x02, 0xCB, 0x00, 0x38, 0x00, + 0x28, 0x00, 0xC0, 0x2F, 0xF5, 0x04, 0x50, 0x04, 0xFF, 0xFF, 0xD8, 0x2B, 0x04, 0x04, 0x00, 0x05, + 0xF2, 0x0A, 0x38, 0x00, 0x0A, 0x00, 0xC0, 0x25, 0x84, 0x04, 0x14, 0x03, 0x00, 0x18, 0xF0, 0x04, + 0x4E, 0x03, 0x01, 0xB1, 0x84, 0x01, 0x00, 0x2F, 0x80, 0x24, 0x14, 0x03, 0x00, 0x11, 0x10, 0x23, + 0x00, 0x81, 0x5A, 0x08, 0x01, 0x04, 0x48, 0x00, 0x01, 0xA3, 0x50, 0x04, 0xFF, 0xFF, 0xF2, 0x09, + 0x42, 0x01, 0x24, 0x73, 0xF2, 0x01, 0x38, 0x01, 0x01, 0x11, 0x12, 0x03, 0x00, 0x41, 0xA4, 0x34, + 0x12, 0x03, 0x00, 0x32, 0xA4, 0x35, 0x12, 0x03, 0x00, 0x33, 0x84, 0x00, 0x12, 0x03, 0x00, 0x2B, + 0xCB, 0x51, 0x04, 0x03, 0x00, 0x18, 0x8E, 0x04, 0xE6, 0x02, 0xE9, 0x4C, 0xF0, 0x0E, 0x5A, 0x00, + 0xFF, 0x4A, 0xF0, 0x04, 0xC8, 0x0E, 0x44, 0x02, 0xCA, 0xB8, 0x38, 0x00, 0x28, 0x00, 0xC0, 0x09, + 0x04, 0x04, 0x00, 0x05, 0xF2, 0x13, 0x88, 0x02, 0xA7, 0x41, 0x50, 0x04, 0xFF, 0xFF, 0xD8, 0x10, + 0xF5, 0x04, 0x50, 0x04, 0xFF, 0xFF, 0xD8, 0x36, 0x44, 0x02, 0xCA, 0x70, 0x38, 0x00, 0x28, 0x00, + 0xC0, 0x31, 0x04, 0x04, 0x00, 0x05, 0xF2, 0x0A, 0x38, 0x00, 0x0A, 0x00, 0xC0, 0x2B, 0xE4, 0x2D, + 0xE9, 0x29, 0x04, 0x13, 0x00, 0x11, 0x84, 0x02, 0x14, 0x03, 0x00, 0x18, 0xC9, 0x23, 0xF1, 0x04, + 0xC9, 0x02, 0x84, 0x01, 0x14, 0x03, 0x00, 0x11, 0x00, 0x0F, 0x80, 0x24, 0x10, 0x03, 0x00, 0x81, + 0x04, 0x03, 0x00, 0x11, 0x5A, 0x00, 0x01, 0x05, 0x50, 0x04, 0xFF, 0xFF, 0xD5, 0x02, 0x84, 0x00, + 0xF1, 0x09, 0x42, 0x00, 0xA4, 0x73, 0xF1, 0x01, 0x38, 0x00, 0x81, 0x11, 0x12, 0x03, 0x00, 0x41, + 0xA4, 0x34, 0x12, 0x03, 0x00, 0x32, 0xA4, 0x35, 0x12, 0x03, 0x00, 0x33, 0x84, 0x00, 0x12, 0x03, + 0x00, 0x2B, 0xB4, 0x66, 0x84, 0x00, 0x5A, 0x38, 0x02, 0x13, 0x22, 0x03, 0x00, 0x04, 0x22, 0x23, + 0x00, 0x34, 0x9A, 0x82, 0x4E, 0x24, 0x00, 0x03, 0xFE, 0x92, 0x22, 0x13, 0x00, 0x05, 0x22, 0x03, + 0x00, 0x35, 0x9A, 0x08, 0x4E, 0x04, 0x00, 0x03, 0xFE, 0x02, 0x88, 0x02, 0x14, 0x03, 0x00, 0x23, + 0x04, 0x03, 0x00, 0x18, 0x5A, 0x08, 0x01, 0x17, 0x8E, 0x61, 0xE6, 0x62, 0xE8, 0x0C, 0x00, 0x13, + 0x00, 0x88, 0x84, 0x00, 0x3E, 0x07, 0xEB, 0xDE, 0x5A, 0x18, 0x01, 0x06, 0x10, 0x03, 0x00, 0x88, + 0x3E, 0x07, 0xEB, 0xE0, 0x04, 0x03, 0x00, 0x23, 0xE6, 0x1A, 0xE9, 0x04, 0x84, 0x00, 0x3E, 0x07, + 0xEB, 0xDD, 0xA4, 0x34, 0x12, 0x03, 0x00, 0x34, 0xA4, 0x35, 0x12, 0x03, 0x00, 0x35, 0x44, 0x00, + 0x00, 0x32, 0x10, 0x03, 0x00, 0x54, 0x48, 0xFF, 0xFB, 0x28, 0x96, 0x16, 0x4E, 0x02, 0x00, 0xF3, + 0x05, 0xE3, 0x00, 0x18, 0x5B, 0xE8, 0x01, 0x05, 0x84, 0x00, 0x3E, 0x07, 0xEB, 0xDF, 0x00, 0x13, + 0x00, 0x6E, 0x84, 0x00, 0x5C, 0xF0, 0x80, 0x28, 0x10, 0x03, 0x00, 0x54, 0x80, 0x01, 0xE8, 0x02, + 0xFA, 0x18, 0x02, 0x43, 0x00, 0x2B, 0x3E, 0x00, 0x05, 0xF8, 0xE6, 0x99, 0xE8, 0x05, 0x44, 0x00, + 0x00, 0x78, 0x3E, 0x00, 0x05, 0xF8, 0x00, 0x53, 0x00, 0x6D, 0x00, 0x13, 0x00, 0x6C, 0xF2, 0x01, + 0x80, 0x05, 0x42, 0x00, 0xA4, 0x73, 0x38, 0xF1, 0x01, 0x11, 0x02, 0x03, 0x00, 0x2C, 0x84, 0x43, + 0x94, 0x01, 0x40, 0x00, 0x08, 0x16, 0xE0, 0x0F, 0x84, 0x01, 0xE8, 0x05, 0x84, 0x02, 0x10, 0x03, + 0x00, 0x54, 0x84, 0x00, 0x5C, 0xF2, 0x00, 0x47, 0xE9, 0x08, 0x3C, 0x2C, 0x01, 0x4A, 0xCA, 0x05, + 0x84, 0x03, 0x10, 0x03, 0x00, 0x54, 0x80, 0x02, 0x00, 0x33, 0x00, 0x51, 0x04, 0x23, 0x00, 0x1D, + 0x40, 0x21, 0x0C, 0x56, 0xE4, 0x4B, 0xE9, 0x0D, 0xF7, 0x12, 0x50, 0xF3, 0xFF, 0xF5, 0xE0, 0x4F, + 0xE8, 0x08, 0x00, 0x73, 0x00, 0x55, 0x00, 0xA3, 0x00, 0x7E, 0x8A, 0xEA, 0x10, 0x73, 0x00, 0x55, + 0x00, 0x73, 0x00, 0x55, 0xE6, 0xE6, 0xE8, 0x06, 0x50, 0xA1, 0x80, 0x01, 0x91, 0x41, 0xE1, 0x47, + 0xE8, 0x05, 0x84, 0x04, 0x10, 0x03, 0x00, 0x54, 0x84, 0x00, 0x2E, 0x70, 0x05, 0xF8, 0xE2, 0xE3, + 0xE9, 0x04, 0xE6, 0x62, 0x84, 0x61, 0xE8, 0x06, 0x84, 0x05, 0x84, 0x60, 0x10, 0x03, 0x00, 0x54, + 0x80, 0x03, 0x44, 0x72, 0xCA, 0xB8, 0x38, 0x73, 0x84, 0x00, 0xC7, 0x0C, 0x44, 0x72, 0xCA, 0xB8, + 0x88, 0xE1, 0x20, 0x73, 0x80, 0x24, 0xE0, 0xE5, 0xE9, 0x05, 0x84, 0x06, 0x10, 0x03, 0x00, 0x54, + 0x84, 0x00, 0x44, 0x72, 0xCA, 0x70, 0x38, 0x73, 0x84, 0x00, 0xC7, 0x0C, 0x44, 0x72, 0xCA, 0x70, + 0x88, 0x27, 0x20, 0xF0, 0x80, 0x24, 0xE0, 0xAF, 0xE9, 0x05, 0x84, 0x07, 0x10, 0x03, 0x00, 0x54, + 0x84, 0x00, 0x5B, 0xE8, 0x05, 0x06, 0x84, 0x08, 0x10, 0x03, 0x00, 0x54, 0x84, 0x00, 0x04, 0x13, + 0x00, 0x21, 0x5C, 0xF0, 0x80, 0x65, 0xE9, 0x08, 0x3C, 0x1C, 0x01, 0x4A, 0xC9, 0x05, 0x84, 0x09, + 0x10, 0x03, 0x00, 0x54, 0x80, 0x01, 0x2E, 0x17, 0xEB, 0xDE, 0xE6, 0x2B, 0xE8, 0x12, 0x3C, 0x1C, + 0x01, 0x4A, 0xC9, 0x0F, 0x5C, 0xF2, 0x00, 0x38, 0xE8, 0x08, 0x5E, 0xF1, 0x7F, 0xFE, 0xE9, 0x05, + 0xF1, 0x12, 0x8C, 0x21, 0xE0, 0x22, 0xE8, 0x05, 0x84, 0x0A, 0x10, 0x03, 0x00, 0x54, 0xD5, 0x02, + 0xC8, 0x08, 0x44, 0x02, 0x2E, 0x00, 0x00, 0x13, 0x00, 0x54, 0xAE, 0x40, 0x84, 0x00, 0xD5, 0x02, + 0x84, 0x01, 0x02, 0x13, 0x00, 0x08, 0xE6, 0x28, 0xE8, 0x0D, 0x5A, 0x38, 0x01, 0x0C, 0x22, 0x23, + 0x00, 0x04, 0xE4, 0x4B, 0xE9, 0x07, 0x3C, 0x13, 0xE3, 0x65, 0x8E, 0x2B, 0xE0, 0x41, 0x40, 0x01, + 0xBC, 0x1B, 0x04, 0x13, 0x00, 0x18, 0x5A, 0x18, 0x01, 0x04, 0x48, 0xFF, 0xFA, 0x56, 0x5A, 0x00, + 0x01, 0x04, 0x48, 0xFF, 0xFA, 0x52, 0x04, 0x13, 0x00, 0x28, 0x14, 0x03, 0x00, 0x18, 0x5A, 0x10, + 0x01, 0x04, 0x48, 0xFF, 0xFA, 0x4A, 0x22, 0x13, 0x00, 0x04, 0x10, 0x03, 0x00, 0x5E, 0xE4, 0x2B, + 0xE9, 0x06, 0x3C, 0x03, 0xE3, 0x65, 0x8E, 0x0B, 0xE0, 0x20, 0xE9, 0x04, 0x02, 0x03, 0x00, 0x32, + 0xAC, 0x34, 0xF2, 0x0B, 0x44, 0x02, 0xCE, 0x64, 0x84, 0x21, 0x38, 0x10, 0x08, 0x08, 0x48, 0xFF, + 0xFA, 0x34, 0xA4, 0x34, 0x12, 0x03, 0x00, 0x34, 0xA4, 0x35, 0x12, 0x03, 0x00, 0x35, 0x48, 0xFF, + 0xFA, 0x2C, 0x84, 0x04, 0x14, 0x03, 0x00, 0x18, 0x48, 0xFF, 0xFE, 0xC5, 0x84, 0x00, 0x48, 0xFF, + 0xFE, 0x60, 0x84, 0x02, 0x48, 0xFF, 0xFE, 0x51, 0xE6, 0x42, 0x4E, 0xF3, 0xFC, 0x95, 0xE4, 0x28, + 0x4E, 0xF3, 0xFC, 0x8B, 0x48, 0xFF, 0xFC, 0x90, 0xFC, 0x4C, 0x81, 0x41, 0x2E, 0x17, 0xC6, 0xBB, + 0xF2, 0x83, 0xF1, 0x87, 0x3C, 0x13, 0xE3, 0x66, 0x2E, 0x87, 0xC6, 0xBA, 0xF1, 0x8C, 0x2E, 0x17, + 0xEB, 0xDC, 0x3C, 0x23, 0xE3, 0x65, 0x5C, 0xF0, 0x80, 0xC8, 0xE8, 0x04, 0x8C, 0x21, 0x3E, 0x17, + 0xEB, 0xDC, 0x2E, 0x17, 0xEB, 0xDB, 0x5C, 0xF0, 0x80, 0xC8, 0xE8, 0x04, 0x8C, 0x21, 0x3E, 0x17, + 0xEB, 0xDB, 0x2E, 0x17, 0xEB, 0xDA, 0x5C, 0xF0, 0x80, 0xC8, 0xE8, 0x04, 0x8C, 0x21, 0x3E, 0x17, + 0xEB, 0xDA, 0x2E, 0x17, 0xEB, 0xD9, 0x5C, 0xF0, 0x80, 0xC8, 0xE8, 0x04, 0x8C, 0x21, 0x3E, 0x17, + 0xEB, 0xD9, 0x2E, 0x17, 0xEB, 0xD8, 0x5C, 0xF0, 0x80, 0xC8, 0xE8, 0x04, 0x8C, 0x21, 0x3E, 0x17, + 0xEB, 0xD8, 0x2E, 0x17, 0xEB, 0xD7, 0x5C, 0xF0, 0x80, 0xC8, 0xE8, 0x04, 0x8C, 0x21, 0x3E, 0x17, + 0xEB, 0xD7, 0x2E, 0x17, 0xEB, 0xD6, 0x5C, 0xF0, 0x80, 0xC8, 0xE8, 0x04, 0x8C, 0x21, 0x3E, 0x17, + 0xEB, 0xD6, 0x2E, 0x17, 0xEB, 0xD5, 0x5C, 0xF0, 0x80, 0xC8, 0xE8, 0x04, 0x8C, 0x21, 0x3E, 0x17, + 0xEB, 0xD5, 0x2E, 0x17, 0xC6, 0xC1, 0x3C, 0x9C, 0x01, 0x4A, 0xF1, 0x93, 0xF1, 0x0C, 0x50, 0x34, + 0xFF, 0xFE, 0x90, 0x21, 0xF1, 0x8E, 0x50, 0x14, 0xFF, 0xFF, 0xF1, 0x84, 0x84, 0x20, 0xE2, 0x23, + 0x14, 0xFF, 0x80, 0x16, 0x2E, 0x37, 0xC6, 0xEA, 0x80, 0xC0, 0x44, 0x00, 0x00, 0x32, 0x90, 0x41, + 0xFE, 0x1C, 0xF2, 0x8F, 0xB6, 0x3F, 0xF1, 0x89, 0xF1, 0x85, 0xF1, 0x81, 0xF1, 0x8A, 0xF0, 0x97, + 0xF0, 0x0A, 0xF1, 0x13, 0xE2, 0x01, 0x4E, 0xF2, 0x04, 0x91, 0xB4, 0xE6, 0x4E, 0x72, 0x04, 0x7F, + 0x5A, 0x78, 0x05, 0x04, 0x48, 0x00, 0x04, 0x7B, 0x5A, 0x78, 0x04, 0x04, 0x48, 0x00, 0x03, 0xEA, + 0x5A, 0x78, 0x03, 0x04, 0x48, 0x00, 0x04, 0x73, 0x80, 0x4A, 0x00, 0x43, 0x00, 0x18, 0xA0, 0x54, + 0x94, 0x21, 0x88, 0x01, 0xA6, 0x41, 0xA6, 0x00, 0xF1, 0x94, 0xA0, 0x55, 0xF0, 0x95, 0x94, 0x22, + 0x88, 0x20, 0xA6, 0x0B, 0xF0, 0x90, 0xA6, 0x0A, 0xF0, 0x8D, 0x04, 0x03, 0x00, 0x25, 0xF0, 0x88, + 0xF2, 0x08, 0xF0, 0x07, 0x8E, 0x01, 0xCA, 0x0C, 0xF2, 0x0D, 0xC2, 0x20, 0xF0, 0x82, 0xF0, 0x07, + 0x44, 0x22, 0xCB, 0x90, 0x8E, 0x02, 0xF0, 0x8B, 0x84, 0x1F, 0xF0, 0x86, 0xD5, 0x23, 0xF2, 0x08, + 0x5A, 0x20, 0x01, 0x0B, 0xF0, 0x82, 0xF0, 0x07, 0x44, 0x22, 0xCB, 0x90, 0x8E, 0x02, 0xF0, 0x8B, + 0x84, 0x1F, 0xF0, 0x86, 0xD5, 0x08, 0xF0, 0x08, 0x44, 0x22, 0xCC, 0x24, 0xF0, 0x86, 0xF0, 0x8B, + 0x84, 0x00, 0xF0, 0x82, 0xF0, 0x0D, 0xC8, 0x0E, 0xD5, 0x08, 0x84, 0x01, 0xF0, 0x86, 0xF0, 0x8B, + 0xF0, 0x0D, 0x44, 0x22, 0xCC, 0x24, 0xF0, 0x82, 0xF0, 0x07, 0xF5, 0x10, 0x8E, 0x01, 0xD8, 0x06, + 0xD5, 0x74, 0xF0, 0x07, 0xF5, 0x10, 0x8E, 0x01, 0xD8, 0x70, 0xF0, 0x02, 0xA6, 0xC8, 0x42, 0x00, + 0x20, 0x24, 0xA6, 0x49, 0xF0, 0x91, 0xE2, 0x23, 0xE9, 0x68, 0xF0, 0x11, 0xB4, 0xAA, 0x88, 0x03, + 0x38, 0x02, 0x81, 0x00, 0x5A, 0x00, 0xFF, 0x1F, 0x04, 0x55, 0x00, 0x01, 0x38, 0x52, 0x81, 0x01, + 0x98, 0x13, 0xA6, 0x01, 0x5A, 0x00, 0xFF, 0x17, 0xDC, 0x15, 0x98, 0x50, 0x50, 0x00, 0x00, 0x34, + 0x00, 0x30, 0x80, 0x5B, 0x94, 0x01, 0x88, 0x02, 0xF3, 0x92, 0x00, 0x30, 0x80, 0x37, 0x00, 0x10, + 0x80, 0x49, 0xA5, 0x03, 0xF3, 0x81, 0xF1, 0x85, 0x80, 0x03, 0xC3, 0x06, 0xF0, 0x01, 0x8E, 0x01, + 0xD5, 0x03, 0x8C, 0x61, 0xD5, 0xD9, 0xF1, 0x05, 0xF0, 0x89, 0x50, 0x04, 0x7F, 0xFE, 0xE2, 0x01, + 0xE8, 0x04, 0x50, 0x04, 0x7F, 0xFF, 0xD5, 0x03, 0xF0, 0x05, 0x8C, 0x01, 0xB6, 0x1F, 0xF1, 0x05, + 0xF2, 0x02, 0xF3, 0x03, 0xF0, 0x01, 0x84, 0xA1, 0x49, 0xFF, 0xF7, 0x9C, 0xF1, 0x11, 0x05, 0xEF, + 0x80, 0x03, 0x95, 0x09, 0xF1, 0x03, 0xF2, 0x09, 0x88, 0x81, 0xF1, 0x0B, 0x94, 0x49, 0x43, 0xE0, + 0xA0, 0x73, 0x84, 0x20, 0x80, 0x61, 0xB4, 0xBF, 0xE0, 0xA2, 0xE9, 0x0D, 0x38, 0x52, 0x09, 0x11, + 0x4E, 0x57, 0x00, 0x03, 0x88, 0x65, 0x38, 0x5F, 0x09, 0x11, 0x4E, 0x57, 0x00, 0x03, 0x88, 0x25, + 0x8C, 0x41, 0xD5, 0xF2, 0xF4, 0x09, 0x80, 0x45, 0x8A, 0x44, 0xFE, 0x93, 0x84, 0x87, 0x42, 0x11, + 0x10, 0x73, 0x80, 0x41, 0x4E, 0x16, 0x00, 0x03, 0x84, 0x41, 0x84, 0x2A, 0xFE, 0x5C, 0x40, 0x10, + 0x88, 0x36, 0x5A, 0x78, 0x01, 0x74, 0xD5, 0x0A, 0x84, 0x20, 0x14, 0x13, 0x00, 0x25, 0x80, 0x01, + 0x5A, 0x70, 0x01, 0x04, 0x48, 0x00, 0x00, 0x8A, 0xF1, 0x92, 0x84, 0x4F, 0x10, 0x23, 0x00, 0xB2, + 0x04, 0x23, 0x00, 0x25, 0xC2, 0x23, 0x84, 0x41, 0x10, 0x23, 0x00, 0xA4, 0x84, 0x43, 0x14, 0x23, + 0x00, 0x28, 0x84, 0x40, 0x10, 0x23, 0x00, 0xA5, 0xF2, 0x01, 0xC2, 0x05, 0xF5, 0x05, 0x50, 0x24, + 0x7F, 0xFF, 0xDA, 0x04, 0xFA, 0x49, 0x10, 0x23, 0x00, 0xB2, 0x00, 0x2F, 0x80, 0x48, 0xF3, 0x02, + 0x10, 0x23, 0x00, 0xAC, 0xF2, 0x12, 0x42, 0x21, 0xA0, 0x73, 0xF3, 0x03, 0x38, 0x21, 0x89, 0x11, + 0x12, 0x03, 0x00, 0x55, 0x12, 0x23, 0x00, 0x57, 0xD5, 0x0E, 0x44, 0x3F, 0xFF, 0xC8, 0x10, 0x33, + 0x00, 0xA4, 0x84, 0x61, 0x14, 0x33, 0x00, 0x28, 0x10, 0x33, 0x00, 0xA5, 0x12, 0x23, 0x00, 0x57, + 0x12, 0x23, 0x00, 0x55, 0x2E, 0x47, 0xEB, 0xDC, 0x22, 0x33, 0x00, 0x05, 0x84, 0x40, 0xE6, 0x83, + 0x14, 0x33, 0x00, 0x2D, 0x12, 0x23, 0x00, 0x53, 0x10, 0x23, 0x00, 0xA8, 0x10, 0x23, 0x00, 0xB8, + 0x10, 0x23, 0x00, 0xB9, 0x10, 0x23, 0x00, 0xBA, 0x10, 0x23, 0x00, 0xBB, 0x10, 0x23, 0x00, 0xBC, + 0x10, 0x23, 0x00, 0xBD, 0x10, 0x23, 0x00, 0xBE, 0x10, 0x23, 0x00, 0xBF, 0x10, 0x23, 0x00, 0xC0, + 0xE8, 0x02, 0x84, 0x41, 0x10, 0x23, 0x00, 0xB0, 0x2E, 0x27, 0xEB, 0xDB, 0xE6, 0x43, 0x84, 0x41, + 0xE9, 0x02, 0x84, 0x40, 0x10, 0x23, 0x00, 0xB1, 0x84, 0x41, 0x10, 0x23, 0x00, 0xC8, 0x84, 0x40, + 0x10, 0x23, 0x00, 0xC9, 0xF2, 0x0E, 0xE0, 0x43, 0xD5, 0x41, 0xF2, 0x08, 0xC2, 0x1E, 0xF2, 0x01, + 0xC2, 0x05, 0xF5, 0x05, 0x50, 0x24, 0x7F, 0xFF, 0xDA, 0x04, 0xFA, 0x49, 0x10, 0x23, 0x00, 0xB2, + 0x00, 0x23, 0x00, 0xAC, 0xF3, 0x11, 0x88, 0x62, 0x80, 0x43, 0xF3, 0x03, 0x38, 0x21, 0x89, 0x11, + 0x22, 0x33, 0x00, 0x57, 0xE0, 0x62, 0xE8, 0x03, 0x12, 0x23, 0x00, 0x57, 0x02, 0x23, 0x00, 0x55, + 0xE2, 0x40, 0xE8, 0x03, 0x12, 0x03, 0x00, 0x55, 0x00, 0x23, 0x00, 0xA4, 0x5C, 0xF1, 0x00, 0xC8, + 0xE8, 0x0B, 0x8C, 0x41, 0x04, 0x33, 0x00, 0x2D, 0x10, 0x23, 0x00, 0xA4, 0x22, 0x23, 0x00, 0x05, + 0x88, 0x43, 0x14, 0x23, 0x00, 0x2D, 0x2E, 0x27, 0xEB, 0xDC, 0xE6, 0x43, 0xE8, 0x04, 0x84, 0x41, + 0x10, 0x23, 0x00, 0xB0, 0x2E, 0x27, 0xEB, 0xDB, 0xE6, 0x43, 0xE8, 0x04, 0x84, 0x41, 0x10, 0x23, + 0x00, 0xB1, 0x22, 0xF3, 0x00, 0x05, 0xF2, 0x0E, 0xE0, 0x4F, 0xE9, 0x0C, 0x2E, 0x27, 0xEB, 0xDA, + 0xE6, 0x43, 0xE9, 0x14, 0x2E, 0x27, 0xEB, 0xD9, 0xE6, 0x43, 0xE9, 0x10, 0x2E, 0x27, 0xEB, 0xD8, + 0xD5, 0x0B, 0x2E, 0x27, 0xEB, 0xD7, 0xE6, 0x43, 0xE9, 0x09, 0x2E, 0x27, 0xEB, 0xD6, 0xE6, 0x43, + 0xE9, 0x05, 0x2E, 0x27, 0xEB, 0xD5, 0xE6, 0x43, 0xE8, 0x04, 0x84, 0x41, 0x10, 0x23, 0x00, 0xC9, + 0xF2, 0x04, 0xE6, 0x42, 0xE9, 0x13, 0x44, 0x2F, 0xFF, 0xC8, 0x10, 0x23, 0x00, 0xA4, 0x04, 0x33, + 0x00, 0x28, 0x84, 0x41, 0x10, 0x23, 0x00, 0xA5, 0x84, 0x5D, 0xFE, 0x9E, 0x5A, 0x28, 0x01, 0x07, + 0x14, 0x23, 0x00, 0x28, 0x84, 0x40, 0x14, 0x23, 0x00, 0x25, 0x84, 0x40, 0x10, 0x23, 0x00, 0x50, + 0xF2, 0x04, 0xE6, 0x42, 0xE8, 0x32, 0x04, 0x23, 0x00, 0x25, 0xC2, 0x2F, 0x5A, 0x28, 0x01, 0x07, + 0x5A, 0x98, 0x01, 0x0C, 0x84, 0x5F, 0x84, 0x62, 0xD5, 0x0C, 0x5A, 0x28, 0x02, 0x09, 0x5A, 0x98, + 0x01, 0x07, 0x84, 0x5F, 0x84, 0x63, 0xD5, 0x05, 0xF3, 0x16, 0xD5, 0x03, 0x84, 0x41, 0x80, 0x62, + 0x44, 0x42, 0xCA, 0x64, 0x38, 0x52, 0x0C, 0x00, 0xC5, 0x18, 0x88, 0x64, 0xF5, 0x14, 0x20, 0x41, + 0x80, 0x08, 0xFF, 0x54, 0xFE, 0xA4, 0xE0, 0x45, 0xE9, 0x10, 0xF4, 0x06, 0xF2, 0x15, 0x20, 0x31, + 0x80, 0x04, 0xFE, 0xA4, 0xFE, 0xE4, 0xE0, 0x62, 0xE9, 0x08, 0x02, 0x23, 0x00, 0x55, 0xE6, 0x5F, + 0xE9, 0x04, 0x84, 0x41, 0x10, 0x23, 0x00, 0x50, 0x00, 0x33, 0x00, 0x50, 0x4E, 0x33, 0x00, 0xC4, + 0x04, 0x23, 0x00, 0x25, 0xC2, 0x65, 0x04, 0x23, 0x00, 0x0D, 0x5A, 0x20, 0x02, 0x62, 0xF2, 0x10, + 0xF4, 0x0D, 0x8C, 0x41, 0x8A, 0x44, 0x04, 0x43, 0x00, 0x28, 0x96, 0x90, 0x5A, 0x48, 0x03, 0x08, + 0x04, 0x53, 0x00, 0x27, 0xE6, 0xA2, 0xE8, 0x10, 0x48, 0x00, 0x02, 0x90, 0x5A, 0x48, 0x02, 0x51, + 0xE6, 0x42, 0xE9, 0x4E, 0xE4, 0x28, 0xE8, 0x27, 0x42, 0xF0, 0x80, 0x24, 0x5C, 0xF7, 0x81, 0x3C, + 0xE9, 0x36, 0x5A, 0x48, 0x03, 0x1D, 0x04, 0x43, 0x00, 0x27, 0x5A, 0x40, 0x03, 0x10, 0x5A, 0x40, + 0x05, 0x0E, 0x04, 0x53, 0x00, 0x31, 0x84, 0xFD, 0xFF, 0x7E, 0x5A, 0x50, 0x01, 0x04, 0x5A, 0x90, + 0x01, 0x11, 0x5A, 0x40, 0x02, 0x36, 0x5A, 0x40, 0x04, 0x34, 0x04, 0x43, 0x00, 0x31, 0x5A, 0x40, + 0x02, 0x30, 0x5A, 0x40, 0x04, 0x2E, 0x5A, 0x98, 0x02, 0x2C, 0xD5, 0x03, 0x5A, 0x48, 0x02, 0x29, + 0xE6, 0x42, 0xE9, 0x26, 0xE4, 0x35, 0xE8, 0x24, 0x42, 0xF0, 0x80, 0x24, 0x5C, 0xF7, 0x83, 0x85, + 0xE8, 0x1F, 0x02, 0x23, 0x00, 0x55, 0x5C, 0xF1, 0x00, 0x2E, 0xE8, 0x1A, 0x00, 0x23, 0x00, 0xA4, + 0xE6, 0x44, 0xE8, 0x16, 0x04, 0x23, 0x00, 0x26, 0x5A, 0x28, 0x02, 0x13, 0x00, 0x23, 0x00, 0x5D, + 0x5A, 0x28, 0x01, 0x07, 0x00, 0x43, 0x00, 0xA5, 0xCC, 0x03, 0x10, 0x23, 0x00, 0x5B, 0x84, 0x41, + 0x14, 0x23, 0x00, 0x28, 0x10, 0x23, 0x00, 0xA5, 0x84, 0x40, 0x14, 0x23, 0x00, 0x25, 0x04, 0x43, + 0x00, 0x25, 0xC4, 0x59, 0x04, 0x23, 0x00, 0x0D, 0x5A, 0x20, 0x02, 0x56, 0x04, 0x23, 0x00, 0x28, + 0x9F, 0x55, 0xE6, 0xA2, 0xE9, 0x04, 0x8E, 0x42, 0xE6, 0x42, 0xE8, 0x4D, 0x5A, 0x48, 0x01, 0x05, + 0x00, 0x23, 0x00, 0xB0, 0xD5, 0x05, 0x5A, 0x48, 0x02, 0x47, 0x00, 0x23, 0x00, 0xB1, 0xCA, 0x43, + 0x04, 0x53, 0x00, 0x26, 0x22, 0x43, 0x00, 0x32, 0x22, 0x23, 0x00, 0x04, 0xC5, 0x3C, 0x8A, 0x82, + 0x4E, 0x44, 0x00, 0x03, 0xFF, 0x22, 0x02, 0x23, 0x00, 0x55, 0xF5, 0x17, 0x44, 0xF0, 0x03, 0xE8, + 0xFE, 0xAC, 0x40, 0x21, 0x3C, 0x57, 0xE2, 0x44, 0xE8, 0x2E, 0x5C, 0xF2, 0x00, 0x51, 0xE9, 0x2B, + 0x00, 0x23, 0x00, 0xAC, 0xF7, 0x02, 0x80, 0xA2, 0x42, 0x53, 0xA0, 0x73, 0xF7, 0x03, 0x38, 0xF3, + 0x95, 0x11, 0x22, 0x53, 0x00, 0x57, 0x84, 0xE2, 0x40, 0x52, 0x9C, 0xB6, 0xE0, 0xAF, 0xE8, 0x0A, + 0xF5, 0x09, 0xE0, 0x45, 0xE9, 0x04, 0xB4, 0xBF, 0xE0, 0xA2, 0xE8, 0x15, 0x5C, 0xF2, 0x01, 0x2D, + 0xE9, 0x12, 0x00, 0x23, 0x00, 0x5D, 0x5A, 0x28, 0x01, 0x07, 0x00, 0x43, 0x00, 0xA5, 0xCC, 0x03, + 0x10, 0x23, 0x00, 0x5B, 0x84, 0x41, 0x14, 0x23, 0x00, 0x28, 0x10, 0x23, 0x00, 0xA5, 0x84, 0x40, + 0x14, 0x23, 0x00, 0x25, 0x04, 0x43, 0x00, 0x25, 0x04, 0x23, 0x00, 0x28, 0x4E, 0x42, 0x01, 0x00, + 0x5A, 0x20, 0x03, 0x04, 0x48, 0x00, 0x01, 0x14, 0x00, 0x23, 0x00, 0xA4, 0x00, 0x53, 0x00, 0xB2, + 0xE2, 0xA2, 0x4E, 0xF3, 0x00, 0xB9, 0x04, 0x23, 0x00, 0x26, 0xCA, 0x0B, 0x00, 0x53, 0x00, 0xA8, + 0x8C, 0xA1, 0x10, 0x53, 0x00, 0xA8, 0x00, 0x53, 0x00, 0xBE, 0x8C, 0xA1, 0x10, 0x53, 0x00, 0xBE, + 0x5E, 0xF0, 0x81, 0x2D, 0xE8, 0x06, 0x42, 0xF0, 0x80, 0x24, 0x5C, 0xF7, 0xB4, 0xBD, 0xE9, 0x0B, + 0x00, 0x53, 0x00, 0xA8, 0x8C, 0xA1, 0x10, 0x53, 0x00, 0xA8, 0x00, 0x53, 0x00, 0xC0, 0x8C, 0xA1, + 0x10, 0x53, 0x00, 0xC0, 0x5A, 0x38, 0x01, 0x19, 0x00, 0x53, 0x00, 0xA8, 0xE6, 0x42, 0x8C, 0xA1, + 0x10, 0x53, 0x00, 0xA8, 0x00, 0x53, 0x00, 0xBF, 0x8C, 0xA1, 0x10, 0x53, 0x00, 0xBF, 0xE9, 0x0E, + 0x02, 0x23, 0x00, 0x53, 0x8C, 0x41, 0x12, 0x23, 0x00, 0x53, 0x00, 0x23, 0x00, 0xB9, 0x8C, 0x41, + 0x10, 0x23, 0x00, 0xB9, 0xD5, 0x2D, 0xE6, 0x42, 0xE8, 0x2B, 0x5A, 0x48, 0x01, 0x15, 0x5A, 0x98, + 0x01, 0x07, 0x22, 0xF3, 0x00, 0x04, 0xF2, 0x0F, 0xE0, 0x4F, 0xD5, 0x07, 0x5A, 0x98, 0x02, 0x1F, + 0x22, 0x23, 0x00, 0x04, 0xF4, 0x0F, 0xE0, 0x44, 0xE9, 0x0F, 0x22, 0x23, 0x00, 0x05, 0xE4, 0x5F, + 0xE8, 0x15, 0xD5, 0x0A, 0x5A, 0x48, 0x02, 0x13, 0xF2, 0x0C, 0x22, 0x43, 0x00, 0x05, 0x50, 0xF1, + 0x7F, 0xE1, 0xE0, 0x8F, 0xE9, 0x0B, 0x02, 0x23, 0x00, 0x53, 0x8C, 0x41, 0x12, 0x23, 0x00, 0x53, + 0x00, 0x23, 0x00, 0xB8, 0x8C, 0x41, 0x10, 0x23, 0x00, 0xB8, 0x5A, 0x30, 0x01, 0xCB, 0x5E, 0xF0, + 0x80, 0x29, 0xE8, 0x05, 0xFE, 0x0C, 0x5C, 0xF0, 0x07, 0x09, 0xE9, 0x0B, 0x02, 0x03, 0x00, 0x53, + 0x8C, 0x01, 0x12, 0x03, 0x00, 0x53, 0x00, 0x03, 0x00, 0xBA, 0x8C, 0x01, 0x10, 0x03, 0x00, 0xBA, + 0x02, 0x03, 0x00, 0x55, 0x5C, 0xF0, 0x00, 0x3D, 0xE9, 0x0E, 0xF0, 0x04, 0xE6, 0x02, 0xE8, 0x0B, + 0x02, 0x03, 0x00, 0x53, 0x8C, 0x01, 0x12, 0x03, 0x00, 0x53, 0x00, 0x03, 0x00, 0xBC, 0x8C, 0x01, + 0x10, 0x03, 0x00, 0xBC, 0x04, 0x03, 0x00, 0x21, 0x5C, 0xF0, 0x00, 0x65, 0xE9, 0x0E, 0xF0, 0x04, + 0xE6, 0x02, 0xE8, 0x7D, 0x02, 0x03, 0x00, 0x53, 0x8C, 0x01, 0x12, 0x03, 0x00, 0x53, 0x00, 0x03, + 0x00, 0xBD, 0x8C, 0x01, 0x10, 0x03, 0x00, 0xBD, 0x5A, 0x98, 0x02, 0x0B, 0x04, 0x03, 0x00, 0x27, + 0x5A, 0x00, 0x02, 0x14, 0x5A, 0x08, 0x04, 0x6C, 0x2E, 0x07, 0xEB, 0xDB, 0xD5, 0x10, 0x5A, 0x98, + 0x01, 0x67, 0x04, 0x03, 0x00, 0x27, 0x5A, 0x08, 0x05, 0x07, 0x2E, 0x17, 0xEB, 0xDB, 0xE6, 0x23, + 0xE8, 0x5E, 0xD5, 0x30, 0x5A, 0x08, 0x03, 0x5C, 0x2E, 0x07, 0xEB, 0xDC, 0xE6, 0x03, 0x84, 0x05, + 0xE9, 0x29, 0xD5, 0x55, 0x04, 0x03, 0x00, 0x2D, 0x40, 0x00, 0x08, 0x16, 0x5A, 0x48, 0x02, 0x0F, + 0xF1, 0x0C, 0x50, 0xF0, 0xFF, 0xE1, 0xE0, 0x0F, 0xE8, 0x18, 0x02, 0x03, 0x00, 0x53, 0x00, 0x13, + 0x00, 0xB8, 0x8A, 0x01, 0x12, 0x03, 0x00, 0x53, 0xD5, 0x10, 0x5A, 0x48, 0x01, 0x0F, 0x5A, 0x90, + 0x01, 0x04, 0x5A, 0x98, 0x02, 0x0B, 0xE4, 0x1F, 0x02, 0x13, 0x00, 0x53, 0xE9, 0x06, 0x00, 0x03, + 0x00, 0xB8, 0x8A, 0x20, 0x12, 0x13, 0x00, 0x53, 0x02, 0x03, 0x00, 0x53, 0xE6, 0x06, 0xE9, 0x05, + 0x84, 0x02, 0x14, 0x03, 0x00, 0x28, 0xD5, 0x2B, 0x00, 0x03, 0x00, 0x5D, 0x5A, 0x08, 0x01, 0x07, + 0x00, 0x13, 0x00, 0xA5, 0xC9, 0x03, 0x10, 0x03, 0x00, 0x5B, 0x84, 0x01, 0x14, 0x03, 0x00, 0x28, + 0x10, 0x03, 0x00, 0xA5, 0x84, 0x00, 0x14, 0x03, 0x00, 0x25, 0xD5, 0x19, 0x04, 0x03, 0x00, 0x0D, + 0x5A, 0x00, 0x02, 0x16, 0x9E, 0x12, 0xE6, 0x02, 0xE9, 0x04, 0x8E, 0x45, 0xE6, 0x42, 0xE8, 0x0F, + 0x00, 0x03, 0x00, 0x5D, 0x5A, 0x08, 0x01, 0x07, 0x00, 0x13, 0x00, 0xA5, 0xC9, 0x03, 0x10, 0x03, + 0x00, 0x5B, 0x84, 0x01, 0x14, 0x03, 0x00, 0x28, 0x10, 0x03, 0x00, 0xA5, 0x04, 0x03, 0x00, 0x28, + 0x5A, 0x08, 0x01, 0x2D, 0xB4, 0x06, 0x8E, 0x01, 0xE6, 0x02, 0xE8, 0x28, 0xF0, 0x0E, 0x22, 0xF3, + 0x00, 0x05, 0x00, 0x13, 0x00, 0xC8, 0xE0, 0x0F, 0x84, 0x00, 0xE9, 0x11, 0x3E, 0x07, 0xEB, 0xDC, + 0x5A, 0x18, 0x01, 0x06, 0x10, 0x03, 0x00, 0xC8, 0x3E, 0x07, 0xEB, 0xDA, 0x04, 0x03, 0x00, 0x23, + 0xE6, 0x1A, 0xE9, 0x14, 0x84, 0x00, 0x3E, 0x07, 0xEB, 0xD8, 0xD5, 0x10, 0x3E, 0x07, 0xEB, 0xDB, + 0x5A, 0x18, 0x01, 0x06, 0x10, 0x03, 0x00, 0xC8, 0x3E, 0x07, 0xEB, 0xD7, 0x04, 0x03, 0x00, 0x23, + 0xE6, 0x1A, 0xE9, 0x04, 0x84, 0x00, 0x3E, 0x07, 0xEB, 0xD5, 0x44, 0x00, 0x00, 0x32, 0xD5, 0x7A, + 0x00, 0x03, 0x00, 0x14, 0x96, 0x16, 0x4E, 0x02, 0x00, 0x8A, 0x04, 0x23, 0x00, 0x28, 0x5A, 0x28, + 0x01, 0x0D, 0xF0, 0x0E, 0x22, 0xF3, 0x00, 0x05, 0xE0, 0x0F, 0x84, 0x00, 0xE9, 0x04, 0x3E, 0x07, + 0xEB, 0xD9, 0xD5, 0x03, 0x3E, 0x07, 0xEB, 0xD6, 0x00, 0x13, 0x00, 0xB2, 0x84, 0x00, 0xE6, 0x2F, + 0x10, 0x03, 0x00, 0xB3, 0x80, 0x01, 0xE8, 0x02, 0x84, 0x0F, 0x96, 0xC0, 0x3E, 0x00, 0x05, 0xF8, + 0x84, 0x01, 0x5A, 0x28, 0x05, 0x06, 0x84, 0x01, 0x10, 0x03, 0x00, 0xB3, 0x84, 0x00, 0x00, 0x43, + 0x00, 0x6C, 0x00, 0x13, 0x00, 0x6D, 0x42, 0x12, 0x20, 0x73, 0xF4, 0x03, 0x38, 0xF2, 0x05, 0x11, + 0x02, 0x13, 0x00, 0x2C, 0x84, 0x83, 0x94, 0x49, 0x40, 0x10, 0x90, 0x36, 0xE0, 0x2F, 0xE8, 0x05, + 0x84, 0x02, 0x10, 0x03, 0x00, 0xB3, 0x84, 0x00, 0x02, 0x13, 0x00, 0x55, 0x5C, 0xF0, 0x80, 0x3D, + 0xE9, 0x08, 0xF1, 0x04, 0xE6, 0x22, 0xE8, 0x05, 0x84, 0x03, 0x10, 0x03, 0x00, 0xB3, 0x84, 0x00, + 0x00, 0x43, 0x00, 0xA4, 0x04, 0x13, 0x00, 0x2D, 0x40, 0x10, 0x90, 0x36, 0xE4, 0x2B, 0xE9, 0x0D, + 0xF5, 0x0C, 0x50, 0xF2, 0xFF, 0xF5, 0xE0, 0x2F, 0xE8, 0x08, 0x00, 0x13, 0x00, 0xA8, 0x00, 0x53, + 0x00, 0xBE, 0x8A, 0x25, 0x10, 0x13, 0x00, 0xA8, 0x00, 0x53, 0x00, 0xA8, 0xE6, 0xA6, 0xE8, 0x05, + 0x9C, 0x61, 0x90, 0x21, 0xE0, 0x25, 0xE8, 0x05, 0x84, 0x04, 0x10, 0x03, 0x00, 0xB3, 0x84, 0x00, + 0xE2, 0x64, 0xE9, 0x03, 0xE6, 0x82, 0xE8, 0x05, 0x84, 0x05, 0x10, 0x03, 0x00, 0xB3, 0x84, 0x00, + 0x04, 0x13, 0x00, 0x21, 0x5C, 0xF0, 0x80, 0x65, 0xE9, 0x08, 0xF1, 0x04, 0xE6, 0x22, 0xE8, 0x05, + 0x84, 0x06, 0x10, 0x03, 0x00, 0xB3, 0xD5, 0x12, 0x5A, 0x20, 0x01, 0x11, 0x5A, 0x08, 0x01, 0x0F, + 0x04, 0x13, 0x00, 0x18, 0x14, 0x03, 0x00, 0x28, 0x5A, 0x18, 0x01, 0x09, 0xF2, 0x0A, 0x44, 0x12, + 0xCE, 0x64, 0x10, 0x03, 0x00, 0x5E, 0x38, 0x00, 0x88, 0x08, 0xF0, 0x0A, 0x50, 0x63, 0x00, 0xE0, + 0x8C, 0x01, 0xF0, 0x8A, 0x48, 0xFF, 0xFB, 0x76, 0xE6, 0x42, 0x4E, 0xF3, 0xFD, 0x7E, 0xE4, 0x28, + 0x4E, 0xF3, 0xFD, 0x74, 0x48, 0xFF, 0xFD, 0x79, 0xFC, 0xCC, 0x00, 0x00, 0x8E, 0x61, 0xE6, 0x64, + 0x3C, 0x53, 0xE3, 0x65, 0x3C, 0x43, 0xE3, 0x66, 0xE8, 0x26, 0xFC, 0x00, 0x22, 0x60, 0x00, 0x00, + 0x44, 0xF0, 0xFB, 0xB0, 0x38, 0x37, 0x8C, 0x00, 0x40, 0xF1, 0xBC, 0x00, 0x4A, 0x00, 0x3C, 0x00, + 0x04, 0x10, 0x18, 0x1C, 0xE0, 0x26, 0xE9, 0x19, 0x22, 0x10, 0x00, 0x01, 0xE0, 0x41, 0xD5, 0x10, + 0x8E, 0xA1, 0x9A, 0x69, 0xE0, 0xC1, 0xD5, 0xF8, 0xE0, 0x26, 0xD5, 0x04, 0x8E, 0xA1, 0x9A, 0x69, + 0xE0, 0xC1, 0xE9, 0x0B, 0x22, 0x10, 0x00, 0x01, 0x8E, 0x81, 0x9A, 0x22, 0xE0, 0x20, 0x56, 0x07, + 0x80, 0x01, 0xD5, 0x04, 0x84, 0x00, 0xDD, 0x9E, 0x84, 0x00, 0xFC, 0x80, 0xFC, 0x43, 0x83, 0x81, + 0x3C, 0x13, 0xE3, 0x65, 0x50, 0x90, 0x00, 0x08, 0x84, 0x00, 0xB6, 0x1F, 0x50, 0x00, 0xFF, 0xF5, + 0x2E, 0x27, 0xC6, 0xBA, 0xF0, 0x82, 0x50, 0x00, 0xFF, 0xE1, 0x2E, 0x37, 0xC6, 0xC1, 0xF0, 0x83, + 0x50, 0x00, 0xFF, 0xC3, 0xF0, 0x84, 0x9E, 0x11, 0xF3, 0x85, 0x85, 0x42, 0x84, 0xE3, 0x85, 0x01, + 0x84, 0xC0, 0xF0, 0x81, 0xB4, 0x1F, 0xF1, 0x05, 0xE2, 0x01, 0x4E, 0xF2, 0x00, 0x9F, 0x04, 0x14, + 0xFF, 0xFE, 0x5A, 0x18, 0x01, 0x16, 0x04, 0x04, 0x80, 0x04, 0xBA, 0x05, 0x94, 0x02, 0x88, 0x02, + 0xA6, 0x80, 0xA7, 0x41, 0xF0, 0x01, 0xCA, 0x07, 0xD0, 0x28, 0x14, 0x14, 0x80, 0x0F, 0x10, 0x24, + 0x80, 0x88, 0xD5, 0x28, 0xD8, 0x22, 0x14, 0xA4, 0x80, 0x0F, 0x84, 0x00, 0xD5, 0x21, 0x5A, 0x18, + 0x02, 0x66, 0x04, 0x04, 0x80, 0x0F, 0x5A, 0x08, 0x01, 0x0D, 0x04, 0x04, 0x80, 0x04, 0xB9, 0x05, + 0x94, 0x02, 0x88, 0x01, 0xA6, 0x40, 0xC9, 0x11, 0xA7, 0x41, 0xF0, 0x01, 0xD8, 0x13, 0xD5, 0x0D, + 0x5A, 0x08, 0x02, 0x11, 0x04, 0x04, 0x80, 0x04, 0xB9, 0x05, 0x94, 0x02, 0x88, 0x01, 0xA6, 0x40, + 0xC1, 0x04, 0xA7, 0x41, 0xF0, 0x01, 0xD0, 0x06, 0x14, 0x64, 0x80, 0x0F, 0x84, 0x01, 0x10, 0x04, + 0x80, 0x88, 0x04, 0x04, 0x80, 0x0F, 0xC8, 0x04, 0x14, 0x74, 0x80, 0x10, 0xD5, 0x3D, 0x5A, 0x08, + 0x01, 0x13, 0x22, 0x14, 0x80, 0x00, 0xE4, 0x2B, 0xE8, 0x04, 0x14, 0x64, 0x80, 0x10, 0xD5, 0x22, + 0xE4, 0x3F, 0xE9, 0x06, 0x5E, 0xF0, 0x80, 0x3D, 0x80, 0x0A, 0x40, 0x03, 0xBC, 0x1A, 0x14, 0x04, + 0x80, 0x10, 0xD5, 0x18, 0x5A, 0x08, 0x02, 0x2B, 0x22, 0x14, 0x80, 0x00, 0xF2, 0x02, 0xE0, 0x22, + 0xE9, 0x04, 0x14, 0x64, 0x80, 0x10, 0xD5, 0x2C, 0xF2, 0x03, 0xE0, 0x22, 0xE9, 0x04, 0x14, 0x84, + 0x80, 0x10, 0xD5, 0x26, 0xF2, 0x04, 0xE0, 0x22, 0x40, 0x03, 0xBC, 0x1B, 0x14, 0x04, 0x80, 0x10, + 0xD5, 0x1F, 0x80, 0x09, 0x44, 0x10, 0x00, 0x3C, 0x44, 0x20, 0x01, 0xF4, 0x84, 0x63, 0x49, 0xFF, + 0xFF, 0x3F, 0xC8, 0x13, 0x80, 0x09, 0x44, 0x10, 0x00, 0x78, 0x44, 0x20, 0x00, 0x96, 0x84, 0x63, + 0x49, 0xFF, 0xFF, 0x36, 0xC8, 0x0A, 0x14, 0x04, 0x80, 0x11, 0xB4, 0x1F, 0x50, 0x94, 0x80, 0xE0, + 0x8C, 0x01, 0xB6, 0x1F, 0x48, 0xFF, 0xFF, 0x78, 0x14, 0x84, 0x80, 0x11, 0xD5, 0xF7, 0x80, 0x09, + 0x44, 0x10, 0x00, 0x3C, 0x44, 0x20, 0x01, 0xF4, 0x84, 0x64, 0x49, 0xFF, 0xFF, 0x21, 0xC8, 0x0A, + 0x80, 0x09, 0x44, 0x10, 0x00, 0x78, 0x44, 0x20, 0x00, 0x96, 0x84, 0x64, 0x49, 0xFF, 0xFF, 0x18, + 0xC0, 0xE3, 0x14, 0xA4, 0x80, 0x11, 0xD5, 0xE2, 0xFC, 0xC3, 0xFC, 0x42, 0x3C, 0x43, 0xE3, 0x66, + 0x2E, 0x37, 0xC6, 0xC1, 0x40, 0x22, 0x04, 0x0A, 0xB6, 0x5F, 0x44, 0x20, 0x00, 0xE0, 0x51, 0xC0, + 0x00, 0x08, 0x42, 0x01, 0x88, 0x73, 0x8C, 0x08, 0x81, 0x01, 0xF0, 0x83, 0x2E, 0x17, 0xC6, 0xBB, + 0x50, 0x02, 0x7F, 0xF5, 0xF0, 0x81, 0x84, 0xE1, 0x50, 0x02, 0x7F, 0xE1, 0xF0, 0x82, 0x84, 0xC0, + 0x81, 0x27, 0x50, 0xA0, 0xFF, 0xFF, 0xF0, 0x03, 0x4D, 0xC0, 0x00, 0xEE, 0x04, 0x1E, 0x7F, 0xFE, + 0x5A, 0x18, 0x01, 0x4F, 0xB8, 0x04, 0x04, 0x24, 0x00, 0x05, 0x94, 0x02, 0x88, 0x02, 0xA6, 0x82, + 0xA7, 0x43, 0xCA, 0x07, 0x4C, 0x55, 0x00, 0x0E, 0xB9, 0xA3, 0x10, 0x2E, 0x00, 0xB9, 0xD5, 0x0C, + 0x4C, 0x55, 0x40, 0x08, 0x84, 0x02, 0xB8, 0xA3, 0x84, 0x00, 0x10, 0x0E, 0x00, 0xB9, 0xD5, 0x04, + 0xBE, 0xA3, 0x10, 0x9E, 0x00, 0xB9, 0xB8, 0x23, 0xC8, 0x0A, 0x84, 0x22, 0xB9, 0xA4, 0x22, 0xFE, + 0x00, 0x01, 0xB4, 0x3F, 0xE0, 0x2F, 0x40, 0x03, 0xBC, 0x1B, 0xD5, 0x27, 0x5A, 0x08, 0x01, 0x0D, + 0x22, 0x1E, 0x00, 0x01, 0xE4, 0x2B, 0xE8, 0x03, 0xBE, 0xA4, 0xD5, 0x15, 0xE4, 0x3F, 0xE9, 0x02, + 0x84, 0x02, 0xB8, 0xA4, 0xD5, 0x10, 0x5A, 0x08, 0x02, 0x1A, 0x22, 0x1E, 0x00, 0x01, 0xF2, 0x01, + 0xE0, 0x22, 0xE9, 0x03, 0xBE, 0xA4, 0xD5, 0x69, 0xF2, 0x02, 0xE0, 0x22, 0x40, 0x03, 0xBC, 0x1A, + 0xB8, 0xA4, 0xD5, 0x63, 0x80, 0x1C, 0x44, 0x10, 0x01, 0xF4, 0x44, 0x20, 0x00, 0x78, 0x84, 0x61, + 0x49, 0xFF, 0xFE, 0xA6, 0xC0, 0x72, 0x84, 0x02, 0xB8, 0xA5, 0xBE, 0xAF, 0xD5, 0x52, 0x5A, 0x18, + 0x02, 0x51, 0xB8, 0x23, 0x5A, 0x08, 0x01, 0x0D, 0xB8, 0x04, 0x04, 0x14, 0x00, 0x05, 0x94, 0x02, + 0x88, 0x01, 0xA6, 0x42, 0xC9, 0x11, 0xA7, 0x43, 0x4C, 0x55, 0x40, 0x12, 0xD5, 0x0D, 0x5A, 0x08, + 0x02, 0x0F, 0xB8, 0x04, 0x04, 0x14, 0x00, 0x05, 0x94, 0x02, 0x88, 0x01, 0xA6, 0x42, 0xC1, 0x04, + 0xA7, 0x43, 0x4C, 0x55, 0x00, 0x05, 0xBE, 0xA3, 0x10, 0x9E, 0x00, 0xB9, 0xB8, 0x23, 0xC8, 0x0A, + 0x84, 0x22, 0xB9, 0xA4, 0x22, 0xFE, 0x00, 0x01, 0xB4, 0x3F, 0xE0, 0x2F, 0x40, 0x03, 0xBC, 0x1B, + 0xD5, 0x27, 0x5A, 0x08, 0x01, 0x0D, 0x22, 0x1E, 0x00, 0x01, 0xE4, 0x2B, 0xE8, 0x03, 0xBE, 0xA4, + 0xD5, 0x15, 0xE4, 0x3F, 0xE9, 0x02, 0x84, 0x02, 0xB8, 0xA4, 0xD5, 0x10, 0x5A, 0x08, 0x02, 0x1A, + 0x22, 0x1E, 0x00, 0x01, 0xF2, 0x01, 0xE0, 0x22, 0xE9, 0x03, 0xBE, 0xA4, 0xD5, 0x44, 0xF2, 0x02, + 0xE0, 0x22, 0x40, 0x03, 0xBC, 0x1A, 0xB8, 0xA4, 0xD5, 0x3E, 0x80, 0x1C, 0x44, 0x10, 0x01, 0xF4, + 0x44, 0x20, 0x00, 0x78, 0x84, 0x61, 0x49, 0xFF, 0xFE, 0x53, 0xC0, 0x2A, 0x84, 0x02, 0xB8, 0xA5, + 0x51, 0xCE, 0x00, 0xE0, 0x48, 0xFF, 0xFF, 0x59, 0x80, 0x1C, 0x44, 0x10, 0x01, 0xF4, 0x44, 0x20, + 0x00, 0x78, 0x84, 0x63, 0x49, 0xFF, 0xFE, 0x44, 0xC0, 0x03, 0x84, 0x04, 0xD5, 0x9E, 0x44, 0x10, + 0x01, 0xF4, 0x80, 0x1C, 0x44, 0x20, 0x00, 0x78, 0x84, 0x64, 0x49, 0xFF, 0xFE, 0x39, 0x84, 0x25, + 0x40, 0x13, 0x80, 0x1A, 0x80, 0x01, 0xD5, 0x91, 0x80, 0x1C, 0x44, 0x10, 0x01, 0xF4, 0x44, 0x20, + 0x00, 0x78, 0x84, 0x62, 0x49, 0xFF, 0xFE, 0x2C, 0xC0, 0x88, 0x84, 0x03, 0xD5, 0x86, 0x80, 0x1C, + 0x44, 0x10, 0x01, 0xF4, 0x44, 0x20, 0x00, 0x78, 0x84, 0x62, 0x49, 0xFF, 0xFE, 0x21, 0xC0, 0xD0, + 0x84, 0x03, 0xD5, 0xCE, 0x80, 0x1C, 0x44, 0x10, 0x01, 0xF4, 0x44, 0x20, 0x00, 0x78, 0x84, 0x63, + 0x49, 0xFF, 0xFE, 0x16, 0xC0, 0x03, 0x84, 0x04, 0xD5, 0xC3, 0x44, 0x10, 0x01, 0xF4, 0x80, 0x1C, + 0x44, 0x20, 0x00, 0x78, 0x84, 0x64, 0x49, 0xFF, 0xFE, 0x0B, 0x84, 0x25, 0x40, 0x13, 0x80, 0x1A, + 0x80, 0x01, 0xD5, 0xB6, 0xFC, 0xC2, 0x00, 0x00, 0xFC, 0x02, 0xF0, 0x81, 0xF1, 0x82, 0xF2, 0x83, + 0x5A, 0x38, 0x05, 0x1C, 0x84, 0x61, 0x49, 0xFF, 0xFD, 0xFB, 0xC8, 0x4A, 0xF0, 0x01, 0xF1, 0x02, + 0xF2, 0x03, 0x84, 0x62, 0x49, 0xFF, 0xFD, 0xF4, 0xC8, 0x45, 0xF0, 0x01, 0xF1, 0x02, 0xF2, 0x03, + 0x84, 0x63, 0x49, 0xFF, 0xFD, 0xED, 0xC8, 0x40, 0xF0, 0x01, 0xF1, 0x02, 0xF2, 0x03, 0x84, 0x64, + 0x49, 0xFF, 0xFD, 0xE6, 0xC8, 0x3B, 0xD5, 0x3F, 0xC3, 0x3B, 0x9E, 0x19, 0xE6, 0x04, 0xE8, 0x3A, + 0x44, 0xF0, 0xFF, 0xE0, 0x38, 0x07, 0x80, 0x00, 0x40, 0xF0, 0x3C, 0x00, 0x4A, 0x00, 0x3C, 0x00, + 0x04, 0x18, 0x2A, 0x3C, 0xF0, 0x01, 0xF1, 0x02, 0xF2, 0x03, 0x84, 0x61, 0x49, 0xFF, 0xFD, 0xD0, + 0x8E, 0x01, 0x5C, 0x00, 0x00, 0x01, 0xD5, 0x27, 0xF0, 0x01, 0xF1, 0x02, 0xF2, 0x03, 0x84, 0x62, + 0x49, 0xFF, 0xFD, 0xC6, 0x5A, 0x08, 0x01, 0x1F, 0xD5, 0x15, 0xF0, 0x01, 0xF1, 0x02, 0xF2, 0x03, + 0x84, 0x63, 0x49, 0xFF, 0xFD, 0xBD, 0x5A, 0x08, 0x01, 0x16, 0xD5, 0x0E, 0xF0, 0x01, 0xF1, 0x02, + 0xF2, 0x03, 0x84, 0x64, 0x49, 0xFF, 0xFD, 0xB4, 0x5A, 0x08, 0x01, 0x0D, 0xD5, 0x07, 0x84, 0x01, + 0xD5, 0x0A, 0x84, 0x02, 0xD5, 0x08, 0x84, 0x03, 0xD5, 0x06, 0x84, 0x04, 0xD5, 0x04, 0x80, 0x03, + 0xD5, 0x02, 0x84, 0x00, 0xFC, 0x82, 0x92, 0x00, 0xFC, 0x41, 0x2E, 0x17, 0xEB, 0xD4, 0x5C, 0xF0, + 0x80, 0xC8, 0xE8, 0x04, 0x8C, 0x21, 0x3E, 0x17, 0xEB, 0xD4, 0x2E, 0x27, 0xC6, 0xC1, 0x44, 0x10, + 0x00, 0xE0, 0x50, 0x60, 0x00, 0x08, 0x42, 0x01, 0x04, 0x73, 0x3C, 0x8C, 0x01, 0x4A, 0x50, 0x70, + 0x00, 0x08, 0x85, 0x20, 0x87, 0x81, 0x4C, 0x63, 0x80, 0x75, 0x04, 0xA3, 0x7F, 0xFE, 0x5A, 0xA8, + 0x01, 0x15, 0x84, 0x00, 0x10, 0x03, 0x00, 0xC2, 0x44, 0x10, 0x00, 0x3C, 0x44, 0x20, 0x01, 0xF4, + 0x84, 0x65, 0x80, 0x06, 0x49, 0xFF, 0xFF, 0x7A, 0xB6, 0x1F, 0x44, 0x10, 0x00, 0x78, 0x80, 0x06, + 0x44, 0x20, 0x00, 0x96, 0x84, 0x65, 0xD5, 0x16, 0x5A, 0xA8, 0x02, 0x24, 0x04, 0x53, 0x00, 0x31, + 0x44, 0x10, 0x00, 0x3C, 0x80, 0x65, 0x44, 0x20, 0x01, 0xF4, 0x80, 0x06, 0xF5, 0x81, 0x49, 0xFF, + 0xFF, 0x65, 0xF5, 0x01, 0xB6, 0x1F, 0x44, 0x10, 0x00, 0x78, 0x80, 0x06, 0x44, 0x20, 0x00, 0x96, + 0x80, 0x65, 0x49, 0xFF, 0xFF, 0x5B, 0xB4, 0x9F, 0x9E, 0x63, 0xE6, 0x22, 0xE8, 0x04, 0x14, 0x43, + 0x00, 0x31, 0xD5, 0x07, 0x9E, 0x43, 0xE6, 0x22, 0x40, 0x04, 0xBC, 0x1A, 0x14, 0x03, 0x00, 0x31, + 0x04, 0x03, 0x00, 0x0B, 0x5A, 0x00, 0x02, 0x07, 0x04, 0x03, 0x00, 0x31, 0xC8, 0x03, 0x10, 0x03, + 0x00, 0xC2, 0x00, 0x03, 0x00, 0xC2, 0xC8, 0x0D, 0x04, 0x03, 0x00, 0x31, 0x5A, 0x00, 0x03, 0x04, + 0x5A, 0x08, 0x04, 0x08, 0x2E, 0x07, 0xEB, 0xD4, 0xE6, 0x02, 0xE8, 0x03, 0x11, 0xC3, 0x00, 0xC2, + 0x04, 0x03, 0x00, 0x16, 0x5A, 0x08, 0x01, 0x10, 0x50, 0x05, 0x7F, 0xFF, 0xE6, 0x02, 0xE8, 0x13, + 0x4E, 0x83, 0x00, 0x15, 0x04, 0x03, 0x00, 0x31, 0x8E, 0x03, 0xE6, 0x02, 0xE9, 0x0C, 0x3E, 0x87, + 0xEB, 0xD4, 0xD5, 0x09, 0x5A, 0xA8, 0x01, 0x08, 0x4E, 0x82, 0x00, 0x06, 0x14, 0x93, 0x00, 0x31, + 0x10, 0x93, 0x00, 0xC2, 0x50, 0x63, 0x00, 0xE0, 0xD5, 0x8F, 0x5A, 0xA8, 0x01, 0xFD, 0xD5, 0xF7, + 0xFC, 0xC1, 0xFC, 0x42, 0x2E, 0x17, 0xEB, 0xD3, 0x5C, 0xF0, 0x80, 0xC8, 0xE8, 0x04, 0x8C, 0x21, + 0x3E, 0x17, 0xEB, 0xD3, 0x2E, 0x17, 0xEB, 0xD2, 0x5C, 0xF0, 0x80, 0xC8, 0xE8, 0x04, 0x8C, 0x21, + 0x3E, 0x17, 0xEB, 0xD2, 0x3C, 0x13, 0xE3, 0x66, 0x2E, 0x37, 0xC6, 0xC1, 0x3C, 0x7C, 0x01, 0x4A, + 0x44, 0x20, 0x00, 0xE0, 0x90, 0x21, 0x50, 0x60, 0x00, 0x08, 0x42, 0x01, 0x88, 0x73, 0x8C, 0x08, + 0xF1, 0x81, 0x9E, 0x79, 0xF0, 0x82, 0xE6, 0x22, 0x85, 0x40, 0x14, 0xFF, 0x80, 0x03, 0x85, 0x20, + 0xF0, 0x02, 0x4C, 0x60, 0x00, 0x89, 0x04, 0x83, 0x7F, 0xFE, 0x5A, 0x88, 0x01, 0x0E, 0x84, 0x05, + 0x14, 0x03, 0x00, 0x33, 0x10, 0xA3, 0x00, 0xC8, 0x80, 0x06, 0x44, 0x10, 0x01, 0xF7, 0x44, 0x20, + 0x00, 0x78, 0x84, 0x65, 0xD5, 0x0A, 0x5A, 0x88, 0x02, 0x0D, 0x80, 0x06, 0x44, 0x10, 0x01, 0xF7, + 0x44, 0x20, 0x00, 0x78, 0x04, 0x33, 0x00, 0x33, 0x49, 0xFF, 0xFE, 0xD0, 0x14, 0x03, 0x00, 0x33, + 0x04, 0x03, 0x00, 0x0B, 0x5A, 0x00, 0x02, 0x07, 0x04, 0x03, 0x00, 0x33, 0xC8, 0x03, 0x10, 0x03, + 0x00, 0xC8, 0x00, 0x03, 0x00, 0xC8, 0xC8, 0x27, 0x5A, 0x78, 0x02, 0x15, 0x04, 0x03, 0x00, 0x33, + 0x5A, 0x08, 0x01, 0x07, 0x2E, 0x17, 0xEB, 0xD3, 0xE6, 0x22, 0xE8, 0x1D, 0xD5, 0x08, 0x5A, 0x08, + 0x03, 0x1B, 0x2E, 0x07, 0xEB, 0xD2, 0xE6, 0x02, 0xE8, 0x16, 0x84, 0x01, 0x10, 0x03, 0x00, 0xC8, + 0xD5, 0x12, 0x5A, 0x78, 0x01, 0x11, 0x04, 0x03, 0x00, 0x33, 0x5A, 0x08, 0x04, 0x05, 0x2E, 0x07, + 0xEB, 0xD2, 0xD5, 0x05, 0x5A, 0x08, 0x02, 0x08, 0x2E, 0x07, 0xEB, 0xD3, 0xE6, 0x02, 0xE8, 0x03, + 0x10, 0x73, 0x00, 0xC8, 0x04, 0x03, 0x00, 0x26, 0x5A, 0x08, 0x01, 0x2A, 0x50, 0x04, 0x7F, 0xFF, + 0xE6, 0x02, 0xE8, 0x25, 0x22, 0xF3, 0x00, 0x01, 0xF0, 0x01, 0xE0, 0x0F, 0xE9, 0x11, 0x5A, 0x78, + 0x02, 0x07, 0x04, 0x03, 0x00, 0x33, 0x5A, 0x08, 0x01, 0x09, 0xD5, 0x19, 0x5A, 0x78, 0x01, 0x18, + 0x04, 0x03, 0x00, 0x33, 0x5A, 0x00, 0x02, 0x14, 0x3E, 0xA7, 0xEB, 0xD3, 0xD5, 0x10, 0x5A, 0x78, + 0x02, 0x07, 0x04, 0x03, 0x00, 0x33, 0x5A, 0x08, 0x03, 0x09, 0xD5, 0x09, 0x5A, 0x78, 0x01, 0x08, + 0x04, 0x03, 0x00, 0x33, 0x5A, 0x00, 0x04, 0x04, 0x3E, 0xA7, 0xEB, 0xD2, 0xF0, 0x03, 0xC8, 0x07, + 0x5A, 0x88, 0x01, 0x06, 0x14, 0x93, 0x00, 0x33, 0x10, 0x93, 0x00, 0xC8, 0x50, 0x63, 0x00, 0xE0, + 0x48, 0xFF, 0xFF, 0x78, 0xFC, 0xC2, 0x3C, 0x0F, 0xFB, 0x47, 0xDD, 0x9E, 0x3C, 0x0F, 0xFB, 0x45, + 0xDD, 0x9E, 0x3C, 0x0F, 0xFB, 0x46, 0xDD, 0x9E, 0x3A, 0x6F, 0x9C, 0x3C, 0xA6, 0x90, 0x3C, 0x43, + 0xE3, 0xC1, 0xC2, 0x02, 0x84, 0x41, 0xA8, 0x82, 0xA0, 0x82, 0xA0, 0x03, 0x96, 0x86, 0x3C, 0x5D, + 0xFB, 0x46, 0x96, 0xD9, 0x96, 0x06, 0xCA, 0x12, 0xC8, 0x33, 0xA6, 0xA8, 0x88, 0x44, 0x88, 0x43, + 0xAC, 0x88, 0x2E, 0x27, 0xC6, 0xBA, 0xE2, 0x02, 0xE8, 0x3C, 0xA6, 0xA8, 0xA1, 0x89, 0x88, 0x44, + 0x88, 0x43, 0x38, 0x23, 0x01, 0x09, 0x8C, 0x01, 0xD5, 0xF5, 0xC0, 0x12, 0xA6, 0x2A, 0x84, 0x40, + 0x88, 0x04, 0x88, 0x03, 0xAC, 0x08, 0x2E, 0x07, 0xC6, 0xBA, 0xE2, 0x40, 0xE8, 0x2A, 0xA6, 0x2A, + 0xA1, 0x89, 0x88, 0x04, 0x88, 0x03, 0x38, 0x03, 0x09, 0x09, 0x8C, 0x41, 0xD5, 0xF5, 0xA6, 0xA9, + 0x88, 0x44, 0x88, 0x43, 0xAC, 0x88, 0x2E, 0x27, 0xC6, 0xBA, 0xE2, 0x02, 0xE8, 0x1A, 0xA6, 0xA9, + 0xA1, 0x89, 0x88, 0x44, 0x88, 0x43, 0x38, 0x23, 0x01, 0x09, 0x8C, 0x01, 0xD5, 0xF5, 0xA6, 0x2B, + 0x88, 0x04, 0x88, 0x03, 0xAC, 0x08, 0x80, 0x02, 0x2E, 0x27, 0xC6, 0xBA, 0xE2, 0x02, 0xE8, 0x09, + 0xA6, 0xAB, 0xA1, 0x89, 0x88, 0x44, 0x88, 0x43, 0x38, 0x23, 0x01, 0x09, 0x8C, 0x01, 0xD5, 0xF5, + 0x3A, 0x6F, 0x9C, 0x04, 0xDD, 0x9E, 0x3A, 0x6F, 0xA6, 0xBC, 0xEF, 0xF8, 0xFD, 0x30, 0xB4, 0x00, + 0xB0, 0x41, 0xFA, 0x40, 0x84, 0x63, 0x49, 0xFF, 0xDF, 0x83, 0x02, 0x0F, 0x80, 0x02, 0xA4, 0x70, + 0xB6, 0x07, 0x3C, 0x0D, 0xFB, 0x56, 0x44, 0x92, 0x8F, 0x70, 0xFA, 0x40, 0x02, 0x00, 0x00, 0x11, + 0x84, 0x64, 0x8A, 0x01, 0x00, 0x14, 0x80, 0x0F, 0x92, 0x01, 0x40, 0x00, 0x04, 0x37, 0x10, 0x13, + 0x80, 0x10, 0xB4, 0x06, 0xB0, 0x41, 0x49, 0xFF, 0xDF, 0x6B, 0x02, 0x0F, 0x80, 0x02, 0xA4, 0x70, + 0xA8, 0x39, 0x3C, 0x0D, 0xFB, 0x56, 0x3C, 0x3D, 0xFB, 0x45, 0x84, 0x81, 0x02, 0x00, 0x00, 0x11, + 0x8A, 0x01, 0x00, 0x14, 0x80, 0x0F, 0x92, 0x01, 0x40, 0x00, 0x04, 0x37, 0x10, 0x13, 0x80, 0x11, + 0xB4, 0x06, 0xA0, 0x72, 0xA0, 0xB6, 0x00, 0x31, 0x80, 0x0C, 0x49, 0xFF, 0xDF, 0xAA, 0x84, 0x01, + 0x12, 0x0F, 0x80, 0x03, 0x50, 0x1F, 0x80, 0x06, 0xA0, 0x36, 0x84, 0x40, 0x49, 0xFF, 0xDF, 0x83, + 0xEC, 0x08, 0x3A, 0x6F, 0xA6, 0x84, 0xDD, 0x9E, 0x48, 0xFF, 0xFF, 0xB7, 0x3A, 0x6F, 0xAA, 0xBC, + 0xEF, 0x8C, 0x81, 0x00, 0x84, 0x00, 0x12, 0x0F, 0x80, 0x21, 0x44, 0x01, 0x32, 0x94, 0xF4, 0x8D, + 0x80, 0xE2, 0x80, 0xC3, 0x3A, 0x20, 0x14, 0x00, 0xB0, 0x14, 0x81, 0x41, 0x3A, 0x20, 0x14, 0x20, + 0x84, 0x20, 0xB0, 0x18, 0xFA, 0x40, 0x49, 0x00, 0x16, 0x63, 0xF0, 0x0D, 0x5A, 0x08, 0x04, 0x1E, + 0xA6, 0xFA, 0x84, 0x00, 0x84, 0xA1, 0xA7, 0x3B, 0xB6, 0x7F, 0xF0, 0x81, 0xF0, 0x82, 0xF0, 0x83, + 0xF0, 0x84, 0xF0, 0x85, 0xF0, 0x86, 0xF5, 0x87, 0xF0, 0x88, 0xF0, 0x89, 0xF0, 0x8A, 0x04, 0x04, + 0x00, 0x06, 0x50, 0x1F, 0x80, 0x42, 0x44, 0x22, 0x32, 0xE8, 0x12, 0x6F, 0x80, 0x21, 0x44, 0x92, + 0x32, 0xE8, 0x49, 0xFF, 0xDF, 0x8C, 0xD5, 0x03, 0x04, 0x94, 0x00, 0x05, 0x00, 0x03, 0x80, 0x10, + 0x02, 0x33, 0x83, 0x9D, 0x00, 0x53, 0x80, 0x0F, 0x84, 0xC0, 0xB6, 0x1F, 0xB0, 0x11, 0xF0, 0x84, + 0xF6, 0x81, 0x80, 0x09, 0xF6, 0x82, 0xF6, 0x83, 0x80, 0x29, 0x84, 0x45, 0x80, 0x83, 0x49, 0xFF, + 0xAD, 0x8C, 0x02, 0x0F, 0x80, 0x22, 0x12, 0x05, 0x00, 0x00, 0x02, 0x0F, 0x80, 0x23, 0x12, 0x05, + 0x00, 0x01, 0xF0, 0x0D, 0x5A, 0x08, 0x04, 0x76, 0x12, 0x6F, 0x80, 0x21, 0x80, 0x86, 0xB0, 0x14, + 0xB0, 0x58, 0x38, 0x60, 0x10, 0x01, 0x88, 0x24, 0x95, 0xB1, 0x88, 0xC9, 0x80, 0x06, 0x84, 0x41, + 0xF4, 0x8E, 0x49, 0xFF, 0xDE, 0x57, 0x84, 0x41, 0x50, 0x0F, 0x80, 0x42, 0x80, 0x26, 0x80, 0x62, + 0x49, 0xFF, 0xDE, 0xF4, 0xF4, 0x0E, 0x8C, 0x82, 0x5A, 0x48, 0x10, 0xEB, 0x00, 0x03, 0x80, 0x10, + 0x04, 0x84, 0x00, 0x06, 0x84, 0xC0, 0x00, 0x53, 0x80, 0x0F, 0xFA, 0x6E, 0xB6, 0x1F, 0xB0, 0x11, + 0x80, 0x83, 0xF0, 0x84, 0x80, 0x28, 0x80, 0x08, 0x84, 0x45, 0xF6, 0x81, 0xF6, 0x82, 0xF6, 0x83, + 0x49, 0xFF, 0xAD, 0x53, 0x02, 0x0F, 0x80, 0x23, 0x00, 0x53, 0x80, 0x0F, 0xF0, 0x8E, 0x00, 0x03, + 0x80, 0x10, 0x80, 0x28, 0xB6, 0x1F, 0xB0, 0x11, 0xF0, 0x84, 0x84, 0x45, 0x80, 0x08, 0x44, 0x30, + 0x00, 0x3C, 0xFA, 0x8E, 0xF6, 0x81, 0xF6, 0x82, 0xF6, 0x83, 0x49, 0xFF, 0xAD, 0x3E, 0x02, 0x0F, + 0x80, 0x22, 0x00, 0x53, 0x80, 0x0F, 0xF0, 0x8F, 0x00, 0x03, 0x80, 0x10, 0x80, 0x28, 0xB6, 0x1F, + 0xB0, 0x11, 0xF0, 0x84, 0x84, 0x45, 0x80, 0x08, 0x44, 0x30, 0x00, 0x78, 0xF6, 0x81, 0xF6, 0x82, + 0xF6, 0x83, 0xFA, 0x8E, 0x49, 0xFF, 0xAD, 0x29, 0xF0, 0x0F, 0x02, 0x1F, 0x80, 0x22, 0xF3, 0x0E, + 0x9A, 0x41, 0x3C, 0x03, 0xE3, 0x76, 0x96, 0x49, 0x40, 0x20, 0x04, 0x09, 0xE2, 0x43, 0x3E, 0x67, + 0xEC, 0x18, 0x3E, 0x67, 0xEC, 0x3B, 0xE8, 0x04, 0x84, 0x41, 0x3E, 0x27, 0xEC, 0x18, 0x85, 0xE3, + 0x94, 0x01, 0x40, 0x00, 0x3C, 0x16, 0xE0, 0x01, 0xE8, 0x04, 0x84, 0x01, 0x3E, 0x07, 0xEC, 0x3B, + 0x80, 0x09, 0x50, 0x1F, 0x80, 0x42, 0x84, 0x40, 0x84, 0x63, 0x49, 0xFF, 0xDE, 0x71, 0x02, 0x0F, + 0x80, 0x21, 0x40, 0x64, 0x80, 0x13, 0x12, 0x05, 0x00, 0x03, 0x49, 0xFF, 0xDE, 0x67, 0x8A, 0x06, + 0x92, 0x01, 0x12, 0x05, 0x00, 0x04, 0xF0, 0x0D, 0x5A, 0x00, 0x04, 0x19, 0x80, 0x09, 0x50, 0x1F, + 0x80, 0x42, 0x84, 0x40, 0x84, 0x64, 0x49, 0xFF, 0xDE, 0x5B, 0x02, 0x0F, 0x80, 0x21, 0x12, 0x05, + 0x00, 0x02, 0x49, 0xFF, 0xDE, 0x53, 0x8A, 0x06, 0x92, 0x01, 0x12, 0x05, 0x00, 0x05, 0xF0, 0x0D, + 0x5A, 0x08, 0x04, 0x27, 0x84, 0xC0, 0xB1, 0xD4, 0xD5, 0x16, 0x44, 0x00, 0x7F, 0xFF, 0x12, 0x0F, + 0x80, 0x21, 0x84, 0xE0, 0x50, 0x8F, 0x80, 0x50, 0x38, 0x14, 0x1D, 0x01, 0x84, 0x41, 0x94, 0x49, + 0x50, 0x0F, 0x80, 0x42, 0x88, 0x29, 0x80, 0x62, 0x8C, 0xE1, 0x49, 0xFF, 0xDE, 0x57, 0x5A, 0x78, + 0x08, 0xF5, 0xD5, 0xD5, 0x38, 0x13, 0x1C, 0x01, 0xB0, 0x18, 0x94, 0x49, 0x88, 0x06, 0x88, 0x29, + 0x84, 0x41, 0x8C, 0xC2, 0x49, 0xFF, 0xDD, 0xA6, 0x5A, 0x68, 0x10, 0xF6, 0xD5, 0x13, 0x84, 0x00, + 0x3E, 0x07, 0xEC, 0x47, 0x22, 0x15, 0x00, 0x03, 0x3C, 0x03, 0xE6, 0xF8, 0xE0, 0x20, 0xE8, 0x0A, + 0x3C, 0x0D, 0xFB, 0x4D, 0xA4, 0x00, 0x92, 0x02, 0x96, 0x06, 0xC8, 0x04, 0x84, 0x01, 0x3E, 0x07, + 0xEC, 0x47, 0xEC, 0x74, 0x3A, 0x6F, 0xAA, 0x84, 0xDD, 0x9E, 0x84, 0x20, 0x3E, 0x10, 0x06, 0x35, + 0x22, 0x10, 0x00, 0x03, 0x5E, 0xF0, 0x80, 0x87, 0xE9, 0x08, 0x2E, 0x27, 0xEC, 0x79, 0xE6, 0x54, + 0xE8, 0x04, 0x8C, 0x41, 0x3E, 0x27, 0xEC, 0x79, 0x22, 0x30, 0x00, 0x02, 0x4E, 0x34, 0x00, 0x03, + 0xFE, 0xDA, 0x4E, 0x14, 0x00, 0x03, 0xFE, 0x4A, 0x84, 0x47, 0xFE, 0x8C, 0x84, 0x8A, 0x40, 0xF1, + 0x11, 0xF6, 0xE0, 0x6F, 0xE9, 0x2A, 0xA4, 0x40, 0x84, 0x45, 0xFE, 0x54, 0xE4, 0x34, 0xA4, 0xC1, + 0xE9, 0x04, 0x40, 0xF0, 0x91, 0xF6, 0xD5, 0x02, 0x85, 0xE1, 0xE0, 0x6F, 0xE9, 0x1E, 0x3A, 0x6F, + 0x98, 0xBC, 0x80, 0xC0, 0x49, 0xFF, 0xAF, 0x20, 0x5A, 0x08, 0x02, 0x16, 0x22, 0xF3, 0x00, 0x03, + 0x5E, 0xF7, 0x80, 0x87, 0xE8, 0x10, 0x2E, 0x07, 0xEC, 0x79, 0xC0, 0x04, 0x8E, 0x01, 0x3E, 0x07, + 0xEC, 0x79, 0x2E, 0x07, 0xEC, 0x79, 0xC8, 0x07, 0x84, 0x01, 0x3E, 0x00, 0x06, 0x35, 0xFA, 0x04, + 0x3E, 0x07, 0xEC, 0x79, 0x3A, 0x6F, 0x98, 0x84, 0xDD, 0x9E, 0x3A, 0x6F, 0xAA, 0xBC, 0xEF, 0xA4, + 0x81, 0x21, 0x50, 0xAF, 0x80, 0x34, 0x83, 0x80, 0x81, 0x02, 0x84, 0x20, 0xFA, 0x54, 0x80, 0x0A, + 0x49, 0x00, 0x14, 0xF6, 0x00, 0x34, 0x80, 0x02, 0x84, 0xC0, 0x84, 0xE1, 0xB6, 0x7F, 0xF7, 0x81, + 0xF6, 0x82, 0xF6, 0x83, 0xF6, 0x84, 0xF6, 0x85, 0xF6, 0x86, 0xF7, 0x87, 0xF6, 0x88, 0xF6, 0x89, + 0xF6, 0x8A, 0x00, 0x44, 0x80, 0x03, 0xB8, 0x06, 0x80, 0x28, 0x44, 0x22, 0x32, 0xE8, 0x80, 0xA7, + 0x49, 0xFF, 0xDE, 0x25, 0x44, 0x00, 0x00, 0x80, 0xF0, 0x83, 0x44, 0x0F, 0xFF, 0xE7, 0x00, 0x34, + 0x80, 0x02, 0xF0, 0x88, 0xFA, 0x09, 0xF0, 0x89, 0x44, 0x02, 0x32, 0xE8, 0x80, 0x40, 0x00, 0x44, + 0x80, 0x03, 0xB6, 0x7F, 0x50, 0x1F, 0x80, 0x32, 0x80, 0xA7, 0xF6, 0x81, 0xF6, 0x82, 0xF6, 0x84, + 0xF6, 0x85, 0xF7, 0x86, 0xF6, 0x87, 0xF6, 0x8A, 0x12, 0x6F, 0x80, 0x19, 0x49, 0xFF, 0xDE, 0x07, + 0x00, 0x34, 0x80, 0x02, 0x44, 0x00, 0x04, 0x00, 0xF0, 0x88, 0x80, 0x2A, 0xB6, 0x7F, 0xF7, 0x81, + 0xF6, 0x82, 0xF6, 0x83, 0xF6, 0x84, 0xF6, 0x85, 0xF6, 0x86, 0xF6, 0x87, 0xF6, 0x89, 0xF7, 0x8A, + 0x44, 0x02, 0x32, 0xE8, 0x80, 0x4A, 0xFA, 0x94, 0x80, 0xA7, 0x49, 0xFF, 0xDD, 0xF0, 0x00, 0x14, + 0x80, 0x02, 0x96, 0x30, 0xE2, 0x01, 0xE8, 0x0E, 0x38, 0x04, 0x19, 0x11, 0x4E, 0x04, 0x00, 0x03, + 0xFE, 0x02, 0x5E, 0xF0, 0x00, 0x33, 0xE9, 0x04, 0x38, 0x05, 0x19, 0x01, 0xC0, 0x05, 0x8C, 0xC1, + 0xD5, 0xF1, 0x84, 0x00, 0xD5, 0x02, 0x84, 0x01, 0xEC, 0x5C, 0x3A, 0x6F, 0xAA, 0x84, 0xDD, 0x9E, + 0x3A, 0x6F, 0xAA, 0xBC, 0xEF, 0xA4, 0x81, 0x01, 0x50, 0x9F, 0x80, 0x34, 0x83, 0x80, 0x81, 0x42, + 0x84, 0x20, 0xFA, 0x54, 0x80, 0x09, 0x49, 0x00, 0x14, 0x83, 0x00, 0x34, 0x00, 0x02, 0x84, 0xC0, + 0x84, 0xE1, 0xB6, 0x7F, 0xF7, 0x81, 0xF6, 0x82, 0xF6, 0x83, 0xF6, 0x84, 0xF6, 0x85, 0xF6, 0x86, + 0xF7, 0x87, 0xF6, 0x88, 0xF6, 0x89, 0xF6, 0x8A, 0x00, 0x44, 0x00, 0x03, 0xB8, 0x06, 0x80, 0x2A, + 0x44, 0x22, 0x32, 0xE8, 0x80, 0xA7, 0x49, 0xFF, 0xDD, 0xB2, 0x44, 0x00, 0x00, 0x80, 0xF0, 0x83, + 0x84, 0x16, 0x00, 0x34, 0x00, 0x02, 0xF0, 0x88, 0x84, 0x0A, 0xF0, 0x89, 0x44, 0x02, 0x32, 0xE8, + 0x80, 0x40, 0x00, 0x44, 0x00, 0x03, 0xB6, 0x7F, 0x50, 0x1F, 0x80, 0x32, 0x80, 0xA7, 0xF6, 0x81, + 0xF6, 0x82, 0xF6, 0x84, 0xF6, 0x85, 0xF7, 0x86, 0xF6, 0x87, 0xF6, 0x8A, 0x12, 0x6F, 0x80, 0x19, + 0x49, 0xFF, 0xDD, 0x95, 0x00, 0x34, 0x00, 0x02, 0x44, 0x00, 0x04, 0x00, 0xF0, 0x88, 0x80, 0x29, + 0x44, 0x02, 0x32, 0xE8, 0xFA, 0x94, 0xB6, 0x7F, 0xF7, 0x81, 0xF6, 0x82, 0xF6, 0x83, 0xF6, 0x84, + 0xF6, 0x85, 0xF6, 0x86, 0xF6, 0x87, 0xF6, 0x89, 0xF7, 0x8A, 0x80, 0x49, 0x80, 0xA7, 0x49, 0xFF, + 0xDD, 0x7E, 0x00, 0x44, 0x00, 0x02, 0x80, 0x06, 0x80, 0x26, 0x96, 0xB0, 0xE2, 0x44, 0xE8, 0x13, + 0x38, 0x24, 0x99, 0x01, 0xE4, 0x47, 0xE8, 0x0D, 0x38, 0x35, 0x19, 0x01, 0x50, 0x21, 0x81, 0x2B, + 0x96, 0x91, 0x5C, 0xF1, 0x02, 0x57, 0xE8, 0x05, 0x8C, 0x21, 0x88, 0x03, 0x96, 0x48, 0x96, 0x03, + 0x8C, 0xC1, 0xD5, 0xEC, 0xC1, 0x03, 0x40, 0x00, 0x04, 0x16, 0xEC, 0x5C, 0x3A, 0x6F, 0xAA, 0x84, + 0xDD, 0x9E, 0x3A, 0x6F, 0xAA, 0xBC, 0xEF, 0x7C, 0x80, 0xC3, 0x50, 0x8F, 0x80, 0x38, 0x80, 0xE0, + 0xFA, 0x54, 0x81, 0x21, 0x80, 0x08, 0x84, 0x20, 0x49, 0x00, 0x14, 0x0A, 0xA6, 0xF2, 0x44, 0x00, + 0x10, 0x00, 0x85, 0x40, 0x84, 0xA1, 0xF0, 0x88, 0x44, 0x0F, 0xF0, 0x00, 0xB6, 0x7F, 0xF0, 0x89, + 0x80, 0x28, 0x80, 0x48, 0xFA, 0x94, 0xF5, 0x81, 0x14, 0xAF, 0x80, 0x02, 0x14, 0xAF, 0x80, 0x03, + 0x14, 0xAF, 0x80, 0x04, 0x14, 0xAF, 0x80, 0x05, 0x14, 0xAF, 0x80, 0x06, 0x14, 0xAF, 0x80, 0x07, + 0xF5, 0x8A, 0xA0, 0x3E, 0x49, 0xFF, 0xDD, 0x33, 0xA6, 0x72, 0x80, 0x8A, 0xB0, 0xD7, 0xFA, 0x54, + 0x96, 0x20, 0xE2, 0x01, 0xE8, 0x09, 0x38, 0x04, 0x11, 0x11, 0x40, 0x00, 0x08, 0x16, 0x38, 0x01, + 0x91, 0x09, 0x8C, 0x81, 0xD5, 0xF6, 0x80, 0x43, 0x80, 0x07, 0x80, 0x26, 0xF3, 0x8D, 0x49, 0xFF, + 0xFE, 0xD6, 0xF3, 0x0D, 0x5A, 0x08, 0x01, 0x09, 0x44, 0x10, 0x00, 0x3C, 0x3E, 0x17, 0xEC, 0x43, + 0x3E, 0x00, 0x05, 0xFC, 0xD5, 0x0A, 0x2E, 0x07, 0xEC, 0x43, 0xC0, 0x05, 0x8E, 0x01, 0x3E, 0x07, + 0xEC, 0x43, 0xD5, 0x03, 0x3E, 0x00, 0x05, 0xFC, 0x80, 0x43, 0x80, 0x26, 0x80, 0x07, 0x49, 0xFF, + 0xFF, 0x31, 0x81, 0x40, 0x80, 0x29, 0x80, 0x07, 0x80, 0x46, 0x80, 0x6A, 0x84, 0x84, 0x49, 0xFF, + 0xFD, 0x3F, 0x2E, 0x07, 0xEC, 0x3B, 0xC8, 0x04, 0x80, 0x09, 0x49, 0xFF, 0xFE, 0x68, 0x84, 0x00, + 0x3E, 0x00, 0x05, 0xE8, 0x2E, 0x00, 0x06, 0x35, 0xC8, 0x6C, 0x2E, 0x10, 0x06, 0x12, 0xC9, 0x69, + 0x3C, 0x0D, 0xFB, 0x4A, 0xA6, 0x01, 0x5A, 0x08, 0x06, 0x65, 0x4E, 0xA4, 0x00, 0x1E, 0x00, 0x23, + 0x00, 0x0F, 0x96, 0x08, 0xE2, 0x02, 0xE8, 0x18, 0xA1, 0x3E, 0x94, 0x09, 0x88, 0x04, 0xA4, 0xC0, + 0x96, 0xDB, 0x8A, 0x6A, 0xE4, 0x75, 0xE8, 0x0D, 0x02, 0x03, 0x00, 0x1A, 0x8E, 0x01, 0x8A, 0x01, + 0x94, 0x01, 0x88, 0x04, 0x8C, 0x21, 0xA4, 0x00, 0x96, 0x03, 0x8A, 0x0A, 0xE4, 0x15, 0xE9, 0xEA, + 0x84, 0x01, 0x3E, 0x00, 0x05, 0xE8, 0x2E, 0x40, 0x05, 0xE8, 0xCC, 0x43, 0x00, 0x03, 0x00, 0x0F, + 0x44, 0x20, 0x00, 0xFF, 0xF0, 0x8D, 0x80, 0x24, 0x80, 0x02, 0x80, 0x64, 0x40, 0x85, 0x00, 0x13, + 0x04, 0xFF, 0x80, 0x0D, 0x97, 0x60, 0xE2, 0xAF, 0xE8, 0x2D, 0x05, 0xE3, 0x80, 0x06, 0x95, 0x61, + 0x88, 0xBE, 0x02, 0xF2, 0x80, 0x00, 0x40, 0xF7, 0x80, 0x11, 0x40, 0xF7, 0xA8, 0x01, 0x5E, 0xF7, + 0x80, 0x15, 0xE9, 0x05, 0xE4, 0x15, 0xE9, 0x03, 0x8C, 0x61, 0x96, 0xD8, 0xA4, 0x28, 0x02, 0x53, + 0x00, 0x1A, 0x8A, 0x08, 0x8E, 0xA1, 0x8A, 0xA4, 0x95, 0x69, 0x88, 0xBE, 0x96, 0x03, 0x02, 0xF2, + 0x80, 0x00, 0x40, 0xF7, 0x80, 0x11, 0x40, 0xF7, 0xA8, 0x01, 0x5E, 0xF7, 0x80, 0x15, 0xE9, 0x05, + 0xE4, 0x55, 0xE9, 0x03, 0x8C, 0x21, 0x96, 0x48, 0xA4, 0xA8, 0x8C, 0x81, 0x8A, 0x48, 0x96, 0x93, + 0xD5, 0xD0, 0xE6, 0x69, 0xE8, 0x03, 0xE6, 0x29, 0xE9, 0x04, 0x84, 0x01, 0x3E, 0x00, 0x05, 0xE8, + 0x2E, 0x07, 0xEC, 0x15, 0x5A, 0x08, 0x01, 0x07, 0x22, 0x14, 0x80, 0x03, 0x44, 0x02, 0x51, 0x98, + 0xAC, 0x40, 0xEC, 0x84, 0x3A, 0x6F, 0xAA, 0x84, 0xDD, 0x9E, 0x3A, 0x6F, 0xAA, 0xBC, 0xEF, 0x94, + 0x81, 0x01, 0xF0, 0x8A, 0x44, 0x12, 0xD0, 0xF8, 0x3C, 0x0C, 0x02, 0xA7, 0x02, 0x24, 0x03, 0x9D, + 0x44, 0x32, 0xB4, 0xF9, 0x84, 0x80, 0x49, 0xFF, 0x7C, 0xFD, 0x2E, 0x07, 0xEC, 0x41, 0x87, 0x80, + 0xF0, 0x88, 0x3C, 0x0C, 0x02, 0x11, 0xB0, 0x4F, 0xF0, 0x89, 0x3C, 0x0C, 0x02, 0x15, 0x51, 0xE0, + 0x00, 0x01, 0xF2, 0x08, 0x54, 0x0E, 0x00, 0xFF, 0xE2, 0x02, 0x4E, 0xF2, 0x01, 0x0E, 0xF0, 0x09, + 0x38, 0x20, 0x71, 0x01, 0x40, 0x0E, 0x00, 0x13, 0x4C, 0x20, 0x41, 0x01, 0x00, 0x0F, 0x00, 0x01, + 0x85, 0x41, 0xE6, 0x02, 0xE9, 0x04, 0x8E, 0x01, 0x54, 0xA0, 0x00, 0xFF, 0x00, 0x04, 0x00, 0x03, + 0x00, 0x2F, 0x00, 0x02, 0x9E, 0xC2, 0xE0, 0x43, 0xE8, 0x05, 0x8C, 0x41, 0x96, 0x10, 0xF0, 0x81, + 0xD5, 0x04, 0x8E, 0x01, 0x96, 0x00, 0xF0, 0x81, 0x00, 0x0F, 0x7F, 0xFF, 0xE6, 0x02, 0xE9, 0x05, + 0x8E, 0x01, 0x96, 0x00, 0xF0, 0x82, 0xD5, 0x03, 0x84, 0x01, 0xF0, 0x82, 0x00, 0x04, 0x00, 0x02, + 0x00, 0x2F, 0x00, 0x00, 0x9E, 0xC2, 0xE0, 0x43, 0xE8, 0x05, 0x8C, 0x41, 0x96, 0x10, 0xF0, 0x83, + 0xD5, 0x04, 0x8E, 0x01, 0x96, 0x00, 0xF0, 0x83, 0xB0, 0x91, 0xF0, 0x01, 0xE3, 0x40, 0x4E, 0xF2, + 0x00, 0xCE, 0x04, 0x9F, 0x80, 0x02, 0xF0, 0x03, 0xE3, 0x20, 0x4E, 0xF2, 0x00, 0xC2, 0xF0, 0x0A, + 0xA1, 0xC5, 0x00, 0x04, 0x00, 0x02, 0xF0, 0x84, 0xF3, 0x04, 0x80, 0x09, 0x42, 0x05, 0x0C, 0x73, + 0x94, 0x01, 0x88, 0x07, 0x02, 0x34, 0x03, 0x9D, 0xF0, 0x85, 0xA4, 0x00, 0xF3, 0x86, 0x96, 0x03, + 0x92, 0x61, 0xE0, 0x03, 0xF3, 0x87, 0x4E, 0xF2, 0x00, 0xA6, 0x84, 0x00, 0xAC, 0x08, 0xAC, 0x10, + 0xAC, 0x09, 0xAC, 0x11, 0xAC, 0x0A, 0xAC, 0x12, 0x84, 0x60, 0x50, 0x04, 0xFF, 0xFF, 0xB6, 0x7F, + 0xF0, 0x8D, 0xF5, 0x0D, 0x84, 0x03, 0x88, 0xA3, 0xF5, 0x8B, 0x80, 0xA0, 0xFF, 0x5C, 0x84, 0x80, + 0xF5, 0x8C, 0x42, 0x62, 0x0C, 0x24, 0x5A, 0x60, 0x01, 0x1C, 0x04, 0xFF, 0x80, 0x04, 0x40, 0x62, + 0x28, 0x00, 0x8E, 0xC1, 0xF5, 0x0B, 0x42, 0x53, 0x3C, 0x73, 0x95, 0xA9, 0x88, 0xC7, 0xF5, 0x07, + 0xA5, 0xB0, 0x97, 0xB3, 0xE0, 0xA6, 0xE8, 0x7E, 0xF5, 0x06, 0xE0, 0xC5, 0xE9, 0x03, 0x84, 0xA1, + 0xB6, 0xBF, 0xF5, 0x0C, 0x40, 0xF2, 0x90, 0x00, 0xB1, 0x55, 0x38, 0x62, 0xBD, 0x09, 0x8E, 0x01, + 0x8C, 0x81, 0x96, 0x00, 0x97, 0x20, 0xC8, 0xDE, 0x8C, 0x61, 0x5A, 0x38, 0x03, 0xD4, 0xB4, 0x7F, + 0x5A, 0x38, 0x01, 0x69, 0xB1, 0x15, 0x84, 0x60, 0x5A, 0x30, 0x01, 0x09, 0x38, 0x60, 0x81, 0x01, + 0x38, 0x72, 0x0D, 0x01, 0x88, 0xC7, 0x38, 0x60, 0x81, 0x09, 0x5A, 0x00, 0x01, 0x09, 0x38, 0x61, + 0x0D, 0x01, 0x38, 0x72, 0x0D, 0x01, 0x88, 0xC7, 0x38, 0x61, 0x0D, 0x09, 0x8C, 0x61, 0x5A, 0x38, + 0x03, 0xED, 0x8C, 0x01, 0x8C, 0x86, 0x5A, 0x08, 0x03, 0xE8, 0xA4, 0x11, 0xF0, 0x84, 0xA4, 0x09, + 0xB6, 0x1F, 0x84, 0x00, 0x80, 0x60, 0xB1, 0x15, 0x84, 0xA6, 0x42, 0x40, 0x14, 0x73, 0x81, 0xE4, + 0x84, 0x80, 0x97, 0xA0, 0x5A, 0x68, 0x01, 0x07, 0x5A, 0x00, 0x01, 0x26, 0x38, 0x70, 0x81, 0x01, + 0xCF, 0x08, 0x5A, 0x08, 0x01, 0x21, 0x38, 0x71, 0x11, 0x01, 0xC7, 0x1D, 0x5A, 0x68, 0x01, 0x0E, + 0xB4, 0xBF, 0x22, 0x67, 0x80, 0x01, 0x38, 0x70, 0x81, 0x01, 0xFF, 0xAC, 0xB1, 0x53, 0x40, 0x63, + 0x1C, 0xD6, 0x38, 0x62, 0x8D, 0x09, 0xD5, 0x0D, 0xB1, 0x55, 0x95, 0xA1, 0x88, 0xC5, 0xF5, 0x04, + 0x22, 0x63, 0x00, 0x03, 0xFF, 0xAC, 0xB1, 0x53, 0x40, 0x63, 0x1C, 0xD6, 0x38, 0x62, 0x8D, 0x09, + 0x8C, 0x61, 0x96, 0xD8, 0x8C, 0x81, 0x5A, 0x48, 0x03, 0xD6, 0x8C, 0x01, 0x5A, 0x08, 0x03, 0xCD, + 0xC3, 0x11, 0x02, 0x0F, 0x80, 0x27, 0x02, 0x4F, 0x80, 0x26, 0x88, 0x80, 0x02, 0x0F, 0x80, 0x28, + 0x88, 0x80, 0x02, 0x0F, 0x80, 0x29, 0x88, 0x04, 0x40, 0x00, 0x0C, 0x16, 0xF3, 0x05, 0x96, 0x03, + 0xAC, 0x18, 0x50, 0x04, 0x80, 0x01, 0x54, 0x90, 0x00, 0xFF, 0x48, 0xFF, 0xFF, 0x3E, 0x50, 0x05, + 0x00, 0x01, 0x54, 0xA0, 0x00, 0xFF, 0x48, 0xFF, 0xFF, 0x32, 0x51, 0xCE, 0x00, 0x01, 0x51, 0xEF, + 0x00, 0x04, 0x48, 0xFF, 0xFE, 0xF0, 0xEC, 0x6C, 0x3A, 0x6F, 0xAA, 0x84, 0xDD, 0x9E, 0x3C, 0x0E, + 0x01, 0x4B, 0xDD, 0x9E, 0x3C, 0x1C, 0x01, 0x4B, 0x2E, 0x07, 0xEC, 0x4C, 0xA6, 0x8E, 0xC8, 0x16, + 0x2E, 0x07, 0xC7, 0x54, 0x5A, 0x08, 0x01, 0x13, 0x94, 0x11, 0xAE, 0x0A, 0xA6, 0x09, 0x8E, 0x01, + 0xFE, 0x14, 0x84, 0x42, 0x40, 0x00, 0x08, 0x16, 0x8E, 0x01, 0x94, 0x01, 0x96, 0x03, 0x3C, 0x0B, + 0xF6, 0x48, 0xFE, 0x03, 0x3C, 0x0B, 0xF6, 0x47, 0xD5, 0x0F, 0xA6, 0x09, 0xAE, 0x8A, 0x8E, 0x01, + 0xFE, 0x14, 0x84, 0x42, 0x40, 0x00, 0x08, 0x16, 0x8E, 0x01, 0x96, 0x03, 0x3C, 0x0B, 0xF6, 0x48, + 0xFE, 0x03, 0x3C, 0x0B, 0xF6, 0x47, 0x2E, 0x20, 0x05, 0xFC, 0x5A, 0x28, 0x01, 0x11, 0xA6, 0xCA, + 0x84, 0x03, 0xFE, 0x1C, 0x90, 0x01, 0xAE, 0x0A, 0x3C, 0x03, 0xF6, 0x48, 0x94, 0x03, 0x3C, 0x0B, + 0xF6, 0x48, 0x3C, 0x03, 0xF6, 0x47, 0x94, 0x03, 0x3C, 0x0B, 0xF6, 0x47, 0x2E, 0x00, 0x05, 0xFB, + 0xC0, 0x11, 0xCA, 0x45, 0x2E, 0x07, 0xEC, 0x66, 0x5A, 0x08, 0x03, 0x0E, 0x3C, 0x03, 0xF6, 0x48, + 0x94, 0x01, 0x3C, 0x0B, 0xF6, 0x48, 0x3C, 0x03, 0xF6, 0x47, 0x94, 0x01, 0x3C, 0x0B, 0xF6, 0x47, + 0xD5, 0x02, 0xCA, 0x35, 0x2E, 0x07, 0xEC, 0x11, 0x5A, 0x08, 0x01, 0x32, 0xA6, 0x0A, 0x94, 0x01, + 0xAE, 0x0A, 0x2E, 0x07, 0xEC, 0x65, 0x5A, 0x08, 0x01, 0x0E, 0x3C, 0x23, 0xF6, 0x48, 0x84, 0x06, + 0xFE, 0x84, 0x3C, 0x2B, 0xF6, 0x48, 0x3C, 0x23, 0xF6, 0x47, 0xFE, 0x14, 0x3C, 0x0B, 0xF6, 0x47, + 0xD5, 0x1E, 0x2E, 0x07, 0xEC, 0x1A, 0x5A, 0x08, 0x01, 0x0D, 0x3C, 0x03, 0xF6, 0x48, 0x94, 0x02, + 0x3C, 0x0B, 0xF6, 0x48, 0x3C, 0x03, 0xF6, 0x47, 0x94, 0x02, 0x3C, 0x0B, 0xF6, 0x47, 0xD5, 0x0F, + 0x2E, 0x07, 0xEC, 0x37, 0x5A, 0x08, 0x01, 0x0C, 0x3C, 0x03, 0xF6, 0x48, 0x94, 0x01, 0x3C, 0x0B, + 0xF6, 0x48, 0x3C, 0x03, 0xF6, 0x47, 0x94, 0x01, 0x3C, 0x0B, 0xF6, 0x47, 0xA6, 0x09, 0x3E, 0x07, + 0xEC, 0x08, 0x8C, 0x01, 0x3E, 0x07, 0xEC, 0x09, 0xDD, 0x9E, 0x3A, 0x6F, 0xAA, 0xBC, 0x51, 0xFF, + 0xFA, 0xAC, 0x2E, 0x37, 0xC6, 0xC7, 0x2E, 0x47, 0xC6, 0xC8, 0x84, 0xC0, 0x85, 0x21, 0xF1, 0x8D, + 0x83, 0x82, 0x94, 0x59, 0x44, 0x20, 0x00, 0x80, 0x8E, 0x81, 0x88, 0x20, 0xB6, 0x7F, 0xF3, 0x82, + 0xF2, 0x83, 0x97, 0x20, 0x44, 0x22, 0x32, 0xE8, 0x80, 0xA9, 0x14, 0x9F, 0x80, 0x01, 0xF6, 0x84, + 0xF6, 0x85, 0xF6, 0x86, 0x14, 0x9F, 0x80, 0x07, 0xF6, 0x88, 0xF6, 0x89, 0xF6, 0x8A, 0x81, 0x40, + 0x49, 0xFF, 0xDA, 0x95, 0x2E, 0x37, 0xC6, 0xC7, 0x2E, 0x47, 0xC6, 0xC8, 0x44, 0x00, 0x00, 0x80, + 0x40, 0x21, 0xA4, 0x0C, 0x44, 0x82, 0x32, 0xE8, 0xF0, 0x83, 0xB1, 0xD0, 0x84, 0x03, 0x8E, 0x82, + 0xF0, 0x87, 0x97, 0x20, 0x40, 0x01, 0x20, 0x00, 0x80, 0xA9, 0xB6, 0x7F, 0x14, 0x9F, 0x80, 0x01, + 0xF3, 0x82, 0xF6, 0x84, 0xF6, 0x85, 0xF6, 0x86, 0xF6, 0x88, 0xF6, 0x89, 0xF6, 0x8A, 0x80, 0x28, + 0x88, 0x47, 0x49, 0xFF, 0xDA, 0x74, 0x12, 0x6F, 0x80, 0x1F, 0x80, 0x88, 0x80, 0xA6, 0x2E, 0x37, + 0xC6, 0xC7, 0x96, 0xB3, 0xE0, 0x43, 0x8C, 0xC1, 0x97, 0xB1, 0xE8, 0x1A, 0x40, 0x91, 0x04, 0x08, + 0x38, 0x04, 0x90, 0x01, 0x38, 0x03, 0x89, 0x09, 0x2E, 0x07, 0xC6, 0xC8, 0x9E, 0x41, 0x42, 0x01, + 0x84, 0x24, 0x98, 0x42, 0x8A, 0x03, 0x88, 0x02, 0x38, 0x02, 0x01, 0x01, 0x38, 0x03, 0x85, 0x09, + 0xF0, 0x0D, 0x89, 0x20, 0x12, 0x54, 0x80, 0x00, 0x38, 0x5E, 0x09, 0x09, 0xD5, 0xE1, 0x84, 0x01, + 0x84, 0xC0, 0x12, 0x0F, 0x80, 0x1F, 0xB0, 0x10, 0xB6, 0x7F, 0xF6, 0x81, 0xF6, 0x82, 0xF6, 0x83, + 0xF6, 0x84, 0xF6, 0x85, 0xF6, 0x86, 0xF6, 0x87, 0xF6, 0x88, 0xF6, 0x89, 0xF6, 0x8A, 0x50, 0x1F, + 0x80, 0x3E, 0x80, 0x40, 0x2E, 0x47, 0xC6, 0xC8, 0x84, 0xA1, 0x49, 0xFF, 0xDA, 0x38, 0x2E, 0x37, + 0xC6, 0xC7, 0x3C, 0x0C, 0x01, 0x4B, 0x84, 0xE1, 0xB6, 0x7F, 0xF6, 0x81, 0xF6, 0x82, 0xF6, 0x83, + 0xF6, 0x84, 0xF6, 0x85, 0xF7, 0x86, 0xF6, 0x87, 0xA6, 0x02, 0x50, 0x1F, 0x80, 0x3E, 0x8C, 0x02, + 0xF0, 0x88, 0xB0, 0x10, 0xF6, 0x89, 0xF6, 0x8A, 0x80, 0x40, 0x80, 0xA7, 0x2E, 0x47, 0xC6, 0xC8, + 0x12, 0x6F, 0x80, 0x1F, 0x49, 0xFF, 0xDA, 0x1B, 0x3C, 0x07, 0xF6, 0x47, 0x2E, 0x37, 0xC6, 0xC7, + 0xF0, 0x88, 0x3C, 0x07, 0xF6, 0x48, 0x44, 0x90, 0x00, 0x80, 0xB6, 0x7F, 0xF6, 0x81, 0xF6, 0x82, + 0x14, 0x9F, 0x80, 0x03, 0xF6, 0x84, 0xF6, 0x85, 0xF7, 0x86, 0xF6, 0x87, 0xF0, 0x89, 0xF6, 0x8A, + 0x80, 0x0A, 0x50, 0x1F, 0x80, 0x3E, 0x80, 0xA7, 0x2E, 0x47, 0xC6, 0xC8, 0x44, 0x22, 0x32, 0xE8, + 0x12, 0x6F, 0x80, 0x1F, 0x49, 0xFF, 0xD9, 0xFB, 0x2E, 0x37, 0xC6, 0xC7, 0x44, 0x02, 0x32, 0xE8, + 0xB6, 0x7F, 0xF6, 0x81, 0xF6, 0x82, 0x14, 0x9F, 0x80, 0x03, 0xF6, 0x84, 0xF6, 0x85, 0xF6, 0x86, + 0xF7, 0x87, 0xF6, 0x88, 0xF6, 0x89, 0xF6, 0x8A, 0x50, 0x1F, 0x80, 0x3E, 0x80, 0x40, 0x80, 0xA7, + 0x2E, 0x47, 0xC6, 0xC8, 0x12, 0x7F, 0x80, 0x1F, 0x49, 0xFF, 0xD9, 0xE1, 0x2E, 0x37, 0xC6, 0xC7, + 0xB0, 0x50, 0x85, 0x28, 0xB6, 0x7F, 0xF7, 0x81, 0xF3, 0x82, 0xF6, 0x83, 0xF6, 0x84, 0xF6, 0x85, + 0xF6, 0x86, 0x14, 0x9F, 0x80, 0x07, 0xF6, 0x88, 0xF6, 0x89, 0xF6, 0x8A, 0x80, 0x41, 0x80, 0xA7, + 0x2E, 0x47, 0xC6, 0xC8, 0x44, 0x02, 0x32, 0xE8, 0x49, 0xFF, 0xD9, 0xC9, 0x2E, 0x37, 0xC6, 0xC7, + 0xF7, 0x81, 0xB6, 0x7F, 0xF6, 0x82, 0xF6, 0x83, 0xF6, 0x84, 0xF6, 0x85, 0xF6, 0x86, 0xF6, 0x87, + 0xF6, 0x88, 0xF6, 0x89, 0xF7, 0x8A, 0xB0, 0x10, 0x80, 0x3C, 0x80, 0x5C, 0x80, 0xA7, 0x2E, 0x47, + 0xC6, 0xC8, 0x49, 0xFF, 0xD9, 0xB4, 0x2E, 0x37, 0xC6, 0xC7, 0xB0, 0x50, 0xB6, 0x7F, 0xF7, 0x81, + 0xF3, 0x82, 0xF6, 0x83, 0xF6, 0x84, 0xF6, 0x85, 0xF6, 0x86, 0x14, 0x9F, 0x80, 0x07, 0xF6, 0x88, + 0xF6, 0x89, 0xF6, 0x8A, 0x80, 0x0A, 0x80, 0x41, 0x80, 0xA7, 0x2E, 0x47, 0xC6, 0xC8, 0x49, 0xFF, + 0xD9, 0x9E, 0xF1, 0x0D, 0x2E, 0x37, 0xC6, 0xC7, 0xF7, 0x81, 0xF6, 0x82, 0xF6, 0x83, 0xF6, 0x84, + 0xF6, 0x85, 0xF6, 0x86, 0xF6, 0x87, 0xF6, 0x88, 0xF6, 0x89, 0xF7, 0x8A, 0xB6, 0x7F, 0xB0, 0x10, + 0x80, 0xA7, 0x2E, 0x47, 0xC6, 0xC8, 0x80, 0x41, 0x49, 0xFF, 0xD9, 0x89, 0x51, 0xFF, 0x85, 0x54, + 0x3A, 0x6F, 0xAA, 0x84, 0xDD, 0x9E, 0x3A, 0x6F, 0xAA, 0xBC, 0xEF, 0xD4, 0x81, 0x20, 0x50, 0xAF, + 0x80, 0x04, 0x84, 0x00, 0x80, 0xC1, 0x3E, 0x07, 0xEC, 0x62, 0x80, 0x4A, 0x04, 0x04, 0x80, 0x06, + 0x49, 0xFF, 0xFE, 0xBD, 0x87, 0x83, 0x3D, 0xEC, 0x01, 0x4B, 0x2E, 0x27, 0xEC, 0x62, 0x3C, 0x8C, + 0x02, 0xA8, 0x80, 0x26, 0x84, 0xA0, 0x2E, 0x07, 0xC6, 0xC7, 0xE2, 0xA0, 0xE8, 0x73, 0x38, 0x35, + 0x15, 0x11, 0x00, 0x0F, 0x00, 0x04, 0xE0, 0x03, 0xE8, 0x08, 0xA4, 0x08, 0x96, 0x03, 0x40, 0x00, + 0x0C, 0x16, 0x96, 0x03, 0xAC, 0x08, 0xD5, 0x03, 0x84, 0x00, 0xAC, 0x08, 0xA4, 0x08, 0x96, 0x03, + 0x4E, 0x04, 0x00, 0x03, 0xFE, 0x02, 0x5E, 0xF0, 0x00, 0x3D, 0xE9, 0x02, 0x84, 0x41, 0x84, 0xE0, + 0x2E, 0x07, 0xC6, 0xC8, 0xE2, 0xE0, 0xE8, 0x53, 0x2E, 0x07, 0xC6, 0xBA, 0x80, 0x85, 0xA4, 0xC8, + 0x42, 0x40, 0x1C, 0x73, 0xA4, 0x08, 0x97, 0x21, 0x96, 0x03, 0x96, 0xDB, 0x95, 0x21, 0x4E, 0x04, + 0x00, 0x26, 0x40, 0x64, 0x10, 0x00, 0xA4, 0x30, 0x02, 0xF0, 0x80, 0x00, 0x96, 0x03, 0x40, 0xF7, + 0x80, 0x11, 0x8A, 0x0F, 0x4E, 0x07, 0x00, 0x30, 0xA4, 0x30, 0xA4, 0xC8, 0x96, 0x03, 0x96, 0xDB, + 0x40, 0x31, 0xF0, 0x76, 0x8A, 0x03, 0x4E, 0x07, 0x00, 0x07, 0xA4, 0xC8, 0x96, 0xDB, 0x40, 0x31, + 0xF0, 0x76, 0xD5, 0x21, 0xA4, 0x08, 0x96, 0x03, 0x5E, 0xF0, 0x7F, 0x6A, 0xE8, 0x04, 0xA4, 0xC8, + 0x96, 0xDB, 0xD5, 0x19, 0xA4, 0xF0, 0x96, 0xDB, 0xD5, 0x16, 0xA4, 0x08, 0x96, 0x03, 0x4E, 0x07, + 0x00, 0x13, 0x40, 0x04, 0x10, 0x00, 0xA5, 0x80, 0x02, 0xF0, 0x80, 0x00, 0x97, 0xB3, 0x40, 0xF7, + 0x80, 0x11, 0x8A, 0xCF, 0x4E, 0x64, 0x00, 0x08, 0xA5, 0x80, 0x97, 0xB3, 0x4E, 0x67, 0x00, 0x04, + 0xA4, 0xC0, 0x96, 0xDB, 0x04, 0x04, 0x80, 0x05, 0x04, 0x64, 0x80, 0x06, 0x88, 0x04, 0x88, 0x86, + 0x8C, 0xE1, 0xA5, 0x20, 0x9A, 0xE3, 0x96, 0xDB, 0xAC, 0xC0, 0xD5, 0xAB, 0x8C, 0xA1, 0x8C, 0x22, + 0xD5, 0x8B, 0xEC, 0x2C, 0x3E, 0x27, 0xEC, 0x62, 0x3A, 0x6F, 0xAA, 0x84, 0xDD, 0x9E, 0x3B, 0xFF, + 0xFC, 0xBC, 0xEF, 0xF4, 0xB6, 0x1F, 0xF1, 0x81, 0x49, 0xFF, 0xFD, 0xA6, 0xB4, 0x1F, 0xF1, 0x01, + 0xEC, 0x0C, 0x3B, 0xFF, 0xFC, 0x84, 0x48, 0xFF, 0xFF, 0x60, 0x2E, 0x10, 0x05, 0x4D, 0x00, 0x30, + 0x00, 0x09, 0x10, 0x10, 0x04, 0x30, 0x2E, 0x10, 0x05, 0x4C, 0x50, 0x20, 0x04, 0x01, 0x10, 0x10, + 0x04, 0x2E, 0x2E, 0x10, 0x05, 0x4B, 0x44, 0x42, 0xCD, 0xEC, 0x10, 0x10, 0x04, 0x2F, 0x2E, 0x10, + 0x05, 0x4A, 0x10, 0x10, 0x04, 0x2D, 0x2E, 0x10, 0x05, 0x49, 0x10, 0x10, 0x04, 0x70, 0x2E, 0x10, + 0x05, 0x48, 0x10, 0x10, 0x04, 0x71, 0x2E, 0x10, 0x05, 0x47, 0x10, 0x10, 0x04, 0x72, 0x2E, 0x10, + 0x05, 0x46, 0x10, 0x10, 0x04, 0x73, 0x2E, 0x10, 0x05, 0x45, 0x10, 0x10, 0x00, 0xA5, 0x2E, 0x10, + 0x05, 0x44, 0x10, 0x10, 0x00, 0xAB, 0x2E, 0x10, 0x05, 0x43, 0x10, 0x10, 0x00, 0x9A, 0x84, 0x20, + 0xE2, 0x23, 0xE8, 0x07, 0x38, 0x52, 0x04, 0x00, 0x8C, 0x21, 0x18, 0x51, 0x00, 0x01, 0xD5, 0xF9, + 0x2E, 0x10, 0x05, 0x30, 0x10, 0x10, 0x00, 0xA4, 0x84, 0x20, 0x10, 0x10, 0x00, 0xB7, 0x3C, 0x0C, + 0x01, 0x56, 0x10, 0x10, 0x00, 0x51, 0xDD, 0x9E, 0xFC, 0x00, 0x49, 0xFF, 0xD5, 0x46, 0x84, 0x20, + 0x3C, 0x0E, 0x01, 0x56, 0x10, 0x10, 0x00, 0x50, 0x10, 0x10, 0x00, 0x51, 0x10, 0x10, 0x00, 0x52, + 0x10, 0x10, 0x00, 0x53, 0x10, 0x10, 0x00, 0x60, 0x10, 0x10, 0x00, 0x61, 0xFC, 0x80, 0xFC, 0x20, + 0x80, 0xC1, 0x84, 0x20, 0xAE, 0x40, 0xA4, 0x10, 0x80, 0xE2, 0x92, 0x0F, 0x5A, 0x08, 0x01, 0x07, + 0xA4, 0x70, 0x44, 0x0F, 0x80, 0x00, 0xFE, 0x0F, 0xAC, 0x30, 0xA4, 0x38, 0x92, 0x0F, 0xC8, 0x05, + 0xA4, 0x30, 0x54, 0x00, 0x7F, 0xFF, 0xAC, 0x30, 0xA4, 0x38, 0x92, 0x07, 0x96, 0x06, 0x5A, 0x08, + 0x01, 0x06, 0xA4, 0x30, 0x58, 0x00, 0x00, 0x80, 0xAC, 0x30, 0xA4, 0x38, 0x92, 0x07, 0x96, 0x06, + 0xC8, 0x06, 0xA4, 0x70, 0x44, 0x0F, 0xFF, 0x7F, 0xFE, 0x0E, 0xAC, 0x30, 0xA4, 0x38, 0x96, 0x06, + 0xC8, 0x05, 0xA4, 0x70, 0x84, 0x1E, 0xFE, 0x0E, 0xAC, 0x30, 0xA4, 0x38, 0x96, 0x06, 0x5A, 0x08, + 0x01, 0x06, 0xA4, 0x30, 0x58, 0x00, 0x00, 0x01, 0xAC, 0x30, 0xA4, 0x38, 0x92, 0x01, 0x96, 0x06, + 0xC8, 0x05, 0xA4, 0x70, 0x84, 0x1D, 0xFE, 0x0E, 0xAC, 0x30, 0xA4, 0x38, 0x92, 0x01, 0x96, 0x06, + 0x5A, 0x08, 0x01, 0x06, 0xA4, 0x30, 0x58, 0x00, 0x00, 0x02, 0xAC, 0x30, 0xA4, 0x38, 0x92, 0x06, + 0x96, 0x06, 0x5A, 0x08, 0x01, 0x06, 0xA4, 0x30, 0x58, 0x00, 0x00, 0x40, 0xAC, 0x30, 0xA4, 0x38, + 0x92, 0x06, 0x96, 0x06, 0xC8, 0x06, 0xA4, 0x70, 0x44, 0x0F, 0xFF, 0xBF, 0xFE, 0x0E, 0xAC, 0x30, + 0xA4, 0x38, 0x92, 0x0C, 0x96, 0x06, 0x5A, 0x08, 0x01, 0x09, 0xA4, 0x30, 0x58, 0x00, 0x10, 0x00, + 0xAC, 0x30, 0x80, 0x06, 0x49, 0xFF, 0xAD, 0xF6, 0xA4, 0x38, 0x92, 0x0C, 0x96, 0x06, 0xC8, 0x0D, + 0xA4, 0x70, 0x44, 0x0F, 0xEF, 0xFF, 0xFE, 0x0E, 0xAC, 0x30, 0x49, 0xFF, 0xDD, 0xE9, 0x3E, 0x00, + 0x06, 0x11, 0x80, 0x06, 0x49, 0xFF, 0xAD, 0xE6, 0xA4, 0x38, 0x92, 0x0D, 0x96, 0x06, 0x5A, 0x08, + 0x01, 0x06, 0xA4, 0x30, 0x58, 0x00, 0x20, 0x00, 0xAC, 0x30, 0xA4, 0x38, 0x92, 0x0D, 0x96, 0x06, + 0xC8, 0x06, 0xA4, 0x70, 0x44, 0x0F, 0xDF, 0xFF, 0xFE, 0x0E, 0xAC, 0x30, 0xA4, 0x38, 0x92, 0x02, + 0x96, 0x06, 0x5A, 0x08, 0x01, 0x06, 0xA4, 0x30, 0x58, 0x00, 0x00, 0x04, 0xAC, 0x30, 0xA4, 0x38, + 0x92, 0x02, 0x96, 0x06, 0xC8, 0x05, 0xA4, 0x70, 0x84, 0x1B, 0xFE, 0x0E, 0xAC, 0x30, 0xA4, 0x38, + 0x92, 0x0E, 0x96, 0x06, 0x5A, 0x08, 0x01, 0x06, 0xA4, 0x30, 0x58, 0x00, 0x40, 0x00, 0xAC, 0x30, + 0xA4, 0x38, 0x92, 0x0E, 0x96, 0x06, 0xC8, 0x06, 0xA4, 0x70, 0x44, 0x0F, 0xBF, 0xFF, 0xFE, 0x0E, + 0xAC, 0x30, 0xA4, 0x38, 0x92, 0x05, 0x96, 0x06, 0x5A, 0x08, 0x01, 0x06, 0xA4, 0x30, 0x58, 0x00, + 0x00, 0x20, 0xAC, 0x30, 0xA4, 0x38, 0x92, 0x05, 0x96, 0x06, 0xC8, 0x06, 0xA4, 0x70, 0x44, 0x0F, + 0xFF, 0xDF, 0xFE, 0x0E, 0xAC, 0x30, 0xFC, 0xA0, 0xFC, 0x00, 0x5A, 0x08, 0x06, 0x04, 0x84, 0x01, + 0xD5, 0x04, 0x5A, 0x08, 0x07, 0x06, 0x84, 0x00, 0x3E, 0x07, 0xEC, 0x16, 0xD5, 0x1C, 0x5A, 0x08, + 0x0D, 0x07, 0x84, 0x00, 0x3E, 0x07, 0xEC, 0x16, 0x84, 0x21, 0xD5, 0x07, 0x5A, 0x08, 0x0E, 0x0B, + 0x84, 0x01, 0x3E, 0x07, 0xEC, 0x16, 0x84, 0x20, 0x3E, 0x17, 0xEC, 0x54, 0x3E, 0x07, 0xEC, 0x45, + 0xD5, 0x0A, 0x5A, 0x08, 0x10, 0x04, 0x84, 0x01, 0xD5, 0x04, 0x5A, 0x08, 0x11, 0x05, 0x84, 0x00, + 0x3E, 0x07, 0xEC, 0x15, 0xFC, 0x80, 0x44, 0x33, 0xF0, 0x4A, 0x44, 0x40, 0x00, 0x55, 0x3C, 0x2D, + 0xFB, 0x64, 0xA6, 0x90, 0xCA, 0x03, 0xAF, 0x18, 0xD5, 0xFB, 0x3C, 0x2C, 0x01, 0x56, 0x10, 0x01, + 0x00, 0x53, 0xC9, 0x04, 0x44, 0x0F, 0xFF, 0xA0, 0xD5, 0x03, 0x44, 0x0F, 0xFF, 0xA1, 0x10, 0x01, + 0x00, 0x51, 0x2E, 0x07, 0xEC, 0x66, 0x5A, 0x08, 0x03, 0x05, 0x44, 0x0F, 0xFF, 0xB1, 0xD5, 0x03, + 0x44, 0x0F, 0xFF, 0xB0, 0x10, 0x01, 0x00, 0x52, 0x44, 0x30, 0x00, 0x55, 0x44, 0x23, 0xF0, 0x4A, + 0x3C, 0x0C, 0x01, 0x56, 0x00, 0x10, 0x00, 0x51, 0x5A, 0x10, 0xBB, 0x04, 0xAE, 0xD0, 0xD5, 0xF9, + 0x84, 0x20, 0x10, 0x10, 0x00, 0x51, 0x10, 0x10, 0x00, 0x52, 0xDD, 0x9E, 0x44, 0x13, 0xF0, 0x4A, + 0x44, 0x20, 0x00, 0x55, 0x3C, 0x0C, 0x01, 0x56, 0x00, 0x00, 0x00, 0x51, 0x5A, 0x08, 0xA0, 0x04, + 0xAE, 0x88, 0xD5, 0xF9, 0xDD, 0x9E, 0xFC, 0x00, 0x3C, 0x0C, 0x01, 0x56, 0x00, 0x00, 0x00, 0x51, + 0x5A, 0x08, 0xBB, 0x04, 0x49, 0xFF, 0xAB, 0x6F, 0x2E, 0x00, 0x06, 0x0D, 0x5A, 0x08, 0xA0, 0x05, + 0x44, 0x02, 0x40, 0x00, 0xD5, 0x08, 0x5A, 0x08, 0xA1, 0x05, 0x44, 0x02, 0x1B, 0x90, 0xD5, 0x03, + 0x44, 0x02, 0x0C, 0x60, 0x44, 0x12, 0x45, 0x10, 0x49, 0xFF, 0xD6, 0x5F, 0x3C, 0x0C, 0x01, 0x56, + 0x44, 0x1F, 0xFF, 0xA0, 0x10, 0x10, 0x00, 0x51, 0xFC, 0x80, 0x3C, 0x1C, 0x01, 0x56, 0x10, 0x00, + 0x80, 0x60, 0xDD, 0x9E, 0x3C, 0x0C, 0x01, 0x56, 0x00, 0x00, 0x00, 0x60, 0xDD, 0x9E, 0x3C, 0x1C, + 0x01, 0x56, 0x10, 0x00, 0x80, 0x61, 0x3C, 0x1D, 0xFA, 0xF9, 0x10, 0x00, 0x80, 0x3E, 0xDD, 0x9E, + 0x3C, 0x1C, 0x01, 0x56, 0x00, 0x00, 0x80, 0x50, 0x50, 0x00, 0x7F, 0xDF, 0xE6, 0x02, 0xE9, 0x04, + 0x84, 0x00, 0x10, 0x00, 0x80, 0x50, 0xDD, 0x9E, 0xFC, 0x00, 0x3C, 0x0C, 0x01, 0x56, 0x44, 0x1F, + 0xFF, 0xCC, 0x44, 0x20, 0x00, 0x55, 0x10, 0x10, 0x00, 0x51, 0x44, 0x13, 0xF0, 0x4A, 0x3C, 0x0C, + 0x01, 0x56, 0x00, 0x00, 0x00, 0x51, 0x5A, 0x00, 0xBB, 0x04, 0xAE, 0x88, 0xD5, 0xF9, 0x44, 0x00, + 0x00, 0x78, 0x49, 0xFF, 0xBF, 0x33, 0x84, 0x00, 0x3C, 0x0F, 0xFB, 0x6D, 0xFC, 0x80, 0x84, 0x21, + 0x3E, 0x17, 0xEC, 0x26, 0x3C, 0x1C, 0x01, 0x56, 0x88, 0x01, 0x00, 0x20, 0x00, 0x52, 0x3C, 0x2B, + 0xF6, 0x5A, 0x00, 0x10, 0x00, 0x53, 0x40, 0x10, 0xA0, 0x08, 0x88, 0x22, 0x3C, 0x1B, 0xF6, 0x5A, + 0x00, 0x10, 0x00, 0x54, 0x3C, 0x1B, 0xF6, 0x58, 0x00, 0x00, 0x00, 0x55, 0x40, 0x00, 0x20, 0x08, + 0x88, 0x01, 0x3C, 0x0B, 0xF6, 0x58, 0xDD, 0x9E, 0x3C, 0x1C, 0x01, 0x56, 0x84, 0x00, 0x3C, 0x0B, + 0xF6, 0x52, 0x00, 0x20, 0x80, 0x52, 0x84, 0x0A, 0xFE, 0x14, 0x3C, 0x0B, 0xF6, 0x50, 0x00, 0x00, + 0x80, 0x51, 0x5A, 0x08, 0xAB, 0x07, 0xFC, 0x00, 0x84, 0x02, 0x49, 0xFF, 0xFF, 0xD2, 0xFC, 0x80, + 0xDD, 0x9E, 0xFC, 0x00, 0x80, 0xC0, 0x49, 0xFF, 0xFF, 0x09, 0x84, 0x01, 0x5A, 0x68, 0x03, 0x05, + 0x49, 0xFF, 0x8F, 0x64, 0x80, 0x06, 0x50, 0x13, 0x7F, 0xF3, 0xE6, 0x22, 0xE9, 0x03, 0x5A, 0x68, + 0x02, 0x16, 0x3C, 0x0D, 0xFB, 0x4A, 0xA6, 0x41, 0x5A, 0x10, 0x03, 0x0D, 0x84, 0x20, 0x49, 0xFF, + 0xD7, 0xB3, 0x49, 0xFF, 0xA7, 0x79, 0x5A, 0x08, 0x02, 0x06, 0x3C, 0x0D, 0xFB, 0x4A, 0x84, 0x23, + 0xAE, 0x41, 0x84, 0x01, 0x3E, 0x00, 0x06, 0x36, 0x84, 0x02, 0xFC, 0x80, 0x3C, 0x0C, 0x01, 0x56, + 0x00, 0x00, 0x00, 0x50, 0x5A, 0x08, 0x13, 0x0B, 0xFC, 0x00, 0x49, 0xFF, 0xA7, 0x65, 0x5A, 0x00, + 0x02, 0x05, 0x84, 0x01, 0x3E, 0x07, 0xEC, 0x2E, 0xFC, 0x80, 0xDD, 0x9E, 0x40, 0x00, 0x04, 0x0E, + 0x96, 0x06, 0xDD, 0x9E, 0xFC, 0x00, 0x3C, 0x0C, 0x01, 0x56, 0x44, 0x1F, 0xFF, 0xAA, 0x10, 0x10, + 0x00, 0x51, 0x3C, 0x0C, 0x01, 0x56, 0x00, 0x00, 0x00, 0x51, 0x5A, 0x08, 0xAA, 0x07, 0x44, 0x00, + 0x00, 0x78, 0x49, 0xFF, 0xBE, 0xB3, 0xD5, 0xF6, 0x5A, 0x00, 0xDD, 0x04, 0x84, 0x01, 0xD5, 0x02, + 0x84, 0x03, 0xFC, 0x80, 0x5A, 0x08, 0x03, 0x1F, 0x00, 0x00, 0x80, 0xA2, 0x84, 0x41, 0x3E, 0x00, + 0x05, 0x55, 0x00, 0x00, 0x80, 0xA1, 0x10, 0x20, 0x80, 0xB6, 0x3E, 0x00, 0x05, 0x54, 0x00, 0x00, + 0x80, 0x9C, 0x3E, 0x00, 0x05, 0x53, 0x00, 0x00, 0x80, 0x9A, 0x3E, 0x00, 0x05, 0x52, 0x84, 0x00, + 0x10, 0x00, 0x80, 0xA2, 0x10, 0x00, 0x80, 0xA1, 0x10, 0x00, 0x80, 0x9C, 0x10, 0x00, 0x80, 0x9A, + 0xD5, 0x16, 0x5A, 0x08, 0x04, 0x19, 0x2E, 0x00, 0x05, 0x55, 0x10, 0x00, 0x80, 0xA2, 0x2E, 0x00, + 0x05, 0x54, 0x10, 0x00, 0x80, 0xA1, 0x2E, 0x00, 0x05, 0x53, 0x10, 0x00, 0x80, 0x9C, 0x2E, 0x00, + 0x05, 0x52, 0x10, 0x00, 0x80, 0x9A, 0x84, 0x00, 0x10, 0x00, 0x80, 0xB6, 0x3C, 0x1C, 0x01, 0x56, + 0x10, 0x00, 0x80, 0x51, 0xDD, 0x9E, 0xFC, 0x00, 0x5A, 0x08, 0x01, 0x6D, 0x00, 0x00, 0x84, 0x30, + 0x50, 0x30, 0x84, 0x01, 0x3E, 0x00, 0x05, 0x4D, 0x00, 0x00, 0x84, 0x2E, 0x00, 0x40, 0x80, 0x09, + 0x3E, 0x00, 0x05, 0x4C, 0x00, 0x00, 0x84, 0x2F, 0x80, 0x43, 0x3E, 0x00, 0x05, 0x4B, 0x00, 0x00, + 0x84, 0x2D, 0x44, 0x52, 0xCD, 0xEC, 0x3E, 0x00, 0x05, 0x4A, 0x00, 0x00, 0x84, 0x70, 0x3E, 0x00, + 0x05, 0x49, 0x00, 0x00, 0x84, 0x71, 0x3E, 0x00, 0x05, 0x48, 0x00, 0x00, 0x84, 0x72, 0x3E, 0x00, + 0x05, 0x47, 0x00, 0x00, 0x84, 0x73, 0x3E, 0x00, 0x05, 0x46, 0x00, 0x00, 0x80, 0xA5, 0x3E, 0x00, + 0x05, 0x45, 0x00, 0x00, 0x80, 0xAB, 0x3E, 0x00, 0x05, 0x44, 0x00, 0x00, 0x80, 0x9A, 0x3E, 0x00, + 0x05, 0x43, 0x84, 0x00, 0xE2, 0x04, 0xE8, 0x07, 0x08, 0x61, 0x00, 0x01, 0x38, 0x62, 0x80, 0x08, + 0x8C, 0x01, 0xD5, 0xF9, 0x00, 0x00, 0x80, 0xA4, 0x84, 0x41, 0x3E, 0x00, 0x05, 0x30, 0x84, 0x00, + 0x10, 0x20, 0x84, 0x30, 0x10, 0x20, 0x84, 0x2E, 0x10, 0x20, 0x84, 0x2F, 0x10, 0x00, 0x84, 0x2D, + 0x10, 0x00, 0x84, 0x70, 0x10, 0x00, 0x84, 0x71, 0x10, 0x00, 0x84, 0x72, 0x10, 0x20, 0x84, 0x73, + 0x10, 0x00, 0x80, 0xA5, 0x10, 0x00, 0x80, 0xAB, 0x10, 0x00, 0x80, 0x9A, 0x84, 0x4A, 0x84, 0x00, + 0xE2, 0x04, 0xE8, 0x05, 0x18, 0x21, 0x80, 0x01, 0x8C, 0x01, 0xD5, 0xFB, 0x84, 0x00, 0x84, 0x41, + 0x10, 0x00, 0x80, 0xA4, 0x10, 0x20, 0x80, 0xB7, 0x3C, 0x1C, 0x01, 0x56, 0x10, 0x00, 0x80, 0x51, + 0xD5, 0x06, 0x5A, 0x08, 0x02, 0x05, 0x80, 0x01, 0x49, 0xFF, 0xFC, 0xF9, 0xFC, 0x80, 0x00, 0x00, + 0xFC, 0x01, 0x84, 0x01, 0x10, 0x0F, 0x80, 0x07, 0x5A, 0x10, 0x01, 0x06, 0x5A, 0x10, 0x02, 0x0E, + 0x48, 0x00, 0x00, 0xB4, 0x84, 0x0A, 0x10, 0x0F, 0x80, 0x07, 0x3C, 0x0C, 0x01, 0x56, 0x84, 0x20, + 0x10, 0x10, 0x00, 0x51, 0x48, 0x00, 0x00, 0xAC, 0x3C, 0x6C, 0x01, 0x56, 0x84, 0x0A, 0x10, 0x0F, + 0x80, 0x07, 0x00, 0x03, 0x00, 0x52, 0x8E, 0x01, 0xE6, 0x09, 0x4E, 0xF2, 0x00, 0x9C, 0x44, 0xF1, + 0x18, 0x3C, 0x38, 0x07, 0x81, 0x01, 0x40, 0xF0, 0x3C, 0x00, 0xDD, 0x0F, 0x12, 0x00, 0x1E, 0x00, + 0x28, 0x00, 0x66, 0x00, 0x26, 0x01, 0x78, 0x00, 0xBC, 0x00, 0xDC, 0x00, 0x14, 0x01, 0x84, 0x01, + 0x44, 0x12, 0x8F, 0x70, 0x49, 0xFF, 0xFF, 0x59, 0xD5, 0x2A, 0x44, 0x02, 0x8F, 0x70, 0x49, 0xFF, + 0xFC, 0xBE, 0xD5, 0x25, 0x2E, 0x07, 0xC7, 0x5A, 0x84, 0x21, 0x3E, 0x00, 0x05, 0x55, 0x2E, 0x07, + 0xC7, 0x59, 0x3E, 0x17, 0xC7, 0x6E, 0x3E, 0x00, 0x05, 0x54, 0x2E, 0x07, 0xC7, 0x54, 0x3E, 0x00, + 0x05, 0x53, 0x2E, 0x07, 0xC7, 0x52, 0x3E, 0x00, 0x05, 0x52, 0x84, 0x00, 0x3E, 0x07, 0xC7, 0x5A, + 0x3E, 0x07, 0xC7, 0x59, 0x3E, 0x07, 0xC7, 0x54, 0x3E, 0x07, 0xC7, 0x52, 0x10, 0x03, 0x00, 0x51, + 0xD5, 0x07, 0x84, 0x04, 0x44, 0x12, 0x8F, 0x70, 0x49, 0xFF, 0xFE, 0xF6, 0x84, 0x00, 0x10, 0x03, + 0x00, 0x52, 0xD5, 0x5D, 0x84, 0x00, 0x80, 0x40, 0x84, 0xC0, 0x3C, 0x1D, 0xFB, 0x4A, 0x44, 0x32, + 0xB5, 0x0D, 0x3E, 0x67, 0xC7, 0xE6, 0x3E, 0x67, 0xEC, 0x45, 0x49, 0xFF, 0x90, 0x6F, 0x3C, 0x07, + 0xF6, 0x62, 0x49, 0xFF, 0x96, 0xE9, 0x2E, 0x07, 0xEC, 0x66, 0x44, 0x12, 0x8F, 0x70, 0x44, 0x22, + 0xB4, 0xFD, 0x50, 0x3F, 0x80, 0x07, 0x3C, 0x4C, 0x01, 0x56, 0x49, 0xFF, 0x96, 0x98, 0x3C, 0x0C, + 0x01, 0x56, 0x10, 0x60, 0x00, 0x52, 0xD5, 0x3B, 0x84, 0x01, 0x3E, 0x07, 0xC7, 0xE6, 0x84, 0x00, + 0x80, 0x40, 0x3C, 0x1D, 0xFB, 0x4A, 0x44, 0x32, 0xB5, 0x0D, 0x49, 0xFF, 0x90, 0x4F, 0x3C, 0x07, + 0xE3, 0xDD, 0x49, 0xFF, 0x96, 0xC9, 0xD5, 0x10, 0x80, 0x06, 0x49, 0xFF, 0x96, 0x54, 0xC8, 0x27, + 0x84, 0x03, 0x3E, 0x07, 0xC7, 0xE6, 0x3C, 0x0C, 0x01, 0x56, 0x44, 0x12, 0x8F, 0x70, 0x00, 0x00, + 0x00, 0x53, 0x49, 0xFF, 0x95, 0xD7, 0x2E, 0x07, 0xEC, 0x66, 0x44, 0x12, 0x8F, 0x70, 0x44, 0x22, + 0xB4, 0xFD, 0x50, 0x3F, 0x80, 0x07, 0x3C, 0x4C, 0x01, 0x56, 0x49, 0xFF, 0x96, 0x68, 0xD5, 0x0F, + 0x44, 0x02, 0x90, 0x72, 0x80, 0x26, 0x49, 0xFF, 0x92, 0x2F, 0x84, 0x01, 0x10, 0x0F, 0x80, 0x07, + 0xD5, 0x06, 0x84, 0x01, 0x10, 0x0F, 0x80, 0x07, 0x84, 0x02, 0xAE, 0x10, 0x00, 0x0F, 0x80, 0x07, + 0x5A, 0x08, 0x0A, 0x0D, 0x49, 0xFF, 0xFE, 0x78, 0x3C, 0x1D, 0xFB, 0x64, 0x10, 0x0F, 0x80, 0x07, + 0x84, 0x01, 0xAE, 0x08, 0x3C, 0x1D, 0xFB, 0x59, 0xAE, 0x08, 0x00, 0x0F, 0x80, 0x07, 0xFC, 0x81, + 0x5A, 0x00, 0x01, 0x08, 0x5A, 0x08, 0x03, 0x0B, 0xA4, 0x08, 0x58, 0x00, 0x00, 0x04, 0xD5, 0x04, + 0xA4, 0x88, 0x84, 0x1B, 0xFE, 0x16, 0xAC, 0x08, 0xDD, 0x9E, 0x84, 0x02, 0xAE, 0x10, 0xDD, 0x9E, + 0xFC, 0x40, 0x9F, 0x01, 0xE6, 0x8F, 0x4E, 0xF2, 0x00, 0x83, 0x80, 0x01, 0x44, 0xF1, 0x19, 0xCC, + 0x38, 0x47, 0x90, 0x00, 0x40, 0xF2, 0x3C, 0x00, 0x4A, 0x00, 0x3C, 0x00, 0x10, 0x14, 0x18, 0x86, + 0xB6, 0xBC, 0xF0, 0xC4, 0xD2, 0xE0, 0xE4, 0xE8, 0xF0, 0xF4, 0xF4, 0x00, 0x84, 0x06, 0xD5, 0x72, + 0x84, 0x07, 0xD5, 0x70, 0x44, 0x73, 0xF0, 0x4A, 0x44, 0x90, 0x00, 0x55, 0x49, 0xFF, 0xE0, 0xB1, + 0x80, 0xC0, 0x5A, 0x00, 0x02, 0x05, 0x10, 0x93, 0x80, 0x00, 0xD5, 0xF9, 0x84, 0x01, 0x49, 0xFF, + 0xE0, 0xBB, 0x49, 0xFF, 0xE0, 0x7A, 0x3C, 0x0E, 0x03, 0x2F, 0x49, 0xFF, 0xE0, 0x80, 0x3C, 0x0E, + 0x03, 0x30, 0x49, 0xFF, 0xE0, 0x8E, 0x3E, 0x00, 0x0C, 0xC5, 0x49, 0xFF, 0xE0, 0x96, 0x3E, 0x00, + 0x0C, 0xC4, 0x49, 0xFF, 0xE0, 0x8C, 0x3E, 0x00, 0x0C, 0xC6, 0x84, 0x21, 0x44, 0x02, 0xD5, 0x74, + 0x49, 0xFF, 0xA4, 0x98, 0x80, 0x06, 0x49, 0xFF, 0xE0, 0x9F, 0x44, 0x63, 0xF0, 0x4A, 0x44, 0x70, + 0x00, 0x55, 0x49, 0xFF, 0xE0, 0x86, 0xC0, 0x03, 0xAF, 0xF0, 0xD5, 0xFC, 0x49, 0xFF, 0xE0, 0x94, + 0xD5, 0x38, 0x3C, 0x2C, 0x01, 0x56, 0x84, 0x2D, 0xAE, 0x41, 0x84, 0x26, 0xAE, 0x40, 0x84, 0x20, + 0x10, 0x11, 0x00, 0x50, 0x44, 0x23, 0xF0, 0x10, 0xAE, 0x50, 0x84, 0x21, 0x49, 0xFF, 0xD5, 0x8C, + 0x84, 0x20, 0x84, 0x02, 0x80, 0x41, 0x84, 0x61, 0x80, 0x81, 0x80, 0xA1, 0x49, 0xFF, 0xD1, 0xD4, + 0xD5, 0x20, 0x84, 0x01, 0xAE, 0x10, 0xD5, 0x11, 0x84, 0x01, 0xAE, 0x10, 0x84, 0x0E, 0xD5, 0x1A, + 0x84, 0x01, 0xAE, 0x10, 0x84, 0x01, 0x49, 0xFF, 0x8D, 0x2C, 0x84, 0x02, 0xD5, 0x13, 0x84, 0x01, + 0xAE, 0x10, 0x84, 0x00, 0x49, 0xFF, 0x8D, 0x25, 0x84, 0x0D, 0xD5, 0x0C, 0xFA, 0x00, 0xD5, 0x0A, + 0xFA, 0x01, 0xD5, 0x08, 0x84, 0x00, 0x49, 0xFF, 0xA8, 0xFD, 0xD5, 0x03, 0x84, 0x02, 0xAE, 0x18, + 0x84, 0x01, 0xFC, 0xC0, 0xFC, 0x00, 0x9E, 0xC1, 0xE6, 0x6E, 0xE8, 0x50, 0x80, 0x01, 0x44, 0xF1, + 0x1A, 0xDC, 0x38, 0x37, 0x8C, 0x00, 0x40, 0xF1, 0xBC, 0x00, 0xDD, 0x0F, 0x0E, 0x16, 0x8E, 0x8E, + 0x8E, 0x8E, 0x26, 0x2E, 0x8E, 0x36, 0x3E, 0x4E, 0x60, 0x74, 0xA4, 0x48, 0x58, 0x10, 0x90, 0x00, + 0xD5, 0x05, 0xA4, 0x88, 0x44, 0x1F, 0xEF, 0xFF, 0xFE, 0x56, 0xAC, 0x40, 0x49, 0xFF, 0xAA, 0x22, + 0xD5, 0x37, 0xA4, 0x48, 0x58, 0x10, 0x80, 0x80, 0xD5, 0x18, 0xA4, 0x88, 0x44, 0x1F, 0xFF, 0x7F, + 0xD5, 0x0B, 0xA4, 0x88, 0x84, 0x3D, 0xFE, 0x56, 0xD5, 0x0C, 0xA4, 0x48, 0x58, 0x10, 0x80, 0x02, + 0xAC, 0x40, 0xA4, 0x80, 0x84, 0x3E, 0xFE, 0x56, 0xD5, 0x08, 0xA4, 0x48, 0x58, 0x10, 0x80, 0x02, + 0xAC, 0x40, 0xA4, 0x40, 0x58, 0x10, 0x80, 0x01, 0xAC, 0x40, 0xD5, 0x1A, 0xA4, 0x48, 0x58, 0x10, + 0x80, 0x40, 0xAC, 0x40, 0x84, 0x00, 0x3C, 0x0E, 0x01, 0x87, 0x44, 0x00, 0x07, 0x08, 0xD5, 0x0B, + 0xA4, 0x88, 0x44, 0x1F, 0xFF, 0xBF, 0xFE, 0x56, 0xAC, 0x40, 0x84, 0x00, 0x3C, 0x0E, 0x01, 0x87, + 0x44, 0x00, 0x00, 0xB4, 0x3C, 0x0B, 0xE5, 0x9A, 0xD5, 0x03, 0x84, 0x02, 0xAE, 0x10, 0xFC, 0x80, + 0xFC, 0x42, 0xA7, 0x49, 0x3C, 0x6C, 0x01, 0x56, 0x5A, 0x58, 0x04, 0x11, 0x2E, 0x07, 0xEC, 0x75, + 0x5A, 0x00, 0x01, 0x0D, 0x00, 0x03, 0x00, 0x50, 0x54, 0x00, 0x00, 0xF0, 0x5A, 0x00, 0x10, 0x07, + 0x44, 0x00, 0x00, 0x55, 0x3E, 0x07, 0xEC, 0x6D, 0xD5, 0x1F, 0x00, 0x03, 0x00, 0x50, 0x81, 0x24, + 0x80, 0xE3, 0xB6, 0x5F, 0xF1, 0x81, 0xC0, 0x03, 0x5A, 0x08, 0xFB, 0x1A, 0x2E, 0x00, 0x06, 0x0D, + 0xC0, 0x07, 0x84, 0x00, 0x3E, 0x00, 0x06, 0x0D, 0x84, 0x00, 0x49, 0xFF, 0xA8, 0x7B, 0xB4, 0x1F, + 0x44, 0x12, 0xB4, 0xE8, 0x49, 0xFF, 0xD2, 0x1A, 0x44, 0x00, 0x00, 0x55, 0x3E, 0x07, 0xEC, 0x6D, + 0x84, 0x00, 0x3E, 0x07, 0xEC, 0x5C, 0x84, 0x01, 0x48, 0x00, 0x01, 0xB7, 0x5A, 0x50, 0x01, 0x09, + 0x49, 0xFF, 0xA4, 0x9A, 0x5A, 0x08, 0x02, 0x05, 0x84, 0x01, 0x49, 0xFF, 0xA6, 0xBF, 0xB4, 0x1F, + 0x44, 0x12, 0xB4, 0xE8, 0x49, 0xFF, 0xD1, 0xCE, 0x3C, 0x3C, 0x01, 0x56, 0x84, 0x00, 0x3E, 0x07, + 0xEC, 0x70, 0x00, 0x21, 0x80, 0x50, 0x84, 0x21, 0x54, 0x61, 0x00, 0x0F, 0x92, 0x44, 0x8E, 0x41, + 0x84, 0x00, 0xE6, 0x4B, 0x00, 0xA1, 0x80, 0x51, 0x10, 0x1F, 0x80, 0x0F, 0x3C, 0x0F, 0xFB, 0x76, + 0x4E, 0xF2, 0x01, 0x67, 0x44, 0xF1, 0x1C, 0x34, 0x38, 0x27, 0x89, 0x01, 0x40, 0xF1, 0x3C, 0x00, + 0x4A, 0x00, 0x3C, 0x00, 0x16, 0x00, 0x3C, 0x00, 0x58, 0x01, 0x76, 0x01, 0x82, 0x02, 0x96, 0x02, + 0xAA, 0x02, 0xBA, 0x02, 0xBA, 0x02, 0xB6, 0x02, 0xC4, 0x02, 0x44, 0x02, 0xB4, 0xC2, 0x44, 0x12, + 0xB5, 0x52, 0x49, 0xFF, 0xD1, 0xE2, 0xB4, 0x1F, 0x44, 0x12, 0xB4, 0xE8, 0x49, 0xFF, 0xD1, 0x9A, + 0x80, 0x06, 0x80, 0x2A, 0xF2, 0x01, 0x49, 0xFF, 0x9C, 0x4B, 0x84, 0x00, 0x48, 0x00, 0x01, 0x42, + 0x8E, 0xC1, 0xE6, 0xC6, 0x3E, 0x17, 0xEC, 0x70, 0x4E, 0xF2, 0x00, 0x85, 0x44, 0xF1, 0x1C, 0x8C, + 0x38, 0x67, 0x98, 0x00, 0x40, 0xF3, 0x3C, 0x00, 0x4A, 0x00, 0x3C, 0x00, 0x06, 0x24, 0x42, 0xC6, + 0xD2, 0x4E, 0x84, 0x00, 0x10, 0x0F, 0x80, 0x0F, 0x84, 0x01, 0x3E, 0x07, 0xEC, 0x5C, 0x2E, 0x07, + 0xEC, 0x16, 0x4E, 0x03, 0x01, 0x30, 0x84, 0x1F, 0x3C, 0x0E, 0x01, 0x87, 0x48, 0x00, 0x01, 0x2B, + 0x84, 0x00, 0x10, 0x0F, 0x80, 0x0F, 0x84, 0x01, 0x3E, 0x07, 0xEC, 0x5C, 0x2E, 0x07, 0xEC, 0x16, + 0x4E, 0x03, 0x01, 0x23, 0x84, 0x1F, 0x3C, 0x0E, 0x01, 0x87, 0x48, 0x00, 0x01, 0x1E, 0x84, 0x01, + 0x3E, 0x07, 0xEC, 0x5C, 0x84, 0xC2, 0x48, 0x00, 0x01, 0x1D, 0x84, 0x00, 0x10, 0x0F, 0x80, 0x0F, + 0x84, 0x01, 0x3E, 0x07, 0xEC, 0x5C, 0x00, 0x01, 0x80, 0x52, 0x50, 0x00, 0x00, 0x56, 0x96, 0x00, + 0xE6, 0x02, 0xE8, 0x27, 0x00, 0x11, 0x80, 0x53, 0x44, 0x0F, 0xFF, 0xA0, 0xFE, 0x0F, 0x3E, 0x00, + 0x06, 0x0D, 0x49, 0xFF, 0xA7, 0x60, 0x84, 0x01, 0x49, 0xFF, 0xA7, 0xD4, 0x3C, 0x0C, 0x01, 0x56, + 0x00, 0x00, 0x00, 0x52, 0x5A, 0x08, 0xAA, 0x05, 0x44, 0x00, 0x45, 0x10, 0xD5, 0x0B, 0x2E, 0x07, + 0xC6, 0xBB, 0x2E, 0x17, 0xC6, 0xBA, 0x92, 0x01, 0xFE, 0x0C, 0x50, 0x00, 0x22, 0x88, 0x94, 0x01, + 0x96, 0x01, 0x49, 0xFF, 0xA7, 0x44, 0x3C, 0x0C, 0x01, 0x56, 0x84, 0x20, 0x10, 0x10, 0x00, 0x52, + 0x2E, 0x07, 0xEC, 0x16, 0x4E, 0x03, 0x00, 0xE3, 0x84, 0x1F, 0x3C, 0x0E, 0x01, 0x87, 0x48, 0x00, + 0x00, 0xDE, 0x44, 0x00, 0x00, 0x69, 0x49, 0xFF, 0xA7, 0x85, 0x48, 0x00, 0x00, 0xCD, 0x84, 0x00, + 0x10, 0x0F, 0x80, 0x0F, 0x84, 0x01, 0x3E, 0x07, 0xEC, 0x5C, 0x00, 0x01, 0x80, 0x55, 0x00, 0x11, + 0x80, 0x54, 0x40, 0x00, 0x20, 0x08, 0x88, 0x01, 0x3C, 0x0B, 0xF6, 0x4F, 0xFA, 0xC2, 0x48, 0x00, + 0x00, 0xC9, 0x84, 0x00, 0x3E, 0x07, 0xEC, 0x70, 0x48, 0x00, 0x00, 0xB3, 0x84, 0x02, 0x3E, 0x07, + 0xEC, 0x00, 0x80, 0x26, 0x84, 0x01, 0x50, 0x2F, 0x80, 0x0F, 0x49, 0xFF, 0xFD, 0x2B, 0x80, 0xC0, + 0x84, 0x05, 0x3E, 0x07, 0xEC, 0x00, 0x48, 0x00, 0x00, 0xB5, 0x2E, 0x17, 0xEC, 0x10, 0x10, 0x0F, + 0x80, 0x0F, 0x84, 0x01, 0x3E, 0x07, 0xEC, 0x70, 0x5A, 0x18, 0x01, 0x04, 0x48, 0x00, 0x00, 0xA9, + 0x3E, 0x07, 0xEC, 0x10, 0x3E, 0x07, 0xEC, 0x00, 0x9E, 0x31, 0xE6, 0x0C, 0xE8, 0x5F, 0x44, 0xF1, + 0x1D, 0xDC, 0x38, 0x07, 0x80, 0x00, 0x40, 0xF0, 0x3C, 0x00, 0xDD, 0x0F, 0x0C, 0xAE, 0x4A, 0xAE, + 0x4A, 0xAE, 0x8E, 0xAE, 0xAE, 0xAE, 0x1C, 0x14, 0x84, 0x01, 0x3E, 0x07, 0xEC, 0x5B, 0xD5, 0x51, + 0x84, 0x01, 0x3E, 0x07, 0xEC, 0x42, 0xD5, 0x4D, 0x84, 0x01, 0x84, 0xC0, 0x3E, 0x07, 0xEC, 0x7B, + 0x3E, 0x67, 0xEC, 0x16, 0x49, 0xFF, 0xFB, 0xE2, 0x3C, 0x1D, 0xFB, 0x4D, 0x3E, 0x60, 0x06, 0x2C, + 0xA4, 0x08, 0x58, 0x00, 0x00, 0x20, 0xAC, 0x08, 0x3C, 0x03, 0xF6, 0xCC, 0x58, 0x00, 0x00, 0x20, + 0x3C, 0x0B, 0xF6, 0xCC, 0xD5, 0x36, 0x80, 0x0A, 0x80, 0x26, 0x50, 0x2F, 0x80, 0x0F, 0x49, 0xFF, + 0xCD, 0xEB, 0x00, 0x0F, 0x80, 0x0F, 0x5A, 0x00, 0x02, 0x2D, 0x3C, 0x2C, 0x01, 0x56, 0x00, 0x01, + 0x00, 0x55, 0x00, 0x31, 0x00, 0x54, 0x40, 0x00, 0x20, 0x08, 0x00, 0x11, 0x00, 0x52, 0x88, 0x03, + 0x44, 0x32, 0x00, 0x00, 0xFE, 0xC7, 0x00, 0x01, 0x00, 0x51, 0x80, 0x46, 0x3E, 0x17, 0xEC, 0x32, + 0x3C, 0x3F, 0xFB, 0x58, 0x49, 0xFF, 0xCD, 0xE4, 0xD5, 0x14, 0x80, 0x0A, 0x84, 0x27, 0x50, 0x2F, + 0x80, 0x0F, 0x49, 0xFF, 0xCD, 0xC9, 0x00, 0x0F, 0x80, 0x0F, 0x5A, 0x00, 0x02, 0x0B, 0x84, 0x01, + 0x3E, 0x07, 0xEC, 0x52, 0x49, 0xFF, 0xFB, 0xA2, 0xD5, 0x04, 0x84, 0x02, 0x10, 0x0F, 0x80, 0x0F, + 0x00, 0x0F, 0x80, 0x0F, 0x84, 0xC9, 0x5A, 0x08, 0x02, 0x0C, 0x3C, 0x1C, 0x01, 0x56, 0x84, 0x00, + 0x3E, 0x07, 0xEC, 0x70, 0x3E, 0x07, 0xEC, 0x10, 0x10, 0x00, 0x80, 0x51, 0x84, 0xC1, 0x84, 0x00, + 0x3C, 0x0F, 0xFB, 0x85, 0xD5, 0x2E, 0xFD, 0x03, 0x50, 0x2F, 0x80, 0x0F, 0x49, 0xFF, 0xFD, 0x6A, + 0x00, 0x0F, 0x80, 0x0F, 0x5A, 0x08, 0x02, 0x1A, 0xD5, 0x16, 0x80, 0x06, 0xF1, 0x01, 0x44, 0x22, + 0xB5, 0x28, 0x50, 0x3F, 0x80, 0x0F, 0x49, 0xFF, 0xFD, 0x6D, 0x97, 0x80, 0xD5, 0x1A, 0xFD, 0x03, + 0x50, 0x2F, 0x80, 0x0F, 0x49, 0xFF, 0xFD, 0xF0, 0xD5, 0xEC, 0x5A, 0x60, 0x01, 0x13, 0x84, 0x02, + 0x10, 0x0F, 0x80, 0x0F, 0x84, 0xC1, 0xD5, 0x0D, 0xA4, 0x38, 0x84, 0xCB, 0x12, 0x04, 0x80, 0x00, + 0xD5, 0x08, 0x84, 0xC4, 0xD5, 0x06, 0x84, 0xC5, 0xD5, 0x04, 0xFA, 0xC9, 0xD5, 0x02, 0x84, 0xC9, + 0x00, 0x0F, 0x80, 0x0F, 0x84, 0x20, 0x5A, 0x00, 0x01, 0x05, 0x5A, 0x08, 0x02, 0x07, 0x84, 0x3B, + 0x3C, 0x0C, 0x01, 0x56, 0x10, 0x10, 0x00, 0x50, 0x2E, 0x07, 0xEC, 0x70, 0xC8, 0x0C, 0x44, 0x02, + 0xB4, 0xC2, 0x44, 0x12, 0xB5, 0x52, 0x49, 0xFF, 0xD0, 0x70, 0xB4, 0x1F, 0x44, 0x12, 0xB4, 0xE8, + 0x49, 0xFF, 0xD0, 0x5C, 0x80, 0x06, 0xFC, 0xC2, 0x5A, 0x08, 0x07, 0x33, 0x8E, 0x27, 0xE6, 0x28, + 0xE8, 0x3E, 0x44, 0xF1, 0x1F, 0x60, 0x38, 0x17, 0x84, 0x00, 0x40, 0xF0, 0xBC, 0x00, 0xDD, 0x0F, + 0x08, 0x10, 0x6C, 0x18, 0x20, 0x2E, 0x3E, 0x46, 0xA4, 0x10, 0x58, 0x00, 0x00, 0x80, 0xD5, 0x2D, + 0xA4, 0x50, 0x44, 0x0F, 0xFF, 0x7F, 0xD5, 0x28, 0xA4, 0x50, 0x84, 0x1D, 0xFE, 0x0E, 0xD5, 0x0B, + 0xA4, 0x10, 0x58, 0x00, 0x00, 0x02, 0xAC, 0x10, 0xA4, 0x50, 0x84, 0x1E, 0xD5, 0x1D, 0xA4, 0x10, + 0x58, 0x00, 0x00, 0x02, 0xAC, 0x10, 0xA4, 0x10, 0x58, 0x00, 0x00, 0x01, 0xD5, 0x16, 0xA4, 0x10, + 0x58, 0x00, 0x00, 0x40, 0xD5, 0x12, 0xA4, 0x50, 0x44, 0x0F, 0xFF, 0xBF, 0xD5, 0x0D, 0x5A, 0x08, + 0x05, 0x13, 0x5A, 0x10, 0x01, 0x08, 0x5A, 0x18, 0x03, 0x0B, 0xA4, 0x10, 0x58, 0x00, 0x00, 0x04, + 0xD5, 0x04, 0xA4, 0x50, 0x84, 0x1B, 0xFE, 0x0E, 0xAC, 0x10, 0xDD, 0x9E, 0x44, 0x02, 0x2D, 0x50, + 0x84, 0x3B, 0xAE, 0x40, 0xDD, 0x9E, 0x92, 0x00, 0xFC, 0x41, 0x81, 0x21, 0x44, 0x12, 0x2D, 0x50, + 0xB6, 0x1F, 0xF2, 0x81, 0xA6, 0x08, 0xA7, 0x88, 0x44, 0x12, 0x2D, 0x51, 0x92, 0x04, 0xA7, 0xC8, + 0x97, 0x9F, 0x97, 0xF8, 0x5A, 0x08, 0x01, 0x1D, 0x9E, 0x31, 0xE6, 0x02, 0xE8, 0x12, 0x44, 0x02, + 0xB4, 0xC2, 0x44, 0x12, 0xB5, 0x52, 0x49, 0xFF, 0xD0, 0x08, 0x44, 0x02, 0xB4, 0xE1, 0x44, 0x12, + 0xB4, 0xE8, 0x49, 0xFF, 0xCF, 0xBF, 0xFD, 0x03, 0xB4, 0x5F, 0x49, 0xFF, 0x9A, 0x71, 0xD5, 0x1C, + 0x5A, 0x68, 0x03, 0x1B, 0x49, 0xFF, 0xA2, 0x78, 0x5A, 0x08, 0x02, 0x17, 0xD5, 0xE9, 0x5A, 0x00, + 0x0B, 0x06, 0x54, 0x10, 0x00, 0x0D, 0x5A, 0x18, 0x05, 0x10, 0x44, 0x72, 0x2D, 0x50, 0x84, 0x20, + 0xAE, 0x78, 0xF2, 0x01, 0x80, 0x26, 0x49, 0xFF, 0xFF, 0x81, 0xA6, 0x38, 0x5A, 0x00, 0xFB, 0x05, + 0x84, 0x01, 0x10, 0x04, 0x80, 0x00, 0xFC, 0xC1, 0x3C, 0x0E, 0x01, 0x67, 0xDD, 0x9E, 0x3C, 0x0E, + 0x01, 0x66, 0xDD, 0x9E, 0xFC, 0x20, 0x3C, 0x6C, 0x01, 0x66, 0x84, 0xE1, 0xA7, 0x72, 0xA7, 0xB3, + 0xC2, 0x02, 0x84, 0xFF, 0xC9, 0x08, 0x9E, 0x69, 0xFF, 0x44, 0x42, 0x51, 0x04, 0x73, 0xB6, 0xA3, + 0x88, 0xA7, 0xD5, 0x0B, 0x9E, 0x71, 0xFE, 0x8C, 0x80, 0x20, 0x42, 0x11, 0x14, 0x73, 0x88, 0x47, + 0x42, 0x01, 0x14, 0x73, 0xB6, 0x23, 0x80, 0xA0, 0xB6, 0xA4, 0xFC, 0xA0, 0xFC, 0x44, 0x84, 0xC0, + 0x81, 0x05, 0x83, 0x80, 0x81, 0x41, 0xF2, 0x82, 0xF3, 0x81, 0x80, 0xE4, 0x80, 0xA3, 0x81, 0x26, + 0xE2, 0xE5, 0xE9, 0x14, 0x80, 0x05, 0xF1, 0x10, 0xF2, 0x02, 0xB0, 0xC4, 0xB1, 0x05, 0xF5, 0x83, + 0x49, 0xFF, 0xFF, 0xD2, 0xF0, 0x04, 0xF5, 0x03, 0x38, 0x0E, 0x01, 0x11, 0x8C, 0xA1, 0x89, 0x20, + 0xF0, 0x05, 0x38, 0x0E, 0x01, 0x11, 0x88, 0xC0, 0xD5, 0xEC, 0xF0, 0x01, 0x80, 0x46, 0x8A, 0xE0, + 0xFF, 0xFB, 0x84, 0x05, 0x42, 0x23, 0x80, 0x73, 0x4E, 0x26, 0x00, 0x03, 0x84, 0x41, 0x80, 0x29, + 0x80, 0x0A, 0x49, 0xFF, 0xB9, 0xD9, 0x00, 0x14, 0x00, 0x00, 0x5A, 0x10, 0xFF, 0x05, 0x8C, 0x21, + 0x88, 0x01, 0x92, 0x01, 0x10, 0x04, 0x00, 0x00, 0xB0, 0x46, 0xB0, 0x87, 0x49, 0xFF, 0xBA, 0x37, + 0xF0, 0x06, 0x38, 0x15, 0x01, 0x11, 0xF0, 0x07, 0x38, 0x25, 0x01, 0x11, 0x84, 0x02, 0x40, 0x00, + 0x80, 0x16, 0x42, 0x04, 0x88, 0x73, 0x40, 0x00, 0x04, 0x16, 0xFC, 0xC4, 0xFC, 0x46, 0x80, 0xE1, + 0x3C, 0x1C, 0x01, 0x66, 0xF2, 0x84, 0x50, 0x60, 0x00, 0x1C, 0x00, 0x20, 0x80, 0x32, 0x44, 0xA2, + 0xCE, 0x14, 0xF2, 0x86, 0x00, 0x20, 0x80, 0x33, 0x85, 0x00, 0xF2, 0x87, 0x20, 0x20, 0x80, 0x39, + 0xF2, 0x88, 0x20, 0x20, 0x80, 0x3A, 0xF2, 0x89, 0xA6, 0x8A, 0xA6, 0x4B, 0xF2, 0x82, 0x80, 0x01, + 0x8E, 0x01, 0xF1, 0x83, 0xF0, 0x85, 0x3C, 0x0C, 0x01, 0x66, 0x00, 0x00, 0x00, 0x09, 0xE3, 0x00, + 0x4E, 0xF2, 0x01, 0x89, 0x04, 0x03, 0x7F, 0xF9, 0x4E, 0x02, 0x01, 0x74, 0x8E, 0x04, 0xE6, 0x02, + 0x4E, 0xF3, 0x01, 0x70, 0xA0, 0x36, 0x5A, 0x08, 0x02, 0x04, 0x48, 0x00, 0x01, 0x6B, 0x04, 0x93, + 0x7F, 0xFF, 0x40, 0x04, 0x88, 0x08, 0xF0, 0x8A, 0xF1, 0x0A, 0xA0, 0x3D, 0x88, 0x01, 0xA6, 0xC0, + 0xCB, 0x6A, 0xA6, 0x42, 0xE6, 0x22, 0xE9, 0x02, 0x9E, 0xC9, 0xA7, 0x03, 0xF0, 0x03, 0x8E, 0x02, + 0xE0, 0x80, 0xE8, 0x03, 0x8C, 0x81, 0xD5, 0x02, 0xF4, 0x05, 0x84, 0x40, 0xB6, 0x5F, 0x3C, 0x1C, + 0x01, 0x67, 0xF0, 0x04, 0x80, 0xA6, 0x49, 0xFF, 0xFF, 0x6B, 0xA0, 0x7E, 0xF2, 0x06, 0x38, 0x10, + 0xA6, 0x02, 0x8A, 0x20, 0xFE, 0x54, 0x04, 0x23, 0x80, 0x08, 0x38, 0x21, 0x26, 0x02, 0x88, 0x02, + 0x3C, 0x2D, 0xFB, 0x4D, 0x40, 0x00, 0x80, 0x16, 0xF1, 0x08, 0x88, 0x01, 0xA4, 0x50, 0x96, 0xC3, + 0x92, 0x26, 0x96, 0x46, 0x5A, 0x18, 0x01, 0x21, 0xA4, 0x50, 0x96, 0x46, 0xC9, 0x1D, 0xA4, 0x50, + 0x92, 0x21, 0x96, 0x46, 0xC1, 0x19, 0x50, 0x10, 0x7F, 0xDD, 0x96, 0x49, 0x5C, 0xF0, 0x80, 0x3D, + 0xE8, 0x13, 0x52, 0x01, 0x80, 0x5F, 0x44, 0x10, 0x00, 0xB4, 0x44, 0xFF, 0xFF, 0x9C, 0xFE, 0x0C, + 0x40, 0x00, 0x3C, 0x16, 0x50, 0x00, 0x00, 0x5F, 0x96, 0x03, 0x5E, 0xF0, 0x00, 0x23, 0x80, 0x60, + 0xE8, 0x02, 0xFA, 0x73, 0x96, 0xDB, 0x44, 0x02, 0xD3, 0xD4, 0x38, 0x00, 0x20, 0x00, 0x5A, 0x08, + 0x01, 0x17, 0xA4, 0x10, 0x92, 0x06, 0x96, 0x06, 0xC8, 0x12, 0xA0, 0x3C, 0x38, 0x10, 0x25, 0x00, + 0xF0, 0x03, 0x8E, 0x04, 0xE0, 0x20, 0xE9, 0x0B, 0xA4, 0x10, 0x92, 0x01, 0x96, 0x06, 0xC8, 0x07, + 0xA4, 0x10, 0x96, 0x06, 0x5A, 0x08, 0x01, 0x04, 0x8C, 0x6A, 0x96, 0xDB, 0x22, 0x03, 0x7F, 0xF4, + 0xE0, 0x60, 0xD5, 0x77, 0xF1, 0x02, 0xA7, 0x41, 0x8E, 0x21, 0xD9, 0x76, 0xA6, 0xC2, 0x20, 0x1F, + 0x80, 0x08, 0xE6, 0x62, 0xF1, 0x8B, 0xE9, 0x03, 0x8E, 0x61, 0xD5, 0x02, 0x84, 0x60, 0xA7, 0x03, + 0xF0, 0x03, 0x8E, 0x02, 0xE0, 0x80, 0xE8, 0x03, 0x8C, 0x81, 0xD5, 0x02, 0xF4, 0x05, 0x3C, 0x1C, + 0x01, 0x67, 0x84, 0x00, 0xB6, 0x1F, 0x50, 0x10, 0x80, 0xA2, 0x84, 0x41, 0xF0, 0x04, 0x80, 0xA6, + 0x49, 0xFF, 0xFE, 0xF6, 0xA0, 0x7E, 0xF2, 0x0B, 0x38, 0x10, 0xA6, 0x02, 0x42, 0x11, 0x00, 0x73, + 0xF2, 0x06, 0xFE, 0x54, 0x04, 0x23, 0x80, 0x08, 0x38, 0x21, 0x26, 0x02, 0x88, 0x02, 0x3C, 0x2D, + 0xFB, 0x4D, 0x40, 0x00, 0x80, 0x16, 0xF1, 0x08, 0x88, 0x01, 0xA4, 0x50, 0x96, 0xC3, 0x92, 0x26, + 0x96, 0x46, 0x5A, 0x18, 0x01, 0x20, 0xA4, 0x50, 0x96, 0x46, 0xC1, 0x1C, 0xA4, 0x50, 0x92, 0x21, + 0x96, 0x46, 0xC1, 0x18, 0x50, 0x10, 0x7C, 0x1E, 0x96, 0x49, 0x5C, 0xF0, 0x80, 0x3C, 0xE8, 0x12, + 0x50, 0x01, 0xFC, 0x1F, 0x44, 0x10, 0x00, 0xB4, 0x44, 0xF0, 0x00, 0x64, 0xFE, 0x0C, 0x40, 0x00, + 0x3C, 0x16, 0x50, 0x00, 0x03, 0xE1, 0x96, 0xC3, 0x5E, 0xF1, 0x84, 0x1D, 0xE9, 0x03, 0x44, 0x30, + 0x04, 0x1D, 0x44, 0x02, 0xD3, 0xD4, 0x38, 0x00, 0x20, 0x00, 0x5A, 0x08, 0x01, 0x18, 0xA4, 0x10, + 0x92, 0x06, 0x96, 0x06, 0xC8, 0x13, 0xA0, 0x3C, 0x38, 0x10, 0x25, 0x00, 0xF0, 0x03, 0x8E, 0x04, + 0xE0, 0x20, 0xE9, 0x0C, 0xA4, 0x10, 0x92, 0x01, 0x96, 0x06, 0xC8, 0x08, 0xA4, 0x10, 0x96, 0x06, + 0x5A, 0x08, 0x01, 0x05, 0x50, 0x01, 0xFF, 0xF6, 0x96, 0xC3, 0x22, 0x03, 0x7F, 0xF4, 0xE0, 0x03, + 0x40, 0x01, 0xBC, 0x1B, 0xD5, 0x05, 0x84, 0x1F, 0xAE, 0x30, 0x02, 0x03, 0x7F, 0xF4, 0x12, 0x03, + 0x7F, 0xF8, 0xF1, 0x0A, 0xA0, 0x3D, 0x88, 0x01, 0xA6, 0xC2, 0xCB, 0x2D, 0xA6, 0x40, 0xE6, 0x22, + 0xE9, 0x02, 0x9E, 0xC9, 0xA7, 0x01, 0xF0, 0x02, 0x8E, 0x02, 0xE0, 0x80, 0xE8, 0x03, 0x8C, 0x81, + 0xD5, 0x03, 0xF0, 0x02, 0x9F, 0x01, 0x3C, 0x1C, 0x01, 0x67, 0x84, 0x01, 0xB6, 0x1F, 0x50, 0x10, + 0x81, 0x44, 0x84, 0x40, 0xF0, 0x04, 0x9D, 0x71, 0x49, 0xFF, 0xFE, 0x7A, 0xA0, 0x7F, 0xF2, 0x07, + 0x38, 0x10, 0xA6, 0x02, 0x8A, 0x20, 0xFE, 0x54, 0x04, 0x23, 0x80, 0x08, 0x38, 0x21, 0x26, 0x02, + 0x88, 0x02, 0x40, 0x00, 0x80, 0x16, 0xF1, 0x09, 0x88, 0x01, 0x22, 0x13, 0x7F, 0xF5, 0x96, 0x03, + 0xE0, 0x01, 0xD5, 0x35, 0xA7, 0x43, 0xF1, 0x05, 0xD9, 0x35, 0xA6, 0xC0, 0x20, 0x1F, 0x80, 0x0C, + 0xE6, 0x62, 0xF1, 0x8A, 0xE9, 0x03, 0x8E, 0x61, 0xD5, 0x02, 0x84, 0x60, 0xA7, 0x01, 0xF0, 0x02, + 0x8E, 0x02, 0xE0, 0x80, 0xE8, 0x03, 0x8C, 0x81, 0xD5, 0x03, 0xF0, 0x02, 0x9F, 0x01, 0x3C, 0x1C, + 0x01, 0x67, 0x84, 0x41, 0xB6, 0x5F, 0x50, 0x10, 0x81, 0xE6, 0x99, 0x72, 0xF0, 0x04, 0x49, 0xFF, + 0xFE, 0x47, 0xA0, 0x7F, 0xF2, 0x0A, 0x38, 0x10, 0xA6, 0x02, 0x42, 0x11, 0x00, 0x73, 0xF2, 0x07, + 0xFE, 0x54, 0x04, 0x23, 0x80, 0x08, 0x38, 0x21, 0x26, 0x02, 0x88, 0x02, 0x40, 0x00, 0x80, 0x16, + 0xF1, 0x09, 0x88, 0x01, 0x22, 0x13, 0x7F, 0xF5, 0x96, 0x03, 0xE0, 0x20, 0x40, 0x00, 0xBC, 0x1A, + 0xD5, 0x05, 0x84, 0x1F, 0xAE, 0x31, 0x02, 0x03, 0x7F, 0xF5, 0x12, 0x03, 0x7F, 0xF9, 0x22, 0x03, + 0x7F, 0xF8, 0x12, 0x05, 0x00, 0x00, 0x22, 0x03, 0x7F, 0xF9, 0x12, 0x05, 0x00, 0x01, 0xD5, 0x0C, + 0x22, 0x05, 0x00, 0x00, 0x12, 0x03, 0x7F, 0xF8, 0x22, 0x05, 0x00, 0x01, 0x12, 0x03, 0x7F, 0xF9, + 0x84, 0x1F, 0xAE, 0x30, 0xAE, 0x31, 0x8D, 0x01, 0x8D, 0x44, 0x50, 0x63, 0x00, 0xE0, 0x48, 0xFF, + 0xFE, 0x74, 0xFC, 0xC6, 0xFC, 0x48, 0xB6, 0x1F, 0x2E, 0x00, 0x05, 0xA8, 0xF1, 0x83, 0xF0, 0x8B, + 0x84, 0x00, 0xF2, 0x8C, 0xF3, 0x8D, 0xF0, 0x81, 0x83, 0xC0, 0xF0, 0x0D, 0x40, 0xFF, 0x00, 0x06, + 0x4E, 0xF2, 0x01, 0x58, 0xB4, 0x1F, 0xA0, 0x01, 0xF0, 0x82, 0x39, 0xC0, 0x79, 0x01, 0x4D, 0xCF, + 0x41, 0x46, 0xB4, 0x1F, 0xA0, 0x43, 0xF0, 0x0B, 0x38, 0xA0, 0xF9, 0x01, 0x5A, 0x08, 0x01, 0x14, + 0x44, 0x00, 0x00, 0x5A, 0x42, 0x15, 0x00, 0x24, 0x44, 0x00, 0x00, 0x64, 0x40, 0x00, 0x80, 0x17, + 0xF0, 0x84, 0x44, 0x00, 0x00, 0x32, 0x42, 0x15, 0x00, 0x24, 0x44, 0x00, 0x00, 0x64, 0x40, 0x00, + 0x80, 0x17, 0xD5, 0x0B, 0x44, 0x00, 0x00, 0x46, 0x42, 0x15, 0x00, 0x24, 0x44, 0x00, 0x00, 0x64, + 0x40, 0x00, 0x80, 0x17, 0xF0, 0x84, 0x84, 0x00, 0xF0, 0x85, 0xB4, 0x1F, 0x40, 0x2E, 0x08, 0x08, + 0x84, 0x80, 0xA0, 0x45, 0x88, 0x41, 0xA6, 0x52, 0xE6, 0x23, 0xE9, 0x03, 0x9F, 0x0A, 0x97, 0x20, + 0xA7, 0x93, 0x5C, 0xF3, 0x00, 0x21, 0xE8, 0x05, 0x9C, 0xF2, 0x96, 0xD8, 0xF3, 0x89, 0xD5, 0x03, + 0xFA, 0x13, 0xF0, 0x89, 0xA7, 0xD0, 0xE6, 0xE3, 0xE9, 0x05, 0x9E, 0xFA, 0x96, 0xD8, 0xF3, 0x87, + 0xD5, 0x03, 0x84, 0x00, 0xF0, 0x87, 0x00, 0x91, 0x00, 0x01, 0xE7, 0x2D, 0xE8, 0x06, 0x50, 0x24, + 0x80, 0x02, 0x96, 0x90, 0xF2, 0x8A, 0xD5, 0x03, 0x84, 0x0F, 0xF0, 0x8A, 0x9A, 0xF1, 0x40, 0x24, + 0x9C, 0x01, 0x8C, 0x45, 0x9D, 0x5D, 0x42, 0x32, 0x88, 0x24, 0x94, 0xA4, 0xF2, 0x88, 0x84, 0x40, + 0xF0, 0x09, 0xE0, 0x04, 0xE9, 0x3A, 0xF5, 0x07, 0xF0, 0x07, 0xF5, 0x86, 0xF5, 0x08, 0x88, 0xA0, + 0xF0, 0x03, 0x95, 0x69, 0x88, 0xA0, 0xF0, 0x0A, 0x04, 0x8F, 0x80, 0x06, 0xE0, 0x08, 0xE9, 0x28, + 0xF0, 0x03, 0x40, 0x82, 0x80, 0x01, 0xB4, 0x1F, 0x04, 0xF0, 0x00, 0x00, 0x38, 0x87, 0xA0, 0x00, + 0x5A, 0x88, 0xFF, 0x08, 0x22, 0x82, 0x80, 0x00, 0xF0, 0x04, 0xE0, 0x08, 0xE8, 0x0F, 0xD5, 0x0C, + 0xF0, 0x02, 0x38, 0x80, 0x21, 0x01, 0x4C, 0x8E, 0x40, 0x0F, 0x22, 0x82, 0x80, 0x00, 0xF0, 0x04, + 0xE0, 0x08, 0x4E, 0xF2, 0x00, 0xC8, 0x8E, 0x61, 0xD5, 0x06, 0xF0, 0x05, 0xE1, 0x00, 0xE9, 0x03, + 0x4E, 0x86, 0x00, 0xC5, 0xF0, 0x06, 0x8C, 0xA2, 0x8C, 0x01, 0xF0, 0x86, 0xD5, 0xD5, 0xF0, 0x08, + 0x8C, 0x81, 0x8C, 0x10, 0xF0, 0x88, 0xD5, 0xC5, 0x4E, 0x37, 0x00, 0x08, 0x40, 0x41, 0x84, 0x0A, + 0x88, 0x44, 0x40, 0x21, 0x0C, 0x56, 0xD5, 0x02, 0x84, 0x40, 0xE2, 0x4A, 0xE9, 0x02, 0x84, 0x40, + 0xE6, 0x22, 0xE9, 0x04, 0x8E, 0x21, 0x96, 0x48, 0xD5, 0x02, 0x84, 0x20, 0x5C, 0xF3, 0x00, 0x22, + 0xE8, 0x04, 0x8C, 0xC1, 0x96, 0x30, 0xD5, 0x02, 0xFA, 0x13, 0xE6, 0xE2, 0xF0, 0x87, 0x84, 0x00, + 0xE9, 0x03, 0x8E, 0xE1, 0x96, 0x38, 0xE7, 0x2E, 0xF0, 0x84, 0x84, 0x0F, 0xE8, 0x04, 0x50, 0x34, + 0x80, 0x01, 0x96, 0x18, 0x9E, 0xC9, 0xF0, 0x88, 0x94, 0x0C, 0xF0, 0x85, 0x94, 0x1D, 0x84, 0x60, + 0xF0, 0x86, 0x80, 0xE3, 0x80, 0xC3, 0xF0, 0x07, 0xE0, 0x01, 0xE9, 0x5B, 0xF5, 0x04, 0xF0, 0x05, + 0x80, 0x85, 0x88, 0x80, 0xF0, 0x03, 0x95, 0x21, 0x88, 0x80, 0x9E, 0x09, 0xF0, 0x8E, 0x9C, 0x09, + 0xF0, 0x8F, 0xF0, 0x08, 0xE0, 0x05, 0xE9, 0x44, 0xB4, 0x1F, 0xB5, 0x20, 0xF0, 0x03, 0x40, 0xA2, + 0x00, 0x01, 0x38, 0xA4, 0xA8, 0x00, 0x5A, 0xA8, 0xFF, 0x2A, 0xF0, 0x06, 0x04, 0x8F, 0x80, 0x0E, + 0x89, 0x20, 0x9E, 0x29, 0xF0, 0x89, 0x9C, 0x29, 0xF0, 0x8A, 0xF0, 0x0F, 0xE0, 0x08, 0xE9, 0x2D, + 0x5C, 0xF4, 0x00, 0x24, 0xE8, 0x17, 0x04, 0xAF, 0x80, 0x09, 0xF0, 0x0A, 0xE0, 0x0A, 0xE9, 0x12, + 0xE7, 0x50, 0xE8, 0x0E, 0x4C, 0xA2, 0xC0, 0x04, 0x4C, 0x80, 0x80, 0x0B, 0x38, 0xF4, 0xA9, 0x00, + 0x5A, 0xF0, 0xFF, 0x07, 0xF0, 0x02, 0x38, 0xF0, 0x3D, 0x01, 0x4C, 0xFE, 0x00, 0x0D, 0x8D, 0x41, + 0xD5, 0xED, 0x8D, 0x01, 0x50, 0x94, 0x80, 0x20, 0xD5, 0xE1, 0xF0, 0x02, 0x38, 0x90, 0x29, 0x01, + 0x4C, 0x9E, 0x40, 0x0C, 0x22, 0x92, 0x00, 0x00, 0xE0, 0x49, 0xE8, 0x07, 0x8B, 0x22, 0x42, 0x62, + 0xA4, 0x73, 0x42, 0x70, 0xA4, 0x73, 0x88, 0x69, 0x8C, 0xA1, 0x8C, 0x82, 0xD5, 0xBB, 0xF0, 0x05, + 0x8C, 0x21, 0x8C, 0x10, 0xF0, 0x85, 0xF0, 0x06, 0x50, 0x00, 0x00, 0x20, 0xF0, 0x86, 0xD5, 0xA4, + 0xCB, 0x02, 0x84, 0x61, 0xF0, 0x01, 0x94, 0x43, 0xF0, 0x0C, 0x88, 0x20, 0x44, 0x00, 0x00, 0x44, + 0x42, 0x23, 0x00, 0x24, 0x40, 0x21, 0x0C, 0x56, 0x44, 0x00, 0x00, 0x43, 0xAC, 0x88, 0x42, 0x23, + 0x80, 0x24, 0xB4, 0x1F, 0x40, 0x21, 0x0C, 0x56, 0xAC, 0x89, 0x04, 0x10, 0x00, 0x08, 0x38, 0x30, + 0xF2, 0x0A, 0xA0, 0x46, 0x38, 0x60, 0xF2, 0x0A, 0xA0, 0x47, 0xF0, 0x01, 0x38, 0x70, 0xF2, 0x0A, + 0x9C, 0x41, 0x96, 0x08, 0xE6, 0x0C, 0xF0, 0x81, 0xE8, 0x0C, 0x51, 0xEF, 0x00, 0x01, 0x48, 0xFF, + 0xFE, 0xAE, 0xF0, 0x05, 0xE1, 0x00, 0x4E, 0xF3, 0xFF, 0x3F, 0x88, 0x48, 0x48, 0xFF, 0xFF, 0x3C, + 0xFC, 0xC8, 0xFC, 0x00, 0x44, 0x62, 0xDE, 0xFC, 0x44, 0x02, 0xB4, 0xB0, 0x84, 0x20, 0x9A, 0xB0, + 0x49, 0x00, 0x04, 0xD6, 0x44, 0x0F, 0xFF, 0xAA, 0xAE, 0x31, 0xFC, 0x80, 0xFC, 0x00, 0x84, 0x00, + 0x3C, 0x0F, 0xFB, 0x6E, 0x3C, 0x0F, 0xFB, 0x76, 0x3C, 0x0F, 0xFB, 0x7A, 0x3C, 0x0F, 0xFB, 0x7E, + 0x3C, 0x0F, 0xFB, 0x87, 0x3C, 0x0F, 0xFB, 0x8B, 0x3C, 0x0F, 0xFB, 0x74, 0x3C, 0x0F, 0xFB, 0x7F, + 0x3C, 0x0F, 0xFB, 0x7B, 0x3C, 0x0F, 0xFB, 0x84, 0x3C, 0x0F, 0xFB, 0x7C, 0x3C, 0x0F, 0xFB, 0x78, + 0x3C, 0x0F, 0xFB, 0x75, 0x3C, 0x0F, 0xFB, 0x70, 0x3C, 0x0F, 0xFB, 0x89, 0x3C, 0x0F, 0xFB, 0x8D, + 0x3C, 0x0F, 0xFB, 0x82, 0x3C, 0x0F, 0xFB, 0x83, 0x3C, 0x0F, 0xFB, 0x80, 0x3C, 0x0F, 0xFB, 0x6C, + 0x3C, 0x0F, 0xFB, 0x8A, 0x3C, 0x0F, 0xFB, 0x7D, 0x3C, 0x0F, 0xFB, 0x73, 0x3C, 0x0F, 0xFB, 0x6F, + 0x3C, 0x0F, 0xFB, 0x6D, 0x3C, 0x0F, 0xFB, 0x72, 0x3C, 0x0F, 0xFB, 0x8C, 0x3C, 0x0F, 0xFB, 0x81, + 0x3C, 0x0F, 0xFB, 0x88, 0x3C, 0x0F, 0xFB, 0x79, 0x3C, 0x0F, 0xFB, 0x71, 0x64, 0x03, 0x00, 0x03, + 0x64, 0x03, 0x04, 0x03, 0x64, 0x12, 0x24, 0x02, 0x96, 0x46, 0xC1, 0x03, 0x64, 0x03, 0x00, 0x03, + 0x44, 0x00, 0x40, 0x00, 0x64, 0x02, 0x24, 0x03, 0x64, 0x12, 0x00, 0x02, 0x84, 0x19, 0xFE, 0x0E, + 0x64, 0x02, 0x00, 0x03, 0x64, 0x00, 0x00, 0x08, 0x64, 0x03, 0x04, 0x02, 0x46, 0x16, 0xF7, 0x80, + 0x50, 0x10, 0x80, 0x7C, 0xFE, 0x0F, 0x64, 0x03, 0x04, 0x03, 0x64, 0x02, 0x00, 0x02, 0x58, 0x00, + 0x00, 0x01, 0x64, 0x02, 0x00, 0x03, 0xFC, 0x80, 0x44, 0x03, 0xF0, 0x4B, 0x84, 0x3F, 0xAE, 0x40, + 0x44, 0x03, 0xF0, 0xED, 0xA6, 0x40, 0x5A, 0x18, 0x01, 0x04, 0x84, 0x20, 0xAE, 0x40, 0x44, 0x13, + 0xF0, 0xDA, 0xA6, 0x08, 0x54, 0x00, 0x00, 0xF0, 0xAE, 0x08, 0x84, 0x04, 0x64, 0x03, 0x04, 0x03, + 0x44, 0x03, 0xF0, 0x49, 0x84, 0x25, 0xAE, 0x40, 0x44, 0x03, 0xF0, 0x4A, 0x44, 0x10, 0x00, 0x53, + 0xAE, 0x40, 0x64, 0x03, 0x04, 0x02, 0x58, 0x00, 0x40, 0x00, 0x64, 0x03, 0x04, 0x03, 0xDD, 0x9E, + 0xDD, 0x9E, 0x44, 0x43, 0xF1, 0x14, 0xB4, 0x64, 0x92, 0x78, 0x40, 0x31, 0xE0, 0x08, 0xFE, 0x1F, + 0xB6, 0x04, 0x44, 0x03, 0xF1, 0x38, 0x44, 0x30, 0x00, 0x55, 0xAC, 0x40, 0x44, 0x03, 0xF1, 0x3A, + 0x84, 0x20, 0xAE, 0x40, 0x44, 0x03, 0xF1, 0x04, 0x84, 0x21, 0xB6, 0x40, 0x44, 0x03, 0xF1, 0x36, + 0x44, 0x23, 0xF0, 0x4A, 0xAE, 0x40, 0xA6, 0x40, 0x96, 0x46, 0xC1, 0x03, 0xAE, 0xD0, 0xD5, 0xFC, + 0x44, 0x03, 0xF1, 0x34, 0xA6, 0x00, 0x96, 0x06, 0xDD, 0x9E, 0x92, 0x42, 0x84, 0xA0, 0xD2, 0x07, + 0x38, 0x30, 0x16, 0x02, 0x38, 0x30, 0x96, 0x0A, 0x8C, 0xA1, 0xD5, 0xFA, 0xDD, 0x9E, 0x84, 0x00, + 0x80, 0x20, 0x3A, 0x6F, 0xA0, 0xBC, 0x49, 0xFF, 0xA0, 0x8C, 0x84, 0x00, 0x49, 0xFF, 0xA2, 0xF6, + 0x84, 0x00, 0x64, 0x05, 0xE4, 0x03, 0x44, 0x03, 0xF0, 0x0E, 0xA4, 0x40, 0x96, 0x66, 0xC1, 0x02, + 0xD5, 0x00, 0xA4, 0x40, 0x96, 0x4E, 0xC9, 0x0F, 0xA4, 0x40, 0x96, 0x56, 0xC9, 0x0C, 0xA4, 0x40, + 0x96, 0x5E, 0xC9, 0x09, 0xA4, 0x40, 0x96, 0x66, 0xC9, 0x06, 0xA4, 0x00, 0x54, 0x00, 0x01, 0x00, + 0x4E, 0x02, 0x00, 0xAE, 0x44, 0x13, 0xF0, 0x0E, 0xA4, 0x08, 0x96, 0x0E, 0xC8, 0x06, 0xA4, 0x08, + 0x54, 0x00, 0x01, 0x00, 0x96, 0x01, 0xC0, 0x22, 0x44, 0x12, 0x2D, 0x50, 0xA6, 0x08, 0x97, 0xC0, + 0x84, 0x00, 0xAC, 0x08, 0x44, 0x12, 0x2C, 0xF0, 0x3E, 0x07, 0xEC, 0x2E, 0xAE, 0x08, 0x44, 0x12, + 0x2C, 0xF1, 0xAE, 0x08, 0x44, 0x12, 0x2C, 0xF2, 0xAE, 0x08, 0x44, 0x12, 0x2C, 0xF3, 0xAE, 0x08, + 0x44, 0x12, 0x2C, 0xF4, 0xAE, 0x08, 0x44, 0x12, 0x2C, 0xF5, 0xAE, 0x08, 0x44, 0x12, 0x2C, 0xF6, + 0xAE, 0x08, 0x44, 0x12, 0x2C, 0xF7, 0xAE, 0x08, 0xD5, 0x02, 0x80, 0xE0, 0x49, 0xFF, 0xFE, 0xEB, + 0x84, 0x01, 0x3E, 0x00, 0x06, 0x0C, 0x44, 0x03, 0xF0, 0x0E, 0xA4, 0x40, 0x96, 0x4E, 0xC9, 0x08, + 0xA4, 0x40, 0x96, 0x66, 0xC9, 0x05, 0xA4, 0x00, 0x54, 0x00, 0x01, 0x00, 0xC0, 0x03, 0x49, 0xFF, + 0xC9, 0x27, 0x44, 0x02, 0x2D, 0x60, 0x84, 0x20, 0xAC, 0x40, 0x84, 0xC0, 0x44, 0x02, 0x70, 0x40, + 0x3C, 0x6F, 0xFB, 0x6D, 0x3C, 0x0F, 0xFB, 0x53, 0x3C, 0x6F, 0xFB, 0x6F, 0x3C, 0x6F, 0xFB, 0x85, + 0x5A, 0x78, 0xAE, 0x32, 0x84, 0xE3, 0x3C, 0x0D, 0xFB, 0x53, 0x94, 0xBC, 0x88, 0x40, 0xA0, 0x51, + 0xC1, 0x0C, 0xB4, 0x02, 0x96, 0x49, 0xA0, 0x93, 0x49, 0xFF, 0xFF, 0x55, 0x5A, 0x08, 0x01, 0x06, + 0x40, 0x00, 0x1C, 0x0C, 0xFF, 0x87, 0x97, 0xB1, 0x8C, 0xE1, 0x5A, 0x78, 0x0F, 0xEE, 0x44, 0x02, + 0x2D, 0x78, 0x84, 0x20, 0xAC, 0x40, 0xC6, 0x17, 0x44, 0x02, 0x2D, 0x60, 0x44, 0x1F, 0xFF, 0x9F, + 0xAE, 0x40, 0x44, 0x02, 0x2D, 0x61, 0x96, 0x70, 0xAE, 0x40, 0x44, 0x02, 0x2D, 0x62, 0x92, 0xC8, + 0xAF, 0x80, 0x44, 0x03, 0xF0, 0x4A, 0x44, 0x10, 0x00, 0x55, 0xAE, 0x40, 0x44, 0x00, 0x00, 0x69, + 0x49, 0xFF, 0xA1, 0x20, 0x44, 0x02, 0x8F, 0x70, 0x44, 0x12, 0x2D, 0x78, 0xFA, 0x54, 0x49, 0xFF, + 0xFF, 0x4E, 0x3C, 0x0D, 0xFB, 0x53, 0x44, 0x32, 0x2D, 0x7C, 0x44, 0x22, 0x2D, 0x7D, 0x04, 0x00, + 0x00, 0x09, 0x40, 0x10, 0x20, 0x09, 0x3E, 0x07, 0xC6, 0xD5, 0x3E, 0x17, 0xC6, 0xD6, 0x40, 0x10, + 0x40, 0x09, 0x92, 0x18, 0x3E, 0x17, 0xC6, 0xD7, 0x3E, 0x07, 0xC6, 0xD8, 0xA6, 0x18, 0xA6, 0x50, + 0x96, 0x02, 0x96, 0x4A, 0xAE, 0x58, 0xAE, 0x10, 0x44, 0x32, 0x2D, 0x7E, 0x44, 0x22, 0x2D, 0x7F, + 0xA6, 0x18, 0xA6, 0x50, 0x96, 0x02, 0x96, 0x4A, 0xAE, 0x58, 0xAE, 0x10, 0x44, 0x13, 0xF0, 0x0E, + 0x3C, 0x0D, 0xFA, 0xF9, 0xA6, 0x48, 0x10, 0x10, 0x00, 0x3C, 0x44, 0x13, 0xF0, 0x0F, 0xA6, 0x48, + 0x10, 0x10, 0x00, 0x3D, 0x49, 0xFF, 0xC9, 0x29, 0x9E, 0x81, 0xE6, 0x48, 0x3C, 0x0F, 0xFB, 0x5C, + 0xE8, 0x0C, 0x84, 0x21, 0x40, 0x10, 0x88, 0x0C, 0x54, 0x10, 0x80, 0x8F, 0xC1, 0x06, 0x50, 0x00, + 0x7F, 0xE0, 0x96, 0x00, 0x49, 0xFF, 0xC8, 0xBE, 0x49, 0x00, 0x02, 0x83, 0x3A, 0x6F, 0xA0, 0x84, + 0xDD, 0x9E, 0x84, 0x01, 0x3C, 0x0F, 0xFB, 0x6E, 0xDD, 0x9E, 0x3C, 0x0D, 0xFB, 0x76, 0x8C, 0x01, + 0x3C, 0x0F, 0xFB, 0x76, 0xDD, 0x9E, 0x3A, 0x6F, 0x9A, 0xBC, 0xEF, 0xFC, 0x3C, 0x0D, 0xFB, 0x7A, + 0x8C, 0x01, 0x3C, 0x0F, 0xFB, 0x7A, 0x3C, 0x0D, 0xFB, 0x4A, 0xA6, 0x00, 0x8E, 0x01, 0xE6, 0x02, + 0xE8, 0x32, 0x2E, 0x07, 0xEC, 0x34, 0x5A, 0x00, 0x55, 0x06, 0x2E, 0x07, 0xEC, 0x2A, 0x5A, 0x08, + 0x55, 0x21, 0x3C, 0x03, 0xF6, 0x4D, 0x8C, 0x01, 0x96, 0x01, 0xE6, 0x0A, 0x3C, 0x0B, 0xF6, 0x4D, + 0xE9, 0x1B, 0x84, 0x04, 0x49, 0xFF, 0xC8, 0x8E, 0x84, 0x01, 0x3E, 0x00, 0x06, 0x31, 0x84, 0x00, + 0x49, 0xFF, 0x83, 0xA8, 0x3C, 0x0D, 0xFB, 0x4A, 0xA6, 0x00, 0x5A, 0x08, 0x01, 0x07, 0x44, 0x00, + 0x00, 0x69, 0x49, 0xFF, 0xA0, 0x97, 0xD5, 0x08, 0x8E, 0x02, 0xE6, 0x02, 0xE9, 0x00, 0xD5, 0x04, + 0x84, 0x00, 0x3C, 0x0B, 0xF6, 0x4D, 0x44, 0x00, 0x00, 0x55, 0x3E, 0x07, 0xEC, 0x34, 0x3E, 0x07, + 0xEC, 0x2A, 0xD5, 0x04, 0x84, 0x00, 0x3C, 0x0B, 0xF6, 0x4D, 0xEC, 0x04, 0x3A, 0x6F, 0x9A, 0x84, + 0xDD, 0x9E, 0x3B, 0xFF, 0xFC, 0xBC, 0xEF, 0xFC, 0xFA, 0x10, 0x49, 0xFF, 0xC8, 0x63, 0x84, 0x01, + 0x3C, 0x0F, 0xFB, 0x7E, 0x49, 0xFF, 0x9C, 0x6B, 0x49, 0xFF, 0x83, 0x75, 0x3C, 0x0D, 0xFB, 0x4A, + 0x84, 0x22, 0x49, 0xFF, 0xCD, 0x01, 0x49, 0xFF, 0x83, 0x8C, 0x84, 0x20, 0x84, 0x02, 0x84, 0x46, + 0x80, 0x61, 0x80, 0x81, 0x80, 0xA1, 0x49, 0xFF, 0xC9, 0x47, 0xEC, 0x04, 0x3B, 0xFF, 0xFC, 0x84, + 0xDD, 0x9E, 0x3A, 0x6F, 0x9A, 0xBC, 0xEF, 0xFC, 0x49, 0xFF, 0x9F, 0xE1, 0xC0, 0x12, 0x84, 0x00, + 0x49, 0xFF, 0x9F, 0xE1, 0x49, 0xFF, 0x9F, 0xF2, 0x5A, 0x08, 0x01, 0x0C, 0x3C, 0x0F, 0xFB, 0x77, + 0x44, 0x12, 0xB5, 0x29, 0x3C, 0x0D, 0xFB, 0x4A, 0x44, 0x22, 0xB6, 0x50, 0x49, 0xFF, 0xFA, 0x06, + 0x49, 0xFF, 0x9F, 0xC4, 0xC0, 0x07, 0x84, 0x01, 0x3C, 0x0F, 0xFB, 0x86, 0x84, 0x00, 0x49, 0xFF, + 0x9F, 0xC1, 0x49, 0xFF, 0xA0, 0x0B, 0xC0, 0x12, 0x84, 0x00, 0x49, 0xFF, 0xA0, 0x0B, 0x49, 0xFF, + 0x9F, 0xD5, 0x5A, 0x08, 0x01, 0x0C, 0x3C, 0x0F, 0xFB, 0x6D, 0x44, 0x12, 0xB5, 0x29, 0x3C, 0x0D, + 0xFB, 0x4A, 0x44, 0x22, 0xB6, 0x50, 0x49, 0xFF, 0xF9, 0xE9, 0x49, 0xFF, 0x9F, 0xEE, 0xC0, 0x07, + 0x84, 0x00, 0x49, 0xFF, 0x9F, 0xEE, 0x84, 0x01, 0x3C, 0x0F, 0xFB, 0x6F, 0xEC, 0x04, 0x3A, 0x6F, + 0x9A, 0x84, 0xDD, 0x9E, 0x3A, 0x6F, 0x9A, 0xBC, 0xEF, 0xFC, 0x3C, 0x0D, 0xFB, 0x64, 0x84, 0x21, + 0x3C, 0x1F, 0xFB, 0x87, 0xAE, 0x40, 0x44, 0x0F, 0xFF, 0xAA, 0x3E, 0x07, 0xEC, 0x34, 0x84, 0x00, + 0x3C, 0x0F, 0xFB, 0x85, 0x3C, 0x0D, 0xFB, 0x4A, 0xA6, 0x81, 0x54, 0x21, 0x00, 0xFD, 0x5A, 0x20, + 0x04, 0x04, 0x49, 0xFF, 0xCC, 0x99, 0x49, 0xFF, 0x82, 0xF9, 0xC8, 0x0A, 0x2E, 0x17, 0xEC, 0x25, + 0x3E, 0x07, 0xEC, 0x80, 0x5A, 0x18, 0x01, 0x11, 0x3E, 0x07, 0xEC, 0x7E, 0xD5, 0x0D, 0x84, 0x09, + 0x49, 0xFF, 0xC7, 0xE0, 0xFA, 0x18, 0x49, 0xFF, 0xB3, 0xB9, 0x84, 0x02, 0x49, 0xFF, 0x9D, 0x54, + 0x84, 0x01, 0x3E, 0x07, 0xEC, 0x57, 0x2E, 0x07, 0xEC, 0x73, 0x5A, 0x00, 0x01, 0x06, 0x2E, 0x07, + 0xEC, 0x1B, 0x5A, 0x08, 0x01, 0x07, 0x2E, 0x07, 0xEC, 0x7D, 0x8C, 0x01, 0x3E, 0x07, 0xEC, 0x7D, + 0xEC, 0x04, 0x3A, 0x6F, 0x9A, 0x84, 0xDD, 0x9E, 0x3B, 0xFF, 0xFC, 0xBC, 0x84, 0x01, 0x3C, 0x0F, + 0xFB, 0x8B, 0xEF, 0xFC, 0xFA, 0x11, 0x49, 0xFF, 0xC7, 0xBD, 0x44, 0x03, 0xF0, 0x82, 0xA6, 0x00, + 0xC0, 0x05, 0x44, 0x00, 0x00, 0x69, 0x49, 0xFF, 0x9F, 0xCD, 0xEC, 0x04, 0x3B, 0xFF, 0xFC, 0x84, + 0xDD, 0x9E, 0x84, 0x01, 0x3C, 0x0F, 0xFB, 0x74, 0xDD, 0x9E, 0x84, 0x01, 0x3C, 0x0F, 0xFB, 0x7F, + 0xDD, 0x9E, 0x84, 0x01, 0x3C, 0x0F, 0xFB, 0x7B, 0xDD, 0x9E, 0x84, 0x01, 0x3C, 0x0F, 0xFB, 0x84, + 0xDD, 0x9E, 0x3B, 0xFF, 0xFC, 0xBC, 0xEF, 0xFC, 0xFA, 0x12, 0x49, 0xFF, 0xC7, 0x9B, 0xEC, 0x04, + 0x84, 0x01, 0x3C, 0x0F, 0xFB, 0x7C, 0x3B, 0xFF, 0xFC, 0x84, 0xDD, 0x9E, 0x84, 0x01, 0x3C, 0x0F, + 0xFB, 0x78, 0xDD, 0x9E, 0x3B, 0xFF, 0xFC, 0xBC, 0xEF, 0xFC, 0xFA, 0x13, 0x49, 0xFF, 0xC7, 0x8A, + 0xEC, 0x04, 0x3B, 0xFF, 0xFC, 0x84, 0xDD, 0x9E, 0x44, 0x03, 0xF0, 0x4B, 0x3B, 0xFF, 0xFC, 0xBC, + 0x84, 0x3F, 0xEF, 0xFC, 0xAE, 0x40, 0xFA, 0x14, 0x49, 0xFF, 0xC7, 0x7C, 0xEC, 0x04, 0x84, 0x01, + 0x3C, 0x0F, 0xFB, 0x70, 0x3B, 0xFF, 0xFC, 0x84, 0xDD, 0x9E, 0x44, 0x03, 0xF0, 0x4B, 0xA6, 0x40, + 0x5A, 0x10, 0xFF, 0x05, 0x84, 0x3F, 0xAE, 0x40, 0xD5, 0xFF, 0x84, 0x01, 0x3C, 0x0F, 0xFB, 0x85, + 0x84, 0x00, 0x3C, 0x0F, 0xFB, 0x89, 0x3E, 0x07, 0xEC, 0x0E, 0x3C, 0x0D, 0xFB, 0x4A, 0xA6, 0x01, + 0x5A, 0x00, 0x04, 0x10, 0x3B, 0xFF, 0xFC, 0xBC, 0xEF, 0xFC, 0x49, 0xFF, 0x82, 0x61, 0x5A, 0x08, + 0x01, 0x06, 0x49, 0xFF, 0xA1, 0x2B, 0x3E, 0x07, 0xEC, 0x3D, 0xEC, 0x04, 0x3B, 0xFF, 0xFC, 0x84, + 0xDD, 0x9E, 0x3C, 0x0D, 0xFB, 0x89, 0x8C, 0x01, 0x3C, 0x0F, 0xFB, 0x89, 0xDD, 0x9E, 0x84, 0x01, + 0x3C, 0x0F, 0xFB, 0x79, 0x3E, 0x00, 0x05, 0xF9, 0x44, 0x03, 0xF0, 0x7E, 0x3B, 0xFF, 0xFC, 0xBC, + 0xA6, 0x40, 0xEF, 0xFC, 0x5A, 0x10, 0x01, 0x0F, 0xA6, 0x40, 0x5A, 0x10, 0x02, 0x0C, 0xA6, 0x40, + 0x5A, 0x10, 0x03, 0x09, 0xA6, 0x40, 0x5A, 0x10, 0x04, 0x06, 0xA6, 0x40, 0x5A, 0x10, 0x10, 0x03, + 0xA6, 0x00, 0x84, 0x41, 0x84, 0x20, 0x80, 0x62, 0x80, 0x82, 0x44, 0x00, 0xB1, 0x01, 0x49, 0xFF, + 0xD6, 0xD0, 0x49, 0xFF, 0xD6, 0xE5, 0xEC, 0x04, 0x3B, 0xFF, 0xFC, 0x84, 0xDD, 0x9E, 0x84, 0x01, + 0x3C, 0x0F, 0xFB, 0x8D, 0xDD, 0x9E, 0x84, 0x01, 0x3C, 0x0F, 0xFB, 0x82, 0x44, 0x03, 0xF0, 0x64, + 0xA6, 0x40, 0x96, 0x46, 0xC9, 0x19, 0x44, 0x23, 0xF0, 0x10, 0xAE, 0x50, 0xA6, 0x40, 0x58, 0x10, + 0x80, 0x01, 0xAE, 0x40, 0x3C, 0x0D, 0xFB, 0x4A, 0xA6, 0x00, 0x8E, 0x02, 0xE6, 0x02, 0xE9, 0x14, + 0x3B, 0xFF, 0xFC, 0xBC, 0xEF, 0xFC, 0x44, 0x00, 0x00, 0x55, 0x49, 0xFF, 0x9F, 0x1B, 0xEC, 0x04, + 0x3B, 0xFF, 0xFC, 0x84, 0xD5, 0x09, 0xA6, 0x40, 0x96, 0x46, 0xC1, 0x06, 0xA6, 0x40, 0x54, 0x10, + 0x80, 0xFE, 0xAE, 0x40, 0xDD, 0x9E, 0xDD, 0x9E, 0x3B, 0xFF, 0xFC, 0xBC, 0xEF, 0xFC, 0xFA, 0x15, + 0x49, 0xFF, 0xC6, 0xF0, 0xEC, 0x04, 0x84, 0x01, 0x3C, 0x0F, 0xFB, 0x83, 0x3B, 0xFF, 0xFC, 0x84, + 0xDD, 0x9E, 0x3B, 0xFF, 0xFC, 0xBC, 0xEF, 0xFC, 0xFA, 0x16, 0x49, 0xFF, 0xC6, 0xE3, 0xEC, 0x04, + 0x84, 0x01, 0x3C, 0x0F, 0xFB, 0x80, 0x3B, 0xFF, 0xFC, 0x84, 0xDD, 0x9E, 0x3B, 0xFF, 0xFC, 0xBC, + 0xEF, 0xFC, 0xFA, 0x17, 0x49, 0xFF, 0xC6, 0xD6, 0x84, 0x01, 0x3C, 0x0F, 0xFB, 0x6C, 0x49, 0xFF, + 0xF3, 0x4B, 0x5A, 0x08, 0xA1, 0x06, 0x44, 0x00, 0x00, 0x55, 0x49, 0xFF, 0x9E, 0xE3, 0xEC, 0x04, + 0x3B, 0xFF, 0xFC, 0x84, 0xDD, 0x9E, 0x3A, 0x6F, 0x9A, 0xBC, 0xEF, 0xFC, 0x49, 0xFF, 0x9B, 0x34, + 0x5A, 0x08, 0x02, 0x14, 0x3C, 0x5D, 0xFB, 0x8A, 0x2E, 0x00, 0x0D, 0x06, 0xD0, 0x06, 0x3C, 0x0D, + 0xFB, 0x4A, 0xA6, 0x01, 0x5A, 0x08, 0x04, 0x0A, 0x49, 0xFF, 0xA0, 0x88, 0x3E, 0x07, 0xEC, 0x1C, + 0x49, 0xFF, 0xCA, 0xAC, 0x3E, 0x07, 0xEC, 0x0E, 0x84, 0x01, 0x3C, 0x0F, 0xFB, 0x88, 0x3C, 0x0D, + 0xFB, 0x8A, 0x8C, 0x01, 0x3C, 0x0F, 0xFB, 0x8A, 0xEC, 0x04, 0x3A, 0x6F, 0x9A, 0x84, 0xDD, 0x9E, + 0x3A, 0x6F, 0x98, 0xBC, 0xFA, 0x18, 0x44, 0x63, 0xF4, 0x21, 0x49, 0xFF, 0xC6, 0x9B, 0x44, 0x00, + 0x00, 0x55, 0xAE, 0x30, 0x84, 0x0C, 0x49, 0xFF, 0xB2, 0x71, 0x84, 0x00, 0xAE, 0x30, 0x84, 0x0C, + 0x49, 0xFF, 0xB2, 0x6C, 0x84, 0x01, 0x3C, 0x0F, 0xFB, 0x7D, 0x2E, 0x07, 0xEC, 0x80, 0x8C, 0x01, + 0x96, 0x00, 0xE6, 0x03, 0x3E, 0x07, 0xEC, 0x80, 0xE9, 0x05, 0x44, 0x00, 0x00, 0x55, 0x49, 0xFF, + 0x9E, 0x99, 0x3A, 0x6F, 0x98, 0x84, 0xDD, 0x9E, 0x84, 0x01, 0x3C, 0x0F, 0xFB, 0x73, 0xDD, 0x9E, + 0xDD, 0x9E, 0x84, 0x01, 0x3C, 0x0F, 0xFB, 0x72, 0xDD, 0x9E, 0xDD, 0x9E, 0x3B, 0xFF, 0xFC, 0xBC, + 0xEF, 0xFC, 0xFA, 0x19, 0x49, 0xFF, 0xC6, 0x6E, 0x84, 0x01, 0x3C, 0x0F, 0xFB, 0x8C, 0x49, 0xFF, + 0x99, 0xA8, 0x49, 0xFF, 0x81, 0x6D, 0xC8, 0x04, 0x49, 0xFF, 0x81, 0x7D, 0xD5, 0x03, 0x49, 0xFF, + 0x99, 0x60, 0x44, 0x00, 0x00, 0x69, 0x49, 0xFF, 0x9E, 0x75, 0xEC, 0x04, 0x3B, 0xFF, 0xFC, 0x84, + 0xDD, 0x9E, 0x84, 0x01, 0x3C, 0x0F, 0xFB, 0x81, 0xDD, 0x9E, 0x84, 0x01, 0x3C, 0x0F, 0xFB, 0x71, + 0xDD, 0x9E, 0x3B, 0xFF, 0xFC, 0xBC, 0xEF, 0xFC, 0xFA, 0x1A, 0x49, 0xFF, 0xC6, 0x4B, 0x44, 0x03, + 0xF0, 0x4B, 0x84, 0x3F, 0xAE, 0x40, 0x44, 0x03, 0xF0, 0xED, 0x84, 0x20, 0xAE, 0x40, 0x44, 0x00, + 0x00, 0x69, 0x49, 0xFF, 0x9E, 0x57, 0xEC, 0x04, 0x3B, 0xFF, 0xFC, 0x84, 0xDD, 0x9E, 0xFC, 0x20, + 0x49, 0xFF, 0xC8, 0x4C, 0x49, 0xFF, 0xBA, 0xE7, 0x5A, 0x00, 0x08, 0x06, 0x49, 0xFF, 0xBB, 0x0E, + 0x49, 0xFF, 0xBB, 0x30, 0x44, 0x73, 0xF0, 0x4B, 0xA6, 0x38, 0x44, 0x13, 0xF0, 0x4B, 0x5A, 0x00, + 0xFF, 0x05, 0x84, 0x1F, 0xAE, 0x08, 0xD5, 0xFF, 0x49, 0xFF, 0xBD, 0x8C, 0x5A, 0x00, 0x03, 0xF0, + 0x5A, 0x00, 0x02, 0xF0, 0x5A, 0x00, 0x13, 0xF2, 0x49, 0xFF, 0xC2, 0x34, 0x5A, 0x00, 0x02, 0xEA, + 0x5A, 0x08, 0x13, 0x05, 0x49, 0xFF, 0xBC, 0x3A, 0xD5, 0xE8, 0x3C, 0x0D, 0xFB, 0x59, 0xA7, 0x80, + 0x97, 0xB0, 0xCE, 0x31, 0x3E, 0x60, 0x06, 0x39, 0x49, 0xFF, 0xBB, 0x43, 0x2E, 0x07, 0xEC, 0x5F, + 0x5A, 0x08, 0x12, 0x0E, 0x3C, 0x03, 0xF6, 0x4F, 0x80, 0x26, 0x49, 0xFF, 0xF3, 0x19, 0x5A, 0x08, + 0x01, 0x07, 0x80, 0x06, 0x2E, 0x10, 0x06, 0x39, 0x49, 0xFF, 0xF2, 0x0F, 0x2E, 0x07, 0xEC, 0x5F, + 0x5A, 0x00, 0x04, 0x12, 0x5A, 0x08, 0x19, 0x04, 0x49, 0xFF, 0xF2, 0x47, 0x49, 0xFF, 0xBB, 0x75, + 0x49, 0xFF, 0xBE, 0x8B, 0x5A, 0x00, 0x02, 0xBE, 0x2E, 0x07, 0xEC, 0x5F, 0x5A, 0x08, 0x05, 0x0A, + 0x49, 0xFF, 0xBC, 0x37, 0x44, 0x00, 0x00, 0xFF, 0x2E, 0x10, 0x06, 0x39, 0x49, 0xFF, 0xF1, 0xF5, + 0x49, 0xFF, 0xBC, 0x10, 0x49, 0xFF, 0x9A, 0x50, 0x5A, 0x08, 0x02, 0xB0, 0x49, 0xFF, 0x9F, 0xAE, + 0xC8, 0xAC, 0x2E, 0x67, 0xEC, 0x44, 0xCE, 0xA9, 0x2E, 0x17, 0xEC, 0x38, 0xC9, 0x04, 0x44, 0x00, + 0x03, 0x00, 0xD5, 0x06, 0x5A, 0x18, 0x0A, 0x0B, 0x44, 0x00, 0x13, 0x00, 0x80, 0x26, 0x84, 0x41, + 0x80, 0x62, 0x80, 0x82, 0x49, 0xFF, 0xD5, 0x6D, 0xD5, 0x1D, 0x44, 0x01, 0x32, 0xB0, 0x84, 0x61, + 0x38, 0x00, 0x05, 0x01, 0x80, 0x46, 0x80, 0x26, 0x80, 0x83, 0x49, 0xFF, 0xD5, 0x62, 0x2E, 0x17, + 0xEC, 0x38, 0x44, 0x21, 0x32, 0xA4, 0x38, 0x51, 0x04, 0x00, 0xD0, 0x0C, 0x84, 0x41, 0x44, 0x00, + 0x28, 0x00, 0x80, 0x26, 0x80, 0x62, 0x80, 0x82, 0x49, 0xFF, 0xD5, 0x53, 0x84, 0x01, 0x3E, 0x07, + 0xEC, 0x44, 0x2E, 0x07, 0xEC, 0x38, 0x84, 0x2B, 0x8C, 0x01, 0x96, 0x00, 0x40, 0x00, 0x04, 0x37, + 0x3E, 0x17, 0xEC, 0x38, 0x48, 0xFF, 0xFF, 0x72, 0x80, 0x60, 0xC2, 0x07, 0x99, 0x4A, 0x08, 0x40, + 0x80, 0x01, 0x18, 0x41, 0x80, 0x01, 0xD9, 0xFC, 0xDD, 0x9E, 0x92, 0x00, 0x80, 0x60, 0x99, 0x5A, + 0xD3, 0x04, 0x18, 0x11, 0x80, 0x01, 0xD5, 0xFD, 0xDD, 0x9E, 0x92, 0x00, 0x00, 0x00, 0x26, 0x00, + 0x58, 0x00, 0x8A, 0x00, 0xBD, 0x00, 0xED, 0x00, 0x20, 0x01, 0x54, 0x01, 0x86, 0x01, 0xBC, 0x01, + 0xEF, 0x01, 0x20, 0x02, 0x56, 0x02, 0x84, 0x02, 0xB9, 0x02, 0xEC, 0x02, 0x25, 0x03, 0x55, 0x03, + 0x89, 0x03, 0xB9, 0x03, 0xEA, 0x03, 0x17, 0x04, 0x3F, 0x04, 0x00, 0x00, 0x00, 0x00, 0x24, 0x00, + 0x53, 0x00, 0x85, 0x00, 0xB6, 0x00, 0xE9, 0x00, 0x20, 0x01, 0x54, 0x01, 0x86, 0x01, 0xBC, 0x01, + 0xEF, 0x01, 0x20, 0x02, 0x56, 0x02, 0x84, 0x02, 0xB9, 0x02, 0xEC, 0x02, 0x25, 0x03, 0x55, 0x03, + 0x8C, 0x03, 0xBB, 0x03, 0xE9, 0x03, 0x17, 0x04, 0x3F, 0x04, 0x00, 0x00, 0x04, 0x05, 0x06, 0x07, + 0x00, 0x00, 0x00, 0x00, 0x0C, 0x0C, 0x00, 0x55, 0x50, 0x71, 0x02, 0x00, 0xD8, 0x73, 0x02, 0x00, + 0x60, 0x76, 0x02, 0x00, 0xE8, 0x78, 0x02, 0x00, 0x60, 0x0C, 0x02, 0x00, 0xA0, 0x20, 0x02, 0x00, + 0x00, 0x40, 0x02, 0x00, 0x60, 0x4C, 0x02, 0x00, 0x70, 0x11, 0x02, 0x00, 0x80, 0x16, 0x02, 0x00, + 0xE0, 0x51, 0x02, 0x00, 0xF0, 0x56, 0x02, 0x00, 0x00, 0x01, 0x02, 0x03, 0x02, 0x14, 0x02, 0x15, + 0x15, 0x14, 0x13, 0x02, 0x02, 0x15, 0x13, 0x15, 0x02, 0x08, 0x14, 0x15, 0x15, 0x02, 0x04, 0x04, + 0x02, 0x04, 0x04, 0x15, 0x15, 0x06, 0x08, 0x06, 0x01, 0x08, 0x21, 0x05, 0x06, 0x06, 0x04, 0x07, + 0x01, 0x04, 0x04, 0x06, 0x01, 0x04, 0x05, 0x22, 0x06, 0x04, 0x04, 0x05, 0x06, 0x06, 0x01, 0x01, + 0x08, 0x06, 0x06, 0x05, 0x06, 0x07, 0x01, 0x01, 0x22, 0x04, 0x04, 0x01, 0x05, 0x22, 0x06, 0x04, + 0x05, 0x05, 0x05, 0x01, 0x06, 0x01, 0x01, 0x06, 0x05, 0x05, 0x01, 0x07, 0x01, 0x01, 0x04, 0x05, + 0x01, 0x01, 0x05, 0x00, 0x00, 0x00, 0x01, 0x00, 0x0F, 0x00, 0x10, 0x00, 0x11, 0x00, 0x1F, 0x00, + 0x30, 0x02, 0x3F, 0x02, 0x40, 0x2B, 0x02, 0x00, 0xD0, 0x2B, 0x02, 0x00, 0xB0, 0x3E, 0x02, 0x00, + 0x40, 0x3F, 0x02, 0x00, 0x20, 0x2A, 0x02, 0x00, 0xB0, 0x2A, 0x02, 0x00, 0x90, 0x3D, 0x02, 0x00, + 0x20, 0x3E, 0x02, 0x00, 0x50, 0x71, 0x02, 0x00, 0xD8, 0x73, 0x02, 0x00, 0x60, 0x76, 0x02, 0x00, + 0xE8, 0x78, 0x02, 0x00, 0x70, 0x11, 0x02, 0x00, 0x80, 0x16, 0x02, 0x00, 0xE0, 0x51, 0x02, 0x00, + 0xF0, 0x56, 0x02, 0x00, 0x60, 0x0C, 0x02, 0x00, 0xA0, 0x20, 0x02, 0x00, 0x00, 0x40, 0x02, 0x00, + 0x60, 0x4C, 0x02, 0x00, 0x60, 0x0C, 0x02, 0x00, 0xA0, 0x20, 0x02, 0x00, 0x00, 0x40, 0x02, 0x00, + 0x60, 0x4C, 0x02, 0x00, 0x70, 0x11, 0x02, 0x00, 0x80, 0x16, 0x02, 0x00, 0xE0, 0x51, 0x02, 0x00, + 0xF0, 0x56, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x0F, 0x00, 0x10, 0x00, 0x11, 0x00, 0x1F, 0x00, + 0x30, 0x02, 0x3F, 0x02, 0x00, 0x89, 0x14, 0x00, 0x0E, 0xE8, 0x07, 0x0E, 0x16, 0xF0, 0x00, 0x00, + 0x00, 0x03, 0x00, 0xC1, 0x03, 0xC1, 0x05, 0xC1, 0x07, 0xC1, 0x09, 0xC1, 0x0B, 0xC1, 0x0D, 0xC1, + 0x0F, 0xC1, 0x01, 0xC2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC3, 0x32, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, + 0x40, 0x70, 0x02, 0x00, 0x6F, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xC0, 0x07, 0x55, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x70, 0x8F, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x9F, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x70, 0x7B, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x8B, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x70, 0x99, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0xA9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xB0, 0xB4, 0x02, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x06, 0xF0, 0xF1, 0x55, 0x06, 0xF0, 0xF1, 0x55, 0x06, 0xF0, 0xF1, 0x55, 0x06, 0xF0, 0xF1, 0x55, + 0x0D, 0x0D, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, + 0x0E, 0x0D, 0x0D, 0x0D, 0x0E, 0x0D, 0x0E, 0x0E, 0x0E, 0x0E, 0x0D, 0x0D, 0x0E, 0x0D, 0x0D, 0x0D, + 0x0E, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0E, 0x0E, 0x0E, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, + 0x0D, 0x0D, 0x0D, 0x0D, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, + 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0E, 0x0E, 0x0E, 0x0E, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, + 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0E, 0x0E, 0x0E, 0x0E, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, + 0x0E, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0E, 0x0E, 0x0E, 0x0E, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, + 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0E, 0x0E, 0x0E, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, + 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0E, 0x0E, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0E, + 0x0D, 0x0D, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, + 0x0E, 0x0D, 0x0D, 0x0D, 0x0D, 0x0E, 0x0E, 0x0E, 0x0E, 0x0D, 0x0E, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, + 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0E, 0x0E, 0x0E, 0x0E, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, + 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0E, 0x0E, 0x0E, 0x0E, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, + 0x0D, 0x0D, 0x0D, 0x0D, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, + 0x0E, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0E, 0x0E, 0x0E, 0x0E, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, + 0x0E, 0x0D, 0x0E, 0x0D, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0D, 0x0E, 0x0D, 0x0D, 0x0D, + 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, + 0x0D, 0x0D, 0x0D, 0x0D, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0D, 0x0D, 0x0D, + 0x0D, 0x0D, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, + 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0D, 0x0E, 0x0E, 0x0E, 0x0E, 0x0D, 0x0E, 0x0D, 0x0E, 0x0D, 0x0D, + 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0D, 0x0E, 0x0D, 0x0D, + 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0D, 0x0E, 0x0E, + 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0D, 0x0D, 0x0D, 0x0E, 0x0E, + 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, + 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0F, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, + 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0F, 0x0F, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, + 0x0F, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0F, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, + 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, + 0x0E, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, + 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, + 0x0F, 0x0F, 0x0F, 0x0E, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, + 0x0E, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0E, 0x0F, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, + 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0E, 0x0F, 0x0F, 0x0F, + 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x10, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0E, + 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0E, + 0x0F, 0x0E, 0x0F, 0x0E, 0x0F, 0x0F, 0x0F, 0x0E, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0E, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x0E, 0x0F, 0x0F, 0x0E, 0x0F, 0x0F, 0x0F, + 0x0F, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0F, 0x0F, + 0x0F, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0F, 0x0F, + 0x0F, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0F, 0x0F, + 0x0F, 0x0F, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0F, + 0x0F, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0F, 0x0F, + 0x0F, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0F, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0F, 0x0F, + 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0F, + 0x0F, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0F, + 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0F, 0x0E, 0x0F, 0x0F, 0x0F, 0x0F, + 0x0F, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0F, 0x0F, 0x0F, + 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0F, 0x0F, 0x0E, + 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0F, + 0x0F, 0x0F, 0x0F, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0F, 0x0F, + 0x0F, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0F, 0x0F, + 0x0F, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0F, 0x0E, 0x0E, 0x0F, + 0x0F, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0F, 0x0E, 0x0E, 0x0F, 0x0F, + 0x0F, 0x0F, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0F, 0x0E, 0x0F, 0x0F, + 0x0F, 0x0E, 0x0F, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0F, + 0x0F, 0x0F, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0F, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0F, 0x0F, + 0x0F, 0x0E, 0x0E, 0x0F, 0x0E, 0x0E, 0x0E, 0x0E, 0x0F, 0x0F, 0x0E, 0x0E, 0x0E, 0x0F, 0x0F, 0x0F, + 0x0F, 0x0F, 0x0F, 0x0F, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, + 0x0F, 0x0F, 0x0F, 0x0F, 0x0E, 0x0E, 0x0F, 0x0E, 0x0F, 0x0E, 0x0E, 0x0E, 0x0F, 0x0F, 0x0F, 0x0F, + 0x0F, 0x0F, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0F, 0x0F, 0x0F, 0x0F, 0x0E, 0x0F, 0x0F, 0x0F, 0x0F, + 0x0F, 0x0F, 0x0F, 0x0F, 0x0E, 0x0E, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0E, 0x0F, 0x0F, 0x0F, 0x0F, + 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0E, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, + 0x0F, 0x0F, 0x0F, 0x0E, 0x0F, 0x0F, 0x0E, 0x0E, 0x10, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, + 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, + 0x10, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x10, 0x10, 0x10, 0x0F, 0x10, 0x10, 0x10, + 0x0F, 0x10, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x10, 0x0F, 0x10, 0x0F, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x10, 0x10, 0x10, 0x10, 0x0F, 0x10, + 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x10, 0x0F, 0x10, 0x10, 0x0F, 0x10, 0x10, 0x10, + 0x0F, 0x10, 0x10, 0x10, 0x0F, 0x10, 0x10, 0x0F, 0x10, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x10, 0x10, + 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x10, 0x10, 0x10, 0x0F, 0x0F, 0x0F, + 0x10, 0x10, 0x10, 0x0F, 0x10, 0x0F, 0x10, 0x0F, 0x10, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, + 0x0F, 0x10, 0x10, 0x0F, 0x0F, 0x0F, 0x0F, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x12, 0x11, 0x11, 0x10, 0x11, 0x10, 0x10, 0x10, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x12, 0x11, 0x11, 0x11, 0x11, 0x10, 0x10, 0x10, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x10, 0x10, 0x10, 0x10, 0x10, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x12, 0x11, 0x11, 0x11, 0x11, 0x10, 0x10, 0x10, 0x11, + 0x11, 0x11, 0x10, 0x10, 0x11, 0x11, 0x11, 0x12, 0x11, 0x11, 0x11, 0x10, 0x11, 0x10, 0x10, 0x10, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x10, 0x11, 0x11, 0x10, 0x10, + 0x11, 0x11, 0x11, 0x11, 0x10, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x10, 0x10, 0x11, 0x10, 0x10, + 0x11, 0x10, 0x10, 0x10, 0x10, 0x11, 0x11, 0x11, 0x11, 0x11, 0x10, 0x11, 0x11, 0x10, 0x11, 0x11, + 0x10, 0x11, 0x11, 0x10, 0x11, 0x11, 0x11, 0x11, 0x11, 0x10, 0x10, 0x10, 0x11, 0x10, 0x10, 0x11, + 0x10, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x12, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x10, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x10, 0x11, 0x10, 0x10, 0x11, 0x11, 0x10, + 0x11, 0x10, 0x10, 0x10, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x10, 0x11, + 0x11, 0x11, 0x10, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x10, 0x10, 0x10, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x10, 0x11, 0x11, 0x11, 0x10, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x10, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x10, 0x11, + 0x10, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x10, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x10, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x12, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x12, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x10, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x12, 0x12, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x12, 0x12, 0x11, 0x12, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x12, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x12, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x11, + 0x11, 0x11, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x11, 0x11, 0x11, 0x12, 0x11, 0x11, 0x11, + 0x11, 0x12, 0x12, 0x12, 0x11, 0x12, 0x12, 0x12, 0x12, 0x12, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x11, 0x12, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x12, 0x11, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x11, + 0x12, 0x11, 0x12, 0x11, 0x11, 0x11, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x11, 0x11, + 0x12, 0x11, 0x12, 0x12, 0x12, 0x11, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x11, + 0x12, 0x11, 0x12, 0x11, 0x11, 0x11, 0x11, 0x11, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x11, 0x11, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x13, 0x14, 0x13, 0x14, 0x14, 0x13, 0x14, + 0x13, 0x12, 0x13, 0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x14, + 0x13, 0x12, 0x12, 0x12, 0x13, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x14, 0x14, + 0x13, 0x12, 0x13, 0x13, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x14, 0x14, + 0x13, 0x13, 0x13, 0x13, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x14, + 0x13, 0x13, 0x13, 0x13, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x14, 0x13, + 0x13, 0x13, 0x13, 0x12, 0x13, 0x13, 0x12, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, + 0x13, 0x13, 0x13, 0x12, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x12, 0x12, 0x13, 0x13, 0x13, + 0x13, 0x12, 0x13, 0x13, 0x13, 0x12, 0x12, 0x13, 0x12, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, + 0x12, 0x12, 0x12, 0x13, 0x12, 0x12, 0x13, 0x13, 0x12, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x14, + 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, + 0x12, 0x13, 0x13, 0x12, 0x12, 0x13, 0x13, 0x12, 0x13, 0x12, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, + 0x13, 0x13, 0x13, 0x13, 0x12, 0x13, 0x13, 0x13, 0x13, 0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, + 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, + 0x13, 0x13, 0x13, 0x13, 0x12, 0x13, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, + 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x12, 0x13, 0x13, 0x13, 0x13, 0x14, 0x13, 0x13, 0x13, + 0x13, 0x13, 0x13, 0x13, 0x12, 0x12, 0x13, 0x12, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x14, + 0x13, 0x13, 0x13, 0x12, 0x13, 0x13, 0x12, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, + 0x13, 0x12, 0x13, 0x13, 0x12, 0x13, 0x13, 0x12, 0x13, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13, 0x13, + 0x13, 0x13, 0x13, 0x13, 0x12, 0x13, 0x12, 0x13, 0x13, 0x13, 0x13, 0x13, 0x12, 0x13, 0x13, 0x13, + 0x13, 0x13, 0x13, 0x13, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, + 0x13, 0x13, 0x13, 0x13, 0x12, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, + 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, + 0x13, 0x13, 0x13, 0x13, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x12, 0x13, 0x14, + 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, + 0x13, 0x14, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x14, 0x13, 0x13, 0x14, + 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x14, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, + 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x14, + 0x14, 0x14, 0x13, 0x14, 0x13, 0x13, 0x14, 0x13, 0x13, 0x13, 0x14, 0x13, 0x13, 0x13, 0x14, 0x14, + 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x14, 0x13, 0x13, 0x14, 0x14, 0x13, + 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x14, 0x13, 0x13, 0x14, 0x13, 0x13, 0x13, 0x13, + 0x14, 0x14, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x14, 0x13, 0x13, 0x13, 0x14, 0x13, 0x13, 0x14, + 0x14, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x14, 0x13, 0x13, 0x13, 0x13, 0x12, 0x13, 0x13, + 0x13, 0x13, 0x13, 0x14, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x14, + 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x14, 0x13, 0x14, 0x13, 0x13, 0x13, 0x13, 0x13, + 0x14, 0x14, 0x14, 0x13, 0x14, 0x13, 0x13, 0x13, 0x14, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, + 0x13, 0x13, 0x13, 0x14, 0x13, 0x13, 0x13, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x05, 0x02, 0x01, 0x01, 0xF4, 0x01, 0xD0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x24, 0x02, 0x10, 0x11, + 0x00, 0x06, 0x69, 0x5F, 0x00, 0x00, 0x00, 0x00, 0xB0, 0x56, 0x8E, 0xEE, 0x44, 0x23, 0x00, 0x00, + 0xEB, 0x1E, 0x00, 0x00, 0x0C, 0x1F, 0x00, 0x00, 0x2D, 0x1F, 0x00, 0x00, 0x4E, 0x1F, 0x00, 0x00, + 0x6F, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1B, 0x03, 0x00, 0x00, + 0x01, 0x88, 0x41, 0x0A, 0xE6, 0xA0, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x20, 0x20, 0x20, 0x20, 0x05, 0x02, 0x02, 0x02, + 0x52, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD2, 0x1F, 0x3E, 0x20, + 0x6A, 0x20, 0x30, 0x21, 0x05, 0x22, 0x4E, 0x21, 0xF6, 0x21, 0xF5, 0x22, 0x00, 0xB8, 0xC3, 0x07, + 0xD6, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x05, 0x58, 0x05, 0xA0, 0x05, + 0xE8, 0x05, 0x00, 0x00, 0x10, 0x40, 0x04, 0x0D, 0x0F, 0x0B, 0x0D, 0x0D, 0x10, 0x00, 0x0E, 0x11, + 0xA5, 0xBB, 0x03, 0x1F, 0x7E, 0xF8, 0x0F, 0x00, 0x13, 0x0F, 0x13, 0x0F, 0x0F, 0x43, 0x0F, 0x43, + 0x1B, 0x03, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xD2, 0x1F, 0x3E, 0x20, 0x6A, 0x20, 0x30, 0x21, 0x05, 0x22, 0x4E, 0x21, 0xF6, 0x21, 0xF5, 0x22, + 0x00, 0xB8, 0xC3, 0x07, 0xD6, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x48, 0x00, 0x90, 0x00, 0xD8, 0x00, 0x00, 0x00, 0x10, 0x40, 0x04, 0x0D, 0x0F, 0x0B, 0x0D, 0x0D, + 0x10, 0x00, 0x0E, 0x11, 0xA5, 0xBB, 0x03, 0x1F, 0x7E, 0xF8, 0x0F, 0x00, 0x13, 0x0F, 0x13, 0x0F, + 0x0F, 0x43, 0x0F, 0x43, 0x1B, 0x03, 0x00, 0x00, 0x01, 0x88, 0x41, 0x0A, 0xE6, 0xA0, 0x04, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, + 0x27, 0x27, 0x27, 0x27, 0x75, 0x72, 0x72, 0x72, 0x52, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x36, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xD2, 0x1F, 0x3E, 0x20, 0x6A, 0x20, 0x30, 0x21, 0x05, 0x22, 0x4E, 0x21, + 0xF6, 0x21, 0xF5, 0x22, 0x00, 0xB8, 0xC3, 0x07, 0xD6, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x10, 0x05, 0x58, 0x05, 0xA0, 0x05, 0xE8, 0x05, 0x00, 0x00, 0x10, 0x40, 0x04, 0x0D, + 0x0F, 0x0B, 0x0D, 0x0D, 0x10, 0x00, 0x0E, 0x11, 0xA5, 0xBB, 0x03, 0x1F, 0x7E, 0xF8, 0x0F, 0x00, + 0x13, 0x0F, 0x13, 0x0F, 0x0F, 0x43, 0x0F, 0x43, 0x1B, 0x03, 0x00, 0x00, 0x8B, 0x35, 0xF7, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x18, 0x00, 0x00, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD2, 0x1F, 0x3E, 0x20, 0x6A, 0x20, 0x30, 0x21, + 0x05, 0x22, 0x4E, 0x21, 0xF6, 0x21, 0xF5, 0x22, 0x00, 0xB8, 0xC3, 0x07, 0xD6, 0x38, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x90, 0x00, 0xD8, 0x00, 0x00, 0x00, + 0x10, 0x40, 0x04, 0x0D, 0x0F, 0x0B, 0x0D, 0x0D, 0x10, 0x00, 0x0E, 0x11, 0xA5, 0xBB, 0x03, 0x1F, + 0x7E, 0xF8, 0x0F, 0x00, 0x13, 0x0F, 0x13, 0x0F, 0x0F, 0x43, 0x0F, 0x43, 0x1B, 0x03, 0x00, 0x00, + 0x8B, 0x35, 0xF7, 0x20, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x27, 0x27, 0x27, 0x03, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x33, 0x02, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD2, 0x1F, 0x3E, 0x20, + 0x6A, 0x20, 0x30, 0x21, 0x05, 0x22, 0x4E, 0x21, 0xF6, 0x21, 0xF5, 0x22, 0x00, 0xB8, 0xC3, 0x07, + 0xD6, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x90, 0x00, + 0xD8, 0x00, 0x00, 0x00, 0x10, 0x40, 0x04, 0x0D, 0x0F, 0x0B, 0x0D, 0x0D, 0x10, 0x00, 0x0E, 0x11, + 0xA5, 0xBB, 0x03, 0x1F, 0x7E, 0xF8, 0x0F, 0x00, 0x13, 0x0F, 0x13, 0x0F, 0x0F, 0x43, 0x0F, 0x43, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x09, 0x01, 0x00, + 0x01, 0x28, 0x00, 0x00, 0x00, 0xD8, 0x03, 0x00, 0x00, 0x00, 0x12, 0x00, 0xA5, 0x1D, 0x02, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x02, 0x02, 0x28, 0x00, 0x00, 0x00, 0xD8, 0x03, 0x00, + 0x00, 0x00, 0x0F, 0x00, 0xA6, 0x1D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x05, 0x04, + 0x03, 0x28, 0x00, 0x00, 0x00, 0xD8, 0x03, 0x00, 0x01, 0x00, 0x0E, 0x00, 0xA7, 0x1D, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x05, 0x04, 0x04, 0x28, 0x00, 0x00, 0x00, 0xD8, 0x03, 0x00, + 0x02, 0x00, 0x0D, 0x00, 0xA8, 0x1D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0x05, 0x04, + 0x05, 0x28, 0x00, 0x00, 0x00, 0xD8, 0x03, 0x00, 0x03, 0x00, 0x0C, 0x00, 0xA9, 0x1D, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x04, 0x04, 0x05, 0x04, 0x06, 0x28, 0x00, 0x00, 0x00, 0xD8, 0x03, 0x00, + 0x04, 0x00, 0x0B, 0x00, 0xAA, 0x1D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x05, 0x05, 0x04, + 0x07, 0x28, 0x00, 0x00, 0x00, 0xD8, 0x03, 0x00, 0x05, 0x00, 0x0A, 0x00, 0xAB, 0x1D, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x05, 0x04, 0x08, 0x28, 0x00, 0x00, 0x00, 0xD8, 0x03, 0x00, + 0x06, 0x00, 0x09, 0x00, 0xAC, 0x1D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x07, 0x05, 0x04, + 0x09, 0x28, 0x00, 0x00, 0x00, 0xD8, 0x03, 0x00, 0x07, 0x00, 0x08, 0x00, 0xAD, 0x1D, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x02, 0x02, 0x0A, 0x28, 0x00, 0x00, 0x00, 0xD8, 0x03, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xAE, 0x1D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x09, 0x01, 0x00, + 0x00, 0x28, 0x00, 0x00, 0x00, 0xD8, 0x03, 0x00, 0x80, 0x14, 0x92, 0x14, 0xA5, 0x1D, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x09, 0x09, 0x01, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0xD8, 0x03, 0x00, + 0x00, 0x00, 0x12, 0x00, 0xA5, 0x1D, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x09, 0x01, 0x00, + 0x00, 0x28, 0x00, 0x00, 0x00, 0xD8, 0x03, 0x00, 0x90, 0x00, 0xA2, 0x00, 0xA6, 0x1D, 0x02, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x09, 0x09, 0x01, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0xD8, 0x03, 0x00, + 0x20, 0x01, 0x32, 0x01, 0xA7, 0x1D, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x09, 0x01, 0x00, + 0x00, 0x28, 0x00, 0x00, 0x00, 0xD8, 0x03, 0x00, 0xB0, 0x01, 0xC2, 0x01, 0xA8, 0x1D, 0x02, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x09, 0x09, 0x01, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0xD8, 0x03, 0x00, + 0x40, 0x02, 0x52, 0x02, 0xA9, 0x1D, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x09, 0x01, 0x00, + 0x00, 0x28, 0x00, 0x00, 0x00, 0xD8, 0x03, 0x00, 0xD0, 0x02, 0xE2, 0x02, 0xAA, 0x1D, 0x02, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x09, 0x09, 0x01, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0xD8, 0x03, 0x00, + 0x80, 0x14, 0x92, 0x14, 0x00, 0x00, 0x02, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x05, 0xB4, 0x05, 0x00, + 0x5D, 0x4C, 0x1B, 0x00, 0x61, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, + 0x15, 0x29, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x40, 0x00, + 0x15, 0x29, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0D, 0xFC, 0x43, 0x00, + 0xFF, 0xFC, 0x1B, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0xFC, 0x43, 0x00, + 0xFF, 0xFC, 0x1B, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0D, 0xB4, 0x41, 0x00, + 0x5D, 0x4B, 0x1B, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0xB4, 0x41, 0x00, + 0x5D, 0x4B, 0x1B, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x01, 0xB4, 0x05, 0x00, + 0x5D, 0x4B, 0x1B, 0x00, 0xE1, 0x00, 0x01, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x01, 0x00, 0x04, 0x00, + 0x15, 0x29, 0x00, 0x00, 0xE0, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x40, 0x00, + 0x15, 0x29, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x05, 0xFC, 0x07, 0x00, + 0xFF, 0xFC, 0x1B, 0x00, 0x61, 0x00, 0x00, 0x00, 0x2B, 0x2B, 0x2D, 0x2E, 0x2B, 0x2C, 0x2C, 0x2C, + 0x2C, 0x2B, 0x2C, 0x2C, 0x2B, 0x2B, 0x2D, 0x2C, 0x2A, 0x2C, 0x2C, 0x2D, 0x2A, 0x2B, 0x2D, 0x2C, + 0x2B, 0x2B, 0x2B, 0x2D, 0x2A, 0x2C, 0x2D, 0x2D, 0x2A, 0x2A, 0x2C, 0x2C, 0x2B, 0x29, 0x2D, 0x2C, + 0x2B, 0x2B, 0x2C, 0x2C, 0x2B, 0x2B, 0x2B, 0x2D, 0x63, 0x70, 0xA7, 0xBF, 0x68, 0xA9, 0x96, 0x94, + 0xA6, 0x2D, 0x9A, 0x99, 0x9E, 0x2D, 0x9B, 0xA7, 0xB5, 0x83, 0x9D, 0xAB, 0x8A, 0x95, 0xAA, 0xAF, + 0x2B, 0x2B, 0x2C, 0x2E, 0x2B, 0x2C, 0x2C, 0x2C, 0x2B, 0x2B, 0x2C, 0x2C, 0x2B, 0x2B, 0x2C, 0x2C, + 0x2A, 0x2C, 0x2C, 0x2D, 0x2A, 0x2B, 0x2D, 0x2C, 0x2A, 0x2B, 0x2B, 0x2D, 0x2A, 0x2C, 0x2D, 0x2D, + 0x2A, 0x2A, 0x2C, 0x2C, 0x2B, 0x29, 0x2D, 0x2C, 0x2A, 0x2B, 0x2B, 0x2C, 0x2B, 0x2B, 0x2B, 0x2C, + 0x2C, 0x2C, 0x2C, 0x2C, 0x2B, 0x29, 0x2C, 0x2C, 0x2B, 0x2B, 0x2D, 0x2D, 0x2C, 0x2B, 0x2D, 0x2B, + 0x2A, 0x2B, 0x2C, 0x2E, 0x2A, 0x2C, 0x2D, 0x2C, 0x2B, 0x2B, 0x2C, 0x2E, 0x2B, 0x2C, 0x2C, 0x2C, + 0x2B, 0x2B, 0x2C, 0x2C, 0x2B, 0x2B, 0x2C, 0x2C, 0x2A, 0x2C, 0x2C, 0x2D, 0x2A, 0x2B, 0x2D, 0x2C, + 0x2A, 0x2B, 0x2B, 0x2D, 0x2A, 0x2C, 0x2D, 0x2E, 0x2A, 0x2A, 0x2C, 0x2C, 0x2A, 0x29, 0x2D, 0x2C, + 0x2A, 0x2B, 0x2B, 0x2C, 0x2B, 0x2B, 0x2B, 0x2C, 0x2B, 0x2B, 0x2B, 0x2C, 0x2B, 0x29, 0x2C, 0x2C, + 0x2B, 0x2B, 0x2D, 0x2D, 0x2C, 0x2B, 0x2D, 0x2C, 0x2A, 0x2B, 0x2C, 0x2E, 0x2A, 0x2B, 0x2D, 0x2D, + 0x2C, 0x2B, 0x2C, 0x2E, 0x2B, 0x2C, 0x2C, 0x2C, 0x2C, 0x2B, 0x2C, 0x2C, 0x2B, 0x2B, 0x2C, 0x2C, + 0x2A, 0x2C, 0x2C, 0x2D, 0x2A, 0x2B, 0x2D, 0x2C, 0x2A, 0x2B, 0x2B, 0x2D, 0x2A, 0x2C, 0x2D, 0x2D, + 0x2A, 0x2A, 0x2C, 0x2C, 0x2A, 0x29, 0x2D, 0x2C, 0x2A, 0x2B, 0x2B, 0x2C, 0x2B, 0x2B, 0x2B, 0x2C, + 0x2B, 0x2C, 0x2B, 0x2C, 0x2B, 0x29, 0x2C, 0x2C, 0x2B, 0x2B, 0x2D, 0x2D, 0x2C, 0x2B, 0x2D, 0x2C, + 0x2A, 0x2B, 0x2C, 0x2F, 0x2A, 0x2B, 0x2D, 0x2D, 0x2C, 0x2B, 0x2C, 0x2E, 0x2B, 0x2C, 0x2C, 0x2C, + 0x2B, 0x2B, 0x2C, 0x2C, 0x2B, 0x2B, 0x2C, 0x2C, 0x2A, 0x2C, 0x2C, 0x2D, 0x2A, 0x2B, 0x2D, 0x2C, + 0xFF, 0x8F, 0xA2, 0xAF, 0x85, 0x81, 0xAD, 0xB1, 0x7C, 0x73, 0xAA, 0xB1, 0x70, 0x69, 0xB3, 0xB6, + 0x69, 0x6F, 0xBA, 0xBF, 0x63, 0x5F, 0xC1, 0x9B, 0x2B, 0x2B, 0x2B, 0x2C, 0x2B, 0x29, 0x2C, 0x2C, + 0x2B, 0x2B, 0x2C, 0x2D, 0x2C, 0x2B, 0x2D, 0x2C, 0x2A, 0x2B, 0x2C, 0x2E, 0x2A, 0x2B, 0x2D, 0x2D, + 0x2C, 0x2B, 0x2C, 0x2E, 0x2B, 0x2C, 0x2C, 0x2C, 0x2C, 0x2B, 0x2C, 0x2C, 0x2B, 0x2B, 0x2C, 0x2C, + 0x2A, 0x2C, 0x2C, 0x2D, 0x2A, 0x2B, 0x2D, 0x2C, 0x2A, 0x2B, 0x2B, 0x2D, 0x2A, 0x2C, 0x2D, 0x2D, + 0x2A, 0x2A, 0x2C, 0x2C, 0x2B, 0x29, 0x2D, 0x2C, 0x2A, 0x2B, 0x2B, 0x2C, 0x2B, 0x2B, 0x2B, 0x2C, + 0x2C, 0x2C, 0x2C, 0x2C, 0x2B, 0x29, 0x2C, 0x2D, 0x2B, 0x2B, 0x2D, 0x2D, 0x2C, 0x2B, 0x2D, 0x2C, + 0x2B, 0x2B, 0x2C, 0x2F, 0x2A, 0x2C, 0x2D, 0x2D, 0x2C, 0x2B, 0x2C, 0x2E, 0x2B, 0x2C, 0x2C, 0x2C, + 0x2C, 0x2B, 0x2C, 0x2D, 0x2B, 0x2B, 0x2C, 0x2C, 0x2A, 0x2C, 0x2C, 0x2D, 0x2A, 0x2B, 0x2D, 0x2C, + 0x2A, 0x2B, 0x2B, 0x2D, 0x2A, 0x2C, 0x2D, 0x2D, 0x2A, 0x2A, 0x2C, 0x2C, 0x2B, 0x29, 0x2D, 0x2C, + 0x2A, 0x2B, 0x2B, 0x2C, 0x2B, 0x2B, 0x2B, 0x2C, 0x2C, 0x2C, 0x2C, 0x2C, 0x2B, 0x29, 0x2C, 0x2D, + 0x2B, 0x2B, 0x2D, 0x2D, 0x2C, 0x2B, 0x2D, 0x2C, 0x2A, 0x2B, 0x2C, 0x2F, 0x2A, 0x2C, 0x2D, 0x2D, + 0x2D, 0x2C, 0x2C, 0x2E, 0x2C, 0x2C, 0x2C, 0x2C, 0x2D, 0x2C, 0x2C, 0x2C, 0x2C, 0x2B, 0x2C, 0x2C, + 0x2B, 0x2D, 0x2C, 0x2D, 0x2B, 0x2B, 0x2D, 0x2C, 0x2B, 0x2B, 0x2B, 0x2D, 0x2A, 0x2C, 0x2D, 0x2D, + 0x2B, 0x2B, 0x2C, 0x2C, 0x2B, 0x29, 0x2D, 0x2C, 0x2B, 0x2B, 0x2C, 0x2C, 0x2B, 0x2B, 0x2B, 0x2C, + 0x2C, 0x2C, 0x2C, 0x2C, 0x2C, 0x29, 0x2D, 0x2C, 0x2B, 0x2C, 0x2D, 0x2D, 0x2C, 0x2B, 0x2E, 0x2C, + 0x2B, 0x2B, 0x2D, 0x2F, 0x2A, 0x2C, 0x2E, 0x2D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7B, 0x97, 0x43, 0x47, 0x8F, 0x93, 0x43, 0x45, + 0x93, 0xA5, 0x43, 0x45, 0x43, 0x43, 0x95, 0x8B, 0x43, 0x45, 0x89, 0x93, 0x43, 0x43, 0x8B, 0x8B, + 0xFF, 0x95, 0xA3, 0xAF, 0x8D, 0x8B, 0xAB, 0xAF, 0x85, 0x7F, 0xA9, 0xAF, 0x7B, 0x75, 0xB1, 0xB3, + 0x75, 0x7B, 0xB7, 0xBB, 0x6F, 0x6F, 0xF5, 0x9F, 0x71, 0x7B, 0xA7, 0xBB, 0x75, 0xA7, 0x99, 0x99, + 0xA5, 0x47, 0x9D, 0x9D, 0x9F, 0x45, 0x9F, 0xA7, 0xB1, 0x8B, 0x9F, 0xAB, 0x8F, 0x99, 0xAB, 0xAF, + 0xB6, 0x6D, 0xB6, 0x6D, 0xB6, 0x05, 0xB6, 0x05, 0x00, 0x00, 0x00, 0x00, 0xB6, 0x6D, 0xB6, 0x6D, + 0xB6, 0x0C, 0xB6, 0x0C, 0x00, 0x00, 0x00, 0x00, 0xB6, 0x6D, 0xB6, 0x6D, 0x96, 0x0D, 0x96, 0x0D, + 0x00, 0x00, 0x00, 0x00, 0xB6, 0x6D, 0xB6, 0x6D, 0xB2, 0x0D, 0xB2, 0x0D, 0x00, 0x00, 0x00, 0x00, + 0xB6, 0x2D, 0xB6, 0x2D, 0xB6, 0x0D, 0xB6, 0x0D, 0x00, 0x00, 0x00, 0x00, 0xB6, 0x65, 0xB6, 0x65, + 0xB6, 0x0D, 0xB6, 0x0D, 0x00, 0x00, 0x00, 0x00, 0xB6, 0x6C, 0xB6, 0x6C, 0xB6, 0x0D, 0xB6, 0x0D, + 0x00, 0x00, 0x00, 0x00, 0x96, 0x6D, 0x96, 0x6D, 0xB6, 0x0D, 0xB6, 0x0D, 0x00, 0x00, 0x00, 0x00, + 0xB2, 0x6D, 0xB2, 0x6D, 0xB6, 0x0D, 0xB6, 0x0D, 0x00, 0x00, 0x00, 0x00, 0x92, 0x24, 0x92, 0x24, + 0x92, 0x04, 0x92, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3D, 0xDB, 0x38, 0xD4, 0xFC, 0x02, 0x02, 0x00, 0xFF, 0x00, + 0x6C, 0x76, 0x8A, 0x94, 0xDB, 0x06, 0x00, 0x00, 0x04, 0x0C, 0x00, 0x00, 0xB0, 0x03, 0x57, 0x00, + 0x36, 0xEA, 0x08, 0x02, 0x01, 0x00, 0x00, 0x00, 0x4E, 0x03, 0xEA, 0x00, 0x47, 0x7E, 0xEC, 0x14, + 0xFF, 0xFF, 0x00, 0x80, 0x1C, 0x84, 0x0C, 0x57, 0x03, 0x80, 0xBB, 0xBB, 0x80, 0x44, 0x22, 0x00, + 0x64, 0x15, 0x64, 0x15, 0x88, 0x39, 0x8A, 0x39, 0x35, 0x00, 0x35, 0x00, 0x01, 0x10, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3D, 0xDB, 0x38, 0xD4, 0xFC, 0x02, + 0x02, 0x00, 0xFF, 0x00, 0x6C, 0x76, 0x8A, 0x94, 0xDB, 0x06, 0x00, 0x00, 0x04, 0x0C, 0x00, 0x00, + 0xB0, 0x03, 0x57, 0x00, 0x36, 0xEA, 0x08, 0x02, 0x41, 0x00, 0x02, 0x00, 0x4E, 0x03, 0xEA, 0x00, + 0x47, 0x7E, 0xEC, 0x14, 0xFF, 0xFF, 0x00, 0x80, 0x1C, 0x84, 0x0C, 0x17, 0xE3, 0x8E, 0xBA, 0xBB, + 0x80, 0x55, 0x22, 0x00, 0x64, 0x15, 0x64, 0x15, 0x88, 0x39, 0x8A, 0x39, 0x35, 0x00, 0x35, 0x00, + 0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0xFF, 0x00, 0x6C, 0x76, 0x8A, 0x94, 0xDB, 0x06, 0x00, 0x00, + 0x04, 0x0C, 0x00, 0x00, 0xB0, 0x03, 0x57, 0x00, 0x36, 0xEA, 0x08, 0x02, 0x01, 0x00, 0x00, 0x00, + 0x4E, 0x03, 0xEA, 0x00, 0x47, 0x7E, 0xEC, 0x14, 0xFF, 0xFF, 0x00, 0x80, 0x1C, 0x04, 0x0C, 0x57, + 0x03, 0x80, 0xBB, 0xBB, 0x80, 0x45, 0x22, 0x00, 0x64, 0x15, 0x64, 0x15, 0x88, 0x39, 0x8A, 0x39, + 0x35, 0x00, 0x35, 0x00, 0x8E, 0x04, 0x02, 0x00, 0x01, 0x02, 0x03, 0x04, 0x82, 0xEF, 0xEF, 0xFB, + 0x29, 0x6F, 0x76, 0xB6, 0xCF, 0x03, 0x04, 0x02, 0x1E, 0x06, 0x00, 0x03, 0x6C, 0x76, 0x8A, 0x94, + 0xDB, 0x06, 0x00, 0x00, 0x01, 0x45, 0x00, 0x00, 0xC0, 0x0F, 0x00, 0x00, 0x00, 0xEA, 0x08, 0x02, + 0x41, 0x00, 0x02, 0x00, 0x00, 0x00, 0xEA, 0x00, 0x47, 0x7E, 0xEC, 0x14, 0xFF, 0xFF, 0x00, 0x80, + 0x1C, 0x5C, 0x11, 0x97, 0x00, 0x80, 0xBA, 0xBB, 0x00, 0x57, 0x22, 0x00, 0x64, 0xD1, 0x64, 0xD1, + 0x88, 0x19, 0x8A, 0x19, 0x35, 0x00, 0x35, 0x00, 0x8E, 0x04, 0x02, 0x00, 0x01, 0x01, 0x01, 0x01, + 0x82, 0xEF, 0xEF, 0xFB, 0x29, 0x6F, 0x76, 0xB6, 0xCF, 0x03, 0x04, 0x02, 0x02, 0x06, 0x00, 0x00, + 0x6C, 0x76, 0x8A, 0x94, 0xDB, 0x06, 0x00, 0x00, 0x01, 0x45, 0x00, 0x00, 0xC0, 0x0F, 0x00, 0x00, + 0x00, 0xEA, 0x08, 0x02, 0x41, 0x00, 0x02, 0x00, 0x00, 0x00, 0xEA, 0x00, 0x39, 0x7D, 0x84, 0x1A, + 0xFF, 0xFF, 0x00, 0x80, 0x1C, 0x5C, 0x11, 0xBF, 0x00, 0x80, 0xBB, 0xBB, 0x00, 0x46, 0x22, 0x00, + 0x64, 0xD1, 0x64, 0xD1, 0x88, 0x39, 0x8A, 0x39, 0x35, 0x00, 0x35, 0x00, 0x8E, 0x04, 0x02, 0x00, + 0x02, 0x02, 0x02, 0x02, 0x82, 0xEF, 0xEF, 0xFB, 0x29, 0x6F, 0x76, 0xB6, 0xCF, 0x03, 0x04, 0x02, + 0x02, 0x06, 0xAA, 0x00, 0x6C, 0x76, 0x8A, 0x94, 0xDB, 0x06, 0x00, 0x00, 0x01, 0x45, 0x00, 0x00, + 0xC0, 0x0F, 0x00, 0x00, 0x00, 0xEA, 0x08, 0x02, 0x41, 0x00, 0x02, 0x00, 0x00, 0x00, 0xEA, 0x00, + 0x9F, 0x7D, 0x8D, 0x18, 0xFF, 0xFF, 0x00, 0x80, 0x1C, 0x5C, 0x11, 0xBF, 0x00, 0x80, 0xBB, 0xBB, + 0x00, 0x46, 0x22, 0x00, 0x64, 0xD1, 0x64, 0xD1, 0x88, 0x39, 0x8A, 0x39, 0x35, 0x00, 0x35, 0x00, + 0x8E, 0x04, 0x02, 0x00, 0x03, 0x03, 0x03, 0x03, 0x82, 0xEF, 0xEF, 0xFB, 0x29, 0x6F, 0x76, 0xB6, + 0xCF, 0x03, 0x04, 0x02, 0x02, 0x06, 0xAA, 0x00, 0x6C, 0x76, 0x8A, 0x94, 0xDB, 0x06, 0x00, 0x00, + 0x01, 0x45, 0x00, 0x00, 0xC0, 0x0F, 0x00, 0x00, 0x00, 0xEA, 0x08, 0x02, 0x41, 0x00, 0x02, 0x00, + 0x00, 0x00, 0xEA, 0x00, 0x66, 0x7E, 0x2B, 0x14, 0xFF, 0xFF, 0x00, 0x80, 0x1C, 0x5C, 0x11, 0xBF, + 0x00, 0x80, 0xBB, 0xBB, 0x00, 0x46, 0x22, 0x00, 0x64, 0xD1, 0x64, 0xD1, 0x88, 0x39, 0x8A, 0x39, + 0x35, 0x00, 0x35, 0x00, 0x8E, 0x04, 0x02, 0x00, 0x04, 0x04, 0x04, 0x04, 0x82, 0xEF, 0xEF, 0xFB, + 0x29, 0x6F, 0x76, 0xB6, 0xCF, 0x03, 0x04, 0x02, 0x02, 0x06, 0x00, 0x00, 0x6C, 0x76, 0x8A, 0x94, + 0xDB, 0x06, 0x00, 0x00, 0x01, 0x45, 0x00, 0x00, 0xC0, 0x0F, 0x00, 0x00, 0x00, 0xEA, 0x08, 0x02, + 0x41, 0x00, 0x02, 0x00, 0x00, 0x00, 0xEA, 0x00, 0xE9, 0x7E, 0xA5, 0x10, 0xFF, 0xFF, 0x00, 0x80, + 0x1C, 0x5C, 0x11, 0xBF, 0x00, 0x80, 0xBB, 0xBB, 0x00, 0x46, 0x22, 0x00, 0x64, 0xD1, 0x64, 0xD1, + 0x88, 0x39, 0x8A, 0x39, 0x35, 0x00, 0x35, 0x00, 0x00, 0x00, 0x5D, 0x3F, 0x00, 0x00, 0xDA, 0x47, + 0xC0, 0xCE, 0xD0, 0xC7, 0xFF, 0xFF, 0x30, 0xCD, 0x00, 0x00, 0x66, 0x13, 0x3F, 0x0E, 0x30, 0x06, + 0xFF, 0xFF, 0x00, 0xF9, 0x00, 0x00, 0x0E, 0xA4, 0xFF, 0xCE, 0xF0, 0xC5, 0xFF, 0xFF, 0x9C, 0x4E, + 0x00, 0x00, 0x5B, 0xA8, 0x3F, 0x0F, 0x30, 0x04, 0xFF, 0xFF, 0x39, 0x87, 0x00, 0x00, 0x54, 0xDB, + 0x3F, 0x0F, 0x30, 0x03, 0x35, 0xD0, 0x30, 0x03, 0x32, 0xC4, 0x00, 0x03, 0x2F, 0xB8, 0xD0, 0x02, + 0x2C, 0xAC, 0xA0, 0x02, 0x29, 0xA0, 0x70, 0x02, 0x26, 0x94, 0x40, 0x02, 0x23, 0x88, 0x10, 0x02, + 0x20, 0x7C, 0xE0, 0x01, 0x1D, 0x70, 0xB0, 0x01, 0x1A, 0x64, 0x80, 0x01, 0x17, 0x58, 0x50, 0x01, + 0x14, 0x4C, 0x20, 0x01, 0x00, 0x04, 0x20, 0x00, 0x03, 0x10, 0x50, 0x00, 0x06, 0x1C, 0x80, 0x00, + 0x09, 0x28, 0xB0, 0x00, 0x0C, 0x34, 0xE0, 0x00, 0x0F, 0x40, 0x10, 0x01, 0x12, 0x4C, 0x40, 0x01, + 0x15, 0x58, 0x70, 0x01, 0x18, 0x64, 0xA0, 0x01, 0x1B, 0x70, 0xD0, 0x01, 0x1E, 0x7C, 0x00, 0x02, + 0x21, 0x88, 0x30, 0x02, 0x00, 0x40, 0x00, 0x02, 0x30, 0x00, 0x01, 0x05, 0x60, 0xC0, 0x01, 0x08, + 0x90, 0x80, 0x02, 0x0B, 0xC0, 0x40, 0x03, 0x0E, 0xF0, 0x00, 0x04, 0x11, 0x20, 0xC1, 0x04, 0x14, + 0x50, 0x81, 0x05, 0x17, 0x80, 0x41, 0x06, 0x1A, 0xB0, 0x01, 0x07, 0x1D, 0xE0, 0xC1, 0x07, 0x20, + 0x10, 0x82, 0x08, 0x23, 0x30, 0x82, 0x08, 0x21, 0x00, 0xC2, 0x07, 0x1E, 0xD0, 0x01, 0x07, 0x1B, + 0xA0, 0x41, 0x06, 0x18, 0x70, 0x81, 0x05, 0x15, 0x40, 0xC1, 0x04, 0x12, 0x10, 0x01, 0x04, 0x0F, + 0xE0, 0x40, 0x03, 0x0C, 0xB0, 0x80, 0x02, 0x09, 0x80, 0xC0, 0x01, 0x06, 0x50, 0x00, 0x01, 0x03, + 0x20, 0x40, 0x00, 0x00, 0x30, 0x82, 0x08, 0x21, 0x00, 0xC2, 0x07, 0x1E, 0xD0, 0x01, 0x07, 0x1B, + 0xA0, 0x41, 0x06, 0x18, 0x70, 0x81, 0x05, 0x15, 0x40, 0xC1, 0x04, 0x12, 0x10, 0x01, 0x04, 0x0F, + 0xE0, 0x40, 0x03, 0x0C, 0xB0, 0x80, 0x02, 0x09, 0x80, 0xC0, 0x01, 0x06, 0x50, 0x00, 0x01, 0x03, + 0x20, 0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x02, 0x30, 0x00, 0x01, 0x05, 0x60, 0xC0, 0x01, 0x08, + 0x90, 0x80, 0x02, 0x0B, 0xC0, 0x40, 0x03, 0x0E, 0xF0, 0x00, 0x04, 0x11, 0x20, 0xC1, 0x04, 0x14, + 0x50, 0x81, 0x05, 0x17, 0x80, 0x41, 0x06, 0x1A, 0xB0, 0x01, 0x07, 0x1D, 0xE0, 0xC1, 0x07, 0x20, + 0x10, 0x82, 0x08, 0x23, 0x85, 0xCE, 0x19, 0x26, 0x4F, 0xF6, 0xB8, 0x22, 0x19, 0x1E, 0x58, 0x1F, + 0xE3, 0x45, 0xF7, 0x1B, 0xAD, 0x6D, 0x96, 0x18, 0x77, 0x95, 0x35, 0x15, 0x41, 0xBD, 0xD4, 0x11, + 0x0B, 0xE5, 0x73, 0x0E, 0xD5, 0x0C, 0x13, 0x0B, 0x9F, 0x34, 0xB2, 0x07, 0x69, 0x5C, 0x51, 0x04, + 0x33, 0x84, 0xF0, 0x00, 0x78, 0x9A, 0x49, 0x25, 0x42, 0xC2, 0xE8, 0x21, 0x0C, 0xEA, 0x87, 0x1E, + 0xD6, 0x11, 0x27, 0x1B, 0xA0, 0x39, 0xC6, 0x17, 0x6A, 0x61, 0x65, 0x14, 0x34, 0x89, 0x04, 0x11, + 0xFE, 0xB0, 0xA3, 0x0D, 0xC8, 0xD8, 0x42, 0x0A, 0x92, 0x00, 0xE2, 0x06, 0x5C, 0x28, 0x81, 0x03, + 0x26, 0x50, 0x20, 0x00, 0x84, 0xCA, 0x09, 0x26, 0x4E, 0xF2, 0xA8, 0x22, 0x18, 0x1A, 0x48, 0x1F, + 0xE2, 0x41, 0xE7, 0x1B, 0xAC, 0x69, 0x86, 0x18, 0x76, 0x91, 0x25, 0x15, 0x40, 0xB9, 0xC4, 0x11, + 0x0A, 0xE1, 0x63, 0x0E, 0xD4, 0x08, 0x03, 0x0B, 0x9E, 0x30, 0xA2, 0x07, 0x68, 0x58, 0x41, 0x04, + 0x32, 0x80, 0xE0, 0x00, 0x79, 0x9E, 0x59, 0x25, 0x43, 0xC6, 0xF8, 0x21, 0x0D, 0xEE, 0x97, 0x1E, + 0xD7, 0x15, 0x37, 0x1B, 0xA1, 0x3D, 0xD6, 0x17, 0x6B, 0x65, 0x75, 0x14, 0x35, 0x8D, 0x14, 0x11, + 0xFF, 0xB4, 0xB3, 0x0D, 0xC9, 0xDC, 0x52, 0x0A, 0x93, 0x04, 0xF2, 0x06, 0x5D, 0x2C, 0x91, 0x03, + 0x27, 0x54, 0x30, 0x00, 0x83, 0xC6, 0xF9, 0xE5, 0x4D, 0xEE, 0x98, 0xE2, 0x17, 0x16, 0x38, 0x1F, + 0xE1, 0x3D, 0xD7, 0x1B, 0xAB, 0x65, 0x76, 0xD8, 0x75, 0x8D, 0x15, 0x15, 0x3F, 0xB5, 0xB4, 0x11, + 0x09, 0xDD, 0x53, 0x0E, 0xD3, 0x04, 0xF3, 0x0A, 0x9D, 0x2C, 0x92, 0x07, 0x67, 0x54, 0x31, 0x04, + 0x31, 0x7C, 0xD0, 0x00, 0x7A, 0xA2, 0x69, 0x25, 0x44, 0xCA, 0x08, 0x22, 0x0E, 0xF2, 0xA7, 0x1E, + 0xD8, 0x19, 0x47, 0x1B, 0xA2, 0x41, 0xE6, 0x17, 0x6C, 0x69, 0x85, 0x14, 0x36, 0x91, 0x24, 0x11, + 0x00, 0xB9, 0xC3, 0x0D, 0xCA, 0xE0, 0x62, 0x0A, 0x94, 0x08, 0x02, 0x07, 0x5E, 0x30, 0xA1, 0x03, + 0x28, 0x58, 0x40, 0x00, 0x82, 0xC2, 0xE9, 0x25, 0x4C, 0xEA, 0x88, 0x22, 0x16, 0x12, 0x28, 0x1F, + 0xE0, 0x39, 0xC7, 0x1B, 0xAA, 0x61, 0x66, 0x18, 0x74, 0x89, 0x05, 0x15, 0x3E, 0xB1, 0xA4, 0x11, + 0x08, 0xD9, 0x43, 0x0E, 0xD2, 0x00, 0xE3, 0x0A, 0x9C, 0x28, 0x82, 0x07, 0x66, 0x50, 0x21, 0x04, + 0x30, 0x78, 0xC0, 0x00, 0x7B, 0xA6, 0x79, 0x25, 0x45, 0xCE, 0x18, 0x22, 0x0F, 0xF6, 0xB7, 0x1E, + 0xD9, 0x1D, 0x57, 0x1B, 0xA3, 0x45, 0xF6, 0x17, 0x6D, 0x6D, 0x95, 0x14, 0x37, 0x95, 0x34, 0x11, + 0x01, 0xBD, 0xD3, 0x0D, 0xCB, 0xE4, 0x72, 0x0A, 0x95, 0x0C, 0x12, 0x07, 0x5F, 0x34, 0xB1, 0x03, + 0x29, 0x5C, 0x50, 0x00, 0x81, 0xBE, 0xD9, 0x25, 0x4B, 0xE6, 0x78, 0x22, 0x15, 0x0E, 0x18, 0x1F, + 0xDF, 0x35, 0xB7, 0x1B, 0xA9, 0x5D, 0x56, 0x18, 0x73, 0x85, 0xF5, 0x14, 0x3D, 0xAD, 0x94, 0x11, + 0x07, 0xD5, 0x33, 0x0E, 0xD1, 0xFC, 0xD2, 0x0A, 0x9B, 0x24, 0x72, 0x07, 0x65, 0x4C, 0x11, 0x04, + 0x2F, 0x74, 0xB0, 0x00, 0x7C, 0xAA, 0x89, 0x25, 0x46, 0xD2, 0x28, 0x22, 0x10, 0xFA, 0xC7, 0x1E, + 0xDA, 0x21, 0x67, 0x1B, 0xA4, 0x49, 0x06, 0x18, 0x6E, 0x71, 0xA5, 0x14, 0x38, 0x99, 0x44, 0x11, + 0x02, 0xC1, 0xE3, 0x0D, 0xCC, 0xE8, 0x82, 0x0A, 0x96, 0x10, 0x22, 0x07, 0x60, 0x38, 0xC1, 0x03, + 0x2A, 0x60, 0x60, 0x00, 0x80, 0xBA, 0xC9, 0x25, 0x4A, 0xE2, 0x68, 0x22, 0x14, 0x0A, 0x08, 0x1F, + 0xDE, 0x31, 0xA7, 0x1B, 0xA8, 0x59, 0x46, 0x18, 0x72, 0x81, 0xE5, 0x14, 0x3C, 0xA9, 0x84, 0x11, + 0x06, 0xD1, 0x23, 0x0E, 0xD0, 0xF8, 0xC2, 0x0A, 0x9A, 0x20, 0x62, 0x07, 0x64, 0x48, 0x01, 0x04, + 0x2E, 0x70, 0xA0, 0x00, 0x7D, 0xAE, 0x99, 0x25, 0x47, 0xD6, 0x38, 0x22, 0x11, 0xFE, 0xD7, 0x1E, + 0xDB, 0x25, 0x77, 0x1B, 0xA5, 0x4D, 0x16, 0x18, 0x6F, 0x75, 0xB5, 0x14, 0x39, 0x9D, 0x54, 0x11, + 0x03, 0xC5, 0xF3, 0x0D, 0xCD, 0xEC, 0x92, 0x0A, 0x97, 0x14, 0x32, 0x07, 0x61, 0x3C, 0xD1, 0x03, + 0x2B, 0x64, 0x70, 0x00, 0x7F, 0xB6, 0xB9, 0x25, 0x49, 0xDE, 0x58, 0x22, 0x13, 0x06, 0xF8, 0x1E, + 0xDD, 0x2D, 0x97, 0x1B, 0xA7, 0x55, 0x36, 0x18, 0x71, 0x7D, 0xD5, 0x14, 0x3B, 0xA5, 0x74, 0x11, + 0x05, 0xCD, 0x13, 0x0E, 0xCF, 0xF4, 0xB2, 0x0A, 0x99, 0x1C, 0x52, 0x07, 0x63, 0x44, 0xF1, 0x03, + 0x2D, 0x6C, 0x90, 0x00, 0x7E, 0xB2, 0xA9, 0x25, 0x48, 0xDA, 0x48, 0x22, 0x12, 0x02, 0xE8, 0x1E, + 0xDC, 0x29, 0x87, 0x1B, 0xA6, 0x51, 0x26, 0x18, 0x70, 0x79, 0xC5, 0x14, 0x3A, 0xA1, 0x64, 0x11, + 0x04, 0xC9, 0x03, 0x0E, 0xCE, 0xF0, 0xA2, 0x0A, 0x98, 0x18, 0x42, 0x07, 0x62, 0x40, 0xE1, 0x03, + 0x2C, 0x68, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x03, 0xFC, 0x10, 0x24, 0x38, 0x04, 0x60, 0x09, 0x0E, 0x0A, 0x00, 0x01, 0x01, 0x01, 0x08, 0x10, + 0x24, 0x00, 0x40, 0x04, 0x6C, 0x09, 0x00, 0x00, 0x04, 0x0C, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x69, 0x5F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x01, 0x09, + 0x00, 0x01, 0x44, 0x43, 0x40, 0x02, 0x00, 0x00, 0x28, 0x22, 0x21, 0x00, 0x02, 0x00, 0x0E, 0x00, + 0x02, 0x00, 0x0E, 0x00, 0x02, 0x00, 0x0E, 0x00, 0x02, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x0E, 0x00, + 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x02, 0x00, 0x0E, 0x00, + 0x02, 0x00, 0x0E, 0x00, 0x02, 0x00, 0x0E, 0x00, 0x02, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x0E, 0x00, + 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, + 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x01, 0x07, 0x01, 0x03, + 0x02, 0x03, 0x14, 0x00, 0x0F, 0x0F, 0x10, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x3C, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC8, 0x00, 0xC8, 0x00, 0x96, 0x00, 0xC8, 0x00, + 0x07, 0x07, 0x80, 0x00, 0x80, 0x00, 0x05, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x06, 0x01, 0x00, 0x00, 0xE5, 0xFF, 0x00, 0x00, 0xF6, 0xFF, 0x1E, 0x00, 0x5A, 0x00, 0xF1, 0xFF, + 0xF9, 0xFF, 0xEC, 0xFF, 0xFF, 0x7F, 0xFF, 0x7F, 0xFF, 0x7F, 0xFF, 0x7F, 0x96, 0x00, 0xBC, 0x02, + 0xC8, 0x00, 0x3C, 0x00, 0x0A, 0x04, 0xB4, 0xB4, 0x32, 0x32, 0x23, 0x05, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x09, 0x0D, 0x00, 0x00, 0x24, 0x0D, 0x00, 0x00, 0x00, 0x00, 0x10, 0x24, 0x24, 0x24, 0x24, + 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0A, 0x05, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x17, 0x16, 0x01, 0x12, 0x10, 0x12, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0F, 0x23, 0x32, 0x46, 0x50, 0x00, 0x00, 0x00, 0x6E, 0x5F, 0x55, 0x50, + 0x46, 0x3C, 0x3C, 0x3C, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x23, 0x32, 0x46, + 0x50, 0x00, 0x00, 0x00, 0x6E, 0x5F, 0x55, 0x50, 0x46, 0x3C, 0x3C, 0x3C, 0x0F, 0x14, 0x1E, 0x28, + 0x00, 0x00, 0x00, 0x00, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x19, 0x46, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x28, 0x1E, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x00, 0x00, 0x00, 0x00, + 0x0A, 0x03, 0x14, 0x00, 0x5F, 0x00, 0xF1, 0xFF, 0x14, 0x00, 0x0F, 0x00, 0x0A, 0x00, 0xBC, 0x02, + 0x00, 0x00, 0x00, 0x00, 0x78, 0x76, 0x00, 0x1E, 0x5A, 0x00, 0x19, 0x00, 0x90, 0x01, 0x1B, 0x00, + 0x0A, 0x00, 0x0A, 0x00, 0x68, 0x01, 0x2C, 0x01, 0xF4, 0x01, 0xF8, 0x02, 0x00, 0x00, 0x37, 0x04, + 0x00, 0x00, 0x5F, 0x09, 0xF4, 0x01, 0x00, 0x00, 0x37, 0x04, 0x00, 0x00, 0x5F, 0x09, 0x32, 0x14, + 0x02, 0x1E, 0x1E, 0x32, 0x02, 0x00, 0x64, 0x00, 0x46, 0x00, 0x1E, 0x00, 0x0A, 0x00, 0x2D, 0x04, + 0x0A, 0x00, 0x55, 0x09, 0x00, 0x00, 0x00, 0x00, 0x40, 0x04, 0x28, 0x00, 0x15, 0x00, 0x01, 0x00, + 0x17, 0x00, 0x00, 0x00, 0x26, 0x00, 0x58, 0x00, 0x8A, 0x00, 0xBD, 0x00, 0xED, 0x00, 0x20, 0x01, + 0x54, 0x01, 0x86, 0x01, 0xBC, 0x01, 0xEF, 0x01, 0x20, 0x02, 0x56, 0x02, 0x84, 0x02, 0xB9, 0x02, + 0xEC, 0x02, 0x25, 0x03, 0x55, 0x03, 0x89, 0x03, 0xB9, 0x03, 0xEA, 0x03, 0x17, 0x04, 0x3F, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6C, 0x09, 0x28, 0x00, 0x14, 0x00, + 0x01, 0x00, 0x16, 0x00, 0x00, 0x00, 0x27, 0x00, 0xA3, 0x00, 0x16, 0x01, 0x98, 0x01, 0x0C, 0x02, + 0x8D, 0x02, 0x04, 0x03, 0x83, 0x03, 0xFD, 0x03, 0x78, 0x04, 0xF3, 0x04, 0x6E, 0x05, 0xE8, 0x05, + 0x63, 0x06, 0xE6, 0x06, 0x5C, 0x07, 0xEC, 0x07, 0x52, 0x08, 0xC8, 0x08, 0x43, 0x09, 0x6B, 0x09, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x01, 0x20, 0x00, 0x19, 0x45, 0x00, 0x00, 0xF1, 0x6C, 0x00, 0x00, 0x84, 0xD9, 0x06, 0x00, + 0x29, 0xB1, 0x01, 0x00, 0x89, 0x11, 0x00, 0x00, 0x41, 0x04, 0x00, 0x00, 0x01, 0x01, 0x03, 0x03, + 0x03, 0x05, 0x05, 0x05, 0x05, 0x05, 0x01, 0x4B, 0x11, 0x00, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x03, 0x03, 0x03, 0x05, 0x05, 0x05, 0x05, 0x05, 0x00, 0x19, 0x45, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x40, 0x9C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x14, 0x0A, 0x0A, + 0x0D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x14, 0x14, 0x14, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x00, 0x40, 0x00, 0x21, 0x00, 0xDC, 0x05, 0x1E, 0x00, 0x08, 0x00, 0x40, 0x06, 0x71, 0x02, + 0x01, 0x00, 0x3C, 0x00, 0x0A, 0x00, 0x0F, 0x0A, 0x0F, 0xA0, 0x1B, 0x00, 0x78, 0x00, 0x14, 0x4B, + 0x1B, 0x00, 0xC8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xA0, 0x1B, 0x00, 0x78, 0x00, 0x14, 0x4B, + 0x1B, 0x00, 0xC8, 0x00, 0x14, 0xA0, 0x28, 0x00, 0x78, 0x00, 0x14, 0x32, 0x28, 0x00, 0xC8, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x41, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB4, 0x00, 0x0D, 0x0D, + 0x0B, 0x0A, 0x19, 0x00, 0x1C, 0x00, 0x2D, 0x00, 0x0A, 0x00, 0x4B, 0x00, 0x05, 0x00, 0x96, 0x00, + 0xC2, 0x01, 0x0F, 0x02, 0xE8, 0xE8, 0xF8, 0x00, 0xF8, 0x00, 0x04, 0x00, 0x41, 0x00, 0x00, 0x00, + 0x23, 0x00, 0x28, 0x00, 0x2E, 0x00, 0x34, 0x00, 0x3B, 0x00, 0x42, 0x00, 0x4B, 0x00, 0x55, 0x00, + 0x5F, 0x00, 0x6B, 0x00, 0x78, 0x00, 0x86, 0x00, 0x96, 0x00, 0xA7, 0x00, 0xBA, 0x00, 0xCF, 0x00, + 0xE6, 0x00, 0xFF, 0x00, 0x1B, 0x01, 0x38, 0x01, 0x59, 0x01, 0x7C, 0x01, 0xA2, 0x01, 0xCB, 0x01, + 0xF7, 0x01, 0x26, 0x02, 0x59, 0x02, 0x90, 0x02, 0xCA, 0x02, 0x09, 0x03, 0x4B, 0x03, 0x92, 0x03, + 0xDD, 0x03, 0x2C, 0x04, 0x80, 0x04, 0xD8, 0x04, 0x35, 0x05, 0x97, 0x05, 0xFE, 0x05, 0x69, 0x06, + 0xD8, 0x06, 0x4D, 0x07, 0xC5, 0x07, 0x42, 0x08, 0xC4, 0x08, 0x49, 0x09, 0xD2, 0x09, 0x5F, 0x0A, + 0xEF, 0x0A, 0x82, 0x0B, 0x18, 0x0C, 0xB0, 0x0C, 0x4A, 0x0D, 0xE5, 0x0D, 0x82, 0x0E, 0x1F, 0x0F, + 0xBD, 0x0F, 0x5A, 0x10, 0xF5, 0x10, 0x90, 0x11, 0x28, 0x12, 0xBE, 0x12, 0x51, 0x13, 0xDF, 0x13, + 0x6A, 0x14, 0xEF, 0x14, 0x6F, 0x15, 0xE9, 0x15, 0x5C, 0x16, 0xC8, 0x16, 0x2C, 0x17, 0x88, 0x17, + 0xDC, 0x17, 0x27, 0x18, 0x69, 0x18, 0xA1, 0x18, 0xCF, 0x18, 0xF4, 0x18, 0x0E, 0x19, 0x1D, 0x19, + 0x23, 0x19, 0x1E, 0x00, 0x23, 0x00, 0x27, 0x00, 0x2D, 0x00, 0x33, 0x00, 0x3A, 0x00, 0x42, 0x00, + 0x4A, 0x00, 0x54, 0x00, 0x5F, 0x00, 0x6B, 0x00, 0x78, 0x00, 0x87, 0x00, 0x97, 0x00, 0xA9, 0x00, + 0xBC, 0x00, 0xD2, 0x00, 0xE9, 0x00, 0x03, 0x01, 0x1F, 0x01, 0x3E, 0x01, 0x60, 0x01, 0x84, 0x01, + 0xAB, 0x01, 0xD6, 0x01, 0x04, 0x02, 0x35, 0x02, 0x6A, 0x02, 0xA3, 0x02, 0xE0, 0x02, 0x21, 0x03, + 0x67, 0x03, 0xB1, 0x03, 0xFF, 0x03, 0x52, 0x04, 0xAA, 0x04, 0x07, 0x05, 0x68, 0x05, 0xCF, 0x05, + 0x3A, 0x06, 0xAA, 0x06, 0x1F, 0x07, 0x99, 0x07, 0x17, 0x08, 0x9A, 0x08, 0x22, 0x09, 0xAD, 0x09, + 0x3D, 0x0A, 0xD0, 0x0A, 0x66, 0x0B, 0xFF, 0x0B, 0x9B, 0x0C, 0x3A, 0x0D, 0xDA, 0x0D, 0x7B, 0x0E, + 0x1D, 0x0F, 0xC0, 0x0F, 0x62, 0x10, 0x04, 0x11, 0xA4, 0x11, 0x42, 0x12, 0xDE, 0x12, 0x76, 0x13, + 0x0B, 0x14, 0x9B, 0x14, 0x26, 0x15, 0xAB, 0x15, 0x2B, 0x16, 0xA3, 0x16, 0x14, 0x17, 0x7D, 0x17, + 0xDE, 0x17, 0x36, 0x18, 0x84, 0x18, 0xC9, 0x18, 0x04, 0x19, 0x35, 0x19, 0x5B, 0x19, 0x76, 0x19, + 0x87, 0x19, 0x8C, 0x19, 0x2F, 0x00, 0x35, 0x00, 0x3C, 0x00, 0x44, 0x00, 0x4C, 0x00, 0x55, 0x00, + 0x60, 0x00, 0x6B, 0x00, 0x77, 0x00, 0x85, 0x00, 0x94, 0x00, 0xA5, 0x00, 0xB7, 0x00, 0xCB, 0x00, + 0xE1, 0x00, 0xF8, 0x00, 0x12, 0x01, 0x2E, 0x01, 0x4C, 0x01, 0x6D, 0x01, 0x90, 0x01, 0xB6, 0x01, + 0xDF, 0x01, 0x0B, 0x02, 0x3A, 0x02, 0x6C, 0x02, 0xA2, 0x02, 0xDB, 0x02, 0x18, 0x03, 0x59, 0x03, + 0x9E, 0x03, 0xE6, 0x03, 0x33, 0x04, 0x84, 0x04, 0xD9, 0x04, 0x32, 0x05, 0x8F, 0x05, 0xF1, 0x05, + 0x57, 0x06, 0xC1, 0x06, 0x2F, 0x07, 0xA1, 0x07, 0x17, 0x08, 0x91, 0x08, 0x0F, 0x09, 0x90, 0x09, + 0x14, 0x0A, 0x9C, 0x0A, 0x26, 0x0B, 0xB2, 0x0B, 0x41, 0x0C, 0xD2, 0x0C, 0x63, 0x0D, 0xF6, 0x0D, + 0x8A, 0x0E, 0x1D, 0x0F, 0xB1, 0x0F, 0x43, 0x10, 0xD5, 0x10, 0x65, 0x11, 0xF2, 0x11, 0x7D, 0x12, + 0x04, 0x13, 0x88, 0x13, 0x08, 0x14, 0x82, 0x14, 0xF8, 0x14, 0x67, 0x15, 0xD1, 0x15, 0x34, 0x16, + 0x90, 0x16, 0xE4, 0x16, 0x30, 0x17, 0x75, 0x17, 0xB1, 0x17, 0xE4, 0x17, 0x0E, 0x18, 0x2F, 0x18, + 0x46, 0x18, 0x55, 0x18, 0x59, 0x18, 0x2F, 0x00, 0x35, 0x00, 0x3C, 0x00, 0x44, 0x00, 0x4C, 0x00, + 0x55, 0x00, 0x60, 0x00, 0x6B, 0x00, 0x77, 0x00, 0x85, 0x00, 0x94, 0x00, 0xA5, 0x00, 0xB7, 0x00, + 0xCB, 0x00, 0xE1, 0x00, 0xF8, 0x00, 0x12, 0x01, 0x2E, 0x01, 0x4C, 0x01, 0x6D, 0x01, 0x90, 0x01, + 0xB6, 0x01, 0xDF, 0x01, 0x0B, 0x02, 0x3A, 0x02, 0x6C, 0x02, 0xA2, 0x02, 0xDB, 0x02, 0x18, 0x03, + 0x59, 0x03, 0x9E, 0x03, 0xE6, 0x03, 0x33, 0x04, 0x84, 0x04, 0xD9, 0x04, 0x32, 0x05, 0x8F, 0x05, + 0xF1, 0x05, 0x57, 0x06, 0xC1, 0x06, 0x2F, 0x07, 0xA1, 0x07, 0x17, 0x08, 0x91, 0x08, 0x0F, 0x09, + 0x90, 0x09, 0x14, 0x0A, 0x9C, 0x0A, 0x26, 0x0B, 0xB2, 0x0B, 0x41, 0x0C, 0xD2, 0x0C, 0x63, 0x0D, + 0xF6, 0x0D, 0x8A, 0x0E, 0x1D, 0x0F, 0xB1, 0x0F, 0x43, 0x10, 0xD5, 0x10, 0x65, 0x11, 0xF2, 0x11, + 0x7D, 0x12, 0x04, 0x13, 0x88, 0x13, 0x08, 0x14, 0x82, 0x14, 0xF8, 0x14, 0x67, 0x15, 0xD1, 0x15, + 0x34, 0x16, 0x90, 0x16, 0xE4, 0x16, 0x30, 0x17, 0x75, 0x17, 0xB1, 0x17, 0xE4, 0x17, 0x0E, 0x18, + 0x2F, 0x18, 0x46, 0x18, 0x55, 0x18, 0x59, 0x18, 0x3E, 0x00, 0x3D, 0x00, 0x40, 0x00, 0x40, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x73, 0x00, 0xA5, 0x00, 0x40, 0x01, 0x1E, 0x00, 0x05, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x05, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x01, 0x04, 0x00, + 0x00, 0x00, 0x69, 0x5F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x67, 0x26, 0x00, 0x00, 0x88, 0x26, 0x00, 0x00, 0xA9, 0x26, 0x00, 0x00, 0x1A, 0x03, 0x00, 0x00, + 0x41, 0x0C, 0x52, 0x0C, 0x07, 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCA, 0x26, 0x42, 0x27, + 0x66, 0x27, 0x2C, 0x28, 0x49, 0x29, 0x68, 0x28, 0x3A, 0x29, 0x39, 0x2A, 0x00, 0xB8, 0xC3, 0x07, + 0x7E, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x05, 0x58, 0x05, 0xA0, 0x05, + 0xE8, 0x05, 0x00, 0x00, 0x10, 0x40, 0x04, 0x0C, 0x0E, 0x0B, 0x0C, 0x0C, 0x10, 0x00, 0x0E, 0x10, + 0xA5, 0xBA, 0x03, 0x1F, 0x7C, 0xC6, 0x0F, 0x00, 0x10, 0x0D, 0x10, 0x0D, 0x0D, 0x41, 0x0D, 0x41, + 0x1A, 0x03, 0x00, 0x00, 0x8B, 0x35, 0xF7, 0x20, 0x51, 0x4E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xCA, 0x26, 0x42, 0x27, 0x66, 0x27, 0x2C, 0x28, 0x49, 0x29, 0x68, 0x28, 0x3A, 0x29, 0x39, 0x2A, + 0x00, 0xB8, 0x87, 0x3A, 0x7E, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x05, + 0x58, 0x05, 0xA0, 0x05, 0xE8, 0x05, 0x00, 0x00, 0x10, 0x40, 0x04, 0x0C, 0x0E, 0x0B, 0x0C, 0x0C, + 0x90, 0x00, 0x0E, 0x10, 0xA5, 0xBB, 0x83, 0x1F, 0xFC, 0xC9, 0x0F, 0x00, 0x10, 0x0D, 0x10, 0x0D, + 0x0D, 0x41, 0x0D, 0x41, 0x1A, 0x03, 0x00, 0x00, 0x8B, 0x35, 0xF7, 0x20, 0x51, 0xC9, 0x09, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, + 0x27, 0x27, 0x27, 0x27, 0x25, 0x27, 0x27, 0x27, 0x27, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x66, 0x66, 0x66, 0x56, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xCA, 0x26, 0x42, 0x27, 0x66, 0x27, 0x2C, 0x28, 0x49, 0x29, 0x68, 0x28, + 0x3A, 0x29, 0x39, 0x2A, 0x00, 0xB8, 0xC3, 0x07, 0x7E, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x10, 0x05, 0x58, 0x05, 0xA0, 0x05, 0xE8, 0x05, 0x00, 0x00, 0x10, 0x40, 0x04, 0x0C, + 0x0E, 0x0B, 0x0C, 0x0C, 0x90, 0x00, 0x0E, 0x10, 0xA5, 0xBB, 0x83, 0x1F, 0xFC, 0xC9, 0x0F, 0x00, + 0x10, 0x0D, 0x10, 0x0D, 0x0D, 0x41, 0x0D, 0x41, 0x00, 0x00, 0x00, 0x00, 0x09, 0x09, 0x01, 0x00, + 0x00, 0x28, 0x00, 0x00, 0x00, 0xA8, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA5, 0x1D, 0x02, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x28, 0x00, 0x00, 0x80, 0xAA, 0x03, 0x00, + 0x07, 0x00, 0x0F, 0x00, 0xA6, 0x1D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x03, + 0x00, 0x28, 0x00, 0x00, 0x80, 0xAA, 0x03, 0x00, 0x06, 0x00, 0x0E, 0x00, 0xA7, 0x1D, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x03, 0x00, 0x28, 0x00, 0x00, 0x80, 0xAA, 0x03, 0x00, + 0x05, 0x00, 0x0D, 0x00, 0xA8, 0x1D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0x02, 0x03, + 0x00, 0x28, 0x00, 0x00, 0x80, 0xAA, 0x03, 0x00, 0x04, 0x00, 0x0C, 0x00, 0xA9, 0x1D, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x04, 0x04, 0x02, 0x03, 0x00, 0x28, 0x00, 0x00, 0x80, 0xAA, 0x03, 0x00, + 0x03, 0x00, 0x0B, 0x00, 0xAA, 0x1D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x05, 0x02, 0x03, + 0x00, 0x28, 0x00, 0x00, 0x80, 0xAA, 0x03, 0x00, 0x02, 0x00, 0x0A, 0x00, 0xAB, 0x1D, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x02, 0x03, 0x00, 0x28, 0x00, 0x00, 0x80, 0xAA, 0x03, 0x00, + 0x01, 0x00, 0x09, 0x00, 0xAC, 0x1D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x07, 0x03, 0x03, + 0x00, 0x28, 0x00, 0x00, 0x80, 0xAA, 0x03, 0x00, 0x00, 0x00, 0x08, 0x00, 0xAD, 0x1D, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x03, 0x12, 0x00, 0x28, 0x00, 0x00, 0x80, 0xAA, 0x03, 0x00, + 0x08, 0x00, 0x10, 0x00, 0xAE, 0x1D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x13, 0x01, 0x00, + 0x00, 0x28, 0x00, 0x00, 0x00, 0xA8, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA5, 0x1D, 0x02, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x02, 0x02, 0x00, 0x28, 0x00, 0x00, 0x80, 0xA8, 0x03, 0x00, + 0x07, 0x00, 0x0F, 0x00, 0xA6, 0x1D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0B, 0x02, 0x03, + 0x00, 0x28, 0x00, 0x00, 0x80, 0xA8, 0x03, 0x00, 0x06, 0x00, 0x0E, 0x00, 0xA7, 0x1D, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x0C, 0x02, 0x03, 0x00, 0x28, 0x00, 0x00, 0x80, 0xA8, 0x03, 0x00, + 0x05, 0x00, 0x0D, 0x00, 0xA8, 0x1D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x0D, 0x02, 0x03, + 0x00, 0x28, 0x00, 0x00, 0x80, 0xA8, 0x03, 0x00, 0x04, 0x00, 0x0C, 0x00, 0xA9, 0x1D, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x04, 0x0E, 0x02, 0x03, 0x00, 0x28, 0x00, 0x00, 0x80, 0xA8, 0x03, 0x00, + 0x03, 0x00, 0x0B, 0x00, 0xAA, 0x1D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0F, 0x02, 0x03, + 0x00, 0x28, 0x00, 0x00, 0x80, 0xA8, 0x03, 0x00, 0x02, 0x00, 0x0A, 0x00, 0xAB, 0x1D, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x06, 0x10, 0x02, 0x03, 0x00, 0x28, 0x00, 0x00, 0x80, 0xA8, 0x03, 0x00, + 0x01, 0x00, 0x09, 0x00, 0xAC, 0x1D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x11, 0x03, 0x03, + 0x00, 0x28, 0x00, 0x00, 0x80, 0xA8, 0x03, 0x00, 0x00, 0x00, 0x08, 0x00, 0xAD, 0x1D, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x08, 0x12, 0x03, 0x12, 0x00, 0x28, 0x00, 0x00, 0x80, 0xA8, 0x03, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xAE, 0x1D, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x01, 0x6C, 0x04, 0x14, + 0x7D, 0xDE, 0x1B, 0x00, 0x61, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x01, 0x00, 0x04, 0x14, + 0x15, 0x29, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x29, 0x00, 0x70, 0x14, + 0x64, 0xC7, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x29, 0x6C, 0x70, 0x14, + 0x30, 0x44, 0x1B, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x29, 0x6C, 0x70, 0x14, + 0x30, 0x44, 0x1B, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x29, 0x6C, 0x70, 0x14, + 0x64, 0xAC, 0x1B, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x29, 0x6C, 0x70, 0x14, + 0x30, 0x44, 0x1B, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x01, 0x6C, 0x04, 0x14, + 0x30, 0x44, 0x1B, 0x00, 0xE1, 0x00, 0x01, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x01, 0x00, 0x04, 0x14, + 0x15, 0x29, 0x00, 0x00, 0xE0, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x14, 0x49, 0x24, 0x49, 0x24, 0x09, 0x24, 0x05, 0x00, 0x00, 0x00, 0x00, 0xA4, 0x48, 0x24, 0x49, + 0x24, 0x09, 0xA4, 0x08, 0x00, 0x00, 0x00, 0x00, 0x24, 0x45, 0x24, 0x49, 0x24, 0x09, 0x14, 0x09, + 0x00, 0x00, 0x00, 0x00, 0x24, 0x29, 0x24, 0x49, 0x24, 0x09, 0x22, 0x09, 0x00, 0x00, 0x00, 0x00, + 0x24, 0x49, 0x24, 0x29, 0x22, 0x09, 0x24, 0x09, 0x00, 0x00, 0x00, 0x00, 0x24, 0x49, 0x24, 0x45, + 0x14, 0x09, 0x24, 0x09, 0x00, 0x00, 0x00, 0x00, 0x24, 0x49, 0xA4, 0x48, 0xA4, 0x08, 0x24, 0x09, + 0x00, 0x00, 0x00, 0x00, 0x24, 0x49, 0x14, 0x49, 0x24, 0x05, 0x24, 0x09, 0x00, 0x00, 0x00, 0x00, + 0x24, 0x49, 0x22, 0x49, 0x24, 0x05, 0x24, 0x09, 0x00, 0x00, 0x00, 0x00, 0x92, 0x24, 0x92, 0x24, + 0x92, 0x04, 0x92, 0x04, 0x00, 0x00, 0x00, 0x00, 0x96, 0x6D, 0xB6, 0x6D, 0xB6, 0x0D, 0xB6, 0x05, + 0x00, 0x00, 0x00, 0x00, 0xB6, 0x6C, 0xB6, 0x6D, 0xB6, 0x0D, 0xB6, 0x0C, 0x00, 0x00, 0x00, 0x00, + 0xB6, 0x65, 0xB6, 0x6D, 0xB6, 0x0D, 0x96, 0x0D, 0x00, 0x00, 0x00, 0x00, 0xB6, 0x2D, 0xB6, 0x6D, + 0xB6, 0x0D, 0xB2, 0x0D, 0x00, 0x00, 0x00, 0x00, 0xB6, 0x6D, 0xB6, 0x2D, 0xB2, 0x0D, 0xB6, 0x0D, + 0x00, 0x00, 0x00, 0x00, 0xB6, 0x6D, 0xB6, 0x65, 0x96, 0x0D, 0xB6, 0x0D, 0x00, 0x00, 0x00, 0x00, + 0xB6, 0x6D, 0xB6, 0x6C, 0xB6, 0x0C, 0xB6, 0x0D, 0x00, 0x00, 0x00, 0x00, 0xB6, 0x6D, 0x96, 0x6D, + 0xB6, 0x05, 0xB6, 0x0D, 0x00, 0x00, 0x00, 0x00, 0xB6, 0x6D, 0xB2, 0x6D, 0xB6, 0x05, 0xB6, 0x0D, + 0x00, 0x00, 0x00, 0x00, 0x92, 0x24, 0x92, 0x24, 0x92, 0x04, 0x92, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x02, 0x02, 0x06, 0xFF, 0x00, 0x6C, 0x76, 0x8A, 0x94, 0xDB, 0x06, 0x00, 0x00, + 0x01, 0x06, 0x00, 0x00, 0x09, 0x01, 0x57, 0x00, 0x36, 0x04, 0x09, 0x02, 0x01, 0x00, 0x00, 0x00, + 0xA9, 0x00, 0x04, 0x01, 0x47, 0x7E, 0xEC, 0x14, 0xFF, 0xFF, 0x00, 0x80, 0x1C, 0x7C, 0x0F, 0x57, + 0x03, 0x80, 0xBB, 0xBB, 0x8E, 0x5C, 0x22, 0x00, 0x64, 0x01, 0x64, 0x01, 0x88, 0x39, 0x8A, 0x39, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x06, 0xFF, 0x00, 0x6C, 0x76, 0x8A, 0x94, + 0xDB, 0x06, 0x00, 0x00, 0x01, 0x06, 0x00, 0x00, 0xFA, 0x00, 0x57, 0x00, 0x36, 0xF5, 0x08, 0x02, + 0x01, 0x00, 0x00, 0x00, 0x9A, 0x00, 0xF5, 0x00, 0x47, 0x7E, 0xEC, 0x14, 0xFF, 0xFF, 0x00, 0x80, + 0x1C, 0xE0, 0x0C, 0x57, 0x03, 0x80, 0xAB, 0xAA, 0x80, 0x44, 0x22, 0x00, 0x64, 0x11, 0x64, 0x11, + 0x88, 0x39, 0x8A, 0x39, 0x05, 0x00, 0x05, 0x00, 0x01, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x06, 0xFF, 0x00, + 0x6C, 0x76, 0x8A, 0x94, 0xDB, 0x06, 0x00, 0x00, 0x01, 0x06, 0x00, 0x00, 0x61, 0x00, 0x57, 0x00, + 0x36, 0x5C, 0x08, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x5C, 0x00, 0x47, 0x7E, 0xEC, 0x14, + 0xFF, 0xFF, 0x00, 0x80, 0x1C, 0x24, 0x0C, 0x57, 0x03, 0x80, 0xAB, 0xAA, 0x80, 0x44, 0x22, 0x00, + 0x64, 0x11, 0x64, 0x11, 0x88, 0x39, 0x8A, 0x39, 0x05, 0x00, 0x05, 0x00, 0x01, 0x28, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, + 0x02, 0x00, 0xFF, 0x00, 0x6C, 0x76, 0x8A, 0x94, 0xDB, 0x06, 0x00, 0x00, 0x01, 0x06, 0x00, 0x00, + 0xF1, 0x00, 0x57, 0x00, 0x36, 0xEC, 0x08, 0x02, 0x41, 0x00, 0x02, 0x00, 0x91, 0x00, 0xEC, 0x00, + 0x47, 0x7E, 0xEC, 0x14, 0xFF, 0xFF, 0x00, 0x80, 0x1C, 0xC4, 0x0C, 0x17, 0xE3, 0x8E, 0xBB, 0xBB, + 0x80, 0x55, 0x22, 0x00, 0x64, 0x11, 0x64, 0x11, 0x88, 0x39, 0x8A, 0x39, 0x05, 0x00, 0x05, 0x00, + 0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0xFF, 0x00, 0x6C, 0x76, 0x8A, 0x94, 0xDB, 0x06, 0x00, 0x00, + 0x04, 0x0C, 0x00, 0x00, 0xB8, 0x03, 0x57, 0x00, 0x36, 0xEC, 0x08, 0x02, 0x01, 0x00, 0x00, 0x00, + 0x58, 0x03, 0xEC, 0x00, 0x47, 0x7E, 0xEC, 0x14, 0xFF, 0xFF, 0x00, 0x80, 0x1C, 0xE0, 0x0C, 0x57, + 0x03, 0x80, 0xBB, 0xBB, 0x80, 0x45, 0x22, 0x00, 0x64, 0x11, 0x64, 0x11, 0x88, 0x39, 0x8A, 0x39, + 0x05, 0x00, 0x05, 0x00, 0x94, 0x04, 0x02, 0x00, 0x01, 0x02, 0x03, 0x04, 0xD6, 0xF0, 0x42, 0xFC, + 0x1C, 0x60, 0x05, 0xAF, 0xCF, 0x03, 0x04, 0x02, 0x1E, 0x06, 0x00, 0x03, 0x6C, 0x76, 0x8A, 0x94, + 0xDB, 0x06, 0x00, 0x00, 0x01, 0xC5, 0x00, 0x00, 0xD2, 0x0F, 0x00, 0x00, 0x00, 0xEC, 0x08, 0x02, + 0x41, 0x00, 0x02, 0x00, 0x00, 0x00, 0xEC, 0x00, 0x47, 0x7E, 0xEC, 0x14, 0xFF, 0xFF, 0x00, 0x80, + 0x1C, 0xC4, 0x11, 0x17, 0x00, 0x80, 0xBB, 0xBB, 0x00, 0x57, 0x22, 0x00, 0x64, 0x11, 0x64, 0x11, + 0x88, 0x19, 0x8A, 0x19, 0x05, 0x00, 0x05, 0x00, 0x94, 0x04, 0x02, 0x00, 0x01, 0x01, 0x01, 0x01, + 0xD6, 0xF0, 0x42, 0xFC, 0x1C, 0x60, 0x05, 0xAF, 0xCF, 0x03, 0x04, 0x02, 0x02, 0x06, 0x00, 0x00, + 0x6C, 0x76, 0x8A, 0x94, 0xDB, 0x06, 0x00, 0x00, 0x01, 0xC5, 0x00, 0x00, 0xD2, 0x0F, 0x00, 0x00, + 0x00, 0xEC, 0x08, 0x02, 0x41, 0x00, 0x02, 0x00, 0x00, 0x00, 0xEC, 0x00, 0x72, 0x78, 0x51, 0x2B, + 0xFF, 0xFF, 0x00, 0x80, 0x1C, 0xC4, 0x11, 0x3F, 0x00, 0x80, 0xBB, 0xBB, 0x00, 0x46, 0x22, 0x00, + 0x64, 0x11, 0x64, 0x11, 0x88, 0x39, 0x8A, 0x39, 0x05, 0x00, 0x05, 0x00, 0x94, 0x04, 0x02, 0x00, + 0x02, 0x02, 0x02, 0x02, 0xD6, 0xF0, 0x42, 0xFC, 0x1C, 0x60, 0x05, 0xAF, 0xCF, 0x03, 0x04, 0x02, + 0x02, 0x06, 0x00, 0x00, 0x6C, 0x76, 0x8A, 0x94, 0xDB, 0x06, 0x00, 0x00, 0x01, 0xC5, 0x00, 0x00, + 0xD2, 0x0F, 0x00, 0x00, 0x00, 0xEC, 0x08, 0x02, 0x41, 0x00, 0x02, 0x00, 0x00, 0x00, 0xEC, 0x00, + 0xBB, 0x7B, 0xC5, 0x20, 0xFF, 0xFF, 0x00, 0x80, 0x1C, 0xC4, 0x11, 0x3F, 0x00, 0x80, 0xBB, 0xBB, + 0x00, 0x46, 0x22, 0x00, 0x64, 0x11, 0x64, 0x11, 0x88, 0x39, 0x8A, 0x39, 0x05, 0x00, 0x05, 0x00, + 0x94, 0x04, 0x02, 0x00, 0x03, 0x03, 0x03, 0x03, 0xD6, 0xF0, 0x42, 0xFC, 0x1C, 0x60, 0x05, 0xAF, + 0xCF, 0x03, 0x04, 0x02, 0x02, 0x06, 0x00, 0x00, 0x6C, 0x76, 0x8A, 0x94, 0xDB, 0x06, 0x00, 0x00, + 0x01, 0xC5, 0x00, 0x00, 0xD2, 0x0F, 0x00, 0x00, 0x00, 0xEC, 0x08, 0x02, 0x41, 0x00, 0x02, 0x00, + 0x00, 0x00, 0xEC, 0x00, 0x19, 0x7E, 0xFC, 0x15, 0xFF, 0xFF, 0x00, 0x80, 0x1C, 0xC4, 0x11, 0x3F, + 0x00, 0x80, 0xBB, 0xBB, 0x00, 0x46, 0x22, 0x00, 0x64, 0x11, 0x64, 0x11, 0x88, 0x39, 0x8A, 0x39, + 0x05, 0x00, 0x05, 0x00, 0x94, 0x04, 0x02, 0x00, 0x04, 0x04, 0x04, 0x04, 0xD6, 0xF0, 0x42, 0xFC, + 0x1C, 0x60, 0x05, 0xAF, 0xCF, 0x03, 0x04, 0x02, 0x02, 0x06, 0x00, 0x00, 0x6C, 0x76, 0x8A, 0x94, + 0xDB, 0x06, 0x00, 0x00, 0x01, 0xC5, 0x00, 0x00, 0xD2, 0x0F, 0x00, 0x00, 0x00, 0xEC, 0x08, 0x02, + 0x41, 0x00, 0x02, 0x00, 0x00, 0x00, 0xEC, 0x00, 0x86, 0x7F, 0x08, 0x0B, 0xFF, 0xFF, 0x00, 0x80, + 0x1C, 0xC4, 0x11, 0x3F, 0x00, 0x80, 0xBB, 0xBB, 0x00, 0x46, 0x22, 0x00, 0x64, 0x11, 0x64, 0x11, + 0x88, 0x39, 0x8A, 0x39, 0x05, 0x00, 0x05, 0x00, 0x00, 0x00, 0x5D, 0x3F, 0x00, 0x00, 0xDA, 0x47, + 0xC0, 0xCE, 0xD0, 0xC7, 0xFF, 0xFF, 0x47, 0x02, 0x00, 0x00, 0xA1, 0x50, 0x3F, 0x0D, 0x30, 0x09, + 0xFF, 0xFF, 0x24, 0x4B, 0x00, 0x00, 0x9F, 0x30, 0xFF, 0xCE, 0xF0, 0xC7, 0xFF, 0xFF, 0xDF, 0x3B, + 0x00, 0x00, 0x47, 0xE4, 0x3F, 0x0F, 0x30, 0x04, 0xFF, 0xFF, 0xAB, 0xCE, 0x00, 0x00, 0xC5, 0x79, + 0x3F, 0x0F, 0x30, 0x02, 0x47, 0x18, 0x51, 0x04, 0x44, 0x0C, 0x21, 0x04, 0x41, 0x00, 0xF1, 0x03, + 0x3E, 0xF4, 0xC0, 0x03, 0x3B, 0xE8, 0x90, 0x03, 0x38, 0xDC, 0x60, 0x03, 0x35, 0xD0, 0x30, 0x03, + 0x32, 0xC4, 0x00, 0x03, 0x2F, 0xB8, 0xD0, 0x02, 0x2C, 0xAC, 0xA0, 0x02, 0x29, 0xA0, 0x70, 0x02, + 0x26, 0x94, 0x40, 0x02, 0x23, 0x88, 0x10, 0x02, 0x20, 0x7C, 0xE0, 0x01, 0x1D, 0x70, 0xB0, 0x01, + 0x1A, 0x64, 0x80, 0x01, 0x17, 0x58, 0x50, 0x01, 0x14, 0x4C, 0x20, 0x01, 0x11, 0x40, 0xF0, 0x00, + 0x0E, 0x34, 0xC0, 0x00, 0x0B, 0x28, 0x90, 0x00, 0x08, 0x1C, 0x60, 0x00, 0x05, 0x10, 0x30, 0x00, + 0x02, 0x04, 0x00, 0x00, 0x00, 0x40, 0x00, 0x02, 0x30, 0x00, 0x01, 0x05, 0x60, 0xC0, 0x01, 0x08, + 0x90, 0x80, 0x02, 0x0B, 0xC0, 0x40, 0x03, 0x0E, 0xF0, 0x00, 0x04, 0x11, 0x20, 0xC1, 0x04, 0x14, + 0x50, 0x81, 0x05, 0x17, 0x80, 0x41, 0x06, 0x1A, 0xB0, 0x01, 0x07, 0x1D, 0xE0, 0xC1, 0x07, 0x20, + 0x10, 0x82, 0x08, 0x23, 0x30, 0x82, 0x08, 0x21, 0x00, 0xC2, 0x07, 0x1E, 0xD0, 0x01, 0x07, 0x1B, + 0xA0, 0x41, 0x06, 0x18, 0x70, 0x81, 0x05, 0x15, 0x40, 0xC1, 0x04, 0x12, 0x10, 0x01, 0x04, 0x0F, + 0xE0, 0x40, 0x03, 0x0C, 0xB0, 0x80, 0x02, 0x09, 0x80, 0xC0, 0x01, 0x06, 0x50, 0x00, 0x01, 0x03, + 0x20, 0x40, 0x00, 0x00, 0x30, 0x82, 0x08, 0x21, 0x00, 0xC2, 0x07, 0x1E, 0xD0, 0x01, 0x07, 0x1B, + 0xA0, 0x41, 0x06, 0x18, 0x70, 0x81, 0x05, 0x15, 0x40, 0xC1, 0x04, 0x12, 0x10, 0x01, 0x04, 0x0F, + 0xE0, 0x40, 0x03, 0x0C, 0xB0, 0x80, 0x02, 0x09, 0x80, 0xC0, 0x01, 0x06, 0x50, 0x00, 0x01, 0x03, + 0x20, 0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x02, 0x30, 0x00, 0x01, 0x05, 0x60, 0xC0, 0x01, 0x08, + 0x90, 0x80, 0x02, 0x0B, 0xC0, 0x40, 0x03, 0x0E, 0xF0, 0x00, 0x04, 0x11, 0x20, 0xC1, 0x04, 0x14, + 0x50, 0x81, 0x05, 0x17, 0x80, 0x41, 0x06, 0x1A, 0xB0, 0x01, 0x07, 0x1D, 0xE0, 0xC1, 0x07, 0x20, + 0x10, 0x82, 0x08, 0x23, 0x85, 0xCE, 0x19, 0x26, 0x4F, 0xF6, 0xB8, 0x22, 0x19, 0x1E, 0x58, 0x1F, + 0xE3, 0x45, 0xF7, 0x1B, 0xAD, 0x6D, 0x96, 0x18, 0x77, 0x95, 0x35, 0x15, 0x41, 0xBD, 0xD4, 0x11, + 0x0B, 0xE5, 0x73, 0x0E, 0xD5, 0x0C, 0x13, 0x0B, 0x9F, 0x34, 0xB2, 0x07, 0x69, 0x5C, 0x51, 0x04, + 0x33, 0x84, 0xF0, 0x00, 0x78, 0x9A, 0x49, 0x25, 0x42, 0xC2, 0xE8, 0x21, 0x0C, 0xEA, 0x87, 0x1E, + 0xD6, 0x11, 0x27, 0x1B, 0xA0, 0x39, 0xC6, 0x17, 0x6A, 0x61, 0x65, 0x14, 0x34, 0x89, 0x04, 0x11, + 0xFE, 0xB0, 0xA3, 0x0D, 0xC8, 0xD8, 0x42, 0x0A, 0x92, 0x00, 0xE2, 0x06, 0x5C, 0x28, 0x81, 0x03, + 0x26, 0x50, 0x20, 0x00, 0x84, 0xCA, 0x09, 0x26, 0x4E, 0xF2, 0xA8, 0x22, 0x18, 0x1A, 0x48, 0x1F, + 0xE2, 0x41, 0xE7, 0x1B, 0xAC, 0x69, 0x86, 0x18, 0x76, 0x91, 0x25, 0x15, 0x40, 0xB9, 0xC4, 0x11, + 0x0A, 0xE1, 0x63, 0x0E, 0xD4, 0x08, 0x03, 0x0B, 0x9E, 0x30, 0xA2, 0x07, 0x68, 0x58, 0x41, 0x04, + 0x32, 0x80, 0xE0, 0x00, 0x79, 0x9E, 0x59, 0x25, 0x43, 0xC6, 0xF8, 0x21, 0x0D, 0xEE, 0x97, 0x1E, + 0xD7, 0x15, 0x37, 0x1B, 0xA1, 0x3D, 0xD6, 0x17, 0x6B, 0x65, 0x75, 0x14, 0x35, 0x8D, 0x14, 0x11, + 0xFF, 0xB4, 0xB3, 0x0D, 0xC9, 0xDC, 0x52, 0x0A, 0x93, 0x04, 0xF2, 0x06, 0x5D, 0x2C, 0x91, 0x03, + 0x27, 0x54, 0x30, 0x00, 0x83, 0xC6, 0xF9, 0xE5, 0x4D, 0xEE, 0x98, 0xE2, 0x17, 0x16, 0x38, 0x1F, + 0xE1, 0x3D, 0xD7, 0x1B, 0xAB, 0x65, 0x76, 0xD8, 0x75, 0x8D, 0x15, 0x15, 0x3F, 0xB5, 0xB4, 0x11, + 0x09, 0xDD, 0x53, 0x0E, 0xD3, 0x04, 0xF3, 0x0A, 0x9D, 0x2C, 0x92, 0x07, 0x67, 0x54, 0x31, 0x04, + 0x31, 0x7C, 0xD0, 0x00, 0x7A, 0xA2, 0x69, 0x25, 0x44, 0xCA, 0x08, 0x22, 0x0E, 0xF2, 0xA7, 0x1E, + 0xD8, 0x19, 0x47, 0x1B, 0xA2, 0x41, 0xE6, 0x17, 0x6C, 0x69, 0x85, 0x14, 0x36, 0x91, 0x24, 0x11, + 0x00, 0xB9, 0xC3, 0x0D, 0xCA, 0xE0, 0x62, 0x0A, 0x94, 0x08, 0x02, 0x07, 0x5E, 0x30, 0xA1, 0x03, + 0x28, 0x58, 0x40, 0x00, 0x82, 0xC2, 0xE9, 0x25, 0x4C, 0xEA, 0x88, 0x22, 0x16, 0x12, 0x28, 0x1F, + 0xE0, 0x39, 0xC7, 0x1B, 0xAA, 0x61, 0x66, 0x18, 0x74, 0x89, 0x05, 0x15, 0x3E, 0xB1, 0xA4, 0x11, + 0x08, 0xD9, 0x43, 0x0E, 0xD2, 0x00, 0xE3, 0x0A, 0x9C, 0x28, 0x82, 0x07, 0x66, 0x50, 0x21, 0x04, + 0x30, 0x78, 0xC0, 0x00, 0x7B, 0xA6, 0x79, 0x25, 0x45, 0xCE, 0x18, 0x22, 0x0F, 0xF6, 0xB7, 0x1E, + 0xD9, 0x1D, 0x57, 0x1B, 0xA3, 0x45, 0xF6, 0x17, 0x6D, 0x6D, 0x95, 0x14, 0x37, 0x95, 0x34, 0x11, + 0x01, 0xBD, 0xD3, 0x0D, 0xCB, 0xE4, 0x72, 0x0A, 0x95, 0x0C, 0x12, 0x07, 0x5F, 0x34, 0xB1, 0x03, + 0x29, 0x5C, 0x50, 0x00, 0x81, 0xBE, 0xD9, 0x25, 0x4B, 0xE6, 0x78, 0x22, 0x15, 0x0E, 0x18, 0x1F, + 0xDF, 0x35, 0xB7, 0x1B, 0xA9, 0x5D, 0x56, 0x18, 0x73, 0x85, 0xF5, 0x14, 0x3D, 0xAD, 0x94, 0x11, + 0x07, 0xD5, 0x33, 0x0E, 0xD1, 0xFC, 0xD2, 0x0A, 0x9B, 0x24, 0x72, 0x07, 0x65, 0x4C, 0x11, 0x04, + 0x2F, 0x74, 0xB0, 0x00, 0x7C, 0xAA, 0x89, 0x25, 0x46, 0xD2, 0x28, 0x22, 0x10, 0xFA, 0xC7, 0x1E, + 0xDA, 0x21, 0x67, 0x1B, 0xA4, 0x49, 0x06, 0x18, 0x6E, 0x71, 0xA5, 0x14, 0x38, 0x99, 0x44, 0x11, + 0x02, 0xC1, 0xE3, 0x0D, 0xCC, 0xE8, 0x82, 0x0A, 0x96, 0x10, 0x22, 0x07, 0x60, 0x38, 0xC1, 0x03, + 0x2A, 0x60, 0x60, 0x00, 0x80, 0xBA, 0xC9, 0x25, 0x4A, 0xE2, 0x68, 0x22, 0x14, 0x0A, 0x08, 0x1F, + 0xDE, 0x31, 0xA7, 0x1B, 0xA8, 0x59, 0x46, 0x18, 0x72, 0x81, 0xE5, 0x14, 0x3C, 0xA9, 0x84, 0x11, + 0x06, 0xD1, 0x23, 0x0E, 0xD0, 0xF8, 0xC2, 0x0A, 0x9A, 0x20, 0x62, 0x07, 0x64, 0x48, 0x01, 0x04, + 0x2E, 0x70, 0xA0, 0x00, 0x7D, 0xAE, 0x99, 0x25, 0x47, 0xD6, 0x38, 0x22, 0x11, 0xFE, 0xD7, 0x1E, + 0xDB, 0x25, 0x77, 0x1B, 0xA5, 0x4D, 0x16, 0x18, 0x6F, 0x75, 0xB5, 0x14, 0x39, 0x9D, 0x54, 0x11, + 0x03, 0xC5, 0xF3, 0x0D, 0xCD, 0xEC, 0x92, 0x0A, 0x97, 0x14, 0x32, 0x07, 0x61, 0x3C, 0xD1, 0x03, + 0x2B, 0x64, 0x70, 0x00, 0x7F, 0xB6, 0xB9, 0x25, 0x49, 0xDE, 0x58, 0x22, 0x13, 0x06, 0xF8, 0x1E, + 0xDD, 0x2D, 0x97, 0x1B, 0xA7, 0x55, 0x36, 0x18, 0x71, 0x7D, 0xD5, 0x14, 0x3B, 0xA5, 0x74, 0x11, + 0x05, 0xCD, 0x13, 0x0E, 0xCF, 0xF4, 0xB2, 0x0A, 0x99, 0x1C, 0x52, 0x07, 0x63, 0x44, 0xF1, 0x03, + 0x2D, 0x6C, 0x90, 0x00, 0x7E, 0xB2, 0xA9, 0x25, 0x48, 0xDA, 0x48, 0x22, 0x12, 0x02, 0xE8, 0x1E, + 0xDC, 0x29, 0x87, 0x1B, 0xA6, 0x51, 0x26, 0x18, 0x70, 0x79, 0xC5, 0x14, 0x3A, 0xA1, 0x64, 0x11, + 0x04, 0xC9, 0x03, 0x0E, 0xCE, 0xF0, 0xA2, 0x0A, 0x98, 0x18, 0x42, 0x07, 0x62, 0x40, 0xE1, 0x03, + 0x2C, 0x68, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xAA, 0x05, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0xAA, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, + 0x13, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, + 0x1D, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x47, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, + 0x4B, 0x00, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, 0x5E, 0x00, 0x00, 0x00, 0x61, 0x00, 0x00, 0x00, + 0x62, 0x00, 0x00, 0x00, 0x63, 0x00, 0x00, 0x00, 0x6D, 0x00, 0x00, 0x00, 0x72, 0x00, 0x00, 0x00, + 0x73, 0x00, 0x00, 0x00, 0x74, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x1E, 0x01, 0x00, 0x00, + 0x21, 0x01, 0x00, 0x00, 0x2D, 0x01, 0x00, 0x00, 0x3B, 0x01, 0x00, 0x00, 0x48, 0x01, 0x00, 0x00, + 0x4B, 0x01, 0x00, 0x00, 0x6C, 0x01, 0x00, 0x00, 0x78, 0x01, 0x00, 0x00, 0x87, 0x01, 0x00, 0x00, + 0x8B, 0x01, 0x00, 0x00, 0x92, 0x01, 0x00, 0x00, 0x9B, 0x01, 0x00, 0x00, 0xB2, 0x01, 0x00, 0x00, + 0xB3, 0x01, 0x00, 0x00, 0xB4, 0x01, 0x00, 0x00, 0xBB, 0x01, 0x00, 0x00, 0xCB, 0x01, 0x00, 0x00, + 0xCC, 0x01, 0x00, 0x00, 0xD2, 0x01, 0x00, 0x00, 0xE1, 0x01, 0x00, 0x00, 0xE2, 0x01, 0x00, 0x00, + 0xE3, 0x01, 0x00, 0x00, 0xEE, 0x01, 0x00, 0x00, 0x78, 0x04, 0x00, 0x00, 0xB4, 0x04, 0x00, 0x00, + 0xBB, 0x04, 0x00, 0x00, 0xED, 0x04, 0x00, 0x00, 0x21, 0x05, 0x00, 0x00, 0x2D, 0x05, 0x00, 0x00, + 0xE1, 0x05, 0x00, 0x00, 0xEE, 0x05, 0x00, 0x00, 0x1E, 0x06, 0x00, 0x00, 0x4B, 0x06, 0x00, 0x00, + 0x6D, 0x06, 0x00, 0x00, 0xCB, 0x06, 0x00, 0x00, 0xD2, 0x06, 0x00, 0x00, 0xE2, 0x06, 0x00, 0x00, + 0xE3, 0x06, 0x00, 0x00, 0xED, 0x06, 0x00, 0x00, 0x38, 0x07, 0x00, 0x00, 0x4B, 0x07, 0x00, 0x00, + 0x87, 0x07, 0x00, 0x00, 0x8B, 0x07, 0x00, 0x00, 0x8C, 0x07, 0x00, 0x00, 0x8E, 0x07, 0x00, 0x00, + 0xB8, 0x07, 0x00, 0x00, 0xCB, 0x12, 0x00, 0x00, 0xD2, 0x12, 0x00, 0x00, 0xED, 0x12, 0x00, 0x00, + 0x8B, 0x13, 0x00, 0x00, 0x87, 0x17, 0x00, 0x00, 0x9E, 0x17, 0x00, 0x00, 0xB8, 0x17, 0x00, 0x00, + 0xED, 0x19, 0x00, 0x00, 0x4B, 0x1B, 0x00, 0x00, 0x6D, 0x1B, 0x00, 0x00, 0x79, 0x1B, 0x00, 0x00, + 0x8B, 0x1B, 0x00, 0x00, 0x38, 0x1E, 0x00, 0x00, 0x8B, 0x4B, 0x00, 0x00, 0xED, 0x6D, 0x00, 0x00, + 0xE2, 0x78, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x7D, 0x00, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x10, 0x00, 0x00, 0x00, 0x74, 0x00, 0x5C, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5B, 0x00, 0x5F, 0x00, + 0x10, 0x00, 0x01, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6C, 0x00, + 0x54, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x7D, 0x00, 0x54, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x10, 0x00, + 0x0F, 0x00, 0x5B, 0x00, 0x5C, 0x00, 0x1F, 0x00, 0x01, 0x00, 0x10, 0x00, 0x0F, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x64, 0x00, 0x55, 0x00, 0x30, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x00, 0x57, 0x00, 0x3F, 0x02, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x40, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, + 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0x00, 0x00, 0x00, 0x50, 0x3D, 0x02, 0x00, + 0x0C, 0x3D, 0x02, 0x00, 0x50, 0x3D, 0x02, 0x00, 0x10, 0x3D, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x03, 0xFC, 0x10, 0x24, 0x38, 0x04, 0x60, 0x09, 0x0E, 0x0A, 0x00, 0x01, 0x01, 0x01, 0x08, 0x10, + 0x24, 0x00, 0x40, 0x04, 0x6C, 0x09, 0x00, 0x00, 0x04, 0x0C, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x69, 0x5F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x01, 0x09, + 0x00, 0x01, 0x44, 0x43, 0x40, 0x02, 0x00, 0x00, 0x28, 0x22, 0x21, 0x00, 0x02, 0x00, 0x0E, 0x00, + 0x02, 0x00, 0x0E, 0x00, 0x02, 0x00, 0x0E, 0x00, 0x02, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x0E, 0x00, + 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x02, 0x00, 0x0E, 0x00, + 0x02, 0x00, 0x0E, 0x00, 0x02, 0x00, 0x0E, 0x00, 0x02, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x0E, 0x00, + 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, + 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x01, 0x07, 0x01, 0x03, + 0x02, 0x03, 0x14, 0x00, 0x0F, 0x0F, 0x10, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x3C, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC8, 0x00, 0xC8, 0x00, 0x96, 0x00, 0xC8, 0x00, + 0x07, 0x07, 0x80, 0x00, 0x80, 0x00, 0x05, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x06, 0x01, 0x00, 0x00, 0xE5, 0xFF, 0x00, 0x00, 0xF6, 0xFF, 0x1E, 0x00, 0x5A, 0x00, 0xF1, 0xFF, + 0xF9, 0xFF, 0xEC, 0xFF, 0xFF, 0x7F, 0xFF, 0x7F, 0xFF, 0x7F, 0xFF, 0x7F, 0x96, 0x00, 0xBC, 0x02, + 0xC8, 0x00, 0x3C, 0x00, 0x0A, 0x04, 0xB4, 0xB4, 0x32, 0x32, 0x23, 0x05, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x09, 0x0D, 0x00, 0x00, 0x24, 0x0D, 0x00, 0x00, 0x00, 0x00, 0x10, 0x24, 0x24, 0x24, 0x24, + 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0A, 0x05, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x17, 0x16, 0x01, 0x12, 0x10, 0x12, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0F, 0x23, 0x32, 0x46, 0x50, 0x00, 0x00, 0x00, 0x6E, 0x5F, 0x55, 0x50, + 0x46, 0x3C, 0x3C, 0x3C, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x23, 0x32, 0x46, + 0x50, 0x00, 0x00, 0x00, 0x6E, 0x5F, 0x55, 0x50, 0x46, 0x3C, 0x3C, 0x3C, 0x0F, 0x14, 0x1E, 0x28, + 0x00, 0x00, 0x00, 0x00, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x19, 0x46, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x28, 0x1E, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x00, 0x00, 0x00, 0x00, + 0x0A, 0x03, 0x14, 0x00, 0x5F, 0x00, 0xF1, 0xFF, 0x14, 0x00, 0x0F, 0x00, 0x0A, 0x00, 0xBC, 0x02, + 0x00, 0x00, 0x00, 0x00, 0x78, 0x76, 0x00, 0x1E, 0x5A, 0x00, 0x19, 0x00, 0x90, 0x01, 0x1B, 0x00, + 0x0A, 0x00, 0x0A, 0x00, 0x68, 0x01, 0x2C, 0x01, 0xF4, 0x01, 0xF8, 0x02, 0x00, 0x00, 0x37, 0x04, + 0x00, 0x00, 0x5F, 0x09, 0xF4, 0x01, 0x00, 0x00, 0x37, 0x04, 0x00, 0x00, 0x5F, 0x09, 0x32, 0x14, + 0x02, 0x1E, 0x1E, 0x32, 0x02, 0x00, 0x64, 0x00, 0x46, 0x00, 0x1E, 0x00, 0x0A, 0x00, 0x2D, 0x04, + 0x0A, 0x00, 0x55, 0x09, 0x00, 0x00, 0x00, 0x00, 0x40, 0x04, 0x28, 0x00, 0x15, 0x00, 0x01, 0x00, + 0x17, 0x00, 0x00, 0x00, 0x26, 0x00, 0x58, 0x00, 0x8A, 0x00, 0xBD, 0x00, 0xED, 0x00, 0x20, 0x01, + 0x54, 0x01, 0x86, 0x01, 0xBC, 0x01, 0xEF, 0x01, 0x20, 0x02, 0x56, 0x02, 0x84, 0x02, 0xB9, 0x02, + 0xEC, 0x02, 0x25, 0x03, 0x55, 0x03, 0x89, 0x03, 0xB9, 0x03, 0xEA, 0x03, 0x17, 0x04, 0x3F, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6C, 0x09, 0x28, 0x00, 0x14, 0x00, + 0x01, 0x00, 0x16, 0x00, 0x00, 0x00, 0x27, 0x00, 0xA3, 0x00, 0x16, 0x01, 0x98, 0x01, 0x0C, 0x02, + 0x8D, 0x02, 0x04, 0x03, 0x83, 0x03, 0xFD, 0x03, 0x78, 0x04, 0xF3, 0x04, 0x6E, 0x05, 0xE8, 0x05, + 0x63, 0x06, 0xE6, 0x06, 0x5C, 0x07, 0xEC, 0x07, 0x52, 0x08, 0xC8, 0x08, 0x43, 0x09, 0x6B, 0x09, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x01, 0x20, 0x00, 0x19, 0x45, 0x00, 0x00, 0xF1, 0x6C, 0x00, 0x00, 0x84, 0xD9, 0x06, 0x00, + 0x29, 0xB1, 0x01, 0x00, 0x89, 0x11, 0x00, 0x00, 0x41, 0x04, 0x00, 0x00, 0x01, 0x01, 0x03, 0x03, + 0x03, 0x05, 0x05, 0x05, 0x05, 0x05, 0x01, 0x4B, 0x11, 0x00, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x03, 0x03, 0x03, 0x05, 0x05, 0x05, 0x05, 0x05, 0x00, 0x19, 0x45, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x40, 0x9C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x14, 0x0A, 0x0A, + 0x0D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x14, 0x14, 0x14, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x00, 0x40, 0x00, 0x21, 0x00, 0xDC, 0x05, 0x1E, 0x00, 0x08, 0x00, 0x40, 0x06, 0x71, 0x02, + 0x01, 0x00, 0x3C, 0x00, 0x0A, 0x00, 0x0F, 0x0A, 0x0F, 0xA0, 0x1B, 0x00, 0x78, 0x00, 0x14, 0x4B, + 0x1B, 0x00, 0xC8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xA0, 0x1B, 0x00, 0x78, 0x00, 0x14, 0x4B, + 0x1B, 0x00, 0xC8, 0x00, 0x14, 0xA0, 0x28, 0x00, 0x78, 0x00, 0x14, 0x32, 0x28, 0x00, 0xC8, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x41, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB4, 0x00, 0x0D, 0x0D, + 0x0B, 0x0A, 0x19, 0x00, 0x1C, 0x00, 0x2D, 0x00, 0x0A, 0x00, 0x4B, 0x00, 0x05, 0x00, 0x96, 0x00, + 0xC2, 0x01, 0x0F, 0x02, 0xE8, 0xE8, 0xF8, 0x00, 0xF8, 0x00, 0x04, 0x00, 0x41, 0x00, 0x00, 0x00, + 0x23, 0x00, 0x28, 0x00, 0x2E, 0x00, 0x34, 0x00, 0x3B, 0x00, 0x42, 0x00, 0x4B, 0x00, 0x55, 0x00, + 0x5F, 0x00, 0x6B, 0x00, 0x78, 0x00, 0x86, 0x00, 0x96, 0x00, 0xA7, 0x00, 0xBA, 0x00, 0xCF, 0x00, + 0xE6, 0x00, 0xFF, 0x00, 0x1B, 0x01, 0x38, 0x01, 0x59, 0x01, 0x7C, 0x01, 0xA2, 0x01, 0xCB, 0x01, + 0xF7, 0x01, 0x26, 0x02, 0x59, 0x02, 0x90, 0x02, 0xCA, 0x02, 0x09, 0x03, 0x4B, 0x03, 0x92, 0x03, + 0xDD, 0x03, 0x2C, 0x04, 0x80, 0x04, 0xD8, 0x04, 0x35, 0x05, 0x97, 0x05, 0xFE, 0x05, 0x69, 0x06, + 0xD8, 0x06, 0x4D, 0x07, 0xC5, 0x07, 0x42, 0x08, 0xC4, 0x08, 0x49, 0x09, 0xD2, 0x09, 0x5F, 0x0A, + 0xEF, 0x0A, 0x82, 0x0B, 0x18, 0x0C, 0xB0, 0x0C, 0x4A, 0x0D, 0xE5, 0x0D, 0x82, 0x0E, 0x1F, 0x0F, + 0xBD, 0x0F, 0x5A, 0x10, 0xF5, 0x10, 0x90, 0x11, 0x28, 0x12, 0xBE, 0x12, 0x51, 0x13, 0xDF, 0x13, + 0x6A, 0x14, 0xEF, 0x14, 0x6F, 0x15, 0xE9, 0x15, 0x5C, 0x16, 0xC8, 0x16, 0x2C, 0x17, 0x88, 0x17, + 0xDC, 0x17, 0x27, 0x18, 0x69, 0x18, 0xA1, 0x18, 0xCF, 0x18, 0xF4, 0x18, 0x0E, 0x19, 0x1D, 0x19, + 0x23, 0x19, 0x1E, 0x00, 0x23, 0x00, 0x27, 0x00, 0x2D, 0x00, 0x33, 0x00, 0x3A, 0x00, 0x42, 0x00, + 0x4A, 0x00, 0x54, 0x00, 0x5F, 0x00, 0x6B, 0x00, 0x78, 0x00, 0x87, 0x00, 0x97, 0x00, 0xA9, 0x00, + 0xBC, 0x00, 0xD2, 0x00, 0xE9, 0x00, 0x03, 0x01, 0x1F, 0x01, 0x3E, 0x01, 0x60, 0x01, 0x84, 0x01, + 0xAB, 0x01, 0xD6, 0x01, 0x04, 0x02, 0x35, 0x02, 0x6A, 0x02, 0xA3, 0x02, 0xE0, 0x02, 0x21, 0x03, + 0x67, 0x03, 0xB1, 0x03, 0xFF, 0x03, 0x52, 0x04, 0xAA, 0x04, 0x07, 0x05, 0x68, 0x05, 0xCF, 0x05, + 0x3A, 0x06, 0xAA, 0x06, 0x1F, 0x07, 0x99, 0x07, 0x17, 0x08, 0x9A, 0x08, 0x22, 0x09, 0xAD, 0x09, + 0x3D, 0x0A, 0xD0, 0x0A, 0x66, 0x0B, 0xFF, 0x0B, 0x9B, 0x0C, 0x3A, 0x0D, 0xDA, 0x0D, 0x7B, 0x0E, + 0x1D, 0x0F, 0xC0, 0x0F, 0x62, 0x10, 0x04, 0x11, 0xA4, 0x11, 0x42, 0x12, 0xDE, 0x12, 0x76, 0x13, + 0x0B, 0x14, 0x9B, 0x14, 0x26, 0x15, 0xAB, 0x15, 0x2B, 0x16, 0xA3, 0x16, 0x14, 0x17, 0x7D, 0x17, + 0xDE, 0x17, 0x36, 0x18, 0x84, 0x18, 0xC9, 0x18, 0x04, 0x19, 0x35, 0x19, 0x5B, 0x19, 0x76, 0x19, + 0x87, 0x19, 0x8C, 0x19, 0x2F, 0x00, 0x35, 0x00, 0x3C, 0x00, 0x44, 0x00, 0x4C, 0x00, 0x55, 0x00, + 0x60, 0x00, 0x6B, 0x00, 0x77, 0x00, 0x85, 0x00, 0x94, 0x00, 0xA5, 0x00, 0xB7, 0x00, 0xCB, 0x00, + 0xE1, 0x00, 0xF8, 0x00, 0x12, 0x01, 0x2E, 0x01, 0x4C, 0x01, 0x6D, 0x01, 0x90, 0x01, 0xB6, 0x01, + 0xDF, 0x01, 0x0B, 0x02, 0x3A, 0x02, 0x6C, 0x02, 0xA2, 0x02, 0xDB, 0x02, 0x18, 0x03, 0x59, 0x03, + 0x9E, 0x03, 0xE6, 0x03, 0x33, 0x04, 0x84, 0x04, 0xD9, 0x04, 0x32, 0x05, 0x8F, 0x05, 0xF1, 0x05, + 0x57, 0x06, 0xC1, 0x06, 0x2F, 0x07, 0xA1, 0x07, 0x17, 0x08, 0x91, 0x08, 0x0F, 0x09, 0x90, 0x09, + 0x14, 0x0A, 0x9C, 0x0A, 0x26, 0x0B, 0xB2, 0x0B, 0x41, 0x0C, 0xD2, 0x0C, 0x63, 0x0D, 0xF6, 0x0D, + 0x8A, 0x0E, 0x1D, 0x0F, 0xB1, 0x0F, 0x43, 0x10, 0xD5, 0x10, 0x65, 0x11, 0xF2, 0x11, 0x7D, 0x12, + 0x04, 0x13, 0x88, 0x13, 0x08, 0x14, 0x82, 0x14, 0xF8, 0x14, 0x67, 0x15, 0xD1, 0x15, 0x34, 0x16, + 0x90, 0x16, 0xE4, 0x16, 0x30, 0x17, 0x75, 0x17, 0xB1, 0x17, 0xE4, 0x17, 0x0E, 0x18, 0x2F, 0x18, + 0x46, 0x18, 0x55, 0x18, 0x59, 0x18, 0x2F, 0x00, 0x35, 0x00, 0x3C, 0x00, 0x44, 0x00, 0x4C, 0x00, + 0x55, 0x00, 0x60, 0x00, 0x6B, 0x00, 0x77, 0x00, 0x85, 0x00, 0x94, 0x00, 0xA5, 0x00, 0xB7, 0x00, + 0xCB, 0x00, 0xE1, 0x00, 0xF8, 0x00, 0x12, 0x01, 0x2E, 0x01, 0x4C, 0x01, 0x6D, 0x01, 0x90, 0x01, + 0xB6, 0x01, 0xDF, 0x01, 0x0B, 0x02, 0x3A, 0x02, 0x6C, 0x02, 0xA2, 0x02, 0xDB, 0x02, 0x18, 0x03, + 0x59, 0x03, 0x9E, 0x03, 0xE6, 0x03, 0x33, 0x04, 0x84, 0x04, 0xD9, 0x04, 0x32, 0x05, 0x8F, 0x05, + 0xF1, 0x05, 0x57, 0x06, 0xC1, 0x06, 0x2F, 0x07, 0xA1, 0x07, 0x17, 0x08, 0x91, 0x08, 0x0F, 0x09, + 0x90, 0x09, 0x14, 0x0A, 0x9C, 0x0A, 0x26, 0x0B, 0xB2, 0x0B, 0x41, 0x0C, 0xD2, 0x0C, 0x63, 0x0D, + 0xF6, 0x0D, 0x8A, 0x0E, 0x1D, 0x0F, 0xB1, 0x0F, 0x43, 0x10, 0xD5, 0x10, 0x65, 0x11, 0xF2, 0x11, + 0x7D, 0x12, 0x04, 0x13, 0x88, 0x13, 0x08, 0x14, 0x82, 0x14, 0xF8, 0x14, 0x67, 0x15, 0xD1, 0x15, + 0x34, 0x16, 0x90, 0x16, 0xE4, 0x16, 0x30, 0x17, 0x75, 0x17, 0xB1, 0x17, 0xE4, 0x17, 0x0E, 0x18, + 0x2F, 0x18, 0x46, 0x18, 0x55, 0x18, 0x59, 0x18, 0x3E, 0x00, 0x3D, 0x00, 0x40, 0x00, 0x40, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x73, 0x00, 0xA5, 0x00, 0x40, 0x01, 0x1E, 0x00, 0x05, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4E, 0x56, 0x54, + 0xCD, 0xCC, 0x58, 0x42, 0x00, 0x00, 0x48, 0x43, 0x00, 0x00, 0x8C, 0x41, 0x0C, 0x00, 0xB7, 0x40, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x20, 0x92, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x50, 0x8B, 0x01, 0x90, 0x7B, 0x02, 0x05, + 0x41, 0x52, 0x5B, 0x14, 0x81, 0x0B, 0x00, 0x00, 0x00, 0x42, 0x52, 0x5B, 0x14, 0x81, 0x0B, 0x00, + 0x00, 0x00, 0x43, 0x52, 0x5B, 0x14, 0x81, 0x0B, 0x00, 0x00, 0x00, 0x46, 0x52, 0x5B, 0x14, 0x81, + 0x0B, 0x00, 0x00, 0x00, 0x47, 0x52, 0x5B, 0x14, 0x81, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x01, 0x10, 0x15, 0x00, 0x00, 0x20, 0x02, 0x10, 0x01, + 0x00, 0x00, 0x30, 0x03, 0x00, 0x02, 0x00, 0x00, 0x80, 0x04, 0x00, 0x03, 0x00, 0x00, 0x40, 0x05, + 0x00, 0x04, 0x00, 0x00, 0x50, 0x06, 0x00, 0x00, 0x00, 0x00, 0x60, 0x07, 0x00, 0x00, 0x00, 0x00, + 0x70, 0x08, 0x00, 0x00, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x01, 0x00, + 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBD, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4D, 0x04, 0x7F, 0xFF, +}; +static const uint8_t FW_20669_ILI7807S[] = +{ + 0x00, 0x00, 0x00, 0x00, 0x02, 0x09, 0x00, 0x02, 0x02, 0x07, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x04, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, + 0x01, 0x00, 0x17, 0x04, 0x00, 0x00, 0x00, 0x01, 0x3F, 0xFF, 0x01, 0xD0, 0x00, 0x01, 0xEF, 0xFF, + 0x01, 0xF0, 0x00, 0x01, 0xF1, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x40, 0x00, 0x01, + 0xCF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x48, 0x00, 0x89, 0xEA, 0x48, 0x00, 0x87, 0xD8, 0x48, 0x00, 0x87, 0xFE, 0x48, 0x00, 0x88, 0x24, + 0x48, 0x00, 0x88, 0x4A, 0x48, 0x00, 0x88, 0x70, 0x48, 0x00, 0x88, 0x96, 0x48, 0x00, 0x88, 0xBC, + 0x48, 0x00, 0x88, 0xE2, 0x48, 0x00, 0x89, 0x50, 0x48, 0x00, 0x89, 0x52, 0x48, 0x00, 0x89, 0x54, + 0x48, 0x00, 0x89, 0x56, 0x48, 0x00, 0x89, 0x58, 0x48, 0x00, 0x89, 0x5A, 0x48, 0x00, 0x89, 0x5C, + 0x48, 0x00, 0x89, 0x5E, 0x48, 0x00, 0x89, 0x60, 0x48, 0x00, 0x89, 0x62, 0x48, 0x00, 0x89, 0x64, + 0x48, 0x00, 0x89, 0x66, 0x48, 0x00, 0x89, 0x68, 0x48, 0x00, 0x89, 0x6A, 0x48, 0x00, 0x89, 0x6C, + 0x48, 0x00, 0x89, 0x6E, 0x48, 0x00, 0x89, 0x70, 0x48, 0x00, 0x89, 0x72, 0x48, 0x00, 0x89, 0x74, + 0x48, 0x00, 0x89, 0x76, 0x48, 0x00, 0x89, 0x78, 0x48, 0x00, 0x89, 0x7A, 0x48, 0x00, 0x89, 0x7C, + 0x48, 0x00, 0x89, 0x7E, 0x48, 0x00, 0x89, 0x80, 0x48, 0x00, 0x89, 0x82, 0x48, 0x00, 0x89, 0x85, + 0x48, 0x00, 0x89, 0x88, 0x48, 0x00, 0x89, 0x8B, 0x48, 0x00, 0x89, 0x8E, 0x48, 0x00, 0x89, 0x91, + 0x48, 0x00, 0x89, 0x94, 0x98, 0x14, 0x01, 0x00, 0x9A, 0x14, 0x01, 0x00, 0xB0, 0x14, 0x01, 0x00, + 0xCA, 0x14, 0x01, 0x00, 0xD8, 0x14, 0x01, 0x00, 0xF0, 0x14, 0x01, 0x00, 0xFE, 0x14, 0x01, 0x00, + 0x1E, 0x15, 0x01, 0x00, 0x26, 0x15, 0x01, 0x00, 0x3A, 0x15, 0x01, 0x00, 0x8C, 0x15, 0x01, 0x00, + 0x30, 0x16, 0x01, 0x00, 0x4E, 0x16, 0x01, 0x00, 0x56, 0x16, 0x01, 0x00, 0x5E, 0x16, 0x01, 0x00, + 0x66, 0x16, 0x01, 0x00, 0x5C, 0x17, 0x01, 0x00, 0x3E, 0x18, 0x01, 0x00, 0xBC, 0x18, 0x01, 0x00, + 0xD0, 0x18, 0x01, 0x00, 0xD2, 0x18, 0x01, 0x00, 0xD4, 0x18, 0x01, 0x00, 0xD6, 0x18, 0x01, 0x00, + 0xE8, 0x18, 0x01, 0x00, 0x0A, 0x19, 0x01, 0x00, 0x36, 0x19, 0x01, 0x00, 0x6C, 0x19, 0x01, 0x00, + 0x86, 0x19, 0x01, 0x00, 0xB4, 0x19, 0x01, 0x00, 0x2E, 0x1A, 0x01, 0x00, 0x6E, 0x1A, 0x01, 0x00, + 0x90, 0x1A, 0x01, 0x00, 0xFC, 0x00, 0x49, 0x00, 0x43, 0xBA, 0xEA, 0x50, 0x49, 0x00, 0x3B, 0xBB, + 0xEA, 0x50, 0x44, 0x12, 0x08, 0x00, 0x49, 0x00, 0x3C, 0x70, 0xDD, 0x41, 0xC8, 0x0D, 0x44, 0x12, + 0x08, 0x00, 0xEA, 0x50, 0x50, 0x20, 0xFF, 0xE0, 0x50, 0x30, 0xFF, 0xEC, 0x2E, 0x40, 0x1B, 0xB8, + 0x49, 0x00, 0x3F, 0x1B, 0xFC, 0x80, 0x44, 0x12, 0x08, 0x00, 0xEA, 0x50, 0x50, 0x20, 0xFF, 0xE0, + 0x50, 0x30, 0xFF, 0xEC, 0x49, 0x00, 0x43, 0x3B, 0xFC, 0x80, 0xFC, 0x00, 0x44, 0x20, 0x01, 0x0C, + 0x2E, 0x36, 0xF3, 0xC0, 0x84, 0x20, 0xFE, 0x9C, 0xEA, 0x50, 0xDD, 0x40, 0x49, 0x00, 0x45, 0x71, + 0xFC, 0x80, 0x44, 0x12, 0x22, 0x90, 0x84, 0x01, 0xAE, 0x08, 0xEA, 0x7F, 0xDD, 0x4B, 0xEA, 0xDC, + 0x3C, 0x03, 0xEC, 0x86, 0xAE, 0x0B, 0xDD, 0x9E, 0xFC, 0x44, 0x49, 0x00, 0x7A, 0xB1, 0x80, 0xC0, + 0xEA, 0x2F, 0xF0, 0x82, 0x3C, 0x14, 0x0A, 0x9C, 0x2E, 0x86, 0xF3, 0xAE, 0x84, 0x60, 0x2E, 0xA6, + 0xF3, 0xAF, 0x40, 0x00, 0xA8, 0x08, 0x3C, 0x17, 0xE9, 0xF4, 0xF0, 0x83, 0x40, 0x00, 0xA8, 0x08, + 0xF0, 0x85, 0x2E, 0x07, 0xF0, 0x13, 0x40, 0x44, 0x04, 0x09, 0x40, 0x25, 0x04, 0x09, 0xF0, 0x87, + 0x80, 0x23, 0x44, 0x90, 0x7F, 0xFF, 0x83, 0x83, 0x97, 0x58, 0xE2, 0xAA, 0xF5, 0x81, 0x44, 0x52, + 0x5C, 0x0C, 0xE8, 0x37, 0x44, 0x52, 0x5C, 0x0C, 0xF0, 0x03, 0x38, 0x52, 0x8D, 0x01, 0x40, 0x70, + 0x14, 0xF6, 0xF0, 0x05, 0x97, 0xFB, 0x40, 0x50, 0x14, 0xB6, 0xFF, 0x6A, 0x97, 0x6B, 0xF7, 0x84, + 0xF5, 0x86, 0x84, 0xE0, 0x55, 0xE3, 0x80, 0xFF, 0x40, 0x5E, 0x1C, 0x00, 0x40, 0xFF, 0x20, 0x06, + 0x97, 0x69, 0xE8, 0x1C, 0xF0, 0x02, 0x38, 0x50, 0x15, 0x11, 0xF0, 0x04, 0xE0, 0x05, 0xE9, 0x04, + 0xF0, 0x07, 0x5A, 0x08, 0x01, 0x08, 0x44, 0x02, 0x22, 0x18, 0x84, 0x20, 0xEB, 0x59, 0x48, 0x00, + 0x00, 0x86, 0xF0, 0x06, 0xE0, 0xA0, 0xE8, 0x08, 0x8C, 0x21, 0xE0, 0xA9, 0x96, 0x49, 0xE8, 0x04, + 0xF2, 0x01, 0x80, 0x9E, 0x81, 0x25, 0x8C, 0xE1, 0xD5, 0xDE, 0x83, 0x85, 0x8C, 0x61, 0xD5, 0xC5, + 0x38, 0x02, 0x89, 0x01, 0x80, 0x61, 0xC8, 0x04, 0x84, 0x01, 0x38, 0x02, 0x89, 0x09, 0x3C, 0x07, + 0xE9, 0xF5, 0x38, 0x52, 0x89, 0x01, 0xEA, 0x21, 0x40, 0x00, 0x14, 0x16, 0xFE, 0x02, 0x96, 0x03, + 0xE1, 0x20, 0x3C, 0x53, 0xE9, 0xF6, 0xE8, 0x21, 0x2E, 0x07, 0xD4, 0x8A, 0xE2, 0x04, 0xE8, 0x03, + 0x9A, 0x20, 0xD5, 0x02, 0x8A, 0x04, 0xE4, 0x02, 0x54, 0x07, 0x80, 0xFF, 0xC0, 0x11, 0x2E, 0x07, + 0xD4, 0x89, 0xE2, 0x02, 0xE8, 0x03, 0x9A, 0x10, 0xD5, 0x02, 0x8A, 0x02, 0xE4, 0x02, 0x54, 0x07, + 0x80, 0xFF, 0xC0, 0x06, 0x9C, 0xE9, 0xE0, 0x23, 0x40, 0x11, 0xBC, 0x1B, 0x96, 0xC9, 0x3E, 0x47, + 0xD4, 0x8A, 0x3E, 0x27, 0xD4, 0x89, 0xD5, 0x06, 0x84, 0x1F, 0x3E, 0x07, 0xD4, 0x8A, 0x3E, 0x07, + 0xD4, 0x89, 0xE2, 0xA3, 0x44, 0x02, 0x22, 0x18, 0xE8, 0x08, 0x84, 0x21, 0x3E, 0x17, 0xED, 0xA4, + 0x38, 0x10, 0x18, 0x00, 0x8C, 0x21, 0xD5, 0x04, 0x84, 0x20, 0x3E, 0x17, 0xED, 0xA4, 0xEB, 0x59, + 0x2E, 0x17, 0xED, 0xA1, 0x2E, 0x07, 0xED, 0xA0, 0x2E, 0x27, 0xD3, 0xEE, 0x88, 0x01, 0x3C, 0x13, + 0xF6, 0xD4, 0x96, 0x00, 0x96, 0x46, 0xE2, 0x40, 0xC1, 0x16, 0xE8, 0x1D, 0x84, 0x07, 0xDD, 0x4A, + 0x5A, 0x08, 0x01, 0x13, 0x2E, 0x07, 0xED, 0xA5, 0x5A, 0x08, 0x01, 0x07, 0x2E, 0x07, 0xD4, 0x88, + 0x8E, 0x01, 0x3E, 0x07, 0xD4, 0x88, 0x2E, 0x07, 0xD4, 0x88, 0xC8, 0x10, 0x84, 0x03, 0x3E, 0x07, + 0xD4, 0x88, 0xD5, 0x07, 0xE8, 0x08, 0x84, 0x00, 0x3E, 0x07, 0xED, 0xA0, 0x3E, 0x07, 0xED, 0xA1, + 0x84, 0x01, 0xFC, 0xC4, 0x84, 0x03, 0x3E, 0x07, 0xD4, 0x88, 0x84, 0x00, 0xFC, 0xC4, 0xFC, 0x00, + 0x49, 0xFF, 0xFF, 0x2C, 0xFC, 0x80, 0xFC, 0x40, 0xB4, 0x80, 0xA5, 0x4C, 0x22, 0x30, 0x80, 0x02, + 0xE0, 0x85, 0x22, 0x70, 0x80, 0x05, 0x22, 0x60, 0x80, 0x03, 0xE8, 0x2B, 0x96, 0xD9, 0xE0, 0x83, + 0x81, 0x43, 0x40, 0x92, 0x8C, 0x01, 0x40, 0xA2, 0x3C, 0x1A, 0x80, 0xC9, 0x4E, 0x94, 0x00, 0x04, + 0x52, 0x64, 0x80, 0x00, 0x40, 0x21, 0xA8, 0x01, 0x4E, 0x24, 0x00, 0x03, 0xFE, 0x92, 0x22, 0x70, + 0x80, 0x00, 0x40, 0x15, 0x0C, 0x01, 0x9A, 0xEF, 0xFE, 0x5C, 0x40, 0x10, 0xA4, 0x36, 0x88, 0x27, + 0xE0, 0x27, 0xE9, 0x05, 0xE0, 0xA1, 0x40, 0x50, 0xBC, 0x1A, 0x80, 0xE5, 0x9A, 0x72, 0xFF, 0x14, + 0x42, 0x23, 0x84, 0x24, 0x40, 0x42, 0x18, 0x96, 0x40, 0x21, 0x18, 0x56, 0x88, 0x82, 0xD5, 0x37, + 0x41, 0xC3, 0x80, 0x13, 0x40, 0x91, 0x70, 0x01, 0xE1, 0x24, 0xE8, 0x34, 0x40, 0xA3, 0x00, 0x13, + 0x40, 0x31, 0x28, 0x01, 0xE0, 0x64, 0x80, 0xA3, 0x40, 0x7E, 0x28, 0x01, 0x40, 0x52, 0x3C, 0x1A, + 0x4E, 0x74, 0x00, 0x03, 0xFF, 0xFA, 0x8A, 0x65, 0x4E, 0x34, 0x00, 0x05, 0x40, 0x35, 0x08, 0x01, + 0x88, 0x65, 0x22, 0x80, 0x80, 0x01, 0x9B, 0x55, 0x8A, 0xAA, 0x40, 0x6E, 0x20, 0x01, 0xFF, 0x74, + 0x40, 0x15, 0x70, 0x01, 0x40, 0x12, 0x84, 0x36, 0x8A, 0x28, 0x88, 0x22, 0xE0, 0x29, 0xE9, 0x06, + 0x8A, 0x48, 0xE0, 0x41, 0x40, 0x20, 0xBC, 0x1A, 0x81, 0x22, 0x9A, 0x7B, 0x42, 0x52, 0x0C, 0x24, + 0x42, 0x34, 0x84, 0x24, 0x40, 0x52, 0x9C, 0xB6, 0xEB, 0x33, 0x99, 0x2B, 0xB6, 0x80, 0x84, 0x01, + 0xFC, 0xC0, 0x84, 0x00, 0xFC, 0xC0, 0xFC, 0x20, 0xB4, 0xA0, 0xA1, 0x01, 0xB4, 0x61, 0xA0, 0x09, + 0x80, 0xC5, 0x4E, 0x54, 0x00, 0x03, 0xFF, 0xAA, 0xEB, 0x54, 0xE0, 0x26, 0xE9, 0x08, 0x80, 0xC4, + 0x4E, 0x44, 0x00, 0x03, 0xFF, 0xA2, 0xE0, 0x26, 0x84, 0x20, 0xE8, 0x04, 0x90, 0xA1, 0x90, 0x81, + 0x84, 0x21, 0x80, 0xE3, 0x4E, 0x34, 0x00, 0x03, 0xFF, 0xDA, 0x44, 0x60, 0x7F, 0xFF, 0xE0, 0xC7, + 0xE9, 0x07, 0x80, 0xE0, 0x4E, 0x04, 0x00, 0x03, 0xFF, 0xC2, 0xE0, 0xC7, 0xE8, 0x05, 0x8C, 0x21, + 0x90, 0x61, 0x90, 0x01, 0x96, 0x4A, 0xFE, 0x2C, 0x42, 0x02, 0x0C, 0x75, 0xC1, 0x14, 0x84, 0x81, + 0x4E, 0x04, 0x00, 0x03, 0x84, 0x9F, 0x4E, 0x04, 0x00, 0x03, 0xFE, 0x02, 0x46, 0x33, 0xFF, 0xFF, + 0x50, 0x31, 0x8F, 0xFF, 0xE0, 0x60, 0xE9, 0x06, 0xC1, 0x05, 0x8E, 0x21, 0x94, 0x01, 0x96, 0x4A, + 0xD5, 0xFA, 0xFE, 0x24, 0xAE, 0x50, 0xFC, 0xA0, 0xFC, 0x43, 0x84, 0xE0, 0x81, 0x00, 0x83, 0x81, + 0x81, 0x42, 0x81, 0x21, 0x80, 0xC7, 0x4C, 0x65, 0x00, 0x38, 0xB4, 0x48, 0x22, 0x04, 0x80, 0x00, + 0x04, 0x14, 0x00, 0x01, 0x22, 0x54, 0x80, 0x01, 0x8C, 0xC1, 0x97, 0xB0, 0x8A, 0x02, 0x8A, 0xA1, + 0xE2, 0xCA, 0xF0, 0x82, 0xF5, 0x83, 0xE9, 0x05, 0x40, 0x33, 0x28, 0x01, 0x96, 0xD8, 0xD5, 0x02, + 0x80, 0x66, 0x94, 0xDA, 0x88, 0x7C, 0x22, 0x41, 0x80, 0x00, 0x22, 0x31, 0x80, 0x01, 0x9A, 0xA2, + 0x9A, 0x59, 0xF2, 0x84, 0xF1, 0x85, 0x4C, 0x01, 0x40, 0x05, 0xD9, 0x03, 0x84, 0x00, 0xFC, 0xC3, + 0x84, 0x00, 0xEA, 0x8E, 0xB0, 0x44, 0xB0, 0x02, 0x50, 0x2F, 0x80, 0x07, 0x49, 0xFF, 0xFF, 0x8D, + 0x4E, 0x05, 0x00, 0x04, 0x84, 0x01, 0xD5, 0x02, 0x84, 0x1F, 0xC7, 0x03, 0x4C, 0x70, 0x7F, 0xF0, + 0x8D, 0x24, 0x80, 0xE0, 0xD5, 0xC9, 0x84, 0x01, 0xFC, 0xC3, 0x3C, 0x03, 0xF6, 0xD7, 0x96, 0x06, + 0xC0, 0x5D, 0xFC, 0x41, 0xEB, 0x1B, 0x84, 0xC0, 0x81, 0x09, 0xEA, 0x4E, 0xE2, 0xC0, 0xE8, 0x55, + 0xDD, 0x57, 0x80, 0x29, 0xEB, 0x1F, 0xEA, 0xE8, 0x9E, 0x89, 0xE6, 0x42, 0xE9, 0x03, 0x5A, 0x18, + 0x04, 0x4A, 0x80, 0x28, 0xEB, 0x1F, 0x22, 0x00, 0x80, 0x19, 0x44, 0x12, 0x07, 0xE0, 0xB6, 0x1F, + 0x3C, 0x73, 0x79, 0xD4, 0x80, 0x1F, 0x80, 0x47, 0x49, 0xFF, 0xFE, 0xEF, 0x81, 0x40, 0x3C, 0x27, + 0xE9, 0xB4, 0xB4, 0x1F, 0xE0, 0x02, 0xE9, 0x08, 0x3C, 0x27, 0xE9, 0xB5, 0x9A, 0xBA, 0xE0, 0x02, + 0x40, 0x20, 0x3C, 0x1B, 0x96, 0x93, 0xDD, 0x57, 0x80, 0x28, 0xEB, 0x1F, 0x22, 0x00, 0x80, 0x1A, + 0x12, 0x20, 0x80, 0x19, 0xF0, 0x81, 0x44, 0x12, 0x07, 0xEC, 0x3C, 0x73, 0x79, 0xD5, 0xB0, 0x01, + 0x80, 0x47, 0x49, 0xFF, 0xFE, 0xD2, 0xF1, 0x01, 0x3C, 0x27, 0xE9, 0xBA, 0xE0, 0x22, 0xE9, 0x08, + 0x3C, 0x27, 0xE9, 0xBB, 0x9A, 0xBA, 0xE0, 0x22, 0x40, 0x20, 0xBC, 0x1B, 0x96, 0x93, 0xEA, 0x76, + 0x80, 0x68, 0x42, 0x33, 0x04, 0x73, 0x12, 0x21, 0x80, 0x1A, 0x4E, 0xA3, 0x00, 0x03, 0xC0, 0x08, + 0x80, 0x08, 0x42, 0x03, 0x04, 0x73, 0x84, 0x21, 0x10, 0x10, 0x01, 0x2E, 0xD5, 0x03, 0x10, 0x01, + 0x81, 0x2E, 0x8C, 0xC1, 0x97, 0xB0, 0xD5, 0xAA, 0xFC, 0xC1, 0xDD, 0x9E, 0xFC, 0x21, 0x80, 0xC0, + 0xF1, 0x81, 0x50, 0x20, 0x00, 0x50, 0x00, 0x01, 0x7F, 0xFF, 0x50, 0x71, 0x7F, 0xEC, 0x5A, 0x08, + 0x01, 0x06, 0x80, 0x02, 0x80, 0x27, 0xFA, 0x44, 0xDD, 0x55, 0x80, 0x47, 0x4C, 0x63, 0xFF, 0xF5, + 0x80, 0x06, 0xF1, 0x01, 0xFA, 0x44, 0xDD, 0x55, 0xFC, 0xA1, 0x44, 0x22, 0x4F, 0x8C, 0x38, 0x31, + 0x01, 0x10, 0xE0, 0x61, 0xE8, 0x08, 0x94, 0x01, 0x88, 0x02, 0x20, 0x00, 0x00, 0x01, 0xE0, 0x20, + 0xEB, 0x27, 0xDD, 0x9E, 0x84, 0x01, 0xDD, 0x9E, 0xFC, 0x41, 0x84, 0x40, 0x2E, 0x16, 0xF3, 0xAF, + 0x2E, 0x87, 0xED, 0xB6, 0xB6, 0x3F, 0x2E, 0xA7, 0xED, 0xB5, 0xEB, 0xB1, 0x2E, 0x77, 0xED, 0xB4, + 0xF1, 0x81, 0x80, 0x62, 0x80, 0x82, 0x80, 0xC2, 0x45, 0xC2, 0x4F, 0xBC, 0xB4, 0x3F, 0x54, 0x91, + 0x80, 0xFF, 0xE3, 0x21, 0xE8, 0x1D, 0x95, 0x59, 0x88, 0xBC, 0x38, 0x1E, 0x0D, 0x00, 0x01, 0xE2, + 0x80, 0x01, 0xE2, 0x3E, 0xE8, 0x11, 0x99, 0x4A, 0x38, 0x50, 0x15, 0x11, 0xE0, 0xC5, 0xE8, 0x04, + 0x81, 0x49, 0x81, 0x01, 0x80, 0xC5, 0xE0, 0xA4, 0x8C, 0x21, 0x40, 0x74, 0xBC, 0x1B, 0x40, 0x42, + 0xBC, 0x1B, 0x96, 0x48, 0xD5, 0xEF, 0xF1, 0x01, 0x8C, 0x61, 0x88, 0x41, 0xD5, 0xE0, 0x3E, 0x87, + 0xED, 0xB6, 0x3E, 0xA7, 0xED, 0xB5, 0x3E, 0x77, 0xED, 0xB4, 0x3C, 0x6B, 0xF8, 0x07, 0x3C, 0x4B, + 0xF8, 0x05, 0xFC, 0xC1, 0xFC, 0x44, 0xF0, 0x82, 0x84, 0x00, 0x3C, 0x0B, 0xF6, 0xD9, 0xF2, 0x83, + 0x2F, 0xC6, 0xF3, 0xAE, 0x81, 0x41, 0x2E, 0x86, 0xF3, 0xAF, 0x80, 0x01, 0x42, 0x24, 0x70, 0x24, + 0x84, 0x2F, 0xF3, 0x84, 0xF4, 0x85, 0xDD, 0x40, 0x84, 0x80, 0x50, 0x2E, 0x7F, 0xFF, 0x80, 0x64, + 0x80, 0xA4, 0x80, 0x04, 0x44, 0x12, 0x4F, 0xBC, 0x50, 0x74, 0x7F, 0xFF, 0xF2, 0x87, 0xE2, 0xA8, + 0xE8, 0x3B, 0x42, 0x22, 0xF0, 0x24, 0xF2, 0x81, 0x94, 0xA9, 0x88, 0x41, 0x38, 0x60, 0x95, 0x00, + 0xF2, 0x86, 0xF2, 0x06, 0xA6, 0x91, 0xE2, 0xC2, 0xE8, 0x2C, 0xF2, 0x01, 0x04, 0x9F, 0x80, 0x03, + 0x41, 0xE3, 0x08, 0x00, 0xF2, 0x02, 0x38, 0x21, 0x79, 0x11, 0xE1, 0x22, 0xE8, 0x15, 0xDF, 0x06, + 0x8C, 0x61, 0x8C, 0x81, 0x96, 0xD8, 0x97, 0x20, 0xD5, 0x09, 0xC6, 0x06, 0xC5, 0x05, 0x04, 0x9F, + 0x80, 0x07, 0x4C, 0x64, 0xC0, 0x04, 0x8C, 0x61, 0x96, 0xD8, 0x44, 0x90, 0x00, 0x4F, 0x8C, 0x01, + 0x38, 0x95, 0x78, 0x08, 0x96, 0x01, 0x3C, 0xF7, 0xE9, 0x56, 0x40, 0xF7, 0x88, 0x07, 0xE8, 0x06, + 0x3C, 0x23, 0xF6, 0xD9, 0x8C, 0x41, 0x3C, 0x2B, 0xF6, 0xD9, 0x8C, 0xC1, 0x97, 0xB0, 0xD5, 0xD2, + 0x8C, 0xA1, 0x97, 0x68, 0xD5, 0xC5, 0xF1, 0x04, 0xAE, 0xC8, 0xF1, 0x05, 0xAF, 0x08, 0xFC, 0xC4, + 0xFC, 0x4D, 0x51, 0xCF, 0x80, 0x88, 0x81, 0x1C, 0x14, 0x0E, 0x7F, 0xE8, 0x22, 0x0E, 0x00, 0x00, + 0x14, 0x1E, 0x7F, 0xE3, 0x14, 0x0E, 0x7F, 0xE2, 0x3C, 0x73, 0x79, 0xD9, 0x2E, 0x16, 0xF3, 0xAF, + 0x40, 0x93, 0x8C, 0x08, 0x50, 0x04, 0x80, 0x08, 0xEA, 0x33, 0x14, 0x1E, 0x7F, 0xF6, 0x15, 0xFE, + 0x7F, 0xEC, 0xB2, 0x36, 0xEA, 0x33, 0x94, 0x3A, 0x8C, 0x08, 0x92, 0x03, 0x94, 0x49, 0x94, 0x03, + 0x8C, 0x28, 0x15, 0xFE, 0x7F, 0xEB, 0x54, 0x10, 0x83, 0xF8, 0xEA, 0x33, 0x95, 0xF9, 0x15, 0xFE, + 0x7F, 0xF2, 0x41, 0xFF, 0x84, 0x01, 0x15, 0xFE, 0x7F, 0xF1, 0xEA, 0x33, 0x9C, 0x3F, 0x92, 0x03, + 0x94, 0x03, 0x15, 0xFE, 0x7F, 0xF0, 0xEA, 0x33, 0x15, 0xFE, 0x7F, 0xED, 0xEA, 0x33, 0x14, 0x2E, + 0x7F, 0xE7, 0x15, 0xFE, 0x7F, 0xF5, 0x84, 0x20, 0xEA, 0x33, 0x80, 0x49, 0xB2, 0x0B, 0x14, 0x3E, + 0x7F, 0xEA, 0x14, 0x4E, 0x7F, 0xE6, 0x14, 0x5E, 0x7F, 0xE5, 0x15, 0xFE, 0x7F, 0xEF, 0x2E, 0x67, + 0xD9, 0x38, 0xDD, 0x40, 0x84, 0x20, 0x80, 0x49, 0xB2, 0x0C, 0xDD, 0x40, 0x84, 0x20, 0x80, 0x47, + 0xB2, 0x0D, 0xDD, 0x40, 0x84, 0x20, 0x80, 0x47, 0xB2, 0x15, 0xDD, 0x40, 0x84, 0x20, 0x80, 0x1F, + 0x80, 0x47, 0xDD, 0x40, 0x44, 0x0F, 0x80, 0x00, 0x3C, 0x0B, 0xEC, 0x9E, 0xEB, 0x54, 0x84, 0x00, + 0xE0, 0x07, 0xE8, 0x08, 0x04, 0x2E, 0x7F, 0xF0, 0x38, 0x11, 0x01, 0x09, 0x8C, 0x01, 0x96, 0x00, + 0xD5, 0xF8, 0xEB, 0x4D, 0xC0, 0x19, 0xEB, 0xA1, 0xEA, 0xA9, 0x14, 0x0E, 0x7F, 0xF7, 0x84, 0xA0, + 0x2E, 0x96, 0xF3, 0xAE, 0xEB, 0xA0, 0x50, 0xA4, 0xFF, 0xFF, 0x50, 0x80, 0x7F, 0xFF, 0x45, 0xE2, + 0x4C, 0xAC, 0xD5, 0x08, 0x00, 0x01, 0x00, 0xEB, 0xC8, 0x11, 0x8C, 0xA1, 0x97, 0x68, 0x50, 0x21, + 0x01, 0x0C, 0xEB, 0x53, 0xD8, 0xF8, 0x84, 0xC0, 0x14, 0x6E, 0x7F, 0xF7, 0x14, 0x6E, 0x7F, 0xF3, + 0x84, 0xFF, 0x81, 0x46, 0x14, 0x6E, 0x7F, 0xE9, 0xD5, 0x64, 0x00, 0x01, 0x00, 0xC8, 0x8A, 0x06, + 0x4E, 0x04, 0x00, 0x03, 0x84, 0x00, 0x00, 0x31, 0x00, 0xC9, 0x96, 0x00, 0x88, 0x66, 0xE0, 0x69, + 0x40, 0x35, 0x3C, 0x1A, 0xE0, 0x60, 0xE9, 0xE2, 0x00, 0x11, 0x00, 0xCA, 0x8A, 0x26, 0x4E, 0x14, + 0x00, 0x03, 0x84, 0x20, 0x00, 0x41, 0x00, 0xCB, 0x04, 0x7E, 0x7F, 0xF6, 0x88, 0x86, 0xE0, 0x87, + 0x96, 0x48, 0x40, 0x44, 0x3C, 0x1A, 0xE0, 0x81, 0xE9, 0x0E, 0x80, 0xE0, 0x42, 0x70, 0xA4, 0x73, + 0x88, 0xFE, 0x8C, 0x21, 0x00, 0xF3, 0x80, 0x00, 0x96, 0x48, 0x58, 0xF7, 0x80, 0x02, 0x10, 0xF3, + 0x80, 0x00, 0xD5, 0xF2, 0x8C, 0x01, 0x96, 0x00, 0xD5, 0xDE, 0x80, 0x22, 0x80, 0x0A, 0x14, 0x4E, + 0x7F, 0xDF, 0x14, 0x2E, 0x7F, 0xE0, 0x49, 0xFF, 0xFE, 0x92, 0x04, 0x2E, 0x7F, 0xE0, 0x04, 0x4E, + 0x7F, 0xDF, 0xC0, 0x42, 0x04, 0x0E, 0x7F, 0xEE, 0x8D, 0x01, 0x88, 0x80, 0xEB, 0xA0, 0x54, 0x24, + 0x00, 0xFF, 0xE2, 0x40, 0xE9, 0xEB, 0x04, 0x0E, 0x7F, 0xF4, 0x5A, 0x08, 0xFF, 0x04, 0x48, 0x00, + 0x00, 0x86, 0x5A, 0x98, 0xFF, 0x04, 0x48, 0x00, 0x00, 0x82, 0x8C, 0xC2, 0x40, 0x05, 0x04, 0x08, + 0x44, 0x12, 0x4F, 0x8C, 0x88, 0x01, 0x97, 0xB0, 0x84, 0xA0, 0x14, 0x0E, 0x7F, 0xEE, 0xEB, 0xA0, + 0x54, 0x82, 0x80, 0xFF, 0xE3, 0x00, 0xE9, 0x75, 0x50, 0x35, 0x00, 0x01, 0x54, 0xA1, 0x80, 0xFF, + 0xEA, 0x3E, 0xE3, 0x40, 0x14, 0x0E, 0x7F, 0xEE, 0x4E, 0xF2, 0x00, 0xDD, 0x04, 0x1E, 0x7F, 0xE8, + 0x40, 0x05, 0x04, 0x08, 0x88, 0x01, 0x14, 0x0E, 0x7F, 0xE4, 0x44, 0x02, 0x4C, 0xAC, 0x8C, 0xE1, + 0x84, 0x80, 0x44, 0x90, 0x00, 0xFF, 0x88, 0x0A, 0x97, 0xFA, 0x81, 0x04, 0x14, 0x9E, 0x7F, 0xF4, + 0x14, 0x0E, 0x7F, 0xE1, 0xD5, 0xC4, 0x80, 0x22, 0x80, 0x0A, 0xBA, 0x01, 0x14, 0x4E, 0x7F, 0xE0, + 0x49, 0x00, 0x1B, 0x57, 0xEB, 0xE5, 0x04, 0x4E, 0x7F, 0xE0, 0x5A, 0x18, 0xFF, 0x06, 0x96, 0x78, + 0xEB, 0x1D, 0x48, 0x00, 0x01, 0xBC, 0x04, 0x5E, 0x7F, 0xF4, 0x4C, 0x50, 0x01, 0xB8, 0x5A, 0x90, + 0xFF, 0x04, 0x48, 0x00, 0x01, 0xB8, 0x8C, 0xE1, 0x96, 0x78, 0x14, 0x1E, 0x7F, 0xF7, 0x81, 0x20, + 0x20, 0x7E, 0x7F, 0xDC, 0x80, 0x01, 0x04, 0x1E, 0x7F, 0xE4, 0x04, 0x2E, 0x7F, 0xF1, 0x04, 0x3E, + 0x7F, 0xF0, 0x38, 0x10, 0x91, 0x11, 0x38, 0x11, 0x21, 0x09, 0x94, 0x81, 0x88, 0x43, 0x22, 0xF1, + 0x00, 0x00, 0xE0, 0x2F, 0xE8, 0x08, 0x04, 0x3E, 0x7F, 0xE1, 0x38, 0x51, 0x90, 0x00, 0x97, 0x4E, + 0xCD, 0x02, 0xAC, 0x50, 0x3C, 0x27, 0xEC, 0x9E, 0xE0, 0x41, 0xE8, 0x07, 0x40, 0x24, 0x00, 0x13, + 0x3C, 0x1B, 0xEC, 0x9E, 0x14, 0x2E, 0x7F, 0xE9, 0x04, 0x3E, 0x7F, 0xEC, 0x94, 0x82, 0x88, 0x43, + 0xB4, 0xA2, 0x88, 0x25, 0xB6, 0x22, 0x04, 0x1E, 0x7F, 0xED, 0x04, 0x2E, 0x7F, 0xED, 0xEB, 0x83, + 0x8C, 0x21, 0x38, 0x11, 0x00, 0x08, 0x48, 0xFF, 0xFF, 0x6F, 0x8C, 0xC1, 0x48, 0xFF, 0xFF, 0x80, + 0x80, 0x0A, 0x80, 0x28, 0x14, 0x5E, 0x7F, 0xE4, 0x49, 0xFF, 0xFD, 0xF1, 0x04, 0x5E, 0x7F, 0xE4, + 0xC8, 0x66, 0x80, 0x28, 0x80, 0x0A, 0xBA, 0x01, 0x49, 0x00, 0x1A, 0xFB, 0xEB, 0xE5, 0x04, 0x5E, + 0x7F, 0xE4, 0x4C, 0x00, 0x80, 0x06, 0x4C, 0x04, 0xC0, 0x05, 0xEB, 0x53, 0xD5, 0x02, 0xEB, 0x50, + 0x44, 0x12, 0x4F, 0x8C, 0x38, 0x10, 0xA9, 0x10, 0x8C, 0x21, 0xD9, 0x07, 0x50, 0x24, 0x00, 0x01, + 0x96, 0x90, 0x50, 0x44, 0x00, 0x02, 0xD5, 0x0C, 0x04, 0x1E, 0x7F, 0xEE, 0x50, 0x34, 0x7F, 0xFF, + 0x20, 0x10, 0x80, 0x01, 0x8E, 0x21, 0xD9, 0x06, 0x96, 0x98, 0x50, 0x44, 0x7F, 0xFE, 0x97, 0x20, + 0xD5, 0x05, 0x50, 0x44, 0x00, 0x01, 0x96, 0xA0, 0x97, 0x18, 0x81, 0x1C, 0xB2, 0x31, 0xB2, 0x71, + 0x38, 0x10, 0x95, 0x11, 0x38, 0x21, 0x89, 0x11, 0x9A, 0x8A, 0x4E, 0x24, 0x00, 0x03, 0xFE, 0x92, + 0x04, 0x3E, 0x7F, 0xE5, 0xE0, 0x43, 0xE8, 0x2B, 0x04, 0x2E, 0x7F, 0xF1, 0x38, 0x21, 0x11, 0x11, + 0x9A, 0x8A, 0x4E, 0x24, 0x00, 0x03, 0xFE, 0x92, 0x04, 0x3E, 0x7F, 0xE5, 0xE0, 0x43, 0xE8, 0x1F, + 0x81, 0x1C, 0xB2, 0x50, 0xB2, 0x62, 0x38, 0x21, 0x01, 0x11, 0x9A, 0x8A, 0xE0, 0x62, 0xE8, 0x09, + 0x81, 0x1C, 0xB2, 0x2F, 0xB2, 0x4F, 0xEB, 0x83, 0x8C, 0x21, 0x38, 0x11, 0x00, 0x08, 0xD5, 0x0F, + 0x81, 0x1C, 0xB2, 0x55, 0xB2, 0x75, 0x38, 0x21, 0x00, 0x00, 0x8C, 0x41, 0x38, 0x21, 0x80, 0x08, + 0xB2, 0x4B, 0x94, 0x02, 0x88, 0x02, 0xB4, 0x40, 0x88, 0x22, 0xB6, 0x20, 0x8C, 0xA1, 0x48, 0xFF, + 0xFF, 0x18, 0x04, 0x4E, 0x7F, 0xF2, 0x2E, 0x26, 0xF3, 0xB1, 0x80, 0x24, 0x92, 0x41, 0x84, 0x00, + 0x96, 0xC0, 0xE2, 0x66, 0xE8, 0x1E, 0x04, 0x3E, 0x7F, 0xF5, 0x38, 0x51, 0x80, 0x00, 0xCD, 0x0F, + 0x04, 0x3E, 0x7F, 0xED, 0x38, 0x51, 0x80, 0x00, 0xE2, 0x45, 0xE9, 0x06, 0x04, 0x3E, 0x7F, 0xF0, + 0x38, 0x31, 0x81, 0x01, 0xD5, 0x0A, 0x04, 0x3E, 0x7F, 0xEC, 0xD5, 0x03, 0x04, 0x3E, 0x7F, 0xEB, + 0x38, 0x31, 0x82, 0x02, 0x40, 0x31, 0x94, 0x76, 0xAC, 0xC8, 0x8C, 0x01, 0x8C, 0x22, 0xD5, 0xE1, + 0x40, 0x03, 0x04, 0x09, 0xEB, 0x21, 0x04, 0x0E, 0x7F, 0xF2, 0x95, 0x71, 0x84, 0x20, 0x88, 0xA0, + 0x3C, 0x97, 0xE9, 0xFE, 0x3C, 0xA3, 0xE9, 0xFF, 0x80, 0x01, 0x87, 0xDE, 0x04, 0x3E, 0x7F, 0xF1, + 0x96, 0x88, 0xE2, 0x43, 0xE8, 0x4E, 0x04, 0x2E, 0x7F, 0xF2, 0x38, 0x71, 0x05, 0x11, 0x80, 0x45, + 0x42, 0x20, 0xF8, 0x73, 0x22, 0x31, 0x7F, 0xFF, 0x9A, 0xBB, 0x4E, 0x24, 0x00, 0x03, 0xFE, 0x92, + 0x04, 0x8E, 0x7F, 0xE3, 0x40, 0x21, 0x20, 0x07, 0x04, 0x8E, 0x7F, 0xE7, 0xE1, 0x07, 0xE8, 0x07, + 0x04, 0x8E, 0x7F, 0xE7, 0xE1, 0x03, 0xE8, 0x03, 0xC2, 0x32, 0xD5, 0x2F, 0xE1, 0x27, 0xE9, 0x2F, + 0xE1, 0x23, 0xE9, 0x2D, 0xC2, 0x2C, 0x81, 0x1C, 0xB2, 0x55, 0x38, 0x31, 0x04, 0x00, 0xB2, 0x4F, + 0x38, 0x21, 0x04, 0x00, 0x40, 0xF1, 0x0C, 0x00, 0xE8, 0x22, 0x04, 0x2E, 0x7F, 0xF5, 0x04, 0x8E, + 0x7F, 0xEF, 0x9B, 0xF1, 0x88, 0x47, 0x88, 0xE8, 0x00, 0x21, 0x7F, 0xFF, 0x00, 0x73, 0xFF, 0xFF, + 0x14, 0x2E, 0x7F, 0xF4, 0x88, 0xE2, 0xC7, 0x13, 0xEA, 0xE5, 0xFE, 0xD4, 0x40, 0x31, 0xBC, 0x76, + 0x96, 0xD9, 0xE3, 0x43, 0xE8, 0x0C, 0x80, 0x62, 0x04, 0x2E, 0x7F, 0xF4, 0xFE, 0x9C, 0x40, 0x71, + 0x1C, 0xF6, 0x97, 0xF9, 0xE3, 0x47, 0xE8, 0x03, 0x8C, 0x01, 0x96, 0x00, 0x8C, 0x21, 0xD5, 0xAF, + 0x2E, 0x17, 0xD4, 0x00, 0xE2, 0x01, 0xE9, 0x08, 0xDD, 0x54, 0x96, 0x2E, 0xC8, 0x05, 0x84, 0x01, + 0x3E, 0x07, 0xF0, 0x13, 0xD5, 0x07, 0x84, 0x00, 0x3E, 0x07, 0xF0, 0x13, 0x84, 0x00, 0x14, 0x0E, + 0x7F, 0xEA, 0x04, 0x2E, 0x7F, 0xE9, 0x44, 0x02, 0x5C, 0x0C, 0x3C, 0x17, 0xEC, 0x9E, 0x38, 0x00, + 0x09, 0x01, 0xFE, 0x0C, 0x90, 0x0A, 0x3C, 0x0B, 0xEC, 0x9E, 0xD4, 0x12, 0x22, 0x02, 0x00, 0x00, + 0x04, 0x1E, 0x7F, 0xEA, 0xE0, 0x01, 0xE9, 0x07, 0x04, 0x1E, 0x7F, 0xE6, 0xE0, 0x20, 0x40, 0x00, + 0xBC, 0x1B, 0xD5, 0x03, 0x04, 0x0E, 0x7F, 0xEA, 0x1A, 0x02, 0x00, 0x01, 0xD5, 0xEF, 0x81, 0x1C, + 0xB2, 0x08, 0x84, 0xFF, 0xEA, 0xF3, 0xB2, 0x0E, 0x84, 0xC0, 0x94, 0x01, 0xEB, 0x21, 0x04, 0x0E, + 0x7F, 0xEE, 0x4C, 0x60, 0x00, 0x55, 0x8C, 0xE1, 0x44, 0x90, 0x00, 0xFF, 0x97, 0xFA, 0x04, 0xAE, + 0x7F, 0xF4, 0x14, 0x9E, 0x7F, 0xF5, 0x85, 0x00, 0xEB, 0xA0, 0x4C, 0x80, 0x00, 0x31, 0x80, 0x06, + 0x80, 0x28, 0x49, 0xFF, 0xFC, 0xB4, 0xC8, 0x23, 0x80, 0x28, 0x80, 0x06, 0xBA, 0x01, 0x49, 0x00, + 0x19, 0xC0, 0x04, 0x1E, 0x7F, 0xF5, 0x5A, 0x18, 0xFF, 0x05, 0x96, 0x78, 0xEB, 0x1D, 0xD5, 0x33, + 0x04, 0x5E, 0x7F, 0xF5, 0xD0, 0x30, 0x5A, 0x98, 0xFF, 0x2B, 0x8C, 0xE1, 0x96, 0x78, 0x14, 0x1E, + 0x7F, 0xF7, 0x81, 0x20, 0x20, 0x7E, 0x7F, 0xDC, 0x80, 0x01, 0x04, 0x2E, 0x7F, 0xF2, 0x02, 0x15, + 0x00, 0x00, 0x38, 0x01, 0x01, 0x01, 0x9A, 0x08, 0x12, 0x05, 0x00, 0x00, 0x04, 0x0E, 0x7F, 0xF1, + 0x50, 0x34, 0x00, 0x01, 0x54, 0x81, 0x80, 0xFF, 0x89, 0x40, 0xD5, 0xCF, 0x04, 0x0E, 0x7F, 0xF4, + 0x8C, 0xC1, 0x8C, 0x02, 0x97, 0xB0, 0xEA, 0xF3, 0xD5, 0xBB, 0xEA, 0xF3, 0xEB, 0x50, 0x48, 0xFF, + 0xFE, 0x54, 0x4C, 0x04, 0xFE, 0x52, 0xEB, 0x53, 0x48, 0xFF, 0xFE, 0x4F, 0x4C, 0x04, 0xFF, 0xDF, + 0xEB, 0x53, 0xD5, 0xDC, 0x14, 0x0E, 0x7F, 0xF5, 0xEB, 0x50, 0xD5, 0xD8, 0xEB, 0x86, 0xFC, 0xC0, + 0x84, 0x00, 0x3E, 0x07, 0xF2, 0x2E, 0x3E, 0x07, 0xED, 0xC1, 0xDD, 0x9E, 0x2E, 0x17, 0xF2, 0x2F, + 0xC1, 0x03, 0x3E, 0x07, 0xF2, 0x2E, 0xDD, 0x9E, 0xEA, 0xAF, 0xC0, 0x13, 0x84, 0x01, 0x3E, 0x07, + 0xED, 0xC1, 0xEA, 0xAF, 0x5A, 0x08, 0x07, 0x0E, 0xFC, 0x00, 0x84, 0x01, 0x44, 0x22, 0x4B, 0x12, + 0x3C, 0x08, 0x0B, 0x57, 0x44, 0x02, 0x4A, 0x0C, 0x9C, 0x42, 0x9C, 0xD2, 0xEA, 0x3D, 0xFC, 0x80, + 0xDD, 0x9E, 0xFC, 0x40, 0x3C, 0x13, 0xF8, 0x07, 0x3C, 0x1B, 0xF6, 0x0F, 0x3C, 0x13, 0xF8, 0x05, + 0x3C, 0x1B, 0xF6, 0x0A, 0x84, 0x20, 0x3E, 0x17, 0xED, 0xC0, 0x2E, 0x17, 0xEE, 0x19, 0xC1, 0x07, + 0x84, 0x01, 0x3E, 0x07, 0xED, 0xC0, 0x84, 0x28, 0x84, 0x02, 0xD5, 0x2F, 0x2E, 0x27, 0xD9, 0x44, + 0x5A, 0x20, 0xFF, 0x0C, 0xEA, 0x49, 0xEA, 0x94, 0x42, 0x11, 0x0C, 0x73, 0xEA, 0xE8, 0x5A, 0x10, + 0x02, 0x05, 0x84, 0x3F, 0x3E, 0x17, 0xD9, 0x44, 0x2E, 0x27, 0xD9, 0x45, 0x5A, 0x28, 0xFF, 0x38, + 0x84, 0x60, 0x2E, 0x66, 0xF3, 0xC0, 0x2E, 0x27, 0xD9, 0x44, 0x2E, 0x47, 0xD9, 0x45, 0x80, 0x23, + 0x44, 0x70, 0x01, 0x0C, 0xEB, 0x1B, 0x97, 0x58, 0xE2, 0xA6, 0xE9, 0x34, 0x3E, 0x27, 0xD9, 0x44, + 0x3E, 0x47, 0xD9, 0x45, 0xAE, 0x40, 0xC1, 0x13, 0x2E, 0x27, 0xD9, 0x44, 0xE2, 0x46, 0xE9, 0x08, + 0xE6, 0x23, 0xE9, 0x3C, 0x84, 0x05, 0x84, 0x22, 0xEA, 0x72, 0x84, 0x02, 0xD5, 0x09, 0xEA, 0x49, + 0xEA, 0x45, 0xEB, 0xBA, 0x00, 0x00, 0x00, 0xEB, 0x5A, 0x00, 0x02, 0xF4, 0x84, 0x00, 0x84, 0x3F, + 0x3E, 0x17, 0xD9, 0x44, 0x3E, 0x17, 0xD9, 0x45, 0x84, 0x3F, 0x3C, 0x1F, 0xFB, 0x5C, 0x3C, 0x1F, + 0xFB, 0x5F, 0x3C, 0x1F, 0xFB, 0x5E, 0x3C, 0x1F, 0xFB, 0x5D, 0xFC, 0xC0, 0xEA, 0x49, 0xEA, 0x94, + 0x42, 0x11, 0x0C, 0x73, 0xEA, 0xE8, 0x5A, 0x10, 0x02, 0xC5, 0x84, 0x3F, 0x3E, 0x17, 0xD9, 0x45, + 0xD5, 0xC0, 0x81, 0x49, 0x42, 0xA1, 0x9C, 0x73, 0x00, 0xA5, 0x00, 0xEB, 0x5A, 0xA8, 0x02, 0x0D, + 0x8C, 0x21, 0x96, 0x48, 0x5A, 0x20, 0xFF, 0x07, 0x5A, 0x48, 0xFF, 0x07, 0xD2, 0x05, 0x80, 0x85, + 0xD5, 0x03, 0x80, 0x82, 0x80, 0x45, 0x8C, 0x61, 0xD5, 0xB7, 0xEA, 0x45, 0xEA, 0x76, 0x80, 0x60, + 0x42, 0x31, 0x04, 0x73, 0x80, 0x43, 0x22, 0x31, 0x80, 0x1D, 0x22, 0x21, 0x00, 0x1E, 0x3C, 0x2F, + 0xFB, 0x5F, 0x2E, 0x27, 0xD9, 0x45, 0x3C, 0x3F, 0xFB, 0x5C, 0xE2, 0x46, 0xE8, 0x0D, 0xEA, 0xB1, + 0x00, 0x10, 0x00, 0xEB, 0x5A, 0x18, 0x02, 0x09, 0x22, 0x10, 0x00, 0x1D, 0x3C, 0x1F, 0xFB, 0x5E, + 0x22, 0x00, 0x00, 0x1E, 0xD5, 0x04, 0x84, 0x1F, 0x3C, 0x0F, 0xFB, 0x5E, 0x3C, 0x0F, 0xFB, 0x5D, + 0x84, 0x01, 0xFC, 0xC0, 0x84, 0x00, 0x3E, 0x07, 0xED, 0xC3, 0x3E, 0x07, 0xED, 0xC2, 0xDD, 0x9E, + 0xFC, 0x00, 0x84, 0x00, 0x3E, 0x07, 0xED, 0xCA, 0x3E, 0x07, 0xED, 0xC8, 0x84, 0x20, 0x84, 0x08, + 0xDD, 0x47, 0x84, 0x0A, 0x84, 0x20, 0xDD, 0x47, 0x49, 0xFF, 0xFF, 0xEE, 0xFC, 0x80, 0x3C, 0x23, + 0xEC, 0x32, 0xE0, 0x02, 0xE9, 0x0E, 0x3C, 0x23, 0xEC, 0x34, 0xE0, 0x40, 0xE9, 0x0A, 0x3C, 0x03, + 0xEC, 0x33, 0xE0, 0x20, 0xE9, 0x06, 0x3C, 0x03, 0xEC, 0x35, 0x40, 0x00, 0x04, 0x07, 0xDD, 0x9E, + 0x84, 0x01, 0xDD, 0x9E, 0xFC, 0x41, 0x81, 0x00, 0x3C, 0x03, 0xEC, 0x55, 0x80, 0xE1, 0xF0, 0x81, + 0x84, 0x04, 0x80, 0xC2, 0x83, 0x83, 0x3C, 0x93, 0xEC, 0x53, 0xEA, 0x32, 0x81, 0x40, 0x5A, 0x08, + 0x01, 0x0E, 0x84, 0x04, 0x84, 0x20, 0xDD, 0x47, 0x84, 0x04, 0xEB, 0x30, 0xEA, 0xAF, 0x5A, 0x00, + 0x04, 0x05, 0x84, 0x07, 0x80, 0x2A, 0xEA, 0x72, 0xEA, 0x8D, 0x5B, 0xC0, 0x02, 0x63, 0x9E, 0x31, + 0xE6, 0x02, 0xE8, 0x62, 0x2E, 0x07, 0xED, 0xC7, 0x5A, 0x00, 0x01, 0x1A, 0xC0, 0x05, 0xE6, 0x04, + 0x4E, 0xF2, 0x00, 0xA3, 0xD5, 0x3E, 0x84, 0x01, 0x3E, 0x07, 0xED, 0xC8, 0x3C, 0x13, 0xEC, 0x50, + 0x84, 0x09, 0x3C, 0x8B, 0xF6, 0xDF, 0x3C, 0x7B, 0xF6, 0xDE, 0xEA, 0x31, 0x84, 0x04, 0x84, 0x20, + 0xDD, 0x47, 0x84, 0x09, 0x84, 0x21, 0xDD, 0x47, 0x84, 0x02, 0xD5, 0x44, 0x3C, 0x67, 0xF6, 0xDF, + 0x3C, 0x8B, 0xF6, 0xDD, 0x8A, 0xC8, 0x3C, 0x7B, 0xF6, 0xDC, 0x4E, 0x64, 0x00, 0x03, 0xFF, 0xB2, + 0x3C, 0x07, 0xF6, 0xDE, 0x9B, 0xC7, 0x4E, 0x74, 0x00, 0x03, 0xFF, 0xFA, 0x84, 0x04, 0x84, 0x20, + 0xFF, 0xB4, 0xDD, 0x47, 0x42, 0x63, 0x9C, 0x73, 0x42, 0x04, 0xA4, 0x24, 0xE0, 0x06, 0x84, 0x03, + 0xE8, 0x29, 0x3C, 0x03, 0xF6, 0xDD, 0x3C, 0x0B, 0xF6, 0xDF, 0x3C, 0x03, 0xF6, 0xDC, 0x3C, 0x0B, + 0xF6, 0xDE, 0x84, 0x02, 0x84, 0x21, 0xEB, 0x30, 0x84, 0x04, 0xEA, 0x72, 0xEA, 0x8D, 0xD5, 0x64, + 0x3C, 0x27, 0xF6, 0xDF, 0x40, 0x01, 0x20, 0x01, 0x4E, 0x04, 0x00, 0x03, 0xFE, 0x02, 0x3C, 0x17, + 0xF6, 0xDE, 0x9B, 0xCF, 0x4E, 0x74, 0x00, 0x03, 0xFF, 0xFA, 0x22, 0x1F, 0x80, 0x02, 0xFE, 0x04, + 0x42, 0x03, 0x9C, 0x73, 0xFE, 0x4C, 0xE0, 0x20, 0xE8, 0x4F, 0x84, 0x03, 0x3E, 0x07, 0xED, 0xC8, + 0x84, 0x04, 0xEB, 0x30, 0xD5, 0x49, 0xCE, 0xFD, 0x2E, 0x07, 0xED, 0xC7, 0x5A, 0x08, 0x02, 0x14, + 0x84, 0x09, 0xEA, 0x32, 0x80, 0x20, 0x5A, 0x08, 0x01, 0x06, 0x84, 0x08, 0xEA, 0x72, 0xEA, 0x8D, + 0xD5, 0x32, 0x84, 0x04, 0x3C, 0x13, 0xEC, 0x4E, 0xEA, 0x31, 0x84, 0x04, 0x84, 0x21, 0xDD, 0x47, + 0x84, 0x01, 0xD5, 0x2A, 0x5A, 0x08, 0x01, 0x11, 0x84, 0x04, 0xEA, 0x32, 0x80, 0xE0, 0x5A, 0x08, + 0x01, 0x2C, 0x84, 0x04, 0x80, 0x26, 0xDD, 0x47, 0xEA, 0xAF, 0x5A, 0x00, 0x04, 0xDB, 0x84, 0x07, + 0x80, 0x27, 0xEA, 0x72, 0xD5, 0xD6, 0x5A, 0x08, 0x03, 0x1A, 0x3C, 0x07, 0xF6, 0xDF, 0x3C, 0x17, + 0xF6, 0xDE, 0x49, 0xFF, 0xFF, 0x3E, 0x5A, 0x00, 0x01, 0x0B, 0x3C, 0x07, 0xF6, 0xDD, 0x3C, 0x17, + 0xF6, 0xDC, 0x49, 0xFF, 0xFF, 0x36, 0x84, 0xC1, 0x5A, 0x08, 0x01, 0x06, 0x84, 0x06, 0x84, 0x21, + 0xEA, 0x72, 0x84, 0xC0, 0x84, 0x04, 0xEB, 0x30, 0xD5, 0x08, 0x5A, 0x08, 0x04, 0x06, 0xEA, 0x8D, + 0x3E, 0x67, 0xED, 0xC7, 0xD5, 0x02, 0x84, 0xC0, 0x2E, 0x07, 0xED, 0xC7, 0x5A, 0x08, 0x04, 0x07, + 0x84, 0x20, 0xDD, 0x47, 0x84, 0x09, 0x84, 0x20, 0xDD, 0x47, 0x80, 0x06, 0xFC, 0xC1, 0xFC, 0x41, + 0x85, 0x40, 0x81, 0x20, 0x50, 0x0F, 0x80, 0x07, 0x10, 0xAF, 0x80, 0x07, 0x49, 0xFF, 0xFE, 0x5B, + 0x80, 0xE0, 0x3E, 0x07, 0xED, 0xC9, 0x3C, 0x17, 0xF6, 0xBE, 0x3C, 0x07, 0xF6, 0xB8, 0x00, 0x2F, + 0x80, 0x07, 0x80, 0x67, 0x49, 0xFF, 0xFF, 0x18, 0x80, 0xC0, 0xC0, 0x09, 0x2E, 0x07, 0xED, 0xC9, + 0x3E, 0x07, 0xED, 0xB7, 0x10, 0xA4, 0x80, 0x00, 0x84, 0x01, 0xFC, 0xC1, 0x2E, 0x17, 0xED, 0xCA, + 0x5A, 0x18, 0x02, 0x07, 0x4E, 0x73, 0x00, 0x99, 0xEA, 0x8D, 0x48, 0x00, 0x00, 0x92, 0xC9, 0x30, + 0x2E, 0x67, 0xED, 0xB7, 0x4E, 0x63, 0x00, 0x90, 0x2E, 0x77, 0xED, 0xC9, 0x5A, 0x78, 0x01, 0x1D, + 0x49, 0x00, 0x02, 0xD0, 0x49, 0x00, 0x02, 0xD6, 0x84, 0x0A, 0x3C, 0x13, 0xEC, 0x4F, 0xEA, 0x31, + 0x84, 0x08, 0x3C, 0x13, 0xEC, 0x51, 0xEA, 0x31, 0x80, 0x27, 0x84, 0x0A, 0xDD, 0x47, 0x80, 0x27, + 0x84, 0x08, 0xDD, 0x47, 0x3C, 0x07, 0xF6, 0xB8, 0x3C, 0x17, 0xF6, 0xBE, 0x00, 0x2F, 0x80, 0x07, + 0x49, 0x00, 0x02, 0xD5, 0xD5, 0x0A, 0x5A, 0x78, 0x02, 0x70, 0x84, 0x0A, 0x3C, 0x13, 0xEC, 0x4F, + 0xEA, 0x31, 0x84, 0x0A, 0x84, 0x21, 0xDD, 0x47, 0x3E, 0x77, 0xED, 0xCA, 0xD5, 0x65, 0x5A, 0x18, + 0x01, 0x64, 0x2E, 0x77, 0xED, 0xC9, 0xCF, 0x4F, 0x2E, 0x07, 0xED, 0xC8, 0x5A, 0x08, 0x03, 0x59, + 0x2E, 0x07, 0xED, 0xB7, 0x5A, 0x08, 0x01, 0x38, 0x49, 0xFF, 0xFD, 0xDC, 0x84, 0x08, 0xEA, 0x32, + 0xC0, 0x03, 0x84, 0xC0, 0xD5, 0x2E, 0x80, 0x09, 0x49, 0x00, 0x04, 0xFE, 0x5A, 0x00, 0x01, 0x1F, + 0x5A, 0x08, 0x02, 0x1B, 0xFA, 0x08, 0x10, 0x04, 0x80, 0x00, 0x3C, 0x04, 0x0A, 0xC6, 0xEB, 0xF0, + 0x3C, 0x13, 0xEC, 0x54, 0xFE, 0x04, 0x42, 0x01, 0x08, 0x73, 0xFE, 0x4C, 0xE0, 0x20, 0xE8, 0x09, + 0x2E, 0x67, 0xF2, 0x2E, 0x97, 0xB0, 0xCE, 0x08, 0x84, 0x01, 0x80, 0x20, 0xEA, 0x72, 0xD5, 0x07, + 0x84, 0x03, 0x84, 0x21, 0xEA, 0x72, 0x84, 0xC0, 0xD5, 0x02, 0x80, 0xC0, 0x2E, 0x07, 0xED, 0xC3, + 0xC0, 0x08, 0x80, 0x09, 0x49, 0x00, 0x0A, 0xDA, 0xC0, 0xD5, 0xFA, 0x04, 0x10, 0x04, 0x80, 0x00, + 0xEB, 0xB0, 0xD5, 0x0C, 0x5A, 0x08, 0x02, 0x04, 0xEA, 0x8D, 0xD5, 0x07, 0x84, 0x08, 0x80, 0x27, + 0xDD, 0x47, 0x84, 0x0A, 0x80, 0x27, 0xDD, 0x47, 0x80, 0xC7, 0x80, 0x09, 0x49, 0x00, 0x0A, 0xF1, + 0xEA, 0x8D, 0xD5, 0x12, 0x5A, 0x78, 0x01, 0x0B, 0x3C, 0x07, 0xF6, 0xB8, 0x3C, 0x17, 0xF6, 0xBE, + 0x00, 0x2F, 0x80, 0x07, 0x49, 0x00, 0x02, 0x6B, 0xD5, 0x07, 0x5A, 0x70, 0x02, 0x9F, 0xEB, 0xB0, + 0x84, 0xC0, 0xD5, 0x02, 0x80, 0xC1, 0x84, 0x0A, 0xEA, 0x32, 0x5A, 0x00, 0x01, 0x05, 0xDD, 0x46, + 0xEA, 0xDF, 0xC0, 0x26, 0x2E, 0x07, 0xED, 0xC9, 0xC0, 0x08, 0x2E, 0x00, 0x15, 0x49, 0x3C, 0xF7, + 0xF8, 0x07, 0x8C, 0x1D, 0xE0, 0x0F, 0xE9, 0x03, 0xEB, 0xB0, 0xD5, 0x0A, 0x2E, 0x00, 0x14, 0x90, + 0x5A, 0x08, 0x02, 0x0C, 0x84, 0x0A, 0xEA, 0x7A, 0x84, 0x00, 0x3E, 0x00, 0x14, 0x90, 0xDD, 0x4F, + 0x44, 0x0F, 0xEF, 0xFF, 0xFE, 0x0E, 0xD5, 0x0B, 0x84, 0x0A, 0xEA, 0x32, 0x5A, 0x08, 0x01, 0x09, + 0x3C, 0x03, 0xF6, 0x0F, 0x3C, 0x0B, 0xF6, 0x0B, 0xDD, 0x46, 0xEB, 0x75, 0xEA, 0x23, 0x2E, 0x07, + 0xED, 0xC9, 0x3E, 0x07, 0xED, 0xB7, 0x80, 0x06, 0xFC, 0xC1, 0xFC, 0x00, 0x44, 0x51, 0x28, 0x40, + 0x84, 0x60, 0x96, 0x98, 0x0A, 0x62, 0x80, 0x01, 0x5A, 0x20, 0x10, 0x07, 0xE2, 0x26, 0xA5, 0x28, + 0xE9, 0x19, 0x81, 0xE4, 0xD5, 0x04, 0xE2, 0x26, 0xE9, 0x1B, 0x85, 0xFF, 0xE2, 0x2F, 0xE8, 0x12, + 0x5A, 0x08, 0x01, 0x06, 0x52, 0x01, 0x80, 0x40, 0x96, 0x2F, 0xFC, 0x80, 0x5A, 0x08, 0x02, 0x05, + 0x50, 0x01, 0x00, 0x20, 0xD5, 0x05, 0x5A, 0x08, 0x03, 0x0A, 0x52, 0x01, 0x00, 0x20, 0x96, 0x00, + 0xFC, 0x80, 0x8C, 0x61, 0x5A, 0x38, 0x11, 0xDF, 0xD5, 0x03, 0x80, 0x02, 0xFC, 0x80, 0xEA, 0xF0, + 0xFC, 0x80, 0xC8, 0x2B, 0x3C, 0x34, 0x0A, 0xCA, 0x3C, 0xF4, 0x0A, 0xCC, 0x3C, 0x00, 0x0B, 0x45, + 0xE0, 0x6F, 0x3C, 0x30, 0x0B, 0x46, 0xE8, 0x06, 0x3C, 0x08, 0x0B, 0x4D, 0x3C, 0x38, 0x0B, 0x4F, + 0xD5, 0x05, 0x3C, 0x38, 0x0B, 0x4D, 0x3C, 0x08, 0x0B, 0x4F, 0x3C, 0x04, 0x0B, 0x51, 0x3C, 0x30, + 0x0B, 0x4F, 0x3C, 0x18, 0x0B, 0x4E, 0x3C, 0x18, 0x0B, 0x50, 0xEA, 0xAD, 0x3C, 0x00, 0x0B, 0x4D, + 0x97, 0x1B, 0x97, 0x43, 0xE0, 0xA4, 0xEA, 0xED, 0x81, 0xE3, 0x40, 0x00, 0xBC, 0x00, 0x3C, 0x08, + 0x0A, 0xE8, 0x3C, 0x28, 0x0A, 0xE9, 0xDD, 0x9E, 0x3C, 0x34, 0x0A, 0xCB, 0x3C, 0xF4, 0x0A, 0xCD, + 0x3C, 0x00, 0x0B, 0x47, 0xE0, 0x6F, 0x3C, 0x30, 0x0B, 0x48, 0xE8, 0x06, 0x3C, 0x08, 0x0B, 0x4E, + 0x3C, 0x38, 0x0B, 0x50, 0xD5, 0x04, 0xEB, 0xD0, 0x3C, 0x08, 0x0B, 0x50, 0x3C, 0x04, 0x0B, 0x52, + 0x3C, 0x30, 0x0B, 0x50, 0x3C, 0x18, 0x0B, 0x4D, 0x3C, 0x18, 0x0B, 0x4F, 0xEA, 0xAD, 0x3C, 0x00, + 0x0B, 0x4E, 0x97, 0x1B, 0x97, 0x43, 0xE0, 0xA4, 0xEA, 0xED, 0x81, 0xE3, 0x40, 0x00, 0xBC, 0x00, + 0x3C, 0x08, 0x0A, 0xE9, 0x3C, 0x28, 0x0A, 0xE8, 0xDD, 0x9E, 0xFC, 0x44, 0xF1, 0x81, 0x3C, 0x63, + 0x79, 0xE2, 0xB0, 0x47, 0x12, 0x6F, 0x80, 0x0E, 0xF3, 0x82, 0x2E, 0x66, 0xF3, 0xC6, 0xAF, 0x8A, + 0xC2, 0x69, 0x9F, 0xC1, 0x9D, 0xA9, 0xB6, 0xFF, 0xFF, 0x6B, 0xF5, 0x84, 0x00, 0x5F, 0x80, 0x00, + 0x54, 0x93, 0x00, 0xFF, 0x84, 0xC0, 0x81, 0x46, 0x83, 0xC6, 0xF5, 0x85, 0x80, 0x61, 0x97, 0x70, + 0xE2, 0xA0, 0xE8, 0x4E, 0xB4, 0x3F, 0x8A, 0x26, 0xE0, 0xC1, 0x40, 0x13, 0x3C, 0x1B, 0x96, 0x48, + 0xE2, 0x29, 0xE8, 0x0D, 0x40, 0x13, 0x24, 0x01, 0x4E, 0x14, 0x00, 0x03, 0x84, 0x20, 0x40, 0x73, + 0x24, 0x00, 0xE0, 0xE0, 0x96, 0x48, 0xE9, 0x06, 0xF5, 0x05, 0xD5, 0x06, 0xF1, 0x04, 0x88, 0x25, + 0x96, 0x48, 0x88, 0xA9, 0x97, 0x68, 0x97, 0xF0, 0x44, 0x8F, 0x80, 0x00, 0x87, 0x80, 0xF7, 0x83, + 0xE2, 0xA1, 0xE9, 0x2A, 0x04, 0xFF, 0x80, 0x03, 0xF7, 0x01, 0x38, 0x73, 0xBC, 0x00, 0x04, 0xFF, + 0x80, 0x02, 0x38, 0xF7, 0x84, 0x00, 0x8A, 0xEF, 0x97, 0xEF, 0x5C, 0xF3, 0x80, 0x21, 0xE9, 0x04, + 0x52, 0x73, 0x80, 0x40, 0x97, 0xF8, 0x38, 0xF2, 0x1D, 0x11, 0x9B, 0xCE, 0x4E, 0x74, 0x00, 0x03, + 0xFF, 0xFA, 0x38, 0x71, 0x9C, 0x00, 0x42, 0x77, 0x9C, 0x24, 0x90, 0xE7, 0x97, 0xFB, 0xE1, 0x07, + 0xE8, 0x08, 0x40, 0xF0, 0xF8, 0x01, 0x4E, 0xF5, 0x00, 0x05, 0x41, 0xC0, 0x80, 0x10, 0x81, 0x07, + 0x8C, 0x21, 0x96, 0x48, 0xD5, 0xD6, 0x89, 0x48, 0x8C, 0xC1, 0x83, 0xDC, 0xD5, 0xB1, 0x40, 0x25, + 0x08, 0x56, 0x4E, 0x25, 0x00, 0x0A, 0x5E, 0xF1, 0x00, 0x65, 0xE9, 0x02, 0xEA, 0xE5, 0x96, 0x10, + 0xFC, 0xC4, 0x80, 0x02, 0xFC, 0xC4, 0x84, 0x00, 0xFC, 0xC4, 0xFC, 0x40, 0x2E, 0x97, 0xD9, 0x48, + 0x84, 0xA0, 0xFB, 0x48, 0x44, 0x82, 0x0D, 0xC8, 0x97, 0xA8, 0xE2, 0xC9, 0xE8, 0x11, 0x38, 0x71, + 0x14, 0x00, 0xE2, 0xE0, 0xE9, 0x0B, 0x81, 0xE8, 0x42, 0xF2, 0xA8, 0x73, 0x00, 0xF7, 0x80, 0x04, + 0x4C, 0xF0, 0xC0, 0x05, 0xAF, 0xD8, 0xAF, 0xA0, 0xFC, 0xC0, 0x8C, 0xA1, 0xD5, 0xEE, 0xFC, 0xC0, + 0xE0, 0x20, 0xE8, 0x04, 0xE0, 0x40, 0xE9, 0x06, 0xDD, 0x9E, 0xE0, 0x01, 0xE8, 0x05, 0xE0, 0x02, + 0xE8, 0x03, 0x84, 0x01, 0xAE, 0x18, 0xDD, 0x9E, 0xFC, 0x44, 0x81, 0x20, 0x22, 0x00, 0x80, 0x00, + 0x41, 0xC2, 0x93, 0x96, 0x12, 0x04, 0x80, 0x00, 0x22, 0x00, 0x80, 0x01, 0x81, 0x01, 0x12, 0x04, + 0x80, 0x01, 0x84, 0x01, 0xAE, 0x18, 0xDD, 0x4C, 0x42, 0x0E, 0x00, 0x24, 0x81, 0x41, 0xF2, 0x83, + 0x80, 0xE3, 0xF0, 0x81, 0x84, 0x20, 0x84, 0xC1, 0xF0, 0x03, 0xE2, 0xC0, 0xE8, 0x6F, 0x22, 0x25, + 0x00, 0x00, 0x22, 0x05, 0x00, 0x02, 0xF1, 0x82, 0x8A, 0x02, 0xF0, 0x84, 0x22, 0x25, 0x00, 0x01, + 0x22, 0x05, 0x00, 0x03, 0x8A, 0x02, 0xF0, 0x85, 0xB0, 0x04, 0xDD, 0x4D, 0xF1, 0x02, 0x80, 0xA0, + 0x98, 0xC1, 0xE0, 0x7C, 0xE9, 0x56, 0xEA, 0xE5, 0x40, 0x1E, 0x04, 0x01, 0xFE, 0x54, 0xEA, 0x53, + 0xF3, 0x05, 0xF0, 0x04, 0xFE, 0x0C, 0xFE, 0x5C, 0xEA, 0xA6, 0xEB, 0xB8, 0xA6, 0xB8, 0xF0, 0x86, + 0xE6, 0x55, 0xF1, 0x87, 0xE8, 0x10, 0x02, 0x35, 0x00, 0x00, 0x88, 0x03, 0x38, 0x04, 0x8A, 0x09, + 0xA6, 0x38, 0x02, 0x25, 0x00, 0x01, 0x94, 0x02, 0x88, 0x09, 0x88, 0x22, 0xAC, 0x41, 0xA6, 0x38, + 0x8C, 0x01, 0xAE, 0x38, 0xB0, 0x06, 0xF5, 0x82, 0xDD, 0x4D, 0xF5, 0x02, 0x05, 0xEF, 0x80, 0x04, + 0x9A, 0xE8, 0xF0, 0x05, 0xF4, 0x06, 0xF0, 0x82, 0xF2, 0x07, 0xDD, 0x4C, 0xE0, 0x7C, 0xE9, 0x27, + 0xF1, 0x01, 0x40, 0x20, 0x94, 0x56, 0xF1, 0x02, 0x42, 0x4F, 0x08, 0x24, 0xFE, 0x8C, 0xA6, 0x78, + 0x40, 0x42, 0x00, 0x96, 0xE6, 0x35, 0x40, 0x21, 0x00, 0x56, 0xE8, 0x17, 0x40, 0xF0, 0x88, 0x08, + 0x40, 0xF4, 0xBC, 0x00, 0x02, 0xF7, 0xFF, 0xFE, 0x40, 0xF2, 0x3C, 0x00, 0x38, 0xF4, 0x86, 0x09, + 0xA6, 0x78, 0x94, 0x4A, 0x88, 0x29, 0x02, 0xF0, 0xFF, 0xFF, 0x40, 0xF1, 0x3C, 0x00, 0x12, 0xF0, + 0x80, 0x01, 0xA6, 0x78, 0x8C, 0x21, 0xAE, 0x78, 0x8A, 0x7C, 0xD5, 0xD9, 0xF4, 0x86, 0xF2, 0x87, + 0x8C, 0xC1, 0x97, 0xB1, 0x8D, 0x44, 0x80, 0x23, 0xD5, 0x90, 0xC1, 0x14, 0x46, 0x03, 0xFF, 0xFF, + 0xDD, 0x42, 0x88, 0xC0, 0xA6, 0x78, 0x95, 0xB2, 0x89, 0x06, 0x88, 0x20, 0x22, 0x24, 0x00, 0x00, + 0x38, 0x24, 0x86, 0x09, 0xA6, 0xB8, 0xEB, 0x70, 0x88, 0x02, 0x94, 0x02, 0x89, 0x20, 0x12, 0x14, + 0x80, 0x01, 0xFC, 0xC4, 0xFC, 0x41, 0x80, 0xE2, 0x3C, 0x24, 0x0A, 0xCA, 0x81, 0x40, 0x8A, 0x40, + 0xB6, 0x5F, 0x3C, 0x24, 0x0A, 0xCB, 0x80, 0x1F, 0x8A, 0x41, 0x81, 0x21, 0xF2, 0x81, 0xDD, 0x4D, + 0xEB, 0xFF, 0x80, 0xC0, 0x40, 0x01, 0x28, 0x01, 0xB6, 0x1F, 0x3C, 0x04, 0x0A, 0xCD, 0x40, 0x10, + 0x24, 0x01, 0x80, 0x1F, 0xF1, 0x81, 0xDD, 0x4D, 0xE0, 0xC0, 0xE8, 0x04, 0x80, 0x26, 0x80, 0xC0, + 0x80, 0x01, 0x44, 0x10, 0x00, 0xB4, 0xEB, 0x23, 0xFE, 0x44, 0x40, 0x10, 0xBC, 0x36, 0xE0, 0x26, + 0xE9, 0x04, 0x5E, 0xF0, 0x07, 0xD0, 0xE8, 0x03, 0x84, 0x01, 0xAE, 0x38, 0xFC, 0xC1, 0xFC, 0x00, + 0xFE, 0x02, 0x4E, 0x17, 0x00, 0x0E, 0x4E, 0x05, 0x00, 0x07, 0x44, 0x20, 0x03, 0xE8, 0xFE, 0x84, + 0x84, 0x01, 0xD5, 0x0D, 0x44, 0x2F, 0xFC, 0x18, 0xFE, 0x84, 0x84, 0x04, 0xD5, 0x08, 0xC1, 0x11, + 0x4E, 0x05, 0x00, 0x0B, 0x44, 0x2F, 0xFC, 0x18, 0xFE, 0x84, 0x84, 0x02, 0x40, 0x11, 0x04, 0x36, + 0x49, 0xFF, 0xFD, 0xFD, 0xFC, 0x80, 0x44, 0x20, 0x03, 0xE8, 0xFE, 0x84, 0x84, 0x03, 0xD5, 0xF7, + 0xC0, 0x07, 0x4E, 0x06, 0x00, 0x04, 0xFA, 0x00, 0xFC, 0x80, 0x44, 0x00, 0x00, 0x30, 0xFC, 0x80, + 0xFC, 0x00, 0x84, 0x20, 0x44, 0x20, 0x00, 0xE4, 0x44, 0x02, 0x4A, 0x48, 0xDD, 0x40, 0xFC, 0x80, + 0xFC, 0x20, 0x44, 0x62, 0x4B, 0x48, 0x84, 0x20, 0xEA, 0xDE, 0xEB, 0xC7, 0xDD, 0x40, 0x84, 0xE0, + 0xB4, 0x06, 0x84, 0x20, 0x44, 0x20, 0x04, 0xB0, 0xAD, 0xF2, 0xDD, 0x40, 0xA0, 0x32, 0x84, 0x20, + 0x44, 0x20, 0x00, 0xA0, 0xAD, 0xF6, 0xDD, 0x40, 0xFC, 0xA0, 0xFC, 0x41, 0x81, 0x40, 0x3C, 0x00, + 0x0B, 0x6A, 0x81, 0x21, 0x5C, 0xF0, 0x01, 0x2C, 0x80, 0xE2, 0xE8, 0x0C, 0x2E, 0x17, 0xED, 0xC3, + 0x5A, 0x18, 0x01, 0x06, 0x5A, 0x28, 0x01, 0x04, 0x48, 0x00, 0x00, 0x87, 0x8C, 0x01, 0x3C, 0x08, + 0x0B, 0x6A, 0x5A, 0x70, 0x02, 0x04, 0x48, 0x00, 0x00, 0x80, 0x3C, 0x60, 0x0B, 0x6E, 0x84, 0x01, + 0x5C, 0xF3, 0x00, 0x28, 0x3E, 0x07, 0xED, 0xC3, 0xE8, 0x0D, 0xCE, 0x08, 0xEB, 0xC7, 0x80, 0x26, + 0xEA, 0xDE, 0xDD, 0x40, 0x84, 0x01, 0x3C, 0x08, 0x0B, 0x6A, 0x8C, 0xC1, 0x3C, 0x68, 0x0B, 0x6E, + 0xD5, 0x0E, 0x3C, 0x1C, 0x05, 0xB6, 0x95, 0xB2, 0x8E, 0xC8, 0x98, 0x0E, 0x8C, 0xC4, 0x88, 0xC1, + 0x22, 0x13, 0x00, 0x00, 0xAC, 0x40, 0x22, 0x13, 0x00, 0x01, 0xAC, 0x41, 0x3C, 0xF0, 0x0B, 0x6E, + 0x3C, 0x6C, 0x05, 0xB6, 0x40, 0x07, 0x88, 0x08, 0x3C, 0x8D, 0xFB, 0x5E, 0x3C, 0x5D, 0xFB, 0x5D, + 0x8E, 0x04, 0x98, 0x70, 0x40, 0x44, 0x00, 0x11, 0x96, 0xEB, 0xAD, 0x08, 0xAC, 0xC9, 0x40, 0x25, + 0x20, 0x01, 0x40, 0x14, 0x94, 0x01, 0x5A, 0xF8, 0x01, 0x12, 0x84, 0x00, 0x3C, 0x48, 0x0A, 0xCE, + 0x3C, 0x38, 0x0A, 0xCF, 0x3C, 0x2B, 0xF6, 0xED, 0x3C, 0x1B, 0xF6, 0xEC, 0x3E, 0xF7, 0xED, 0xC5, + 0x3E, 0xF7, 0xED, 0xC4, 0x3E, 0x07, 0xED, 0xC6, 0xD5, 0x2E, 0x3C, 0xF7, 0xF6, 0xED, 0x8A, 0x4F, + 0x4E, 0x24, 0x00, 0x05, 0x40, 0x24, 0x28, 0x01, 0x88, 0x4F, 0x3C, 0x83, 0xEC, 0x56, 0xE1, 0x02, + 0xE8, 0x04, 0x84, 0x40, 0x3E, 0x27, 0xED, 0xC5, 0x3C, 0x27, 0xF6, 0xEC, 0x8A, 0x22, 0x4E, 0x14, + 0x00, 0x05, 0x40, 0x12, 0xA4, 0x01, 0x88, 0x22, 0x3C, 0x23, 0xEC, 0x57, 0xE0, 0x41, 0xE8, 0x04, + 0x84, 0x20, 0x3E, 0x17, 0xED, 0xC4, 0x8E, 0x04, 0x88, 0x06, 0xEB, 0xCB, 0xEB, 0xB3, 0x8A, 0x81, + 0x8A, 0x60, 0x80, 0x1F, 0xB6, 0x9F, 0xF3, 0x81, 0xDD, 0x4D, 0x3C, 0x1C, 0x05, 0x61, 0x88, 0x01, + 0x3C, 0x0E, 0x05, 0x61, 0x3C, 0x0D, 0xFB, 0x5E, 0x3C, 0x08, 0x0A, 0xD0, 0x3C, 0x0D, 0xFB, 0x5D, + 0x3C, 0x08, 0x0A, 0xD1, 0xD5, 0x14, 0x2E, 0x07, 0xED, 0xC3, 0x5A, 0x08, 0x01, 0x11, 0x5A, 0x78, + 0x01, 0x0F, 0x2E, 0x07, 0xED, 0xC6, 0x2E, 0x17, 0xD8, 0xB1, 0xE2, 0x01, 0xE8, 0x05, 0x8C, 0x01, + 0x3E, 0x07, 0xED, 0xC6, 0xFC, 0xC1, 0x3E, 0x77, 0xED, 0xC2, 0xFC, 0xC1, 0x3C, 0x30, 0x0B, 0x6A, + 0x3C, 0x2C, 0x05, 0xB4, 0x94, 0x5A, 0x9E, 0x0C, 0x98, 0x50, 0x12, 0xA0, 0x80, 0x00, 0x12, 0x90, + 0x80, 0x01, 0x5A, 0x38, 0x01, 0x0F, 0x3C, 0xA8, 0x0A, 0xBA, 0x3C, 0xA8, 0x0A, 0xBB, 0x3C, 0x98, + 0x0A, 0xBC, 0x3C, 0x98, 0x0A, 0xBD, 0x3C, 0xA8, 0x0A, 0xCA, 0x3C, 0x98, 0x0A, 0xCB, 0xD5, 0x44, + 0x3C, 0xF4, 0x0A, 0xBA, 0xE1, 0x4F, 0xE8, 0x06, 0x3C, 0xA8, 0x0A, 0xBA, 0x3C, 0x98, 0x0A, 0xBE, + 0xD5, 0x09, 0x3C, 0x14, 0x0A, 0xBB, 0xE0, 0x2A, 0xE8, 0x05, 0x3C, 0xA8, 0x0A, 0xBB, 0x3C, 0x98, + 0x0A, 0xBF, 0x3C, 0xF4, 0x0A, 0xBC, 0xE1, 0x2F, 0xE8, 0x06, 0x3C, 0x98, 0x0A, 0xBC, 0x3C, 0xA8, + 0x0A, 0xC0, 0xD5, 0x09, 0x3C, 0x14, 0x0A, 0xBD, 0xE0, 0x29, 0xE8, 0x05, 0x3C, 0x98, 0x0A, 0xBD, + 0x3C, 0xA8, 0x0A, 0xC1, 0x8E, 0x04, 0x88, 0x02, 0xEB, 0xCB, 0xEB, 0xB3, 0x40, 0x15, 0x04, 0x01, + 0x40, 0x04, 0x80, 0x01, 0xB6, 0x3F, 0xF0, 0x81, 0x4E, 0x14, 0x00, 0x03, 0xFE, 0x4A, 0x3C, 0x20, + 0x0A, 0xC8, 0x88, 0x22, 0x3C, 0x18, 0x0A, 0xC8, 0x4E, 0x04, 0x00, 0x03, 0xFE, 0x02, 0x3C, 0x10, + 0x0A, 0xC9, 0x88, 0x01, 0x3C, 0x08, 0x0A, 0xC9, 0x80, 0x1F, 0xDD, 0x4D, 0x3C, 0x1C, 0x05, 0x62, + 0x88, 0x01, 0x3C, 0x0E, 0x05, 0x62, 0x5A, 0x78, 0x02, 0x28, 0x3C, 0x07, 0xF6, 0xBC, 0x3C, 0xF4, + 0x0A, 0xBA, 0x3C, 0x17, 0xF6, 0xBA, 0xE0, 0x0F, 0xE8, 0x06, 0x3C, 0x08, 0x0A, 0xBA, 0x3C, 0x18, + 0x0A, 0xBE, 0xD5, 0x09, 0x3C, 0x24, 0x0A, 0xBB, 0xE0, 0x40, 0xE8, 0x05, 0x3C, 0x08, 0x0A, 0xBB, + 0x3C, 0x18, 0x0A, 0xBF, 0x3C, 0xF4, 0x0A, 0xBC, 0xE0, 0x2F, 0xE8, 0x06, 0x3C, 0x18, 0x0A, 0xBC, + 0x3C, 0x08, 0x0A, 0xC0, 0xD5, 0x09, 0x3C, 0x24, 0x0A, 0xBD, 0xE0, 0x41, 0xE8, 0x05, 0x3C, 0x18, + 0x0A, 0xBD, 0x3C, 0x08, 0x0A, 0xC1, 0x3C, 0x10, 0x0A, 0xBA, 0x3C, 0x00, 0x0A, 0xBB, 0x3C, 0xA8, + 0x0A, 0xCC, 0x8A, 0x01, 0x3C, 0x08, 0x0A, 0xC6, 0x3C, 0x10, 0x0A, 0xBC, 0x3C, 0x00, 0x0A, 0xBD, + 0x3C, 0x98, 0x0A, 0xCD, 0x8A, 0x01, 0x3C, 0x08, 0x0A, 0xC7, 0xFC, 0xC1, 0xE2, 0x20, 0x80, 0x61, + 0x9A, 0x41, 0xEA, 0xED, 0x4E, 0x14, 0x00, 0x03, 0xFE, 0x4A, 0x96, 0x0A, 0x5E, 0xF0, 0x00, 0x21, + 0xE9, 0x07, 0x52, 0x10, 0x80, 0x40, 0x96, 0x0A, 0xEA, 0xAD, 0x88, 0x61, 0xD5, 0x03, 0xEA, 0xAD, + 0x8A, 0x61, 0x96, 0xDA, 0x96, 0xEF, 0xAE, 0xD0, 0xDD, 0x9E, 0xFC, 0x4D, 0x51, 0xCF, 0x80, 0x2C, + 0xF0, 0x82, 0xF1, 0x83, 0x80, 0xC2, 0x84, 0x20, 0x84, 0x4A, 0x80, 0x1C, 0xDD, 0x40, 0x84, 0x20, + 0xFA, 0x45, 0xB0, 0x0E, 0xDD, 0x40, 0xB0, 0x14, 0x84, 0x20, 0xFA, 0x45, 0xDD, 0x40, 0x5A, 0x60, + 0x05, 0x0E, 0x9E, 0x36, 0xE6, 0x02, 0xE9, 0x0F, 0x8E, 0xC8, 0xE6, 0xC2, 0x4E, 0xF2, 0x00, 0xCD, + 0x85, 0x00, 0xFB, 0x40, 0x44, 0x90, 0x00, 0x30, 0xD5, 0x0A, 0x85, 0x00, 0x44, 0xA0, 0x00, 0x30, + 0xFB, 0x20, 0xD5, 0x05, 0x44, 0xA0, 0x00, 0x30, 0x85, 0x01, 0x81, 0x2A, 0x46, 0x03, 0xFF, 0xFF, + 0xDD, 0x42, 0x84, 0xE0, 0x84, 0xC1, 0xF0, 0x85, 0x3C, 0x00, 0x0B, 0x6A, 0x8E, 0x01, 0xE0, 0xC0, + 0xE8, 0x6D, 0xF0, 0x05, 0x3C, 0x3C, 0x05, 0xB4, 0x98, 0xB0, 0x94, 0x92, 0x9C, 0x14, 0x98, 0x5A, + 0x88, 0x03, 0xF2, 0x89, 0x22, 0x50, 0x00, 0x01, 0x22, 0x40, 0x00, 0x00, 0x22, 0x00, 0x80, 0x01, + 0x22, 0x10, 0x80, 0x00, 0x8A, 0x05, 0x8A, 0x24, 0xF3, 0x88, 0xF5, 0x87, 0xF4, 0x86, 0xEA, 0xB9, + 0xF2, 0x09, 0xF3, 0x08, 0x8C, 0x48, 0xF0, 0x81, 0x88, 0x62, 0x20, 0x0F, 0x80, 0x04, 0xF5, 0x07, + 0xF4, 0x06, 0x22, 0x11, 0x80, 0x00, 0xF0, 0x84, 0x22, 0x01, 0x80, 0x01, 0x8A, 0x24, 0x8A, 0x05, + 0xEA, 0xB9, 0x97, 0x42, 0x80, 0x20, 0xEB, 0xD9, 0x84, 0x00, 0xF5, 0x86, 0xEB, 0x4C, 0x3C, 0x10, + 0x0B, 0x6A, 0xF5, 0x06, 0x8E, 0x22, 0xE0, 0xC1, 0xE8, 0x18, 0xE4, 0x03, 0xE8, 0x16, 0x8C, 0xC1, + 0x97, 0xB0, 0x3C, 0x2C, 0x05, 0xB4, 0x9C, 0x31, 0x94, 0x02, 0x98, 0x50, 0x8E, 0x04, 0x88, 0x40, + 0x22, 0x40, 0x80, 0x01, 0x22, 0x30, 0x80, 0x00, 0x22, 0x01, 0x00, 0x01, 0x22, 0x11, 0x00, 0x00, + 0x9A, 0x20, 0x9A, 0x59, 0xEA, 0xB9, 0x97, 0x42, 0x96, 0x68, 0xF0, 0x01, 0xEB, 0xD9, 0xF5, 0x81, + 0xEB, 0x4C, 0xB0, 0x4E, 0xF5, 0x01, 0x38, 0x00, 0x98, 0x08, 0xB0, 0x14, 0x00, 0x1F, 0x80, 0x2B, + 0xEB, 0x59, 0xF0, 0x04, 0x90, 0xA5, 0x90, 0x05, 0xD8, 0x33, 0x80, 0x09, 0x50, 0x2F, 0x80, 0x2A, + 0xEB, 0x4C, 0xE4, 0x10, 0xE8, 0x2D, 0x4E, 0x82, 0x00, 0x08, 0x50, 0x04, 0x80, 0x20, 0x54, 0x90, + 0x00, 0x3F, 0x85, 0x00, 0xD5, 0x25, 0xE4, 0xE3, 0xE9, 0x11, 0x96, 0x38, 0x88, 0x1C, 0x81, 0x07, + 0x00, 0x60, 0x7F, 0xFF, 0x3C, 0x00, 0x0B, 0x6A, 0x8C, 0xC1, 0x8E, 0x01, 0x97, 0xB0, 0x96, 0xC0, + 0x51, 0xCF, 0x80, 0x38, 0x50, 0x9F, 0x80, 0x50, 0xD5, 0x1D, 0x3C, 0x1C, 0x05, 0xB4, 0x94, 0x32, + 0x88, 0x01, 0xF2, 0x02, 0xA4, 0x40, 0x38, 0x6E, 0x1C, 0x08, 0x38, 0x11, 0x1D, 0x09, 0xF1, 0x03, + 0xA4, 0x01, 0xEA, 0xD0, 0x50, 0x04, 0x80, 0x20, 0x8C, 0xE1, 0x54, 0x90, 0x00, 0x3F, 0x8C, 0xC1, + 0x97, 0xB0, 0x48, 0xFF, 0xFF, 0x6B, 0x38, 0x0E, 0x18, 0x10, 0xE4, 0x18, 0xE9, 0x06, 0x8C, 0xC1, + 0x97, 0xB0, 0xE2, 0xC3, 0xE9, 0xF9, 0xD5, 0x15, 0x80, 0x0A, 0x38, 0x14, 0x98, 0x00, 0xEB, 0xD9, + 0xF3, 0x81, 0xEB, 0x4C, 0xE4, 0x0E, 0xF3, 0x01, 0xE8, 0xF3, 0xEA, 0xDA, 0x95, 0xB2, 0x88, 0xC0, + 0xF1, 0x02, 0xA4, 0x30, 0x50, 0x83, 0x80, 0x01, 0xEA, 0xD0, 0xF1, 0x03, 0xA4, 0x31, 0xEA, 0xD0, + 0x54, 0x04, 0x00, 0xFF, 0xFC, 0xCD, 0x84, 0x00, 0xFC, 0xCD, 0x80, 0xA1, 0x9B, 0x29, 0x97, 0x20, + 0xE2, 0x80, 0xE8, 0x08, 0x28, 0x42, 0x80, 0x01, 0x88, 0x82, 0x97, 0x2F, 0x18, 0x41, 0x80, 0x01, + 0xD5, 0xF6, 0xDD, 0x9E, 0xFC, 0x40, 0x51, 0xCF, 0x80, 0x20, 0xEE, 0xD0, 0xEB, 0xF0, 0x14, 0x0E, + 0x7F, 0xAC, 0x3C, 0x03, 0xEC, 0x52, 0x3C, 0x14, 0x0A, 0xC6, 0xE0, 0x40, 0xE8, 0x04, 0xE0, 0x20, + 0x4E, 0xF3, 0x05, 0xDD, 0x3C, 0x03, 0xEC, 0x53, 0x3C, 0x1C, 0x05, 0x62, 0x44, 0xA2, 0x49, 0xEC, + 0xE0, 0x20, 0x4E, 0xF3, 0x05, 0xD4, 0x2E, 0x17, 0xED, 0xC3, 0x5A, 0x18, 0x01, 0x07, 0x3C, 0x1C, + 0x05, 0x61, 0xE0, 0x20, 0x4E, 0xF3, 0x05, 0xCB, 0x3C, 0x70, 0x0B, 0x6E, 0x50, 0x6E, 0x7F, 0x38, + 0xC7, 0x21, 0x84, 0x3F, 0x44, 0x20, 0x00, 0x54, 0x80, 0x06, 0xDD, 0x40, 0x50, 0x3E, 0x7E, 0xE1, + 0xFA, 0x84, 0x3C, 0x5C, 0x05, 0x61, 0x80, 0x06, 0x3C, 0x1C, 0x05, 0xB6, 0x80, 0x47, 0x49, 0xFF, + 0xFC, 0x6D, 0x84, 0x20, 0x44, 0x20, 0x00, 0xA0, 0x3C, 0x0C, 0x05, 0xB6, 0xDD, 0x40, 0x00, 0x2E, + 0x7E, 0xE1, 0x3C, 0x0C, 0x05, 0xB6, 0x80, 0x26, 0x94, 0x92, 0xDD, 0x55, 0xEB, 0x0B, 0x3C, 0x08, + 0x0B, 0x6E, 0x44, 0x02, 0x4B, 0x3C, 0x3C, 0x0E, 0x05, 0xAD, 0x44, 0x02, 0x4A, 0x34, 0x3C, 0x0E, + 0x05, 0xAF, 0x84, 0x3F, 0x80, 0x06, 0x44, 0x20, 0x00, 0x54, 0xDD, 0x40, 0x44, 0x72, 0x4B, 0x2C, + 0x85, 0x20, 0x85, 0x0A, 0x40, 0x44, 0x24, 0x0C, 0x80, 0x06, 0x50, 0x3E, 0x7E, 0xE1, 0x97, 0x20, + 0x3C, 0x1C, 0x05, 0xB4, 0x3C, 0x20, 0x0B, 0x6A, 0x3C, 0x5C, 0x05, 0x62, 0x49, 0xFF, 0xFC, 0x3E, + 0xEB, 0x0B, 0x80, 0x66, 0x14, 0x0E, 0x7F, 0xB7, 0x84, 0x00, 0xAE, 0x3C, 0x84, 0x81, 0xEB, 0x08, + 0xA6, 0xBC, 0xE2, 0x80, 0xE8, 0x29, 0x23, 0xE1, 0x80, 0x03, 0x22, 0x01, 0x80, 0x01, 0x22, 0x51, + 0x80, 0x02, 0x22, 0x11, 0x80, 0x00, 0x40, 0x0F, 0x00, 0x01, 0x9A, 0x69, 0x14, 0x2E, 0x7F, 0xB4, + 0x14, 0x4E, 0x7F, 0xB5, 0x14, 0x3E, 0x7F, 0xB6, 0xEA, 0xB9, 0xB4, 0x27, 0x04, 0x2E, 0x7F, 0xB4, + 0x04, 0x3E, 0x7F, 0xB6, 0x04, 0x4E, 0x7F, 0xB5, 0x38, 0x00, 0x88, 0x08, 0xA6, 0x3C, 0x4E, 0x93, + 0x00, 0x04, 0xE6, 0x0A, 0xD5, 0x02, 0xE6, 0x14, 0xE8, 0x03, 0x8C, 0x01, 0xAE, 0x3C, 0x8C, 0x81, + 0x97, 0x20, 0x8C, 0x64, 0xD5, 0xD5, 0x84, 0x20, 0x84, 0x81, 0x80, 0x61, 0x96, 0x20, 0xE2, 0x02, + 0xE8, 0x33, 0xB4, 0xA7, 0x38, 0x02, 0x90, 0x10, 0x88, 0xA4, 0x20, 0xF2, 0xFF, 0xFF, 0x8A, 0x0F, + 0x5E, 0xF0, 0x7F, 0xE0, 0xE8, 0x04, 0x50, 0x00, 0x00, 0x40, 0xD5, 0x07, 0x5E, 0xF0, 0x00, 0x21, + 0xE9, 0x04, 0x50, 0x00, 0x7F, 0xC0, 0x96, 0x03, 0x97, 0x41, 0x88, 0x65, 0x96, 0xDB, 0x4E, 0x04, + 0x00, 0x03, 0xFE, 0x02, 0x41, 0xE0, 0x00, 0x13, 0x88, 0x3E, 0x96, 0x49, 0x4E, 0x93, 0x00, 0x13, + 0xE4, 0x09, 0xE9, 0x07, 0x3C, 0x00, 0x0A, 0xDB, 0x88, 0x1E, 0x3C, 0x08, 0x0A, 0xDB, 0xD5, 0x0A, + 0x9C, 0x29, 0x96, 0x01, 0xE6, 0x03, 0xE8, 0x06, 0x3C, 0x00, 0x0A, 0xDC, 0x8C, 0x01, 0x3C, 0x08, + 0x0A, 0xDC, 0x8C, 0x81, 0xD5, 0xCC, 0x40, 0x04, 0x84, 0x08, 0x88, 0x0A, 0x3C, 0x38, 0x0A, 0xD4, + 0x8C, 0xE8, 0x12, 0x10, 0x00, 0x1B, 0x5A, 0x90, 0x01, 0x05, 0x85, 0x21, 0x48, 0xFF, 0xFF, 0x7C, + 0x00, 0x4E, 0x7E, 0xE1, 0x84, 0x40, 0x40, 0xA2, 0x00, 0x13, 0x80, 0x02, 0x80, 0x22, 0x50, 0x5E, + 0x7F, 0x8C, 0x96, 0xD1, 0xE2, 0x6A, 0xE8, 0x0F, 0x94, 0xD2, 0x99, 0xF3, 0x38, 0x93, 0x0A, 0x11, + 0x22, 0x73, 0x80, 0x01, 0x88, 0x65, 0x38, 0x92, 0x8A, 0x09, 0x88, 0x29, 0x88, 0x07, 0xAD, 0xD9, + 0x8C, 0x41, 0xD5, 0xF0, 0xEB, 0x24, 0x40, 0x00, 0x10, 0x16, 0x3C, 0x4C, 0x05, 0xB4, 0x84, 0xE0, + 0x96, 0x4B, 0x96, 0x03, 0x46, 0x98, 0x00, 0x00, 0x3C, 0x18, 0x0A, 0xD2, 0x3C, 0x08, 0x0A, 0xD3, + 0x3D, 0xE0, 0x0B, 0x6A, 0x50, 0xA4, 0xFF, 0xFF, 0x80, 0x67, 0x80, 0xA7, 0x81, 0x04, 0x4C, 0x5F, + 0x00, 0x1A, 0x22, 0x22, 0x00, 0x00, 0x8C, 0x84, 0x40, 0xF0, 0x88, 0x01, 0x22, 0x22, 0x7F, 0xFF, + 0x9A, 0x82, 0xFE, 0x94, 0x42, 0x27, 0xBC, 0x73, 0xE0, 0x4A, 0x40, 0x32, 0xBC, 0x1B, 0x40, 0xA1, + 0x3C, 0x1B, 0xE1, 0x22, 0x40, 0x72, 0xBC, 0x1B, 0x8C, 0xA1, 0x40, 0x91, 0x3C, 0x1B, 0x97, 0x69, + 0xD5, 0xE7, 0x94, 0xDA, 0x89, 0x03, 0x95, 0xFA, 0x22, 0x24, 0x00, 0x00, 0x8A, 0x22, 0x14, 0x1E, + 0x7F, 0xB9, 0xEB, 0x70, 0x8A, 0x01, 0xEB, 0x5E, 0xEB, 0x14, 0xDD, 0x4D, 0x81, 0x20, 0xEA, 0xDA, + 0x88, 0xE0, 0x3C, 0x04, 0x0A, 0xD2, 0x22, 0x13, 0x80, 0x00, 0x8A, 0x01, 0x14, 0x0E, 0x7F, 0xB9, + 0x22, 0x13, 0x80, 0x01, 0x3C, 0x04, 0x0A, 0xD3, 0x8A, 0x01, 0xEB, 0x5E, 0xEB, 0x14, 0xDD, 0x4D, + 0xC0, 0x07, 0xEA, 0x92, 0x42, 0x14, 0x84, 0x24, 0xEB, 0x88, 0x3E, 0x00, 0x15, 0xB4, 0x3C, 0x94, + 0x0A, 0xD2, 0xEB, 0xFF, 0x3C, 0x14, 0x0A, 0xCA, 0x3C, 0xA4, 0x0A, 0xD3, 0x8A, 0x29, 0x3C, 0x04, + 0x0A, 0xCB, 0x40, 0x91, 0x24, 0x01, 0x3C, 0x24, 0x0A, 0xCD, 0x8A, 0x0A, 0x40, 0xA1, 0x28, 0x01, + 0x14, 0x1E, 0x7F, 0xB9, 0xEB, 0x5E, 0x14, 0x9E, 0x7F, 0xBB, 0x14, 0xAE, 0x7F, 0xBC, 0xEA, 0xB9, + 0x80, 0xE0, 0x80, 0x29, 0x80, 0x0A, 0xEA, 0xB9, 0x9A, 0x47, 0x5E, 0xF0, 0xFF, 0xE0, 0xE8, 0x04, + 0x50, 0x10, 0x80, 0x40, 0xD5, 0x06, 0x5E, 0xF0, 0x80, 0x21, 0xE9, 0x03, 0x50, 0x10, 0xFF, 0xC0, + 0x90, 0x21, 0x88, 0x27, 0x9B, 0xC7, 0x97, 0xEF, 0x96, 0x6F, 0x5E, 0xF3, 0x80, 0x21, 0x3E, 0x10, + 0x15, 0xAE, 0xE9, 0x03, 0x52, 0x73, 0x80, 0x40, 0x44, 0x10, 0x00, 0xB4, 0xFF, 0xCC, 0xEB, 0x14, + 0x50, 0x1E, 0x7E, 0xEC, 0x50, 0x2E, 0x7E, 0xE2, 0x90, 0xE5, 0x49, 0xFF, 0xF2, 0xBE, 0x4E, 0x04, + 0x00, 0x03, 0xFF, 0xFA, 0x3C, 0x04, 0x0A, 0xD4, 0x4E, 0x07, 0x00, 0x03, 0xFF, 0xFA, 0x50, 0x3E, + 0x7F, 0x10, 0x80, 0x03, 0x84, 0x20, 0xFA, 0x40, 0x3C, 0x78, 0x0A, 0xD8, 0x50, 0x7E, 0x7E, 0xD4, + 0xB6, 0x67, 0xDD, 0x40, 0xEB, 0x0B, 0xB4, 0x67, 0xA8, 0x39, 0x3C, 0xA4, 0x0A, 0xD2, 0x3C, 0x53, + 0x79, 0xD4, 0x3C, 0x84, 0x0A, 0xD3, 0x40, 0x02, 0x84, 0x09, 0xA8, 0x3A, 0x84, 0x20, 0x3C, 0x73, + 0x79, 0xD5, 0x50, 0x9E, 0x7F, 0x8C, 0x92, 0xE1, 0x83, 0xC3, 0x04, 0x2E, 0x7F, 0xB6, 0x96, 0x09, + 0xE2, 0x02, 0xE8, 0x33, 0x94, 0x0A, 0x88, 0x09, 0x38, 0x24, 0x86, 0x11, 0xEB, 0xB3, 0x50, 0x4E, + 0x7E, 0xDC, 0xB4, 0x64, 0x8A, 0x4A, 0x8A, 0x08, 0xE0, 0x62, 0xA8, 0xA6, 0xA8, 0x27, 0xE9, 0x23, + 0xE0, 0xE0, 0x84, 0x80, 0xE9, 0x20, 0x50, 0x0E, 0x7E, 0xF4, 0x84, 0x60, 0x38, 0xF0, 0x12, 0x02, + 0x94, 0x23, 0x88, 0x1E, 0x50, 0x2E, 0x7E, 0xF4, 0x38, 0x21, 0x0E, 0x02, 0x42, 0x27, 0x88, 0x24, + 0x4E, 0x27, 0x00, 0x04, 0x90, 0x48, 0xD5, 0x04, 0xFE, 0x92, 0x90, 0x48, 0xFE, 0x92, 0xB4, 0xA0, + 0x88, 0x45, 0xAA, 0x81, 0x5A, 0x30, 0x01, 0x04, 0x84, 0x61, 0xD5, 0xED, 0x5A, 0x40, 0x01, 0x04, + 0x80, 0x83, 0xD5, 0xE2, 0x8C, 0x21, 0xD5, 0xCA, 0x50, 0x0E, 0x7F, 0x10, 0x50, 0x1E, 0x7F, 0x04, + 0x49, 0x00, 0x06, 0xA2, 0x50, 0xAE, 0x7F, 0x20, 0x5A, 0x08, 0x01, 0x5A, 0x50, 0x3E, 0x7F, 0x04, + 0xB4, 0x43, 0xA0, 0x59, 0x3C, 0x44, 0x0A, 0xD3, 0xFE, 0x12, 0xA8, 0x5F, 0x80, 0xAA, 0xA8, 0x29, + 0x3C, 0x04, 0x0A, 0xD2, 0x42, 0x31, 0x10, 0x24, 0x42, 0x30, 0x80, 0x75, 0xFE, 0x14, 0x42, 0x00, + 0x90, 0x73, 0x85, 0x20, 0xFE, 0x02, 0xA8, 0xEA, 0xA8, 0xAB, 0xA8, 0x6C, 0xA8, 0x2D, 0x80, 0xE9, + 0x80, 0x89, 0x50, 0x8E, 0x7F, 0x8C, 0xEB, 0x0B, 0xE2, 0x80, 0xE8, 0x2D, 0x38, 0x04, 0x12, 0x11, + 0x50, 0x1E, 0x7F, 0x20, 0x14, 0x0E, 0x7F, 0xB9, 0x94, 0x22, 0x88, 0x08, 0x50, 0x2E, 0x7E, 0xE3, + 0xEB, 0xB3, 0x50, 0x3E, 0x7E, 0xFC, 0xEB, 0x5E, 0xEB, 0x14, 0x14, 0x4E, 0x7F, 0xB7, 0x49, 0x00, + 0x06, 0xFE, 0xEB, 0x14, 0x50, 0x1E, 0x7F, 0x2C, 0x50, 0x2E, 0x7E, 0xE3, 0x50, 0x3E, 0x7F, 0x00, + 0x49, 0x00, 0x06, 0xF5, 0x04, 0x0E, 0x7F, 0xBF, 0x04, 0x4E, 0x7F, 0xB7, 0xE0, 0xE0, 0xE8, 0x02, + 0x97, 0xC1, 0x04, 0x0E, 0x7F, 0xC0, 0xE1, 0x20, 0xE8, 0x03, 0x40, 0x90, 0x00, 0x13, 0x8C, 0x81, + 0x97, 0x21, 0xD5, 0xD2, 0xE3, 0x27, 0x80, 0x07, 0x40, 0x04, 0xBC, 0x1B, 0xC0, 0x08, 0xE2, 0xE9, + 0x40, 0x74, 0xBC, 0x1B, 0x40, 0x73, 0x80, 0xF6, 0x3C, 0x78, 0x0A, 0xD9, 0x84, 0xE0, 0x84, 0x20, + 0x44, 0x20, 0x04, 0xB0, 0xEA, 0xDA, 0x3C, 0x78, 0x0B, 0x6A, 0xDD, 0x40, 0x00, 0x2E, 0x7E, 0xE1, + 0x80, 0x26, 0x94, 0x92, 0xEA, 0xDA, 0xDD, 0x55, 0xEB, 0x0B, 0x3C, 0x08, 0x0B, 0x6A, 0x84, 0x20, + 0xFA, 0x44, 0x80, 0x0A, 0x15, 0xFE, 0x7F, 0xAD, 0xDD, 0x40, 0x2E, 0x07, 0xD9, 0x48, 0x84, 0x20, + 0x8C, 0x07, 0x54, 0x00, 0x01, 0xF8, 0xEA, 0x33, 0x84, 0x1F, 0x10, 0x0E, 0x7E, 0xFC, 0xFA, 0x44, + 0x80, 0x06, 0x15, 0xFE, 0x7F, 0xB5, 0x10, 0x7E, 0x7E, 0xF4, 0x3C, 0x84, 0x0A, 0xBD, 0xDD, 0x40, + 0x84, 0x20, 0x84, 0x4C, 0x50, 0x0E, 0x7F, 0x04, 0xDD, 0x40, 0x84, 0x20, 0x84, 0x4C, 0x50, 0x0E, + 0x7F, 0x10, 0xDD, 0x40, 0x3E, 0x77, 0xEC, 0x0A, 0x84, 0x20, 0x50, 0x2E, 0x7F, 0x8C, 0x44, 0x30, + 0x00, 0x64, 0x42, 0x00, 0x84, 0x24, 0x52, 0x00, 0x00, 0x80, 0xFE, 0x1C, 0x90, 0x07, 0x38, 0x01, + 0x05, 0x09, 0x8C, 0x21, 0x5A, 0x18, 0x21, 0xF7, 0x84, 0x00, 0x50, 0x1E, 0x7E, 0xC4, 0xA8, 0x0E, + 0x84, 0x00, 0xA8, 0x0D, 0x84, 0x00, 0xB6, 0x01, 0x84, 0x00, 0x14, 0x0E, 0x7F, 0xB4, 0x04, 0x1E, + 0x7F, 0xB4, 0x2E, 0x07, 0xD9, 0x48, 0xFA, 0xC8, 0xE2, 0x20, 0x4E, 0xF2, 0x01, 0x8F, 0x50, 0x3E, + 0x7E, 0xC8, 0xA0, 0x1A, 0x3C, 0x2D, 0xF6, 0x53, 0xFE, 0x34, 0x88, 0x40, 0xA8, 0x19, 0xA7, 0xD5, + 0xA6, 0x14, 0x44, 0x12, 0x49, 0xEC, 0xB6, 0x03, 0x50, 0x03, 0x80, 0x18, 0x94, 0x01, 0x88, 0x01, + 0xEA, 0x78, 0xA5, 0x83, 0x94, 0x3B, 0x88, 0x01, 0x84, 0x60, 0x00, 0x90, 0x00, 0x04, 0x84, 0x01, + 0x96, 0x40, 0xE2, 0x29, 0xB4, 0x82, 0xE8, 0x1A, 0x38, 0x12, 0x00, 0x10, 0x88, 0x80, 0x20, 0x42, + 0x7F, 0xFF, 0x8A, 0x24, 0x5E, 0xF0, 0xFF, 0xE0, 0xE8, 0x04, 0x50, 0x10, 0x80, 0x40, 0xD5, 0x07, + 0x5E, 0xF0, 0x80, 0x21, 0xE9, 0x04, 0x50, 0x10, 0xFF, 0xC0, 0x96, 0x4B, 0x4E, 0x14, 0x00, 0x03, + 0xFE, 0x4A, 0x88, 0x23, 0x96, 0xC9, 0x8C, 0x01, 0xD5, 0xE4, 0xE2, 0xC3, 0x4E, 0xF3, 0x03, 0x1C, + 0x50, 0x0E, 0x7F, 0x20, 0x14, 0x4E, 0x7F, 0xAF, 0x14, 0x0E, 0x7F, 0xB0, 0xA0, 0x15, 0xEB, 0x01, + 0xFE, 0x46, 0xC1, 0x0D, 0x3C, 0x14, 0x0A, 0xD4, 0x22, 0xF1, 0x00, 0x06, 0xE0, 0x2F, 0x4E, 0xF3, + 0x01, 0x3F, 0x22, 0xF1, 0x00, 0x07, 0xE0, 0x2F, 0x4E, 0xF2, 0x01, 0x3A, 0x46, 0x10, 0x10, 0x00, + 0xFE, 0x46, 0xC1, 0x0B, 0x3C, 0x10, 0x0A, 0xD6, 0xA4, 0xD4, 0xE2, 0x23, 0x4E, 0xF3, 0x01, 0x30, + 0xA4, 0xD5, 0xE2, 0x23, 0x4E, 0xF2, 0x01, 0x2C, 0x46, 0x10, 0x80, 0x00, 0xFE, 0x46, 0xC1, 0x16, + 0x2E, 0x38, 0x15, 0xAE, 0x20, 0x41, 0x00, 0x14, 0x50, 0x11, 0x80, 0x40, 0xE0, 0x64, 0x96, 0x4A, + 0xE9, 0x05, 0x20, 0xF1, 0x00, 0x15, 0xE0, 0x6F, 0xE9, 0x09, 0xE0, 0x24, 0x4E, 0xF3, 0x01, 0x18, + 0x20, 0xF1, 0x00, 0x15, 0xE0, 0x2F, 0x4E, 0xF2, 0x01, 0x13, 0x46, 0x10, 0x40, 0x00, 0xFE, 0x0E, + 0xC0, 0x0D, 0x3C, 0x04, 0x0A, 0xD8, 0x22, 0xF1, 0x00, 0x08, 0xE0, 0x0F, 0x4E, 0xF3, 0x01, 0x08, + 0x22, 0xF1, 0x00, 0x09, 0xE0, 0x0F, 0x4E, 0xF2, 0x01, 0x03, 0xEA, 0xE3, 0x8E, 0x01, 0xE6, 0x04, + 0xE8, 0x15, 0xEA, 0x78, 0x80, 0x49, 0x38, 0x10, 0x9F, 0x02, 0x50, 0x0E, 0x7F, 0x20, 0xDD, 0x55, + 0x80, 0x09, 0x04, 0x1E, 0x7F, 0xB0, 0x80, 0x49, 0x04, 0x3E, 0x7F, 0xAF, 0xEB, 0xC8, 0x80, 0xA7, + 0x49, 0xFF, 0xF8, 0xC5, 0x80, 0xC0, 0x48, 0x00, 0x00, 0xAC, 0xEA, 0xE3, 0x8E, 0x0D, 0xE6, 0x02, + 0x4E, 0xF2, 0x00, 0x78, 0xB4, 0x22, 0x84, 0x4A, 0x50, 0x0E, 0x7F, 0x38, 0x40, 0x21, 0x1C, 0x0C, + 0xDD, 0x55, 0x50, 0xF3, 0x7F, 0xC0, 0x5C, 0xF7, 0x80, 0x41, 0xE9, 0x0A, 0x94, 0x3B, 0xEA, 0x78, + 0x85, 0x20, 0x88, 0x01, 0x80, 0xC9, 0x81, 0x49, 0x14, 0x0E, 0x7F, 0xAE, 0xD5, 0x35, 0x40, 0x63, + 0x24, 0xD6, 0x94, 0xFB, 0xEA, 0x78, 0x97, 0xB0, 0x84, 0x01, 0x88, 0x61, 0xA6, 0x5C, 0xE2, 0x01, + 0xE8, 0xEE, 0x04, 0x2E, 0x7F, 0xB2, 0x3C, 0x1D, 0xF6, 0x53, 0x5A, 0x28, 0x0D, 0x09, 0xEB, 0xBF, + 0xEB, 0xF2, 0x98, 0x50, 0x00, 0x10, 0xFF, 0xFF, 0x8A, 0x26, 0xD5, 0x07, 0xEB, 0xBF, 0xEB, 0xF2, + 0x98, 0x50, 0x00, 0x10, 0xFF, 0xFF, 0x88, 0x26, 0x38, 0x11, 0x00, 0x08, 0x3C, 0x1D, 0xF6, 0x53, + 0xEB, 0xBF, 0xEB, 0xF2, 0x88, 0x40, 0x20, 0x11, 0x00, 0x00, 0x4E, 0x14, 0x00, 0x05, 0x50, 0x10, + 0x80, 0x40, 0xD5, 0x06, 0x5E, 0xF0, 0x80, 0x40, 0xE9, 0x04, 0x50, 0x10, 0xFF, 0xC0, 0xAE, 0x50, + 0x8C, 0x01, 0x96, 0x00, 0xD5, 0xD4, 0xEB, 0xC6, 0xEA, 0x78, 0x80, 0x4A, 0xA6, 0x04, 0x38, 0x10, + 0x9F, 0x02, 0x50, 0x3E, 0x7F, 0x20, 0x49, 0xFF, 0xFC, 0x5A, 0xEB, 0xC6, 0x04, 0x1E, 0x7F, 0xB0, + 0x04, 0x3E, 0x7F, 0xAF, 0xA6, 0x04, 0xEB, 0xC8, 0x80, 0x40, 0x80, 0xA7, 0x49, 0xFF, 0xF8, 0x5F, + 0xE2, 0xC0, 0xEA, 0x84, 0xEB, 0x91, 0x50, 0x05, 0x00, 0x04, 0x40, 0x95, 0x3C, 0x1B, 0x40, 0xA0, + 0x00, 0x10, 0x5A, 0xA8, 0x40, 0xE2, 0x04, 0x1E, 0x7F, 0xB3, 0xEB, 0x63, 0x84, 0x6A, 0x88, 0x01, + 0x50, 0x1E, 0x7F, 0x38, 0xA6, 0x85, 0xB4, 0x00, 0x40, 0x21, 0x88, 0x0C, 0xDD, 0x55, 0xD5, 0x03, + 0x85, 0x20, 0x80, 0xC9, 0x50, 0x04, 0xFF, 0xFB, 0x40, 0xA0, 0x00, 0x10, 0x50, 0x04, 0x80, 0x05, + 0x14, 0x0E, 0x7F, 0xAE, 0xEA, 0x78, 0x94, 0x3B, 0x40, 0x90, 0x80, 0x00, 0xEB, 0xC6, 0xE0, 0x0A, + 0xE9, 0x1F, 0xEA, 0x78, 0x80, 0x4A, 0x00, 0x04, 0x80, 0x04, 0x38, 0x10, 0x9F, 0x02, 0x50, 0x3E, + 0x7F, 0x20, 0x49, 0xFF, 0xFC, 0x1C, 0x00, 0x04, 0x80, 0x04, 0x04, 0x1E, 0x7F, 0xB0, 0x80, 0x40, + 0x04, 0x3E, 0x7F, 0xAF, 0xEB, 0xC8, 0x80, 0xA7, 0x49, 0xFF, 0xF8, 0x21, 0xE2, 0x06, 0x40, 0x60, + 0x3C, 0x1A, 0xEA, 0x84, 0xEA, 0xCB, 0x97, 0xB0, 0x40, 0xA0, 0x00, 0x10, 0xD5, 0xE0, 0xEB, 0x63, + 0x04, 0x1E, 0x7F, 0xB3, 0x88, 0x01, 0x00, 0x00, 0x00, 0x16, 0xE2, 0xC0, 0xE9, 0x38, 0x00, 0x0E, + 0x7E, 0xF4, 0xE2, 0x06, 0xE8, 0x07, 0x00, 0x0E, 0x7E, 0xD0, 0x10, 0x6E, 0x7E, 0xF4, 0x10, 0x0E, + 0x7E, 0xFC, 0xEA, 0xE3, 0x5A, 0x08, 0x0A, 0x0D, 0x04, 0x0E, 0x7F, 0xB1, 0xE2, 0xC0, 0x00, 0x0E, + 0x7E, 0xC4, 0x40, 0x03, 0x3C, 0x1A, 0x96, 0x00, 0x14, 0x0E, 0x7F, 0xB1, 0xD5, 0x1A, 0xEA, 0xE3, + 0x5A, 0x08, 0x0B, 0x0C, 0xEB, 0x08, 0xE2, 0xC0, 0x00, 0x0E, 0x7E, 0xDC, 0x40, 0x03, 0x3C, 0x1A, + 0x96, 0x00, 0x14, 0x0E, 0x7F, 0xB7, 0xD5, 0x0D, 0xEA, 0xE3, 0x5A, 0x08, 0x0D, 0x0B, 0xEA, 0xE4, + 0xE2, 0xC0, 0x00, 0x0E, 0x7E, 0xD8, 0x40, 0x03, 0x3C, 0x1A, 0x96, 0x00, 0x14, 0x0E, 0x7F, 0xB6, + 0x04, 0x0E, 0x7F, 0xB5, 0x04, 0x1E, 0x7F, 0xB4, 0x38, 0x60, 0x04, 0x08, 0x04, 0x0E, 0x7F, 0xB4, + 0x8C, 0x01, 0x96, 0x00, 0x48, 0xFF, 0xFE, 0x6B, 0x00, 0x1E, 0x7E, 0xFC, 0x44, 0x72, 0x4A, 0x48, + 0x5A, 0x18, 0xFF, 0x04, 0x48, 0x00, 0x01, 0xA6, 0xEB, 0x63, 0x42, 0x00, 0x98, 0x73, 0xA7, 0x84, + 0x5A, 0x60, 0x0B, 0x1D, 0x04, 0x0E, 0x7F, 0xB1, 0xC0, 0x16, 0xEA, 0xE4, 0xC0, 0x34, 0x5A, 0x68, + 0x0A, 0x08, 0x3C, 0xF4, 0x0A, 0xD8, 0x5E, 0xF7, 0x80, 0x32, 0xE8, 0x3D, 0xD5, 0x17, 0x5A, 0x68, + 0x0D, 0x3B, 0x3C, 0xF4, 0x0A, 0xD8, 0x5E, 0xF7, 0x80, 0x32, 0xE9, 0x27, 0x04, 0x0E, 0x7F, 0xB1, + 0x84, 0x2A, 0xD5, 0x19, 0xEB, 0x08, 0xC8, 0x0D, 0xD5, 0x1E, 0xEB, 0x08, 0xC0, 0x2C, 0xEA, 0xE4, + 0xC0, 0x2A, 0x2E, 0x00, 0x15, 0xB4, 0xE6, 0x1F, 0xE9, 0x26, 0xEA, 0xE4, 0x84, 0x2D, 0xD5, 0x1C, + 0xEA, 0xE4, 0xC0, 0x11, 0x5A, 0x68, 0x0D, 0x20, 0x2E, 0x00, 0x15, 0xB4, 0xE6, 0x1E, 0xE8, 0x0D, + 0xEB, 0x08, 0x84, 0x2B, 0xEB, 0xBD, 0x50, 0x3E, 0x7E, 0xF4, 0x50, 0x4E, 0x7E, 0xFC, 0x49, 0xFF, + 0xF8, 0x06, 0xD5, 0x03, 0x5A, 0x68, 0x0D, 0x10, 0x2E, 0x00, 0x15, 0xB4, 0xE6, 0x0A, 0xE8, 0x0B, + 0x2E, 0x07, 0xD8, 0xB0, 0xFA, 0x25, 0xEB, 0xBD, 0x50, 0x3E, 0x7E, 0xF4, 0x50, 0x4E, 0x7E, 0xFC, + 0x49, 0xFF, 0xF7, 0xF5, 0x8E, 0xC6, 0xE6, 0xC2, 0xE8, 0x11, 0x3C, 0xF4, 0x0A, 0xD3, 0x3C, 0x14, + 0x0A, 0xCD, 0xE0, 0x2F, 0xE8, 0x0B, 0x2E, 0x07, 0xD8, 0xB0, 0x84, 0x29, 0xEB, 0xBD, 0x50, 0x3E, + 0x7E, 0xF4, 0x50, 0x4E, 0x7E, 0xFC, 0x49, 0xFF, 0xF7, 0xE2, 0x00, 0x2E, 0x7E, 0xFC, 0xFA, 0x28, + 0xEB, 0x63, 0xEA, 0xB1, 0xA7, 0x84, 0x50, 0x9E, 0x7F, 0x04, 0x84, 0x00, 0x50, 0xAE, 0x7F, 0x10, + 0xEA, 0x84, 0x80, 0x2A, 0x80, 0x09, 0x80, 0x46, 0x49, 0xFF, 0xFA, 0x61, 0x3E, 0x07, 0xEC, 0x0A, + 0x84, 0x20, 0x96, 0x88, 0xE2, 0x40, 0xE8, 0x0C, 0x38, 0x34, 0x85, 0x01, 0x94, 0x8A, 0x38, 0x33, + 0x86, 0x09, 0x88, 0x47, 0x38, 0x35, 0x05, 0x01, 0x8C, 0x21, 0xAC, 0xD1, 0xD5, 0xF3, 0x9E, 0x75, + 0xE6, 0x25, 0xE8, 0x22, 0x3C, 0x14, 0x0A, 0xCB, 0x84, 0x60, 0x96, 0x98, 0xE2, 0x40, 0xE8, 0x11, + 0x94, 0x9A, 0x88, 0x47, 0x22, 0x21, 0x00, 0x01, 0xE0, 0x41, 0xE9, 0x07, 0xE1, 0x02, 0x80, 0x82, + 0x40, 0x44, 0x3C, 0x1B, 0x80, 0x41, 0x96, 0x63, 0x81, 0x01, 0x8C, 0x61, 0x80, 0x22, 0xD5, 0xEE, + 0x80, 0x48, 0x3C, 0x84, 0x0A, 0xCD, 0xE1, 0x01, 0xE9, 0x08, 0xE1, 0x02, 0x40, 0x24, 0x3C, 0x1B, + 0x81, 0x01, 0x96, 0x53, 0xD5, 0x02, 0x80, 0x28, 0xE6, 0xCA, 0xE8, 0x0E, 0xE6, 0xC8, 0xE8, 0x43, + 0xE6, 0xC5, 0xE8, 0x41, 0xE6, 0xC3, 0xE8, 0x2D, 0x4E, 0x62, 0x00, 0xEC, 0x3C, 0xF4, 0x0A, 0xC7, + 0x5E, 0xF7, 0x93, 0x98, 0xD5, 0x2A, 0xE6, 0xCF, 0xE8, 0x11, 0xE6, 0xCD, 0x4E, 0xF2, 0x00, 0x97, + 0x5A, 0x60, 0x0C, 0x04, 0x48, 0x00, 0x00, 0xDE, 0x3C, 0x04, 0x0A, 0xC1, 0x3C, 0x14, 0x0A, 0xBD, + 0xEB, 0x58, 0xEB, 0x4E, 0x3C, 0x04, 0x0A, 0xC1, 0xD5, 0x6B, 0x5A, 0x60, 0x12, 0x6E, 0x5A, 0x68, + 0x13, 0x04, 0x48, 0x00, 0x00, 0x7B, 0x5A, 0x60, 0x11, 0x04, 0x48, 0x00, 0x00, 0xCB, 0x3C, 0x04, + 0x0A, 0xC0, 0x3C, 0x14, 0x0A, 0xBC, 0xEB, 0x58, 0xEB, 0x4E, 0x3C, 0x04, 0x0A, 0xC0, 0xD5, 0x58, + 0x3C, 0xF4, 0x0A, 0xC6, 0x5E, 0xF7, 0x88, 0xD1, 0xE8, 0x03, 0x84, 0x01, 0xEA, 0x84, 0x00, 0x1E, + 0x7E, 0xF4, 0x22, 0xFE, 0x7F, 0xCA, 0xE0, 0x2F, 0x4E, 0xF2, 0x00, 0xB4, 0x84, 0x01, 0xEA, 0x84, + 0x48, 0x00, 0x00, 0xB0, 0x3C, 0x20, 0x0A, 0xD9, 0xE6, 0x44, 0xE9, 0x04, 0x84, 0x41, 0x10, 0x2E, + 0x7E, 0xEC, 0xEB, 0xF0, 0x3C, 0x34, 0x0A, 0xC6, 0xE0, 0x62, 0x80, 0x83, 0x40, 0x41, 0x3C, 0x1B, + 0x5E, 0xF2, 0x07, 0xD0, 0xE9, 0x08, 0xE0, 0x43, 0x80, 0x83, 0x40, 0x41, 0x3C, 0x1B, 0x5E, 0xF2, + 0x03, 0xE8, 0xE8, 0x04, 0x84, 0x81, 0x10, 0x4E, 0x7E, 0xEC, 0x5A, 0x08, 0x04, 0x1E, 0x3C, 0x04, + 0x0A, 0xCC, 0x3C, 0xF4, 0x0A, 0xEE, 0x8A, 0x0F, 0x4E, 0x04, 0x00, 0x03, 0xFE, 0x02, 0x85, 0xE5, + 0x40, 0x31, 0xBC, 0x76, 0xE0, 0x60, 0xE9, 0x0E, 0x3C, 0x04, 0x0A, 0xCD, 0x3C, 0xF4, 0x0A, 0xEF, + 0x8A, 0x0F, 0x4E, 0x04, 0x00, 0x03, 0xFE, 0x02, 0x85, 0xE5, 0x40, 0x21, 0x3C, 0x56, 0xE0, 0x40, + 0xE8, 0x03, 0x84, 0x01, 0xEA, 0x84, 0x3C, 0x04, 0x0A, 0xBD, 0x85, 0xEA, 0x40, 0x20, 0x20, 0x01, + 0x9A, 0x41, 0xFA, 0x09, 0xFE, 0x44, 0x40, 0x10, 0xBC, 0x36, 0xE0, 0x22, 0xD5, 0xB6, 0x3C, 0x14, + 0x0A, 0xCA, 0xEB, 0xFF, 0xD5, 0x0D, 0x3C, 0x04, 0x0A, 0xBB, 0x3C, 0x14, 0x0A, 0xBF, 0xEB, 0x58, + 0xEB, 0x4E, 0x3C, 0x04, 0x0A, 0xBF, 0x3C, 0x14, 0x0A, 0xCB, 0x3C, 0x24, 0x0A, 0xCD, 0x50, 0x3E, + 0x7E, 0xEC, 0x49, 0xFF, 0xF7, 0x17, 0xD5, 0x55, 0x3C, 0x04, 0x0A, 0xBA, 0x3C, 0x14, 0x0A, 0xBE, + 0xEB, 0x58, 0xEB, 0x4E, 0x3C, 0x04, 0x0A, 0xBE, 0xD5, 0xEF, 0x3C, 0x00, 0x0A, 0xDB, 0x5C, 0xF0, + 0x00, 0x25, 0xE8, 0x05, 0x3C, 0x00, 0x0A, 0xDC, 0xE6, 0x02, 0xE8, 0x0A, 0x3C, 0x00, 0x0A, 0xD5, + 0x5C, 0xF0, 0x00, 0x5B, 0xE8, 0x05, 0x3C, 0x00, 0x0A, 0xDC, 0xE6, 0x04, 0xE9, 0x03, 0x84, 0x01, + 0xEA, 0x84, 0x3C, 0x04, 0x0A, 0xCC, 0x3C, 0x14, 0x0A, 0xCA, 0x3C, 0x24, 0x0A, 0xCD, 0x8A, 0x20, + 0x3C, 0x04, 0x0A, 0xCB, 0x3C, 0x34, 0x0A, 0xC7, 0x9A, 0x82, 0x3C, 0x04, 0x0A, 0xC6, 0xE0, 0x03, + 0x80, 0x80, 0x40, 0x41, 0xBC, 0x1B, 0x5E, 0xF2, 0x07, 0xD0, 0xE9, 0x08, 0xE0, 0x60, 0x80, 0xA0, + 0x40, 0x51, 0xBC, 0x1B, 0x5E, 0xF2, 0x83, 0xE8, 0xE8, 0x04, 0x84, 0xA1, 0x10, 0x5E, 0x7E, 0xEC, + 0x3C, 0x54, 0x0A, 0xD8, 0xFE, 0x94, 0xFE, 0x4C, 0x4E, 0x57, 0x00, 0x0E, 0x3C, 0x50, 0x0A, 0xD6, + 0x5C, 0xF2, 0x80, 0x46, 0xE8, 0x08, 0xE0, 0x60, 0x40, 0x01, 0xBC, 0x1B, 0x90, 0x01, 0x88, 0x22, + 0xFE, 0x04, 0xD5, 0x04, 0x88, 0x22, 0x42, 0x02, 0x10, 0x24, 0xE0, 0x01, 0x48, 0xFF, 0xFF, 0x4E, + 0x00, 0x0E, 0x7E, 0xEC, 0x5A, 0x08, 0x01, 0x06, 0x84, 0x00, 0x10, 0x0E, 0x7E, 0xF4, 0xFA, 0xC8, + 0x00, 0x0E, 0x7E, 0xF4, 0x84, 0x20, 0x3E, 0x00, 0x16, 0xB2, 0x05, 0xFE, 0x7F, 0xAD, 0x5A, 0x60, + 0x0D, 0x09, 0x84, 0x21, 0x5A, 0x60, 0x0E, 0x06, 0xD5, 0x03, 0xFA, 0xC8, 0x84, 0x00, 0x84, 0x22, + 0x3E, 0x10, 0x16, 0x88, 0xC0, 0x06, 0x04, 0x0E, 0x7F, 0xAC, 0xAF, 0x80, 0x84, 0x01, 0xD5, 0x0B, + 0x84, 0x02, 0xD5, 0x09, 0x50, 0x0E, 0x7F, 0x20, 0x14, 0x4E, 0x7F, 0xB0, 0x14, 0x0E, 0x7F, 0xAF, + 0x48, 0xFF, 0xFC, 0xE6, 0xEB, 0x86, 0xFC, 0xC0, 0x80, 0x20, 0x2E, 0x07, 0xED, 0xC2, 0xC8, 0x0B, + 0x2E, 0x07, 0xED, 0xC5, 0xC0, 0x09, 0x2E, 0x07, 0xED, 0xC4, 0xC0, 0x06, 0xA6, 0x08, 0x8E, 0x02, + 0xEA, 0xD8, 0xDD, 0x9E, 0x84, 0x00, 0xDD, 0x9E, 0xFC, 0x41, 0x22, 0x90, 0x80, 0x00, 0x22, 0x00, + 0x00, 0x00, 0x44, 0x11, 0x28, 0x20, 0xB6, 0x1F, 0x14, 0x9F, 0x80, 0x01, 0x80, 0xE2, 0x80, 0xC3, + 0xA4, 0x88, 0xA4, 0xC9, 0xA5, 0x0F, 0x02, 0x50, 0x80, 0x08, 0x3A, 0x0F, 0x84, 0x00, 0xEB, 0xD3, + 0x3A, 0x0F, 0x84, 0x20, 0xB4, 0x1F, 0xAC, 0x38, 0xF0, 0x01, 0xAC, 0x30, 0xFC, 0xC1, 0xFC, 0x40, + 0x80, 0xE0, 0xFA, 0x05, 0x44, 0x22, 0x4B, 0x12, 0x3C, 0x08, 0x0B, 0x57, 0x44, 0x02, 0x4A, 0x0C, + 0x9C, 0x42, 0x9C, 0xD2, 0xEA, 0x3D, 0x44, 0x02, 0x4A, 0x10, 0x44, 0x22, 0x4B, 0x16, 0x9C, 0x42, + 0x9C, 0xD2, 0xEA, 0x3D, 0x44, 0x02, 0x4A, 0x04, 0x44, 0x22, 0x4B, 0x1A, 0x9C, 0x42, 0x9C, 0xD2, + 0xEA, 0x3D, 0xA6, 0x38, 0x44, 0x62, 0x4A, 0x48, 0x5A, 0x08, 0x14, 0x1A, 0x84, 0x0B, 0x3C, 0x08, + 0x0B, 0x57, 0x3C, 0x08, 0x0B, 0x58, 0x44, 0x02, 0x4A, 0x14, 0x9C, 0x42, 0x50, 0x23, 0x00, 0xD6, + 0x50, 0x33, 0x00, 0xD8, 0xEA, 0x3D, 0x44, 0x02, 0x4A, 0x18, 0x9C, 0x42, 0x50, 0x23, 0x00, 0xDA, + 0x50, 0x33, 0x00, 0xDC, 0xEA, 0x3D, 0x85, 0x42, 0x84, 0x2B, 0xD5, 0x03, 0x85, 0x41, 0xFA, 0x25, + 0x8E, 0x21, 0x96, 0x48, 0x94, 0x4A, 0x8C, 0x36, 0x44, 0x92, 0x4A, 0x5A, 0x88, 0xC1, 0x85, 0x00, + 0xEA, 0xDA, 0x41, 0xC4, 0x08, 0x08, 0x88, 0x1C, 0x9C, 0x42, 0x50, 0x24, 0xFF, 0xFE, 0x80, 0x69, + 0xEA, 0x3D, 0x3C, 0x0C, 0x05, 0xB6, 0x50, 0x24, 0x80, 0x52, 0x88, 0x1C, 0x9C, 0x42, 0x50, 0x34, + 0x80, 0x54, 0xEA, 0x3D, 0x8D, 0x24, 0x40, 0x04, 0x28, 0x00, 0xEA, 0x71, 0x4C, 0x93, 0x7F, 0xEA, + 0xEB, 0xC7, 0x44, 0x22, 0x4B, 0x02, 0x9C, 0x44, 0x9C, 0xD4, 0xEA, 0x3D, 0x44, 0x02, 0x49, 0xEE, + 0x44, 0x22, 0x4B, 0x04, 0x9C, 0x44, 0x9C, 0xD4, 0xEA, 0x3D, 0xA6, 0x38, 0x9E, 0x45, 0xE6, 0x23, + 0xE8, 0x22, 0x3C, 0x10, 0x0B, 0x46, 0x3C, 0x04, 0x0B, 0x45, 0x3C, 0x18, 0x0B, 0x4F, 0x3C, 0x14, + 0x0B, 0x51, 0x3C, 0x08, 0x0B, 0x4D, 0x40, 0x20, 0x88, 0x0A, 0x96, 0x01, 0x90, 0x21, 0x88, 0x20, + 0x96, 0x91, 0x3C, 0x18, 0x0A, 0xEA, 0x84, 0x23, 0x3C, 0x34, 0x0B, 0x48, 0x99, 0x10, 0xEA, 0xB1, + 0x3C, 0x08, 0x0A, 0xEC, 0xEB, 0xD0, 0x3C, 0x38, 0x0B, 0x50, 0x3C, 0x48, 0x0A, 0xE8, 0x3C, 0x04, + 0x0B, 0x47, 0xD5, 0x25, 0x50, 0x10, 0x7F, 0xF8, 0xE6, 0x22, 0xE8, 0x28, 0x3C, 0x10, 0x0B, 0x46, + 0x3C, 0x04, 0x0B, 0x45, 0x3C, 0x18, 0x0B, 0x4F, 0x3C, 0x14, 0x0B, 0x51, 0x3C, 0x08, 0x0B, 0x4D, + 0x40, 0x20, 0x88, 0x0A, 0x96, 0x01, 0x90, 0x21, 0x88, 0x20, 0x96, 0x91, 0x3C, 0x18, 0x0A, 0xEA, + 0x84, 0x23, 0x3C, 0x34, 0x0B, 0x47, 0x99, 0x10, 0xEA, 0xB1, 0x3C, 0x08, 0x0A, 0xEC, 0xEB, 0xD0, + 0x3C, 0x38, 0x0B, 0x50, 0x3C, 0x48, 0x0A, 0xE8, 0x3C, 0x04, 0x0B, 0x48, 0x3C, 0x08, 0x0A, 0xE9, + 0x3C, 0x38, 0x0A, 0xEB, 0x3C, 0x08, 0x0A, 0xED, 0xFC, 0xC0, 0x5A, 0x08, 0x0C, 0x08, 0x84, 0x00, + 0x3C, 0x14, 0x0B, 0x47, 0x3C, 0x24, 0x0B, 0x48, 0xD5, 0x18, 0x5A, 0x08, 0x11, 0x08, 0x84, 0x00, + 0x3C, 0x14, 0x0B, 0x48, 0x3C, 0x24, 0x0B, 0x47, 0xD5, 0x10, 0x5A, 0x08, 0x12, 0x08, 0x84, 0x01, + 0x3C, 0x14, 0x0B, 0x45, 0x3C, 0x24, 0x0B, 0x46, 0xD5, 0x08, 0x5A, 0x08, 0x13, 0x09, 0x84, 0x01, + 0x3C, 0x14, 0x0B, 0x46, 0x3C, 0x24, 0x0B, 0x45, 0x49, 0xFF, 0xF4, 0xAD, 0xFC, 0xC0, 0xFC, 0x58, + 0xB6, 0x3F, 0x80, 0xE0, 0x44, 0x11, 0x28, 0x64, 0x81, 0x42, 0xB0, 0x0C, 0xEA, 0xDE, 0xF3, 0x81, + 0xFD, 0x42, 0x21, 0xCF, 0x80, 0xE0, 0x20, 0x6F, 0x80, 0xE4, 0xDD, 0x55, 0x44, 0x11, 0x28, 0xAC, + 0xEA, 0xDE, 0xB0, 0x1E, 0xDD, 0x55, 0xB0, 0x43, 0x44, 0x01, 0x28, 0xF4, 0x81, 0xE1, 0xEA, 0x4D, + 0xEB, 0x5C, 0xEA, 0x4D, 0xEB, 0x5C, 0xB4, 0x00, 0xB6, 0x0F, 0x54, 0x0E, 0x00, 0xFF, 0xCE, 0x08, + 0x3C, 0x23, 0xF6, 0xD6, 0x96, 0x86, 0xC2, 0x04, 0x44, 0x12, 0x13, 0x6C, 0xD5, 0x0B, 0xEA, 0xE1, + 0x8E, 0x41, 0x4C, 0x61, 0x40, 0x06, 0x3C, 0x23, 0xF6, 0xD6, 0x96, 0x86, 0xCA, 0x03, 0x44, 0x12, + 0x13, 0xD8, 0x38, 0x10, 0x81, 0x01, 0xB4, 0x1F, 0xB4, 0x5F, 0xB4, 0x00, 0xEA, 0x8B, 0xB6, 0x02, + 0xCF, 0x03, 0xF0, 0x01, 0xAC, 0x40, 0x3C, 0x13, 0xF6, 0xD6, 0xB4, 0x0A, 0x54, 0x20, 0x80, 0x04, + 0xC2, 0x59, 0x96, 0x4E, 0xC1, 0x44, 0x2E, 0x20, 0x17, 0x90, 0x44, 0x32, 0x4C, 0x08, 0xEB, 0xB1, + 0x5A, 0x28, 0x87, 0x0E, 0x9E, 0x89, 0x38, 0x31, 0x88, 0x00, 0x5A, 0x30, 0x87, 0x18, 0x5B, 0xC8, + 0x01, 0x04, 0xCE, 0x2B, 0xD5, 0x16, 0x4F, 0xC2, 0x00, 0x1D, 0xD5, 0x27, 0x9E, 0x89, 0x38, 0x31, + 0x88, 0x00, 0x5A, 0x38, 0x87, 0x27, 0x8E, 0x22, 0x4D, 0xC0, 0xC0, 0x03, 0xC6, 0x18, 0x97, 0xB0, + 0x4D, 0xC1, 0x00, 0x33, 0x4F, 0xC3, 0x00, 0x38, 0xD5, 0x25, 0x5B, 0xC8, 0x01, 0x09, 0xCE, 0x0B, + 0x02, 0x1F, 0x80, 0x18, 0xEA, 0x8B, 0xB6, 0x0A, 0xCF, 0x36, 0xD5, 0x33, 0x4F, 0xC3, 0x00, 0x04, + 0x97, 0xB0, 0xD5, 0x18, 0x8E, 0x22, 0x4D, 0xC0, 0xC0, 0x09, 0xCE, 0x07, 0x02, 0x1F, 0x80, 0x3C, + 0xEA, 0x8B, 0xB6, 0x0A, 0xCF, 0x28, 0xD5, 0x25, 0x97, 0xB0, 0x4D, 0xC1, 0x40, 0x1D, 0xD5, 0x14, + 0x97, 0xB0, 0x4F, 0xC2, 0x00, 0x08, 0x4D, 0xC1, 0x40, 0x17, 0xD5, 0x0E, 0x97, 0xB0, 0x4F, 0xC3, + 0x00, 0x08, 0xB0, 0x4C, 0xEB, 0x9C, 0xEA, 0x8B, 0xB6, 0x0A, 0xCF, 0x15, 0xD5, 0x12, 0xEB, 0xB1, + 0x8E, 0x21, 0x4D, 0xC0, 0xC0, 0x09, 0xB0, 0x5E, 0xEB, 0x9C, 0xEA, 0x8B, 0xB6, 0x0A, 0xCF, 0x0B, + 0xD5, 0x08, 0x97, 0xB0, 0x44, 0x12, 0x13, 0x90, 0xEB, 0x9C, 0xEA, 0x8B, 0xB6, 0x0A, 0xCF, 0x03, + 0x12, 0x14, 0x00, 0x00, 0xFC, 0xD8, 0xFC, 0x42, 0x44, 0x41, 0x29, 0x18, 0x80, 0xC2, 0x81, 0x23, + 0x3A, 0x22, 0x14, 0x00, 0x3A, 0x2F, 0x94, 0x20, 0x80, 0xFF, 0x2E, 0xA6, 0xF3, 0xAF, 0xC6, 0x4C, + 0x50, 0xF3, 0x7F, 0xFF, 0x54, 0xF7, 0x80, 0xFF, 0x50, 0xF7, 0x80, 0x01, 0xA7, 0x83, 0xA6, 0xC2, + 0x40, 0xF7, 0x84, 0x08, 0x2E, 0x76, 0xF3, 0xAE, 0x80, 0x9F, 0x40, 0xFF, 0xBC, 0x00, 0x84, 0x0F, + 0x87, 0x80, 0x85, 0x00, 0xA6, 0xA0, 0x20, 0x52, 0x00, 0x01, 0x88, 0x46, 0x96, 0x92, 0x4E, 0x25, + 0x00, 0x22, 0x41, 0xE1, 0x1C, 0x07, 0x4F, 0xE2, 0x00, 0x1E, 0x88, 0xA3, 0x97, 0x6A, 0x4E, 0x55, + 0x00, 0x1A, 0x41, 0xE2, 0xA8, 0x07, 0x4F, 0xE2, 0x00, 0x16, 0x83, 0xC1, 0x43, 0xE3, 0x94, 0x73, + 0x38, 0x2F, 0x08, 0x00, 0x54, 0x51, 0x00, 0x20, 0xC5, 0x0D, 0x54, 0x51, 0x00, 0x2F, 0x5A, 0x50, + 0x2F, 0x24, 0x54, 0x51, 0x00, 0x0F, 0x5A, 0x50, 0x0F, 0x06, 0x4E, 0x83, 0x00, 0x18, 0x80, 0x02, + 0x85, 0x01, 0x8C, 0x82, 0x4C, 0x47, 0xFF, 0xD8, 0xE7, 0x02, 0xE9, 0x1E, 0x00, 0x14, 0x80, 0x00, + 0xFA, 0x1F, 0xE6, 0x39, 0xE8, 0x0A, 0x94, 0x8A, 0x88, 0x49, 0x8C, 0x21, 0xAF, 0x95, 0xAE, 0xD4, + 0x10, 0x14, 0x80, 0x00, 0xFC, 0xC2, 0x84, 0x0F, 0xFC, 0xC2, 0x4C, 0x20, 0x3F, 0xEC, 0x8D, 0x01, + 0x54, 0x84, 0x00, 0xFF, 0xD5, 0xEA, 0x51, 0xCE, 0x00, 0x01, 0x8C, 0x82, 0x55, 0xCE, 0x00, 0xFF, + 0x4C, 0x47, 0xFF, 0xBA, 0xD5, 0xE2, 0x4E, 0x83, 0xFF, 0xF1, 0x84, 0x0F, 0x4F, 0xC2, 0xFF, 0xEE, + 0xD5, 0xDE, 0xFC, 0x44, 0x22, 0x0F, 0x80, 0x20, 0x81, 0x23, 0xF0, 0x84, 0x00, 0x0F, 0x80, 0x44, + 0x80, 0x62, 0xF0, 0x82, 0xB6, 0x5F, 0xEA, 0x4E, 0xF4, 0x83, 0xF5, 0x81, 0x22, 0x2F, 0x80, 0x24, + 0xF0, 0x85, 0x4E, 0x92, 0x00, 0x22, 0x80, 0xE1, 0x2E, 0xA6, 0xF3, 0xAE, 0xA6, 0x5A, 0xA6, 0x1B, + 0x80, 0x87, 0x42, 0x40, 0xA8, 0x73, 0x38, 0x02, 0x00, 0x00, 0x80, 0x23, 0x96, 0x2E, 0x8C, 0x27, + 0x84, 0xC0, 0xC8, 0x0D, 0xD5, 0x13, 0x00, 0x30, 0x7F, 0xFF, 0x80, 0x87, 0xA6, 0x00, 0x42, 0x41, + 0xA8, 0x73, 0x38, 0x02, 0x00, 0x00, 0x8C, 0x24, 0x96, 0x2E, 0xC0, 0x08, 0x8C, 0xC1, 0x97, 0xB0, + 0x80, 0x01, 0x4C, 0x64, 0xFF, 0xF2, 0xF0, 0x03, 0xFC, 0xC4, 0xF1, 0x04, 0xE2, 0xC9, 0x40, 0x11, + 0x04, 0x07, 0x12, 0x2F, 0x80, 0x0D, 0xF1, 0x87, 0xE9, 0x0F, 0xD5, 0xF6, 0x00, 0x2E, 0x00, 0x02, + 0x00, 0x1E, 0x00, 0x03, 0x80, 0x67, 0x42, 0x31, 0x28, 0x73, 0x38, 0x01, 0x84, 0x08, 0x8C, 0xC1, + 0x97, 0xB0, 0xE2, 0xC9, 0xE8, 0xE9, 0xB4, 0x1F, 0x40, 0x83, 0x08, 0x08, 0x41, 0xC0, 0x20, 0x00, + 0x80, 0x1C, 0x80, 0x27, 0xF2, 0x02, 0xF3, 0x01, 0x49, 0xFF, 0xFF, 0x3F, 0x5A, 0x08, 0x0F, 0xE8, + 0xF1, 0x07, 0x02, 0x2F, 0x80, 0x0D, 0x02, 0x0F, 0x80, 0x08, 0x40, 0x01, 0x04, 0x1A, 0xF1, 0x03, + 0xF2, 0x05, 0x96, 0x03, 0xE2, 0x22, 0xE8, 0xE4, 0xB4, 0x3F, 0xF3, 0x03, 0x38, 0x10, 0xA0, 0x11, + 0x58, 0x21, 0x80, 0x20, 0xE0, 0x20, 0x80, 0x23, 0x8C, 0x21, 0xE9, 0xDA, 0x00, 0x3E, 0x00, 0x02, + 0x00, 0x0E, 0x00, 0x03, 0x80, 0x87, 0x42, 0x41, 0xA8, 0x73, 0x96, 0x48, 0xF1, 0x83, 0x38, 0x22, + 0x00, 0x08, 0xD5, 0xCE, 0xFC, 0x41, 0x80, 0xC0, 0xB4, 0x00, 0x81, 0x21, 0xEB, 0x95, 0xEA, 0xA0, + 0xA0, 0x31, 0xEB, 0x95, 0xEB, 0x0F, 0x50, 0x73, 0x00, 0x08, 0xA0, 0x32, 0xEB, 0x95, 0x10, 0x0F, + 0x80, 0x06, 0xA0, 0x39, 0xEB, 0x95, 0xEA, 0x8E, 0x00, 0x1F, 0x80, 0x04, 0xE6, 0x2F, 0xE8, 0x0E, + 0xEB, 0x0E, 0xE6, 0x0F, 0xE8, 0x0B, 0x88, 0x01, 0x5A, 0x00, 0x1C, 0x09, 0x00, 0x1F, 0x80, 0x06, + 0x00, 0x0F, 0x80, 0x05, 0x88, 0x01, 0xE4, 0x1C, 0xE9, 0x25, 0x80, 0xA6, 0x84, 0x20, 0xB0, 0x01, + 0x98, 0x81, 0x50, 0x32, 0x80, 0x08, 0xB4, 0x05, 0x84, 0x81, 0x4E, 0x04, 0x00, 0x03, 0x84, 0x9F, + 0x4E, 0x04, 0x00, 0x03, 0xFE, 0x02, 0x90, 0x01, 0xFE, 0x24, 0xAA, 0x29, 0xA6, 0x10, 0xE4, 0x02, + 0xE9, 0x07, 0x5E, 0xF0, 0x00, 0x22, 0xE8, 0x06, 0x8E, 0x01, 0x96, 0x00, 0xD5, 0x04, 0x84, 0x01, + 0xD5, 0x02, 0xFA, 0x10, 0x18, 0x01, 0x00, 0x01, 0xDB, 0xE7, 0x8C, 0x22, 0x5A, 0x18, 0x04, 0xE1, + 0xD5, 0xCC, 0xB4, 0x66, 0xA0, 0xB9, 0xFE, 0x1A, 0xA0, 0x71, 0xA1, 0x32, 0x40, 0xA0, 0x08, 0x01, + 0x42, 0x01, 0x88, 0x24, 0x42, 0x02, 0x04, 0x75, 0x84, 0x3C, 0xFE, 0x0C, 0x42, 0x05, 0x28, 0x73, + 0x4E, 0x04, 0x00, 0x04, 0x84, 0x00, 0xFC, 0xC1, 0xCB, 0x06, 0xEA, 0xB8, 0xB6, 0x69, 0x14, 0x04, + 0x80, 0x01, 0xD5, 0x2D, 0xCA, 0x06, 0xEA, 0xB8, 0xB6, 0x09, 0x14, 0x24, 0x80, 0x01, 0xD5, 0x27, + 0xEA, 0xBE, 0xA0, 0xF1, 0x8A, 0x0A, 0xFF, 0x5A, 0x90, 0x01, 0x4E, 0x55, 0x00, 0x03, 0x80, 0x65, + 0xB4, 0x26, 0x8A, 0x20, 0x80, 0x41, 0x4E, 0x14, 0x00, 0x03, 0xFE, 0x8A, 0xA1, 0xB2, 0x88, 0x43, + 0xFF, 0x32, 0x4E, 0x45, 0x00, 0x03, 0x80, 0xC4, 0x04, 0xA3, 0x80, 0x01, 0x40, 0x05, 0x00, 0x01, + 0x80, 0x60, 0x4E, 0x04, 0x00, 0x03, 0xFE, 0xC2, 0x88, 0x66, 0xE0, 0x62, 0xE8, 0x05, 0xB6, 0xA9, + 0x14, 0x14, 0x80, 0x01, 0xD5, 0x04, 0xB6, 0x09, 0x14, 0x44, 0x80, 0x01, 0xB4, 0x09, 0xC8, 0x04, + 0x04, 0x04, 0x80, 0x01, 0xC0, 0xC8, 0x84, 0x01, 0xFC, 0xC1, 0xFC, 0x40, 0xB4, 0x81, 0xB5, 0x00, + 0xA1, 0x81, 0xA0, 0x09, 0xA0, 0x4A, 0xC4, 0x06, 0x44, 0xA0, 0x7F, 0xFF, 0xFA, 0xA0, 0x80, 0xEA, + 0xD5, 0x24, 0xC8, 0xFB, 0xFC, 0xC0, 0xE1, 0x49, 0xE8, 0x26, 0x85, 0xFF, 0x4E, 0x45, 0x00, 0x03, + 0x85, 0xE1, 0x40, 0x44, 0x84, 0x0A, 0x42, 0x47, 0x90, 0x24, 0x85, 0x21, 0x4E, 0x04, 0x00, 0x03, + 0x85, 0x3F, 0x4E, 0x04, 0x00, 0x03, 0xFE, 0x02, 0x90, 0x01, 0x42, 0x04, 0x80, 0x24, 0x85, 0x21, + 0x4E, 0x14, 0x00, 0x03, 0x85, 0x3F, 0x4E, 0x14, 0x00, 0x03, 0xFE, 0x4A, 0x8E, 0xA1, 0x90, 0x21, + 0x97, 0x68, 0x42, 0x14, 0x84, 0x24, 0xC5, 0x0E, 0x81, 0x24, 0x4E, 0x44, 0xFF, 0xDE, 0x52, 0x92, + 0x00, 0x00, 0xD5, 0xDA, 0x81, 0xE0, 0x4E, 0x04, 0x00, 0x04, 0x52, 0xF0, 0x00, 0x00, 0xE0, 0xEF, + 0xE9, 0xD5, 0xFF, 0x84, 0x42, 0x62, 0x20, 0x73, 0xFE, 0x04, 0x88, 0xC1, 0x42, 0x02, 0x10, 0x73, + 0x81, 0x22, 0x80, 0xE3, 0xEA, 0xBE, 0x84, 0x41, 0x4E, 0x64, 0x00, 0x03, 0x84, 0x5F, 0x10, 0x24, + 0x80, 0x00, 0x80, 0x26, 0x4E, 0x64, 0x00, 0x03, 0xFE, 0x72, 0xEA, 0x53, 0x40, 0x00, 0x94, 0x0A, + 0x96, 0x02, 0xB6, 0x27, 0xFE, 0x04, 0xFC, 0xC0, 0xFC, 0x4C, 0x87, 0x80, 0x50, 0x8F, 0x80, 0x50, + 0x80, 0xC0, 0x81, 0x21, 0xF2, 0x85, 0x80, 0x3C, 0xFA, 0x40, 0x80, 0x08, 0x81, 0x43, 0x80, 0xE4, + 0x15, 0xCF, 0x80, 0x08, 0xDD, 0x40, 0x80, 0x3C, 0xB0, 0x09, 0x84, 0x46, 0xDD, 0x40, 0x80, 0x3C, + 0x3C, 0x03, 0x79, 0xD4, 0x80, 0xA6, 0x92, 0x01, 0xF0, 0x82, 0x45, 0xC2, 0x13, 0xD8, 0xEA, 0x6F, + 0x45, 0xE2, 0x13, 0x90, 0x92, 0x01, 0xF0, 0x83, 0x40, 0x04, 0x88, 0x08, 0x40, 0x93, 0x00, 0x00, + 0x4C, 0x54, 0x80, 0x3F, 0xA6, 0x2B, 0x22, 0x22, 0x80, 0x00, 0xF4, 0x02, 0x38, 0x3E, 0x01, 0x01, + 0x88, 0x22, 0x8A, 0x6A, 0xF3, 0x8F, 0xA6, 0x2A, 0xE0, 0x83, 0x38, 0x0F, 0x01, 0x01, 0x8A, 0x07, + 0xF0, 0x90, 0xE9, 0x2C, 0xF3, 0x03, 0xE0, 0x60, 0xE9, 0x29, 0x40, 0xF1, 0x14, 0x0A, 0x84, 0x80, + 0xB0, 0x0F, 0xB0, 0x94, 0x38, 0x00, 0x12, 0x02, 0x84, 0x60, 0xF0, 0x84, 0x94, 0x23, 0x88, 0x02, + 0xF0, 0x81, 0xB0, 0x8F, 0xF0, 0x04, 0x38, 0x21, 0x0E, 0x02, 0xFE, 0x84, 0x4E, 0x27, 0x00, 0x04, + 0x90, 0x48, 0xD5, 0x04, 0xFE, 0x92, 0x90, 0x48, 0xFE, 0x92, 0xF0, 0x01, 0xB4, 0x00, 0x42, 0x01, + 0x3C, 0x73, 0x80, 0x40, 0xF0, 0x01, 0xAA, 0x81, 0xF0, 0x81, 0x5A, 0x30, 0x01, 0x04, 0x84, 0x61, + 0xD5, 0xE9, 0x5A, 0x40, 0x01, 0x04, 0x80, 0x83, 0xD5, 0xDC, 0x8C, 0xA4, 0xD5, 0xC2, 0x90, 0x25, + 0x4E, 0x16, 0x00, 0x03, 0x84, 0x21, 0xF0, 0x14, 0xDD, 0x5C, 0xF0, 0x94, 0x80, 0x48, 0xA0, 0x11, + 0xDD, 0x5C, 0xA8, 0x11, 0xA0, 0x12, 0xDD, 0x5C, 0xA8, 0x12, 0xA0, 0x13, 0x40, 0x10, 0x04, 0x36, + 0xA8, 0x53, 0x80, 0x08, 0xB0, 0x4B, 0x49, 0xFF, 0xFE, 0x9F, 0x5A, 0x08, 0x01, 0x18, 0xF1, 0x0B, + 0x10, 0x0F, 0x80, 0x28, 0xF4, 0x0C, 0xFE, 0x0A, 0xC9, 0x16, 0xCC, 0x15, 0xD5, 0x0F, 0x40, 0x03, + 0xA8, 0x16, 0xEA, 0xBE, 0x44, 0x20, 0x00, 0x6E, 0x2E, 0x17, 0xD8, 0x76, 0xEB, 0x69, 0x96, 0x89, + 0xEA, 0x6F, 0xE2, 0x02, 0xEA, 0xD5, 0x12, 0x0F, 0x80, 0x13, 0xF0, 0x05, 0xB0, 0x49, 0x84, 0x46, + 0xDD, 0x55, 0xFC, 0xCC, 0xFF, 0xE4, 0x42, 0x70, 0x28, 0x75, 0xFE, 0x62, 0xF7, 0x93, 0x84, 0xE0, + 0xF0, 0x91, 0xF1, 0x92, 0x81, 0x47, 0x45, 0xC2, 0x13, 0xD8, 0x44, 0x82, 0x13, 0x90, 0x4C, 0x64, + 0xBF, 0xE0, 0x22, 0x03, 0x00, 0x00, 0xB0, 0x51, 0x89, 0x40, 0xA6, 0x33, 0x50, 0x2F, 0x80, 0x1F, + 0xB0, 0xC8, 0x38, 0x0E, 0x01, 0x01, 0xF0, 0x8D, 0xA6, 0x32, 0x38, 0x04, 0x01, 0x01, 0xF0, 0x8E, + 0xB0, 0x0D, 0x49, 0xFF, 0xFE, 0xF4, 0x2A, 0x13, 0x00, 0x02, 0x42, 0x70, 0x04, 0x73, 0xD5, 0xE8, + 0x44, 0x32, 0x07, 0x00, 0x44, 0x12, 0x4B, 0xC0, 0x84, 0x40, 0x80, 0x83, 0x99, 0x62, 0x5A, 0x08, + 0x02, 0x09, 0x00, 0x52, 0x80, 0x7C, 0xAD, 0x48, 0x02, 0x51, 0x80, 0x3A, 0xAD, 0x49, 0xD5, 0x07, + 0x00, 0x52, 0x80, 0x70, 0xAD, 0x48, 0x02, 0x51, 0x80, 0x34, 0xAD, 0x49, 0x8C, 0x41, 0x8C, 0x24, + 0x8C, 0x62, 0x5A, 0x28, 0x04, 0xED, 0xDD, 0x9E, 0xFC, 0x40, 0x3C, 0x73, 0xEF, 0x78, 0x3C, 0x97, + 0xF7, 0x11, 0x97, 0xEE, 0x97, 0xF9, 0x3C, 0x64, 0x0B, 0xA5, 0x44, 0x82, 0x4B, 0xC0, 0xCF, 0x10, + 0x81, 0x41, 0x83, 0x80, 0xDD, 0x41, 0x5A, 0x00, 0x01, 0x0C, 0x89, 0x5C, 0xE5, 0x44, 0xE9, 0x04, + 0x3C, 0x04, 0x0B, 0xAB, 0xFC, 0xC0, 0x3C, 0x04, 0x0B, 0xA4, 0xE0, 0x09, 0xE9, 0x04, 0x3C, 0x04, + 0x0B, 0xA5, 0xFC, 0xC0, 0x84, 0x61, 0x80, 0x27, 0x81, 0x48, 0x38, 0x04, 0x06, 0x11, 0x95, 0x0A, + 0xE0, 0x09, 0x44, 0x72, 0x4B, 0xC0, 0xE8, 0x17, 0x38, 0x25, 0x0E, 0x11, 0x95, 0x5A, 0xE0, 0x49, + 0xE9, 0x12, 0x88, 0x87, 0x88, 0xA7, 0x22, 0x12, 0x00, 0x01, 0x8A, 0x49, 0x22, 0x52, 0x80, 0x01, + 0x40, 0x34, 0x80, 0x01, 0x42, 0x01, 0x04, 0x24, 0x42, 0x01, 0x94, 0x73, 0x80, 0x20, 0x98, 0x1A, + 0xEB, 0x88, 0xD5, 0x06, 0x8C, 0x21, 0x8C, 0x61, 0x5A, 0x18, 0x03, 0xE1, 0x80, 0x06, 0x96, 0x03, + 0xFC, 0xC0, 0x44, 0x12, 0x49, 0xAC, 0x5A, 0x08, 0x02, 0x05, 0x44, 0x02, 0x07, 0x40, 0xD5, 0x03, + 0x44, 0x02, 0x07, 0x20, 0xEA, 0x4D, 0xEA, 0x9F, 0x3A, 0x20, 0x0C, 0x00, 0x3A, 0x20, 0x8C, 0x20, + 0xDD, 0x9E, 0xFC, 0x40, 0x51, 0xFF, 0xFA, 0xF0, 0x84, 0x00, 0xF1, 0x8B, 0xF2, 0x8A, 0x10, 0x0F, + 0x80, 0x7B, 0x84, 0x20, 0x44, 0x20, 0x00, 0xF0, 0xEA, 0xFC, 0xF3, 0x8F, 0xF5, 0x95, 0xDD, 0x40, + 0x84, 0x20, 0x44, 0x20, 0x01, 0xE4, 0x50, 0x0F, 0x83, 0x2C, 0xDD, 0x40, 0xB0, 0x33, 0x84, 0x20, + 0x44, 0x20, 0x00, 0xB0, 0xDD, 0x40, 0x3C, 0x07, 0xF6, 0xEE, 0xC8, 0x04, 0x02, 0x0F, 0x80, 0x2A, + 0xEB, 0xBB, 0x84, 0x20, 0x44, 0x20, 0x00, 0x66, 0x44, 0x02, 0x4B, 0x58, 0xDD, 0x40, 0x84, 0x00, + 0x3E, 0x07, 0xEC, 0x0D, 0x3E, 0x07, 0xEC, 0x0C, 0x84, 0x1F, 0x3E, 0x07, 0xEC, 0x0B, 0x84, 0x00, + 0x3C, 0x0B, 0xF6, 0x10, 0x44, 0x12, 0x4C, 0xAC, 0xF0, 0x0B, 0xF2, 0x0A, 0xB0, 0xDF, 0x50, 0x4F, + 0x80, 0x7D, 0x3C, 0x67, 0xF8, 0x07, 0x3C, 0x74, 0x0A, 0xA6, 0x49, 0xFF, 0xEA, 0xAD, 0x4E, 0x02, + 0x01, 0x84, 0x84, 0x02, 0x40, 0x03, 0x00, 0x16, 0xE0, 0x07, 0x40, 0x03, 0xBC, 0x1B, 0xF0, 0x99, + 0x84, 0x00, 0xF0, 0x8E, 0xF0, 0x8D, 0x85, 0x48, 0xF0, 0x8A, 0x83, 0x80, 0xF0, 0x8C, 0xF1, 0x0C, + 0xEA, 0xBB, 0xE2, 0x20, 0x4E, 0xF2, 0x01, 0x74, 0xF1, 0x0C, 0x44, 0x02, 0x4F, 0xBC, 0x38, 0x00, + 0x05, 0x00, 0xF0, 0x90, 0x94, 0x09, 0x44, 0x12, 0x4F, 0xBC, 0x88, 0x01, 0xF0, 0x9D, 0xF0, 0x1D, + 0xF1, 0x10, 0xA6, 0x01, 0xE2, 0x20, 0x4E, 0xF2, 0x01, 0x57, 0xEB, 0xA6, 0xEA, 0x3E, 0xF1, 0x0C, + 0xF0, 0x91, 0xF0, 0x10, 0xF2, 0x11, 0x88, 0x04, 0xEA, 0xB7, 0xA6, 0x00, 0x96, 0x36, 0x4E, 0x02, + 0x01, 0x43, 0x50, 0x0F, 0x80, 0x7B, 0xF0, 0x81, 0x50, 0x0F, 0x80, 0x7E, 0x84, 0xE0, 0x85, 0x21, + 0xF0, 0x84, 0x50, 0x6F, 0x82, 0x3C, 0xB0, 0x21, 0xF0, 0x89, 0xB6, 0xDF, 0x14, 0xAF, 0x80, 0x02, + 0x14, 0x9F, 0x80, 0x03, 0xF7, 0x85, 0xF7, 0x86, 0xF7, 0x87, 0xF7, 0x88, 0xF0, 0x10, 0x44, 0x20, + 0x00, 0x40, 0xF3, 0x0A, 0xF5, 0x0B, 0x49, 0x00, 0x2B, 0xAD, 0x2E, 0x17, 0xEC, 0x0C, 0x88, 0x29, + 0x3E, 0x17, 0xEC, 0x0C, 0xF1, 0x0F, 0xE0, 0x01, 0x4E, 0xF3, 0x01, 0x1E, 0x00, 0x8F, 0x80, 0x7B, + 0x3E, 0x77, 0xED, 0xF0, 0x4E, 0x83, 0x00, 0x06, 0xEB, 0x4D, 0xE6, 0x06, 0xE9, 0x5B, 0xD5, 0x71, + 0x50, 0x04, 0x7F, 0xFF, 0x3E, 0x07, 0xED, 0xF1, 0x80, 0x29, 0x44, 0x42, 0x22, 0x68, 0x80, 0x46, + 0x4E, 0x15, 0xFF, 0xF4, 0x96, 0x09, 0xF0, 0x93, 0x38, 0x72, 0x04, 0x00, 0x8E, 0x01, 0x96, 0x03, + 0x95, 0x7A, 0x38, 0x92, 0x00, 0x00, 0x98, 0x2A, 0xF0, 0x92, 0x23, 0xE0, 0x00, 0x00, 0x50, 0x04, + 0xFF, 0xFF, 0x96, 0x03, 0x40, 0x34, 0x80, 0x11, 0xE0, 0x67, 0xE8, 0x17, 0x95, 0x9A, 0x88, 0xC2, + 0x22, 0xA3, 0x00, 0x00, 0xE1, 0x5E, 0xE9, 0x0E, 0x8C, 0x01, 0x96, 0x03, 0x40, 0xA0, 0x08, 0x08, + 0x89, 0x42, 0xB4, 0xA6, 0x04, 0xF5, 0x00, 0x00, 0xB6, 0xAA, 0x14, 0xFF, 0x80, 0x5F, 0x14, 0xF3, + 0x00, 0x00, 0x8C, 0x61, 0x96, 0xDB, 0xD5, 0xE9, 0xF3, 0x12, 0x8C, 0x01, 0x95, 0x82, 0xB4, 0x63, + 0x88, 0xC2, 0x96, 0x01, 0xB5, 0x46, 0xB6, 0x66, 0xF3, 0x12, 0x14, 0xAF, 0x80, 0x5F, 0xB7, 0x43, + 0x96, 0xC3, 0x9F, 0x59, 0xE1, 0x25, 0xE9, 0x05, 0xF1, 0x13, 0x8E, 0x22, 0x96, 0x4B, 0xD5, 0x04, + 0x9F, 0x41, 0x38, 0x52, 0x04, 0x08, 0x8C, 0x61, 0xE0, 0x67, 0xE8, 0xBB, 0x96, 0x49, 0x9C, 0xC9, + 0x8C, 0x22, 0x96, 0xDB, 0x96, 0x4B, 0x8C, 0x01, 0x38, 0x02, 0x0C, 0x08, 0x38, 0x72, 0x04, 0x08, + 0xD5, 0xB0, 0xDD, 0x54, 0x96, 0x2E, 0xC0, 0x0C, 0x02, 0x0F, 0x81, 0x1E, 0x80, 0x20, 0x96, 0x03, + 0x5E, 0xF0, 0x05, 0xDD, 0xE9, 0x03, 0x44, 0x10, 0x05, 0xDC, 0x96, 0x4B, 0xD5, 0x03, 0x22, 0x1F, + 0x81, 0x1E, 0x2E, 0x00, 0x15, 0x45, 0xFE, 0x44, 0xDD, 0x4C, 0xEA, 0x53, 0x96, 0x4B, 0xD5, 0x08, + 0x22, 0x1F, 0x81, 0x1E, 0xEB, 0x66, 0xFE, 0x44, 0xDD, 0x4C, 0xEA, 0x53, 0x96, 0x4B, 0x22, 0x7F, + 0x81, 0x1E, 0x3C, 0x37, 0xF6, 0xEE, 0xE0, 0xE3, 0xE8, 0x05, 0xF0, 0x0D, 0x8C, 0x01, 0x96, 0x00, + 0xF0, 0x8D, 0x50, 0x9F, 0x82, 0x3C, 0x80, 0x49, 0x84, 0xA0, 0xEB, 0xA6, 0x44, 0x6F, 0xFF, 0x80, + 0x40, 0x33, 0x8C, 0x07, 0x4C, 0x54, 0x00, 0x15, 0x22, 0x01, 0x00, 0x00, 0xE0, 0x01, 0xE8, 0x02, + 0xC3, 0x0B, 0xA7, 0xD2, 0x04, 0xAF, 0x80, 0x11, 0xA6, 0x13, 0x42, 0x03, 0xA8, 0x73, 0x88, 0x04, + 0xA7, 0xC0, 0xFF, 0xF7, 0xAF, 0xC0, 0x8C, 0xA1, 0x97, 0x68, 0x8C, 0x44, 0xD5, 0xEC, 0x2E, 0x00, + 0x15, 0x4B, 0xE2, 0xA0, 0x4E, 0xF2, 0x02, 0x39, 0xE6, 0xA2, 0x4E, 0xF3, 0x02, 0x36, 0xE6, 0xA6, + 0x80, 0x05, 0xE9, 0x02, 0x84, 0x05, 0x55, 0xE0, 0x00, 0xFF, 0x2E, 0x00, 0x15, 0x4A, 0x84, 0x20, + 0xF0, 0x94, 0x50, 0x0F, 0x7F, 0xFF, 0x80, 0x61, 0x80, 0x41, 0xF0, 0x96, 0xF0, 0x16, 0xE0, 0x40, + 0x4E, 0xF2, 0x02, 0x23, 0x9C, 0x11, 0x96, 0x00, 0xF0, 0x92, 0x94, 0x92, 0xEA, 0xFC, 0x88, 0x40, + 0xF6, 0x12, 0xE2, 0xDE, 0xE8, 0x4E, 0xEA, 0xFC, 0x95, 0x32, 0x88, 0x80, 0xA7, 0xD3, 0xA6, 0x23, + 0x00, 0xA1, 0x00, 0x02, 0x9A, 0x38, 0x96, 0x02, 0xA7, 0x62, 0x81, 0xE0, 0x4E, 0x04, 0x00, 0x04, + 0x52, 0xF0, 0x00, 0x00, 0x5A, 0xF8, 0x01, 0x3B, 0x40, 0x55, 0x14, 0x01, 0x97, 0x6A, 0x81, 0xE5, + 0x4E, 0x54, 0x00, 0x04, 0x52, 0xF2, 0x80, 0x00, 0x5A, 0xF8, 0x01, 0x31, 0x02, 0x81, 0x00, 0x00, + 0xA5, 0x20, 0x14, 0x8F, 0x80, 0x13, 0x22, 0x8F, 0x80, 0x26, 0x40, 0xF2, 0x00, 0x11, 0xE1, 0x0F, + 0x02, 0x8F, 0x80, 0x26, 0x40, 0x44, 0x3C, 0x1A, 0x97, 0x23, 0xC4, 0x18, 0xF1, 0x11, 0x9A, 0x38, + 0x42, 0x05, 0x04, 0x73, 0xF1, 0x0B, 0x40, 0x55, 0x14, 0x01, 0x38, 0x30, 0x81, 0x11, 0xDD, 0x4C, + 0xFE, 0xC4, 0xF0, 0x11, 0x40, 0x31, 0x90, 0x76, 0x42, 0x72, 0x80, 0x73, 0x38, 0x10, 0x9D, 0x11, + 0xDD, 0x4C, 0xFE, 0x44, 0xEB, 0x24, 0x96, 0xDB, 0x96, 0x4B, 0xE0, 0x61, 0x80, 0x03, 0xF4, 0x14, + 0x40, 0x00, 0xBC, 0x1B, 0xE0, 0x04, 0x4E, 0xF3, 0x01, 0xC9, 0x8C, 0xC1, 0x97, 0xB0, 0xD5, 0xB2, + 0xF2, 0x12, 0xD5, 0xA5, 0x81, 0x1C, 0xF0, 0x10, 0x83, 0x88, 0x8C, 0x01, 0x96, 0x00, 0xF0, 0x90, + 0x48, 0xFF, 0xFE, 0xA7, 0xF0, 0x0E, 0x5A, 0x00, 0x01, 0x0B, 0xF0, 0x0C, 0x8C, 0x01, 0x96, 0x00, + 0xF0, 0x8C, 0x48, 0xFF, 0xFE, 0x8E, 0xF0, 0x8D, 0xF0, 0x8A, 0x83, 0x80, 0x84, 0x00, 0x3F, 0xC7, + 0xED, 0xE8, 0x80, 0x20, 0xFA, 0x7C, 0x96, 0x88, 0xE2, 0x5C, 0xE8, 0x0C, 0x50, 0x2F, 0x83, 0x2C, + 0x42, 0x20, 0x8C, 0x73, 0x00, 0x21, 0x00, 0x22, 0x8C, 0x21, 0xE2, 0x02, 0x40, 0x01, 0x3C, 0x1B, + 0xD5, 0xF3, 0x3C, 0x0B, 0xF8, 0x26, 0x5B, 0xC8, 0x01, 0x47, 0x2E, 0x10, 0x15, 0x5A, 0xE2, 0x20, + 0xE8, 0x42, 0x3C, 0x37, 0xF8, 0x07, 0x84, 0x03, 0x94, 0xD9, 0x40, 0x31, 0x80, 0x76, 0x00, 0x1F, + 0x83, 0x2C, 0x00, 0x0F, 0x83, 0x2D, 0x00, 0x2F, 0x83, 0x2F, 0x88, 0x20, 0x00, 0x0F, 0x83, 0x2E, + 0x90, 0x21, 0x88, 0x40, 0xEB, 0x5B, 0x90, 0x41, 0x3C, 0x0B, 0xEF, 0x4E, 0x84, 0x00, 0x9F, 0x91, + 0x3E, 0x07, 0xEC, 0x0E, 0x9E, 0x09, 0x96, 0xDB, 0x96, 0x00, 0x2E, 0x96, 0xF3, 0xAE, 0x84, 0xA0, + 0x8C, 0x21, 0x97, 0xB0, 0x8C, 0x41, 0xE0, 0x20, 0xE9, 0x1B, 0x80, 0x86, 0xE0, 0x44, 0xE9, 0x15, + 0x80, 0xE0, 0x04, 0xAF, 0x80, 0x0B, 0x42, 0x72, 0x24, 0x73, 0x38, 0x75, 0x1D, 0x11, 0xE0, 0x67, + 0xE8, 0x03, 0x8C, 0xA1, 0x97, 0x68, 0x3C, 0xF7, 0xEF, 0x4E, 0xE0, 0xEF, 0xE8, 0x03, 0x3C, 0x7B, + 0xEF, 0x4E, 0x8C, 0x81, 0x97, 0x20, 0xD5, 0xEB, 0x8C, 0x01, 0x96, 0x00, 0xD5, 0xE5, 0x3E, 0x57, + 0xEC, 0x0E, 0xD5, 0x07, 0x84, 0x00, 0x3E, 0x07, 0xEC, 0x0E, 0xEB, 0x5B, 0x3C, 0x0B, 0xEF, 0x4E, + 0x3C, 0x03, 0xF6, 0xD9, 0x49, 0x00, 0x0F, 0xAC, 0x3E, 0x07, 0xEC, 0x0D, 0x00, 0x0F, 0x80, 0x7C, + 0x85, 0x00, 0xF0, 0x8B, 0x00, 0x0F, 0x80, 0x7D, 0x50, 0xAF, 0x80, 0xCC, 0xF0, 0x8C, 0x81, 0x28, + 0x2E, 0x76, 0xF3, 0xAF, 0x80, 0xC8, 0x8E, 0xE1, 0xF1, 0x0A, 0x54, 0x04, 0x00, 0xFF, 0xE2, 0x01, + 0xE8, 0x39, 0x00, 0x55, 0x00, 0x03, 0xDF, 0x04, 0xEB, 0x8E, 0xDD, 0x4B, 0xEB, 0x9D, 0x00, 0x55, + 0x00, 0x01, 0xEA, 0x3E, 0x8E, 0x01, 0xD8, 0x04, 0xEB, 0x8E, 0xEA, 0x39, 0xEB, 0x9D, 0x00, 0x05, + 0x00, 0x02, 0xC8, 0x04, 0xEB, 0x8E, 0xEA, 0xA5, 0xEB, 0x9D, 0x00, 0x05, 0x00, 0x00, 0xC8, 0x04, + 0xEB, 0x8E, 0xEB, 0x6A, 0xEB, 0x9D, 0xFA, 0x1C, 0x50, 0x1F, 0x83, 0x2C, 0x42, 0x14, 0x00, 0x73, + 0x80, 0x01, 0xF1, 0x8E, 0x49, 0x00, 0x17, 0x2D, 0xE6, 0x06, 0xF1, 0x0E, 0xE8, 0x0D, 0x80, 0x01, + 0x49, 0x00, 0x17, 0x31, 0xE6, 0x06, 0xE8, 0x08, 0x00, 0x05, 0x00, 0x0A, 0xE6, 0x03, 0xE8, 0x04, + 0x8C, 0xC1, 0x97, 0xB0, 0xD5, 0x04, 0x50, 0x14, 0x80, 0x01, 0xEB, 0x8D, 0x8D, 0x01, 0x8D, 0x50, + 0xD5, 0xC4, 0x2E, 0x77, 0xF0, 0x13, 0x84, 0x00, 0xCF, 0x0E, 0xEA, 0x2E, 0xEA, 0x67, 0x96, 0x09, + 0xC8, 0x09, 0xEA, 0x2E, 0x96, 0x4E, 0xC9, 0x07, 0x80, 0x06, 0x80, 0x29, 0x49, 0xFF, 0xFD, 0x26, + 0xD5, 0x02, 0x80, 0x07, 0xF1, 0x0F, 0x50, 0x6F, 0x83, 0x2C, 0x98, 0x81, 0x84, 0x63, 0x90, 0x01, + 0xFE, 0xD4, 0x99, 0xC1, 0x80, 0xA6, 0xFA, 0x1C, 0x40, 0x81, 0x84, 0x0A, 0x42, 0x5E, 0x00, 0x73, + 0x81, 0x26, 0x84, 0x80, 0x4C, 0x92, 0x80, 0x46, 0xEA, 0x2E, 0x00, 0x04, 0x80, 0x27, 0xEA, 0x67, + 0xC9, 0x31, 0xF1, 0x0C, 0xE6, 0x2A, 0xE9, 0x09, 0x94, 0x44, 0x50, 0x3F, 0x85, 0x10, 0x88, 0x23, + 0x00, 0x10, 0xFB, 0xC8, 0x96, 0x46, 0xC9, 0x0E, 0xF1, 0x0B, 0xE6, 0x2D, 0xE9, 0x0E, 0x94, 0x04, + 0x50, 0x1F, 0x85, 0x10, 0x88, 0x01, 0x81, 0x48, 0x00, 0x00, 0x7B, 0xC8, 0x40, 0xA1, 0x00, 0x1A, + 0xD5, 0x05, 0x44, 0xA0, 0x01, 0xF4, 0xD5, 0x02, 0x81, 0x42, 0x00, 0x04, 0x80, 0x20, 0x00, 0x14, + 0x80, 0x21, 0xF4, 0x90, 0xF2, 0x8E, 0xF5, 0x8A, 0xEA, 0x64, 0x40, 0xA3, 0x80, 0x1B, 0x22, 0x04, + 0x80, 0x0E, 0xF5, 0x0A, 0xE0, 0x0A, 0xF2, 0x0E, 0xF4, 0x10, 0xE8, 0x0E, 0x10, 0x44, 0x80, 0x23, + 0xD5, 0x0B, 0x22, 0x04, 0x80, 0x0E, 0xF1, 0x0F, 0xE0, 0x01, 0xE8, 0x05, 0x10, 0x44, 0x80, 0x23, + 0x81, 0x42, 0xD5, 0x02, 0x81, 0x42, 0x12, 0xA4, 0x80, 0x15, 0x50, 0x94, 0x80, 0x2C, 0xD5, 0xBB, + 0x44, 0x10, 0x00, 0xFF, 0xEA, 0x4E, 0x3C, 0x7C, 0x05, 0x4D, 0xF0, 0x8A, 0xF2, 0x0A, 0x44, 0x02, + 0x4B, 0xFC, 0xDD, 0x40, 0x5B, 0xC8, 0x02, 0x07, 0x95, 0xFA, 0x84, 0x05, 0x40, 0x73, 0x80, 0xF6, + 0xD5, 0x0F, 0x50, 0x0E, 0x7F, 0xFD, 0x96, 0x00, 0xE6, 0x03, 0xE8, 0x06, 0x95, 0xF9, 0x84, 0x03, + 0x40, 0x73, 0x80, 0xF6, 0xD5, 0x05, 0x5C, 0xFE, 0x00, 0x06, 0xE9, 0x02, 0x90, 0xE1, 0x94, 0x39, + 0x84, 0x23, 0xDD, 0x5C, 0xF0, 0x8B, 0x85, 0x40, 0xEA, 0x3E, 0x40, 0x83, 0x84, 0x0A, 0x8E, 0x01, + 0x81, 0x2A, 0xF0, 0x8C, 0x54, 0x05, 0x00, 0xFF, 0xE2, 0x1C, 0xE8, 0x52, 0x02, 0x03, 0x00, 0x10, + 0xC0, 0x18, 0x00, 0x03, 0x00, 0x20, 0x00, 0x13, 0x00, 0x21, 0xC8, 0x05, 0xEA, 0xE1, 0x8E, 0x41, + 0x4C, 0x11, 0x00, 0x10, 0xF2, 0x0C, 0x4C, 0x01, 0x40, 0x07, 0xC1, 0x0B, 0xEA, 0xE1, 0x8E, 0x41, + 0x4C, 0x11, 0x00, 0x08, 0xEA, 0x64, 0xF1, 0x0B, 0x40, 0x13, 0x80, 0x1A, 0x80, 0x01, 0xD5, 0x02, + 0x80, 0x08, 0xA0, 0x76, 0xE0, 0x20, 0xE8, 0x06, 0xDD, 0x54, 0x92, 0x09, 0x54, 0xF0, 0x00, 0x01, + 0xD5, 0x02, 0x85, 0xE1, 0x00, 0x03, 0x00, 0x23, 0xC0, 0x27, 0x5A, 0xF8, 0x01, 0x26, 0xFA, 0x1C, + 0xEA, 0x41, 0x42, 0x14, 0x80, 0x73, 0x9C, 0x0C, 0x83, 0xC0, 0x80, 0x06, 0xEA, 0x4D, 0x3A, 0x2F, + 0x14, 0x24, 0xEA, 0x4D, 0x3A, 0x2F, 0x14, 0x24, 0x3A, 0x20, 0x10, 0x00, 0x84, 0x1F, 0x3A, 0x2F, + 0x10, 0x20, 0x10, 0x00, 0x80, 0x28, 0x44, 0x02, 0x4B, 0xFC, 0x10, 0xF0, 0x80, 0x29, 0x38, 0x90, + 0x28, 0x08, 0xF0, 0x0A, 0x10, 0xA0, 0x80, 0x22, 0xE1, 0x20, 0xE8, 0x04, 0xEA, 0x7C, 0xEA, 0x82, + 0xD5, 0x03, 0x04, 0x9F, 0x80, 0x0A, 0x8D, 0x41, 0x50, 0x63, 0x00, 0x2C, 0xD5, 0xAC, 0xF0, 0x0D, + 0x3E, 0x97, 0xEE, 0x20, 0xC0, 0x0D, 0x2E, 0x00, 0x15, 0x48, 0xF1, 0x15, 0x50, 0x00, 0x00, 0x64, + 0xFE, 0x44, 0x80, 0x01, 0xEA, 0x92, 0xDD, 0x5C, 0xEB, 0xBB, 0x48, 0x00, 0x02, 0x65, 0x02, 0x0F, + 0x80, 0x2A, 0xEB, 0xBB, 0x48, 0x00, 0x02, 0x60, 0x00, 0x0F, 0x82, 0x3E, 0xE6, 0x02, 0xE9, 0x04, + 0xDD, 0x41, 0x85, 0x44, 0xC0, 0x02, 0x85, 0x48, 0x81, 0x1C, 0x84, 0xC0, 0x50, 0x7F, 0x82, 0x3C, + 0xEB, 0xF9, 0xE2, 0xC0, 0xE8, 0x32, 0x94, 0x72, 0x88, 0x27, 0x44, 0x22, 0x4C, 0xAC, 0xA6, 0x0B, + 0xF3, 0x11, 0xA6, 0x4A, 0x88, 0x40, 0x42, 0x20, 0x8C, 0x73, 0x20, 0x21, 0x00, 0x00, 0x4E, 0x24, + 0x00, 0x20, 0x50, 0x2F, 0x80, 0x7B, 0x58, 0x34, 0x00, 0x20, 0xF2, 0x81, 0x50, 0x4F, 0x80, 0x7E, + 0x84, 0x40, 0xF2, 0x83, 0xF4, 0x84, 0xF2, 0x85, 0xF2, 0x86, 0xF2, 0x87, 0xF2, 0x88, 0xF2, 0x89, + 0xB6, 0xFF, 0x14, 0xAF, 0x80, 0x02, 0x44, 0x20, 0x00, 0x80, 0x96, 0xD8, 0xEB, 0xA6, 0xF5, 0x0B, + 0x49, 0x00, 0x28, 0x90, 0xEB, 0x02, 0xEA, 0x71, 0xEA, 0x4E, 0xE3, 0x00, 0xE8, 0x04, 0x8C, 0xC1, + 0x97, 0xB0, 0xD5, 0xCF, 0x84, 0x01, 0xF0, 0x8E, 0x40, 0x04, 0x70, 0x01, 0x5A, 0x08, 0x01, 0x1A, + 0xEB, 0x4D, 0xE6, 0x06, 0xE9, 0x16, 0x00, 0x2F, 0x80, 0x7B, 0xEB, 0xFC, 0x84, 0xA0, 0xEA, 0xFC, + 0xEB, 0xA6, 0x58, 0x6E, 0x00, 0x20, 0x8C, 0x04, 0xD2, 0x20, 0x00, 0x10, 0x7F, 0xFF, 0x00, 0x70, + 0x7F, 0xFE, 0x88, 0x24, 0x42, 0x13, 0x8C, 0x73, 0x8C, 0xA1, 0xAF, 0x88, 0x97, 0x68, 0xD5, 0xF4, + 0xF0, 0x0F, 0x80, 0x88, 0xB6, 0x1F, 0x3C, 0x07, 0xF6, 0xEE, 0x00, 0x3F, 0x80, 0x7B, 0xF0, 0x82, + 0x14, 0xAF, 0x80, 0x01, 0xF0, 0x0B, 0x44, 0x12, 0x4C, 0xAC, 0x50, 0x2F, 0x82, 0x3C, 0x44, 0x52, + 0x4B, 0x58, 0x49, 0xFF, 0xF9, 0x90, 0x81, 0x00, 0xEB, 0xF9, 0x44, 0x11, 0x29, 0x28, 0xF0, 0x92, + 0xB0, 0x24, 0xEA, 0x70, 0xEA, 0x5C, 0x84, 0x20, 0xEA, 0xBB, 0x44, 0x20, 0x00, 0xC0, 0xF0, 0x98, + 0xEB, 0x98, 0xDD, 0x40, 0x84, 0x20, 0xB0, 0x28, 0xFA, 0x5C, 0xDD, 0x40, 0xF0, 0x12, 0x50, 0x1F, + 0x82, 0x3C, 0x94, 0x02, 0x88, 0x01, 0xF0, 0x9B, 0x84, 0x00, 0xF0, 0x93, 0xEA, 0x3E, 0xF0, 0x94, + 0xF0, 0x1B, 0x4C, 0x90, 0x01, 0x17, 0xEB, 0xE6, 0x44, 0x22, 0x4C, 0xAC, 0x88, 0x02, 0x00, 0x14, + 0x80, 0x02, 0xF2, 0x14, 0xEA, 0xB7, 0xA7, 0xC0, 0x54, 0x03, 0x80, 0x20, 0x4E, 0x02, 0x01, 0x07, + 0x5A, 0x78, 0x2F, 0x04, 0x48, 0x00, 0x00, 0xC1, 0x97, 0xDF, 0xE6, 0xEB, 0x4E, 0xF2, 0x00, 0xFF, + 0xFA, 0x1C, 0x50, 0x6F, 0x83, 0x2C, 0x42, 0x63, 0x80, 0x73, 0xF0, 0x12, 0x5C, 0xF0, 0x00, 0x2D, + 0xE8, 0x03, 0xE7, 0x03, 0xE9, 0x05, 0x94, 0x3C, 0xEB, 0x42, 0xEB, 0xCE, 0xC8, 0x71, 0x94, 0x3C, + 0xEB, 0x42, 0xEB, 0x83, 0x84, 0x04, 0xC9, 0x03, 0x80, 0x0A, 0xF1, 0x93, 0x8E, 0x01, 0x50, 0x1F, + 0x80, 0x91, 0x96, 0x00, 0xF1, 0x91, 0x94, 0x01, 0x50, 0x1F, 0x85, 0x10, 0x88, 0x01, 0x50, 0x00, + 0x7B, 0x83, 0xF0, 0x9A, 0x94, 0x3C, 0xF0, 0x96, 0xEB, 0x42, 0x8C, 0x08, 0x88, 0x01, 0xF0, 0x97, + 0x8C, 0x04, 0xF0, 0x9C, 0xF0, 0x11, 0x00, 0x24, 0x80, 0x02, 0x00, 0x10, 0x7F, 0xFF, 0xEB, 0xE6, + 0x88, 0x20, 0xF0, 0x11, 0x96, 0x4A, 0x20, 0x00, 0x00, 0x00, 0x4E, 0x15, 0x00, 0x45, 0xF3, 0x14, + 0xE0, 0x23, 0xE8, 0x41, 0x88, 0x02, 0x96, 0x02, 0x4E, 0x05, 0x00, 0x3E, 0xF2, 0x18, 0xE0, 0x02, + 0xE8, 0x3A, 0xF2, 0x16, 0x50, 0x3F, 0x81, 0x7C, 0x38, 0x21, 0x88, 0x00, 0xCA, 0x0E, 0xF3, 0x14, + 0x80, 0x41, 0xEA, 0xEA, 0xF3, 0x0B, 0x38, 0x21, 0x89, 0x11, 0xA0, 0xF6, 0x88, 0x43, 0xA8, 0xB6, + 0xF2, 0x13, 0x8C, 0x41, 0x96, 0x90, 0xF2, 0x93, 0x2E, 0x20, 0x1B, 0xB8, 0xE6, 0x44, 0xE8, 0x23, + 0xF3, 0x14, 0x80, 0x41, 0xEA, 0xEA, 0x44, 0x32, 0x4C, 0xAC, 0x88, 0x62, 0xA7, 0x18, 0x5A, 0x48, + 0x0F, 0x1B, 0xFA, 0x8F, 0xAF, 0x18, 0xF3, 0x0B, 0x38, 0x51, 0x89, 0x11, 0x8E, 0xB4, 0x4E, 0x57, + 0x00, 0x13, 0xF3, 0x16, 0x50, 0x2F, 0x81, 0x7C, 0x88, 0x62, 0x50, 0x4F, 0x80, 0x82, 0xA0, 0x99, + 0x88, 0x45, 0xA8, 0x99, 0xB6, 0x3F, 0xF0, 0x81, 0xF1, 0x17, 0x84, 0x01, 0xF2, 0x1C, 0xB0, 0xE0, + 0x49, 0xFF, 0xF7, 0xCF, 0xF5, 0x11, 0xF1, 0x1A, 0x8C, 0xA2, 0xF5, 0x91, 0xD9, 0xAC, 0x94, 0x3C, + 0xEB, 0x42, 0x98, 0xC8, 0xA6, 0x18, 0xC8, 0x22, 0x22, 0x04, 0x80, 0x00, 0xF1, 0x13, 0xA1, 0x36, + 0x42, 0x50, 0x04, 0x24, 0x44, 0x20, 0x03, 0xE8, 0x9A, 0x6C, 0xFE, 0x54, 0x40, 0x10, 0x94, 0x36, + 0x00, 0x24, 0x80, 0x03, 0x12, 0x13, 0x00, 0x14, 0x12, 0x03, 0x00, 0x0E, 0x00, 0x14, 0x80, 0x02, + 0x88, 0x04, 0xA8, 0x36, 0x84, 0x01, 0xAE, 0xB0, 0xAE, 0xB1, 0xAE, 0x72, 0xAE, 0x73, 0x10, 0x23, + 0x00, 0x20, 0x10, 0x13, 0x00, 0x21, 0xAE, 0x18, 0xD5, 0x19, 0x00, 0x04, 0x80, 0x02, 0xA6, 0x73, + 0xE2, 0x20, 0xE8, 0x03, 0xAE, 0x33, 0xD5, 0x05, 0xA6, 0x72, 0xE2, 0x01, 0xE8, 0x02, 0xAE, 0x32, + 0xEB, 0xE6, 0xA6, 0x71, 0xE2, 0x20, 0xE8, 0x03, 0xAE, 0x31, 0xD5, 0x08, 0xA6, 0x70, 0xE2, 0x01, + 0xE8, 0x05, 0xAE, 0x30, 0xD5, 0x03, 0xB1, 0xA8, 0x84, 0xEB, 0x22, 0x54, 0x80, 0x00, 0xF0, 0x19, + 0xE0, 0x05, 0xE8, 0x06, 0x00, 0x03, 0x00, 0x22, 0x8C, 0x01, 0x10, 0x03, 0x00, 0x22, 0xF0, 0x12, + 0x5C, 0xF0, 0x00, 0x2D, 0xE9, 0x10, 0x22, 0xF3, 0x00, 0x0E, 0x84, 0x03, 0xFE, 0x2C, 0xE0, 0x0F, + 0xE8, 0x0A, 0x00, 0x03, 0x00, 0x23, 0x84, 0xA0, 0x5A, 0x00, 0xFF, 0x06, 0x8C, 0x01, 0x10, 0x03, + 0x00, 0x23, 0x84, 0xA0, 0xA0, 0x35, 0x88, 0x05, 0x8E, 0xB4, 0xA8, 0x35, 0x4E, 0x57, 0x00, 0x1F, + 0x95, 0xFC, 0xEB, 0x98, 0x98, 0x47, 0x8C, 0xE8, 0xA0, 0x09, 0xB0, 0xE0, 0x88, 0x05, 0xA8, 0x09, + 0xEB, 0x98, 0x98, 0x47, 0x20, 0x04, 0x80, 0x03, 0x9C, 0x8C, 0xB6, 0x1F, 0x20, 0x04, 0x80, 0x02, + 0x50, 0x4F, 0x80, 0x82, 0xF0, 0x81, 0x84, 0x00, 0x49, 0xFF, 0xF7, 0x53, 0x00, 0x03, 0x00, 0x23, + 0x5A, 0x00, 0xFF, 0x05, 0x8C, 0x01, 0x10, 0x03, 0x00, 0x23, 0x8D, 0x24, 0x48, 0xFF, 0xFE, 0xEA, + 0xFA, 0x1C, 0x50, 0x1F, 0x85, 0x10, 0x42, 0x1E, 0x00, 0x73, 0x04, 0x00, 0xFF, 0x87, 0x80, 0xDC, + 0xF0, 0xA8, 0xE2, 0xC8, 0xE8, 0x41, 0xEB, 0x98, 0x94, 0x74, 0x88, 0x20, 0xA0, 0x09, 0x4E, 0x07, + 0x00, 0x1F, 0xA0, 0xCA, 0xFA, 0x5C, 0x50, 0x4F, 0x83, 0x2C, 0x42, 0x43, 0x08, 0x73, 0x40, 0x20, + 0x04, 0x0A, 0x88, 0x62, 0x40, 0x31, 0x80, 0x76, 0xA8, 0xE3, 0xA0, 0xCB, 0x88, 0x43, 0x40, 0x21, + 0x00, 0x56, 0xA8, 0xA4, 0x50, 0x4F, 0x82, 0x30, 0xB4, 0x44, 0x88, 0x02, 0xB6, 0x04, 0xA0, 0xA1, + 0xA0, 0x0A, 0x88, 0x02, 0xA8, 0x21, 0xA0, 0x22, 0x88, 0x60, 0xA8, 0xE2, 0xFA, 0x1C, 0x50, 0x1F, + 0x83, 0x2C, 0xEB, 0x1F, 0xF2, 0x2D, 0xA0, 0x0D, 0x8C, 0xC1, 0x88, 0x02, 0xF0, 0xAD, 0x00, 0x20, + 0x80, 0x23, 0x00, 0x0F, 0x80, 0xC3, 0x97, 0xB0, 0x88, 0x02, 0x10, 0x0F, 0x80, 0xC3, 0x00, 0x20, + 0x80, 0x22, 0x00, 0x0F, 0x80, 0xC2, 0x88, 0x02, 0x10, 0x0F, 0x80, 0xC2, 0xB0, 0x28, 0x80, 0x40, + 0x49, 0x00, 0x14, 0x17, 0xD5, 0xBF, 0x04, 0x1F, 0x80, 0x8C, 0x4E, 0x17, 0x00, 0x0A, 0x04, 0x0F, + 0x80, 0x8D, 0xDD, 0x5C, 0xF0, 0xAB, 0x04, 0x0F, 0x80, 0x8E, 0xDD, 0x5C, 0xF0, 0xAC, 0x40, 0xFE, + 0x20, 0x06, 0xE9, 0x17, 0xF0, 0x0A, 0xB0, 0x73, 0x94, 0x04, 0x88, 0x01, 0x80, 0x20, 0xF2, 0x28, + 0x40, 0xFE, 0x20, 0x06, 0xAA, 0x8A, 0x40, 0x24, 0x70, 0x01, 0xAE, 0x8A, 0x02, 0x2F, 0x80, 0x5E, + 0xAC, 0x84, 0xF2, 0x2D, 0xA8, 0x81, 0xEB, 0xF9, 0xAE, 0x0B, 0xE9, 0x20, 0x48, 0xFF, 0xFC, 0x2D, + 0xB1, 0xA2, 0xF3, 0x2B, 0xEA, 0xFC, 0xF1, 0x12, 0x80, 0x46, 0xF4, 0x2C, 0x49, 0xFF, 0xF9, 0x46, + 0x80, 0xBC, 0xFA, 0x7C, 0x50, 0x0F, 0x85, 0x10, 0x42, 0x02, 0x8C, 0x73, 0x50, 0x10, 0x7E, 0x20, + 0x3A, 0x23, 0x08, 0x00, 0x8C, 0xA1, 0x3A, 0x20, 0x88, 0x20, 0x02, 0x1F, 0x80, 0x46, 0x97, 0x68, + 0x12, 0x10, 0x7F, 0x12, 0x4C, 0x54, 0x7F, 0xF0, 0xD5, 0xCE, 0x3C, 0x13, 0xF6, 0x10, 0x96, 0x01, + 0xE2, 0x20, 0xE8, 0x07, 0x3C, 0x0B, 0xF6, 0x10, 0x00, 0x0F, 0x80, 0x28, 0x3E, 0x07, 0xEC, 0x0B, + 0xFA, 0x3C, 0x50, 0x0F, 0x83, 0x2C, 0x42, 0x0E, 0x04, 0x73, 0x00, 0x2F, 0x80, 0x28, 0x10, 0x20, + 0x00, 0x27, 0x02, 0x2F, 0x80, 0x1E, 0x12, 0x20, 0x00, 0x15, 0x50, 0x0E, 0x00, 0x01, 0x55, 0xC0, + 0x00, 0xFF, 0x4D, 0xC4, 0x7F, 0xF0, 0xF1, 0x0A, 0xEA, 0x4E, 0xE2, 0x20, 0xE8, 0x09, 0x8C, 0x21, + 0x96, 0x48, 0xE2, 0x20, 0xF1, 0x8A, 0xE8, 0x04, 0xE3, 0x00, 0x4E, 0xF3, 0xFB, 0xE6, 0x83, 0x88, + 0x48, 0xFF, 0xFB, 0xF6, 0x51, 0xFF, 0x85, 0x10, 0xFC, 0xC0, 0x3C, 0x20, 0x0A, 0xB8, 0xFA, 0x13, + 0x3C, 0x40, 0x0A, 0xB9, 0xFE, 0x84, 0x44, 0x1F, 0xFF, 0xDD, 0x44, 0x00, 0x88, 0xB8, 0x40, 0x21, + 0x28, 0x08, 0xEB, 0xF1, 0x84, 0x60, 0x44, 0x52, 0x5C, 0x0C, 0xEA, 0xAD, 0x88, 0x22, 0xEA, 0x53, + 0x38, 0x12, 0x8D, 0x09, 0x8C, 0x61, 0x88, 0x04, 0x5A, 0x38, 0x24, 0xF9, 0xDD, 0x9E, 0xFC, 0x40, + 0xEE, 0x98, 0x2E, 0x17, 0xF0, 0x12, 0xE6, 0x22, 0xE8, 0x05, 0xDD, 0x41, 0x5A, 0x08, 0x01, 0x32, + 0xD5, 0x1D, 0x3C, 0x0D, 0xF4, 0xD3, 0x94, 0x49, 0xFE, 0x04, 0xEA, 0xE5, 0x40, 0x20, 0x08, 0x56, + 0x96, 0x48, 0xEA, 0x45, 0x84, 0x6B, 0x00, 0x40, 0x00, 0xEB, 0xC4, 0x0B, 0x04, 0x40, 0x00, 0x38, + 0xE0, 0x44, 0xE8, 0x07, 0xFF, 0x0C, 0x83, 0x80, 0xBC, 0xB8, 0xBC, 0x37, 0xFF, 0x0C, 0xBC, 0xB7, + 0x8E, 0x61, 0x96, 0xD8, 0xEB, 0xA2, 0xCB, 0xF0, 0xD5, 0xE1, 0x3C, 0x0D, 0xF4, 0xD3, 0x2E, 0x57, + 0xD3, 0x5E, 0xEA, 0x92, 0xFE, 0x04, 0xDD, 0x5C, 0x88, 0xA1, 0xEB, 0xC1, 0x84, 0x4B, 0x80, 0x81, + 0x00, 0x11, 0x80, 0xEB, 0xC9, 0x0D, 0x8E, 0x41, 0x96, 0x90, 0x50, 0x31, 0x81, 0x0C, 0xCA, 0xF9, + 0x85, 0x40, 0xEA, 0xBD, 0x80, 0xC7, 0x80, 0x4A, 0x81, 0x2A, 0x85, 0x02, 0xD5, 0x33, 0x04, 0x11, + 0x80, 0x38, 0xE0, 0x01, 0xE8, 0xF1, 0xFE, 0x6C, 0xEB, 0x24, 0x14, 0x11, 0x80, 0x38, 0xD5, 0xEC, + 0xEA, 0x2E, 0x00, 0x03, 0x00, 0xEB, 0x96, 0x6E, 0xC9, 0x2B, 0x5A, 0x08, 0x01, 0x2A, 0x94, 0x55, + 0xB0, 0x02, 0x88, 0x20, 0x22, 0x03, 0x00, 0x19, 0x22, 0x33, 0x00, 0x48, 0xA8, 0x09, 0x22, 0x03, + 0x00, 0x1A, 0x8C, 0x41, 0xA8, 0x0A, 0x50, 0x00, 0x80, 0x08, 0xA8, 0xC1, 0x80, 0x01, 0x22, 0x33, + 0x00, 0x49, 0x18, 0x90, 0x00, 0x10, 0xA8, 0xCC, 0x83, 0x86, 0xBB, 0x38, 0x96, 0x90, 0xA8, 0xC1, + 0xB8, 0x37, 0xA8, 0x0E, 0xB8, 0x0B, 0xA8, 0x0F, 0xEA, 0x7C, 0xEA, 0x82, 0xEB, 0x49, 0x5A, 0x90, + 0x0B, 0x1B, 0x02, 0x03, 0x00, 0x72, 0x10, 0x83, 0x00, 0xEC, 0xC0, 0x0F, 0xD5, 0xD2, 0x5A, 0x00, + 0x02, 0xD8, 0x5A, 0x00, 0x04, 0xD6, 0x5A, 0x08, 0x03, 0x09, 0x80, 0x09, 0xF2, 0x81, 0xEA, 0x54, + 0xEB, 0x1C, 0xF2, 0x01, 0xE2, 0x20, 0xE8, 0xCC, 0x00, 0x03, 0x00, 0xEB, 0x5A, 0x08, 0x01, 0xE6, + 0x81, 0x40, 0xD5, 0xE3, 0xEA, 0x8C, 0xC0, 0x3A, 0xEB, 0x3C, 0xB0, 0x42, 0x80, 0x6A, 0x49, 0x00, + 0x19, 0x99, 0xDD, 0x54, 0x96, 0x2E, 0xC0, 0x32, 0x84, 0x40, 0x80, 0x22, 0x02, 0x03, 0x80, 0x72, + 0xC0, 0x22, 0x00, 0x03, 0x80, 0xEB, 0x5A, 0x08, 0x01, 0x1F, 0x94, 0x15, 0xB0, 0xC2, 0x88, 0x03, + 0x22, 0x33, 0x80, 0x19, 0x22, 0x43, 0x80, 0x48, 0xA8, 0xC1, 0x22, 0x33, 0x80, 0x1A, 0x8C, 0x41, + 0xA8, 0xC2, 0x50, 0x30, 0x00, 0x08, 0xA9, 0x19, 0x80, 0x60, 0x22, 0x43, 0x80, 0x49, 0x18, 0x11, + 0x80, 0x10, 0xA9, 0x04, 0x83, 0x87, 0xBC, 0x38, 0x96, 0x90, 0xA9, 0x19, 0xBB, 0x37, 0xA8, 0xC6, + 0xBB, 0x0B, 0xA8, 0xC7, 0x8C, 0x21, 0x96, 0x48, 0x50, 0x73, 0x81, 0x0C, 0x5A, 0x18, 0x0B, 0xD8, + 0xEB, 0x3C, 0xB0, 0x42, 0x84, 0x60, 0x49, 0x00, 0x19, 0x65, 0xED, 0x68, 0xFC, 0xC0, 0xFC, 0x45, + 0x44, 0x62, 0x50, 0x30, 0x80, 0xE1, 0x81, 0x40, 0x81, 0x22, 0xB0, 0x45, 0x5A, 0x20, 0x01, 0x04, + 0x48, 0x00, 0x00, 0x8A, 0xFA, 0x1C, 0x45, 0xC2, 0x22, 0x98, 0x43, 0xC5, 0x00, 0x73, 0x50, 0x0E, + 0x00, 0x10, 0x50, 0x3E, 0x00, 0x20, 0xA0, 0x01, 0xBA, 0x06, 0xAC, 0x0C, 0x02, 0x0E, 0x00, 0x10, + 0xBC, 0x04, 0xAC, 0x0A, 0xDD, 0x57, 0xF2, 0x85, 0x42, 0x83, 0x80, 0x24, 0xA6, 0x9F, 0x40, 0x03, + 0x20, 0x00, 0x10, 0x20, 0x80, 0x12, 0xAD, 0x0B, 0x50, 0x2E, 0x00, 0x08, 0x50, 0x4E, 0x00, 0x18, + 0xEA, 0xF6, 0x10, 0x7E, 0x00, 0x28, 0xF3, 0x83, 0xF2, 0x82, 0xF4, 0x81, 0x10, 0x90, 0x80, 0x13, + 0x49, 0xFF, 0xE3, 0x9E, 0xF3, 0x03, 0x40, 0x03, 0x20, 0x00, 0xF4, 0x01, 0xA7, 0x5C, 0x02, 0x10, + 0x00, 0x72, 0x10, 0x50, 0x01, 0x01, 0xA7, 0x5D, 0x00, 0x31, 0x80, 0x0B, 0xA5, 0x24, 0x10, 0x30, + 0x00, 0xF4, 0x02, 0x3E, 0x00, 0x17, 0x10, 0x50, 0x01, 0x02, 0x12, 0x30, 0x00, 0x79, 0xBB, 0x01, + 0x12, 0x40, 0x00, 0x78, 0x14, 0x30, 0x00, 0x32, 0xF2, 0x02, 0x00, 0x3E, 0x00, 0x0C, 0xC9, 0x16, + 0x50, 0x84, 0x00, 0xC8, 0x5A, 0x38, 0x01, 0x0D, 0x89, 0x06, 0x8D, 0x04, 0x3A, 0x21, 0x08, 0x00, + 0x3A, 0x24, 0x08, 0x20, 0x02, 0x0E, 0x00, 0x06, 0x12, 0x04, 0x00, 0x02, 0xD5, 0x44, 0x40, 0x03, + 0x20, 0x00, 0x84, 0x46, 0x8C, 0x04, 0xDD, 0x40, 0xD5, 0x3E, 0x5A, 0x38, 0x01, 0x3D, 0x02, 0x20, + 0x00, 0x67, 0x02, 0x1E, 0x00, 0x05, 0x8A, 0x22, 0x80, 0x81, 0x4E, 0x14, 0x00, 0x03, 0xFF, 0x0A, + 0x2E, 0x57, 0xD8, 0x76, 0xE0, 0xA4, 0xE8, 0x2F, 0x84, 0x01, 0x4E, 0x14, 0x00, 0x03, 0x84, 0x1F, + 0x2E, 0x37, 0xD8, 0x78, 0x8A, 0x85, 0x2E, 0x17, 0xD8, 0x77, 0xFF, 0x04, 0x42, 0x02, 0x0C, 0x24, + 0x88, 0x61, 0x40, 0x40, 0x0C, 0x96, 0x98, 0xD4, 0x4E, 0x35, 0x00, 0x07, 0xEA, 0x6F, 0xE0, 0x03, + 0xEA, 0xED, 0x96, 0xD9, 0xD5, 0x02, 0x84, 0x60, 0xDD, 0x57, 0x80, 0x26, 0xEA, 0x27, 0x12, 0x30, + 0x80, 0x67, 0xD5, 0x11, 0xDD, 0x57, 0xFE, 0x3C, 0x98, 0xB0, 0x50, 0x21, 0x00, 0x2C, 0x81, 0x02, + 0x81, 0xE1, 0x3A, 0x24, 0x14, 0x04, 0xEB, 0x5C, 0xB4, 0x68, 0x88, 0x06, 0xB6, 0x6F, 0xEA, 0xF6, + 0x49, 0xFF, 0xE3, 0x2E, 0xDD, 0x57, 0x80, 0x26, 0xEA, 0x27, 0x80, 0x01, 0x02, 0x10, 0x80, 0x72, + 0xC9, 0x0B, 0xFA, 0x5C, 0xEA, 0x41, 0x42, 0x15, 0x08, 0x73, 0x50, 0x00, 0x00, 0xF0, 0xA0, 0x8C, + 0xA0, 0x4D, 0xAC, 0x83, 0xAC, 0x44, 0xDD, 0x57, 0x42, 0x63, 0x80, 0x73, 0x50, 0x63, 0x00, 0xE0, + 0x10, 0x93, 0x00, 0x0C, 0xA5, 0x72, 0xEB, 0xB7, 0xD0, 0x03, 0x8C, 0xA1, 0xAD, 0x72, 0xFC, 0xC5, + 0xFC, 0x40, 0x3C, 0x23, 0xF6, 0xD6, 0x2E, 0x77, 0xD9, 0x28, 0x96, 0x8E, 0x96, 0x91, 0x44, 0x02, + 0x4F, 0x8C, 0x84, 0x20, 0x85, 0x3F, 0xFB, 0x54, 0x44, 0x52, 0x13, 0x64, 0x10, 0x90, 0x00, 0x00, + 0x10, 0xA0, 0x00, 0x01, 0xCA, 0x07, 0x8C, 0x21, 0x96, 0x48, 0x8C, 0x02, 0x5A, 0x18, 0x12, 0xF8, + 0xFC, 0xC0, 0x84, 0x80, 0x96, 0xE0, 0xE2, 0x67, 0xE8, 0xF7, 0x38, 0x62, 0x91, 0x00, 0x94, 0xE1, + 0x4C, 0x60, 0xC0, 0x15, 0x88, 0x65, 0xA6, 0xD9, 0xE6, 0x72, 0xE8, 0x09, 0x20, 0x60, 0x00, 0x00, + 0x5A, 0x67, 0xFF, 0x04, 0xE0, 0xC3, 0xE8, 0x0A, 0xAE, 0xC0, 0xD5, 0x08, 0x20, 0xF0, 0x00, 0x01, + 0x5A, 0xF0, 0x24, 0x04, 0xE0, 0x6F, 0xE8, 0x02, 0xAE, 0xC1, 0x8C, 0x81, 0xD5, 0xE4, 0xC2, 0x0B, + 0xEB, 0xFC, 0x42, 0x00, 0x8C, 0x73, 0x38, 0x01, 0x01, 0x01, 0x3C, 0x13, 0x79, 0xDA, 0x8E, 0x01, + 0xDD, 0x5C, 0x96, 0x00, 0xDD, 0x9E, 0xFC, 0x42, 0x2E, 0x60, 0x15, 0x49, 0x80, 0xE0, 0xFF, 0xB2, + 0x96, 0x33, 0xF1, 0x82, 0xB6, 0x1F, 0xEB, 0x3F, 0x81, 0x42, 0x44, 0x02, 0x4F, 0xBC, 0xEA, 0xDE, + 0xF3, 0x83, 0xDD, 0x40, 0x2E, 0x27, 0xDE, 0xED, 0xEB, 0x61, 0xFA, 0x22, 0xEA, 0xB1, 0x84, 0x20, + 0x38, 0x13, 0x81, 0x09, 0xEA, 0x2F, 0x50, 0x50, 0x00, 0x26, 0x44, 0x22, 0x4C, 0x08, 0x50, 0x00, + 0x00, 0x46, 0x84, 0x8A, 0x84, 0x67, 0x08, 0x11, 0x00, 0x01, 0x00, 0x81, 0x00, 0x00, 0x00, 0xF1, + 0x00, 0x01, 0x5A, 0x88, 0x01, 0x22, 0x40, 0x60, 0xBC, 0x00, 0x5A, 0x60, 0x02, 0x12, 0xC9, 0x06, + 0x02, 0x12, 0xFF, 0xED, 0xFE, 0x5C, 0x96, 0x4B, 0xD5, 0x02, 0x84, 0x20, 0xE9, 0x06, 0x02, 0xF2, + 0xFF, 0xEF, 0x42, 0x17, 0x8C, 0x73, 0x96, 0x4B, 0xCE, 0x06, 0x90, 0x21, 0xD5, 0x04, 0x84, 0x20, + 0x85, 0x09, 0xD5, 0x02, 0x85, 0x03, 0x02, 0xF2, 0x80, 0x00, 0x42, 0x14, 0x3C, 0x73, 0x96, 0x4B, + 0xEB, 0x24, 0x12, 0x12, 0xFF, 0xEE, 0x8C, 0xA2, 0xD8, 0xD7, 0x84, 0xA0, 0x44, 0x0F, 0x80, 0x00, + 0x3C, 0x0B, 0xEC, 0x9E, 0x44, 0x42, 0x4F, 0xBC, 0x80, 0x45, 0x80, 0x25, 0x81, 0x25, 0x44, 0x02, + 0x5C, 0x0C, 0x83, 0x87, 0x38, 0x00, 0x15, 0x01, 0xF0, 0x81, 0xFA, 0x14, 0x43, 0xC2, 0x80, 0x73, + 0x84, 0x01, 0x55, 0xE0, 0x00, 0xFF, 0x50, 0x3F, 0x7F, 0xFF, 0x54, 0x81, 0x80, 0xFF, 0xF6, 0x01, + 0x22, 0x3E, 0x00, 0x00, 0xFE, 0xF4, 0x90, 0x6A, 0x96, 0xDB, 0x1A, 0x3E, 0x00, 0x01, 0x3C, 0xF7, + 0xEC, 0x9E, 0x40, 0xF7, 0x8C, 0x07, 0xE8, 0x03, 0x3C, 0x3B, 0xEC, 0x9E, 0xF6, 0x02, 0xE0, 0x66, + 0xE8, 0x05, 0xB4, 0xDF, 0xE0, 0xC3, 0xE8, 0x31, 0xD5, 0x1D, 0xE0, 0x6A, 0xE9, 0x04, 0x8C, 0x21, + 0x96, 0x49, 0xD5, 0x06, 0xB4, 0xDF, 0xE0, 0xC3, 0xE9, 0x03, 0x8C, 0x41, 0x96, 0x91, 0xA6, 0xE0, + 0x5A, 0x38, 0xFF, 0x07, 0x10, 0x82, 0x00, 0x00, 0x11, 0xE2, 0x00, 0x01, 0xD5, 0x0B, 0xE2, 0x68, + 0x40, 0x81, 0xBC, 0x1B, 0xA6, 0xE1, 0x10, 0x82, 0x00, 0x00, 0xE0, 0x03, 0x40, 0x30, 0x3C, 0x1A, + 0xAE, 0xE1, 0x8C, 0x01, 0x5A, 0x08, 0x13, 0xC7, 0xA6, 0x20, 0x5A, 0x08, 0xFF, 0x06, 0x10, 0x92, + 0x00, 0x00, 0x10, 0x92, 0x00, 0x01, 0x8C, 0xA1, 0x8C, 0x82, 0x5A, 0x58, 0x24, 0xB2, 0xF0, 0x03, + 0xAC, 0x80, 0x3C, 0x1B, 0xF7, 0x11, 0xFC, 0xC2, 0xE0, 0x6A, 0xE8, 0xD2, 0xD5, 0xD7, 0xFC, 0x40, + 0x84, 0x20, 0x3C, 0x1B, 0xF6, 0xF2, 0x3C, 0x1B, 0xF6, 0xF3, 0x3C, 0x1B, 0xF6, 0x11, 0x3C, 0x47, + 0xF8, 0x07, 0x3C, 0x10, 0x0A, 0xA9, 0xE0, 0x81, 0xE9, 0x05, 0x2E, 0x17, 0xED, 0xEA, 0x5A, 0x18, + 0x01, 0x10, 0x94, 0x62, 0x84, 0x4A, 0xEB, 0xB8, 0x96, 0x4B, 0xE4, 0x34, 0xE8, 0x0E, 0x2E, 0x27, + 0xED, 0xE9, 0xCA, 0x0D, 0x2E, 0x37, 0xED, 0xEA, 0x5A, 0x38, 0x01, 0x66, 0xD5, 0x09, 0x84, 0x27, + 0xFE, 0x64, 0x84, 0x4A, 0xEB, 0xB8, 0x96, 0x4B, 0x84, 0x60, 0xD5, 0x02, 0x84, 0x61, 0x84, 0x4F, + 0x40, 0x22, 0x08, 0x56, 0xE4, 0x54, 0xE9, 0x0A, 0x5E, 0xF1, 0x00, 0x47, 0x80, 0xA2, 0xE9, 0x03, + 0x44, 0x50, 0x00, 0x46, 0x40, 0x92, 0x80, 0x11, 0xD5, 0x02, 0xFB, 0x24, 0x84, 0x43, 0xFF, 0x14, + 0x84, 0x44, 0x40, 0x42, 0x08, 0x96, 0x97, 0x23, 0x80, 0xA0, 0x50, 0x80, 0x05, 0x10, 0x84, 0xE0, + 0x84, 0xC0, 0x81, 0x46, 0x38, 0x22, 0x99, 0x11, 0xE1, 0x22, 0xE8, 0x0A, 0x3C, 0x03, 0xF6, 0xF3, + 0xE0, 0x82, 0x8C, 0x01, 0x3C, 0x0B, 0xF6, 0xF3, 0xE8, 0x03, 0x9C, 0x39, 0x97, 0xC1, 0xE0, 0x22, + 0x51, 0xC3, 0x00, 0x01, 0xE8, 0x09, 0x5A, 0x68, 0x11, 0x16, 0x3C, 0x03, 0xF6, 0xF2, 0x8C, 0x01, + 0x3C, 0x0B, 0xF6, 0xF2, 0xD5, 0x15, 0x5A, 0xA8, 0x01, 0x10, 0x9A, 0x8A, 0x4E, 0x24, 0x00, 0x03, + 0xFE, 0x92, 0xE4, 0x4B, 0xE9, 0x0A, 0x3C, 0x03, 0xF6, 0xF2, 0x8C, 0x01, 0x3C, 0x0B, 0xF6, 0xF2, + 0xD5, 0x03, 0x85, 0x41, 0xD5, 0x02, 0x85, 0x40, 0x80, 0xDC, 0x5B, 0xC8, 0x12, 0xD5, 0x50, 0x52, + 0x80, 0x24, 0x4C, 0x54, 0x7F, 0xCF, 0xC3, 0x05, 0x84, 0x00, 0x3C, 0x0B, 0xF6, 0xF2, 0xFC, 0xC0, + 0x3C, 0x23, 0xF6, 0xF3, 0xC2, 0x08, 0x44, 0x10, 0x03, 0xE8, 0x42, 0x03, 0x84, 0x24, 0xEA, 0xA6, + 0x3C, 0x0B, 0xF6, 0x11, 0xFC, 0xC0, 0xFC, 0x03, 0x84, 0x00, 0x12, 0x0F, 0x80, 0x0B, 0xEA, 0x2F, + 0x3C, 0x67, 0xE9, 0xFD, 0x3C, 0x47, 0xE9, 0xF9, 0xB6, 0xDF, 0x44, 0x62, 0x13, 0xFC, 0x3C, 0x57, + 0xE9, 0xFC, 0x3C, 0x17, 0xE9, 0x56, 0x3C, 0x27, 0xE9, 0xF8, 0x3C, 0x37, 0xE9, 0xFA, 0xF6, 0x81, + 0xF0, 0x83, 0x49, 0xFF, 0xE2, 0x47, 0x44, 0x10, 0x00, 0x32, 0x3C, 0x27, 0xE9, 0x56, 0x50, 0x3F, + 0x80, 0x16, 0xF0, 0x03, 0x49, 0xFF, 0xFE, 0xB1, 0xF0, 0x03, 0x49, 0xFF, 0xE1, 0x9F, 0xF0, 0x03, + 0x49, 0xFF, 0xFF, 0x57, 0xEA, 0x4B, 0x84, 0x1E, 0xFE, 0x0E, 0x3C, 0xF7, 0xF8, 0x07, 0xEA, 0xCE, + 0xEA, 0xDC, 0xE0, 0x2F, 0xE8, 0x05, 0xEA, 0x7F, 0xDD, 0x4B, 0xEA, 0xDC, 0xD5, 0x0B, 0xEB, 0xDA, + 0x5A, 0x08, 0x01, 0x09, 0x2E, 0x00, 0x15, 0x49, 0x3C, 0x17, 0xF8, 0x05, 0xFE, 0x02, 0xE0, 0x20, + 0xE9, 0xF3, 0xEB, 0x4B, 0xC0, 0x0F, 0xEA, 0x7F, 0x96, 0x06, 0xC8, 0x06, 0xDD, 0x41, 0xC8, 0x04, + 0x84, 0x02, 0x84, 0x21, 0xEB, 0x07, 0xEB, 0x4B, 0x49, 0x00, 0x6D, 0x77, 0x84, 0x00, 0x3C, 0x0E, + 0x00, 0xE8, 0x84, 0x01, 0xFC, 0x83, 0x44, 0x12, 0x07, 0xD8, 0x44, 0x02, 0x49, 0xA4, 0x3A, 0x20, + 0x8C, 0x00, 0xEB, 0xEF, 0xDD, 0x9E, 0xFC, 0x20, 0x84, 0x20, 0x84, 0x48, 0x44, 0x02, 0x22, 0x90, + 0xDD, 0x40, 0x84, 0x01, 0x3E, 0x07, 0xF0, 0x09, 0x84, 0x02, 0x44, 0x20, 0x0B, 0xB0, 0x84, 0xE0, + 0x84, 0x20, 0x3E, 0x07, 0xF0, 0x08, 0xEA, 0x45, 0x3C, 0x7B, 0xF6, 0xD8, 0xDD, 0x40, 0x49, 0x00, + 0x24, 0x68, 0x44, 0x02, 0x07, 0x00, 0x44, 0x62, 0x49, 0xA4, 0x02, 0x10, 0x00, 0x0C, 0x02, 0x00, + 0x00, 0x0D, 0x12, 0x13, 0x00, 0x23, 0x12, 0x03, 0x00, 0x22, 0x49, 0xFF, 0xFC, 0x70, 0x84, 0x01, + 0x3C, 0x7B, 0xF7, 0x0B, 0x49, 0xFF, 0xF6, 0x87, 0x84, 0x01, 0x49, 0xFF, 0xF6, 0x23, 0x49, 0x00, + 0x08, 0x54, 0x84, 0x01, 0x49, 0x00, 0x08, 0x56, 0xDD, 0x4C, 0x10, 0x03, 0x00, 0x42, 0x44, 0x00, + 0x01, 0x78, 0x12, 0x03, 0x00, 0x1F, 0x44, 0x00, 0x01, 0xA2, 0x12, 0x03, 0x00, 0x20, 0x49, 0xFF, + 0xFF, 0xBC, 0xDD, 0x46, 0x84, 0xC1, 0x58, 0x00, 0x00, 0x40, 0xEA, 0x23, 0x84, 0x07, 0x3C, 0x0B, + 0xF6, 0xD6, 0x3C, 0x6B, 0xF6, 0xD7, 0x49, 0xFF, 0xFD, 0xED, 0xDD, 0x4F, 0x44, 0x0F, 0xEF, 0xFF, + 0xFE, 0x0E, 0x3C, 0x7B, 0xF6, 0xD5, 0x3C, 0x6B, 0xF6, 0xD4, 0xEA, 0x23, 0xFC, 0xA0, 0x84, 0x00, + 0x3C, 0x0B, 0xF7, 0x0B, 0xDD, 0x9E, 0xFC, 0x00, 0xDD, 0x54, 0x96, 0x0E, 0xC0, 0x09, 0x84, 0x02, + 0x49, 0xFF, 0xF6, 0x51, 0x84, 0x02, 0x49, 0xFF, 0xF5, 0xED, 0x84, 0x02, 0xD5, 0x08, 0x84, 0x01, + 0x49, 0xFF, 0xF6, 0x49, 0x84, 0x01, 0x49, 0xFF, 0xF5, 0xE5, 0x84, 0x01, 0x49, 0x00, 0x08, 0x1A, + 0xFC, 0x80, 0xFC, 0x00, 0xEA, 0x2E, 0x84, 0x01, 0x3E, 0x07, 0xF0, 0x09, 0x96, 0x4E, 0x84, 0x02, + 0x3E, 0x07, 0xF0, 0x08, 0xC1, 0x09, 0x2E, 0x17, 0xF0, 0xC5, 0xC1, 0x06, 0x3E, 0x07, 0xF0, 0x09, + 0x84, 0x03, 0x3E, 0x07, 0xF0, 0x08, 0x49, 0xFF, 0xFF, 0x78, 0xEB, 0x61, 0x84, 0x41, 0x9E, 0x41, + 0xE6, 0x30, 0xE9, 0x07, 0x84, 0x21, 0xEA, 0x64, 0xC0, 0x08, 0xEB, 0x61, 0x44, 0x2F, 0xFF, 0x87, + 0x44, 0x12, 0x4C, 0x08, 0x38, 0x20, 0x80, 0x08, 0x3C, 0x13, 0xE9, 0x50, 0x3C, 0x50, 0x0A, 0xB9, + 0x3C, 0x03, 0xE9, 0x51, 0xD9, 0x04, 0x3C, 0x50, 0x0A, 0xB8, 0xD0, 0x07, 0x3C, 0x18, 0x0A, 0xB9, + 0x3C, 0x08, 0x0A, 0xB8, 0x49, 0xFF, 0xFB, 0xF3, 0xFC, 0x80, 0xFC, 0x40, 0x3C, 0x63, 0xF8, 0x07, + 0x3C, 0x84, 0x0A, 0x9C, 0x80, 0x86, 0x97, 0xB3, 0x5E, 0xF3, 0x05, 0xDD, 0x3C, 0x54, 0x0A, 0x9D, + 0x3C, 0x94, 0x0A, 0x9E, 0xE9, 0x03, 0x44, 0x40, 0x05, 0xDC, 0x3C, 0x64, 0x0A, 0x9F, 0x97, 0x23, + 0xAD, 0x98, 0x2E, 0x37, 0xF0, 0x13, 0x12, 0x80, 0x00, 0x00, 0xAD, 0x48, 0x12, 0x91, 0x00, 0x00, + 0x5A, 0x38, 0x01, 0x2A, 0x3C, 0x63, 0xE9, 0xFB, 0x84, 0x6F, 0x44, 0x70, 0x00, 0x64, 0xFE, 0xE4, + 0x42, 0x64, 0x18, 0x24, 0x40, 0x63, 0x1C, 0xD6, 0xEB, 0x33, 0xE0, 0x66, 0x40, 0x33, 0x3C, 0x1B, + 0xAC, 0xC0, 0x3C, 0x33, 0xE9, 0xFB, 0x84, 0xC4, 0xFE, 0xEC, 0xEB, 0x33, 0x40, 0x62, 0x18, 0xD6, + 0xE0, 0x66, 0x40, 0x33, 0x3C, 0x1B, 0xAC, 0xC8, 0x3C, 0x33, 0xE9, 0xFB, 0xFA, 0xD8, 0xFF, 0xA4, + 0x42, 0x34, 0x8C, 0x24, 0x40, 0x63, 0x1C, 0xD6, 0x40, 0x71, 0x9C, 0xF6, 0xE0, 0xC7, 0x40, 0x63, + 0xBC, 0x1B, 0xAD, 0x90, 0x3C, 0x33, 0xEF, 0x78, 0x96, 0xEE, 0xC3, 0x39, 0x84, 0x6F, 0x44, 0x70, + 0x00, 0x64, 0xFE, 0xE4, 0x40, 0xA1, 0x9D, 0x56, 0x3C, 0x33, 0xEA, 0x0E, 0x22, 0x60, 0x00, 0x00, + 0x42, 0x34, 0x0C, 0x24, 0xEB, 0x33, 0xE1, 0x43, 0x40, 0x35, 0x3C, 0x1A, 0xE0, 0x66, 0x40, 0x33, + 0x3C, 0x1B, 0xAC, 0xC0, 0x3C, 0x33, 0xEA, 0x0E, 0xFF, 0x5C, 0x40, 0x62, 0x9C, 0xD6, 0x84, 0xA4, + 0x40, 0x52, 0x14, 0xB6, 0x22, 0x30, 0x80, 0x00, 0xE0, 0xC5, 0x40, 0x53, 0x3C, 0x1A, 0xE0, 0xA3, + 0x40, 0x51, 0xBC, 0x1B, 0xAD, 0x48, 0xFA, 0xB8, 0x22, 0x31, 0x00, 0x00, 0xFF, 0x64, 0x40, 0x52, + 0x9C, 0xB6, 0xE0, 0xA3, 0x40, 0x32, 0xBC, 0x1A, 0x3C, 0x53, 0xEA, 0x0E, 0x42, 0x54, 0x94, 0x24, + 0x40, 0x72, 0x9C, 0xF6, 0xE0, 0x67, 0x40, 0x33, 0xBC, 0x1B, 0xAC, 0xD0, 0x3C, 0x33, 0xEF, 0x78, + 0x96, 0xFE, 0xC3, 0x1A, 0xA5, 0x40, 0x3C, 0x33, 0xE9, 0x66, 0x97, 0xEB, 0x97, 0x9B, 0xE0, 0xE6, + 0x40, 0x32, 0xBC, 0x1A, 0xAC, 0xC0, 0xA4, 0xC8, 0x3C, 0x03, 0xE9, 0x67, 0x97, 0x9B, 0x97, 0x43, + 0xE0, 0xC5, 0xEB, 0x3E, 0xAC, 0x08, 0x3C, 0x03, 0xE9, 0x68, 0xA4, 0xD0, 0x97, 0x43, 0x97, 0x9B, + 0xE0, 0xC5, 0xEB, 0x3E, 0xAC, 0x10, 0x22, 0x00, 0x80, 0x00, 0x84, 0x64, 0x40, 0x32, 0x0C, 0x76, + 0xE0, 0x03, 0x40, 0x01, 0xBC, 0x1B, 0xAC, 0x08, 0x44, 0x00, 0x00, 0x46, 0x22, 0x11, 0x00, 0x00, + 0xEB, 0x23, 0xFF, 0x04, 0x40, 0x42, 0x3C, 0x96, 0xE0, 0x24, 0x40, 0x40, 0xBC, 0x1A, 0xAD, 0x10, + 0xFC, 0xC0, 0xDD, 0x46, 0x54, 0x00, 0x08, 0x00, 0xC8, 0x39, 0xFC, 0x00, 0xEA, 0x6B, 0x84, 0x09, + 0xDD, 0x4A, 0xC0, 0x05, 0xDD, 0x54, 0x58, 0x00, 0x00, 0x80, 0xEA, 0x6B, 0x84, 0x07, 0xDD, 0x4A, + 0x5A, 0x00, 0x01, 0x05, 0x2E, 0x07, 0xF0, 0xC5, 0xC0, 0x05, 0xDD, 0x54, 0x58, 0x00, 0x02, 0x00, + 0xEA, 0x6B, 0xEB, 0xDA, 0x5A, 0x00, 0x01, 0x05, 0x2E, 0x07, 0xF0, 0xC5, 0xC0, 0x04, 0xDD, 0x54, + 0xEA, 0x93, 0xEA, 0x6B, 0xDD, 0x46, 0x96, 0x16, 0xC0, 0x04, 0xDD, 0x54, 0xEA, 0x39, 0xEA, 0x6B, + 0xDD, 0x4F, 0x44, 0x00, 0x80, 0x00, 0xFE, 0x0E, 0xC0, 0x04, 0xDD, 0x54, 0xEA, 0xA1, 0xEA, 0x6B, + 0x2E, 0x07, 0xF0, 0xD6, 0xC0, 0x05, 0xDD, 0x54, 0x58, 0x00, 0x0A, 0x20, 0xEA, 0x6B, 0xDD, 0x54, + 0xC8, 0x04, 0xDD, 0x54, 0xDD, 0x4B, 0xEA, 0x6B, 0xFC, 0x80, 0xDD, 0x9E, 0xFC, 0x00, 0x49, 0xFF, + 0xFF, 0xC2, 0xDD, 0x54, 0x3C, 0x53, 0xF7, 0x0B, 0xD0, 0x08, 0xDD, 0x54, 0x3C, 0x0B, 0xF7, 0x0B, + 0x49, 0xFF, 0xFE, 0xBB, 0x49, 0xFF, 0xFE, 0xCF, 0xFC, 0x80, 0xFC, 0x41, 0x80, 0xC0, 0x81, 0x41, + 0x22, 0x00, 0x00, 0x67, 0x22, 0x13, 0x00, 0x05, 0x80, 0xE2, 0x8A, 0x01, 0xB6, 0x1F, 0x22, 0x13, + 0x00, 0x06, 0x22, 0x03, 0x00, 0x68, 0x81, 0x23, 0x8A, 0x01, 0xF0, 0x81, 0x80, 0x1F, 0xDD, 0x4D, + 0xE0, 0x0A, 0xE8, 0x18, 0x84, 0x20, 0x84, 0x4C, 0x44, 0x32, 0x4C, 0x28, 0x80, 0x03, 0xEA, 0xB7, + 0x00, 0x40, 0x00, 0x0A, 0xCC, 0x0C, 0x22, 0x13, 0x00, 0x05, 0xB6, 0x20, 0x22, 0x13, 0x00, 0x06, + 0x10, 0x90, 0x00, 0x0A, 0xA8, 0x41, 0xAD, 0xC4, 0x84, 0x01, 0xFC, 0xC1, 0x8C, 0x21, 0x5A, 0x18, + 0x0B, 0xEF, 0x84, 0x00, 0xFC, 0xC1, 0xFC, 0x40, 0x81, 0x00, 0x80, 0xE1, 0xEA, 0x2F, 0xEA, 0x49, + 0x44, 0x42, 0x50, 0x30, 0x42, 0x34, 0x0C, 0x24, 0x98, 0x63, 0x00, 0x20, 0x81, 0x37, 0xC2, 0x4D, + 0x84, 0x20, 0x81, 0x44, 0x80, 0xC1, 0x98, 0x8B, 0x88, 0x4A, 0x8C, 0x34, 0x02, 0x21, 0x00, 0x18, + 0x97, 0x13, 0xE0, 0xC4, 0x40, 0x61, 0x3C, 0x1B, 0x97, 0xB3, 0x5A, 0x18, 0x64, 0xF6, 0xEA, 0x76, + 0x42, 0x14, 0x04, 0x24, 0x40, 0x25, 0x04, 0x00, 0x88, 0x2A, 0x00, 0x41, 0x01, 0x02, 0x00, 0x31, + 0x01, 0x01, 0xFA, 0x42, 0x42, 0x32, 0x08, 0x73, 0x51, 0xC0, 0x80, 0xC8, 0x38, 0x90, 0x0D, 0x11, + 0x80, 0x1C, 0x49, 0x00, 0x0E, 0x4E, 0xE6, 0x02, 0xE8, 0x0E, 0xDD, 0x57, 0x42, 0xA4, 0x00, 0x73, + 0x02, 0x05, 0x00, 0x72, 0x84, 0x40, 0xE6, 0x03, 0xE9, 0x16, 0x3C, 0x23, 0xEF, 0x78, 0x92, 0x49, + 0x96, 0x86, 0xD5, 0x11, 0x80, 0x1C, 0x49, 0x00, 0x0E, 0x46, 0xE6, 0x02, 0xE9, 0xEF, 0x80, 0x1C, + 0x49, 0x00, 0x0E, 0x37, 0xE6, 0x08, 0xE8, 0xEA, 0x80, 0x1C, 0x49, 0x00, 0x0E, 0x3C, 0xE6, 0x08, + 0x84, 0x41, 0xE8, 0xE4, 0xE0, 0xC7, 0xE9, 0x08, 0x3C, 0xF7, 0xF8, 0x06, 0x3C, 0x07, 0xE9, 0x79, + 0x88, 0x0F, 0xE1, 0x20, 0xE9, 0x02, 0x84, 0x40, 0x80, 0x02, 0xFC, 0xC0, 0xFC, 0x02, 0x84, 0x00, + 0x12, 0x0F, 0x80, 0x04, 0x12, 0x0F, 0x80, 0x05, 0x12, 0x0F, 0x80, 0x06, 0x12, 0x0F, 0x80, 0x07, + 0xEA, 0x2F, 0xF0, 0x81, 0x84, 0x00, 0x49, 0xFF, 0xFF, 0x5B, 0xB0, 0x02, 0x50, 0x1F, 0x80, 0x0A, + 0xB0, 0x83, 0x50, 0x3F, 0x80, 0x0E, 0x49, 0xFF, 0xFE, 0x62, 0x22, 0x3F, 0x80, 0x05, 0x84, 0x00, + 0xF1, 0x01, 0x22, 0x2F, 0x80, 0x04, 0x22, 0x4F, 0x80, 0x06, 0x22, 0x5F, 0x80, 0x07, 0x3C, 0x3B, + 0xF8, 0x06, 0x49, 0xFF, 0xF4, 0x70, 0xFC, 0x82, 0xFC, 0x48, 0x84, 0x00, 0xEA, 0x4B, 0x3E, 0x07, + 0xEE, 0x20, 0x44, 0x0F, 0xFF, 0xBF, 0xFE, 0x0E, 0xEA, 0xDC, 0x84, 0x08, 0xDD, 0x4A, 0x5A, 0x00, + 0x01, 0x05, 0xEB, 0x2E, 0x5A, 0x08, 0x01, 0x0C, 0xEA, 0x5A, 0x84, 0x20, 0xDD, 0x43, 0xEB, 0x2F, + 0xDD, 0x4B, 0x3C, 0x0B, 0xF6, 0xD5, 0x84, 0x00, 0x3C, 0x0B, 0xF6, 0xEF, 0x3C, 0x13, 0xF6, 0xD5, + 0x54, 0x00, 0x80, 0x01, 0xC0, 0x0D, 0x3C, 0x03, 0xF6, 0xEF, 0x8C, 0x01, 0x96, 0x01, 0xE6, 0x03, + 0x3C, 0x0B, 0xF6, 0xEF, 0xE9, 0x05, 0x84, 0x1E, 0xFE, 0x0E, 0x3C, 0x0B, 0xF6, 0xD5, 0xEA, 0xCE, + 0x3C, 0x07, 0xF8, 0x07, 0xE0, 0x01, 0xE8, 0x0C, 0x3C, 0x07, 0xF8, 0x05, 0x4E, 0x04, 0x00, 0x03, + 0xFE, 0x02, 0xE0, 0x01, 0xE8, 0x05, 0x44, 0x00, 0x02, 0x00, 0x84, 0x20, 0xDD, 0x43, 0xEA, 0x2F, + 0x80, 0xC0, 0x49, 0xFF, 0xFF, 0x9D, 0x2E, 0x07, 0xEC, 0x0D, 0x5A, 0x08, 0x01, 0x04, 0xEB, 0x4A, + 0xFC, 0xC8, 0x49, 0xFF, 0xFA, 0x16, 0xDD, 0x41, 0xC8, 0x15, 0xEA, 0x50, 0xB6, 0x1F, 0x44, 0x02, + 0x4B, 0x58, 0xF0, 0x81, 0xF6, 0x82, 0x3C, 0x0C, 0x05, 0x4D, 0x3C, 0x1C, 0x05, 0x4E, 0x3C, 0x2C, + 0x05, 0x4F, 0x3C, 0x3C, 0x05, 0x50, 0x3C, 0x4C, 0x05, 0x51, 0x3C, 0x5C, 0x05, 0x52, 0x49, 0x00, + 0x0E, 0x7D, 0xDD, 0x41, 0xC8, 0x0B, 0xEA, 0x8C, 0xE6, 0x06, 0xE8, 0x08, 0xEA, 0x2E, 0x54, 0x10, + 0x82, 0x20, 0xC9, 0x04, 0x80, 0x06, 0x49, 0x00, 0x17, 0xAA, 0x44, 0x01, 0x29, 0x38, 0x84, 0xE0, + 0x3A, 0x20, 0x14, 0x00, 0xB0, 0x0C, 0xEA, 0x5C, 0xDD, 0x54, 0xEA, 0x98, 0x96, 0x01, 0xF0, 0x86, + 0x2E, 0x00, 0x15, 0x48, 0x50, 0x00, 0x00, 0x64, 0xF0, 0x85, 0xEA, 0x45, 0xF0, 0x87, 0x81, 0x20, + 0x80, 0xC0, 0x02, 0x04, 0x80, 0x72, 0xC0, 0x08, 0x00, 0x04, 0x81, 0x00, 0x80, 0x27, 0x00, 0x24, + 0x80, 0xEC, 0x49, 0xFF, 0xFA, 0x9E, 0x8C, 0xE1, 0x97, 0xF8, 0x50, 0x94, 0x81, 0x0C, 0x5A, 0x78, + 0x0B, 0xF2, 0x85, 0x40, 0x44, 0x72, 0x22, 0x98, 0xFB, 0x3C, 0xEA, 0x8C, 0xE3, 0x40, 0xE8, 0x1D, + 0x80, 0x47, 0x42, 0x25, 0x24, 0x73, 0x00, 0x11, 0x00, 0x28, 0x5A, 0x18, 0xFF, 0x45, 0x00, 0x01, + 0x00, 0x29, 0x5A, 0x08, 0x01, 0x41, 0xF0, 0x06, 0xC0, 0x0B, 0x22, 0x11, 0x00, 0x10, 0xDD, 0x4C, + 0xFE, 0x44, 0x22, 0x01, 0x00, 0x17, 0xF2, 0x05, 0xFE, 0x14, 0xE0, 0x20, 0xE9, 0x34, 0x49, 0x00, + 0x21, 0x84, 0xE6, 0x0B, 0x81, 0x00, 0xE9, 0x0A, 0x44, 0xA2, 0x50, 0x5C, 0x84, 0xC0, 0x49, 0x00, + 0x12, 0xA9, 0x50, 0x75, 0x7F, 0xD4, 0x81, 0x26, 0xD5, 0x3C, 0xDD, 0x57, 0x80, 0x26, 0x42, 0x14, + 0x00, 0x73, 0xF0, 0x06, 0x84, 0x61, 0x10, 0x30, 0x81, 0x2C, 0x50, 0x20, 0x81, 0x30, 0x50, 0x10, + 0x80, 0xE8, 0xC0, 0x06, 0x84, 0x00, 0xAE, 0x17, 0x2E, 0x27, 0xD8, 0xF0, 0xD5, 0x04, 0xAE, 0xD7, + 0x2E, 0x27, 0xD3, 0x9C, 0x84, 0x0A, 0xFE, 0x14, 0xAC, 0x0B, 0x84, 0x41, 0x80, 0x0A, 0x80, 0x28, + 0x49, 0xFF, 0xFA, 0x4F, 0xDD, 0x57, 0x80, 0x46, 0x3C, 0x10, 0x0A, 0x8C, 0x42, 0x24, 0x00, 0x73, + 0x12, 0x11, 0x00, 0x86, 0xEA, 0xCB, 0x54, 0xA0, 0x00, 0xFF, 0xD5, 0xB0, 0xE6, 0x03, 0xE8, 0x17, + 0xC0, 0x1F, 0x5A, 0x00, 0x01, 0x3E, 0xF0, 0x06, 0x4E, 0x03, 0x01, 0x24, 0xEA, 0x7C, 0xEA, 0x82, + 0x50, 0x73, 0x81, 0x0C, 0x50, 0xA5, 0x01, 0x0C, 0x5A, 0x98, 0x0B, 0x04, 0x48, 0x00, 0x01, 0x4D, + 0x00, 0x03, 0x80, 0xEB, 0x5A, 0x08, 0x02, 0xEC, 0x48, 0x00, 0x00, 0x99, 0x5A, 0x08, 0x03, 0x04, + 0x48, 0x00, 0x00, 0xB3, 0x5A, 0x08, 0x04, 0x04, 0x48, 0x00, 0x00, 0xEF, 0xD5, 0xE5, 0x00, 0x13, + 0x80, 0xEC, 0x5A, 0x18, 0x01, 0xE2, 0x22, 0x23, 0x80, 0x78, 0xDD, 0x4C, 0xFE, 0x84, 0xF3, 0x05, + 0x22, 0x03, 0x80, 0x79, 0x8C, 0xC1, 0xFE, 0x1C, 0xE0, 0x40, 0x97, 0xB0, 0xE9, 0x03, 0x80, 0x09, + 0xEA, 0x97, 0x80, 0x09, 0xEA, 0x54, 0x2E, 0x17, 0xF0, 0x09, 0xE2, 0x20, 0x4E, 0xF3, 0x00, 0x9E, + 0xEB, 0x2E, 0x4E, 0x03, 0x00, 0x9B, 0x80, 0x09, 0x84, 0x21, 0xEB, 0xC2, 0xD5, 0xC5, 0x00, 0x13, + 0x80, 0xEC, 0x5A, 0x18, 0x02, 0x1F, 0xF0, 0x05, 0x22, 0x13, 0x80, 0x79, 0xFE, 0x44, 0xDD, 0x4C, + 0xEA, 0x53, 0x96, 0x4B, 0x80, 0x09, 0x49, 0xFF, 0xFE, 0x50, 0x5A, 0x08, 0x01, 0x0B, 0x80, 0x09, + 0x84, 0x22, 0xEB, 0xC2, 0x8C, 0xC1, 0x84, 0x01, 0x97, 0xB0, 0x10, 0x03, 0x81, 0x34, 0xD5, 0xAC, + 0x80, 0x09, 0xEA, 0x54, 0x2E, 0x17, 0xF0, 0x09, 0xE2, 0x20, 0xE9, 0xF2, 0x48, 0x00, 0x00, 0xB9, + 0x5A, 0x18, 0x01, 0xA3, 0x22, 0x23, 0x80, 0x78, 0xDD, 0x4C, 0xFE, 0x84, 0xF3, 0x05, 0x22, 0x03, + 0x80, 0x79, 0x8C, 0xC1, 0xFE, 0x1C, 0xE0, 0x40, 0x97, 0xB0, 0xE9, 0x03, 0x80, 0x09, 0xEA, 0x97, + 0x80, 0x09, 0xEA, 0x54, 0x2E, 0x17, 0xF0, 0x09, 0xE2, 0x20, 0x4E, 0xF2, 0xFF, 0x8E, 0xDD, 0x54, + 0xEA, 0x98, 0x40, 0x80, 0x00, 0x13, 0xDD, 0x41, 0xC8, 0x06, 0x4E, 0x82, 0x00, 0x05, 0x45, 0xC0, + 0x02, 0x76, 0xD5, 0x03, 0x45, 0xC0, 0x01, 0xA4, 0x22, 0x13, 0x80, 0x7B, 0x22, 0x03, 0x80, 0x19, + 0x8A, 0x01, 0xF0, 0x8A, 0x22, 0x13, 0x80, 0x7C, 0x22, 0x03, 0x80, 0x1A, 0x8A, 0x01, 0xF0, 0x8B, + 0xEB, 0x4D, 0xE6, 0x02, 0xE8, 0x0A, 0x00, 0x13, 0x81, 0x02, 0x00, 0x03, 0x81, 0x01, 0xEA, 0x64, + 0x84, 0x20, 0x40, 0x10, 0x80, 0x06, 0xD5, 0x09, 0x4E, 0x83, 0x00, 0x04, 0x84, 0x21, 0xD5, 0x05, + 0xDD, 0x41, 0x5A, 0x08, 0x01, 0xF2, 0xD5, 0xFB, 0xB0, 0x0A, 0xF1, 0x87, 0xDD, 0x4D, 0xEB, 0x2A, + 0xF1, 0x07, 0x4E, 0xF3, 0x01, 0xF6, 0x48, 0x00, 0x01, 0xB3, 0x00, 0x03, 0x80, 0xEC, 0x5A, 0x08, + 0x02, 0x16, 0x84, 0x21, 0x80, 0x09, 0xEA, 0x97, 0x80, 0x09, 0xEA, 0x54, 0x81, 0x00, 0x2F, 0xC7, + 0xF0, 0x08, 0x80, 0x09, 0x49, 0x00, 0x06, 0x6E, 0x88, 0x1C, 0xE0, 0x08, 0xE9, 0x59, 0x8C, 0xC1, + 0x97, 0xB0, 0x80, 0x09, 0x84, 0x23, 0x48, 0xFF, 0xFF, 0x7A, 0x8C, 0xC1, 0x84, 0x00, 0x97, 0xB0, + 0x10, 0x03, 0x81, 0x35, 0xEA, 0xBA, 0x00, 0x03, 0x80, 0xEC, 0x5A, 0x08, 0x01, 0x0B, 0x00, 0x03, + 0x81, 0x33, 0xC8, 0x09, 0x8C, 0xC1, 0x97, 0xB0, 0x80, 0x09, 0x84, 0x22, 0x48, 0xFF, 0xFF, 0x67, + 0x5A, 0x00, 0x02, 0x07, 0x00, 0x03, 0x81, 0x33, 0x5A, 0x00, 0x01, 0x03, 0xEA, 0xBA, 0x80, 0x09, + 0x84, 0x21, 0xEA, 0x97, 0x44, 0x10, 0x01, 0x2C, 0x44, 0x20, 0x02, 0xEE, 0x84, 0x63, 0x80, 0x0A, + 0x49, 0xFF, 0xFD, 0x85, 0x80, 0x09, 0xEA, 0x54, 0xEB, 0x1C, 0xE2, 0x20, 0xE8, 0x04, 0x84, 0x01, + 0x10, 0x03, 0x81, 0x33, 0xDD, 0x41, 0xC8, 0x24, 0x00, 0x03, 0x81, 0x33, 0x5A, 0x00, 0x01, 0x07, + 0x00, 0x03, 0x81, 0x34, 0x5A, 0x08, 0x01, 0x25, 0xD5, 0x07, 0x80, 0x0A, 0x49, 0x00, 0x23, 0xAC, + 0x5A, 0x08, 0x01, 0xF8, 0xD5, 0x15, 0x02, 0x03, 0x80, 0x73, 0xE6, 0x03, 0xE8, 0x19, 0x00, 0x03, + 0x81, 0x2D, 0xC0, 0x0E, 0xD5, 0x15, 0x00, 0x03, 0x80, 0xEC, 0x5A, 0x08, 0x02, 0x15, 0x84, 0x21, + 0x80, 0x09, 0xEA, 0x97, 0x80, 0x09, 0xEA, 0x54, 0xEB, 0x1C, 0xE2, 0x20, 0xE8, 0x09, 0x80, 0x09, + 0x49, 0x00, 0x20, 0x4A, 0x80, 0x0A, 0x84, 0x20, 0xEA, 0x9D, 0xDD, 0x40, 0xEA, 0xBA, 0x8C, 0xC1, + 0x97, 0xB0, 0xEA, 0xBA, 0x8C, 0xC1, 0x80, 0x09, 0x84, 0x20, 0x97, 0xB0, 0xEA, 0x97, 0xEA, 0xBA, + 0xEA, 0x2F, 0x00, 0x23, 0x81, 0x37, 0x81, 0x00, 0x4E, 0x23, 0xFE, 0xDA, 0xEB, 0xFC, 0xB0, 0x0C, + 0xF3, 0x89, 0x38, 0x10, 0x08, 0x00, 0x00, 0x03, 0x81, 0x01, 0xF2, 0x88, 0x88, 0x01, 0x55, 0xC0, + 0x00, 0xFF, 0xB0, 0x0C, 0x88, 0x02, 0xA7, 0x01, 0x00, 0x03, 0x81, 0x02, 0x88, 0x80, 0x97, 0x20, + 0x80, 0x24, 0x80, 0x1C, 0xF4, 0x87, 0xEB, 0x43, 0xF4, 0x07, 0xF2, 0x08, 0xF3, 0x09, 0xC0, 0x0C, + 0x40, 0x0E, 0x00, 0x10, 0x97, 0x22, 0x42, 0x02, 0x0C, 0x73, 0x38, 0xF4, 0x01, 0x11, 0x5E, 0xF7, + 0xFF, 0xEC, 0x4E, 0xF3, 0xFE, 0xB5, 0x8C, 0x42, 0x5A, 0x28, 0x10, 0xDB, 0x84, 0x01, 0x10, 0x03, + 0x81, 0x37, 0x48, 0xFF, 0xFE, 0xAD, 0xEA, 0x4B, 0x84, 0x1D, 0xFE, 0x0E, 0xC6, 0x02, 0xEA, 0x39, + 0x84, 0xA0, 0xEA, 0xDC, 0xEB, 0xC1, 0x80, 0x05, 0x44, 0x20, 0x0B, 0x84, 0x98, 0x6B, 0xEA, 0xE8, + 0xE6, 0x22, 0xE9, 0x05, 0x5A, 0x10, 0x04, 0x04, 0x8C, 0x01, 0x96, 0x00, 0xEB, 0x7A, 0xDA, 0xF7, + 0x44, 0x52, 0x50, 0x34, 0x00, 0x12, 0xFF, 0xFF, 0x18, 0x12, 0xFF, 0xFF, 0xA6, 0x6D, 0xAE, 0x6E, + 0xEA, 0x94, 0xD9, 0xF9, 0x3E, 0x60, 0x1B, 0xB8, 0x3E, 0x00, 0x1B, 0xBD, 0x49, 0x00, 0x58, 0x8F, + 0xEA, 0x4B, 0x5A, 0x08, 0x01, 0x09, 0x54, 0x00, 0x80, 0x01, 0x3E, 0x07, 0xEE, 0x1D, 0x3E, 0x07, + 0xEE, 0x1E, 0xD5, 0x05, 0x54, 0x00, 0x80, 0x01, 0x3E, 0x07, 0xEE, 0x1D, 0x96, 0x4E, 0x84, 0x02, + 0xC9, 0x2C, 0x2E, 0x07, 0xEE, 0x18, 0x5A, 0x00, 0x01, 0x10, 0xC0, 0x06, 0x5A, 0x00, 0x02, 0x28, + 0x5A, 0x00, 0x03, 0x1B, 0xD5, 0x30, 0x2E, 0x07, 0xEE, 0x1D, 0x5A, 0x08, 0x01, 0x2D, 0xEB, 0xBC, + 0x2E, 0x07, 0xEE, 0x1B, 0xD5, 0x0D, 0x2E, 0x07, 0xEE, 0x1D, 0x5A, 0x00, 0x01, 0x06, 0x2E, 0x07, + 0xEE, 0x1E, 0x5A, 0x08, 0x01, 0x12, 0x2E, 0x07, 0xEE, 0x1B, 0x5A, 0x00, 0xFF, 0x1D, 0x8C, 0x01, + 0x3E, 0x07, 0xEE, 0x1B, 0xD5, 0x18, 0x2E, 0x07, 0xEE, 0x1D, 0x5A, 0x00, 0x01, 0x0E, 0x2E, 0x07, + 0xEE, 0x1E, 0x5A, 0x00, 0x01, 0x0A, 0x84, 0x00, 0xEB, 0xBC, 0xD5, 0x0D, 0x84, 0x03, 0xEB, 0xBC, + 0x2E, 0x07, 0xEE, 0x1C, 0xD5, 0x05, 0x2E, 0x07, 0xEE, 0x1C, 0x5A, 0x00, 0xFF, 0x05, 0x8C, 0x01, + 0x3E, 0x07, 0xEE, 0x1C, 0x2E, 0x07, 0xEE, 0x18, 0x5A, 0x08, 0x01, 0x06, 0x84, 0x00, 0x3E, 0x07, + 0xEE, 0x1C, 0xD5, 0x06, 0x84, 0x20, 0x3E, 0x17, 0xEE, 0x1B, 0x5A, 0x08, 0x03, 0xF9, 0x49, 0xFF, + 0xDB, 0xD6, 0x49, 0xFF, 0xD9, 0xD1, 0xDD, 0x46, 0x96, 0x26, 0xC0, 0x1F, 0x84, 0x00, 0x3E, 0x07, + 0xF0, 0x4A, 0xDD, 0x46, 0x54, 0x00, 0x01, 0x00, 0xC0, 0x03, 0x84, 0x02, 0xD5, 0x05, 0xDD, 0x46, + 0xEA, 0x98, 0xC0, 0x04, 0x84, 0x01, 0x3E, 0x07, 0xF0, 0x4A, 0xEA, 0x8C, 0xE6, 0x09, 0xE8, 0x0D, + 0x2E, 0x37, 0xF0, 0x4A, 0x44, 0x12, 0x09, 0x04, 0x44, 0x20, 0x01, 0x48, 0x44, 0x02, 0x08, 0x20, + 0x42, 0x11, 0x88, 0x73, 0x49, 0x00, 0x05, 0x37, 0x84, 0x00, 0x44, 0x32, 0x4C, 0x28, 0x98, 0x83, + 0x00, 0x11, 0x00, 0x0A, 0xC1, 0x04, 0x8E, 0x21, 0x10, 0x11, 0x00, 0x0A, 0x8C, 0x0C, 0x5A, 0x08, + 0x84, 0xF8, 0xDD, 0x41, 0x4E, 0x03, 0x00, 0x99, 0x2E, 0x67, 0xEE, 0x18, 0xC6, 0x07, 0xEB, 0xFA, + 0x5A, 0x60, 0x01, 0x41, 0x5A, 0x60, 0x03, 0x48, 0xFC, 0xC8, 0x84, 0x09, 0xDD, 0x4A, 0x80, 0x20, + 0x80, 0x06, 0x5A, 0x10, 0x01, 0x03, 0x80, 0x26, 0xEB, 0x07, 0x3C, 0x03, 0xF7, 0x0A, 0x44, 0x10, + 0xFF, 0xFB, 0xE0, 0x20, 0xE9, 0x04, 0x8C, 0x01, 0x96, 0x01, 0xD5, 0x03, 0x44, 0x00, 0xFF, 0xFD, + 0x5C, 0xF0, 0x00, 0x79, 0xEB, 0xFA, 0x4E, 0xF3, 0x00, 0x78, 0x49, 0x00, 0x57, 0xE0, 0x5A, 0x00, + 0x01, 0x1F, 0xEB, 0x4B, 0xC8, 0x07, 0x44, 0x00, 0x05, 0x10, 0x49, 0x00, 0x67, 0xF7, 0x3C, 0x0E, + 0x00, 0xE8, 0xEB, 0x4B, 0xC0, 0x14, 0x49, 0x00, 0x41, 0xAB, 0xEA, 0x38, 0x84, 0x00, 0xDD, 0x45, + 0x84, 0x00, 0xEA, 0x20, 0xEA, 0x35, 0xF0, 0x85, 0xEA, 0x3A, 0xF0, 0x86, 0xF1, 0x05, 0x84, 0x00, + 0xF2, 0x06, 0xDD, 0x5B, 0x84, 0x01, 0xDD, 0x45, 0x84, 0x01, 0xEB, 0x76, 0x84, 0x00, 0xEB, 0xFA, + 0xFC, 0xC8, 0x2E, 0x07, 0xEE, 0x1B, 0x5C, 0xF0, 0x00, 0xC9, 0xE9, 0x4E, 0x84, 0x00, 0x80, 0x20, + 0xEB, 0x07, 0xFC, 0xC8, 0x2E, 0x07, 0xEE, 0x1C, 0xE6, 0x1F, 0xD5, 0xF8, 0x84, 0x00, 0x5A, 0x10, + 0x01, 0x2F, 0x02, 0x13, 0x80, 0x72, 0xE6, 0x2A, 0xE8, 0x1D, 0x5A, 0x00, 0x01, 0x1E, 0xE6, 0x22, + 0x4E, 0xF3, 0xFD, 0x9B, 0xB4, 0x6A, 0x04, 0x13, 0x80, 0x10, 0xDD, 0x4C, 0x44, 0x20, 0x00, 0x4B, + 0xFE, 0x0C, 0xFE, 0x9C, 0xE0, 0x40, 0x4E, 0xF2, 0xFD, 0x90, 0x44, 0x10, 0x00, 0x7D, 0xFE, 0x5C, + 0xE0, 0x01, 0xE9, 0x15, 0x4E, 0x82, 0x00, 0x14, 0xDD, 0x41, 0x5A, 0x00, 0x01, 0x03, 0xEA, 0xBA, + 0xD5, 0x0E, 0x5A, 0x08, 0x01, 0x0D, 0x02, 0x03, 0x80, 0x72, 0xE6, 0x04, 0xE8, 0x08, 0x00, 0x03, + 0x80, 0x3E, 0xE6, 0x1B, 0xE8, 0x04, 0x4E, 0x82, 0x00, 0x0F, 0xD5, 0x08, 0x00, 0x03, 0x81, 0x2E, + 0x5A, 0x00, 0x01, 0x04, 0x48, 0xFF, 0xFE, 0x42, 0xD5, 0xF7, 0xDD, 0x41, 0x5A, 0x00, 0x01, 0x04, + 0x48, 0xFF, 0xFE, 0x3C, 0x84, 0x01, 0x10, 0x03, 0x81, 0x2B, 0x48, 0xFF, 0xFE, 0x37, 0x84, 0x01, + 0x5A, 0x18, 0x01, 0xC1, 0xD5, 0xE1, 0xFC, 0xC8, 0x84, 0xA0, 0x80, 0x05, 0xEB, 0xC1, 0x44, 0x20, + 0x0B, 0x84, 0x98, 0x6B, 0xEA, 0xE8, 0x8E, 0x22, 0xE6, 0x22, 0xE8, 0x03, 0x8C, 0x01, 0x96, 0x00, + 0xEB, 0x7A, 0xDA, 0xF8, 0xC0, 0x06, 0x84, 0x01, 0x3E, 0x07, 0xED, 0xE0, 0x84, 0x01, 0xDD, 0x9E, + 0x2E, 0x17, 0xED, 0xE0, 0x5A, 0x18, 0x01, 0x05, 0x3E, 0x07, 0xED, 0xE0, 0x80, 0x01, 0xDD, 0x9E, + 0xFC, 0x40, 0x46, 0x77, 0xFF, 0xFF, 0x50, 0x73, 0x8F, 0xFF, 0x80, 0xC0, 0x80, 0x27, 0xFA, 0x5C, + 0x44, 0x02, 0x4B, 0xD0, 0xDD, 0x40, 0x80, 0x27, 0xFA, 0x5C, 0x44, 0x02, 0x5E, 0x64, 0xDD, 0x40, + 0x2E, 0x47, 0xD9, 0x2B, 0x80, 0x06, 0x2E, 0x77, 0xDE, 0xD5, 0x95, 0x22, 0x84, 0x40, 0x44, 0x62, + 0x4B, 0xD0, 0x96, 0x50, 0xE2, 0x27, 0xE8, 0x14, 0x95, 0x52, 0x84, 0x20, 0x96, 0xC8, 0xE2, 0x67, + 0xE8, 0x0C, 0x38, 0x30, 0x06, 0x02, 0x38, 0x93, 0x14, 0x02, 0x8C, 0x21, 0xE1, 0x23, 0x40, 0x34, + 0xBC, 0x1B, 0x38, 0x33, 0x14, 0x0A, 0xD5, 0xF3, 0x8C, 0x41, 0x88, 0x04, 0xD5, 0xEB, 0xFC, 0xC0, + 0x2E, 0x27, 0xDE, 0xD5, 0x46, 0x18, 0x00, 0x00, 0x84, 0x00, 0x44, 0x42, 0x5E, 0x90, 0x44, 0x52, + 0x5E, 0x38, 0xE0, 0x02, 0xE8, 0x0B, 0x38, 0x32, 0x00, 0x00, 0xCB, 0x06, 0x38, 0x32, 0x82, 0x02, + 0xE0, 0x23, 0x40, 0x11, 0xBC, 0x1B, 0x8C, 0x01, 0xD5, 0xF5, 0x84, 0x00, 0x44, 0x52, 0x4C, 0x1C, + 0x44, 0x42, 0x4B, 0xD0, 0xE0, 0x02, 0xE8, 0x0B, 0x38, 0x32, 0x80, 0x00, 0xC3, 0x06, 0x38, 0x32, + 0x02, 0x02, 0x8A, 0x61, 0x38, 0x32, 0x02, 0x0A, 0x8C, 0x01, 0xD5, 0xF5, 0x84, 0x00, 0x44, 0x52, + 0x5E, 0x90, 0x44, 0x42, 0x5E, 0x64, 0xE0, 0x02, 0xE8, 0x0B, 0x38, 0x32, 0x80, 0x00, 0xC3, 0x06, + 0x38, 0x32, 0x02, 0x02, 0x88, 0x61, 0x38, 0x32, 0x02, 0x0A, 0x8C, 0x01, 0xD5, 0xF5, 0x84, 0x00, + 0x44, 0x52, 0x5E, 0x90, 0x44, 0x42, 0x5E, 0x38, 0xE0, 0x02, 0xE8, 0x0B, 0x38, 0x32, 0x80, 0x00, + 0xCB, 0x06, 0x38, 0x32, 0x02, 0x02, 0x8A, 0x61, 0x38, 0x32, 0x02, 0x0A, 0x8C, 0x01, 0xD5, 0xF5, + 0xDD, 0x9E, 0xFC, 0x40, 0x44, 0x32, 0x4C, 0x1C, 0x84, 0x81, 0x38, 0x41, 0x80, 0x08, 0x44, 0x32, + 0x5B, 0xE0, 0x2E, 0x57, 0xDE, 0xD5, 0x38, 0x11, 0x82, 0x0A, 0x2E, 0x17, 0xD9, 0x2B, 0x44, 0x62, + 0x4B, 0xD0, 0xFE, 0x44, 0x94, 0x4A, 0x88, 0x41, 0x44, 0x72, 0x5E, 0x64, 0x84, 0x20, 0x44, 0x42, + 0x5E, 0x38, 0x44, 0x92, 0x4F, 0x60, 0x96, 0xC8, 0xE2, 0x65, 0xE8, 0x13, 0x38, 0xA3, 0x02, 0x02, + 0x38, 0x33, 0x86, 0x02, 0x88, 0x6A, 0x38, 0xA1, 0x06, 0x02, 0x8A, 0x6A, 0x38, 0xA2, 0x06, 0x02, + 0xE1, 0x43, 0xE8, 0x05, 0x38, 0x32, 0x06, 0x0A, 0x38, 0x04, 0x86, 0x0A, 0x8C, 0x21, 0xD5, 0xEC, + 0xFC, 0xC0, 0xFC, 0x42, 0x44, 0x92, 0x5C, 0x54, 0xB6, 0x1F, 0x2E, 0xA7, 0xDE, 0xD5, 0x2E, 0x57, + 0xEC, 0x0F, 0x4C, 0x55, 0x00, 0xE1, 0x84, 0x20, 0x84, 0x4B, 0x44, 0x02, 0x4C, 0x1C, 0xDD, 0x40, + 0x84, 0x20, 0x84, 0x4B, 0x44, 0x02, 0x5E, 0x90, 0xDD, 0x40, 0x84, 0x3F, 0xFA, 0x5C, 0x44, 0x02, + 0x5B, 0xE0, 0xDD, 0x40, 0x44, 0x02, 0x4F, 0x34, 0x84, 0x20, 0xFA, 0x5C, 0xDD, 0x40, 0x84, 0xE0, + 0xE0, 0xEA, 0xE8, 0x17, 0x38, 0x04, 0x9E, 0x02, 0x5A, 0x0F, 0xFF, 0x12, 0x44, 0x02, 0x5B, 0xE0, + 0x84, 0x3E, 0x38, 0x10, 0x1E, 0x0A, 0x44, 0x02, 0x4C, 0x1C, 0x84, 0x21, 0x38, 0x10, 0x1C, 0x08, + 0x3C, 0x7E, 0x06, 0xAF, 0x80, 0xCA, 0x80, 0x67, 0x84, 0x21, 0xD5, 0x06, 0x8C, 0xE1, 0xD5, 0xE9, + 0x84, 0x20, 0x80, 0xCA, 0x80, 0x61, 0x2E, 0x07, 0xD9, 0x2B, 0xB4, 0x5F, 0xFE, 0x1C, 0x94, 0x02, + 0x88, 0x02, 0x84, 0xA0, 0x45, 0xE2, 0x5E, 0x38, 0x44, 0x42, 0x4B, 0xD0, 0x44, 0x82, 0x5E, 0x64, + 0x44, 0xF2, 0x4F, 0x60, 0x4C, 0x55, 0x00, 0x10, 0x39, 0xC2, 0x0E, 0x02, 0x38, 0x24, 0x16, 0x02, + 0x88, 0x5C, 0x39, 0xC0, 0x16, 0x02, 0x38, 0x37, 0x96, 0x0A, 0x8A, 0x5C, 0x38, 0x2F, 0x16, 0x0A, + 0x8C, 0xA1, 0xD5, 0xF1, 0x84, 0x60, 0x44, 0xA2, 0x5E, 0x90, 0xE0, 0x61, 0xE8, 0x38, 0x44, 0x82, + 0x4F, 0x34, 0x14, 0x8F, 0x80, 0x02, 0x38, 0x74, 0x0E, 0x02, 0x84, 0xC0, 0x45, 0xC2, 0x4B, 0xD0, + 0x44, 0x82, 0x5E, 0x64, 0xEB, 0x8C, 0xE0, 0xC0, 0x4E, 0xF2, 0x00, 0x7B, 0x2E, 0x07, 0xD9, 0x2B, + 0x81, 0xE6, 0x42, 0xF3, 0x80, 0x73, 0x38, 0x4E, 0x1E, 0x02, 0x38, 0x04, 0x1A, 0x02, 0x94, 0xB2, + 0x88, 0x04, 0xB4, 0x9F, 0x38, 0x52, 0x3E, 0x02, 0xD8, 0x18, 0x38, 0x05, 0x18, 0x00, 0xC8, 0x15, + 0xEB, 0x87, 0xF3, 0x83, 0x38, 0x00, 0x08, 0x02, 0x5A, 0x07, 0xFF, 0x12, 0x84, 0x41, 0x38, 0x25, + 0x18, 0x08, 0x9C, 0x89, 0xF2, 0x81, 0xF2, 0x02, 0x38, 0x01, 0x06, 0x0A, 0x80, 0x27, 0x80, 0x44, + 0x49, 0xFF, 0xFF, 0x41, 0xF1, 0x01, 0xF3, 0x03, 0x8C, 0xC1, 0xD5, 0xD5, 0xEB, 0x8C, 0xE0, 0xC0, + 0xE9, 0x36, 0x49, 0xFF, 0xFE, 0xEF, 0x84, 0x20, 0x80, 0xC1, 0x45, 0xC2, 0x5E, 0x38, 0xEB, 0x8C, + 0xE0, 0xC0, 0xE8, 0x2A, 0x38, 0x05, 0x18, 0x00, 0xC8, 0x25, 0x38, 0x0E, 0x1A, 0x02, 0x94, 0xB2, + 0xC8, 0x21, 0xEB, 0x87, 0x38, 0x00, 0x1A, 0x02, 0x5A, 0x0F, 0xFF, 0x07, 0x44, 0x02, 0x4F, 0x60, + 0x38, 0x70, 0x1A, 0x02, 0xD5, 0x1C, 0x84, 0x61, 0x38, 0x35, 0x18, 0x08, 0x44, 0x32, 0x4C, 0x1C, + 0x38, 0x31, 0x80, 0x00, 0xCB, 0x0F, 0x44, 0x32, 0x4F, 0x34, 0x50, 0x80, 0x80, 0x01, 0x38, 0x01, + 0x86, 0x0A, 0x44, 0x12, 0x4F, 0x60, 0x38, 0x10, 0x88, 0x02, 0xB4, 0x5F, 0x49, 0xFF, 0xFF, 0x0B, + 0x80, 0x28, 0x8C, 0xC1, 0xD5, 0xD5, 0x84, 0x60, 0x48, 0xFF, 0xFF, 0x91, 0xEB, 0x8C, 0xE0, 0xC0, + 0xE8, 0x1A, 0x2E, 0x07, 0xEC, 0x0F, 0x44, 0x12, 0x5B, 0xE0, 0x8C, 0x01, 0x3E, 0x07, 0xEC, 0x0F, + 0xEB, 0x87, 0x5A, 0x7F, 0xFE, 0x04, 0x48, 0xFF, 0xFF, 0x2A, 0x38, 0x24, 0x9E, 0x02, 0x38, 0x70, + 0x1A, 0x0A, 0x38, 0x64, 0x9E, 0x0A, 0x38, 0x70, 0x9E, 0x02, 0x80, 0xC2, 0xD5, 0xF3, 0x8C, 0x61, + 0x48, 0xFF, 0xFF, 0x75, 0xFC, 0xC2, 0xFC, 0x01, 0xF0, 0x81, 0x84, 0x00, 0x80, 0xC1, 0x3E, 0x07, + 0xEC, 0x0F, 0x84, 0x3F, 0xFA, 0x5C, 0x44, 0x02, 0x5C, 0x54, 0xDD, 0x40, 0x84, 0x3F, 0xFA, 0x5C, + 0xEB, 0x87, 0xDD, 0x40, 0xF0, 0x01, 0x3E, 0x67, 0xDE, 0xD5, 0x49, 0xFF, 0xFE, 0x5B, 0xF0, 0x01, + 0x49, 0xFF, 0xFF, 0x01, 0xFC, 0x81, 0x4E, 0x05, 0x00, 0x22, 0xE4, 0x02, 0xE9, 0x20, 0x40, 0x50, + 0x08, 0x0A, 0x84, 0x22, 0xCD, 0x05, 0x8E, 0x22, 0x96, 0x4A, 0x84, 0x40, 0xD5, 0x07, 0xD0, 0xFC, + 0x8C, 0x22, 0x96, 0x4A, 0x40, 0x50, 0x04, 0x0E, 0xD5, 0xF6, 0x4E, 0x15, 0x00, 0x0E, 0x94, 0x91, + 0x9C, 0xD1, 0x40, 0x50, 0x04, 0x0E, 0x42, 0xF1, 0x8C, 0x24, 0xE0, 0xAF, 0x8E, 0x22, 0x40, 0x21, + 0xBC, 0x1A, 0x96, 0x4A, 0xD5, 0xF3, 0x80, 0x02, 0xDD, 0x9E, 0x84, 0x00, 0xDD, 0x9E, 0xFC, 0x00, + 0x49, 0xFF, 0xFF, 0xDB, 0xFC, 0x80, 0x9A, 0xCB, 0x8A, 0x02, 0xFE, 0xDC, 0x42, 0x30, 0x00, 0x73, + 0xDD, 0x4C, 0x40, 0x01, 0x80, 0x16, 0xDD, 0x9E, 0xFE, 0x5C, 0xEB, 0x69, 0x80, 0x01, 0xDD, 0x9E, + 0xB4, 0x20, 0x84, 0x61, 0x4E, 0x14, 0x00, 0x03, 0x84, 0x7F, 0x4E, 0x14, 0x00, 0x03, 0xFE, 0x4A, + 0x84, 0x40, 0x40, 0x40, 0x88, 0x0E, 0xC4, 0x04, 0x8C, 0x41, 0x96, 0x90, 0xD5, 0xFB, 0x52, 0x21, + 0x00, 0x1F, 0x96, 0x90, 0x40, 0x10, 0x88, 0x0C, 0xFE, 0x5C, 0xB6, 0x20, 0x80, 0x02, 0xDD, 0x9E, + 0x46, 0x18, 0x00, 0x00, 0x4C, 0x00, 0x80, 0x11, 0xC0, 0x10, 0x4E, 0x04, 0x00, 0x03, 0xFE, 0x02, + 0xFA, 0xAF, 0x40, 0x10, 0x14, 0x0E, 0x96, 0x46, 0xC9, 0x04, 0x8E, 0xA1, 0x97, 0x68, 0xD5, 0xFA, + 0x9C, 0x29, 0x96, 0x00, 0xDD, 0x9E, 0xFA, 0x10, 0xDD, 0x9E, 0xEB, 0x92, 0xE2, 0x02, 0xE8, 0x05, + 0xEA, 0xBB, 0x40, 0x00, 0x80, 0x06, 0xDD, 0x9E, 0x84, 0x00, 0xDD, 0x9E, 0xC0, 0x0B, 0xEB, 0x92, + 0x8E, 0x41, 0x4C, 0x01, 0x00, 0x08, 0xC1, 0x06, 0xEA, 0xBB, 0x8E, 0x01, 0xFE, 0x0D, 0xEA, 0xD8, + 0xDD, 0x9E, 0x84, 0x01, 0xDD, 0x9E, 0x80, 0x80, 0x44, 0x12, 0x50, 0x5C, 0xDD, 0x57, 0x42, 0x12, + 0x00, 0x73, 0x00, 0x20, 0x80, 0xFE, 0x84, 0x02, 0x54, 0x21, 0x00, 0xF0, 0x10, 0x20, 0x80, 0xFE, + 0x2E, 0x27, 0xF0, 0x09, 0x10, 0x00, 0x80, 0xBE, 0x10, 0x00, 0x80, 0xBF, 0x84, 0x60, 0x84, 0x01, + 0x8C, 0x41, 0x12, 0x00, 0x80, 0x5D, 0x12, 0x30, 0x80, 0x5E, 0x12, 0x20, 0x80, 0x5C, 0x44, 0x02, + 0x5C, 0x80, 0xFA, 0x38, 0xEB, 0xF1, 0x8C, 0x08, 0xAE, 0xC4, 0xDD, 0x9E, 0xFC, 0x20, 0x44, 0x42, + 0x5C, 0x80, 0xFA, 0x58, 0x80, 0x64, 0x42, 0x30, 0x88, 0x73, 0x50, 0x61, 0x80, 0x08, 0x2E, 0x57, + 0xD3, 0xD1, 0x80, 0x43, 0xA6, 0xF4, 0xE2, 0x65, 0x9D, 0x59, 0xE9, 0x03, 0xAF, 0x74, 0xFC, 0xA0, + 0xFA, 0xC4, 0x42, 0x30, 0x98, 0x73, 0x8C, 0x64, 0x94, 0xD9, 0x88, 0x64, 0xA5, 0x82, 0xAD, 0x9B, + 0x44, 0x60, 0x01, 0x0C, 0x44, 0x32, 0x50, 0x5C, 0x42, 0x30, 0x98, 0x73, 0x02, 0x31, 0x80, 0x5C, + 0xE6, 0x63, 0xE9, 0x1C, 0xA5, 0x93, 0x22, 0x30, 0x00, 0x07, 0x97, 0xF3, 0xE0, 0xE3, 0x40, 0x61, + 0xBC, 0x1B, 0xAD, 0x93, 0xA5, 0x92, 0x8C, 0x44, 0x97, 0xF3, 0xE0, 0x67, 0x40, 0x33, 0x3C, 0x1A, + 0xAC, 0xD0, 0xA4, 0xD3, 0x22, 0x00, 0x00, 0x08, 0x97, 0x9B, 0xE0, 0xC0, 0xEA, 0xED, 0xAC, 0xD3, + 0xA4, 0xD2, 0x97, 0x9B, 0xE0, 0x06, 0xEB, 0x3E, 0xAC, 0x12, 0xFA, 0x18, 0x42, 0x40, 0x80, 0x73, + 0x10, 0x52, 0x00, 0x0C, 0xFC, 0xA0, 0x84, 0x00, 0x3E, 0x07, 0xF0, 0x4F, 0xEB, 0x6D, 0xDD, 0x9E, + 0x44, 0x12, 0x49, 0xC4, 0x5A, 0x08, 0x02, 0x05, 0x44, 0x02, 0x07, 0x90, 0xD5, 0x03, 0x44, 0x02, + 0x07, 0x80, 0x3A, 0x20, 0x14, 0x00, 0x3A, 0x20, 0x94, 0x20, 0xDD, 0x9E, 0xFC, 0x40, 0x2E, 0x17, + 0xF0, 0x48, 0x2E, 0x60, 0x15, 0x57, 0xE6, 0x23, 0x2E, 0x90, 0x15, 0x5A, 0x3C, 0x37, 0xF8, 0x23, + 0x3C, 0x27, 0xF8, 0x07, 0x3C, 0x53, 0xF4, 0xD2, 0xE9, 0x14, 0x9B, 0x1A, 0x40, 0x71, 0x84, 0x0A, + 0xE0, 0xE4, 0xE9, 0x04, 0x5E, 0xF2, 0x01, 0x2D, 0xE9, 0x0C, 0x3C, 0x43, 0xF8, 0x22, 0xE6, 0x95, + 0xE9, 0x08, 0x5C, 0xF2, 0x80, 0xC8, 0xE8, 0x05, 0x44, 0x40, 0x00, 0x64, 0x3E, 0x47, 0xED, 0xE9, + 0x95, 0x19, 0xE0, 0x82, 0xE8, 0x05, 0xC3, 0x04, 0x84, 0x60, 0x3E, 0x37, 0xED, 0xE9, 0x3C, 0x70, + 0x0A, 0xA9, 0xE0, 0xE2, 0xE8, 0x05, 0x5A, 0x10, 0xFF, 0x04, 0x8C, 0x21, 0xD5, 0x02, 0x84, 0x20, + 0x3E, 0x17, 0xF0, 0x48, 0x3C, 0x43, 0xF6, 0xF3, 0x44, 0x10, 0xFF, 0xFF, 0x3C, 0x4B, 0xF8, 0x22, + 0x3C, 0x2B, 0xF8, 0x23, 0x3C, 0x33, 0xF6, 0x11, 0xD9, 0x04, 0x3C, 0x3B, 0xF4, 0xD2, 0xD5, 0x05, + 0x88, 0xA3, 0x90, 0xA1, 0x3C, 0x5B, 0xF4, 0xD2, 0x2E, 0xA7, 0xF0, 0x4E, 0x4E, 0xA3, 0x00, 0x07, + 0xE0, 0x47, 0xE8, 0x04, 0x9C, 0x75, 0x96, 0x48, 0xD5, 0x02, 0x80, 0x26, 0x2E, 0x57, 0xEE, 0x19, + 0x2E, 0x87, 0xED, 0xE9, 0x4E, 0x53, 0x00, 0x9C, 0x2E, 0xA7, 0xEC, 0x0E, 0x5A, 0xA8, 0x09, 0x38, + 0x3C, 0xF0, 0x0A, 0xAA, 0x85, 0x4A, 0x42, 0xA7, 0xA8, 0x24, 0xE1, 0x43, 0xE8, 0x30, 0x41, 0xC1, + 0x08, 0x0A, 0x41, 0xCE, 0x00, 0x13, 0x5C, 0xFE, 0x00, 0x28, 0xE9, 0x0A, 0x5C, 0xFE, 0x01, 0x2D, + 0x81, 0x5C, 0xE9, 0x03, 0x44, 0xA0, 0x01, 0x2C, 0x40, 0xF5, 0x00, 0x13, 0xD5, 0x03, 0x44, 0xF0, + 0x00, 0x28, 0x3C, 0xA7, 0xEF, 0x4E, 0x8B, 0x42, 0x4E, 0xA4, 0x00, 0x04, 0x52, 0xA5, 0x00, 0x00, + 0xE1, 0x4F, 0xE8, 0x15, 0x3C, 0xF7, 0xE9, 0x56, 0x85, 0x46, 0x42, 0xF7, 0xA8, 0x24, 0xE0, 0x4F, + 0x4E, 0xF2, 0x00, 0xE7, 0x3C, 0xF3, 0xF8, 0x26, 0x44, 0xA0, 0x00, 0x64, 0x42, 0xF7, 0xA8, 0x24, + 0x40, 0xF7, 0x91, 0xF6, 0x5E, 0xF7, 0x80, 0x29, 0x4E, 0xF2, 0x00, 0xDB, 0xC1, 0x23, 0x3C, 0xA0, + 0x0A, 0xA8, 0xE3, 0x44, 0xE8, 0x0E, 0x3D, 0xC0, 0x0A, 0xAA, 0x44, 0xF0, 0x00, 0x1E, 0x42, 0xFE, + 0x3C, 0x24, 0x40, 0xF7, 0x88, 0x0A, 0xE0, 0x6F, 0xE8, 0x04, 0x9C, 0x76, 0x96, 0x48, 0xD5, 0x0C, + 0x85, 0xEA, 0x40, 0xA5, 0x08, 0x08, 0x40, 0xA5, 0x3D, 0x56, 0xE1, 0x44, 0xE8, 0x05, 0xE0, 0x47, + 0xE9, 0x05, 0x9C, 0x72, 0xD5, 0x06, 0xE0, 0x47, 0xE8, 0x05, 0x4E, 0x82, 0x00, 0x04, 0x8C, 0x29, + 0x96, 0x48, 0x84, 0xC0, 0xE0, 0x47, 0x3E, 0x67, 0xF0, 0x4E, 0xE8, 0x1C, 0x3C, 0x63, 0xF6, 0xF2, + 0xE2, 0x26, 0xE8, 0x18, 0xC1, 0x17, 0x2E, 0x60, 0x15, 0x59, 0xE2, 0xC4, 0xE8, 0x13, 0x2E, 0x77, + 0xED, 0xE8, 0xC7, 0x0D, 0x42, 0x61, 0x90, 0x24, 0x44, 0x30, 0x03, 0xE8, 0x40, 0x33, 0x0C, 0x76, + 0x2E, 0x60, 0x15, 0x58, 0x40, 0xF1, 0x9D, 0xF6, 0xE0, 0xCF, 0xE8, 0x04, 0x84, 0x61, 0x3E, 0x37, + 0xF0, 0x4E, 0x3C, 0x30, 0x0A, 0xA8, 0xE2, 0x60, 0xE9, 0x05, 0x3C, 0x63, 0xF8, 0x26, 0xE2, 0xC9, + 0xE9, 0x28, 0x3C, 0x63, 0xF6, 0xF2, 0xE2, 0x26, 0xE8, 0x24, 0xE2, 0x60, 0xE8, 0x06, 0x2E, 0x07, + 0xF0, 0x4E, 0xEA, 0x39, 0x3E, 0x07, 0xF0, 0x4E, 0x3C, 0x03, 0xF8, 0x26, 0xE2, 0x09, 0xE9, 0x19, + 0x2E, 0x07, 0xF0, 0x4E, 0xEA, 0xA5, 0x3E, 0x07, 0xF0, 0x4E, 0xD5, 0x13, 0x5A, 0x50, 0x02, 0xC3, + 0x54, 0x35, 0x00, 0x01, 0x4E, 0x33, 0x00, 0x78, 0x2E, 0x17, 0xF0, 0x4E, 0x54, 0x30, 0x80, 0x02, + 0x4E, 0x33, 0x00, 0x87, 0x2E, 0x07, 0xF0, 0x4E, 0x54, 0x10, 0x00, 0x04, 0x4E, 0x13, 0x00, 0x8F, + 0x4E, 0x82, 0x00, 0x05, 0x8F, 0x01, 0x3E, 0x87, 0xED, 0xE9, 0xEA, 0xCE, 0xE0, 0x41, 0xE8, 0x12, + 0x3C, 0x07, 0xF8, 0x05, 0x4E, 0x04, 0x00, 0x03, 0xFE, 0x02, 0xE0, 0x01, 0xE8, 0x0B, 0x2E, 0x10, + 0x15, 0x59, 0x84, 0x03, 0xFE, 0x0C, 0x90, 0x02, 0xE0, 0x80, 0xE8, 0x04, 0x84, 0x00, 0x3E, 0x07, + 0xED, 0xE9, 0x2E, 0x67, 0xF0, 0x4E, 0x3E, 0x67, 0xED, 0xEA, 0x5A, 0x50, 0x01, 0x22, 0xC5, 0x0D, + 0x5A, 0x50, 0x02, 0x25, 0x5A, 0x50, 0x03, 0x04, 0x48, 0x00, 0x00, 0x78, 0x49, 0xFF, 0xD5, 0x53, + 0xEB, 0x4A, 0x84, 0x00, 0xEB, 0x6D, 0xD5, 0x3A, 0xCE, 0x04, 0x3E, 0x67, 0xF0, 0x49, 0xD5, 0x6D, + 0x2E, 0x07, 0xF0, 0x49, 0x2E, 0x10, 0x15, 0x56, 0xE2, 0x01, 0xE9, 0x06, 0x84, 0x00, 0x3E, 0x07, + 0xF0, 0x49, 0x84, 0x01, 0xD5, 0x09, 0x8C, 0x01, 0x3E, 0x07, 0xF0, 0x49, 0xD5, 0x5E, 0xCE, 0x5D, + 0x3E, 0x67, 0xF0, 0x4F, 0x84, 0x02, 0xEB, 0x6D, 0xD5, 0x58, 0xCE, 0x1D, 0x2E, 0x07, 0xF0, 0x4F, + 0x2E, 0x17, 0xF0, 0x4B, 0x8C, 0x01, 0x96, 0x00, 0x3E, 0x07, 0xF0, 0x4F, 0x5A, 0x18, 0x01, 0x0E, + 0x3C, 0x17, 0xF8, 0x06, 0xE0, 0x22, 0xE8, 0x09, 0x49, 0xFF, 0xD5, 0x25, 0xEB, 0x4A, 0x3E, 0x67, + 0xF0, 0x4B, 0x3E, 0x67, 0xEE, 0x19, 0xD5, 0x41, 0x2E, 0x10, 0x15, 0x5B, 0xE2, 0x20, 0x84, 0x03, + 0xE9, 0x03, 0xD5, 0x3B, 0x84, 0x01, 0xEB, 0x6D, 0x84, 0x00, 0xEB, 0xD5, 0xD5, 0x36, 0x84, 0x20, + 0x48, 0xFF, 0xFF, 0x49, 0x3C, 0x33, 0xF6, 0xF2, 0xE2, 0x23, 0x4E, 0xF3, 0xFF, 0x87, 0xE0, 0x47, + 0xE9, 0x06, 0x2E, 0x10, 0x15, 0x59, 0xE2, 0x81, 0x4E, 0xF2, 0xFF, 0x80, 0x54, 0xA5, 0x00, 0xFE, + 0x84, 0x21, 0x3E, 0xA7, 0xF0, 0x4E, 0x3E, 0x17, 0xF0, 0x4B, 0x48, 0xFF, 0xFF, 0x77, 0x3C, 0x30, + 0x0A, 0xA7, 0x94, 0xDB, 0xE0, 0x60, 0x4E, 0xF3, 0xFF, 0x77, 0x54, 0x10, 0x80, 0xFD, 0x84, 0x00, + 0x3E, 0x17, 0xF0, 0x4E, 0xEB, 0xD5, 0x48, 0xFF, 0xFF, 0x6F, 0x3C, 0x13, 0xF8, 0x26, 0x3C, 0x30, + 0x0A, 0xA7, 0xE2, 0x61, 0x4E, 0xF3, 0xFF, 0x6E, 0x54, 0x00, 0x00, 0xFB, 0x3E, 0x07, 0xF0, 0x4E, + 0x84, 0x00, 0xEB, 0xD5, 0x48, 0xFF, 0xFF, 0x66, 0x2E, 0x17, 0xEE, 0x19, 0x84, 0x00, 0x40, 0x00, + 0x04, 0x06, 0xFC, 0xC0, 0xFC, 0x20, 0x80, 0x80, 0x2E, 0x36, 0xF3, 0xC0, 0xEA, 0x9D, 0x42, 0x40, + 0x88, 0x73, 0x2E, 0x67, 0xD8, 0x6E, 0x50, 0x00, 0x00, 0xBF, 0x84, 0xA0, 0x96, 0x49, 0xE2, 0xA3, + 0xE8, 0x14, 0xA6, 0x80, 0x5A, 0x28, 0x04, 0x0E, 0xD1, 0x0C, 0x9F, 0xC7, 0x02, 0x22, 0x00, 0x5C, + 0xA5, 0xF8, 0x8A, 0x47, 0x4E, 0x24, 0x00, 0x03, 0xFE, 0x92, 0x96, 0x91, 0xE2, 0x46, 0xE9, 0x07, + 0x8C, 0xA1, 0x97, 0x69, 0xEB, 0xA2, 0xD5, 0xEC, 0x84, 0x00, 0xFC, 0xA0, 0x84, 0x01, 0xFC, 0xA0, + 0x44, 0x20, 0x01, 0x0C, 0xEA, 0x94, 0xEB, 0x69, 0x04, 0x00, 0x80, 0x47, 0xC0, 0x02, 0x84, 0x04, + 0xDD, 0x9E, 0xFC, 0x4E, 0x84, 0xE0, 0xF0, 0x83, 0x81, 0x01, 0xF7, 0x8F, 0xF7, 0x90, 0xF7, 0x91, + 0xF7, 0x92, 0xEA, 0x2F, 0xF0, 0x85, 0x3E, 0x70, 0x1B, 0xE0, 0xEA, 0x4E, 0x3E, 0x70, 0x1B, 0xE1, + 0xF0, 0x81, 0xEA, 0x50, 0xB6, 0x1F, 0x80, 0xC0, 0x44, 0xA2, 0x5C, 0x80, 0xEA, 0x6F, 0x81, 0x27, + 0x41, 0xC0, 0x04, 0x09, 0x40, 0x0E, 0x00, 0x13, 0xF0, 0x82, 0xF0, 0x01, 0x4C, 0x90, 0x00, 0xEF, + 0xDD, 0x5A, 0x4E, 0x02, 0x00, 0xE5, 0x5A, 0x08, 0x03, 0x04, 0x48, 0x00, 0x00, 0xE1, 0xEB, 0x34, + 0xEA, 0xD6, 0x2E, 0x27, 0xF0, 0x4A, 0xF1, 0x8D, 0xF0, 0x8E, 0xCA, 0x06, 0x3C, 0x73, 0x79, 0xD4, + 0x92, 0xE1, 0xE0, 0x27, 0xD5, 0x07, 0x5A, 0x28, 0x01, 0x09, 0x3C, 0x73, 0x79, 0xD5, 0x92, 0xE1, + 0xE0, 0x07, 0x56, 0x77, 0x80, 0x01, 0xD5, 0x06, 0x5A, 0x28, 0x02, 0x05, 0xF1, 0x02, 0x40, 0x70, + 0x04, 0x07, 0x84, 0x00, 0xFA, 0xA4, 0xEA, 0x62, 0x84, 0x60, 0xFF, 0x7C, 0x40, 0x04, 0x1C, 0x00, + 0xA6, 0x01, 0xE2, 0x60, 0xE8, 0x1B, 0xFA, 0x18, 0xF5, 0x87, 0x42, 0x51, 0x80, 0x73, 0x50, 0x12, + 0x80, 0x08, 0xB0, 0x0D, 0x88, 0x28, 0x84, 0x44, 0xF3, 0x86, 0xF5, 0x84, 0x49, 0xFF, 0xD5, 0xE6, + 0xF4, 0x04, 0xF3, 0x06, 0xF5, 0x07, 0x5A, 0x08, 0x01, 0x07, 0x88, 0x88, 0x00, 0x02, 0x00, 0x18, + 0xDD, 0x4B, 0xEA, 0x62, 0x8C, 0x61, 0x96, 0xD8, 0xD5, 0xE2, 0x9D, 0x39, 0xFA, 0xA4, 0x97, 0x0F, + 0x84, 0x60, 0xFF, 0x7C, 0x95, 0x25, 0x40, 0x04, 0x1C, 0x00, 0xA6, 0x03, 0xE2, 0x60, 0xE8, 0x1B, + 0xFA, 0x18, 0xF5, 0x86, 0x42, 0x51, 0x80, 0x73, 0x50, 0x12, 0x80, 0xF8, 0xB0, 0x0D, 0x88, 0x28, + 0x84, 0x44, 0xF4, 0x87, 0xF3, 0x84, 0x49, 0xFF, 0xD5, 0xC1, 0xF3, 0x04, 0xF5, 0x06, 0xF4, 0x07, + 0x5A, 0x08, 0x01, 0x07, 0xEA, 0x51, 0x54, 0x00, 0x00, 0x9F, 0xFE, 0x27, 0xEA, 0x62, 0x8C, 0x61, + 0x96, 0xD8, 0xD5, 0xE2, 0xEA, 0x66, 0x54, 0x10, 0x00, 0x01, 0xC9, 0x0B, 0x54, 0x00, 0x00, 0x60, + 0xC0, 0x08, 0x5A, 0x08, 0x20, 0x04, 0xFA, 0x1E, 0xD5, 0x03, 0x44, 0x00, 0x00, 0x4E, 0xEA, 0x62, + 0xEA, 0x86, 0x5A, 0x08, 0x01, 0x2D, 0x04, 0x13, 0x00, 0x3A, 0x54, 0x00, 0x80, 0x02, 0xC0, 0x14, + 0xEA, 0x66, 0x96, 0x0E, 0x4E, 0x02, 0x05, 0x15, 0x22, 0x03, 0x00, 0x02, 0x22, 0x25, 0x00, 0x11, + 0xE0, 0x40, 0xE8, 0x0A, 0x12, 0x05, 0x00, 0x11, 0xA4, 0x37, 0x12, 0x05, 0x00, 0x12, 0x02, 0x03, + 0x00, 0x08, 0x12, 0x05, 0x00, 0x13, 0xEA, 0x66, 0x96, 0x56, 0x96, 0x16, 0xC1, 0x05, 0xC8, 0x09, + 0xEA, 0x51, 0xEA, 0xA5, 0xD5, 0x05, 0xC0, 0x05, 0xEA, 0x51, 0x54, 0x00, 0x00, 0xFB, 0xEA, 0x62, + 0xEA, 0x66, 0x96, 0x06, 0xC8, 0x04, 0xEA, 0x51, 0xEB, 0x6A, 0xEA, 0x62, 0x04, 0x23, 0x00, 0x39, + 0x96, 0x9F, 0xC2, 0x17, 0xEA, 0x50, 0x80, 0x29, 0xF2, 0x84, 0x49, 0xFF, 0xFF, 0x05, 0xF2, 0x04, + 0x5A, 0x08, 0x01, 0x10, 0xEA, 0x51, 0x8C, 0x4F, 0x54, 0x00, 0x00, 0xF9, 0xEA, 0x62, 0x54, 0x01, + 0x00, 0x0F, 0x00, 0x23, 0x00, 0xE4, 0x54, 0x21, 0x00, 0xF0, 0xFE, 0x87, 0x10, 0x23, 0x00, 0xE4, + 0xEA, 0x66, 0x54, 0x10, 0x00, 0x60, 0xC9, 0x13, 0x00, 0x23, 0x00, 0xE3, 0x5A, 0x28, 0x01, 0x10, + 0x04, 0x13, 0x00, 0x39, 0x54, 0x30, 0x80, 0x30, 0x5A, 0x38, 0x10, 0x0A, 0x00, 0x33, 0x00, 0xC0, + 0x5A, 0x30, 0x02, 0x06, 0x96, 0x5F, 0xC9, 0x03, 0x10, 0x23, 0x00, 0xE2, 0x54, 0x00, 0x00, 0x61, + 0xC8, 0x0E, 0xDD, 0x5A, 0x8E, 0x01, 0xE6, 0x03, 0xE8, 0x0A, 0xF0, 0x0E, 0xE0, 0x1C, 0x84, 0x01, + 0xE8, 0x04, 0x3E, 0x00, 0x1B, 0xE0, 0xD5, 0x03, 0x3E, 0x00, 0x1B, 0xE1, 0xEA, 0x7C, 0xEA, 0x82, + 0xEB, 0x49, 0x50, 0xA5, 0x00, 0x28, 0x48, 0xFF, 0xFF, 0x12, 0x84, 0xE0, 0xEA, 0xBB, 0x44, 0x92, + 0x5C, 0x80, 0xF0, 0x84, 0x92, 0x01, 0xF0, 0x8B, 0xEA, 0x4E, 0xE2, 0xE0, 0xF0, 0x82, 0x4E, 0xF2, + 0x04, 0x24, 0xDD, 0x57, 0x44, 0x62, 0x50, 0x5C, 0x42, 0x63, 0x80, 0x73, 0xDD, 0x5A, 0x4E, 0x02, + 0x04, 0x18, 0x5A, 0x08, 0x03, 0x08, 0x84, 0x00, 0x14, 0x03, 0x00, 0x3E, 0x84, 0x24, 0x48, 0x00, + 0x03, 0x8D, 0x22, 0x13, 0x00, 0x62, 0x2E, 0x07, 0xD3, 0xCD, 0x44, 0x80, 0x00, 0x64, 0xFE, 0x0C, + 0x3C, 0x14, 0x0A, 0x9C, 0x40, 0x00, 0x20, 0x16, 0xE0, 0x20, 0xE8, 0x03, 0xEA, 0x71, 0xD5, 0x03, + 0x54, 0x80, 0x80, 0xFF, 0xEB, 0x5D, 0x5A, 0x00, 0x01, 0x04, 0x48, 0x00, 0x00, 0xB5, 0x94, 0x79, + 0xEB, 0xF5, 0x41, 0xC0, 0x80, 0x00, 0x84, 0x00, 0x12, 0x0E, 0x00, 0x00, 0x80, 0x29, 0x2E, 0xA6, + 0xF3, 0xAE, 0xFA, 0x18, 0xEA, 0x27, 0x80, 0x01, 0x84, 0x20, 0xB6, 0x20, 0x00, 0x03, 0x00, 0x9D, + 0x00, 0x53, 0x00, 0x9C, 0xF0, 0x87, 0x50, 0x05, 0x7F, 0xFF, 0xF0, 0x88, 0xF0, 0x04, 0xF1, 0x81, + 0x8E, 0x01, 0xF0, 0x89, 0x50, 0x05, 0x7F, 0xFE, 0xF0, 0x8A, 0xF0, 0x04, 0x80, 0x61, 0x80, 0x41, + 0x51, 0xE0, 0x7F, 0xFE, 0xF0, 0x07, 0xE2, 0x05, 0xE9, 0x3B, 0x00, 0x43, 0x00, 0x9F, 0x00, 0x03, + 0x00, 0x9E, 0xF4, 0x86, 0xF4, 0x06, 0xE2, 0x80, 0xE9, 0x30, 0x81, 0xE5, 0xF4, 0x05, 0x42, 0xF0, + 0x28, 0x73, 0x38, 0xF2, 0x3D, 0x11, 0xE1, 0x0F, 0xE8, 0x25, 0xC5, 0x03, 0xF4, 0x08, 0xDC, 0x07, + 0xF4, 0x01, 0x8C, 0x4A, 0x8C, 0x81, 0x97, 0x20, 0xF4, 0x81, 0xD5, 0x12, 0xC0, 0x04, 0xF4, 0x09, + 0x4C, 0x02, 0x40, 0x08, 0xF4, 0x01, 0x8C, 0x6A, 0x8C, 0x81, 0x97, 0x20, 0xF4, 0x81, 0xD5, 0x11, + 0x5A, 0x50, 0x01, 0x04, 0xF4, 0x0A, 0xDC, 0x06, 0x8C, 0x21, 0x96, 0x48, 0x8C, 0x41, 0x96, 0x93, + 0xD5, 0x09, 0x5A, 0x00, 0x01, 0x04, 0x4C, 0x0F, 0x40, 0x06, 0x8C, 0x21, 0x96, 0x48, 0x8C, 0x61, + 0x96, 0xDB, 0x8C, 0x01, 0x96, 0x00, 0xD5, 0xCF, 0x8C, 0xA1, 0x97, 0x68, 0xD5, 0xC4, 0x00, 0x03, + 0x00, 0xD5, 0x4E, 0x26, 0x00, 0x05, 0x4E, 0x36, 0x00, 0x15, 0xD5, 0x2E, 0xE0, 0x62, 0xE8, 0x11, + 0xFA, 0x58, 0x80, 0x69, 0x42, 0x33, 0x88, 0x73, 0x40, 0xF5, 0x04, 0x09, 0xA6, 0x98, 0xE2, 0x0F, + 0x54, 0x21, 0x00, 0xFC, 0xE8, 0x03, 0xEB, 0x8A, 0xD5, 0x18, 0x58, 0x21, 0x00, 0x02, 0xD5, 0x15, + 0x2E, 0x27, 0xF0, 0x4A, 0xC2, 0x13, 0x00, 0x23, 0x00, 0xD6, 0xF3, 0x0B, 0xE2, 0x43, 0xFA, 0x58, + 0x80, 0x69, 0x42, 0x33, 0x88, 0x73, 0xA6, 0x98, 0x54, 0x21, 0x00, 0xF3, 0xE8, 0x04, 0x58, 0x21, + 0x00, 0x04, 0xD5, 0x03, 0x58, 0x21, 0x00, 0x08, 0xAE, 0x98, 0x00, 0x2F, 0x80, 0x04, 0x10, 0x1E, + 0x00, 0x01, 0x10, 0x2E, 0x00, 0x00, 0x00, 0x13, 0x00, 0xD6, 0xEA, 0x64, 0xC0, 0x07, 0xFA, 0x18, + 0x80, 0x29, 0xEA, 0x27, 0xA6, 0x08, 0xEA, 0x65, 0xAE, 0x08, 0x00, 0x03, 0x00, 0xD5, 0xE6, 0x02, + 0xE9, 0x04, 0x8F, 0x42, 0xE0, 0x0A, 0xE9, 0x0F, 0x00, 0x03, 0x00, 0xD6, 0xE6, 0x02, 0xE9, 0x05, + 0xF1, 0x04, 0x8E, 0x22, 0xE0, 0x01, 0xE9, 0x07, 0xFA, 0x18, 0x80, 0x29, 0xEA, 0x27, 0xA6, 0x08, + 0xEA, 0x93, 0xAE, 0x08, 0x04, 0x83, 0x00, 0x37, 0x54, 0xA4, 0x00, 0x60, 0x4E, 0xA2, 0x00, 0x4B, + 0x00, 0x03, 0x00, 0xE2, 0xC8, 0x47, 0x04, 0x53, 0x00, 0x3A, 0x54, 0x02, 0x80, 0x60, 0xC0, 0x42, + 0xDD, 0x5A, 0x5A, 0x00, 0x01, 0x40, 0x92, 0xA5, 0x40, 0x04, 0x14, 0x09, 0x97, 0x4F, 0x96, 0x0F, + 0xD8, 0x39, 0x2E, 0x07, 0xF0, 0x4A, 0xC0, 0x16, 0x5A, 0x08, 0x01, 0x0E, 0x5A, 0xA8, 0x20, 0x05, + 0x2E, 0x00, 0x1B, 0xE0, 0xD5, 0x05, 0x5A, 0xA8, 0x40, 0x2E, 0x2E, 0x00, 0x1B, 0xE1, 0x5A, 0x00, + 0x01, 0x0E, 0xD5, 0x28, 0x5A, 0x08, 0x02, 0x27, 0x5A, 0xA0, 0x20, 0xF9, 0x5A, 0xA8, 0x40, 0x23, + 0xD5, 0xF0, 0x2E, 0x00, 0x1B, 0xE1, 0x5A, 0x08, 0x01, 0xED, 0xFA, 0x58, 0x83, 0x89, 0x43, 0xC3, + 0x88, 0x73, 0x80, 0x1C, 0x84, 0x20, 0xDD, 0x40, 0xEB, 0x5B, 0x12, 0x0E, 0x00, 0x02, 0x12, 0x0E, + 0x00, 0x04, 0x84, 0x04, 0xEB, 0x7F, 0x84, 0x01, 0x10, 0x03, 0x00, 0xE3, 0xEB, 0xE8, 0x00, 0x03, + 0x00, 0xE4, 0xEB, 0xD6, 0xEA, 0x65, 0xEB, 0x3D, 0x84, 0x00, 0xEB, 0xC5, 0xEA, 0x51, 0x10, 0x03, + 0x00, 0xE8, 0xEA, 0x86, 0x5A, 0x08, 0x01, 0x04, 0x48, 0x00, 0x00, 0xAD, 0xC0, 0x06, 0x5A, 0x08, + 0x02, 0x04, 0x48, 0x00, 0x02, 0x70, 0xEA, 0x74, 0x00, 0x03, 0x01, 0x06, 0x5A, 0x08, 0x01, 0x07, + 0xB4, 0x06, 0x5E, 0xF0, 0x13, 0x88, 0x4E, 0xF3, 0x02, 0xE4, 0x00, 0x03, 0x01, 0x08, 0x5A, 0x08, + 0x01, 0x0B, 0x54, 0x04, 0x00, 0x10, 0xC0, 0x07, 0x84, 0x00, 0x10, 0x03, 0x01, 0x08, 0x84, 0x04, + 0xEB, 0x7F, 0xEA, 0x74, 0xDD, 0x5A, 0x5A, 0x00, 0x02, 0x03, 0xEA, 0x74, 0xEB, 0x8F, 0xE6, 0x02, + 0x4E, 0xF2, 0x02, 0xCF, 0x54, 0x04, 0x00, 0x61, 0xC0, 0x1D, 0xEB, 0xF5, 0x94, 0xB9, 0x88, 0x40, + 0x84, 0x01, 0xEB, 0xE8, 0x3C, 0x13, 0xEC, 0x38, 0xA6, 0x10, 0x3C, 0x33, 0xEC, 0x39, 0xFE, 0x44, + 0xA6, 0x11, 0x00, 0x23, 0x00, 0xE4, 0x42, 0x11, 0x80, 0x75, 0x3C, 0x03, 0xEC, 0x3A, 0x8A, 0x20, + 0x44, 0x0F, 0xFF, 0xCF, 0xFE, 0x16, 0x4E, 0x17, 0x00, 0x04, 0xEA, 0x93, 0xD5, 0x02, 0xEA, 0x65, + 0xEB, 0x3D, 0x2E, 0x07, 0xF0, 0x4A, 0xC8, 0x06, 0x4E, 0xA2, 0x00, 0x26, 0x2E, 0x00, 0x1B, 0xE1, + 0xD5, 0x07, 0x5A, 0x08, 0x01, 0x1B, 0x5A, 0xA8, 0x20, 0x16, 0x2E, 0x00, 0x1B, 0xE0, 0x5A, 0x08, + 0x01, 0x1B, 0xEA, 0x51, 0x84, 0x21, 0x54, 0x00, 0x00, 0xF9, 0x10, 0x03, 0x00, 0xE8, 0x00, 0x03, + 0x00, 0xE4, 0x10, 0x13, 0x00, 0xBE, 0xEB, 0xD6, 0xEA, 0x65, 0xEB, 0x3D, 0x10, 0x13, 0x00, 0xE3, + 0xD5, 0x0A, 0x5A, 0xA8, 0x40, 0x09, 0xD5, 0xE3, 0x5A, 0x08, 0x02, 0x06, 0x5A, 0xA0, 0x40, 0xE7, + 0x5A, 0xA0, 0x20, 0xDE, 0xEA, 0x86, 0x5A, 0x00, 0x01, 0x03, 0xEA, 0x74, 0xEA, 0x51, 0xFA, 0x58, + 0x81, 0x49, 0x42, 0xA3, 0x88, 0x73, 0x10, 0x03, 0x00, 0xE8, 0x84, 0x20, 0x80, 0x0A, 0xDD, 0x40, + 0xEB, 0x5B, 0x12, 0x05, 0x00, 0x02, 0x12, 0x05, 0x00, 0x04, 0x2E, 0x17, 0xDE, 0xE6, 0xEB, 0xF7, + 0x85, 0x00, 0xE2, 0x01, 0xEA, 0xD5, 0x54, 0xA0, 0x00, 0xFF, 0x45, 0xC0, 0x00, 0x14, 0x54, 0x04, + 0x00, 0xFF, 0xE2, 0x0A, 0xE8, 0x0D, 0x40, 0x05, 0x20, 0x01, 0x80, 0x26, 0x42, 0x10, 0x70, 0x73, + 0x80, 0x01, 0x8E, 0x14, 0x80, 0x27, 0x49, 0xFF, 0xFA, 0xFB, 0x8D, 0x01, 0xD5, 0xF1, 0xFA, 0x18, + 0x44, 0x12, 0x5C, 0x80, 0xEA, 0x27, 0x50, 0x00, 0x80, 0x20, 0xA4, 0x72, 0xAC, 0x41, 0xA4, 0x77, + 0xAC, 0x42, 0x02, 0x13, 0x00, 0x08, 0xAC, 0x43, 0x84, 0x04, 0xEB, 0x7F, 0x84, 0x00, 0xEB, 0xC5, + 0xEA, 0x74, 0x94, 0x79, 0xEB, 0xF5, 0x40, 0xA0, 0x80, 0x00, 0xEA, 0x2F, 0x04, 0x03, 0x00, 0x39, + 0x00, 0x15, 0x00, 0x00, 0x54, 0x00, 0x00, 0x30, 0x00, 0x25, 0x00, 0x01, 0x5A, 0x08, 0x10, 0x15, + 0x3C, 0x03, 0xEC, 0x38, 0x3C, 0x33, 0xEC, 0x39, 0xFE, 0x0C, 0x42, 0x01, 0x88, 0x75, 0x3C, 0x23, + 0xEC, 0x3A, 0x8A, 0x02, 0x4E, 0x07, 0x00, 0x09, 0xE6, 0x26, 0xE9, 0x06, 0x00, 0x03, 0x00, 0xE4, + 0xEB, 0xD6, 0xEA, 0x93, 0xEB, 0x3D, 0xEA, 0x66, 0x54, 0x10, 0x00, 0x60, 0xC9, 0x06, 0x04, 0x13, + 0x00, 0x3A, 0x54, 0x10, 0x80, 0x60, 0xC1, 0x11, 0x04, 0x13, 0x00, 0x39, 0x96, 0x6F, 0x5A, 0x18, + 0x10, 0x0D, 0x00, 0x13, 0x00, 0xE2, 0x5A, 0x18, 0x01, 0x09, 0x54, 0x00, 0x00, 0x11, 0xC8, 0x05, + 0x84, 0x02, 0xEB, 0xE8, 0x80, 0x07, 0xEB, 0x7E, 0x04, 0x13, 0x00, 0x39, 0x44, 0x00, 0xFF, 0x30, + 0xFE, 0x0E, 0x5A, 0x00, 0x10, 0x04, 0x48, 0x00, 0x00, 0xB2, 0x00, 0x03, 0x00, 0xE3, 0x4E, 0x03, + 0x00, 0xAE, 0xEB, 0x5D, 0x5A, 0x08, 0x01, 0x05, 0xFD, 0x03, 0x49, 0xFF, 0xFA, 0x99, 0x04, 0x53, + 0x00, 0x37, 0x54, 0x02, 0x80, 0x05, 0x5A, 0x00, 0x01, 0x70, 0xFA, 0x18, 0x80, 0x29, 0xEA, 0x27, + 0x2E, 0x07, 0xD3, 0xD1, 0x00, 0x20, 0x80, 0x0C, 0x4C, 0x01, 0x40, 0x67, 0xA4, 0x8B, 0xA5, 0x0A, + 0x8C, 0x24, 0x9B, 0x14, 0xA4, 0xCA, 0xA4, 0x8B, 0x50, 0x80, 0x7F, 0xFF, 0x9A, 0xD3, 0xFA, 0x04, + 0x97, 0x21, 0x96, 0xD9, 0x84, 0x43, 0xEB, 0x54, 0x85, 0x40, 0x43, 0xC3, 0x80, 0x24, 0xE0, 0x48, + 0xE8, 0x18, 0xE6, 0x4B, 0x80, 0x02, 0xE9, 0x02, 0x84, 0x0A, 0x96, 0x00, 0x88, 0x1C, 0x8C, 0x04, + 0x94, 0x01, 0x88, 0x09, 0x8C, 0x41, 0x22, 0x00, 0x00, 0x03, 0x96, 0x90, 0xE0, 0x0A, 0x83, 0xC0, + 0x41, 0xE5, 0x3C, 0x1B, 0xE0, 0x20, 0x40, 0x00, 0xBC, 0x1B, 0x81, 0x5E, 0x80, 0x20, 0xD5, 0xE8, + 0xFA, 0x18, 0x44, 0x22, 0x5C, 0x80, 0x42, 0x23, 0x80, 0x73, 0x22, 0x81, 0x00, 0x0B, 0x22, 0x01, + 0x00, 0x0C, 0xF2, 0x03, 0x2E, 0xF7, 0xF0, 0x4A, 0xA4, 0x97, 0xE9, 0x09, 0x94, 0x91, 0xE0, 0x82, + 0xE8, 0x2B, 0xF2, 0x03, 0x02, 0x21, 0x00, 0x08, 0xE2, 0x62, 0xD5, 0x08, 0xE2, 0x82, 0xE8, 0x24, + 0xF2, 0x03, 0x02, 0x21, 0x00, 0x08, 0x94, 0x91, 0xE0, 0x62, 0xE8, 0x1E, 0x3C, 0x34, 0x0A, 0x9D, + 0x2E, 0x27, 0xD3, 0xD4, 0x88, 0x08, 0x90, 0x01, 0xFE, 0x9C, 0xE0, 0x40, 0xE8, 0x15, 0x40, 0x15, + 0x04, 0x01, 0xDD, 0x4C, 0x96, 0x4B, 0xFE, 0x44, 0xF0, 0x03, 0x40, 0x10, 0xA8, 0x36, 0x02, 0x00, + 0x00, 0x09, 0x96, 0x4B, 0xE0, 0x20, 0xE9, 0x04, 0x54, 0x02, 0x80, 0x01, 0xC8, 0x05, 0x80, 0x07, + 0xEB, 0x7E, 0x48, 0x00, 0x01, 0x02, 0x97, 0x4E, 0xC5, 0x31, 0x04, 0x03, 0x00, 0x3B, 0xC8, 0x2E, + 0x04, 0x53, 0x00, 0x39, 0x54, 0x22, 0x80, 0x0F, 0xCA, 0x29, 0x02, 0x13, 0x00, 0x70, 0x3C, 0x00, + 0x0A, 0x8C, 0x8A, 0x01, 0x3C, 0x13, 0xE9, 0xE5, 0x96, 0x01, 0xE2, 0x20, 0xE9, 0x1F, 0xEB, 0x5D, + 0x5A, 0x08, 0x02, 0x1D, 0x45, 0xC2, 0x50, 0xF8, 0x81, 0x02, 0x50, 0xA3, 0x00, 0x9C, 0xF0, 0x02, + 0x4C, 0x80, 0x01, 0xB4, 0x00, 0x0E, 0x00, 0x23, 0x5A, 0x08, 0x04, 0x0A, 0x4C, 0x83, 0x80, 0x08, + 0x80, 0x0A, 0x80, 0x3C, 0x49, 0x00, 0x01, 0xE2, 0x5A, 0x00, 0x01, 0x09, 0x50, 0x54, 0x00, 0x01, + 0x54, 0x82, 0x80, 0xFF, 0x51, 0xCE, 0x01, 0x0C, 0xD5, 0xEB, 0xEA, 0x66, 0x54, 0x10, 0x00, 0x08, + 0x4E, 0x12, 0x00, 0xCB, 0x00, 0x13, 0x00, 0xE3, 0xC1, 0x05, 0x54, 0x00, 0x00, 0x60, 0x4E, 0x03, + 0x00, 0xC4, 0xEB, 0x34, 0x22, 0x23, 0x00, 0x65, 0xEA, 0xD6, 0x22, 0x33, 0x00, 0x66, 0x2E, 0x47, + 0xF0, 0x4A, 0x9A, 0x8A, 0x9A, 0xC3, 0xF2, 0x93, 0xF3, 0x94, 0xCC, 0x04, 0x90, 0x61, 0xF3, 0x94, + 0xD5, 0x03, 0x90, 0x41, 0xF2, 0x93, 0xF3, 0x13, 0x4E, 0x34, 0x00, 0x03, 0xFE, 0xDA, 0xF2, 0x14, + 0x4E, 0x24, 0x00, 0x03, 0xFE, 0x92, 0xE0, 0x62, 0x40, 0x21, 0xBC, 0x1A, 0x81, 0xE2, 0x00, 0x23, + 0x00, 0xC0, 0x5A, 0x28, 0x02, 0x11, 0x10, 0x23, 0x00, 0xBE, 0x80, 0x07, 0x49, 0x00, 0x16, 0x1C, + 0xEA, 0x9D, 0x44, 0x02, 0x50, 0x58, 0x42, 0x03, 0x88, 0x73, 0x84, 0x20, 0x8C, 0x04, 0xDD, 0x40, + 0x48, 0x00, 0x00, 0x89, 0x04, 0x23, 0x00, 0x39, 0x54, 0x21, 0x00, 0x30, 0x5A, 0x28, 0x10, 0x05, + 0x3C, 0x2D, 0xF4, 0xEA, 0xD5, 0x09, 0x5A, 0x20, 0x20, 0x04, 0x48, 0x00, 0x00, 0x7C, 0x3C, 0x2D, + 0xF4, 0xEA, 0x50, 0x21, 0x02, 0x58, 0xE0, 0x4F, 0x4E, 0xF2, 0x00, 0x75, 0x22, 0x53, 0x00, 0x11, + 0x22, 0x43, 0x00, 0x12, 0x84, 0x42, 0x8A, 0x25, 0x8A, 0x04, 0x10, 0x23, 0x00, 0xBE, 0x44, 0x21, + 0x29, 0x48, 0x50, 0xAF, 0x80, 0x5C, 0xF0, 0x96, 0xFF, 0x0C, 0xFE, 0x02, 0x42, 0x40, 0x14, 0x73, + 0x3A, 0x21, 0x0C, 0x00, 0xF0, 0x99, 0x3A, 0x25, 0x0C, 0x20, 0xF1, 0x95, 0xF1, 0x9A, 0xF4, 0x9B, + 0xB0, 0x19, 0x4E, 0x17, 0x00, 0x05, 0x44, 0x12, 0x13, 0x40, 0xD5, 0x03, 0x44, 0x12, 0x13, 0x34, + 0x80, 0x4A, 0xEB, 0xB5, 0x5A, 0x08, 0x02, 0x0B, 0x80, 0x0A, 0x3C, 0x13, 0x79, 0xD4, 0x3C, 0x23, + 0x79, 0xD5, 0x49, 0x00, 0x0F, 0x3D, 0x5A, 0x00, 0x01, 0x19, 0xF0, 0x16, 0x4E, 0x07, 0x00, 0x06, + 0xB0, 0x19, 0x44, 0x12, 0x13, 0x28, 0xD5, 0x04, 0xB0, 0x19, 0x44, 0x12, 0x13, 0x1C, 0x80, 0x4A, + 0xEB, 0xB5, 0x5A, 0x08, 0x02, 0x1C, 0x80, 0x0A, 0x3C, 0x13, 0x79, 0xD4, 0x3C, 0x23, 0x79, 0xD5, + 0x49, 0x00, 0x0F, 0x26, 0x5A, 0x08, 0x01, 0x0D, 0xB4, 0x2A, 0x22, 0x03, 0x00, 0x67, 0x8A, 0x01, + 0xF0, 0x95, 0x04, 0x15, 0x00, 0x01, 0x22, 0x03, 0x00, 0x68, 0x8A, 0x01, 0xF0, 0x96, 0xB0, 0x15, + 0xDD, 0x4D, 0x5E, 0xF0, 0x03, 0xE8, 0x4E, 0xF3, 0x01, 0x15, 0x02, 0x03, 0x00, 0x67, 0xAC, 0x37, + 0x02, 0x03, 0x00, 0x68, 0xEA, 0x55, 0x80, 0x07, 0xEB, 0x7E, 0x84, 0x01, 0x83, 0x86, 0xB8, 0xBB, + 0xEB, 0x34, 0x22, 0x03, 0x00, 0x03, 0x22, 0x23, 0x00, 0x04, 0x8A, 0x20, 0x12, 0x03, 0x00, 0x7A, + 0xEA, 0xD6, 0x12, 0x23, 0x00, 0x7B, 0x8A, 0x02, 0xF0, 0x94, 0xB0, 0x13, 0xF1, 0x93, 0xDD, 0x4D, + 0xB8, 0xBE, 0xEA, 0x66, 0x54, 0x00, 0x00, 0x60, 0xC8, 0x07, 0xEA, 0x86, 0x5A, 0x08, 0x02, 0x05, + 0x84, 0x01, 0x10, 0x03, 0x00, 0xE2, 0x84, 0x20, 0x44, 0x02, 0x24, 0xA4, 0x38, 0x10, 0x1D, 0x09, + 0xEA, 0x74, 0xEA, 0x45, 0xEA, 0x76, 0x80, 0x40, 0x42, 0x23, 0x84, 0x73, 0x00, 0x11, 0x01, 0x30, + 0x80, 0x40, 0x5A, 0x18, 0x01, 0x03, 0xEA, 0x74, 0x44, 0x12, 0x24, 0xA4, 0x3C, 0x37, 0xEF, 0x74, + 0x38, 0x00, 0x9D, 0x01, 0xE0, 0x60, 0xE9, 0x03, 0x8C, 0x01, 0xEA, 0xD0, 0x04, 0x03, 0x00, 0x3E, + 0x4E, 0x07, 0x00, 0x49, 0x84, 0x00, 0xEA, 0xD0, 0x22, 0x43, 0x00, 0x11, 0x22, 0x03, 0x00, 0x03, + 0x22, 0x33, 0x00, 0x12, 0x8A, 0x04, 0xF0, 0x91, 0x22, 0x03, 0x00, 0x7B, 0x22, 0x23, 0x00, 0x04, + 0x22, 0x13, 0x00, 0x7A, 0x8A, 0x03, 0x8A, 0x43, 0x8A, 0x24, 0xF0, 0x90, 0xB0, 0x0F, 0xF2, 0x92, + 0xF1, 0x8F, 0xDD, 0x4D, 0x81, 0x40, 0x4E, 0x07, 0x00, 0x15, 0x04, 0x8F, 0x80, 0x0F, 0xB0, 0x11, + 0xDD, 0x4D, 0x42, 0x04, 0x00, 0x24, 0x40, 0x00, 0x28, 0x16, 0xF0, 0x8F, 0x04, 0x8F, 0x80, 0x10, + 0xB0, 0x11, 0xDD, 0x4D, 0x42, 0x04, 0x00, 0x24, 0x40, 0xA0, 0x29, 0x56, 0x14, 0xAF, 0x80, 0x10, + 0x3C, 0x37, 0xEF, 0x74, 0xF1, 0x0F, 0x02, 0x23, 0x00, 0x11, 0xEA, 0xE6, 0x88, 0x22, 0xF0, 0x10, + 0xAC, 0x77, 0x02, 0x13, 0x00, 0x12, 0xEB, 0x12, 0x88, 0x01, 0xEA, 0x55, 0xB0, 0x11, 0x04, 0xA3, + 0x00, 0x3E, 0xDD, 0x4D, 0x3C, 0x17, 0xEF, 0x74, 0xDD, 0x5C, 0x8B, 0x40, 0x14, 0xA3, 0x00, 0x3E, + 0xD5, 0x1F, 0x38, 0x10, 0x9D, 0x01, 0xE0, 0x61, 0xE9, 0x1B, 0xDD, 0x57, 0x42, 0x23, 0x80, 0x73, + 0x04, 0x01, 0x00, 0x46, 0x5A, 0x08, 0x01, 0x15, 0x22, 0x23, 0x00, 0x05, 0x22, 0x03, 0x00, 0x11, + 0x9B, 0x19, 0xFE, 0x8C, 0x42, 0x20, 0x10, 0x73, 0x40, 0x21, 0x0C, 0x56, 0xEB, 0x39, 0xAC, 0xB7, + 0x22, 0x23, 0x00, 0x12, 0xFE, 0x0C, 0x42, 0x01, 0x10, 0x73, 0xEB, 0x12, 0xEA, 0x55, 0x8C, 0xE1, + 0x97, 0xF8, 0x48, 0xFF, 0xFB, 0xDB, 0x84, 0xA0, 0x44, 0xA2, 0x50, 0x5C, 0xF0, 0x02, 0xD0, 0x44, + 0xB4, 0x1F, 0x9D, 0xA9, 0x00, 0x00, 0x00, 0xBF, 0x5A, 0x08, 0x04, 0x3A, 0xB4, 0x1F, 0x02, 0x00, + 0x00, 0x5C, 0xE6, 0x09, 0xE9, 0x34, 0x97, 0xF0, 0x44, 0x80, 0x01, 0x0C, 0xF0, 0x02, 0x4C, 0x70, + 0x00, 0x2F, 0x81, 0x2A, 0x42, 0x93, 0xA0, 0x73, 0x00, 0x04, 0x80, 0xBF, 0x5A, 0x08, 0x04, 0x25, + 0x02, 0x04, 0x80, 0x5C, 0xE6, 0x09, 0xE9, 0x20, 0xB4, 0x1F, 0xB4, 0x3F, 0x22, 0x24, 0x80, 0x07, + 0x22, 0x00, 0x00, 0x07, 0x22, 0x10, 0x80, 0x08, 0x22, 0x34, 0x80, 0x08, 0x49, 0xFF, 0xF7, 0xFD, + 0x3C, 0x13, 0xEC, 0x36, 0xFE, 0x4C, 0xE0, 0x20, 0xE9, 0x0F, 0xB4, 0x1F, 0xB4, 0x3F, 0x00, 0x00, + 0x00, 0xE4, 0x58, 0x00, 0x00, 0x0F, 0x10, 0x00, 0x80, 0xE4, 0x00, 0x04, 0x80, 0xE4, 0x58, 0x00, + 0x00, 0x0F, 0x10, 0x04, 0x80, 0xE4, 0x8C, 0xE1, 0x97, 0xF8, 0xD5, 0xD1, 0xB4, 0x1F, 0x97, 0x70, + 0xEB, 0xA2, 0xB6, 0x1F, 0xD5, 0xBC, 0xFC, 0xCE, 0x80, 0x07, 0xEB, 0x7E, 0xFA, 0x18, 0x80, 0x29, + 0xEA, 0x27, 0x50, 0x00, 0x80, 0x20, 0xA4, 0x42, 0xA4, 0x03, 0xAC, 0x77, 0xEA, 0x55, 0x84, 0x03, + 0xEB, 0x7F, 0x2E, 0x07, 0xF0, 0x08, 0x8C, 0x01, 0xEB, 0x57, 0x00, 0x03, 0x00, 0xFE, 0xEB, 0x5F, + 0xFE, 0x0F, 0x10, 0x03, 0x00, 0xFE, 0x84, 0x01, 0x14, 0x03, 0x00, 0x3C, 0x48, 0xFF, 0xFF, 0x15, + 0x2E, 0x07, 0xF0, 0x4A, 0xC8, 0x0B, 0xB4, 0x0A, 0x22, 0x13, 0x00, 0x68, 0xAC, 0x37, 0x04, 0x05, + 0x00, 0x01, 0x88, 0x01, 0x90, 0x01, 0x48, 0xFF, 0xFE, 0xE7, 0x22, 0x13, 0x00, 0x67, 0xB4, 0x0A, + 0x88, 0x01, 0x90, 0x01, 0xAC, 0x37, 0x04, 0x05, 0x00, 0x01, 0x48, 0xFF, 0xFE, 0xDD, 0xEA, 0x51, + 0xEA, 0x39, 0xEA, 0x62, 0x48, 0xFF, 0xFA, 0xF9, 0xA6, 0xC9, 0xA6, 0x80, 0xE2, 0x62, 0xE9, 0x0E, + 0xA6, 0x88, 0xA6, 0xC1, 0xE2, 0x62, 0xE9, 0x0A, 0xA6, 0xCB, 0xA6, 0x82, 0xE2, 0x62, 0xE9, 0x06, + 0xA6, 0x03, 0xA6, 0x4A, 0xE2, 0x01, 0xEB, 0x27, 0xDD, 0x9E, 0x84, 0x00, 0xDD, 0x9E, 0xA7, 0x08, + 0xA6, 0xC0, 0xE2, 0x64, 0x40, 0x32, 0x3C, 0x1A, 0xAE, 0xD0, 0xA7, 0x01, 0xA6, 0xC9, 0xE2, 0x83, + 0x40, 0x32, 0x3C, 0x1A, 0xAE, 0xD1, 0xA7, 0x0A, 0xA6, 0xC2, 0xA6, 0x4B, 0xA6, 0x03, 0xE2, 0x64, + 0x40, 0x32, 0x3C, 0x1A, 0xE2, 0x01, 0xEB, 0x56, 0xAE, 0xD2, 0xAE, 0x53, 0xDD, 0x9E, 0xA6, 0x41, + 0xA6, 0x00, 0xE2, 0x20, 0xE9, 0x05, 0x8C, 0x21, 0x9A, 0x08, 0x96, 0x00, 0xDD, 0x9E, 0x84, 0x00, + 0xDD, 0x9E, 0xA6, 0x43, 0xA6, 0x02, 0xE2, 0x20, 0xE9, 0x05, 0x8C, 0x21, 0x9A, 0x08, 0x96, 0x00, + 0xDD, 0x9E, 0x84, 0x00, 0xDD, 0x9E, 0xFC, 0x49, 0xB1, 0x87, 0x80, 0xE1, 0x81, 0x40, 0xF2, 0x84, + 0x84, 0x20, 0x80, 0x06, 0xFA, 0x5C, 0xB6, 0xBF, 0xF3, 0x85, 0x83, 0x84, 0xDD, 0x40, 0x00, 0x83, + 0x80, 0x03, 0xEA, 0x3E, 0x00, 0x93, 0x80, 0x02, 0xF0, 0x81, 0xF1, 0x01, 0x80, 0x08, 0xEA, 0x8B, + 0xB4, 0xBF, 0x38, 0x05, 0x01, 0x01, 0x9B, 0x45, 0x97, 0x6B, 0x4E, 0x57, 0x00, 0xAE, 0x44, 0x02, + 0x13, 0xD8, 0x04, 0xAF, 0x80, 0x04, 0x38, 0x00, 0x21, 0x01, 0x44, 0x40, 0x00, 0xFF, 0xF0, 0x82, + 0x44, 0x02, 0x13, 0x90, 0x38, 0x00, 0x25, 0x01, 0xF0, 0x83, 0x84, 0x00, 0xB6, 0x1F, 0x46, 0x00, + 0x7F, 0xFF, 0x50, 0x10, 0x0F, 0xFF, 0xF0, 0x04, 0x40, 0x25, 0x00, 0x01, 0xF0, 0x05, 0x96, 0x90, + 0xE2, 0x40, 0xE8, 0x47, 0x08, 0x45, 0x00, 0x01, 0x83, 0xDC, 0xFA, 0x1C, 0x43, 0xE2, 0x00, 0x73, + 0x00, 0x2F, 0x00, 0x25, 0x5A, 0x28, 0x01, 0xF1, 0x38, 0x23, 0x12, 0x02, 0xCA, 0xED, 0xF3, 0x02, + 0x04, 0x2F, 0x00, 0x03, 0xF0, 0x03, 0x9A, 0x9A, 0x04, 0x3F, 0x00, 0x04, 0x9A, 0xC3, 0xFE, 0xDC, + 0x42, 0x31, 0x08, 0x73, 0x00, 0x2F, 0x00, 0x20, 0x40, 0x24, 0x08, 0x01, 0x4E, 0x24, 0x00, 0x03, + 0xFE, 0x92, 0x00, 0xFF, 0x00, 0x21, 0x40, 0xF4, 0xBC, 0x01, 0x4E, 0xF4, 0x00, 0x04, 0x52, 0xF7, + 0x80, 0x00, 0x88, 0x4F, 0x52, 0xF1, 0x00, 0x02, 0x4E, 0xF7, 0x00, 0x07, 0x40, 0x27, 0x84, 0x08, + 0x40, 0x31, 0x88, 0x0E, 0xD5, 0x05, 0x8E, 0x42, 0x94, 0x91, 0x40, 0x31, 0x88, 0x0C, 0x85, 0xE1, + 0x4E, 0x37, 0x00, 0x08, 0x46, 0x00, 0x7F, 0xFF, 0xE0, 0x23, 0xDD, 0x42, 0xEB, 0x3E, 0x81, 0xE0, + 0xB4, 0x1F, 0x40, 0x30, 0xBC, 0x76, 0x88, 0x03, 0x38, 0x33, 0x12, 0x0A, 0xB6, 0x1F, 0xD5, 0xB4, + 0x84, 0x60, 0x2E, 0xA6, 0xF3, 0xC0, 0x50, 0x2E, 0x00, 0x0C, 0x80, 0xC3, 0x54, 0x91, 0x80, 0xFF, + 0xE3, 0x2A, 0xE8, 0x2D, 0xB0, 0x07, 0x38, 0x00, 0x0E, 0x02, 0xC0, 0x25, 0xB4, 0x3F, 0xFE, 0x2C, + 0xDD, 0x5C, 0xF1, 0x02, 0xA1, 0x12, 0xB5, 0x02, 0x42, 0xF0, 0x04, 0x24, 0x42, 0xF2, 0x20, 0x73, + 0x40, 0x82, 0x00, 0x00, 0x40, 0xF7, 0xA1, 0xF6, 0xF1, 0x03, 0x14, 0xF1, 0x00, 0x00, 0x04, 0xF1, + 0x00, 0x01, 0xFE, 0x0C, 0x42, 0x02, 0x3C, 0x73, 0x40, 0x00, 0x20, 0x16, 0xA8, 0x11, 0xB0, 0x07, + 0xB4, 0x3F, 0x38, 0x00, 0x0E, 0x02, 0x8C, 0xC1, 0xFE, 0x2C, 0xDD, 0x5C, 0x88, 0x80, 0xA9, 0x12, + 0x97, 0xB0, 0x80, 0x89, 0x8C, 0x61, 0x50, 0x21, 0x00, 0x2C, 0xD5, 0xD1, 0x5A, 0x68, 0x01, 0x15, + 0xFA, 0x1C, 0x43, 0xC2, 0x00, 0x73, 0x00, 0x0E, 0x00, 0x23, 0xF2, 0x1A, 0x8C, 0x01, 0x10, 0x0E, + 0x00, 0x23, 0xA6, 0x3B, 0xA6, 0x7A, 0x88, 0x02, 0xF2, 0x01, 0xEA, 0xB7, 0x00, 0x1E, 0x00, 0x1E, + 0x58, 0x10, 0x80, 0x20, 0xAE, 0x40, 0xFC, 0xC9, 0xFC, 0x40, 0x51, 0xFF, 0xFD, 0x60, 0xF0, 0x8C, + 0xF1, 0x8D, 0x96, 0x19, 0x44, 0x11, 0x29, 0x50, 0xF0, 0x85, 0xB0, 0x17, 0x40, 0x72, 0x20, 0x09, + 0x40, 0x61, 0xC0, 0x09, 0xF2, 0x8E, 0xF3, 0x8F, 0xF4, 0x90, 0xF5, 0x91, 0xEA, 0x70, 0xEA, 0x5C, + 0xEB, 0x3F, 0x84, 0x4B, 0xB0, 0x14, 0xDD, 0x40, 0x84, 0x20, 0x44, 0x20, 0x01, 0xE0, 0xB0, 0x30, + 0xDD, 0x40, 0xB0, 0x21, 0x84, 0x20, 0x44, 0x20, 0x00, 0x3C, 0xDD, 0x40, 0x96, 0x38, 0xF0, 0x89, + 0xF0, 0x05, 0xE2, 0xC0, 0xEB, 0x91, 0x84, 0x00, 0xF6, 0x86, 0xF0, 0x83, 0x80, 0xE0, 0xEB, 0x93, + 0xA6, 0x00, 0xE2, 0xE0, 0x4E, 0xF2, 0x00, 0xB7, 0x04, 0x1F, 0x80, 0xB1, 0x85, 0x40, 0x94, 0x3A, + 0x80, 0xCA, 0x41, 0xC0, 0x80, 0x00, 0xB0, 0x17, 0x00, 0x1E, 0x00, 0x05, 0x38, 0x25, 0x00, 0x00, + 0x88, 0x0A, 0x88, 0x22, 0xEB, 0x8D, 0xA6, 0x41, 0x00, 0x0E, 0x00, 0x04, 0x88, 0x01, 0xEA, 0x71, + 0x80, 0x28, 0x80, 0x09, 0xEB, 0x43, 0xC0, 0x20, 0x44, 0x02, 0x4C, 0xAC, 0x89, 0x20, 0xEA, 0x3E, + 0x42, 0x94, 0x00, 0x73, 0x00, 0x04, 0x80, 0x00, 0x54, 0x10, 0x00, 0xEF, 0x5A, 0x10, 0x0F, 0x15, + 0x5A, 0x00, 0x2F, 0x13, 0xEB, 0x57, 0x84, 0x00, 0x97, 0x40, 0xDE, 0x06, 0xB0, 0x12, 0xEB, 0x59, + 0x8C, 0xC1, 0x97, 0xB0, 0xD5, 0x09, 0xB0, 0x92, 0x38, 0x51, 0x00, 0x00, 0xD1, 0x05, 0x8C, 0x01, + 0x96, 0x80, 0xE2, 0xC2, 0xE8, 0xF2, 0x8D, 0x42, 0x5A, 0xA8, 0x10, 0xCF, 0x04, 0x1F, 0x80, 0xB1, + 0x2E, 0x86, 0xF3, 0xAE, 0x94, 0x3A, 0x88, 0x01, 0x84, 0x40, 0x45, 0xE2, 0x4B, 0xFC, 0xF0, 0x88, + 0x45, 0xC2, 0x22, 0x98, 0x4C, 0x23, 0x00, 0x6B, 0x9C, 0xD1, 0x96, 0x18, 0xF0, 0x84, 0x80, 0xA0, + 0xD6, 0x63, 0xB0, 0x12, 0xB0, 0x52, 0x38, 0x00, 0x08, 0x00, 0x38, 0x10, 0x94, 0x00, 0x38, 0xFF, + 0x00, 0x00, 0x38, 0xAF, 0x04, 0x00, 0x5A, 0xF0, 0xFF, 0x55, 0x5A, 0xA0, 0xFF, 0x53, 0xF3, 0x08, + 0x00, 0x91, 0x80, 0x04, 0xA7, 0x1D, 0x04, 0x3F, 0x80, 0xB2, 0x42, 0x44, 0xA0, 0x73, 0x38, 0x41, + 0x91, 0x11, 0x44, 0x30, 0x00, 0x64, 0x42, 0x92, 0x0C, 0x24, 0xFA, 0x7C, 0x80, 0x9C, 0x42, 0x47, + 0x8C, 0x73, 0x50, 0x42, 0x00, 0x20, 0x00, 0xF2, 0x00, 0x04, 0xA7, 0x25, 0x04, 0x3F, 0x80, 0xB2, + 0x42, 0xF2, 0x20, 0x73, 0x38, 0x41, 0xBD, 0x11, 0x40, 0x34, 0x90, 0x77, 0xF3, 0x87, 0xFA, 0x9C, + 0x80, 0x7C, 0x42, 0x35, 0x10, 0x73, 0x50, 0xA1, 0x80, 0x20, 0x00, 0xF5, 0x00, 0x04, 0x00, 0xA5, + 0x00, 0x05, 0x04, 0x3F, 0x80, 0xB2, 0x42, 0xF5, 0x20, 0x73, 0x38, 0xA1, 0xBD, 0x11, 0xF3, 0x07, + 0x40, 0x94, 0xA9, 0x37, 0xE3, 0x23, 0xE8, 0x04, 0x00, 0x4F, 0x80, 0x1C, 0xD5, 0x03, 0x54, 0x44, + 0x80, 0xFF, 0xF3, 0x03, 0xE6, 0x74, 0xE8, 0x15, 0x04, 0xAF, 0x80, 0x03, 0x85, 0x23, 0xB0, 0xE1, + 0x42, 0x35, 0x24, 0x73, 0xE2, 0x01, 0x81, 0x41, 0x40, 0xA0, 0x3C, 0x1B, 0xE2, 0x20, 0xEA, 0xD5, + 0xAE, 0x19, 0xF0, 0x03, 0x10, 0xA1, 0x80, 0x00, 0x8C, 0x01, 0x96, 0x00, 0xAF, 0x1A, 0xF0, 0x83, + 0x8C, 0xA1, 0x97, 0x68, 0xD5, 0x9E, 0xF2, 0x04, 0xD5, 0x96, 0x8C, 0xE1, 0x97, 0xF8, 0x48, 0xFF, + 0xFF, 0x48, 0xEA, 0x8C, 0x46, 0x10, 0x08, 0x95, 0xF0, 0x87, 0x87, 0x80, 0x44, 0x02, 0x22, 0x9C, + 0x50, 0x10, 0x84, 0x3F, 0x83, 0xDC, 0x9E, 0xC4, 0xFA, 0x9C, 0xF1, 0x8A, 0xF2, 0x07, 0x54, 0x1E, + 0x00, 0xFF, 0xE2, 0x22, 0xF1, 0x84, 0x4E, 0xF2, 0x00, 0xDA, 0xB0, 0x54, 0x00, 0x2F, 0x80, 0x10, + 0x38, 0x2E, 0x04, 0x08, 0xF1, 0x04, 0x9D, 0x49, 0xF1, 0x07, 0x97, 0x68, 0x4C, 0x50, 0x80, 0xCA, + 0x00, 0x20, 0x00, 0x24, 0x5A, 0x20, 0xFF, 0x1A, 0x80, 0x23, 0x42, 0x12, 0x90, 0x73, 0x00, 0x60, + 0x80, 0x28, 0x5A, 0x60, 0xFF, 0x13, 0xEA, 0x76, 0xEA, 0xBD, 0x42, 0x71, 0x04, 0x73, 0x00, 0x73, + 0x80, 0xEB, 0x5A, 0x78, 0x02, 0x0B, 0xEA, 0xBD, 0x42, 0x73, 0x04, 0x73, 0x00, 0x13, 0x80, 0xEB, + 0x5A, 0x18, 0x02, 0x04, 0x48, 0x00, 0x00, 0xAB, 0x5C, 0xFF, 0x00, 0x14, 0x4E, 0xF2, 0x00, 0xA7, + 0x80, 0xC3, 0x42, 0x62, 0x90, 0x73, 0xA0, 0x43, 0xA1, 0xF4, 0x9B, 0xCF, 0x4E, 0x74, 0x00, 0x03, + 0xFF, 0xFA, 0x44, 0x62, 0x22, 0x98, 0xFB, 0x3C, 0x42, 0x62, 0xA4, 0x73, 0xA0, 0x44, 0xA1, 0xB5, + 0x9B, 0x8E, 0x4E, 0x64, 0x00, 0x03, 0xFF, 0xB2, 0xFF, 0xB4, 0xF1, 0x0A, 0x42, 0x63, 0x9C, 0x73, + 0xE0, 0x26, 0x4E, 0xF3, 0x00, 0x8C, 0xFA, 0x28, 0xB1, 0xF0, 0x42, 0x7F, 0x04, 0x73, 0x80, 0x27, + 0x81, 0x23, 0x00, 0x7F, 0x80, 0x10, 0x42, 0x92, 0x90, 0x73, 0x10, 0x70, 0x80, 0x10, 0x50, 0x74, + 0x80, 0x04, 0xA9, 0xC9, 0xA9, 0x8A, 0x10, 0x50, 0x80, 0x11, 0xB6, 0x01, 0xB1, 0xE1, 0x84, 0xC0, + 0x8D, 0x38, 0xF1, 0x88, 0xF1, 0x03, 0x4C, 0x60, 0x80, 0x1B, 0x20, 0x80, 0x00, 0x1E, 0xA6, 0x78, + 0x4C, 0x80, 0xC0, 0x12, 0x20, 0x84, 0x80, 0x0A, 0xA6, 0x79, 0x4C, 0x80, 0xC0, 0x0D, 0xF1, 0x08, + 0x50, 0x80, 0x80, 0x10, 0xA6, 0x7A, 0x00, 0xA4, 0x00, 0x03, 0xE2, 0x2A, 0x40, 0xA0, 0xBC, 0x1A, + 0x10, 0xA4, 0x00, 0x03, 0x8C, 0xC1, 0x97, 0xB0, 0x8C, 0xE3, 0xD5, 0xE5, 0x80, 0x23, 0x42, 0x12, + 0x90, 0x73, 0x5A, 0x20, 0xFF, 0x2B, 0xEB, 0xE1, 0x5A, 0x10, 0xFF, 0x26, 0x44, 0x60, 0x01, 0x0C, + 0xEA, 0xBD, 0x42, 0x71, 0x18, 0x73, 0x50, 0x93, 0x80, 0xE0, 0xEA, 0xBD, 0x42, 0x70, 0x98, 0x73, + 0x50, 0x73, 0x80, 0xE0, 0x00, 0x84, 0x80, 0x0B, 0x00, 0xA3, 0x80, 0x0B, 0xFA, 0xC8, 0xE3, 0x48, + 0xE9, 0x08, 0xE3, 0x0A, 0xE9, 0x0A, 0x02, 0x94, 0x80, 0x02, 0xA5, 0xFA, 0xE3, 0x27, 0xE9, 0x05, + 0xB0, 0x70, 0x42, 0x1F, 0x18, 0x73, 0xD5, 0x18, 0xB0, 0xB0, 0x42, 0x2F, 0x18, 0x73, 0x10, 0x11, + 0x00, 0x12, 0xD5, 0x14, 0xFA, 0x28, 0xD5, 0x06, 0x00, 0x20, 0x80, 0x28, 0xFA, 0x28, 0x5A, 0x20, + 0xFF, 0x07, 0xB1, 0xB0, 0x42, 0x6F, 0x04, 0x73, 0x80, 0x26, 0xD5, 0x06, 0xB0, 0xB0, 0x42, 0x2F, + 0x04, 0x73, 0x80, 0x22, 0x84, 0x5F, 0x10, 0x20, 0x80, 0x12, 0xFA, 0x28, 0xB1, 0xF0, 0x42, 0x7F, + 0x04, 0x73, 0x50, 0x23, 0x80, 0x10, 0xA6, 0x52, 0x5A, 0x10, 0xFF, 0x0D, 0x44, 0x60, 0x01, 0x0C, + 0x04, 0x9F, 0x80, 0xB0, 0x42, 0x90, 0x98, 0x73, 0xB4, 0x29, 0xA8, 0x7B, 0x00, 0x14, 0x80, 0x12, + 0xAE, 0x54, 0x50, 0x1F, 0x00, 0x01, 0x55, 0xE0, 0x80, 0xFF, 0x8C, 0xA1, 0x48, 0xFF, 0xFF, 0x36, + 0x51, 0xCE, 0x00, 0x01, 0xEA, 0xF6, 0x48, 0xFF, 0xFF, 0x23, 0x51, 0xCF, 0x80, 0xC0, 0x80, 0x1C, + 0x84, 0xE0, 0x4C, 0x7F, 0x00, 0x32, 0x8C, 0xE1, 0x97, 0xF8, 0x81, 0x27, 0x4C, 0x9F, 0x00, 0x2B, + 0xFA, 0x48, 0xB0, 0x70, 0x42, 0x14, 0x88, 0x73, 0xA0, 0xC2, 0xA0, 0x8A, 0xE0, 0x43, 0xE8, 0x1E, + 0xB1, 0x9B, 0x81, 0xE0, 0x81, 0x06, 0x3A, 0x27, 0x94, 0x04, 0x3A, 0x24, 0x14, 0x24, 0x3A, 0x27, + 0x8C, 0x00, 0x81, 0x41, 0x3A, 0x24, 0x0C, 0x20, 0x80, 0xC0, 0x3A, 0x25, 0x14, 0x04, 0x3A, 0x23, + 0x14, 0x24, 0x3A, 0x25, 0x0C, 0x00, 0x3A, 0x27, 0x8C, 0x20, 0xB0, 0x9B, 0x80, 0xC2, 0xEB, 0x64, + 0xEA, 0x9F, 0x3A, 0x24, 0x0C, 0x00, 0x3A, 0x25, 0x0C, 0x20, 0x50, 0x14, 0x80, 0x01, 0xEB, 0x8D, + 0xD5, 0xD6, 0x8C, 0x18, 0xD5, 0xCF, 0xF0, 0x05, 0xB0, 0x70, 0xFE, 0x04, 0xF0, 0x83, 0xF0, 0x06, + 0xFE, 0x04, 0xF0, 0x84, 0xFA, 0x08, 0xEA, 0x27, 0xF1, 0x8B, 0xF0, 0x0B, 0x4D, 0xC0, 0x01, 0x53, + 0x00, 0x0E, 0x00, 0x11, 0xB0, 0x54, 0x38, 0x90, 0x80, 0x00, 0x00, 0x0E, 0x00, 0x10, 0x38, 0x70, + 0x80, 0x00, 0x4C, 0x93, 0x81, 0x44, 0x00, 0x0E, 0x00, 0x12, 0x5A, 0x00, 0xFF, 0x3B, 0xEA, 0x76, + 0x04, 0x6F, 0x80, 0xB0, 0x42, 0x60, 0x04, 0x73, 0xB5, 0x1C, 0x50, 0x63, 0x00, 0x9C, 0x80, 0x06, + 0x80, 0x28, 0x49, 0xFF, 0xFC, 0xCB, 0xC0, 0x2D, 0x04, 0xAE, 0x00, 0x01, 0x80, 0x06, 0x80, 0x2A, + 0x49, 0xFF, 0xFC, 0xC4, 0xC0, 0x26, 0x04, 0x05, 0x00, 0x05, 0x04, 0x14, 0x00, 0x05, 0x44, 0x30, + 0x00, 0x7D, 0x88, 0x20, 0xB8, 0x03, 0xEA, 0xE5, 0xFE, 0xC4, 0x40, 0xF1, 0x89, 0xF6, 0xE0, 0x2F, + 0xE8, 0x07, 0x44, 0x30, 0x00, 0x4B, 0xFE, 0x1C, 0xEA, 0xA6, 0xE0, 0x01, 0xE9, 0x14, 0x00, 0x05, + 0x00, 0x23, 0x00, 0x14, 0x00, 0x23, 0x00, 0x2E, 0x00, 0x14, 0x88, 0x20, 0xEB, 0x67, 0xEB, 0x23, + 0xFE, 0x14, 0x40, 0x00, 0x3C, 0x16, 0xE0, 0x01, 0xF0, 0x03, 0xF1, 0x04, 0xEA, 0xD5, 0xD5, 0x04, + 0xF0, 0x03, 0xD5, 0x02, 0xF0, 0x04, 0xE3, 0x27, 0x81, 0x47, 0xEB, 0xC9, 0x40, 0xA4, 0xBC, 0x1B, + 0xE2, 0xE9, 0xFF, 0x84, 0x40, 0x74, 0xBC, 0x1B, 0xFA, 0x1C, 0xEA, 0x41, 0xEA, 0x27, 0x50, 0x10, + 0x80, 0x20, 0x00, 0x20, 0x80, 0x08, 0x5A, 0x28, 0xFF, 0x0C, 0xFA, 0x1C, 0xEA, 0x41, 0xEA, 0x27, + 0x00, 0x00, 0x80, 0x28, 0x5A, 0x00, 0xFF, 0x0F, 0x85, 0x20, 0x81, 0x09, 0xD5, 0x18, 0xEA, 0x49, + 0xEA, 0x45, 0xEB, 0xBA, 0x00, 0x00, 0x01, 0x2F, 0xC8, 0xF1, 0xA6, 0x0C, 0xA6, 0x4D, 0xEA, 0x64, + 0xC8, 0xED, 0xFA, 0x1C, 0xEA, 0x41, 0xEA, 0x27, 0xEB, 0xE1, 0x85, 0x20, 0x5A, 0x10, 0xFF, 0x07, + 0xEA, 0x9D, 0xEA, 0x45, 0xEA, 0xB7, 0x02, 0x90, 0x00, 0x72, 0x85, 0x01, 0xFA, 0x1C, 0xEA, 0x41, + 0x42, 0x15, 0x00, 0x73, 0x50, 0x10, 0x80, 0x20, 0x00, 0x20, 0x80, 0x08, 0x5A, 0x28, 0xFF, 0x0C, + 0xFA, 0x1C, 0xEA, 0x41, 0x42, 0x15, 0x00, 0x73, 0x00, 0x00, 0x80, 0x28, 0x84, 0x20, 0x5A, 0x08, + 0xFF, 0x1E, 0xD5, 0x0B, 0xEA, 0x49, 0xEA, 0x45, 0xEB, 0xBA, 0x00, 0x00, 0x01, 0x2F, 0xC8, 0xF1, + 0xA6, 0x0C, 0xA6, 0x4D, 0xEA, 0x64, 0xC8, 0xED, 0xFA, 0x1C, 0xEA, 0x41, 0x42, 0x15, 0x00, 0x73, + 0xEB, 0xE1, 0x5A, 0x10, 0xFF, 0x08, 0xEA, 0x9D, 0xEA, 0x45, 0xEA, 0xB7, 0x02, 0x10, 0x00, 0x72, + 0xD5, 0x02, 0x84, 0x20, 0xEB, 0x02, 0x40, 0x80, 0x00, 0x13, 0xFA, 0x5C, 0xEB, 0x3C, 0x42, 0x05, + 0x08, 0x73, 0x00, 0x00, 0x00, 0x28, 0x5A, 0x08, 0xFF, 0x0A, 0x44, 0x32, 0x22, 0x98, 0x42, 0x33, + 0x88, 0x73, 0x00, 0x21, 0x80, 0x28, 0x5A, 0x20, 0xFF, 0x12, 0x8B, 0x21, 0x8D, 0x24, 0xE7, 0x29, + 0xE9, 0x0D, 0x5A, 0x88, 0x02, 0x0C, 0xB8, 0x02, 0xE0, 0x06, 0xE9, 0x4A, 0x00, 0x0E, 0x00, 0x13, + 0x5C, 0xF0, 0x00, 0x5B, 0xE8, 0x45, 0x48, 0x00, 0x00, 0x82, 0xFA, 0x3C, 0xEB, 0x22, 0x42, 0x23, + 0x84, 0x73, 0x00, 0x11, 0x00, 0x28, 0x5A, 0x10, 0xFF, 0x05, 0x5A, 0x08, 0xFF, 0x32, 0xD5, 0x03, + 0x5A, 0x00, 0xFF, 0x2F, 0x00, 0x0E, 0x00, 0x12, 0x5A, 0x00, 0xFF, 0x2B, 0xEA, 0x76, 0xEA, 0xA9, + 0xFE, 0x0C, 0x98, 0x50, 0x00, 0x10, 0x80, 0xEA, 0x5A, 0x18, 0x01, 0x23, 0x88, 0x02, 0x04, 0x00, + 0x00, 0x44, 0x92, 0x04, 0x96, 0x0F, 0x5A, 0x08, 0x02, 0x1C, 0x2E, 0x27, 0xF0, 0x4A, 0xB4, 0x3C, + 0xB8, 0x01, 0xCA, 0x06, 0x00, 0x50, 0x80, 0x20, 0x00, 0x00, 0x00, 0x20, 0xD5, 0x05, 0x00, 0x50, + 0x80, 0x21, 0x00, 0x00, 0x00, 0x21, 0xD8, 0x0C, 0xFA, 0x1C, 0xEA, 0x41, 0xEB, 0x22, 0xEA, 0x27, + 0x42, 0x25, 0x00, 0x73, 0x00, 0x50, 0x80, 0x2B, 0x00, 0x01, 0x00, 0x2B, 0xD0, 0x09, 0xB8, 0x02, + 0xE0, 0x06, 0xE9, 0x06, 0x00, 0x0E, 0x00, 0x13, 0xF1, 0x09, 0xE2, 0x20, 0xE8, 0x3F, 0x00, 0x0E, + 0x00, 0x10, 0xB0, 0x54, 0xB0, 0x94, 0xEB, 0xCE, 0x00, 0x1E, 0x00, 0x11, 0x38, 0x61, 0x04, 0x00, + 0xEB, 0x22, 0xE2, 0x06, 0x80, 0xE6, 0x40, 0x70, 0x3C, 0x1B, 0xE2, 0xC0, 0xEB, 0x91, 0xFA, 0x1C, + 0x42, 0x23, 0x00, 0x73, 0x50, 0x21, 0x00, 0x20, 0x00, 0x11, 0x00, 0x08, 0x5A, 0x18, 0xFF, 0x04, + 0x48, 0x00, 0x01, 0x40, 0x44, 0x32, 0x22, 0x98, 0x42, 0x33, 0x80, 0x73, 0x50, 0x31, 0x80, 0x20, + 0x00, 0xA1, 0x80, 0x08, 0x80, 0xA7, 0x5A, 0xA8, 0xFF, 0x04, 0x48, 0x00, 0x00, 0x9E, 0x44, 0x42, + 0x50, 0x30, 0xDD, 0x57, 0x81, 0x24, 0x42, 0x90, 0x80, 0x73, 0x80, 0x29, 0x42, 0x05, 0x00, 0x24, + 0x00, 0x84, 0x80, 0xEB, 0x50, 0x94, 0x80, 0xE0, 0x88, 0x80, 0x5A, 0x80, 0x01, 0x5E, 0x00, 0x02, + 0x00, 0xEB, 0x5A, 0x08, 0x01, 0x04, 0x48, 0x00, 0x00, 0x82, 0x51, 0xCE, 0x00, 0x18, 0x48, 0xFF, + 0xFE, 0xAE, 0x84, 0xE0, 0x44, 0xA2, 0x4C, 0xAC, 0x44, 0x82, 0x4B, 0xFC, 0xEB, 0x93, 0xA6, 0x00, + 0xE2, 0xE0, 0x4E, 0xF2, 0x01, 0x14, 0xEB, 0x93, 0x87, 0x80, 0x95, 0x3A, 0x81, 0x3C, 0x99, 0x44, + 0xB0, 0x17, 0xA6, 0x6D, 0x38, 0x6E, 0x00, 0x00, 0x88, 0x1C, 0x88, 0xC1, 0xA6, 0x81, 0xA6, 0x2C, + 0x97, 0xB0, 0x88, 0x40, 0x96, 0x90, 0x80, 0x22, 0x80, 0x06, 0xF4, 0x85, 0xF5, 0x84, 0xF2, 0x83, + 0xEB, 0x43, 0xF2, 0x03, 0xF5, 0x04, 0xF4, 0x05, 0xC0, 0x1A, 0x88, 0xCA, 0xEA, 0x3E, 0x42, 0x61, + 0x00, 0x73, 0xA6, 0x30, 0x54, 0x10, 0x00, 0xEF, 0x5A, 0x10, 0x0F, 0x12, 0x5A, 0x00, 0x2F, 0x10, + 0x96, 0x1F, 0x38, 0x04, 0x00, 0x00, 0x5A, 0x00, 0xFF, 0x0B, 0xB0, 0x54, 0x50, 0x34, 0x80, 0x01, + 0xEB, 0x83, 0xB0, 0x12, 0x38, 0x10, 0x24, 0x08, 0x54, 0x91, 0x80, 0xFF, 0x51, 0xCE, 0x00, 0x02, + 0x5B, 0xC8, 0x10, 0xD0, 0xEB, 0x93, 0x3C, 0x57, 0xEC, 0x83, 0x98, 0x44, 0xB7, 0x5F, 0x04, 0x0F, + 0x80, 0xB2, 0x8C, 0x22, 0xB0, 0x92, 0x80, 0x69, 0x44, 0x42, 0x22, 0x9C, 0x8C, 0xE1, 0x49, 0xFF, + 0xFB, 0x84, 0x97, 0xF8, 0xD5, 0xB4, 0x00, 0xA2, 0x00, 0xEB, 0x50, 0x02, 0x00, 0xE0, 0x5A, 0xA8, + 0x01, 0x22, 0x02, 0x94, 0x80, 0x02, 0xA4, 0x02, 0xE2, 0x09, 0xE9, 0x20, 0xE3, 0x20, 0x50, 0x10, + 0x80, 0xE8, 0xE8, 0x04, 0x84, 0x02, 0xAE, 0x0C, 0xD5, 0x0F, 0x22, 0x92, 0x00, 0x78, 0x22, 0xF0, + 0x80, 0x04, 0x50, 0x42, 0x00, 0xE8, 0xE1, 0x2F, 0x85, 0x22, 0xE8, 0x04, 0x10, 0x92, 0x00, 0x04, + 0xD5, 0x10, 0x10, 0x90, 0x80, 0x04, 0x84, 0x1F, 0x80, 0xE6, 0x10, 0x01, 0x00, 0x08, 0x80, 0xC5, + 0xD5, 0x0B, 0x84, 0x02, 0x10, 0x00, 0x80, 0xEC, 0xD5, 0xF7, 0x84, 0x02, 0x10, 0x02, 0x00, 0xEC, + 0x84, 0x1F, 0x10, 0x01, 0x80, 0x08, 0xFA, 0x3C, 0xEB, 0x3C, 0x42, 0x03, 0x84, 0x73, 0x50, 0xA0, + 0x00, 0x20, 0x84, 0x40, 0x10, 0x25, 0x00, 0x09, 0x00, 0x25, 0x00, 0x04, 0xF2, 0x86, 0x00, 0x25, + 0x00, 0x05, 0xF2, 0x87, 0xEB, 0x22, 0x42, 0x23, 0x04, 0x73, 0x50, 0x91, 0x00, 0x20, 0x80, 0x22, + 0x00, 0x24, 0x80, 0x04, 0x04, 0xF0, 0x80, 0x06, 0xF2, 0x88, 0x00, 0x24, 0x80, 0x05, 0xA0, 0xCC, + 0xF2, 0x8A, 0x50, 0x20, 0x00, 0x10, 0xF2, 0x85, 0x04, 0x81, 0x00, 0x02, 0xA0, 0x84, 0x42, 0x37, + 0x8C, 0x24, 0x42, 0x34, 0x08, 0x73, 0xF2, 0x05, 0x40, 0x54, 0x3C, 0x00, 0x50, 0x40, 0x80, 0x10, + 0x40, 0x31, 0x94, 0x76, 0xA8, 0xCC, 0xA0, 0xD1, 0xA0, 0xA1, 0xA9, 0x4E, 0x42, 0x27, 0x88, 0x24, + 0x42, 0x24, 0x0C, 0x73, 0x40, 0x21, 0x14, 0x56, 0x00, 0x34, 0x80, 0x07, 0xA8, 0xA1, 0x00, 0x25, + 0x00, 0x07, 0x02, 0x40, 0x00, 0x10, 0x88, 0x43, 0x10, 0x24, 0x80, 0x07, 0x00, 0x34, 0x80, 0x06, + 0x00, 0x25, 0x00, 0x06, 0x40, 0x82, 0x00, 0x11, 0x88, 0x43, 0x10, 0x24, 0x80, 0x06, 0x02, 0x20, + 0x80, 0x10, 0x8C, 0x24, 0x97, 0x53, 0xE1, 0x05, 0x40, 0x22, 0x3C, 0x1A, 0x12, 0x20, 0x80, 0x0E, + 0x8C, 0x04, 0x80, 0x41, 0x49, 0xFF, 0xFA, 0xCD, 0x00, 0x05, 0x00, 0x08, 0x5A, 0x00, 0xFF, 0x05, + 0x10, 0x04, 0x80, 0x08, 0xD5, 0x05, 0x00, 0x04, 0x80, 0x08, 0x10, 0x05, 0x00, 0x08, 0xF2, 0x07, + 0xEA, 0x3E, 0xF1, 0x06, 0xF3, 0x0A, 0x42, 0x11, 0x00, 0x73, 0xF2, 0x08, 0x42, 0x21, 0x80, 0x73, + 0x80, 0x02, 0x04, 0x2F, 0x80, 0xB2, 0x38, 0xF1, 0x05, 0x11, 0x38, 0x01, 0x01, 0x11, 0xE0, 0x0F, + 0xE8, 0x10, 0xFA, 0x1C, 0xEA, 0x41, 0xEA, 0x27, 0x50, 0x10, 0x80, 0x20, 0x44, 0x32, 0x22, 0x98, + 0x42, 0x33, 0x00, 0x73, 0xA6, 0x8C, 0x50, 0x01, 0x80, 0x20, 0xA6, 0x4D, 0xAE, 0x84, 0xAE, 0x45, + 0xB0, 0x94, 0x2E, 0x37, 0xEE, 0x20, 0x80, 0x02, 0x9A, 0x42, 0x96, 0x48, 0xE2, 0x23, 0x4E, 0xF2, + 0xFE, 0xEE, 0x08, 0x10, 0x00, 0x01, 0x4C, 0x70, 0xFF, 0xF9, 0x10, 0x60, 0x7F, 0xFF, 0xD5, 0xF5, + 0x80, 0x07, 0x80, 0xE6, 0x80, 0xC0, 0x48, 0xFF, 0xFF, 0x68, 0x51, 0xFF, 0x82, 0xA0, 0xFC, 0xC0, + 0xFC, 0x45, 0x3C, 0x6D, 0xF4, 0xD6, 0x3D, 0xCD, 0xF4, 0xD2, 0x3C, 0xAD, 0xF4, 0xD3, 0x3C, 0x8D, + 0xF4, 0xD4, 0x3C, 0x9D, 0xF4, 0xD5, 0x2E, 0x77, 0xD3, 0x5C, 0xEA, 0x26, 0x5A, 0x08, 0x01, 0x04, + 0x2E, 0x77, 0xD3, 0x5D, 0xEB, 0x2F, 0x96, 0x06, 0xC0, 0x03, 0x95, 0xF9, 0x97, 0xF8, 0x44, 0x10, + 0x00, 0x64, 0xEA, 0x4E, 0xFF, 0xB4, 0xF0, 0x83, 0x42, 0x04, 0xA4, 0x24, 0xF0, 0x84, 0x2E, 0x07, + 0xDE, 0xE5, 0x2E, 0x90, 0x1B, 0xB8, 0xF0, 0x85, 0xEA, 0x8C, 0xE7, 0x25, 0xF0, 0x86, 0x50, 0x04, + 0x80, 0x02, 0xF0, 0x87, 0x42, 0x0E, 0x70, 0x24, 0xFE, 0x3C, 0x40, 0x20, 0x04, 0x56, 0xF2, 0x88, + 0x42, 0x24, 0x20, 0x24, 0x40, 0x21, 0x04, 0x56, 0xFF, 0xF4, 0xF2, 0x82, 0x40, 0x20, 0x08, 0x0A, + 0x40, 0x20, 0x3C, 0x1B, 0x40, 0x03, 0x88, 0x0A, 0x40, 0x03, 0xBC, 0x1B, 0x42, 0x35, 0x28, 0x24, + 0x83, 0xC2, 0x84, 0x40, 0x81, 0x00, 0x40, 0xA1, 0x85, 0x56, 0xEA, 0x50, 0xB6, 0x5F, 0x83, 0x81, + 0x00, 0x1F, 0x80, 0x00, 0xF2, 0x03, 0xE2, 0x22, 0x4E, 0xF2, 0x00, 0xA7, 0x02, 0x50, 0x00, 0x5C, + 0x4E, 0x52, 0x00, 0x9D, 0x22, 0x20, 0x00, 0x03, 0x22, 0x10, 0x00, 0x04, 0xE6, 0xA5, 0xAC, 0x87, + 0x12, 0x10, 0x00, 0x08, 0x84, 0x84, 0xE8, 0x03, 0x9F, 0x29, 0x97, 0x21, 0xF4, 0x81, 0x00, 0x40, + 0x01, 0x03, 0xCC, 0x1D, 0x22, 0xF0, 0x00, 0x66, 0x22, 0x40, 0x00, 0x65, 0x8A, 0x2F, 0x8A, 0x44, + 0xFE, 0x4C, 0x42, 0x11, 0x08, 0x73, 0x81, 0xE1, 0xF1, 0x04, 0xE0, 0x2F, 0xE8, 0x10, 0x00, 0x20, + 0x00, 0xD2, 0x00, 0x10, 0x00, 0xD5, 0x4C, 0x20, 0xC0, 0x08, 0x00, 0x20, 0x00, 0xD3, 0x00, 0x10, + 0x00, 0xD6, 0x4C, 0x20, 0x80, 0x05, 0x84, 0x21, 0x10, 0x10, 0x01, 0x03, 0xB4, 0xDF, 0x44, 0x40, + 0x00, 0x43, 0x84, 0x20, 0xFF, 0x34, 0x80, 0x41, 0xF4, 0x89, 0xF4, 0x01, 0xE2, 0x44, 0xE8, 0x31, + 0xFA, 0x84, 0xFF, 0x14, 0x40, 0xF0, 0x10, 0x00, 0x8C, 0x94, 0x22, 0x67, 0x80, 0x03, 0x88, 0x80, + 0x80, 0xE6, 0x22, 0x62, 0x00, 0x03, 0x22, 0xF7, 0x80, 0x04, 0x9B, 0xBE, 0x22, 0x42, 0x00, 0x04, + 0xF7, 0x05, 0x40, 0x47, 0x90, 0x01, 0xE2, 0x47, 0xE8, 0x13, 0x00, 0xF0, 0x00, 0xC0, 0x5A, 0xF8, + 0x01, 0x10, 0xF7, 0x09, 0x40, 0xF3, 0x88, 0x00, 0x50, 0xF7, 0x80, 0x22, 0x40, 0xF7, 0x88, 0x08, + 0xEA, 0xBD, 0x40, 0xF3, 0xBC, 0x00, 0x12, 0x67, 0x80, 0x04, 0x12, 0x47, 0x80, 0x05, 0xFF, 0x24, + 0x42, 0x43, 0x18, 0x73, 0xE0, 0x24, 0x8C, 0x41, 0x40, 0x12, 0x3C, 0x1B, 0x96, 0x90, 0xD5, 0xCE, + 0xE6, 0xA3, 0xE8, 0x14, 0x5A, 0x58, 0x02, 0x0D, 0xE7, 0x25, 0xE8, 0x05, 0xF2, 0x07, 0xF4, 0x06, + 0xE0, 0x44, 0xE8, 0x06, 0xE0, 0x2A, 0xE8, 0x04, 0x14, 0xA0, 0x00, 0x2D, 0xD5, 0x04, 0xF1, 0x08, + 0x14, 0x10, 0x00, 0x2D, 0x04, 0x10, 0x00, 0x2D, 0xD5, 0x1F, 0x00, 0x20, 0x01, 0x03, 0xCA, 0x05, + 0xF1, 0x02, 0x14, 0x10, 0x00, 0x2D, 0xD5, 0x18, 0x98, 0x99, 0xE0, 0x43, 0xE9, 0x08, 0x40, 0xFF, + 0x08, 0x07, 0x40, 0x2F, 0x3C, 0x1B, 0x40, 0x21, 0x70, 0x56, 0xD5, 0x02, 0x80, 0x4A, 0x94, 0x4A, + 0xE0, 0x23, 0x14, 0x20, 0x00, 0x2D, 0xE9, 0x07, 0xE1, 0x01, 0x40, 0x14, 0x3C, 0x1B, 0x40, 0x10, + 0xF0, 0x36, 0xD5, 0x02, 0x80, 0x2A, 0x14, 0x10, 0x00, 0x2C, 0xB4, 0x3F, 0xEB, 0xA2, 0x8C, 0x21, + 0xB6, 0x3F, 0x48, 0xFF, 0xFF, 0x57, 0xFC, 0xC5, 0xFC, 0x43, 0x84, 0xC0, 0x80, 0xE0, 0xF1, 0x81, + 0x81, 0x42, 0x81, 0x03, 0x45, 0xC2, 0x4C, 0x28, 0x2E, 0x07, 0xDE, 0xD4, 0xE2, 0xC0, 0xE8, 0x25, + 0x84, 0x0C, 0x81, 0x3C, 0x42, 0x93, 0x00, 0x73, 0x00, 0x04, 0x80, 0x0A, 0xC0, 0x1B, 0xB4, 0x49, + 0xF1, 0x01, 0x9A, 0x3A, 0xF0, 0x82, 0x04, 0x04, 0x80, 0x01, 0x40, 0x25, 0x08, 0x01, 0x9A, 0xC8, + 0x40, 0x04, 0x00, 0x01, 0xF0, 0x85, 0xB0, 0x02, 0xF2, 0x84, 0xF3, 0x83, 0xDD, 0x4D, 0x02, 0x24, + 0x80, 0x04, 0xE0, 0x02, 0xE8, 0x07, 0xB0, 0x04, 0xDD, 0x4D, 0x02, 0x14, 0x80, 0x04, 0xE0, 0x20, + 0xE9, 0x06, 0x8C, 0xC1, 0x97, 0xB0, 0xD5, 0xD9, 0x84, 0x00, 0xFC, 0xC3, 0x84, 0x01, 0xFC, 0xC3, + 0xFC, 0x40, 0x51, 0xFF, 0xFD, 0xE0, 0xF0, 0x84, 0xA6, 0x00, 0xF1, 0x88, 0xF3, 0x8B, 0x4E, 0x02, + 0x01, 0xCA, 0x4E, 0x22, 0x01, 0xC8, 0xE6, 0x0C, 0x80, 0x20, 0xE9, 0x02, 0x84, 0x2B, 0x96, 0x08, + 0xE6, 0x4C, 0xF0, 0x87, 0x80, 0x02, 0xE9, 0x02, 0x84, 0x0B, 0x96, 0x00, 0xF0, 0x83, 0x3C, 0x3D, + 0xF7, 0xB8, 0x84, 0x00, 0xB0, 0x8F, 0x84, 0x20, 0x88, 0x40, 0x38, 0x31, 0x06, 0x0A, 0x8C, 0x21, + 0x5A, 0x18, 0x0B, 0xFD, 0xEA, 0xF6, 0x5A, 0x09, 0xE4, 0xF7, 0x3C, 0x03, 0xF6, 0xD4, 0x96, 0x06, + 0xC0, 0x07, 0xEB, 0x2F, 0x96, 0x06, 0xC8, 0x07, 0xF0, 0x81, 0x84, 0x01, 0xD5, 0x07, 0x84, 0x01, + 0xF0, 0x81, 0xD5, 0x04, 0x84, 0x01, 0xF0, 0x81, 0x84, 0x00, 0xF0, 0x86, 0xB0, 0x0F, 0xF0, 0x85, + 0xF0, 0x08, 0xF1, 0x08, 0x9D, 0xC4, 0xF0, 0x03, 0x84, 0xC0, 0x8E, 0x01, 0x96, 0x00, 0x94, 0x05, + 0x50, 0x00, 0x00, 0x24, 0x88, 0x01, 0xF0, 0x8A, 0xF0, 0x04, 0x8C, 0x10, 0xF0, 0x8C, 0x46, 0x07, + 0xFF, 0xFF, 0xDD, 0x42, 0xF0, 0x8D, 0x84, 0x00, 0x04, 0xAF, 0x80, 0x0C, 0xF0, 0x82, 0x84, 0x00, + 0xF0, 0x8E, 0xEA, 0x2F, 0xF0, 0x89, 0x00, 0x05, 0x00, 0x18, 0x5A, 0x00, 0xFF, 0x04, 0x48, 0x00, + 0x01, 0x1C, 0xB4, 0xA7, 0xA0, 0xBA, 0xA1, 0x39, 0xA0, 0xFB, 0x50, 0x85, 0x00, 0x84, 0xB2, 0x20, + 0x88, 0x45, 0x88, 0x64, 0xB4, 0x0A, 0x49, 0xFF, 0xF0, 0x90, 0x81, 0x20, 0xA0, 0x7E, 0xB2, 0x01, + 0x80, 0x41, 0xE0, 0x01, 0x40, 0x20, 0x3C, 0x1A, 0xE0, 0x20, 0xEB, 0x56, 0x94, 0x95, 0x41, 0xC1, + 0x07, 0x96, 0xB4, 0x0A, 0xB2, 0x20, 0xB4, 0x47, 0xA0, 0xF9, 0x49, 0xFF, 0xFF, 0x57, 0x5A, 0x08, + 0x01, 0x04, 0x48, 0x00, 0x00, 0xFA, 0xF0, 0x01, 0x5A, 0x08, 0x01, 0x2B, 0xF0, 0x04, 0xA6, 0x00, + 0x5A, 0x08, 0x01, 0x27, 0x00, 0x13, 0xFF, 0xFC, 0xDD, 0x57, 0xEA, 0xA9, 0x42, 0x20, 0x80, 0x73, + 0x00, 0x11, 0x00, 0xEB, 0x5A, 0x18, 0x02, 0x1D, 0x2E, 0x10, 0x1B, 0xB8, 0x5A, 0x18, 0x01, 0x19, + 0x00, 0x11, 0x01, 0x01, 0x50, 0x01, 0x00, 0xF8, 0x00, 0x25, 0x7F, 0xF4, 0x00, 0x00, 0x00, 0x0A, + 0xE2, 0x22, 0xE9, 0x0E, 0x00, 0x25, 0x7F, 0xF5, 0xE2, 0x41, 0xE9, 0x0A, 0x00, 0x15, 0x7F, 0xF6, + 0xE2, 0x01, 0xE9, 0x06, 0x00, 0x15, 0x7F, 0xF7, 0xE2, 0x20, 0x4E, 0xF2, 0x01, 0x24, 0x3C, 0x6D, + 0xF7, 0xB8, 0xF0, 0x06, 0xE0, 0xC9, 0x40, 0x64, 0xBC, 0x1A, 0x81, 0x06, 0x3C, 0x6D, 0xF7, 0xB6, + 0x95, 0xB5, 0xC0, 0x0A, 0x40, 0xFE, 0x18, 0x07, 0xE9, 0x07, 0x3C, 0x6D, 0xF7, 0xB7, 0x95, 0xB5, + 0xE0, 0xDC, 0x40, 0x6E, 0x3C, 0x1A, 0xA0, 0x3C, 0xE0, 0x08, 0xE9, 0x5A, 0xF0, 0x0B, 0xC0, 0x33, + 0xEB, 0x1B, 0x05, 0xCF, 0x80, 0x0D, 0x00, 0x04, 0x80, 0xEB, 0x5A, 0x08, 0x01, 0x0E, 0xB4, 0x0A, + 0x04, 0x15, 0x00, 0x01, 0x22, 0x24, 0x80, 0x19, 0x22, 0x34, 0x80, 0x1A, 0x49, 0xFF, 0xF0, 0x25, + 0xE0, 0x1C, 0x41, 0xC0, 0x3C, 0x1B, 0x50, 0x94, 0x81, 0x0C, 0x44, 0x02, 0x5B, 0xB4, 0x4C, 0x90, + 0x7F, 0xEC, 0x40, 0xFE, 0x20, 0x07, 0x4E, 0xF2, 0x00, 0x90, 0x3C, 0x1D, 0xF4, 0xD2, 0x40, 0x00, + 0x84, 0x0A, 0x90, 0x22, 0x88, 0x01, 0xFE, 0x04, 0xEA, 0x92, 0xDD, 0x5C, 0xE0, 0x08, 0x4E, 0xF2, + 0x00, 0x84, 0x3C, 0x0D, 0xF4, 0xD3, 0xFE, 0x04, 0x40, 0xF0, 0x05, 0xF6, 0x40, 0xFE, 0x3C, 0x07, + 0x48, 0x00, 0x00, 0x7A, 0x00, 0x13, 0xFF, 0xFC, 0xDD, 0x57, 0xEA, 0xA9, 0x42, 0x20, 0x80, 0x73, + 0x02, 0x01, 0x00, 0x72, 0xE6, 0x03, 0xE8, 0x70, 0x3C, 0x1D, 0xF4, 0xD2, 0xEB, 0x23, 0x40, 0x00, + 0x84, 0x0A, 0x90, 0x22, 0x88, 0x01, 0xFE, 0x04, 0x40, 0x00, 0x3C, 0x16, 0xE0, 0x08, 0xE8, 0x64, + 0x00, 0x01, 0x01, 0x01, 0x50, 0x21, 0x00, 0xF8, 0xEB, 0xB1, 0x00, 0x21, 0x00, 0x0A, 0xEA, 0xB1, + 0xF1, 0x09, 0x38, 0xF0, 0x81, 0x11, 0x3C, 0x14, 0x0A, 0x9C, 0xE0, 0x2F, 0xD5, 0x54, 0xA0, 0x7D, + 0xE0, 0x01, 0xE8, 0x5A, 0xB4, 0x6A, 0xB4, 0x47, 0x04, 0x55, 0x00, 0x01, 0x9A, 0x9A, 0xA0, 0x7B, + 0xA0, 0xF9, 0xA0, 0x3A, 0x9A, 0xEB, 0x42, 0x50, 0x84, 0x24, 0x42, 0x50, 0x00, 0x73, 0x42, 0x91, + 0x8C, 0x24, 0x83, 0x85, 0x42, 0x91, 0x08, 0x73, 0x49, 0xFF, 0xEF, 0xD0, 0x4E, 0x04, 0x00, 0x09, + 0xFE, 0x02, 0xD5, 0x06, 0x40, 0xFE, 0x24, 0x07, 0x90, 0x01, 0xE8, 0x06, 0x91, 0x22, 0xEB, 0x54, + 0xE0, 0x20, 0xE9, 0xF9, 0xD5, 0x04, 0x41, 0xCE, 0x08, 0x0A, 0xD5, 0xFA, 0x4E, 0x92, 0x00, 0x20, + 0x4F, 0xC2, 0x00, 0x20, 0xFE, 0x04, 0xF0, 0x8E, 0xB0, 0x0E, 0x49, 0xFF, 0xEF, 0xBB, 0xF0, 0x89, + 0xF0, 0x0E, 0x40, 0x90, 0x25, 0x36, 0xB0, 0x0E, 0x14, 0x9F, 0x80, 0x0E, 0x49, 0xFF, 0xEF, 0xB2, + 0xF1, 0x09, 0x88, 0x01, 0x96, 0x40, 0xF0, 0x0E, 0x40, 0x50, 0x70, 0xB6, 0xE6, 0x3F, 0xE9, 0x05, + 0x9E, 0x09, 0x90, 0xA1, 0x96, 0x40, 0xD5, 0xFB, 0xF5, 0x8E, 0xD5, 0x04, 0x80, 0x29, 0xD5, 0x02, + 0x80, 0x3C, 0x84, 0x01, 0xEB, 0x80, 0x90, 0x07, 0xF1, 0x0E, 0x94, 0x06, 0xE0, 0x01, 0xE8, 0x0C, + 0xA0, 0x3D, 0xE0, 0x08, 0xE9, 0x09, 0x3C, 0x0D, 0xF7, 0xB8, 0x42, 0x64, 0x18, 0x24, 0x90, 0xC5, + 0xE0, 0x06, 0xEB, 0x91, 0xD5, 0x03, 0x3C, 0x6D, 0xF7, 0xB8, 0xF1, 0x02, 0xF0, 0x05, 0x50, 0xA5, + 0x00, 0x2C, 0x38, 0x60, 0x06, 0x0A, 0x80, 0x01, 0x8C, 0x01, 0xF0, 0x82, 0x00, 0x0F, 0x80, 0x08, + 0xF1, 0x07, 0xE2, 0x01, 0x4E, 0xF3, 0xFE, 0xCD, 0xF0, 0x05, 0x50, 0x73, 0x80, 0x20, 0xEA, 0xF6, + 0xF0, 0x85, 0xF0, 0x0A, 0x4C, 0x70, 0x7E, 0xC1, 0xF0, 0x03, 0xF1, 0x07, 0xF2, 0x07, 0xE2, 0x01, + 0xF1, 0x03, 0xB1, 0x8F, 0x80, 0x06, 0x40, 0x11, 0x3C, 0x1B, 0x49, 0xFF, 0xEF, 0x1E, 0xFA, 0xFC, + 0x3C, 0x4D, 0xF7, 0xB8, 0x84, 0x20, 0x44, 0x02, 0x5C, 0x54, 0x84, 0xAB, 0xEB, 0x1B, 0x44, 0xA0, + 0x01, 0x0C, 0x87, 0x81, 0x87, 0xDF, 0x38, 0x20, 0x06, 0x02, 0x80, 0x62, 0x42, 0x30, 0x94, 0x73, + 0x38, 0x33, 0x0E, 0x02, 0x4C, 0x32, 0x40, 0x05, 0x39, 0xE0, 0x06, 0x0A, 0xD5, 0x15, 0x4E, 0x25, + 0x00, 0x14, 0x04, 0x8F, 0x80, 0x08, 0x94, 0xCD, 0x04, 0xFF, 0x80, 0x04, 0x38, 0x34, 0x0C, 0x00, + 0x81, 0x09, 0x42, 0x81, 0xA8, 0x73, 0x42, 0xF1, 0x1C, 0x73, 0x10, 0x37, 0x80, 0x28, 0x11, 0xC4, + 0x00, 0xEC, 0x10, 0x24, 0x01, 0x00, 0x8C, 0x21, 0xF3, 0x03, 0x96, 0x88, 0xE2, 0x43, 0xE9, 0xDC, + 0xD5, 0x09, 0x40, 0x04, 0xF0, 0x16, 0xA0, 0x7D, 0x94, 0x05, 0xE0, 0x01, 0x4E, 0xF2, 0xFE, 0xD9, + 0xD5, 0xA5, 0x51, 0xFF, 0x82, 0x20, 0xFC, 0xC0, 0xFC, 0x40, 0x84, 0x81, 0x40, 0x42, 0x04, 0x0C, + 0xE4, 0x02, 0x40, 0x20, 0x04, 0x0C, 0x95, 0xA1, 0x9D, 0xE5, 0x50, 0x92, 0x7F, 0xFB, 0xE9, 0x23, + 0x84, 0x60, 0x90, 0x01, 0x8C, 0x61, 0x5A, 0x08, 0x01, 0xFE, 0x40, 0x21, 0x0C, 0x0E, 0x40, 0x01, + 0x84, 0x0C, 0x85, 0x00, 0xE0, 0x49, 0xE9, 0x03, 0xE0, 0xE2, 0xE8, 0x16, 0x80, 0x68, 0xE0, 0x46, + 0xE8, 0x06, 0xFE, 0x94, 0x40, 0x21, 0x04, 0x0E, 0x8C, 0x61, 0xD5, 0xFA, 0x81, 0x03, 0x81, 0x44, + 0x84, 0xA0, 0xD3, 0x04, 0x91, 0x41, 0x8C, 0xA1, 0xD5, 0xFD, 0xE4, 0xAA, 0x88, 0x0A, 0x90, 0x41, + 0xE9, 0xEA, 0xD5, 0x02, 0x84, 0x00, 0xFC, 0xC0, 0xFC, 0x4E, 0xF0, 0x85, 0x44, 0x01, 0x29, 0x60, + 0xB1, 0x92, 0xF2, 0x83, 0x83, 0x83, 0xEA, 0x4D, 0x3A, 0x23, 0x14, 0x24, 0xA4, 0x00, 0xAC, 0x30, + 0x4F, 0xC3, 0x00, 0x12, 0x3C, 0x23, 0x79, 0xD4, 0x3C, 0x00, 0x0A, 0x96, 0xE2, 0x02, 0x40, 0x01, + 0x3C, 0x1A, 0x96, 0xC3, 0x3C, 0x00, 0x0A, 0x97, 0xE2, 0x40, 0x40, 0x20, 0x3C, 0x1A, 0x96, 0x13, + 0xEB, 0x92, 0xD5, 0x0F, 0x3C, 0x30, 0x0A, 0x98, 0xEA, 0x6F, 0x3C, 0x20, 0x0A, 0x99, 0xE2, 0x60, + 0x40, 0x30, 0x3C, 0x1A, 0xE2, 0x02, 0x40, 0x20, 0x3C, 0x1B, 0x96, 0x13, 0x96, 0xDB, 0xEA, 0xE1, + 0x8E, 0x41, 0x96, 0x92, 0x8A, 0x03, 0xEA, 0xA6, 0x96, 0x03, 0xF0, 0x84, 0x84, 0x00, 0xF0, 0x81, + 0x50, 0x60, 0x80, 0x21, 0xEA, 0xBB, 0x8E, 0x01, 0xF0, 0x87, 0xF5, 0x01, 0xF1, 0x03, 0x4C, 0x50, + 0x81, 0x4D, 0xA6, 0x34, 0x4E, 0x02, 0x01, 0x42, 0x50, 0x03, 0x7F, 0xF3, 0xB4, 0x00, 0x4E, 0x07, + 0x01, 0x3D, 0x3C, 0x03, 0xF6, 0xD6, 0x96, 0x06, 0xC0, 0x08, 0xA7, 0x70, 0xE6, 0xA2, 0x4E, 0xF3, + 0x01, 0x35, 0xF0, 0x07, 0x4C, 0x50, 0x01, 0x32, 0x4F, 0xC3, 0x00, 0x0D, 0x00, 0x03, 0x7F, 0xFF, + 0x84, 0x21, 0xEA, 0x64, 0x4E, 0x03, 0x01, 0x2A, 0x00, 0x93, 0x7F, 0xFF, 0xA7, 0xF0, 0x84, 0x02, + 0xD5, 0x42, 0x84, 0x01, 0xA6, 0x70, 0xD5, 0xF6, 0xB0, 0x12, 0xF5, 0x8B, 0x38, 0x30, 0x08, 0x00, + 0xF2, 0x89, 0x40, 0x01, 0xA4, 0x00, 0xEA, 0x71, 0xB0, 0x12, 0x88, 0x02, 0xF3, 0x8A, 0x00, 0xA0, + 0x00, 0x01, 0x80, 0x08, 0x40, 0x45, 0x1C, 0x00, 0x97, 0x20, 0x80, 0x24, 0xF4, 0x88, 0xEB, 0x43, + 0xF4, 0x08, 0xF2, 0x09, 0xF3, 0x0A, 0xF5, 0x0B, 0xC8, 0x34, 0x8C, 0x42, 0x5A, 0x28, 0x12, 0xE6, + 0xB0, 0xD7, 0x84, 0x40, 0xB0, 0x4F, 0x84, 0x00, 0x38, 0x41, 0x81, 0x11, 0x4F, 0xC3, 0x00, 0x43, + 0x38, 0xA0, 0x8A, 0x02, 0x88, 0x8A, 0x38, 0x40, 0x8A, 0x0A, 0x8C, 0x01, 0x5A, 0x08, 0x03, 0xF6, + 0x8C, 0x41, 0x8C, 0x66, 0x5A, 0x28, 0x03, 0xF1, 0xF0, 0x03, 0x5A, 0x08, 0x01, 0x49, 0xA0, 0x09, + 0xB4, 0x41, 0xE0, 0x02, 0xE9, 0x35, 0xA0, 0x8A, 0xE0, 0x02, 0xE9, 0x39, 0xF0, 0x02, 0x5A, 0x00, + 0x01, 0x3F, 0x84, 0x01, 0xF0, 0x82, 0x84, 0x20, 0x84, 0x4C, 0xB0, 0x0F, 0xDD, 0x40, 0xFA, 0x42, + 0xB0, 0x17, 0x84, 0x20, 0xDD, 0x40, 0x84, 0x40, 0xEA, 0x3E, 0x80, 0xA2, 0xF0, 0x86, 0xD5, 0xB5, + 0xF1, 0x06, 0x40, 0x04, 0x00, 0x10, 0x97, 0x22, 0xEB, 0xF1, 0x81, 0x00, 0xF0, 0x05, 0x38, 0x10, + 0x21, 0x11, 0x4E, 0x15, 0x00, 0x04, 0x88, 0xA1, 0xD5, 0x02, 0x84, 0x20, 0xEA, 0xCB, 0x8C, 0x61, + 0x97, 0x00, 0x96, 0xD8, 0x84, 0x03, 0x42, 0x41, 0x80, 0x73, 0xB0, 0x17, 0x38, 0x10, 0x11, 0x09, + 0xD5, 0xB5, 0x38, 0xA0, 0x82, 0x02, 0x88, 0x8A, 0x38, 0x40, 0x82, 0x0A, 0xD5, 0xBF, 0x4F, 0xC3, + 0x00, 0x05, 0x50, 0x04, 0xFF, 0xFF, 0xD5, 0x06, 0x8E, 0xE1, 0xD5, 0x07, 0x4F, 0xC3, 0x00, 0x05, + 0xEA, 0x7C, 0xEA, 0x82, 0xD5, 0xC4, 0x8C, 0xE1, 0x97, 0xF8, 0xD5, 0xC1, 0x50, 0x23, 0x7F, 0xF3, + 0xDD, 0x4C, 0xB5, 0x42, 0x3C, 0x27, 0xEC, 0x80, 0xFE, 0x2C, 0x42, 0xF5, 0x08, 0x24, 0xE0, 0x0F, + 0x4E, 0xF3, 0x00, 0x9C, 0xE0, 0xAA, 0xE8, 0x08, 0x40, 0x00, 0x28, 0x16, 0x40, 0x80, 0x08, 0x01, + 0x52, 0xA0, 0x00, 0x64, 0xD5, 0x03, 0x85, 0x40, 0x85, 0x01, 0xB4, 0x01, 0xA0, 0x89, 0xE0, 0x40, + 0xE8, 0x02, 0xA8, 0x09, 0xB0, 0x8F, 0xA0, 0xD2, 0xA0, 0x51, 0xE0, 0x23, 0xE8, 0x02, 0xA8, 0xD1, + 0xA1, 0x11, 0x88, 0x03, 0xEA, 0x92, 0x3C, 0x37, 0xEC, 0x82, 0xFE, 0x0C, 0x94, 0x61, 0x42, 0x50, + 0x8C, 0x24, 0xE0, 0xA0, 0xE9, 0x19, 0x3C, 0x57, 0xEC, 0x81, 0x42, 0xF0, 0x94, 0x24, 0xE0, 0x0F, + 0xE9, 0x15, 0x40, 0x10, 0x04, 0x36, 0x9B, 0x4D, 0x84, 0x3E, 0xFF, 0x0C, 0x40, 0x00, 0x10, 0x16, + 0x88, 0x60, 0x42, 0x11, 0xA8, 0x24, 0x42, 0xF4, 0x14, 0x24, 0xE0, 0x2F, 0x40, 0xA2, 0xBC, 0x1B, + 0x40, 0x81, 0xBC, 0x1B, 0xD5, 0x03, 0x85, 0x41, 0x85, 0x00, 0x84, 0x60, 0xB1, 0x0D, 0xB0, 0x0F, + 0x38, 0x00, 0x0E, 0x02, 0x4E, 0x06, 0x00, 0x06, 0xB0, 0x4F, 0x84, 0x01, 0x38, 0x00, 0x8E, 0x0A, + 0x38, 0x01, 0x0E, 0x02, 0x84, 0x28, 0xF4, 0x88, 0xF2, 0x86, 0xF3, 0x82, 0x49, 0xFF, 0xFE, 0x9E, + 0xF3, 0x02, 0xF4, 0x08, 0xF2, 0x06, 0x38, 0x02, 0x0D, 0x09, 0x8C, 0x61, 0x5A, 0x38, 0x03, 0xE9, + 0xA4, 0x21, 0x22, 0x12, 0x00, 0x02, 0x22, 0x22, 0x00, 0x00, 0x94, 0x01, 0x8A, 0x01, 0x8A, 0x02, + 0x96, 0x03, 0xC0, 0x07, 0x8A, 0x22, 0xF2, 0x04, 0x94, 0x01, 0xFE, 0x54, 0xEB, 0x88, 0x96, 0x03, + 0x40, 0x34, 0x28, 0x00, 0x4F, 0xC3, 0x00, 0x1B, 0x44, 0x12, 0x13, 0xD8, 0x38, 0x10, 0xA5, 0x11, + 0x88, 0x01, 0x50, 0x13, 0x7F, 0xEB, 0xB4, 0x41, 0x42, 0x25, 0x08, 0x24, 0x42, 0x20, 0x20, 0x73, + 0x40, 0xA1, 0x0D, 0x56, 0x4E, 0xA5, 0x00, 0x08, 0x3C, 0x33, 0x79, 0xD4, 0xE0, 0x6A, 0x40, 0xA1, + 0xBC, 0x1B, 0xD5, 0x02, 0x81, 0x5C, 0xB7, 0x41, 0xD5, 0x18, 0x44, 0x12, 0x13, 0x90, 0x50, 0x23, + 0x7F, 0xEF, 0x38, 0x10, 0x9D, 0x11, 0x88, 0x01, 0xB4, 0x22, 0x42, 0x15, 0x04, 0x24, 0x42, 0x10, + 0x20, 0x73, 0x40, 0xA0, 0x8D, 0x56, 0x4E, 0xA5, 0x00, 0x07, 0xEA, 0x6F, 0xE0, 0x0A, 0x40, 0xA0, + 0x3C, 0x1B, 0xD5, 0x02, 0x85, 0x40, 0xB7, 0x42, 0xF0, 0x01, 0x50, 0x63, 0x00, 0x2C, 0x8C, 0x01, + 0x96, 0x00, 0xF0, 0x81, 0x48, 0xFF, 0xFE, 0xB3, 0xFC, 0xCE, 0xFC, 0x21, 0x44, 0x62, 0x22, 0x9C, + 0x44, 0x72, 0x49, 0xA4, 0x80, 0x26, 0x00, 0x23, 0x7F, 0xFC, 0x22, 0x43, 0x80, 0x06, 0x84, 0x60, + 0xF0, 0x81, 0x49, 0xFF, 0xFE, 0x6B, 0xF0, 0x01, 0x80, 0x26, 0x00, 0x23, 0x7F, 0xFC, 0x84, 0x61, + 0x22, 0x43, 0x80, 0x06, 0x49, 0xFF, 0xFE, 0x62, 0xFC, 0xA1, 0xFC, 0x00, 0xB4, 0x40, 0x80, 0xA2, + 0x4E, 0x24, 0x00, 0x03, 0xFF, 0x52, 0x84, 0xC0, 0x50, 0x43, 0x00, 0x0F, 0x40, 0x12, 0x90, 0x0E, + 0xC1, 0x03, 0x8C, 0xC1, 0xD5, 0xFA, 0xA0, 0x41, 0x80, 0x61, 0x4E, 0x14, 0x00, 0x03, 0xFE, 0xCA, + 0x40, 0x31, 0x90, 0x0E, 0xCB, 0xF7, 0x40, 0x21, 0x18, 0x0E, 0x40, 0x10, 0x98, 0x0E, 0xB6, 0x40, + 0xA8, 0x41, 0x42, 0x00, 0x84, 0x24, 0x42, 0x01, 0x08, 0x73, 0xEA, 0xBE, 0x40, 0x00, 0x18, 0x0C, + 0xFC, 0x80, 0xFC, 0x41, 0x84, 0xE0, 0x81, 0x20, 0x44, 0xA0, 0x01, 0x0C, 0xEB, 0xA1, 0xE2, 0xE0, + 0xE8, 0x33, 0x80, 0xC9, 0x42, 0x63, 0xA8, 0x73, 0xDD, 0x5A, 0xC0, 0x2B, 0x22, 0x13, 0x00, 0x03, + 0x22, 0x03, 0x00, 0x67, 0x22, 0x23, 0x00, 0x04, 0x8A, 0x01, 0xAC, 0x75, 0xAC, 0x77, 0x22, 0x13, + 0x00, 0x68, 0xB6, 0x1F, 0xEB, 0xF7, 0x8A, 0x22, 0xAC, 0xB6, 0x12, 0x23, 0x00, 0x08, 0xF1, 0x81, + 0x5A, 0x08, 0x01, 0x11, 0xA4, 0x33, 0x12, 0x03, 0x00, 0x67, 0xA4, 0x34, 0x12, 0x03, 0x00, 0x68, + 0x00, 0x03, 0x00, 0xD5, 0x10, 0x03, 0x00, 0xD2, 0x00, 0x03, 0x00, 0xD6, 0x10, 0x03, 0x00, 0xD3, + 0xD5, 0x08, 0x5A, 0x08, 0x02, 0x07, 0x80, 0x1F, 0xDD, 0x4D, 0x5E, 0xF0, 0x00, 0x64, 0xE9, 0xEB, + 0x8C, 0xE1, 0x97, 0xF8, 0xD5, 0xCC, 0xFC, 0xC1, 0xB4, 0x40, 0xA0, 0xC1, 0xE0, 0x43, 0xE8, 0x07, + 0xB6, 0x60, 0xA8, 0x81, 0xB4, 0x01, 0xA0, 0x89, 0xA8, 0x09, 0xB6, 0x41, 0xDD, 0x9E, 0xFC, 0x43, + 0x51, 0xCF, 0x80, 0x38, 0x94, 0xE2, 0x50, 0x7E, 0x7F, 0xD0, 0xA8, 0x39, 0x50, 0x01, 0x80, 0x0A, + 0x54, 0x00, 0x07, 0xF8, 0xEA, 0x33, 0x81, 0x3F, 0xEA, 0x33, 0x50, 0x2E, 0x7F, 0xD4, 0x81, 0x5F, + 0xEA, 0x33, 0x81, 0x1F, 0xB6, 0x27, 0xEA, 0x33, 0xB4, 0x22, 0x80, 0x08, 0x80, 0x43, 0x80, 0xC4, + 0xA8, 0xF9, 0xDD, 0x55, 0xA0, 0xF9, 0xB4, 0x27, 0x80, 0x43, 0x80, 0x1F, 0xDD, 0x55, 0x84, 0x20, + 0x80, 0xFF, 0x80, 0x41, 0x80, 0x01, 0x96, 0xC8, 0xE2, 0x66, 0xE8, 0x09, 0x38, 0x34, 0x06, 0x02, + 0x88, 0x03, 0x38, 0x33, 0x86, 0x02, 0x8C, 0x21, 0x88, 0x43, 0xD5, 0xF6, 0x40, 0x00, 0x18, 0x16, + 0x40, 0x31, 0x18, 0x76, 0x84, 0x20, 0x96, 0x88, 0xE2, 0x46, 0xE8, 0x0D, 0x38, 0x24, 0x06, 0x02, + 0x8A, 0x40, 0x38, 0x24, 0x86, 0x0A, 0x38, 0x23, 0x86, 0x02, 0x8A, 0x43, 0x38, 0x25, 0x06, 0x0A, + 0x8C, 0x21, 0xD5, 0xF2, 0x84, 0x40, 0x8E, 0xC1, 0xE0, 0x46, 0xE8, 0x27, 0x84, 0x60, 0x9B, 0x32, + 0xE0, 0x64, 0xE8, 0x20, 0x95, 0x5A, 0x40, 0x04, 0x94, 0x00, 0x40, 0x14, 0x14, 0x00, 0x14, 0x4E, + 0x7F, 0xF2, 0x14, 0x2E, 0x7F, 0xF3, 0x14, 0x3E, 0x7F, 0xF4, 0x14, 0x5E, 0x7F, 0xF5, 0x49, 0xFF, + 0xFF, 0x9D, 0x04, 0x5E, 0x7F, 0xF5, 0x40, 0x05, 0x14, 0x00, 0x98, 0x7D, 0x49, 0xFF, 0xFF, 0x96, + 0x04, 0x3E, 0x7F, 0xF4, 0x04, 0x2E, 0x7F, 0xF3, 0x8C, 0x61, 0x96, 0xD8, 0x04, 0x4E, 0x7F, 0xF2, + 0xD5, 0xE0, 0x8C, 0x41, 0x96, 0x90, 0xD5, 0xD9, 0x90, 0xC1, 0x38, 0x04, 0x1A, 0x02, 0x38, 0x13, + 0x9A, 0x02, 0xEB, 0x86, 0xFC, 0xC0, 0xFC, 0x46, 0xFA, 0x44, 0x01, 0xC0, 0x80, 0x16, 0x81, 0x00, + 0x84, 0x20, 0xB0, 0x02, 0x50, 0xAF, 0x80, 0x1C, 0xDD, 0x40, 0x80, 0x0A, 0x84, 0x20, 0xFA, 0x44, + 0xDD, 0x40, 0x85, 0x20, 0xEB, 0xA1, 0xE3, 0x20, 0xE8, 0x60, 0xDD, 0x57, 0x80, 0xE8, 0x42, 0x74, + 0x80, 0x73, 0x00, 0x03, 0x80, 0xBF, 0x5A, 0x08, 0x02, 0x56, 0x84, 0xC4, 0xFA, 0x24, 0x80, 0x07, + 0x42, 0x03, 0x04, 0x73, 0xB0, 0x82, 0x22, 0x10, 0x00, 0x03, 0x22, 0x00, 0x00, 0x04, 0x38, 0x11, + 0x1A, 0x0A, 0x38, 0x05, 0x1A, 0x0A, 0xC6, 0x04, 0x8E, 0xC1, 0x97, 0xB0, 0xD5, 0xF0, 0xDD, 0x54, + 0xEA, 0x98, 0xC8, 0x06, 0x5B, 0xC0, 0x01, 0x08, 0x5B, 0xC8, 0x02, 0x38, 0xD5, 0x14, 0xDD, 0x41, + 0xC0, 0x12, 0xD5, 0xF9, 0x02, 0x03, 0x80, 0x5D, 0xE6, 0x02, 0xE9, 0x2F, 0xF1, 0x02, 0xF0, 0x03, + 0x88, 0x01, 0x90, 0x01, 0xAC, 0x3D, 0xB4, 0x2A, 0x04, 0x05, 0x00, 0x01, 0x88, 0x01, 0x90, 0x01, + 0xAC, 0x3E, 0xD5, 0x23, 0x02, 0x23, 0x80, 0x5D, 0xE4, 0x45, 0xE9, 0x0C, 0xB0, 0x02, 0x80, 0x2A, + 0xFD, 0x14, 0x84, 0x85, 0x49, 0xFF, 0xFF, 0x3D, 0xB6, 0x1F, 0xAC, 0x3D, 0xF1, 0x81, 0x80, 0x01, + 0xD5, 0x12, 0x84, 0x00, 0x80, 0x20, 0xE2, 0xC2, 0xE8, 0x0B, 0xB0, 0xC2, 0x38, 0x31, 0x9A, 0x02, + 0x88, 0x23, 0x38, 0x35, 0x1A, 0x02, 0x8C, 0xC1, 0x88, 0x03, 0x97, 0xB0, 0xD5, 0xF5, 0xEB, 0xB8, + 0xAC, 0x7D, 0xEA, 0xA6, 0xAC, 0x3E, 0x87, 0x82, 0xA4, 0x3D, 0xAC, 0x3F, 0xA4, 0x3E, 0x12, 0x03, + 0x80, 0x08, 0xEA, 0x7C, 0xEA, 0x82, 0xD5, 0x9F, 0xFC, 0xC6, 0xFC, 0x40, 0xB4, 0xE0, 0xA1, 0x42, + 0xA1, 0x09, 0xB4, 0xC1, 0x04, 0x90, 0x00, 0x01, 0xA0, 0x0A, 0x42, 0x33, 0x90, 0x24, 0x42, 0x12, + 0x90, 0x24, 0x42, 0x10, 0x24, 0x75, 0x42, 0x33, 0x24, 0x75, 0xFE, 0x3C, 0x42, 0x03, 0x14, 0x75, + 0xCB, 0x04, 0xC9, 0x09, 0xEA, 0xD8, 0xFC, 0xC0, 0xEB, 0x12, 0xEA, 0xE6, 0xA8, 0x11, 0xB6, 0x22, + 0x84, 0x02, 0xFC, 0xC0, 0x80, 0x03, 0xFC, 0xC0, 0xFC, 0x44, 0x81, 0x42, 0xB1, 0x83, 0x3C, 0x83, + 0x79, 0xD4, 0x80, 0xE3, 0x3D, 0xC3, 0x79, 0xD5, 0x44, 0x21, 0x29, 0x74, 0x3A, 0x21, 0x0C, 0x00, + 0x3A, 0x23, 0x0C, 0x20, 0x4E, 0x17, 0x00, 0x0A, 0xE0, 0x28, 0xE8, 0x07, 0x4E, 0xA7, 0x00, 0x06, + 0xE1, 0x5C, 0xE8, 0x03, 0x84, 0x00, 0xFC, 0xC4, 0x5A, 0x08, 0x01, 0x12, 0x22, 0xF2, 0x00, 0x08, + 0x22, 0x32, 0x80, 0x08, 0x22, 0x92, 0x00, 0x07, 0x22, 0x22, 0x80, 0x07, 0x8A, 0x6F, 0x40, 0x24, + 0x88, 0x01, 0xF2, 0x86, 0xF3, 0x85, 0x42, 0x21, 0x3C, 0x24, 0xD5, 0x0B, 0xA0, 0xF9, 0xB4, 0xA7, + 0x22, 0x22, 0x00, 0x06, 0xFE, 0xDA, 0xF3, 0x85, 0xF5, 0x86, 0x22, 0x92, 0x00, 0x05, 0xFE, 0xAC, + 0x42, 0x21, 0xA4, 0x73, 0xF2, 0x87, 0x81, 0x24, 0xF0, 0x81, 0x4E, 0x16, 0x00, 0x06, 0xB0, 0x05, + 0x44, 0x12, 0x13, 0x40, 0xD5, 0x07, 0xE0, 0x28, 0x84, 0x00, 0xE9, 0x06, 0xB0, 0x05, 0x44, 0x12, + 0x13, 0x34, 0x80, 0x46, 0xEB, 0xB5, 0xF1, 0x03, 0x4E, 0x15, 0x00, 0x0A, 0xE1, 0x01, 0xE9, 0x07, + 0xA0, 0xB1, 0x4E, 0x25, 0x00, 0x05, 0x40, 0xFE, 0x08, 0x07, 0xE8, 0x2F, 0x4E, 0xA6, 0x00, 0x06, + 0xB0, 0x05, 0x44, 0x12, 0x13, 0x28, 0xD5, 0x06, 0xE1, 0x5C, 0xE9, 0x06, 0xB0, 0x05, 0x44, 0x12, + 0x13, 0x1C, 0x80, 0x46, 0xEB, 0xB5, 0x5A, 0x08, 0x02, 0xB7, 0xF1, 0x03, 0x4E, 0x15, 0x00, 0x06, + 0xE1, 0x01, 0x40, 0x80, 0xBC, 0x1A, 0xD5, 0x02, 0x85, 0x00, 0xA0, 0x31, 0xB7, 0x07, 0x4E, 0x05, + 0x00, 0x06, 0xE0, 0x1C, 0x40, 0x0E, 0x3C, 0x1A, 0xD5, 0x02, 0x84, 0x00, 0xF1, 0x01, 0xA8, 0x39, + 0x5A, 0x18, 0x01, 0x0A, 0x22, 0x14, 0x80, 0x07, 0x22, 0xF4, 0x80, 0x08, 0x8B, 0x01, 0x8A, 0x0F, + 0xB7, 0x07, 0xA8, 0x39, 0x84, 0x01, 0xFC, 0xC4, 0x5A, 0x08, 0x02, 0x96, 0xD5, 0xE2, 0xFC, 0x41, + 0x00, 0x50, 0x00, 0xBF, 0x00, 0x9F, 0x80, 0x28, 0x00, 0x2F, 0x80, 0x2C, 0x5A, 0x50, 0x03, 0x04, + 0x84, 0x00, 0xFC, 0xC1, 0x80, 0xE1, 0x22, 0x52, 0x00, 0x07, 0x22, 0x11, 0x80, 0x07, 0x02, 0x60, + 0x00, 0x7F, 0x8A, 0x25, 0xB6, 0x3F, 0x97, 0x9F, 0x22, 0x11, 0x80, 0x08, 0x22, 0x32, 0x00, 0x08, + 0x52, 0x63, 0x00, 0x01, 0x8A, 0x23, 0x88, 0xC9, 0xF1, 0x81, 0x97, 0xB0, 0x5A, 0x28, 0x01, 0x0F, + 0x80, 0x1F, 0xDD, 0x4D, 0x81, 0x40, 0x80, 0x07, 0xDD, 0x4D, 0x4E, 0xA7, 0x00, 0x05, 0x40, 0x60, + 0x28, 0xD6, 0x97, 0xB0, 0xE6, 0xC2, 0xE8, 0x03, 0xD5, 0xDC, 0xC6, 0x05, 0xE3, 0x26, 0x40, 0x64, + 0xBC, 0x1B, 0xD5, 0x02, 0x84, 0xC1, 0x84, 0x60, 0x84, 0x01, 0xE2, 0xC0, 0xE9, 0x06, 0x98, 0x58, + 0x8C, 0x01, 0x96, 0xC8, 0x96, 0x00, 0xD5, 0xFA, 0xB4, 0xBF, 0xF4, 0x01, 0xA0, 0x39, 0xB4, 0x27, + 0x42, 0x02, 0x18, 0x75, 0x42, 0x12, 0x98, 0x75, 0xEB, 0x12, 0xEA, 0xE6, 0x88, 0x04, 0x88, 0x25, + 0xA8, 0x39, 0xB6, 0x27, 0x84, 0x01, 0xFC, 0xC1, 0x88, 0x41, 0xA1, 0x01, 0x40, 0x31, 0x04, 0x0A, + 0x80, 0xA3, 0x42, 0x50, 0x90, 0x73, 0x40, 0x42, 0x88, 0x96, 0xB4, 0xA0, 0xA9, 0x01, 0x42, 0x30, + 0x94, 0x73, 0x40, 0x31, 0x88, 0x76, 0xB6, 0x60, 0xDD, 0x9E, 0xFC, 0x44, 0xB1, 0x84, 0x2E, 0x97, + 0xD3, 0xA0, 0x3A, 0x23, 0x14, 0x20, 0xF2, 0x11, 0x84, 0x60, 0x10, 0x31, 0x01, 0x0A, 0x00, 0x31, + 0x01, 0x00, 0xC3, 0x18, 0x85, 0x40, 0x3C, 0x33, 0x79, 0xD5, 0x50, 0xF1, 0xFE, 0xAF, 0x22, 0x31, + 0x00, 0x12, 0xE0, 0x6F, 0xE9, 0x10, 0xB4, 0x60, 0x4E, 0x34, 0x00, 0x03, 0xFE, 0xDA, 0x44, 0x40, + 0x00, 0x64, 0xA1, 0x41, 0xFE, 0xE4, 0x44, 0x4F, 0xFF, 0x53, 0xFF, 0x2C, 0x40, 0xA1, 0x90, 0x07, + 0xD5, 0x02, 0x81, 0x43, 0xF3, 0x10, 0xA6, 0xD8, 0x4E, 0x32, 0x01, 0x01, 0x05, 0xC0, 0x00, 0x00, + 0xA1, 0xC1, 0x4F, 0xC5, 0x00, 0x04, 0xA0, 0xF1, 0xD5, 0x02, 0xF3, 0x04, 0x4E, 0x75, 0x00, 0x04, + 0xA1, 0xB3, 0xD5, 0x02, 0xA1, 0xB2, 0xC6, 0x02, 0xCB, 0x03, 0x84, 0x83, 0xD5, 0x0B, 0x80, 0xA3, + 0x4E, 0x34, 0x00, 0x03, 0xFF, 0x5A, 0x80, 0x86, 0x4E, 0x64, 0x00, 0x03, 0xFF, 0x32, 0xD4, 0x04, + 0x84, 0x82, 0xF5, 0x10, 0xAF, 0x28, 0x81, 0x00, 0xF0, 0x10, 0xA6, 0x00, 0x5A, 0x08, 0x03, 0x49, + 0x80, 0x1C, 0x4F, 0xC4, 0x00, 0x04, 0x52, 0x0E, 0x00, 0x00, 0xE0, 0x60, 0x84, 0x00, 0xE8, 0x08, + 0x84, 0x01, 0x4F, 0xC4, 0x00, 0x03, 0x84, 0x1F, 0x43, 0xC1, 0x80, 0x75, 0x80, 0x1C, 0xB6, 0x08, + 0x80, 0x07, 0x4E, 0x74, 0x00, 0x03, 0xFE, 0x3A, 0xE0, 0xC0, 0xE9, 0x04, 0x84, 0x00, 0x48, 0x00, + 0x00, 0xC4, 0x4E, 0xA2, 0x00, 0x25, 0x9A, 0x46, 0xE0, 0x29, 0xE8, 0x15, 0x40, 0x90, 0x24, 0x01, + 0x4E, 0x94, 0x00, 0x03, 0x85, 0x20, 0x8A, 0xC9, 0x84, 0x21, 0x4E, 0x74, 0x00, 0x03, 0x84, 0x3F, + 0x42, 0x74, 0x84, 0x75, 0x02, 0x11, 0x00, 0x61, 0x14, 0x74, 0x00, 0x01, 0x9B, 0x8E, 0x12, 0x61, + 0x00, 0x61, 0xD5, 0x09, 0x84, 0x01, 0x4E, 0x74, 0x00, 0x03, 0x84, 0x1F, 0x42, 0x73, 0x00, 0x75, + 0x14, 0x74, 0x00, 0x01, 0x84, 0x01, 0x10, 0x01, 0x01, 0x0A, 0xFC, 0xC4, 0x84, 0x01, 0x4E, 0x74, + 0x00, 0x03, 0x84, 0x1F, 0x42, 0x73, 0x00, 0x75, 0x14, 0x74, 0x00, 0x01, 0xFC, 0xC4, 0x5A, 0x08, + 0x02, 0x42, 0x42, 0x53, 0x70, 0x24, 0xFF, 0x2A, 0x42, 0x01, 0x9C, 0x24, 0xF4, 0x81, 0xFF, 0x02, + 0x84, 0x20, 0xF4, 0x82, 0x51, 0xE0, 0x80, 0x0F, 0x81, 0xE5, 0x4E, 0x54, 0x00, 0x04, 0x04, 0xFF, + 0x80, 0x01, 0x40, 0x47, 0xF8, 0x0E, 0xC4, 0x04, 0x8C, 0x21, 0x96, 0x48, 0xD5, 0xF4, 0x81, 0xE0, + 0x4E, 0x04, 0x00, 0x04, 0x04, 0xFF, 0x80, 0x02, 0x40, 0x47, 0xF8, 0x0E, 0xCC, 0xF6, 0x40, 0x00, + 0x04, 0x0E, 0x40, 0x52, 0x84, 0x0E, 0xFE, 0x04, 0x42, 0x02, 0x94, 0x73, 0xF2, 0x83, 0xF3, 0x82, + 0xF1, 0x81, 0xEA, 0xBE, 0xF1, 0x01, 0xF3, 0x02, 0x40, 0x10, 0x04, 0x0C, 0xF2, 0x03, 0xC1, 0x12, + 0x42, 0x03, 0x9C, 0x24, 0x42, 0x0E, 0x70, 0x73, 0xFF, 0x9C, 0xF2, 0x82, 0xF1, 0x81, 0xEA, 0xBE, + 0xF1, 0x01, 0xFE, 0x34, 0x40, 0x60, 0x04, 0xD6, 0xF2, 0x02, 0x4E, 0x64, 0x00, 0x05, 0xFF, 0xB2, + 0xD5, 0x02, 0x80, 0xC1, 0x80, 0x08, 0xF2, 0x81, 0xDD, 0x4D, 0xE0, 0xC0, 0xF2, 0x01, 0xE9, 0x04, + 0x84, 0x00, 0xB6, 0x08, 0xD5, 0x2A, 0x04, 0x54, 0x00, 0x01, 0x4E, 0xA2, 0x00, 0x1C, 0x84, 0x21, + 0x10, 0x11, 0x01, 0x0A, 0x4E, 0x74, 0x00, 0x17, 0x42, 0x13, 0x98, 0x24, 0xEA, 0x53, 0x9A, 0x69, + 0x4E, 0x14, 0x00, 0x03, 0xFE, 0x4A, 0xE0, 0x29, 0xE8, 0x0D, 0x40, 0x12, 0xA4, 0x00, 0xFE, 0x44, + 0x40, 0x90, 0x9D, 0x36, 0x02, 0x11, 0x00, 0x61, 0x9B, 0x8E, 0x88, 0xC9, 0x12, 0x61, 0x00, 0x61, + 0x80, 0xC9, 0xB4, 0x28, 0x42, 0x2E, 0x18, 0x24, 0x41, 0xC1, 0x03, 0x96, 0xFF, 0xF4, 0x8A, 0x3C, + 0x40, 0x03, 0x80, 0x16, 0xB6, 0x28, 0x9A, 0x28, 0x14, 0x04, 0x00, 0x01, 0xF0, 0x10, 0xA6, 0x00, + 0x5A, 0x08, 0x01, 0x1D, 0xB4, 0x08, 0x50, 0x10, 0x00, 0x09, 0xE6, 0x33, 0xE8, 0x03, 0x84, 0x00, + 0xD5, 0x06, 0x4E, 0x07, 0x00, 0x04, 0x8E, 0x0A, 0xD5, 0x02, 0x8C, 0x0A, 0xB6, 0x08, 0x04, 0x04, + 0x00, 0x01, 0x50, 0x10, 0x00, 0x09, 0xE6, 0x33, 0x4E, 0xF3, 0xFF, 0x42, 0x4E, 0x07, 0x00, 0x04, + 0x8E, 0x0A, 0xD5, 0x02, 0x8C, 0x0A, 0x14, 0x04, 0x00, 0x01, 0xFC, 0xC4, 0x84, 0x6A, 0xFE, 0x5C, + 0xE2, 0x20, 0xE8, 0x0B, 0x94, 0xC9, 0xE0, 0x03, 0xE9, 0x06, 0x9A, 0x41, 0x40, 0x30, 0x84, 0x0A, + 0x9A, 0x43, 0xD5, 0x02, 0x9A, 0x42, 0x96, 0x49, 0x80, 0x01, 0xDD, 0x9E, 0xB4, 0x60, 0x4E, 0x35, + 0x00, 0x0A, 0xE0, 0x23, 0xE9, 0x07, 0xA0, 0x01, 0x4E, 0x05, 0x00, 0x05, 0xE0, 0x40, 0xEB, 0x27, + 0xDD, 0x9E, 0x84, 0x00, 0xDD, 0x9E, 0xFC, 0x52, 0x80, 0xE1, 0x44, 0x11, 0x29, 0x7C, 0xF2, 0x85, + 0x81, 0x03, 0xF4, 0x96, 0xEA, 0x70, 0xF0, 0x95, 0x3C, 0x13, 0x79, 0xD4, 0xB0, 0x20, 0xF1, 0x86, + 0x3A, 0x20, 0x14, 0x20, 0x3C, 0x13, 0x79, 0xD5, 0xF2, 0x06, 0xF1, 0x87, 0xF1, 0x05, 0x84, 0x00, + 0xF0, 0x9C, 0x22, 0x10, 0x80, 0x00, 0xF0, 0x9D, 0xF1, 0x88, 0xF1, 0x05, 0x81, 0x40, 0xA4, 0x49, + 0x9A, 0x51, 0x96, 0x4B, 0xF1, 0x89, 0x22, 0x14, 0x00, 0x00, 0xF2, 0x07, 0xF1, 0x8A, 0x02, 0x14, + 0x00, 0x01, 0x9A, 0x51, 0x96, 0x4B, 0xF1, 0x8B, 0xA4, 0x7B, 0xFE, 0x4C, 0xF1, 0x92, 0xA4, 0x7C, + 0xFE, 0x4C, 0xF1, 0x93, 0xF1, 0x06, 0xF0, 0x8C, 0xF0, 0x06, 0x92, 0x21, 0xF0, 0x8E, 0xF0, 0x06, + 0xF1, 0x94, 0x80, 0x22, 0x92, 0x21, 0x92, 0x02, 0xF1, 0x90, 0xF2, 0x8F, 0xF0, 0x97, 0xF1, 0x91, + 0xEB, 0xA1, 0xE3, 0x40, 0x4E, 0xF2, 0x03, 0xD3, 0xDD, 0x57, 0xF6, 0x15, 0x42, 0x65, 0x00, 0x73, + 0xDD, 0x5A, 0x4E, 0x02, 0x03, 0xC7, 0x00, 0x03, 0x01, 0x07, 0x4E, 0x03, 0x03, 0xC3, 0xEB, 0x8F, + 0xE6, 0x02, 0x4E, 0xF2, 0x00, 0x92, 0x02, 0x13, 0x00, 0x5C, 0xE6, 0x22, 0x4E, 0xF3, 0x00, 0x8D, + 0xE6, 0x24, 0x3C, 0x33, 0x79, 0xD4, 0xEA, 0x6F, 0x4E, 0xF2, 0x00, 0x87, 0xF1, 0x05, 0x22, 0x53, + 0x00, 0x05, 0x22, 0x10, 0x80, 0x00, 0x4C, 0x12, 0x80, 0x80, 0xF1, 0x05, 0x22, 0x10, 0x80, 0x01, + 0x9A, 0x59, 0x4C, 0x50, 0x80, 0x7A, 0x22, 0x53, 0x00, 0x06, 0x22, 0x14, 0x00, 0x00, 0x4C, 0x12, + 0x80, 0x74, 0xEB, 0x70, 0x9A, 0x41, 0xD1, 0x70, 0x2E, 0x17, 0xF0, 0x4A, 0xC9, 0x06, 0x00, 0x13, + 0x00, 0x9F, 0x00, 0x23, 0x00, 0x9E, 0xD5, 0x05, 0x00, 0x13, 0x00, 0x9D, 0x00, 0x23, 0x00, 0x9C, + 0x8A, 0x22, 0xE4, 0x29, 0xE8, 0x61, 0x22, 0x43, 0x00, 0x03, 0x40, 0x11, 0x88, 0x09, 0x8A, 0x64, + 0x22, 0x53, 0x00, 0x04, 0x4E, 0x34, 0x00, 0x03, 0xFE, 0xDA, 0x96, 0xDB, 0xE0, 0x23, 0xE8, 0x0E, + 0x40, 0x20, 0x08, 0x09, 0x8A, 0x05, 0x4E, 0x04, 0x00, 0x03, 0xFE, 0x02, 0x96, 0x03, 0xE0, 0x40, + 0xE8, 0x05, 0xE0, 0x24, 0xE8, 0x03, 0xE0, 0x45, 0xE9, 0x47, 0x50, 0x13, 0x00, 0x14, 0x22, 0x23, + 0x00, 0x0E, 0x23, 0xC0, 0x80, 0x03, 0x84, 0x03, 0x8A, 0x9C, 0x8A, 0xA2, 0xFF, 0x04, 0xFF, 0x44, + 0x90, 0x81, 0x40, 0x92, 0x84, 0x0A, 0xF4, 0x9E, 0x14, 0x9F, 0x80, 0x1F, 0xCC, 0x03, 0x4E, 0x92, + 0x00, 0x34, 0xB0, 0x1E, 0xF2, 0x98, 0xF4, 0x8D, 0xDD, 0x4D, 0x5E, 0xF0, 0x03, 0x0C, 0xF4, 0x0D, + 0xF2, 0x18, 0xE9, 0x2A, 0x40, 0x1E, 0x10, 0x01, 0x84, 0x00, 0x8A, 0x49, 0xB0, 0xDE, 0x50, 0x43, + 0x00, 0x14, 0x50, 0x53, 0x00, 0x28, 0x49, 0xFF, 0xFD, 0x19, 0xF1, 0x1E, 0x3C, 0x1F, 0xFA, 0x6C, + 0xF1, 0x1F, 0x3C, 0x1F, 0xFA, 0x6D, 0xC0, 0x18, 0xDD, 0x5A, 0x5A, 0x00, 0x04, 0x16, 0x84, 0x01, + 0xEB, 0xC5, 0x10, 0x03, 0x01, 0x06, 0x84, 0x22, 0x80, 0x0A, 0xEB, 0xC2, 0x3C, 0x07, 0xF4, 0xDA, + 0x3C, 0x17, 0xF4, 0xD8, 0xEA, 0x55, 0xAC, 0x36, 0x84, 0x00, 0xAC, 0x77, 0xAC, 0x75, 0x10, 0x03, + 0x01, 0x00, 0x48, 0x00, 0x03, 0x2F, 0x02, 0x23, 0x00, 0x5D, 0x5A, 0x28, 0x01, 0x47, 0x00, 0x03, + 0x01, 0x00, 0x5A, 0x08, 0x01, 0x2E, 0xF0, 0x16, 0x5A, 0x08, 0x01, 0x2B, 0x44, 0x02, 0x1E, 0x20, + 0xF1, 0x06, 0xF2, 0x07, 0x49, 0xFF, 0xFF, 0x04, 0x5A, 0x08, 0x01, 0x23, 0x3C, 0x2D, 0xFA, 0x6B, + 0xEB, 0x39, 0x3C, 0x1D, 0xFA, 0x6A, 0x22, 0x33, 0x00, 0x05, 0x8A, 0x02, 0x8A, 0x61, 0xFE, 0x04, + 0x42, 0x01, 0x8C, 0x73, 0xF3, 0x12, 0xE0, 0x03, 0xE8, 0x13, 0xF3, 0x13, 0xE0, 0x03, 0xE8, 0x06, + 0xAC, 0x77, 0x12, 0x23, 0x00, 0x08, 0x48, 0x00, 0x03, 0x05, 0x22, 0x03, 0x00, 0x07, 0x88, 0x20, + 0xEA, 0xD6, 0x90, 0x21, 0x88, 0x02, 0xAC, 0x77, 0x90, 0x01, 0x48, 0x00, 0x02, 0xFA, 0x00, 0x03, + 0x00, 0xFF, 0x4E, 0x02, 0x02, 0xF7, 0xDD, 0x5A, 0x5A, 0x08, 0x03, 0x04, 0x48, 0x00, 0x02, 0xE9, + 0xEA, 0x86, 0x5A, 0x08, 0x02, 0x04, 0x48, 0x00, 0x02, 0xED, 0x02, 0x03, 0x00, 0x67, 0xAC, 0x37, + 0x02, 0x03, 0x00, 0x68, 0x48, 0x00, 0x02, 0xE5, 0xE6, 0x42, 0x4E, 0xF3, 0x02, 0xE3, 0xB4, 0xA6, + 0xB4, 0x07, 0xE0, 0x05, 0xE8, 0x04, 0x2E, 0x07, 0xDE, 0xA2, 0xD5, 0x05, 0x00, 0x03, 0x00, 0xD7, + 0xC0, 0x04, 0x8E, 0x01, 0x10, 0x03, 0x00, 0xD7, 0xA1, 0x35, 0x40, 0xF2, 0x04, 0x0A, 0xE0, 0xAF, + 0xE8, 0x0B, 0xDD, 0x54, 0xEA, 0x98, 0xC0, 0x06, 0x04, 0x03, 0x00, 0x0F, 0x90, 0x01, 0xE0, 0x80, + 0xE8, 0x26, 0x84, 0x03, 0xD5, 0x22, 0x84, 0x07, 0xFE, 0x24, 0x90, 0x03, 0xE0, 0x05, 0xE9, 0x1C, + 0x00, 0x13, 0x00, 0xD8, 0x84, 0x01, 0xC1, 0x19, 0x04, 0x33, 0x00, 0x0A, 0x44, 0x00, 0x00, 0x31, + 0xFE, 0xC4, 0x90, 0x66, 0xE0, 0xA3, 0xE8, 0x10, 0x3C, 0x33, 0xEF, 0x78, 0x54, 0x31, 0x82, 0x00, + 0xC3, 0x07, 0x04, 0x33, 0x00, 0x0F, 0xFE, 0x1C, 0x90, 0x06, 0xE0, 0x80, 0xE8, 0x08, 0x8C, 0x21, + 0x10, 0x13, 0x00, 0xD8, 0xD5, 0x04, 0x84, 0x00, 0x10, 0x03, 0x00, 0xD8, 0x00, 0x13, 0x00, 0xD7, + 0x84, 0x00, 0x40, 0x00, 0x04, 0x06, 0x00, 0x13, 0x01, 0x00, 0x10, 0x03, 0x01, 0x01, 0x5A, 0x18, + 0x01, 0x4A, 0x00, 0x13, 0x00, 0xBF, 0x5A, 0x18, 0x02, 0x46, 0x5A, 0x08, 0x01, 0x1D, 0x5A, 0x20, + 0x02, 0x11, 0x00, 0x03, 0x00, 0xD8, 0xE6, 0x02, 0xE9, 0x0C, 0xDD, 0x4F, 0x84, 0x0A, 0x96, 0x6E, + 0xC1, 0x04, 0x3C, 0x13, 0xEC, 0x3D, 0xD5, 0x02, 0xA4, 0x7A, 0xFE, 0x0C, 0x48, 0x00, 0x00, 0xB4, + 0xEA, 0x2E, 0x84, 0x0A, 0xEA, 0x67, 0xC1, 0x04, 0x2E, 0x17, 0xD8, 0xF0, 0xD5, 0xF7, 0x00, 0x13, + 0x80, 0x14, 0xD5, 0xF4, 0x5A, 0x28, 0x02, 0x04, 0x48, 0x00, 0x00, 0xA8, 0x00, 0x13, 0x01, 0x02, + 0xEA, 0x7E, 0x5A, 0x18, 0x01, 0x11, 0xDD, 0x4F, 0x96, 0x6E, 0xC1, 0x04, 0x2E, 0x17, 0xD8, 0x7C, + 0xEA, 0xB6, 0xEA, 0x2E, 0xEA, 0x67, 0xC1, 0x04, 0x2E, 0x17, 0xD8, 0xED, 0xEA, 0xB6, 0x00, 0x13, + 0x80, 0x11, 0xEA, 0xB6, 0xDD, 0x4F, 0x96, 0x6E, 0xC1, 0x04, 0x2E, 0x17, 0xD8, 0x7D, 0xEA, 0xB6, + 0xEA, 0x2E, 0xEA, 0x67, 0xC1, 0x04, 0x2E, 0x17, 0xD8, 0xEC, 0xEA, 0xB6, 0x00, 0x13, 0x80, 0x10, + 0xEA, 0xB6, 0xE6, 0x46, 0xE9, 0x35, 0x5A, 0x08, 0x01, 0x34, 0x00, 0x03, 0x00, 0xD8, 0xE6, 0x03, + 0xE8, 0x04, 0xDD, 0x5A, 0x5A, 0x08, 0x03, 0x2D, 0x22, 0x03, 0x00, 0x11, 0x22, 0x13, 0x00, 0x1B, + 0x22, 0xF3, 0x00, 0x1C, 0x9A, 0x41, 0x22, 0x03, 0x00, 0x12, 0x8A, 0x0F, 0xFE, 0x04, 0x42, 0x00, + 0x84, 0x73, 0x44, 0x10, 0x9C, 0x3F, 0xE0, 0x20, 0xE9, 0x1B, 0xDD, 0x54, 0xEA, 0x98, 0xC8, 0x08, + 0xDD, 0x4F, 0x84, 0x0A, 0x96, 0x6E, 0xC1, 0x0D, 0x3C, 0x13, 0xEC, 0x3D, 0xD5, 0x0B, 0x80, 0x0A, + 0xEA, 0x54, 0x5A, 0x08, 0x01, 0xF7, 0x00, 0x03, 0x00, 0xD8, 0xE6, 0x03, 0xE8, 0xF2, 0xD5, 0x55, + 0xA4, 0x7A, 0xFE, 0x0C, 0x12, 0x03, 0x00, 0x61, 0x84, 0x01, 0xF0, 0x8C, 0xD5, 0x4E, 0xDD, 0x5A, + 0x5A, 0x08, 0x03, 0x13, 0xDD, 0x46, 0x96, 0x2E, 0xC0, 0x05, 0xEA, 0x7E, 0x2E, 0x17, 0xD8, 0x7E, + 0xD5, 0x3F, 0xEA, 0x2E, 0xEA, 0x7E, 0xEA, 0x67, 0xC1, 0x04, 0x2E, 0x17, 0xD8, 0xEF, 0xD5, 0x38, + 0x00, 0x13, 0x80, 0x13, 0xD5, 0x35, 0x22, 0x53, 0x00, 0x11, 0xF1, 0x08, 0xD1, 0x09, 0xF1, 0x09, + 0xD1, 0x07, 0x22, 0x53, 0x00, 0x12, 0xF0, 0x0A, 0xD0, 0x03, 0xF0, 0x0B, 0xD8, 0x19, 0xDD, 0x46, + 0x96, 0x2E, 0xC0, 0x08, 0x2E, 0x17, 0xD8, 0x7F, 0x84, 0x03, 0xFE, 0x44, 0x90, 0x21, 0xEA, 0x7E, + 0xD5, 0x0D, 0xEA, 0x2E, 0xEA, 0x7E, 0xEA, 0x67, 0xC1, 0x04, 0x2E, 0x27, 0xD8, 0xEE, 0xD5, 0x03, + 0x00, 0x23, 0x80, 0x12, 0x84, 0x23, 0xFE, 0x54, 0x90, 0x21, 0x96, 0x48, 0xD5, 0x11, 0xDD, 0x46, + 0x96, 0x2E, 0xC0, 0x05, 0xEA, 0x7E, 0x2E, 0x17, 0xD8, 0x7F, 0xD5, 0x0A, 0xEA, 0x2E, 0xEA, 0x7E, + 0xEA, 0x67, 0xC1, 0x04, 0x2E, 0x17, 0xD8, 0xEE, 0xD5, 0x03, 0x00, 0x13, 0x80, 0x12, 0x84, 0x4A, + 0x49, 0xFF, 0xFD, 0xA6, 0x12, 0x03, 0x00, 0x61, 0x84, 0x01, 0x10, 0x0F, 0x80, 0x6F, 0xF0, 0x0C, + 0x02, 0x93, 0x00, 0x61, 0xC8, 0x48, 0xDD, 0x5A, 0x5A, 0x00, 0x03, 0x46, 0x22, 0x43, 0x00, 0x11, + 0xF0, 0x09, 0xF1, 0x08, 0x8A, 0x04, 0x9A, 0x61, 0xE0, 0x20, 0xEB, 0x56, 0x22, 0x33, 0x00, 0x12, + 0xF0, 0x0B, 0xF2, 0x0A, 0x8A, 0x03, 0x9A, 0x9A, 0xE0, 0x40, 0x40, 0x01, 0x3C, 0x1B, 0x3C, 0xF7, + 0xEF, 0x50, 0x14, 0x9F, 0x80, 0x20, 0x50, 0xF7, 0xFF, 0x9C, 0xE0, 0x8F, 0x14, 0x9F, 0x80, 0x21, + 0x14, 0x9F, 0x80, 0x22, 0x14, 0x9F, 0x80, 0x23, 0x96, 0x4B, 0x96, 0x03, 0xE9, 0x10, 0x3C, 0x27, + 0xEF, 0x4F, 0x50, 0x21, 0x00, 0x64, 0xE0, 0x44, 0xE9, 0x0A, 0x3C, 0x27, 0xF6, 0xF6, 0x40, 0x54, + 0x88, 0x08, 0x88, 0xA2, 0xE0, 0xA3, 0xE9, 0x03, 0x9A, 0x1A, 0x96, 0x03, 0x40, 0x24, 0x88, 0x08, + 0xE0, 0x22, 0xE8, 0x08, 0xF5, 0x14, 0x90, 0x22, 0xE0, 0x85, 0xE8, 0x03, 0xF1, 0xA0, 0xD5, 0x02, + 0xF1, 0xA1, 0xE0, 0x02, 0xE8, 0x08, 0xF1, 0x10, 0x90, 0x02, 0xE0, 0x61, 0xE8, 0x03, 0xF0, 0xA2, + 0xD5, 0x02, 0xF0, 0xA3, 0x22, 0x33, 0x00, 0x11, 0x83, 0x86, 0xB8, 0x2A, 0x22, 0x53, 0x00, 0x12, + 0x8A, 0x03, 0xF0, 0x9C, 0xB8, 0x2B, 0x8A, 0x05, 0xF0, 0x9D, 0xEB, 0x31, 0xC0, 0x04, 0xDD, 0x5A, + 0x5A, 0x08, 0x02, 0x0C, 0x84, 0x00, 0x10, 0x03, 0x01, 0x04, 0x22, 0x03, 0x00, 0x05, 0x8A, 0x03, + 0xF0, 0x9C, 0xEB, 0x39, 0x8A, 0x05, 0xF0, 0x9D, 0xDD, 0x5A, 0x5A, 0x08, 0x02, 0x08, 0xEA, 0x86, + 0x5A, 0x00, 0x02, 0x05, 0x84, 0x00, 0x10, 0x03, 0x01, 0x04, 0xEB, 0x31, 0x4E, 0x03, 0x00, 0xE5, + 0xEB, 0xF7, 0xE6, 0x03, 0x4E, 0xF3, 0x00, 0xAB, 0x00, 0x13, 0x00, 0xC0, 0x5A, 0x18, 0x01, 0x04, + 0x48, 0x00, 0x00, 0xA5, 0xE6, 0x05, 0xE8, 0x04, 0x8E, 0x01, 0x96, 0x01, 0xD5, 0x02, 0x84, 0x04, + 0x02, 0x23, 0x00, 0x5E, 0x3C, 0x13, 0xE9, 0xC9, 0xF0, 0x8D, 0xE2, 0x41, 0x4E, 0xF3, 0x00, 0x97, + 0xF0, 0x05, 0xEB, 0xCB, 0x4C, 0x11, 0x80, 0x93, 0x22, 0x10, 0x00, 0x01, 0xF2, 0x0E, 0x9A, 0x51, + 0x4C, 0x30, 0x80, 0x8D, 0x22, 0x14, 0x00, 0x00, 0x4C, 0x12, 0x80, 0x89, 0xEB, 0x70, 0xF2, 0x0F, + 0x9A, 0x51, 0x4C, 0x50, 0x80, 0x84, 0x50, 0x13, 0x00, 0x14, 0x22, 0x40, 0x80, 0x03, 0xF1, 0x0E, + 0x23, 0xC3, 0x00, 0x0E, 0x8A, 0x24, 0x02, 0x2F, 0x80, 0x2E, 0x4E, 0x14, 0x00, 0x03, 0xFE, 0x4A, + 0x96, 0x4B, 0xE0, 0x41, 0xE8, 0x12, 0xF0, 0x0F, 0x40, 0xF0, 0x70, 0x01, 0x40, 0x10, 0x08, 0x09, + 0x4E, 0xF4, 0x00, 0x04, 0x52, 0xF7, 0x80, 0x00, 0x40, 0xF7, 0x80, 0x11, 0xE0, 0x2F, 0xE8, 0x05, + 0xE0, 0x44, 0xE8, 0x03, 0xE0, 0x3C, 0xE9, 0x62, 0xF2, 0x1C, 0xF1, 0x1D, 0x81, 0xE2, 0x4E, 0x24, + 0x00, 0x04, 0x52, 0xF1, 0x00, 0x00, 0x83, 0xC1, 0x4E, 0x14, 0x00, 0x04, 0x53, 0xE0, 0x80, 0x00, + 0x40, 0xFF, 0x3C, 0x07, 0xE8, 0x0E, 0xF0, 0x0E, 0x41, 0xE0, 0x04, 0x09, 0x40, 0xFF, 0x10, 0x07, + 0xE8, 0x03, 0x4E, 0x25, 0x00, 0x4C, 0xE0, 0x9E, 0xE8, 0x0E, 0x4E, 0x26, 0x00, 0x48, 0xD5, 0x0B, + 0xF0, 0x11, 0xE0, 0x1C, 0xE8, 0x03, 0x4E, 0x15, 0x00, 0x42, 0xF0, 0x11, 0xEB, 0x2A, 0xE8, 0x03, + 0x4E, 0x16, 0x00, 0x3D, 0xCA, 0x02, 0xC1, 0x3A, 0xF0, 0x0D, 0xFA, 0x24, 0x81, 0xE6, 0x42, 0xF0, + 0x04, 0x73, 0x22, 0x27, 0x80, 0x07, 0x8E, 0x01, 0x8A, 0x62, 0x40, 0x31, 0x80, 0x76, 0x22, 0x17, + 0x80, 0x08, 0xCB, 0x05, 0x8A, 0xA1, 0x40, 0x52, 0x80, 0xB6, 0xC5, 0x28, 0x22, 0x17, 0x80, 0x03, + 0x22, 0x27, 0x80, 0x04, 0x9A, 0x61, 0x40, 0x2E, 0x08, 0x01, 0xEA, 0x53, 0x40, 0x01, 0x00, 0x16, + 0x94, 0x49, 0x94, 0x81, 0xF1, 0x9E, 0xF2, 0x9F, 0xC9, 0x02, 0xC2, 0x18, 0xB0, 0x1E, 0xF2, 0x99, + 0xF1, 0x98, 0xF4, 0x8D, 0xDD, 0x4D, 0x3C, 0x33, 0xE9, 0xCA, 0xF4, 0x0D, 0xE0, 0x03, 0xF1, 0x18, + 0xF2, 0x19, 0xE9, 0x0C, 0x88, 0x24, 0x84, 0x01, 0x88, 0x5C, 0xB0, 0xDC, 0x50, 0x43, 0x00, 0x14, + 0x50, 0x53, 0x00, 0x28, 0x49, 0xFF, 0xFA, 0x7A, 0xC8, 0x37, 0x50, 0x0F, 0x80, 0x6F, 0xB6, 0x1F, + 0xB0, 0xA0, 0x44, 0x00, 0x00, 0x32, 0xF0, 0x82, 0xF6, 0x81, 0xB0, 0x1C, 0x80, 0x29, 0x3A, 0x21, + 0x14, 0x00, 0x49, 0xFF, 0xFB, 0x4C, 0xEB, 0x5D, 0x5A, 0x08, 0x01, 0x11, 0x00, 0x03, 0x01, 0x0A, + 0xC8, 0x0D, 0x00, 0x0F, 0x80, 0x6F, 0x5A, 0x00, 0x03, 0x0A, 0xB0, 0x1C, 0x00, 0x13, 0x80, 0x0E, + 0x00, 0x23, 0x80, 0x0F, 0x49, 0xFF, 0xFB, 0x2A, 0xD5, 0x42, 0xDD, 0x5A, 0x5A, 0x08, 0x03, 0x40, + 0x04, 0x03, 0x00, 0x3F, 0x46, 0x50, 0x00, 0xF0, 0xFF, 0x46, 0xEA, 0x5E, 0xD8, 0x1D, 0x22, 0x23, + 0x00, 0x11, 0xF0, 0x1C, 0x22, 0x13, 0x00, 0x12, 0x88, 0x02, 0x83, 0x86, 0xB8, 0xAA, 0xF0, 0x1D, + 0x88, 0x01, 0xB8, 0xAB, 0xD5, 0x11, 0xEB, 0x31, 0xC8, 0x0F, 0x22, 0x23, 0x00, 0x11, 0xF0, 0x1C, + 0x22, 0x13, 0x00, 0x12, 0x88, 0x02, 0x83, 0x86, 0xB8, 0xAA, 0xF0, 0x1D, 0x88, 0x01, 0xB8, 0xAB, + 0x84, 0x01, 0x10, 0x03, 0x01, 0x04, 0x2E, 0x07, 0xF0, 0x08, 0xB0, 0x5C, 0xB6, 0x1F, 0xEB, 0x31, + 0x80, 0x46, 0xF0, 0x81, 0x50, 0x33, 0x00, 0x14, 0x80, 0x06, 0x50, 0x43, 0x00, 0x28, 0x50, 0x53, + 0x00, 0x3C, 0x49, 0xFF, 0xFA, 0xA6, 0xC8, 0x0B, 0x2E, 0x07, 0xF0, 0x08, 0x8C, 0x01, 0xEB, 0x57, + 0x00, 0x03, 0x00, 0xFE, 0xEB, 0x5F, 0xFE, 0x0F, 0x10, 0x03, 0x00, 0xFE, 0xF2, 0x1C, 0x22, 0x13, + 0x00, 0x11, 0xF0, 0x08, 0x88, 0x22, 0xE0, 0x20, 0xE9, 0x06, 0xF0, 0x09, 0xE0, 0x20, 0xEB, 0x56, + 0x96, 0x4B, 0xD5, 0x02, 0xF1, 0x08, 0xF3, 0x1D, 0x22, 0x03, 0x00, 0x12, 0xF4, 0x0A, 0x88, 0x03, + 0xE0, 0x04, 0xAC, 0x77, 0xE9, 0x07, 0xF4, 0x0B, 0xE0, 0x04, 0x40, 0x02, 0x3C, 0x1A, 0x96, 0x03, + 0xD5, 0x02, 0xF0, 0x0A, 0x00, 0x43, 0x01, 0x00, 0xEA, 0x55, 0x5A, 0x48, 0x01, 0x2B, 0x3C, 0x1F, + 0xFA, 0x6A, 0x3C, 0x0F, 0xFA, 0x6B, 0xCA, 0x02, 0xC3, 0x24, 0x84, 0x00, 0x10, 0x03, 0x01, 0x00, + 0x44, 0x0F, 0xFF, 0x9C, 0x22, 0x13, 0x00, 0x67, 0x3C, 0x0F, 0xFA, 0x6A, 0x3C, 0x0F, 0xFA, 0x6B, + 0x22, 0x03, 0x00, 0x03, 0x8A, 0x01, 0xF0, 0x9C, 0x22, 0x13, 0x00, 0x68, 0x22, 0x03, 0x00, 0x04, + 0x8A, 0x01, 0xF0, 0x9D, 0xB0, 0x1C, 0xDD, 0x4D, 0x12, 0x03, 0x00, 0x5E, 0xD5, 0x0A, 0xEA, 0x86, + 0x5A, 0x00, 0x02, 0x08, 0x02, 0x13, 0x00, 0x11, 0x02, 0x03, 0x00, 0x12, 0xAC, 0x77, 0xEA, 0x55, + 0xEA, 0xCB, 0x54, 0xA0, 0x00, 0xFF, 0x48, 0xFF, 0xFC, 0x2D, 0xFC, 0xD2, 0xFC, 0x20, 0x80, 0xC1, + 0x80, 0xE0, 0xDD, 0x4D, 0xE0, 0xC0, 0xE9, 0x05, 0x84, 0x00, 0xB6, 0x07, 0xA8, 0x39, 0xFC, 0xA0, + 0xB4, 0x47, 0x42, 0x11, 0x18, 0x24, 0xEA, 0x53, 0x8A, 0x41, 0xB6, 0x47, 0xA0, 0xB9, 0xFF, 0x94, + 0x40, 0x63, 0x00, 0xD6, 0x9B, 0x96, 0xA9, 0xB9, 0xFC, 0xA0, 0xFC, 0x44, 0xF0, 0x81, 0x80, 0xA1, + 0x3C, 0x03, 0x79, 0xD4, 0xA4, 0x51, 0x23, 0xC1, 0x00, 0x00, 0x8A, 0x01, 0x40, 0x90, 0x00, 0x11, + 0xA4, 0x59, 0xEA, 0x6F, 0x22, 0x21, 0x80, 0x00, 0x8A, 0x01, 0x40, 0xA0, 0x00, 0x11, 0x84, 0xE0, + 0xEA, 0x4E, 0xEA, 0x49, 0xF0, 0x82, 0xF0, 0x02, 0xE2, 0xE0, 0xE8, 0x47, 0xF6, 0x01, 0x42, 0x63, + 0x8C, 0x73, 0x00, 0x13, 0x00, 0xBF, 0xC1, 0x3E, 0xEB, 0x8F, 0xE6, 0x02, 0xE9, 0x3B, 0x84, 0x0A, + 0x5A, 0x18, 0x03, 0x05, 0x00, 0x12, 0x80, 0x13, 0xD5, 0x03, 0x00, 0x12, 0x80, 0x12, 0x50, 0x83, + 0x00, 0x14, 0xFE, 0x44, 0x22, 0xF4, 0x00, 0x07, 0x22, 0x03, 0x00, 0x05, 0x96, 0x49, 0x8A, 0x0F, + 0xF0, 0x86, 0x22, 0xF4, 0x00, 0x08, 0xEB, 0x39, 0xF3, 0x85, 0x8A, 0x0F, 0xF0, 0x87, 0xB0, 0x06, + 0xF5, 0x84, 0xF2, 0x83, 0x49, 0xFF, 0xFF, 0xAC, 0x22, 0xF4, 0x00, 0x07, 0xF0, 0x06, 0xF2, 0x03, + 0x88, 0x0F, 0xE0, 0x1C, 0xF5, 0x04, 0xF3, 0x05, 0xE9, 0x06, 0xE0, 0x09, 0x40, 0x04, 0xBC, 0x1A, + 0x96, 0x03, 0xD5, 0x02, 0x80, 0x1C, 0x22, 0xF4, 0x00, 0x08, 0xAC, 0x37, 0xF0, 0x07, 0x88, 0x0F, + 0xE0, 0x02, 0xE9, 0x06, 0xE0, 0x0A, 0x40, 0x05, 0x3C, 0x1A, 0x96, 0x03, 0xD5, 0x02, 0x80, 0x02, + 0xEA, 0x55, 0x8C, 0xE1, 0x97, 0xF8, 0xD5, 0xB8, 0xFC, 0xC4, 0xFC, 0x21, 0x44, 0x62, 0x50, 0x30, + 0x84, 0xEB, 0x00, 0x03, 0x00, 0xEB, 0x5A, 0x08, 0x02, 0x23, 0x22, 0x13, 0x00, 0x23, 0x22, 0x03, + 0x00, 0x19, 0x02, 0x53, 0x00, 0x73, 0x8A, 0x01, 0xB6, 0x1F, 0x22, 0x13, 0x00, 0x24, 0x22, 0x03, + 0x00, 0x1A, 0x8A, 0x01, 0xF0, 0x81, 0xEB, 0xB7, 0xD0, 0x04, 0x8C, 0xA1, 0x12, 0x53, 0x00, 0x73, + 0x00, 0x03, 0x01, 0x2C, 0xC8, 0x0C, 0x80, 0x1F, 0xDD, 0x4D, 0x02, 0x13, 0x00, 0x74, 0x88, 0x01, + 0x44, 0x10, 0xFF, 0xFE, 0xE0, 0x20, 0xE9, 0x03, 0x12, 0x03, 0x00, 0x74, 0x8E, 0xE1, 0x97, 0xF8, + 0xEB, 0x49, 0xCF, 0xD8, 0xFC, 0xA1, 0xA7, 0x60, 0x5C, 0xF2, 0x80, 0x3C, 0xE8, 0x0F, 0x95, 0x6A, + 0x88, 0xA3, 0xAE, 0x2B, 0xA6, 0x20, 0x94, 0x02, 0x88, 0x03, 0xAE, 0x42, 0xA6, 0x20, 0x38, 0x21, + 0x82, 0x09, 0xA6, 0x20, 0x8C, 0x01, 0xAE, 0x20, 0xDD, 0x9E, 0xFC, 0x40, 0x84, 0xC0, 0x44, 0x70, + 0x7F, 0xFF, 0x80, 0x86, 0x38, 0x91, 0x9A, 0x11, 0x54, 0xA3, 0x00, 0xFF, 0xE0, 0xE9, 0x8C, 0xC1, + 0x40, 0x74, 0xBC, 0x1A, 0x54, 0x93, 0x00, 0xFF, 0x40, 0x45, 0x3C, 0x1A, 0xE3, 0x25, 0xE9, 0xF3, + 0xE0, 0xE2, 0xE8, 0x06, 0x95, 0x22, 0x88, 0x64, 0xAE, 0x1B, 0xAE, 0x5A, 0xAC, 0x98, 0xFC, 0xC0, + 0xFC, 0x5A, 0x81, 0x22, 0x00, 0x2F, 0x80, 0xF8, 0x12, 0x1F, 0x80, 0x19, 0xF2, 0x89, 0x00, 0x2F, + 0x80, 0xFC, 0xF1, 0x40, 0xF2, 0x85, 0x00, 0x2F, 0x81, 0x04, 0x12, 0x0F, 0x80, 0x18, 0xF2, 0x87, + 0x84, 0x00, 0xEB, 0x92, 0xAC, 0x08, 0xF2, 0x81, 0xF1, 0x05, 0xEA, 0xE1, 0xF3, 0x86, 0xB6, 0x9F, + 0xF5, 0x83, 0xF2, 0x88, 0x5A, 0x18, 0x01, 0x04, 0xF1, 0x3D, 0xAE, 0x08, 0x85, 0x01, 0x87, 0x80, + 0x4E, 0x82, 0x01, 0x34, 0x50, 0x04, 0x7F, 0xFF, 0xB0, 0x4C, 0xB0, 0x8C, 0x38, 0x60, 0x82, 0x11, + 0x94, 0x42, 0x88, 0x22, 0xEA, 0x71, 0x22, 0x70, 0x80, 0x01, 0xF0, 0x01, 0xFE, 0x3C, 0xF0, 0x82, + 0xF1, 0x02, 0xB4, 0x1F, 0x88, 0x01, 0x38, 0x00, 0x18, 0x00, 0xEB, 0xEE, 0x4C, 0x54, 0xFF, 0xEA, + 0x40, 0x14, 0xA4, 0x05, 0x81, 0x46, 0xF1, 0x8A, 0xEB, 0xEE, 0x4C, 0x54, 0x80, 0x10, 0x50, 0x25, + 0x7F, 0xFF, 0x96, 0x10, 0xF0, 0x84, 0x8E, 0xC1, 0xB4, 0x1F, 0xF1, 0x02, 0x97, 0xB3, 0x88, 0x06, + 0xEB, 0x37, 0x40, 0x14, 0xA4, 0x05, 0xF1, 0x8A, 0xD5, 0x6F, 0xF1, 0x01, 0xE1, 0x41, 0xE8, 0xF0, + 0xF1, 0x0A, 0xFE, 0x0E, 0x84, 0x30, 0xFE, 0x0E, 0xF1, 0x02, 0x40, 0x55, 0x04, 0x00, 0xF1, 0x06, + 0xFE, 0x0F, 0xB4, 0x3F, 0x38, 0x00, 0x94, 0x08, 0xF0, 0x40, 0xF1, 0x40, 0xA4, 0x00, 0x8C, 0x01, + 0xAC, 0x08, 0xF0, 0x05, 0x5A, 0x08, 0x01, 0x14, 0xF0, 0x03, 0x80, 0x27, 0xF3, 0x3C, 0x38, 0x00, + 0x15, 0x11, 0xF4, 0x3D, 0xF0, 0x84, 0xF2, 0x04, 0x80, 0x0A, 0xF5, 0x8B, 0x49, 0xFF, 0xFF, 0x65, + 0xF0, 0x04, 0xF5, 0x0B, 0xE0, 0x1C, 0x40, 0x0E, 0x3C, 0x1B, 0x83, 0x80, 0xF0, 0x07, 0x5A, 0x08, + 0x01, 0x0D, 0xF0, 0x03, 0x38, 0x00, 0x15, 0x11, 0xEB, 0x2A, 0xE8, 0x07, 0xF1, 0x42, 0x83, 0x80, + 0x10, 0xA0, 0x80, 0x00, 0xF1, 0x43, 0xAF, 0xC8, 0xEA, 0xCB, 0x40, 0xA0, 0x00, 0x11, 0xB4, 0x1F, + 0xF1, 0x02, 0x88, 0x0A, 0xEB, 0x37, 0xD5, 0xB1, 0x4E, 0x65, 0x00, 0x32, 0xF1, 0x0A, 0xFE, 0x0E, + 0x84, 0x30, 0xFE, 0x0E, 0xF1, 0x02, 0x40, 0xA3, 0x04, 0x00, 0xF1, 0x06, 0xFE, 0x0F, 0xB4, 0x3F, + 0x38, 0x00, 0xA8, 0x08, 0xF0, 0x40, 0xF1, 0x40, 0xA4, 0x00, 0x8C, 0x01, 0xAC, 0x08, 0xF0, 0x05, + 0x5A, 0x08, 0x01, 0x12, 0xF0, 0x03, 0x80, 0x27, 0xF3, 0x3C, 0x38, 0x50, 0x29, 0x11, 0xF4, 0x3D, + 0x80, 0x45, 0x80, 0x06, 0xF5, 0x8B, 0x49, 0xFF, 0xFF, 0x28, 0xF5, 0x0B, 0xE0, 0xBC, 0x40, 0x5E, + 0x3C, 0x1B, 0x83, 0x85, 0xF0, 0x07, 0x5A, 0x00, 0x01, 0x13, 0x8E, 0xC1, 0xB4, 0x1F, 0x97, 0xB3, + 0xF1, 0x02, 0x88, 0x06, 0xEB, 0x37, 0xEB, 0xEE, 0x4C, 0x54, 0xBF, 0xD0, 0xF0, 0x09, 0x8C, 0xC1, + 0x97, 0xB0, 0x5A, 0x00, 0x08, 0x10, 0x84, 0x40, 0x80, 0x02, 0xD5, 0x14, 0xF0, 0x03, 0x38, 0x00, + 0x29, 0x11, 0xEB, 0x2A, 0xE8, 0xEB, 0xF1, 0x42, 0x83, 0x80, 0xAF, 0x88, 0xF1, 0x43, 0xAF, 0xC8, + 0xD5, 0xE5, 0xF0, 0x01, 0x9E, 0x81, 0xF0, 0x04, 0x40, 0x20, 0x08, 0x07, 0x84, 0x00, 0x40, 0x00, + 0x18, 0x06, 0xF1, 0x08, 0x8E, 0x21, 0xE0, 0xE1, 0xE8, 0x3E, 0x97, 0xF9, 0x8A, 0xC0, 0x9C, 0xF9, + 0xF0, 0x01, 0x96, 0xDB, 0x42, 0x51, 0x80, 0x24, 0xF0, 0x04, 0x80, 0x26, 0x40, 0xA0, 0x08, 0x00, + 0xB4, 0x1F, 0x41, 0xE0, 0x14, 0x00, 0xE1, 0x41, 0xE9, 0x2A, 0x80, 0x01, 0x84, 0x80, 0xB4, 0x3F, + 0x88, 0x20, 0x38, 0x10, 0x94, 0x00, 0x40, 0x14, 0x84, 0x02, 0x4C, 0x14, 0x80, 0x0F, 0x80, 0x20, + 0xC4, 0x17, 0xB1, 0x0C, 0x8E, 0x01, 0x38, 0x02, 0x22, 0x09, 0x40, 0x04, 0x08, 0x08, 0x88, 0x04, + 0xAC, 0xC1, 0xEB, 0x02, 0xEA, 0x71, 0xD5, 0x0C, 0xF1, 0x01, 0xE0, 0x01, 0xE8, 0xF1, 0x8C, 0x01, + 0x96, 0x03, 0x84, 0x81, 0xD5, 0xE5, 0xE1, 0x41, 0xE9, 0xDF, 0x8C, 0x21, 0x96, 0x4B, 0x38, 0x0F, + 0x04, 0x00, 0x40, 0x04, 0x80, 0x02, 0x4C, 0x04, 0xFF, 0xF8, 0xD5, 0xD6, 0xE4, 0x62, 0xE8, 0x07, + 0x48, 0xFF, 0xFF, 0x08, 0xE4, 0xE2, 0x4E, 0xF3, 0xFF, 0x05, 0x8A, 0xC0, 0xF0, 0x01, 0x8E, 0xE1, + 0x97, 0xFB, 0x42, 0x33, 0x80, 0x24, 0xF0, 0x04, 0x88, 0x02, 0x80, 0x40, 0xB4, 0x1F, 0x99, 0x03, + 0xE0, 0x46, 0x4E, 0xF3, 0xFE, 0xF7, 0x80, 0x06, 0x84, 0x20, 0xB4, 0xBF, 0x88, 0xA0, 0x38, 0x52, + 0x8C, 0x00, 0x40, 0x54, 0x94, 0x02, 0x4C, 0x54, 0x80, 0x0F, 0x80, 0xC0, 0xC1, 0x17, 0xB0, 0x4C, + 0x8E, 0x01, 0x38, 0x00, 0xA2, 0x09, 0x40, 0x04, 0x08, 0x08, 0x88, 0x01, 0xAD, 0xC1, 0xEB, 0x02, + 0xEA, 0x71, 0xD5, 0x0C, 0xF5, 0x01, 0xE0, 0x05, 0xE8, 0xF1, 0x8C, 0x01, 0x96, 0x03, 0x84, 0x21, + 0xD5, 0xE5, 0xE0, 0x46, 0xE9, 0xDE, 0x8C, 0xC1, 0x97, 0xB3, 0x38, 0x52, 0x18, 0x00, 0x40, 0x54, + 0x94, 0x02, 0x4C, 0x54, 0xFF, 0xF8, 0xD5, 0xD5, 0x80, 0x1C, 0xFC, 0xDA, 0x5A, 0x18, 0x02, 0x0C, + 0xEA, 0x49, 0x44, 0x22, 0x51, 0x50, 0xEA, 0xEA, 0x00, 0x31, 0x00, 0x0A, 0x54, 0x31, 0x80, 0xF0, + 0x10, 0x31, 0x00, 0x0A, 0xEA, 0x49, 0xEA, 0xA9, 0xEA, 0xEA, 0x10, 0x11, 0x00, 0xEB, 0xDD, 0x9E, + 0x44, 0x22, 0x51, 0x50, 0xEA, 0x49, 0xEA, 0xEA, 0x80, 0x02, 0xC1, 0x0B, 0xA4, 0x55, 0x8C, 0x21, + 0x54, 0x20, 0x80, 0x0F, 0x00, 0x10, 0x00, 0x0A, 0x54, 0x10, 0x80, 0xF0, 0xFE, 0x57, 0xD5, 0x05, + 0x00, 0x11, 0x00, 0x0A, 0x54, 0x10, 0x80, 0xF0, 0x10, 0x10, 0x00, 0x0A, 0xDD, 0x9E, 0x44, 0x20, + 0x01, 0x0C, 0x44, 0x12, 0x51, 0x50, 0xEB, 0x69, 0xA4, 0x0D, 0x96, 0x1F, 0xDD, 0x9E, 0x84, 0x00, + 0x3C, 0x0B, 0xF8, 0x28, 0xDD, 0x9E, 0x2E, 0x57, 0xD9, 0x2A, 0x3C, 0x13, 0xF8, 0x28, 0x84, 0x40, + 0x96, 0x10, 0xE2, 0x05, 0xE8, 0x0E, 0x80, 0x82, 0x40, 0x30, 0x88, 0x0E, 0x96, 0xC6, 0x8C, 0x41, + 0xCB, 0xF8, 0x84, 0x41, 0x40, 0x21, 0x10, 0x0C, 0xFE, 0x57, 0x3C, 0x1B, 0xF8, 0x28, 0xDD, 0x9E, + 0xEA, 0xF0, 0xDD, 0x9E, 0x84, 0x21, 0x40, 0x00, 0x80, 0x0C, 0x3C, 0x13, 0xF8, 0x28, 0xFE, 0x03, + 0xFE, 0x0E, 0x3C, 0x0B, 0xF8, 0x28, 0xDD, 0x9E, 0xFC, 0x00, 0xEA, 0x26, 0xC8, 0x03, 0x84, 0x01, + 0xD5, 0x02, 0x84, 0x02, 0xEA, 0x9B, 0xEA, 0xEC, 0xEA, 0x5D, 0xFC, 0x80, 0xFC, 0x00, 0x84, 0x01, + 0xEB, 0xE3, 0x44, 0x00, 0x03, 0x80, 0x84, 0x21, 0xDD, 0x43, 0x84, 0x00, 0xEB, 0x25, 0x84, 0x02, + 0xEA, 0x9B, 0xFC, 0x80, 0xFC, 0x02, 0xEB, 0x73, 0x3C, 0x03, 0xF8, 0x2A, 0x2E, 0x27, 0xF0, 0x5D, + 0x8C, 0x01, 0x44, 0x10, 0x00, 0x3C, 0x96, 0x01, 0xFE, 0x54, 0xE0, 0x01, 0x3C, 0x0B, 0xF8, 0x2A, + 0xE9, 0x1A, 0x2E, 0x07, 0xF0, 0x52, 0x84, 0x20, 0x8C, 0x01, 0x96, 0x00, 0xE6, 0x14, 0xEA, 0xD5, + 0x3E, 0x07, 0xF0, 0x52, 0x96, 0x00, 0x3C, 0x1B, 0xF8, 0x2A, 0xEA, 0x30, 0xEA, 0x26, 0xEA, 0x20, + 0xEA, 0x26, 0xF0, 0x81, 0xEA, 0x35, 0xF0, 0x82, 0xEA, 0x3A, 0xF0, 0x83, 0xF1, 0x02, 0xF0, 0x01, + 0xF2, 0x03, 0xDD, 0x5B, 0xFC, 0x82, 0xFC, 0x02, 0xEA, 0x81, 0x8C, 0x01, 0x97, 0x80, 0x5A, 0x60, + 0x05, 0x54, 0xE6, 0xC4, 0xE9, 0x53, 0xE6, 0xCA, 0xE9, 0x02, 0x84, 0xC4, 0x2E, 0x07, 0xF2, 0x01, + 0xE6, 0x06, 0xE9, 0x35, 0x84, 0x00, 0x44, 0x10, 0xFF, 0xFF, 0x44, 0x32, 0x25, 0xBC, 0x38, 0x21, + 0x81, 0x01, 0x97, 0x00, 0xC2, 0x06, 0xE2, 0x41, 0x40, 0x11, 0x3C, 0x1B, 0x40, 0x62, 0x3C, 0x1B, + 0x8C, 0x01, 0x5A, 0x08, 0x14, 0xF6, 0x84, 0x00, 0x3E, 0x07, 0xF2, 0x00, 0x84, 0x21, 0xFA, 0x00, + 0xDD, 0x43, 0x3C, 0x03, 0xF9, 0x01, 0x5E, 0xF0, 0x02, 0x59, 0xE8, 0x05, 0x50, 0x00, 0x00, 0xC8, + 0x96, 0x01, 0xD5, 0x03, 0x44, 0x00, 0x03, 0x20, 0x49, 0x00, 0x29, 0x1E, 0x2E, 0x07, 0xF0, 0x5E, + 0xE4, 0x03, 0xE8, 0x04, 0x8C, 0x01, 0x96, 0x00, 0xD5, 0x02, 0x84, 0x03, 0x3E, 0x07, 0xF0, 0x5E, + 0x84, 0x20, 0xFA, 0x58, 0x44, 0x02, 0x25, 0xBC, 0xDD, 0x40, 0xD5, 0x03, 0x8C, 0x01, 0xEB, 0x20, + 0x80, 0x06, 0xEA, 0x30, 0xEA, 0x26, 0xEA, 0x20, 0xEA, 0x26, 0xF0, 0x81, 0xEA, 0x35, 0xF0, 0x82, + 0xEA, 0x3A, 0xF0, 0x83, 0xF1, 0x02, 0xF0, 0x01, 0xF2, 0x03, 0xDD, 0x5B, 0x44, 0x00, 0x03, 0x20, + 0x84, 0x21, 0xDD, 0x43, 0xFC, 0x82, 0x84, 0xC0, 0xD5, 0xB2, 0x84, 0xC5, 0xD5, 0xB0, 0xFC, 0x45, + 0x44, 0x01, 0x29, 0x8C, 0xB1, 0x81, 0x80, 0x26, 0xEA, 0x4D, 0xEA, 0x9F, 0x80, 0xE1, 0xEA, 0x4D, + 0x3A, 0x23, 0x94, 0x24, 0xB5, 0x20, 0x44, 0x72, 0x5F, 0xBC, 0x3C, 0x0D, 0xBD, 0x4E, 0x3C, 0x0F, + 0xFC, 0x18, 0x80, 0x07, 0xEB, 0x64, 0xEA, 0x5B, 0xEA, 0x88, 0xEA, 0x5B, 0xB7, 0x20, 0xFC, 0xC5, + 0xFC, 0x01, 0x49, 0x00, 0x28, 0xD6, 0x44, 0x00, 0x03, 0x28, 0x84, 0x21, 0xDD, 0x43, 0x84, 0x20, + 0x84, 0x02, 0xDD, 0x43, 0xEA, 0x5D, 0x84, 0x00, 0xDD, 0x45, 0x84, 0x00, 0xEA, 0x30, 0x84, 0x00, + 0xEA, 0x20, 0xEA, 0x35, 0xB6, 0x1F, 0xEA, 0x3A, 0xF0, 0x81, 0xB4, 0x3F, 0x84, 0x00, 0xF2, 0x01, + 0xDD, 0x5B, 0x2E, 0x07, 0xED, 0xA6, 0x5A, 0x08, 0x01, 0x08, 0x84, 0x00, 0x49, 0x00, 0x3A, 0xAB, + 0x84, 0x00, 0x3E, 0x07, 0xED, 0xA6, 0x84, 0x01, 0xDD, 0x45, 0x84, 0x01, 0xEA, 0x9B, 0xFC, 0x81, + 0xFC, 0x21, 0x84, 0x00, 0x3C, 0x63, 0xF6, 0xD8, 0x3E, 0x07, 0xF0, 0x5C, 0xEB, 0x48, 0x92, 0xC1, + 0x97, 0x86, 0x5A, 0x00, 0x02, 0x46, 0x5A, 0x08, 0x05, 0x04, 0x48, 0x00, 0x00, 0xC2, 0x5A, 0x00, + 0x01, 0x03, 0xEA, 0x90, 0xEB, 0x73, 0x80, 0xE0, 0x5A, 0x08, 0x01, 0x1D, 0xEB, 0xE3, 0x84, 0x00, + 0x80, 0x27, 0xEB, 0x25, 0xFA, 0x10, 0xDD, 0x43, 0x49, 0x00, 0x28, 0x93, 0x84, 0x04, 0xEA, 0x30, + 0x84, 0x00, 0xDD, 0x45, 0x80, 0x07, 0xEA, 0x20, 0xEA, 0x35, 0xB6, 0x1F, 0xEA, 0x3A, 0xF0, 0x81, + 0xB4, 0x3F, 0x80, 0x07, 0xF2, 0x01, 0xDD, 0x5B, 0x84, 0x02, 0xEA, 0x9B, 0x80, 0x07, 0xDD, 0x45, + 0xEA, 0x90, 0xEB, 0xDA, 0x5A, 0x00, 0x01, 0x03, 0xEA, 0x90, 0xEA, 0x61, 0x5A, 0x00, 0x01, 0x03, + 0xEA, 0x90, 0x84, 0x00, 0x5A, 0x68, 0x01, 0x05, 0x3C, 0x03, 0xF8, 0x2B, 0x8C, 0x01, 0xEB, 0x25, + 0x3C, 0x13, 0xF8, 0x2B, 0x3C, 0x03, 0xEA, 0x0B, 0xE2, 0x20, 0x4E, 0xF3, 0x00, 0xB7, 0x84, 0x00, + 0xEB, 0xE3, 0xEB, 0xDC, 0x84, 0x20, 0xDD, 0x43, 0x84, 0x00, 0xEB, 0x25, 0xEA, 0x90, 0xEB, 0x73, + 0x80, 0xE0, 0x5A, 0x08, 0x01, 0x12, 0x49, 0xFF, 0xFF, 0x10, 0x84, 0x20, 0x44, 0x00, 0x08, 0x00, + 0xDD, 0x43, 0x84, 0x20, 0x3C, 0x1B, 0xF8, 0x2D, 0x3C, 0x1B, 0xF8, 0x2C, 0x3E, 0x17, 0xF2, 0x00, + 0x3E, 0x77, 0xF0, 0x5C, 0xEA, 0x90, 0xEA, 0x61, 0x5A, 0x00, 0x01, 0x03, 0xEA, 0x90, 0x84, 0x0B, + 0xDD, 0x4A, 0x5A, 0x08, 0x01, 0x0A, 0x4E, 0x63, 0x00, 0x91, 0x44, 0x00, 0x08, 0x00, 0x80, 0x26, + 0xDD, 0x43, 0x48, 0x00, 0x00, 0x89, 0x5A, 0x68, 0x01, 0x12, 0x84, 0x04, 0xDD, 0x4A, 0xC0, 0x0E, + 0xEB, 0x15, 0xEB, 0x09, 0x92, 0x01, 0x5C, 0xF0, 0x00, 0x64, 0xE8, 0x02, 0xDD, 0x4C, 0xE0, 0x01, + 0xE9, 0x05, 0x2E, 0x07, 0xF2, 0x00, 0x8C, 0x01, 0xD5, 0x02, 0x84, 0x00, 0x3E, 0x07, 0xF2, 0x00, + 0x2E, 0x07, 0xF2, 0x00, 0xEB, 0x7C, 0xE9, 0x0C, 0xFA, 0x00, 0x84, 0x20, 0xDD, 0x43, 0x84, 0x00, + 0x3E, 0x07, 0xF2, 0x00, 0x3E, 0x07, 0xF0, 0x5E, 0xEB, 0x15, 0x49, 0x00, 0x28, 0x1D, 0x5A, 0x68, + 0x01, 0x0B, 0x3C, 0x53, 0xF9, 0x01, 0xEB, 0x15, 0xD8, 0x06, 0xEB, 0x9F, 0x8C, 0x01, 0xEA, 0x58, + 0x84, 0x00, 0xD5, 0x09, 0xEB, 0x44, 0xEA, 0xCE, 0x84, 0x00, 0xE0, 0x41, 0xEA, 0x58, 0xE8, 0x03, + 0xEB, 0x5A, 0x8C, 0x01, 0xEA, 0xB5, 0xEA, 0x81, 0xE6, 0x04, 0xE9, 0x0E, 0xEB, 0x9F, 0xEB, 0x7C, + 0xE8, 0x04, 0xEB, 0x5A, 0xEB, 0x7C, 0xE9, 0x08, 0x84, 0x00, 0xEA, 0x58, 0xEA, 0xB5, 0x49, 0x00, + 0x26, 0xF0, 0x84, 0x05, 0xD5, 0x1E, 0xEA, 0x81, 0xE6, 0x04, 0xE8, 0x3F, 0xEB, 0x9F, 0x5C, 0xF0, + 0x01, 0x39, 0xE8, 0x05, 0xEB, 0x5A, 0x5C, 0xF0, 0x01, 0x39, 0xE9, 0x37, 0x84, 0x00, 0xEA, 0x58, + 0xEA, 0xB5, 0xC6, 0x31, 0x44, 0x00, 0x08, 0x00, 0x84, 0x21, 0xDD, 0x43, 0xD5, 0x2E, 0xEB, 0x73, + 0x5A, 0x08, 0x01, 0x0A, 0x84, 0x00, 0xEA, 0x58, 0xEA, 0xB5, 0x49, 0x00, 0x26, 0xE6, 0x84, 0x02, + 0xEA, 0x9B, 0xD5, 0x23, 0xEA, 0x61, 0x5A, 0x08, 0x01, 0x21, 0x5A, 0x68, 0x01, 0x07, 0xEB, 0x9F, + 0x8C, 0x01, 0xEA, 0x58, 0x84, 0x00, 0xD5, 0x09, 0xEB, 0x44, 0xEA, 0xCE, 0x84, 0x00, 0xE0, 0x41, + 0xEA, 0x58, 0xE8, 0x03, 0xEB, 0x5A, 0x8C, 0x01, 0xEA, 0xB5, 0x3C, 0x13, 0xF8, 0x2D, 0x2E, 0x07, + 0xD4, 0x1E, 0xE2, 0x20, 0xE8, 0x05, 0x3C, 0x13, 0xF8, 0x2C, 0xE2, 0x20, 0xE9, 0x06, 0x84, 0x00, + 0xEA, 0x58, 0xEA, 0xB5, 0x49, 0xFF, 0xFE, 0xDE, 0xEA, 0x61, 0x3E, 0x07, 0xF1, 0x38, 0x84, 0x01, + 0xDD, 0x4A, 0xC0, 0x0A, 0xEA, 0x61, 0x5A, 0x08, 0x01, 0x04, 0x84, 0x00, 0xD5, 0x02, 0x84, 0x01, + 0x3E, 0x07, 0xF1, 0x37, 0xD5, 0x04, 0x84, 0x02, 0x84, 0x21, 0xDD, 0x43, 0x84, 0x03, 0xDD, 0x4A, + 0xC0, 0x05, 0xEA, 0xEC, 0x84, 0x08, 0x84, 0x20, 0xDD, 0x43, 0x84, 0x02, 0xDD, 0x4A, 0xC0, 0x06, + 0x49, 0x00, 0x27, 0x7F, 0x84, 0x04, 0x84, 0x20, 0xDD, 0x43, 0x84, 0x0A, 0xDD, 0x4A, 0xC0, 0x0A, + 0x44, 0x00, 0x04, 0x00, 0x84, 0x20, 0xDD, 0x43, 0x44, 0x02, 0x1F, 0xB8, 0x9C, 0x43, 0x84, 0x43, + 0xDD, 0x55, 0x2E, 0x07, 0xF0, 0x5C, 0xFC, 0xA1, 0xFC, 0x01, 0xFA, 0x08, 0xEA, 0x8E, 0x50, 0x0F, + 0x80, 0x07, 0x49, 0xFF, 0xBF, 0xFE, 0x5A, 0x00, 0x01, 0x06, 0x2E, 0x07, 0xED, 0xC1, 0x5A, 0x08, + 0x01, 0x10, 0xEB, 0x0E, 0x49, 0x00, 0x31, 0x5D, 0x5A, 0x08, 0xFF, 0x05, 0x2E, 0x17, 0xED, 0xC1, + 0xC1, 0x07, 0x3E, 0x07, 0xED, 0x94, 0x84, 0x03, 0xEB, 0x19, 0x49, 0xFF, 0xBE, 0x2B, 0xFC, 0x81, + 0xFC, 0x00, 0xEA, 0x4B, 0x2E, 0x07, 0xF0, 0x65, 0x96, 0x46, 0xC1, 0x02, 0xC0, 0x0C, 0x84, 0x20, + 0x3E, 0x17, 0xF0, 0x64, 0xC0, 0x04, 0x8E, 0x01, 0x3E, 0x07, 0xF0, 0x65, 0x84, 0x00, 0x84, 0x21, + 0xEB, 0x07, 0xFC, 0x80, 0x2E, 0x17, 0xED, 0xC9, 0xC9, 0x08, 0x2E, 0x07, 0xF0, 0x64, 0x8C, 0x01, + 0x96, 0x00, 0x5C, 0xF0, 0x00, 0x65, 0xE8, 0x04, 0x3E, 0x07, 0xF0, 0x64, 0xFC, 0x80, 0x84, 0x05, + 0x3E, 0x17, 0xF0, 0x64, 0x3E, 0x07, 0xF0, 0x65, 0xFC, 0x80, 0xEA, 0xF8, 0x5A, 0x00, 0x01, 0x12, + 0xFC, 0x00, 0xEA, 0xF8, 0x5A, 0x08, 0x02, 0x05, 0x84, 0x03, 0x3E, 0x07, 0xEA, 0x4C, 0xEA, 0xF8, + 0x5A, 0x08, 0x04, 0x05, 0x84, 0x01, 0x3E, 0x07, 0xEA, 0x4C, 0x49, 0xFF, 0xD9, 0x5A, 0xFC, 0x80, + 0xDD, 0x9E, 0xFC, 0x00, 0xEA, 0x34, 0x80, 0xC0, 0xC8, 0x06, 0x49, 0xFF, 0xDE, 0xD7, 0x40, 0x03, + 0x00, 0x06, 0xFC, 0x80, 0x84, 0x01, 0xFC, 0x80, 0xFC, 0x00, 0x80, 0x60, 0xEA, 0xEE, 0x5A, 0x08, + 0x01, 0x70, 0x2E, 0x17, 0xEA, 0x52, 0x96, 0x48, 0x5A, 0x18, 0x01, 0x10, 0x84, 0x00, 0x3E, 0x07, + 0xEA, 0x52, 0x3C, 0x03, 0xF8, 0x66, 0x3C, 0x23, 0xF8, 0x64, 0x9A, 0x82, 0x90, 0x41, 0x96, 0x91, + 0xAC, 0x98, 0x3C, 0x28, 0x0D, 0xE1, 0xD5, 0x34, 0x3C, 0x13, 0xF8, 0x33, 0x3C, 0x03, 0xF8, 0x66, + 0x84, 0xC0, 0x8A, 0x01, 0x97, 0x41, 0x3C, 0x00, 0x0D, 0xEF, 0x44, 0x10, 0xAF, 0xFF, 0xE2, 0x20, + 0xE8, 0x03, 0x44, 0x60, 0xA0, 0x00, 0xEA, 0xA9, 0x84, 0x24, 0x02, 0x41, 0x00, 0x12, 0x02, 0x01, + 0x00, 0x0D, 0x8A, 0x86, 0x12, 0x41, 0x00, 0x13, 0x02, 0x41, 0x00, 0x09, 0x8E, 0x21, 0x8A, 0x86, + 0x96, 0x48, 0x12, 0x01, 0x00, 0x0E, 0x12, 0x41, 0x00, 0x09, 0x8E, 0x42, 0xC9, 0xEF, 0x3C, 0x00, + 0x0D, 0xEB, 0x3C, 0x58, 0x0D, 0xE6, 0x88, 0x05, 0x8A, 0x06, 0x3C, 0x08, 0x0D, 0xEB, 0x3C, 0x00, + 0x0D, 0xE1, 0x8A, 0x06, 0x3C, 0x08, 0x0D, 0xE1, 0xD5, 0x20, 0x3C, 0x58, 0x0D, 0xE1, 0x80, 0x01, + 0xD5, 0x34, 0x5A, 0x10, 0x05, 0xFC, 0x3C, 0x00, 0x0D, 0xE4, 0x3C, 0x08, 0x0D, 0xE5, 0x3C, 0x00, + 0x0D, 0xE3, 0x3C, 0x08, 0x0D, 0xE4, 0x3C, 0x00, 0x0D, 0xE2, 0x3C, 0x08, 0x0D, 0xE3, 0xEB, 0x3B, + 0x3C, 0x28, 0x0D, 0xE2, 0x88, 0x40, 0x3C, 0x00, 0x0D, 0xEC, 0x96, 0x91, 0x3C, 0x28, 0x0D, 0xE1, + 0x8A, 0x40, 0x38, 0x21, 0x85, 0x09, 0x8C, 0x21, 0x3C, 0x20, 0x0D, 0xE1, 0x3C, 0x43, 0xEC, 0x85, + 0x3C, 0x50, 0x0D, 0xEB, 0x88, 0x82, 0xE2, 0x85, 0x96, 0x08, 0xE9, 0xDC, 0xD5, 0x0E, 0x2E, 0x17, + 0xF0, 0xD0, 0x84, 0x00, 0x96, 0x48, 0xC9, 0x09, 0x44, 0x02, 0x50, 0x3A, 0xFA, 0x4E, 0xDD, 0x40, + 0x84, 0x01, 0x3E, 0x07, 0xEA, 0x52, 0x84, 0x02, 0x3C, 0x13, 0xF8, 0x66, 0x3C, 0x1B, 0xF8, 0x33, + 0xFC, 0x80, 0xFC, 0x40, 0x44, 0x40, 0x01, 0x0C, 0xEA, 0x94, 0x42, 0x10, 0x10, 0x73, 0x50, 0x90, + 0x80, 0xE0, 0x00, 0xA4, 0x80, 0x0B, 0x3C, 0x50, 0x0D, 0xE6, 0xE7, 0x42, 0x22, 0x00, 0x80, 0x1D, + 0x22, 0x40, 0x80, 0x1E, 0x22, 0x70, 0x80, 0x27, 0x22, 0x60, 0x80, 0x28, 0xE9, 0x21, 0x02, 0xA4, + 0x80, 0x02, 0x5A, 0xA0, 0x01, 0x06, 0x02, 0x94, 0x80, 0x03, 0x5A, 0x98, 0x01, 0x05, 0xAC, 0x12, + 0xAD, 0x13, 0xD5, 0x16, 0xE7, 0x22, 0xE8, 0x05, 0x00, 0x10, 0x81, 0x36, 0x5A, 0x18, 0x01, 0x11, + 0xE2, 0xA3, 0x40, 0x32, 0xBC, 0x1B, 0x8A, 0x07, 0x8A, 0x86, 0xFE, 0x1C, 0xFE, 0xE4, 0x40, 0x00, + 0x14, 0x16, 0x40, 0x31, 0x94, 0x76, 0x88, 0x07, 0x88, 0x66, 0xAC, 0x12, 0xAC, 0xD3, 0xA4, 0x52, + 0x80, 0x01, 0x96, 0x4B, 0x5E, 0xF0, 0x9A, 0x75, 0xE9, 0x03, 0x44, 0x00, 0x1A, 0x74, 0x96, 0x43, + 0x4E, 0x14, 0x00, 0x03, 0x84, 0x00, 0xA4, 0x53, 0xAC, 0x12, 0x80, 0x01, 0x96, 0x4B, 0x5E, 0xF0, + 0xBA, 0xCA, 0xE9, 0x03, 0x44, 0x00, 0x3A, 0xC9, 0x96, 0x43, 0x4E, 0x14, 0x00, 0x03, 0x84, 0x00, + 0xAC, 0x13, 0xFC, 0xC0, 0x00, 0x10, 0x00, 0xFD, 0x5A, 0x18, 0x01, 0x0A, 0x04, 0x10, 0x00, 0x3F, + 0x40, 0x00, 0x90, 0x09, 0xFE, 0x0D, 0x96, 0x1F, 0xEA, 0xD8, 0xDD, 0x9E, 0x84, 0x01, 0xDD, 0x9E, + 0xFC, 0x20, 0x04, 0x60, 0x00, 0x3F, 0x80, 0xE0, 0x92, 0xC4, 0x97, 0x9F, 0x50, 0x03, 0x00, 0x0D, + 0x94, 0x03, 0x88, 0x07, 0x8C, 0x04, 0x84, 0x48, 0xDD, 0x55, 0x8C, 0xC1, 0x84, 0x26, 0x40, 0x03, + 0x04, 0xD6, 0x04, 0x03, 0x80, 0x3F, 0x97, 0x70, 0x96, 0x1F, 0xD8, 0x0D, 0x8C, 0xA1, 0x40, 0x52, + 0x84, 0x36, 0x54, 0x50, 0x80, 0x0F, 0x00, 0x13, 0x80, 0xFC, 0x54, 0x10, 0x80, 0xF0, 0xFE, 0x6F, + 0x10, 0x13, 0x80, 0xFC, 0x00, 0x03, 0x80, 0xFC, 0x95, 0xB4, 0x96, 0x1F, 0xFF, 0x87, 0x84, 0x01, + 0x10, 0x63, 0x80, 0xFC, 0x10, 0x03, 0x80, 0xFD, 0xFC, 0xA0, 0xFC, 0x42, 0x3A, 0x0F, 0x84, 0x20, + 0x80, 0xE0, 0x2E, 0x07, 0xD2, 0x99, 0x80, 0xC1, 0xC0, 0x02, 0x9B, 0xD7, 0x2E, 0x07, 0xD2, 0x9A, + 0xC0, 0x02, 0x9B, 0x9E, 0x2E, 0x07, 0xD2, 0x9B, 0xC0, 0x0B, 0x40, 0x93, 0x00, 0x13, 0x96, 0x11, + 0x96, 0x61, 0x80, 0xC7, 0x80, 0x85, 0x80, 0x43, 0x80, 0xE9, 0x80, 0xA1, 0x80, 0x60, 0x42, 0x03, + 0x90, 0x24, 0x42, 0x13, 0x14, 0x24, 0x40, 0x00, 0x08, 0x17, 0x40, 0x10, 0x8C, 0x37, 0xFC, 0xC2, + 0xFC, 0x46, 0x51, 0xCF, 0x80, 0x50, 0xEA, 0x34, 0x14, 0x0E, 0x7F, 0xEF, 0x84, 0x20, 0x84, 0x4A, + 0x50, 0x0E, 0x7F, 0xD4, 0xDD, 0x40, 0x50, 0x0E, 0x7F, 0xD4, 0x49, 0xFF, 0xFE, 0xBF, 0x50, 0x1E, + 0x7F, 0xB8, 0x14, 0x0E, 0x7F, 0xEE, 0xB4, 0x01, 0x85, 0x40, 0x94, 0x03, 0x50, 0x10, 0x00, 0x08, + 0x41, 0xFF, 0x84, 0x01, 0x88, 0x1F, 0x15, 0xFE, 0x7F, 0xF0, 0x44, 0x62, 0x50, 0x5C, 0x44, 0x72, + 0x24, 0xE4, 0x14, 0x0E, 0x7F, 0xEC, 0x81, 0x0A, 0x54, 0x05, 0x00, 0xFF, 0x14, 0x0E, 0x7F, 0xED, + 0xDD, 0x5A, 0x9E, 0x42, 0xE6, 0x22, 0x4E, 0xF2, 0x00, 0xCD, 0x00, 0x13, 0x01, 0x07, 0x4E, 0x13, + 0x00, 0xC9, 0xEA, 0x9D, 0x44, 0x12, 0x51, 0x50, 0x42, 0x15, 0x08, 0x73, 0xA4, 0x4D, 0x2E, 0x27, + 0xF0, 0x08, 0x96, 0x5F, 0xE0, 0x41, 0xE8, 0x06, 0x5A, 0x08, 0x03, 0x05, 0x84, 0x21, 0x10, 0x13, + 0x01, 0x07, 0x04, 0x1E, 0x7F, 0xEF, 0xC9, 0x0F, 0x00, 0x13, 0x01, 0x04, 0x5A, 0x10, 0x01, 0x0E, + 0x5A, 0x08, 0x03, 0x08, 0x04, 0x0E, 0x7F, 0xED, 0xEA, 0x54, 0xEB, 0x1C, 0xE2, 0x20, 0xE9, 0x05, + 0x4E, 0x82, 0x00, 0x42, 0x5A, 0x88, 0x01, 0x10, 0x22, 0x53, 0x00, 0x07, 0x04, 0x03, 0x00, 0x2A, + 0xD8, 0x09, 0x22, 0x53, 0x00, 0x08, 0x04, 0x03, 0x00, 0x2B, 0xD8, 0x04, 0x84, 0x01, 0x10, 0x03, + 0x01, 0x05, 0x85, 0x01, 0xEB, 0x34, 0xEA, 0xD6, 0xB4, 0x46, 0x50, 0x9E, 0x7F, 0xCC, 0xEB, 0x1D, + 0xEA, 0xF3, 0x44, 0x40, 0x08, 0x00, 0xAC, 0x7A, 0xAC, 0x3B, 0xB6, 0x47, 0x3A, 0x04, 0x84, 0x00, + 0x44, 0x20, 0x1A, 0x74, 0x44, 0x30, 0x3A, 0xC9, 0x80, 0xA4, 0xEB, 0xD3, 0x5E, 0xF0, 0x88, 0x00, + 0x14, 0x0E, 0x7F, 0xF3, 0x14, 0x14, 0x80, 0x01, 0xE9, 0x04, 0x44, 0x10, 0x07, 0xFF, 0xD5, 0x04, + 0x4E, 0x14, 0x00, 0x03, 0x84, 0x20, 0xEB, 0x50, 0x5E, 0xF0, 0x08, 0x00, 0xE9, 0x04, 0x44, 0x00, + 0x07, 0xFF, 0xD5, 0x04, 0x4E, 0x04, 0x00, 0x03, 0x84, 0x00, 0xAC, 0x3A, 0xAC, 0x7B, 0xFD, 0x03, + 0x49, 0xFF, 0xFF, 0x20, 0xEB, 0x8F, 0xC8, 0x08, 0xDD, 0x5A, 0x5A, 0x00, 0x03, 0x06, 0x04, 0x0E, + 0x7F, 0xEF, 0xC0, 0x51, 0xD5, 0x5E, 0x84, 0x00, 0x04, 0x9E, 0x7F, 0xF0, 0xEB, 0x21, 0x00, 0x0E, + 0x7F, 0xC4, 0x04, 0x1E, 0x7F, 0xEE, 0xE2, 0x01, 0xE8, 0xF3, 0x04, 0x3E, 0x7F, 0xF1, 0x50, 0x4E, + 0x7F, 0xD4, 0x04, 0x0E, 0x7F, 0xED, 0x38, 0x32, 0x0D, 0x01, 0x84, 0x22, 0x80, 0x49, 0x49, 0xFF, + 0xFE, 0xA2, 0xB4, 0x26, 0xA0, 0x35, 0x44, 0x40, 0x08, 0x00, 0x88, 0x01, 0x84, 0x22, 0xDD, 0x5C, + 0xB6, 0x09, 0x22, 0x04, 0x80, 0x03, 0x22, 0x14, 0x80, 0x02, 0xEA, 0xF3, 0x50, 0x0E, 0x7F, 0xCC, + 0xEB, 0x1D, 0x3A, 0x00, 0x04, 0x00, 0x44, 0x20, 0x1A, 0x74, 0x44, 0x30, 0x3A, 0xC9, 0x80, 0xA4, + 0xEB, 0xD3, 0x5E, 0xF0, 0x08, 0x00, 0x14, 0x0E, 0x7F, 0xF3, 0x14, 0x1E, 0x7F, 0xF4, 0xE9, 0x04, + 0x44, 0x00, 0x07, 0xFF, 0xD5, 0x04, 0x4E, 0x04, 0x00, 0x03, 0x84, 0x00, 0xEB, 0xE5, 0x5E, 0xF0, + 0x88, 0x00, 0xE9, 0x04, 0x44, 0x10, 0x07, 0xFF, 0xD5, 0x04, 0x4E, 0x14, 0x00, 0x03, 0x84, 0x20, + 0x12, 0x04, 0x80, 0x02, 0x04, 0x0E, 0x7F, 0xF1, 0x12, 0x14, 0x80, 0x03, 0x8C, 0x01, 0xEB, 0x21, + 0x8D, 0x28, 0xD5, 0xB6, 0x4E, 0x83, 0x00, 0x0E, 0x04, 0x9E, 0x7F, 0xF0, 0x04, 0x0E, 0x7F, 0xEC, + 0x4C, 0x90, 0x00, 0x08, 0x80, 0x29, 0x80, 0x06, 0x49, 0xFF, 0xFE, 0xBC, 0x8D, 0x28, 0xD5, 0xF7, + 0x8D, 0x41, 0xEB, 0x49, 0x8C, 0xE8, 0x5A, 0xA0, 0x0A, 0x04, 0x48, 0xFF, 0xFF, 0x27, 0xEB, 0x86, + 0xFC, 0xC0, 0xFC, 0x01, 0x84, 0x00, 0x49, 0x00, 0x2C, 0xFC, 0x84, 0x00, 0x49, 0x00, 0x2E, 0x05, + 0xF0, 0x81, 0x84, 0x27, 0x84, 0x00, 0x49, 0x00, 0x2E, 0xBB, 0xF0, 0x01, 0xFC, 0x81, 0xFC, 0x20, + 0xEA, 0x34, 0x80, 0xE0, 0xC8, 0x08, 0x49, 0xFF, 0xFF, 0xEE, 0x80, 0xC0, 0xC0, 0x08, 0x3E, 0x77, + 0xF0, 0x68, 0xD5, 0x05, 0x84, 0x00, 0xEB, 0xFD, 0x84, 0x00, 0xFC, 0xA0, 0xEB, 0xDE, 0x5A, 0x08, + 0x01, 0x04, 0x49, 0x00, 0x29, 0x07, 0x84, 0x00, 0x49, 0x00, 0x29, 0x53, 0xEA, 0xC4, 0xCE, 0x06, + 0x84, 0x01, 0x3E, 0x67, 0xF0, 0xD0, 0x3E, 0x07, 0xF0, 0x68, 0x84, 0x01, 0xFC, 0xA0, 0xFC, 0x20, + 0x80, 0xE0, 0xC0, 0x0C, 0x5A, 0x08, 0x01, 0x04, 0xEA, 0x2F, 0xD5, 0x06, 0x84, 0xC0, 0x5A, 0x08, + 0x02, 0x07, 0x49, 0x00, 0x32, 0xFC, 0x80, 0xC0, 0xD5, 0x02, 0x80, 0xC0, 0x84, 0x02, 0x49, 0x00, + 0x2C, 0xC0, 0x84, 0x02, 0x49, 0x00, 0x2D, 0xC9, 0xC6, 0x09, 0x80, 0x06, 0x5A, 0x78, 0x02, 0x05, + 0x49, 0x00, 0x2E, 0x48, 0xD5, 0x03, 0x49, 0x00, 0x2E, 0x33, 0x49, 0x00, 0x32, 0xED, 0x49, 0x00, + 0x2E, 0x64, 0x84, 0x02, 0x84, 0x27, 0x49, 0x00, 0x2E, 0x73, 0xFC, 0xA0, 0xFC, 0x21, 0xF0, 0x81, + 0xEA, 0x34, 0x80, 0xC0, 0xC8, 0x05, 0x49, 0xFF, 0xFF, 0xA6, 0x80, 0xE0, 0xD5, 0x09, 0x5A, 0x00, + 0x01, 0x0D, 0x49, 0x00, 0x2C, 0x9B, 0xF1, 0x01, 0x49, 0xFF, 0xFF, 0xCB, 0x84, 0xE1, 0x80, 0x06, + 0x49, 0x00, 0x29, 0x0F, 0xC7, 0x02, 0xEA, 0xC4, 0xFC, 0xA1, 0xFC, 0x00, 0x49, 0x00, 0x2E, 0x81, + 0xDD, 0x46, 0x92, 0x0D, 0x96, 0x06, 0x49, 0x00, 0x29, 0x0C, 0xEA, 0xC4, 0xFC, 0x80, 0xFC, 0x00, + 0x84, 0x20, 0x80, 0xC0, 0xEB, 0xD4, 0x5A, 0x60, 0x01, 0x08, 0x5A, 0x68, 0x03, 0x0E, 0xD5, 0x04, + 0xEA, 0x34, 0x5A, 0x08, 0x02, 0x08, 0x80, 0x06, 0x84, 0x21, 0xEB, 0xD4, 0x5A, 0x00, 0x01, 0xFA, + 0xD5, 0x03, 0x5A, 0x68, 0x01, 0xFA, 0xFC, 0x80, 0xFC, 0x00, 0x84, 0x21, 0xEB, 0xD4, 0xEA, 0xD8, + 0xFC, 0x80, 0xFC, 0x00, 0xDD, 0x41, 0x5A, 0x08, 0x01, 0x06, 0x84, 0x00, 0x3C, 0x13, 0xEA, 0x11, + 0xD5, 0x04, 0x84, 0x00, 0x3C, 0x13, 0xEA, 0x10, 0xEA, 0x31, 0x84, 0x00, 0x84, 0x21, 0xDD, 0x47, + 0xFC, 0x80, 0xFC, 0x00, 0x2E, 0x07, 0xF0, 0xC0, 0x5A, 0x08, 0x01, 0x04, 0x84, 0x00, 0xEA, 0x7A, + 0x84, 0x00, 0xEA, 0x32, 0x5A, 0x00, 0x01, 0x10, 0xDD, 0x46, 0x92, 0x0C, 0x96, 0x06, 0x3E, 0x07, + 0xF0, 0xBE, 0xDD, 0x46, 0xEA, 0xDF, 0xC8, 0x03, 0x84, 0x00, 0xFC, 0x80, 0xDD, 0x41, 0x5A, 0x08, + 0x01, 0xFD, 0xEB, 0x45, 0xFC, 0x80, 0xFC, 0x00, 0x49, 0x00, 0x37, 0x2F, 0x49, 0x00, 0x3B, 0x6C, + 0x49, 0x00, 0x37, 0x32, 0x49, 0x00, 0x37, 0x71, 0x49, 0x00, 0x37, 0x86, 0x49, 0x00, 0x37, 0xDC, + 0x49, 0x00, 0x24, 0x36, 0x49, 0x00, 0x37, 0xB4, 0x49, 0x00, 0x38, 0x1B, 0x49, 0x00, 0x36, 0x49, + 0x49, 0x00, 0x26, 0x6C, 0x49, 0x00, 0x26, 0x86, 0x49, 0x00, 0x36, 0xCE, 0xFC, 0x80, 0xEA, 0x2C, + 0xDD, 0x9E, 0xFC, 0x00, 0x49, 0x00, 0x0C, 0xD3, 0xC0, 0x03, 0x84, 0x0A, 0xD5, 0x08, 0x49, 0x00, + 0x0C, 0xD4, 0xC8, 0xFC, 0x2E, 0x07, 0xF0, 0xBC, 0xC0, 0x04, 0x8E, 0x01, 0x3E, 0x07, 0xF0, 0xBC, + 0x2E, 0x07, 0xF0, 0xBC, 0xC0, 0x04, 0xE6, 0x0B, 0xE8, 0x04, 0x84, 0x01, 0x3E, 0x07, 0xF0, 0xD6, + 0xFC, 0x80, 0xFC, 0x00, 0x49, 0xFF, 0xFF, 0xE7, 0xDD, 0x4F, 0xEB, 0x2C, 0xFE, 0x0E, 0xC0, 0x04, + 0x49, 0xFF, 0xFA, 0x82, 0xD5, 0x0F, 0x84, 0x06, 0xDD, 0x4A, 0xC8, 0x04, 0x49, 0x00, 0x21, 0x22, + 0xD5, 0x05, 0xEA, 0x4B, 0x84, 0x01, 0xFE, 0x46, 0xDD, 0x43, 0x49, 0xFF, 0xFB, 0x3B, 0x3E, 0x07, + 0xF0, 0xC1, 0xEA, 0x81, 0x3E, 0x07, 0xF1, 0x40, 0xEA, 0x81, 0x44, 0x12, 0x1E, 0x7C, 0x38, 0x00, + 0x81, 0x01, 0x3C, 0x0B, 0xF8, 0x9F, 0x84, 0x00, 0x3E, 0x07, 0xED, 0xA5, 0xEA, 0x61, 0x5A, 0x08, + 0x01, 0x09, 0x3C, 0xF7, 0xF8, 0x9D, 0x5E, 0xF7, 0x80, 0x65, 0xE8, 0x03, 0x3E, 0x07, 0xED, 0xA5, + 0xFC, 0x80, 0xFC, 0x40, 0xEA, 0x2F, 0x2E, 0x17, 0xF0, 0xD7, 0x96, 0x48, 0x5A, 0x10, 0x01, 0x11, + 0xC1, 0x06, 0x5A, 0x18, 0x03, 0x04, 0x48, 0x00, 0x00, 0x81, 0xFC, 0xC0, 0x84, 0x00, 0x3E, 0x07, + 0xF9, 0x08, 0x84, 0x20, 0xEB, 0x51, 0x44, 0x02, 0x32, 0x94, 0xDD, 0x40, 0xFC, 0xC0, 0x84, 0x20, + 0x3E, 0x17, 0xF9, 0x08, 0x44, 0x22, 0x32, 0x94, 0x84, 0x20, 0x38, 0x30, 0x05, 0x11, 0x38, 0x31, + 0x05, 0x09, 0x8C, 0x21, 0x5A, 0x1A, 0x88, 0xFB, 0x84, 0xA0, 0xEA, 0x94, 0x44, 0x00, 0x0B, 0x84, + 0x98, 0xA9, 0x02, 0x61, 0x00, 0x73, 0x5A, 0x68, 0x01, 0x0E, 0x44, 0x02, 0x2D, 0x84, 0x44, 0x12, + 0x32, 0x94, 0xEB, 0x51, 0xDD, 0x55, 0x84, 0x00, 0x3E, 0x07, 0xF9, 0x07, 0x3E, 0x67, 0xF9, 0x06, + 0xD5, 0x03, 0xEB, 0x7A, 0xD8, 0xEE, 0xEB, 0x48, 0x2E, 0x97, 0xEA, 0x4F, 0x94, 0x02, 0x2E, 0x6F, + 0xEE, 0x19, 0x97, 0xC2, 0x5A, 0x98, 0xFF, 0x14, 0xEA, 0xDD, 0x5A, 0x00, 0x01, 0x05, 0xDD, 0x46, + 0x92, 0x03, 0x96, 0x06, 0x2E, 0x17, 0xF0, 0x13, 0x94, 0x05, 0x94, 0x4E, 0xFF, 0xCF, 0xFF, 0xBF, + 0xFE, 0x37, 0x96, 0x00, 0xEB, 0xCF, 0x3E, 0x07, 0xF9, 0x05, 0xFC, 0xC0, 0xEA, 0xDD, 0x5A, 0x00, + 0x01, 0x05, 0xDD, 0x46, 0x92, 0x03, 0x96, 0x06, 0x2E, 0x17, 0xF0, 0x13, 0x94, 0x05, 0x94, 0x4E, + 0xFF, 0xCF, 0xFF, 0xBF, 0xFE, 0x37, 0x96, 0x00, 0x4C, 0x90, 0x00, 0x37, 0x44, 0x02, 0x2D, 0x84, + 0x44, 0x12, 0x32, 0x94, 0xEB, 0x51, 0xDD, 0x55, 0x2E, 0x67, 0xE9, 0xB8, 0x2E, 0x07, 0xF9, 0x08, + 0x95, 0xB2, 0x3E, 0x07, 0xF9, 0x07, 0x2E, 0x7F, 0xEE, 0x19, 0x97, 0xB2, 0xEA, 0xDD, 0x5A, 0x00, + 0x01, 0x05, 0xDD, 0x46, 0x92, 0x03, 0x96, 0x06, 0x2E, 0x27, 0xF0, 0x13, 0x94, 0x05, 0x94, 0x96, + 0x40, 0x13, 0x08, 0x04, 0xFE, 0x7F, 0xFE, 0x0F, 0x96, 0x00, 0xEB, 0xCF, 0x3E, 0x07, 0xF9, 0x05, + 0x84, 0x02, 0x3E, 0x07, 0xF9, 0x06, 0xFC, 0xC0, 0x84, 0x00, 0x3E, 0x07, 0xF9, 0x08, 0x3E, 0x07, + 0xF9, 0x06, 0x84, 0x1F, 0xEB, 0xCF, 0x84, 0x20, 0x44, 0x02, 0x32, 0x94, 0xEB, 0x51, 0xDD, 0x40, + 0x84, 0x01, 0x3E, 0x07, 0xF0, 0xD7, 0xFC, 0xC0, 0xFC, 0x00, 0x84, 0x00, 0x3E, 0x07, 0xF0, 0xC0, + 0xDD, 0x41, 0xC8, 0x1B, 0x49, 0xFF, 0xFF, 0x5F, 0x49, 0x00, 0x0B, 0xE9, 0xC0, 0x05, 0x84, 0x0A, + 0x3E, 0x07, 0xF0, 0xC5, 0xD5, 0x04, 0x49, 0x00, 0x0B, 0xE8, 0xC8, 0xFA, 0x49, 0xFF, 0xD7, 0x46, + 0x2E, 0x07, 0xF0, 0xC5, 0xC0, 0x04, 0x8E, 0x01, 0x3E, 0x07, 0xF0, 0xC5, 0xEA, 0x8C, 0xC0, 0x13, + 0x84, 0x01, 0x3E, 0x07, 0xF0, 0xC0, 0xD5, 0x0F, 0x49, 0xFF, 0xD7, 0x38, 0x49, 0xFF, 0xFB, 0x8E, + 0x49, 0xFF, 0xFB, 0xA8, 0x3C, 0xF7, 0xF8, 0x07, 0x5E, 0xF7, 0x81, 0x5E, 0xE9, 0x04, 0xDD, 0x46, + 0xEA, 0xDF, 0xC0, 0xEF, 0x84, 0x00, 0x3E, 0x00, 0x12, 0xDA, 0x3E, 0x07, 0xF0, 0x12, 0xFC, 0x80, + 0xFC, 0x21, 0xDD, 0x41, 0xC0, 0x05, 0xEA, 0x34, 0x5A, 0x08, 0x02, 0x09, 0xD5, 0x18, 0x84, 0x09, + 0xDD, 0x4A, 0xC8, 0x15, 0xEA, 0x26, 0xC8, 0x13, 0xD5, 0xF7, 0x2E, 0x07, 0xF1, 0x3C, 0x5A, 0x00, + 0x01, 0x0F, 0x2E, 0x77, 0xF2, 0x17, 0x97, 0xF8, 0xCF, 0x0A, 0x2E, 0x67, 0xF0, 0xD3, 0xC6, 0x0D, + 0x5A, 0x68, 0x01, 0x2E, 0x2E, 0x07, 0xF0, 0xC0, 0x5A, 0x08, 0x01, 0x1E, 0xEB, 0xF8, 0x84, 0x00, + 0x3E, 0x07, 0xF0, 0xD3, 0x84, 0x00, 0xFC, 0xA1, 0x49, 0xFF, 0xFE, 0x8D, 0x80, 0xE0, 0x5A, 0x08, + 0x01, 0x11, 0x49, 0x00, 0x34, 0x37, 0x49, 0x00, 0x1B, 0x7F, 0xEB, 0x77, 0x3E, 0x77, 0xF0, 0xD3, + 0x96, 0x00, 0x3E, 0x60, 0x14, 0x90, 0x5A, 0x08, 0x01, 0x13, 0x3E, 0x60, 0x12, 0xDB, 0xFC, 0xA1, + 0x80, 0x06, 0xFC, 0xA1, 0xDD, 0x46, 0x2E, 0x57, 0xF0, 0xBE, 0x92, 0x0C, 0x96, 0x06, 0xD8, 0xDF, + 0x49, 0x00, 0x1B, 0x6E, 0x49, 0x00, 0x1B, 0x79, 0x5A, 0x00, 0x01, 0x04, 0x84, 0x01, 0xFC, 0xA1, + 0x49, 0x00, 0x38, 0x4C, 0x5A, 0x08, 0x01, 0xFC, 0xF0, 0x81, 0xEB, 0xF8, 0x3E, 0x77, 0xF0, 0xD3, + 0xF0, 0x01, 0xFC, 0xA1, 0xFC, 0x00, 0x49, 0x00, 0x1F, 0x4E, 0xDD, 0x41, 0xC8, 0x16, 0x49, 0xFF, + 0xFB, 0x7A, 0x80, 0xC0, 0x5A, 0x08, 0x01, 0x0D, 0x49, 0xFF, 0xFC, 0xB4, 0xEA, 0x34, 0xC8, 0x05, + 0xEA, 0xEE, 0xC8, 0x0B, 0x84, 0x02, 0xD5, 0x02, 0x80, 0x06, 0xEB, 0x19, 0xFC, 0x80, 0xEA, 0xEE, + 0x5A, 0x08, 0x01, 0x04, 0x49, 0xFF, 0xFC, 0xA6, 0xFC, 0x80, 0x2E, 0x07, 0xF0, 0xC1, 0x5A, 0x08, + 0x02, 0x06, 0x84, 0x01, 0xEA, 0x3F, 0x84, 0x01, 0xDD, 0x9E, 0x5A, 0x08, 0x01, 0x06, 0x84, 0x22, + 0x3E, 0x17, 0xF0, 0xD4, 0xDD, 0x9E, 0x84, 0x00, 0xDD, 0x9E, 0xFC, 0x01, 0x2E, 0x67, 0xF0, 0xD9, + 0x97, 0xB0, 0xC6, 0x1E, 0xDD, 0x41, 0x80, 0xC0, 0xC8, 0x17, 0xDD, 0x49, 0x4E, 0x02, 0x00, 0xD6, + 0x49, 0x00, 0x24, 0xC8, 0x4E, 0x02, 0x00, 0xD2, 0x80, 0x06, 0xEA, 0x7A, 0x80, 0x06, 0x84, 0x21, + 0xDD, 0x47, 0x49, 0x00, 0x24, 0xCF, 0xEA, 0x38, 0x84, 0x01, 0xDD, 0x45, 0x84, 0x01, 0x3E, 0x67, + 0xF0, 0xD9, 0xEA, 0x3F, 0xFC, 0x81, 0x84, 0x00, 0x3E, 0x07, 0xF0, 0xD9, 0xFC, 0x81, 0xEA, 0x9E, + 0x3E, 0x67, 0xF0, 0xC4, 0x5A, 0x08, 0x01, 0x0C, 0xDD, 0x49, 0xC0, 0x09, 0xEA, 0x2C, 0x5A, 0x08, + 0x02, 0x07, 0x3E, 0x67, 0xF0, 0xDA, 0x3E, 0x67, 0xF0, 0xC3, 0xD5, 0x06, 0xEA, 0x9E, 0x5A, 0x08, + 0x01, 0x04, 0x48, 0x00, 0x00, 0xAB, 0xEA, 0x9E, 0xC8, 0x3F, 0xDD, 0x41, 0xC8, 0x03, 0x84, 0x01, + 0xEB, 0x90, 0xDD, 0x41, 0xC8, 0x17, 0xDD, 0x49, 0x4E, 0x02, 0x00, 0xA0, 0x84, 0x0A, 0xEA, 0xB4, + 0xEA, 0x3B, 0x5A, 0x08, 0x1C, 0x08, 0x2E, 0x07, 0xF0, 0xD5, 0xC8, 0x04, 0x84, 0x01, 0x3E, 0x07, + 0xF0, 0xD5, 0x49, 0x00, 0x24, 0x87, 0x4E, 0x02, 0x00, 0x91, 0x49, 0x00, 0x35, 0x32, 0x49, 0x00, + 0x24, 0x91, 0x49, 0xFF, 0xF9, 0x3E, 0x49, 0x00, 0x1B, 0xFB, 0x49, 0x00, 0x31, 0x8F, 0x84, 0x01, + 0x3E, 0x07, 0xEA, 0x51, 0xEA, 0x26, 0x5A, 0x08, 0x01, 0x05, 0x2E, 0x07, 0xD8, 0xEA, 0xEA, 0x30, + 0xEA, 0x26, 0xEA, 0x20, 0xEA, 0x38, 0xDD, 0x41, 0xC8, 0x03, 0x49, 0x00, 0x15, 0x7B, 0xEA, 0x26, + 0xB6, 0x1F, 0xEA, 0x3A, 0xF0, 0x81, 0x84, 0x20, 0xB4, 0x1F, 0xF2, 0x01, 0xDD, 0x5B, 0xDD, 0x41, + 0xC8, 0x03, 0x84, 0x01, 0xDD, 0x45, 0xDD, 0x41, 0xC8, 0x09, 0x49, 0x00, 0x32, 0x3B, 0xEA, 0x9E, + 0x5A, 0x08, 0x01, 0x1D, 0x84, 0x00, 0xDD, 0x45, 0xFC, 0x81, 0xEA, 0x48, 0x96, 0x16, 0xC0, 0x0C, + 0x3C, 0x13, 0xEC, 0x8D, 0x84, 0x03, 0xFE, 0x0C, 0x84, 0x41, 0x96, 0x01, 0x84, 0x20, 0x80, 0x62, + 0xEA, 0x6D, 0x49, 0x00, 0x32, 0x27, 0xEA, 0x48, 0x84, 0x41, 0x54, 0x00, 0x00, 0xFB, 0xEA, 0xFB, + 0x84, 0x20, 0x3C, 0x03, 0xEC, 0x8D, 0x80, 0x62, 0xEA, 0x6D, 0xDD, 0x41, 0xC8, 0x0F, 0x44, 0x10, + 0x00, 0x69, 0x84, 0x41, 0x84, 0x05, 0xEB, 0x13, 0x80, 0x20, 0x3E, 0x07, 0xF0, 0xE6, 0x84, 0x01, + 0x49, 0x00, 0x35, 0x72, 0x84, 0x01, 0x84, 0x22, 0xEA, 0xAB, 0x84, 0xC0, 0x49, 0xFF, 0xF8, 0x4E, + 0x49, 0x00, 0x0A, 0x59, 0x3E, 0x67, 0xEA, 0x51, 0x3E, 0x67, 0xF2, 0x09, 0x49, 0x00, 0x33, 0xC8, + 0xEA, 0x9E, 0x5A, 0x00, 0x01, 0xC9, 0x3E, 0x67, 0xF0, 0xC3, 0x49, 0xFF, 0xD3, 0x9E, 0xEB, 0xF8, + 0x84, 0x01, 0xEA, 0x3F, 0x3E, 0x07, 0xF0, 0xC4, 0xEA, 0xB0, 0xE6, 0x05, 0xE9, 0x1C, 0x44, 0x27, + 0x20, 0xC0, 0xEB, 0x74, 0xB4, 0x22, 0xFE, 0x46, 0xB6, 0x22, 0x44, 0x27, 0x21, 0x00, 0xB4, 0x22, + 0xFE, 0x46, 0xB6, 0x22, 0x44, 0x17, 0x21, 0x40, 0xB4, 0x41, 0xFE, 0x16, 0x44, 0x27, 0x20, 0x94, + 0xB6, 0x01, 0xB4, 0x02, 0x96, 0x00, 0x58, 0x10, 0x00, 0x01, 0xB4, 0x02, 0x92, 0x08, 0xDD, 0x52, + 0xFE, 0x0F, 0xB6, 0x02, 0x49, 0x00, 0x03, 0x35, 0xFC, 0x81, 0xFC, 0x00, 0x84, 0x01, 0x49, 0x00, + 0x0C, 0x83, 0x49, 0x00, 0x2B, 0x79, 0xFC, 0x80, 0xFC, 0x00, 0x49, 0x00, 0x30, 0x7B, 0x49, 0x00, + 0x30, 0x82, 0xC0, 0x03, 0x84, 0x02, 0xEA, 0x3F, 0xFC, 0x80, 0xFC, 0x00, 0x49, 0x00, 0x30, 0x8F, + 0x4E, 0x02, 0x00, 0x73, 0xDD, 0x50, 0xC0, 0x05, 0xEA, 0x2C, 0x5A, 0x08, 0x02, 0x05, 0xFC, 0x80, + 0xDD, 0x49, 0xC0, 0xFB, 0xDD, 0x51, 0x5A, 0x00, 0x01, 0x68, 0x49, 0xFF, 0xFA, 0x40, 0xEA, 0xF8, + 0x5A, 0x08, 0x03, 0x06, 0x49, 0x00, 0x2F, 0xFC, 0x84, 0x01, 0xD5, 0x5D, 0xEA, 0xB8, 0x84, 0x20, + 0xDD, 0x43, 0xEA, 0x7F, 0x96, 0x0E, 0xC0, 0x11, 0xFA, 0x10, 0x84, 0x20, 0xDD, 0x43, 0xEA, 0xB8, + 0x84, 0x21, 0xDD, 0x43, 0x49, 0x00, 0x1E, 0x9E, 0x84, 0x02, 0xDD, 0x4A, 0xC0, 0x06, 0x49, 0x00, + 0x21, 0x50, 0x84, 0x04, 0x84, 0x20, 0xDD, 0x43, 0x49, 0x00, 0x2F, 0x8D, 0x3C, 0x03, 0xF8, 0x08, + 0x8C, 0x01, 0x3C, 0x0B, 0xF8, 0x08, 0x2E, 0x07, 0xF0, 0x12, 0x8C, 0x01, 0x3E, 0x07, 0xF0, 0x12, + 0x2E, 0x07, 0xF1, 0x3C, 0xC8, 0x1C, 0xEA, 0xDD, 0x5A, 0x00, 0x01, 0x05, 0xDD, 0x46, 0x96, 0x1E, + 0xC0, 0x16, 0x3C, 0x3D, 0xFB, 0x5B, 0x84, 0x0A, 0x3E, 0x07, 0xEC, 0x11, 0x84, 0x17, 0xFE, 0x1E, + 0x84, 0x40, 0x84, 0x21, 0xEA, 0x23, 0x84, 0x03, 0x3E, 0x27, 0xED, 0xA6, 0x3E, 0x17, 0xEC, 0x10, + 0xEA, 0x3F, 0x3E, 0x27, 0xF0, 0xD2, 0x3E, 0x17, 0xEA, 0x50, 0xFC, 0x80, 0x49, 0xFF, 0xD2, 0xB5, + 0x49, 0xFF, 0xFD, 0x39, 0x49, 0xFF, 0xFE, 0xA3, 0x5A, 0x08, 0x01, 0x04, 0xEB, 0x76, 0xFC, 0x80, + 0x49, 0xFF, 0xFD, 0xFC, 0x49, 0xFF, 0xFE, 0x2E, 0xC8, 0x03, 0x49, 0xFF, 0xFE, 0x7D, 0x2E, 0x07, + 0xEA, 0x50, 0x5A, 0x08, 0x01, 0x06, 0x84, 0x00, 0xEB, 0x76, 0x49, 0x00, 0x08, 0x2A, 0x84, 0x01, + 0x3E, 0x07, 0xF0, 0xBD, 0xEA, 0x3F, 0xFC, 0x80, 0xFC, 0x01, 0x2E, 0x07, 0xF0, 0xD2, 0x5A, 0x00, + 0x01, 0x22, 0xC0, 0x04, 0x5A, 0x00, 0x02, 0x26, 0xFC, 0x81, 0xEA, 0x38, 0x84, 0x00, 0xDD, 0x45, + 0xDD, 0x41, 0x80, 0xC0, 0xC8, 0x14, 0xEA, 0x26, 0xC0, 0x12, 0x3E, 0x67, 0xEA, 0x4E, 0xEA, 0x81, + 0x3E, 0x07, 0xEA, 0x4D, 0x80, 0x06, 0xEA, 0x30, 0x80, 0x06, 0xEA, 0x20, 0xEA, 0x35, 0xB6, 0x1F, + 0xEA, 0x3A, 0xF0, 0x81, 0xB4, 0x3F, 0x80, 0x06, 0xF2, 0x01, 0xDD, 0x5B, 0x84, 0x01, 0xDD, 0x45, + 0xD5, 0x46, 0x49, 0x00, 0x2F, 0xD7, 0x49, 0x00, 0x2F, 0xDE, 0xC0, 0x44, 0x84, 0x02, 0xD5, 0x40, + 0x49, 0x00, 0x2F, 0xED, 0xC0, 0x3F, 0xDD, 0x50, 0xC0, 0x05, 0xEA, 0x2C, 0x5A, 0x08, 0x02, 0x05, + 0xFC, 0x81, 0xDD, 0x49, 0xC0, 0xFB, 0xDD, 0x51, 0x5A, 0x00, 0x01, 0x35, 0xEB, 0x04, 0x49, 0x00, + 0x19, 0xFD, 0x5A, 0x08, 0x01, 0x22, 0xDD, 0x41, 0x80, 0xC0, 0xC8, 0x18, 0x2E, 0x07, 0xEA, 0x4D, + 0xEA, 0x30, 0x49, 0x00, 0x2F, 0x1F, 0x49, 0x00, 0x19, 0xC3, 0x2E, 0x07, 0xEA, 0x4E, 0x5A, 0x08, + 0x01, 0x0E, 0x80, 0x06, 0xEA, 0x30, 0x80, 0x06, 0xEA, 0x20, 0xEA, 0x35, 0xB6, 0x1F, 0xEA, 0x3A, + 0xF0, 0x81, 0xB4, 0x3F, 0x80, 0x06, 0xF2, 0x01, 0xDD, 0x5B, 0x84, 0x00, 0xEA, 0x96, 0xEA, 0xEC, + 0xEA, 0x5D, 0x84, 0x01, 0xEA, 0x3F, 0xEA, 0x38, 0xEA, 0x6C, 0x5A, 0x08, 0x01, 0x09, 0x3E, 0x07, + 0xEA, 0x4E, 0x84, 0x04, 0x3E, 0x07, 0xEA, 0x4D, 0x84, 0x00, 0xD5, 0x02, 0x84, 0x01, 0x3E, 0x07, + 0xF0, 0xD2, 0xFC, 0x81, 0xFC, 0x20, 0xEA, 0x34, 0xC8, 0x0F, 0xEB, 0xDE, 0x5A, 0x08, 0x01, 0x0D, + 0xDD, 0x41, 0xC8, 0x0A, 0x49, 0x00, 0x24, 0x1E, 0xC0, 0x07, 0x84, 0x04, 0x49, 0xFF, 0xFC, 0x3E, + 0xC0, 0x03, 0x84, 0x04, 0xEB, 0x19, 0xEA, 0x2C, 0x8E, 0x02, 0xE6, 0x03, 0xE8, 0x0D, 0xEA, 0x99, + 0x5A, 0x08, 0x01, 0x0B, 0xFA, 0x01, 0xEA, 0x32, 0x5A, 0x08, 0x01, 0x07, 0x84, 0x00, 0xEB, 0x6F, + 0x84, 0x20, 0xFA, 0x01, 0xDD, 0x47, 0xEA, 0x6C, 0x8E, 0x01, 0xE6, 0x02, 0xE8, 0x09, 0x2E, 0x07, + 0xF0, 0xC2, 0xC0, 0x06, 0x84, 0x00, 0x3E, 0x07, 0xF0, 0xC2, 0xEA, 0x95, 0xEB, 0x79, 0xEA, 0x34, + 0xC8, 0x1E, 0xEA, 0x6C, 0x8E, 0x01, 0xE6, 0x02, 0xE8, 0x1A, 0x2E, 0x07, 0xF0, 0xBD, 0x5A, 0x08, + 0x01, 0x17, 0x49, 0x00, 0x2F, 0x58, 0xC8, 0x10, 0x2E, 0x07, 0xF2, 0x21, 0xC8, 0x0D, 0xDD, 0x50, + 0xC0, 0x04, 0xEA, 0x2C, 0x5A, 0x00, 0x02, 0x09, 0x2E, 0x07, 0xF2, 0x19, 0xC8, 0x05, 0x2E, 0x77, + 0xF2, 0x20, 0x97, 0xB8, 0xC6, 0x37, 0x84, 0x00, 0x3E, 0x07, 0xF0, 0xBD, 0xEA, 0x6C, 0xC0, 0x15, + 0xEA, 0x34, 0x5A, 0x08, 0x01, 0x0B, 0x84, 0x04, 0xEA, 0x3F, 0x84, 0x00, 0xDD, 0x45, 0x84, 0x00, + 0x49, 0x00, 0x01, 0xE8, 0xEB, 0x04, 0xD5, 0x09, 0xEA, 0x6C, 0x5A, 0x08, 0x04, 0x07, 0x84, 0x01, + 0xEA, 0x3F, 0x84, 0x01, 0xDD, 0x45, 0xEA, 0x38, 0xEA, 0x6C, 0x5A, 0x00, 0x02, 0x16, 0xE6, 0x03, + 0xE8, 0x05, 0xC0, 0x09, 0x5A, 0x00, 0x01, 0x0E, 0xFC, 0xA0, 0x5A, 0x00, 0x03, 0x11, 0x5A, 0x00, + 0x04, 0x06, 0xFC, 0xA0, 0x49, 0xFF, 0xFD, 0xBB, 0xFC, 0xA0, 0x49, 0xFF, 0xFE, 0x98, 0xFC, 0xA0, + 0x49, 0xFF, 0xFE, 0x9C, 0xFC, 0xA0, 0x49, 0xFF, 0xFE, 0xA2, 0xFC, 0xA0, 0x49, 0xFF, 0xFF, 0x16, + 0xFC, 0xA0, 0x80, 0x06, 0x49, 0x00, 0x21, 0xDC, 0x80, 0x06, 0x49, 0x00, 0x21, 0xE8, 0x84, 0x01, + 0x49, 0x00, 0x21, 0xD6, 0xEA, 0x2C, 0x8E, 0x02, 0xE6, 0x03, 0xE8, 0xAC, 0xEA, 0x99, 0x5A, 0x08, + 0x01, 0xAA, 0xFA, 0x01, 0xEA, 0x32, 0x5A, 0x08, 0x01, 0xA6, 0xFA, 0x01, 0x80, 0x26, 0x3E, 0x77, + 0xF0, 0xE5, 0xDD, 0x47, 0xD5, 0x9F, 0xFC, 0x54, 0xEA, 0x48, 0x84, 0xC1, 0x96, 0x06, 0xC0, 0x10, + 0xEA, 0x48, 0xEA, 0x39, 0xEA, 0xFB, 0x84, 0x01, 0x49, 0x00, 0x22, 0x08, 0x3E, 0x67, 0xF0, 0xD1, + 0x3E, 0x67, 0xF2, 0x1A, 0xEB, 0x6C, 0xEB, 0x03, 0x84, 0x00, 0x3E, 0x07, 0xF0, 0xC6, 0x84, 0xE0, + 0x44, 0x90, 0x00, 0x41, 0x44, 0xA0, 0x00, 0x40, 0x49, 0x00, 0x37, 0x64, 0xDD, 0x50, 0xC0, 0x13, + 0xEA, 0x2C, 0x5A, 0x08, 0x02, 0x11, 0x2E, 0x17, 0xF0, 0xD4, 0xC1, 0x0D, 0xCF, 0x0C, 0xEA, 0x7A, + 0x80, 0x07, 0x3E, 0x77, 0xF0, 0xDB, 0xDD, 0x45, 0xEA, 0xFE, 0x80, 0x07, 0x80, 0x27, 0xDD, 0x47, + 0x84, 0xE1, 0xD5, 0x0E, 0xDD, 0x49, 0xC0, 0x0C, 0xEA, 0x2C, 0x5A, 0x08, 0x02, 0x0A, 0x5A, 0x78, + 0x01, 0x07, 0x84, 0x00, 0x3E, 0x77, 0xF0, 0xD9, 0xEA, 0x3F, 0xEB, 0xAE, 0x84, 0xE0, 0x49, 0x00, + 0x36, 0xBF, 0xEA, 0x2C, 0x5A, 0x00, 0x02, 0x3C, 0xE6, 0x03, 0xE8, 0x05, 0xC0, 0x0D, 0x5A, 0x00, + 0x01, 0x0E, 0xD5, 0xD3, 0x5A, 0x08, 0x03, 0x04, 0x48, 0x00, 0x00, 0x86, 0x5A, 0x08, 0x04, 0x04, + 0x48, 0x00, 0x00, 0xCE, 0xD5, 0xCA, 0x84, 0x01, 0xD5, 0x20, 0x84, 0x20, 0x3E, 0xA7, 0xEA, 0x53, + 0x3E, 0x17, 0xF0, 0xD4, 0x3E, 0x17, 0xF0, 0xD3, 0x3E, 0x17, 0xF0, 0xBF, 0xEB, 0x76, 0xDD, 0x41, + 0x5A, 0x08, 0x01, 0x1C, 0x49, 0x00, 0x21, 0xB5, 0x5A, 0x08, 0x02, 0x0A, 0x44, 0x02, 0x7F, 0xC0, + 0x3C, 0x0E, 0x05, 0xB4, 0x3D, 0xFE, 0x05, 0xB6, 0x84, 0x03, 0xD5, 0x02, 0x84, 0x04, 0x3E, 0x07, + 0xF0, 0xD1, 0xEA, 0x47, 0xC0, 0x05, 0x84, 0x04, 0x3E, 0x07, 0xF0, 0xD1, 0xD5, 0xA6, 0x2E, 0x07, + 0xF2, 0x16, 0xC0, 0xA3, 0x84, 0x03, 0xD5, 0xF9, 0x84, 0x02, 0xD5, 0xF7, 0x49, 0x00, 0x1F, 0xF0, + 0xEB, 0xE2, 0xEA, 0xDB, 0x5A, 0x08, 0x01, 0x0F, 0xEA, 0xD7, 0x84, 0x00, 0xDD, 0x45, 0x2E, 0x07, + 0xF2, 0x1B, 0x84, 0x00, 0xEA, 0xC2, 0xEB, 0x90, 0x84, 0x00, 0x3E, 0x07, 0xF0, 0xD9, 0x84, 0xE0, + 0xEB, 0xAE, 0xEB, 0x6C, 0x5A, 0x08, 0x01, 0x1A, 0x2E, 0x07, 0xF0, 0xC6, 0xC8, 0x02, 0xEA, 0xFE, + 0x84, 0x00, 0xEA, 0x79, 0xEA, 0xA8, 0x5A, 0x08, 0x02, 0x04, 0x49, 0x00, 0x19, 0x19, 0xEB, 0x71, + 0x5A, 0x68, 0x01, 0x0C, 0xEB, 0x03, 0x2E, 0x07, 0xF2, 0x14, 0x4E, 0x02, 0xFF, 0x77, 0x84, 0x00, + 0x3E, 0x07, 0xF0, 0xC6, 0x48, 0x00, 0x00, 0x92, 0x2E, 0x07, 0xF2, 0x1D, 0xC0, 0x1F, 0x84, 0x00, + 0xDD, 0x45, 0xEA, 0xFE, 0x84, 0x00, 0x84, 0xC0, 0x85, 0x01, 0xEA, 0xC2, 0xEB, 0x90, 0x84, 0x02, + 0x84, 0x20, 0x3E, 0x67, 0xF0, 0xD9, 0x3E, 0x67, 0xF0, 0xDA, 0xDD, 0x47, 0x3E, 0x87, 0xF0, 0xBF, + 0x3E, 0x87, 0xF2, 0x23, 0xEB, 0x03, 0x2E, 0x77, 0xF2, 0x14, 0x4E, 0x72, 0xFF, 0x57, 0x3E, 0x87, + 0xF0, 0xD1, 0x3E, 0x67, 0xF2, 0x1D, 0x84, 0xE0, 0xEA, 0x91, 0x2E, 0x07, 0xF0, 0xBF, 0x4E, 0x03, + 0xFF, 0x4D, 0xD5, 0x4A, 0xEA, 0x47, 0xC0, 0x16, 0x2E, 0x67, 0xF2, 0x16, 0x97, 0xB0, 0xCE, 0x12, + 0xEA, 0xDB, 0x5A, 0x08, 0x01, 0x06, 0xEA, 0xD7, 0x80, 0x06, 0xDD, 0x45, 0xEA, 0xC2, 0xEB, 0x6C, + 0x5A, 0x08, 0x01, 0x09, 0xEB, 0x71, 0x84, 0x00, 0xEA, 0x79, 0x5A, 0x68, 0x01, 0x04, 0xEB, 0x03, + 0xD5, 0x54, 0x84, 0x00, 0x3E, 0x07, 0xF2, 0x16, 0xEA, 0x47, 0xC8, 0x04, 0xEA, 0xDB, 0x49, 0x00, + 0x1F, 0xAF, 0xEB, 0xE2, 0x5A, 0x08, 0x01, 0x12, 0xEA, 0xD7, 0x84, 0x00, 0xDD, 0x45, 0xEA, 0xA8, + 0x5A, 0x08, 0x02, 0x04, 0x49, 0x00, 0x18, 0xCE, 0xEA, 0xFE, 0x49, 0x00, 0x12, 0x7B, 0x49, 0x00, + 0x1F, 0xB8, 0x84, 0x00, 0xEB, 0x97, 0xEA, 0xC2, 0x49, 0x00, 0x1F, 0x6A, 0x5A, 0x08, 0x01, 0x09, + 0xEB, 0x90, 0x2E, 0x07, 0xF0, 0xBF, 0x5A, 0x08, 0x01, 0x04, 0x48, 0xFF, 0xFF, 0x67, 0x2E, 0x07, + 0xF0, 0xBF, 0x4E, 0x03, 0xFF, 0x0B, 0xEA, 0xA8, 0x5A, 0x08, 0x02, 0x07, 0xEA, 0x48, 0x96, 0x06, + 0xC0, 0x03, 0x49, 0x00, 0x18, 0x9D, 0x49, 0xFF, 0xFE, 0x4F, 0xEA, 0x91, 0xEA, 0x47, 0xC0, 0x20, + 0xEA, 0xC0, 0xC0, 0x1E, 0xEA, 0xDB, 0x5A, 0x08, 0x01, 0x06, 0xEA, 0xD7, 0x84, 0x00, 0xDD, 0x45, + 0xEA, 0xC2, 0xEB, 0x6C, 0x5A, 0x08, 0x01, 0x15, 0xEB, 0x71, 0x85, 0x00, 0x3E, 0x80, 0x03, 0x2F, + 0x5A, 0x68, 0x01, 0x0F, 0x3E, 0x87, 0xF2, 0x15, 0x3E, 0x67, 0xF2, 0x16, 0xEB, 0x03, 0x80, 0x06, + 0x84, 0x20, 0x3E, 0x87, 0xF2, 0x17, 0xDD, 0x4E, 0x3E, 0x67, 0xF0, 0xD1, 0xEA, 0x91, 0xEA, 0x47, + 0xC8, 0x04, 0xEA, 0xDB, 0x49, 0x00, 0x1F, 0x65, 0xEB, 0xE2, 0x5A, 0x08, 0x01, 0x12, 0x84, 0xC0, + 0xEA, 0xD7, 0x84, 0x00, 0xDD, 0x45, 0x49, 0x00, 0x18, 0x7D, 0xEA, 0xFE, 0x3E, 0x67, 0xF2, 0x17, + 0x3E, 0x67, 0xF2, 0x15, 0x49, 0x00, 0x1F, 0x65, 0x3E, 0x67, 0xF2, 0x23, 0xEA, 0xC2, 0x49, 0x00, + 0x1F, 0x17, 0xEB, 0x71, 0x5A, 0x08, 0x01, 0x0A, 0x5A, 0x68, 0x01, 0x08, 0x84, 0x00, 0x3E, 0x67, + 0xF0, 0xD1, 0x3E, 0x07, 0xF2, 0x15, 0xEA, 0x91, 0x4E, 0x63, 0xFE, 0xB8, 0x2E, 0x07, 0xF2, 0x15, + 0xC0, 0x1B, 0x80, 0x06, 0x80, 0x26, 0xDD, 0x4E, 0x80, 0x06, 0x80, 0x26, 0xEA, 0x2A, 0x80, 0x06, + 0x84, 0x21, 0xDD, 0x4E, 0x84, 0x21, 0x80, 0x06, 0xEA, 0x2A, 0x49, 0x00, 0x08, 0x6C, 0x49, 0x00, + 0x08, 0x7C, 0x49, 0x00, 0x08, 0xFD, 0x84, 0x01, 0x49, 0x00, 0x20, 0x59, 0x49, 0x00, 0x09, 0x06, + 0x49, 0x00, 0x08, 0xAF, 0xEA, 0x91, 0x84, 0x02, 0xEB, 0xD1, 0x80, 0x06, 0x80, 0x26, 0xDD, 0x4E, + 0x80, 0x06, 0x80, 0x26, 0xEA, 0x2A, 0x80, 0x06, 0x84, 0x21, 0xDD, 0x4E, 0x80, 0x06, 0x84, 0x21, + 0xEA, 0x2A, 0x44, 0x11, 0x86, 0xA0, 0x80, 0x06, 0xEA, 0xE9, 0x84, 0x01, 0x49, 0x00, 0x20, 0x3F, + 0x84, 0x0A, 0xEA, 0xB4, 0x84, 0x01, 0x44, 0x11, 0x86, 0xA0, 0xEA, 0xE9, 0xEA, 0x91, 0xEA, 0x6C, + 0xDD, 0x9E, 0x2E, 0x07, 0xEA, 0x53, 0xDD, 0x9E, 0x3E, 0x07, 0xEA, 0x53, 0xDD, 0x9E, 0xDD, 0x9E, + 0x46, 0x10, 0x00, 0x81, 0xC8, 0x06, 0x04, 0x00, 0x80, 0x33, 0x58, 0x00, 0x02, 0x00, 0xD5, 0x05, + 0x04, 0x20, 0x80, 0x33, 0xEB, 0x74, 0xFE, 0x16, 0x14, 0x00, 0x80, 0x33, 0xDD, 0x9E, 0x5A, 0x10, + 0x01, 0x0D, 0xC1, 0x04, 0x5A, 0x10, 0x02, 0x12, 0xDD, 0x9E, 0xDD, 0x5E, 0x96, 0x06, 0xEA, 0x24, + 0x04, 0x31, 0x00, 0x29, 0xEA, 0x29, 0xD5, 0x12, 0xDD, 0x5E, 0x96, 0x06, 0xEB, 0xDF, 0x04, 0x31, + 0x00, 0x29, 0x44, 0x0B, 0xFF, 0xFF, 0xD5, 0x0A, 0x96, 0x06, 0xDD, 0x5E, 0x40, 0x10, 0x4C, 0x08, + 0x46, 0x0F, 0xFF, 0x7F, 0x04, 0x31, 0x00, 0x29, 0xDD, 0x42, 0xFE, 0x1E, 0xFE, 0x0F, 0x14, 0x01, + 0x00, 0x29, 0xDD, 0x9E, 0x44, 0x24, 0x2C, 0x14, 0x84, 0x30, 0xB4, 0x62, 0x96, 0x1F, 0xFE, 0x5E, + 0xFE, 0x0F, 0xB6, 0x02, 0xDD, 0x9E, 0xFC, 0x00, 0x80, 0xC0, 0xEA, 0x3B, 0x5A, 0x08, 0x1F, 0x07, + 0xE6, 0xC4, 0x80, 0x06, 0xE8, 0x02, 0x84, 0x04, 0x97, 0x80, 0x44, 0x24, 0x2C, 0x14, 0x97, 0x9F, + 0x40, 0x03, 0x20, 0x08, 0xB4, 0xC2, 0x44, 0x1F, 0xF0, 0xFF, 0xFF, 0x8E, 0xFF, 0x87, 0xB6, 0xC2, + 0xFC, 0x80, 0xFC, 0x40, 0xEA, 0x56, 0x81, 0x42, 0x83, 0x81, 0x80, 0xE4, 0x81, 0x00, 0x81, 0x23, + 0xEB, 0x32, 0x04, 0x03, 0x03, 0x91, 0x54, 0x84, 0x03, 0xFF, 0x92, 0x0A, 0xEA, 0x21, 0x40, 0x80, + 0x20, 0x04, 0x14, 0x83, 0x03, 0x91, 0xEB, 0xAA, 0x04, 0x23, 0x00, 0x2C, 0x46, 0x0F, 0xF0, 0x0F, + 0x40, 0x1E, 0x40, 0x08, 0x50, 0x00, 0x0F, 0x00, 0xFE, 0x16, 0x41, 0xC0, 0xF0, 0x04, 0x40, 0x1E, + 0x00, 0x04, 0x14, 0x13, 0x00, 0x2C, 0x40, 0x34, 0xC0, 0x08, 0x04, 0x13, 0x00, 0x2D, 0x40, 0x31, + 0xA8, 0x04, 0x46, 0x23, 0xF3, 0xF0, 0x40, 0xA5, 0x60, 0x08, 0x46, 0x0C, 0x0C, 0x0F, 0x50, 0x21, + 0x00, 0x3F, 0x40, 0x31, 0xA8, 0x04, 0x50, 0x00, 0x0F, 0xC0, 0xFE, 0xD6, 0xFE, 0x0E, 0x40, 0x21, + 0x80, 0x04, 0x14, 0x23, 0x00, 0x2D, 0x04, 0x43, 0x00, 0x2F, 0x97, 0xEF, 0x92, 0x86, 0x95, 0x26, + 0xFF, 0xE7, 0x14, 0x73, 0x00, 0x2F, 0xFC, 0xC0, 0xFC, 0x00, 0x44, 0x24, 0x2C, 0x24, 0x44, 0x0F, + 0x3F, 0xFF, 0xB4, 0x22, 0xFE, 0x0E, 0x44, 0x10, 0x80, 0x00, 0xFE, 0x0F, 0xB6, 0x02, 0x84, 0x41, + 0x44, 0x04, 0x28, 0x24, 0x44, 0x14, 0x24, 0x24, 0x80, 0x62, 0xDD, 0x44, 0xFC, 0x80, 0x44, 0x24, + 0x80, 0x90, 0x96, 0x06, 0xB4, 0x62, 0xDD, 0x56, 0xEA, 0x25, 0xFE, 0x1E, 0xFE, 0x0F, 0xB6, 0x02, + 0xDD, 0x9E, 0x46, 0x20, 0x00, 0x82, 0x96, 0x06, 0xA0, 0xD5, 0xEA, 0x24, 0xEA, 0x29, 0xFE, 0x1E, + 0xFE, 0x0F, 0xA8, 0x15, 0xDD, 0x9E, 0x46, 0x00, 0x00, 0x82, 0xA0, 0x05, 0x92, 0x10, 0x96, 0x06, + 0xDD, 0x9E, 0x46, 0x30, 0x00, 0x82, 0x44, 0x41, 0x00, 0x00, 0xB4, 0xA3, 0xEA, 0xBC, 0xFF, 0x2F, + 0xB6, 0x83, 0xB4, 0x83, 0x94, 0x92, 0x92, 0x8A, 0x40, 0x42, 0x28, 0x08, 0xFF, 0x0F, 0xB6, 0x83, + 0x88, 0x40, 0x4C, 0x01, 0x00, 0x05, 0xA0, 0x59, 0xAA, 0x41, 0xD5, 0xFC, 0xB4, 0x23, 0xEA, 0x29, + 0xFE, 0x0E, 0xB6, 0x03, 0xDD, 0x9E, 0x46, 0x30, 0x00, 0x82, 0x44, 0x41, 0x00, 0x00, 0xB4, 0xA3, + 0xEA, 0xBC, 0xFF, 0x2F, 0xB6, 0x83, 0xB4, 0x83, 0x94, 0x92, 0x92, 0x8A, 0x40, 0x42, 0x28, 0x08, + 0xFF, 0x0F, 0xB6, 0x83, 0x88, 0x40, 0x80, 0x23, 0x4C, 0x01, 0x00, 0x05, 0xA3, 0x01, 0xA9, 0x09, + 0xD5, 0xFC, 0xB4, 0x23, 0xEA, 0x29, 0xFE, 0x0E, 0xB6, 0x03, 0xDD, 0x9E, 0xFC, 0x00, 0x46, 0x50, + 0x00, 0x80, 0x46, 0x3F, 0xFF, 0x00, 0x9D, 0x99, 0x9D, 0x2E, 0x94, 0xA9, 0x88, 0x40, 0x38, 0x11, + 0x18, 0x00, 0x38, 0x21, 0x0C, 0x00, 0x94, 0x4C, 0xFE, 0x57, 0x96, 0x48, 0x18, 0x12, 0x80, 0x01, + 0xDC, 0xF5, 0xFC, 0x80, 0x46, 0x30, 0x00, 0x80, 0xEA, 0x4F, 0x04, 0x41, 0x80, 0x71, 0xFE, 0x0F, + 0x44, 0x2F, 0xF8, 0xFE, 0x54, 0x10, 0x07, 0x01, 0xFE, 0xA6, 0x40, 0x00, 0x88, 0x04, 0x14, 0x01, + 0x80, 0x71, 0xDD, 0x9E, 0x46, 0x20, 0x00, 0x80, 0x84, 0x3E, 0x04, 0x31, 0x00, 0xA4, 0x96, 0x06, + 0xFE, 0x5E, 0xFE, 0x0F, 0x14, 0x01, 0x00, 0xA4, 0xDD, 0x9E, 0x46, 0x20, 0x00, 0x81, 0xEA, 0x22, + 0x04, 0x11, 0x00, 0x11, 0x96, 0x49, 0xFE, 0x0F, 0x14, 0x01, 0x00, 0x11, 0xDD, 0x9E, 0x46, 0x20, + 0x00, 0x81, 0xEA, 0x22, 0x04, 0x11, 0x00, 0x10, 0x96, 0x49, 0xFE, 0x0F, 0xEB, 0x26, 0xDD, 0x9E, + 0x46, 0x20, 0x00, 0x81, 0x04, 0x11, 0x00, 0x10, 0x92, 0x30, 0xEA, 0x28, 0xFE, 0x0F, 0xEB, 0x26, + 0xDD, 0x9E, 0x46, 0x20, 0x00, 0x81, 0x04, 0x11, 0x00, 0x11, 0x92, 0x30, 0xEA, 0x28, 0xFE, 0x0F, + 0x14, 0x01, 0x00, 0x11, 0xDD, 0x9E, 0x46, 0x20, 0x00, 0x81, 0x84, 0x30, 0xEA, 0x89, 0x96, 0x1F, + 0xFE, 0x5E, 0xFE, 0x0F, 0xEA, 0x73, 0xDD, 0x9E, 0x46, 0x20, 0x00, 0x80, 0x84, 0x30, 0x04, 0x31, + 0x00, 0x70, 0x96, 0x1F, 0xFE, 0x5E, 0xFE, 0x0F, 0x14, 0x01, 0x00, 0x70, 0xDD, 0x9E, 0x46, 0x20, + 0x00, 0x81, 0x84, 0x3E, 0x04, 0x31, 0x00, 0x13, 0x96, 0x06, 0xFE, 0x5E, 0xFE, 0x0F, 0x14, 0x01, + 0x00, 0x13, 0xDD, 0x9E, 0x46, 0x20, 0x00, 0x81, 0x96, 0x06, 0xEA, 0x89, 0xDD, 0x56, 0xEA, 0x25, + 0xFE, 0x1E, 0xFE, 0x0F, 0xEA, 0x73, 0xDD, 0x9E, 0x46, 0x20, 0x00, 0x81, 0x96, 0x0F, 0xEA, 0x89, + 0xEA, 0x24, 0x44, 0x0C, 0xFF, 0xFF, 0xFE, 0x1E, 0xFE, 0x0F, 0xEA, 0x73, 0xDD, 0x9E, 0x46, 0x20, + 0x00, 0x81, 0x96, 0x1F, 0xEA, 0x24, 0x04, 0x31, 0x00, 0x13, 0x46, 0x0F, 0xFF, 0x0F, 0xDD, 0x42, + 0xFE, 0x1E, 0xFE, 0x0F, 0x14, 0x01, 0x00, 0x13, 0xDD, 0x9E, 0x46, 0x20, 0x00, 0x81, 0x84, 0x38, + 0x04, 0x31, 0x00, 0x76, 0x96, 0x17, 0xFE, 0x5E, 0xFE, 0x0F, 0x14, 0x01, 0x00, 0x76, 0xDD, 0x9E, + 0x46, 0x20, 0x00, 0x81, 0x96, 0x06, 0x40, 0x10, 0x54, 0x08, 0xEA, 0x89, 0x46, 0x0F, 0xFD, 0xFF, + 0xDD, 0x42, 0xFE, 0x1E, 0xFE, 0x0F, 0xEA, 0x73, 0xDD, 0x9E, 0x46, 0x20, 0x00, 0x81, 0x96, 0x0F, + 0xEB, 0xDF, 0xEA, 0x89, 0x46, 0x0F, 0xFF, 0x3F, 0xDD, 0x42, 0xFE, 0x1E, 0xFE, 0x0F, 0xEA, 0x73, + 0xDD, 0x9E, 0x46, 0x20, 0x00, 0x81, 0x96, 0x06, 0x40, 0x10, 0x58, 0x08, 0xEA, 0x89, 0x46, 0x0F, + 0xFB, 0xFF, 0xDD, 0x42, 0xFE, 0x1E, 0xFE, 0x0F, 0xEA, 0x73, 0xDD, 0x9E, 0x46, 0x00, 0x00, 0x81, + 0x04, 0x00, 0x00, 0x12, 0x92, 0x12, 0x96, 0x0F, 0xDD, 0x9E, 0x44, 0x04, 0x80, 0x10, 0x84, 0x21, + 0xB4, 0x00, 0x92, 0x08, 0x96, 0x06, 0xC0, 0x07, 0xEB, 0x7D, 0xAE, 0x40, 0x3E, 0x17, 0xF0, 0xDC, + 0x3E, 0x17, 0xF0, 0xDB, 0xDD, 0x9E, 0xDD, 0x9E, 0xDD, 0x9E, 0x46, 0x20, 0x00, 0x81, 0x96, 0x0F, + 0x50, 0x41, 0x00, 0xE4, 0xB4, 0x64, 0xEB, 0xDF, 0x46, 0x0F, 0xFF, 0x3F, 0xDD, 0x42, 0xFE, 0x1E, + 0xFE, 0x0F, 0xB6, 0x04, 0xB4, 0x24, 0x46, 0x03, 0x00, 0x00, 0xFE, 0x0F, 0xB6, 0x04, 0xDD, 0x9E, + 0x46, 0x20, 0x00, 0x81, 0x96, 0x0F, 0x40, 0x10, 0x58, 0x08, 0x04, 0x31, 0x00, 0x39, 0x46, 0x0F, + 0xF3, 0xFF, 0xDD, 0x42, 0xFE, 0x1E, 0xFE, 0x0F, 0x14, 0x01, 0x00, 0x39, 0xDD, 0x9E, 0x46, 0x20, + 0x00, 0x81, 0x96, 0x0F, 0x50, 0x41, 0x00, 0xE4, 0xB4, 0x64, 0x94, 0x46, 0x44, 0x0F, 0xFF, 0x3F, + 0xFE, 0x1E, 0xFE, 0x0F, 0xB6, 0x04, 0xB4, 0x24, 0x44, 0x03, 0x00, 0x00, 0xFE, 0x0F, 0xB6, 0x04, + 0xDD, 0x9E, 0x46, 0x20, 0x00, 0x81, 0x96, 0x0F, 0x04, 0x31, 0x00, 0x39, 0xEB, 0x28, 0x44, 0x0F, + 0xF3, 0xFF, 0xFE, 0x1E, 0xFE, 0x0F, 0x14, 0x01, 0x00, 0x39, 0xDD, 0x9E, 0x46, 0x10, 0x00, 0x81, + 0x46, 0x2F, 0x8F, 0x8F, 0x04, 0x30, 0x80, 0x3A, 0x50, 0x21, 0x08, 0xF8, 0xFE, 0x9E, 0x46, 0x30, + 0x50, 0x10, 0x50, 0x31, 0x84, 0x00, 0xFE, 0x9F, 0x14, 0x20, 0x80, 0x3A, 0xC8, 0x0F, 0x46, 0x00, + 0x03, 0x08, 0x50, 0x00, 0x03, 0x20, 0x14, 0x00, 0x80, 0x38, 0x04, 0x00, 0x80, 0x70, 0x92, 0x06, + 0x94, 0x06, 0x58, 0x00, 0x00, 0x38, 0x14, 0x00, 0x80, 0x70, 0xDD, 0x9E, 0xFC, 0x00, 0x80, 0xC0, + 0xEB, 0x32, 0xDD, 0x5E, 0x97, 0x86, 0x94, 0x32, 0x04, 0x61, 0x03, 0x93, 0x84, 0x3B, 0xFF, 0x8E, + 0xFF, 0x87, 0x14, 0x61, 0x03, 0x93, 0xEB, 0xAA, 0xFC, 0x80, 0x44, 0x04, 0x50, 0x2C, 0xB4, 0x00, + 0x92, 0x05, 0x96, 0x06, 0xDD, 0x9E, 0x46, 0x20, 0x00, 0x81, 0x96, 0x06, 0x04, 0x31, 0x00, 0x15, + 0xEA, 0x24, 0xEA, 0x29, 0xFE, 0x1E, 0xFE, 0x0F, 0x14, 0x01, 0x00, 0x15, 0xDD, 0x9E, 0x44, 0x04, + 0x80, 0x08, 0xB4, 0x00, 0x92, 0x0A, 0x96, 0x06, 0xDD, 0x9E, 0x2E, 0x07, 0xEA, 0x55, 0xDD, 0x9E, + 0x3E, 0x07, 0xEA, 0x55, 0xDD, 0x9E, 0x5A, 0x08, 0x01, 0x0E, 0x44, 0x07, 0x21, 0x00, 0xEB, 0x01, + 0xB4, 0x40, 0xFE, 0x57, 0xB6, 0x20, 0x80, 0x20, 0xB4, 0x01, 0x92, 0x19, 0x96, 0x06, 0xC8, 0xFD, + 0xDD, 0x9E, 0x5A, 0x08, 0x02, 0x0D, 0x44, 0x07, 0x21, 0x40, 0xEB, 0x01, 0xB4, 0x40, 0xFE, 0x57, + 0xB6, 0x20, 0x80, 0x20, 0xB4, 0x01, 0x92, 0x19, 0x96, 0x06, 0xC8, 0xFD, 0xDD, 0x9E, 0xFC, 0x00, + 0x44, 0x14, 0x80, 0x04, 0x84, 0x41, 0xB4, 0x01, 0x92, 0x10, 0x96, 0x06, 0xC0, 0x05, 0xEA, 0xC9, + 0xAE, 0x80, 0x3E, 0x27, 0xEA, 0x56, 0xB4, 0x01, 0x92, 0x11, 0x96, 0x06, 0xC0, 0x08, 0xEA, 0xC9, + 0x84, 0x22, 0xAE, 0x40, 0x84, 0x01, 0x3E, 0x07, 0xEA, 0x55, 0xEB, 0x6E, 0xEB, 0xBE, 0xB4, 0x00, + 0x92, 0x12, 0x96, 0x06, 0xC0, 0x07, 0xEA, 0xC9, 0x84, 0x24, 0xAE, 0x40, 0x84, 0x01, 0x3E, 0x07, + 0xEA, 0x54, 0xFC, 0x80, 0xFC, 0x00, 0xEB, 0xBE, 0xEB, 0x47, 0xB6, 0x20, 0x44, 0x14, 0x80, 0x84, + 0x44, 0x02, 0x00, 0x00, 0xB4, 0x41, 0xFE, 0x17, 0xB6, 0x01, 0x44, 0x16, 0x00, 0x30, 0xB4, 0x01, + 0xEA, 0xA1, 0xB6, 0x01, 0x84, 0x01, 0xEB, 0x10, 0xFC, 0x80, 0xFC, 0x41, 0x81, 0x20, 0xF1, 0x81, + 0xB6, 0x9F, 0x83, 0x82, 0x81, 0x43, 0x81, 0x05, 0x00, 0x6F, 0x80, 0x4C, 0xEB, 0x10, 0xB4, 0x9F, + 0xF1, 0x01, 0x4E, 0x92, 0x00, 0x0A, 0x5A, 0x90, 0x01, 0x0B, 0x84, 0xE0, 0x5A, 0x98, 0x02, 0x0A, + 0x44, 0x77, 0x21, 0x40, 0xD5, 0x06, 0x44, 0x77, 0x20, 0xC0, 0xD5, 0x03, 0x44, 0x77, 0x21, 0x00, + 0xB4, 0x07, 0x46, 0x2F, 0x8F, 0x0F, 0x50, 0x21, 0x0F, 0xFE, 0xFE, 0x86, 0xEA, 0x28, 0x46, 0x00, + 0x00, 0xF0, 0xFE, 0x46, 0xFE, 0x57, 0xB6, 0x27, 0xC4, 0x23, 0xA0, 0xB9, 0x46, 0x17, 0xCF, 0xFF, + 0x92, 0x54, 0x40, 0x01, 0x50, 0x08, 0x40, 0x2E, 0x30, 0x08, 0x92, 0x4C, 0xFE, 0x87, 0xA0, 0x3A, + 0x50, 0x10, 0x8F, 0x00, 0xFE, 0x46, 0x00, 0x0F, 0x80, 0x3C, 0x22, 0x3F, 0x80, 0x18, 0xEB, 0xB2, + 0xFE, 0x1F, 0x40, 0x42, 0x7C, 0x08, 0xFF, 0x07, 0x46, 0x08, 0x30, 0x00, 0x50, 0x00, 0x00, 0xFF, + 0xFF, 0x06, 0xFF, 0x0F, 0xA8, 0xB9, 0xA9, 0x3A, 0x50, 0x23, 0x80, 0x08, 0xD5, 0x03, 0x50, 0x23, + 0x80, 0x08, 0x50, 0x11, 0x00, 0x08, 0x4E, 0x82, 0x00, 0x24, 0xA0, 0x11, 0xA0, 0xD2, 0x46, 0x57, + 0xCF, 0xFF, 0x50, 0x52, 0x8F, 0x00, 0x92, 0x14, 0x40, 0xA5, 0x30, 0x08, 0xEB, 0x17, 0xFE, 0xEE, + 0x93, 0x4C, 0x00, 0x5F, 0x80, 0x40, 0x40, 0xA0, 0x28, 0x04, 0x22, 0x0F, 0x80, 0x1A, 0x40, 0x52, + 0xE0, 0x08, 0xFF, 0x47, 0x40, 0x84, 0x7C, 0x08, 0x46, 0x08, 0x30, 0x00, 0x40, 0x52, 0xA0, 0x04, + 0x50, 0x00, 0x00, 0xFF, 0xFF, 0x46, 0xFF, 0x5F, 0x14, 0xA1, 0x00, 0x01, 0xA9, 0x52, 0xA0, 0x09, + 0xA0, 0xCA, 0x92, 0x14, 0x40, 0x20, 0x50, 0x08, 0xF0, 0x0A, 0xEA, 0x8F, 0x92, 0x0C, 0xFE, 0x17, + 0xA8, 0x09, 0x46, 0x07, 0xCF, 0xFF, 0x50, 0x00, 0x0F, 0x00, 0xFE, 0xC6, 0x00, 0x0F, 0x80, 0x44, + 0x22, 0x2F, 0x80, 0x1C, 0xEB, 0xB2, 0xFE, 0x17, 0x00, 0x2F, 0x80, 0x2C, 0x40, 0x21, 0x7C, 0x08, + 0xFE, 0x17, 0x46, 0x28, 0x30, 0x00, 0x50, 0x21, 0x00, 0xFF, 0xFE, 0x16, 0xFE, 0x1F, 0xA8, 0x0A, + 0xA0, 0x0B, 0x46, 0x2F, 0x0F, 0xE0, 0xFE, 0x16, 0xF3, 0x12, 0x46, 0x20, 0xF0, 0x1F, 0xEB, 0x11, + 0xFE, 0x9E, 0xFE, 0x87, 0x84, 0x00, 0xA8, 0x8B, 0xA8, 0x0C, 0x5A, 0x98, 0x01, 0x15, 0x44, 0x17, + 0x21, 0x1C, 0x97, 0x9F, 0xB4, 0x41, 0x40, 0x03, 0x60, 0x08, 0x46, 0x6F, 0x0F, 0xFF, 0x50, 0x63, + 0x0F, 0xFF, 0xFF, 0x96, 0xFF, 0x87, 0xB6, 0xC1, 0x44, 0x14, 0x80, 0x84, 0x44, 0x02, 0x00, 0x00, + 0xB4, 0x41, 0xD5, 0x15, 0x5A, 0x98, 0x02, 0x16, 0x44, 0x17, 0x21, 0x5C, 0x97, 0x9F, 0xB4, 0x41, + 0x40, 0x03, 0x60, 0x08, 0x46, 0x6F, 0x0F, 0xFF, 0x50, 0x63, 0x0F, 0xFF, 0xFF, 0x96, 0xFF, 0x87, + 0xB6, 0xC1, 0x44, 0x14, 0x80, 0x84, 0x44, 0x04, 0x00, 0x00, 0xB4, 0x41, 0xFE, 0x17, 0xB6, 0x01, + 0xFC, 0xC1, 0x46, 0x20, 0x00, 0x83, 0x84, 0x3C, 0x04, 0x31, 0x00, 0x10, 0x96, 0x0F, 0xFE, 0x5E, + 0xFE, 0x0F, 0xEB, 0x26, 0xDD, 0x9E, 0x46, 0x20, 0x00, 0x83, 0x96, 0x06, 0x04, 0x31, 0x00, 0x10, + 0xDD, 0x56, 0xEA, 0x25, 0xFE, 0x1E, 0xFE, 0x0F, 0xEB, 0x26, 0xDD, 0x9E, 0xFC, 0x40, 0x46, 0x20, + 0x00, 0x83, 0x44, 0x5F, 0xFE, 0xFF, 0x83, 0x82, 0xBB, 0x18, 0x46, 0x40, 0x0F, 0x03, 0xFE, 0xEE, + 0xBB, 0x98, 0xBB, 0x18, 0x50, 0x42, 0x0C, 0x0F, 0x92, 0x68, 0xEA, 0xCD, 0x58, 0x31, 0x80, 0x70, + 0xBB, 0x98, 0xBF, 0x39, 0xBE, 0x3A, 0x04, 0x91, 0x00, 0x3B, 0xFF, 0xE6, 0xFF, 0xA6, 0x40, 0x44, + 0x90, 0x02, 0x04, 0x90, 0x80, 0x02, 0xBB, 0x3C, 0xB5, 0x41, 0x89, 0x24, 0xA1, 0x0B, 0x96, 0xDF, + 0x88, 0xEA, 0x04, 0xA0, 0x80, 0x01, 0x98, 0x5C, 0xBB, 0x18, 0x88, 0xCA, 0x58, 0x31, 0x81, 0x00, + 0xBB, 0x98, 0xBB, 0x18, 0x92, 0x68, 0xEA, 0xCD, 0x58, 0x31, 0x80, 0x70, 0xBB, 0x98, 0xBF, 0xB9, + 0xBE, 0xBA, 0x14, 0x91, 0x00, 0x3B, 0x96, 0xC9, 0xB9, 0x3C, 0x92, 0x30, 0xEA, 0x28, 0xFE, 0x5F, + 0xB9, 0xBC, 0xB4, 0x20, 0xB9, 0xB9, 0xA0, 0x41, 0xB9, 0xBA, 0xA0, 0x42, 0xB9, 0xBB, 0xA4, 0x46, + 0xB8, 0x3C, 0x92, 0x10, 0xEA, 0x22, 0xFE, 0x0F, 0xB8, 0xBC, 0xB8, 0x18, 0xFF, 0x46, 0xBD, 0x98, + 0xFC, 0xC0, 0xFC, 0x20, 0x46, 0x20, 0x00, 0x83, 0x44, 0x3F, 0xFE, 0xFF, 0x83, 0x82, 0xBC, 0x18, + 0x94, 0x4A, 0xFE, 0xE6, 0xBB, 0x98, 0xBB, 0x18, 0x50, 0x51, 0x00, 0xE4, 0x92, 0x68, 0xEA, 0xCD, + 0x58, 0x31, 0x80, 0x72, 0xBB, 0x98, 0xBB, 0x18, 0x50, 0x61, 0x00, 0xE8, 0x58, 0x31, 0x81, 0x00, + 0xBB, 0x98, 0x50, 0x71, 0x00, 0xEC, 0x88, 0x20, 0x50, 0x21, 0x00, 0xF0, 0x46, 0x30, 0x00, 0x83, + 0x4C, 0x00, 0x80, 0x11, 0xA2, 0xC1, 0xB6, 0x65, 0x83, 0x80, 0xBB, 0x3F, 0x02, 0x40, 0x01, 0x7E, + 0xB6, 0x66, 0xBB, 0x7F, 0xB6, 0x67, 0xB4, 0x62, 0x92, 0x70, 0xEB, 0xD2, 0xFE, 0xE7, 0xB6, 0x62, + 0xD5, 0xEE, 0x83, 0x83, 0xB9, 0x18, 0xEA, 0x25, 0xFE, 0x0E, 0xB8, 0x98, 0xFC, 0xA0, 0xFC, 0x20, + 0x46, 0x10, 0x00, 0x83, 0x44, 0x2F, 0xFE, 0xFF, 0x83, 0x81, 0xBB, 0x18, 0x46, 0x40, 0xF0, 0x3C, + 0xFE, 0x9E, 0xBA, 0x98, 0xBA, 0x18, 0x50, 0x32, 0x00, 0xF0, 0x92, 0x48, 0xEB, 0xED, 0x58, 0x21, + 0x00, 0x70, 0xBA, 0x98, 0xBE, 0x39, 0xB4, 0x80, 0xBD, 0x3A, 0xFF, 0x9E, 0x88, 0xC4, 0xA1, 0x01, + 0xBF, 0x3B, 0xFF, 0x5E, 0x88, 0xA4, 0xA1, 0x02, 0xBA, 0x3C, 0xFE, 0xFE, 0x88, 0x83, 0xA0, 0xC3, + 0x54, 0x21, 0x00, 0xF0, 0xBE, 0xB9, 0x98, 0x13, 0xBD, 0xBA, 0xBC, 0xBB, 0x96, 0x81, 0xB8, 0x3C, + 0x92, 0x10, 0xEA, 0x22, 0xFE, 0x17, 0xB8, 0xBC, 0xFC, 0xA0, 0xFC, 0x00, 0xEA, 0x87, 0x46, 0x18, + 0x00, 0x00, 0x83, 0x80, 0xBA, 0x6E, 0xFE, 0x57, 0xB9, 0xEE, 0xBA, 0x75, 0xEB, 0x47, 0xFE, 0x57, + 0xB9, 0xF5, 0xBA, 0x17, 0x46, 0x10, 0x40, 0x00, 0xFE, 0x57, 0xB9, 0x97, 0xBA, 0x75, 0x44, 0x1E, + 0xFF, 0xFF, 0xFE, 0x56, 0xB9, 0xF5, 0x84, 0x0A, 0xEA, 0x2D, 0xFC, 0x80, 0x46, 0x10, 0x00, 0x80, + 0x46, 0x0F, 0xC0, 0x0F, 0x04, 0x20, 0x80, 0x74, 0xDD, 0x42, 0xFE, 0x16, 0x14, 0x00, 0x80, 0x74, + 0xDD, 0x9E, 0xFC, 0x00, 0x44, 0x44, 0x80, 0x90, 0x94, 0x84, 0xEB, 0x28, 0xB4, 0x64, 0xFE, 0x57, + 0xFE, 0x47, 0x44, 0x2F, 0xFB, 0xEE, 0xFE, 0x9E, 0x54, 0x10, 0x84, 0x11, 0xFE, 0x57, 0xB6, 0x24, + 0xEB, 0x72, 0x84, 0x58, 0x51, 0xC0, 0x82, 0x6C, 0xB4, 0x7C, 0x46, 0x50, 0x00, 0x81, 0xFE, 0x9E, + 0x58, 0x21, 0x00, 0x06, 0xB6, 0x5C, 0xB4, 0x7C, 0x44, 0x2F, 0xF0, 0xFF, 0xFE, 0x9E, 0x58, 0x21, + 0x06, 0x00, 0xB6, 0x5C, 0xB4, 0x5C, 0x84, 0x61, 0x92, 0x48, 0x96, 0x9F, 0x40, 0x21, 0x88, 0x0C, + 0x54, 0x21, 0x0F, 0xFF, 0x04, 0x62, 0x80, 0x6E, 0x40, 0x31, 0x40, 0x08, 0x46, 0x2F, 0x00, 0x0F, + 0xEB, 0x11, 0xFE, 0xB6, 0xFE, 0x9F, 0x14, 0x22, 0x80, 0x6E, 0xB4, 0x7C, 0x44, 0x28, 0xFF, 0xFF, + 0xFE, 0x9E, 0xB6, 0x5C, 0xB4, 0x7C, 0x46, 0x2F, 0x0F, 0xFF, 0xEB, 0x11, 0xFE, 0x9E, 0x46, 0x30, + 0x70, 0x00, 0xFE, 0x9F, 0xB6, 0x5C, 0x96, 0x06, 0xB4, 0x44, 0x40, 0x10, 0x2C, 0x08, 0x44, 0x0F, + 0xF7, 0xFF, 0xFE, 0x16, 0xFE, 0x0F, 0xB6, 0x04, 0xFC, 0x80, 0x3E, 0x07, 0xEA, 0x57, 0xDD, 0x9E, + 0x2E, 0x07, 0xEA, 0x57, 0xDD, 0x9E, 0x52, 0x00, 0x00, 0x01, 0x46, 0x20, 0x00, 0x80, 0x96, 0x06, + 0xC9, 0x06, 0xDD, 0x56, 0x04, 0x31, 0x00, 0x79, 0xEA, 0x25, 0xD5, 0x05, 0xEA, 0x24, 0x04, 0x31, + 0x00, 0x79, 0xEA, 0x29, 0xFE, 0x1E, 0xFE, 0x0F, 0x14, 0x01, 0x00, 0x79, 0xDD, 0x9E, 0x44, 0x37, + 0x20, 0x00, 0x54, 0x10, 0x00, 0x01, 0xB4, 0x83, 0x40, 0x20, 0xA4, 0x08, 0x44, 0x1F, 0xFD, 0xFF, + 0xFE, 0x66, 0xFE, 0x57, 0xB6, 0x23, 0x3E, 0x07, 0xEA, 0x57, 0xDD, 0x9E, 0x46, 0x10, 0x00, 0x82, + 0x04, 0x20, 0x80, 0x08, 0x5A, 0x08, 0x01, 0x06, 0x84, 0x1C, 0xFE, 0x16, 0xEA, 0x39, 0xD5, 0x03, + 0x84, 0x1D, 0xFE, 0x16, 0x14, 0x00, 0x80, 0x08, 0xDD, 0x9E, 0x46, 0x20, 0x00, 0x83, 0x80, 0x62, + 0x04, 0x41, 0x00, 0xEE, 0xDD, 0x56, 0x84, 0x40, 0xC8, 0x03, 0x44, 0x20, 0x02, 0x00, 0xFE, 0x8F, + 0x44, 0x1F, 0xFC, 0xFF, 0x54, 0x21, 0x03, 0x00, 0x40, 0x02, 0x04, 0x02, 0xFE, 0x17, 0x14, 0x01, + 0x80, 0xEE, 0xDD, 0x9E, 0x46, 0x20, 0x00, 0x83, 0x80, 0x62, 0x04, 0x41, 0x00, 0xEE, 0xEB, 0x28, + 0x84, 0x40, 0xC8, 0x03, 0x44, 0x20, 0x08, 0x00, 0xFE, 0x8F, 0x44, 0x1F, 0xF3, 0xFF, 0x54, 0x21, + 0x0C, 0x00, 0x40, 0x02, 0x04, 0x02, 0xFE, 0x17, 0x14, 0x01, 0x80, 0xEE, 0xDD, 0x9E, 0x44, 0x27, + 0x20, 0x68, 0x96, 0x01, 0xB4, 0x22, 0x92, 0x30, 0xEA, 0x28, 0xFE, 0x47, 0xB6, 0x22, 0x44, 0x27, + 0x20, 0x70, 0xB4, 0x22, 0x92, 0x30, 0xEA, 0x28, 0xFE, 0x0F, 0xB6, 0x02, 0xDD, 0x9E, 0xC8, 0x08, + 0x44, 0x17, 0x20, 0x00, 0xEA, 0x5F, 0xB4, 0x41, 0xDD, 0x42, 0xFE, 0x16, 0xD5, 0x08, 0x5A, 0x08, + 0x01, 0x08, 0x44, 0x17, 0x20, 0x00, 0xEB, 0x3A, 0xB4, 0x41, 0xFE, 0x17, 0xB6, 0x01, 0xDD, 0x9E, + 0x44, 0x07, 0x20, 0x00, 0xB4, 0x00, 0x92, 0x18, 0x96, 0x06, 0xDD, 0x9E, 0x44, 0x27, 0x20, 0x00, + 0x84, 0x3E, 0xB4, 0x62, 0x96, 0x06, 0xFE, 0x5E, 0xFE, 0x0F, 0xB6, 0x02, 0xDD, 0x9E, 0x44, 0x27, + 0x20, 0x04, 0x96, 0x06, 0xB4, 0x62, 0x40, 0x10, 0x24, 0x08, 0xEB, 0x74, 0xFE, 0x1E, 0xFE, 0x0F, + 0xB6, 0x02, 0xDD, 0x9E, 0x44, 0x27, 0x20, 0x04, 0x84, 0x3E, 0xB4, 0x62, 0x96, 0x06, 0xFE, 0x5E, + 0xFE, 0x0F, 0xB6, 0x02, 0xDD, 0x9E, 0x44, 0x27, 0x20, 0x00, 0x96, 0x06, 0xB4, 0x62, 0xEA, 0x24, + 0xEA, 0x29, 0xFE, 0x1E, 0xFE, 0x0F, 0xB6, 0x02, 0xDD, 0x9E, 0x84, 0x01, 0x3E, 0x07, 0xEA, 0x59, + 0xDD, 0x9E, 0x2E, 0x07, 0xEA, 0x59, 0xDD, 0x9E, 0x84, 0x00, 0x3E, 0x07, 0xEA, 0x59, 0xDD, 0x9E, + 0x84, 0x01, 0x3E, 0x07, 0xEA, 0x58, 0xDD, 0x9E, 0x2E, 0x07, 0xEA, 0x58, 0xDD, 0x9E, 0x84, 0x00, + 0x3E, 0x07, 0xEA, 0x58, 0xDD, 0x9E, 0x46, 0x00, 0x00, 0x83, 0x04, 0x00, 0x00, 0xEE, 0x92, 0x08, + 0x96, 0x06, 0xDD, 0x9E, 0x44, 0x24, 0x80, 0x90, 0x96, 0x06, 0xB4, 0x62, 0x94, 0x44, 0xEA, 0xA3, + 0xFE, 0x1E, 0xFE, 0x0F, 0xB6, 0x02, 0xDD, 0x9E, 0xC9, 0x06, 0x44, 0x27, 0x10, 0x00, 0xB4, 0x22, + 0xFE, 0x0F, 0xD5, 0x08, 0x5A, 0x18, 0x01, 0x0E, 0x44, 0x27, 0x10, 0x00, 0xFE, 0x03, 0xB4, 0x22, + 0xFE, 0x0E, 0x94, 0x04, 0xEB, 0x84, 0xB4, 0x02, 0x92, 0x1C, 0xEB, 0x06, 0xFE, 0x0F, 0xB6, 0x02, + 0xDD, 0x9E, 0x5A, 0x18, 0x01, 0x07, 0x44, 0x27, 0x10, 0x04, 0xB4, 0x22, 0xFE, 0x0F, 0xD5, 0x07, + 0xC9, 0x0D, 0x44, 0x27, 0x10, 0x04, 0xFE, 0x03, 0xB4, 0x22, 0xFE, 0x0E, 0x94, 0x04, 0xEB, 0x84, + 0xB4, 0x02, 0x92, 0x1C, 0xEB, 0x06, 0xFE, 0x0F, 0xB6, 0x02, 0xDD, 0x9E, 0x5A, 0x18, 0x01, 0x07, + 0x44, 0x27, 0x10, 0x08, 0xB4, 0x22, 0xFE, 0x0F, 0xD5, 0x07, 0xC9, 0x0D, 0x44, 0x27, 0x10, 0x08, + 0xFE, 0x03, 0xB4, 0x22, 0xFE, 0x0E, 0x94, 0x04, 0xEB, 0x84, 0xB4, 0x02, 0x92, 0x1C, 0xEB, 0x06, + 0xFE, 0x0F, 0xB6, 0x02, 0xDD, 0x9E, 0xC8, 0x07, 0x44, 0x17, 0x10, 0x18, 0x84, 0x1E, 0xB4, 0x41, + 0xFE, 0x16, 0xD5, 0x07, 0x5A, 0x08, 0x01, 0x13, 0x44, 0x17, 0x10, 0x18, 0xB4, 0x01, 0xDD, 0x4B, + 0x44, 0x27, 0x10, 0x0C, 0xB6, 0x01, 0xB4, 0x02, 0x94, 0x04, 0xEB, 0x75, 0xEB, 0x84, 0xB4, 0x02, + 0x92, 0x1C, 0xEB, 0x06, 0xFE, 0x0F, 0xB6, 0x02, 0xDD, 0x9E, 0x5A, 0x08, 0x02, 0x0E, 0x44, 0x17, + 0x10, 0x18, 0xB4, 0x01, 0xDD, 0x4B, 0xB6, 0x01, 0x44, 0x17, 0x10, 0x0C, 0xB4, 0x01, 0xB4, 0x01, + 0x92, 0x1C, 0xEB, 0x06, 0xB6, 0x01, 0xDD, 0x9E, 0x44, 0x27, 0x10, 0x18, 0x96, 0x06, 0xB4, 0x62, + 0xDD, 0x56, 0xEA, 0x25, 0xFE, 0x1E, 0xFE, 0x0F, 0xB6, 0x02, 0xDD, 0x9E, 0x44, 0x07, 0x10, 0x14, + 0xB4, 0x00, 0x94, 0x04, 0x92, 0x04, 0xDD, 0x9E, 0x44, 0x16, 0x00, 0x00, 0x5A, 0x08, 0x01, 0x05, + 0xB4, 0x01, 0xDD, 0x4B, 0xD5, 0x04, 0xB4, 0x41, 0x84, 0x1E, 0xFE, 0x16, 0xB6, 0x01, 0xDD, 0x9E, + 0xFC, 0x00, 0xEA, 0xC4, 0xFC, 0x80, 0x44, 0x16, 0x00, 0x34, 0xB6, 0x01, 0xDD, 0x9E, 0xFC, 0x00, + 0x2E, 0x17, 0xF2, 0x2D, 0x44, 0x27, 0x21, 0x1C, 0x5A, 0x18, 0x01, 0x07, 0xB4, 0x22, 0x92, 0x31, + 0x40, 0x10, 0xC4, 0x08, 0xD5, 0x0A, 0x8E, 0x01, 0x40, 0x00, 0x3C, 0x08, 0x40, 0x10, 0x3C, 0x09, + 0xB4, 0x02, 0x92, 0x11, 0x40, 0x00, 0x44, 0x08, 0xFE, 0x0F, 0xB6, 0x02, 0x84, 0x00, 0xEB, 0x78, + 0x84, 0x00, 0x49, 0xFF, 0xFC, 0x2F, 0xFC, 0x80, 0xFC, 0x00, 0x49, 0xFF, 0xFC, 0x2B, 0xEB, 0x6E, + 0xFC, 0x80, 0xFC, 0x00, 0x49, 0xFF, 0xFC, 0x23, 0xFC, 0x80, 0x44, 0x14, 0x01, 0x08, 0xB4, 0x01, + 0xDD, 0x4B, 0xB6, 0x01, 0x44, 0x16, 0x38, 0x20, 0xB4, 0x01, 0xDD, 0x4B, 0xB6, 0x01, 0x44, 0x16, + 0x34, 0x20, 0xB4, 0x01, 0xDD, 0x4B, 0xB6, 0x01, 0xDD, 0x9E, 0x44, 0x26, 0x38, 0x20, 0x84, 0x1E, + 0xB4, 0x22, 0xFE, 0x46, 0xB6, 0x22, 0x44, 0x26, 0x34, 0x20, 0xB4, 0x22, 0xFE, 0x46, 0xB6, 0x22, + 0xEB, 0xEC, 0xB4, 0x41, 0xFE, 0x16, 0xB6, 0x01, 0xDD, 0x9E, 0x44, 0x34, 0x01, 0x08, 0xDD, 0x52, + 0xB4, 0x43, 0x96, 0x6F, 0xEB, 0x8A, 0xB6, 0x43, 0x44, 0x36, 0x38, 0x14, 0xEB, 0xE7, 0xB4, 0x03, + 0x92, 0x18, 0xEB, 0xB2, 0xFE, 0x17, 0x44, 0x26, 0x38, 0x08, 0xB6, 0x03, 0xB4, 0x62, 0x40, 0x00, + 0xE0, 0x08, 0x46, 0x1C, 0x0F, 0xFF, 0xEA, 0x2B, 0xFE, 0x5E, 0xFE, 0x47, 0xB6, 0x22, 0x44, 0x16, + 0x38, 0x04, 0xEA, 0x5E, 0xB4, 0x41, 0xFE, 0x17, 0xB6, 0x01, 0x44, 0x14, 0x80, 0x0C, 0xB4, 0x01, + 0x92, 0x03, 0x96, 0x06, 0xC0, 0xFD, 0x44, 0x04, 0x80, 0x0C, 0x84, 0x28, 0xAE, 0x40, 0xEB, 0xEC, + 0x84, 0x1E, 0xB4, 0x41, 0xFE, 0x16, 0xB6, 0x01, 0xDD, 0x9E, 0x44, 0x34, 0x01, 0x08, 0xDD, 0x52, + 0xB4, 0x43, 0x96, 0x6F, 0xEB, 0x8A, 0xB6, 0x43, 0x44, 0x36, 0x34, 0x14, 0xEB, 0xE7, 0xB4, 0x03, + 0x92, 0x18, 0xEB, 0xB2, 0xFE, 0x17, 0x44, 0x26, 0x34, 0x08, 0xB6, 0x03, 0xB4, 0x62, 0x40, 0x00, + 0xE0, 0x08, 0x46, 0x1C, 0x0F, 0xFF, 0xEA, 0x2B, 0xFE, 0x5E, 0xFE, 0x47, 0xB6, 0x22, 0x44, 0x16, + 0x34, 0x04, 0xEA, 0x5E, 0xB4, 0x41, 0xFE, 0x17, 0xB6, 0x01, 0x44, 0x14, 0x80, 0x0C, 0xB4, 0x01, + 0x92, 0x13, 0x96, 0x06, 0xC0, 0xFD, 0x44, 0x04, 0x80, 0x0E, 0x84, 0x28, 0xAE, 0x40, 0xEB, 0xEC, + 0x84, 0x1E, 0xB4, 0x41, 0xFE, 0x16, 0xB6, 0x01, 0xDD, 0x9E, 0xFC, 0x01, 0xB6, 0x3F, 0x80, 0x22, + 0xF3, 0x81, 0x49, 0xFF, 0xFF, 0x9C, 0xB4, 0x1F, 0xF1, 0x01, 0x49, 0xFF, 0xFF, 0xC8, 0xFC, 0x81, + 0x44, 0x16, 0x3C, 0x04, 0xB4, 0x01, 0xDD, 0x4B, 0xB6, 0x01, 0xDD, 0x9E, 0x44, 0x26, 0x38, 0x04, + 0xB4, 0x22, 0x44, 0x06, 0x38, 0x04, 0x92, 0x28, 0x96, 0x46, 0xC9, 0xFB, 0xB4, 0x40, 0x84, 0x3E, + 0xFE, 0x56, 0xB6, 0x20, 0x80, 0x20, 0xB4, 0x01, 0x92, 0x08, 0x96, 0x06, 0xC8, 0xFD, 0x44, 0x26, + 0x34, 0x04, 0xB4, 0x22, 0x44, 0x06, 0x34, 0x04, 0x92, 0x28, 0x96, 0x46, 0xC9, 0xFB, 0xB4, 0x40, + 0x84, 0x3E, 0xFE, 0x56, 0xB6, 0x20, 0x80, 0x20, 0xB4, 0x01, 0x92, 0x08, 0x96, 0x06, 0xC8, 0xFD, + 0xDD, 0x9E, 0x44, 0x04, 0x80, 0x8C, 0x84, 0x20, 0xB6, 0x20, 0xDD, 0x9E, 0xFC, 0x40, 0x46, 0x70, + 0x00, 0x83, 0x40, 0x52, 0xAC, 0x08, 0xFE, 0x2F, 0x40, 0x42, 0x44, 0x08, 0x83, 0x87, 0x04, 0x93, + 0x80, 0x14, 0xFE, 0x27, 0x40, 0x10, 0xE0, 0x08, 0x46, 0x50, 0xF7, 0xFF, 0x46, 0x6F, 0x08, 0x00, + 0xFE, 0x0F, 0x50, 0x52, 0x88, 0x01, 0x50, 0x63, 0x07, 0xFE, 0xFE, 0x2E, 0x40, 0x64, 0x98, 0x02, + 0x40, 0x10, 0x18, 0x04, 0xB9, 0x94, 0xBC, 0x15, 0xEB, 0xD2, 0x46, 0x10, 0x07, 0xF0, 0x46, 0x0F, + 0xF8, 0x0F, 0xFE, 0x9F, 0x50, 0x10, 0x83, 0xFF, 0x50, 0x00, 0x0C, 0x00, 0x40, 0x31, 0x04, 0x02, + 0xFE, 0x26, 0x40, 0x21, 0x80, 0x04, 0xBA, 0x95, 0xFC, 0xC0, 0x44, 0x10, 0x0F, 0xFF, 0xFE, 0x0C, + 0x46, 0x10, 0x00, 0x83, 0x14, 0x00, 0x80, 0xBB, 0xDD, 0x9E, 0x46, 0x00, 0x00, 0x83, 0x04, 0x00, + 0x00, 0x16, 0x96, 0x01, 0xDD, 0x9E, 0x46, 0x00, 0x00, 0x83, 0x04, 0x00, 0x00, 0x16, 0x92, 0x11, + 0x54, 0x00, 0x03, 0xFF, 0xDD, 0x9E, 0xB4, 0x40, 0x46, 0x30, 0x00, 0x80, 0xA0, 0x41, 0x14, 0x21, + 0x80, 0x4A, 0xA0, 0x82, 0x40, 0x10, 0xA8, 0x08, 0xA0, 0x03, 0x14, 0x21, 0x80, 0x4B, 0x40, 0x20, + 0xA8, 0x09, 0x04, 0x11, 0x80, 0x4C, 0xEA, 0x21, 0x92, 0x36, 0x40, 0x10, 0xD8, 0x08, 0xFE, 0x57, + 0x14, 0x11, 0x80, 0x4C, 0x40, 0x10, 0x28, 0x09, 0x04, 0x01, 0x80, 0x58, 0x92, 0x16, 0x40, 0x00, + 0x58, 0x08, 0xFE, 0x0F, 0x14, 0x01, 0x80, 0x58, 0xDD, 0x9E, 0x46, 0x20, 0x00, 0x83, 0x96, 0x0F, + 0xEA, 0x89, 0xEA, 0x24, 0x44, 0x0C, 0xFF, 0xFF, 0xFE, 0x1E, 0xFE, 0x0F, 0xEA, 0x73, 0xDD, 0x9E, + 0xFC, 0x40, 0x80, 0xC4, 0x81, 0x22, 0x80, 0xE3, 0x84, 0x00, 0x84, 0x23, 0x49, 0xFF, 0xF9, 0x9C, + 0x38, 0x14, 0x99, 0x01, 0x84, 0x02, 0xEA, 0xAC, 0x38, 0x03, 0x98, 0x00, 0x84, 0x22, 0xEB, 0xE4, + 0xFC, 0xC0, 0x46, 0x20, 0x00, 0x81, 0x96, 0x06, 0xA0, 0xD5, 0xDD, 0x56, 0xEA, 0x25, 0xFE, 0x1E, + 0xFE, 0x0F, 0xA8, 0x15, 0xDD, 0x9E, 0x46, 0x20, 0x00, 0x91, 0x96, 0x06, 0x04, 0x31, 0x00, 0x14, + 0x94, 0x41, 0x84, 0x1D, 0xFE, 0x1E, 0xFE, 0x0F, 0x14, 0x01, 0x00, 0x14, 0xDD, 0x9E, 0xC9, 0x08, + 0x46, 0x20, 0x00, 0x91, 0x84, 0x3E, 0xB4, 0x62, 0x96, 0x06, 0xFE, 0x5E, 0xD5, 0x0A, 0x5A, 0x18, + 0x01, 0x0B, 0x46, 0x20, 0x00, 0x91, 0x96, 0x06, 0xB4, 0x62, 0x94, 0x41, 0x84, 0x1D, 0xFE, 0x1E, + 0xFE, 0x0F, 0xB6, 0x02, 0xDD, 0x9E, 0xC8, 0x1D, 0xDD, 0x5E, 0x46, 0x0E, 0x0E, 0x0E, 0x50, 0x41, + 0x00, 0x64, 0xA0, 0xE1, 0x50, 0x00, 0x00, 0xE0, 0xFE, 0x1E, 0x44, 0x31, 0x01, 0x08, 0xFE, 0x1F, + 0xA8, 0x21, 0xA0, 0xE2, 0x84, 0x10, 0xFE, 0x1E, 0xA8, 0x22, 0x40, 0x10, 0xB8, 0x08, 0x40, 0x00, + 0xB8, 0x09, 0xB4, 0x24, 0x92, 0x32, 0x40, 0x10, 0xC8, 0x08, 0xFE, 0x47, 0xB6, 0x24, 0xDD, 0x9E, + 0x5A, 0x08, 0x01, 0x19, 0xEA, 0xCC, 0x46, 0x0E, 0x0E, 0x0E, 0x50, 0x30, 0x80, 0x64, 0xA0, 0x99, + 0x50, 0x00, 0x00, 0xE0, 0xFE, 0x16, 0xEB, 0x6A, 0xA8, 0x19, 0xA0, 0x9A, 0x84, 0x10, 0xFE, 0x16, + 0xA8, 0x1A, 0xB4, 0x03, 0x44, 0x21, 0x01, 0xD0, 0x92, 0x12, 0x40, 0x00, 0x48, 0x08, 0xFE, 0x17, + 0xB6, 0x03, 0xDD, 0x9E, 0x5A, 0x00, 0x01, 0x2E, 0xC0, 0x06, 0x5A, 0x00, 0x02, 0x1B, 0x5A, 0x00, + 0x03, 0x3B, 0xDD, 0x9E, 0xEA, 0xE7, 0xEA, 0xC5, 0xB4, 0x02, 0x44, 0x30, 0x98, 0x78, 0x96, 0x01, + 0x3C, 0x0F, 0xFC, 0x38, 0xB4, 0x01, 0x3E, 0x07, 0xF0, 0xDF, 0xB4, 0x02, 0x92, 0x10, 0xEA, 0x22, + 0xFE, 0x1F, 0xB6, 0x02, 0xB4, 0x01, 0x92, 0x08, 0xDD, 0x52, 0x58, 0x00, 0x00, 0x98, 0xD5, 0x21, + 0xEA, 0xE7, 0xEA, 0xC5, 0xB4, 0x02, 0x44, 0x30, 0x98, 0x78, 0x96, 0x01, 0x3C, 0x0F, 0xFC, 0x38, + 0xB4, 0x01, 0x3E, 0x07, 0xF0, 0xDF, 0xB4, 0x02, 0x92, 0x10, 0xEA, 0x22, 0xFE, 0x1F, 0xD5, 0x0D, + 0xEA, 0xE7, 0xEA, 0xC5, 0xB4, 0x02, 0x96, 0x01, 0x3C, 0x0F, 0xFC, 0x38, 0xB4, 0x01, 0x3E, 0x07, + 0xF0, 0xDF, 0xB4, 0x02, 0x92, 0x10, 0xEA, 0x22, 0xB6, 0x02, 0xB4, 0x01, 0x92, 0x08, 0xDD, 0x52, + 0xB6, 0x01, 0xDD, 0x9E, 0x44, 0x24, 0x50, 0x10, 0x2E, 0x17, 0xF0, 0xDF, 0xB4, 0x02, 0x92, 0x08, + 0xDD, 0x52, 0xFE, 0x0F, 0xB6, 0x02, 0xEA, 0xE7, 0x3C, 0x13, 0xF8, 0x70, 0xB4, 0x02, 0x92, 0x10, + 0xEA, 0x22, 0xFE, 0x0F, 0xB6, 0x02, 0xDD, 0x9E, 0xFC, 0x00, 0x44, 0x14, 0x2C, 0x1C, 0xEA, 0xA3, + 0xB4, 0x41, 0xFE, 0x16, 0x84, 0x41, 0xB6, 0x01, 0x80, 0x62, 0xEB, 0xA8, 0xEB, 0x52, 0xDD, 0x44, + 0xFC, 0x80, 0xFC, 0x00, 0xEA, 0xAA, 0xEA, 0x5E, 0xB4, 0x41, 0xFE, 0x17, 0xB6, 0x01, 0x44, 0x04, + 0x2C, 0x1C, 0x44, 0x1F, 0xFF, 0xEF, 0xB4, 0x40, 0xFE, 0x56, 0x84, 0x41, 0xB6, 0x20, 0x80, 0x62, + 0x80, 0x20, 0xDD, 0x44, 0xFC, 0x80, 0xFC, 0x00, 0x44, 0x24, 0x2C, 0x18, 0x46, 0x0B, 0x67, 0xFF, + 0xB4, 0x22, 0xDD, 0x42, 0xFE, 0x0E, 0x46, 0x10, 0x10, 0x00, 0xFE, 0x0F, 0xB6, 0x02, 0x84, 0x41, + 0x80, 0x62, 0x44, 0x04, 0x28, 0x18, 0x44, 0x14, 0x24, 0x18, 0xDD, 0x44, 0x44, 0x14, 0x2C, 0x20, + 0x44, 0x0F, 0xFF, 0xB3, 0xB4, 0x41, 0xFE, 0x16, 0x58, 0x00, 0x00, 0x48, 0x84, 0x41, 0xB6, 0x01, + 0x80, 0x62, 0x44, 0x04, 0x28, 0x20, 0x44, 0x14, 0x24, 0x20, 0xDD, 0x44, 0x44, 0x24, 0x2C, 0x1C, + 0x46, 0x0F, 0xFB, 0x3F, 0xB4, 0x22, 0xDD, 0x42, 0xFE, 0x0E, 0x46, 0x10, 0x04, 0x80, 0xFE, 0x0F, + 0xB6, 0x02, 0x84, 0x41, 0x80, 0x62, 0xEB, 0xA8, 0xEB, 0x52, 0xDD, 0x44, 0x44, 0x14, 0x50, 0x0C, + 0x84, 0x1E, 0xB4, 0x41, 0xFE, 0x16, 0xB6, 0x01, 0x84, 0x0F, 0xEA, 0xB4, 0xFC, 0x80, 0xFC, 0x00, + 0x44, 0x64, 0x2C, 0x1C, 0xEA, 0xA3, 0xB4, 0x26, 0x84, 0x41, 0xFE, 0x0E, 0x80, 0x62, 0xB6, 0x06, + 0xEB, 0x52, 0xEB, 0xA8, 0xDD, 0x44, 0x44, 0x14, 0x2C, 0x18, 0x46, 0x0B, 0x6F, 0xFF, 0xB4, 0x41, + 0xDD, 0x42, 0xFE, 0x16, 0x84, 0x41, 0xB6, 0x01, 0x80, 0x62, 0x44, 0x04, 0x28, 0x18, 0x44, 0x14, + 0x24, 0x18, 0xDD, 0x44, 0x44, 0x14, 0x2C, 0x20, 0x44, 0x0F, 0xFF, 0xB7, 0xB4, 0x41, 0xFE, 0x16, + 0x84, 0x41, 0xB6, 0x01, 0x80, 0x62, 0x44, 0x04, 0x28, 0x20, 0x44, 0x14, 0x24, 0x20, 0xDD, 0x44, + 0xB4, 0x26, 0x46, 0x0F, 0xFB, 0x7F, 0xDD, 0x42, 0xFE, 0x0E, 0x84, 0x41, 0xB6, 0x06, 0xEB, 0x52, + 0xEB, 0xA8, 0x80, 0x62, 0xDD, 0x44, 0x44, 0x14, 0x50, 0x0C, 0xB4, 0x01, 0xDD, 0x4B, 0xB6, 0x01, + 0xFC, 0x80, 0x44, 0x24, 0x70, 0x18, 0x94, 0x42, 0xB4, 0x62, 0x94, 0x01, 0xFE, 0x0F, 0x84, 0x39, + 0x54, 0x00, 0x00, 0x06, 0xFE, 0x5E, 0xFE, 0x0F, 0xB6, 0x02, 0xDD, 0x9E, 0x44, 0x04, 0x70, 0x04, + 0x84, 0x20, 0xB6, 0x20, 0x44, 0x04, 0x50, 0x10, 0x44, 0x10, 0x98, 0x98, 0xB6, 0x20, 0x44, 0x04, + 0x00, 0x10, 0xEB, 0xEA, 0xB6, 0x20, 0xDD, 0x9E, 0x44, 0x14, 0x00, 0x10, 0xB4, 0x01, 0x92, 0x10, + 0xEA, 0x22, 0xB6, 0x01, 0xEA, 0xAA, 0xEA, 0x29, 0xB4, 0x41, 0xFE, 0x16, 0xB6, 0x01, 0xEA, 0xC5, + 0xB4, 0x01, 0x92, 0x08, 0xDD, 0x52, 0xB6, 0x01, 0xB4, 0x41, 0x44, 0x0F, 0x00, 0xFF, 0xFE, 0x16, + 0xB6, 0x01, 0xDD, 0x9E, 0x44, 0x24, 0x70, 0x04, 0x44, 0x10, 0x89, 0x12, 0xB4, 0x02, 0x92, 0x10, + 0xEA, 0x22, 0xFE, 0x0F, 0xB6, 0x02, 0xDD, 0x9E, 0x44, 0x24, 0x00, 0x10, 0x96, 0x01, 0xB4, 0x22, + 0x92, 0x30, 0xEA, 0x28, 0xFE, 0x47, 0xB6, 0x22, 0xDD, 0x9E, 0x44, 0x14, 0x00, 0x8C, 0x46, 0x24, + 0xA8, 0x30, 0xB4, 0x01, 0x92, 0x08, 0xDD, 0x52, 0x58, 0x00, 0x00, 0x8A, 0xB6, 0x01, 0x44, 0x04, + 0x00, 0x20, 0xB6, 0x40, 0xB4, 0x01, 0x46, 0x28, 0xA0, 0x00, 0x92, 0x08, 0xDD, 0x52, 0xB6, 0x01, + 0x46, 0x00, 0x00, 0x80, 0x50, 0x30, 0x00, 0x3C, 0xB4, 0x23, 0xEA, 0x4F, 0x92, 0x28, 0xFE, 0x57, + 0xB6, 0x23, 0xB4, 0x23, 0x44, 0x27, 0x20, 0x00, 0xEB, 0xEB, 0xB6, 0x23, 0xB4, 0x23, 0x58, 0x10, + 0x80, 0x02, 0xB6, 0x23, 0xB4, 0x23, 0xEA, 0x4F, 0x92, 0x28, 0xB6, 0x23, 0xA0, 0x47, 0x92, 0x28, + 0xEA, 0x4F, 0x58, 0x10, 0x80, 0x07, 0xA8, 0x47, 0xB4, 0x62, 0x44, 0x1F, 0xFF, 0xEF, 0xFE, 0x5E, + 0x44, 0x37, 0x20, 0xC0, 0xB6, 0x22, 0xB4, 0x43, 0x44, 0x1F, 0xFD, 0xFF, 0xFE, 0x8E, 0xB6, 0x43, + 0x44, 0x37, 0x21, 0x00, 0xB4, 0x43, 0xFE, 0x8E, 0xB6, 0x43, 0x44, 0x27, 0x21, 0x40, 0xB4, 0x62, + 0xFE, 0x5E, 0xB6, 0x22, 0xA0, 0x87, 0x44, 0x1F, 0x07, 0xFF, 0xFE, 0x56, 0x58, 0x10, 0x90, 0x00, + 0xA8, 0x47, 0xDD, 0x9E, 0x44, 0x27, 0x20, 0x00, 0x96, 0x06, 0xB4, 0x62, 0x94, 0x44, 0xEA, 0xA3, + 0xFE, 0x1E, 0xFE, 0x0F, 0xB6, 0x02, 0xDD, 0x9E, 0xFC, 0x00, 0xEA, 0x56, 0xEA, 0x25, 0x83, 0x86, + 0xB9, 0x1C, 0xFE, 0x0E, 0xB8, 0x9C, 0xDD, 0x4C, 0xEA, 0x46, 0xB9, 0x1C, 0xEA, 0x5E, 0xFE, 0x0F, + 0xB8, 0x9C, 0xDD, 0x4C, 0xEA, 0x46, 0xB9, 0x1C, 0xEB, 0x3A, 0xFE, 0x0F, 0xB8, 0x9C, 0xDD, 0x4C, + 0xEA, 0x46, 0xFC, 0x80, 0x46, 0x00, 0x00, 0x81, 0x44, 0x1E, 0xFF, 0xFF, 0x04, 0x20, 0x00, 0x71, + 0x46, 0x30, 0x30, 0x00, 0xFE, 0x56, 0x14, 0x10, 0x00, 0x71, 0x04, 0x20, 0x00, 0x1A, 0x46, 0x1E, + 0x0F, 0xFF, 0xEA, 0x2B, 0xFE, 0x8E, 0xFE, 0x9F, 0x14, 0x20, 0x00, 0x1A, 0x04, 0x20, 0x00, 0x14, + 0xFE, 0x56, 0xFE, 0x5F, 0x14, 0x10, 0x00, 0x14, 0x04, 0x10, 0x00, 0x1A, 0x92, 0x25, 0x94, 0x4D, + 0x58, 0x10, 0x80, 0x02, 0x14, 0x10, 0x00, 0x1A, 0x04, 0x10, 0x00, 0x71, 0x92, 0x25, 0x94, 0x4D, + 0xEB, 0xEB, 0x14, 0x10, 0x00, 0x71, 0x04, 0x20, 0x00, 0x71, 0x44, 0x1F, 0xE0, 0xFF, 0xFE, 0x56, + 0x14, 0x10, 0x00, 0x71, 0xDD, 0x9E, 0xFC, 0x00, 0x44, 0x04, 0x2C, 0x10, 0x44, 0x1F, 0xFB, 0xFF, + 0xB4, 0x40, 0xFE, 0x56, 0xB6, 0x20, 0xB4, 0x20, 0x58, 0x10, 0x88, 0x00, 0xB6, 0x20, 0xB4, 0x40, + 0x44, 0x1F, 0x7F, 0xFF, 0xFE, 0x56, 0xB6, 0x20, 0xB4, 0x40, 0xEB, 0x47, 0xFE, 0x57, 0x84, 0x41, + 0xB6, 0x20, 0x80, 0x62, 0x44, 0x04, 0x28, 0x10, 0x44, 0x14, 0x24, 0x10, 0xDD, 0x44, 0xFC, 0x80, + 0xFC, 0x00, 0xEA, 0x56, 0x84, 0x41, 0xEB, 0x85, 0xB4, 0x1C, 0x80, 0x62, 0x92, 0x08, 0xDD, 0x52, + 0x58, 0x00, 0x00, 0x2D, 0xB6, 0x1C, 0xB4, 0x3C, 0x44, 0x0F, 0x80, 0xFF, 0xFE, 0x0E, 0x58, 0x00, + 0x15, 0x00, 0xB6, 0x1C, 0xEB, 0x9B, 0x50, 0x03, 0x0A, 0x94, 0xDD, 0x44, 0xB9, 0x01, 0x46, 0x0F, + 0xF7, 0xFF, 0xDD, 0x42, 0xFE, 0x0E, 0x84, 0x41, 0xB8, 0x81, 0x50, 0x13, 0x06, 0x98, 0x50, 0x03, + 0x0A, 0x98, 0x80, 0x62, 0xDD, 0x44, 0xFC, 0x80, 0xFC, 0x00, 0x80, 0x40, 0x5A, 0x08, 0x02, 0x4E, + 0xEA, 0x3B, 0xEA, 0x56, 0x44, 0x2F, 0x80, 0xFF, 0x50, 0x33, 0x0A, 0x94, 0xEB, 0x9B, 0x5A, 0x08, + 0x1F, 0x21, 0xEB, 0x85, 0xB4, 0x1C, 0xFE, 0x86, 0x58, 0x21, 0x15, 0x00, 0xB6, 0x5C, 0x84, 0x41, + 0x80, 0x03, 0x80, 0x62, 0xDD, 0x44, 0xB9, 0x01, 0xEA, 0x85, 0xDD, 0x42, 0xFE, 0x0E, 0x84, 0x41, + 0xB8, 0x81, 0x50, 0x13, 0x06, 0x98, 0x50, 0x03, 0x0A, 0x98, 0x80, 0x62, 0xDD, 0x44, 0x44, 0x24, + 0x2C, 0x34, 0x44, 0x08, 0xFF, 0xFF, 0xB4, 0x22, 0xFE, 0x0E, 0x44, 0x13, 0x00, 0x00, 0xD5, 0x1E, + 0xEB, 0x85, 0xB4, 0x1C, 0xFE, 0x86, 0x58, 0x21, 0x1A, 0x00, 0xB6, 0x5C, 0x84, 0x41, 0x80, 0x03, + 0x80, 0x62, 0xDD, 0x44, 0xB9, 0x01, 0xEA, 0x85, 0xDD, 0x42, 0xFE, 0x0E, 0x84, 0x41, 0xB8, 0x81, + 0x50, 0x13, 0x06, 0x98, 0x50, 0x03, 0x0A, 0x98, 0x80, 0x62, 0xDD, 0x44, 0x44, 0x24, 0x2C, 0x34, + 0x44, 0x08, 0xFF, 0xFF, 0xB4, 0x22, 0xFE, 0x0E, 0xEB, 0x47, 0xFE, 0x0F, 0xB6, 0x02, 0x44, 0x14, + 0x24, 0x34, 0x44, 0x04, 0x28, 0x34, 0xD5, 0x12, 0xC8, 0x13, 0xEA, 0xCC, 0xEB, 0xFB, 0x50, 0x30, + 0x8E, 0x98, 0xB4, 0x43, 0xDD, 0x42, 0xFE, 0x16, 0xB6, 0x03, 0xB4, 0x43, 0xEB, 0x2C, 0xFE, 0x17, + 0xB6, 0x03, 0x50, 0x00, 0x8A, 0x98, 0x50, 0x10, 0x86, 0x98, 0x84, 0x41, 0xD5, 0x12, 0x5A, 0x08, + 0x01, 0x13, 0xEA, 0xCC, 0xEB, 0x1A, 0x50, 0x40, 0x8E, 0x98, 0xB4, 0x64, 0xFE, 0x1F, 0xB6, 0x04, + 0xB4, 0x64, 0xEB, 0x2C, 0xFE, 0x1F, 0xB6, 0x04, 0x50, 0x00, 0x8A, 0x98, 0x50, 0x10, 0x86, 0x98, + 0x80, 0x62, 0xDD, 0x44, 0xFC, 0x80, 0x46, 0x00, 0x00, 0x81, 0x46, 0x30, 0xB0, 0x00, 0x04, 0x10, + 0x00, 0x77, 0x92, 0x25, 0x94, 0x4D, 0x58, 0x10, 0x80, 0x1E, 0x14, 0x10, 0x00, 0x77, 0x04, 0x20, + 0x00, 0x76, 0x46, 0x1E, 0x0F, 0xFF, 0xEA, 0x2B, 0xFE, 0x8E, 0xFE, 0x9F, 0x14, 0x20, 0x00, 0x76, + 0x04, 0x40, 0x00, 0x78, 0x46, 0x2F, 0x83, 0xFF, 0xEB, 0x11, 0xFE, 0xA6, 0x46, 0x40, 0x1C, 0x00, + 0xFE, 0xA7, 0x14, 0x20, 0x00, 0x78, 0x04, 0x20, 0x00, 0x1B, 0xFE, 0x56, 0xFE, 0x5F, 0x14, 0x10, + 0x00, 0x1B, 0xDD, 0x9E, 0xFC, 0x00, 0xDD, 0x49, 0xC0, 0x18, 0xEA, 0xB0, 0xE6, 0x05, 0xE8, 0x0A, + 0x84, 0x61, 0x84, 0x09, 0xFA, 0x2F, 0x44, 0x20, 0x00, 0x82, 0x44, 0x40, 0x00, 0xE8, 0x80, 0xA3, + 0xDD, 0x5D, 0x84, 0x61, 0x84, 0x05, 0xFA, 0x2F, 0xEB, 0xA4, 0x44, 0x40, 0x00, 0xFF, 0x80, 0xA3, + 0xDD, 0x5D, 0x49, 0xFF, 0xFF, 0xC2, 0xFC, 0x80, 0xEA, 0xB0, 0xE6, 0x05, 0xE8, 0x0A, 0x84, 0x61, + 0x84, 0x09, 0xFA, 0x2F, 0x44, 0x20, 0x00, 0x82, 0x44, 0x40, 0x00, 0xC0, 0x80, 0xA3, 0xDD, 0x5D, + 0x84, 0x61, 0x84, 0x05, 0xFA, 0x2F, 0xEB, 0xA4, 0x44, 0x40, 0x00, 0xF0, 0x80, 0xA3, 0xDD, 0x5D, + 0xFC, 0x80, 0xFC, 0x00, 0xEA, 0x56, 0x84, 0x00, 0x3C, 0x1D, 0xF6, 0x3E, 0x49, 0xFF, 0xFC, 0xED, + 0x83, 0x86, 0xB9, 0x1C, 0xEA, 0x5F, 0xDD, 0x42, 0xFE, 0x0E, 0xB8, 0x9C, 0xDD, 0x4C, 0xEA, 0x46, + 0xB9, 0x1C, 0xEA, 0x29, 0xFE, 0x0E, 0xB8, 0x9C, 0xDD, 0x4C, 0xEA, 0x46, 0xB8, 0x1C, 0xEA, 0xA1, + 0xB8, 0x9C, 0xDD, 0x4C, 0xEA, 0x46, 0xB9, 0x1C, 0xEB, 0x1A, 0xFE, 0x0F, 0xB8, 0x9C, 0x44, 0x00, + 0x01, 0x2C, 0xEA, 0x2D, 0xB9, 0x1C, 0xEB, 0xFB, 0xDD, 0x42, 0xFE, 0x0E, 0xB8, 0x9C, 0xEA, 0x3B, + 0x5A, 0x08, 0x1C, 0x0E, 0xEA, 0xB0, 0xE6, 0x03, 0xE8, 0x0A, 0x84, 0x61, 0x84, 0x04, 0xFA, 0x2F, + 0x44, 0x20, 0x00, 0xB8, 0x44, 0x40, 0x00, 0x45, 0x80, 0xA3, 0xDD, 0x5D, 0xEB, 0x8B, 0xFC, 0x80, + 0x46, 0x10, 0x00, 0x80, 0x50, 0x50, 0x80, 0x80, 0x50, 0x10, 0x80, 0xB0, 0xA2, 0x81, 0xAA, 0xA9, + 0xD9, 0xFE, 0xDD, 0x9E, 0x46, 0x10, 0x00, 0x80, 0x50, 0x50, 0x80, 0xB0, 0x50, 0x10, 0x80, 0xC4, + 0xA2, 0x81, 0xAA, 0xA9, 0xD9, 0xFE, 0xDD, 0x9E, 0xB4, 0x40, 0x46, 0x30, 0x00, 0x80, 0xA0, 0x41, + 0x14, 0x21, 0x80, 0x47, 0xA0, 0x82, 0x40, 0x10, 0xA8, 0x08, 0xA0, 0x03, 0x14, 0x21, 0x80, 0x48, + 0x40, 0x20, 0xA8, 0x09, 0x04, 0x11, 0x80, 0x49, 0xEA, 0x21, 0x92, 0x36, 0x40, 0x10, 0xD8, 0x08, + 0xFE, 0x57, 0x14, 0x11, 0x80, 0x49, 0x40, 0x10, 0x28, 0x09, 0x04, 0x01, 0x80, 0x57, 0x92, 0x16, + 0x40, 0x00, 0x58, 0x08, 0xFE, 0x0F, 0x14, 0x01, 0x80, 0x57, 0xDD, 0x9E, 0x46, 0x10, 0x00, 0x80, + 0x50, 0x50, 0x80, 0x40, 0x50, 0x30, 0x80, 0x46, 0xA6, 0x41, 0xA6, 0x80, 0x94, 0x4C, 0xFE, 0x57, + 0x96, 0x48, 0xAE, 0x68, 0x00, 0x10, 0x00, 0x0D, 0x00, 0x20, 0x00, 0x0C, 0x94, 0x4C, 0xFE, 0x57, + 0x96, 0x48, 0x10, 0x12, 0x80, 0x0C, 0x8C, 0xA1, 0x8C, 0x02, 0xDB, 0xEF, 0xDD, 0x9E, 0xA6, 0x81, + 0x80, 0xA0, 0x94, 0x94, 0x08, 0x12, 0x80, 0x05, 0xFE, 0x8F, 0xEB, 0x72, 0x96, 0x90, 0x10, 0x20, + 0x80, 0x48, 0xA6, 0xA9, 0xA6, 0xC5, 0x94, 0x94, 0xFE, 0x9F, 0x96, 0x90, 0x10, 0x20, 0x80, 0x54, + 0xA6, 0x83, 0xA6, 0xC2, 0x94, 0x94, 0xFE, 0x9F, 0x96, 0x90, 0x10, 0x20, 0x80, 0x49, 0xA6, 0xAB, + 0xA6, 0xEA, 0x94, 0x94, 0xFE, 0x9F, 0x96, 0x90, 0x10, 0x20, 0x80, 0x55, 0xA6, 0x84, 0x84, 0x0F, + 0xFE, 0x86, 0x40, 0x31, 0x40, 0x08, 0x46, 0x4F, 0xFF, 0x0F, 0x04, 0x20, 0x80, 0x12, 0x50, 0x42, + 0x0F, 0xFF, 0xFE, 0xA6, 0xFE, 0x9F, 0x14, 0x20, 0x80, 0x12, 0xA6, 0xAC, 0xFE, 0x16, 0x40, 0x20, + 0x40, 0x08, 0x04, 0x00, 0x80, 0x15, 0xFE, 0x26, 0xFE, 0x17, 0x14, 0x00, 0x80, 0x15, 0xDD, 0x9E, + 0x5A, 0x00, 0x02, 0x16, 0xE6, 0x03, 0xE8, 0x03, 0xC0, 0x07, 0xDD, 0x9E, 0x5A, 0x00, 0x03, 0x26, + 0x5A, 0x00, 0x04, 0x16, 0xDD, 0x9E, 0xDD, 0x5E, 0xEB, 0xA5, 0x04, 0x01, 0x00, 0x20, 0x92, 0x0B, + 0x40, 0x00, 0x2C, 0x08, 0xFE, 0x47, 0x14, 0x11, 0x00, 0x20, 0xDD, 0x9E, 0xDD, 0x5E, 0xEB, 0xA5, + 0x04, 0x01, 0x00, 0x21, 0x92, 0x0B, 0x40, 0x00, 0x2C, 0x08, 0xD5, 0x0B, 0xDD, 0x5E, 0xEB, 0xA5, + 0x40, 0x00, 0xC0, 0x08, 0x04, 0x31, 0x00, 0x21, 0x46, 0x1F, 0x80, 0x0F, 0xEA, 0x2B, 0xFE, 0x5E, + 0xFE, 0x47, 0x14, 0x11, 0x00, 0x21, 0xDD, 0x9E, 0xFC, 0x00, 0x80, 0xC1, 0xEB, 0x32, 0xDD, 0x5E, + 0x54, 0x13, 0x07, 0xFF, 0x95, 0x8E, 0x04, 0x11, 0x03, 0x98, 0x44, 0x0E, 0x00, 0x3F, 0xFE, 0x46, + 0xFE, 0x77, 0x14, 0x11, 0x03, 0x98, 0xEB, 0xAA, 0xFC, 0x80, 0x46, 0x20, 0x00, 0x83, 0x96, 0x06, + 0xEA, 0xE0, 0x04, 0x31, 0x00, 0xC0, 0xEA, 0x5F, 0xDD, 0x42, 0xFE, 0x1E, 0xFE, 0x0F, 0x14, 0x01, + 0x00, 0xC0, 0xDD, 0x9E, 0x46, 0x20, 0x00, 0x83, 0x96, 0x06, 0x40, 0x10, 0x64, 0x08, 0x04, 0x31, + 0x00, 0xC0, 0xEA, 0x85, 0xDD, 0x42, 0xFE, 0x1E, 0xFE, 0x0F, 0x14, 0x01, 0x00, 0xC0, 0xDD, 0x9E, + 0x46, 0x20, 0x00, 0x83, 0x96, 0x0F, 0xEB, 0xC4, 0xDD, 0x56, 0x44, 0x0F, 0xFC, 0xFF, 0xFE, 0x1E, + 0xFE, 0x0F, 0xEB, 0xCD, 0xDD, 0x9E, 0x46, 0x20, 0x00, 0x83, 0x84, 0x3E, 0xEB, 0xC4, 0x96, 0x06, + 0xFE, 0x5E, 0xFE, 0x0F, 0xEB, 0xCD, 0xDD, 0x9E, 0x46, 0x20, 0x00, 0x83, 0x96, 0x06, 0xEB, 0xC4, + 0xEB, 0x28, 0x44, 0x0F, 0xFB, 0xFF, 0xFE, 0x1E, 0xFE, 0x0F, 0xEB, 0xCD, 0xDD, 0x9E, 0x46, 0x10, + 0x00, 0x83, 0xEA, 0x5E, 0x04, 0x20, 0x80, 0x0E, 0xFE, 0x17, 0x14, 0x00, 0x80, 0x0E, 0xDD, 0x9E, + 0x46, 0x10, 0x00, 0x83, 0x46, 0x2E, 0x7F, 0xFF, 0x04, 0x30, 0x80, 0x0E, 0xEB, 0x11, 0xFE, 0x9E, + 0x14, 0x20, 0x80, 0x0E, 0x5A, 0x08, 0x01, 0x13, 0x84, 0x1F, 0x14, 0x00, 0x80, 0x0B, 0x14, 0x00, + 0x80, 0x0C, 0x04, 0x20, 0x80, 0x30, 0xEB, 0xB7, 0xFE, 0x17, 0x14, 0x00, 0x80, 0x30, 0x04, 0x20, + 0x80, 0x30, 0x44, 0x0F, 0x00, 0x00, 0xFE, 0x17, 0xD5, 0x0F, 0x84, 0x00, 0x14, 0x00, 0x80, 0x0B, + 0x14, 0x00, 0x80, 0x0C, 0x04, 0x00, 0x80, 0x30, 0x92, 0x10, 0xEA, 0x22, 0x14, 0x00, 0x80, 0x30, + 0x04, 0x00, 0x80, 0x30, 0x96, 0x01, 0x14, 0x00, 0x80, 0x30, 0xDD, 0x9E, 0x46, 0x20, 0x00, 0x83, + 0xDD, 0x56, 0x04, 0x31, 0x00, 0x0E, 0x40, 0x00, 0x24, 0x08, 0xFE, 0x0F, 0x44, 0x1F, 0xFC, 0xFF, + 0x54, 0x00, 0x03, 0x00, 0xFE, 0x5E, 0xFE, 0x0F, 0x14, 0x01, 0x00, 0x0E, 0xDD, 0x9E, 0x46, 0x20, + 0x00, 0x81, 0x50, 0x51, 0x00, 0x90, 0x50, 0x31, 0x00, 0x9A, 0x08, 0x20, 0x00, 0x01, 0x88, 0x41, + 0x96, 0x90, 0x18, 0x22, 0x80, 0x01, 0xDB, 0xFA, 0xDD, 0x9E, 0xFC, 0x40, 0x84, 0x60, 0x80, 0x43, + 0x80, 0xC3, 0x46, 0x70, 0x00, 0x80, 0x8C, 0x21, 0x85, 0x2F, 0xB4, 0xA7, 0x95, 0x1A, 0x40, 0x52, + 0x90, 0x0D, 0x97, 0x57, 0xD9, 0x07, 0x40, 0x50, 0x10, 0x0C, 0x40, 0x44, 0x90, 0x0C, 0xFF, 0xAF, + 0xFE, 0xA7, 0x8C, 0x61, 0x5A, 0x38, 0x08, 0xF3, 0xEA, 0xCC, 0xFE, 0xD3, 0x83, 0x81, 0xB8, 0x23, + 0xFE, 0xB6, 0xFE, 0x1E, 0xFE, 0x87, 0xBA, 0xA3, 0xFC, 0xC0, 0x46, 0x10, 0x00, 0x81, 0x04, 0x00, + 0x80, 0x12, 0x92, 0x10, 0x96, 0x0F, 0xC8, 0x08, 0x04, 0x00, 0x80, 0x12, 0x92, 0x08, 0x96, 0x06, + 0x56, 0x00, 0x00, 0x01, 0xDD, 0x9E, 0x84, 0x01, 0xDD, 0x9E, 0x46, 0x20, 0x00, 0x81, 0x54, 0x00, + 0x03, 0xFF, 0xEA, 0x24, 0x04, 0x31, 0x00, 0x49, 0x46, 0x0F, 0xC0, 0x0F, 0xDD, 0x42, 0xFE, 0x1E, + 0xFE, 0x0F, 0x14, 0x01, 0x00, 0x49, 0xDD, 0x9E, 0x46, 0x20, 0x00, 0x80, 0x54, 0x00, 0x03, 0xFF, + 0x04, 0x11, 0x00, 0x75, 0x92, 0x2A, 0x40, 0x10, 0xA8, 0x08, 0xFE, 0x47, 0x14, 0x11, 0x00, 0x75, + 0xDD, 0x9E, 0x5A, 0x00, 0x02, 0x20, 0xE6, 0x03, 0xE8, 0x03, 0xC0, 0x07, 0xDD, 0x9E, 0x5A, 0x00, + 0x03, 0x24, 0x5A, 0x00, 0x04, 0x0D, 0xDD, 0x9E, 0xDD, 0x5E, 0xEA, 0xBC, 0x04, 0x01, 0x00, 0x30, + 0x92, 0x0A, 0xEA, 0x21, 0xFE, 0x47, 0x14, 0x11, 0x00, 0x30, 0xDD, 0x9E, 0xDD, 0x5E, 0xEA, 0xBC, + 0x40, 0x00, 0xC0, 0x08, 0x04, 0x31, 0x00, 0x31, 0x46, 0x1F, 0xC0, 0x0F, 0xEA, 0x2B, 0xFE, 0x5E, + 0xD5, 0x07, 0xDD, 0x5E, 0xEA, 0xBC, 0x04, 0x01, 0x00, 0x31, 0x92, 0x0A, 0xEA, 0x21, 0xFE, 0x47, + 0x14, 0x11, 0x00, 0x31, 0xDD, 0x9E, 0xFC, 0x00, 0x80, 0xC1, 0xEB, 0x32, 0xEA, 0x87, 0x54, 0x13, + 0x03, 0xFF, 0x40, 0x60, 0xC4, 0x08, 0x04, 0x20, 0x03, 0x98, 0x46, 0x1F, 0x80, 0x1F, 0xEA, 0x2B, + 0xFE, 0x56, 0xFE, 0x77, 0x14, 0x10, 0x03, 0x98, 0xEB, 0xAA, 0xFC, 0x80, 0x54, 0x20, 0x80, 0x03, + 0x54, 0x10, 0x80, 0x0C, 0x90, 0x22, 0x5A, 0x00, 0x01, 0x16, 0xC0, 0x04, 0x5A, 0x00, 0x02, 0x28, + 0xDD, 0x9E, 0xEA, 0x87, 0x84, 0x7C, 0x50, 0x50, 0x00, 0x9C, 0xB4, 0x85, 0xEB, 0xD8, 0xFE, 0xE6, + 0xFE, 0x5F, 0xB6, 0x25, 0xB4, 0x65, 0x44, 0x1C, 0xFF, 0xFF, 0xFE, 0x5E, 0xFE, 0x8F, 0xB6, 0x45, + 0xDD, 0x9E, 0x46, 0x30, 0x00, 0x81, 0x44, 0x0F, 0xFF, 0xCF, 0x50, 0x51, 0x80, 0x9C, 0xB4, 0x85, + 0x94, 0x4C, 0xFE, 0x26, 0xFE, 0x47, 0xB6, 0x25, 0xB4, 0x05, 0x46, 0x1F, 0xFC, 0xFF, 0xEA, 0x2B, + 0x40, 0x21, 0x50, 0x08, 0xFE, 0x0E, 0xFE, 0x17, 0xB6, 0x05, 0xDD, 0x9E, 0x46, 0x30, 0x00, 0x81, + 0x44, 0x0F, 0xFF, 0x3F, 0x50, 0x51, 0x80, 0x9C, 0xB4, 0x85, 0x94, 0x4E, 0xFE, 0x26, 0xFE, 0x47, + 0xB6, 0x25, 0xB4, 0x25, 0x46, 0x0F, 0xF3, 0xFF, 0xDD, 0x42, 0x40, 0x21, 0x58, 0x08, 0xFE, 0x0E, + 0xFE, 0x87, 0xB6, 0x45, 0xDD, 0x9E, 0x5A, 0x00, 0x01, 0x0D, 0xC0, 0x04, 0x5A, 0x00, 0x02, 0x12, + 0xDD, 0x9E, 0xDD, 0x5E, 0x84, 0x1C, 0x04, 0x31, 0x00, 0x28, 0x96, 0x4F, 0xFE, 0x1E, 0xD5, 0x11, + 0xDD, 0x5E, 0x96, 0x4F, 0x94, 0x0C, 0x04, 0x31, 0x00, 0x28, 0x44, 0x1F, 0xFF, 0xCF, 0xD5, 0x08, + 0xDD, 0x5E, 0x96, 0x4F, 0x94, 0x0E, 0x04, 0x31, 0x00, 0x28, 0x44, 0x1F, 0xFF, 0x3F, 0xFE, 0x5E, + 0xFE, 0x47, 0x14, 0x11, 0x00, 0x28, 0xDD, 0x9E, 0x46, 0x10, 0x00, 0x81, 0x04, 0x20, 0x80, 0x12, + 0x5A, 0x08, 0x01, 0x06, 0xEA, 0x5F, 0xDD, 0x42, 0xFE, 0x16, 0xD5, 0x03, 0xEB, 0x3A, 0xFE, 0x17, + 0x14, 0x00, 0x80, 0x12, 0xDD, 0x9E, 0x46, 0x00, 0x00, 0x81, 0xEB, 0xF4, 0x92, 0x0B, 0x96, 0x27, + 0xDD, 0x9E, 0xFC, 0x00, 0x84, 0x20, 0x46, 0x40, 0x00, 0x80, 0x80, 0x61, 0x50, 0x62, 0x10, 0x8C, + 0xB4, 0x44, 0x95, 0x4A, 0x40, 0x21, 0x14, 0x0D, 0x54, 0x21, 0x00, 0x05, 0xC2, 0x09, 0xB4, 0x06, + 0x40, 0x00, 0x14, 0x0D, 0x96, 0x1F, 0xE2, 0x03, 0x40, 0x01, 0xBC, 0x1B, 0x80, 0x60, 0x8C, 0x21, + 0x5A, 0x18, 0x08, 0xF0, 0xEA, 0x87, 0x50, 0x00, 0x00, 0x90, 0x88, 0x03, 0xA6, 0x00, 0x96, 0x2F, + 0x8C, 0x01, 0xFC, 0x80, 0x84, 0x40, 0x46, 0x30, 0x00, 0x80, 0x80, 0x02, 0x50, 0x41, 0x90, 0x80, + 0xB4, 0x23, 0x95, 0x52, 0x40, 0x10, 0x94, 0x0D, 0x96, 0x48, 0x54, 0x50, 0x80, 0x05, 0xC5, 0x12, + 0x96, 0x57, 0x8E, 0x21, 0x96, 0x48, 0x40, 0x50, 0x84, 0x09, 0x95, 0x6A, 0x88, 0xA4, 0x96, 0x46, + 0xB4, 0xA5, 0x94, 0x4C, 0x40, 0x12, 0x84, 0x0D, 0xEB, 0xA5, 0xE2, 0x20, 0x40, 0x10, 0x3C, 0x1B, + 0x80, 0x01, 0x8C, 0x41, 0x5A, 0x28, 0x08, 0xE6, 0xDD, 0x9E, 0xFC, 0x40, 0x80, 0xC0, 0xEA, 0x87, + 0x80, 0xE0, 0x04, 0x10, 0x00, 0x12, 0x92, 0x28, 0x96, 0x46, 0xC1, 0x09, 0x04, 0x13, 0x80, 0xF5, + 0x46, 0x90, 0x00, 0x81, 0x92, 0x2B, 0x96, 0x67, 0xC1, 0x05, 0xD5, 0x62, 0xDD, 0x41, 0xC8, 0xF7, + 0xFC, 0xC0, 0x49, 0xFF, 0xF8, 0xA4, 0x04, 0xA4, 0x83, 0x92, 0x49, 0xFF, 0xF8, 0xB0, 0x49, 0xFF, + 0xFF, 0xA2, 0x80, 0xE0, 0x49, 0xFF, 0xFF, 0xC0, 0xFE, 0x3C, 0x95, 0xC1, 0x97, 0xF9, 0xDD, 0x41, + 0xC8, 0x15, 0x44, 0x20, 0x00, 0x4D, 0x50, 0x73, 0x83, 0x9D, 0xFF, 0xD4, 0x44, 0x1F, 0x22, 0x06, + 0x44, 0x20, 0x00, 0x33, 0x40, 0x03, 0x88, 0x16, 0x99, 0xB9, 0x50, 0x00, 0x00, 0x45, 0x40, 0x63, + 0x08, 0xD6, 0x96, 0x01, 0x50, 0x63, 0x00, 0x45, 0xD5, 0x24, 0x04, 0x04, 0x80, 0x12, 0x40, 0x35, + 0x64, 0x09, 0x92, 0x18, 0x40, 0x65, 0x48, 0x09, 0x96, 0x06, 0x96, 0xEF, 0x54, 0x63, 0x00, 0x7E, + 0xC0, 0x1A, 0x50, 0x23, 0x80, 0x8A, 0x50, 0x03, 0x83, 0xC5, 0x99, 0xD3, 0x44, 0x10, 0x00, 0x4D, + 0x88, 0xE6, 0xFE, 0x0C, 0x44, 0x40, 0x00, 0x33, 0x50, 0x73, 0x80, 0x36, 0x40, 0x00, 0x10, 0x16, + 0xFE, 0x7C, 0x50, 0x00, 0x00, 0x27, 0x40, 0x60, 0x90, 0xD6, 0x96, 0x01, 0x50, 0x63, 0x00, 0x27, + 0x97, 0xB1, 0xD5, 0x11, 0x50, 0x03, 0x83, 0x8F, 0x88, 0x60, 0x88, 0xC3, 0x44, 0x00, 0x00, 0x4D, + 0x8C, 0xD3, 0xFF, 0x84, 0x44, 0x00, 0x00, 0x33, 0x40, 0x63, 0x00, 0xD6, 0x50, 0x63, 0x00, 0x59, + 0x97, 0xB1, 0x80, 0x06, 0x8C, 0x02, 0x8C, 0xC2, 0x96, 0x01, 0x97, 0xB1, 0xD5, 0x15, 0xDD, 0x41, + 0xC8, 0x07, 0xC6, 0x0B, 0x44, 0x60, 0x25, 0x51, 0x44, 0x00, 0x29, 0xA4, 0xD5, 0x0A, 0x44, 0x60, + 0x24, 0xEC, 0x44, 0x00, 0x29, 0x3F, 0xD5, 0x05, 0x44, 0x60, 0x11, 0xC2, 0x44, 0x00, 0x16, 0x15, + 0x84, 0x21, 0x3E, 0x17, 0xF0, 0xC2, 0xEB, 0x55, 0x80, 0x06, 0x49, 0xFF, 0xF3, 0x2B, 0xFC, 0xC0, + 0x44, 0x36, 0x20, 0x04, 0x46, 0x1F, 0xF0, 0x0F, 0xB4, 0x43, 0xEA, 0x2B, 0xFE, 0x56, 0x46, 0x20, + 0x0A, 0x30, 0xFE, 0x57, 0xB6, 0x23, 0x44, 0x14, 0x80, 0x80, 0x84, 0x68, 0xB4, 0x41, 0x58, 0x21, + 0x08, 0x00, 0xB6, 0x41, 0x44, 0x24, 0x80, 0x01, 0xAE, 0xD0, 0xB4, 0x81, 0x44, 0x3F, 0xEF, 0xFF, + 0xFE, 0xE6, 0xB6, 0x61, 0xFA, 0x60, 0xAE, 0xD0, 0xB4, 0x61, 0x58, 0x31, 0x82, 0x00, 0xB6, 0x61, + 0x84, 0x62, 0xAE, 0xD0, 0xB4, 0x61, 0x58, 0x31, 0x81, 0x00, 0xB6, 0x61, 0x84, 0x61, 0xAE, 0xD0, + 0xB4, 0x81, 0x44, 0x3F, 0xFB, 0xFF, 0xFE, 0xE6, 0xB6, 0x61, 0x84, 0x24, 0xAE, 0x50, 0x44, 0x16, + 0x20, 0x00, 0x5A, 0x00, 0x02, 0x12, 0x5A, 0x00, 0x03, 0x17, 0x5A, 0x00, 0x01, 0x06, 0xB4, 0x41, + 0x84, 0x1E, 0xFE, 0x16, 0xD5, 0x03, 0xB4, 0x01, 0xDD, 0x4B, 0xB6, 0x01, 0xB4, 0x41, 0x84, 0x1D, + 0xFE, 0x16, 0xB6, 0x01, 0xD5, 0x09, 0xB4, 0x41, 0x84, 0x1E, 0xFE, 0x16, 0xB6, 0x01, 0xB4, 0x01, + 0xEA, 0x39, 0xD5, 0xF8, 0xAE, 0x08, 0x44, 0x16, 0x20, 0x00, 0x46, 0x08, 0x00, 0x00, 0xB4, 0x41, + 0xFE, 0x17, 0xB6, 0x01, 0x44, 0x16, 0x20, 0x0C, 0xEA, 0x25, 0xB4, 0x41, 0xFE, 0x16, 0xB6, 0x01, + 0xB4, 0x41, 0x46, 0x0F, 0xF0, 0x0F, 0xDD, 0x42, 0xFE, 0x16, 0x46, 0x20, 0x04, 0x00, 0xFE, 0x17, + 0xB6, 0x01, 0xDD, 0x9E, 0xFC, 0x00, 0x2E, 0x07, 0xF0, 0xE4, 0xC0, 0x0A, 0xFA, 0x01, 0x44, 0x10, + 0x03, 0x20, 0xEA, 0x31, 0xFA, 0x01, 0x84, 0x21, 0xDD, 0x47, 0x84, 0x01, 0xEB, 0x6F, 0x44, 0x14, + 0x80, 0x00, 0xB4, 0x01, 0x92, 0x0B, 0x96, 0x06, 0xC0, 0x04, 0xEA, 0xAE, 0x84, 0x48, 0xAE, 0x80, + 0xB4, 0x01, 0x92, 0x0C, 0x96, 0x06, 0xC0, 0x04, 0xEA, 0xAE, 0xFA, 0x20, 0xAE, 0x40, 0x44, 0x04, + 0x80, 0x00, 0xB4, 0x00, 0x92, 0x09, 0x96, 0x06, 0xC0, 0x22, 0x2E, 0x07, 0xF0, 0xE4, 0xC8, 0x0D, + 0x44, 0x16, 0x20, 0x08, 0xB4, 0x01, 0x92, 0x08, 0x96, 0x00, 0x5A, 0x08, 0xA3, 0x10, 0xB4, 0x01, + 0x92, 0x10, 0x96, 0x00, 0x5A, 0x08, 0xA3, 0x0B, 0xFA, 0x01, 0x44, 0x10, 0x03, 0x20, 0xEA, 0x31, + 0xFA, 0x01, 0x84, 0x21, 0xDD, 0x47, 0x84, 0x01, 0xEB, 0x6F, 0xEA, 0xAE, 0x84, 0x22, 0xAE, 0x40, + 0x84, 0x01, 0xEB, 0x10, 0x84, 0x02, 0xEB, 0x10, 0x49, 0x00, 0x14, 0x64, 0x44, 0x14, 0x80, 0x00, + 0xB4, 0x01, 0x92, 0x08, 0x96, 0x06, 0xC0, 0x04, 0xEA, 0xAE, 0x84, 0x41, 0xAE, 0x80, 0xB4, 0x01, + 0x92, 0x0A, 0x96, 0x06, 0xC0, 0x04, 0xEA, 0xAE, 0x84, 0x24, 0xAE, 0x40, 0xFC, 0x80, 0x44, 0x26, + 0x20, 0x04, 0x96, 0x06, 0xEA, 0xE0, 0xB4, 0x62, 0xEA, 0x5F, 0xDD, 0x42, 0xFE, 0x1E, 0xFE, 0x0F, + 0xB6, 0x02, 0xDD, 0x9E, 0x44, 0x06, 0x20, 0x10, 0xB4, 0x00, 0x92, 0x01, 0x96, 0x06, 0xDD, 0x9E, + 0x44, 0x06, 0x20, 0x10, 0xB4, 0x00, 0x96, 0x06, 0xDD, 0x9E, 0x44, 0x04, 0x40, 0x0C, 0xB4, 0x00, + 0x92, 0x01, 0x96, 0x06, 0xDD, 0x9E, 0xC8, 0x04, 0x44, 0x07, 0x20, 0x14, 0xD5, 0x03, 0x44, 0x07, + 0x20, 0x18, 0xB4, 0x00, 0xEA, 0x8F, 0x92, 0x0C, 0xDD, 0x9E, 0xC8, 0x04, 0x44, 0x07, 0x20, 0x0C, + 0xD5, 0x03, 0x44, 0x07, 0x20, 0x10, 0xB4, 0x00, 0xEA, 0x8F, 0x92, 0x0C, 0xDD, 0x9E, 0xFC, 0x00, + 0x80, 0xC1, 0xEA, 0x52, 0x84, 0x40, 0x80, 0x22, 0xE2, 0x46, 0xE8, 0x05, 0x38, 0x10, 0x09, 0x09, + 0x8C, 0x41, 0xD5, 0xFB, 0xFC, 0x80, 0xFC, 0x00, 0x80, 0xC1, 0xEA, 0x52, 0x84, 0x40, 0xEB, 0x6B, + 0x80, 0x22, 0xE2, 0x46, 0xE8, 0x05, 0x1A, 0x10, 0x00, 0x01, 0x8C, 0x41, 0xD5, 0xFB, 0xFC, 0x80, + 0x44, 0x27, 0x20, 0x14, 0xEA, 0x8F, 0xEB, 0x62, 0xB4, 0x02, 0x92, 0x14, 0xEB, 0x17, 0xFE, 0x0F, + 0xB6, 0x02, 0xDD, 0x9E, 0x44, 0x27, 0x20, 0x18, 0xEA, 0x8F, 0xEB, 0x62, 0xB4, 0x02, 0x92, 0x14, + 0xEB, 0x17, 0xFE, 0x0F, 0xB6, 0x02, 0xDD, 0x9E, 0x44, 0x27, 0x20, 0x1C, 0xEA, 0x69, 0xB4, 0x22, + 0x92, 0x2C, 0xEB, 0x4F, 0xFE, 0x47, 0xB6, 0x22, 0xDD, 0x9E, 0x44, 0x27, 0x20, 0x20, 0xEA, 0x69, + 0xB4, 0x22, 0x92, 0x2C, 0xEB, 0x4F, 0xFE, 0x47, 0xB6, 0x22, 0xDD, 0x9E, 0x44, 0x27, 0x20, 0x34, + 0xEA, 0x69, 0xB4, 0x22, 0x92, 0x2C, 0xEB, 0x4F, 0xFE, 0x47, 0xB6, 0x22, 0xDD, 0x9E, 0x44, 0x27, + 0x20, 0x0C, 0xEA, 0x8F, 0xEB, 0x62, 0xB4, 0x02, 0x92, 0x14, 0xEB, 0x17, 0xFE, 0x0F, 0xB6, 0x02, + 0xDD, 0x9E, 0x44, 0x27, 0x20, 0x10, 0xEA, 0x8F, 0xEB, 0x62, 0xB4, 0x02, 0x92, 0x14, 0xEB, 0x17, + 0xFE, 0x0F, 0xB6, 0x02, 0xDD, 0x9E, 0x44, 0x27, 0x20, 0x1C, 0xEA, 0x69, 0xEA, 0x24, 0xB4, 0x62, + 0x46, 0x0F, 0x00, 0x0F, 0xDD, 0x42, 0xFE, 0x1E, 0xFE, 0x0F, 0xB6, 0x02, 0xDD, 0x9E, 0x44, 0x27, + 0x20, 0x20, 0xEA, 0x69, 0xEA, 0x24, 0xB4, 0x62, 0x46, 0x0F, 0x00, 0x0F, 0xDD, 0x42, 0xFE, 0x1E, + 0xFE, 0x0F, 0xB6, 0x02, 0xDD, 0x9E, 0x44, 0x27, 0x20, 0x34, 0xEA, 0x69, 0xEA, 0x24, 0xB4, 0x62, + 0x46, 0x0F, 0x00, 0x0F, 0xDD, 0x42, 0xFE, 0x1E, 0xFE, 0x0F, 0xB6, 0x02, 0xDD, 0x9E, 0x44, 0x27, + 0x20, 0x54, 0x84, 0x30, 0xB4, 0x62, 0x96, 0x1F, 0xFE, 0x5E, 0xFE, 0x0F, 0xB6, 0x02, 0xDD, 0x9E, + 0x44, 0x27, 0x20, 0x54, 0x96, 0x1F, 0xB4, 0x62, 0xDD, 0x56, 0x44, 0x0F, 0xF0, 0xFF, 0xFE, 0x1E, + 0xFE, 0x0F, 0xB6, 0x02, 0xDD, 0x9E, 0x44, 0x27, 0x20, 0x58, 0x96, 0x1F, 0xEA, 0x24, 0xB4, 0x62, + 0x46, 0x0F, 0xFF, 0x0F, 0xDD, 0x42, 0xFE, 0x1E, 0xFE, 0x0F, 0xB6, 0x02, 0xDD, 0x9E, 0x44, 0x14, + 0x00, 0x04, 0xEA, 0xE7, 0xB4, 0x01, 0xDD, 0x4B, 0xB6, 0x01, 0xB4, 0x02, 0xEB, 0xEA, 0x92, 0x10, + 0xEA, 0x22, 0xFE, 0x0F, 0xEA, 0xAA, 0xB6, 0x02, 0xB4, 0x41, 0xEA, 0x29, 0xFE, 0x16, 0xB6, 0x01, + 0x44, 0x14, 0x00, 0x1C, 0xB4, 0x01, 0xDD, 0x4B, 0xB6, 0x01, 0xDD, 0x9E, 0xFC, 0x40, 0x44, 0x64, + 0x00, 0x40, 0x44, 0x74, 0x0C, 0x40, 0x46, 0x00, 0x80, 0x80, 0x85, 0x20, 0xB6, 0x06, 0xDD, 0x4C, + 0xB7, 0x26, 0xEA, 0x2D, 0xB4, 0x07, 0x46, 0xA0, 0x00, 0x80, 0x84, 0x41, 0x40, 0x00, 0x28, 0x04, + 0x80, 0x62, 0xB6, 0x07, 0x44, 0x14, 0x04, 0x40, 0x44, 0x04, 0x08, 0x40, 0xDD, 0x44, 0xB4, 0x27, + 0x46, 0x0F, 0xFF, 0x7F, 0xDD, 0x42, 0xFE, 0x0E, 0x84, 0x41, 0xB6, 0x07, 0x44, 0x14, 0x04, 0x40, + 0x44, 0x04, 0x08, 0x40, 0x80, 0x62, 0xDD, 0x44, 0x44, 0x07, 0x20, 0xC0, 0xB7, 0x46, 0xB7, 0x26, + 0xB4, 0x40, 0xEB, 0x01, 0xFE, 0x57, 0xB6, 0x20, 0x80, 0x20, 0xB4, 0x01, 0x92, 0x19, 0x96, 0x06, + 0xC8, 0xFD, 0x84, 0x01, 0x49, 0xFF, 0xF4, 0xD3, 0xFC, 0xC0, 0xFC, 0x00, 0x49, 0xFF, 0xFF, 0xC8, + 0xFC, 0x80, 0x44, 0x04, 0x00, 0x50, 0xB4, 0x20, 0x44, 0x11, 0x98, 0x78, 0xB6, 0x20, 0xDD, 0x9E, + 0x44, 0x04, 0x00, 0x9C, 0xB4, 0x00, 0x96, 0x00, 0xDD, 0x9E, 0x44, 0x04, 0x00, 0x9C, 0xB4, 0x00, + 0x92, 0x08, 0x96, 0x00, 0xDD, 0x9E, 0x44, 0x34, 0x80, 0x90, 0x96, 0x06, 0xB4, 0x83, 0x84, 0x3D, + 0x94, 0x81, 0xFE, 0x66, 0xFE, 0x57, 0xDD, 0x5E, 0xB6, 0x23, 0x04, 0x31, 0x00, 0x15, 0x84, 0x3E, + 0xFE, 0x5E, 0xFE, 0x0F, 0x14, 0x01, 0x00, 0x15, 0x84, 0x00, 0xEB, 0xAE, 0xEA, 0x75, 0x84, 0x22, + 0xAE, 0x40, 0xDD, 0x9E, 0x44, 0x24, 0x00, 0x18, 0xC8, 0x0C, 0xB4, 0x22, 0x44, 0x0B, 0xFF, 0xFF, + 0xFE, 0x0E, 0xEA, 0xC5, 0xB6, 0x02, 0xB4, 0x01, 0x92, 0x08, 0xDD, 0x52, 0xB6, 0x01, 0xD5, 0x15, + 0xB4, 0x62, 0x44, 0x04, 0x00, 0x00, 0xFE, 0x1F, 0xB6, 0x02, 0x44, 0x24, 0x50, 0x10, 0xB4, 0x02, + 0x92, 0x08, 0xDD, 0x52, 0xC1, 0x09, 0x58, 0x00, 0x00, 0x98, 0xEA, 0xAA, 0xB6, 0x02, 0xB4, 0x41, + 0xEA, 0x5E, 0xFE, 0x17, 0xD5, 0x06, 0xB6, 0x02, 0xEA, 0xAA, 0xEA, 0x29, 0xB4, 0x41, 0xFE, 0x16, + 0xB6, 0x01, 0xDD, 0x9E, 0xDD, 0x9E, 0x44, 0x04, 0x80, 0x10, 0xFA, 0x20, 0xAE, 0x40, 0xDD, 0x9E, + 0x44, 0x04, 0x80, 0x09, 0x84, 0x24, 0xAE, 0x40, 0xDD, 0x9E, 0x44, 0x04, 0x80, 0x10, 0x84, 0x21, + 0xAE, 0x40, 0xDD, 0x9E, 0x44, 0x04, 0x80, 0x11, 0x84, 0x24, 0xAE, 0x40, 0xDD, 0x9E, 0x46, 0x20, + 0x00, 0x80, 0x96, 0x06, 0x04, 0x31, 0x00, 0x73, 0x94, 0x45, 0x44, 0x0F, 0xFF, 0xDF, 0xFE, 0x1E, + 0xFE, 0x0F, 0x14, 0x01, 0x00, 0x73, 0xDD, 0x9E, 0xFC, 0x00, 0x44, 0x64, 0x80, 0x88, 0xEA, 0x5F, + 0xB4, 0x26, 0xDD, 0x42, 0xFE, 0x0E, 0x44, 0x14, 0x00, 0x40, 0xB6, 0x06, 0xB4, 0x41, 0xEB, 0x2C, + 0xFE, 0x17, 0xB6, 0x01, 0xB4, 0x41, 0xEA, 0x85, 0xDD, 0x42, 0xFE, 0x16, 0xB6, 0x01, 0x84, 0x05, + 0xEA, 0x46, 0xEA, 0xCF, 0x84, 0x21, 0xAE, 0x40, 0xB4, 0x26, 0xEB, 0x3A, 0xFE, 0x0F, 0xB6, 0x06, + 0xFC, 0x80, 0xFC, 0x00, 0x44, 0x14, 0x55, 0x0C, 0xB4, 0x01, 0x92, 0x08, 0xDD, 0x52, 0xB6, 0x01, + 0x44, 0x04, 0x58, 0x8C, 0xB4, 0x40, 0x92, 0x48, 0xEB, 0xED, 0xB6, 0x40, 0x84, 0x41, 0x80, 0x62, + 0xDD, 0x44, 0xFC, 0x80, 0x44, 0x05, 0x10, 0x10, 0xB4, 0x00, 0xDD, 0x52, 0x92, 0x08, 0xDD, 0x9E, + 0x44, 0x34, 0x80, 0x88, 0xEA, 0xE0, 0x40, 0x20, 0x64, 0x08, 0xB4, 0x83, 0xFE, 0x8F, 0x46, 0x1F, + 0xCF, 0xFF, 0x46, 0x00, 0x30, 0x00, 0xEA, 0x2B, 0xFE, 0x86, 0xFE, 0x66, 0x40, 0x01, 0x04, 0x04, + 0xB6, 0x03, 0xDD, 0x9E, 0xDD, 0x9E, 0x44, 0x14, 0x50, 0x0C, 0xB4, 0x01, 0xDD, 0x4B, 0xB6, 0x01, + 0xDD, 0x9E, 0x44, 0x24, 0x00, 0x90, 0xEA, 0x69, 0xB4, 0x22, 0x92, 0x2C, 0xEB, 0x4F, 0xFE, 0x47, + 0xB6, 0x22, 0xDD, 0x9E, 0xFC, 0x00, 0x44, 0x24, 0x2C, 0x04, 0x46, 0x0F, 0xF3, 0x3F, 0xB4, 0x22, + 0xDD, 0x42, 0xFE, 0x0E, 0x46, 0x10, 0x08, 0x80, 0xFE, 0x0F, 0xB6, 0x02, 0x84, 0x41, 0x80, 0x62, + 0x44, 0x04, 0x28, 0x04, 0x44, 0x14, 0x24, 0x04, 0xDD, 0x44, 0x44, 0x14, 0x2C, 0x0C, 0x46, 0x0F, + 0xFE, 0xFF, 0xB4, 0x41, 0xDD, 0x42, 0xFE, 0x16, 0x84, 0x41, 0xB6, 0x01, 0x80, 0x62, 0x44, 0x04, + 0x28, 0x0C, 0x44, 0x14, 0x24, 0x0C, 0xDD, 0x44, 0x44, 0x24, 0x2C, 0x00, 0x44, 0x04, 0x00, 0x9C, + 0xB4, 0x20, 0xB4, 0x22, 0x44, 0x0F, 0xE3, 0xFF, 0xFE, 0x0E, 0x58, 0x00, 0x18, 0x00, 0xB6, 0x02, + 0x84, 0x41, 0x44, 0x04, 0x28, 0x00, 0x44, 0x14, 0x24, 0x00, 0x80, 0x62, 0xDD, 0x44, 0xFC, 0x80, + 0xDD, 0x9E, 0x46, 0x10, 0x00, 0x81, 0x14, 0x00, 0x80, 0x34, 0x14, 0x00, 0x80, 0x36, 0xDD, 0x9E, + 0xFC, 0x00, 0xEA, 0x56, 0xEA, 0x85, 0x51, 0xC3, 0x0E, 0x48, 0xB9, 0x13, 0xDD, 0x42, 0xFE, 0x0E, + 0xB8, 0x93, 0xB9, 0x13, 0xEB, 0x1A, 0xFE, 0x0F, 0x84, 0x41, 0xB8, 0x93, 0xEB, 0x9B, 0x50, 0x03, + 0x0A, 0x94, 0x80, 0x62, 0xDD, 0x44, 0xB4, 0x1C, 0x84, 0x41, 0xEA, 0x93, 0xB6, 0x1C, 0xB4, 0x1C, + 0x50, 0x13, 0x06, 0x48, 0x58, 0x00, 0x00, 0x40, 0xB6, 0x1C, 0x80, 0x62, 0x50, 0x03, 0x0A, 0x48, + 0xDD, 0x44, 0x44, 0x04, 0x55, 0x0C, 0xB4, 0x20, 0x92, 0x28, 0xEA, 0x4F, 0xB6, 0x20, 0x84, 0x21, + 0x49, 0xFF, 0xF5, 0x75, 0x44, 0x04, 0x58, 0x8C, 0xB4, 0x20, 0x92, 0x28, 0xEA, 0x4F, 0xB6, 0x20, + 0x84, 0x21, 0x49, 0xFF, 0xF5, 0x3C, 0xFC, 0x80, 0xC0, 0x3A, 0x5A, 0x00, 0x01, 0x39, 0x5A, 0x08, + 0x02, 0x35, 0x44, 0x04, 0x58, 0x9C, 0x46, 0x10, 0x92, 0x00, 0xB6, 0x20, 0x44, 0x24, 0x58, 0xA0, + 0x46, 0x03, 0x6D, 0xB6, 0x50, 0x00, 0x0D, 0xB6, 0x44, 0x34, 0x58, 0xA4, 0xB6, 0x02, 0x44, 0x20, + 0x0D, 0xB6, 0xB6, 0x43, 0x44, 0x34, 0x55, 0x1C, 0xB6, 0x23, 0x44, 0x34, 0x55, 0x20, 0xB6, 0x03, + 0x44, 0x04, 0x55, 0x24, 0x44, 0x34, 0x58, 0x98, 0xB6, 0x40, 0x44, 0x04, 0x58, 0x90, 0x44, 0x24, + 0x58, 0x94, 0xB6, 0x20, 0x46, 0x00, 0x92, 0x76, 0x50, 0x00, 0x0C, 0x4E, 0xB6, 0x02, 0x44, 0x20, + 0x03, 0xB1, 0xB6, 0x43, 0x44, 0x34, 0x55, 0x10, 0xB6, 0x23, 0x44, 0x14, 0x55, 0x14, 0xB6, 0x01, + 0x44, 0x04, 0x55, 0x18, 0xB6, 0x40, 0xDD, 0x9E, 0x5A, 0x08, 0x03, 0x1C, 0x44, 0x04, 0x58, 0x9C, + 0x46, 0x22, 0x48, 0x00, 0xB6, 0x40, 0x44, 0x14, 0x58, 0xA0, 0x46, 0x02, 0x49, 0x24, 0x50, 0x00, + 0x09, 0x24, 0x44, 0x34, 0x58, 0xA4, 0xB6, 0x01, 0x44, 0x10, 0x09, 0x24, 0xB6, 0x23, 0x44, 0x34, + 0x55, 0x1C, 0xB6, 0x43, 0x44, 0x24, 0x55, 0x20, 0xB6, 0x02, 0x44, 0x04, 0x55, 0x24, 0xB6, 0x20, + 0xDD, 0x9E, 0xFC, 0x40, 0x44, 0x94, 0x58, 0x80, 0x44, 0x74, 0x55, 0x00, 0x84, 0x00, 0x84, 0x41, + 0xB6, 0x09, 0x80, 0x27, 0xB6, 0x07, 0x80, 0x62, 0x80, 0x09, 0xDD, 0x44, 0x44, 0x14, 0x55, 0x04, + 0x44, 0x04, 0x58, 0x84, 0x44, 0x20, 0x14, 0x00, 0xB6, 0x41, 0xB6, 0x40, 0x84, 0x41, 0x80, 0x62, + 0xDD, 0x44, 0xDD, 0x4C, 0xEA, 0x46, 0xB4, 0x07, 0x84, 0x41, 0xEB, 0x75, 0xB6, 0x07, 0xB4, 0x09, + 0xEA, 0x56, 0xEB, 0x75, 0x80, 0x27, 0x80, 0x62, 0xB6, 0x09, 0x80, 0x09, 0xDD, 0x44, 0x44, 0x00, + 0x00, 0xC8, 0xEA, 0x2D, 0xEB, 0x85, 0xB4, 0x3C, 0x46, 0x01, 0x00, 0x00, 0xFE, 0x0F, 0x84, 0x41, + 0xB6, 0x1C, 0xEB, 0x9B, 0x50, 0x03, 0x0A, 0x94, 0x80, 0x62, 0xDD, 0x44, 0xB9, 0x08, 0x46, 0x00, + 0x11, 0x00, 0x84, 0x41, 0xFE, 0x0F, 0x80, 0x62, 0xB8, 0x88, 0x50, 0x13, 0x06, 0xB4, 0x50, 0x03, + 0x0A, 0xB4, 0xDD, 0x44, 0xB9, 0x08, 0x46, 0x0F, 0xEE, 0xFF, 0xDD, 0x42, 0xFE, 0x0E, 0xB8, 0x88, + 0x84, 0x01, 0xEA, 0xB4, 0xB4, 0x27, 0x44, 0x0F, 0xEF, 0xFF, 0xFE, 0x46, 0xB6, 0x27, 0xB4, 0x29, + 0x84, 0x41, 0xFE, 0x0E, 0xB6, 0x09, 0x80, 0x27, 0x80, 0x09, 0x80, 0x62, 0xDD, 0x44, 0xFC, 0xC0, + 0xFC, 0x20, 0xEA, 0x56, 0x46, 0x00, 0x44, 0x00, 0x50, 0x73, 0x0E, 0xB4, 0xB4, 0x27, 0x84, 0x41, + 0xFE, 0x0F, 0xB6, 0x07, 0x50, 0x13, 0x06, 0xB4, 0x50, 0x03, 0x0A, 0xB4, 0x80, 0x62, 0xDD, 0x44, + 0xB4, 0x27, 0x46, 0x0F, 0xBB, 0xFF, 0xDD, 0x42, 0xFE, 0x0E, 0xB6, 0x07, 0x44, 0x64, 0x55, 0x00, + 0x44, 0x74, 0x58, 0x80, 0xB4, 0x06, 0x84, 0x41, 0x58, 0x00, 0x04, 0x00, 0xB6, 0x06, 0xB4, 0x07, + 0x80, 0x26, 0x58, 0x00, 0x04, 0x00, 0xB6, 0x07, 0x80, 0x62, 0x80, 0x07, 0xDD, 0x44, 0x44, 0x14, + 0x55, 0x04, 0x44, 0x04, 0x58, 0x84, 0x84, 0x40, 0xB6, 0x41, 0xB6, 0x40, 0x84, 0x41, 0x80, 0x62, + 0xDD, 0x44, 0xB4, 0x26, 0x44, 0x0F, 0xFB, 0xFF, 0xFE, 0x46, 0xB6, 0x26, 0xB4, 0x27, 0x84, 0x41, + 0xFE, 0x0E, 0xB6, 0x07, 0x80, 0x26, 0x80, 0x07, 0x80, 0x62, 0xDD, 0x44, 0xFC, 0xA0, 0x44, 0x14, + 0x00, 0x9C, 0xB4, 0x21, 0x92, 0x28, 0x96, 0x48, 0x5A, 0x18, 0x1C, 0x0D, 0x44, 0x24, 0x80, 0x88, + 0x96, 0x06, 0xB4, 0x62, 0x40, 0x10, 0x34, 0x08, 0x44, 0x0F, 0xDF, 0xFF, 0xFE, 0x1E, 0xFE, 0x0F, + 0xB6, 0x02, 0xDD, 0x9E, 0x44, 0x34, 0x30, 0x40, 0x46, 0x1F, 0xF0, 0x0F, 0xB4, 0x03, 0xEA, 0x2B, + 0xFE, 0x0E, 0x44, 0x22, 0x00, 0x00, 0xFE, 0x17, 0x44, 0x24, 0x30, 0x44, 0xB6, 0x03, 0xB4, 0x02, + 0x92, 0x08, 0xDD, 0x52, 0x58, 0x00, 0x00, 0x03, 0xB6, 0x02, 0xB4, 0x02, 0xFE, 0x46, 0x44, 0x03, + 0x00, 0x00, 0xFE, 0x47, 0x44, 0x04, 0x30, 0x38, 0xB6, 0x22, 0x44, 0x10, 0x00, 0x54, 0xB6, 0x20, + 0xDD, 0x9E, 0x46, 0x20, 0x00, 0x80, 0x96, 0x0F, 0x04, 0x31, 0x00, 0xA4, 0x94, 0x45, 0x44, 0x0F, + 0xFF, 0x9F, 0xFE, 0x1E, 0xFE, 0x0F, 0x14, 0x01, 0x00, 0xA4, 0xDD, 0x9E, 0x44, 0x14, 0x00, 0xD4, + 0x5A, 0x08, 0x01, 0x05, 0xB4, 0x01, 0xDD, 0x4B, 0xD5, 0x04, 0xB4, 0x41, 0x84, 0x1E, 0xFE, 0x16, + 0xB6, 0x01, 0xDD, 0x9E, 0x44, 0x14, 0x00, 0xD4, 0x5A, 0x08, 0x01, 0x05, 0xB4, 0x01, 0xEA, 0x39, + 0xD5, 0x04, 0xB4, 0x41, 0x84, 0x1D, 0xFE, 0x16, 0xB6, 0x01, 0xDD, 0x9E, 0x44, 0x14, 0x00, 0xD8, + 0x5A, 0x08, 0x01, 0x05, 0xB4, 0x01, 0xDD, 0x4B, 0xD5, 0x04, 0xB4, 0x41, 0x84, 0x1E, 0xFE, 0x16, + 0xB6, 0x01, 0xDD, 0x9E, 0x44, 0x24, 0x80, 0x88, 0x84, 0x3E, 0xB4, 0x62, 0x96, 0x06, 0xFE, 0x5E, + 0xFE, 0x47, 0xB6, 0x22, 0xB4, 0x62, 0x84, 0x3D, 0x94, 0x01, 0xFE, 0x5E, 0xFE, 0x0F, 0xB6, 0x02, + 0xDD, 0x9E, 0xFC, 0x00, 0x44, 0x24, 0x00, 0x18, 0x46, 0x0E, 0x1F, 0x8F, 0xB4, 0x22, 0x50, 0x00, + 0x0F, 0xFE, 0xFE, 0x0E, 0x46, 0x10, 0xE0, 0x60, 0x8C, 0x21, 0xFE, 0x0F, 0x44, 0x34, 0x00, 0x10, + 0xB6, 0x02, 0xB4, 0x03, 0xEB, 0xEA, 0x92, 0x10, 0xEA, 0x22, 0xFE, 0x0F, 0xB6, 0x03, 0xB4, 0x22, + 0x46, 0x09, 0xE4, 0xFF, 0x50, 0x00, 0x0C, 0xFF, 0xFE, 0x0E, 0x46, 0x16, 0x09, 0x00, 0x50, 0x10, + 0x81, 0x00, 0xFE, 0x0F, 0xB6, 0x02, 0x84, 0x00, 0x80, 0x20, 0xEB, 0x18, 0xFC, 0x80, 0xFC, 0x00, + 0x44, 0x57, 0x20, 0x44, 0xFE, 0x44, 0xB4, 0xC5, 0xEA, 0xBC, 0x46, 0x4F, 0xC0, 0x0F, 0x40, 0x30, + 0xC0, 0x08, 0x50, 0x12, 0x0F, 0xFF, 0xFE, 0x76, 0xFE, 0x5F, 0x44, 0x37, 0x20, 0x4C, 0xB6, 0x25, + 0xB4, 0x23, 0xEB, 0xD8, 0xFF, 0x0E, 0x46, 0x10, 0x3F, 0xF0, 0xFE, 0x8E, 0x58, 0x42, 0x02, 0x88, + 0xFF, 0x17, 0xB6, 0x83, 0x44, 0x37, 0x20, 0x04, 0x46, 0x1F, 0xF0, 0x0F, 0xB4, 0x43, 0xEA, 0x2B, + 0xFE, 0x56, 0x46, 0x20, 0x02, 0x90, 0xFE, 0x57, 0xB6, 0x23, 0xEB, 0x72, 0x04, 0x30, 0x80, 0x70, + 0x5A, 0x00, 0x10, 0x05, 0x44, 0x21, 0x05, 0x00, 0xD5, 0x03, 0x44, 0x21, 0x07, 0x00, 0x46, 0x1F, + 0xFF, 0x0F, 0x50, 0x10, 0x80, 0xFF, 0x40, 0x01, 0x84, 0x02, 0xEB, 0x72, 0xFE, 0x17, 0x14, 0x00, + 0x80, 0x70, 0x46, 0x00, 0x00, 0x91, 0x83, 0x80, 0xB9, 0x11, 0x58, 0x10, 0x80, 0x10, 0xB9, 0x91, + 0xBA, 0x13, 0x44, 0x14, 0x00, 0x00, 0xFE, 0x57, 0xB9, 0x93, 0xFC, 0x80, 0x44, 0x37, 0x20, 0x4C, + 0x46, 0x0F, 0xC0, 0x0F, 0xB4, 0x23, 0xDD, 0x42, 0x44, 0x21, 0x00, 0x00, 0xFE, 0x46, 0xFE, 0x57, + 0xB6, 0x23, 0x44, 0x17, 0x20, 0x44, 0xB4, 0x61, 0xFE, 0x1E, 0xFE, 0x17, 0xB6, 0x01, 0x46, 0x10, + 0x00, 0x91, 0xA0, 0x0B, 0x92, 0x06, 0x94, 0x06, 0xDD, 0x4B, 0xA8, 0x0B, 0xA0, 0x0C, 0x92, 0x05, + 0x94, 0x05, 0xDD, 0x4B, 0xA8, 0x0C, 0x04, 0x20, 0x80, 0x11, 0xEA, 0xA3, 0xFE, 0x16, 0x14, 0x00, + 0x80, 0x11, 0xDD, 0x9E, 0x46, 0x00, 0x00, 0x91, 0xA0, 0x02, 0x96, 0x01, 0xDD, 0x9E, 0xFC, 0x20, + 0x46, 0x40, 0x00, 0x91, 0x22, 0x5F, 0x80, 0x12, 0xEA, 0x28, 0x22, 0x6F, 0x80, 0x10, 0xFE, 0x0F, + 0xEB, 0xD2, 0x83, 0x84, 0xBF, 0x1C, 0xFE, 0x9F, 0xB8, 0x9C, 0x40, 0x32, 0xC0, 0x08, 0x46, 0x10, + 0x3F, 0xF0, 0xB8, 0x1D, 0xFE, 0xF7, 0xBA, 0x9D, 0x50, 0x10, 0x83, 0xFF, 0xB8, 0x20, 0xFE, 0xCE, + 0x46, 0x1F, 0xC0, 0x0F, 0x50, 0x20, 0x8C, 0x00, 0xFE, 0x16, 0xFE, 0x1F, 0xB8, 0xA0, 0xB8, 0x20, + 0x54, 0x63, 0x03, 0xFF, 0x92, 0x0A, 0xEA, 0x21, 0xFF, 0x87, 0xBE, 0xA0, 0x54, 0x52, 0x83, 0xFF, + 0x40, 0x02, 0xC0, 0x08, 0xBD, 0x20, 0xEA, 0x2B, 0xFF, 0x4E, 0xFF, 0x47, 0xBD, 0xA0, 0xFC, 0xA0, + 0x46, 0x30, 0x00, 0x91, 0x84, 0x83, 0x14, 0x41, 0x80, 0x22, 0xA8, 0x19, 0x44, 0x00, 0x01, 0xF4, + 0xA8, 0x1A, 0x04, 0x01, 0x80, 0x0A, 0xEA, 0x4F, 0x92, 0x0A, 0xEA, 0x21, 0xDD, 0x4B, 0x14, 0x01, + 0x80, 0x0A, 0x04, 0x01, 0x80, 0x0B, 0xEB, 0xD8, 0x92, 0x0A, 0xEA, 0x21, 0x58, 0x00, 0x02, 0x1C, + 0x14, 0x01, 0x80, 0x0B, 0x04, 0x51, 0x80, 0x0E, 0x46, 0x40, 0x03, 0xF3, 0x46, 0x0F, 0xFC, 0x0C, + 0xFE, 0x8F, 0x50, 0x42, 0x0F, 0x00, 0x50, 0x00, 0x00, 0xFF, 0xFE, 0x2E, 0xFE, 0xA6, 0x40, 0x11, + 0x00, 0x04, 0x14, 0x11, 0x80, 0x0E, 0x04, 0x01, 0x80, 0x12, 0x58, 0x00, 0x30, 0x20, 0x14, 0x01, + 0x80, 0x12, 0x04, 0x11, 0x80, 0x13, 0x44, 0x0E, 0xE7, 0x87, 0xFE, 0x0E, 0x44, 0x11, 0x08, 0x48, + 0xFE, 0x0F, 0x14, 0x01, 0x80, 0x13, 0xB4, 0x23, 0xEA, 0x5E, 0xFE, 0x0F, 0xB6, 0x03, 0xDD, 0x9E, + 0x46, 0x00, 0x00, 0x91, 0x50, 0x30, 0x00, 0x44, 0xB4, 0x23, 0xEB, 0xEB, 0xB6, 0x23, 0xB4, 0x43, + 0x84, 0x3E, 0xFE, 0x56, 0xB6, 0x23, 0xDD, 0x9E, 0x44, 0x24, 0x00, 0x18, 0xC8, 0x20, 0xB4, 0x02, + 0x96, 0x06, 0xAE, 0x08, 0xB4, 0x02, 0x92, 0x08, 0x96, 0x06, 0xAE, 0x09, 0xB4, 0x02, 0x92, 0x12, + 0x96, 0x06, 0xAE, 0x0A, 0xB4, 0x02, 0x92, 0x1C, 0x96, 0x06, 0xAE, 0x0B, 0x44, 0x04, 0x50, 0x10, + 0xB4, 0x00, 0x92, 0x08, 0xAE, 0x0D, 0xB4, 0x02, 0x92, 0x1B, 0x96, 0x06, 0xAE, 0x0E, 0x44, 0x04, + 0x70, 0x00, 0xB4, 0x00, 0x92, 0x10, 0x96, 0x06, 0xAE, 0x0F, 0xDD, 0x9E, 0x5A, 0x08, 0x01, 0x35, + 0xA7, 0x09, 0xA6, 0xCA, 0x40, 0x42, 0x20, 0x08, 0x40, 0x31, 0xC8, 0x08, 0xFF, 0x1F, 0xA6, 0xC8, + 0xB4, 0x02, 0xFF, 0x1F, 0xA6, 0xCB, 0x40, 0x31, 0xF0, 0x08, 0xFF, 0x1F, 0xA6, 0xCE, 0x40, 0x31, + 0xEC, 0x08, 0xFF, 0x1F, 0x46, 0x31, 0x80, 0x40, 0x50, 0x31, 0x81, 0x01, 0xFF, 0x1E, 0x46, 0x3E, + 0x7F, 0xBF, 0x50, 0x31, 0x8E, 0xFE, 0xFE, 0x1E, 0xFE, 0x27, 0x44, 0x44, 0x50, 0x10, 0xB6, 0x02, + 0xB4, 0x04, 0xA6, 0xCD, 0x44, 0x2F, 0x00, 0xFF, 0xEA, 0xCD, 0xFE, 0x16, 0xFE, 0x1F, 0xB6, 0x04, + 0xA6, 0x0F, 0x44, 0x24, 0x70, 0x00, 0x96, 0x06, 0xB4, 0x62, 0xEA, 0x24, 0xEA, 0x29, 0xFE, 0x1E, + 0xFE, 0x0F, 0xB6, 0x02, 0xDD, 0x9E, 0xB4, 0x22, 0x46, 0x0E, 0x7F, 0xBF, 0x50, 0x00, 0x0E, 0xFE, + 0xFE, 0x0E, 0xEA, 0xC5, 0xB6, 0x02, 0xB4, 0x41, 0x44, 0x0F, 0x00, 0xFF, 0xFE, 0x16, 0xB6, 0x01, + 0xEA, 0xAA, 0xEA, 0x29, 0xB4, 0x41, 0xFE, 0x16, 0xB6, 0x01, 0xDD, 0x9E, 0x46, 0x20, 0x00, 0x91, + 0x96, 0x2F, 0xA0, 0x53, 0x92, 0x26, 0x94, 0x4E, 0xFE, 0x47, 0xA8, 0x53, 0xDD, 0x9E, 0xFC, 0x00, + 0x49, 0xFF, 0xFA, 0xD5, 0x5A, 0x00, 0x01, 0x08, 0x49, 0xFF, 0xF1, 0xF2, 0x92, 0x0E, 0x56, 0x00, + 0x00, 0x01, 0x96, 0x06, 0xFC, 0x80, 0x46, 0x20, 0x00, 0x91, 0x96, 0x27, 0xA0, 0x54, 0x92, 0x25, + 0x94, 0x4D, 0xFE, 0x47, 0xA8, 0x54, 0xDD, 0x9E, 0x44, 0x17, 0x30, 0x10, 0xB4, 0x01, 0x96, 0x06, + 0xC0, 0xFE, 0x44, 0x17, 0x30, 0x10, 0xB4, 0x01, 0x92, 0x03, 0x96, 0x06, 0x5A, 0x00, 0x01, 0xFD, + 0xDD, 0x9E, 0x84, 0xA0, 0xD0, 0x05, 0x40, 0x00, 0x00, 0x09, 0x8C, 0xA1, 0xD5, 0xFC, 0xDD, 0x9E, + 0x44, 0x27, 0x30, 0x10, 0xB4, 0x22, 0x92, 0x21, 0x96, 0x46, 0x5A, 0x10, 0x01, 0xFD, 0xFC, 0x00, + 0x44, 0x17, 0x30, 0x00, 0xB6, 0x01, 0x84, 0x02, 0xEA, 0x46, 0xFC, 0x80, 0xFC, 0x00, 0x46, 0x61, + 0xFF, 0xF9, 0x50, 0x03, 0x05, 0x27, 0xEA, 0x60, 0x50, 0x03, 0x04, 0x87, 0xEA, 0x60, 0xFC, 0x80, + 0xFC, 0x00, 0x46, 0x61, 0xFF, 0xF9, 0x50, 0x03, 0x05, 0x00, 0xEA, 0x60, 0x50, 0x03, 0x04, 0x00, + 0xEA, 0x60, 0xFC, 0x80, 0xFC, 0x00, 0x46, 0x11, 0xFF, 0xFF, 0x50, 0x10, 0x8F, 0x00, 0xFE, 0x0F, + 0xEA, 0x60, 0xFC, 0x80, 0xFC, 0x00, 0x46, 0x11, 0xFF, 0xFF, 0xFE, 0x0F, 0xEA, 0x60, 0xFC, 0x80, + 0xFC, 0x00, 0x46, 0x01, 0xFF, 0xFF, 0x50, 0x00, 0x02, 0xBB, 0xEA, 0x60, 0xFC, 0x80, 0xFC, 0x41, + 0xF0, 0x81, 0x80, 0xE1, 0x80, 0xC2, 0x81, 0x03, 0x81, 0x44, 0x81, 0x25, 0x49, 0xFF, 0xFF, 0xD0, + 0xF0, 0x01, 0x5A, 0x00, 0xFF, 0x04, 0xEB, 0xAB, 0xEA, 0xF9, 0x40, 0x84, 0x20, 0x08, 0x40, 0xA4, + 0x28, 0x04, 0x40, 0x63, 0x40, 0x08, 0x40, 0x65, 0x18, 0x04, 0x40, 0x03, 0xE0, 0x08, 0xFE, 0x37, + 0xEA, 0x60, 0xEA, 0xF9, 0x5A, 0x98, 0x01, 0x05, 0x84, 0x0F, 0xEB, 0xAB, 0xEA, 0xF9, 0x49, 0xFF, + 0xFF, 0xC1, 0xFC, 0xC1, 0x44, 0x27, 0x30, 0x10, 0xB4, 0x22, 0x92, 0x21, 0x96, 0x46, 0x5A, 0x10, + 0x01, 0xFD, 0xFC, 0x20, 0x44, 0x17, 0x30, 0x00, 0x44, 0x60, 0x10, 0x00, 0xB6, 0x01, 0x44, 0x74, + 0x80, 0x08, 0xB4, 0x07, 0x92, 0x11, 0x96, 0x06, 0xC0, 0x09, 0x2E, 0x07, 0xF0, 0xF0, 0xC0, 0x0E, + 0x84, 0x00, 0x3E, 0x07, 0xF0, 0xF0, 0xEA, 0xF0, 0xFC, 0xA0, 0x2E, 0x07, 0xF0, 0xF0, 0xC8, 0xF6, + 0x84, 0x01, 0x8E, 0xC1, 0xEA, 0x46, 0xCE, 0xEE, 0xD5, 0xF1, 0x44, 0x07, 0x30, 0x14, 0xB4, 0x00, + 0x92, 0x10, 0x96, 0x00, 0xFC, 0xA0, 0xFC, 0x01, 0xEB, 0xED, 0xF0, 0x81, 0x46, 0x02, 0xF0, 0x00, + 0x40, 0x61, 0x00, 0x04, 0xEA, 0x28, 0xFF, 0x8F, 0x49, 0xFF, 0xFF, 0x82, 0xF0, 0x01, 0xEB, 0xAB, + 0xEA, 0xF9, 0x80, 0x06, 0x49, 0xFF, 0xFF, 0xC8, 0xF0, 0x81, 0x84, 0x0F, 0xEB, 0xAB, 0xEA, 0xF9, + 0x49, 0xFF, 0xFF, 0x80, 0xF0, 0x01, 0xFC, 0x81, 0xFC, 0x00, 0x44, 0x17, 0x30, 0x08, 0x84, 0xC1, + 0xB4, 0x01, 0x92, 0x05, 0x94, 0x05, 0xFE, 0x37, 0xB6, 0x01, 0x49, 0xFF, 0xFF, 0x69, 0x80, 0x66, + 0x80, 0xA6, 0x84, 0x06, 0xFA, 0x2F, 0x44, 0x20, 0x00, 0xAC, 0x84, 0x80, 0xDD, 0x5D, 0x84, 0x06, + 0xFA, 0x2F, 0x44, 0x20, 0x00, 0xAD, 0x80, 0x66, 0x84, 0x80, 0x80, 0xA6, 0xDD, 0x5D, 0xEA, 0xF7, + 0x84, 0x24, 0xAE, 0x40, 0x84, 0x22, 0xAE, 0x40, 0xEB, 0xB4, 0x44, 0x14, 0x00, 0x00, 0xB4, 0x40, + 0xFE, 0x57, 0xB6, 0x20, 0xB4, 0x40, 0x44, 0x12, 0x00, 0x00, 0xFE, 0x57, 0xB6, 0x20, 0x49, 0xFF, + 0xFF, 0x51, 0xFC, 0x80, 0x3C, 0x0F, 0xFC, 0x3D, 0xDD, 0x9E, 0xC9, 0x08, 0x44, 0x24, 0x00, 0x0C, + 0x84, 0x3E, 0xB4, 0x62, 0x96, 0x06, 0xFE, 0x5E, 0xD5, 0x0A, 0x5A, 0x18, 0x01, 0x0B, 0x44, 0x24, + 0x00, 0x0C, 0x96, 0x06, 0xB4, 0x62, 0x94, 0x41, 0x84, 0x1D, 0xFE, 0x1E, 0xFE, 0x0F, 0xB6, 0x02, + 0xDD, 0x9E, 0xC8, 0x04, 0x44, 0x05, 0x00, 0x00, 0xD5, 0x03, 0x44, 0x05, 0x00, 0x10, 0xB4, 0x00, + 0x92, 0x10, 0x96, 0x1F, 0xDD, 0x9E, 0xC9, 0x04, 0x44, 0x25, 0x00, 0x00, 0xD5, 0x05, 0x5A, 0x18, + 0x01, 0x0D, 0x44, 0x25, 0x00, 0x10, 0x96, 0x1F, 0xEA, 0x24, 0xB4, 0x62, 0x46, 0x0F, 0xFF, 0x0F, + 0xDD, 0x42, 0xFE, 0x1E, 0xFE, 0x0F, 0xB6, 0x02, 0xDD, 0x9E, 0xC9, 0x08, 0x44, 0x24, 0x80, 0x80, + 0x96, 0x06, 0xEA, 0xE0, 0xB4, 0x62, 0xEA, 0x5F, 0xD5, 0x0A, 0x5A, 0x18, 0x01, 0x0D, 0x44, 0x24, + 0x80, 0x80, 0x96, 0x06, 0x40, 0x10, 0x64, 0x08, 0xB4, 0x62, 0xEA, 0x85, 0xDD, 0x42, 0xFE, 0x1E, + 0xFE, 0x0F, 0xB6, 0x02, 0xDD, 0x9E, 0xC9, 0x04, 0x44, 0x25, 0x00, 0x08, 0xD5, 0x05, 0x5A, 0x18, + 0x01, 0x0C, 0x44, 0x25, 0x00, 0x18, 0x96, 0x06, 0xEA, 0xE0, 0xB4, 0x62, 0xEA, 0x5F, 0xDD, 0x42, + 0xFE, 0x1E, 0xFE, 0x0F, 0xB6, 0x02, 0xDD, 0x9E, 0xC8, 0x04, 0x44, 0x05, 0x00, 0x04, 0xD5, 0x03, + 0x44, 0x05, 0x00, 0x14, 0xB4, 0x00, 0x96, 0x01, 0xDD, 0x9E, 0xFC, 0x00, 0xEB, 0xC9, 0xCA, 0x06, + 0x44, 0x21, 0x2D, 0xF4, 0x42, 0x50, 0x08, 0x24, 0xD5, 0x11, 0x44, 0x20, 0xFF, 0xFF, 0xDA, 0x0D, + 0x44, 0x50, 0x03, 0xE8, 0x40, 0x42, 0x14, 0x97, 0x42, 0x50, 0x10, 0x24, 0x40, 0x63, 0x04, 0x0C, + 0x40, 0x62, 0x98, 0xD7, 0x96, 0x31, 0xD5, 0x07, 0xFF, 0x44, 0x40, 0x03, 0x04, 0x0C, 0x40, 0x02, + 0x80, 0x16, 0x96, 0x01, 0xCB, 0x04, 0x44, 0x25, 0x00, 0x04, 0xD5, 0x05, 0x5A, 0x38, 0x01, 0x09, + 0x44, 0x25, 0x00, 0x14, 0xB4, 0x22, 0x92, 0x30, 0xEA, 0x28, 0xFE, 0x0F, 0xB6, 0x02, 0xFC, 0x80, + 0xC8, 0x07, 0xEA, 0x43, 0x84, 0x21, 0xAE, 0x40, 0x44, 0x15, 0x00, 0x08, 0xD5, 0x08, 0x5A, 0x08, + 0x01, 0x0A, 0xEA, 0x43, 0x84, 0x22, 0xAE, 0x40, 0x44, 0x15, 0x00, 0x18, 0xB4, 0x01, 0xEA, 0xA1, + 0xB6, 0x01, 0xDD, 0x9E, 0xC8, 0x07, 0xEA, 0x43, 0x84, 0x21, 0xAE, 0x40, 0x44, 0x15, 0x00, 0x08, + 0xD5, 0x08, 0x5A, 0x08, 0x01, 0x0A, 0xEA, 0x43, 0x84, 0x22, 0xAE, 0x40, 0x44, 0x15, 0x00, 0x18, + 0xB4, 0x01, 0xEA, 0x39, 0xB6, 0x01, 0xDD, 0x9E, 0xC8, 0x07, 0xEA, 0x43, 0x84, 0x21, 0xAE, 0x40, + 0x44, 0x15, 0x00, 0x08, 0xD5, 0x08, 0x5A, 0x08, 0x01, 0x0B, 0xEA, 0x43, 0x84, 0x22, 0xAE, 0x40, + 0x44, 0x15, 0x00, 0x18, 0xB4, 0x41, 0x84, 0x1D, 0xFE, 0x16, 0xB6, 0x01, 0xDD, 0x9E, 0xC9, 0x04, + 0x44, 0x25, 0x00, 0x00, 0xD5, 0x05, 0x5A, 0x18, 0x01, 0x0A, 0x44, 0x25, 0x00, 0x10, 0xB4, 0x62, + 0x84, 0x3E, 0x96, 0x06, 0xFE, 0x5E, 0xFE, 0x0F, 0xB6, 0x02, 0xDD, 0x9E, 0x84, 0x21, 0xC0, 0x04, + 0x5A, 0x08, 0x01, 0x05, 0x84, 0x22, 0xEA, 0x43, 0xAE, 0x40, 0xDD, 0x9E, 0x44, 0x04, 0x80, 0x00, + 0xB4, 0x00, 0x92, 0x18, 0x96, 0x06, 0xC0, 0x11, 0xFC, 0x00, 0xEA, 0x43, 0x84, 0x21, 0xAE, 0x40, + 0xDD, 0x41, 0x5A, 0x08, 0x01, 0x04, 0x49, 0x00, 0x10, 0xBA, 0x3C, 0x0D, 0xFC, 0x3D, 0xC0, 0x04, + 0x3C, 0x0D, 0xFC, 0x3D, 0xDD, 0x20, 0xFC, 0x80, 0xDD, 0x9E, 0x44, 0x04, 0x80, 0x00, 0xB4, 0x00, + 0x92, 0x19, 0x96, 0x06, 0xC0, 0x39, 0xFC, 0x00, 0xEA, 0x43, 0x84, 0x22, 0xAE, 0x40, 0xDD, 0x41, + 0xC8, 0x03, 0x49, 0x00, 0x10, 0xA4, 0xEA, 0x2C, 0x5A, 0x08, 0x02, 0x19, 0x3C, 0x03, 0xF8, 0x65, + 0x8C, 0x01, 0x96, 0x01, 0x3C, 0x0B, 0xF8, 0x65, 0x3C, 0x03, 0xF8, 0x67, 0x96, 0x03, 0xE4, 0x02, + 0x84, 0x00, 0xE9, 0x05, 0x3C, 0x03, 0xF8, 0x67, 0x8E, 0x01, 0x96, 0x03, 0xEB, 0x29, 0x3C, 0x03, + 0xF8, 0x67, 0xC8, 0x19, 0xEB, 0x3B, 0x96, 0x03, 0xEB, 0x29, 0xDD, 0x41, 0x5A, 0x08, 0x01, 0x04, + 0x49, 0x00, 0x00, 0x5A, 0xEA, 0xEE, 0x5A, 0x08, 0x01, 0x0F, 0xEA, 0x34, 0xC8, 0x0A, 0xDD, 0x41, + 0xC8, 0x08, 0x84, 0x02, 0x49, 0xFF, 0xE3, 0xEA, 0xC0, 0x06, 0x84, 0x02, 0xEB, 0x19, 0xFC, 0x80, + 0x84, 0x00, 0xEB, 0xFD, 0xFC, 0x80, 0xDD, 0x9E, 0x44, 0x24, 0x00, 0x5C, 0xB4, 0x22, 0x92, 0x30, + 0xEA, 0x28, 0xFE, 0x0F, 0xB6, 0x02, 0xDD, 0x9E, 0x44, 0x04, 0x00, 0x5C, 0xB4, 0x00, 0x96, 0x01, + 0xDD, 0x9E, 0xFC, 0x00, 0x44, 0x54, 0x00, 0x0C, 0x84, 0x61, 0xB4, 0xC5, 0xFE, 0x1E, 0x40, 0x40, + 0x40, 0x08, 0xEA, 0x29, 0xFE, 0x36, 0xFE, 0x27, 0x46, 0x40, 0x00, 0x92, 0xB6, 0x05, 0x40, 0x11, + 0x84, 0x0C, 0x96, 0xC9, 0xA0, 0x61, 0x96, 0x8F, 0x92, 0x30, 0xEA, 0x28, 0xFE, 0x5F, 0xA8, 0x61, + 0x40, 0x01, 0x40, 0x08, 0xA0, 0xA1, 0x44, 0x1C, 0xFF, 0xFF, 0xFE, 0x8E, 0xFE, 0x87, 0xA8, 0xA1, + 0xFC, 0x80, 0x44, 0x24, 0x80, 0x94, 0x96, 0x06, 0xB4, 0x62, 0xDD, 0x56, 0xEA, 0x25, 0xFE, 0x1E, + 0xFE, 0x0F, 0xB6, 0x02, 0xDD, 0x9E, 0x46, 0x20, 0x00, 0x92, 0x84, 0x3E, 0xB4, 0x62, 0x96, 0x06, + 0xFE, 0x5E, 0xFE, 0x0F, 0xB6, 0x02, 0xDD, 0x9E, 0x46, 0x00, 0x00, 0x92, 0xA0, 0x02, 0xEA, 0x21, + 0x92, 0x0A, 0xDD, 0x9E, 0x46, 0x00, 0x00, 0x81, 0x04, 0x10, 0x00, 0x13, 0x96, 0x46, 0x5A, 0x18, + 0x01, 0x0E, 0x50, 0x30, 0x00, 0x5C, 0xB4, 0x43, 0x84, 0x3E, 0xFE, 0x8E, 0xB6, 0x43, 0xB4, 0x43, + 0xEB, 0x8A, 0xB6, 0x43, 0xB4, 0x43, 0xFE, 0x56, 0xB6, 0x23, 0xDD, 0x9E, 0x46, 0x20, 0x00, 0x81, + 0x84, 0x3E, 0x04, 0x31, 0x00, 0x14, 0x96, 0x06, 0xFE, 0x5E, 0xFE, 0x0F, 0x14, 0x01, 0x00, 0x14, + 0xDD, 0x9E, 0x46, 0x20, 0x00, 0x81, 0x84, 0x3E, 0xA0, 0xD5, 0x96, 0x06, 0xFE, 0x5E, 0xFE, 0x0F, + 0xA8, 0x15, 0xDD, 0x9E, 0x46, 0x00, 0x00, 0x81, 0xA0, 0x05, 0x96, 0x06, 0xDD, 0x9E, 0x44, 0x14, + 0x70, 0x08, 0x5A, 0x08, 0x01, 0x08, 0xB4, 0x01, 0x92, 0x10, 0xEA, 0x22, 0x58, 0x00, 0x78, 0x23, + 0xD5, 0x04, 0xB4, 0x01, 0x92, 0x10, 0xEA, 0x22, 0xB6, 0x01, 0xDD, 0x9E, 0x44, 0x24, 0x50, 0x14, + 0x84, 0x3E, 0xB4, 0x62, 0x96, 0x06, 0xFE, 0x5E, 0xFE, 0x0F, 0xB6, 0x02, 0xDD, 0x9E, 0x44, 0x24, + 0x00, 0x0C, 0x96, 0x06, 0xB4, 0x62, 0xDD, 0x56, 0xEA, 0x25, 0xFE, 0x1E, 0xFE, 0x0F, 0xB6, 0x02, + 0xDD, 0x9E, 0x44, 0x05, 0x10, 0x00, 0xB4, 0x00, 0x92, 0x08, 0x96, 0x17, 0xDD, 0x9E, 0x44, 0x25, + 0x10, 0x00, 0x96, 0x17, 0xB4, 0x62, 0xDD, 0x56, 0x44, 0x0F, 0xF8, 0xFF, 0xFE, 0x1E, 0xFE, 0x0F, + 0xB6, 0x02, 0xDD, 0x9E, 0x44, 0x24, 0x80, 0x84, 0x96, 0x06, 0xB4, 0x62, 0xDD, 0x56, 0xEA, 0x25, + 0xFE, 0x1E, 0xFE, 0x0F, 0xB6, 0x02, 0xDD, 0x9E, 0x44, 0x25, 0x10, 0x00, 0x84, 0x3E, 0xB4, 0x62, + 0x96, 0x06, 0xFE, 0x5E, 0xFE, 0x0F, 0xB6, 0x02, 0xDD, 0x9E, 0x44, 0x25, 0x10, 0x04, 0xB4, 0x22, + 0x92, 0x30, 0xEA, 0x28, 0xFE, 0x0F, 0xB6, 0x02, 0xDD, 0x9E, 0x44, 0x15, 0x10, 0x0C, 0xB4, 0x01, + 0xEA, 0xA1, 0xB6, 0x01, 0xDD, 0x9E, 0x44, 0x15, 0x10, 0x0C, 0xB4, 0x01, 0xDD, 0x4B, 0xB6, 0x01, + 0x44, 0x15, 0x10, 0x18, 0xB4, 0x01, 0x96, 0x00, 0x5A, 0x00, 0x5A, 0xFE, 0xDD, 0x9E, 0xFC, 0x40, + 0x44, 0x00, 0x01, 0x2C, 0xEA, 0x2D, 0x44, 0x75, 0x10, 0x0C, 0x44, 0x9F, 0xFF, 0x98, 0x84, 0x00, + 0xAE, 0x38, 0xFA, 0x18, 0x10, 0x93, 0x80, 0x00, 0xEA, 0x2D, 0x44, 0x05, 0x10, 0x18, 0x44, 0x65, + 0x10, 0x0C, 0xB4, 0x00, 0x96, 0x00, 0x5A, 0x00, 0xA5, 0xF4, 0xB4, 0x26, 0x84, 0x1E, 0xFE, 0x0E, + 0xB6, 0x06, 0xFC, 0xC0, 0x84, 0x02, 0xEB, 0x36, 0xEB, 0xF3, 0xDD, 0x9E, 0xDD, 0x46, 0xEA, 0xDF, + 0xC8, 0x0A, 0x3C, 0xF7, 0xEC, 0x9E, 0x2E, 0x20, 0x15, 0x49, 0xE0, 0x4F, 0xE8, 0x04, 0xEB, 0x36, + 0x84, 0x08, 0xEB, 0xF3, 0xDD, 0x9E, 0x2E, 0x07, 0xF0, 0xFB, 0x2E, 0x17, 0xEA, 0x5C, 0x8C, 0x01, + 0x96, 0x00, 0xE2, 0x01, 0xEB, 0x36, 0xE9, 0x07, 0x84, 0x00, 0xEB, 0x36, 0x84, 0x02, 0xEB, 0xF3, + 0x84, 0x01, 0xDD, 0x9E, 0x84, 0x00, 0xDD, 0x9E, 0xFC, 0x41, 0xFD, 0x30, 0xEA, 0x35, 0xF0, 0x81, + 0x85, 0x28, 0xCF, 0x02, 0xFB, 0x38, 0xCE, 0x08, 0xF0, 0x01, 0xEA, 0x52, 0x80, 0xE0, 0x49, 0x00, + 0x15, 0x6E, 0x80, 0x40, 0xD5, 0x08, 0x5A, 0x68, 0x02, 0x09, 0x49, 0x00, 0x15, 0x6B, 0x80, 0xE0, + 0x3C, 0x2C, 0x00, 0xE8, 0x80, 0xA6, 0xD5, 0x04, 0x84, 0xE0, 0x80, 0x47, 0x80, 0xA7, 0xEA, 0x9C, + 0x80, 0x27, 0x84, 0x61, 0x80, 0x89, 0x49, 0x00, 0x02, 0x75, 0xFC, 0xC1, 0xFC, 0x01, 0x80, 0xC0, + 0xEA, 0x38, 0x84, 0x00, 0xDD, 0x45, 0x84, 0x01, 0xEA, 0x20, 0xEA, 0x35, 0xB6, 0x1F, 0xEA, 0x3A, + 0xF0, 0x81, 0xB4, 0x3F, 0x84, 0x01, 0xF2, 0x01, 0xDD, 0x5B, 0x84, 0x01, 0xDD, 0x45, 0xEA, 0x37, + 0xC8, 0x0C, 0xDD, 0x50, 0xC0, 0x05, 0xDD, 0x58, 0x5A, 0x08, 0x02, 0x05, 0xD5, 0x06, 0xDD, 0x49, + 0xC0, 0xFB, 0xDD, 0x51, 0x5A, 0x08, 0x01, 0xF5, 0xEB, 0xA7, 0x84, 0x00, 0xEA, 0x7B, 0xEB, 0x04, + 0xEA, 0x57, 0xEA, 0x83, 0x50, 0x13, 0x05, 0x10, 0x80, 0xA6, 0x9A, 0xAE, 0x38, 0x21, 0x00, 0x11, + 0x1A, 0x22, 0x80, 0x01, 0xD9, 0xFB, 0xFC, 0x81, 0xFC, 0x20, 0x2E, 0x0F, 0xF0, 0xFA, 0xE4, 0x02, + 0xE8, 0x13, 0x2E, 0x1F, 0xF0, 0xF9, 0xE4, 0x22, 0xE8, 0x0F, 0xEA, 0x57, 0xEA, 0x83, 0x80, 0xC0, + 0xEA, 0x35, 0xEA, 0x52, 0x80, 0xA0, 0x8A, 0xC0, 0xEB, 0x6B, 0x38, 0x13, 0x14, 0x11, 0x1A, 0x12, + 0x80, 0x01, 0xD8, 0xFC, 0xD5, 0x30, 0x2E, 0x17, 0xEC, 0x11, 0xE0, 0x20, 0xE9, 0x2C, 0x2E, 0xFF, + 0xF0, 0xF9, 0x2E, 0x17, 0xEC, 0x10, 0xE0, 0x2F, 0xE9, 0x26, 0x49, 0x00, 0x14, 0xEC, 0xEA, 0x2F, + 0x2E, 0x30, 0x15, 0x49, 0x2E, 0x66, 0xF3, 0xAF, 0x84, 0x40, 0x2E, 0x46, 0xF3, 0xAE, 0x84, 0x23, + 0xFE, 0xCC, 0xE0, 0x46, 0xE8, 0x15, 0x42, 0x51, 0x10, 0x24, 0x84, 0x20, 0xE0, 0x24, 0xE8, 0x0D, + 0x99, 0xCD, 0x38, 0xF0, 0x1D, 0x11, 0xE0, 0x6F, 0xE8, 0x05, 0x84, 0x00, 0x3E, 0x07, 0xF0, 0xF9, + 0xD5, 0x07, 0x8C, 0x21, 0x96, 0x4B, 0xD5, 0xF3, 0x8C, 0x41, 0x96, 0x93, 0xD5, 0xEB, 0x84, 0x00, + 0x84, 0x21, 0xEB, 0x07, 0x2E, 0x1F, 0xF0, 0xFA, 0x2E, 0x07, 0xEC, 0x11, 0xE0, 0x01, 0xE9, 0x07, + 0x2E, 0x0F, 0xF0, 0xF9, 0x2E, 0x27, 0xEC, 0x10, 0xE0, 0x40, 0xE8, 0x08, 0x84, 0x00, 0x3E, 0x07, + 0xF0, 0xFA, 0x3E, 0x07, 0xF0, 0xF9, 0x84, 0x01, 0xFC, 0xA0, 0x8C, 0x21, 0x8C, 0x01, 0x3E, 0x07, + 0xF0, 0xF9, 0x3E, 0x17, 0xF0, 0xFA, 0x84, 0x00, 0xFC, 0xA0, 0xFC, 0x00, 0x49, 0xFF, 0xFE, 0x46, + 0x80, 0xA0, 0x44, 0x60, 0xC9, 0xAE, 0xD6, 0x1A, 0x44, 0x00, 0xF3, 0x8A, 0xD8, 0x08, 0x44, 0x00, + 0x4E, 0x1D, 0xEA, 0xF1, 0xEA, 0x48, 0xDD, 0x4B, 0xEA, 0xFB, 0xFC, 0x80, 0x44, 0x00, 0xA6, 0x7C, + 0xD8, 0x06, 0x49, 0xFF, 0xF8, 0x89, 0xC8, 0x0A, 0x80, 0x06, 0xD5, 0x07, 0x44, 0x00, 0x84, 0x11, + 0xD8, 0x05, 0x49, 0xFF, 0xF8, 0x81, 0xC8, 0x02, 0xEA, 0xF1, 0xFC, 0x80, 0xFC, 0x00, 0x44, 0x00, + 0x84, 0x11, 0xEA, 0xF1, 0xEA, 0x48, 0x96, 0x06, 0xC0, 0x0B, 0x44, 0x00, 0xA6, 0x7C, 0xEA, 0xF1, + 0xEA, 0x48, 0xEA, 0xA5, 0xEA, 0xFB, 0xEA, 0x48, 0x54, 0x00, 0x00, 0xFE, 0xEA, 0xFB, 0xFC, 0x80, + 0xFC, 0x00, 0x84, 0x00, 0xEA, 0xF1, 0xFC, 0x80, 0x4E, 0x05, 0x00, 0x18, 0x8E, 0x01, 0xEA, 0xAD, + 0xFE, 0x0F, 0x40, 0x10, 0x08, 0x0A, 0xFE, 0x0F, 0x40, 0x10, 0x10, 0x0A, 0xFE, 0x0F, 0x40, 0x10, + 0x20, 0x0A, 0xFE, 0x0F, 0x40, 0x10, 0x40, 0x0A, 0xFE, 0x47, 0x8C, 0x21, 0x84, 0x00, 0x90, 0x21, + 0xC1, 0x03, 0x8C, 0x01, 0xD5, 0xFD, 0xDD, 0x9E, 0x84, 0x00, 0xDD, 0x9E, 0xFC, 0x4D, 0x44, 0x01, + 0x29, 0xB4, 0x50, 0xFF, 0x80, 0x18, 0x80, 0xC0, 0x80, 0x2F, 0xEB, 0x64, 0xEA, 0x9F, 0x81, 0x46, + 0x83, 0x81, 0x3A, 0x25, 0x14, 0x04, 0x44, 0x91, 0x29, 0xDC, 0x3A, 0x2E, 0x14, 0x24, 0x80, 0x89, + 0x3A, 0x25, 0x0C, 0x00, 0x80, 0xBF, 0x3A, 0x2E, 0x0C, 0x20, 0x3A, 0x22, 0x0C, 0x04, 0x3A, 0x22, + 0x8C, 0x24, 0x45, 0xE2, 0x25, 0x84, 0xA5, 0xE0, 0x3A, 0x27, 0x94, 0x04, 0x81, 0xFE, 0x81, 0x1F, + 0xEB, 0x5C, 0xEA, 0x88, 0x80, 0x2F, 0xEA, 0x9F, 0x3A, 0x2E, 0x0C, 0x00, 0x3A, 0x20, 0x8C, 0x20, + 0x44, 0x12, 0x25, 0x78, 0x3A, 0x24, 0x0C, 0x04, 0x3A, 0x20, 0x8C, 0x24, 0xAD, 0xC8, 0xB0, 0x50, + 0xEA, 0x4D, 0x80, 0x01, 0xEA, 0x5B, 0x81, 0x00, 0xEB, 0x64, 0x3A, 0x24, 0x14, 0x24, 0xB1, 0x83, + 0x3A, 0x25, 0x0C, 0x00, 0x80, 0x86, 0x3A, 0x24, 0x0C, 0x20, 0x3A, 0x24, 0x8C, 0x04, 0x44, 0x92, + 0x1E, 0xE4, 0x3A, 0x22, 0x0C, 0x24, 0xEA, 0x88, 0x80, 0x29, 0xEA, 0x9F, 0xEA, 0x4D, 0x80, 0x01, + 0xEA, 0x5B, 0x3A, 0x24, 0x0C, 0x00, 0xEB, 0xEF, 0x44, 0x02, 0x1E, 0xD8, 0x3A, 0x23, 0x0C, 0x04, + 0x3A, 0x20, 0x0C, 0x24, 0xAD, 0xC0, 0xFC, 0xCD, 0xFC, 0x48, 0x81, 0x20, 0x50, 0xAF, 0x80, 0x14, + 0x44, 0x01, 0x29, 0xE8, 0x83, 0x81, 0x80, 0x2A, 0x80, 0xE2, 0x80, 0xC3, 0x3A, 0x20, 0x0C, 0x04, + 0x3A, 0x20, 0x8C, 0x24, 0xA4, 0x00, 0xFA, 0x40, 0xAC, 0x08, 0x50, 0x8F, 0x80, 0x30, 0x84, 0x20, + 0xB0, 0x08, 0xDD, 0x40, 0x80, 0x08, 0x84, 0x20, 0xFA, 0x40, 0xDD, 0x40, 0x5A, 0x78, 0x01, 0x03, + 0x87, 0x80, 0x4E, 0x92, 0x00, 0x05, 0x44, 0x12, 0x1E, 0x5C, 0xD5, 0x03, 0x44, 0x12, 0x1E, 0xB8, + 0x5A, 0x68, 0x02, 0x05, 0x58, 0x03, 0x80, 0x01, 0xD5, 0x02, 0x80, 0x07, 0x8C, 0x01, 0x85, 0x20, + 0xB6, 0x1F, 0x8C, 0xE1, 0x84, 0x63, 0x84, 0x81, 0x38, 0x05, 0x24, 0x00, 0xF4, 0x83, 0xF3, 0x82, + 0x38, 0x60, 0x80, 0x00, 0xB4, 0x1F, 0x8C, 0xC1, 0xFF, 0x84, 0x97, 0xB1, 0x40, 0x63, 0x1C, 0xD6, + 0x80, 0x06, 0xF1, 0x81, 0x49, 0xFF, 0xFF, 0x52, 0xF3, 0x02, 0x54, 0x54, 0x80, 0xFF, 0x40, 0x52, + 0x8C, 0xB7, 0xF4, 0x03, 0x38, 0x24, 0x16, 0x02, 0x8C, 0x08, 0x41, 0xE1, 0x28, 0x08, 0x40, 0x20, + 0x70, 0x01, 0x40, 0x02, 0x00, 0x0C, 0x40, 0x60, 0x18, 0xD7, 0xB0, 0x08, 0x94, 0x94, 0x38, 0x00, + 0x16, 0x02, 0x88, 0x5E, 0xEA, 0x21, 0x88, 0xC0, 0xB0, 0x08, 0x8D, 0x21, 0x38, 0x24, 0x16, 0x0A, + 0x38, 0x60, 0x16, 0x0A, 0xF1, 0x01, 0x5A, 0x98, 0x0A, 0xD1, 0x80, 0x28, 0x49, 0xFF, 0xEA, 0xA0, + 0xFC, 0xC8, 0x80, 0x80, 0x84, 0x40, 0x9A, 0xE0, 0x96, 0xD8, 0xE2, 0x61, 0xE8, 0x08, 0x08, 0x32, + 0x00, 0x01, 0xE2, 0x62, 0x40, 0x31, 0x3C, 0x1B, 0x80, 0x43, 0xD5, 0xF6, 0x9C, 0x11, 0x96, 0x00, + 0xDD, 0x9E, 0xFC, 0x40, 0x51, 0xFF, 0xFB, 0xE0, 0x44, 0x20, 0x04, 0x00, 0x80, 0xE0, 0x81, 0x21, + 0xB0, 0x08, 0x84, 0x20, 0xDD, 0x40, 0x50, 0xAF, 0x80, 0x04, 0x44, 0x01, 0x29, 0xE8, 0x80, 0x2A, + 0x3A, 0x20, 0x0C, 0x04, 0x3A, 0x20, 0x8C, 0x24, 0xA4, 0x00, 0xB1, 0x84, 0xAC, 0x08, 0xFA, 0x40, + 0x80, 0x06, 0x84, 0x20, 0xDD, 0x40, 0xCF, 0x04, 0x44, 0x02, 0x1E, 0xB8, 0xD5, 0x03, 0x44, 0x02, + 0x1E, 0x5C, 0x84, 0x2A, 0x49, 0xFF, 0xFF, 0xCF, 0x80, 0x20, 0x80, 0x4A, 0x84, 0x80, 0x44, 0x82, + 0x1E, 0xE4, 0x45, 0xC2, 0x1E, 0xD8, 0x84, 0x03, 0x40, 0xA2, 0x01, 0x57, 0xB1, 0x48, 0x40, 0x35, + 0x20, 0x08, 0x88, 0x65, 0x84, 0xA0, 0xCF, 0x21, 0x80, 0xA7, 0x54, 0xF2, 0x80, 0xFF, 0x40, 0xF7, + 0x84, 0x06, 0xE8, 0x15, 0x00, 0xF1, 0x00, 0x00, 0x44, 0x02, 0x25, 0x84, 0x38, 0xF0, 0x3E, 0x02, + 0x38, 0xF7, 0x95, 0x01, 0x55, 0xE7, 0x83, 0xFF, 0x38, 0xF1, 0x96, 0x02, 0x40, 0xF7, 0xA8, 0x08, + 0x40, 0xFF, 0x3C, 0x00, 0x38, 0xF1, 0x96, 0x0A, 0x8C, 0xA1, 0xD5, 0xE8, 0xA6, 0xD0, 0x44, 0x02, + 0x25, 0x78, 0x38, 0x30, 0x0C, 0x00, 0xD5, 0x1B, 0x54, 0xF2, 0x80, 0xFF, 0x40, 0xF7, 0x84, 0x06, + 0xE8, 0x13, 0x00, 0xF1, 0x00, 0x00, 0x38, 0xF4, 0x3E, 0x02, 0x38, 0xF7, 0x95, 0x01, 0x55, 0xE7, + 0x83, 0xFF, 0x38, 0xF1, 0x96, 0x02, 0x40, 0xF7, 0xA8, 0x08, 0x40, 0xFF, 0x3C, 0x00, 0x38, 0xF1, + 0x96, 0x0A, 0x8C, 0xA1, 0xD5, 0xEA, 0xA6, 0xD0, 0x38, 0x3E, 0x0C, 0x00, 0x8A, 0x69, 0x54, 0x51, + 0x83, 0xFF, 0x38, 0x33, 0x2A, 0x02, 0x8C, 0x81, 0x40, 0x31, 0xA8, 0x08, 0x88, 0x65, 0x97, 0x20, + 0x38, 0x33, 0x2A, 0x0A, 0x8C, 0x41, 0x5A, 0x48, 0x0A, 0xB0, 0xB0, 0x08, 0x49, 0xFF, 0xEA, 0x5B, + 0x80, 0x06, 0x49, 0xFF, 0xEA, 0x8E, 0x51, 0xFF, 0x84, 0x20, 0xFC, 0xC0, 0xFC, 0x42, 0x85, 0x20, + 0x80, 0xC0, 0x80, 0x03, 0x80, 0xE1, 0xF4, 0x81, 0x14, 0x9F, 0x80, 0x03, 0xEA, 0x83, 0xF0, 0x83, + 0xF0, 0x01, 0xEA, 0x52, 0xF1, 0x03, 0x80, 0x49, 0xF1, 0x83, 0x44, 0x92, 0x19, 0x0C, 0x84, 0x80, + 0x98, 0xD4, 0x96, 0xD9, 0x38, 0x14, 0x8D, 0x01, 0xC6, 0x0A, 0x04, 0xAF, 0x80, 0x03, 0x38, 0x50, + 0x05, 0x01, 0x38, 0x15, 0x05, 0x01, 0x8A, 0xA1, 0x38, 0x53, 0x0D, 0x09, 0xC7, 0x06, 0xF1, 0x03, + 0x38, 0x10, 0x8D, 0x11, 0x38, 0x13, 0x8D, 0x09, 0x8C, 0x81, 0x5A, 0x48, 0x12, 0xEB, 0x8C, 0x52, + 0x96, 0x91, 0x5A, 0x2A, 0x88, 0xE6, 0xFC, 0xC2, 0xFC, 0x41, 0x84, 0xC0, 0x81, 0x20, 0x80, 0x02, + 0x80, 0xE1, 0xF6, 0x81, 0xEA, 0x52, 0xF0, 0x81, 0x80, 0x46, 0x96, 0x51, 0xE2, 0x27, 0xE8, 0x08, + 0xF0, 0x01, 0x38, 0x00, 0x09, 0x11, 0x38, 0x04, 0x89, 0x09, 0x8C, 0x41, 0xD5, 0xF7, 0xFC, 0xC1, + 0xFC, 0x40, 0x44, 0xA0, 0x80, 0x00, 0x40, 0x92, 0x04, 0x0A, 0xC0, 0x2B, 0x2A, 0x51, 0x00, 0x01, + 0x2A, 0x80, 0x80, 0x01, 0x40, 0x74, 0x40, 0x08, 0x40, 0x52, 0xC0, 0x08, 0x8A, 0xA7, 0x80, 0xC9, + 0x42, 0x61, 0x94, 0x73, 0x40, 0x53, 0x10, 0xB6, 0x80, 0xC5, 0x4E, 0x54, 0x00, 0x03, 0xFF, 0xAA, + 0x90, 0xD0, 0xCE, 0x0F, 0x40, 0x74, 0x00, 0x13, 0x4E, 0x56, 0x00, 0x07, 0xE2, 0xC5, 0x52, 0x57, + 0x80, 0x00, 0x97, 0x69, 0xD5, 0x02, 0x84, 0xA1, 0x88, 0xA7, 0x12, 0x50, 0xFF, 0xFF, 0xD5, 0x06, + 0x88, 0xE5, 0x88, 0xEA, 0x90, 0xF0, 0x12, 0x70, 0xFF, 0xFF, 0x8E, 0x01, 0x96, 0x01, 0xD5, 0xD6, + 0xFC, 0xC0, 0x2E, 0x17, 0xD8, 0xCC, 0x88, 0x01, 0x96, 0x01, 0x54, 0x10, 0x00, 0x01, 0xC1, 0x03, + 0x8C, 0x01, 0x96, 0x01, 0xDD, 0x9E, 0xEA, 0xFF, 0xDD, 0x9E, 0x3E, 0x07, 0xF2, 0x08, 0xDD, 0x9E, + 0xFC, 0x00, 0x84, 0x42, 0x80, 0x61, 0x5A, 0x10, 0x01, 0x03, 0x84, 0x40, 0x94, 0x91, 0xFE, 0x14, + 0x96, 0x40, 0xCB, 0x06, 0x44, 0x02, 0x1E, 0xB8, 0x49, 0xFF, 0xF2, 0x13, 0xFC, 0x80, 0x44, 0x02, + 0x1E, 0x5C, 0x49, 0xFF, 0xF2, 0x0E, 0xFC, 0x80, 0xFC, 0x00, 0x80, 0xC0, 0x5A, 0x18, 0x01, 0x04, + 0x84, 0x22, 0xD5, 0x02, 0x84, 0x20, 0x42, 0x00, 0x98, 0x24, 0x54, 0x00, 0x00, 0xFE, 0x49, 0xFF, + 0xF1, 0x99, 0x80, 0x06, 0x84, 0x20, 0x49, 0xFF, 0xF1, 0xBD, 0x80, 0x06, 0x49, 0xFF, 0xF1, 0xE8, + 0xFC, 0x80, 0xFC, 0x49, 0x84, 0x20, 0x80, 0xE0, 0xEA, 0xA7, 0xB0, 0x06, 0xDD, 0x40, 0xEB, 0x35, + 0xEA, 0xC7, 0xF0, 0x86, 0xEB, 0x7B, 0xF1, 0x89, 0xF0, 0x87, 0xEA, 0xFD, 0xEB, 0x0C, 0xF1, 0x8A, + 0x94, 0x46, 0xF0, 0x88, 0xF1, 0x8B, 0xDD, 0x56, 0xEA, 0x21, 0xF1, 0x8C, 0xF0, 0x8D, 0x5A, 0x78, + 0x01, 0x07, 0x44, 0x62, 0x1E, 0x68, 0x44, 0x92, 0x1E, 0x34, 0xD5, 0x05, 0x44, 0x62, 0x1E, 0xA4, + 0x44, 0x92, 0x1E, 0x7C, 0xB0, 0x06, 0xEA, 0xC1, 0x80, 0x1F, 0x44, 0x12, 0x1F, 0xD8, 0xFA, 0x48, + 0xCF, 0x07, 0xDD, 0x55, 0x80, 0x1F, 0xEA, 0xD2, 0x80, 0x07, 0xEA, 0x4A, 0xD5, 0x06, 0xDD, 0x55, + 0x80, 0x1F, 0xEA, 0xD2, 0x84, 0x01, 0xEA, 0x4A, 0x2E, 0x47, 0xF2, 0x08, 0x84, 0x00, 0x80, 0x66, + 0x80, 0x49, 0x80, 0xA4, 0x80, 0x20, 0xEB, 0xD7, 0x2E, 0x17, 0xF2, 0x08, 0x84, 0x00, 0x38, 0x14, + 0x85, 0x01, 0xEA, 0xAC, 0x2E, 0x17, 0xF2, 0x08, 0x84, 0x04, 0x38, 0x14, 0x85, 0x01, 0xEA, 0xAC, + 0xEA, 0xFF, 0x84, 0x20, 0x38, 0x03, 0x00, 0x00, 0xEB, 0xE4, 0xEA, 0xFF, 0x84, 0x23, 0x38, 0x03, + 0x00, 0x00, 0xEB, 0xE4, 0xEA, 0x9C, 0x49, 0xFF, 0xF4, 0xAB, 0x84, 0x02, 0x49, 0xFF, 0xF4, 0xFD, + 0x84, 0xC0, 0x5A, 0x78, 0x01, 0x06, 0x2E, 0x67, 0xF2, 0x08, 0x5C, 0x63, 0x00, 0x04, 0x97, 0xB0, + 0xFD, 0x03, 0x3E, 0x67, 0xF2, 0x09, 0x49, 0xFF, 0xFF, 0x89, 0xFD, 0x03, 0x49, 0xFF, 0xFF, 0x72, + 0x80, 0x07, 0x49, 0x00, 0x15, 0xEC, 0xFC, 0xC9, 0xFC, 0x00, 0x44, 0x02, 0x5E, 0x9C, 0x84, 0x20, + 0x44, 0x20, 0x01, 0x20, 0xDD, 0x40, 0x84, 0x00, 0xEB, 0xE9, 0xFC, 0x80, 0x3C, 0x23, 0xF8, 0x9A, + 0xC1, 0x05, 0xFE, 0x87, 0x3C, 0x2B, 0xF8, 0x9A, 0xDD, 0x9E, 0xFE, 0x03, 0xFE, 0x86, 0x3C, 0x2B, + 0xF8, 0x9A, 0xDD, 0x9E, 0xFC, 0x42, 0x3C, 0x03, 0xEF, 0xC2, 0x5C, 0xF0, 0x01, 0x45, 0xE9, 0x05, + 0x44, 0x00, 0x20, 0x00, 0x84, 0x21, 0xDD, 0x43, 0xEB, 0x61, 0x44, 0xA2, 0x25, 0xE8, 0xF0, 0x81, + 0x84, 0xE0, 0x44, 0x90, 0x00, 0x36, 0x94, 0x39, 0x84, 0xC0, 0xF0, 0x82, 0x96, 0x38, 0x81, 0x06, + 0x83, 0x86, 0xF0, 0x83, 0xF5, 0x01, 0xF2, 0x03, 0x96, 0x30, 0xDA, 0x04, 0x2E, 0x57, 0xDE, 0xED, + 0xD0, 0x19, 0xFA, 0x34, 0x44, 0x02, 0x13, 0xFC, 0x42, 0x03, 0x04, 0x73, 0xF1, 0x02, 0x38, 0x20, + 0x04, 0x01, 0x5C, 0xF1, 0x01, 0x45, 0x8E, 0x41, 0xE9, 0x18, 0x40, 0x01, 0x24, 0x56, 0x84, 0x20, + 0x84, 0x01, 0x52, 0x21, 0x00, 0x35, 0x49, 0x00, 0x22, 0x7D, 0x40, 0x84, 0x00, 0x04, 0x41, 0xCE, + 0x04, 0x04, 0x8C, 0xC1, 0x5A, 0x68, 0x24, 0xE0, 0x8C, 0xE1, 0xB7, 0x0A, 0x15, 0xC5, 0x00, 0x01, + 0x8D, 0x48, 0x5A, 0x78, 0x12, 0xD2, 0xFC, 0xC2, 0x40, 0x01, 0x24, 0x56, 0x84, 0x20, 0x84, 0x01, + 0x49, 0x00, 0x22, 0x68, 0x40, 0x84, 0x00, 0x04, 0x41, 0xCE, 0x04, 0x04, 0xD5, 0xEB, 0x3C, 0x23, + 0xF8, 0x9A, 0x84, 0x21, 0x40, 0x10, 0x80, 0x0C, 0xFE, 0x56, 0x40, 0x00, 0x80, 0x0E, 0x96, 0x06, + 0xDD, 0x9E, 0xFC, 0x00, 0x49, 0x00, 0x11, 0xA8, 0x80, 0xC0, 0xEA, 0x34, 0x4E, 0x02, 0x00, 0x89, + 0xEB, 0x48, 0x50, 0x00, 0x03, 0x84, 0xAC, 0x30, 0xEA, 0xFF, 0xAC, 0x31, 0xEA, 0x26, 0x2E, 0x17, + 0xF2, 0x08, 0xC8, 0x07, 0x44, 0x02, 0x1E, 0x7C, 0x38, 0x00, 0x05, 0x01, 0xAC, 0x32, 0xD5, 0x06, + 0x44, 0x02, 0x1E, 0x34, 0x38, 0x00, 0x05, 0x01, 0xAC, 0x32, 0x3C, 0x03, 0xF9, 0x02, 0xAC, 0x33, + 0x3C, 0x03, 0xF8, 0x9D, 0xAC, 0x34, 0x84, 0x09, 0xDD, 0x4A, 0x50, 0x00, 0x00, 0x64, 0xAC, 0x35, + 0x84, 0x04, 0xDD, 0x4A, 0x50, 0x00, 0x00, 0xC8, 0xAC, 0x36, 0x84, 0x08, 0xDD, 0x4A, 0x50, 0x00, + 0x01, 0x2C, 0xAC, 0x37, 0x3C, 0x03, 0xF8, 0x9A, 0xEA, 0x69, 0xEA, 0x55, 0x3C, 0x03, 0xF9, 0x01, + 0x12, 0x03, 0x00, 0x09, 0x49, 0xFF, 0xEB, 0xE3, 0x12, 0x03, 0x00, 0x0A, 0x44, 0x0F, 0xFF, 0x9C, + 0x12, 0x03, 0x00, 0x0B, 0x2E, 0x00, 0x1C, 0xA3, 0x12, 0x03, 0x00, 0x0C, 0x2E, 0x00, 0x1D, 0xAF, + 0x12, 0x03, 0x00, 0x0D, 0xEB, 0x2F, 0x96, 0x06, 0x12, 0x03, 0x00, 0x0E, 0x3C, 0x03, 0xF8, 0x08, + 0x12, 0x03, 0x00, 0x0F, 0x3C, 0x03, 0xF8, 0x07, 0x12, 0x03, 0x00, 0x21, 0x3C, 0x03, 0xF8, 0x05, + 0x12, 0x03, 0x00, 0x22, 0x44, 0x00, 0x03, 0x09, 0x12, 0x03, 0x00, 0x23, 0x2E, 0x07, 0xF0, 0x13, + 0x12, 0x03, 0x00, 0x28, 0x44, 0x00, 0x03, 0xE7, 0x12, 0x03, 0x00, 0x29, 0xDD, 0x46, 0xDD, 0x4F, + 0x92, 0x02, 0x96, 0x06, 0x96, 0x66, 0x12, 0x03, 0x00, 0x2A, 0xC1, 0x02, 0x84, 0x24, 0x3C, 0x3D, + 0xFB, 0x5B, 0x54, 0x01, 0x82, 0x00, 0x84, 0x62, 0xC8, 0x02, 0x80, 0x60, 0x3C, 0x2D, 0xFB, 0x5B, + 0x92, 0x48, 0x96, 0x86, 0xFE, 0x57, 0x40, 0x01, 0x84, 0x04, 0x12, 0x03, 0x00, 0x2B, 0xDD, 0x46, + 0x92, 0x0F, 0x96, 0x06, 0x12, 0x03, 0x00, 0x2C, 0xDD, 0x46, 0x92, 0x05, 0x96, 0x06, 0x12, 0x03, + 0x00, 0x2D, 0xDD, 0x41, 0xC8, 0x05, 0x3C, 0x03, 0xF6, 0xF1, 0x12, 0x03, 0x00, 0x30, 0xFC, 0x80, + 0xFC, 0x40, 0x44, 0x52, 0x50, 0x30, 0x2E, 0x46, 0xF3, 0xAE, 0x84, 0x60, 0x3C, 0x73, 0x79, 0xD4, + 0x2E, 0x07, 0xED, 0xB6, 0x2E, 0x66, 0xF3, 0xAF, 0x2E, 0x17, 0xED, 0xB5, 0x3C, 0x23, 0x79, 0xD5, + 0x40, 0x73, 0x90, 0xF6, 0x40, 0x91, 0x19, 0x36, 0x9E, 0xB1, 0x54, 0x81, 0x00, 0xFF, 0x9E, 0xA1, + 0x51, 0xE2, 0x8A, 0x78, 0x81, 0x43, 0x55, 0xC1, 0x00, 0xFF, 0x00, 0x22, 0x80, 0xEB, 0xC2, 0x1B, + 0x04, 0x22, 0x80, 0x0B, 0x4E, 0x24, 0x00, 0x03, 0xFE, 0x92, 0xE2, 0x62, 0xE8, 0x14, 0x22, 0x02, + 0x80, 0x1D, 0x22, 0x12, 0x80, 0x1E, 0x40, 0x00, 0x1C, 0x17, 0x96, 0x00, 0x40, 0x10, 0xA4, 0x37, + 0xE2, 0x04, 0x96, 0x48, 0x40, 0x0E, 0x3C, 0x1A, 0xE2, 0x26, 0x40, 0x14, 0x3C, 0x1A, 0x22, 0xA2, + 0x80, 0x48, 0x80, 0x62, 0xEB, 0x7A, 0x4C, 0x5F, 0x7F, 0xE2, 0xE6, 0x09, 0x80, 0xC0, 0x3E, 0x17, + 0xF1, 0x36, 0xE9, 0x04, 0x52, 0x60, 0x00, 0x11, 0x97, 0xB0, 0xC6, 0x1A, 0xE4, 0xC8, 0xE8, 0x1B, + 0xE6, 0xC2, 0x85, 0x20, 0xE9, 0x03, 0x9E, 0x72, 0xEB, 0x8D, 0x84, 0xE8, 0x5A, 0x60, 0x07, 0x04, + 0x9D, 0xF2, 0x97, 0xF8, 0xE6, 0x09, 0x4E, 0xA7, 0x00, 0x07, 0x40, 0x93, 0x3C, 0x1B, 0x40, 0x73, + 0x3C, 0x1A, 0xD5, 0x0B, 0x40, 0x73, 0x3C, 0x1B, 0x40, 0x93, 0x3C, 0x1A, 0xD5, 0x06, 0x81, 0x26, + 0x84, 0xE1, 0xD5, 0x03, 0x84, 0xE8, 0x85, 0x27, 0x84, 0x04, 0x84, 0x20, 0xDD, 0x43, 0x2E, 0xA7, + 0xF1, 0x37, 0x4E, 0xA3, 0x00, 0x26, 0x80, 0x0A, 0xDD, 0x4A, 0xC8, 0x17, 0xEA, 0x7F, 0x96, 0x06, + 0xC0, 0x14, 0x2E, 0x57, 0xEB, 0x3C, 0xD6, 0x11, 0x84, 0x06, 0xDD, 0x4A, 0x80, 0x20, 0xC8, 0x0D, + 0xEB, 0x48, 0x5A, 0x00, 0x05, 0x0B, 0x84, 0x02, 0xDD, 0x43, 0x44, 0x00, 0x04, 0x25, 0x84, 0x21, + 0xDD, 0x43, 0x3E, 0x67, 0xEB, 0x3C, 0xD5, 0x25, 0x84, 0x05, 0xDD, 0x4A, 0xC0, 0x22, 0xFA, 0x12, + 0x84, 0x20, 0xDD, 0x43, 0xEA, 0x4B, 0x84, 0x01, 0xFE, 0x46, 0xDD, 0x43, 0xD5, 0x1A, 0x5A, 0xA8, + 0x01, 0x19, 0x84, 0x06, 0xDD, 0x4A, 0xC8, 0x05, 0xEA, 0x4B, 0x80, 0x0A, 0x96, 0x46, 0xDD, 0x43, + 0x2E, 0x57, 0xEB, 0x3C, 0xDE, 0x08, 0x84, 0x05, 0xDD, 0x4A, 0x80, 0x20, 0xC8, 0x04, 0x84, 0x02, + 0xDD, 0x43, 0xD5, 0x07, 0x44, 0x00, 0x04, 0x24, 0x84, 0x21, 0xDD, 0x43, 0x3E, 0x67, 0xEB, 0x3C, + 0x84, 0x02, 0xDD, 0x4A, 0xC0, 0x0B, 0x44, 0x02, 0x5F, 0xBC, 0x38, 0x10, 0x26, 0x02, 0x38, 0x00, + 0x1E, 0x02, 0x3C, 0x1F, 0xFA, 0xD3, 0x3C, 0x0F, 0xFA, 0xD2, 0x84, 0x0A, 0xDD, 0x4A, 0xC0, 0x07, + 0x3E, 0x97, 0xEB, 0x43, 0x3E, 0x67, 0xEB, 0x44, 0x3E, 0x77, 0xEB, 0x45, 0xFC, 0xC0, 0xFC, 0x44, + 0xEA, 0x57, 0xEA, 0x83, 0xEB, 0x6B, 0xF0, 0x86, 0xEA, 0x61, 0x84, 0xE0, 0xF0, 0x87, 0x84, 0x00, + 0xF0, 0x84, 0xF0, 0x06, 0x84, 0xC0, 0xF0, 0x85, 0x9A, 0x3E, 0x40, 0x10, 0x7C, 0x0A, 0xFE, 0x0D, + 0x9A, 0x41, 0x44, 0x22, 0x1F, 0xB8, 0x84, 0x0D, 0x38, 0x91, 0x05, 0x00, 0xDD, 0x4A, 0x9A, 0x70, + 0x4E, 0x15, 0x00, 0xA1, 0xFA, 0x01, 0xFE, 0x44, 0x40, 0x04, 0x84, 0x01, 0x4E, 0x05, 0x00, 0xA9, + 0x96, 0x08, 0x40, 0x04, 0x80, 0x01, 0x96, 0x00, 0x44, 0x12, 0x25, 0xE8, 0x94, 0x03, 0x88, 0x01, + 0xF2, 0x07, 0x3A, 0x00, 0x04, 0x00, 0xF5, 0x05, 0x3A, 0x0F, 0x84, 0x20, 0x5A, 0x20, 0x01, 0x3D, + 0x94, 0x09, 0x84, 0x40, 0x84, 0x80, 0xF0, 0x83, 0xD5, 0x04, 0x8C, 0xA8, 0x5A, 0x20, 0x36, 0x27, + 0xF3, 0x03, 0x40, 0x81, 0x08, 0x05, 0xB4, 0x3F, 0x40, 0x81, 0xA0, 0x0C, 0xF3, 0x01, 0x40, 0x10, + 0x88, 0x0D, 0x54, 0xA1, 0x00, 0x20, 0x40, 0x91, 0x88, 0x0D, 0x40, 0x14, 0x04, 0x04, 0x94, 0x21, + 0x88, 0x06, 0x40, 0x14, 0xA8, 0x1B, 0x94, 0x01, 0x96, 0x46, 0x50, 0x82, 0x00, 0x01, 0x88, 0x07, + 0x8C, 0x41, 0xC1, 0xE4, 0x54, 0x44, 0x00, 0xFF, 0x44, 0x32, 0x5E, 0x9C, 0x22, 0x92, 0x80, 0x00, + 0x5C, 0xF2, 0x00, 0x24, 0x38, 0x91, 0x81, 0x09, 0xE9, 0xD9, 0xF0, 0x05, 0x8C, 0x04, 0xF0, 0x85, + 0x5A, 0x60, 0x01, 0x04, 0x84, 0xC1, 0xD5, 0xA9, 0xF0, 0x06, 0x8C, 0x02, 0xF0, 0x86, 0x5A, 0x70, + 0x01, 0x5C, 0x84, 0xE1, 0xD5, 0x9F, 0xF0, 0x01, 0x84, 0x20, 0x94, 0x01, 0x85, 0xE0, 0xF0, 0x83, + 0xD5, 0x1A, 0xF3, 0x04, 0x42, 0x8E, 0x20, 0x24, 0x41, 0xC4, 0x00, 0x13, 0x41, 0xC1, 0xF0, 0x06, + 0x40, 0x81, 0xF0, 0x1A, 0x40, 0x34, 0x00, 0x13, 0xF3, 0x84, 0xC2, 0x0A, 0x54, 0xFF, 0x00, 0xFF, + 0x44, 0x32, 0x5E, 0x9C, 0x5C, 0x27, 0x80, 0x24, 0x38, 0xA1, 0x81, 0x09, 0xC2, 0xD7, 0x8C, 0xA8, + 0x5A, 0x10, 0x36, 0xD5, 0x40, 0x07, 0x84, 0x08, 0x99, 0x06, 0xF3, 0x03, 0x41, 0xC0, 0x84, 0x05, + 0x95, 0x21, 0x41, 0xC1, 0xF0, 0x0C, 0x88, 0x87, 0x44, 0x32, 0x5E, 0x9C, 0xB4, 0x5F, 0x38, 0x91, + 0x91, 0x11, 0xF3, 0x01, 0x40, 0x21, 0x04, 0x0D, 0x54, 0x80, 0x80, 0x20, 0x40, 0x41, 0x84, 0x0D, + 0x40, 0x2E, 0x08, 0x04, 0x22, 0xA2, 0x80, 0x00, 0x40, 0x22, 0x20, 0x1B, 0x88, 0x06, 0x94, 0x01, + 0x96, 0x86, 0x40, 0x45, 0x24, 0x01, 0x51, 0xE7, 0x80, 0x01, 0x88, 0x07, 0x8C, 0x21, 0x41, 0xC2, + 0x00, 0x13, 0x40, 0x81, 0x00, 0x13, 0x4E, 0x44, 0xFF, 0xBE, 0x8B, 0x2A, 0x41, 0xC4, 0x80, 0x13, + 0xD5, 0xB9, 0xFA, 0x21, 0x8A, 0x06, 0xFE, 0x0C, 0x40, 0x14, 0x80, 0x01, 0x4E, 0x15, 0x00, 0x2D, + 0x96, 0x00, 0x48, 0xFF, 0xFF, 0x60, 0xF0, 0x07, 0x5A, 0x00, 0x01, 0x08, 0xFC, 0xC4, 0x96, 0x08, + 0x8A, 0x09, 0x96, 0x00, 0x48, 0xFF, 0xFF, 0x5A, 0xF0, 0x04, 0xEA, 0x4B, 0x85, 0x0A, 0x42, 0x80, + 0x20, 0x24, 0x96, 0x4E, 0xFA, 0x01, 0x40, 0x84, 0x01, 0x17, 0xC9, 0x18, 0x3C, 0x00, 0x0A, 0xB8, + 0x44, 0x10, 0x03, 0xE8, 0x42, 0x04, 0x00, 0x24, 0xDD, 0x5C, 0xEB, 0x09, 0x96, 0x01, 0xE0, 0x20, + 0xE9, 0x1A, 0x84, 0x4D, 0xFE, 0x14, 0x84, 0x47, 0xFA, 0x64, 0xFE, 0x54, 0xEB, 0x12, 0xEA, 0xE6, + 0x88, 0x01, 0xEB, 0xE9, 0xFC, 0xC4, 0x96, 0x00, 0xD5, 0xDC, 0x2E, 0x17, 0xF1, 0x36, 0x44, 0x02, + 0x5C, 0x0C, 0x38, 0x10, 0x05, 0x01, 0x42, 0x04, 0x04, 0x24, 0x92, 0x0A, 0xEB, 0x09, 0x96, 0x01, + 0xE0, 0x20, 0xE8, 0xE8, 0x3C, 0x23, 0xF9, 0x03, 0xE2, 0x40, 0x40, 0x01, 0x3C, 0x1B, 0xEB, 0xE9, + 0xFC, 0xC4, 0x84, 0x00, 0x3E, 0x07, 0xF1, 0x38, 0x3E, 0x07, 0xF1, 0x37, 0xDD, 0x9E, 0xFC, 0x00, + 0x84, 0x00, 0x80, 0x80, 0x80, 0xA0, 0x44, 0x22, 0x1E, 0x7C, 0x44, 0x32, 0x1E, 0xA4, 0x80, 0x20, + 0xEB, 0xD7, 0xFA, 0x18, 0x84, 0x21, 0xDD, 0x43, 0x84, 0x20, 0x84, 0x02, 0xDD, 0x43, 0xEA, 0x5D, + 0xEA, 0x95, 0xEB, 0x79, 0xFC, 0x80, 0xFC, 0x00, 0x2E, 0x47, 0xF2, 0x08, 0x84, 0x00, 0x44, 0x22, + 0x1E, 0x34, 0x44, 0x32, 0x1E, 0x68, 0x80, 0xA4, 0x80, 0x20, 0xEB, 0xD7, 0xFA, 0x18, 0x84, 0x21, + 0xDD, 0x43, 0x84, 0x20, 0x84, 0x02, 0xDD, 0x43, 0xEA, 0x5D, 0xEA, 0x95, 0xEB, 0x79, 0xFC, 0x80, + 0xFC, 0x00, 0x49, 0xFF, 0xFE, 0xCE, 0xEA, 0x61, 0x5A, 0x00, 0x01, 0x04, 0x48, 0x00, 0x00, 0xBF, + 0x2E, 0x37, 0xE9, 0xB8, 0x5A, 0x38, 0x05, 0x04, 0x48, 0x00, 0x00, 0xAA, 0x84, 0x03, 0xDD, 0x4A, + 0x4E, 0x03, 0x00, 0xB5, 0x2E, 0x27, 0xF2, 0x08, 0x44, 0x02, 0x25, 0xBC, 0xEB, 0x09, 0x38, 0x30, + 0x09, 0x01, 0xE0, 0x23, 0xE9, 0x02, 0xCB, 0x03, 0x38, 0x10, 0x09, 0x09, 0x3C, 0x23, 0xF9, 0x01, + 0xE0, 0x41, 0xE8, 0x12, 0x2E, 0x07, 0xF1, 0x6F, 0x84, 0xC0, 0x8C, 0x01, 0x3E, 0x07, 0xF1, 0x6F, + 0x84, 0x04, 0x3E, 0x67, 0xF1, 0x6E, 0xDD, 0x4A, 0xC0, 0x30, 0xFA, 0x00, 0x84, 0x20, 0xDD, 0x43, + 0x3E, 0x67, 0xF2, 0x00, 0xD5, 0x2A, 0x84, 0x00, 0x3E, 0x07, 0xF1, 0x6F, 0xEA, 0x7F, 0x44, 0x42, + 0x24, 0xD8, 0x96, 0x0E, 0x2E, 0x37, 0xF0, 0x5E, 0xC0, 0x0F, 0x2E, 0x07, 0xF2, 0x01, 0xC0, 0x0C, + 0x2E, 0x07, 0xF1, 0x6E, 0x38, 0x12, 0x0C, 0x00, 0xE0, 0x01, 0xE8, 0x03, 0x8C, 0x01, 0x96, 0x40, + 0x3E, 0x17, 0xF1, 0x6E, 0xD5, 0x04, 0x84, 0x00, 0x3E, 0x07, 0xF1, 0x6E, 0x2E, 0x17, 0xF1, 0x6E, + 0x38, 0x02, 0x0C, 0x00, 0xE2, 0x20, 0xE9, 0x03, 0x84, 0x00, 0xEB, 0x20, 0x3C, 0x53, 0xEA, 0x07, + 0xD2, 0x04, 0xFA, 0x00, 0x84, 0x21, 0xDD, 0x43, 0x84, 0x07, 0xDD, 0x4A, 0xC8, 0x18, 0x3C, 0x13, + 0xEA, 0x07, 0xEB, 0x44, 0x92, 0x21, 0xE0, 0x41, 0xE9, 0x12, 0x2E, 0x17, 0xF1, 0x6D, 0x8C, 0x21, + 0x96, 0x48, 0xE6, 0x23, 0xE8, 0x04, 0x3E, 0x17, 0xF1, 0x6D, 0xD5, 0x0C, 0x3E, 0x07, 0xF1, 0x6D, + 0x3E, 0x07, 0xF1, 0x6C, 0x84, 0x21, 0xEB, 0xDC, 0xDD, 0x43, 0xD5, 0x04, 0x84, 0x00, 0x3E, 0x07, + 0xF1, 0x6D, 0x84, 0x07, 0xDD, 0x4A, 0xC0, 0x15, 0xEA, 0x7F, 0x96, 0x0E, 0xC0, 0x12, 0xEB, 0x15, + 0xEB, 0x09, 0x92, 0x01, 0xE0, 0x20, 0xE8, 0x0D, 0x2E, 0x07, 0xF1, 0x6C, 0x8C, 0x01, 0x96, 0x00, + 0xEB, 0x7C, 0x3E, 0x07, 0xF1, 0x6C, 0xE9, 0x08, 0xEB, 0xDC, 0x84, 0x20, 0xDD, 0x43, 0xD5, 0x04, + 0x84, 0x00, 0x3E, 0x07, 0xF1, 0x6C, 0x3C, 0x03, 0xF9, 0x01, 0x2E, 0x17, 0xF1, 0x6F, 0x5C, 0xF0, + 0x03, 0x20, 0x3C, 0x03, 0xEA, 0x08, 0xE9, 0x04, 0x84, 0x43, 0xFE, 0x14, 0xD5, 0x07, 0x2E, 0x57, + 0xF1, 0x38, 0x2E, 0x27, 0xF1, 0x37, 0xDA, 0x02, 0x8C, 0x01, 0xE0, 0x20, 0xE9, 0x1F, 0x84, 0x00, + 0x3E, 0x07, 0xF1, 0x6E, 0x3E, 0x07, 0xF1, 0x6F, 0x84, 0x21, 0x44, 0x00, 0x00, 0xA8, 0xDD, 0x43, + 0x84, 0x02, 0x84, 0x20, 0xDD, 0x43, 0xEA, 0x5D, 0x84, 0x01, 0xFC, 0x80, 0x3C, 0x13, 0xEA, 0x07, + 0xEB, 0x44, 0x94, 0x4A, 0xEA, 0xE6, 0xE0, 0x22, 0xE9, 0x0A, 0xEA, 0x4B, 0x96, 0x4E, 0xC9, 0x06, + 0x2E, 0x00, 0x15, 0x49, 0x40, 0x00, 0x08, 0x07, 0xFC, 0x80, 0x84, 0x00, 0xFC, 0x80, 0xFC, 0x06, + 0x84, 0x20, 0x80, 0x1F, 0xEA, 0xA7, 0xDD, 0x40, 0xEB, 0x35, 0xEA, 0xC7, 0xB6, 0x1F, 0xEB, 0x7B, + 0xF1, 0x83, 0xF0, 0x81, 0xEA, 0xFD, 0xEB, 0x0C, 0xF1, 0x84, 0x94, 0x46, 0xF0, 0x82, 0xF1, 0x85, + 0xDD, 0x56, 0xEA, 0x21, 0xF0, 0x87, 0x80, 0x1F, 0xF1, 0x86, 0xEA, 0xC1, 0xFC, 0x86, 0x84, 0x00, + 0xEB, 0x20, 0xDD, 0x9E, 0xFA, 0x24, 0x3C, 0x0B, 0xF9, 0x01, 0x8C, 0x02, 0xFE, 0x0C, 0x84, 0x2D, + 0xDD, 0x5C, 0x3C, 0x0B, 0xF9, 0x03, 0x84, 0x00, 0xEB, 0x20, 0xDD, 0x9E, 0xFC, 0x00, 0x44, 0x62, + 0x0C, 0xE4, 0x44, 0x02, 0x1F, 0xC8, 0x49, 0xFF, 0xE8, 0xB8, 0x00, 0x13, 0x00, 0x65, 0x00, 0x23, + 0x00, 0x69, 0x00, 0x33, 0x00, 0x68, 0x00, 0x43, 0x00, 0x66, 0x00, 0x53, 0x00, 0x67, 0x84, 0x01, + 0x49, 0xFF, 0xE8, 0x66, 0x84, 0x01, 0x49, 0xFF, 0xE8, 0x92, 0x49, 0xFF, 0xED, 0x52, 0x84, 0x00, + 0x49, 0xFF, 0xED, 0x44, 0x49, 0xFF, 0xF1, 0xDF, 0x00, 0x03, 0x00, 0x64, 0x3E, 0x07, 0xF2, 0x08, + 0xEB, 0x15, 0x49, 0xFF, 0xFF, 0xD1, 0xEA, 0xEC, 0xEA, 0x5D, 0x49, 0xFF, 0xFC, 0x15, 0xFC, 0x80, + 0xFC, 0x02, 0xEA, 0xFF, 0x8C, 0x01, 0x96, 0x00, 0x5A, 0x00, 0x05, 0x16, 0xE6, 0x04, 0xE9, 0x15, + 0xE6, 0x0A, 0xE9, 0x02, 0x84, 0x04, 0x3E, 0x07, 0xF2, 0x08, 0xEA, 0x26, 0xEA, 0x20, 0xEA, 0x26, + 0xF0, 0x81, 0xEA, 0x35, 0xF0, 0x82, 0xEA, 0x3A, 0xF0, 0x83, 0xF1, 0x02, 0xF0, 0x01, 0xF2, 0x03, + 0xDD, 0x5B, 0xFC, 0x82, 0x84, 0x00, 0xD5, 0xF0, 0x84, 0x05, 0xD5, 0xEE, 0x2E, 0x07, 0xF2, 0x22, + 0x96, 0x00, 0xC0, 0x04, 0x84, 0x00, 0xEB, 0xFE, 0x84, 0x01, 0xDD, 0x9E, 0x2E, 0x07, 0xF2, 0x21, + 0x96, 0x00, 0xC0, 0x04, 0x84, 0x00, 0xEA, 0x8A, 0x84, 0x01, 0xDD, 0x9E, 0x2E, 0x17, 0xF2, 0x20, + 0x96, 0x48, 0xC1, 0x05, 0x84, 0x00, 0x3E, 0x07, 0xF2, 0x20, 0xD5, 0x07, 0x2E, 0x07, 0xF2, 0x19, + 0x96, 0x00, 0xC0, 0x04, 0x3E, 0x17, 0xF2, 0x19, 0x84, 0x01, 0xDD, 0x9E, 0x2E, 0x07, 0xF2, 0x1F, + 0xC0, 0x03, 0x84, 0x00, 0xD5, 0x09, 0xEB, 0xA9, 0xC0, 0x03, 0x84, 0x01, 0xD5, 0x05, 0xEA, 0xC0, + 0x96, 0x00, 0xC0, 0x04, 0x84, 0x02, 0xEB, 0x97, 0x84, 0x01, 0xDD, 0x9E, 0xEA, 0xC0, 0x96, 0x00, + 0xC0, 0x06, 0x84, 0x00, 0xEA, 0xEF, 0x84, 0x02, 0xEB, 0x97, 0x84, 0x01, 0xDD, 0x9E, 0x2E, 0x17, + 0xF2, 0x1F, 0x96, 0x48, 0xC1, 0x04, 0x84, 0x00, 0xEB, 0x81, 0xD5, 0x07, 0xEB, 0xA9, 0x96, 0x00, + 0xC0, 0x06, 0x3E, 0x17, 0xF2, 0x1E, 0x84, 0x01, 0xEB, 0x97, 0x84, 0x01, 0xDD, 0x9E, 0xFC, 0x00, + 0x84, 0x00, 0x49, 0xFF, 0xF7, 0x75, 0x84, 0x00, 0xEB, 0xB6, 0x84, 0x00, 0x49, 0xFF, 0xF7, 0x89, + 0x3C, 0x03, 0xEC, 0x84, 0x84, 0x27, 0x84, 0x40, 0x84, 0x61, 0xEA, 0x6D, 0xEA, 0xA8, 0xE6, 0x02, + 0xE8, 0x04, 0x84, 0x01, 0x84, 0x20, 0xDD, 0x4E, 0x84, 0x00, 0x80, 0x20, 0xEA, 0x2A, 0x84, 0x00, + 0x84, 0x21, 0xDD, 0x4E, 0x84, 0x00, 0x84, 0x21, 0xEA, 0x2A, 0x84, 0x01, 0x80, 0x20, 0xEB, 0x16, + 0x84, 0x00, 0x49, 0x00, 0x0D, 0x30, 0x84, 0x00, 0xEA, 0x96, 0x84, 0x00, 0x3E, 0x07, 0xF2, 0x24, + 0x84, 0x01, 0xEB, 0x45, 0xFC, 0x80, 0xFC, 0x00, 0xEB, 0x00, 0xE6, 0x23, 0xE8, 0x65, 0xEA, 0x48, + 0x96, 0x06, 0xC0, 0x05, 0xEA, 0xC0, 0xC0, 0x03, 0x84, 0x00, 0xEA, 0xEF, 0x2E, 0x07, 0xF2, 0x1B, + 0xC8, 0x03, 0xEA, 0x47, 0xC0, 0x21, 0x2E, 0x07, 0xF2, 0x1F, 0xC0, 0x03, 0x84, 0x00, 0xEB, 0x81, + 0xEB, 0xA9, 0xC0, 0x03, 0x84, 0x00, 0xEB, 0x65, 0xEA, 0xC0, 0xC0, 0x03, 0x84, 0x00, 0xEA, 0xEF, + 0x84, 0x01, 0x3E, 0x07, 0xF2, 0x14, 0x2E, 0x07, 0xF2, 0x16, 0xC0, 0x04, 0x84, 0x02, 0xEA, 0xAB, + 0xD5, 0x41, 0xEA, 0x47, 0xC0, 0x41, 0x2E, 0x07, 0xF2, 0x16, 0xC8, 0x3E, 0x84, 0x02, 0xEA, 0xAB, + 0x49, 0xFF, 0xF2, 0x68, 0xD5, 0x39, 0x2E, 0x07, 0xF0, 0xC6, 0xC8, 0x08, 0x84, 0x21, 0x3E, 0x17, + 0xF0, 0xC6, 0x49, 0xFF, 0xED, 0xBB, 0x49, 0xFF, 0xE9, 0xE9, 0x49, 0xFF, 0xF6, 0xBF, 0x44, 0x10, + 0xF3, 0x8A, 0x4C, 0x00, 0x80, 0x17, 0xDD, 0x49, 0xC0, 0x05, 0x84, 0x00, 0x3E, 0x07, 0xF2, 0x14, + 0xFC, 0x80, 0x2E, 0x17, 0xF2, 0x1F, 0xC1, 0x02, 0xEB, 0x81, 0xEB, 0xA9, 0xC0, 0x03, 0x84, 0x00, + 0xEB, 0x65, 0xEA, 0xC0, 0xC0, 0x03, 0x84, 0x00, 0xEA, 0xEF, 0x84, 0x01, 0x3E, 0x07, 0xF2, 0x14, + 0x84, 0x00, 0x49, 0xFF, 0xE2, 0x66, 0x84, 0x02, 0x49, 0xFF, 0xE2, 0x75, 0x84, 0x02, 0xEB, 0x00, + 0xEA, 0xAB, 0x84, 0x03, 0x2E, 0x17, 0xF0, 0xE6, 0x49, 0x00, 0x12, 0x66, 0xEA, 0xA8, 0x5A, 0x08, + 0x02, 0x04, 0x49, 0xFF, 0xF1, 0xD8, 0x2E, 0x67, 0xF2, 0x1D, 0x97, 0xB0, 0xCE, 0x06, 0x84, 0x01, + 0x49, 0x00, 0x0C, 0xB9, 0x80, 0x06, 0xEA, 0x96, 0x2E, 0x67, 0xF2, 0x23, 0xCE, 0x0F, 0xEB, 0x8B, + 0x80, 0x06, 0x49, 0xFF, 0xF6, 0xEE, 0x80, 0x06, 0x80, 0x26, 0xDD, 0x4E, 0x80, 0x06, 0x84, 0x21, + 0xDD, 0x4E, 0x3E, 0x67, 0xF0, 0xD0, 0x80, 0x06, 0xD5, 0x54, 0x5A, 0x68, 0x01, 0x2C, 0x2E, 0x07, + 0xF2, 0x1D, 0x96, 0x00, 0xC8, 0x03, 0x80, 0x20, 0xDD, 0x4E, 0x2E, 0x07, 0xF2, 0x1B, 0xC0, 0x1C, + 0x84, 0x00, 0x3E, 0x07, 0xF2, 0x1B, 0x49, 0xFF, 0xE8, 0x6E, 0x49, 0xFF, 0xE8, 0x7E, 0x49, 0xFF, + 0xE9, 0xD4, 0x84, 0x00, 0x49, 0xFF, 0xE8, 0xEF, 0x49, 0xFF, 0xE8, 0xFA, 0x49, 0xFF, 0xEE, 0xFC, + 0x5A, 0x00, 0x01, 0xFE, 0xEB, 0x96, 0x5A, 0x00, 0x01, 0xFF, 0x84, 0x01, 0xEB, 0x41, 0xEB, 0x2B, + 0x84, 0x00, 0xEB, 0x41, 0xD5, 0x00, 0xEB, 0x8B, 0x49, 0xFF, 0xE8, 0x67, 0x49, 0xFF, 0xE9, 0x0C, + 0xD5, 0x2B, 0xEB, 0x8B, 0x84, 0x01, 0x3C, 0x1D, 0xF6, 0x3E, 0x49, 0xFF, 0xE7, 0xB6, 0x84, 0x41, + 0x80, 0x62, 0x3C, 0x03, 0xEC, 0x8D, 0x84, 0x20, 0xEA, 0x6D, 0x84, 0x21, 0x84, 0x00, 0xEB, 0x16, + 0x84, 0x01, 0x49, 0xFF, 0xF5, 0xD5, 0x84, 0x01, 0x80, 0x20, 0xDD, 0x4E, 0x84, 0x01, 0x49, 0xFF, + 0xF5, 0x9B, 0x84, 0x00, 0xEB, 0xB6, 0x84, 0x01, 0x84, 0x20, 0xDD, 0x4E, 0x84, 0x01, 0x84, 0x20, + 0xEA, 0x2A, 0x84, 0x01, 0x80, 0x20, 0xDD, 0x4E, 0x84, 0x01, 0x80, 0x20, 0xEA, 0x2A, 0x84, 0x00, + 0x80, 0x20, 0x84, 0x41, 0xEB, 0x13, 0xEB, 0x00, 0x84, 0x01, 0x3E, 0x07, 0xF2, 0x24, 0x80, 0xC0, + 0x5A, 0x18, 0x02, 0x03, 0xEB, 0xB0, 0x3E, 0x67, 0xEB, 0xCC, 0xFC, 0x80, 0xFC, 0x00, 0xC8, 0x07, + 0x44, 0x12, 0x26, 0x84, 0x49, 0xFF, 0xF3, 0x72, 0x84, 0x07, 0xD5, 0x03, 0x5A, 0x08, 0x01, 0x06, + 0x44, 0x12, 0x26, 0x84, 0x49, 0xFF, 0xF3, 0x6A, 0xFC, 0x80, 0xFC, 0x00, 0x80, 0xC0, 0xEB, 0x96, + 0xC8, 0x38, 0x5A, 0x68, 0x01, 0x04, 0x80, 0x06, 0xEB, 0x41, 0x49, 0xFF, 0xEE, 0x9D, 0x5A, 0x00, + 0x01, 0xFE, 0xEB, 0x96, 0xC8, 0x2A, 0xEA, 0x2C, 0x5A, 0x08, 0x02, 0x04, 0xEB, 0x2B, 0xD5, 0x25, + 0x5A, 0x08, 0x03, 0x14, 0xEA, 0x99, 0xC8, 0x21, 0x2E, 0x07, 0xF2, 0x19, 0xC8, 0x1E, 0xEA, 0x47, + 0xC8, 0x1C, 0x2E, 0x17, 0xF0, 0xD8, 0x96, 0x48, 0x5A, 0x18, 0x01, 0x04, 0x3E, 0x17, 0xF0, 0xE4, + 0xEB, 0x2B, 0x84, 0x00, 0xEB, 0x1E, 0xD5, 0x11, 0x5A, 0x08, 0x04, 0x10, 0xEA, 0x99, 0xC8, 0x0D, + 0x2E, 0x07, 0xF2, 0x20, 0xC8, 0x0A, 0x2E, 0x17, 0xF2, 0x1A, 0x96, 0x48, 0xC9, 0x06, 0x84, 0x01, + 0xEB, 0x1E, 0xEB, 0x2B, 0x3E, 0x17, 0xF0, 0xE4, 0x5A, 0x68, 0x01, 0x04, 0x84, 0x00, 0xEB, 0x41, + 0xFC, 0x80, 0x2E, 0x07, 0xF2, 0x24, 0xDD, 0x9E, 0x3E, 0x07, 0xF2, 0x24, 0xDD, 0x9E, 0xEA, 0xA8, + 0xDD, 0x9E, 0xFC, 0x40, 0x2E, 0x07, 0xF2, 0x24, 0xC8, 0x1E, 0x49, 0xFF, 0xF2, 0x9D, 0x3C, 0x7D, + 0xFA, 0xCE, 0xFA, 0xC4, 0xFF, 0xBC, 0xFF, 0x84, 0x44, 0x70, 0x00, 0x3C, 0xEA, 0x80, 0x40, 0x03, + 0x80, 0x0C, 0x84, 0x2A, 0xFE, 0x0C, 0x40, 0x03, 0x00, 0x17, 0x97, 0xC1, 0x2E, 0x07, 0xF2, 0x18, + 0xC8, 0x02, 0x92, 0xE1, 0x3C, 0x6D, 0xFA, 0xCE, 0xEA, 0x80, 0x40, 0x03, 0x00, 0x0D, 0x9D, 0x81, + 0x98, 0x3E, 0xD5, 0x1F, 0x49, 0xFF, 0xF2, 0x80, 0x80, 0xC0, 0x84, 0x01, 0x49, 0xFF, 0xF4, 0xBE, + 0x42, 0x93, 0x00, 0x24, 0x84, 0x01, 0x49, 0xFF, 0xF4, 0x76, 0x81, 0x40, 0xEA, 0x80, 0x3C, 0x6D, + 0xFA, 0xCE, 0x80, 0xE0, 0xEA, 0x80, 0x40, 0x03, 0x00, 0x0D, 0x9D, 0x81, 0x40, 0x14, 0xA8, 0x0C, + 0xFA, 0x64, 0x84, 0x0A, 0xEB, 0x05, 0x42, 0x20, 0x8C, 0x24, 0x40, 0x11, 0x00, 0x36, 0x98, 0x31, + 0x44, 0x61, 0x86, 0xA0, 0x96, 0x01, 0xFE, 0x34, 0x3C, 0x6D, 0xFA, 0xCE, 0x40, 0x60, 0x18, 0xD7, + 0xEA, 0x80, 0x40, 0x03, 0x00, 0x0C, 0xFC, 0xC0, 0xFC, 0x00, 0x49, 0xFF, 0xE8, 0x48, 0xFC, 0x80, + 0xFC, 0x00, 0x84, 0x0B, 0x44, 0x10, 0x00, 0xAB, 0x84, 0x41, 0xEB, 0x13, 0x96, 0x2E, 0xC0, 0x07, + 0x49, 0xFF, 0xE1, 0x8F, 0x84, 0x20, 0x40, 0x00, 0x80, 0x06, 0xFC, 0x80, 0x84, 0x01, 0xFC, 0x80, + 0xFC, 0x00, 0x49, 0xFF, 0xE9, 0xE0, 0xFC, 0x80, 0xFC, 0x00, 0x49, 0xFF, 0xEF, 0x14, 0xFC, 0x80, + 0xFC, 0x00, 0x49, 0xFF, 0xE8, 0x99, 0xEA, 0x3B, 0x5A, 0x08, 0x1F, 0x04, 0x49, 0xFF, 0xE8, 0xE2, + 0xFC, 0x80, 0x80, 0x80, 0x84, 0x40, 0x9A, 0xE0, 0x96, 0xD9, 0xE2, 0x61, 0xE8, 0x05, 0x08, 0x32, + 0x00, 0x01, 0x88, 0x43, 0xD5, 0xF9, 0xFE, 0x12, 0x96, 0x00, 0xDD, 0x9E, 0x84, 0x40, 0x44, 0x42, + 0x26, 0xAC, 0x96, 0xD1, 0xE2, 0x61, 0xE8, 0x07, 0x38, 0x30, 0x08, 0x00, 0x38, 0x32, 0x08, 0x08, + 0x8C, 0x41, 0xD5, 0xF8, 0xDD, 0x9E, 0x44, 0x32, 0x26, 0xAC, 0xE2, 0x22, 0xE8, 0x08, 0x38, 0x40, + 0x04, 0x00, 0x38, 0x41, 0x84, 0x08, 0x8C, 0x21, 0x96, 0x48, 0xD5, 0xF8, 0xDD, 0x9E, 0xFC, 0x00, + 0xEA, 0xA2, 0x5A, 0x08, 0x01, 0x15, 0xEA, 0xD1, 0x3C, 0x23, 0xF6, 0xC8, 0xFE, 0x4B, 0xFE, 0x56, + 0x3C, 0x1B, 0xF6, 0xC8, 0xEA, 0xD1, 0x3C, 0x23, 0xF6, 0xC9, 0xFE, 0x4B, 0xFE, 0x56, 0x3C, 0x1B, + 0xF6, 0xC9, 0x84, 0x20, 0xDD, 0x47, 0x84, 0x03, 0x84, 0x20, 0xDD, 0x47, 0xFC, 0x80, 0xFC, 0x20, + 0x80, 0xE0, 0x5A, 0x10, 0x02, 0x3F, 0xE6, 0x23, 0xE8, 0x05, 0xC1, 0x0B, 0x5A, 0x10, 0x01, 0x42, + 0xD5, 0x3E, 0x5A, 0x10, 0x04, 0x47, 0xE6, 0x24, 0xE9, 0x3E, 0x5A, 0x10, 0x05, 0x48, 0xD5, 0x37, + 0xEA, 0x6A, 0x84, 0x01, 0xEB, 0x05, 0xFE, 0x0F, 0x96, 0x01, 0xEB, 0x9E, 0xCF, 0x03, 0x3C, 0x7B, + 0xF6, 0xC9, 0xDD, 0x41, 0xC8, 0x2C, 0x2E, 0x67, 0xF0, 0xD0, 0x97, 0xB0, 0xCE, 0x28, 0x84, 0x01, + 0x49, 0xFF, 0xF4, 0x6C, 0x80, 0x06, 0x84, 0x21, 0xDD, 0x4E, 0x84, 0x21, 0x80, 0x06, 0xEB, 0x16, + 0x84, 0x01, 0xEB, 0xCA, 0x84, 0x01, 0x49, 0xFF, 0xF4, 0x4F, 0x84, 0x01, 0x80, 0x20, 0xDD, 0x4E, + 0x5A, 0x78, 0x02, 0x16, 0xEB, 0x3B, 0x96, 0x03, 0xEB, 0x29, 0x84, 0x01, 0x3C, 0x6B, 0xF8, 0x65, + 0x3C, 0x6B, 0xF8, 0x64, 0x3C, 0x6B, 0xF8, 0x66, 0x3E, 0x07, 0xEA, 0x52, 0xEB, 0xFD, 0xD5, 0x07, + 0x84, 0x01, 0xEA, 0x6A, 0xEB, 0x05, 0xFE, 0x03, 0xFE, 0x0E, 0xEB, 0x9E, 0x84, 0x00, 0xFC, 0xA0, + 0xEA, 0x6A, 0xD5, 0x08, 0xEA, 0xD1, 0x84, 0x01, 0xEB, 0x05, 0xFE, 0x0F, 0x96, 0x01, 0xD5, 0x0B, + 0xEA, 0xD1, 0x40, 0x00, 0x9C, 0x0E, 0x96, 0x06, 0xFC, 0xA0, 0x84, 0x01, 0xEA, 0xD1, 0xEB, 0x05, + 0xFE, 0x03, 0xFE, 0x0E, 0x3C, 0x0B, 0xF6, 0xC9, 0xD5, 0xEA, 0xFC, 0x05, 0x44, 0x02, 0x2C, 0xEC, + 0x84, 0x60, 0x84, 0x81, 0xB6, 0x1F, 0x44, 0x00, 0x00, 0x90, 0xF0, 0x88, 0xF4, 0x81, 0xF3, 0x82, + 0xF3, 0x83, 0xF4, 0x84, 0xF3, 0x85, 0xF3, 0x86, 0xF3, 0x87, 0xF3, 0x89, 0x84, 0x02, 0x84, 0x25, + 0x44, 0x26, 0x20, 0x08, 0x80, 0xA3, 0x49, 0xFF, 0xE1, 0x22, 0xFC, 0x85, 0xFC, 0x05, 0x49, 0xFF, + 0xE1, 0x0B, 0x44, 0x06, 0x20, 0x04, 0x84, 0x60, 0x44, 0x62, 0x26, 0xAD, 0xB6, 0x1F, 0x44, 0x10, + 0x06, 0x3F, 0x84, 0x01, 0xF0, 0x81, 0xF0, 0x82, 0xF1, 0x88, 0x80, 0x46, 0x80, 0x80, 0xF3, 0x83, + 0xF3, 0x84, 0xF3, 0x85, 0xF3, 0x86, 0xF3, 0x87, 0xF3, 0x89, 0x84, 0x24, 0x80, 0xA3, 0x49, 0xFF, + 0xE1, 0x06, 0x80, 0x46, 0x44, 0x00, 0x00, 0x79, 0x18, 0x01, 0x7F, 0xFF, 0x44, 0x0F, 0xFF, 0x84, + 0xAE, 0x12, 0x84, 0x19, 0xAE, 0x13, 0xFC, 0x85, 0xFC, 0x00, 0x84, 0x00, 0x3E, 0x07, 0xF9, 0x04, + 0x84, 0xC0, 0x84, 0x01, 0x3E, 0x07, 0xEB, 0x7C, 0x3C, 0x6B, 0xF9, 0x18, 0x49, 0xFF, 0xFF, 0xD0, + 0x84, 0x00, 0x49, 0xFF, 0xEC, 0x47, 0x49, 0xFF, 0xFF, 0xB2, 0x3E, 0x67, 0xF0, 0xE5, 0xFC, 0x80, + 0xFC, 0x20, 0x44, 0x26, 0x20, 0x04, 0x44, 0x72, 0x26, 0xAC, 0x80, 0xC0, 0xA6, 0x38, 0xB4, 0x22, + 0x92, 0x28, 0xEA, 0x4F, 0xFE, 0x47, 0xB6, 0x22, 0x80, 0x07, 0x80, 0x26, 0xEB, 0x2D, 0x38, 0x03, + 0x98, 0x08, 0x9C, 0x31, 0x96, 0x01, 0x49, 0xFF, 0xE4, 0x34, 0x84, 0x01, 0xEB, 0x10, 0xFC, 0xA0, + 0xFC, 0x20, 0x84, 0x00, 0x3E, 0x00, 0x03, 0x2C, 0xEB, 0x3F, 0x44, 0x02, 0x5F, 0xEC, 0x84, 0x4C, + 0xDD, 0x40, 0xEB, 0xDE, 0x5A, 0x00, 0x01, 0x04, 0x48, 0x00, 0x00, 0xAF, 0xEA, 0x6C, 0x2E, 0x67, + 0xE9, 0xB8, 0x94, 0x43, 0x2E, 0x07, 0xEE, 0x18, 0x95, 0xB2, 0x94, 0x06, 0xFE, 0x0F, 0x2E, 0x17, + 0xF0, 0xD1, 0x2E, 0x7F, 0xEE, 0x19, 0xFE, 0x0F, 0x2E, 0x10, 0x2B, 0x74, 0x97, 0xB2, 0xFE, 0x0E, + 0x3E, 0x00, 0x2B, 0x74, 0xEA, 0xDD, 0x5A, 0x00, 0x01, 0x05, 0xDD, 0x46, 0x92, 0x03, 0x96, 0x06, + 0x2E, 0x27, 0xF0, 0x13, 0x94, 0x05, 0x94, 0x96, 0x40, 0x13, 0x08, 0x04, 0xFE, 0x7F, 0xFE, 0x0F, + 0x2E, 0x10, 0x2B, 0x75, 0xFE, 0x0E, 0x3E, 0x00, 0x2B, 0x75, 0xEA, 0x2E, 0x2E, 0x00, 0x2B, 0x76, + 0xFE, 0x0E, 0x3E, 0x00, 0x2B, 0x76, 0x2E, 0x10, 0x1E, 0xBB, 0x2E, 0x00, 0x1D, 0xAF, 0x94, 0x8E, + 0x94, 0x03, 0xFE, 0x17, 0x2E, 0x20, 0x1C, 0xA3, 0x96, 0x56, 0xFE, 0x17, 0x2E, 0x20, 0x2B, 0x77, + 0x92, 0x22, 0xFE, 0x16, 0x2E, 0x20, 0x20, 0xD3, 0x3E, 0x00, 0x2B, 0x77, 0x94, 0xD4, 0x2E, 0x20, + 0x1F, 0xC7, 0x2E, 0x00, 0x21, 0xDF, 0x94, 0x91, 0xFE, 0x9F, 0x94, 0xC7, 0xFE, 0x9F, 0xFE, 0x57, + 0x2E, 0x20, 0x2B, 0x78, 0x54, 0x00, 0x00, 0x06, 0xFE, 0x56, 0x3E, 0x10, 0x2B, 0x78, 0x2E, 0x10, + 0x23, 0xF7, 0x90, 0x01, 0x94, 0x8D, 0x2E, 0x10, 0x22, 0xEB, 0x94, 0x4A, 0xFE, 0x57, 0xFE, 0x0F, + 0x2E, 0x10, 0x2B, 0x79, 0xFE, 0x0E, 0x3E, 0x00, 0x2B, 0x79, 0x2E, 0x00, 0x26, 0x0F, 0x2E, 0x10, + 0x25, 0x03, 0x94, 0x03, 0xFE, 0x0F, 0x2E, 0x10, 0x2B, 0x7A, 0xFE, 0x0E, 0x3E, 0x00, 0x2B, 0x7A, + 0x3C, 0x03, 0xF8, 0x9F, 0xC0, 0x04, 0x44, 0x10, 0x7D, 0x00, 0xEB, 0x88, 0x2E, 0x67, 0xF1, 0x40, + 0x2E, 0x27, 0xF1, 0x3D, 0x54, 0x13, 0x00, 0x1F, 0x94, 0xC9, 0x54, 0x11, 0x00, 0x01, 0xEB, 0xE7, + 0x96, 0x91, 0xFE, 0x5F, 0x94, 0x96, 0xFE, 0x57, 0x3E, 0x00, 0x2B, 0x7C, 0x84, 0x1F, 0x3E, 0x10, + 0x2B, 0x7B, 0x3E, 0x00, 0x2B, 0x7D, 0x3E, 0x00, 0x2B, 0x7E, 0x84, 0x2A, 0x44, 0x02, 0x5F, 0xED, + 0xEB, 0x2D, 0x2E, 0x10, 0x2B, 0x7F, 0xFE, 0x46, 0x2E, 0x07, 0xF1, 0x3D, 0x3E, 0x10, 0x2B, 0x7F, + 0x96, 0x00, 0x5A, 0x08, 0x01, 0x0A, 0x3C, 0x57, 0xF5, 0xBD, 0x4E, 0x55, 0x00, 0x03, 0xD6, 0x10, + 0x3C, 0x6B, 0xF5, 0xBD, 0xFC, 0xA0, 0x3C, 0x57, 0xF5, 0xBC, 0x4E, 0x54, 0x00, 0x05, 0x3C, 0x1B, + 0xF5, 0xBC, 0xD5, 0x06, 0xD1, 0x05, 0x3C, 0x1B, 0xF5, 0xBC, 0x84, 0x01, 0xFC, 0xA0, 0x84, 0x01, + 0x3E, 0x00, 0x03, 0x2C, 0xD5, 0x04, 0x84, 0x1F, 0x3C, 0x0B, 0xF5, 0xBC, 0x84, 0x00, 0xFC, 0xA0, + 0xFC, 0x20, 0xEB, 0x66, 0x49, 0xFF, 0xE3, 0x6D, 0xFA, 0x3A, 0x44, 0x22, 0x26, 0xAC, 0x38, 0x01, + 0x04, 0x00, 0x9C, 0xCB, 0x96, 0x00, 0x8E, 0x21, 0x38, 0x01, 0x0C, 0x08, 0x44, 0x62, 0x26, 0xAC, + 0x5A, 0x1F, 0xFF, 0xF7, 0x44, 0x0F, 0xFF, 0xB7, 0xEA, 0xA4, 0xEB, 0x66, 0xEB, 0x0A, 0x84, 0xE0, + 0x44, 0x00, 0x00, 0x5C, 0x3E, 0x77, 0xF2, 0x36, 0xFA, 0x3D, 0xEB, 0xAF, 0x80, 0x06, 0xEB, 0x2D, + 0x2E, 0x10, 0x03, 0x2C, 0x3E, 0x07, 0xF2, 0x61, 0x84, 0x0C, 0x3E, 0x07, 0xF2, 0x62, 0x3E, 0x77, + 0xF2, 0x63, 0x44, 0x02, 0x5F, 0xE0, 0x5A, 0x10, 0x01, 0x05, 0x44, 0x10, 0x00, 0x30, 0xD5, 0x0C, + 0x84, 0x20, 0x44, 0x32, 0x5F, 0xEC, 0x38, 0x21, 0x84, 0x00, 0x38, 0x20, 0x04, 0x08, 0x8C, 0x21, + 0x5A, 0x18, 0x0C, 0xFB, 0xD5, 0xF3, 0x98, 0x81, 0x00, 0x21, 0x7F, 0xD0, 0x38, 0x23, 0x04, 0x08, + 0x8C, 0x21, 0x5A, 0x18, 0x3B, 0xFA, 0x44, 0x02, 0x26, 0xAC, 0xEB, 0x2D, 0x3E, 0x07, 0xF2, 0x6F, + 0x2E, 0x07, 0xF2, 0x34, 0x49, 0xFF, 0xE3, 0x21, 0xEB, 0x66, 0xEA, 0xD9, 0xFC, 0xA0, 0xFC, 0x00, + 0xC8, 0x03, 0xFA, 0x1A, 0xD5, 0x03, 0x44, 0x00, 0x05, 0xB3, 0xEA, 0xD9, 0xFC, 0x80, 0xFC, 0x00, + 0x44, 0x00, 0x00, 0xA9, 0xEA, 0xD9, 0xFC, 0x80, 0xFC, 0x00, 0xEA, 0x5A, 0x84, 0x20, 0xEB, 0x60, + 0x84, 0x00, 0x3C, 0x0F, 0xFC, 0x8A, 0x3C, 0x0D, 0xFC, 0x8A, 0x5C, 0xF0, 0x00, 0x64, 0xE8, 0x05, + 0x3C, 0x0D, 0xFC, 0x8A, 0x8C, 0x01, 0xD5, 0xF6, 0xEA, 0x5A, 0x84, 0x21, 0xEB, 0x60, 0xFC, 0x80, + 0xFC, 0x41, 0x2E, 0x07, 0xF8, 0x74, 0x84, 0x21, 0x96, 0x00, 0x3E, 0x10, 0x12, 0xDB, 0x5A, 0x08, + 0x04, 0x06, 0x2E, 0x00, 0x12, 0xD5, 0x48, 0x00, 0x01, 0x29, 0x5A, 0x08, 0x20, 0x09, 0x44, 0x02, + 0x20, 0x34, 0x84, 0x20, 0x84, 0x4E, 0xEA, 0x77, 0x84, 0x0E, 0xEA, 0x44, 0x5A, 0x08, 0x21, 0x29, + 0x3C, 0x1D, 0xC2, 0xDA, 0x3E, 0x17, 0xEB, 0xB1, 0x40, 0x00, 0xA0, 0x09, 0x3E, 0x07, 0xEB, 0xB2, + 0x40, 0x00, 0xC0, 0x09, 0x3E, 0x07, 0xEB, 0xB3, 0x40, 0x00, 0xE0, 0x09, 0x3C, 0x1D, 0xFA, 0xF4, + 0x3E, 0x07, 0xEB, 0xB4, 0x40, 0x00, 0xA0, 0x09, 0x3E, 0x07, 0xEB, 0xB6, 0x40, 0x00, 0xC0, 0x09, + 0x3E, 0x07, 0xEB, 0xB7, 0x40, 0x00, 0xE0, 0x09, 0x3E, 0x17, 0xEB, 0xB5, 0x3E, 0x07, 0xEB, 0xB8, + 0x84, 0x20, 0x44, 0x02, 0x20, 0x28, 0x84, 0x49, 0xEA, 0x77, 0x84, 0x09, 0xEA, 0x44, 0x5A, 0x08, + 0x22, 0x05, 0x44, 0x02, 0x20, 0x24, 0xD5, 0x05, 0x5A, 0x08, 0x23, 0x09, 0x44, 0x02, 0x20, 0x20, + 0x84, 0x20, 0x84, 0x44, 0xEA, 0x77, 0x84, 0x04, 0xEA, 0x44, 0x5A, 0x08, 0x24, 0x09, 0x44, 0x02, + 0x20, 0x18, 0x84, 0x20, 0x84, 0x45, 0xEA, 0x77, 0x84, 0x05, 0xEA, 0x44, 0x5A, 0x08, 0x28, 0x09, + 0x44, 0x02, 0x20, 0x04, 0x84, 0x20, 0xFA, 0x41, 0xEA, 0x77, 0xFA, 0x01, 0xEA, 0x44, 0x5A, 0x08, + 0x29, 0x09, 0x44, 0x02, 0x1F, 0xFC, 0x84, 0x20, 0x84, 0x46, 0xEA, 0x77, 0x84, 0x06, 0xEA, 0x44, + 0x5A, 0x08, 0x37, 0x09, 0x44, 0x02, 0x1F, 0xF8, 0x84, 0x20, 0x84, 0x42, 0xEA, 0x77, 0x48, 0x00, + 0x02, 0x69, 0x5A, 0x08, 0x62, 0x11, 0xDD, 0x53, 0x96, 0x00, 0xC0, 0x0A, 0xDD, 0x53, 0x96, 0x00, + 0x5A, 0x00, 0x01, 0x07, 0xDD, 0x53, 0x96, 0x00, 0x5A, 0x00, 0x02, 0x03, 0xDD, 0x5F, 0x49, 0xFF, + 0xE2, 0x34, 0xDD, 0x59, 0x5A, 0x08, 0xD1, 0x0C, 0x84, 0x61, 0xDD, 0x53, 0xFA, 0x2F, 0x2E, 0x27, + 0xF8, 0x76, 0x80, 0xA3, 0x2E, 0x47, 0xF8, 0x77, 0xDD, 0x5D, 0xDD, 0x59, 0x5A, 0x08, 0xD2, 0x0B, + 0x44, 0x0F, 0xFF, 0xD2, 0xEA, 0xA4, 0xDD, 0x53, 0x84, 0x41, 0xEA, 0xBF, 0xEB, 0x13, 0x48, 0x00, + 0x02, 0x40, 0x5A, 0x08, 0xF3, 0x06, 0x49, 0xFF, 0xDC, 0x46, 0x48, 0x00, 0x00, 0x97, 0x5A, 0x00, + 0x01, 0x04, 0x48, 0x00, 0x01, 0xB0, 0xEA, 0x7D, 0x5A, 0x18, 0x01, 0x10, 0xEA, 0xBF, 0x5A, 0x18, + 0x01, 0x07, 0x84, 0x20, 0x3E, 0x10, 0x03, 0x2F, 0xEB, 0xFE, 0xDD, 0x59, 0xEA, 0xBF, 0x4E, 0x13, + 0x02, 0xAE, 0xEA, 0x79, 0xEA, 0x8A, 0xDD, 0x59, 0xEA, 0x7D, 0x5A, 0x18, 0x02, 0x50, 0xEA, 0xBF, + 0xC9, 0x0B, 0x2E, 0x10, 0x03, 0x2F, 0xC9, 0x03, 0xEA, 0x79, 0xEA, 0x8A, 0x84, 0x01, 0xEB, 0x81, + 0x3E, 0x07, 0xF2, 0x15, 0xD5, 0x1A, 0xEA, 0xBF, 0x5A, 0x18, 0x01, 0x0E, 0x2E, 0x10, 0x03, 0x2F, + 0x5A, 0x18, 0x01, 0x06, 0x84, 0x20, 0x3E, 0x10, 0x03, 0x2F, 0xEB, 0xFE, 0x84, 0x01, 0x3E, 0x07, + 0xF2, 0x20, 0xDD, 0x59, 0xDD, 0x48, 0x5A, 0x08, 0x03, 0x15, 0xDD, 0x51, 0xC8, 0x04, 0x84, 0x01, + 0xEA, 0x79, 0xEA, 0x8A, 0x84, 0x01, 0xEB, 0x65, 0xEB, 0x00, 0x5A, 0x10, 0x02, 0x03, 0xDD, 0x59, + 0x2E, 0x17, 0xF0, 0xD1, 0x5A, 0x10, 0x03, 0x03, 0xDD, 0x59, 0x3E, 0x07, 0xF2, 0x17, 0xDD, 0x59, + 0xDD, 0x48, 0x5A, 0x08, 0x04, 0x06, 0x84, 0x01, 0x3E, 0x07, 0xF2, 0x1D, 0xDD, 0x59, 0xDD, 0x48, + 0x5A, 0x08, 0x05, 0x0B, 0xDD, 0x51, 0xC8, 0x04, 0x84, 0x01, 0xEA, 0x79, 0xEA, 0x8A, 0x84, 0x01, + 0x3E, 0x07, 0xF2, 0x1C, 0xD5, 0x09, 0xDD, 0x48, 0x5A, 0x00, 0x06, 0x03, 0xDD, 0x5F, 0x84, 0x01, + 0xEA, 0x8A, 0x3E, 0x07, 0xF2, 0x1B, 0xEB, 0x65, 0xDD, 0x59, 0xEA, 0x7D, 0x5A, 0x18, 0x09, 0x05, + 0x49, 0xFF, 0xFC, 0xB4, 0xDD, 0x59, 0xEA, 0x7D, 0x5A, 0x18, 0x0A, 0x3E, 0xEA, 0xBF, 0xC9, 0x04, + 0x3E, 0x07, 0xF2, 0x19, 0xDD, 0x59, 0xDD, 0x48, 0x5A, 0x08, 0x02, 0x0A, 0xDD, 0x51, 0xC8, 0x04, + 0x84, 0x01, 0xEA, 0x79, 0xEA, 0x8A, 0x84, 0x01, 0xEA, 0xEF, 0xDD, 0x59, 0xDD, 0x48, 0x5A, 0x08, + 0x08, 0x0F, 0x2E, 0x27, 0xF8, 0x77, 0x2E, 0x07, 0xF8, 0x78, 0x2E, 0x17, 0xF8, 0x79, 0xDD, 0x52, + 0xEA, 0x28, 0xFE, 0x0F, 0xFE, 0x17, 0x3C, 0x0F, 0xF6, 0x50, 0xDD, 0x59, 0xDD, 0x48, 0x5A, 0x08, + 0x09, 0x08, 0x2E, 0x07, 0xF2, 0x2F, 0x96, 0x00, 0xEA, 0xA4, 0x84, 0x01, 0xEA, 0x44, 0xDD, 0x48, + 0x5A, 0x00, 0x10, 0x03, 0xDD, 0x5F, 0x2E, 0x07, 0xF8, 0x77, 0x96, 0x06, 0xC0, 0x05, 0x2E, 0x07, + 0xF2, 0x2F, 0xDD, 0x4B, 0xD5, 0x05, 0x2E, 0x07, 0xF2, 0x2F, 0x54, 0x00, 0x00, 0xFE, 0x3E, 0x07, + 0xF2, 0x2F, 0xDD, 0x5F, 0xDD, 0x53, 0x5A, 0x08, 0x11, 0x10, 0xDD, 0x48, 0xC8, 0x04, 0xDD, 0x46, + 0xEA, 0xA5, 0xD5, 0x08, 0xDD, 0x48, 0x5A, 0x00, 0x01, 0x03, 0xDD, 0x5F, 0xDD, 0x4F, 0x84, 0x1B, + 0xFE, 0x0E, 0xEA, 0x23, 0xDD, 0x5F, 0xDD, 0x53, 0x5A, 0x08, 0x12, 0x43, 0xDD, 0x48, 0xC8, 0x0C, + 0xDD, 0x46, 0xEA, 0x65, 0xEA, 0x23, 0xDD, 0x4F, 0x44, 0x0F, 0xFF, 0x7F, 0xFE, 0x0E, 0xEA, 0x23, + 0xDD, 0x46, 0xEA, 0xA1, 0xD5, 0x0E, 0xDD, 0x48, 0x5A, 0x08, 0x01, 0x10, 0xDD, 0x46, 0xEA, 0x65, + 0xEA, 0x23, 0xDD, 0x46, 0x58, 0x00, 0x00, 0x80, 0xEA, 0x23, 0xDD, 0x4F, 0xEA, 0x25, 0xFE, 0x0E, + 0xEA, 0x23, 0xDD, 0x4F, 0xEB, 0x74, 0xD5, 0xDD, 0xDD, 0x48, 0x5A, 0x08, 0x02, 0x12, 0xDD, 0x46, + 0xEA, 0x65, 0xEA, 0x23, 0xDD, 0x4F, 0x44, 0x0F, 0xFF, 0x7F, 0xFE, 0x0E, 0xEA, 0x23, 0xDD, 0x4F, + 0xEA, 0x25, 0xFE, 0x0E, 0xEA, 0x23, 0xDD, 0x46, 0x58, 0x00, 0x02, 0x00, 0xD5, 0xCB, 0xDD, 0x48, + 0x5A, 0x00, 0x03, 0x0C, 0xDD, 0x48, 0x5A, 0x00, 0x04, 0x09, 0xDD, 0x48, 0x5A, 0x00, 0x05, 0x06, + 0xDD, 0x48, 0x5A, 0x00, 0x06, 0x03, 0xDD, 0x5F, 0xDD, 0x4F, 0xEA, 0xA3, 0xD5, 0xBA, 0xDD, 0x53, + 0x5A, 0x08, 0x13, 0x10, 0xDD, 0x48, 0xC8, 0x04, 0xDD, 0x46, 0xEA, 0x93, 0xD5, 0xB3, 0xDD, 0x48, + 0x5A, 0x00, 0x01, 0x03, 0xDD, 0x5F, 0xDD, 0x4F, 0x44, 0x0F, 0xFF, 0xDF, 0x48, 0xFF, 0xFF, 0xAA, + 0xDD, 0x53, 0x5A, 0x08, 0x15, 0x54, 0x2E, 0x67, 0xF8, 0x76, 0x97, 0xB0, 0xCE, 0x2B, 0xDD, 0x4F, + 0xEA, 0x85, 0xDD, 0x42, 0xFE, 0x0E, 0xEA, 0x23, 0xDD, 0x4F, 0xEB, 0xFB, 0xDD, 0x42, 0xFE, 0x0E, + 0xEA, 0x23, 0xDD, 0x4F, 0x46, 0x0F, 0x7F, 0xFF, 0xDD, 0x42, 0xFE, 0x0E, 0xEA, 0x23, 0x84, 0x01, + 0xEA, 0x9B, 0xEA, 0x38, 0x80, 0x06, 0xDD, 0x45, 0x80, 0x06, 0xEA, 0x30, 0x80, 0x06, 0xEA, 0x20, + 0xEA, 0x35, 0xB6, 0x1F, 0xEA, 0x3A, 0xF0, 0x81, 0xB4, 0x3F, 0x80, 0x06, 0xF2, 0x01, 0xDD, 0x5B, + 0x84, 0x01, 0xDD, 0x45, 0x3E, 0x67, 0xF1, 0x3D, 0x3E, 0x67, 0xF0, 0x5D, 0x3E, 0x67, 0xF1, 0x3C, + 0xDD, 0x5F, 0xDD, 0x48, 0x96, 0x00, 0x5A, 0x08, 0x01, 0x0D, 0x3C, 0x2D, 0xFB, 0x5B, 0xEB, 0x01, + 0xFE, 0x57, 0x3C, 0x1F, 0xFB, 0x5B, 0x3E, 0x07, 0xF1, 0x3D, 0x3E, 0x07, 0xF1, 0x3C, 0xDD, 0x5F, + 0xDD, 0x48, 0x5A, 0x08, 0x02, 0x05, 0xDD, 0x4F, 0xEB, 0x1A, 0xD5, 0x21, 0xDD, 0x48, 0x5A, 0x08, + 0x03, 0x06, 0xDD, 0x4F, 0x46, 0x00, 0x80, 0x00, 0xD5, 0x1A, 0xDD, 0x48, 0x5A, 0x00, 0x04, 0x03, + 0xDD, 0x5F, 0xDD, 0x4F, 0x46, 0x01, 0x00, 0x00, 0xD5, 0x12, 0xDD, 0x53, 0x5A, 0x08, 0x17, 0x13, + 0xDD, 0x48, 0xC8, 0x06, 0xDD, 0x4F, 0x44, 0x0F, 0x7F, 0xFF, 0x48, 0xFF, 0xFF, 0x4B, 0xDD, 0x48, + 0x5A, 0x00, 0x01, 0x03, 0xDD, 0x5F, 0xDD, 0x4F, 0x44, 0x00, 0x80, 0x00, 0xFE, 0x0F, 0x48, 0xFF, + 0xFF, 0x42, 0xDD, 0x53, 0x5A, 0x00, 0x18, 0x03, 0xDD, 0x5F, 0xDD, 0x48, 0x96, 0x00, 0xC0, 0x2F, + 0xDD, 0x48, 0x96, 0x00, 0x5A, 0x00, 0x01, 0x2C, 0xDD, 0x48, 0x96, 0x00, 0x5A, 0x08, 0x02, 0x23, + 0x3E, 0x07, 0xF0, 0xD7, 0x44, 0x02, 0x2D, 0x84, 0x40, 0x10, 0x20, 0x09, 0x96, 0x48, 0x96, 0x00, + 0x3E, 0x17, 0xF2, 0x34, 0xEB, 0x0A, 0x84, 0x05, 0x3E, 0x07, 0xF2, 0x36, 0xFA, 0x00, 0xEB, 0xAF, + 0x2E, 0x07, 0xF9, 0x07, 0x3E, 0x07, 0xF2, 0x38, 0x84, 0x01, 0x3E, 0x07, 0xF2, 0x39, 0x2E, 0x07, + 0xF9, 0x06, 0x3E, 0x07, 0xF2, 0x3A, 0x2E, 0x07, 0xF9, 0x05, 0x3E, 0x07, 0xF2, 0x3B, 0x84, 0x08, + 0xEA, 0x44, 0xDD, 0x48, 0x96, 0x00, 0x5A, 0x00, 0x03, 0x03, 0xDD, 0x5F, 0x3E, 0x07, 0xF0, 0xD7, + 0xDD, 0x5F, 0x5A, 0x08, 0x30, 0x41, 0x2E, 0x57, 0xF8, 0x75, 0x2E, 0x47, 0xF8, 0x77, 0xDD, 0x48, + 0x40, 0x42, 0x20, 0x08, 0x2E, 0x37, 0xF8, 0x79, 0x2E, 0x17, 0xF8, 0x78, 0xFF, 0x07, 0x84, 0x46, + 0x97, 0x68, 0x96, 0xD8, 0x96, 0x48, 0x84, 0x00, 0x99, 0xA2, 0x44, 0x72, 0x2C, 0xEC, 0xE0, 0xC2, + 0xE9, 0x08, 0x8C, 0x41, 0x38, 0x93, 0x88, 0x00, 0x96, 0x91, 0x88, 0x09, 0x96, 0x00, 0xD5, 0xF8, + 0x4E, 0x03, 0x00, 0xEB, 0x5A, 0x50, 0x02, 0x03, 0xDD, 0x59, 0xEA, 0xCD, 0xFE, 0x5F, 0x44, 0x22, + 0x07, 0x00, 0x44, 0x32, 0x07, 0x00, 0x44, 0x52, 0x2C, 0xEC, 0x88, 0x41, 0x88, 0x61, 0x97, 0x81, + 0xE2, 0xC4, 0x4E, 0xF2, 0x00, 0xDA, 0x9D, 0x87, 0x38, 0x72, 0x98, 0x00, 0x38, 0x71, 0x00, 0x08, + 0x99, 0xC1, 0x5C, 0xF3, 0x81, 0xFC, 0xE9, 0x05, 0x38, 0x62, 0x98, 0x00, 0x38, 0x61, 0x80, 0x08, + 0x8C, 0x01, 0xD5, 0xEE, 0x5A, 0x08, 0x31, 0x30, 0x84, 0x01, 0xEB, 0x78, 0xDD, 0x48, 0xEA, 0x7D, + 0xDD, 0x52, 0xFE, 0x0F, 0x2E, 0x17, 0xF8, 0x78, 0x2E, 0x57, 0xF8, 0x77, 0xEA, 0x4F, 0xFF, 0x4F, + 0x2E, 0x17, 0xF8, 0x74, 0x44, 0x22, 0x07, 0x00, 0x96, 0x48, 0x44, 0x32, 0x07, 0x00, 0x3E, 0x17, + 0xF2, 0x34, 0x44, 0x62, 0x26, 0xAC, 0x84, 0x20, 0x88, 0x45, 0x88, 0x65, 0x97, 0x09, 0xE2, 0x80, + 0xE8, 0x0F, 0x99, 0x0D, 0x5C, 0xF2, 0x01, 0xFC, 0x9D, 0x09, 0xE8, 0x04, 0x38, 0x11, 0x84, 0x00, + 0xD5, 0x03, 0x38, 0x11, 0x04, 0x00, 0x38, 0x13, 0x10, 0x08, 0x80, 0x24, 0xD5, 0xF0, 0x8C, 0x01, + 0x96, 0x01, 0xEA, 0x44, 0x5A, 0x08, 0x35, 0x18, 0xEA, 0x7D, 0x5A, 0x18, 0x01, 0x0F, 0xDD, 0x48, + 0x96, 0x00, 0x5A, 0x00, 0x01, 0x07, 0x5A, 0x00, 0x02, 0x03, 0xDD, 0x59, 0x84, 0x04, 0xD5, 0x02, + 0x84, 0x02, 0x3E, 0x07, 0xEA, 0x4C, 0xDD, 0x59, 0xEA, 0xA4, 0xEA, 0xF8, 0x96, 0x00, 0xEB, 0x0A, + 0x84, 0x02, 0xEA, 0x44, 0x5A, 0x08, 0x61, 0x0F, 0xEA, 0x7D, 0x96, 0x48, 0xC9, 0x03, 0xEA, 0x5A, + 0xD5, 0x07, 0xDD, 0x53, 0x5A, 0x00, 0x01, 0x03, 0xDD, 0x5F, 0xEA, 0x5A, 0x84, 0x21, 0xEB, 0x60, + 0xDD, 0x59, 0x5A, 0x08, 0xA3, 0x0B, 0xFA, 0x01, 0x44, 0x10, 0x03, 0x20, 0xEA, 0x31, 0xFA, 0x01, + 0x84, 0x21, 0xDD, 0x47, 0x84, 0x01, 0xD5, 0x69, 0x5A, 0x08, 0xF0, 0x2C, 0xDD, 0x53, 0xC0, 0x04, + 0xDD, 0x53, 0x5A, 0x08, 0x04, 0x0F, 0x84, 0x21, 0x3E, 0x17, 0xEA, 0x50, 0xDD, 0x53, 0x96, 0x00, + 0xC8, 0x04, 0x3E, 0x00, 0x03, 0x2D, 0xD5, 0x03, 0x3E, 0x10, 0x03, 0x2D, 0x84, 0x00, 0xD5, 0x0F, + 0xDD, 0x53, 0x96, 0x00, 0x5A, 0x08, 0x01, 0x08, 0x3E, 0x07, 0xF9, 0x04, 0xEA, 0xB8, 0x49, 0xFF, + 0xD9, 0xD5, 0xD5, 0x4A, 0xDD, 0x53, 0x96, 0x00, 0x5A, 0x08, 0x02, 0x05, 0x3E, 0x07, 0xF9, 0x04, + 0xD5, 0x43, 0xDD, 0x53, 0x5A, 0x08, 0xFA, 0x43, 0x84, 0x01, 0x3E, 0x07, 0xF2, 0x2C, 0xD5, 0x3E, + 0x5A, 0x08, 0xF6, 0x06, 0xDD, 0x53, 0x5A, 0x08, 0xF2, 0x3A, 0xD5, 0x36, 0x5A, 0x08, 0xFA, 0x0E, + 0xDD, 0x53, 0x5A, 0x08, 0x03, 0x04, 0x84, 0x01, 0xD5, 0x05, 0xDD, 0x53, 0x5A, 0x08, 0x08, 0x2F, + 0x84, 0x02, 0x3E, 0x07, 0xEB, 0x7C, 0xD5, 0x28, 0x5A, 0x08, 0xFE, 0x29, 0x84, 0x01, 0x84, 0x3E, + 0xEB, 0x78, 0x3E, 0x17, 0xF2, 0x34, 0xEB, 0x0A, 0xEA, 0xB8, 0x3E, 0x07, 0xF2, 0x36, 0x44, 0x1F, + 0xFF, 0x90, 0x84, 0x00, 0xEB, 0xAF, 0x3E, 0x07, 0xF2, 0x38, 0x3E, 0x17, 0xF2, 0x39, 0x3E, 0x07, + 0xF2, 0x3A, 0x3E, 0x07, 0xF2, 0x3B, 0x3E, 0x07, 0xF2, 0x3C, 0x3E, 0x07, 0xF2, 0x3D, 0x3E, 0x07, + 0xF2, 0x3E, 0x3E, 0x07, 0xF2, 0x3F, 0x3E, 0x07, 0xF2, 0x40, 0x84, 0x0D, 0xEA, 0xD9, 0x49, 0xFF, + 0xDF, 0xA1, 0x84, 0x00, 0xEB, 0x19, 0x84, 0x00, 0xEB, 0x6F, 0x84, 0x00, 0x3E, 0x07, 0xF8, 0x74, + 0xFC, 0xC1, 0x2E, 0x07, 0xF9, 0x04, 0xDD, 0x9E, 0x2E, 0x07, 0xEB, 0x7C, 0xDD, 0x9E, 0xFC, 0x00, + 0xEB, 0x3F, 0x80, 0xC0, 0x44, 0x20, 0x06, 0x40, 0x44, 0x02, 0x26, 0xAC, 0xDD, 0x40, 0xCE, 0x05, + 0x44, 0x00, 0x00, 0x5A, 0xEA, 0xA4, 0xD5, 0x0F, 0x44, 0x0F, 0xFF, 0xA7, 0xEA, 0xA4, 0x84, 0x05, + 0xEB, 0x0A, 0x44, 0x0F, 0xFF, 0xB4, 0x3E, 0x07, 0xF2, 0x36, 0xFA, 0x10, 0xEB, 0xAF, 0x84, 0x1F, + 0x3E, 0x07, 0xF2, 0x38, 0x84, 0x01, 0xEB, 0x78, 0xFC, 0x80, 0xFC, 0x40, 0x2E, 0x67, 0xF9, 0x04, + 0x49, 0xFF, 0xD9, 0x57, 0x80, 0xE0, 0xEB, 0xE0, 0x96, 0x06, 0x5A, 0x08, 0x01, 0x0A, 0x84, 0x20, + 0xDD, 0x47, 0xEA, 0x6A, 0x84, 0x1E, 0xFE, 0x0E, 0xEB, 0x9E, 0x48, 0x00, 0x00, 0x87, 0xEB, 0xE0, + 0x92, 0x04, 0x96, 0x06, 0x5A, 0x08, 0x01, 0x16, 0xEA, 0xA2, 0x5A, 0x00, 0x01, 0x04, 0x48, 0x00, + 0x00, 0x84, 0xEA, 0x6E, 0x92, 0x04, 0x96, 0x06, 0x4E, 0x03, 0x00, 0x7F, 0x49, 0xFF, 0xFF, 0xC1, + 0xFA, 0x1A, 0xEA, 0xD9, 0x49, 0xFF, 0xFB, 0xE6, 0xEA, 0xC4, 0xEA, 0x6E, 0xEA, 0x65, 0xD5, 0x46, + 0xEA, 0x6A, 0x92, 0x23, 0x96, 0x46, 0x5A, 0x18, 0x01, 0x12, 0xEA, 0xA2, 0x5A, 0x00, 0x01, 0x04, + 0x48, 0x00, 0x00, 0x6B, 0xEA, 0x6E, 0x92, 0x03, 0x96, 0x06, 0xC8, 0x66, 0x2E, 0x07, 0xED, 0x94, + 0x49, 0xFF, 0xD3, 0x15, 0xEA, 0x6E, 0xEB, 0x6A, 0xD5, 0x31, 0xEA, 0x6A, 0x92, 0x21, 0x96, 0x46, + 0x5A, 0x18, 0x01, 0x18, 0xEA, 0xA2, 0x5A, 0x08, 0x01, 0x58, 0x5A, 0x78, 0x02, 0x03, 0xC6, 0x54, + 0xEA, 0x6E, 0x92, 0x01, 0x96, 0x06, 0xC8, 0x50, 0x49, 0xFF, 0xD2, 0xEA, 0x2E, 0x07, 0xF0, 0x68, + 0x5A, 0x08, 0x01, 0x05, 0xEA, 0x6E, 0xEA, 0x39, 0xD5, 0x19, 0xEA, 0x6A, 0x84, 0x1D, 0xD5, 0x1B, + 0xEB, 0xE0, 0x92, 0x02, 0x96, 0x06, 0x5A, 0x08, 0x01, 0x1A, 0xEA, 0xA2, 0x5A, 0x08, 0x01, 0x3D, + 0xEA, 0x6E, 0x92, 0x02, 0x96, 0x06, 0xC8, 0x38, 0x80, 0x20, 0x49, 0xFF, 0xD2, 0x8A, 0x2E, 0x07, + 0xF0, 0x68, 0x5A, 0x08, 0x01, 0x07, 0xEA, 0x6E, 0xEA, 0xA5, 0x3C, 0x0B, 0xF6, 0xC9, 0xD5, 0x1C, + 0xEA, 0x6A, 0x84, 0x1B, 0xFE, 0x0E, 0xEB, 0x9E, 0xD5, 0x17, 0xEA, 0xA2, 0x81, 0x20, 0x5A, 0x08, + 0x01, 0x24, 0xDD, 0x41, 0xC8, 0x0B, 0x2E, 0x77, 0xF0, 0xD0, 0x97, 0xF8, 0xCF, 0x07, 0x80, 0x09, + 0x49, 0xFF, 0xEE, 0x8C, 0x80, 0x07, 0x80, 0x29, 0xDD, 0x4E, 0x84, 0x01, 0x84, 0x20, 0xDD, 0x47, + 0x84, 0x03, 0x84, 0x20, 0xD5, 0x10, 0x5A, 0x68, 0x02, 0x2C, 0x84, 0x01, 0x44, 0x10, 0x01, 0x90, + 0xEA, 0x31, 0x84, 0x01, 0x80, 0x20, 0xDD, 0x47, 0x84, 0x03, 0x44, 0x10, 0x01, 0xF4, 0xEA, 0x31, + 0x84, 0x03, 0x84, 0x21, 0xDD, 0x47, 0x84, 0x01, 0xEA, 0x32, 0x80, 0xE0, 0x5A, 0x08, 0x01, 0x11, + 0xCE, 0x07, 0xEA, 0x7A, 0xEB, 0x3B, 0x96, 0x03, 0xEB, 0x29, 0xEA, 0xC4, 0xD5, 0x09, 0x5A, 0x68, + 0x02, 0x08, 0x84, 0x20, 0xDD, 0x47, 0x80, 0x07, 0x49, 0xFF, 0xDE, 0xE8, 0xEB, 0x6E, 0x84, 0x03, + 0xEA, 0x32, 0x5A, 0x08, 0x01, 0x09, 0x49, 0xFF, 0xDE, 0xE1, 0xEB, 0x6E, 0xFC, 0xC0, 0x84, 0x01, + 0xFA, 0x24, 0xD5, 0xD7, 0xFC, 0xC0, 0xFC, 0x00, 0x04, 0x30, 0x00, 0x3F, 0x80, 0xC0, 0x00, 0x00, + 0x00, 0xFD, 0x54, 0x51, 0x80, 0x0F, 0x5A, 0x08, 0x01, 0x24, 0x92, 0x64, 0x96, 0xDF, 0x4C, 0x32, + 0xC0, 0x08, 0x9D, 0x5D, 0x84, 0x66, 0x40, 0x32, 0x8C, 0xB6, 0x97, 0x68, 0xD5, 0x0F, 0x9D, 0x29, + 0x84, 0x66, 0x40, 0x42, 0x0C, 0x76, 0x54, 0x41, 0x80, 0x0F, 0x00, 0x33, 0x00, 0xFC, 0x84, 0x02, + 0x54, 0x31, 0x80, 0xF0, 0xFE, 0xE7, 0x10, 0x33, 0x00, 0xFC, 0x8C, 0xAD, 0x95, 0x6B, 0xAE, 0x10, + 0x80, 0x01, 0x98, 0x75, 0x8C, 0x24, 0x84, 0x48, 0xDD, 0x55, 0x84, 0x01, 0xFC, 0x80, 0x84, 0x00, + 0xAE, 0x10, 0x84, 0x00, 0xFC, 0x80, 0xFC, 0x42, 0x84, 0x20, 0x81, 0x40, 0x84, 0x48, 0xB0, 0x02, + 0xDD, 0x40, 0x2E, 0x07, 0xF2, 0x25, 0x44, 0x72, 0x50, 0x5C, 0x8C, 0x01, 0x3E, 0x07, 0xF2, 0x25, + 0x85, 0x05, 0x84, 0xC1, 0x87, 0x80, 0x44, 0x92, 0x26, 0xAC, 0x80, 0x07, 0xB0, 0x42, 0x50, 0x2F, + 0x80, 0x07, 0x49, 0xFF, 0xFF, 0xBA, 0xC0, 0x53, 0x00, 0x13, 0x80, 0xBF, 0x5A, 0x18, 0x03, 0x05, + 0xEB, 0x0E, 0x5A, 0x00, 0x01, 0x06, 0x00, 0x03, 0x81, 0x09, 0x5A, 0x08, 0x01, 0x09, 0x00, 0x03, + 0x81, 0x05, 0x5A, 0x08, 0x01, 0x05, 0x10, 0x03, 0x81, 0x09, 0xD5, 0x41, 0x8E, 0x22, 0xE6, 0x22, + 0xE8, 0x3E, 0xF1, 0x02, 0x90, 0x2A, 0x4E, 0x17, 0x00, 0x08, 0x5E, 0xF0, 0x80, 0xFF, 0xE9, 0x05, + 0x44, 0x10, 0x00, 0xFE, 0xD5, 0x02, 0x84, 0x21, 0x4E, 0xA3, 0x00, 0x1C, 0x22, 0x3F, 0x80, 0x07, + 0x22, 0x4F, 0x80, 0x06, 0xEA, 0xC6, 0x54, 0x20, 0x00, 0x0F, 0x40, 0x02, 0x10, 0x0A, 0xEB, 0x5F, + 0xFE, 0x17, 0x38, 0x04, 0x98, 0x08, 0x9C, 0x31, 0x97, 0x20, 0x38, 0x44, 0x80, 0x08, 0x9C, 0x32, + 0x96, 0xD8, 0x38, 0x34, 0x80, 0x08, 0x9C, 0x33, 0x96, 0x48, 0x38, 0x14, 0x80, 0x08, 0xD5, 0x16, + 0x22, 0x3F, 0x80, 0x07, 0x22, 0x2F, 0x80, 0x06, 0xEA, 0xC6, 0xEB, 0x57, 0x40, 0x01, 0x10, 0x0A, + 0xEB, 0x5F, 0xFE, 0x0F, 0x38, 0x04, 0xA0, 0x08, 0xEB, 0x02, 0x96, 0x90, 0x50, 0x14, 0x00, 0x02, + 0x38, 0x24, 0x80, 0x08, 0x96, 0x18, 0x38, 0x04, 0x84, 0x08, 0x87, 0x81, 0x8C, 0xC4, 0x50, 0x73, + 0x81, 0x0C, 0x8D, 0x03, 0x5A, 0x68, 0x29, 0xA3, 0x80, 0x1C, 0xFC, 0xC2, 0xFA, 0xB3, 0x44, 0x22, + 0x26, 0xAC, 0x44, 0x30, 0x05, 0x33, 0x80, 0x80, 0x0A, 0x10, 0x00, 0x01, 0x92, 0x28, 0x38, 0x11, + 0x14, 0x08, 0x9C, 0x69, 0xA7, 0x20, 0x8C, 0xA2, 0x38, 0x41, 0x04, 0x08, 0xDB, 0xF5, 0xDD, 0x9E, + 0xFC, 0x40, 0x84, 0x60, 0x44, 0x72, 0x19, 0x0C, 0x44, 0x62, 0x26, 0xAC, 0x84, 0x40, 0x98, 0x53, + 0x96, 0x49, 0x38, 0x43, 0x85, 0x01, 0xC0, 0x0F, 0x95, 0x21, 0x88, 0x80, 0x94, 0x49, 0xA5, 0x60, + 0x50, 0x90, 0x80, 0x23, 0x92, 0xA8, 0x38, 0x53, 0x24, 0x08, 0x50, 0x10, 0x80, 0x24, 0xA7, 0x20, + 0x38, 0x43, 0x04, 0x08, 0x8C, 0x41, 0x96, 0x91, 0x5A, 0x28, 0x12, 0xEB, 0x8C, 0x72, 0x96, 0xD9, + 0x5A, 0x3A, 0x88, 0xE6, 0xFC, 0xC0, 0x44, 0x50, 0x05, 0x33, 0x44, 0x22, 0x26, 0xAC, 0x44, 0x30, + 0x05, 0x9F, 0x80, 0x80, 0x0A, 0x10, 0x00, 0x01, 0x92, 0x28, 0x38, 0x11, 0x14, 0x08, 0x9C, 0x69, + 0xA7, 0x20, 0x8C, 0xA2, 0x38, 0x41, 0x04, 0x08, 0xDB, 0xF5, 0xDD, 0x9E, 0xC8, 0x03, 0x3E, 0x17, + 0xF2, 0x5D, 0xDD, 0x9E, 0xFC, 0x00, 0x49, 0xFF, 0xD7, 0xAE, 0x5A, 0x08, 0x40, 0x09, 0x49, 0xFF, + 0xEE, 0xB0, 0x44, 0x00, 0x00, 0x41, 0x49, 0xFF, 0xD7, 0xA9, 0xD5, 0x00, 0xFC, 0x80, 0xE6, 0x18, + 0x80, 0x20, 0xE8, 0x09, 0x44, 0x01, 0x2A, 0x0C, 0x44, 0x21, 0x29, 0xF4, 0xEB, 0x37, 0x38, 0x31, + 0x04, 0x00, 0xD5, 0x03, 0xFA, 0x63, 0xEA, 0xF0, 0x3C, 0x1D, 0xF6, 0x50, 0x44, 0x21, 0xE6, 0x7F, + 0xFE, 0x56, 0x40, 0x10, 0x8C, 0x0D, 0x96, 0x46, 0xC9, 0x02, 0xEA, 0xF0, 0xDD, 0x9E, 0xFC, 0x56, + 0x84, 0x20, 0x81, 0x20, 0x44, 0x20, 0x00, 0xA9, 0xB0, 0x01, 0xDD, 0x40, 0xEA, 0xAF, 0xC0, 0x07, + 0x44, 0x0F, 0xFF, 0xAE, 0xEA, 0xA0, 0xEA, 0xAF, 0xEB, 0x0F, 0xD5, 0x06, 0x44, 0x0F, 0xFF, 0xAA, + 0xEA, 0xA0, 0x10, 0x9F, 0x80, 0x05, 0x3C, 0x34, 0x0B, 0x4D, 0x84, 0x00, 0x10, 0x0F, 0x80, 0x06, + 0x44, 0x0F, 0xFF, 0xAA, 0x3C, 0x24, 0x0B, 0x4E, 0xEA, 0x8E, 0xEA, 0xC6, 0x96, 0x01, 0x94, 0x44, + 0xEA, 0xF5, 0x96, 0x1F, 0x10, 0x3F, 0x80, 0x09, 0x3C, 0x34, 0x0B, 0x4F, 0xFE, 0x0F, 0x10, 0x0F, + 0x80, 0x08, 0x10, 0x2F, 0x80, 0x0A, 0xEA, 0xC6, 0x3C, 0x24, 0x0B, 0x50, 0x96, 0x01, 0x94, 0x44, + 0xEA, 0xF5, 0x96, 0x1F, 0x10, 0x3F, 0x80, 0x0C, 0x3C, 0x34, 0x0B, 0x53, 0xFE, 0x0F, 0x10, 0x0F, + 0x80, 0x0B, 0x10, 0x2F, 0x80, 0x0D, 0xEA, 0xC6, 0x3C, 0x24, 0x0B, 0x54, 0x96, 0x01, 0x94, 0x44, + 0xEA, 0xF5, 0x96, 0x1F, 0x10, 0x3F, 0x80, 0x0F, 0x3C, 0x34, 0x0B, 0x55, 0xFE, 0x0F, 0x10, 0x0F, + 0x80, 0x0E, 0x10, 0x2F, 0x80, 0x10, 0xEA, 0xC6, 0x3C, 0x24, 0x0B, 0x56, 0x96, 0x01, 0x94, 0x44, + 0xEA, 0xF5, 0x96, 0x1F, 0xFE, 0x0F, 0x10, 0x3F, 0x80, 0x12, 0x3C, 0x10, 0x0B, 0x57, 0x3C, 0x30, + 0x0B, 0x58, 0x44, 0x52, 0x4A, 0x48, 0x10, 0x2F, 0x80, 0x13, 0x10, 0x0F, 0x80, 0x11, 0x54, 0xA0, + 0x80, 0xFF, 0x54, 0x81, 0x80, 0xFF, 0xB1, 0x81, 0x84, 0x40, 0x80, 0x85, 0x5A, 0x98, 0x6F, 0x0A, + 0xCA, 0x08, 0x10, 0x2F, 0x80, 0x14, 0x10, 0xAF, 0x80, 0x15, 0x10, 0x8F, 0x80, 0x16, 0xD5, 0x11, + 0x20, 0x72, 0x80, 0x01, 0x97, 0xF9, 0x94, 0x3C, 0x20, 0x72, 0x80, 0x03, 0x97, 0xDF, 0xFF, 0xC7, + 0xA4, 0x28, 0x10, 0x73, 0x00, 0x10, 0x10, 0x03, 0x00, 0x11, 0xA4, 0x29, 0x10, 0x03, 0x00, 0x12, + 0x8C, 0x41, 0x96, 0x90, 0x8C, 0xA4, 0x8C, 0xC3, 0x5A, 0x28, 0x04, 0xE2, 0x3C, 0x64, 0x0B, 0x45, + 0x3C, 0x54, 0x0B, 0x47, 0x40, 0x03, 0x20, 0x0A, 0x96, 0x01, 0x94, 0x84, 0x40, 0x02, 0xA0, 0x0A, + 0x96, 0x1F, 0x10, 0x5F, 0x80, 0x22, 0x3C, 0x54, 0x0B, 0x46, 0xFE, 0x17, 0x10, 0x0F, 0x80, 0x20, + 0x3C, 0x24, 0x0B, 0x48, 0x40, 0x02, 0xA0, 0x0A, 0x96, 0x01, 0x10, 0x6F, 0x80, 0x21, 0x95, 0x84, + 0xEA, 0xF5, 0x96, 0x1F, 0xFE, 0x37, 0x2E, 0x60, 0x16, 0x88, 0x96, 0x00, 0x10, 0x6F, 0x80, 0x26, + 0x99, 0x99, 0x10, 0x6F, 0x80, 0x27, 0x2E, 0x60, 0x16, 0xB2, 0x97, 0x68, 0x96, 0x90, 0x10, 0x0F, + 0x80, 0x23, 0x10, 0x0F, 0x80, 0x29, 0x10, 0x5F, 0x80, 0x24, 0x10, 0x2F, 0x80, 0x25, 0x10, 0x6F, + 0x80, 0x28, 0x10, 0x5F, 0x80, 0x2A, 0x10, 0x2F, 0x80, 0x2B, 0x84, 0x00, 0x84, 0xE3, 0xE2, 0x01, + 0x84, 0xC3, 0xE8, 0x20, 0x9D, 0x44, 0x42, 0x20, 0x1C, 0x24, 0x38, 0x62, 0x16, 0x11, 0x95, 0x6A, + 0x88, 0xA4, 0x96, 0x90, 0x22, 0xA2, 0x80, 0x01, 0xB1, 0x41, 0x88, 0x45, 0x40, 0x53, 0x20, 0x0A, + 0x97, 0x69, 0x40, 0x92, 0x90, 0x08, 0x40, 0x55, 0x20, 0x0A, 0x97, 0x5F, 0x40, 0x54, 0x94, 0x04, + 0x8C, 0x01, 0x10, 0x51, 0x00, 0x28, 0x10, 0x61, 0x00, 0x29, 0x10, 0xA1, 0x00, 0x2A, 0x96, 0x00, + 0xD5, 0xDF, 0xFE, 0x74, 0x96, 0x48, 0x84, 0x00, 0x80, 0x41, 0x42, 0x20, 0x18, 0x73, 0xE2, 0x03, + 0x96, 0x90, 0xE8, 0x1C, 0x50, 0x50, 0x00, 0x18, 0x95, 0x6A, 0x88, 0xA4, 0x8C, 0x01, 0x22, 0x92, + 0x80, 0x02, 0x22, 0xA2, 0x80, 0x03, 0xB1, 0x41, 0x88, 0x45, 0x40, 0x54, 0xA0, 0x0A, 0x97, 0x69, + 0x95, 0xEC, 0x40, 0x55, 0x20, 0x0A, 0x97, 0x5F, 0xFF, 0x7F, 0x10, 0x51, 0x00, 0x28, 0x10, 0x91, + 0x00, 0x29, 0x10, 0xA1, 0x00, 0x2A, 0x96, 0x00, 0xD5, 0xE0, 0xB0, 0x01, 0x44, 0x10, 0x00, 0xA9, + 0x49, 0xFF, 0xF7, 0x76, 0xFC, 0xD6, 0xFC, 0x40, 0x51, 0xFF, 0xFD, 0x10, 0x50, 0x9F, 0x80, 0x28, + 0x84, 0x20, 0xFA, 0x50, 0x80, 0x09, 0xDD, 0x40, 0x84, 0x20, 0x44, 0x20, 0x02, 0x88, 0xB0, 0x1A, + 0xDD, 0x40, 0xB1, 0xD2, 0x44, 0x11, 0x2A, 0x28, 0x80, 0x07, 0xEA, 0x88, 0xEA, 0x5B, 0xEA, 0x70, + 0xEA, 0x5C, 0x44, 0x01, 0x2A, 0x48, 0xB1, 0x83, 0x3A, 0x20, 0x14, 0x00, 0xB0, 0x06, 0x84, 0x20, + 0xEA, 0x5C, 0x84, 0x4C, 0x80, 0x06, 0xDD, 0x40, 0x84, 0x04, 0x10, 0x0F, 0x80, 0x0C, 0xAE, 0x31, + 0x84, 0x01, 0xAE, 0x32, 0xAE, 0x33, 0xAE, 0x34, 0xAE, 0x35, 0xAE, 0x36, 0xAE, 0x37, 0x84, 0x00, + 0xEA, 0xEB, 0x84, 0x00, 0x38, 0x13, 0x00, 0x00, 0x96, 0x89, 0xC2, 0x08, 0x5A, 0x20, 0x03, 0x07, + 0x38, 0x24, 0x86, 0x02, 0xCA, 0x03, 0x38, 0x14, 0x86, 0x0A, 0x8C, 0x01, 0x5A, 0x08, 0x0C, 0xF4, + 0x46, 0x80, 0x03, 0x8E, 0x47, 0xC0, 0x04, 0x10, 0x85, 0x40, 0x50, 0x84, 0x03, 0x8E, 0x51, 0xCE, + 0x04, 0x10, 0x38, 0x04, 0xAA, 0x02, 0xC0, 0x3B, 0xB0, 0x06, 0x84, 0x80, 0x38, 0x60, 0x29, 0x01, + 0x92, 0xC2, 0x84, 0x00, 0x96, 0x41, 0xE2, 0x26, 0xE8, 0x12, 0x38, 0x14, 0xAA, 0x02, 0x9E, 0x8C, + 0xE6, 0x42, 0xE8, 0x05, 0xB0, 0x5A, 0x39, 0xC0, 0x82, 0x0A, 0xD5, 0x07, 0x8E, 0x21, 0xE6, 0x22, + 0xE8, 0x04, 0xB0, 0x5A, 0x38, 0x80, 0x82, 0x0A, 0x8C, 0x01, 0xD5, 0xED, 0xCC, 0x0D, 0x38, 0x13, + 0xAA, 0x01, 0xB6, 0x3F, 0xEA, 0xC3, 0xB4, 0x3F, 0xDD, 0x52, 0x88, 0x20, 0x96, 0x49, 0xB0, 0x1A, + 0x80, 0x46, 0xEB, 0x89, 0xD5, 0x12, 0x38, 0x13, 0xAA, 0x01, 0xF4, 0x81, 0xB6, 0x3F, 0xEA, 0xC3, + 0xB4, 0x3F, 0xDD, 0x52, 0x50, 0x10, 0x82, 0x00, 0x88, 0x20, 0x96, 0x49, 0xB0, 0x1A, 0x80, 0x46, + 0xEB, 0x89, 0xF4, 0x01, 0x5A, 0x40, 0x01, 0x04, 0x84, 0x81, 0xD5, 0xCC, 0x8D, 0x41, 0x5A, 0xA8, + 0x08, 0xC2, 0x84, 0x01, 0xEA, 0xEB, 0x51, 0xFF, 0x82, 0xF0, 0xFC, 0xC0, 0xFC, 0x00, 0x84, 0xC0, + 0x3E, 0x67, 0xF0, 0xDE, 0xEB, 0xA7, 0x3E, 0x67, 0xF0, 0xDD, 0xFC, 0x80, 0xFC, 0x00, 0xEA, 0x57, + 0xFC, 0x80, 0xFC, 0x09, 0x84, 0x20, 0xB0, 0x06, 0xEA, 0xA7, 0xDD, 0x40, 0x44, 0x03, 0xF0, 0x3F, + 0xF0, 0x86, 0xEA, 0xC7, 0x94, 0x06, 0xF0, 0x87, 0xF1, 0x89, 0xEB, 0x0C, 0xEA, 0xFD, 0xF1, 0x8A, + 0x94, 0x46, 0xF0, 0x88, 0xF1, 0x8B, 0xDD, 0x56, 0xEA, 0x21, 0xF1, 0x8C, 0xF0, 0x8D, 0x84, 0x20, + 0x80, 0x1F, 0xFA, 0x48, 0xDD, 0x40, 0x84, 0x01, 0x84, 0x82, 0x84, 0x63, 0x84, 0x44, 0x84, 0x25, + 0x10, 0x0F, 0x80, 0x01, 0x10, 0x0F, 0x80, 0x03, 0x10, 0x0F, 0x80, 0x0D, 0x10, 0x0F, 0x80, 0x0F, + 0x80, 0x1F, 0x10, 0x4F, 0x80, 0x04, 0x10, 0x3F, 0x80, 0x05, 0x10, 0x2F, 0x80, 0x06, 0x10, 0x1F, + 0x80, 0x07, 0x10, 0x4F, 0x80, 0x10, 0x10, 0x3F, 0x80, 0x11, 0x10, 0x2F, 0x80, 0x12, 0x10, 0x1F, + 0x80, 0x13, 0xEA, 0xD2, 0xB0, 0x06, 0xEA, 0xC1, 0xFC, 0x89, 0x50, 0x40, 0x5A, 0xE3, 0x97, 0x21, + 0x5C, 0xF2, 0x03, 0xE7, 0xCA, 0x17, 0xE9, 0x33, 0x5E, 0xF0, 0x29, 0x04, 0xE9, 0x0A, 0x5E, 0xF0, + 0x3F, 0x06, 0xE9, 0x04, 0x84, 0x41, 0xAE, 0x98, 0x84, 0x41, 0x50, 0x00, 0x5A, 0xE4, 0xD5, 0x20, + 0x5E, 0xF0, 0x00, 0xFB, 0xE8, 0x04, 0x84, 0x41, 0xAE, 0x98, 0x84, 0x41, 0x50, 0x00, 0x56, 0xFC, + 0xD5, 0x17, 0xE9, 0x1C, 0x5E, 0xF0, 0x29, 0x04, 0x84, 0x40, 0xE9, 0x0A, 0x5E, 0xF0, 0x3F, 0x06, + 0xE9, 0x04, 0x84, 0x41, 0xAE, 0x98, 0x84, 0x41, 0x52, 0x00, 0x25, 0x1C, 0xD5, 0x09, 0x5E, 0xF0, + 0x00, 0xFB, 0xE8, 0x04, 0x84, 0x41, 0xAE, 0x98, 0x84, 0x41, 0x52, 0x00, 0x29, 0x04, 0x44, 0xF0, + 0x03, 0xE8, 0x40, 0x00, 0x3C, 0x16, 0x96, 0x02, 0xD5, 0x03, 0x84, 0x40, 0x80, 0x02, 0x54, 0x30, + 0x80, 0x20, 0x96, 0x67, 0xC3, 0x02, 0xFE, 0x4A, 0x96, 0x4A, 0x5A, 0x28, 0x01, 0x08, 0x84, 0x44, + 0x40, 0x20, 0x08, 0x56, 0x88, 0x40, 0x98, 0x11, 0xD5, 0x02, 0x88, 0x01, 0x96, 0x42, 0x5E, 0xF0, + 0x80, 0x20, 0x80, 0x01, 0xE9, 0x02, 0xFA, 0x0F, 0x96, 0x42, 0x4E, 0x14, 0x00, 0x03, 0x84, 0x00, + 0x96, 0x00, 0xDD, 0x9E, 0xFC, 0x40, 0x51, 0xFF, 0xFC, 0xB8, 0xFA, 0x50, 0xF1, 0x87, 0x80, 0xC0, + 0x84, 0x20, 0xB0, 0x18, 0xDD, 0x40, 0x44, 0x11, 0x2A, 0x28, 0xB0, 0x20, 0xEA, 0x88, 0xEA, 0x5B, + 0xEA, 0x70, 0x50, 0x9F, 0x80, 0xA0, 0x44, 0x11, 0x2A, 0x58, 0xEA, 0x5C, 0x80, 0x09, 0xEA, 0x88, + 0xEA, 0x5B, 0xEA, 0x70, 0x44, 0x11, 0x2A, 0x48, 0xEA, 0x5C, 0xB0, 0x14, 0xEA, 0x70, 0x44, 0x11, + 0x2A, 0x78, 0xEA, 0x5C, 0xB0, 0x0F, 0xB1, 0xD1, 0x3A, 0x20, 0x8C, 0x00, 0xEB, 0xEF, 0x84, 0x20, + 0x84, 0x4C, 0x80, 0x07, 0xDD, 0x40, 0x84, 0x04, 0x10, 0x0F, 0x80, 0x44, 0xAE, 0x39, 0x84, 0x01, + 0xAE, 0x3A, 0xAE, 0x3B, 0xAE, 0x3C, 0xAE, 0x3D, 0xAE, 0x3E, 0xAE, 0x3F, 0x49, 0xFF, 0xDA, 0xA5, + 0xF0, 0x85, 0x85, 0x00, 0x39, 0xC3, 0xA0, 0x00, 0x40, 0x0E, 0x00, 0x13, 0xC0, 0x11, 0x5A, 0x00, + 0x03, 0x10, 0xB0, 0x18, 0x38, 0x00, 0x72, 0x02, 0xC8, 0x0B, 0x38, 0x04, 0xF2, 0x02, 0x40, 0xA0, + 0x04, 0x08, 0xEA, 0x57, 0xEA, 0x83, 0xB0, 0x58, 0x88, 0x0A, 0x38, 0x00, 0xF2, 0x0A, 0x8D, 0x01, + 0x5A, 0x88, 0x0C, 0xEA, 0x84, 0x26, 0x42, 0x03, 0x04, 0x24, 0xF0, 0x83, 0x8C, 0xC2, 0xF2, 0x03, + 0xFE, 0x74, 0x44, 0x00, 0x00, 0x3F, 0x40, 0x20, 0x08, 0x0C, 0xEB, 0x80, 0xFE, 0x93, 0xFE, 0x03, + 0xF2, 0x8A, 0xF1, 0x84, 0xF0, 0x8B, 0x84, 0xC0, 0x50, 0xAF, 0x80, 0xC0, 0xB0, 0x18, 0x38, 0x00, + 0x1A, 0x02, 0xF0, 0x82, 0xC8, 0x07, 0x8C, 0xC1, 0x5A, 0x68, 0x08, 0xFA, 0x51, 0xFF, 0x83, 0x48, + 0xFC, 0xC0, 0xB0, 0x0F, 0x84, 0xE0, 0x38, 0x03, 0x00, 0x00, 0x50, 0x8F, 0x80, 0x80, 0xB6, 0x1F, + 0x94, 0x01, 0xF0, 0x81, 0x02, 0x0F, 0x80, 0x02, 0xF0, 0x86, 0xF0, 0x01, 0xE0, 0xE0, 0xE8, 0xEC, + 0xCF, 0x0E, 0x38, 0x94, 0x1A, 0x01, 0xEA, 0xC3, 0xDD, 0x52, 0x40, 0x14, 0x80, 0x00, 0xB0, 0x14, + 0x96, 0x49, 0xEB, 0xA3, 0x80, 0x0A, 0x92, 0x42, 0x49, 0xFF, 0xD5, 0x95, 0xB4, 0x1F, 0x4C, 0x70, + 0x40, 0x10, 0x38, 0x94, 0x1A, 0x01, 0xEA, 0xC3, 0xDD, 0x52, 0x50, 0x14, 0x82, 0x00, 0x88, 0x20, + 0xB0, 0x14, 0x96, 0x49, 0xEB, 0xA3, 0x80, 0x0A, 0x92, 0x42, 0x49, 0xFF, 0xD5, 0x84, 0xFA, 0x0B, + 0x40, 0x93, 0x80, 0x13, 0x42, 0x14, 0x80, 0x24, 0xF1, 0x88, 0xF1, 0x01, 0x84, 0x80, 0x8A, 0x27, + 0x8E, 0x21, 0xFE, 0x0C, 0x96, 0x01, 0xF0, 0x89, 0xB4, 0x1F, 0xE2, 0xE0, 0x40, 0x02, 0x04, 0x09, + 0xE8, 0x03, 0xF1, 0x08, 0xD5, 0x02, 0xF1, 0x09, 0x88, 0x01, 0x41, 0xC0, 0x00, 0x13, 0xF0, 0x0A, + 0x38, 0x15, 0x72, 0x02, 0xF2, 0x05, 0x40, 0x50, 0x80, 0x02, 0xF0, 0x03, 0xF3, 0x07, 0x40, 0x10, + 0x80, 0x0D, 0xF0, 0x02, 0x96, 0x6F, 0xF4, 0x8D, 0x38, 0x00, 0x25, 0x11, 0xF5, 0x8C, 0x49, 0xFF, + 0xFE, 0xE6, 0xF1, 0x03, 0xF5, 0x0C, 0xEB, 0x80, 0xFF, 0x47, 0xF0, 0x06, 0xF2, 0x05, 0x88, 0x09, + 0x40, 0x90, 0x00, 0x13, 0xF0, 0x0B, 0xF3, 0x07, 0xFE, 0x2E, 0xF0, 0x8C, 0xF0, 0x04, 0x38, 0x55, + 0x72, 0x0A, 0x40, 0x12, 0x80, 0x0D, 0xF0, 0x02, 0x96, 0x6F, 0x38, 0x00, 0x25, 0x11, 0x49, 0xFF, + 0xFE, 0xCE, 0xF1, 0x04, 0xF4, 0x0D, 0xEB, 0x80, 0xF1, 0x0C, 0x8C, 0x82, 0xFE, 0x0F, 0x38, 0x05, + 0x72, 0x0A, 0xF0, 0x06, 0x97, 0x20, 0x88, 0x09, 0x40, 0x90, 0x00, 0x13, 0x5A, 0x48, 0x36, 0xBE, + 0xB4, 0x1F, 0x50, 0x93, 0x80, 0x01, 0x4C, 0x90, 0x40, 0x0E, 0x39, 0xC4, 0x1A, 0x01, 0xEA, 0xC3, + 0xDD, 0x52, 0x40, 0x1E, 0x00, 0x00, 0xB0, 0x14, 0x96, 0x49, 0xEB, 0xA3, 0x80, 0x0A, 0x92, 0x42, + 0xEB, 0x89, 0xF0, 0x01, 0x4C, 0x90, 0x40, 0x0F, 0x38, 0x94, 0x1A, 0x01, 0xEA, 0xC3, 0xDD, 0x52, + 0x50, 0x14, 0x82, 0x00, 0x88, 0x20, 0xB0, 0x14, 0x96, 0x49, 0xEB, 0xA3, 0x80, 0x0A, 0x92, 0x42, + 0xEB, 0x89, 0x8C, 0xE1, 0x97, 0xF8, 0x48, 0xFF, 0xFF, 0x6A, 0xFC, 0x05, 0x84, 0x20, 0xB0, 0x04, + 0xFA, 0x48, 0xDD, 0x40, 0x84, 0x25, 0x84, 0x01, 0x10, 0x1F, 0x80, 0x17, 0x10, 0x1F, 0x80, 0x23, + 0xB1, 0x81, 0x44, 0x11, 0x2A, 0x80, 0x10, 0x0F, 0x80, 0x11, 0x10, 0x0F, 0x80, 0x13, 0x10, 0x0F, + 0x80, 0x1D, 0x10, 0x0F, 0x80, 0x1F, 0x84, 0x63, 0x84, 0x44, 0x80, 0x06, 0x10, 0x3F, 0x80, 0x15, + 0x10, 0x2F, 0x80, 0x16, 0x10, 0x3F, 0x80, 0x21, 0x10, 0x2F, 0x80, 0x22, 0x84, 0x82, 0x3A, 0x20, + 0x8C, 0x04, 0x3A, 0x20, 0x0C, 0x24, 0x10, 0x4F, 0x80, 0x14, 0x10, 0x4F, 0x80, 0x20, 0xA4, 0x48, + 0xAC, 0x40, 0xB0, 0x04, 0xEA, 0xD2, 0x80, 0x06, 0x49, 0xFF, 0xDF, 0x53, 0xFC, 0x85, 0xFC, 0x06, + 0x84, 0x20, 0x80, 0x1F, 0xEA, 0xA7, 0xDD, 0x40, 0x44, 0x03, 0xF0, 0x3F, 0x94, 0x46, 0xB6, 0x1F, + 0xF0, 0x82, 0xF0, 0x84, 0xF0, 0x86, 0x80, 0x1F, 0xF1, 0x81, 0xF1, 0x83, 0xF1, 0x85, 0xF1, 0x87, + 0xEA, 0xC1, 0xFC, 0x86, 0xFC, 0x09, 0x84, 0x20, 0xB0, 0x06, 0xEA, 0xA7, 0xDD, 0x40, 0xEB, 0x35, + 0xEA, 0xC7, 0xF0, 0x86, 0xEB, 0x7B, 0xF1, 0x89, 0xF0, 0x87, 0xEA, 0xFD, 0xEB, 0x0C, 0xF1, 0x8A, + 0x94, 0x46, 0xF1, 0x8B, 0xDD, 0x56, 0xF0, 0x88, 0xF1, 0x8C, 0xB1, 0x81, 0xEA, 0x21, 0x44, 0x11, + 0x2A, 0x8C, 0xF0, 0x8D, 0x80, 0x06, 0xEA, 0x88, 0xEA, 0x5B, 0xB4, 0x21, 0xB6, 0x20, 0xB0, 0x06, + 0xEA, 0xC1, 0x80, 0x06, 0x49, 0xFF, 0xDE, 0xD8, 0xFC, 0x89, 0xFC, 0x02, 0x44, 0x11, 0x2A, 0xA0, + 0x80, 0x1F, 0xEA, 0x70, 0x3A, 0x2F, 0x94, 0x20, 0x49, 0xFF, 0xDE, 0xD8, 0xFC, 0x82, 0xFC, 0x00, + 0x80, 0xC0, 0xDD, 0x41, 0xC8, 0x18, 0xDD, 0x4C, 0xCE, 0x09, 0x49, 0xFF, 0xD4, 0xF8, 0x44, 0x00, + 0x16, 0x15, 0xEB, 0x55, 0x44, 0x00, 0x11, 0xC2, 0xD5, 0x08, 0x49, 0xFF, 0xD4, 0xF0, 0x44, 0x00, + 0x29, 0xA4, 0xEB, 0x55, 0x44, 0x00, 0x25, 0x51, 0x49, 0xFF, 0xD4, 0xFC, 0x44, 0x00, 0x01, 0xCC, + 0x49, 0xFF, 0xD5, 0x01, 0x2E, 0x07, 0xEA, 0x51, 0xC8, 0x03, 0x80, 0x06, 0xEB, 0x79, 0xFC, 0x80, + 0xFC, 0x00, 0xC8, 0x03, 0x84, 0x07, 0xD5, 0x07, 0x9E, 0x42, 0xE6, 0x23, 0xE9, 0xFC, 0x5A, 0x08, + 0x05, 0x04, 0x84, 0x01, 0xEA, 0xC8, 0xFC, 0x80, 0xFC, 0x00, 0xE6, 0x06, 0xE8, 0x05, 0x44, 0x11, + 0x2A, 0xB0, 0xEB, 0xCE, 0xD5, 0x02, 0x84, 0x00, 0x8C, 0x01, 0x96, 0x00, 0x49, 0xFF, 0xD4, 0xED, + 0xFC, 0x80, 0xFC, 0x00, 0x80, 0xC0, 0xC0, 0x04, 0x5A, 0x00, 0x01, 0x0A, 0xFC, 0x80, 0x49, 0xFF, + 0xEA, 0x47, 0xEA, 0x3C, 0x49, 0xFF, 0xFF, 0xBD, 0x80, 0x06, 0xD5, 0x12, 0x49, 0xFF, 0xEA, 0x40, + 0xDD, 0x4C, 0x49, 0xFF, 0xD4, 0xB4, 0x44, 0x00, 0x29, 0x3F, 0xEB, 0x55, 0x44, 0x00, 0x24, 0xEC, + 0x49, 0xFF, 0xD4, 0xC0, 0x44, 0x00, 0x01, 0xCC, 0x49, 0xFF, 0xD4, 0xC5, 0x84, 0x00, 0xEA, 0xFA, + 0xFC, 0x80, 0xFC, 0x00, 0x84, 0x00, 0xEB, 0xF6, 0x84, 0x01, 0xEA, 0xD3, 0x84, 0x00, 0xEA, 0xD4, + 0xFC, 0x80, 0xFC, 0x00, 0x84, 0x01, 0xEB, 0xF6, 0x84, 0x00, 0xEA, 0xD3, 0x84, 0x00, 0xEA, 0xD4, + 0xFC, 0x80, 0xFC, 0x00, 0x84, 0x00, 0xEB, 0xF6, 0x84, 0x00, 0xEA, 0xD3, 0x84, 0x00, 0xEA, 0xD4, + 0xFC, 0x80, 0xFC, 0x00, 0x44, 0x01, 0x28, 0x20, 0x84, 0x20, 0xA6, 0xC7, 0xA6, 0x86, 0x44, 0x02, + 0x4C, 0xAC, 0xFE, 0x9C, 0xDD, 0x40, 0xEA, 0x57, 0x80, 0x60, 0x3E, 0x00, 0x12, 0xD4, 0x44, 0x12, + 0x3D, 0x2C, 0x44, 0x02, 0x42, 0x3C, 0x44, 0x20, 0x02, 0x88, 0x2E, 0x40, 0x03, 0x32, 0x49, 0xFF, + 0xEC, 0xDF, 0xFC, 0x80, 0x44, 0x02, 0x42, 0x3C, 0xDD, 0x9E, 0x44, 0x02, 0x3D, 0x2C, 0xDD, 0x9E, + 0xEB, 0xCC, 0xDD, 0x9E, 0x44, 0x02, 0x37, 0xAC, 0xDD, 0x9E, 0xFC, 0x20, 0xC8, 0x09, 0x84, 0x01, + 0x49, 0xFF, 0xD4, 0xD8, 0x84, 0x01, 0xEB, 0x68, 0x84, 0xC2, 0x84, 0xE1, 0xD5, 0x0B, 0x84, 0x00, + 0x49, 0xFF, 0xD4, 0xD0, 0x84, 0x03, 0xEB, 0x68, 0x84, 0x03, 0x49, 0xFF, 0xD4, 0xC0, 0x84, 0xC1, + 0x84, 0xE0, 0x80, 0x07, 0x49, 0xFF, 0xD4, 0x98, 0x5A, 0x78, 0x01, 0x09, 0x9E, 0x32, 0x96, 0x00, + 0x49, 0xFF, 0xD4, 0x9C, 0x80, 0x06, 0x49, 0xFF, 0xD4, 0xA4, 0xFC, 0xA0, 0xFC, 0x00, 0x84, 0x00, + 0x80, 0x20, 0xEA, 0xF4, 0x84, 0x00, 0x84, 0x21, 0xEA, 0xF4, 0xFC, 0x80, 0xFC, 0x00, 0x84, 0x01, + 0x84, 0x20, 0xEA, 0xF4, 0x84, 0x01, 0x80, 0x20, 0xEA, 0xF4, 0xFC, 0x80, 0xFC, 0x00, 0xEA, 0x57, + 0x52, 0x10, 0x00, 0x01, 0x96, 0x48, 0x84, 0x01, 0xEA, 0xF4, 0xFC, 0x80, 0xFC, 0x02, 0x80, 0xC0, + 0xC8, 0x04, 0xB0, 0x01, 0x80, 0x26, 0xD5, 0x2E, 0x5A, 0x08, 0x01, 0x16, 0xB0, 0x01, 0x84, 0x20, + 0x84, 0x4C, 0xDD, 0x40, 0x84, 0x03, 0xEA, 0xA0, 0xEB, 0x0F, 0x10, 0x6F, 0x80, 0x06, 0x10, 0x6F, + 0x80, 0x07, 0x10, 0x6F, 0x80, 0x08, 0x10, 0x6F, 0x80, 0x09, 0x10, 0x6F, 0x80, 0x0A, 0x10, 0x6F, + 0x80, 0x0B, 0xD5, 0x3B, 0x5A, 0x08, 0x02, 0x08, 0xB0, 0x01, 0x84, 0x20, 0x84, 0x4C, 0xDD, 0x40, + 0x84, 0x04, 0xD5, 0x13, 0x5A, 0x08, 0x04, 0x0B, 0xB0, 0x01, 0x84, 0x20, 0x84, 0x4C, 0xDD, 0x40, + 0x10, 0x6F, 0x80, 0x04, 0x10, 0x6F, 0x80, 0x05, 0xD5, 0x0A, 0x5A, 0x08, 0x06, 0x16, 0xB0, 0x01, + 0x84, 0x20, 0x84, 0x4C, 0xDD, 0x40, 0x84, 0x03, 0xEA, 0xA0, 0xEB, 0x0F, 0x84, 0x01, 0x10, 0x0F, + 0x80, 0x06, 0xEA, 0x8E, 0x10, 0x0F, 0x80, 0x08, 0x10, 0x0F, 0x80, 0x09, 0x10, 0x0F, 0x80, 0x0A, + 0x10, 0x0F, 0x80, 0x0B, 0xD5, 0x12, 0x5A, 0x08, 0x05, 0x08, 0xB0, 0x01, 0x84, 0x20, 0x84, 0x4C, + 0xDD, 0x40, 0x84, 0x04, 0xD5, 0x08, 0x5A, 0x08, 0x07, 0x0C, 0xB0, 0x01, 0x84, 0x20, 0x84, 0x4C, + 0xDD, 0x40, 0x84, 0x01, 0xEA, 0xA0, 0xEB, 0x0F, 0xB0, 0x01, 0x49, 0xFF, 0xD3, 0xA9, 0xFC, 0x82, + 0xDD, 0x9E, 0xFC, 0x00, 0x49, 0xFF, 0xD8, 0x22, 0xC0, 0x04, 0x49, 0xFF, 0xD8, 0x22, 0x84, 0x01, + 0xFC, 0x80, 0xFC, 0x00, 0x49, 0xFF, 0xD8, 0x0F, 0x80, 0xC0, 0xC8, 0x0C, 0xDD, 0x50, 0xC0, 0x05, + 0xDD, 0x58, 0x5A, 0x08, 0x02, 0x05, 0xD5, 0x06, 0xDD, 0x49, 0xC0, 0xFB, 0xDD, 0x51, 0x5A, 0x08, + 0x01, 0x04, 0xEB, 0xA7, 0x84, 0xC1, 0x80, 0x06, 0xFC, 0x80, 0xEA, 0x37, 0xC8, 0x13, 0xFC, 0x00, + 0xDD, 0x50, 0xC0, 0x05, 0xDD, 0x58, 0x5A, 0x08, 0x02, 0x05, 0xD5, 0x08, 0xDD, 0x49, 0xC0, 0xFB, + 0xDD, 0x51, 0x5A, 0x00, 0x01, 0x04, 0x84, 0x00, 0xFC, 0x80, 0x84, 0x00, 0xEA, 0x7B, 0x84, 0x01, + 0xFC, 0x80, 0x84, 0x00, 0xEA, 0x7B, 0x84, 0x01, 0xDD, 0x9E, 0xFC, 0x00, 0xEA, 0x95, 0xFC, 0x80, + 0xEA, 0x3C, 0xDD, 0x9E, 0x2E, 0x00, 0x03, 0x32, 0xDD, 0x9E, 0x2E, 0x00, 0x03, 0x31, 0xDD, 0x9E, + 0x2E, 0x00, 0x03, 0x30, 0xDD, 0x9E, 0x3E, 0x00, 0x03, 0x30, 0xDD, 0x9E, 0xFC, 0x00, 0x80, 0xC0, + 0x49, 0xFF, 0xD3, 0x19, 0x5A, 0x68, 0x01, 0x0B, 0x80, 0x06, 0x84, 0x20, 0xEA, 0xB3, 0x80, 0x06, + 0x84, 0x22, 0xEA, 0xB3, 0x80, 0x06, 0x80, 0x26, 0xD5, 0x0D, 0x84, 0x02, 0x84, 0x2A, 0x49, 0xFF, + 0xDF, 0x1F, 0x84, 0x01, 0x84, 0x20, 0xEA, 0xB3, 0x84, 0x01, 0x80, 0x20, 0xEA, 0xB3, 0x84, 0x00, + 0x84, 0x22, 0xEA, 0xB3, 0xFC, 0x80, 0xFC, 0x21, 0x84, 0xC2, 0xF0, 0x81, 0x80, 0xE2, 0x80, 0x01, + 0x5A, 0x10, 0x01, 0x03, 0x84, 0xC1, 0x49, 0xFF, 0xFF, 0xDB, 0xCF, 0x0B, 0x84, 0x03, 0xEB, 0x9A, + 0x84, 0x03, 0x49, 0xFF, 0xD9, 0x9C, 0xF0, 0x01, 0x80, 0x26, 0x49, 0xFF, 0xEB, 0x44, 0xFC, 0xA1, + 0x84, 0x02, 0xEB, 0x9A, 0x84, 0x02, 0x49, 0xFF, 0xD9, 0x92, 0xF0, 0x01, 0x80, 0x26, 0x84, 0x40, + 0x84, 0x62, 0x49, 0xFF, 0xEA, 0xC3, 0xFC, 0xA1, 0xFC, 0x00, 0x84, 0x07, 0xEA, 0xC8, 0x84, 0x00, + 0x84, 0x20, 0x3E, 0x00, 0x03, 0x32, 0x3E, 0x00, 0x03, 0x31, 0x80, 0x41, 0xEA, 0x3C, 0xDD, 0x5B, + 0xFC, 0x80, 0xFC, 0x21, 0xF0, 0x81, 0x80, 0xE2, 0x80, 0x01, 0x80, 0xC3, 0x49, 0xFF, 0xFF, 0xB0, + 0x5A, 0x78, 0x01, 0x12, 0x5A, 0x68, 0x02, 0x08, 0x80, 0x06, 0xEB, 0x9A, 0xF0, 0x01, 0x84, 0x20, + 0x80, 0x47, 0xD5, 0x06, 0x84, 0x02, 0xEB, 0x9A, 0xF0, 0x01, 0x80, 0x27, 0x84, 0x40, 0x80, 0x66, + 0x49, 0xFF, 0xEA, 0x9C, 0xFC, 0xA1, 0xFC, 0x00, 0x84, 0x00, 0xEB, 0xDB, 0xFA, 0xC2, 0xEB, 0xAC, + 0x49, 0xFF, 0xDF, 0x3B, 0xC0, 0x06, 0x8E, 0xC1, 0xC6, 0x04, 0x84, 0x01, 0xEA, 0xB4, 0xD5, 0xF9, + 0xEB, 0xAC, 0x84, 0x01, 0xEB, 0xDB, 0xFC, 0x80, 0xFC, 0x01, 0xF0, 0x81, 0x49, 0x00, 0x07, 0x36, + 0xF0, 0x01, 0x49, 0xFF, 0xD3, 0x4E, 0xFC, 0x81, 0xFC, 0x01, 0x5A, 0x08, 0x01, 0x08, 0xF0, 0x81, + 0xEA, 0x9A, 0xF0, 0x01, 0x49, 0xFF, 0xFF, 0xF2, 0xFC, 0x81, 0x84, 0x00, 0x49, 0xFF, 0xFF, 0xEE, + 0x84, 0x01, 0xEA, 0x2D, 0x49, 0xFF, 0xFF, 0xD9, 0xEA, 0x9A, 0xFC, 0x81, 0xFC, 0x00, 0x2E, 0x00, + 0x03, 0x2E, 0xC0, 0x08, 0x84, 0x01, 0xDD, 0x45, 0xEA, 0x38, 0x84, 0x00, 0x3E, 0x00, 0x03, 0x2E, + 0xFC, 0x80, 0xDD, 0x41, 0x5A, 0x00, 0x01, 0xF8, 0xEA, 0x9A, 0xEA, 0x38, 0xFC, 0x80, 0xFC, 0x00, + 0xEA, 0x40, 0x84, 0x00, 0xEB, 0xAD, 0xEA, 0x7B, 0x2E, 0x07, 0xF0, 0xDE, 0xC8, 0x0C, 0xDD, 0x50, + 0xC0, 0x05, 0xDD, 0x58, 0x5A, 0x08, 0x02, 0x05, 0xD5, 0x06, 0xDD, 0x49, 0xC0, 0xFB, 0xDD, 0x51, + 0x5A, 0x08, 0x01, 0xF4, 0xEA, 0x37, 0xC8, 0x0C, 0xDD, 0x50, 0xC0, 0x05, 0xDD, 0x58, 0x5A, 0x08, + 0x02, 0x05, 0xD5, 0x06, 0xDD, 0x49, 0xC0, 0xFB, 0xDD, 0x51, 0x5A, 0x08, 0x01, 0xF5, 0xEB, 0x04, + 0xFC, 0x80, 0xFC, 0x00, 0xEB, 0x04, 0x49, 0xFF, 0xDE, 0xE0, 0xC8, 0x03, 0xDD, 0x41, 0xC0, 0x04, + 0x84, 0x00, 0xDD, 0x45, 0x84, 0x01, 0x3E, 0x00, 0x03, 0x2E, 0xFC, 0x80, 0xFC, 0x01, 0x84, 0x00, + 0xEA, 0x8E, 0x84, 0x00, 0xEA, 0xEB, 0x84, 0x00, 0x49, 0xFF, 0xDD, 0x4E, 0x84, 0x20, 0x80, 0x61, + 0x84, 0x41, 0xEA, 0x3C, 0xEB, 0xC0, 0x49, 0xFF, 0xFF, 0xC4, 0x50, 0x1F, 0x80, 0x07, 0x84, 0x00, + 0x49, 0xFF, 0xFC, 0x2A, 0xEA, 0x4C, 0x84, 0x01, 0x49, 0xFF, 0xDD, 0x3E, 0x84, 0x20, 0x80, 0x41, + 0x84, 0x61, 0xEA, 0x3C, 0xEB, 0xC0, 0x49, 0xFF, 0xFF, 0xB4, 0x84, 0x01, 0x50, 0x1F, 0x80, 0x07, + 0x49, 0xFF, 0xFC, 0x1A, 0xEA, 0x4C, 0x84, 0x01, 0xEA, 0xEB, 0xDD, 0x50, 0xC0, 0x05, 0xDD, 0x58, + 0x5A, 0x08, 0x02, 0x05, 0xD5, 0x06, 0xDD, 0x49, 0xC0, 0xFB, 0xDD, 0x51, 0x5A, 0x08, 0x01, 0x06, + 0x84, 0x01, 0xEB, 0x38, 0x84, 0x00, 0xFC, 0x81, 0x84, 0x00, 0xEB, 0x38, 0xEB, 0x0E, 0xFC, 0x81, + 0xFC, 0x09, 0x84, 0x20, 0x84, 0x41, 0x84, 0x62, 0xEA, 0x3C, 0xEB, 0xC0, 0x84, 0x04, 0xEA, 0x4A, + 0x84, 0x00, 0x49, 0xFF, 0xFB, 0x68, 0x84, 0xC6, 0x49, 0xFF, 0xFA, 0xCF, 0x49, 0xFF, 0xFF, 0xB8, + 0x5A, 0x08, 0x01, 0x05, 0x8E, 0xC1, 0x97, 0xB0, 0xCE, 0xFA, 0xEA, 0x9E, 0x5A, 0x00, 0x01, 0x3D, + 0x84, 0x00, 0xEA, 0x4A, 0x84, 0x20, 0xEA, 0xA7, 0xB0, 0x06, 0xDD, 0x40, 0xEB, 0x35, 0xEA, 0xC7, + 0xF0, 0x86, 0xEB, 0x7B, 0xF1, 0x89, 0xF0, 0x87, 0xEA, 0xFD, 0xEB, 0x0C, 0xF1, 0x8A, 0x94, 0x46, + 0xF0, 0x88, 0xF1, 0x8B, 0xDD, 0x56, 0xEA, 0x21, 0xF1, 0x8C, 0xF0, 0x8D, 0x84, 0x20, 0xFA, 0x48, + 0x80, 0x1F, 0xDD, 0x40, 0x84, 0x01, 0x84, 0x82, 0x84, 0x63, 0x84, 0x44, 0x84, 0x25, 0x10, 0x0F, + 0x80, 0x01, 0x10, 0x0F, 0x80, 0x03, 0x10, 0x0F, 0x80, 0x0D, 0x10, 0x0F, 0x80, 0x0F, 0x80, 0x1F, + 0x10, 0x4F, 0x80, 0x04, 0x10, 0x3F, 0x80, 0x05, 0x10, 0x2F, 0x80, 0x06, 0x10, 0x1F, 0x80, 0x07, + 0x10, 0x4F, 0x80, 0x10, 0x10, 0x3F, 0x80, 0x11, 0x10, 0x2F, 0x80, 0x12, 0x10, 0x1F, 0x80, 0x13, + 0xEA, 0xD2, 0xB0, 0x06, 0xEA, 0xC1, 0xFC, 0x89, 0xFC, 0x00, 0xEA, 0x4C, 0x84, 0x00, 0xEA, 0x42, + 0x84, 0x00, 0xEA, 0x63, 0xEA, 0xCA, 0xEB, 0x82, 0xEA, 0x40, 0xEA, 0x37, 0xC0, 0x0A, 0xEA, 0x9A, + 0xEA, 0x4C, 0xEB, 0xCC, 0xEA, 0x63, 0x84, 0x40, 0x49, 0xFF, 0xEA, 0xB8, 0xEA, 0xE2, 0xFC, 0x80, + 0xDD, 0x50, 0xC0, 0x05, 0xDD, 0x58, 0x5A, 0x08, 0x02, 0x05, 0xD5, 0xF2, 0xDD, 0x49, 0xC0, 0xFB, + 0xDD, 0x51, 0x5A, 0x08, 0x01, 0xEC, 0xD5, 0xEC, 0xFC, 0x42, 0x84, 0x00, 0xF0, 0x83, 0xEA, 0xE2, + 0xDD, 0x41, 0x80, 0xE0, 0xC8, 0x65, 0xEA, 0x40, 0x81, 0x27, 0x85, 0x49, 0xEA, 0x37, 0xC8, 0x0C, + 0xDD, 0x50, 0xC0, 0x05, 0xDD, 0x58, 0x5A, 0x08, 0x02, 0x05, 0xD5, 0x06, 0xDD, 0x49, 0xC0, 0xFB, + 0xDD, 0x51, 0x5A, 0x08, 0x01, 0xF5, 0xEA, 0x9A, 0xEA, 0x57, 0xF0, 0x81, 0x2E, 0x00, 0x03, 0x32, + 0xEA, 0x52, 0x80, 0xC0, 0xF0, 0x01, 0xEA, 0x83, 0xF0, 0x83, 0xF1, 0x03, 0x50, 0x30, 0x85, 0x10, + 0x80, 0xA1, 0x9A, 0xB1, 0x38, 0x01, 0x14, 0x11, 0x2A, 0xF2, 0x80, 0x01, 0x8A, 0x0F, 0x4E, 0x04, + 0x00, 0x03, 0xFE, 0x02, 0x96, 0x03, 0x5E, 0xF0, 0x00, 0x47, 0xE8, 0x04, 0xDB, 0xF4, 0xEA, 0x4C, + 0xFC, 0xC2, 0xEA, 0x7C, 0xEA, 0x82, 0x5A, 0x98, 0x04, 0x22, 0x49, 0x00, 0x06, 0x8B, 0x84, 0x01, + 0x3E, 0x07, 0xED, 0xA6, 0xEA, 0x95, 0xC8, 0x0E, 0xEA, 0x4C, 0x80, 0x09, 0xEA, 0x30, 0x84, 0x01, + 0xEA, 0x20, 0x84, 0x01, 0xEB, 0x94, 0xEB, 0x0D, 0xDD, 0x5B, 0x49, 0xFF, 0xC5, 0x91, 0xEA, 0x40, + 0xD5, 0x03, 0x49, 0xFF, 0xEF, 0x47, 0x8C, 0xE1, 0x97, 0xF8, 0xE6, 0xE2, 0xE8, 0x02, 0x85, 0x20, + 0x84, 0x00, 0x49, 0xFF, 0xFF, 0x8B, 0xEA, 0x40, 0xD5, 0x10, 0x50, 0x33, 0x05, 0x10, 0x80, 0xA6, + 0x8A, 0x26, 0x84, 0x4A, 0x22, 0x42, 0x80, 0x00, 0x38, 0x00, 0x94, 0x11, 0x42, 0x02, 0x28, 0x73, + 0xEA, 0xA6, 0x1A, 0x02, 0x80, 0x01, 0xDB, 0xF7, 0xE7, 0x24, 0xE9, 0xA1, 0xD5, 0xC9, 0xFC, 0xC2, + 0xFC, 0x21, 0x84, 0x00, 0xDD, 0x45, 0x49, 0xFF, 0xD5, 0xB5, 0xF0, 0x81, 0x84, 0x00, 0xEA, 0x42, + 0x44, 0x10, 0x00, 0xD8, 0x84, 0x00, 0x49, 0xFF, 0xDF, 0x78, 0xEB, 0x82, 0x84, 0x01, 0xEA, 0xC8, + 0x84, 0x05, 0xEA, 0xFA, 0x84, 0x05, 0xEA, 0x4A, 0x49, 0xFF, 0xFC, 0x53, 0x84, 0x01, 0xDD, 0x45, + 0x84, 0xC2, 0xEA, 0x38, 0x84, 0xE0, 0xEA, 0x47, 0x96, 0x00, 0xC0, 0x11, 0x84, 0x00, 0xDD, 0x45, + 0x84, 0x07, 0xEA, 0xC8, 0x84, 0x00, 0xEA, 0xFA, 0x84, 0x00, 0xEA, 0x4A, 0xEB, 0x46, 0x49, 0xFF, + 0xFC, 0xEA, 0xF0, 0x01, 0xEA, 0x42, 0x84, 0x01, 0xDD, 0x45, 0xFC, 0xA1, 0xEB, 0xAD, 0x2E, 0x07, + 0xF0, 0xDE, 0xC8, 0x0C, 0xDD, 0x50, 0xC0, 0x05, 0xDD, 0x58, 0x5A, 0x08, 0x02, 0x05, 0xD5, 0x06, + 0xDD, 0x49, 0xC0, 0xFB, 0xDD, 0x51, 0x5A, 0x08, 0x01, 0xF4, 0x3E, 0x77, 0xF0, 0xDD, 0xEA, 0x37, + 0xC8, 0x0C, 0xDD, 0x50, 0xC0, 0x05, 0xDD, 0x58, 0x5A, 0x08, 0x02, 0x05, 0xD5, 0x06, 0xDD, 0x49, + 0xC0, 0xFB, 0xDD, 0x51, 0x5A, 0x08, 0x01, 0xF5, 0x5A, 0x60, 0x01, 0xD2, 0x84, 0xC1, 0xD5, 0xCC, + 0x2E, 0x07, 0xEB, 0xCC, 0x5A, 0x08, 0x01, 0x08, 0xFC, 0x00, 0x49, 0xFF, 0xFF, 0xAB, 0x84, 0x00, + 0xEB, 0x45, 0xFC, 0x80, 0xDD, 0x9E, 0xFC, 0x01, 0xEA, 0x81, 0xF0, 0x81, 0xDD, 0x41, 0x80, 0xC0, + 0xC8, 0x1F, 0x84, 0x04, 0xEA, 0x30, 0x84, 0x01, 0xEA, 0x20, 0xEB, 0x0D, 0xEB, 0x94, 0x84, 0x01, + 0xDD, 0x5B, 0x80, 0x06, 0xEA, 0x42, 0x80, 0x06, 0xEA, 0x63, 0xEA, 0xCA, 0xEB, 0x82, 0x84, 0x01, + 0xDD, 0x45, 0xEA, 0x37, 0xC8, 0x26, 0xDD, 0x50, 0xC0, 0x05, 0xDD, 0x58, 0x5A, 0x08, 0x02, 0x05, + 0xD5, 0x20, 0xDD, 0x49, 0xC0, 0xFB, 0xDD, 0x51, 0x5A, 0x08, 0x01, 0xF5, 0xD5, 0x1A, 0x84, 0xC2, + 0x84, 0x00, 0xEA, 0x52, 0xF0, 0x81, 0x84, 0x00, 0xEA, 0x42, 0x84, 0x00, 0xEA, 0x63, 0xEA, 0xCA, + 0xEB, 0x82, 0xEA, 0x40, 0xEA, 0x37, 0xC8, 0x48, 0xDD, 0x50, 0xC0, 0x05, 0xDD, 0x58, 0x5A, 0x08, + 0x02, 0x05, 0xD5, 0x42, 0xDD, 0x49, 0xC0, 0xFB, 0xDD, 0x51, 0x5A, 0x08, 0x01, 0xF5, 0xD5, 0x3C, + 0xEA, 0x4C, 0xEA, 0x63, 0x84, 0x40, 0xEB, 0xCC, 0x49, 0xFF, 0xE9, 0xA0, 0xF0, 0x01, 0xEA, 0x30, + 0x84, 0x00, 0xEA, 0x20, 0xEB, 0x0D, 0xEB, 0x94, 0x84, 0x00, 0xDD, 0x5B, 0x84, 0x00, 0xEA, 0x42, + 0x84, 0x00, 0xEA, 0x63, 0xEA, 0xCA, 0xEA, 0x40, 0xEB, 0xA7, 0x84, 0x00, 0xEA, 0x7B, 0xEA, 0x37, + 0xC8, 0x0C, 0xDD, 0x50, 0xC0, 0x05, 0xDD, 0x58, 0x5A, 0x08, 0x02, 0x05, 0xD5, 0x06, 0xDD, 0x49, + 0xC0, 0xFB, 0xDD, 0x51, 0x5A, 0x08, 0x01, 0xF5, 0xEA, 0x4C, 0x84, 0x01, 0xEA, 0x42, 0x84, 0x01, + 0xEA, 0x63, 0xEA, 0xCA, 0xEA, 0x40, 0xEA, 0x37, 0xC8, 0x0C, 0xDD, 0x50, 0xC0, 0x05, 0xDD, 0x58, + 0x5A, 0x08, 0x02, 0x05, 0xD5, 0x06, 0xDD, 0x49, 0xC0, 0xFB, 0xDD, 0x51, 0x5A, 0x08, 0x01, 0xF5, + 0xEA, 0x4C, 0xEA, 0xE2, 0xFC, 0x81, 0xEA, 0x9A, 0xEA, 0x4C, 0xF0, 0x01, 0xEA, 0x63, 0x84, 0x40, + 0x49, 0xFF, 0xE9, 0x64, 0xEA, 0xE2, 0x5A, 0x60, 0x01, 0x05, 0x84, 0xC1, 0x48, 0xFF, 0xFF, 0xA2, + 0xFC, 0x81, 0xFC, 0x00, 0x49, 0xFF, 0xFF, 0x79, 0xEA, 0x40, 0xFC, 0x80, 0xFC, 0x00, 0xEA, 0x3C, + 0xEA, 0x20, 0x84, 0x07, 0xEA, 0xC8, 0xEA, 0x3C, 0x84, 0x20, 0xEB, 0x0D, 0xDD, 0x5B, 0x84, 0x00, + 0x49, 0xFF, 0xFF, 0x6B, 0xDD, 0x50, 0xC0, 0x05, 0xDD, 0x58, 0x5A, 0x08, 0x02, 0x05, 0xD5, 0x06, + 0xDD, 0x49, 0xC0, 0xFB, 0xDD, 0x51, 0x5A, 0x08, 0x01, 0x05, 0x84, 0x01, 0xEB, 0x38, 0xFC, 0x80, + 0x84, 0x00, 0xEB, 0x38, 0x49, 0xFF, 0xFE, 0x92, 0xEB, 0x94, 0xEB, 0x0D, 0xEA, 0x3C, 0xDD, 0x5B, + 0xEA, 0x3C, 0xEA, 0x20, 0xEA, 0xE2, 0xEA, 0x40, 0xFC, 0x80, 0xFC, 0x00, 0x80, 0xC0, 0x3E, 0x00, + 0x03, 0x33, 0x49, 0xFF, 0xFC, 0x2C, 0x80, 0x06, 0x49, 0xFF, 0xFB, 0x93, 0xFC, 0x80, 0xFC, 0x01, + 0x84, 0x00, 0xEA, 0x4A, 0x84, 0x01, 0x49, 0xFF, 0xD0, 0x7F, 0x84, 0x00, 0x49, 0xFF, 0xD4, 0xA9, + 0x84, 0x00, 0x49, 0xFF, 0xD4, 0x76, 0x84, 0x00, 0xEA, 0x42, 0x84, 0x00, 0x49, 0xFF, 0xDF, 0xA9, + 0xEA, 0x9C, 0x49, 0xFF, 0xDE, 0xC2, 0x49, 0xFF, 0xFB, 0x0A, 0xEB, 0x46, 0x49, 0xFF, 0xFB, 0x6F, + 0x44, 0x02, 0x86, 0x80, 0x49, 0xFF, 0xDE, 0x5E, 0x44, 0x02, 0x8D, 0x40, 0x49, 0xFF, 0xDE, 0x64, + 0x44, 0x02, 0x79, 0x00, 0x49, 0xFF, 0xDE, 0x85, 0x44, 0x02, 0x7F, 0xC0, 0x49, 0xFF, 0xDE, 0x8B, + 0x84, 0x00, 0x49, 0xFF, 0xDE, 0x63, 0xEA, 0x9C, 0x49, 0xFF, 0xDE, 0x69, 0xEA, 0x9C, 0x49, 0xFF, + 0xDE, 0x6F, 0x84, 0x00, 0x49, 0xFF, 0xDE, 0x89, 0xEA, 0x9C, 0x49, 0xFF, 0xDE, 0x92, 0x84, 0x06, + 0x49, 0xFF, 0xDE, 0xA7, 0x84, 0x02, 0x49, 0xFF, 0xDE, 0xAD, 0x84, 0x04, 0x49, 0xFF, 0xE3, 0x3D, + 0xEA, 0x59, 0x84, 0x00, 0xEA, 0x68, 0xEB, 0x67, 0x49, 0xFF, 0xE9, 0x25, 0xF0, 0x81, 0xF1, 0x01, + 0x84, 0x00, 0xEA, 0xAC, 0xEA, 0x59, 0x84, 0x02, 0xEA, 0x68, 0xEB, 0x67, 0x49, 0xFF, 0xE9, 0x1B, + 0xF0, 0x81, 0xF1, 0x01, 0x84, 0x02, 0xEA, 0xAC, 0xEA, 0x59, 0x84, 0x04, 0xEA, 0x68, 0xEB, 0x67, + 0x49, 0xFF, 0xE9, 0x11, 0xF0, 0x81, 0xF1, 0x01, 0x84, 0x04, 0xEA, 0xAC, 0x2E, 0x17, 0xD8, 0xE6, + 0x2E, 0x27, 0xD8, 0xE7, 0x2E, 0x37, 0xD8, 0xE8, 0x2E, 0x47, 0xD8, 0xE9, 0x3C, 0x03, 0xEC, 0x5C, + 0x49, 0xFF, 0xCF, 0x51, 0x44, 0x00, 0x01, 0x02, 0x49, 0xFF, 0xDB, 0x69, 0x84, 0x00, 0x49, 0xFF, + 0xDB, 0x75, 0x84, 0x00, 0x49, 0xFF, 0xFF, 0x83, 0xEA, 0x95, 0x3E, 0x00, 0x03, 0x33, 0x84, 0x01, + 0x49, 0xFF, 0xD0, 0xA1, 0xEA, 0xB0, 0xE6, 0x05, 0xE9, 0x0D, 0x44, 0x14, 0x00, 0xD4, 0xB4, 0x01, + 0x58, 0x00, 0x00, 0x03, 0xB6, 0x01, 0x44, 0x14, 0x00, 0xD8, 0x84, 0x1E, 0xB4, 0x41, 0xFE, 0x16, + 0xB6, 0x01, 0xFC, 0x81, 0x46, 0x00, 0x00, 0x82, 0x44, 0x1F, 0xF8, 0xFF, 0xA0, 0x85, 0xFE, 0x56, + 0x58, 0x10, 0x84, 0x00, 0xA8, 0x45, 0xA0, 0x42, 0x46, 0x20, 0x10, 0x00, 0xFE, 0x57, 0xA8, 0x42, + 0xA0, 0xC2, 0x46, 0x1F, 0xDF, 0xFF, 0xEA, 0x2B, 0xFE, 0x5E, 0xA8, 0x42, 0x04, 0x30, 0x00, 0x2A, + 0x44, 0x1F, 0xFE, 0xFF, 0xFE, 0x5E, 0x14, 0x10, 0x00, 0x2A, 0xB4, 0x20, 0xFE, 0x8F, 0xB6, 0x40, + 0xB4, 0x20, 0x92, 0x38, 0x96, 0x46, 0xC9, 0xFD, 0xFC, 0x00, 0x44, 0x14, 0x2C, 0x00, 0x46, 0x0B, + 0xFF, 0xFF, 0xB4, 0x41, 0xDD, 0x42, 0xFE, 0x16, 0xB6, 0x01, 0xB4, 0x41, 0x46, 0x08, 0x00, 0x00, + 0xFE, 0x17, 0x84, 0x41, 0xB6, 0x01, 0x80, 0x62, 0x44, 0x04, 0x28, 0x00, 0x44, 0x14, 0x24, 0x00, + 0xDD, 0x44, 0x44, 0x04, 0x2C, 0x04, 0x84, 0x3E, 0xB4, 0x40, 0xFE, 0x56, 0xB6, 0x20, 0xB4, 0x20, + 0x84, 0x41, 0x58, 0x10, 0x80, 0x02, 0xB6, 0x20, 0x80, 0x62, 0x44, 0x04, 0x28, 0x04, 0x44, 0x14, + 0x24, 0x04, 0xDD, 0x44, 0xFC, 0x80, 0xFC, 0x00, 0x49, 0xFF, 0xE0, 0xB6, 0xFC, 0x80, 0xFC, 0x00, + 0xEB, 0x99, 0xFC, 0x80, 0xFC, 0x00, 0x49, 0xFF, 0xCF, 0x21, 0x49, 0xFF, 0xD2, 0xD0, 0x84, 0x01, + 0x49, 0xFF, 0xDF, 0x18, 0x49, 0xFF, 0xDE, 0xC6, 0x84, 0x01, 0x49, 0xFF, 0xDF, 0x13, 0x49, 0xFF, + 0xDF, 0x23, 0x46, 0x00, 0x03, 0x33, 0x50, 0x00, 0x03, 0x33, 0x49, 0xFF, 0xDF, 0x64, 0x49, 0xFF, + 0xDF, 0x1C, 0x84, 0x0A, 0x49, 0xFF, 0xDF, 0x1F, 0x84, 0x00, 0x49, 0xFF, 0xD4, 0x3E, 0x84, 0x02, + 0x49, 0xFF, 0xD8, 0x54, 0xEA, 0x3B, 0x5A, 0x08, 0x1F, 0x07, 0x84, 0x00, 0x49, 0xFF, 0xCE, 0x9C, + 0x84, 0x04, 0xD5, 0x05, 0x84, 0x00, 0x49, 0xFF, 0xCE, 0x97, 0x84, 0x00, 0x49, 0xFF, 0xCE, 0x9D, + 0x84, 0x41, 0x44, 0x14, 0x24, 0x14, 0x80, 0x62, 0x44, 0x04, 0x28, 0x14, 0xDD, 0x44, 0x49, 0xFF, + 0xDF, 0x0B, 0x84, 0x00, 0x49, 0xFF, 0xDF, 0x3E, 0xEA, 0xB2, 0xFA, 0x30, 0xAE, 0x40, 0x84, 0x01, + 0x49, 0xFF, 0xE0, 0x5F, 0xFC, 0x80, 0xFC, 0x00, 0x84, 0x00, 0x49, 0xFF, 0xD0, 0x20, 0x84, 0x02, + 0x49, 0xFF, 0xD0, 0x30, 0x84, 0x00, 0x49, 0xFF, 0xD0, 0x3C, 0x84, 0x02, 0x49, 0xFF, 0xD0, 0x4B, + 0x84, 0x00, 0x49, 0xFF, 0xD0, 0x55, 0x84, 0x01, 0x49, 0xFF, 0xD0, 0x72, 0x84, 0x01, 0x49, 0xFF, + 0xD0, 0x84, 0xFC, 0x80, 0xFC, 0x00, 0x84, 0x00, 0xEA, 0x59, 0xEA, 0x68, 0x84, 0x02, 0xEA, 0x59, + 0xEA, 0x68, 0x84, 0x01, 0xEA, 0x59, 0xEA, 0x68, 0x84, 0x03, 0xEA, 0x59, 0xEA, 0x68, 0xEA, 0x59, + 0x84, 0x04, 0xEA, 0x68, 0x84, 0x01, 0x49, 0xFF, 0xCE, 0x25, 0x84, 0x02, 0x84, 0x2A, 0x49, 0xFF, + 0xDA, 0xE7, 0x84, 0x00, 0x84, 0x22, 0xEA, 0xB3, 0x84, 0x00, 0x84, 0x22, 0x49, 0xFF, 0xDB, 0x25, + 0x84, 0x01, 0x84, 0x22, 0x49, 0xFF, 0xDB, 0x21, 0x84, 0x02, 0x80, 0x20, 0x49, 0xFF, 0xDB, 0x1D, + 0xFC, 0x80, 0xFC, 0x00, 0x80, 0xC0, 0x49, 0xFF, 0xDE, 0x08, 0x5A, 0x68, 0x01, 0x05, 0x84, 0x00, + 0x80, 0x20, 0xD5, 0x03, 0x84, 0x01, 0x84, 0x20, 0xEB, 0x18, 0xFC, 0x80, 0xFC, 0x00, 0x49, 0xFF, + 0xDE, 0xF1, 0xFC, 0x80, 0xFC, 0x01, 0x80, 0xC0, 0xF1, 0x81, 0xEB, 0x99, 0xC6, 0x0C, 0x54, 0x33, + 0x00, 0xFD, 0x5A, 0x38, 0x01, 0x09, 0x84, 0x05, 0xFA, 0x2F, 0x44, 0x20, 0x00, 0x69, 0xF4, 0x01, + 0x80, 0xA3, 0xDD, 0x5D, 0xFC, 0x81, 0xFC, 0x00, 0x5A, 0x10, 0x02, 0x04, 0xC9, 0x04, 0x84, 0x03, + 0x49, 0xFF, 0xDF, 0x0C, 0x84, 0x46, 0x44, 0x04, 0x58, 0x90, 0x44, 0x14, 0x55, 0x10, 0x80, 0x62, + 0xDD, 0x44, 0xFC, 0x80, 0xFC, 0x00, 0x84, 0x01, 0x49, 0xFF, 0xD3, 0xE0, 0x84, 0x01, 0x49, 0xFF, + 0xCE, 0x80, 0xFA, 0x22, 0x84, 0x01, 0xEB, 0xC3, 0x84, 0x00, 0x49, 0xFF, 0xFA, 0x34, 0x84, 0x00, + 0xEA, 0x96, 0x84, 0x01, 0xEA, 0xEB, 0x84, 0x01, 0x49, 0xFF, 0xD9, 0x86, 0x84, 0x01, 0x49, 0xFF, + 0xD1, 0x54, 0x84, 0x01, 0x49, 0xFF, 0xD9, 0x99, 0x84, 0x00, 0x80, 0x20, 0x49, 0xFF, 0xE7, 0xE6, + 0x84, 0x01, 0x49, 0xFF, 0xD2, 0x9D, 0x84, 0x01, 0x49, 0xFF, 0xD2, 0xA9, 0x84, 0x01, 0x49, 0xFF, + 0xD2, 0xBB, 0x49, 0xFF, 0xD2, 0x15, 0x84, 0x41, 0x44, 0x10, 0x00, 0x69, 0x84, 0x05, 0xEB, 0x13, + 0xEB, 0x99, 0x84, 0x00, 0x84, 0x22, 0xEA, 0xAB, 0x84, 0x00, 0x49, 0xFF, 0xDF, 0xEC, 0xEA, 0x3B, + 0x5A, 0x08, 0x1F, 0x0E, 0xEA, 0xB0, 0xE6, 0x02, 0xE9, 0x0A, 0x84, 0x01, 0x49, 0xFF, 0xDF, 0xF0, + 0x84, 0x01, 0x49, 0xFF, 0xDF, 0xF9, 0x84, 0x00, 0x49, 0xFF, 0xE0, 0x02, 0xFC, 0x80, 0xFC, 0x42, + 0x44, 0x62, 0x0C, 0xE4, 0x49, 0xFF, 0xE0, 0x17, 0x44, 0x11, 0x28, 0x20, 0x02, 0x23, 0x00, 0x12, + 0xA6, 0x0E, 0xA6, 0x4F, 0x49, 0xFF, 0xE0, 0x35, 0x00, 0x03, 0x00, 0xC5, 0x49, 0xFF, 0xE1, 0x88, + 0x00, 0x03, 0x00, 0x27, 0x00, 0x13, 0x00, 0x26, 0x00, 0x23, 0x00, 0x2E, 0x49, 0xFF, 0xE0, 0xCA, + 0x22, 0x93, 0x00, 0x0E, 0x22, 0x43, 0x00, 0x0C, 0x22, 0x53, 0x00, 0x0D, 0xB7, 0x3F, 0x22, 0x93, + 0x00, 0x0F, 0x44, 0x72, 0x07, 0x00, 0x14, 0x9F, 0x80, 0x01, 0x22, 0x93, 0x00, 0x10, 0x22, 0x03, + 0x80, 0xD0, 0x14, 0x9F, 0x80, 0x02, 0x22, 0x63, 0x00, 0x11, 0x22, 0x13, 0x80, 0xCF, 0x22, 0x23, + 0x80, 0xD2, 0x22, 0x33, 0x80, 0xD1, 0xF6, 0x83, 0x49, 0xFF, 0xE0, 0x7B, 0x84, 0x00, 0x49, 0xFF, + 0xDF, 0xD3, 0x02, 0x03, 0x80, 0xD0, 0x3C, 0x08, 0x09, 0x6F, 0x44, 0x00, 0x01, 0xF4, 0x3C, 0x08, + 0x09, 0x6E, 0xFC, 0xC2, 0xFC, 0x00, 0xDD, 0x41, 0x5A, 0x08, 0x01, 0x26, 0xDD, 0x45, 0x84, 0x00, + 0xEB, 0xAD, 0x2E, 0x07, 0xF0, 0xDE, 0xC8, 0x0C, 0xDD, 0x50, 0xC0, 0x05, 0xDD, 0x58, 0x5A, 0x08, + 0x02, 0x05, 0xD5, 0x06, 0xDD, 0x49, 0xC0, 0xFB, 0xDD, 0x51, 0x5A, 0x08, 0x01, 0xF4, 0x84, 0x00, + 0xEA, 0x7B, 0xEA, 0x37, 0xC8, 0x0C, 0xDD, 0x50, 0xC0, 0x05, 0xDD, 0x58, 0x5A, 0x08, 0x02, 0x05, + 0xD5, 0x06, 0xDD, 0x49, 0xC0, 0xFB, 0xDD, 0x51, 0x5A, 0x08, 0x01, 0xF5, 0x84, 0x00, 0xEA, 0x7B, + 0x84, 0x00, 0xDD, 0x45, 0x84, 0x00, 0xEB, 0x68, 0xFC, 0x80, 0x3C, 0x13, 0xEC, 0x48, 0x94, 0x49, + 0x88, 0x20, 0x4C, 0x00, 0x80, 0x09, 0x2A, 0xF0, 0x00, 0x01, 0x5E, 0xF7, 0xFF, 0xB0, 0xE8, 0xFA, + 0x84, 0x01, 0xDD, 0x9E, 0x84, 0x00, 0xDD, 0x9E, 0xFC, 0x21, 0x84, 0x20, 0x80, 0xC0, 0x84, 0x48, + 0x80, 0x1F, 0xDD, 0x40, 0x80, 0xA6, 0x84, 0x80, 0x84, 0x40, 0x80, 0x22, 0x94, 0x0A, 0x88, 0x04, + 0x38, 0xF2, 0x8B, 0x11, 0x38, 0x03, 0x01, 0x11, 0x96, 0xD0, 0xE0, 0x0F, 0x8C, 0x41, 0x40, 0x11, + 0xBC, 0x1B, 0x5A, 0x28, 0x36, 0xF5, 0x84, 0x60, 0x80, 0x43, 0x94, 0x12, 0x88, 0x04, 0x38, 0xF2, + 0x8F, 0x11, 0x38, 0x03, 0x01, 0x11, 0x97, 0xD8, 0xE0, 0x0F, 0xE8, 0x04, 0x4C, 0x70, 0x80, 0x03, + 0x80, 0x47, 0x8C, 0x61, 0x5A, 0x38, 0x36, 0xF3, 0x94, 0x92, 0x94, 0x4A, 0x88, 0x44, 0x88, 0x24, + 0x38, 0x23, 0x09, 0x01, 0x38, 0x03, 0x05, 0x01, 0x8C, 0xA2, 0x88, 0x02, 0x38, 0x0F, 0x91, 0x09, + 0x8C, 0x81, 0x5A, 0x48, 0x04, 0xD3, 0x3C, 0x24, 0x09, 0x6F, 0x84, 0x20, 0x84, 0x61, 0x40, 0x0F, + 0x84, 0x00, 0x22, 0x40, 0x00, 0x01, 0x38, 0x0F, 0x84, 0x11, 0x88, 0x04, 0x4E, 0x04, 0x00, 0x03, + 0xFE, 0x02, 0xE0, 0x40, 0xE8, 0x06, 0x84, 0x00, 0x3E, 0x00, 0x12, 0xD9, 0x84, 0x01, 0xFC, 0xA1, + 0x5E, 0xF0, 0x00, 0x29, 0xE9, 0x03, 0x3E, 0x30, 0x12, 0xD9, 0x8C, 0x22, 0x5A, 0x18, 0x06, 0xE9, + 0x84, 0x00, 0xFC, 0xA1, 0xFC, 0x20, 0x84, 0x40, 0x84, 0xE9, 0x84, 0xCA, 0x3C, 0x33, 0xEC, 0x48, + 0xE2, 0x43, 0xE8, 0x11, 0x95, 0x51, 0x88, 0xA0, 0x22, 0x32, 0x80, 0x00, 0xFE, 0xFC, 0x40, 0x41, + 0x98, 0x96, 0x38, 0x30, 0x89, 0x11, 0x8C, 0x41, 0x40, 0x31, 0x98, 0x76, 0x88, 0x64, 0xAC, 0xE8, + 0x96, 0x91, 0xD5, 0xED, 0xFC, 0xA0, 0xFC, 0x01, 0x2E, 0x00, 0x12, 0xD9, 0xB6, 0x3F, 0x96, 0x00, + 0xF2, 0x81, 0xC0, 0x0B, 0x84, 0x01, 0x3E, 0x00, 0x12, 0xD8, 0x2E, 0x00, 0x12, 0xD7, 0x5A, 0x00, + 0xFF, 0x07, 0x8C, 0x01, 0xEB, 0xB9, 0xD5, 0x03, 0x3E, 0x00, 0x12, 0xD8, 0x2E, 0x00, 0x12, 0xD8, + 0xC0, 0x04, 0x5A, 0x00, 0x01, 0x05, 0xFC, 0x81, 0xEB, 0xB9, 0xD5, 0x06, 0x2E, 0x00, 0x12, 0xD7, + 0x5C, 0xF0, 0x00, 0xC9, 0xE9, 0x05, 0xB4, 0x1F, 0xF1, 0x01, 0x49, 0xFF, 0xFF, 0xC5, 0xFC, 0x81, + 0xFC, 0x41, 0x84, 0x00, 0xEA, 0x83, 0x80, 0xE0, 0x50, 0x90, 0x05, 0x10, 0x84, 0x00, 0xEA, 0x52, + 0x81, 0x40, 0xEB, 0x6B, 0xF0, 0x81, 0x84, 0x01, 0xEB, 0xDB, 0x84, 0xC0, 0xEB, 0x4A, 0x44, 0x82, + 0x47, 0x58, 0x49, 0x00, 0x02, 0x4F, 0xEB, 0xAC, 0xDD, 0x41, 0x5A, 0x08, 0x01, 0x06, 0xEB, 0xCA, + 0xEA, 0x43, 0x84, 0x22, 0xAE, 0x40, 0x49, 0xFF, 0xDB, 0x45, 0x5A, 0x00, 0x01, 0xFE, 0xEB, 0x96, + 0x5A, 0x00, 0x01, 0x05, 0xEB, 0x77, 0x96, 0x00, 0xC0, 0x05, 0x84, 0x01, 0x3E, 0x00, 0x12, 0xDB, + 0xD5, 0x4A, 0x64, 0x00, 0x00, 0x40, 0x49, 0xFF, 0xCD, 0xBC, 0xDD, 0x50, 0x96, 0x00, 0xC8, 0x42, + 0xEB, 0x40, 0x49, 0xFF, 0xDF, 0xDF, 0xEB, 0x77, 0x5A, 0x00, 0x01, 0x3D, 0xEA, 0x99, 0x96, 0x00, + 0xC8, 0x39, 0x3C, 0x33, 0xEC, 0x48, 0x80, 0x29, 0x40, 0x45, 0x1C, 0x01, 0x96, 0x81, 0xE2, 0x43, + 0xE8, 0x0A, 0x38, 0x22, 0x04, 0x01, 0x2A, 0x50, 0x80, 0x01, 0x8A, 0x45, 0x38, 0x24, 0x01, 0x09, + 0x8C, 0x01, 0xD5, 0xF5, 0x44, 0x02, 0x47, 0x58, 0x49, 0xFF, 0xFF, 0x11, 0x83, 0x80, 0x44, 0x02, + 0x47, 0x58, 0x49, 0xFF, 0xFF, 0x1B, 0x2E, 0x17, 0xF0, 0xDA, 0xC1, 0x04, 0xE6, 0xC5, 0xE9, 0x05, + 0xD5, 0x12, 0x5A, 0x08, 0x01, 0x1C, 0xD5, 0xFB, 0x2E, 0x00, 0x12, 0xD6, 0x8C, 0x01, 0x96, 0x00, + 0xE6, 0x03, 0x3E, 0x00, 0x12, 0xD6, 0xE9, 0x0A, 0x84, 0x00, 0x3E, 0x00, 0x12, 0xD6, 0x84, 0x01, + 0xEB, 0x45, 0xD5, 0x06, 0x84, 0x00, 0x3E, 0x00, 0x12, 0xD6, 0x5B, 0xC0, 0x01, 0xF7, 0x84, 0x00, + 0xEB, 0xB9, 0x84, 0x01, 0x3E, 0x07, 0xF0, 0xE9, 0xFC, 0xC1, 0x44, 0x02, 0x47, 0x58, 0xF1, 0x01, + 0x80, 0x49, 0x49, 0xFF, 0xFF, 0x62, 0x8C, 0xC1, 0x3C, 0x00, 0x09, 0x6E, 0x97, 0xB1, 0xE2, 0x06, + 0xE8, 0x05, 0x84, 0x01, 0x3E, 0x07, 0xF0, 0xE8, 0xFC, 0xC1, 0x84, 0x01, 0x49, 0xFF, 0xCD, 0x61, + 0x84, 0x01, 0xEB, 0x40, 0x48, 0xFF, 0xFF, 0x87, 0xFC, 0x22, 0x84, 0x00, 0x3E, 0x00, 0x12, 0xDA, + 0x49, 0xFF, 0xCD, 0xB6, 0xB6, 0x1F, 0x49, 0xFF, 0xD1, 0x2D, 0xF0, 0x81, 0x49, 0xFF, 0xE2, 0x8C, + 0xF0, 0x82, 0x84, 0x00, 0xDD, 0x45, 0x84, 0x00, 0x49, 0xFF, 0xD0, 0xBB, 0x84, 0x00, 0xEA, 0xD3, + 0x84, 0x00, 0xEA, 0x42, 0x84, 0x00, 0xEA, 0xD4, 0x49, 0xFF, 0xDE, 0xD2, 0xEA, 0x3B, 0x5A, 0x08, + 0x1C, 0x08, 0x84, 0x00, 0x49, 0xFF, 0xDD, 0xED, 0xEA, 0xB2, 0xFA, 0x30, 0xAE, 0x40, 0x84, 0x05, + 0xEA, 0xFA, 0x84, 0x05, 0xEA, 0x96, 0x84, 0x05, 0xEA, 0x4A, 0x49, 0xFF, 0xF7, 0xBA, 0x49, 0xFF, + 0xFE, 0x7B, 0x2E, 0x76, 0xF3, 0xAE, 0x84, 0x00, 0x80, 0x27, 0xEB, 0xC3, 0x84, 0x00, 0x80, 0x20, + 0xDD, 0x4E, 0x84, 0x00, 0xEB, 0xB6, 0xDD, 0x50, 0xC0, 0x06, 0xDD, 0x58, 0x5A, 0x08, 0x02, 0x06, + 0x48, 0x00, 0x00, 0x7E, 0xDD, 0x49, 0xC0, 0xFA, 0xDD, 0x51, 0x5A, 0x08, 0x01, 0x04, 0x48, 0x00, + 0x00, 0x77, 0x49, 0xFF, 0xDF, 0x3F, 0xDD, 0x41, 0x80, 0x40, 0x5A, 0x08, 0x01, 0x07, 0x3C, 0x03, + 0xEC, 0x40, 0x84, 0x20, 0x80, 0x62, 0xEA, 0x6D, 0x49, 0xFF, 0xDE, 0x2D, 0x84, 0x07, 0xEA, 0x4A, + 0xEB, 0x46, 0x84, 0x01, 0xEB, 0x40, 0x49, 0xFF, 0xEC, 0x16, 0xF0, 0x83, 0xF1, 0x03, 0x84, 0x01, + 0xEA, 0xE9, 0xDD, 0x41, 0x80, 0xC0, 0x5A, 0x08, 0x01, 0x11, 0x84, 0x00, 0x80, 0x20, 0xDD, 0x4E, + 0x84, 0x00, 0x80, 0x20, 0xEA, 0x2A, 0x84, 0x00, 0x80, 0x26, 0xDD, 0x4E, 0x84, 0x00, 0x80, 0x26, + 0xEA, 0x2A, 0x80, 0x06, 0x80, 0x26, 0xD5, 0x04, 0xDD, 0x41, 0x80, 0x20, 0xC8, 0x02, 0xEB, 0x18, + 0xEA, 0x99, 0xC0, 0x04, 0x84, 0x01, 0x3E, 0x07, 0xF0, 0xE7, 0xEA, 0x47, 0xC0, 0x1A, 0xDD, 0x41, + 0x80, 0xC0, 0x5A, 0x00, 0x01, 0x04, 0x48, 0x00, 0x00, 0xA6, 0x84, 0x20, 0xDD, 0x4E, 0x80, 0x06, + 0x84, 0x20, 0xEA, 0x2A, 0x80, 0x06, 0x80, 0x26, 0xDD, 0x4E, 0x80, 0x26, 0x80, 0x06, 0xEA, 0x2A, + 0x84, 0x00, 0x49, 0xFF, 0xD4, 0x6B, 0x84, 0x00, 0x80, 0x20, 0xEB, 0x18, 0x80, 0x06, 0xFC, 0xA2, + 0x2E, 0x07, 0xF0, 0xE7, 0xC0, 0x05, 0x84, 0x01, 0x3E, 0x07, 0xF0, 0xE9, 0xD5, 0x0B, 0xDD, 0x41, + 0x5A, 0x08, 0x01, 0x03, 0xEB, 0x1E, 0x84, 0x01, 0xDD, 0x45, 0x49, 0xFF, 0xFE, 0xD3, 0x84, 0x00, + 0xEB, 0x1E, 0xDD, 0x41, 0x80, 0xC0, 0x5A, 0x08, 0x01, 0x0D, 0x84, 0x20, 0xDD, 0x4E, 0x80, 0x06, + 0x84, 0x20, 0xEA, 0x2A, 0x80, 0x06, 0x80, 0x26, 0xDD, 0x4E, 0x80, 0x06, 0x80, 0x26, 0xEA, 0x2A, + 0x84, 0x00, 0x49, 0xFF, 0xD4, 0x43, 0x84, 0x00, 0x80, 0x20, 0xEB, 0x18, 0x2E, 0x07, 0xF0, 0xE9, + 0xC0, 0x07, 0x84, 0x00, 0x3E, 0x07, 0xF0, 0xE9, 0x84, 0x01, 0x3E, 0x00, 0x12, 0xDA, 0x2E, 0x07, + 0xF0, 0xE7, 0xC0, 0x04, 0x84, 0x00, 0x3E, 0x07, 0xF0, 0xE7, 0xEB, 0x77, 0x5A, 0x08, 0x01, 0x05, + 0x84, 0x00, 0x3E, 0x00, 0x12, 0xDB, 0x84, 0x00, 0xDD, 0x45, 0x84, 0x00, 0xEB, 0x40, 0x49, 0xFF, + 0xDE, 0xB1, 0x84, 0x00, 0xEA, 0x96, 0x84, 0x00, 0xEA, 0xFA, 0x84, 0x00, 0xEA, 0x4A, 0xEB, 0x46, + 0xB4, 0x1F, 0xEB, 0x68, 0xF0, 0x02, 0xEB, 0xB6, 0xF0, 0x01, 0xEA, 0x42, 0x84, 0x01, 0xEA, 0xD3, + 0x84, 0x00, 0xEA, 0xD4, 0x49, 0xFF, 0xDB, 0x5B, 0x49, 0xFF, 0xDB, 0x5E, 0xEB, 0xAC, 0xEA, 0xEC, + 0xEA, 0x5D, 0x84, 0x01, 0x3C, 0x1D, 0xF6, 0x3F, 0xEA, 0xE9, 0xEB, 0x2E, 0x5A, 0x08, 0x01, 0x07, + 0xDD, 0x46, 0xEA, 0xDF, 0xC0, 0x03, 0x84, 0x02, 0xD5, 0x07, 0x2E, 0x07, 0xF0, 0xE8, 0xC0, 0x03, + 0x84, 0x01, 0xD5, 0x02, 0x84, 0x03, 0x3E, 0x00, 0x14, 0x90, 0x84, 0x20, 0x84, 0x01, 0xDD, 0x4E, + 0x84, 0x01, 0x80, 0x27, 0xEB, 0xC3, 0xDD, 0x41, 0x80, 0x40, 0x5A, 0x08, 0x01, 0x07, 0x3C, 0x03, + 0xEC, 0x8D, 0x84, 0x20, 0x80, 0x62, 0xEA, 0x6D, 0x2E, 0x07, 0xF0, 0xE8, 0xC0, 0x04, 0x84, 0x00, + 0x3E, 0x07, 0xF0, 0xE8, 0x84, 0x01, 0xDD, 0x45, 0xEA, 0x3B, 0x5A, 0x08, 0x1C, 0x08, 0xEA, 0xB2, + 0xFA, 0x30, 0xAE, 0x40, 0x84, 0x01, 0x49, 0xFF, 0xDC, 0xEC, 0x49, 0xFF, 0xD0, 0x52, 0xEB, 0x2E, + 0xFC, 0xA2, 0x84, 0x01, 0xFC, 0xA2, 0xFC, 0x02, 0xF0, 0x83, 0xF1, 0x81, 0xFD, 0x01, 0xF2, 0x82, + 0xB6, 0x7F, 0x49, 0xFF, 0xDF, 0xCC, 0xF0, 0x01, 0xB4, 0x3F, 0x49, 0xFF, 0xDF, 0xE6, 0xF0, 0x03, + 0x3C, 0x53, 0xF5, 0x2D, 0xF1, 0x01, 0xF2, 0x02, 0xB4, 0x7F, 0x3C, 0x4D, 0xFA, 0xCE, 0x49, 0xFF, + 0xE0, 0x1E, 0xB4, 0x1F, 0xEB, 0xCA, 0xFC, 0x82, 0xFC, 0x00, 0x80, 0xC0, 0x5A, 0x08, 0x01, 0x0C, + 0x84, 0x00, 0x3E, 0x07, 0xF0, 0xDB, 0x3C, 0x13, 0xEC, 0x9B, 0x84, 0x02, 0xEA, 0x31, 0x84, 0x02, + 0x80, 0x26, 0xD5, 0x03, 0x84, 0x02, 0x84, 0x20, 0xDD, 0x47, 0xFC, 0x80, 0xFC, 0x00, 0x2E, 0x07, + 0xF0, 0xDB, 0xC0, 0x06, 0x84, 0x02, 0xEA, 0x7A, 0x84, 0x00, 0x3E, 0x07, 0xF0, 0xDB, 0x84, 0x02, + 0xEA, 0x32, 0x5A, 0x08, 0x01, 0x0B, 0x44, 0x00, 0xFF, 0xFE, 0x49, 0xFF, 0xE1, 0x80, 0x49, 0xFF, + 0xE1, 0x8C, 0x49, 0xFF, 0xE1, 0x84, 0xD5, 0x00, 0xFC, 0x80, 0xFC, 0x00, 0x84, 0x00, 0x80, 0x20, + 0x80, 0x40, 0x49, 0xFF, 0xE0, 0xC8, 0x84, 0x01, 0x49, 0xFF, 0xE0, 0xE5, 0x84, 0x01, 0x49, 0xFF, + 0xE0, 0xEC, 0x84, 0x01, 0x3E, 0x07, 0xF0, 0xF8, 0x2E, 0x07, 0xF0, 0xF8, 0x5A, 0x00, 0x01, 0xFE, + 0x3C, 0x13, 0xF5, 0x2D, 0x46, 0x20, 0x00, 0xF4, 0x8C, 0x22, 0x40, 0x00, 0x88, 0x0A, 0x50, 0x21, + 0x02, 0x40, 0x84, 0x60, 0x90, 0x3F, 0x49, 0x00, 0x07, 0xBD, 0x44, 0x21, 0x2D, 0xF4, 0x84, 0x60, + 0x49, 0x00, 0x06, 0xD4, 0xFD, 0x10, 0x40, 0x40, 0x04, 0x09, 0x40, 0x10, 0xFC, 0x08, 0x46, 0x50, + 0x00, 0xF4, 0xFF, 0x0F, 0x50, 0x52, 0x82, 0x40, 0x98, 0x25, 0x40, 0x11, 0x84, 0x09, 0x40, 0x40, + 0x10, 0x06, 0x88, 0x24, 0x49, 0x00, 0x06, 0xC2, 0x96, 0x01, 0x3C, 0x0B, 0xF5, 0x2D, 0x49, 0x00, + 0x00, 0x5E, 0xFC, 0x80, 0xFC, 0x00, 0x49, 0xFF, 0xD9, 0xEC, 0x49, 0xFF, 0xFF, 0xC0, 0x44, 0x01, + 0x0F, 0xA6, 0x49, 0xFF, 0xDF, 0x49, 0x84, 0x20, 0x80, 0x61, 0x84, 0x41, 0xDD, 0x4C, 0xEA, 0x6D, + 0x84, 0x00, 0x80, 0x20, 0xEB, 0x16, 0x84, 0x00, 0x80, 0x20, 0x49, 0xFF, 0xD1, 0xD2, 0x84, 0x00, + 0x49, 0xFF, 0xE0, 0x0E, 0x84, 0x20, 0x84, 0x01, 0xDD, 0x4E, 0x84, 0x00, 0x49, 0xFF, 0xDF, 0xD4, + 0x84, 0x40, 0x84, 0x61, 0x3C, 0x03, 0xEC, 0x84, 0x84, 0x27, 0xEA, 0x6D, 0x84, 0x00, 0x84, 0x21, + 0xEB, 0x16, 0x84, 0x01, 0x80, 0x20, 0x49, 0xFF, 0xD1, 0xBC, 0x49, 0x00, 0x00, 0x4A, 0xFC, 0x80, + 0xFC, 0x00, 0x49, 0xFF, 0xE1, 0x14, 0xFC, 0x80, 0xFC, 0x20, 0x3C, 0x53, 0xF5, 0x2D, 0x80, 0xE0, + 0xEB, 0xB7, 0x80, 0xC1, 0xD8, 0x0B, 0xEA, 0x80, 0xFA, 0x4E, 0x42, 0x13, 0x08, 0x24, 0xEB, 0xC9, + 0x40, 0x03, 0x00, 0x0C, 0x40, 0x10, 0x80, 0x37, 0xD5, 0x0A, 0x3C, 0x23, 0xF5, 0x2D, 0xFF, 0x94, + 0xEA, 0x80, 0xEA, 0x92, 0x40, 0x00, 0x80, 0x0C, 0x40, 0x13, 0x00, 0x37, 0x96, 0x49, 0x5A, 0x78, + 0x01, 0x0B, 0xFE, 0x0B, 0x96, 0x01, 0x49, 0xFF, 0xE0, 0xEA, 0x49, 0xFF, 0xE0, 0xF6, 0x49, 0xFF, + 0xE0, 0xEE, 0xFC, 0xA0, 0x49, 0xFF, 0xE0, 0xFD, 0xFC, 0xA0, 0xFC, 0x00, 0x84, 0x01, 0x49, 0xFF, + 0xE0, 0xB0, 0x84, 0x07, 0x49, 0xFF, 0xE0, 0xBD, 0x84, 0x00, 0x49, 0xFF, 0xE0, 0xC5, 0x84, 0x00, + 0x49, 0xFF, 0xE0, 0xCC, 0x84, 0x01, 0x3C, 0x1D, 0xF6, 0x3F, 0xEA, 0xE9, 0xFC, 0x80, 0x3C, 0x00, + 0x0A, 0x8C, 0x3C, 0x10, 0x0A, 0x8C, 0x96, 0x01, 0x4C, 0x00, 0xFF, 0xFB, 0xDD, 0x9E, 0x84, 0x00, + 0x3C, 0x0E, 0x05, 0x25, 0xDD, 0x9E, 0x44, 0x22, 0x49, 0x10, 0x38, 0x11, 0x01, 0x09, 0xDD, 0x9E, + 0xFC, 0x00, 0x80, 0xC0, 0x49, 0xFF, 0xFF, 0xED, 0x44, 0x12, 0x49, 0x50, 0x38, 0x00, 0x99, 0x09, + 0xFC, 0x80, 0x80, 0x60, 0x5A, 0x18, 0x01, 0x0E, 0xFC, 0x20, 0x80, 0xE0, 0x80, 0xC1, 0xEA, 0x7A, + 0x3C, 0x0C, 0x05, 0x25, 0x40, 0x13, 0x1C, 0x0C, 0xFE, 0x47, 0x3C, 0x1E, 0x05, 0x25, 0xFC, 0xA0, + 0x84, 0x41, 0x3C, 0x0C, 0x05, 0x25, 0x40, 0x11, 0x0C, 0x0C, 0xFE, 0x4B, 0xFE, 0x46, 0x3C, 0x1E, + 0x05, 0x25, 0xDD, 0x9E, 0x3C, 0x2C, 0x05, 0x25, 0x84, 0x21, 0x40, 0x10, 0x80, 0x0C, 0xFE, 0x56, + 0xC9, 0x03, 0x80, 0x01, 0xDD, 0x9E, 0xFC, 0x00, 0x80, 0xC0, 0x49, 0xFF, 0xFF, 0xC2, 0x44, 0x12, + 0x49, 0x50, 0x44, 0x22, 0x49, 0x10, 0xEB, 0x9C, 0x38, 0x21, 0x19, 0x01, 0x8A, 0x01, 0x96, 0x01, + 0xE2, 0x02, 0xEB, 0x27, 0xFC, 0x80, 0x3C, 0x00, 0x0A, 0x8C, 0x8C, 0x01, 0x96, 0x01, 0x3C, 0x08, + 0x0A, 0x8C, 0xDD, 0x9E, 0x3A, 0x1F, 0xA4, 0x3C, 0x3A, 0xFF, 0xBF, 0xBC, 0x42, 0x6E, 0x80, 0x20, + 0x3A, 0x6F, 0x98, 0x3C, 0x64, 0x62, 0xA4, 0x02, 0x9D, 0xB4, 0x64, 0x72, 0x04, 0x02, 0x3A, 0x6F, + 0x9C, 0x3C, 0x64, 0x62, 0x00, 0x02, 0x9F, 0xB2, 0x64, 0x62, 0x00, 0x03, 0x64, 0x00, 0x00, 0x08, + 0x49, 0x00, 0x02, 0x54, 0x3A, 0x6F, 0x9C, 0x04, 0x64, 0x62, 0xA4, 0x03, 0x64, 0x72, 0x04, 0x03, + 0x3A, 0x6F, 0x98, 0x04, 0x42, 0x6E, 0x80, 0x21, 0x3A, 0xFF, 0xBF, 0x84, 0x3A, 0x1F, 0xA4, 0x04, + 0x64, 0x00, 0x00, 0x04, 0x3A, 0x1F, 0xA4, 0x3C, 0x3A, 0xFF, 0xBF, 0xBC, 0x42, 0x6E, 0x80, 0x20, + 0x3A, 0x6F, 0x98, 0x3C, 0x64, 0x62, 0xA4, 0x02, 0x9D, 0xB4, 0x64, 0x72, 0x04, 0x02, 0x3A, 0x6F, + 0x9C, 0x3C, 0x64, 0x62, 0x00, 0x02, 0x9F, 0xB2, 0x64, 0x62, 0x00, 0x03, 0x64, 0x00, 0x00, 0x08, + 0x49, 0x00, 0x02, 0x2D, 0x3A, 0x6F, 0x9C, 0x04, 0x64, 0x62, 0xA4, 0x03, 0x64, 0x72, 0x04, 0x03, + 0x3A, 0x6F, 0x98, 0x04, 0x42, 0x6E, 0x80, 0x21, 0x3A, 0xFF, 0xBF, 0x84, 0x3A, 0x1F, 0xA4, 0x04, + 0x64, 0x00, 0x00, 0x04, 0x3A, 0x1F, 0xA4, 0x3C, 0x3A, 0xFF, 0xBF, 0xBC, 0x42, 0x6E, 0x80, 0x20, + 0x3A, 0x6F, 0x98, 0x3C, 0x64, 0x62, 0xA4, 0x02, 0x9D, 0xB4, 0x64, 0x72, 0x04, 0x02, 0x3A, 0x6F, + 0x9C, 0x3C, 0x64, 0x62, 0x00, 0x02, 0x9F, 0xB2, 0x64, 0x62, 0x00, 0x03, 0x64, 0x00, 0x00, 0x08, + 0x49, 0x00, 0x02, 0x06, 0x3A, 0x6F, 0x9C, 0x04, 0x64, 0x62, 0xA4, 0x03, 0x64, 0x72, 0x04, 0x03, + 0x3A, 0x6F, 0x98, 0x04, 0x42, 0x6E, 0x80, 0x21, 0x3A, 0xFF, 0xBF, 0x84, 0x3A, 0x1F, 0xA4, 0x04, + 0x64, 0x00, 0x00, 0x04, 0x3A, 0x1F, 0xA4, 0x3C, 0x3A, 0xFF, 0xBF, 0xBC, 0x42, 0x6E, 0x80, 0x20, + 0x3A, 0x6F, 0x98, 0x3C, 0x64, 0x62, 0xA4, 0x02, 0x9D, 0xB4, 0x64, 0x72, 0x04, 0x02, 0x3A, 0x6F, + 0x9C, 0x3C, 0x64, 0x62, 0x00, 0x02, 0x9F, 0xB2, 0x64, 0x62, 0x00, 0x03, 0x64, 0x00, 0x00, 0x08, + 0x49, 0x00, 0x01, 0xDF, 0x3A, 0x6F, 0x9C, 0x04, 0x64, 0x62, 0xA4, 0x03, 0x64, 0x72, 0x04, 0x03, + 0x3A, 0x6F, 0x98, 0x04, 0x42, 0x6E, 0x80, 0x21, 0x3A, 0xFF, 0xBF, 0x84, 0x3A, 0x1F, 0xA4, 0x04, + 0x64, 0x00, 0x00, 0x04, 0x3A, 0x1F, 0xA4, 0x3C, 0x3A, 0xFF, 0xBF, 0xBC, 0x42, 0x6E, 0x80, 0x20, + 0x3A, 0x6F, 0x98, 0x3C, 0x64, 0x62, 0xA4, 0x02, 0x9D, 0xB4, 0x64, 0x72, 0x04, 0x02, 0x3A, 0x6F, + 0x9C, 0x3C, 0x64, 0x62, 0x00, 0x02, 0x9F, 0xB2, 0x64, 0x62, 0x00, 0x03, 0x64, 0x00, 0x00, 0x08, + 0x49, 0x00, 0x01, 0xB8, 0x3A, 0x6F, 0x9C, 0x04, 0x64, 0x62, 0xA4, 0x03, 0x64, 0x72, 0x04, 0x03, + 0x3A, 0x6F, 0x98, 0x04, 0x42, 0x6E, 0x80, 0x21, 0x3A, 0xFF, 0xBF, 0x84, 0x3A, 0x1F, 0xA4, 0x04, + 0x64, 0x00, 0x00, 0x04, 0x3A, 0x1F, 0xA4, 0x3C, 0x3A, 0xFF, 0xBF, 0xBC, 0x42, 0x6E, 0x80, 0x20, + 0x3A, 0x6F, 0x98, 0x3C, 0x64, 0x62, 0xA4, 0x02, 0x9D, 0xB4, 0x64, 0x72, 0x04, 0x02, 0x3A, 0x6F, + 0x9C, 0x3C, 0x64, 0x62, 0x00, 0x02, 0x9F, 0xB2, 0x64, 0x62, 0x00, 0x03, 0x64, 0x00, 0x00, 0x08, + 0x49, 0x00, 0x01, 0x91, 0x3A, 0x6F, 0x9C, 0x04, 0x64, 0x62, 0xA4, 0x03, 0x64, 0x72, 0x04, 0x03, + 0x3A, 0x6F, 0x98, 0x04, 0x42, 0x6E, 0x80, 0x21, 0x3A, 0xFF, 0xBF, 0x84, 0x3A, 0x1F, 0xA4, 0x04, + 0x64, 0x00, 0x00, 0x04, 0x3A, 0x1F, 0xA4, 0x3C, 0x3A, 0xFF, 0xBF, 0xBC, 0x42, 0x6E, 0x80, 0x20, + 0x3A, 0x6F, 0x98, 0x3C, 0x64, 0x62, 0xA4, 0x02, 0x9D, 0xB4, 0x64, 0x72, 0x04, 0x02, 0x3A, 0x6F, + 0x9C, 0x3C, 0x64, 0x62, 0x00, 0x02, 0x9F, 0xB2, 0x64, 0x62, 0x00, 0x03, 0x64, 0x00, 0x00, 0x08, + 0x49, 0x00, 0x01, 0x6A, 0x3A, 0x6F, 0x9C, 0x04, 0x64, 0x62, 0xA4, 0x03, 0x64, 0x72, 0x04, 0x03, + 0x3A, 0x6F, 0x98, 0x04, 0x42, 0x6E, 0x80, 0x21, 0x3A, 0xFF, 0xBF, 0x84, 0x3A, 0x1F, 0xA4, 0x04, + 0x64, 0x00, 0x00, 0x04, 0x3A, 0x1F, 0xA4, 0x3C, 0x3A, 0xFF, 0xBF, 0xBC, 0x42, 0x6E, 0x80, 0x20, + 0x3A, 0x6F, 0x98, 0x3C, 0x64, 0x62, 0xA4, 0x02, 0x9D, 0xB4, 0x64, 0x72, 0x04, 0x02, 0x3A, 0x6F, + 0x9C, 0x3C, 0x64, 0x62, 0x00, 0x02, 0x9F, 0xB2, 0x64, 0x62, 0x00, 0x03, 0x64, 0x00, 0x00, 0x08, + 0x49, 0x00, 0x01, 0x43, 0x3A, 0x6F, 0x9C, 0x04, 0x64, 0x62, 0xA4, 0x03, 0x64, 0x72, 0x04, 0x03, + 0x3A, 0x6F, 0x98, 0x04, 0x42, 0x6E, 0x80, 0x21, 0x3A, 0xFF, 0xBF, 0x84, 0x3A, 0x1F, 0xA4, 0x04, + 0x64, 0x00, 0x00, 0x04, 0x3A, 0x1F, 0x94, 0x3C, 0x3A, 0xFF, 0xBF, 0xBC, 0x42, 0x2E, 0x80, 0x20, + 0x3A, 0x2F, 0x8C, 0x3C, 0x64, 0x12, 0xA4, 0x02, 0x64, 0x22, 0x04, 0x02, 0x3A, 0x1F, 0x88, 0x3C, + 0x64, 0x12, 0x00, 0x02, 0x9E, 0x4A, 0x64, 0x12, 0x00, 0x03, 0x44, 0x10, 0x00, 0xA4, 0x38, 0x10, + 0x82, 0x02, 0xDD, 0x21, 0x3A, 0x0F, 0x84, 0x04, 0x64, 0x02, 0x00, 0x43, 0x64, 0x00, 0x00, 0x08, + 0x64, 0x02, 0xA4, 0x03, 0x64, 0x12, 0x04, 0x03, 0x3A, 0x2F, 0x8C, 0x04, 0x42, 0x2E, 0x80, 0x21, + 0x3A, 0xFF, 0xBF, 0x84, 0x3A, 0x1F, 0x94, 0x04, 0x3A, 0x0F, 0x80, 0x04, 0x64, 0x00, 0x00, 0x04, + 0x3A, 0x1F, 0x94, 0x3C, 0x3A, 0xFF, 0xBF, 0xBC, 0x42, 0x2E, 0x80, 0x20, 0x3A, 0x2F, 0x8C, 0x3C, + 0x44, 0x10, 0x00, 0xA4, 0x38, 0x10, 0x82, 0x02, 0xDD, 0x21, 0x3A, 0x2F, 0x8C, 0x04, 0x42, 0x2E, + 0x80, 0x21, 0x3A, 0xFF, 0xBF, 0x84, 0x3A, 0x1F, 0x94, 0x04, 0x3A, 0x0F, 0x80, 0x04, 0x64, 0x00, + 0x00, 0x04, 0xD5, 0x00, 0x3A, 0x0F, 0x80, 0x3C, 0x84, 0x00, 0xD5, 0xE3, 0x3A, 0x0F, 0x80, 0x3C, + 0x84, 0x01, 0xD5, 0xDF, 0x3A, 0x0F, 0x80, 0x3C, 0x84, 0x02, 0xD5, 0xDB, 0x3A, 0x0F, 0x80, 0x3C, + 0x84, 0x03, 0xD5, 0xD7, 0x3A, 0x0F, 0x80, 0x3C, 0x84, 0x04, 0xD5, 0xD3, 0x3A, 0x0F, 0x80, 0x3C, + 0x84, 0x05, 0xD5, 0xCF, 0x3A, 0x0F, 0x80, 0x3C, 0x84, 0x06, 0xD5, 0xCB, 0x3A, 0x0F, 0x80, 0x3C, + 0x84, 0x07, 0xD5, 0xC7, 0x3A, 0x0F, 0x80, 0x3C, 0x84, 0x08, 0xD5, 0xC3, 0x3A, 0x0F, 0x80, 0x3C, + 0x84, 0x09, 0xD5, 0xBF, 0x3A, 0x0F, 0x80, 0x3C, 0x84, 0x0A, 0xD5, 0xBB, 0x3A, 0x0F, 0x80, 0x3C, + 0x84, 0x0B, 0xD5, 0xB7, 0x3A, 0x0F, 0x80, 0x3C, 0x84, 0x0C, 0xD5, 0xB3, 0x3A, 0x0F, 0x80, 0x3C, + 0x84, 0x0D, 0xD5, 0xAF, 0x3A, 0x0F, 0x80, 0x3C, 0x84, 0x0E, 0xD5, 0xAB, 0x3A, 0x0F, 0x80, 0x3C, + 0x84, 0x0F, 0xD5, 0xA7, 0x3A, 0x0F, 0x80, 0x3C, 0xFA, 0x00, 0xD5, 0xA3, 0x3A, 0x0F, 0x80, 0x3C, + 0xFA, 0x01, 0xD5, 0x9F, 0x3A, 0x0F, 0x80, 0x3C, 0xFA, 0x02, 0xD5, 0x9B, 0x3A, 0x0F, 0x80, 0x3C, + 0xFA, 0x03, 0xD5, 0x97, 0x3A, 0x0F, 0x80, 0x3C, 0xFA, 0x04, 0xD5, 0x93, 0x3A, 0x0F, 0x80, 0x3C, + 0xFA, 0x05, 0xD5, 0x8F, 0x3A, 0x0F, 0x80, 0x3C, 0xFA, 0x06, 0xD5, 0x8B, 0x3A, 0x0F, 0x80, 0x3C, + 0xFA, 0x07, 0xD5, 0x87, 0x3A, 0x0F, 0x80, 0x3C, 0xFA, 0x08, 0xD5, 0x83, 0x3A, 0x0F, 0x80, 0x3C, + 0xFA, 0x09, 0x48, 0xFF, 0xFF, 0x7F, 0x3A, 0x0F, 0x80, 0x3C, 0xFA, 0x0A, 0x48, 0xFF, 0xFF, 0x7A, + 0x3A, 0x0F, 0x80, 0x3C, 0xFA, 0x0B, 0x48, 0xFF, 0xFF, 0x75, 0x3A, 0x0F, 0x80, 0x3C, 0xFA, 0x0C, + 0x48, 0xFF, 0xFF, 0x70, 0x3A, 0x0F, 0x80, 0x3C, 0xFA, 0x0D, 0x48, 0xFF, 0xFF, 0x6B, 0x3A, 0x0F, + 0x80, 0x3C, 0xFA, 0x0E, 0x48, 0xFF, 0xFF, 0x66, 0x3A, 0x0F, 0x80, 0x3C, 0x44, 0x00, 0x00, 0x1F, + 0x48, 0xFF, 0xFF, 0x60, 0x84, 0x01, 0x64, 0x04, 0xC0, 0x02, 0x44, 0x02, 0x00, 0x01, 0x64, 0x04, + 0xE0, 0x03, 0x45, 0xD2, 0x34, 0x78, 0x3F, 0xC8, 0x00, 0x00, 0x45, 0xF2, 0x77, 0xF4, 0x44, 0x01, + 0x20, 0x20, 0x42, 0x0E, 0x00, 0x21, 0x49, 0x00, 0x00, 0x34, 0x49, 0x00, 0x03, 0xD2, 0xD5, 0x00, + 0xFC, 0x00, 0xEA, 0x5A, 0x84, 0x20, 0x49, 0xFF, 0xCC, 0xF9, 0xEA, 0x5A, 0x84, 0x20, 0x49, 0xFF, + 0xCD, 0x0A, 0x84, 0x21, 0xEA, 0x5A, 0xEB, 0x60, 0x84, 0x00, 0x49, 0xFF, 0xCD, 0x57, 0x44, 0x02, + 0x20, 0x64, 0x44, 0x22, 0x5F, 0xF8, 0x84, 0x20, 0x8A, 0x40, 0xDD, 0x40, 0xFC, 0x80, 0x84, 0x00, + 0x64, 0x05, 0xE4, 0x03, 0x84, 0x1F, 0x64, 0x03, 0x04, 0x03, 0x64, 0x03, 0x24, 0x03, 0x64, 0x12, + 0x24, 0x02, 0x44, 0x0F, 0x0F, 0xFF, 0xFE, 0x0E, 0x64, 0x02, 0x24, 0x03, 0x64, 0x12, 0x00, 0x02, + 0x84, 0x18, 0xFE, 0x0E, 0x64, 0x02, 0x00, 0x03, 0x64, 0x00, 0x00, 0x08, 0xDD, 0x9E, 0xFC, 0x00, + 0x49, 0xFF, 0xFF, 0xE7, 0x64, 0x00, 0x80, 0x02, 0x92, 0x1E, 0xC0, 0x06, 0x64, 0x00, 0x84, 0x02, + 0x96, 0x2E, 0xC0, 0x02, 0xD5, 0x00, 0x49, 0xFF, 0xFF, 0xC5, 0x64, 0x12, 0x00, 0x43, 0x64, 0x00, + 0x00, 0x08, 0x64, 0x00, 0x00, 0x08, 0xFC, 0x80, 0xDD, 0x9E, 0xDD, 0x9E, 0xDD, 0x9E, 0xDD, 0x9E, + 0xDD, 0x9E, 0xDD, 0x9E, 0xDD, 0x9E, 0xDD, 0x9E, 0xDD, 0x9E, 0x44, 0x04, 0x80, 0x04, 0xB4, 0x00, + 0x92, 0x08, 0x96, 0x06, 0xC0, 0x05, 0x44, 0x04, 0x80, 0x05, 0x84, 0x21, 0xAE, 0x40, 0xDD, 0x9E, + 0xFC, 0x01, 0xEA, 0xAE, 0x44, 0x14, 0x80, 0x81, 0xA6, 0x00, 0xA6, 0x48, 0xFE, 0x0E, 0xEA, 0x8E, + 0xEB, 0x0E, 0xC0, 0x03, 0x49, 0xFF, 0xD5, 0x80, 0xFC, 0x81, 0xFC, 0x00, 0x44, 0x04, 0x80, 0x00, + 0xB4, 0x00, 0x49, 0xFF, 0xDC, 0xDD, 0xFC, 0x80, 0x44, 0x14, 0x80, 0x04, 0x44, 0x04, 0x80, 0x84, + 0xB4, 0x41, 0xB4, 0x00, 0x96, 0x06, 0xFE, 0x16, 0xC0, 0x03, 0x84, 0x01, 0xAE, 0x08, 0xDD, 0x9E, + 0xFC, 0x00, 0x44, 0x04, 0x80, 0x00, 0xB4, 0x00, 0x49, 0xFF, 0xDC, 0xE1, 0xFC, 0x80, 0x44, 0x04, + 0x80, 0x14, 0xB4, 0x20, 0x96, 0x46, 0xC1, 0x03, 0x84, 0x21, 0xAE, 0x40, 0xB4, 0x00, 0x92, 0x01, + 0x96, 0x06, 0xC0, 0x05, 0x44, 0x04, 0x80, 0x14, 0x84, 0x22, 0xAE, 0x40, 0xDD, 0x9E, 0xFC, 0x00, + 0x49, 0xFF, 0xC9, 0x5F, 0xFC, 0x80, 0x44, 0x04, 0x80, 0x04, 0xB4, 0x00, 0x92, 0x13, 0x96, 0x06, + 0xC0, 0x04, 0xEA, 0xC9, 0x84, 0x28, 0xAE, 0x40, 0xDD, 0x9E, 0x44, 0x14, 0x80, 0x04, 0xB4, 0x01, + 0x92, 0x19, 0x96, 0x06, 0xC0, 0x04, 0xEA, 0xF2, 0x84, 0x42, 0xAE, 0x80, 0xB4, 0x01, 0x92, 0x18, + 0x96, 0x06, 0xC0, 0x04, 0xEA, 0xF2, 0x84, 0x21, 0xAE, 0x40, 0x44, 0x14, 0x80, 0x04, 0xB4, 0x01, + 0x92, 0x1A, 0x96, 0x06, 0xC0, 0x04, 0xEA, 0xF2, 0x84, 0x44, 0xAE, 0x80, 0xB4, 0x01, 0x92, 0x1B, + 0x96, 0x06, 0xC0, 0x04, 0xEA, 0xF2, 0x84, 0x28, 0xAE, 0x40, 0xEB, 0xBE, 0xB4, 0x00, 0x92, 0x1C, + 0x96, 0x06, 0xC0, 0x04, 0xEA, 0xF2, 0xFA, 0x20, 0xAE, 0x40, 0xDD, 0x9E, 0x44, 0x04, 0x80, 0x08, + 0xB4, 0x20, 0x92, 0x24, 0x96, 0x46, 0xC1, 0x03, 0xFA, 0x20, 0xAE, 0x40, 0xB4, 0x00, 0x84, 0x21, + 0x96, 0x06, 0xC0, 0x05, 0xEA, 0x36, 0xAE, 0x40, 0x3E, 0x17, 0xF0, 0xE9, 0xEA, 0x36, 0xB4, 0x20, + 0x92, 0x21, 0x96, 0x46, 0xC1, 0x06, 0x84, 0x22, 0xAE, 0x40, 0x84, 0x21, 0x3E, 0x17, 0xF0, 0xE8, + 0xB4, 0x00, 0x92, 0x02, 0x96, 0x06, 0xC0, 0x04, 0xEA, 0x36, 0x84, 0x24, 0xAE, 0x40, 0x44, 0x04, + 0x80, 0x14, 0xB4, 0x00, 0x92, 0x08, 0x96, 0x06, 0xC0, 0x2B, 0x2E, 0x07, 0xF0, 0xF8, 0x5A, 0x08, + 0x01, 0x24, 0xFC, 0x00, 0x2E, 0x00, 0x15, 0x1A, 0xC0, 0x08, 0x49, 0xFF, 0xDC, 0xE7, 0x3C, 0x13, + 0xF5, 0x2D, 0x8C, 0x03, 0x88, 0x01, 0x96, 0x01, 0x3C, 0x0B, 0xF5, 0x2D, 0x2E, 0x00, 0x15, 0x1A, + 0x8C, 0x01, 0x96, 0x00, 0x3E, 0x00, 0x15, 0x1A, 0x5A, 0x08, 0x05, 0x0A, 0x84, 0x00, 0x49, 0xFF, + 0xDC, 0xCC, 0x84, 0x00, 0x3E, 0x07, 0xF0, 0xF8, 0x3E, 0x00, 0x15, 0x1A, 0x44, 0x04, 0x80, 0x15, + 0x84, 0x21, 0xAE, 0x40, 0xFC, 0x80, 0x44, 0x04, 0x80, 0x15, 0x84, 0x21, 0xAE, 0x40, 0xDD, 0x9E, + 0x44, 0x04, 0x80, 0x9C, 0xB4, 0x00, 0x92, 0x02, 0x96, 0x06, 0xC0, 0x09, 0x44, 0x14, 0x80, 0x1C, + 0xB4, 0x01, 0x92, 0x02, 0x96, 0x06, 0xC0, 0x03, 0x84, 0x04, 0xAE, 0x08, 0xDD, 0x9E, 0xFC, 0x00, + 0x49, 0xFF, 0xC8, 0x0D, 0xFC, 0x80, 0xFC, 0x00, 0x49, 0xFF, 0xC8, 0x17, 0xFC, 0x80, 0xFC, 0x00, + 0x49, 0xFF, 0xC8, 0x14, 0xFC, 0x80, 0x44, 0x14, 0x80, 0x08, 0xB4, 0x01, 0x92, 0x08, 0x96, 0x06, + 0xC0, 0x04, 0xEA, 0xB2, 0x84, 0x41, 0xAE, 0x80, 0xB4, 0x01, 0x92, 0x09, 0x96, 0x06, 0xC0, 0x04, + 0xEA, 0xB2, 0x84, 0x22, 0xAE, 0x40, 0xEA, 0x36, 0xB4, 0x00, 0x40, 0x10, 0x34, 0x09, 0xEB, 0xB4, + 0xB4, 0x00, 0x92, 0x0D, 0x96, 0x06, 0xFE, 0x0E, 0xC0, 0x61, 0xFC, 0x00, 0xEA, 0x3B, 0x5A, 0x08, + 0x1C, 0x1A, 0xDD, 0x41, 0xC8, 0x17, 0xDD, 0x49, 0xC0, 0x15, 0x84, 0x61, 0x80, 0xA3, 0xFA, 0x2F, + 0x44, 0x20, 0x00, 0xB7, 0x44, 0x40, 0x00, 0xC0, 0x84, 0x04, 0xDD, 0x5D, 0x84, 0x01, 0xEA, 0x2D, + 0x84, 0x61, 0x84, 0x04, 0xFA, 0x2F, 0x44, 0x20, 0x00, 0xB7, 0x44, 0x40, 0x00, 0xCF, 0x80, 0xA3, + 0xDD, 0x5D, 0x2E, 0x37, 0xF0, 0xD5, 0x5A, 0x38, 0x01, 0x0A, 0x84, 0x02, 0x3E, 0x07, 0xF0, 0xD5, + 0xFA, 0x2F, 0x84, 0x02, 0x84, 0x4B, 0x80, 0x83, 0xD5, 0x2D, 0x5A, 0x38, 0x02, 0x2E, 0x84, 0x05, + 0x3E, 0x07, 0xF0, 0xD5, 0x80, 0x03, 0x84, 0x61, 0x80, 0xA3, 0xFA, 0x2F, 0x84, 0x4B, 0x84, 0x80, + 0xDD, 0x5D, 0x84, 0x61, 0x80, 0xA3, 0x84, 0x05, 0xFA, 0x2F, 0x44, 0x20, 0x00, 0x61, 0x84, 0x8B, + 0xDD, 0x5D, 0x84, 0x61, 0x80, 0xA3, 0xFA, 0x2F, 0xEB, 0xA4, 0x84, 0x80, 0x84, 0x05, 0xDD, 0x5D, + 0x84, 0x06, 0xEA, 0xB4, 0x84, 0x61, 0x84, 0x05, 0xFA, 0x2F, 0x44, 0x20, 0x00, 0x61, 0x44, 0x40, + 0x00, 0xCB, 0x80, 0xA3, 0xDD, 0x5D, 0x84, 0x05, 0xFA, 0x2F, 0xEB, 0xA4, 0x84, 0x61, 0x44, 0x40, + 0x00, 0xF0, 0x80, 0xA3, 0xDD, 0x5D, 0xEA, 0xB2, 0xFA, 0x30, 0xAE, 0x40, 0x44, 0x14, 0x80, 0x08, + 0xB4, 0x01, 0x92, 0x0D, 0x96, 0x06, 0xC8, 0xFD, 0xFC, 0x80, 0xDD, 0x9E, 0xFC, 0x00, 0xEA, 0x36, + 0xB4, 0x00, 0x92, 0x12, 0x96, 0x06, 0xC0, 0x4F, 0x44, 0x14, 0x80, 0x88, 0xB4, 0x01, 0x92, 0x12, + 0x96, 0x06, 0xC0, 0x49, 0xEA, 0xF7, 0x84, 0x44, 0xAE, 0x80, 0xB4, 0x41, 0x44, 0x0D, 0xFF, 0xFF, + 0xFE, 0x16, 0x44, 0x67, 0x30, 0x04, 0xB6, 0x01, 0xB4, 0x26, 0x84, 0x1E, 0xFE, 0x0E, 0xB6, 0x06, + 0x84, 0x0A, 0xEA, 0x2D, 0xB4, 0x06, 0xDD, 0x4B, 0xB6, 0x06, 0x84, 0x0A, 0xEA, 0x2D, 0x49, 0xFF, + 0xDA, 0x01, 0x44, 0x00, 0x00, 0x87, 0x49, 0xFF, 0xD9, 0xF7, 0x44, 0x17, 0x30, 0x10, 0xB4, 0x01, + 0x96, 0x06, 0xC0, 0xFE, 0x44, 0x17, 0x30, 0x10, 0xB4, 0x01, 0x92, 0x03, 0x96, 0x06, 0x5A, 0x00, + 0x01, 0xFD, 0x44, 0x67, 0x30, 0x04, 0x84, 0x0A, 0xEA, 0x2D, 0xB4, 0x26, 0x84, 0x1E, 0xFE, 0x0E, + 0xB6, 0x06, 0x84, 0x0A, 0xEA, 0x2D, 0xB4, 0x06, 0xDD, 0x4B, 0xB6, 0x06, 0x84, 0x0A, 0xEA, 0x2D, + 0x44, 0x14, 0x80, 0x88, 0x84, 0x01, 0x3E, 0x07, 0xF0, 0xF0, 0xB4, 0x41, 0x44, 0x02, 0x00, 0x00, + 0xFE, 0x17, 0xB6, 0x01, 0xEA, 0xF7, 0x84, 0x22, 0xAE, 0x40, 0x3C, 0x0D, 0xFC, 0x3B, 0x8C, 0x01, + 0x3C, 0x0F, 0xFC, 0x3B, 0xEA, 0x36, 0x84, 0x21, 0xB4, 0x00, 0x92, 0x10, 0x96, 0x06, 0xC0, 0x0A, + 0xEB, 0xB4, 0xB4, 0x00, 0x92, 0x10, 0x96, 0x06, 0xC0, 0x05, 0xEA, 0xF7, 0x3E, 0x17, 0xF0, 0xF1, + 0xAE, 0x40, 0xEA, 0x36, 0xB4, 0x00, 0x92, 0x11, 0x96, 0x06, 0xC0, 0x09, 0xEB, 0xB4, 0xB4, 0x00, + 0x92, 0x11, 0x96, 0x06, 0xC0, 0x04, 0xEA, 0xF7, 0x84, 0x22, 0xAE, 0x40, 0xFC, 0x80, 0xFC, 0x00, + 0xEA, 0x36, 0xB4, 0x00, 0x92, 0x18, 0x96, 0x06, 0xC0, 0x11, 0xEA, 0xCF, 0x84, 0x21, 0xAE, 0x40, + 0xDD, 0x49, 0xDD, 0x41, 0x5A, 0x08, 0x01, 0x0B, 0x49, 0xFF, 0xD4, 0xF2, 0x49, 0xFF, 0xD5, 0x9E, + 0x84, 0x00, 0xDD, 0x45, 0x84, 0x03, 0xEB, 0x00, 0xEA, 0xAB, 0xEA, 0x36, 0xB4, 0x00, 0x92, 0x19, + 0x96, 0x06, 0xC0, 0x0C, 0xEA, 0xCF, 0x84, 0x22, 0xAE, 0x40, 0xDD, 0x49, 0xC8, 0x07, 0xEA, 0xCC, + 0xEA, 0x25, 0x83, 0x81, 0xBA, 0x1C, 0xFE, 0x16, 0xB8, 0x9C, 0xEA, 0x36, 0xB4, 0x00, 0x92, 0x1A, + 0x96, 0x06, 0xC0, 0x0C, 0x44, 0x14, 0x70, 0x08, 0xB4, 0x01, 0x92, 0x10, 0xEA, 0x22, 0x58, 0x00, + 0x78, 0x23, 0xB6, 0x01, 0xEA, 0xCF, 0x84, 0x24, 0xAE, 0x40, 0xEA, 0x36, 0xB4, 0x00, 0x92, 0x1B, + 0x96, 0x06, 0xC0, 0x04, 0xEA, 0xCF, 0x84, 0x28, 0xAE, 0x40, 0xFC, 0x80, 0x44, 0x04, 0x80, 0x04, + 0xB4, 0x00, 0x92, 0x14, 0x96, 0x06, 0xC0, 0x04, 0xEA, 0xC9, 0xFA, 0x20, 0xAE, 0x40, 0xDD, 0x9E, + 0xDD, 0x9E, 0xDD, 0x9E, 0xDD, 0x9E, 0x44, 0x14, 0x80, 0x1C, 0xB4, 0x01, 0x92, 0x03, 0x96, 0x06, + 0xC0, 0x03, 0x84, 0x08, 0xAE, 0x08, 0xDD, 0x9E, 0x44, 0x14, 0x80, 0x1C, 0xB4, 0x01, 0x92, 0x01, + 0x96, 0x06, 0xC0, 0x03, 0x84, 0x02, 0xAE, 0x08, 0xEA, 0x75, 0xB4, 0x00, 0x92, 0x0C, 0x96, 0x06, + 0xC0, 0x04, 0xEB, 0x7D, 0xFA, 0x20, 0xAE, 0x40, 0xDD, 0x9E, 0xFC, 0x00, 0x44, 0x24, 0x80, 0x10, + 0x84, 0x01, 0xB4, 0x22, 0x96, 0x46, 0xC1, 0x0F, 0x3E, 0x07, 0xEB, 0xFC, 0xAE, 0x10, 0xEB, 0xAD, + 0xEA, 0x2C, 0x5A, 0x00, 0x02, 0x07, 0x5A, 0x08, 0x03, 0x07, 0x84, 0x00, 0x3E, 0x07, 0xF0, 0xD8, + 0x84, 0x01, 0xEB, 0xD1, 0xFC, 0x80, 0xFC, 0x00, 0xEA, 0x75, 0xB4, 0x00, 0x92, 0x0A, 0x96, 0x06, + 0xC0, 0x0D, 0xEB, 0x7D, 0x84, 0x24, 0xAE, 0x40, 0x49, 0xFF, 0xCA, 0x31, 0x44, 0x07, 0x20, 0x00, + 0xB4, 0x00, 0x92, 0x08, 0x96, 0x06, 0x49, 0xFF, 0xC9, 0x7A, 0x44, 0x14, 0x80, 0x1C, 0xB4, 0x01, + 0x92, 0x05, 0x96, 0x06, 0xC0, 0x03, 0xFA, 0x10, 0xAE, 0x08, 0xFC, 0x80, 0x44, 0x14, 0x80, 0x10, + 0xB4, 0x01, 0x92, 0x07, 0x96, 0x06, 0xC0, 0x07, 0x44, 0x0F, 0xFF, 0x80, 0xAE, 0x08, 0x84, 0x01, + 0x3E, 0x07, 0xEC, 0x04, 0xDD, 0x9E, 0x44, 0x04, 0x80, 0x10, 0xB4, 0x20, 0x92, 0x25, 0x96, 0x46, + 0xC1, 0x06, 0xFA, 0x30, 0xAE, 0x40, 0x84, 0x21, 0x3E, 0x17, 0xEB, 0xEF, 0xB4, 0x00, 0x92, 0x06, + 0x96, 0x06, 0xC0, 0x08, 0xEA, 0x75, 0x44, 0x10, 0x00, 0x40, 0xAE, 0x40, 0x84, 0x01, 0x3E, 0x07, + 0xEB, 0xED, 0xDD, 0x9E, 0x44, 0x04, 0x80, 0x10, 0xB4, 0x00, 0x92, 0x04, 0x96, 0x06, 0xC0, 0x37, + 0xFC, 0x00, 0xEA, 0x2C, 0x5A, 0x08, 0x02, 0x0F, 0xEA, 0xEE, 0x5A, 0x08, 0x01, 0x0C, 0x3C, 0x03, + 0xF8, 0x66, 0x96, 0x01, 0x3C, 0x0B, 0xF8, 0x64, 0x3C, 0x03, 0xF8, 0x65, 0x96, 0x01, 0x3C, 0x0B, + 0xF8, 0x66, 0xEA, 0x75, 0x84, 0x21, 0xFA, 0x40, 0x3E, 0x17, 0xEB, 0xFD, 0xAE, 0x80, 0x2E, 0x27, + 0xF0, 0xD1, 0x3E, 0x17, 0xF0, 0xDD, 0xEA, 0x87, 0x3E, 0x17, 0xF0, 0xDB, 0x5A, 0x28, 0x02, 0x07, + 0xEB, 0xF4, 0x92, 0x0B, 0x96, 0x27, 0xC8, 0x0B, 0xD5, 0x09, 0x5A, 0x28, 0x03, 0x09, 0xEB, 0xF4, + 0x92, 0x0B, 0x96, 0x27, 0xC8, 0x04, 0x3E, 0x17, 0xF0, 0xD8, 0xEB, 0xD1, 0xEA, 0x87, 0x04, 0x00, + 0x00, 0xF0, 0x92, 0x03, 0x96, 0x06, 0x49, 0xFF, 0xC9, 0x12, 0xFC, 0x80, 0xDD, 0x9E, 0x44, 0x04, + 0x80, 0x10, 0xB4, 0x20, 0x92, 0x23, 0x96, 0x46, 0xC1, 0x03, 0x84, 0x28, 0xAE, 0x40, 0xB4, 0x00, + 0x92, 0x02, 0x96, 0x06, 0xC0, 0x04, 0xEA, 0x75, 0x84, 0x24, 0xAE, 0x40, 0x44, 0x04, 0x80, 0x1C, + 0xB4, 0x20, 0x96, 0x46, 0xC1, 0x03, 0x84, 0x21, 0xAE, 0x40, 0xB4, 0x00, 0x92, 0x06, 0x96, 0x06, + 0xC0, 0x06, 0x44, 0x04, 0x80, 0x1C, 0x44, 0x10, 0x00, 0x40, 0xAE, 0x40, 0xDD, 0x9E, 0x44, 0x14, + 0x80, 0x10, 0xB4, 0x01, 0x92, 0x01, 0x96, 0x06, 0xC0, 0x0B, 0x44, 0x04, 0x80, 0x90, 0xB4, 0x00, + 0x92, 0x01, 0x96, 0x06, 0x5A, 0x08, 0x01, 0x05, 0x84, 0x42, 0xAE, 0x88, 0xEB, 0xAE, 0xDD, 0x9E, + 0xFC, 0x00, 0xEA, 0x75, 0xB4, 0x00, 0x92, 0x0B, 0x96, 0x06, 0xC0, 0x06, 0xEB, 0x7D, 0x84, 0x28, + 0xAE, 0x40, 0x49, 0xFF, 0xC9, 0x8F, 0x44, 0x14, 0x80, 0x1C, 0xB4, 0x01, 0x92, 0x04, 0x96, 0x06, + 0xC0, 0x03, 0xFA, 0x00, 0xAE, 0x08, 0xFC, 0x80, 0x3C, 0x1C, 0x05, 0x47, 0xC9, 0x05, 0x44, 0x12, + 0x5F, 0xF8, 0x3C, 0x1E, 0x05, 0x47, 0x9C, 0x07, 0x92, 0x03, 0x94, 0x03, 0x98, 0x08, 0x40, 0x2F, + 0x80, 0x06, 0xCA, 0x05, 0x3C, 0x0E, 0x05, 0x47, 0x80, 0x01, 0xDD, 0x9E, 0x84, 0x0C, 0x3C, 0x0E, + 0x05, 0x48, 0x84, 0x1F, 0xDD, 0x9E, 0x92, 0x00, 0x84, 0x2A, 0xFE, 0x0C, 0x8E, 0x01, 0x5A, 0x07, + 0xFF, 0x05, 0x40, 0x00, 0x00, 0x09, 0xD5, 0xFB, 0xDD, 0x9E, 0x44, 0x15, 0x00, 0x08, 0xB4, 0x21, + 0x96, 0x46, 0xC1, 0x2D, 0x44, 0x25, 0x00, 0x04, 0xB4, 0x22, 0x96, 0x49, 0xC1, 0x28, 0xFC, 0x02, + 0xB4, 0x22, 0x96, 0x49, 0xFE, 0x0C, 0xB6, 0x1F, 0xB4, 0x02, 0x92, 0x10, 0xF0, 0x81, 0x84, 0x00, + 0xF0, 0x83, 0xB4, 0x02, 0x92, 0x10, 0xF0, 0x82, 0xF1, 0x01, 0xF0, 0x02, 0xE2, 0x20, 0xE9, 0x07, + 0xF1, 0x01, 0xF3, 0x02, 0xF0, 0x03, 0x88, 0x01, 0x8A, 0x03, 0xD5, 0x09, 0xF3, 0x01, 0xF4, 0x02, + 0xB4, 0x22, 0xF0, 0x03, 0x96, 0x49, 0x88, 0x03, 0x88, 0x01, 0x8A, 0x04, 0xF0, 0x83, 0xF1, 0x03, + 0xB4, 0x1F, 0xE2, 0x20, 0xE8, 0x0E, 0xF0, 0x02, 0xF0, 0x81, 0xD5, 0xE4, 0x44, 0x10, 0x29, 0xCC, + 0xFE, 0x0C, 0x8E, 0x01, 0x5A, 0x07, 0xFF, 0x05, 0x40, 0x00, 0x00, 0x09, 0xD5, 0xFB, 0xDD, 0x9E, + 0xFC, 0x82, 0xFC, 0x00, 0x49, 0xFF, 0xF9, 0xBB, 0x84, 0x01, 0x49, 0xFF, 0xD2, 0x7A, 0x49, 0xFF, + 0xCB, 0xDD, 0x49, 0xFF, 0xE5, 0x6B, 0x84, 0x01, 0x49, 0xFF, 0xD3, 0xE6, 0xEB, 0x99, 0x49, 0xFF, + 0xDB, 0x96, 0x49, 0xFF, 0xBD, 0xE2, 0x49, 0xFF, 0xC2, 0x00, 0x84, 0x00, 0xFC, 0x80, 0xFC, 0x00, + 0x49, 0xFF, 0xFF, 0xE9, 0x84, 0x00, 0xFC, 0x80, 0x84, 0x80, 0xD5, 0x2D, 0x40, 0xA1, 0x40, 0x09, + 0x97, 0x41, 0x92, 0x10, 0x40, 0x40, 0xA8, 0x37, 0x96, 0xD1, 0x40, 0x10, 0xC0, 0x08, 0xFE, 0x47, + 0x42, 0x02, 0x0C, 0x24, 0xE2, 0x20, 0xE8, 0x09, 0x9F, 0x21, 0x98, 0x4A, 0xE2, 0x22, 0xE9, 0x05, + 0xE2, 0x20, 0xE8, 0x03, 0x9F, 0x21, 0x98, 0x4A, 0x9A, 0x48, 0x40, 0x10, 0xA8, 0x17, 0x40, 0x00, + 0x40, 0x08, 0xFE, 0x2F, 0xFE, 0xCC, 0xE2, 0x03, 0xE8, 0x09, 0x98, 0x02, 0x9E, 0x49, 0xE2, 0x02, + 0xE9, 0x05, 0xE2, 0x03, 0xE8, 0x03, 0x98, 0x02, 0x9E, 0x49, 0x9A, 0x03, 0x40, 0x42, 0x40, 0x08, + 0xFE, 0x67, 0xDD, 0x9E, 0xEF, 0xD8, 0x3A, 0x6F, 0xAA, 0xA0, 0xFD, 0x30, 0xFD, 0x41, 0x83, 0x84, + 0xCB, 0x51, 0xE2, 0xE8, 0xE8, 0x1A, 0x80, 0x08, 0x49, 0x00, 0x00, 0xE0, 0xF0, 0x87, 0xC0, 0x0C, + 0x40, 0x84, 0x00, 0x0C, 0x52, 0x50, 0x00, 0x20, 0x40, 0x53, 0x14, 0x0D, 0x40, 0x73, 0x80, 0x0C, + 0xFF, 0xEF, 0x40, 0x63, 0x00, 0x0C, 0xFD, 0x03, 0x80, 0x48, 0x49, 0xFF, 0xFF, 0xB9, 0xF1, 0x88, + 0x80, 0xC0, 0x84, 0xA0, 0xF5, 0x89, 0xD5, 0x25, 0xC2, 0x2C, 0x80, 0x08, 0x49, 0x00, 0x00, 0xC6, + 0xF0, 0x87, 0xC8, 0x05, 0x8A, 0xE8, 0x84, 0xA1, 0xF5, 0x89, 0xD5, 0x14, 0x52, 0xF0, 0x00, 0x20, + 0x40, 0x84, 0x00, 0x0C, 0x80, 0x48, 0x40, 0x43, 0x3C, 0x0D, 0x40, 0x53, 0x80, 0x0C, 0x40, 0x63, + 0x00, 0x0C, 0x40, 0x02, 0x90, 0x04, 0x40, 0x13, 0xBC, 0x0D, 0x49, 0xFF, 0xFF, 0x99, 0xF1, 0x89, + 0x80, 0xE0, 0xFD, 0x03, 0x80, 0x48, 0x49, 0xFF, 0xFF, 0x93, 0xF1, 0x88, 0x50, 0x60, 0x00, 0x00, + 0x4F, 0xC2, 0x00, 0x55, 0xF3, 0x07, 0x44, 0x70, 0x00, 0x00, 0x40, 0x63, 0x0C, 0x0D, 0xD5, 0x4C, + 0x40, 0x74, 0x20, 0xD7, 0x84, 0x20, 0x84, 0x00, 0x4F, 0xC2, 0x00, 0x4C, 0xB6, 0xDC, 0xBF, 0x81, + 0xD5, 0x48, 0xE2, 0xE9, 0xE9, 0xF8, 0x80, 0x09, 0x49, 0x00, 0x00, 0x90, 0xF0, 0x87, 0xC0, 0x45, + 0x52, 0x40, 0x00, 0x20, 0x40, 0x54, 0x10, 0x0D, 0x40, 0x24, 0x80, 0x0C, 0xFE, 0xAF, 0x81, 0x22, + 0x40, 0x84, 0x00, 0x0C, 0x40, 0x33, 0x10, 0x0D, 0x40, 0x63, 0x00, 0x0C, 0x40, 0x03, 0x80, 0x0C, + 0x40, 0x13, 0x90, 0x0D, 0xFE, 0x1F, 0x49, 0xFF, 0xFF, 0x63, 0xF1, 0x88, 0x80, 0xE0, 0x80, 0x08, + 0x49, 0x00, 0x00, 0x84, 0xE2, 0xE1, 0xE9, 0x05, 0x4C, 0x13, 0xC0, 0x0D, 0xE2, 0xC0, 0xE8, 0x0A, + 0xF3, 0x08, 0x8A, 0x29, 0x9E, 0xD9, 0xF3, 0x88, 0x40, 0x30, 0x20, 0x01, 0xE2, 0x03, 0x8A, 0x2F, + 0x80, 0x03, 0x84, 0x60, 0xF3, 0x89, 0x4F, 0xC2, 0x00, 0x12, 0x9A, 0x30, 0x9A, 0x79, 0xE2, 0xC0, + 0x8A, 0x2F, 0xF3, 0x07, 0x52, 0x41, 0x80, 0x20, 0x40, 0x70, 0x90, 0x0C, 0x40, 0x60, 0x0C, 0x0D, + 0xFF, 0xBF, 0x40, 0x70, 0x8C, 0x0D, 0xB6, 0xDC, 0xBF, 0x81, 0xF0, 0x08, 0x04, 0x1F, 0x80, 0x09, + 0x3A, 0x6F, 0xAA, 0x80, 0xEC, 0x28, 0xDD, 0x9E, 0x84, 0x60, 0xE3, 0x27, 0xE9, 0x03, 0xE2, 0xC8, + 0xE9, 0x0A, 0x84, 0xA1, 0xF5, 0x88, 0x40, 0x43, 0x20, 0x01, 0x8A, 0xE9, 0xE2, 0xC4, 0x8A, 0xEF, + 0x80, 0xC4, 0xD5, 0x02, 0xF3, 0x88, 0xF3, 0x89, 0x4F, 0xC3, 0xFF, 0xE7, 0xD5, 0xE7, 0x92, 0x00, + 0x42, 0x50, 0x88, 0x24, 0x40, 0x10, 0x40, 0x09, 0x42, 0x50, 0x0C, 0x73, 0x96, 0x01, 0x40, 0x31, + 0x40, 0x09, 0x96, 0x91, 0x42, 0xF0, 0x0C, 0x24, 0x42, 0x40, 0x08, 0x24, 0xFE, 0x8C, 0x40, 0x07, + 0x88, 0x00, 0xE2, 0x02, 0x40, 0xF7, 0xC0, 0x08, 0x40, 0x20, 0x40, 0x08, 0x42, 0xF0, 0x8C, 0x73, + 0x40, 0x10, 0x40, 0x09, 0x88, 0x2F, 0x98, 0x22, 0xE2, 0x04, 0x88, 0x2F, 0x98, 0x4D, 0xDD, 0x9E, + 0xC2, 0x12, 0x52, 0x31, 0x00, 0x20, 0x4E, 0x36, 0x00, 0x07, 0xFE, 0xDA, 0x84, 0x80, 0x40, 0x10, + 0x0C, 0x0C, 0xD5, 0x08, 0x40, 0x30, 0x0C, 0x0D, 0x40, 0x10, 0x88, 0x0C, 0x40, 0x40, 0x08, 0x0C, + 0xFE, 0x5F, 0x80, 0x04, 0xDD, 0x9E, 0x00, 0x00, 0xC0, 0x0E, 0xFA, 0x20, 0xFA, 0x6F, 0x9B, 0x19, + 0x40, 0x20, 0x04, 0x0D, 0x40, 0x32, 0x08, 0x1B, 0x40, 0x01, 0x08, 0x1B, 0x92, 0x21, 0xC9, 0xF8, + 0x80, 0x03, 0xDD, 0x9E, 0xFA, 0x10, 0xDD, 0x9E, 0x96, 0x81, 0x40, 0x30, 0x40, 0x09, 0x96, 0x09, + 0x92, 0x30, 0x42, 0x51, 0x04, 0x24, 0xFE, 0x84, 0xFE, 0x1C, 0x99, 0x68, 0xE2, 0xA0, 0x40, 0xF7, + 0xC0, 0x08, 0x42, 0xF1, 0x84, 0x73, 0x40, 0x12, 0xC0, 0x09, 0x88, 0x2F, 0x40, 0x02, 0xC0, 0x08, + 0x98, 0x02, 0xE2, 0x02, 0x88, 0x2F, 0xDD, 0x9E, 0xFC, 0x01, 0xF0, 0x81, 0xF1, 0x01, 0x84, 0x00, + 0x49, 0x00, 0x00, 0x92, 0xFC, 0x81, 0xFC, 0x01, 0xF0, 0x81, 0xF1, 0x01, 0x84, 0x00, 0x49, 0x00, + 0x00, 0x51, 0xFC, 0x81, 0x80, 0x60, 0xE6, 0x44, 0xE9, 0x1C, 0x54, 0x41, 0x80, 0x03, 0x54, 0x50, + 0x80, 0x03, 0xDC, 0x17, 0x4E, 0x52, 0x00, 0x0C, 0x52, 0x52, 0x80, 0x04, 0x9A, 0x95, 0x99, 0x69, + 0x08, 0x40, 0x80, 0x01, 0x18, 0x41, 0x80, 0x01, 0x4C, 0x12, 0xFF, 0xFC, 0x40, 0x51, 0x08, 0x09, + 0xC5, 0x08, 0x95, 0x6A, 0x99, 0x69, 0x96, 0x8F, 0xA3, 0x09, 0xAB, 0x19, 0x4C, 0x12, 0xFF, 0xFE, + 0xC2, 0x08, 0x99, 0x4A, 0x08, 0x40, 0x80, 0x01, 0x18, 0x41, 0x80, 0x01, 0x4C, 0x12, 0xFF, 0xFC, + 0xDD, 0x9E, 0x92, 0x00, 0x80, 0x60, 0xE6, 0x44, 0xE9, 0x1C, 0x54, 0x51, 0x80, 0x03, 0xC5, 0x09, + 0x52, 0x52, 0x80, 0x04, 0x9A, 0x95, 0x99, 0x68, 0x18, 0x11, 0x80, 0x01, 0x4C, 0x32, 0xFF, 0xFE, + 0x96, 0x48, 0x40, 0x40, 0xA0, 0x08, 0xFE, 0x67, 0x40, 0x40, 0xC0, 0x08, 0x40, 0x10, 0x90, 0x04, + 0x40, 0x51, 0x08, 0x09, 0xC5, 0x06, 0x95, 0x6A, 0x99, 0x6B, 0x96, 0x8F, 0xAA, 0x59, 0xDB, 0xFF, + 0xC2, 0x06, 0x99, 0x5A, 0x18, 0x11, 0x80, 0x01, 0x4C, 0x32, 0xFF, 0xFE, 0xDD, 0x9E, 0x92, 0x00, + 0xC1, 0x39, 0x9E, 0x0C, 0x04, 0x10, 0xFF, 0xFF, 0x4E, 0x14, 0x00, 0x03, 0x88, 0x01, 0x3C, 0x1C, + 0x05, 0x4A, 0xC1, 0x0A, 0xE2, 0x01, 0xE8, 0x0F, 0xB4, 0x40, 0x99, 0x42, 0xD9, 0x05, 0xB4, 0x25, + 0x88, 0x22, 0xB6, 0x20, 0xA0, 0x69, 0xA8, 0x41, 0x3C, 0x0E, 0x05, 0x4A, 0xDD, 0x9E, 0xE2, 0x02, + 0xE9, 0x04, 0x80, 0x22, 0xA0, 0x89, 0xCA, 0xFC, 0xB4, 0x61, 0x99, 0x4B, 0xD8, 0x0C, 0xB4, 0x00, + 0x80, 0xA1, 0x88, 0x03, 0x38, 0x02, 0x80, 0x0E, 0xDA, 0x15, 0xB4, 0x62, 0x88, 0x03, 0xB6, 0x01, + 0xA0, 0x11, 0xD5, 0x0F, 0xE2, 0x05, 0xE8, 0x05, 0x84, 0x0C, 0x3C, 0x0E, 0x05, 0x48, 0xDD, 0x9E, + 0xB4, 0x80, 0x99, 0x44, 0xDA, 0x05, 0xB4, 0x62, 0xA0, 0x91, 0x88, 0x64, 0xB6, 0x60, 0xA8, 0x81, + 0xA8, 0x09, 0xDD, 0x9E, 0xFC, 0x21, 0x9D, 0x8B, 0x84, 0x5C, 0xFF, 0x96, 0x8C, 0xC8, 0xE6, 0xCC, + 0xE8, 0x03, 0x84, 0xCC, 0xD5, 0x08, 0x4E, 0x64, 0x00, 0x07, 0x84, 0x0C, 0x3C, 0x0E, 0x05, 0x48, + 0x84, 0x00, 0xD5, 0x43, 0xE2, 0xC1, 0xE9, 0xFA, 0x3C, 0x5C, 0x05, 0x4A, 0x80, 0x25, 0xC1, 0x0C, + 0xB4, 0x41, 0x8A, 0x46, 0x4E, 0x25, 0x00, 0x1B, 0xE6, 0x4C, 0xE9, 0x0F, 0x80, 0xA1, 0x38, 0x22, + 0x88, 0x0E, 0xB6, 0xC5, 0xCD, 0x28, 0x3C, 0x1C, 0x05, 0x49, 0xF0, 0x81, 0xC9, 0x12, 0xF0, 0x01, + 0xEB, 0xDD, 0x3C, 0x0E, 0x05, 0x49, 0xD5, 0x0D, 0xD9, 0x05, 0xA0, 0x29, 0x3C, 0x0E, 0x05, 0x4A, + 0xD5, 0x1A, 0xA0, 0x09, 0xA8, 0x29, 0x80, 0xA1, 0xD5, 0x16, 0x80, 0xA1, 0xA0, 0x49, 0xD5, 0xE0, + 0xF0, 0x01, 0x80, 0x26, 0xEB, 0xDD, 0x80, 0xA0, 0x5A, 0x07, 0xFF, 0xD1, 0x9D, 0xC3, 0x84, 0x1C, + 0xFF, 0xC6, 0x4C, 0x72, 0x80, 0x08, 0xF0, 0x01, 0x9A, 0x7D, 0xEB, 0xDD, 0x5A, 0x07, 0xFF, 0xC7, + 0x80, 0xA7, 0xB6, 0xC5, 0x50, 0x22, 0x80, 0x0B, 0x84, 0x18, 0x9C, 0x6C, 0xFE, 0x16, 0x9A, 0x41, + 0xC1, 0x04, 0xFE, 0x8A, 0x38, 0x22, 0x84, 0x0A, 0xFC, 0xA1, 0xFC, 0x00, 0x84, 0x00, 0x3C, 0x0F, + 0xFB, 0x66, 0x80, 0x01, 0x49, 0xFF, 0xFD, 0x5A, 0x5A, 0x0F, 0xFF, 0x07, 0x3C, 0x1D, 0xFB, 0x66, + 0xC1, 0x03, 0x3C, 0x1E, 0x05, 0x48, 0xFC, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x49, 0x00, 0x8F, 0x4A, 0x49, 0x00, 0x71, 0xD9, 0x50, 0x00, 0x0F, 0xFF, 0x49, 0x00, 0x6C, 0x1E, + 0x49, 0x00, 0x58, 0x2D, 0x49, 0x00, 0x7F, 0x84, 0x3C, 0x0D, 0xFB, 0x5B, 0x49, 0x00, 0x87, 0xA1, + 0x2E, 0x07, 0xF8, 0x76, 0x49, 0x00, 0x53, 0xB5, 0x49, 0x00, 0x6C, 0x77, 0x58, 0x00, 0x00, 0x01, + 0x44, 0x00, 0x00, 0x64, 0x49, 0x00, 0x3C, 0x2D, 0x49, 0x00, 0x66, 0x9D, 0x3C, 0x1D, 0xFB, 0x5B, + 0x2E, 0x07, 0xF0, 0xDA, 0x2E, 0x00, 0x03, 0x2F, 0x40, 0x00, 0x20, 0x08, 0x2E, 0x07, 0xF8, 0x75, + 0x3C, 0x03, 0xEF, 0x78, 0x49, 0x00, 0x8F, 0x22, 0x40, 0x10, 0x20, 0x08, 0x44, 0x00, 0x01, 0x0C, + 0x49, 0x00, 0x4B, 0xC7, 0x48, 0x00, 0x77, 0xE3, 0x00, 0x03, 0x00, 0xBF, 0x49, 0x00, 0x7F, 0x23, + 0x40, 0x00, 0x04, 0x16, 0x49, 0x00, 0x65, 0xD7, 0x46, 0x20, 0x00, 0x81, 0x48, 0x00, 0x77, 0xE5, + 0x49, 0x00, 0x6B, 0xA9, 0x40, 0x00, 0x28, 0x08, 0x40, 0x00, 0x40, 0x08, 0x3C, 0x0F, 0xFB, 0x5B, + 0x40, 0x10, 0x40, 0x08, 0x44, 0x0F, 0xFE, 0xFF, 0x49, 0x00, 0x7E, 0xF8, 0x42, 0x13, 0x80, 0x73, + 0x40, 0x10, 0xC0, 0x08, 0x44, 0x0E, 0xFF, 0xFF, 0x49, 0x00, 0x66, 0xB3, 0x50, 0x10, 0x8F, 0xFF, + 0x2E, 0x07, 0xF0, 0xD1, 0x49, 0x00, 0x8D, 0x74, 0x3C, 0x13, 0xEF, 0x78, 0x49, 0x00, 0x7E, 0x22, + 0x49, 0x00, 0x6B, 0x7D, 0x49, 0x00, 0x87, 0x93, 0x49, 0x00, 0x87, 0xBA, 0x41, 0xFF, 0x80, 0x01, + 0x49, 0x00, 0x77, 0xE9, 0x49, 0x00, 0x7E, 0xFA, 0x44, 0x04, 0x80, 0x08, 0x2E, 0x07, 0xF0, 0xDD, + 0x49, 0x00, 0x7E, 0x56, 0x58, 0x00, 0x00, 0x02, 0x49, 0x00, 0x7E, 0xFD, 0x49, 0x00, 0x61, 0x65, + 0x2E, 0x00, 0x03, 0x33, 0x49, 0x00, 0x13, 0xDC, 0x2E, 0x06, 0xF3, 0xAE, 0x3E, 0x07, 0xF0, 0xD4, + 0x49, 0x00, 0x7F, 0x96, 0x44, 0x12, 0x22, 0x98, 0x49, 0x00, 0x56, 0x97, 0x44, 0x04, 0x80, 0x03, + 0x48, 0x00, 0x77, 0xDE, 0x44, 0x02, 0x50, 0x30, 0x49, 0x00, 0x65, 0x99, 0x2E, 0x07, 0xF2, 0x17, + 0x2E, 0x07, 0xF0, 0xFC, 0x44, 0x30, 0x01, 0x0C, 0x49, 0x00, 0x7E, 0x66, 0x3C, 0x13, 0xF6, 0xD8, + 0x49, 0x00, 0x7F, 0xC9, 0x3A, 0x20, 0x14, 0x04, 0x2E, 0x06, 0xF3, 0xC0, 0x40, 0x10, 0xA0, 0x08, + 0x44, 0x02, 0x50, 0x5C, 0x00, 0x03, 0x00, 0xDC, 0x49, 0x00, 0x60, 0x5D, 0x40, 0x10, 0x80, 0x36, + 0x49, 0x00, 0x46, 0x27, 0x12, 0x03, 0x00, 0x08, 0x46, 0x60, 0x00, 0x81, 0x49, 0x00, 0x56, 0x28, + 0x3C, 0x0B, 0xF8, 0x2D, 0x44, 0x10, 0x00, 0x96, 0x44, 0x00, 0x01, 0x00, 0x3A, 0x20, 0x14, 0x24, + 0x3A, 0x20, 0x14, 0x20, 0x49, 0x00, 0x6E, 0xD1, 0x44, 0x01, 0x00, 0x00, 0x46, 0x0F, 0xEF, 0xFF, + 0x49, 0x00, 0x65, 0xA0, 0x2E, 0x07, 0xF1, 0x37, 0x10, 0x03, 0x00, 0xDC, 0x44, 0x10, 0x02, 0x88, + 0x49, 0x00, 0x29, 0xBE, 0x58, 0x00, 0x00, 0x10, 0x04, 0x03, 0x00, 0x37, 0x54, 0x10, 0x82, 0x00, + 0x49, 0x00, 0x5D, 0xF9, 0x54, 0x00, 0x0F, 0xFF, 0x3C, 0x13, 0xF6, 0xC8, 0x3C, 0x0B, 0xEF, 0x78, + 0x2E, 0x07, 0xF0, 0xD4, 0x49, 0x00, 0x86, 0x9B, 0x3C, 0x03, 0xF6, 0xC9, 0x3C, 0x03, 0x79, 0xD5, + 0x3A, 0x20, 0x94, 0x00, 0x54, 0x80, 0x00, 0xFF, 0x49, 0x00, 0x06, 0xA6, 0x14, 0x01, 0x00, 0x12, + 0x48, 0x00, 0x31, 0x4F, 0x44, 0x04, 0x80, 0x10, 0x44, 0x10, 0x01, 0x0C, 0x49, 0x00, 0x72, 0x6B, + 0x44, 0x12, 0x4B, 0x2C, 0x3E, 0x00, 0x03, 0x2F, 0x49, 0x00, 0x87, 0x98, 0x3E, 0x07, 0xF0, 0xDD, + 0x50, 0x04, 0x80, 0x01, 0x2E, 0x17, 0xF8, 0x75, 0x02, 0x03, 0x00, 0x61, 0x3C, 0x03, 0xF6, 0xD8, + 0x49, 0x00, 0x68, 0x31, 0x49, 0x00, 0x6B, 0x7B, 0x54, 0x90, 0x00, 0xFF, 0x49, 0x00, 0x60, 0x53, + 0x10, 0x0E, 0x7E, 0xEC, 0x46, 0x0F, 0xDF, 0xFF, 0x00, 0x03, 0x00, 0xBE, 0x46, 0x00, 0x00, 0x81, + 0x3A, 0x20, 0x94, 0x04, 0x04, 0x31, 0x00, 0x12, 0x3E, 0x07, 0xF2, 0x21, 0x42, 0x04, 0x84, 0x73, + 0x2E, 0x07, 0xEE, 0x20, 0x49, 0x00, 0x06, 0xAC, 0x10, 0x0F, 0x80, 0x07, 0x40, 0x00, 0x30, 0x08, + 0x48, 0x00, 0x48, 0x2C, 0x48, 0x00, 0x4F, 0xE4, 0x44, 0x10, 0x00, 0x64, 0x58, 0x00, 0x00, 0x20, + 0x44, 0x12, 0x50, 0x30, 0x49, 0x00, 0x5D, 0xCD, 0x49, 0x00, 0x7D, 0xB8, 0x49, 0x00, 0x46, 0x10, + 0x54, 0x00, 0x02, 0x00, 0x2E, 0x07, 0xF0, 0xE5, 0x49, 0x00, 0x7B, 0x76, 0x3E, 0x07, 0xE9, 0xB8, + 0x44, 0x00, 0x02, 0x88, 0x44, 0x20, 0x01, 0x0C, 0x2E, 0x07, 0xF0, 0xC3, 0x3A, 0x20, 0x94, 0x24, + 0x10, 0x0F, 0x80, 0x04, 0x58, 0x00, 0x01, 0x00, 0x49, 0x00, 0x57, 0xA9, 0x44, 0x0F, 0xFF, 0xEF, + 0x3E, 0x07, 0xF2, 0x34, 0x58, 0x00, 0x00, 0x04, 0x40, 0x00, 0x08, 0x16, 0x44, 0x20, 0x00, 0x30, + 0x2E, 0x07, 0xF2, 0x23, 0x44, 0x22, 0x50, 0x30, 0x44, 0x14, 0x70, 0x00, 0x49, 0x00, 0x83, 0x83, + 0x49, 0x00, 0x5C, 0xE0, 0x40, 0x10, 0x04, 0x0A, 0x44, 0x04, 0x80, 0x01, 0x2E, 0x07, 0xF2, 0x2E, + 0x49, 0x00, 0x61, 0x60, 0x42, 0x01, 0x04, 0x73, 0x44, 0x04, 0x80, 0x09, 0x49, 0x00, 0x51, 0x7F, + 0x49, 0x00, 0x8D, 0x7D, 0x3C, 0x0B, 0xF8, 0x2C, 0x48, 0x00, 0x41, 0xFF, 0x42, 0x00, 0x88, 0x73, + 0x44, 0x00, 0x00, 0x40, 0x49, 0x00, 0x0B, 0x37, 0x48, 0x00, 0x24, 0xEB, 0x2E, 0x06, 0xF3, 0xAF, + 0x54, 0x10, 0x83, 0xFF, 0x44, 0x72, 0x50, 0x30, 0x49, 0x00, 0x29, 0x77, 0x2E, 0x17, 0xF8, 0x76, + 0x2E, 0x07, 0xF2, 0x1A, 0x49, 0x00, 0x5C, 0x58, 0x3E, 0x97, 0xEA, 0x53, 0x49, 0x00, 0x52, 0x2B, + 0x49, 0x00, 0x74, 0x74, 0x44, 0x14, 0x50, 0x10, 0x40, 0x01, 0xA0, 0x0A, 0x44, 0x10, 0xC0, 0x0C, + 0x49, 0x00, 0x52, 0xC4, 0x44, 0x04, 0x80, 0x06, 0x49, 0x00, 0x60, 0x67, 0x50, 0x05, 0x00, 0x01, + 0x46, 0x10, 0x00, 0x81, 0x40, 0x31, 0xA0, 0x08, 0x2E, 0x10, 0x15, 0x49, 0x44, 0x04, 0x80, 0x0B, + 0x38, 0x00, 0x9D, 0x09, 0x3C, 0x13, 0xF6, 0xC9, 0x49, 0x00, 0x5C, 0x8E, 0x49, 0x00, 0x56, 0xAE, + 0x49, 0x00, 0x56, 0xC2, 0x40, 0x00, 0xBC, 0x1A, 0x22, 0x03, 0x00, 0x08, 0x3E, 0x07, 0xF0, 0xBF, + 0x5C, 0x00, 0x00, 0x01, 0x49, 0x00, 0x73, 0x40, 0x3C, 0x0C, 0x05, 0xB4, 0x49, 0x00, 0x70, 0x3E, + 0x3C, 0x0B, 0xF6, 0xD8, 0x49, 0x00, 0x01, 0x9F, 0x44, 0x20, 0x00, 0x48, 0x54, 0x00, 0x10, 0x00, + 0x40, 0x10, 0x60, 0x08, 0x2E, 0x26, 0xF3, 0xAF, 0x49, 0x00, 0x7D, 0xF1, 0x04, 0x0E, 0x7F, 0xB2, + 0x04, 0x0E, 0x7F, 0xB6, 0x44, 0x20, 0x00, 0x64, 0x40, 0x10, 0x8C, 0x36, 0x44, 0x24, 0x00, 0x10, + 0x00, 0x10, 0x80, 0xEB, 0x49, 0x00, 0x87, 0x4C, 0x42, 0x20, 0x0C, 0x73, 0x49, 0x00, 0x5D, 0x1D, + 0x49, 0x00, 0x6C, 0x14, 0x40, 0x30, 0x3C, 0x1B, 0x2E, 0x07, 0xF0, 0xD0, 0x3E, 0x07, 0xF2, 0x1A, + 0x44, 0x00, 0x00, 0xFF, 0x49, 0x00, 0x67, 0x9C, 0x44, 0x04, 0x80, 0x07, 0x14, 0x0E, 0x7F, 0xF4, + 0x49, 0x00, 0x56, 0x2B, 0x40, 0x01, 0x20, 0x0A, 0x50, 0x00, 0x00, 0x2C, 0x44, 0x04, 0x80, 0x0A, + 0x2E, 0x07, 0xEA, 0x4C, 0x49, 0x00, 0x65, 0x8C, 0x49, 0x00, 0x7D, 0xC4, 0x3E, 0x07, 0xF0, 0xFC, + 0x50, 0x0F, 0x82, 0x3C, 0x44, 0x13, 0x00, 0x30, 0x49, 0x00, 0x61, 0x55, 0x2E, 0x07, 0xF2, 0x08, + 0x2E, 0x17, 0xF2, 0x23, 0x46, 0x10, 0x20, 0x00, 0x50, 0x04, 0x00, 0x01, 0x49, 0x00, 0x70, 0xAB, + 0x49, 0x00, 0x7E, 0x4E, 0x40, 0x00, 0x1C, 0x0C, 0x40, 0x00, 0x70, 0x08, 0x49, 0x00, 0x68, 0xAC, + 0x04, 0x0E, 0x7F, 0xB7, 0x3C, 0x17, 0xF8, 0x9D, 0x3E, 0x07, 0xF2, 0x35, 0x00, 0x0E, 0x7E, 0xE1, + 0x44, 0x00, 0x30, 0x03, 0x2E, 0x20, 0x03, 0x31, 0x00, 0x0F, 0x80, 0x07, 0x10, 0x0F, 0x80, 0x05, + 0x49, 0x00, 0x53, 0xD3, 0x50, 0x21, 0x0F, 0xFF, 0x40, 0x00, 0x0C, 0x16, 0x49, 0x00, 0x66, 0x23, + 0x50, 0x0E, 0x7E, 0xE4, 0x3C, 0x03, 0xEA, 0x07, 0x49, 0x00, 0x67, 0x2F, 0x40, 0x00, 0x50, 0x08, + 0x49, 0x00, 0x61, 0x82, 0x49, 0x00, 0x4B, 0x67, 0x46, 0x00, 0x40, 0x00, 0x44, 0x92, 0x50, 0x30, + 0x2E, 0x17, 0xF0, 0x08, 0x14, 0x1E, 0x7F, 0xF3, 0x3E, 0x07, 0xF0, 0xE4, 0x42, 0x13, 0x00, 0x73, + 0x3E, 0x07, 0xF2, 0x01, 0x14, 0x0E, 0x7F, 0xF1, 0x44, 0x22, 0x22, 0x98, 0x44, 0xF0, 0x00, 0x64, + 0x40, 0x10, 0x90, 0x36, 0x3C, 0x0B, 0xF8, 0x2B, 0x14, 0x01, 0x00, 0x10, 0x56, 0x07, 0x80, 0x01, + 0x40, 0x10, 0x28, 0x08, 0x3C, 0x0B, 0xF8, 0x67, 0x40, 0xFE, 0x00, 0x07, 0x64, 0x00, 0x00, 0x20, + 0x46, 0x00, 0x20, 0x00, 0x49, 0x00, 0x72, 0x51, 0x2E, 0x00, 0x12, 0xDA, 0x3C, 0x03, 0xF6, 0xD5, + 0x3E, 0x07, 0xED, 0xC7, 0x00, 0x03, 0x01, 0x04, 0x49, 0x00, 0x58, 0x3E, 0x40, 0x31, 0x9C, 0x76, + 0x22, 0x13, 0x00, 0x07, 0x3C, 0x0D, 0xFA, 0xD3, 0x3E, 0x07, 0xF0, 0xFB, 0x38, 0x00, 0x04, 0x00, + 0x3E, 0x07, 0xF0, 0xC3, 0x22, 0x03, 0x00, 0x06, 0x46, 0x00, 0x10, 0x00, 0x3C, 0x03, 0xEC, 0x85, + 0x44, 0x02, 0x22, 0x98, 0x10, 0x03, 0x00, 0xE4, 0x40, 0x01, 0xBC, 0x1A, 0x44, 0x10, 0x00, 0xFF, + 0x49, 0x00, 0x58, 0xE9, 0x49, 0x00, 0x58, 0xF3, 0x50, 0x1F, 0x81, 0x7C, 0x49, 0x00, 0x29, 0xB5, + 0x3C, 0x27, 0xF8, 0x9D, 0x3E, 0x07, 0xEB, 0xCC, 0x49, 0x00, 0x7D, 0x6A, 0x44, 0x11, 0x00, 0x00, + 0x2E, 0x07, 0xE9, 0xB8, 0x50, 0x63, 0x01, 0x0C, 0x49, 0x00, 0x00, 0xB5, 0x3C, 0x0C, 0x00, 0xE8, + 0x49, 0x00, 0x0C, 0xBE, 0x2E, 0x00, 0x1B, 0xB8, 0x49, 0x00, 0x0B, 0x0A, 0x40, 0x10, 0xB0, 0x08, + 0x04, 0x0E, 0x7F, 0xF3, 0x44, 0x20, 0x05, 0x10, 0x44, 0x14, 0x24, 0x1C, 0x04, 0x0E, 0x7F, 0xF7, + 0x44, 0x10, 0x7F, 0xFF, 0x49, 0x00, 0x52, 0x9F, 0x40, 0x10, 0x3C, 0x1A, 0x54, 0x10, 0x00, 0x0F, + 0x50, 0x2E, 0x7E, 0xEC, 0x38, 0x10, 0x18, 0x08, 0x3C, 0x03, 0xF8, 0x2C, 0x44, 0x00, 0x7F, 0xFF, + 0x3A, 0x27, 0x94, 0x24, 0x00, 0x03, 0x00, 0xC0, 0x14, 0x0E, 0x7F, 0xBA, 0x54, 0x00, 0x00, 0xF0, + 0x49, 0x00, 0x57, 0x26, 0x2E, 0x07, 0xDE, 0xEC, 0x40, 0x10, 0x30, 0x09, 0x3C, 0x0D, 0xF6, 0x53, + 0x3A, 0x23, 0x14, 0x04, 0x3E, 0x07, 0xF2, 0x1E, 0x44, 0x00, 0x00, 0x3C, 0x44, 0x00, 0x00, 0x96, + 0x49, 0x00, 0x53, 0x15, 0x42, 0x10, 0x08, 0x73, 0x58, 0x00, 0x00, 0x08, 0x50, 0x00, 0x05, 0x10, + 0x49, 0x00, 0x70, 0x56, 0x3E, 0x07, 0xEE, 0x19, 0x49, 0x00, 0x72, 0x77, 0x3E, 0x07, 0xF0, 0xE5, + 0x22, 0x14, 0x00, 0x01, 0x2E, 0x67, 0xF0, 0xBF, 0x46, 0x10, 0x00, 0x80, 0x49, 0x00, 0x6F, 0x00, + 0x44, 0x0F, 0xFD, 0xFF, 0x58, 0x00, 0x10, 0x00, 0x3E, 0x07, 0xEA, 0x50, 0x2E, 0x00, 0x12, 0xDB, + 0x3E, 0x07, 0xF2, 0x2D, 0x49, 0x00, 0x5E, 0xF5, 0x50, 0x52, 0x81, 0x0C, 0x3C, 0x0D, 0xFA, 0xD2, + 0x5C, 0xF0, 0x00, 0x3F, 0x44, 0x04, 0x80, 0x11, 0x49, 0x00, 0x29, 0xCB, 0x10, 0x03, 0x00, 0xBF, + 0x40, 0x00, 0x04, 0x0C, 0x3E, 0x07, 0xF2, 0x1F, 0x49, 0x00, 0x7D, 0xF9, 0x38, 0x10, 0x80, 0x00, + 0x40, 0x10, 0x10, 0x09, 0x51, 0xC3, 0x0E, 0x94, 0x51, 0xFE, 0x7F, 0xE0, 0x44, 0x02, 0x50, 0x04, + 0x40, 0x00, 0x80, 0x16, 0x49, 0x00, 0x52, 0x4B, 0x58, 0x21, 0x00, 0x01, 0x49, 0x00, 0x5B, 0xF2, + 0x2E, 0x07, 0xDE, 0xD5, 0x54, 0x90, 0x80, 0xFF, 0x00, 0x05, 0x00, 0x0C, 0x02, 0x03, 0x00, 0x5D, + 0x49, 0x00, 0x83, 0x61, 0x40, 0x60, 0x3C, 0x1B, 0x2E, 0x26, 0xF3, 0xAE, 0x04, 0x0F, 0x80, 0xB1, + 0x2E, 0x10, 0x03, 0x32, 0x49, 0x00, 0x29, 0xA0, 0x49, 0x00, 0x65, 0x77, 0x3E, 0x07, 0xF2, 0x23, + 0x50, 0x0F, 0x81, 0x7C, 0x49, 0x00, 0x66, 0x3C, 0x49, 0x00, 0x54, 0xF1, 0x50, 0x13, 0x06, 0x94, + 0x38, 0x10, 0x99, 0x01, 0x10, 0x05, 0x00, 0x0C, 0x3C, 0x0B, 0xF6, 0xC8, 0x3C, 0x03, 0xF8, 0x2D, + 0x04, 0x0E, 0x7F, 0xF6, 0x2E, 0x07, 0xDE, 0xE4, 0x50, 0x00, 0x01, 0x0C, 0x38, 0x20, 0x19, 0x01, + 0x44, 0x20, 0x00, 0x56, 0x54, 0x10, 0x87, 0xFF, 0x44, 0x42, 0x4C, 0xAC, 0x49, 0x00, 0x56, 0xDC, + 0x44, 0x04, 0x28, 0x1C, 0x2E, 0x07, 0xF2, 0x1E, 0x49, 0x00, 0x58, 0x38, 0x49, 0x00, 0x65, 0xC2, + 0x49, 0x00, 0x61, 0xAB, 0x3E, 0x07, 0xF0, 0xDE, 0x3E, 0x07, 0xF0, 0xDA, 0x3E, 0x07, 0xF2, 0x37, + 0x49, 0x00, 0x07, 0x68, 0x2E, 0x16, 0xF3, 0xAE, 0x40, 0x00, 0x60, 0x08, 0x22, 0x00, 0x00, 0x01, + 0x44, 0x04, 0x80, 0x88, 0x49, 0x00, 0x3D, 0x7D, 0x49, 0x00, 0x68, 0x01, 0x44, 0x00, 0xFF, 0xFF, + 0x40, 0x10, 0x88, 0x36, 0x3E, 0x00, 0x12, 0xD7, 0x42, 0x01, 0x0C, 0x73, 0x3C, 0x0B, 0xF6, 0xEE, + 0x3E, 0x07, 0xEE, 0x18, 0x04, 0x2E, 0x7F, 0xB5, 0x44, 0x04, 0x80, 0x04, 0x04, 0x2E, 0x7F, 0xB3, + 0x49, 0x00, 0x7F, 0x51, 0x44, 0x32, 0x50, 0x30, 0x49, 0x00, 0x45, 0xFE, 0x49, 0x00, 0x55, 0xD9, + 0x04, 0x31, 0x00, 0x0F, 0x12, 0x03, 0x00, 0x5D, 0x04, 0x0E, 0x7F, 0xAE, 0x44, 0x02, 0x49, 0xEC, + 0x50, 0x4E, 0x7F, 0x8C, 0x44, 0x60, 0x00, 0x64, 0x49, 0x00, 0x66, 0xF8, 0x22, 0x10, 0x00, 0x00, + 0x44, 0x02, 0x38, 0x1C, 0x14, 0x01, 0x00, 0x0F, 0x38, 0x00, 0x80, 0x00, 0x3E, 0x07, 0xEA, 0x4F, + 0x3C, 0x38, 0x0B, 0x4E, 0x49, 0x00, 0x59, 0x4A, 0x40, 0x31, 0xC0, 0x08, 0x49, 0x00, 0x49, 0xCD, + 0x49, 0x00, 0x72, 0x8F, 0x3E, 0x07, 0xF0, 0x4B, 0x54, 0x00, 0x00, 0xCF, 0x49, 0x00, 0x58, 0xD8, + 0x40, 0x21, 0x40, 0x08, 0x50, 0x2F, 0x80, 0x2B, 0x49, 0x00, 0x7F, 0x00, 0x49, 0x00, 0x56, 0xF2, + 0x44, 0x00, 0x00, 0x80, 0x49, 0x00, 0x8F, 0xFD, 0x2E, 0x00, 0x03, 0x2D, 0x40, 0x10, 0x48, 0x08, + 0x3C, 0x03, 0xF6, 0xC8, 0x00, 0x10, 0x80, 0x28, 0x49, 0x00, 0x70, 0x46, 0x49, 0x00, 0x7F, 0x03, + 0x49, 0x00, 0x5D, 0xAD, 0x04, 0x1E, 0x7F, 0xF4, 0x00, 0x04, 0x80, 0x03, 0x40, 0x20, 0x20, 0x09, + 0x10, 0x03, 0x00, 0xBE, 0x3C, 0x0B, 0xF8, 0x9D, 0x44, 0x10, 0x98, 0x78, 0x58, 0x10, 0x80, 0x01, + 0x44, 0x14, 0x01, 0x08, 0x40, 0x21, 0x20, 0x08, 0x40, 0x50, 0x24, 0x02, 0x3A, 0x20, 0x0C, 0x20, + 0x3C, 0x24, 0x0A, 0xC7, 0x42, 0x02, 0x04, 0x73, 0x38, 0x20, 0x88, 0x02, 0x3E, 0x07, 0xEA, 0x5C, + 0x04, 0x00, 0x00, 0xF5, 0x44, 0x02, 0x24, 0x8C, 0x49, 0x00, 0x56, 0xCB, 0x02, 0x03, 0x00, 0x5C, + 0x49, 0x00, 0x4B, 0x81, 0x00, 0x0F, 0x80, 0x7B, 0x3C, 0x0B, 0xF7, 0x0A, 0x46, 0x0F, 0xBF, 0xFF, + 0x2E, 0x36, 0xF3, 0xAE, 0x3E, 0x07, 0xF0, 0xD0, 0x3E, 0x07, 0xF2, 0x22, 0x3C, 0x24, 0x0A, 0xCC, + 0x74, 0x1A, 0xC9, 0x3A, 0x10, 0x80, 0x12, 0x24, 0x12, 0x24, 0x0C, 0x00, 0x36, 0x00, 0xFF, 0x07, + 0xFF, 0x07, 0x38, 0x04, 0x60, 0x09, 0x05, 0x0A, 0x0B, 0x01, 0x00, 0x00, 0x80, 0x59, 0x59, 0x00, + 0x00, 0x00, 0x31, 0x00, 0x94, 0x00, 0xFA, 0x00, 0x66, 0x01, 0xD9, 0x01, 0x57, 0x02, 0xE6, 0x02, + 0x8A, 0x03, 0x4F, 0x04, 0x44, 0x05, 0x84, 0x06, 0x42, 0x08, 0xEB, 0x0A, 0x98, 0x0F, 0x55, 0x1A, + 0x83, 0x4F, 0xFF, 0xFF, 0xF2, 0x00, 0x74, 0x02, 0x1B, 0x04, 0xBC, 0x05, 0x5C, 0x07, 0xFD, 0x08, + 0x9F, 0x0A, 0x42, 0x0C, 0xE6, 0x0D, 0x80, 0x0F, 0x25, 0x11, 0xC5, 0x12, 0x66, 0x14, 0x07, 0x16, + 0xA8, 0x17, 0x48, 0x19, 0xE8, 0x1A, 0x88, 0x1C, 0x29, 0x1E, 0xCD, 0x1F, 0x71, 0x21, 0x14, 0x23, + 0xB5, 0x24, 0x56, 0x26, 0xF5, 0x27, 0x93, 0x29, 0x34, 0x2B, 0xC9, 0x2C, 0x71, 0x2E, 0x16, 0x30, + 0xB8, 0x31, 0x56, 0x33, 0xEF, 0x34, 0x84, 0x36, 0x1B, 0x38, 0xA8, 0x39, 0xA6, 0x00, 0x65, 0x02, + 0x06, 0x04, 0xAC, 0x05, 0x52, 0x07, 0xF8, 0x08, 0x9E, 0x0A, 0x45, 0x0C, 0xEC, 0x0D, 0x92, 0x0F, + 0x2F, 0x11, 0xCD, 0x12, 0x6C, 0x14, 0x0C, 0x16, 0xAD, 0x17, 0x4F, 0x19, 0xF1, 0x1A, 0x93, 0x1C, + 0x35, 0x1E, 0xD6, 0x1F, 0x77, 0x21, 0x18, 0x23, 0xB9, 0x24, 0x59, 0x26, 0xF8, 0x27, 0x97, 0x29, + 0x36, 0x2B, 0xD9, 0x2C, 0x7E, 0x2E, 0x22, 0x30, 0xC4, 0x31, 0x65, 0x33, 0x03, 0x35, 0x9C, 0x36, + 0x2D, 0x38, 0xC0, 0x39, 0xC6, 0x00, 0x08, 0x02, 0x8B, 0x03, 0x13, 0x05, 0x98, 0x06, 0x14, 0x08, + 0x88, 0x09, 0xFD, 0x0A, 0x71, 0x0C, 0xE5, 0x0D, 0x5B, 0x0F, 0xD3, 0x10, 0x4B, 0x12, 0xBE, 0x13, + 0x4B, 0x15, 0xE4, 0x16, 0x70, 0x18, 0xF1, 0x19, 0x00, 0xFF, 0xFF, 0x00, 0x01, 0x00, 0x00, 0x01, + 0x01, 0x01, 0xFF, 0x01, 0x01, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x01, 0x00, 0x00, 0x01, + 0xFF, 0xFF, 0x01, 0xFF, 0xFF, 0x01, 0x01, 0x01, 0x00, 0xFF, 0xFF, 0x00, 0x01, 0x00, 0x00, 0x01, + 0x01, 0x01, 0xFF, 0x01, 0x01, 0xFF, 0xFF, 0xFF, 0x9C, 0xFF, 0xFF, 0xFF, 0x9C, 0xFF, 0xFF, 0xFF, + 0x00, 0xFF, 0xFF, 0x00, 0x01, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0x01, 0xFF, 0xFF, 0x01, 0x01, 0x01, + 0xFF, 0xFF, 0x00, 0xFF, 0x01, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x00, 0xFF, 0x01, 0x00, 0x01, + 0x01, 0x01, 0x00, 0x00, 0x9C, 0xFF, 0xFF, 0xFF, 0x9C, 0xFF, 0xFF, 0xFF, 0x64, 0x00, 0x00, 0x00, + 0x64, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, + 0x06, 0x60, 0x00, 0x00, 0x08, 0x80, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00, 0x60, 0x00, 0x06, 0x00, + 0x80, 0x00, 0x08, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x06, 0x60, 0x00, 0x00, 0x08, 0x80, 0x00, + 0x40, 0x20, 0x10, 0x08, 0xA8, 0x1F, 0x02, 0x00, 0xA0, 0x1F, 0x02, 0x00, 0x94, 0x1F, 0x02, 0x00, + 0x88, 0x1F, 0x02, 0x00, 0x78, 0x1F, 0x02, 0x00, 0x68, 0x1F, 0x02, 0x00, 0x54, 0x1F, 0x02, 0x00, + 0x40, 0x1F, 0x02, 0x00, 0x28, 0x1F, 0x02, 0x00, 0x0C, 0x1F, 0x02, 0x00, 0x0A, 0x0B, 0x0B, 0x0B, + 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0D, 0x00, 0x00, 0x01, 0x05, 0x00, 0x07, 0x02, 0x06, 0x04, 0x08, + 0x03, 0x09, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x05, 0x05, 0x06, 0x06, 0x07, 0x08, + 0x09, 0x0A, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x11, 0x12, 0x58, 0x60, 0x61, 0x62, + 0x63, 0x64, 0x64, 0x64, 0x65, 0x65, 0x66, 0x67, 0x68, 0x69, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, + 0x6F, 0x70, 0x70, 0x71, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA2, 0x00, 0x00, 0x00, 0xA2, 0x00, 0x00, 0x00, + 0xE0, 0x00, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x02, 0x88, 0x02, 0x00, 0x00, + 0xD8, 0x00, 0xD8, 0x00, 0x40, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x02, 0x00, 0x00, 0x88, 0x02, 0x00, 0x00, + 0x92, 0x02, 0x00, 0x00, 0xD2, 0x02, 0x00, 0x00, 0x00, 0x06, 0x06, 0x00, 0x02, 0x02, 0x01, 0x01, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x00, 0x01, 0x02, 0x03, 0x04, 0x00, 0x00, 0x3F, 0xF0, 0x03, 0x00, + 0xC0, 0x0F, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x00, + 0x07, 0x00, 0x07, 0x07, 0x07, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0x49, 0x4C, 0x01, 0x01, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xEA, 0x20, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x07, 0xFF, 0x07, 0x12, 0x00, 0x24, 0x00, + 0x38, 0x04, 0x60, 0x09, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x24, 0x01, 0x00, 0x00, 0x24, 0x01, 0x00, 0x00, + 0x04, 0x00, 0x04, 0x00, 0x02, 0x00, 0x08, 0x2C, 0x02, 0x00, 0x08, 0x2C, 0x01, 0x00, 0x0C, 0x00, + 0x02, 0x00, 0x08, 0x00, 0x01, 0x04, 0x06, 0x08, 0x05, 0x06, 0x00, 0x00, 0xA7, 0x79, 0xA1, 0x18, + 0x48, 0x00, 0x36, 0xA8, 0x48, 0x00, 0x34, 0x96, 0x48, 0x00, 0x34, 0xBC, 0x48, 0x00, 0x34, 0xE2, + 0x48, 0x00, 0x35, 0x08, 0x48, 0x00, 0x35, 0x2E, 0x48, 0x00, 0x35, 0x54, 0x48, 0x00, 0x35, 0x7A, + 0x48, 0x00, 0x35, 0xA0, 0x48, 0x00, 0x36, 0x0E, 0x48, 0x00, 0x36, 0x10, 0x48, 0x00, 0x36, 0x12, + 0x48, 0x00, 0x36, 0x14, 0x48, 0x00, 0x36, 0x16, 0x48, 0x00, 0x36, 0x18, 0x48, 0x00, 0x36, 0x1A, + 0x48, 0x00, 0x36, 0x1C, 0x48, 0x00, 0x36, 0x1E, 0x48, 0x00, 0x36, 0x20, 0x48, 0x00, 0x36, 0x22, + 0x48, 0x00, 0x36, 0x24, 0x48, 0x00, 0x36, 0x26, 0x48, 0x00, 0x36, 0x28, 0x48, 0x00, 0x36, 0x2A, + 0x48, 0x00, 0x36, 0x2C, 0x48, 0x00, 0x36, 0x2E, 0x48, 0x00, 0x36, 0x30, 0x48, 0x00, 0x36, 0x32, + 0x48, 0x00, 0x36, 0x34, 0x48, 0x00, 0x36, 0x36, 0x48, 0x00, 0x36, 0x38, 0x48, 0x00, 0x36, 0x3A, + 0x48, 0x00, 0x36, 0x3C, 0x48, 0x00, 0x36, 0x3E, 0x48, 0x00, 0x36, 0x40, 0x48, 0x00, 0x36, 0x43, + 0x48, 0x00, 0x36, 0x46, 0x48, 0x00, 0x36, 0x49, 0x48, 0x00, 0x36, 0x4C, 0x48, 0x00, 0x36, 0x4F, + 0x48, 0x00, 0x36, 0x52, 0x30, 0x6E, 0x00, 0x00, 0x32, 0x6E, 0x00, 0x00, 0x48, 0x6E, 0x00, 0x00, + 0x62, 0x6E, 0x00, 0x00, 0x6E, 0x6E, 0x00, 0x00, 0x86, 0x6E, 0x00, 0x00, 0x92, 0x6E, 0x00, 0x00, + 0xB2, 0x6E, 0x00, 0x00, 0xBA, 0x6E, 0x00, 0x00, 0xCE, 0x6E, 0x00, 0x00, 0x20, 0x6F, 0x00, 0x00, + 0x78, 0x6F, 0x00, 0x00, 0x94, 0x6F, 0x00, 0x00, 0x9C, 0x6F, 0x00, 0x00, 0xA4, 0x6F, 0x00, 0x00, + 0xAC, 0x6F, 0x00, 0x00, 0xF2, 0x6F, 0x00, 0x00, 0xCE, 0x70, 0x00, 0x00, 0x36, 0x71, 0x00, 0x00, + 0x4A, 0x71, 0x00, 0x00, 0x4C, 0x71, 0x00, 0x00, 0x4E, 0x71, 0x00, 0x00, 0x50, 0x71, 0x00, 0x00, + 0x62, 0x71, 0x00, 0x00, 0x84, 0x71, 0x00, 0x00, 0x9C, 0x71, 0x00, 0x00, 0xD0, 0x71, 0x00, 0x00, + 0xEA, 0x71, 0x00, 0x00, 0x16, 0x72, 0x00, 0x00, 0x48, 0x72, 0x00, 0x00, 0x86, 0x72, 0x00, 0x00, + 0xAA, 0x72, 0x00, 0x00, 0xFC, 0x43, 0x51, 0xCF, 0x80, 0x38, 0x14, 0x0E, 0x7F, 0xF6, 0x3C, 0x2D, + 0xFE, 0x3C, 0x2E, 0x86, 0x61, 0xFF, 0x14, 0x1E, 0x7F, 0xF7, 0x40, 0x04, 0x04, 0x08, 0x8C, 0x08, + 0x54, 0x00, 0x03, 0xF8, 0xEA, 0x54, 0xEA, 0xA2, 0xFE, 0x16, 0x81, 0x5F, 0xC8, 0x09, 0x04, 0x0E, + 0x7F, 0xF7, 0x5A, 0x00, 0x01, 0x0C, 0x44, 0x90, 0x00, 0x64, 0x85, 0x00, 0xD5, 0x24, 0xDD, 0x44, + 0x5A, 0x08, 0x01, 0xF7, 0x44, 0x90, 0x00, 0xC8, 0xD5, 0x1E, 0x84, 0xA0, 0x3C, 0x23, 0x31, 0x0A, + 0xFF, 0x92, 0x3C, 0x73, 0x31, 0x0B, 0x42, 0x21, 0x20, 0x73, 0x80, 0x85, 0x44, 0x10, 0x00, 0xC8, + 0x96, 0x20, 0xE2, 0x08, 0x88, 0xA6, 0xE8, 0x0D, 0x98, 0x15, 0x40, 0x00, 0x20, 0x16, 0x52, 0x00, + 0x03, 0xE8, 0xFE, 0x0C, 0x40, 0x00, 0x1C, 0x16, 0x38, 0x05, 0x11, 0x09, 0x8C, 0x81, 0xD5, 0xF1, + 0x44, 0x90, 0x00, 0x64, 0x84, 0x80, 0x97, 0x60, 0xE2, 0xA8, 0xE8, 0x73, 0x04, 0x0E, 0x7F, 0xF7, + 0x5A, 0x08, 0x01, 0x04, 0x38, 0x95, 0x11, 0x01, 0x3C, 0x03, 0xFC, 0x7C, 0x96, 0x0E, 0xC8, 0x0D, + 0x44, 0x10, 0x7F, 0xFF, 0x2E, 0x56, 0x61, 0xFE, 0x04, 0x0E, 0x7F, 0xF6, 0x42, 0x72, 0x14, 0x24, + 0x95, 0xF9, 0x88, 0xE0, 0x84, 0x00, 0xD5, 0x11, 0x2E, 0x67, 0xEF, 0xEA, 0x84, 0x00, 0x96, 0x80, + 0xE2, 0x46, 0xE8, 0xEF, 0x8C, 0x01, 0x94, 0x81, 0x44, 0x12, 0x07, 0xC4, 0x88, 0x41, 0x00, 0x21, + 0x7F, 0xFF, 0x4C, 0x22, 0xFF, 0xF6, 0xD5, 0x4B, 0x96, 0x80, 0xE2, 0x45, 0xE8, 0x09, 0x38, 0x23, + 0x81, 0x11, 0x8C, 0x01, 0xE0, 0x22, 0x40, 0x20, 0xBC, 0x1B, 0x80, 0x22, 0xD5, 0xF6, 0x84, 0x00, + 0x80, 0xC0, 0x80, 0x40, 0x88, 0x29, 0x96, 0xC0, 0xE2, 0x65, 0xE8, 0x0A, 0x38, 0x33, 0x81, 0x11, + 0xE0, 0x61, 0xE8, 0x04, 0x8C, 0x41, 0x88, 0xC3, 0x96, 0x90, 0x8C, 0x01, 0xD5, 0xF5, 0xC2, 0x2F, + 0x14, 0x5E, 0x7F, 0xF3, 0x14, 0x2E, 0x7F, 0xF4, 0x14, 0x4E, 0x7F, 0xF5, 0xDD, 0x44, 0x04, 0x4E, + 0x7F, 0xF5, 0x04, 0x2E, 0x7F, 0xF4, 0x04, 0x5E, 0x7F, 0xF3, 0x5A, 0x08, 0x01, 0x0A, 0x40, 0x63, + 0x08, 0xD6, 0x4E, 0x65, 0x00, 0x12, 0xE1, 0x26, 0x40, 0x64, 0xBC, 0x1B, 0xD5, 0x0B, 0x40, 0x23, + 0x08, 0x56, 0x52, 0x64, 0x80, 0x00, 0xE0, 0x46, 0xE9, 0x05, 0xE1, 0x22, 0x40, 0x24, 0xBC, 0x1B, + 0x80, 0xC2, 0x97, 0xB3, 0xD5, 0x02, 0x84, 0xC0, 0x84, 0x00, 0x4C, 0x02, 0x80, 0x09, 0xA4, 0xB8, + 0x8C, 0x01, 0x8A, 0x46, 0x1A, 0x23, 0x80, 0x01, 0x96, 0x00, 0xD5, 0xF8, 0x8C, 0x81, 0xD5, 0x8C, + 0x51, 0xFE, 0x7F, 0xE0, 0xFC, 0xC0, 0xFC, 0x00, 0x49, 0x00, 0x19, 0x24, 0x80, 0xC0, 0xEA, 0x56, + 0xDD, 0x58, 0x44, 0x12, 0x0D, 0x20, 0x38, 0x00, 0x99, 0x09, 0xFC, 0x80, 0xFC, 0x00, 0xDD, 0x44, + 0x84, 0x00, 0x44, 0x10, 0x07, 0xD0, 0xEB, 0x19, 0x84, 0x00, 0x84, 0x21, 0xEB, 0x4A, 0xFC, 0x80, + 0xFC, 0x00, 0x64, 0x12, 0x00, 0x43, 0xEA, 0x66, 0xEA, 0x66, 0x49, 0x00, 0x31, 0x2F, 0x49, 0x00, + 0x32, 0x5D, 0x49, 0x00, 0x31, 0x32, 0xEB, 0x3A, 0x49, 0x00, 0x31, 0x7B, 0x49, 0x00, 0x31, 0xC9, + 0x49, 0x00, 0x19, 0x05, 0x49, 0x00, 0x22, 0x89, 0x49, 0x00, 0x19, 0xB4, 0x49, 0x00, 0x19, 0xC7, + 0x49, 0x00, 0x23, 0x04, 0xFC, 0x80, 0xFC, 0x00, 0x84, 0x00, 0x3E, 0x07, 0xF8, 0xFB, 0xEA, 0x39, + 0x80, 0xC0, 0xC0, 0x0A, 0x49, 0x00, 0x19, 0xA7, 0x4E, 0x02, 0x00, 0x8D, 0x49, 0x00, 0x31, 0x12, + 0x49, 0x00, 0x19, 0xB1, 0xD5, 0x0B, 0x84, 0x02, 0x3E, 0x07, 0xF9, 0x65, 0x84, 0x01, 0x3E, 0x07, + 0xF9, 0x64, 0x49, 0x00, 0x19, 0xD0, 0x3E, 0x67, 0xF9, 0x64, 0x49, 0xFF, 0xFF, 0xB6, 0x49, 0x00, + 0x16, 0x85, 0x49, 0x00, 0x21, 0x3C, 0xEA, 0x78, 0x5A, 0x08, 0x01, 0x06, 0x2E, 0x07, 0xEF, 0xB0, + 0x49, 0x00, 0x18, 0xD2, 0xEA, 0x78, 0xEA, 0xF7, 0xEA, 0x20, 0xDD, 0x44, 0xC8, 0x03, 0x49, 0x00, + 0x12, 0x50, 0xDD, 0x44, 0xC8, 0x03, 0xEB, 0x47, 0xD5, 0x1B, 0x2E, 0x07, 0xF9, 0x18, 0x96, 0x16, + 0xC0, 0x0B, 0x3C, 0x13, 0xF7, 0xEE, 0x84, 0x03, 0xFE, 0x0C, 0x84, 0x41, 0x96, 0x01, 0x84, 0x20, + 0x80, 0x62, 0xEA, 0x5C, 0xEB, 0x47, 0x2E, 0x07, 0xF9, 0x18, 0x84, 0x41, 0x54, 0x00, 0x00, 0xFB, + 0x3E, 0x07, 0xF9, 0x18, 0x84, 0x20, 0x3C, 0x03, 0xF7, 0xEE, 0x80, 0x62, 0xEA, 0x5C, 0xDD, 0x44, + 0xC8, 0x0E, 0x44, 0x10, 0x00, 0x69, 0x84, 0x41, 0x84, 0x05, 0xEA, 0x45, 0x80, 0x20, 0x3E, 0x07, + 0xF9, 0x06, 0x84, 0x01, 0xEA, 0xF0, 0x84, 0x01, 0x84, 0x22, 0xEA, 0x86, 0x49, 0x00, 0x07, 0xD5, + 0x84, 0x00, 0x3E, 0x07, 0xF9, 0x51, 0x49, 0x00, 0x21, 0xFB, 0x49, 0xFF, 0xFF, 0x79, 0x84, 0x04, + 0x3E, 0x07, 0xF8, 0xFF, 0x3C, 0x03, 0xFC, 0x7C, 0xEA, 0x87, 0x3C, 0x0B, 0xFC, 0x7C, 0x84, 0x00, + 0xDD, 0x48, 0x84, 0x00, 0xEA, 0x46, 0xDD, 0x5A, 0xDD, 0x44, 0xC8, 0x04, 0x84, 0x01, 0x49, 0x00, + 0x31, 0x1A, 0xEA, 0x71, 0xE6, 0x05, 0xE9, 0x1C, 0x44, 0x27, 0x20, 0xC0, 0xEB, 0x00, 0xB4, 0x22, + 0xFE, 0x46, 0xB6, 0x22, 0x44, 0x27, 0x21, 0x00, 0xB4, 0x22, 0xFE, 0x46, 0xB6, 0x22, 0x44, 0x17, + 0x21, 0x40, 0xB4, 0x41, 0xFE, 0x16, 0x44, 0x27, 0x20, 0x94, 0xB6, 0x01, 0xB4, 0x02, 0x96, 0x00, + 0x58, 0x10, 0x00, 0x01, 0xB4, 0x02, 0x92, 0x08, 0xDD, 0x4C, 0xFE, 0x0F, 0xB6, 0x02, 0x49, 0x00, + 0x00, 0x55, 0xFC, 0x80, 0xFC, 0x00, 0x84, 0x01, 0x49, 0x00, 0x08, 0x62, 0x49, 0x00, 0x1B, 0xF1, + 0xFC, 0x80, 0xFC, 0x00, 0x2E, 0x07, 0xF8, 0xFF, 0xC0, 0x04, 0x5A, 0x00, 0x04, 0x06, 0xFC, 0x80, + 0x49, 0xFF, 0xFF, 0x5B, 0xFC, 0x80, 0x49, 0xFF, 0xFF, 0xEF, 0xFC, 0x80, 0xFC, 0x20, 0x44, 0x70, + 0x00, 0x40, 0x84, 0xC0, 0x49, 0x00, 0x31, 0xE9, 0x2E, 0x07, 0xF8, 0xFD, 0x5A, 0x00, 0x01, 0x08, + 0xC0, 0x04, 0x5A, 0x00, 0x02, 0x27, 0xD5, 0xF7, 0x84, 0x01, 0xD5, 0x20, 0x3E, 0x77, 0xF5, 0xA0, + 0x3E, 0x67, 0xF8, 0xFF, 0x3E, 0x67, 0xF8, 0xFE, 0x3E, 0x67, 0xF8, 0xFA, 0xDD, 0x44, 0x5A, 0x08, + 0x01, 0x15, 0x49, 0x00, 0x18, 0xE4, 0x5A, 0x08, 0x02, 0x04, 0x84, 0x03, 0xD5, 0x02, 0x84, 0x04, + 0x3E, 0x07, 0xF8, 0xFD, 0x2E, 0x07, 0xF9, 0x53, 0xC0, 0x03, 0x84, 0x04, 0xD5, 0x07, 0x2E, 0x07, + 0xF9, 0x52, 0xC0, 0xD9, 0x84, 0x03, 0xD5, 0x02, 0x84, 0x02, 0x3E, 0x07, 0xF8, 0xFD, 0xD5, 0xD3, + 0x49, 0x00, 0x18, 0xAE, 0x49, 0x00, 0x18, 0xB5, 0x2E, 0x07, 0xF8, 0xFA, 0x3E, 0x67, 0xF9, 0x00, + 0xC8, 0xCA, 0x49, 0xFF, 0xFF, 0xB8, 0xD5, 0xC7, 0xDD, 0x9E, 0x46, 0x10, 0x00, 0x81, 0xC8, 0x06, + 0x04, 0x00, 0x80, 0x33, 0x58, 0x00, 0x02, 0x00, 0xD5, 0x05, 0x04, 0x20, 0x80, 0x33, 0xEB, 0x00, + 0xFE, 0x16, 0x14, 0x00, 0x80, 0x33, 0xDD, 0x9E, 0x5A, 0x10, 0x01, 0x0C, 0xC1, 0x04, 0x5A, 0x10, + 0x02, 0x0F, 0xDD, 0x9E, 0xDD, 0x43, 0x96, 0x06, 0xDD, 0x49, 0xEB, 0x45, 0xDD, 0x55, 0xD5, 0x0F, + 0xDD, 0x43, 0x96, 0x06, 0xEB, 0x17, 0xEB, 0x45, 0xEB, 0x39, 0xD5, 0x09, 0x96, 0x06, 0xDD, 0x43, + 0x40, 0x10, 0x4C, 0x08, 0x46, 0x0F, 0xFF, 0x7F, 0xEB, 0x45, 0xDD, 0x41, 0xFE, 0x1E, 0xFE, 0x0F, + 0x14, 0x01, 0x00, 0x29, 0xDD, 0x9E, 0x44, 0x24, 0x2C, 0x14, 0x84, 0x30, 0xB4, 0x62, 0x96, 0x1F, + 0xFE, 0x5E, 0xFE, 0x0F, 0xB6, 0x02, 0xDD, 0x9E, 0xFC, 0x00, 0x80, 0xC0, 0xEA, 0x58, 0x5A, 0x08, + 0x1F, 0x07, 0xE6, 0xC4, 0x80, 0x06, 0xE8, 0x02, 0x84, 0x04, 0x97, 0x80, 0x44, 0x24, 0x2C, 0x14, + 0x97, 0x9F, 0x40, 0x03, 0x20, 0x08, 0xB4, 0xC2, 0x44, 0x1F, 0xF0, 0xFF, 0xFF, 0x8E, 0xFF, 0x87, + 0xB6, 0xC2, 0xFC, 0x80, 0xFC, 0x40, 0xEA, 0x2A, 0x81, 0x42, 0x83, 0x81, 0x80, 0xE4, 0x81, 0x00, + 0x81, 0x23, 0xEA, 0xAA, 0x04, 0x03, 0x03, 0x91, 0x54, 0x84, 0x03, 0xFF, 0x92, 0x0A, 0xDD, 0x47, + 0x40, 0x80, 0x20, 0x04, 0x14, 0x83, 0x03, 0x91, 0xEA, 0x8A, 0x04, 0x23, 0x00, 0x2C, 0xEB, 0x31, + 0x40, 0x1E, 0x40, 0x08, 0x50, 0x00, 0x0F, 0x00, 0xFE, 0x16, 0x41, 0xC0, 0xF0, 0x04, 0x40, 0x1E, + 0x00, 0x04, 0x14, 0x13, 0x00, 0x2C, 0x40, 0x34, 0xC0, 0x08, 0x04, 0x13, 0x00, 0x2D, 0x40, 0x31, + 0xA8, 0x04, 0x46, 0x23, 0xF3, 0xF0, 0x40, 0xA5, 0x60, 0x08, 0x46, 0x0C, 0x0C, 0x0F, 0x50, 0x21, + 0x00, 0x3F, 0x40, 0x31, 0xA8, 0x04, 0xEA, 0xDA, 0xFE, 0xD6, 0xFE, 0x0E, 0x40, 0x21, 0x80, 0x04, + 0x14, 0x23, 0x00, 0x2D, 0x04, 0x43, 0x00, 0x2F, 0x97, 0xEF, 0x92, 0x86, 0x95, 0x26, 0xFF, 0xE7, + 0x14, 0x73, 0x00, 0x2F, 0xFC, 0xC0, 0xFC, 0x00, 0x44, 0x24, 0x2C, 0x24, 0xEA, 0xE1, 0xB4, 0x22, + 0xFE, 0x0E, 0x44, 0x10, 0x80, 0x00, 0xFE, 0x0F, 0xB6, 0x02, 0x84, 0x41, 0x44, 0x04, 0x28, 0x24, + 0x44, 0x14, 0x24, 0x24, 0x80, 0x62, 0xDD, 0x40, 0xFC, 0x80, 0x44, 0x24, 0x80, 0x90, 0x96, 0x06, + 0xB4, 0x62, 0xDD, 0x4F, 0xDD, 0x52, 0xFE, 0x1E, 0xFE, 0x0F, 0xB6, 0x02, 0xDD, 0x9E, 0x46, 0x20, + 0x00, 0x82, 0x96, 0x06, 0xA0, 0xD5, 0xDD, 0x49, 0xDD, 0x55, 0xFE, 0x1E, 0xFE, 0x0F, 0xA8, 0x15, + 0xDD, 0x9E, 0x46, 0x00, 0x00, 0x82, 0xA0, 0x05, 0x92, 0x10, 0x96, 0x06, 0xDD, 0x9E, 0x46, 0x20, + 0x00, 0x82, 0x84, 0x3E, 0xA0, 0xD4, 0x96, 0x06, 0xFE, 0x5E, 0xFE, 0x47, 0xA8, 0x54, 0xA0, 0xD4, + 0xEA, 0xBB, 0xDD, 0x4E, 0xFE, 0x5E, 0xFE, 0x0F, 0xA8, 0x14, 0xDD, 0x9E, 0xFC, 0x00, 0x40, 0x61, + 0x20, 0x08, 0x95, 0x51, 0xFF, 0x77, 0x40, 0x61, 0x44, 0x08, 0xFF, 0x77, 0x40, 0x21, 0x60, 0x08, + 0xFE, 0xAF, 0xFE, 0x87, 0x95, 0x4E, 0xFE, 0xAF, 0x40, 0x50, 0xB4, 0x08, 0xFE, 0xAF, 0x40, 0x50, + 0xD8, 0x08, 0x46, 0x30, 0x00, 0x82, 0xFE, 0xAF, 0x40, 0x10, 0xF4, 0x08, 0xFE, 0x57, 0xDD, 0x4E, + 0xA1, 0x1C, 0xFE, 0x0F, 0x46, 0x2C, 0x08, 0x0C, 0x46, 0x13, 0xF7, 0xF3, 0x50, 0x10, 0x8F, 0x7F, + 0x50, 0x21, 0x00, 0x80, 0xFE, 0x46, 0xFE, 0xA6, 0xFE, 0x57, 0xA8, 0x5C, 0xFC, 0x80, 0x46, 0x30, + 0x00, 0x82, 0x44, 0x41, 0x00, 0x00, 0xB4, 0xA3, 0xEA, 0x2B, 0xFF, 0x2F, 0xB6, 0x83, 0xB4, 0x83, + 0x94, 0x92, 0x92, 0x8A, 0x40, 0x42, 0x28, 0x08, 0xFF, 0x0F, 0xB6, 0x83, 0x88, 0x40, 0x4C, 0x01, + 0x00, 0x05, 0xA0, 0x59, 0xAA, 0x41, 0xD5, 0xFC, 0xB4, 0x23, 0xDD, 0x55, 0xFE, 0x0E, 0xB6, 0x03, + 0xDD, 0x9E, 0x46, 0x30, 0x00, 0x82, 0x44, 0x41, 0x00, 0x00, 0xB4, 0xA3, 0xEA, 0x2B, 0xFF, 0x2F, + 0xB6, 0x83, 0xB4, 0x83, 0x94, 0x92, 0x92, 0x8A, 0x40, 0x42, 0x28, 0x08, 0xFF, 0x0F, 0xB6, 0x83, + 0x88, 0x40, 0x80, 0x23, 0x4C, 0x01, 0x00, 0x05, 0xA3, 0x01, 0xA9, 0x09, 0xD5, 0xFC, 0xB4, 0x23, + 0xDD, 0x55, 0xFE, 0x0E, 0xB6, 0x03, 0xDD, 0x9E, 0xFC, 0x00, 0x46, 0x50, 0x00, 0x80, 0x46, 0x3F, + 0xFF, 0x00, 0x9D, 0x99, 0x9D, 0x2E, 0x94, 0xA9, 0x88, 0x40, 0x38, 0x11, 0x18, 0x00, 0x38, 0x21, + 0x0C, 0x00, 0x94, 0x4C, 0xFE, 0x57, 0x96, 0x48, 0x18, 0x12, 0x80, 0x01, 0xDC, 0xF5, 0xFC, 0x80, + 0x46, 0x20, 0x00, 0x80, 0x84, 0x3E, 0x04, 0x31, 0x00, 0xA4, 0x96, 0x06, 0xFE, 0x5E, 0xFE, 0x0F, + 0x14, 0x01, 0x00, 0xA4, 0xDD, 0x9E, 0x46, 0x20, 0x00, 0x81, 0xDD, 0x4E, 0x04, 0x11, 0x00, 0x11, + 0x96, 0x49, 0xFE, 0x0F, 0xEA, 0xAD, 0xDD, 0x9E, 0x46, 0x20, 0x00, 0x81, 0xDD, 0x4E, 0x04, 0x11, + 0x00, 0x10, 0x96, 0x49, 0xFE, 0x0F, 0xEA, 0x73, 0xDD, 0x9E, 0x46, 0x20, 0x00, 0x81, 0x04, 0x11, + 0x00, 0x10, 0x92, 0x30, 0xDD, 0x5E, 0xFE, 0x0F, 0xEA, 0x73, 0xDD, 0x9E, 0x46, 0x20, 0x00, 0x81, + 0x04, 0x11, 0x00, 0x11, 0x92, 0x30, 0xDD, 0x5E, 0xFE, 0x0F, 0xEA, 0xAD, 0xDD, 0x9E, 0x46, 0x20, + 0x00, 0x81, 0x84, 0x30, 0xEA, 0x3D, 0x96, 0x1F, 0xFE, 0x5E, 0xFE, 0x0F, 0xEA, 0x3E, 0xDD, 0x9E, + 0x46, 0x20, 0x00, 0x80, 0x84, 0x30, 0x04, 0x31, 0x00, 0x70, 0x96, 0x1F, 0xFE, 0x5E, 0xFE, 0x0F, + 0x14, 0x01, 0x00, 0x70, 0xDD, 0x9E, 0x46, 0x20, 0x00, 0x81, 0x84, 0x3E, 0x04, 0x31, 0x00, 0x13, + 0x96, 0x06, 0xFE, 0x5E, 0xFE, 0x0F, 0x14, 0x01, 0x00, 0x13, 0xDD, 0x9E, 0x46, 0x20, 0x00, 0x81, + 0x96, 0x06, 0xEA, 0x3D, 0xDD, 0x4F, 0xDD, 0x52, 0xFE, 0x1E, 0xFE, 0x0F, 0xEA, 0x3E, 0xDD, 0x9E, + 0x46, 0x20, 0x00, 0x81, 0x96, 0x0F, 0xEA, 0x3D, 0xDD, 0x49, 0xEA, 0xCE, 0xFE, 0x1E, 0xFE, 0x0F, + 0xEA, 0x3E, 0xDD, 0x9E, 0x46, 0x20, 0x00, 0x81, 0x96, 0x1F, 0xDD, 0x49, 0x04, 0x31, 0x00, 0x13, + 0xEA, 0xC6, 0xDD, 0x41, 0xFE, 0x1E, 0xFE, 0x0F, 0x14, 0x01, 0x00, 0x13, 0xDD, 0x9E, 0x46, 0x20, + 0x00, 0x81, 0x84, 0x38, 0x04, 0x31, 0x00, 0x76, 0x96, 0x17, 0xFE, 0x5E, 0xFE, 0x0F, 0x14, 0x01, + 0x00, 0x76, 0xDD, 0x9E, 0x46, 0x20, 0x00, 0x81, 0x96, 0x06, 0x40, 0x10, 0x54, 0x08, 0xEA, 0x3D, + 0x46, 0x0F, 0xFD, 0xFF, 0xDD, 0x41, 0xFE, 0x1E, 0xFE, 0x0F, 0xEA, 0x3E, 0xDD, 0x9E, 0x46, 0x20, + 0x00, 0x81, 0x96, 0x0F, 0xEB, 0x17, 0xEA, 0x3D, 0x46, 0x0F, 0xFF, 0x3F, 0xDD, 0x41, 0xFE, 0x1E, + 0xFE, 0x0F, 0xEA, 0x3E, 0xDD, 0x9E, 0x46, 0x20, 0x00, 0x81, 0x96, 0x06, 0xEA, 0xF8, 0xEA, 0x3D, + 0x46, 0x0F, 0xFB, 0xFF, 0xDD, 0x41, 0xFE, 0x1E, 0xFE, 0x0F, 0xEA, 0x3E, 0xDD, 0x9E, 0x46, 0x00, + 0x00, 0x81, 0x04, 0x00, 0x00, 0x12, 0x92, 0x12, 0x96, 0x0F, 0xDD, 0x9E, 0x44, 0x04, 0x80, 0x10, + 0x84, 0x21, 0xB4, 0x00, 0x92, 0x08, 0x96, 0x06, 0xC0, 0x07, 0xEA, 0xD4, 0xAE, 0x40, 0x3E, 0x17, + 0xF9, 0x03, 0x3E, 0x17, 0xF9, 0x02, 0xDD, 0x9E, 0xDD, 0x9E, 0xDD, 0x9E, 0x44, 0x14, 0x80, 0x10, + 0xC8, 0x0F, 0xFA, 0x50, 0xAE, 0x88, 0xB4, 0x01, 0x92, 0x05, 0x96, 0x06, 0xC8, 0xFC, 0x44, 0x14, + 0x80, 0x10, 0xB4, 0x01, 0x92, 0x05, 0x96, 0x06, 0xC0, 0xFD, 0xFA, 0x30, 0xD5, 0x0F, 0x44, 0x20, + 0x00, 0x40, 0xAE, 0x88, 0xB4, 0x01, 0x92, 0x06, 0x96, 0x06, 0xC8, 0xFC, 0x44, 0x14, 0x80, 0x10, + 0xB4, 0x01, 0x92, 0x06, 0x96, 0x06, 0xC0, 0xFD, 0xEB, 0x22, 0xEA, 0x5A, 0xAE, 0x40, 0xDD, 0x9E, + 0x46, 0x20, 0x00, 0x81, 0x96, 0x0F, 0x50, 0x41, 0x00, 0xE4, 0xB4, 0x64, 0xEB, 0x17, 0x46, 0x0F, + 0xFF, 0x3F, 0xDD, 0x41, 0xFE, 0x1E, 0xFE, 0x0F, 0xB6, 0x04, 0xB4, 0x24, 0x46, 0x03, 0x00, 0x00, + 0xFE, 0x0F, 0xB6, 0x04, 0xDD, 0x9E, 0x46, 0x20, 0x00, 0x81, 0x96, 0x0F, 0xEA, 0xF8, 0xEB, 0x03, + 0xEB, 0x2F, 0xDD, 0x41, 0xFE, 0x1E, 0xFE, 0x0F, 0x14, 0x01, 0x00, 0x39, 0xDD, 0x9E, 0x46, 0x20, + 0x00, 0x81, 0x96, 0x0F, 0x50, 0x41, 0x00, 0xE4, 0xB4, 0x64, 0x94, 0x46, 0xEB, 0x36, 0xFE, 0x1E, + 0xFE, 0x0F, 0xB6, 0x04, 0xB4, 0x24, 0x44, 0x03, 0x00, 0x00, 0xFE, 0x0F, 0xB6, 0x04, 0xDD, 0x9E, + 0x46, 0x20, 0x00, 0x81, 0x96, 0x0F, 0xEB, 0x03, 0xEA, 0xA8, 0x44, 0x0F, 0xF3, 0xFF, 0xFE, 0x1E, + 0xFE, 0x0F, 0x14, 0x01, 0x00, 0x39, 0xDD, 0x9E, 0x46, 0x10, 0x00, 0x81, 0x46, 0x2F, 0x8F, 0x8F, + 0x04, 0x30, 0x80, 0x3A, 0x50, 0x21, 0x08, 0xF8, 0xFE, 0x9E, 0x46, 0x30, 0x50, 0x10, 0x50, 0x31, + 0x84, 0x00, 0xFE, 0x9F, 0x14, 0x20, 0x80, 0x3A, 0xC8, 0x0F, 0x46, 0x00, 0x03, 0x08, 0x50, 0x00, + 0x03, 0x20, 0x14, 0x00, 0x80, 0x38, 0x04, 0x00, 0x80, 0x70, 0x92, 0x06, 0x94, 0x06, 0x58, 0x00, + 0x00, 0x38, 0x14, 0x00, 0x80, 0x70, 0xDD, 0x9E, 0xFC, 0x00, 0x80, 0xC0, 0xEA, 0xAA, 0xDD, 0x43, + 0x97, 0x86, 0x94, 0x32, 0x04, 0x61, 0x03, 0x93, 0x84, 0x3B, 0xFF, 0x8E, 0xFF, 0x87, 0x14, 0x61, + 0x03, 0x93, 0xEA, 0x8A, 0xFC, 0x80, 0x44, 0x04, 0x50, 0x2C, 0xB4, 0x00, 0x92, 0x05, 0x96, 0x06, + 0xDD, 0x9E, 0x46, 0x20, 0x00, 0x81, 0x96, 0x06, 0x04, 0x31, 0x00, 0x15, 0xDD, 0x49, 0xDD, 0x55, + 0xFE, 0x1E, 0xFE, 0x0F, 0x14, 0x01, 0x00, 0x15, 0xDD, 0x9E, 0x44, 0x04, 0x80, 0x08, 0xB4, 0x00, + 0x92, 0x0A, 0x96, 0x06, 0xDD, 0x9E, 0x5A, 0x00, 0x0F, 0x0E, 0xEA, 0x92, 0x96, 0x0F, 0x40, 0x20, + 0x58, 0x08, 0x04, 0x41, 0x80, 0x39, 0xEB, 0x2F, 0xDD, 0x41, 0xFE, 0x26, 0xFE, 0x17, 0x14, 0x01, + 0x80, 0x39, 0x5A, 0x10, 0x0F, 0x0D, 0xDD, 0x43, 0x96, 0x4F, 0xEB, 0x03, 0x40, 0x00, 0xA8, 0x08, + 0x44, 0x1F, 0xF3, 0xFF, 0xFE, 0x5E, 0xFE, 0x47, 0x14, 0x11, 0x00, 0x39, 0xEA, 0x2D, 0x44, 0x0F, + 0xF8, 0xFF, 0x50, 0x30, 0x80, 0xE8, 0xB4, 0x43, 0xFE, 0x16, 0xEA, 0xFB, 0xB6, 0x03, 0xB4, 0x43, + 0x46, 0x0F, 0x8F, 0xFF, 0xDD, 0x41, 0xFE, 0x16, 0x46, 0x20, 0x50, 0x00, 0xFE, 0x17, 0xB6, 0x03, + 0xDD, 0x9E, 0x2E, 0x07, 0xF5, 0xA2, 0xDD, 0x9E, 0x3E, 0x07, 0xF5, 0xA2, 0xDD, 0x9E, 0x5A, 0x08, + 0x01, 0x0F, 0x44, 0x07, 0x21, 0x00, 0x46, 0x10, 0x20, 0x00, 0xB4, 0x40, 0xFE, 0x57, 0xB6, 0x20, + 0x80, 0x20, 0xB4, 0x01, 0x92, 0x19, 0x96, 0x06, 0xC8, 0xFD, 0xDD, 0x9E, 0x5A, 0x08, 0x02, 0x0E, + 0x44, 0x07, 0x21, 0x40, 0x46, 0x10, 0x20, 0x00, 0xB4, 0x40, 0xFE, 0x57, 0xB6, 0x20, 0x80, 0x20, + 0xB4, 0x01, 0x92, 0x19, 0x96, 0x06, 0xC8, 0xFD, 0xDD, 0x9E, 0x44, 0x14, 0x80, 0x04, 0x84, 0x41, + 0xB4, 0x01, 0x92, 0x10, 0x96, 0x06, 0xC0, 0x05, 0xEA, 0x7C, 0xAE, 0x80, 0x3E, 0x27, 0xF5, 0xA3, + 0xB4, 0x01, 0x92, 0x11, 0x96, 0x06, 0xC0, 0x07, 0xEA, 0x7C, 0x84, 0x22, 0xAE, 0x40, 0x84, 0x01, + 0x3E, 0x07, 0xF5, 0xA2, 0xEB, 0x0F, 0xB4, 0x00, 0x92, 0x12, 0x96, 0x06, 0xC0, 0x07, 0xEA, 0x7C, + 0x84, 0x24, 0xAE, 0x40, 0x84, 0x01, 0x3E, 0x07, 0xF5, 0xA1, 0xDD, 0x9E, 0xFC, 0x00, 0xEB, 0x0F, + 0xEA, 0x6B, 0xB6, 0x20, 0xEB, 0x23, 0xEA, 0xA2, 0xB4, 0x41, 0xFE, 0x17, 0xB6, 0x01, 0x44, 0x16, + 0x00, 0x30, 0xB4, 0x01, 0xEA, 0x57, 0xB6, 0x01, 0x84, 0x01, 0xEA, 0x8F, 0xFC, 0x80, 0xFC, 0x41, + 0x81, 0x20, 0xF1, 0x81, 0xB6, 0x9F, 0x83, 0x82, 0x81, 0x43, 0x81, 0x05, 0x00, 0x6F, 0x80, 0x4C, + 0xEA, 0x8F, 0xB4, 0x9F, 0xF1, 0x01, 0x4E, 0x92, 0x00, 0x0A, 0x5A, 0x90, 0x01, 0x0B, 0x84, 0xE0, + 0x5A, 0x98, 0x02, 0x0A, 0x44, 0x77, 0x21, 0x40, 0xD5, 0x06, 0x44, 0x77, 0x20, 0xC0, 0xD5, 0x03, + 0x44, 0x77, 0x21, 0x00, 0xB4, 0x07, 0x46, 0x2F, 0x8F, 0x0F, 0x50, 0x21, 0x0F, 0xFE, 0xFE, 0x86, + 0xDD, 0x5E, 0x46, 0x00, 0x00, 0xF0, 0xFE, 0x46, 0xFE, 0x57, 0xB6, 0x27, 0xC4, 0x22, 0xA0, 0xB9, + 0x46, 0x17, 0xCF, 0xFF, 0x92, 0x54, 0x40, 0x01, 0x50, 0x08, 0x40, 0x2E, 0x30, 0x08, 0x92, 0x4C, + 0xFE, 0x87, 0xA0, 0x3A, 0x50, 0x10, 0x8F, 0x00, 0xFE, 0x46, 0x00, 0x0F, 0x80, 0x3C, 0x22, 0x3F, + 0x80, 0x18, 0xEA, 0xD8, 0xFE, 0x1F, 0x40, 0x42, 0x7C, 0x08, 0xFF, 0x07, 0x46, 0x08, 0x30, 0x00, + 0xEB, 0x37, 0xFF, 0x06, 0xFF, 0x0F, 0xA8, 0xB9, 0xA9, 0x3A, 0x50, 0x23, 0x80, 0x08, 0xD5, 0x03, + 0x50, 0x23, 0x80, 0x08, 0x50, 0x11, 0x00, 0x08, 0x4E, 0x82, 0x00, 0x23, 0xA0, 0x11, 0xA0, 0xD2, + 0x46, 0x57, 0xCF, 0xFF, 0x50, 0x52, 0x8F, 0x00, 0x92, 0x14, 0x40, 0xA5, 0x30, 0x08, 0xEA, 0x3A, + 0xFE, 0xEE, 0x93, 0x4C, 0x00, 0x5F, 0x80, 0x40, 0x40, 0xA0, 0x28, 0x04, 0x22, 0x0F, 0x80, 0x1A, + 0x40, 0x52, 0xE0, 0x08, 0xFF, 0x47, 0x40, 0x84, 0x7C, 0x08, 0x46, 0x08, 0x30, 0x00, 0x40, 0x52, + 0xA0, 0x04, 0xEB, 0x37, 0xFF, 0x46, 0xFF, 0x5F, 0x14, 0xA1, 0x00, 0x01, 0xA9, 0x52, 0xA0, 0x09, + 0xA0, 0xCA, 0x92, 0x14, 0x40, 0x20, 0x50, 0x08, 0xF0, 0x0A, 0xEA, 0x48, 0x92, 0x0C, 0xFE, 0x17, + 0xA8, 0x09, 0x46, 0x07, 0xCF, 0xFF, 0x50, 0x00, 0x0F, 0x00, 0xFE, 0xC6, 0x00, 0x0F, 0x80, 0x44, + 0x22, 0x2F, 0x80, 0x1C, 0xEA, 0xD8, 0xFE, 0x17, 0x00, 0x2F, 0x80, 0x2C, 0x40, 0x21, 0x7C, 0x08, + 0xFE, 0x17, 0x46, 0x28, 0x30, 0x00, 0x50, 0x21, 0x00, 0xFF, 0xFE, 0x16, 0xFE, 0x1F, 0xA8, 0x0A, + 0xA0, 0x0B, 0x46, 0x2F, 0x0F, 0xE0, 0xFE, 0x16, 0xF3, 0x12, 0x46, 0x20, 0xF0, 0x1F, 0xEA, 0xE3, + 0xFE, 0x9E, 0xFE, 0x87, 0x84, 0x00, 0xA8, 0x8B, 0xA8, 0x0C, 0x5A, 0x98, 0x01, 0x12, 0x44, 0x17, + 0x21, 0x1C, 0x97, 0x9F, 0xB4, 0x41, 0x40, 0x03, 0x60, 0x08, 0x46, 0x6F, 0x0F, 0xFF, 0xEA, 0xB5, + 0xFF, 0x96, 0xFF, 0x87, 0xB6, 0xC1, 0xEB, 0x23, 0xEA, 0xA2, 0xB4, 0x41, 0xD5, 0x13, 0x5A, 0x98, + 0x02, 0x14, 0x44, 0x17, 0x21, 0x5C, 0x97, 0x9F, 0xB4, 0x41, 0x40, 0x03, 0x60, 0x08, 0x46, 0x6F, + 0x0F, 0xFF, 0xEA, 0xB5, 0xFF, 0x96, 0xFF, 0x87, 0xB6, 0xC1, 0xEB, 0x23, 0x44, 0x04, 0x00, 0x00, + 0xB4, 0x41, 0xFE, 0x17, 0xB6, 0x01, 0xFC, 0xC1, 0x46, 0x20, 0x00, 0x83, 0x84, 0x3C, 0x04, 0x31, + 0x00, 0x10, 0x96, 0x0F, 0xFE, 0x5E, 0xFE, 0x0F, 0xEA, 0x73, 0xDD, 0x9E, 0x46, 0x20, 0x00, 0x83, + 0x96, 0x06, 0x04, 0x31, 0x00, 0x10, 0xDD, 0x4F, 0xDD, 0x52, 0xFE, 0x1E, 0xFE, 0x0F, 0xEA, 0x73, + 0xDD, 0x9E, 0xFC, 0x40, 0x46, 0x20, 0x00, 0x83, 0x44, 0x5F, 0xFE, 0xFF, 0x83, 0x82, 0xBB, 0x18, + 0x46, 0x40, 0x0F, 0x03, 0xFE, 0xEE, 0xBB, 0x98, 0xBB, 0x18, 0x50, 0x42, 0x0C, 0x0F, 0x92, 0x68, + 0xEB, 0x3C, 0x58, 0x31, 0x80, 0x70, 0xBB, 0x98, 0xBF, 0x39, 0xBE, 0x3A, 0x04, 0x91, 0x00, 0x3B, + 0xFF, 0xE6, 0xFF, 0xA6, 0x40, 0x44, 0x90, 0x02, 0x04, 0x90, 0x80, 0x02, 0xBB, 0x3C, 0xB5, 0x41, + 0x89, 0x24, 0xA1, 0x0B, 0x96, 0xDF, 0x88, 0xEA, 0x04, 0xA0, 0x80, 0x01, 0x98, 0x5C, 0xBB, 0x18, + 0x88, 0xCA, 0xEA, 0xEE, 0xBB, 0x98, 0xBB, 0x18, 0x92, 0x68, 0xEB, 0x3C, 0x58, 0x31, 0x80, 0x70, + 0xBB, 0x98, 0xBF, 0xB9, 0xBE, 0xBA, 0x14, 0x91, 0x00, 0x3B, 0x96, 0xC9, 0xB9, 0x3C, 0x92, 0x30, + 0xDD, 0x5E, 0xFE, 0x5F, 0xB9, 0xBC, 0xB4, 0x20, 0xB9, 0xB9, 0xA0, 0x41, 0xB9, 0xBA, 0xA0, 0x42, + 0xB9, 0xBB, 0xA4, 0x46, 0xB8, 0x3C, 0x92, 0x10, 0xDD, 0x4E, 0xFE, 0x0F, 0xB8, 0xBC, 0xB8, 0x18, + 0xFF, 0x46, 0xBD, 0x98, 0xFC, 0xC0, 0xFC, 0x20, 0x46, 0x20, 0x00, 0x83, 0x44, 0x3F, 0xFE, 0xFF, + 0x83, 0x82, 0xBC, 0x18, 0x94, 0x4A, 0xFE, 0xE6, 0xBB, 0x98, 0xBB, 0x18, 0x50, 0x51, 0x00, 0xE4, + 0x92, 0x68, 0xEB, 0x3C, 0x58, 0x31, 0x80, 0x72, 0xBB, 0x98, 0xBB, 0x18, 0x50, 0x61, 0x00, 0xE8, + 0xEA, 0xEE, 0xBB, 0x98, 0x50, 0x71, 0x00, 0xEC, 0x88, 0x20, 0x50, 0x21, 0x00, 0xF0, 0x46, 0x30, + 0x00, 0x83, 0x4C, 0x00, 0x80, 0x11, 0xA2, 0xC1, 0xB6, 0x65, 0x83, 0x80, 0xBB, 0x3F, 0x02, 0x40, + 0x01, 0x7E, 0xB6, 0x66, 0xBB, 0x7F, 0xB6, 0x67, 0xB4, 0x62, 0x92, 0x70, 0xEB, 0x4D, 0xFE, 0xE7, + 0xB6, 0x62, 0xD5, 0xEE, 0x83, 0x83, 0xB9, 0x18, 0xDD, 0x52, 0xFE, 0x0E, 0xB8, 0x98, 0xFC, 0xA0, + 0xFC, 0x20, 0x46, 0x10, 0x00, 0x83, 0x44, 0x2F, 0xFE, 0xFF, 0x83, 0x81, 0xBB, 0x18, 0x46, 0x40, + 0xF0, 0x3C, 0xFE, 0x9E, 0xBA, 0x98, 0xBA, 0x18, 0x50, 0x32, 0x00, 0xF0, 0x92, 0x48, 0xEB, 0x32, + 0x58, 0x21, 0x00, 0x70, 0xBA, 0x98, 0xBE, 0x39, 0xB4, 0x80, 0xBD, 0x3A, 0xFF, 0x9E, 0x88, 0xC4, + 0xA1, 0x01, 0xBF, 0x3B, 0xFF, 0x5E, 0x88, 0xA4, 0xA1, 0x02, 0xBA, 0x3C, 0xFE, 0xFE, 0x88, 0x83, + 0xA0, 0xC3, 0x54, 0x21, 0x00, 0xF0, 0xBE, 0xB9, 0x98, 0x13, 0xBD, 0xBA, 0xBC, 0xBB, 0x96, 0x81, + 0xB8, 0x3C, 0x92, 0x10, 0xDD, 0x4E, 0xFE, 0x17, 0xB8, 0xBC, 0xFC, 0xA0, 0xFC, 0x00, 0xDD, 0x56, + 0x46, 0x18, 0x00, 0x00, 0x83, 0x80, 0xBA, 0x6E, 0xFE, 0x57, 0xB9, 0xEE, 0xBA, 0x75, 0xEA, 0x6B, + 0xFE, 0x57, 0xB9, 0xF5, 0xBA, 0x17, 0x46, 0x10, 0x40, 0x00, 0xFE, 0x57, 0xB9, 0x97, 0xBA, 0x75, + 0xEA, 0xBB, 0xFE, 0x56, 0xB9, 0xF5, 0x84, 0x0A, 0xDD, 0x51, 0xFC, 0x80, 0x46, 0x10, 0x00, 0x80, + 0x46, 0x0F, 0xC0, 0x0F, 0x04, 0x20, 0x80, 0x74, 0xDD, 0x41, 0xFE, 0x16, 0x14, 0x00, 0x80, 0x74, + 0xDD, 0x9E, 0x44, 0x34, 0x80, 0x90, 0xEA, 0xA8, 0x94, 0x84, 0xB4, 0x83, 0xFE, 0x8F, 0xFE, 0x17, + 0x44, 0x1F, 0xFB, 0xEE, 0xFE, 0x66, 0x54, 0x00, 0x04, 0x11, 0xFE, 0x0F, 0xB6, 0x03, 0x46, 0x00, + 0x00, 0x80, 0x84, 0x38, 0x50, 0x30, 0x02, 0x6C, 0xB4, 0x43, 0xFE, 0x56, 0x58, 0x10, 0x80, 0x06, + 0xB6, 0x23, 0xB4, 0x43, 0x44, 0x1F, 0xF0, 0xFF, 0xFE, 0x56, 0x58, 0x10, 0x86, 0x00, 0xB6, 0x23, + 0xB4, 0x03, 0x84, 0x21, 0x92, 0x08, 0x96, 0x1F, 0x40, 0x00, 0x80, 0x0C, 0xDD, 0x43, 0xEA, 0x42, + 0xDD, 0x49, 0x04, 0x31, 0x00, 0x6E, 0xEA, 0xE7, 0xDD, 0x41, 0xFE, 0x1E, 0xFE, 0x0F, 0x14, 0x01, + 0x00, 0x6E, 0xDD, 0x9E, 0x3E, 0x07, 0xF5, 0xA4, 0xDD, 0x9E, 0x2E, 0x07, 0xF5, 0xA4, 0xDD, 0x9E, + 0x52, 0x00, 0x00, 0x01, 0x46, 0x20, 0x00, 0x80, 0x96, 0x06, 0xC9, 0x06, 0xDD, 0x4F, 0x04, 0x31, + 0x00, 0x79, 0xDD, 0x52, 0xD5, 0x05, 0xDD, 0x49, 0x04, 0x31, 0x00, 0x79, 0xDD, 0x55, 0xFE, 0x1E, + 0xFE, 0x0F, 0x14, 0x01, 0x00, 0x79, 0xDD, 0x9E, 0x44, 0x37, 0x20, 0x00, 0x54, 0x10, 0x00, 0x01, + 0xB4, 0x83, 0x40, 0x20, 0xA4, 0x08, 0x44, 0x1F, 0xFD, 0xFF, 0xFE, 0x66, 0xFE, 0x57, 0xB6, 0x23, + 0x3E, 0x07, 0xF5, 0xA4, 0xDD, 0x9E, 0x46, 0x10, 0x00, 0x82, 0x04, 0x20, 0x80, 0x08, 0x5A, 0x08, + 0x01, 0x06, 0x84, 0x1C, 0xFE, 0x16, 0xEA, 0x87, 0xD5, 0x03, 0x84, 0x1D, 0xFE, 0x16, 0x14, 0x00, + 0x80, 0x08, 0xDD, 0x9E, 0x46, 0x20, 0x00, 0x83, 0x80, 0x62, 0x04, 0x41, 0x00, 0xEE, 0xDD, 0x4F, + 0x84, 0x40, 0xC8, 0x03, 0x44, 0x20, 0x02, 0x00, 0xFE, 0x8F, 0x44, 0x1F, 0xFC, 0xFF, 0x54, 0x21, + 0x03, 0x00, 0x40, 0x02, 0x04, 0x02, 0xFE, 0x17, 0x14, 0x01, 0x80, 0xEE, 0xDD, 0x9E, 0x46, 0x20, + 0x00, 0x83, 0x80, 0x62, 0x04, 0x41, 0x00, 0xEE, 0xEA, 0xA8, 0x84, 0x40, 0xC8, 0x03, 0x44, 0x20, + 0x08, 0x00, 0xFE, 0x8F, 0x44, 0x1F, 0xF3, 0xFF, 0x54, 0x21, 0x0C, 0x00, 0x40, 0x02, 0x04, 0x02, + 0xFE, 0x17, 0x14, 0x01, 0x80, 0xEE, 0xDD, 0x9E, 0x44, 0x27, 0x20, 0x68, 0x96, 0x01, 0xB4, 0x22, + 0x92, 0x30, 0xDD, 0x5E, 0xFE, 0x47, 0xB6, 0x22, 0x44, 0x27, 0x20, 0x70, 0xB4, 0x22, 0x92, 0x30, + 0xDD, 0x5E, 0xFE, 0x0F, 0xB6, 0x02, 0xDD, 0x9E, 0xC8, 0x08, 0x44, 0x17, 0x20, 0x00, 0xEA, 0x44, + 0xB4, 0x41, 0xDD, 0x41, 0xFE, 0x16, 0xD5, 0x08, 0x5A, 0x08, 0x01, 0x08, 0x44, 0x17, 0x20, 0x00, + 0xEB, 0x2B, 0xB4, 0x41, 0xFE, 0x17, 0xB6, 0x01, 0xDD, 0x9E, 0x44, 0x27, 0x20, 0x00, 0x84, 0x3E, + 0xB4, 0x62, 0x96, 0x06, 0xFE, 0x5E, 0xFE, 0x0F, 0xB6, 0x02, 0xDD, 0x9E, 0x44, 0x27, 0x20, 0x04, + 0x96, 0x06, 0xB4, 0x62, 0x40, 0x10, 0x24, 0x08, 0xEB, 0x00, 0xFE, 0x1E, 0xFE, 0x0F, 0xB6, 0x02, + 0xDD, 0x9E, 0x44, 0x27, 0x20, 0x04, 0x84, 0x3E, 0xB4, 0x62, 0x96, 0x06, 0xFE, 0x5E, 0xFE, 0x0F, + 0xB6, 0x02, 0xDD, 0x9E, 0x44, 0x27, 0x20, 0x00, 0x96, 0x06, 0xB4, 0x62, 0xDD, 0x49, 0xDD, 0x55, + 0xFE, 0x1E, 0xFE, 0x0F, 0xB6, 0x02, 0xDD, 0x9E, 0x84, 0x01, 0x3E, 0x07, 0xF5, 0xA5, 0xDD, 0x9E, + 0x84, 0x00, 0x3E, 0x07, 0xF5, 0xA5, 0xDD, 0x9E, 0x46, 0x00, 0x00, 0x83, 0x04, 0x00, 0x00, 0xEE, + 0x92, 0x08, 0x96, 0x06, 0xDD, 0x9E, 0x44, 0x24, 0x80, 0x90, 0x96, 0x06, 0xB4, 0x62, 0x94, 0x44, + 0xEB, 0x11, 0xFE, 0x1E, 0xFE, 0x0F, 0xB6, 0x02, 0xDD, 0x9E, 0xC9, 0x06, 0x44, 0x27, 0x10, 0x00, + 0xB4, 0x22, 0xFE, 0x0F, 0xD5, 0x08, 0x5A, 0x18, 0x01, 0x0E, 0x44, 0x27, 0x10, 0x00, 0xFE, 0x03, + 0xB4, 0x22, 0xFE, 0x0E, 0x94, 0x04, 0xEA, 0xC3, 0xB4, 0x02, 0x92, 0x1C, 0xEA, 0x6A, 0xFE, 0x0F, + 0xB6, 0x02, 0xDD, 0x9E, 0x5A, 0x18, 0x01, 0x07, 0x44, 0x27, 0x10, 0x04, 0xB4, 0x22, 0xFE, 0x0F, + 0xD5, 0x07, 0xC9, 0x0D, 0x44, 0x27, 0x10, 0x04, 0xFE, 0x03, 0xB4, 0x22, 0xFE, 0x0E, 0x94, 0x04, + 0xEA, 0xC3, 0xB4, 0x02, 0x92, 0x1C, 0xEA, 0x6A, 0xFE, 0x0F, 0xB6, 0x02, 0xDD, 0x9E, 0x5A, 0x18, + 0x01, 0x07, 0x44, 0x27, 0x10, 0x08, 0xB4, 0x22, 0xFE, 0x0F, 0xD5, 0x07, 0xC9, 0x0D, 0x44, 0x27, + 0x10, 0x08, 0xFE, 0x03, 0xB4, 0x22, 0xFE, 0x0E, 0x94, 0x04, 0xEA, 0xC3, 0xB4, 0x02, 0x92, 0x1C, + 0xEA, 0x6A, 0xFE, 0x0F, 0xB6, 0x02, 0xDD, 0x9E, 0xC8, 0x06, 0xEB, 0x2D, 0x84, 0x1E, 0xB4, 0x41, + 0xFE, 0x16, 0xD5, 0x06, 0x5A, 0x08, 0x01, 0x12, 0xEB, 0x2D, 0xB4, 0x01, 0xDD, 0x45, 0x44, 0x27, + 0x10, 0x0C, 0xB6, 0x01, 0xB4, 0x02, 0x94, 0x04, 0xEB, 0x0D, 0xEA, 0xC3, 0xB4, 0x02, 0x92, 0x1C, + 0xEA, 0x6A, 0xFE, 0x0F, 0xB6, 0x02, 0xDD, 0x9E, 0x5A, 0x08, 0x02, 0x0D, 0xEB, 0x2D, 0xB4, 0x01, + 0xDD, 0x45, 0xB6, 0x01, 0x44, 0x17, 0x10, 0x0C, 0xB4, 0x01, 0xB4, 0x01, 0x92, 0x1C, 0xEA, 0x6A, + 0xB6, 0x01, 0xDD, 0x9E, 0x44, 0x27, 0x10, 0x18, 0x96, 0x06, 0xB4, 0x62, 0xDD, 0x4F, 0xDD, 0x52, + 0xFE, 0x1E, 0xFE, 0x0F, 0xB6, 0x02, 0xDD, 0x9E, 0x44, 0x16, 0x00, 0x00, 0x5A, 0x08, 0x01, 0x05, + 0xB4, 0x01, 0xDD, 0x45, 0xD5, 0x04, 0xB4, 0x41, 0x84, 0x1E, 0xFE, 0x16, 0xB6, 0x01, 0xDD, 0x9E, + 0xFC, 0x00, 0x49, 0x00, 0x13, 0xBD, 0xFC, 0x80, 0xFC, 0x00, 0x2E, 0x17, 0xF9, 0x60, 0x44, 0x27, + 0x21, 0x1C, 0x5A, 0x18, 0x01, 0x07, 0xB4, 0x22, 0x92, 0x31, 0x40, 0x10, 0xC4, 0x08, 0xD5, 0x0A, + 0x8E, 0x01, 0x40, 0x00, 0x3C, 0x08, 0x40, 0x10, 0x3C, 0x09, 0xB4, 0x02, 0x92, 0x11, 0x40, 0x00, + 0x44, 0x08, 0xFE, 0x0F, 0xB6, 0x02, 0x84, 0x00, 0x3E, 0x07, 0xF9, 0x60, 0x84, 0x00, 0x49, 0xFF, + 0xFC, 0x75, 0xFC, 0x80, 0xFC, 0x00, 0x49, 0xFF, 0xFC, 0x6E, 0xFC, 0x80, 0x44, 0x06, 0x00, 0x00, + 0xB4, 0x00, 0x92, 0x1C, 0x96, 0x06, 0xDD, 0x9E, 0x44, 0x14, 0x01, 0x08, 0xB4, 0x01, 0xDD, 0x45, + 0xB6, 0x01, 0x44, 0x16, 0x38, 0x20, 0xB4, 0x01, 0xEA, 0x57, 0xB6, 0x01, 0xEB, 0x1D, 0xB4, 0x01, + 0xEA, 0x57, 0xB6, 0x01, 0xDD, 0x9E, 0x44, 0x26, 0x38, 0x20, 0xDD, 0x52, 0xB4, 0x22, 0xFE, 0x46, + 0xB6, 0x22, 0xEB, 0x1D, 0xB4, 0x41, 0xFE, 0x16, 0xB6, 0x01, 0xEA, 0xD0, 0x84, 0x1E, 0xB4, 0x41, + 0xFE, 0x16, 0xB6, 0x01, 0xDD, 0x9E, 0x44, 0x14, 0x01, 0x08, 0xB4, 0x01, 0xDD, 0x45, 0xB6, 0x01, + 0x44, 0x16, 0x38, 0x20, 0xB4, 0x01, 0xDD, 0x45, 0xB6, 0x01, 0xEB, 0x1D, 0xB4, 0x01, 0xDD, 0x45, + 0xB6, 0x01, 0xDD, 0x9E, 0x44, 0x26, 0x38, 0x20, 0x84, 0x1E, 0xB4, 0x22, 0xFE, 0x46, 0xB6, 0x22, + 0x44, 0x26, 0x34, 0x20, 0xB4, 0x22, 0xFE, 0x46, 0xB6, 0x22, 0xEA, 0xD0, 0xB4, 0x41, 0xFE, 0x16, + 0xB6, 0x01, 0xDD, 0x9E, 0x44, 0x36, 0x38, 0x1C, 0x84, 0x5C, 0xB4, 0x23, 0x96, 0x0F, 0xFE, 0x56, + 0xFE, 0x47, 0xB6, 0x23, 0x44, 0x16, 0x34, 0x1C, 0xB4, 0x61, 0xFE, 0x9E, 0xFE, 0x17, 0xB6, 0x01, + 0xDD, 0x9E, 0x44, 0x06, 0x38, 0x18, 0xB4, 0x00, 0xDD, 0x9E, 0x44, 0x34, 0x01, 0x08, 0xDD, 0x4C, + 0xB4, 0x43, 0x96, 0x6F, 0x58, 0x21, 0x00, 0x01, 0xB6, 0x43, 0x44, 0x36, 0x38, 0x14, 0x40, 0x20, + 0x20, 0x09, 0xB4, 0x03, 0x92, 0x18, 0xEA, 0xD8, 0xFE, 0x17, 0x44, 0x26, 0x38, 0x08, 0xB6, 0x03, + 0xB4, 0x62, 0xEA, 0xED, 0x46, 0x1C, 0x0F, 0xFF, 0xDD, 0x4A, 0xFE, 0x5E, 0xFE, 0x47, 0xB6, 0x22, + 0x44, 0x16, 0x38, 0x04, 0xEA, 0x55, 0xB4, 0x41, 0xFE, 0x17, 0xB6, 0x01, 0x44, 0x14, 0x80, 0x0C, + 0xB4, 0x01, 0x92, 0x03, 0x96, 0x06, 0xC0, 0xFD, 0x44, 0x04, 0x80, 0x0C, 0x84, 0x28, 0xAE, 0x40, + 0xEA, 0xD0, 0x84, 0x1E, 0xB4, 0x41, 0xFE, 0x16, 0xB6, 0x01, 0xDD, 0x9E, 0x44, 0x34, 0x01, 0x08, + 0xDD, 0x4C, 0xB4, 0x43, 0x96, 0x6F, 0x58, 0x21, 0x00, 0x01, 0xB6, 0x43, 0x44, 0x36, 0x34, 0x14, + 0x40, 0x20, 0x20, 0x09, 0xB4, 0x03, 0x92, 0x18, 0xEA, 0xD8, 0xFE, 0x17, 0x44, 0x26, 0x34, 0x08, + 0xB6, 0x03, 0xB4, 0x62, 0xEA, 0xED, 0x46, 0x1C, 0x0F, 0xFF, 0xDD, 0x4A, 0xFE, 0x5E, 0xFE, 0x47, + 0xB6, 0x22, 0x44, 0x16, 0x34, 0x04, 0xEA, 0x55, 0xB4, 0x41, 0xFE, 0x17, 0xB6, 0x01, 0x44, 0x14, + 0x80, 0x0C, 0xB4, 0x01, 0x92, 0x13, 0x96, 0x06, 0xC0, 0xFD, 0x44, 0x04, 0x80, 0x0E, 0x84, 0x28, + 0xAE, 0x40, 0xEA, 0xD0, 0x84, 0x1E, 0xB4, 0x41, 0xFE, 0x16, 0xB6, 0x01, 0xDD, 0x9E, 0xFC, 0x01, + 0xB6, 0x3F, 0x80, 0x22, 0xF3, 0x81, 0x49, 0xFF, 0xFF, 0x9A, 0xB4, 0x1F, 0xF1, 0x01, 0x49, 0xFF, + 0xFF, 0xC7, 0xFC, 0x81, 0x44, 0x16, 0x3C, 0x04, 0xB4, 0x01, 0xDD, 0x45, 0xB6, 0x01, 0xDD, 0x9E, + 0x44, 0x26, 0x38, 0x04, 0xB4, 0x22, 0x44, 0x06, 0x38, 0x04, 0x92, 0x28, 0x96, 0x46, 0xC9, 0xFB, + 0xB4, 0x40, 0x84, 0x3E, 0xFE, 0x56, 0xB6, 0x20, 0x80, 0x20, 0xB4, 0x01, 0x92, 0x08, 0x96, 0x06, + 0xC8, 0xFD, 0x44, 0x26, 0x34, 0x04, 0xB4, 0x22, 0x44, 0x06, 0x34, 0x04, 0x92, 0x28, 0x96, 0x46, + 0xC9, 0xFB, 0xB4, 0x40, 0x84, 0x3E, 0xFE, 0x56, 0xB6, 0x20, 0x80, 0x20, 0xB4, 0x01, 0x92, 0x08, + 0x96, 0x06, 0xC8, 0xFD, 0xDD, 0x9E, 0x44, 0x04, 0x80, 0x8C, 0x84, 0x20, 0xB6, 0x20, 0xDD, 0x9E, + 0xFC, 0x40, 0x46, 0x70, 0x00, 0x83, 0x40, 0x52, 0xAC, 0x08, 0xFE, 0x2F, 0x40, 0x42, 0x44, 0x08, + 0x83, 0x87, 0x04, 0x93, 0x80, 0x14, 0xFE, 0x27, 0x40, 0x10, 0xE0, 0x08, 0x46, 0x50, 0xF7, 0xFF, + 0x46, 0x6F, 0x08, 0x00, 0xFE, 0x0F, 0x50, 0x52, 0x88, 0x01, 0x50, 0x63, 0x07, 0xFE, 0xFE, 0x2E, + 0x40, 0x64, 0x98, 0x02, 0x40, 0x10, 0x18, 0x04, 0xB9, 0x94, 0xBC, 0x15, 0xEB, 0x4D, 0x46, 0x10, + 0x07, 0xF0, 0x46, 0x0F, 0xF8, 0x0F, 0xFE, 0x9F, 0x50, 0x10, 0x83, 0xFF, 0x50, 0x00, 0x0C, 0x00, + 0x40, 0x31, 0x04, 0x02, 0xFE, 0x26, 0x40, 0x21, 0x80, 0x04, 0xBA, 0x95, 0xFC, 0xC0, 0x44, 0x10, + 0x0F, 0xFF, 0xFE, 0x0C, 0x46, 0x10, 0x00, 0x83, 0x14, 0x00, 0x80, 0xBB, 0xDD, 0x9E, 0x46, 0x00, + 0x00, 0x83, 0x04, 0x00, 0x00, 0x16, 0x96, 0x01, 0xDD, 0x9E, 0xB4, 0x40, 0xEA, 0xD1, 0xA0, 0x41, + 0x14, 0x21, 0x80, 0x4A, 0xA0, 0x82, 0xEA, 0x37, 0xA0, 0x03, 0x14, 0x21, 0x80, 0x4B, 0xEB, 0x25, + 0x04, 0x11, 0x80, 0x4C, 0xDD, 0x47, 0x92, 0x36, 0xEA, 0xFE, 0xFE, 0x57, 0x14, 0x11, 0x80, 0x4C, + 0xEA, 0xFF, 0x04, 0x01, 0x80, 0x58, 0x92, 0x16, 0xEA, 0x33, 0xFE, 0x0F, 0x14, 0x01, 0x80, 0x58, + 0xDD, 0x9E, 0x46, 0x20, 0x00, 0x83, 0x96, 0x0F, 0xEA, 0x3D, 0xDD, 0x49, 0xEA, 0xCE, 0xFE, 0x1E, + 0xFE, 0x0F, 0xEA, 0x3E, 0xDD, 0x9E, 0x46, 0x20, 0x00, 0x81, 0x96, 0x06, 0xA0, 0xD5, 0xDD, 0x4F, + 0xDD, 0x52, 0xFE, 0x1E, 0xFE, 0x0F, 0xA8, 0x15, 0xDD, 0x9E, 0xC9, 0x08, 0x46, 0x20, 0x00, 0x91, + 0x84, 0x3E, 0xB4, 0x62, 0x96, 0x06, 0xFE, 0x5E, 0xD5, 0x0A, 0x5A, 0x18, 0x01, 0x0B, 0x46, 0x20, + 0x00, 0x91, 0x96, 0x06, 0xB4, 0x62, 0x94, 0x41, 0x84, 0x1D, 0xFE, 0x1E, 0xFE, 0x0F, 0xB6, 0x02, + 0xDD, 0x9E, 0xC8, 0x1D, 0xDD, 0x43, 0x46, 0x0E, 0x0E, 0x0E, 0x50, 0x41, 0x00, 0x64, 0xA0, 0xE1, + 0x50, 0x00, 0x00, 0xE0, 0xFE, 0x1E, 0x44, 0x31, 0x01, 0x08, 0xFE, 0x1F, 0xA8, 0x21, 0xA0, 0xE2, + 0x84, 0x10, 0xFE, 0x1E, 0xA8, 0x22, 0x40, 0x10, 0xB8, 0x08, 0x40, 0x00, 0xB8, 0x09, 0xB4, 0x24, + 0x92, 0x32, 0x40, 0x10, 0xC8, 0x08, 0xFE, 0x47, 0xB6, 0x24, 0xDD, 0x9E, 0x5A, 0x08, 0x01, 0x1A, + 0xEA, 0x2D, 0x46, 0x0E, 0x0E, 0x0E, 0x50, 0x30, 0x80, 0x64, 0xA0, 0x99, 0x50, 0x00, 0x00, 0xE0, + 0xFE, 0x16, 0x58, 0x00, 0x00, 0x08, 0xA8, 0x19, 0xA0, 0x9A, 0x84, 0x10, 0xFE, 0x16, 0xA8, 0x1A, + 0xB4, 0x03, 0x44, 0x21, 0x01, 0xD0, 0x92, 0x12, 0x40, 0x00, 0x48, 0x08, 0xFE, 0x17, 0xB6, 0x03, + 0xDD, 0x9E, 0xFC, 0x00, 0x44, 0x14, 0x2C, 0x1C, 0xEB, 0x11, 0xB4, 0x41, 0xFE, 0x16, 0x84, 0x41, + 0xB6, 0x01, 0x80, 0x62, 0xEA, 0xB8, 0xEA, 0xAF, 0xDD, 0x40, 0xFC, 0x80, 0x44, 0x27, 0x20, 0x00, + 0x96, 0x06, 0xB4, 0x62, 0x94, 0x44, 0xEB, 0x11, 0xFE, 0x1E, 0xFE, 0x0F, 0xB6, 0x02, 0xDD, 0x9E, + 0xFC, 0x00, 0xEA, 0x2A, 0xDD, 0x52, 0x83, 0x86, 0xB9, 0x1C, 0xFE, 0x0E, 0xB8, 0x9C, 0xDD, 0x57, + 0xEA, 0x2F, 0xB9, 0x1C, 0xEA, 0x55, 0xFE, 0x0F, 0xB8, 0x9C, 0xDD, 0x57, 0xEA, 0x2F, 0xB9, 0x1C, + 0xEB, 0x2B, 0xFE, 0x0F, 0xB8, 0x9C, 0xDD, 0x57, 0xEA, 0x2F, 0xFC, 0x80, 0x46, 0x00, 0x00, 0x81, + 0xEA, 0xBB, 0x04, 0x20, 0x00, 0x71, 0x46, 0x30, 0x30, 0x00, 0xFE, 0x56, 0xEA, 0xEF, 0x04, 0x20, + 0x00, 0x1A, 0x46, 0x1E, 0x0F, 0xFF, 0xDD, 0x4A, 0xFE, 0x8E, 0xFE, 0x9F, 0x14, 0x20, 0x00, 0x1A, + 0x04, 0x20, 0x00, 0x14, 0xFE, 0x56, 0xFE, 0x5F, 0x14, 0x10, 0x00, 0x14, 0x04, 0x10, 0x00, 0x1A, + 0x92, 0x25, 0x94, 0x4D, 0x58, 0x10, 0x80, 0x02, 0x14, 0x10, 0x00, 0x1A, 0x04, 0x10, 0x00, 0x71, + 0x92, 0x25, 0x94, 0x4D, 0x58, 0x10, 0x80, 0x01, 0xEA, 0xEF, 0x04, 0x20, 0x00, 0x71, 0x44, 0x1F, + 0xE0, 0xFF, 0xFE, 0x56, 0xEA, 0xEF, 0xDD, 0x9E, 0xFC, 0x00, 0xEA, 0x2A, 0x84, 0x41, 0xEA, 0x9F, + 0xB4, 0x1C, 0x80, 0x62, 0x92, 0x08, 0xDD, 0x4C, 0x58, 0x00, 0x00, 0x2D, 0xB6, 0x1C, 0xB4, 0x3C, + 0x44, 0x0F, 0x80, 0xFF, 0xFE, 0x0E, 0x58, 0x00, 0x15, 0x00, 0xB6, 0x1C, 0xEB, 0x46, 0x50, 0x03, + 0x0A, 0x94, 0xDD, 0x40, 0xB9, 0x01, 0x46, 0x0F, 0xF7, 0xFF, 0xDD, 0x41, 0xFE, 0x0E, 0x84, 0x41, + 0xB8, 0x81, 0xEB, 0x4C, 0xEB, 0x16, 0x80, 0x62, 0xDD, 0x40, 0xFC, 0x80, 0xFC, 0x00, 0x80, 0x40, + 0x5A, 0x08, 0x02, 0x44, 0xEA, 0x58, 0xEA, 0x2A, 0x44, 0x2F, 0x80, 0xFF, 0x50, 0x33, 0x0A, 0x94, + 0xEB, 0x46, 0x5A, 0x08, 0x1F, 0x1D, 0xEA, 0x9F, 0xB4, 0x1C, 0xFE, 0x86, 0x58, 0x21, 0x15, 0x00, + 0xB6, 0x5C, 0x84, 0x41, 0x80, 0x03, 0x80, 0x62, 0xDD, 0x40, 0xB9, 0x01, 0xEA, 0x9C, 0xDD, 0x41, + 0xFE, 0x0E, 0x84, 0x41, 0xB8, 0x81, 0xEB, 0x4C, 0xEB, 0x16, 0x80, 0x62, 0xDD, 0x40, 0xEA, 0x8D, + 0xEA, 0x4D, 0xB4, 0x22, 0xFE, 0x0E, 0x44, 0x13, 0x00, 0x00, 0xD5, 0x1A, 0xEA, 0x9F, 0xB4, 0x1C, + 0xFE, 0x86, 0x58, 0x21, 0x1A, 0x00, 0xB6, 0x5C, 0x84, 0x41, 0x80, 0x03, 0x80, 0x62, 0xDD, 0x40, + 0xB9, 0x01, 0xEA, 0x9C, 0xDD, 0x41, 0xFE, 0x0E, 0x84, 0x41, 0xB8, 0x81, 0xEB, 0x4C, 0xEB, 0x16, + 0x80, 0x62, 0xDD, 0x40, 0xEA, 0x8D, 0xEA, 0x4D, 0xB4, 0x22, 0xFE, 0x0E, 0xEA, 0x6B, 0xFE, 0x0F, + 0xB6, 0x02, 0xEA, 0x70, 0xEA, 0x5B, 0xD5, 0x14, 0xC8, 0x15, 0xEA, 0x2D, 0x46, 0x0F, 0xBF, 0xFF, + 0x50, 0x30, 0x8E, 0x98, 0xB4, 0x43, 0xDD, 0x41, 0xFE, 0x16, 0xB6, 0x03, 0xB4, 0x43, 0x46, 0x00, + 0x20, 0x00, 0xFE, 0x17, 0xB6, 0x03, 0x50, 0x00, 0x8A, 0x98, 0x50, 0x10, 0x86, 0x98, 0x84, 0x41, + 0xD5, 0x14, 0x5A, 0x08, 0x01, 0x15, 0xEA, 0x2D, 0x46, 0x00, 0x40, 0x00, 0x50, 0x40, 0x8E, 0x98, + 0xB4, 0x64, 0xFE, 0x1F, 0xB6, 0x04, 0xB4, 0x64, 0x46, 0x00, 0x20, 0x00, 0xFE, 0x1F, 0xB6, 0x04, + 0x50, 0x00, 0x8A, 0x98, 0x50, 0x10, 0x86, 0x98, 0x80, 0x62, 0xDD, 0x40, 0xFC, 0x80, 0x46, 0x00, + 0x00, 0x81, 0x46, 0x30, 0xB0, 0x00, 0x04, 0x10, 0x00, 0x77, 0x92, 0x25, 0x94, 0x4D, 0x58, 0x10, + 0x80, 0x1E, 0x14, 0x10, 0x00, 0x77, 0x04, 0x20, 0x00, 0x76, 0x46, 0x1E, 0x0F, 0xFF, 0xDD, 0x4A, + 0xFE, 0x8E, 0xFE, 0x9F, 0x14, 0x20, 0x00, 0x76, 0x04, 0x40, 0x00, 0x78, 0x46, 0x2F, 0x83, 0xFF, + 0xEA, 0xE3, 0xFE, 0xA6, 0x46, 0x40, 0x1C, 0x00, 0xFE, 0xA7, 0x14, 0x20, 0x00, 0x78, 0x04, 0x20, + 0x00, 0x1B, 0xFE, 0x56, 0xFE, 0x5F, 0x14, 0x10, 0x00, 0x1B, 0xDD, 0x9E, 0xFC, 0x00, 0xEA, 0x39, + 0xC0, 0x19, 0xEA, 0x71, 0xE6, 0x05, 0xE8, 0x0A, 0x84, 0x61, 0x84, 0x09, 0xFA, 0x2F, 0x44, 0x20, + 0x00, 0x82, 0x44, 0x40, 0x00, 0xE8, 0x80, 0xA3, 0xDD, 0x46, 0x84, 0x61, 0x84, 0x05, 0xFA, 0x2F, + 0x44, 0x20, 0x00, 0x56, 0x44, 0x40, 0x00, 0xFF, 0x80, 0xA3, 0xDD, 0x46, 0x49, 0xFF, 0xFF, 0xC1, + 0xFC, 0x80, 0xEA, 0x71, 0xE6, 0x05, 0xE8, 0x0A, 0x84, 0x61, 0x84, 0x09, 0xFA, 0x2F, 0x44, 0x20, + 0x00, 0x82, 0x44, 0x40, 0x00, 0xC0, 0x80, 0xA3, 0xDD, 0x46, 0x84, 0x61, 0x84, 0x05, 0xFA, 0x2F, + 0x44, 0x20, 0x00, 0x56, 0x44, 0x40, 0x00, 0xF0, 0x80, 0xA3, 0xDD, 0x46, 0xFC, 0x80, 0xFC, 0x00, + 0xEA, 0x2A, 0x84, 0x00, 0xEB, 0x06, 0xEB, 0x49, 0x83, 0x86, 0xB9, 0x1C, 0xEA, 0x44, 0xDD, 0x41, + 0xFE, 0x0E, 0xB8, 0x9C, 0xDD, 0x57, 0xEA, 0x2F, 0xB9, 0x1C, 0xDD, 0x55, 0xFE, 0x0E, 0xB8, 0x9C, + 0xDD, 0x57, 0xEA, 0x2F, 0xB8, 0x1C, 0xEA, 0x57, 0xB8, 0x9C, 0xDD, 0x57, 0xEA, 0x2F, 0xB9, 0x1C, + 0x46, 0x00, 0x40, 0x00, 0xFE, 0x0F, 0xB8, 0x9C, 0x44, 0x00, 0x01, 0x2C, 0xDD, 0x51, 0xB9, 0x1C, + 0x46, 0x0F, 0xBF, 0xFF, 0xDD, 0x41, 0xFE, 0x0E, 0xB8, 0x9C, 0x49, 0xFF, 0xFF, 0xA9, 0xFC, 0x80, + 0x46, 0x10, 0x00, 0x80, 0x50, 0x50, 0x80, 0x80, 0x50, 0x10, 0x80, 0xB0, 0xA2, 0x81, 0xAA, 0xA9, + 0xD9, 0xFE, 0xDD, 0x9E, 0x46, 0x10, 0x00, 0x80, 0x50, 0x50, 0x80, 0xB0, 0x50, 0x10, 0x80, 0xC4, + 0xA2, 0x81, 0xAA, 0xA9, 0xD9, 0xFE, 0xDD, 0x9E, 0xB4, 0x40, 0xEA, 0xD1, 0xA0, 0x41, 0x14, 0x21, + 0x80, 0x47, 0xA0, 0x82, 0xEA, 0x37, 0xA0, 0x03, 0x14, 0x21, 0x80, 0x48, 0xEB, 0x25, 0xEB, 0x0E, + 0xDD, 0x47, 0x92, 0x36, 0xEA, 0xFE, 0xFE, 0x57, 0xEA, 0xDF, 0xEA, 0xFF, 0x04, 0x01, 0x80, 0x57, + 0x92, 0x16, 0xEA, 0x33, 0xFE, 0x0F, 0xEB, 0x12, 0xDD, 0x9E, 0x46, 0x10, 0x00, 0x80, 0x50, 0x50, + 0x80, 0x40, 0x50, 0x30, 0x80, 0x46, 0xA6, 0x41, 0xA6, 0x80, 0x94, 0x4C, 0xFE, 0x57, 0x96, 0x48, + 0xAE, 0x68, 0x00, 0x10, 0x00, 0x0D, 0x00, 0x20, 0x00, 0x0C, 0x94, 0x4C, 0xFE, 0x57, 0x96, 0x48, + 0x10, 0x12, 0x80, 0x0C, 0x8C, 0xA1, 0x8C, 0x02, 0xDB, 0xEF, 0xDD, 0x9E, 0xA6, 0x81, 0x80, 0xA0, + 0x94, 0x94, 0x08, 0x12, 0x80, 0x05, 0xFE, 0x8F, 0xEA, 0x62, 0x96, 0x90, 0x10, 0x20, 0x80, 0x48, + 0xA6, 0xA9, 0xA6, 0xC5, 0x94, 0x94, 0xFE, 0x9F, 0x96, 0x90, 0x10, 0x20, 0x80, 0x54, 0xA6, 0x83, + 0xA6, 0xC2, 0x94, 0x94, 0xFE, 0x9F, 0x96, 0x90, 0x10, 0x20, 0x80, 0x49, 0xA6, 0xAB, 0xA6, 0xEA, + 0x94, 0x94, 0xFE, 0x9F, 0x96, 0x90, 0x10, 0x20, 0x80, 0x55, 0xA6, 0x84, 0x84, 0x0F, 0xFE, 0x86, + 0x40, 0x31, 0x40, 0x08, 0x46, 0x4F, 0xFF, 0x0F, 0x04, 0x20, 0x80, 0x12, 0x50, 0x42, 0x0F, 0xFF, + 0xFE, 0xA6, 0xFE, 0x9F, 0x14, 0x20, 0x80, 0x12, 0xA6, 0xAC, 0xFE, 0x16, 0x40, 0x20, 0x40, 0x08, + 0x04, 0x00, 0x80, 0x15, 0xFE, 0x26, 0xFE, 0x17, 0x14, 0x00, 0x80, 0x15, 0xDD, 0x9E, 0x5A, 0x00, + 0x02, 0x16, 0xE6, 0x03, 0xE8, 0x03, 0xC0, 0x07, 0xDD, 0x9E, 0x5A, 0x00, 0x03, 0x25, 0x5A, 0x00, + 0x04, 0x16, 0xDD, 0x9E, 0xDD, 0x43, 0xEA, 0x82, 0x04, 0x01, 0x00, 0x20, 0x92, 0x0B, 0x40, 0x00, + 0x2C, 0x08, 0xFE, 0x47, 0x14, 0x11, 0x00, 0x20, 0xDD, 0x9E, 0xDD, 0x43, 0xEA, 0x82, 0x04, 0x01, + 0x00, 0x21, 0x92, 0x0B, 0x40, 0x00, 0x2C, 0x08, 0xD5, 0x0A, 0xDD, 0x43, 0xEA, 0x82, 0xEB, 0x4B, + 0x04, 0x31, 0x00, 0x21, 0x46, 0x1F, 0x80, 0x0F, 0xDD, 0x4A, 0xFE, 0x5E, 0xFE, 0x47, 0x14, 0x11, + 0x00, 0x21, 0xDD, 0x9E, 0xFC, 0x00, 0x80, 0xC1, 0xEA, 0xAA, 0xDD, 0x43, 0x54, 0x13, 0x07, 0xFF, + 0x95, 0x8E, 0x04, 0x11, 0x03, 0x98, 0x44, 0x0E, 0x00, 0x3F, 0xFE, 0x46, 0xFE, 0x77, 0x14, 0x11, + 0x03, 0x98, 0xEA, 0x8A, 0xFC, 0x80, 0x46, 0x20, 0x00, 0x83, 0x96, 0x06, 0xEA, 0xD7, 0x04, 0x31, + 0x00, 0xC0, 0xEA, 0x44, 0xDD, 0x41, 0xFE, 0x1E, 0xFE, 0x0F, 0x14, 0x01, 0x00, 0xC0, 0xDD, 0x9E, + 0x46, 0x20, 0x00, 0x83, 0x96, 0x06, 0x40, 0x10, 0x64, 0x08, 0x04, 0x31, 0x00, 0xC0, 0xEA, 0x9C, + 0xDD, 0x41, 0xFE, 0x1E, 0xFE, 0x0F, 0x14, 0x01, 0x00, 0xC0, 0xDD, 0x9E, 0x46, 0x20, 0x00, 0x83, + 0x96, 0x0F, 0xEB, 0x2A, 0xDD, 0x4F, 0x44, 0x0F, 0xFC, 0xFF, 0xFE, 0x1E, 0xFE, 0x0F, 0xEB, 0x3D, + 0xDD, 0x9E, 0x46, 0x20, 0x00, 0x83, 0x84, 0x3E, 0xEB, 0x2A, 0x96, 0x06, 0xFE, 0x5E, 0xFE, 0x0F, + 0xEB, 0x3D, 0xDD, 0x9E, 0x46, 0x20, 0x00, 0x83, 0x96, 0x06, 0xEB, 0x2A, 0xEA, 0xA8, 0xEB, 0x2E, + 0xFE, 0x1E, 0xFE, 0x0F, 0xEB, 0x3D, 0xDD, 0x9E, 0x46, 0x10, 0x00, 0x83, 0xEA, 0x55, 0x04, 0x20, + 0x80, 0x0E, 0xFE, 0x17, 0x14, 0x00, 0x80, 0x0E, 0xDD, 0x9E, 0x46, 0x10, 0x00, 0x83, 0x46, 0x2E, + 0x7F, 0xFF, 0x04, 0x30, 0x80, 0x0E, 0xEA, 0xE3, 0xFE, 0x9E, 0x14, 0x20, 0x80, 0x0E, 0x5A, 0x08, + 0x01, 0x11, 0x84, 0x1F, 0x14, 0x00, 0x80, 0x0B, 0x14, 0x00, 0x80, 0x0C, 0x04, 0x20, 0x80, 0x30, + 0xEA, 0x36, 0xFE, 0x17, 0xEA, 0xF9, 0x04, 0x20, 0x80, 0x30, 0xEA, 0xCC, 0xFE, 0x17, 0xD5, 0x0E, + 0x84, 0x00, 0x14, 0x00, 0x80, 0x0B, 0x14, 0x00, 0x80, 0x0C, 0x04, 0x00, 0x80, 0x30, 0x92, 0x10, + 0xDD, 0x4E, 0xEA, 0xF9, 0x04, 0x00, 0x80, 0x30, 0x96, 0x01, 0xEA, 0xF9, 0xDD, 0x9E, 0x46, 0x20, + 0x00, 0x83, 0xDD, 0x4F, 0x04, 0x31, 0x00, 0x0E, 0x40, 0x00, 0x24, 0x08, 0xFE, 0x0F, 0x44, 0x1F, + 0xFC, 0xFF, 0x54, 0x00, 0x03, 0x00, 0xFE, 0x5E, 0xFE, 0x0F, 0x14, 0x01, 0x00, 0x0E, 0xDD, 0x9E, + 0x46, 0x20, 0x00, 0x81, 0x50, 0x51, 0x00, 0x90, 0x50, 0x31, 0x00, 0x9A, 0x08, 0x20, 0x00, 0x01, + 0x88, 0x41, 0x96, 0x90, 0x18, 0x22, 0x80, 0x01, 0xDB, 0xFA, 0xDD, 0x9E, 0xFC, 0x40, 0x84, 0x60, + 0x80, 0x43, 0x80, 0xC3, 0x46, 0x70, 0x00, 0x80, 0x8C, 0x21, 0x85, 0x2F, 0xB4, 0xA7, 0x95, 0x1A, + 0x40, 0x52, 0x90, 0x0D, 0x97, 0x57, 0xD9, 0x07, 0x40, 0x50, 0x10, 0x0C, 0x40, 0x44, 0x90, 0x0C, + 0xFF, 0xAF, 0xFE, 0xA7, 0x8C, 0x61, 0x5A, 0x38, 0x08, 0xF3, 0xEA, 0x2D, 0xFE, 0xD3, 0x83, 0x81, + 0xB8, 0x23, 0xFE, 0xB6, 0xFE, 0x1E, 0xFE, 0x87, 0xBA, 0xA3, 0xFC, 0xC0, 0x46, 0x00, 0x00, 0x81, + 0x04, 0x00, 0x00, 0x23, 0x96, 0x1F, 0xDD, 0x9E, 0x46, 0x10, 0x00, 0x81, 0x04, 0x00, 0x80, 0x12, + 0x92, 0x10, 0x96, 0x0F, 0xC8, 0x08, 0x04, 0x00, 0x80, 0x12, 0x92, 0x08, 0x96, 0x06, 0x56, 0x00, + 0x00, 0x01, 0xDD, 0x9E, 0x84, 0x01, 0xDD, 0x9E, 0x46, 0x20, 0x00, 0x81, 0xDD, 0x50, 0xDD, 0x49, + 0x04, 0x31, 0x00, 0x49, 0x46, 0x0F, 0xC0, 0x0F, 0xDD, 0x41, 0xFE, 0x1E, 0xFE, 0x0F, 0x14, 0x01, + 0x00, 0x49, 0xDD, 0x9E, 0x46, 0x20, 0x00, 0x80, 0xDD, 0x50, 0x04, 0x11, 0x00, 0x75, 0x92, 0x2A, + 0xEA, 0x37, 0xFE, 0x47, 0x14, 0x11, 0x00, 0x75, 0xDD, 0x9E, 0x5A, 0x00, 0x02, 0x1F, 0xE6, 0x03, + 0xE8, 0x03, 0xC0, 0x07, 0xDD, 0x9E, 0x5A, 0x00, 0x03, 0x23, 0x5A, 0x00, 0x04, 0x0D, 0xDD, 0x9E, + 0xDD, 0x43, 0xEA, 0x2B, 0x04, 0x01, 0x00, 0x30, 0x92, 0x0A, 0xDD, 0x47, 0xFE, 0x47, 0x14, 0x11, + 0x00, 0x30, 0xDD, 0x9E, 0xDD, 0x43, 0xEA, 0x2B, 0xEB, 0x4B, 0x04, 0x31, 0x00, 0x31, 0x46, 0x1F, + 0xC0, 0x0F, 0xDD, 0x4A, 0xFE, 0x5E, 0xD5, 0x07, 0xDD, 0x43, 0xEA, 0x2B, 0x04, 0x01, 0x00, 0x31, + 0x92, 0x0A, 0xDD, 0x47, 0xFE, 0x47, 0x14, 0x11, 0x00, 0x31, 0xDD, 0x9E, 0xFC, 0x00, 0x80, 0xC1, + 0xEA, 0xAA, 0xDD, 0x56, 0x54, 0x13, 0x03, 0xFF, 0x40, 0x60, 0xC4, 0x08, 0x04, 0x20, 0x03, 0x98, + 0x46, 0x1F, 0x80, 0x1F, 0xDD, 0x4A, 0xFE, 0x56, 0xFE, 0x77, 0x14, 0x10, 0x03, 0x98, 0xEA, 0x8A, + 0xFC, 0x80, 0x5A, 0x00, 0x02, 0x0D, 0x5A, 0x00, 0x03, 0x15, 0xC8, 0x1D, 0xDD, 0x43, 0x96, 0x5F, + 0xEB, 0x4B, 0x04, 0x31, 0x00, 0x32, 0x46, 0x1F, 0xFF, 0x0F, 0xD5, 0x08, 0xDD, 0x43, 0x96, 0x5F, + 0xEA, 0xED, 0x04, 0x31, 0x00, 0x32, 0x46, 0x1F, 0x0F, 0xFF, 0xDD, 0x4A, 0xFE, 0x5E, 0xD5, 0x08, + 0xDD, 0x43, 0x40, 0x10, 0xF0, 0x08, 0x04, 0x01, 0x00, 0x32, 0x94, 0x04, 0x92, 0x04, 0xFE, 0x47, + 0x14, 0x11, 0x00, 0x32, 0xDD, 0x9E, 0x54, 0x20, 0x80, 0x03, 0x54, 0x10, 0x80, 0x0C, 0x90, 0x22, + 0x5A, 0x00, 0x01, 0x16, 0xC0, 0x04, 0x5A, 0x00, 0x02, 0x27, 0xDD, 0x9E, 0xDD, 0x56, 0x84, 0x7C, + 0x50, 0x50, 0x00, 0x9C, 0xB4, 0x85, 0xEB, 0x0B, 0xFE, 0xE6, 0xFE, 0x5F, 0xB6, 0x25, 0xB4, 0x65, + 0x44, 0x1C, 0xFF, 0xFF, 0xFE, 0x5E, 0xFE, 0x8F, 0xB6, 0x45, 0xDD, 0x9E, 0xEA, 0x92, 0x44, 0x0F, + 0xFF, 0xCF, 0x50, 0x51, 0x80, 0x9C, 0xB4, 0x85, 0x94, 0x4C, 0xFE, 0x26, 0xFE, 0x47, 0xB6, 0x25, + 0xB4, 0x05, 0x46, 0x1F, 0xFC, 0xFF, 0xDD, 0x4A, 0x40, 0x21, 0x50, 0x08, 0xFE, 0x0E, 0xFE, 0x17, + 0xB6, 0x05, 0xDD, 0x9E, 0xEA, 0x92, 0xEB, 0x36, 0x50, 0x51, 0x80, 0x9C, 0xB4, 0x85, 0x94, 0x4E, + 0xFE, 0x26, 0xFE, 0x47, 0xB6, 0x25, 0xB4, 0x25, 0xEB, 0x2F, 0xDD, 0x41, 0x40, 0x21, 0x58, 0x08, + 0xFE, 0x0E, 0xFE, 0x87, 0xB6, 0x45, 0xDD, 0x9E, 0x5A, 0x00, 0x01, 0x0C, 0xC0, 0x04, 0x5A, 0x00, + 0x02, 0x10, 0xDD, 0x9E, 0xDD, 0x43, 0x84, 0x1C, 0xEB, 0x3B, 0x96, 0x4F, 0xFE, 0x1E, 0xD5, 0x0F, + 0xDD, 0x43, 0x96, 0x4F, 0x94, 0x0C, 0xEB, 0x3B, 0x44, 0x1F, 0xFF, 0xCF, 0xD5, 0x07, 0xDD, 0x43, + 0x96, 0x4F, 0x94, 0x0E, 0xEB, 0x3B, 0x44, 0x1F, 0xFF, 0x3F, 0xFE, 0x5E, 0xFE, 0x47, 0x14, 0x11, + 0x00, 0x28, 0xDD, 0x9E, 0x46, 0x10, 0x00, 0x81, 0x04, 0x20, 0x80, 0x12, 0x5A, 0x08, 0x01, 0x06, + 0xEA, 0x44, 0xDD, 0x41, 0xFE, 0x16, 0xD5, 0x03, 0xEB, 0x2B, 0xFE, 0x17, 0x14, 0x00, 0x80, 0x12, + 0xDD, 0x9E, 0x46, 0x00, 0x00, 0x81, 0x04, 0x00, 0x00, 0xF5, 0x92, 0x0B, 0x96, 0x27, 0xDD, 0x9E, + 0xFC, 0x00, 0x80, 0xC0, 0x5A, 0x08, 0x0C, 0x06, 0x84, 0x01, 0x84, 0x20, 0xDD, 0x5F, 0xFC, 0x80, + 0x84, 0x00, 0x80, 0x20, 0xDD, 0x5F, 0x44, 0x24, 0x2C, 0x00, 0x54, 0x13, 0x00, 0x0C, 0xB4, 0x02, + 0x97, 0x8F, 0x90, 0x22, 0x95, 0xB3, 0xFF, 0x8F, 0x92, 0x0A, 0xDD, 0x47, 0x58, 0x63, 0x02, 0xA4, + 0xFF, 0x87, 0xB6, 0xC2, 0x84, 0x41, 0xDD, 0x59, 0xEA, 0x23, 0x80, 0x62, 0xDD, 0x40, 0xFC, 0x80, + 0xFC, 0x00, 0xEA, 0x64, 0xB4, 0x41, 0x58, 0x21, 0x00, 0x24, 0xB6, 0x41, 0x5A, 0x00, 0x02, 0x10, + 0x5A, 0x00, 0x04, 0x1A, 0x5A, 0x08, 0x01, 0x22, 0xB4, 0x41, 0x84, 0x1C, 0xFE, 0x16, 0xEA, 0x8D, + 0xB6, 0x01, 0xB4, 0x22, 0xEA, 0x4D, 0xFE, 0x0E, 0xEA, 0x6B, 0xD5, 0x0A, 0xB4, 0x41, 0x84, 0x1C, + 0xFE, 0x16, 0xEA, 0x8D, 0xB6, 0x01, 0xB4, 0x22, 0xEA, 0x4D, 0xFE, 0x0E, 0xEB, 0x3F, 0xFE, 0x0F, + 0xB6, 0x02, 0xD5, 0x0B, 0xB4, 0x41, 0x84, 0x1C, 0xFE, 0x16, 0xDD, 0x45, 0xB6, 0x01, 0xEA, 0xF5, + 0xEA, 0x4D, 0xB4, 0x41, 0xFE, 0x16, 0xB6, 0x01, 0x84, 0x41, 0x80, 0x62, 0xEA, 0x5B, 0xEA, 0x70, + 0xDD, 0x40, 0xEA, 0x64, 0xEB, 0x36, 0xB4, 0x41, 0xFE, 0x16, 0x58, 0x00, 0x00, 0x80, 0xB6, 0x01, + 0xB4, 0x01, 0x84, 0x41, 0x58, 0x00, 0x03, 0x00, 0xB6, 0x01, 0x80, 0x62, 0xDD, 0x59, 0xEA, 0x23, + 0xDD, 0x40, 0xFC, 0x80, 0xFC, 0x40, 0x44, 0x74, 0x2C, 0x14, 0x84, 0xCF, 0xB5, 0x27, 0x40, 0x94, + 0x98, 0x02, 0x10, 0x90, 0x00, 0x00, 0xB4, 0x07, 0x92, 0x08, 0xFE, 0x36, 0xAE, 0x08, 0xB4, 0x27, + 0x84, 0x01, 0x92, 0x2C, 0xFE, 0x46, 0xAE, 0x50, 0xEA, 0x43, 0x44, 0x24, 0x2C, 0x1C, 0xB4, 0x21, + 0xFF, 0x8E, 0xAF, 0x98, 0xB4, 0x22, 0x92, 0x32, 0xFE, 0x46, 0xAE, 0x60, 0xB4, 0x22, 0x92, 0x33, + 0xFE, 0x46, 0xAE, 0x68, 0xB4, 0x22, 0x92, 0x36, 0xFE, 0x0E, 0xF1, 0x08, 0xAE, 0x08, 0xFC, 0xC0, + 0xFC, 0x41, 0x81, 0x21, 0xF3, 0x81, 0x5A, 0x08, 0xFF, 0x05, 0x5A, 0x18, 0xFF, 0x45, 0xFC, 0xC1, + 0x5A, 0x08, 0xFE, 0x3F, 0x5A, 0x18, 0xFE, 0x3D, 0x44, 0x34, 0x2C, 0x14, 0x96, 0x86, 0x40, 0x01, + 0x30, 0x08, 0xB4, 0x43, 0x44, 0x1F, 0xEF, 0xFF, 0xFE, 0x8E, 0xFE, 0x87, 0xB6, 0x43, 0x84, 0x41, + 0x80, 0x62, 0xEA, 0x43, 0xEA, 0x53, 0x80, 0xE4, 0x80, 0xC5, 0xDD, 0x40, 0xF0, 0x01, 0xEA, 0x85, + 0x44, 0x04, 0x24, 0x14, 0x84, 0x21, 0x49, 0xFF, 0xFA, 0x5B, 0x44, 0x24, 0x2C, 0x1C, 0x97, 0xC6, + 0x40, 0x43, 0xC8, 0x08, 0xB4, 0xE2, 0xEB, 0x39, 0xFF, 0xC6, 0xFF, 0xE7, 0xB6, 0xE2, 0x97, 0x86, + 0xB4, 0x02, 0x40, 0x53, 0x4C, 0x08, 0x46, 0x6F, 0xFF, 0x7F, 0xEA, 0xB5, 0xFF, 0x86, 0xFF, 0xAF, + 0xB6, 0xC2, 0x00, 0x0F, 0x80, 0x28, 0xB4, 0x62, 0x96, 0x06, 0xEA, 0xF8, 0x46, 0x0F, 0xFB, 0xFF, + 0xDD, 0x41, 0xFE, 0x1E, 0xFE, 0x0F, 0xB6, 0x02, 0xEA, 0xAF, 0xEA, 0xB8, 0xD5, 0x08, 0xEA, 0x85, + 0x5A, 0x90, 0xFF, 0x04, 0x80, 0x09, 0xEA, 0xFC, 0xEA, 0x53, 0xEA, 0x43, 0x84, 0x41, 0x80, 0x62, + 0xDD, 0x40, 0xFC, 0xC1, 0xFC, 0x00, 0xB4, 0x60, 0x44, 0x04, 0x2C, 0x00, 0xB6, 0x60, 0xB4, 0x21, + 0x44, 0x04, 0x2C, 0x08, 0xB6, 0x20, 0xA6, 0x10, 0xEA, 0x8D, 0x96, 0x17, 0xB4, 0x62, 0xDD, 0x49, + 0xEA, 0x4D, 0xFE, 0x1E, 0xFE, 0x0F, 0xB6, 0x02, 0x84, 0x41, 0x80, 0x62, 0xDD, 0x59, 0xEA, 0x23, + 0xDD, 0x40, 0x84, 0x41, 0x80, 0x62, 0x44, 0x04, 0x28, 0x08, 0x44, 0x14, 0x24, 0x08, 0xDD, 0x40, + 0x84, 0x41, 0xEA, 0x5B, 0xEA, 0x70, 0x80, 0x62, 0xDD, 0x40, 0xFC, 0x80, 0xFC, 0x00, 0x80, 0xC0, + 0xEA, 0xE9, 0x44, 0x04, 0x2C, 0x00, 0xB4, 0x00, 0xEA, 0xB0, 0xB6, 0x06, 0xEB, 0x10, 0xFC, 0x80, + 0xFC, 0x00, 0xEA, 0x64, 0x84, 0x41, 0xB6, 0x01, 0x80, 0x62, 0xDD, 0x59, 0xEA, 0x23, 0xDD, 0x40, + 0xFC, 0x80, 0xFC, 0x40, 0x80, 0xE1, 0x80, 0xC2, 0x81, 0x20, 0xEA, 0xE9, 0xDD, 0x59, 0xB4, 0x00, + 0xEA, 0xB0, 0xB6, 0x09, 0x44, 0x04, 0x28, 0x08, 0xB4, 0x00, 0xEA, 0xB0, 0xB6, 0x07, 0xEA, 0x5B, + 0xB4, 0x00, 0xEA, 0xB0, 0x84, 0x00, 0xAE, 0x30, 0xEB, 0x10, 0xFC, 0xC0, 0x44, 0x12, 0x07, 0x00, + 0x02, 0x00, 0x80, 0x4C, 0x02, 0x20, 0x80, 0x4E, 0xDD, 0x4E, 0x88, 0x02, 0xDD, 0x43, 0x02, 0x30, + 0x80, 0x22, 0xEA, 0x73, 0x00, 0x00, 0x80, 0x59, 0xDD, 0x4E, 0x88, 0x03, 0xEA, 0xAD, 0xDD, 0x9E, + 0xFC, 0x40, 0x46, 0x70, 0x00, 0x82, 0x02, 0x91, 0x00, 0x00, 0x2E, 0x27, 0xEF, 0xEE, 0xB4, 0xC7, + 0x92, 0x41, 0x42, 0x10, 0x08, 0x73, 0x88, 0x29, 0x92, 0xCB, 0xEA, 0x82, 0x40, 0x63, 0x2C, 0x08, + 0xFF, 0x8F, 0xB6, 0xC7, 0xA0, 0x39, 0xF1, 0x08, 0x96, 0x2F, 0xAE, 0x20, 0xA0, 0x39, 0x54, 0x00, + 0x0F, 0xC0, 0x92, 0x06, 0xAE, 0x18, 0xA0, 0x39, 0x92, 0x0C, 0x96, 0x2F, 0xAE, 0x08, 0xA0, 0x39, + 0x92, 0x12, 0x96, 0x2F, 0xAE, 0x28, 0xFC, 0xC0, 0xFC, 0x00, 0xEA, 0x2A, 0x84, 0x41, 0x51, 0xC3, + 0x0E, 0x44, 0xB8, 0x08, 0x80, 0x62, 0x92, 0x06, 0x94, 0x06, 0x58, 0x00, 0x00, 0x0A, 0xB8, 0x88, + 0xB8, 0x07, 0x92, 0x06, 0x94, 0x06, 0xDD, 0x45, 0xB8, 0x87, 0xB9, 0x06, 0x44, 0x0F, 0x03, 0xFF, + 0xFE, 0x0E, 0x58, 0x00, 0x08, 0x00, 0xB8, 0x86, 0xB9, 0x06, 0xEB, 0x31, 0xDD, 0x41, 0xFE, 0x0E, + 0x46, 0x10, 0x02, 0x90, 0xFE, 0x0F, 0xB8, 0x86, 0xB9, 0x08, 0x46, 0x0E, 0x03, 0xFF, 0xDD, 0x41, + 0xFE, 0x0E, 0x46, 0x10, 0xA0, 0x00, 0xFE, 0x0F, 0xB8, 0x88, 0xB9, 0x06, 0x46, 0x08, 0x1F, 0xFF, + 0xDD, 0x41, 0xFE, 0x0E, 0x46, 0x13, 0x40, 0x00, 0xFE, 0x0F, 0xB8, 0x86, 0xB4, 0x3C, 0x44, 0x0F, + 0x83, 0xFF, 0xFE, 0x0E, 0x58, 0x00, 0x38, 0x00, 0xB6, 0x1C, 0xB9, 0x04, 0x44, 0x0F, 0xC0, 0xFF, + 0xFE, 0x0E, 0x58, 0x00, 0x20, 0x00, 0xB8, 0x84, 0x50, 0x13, 0x06, 0x54, 0x50, 0x03, 0x0A, 0x54, + 0xDD, 0x40, 0x84, 0x41, 0x50, 0x03, 0x0A, 0x5C, 0x50, 0x13, 0x06, 0x5C, 0x80, 0x62, 0xDD, 0x40, + 0x84, 0x41, 0x50, 0x03, 0x0A, 0x60, 0x50, 0x13, 0x06, 0x60, 0x80, 0x62, 0xDD, 0x40, 0x84, 0x41, + 0x50, 0x03, 0x0A, 0x64, 0x50, 0x13, 0x06, 0x64, 0x80, 0x62, 0xDD, 0x40, 0xFC, 0x80, 0x44, 0x36, + 0x20, 0x04, 0xEB, 0x4E, 0xB4, 0x43, 0xDD, 0x4A, 0xFE, 0x56, 0x46, 0x20, 0x0A, 0x30, 0xFE, 0x57, + 0xB6, 0x23, 0x44, 0x14, 0x80, 0x80, 0x84, 0x68, 0xB4, 0x41, 0x58, 0x21, 0x08, 0x00, 0xB6, 0x41, + 0x44, 0x24, 0x80, 0x01, 0xAE, 0xD0, 0xB4, 0x81, 0x44, 0x3F, 0xEF, 0xFF, 0xFE, 0xE6, 0xB6, 0x61, + 0xFA, 0x60, 0xAE, 0xD0, 0xB4, 0x61, 0x58, 0x31, 0x82, 0x00, 0xB6, 0x61, 0x84, 0x62, 0xAE, 0xD0, + 0xB4, 0x61, 0xEA, 0xEE, 0xB6, 0x61, 0x84, 0x61, 0xAE, 0xD0, 0xB4, 0x81, 0x44, 0x3F, 0xFB, 0xFF, + 0xFE, 0xE6, 0xB6, 0x61, 0x84, 0x24, 0xAE, 0x50, 0x44, 0x16, 0x20, 0x00, 0x5A, 0x00, 0x02, 0x12, + 0x5A, 0x00, 0x03, 0x17, 0x5A, 0x00, 0x01, 0x06, 0xB4, 0x41, 0x84, 0x1E, 0xFE, 0x16, 0xD5, 0x03, + 0xB4, 0x01, 0xDD, 0x45, 0xB6, 0x01, 0xB4, 0x41, 0x84, 0x1D, 0xFE, 0x16, 0xB6, 0x01, 0xD5, 0x09, + 0xB4, 0x41, 0x84, 0x1E, 0xFE, 0x16, 0xB6, 0x01, 0xB4, 0x01, 0xEA, 0x87, 0xD5, 0xF8, 0xAE, 0x08, + 0x44, 0x16, 0x20, 0x00, 0x46, 0x08, 0x00, 0x00, 0xB4, 0x41, 0xFE, 0x17, 0xB6, 0x01, 0x44, 0x16, + 0x20, 0x0C, 0xDD, 0x52, 0xB4, 0x41, 0xFE, 0x16, 0xB6, 0x01, 0xB4, 0x41, 0xEB, 0x31, 0xDD, 0x41, + 0xFE, 0x16, 0x46, 0x20, 0x04, 0x00, 0xFE, 0x17, 0xB6, 0x01, 0xDD, 0x9E, 0xFC, 0x00, 0x44, 0x14, + 0x80, 0x00, 0xB4, 0x01, 0x92, 0x0B, 0x96, 0x06, 0xC0, 0x04, 0xEA, 0x50, 0x84, 0x48, 0xAE, 0x80, + 0xB4, 0x01, 0x92, 0x0C, 0x96, 0x06, 0xC0, 0x04, 0xEA, 0x50, 0xFA, 0x20, 0xAE, 0x40, 0xEA, 0xE6, + 0xB4, 0x00, 0x92, 0x09, 0x96, 0x06, 0xC0, 0x0A, 0xEA, 0x50, 0x84, 0x22, 0xAE, 0x40, 0x84, 0x01, + 0xEA, 0x8F, 0x84, 0x02, 0xEA, 0x8F, 0x49, 0x00, 0x0B, 0xF7, 0x44, 0x14, 0x80, 0x00, 0xB4, 0x01, + 0x92, 0x08, 0x96, 0x06, 0xC0, 0x04, 0xEA, 0x50, 0x84, 0x41, 0xAE, 0x80, 0xB4, 0x01, 0x92, 0x0A, + 0x96, 0x06, 0xC0, 0x04, 0xEA, 0x50, 0x84, 0x24, 0xAE, 0x40, 0xFC, 0x80, 0x44, 0x26, 0x20, 0x04, + 0x96, 0x06, 0xEA, 0xD7, 0xB4, 0x62, 0xEA, 0x44, 0xDD, 0x41, 0xFE, 0x1E, 0xFE, 0x0F, 0xB6, 0x02, + 0xDD, 0x9E, 0xC8, 0x04, 0x44, 0x07, 0x20, 0x14, 0xD5, 0x03, 0x44, 0x07, 0x20, 0x18, 0xB4, 0x00, + 0xEA, 0x48, 0x92, 0x0C, 0xDD, 0x9E, 0xC8, 0x04, 0x44, 0x07, 0x20, 0x0C, 0xD5, 0x03, 0x44, 0x07, + 0x20, 0x10, 0xB4, 0x00, 0xEA, 0x48, 0x92, 0x0C, 0xDD, 0x9E, 0x44, 0x27, 0x20, 0x14, 0xEA, 0x48, + 0xEA, 0xCF, 0xB4, 0x02, 0x92, 0x14, 0xEA, 0x3A, 0xFE, 0x0F, 0xB6, 0x02, 0xDD, 0x9E, 0x44, 0x27, + 0x20, 0x18, 0xEA, 0x48, 0xEA, 0xCF, 0xB4, 0x02, 0x92, 0x14, 0xEA, 0x3A, 0xFE, 0x0F, 0xB6, 0x02, + 0xDD, 0x9E, 0x44, 0x27, 0x20, 0x1C, 0xEA, 0x42, 0xB4, 0x22, 0x92, 0x2C, 0xEA, 0x98, 0xFE, 0x47, + 0xB6, 0x22, 0xDD, 0x9E, 0x44, 0x27, 0x20, 0x20, 0xEA, 0x42, 0xB4, 0x22, 0x92, 0x2C, 0xEA, 0x98, + 0xFE, 0x47, 0xB6, 0x22, 0xDD, 0x9E, 0x44, 0x27, 0x20, 0x34, 0xEA, 0x42, 0xB4, 0x22, 0x92, 0x2C, + 0xEA, 0x98, 0xFE, 0x47, 0xB6, 0x22, 0xDD, 0x9E, 0x44, 0x27, 0x20, 0x0C, 0xEA, 0x48, 0xEA, 0xCF, + 0xB4, 0x02, 0x92, 0x14, 0xEA, 0x3A, 0xFE, 0x0F, 0xB6, 0x02, 0xDD, 0x9E, 0x44, 0x27, 0x20, 0x10, + 0xEA, 0x48, 0xEA, 0xCF, 0xB4, 0x02, 0x92, 0x14, 0xEA, 0x3A, 0xFE, 0x0F, 0xB6, 0x02, 0xDD, 0x9E, + 0x44, 0x27, 0x20, 0x1C, 0xEA, 0x42, 0xDD, 0x49, 0xB4, 0x62, 0xEA, 0xE7, 0xDD, 0x41, 0xFE, 0x1E, + 0xFE, 0x0F, 0xB6, 0x02, 0xDD, 0x9E, 0x44, 0x27, 0x20, 0x20, 0xEA, 0x42, 0xDD, 0x49, 0xB4, 0x62, + 0xEA, 0xE7, 0xDD, 0x41, 0xFE, 0x1E, 0xFE, 0x0F, 0xB6, 0x02, 0xDD, 0x9E, 0x44, 0x27, 0x20, 0x54, + 0x84, 0x30, 0xB4, 0x62, 0x96, 0x1F, 0xFE, 0x5E, 0xFE, 0x0F, 0xB6, 0x02, 0xDD, 0x9E, 0x44, 0x27, + 0x20, 0x54, 0x96, 0x1F, 0xB4, 0x62, 0xDD, 0x4F, 0x44, 0x0F, 0xF0, 0xFF, 0xFE, 0x1E, 0xFE, 0x0F, + 0xB6, 0x02, 0xDD, 0x9E, 0x44, 0x27, 0x20, 0x58, 0x96, 0x1F, 0xDD, 0x49, 0xB4, 0x62, 0xEA, 0xC6, + 0xDD, 0x41, 0xFE, 0x1E, 0xFE, 0x0F, 0xB6, 0x02, 0xDD, 0x9E, 0x44, 0x14, 0x00, 0x04, 0x44, 0x24, + 0x00, 0x10, 0xB4, 0x01, 0xDD, 0x45, 0xB6, 0x01, 0xB4, 0x02, 0x44, 0x10, 0x98, 0x78, 0x92, 0x10, + 0xDD, 0x4E, 0xFE, 0x0F, 0x44, 0x14, 0x70, 0x00, 0xB6, 0x02, 0xB4, 0x41, 0xDD, 0x55, 0xFE, 0x16, + 0xB6, 0x01, 0x44, 0x14, 0x00, 0x1C, 0xB4, 0x01, 0xDD, 0x45, 0xB6, 0x01, 0xDD, 0x9E, 0x44, 0x04, + 0x00, 0x9C, 0xB4, 0x00, 0x96, 0x00, 0xDD, 0x9E, 0x44, 0x04, 0x00, 0x9C, 0xB4, 0x00, 0x92, 0x08, + 0x96, 0x00, 0xDD, 0x9E, 0x44, 0x34, 0x80, 0x90, 0x96, 0x06, 0xB4, 0x83, 0x84, 0x3D, 0x94, 0x81, + 0xFE, 0x66, 0xFE, 0x57, 0xDD, 0x43, 0xB6, 0x23, 0x04, 0x31, 0x00, 0x15, 0x84, 0x3E, 0xFE, 0x5E, + 0xFE, 0x0F, 0x14, 0x01, 0x00, 0x15, 0x84, 0x00, 0x3E, 0x07, 0xF9, 0x00, 0xEA, 0x5A, 0x84, 0x22, + 0xAE, 0x40, 0xDD, 0x9E, 0x44, 0x14, 0x00, 0x18, 0xB4, 0x41, 0xC8, 0x04, 0xEB, 0x39, 0xFE, 0x16, + 0xD5, 0x04, 0x44, 0x04, 0x00, 0x00, 0xFE, 0x17, 0xB6, 0x01, 0x44, 0x14, 0x50, 0x10, 0xB4, 0x01, + 0x92, 0x08, 0xDD, 0x4C, 0xB6, 0x01, 0x44, 0x14, 0x70, 0x00, 0xDD, 0x55, 0xB4, 0x41, 0xFE, 0x16, + 0xB6, 0x01, 0xDD, 0x9E, 0xDD, 0x9E, 0x44, 0x04, 0x80, 0x10, 0xFA, 0x20, 0xAE, 0x40, 0xDD, 0x9E, + 0x44, 0x04, 0x80, 0x08, 0x84, 0x24, 0xAE, 0x40, 0xDD, 0x9E, 0x44, 0x04, 0x80, 0x09, 0x84, 0x24, + 0xAE, 0x40, 0xDD, 0x9E, 0xFC, 0x00, 0x44, 0x14, 0x55, 0x0C, 0xB4, 0x01, 0x92, 0x08, 0xDD, 0x4C, + 0xB6, 0x01, 0x44, 0x04, 0x58, 0x8C, 0xB4, 0x40, 0x92, 0x48, 0xEB, 0x32, 0xB6, 0x40, 0x84, 0x41, + 0x80, 0x62, 0xDD, 0x40, 0xFC, 0x80, 0x44, 0x34, 0x80, 0x88, 0xEA, 0xD7, 0x40, 0x20, 0x64, 0x08, + 0xB4, 0x83, 0xFE, 0x8F, 0x46, 0x1F, 0xCF, 0xFF, 0x46, 0x00, 0x30, 0x00, 0xDD, 0x4A, 0xFE, 0x86, + 0xFE, 0x66, 0x40, 0x01, 0x04, 0x04, 0xB6, 0x03, 0xDD, 0x9E, 0xDD, 0x9E, 0x44, 0x14, 0x50, 0x0C, + 0xB4, 0x01, 0xDD, 0x45, 0xB6, 0x01, 0xDD, 0x9E, 0x44, 0x24, 0x00, 0x90, 0xEA, 0x42, 0xB4, 0x22, + 0x92, 0x2C, 0xEA, 0x98, 0xFE, 0x47, 0xB6, 0x22, 0xDD, 0x9E, 0xFC, 0x00, 0x44, 0x24, 0x2C, 0x04, + 0x46, 0x0F, 0xF3, 0x3F, 0xB4, 0x22, 0xDD, 0x41, 0xFE, 0x0E, 0x46, 0x10, 0x08, 0x80, 0xFE, 0x0F, + 0xB6, 0x02, 0x84, 0x41, 0x80, 0x62, 0x44, 0x04, 0x28, 0x04, 0x44, 0x14, 0x24, 0x04, 0xDD, 0x40, + 0x44, 0x14, 0x2C, 0x0C, 0x46, 0x0F, 0xFE, 0xFF, 0xB4, 0x41, 0xDD, 0x41, 0xFE, 0x16, 0x84, 0x41, + 0xB6, 0x01, 0x80, 0x62, 0x44, 0x04, 0x28, 0x0C, 0x44, 0x14, 0x24, 0x0C, 0xDD, 0x40, 0x44, 0x24, + 0x2C, 0x00, 0x44, 0x04, 0x00, 0x9C, 0xB4, 0x20, 0xB4, 0x22, 0x44, 0x0F, 0xE3, 0xFF, 0xFE, 0x0E, + 0x58, 0x00, 0x18, 0x00, 0xB6, 0x02, 0x84, 0x41, 0xDD, 0x59, 0xEA, 0x23, 0x80, 0x62, 0xDD, 0x40, + 0xFC, 0x80, 0xDD, 0x9E, 0x46, 0x20, 0x00, 0x81, 0x40, 0x40, 0xA8, 0x08, 0x50, 0x51, 0x01, 0x20, + 0xA8, 0x2B, 0xA8, 0x2C, 0xA0, 0xED, 0x92, 0x8A, 0x92, 0x76, 0x40, 0x31, 0xD8, 0x08, 0xFE, 0xE7, + 0xA8, 0xED, 0xB4, 0x65, 0x92, 0x76, 0x40, 0x31, 0xD8, 0x08, 0xFE, 0xE7, 0xB6, 0x65, 0xEA, 0xD1, + 0x14, 0x01, 0x80, 0x47, 0x14, 0x01, 0x80, 0x48, 0x04, 0x51, 0x80, 0x49, 0x92, 0xB6, 0xEA, 0xB7, + 0xFF, 0x67, 0x14, 0x51, 0x80, 0x49, 0x04, 0x51, 0x80, 0x57, 0x92, 0xB6, 0xEA, 0xB7, 0xFF, 0x2F, + 0x14, 0x41, 0x80, 0x57, 0x2E, 0x47, 0xF9, 0x08, 0xCC, 0x18, 0xFE, 0x03, 0x50, 0x51, 0x00, 0xF0, + 0xB6, 0x05, 0xA8, 0x29, 0xA0, 0x2A, 0xFE, 0x4B, 0xEA, 0x37, 0x92, 0x16, 0x92, 0x2A, 0xEA, 0x33, + 0xFE, 0x0F, 0xA8, 0x2A, 0xA0, 0x2B, 0x92, 0x16, 0xEA, 0x33, 0xFE, 0x47, 0xA8, 0x6B, 0x44, 0x04, + 0x44, 0x44, 0x14, 0x41, 0x80, 0xA3, 0xD5, 0x6C, 0x5A, 0x48, 0x01, 0x5B, 0x2E, 0x27, 0xF9, 0x07, + 0xCA, 0x07, 0x54, 0x40, 0x0F, 0xFF, 0x46, 0x30, 0x0F, 0xC0, 0xFF, 0x1F, 0xD5, 0x22, 0x5A, 0x28, + 0x01, 0x11, 0x40, 0x40, 0x60, 0x09, 0x44, 0x23, 0xF0, 0x00, 0x40, 0x42, 0x60, 0x08, 0xFF, 0x17, + 0x54, 0x20, 0x80, 0x0F, 0x46, 0x13, 0xFF, 0xC0, 0xFE, 0x0E, 0x44, 0x10, 0x03, 0xF0, 0xD5, 0x11, + 0x5A, 0x28, 0x02, 0x0E, 0x46, 0x30, 0x03, 0xFF, 0x50, 0x31, 0x8C, 0x00, 0xFE, 0xCE, 0x80, 0x80, + 0x80, 0x41, 0x46, 0x0C, 0x00, 0x00, 0x58, 0x11, 0x80, 0x0F, 0xD5, 0x03, 0x80, 0x80, 0x80, 0x41, + 0xEA, 0x92, 0x40, 0x21, 0x28, 0x08, 0x14, 0x41, 0x80, 0x3C, 0x14, 0x01, 0x80, 0x3D, 0x04, 0x51, + 0x80, 0x3E, 0x92, 0x4A, 0x92, 0xB6, 0xEA, 0xB7, 0xFF, 0x57, 0x14, 0x51, 0x80, 0x3E, 0x04, 0x51, + 0x80, 0x3F, 0xEA, 0x37, 0x92, 0xB6, 0x92, 0x2A, 0xEA, 0xB7, 0xFF, 0x4F, 0x14, 0x51, 0x80, 0x3F, + 0x14, 0x01, 0x80, 0x40, 0x14, 0x41, 0x80, 0x41, 0x04, 0x01, 0x80, 0x42, 0x92, 0x16, 0xEA, 0x33, + 0xFE, 0x47, 0x14, 0x11, 0x80, 0x42, 0x04, 0x01, 0x80, 0x43, 0x92, 0x16, 0xEA, 0x33, 0xFE, 0x87, + 0x44, 0x00, 0x08, 0x40, 0x14, 0x21, 0x80, 0x43, 0x14, 0x01, 0x80, 0x44, 0xDD, 0x9E, 0x5A, 0x48, + 0x02, 0x12, 0x84, 0x1F, 0x14, 0x01, 0x80, 0x47, 0x14, 0x01, 0x80, 0x48, 0xEB, 0x0E, 0x92, 0x0A, + 0xFE, 0x47, 0xEA, 0xDF, 0x04, 0x11, 0x80, 0x57, 0xFE, 0x0F, 0xEB, 0x12, 0x84, 0x00, 0x14, 0x01, + 0x00, 0x44, 0xDD, 0x9E, 0x44, 0x24, 0x2C, 0x14, 0xB4, 0x42, 0xB6, 0x40, 0x44, 0x04, 0x2C, 0x1C, + 0xB4, 0x00, 0xB6, 0x01, 0xDD, 0x9E, 0xFC, 0x41, 0x80, 0xE1, 0xEA, 0x2D, 0x81, 0x20, 0x04, 0x40, + 0x83, 0x97, 0x44, 0x0F, 0xFF, 0x7F, 0xFF, 0x06, 0x80, 0xC2, 0x84, 0x41, 0x14, 0x40, 0x83, 0x97, + 0x50, 0x00, 0x8A, 0x5C, 0x80, 0x62, 0x50, 0x10, 0x86, 0x5C, 0xDD, 0x40, 0x84, 0x01, 0xEA, 0x40, + 0x46, 0x00, 0x00, 0x83, 0x46, 0x3F, 0x3F, 0xFF, 0x04, 0x10, 0x00, 0xEE, 0x50, 0x31, 0x8F, 0xFF, + 0xFE, 0xCE, 0x14, 0x30, 0x00, 0xEE, 0x5A, 0x98, 0xFF, 0x04, 0x5A, 0x70, 0xFF, 0x0B, 0x84, 0x41, + 0xB6, 0x5F, 0x80, 0x09, 0x80, 0x27, 0x84, 0x65, 0x84, 0x80, 0x80, 0xA2, 0xEB, 0x24, 0xD5, 0x0A, + 0x84, 0x01, 0xEA, 0x85, 0x84, 0x06, 0xEA, 0xFC, 0x84, 0x41, 0xEA, 0x53, 0xEA, 0x43, 0x80, 0x62, + 0xDD, 0x40, 0x84, 0x01, 0x84, 0x20, 0x5A, 0x60, 0xFF, 0x03, 0x80, 0x26, 0xEA, 0x38, 0xFC, 0xC1, + 0x5A, 0x18, 0x01, 0x0D, 0xEA, 0x92, 0x96, 0x06, 0x04, 0x41, 0x80, 0x17, 0x40, 0x20, 0x20, 0x08, + 0xDD, 0x52, 0xFE, 0x26, 0xFE, 0x17, 0x14, 0x01, 0x80, 0x17, 0xDD, 0x43, 0x84, 0x1E, 0xA0, 0xD6, + 0x96, 0x46, 0xFE, 0x1E, 0xFE, 0x47, 0xA8, 0x56, 0xDD, 0x9E, 0xB4, 0x20, 0x46, 0x25, 0x55, 0x55, + 0x50, 0x21, 0x05, 0x55, 0x40, 0x40, 0x88, 0x02, 0xEA, 0x62, 0xA0, 0xC1, 0x14, 0x40, 0x80, 0x47, + 0xA1, 0x02, 0xA0, 0x03, 0xFE, 0xA6, 0x14, 0x20, 0x80, 0x48, 0x04, 0x20, 0x80, 0x49, 0x54, 0x31, + 0x95, 0x55, 0x92, 0x56, 0x40, 0x21, 0x58, 0x08, 0xFE, 0x9F, 0x14, 0x20, 0x80, 0x49, 0x54, 0x20, + 0x15, 0x55, 0x04, 0x00, 0x80, 0x57, 0x92, 0x16, 0xEA, 0x33, 0xFE, 0x17, 0x14, 0x00, 0x80, 0x57, + 0xDD, 0x9E, 0xB4, 0x40, 0xEA, 0xD1, 0xA0, 0x41, 0x14, 0x21, 0x80, 0x47, 0xA0, 0x82, 0xEA, 0x37, + 0xA0, 0x03, 0x14, 0x21, 0x80, 0x48, 0xEB, 0x25, 0xEB, 0x0E, 0xDD, 0x47, 0x92, 0x36, 0xEA, 0xFE, + 0xFE, 0x57, 0xEA, 0xDF, 0xEA, 0xFF, 0x04, 0x01, 0x80, 0x57, 0x92, 0x16, 0xEA, 0x33, 0xFE, 0x0F, + 0xEB, 0x12, 0xDD, 0x9E, 0xFC, 0x00, 0x44, 0x24, 0x2C, 0x14, 0xB6, 0x02, 0x44, 0x04, 0x2C, 0x1C, + 0x84, 0x41, 0xB6, 0x20, 0x80, 0x62, 0xEA, 0x53, 0xEA, 0x43, 0xDD, 0x40, 0x84, 0x41, 0xEA, 0xB8, + 0xEA, 0xAF, 0x80, 0x62, 0xDD, 0x40, 0xFC, 0x80, 0x46, 0x10, 0x00, 0x81, 0x14, 0x00, 0x80, 0x34, + 0x14, 0x00, 0x80, 0x36, 0xDD, 0x9E, 0xC0, 0x3A, 0x5A, 0x00, 0x01, 0x39, 0x5A, 0x08, 0x02, 0x35, + 0x44, 0x04, 0x58, 0x9C, 0x46, 0x10, 0x92, 0x00, 0xB6, 0x20, 0x44, 0x24, 0x58, 0xA0, 0x46, 0x03, + 0x6D, 0xB6, 0x50, 0x00, 0x0D, 0xB6, 0x44, 0x34, 0x58, 0xA4, 0xB6, 0x02, 0x44, 0x20, 0x0D, 0xB6, + 0xB6, 0x43, 0x44, 0x34, 0x55, 0x1C, 0xB6, 0x23, 0x44, 0x34, 0x55, 0x20, 0xB6, 0x03, 0x44, 0x04, + 0x55, 0x24, 0x44, 0x34, 0x58, 0x98, 0xB6, 0x40, 0x44, 0x04, 0x58, 0x90, 0x44, 0x24, 0x58, 0x94, + 0xB6, 0x20, 0x46, 0x00, 0x92, 0x76, 0x50, 0x00, 0x0C, 0x4E, 0xB6, 0x02, 0x44, 0x20, 0x03, 0xB1, + 0xB6, 0x43, 0x44, 0x34, 0x55, 0x10, 0xB6, 0x23, 0x44, 0x14, 0x55, 0x14, 0xB6, 0x01, 0x44, 0x04, + 0x55, 0x18, 0xB6, 0x40, 0xDD, 0x9E, 0x5A, 0x08, 0x03, 0x1C, 0x44, 0x04, 0x58, 0x9C, 0x46, 0x22, + 0x48, 0x00, 0xB6, 0x40, 0x44, 0x14, 0x58, 0xA0, 0x46, 0x02, 0x49, 0x24, 0x50, 0x00, 0x09, 0x24, + 0x44, 0x34, 0x58, 0xA4, 0xB6, 0x01, 0x44, 0x10, 0x09, 0x24, 0xB6, 0x23, 0x44, 0x34, 0x55, 0x1C, + 0xB6, 0x43, 0x44, 0x24, 0x55, 0x20, 0xB6, 0x02, 0x44, 0x04, 0x55, 0x24, 0xB6, 0x20, 0xDD, 0x9E, + 0xFC, 0x40, 0x44, 0x94, 0x58, 0x80, 0x44, 0x74, 0x55, 0x00, 0x84, 0x00, 0x84, 0x41, 0xB6, 0x09, + 0x80, 0x27, 0xB6, 0x07, 0x80, 0x62, 0x80, 0x09, 0xDD, 0x40, 0x44, 0x14, 0x55, 0x04, 0x44, 0x04, + 0x58, 0x84, 0x44, 0x20, 0x14, 0x00, 0xB6, 0x41, 0xB6, 0x40, 0x84, 0x41, 0x80, 0x62, 0xDD, 0x40, + 0xDD, 0x57, 0xEA, 0x2F, 0xB4, 0x07, 0x84, 0x41, 0xEB, 0x0D, 0xB6, 0x07, 0xB4, 0x09, 0xEA, 0x2A, + 0xEB, 0x0D, 0x80, 0x27, 0x80, 0x62, 0xB6, 0x09, 0x80, 0x09, 0xDD, 0x40, 0x44, 0x00, 0x00, 0xC8, + 0xDD, 0x51, 0xEA, 0x9F, 0xB4, 0x3C, 0x46, 0x01, 0x00, 0x00, 0xFE, 0x0F, 0x84, 0x41, 0xB6, 0x1C, + 0xEB, 0x46, 0x50, 0x03, 0x0A, 0x94, 0x80, 0x62, 0xDD, 0x40, 0xB9, 0x08, 0x46, 0x00, 0x11, 0x00, + 0x84, 0x41, 0xFE, 0x0F, 0x80, 0x62, 0xB8, 0x88, 0x50, 0x13, 0x06, 0xB4, 0x50, 0x03, 0x0A, 0xB4, + 0xDD, 0x40, 0xB9, 0x08, 0x46, 0x0F, 0xEE, 0xFF, 0xDD, 0x41, 0xFE, 0x0E, 0xB8, 0x88, 0x84, 0x01, + 0xEA, 0x3C, 0xB4, 0x27, 0x44, 0x0F, 0xEF, 0xFF, 0xFE, 0x46, 0xB6, 0x27, 0xB4, 0x29, 0x84, 0x41, + 0xFE, 0x0E, 0xB6, 0x09, 0x80, 0x27, 0x80, 0x09, 0x80, 0x62, 0xDD, 0x40, 0xFC, 0xC0, 0xFC, 0x20, + 0xEA, 0x2A, 0x46, 0x00, 0x44, 0x00, 0x50, 0x73, 0x0E, 0xB4, 0xB4, 0x27, 0x84, 0x41, 0xFE, 0x0F, + 0xB6, 0x07, 0x50, 0x13, 0x06, 0xB4, 0x50, 0x03, 0x0A, 0xB4, 0x80, 0x62, 0xDD, 0x40, 0xB4, 0x27, + 0x46, 0x0F, 0xBB, 0xFF, 0xDD, 0x41, 0xFE, 0x0E, 0xB6, 0x07, 0x44, 0x64, 0x55, 0x00, 0x44, 0x74, + 0x58, 0x80, 0xB4, 0x06, 0x84, 0x41, 0xEA, 0xFB, 0xB6, 0x06, 0xB4, 0x07, 0x80, 0x26, 0xEA, 0xFB, + 0xB6, 0x07, 0x80, 0x62, 0x80, 0x07, 0xDD, 0x40, 0x44, 0x14, 0x55, 0x04, 0x44, 0x04, 0x58, 0x84, + 0x84, 0x40, 0xB6, 0x41, 0xB6, 0x40, 0x84, 0x41, 0x80, 0x62, 0xDD, 0x40, 0xB4, 0x26, 0xEB, 0x2E, + 0xFE, 0x46, 0xB6, 0x26, 0xB4, 0x27, 0x84, 0x41, 0xFE, 0x0E, 0xB6, 0x07, 0x80, 0x26, 0x80, 0x07, + 0x80, 0x62, 0xDD, 0x40, 0xFC, 0xA0, 0x44, 0x14, 0x00, 0x9C, 0xB4, 0x21, 0x92, 0x28, 0x96, 0x48, + 0x5A, 0x18, 0x1C, 0x0D, 0x44, 0x24, 0x80, 0x88, 0x96, 0x06, 0xB4, 0x62, 0x40, 0x10, 0x34, 0x08, + 0x44, 0x0F, 0xDF, 0xFF, 0xFE, 0x1E, 0xFE, 0x0F, 0xB6, 0x02, 0xDD, 0x9E, 0x44, 0x34, 0x30, 0x40, + 0xEB, 0x4E, 0xB4, 0x03, 0xDD, 0x4A, 0xFE, 0x0E, 0x44, 0x22, 0x00, 0x00, 0xFE, 0x17, 0x44, 0x24, + 0x30, 0x44, 0xB6, 0x03, 0xB4, 0x02, 0x92, 0x08, 0xDD, 0x4C, 0x58, 0x00, 0x00, 0x03, 0xB6, 0x02, + 0xB4, 0x02, 0xFE, 0x46, 0x44, 0x03, 0x00, 0x00, 0xFE, 0x47, 0x44, 0x04, 0x30, 0x38, 0xB6, 0x22, + 0x44, 0x10, 0x00, 0x54, 0xB6, 0x20, 0xDD, 0x9E, 0x46, 0x20, 0x00, 0x80, 0x96, 0x0F, 0x04, 0x31, + 0x00, 0xA4, 0x94, 0x45, 0x44, 0x0F, 0xFF, 0x9F, 0xFE, 0x1E, 0xFE, 0x0F, 0x14, 0x01, 0x00, 0xA4, + 0xDD, 0x9E, 0x44, 0x14, 0x00, 0xD4, 0x5A, 0x08, 0x01, 0x05, 0xB4, 0x01, 0xDD, 0x45, 0xD5, 0x04, + 0xB4, 0x41, 0x84, 0x1E, 0xFE, 0x16, 0xB6, 0x01, 0xDD, 0x9E, 0x44, 0x14, 0x00, 0xD4, 0x5A, 0x08, + 0x01, 0x05, 0xB4, 0x01, 0xEA, 0x87, 0xD5, 0x04, 0xB4, 0x41, 0x84, 0x1D, 0xFE, 0x16, 0xB6, 0x01, + 0xDD, 0x9E, 0x44, 0x14, 0x00, 0xD8, 0x5A, 0x08, 0x01, 0x05, 0xB4, 0x01, 0xDD, 0x45, 0xD5, 0x04, + 0xB4, 0x41, 0x84, 0x1E, 0xFE, 0x16, 0xB6, 0x01, 0xDD, 0x9E, 0x44, 0x24, 0x80, 0x88, 0x84, 0x3E, + 0xB4, 0x62, 0x96, 0x06, 0xFE, 0x5E, 0xFE, 0x47, 0xB6, 0x22, 0xB4, 0x62, 0x84, 0x3D, 0x94, 0x01, + 0xFE, 0x5E, 0xFE, 0x0F, 0xB6, 0x02, 0xDD, 0x9E, 0xFC, 0x00, 0x44, 0x24, 0x00, 0x18, 0x46, 0x0E, + 0x1F, 0x8F, 0xB4, 0x22, 0x50, 0x00, 0x0F, 0xFE, 0xFE, 0x0E, 0x46, 0x10, 0xE0, 0x60, 0x8C, 0x21, + 0xFE, 0x0F, 0x44, 0x34, 0x00, 0x10, 0xB6, 0x02, 0xB4, 0x03, 0x44, 0x10, 0x98, 0x78, 0x92, 0x10, + 0xDD, 0x4E, 0xFE, 0x0F, 0xB6, 0x03, 0xB4, 0x22, 0x46, 0x09, 0xE4, 0xFF, 0x50, 0x00, 0x0C, 0xFF, + 0xFE, 0x0E, 0x46, 0x16, 0x09, 0x00, 0x50, 0x10, 0x81, 0x00, 0xFE, 0x0F, 0xB6, 0x02, 0x84, 0x00, + 0x80, 0x20, 0x49, 0xFF, 0xFC, 0x91, 0xFC, 0x80, 0xFC, 0x00, 0x44, 0x57, 0x20, 0x44, 0xFE, 0x44, + 0xB4, 0xC5, 0xEA, 0x2B, 0x46, 0x4F, 0xC0, 0x0F, 0x40, 0x30, 0xC0, 0x08, 0x50, 0x12, 0x0F, 0xFF, + 0xFE, 0x76, 0xFE, 0x5F, 0x44, 0x37, 0x20, 0x4C, 0xB6, 0x25, 0xB4, 0x23, 0xEB, 0x0B, 0xFF, 0x0E, + 0x46, 0x10, 0x3F, 0xF0, 0xFE, 0x8E, 0x58, 0x42, 0x02, 0x88, 0xFF, 0x17, 0xB6, 0x83, 0x44, 0x37, + 0x20, 0x04, 0xEB, 0x4E, 0xB4, 0x43, 0xDD, 0x4A, 0xFE, 0x56, 0x46, 0x20, 0x02, 0x90, 0xFE, 0x57, + 0xB6, 0x23, 0xEA, 0x62, 0x04, 0x30, 0x80, 0x70, 0x5A, 0x00, 0x10, 0x05, 0x44, 0x21, 0x05, 0x00, + 0xD5, 0x03, 0x44, 0x21, 0x07, 0x00, 0x46, 0x1F, 0xFF, 0x0F, 0x50, 0x10, 0x80, 0xFF, 0x40, 0x01, + 0x84, 0x02, 0xEA, 0x62, 0xFE, 0x17, 0x14, 0x00, 0x80, 0x70, 0x46, 0x00, 0x00, 0x91, 0x83, 0x80, + 0xB9, 0x11, 0x58, 0x10, 0x80, 0x10, 0xB9, 0x91, 0xBA, 0x13, 0xEA, 0xDB, 0xFE, 0x57, 0xB9, 0x93, + 0xFC, 0x80, 0xFC, 0x20, 0x46, 0x40, 0x00, 0x91, 0x22, 0x5F, 0x80, 0x12, 0xDD, 0x5E, 0x22, 0x6F, + 0x80, 0x10, 0xFE, 0x0F, 0xEB, 0x4D, 0x83, 0x84, 0xBF, 0x1C, 0xFE, 0x9F, 0xB8, 0x9C, 0x40, 0x32, + 0xC0, 0x08, 0x46, 0x10, 0x3F, 0xF0, 0xB8, 0x1D, 0xFE, 0xF7, 0xBA, 0x9D, 0x50, 0x10, 0x83, 0xFF, + 0xB8, 0x20, 0xFE, 0xCE, 0x46, 0x1F, 0xC0, 0x0F, 0x50, 0x20, 0x8C, 0x00, 0xFE, 0x16, 0xFE, 0x1F, + 0xB8, 0xA0, 0xB8, 0x20, 0x54, 0x63, 0x03, 0xFF, 0x92, 0x0A, 0xDD, 0x47, 0xFF, 0x87, 0xBE, 0xA0, + 0x54, 0x52, 0x83, 0xFF, 0x40, 0x02, 0xC0, 0x08, 0xBD, 0x20, 0xDD, 0x4A, 0xFF, 0x4E, 0xFF, 0x47, + 0xBD, 0xA0, 0xFC, 0xA0, 0x46, 0x30, 0x00, 0x91, 0x84, 0x83, 0x14, 0x41, 0x80, 0x22, 0xA8, 0x19, + 0x44, 0x00, 0x01, 0xF4, 0xA8, 0x1A, 0x04, 0x01, 0x80, 0x0A, 0xEA, 0x67, 0x92, 0x0A, 0xDD, 0x47, + 0xDD, 0x45, 0x14, 0x01, 0x80, 0x0A, 0x04, 0x01, 0x80, 0x0B, 0xEB, 0x0B, 0x92, 0x0A, 0xDD, 0x47, + 0x58, 0x00, 0x02, 0x1C, 0x14, 0x01, 0x80, 0x0B, 0x04, 0x51, 0x80, 0x0E, 0x46, 0x40, 0x03, 0xF3, + 0x46, 0x0F, 0xFC, 0x0C, 0xFE, 0x8F, 0x50, 0x42, 0x0F, 0x00, 0xEB, 0x37, 0xFE, 0x2E, 0xFE, 0xA6, + 0x40, 0x11, 0x00, 0x04, 0x14, 0x11, 0x80, 0x0E, 0x04, 0x01, 0x80, 0x12, 0x58, 0x00, 0x30, 0x20, + 0x14, 0x01, 0x80, 0x12, 0x04, 0x11, 0x80, 0x13, 0x44, 0x0E, 0xE7, 0x87, 0xFE, 0x0E, 0x44, 0x11, + 0x08, 0x48, 0xFE, 0x0F, 0x14, 0x01, 0x80, 0x13, 0xB4, 0x23, 0xEA, 0x55, 0xFE, 0x0F, 0xB6, 0x03, + 0xDD, 0x9E, 0x46, 0x00, 0x00, 0x91, 0x50, 0x30, 0x00, 0x44, 0xB4, 0x23, 0x58, 0x10, 0x80, 0x01, + 0xB6, 0x23, 0xB4, 0x43, 0x84, 0x3E, 0xFE, 0x56, 0xB6, 0x23, 0xDD, 0x9E, 0x46, 0x20, 0x00, 0x91, + 0x96, 0x2F, 0xA0, 0x53, 0x92, 0x26, 0x94, 0x4E, 0xFE, 0x47, 0xA8, 0x53, 0xDD, 0x9E, 0x46, 0x20, + 0x00, 0x91, 0x96, 0x06, 0x04, 0x31, 0x00, 0x11, 0x94, 0x41, 0x84, 0x1D, 0xFE, 0x1E, 0xFE, 0x0F, + 0xEA, 0xAD, 0xDD, 0x9E, 0x44, 0x04, 0x80, 0x08, 0xB4, 0x00, 0x92, 0x02, 0x96, 0x06, 0xDD, 0x9E, + 0x46, 0x20, 0x00, 0x91, 0x96, 0x27, 0xA0, 0x54, 0x92, 0x25, 0x94, 0x4D, 0xFE, 0x47, 0xA8, 0x54, + 0xDD, 0x9E, 0x44, 0x17, 0x30, 0x10, 0xB4, 0x01, 0x96, 0x06, 0xC0, 0xFE, 0xEA, 0xF3, 0xB4, 0x01, + 0x92, 0x03, 0x96, 0x06, 0x5A, 0x00, 0x01, 0xFD, 0xDD, 0x9E, 0x84, 0xA0, 0xD0, 0x04, 0xEA, 0xF6, + 0x8C, 0xA1, 0xD5, 0xFD, 0xDD, 0x9E, 0x44, 0x27, 0x30, 0x10, 0xB4, 0x22, 0x92, 0x21, 0x96, 0x46, + 0x5A, 0x10, 0x01, 0xFD, 0xFC, 0x00, 0x44, 0x17, 0x30, 0x00, 0xB6, 0x01, 0x84, 0x02, 0xEA, 0x2F, + 0xFC, 0x80, 0xFC, 0x00, 0x46, 0x61, 0xFF, 0xF9, 0x50, 0x03, 0x05, 0x27, 0xEA, 0x32, 0x50, 0x03, + 0x04, 0x87, 0xEA, 0x32, 0xFC, 0x80, 0xFC, 0x00, 0x46, 0x61, 0xFF, 0xF9, 0x50, 0x03, 0x05, 0x00, + 0xEA, 0x32, 0x50, 0x03, 0x04, 0x00, 0xEA, 0x32, 0xFC, 0x80, 0xFC, 0x00, 0x46, 0x11, 0xFF, 0xFF, + 0x50, 0x10, 0x8F, 0x00, 0xFE, 0x0F, 0xEA, 0x32, 0xFC, 0x80, 0xFC, 0x00, 0x46, 0x11, 0xFF, 0xFF, + 0xFE, 0x0F, 0xEA, 0x32, 0xFC, 0x80, 0xFC, 0x00, 0x46, 0x01, 0xFF, 0xFF, 0x50, 0x00, 0x02, 0xBB, + 0xEA, 0x32, 0xFC, 0x80, 0xFC, 0x41, 0xF0, 0x81, 0x80, 0xE1, 0x80, 0xC2, 0x81, 0x03, 0x81, 0x44, + 0x81, 0x25, 0xEB, 0x26, 0xF0, 0x01, 0x5A, 0x00, 0xFF, 0x04, 0xEA, 0xBD, 0xEA, 0x93, 0x40, 0x84, + 0x20, 0x08, 0x40, 0xA4, 0x28, 0x04, 0x40, 0x63, 0x40, 0x08, 0x40, 0x65, 0x18, 0x04, 0x40, 0x03, + 0xE0, 0x08, 0xFE, 0x37, 0xEA, 0x32, 0xEA, 0x93, 0x5A, 0x98, 0x01, 0x05, 0x84, 0x0F, 0xEA, 0xBD, + 0xEA, 0x93, 0xEB, 0x04, 0xFC, 0xC1, 0x44, 0x27, 0x30, 0x10, 0xB4, 0x22, 0x92, 0x21, 0x96, 0x46, + 0x5A, 0x10, 0x01, 0xFD, 0xFC, 0x20, 0x44, 0x17, 0x30, 0x00, 0x44, 0x60, 0x10, 0x00, 0xB6, 0x01, + 0x44, 0x74, 0x80, 0x08, 0xB4, 0x07, 0x92, 0x11, 0x96, 0x06, 0xC0, 0x09, 0x2E, 0x07, 0xF9, 0x10, + 0xC0, 0x0E, 0x84, 0x00, 0x3E, 0x07, 0xF9, 0x10, 0xEA, 0xB4, 0xFC, 0xA0, 0x2E, 0x07, 0xF9, 0x10, + 0xC8, 0xF6, 0x84, 0x01, 0x8E, 0xC1, 0xEA, 0x2F, 0xCE, 0xEE, 0xD5, 0xF1, 0x44, 0x07, 0x30, 0x14, + 0xB4, 0x00, 0x92, 0x10, 0x96, 0x00, 0xFC, 0xA0, 0xFC, 0x01, 0xEB, 0x32, 0xF0, 0x81, 0x46, 0x02, + 0xF0, 0x00, 0x40, 0x61, 0x00, 0x04, 0xDD, 0x5E, 0xFF, 0x8F, 0xEB, 0x26, 0xF0, 0x01, 0xEA, 0xBD, + 0xEA, 0x93, 0x80, 0x06, 0x49, 0xFF, 0xFF, 0xC9, 0xF0, 0x81, 0x84, 0x0F, 0xEA, 0xBD, 0xEA, 0x93, + 0xEB, 0x04, 0xF0, 0x01, 0xFC, 0x81, 0xFC, 0x00, 0x44, 0x17, 0x30, 0x08, 0x84, 0xC1, 0xB4, 0x01, + 0x92, 0x05, 0x94, 0x05, 0xFE, 0x37, 0xB6, 0x01, 0xEB, 0x26, 0x80, 0x66, 0x80, 0xA6, 0x84, 0x06, + 0xFA, 0x2F, 0x44, 0x20, 0x00, 0xAC, 0x84, 0x80, 0xDD, 0x46, 0x84, 0x06, 0xFA, 0x2F, 0x44, 0x20, + 0x00, 0xAD, 0x80, 0x66, 0x84, 0x80, 0x80, 0xA6, 0xDD, 0x46, 0xEA, 0x7A, 0x84, 0x24, 0xAE, 0x40, + 0x84, 0x22, 0xAE, 0x40, 0xEA, 0x9A, 0xEA, 0xDB, 0xB4, 0x40, 0xFE, 0x57, 0xB6, 0x20, 0xB4, 0x40, + 0xEB, 0x3F, 0xFE, 0x57, 0xB6, 0x20, 0xEB, 0x04, 0xFC, 0x80, 0xFC, 0x00, 0xEA, 0x31, 0x84, 0x61, + 0x84, 0x00, 0x80, 0x80, 0x80, 0xA3, 0xFA, 0x2F, 0xFA, 0x41, 0xDD, 0x46, 0xDD, 0x5C, 0xEA, 0x3C, + 0x84, 0x00, 0x84, 0x61, 0x80, 0x80, 0xFA, 0x2F, 0xFA, 0x59, 0x80, 0xA3, 0xDD, 0x46, 0xFA, 0x04, + 0xEA, 0x3C, 0xFC, 0x80, 0xFC, 0x00, 0xEA, 0x31, 0x84, 0x61, 0x84, 0x00, 0x80, 0x80, 0x80, 0xA3, + 0xFA, 0x2F, 0xFA, 0x58, 0xDD, 0x46, 0xFA, 0x04, 0xEA, 0x3C, 0x84, 0x00, 0x84, 0x61, 0x80, 0x80, + 0xFA, 0x2F, 0xFA, 0x40, 0x80, 0xA3, 0xDD, 0x46, 0xDD, 0x5C, 0xEA, 0x3C, 0xFC, 0x80, 0xFC, 0x00, + 0x80, 0xC0, 0xEA, 0xE9, 0x49, 0xFF, 0xF2, 0x12, 0x84, 0x41, 0x44, 0x14, 0x2C, 0x20, 0xFF, 0x96, + 0xB4, 0x61, 0x40, 0x03, 0x64, 0x08, 0x46, 0x6F, 0xDF, 0xFF, 0xEA, 0xB5, 0xFF, 0x9E, 0xFF, 0x87, + 0xB6, 0xC1, 0xB4, 0x61, 0xEA, 0x44, 0xDD, 0x41, 0xFE, 0x1E, 0xB6, 0x01, 0x80, 0x62, 0x44, 0x04, + 0x28, 0x20, 0x44, 0x14, 0x24, 0x20, 0xDD, 0x40, 0x49, 0xFF, 0xF2, 0x07, 0xEB, 0x10, 0xFC, 0x80, + 0x3C, 0x0F, 0xFE, 0x45, 0xDD, 0x9E, 0xC9, 0x08, 0x44, 0x24, 0x00, 0x0C, 0x84, 0x3E, 0xB4, 0x62, + 0x96, 0x06, 0xFE, 0x5E, 0xD5, 0x0A, 0x5A, 0x18, 0x01, 0x0B, 0x44, 0x24, 0x00, 0x0C, 0x96, 0x06, + 0xB4, 0x62, 0x94, 0x41, 0x84, 0x1D, 0xFE, 0x1E, 0xFE, 0x0F, 0xB6, 0x02, 0xDD, 0x9E, 0xC9, 0x04, + 0x44, 0x25, 0x00, 0x00, 0xD5, 0x05, 0x5A, 0x18, 0x01, 0x0C, 0x44, 0x25, 0x00, 0x10, 0x96, 0x1F, + 0xDD, 0x49, 0xB4, 0x62, 0xEA, 0xC6, 0xDD, 0x41, 0xFE, 0x1E, 0xFE, 0x0F, 0xB6, 0x02, 0xDD, 0x9E, + 0xC9, 0x08, 0x44, 0x24, 0x80, 0x80, 0x96, 0x06, 0xEA, 0xD7, 0xB4, 0x62, 0xEA, 0x44, 0xD5, 0x0A, + 0x5A, 0x18, 0x01, 0x0D, 0x44, 0x24, 0x80, 0x80, 0x96, 0x06, 0x40, 0x10, 0x64, 0x08, 0xB4, 0x62, + 0xEA, 0x9C, 0xDD, 0x41, 0xFE, 0x1E, 0xFE, 0x0F, 0xB6, 0x02, 0xDD, 0x9E, 0xFC, 0x00, 0x44, 0x60, + 0x00, 0x64, 0xCA, 0x06, 0x44, 0x21, 0x2D, 0xF4, 0x42, 0x50, 0x08, 0x24, 0xD5, 0x11, 0x44, 0x20, + 0xFF, 0xFF, 0xDA, 0x0D, 0x44, 0x50, 0x03, 0xE8, 0x40, 0x42, 0x14, 0x97, 0x42, 0x50, 0x10, 0x24, + 0x40, 0x63, 0x04, 0x0C, 0x40, 0x62, 0x98, 0xD7, 0x96, 0x31, 0xD5, 0x07, 0xFF, 0x44, 0x40, 0x03, + 0x04, 0x0C, 0x40, 0x02, 0x80, 0x16, 0x96, 0x01, 0xCB, 0x04, 0x44, 0x25, 0x00, 0x04, 0xD5, 0x05, + 0x5A, 0x38, 0x01, 0x09, 0x44, 0x25, 0x00, 0x14, 0xB4, 0x22, 0x92, 0x30, 0xDD, 0x5E, 0xFE, 0x0F, + 0xB6, 0x02, 0xFC, 0x80, 0xC8, 0x07, 0xEA, 0x3B, 0x84, 0x21, 0xAE, 0x40, 0x44, 0x15, 0x00, 0x08, + 0xD5, 0x08, 0x5A, 0x08, 0x01, 0x0A, 0xEA, 0x3B, 0x84, 0x22, 0xAE, 0x40, 0x44, 0x15, 0x00, 0x18, + 0xB4, 0x01, 0xEA, 0x57, 0xB6, 0x01, 0xDD, 0x9E, 0xC8, 0x07, 0xEA, 0x3B, 0x84, 0x21, 0xAE, 0x40, + 0x44, 0x15, 0x00, 0x08, 0xD5, 0x08, 0x5A, 0x08, 0x01, 0x0A, 0xEA, 0x3B, 0x84, 0x22, 0xAE, 0x40, + 0x44, 0x15, 0x00, 0x18, 0xB4, 0x01, 0xEA, 0x87, 0xB6, 0x01, 0xDD, 0x9E, 0xC9, 0x04, 0x44, 0x25, + 0x00, 0x00, 0xD5, 0x05, 0x5A, 0x18, 0x01, 0x0A, 0x44, 0x25, 0x00, 0x10, 0xB4, 0x62, 0x84, 0x3E, + 0x96, 0x06, 0xFE, 0x5E, 0xFE, 0x0F, 0xB6, 0x02, 0xDD, 0x9E, 0x84, 0x21, 0xC0, 0x04, 0x5A, 0x08, + 0x01, 0x05, 0x84, 0x22, 0xEA, 0x3B, 0xAE, 0x40, 0xDD, 0x9E, 0x44, 0x04, 0x80, 0x00, 0xB4, 0x00, + 0x92, 0x18, 0x96, 0x06, 0xC0, 0x0D, 0xFC, 0x00, 0xEA, 0x3B, 0x84, 0x21, 0xAE, 0x40, 0xDD, 0x44, + 0x3C, 0x0D, 0xFE, 0x45, 0xC0, 0x04, 0x3C, 0x0D, 0xFE, 0x45, 0xDD, 0x20, 0xFC, 0x80, 0xDD, 0x9E, + 0x44, 0x04, 0x80, 0x00, 0xB4, 0x00, 0x92, 0x19, 0x96, 0x06, 0xC0, 0x07, 0xFC, 0x00, 0xEA, 0x3B, + 0x84, 0x22, 0xAE, 0x40, 0xDD, 0x44, 0xFC, 0x80, 0xDD, 0x9E, 0x46, 0x20, 0x00, 0x81, 0x84, 0x3E, + 0x04, 0x31, 0x00, 0x14, 0x96, 0x06, 0xFE, 0x5E, 0xFE, 0x0F, 0x14, 0x01, 0x00, 0x14, 0xDD, 0x9E, + 0x46, 0x20, 0x00, 0x81, 0x84, 0x3E, 0xA0, 0xD5, 0x96, 0x06, 0xFE, 0x5E, 0xFE, 0x0F, 0xA8, 0x15, + 0xDD, 0x9E, 0x46, 0x00, 0x00, 0x81, 0xA0, 0x05, 0x96, 0x06, 0xDD, 0x9E, 0x44, 0x14, 0x70, 0x08, + 0x5A, 0x08, 0x01, 0x08, 0xB4, 0x01, 0x92, 0x10, 0xDD, 0x4E, 0x58, 0x00, 0x78, 0x23, 0xD5, 0x04, + 0xB4, 0x01, 0x92, 0x10, 0xDD, 0x4E, 0xB6, 0x01, 0xDD, 0x9E, 0x44, 0x24, 0x50, 0x14, 0x84, 0x3E, + 0xB4, 0x62, 0x96, 0x06, 0xFE, 0x5E, 0xFE, 0x0F, 0xB6, 0x02, 0xDD, 0x9E, 0x44, 0x05, 0x10, 0x00, + 0xB4, 0x00, 0x92, 0x08, 0x96, 0x17, 0xDD, 0x9E, 0x44, 0x25, 0x10, 0x04, 0xB4, 0x22, 0x92, 0x30, + 0xDD, 0x5E, 0xFE, 0x0F, 0xB6, 0x02, 0xDD, 0x9E, 0x44, 0x15, 0x10, 0x0C, 0xB4, 0x01, 0xEA, 0x57, + 0xB6, 0x01, 0xDD, 0x9E, 0x44, 0x15, 0x10, 0x0C, 0xB4, 0x01, 0xDD, 0x45, 0xB6, 0x01, 0x44, 0x15, + 0x10, 0x18, 0xB4, 0x01, 0x96, 0x00, 0x5A, 0x00, 0x5A, 0xFE, 0xDD, 0x9E, 0xFC, 0x40, 0x44, 0x00, + 0x01, 0x2C, 0xDD, 0x51, 0x44, 0x75, 0x10, 0x0C, 0x44, 0x9F, 0xFF, 0x98, 0x84, 0x00, 0xAE, 0x38, + 0xFA, 0x18, 0x10, 0x93, 0x80, 0x00, 0xDD, 0x51, 0x44, 0x05, 0x10, 0x18, 0x44, 0x65, 0x10, 0x0C, + 0xB4, 0x00, 0x96, 0x00, 0x5A, 0x00, 0xA5, 0xF4, 0xB4, 0x26, 0x84, 0x1E, 0xFE, 0x0E, 0xB6, 0x06, + 0xFC, 0xC0, 0x4E, 0x05, 0x00, 0x19, 0x8E, 0x01, 0x40, 0x10, 0x04, 0x0A, 0xFE, 0x0F, 0x40, 0x10, + 0x08, 0x0A, 0xFE, 0x0F, 0x40, 0x10, 0x10, 0x0A, 0xFE, 0x0F, 0x40, 0x10, 0x20, 0x0A, 0xFE, 0x0F, + 0x40, 0x10, 0x40, 0x0A, 0xFE, 0x47, 0x8C, 0x21, 0x84, 0x00, 0x90, 0x21, 0xC1, 0x03, 0x8C, 0x01, + 0xD5, 0xFD, 0xDD, 0x9E, 0x84, 0x00, 0xDD, 0x9E, 0xFC, 0x4D, 0x44, 0x00, 0x79, 0xE0, 0x50, 0xFF, + 0x80, 0x18, 0x80, 0xC0, 0x80, 0x2F, 0x3A, 0x23, 0x14, 0x04, 0xEA, 0x60, 0x81, 0x46, 0x83, 0x81, + 0x3A, 0x25, 0x14, 0x04, 0x44, 0x90, 0x7A, 0x08, 0x3A, 0x2E, 0x14, 0x24, 0x80, 0x89, 0x3A, 0x25, + 0x0C, 0x00, 0x80, 0xBF, 0x3A, 0x2E, 0x0C, 0x20, 0x3A, 0x22, 0x0C, 0x04, 0x3A, 0x22, 0x8C, 0x24, + 0x45, 0xE2, 0x10, 0xF0, 0xA5, 0xE0, 0x3A, 0x27, 0x94, 0x04, 0x81, 0xFE, 0x81, 0x1F, 0x3A, 0x27, + 0x94, 0x24, 0xEA, 0x88, 0x80, 0x2F, 0xEA, 0x60, 0x3A, 0x2E, 0x0C, 0x00, 0x3A, 0x20, 0x8C, 0x20, + 0x44, 0x12, 0x10, 0xE4, 0x3A, 0x24, 0x0C, 0x04, 0xEA, 0xAC, 0xAD, 0xC8, 0xB0, 0x50, 0xEA, 0x79, + 0x80, 0x01, 0xEA, 0x6C, 0x81, 0x00, 0x3A, 0x23, 0x14, 0x04, 0x3A, 0x24, 0x14, 0x24, 0xB1, 0x83, + 0x3A, 0x25, 0x0C, 0x00, 0x80, 0x86, 0x3A, 0x24, 0x0C, 0x20, 0x3A, 0x24, 0x8C, 0x04, 0x44, 0x92, + 0x0D, 0x7C, 0x3A, 0x22, 0x0C, 0x24, 0xEA, 0x88, 0x80, 0x29, 0xEA, 0x60, 0xEA, 0x79, 0x80, 0x01, + 0xEA, 0x6C, 0x3A, 0x24, 0x0C, 0x00, 0x3A, 0x20, 0x0C, 0x20, 0x44, 0x02, 0x0D, 0x70, 0x3A, 0x23, + 0x0C, 0x04, 0x3A, 0x20, 0x0C, 0x24, 0xAD, 0xC0, 0xFC, 0xCD, 0xFC, 0x48, 0x81, 0x20, 0x50, 0xAF, + 0x80, 0x14, 0x44, 0x00, 0x7A, 0x14, 0x83, 0x81, 0x80, 0x2A, 0x80, 0xE2, 0x80, 0xC3, 0xEA, 0xE4, + 0xEA, 0xAC, 0xA4, 0x00, 0xFA, 0x40, 0xAC, 0x08, 0x50, 0x8F, 0x80, 0x30, 0x84, 0x20, 0xB0, 0x08, + 0xDD, 0x42, 0x80, 0x08, 0x84, 0x20, 0xFA, 0x40, 0xDD, 0x42, 0x5A, 0x78, 0x01, 0x03, 0x87, 0x80, + 0x4E, 0x92, 0x00, 0x05, 0x44, 0x12, 0x0D, 0x00, 0xD5, 0x03, 0x44, 0x12, 0x0D, 0x5C, 0x5A, 0x68, + 0x02, 0x05, 0x58, 0x03, 0x80, 0x01, 0xD5, 0x02, 0x80, 0x07, 0x8C, 0x01, 0x85, 0x20, 0xB6, 0x1F, + 0x8C, 0xE1, 0x84, 0x63, 0x84, 0x81, 0x38, 0x05, 0x24, 0x00, 0xF4, 0x83, 0xF3, 0x82, 0x38, 0x60, + 0x80, 0x00, 0xB4, 0x1F, 0x8C, 0xC1, 0xFF, 0x84, 0x97, 0xB1, 0x40, 0x63, 0x1C, 0xD6, 0x80, 0x06, + 0xF1, 0x81, 0x49, 0xFF, 0xFF, 0x50, 0xF3, 0x02, 0x54, 0x54, 0x80, 0xFF, 0x40, 0x52, 0x8C, 0xB7, + 0xF4, 0x03, 0x38, 0x24, 0x16, 0x02, 0x8C, 0x08, 0x41, 0xE1, 0x28, 0x08, 0x40, 0x20, 0x70, 0x01, + 0x40, 0x02, 0x00, 0x0C, 0x40, 0x60, 0x18, 0xD7, 0xB0, 0x08, 0x94, 0x94, 0x38, 0x00, 0x16, 0x02, + 0x88, 0x5E, 0xDD, 0x47, 0x88, 0xC0, 0xB0, 0x08, 0x8D, 0x21, 0x38, 0x24, 0x16, 0x0A, 0x38, 0x60, + 0x16, 0x0A, 0xF1, 0x01, 0x5A, 0x98, 0x0A, 0xD1, 0x80, 0x28, 0x49, 0xFF, 0xED, 0x84, 0xFC, 0xC8, + 0x80, 0x80, 0x84, 0x40, 0x9A, 0xE0, 0x96, 0xD8, 0xE2, 0x61, 0xE8, 0x08, 0x08, 0x32, 0x00, 0x01, + 0xE2, 0x62, 0x40, 0x31, 0x3C, 0x1B, 0x80, 0x43, 0xD5, 0xF6, 0x9C, 0x11, 0x96, 0x00, 0xDD, 0x9E, + 0xFC, 0x40, 0x51, 0xFF, 0xFB, 0xE0, 0x44, 0x20, 0x04, 0x00, 0x80, 0xE0, 0x81, 0x21, 0xB0, 0x08, + 0x84, 0x20, 0xDD, 0x42, 0x50, 0xAF, 0x80, 0x04, 0x44, 0x00, 0x7A, 0x14, 0x80, 0x2A, 0xEA, 0xE4, + 0xEA, 0xAC, 0xA4, 0x00, 0xB1, 0x84, 0xAC, 0x08, 0xFA, 0x40, 0x80, 0x06, 0x84, 0x20, 0xDD, 0x42, + 0xCF, 0x04, 0x44, 0x02, 0x0D, 0x5C, 0xD5, 0x03, 0x44, 0x02, 0x0D, 0x00, 0x84, 0x2A, 0x49, 0xFF, + 0xFF, 0xD1, 0x80, 0x20, 0x80, 0x4A, 0x84, 0x80, 0x44, 0x82, 0x0D, 0x7C, 0x45, 0xC2, 0x0D, 0x70, + 0x84, 0x03, 0x40, 0xA2, 0x01, 0x57, 0xB1, 0x48, 0x40, 0x35, 0x20, 0x08, 0x88, 0x65, 0x84, 0xA0, + 0xCF, 0x21, 0x80, 0xA7, 0x54, 0xF2, 0x80, 0xFF, 0x40, 0xF7, 0x84, 0x06, 0xE8, 0x15, 0x00, 0xF1, + 0x00, 0x00, 0x44, 0x02, 0x10, 0xF0, 0x38, 0xF0, 0x3E, 0x02, 0x38, 0xF7, 0x95, 0x01, 0x55, 0xE7, + 0x83, 0xFF, 0x38, 0xF1, 0x96, 0x02, 0x40, 0xF7, 0xA8, 0x08, 0x40, 0xFF, 0x3C, 0x00, 0x38, 0xF1, + 0x96, 0x0A, 0x8C, 0xA1, 0xD5, 0xE8, 0xA6, 0xD0, 0x44, 0x02, 0x10, 0xE4, 0x38, 0x30, 0x0C, 0x00, + 0xD5, 0x1B, 0x54, 0xF2, 0x80, 0xFF, 0x40, 0xF7, 0x84, 0x06, 0xE8, 0x13, 0x00, 0xF1, 0x00, 0x00, + 0x38, 0xF4, 0x3E, 0x02, 0x38, 0xF7, 0x95, 0x01, 0x55, 0xE7, 0x83, 0xFF, 0x38, 0xF1, 0x96, 0x02, + 0x40, 0xF7, 0xA8, 0x08, 0x40, 0xFF, 0x3C, 0x00, 0x38, 0xF1, 0x96, 0x0A, 0x8C, 0xA1, 0xD5, 0xEA, + 0xA6, 0xD0, 0x38, 0x3E, 0x0C, 0x00, 0x8A, 0x69, 0x54, 0x51, 0x83, 0xFF, 0x38, 0x33, 0x2A, 0x02, + 0x8C, 0x81, 0x40, 0x31, 0xA8, 0x08, 0x88, 0x65, 0x97, 0x20, 0x38, 0x33, 0x2A, 0x0A, 0x8C, 0x41, + 0x5A, 0x48, 0x0A, 0xB0, 0xB0, 0x08, 0x49, 0xFF, 0xED, 0x40, 0x80, 0x06, 0x49, 0xFF, 0xED, 0x72, + 0x51, 0xFF, 0x84, 0x20, 0xFC, 0xC0, 0xFC, 0x42, 0x85, 0x20, 0x80, 0xC0, 0x80, 0x03, 0x80, 0xE1, + 0xF4, 0x81, 0x14, 0x9F, 0x80, 0x03, 0xEA, 0x99, 0xF0, 0x83, 0xF0, 0x01, 0x49, 0xFF, 0xF7, 0x25, + 0xF1, 0x03, 0x80, 0x69, 0xF1, 0x83, 0x44, 0xA2, 0x07, 0xC8, 0x44, 0x10, 0x00, 0x36, 0x85, 0x2C, + 0x84, 0xA0, 0x99, 0x1D, 0x97, 0x21, 0x38, 0x25, 0x11, 0x01, 0x5C, 0xF1, 0x01, 0x45, 0x8E, 0x41, + 0x40, 0x21, 0x05, 0x16, 0xE9, 0x04, 0x8E, 0x4C, 0x52, 0x84, 0x00, 0x36, 0x42, 0x24, 0x24, 0x73, + 0x96, 0x91, 0xC6, 0x0A, 0x04, 0xFF, 0x80, 0x03, 0x38, 0x80, 0x09, 0x01, 0x38, 0xF7, 0x89, 0x01, + 0x8B, 0x0F, 0x38, 0x83, 0x11, 0x09, 0xC7, 0x07, 0x04, 0x8F, 0x80, 0x03, 0x38, 0x24, 0x09, 0x11, + 0x38, 0x23, 0x91, 0x09, 0x8C, 0xA1, 0x5A, 0x58, 0x12, 0xDE, 0x8C, 0x72, 0x96, 0xD9, 0x5A, 0x3A, + 0x88, 0xD9, 0xFC, 0xC2, 0xFC, 0x41, 0x84, 0xC0, 0x81, 0x20, 0x80, 0x02, 0x80, 0xE1, 0xF6, 0x81, + 0xEA, 0x99, 0xF0, 0x81, 0xF0, 0x01, 0x80, 0x46, 0xF0, 0x81, 0x96, 0x51, 0xE2, 0x27, 0xE8, 0x08, + 0xF0, 0x01, 0x38, 0x00, 0x09, 0x11, 0x38, 0x04, 0x89, 0x09, 0x8C, 0x41, 0xD5, 0xF7, 0xFC, 0xC1, + 0xFC, 0x41, 0x84, 0xC0, 0x81, 0x20, 0x80, 0x06, 0x80, 0xE1, 0xF6, 0x81, 0xEA, 0x99, 0xF0, 0x81, + 0xF2, 0x01, 0x50, 0x21, 0x05, 0x10, 0xF2, 0x81, 0x80, 0x46, 0x96, 0x11, 0xE2, 0x07, 0xE8, 0x08, + 0xF0, 0x01, 0x38, 0x00, 0x09, 0x11, 0x38, 0x04, 0x89, 0x09, 0x8C, 0x41, 0xD5, 0xF7, 0xFC, 0xC1, + 0xFC, 0x40, 0x44, 0xA0, 0x80, 0x00, 0x40, 0x92, 0x04, 0x0A, 0xC0, 0x2A, 0x2A, 0x51, 0x00, 0x01, + 0x2A, 0x80, 0x80, 0x01, 0x40, 0x74, 0x40, 0x08, 0xEA, 0xCA, 0x8A, 0xA7, 0x80, 0xC9, 0x42, 0x61, + 0x94, 0x73, 0x40, 0x53, 0x10, 0xB6, 0x80, 0xC5, 0x4E, 0x54, 0x00, 0x03, 0xFF, 0xAA, 0x90, 0xD0, + 0xCE, 0x0F, 0x40, 0x74, 0x00, 0x13, 0x4E, 0x56, 0x00, 0x07, 0xE2, 0xC5, 0x52, 0x57, 0x80, 0x00, + 0x97, 0x69, 0xD5, 0x02, 0x84, 0xA1, 0x88, 0xA7, 0x12, 0x50, 0xFF, 0xFF, 0xD5, 0x06, 0x88, 0xE5, + 0x88, 0xEA, 0x90, 0xF0, 0x12, 0x70, 0xFF, 0xFF, 0x8E, 0x01, 0x96, 0x01, 0xD5, 0xD7, 0xFC, 0xC0, + 0x2E, 0x17, 0xEF, 0x92, 0x88, 0x01, 0x96, 0x01, 0x54, 0x10, 0x00, 0x01, 0xC1, 0x03, 0x8C, 0x01, + 0x96, 0x01, 0xDD, 0x9E, 0xFC, 0x20, 0x80, 0xC1, 0xEA, 0x78, 0xC8, 0x04, 0x2E, 0x57, 0xEF, 0x93, + 0xD5, 0x03, 0x2E, 0x57, 0xEF, 0x94, 0x3C, 0x03, 0xF7, 0xBC, 0x3C, 0x33, 0xF7, 0xBD, 0x2E, 0x27, + 0xEF, 0x91, 0x9A, 0xC3, 0x44, 0x40, 0x00, 0x4D, 0xFE, 0xE4, 0x3C, 0x03, 0xF7, 0xBE, 0x8A, 0x62, + 0x52, 0x72, 0x80, 0x01, 0x50, 0x21, 0xFF, 0xCE, 0x8C, 0x1E, 0x42, 0x20, 0x1C, 0x73, 0x2E, 0x07, + 0xEF, 0x8E, 0x3C, 0x13, 0xF7, 0xC4, 0x42, 0x20, 0x14, 0x75, 0x80, 0x62, 0x3C, 0x03, 0xF7, 0xC0, + 0x3C, 0x23, 0xF7, 0xBF, 0x84, 0x82, 0x88, 0x40, 0x2E, 0x07, 0xEF, 0x8F, 0x88, 0x41, 0x88, 0x40, + 0x84, 0x03, 0xFE, 0x84, 0x40, 0x21, 0x10, 0x56, 0x9A, 0x9A, 0x2E, 0x47, 0xEF, 0x8B, 0x2E, 0x37, + 0xEF, 0x8A, 0x88, 0x64, 0x2E, 0x47, 0xEF, 0x90, 0x88, 0x61, 0x88, 0x64, 0xFE, 0xC4, 0x90, 0x61, + 0x42, 0x21, 0x9C, 0x73, 0x40, 0x21, 0x14, 0x57, 0x94, 0x91, 0xFE, 0x34, 0x40, 0x01, 0x00, 0x17, + 0x92, 0x01, 0x96, 0x00, 0xFC, 0xA0, 0xFC, 0x04, 0xB1, 0x83, 0x80, 0x06, 0x44, 0x12, 0x0E, 0x8C, + 0xFA, 0x44, 0xEA, 0x41, 0x80, 0x1F, 0x44, 0x12, 0x0E, 0x80, 0x84, 0x4A, 0xEA, 0x41, 0x2E, 0x07, + 0xEF, 0x96, 0x38, 0x03, 0x00, 0x00, 0x38, 0x0F, 0x80, 0x00, 0x8C, 0x01, 0x96, 0x00, 0xFC, 0x84, + 0xEA, 0xF4, 0xDD, 0x9E, 0x3E, 0x07, 0xF9, 0x50, 0xDD, 0x9E, 0xFC, 0x00, 0x44, 0x62, 0x07, 0x00, + 0x44, 0x02, 0x0E, 0x58, 0x49, 0xFF, 0xEF, 0x73, 0x00, 0x13, 0x00, 0x5F, 0x00, 0x23, 0x00, 0x63, + 0x00, 0x33, 0x00, 0x62, 0x00, 0x43, 0x00, 0x60, 0x00, 0x53, 0x00, 0x61, 0x84, 0x01, 0x49, 0xFF, + 0xEF, 0x29, 0x84, 0x01, 0x49, 0xFF, 0xEF, 0x55, 0x49, 0xFF, 0xF2, 0x40, 0x84, 0x00, 0x49, 0xFF, + 0xF2, 0x33, 0x49, 0xFF, 0xF6, 0xF1, 0x00, 0x03, 0x00, 0x5E, 0x3E, 0x07, 0xF9, 0x50, 0xFC, 0x80, + 0xFC, 0x00, 0x80, 0xC0, 0x5A, 0x18, 0x01, 0x04, 0x84, 0x22, 0xD5, 0x02, 0x84, 0x20, 0x42, 0x00, + 0x98, 0x24, 0x54, 0x00, 0x00, 0xFE, 0x49, 0xFF, 0xF2, 0x0B, 0x80, 0x06, 0x84, 0x20, 0x49, 0xFF, + 0xF2, 0x2E, 0x80, 0x06, 0x49, 0xFF, 0xF2, 0x55, 0xFC, 0x80, 0xFC, 0x49, 0x84, 0x20, 0x80, 0xC0, + 0xEA, 0x49, 0xB0, 0x06, 0xDD, 0x42, 0xEB, 0x18, 0xEA, 0xB2, 0xF0, 0x86, 0xEB, 0x20, 0xF1, 0x89, + 0xF0, 0x87, 0xEA, 0xA5, 0xEA, 0xC7, 0xF1, 0x8A, 0x94, 0x46, 0xF0, 0x88, 0xF1, 0x8B, 0xDD, 0x4F, + 0xDD, 0x47, 0xF1, 0x8C, 0xF0, 0x8D, 0x5A, 0x68, 0x01, 0x07, 0x44, 0x72, 0x0D, 0x0C, 0x44, 0x92, + 0x0C, 0xD8, 0xD5, 0x05, 0x44, 0x72, 0x0D, 0x48, 0x44, 0x92, 0x0D, 0x20, 0xB0, 0x06, 0xEA, 0x47, + 0x80, 0x1F, 0x44, 0x12, 0x0E, 0x68, 0xFA, 0x48, 0xCE, 0x06, 0xEA, 0x41, 0x80, 0x1F, 0xDD, 0x5D, + 0x80, 0x06, 0xD5, 0x05, 0xEA, 0x41, 0x80, 0x1F, 0xDD, 0x5D, 0x84, 0x01, 0xEA, 0x4A, 0x2E, 0x17, + 0xF9, 0x50, 0x84, 0x00, 0x38, 0x14, 0x85, 0x01, 0xEA, 0x4E, 0x2E, 0x17, 0xF9, 0x50, 0x84, 0x04, + 0x38, 0x14, 0x85, 0x01, 0xEA, 0x4E, 0xEA, 0xF4, 0x84, 0x20, 0x38, 0x03, 0x80, 0x00, 0xEA, 0x24, + 0xEA, 0xF4, 0x84, 0x23, 0x38, 0x03, 0x80, 0x00, 0xEA, 0x24, 0x84, 0x00, 0x80, 0x26, 0x49, 0xFF, + 0xFF, 0xA1, 0xCE, 0x05, 0x44, 0x02, 0x0D, 0x5C, 0x80, 0x26, 0xD5, 0x04, 0x44, 0x02, 0x0D, 0x00, + 0x84, 0x20, 0x49, 0xFF, 0xF2, 0x0F, 0x80, 0x06, 0xEA, 0xE2, 0xFC, 0xC9, 0x2E, 0x07, 0xF9, 0x56, + 0x96, 0x00, 0xC0, 0x05, 0x84, 0x00, 0x3E, 0x07, 0xF9, 0x56, 0x84, 0x01, 0xDD, 0x9E, 0x2E, 0x17, + 0xF9, 0x55, 0x96, 0x48, 0xC1, 0x05, 0x84, 0x00, 0x3E, 0x07, 0xF9, 0x55, 0xD5, 0x07, 0x2E, 0x07, + 0xF9, 0x54, 0x96, 0x00, 0xC0, 0x04, 0x3E, 0x17, 0xF9, 0x54, 0x84, 0x01, 0xDD, 0x9E, 0x2E, 0x07, + 0xF9, 0x58, 0xDD, 0x9E, 0x3E, 0x07, 0xF9, 0x58, 0xDD, 0x9E, 0x2E, 0x07, 0xF9, 0x57, 0xDD, 0x9E, + 0xDD, 0x9E, 0xFC, 0x00, 0x84, 0x0B, 0x44, 0x10, 0x00, 0xAB, 0x84, 0x41, 0xEA, 0x45, 0x96, 0x2E, + 0xC0, 0x07, 0x49, 0xFF, 0xE9, 0xC4, 0x84, 0x20, 0x40, 0x00, 0x80, 0x06, 0xFC, 0x80, 0x84, 0x01, + 0xFC, 0x80, 0xFC, 0x00, 0x49, 0xFF, 0xF0, 0x75, 0xFC, 0x80, 0xFC, 0x00, 0x49, 0xFF, 0xEF, 0x58, + 0xEA, 0x58, 0x5A, 0x08, 0x1F, 0x04, 0x49, 0xFF, 0xEF, 0x81, 0xFC, 0x80, 0x84, 0x40, 0x80, 0x22, + 0x44, 0x42, 0x11, 0x44, 0x96, 0xD1, 0xE2, 0x60, 0xE8, 0x06, 0x38, 0x32, 0x08, 0x00, 0x8C, 0x41, + 0x88, 0x23, 0xD5, 0xF9, 0xFE, 0x0A, 0x96, 0x00, 0xDD, 0x9E, 0x44, 0x32, 0x11, 0x44, 0xE2, 0x22, + 0xE8, 0x08, 0x38, 0x40, 0x04, 0x00, 0x38, 0x41, 0x84, 0x08, 0x8C, 0x21, 0x96, 0x48, 0xD5, 0xF8, + 0xDD, 0x9E, 0xFC, 0x01, 0xEA, 0x39, 0xEA, 0x63, 0x2E, 0x07, 0xF9, 0x65, 0x5A, 0x08, 0x01, 0x3E, + 0xEA, 0xD3, 0x5A, 0x08, 0x01, 0x06, 0x2E, 0x07, 0xF9, 0x64, 0x4E, 0x02, 0x00, 0x80, 0x84, 0x00, + 0x2E, 0x17, 0xF9, 0x06, 0xEA, 0xF0, 0x84, 0x22, 0x84, 0x00, 0xEA, 0x86, 0x49, 0xFF, 0xF8, 0x81, + 0x49, 0xFF, 0xFB, 0x0D, 0x49, 0xFF, 0xFF, 0xBF, 0x84, 0x00, 0x49, 0xFF, 0xFC, 0x18, 0x84, 0x00, + 0xEA, 0xA6, 0x84, 0x00, 0x49, 0xFF, 0xFC, 0x2C, 0x84, 0x40, 0x84, 0x61, 0x3C, 0x03, 0xF7, 0xE6, + 0x84, 0x27, 0xEA, 0x5C, 0x84, 0x00, 0x84, 0x21, 0xEA, 0xE0, 0x84, 0x01, 0x80, 0x20, 0xEA, 0xB6, + 0x84, 0x00, 0x49, 0xFF, 0xFF, 0x91, 0x84, 0x00, 0xEA, 0xEA, 0x84, 0x00, 0xEA, 0x6E, 0x84, 0x00, + 0xEB, 0x06, 0xEB, 0x49, 0x44, 0x60, 0x08, 0x01, 0xEA, 0x39, 0xC8, 0x50, 0x8E, 0xC1, 0x84, 0x01, + 0x97, 0xB1, 0xDD, 0x51, 0xCE, 0xFA, 0xFC, 0x81, 0x2E, 0x07, 0xF9, 0x65, 0x5A, 0x08, 0x02, 0x47, + 0xEA, 0xD3, 0xC8, 0x04, 0x2E, 0x07, 0xF9, 0x64, 0xC0, 0x41, 0x84, 0x00, 0x49, 0xFF, 0xF2, 0x7C, + 0x84, 0x01, 0x2E, 0x17, 0xF9, 0x06, 0xEA, 0xF0, 0x84, 0x01, 0x84, 0x22, 0xEA, 0x86, 0x49, 0xFF, + 0xEE, 0xC9, 0x49, 0xFF, 0xFA, 0xE1, 0x84, 0x02, 0x80, 0x20, 0xEA, 0x86, 0x49, 0xFF, 0xF7, 0xE2, + 0x84, 0x01, 0xEA, 0xEA, 0x84, 0x00, 0xEA, 0x6E, 0x84, 0x01, 0xEB, 0x06, 0xEB, 0x49, 0x84, 0x41, + 0x80, 0x62, 0x3C, 0x03, 0xF7, 0xEE, 0x84, 0x20, 0xEA, 0x5C, 0x84, 0x21, 0x84, 0x00, 0xEA, 0xB6, + 0x84, 0x01, 0x49, 0xFF, 0xFB, 0x9C, 0x84, 0x01, 0x80, 0x20, 0xEA, 0xE0, 0x84, 0x01, 0x49, 0xFF, + 0xFB, 0x75, 0x84, 0x01, 0xEA, 0xA6, 0x84, 0x00, 0x80, 0x20, 0x84, 0x41, 0xEA, 0x45, 0x49, 0xFF, + 0xEF, 0x9F, 0x84, 0x01, 0x49, 0xFF, 0xFF, 0x40, 0x44, 0x60, 0x08, 0x01, 0xEA, 0x39, 0xC0, 0x06, + 0x8E, 0xC1, 0x84, 0x01, 0x97, 0xB1, 0xDD, 0x51, 0xCE, 0xFA, 0xFC, 0x81, 0xFC, 0x05, 0x44, 0x02, + 0x17, 0x84, 0x84, 0x60, 0x84, 0x81, 0xB6, 0x1F, 0x44, 0x00, 0x00, 0x90, 0xF0, 0x88, 0xF4, 0x81, + 0xF3, 0x82, 0xF3, 0x83, 0xF4, 0x84, 0xF3, 0x85, 0xF3, 0x86, 0xF3, 0x87, 0xF3, 0x89, 0x84, 0x02, + 0x84, 0x25, 0x44, 0x26, 0x20, 0x08, 0x80, 0xA3, 0x49, 0xFF, 0xE9, 0x7B, 0xFC, 0x85, 0xFC, 0x05, + 0x49, 0xFF, 0xE9, 0x66, 0x44, 0x06, 0x20, 0x04, 0x84, 0x60, 0x44, 0x62, 0x11, 0x45, 0xB6, 0x1F, + 0x44, 0x10, 0x06, 0x3F, 0x84, 0x01, 0xF0, 0x81, 0xF0, 0x82, 0xF1, 0x88, 0x80, 0x46, 0x80, 0x80, + 0xF3, 0x83, 0xF3, 0x84, 0xF3, 0x85, 0xF3, 0x86, 0xF3, 0x87, 0xF3, 0x89, 0x84, 0x24, 0x80, 0xA3, + 0x49, 0xFF, 0xE9, 0x5F, 0x80, 0x46, 0x44, 0x00, 0x00, 0x79, 0x18, 0x01, 0x7F, 0xFF, 0x44, 0x0F, + 0xFF, 0x84, 0xAE, 0x12, 0x84, 0x19, 0xAE, 0x13, 0xFC, 0x85, 0xFC, 0x00, 0x84, 0x00, 0x3E, 0x00, + 0x00, 0x4D, 0x84, 0x01, 0x3E, 0x07, 0xF6, 0xD9, 0x84, 0x00, 0x3C, 0x0B, 0xFC, 0xBC, 0x49, 0xFF, + 0xFF, 0xD0, 0x84, 0x00, 0x49, 0xFF, 0xF3, 0xBD, 0x49, 0xFF, 0xFF, 0xB2, 0xFC, 0x80, 0xFC, 0x20, + 0x44, 0x36, 0x20, 0x04, 0x44, 0x72, 0x11, 0x44, 0x80, 0xC0, 0xA6, 0xB8, 0xB4, 0x23, 0x92, 0x28, + 0xEA, 0x67, 0xFE, 0x57, 0xB6, 0x23, 0x49, 0xFF, 0xFE, 0xFB, 0x38, 0x03, 0x98, 0x08, 0x9C, 0x31, + 0x96, 0x01, 0x49, 0xFF, 0xEC, 0x4B, 0x84, 0x01, 0xEA, 0x8F, 0xFC, 0xA0, 0xFC, 0x00, 0xDD, 0x54, + 0x84, 0x20, 0xEA, 0x2C, 0x84, 0x00, 0x3C, 0x0F, 0xFE, 0x57, 0x3C, 0x0D, 0xFE, 0x57, 0x5C, 0xF0, + 0x00, 0x64, 0xE8, 0x05, 0x3C, 0x0D, 0xFE, 0x57, 0x8C, 0x01, 0xD5, 0xF6, 0xDD, 0x54, 0x84, 0x21, + 0xEA, 0x2C, 0xFC, 0x80, 0xFC, 0x00, 0x2E, 0x07, 0xFF, 0xBC, 0x84, 0x21, 0x96, 0x00, 0x3E, 0x10, + 0x0F, 0x9A, 0x5A, 0x08, 0x04, 0x06, 0x2E, 0x00, 0x0F, 0x99, 0x48, 0x00, 0x00, 0x95, 0x5A, 0x08, + 0x20, 0x09, 0x44, 0x02, 0x0F, 0x20, 0x84, 0x20, 0x84, 0x4E, 0xEA, 0x30, 0x84, 0x0E, 0xEA, 0x34, + 0x5A, 0x08, 0x21, 0x29, 0x3C, 0x1D, 0xFD, 0xDB, 0x3E, 0x17, 0xF7, 0x4D, 0x40, 0x00, 0xA0, 0x09, + 0x3E, 0x07, 0xF7, 0x4E, 0x40, 0x00, 0xC0, 0x09, 0x3E, 0x07, 0xF7, 0x4F, 0x40, 0x00, 0xE0, 0x09, + 0x3C, 0x1D, 0x9E, 0x06, 0x3E, 0x07, 0xF7, 0x50, 0x40, 0x00, 0xA0, 0x09, 0x3E, 0x07, 0xF7, 0x52, + 0x40, 0x00, 0xC0, 0x09, 0x3E, 0x07, 0xF7, 0x53, 0x40, 0x00, 0xE0, 0x09, 0x3E, 0x17, 0xF7, 0x51, + 0x3E, 0x07, 0xF7, 0x54, 0x84, 0x20, 0x44, 0x02, 0x0F, 0x14, 0x84, 0x49, 0xEA, 0x30, 0x84, 0x09, + 0xEA, 0x34, 0x5A, 0x08, 0x22, 0x05, 0x44, 0x02, 0x0F, 0x10, 0xD5, 0x05, 0x5A, 0x08, 0x23, 0x09, + 0x44, 0x02, 0x0F, 0x0C, 0x84, 0x20, 0x84, 0x44, 0xEA, 0x30, 0x84, 0x04, 0xEA, 0x34, 0x5A, 0x08, + 0x24, 0x09, 0x44, 0x02, 0x0F, 0x04, 0x84, 0x20, 0x84, 0x45, 0xEA, 0x30, 0x84, 0x05, 0xEA, 0x34, + 0x5A, 0x08, 0x28, 0x09, 0x44, 0x02, 0x0E, 0xF0, 0x84, 0x20, 0xFA, 0x41, 0xEA, 0x30, 0xFA, 0x01, + 0xEA, 0x34, 0x5A, 0x08, 0x29, 0x09, 0x44, 0x02, 0x0E, 0xE8, 0x84, 0x20, 0x84, 0x46, 0xEA, 0x30, + 0x84, 0x06, 0xEA, 0x34, 0x5A, 0x08, 0x37, 0x09, 0x44, 0x02, 0x0E, 0xE4, 0x84, 0x20, 0x84, 0x42, + 0xEA, 0x30, 0x48, 0x00, 0x00, 0xF3, 0x5A, 0x08, 0x62, 0x13, 0xEA, 0x28, 0x96, 0x00, 0xC0, 0x0C, + 0xEA, 0x28, 0x97, 0x80, 0x5A, 0x68, 0x01, 0x04, 0x80, 0x06, 0xD5, 0x06, 0xEA, 0x28, 0x96, 0x00, + 0x5A, 0x00, 0x02, 0x03, 0xEB, 0x3E, 0x49, 0xFF, 0xEB, 0x71, 0xEA, 0xBF, 0x5A, 0x08, 0xD1, 0x0C, + 0x84, 0x61, 0xEA, 0x28, 0xFA, 0x2F, 0x2E, 0x27, 0xFF, 0xBE, 0x80, 0xA3, 0x2E, 0x47, 0xFF, 0xBF, + 0xDD, 0x46, 0xEA, 0xBF, 0x5A, 0x08, 0xD2, 0x0C, 0x44, 0x0F, 0xFF, 0xD2, 0xEA, 0xA3, 0xEA, 0x28, + 0x84, 0x41, 0x2E, 0x17, 0xFF, 0xBE, 0xEA, 0x45, 0x48, 0x00, 0x00, 0xC6, 0x5A, 0x08, 0xF3, 0x07, + 0x2E, 0x07, 0xF6, 0xD8, 0xEA, 0xA3, 0x84, 0x01, 0xEA, 0x34, 0x5A, 0x08, 0x0F, 0x1B, 0x2E, 0x17, + 0xFF, 0xBD, 0x96, 0x48, 0x5A, 0x18, 0x01, 0x0A, 0xEA, 0xA3, 0x3E, 0x17, 0xF9, 0x7D, 0xEA, 0x39, + 0x3E, 0x07, 0xF9, 0x7E, 0x84, 0x03, 0xEA, 0x34, 0xEA, 0x28, 0x5A, 0x00, 0x02, 0x03, 0xEB, 0x3E, + 0x2E, 0x07, 0xFF, 0xBF, 0x96, 0x00, 0x3E, 0x07, 0xF9, 0x65, 0x49, 0xFF, 0xFE, 0x3C, 0xEA, 0xBF, + 0x5A, 0x08, 0x61, 0x21, 0x2E, 0x17, 0xFF, 0xBD, 0x96, 0x48, 0xC9, 0x03, 0xDD, 0x54, 0xD5, 0x07, + 0xEA, 0x28, 0x97, 0x80, 0x5A, 0x68, 0x01, 0x06, 0xDD, 0x54, 0x80, 0x26, 0xEA, 0x2C, 0xEA, 0xBF, + 0xEA, 0x28, 0x5A, 0x00, 0x02, 0x03, 0xEB, 0x3E, 0x2E, 0x17, 0xFF, 0xBE, 0x84, 0x05, 0xFE, 0x0C, + 0xC8, 0x02, 0xDD, 0x57, 0x3C, 0x0B, 0xFC, 0xB1, 0xDD, 0x5C, 0xEA, 0x25, 0x84, 0x08, 0x48, 0x00, + 0x00, 0x7C, 0x5A, 0x00, 0xF1, 0x04, 0x48, 0x00, 0x00, 0x7A, 0x84, 0x00, 0x44, 0x32, 0x17, 0x84, + 0x44, 0x22, 0x11, 0x30, 0x38, 0x11, 0x80, 0x00, 0x96, 0x48, 0x38, 0x11, 0x00, 0x08, 0x8C, 0x01, + 0x5A, 0x08, 0x10, 0xFA, 0xEA, 0x28, 0x2E, 0x57, 0xFF, 0xBE, 0x96, 0x00, 0x96, 0x68, 0x40, 0x50, + 0x20, 0x08, 0x5A, 0x00, 0x10, 0x11, 0x5A, 0x00, 0x1D, 0x0F, 0x5A, 0x00, 0x08, 0x0D, 0x5A, 0x00, + 0x01, 0x0B, 0x9E, 0x84, 0xE6, 0x42, 0xE9, 0x07, 0x50, 0x00, 0x7F, 0xCE, 0xE6, 0x03, 0xE9, 0x03, + 0xFF, 0x4F, 0xD5, 0x02, 0x97, 0x69, 0x44, 0x00, 0x1D, 0x00, 0xD0, 0x43, 0x5C, 0xF2, 0x9D, 0x01, + 0xE8, 0x17, 0x44, 0x00, 0x04, 0x00, 0xD0, 0x35, 0x5C, 0xF2, 0x84, 0x01, 0xE8, 0x07, 0x5A, 0x59, + 0x00, 0x52, 0xDD, 0x5C, 0xEA, 0x25, 0x84, 0x01, 0xD5, 0x3F, 0x44, 0x00, 0x05, 0x00, 0xD0, 0x2D, + 0x44, 0x00, 0x08, 0x00, 0xD8, 0x47, 0xDD, 0x5C, 0xEA, 0x25, 0x84, 0x04, 0xD5, 0x35, 0x44, 0x00, + 0x32, 0x00, 0xD0, 0x2B, 0x5C, 0xF2, 0xB2, 0x01, 0xE8, 0x0B, 0x44, 0x00, 0x30, 0x00, 0xD8, 0x3A, + 0x44, 0x02, 0x0E, 0xBC, 0x84, 0x20, 0xFA, 0x58, 0xEA, 0x30, 0xFA, 0x18, 0xD5, 0x2F, 0x44, 0x00, + 0x33, 0x00, 0xD0, 0x1F, 0x44, 0x00, 0x3A, 0x00, 0xD8, 0x2D, 0x44, 0x02, 0x0E, 0xA4, 0x84, 0x20, + 0xFA, 0x48, 0xEA, 0x30, 0x49, 0xFF, 0xFC, 0xB1, 0x3E, 0x07, 0xF9, 0x8A, 0xFA, 0x08, 0xD5, 0x1E, + 0xDD, 0x5C, 0xEA, 0x25, 0x84, 0x02, 0xD5, 0x10, 0xDD, 0x5C, 0xEA, 0x25, 0x84, 0x03, 0xD5, 0x0C, + 0xDD, 0x5C, 0xEA, 0x25, 0x84, 0x05, 0xD5, 0x08, 0xDD, 0x5C, 0xEA, 0x25, 0x84, 0x06, 0xD5, 0x04, + 0xDD, 0x5C, 0xEA, 0x25, 0x84, 0x07, 0xEA, 0x3F, 0xD5, 0x0D, 0x5A, 0x08, 0xFD, 0x13, 0x84, 0x1D, + 0xEA, 0xA3, 0x84, 0x01, 0x3E, 0x07, 0xF9, 0x7D, 0x84, 0x02, 0x49, 0xFF, 0xFE, 0x72, 0x49, 0xFF, + 0xEA, 0xC9, 0x84, 0x01, 0x3E, 0x07, 0xF8, 0xFC, 0x84, 0x00, 0x3E, 0x07, 0xFF, 0xBC, 0xFC, 0x80, + 0x84, 0x00, 0xD5, 0xF9, 0x2E, 0x00, 0x00, 0x4C, 0xDD, 0x9E, 0xFC, 0x00, 0x49, 0xFF, 0xEA, 0xDC, + 0xFC, 0x80, 0xFC, 0x00, 0xEA, 0xC2, 0x84, 0x32, 0x3E, 0x17, 0xF9, 0x7C, 0x2E, 0x10, 0x0F, 0x98, + 0x44, 0x22, 0x11, 0x44, 0x5A, 0x18, 0x01, 0x08, 0x84, 0x34, 0x3E, 0x17, 0xF9, 0x7C, 0x84, 0x20, + 0x3E, 0x10, 0x0F, 0x98, 0x84, 0xA0, 0x44, 0x30, 0x05, 0x10, 0x80, 0x80, 0x2A, 0x10, 0x00, 0x01, + 0x9D, 0xA9, 0x90, 0x28, 0x96, 0x48, 0x38, 0x11, 0x18, 0x08, 0x8C, 0xA2, 0xA6, 0x60, 0x38, 0x11, + 0x14, 0x08, 0xDB, 0xF4, 0x44, 0x00, 0x05, 0x11, 0x49, 0xFF, 0xFE, 0x3B, 0xFC, 0x80, 0xFC, 0x00, + 0x2E, 0x07, 0xF6, 0xD8, 0x5A, 0x08, 0x52, 0x05, 0x44, 0x00, 0x00, 0x51, 0xEA, 0x25, 0x2E, 0x00, + 0x00, 0x4C, 0x5A, 0x08, 0x01, 0x07, 0x84, 0x00, 0xEA, 0x3F, 0x49, 0x00, 0x0A, 0x05, 0xFC, 0x80, + 0x5A, 0x08, 0x02, 0x07, 0x84, 0x00, 0xEA, 0x3F, 0x49, 0x00, 0x0C, 0x0B, 0xFC, 0x80, 0x9E, 0x43, + 0xE6, 0x22, 0xE8, 0x06, 0x84, 0x00, 0xEA, 0x3F, 0x49, 0x00, 0x0E, 0xF0, 0xFC, 0x80, 0x5A, 0x08, + 0x05, 0x07, 0x84, 0x00, 0xEA, 0x3F, 0x49, 0x00, 0x0F, 0xAA, 0xFC, 0x80, 0x9E, 0x46, 0xE6, 0x22, + 0xE8, 0x06, 0x84, 0x00, 0xEA, 0x3F, 0x49, 0x00, 0x12, 0x39, 0xFC, 0x80, 0x5A, 0x08, 0x08, 0x08, + 0x84, 0x00, 0xEA, 0x3F, 0x3C, 0x03, 0xFC, 0xB1, 0x49, 0x00, 0x14, 0x42, 0xFC, 0x80, 0xFC, 0x40, + 0x51, 0xFF, 0xFD, 0x10, 0x50, 0x9F, 0x80, 0x28, 0x84, 0x20, 0xFA, 0x50, 0x80, 0x09, 0xDD, 0x42, + 0x84, 0x20, 0x44, 0x20, 0x02, 0x88, 0xB0, 0x1A, 0xDD, 0x42, 0xB1, 0xD2, 0x44, 0x10, 0x7A, 0x20, + 0x80, 0x07, 0xEA, 0x88, 0xEA, 0x6C, 0xEA, 0xD6, 0xEA, 0xA0, 0x44, 0x00, 0x7A, 0x40, 0xB1, 0x83, + 0xEA, 0x97, 0xB0, 0x06, 0x84, 0x20, 0xEA, 0xA0, 0x84, 0x4C, 0x80, 0x06, 0xDD, 0x42, 0x84, 0x04, + 0x10, 0x0F, 0x80, 0x0C, 0xAE, 0x31, 0x84, 0x01, 0xAE, 0x32, 0xAE, 0x33, 0xAE, 0x34, 0xAE, 0x35, + 0xAE, 0x36, 0xAE, 0x37, 0x84, 0x00, 0xEA, 0x40, 0x84, 0x00, 0x38, 0x13, 0x00, 0x00, 0x96, 0x89, + 0xC2, 0x08, 0x5A, 0x20, 0x03, 0x07, 0x38, 0x24, 0x86, 0x02, 0xCA, 0x03, 0x38, 0x14, 0x86, 0x0A, + 0x8C, 0x01, 0x5A, 0x08, 0x0C, 0xF4, 0x46, 0x80, 0x03, 0x8E, 0x47, 0xC0, 0x04, 0x10, 0x85, 0x40, + 0x50, 0x84, 0x03, 0x8E, 0x51, 0xCE, 0x04, 0x10, 0x38, 0x04, 0xAA, 0x02, 0xC0, 0x3B, 0xB0, 0x06, + 0x84, 0x80, 0x38, 0x60, 0x29, 0x01, 0x92, 0xC2, 0x84, 0x00, 0x96, 0x41, 0xE2, 0x26, 0xE8, 0x12, + 0x38, 0x14, 0xAA, 0x02, 0x9E, 0x8C, 0xE6, 0x42, 0xE8, 0x05, 0xB0, 0x5A, 0x39, 0xC0, 0x82, 0x0A, + 0xD5, 0x07, 0x8E, 0x21, 0xE6, 0x22, 0xE8, 0x04, 0xB0, 0x5A, 0x38, 0x80, 0x82, 0x0A, 0x8C, 0x01, + 0xD5, 0xED, 0xCC, 0x0D, 0x38, 0x13, 0xAA, 0x01, 0xB6, 0x3F, 0xEA, 0x5F, 0xB4, 0x3F, 0xDD, 0x4C, + 0x88, 0x20, 0x96, 0x49, 0xB0, 0x1A, 0x80, 0x46, 0xEA, 0xA1, 0xD5, 0x12, 0x38, 0x13, 0xAA, 0x01, + 0xF4, 0x81, 0xB6, 0x3F, 0xEA, 0x5F, 0xB4, 0x3F, 0xDD, 0x4C, 0x50, 0x10, 0x82, 0x00, 0x88, 0x20, + 0x96, 0x49, 0xB0, 0x1A, 0x80, 0x46, 0xEA, 0xA1, 0xF4, 0x01, 0x5A, 0x40, 0x01, 0x04, 0x84, 0x81, + 0xD5, 0xCC, 0x8D, 0x41, 0x5A, 0xA8, 0x08, 0xC2, 0x84, 0x01, 0xEA, 0x40, 0x51, 0xFF, 0x82, 0xF0, + 0xFC, 0xC0, 0xFC, 0x00, 0x84, 0xC0, 0x3E, 0x67, 0xF9, 0x05, 0x49, 0xFF, 0xE9, 0x3B, 0x3E, 0x67, + 0xF9, 0x04, 0xFC, 0x80, 0xFC, 0x54, 0x84, 0x20, 0xEA, 0x49, 0xB0, 0x10, 0xDD, 0x42, 0x46, 0x00, + 0x0F, 0xC0, 0xEA, 0xDA, 0xF0, 0x93, 0x44, 0x03, 0x00, 0x30, 0xF0, 0x96, 0xEA, 0xDD, 0x50, 0x00, + 0x00, 0xC0, 0xF0, 0x97, 0x46, 0x00, 0x03, 0x00, 0x44, 0x70, 0x30, 0x03, 0x50, 0x00, 0x03, 0x00, + 0x44, 0x50, 0xC0, 0x0C, 0x44, 0x83, 0xF0, 0x3F, 0xF0, 0x98, 0x41, 0xC3, 0xA8, 0x08, 0x84, 0x20, + 0xFA, 0x48, 0xB0, 0x04, 0x84, 0xC1, 0x85, 0x42, 0x85, 0x23, 0xF5, 0x91, 0xF5, 0x95, 0xF5, 0x83, + 0xF7, 0x90, 0x14, 0x8F, 0x80, 0x12, 0xF7, 0x94, 0x15, 0xCF, 0x80, 0x19, 0xDD, 0x42, 0x84, 0x84, + 0x84, 0x65, 0x84, 0x20, 0xEA, 0x49, 0xB0, 0x1C, 0x10, 0x4F, 0x80, 0x18, 0x10, 0x3F, 0x80, 0x19, + 0x10, 0x4F, 0x80, 0x24, 0xF4, 0x82, 0x10, 0x3F, 0x80, 0x25, 0xF3, 0x81, 0x10, 0x6F, 0x80, 0x13, + 0x10, 0x6F, 0x80, 0x15, 0x10, 0xAF, 0x80, 0x16, 0x10, 0x9F, 0x80, 0x17, 0x10, 0x6F, 0x80, 0x1F, + 0x10, 0x6F, 0x80, 0x21, 0x10, 0xAF, 0x80, 0x22, 0x10, 0x9F, 0x80, 0x23, 0xDD, 0x42, 0x46, 0x00, + 0x0F, 0xC0, 0xEA, 0xDA, 0xF0, 0x9D, 0x44, 0x03, 0x00, 0x30, 0xF0, 0xA0, 0xEA, 0xDD, 0x50, 0x00, + 0x00, 0xC0, 0xF0, 0xA1, 0x46, 0x00, 0x03, 0x00, 0xF5, 0x03, 0x50, 0x00, 0x03, 0x00, 0xF0, 0xA2, + 0x84, 0x20, 0xB0, 0x0A, 0xFA, 0x48, 0x14, 0x8F, 0x80, 0x1C, 0xF7, 0x9E, 0xF5, 0x9F, 0x15, 0xCF, + 0x80, 0x23, 0xDD, 0x42, 0xF4, 0x02, 0xF3, 0x01, 0x10, 0x6F, 0x80, 0x29, 0x10, 0x6F, 0x80, 0x2B, + 0x10, 0xAF, 0x80, 0x2C, 0x10, 0x9F, 0x80, 0x2D, 0x10, 0x4F, 0x80, 0x2E, 0x10, 0x3F, 0x80, 0x2F, + 0x10, 0x6F, 0x80, 0x35, 0x10, 0x6F, 0x80, 0x37, 0x10, 0xAF, 0x80, 0x38, 0x10, 0x9F, 0x80, 0x39, + 0x10, 0x4F, 0x80, 0x3A, 0x10, 0x3F, 0x80, 0x3B, 0xDD, 0x44, 0x5A, 0x08, 0x01, 0x06, 0xB0, 0x04, + 0xDD, 0x5D, 0xB0, 0x10, 0xD5, 0x04, 0xB0, 0x0A, 0xDD, 0x5D, 0xB0, 0x1C, 0xEA, 0x47, 0xFC, 0xD4, + 0x50, 0x40, 0x61, 0xF3, 0x97, 0x21, 0x5C, 0xF2, 0x03, 0xE7, 0xCA, 0x17, 0xE9, 0x33, 0x5E, 0xF0, + 0x21, 0xF4, 0xE9, 0x0A, 0x5E, 0xF0, 0x3F, 0x06, 0xE9, 0x04, 0x84, 0x41, 0xAE, 0x98, 0x84, 0x41, + 0x50, 0x00, 0x61, 0xF4, 0xD5, 0x20, 0x5E, 0xF0, 0x00, 0xFB, 0xE8, 0x04, 0x84, 0x41, 0xAE, 0x98, + 0x84, 0x41, 0x50, 0x00, 0x5E, 0x0C, 0xD5, 0x17, 0xE9, 0x1C, 0x5E, 0xF0, 0x21, 0xF4, 0x84, 0x40, + 0xE9, 0x0A, 0x5E, 0xF0, 0x3F, 0x06, 0xE9, 0x04, 0x84, 0x41, 0xAE, 0x98, 0x84, 0x41, 0x52, 0x00, + 0x1E, 0x0C, 0xD5, 0x09, 0x5E, 0xF0, 0x00, 0xFB, 0xE8, 0x04, 0x84, 0x41, 0xAE, 0x98, 0x84, 0x41, + 0x52, 0x00, 0x21, 0xF4, 0x44, 0xF0, 0x03, 0xE8, 0x40, 0x00, 0x3C, 0x16, 0x96, 0x02, 0xD5, 0x03, + 0x84, 0x40, 0x80, 0x02, 0x54, 0x30, 0x80, 0x20, 0x96, 0x67, 0xC3, 0x02, 0xFE, 0x4A, 0x96, 0x4A, + 0x5A, 0x28, 0x01, 0x08, 0x84, 0x44, 0x40, 0x20, 0x08, 0x56, 0x88, 0x40, 0x98, 0x11, 0xD5, 0x02, + 0x88, 0x01, 0x96, 0x42, 0x5E, 0xF0, 0x80, 0x20, 0x80, 0x01, 0xE9, 0x02, 0xFA, 0x0F, 0x96, 0x42, + 0x4E, 0x14, 0x00, 0x03, 0x84, 0x00, 0x96, 0x00, 0xDD, 0x9E, 0xFC, 0x40, 0x51, 0xFF, 0xFC, 0xB0, + 0xFA, 0x50, 0xF1, 0x87, 0x81, 0x20, 0x84, 0x20, 0xB0, 0x1A, 0xDD, 0x42, 0x44, 0x00, 0x7A, 0x20, + 0xB0, 0x62, 0xEA, 0x79, 0xEA, 0x60, 0xEA, 0x97, 0x3A, 0x20, 0x94, 0x20, 0x50, 0xAF, 0x80, 0xA8, + 0x44, 0x10, 0x7A, 0x50, 0x80, 0x0A, 0xEA, 0x88, 0xEA, 0x6C, 0xEA, 0xD6, 0x44, 0x10, 0x7A, 0x40, + 0xEA, 0xA0, 0xB0, 0x16, 0xEA, 0xD6, 0x44, 0x10, 0x7A, 0x70, 0xEA, 0xA0, 0xB0, 0x0E, 0xB1, 0xD0, + 0x3A, 0x20, 0x8C, 0x00, 0x50, 0x8F, 0x80, 0x4C, 0x3A, 0x20, 0x0C, 0x20, 0x84, 0x20, 0x84, 0x4C, + 0x80, 0x07, 0xDD, 0x42, 0x84, 0xC1, 0x87, 0x84, 0x84, 0x20, 0x84, 0x4C, 0x80, 0x08, 0x11, 0xC3, + 0x80, 0x02, 0x11, 0xC3, 0x80, 0x03, 0xAF, 0xBC, 0xAF, 0xBD, 0xAF, 0xBE, 0xAF, 0xBF, 0x10, 0x63, + 0x80, 0x08, 0x10, 0x63, 0x80, 0x09, 0xDD, 0x42, 0x11, 0xCF, 0x80, 0x4C, 0x11, 0xC4, 0x00, 0x01, + 0x10, 0x64, 0x00, 0x02, 0x10, 0x64, 0x00, 0x03, 0x10, 0x64, 0x00, 0x04, 0x10, 0x64, 0x00, 0x05, + 0x10, 0x64, 0x00, 0x06, 0x10, 0x64, 0x00, 0x07, 0x49, 0xFF, 0xE8, 0x08, 0xF0, 0x85, 0x87, 0x80, + 0xDD, 0x44, 0x5A, 0x08, 0x01, 0x05, 0x38, 0x63, 0xF0, 0x00, 0xD5, 0x03, 0x38, 0x64, 0x70, 0x00, + 0xC6, 0x13, 0x5A, 0x60, 0x03, 0x12, 0xB0, 0x1A, 0x38, 0x00, 0x1A, 0x02, 0xC8, 0x0D, 0x38, 0x15, + 0x1A, 0x02, 0x94, 0x49, 0xB6, 0x3F, 0x49, 0xFF, 0xE7, 0x42, 0xEA, 0x99, 0xB4, 0x3F, 0x88, 0x01, + 0xB0, 0x5A, 0x38, 0x00, 0x9A, 0x0A, 0x51, 0xCE, 0x00, 0x01, 0x5B, 0xC8, 0x0C, 0xE3, 0x84, 0x46, + 0x42, 0x04, 0x88, 0x24, 0xF0, 0x83, 0xF1, 0x03, 0x44, 0x00, 0x00, 0x3F, 0x40, 0x10, 0x04, 0x0C, + 0xFE, 0x4B, 0xF1, 0x8A, 0x50, 0x14, 0x80, 0x02, 0xFE, 0x54, 0xEA, 0xFA, 0xFE, 0x03, 0xF1, 0x84, + 0xF0, 0x8B, 0x84, 0xC0, 0x50, 0xAF, 0x80, 0xC8, 0xB0, 0x1A, 0x38, 0x00, 0x1A, 0x02, 0xF0, 0x82, + 0xC8, 0x07, 0x8C, 0xC1, 0x5A, 0x68, 0x08, 0xFA, 0x51, 0xFF, 0x83, 0x50, 0xFC, 0xC0, 0xB0, 0x0E, + 0x84, 0xE0, 0x38, 0x00, 0x18, 0x00, 0x50, 0x8F, 0x80, 0x88, 0xB6, 0x1F, 0x94, 0x01, 0xF0, 0x81, + 0x02, 0x0F, 0x80, 0x02, 0xF0, 0x86, 0xF0, 0x01, 0xE0, 0xE0, 0xE8, 0xEC, 0xCF, 0x0D, 0xEB, 0x28, + 0xEA, 0x5F, 0xDD, 0x4C, 0x40, 0x14, 0x80, 0x00, 0xB0, 0x16, 0x96, 0x49, 0xEA, 0xD2, 0x80, 0x0A, + 0x92, 0x42, 0x49, 0xFF, 0xE2, 0xF6, 0xB4, 0x1F, 0x4C, 0x70, 0x40, 0x0F, 0xEB, 0x28, 0xEA, 0x5F, + 0xDD, 0x4C, 0x50, 0x14, 0x82, 0x00, 0x88, 0x20, 0xB0, 0x16, 0x96, 0x49, 0xEA, 0xD2, 0x80, 0x0A, + 0x92, 0x42, 0x49, 0xFF, 0xE2, 0xE6, 0xFA, 0x0B, 0x40, 0x93, 0x80, 0x13, 0x42, 0x14, 0x80, 0x24, + 0xF1, 0x88, 0xF1, 0x01, 0x84, 0x80, 0x8A, 0x27, 0x8E, 0x21, 0xFE, 0x0C, 0x96, 0x01, 0xF0, 0x89, + 0xB4, 0x1F, 0xE2, 0xE0, 0x40, 0x02, 0x04, 0x09, 0xE8, 0x03, 0xF1, 0x08, 0xD5, 0x02, 0xF1, 0x09, + 0x88, 0x01, 0x41, 0xC0, 0x00, 0x13, 0xF0, 0x0A, 0x38, 0x15, 0x72, 0x02, 0xF2, 0x05, 0x40, 0x50, + 0x80, 0x02, 0xF0, 0x03, 0xF3, 0x07, 0x40, 0x10, 0x80, 0x0D, 0xF0, 0x02, 0x96, 0x6F, 0xF4, 0x8D, + 0x38, 0x00, 0x25, 0x11, 0xF5, 0x8C, 0x49, 0xFF, 0xFE, 0xC5, 0xF1, 0x03, 0xF5, 0x0C, 0xEA, 0xFA, + 0xFF, 0x47, 0xF0, 0x06, 0xF2, 0x05, 0x88, 0x09, 0x40, 0x90, 0x00, 0x13, 0xF0, 0x0B, 0xF3, 0x07, + 0xFE, 0x2E, 0xF0, 0x8C, 0xF0, 0x04, 0x38, 0x55, 0x72, 0x0A, 0x40, 0x12, 0x80, 0x0D, 0xF0, 0x02, + 0x96, 0x6F, 0x38, 0x00, 0x25, 0x11, 0x49, 0xFF, 0xFE, 0xAD, 0xF1, 0x04, 0xF4, 0x0D, 0xEA, 0xFA, + 0xF1, 0x0C, 0x8C, 0x82, 0xFE, 0x0F, 0x38, 0x05, 0x72, 0x0A, 0xF0, 0x06, 0x97, 0x20, 0x88, 0x09, + 0x40, 0x90, 0x00, 0x13, 0x5A, 0x48, 0x36, 0xBE, 0xB4, 0x1F, 0x50, 0x93, 0x80, 0x01, 0x4C, 0x90, + 0x40, 0x0E, 0x39, 0xC4, 0x1A, 0x01, 0xEA, 0x5F, 0xDD, 0x4C, 0x40, 0x1E, 0x00, 0x00, 0xB0, 0x16, + 0x96, 0x49, 0xEA, 0xD2, 0x80, 0x0A, 0x92, 0x42, 0xEA, 0xA1, 0xF0, 0x01, 0x4C, 0x90, 0x40, 0x0E, + 0xEB, 0x28, 0xEA, 0x5F, 0xDD, 0x4C, 0x50, 0x14, 0x82, 0x00, 0x88, 0x20, 0xB0, 0x16, 0x96, 0x49, + 0xEA, 0xD2, 0x80, 0x0A, 0x92, 0x42, 0xEA, 0xA1, 0x8C, 0xE1, 0x97, 0xF8, 0x48, 0xFF, 0xFF, 0x6D, + 0xFC, 0x05, 0x84, 0x20, 0xB0, 0x04, 0xFA, 0x48, 0xDD, 0x42, 0x84, 0x25, 0x84, 0x01, 0x10, 0x1F, + 0x80, 0x17, 0x10, 0x1F, 0x80, 0x23, 0xB1, 0x81, 0x44, 0x10, 0x7A, 0x78, 0x10, 0x0F, 0x80, 0x11, + 0x10, 0x0F, 0x80, 0x13, 0x10, 0x0F, 0x80, 0x1D, 0x10, 0x0F, 0x80, 0x1F, 0x84, 0x63, 0x84, 0x44, + 0x80, 0x06, 0x10, 0x3F, 0x80, 0x15, 0x10, 0x2F, 0x80, 0x16, 0x10, 0x3F, 0x80, 0x21, 0x10, 0x2F, + 0x80, 0x22, 0x84, 0x82, 0x3A, 0x20, 0x8C, 0x04, 0x3A, 0x20, 0x0C, 0x24, 0x10, 0x4F, 0x80, 0x14, + 0x10, 0x4F, 0x80, 0x20, 0xA4, 0x48, 0xAC, 0x40, 0xB0, 0x04, 0xDD, 0x5D, 0x80, 0x06, 0x49, 0xFF, + 0xEB, 0x07, 0xFC, 0x85, 0xFC, 0x06, 0x84, 0x20, 0x80, 0x1F, 0xEA, 0x49, 0xDD, 0x42, 0x44, 0x03, + 0xF0, 0x3F, 0x94, 0x46, 0xF0, 0x82, 0xF0, 0x84, 0xF0, 0x86, 0xF0, 0x88, 0x80, 0x1F, 0xF1, 0x83, + 0xF1, 0x85, 0xF1, 0x87, 0xF1, 0x89, 0xEA, 0x47, 0xFC, 0x86, 0xFC, 0x09, 0x84, 0x20, 0xB0, 0x06, + 0xEA, 0x49, 0xDD, 0x42, 0xEB, 0x18, 0xEA, 0xB2, 0xF0, 0x86, 0xEB, 0x20, 0xF1, 0x89, 0xF0, 0x87, + 0xEA, 0xA5, 0xEA, 0xC7, 0xF1, 0x8A, 0x94, 0x46, 0xF1, 0x8B, 0xDD, 0x4F, 0xF0, 0x88, 0xF1, 0x8C, + 0xB1, 0x81, 0xDD, 0x47, 0x44, 0x10, 0x7A, 0x84, 0xF0, 0x8D, 0x80, 0x06, 0xEA, 0x88, 0xEA, 0x6C, + 0xB4, 0x21, 0xB6, 0x20, 0xB0, 0x06, 0xEA, 0x47, 0x80, 0x06, 0x49, 0xFF, 0xEA, 0x95, 0xFC, 0x89, + 0xFC, 0x02, 0x44, 0x10, 0x7A, 0x98, 0x80, 0x1F, 0xEA, 0xD6, 0x3A, 0x2F, 0x94, 0x20, 0x49, 0xFF, + 0xEA, 0x95, 0xFC, 0x82, 0xFC, 0x00, 0x80, 0xC0, 0xDD, 0x44, 0xC8, 0x16, 0xDD, 0x57, 0xCE, 0x08, + 0xEB, 0x34, 0x44, 0x00, 0x16, 0x15, 0xEB, 0x38, 0x44, 0x00, 0x11, 0xC2, 0xD5, 0x07, 0xEB, 0x34, + 0x44, 0x00, 0x29, 0xA4, 0xEB, 0x38, 0x44, 0x00, 0x25, 0x51, 0x49, 0xFF, 0xE2, 0x50, 0x44, 0x00, + 0x01, 0xCC, 0x49, 0xFF, 0xE2, 0x55, 0xFC, 0x80, 0xFC, 0x00, 0xC8, 0x03, 0x84, 0x07, 0xD5, 0x04, + 0x5A, 0x08, 0x05, 0x04, 0x84, 0x01, 0xEA, 0x4B, 0xFC, 0x80, 0xFC, 0x00, 0xC0, 0x05, 0x8E, 0x05, + 0x5C, 0x00, 0x00, 0x01, 0xD5, 0x02, 0x84, 0x07, 0x8C, 0x01, 0xEA, 0x90, 0xFC, 0x80, 0xFC, 0x00, + 0x80, 0xC0, 0xC0, 0x04, 0x5A, 0x00, 0x01, 0x0A, 0xFC, 0x80, 0x49, 0xFF, 0xF6, 0x30, 0xDD, 0x5B, + 0x49, 0xFF, 0xFF, 0xCA, 0x80, 0x06, 0xD5, 0x11, 0x49, 0xFF, 0xF6, 0x29, 0xDD, 0x57, 0xEB, 0x34, + 0x44, 0x00, 0x29, 0x3F, 0xEB, 0x38, 0x44, 0x00, 0x24, 0xEC, 0x49, 0xFF, 0xE2, 0x20, 0x44, 0x00, + 0x01, 0xCC, 0x49, 0xFF, 0xE2, 0x25, 0x84, 0x00, 0xEB, 0x01, 0xFC, 0x80, 0xFC, 0x00, 0x84, 0x00, + 0xEB, 0x13, 0x84, 0x01, 0xEA, 0x4C, 0x84, 0x00, 0xEB, 0x48, 0xFC, 0x80, 0xFC, 0x00, 0x84, 0x01, + 0xEB, 0x13, 0x84, 0x00, 0xEA, 0x4C, 0x84, 0x00, 0xEB, 0x48, 0xFC, 0x80, 0xFC, 0x00, 0x84, 0x00, + 0xEB, 0x13, 0x84, 0x00, 0xEA, 0x4C, 0x84, 0x00, 0xEB, 0x48, 0xFC, 0x80, 0xFC, 0x00, 0x5A, 0x00, + 0x02, 0x09, 0x5A, 0x00, 0x03, 0x0A, 0x5A, 0x08, 0x01, 0x0A, 0x49, 0xFF, 0xFF, 0xE1, 0xFC, 0x80, + 0x49, 0xFF, 0xFF, 0xE6, 0xFC, 0x80, 0x49, 0xFF, 0xFF, 0xEB, 0xFC, 0x80, 0xFC, 0x00, 0x49, 0xFF, + 0xE5, 0x8E, 0x80, 0x60, 0x3E, 0x00, 0x0F, 0x84, 0x44, 0x12, 0x18, 0x1C, 0x44, 0x02, 0x1F, 0xB4, + 0x44, 0x20, 0x02, 0x88, 0x2E, 0x40, 0x00, 0x50, 0x49, 0xFF, 0xF7, 0x8F, 0xFC, 0x80, 0x44, 0x02, + 0x1F, 0xB4, 0xDD, 0x9E, 0x44, 0x02, 0x18, 0x1C, 0xDD, 0x9E, 0xFC, 0x20, 0xC8, 0x08, 0x84, 0x01, + 0xEA, 0xCD, 0x84, 0x01, 0xEA, 0x75, 0x84, 0xC2, 0x84, 0xE1, 0xD5, 0x0A, 0x84, 0x00, 0xEA, 0xCD, + 0x84, 0x03, 0xEA, 0x75, 0x84, 0x03, 0x49, 0xFF, 0xE2, 0x1C, 0x84, 0xC1, 0x84, 0xE0, 0x80, 0x07, + 0x49, 0xFF, 0xE1, 0xF6, 0x5A, 0x78, 0x01, 0x09, 0x9E, 0x32, 0x96, 0x00, 0x49, 0xFF, 0xE1, 0xFA, + 0x80, 0x06, 0x49, 0xFF, 0xE2, 0x01, 0xFC, 0xA0, 0xFC, 0x00, 0x84, 0x00, 0x80, 0x20, 0xEA, 0xC1, + 0x84, 0x00, 0x84, 0x21, 0xEA, 0xC1, 0xFC, 0x80, 0xFC, 0x00, 0x84, 0x01, 0x84, 0x20, 0xEA, 0xC1, + 0x84, 0x01, 0x80, 0x20, 0xEA, 0xC1, 0xFC, 0x80, 0x2E, 0x27, 0xEF, 0xF3, 0x42, 0x11, 0x00, 0x73, + 0x96, 0x49, 0x5C, 0xF0, 0x81, 0x45, 0xE9, 0x04, 0x52, 0x10, 0x83, 0xCD, 0x96, 0x49, 0x84, 0x60, + 0x44, 0x42, 0x07, 0xC8, 0x84, 0x40, 0x98, 0x13, 0x96, 0x01, 0x38, 0x52, 0x01, 0x01, 0xD1, 0x0A, + 0x8C, 0x41, 0x96, 0x91, 0x5A, 0x28, 0x12, 0xF9, 0x8C, 0x72, 0x96, 0xD9, 0x5A, 0x3A, 0x88, 0xF4, + 0xEA, 0x9B, 0xDD, 0x9E, 0xFC, 0x22, 0x80, 0xC0, 0xC8, 0x04, 0xB0, 0x01, 0x80, 0x26, 0xD5, 0x2E, + 0x5A, 0x08, 0x02, 0x08, 0xB0, 0x01, 0x84, 0x20, 0x84, 0x4C, 0xDD, 0x42, 0x84, 0x04, 0xD5, 0x29, + 0x5A, 0x08, 0x04, 0x21, 0xDD, 0x44, 0x80, 0xE0, 0x84, 0x20, 0xB0, 0x01, 0x84, 0x4C, 0x5A, 0x78, + 0x01, 0x14, 0xDD, 0x42, 0x10, 0x6F, 0x80, 0x06, 0x10, 0x6F, 0x80, 0x07, 0x10, 0x7F, 0x80, 0x08, + 0x10, 0x7F, 0x80, 0x09, 0x10, 0x7F, 0x80, 0x0A, 0x10, 0x7F, 0x80, 0x0B, 0x10, 0x7F, 0x80, 0x0C, + 0x10, 0x7F, 0x80, 0x0D, 0xD5, 0x35, 0xDD, 0x42, 0x10, 0x6F, 0x80, 0x04, 0x10, 0x6F, 0x80, 0x05, + 0xD5, 0x0C, 0x5A, 0x08, 0x06, 0x18, 0xB0, 0x01, 0x84, 0x20, 0x84, 0x4C, 0xDD, 0x42, 0x84, 0x03, + 0x10, 0x0F, 0x80, 0x04, 0x10, 0x0F, 0x80, 0x05, 0x84, 0x01, 0x10, 0x0F, 0x80, 0x06, 0xEA, 0x63, + 0x10, 0x0F, 0x80, 0x08, 0x10, 0x0F, 0x80, 0x09, 0x10, 0x0F, 0x80, 0x0A, 0x10, 0x0F, 0x80, 0x0B, + 0xD5, 0x17, 0x5A, 0x08, 0x05, 0x0C, 0xB0, 0x01, 0x84, 0x20, 0x84, 0x4C, 0xDD, 0x42, 0x84, 0x04, + 0x10, 0x0F, 0x80, 0x04, 0x10, 0x0F, 0x80, 0x05, 0xD5, 0x0B, 0x5A, 0x08, 0x07, 0x0D, 0xB0, 0x01, + 0x84, 0x20, 0x84, 0x4C, 0xDD, 0x42, 0x84, 0x01, 0x10, 0x0F, 0x80, 0x06, 0xEA, 0x63, 0xB0, 0x01, + 0x49, 0xFF, 0xE0, 0xFC, 0xFC, 0xA2, 0xDD, 0x9E, 0xDD, 0x5B, 0xDD, 0x9E, 0x2E, 0x00, 0x00, 0x50, + 0xDD, 0x9E, 0x2E, 0x00, 0x00, 0x4F, 0xDD, 0x9E, 0xFC, 0x00, 0x80, 0xC0, 0x49, 0xFF, 0xE0, 0x71, + 0x5A, 0x68, 0x01, 0x0B, 0x80, 0x06, 0x84, 0x20, 0xDD, 0x5F, 0x80, 0x06, 0x84, 0x22, 0xDD, 0x5F, + 0x80, 0x06, 0x80, 0x26, 0xD5, 0x0C, 0x84, 0x02, 0x84, 0x2A, 0xEB, 0x1F, 0x84, 0x01, 0x84, 0x20, + 0xDD, 0x5F, 0x84, 0x01, 0x80, 0x20, 0xDD, 0x5F, 0x84, 0x00, 0x84, 0x22, 0xDD, 0x5F, 0xFC, 0x80, + 0xFC, 0x21, 0x84, 0xC2, 0xF0, 0x81, 0x80, 0xE2, 0x80, 0x01, 0x5A, 0x10, 0x01, 0x03, 0x84, 0xC1, + 0xEA, 0x96, 0xCF, 0x0B, 0x84, 0x03, 0xEA, 0x9D, 0x84, 0x03, 0x49, 0xFF, 0xE7, 0x44, 0xF0, 0x01, + 0x80, 0x26, 0x49, 0xFF, 0xF6, 0x1F, 0xFC, 0xA1, 0x84, 0x02, 0xEA, 0x9D, 0xF0, 0x01, 0x80, 0x26, + 0x84, 0x40, 0x84, 0x62, 0x49, 0xFF, 0xF5, 0xA3, 0xFC, 0xA1, 0xFC, 0x00, 0x84, 0x07, 0xEA, 0x4B, + 0x84, 0x00, 0x84, 0x20, 0x3E, 0x00, 0x00, 0x50, 0x3E, 0x00, 0x00, 0x4F, 0x80, 0x41, 0xDD, 0x5B, + 0xEA, 0xD5, 0xFC, 0x80, 0xFC, 0x21, 0xF0, 0x81, 0x80, 0xE2, 0x80, 0x01, 0x80, 0xC3, 0xEA, 0x96, + 0x5A, 0x78, 0x01, 0x12, 0x5A, 0x68, 0x02, 0x08, 0x80, 0x06, 0xEA, 0x9D, 0xF0, 0x01, 0x84, 0x20, + 0x80, 0x47, 0xD5, 0x06, 0x84, 0x02, 0xEA, 0x9D, 0xF0, 0x01, 0x80, 0x27, 0x84, 0x40, 0x80, 0x66, + 0x49, 0xFF, 0xF5, 0x7D, 0xFC, 0xA1, 0xFC, 0x00, 0x84, 0x00, 0x49, 0xFF, 0xE5, 0x16, 0xFA, 0xC2, + 0x49, 0xFF, 0xEE, 0x73, 0x49, 0xFF, 0xEB, 0x37, 0xC0, 0x06, 0x8E, 0xC1, 0xC6, 0x04, 0x84, 0x01, + 0xEA, 0x3C, 0xD5, 0xF9, 0x49, 0xFF, 0xEE, 0x69, 0x84, 0x01, 0x49, 0xFF, 0xE5, 0x06, 0xFC, 0x80, + 0xFC, 0x01, 0xF0, 0x81, 0x49, 0x00, 0x10, 0xDE, 0xF0, 0x01, 0x49, 0xFF, 0xE0, 0xCE, 0xFC, 0x81, + 0xFC, 0x01, 0x5A, 0x08, 0x01, 0x08, 0xF0, 0x81, 0x49, 0xFF, 0xFB, 0xAD, 0xF0, 0x01, 0xEA, 0x65, + 0xFC, 0x81, 0x84, 0x00, 0xEA, 0x65, 0x84, 0x01, 0xDD, 0x51, 0x49, 0xFF, 0xFF, 0xD6, 0x49, 0xFF, + 0xFB, 0xA2, 0xFC, 0x81, 0xFC, 0x00, 0x84, 0x01, 0xDD, 0x48, 0xEA, 0x20, 0x84, 0x00, 0x3E, 0x07, + 0xF9, 0x05, 0xEA, 0x84, 0x2E, 0x07, 0xF9, 0x05, 0xC8, 0x04, 0xEA, 0x5D, 0x5A, 0x08, 0x01, 0xFC, + 0xEA, 0x69, 0xC8, 0x04, 0xEA, 0x5D, 0x5A, 0x08, 0x01, 0xFD, 0xDD, 0x5A, 0xFC, 0x80, 0xFC, 0x01, + 0x84, 0x00, 0xEA, 0x63, 0x84, 0x00, 0xEA, 0x40, 0x84, 0x00, 0xEA, 0xEC, 0x84, 0x20, 0x80, 0x61, + 0x84, 0x41, 0xDD, 0x5B, 0xEB, 0x08, 0x49, 0xFF, 0xFF, 0xDF, 0x50, 0x1F, 0x80, 0x07, 0x84, 0x00, + 0x49, 0xFF, 0xFC, 0x65, 0xDD, 0x5A, 0x84, 0x00, 0xDD, 0x48, 0x84, 0x01, 0xEA, 0xEC, 0x84, 0x20, + 0x80, 0x41, 0x84, 0x61, 0xDD, 0x5B, 0xEB, 0x08, 0x49, 0xFF, 0xFF, 0xCE, 0x50, 0x1F, 0x80, 0x07, + 0x84, 0x01, 0x49, 0xFF, 0xFC, 0x54, 0xDD, 0x5A, 0x84, 0x00, 0xDD, 0x48, 0x84, 0x01, 0xEA, 0x40, + 0xEA, 0xD3, 0xFC, 0x81, 0xFC, 0x49, 0x84, 0x20, 0x84, 0x41, 0x84, 0x62, 0xDD, 0x5B, 0xEB, 0x08, + 0x84, 0x04, 0xEA, 0x4A, 0x84, 0x00, 0x49, 0xFF, 0xFB, 0x5F, 0xDD, 0x44, 0x5A, 0x08, 0x01, 0x11, + 0x46, 0x00, 0x00, 0x80, 0x04, 0x00, 0x00, 0x70, 0x54, 0x90, 0x00, 0x0F, 0xDD, 0x56, 0x04, 0x60, + 0x00, 0x12, 0x84, 0x09, 0xEA, 0x4B, 0x84, 0x0A, 0x97, 0x9F, 0xEA, 0x90, 0xD5, 0x03, 0x84, 0xC0, + 0x81, 0x26, 0x49, 0xFF, 0xFA, 0xB6, 0x84, 0xE6, 0x49, 0xFF, 0xFF, 0xB3, 0x5A, 0x08, 0x01, 0x05, + 0x8E, 0xE1, 0x97, 0xF8, 0xCF, 0xFA, 0xDD, 0x44, 0x5A, 0x08, 0x01, 0x06, 0x80, 0x09, 0xEA, 0x4B, + 0x80, 0x06, 0xEA, 0x90, 0x84, 0x00, 0xEA, 0x4A, 0xB0, 0x06, 0x84, 0x20, 0xEA, 0x49, 0xDD, 0x42, + 0xEB, 0x18, 0xEA, 0xB2, 0xF0, 0x86, 0xEB, 0x20, 0xF1, 0x89, 0xF0, 0x87, 0xEA, 0xA5, 0xEA, 0xC7, + 0xF1, 0x8A, 0x94, 0x46, 0xF0, 0x88, 0xF1, 0x8B, 0xDD, 0x4F, 0xDD, 0x47, 0xF1, 0x8C, 0xF0, 0x8D, + 0x84, 0x20, 0x80, 0x1F, 0xFA, 0x48, 0xDD, 0x42, 0x84, 0x01, 0x84, 0x82, 0x84, 0x63, 0x84, 0x44, + 0x84, 0x25, 0x10, 0x0F, 0x80, 0x01, 0x10, 0x0F, 0x80, 0x03, 0x10, 0x0F, 0x80, 0x0D, 0x10, 0x0F, + 0x80, 0x0F, 0x80, 0x1F, 0x10, 0x4F, 0x80, 0x04, 0x10, 0x3F, 0x80, 0x05, 0x10, 0x2F, 0x80, 0x06, + 0x10, 0x1F, 0x80, 0x07, 0x10, 0x4F, 0x80, 0x10, 0x10, 0x3F, 0x80, 0x11, 0x10, 0x2F, 0x80, 0x12, + 0x10, 0x1F, 0x80, 0x13, 0xDD, 0x5D, 0xB0, 0x06, 0xEA, 0x47, 0xFC, 0xC9, 0xFC, 0x00, 0xDD, 0x5B, + 0xEA, 0xF7, 0x84, 0x07, 0xEA, 0x4B, 0xDD, 0x5B, 0x84, 0x20, 0x2E, 0x20, 0x00, 0x4F, 0xEA, 0xD5, + 0x2E, 0x10, 0x00, 0x50, 0x2E, 0x20, 0x00, 0x4F, 0xDD, 0x5B, 0xEA, 0xD5, 0xDD, 0x5B, 0xEA, 0xF7, + 0x49, 0xFF, 0xFD, 0xBE, 0xEA, 0x20, 0x84, 0x01, 0xDD, 0x48, 0xFC, 0x80, 0xFC, 0x00, 0xEA, 0x4E, + 0xFC, 0x80, 0xFC, 0x00, 0x80, 0xC0, 0x3E, 0x00, 0x00, 0x51, 0x49, 0xFF, 0xFD, 0xF0, 0x80, 0x06, + 0x49, 0xFF, 0xFD, 0x62, 0xFC, 0x80, 0xFC, 0x01, 0x84, 0x00, 0xEA, 0x4A, 0x84, 0x01, 0x49, 0xFF, + 0xDF, 0xA1, 0x84, 0x00, 0x49, 0xFF, 0xE3, 0xE4, 0x84, 0x00, 0x49, 0xFF, 0xE3, 0xB7, 0x84, 0x00, + 0x49, 0xFF, 0xE3, 0xC4, 0x49, 0xFF, 0xFC, 0xDE, 0xEA, 0xDE, 0x49, 0xFF, 0xFD, 0x43, 0x44, 0x02, + 0x86, 0x80, 0x49, 0xFF, 0xEC, 0x94, 0x44, 0x02, 0x8D, 0x40, 0x49, 0xFF, 0xEC, 0x9A, 0x44, 0x02, + 0x79, 0x00, 0x49, 0xFF, 0xEC, 0xBB, 0x44, 0x02, 0x7F, 0xC0, 0x49, 0xFF, 0xEC, 0xC1, 0x84, 0x00, + 0x49, 0xFF, 0xEC, 0x99, 0xEA, 0x83, 0x49, 0xFF, 0xEC, 0x9F, 0xEA, 0x83, 0xEB, 0x35, 0x84, 0x00, + 0x49, 0xFF, 0xEC, 0xC0, 0xEA, 0x83, 0x49, 0xFF, 0xEC, 0xC8, 0x84, 0x06, 0x49, 0xFF, 0xEC, 0xD0, + 0x84, 0x02, 0x49, 0xFF, 0xEC, 0xD6, 0x84, 0x04, 0x49, 0xFF, 0xF1, 0x74, 0xEA, 0x27, 0x84, 0x00, + 0xDD, 0x4B, 0xEA, 0x56, 0xDD, 0x58, 0xF0, 0x81, 0xF1, 0x01, 0x84, 0x00, 0xEA, 0x4E, 0xEA, 0x27, + 0x84, 0x02, 0xDD, 0x4B, 0xEA, 0x56, 0xDD, 0x58, 0xF0, 0x81, 0xF1, 0x01, 0x84, 0x02, 0xEA, 0x4E, + 0xEA, 0x27, 0x84, 0x04, 0xDD, 0x4B, 0xEA, 0x56, 0xDD, 0x58, 0xF0, 0x81, 0xF1, 0x01, 0x84, 0x04, + 0xEA, 0x4E, 0x2E, 0x17, 0xEF, 0xAC, 0x2E, 0x27, 0xEF, 0xAD, 0x2E, 0x37, 0xEF, 0xAE, 0x2E, 0x47, + 0xEF, 0xAF, 0x3C, 0x03, 0xF7, 0xBF, 0x49, 0xFF, 0xDE, 0x57, 0x44, 0x00, 0x01, 0x02, 0x49, 0xFF, + 0xE8, 0xF5, 0x84, 0x00, 0xEB, 0x1A, 0x84, 0x00, 0xEA, 0xE2, 0x49, 0xFF, 0xE8, 0xDF, 0x3E, 0x00, + 0x00, 0x51, 0x84, 0x01, 0x49, 0xFF, 0xDF, 0xC9, 0xEA, 0x71, 0xE6, 0x05, 0xE9, 0x0D, 0x44, 0x14, + 0x00, 0xD4, 0xB4, 0x01, 0x58, 0x00, 0x00, 0x03, 0xB6, 0x01, 0x44, 0x14, 0x00, 0xD8, 0x84, 0x1E, + 0xB4, 0x41, 0xFE, 0x16, 0xB6, 0x01, 0xFC, 0x81, 0x46, 0x00, 0x00, 0x82, 0x44, 0x1F, 0xF8, 0xFF, + 0xA0, 0x85, 0xFE, 0x56, 0x58, 0x10, 0x84, 0x00, 0xA8, 0x45, 0xA0, 0x42, 0x46, 0x20, 0x10, 0x00, + 0xFE, 0x57, 0xA8, 0x42, 0xA0, 0xC2, 0x46, 0x1F, 0xDF, 0xFF, 0xDD, 0x4A, 0xFE, 0x5E, 0xA8, 0x42, + 0x04, 0x30, 0x00, 0x2A, 0x44, 0x1F, 0xFE, 0xFF, 0xFE, 0x5E, 0x14, 0x10, 0x00, 0x2A, 0xB4, 0x20, + 0xFE, 0x8F, 0xB6, 0x40, 0xB4, 0x20, 0x92, 0x38, 0x96, 0x46, 0xC9, 0xFD, 0xFC, 0x00, 0xEA, 0x64, + 0x46, 0x0B, 0xFF, 0xFF, 0xB4, 0x41, 0xDD, 0x41, 0xFE, 0x16, 0xB6, 0x01, 0xB4, 0x41, 0x46, 0x08, + 0x00, 0x00, 0xFE, 0x17, 0x84, 0x41, 0xB6, 0x01, 0x80, 0x62, 0xDD, 0x59, 0xEA, 0x23, 0xDD, 0x40, + 0x44, 0x04, 0x2C, 0x04, 0x84, 0x3E, 0xB4, 0x40, 0xFE, 0x56, 0xB6, 0x20, 0xB4, 0x20, 0x84, 0x41, + 0x58, 0x10, 0x80, 0x02, 0xB6, 0x20, 0x80, 0x62, 0x44, 0x04, 0x28, 0x04, 0x44, 0x14, 0x24, 0x04, + 0xDD, 0x40, 0xFC, 0x80, 0xFC, 0x40, 0x84, 0xC0, 0x45, 0xC2, 0x07, 0xC8, 0xFB, 0x34, 0xFB, 0x42, + 0x84, 0x80, 0x87, 0xDE, 0x99, 0xE6, 0x97, 0xF9, 0x38, 0x3E, 0x1D, 0x01, 0x5C, 0xF1, 0x81, 0x45, + 0x8E, 0x61, 0xE9, 0x0A, 0x40, 0x51, 0xA4, 0x76, 0x52, 0x31, 0x80, 0x23, 0x80, 0xA4, 0x42, 0x51, + 0xA8, 0x73, 0x80, 0x65, 0xD5, 0x06, 0x40, 0x31, 0xA4, 0xB6, 0x80, 0x64, 0x42, 0x32, 0xA8, 0x73, + 0x96, 0xD9, 0x94, 0xD9, 0x40, 0x80, 0x0C, 0x00, 0x88, 0x61, 0x22, 0xF4, 0x00, 0x00, 0x22, 0x51, + 0x80, 0x00, 0x40, 0x57, 0x94, 0x01, 0x4E, 0x54, 0x00, 0x03, 0xFF, 0x6A, 0x81, 0xE2, 0x42, 0xF3, + 0xF8, 0x73, 0x50, 0x77, 0x85, 0x0E, 0x22, 0xF3, 0x80, 0x00, 0x40, 0xF7, 0x94, 0x07, 0xE8, 0x02, + 0xAD, 0x78, 0x22, 0xF4, 0x00, 0x00, 0x5E, 0xF7, 0xBF, 0xC1, 0xE8, 0x06, 0x22, 0xF1, 0x80, 0x00, + 0x5E, 0xF7, 0xBF, 0xC1, 0xE9, 0x04, 0x44, 0x30, 0x20, 0x00, 0xAC, 0xF8, 0x8C, 0x81, 0x97, 0x21, + 0x5A, 0x48, 0x12, 0xC2, 0x8C, 0xD2, 0x97, 0xB1, 0x5A, 0x6A, 0x88, 0xBC, 0xFC, 0xC0, 0xFC, 0x00, + 0x84, 0xC0, 0x3E, 0x67, 0xF9, 0x05, 0x49, 0xFF, 0xE2, 0xF5, 0x3E, 0x67, 0xF9, 0x04, 0xEA, 0x69, + 0xC0, 0x04, 0x84, 0x00, 0xEA, 0x84, 0xFC, 0x80, 0xEA, 0x5D, 0x5A, 0x00, 0x01, 0xFC, 0xEA, 0x4F, + 0xEA, 0x2E, 0xC0, 0xF6, 0xD5, 0xF7, 0xFC, 0x00, 0x84, 0x01, 0x44, 0x10, 0x00, 0xB3, 0x80, 0x40, + 0xEA, 0x45, 0x3E, 0x00, 0x0F, 0x8F, 0x44, 0x10, 0x00, 0xBD, 0x84, 0x0E, 0x84, 0x41, 0xEA, 0x45, + 0x3E, 0x00, 0x0F, 0x8E, 0xFC, 0x80, 0xFC, 0x20, 0xDD, 0x56, 0x44, 0x54, 0x2C, 0x00, 0x83, 0x80, + 0xBF, 0x29, 0xB9, 0x29, 0xBE, 0x29, 0x84, 0x41, 0xB4, 0x85, 0x92, 0x32, 0x92, 0xD3, 0xB4, 0x65, + 0xFE, 0x56, 0xFF, 0x96, 0x40, 0x10, 0x88, 0x0C, 0x95, 0xB2, 0x92, 0xF0, 0x92, 0x86, 0xFF, 0xD6, + 0xFF, 0x16, 0xFE, 0x77, 0x92, 0x67, 0xFE, 0xD6, 0xFE, 0x7F, 0x95, 0x23, 0xFE, 0x67, 0x94, 0xDC, + 0xFE, 0x5F, 0x3E, 0x10, 0x0F, 0x8C, 0xBB, 0x29, 0xEA, 0x6B, 0xFE, 0x5F, 0xB9, 0xA9, 0xBB, 0x29, + 0xEA, 0xDB, 0xFE, 0x5F, 0xB9, 0xA9, 0xBB, 0x29, 0xEA, 0x62, 0xFE, 0x5F, 0xB9, 0xA9, 0xB4, 0x05, + 0xEA, 0x23, 0x58, 0x00, 0x00, 0x40, 0xB6, 0x05, 0xB4, 0x05, 0x80, 0x62, 0x58, 0x00, 0x00, 0x80, + 0xB6, 0x05, 0xDD, 0x59, 0xDD, 0x40, 0xFC, 0xA0, 0xFC, 0x00, 0x2E, 0x00, 0x0F, 0x8C, 0x46, 0x40, + 0x00, 0x81, 0x84, 0x41, 0x83, 0x84, 0xBD, 0x29, 0x40, 0x10, 0x08, 0x02, 0x40, 0x30, 0xC0, 0x08, + 0xEA, 0xBB, 0xFE, 0x6E, 0xFE, 0x5F, 0xB9, 0xA9, 0x40, 0x10, 0x08, 0x0D, 0xBD, 0x29, 0xFE, 0x56, + 0x40, 0x30, 0xC8, 0x08, 0x44, 0x1B, 0xFF, 0xFF, 0xFE, 0x6E, 0xFE, 0x5F, 0xB9, 0xA9, 0x40, 0x10, + 0x08, 0x09, 0xFE, 0x56, 0xBD, 0x29, 0x40, 0x30, 0xCC, 0x08, 0x46, 0x1F, 0xFF, 0x7F, 0xDD, 0x4A, + 0xFE, 0x6E, 0xFE, 0x5F, 0xB9, 0xA9, 0x44, 0x44, 0x2C, 0x00, 0x40, 0x10, 0x0C, 0x09, 0xB4, 0xA4, + 0xFE, 0x56, 0x94, 0xCE, 0x44, 0x1F, 0xFF, 0xBF, 0xFE, 0x6E, 0xFE, 0x5F, 0xB6, 0x24, 0x92, 0x04, + 0xB4, 0x64, 0xFE, 0x16, 0x94, 0x47, 0x44, 0x0F, 0xFF, 0x7F, 0xFE, 0x1E, 0xFE, 0x0F, 0xB6, 0x04, + 0xEA, 0x23, 0xDD, 0x59, 0x80, 0x62, 0xDD, 0x40, 0xFC, 0x80, 0xFC, 0x01, 0xDD, 0x53, 0x3E, 0x00, + 0x10, 0xBC, 0xEA, 0xC2, 0x3C, 0x0E, 0x04, 0x2C, 0x2E, 0x07, 0xF9, 0x6E, 0x96, 0x06, 0xEB, 0x05, + 0x2E, 0x07, 0xF9, 0x6F, 0x3E, 0x00, 0x10, 0xBD, 0xEA, 0xF1, 0x96, 0x1F, 0x3E, 0x00, 0x10, 0xD0, + 0xEA, 0xF1, 0x54, 0x00, 0x00, 0x30, 0x90, 0x04, 0x3E, 0x00, 0x10, 0xC0, 0x2E, 0x07, 0xF9, 0x71, + 0x96, 0x1F, 0x3E, 0x00, 0x10, 0xC2, 0x2E, 0x07, 0xF9, 0x71, 0x92, 0x04, 0x3E, 0x00, 0x10, 0xC3, + 0xEB, 0x30, 0xEB, 0x40, 0xDD, 0x4C, 0xFE, 0x0F, 0xEA, 0x95, 0x84, 0x00, 0x3E, 0x00, 0x10, 0xC4, + 0x3E, 0x00, 0x10, 0xC5, 0x84, 0x1F, 0x3E, 0x00, 0x10, 0xC8, 0x3E, 0x00, 0x10, 0xC9, 0x3E, 0x00, + 0x10, 0xCA, 0x3E, 0x00, 0x10, 0xCB, 0x3E, 0x00, 0x10, 0xCC, 0x3E, 0x00, 0x10, 0xCD, 0x3E, 0x00, + 0x10, 0xCE, 0x49, 0xFF, 0xFB, 0xF6, 0x3C, 0x0E, 0x04, 0x2B, 0x84, 0x00, 0x3C, 0x0E, 0x04, 0x29, + 0x2E, 0x07, 0xF9, 0x72, 0x3E, 0x00, 0x10, 0xC6, 0x2E, 0x07, 0xF9, 0x73, 0x3E, 0x00, 0x10, 0xC7, + 0xEA, 0xF1, 0x2E, 0x10, 0x10, 0xC2, 0x92, 0x06, 0xEB, 0x09, 0x5A, 0x10, 0x0F, 0x06, 0x5A, 0x08, + 0x03, 0x04, 0x84, 0x01, 0xEB, 0x09, 0x2E, 0x10, 0x10, 0xBC, 0x5A, 0x10, 0x1D, 0x04, 0x5A, 0x18, + 0x32, 0x0E, 0x84, 0x01, 0xEB, 0x05, 0x2E, 0x07, 0xF9, 0x6E, 0x96, 0x00, 0x3E, 0x00, 0x10, 0xCF, + 0x5A, 0x08, 0xFF, 0x03, 0xFA, 0x18, 0x3C, 0x0E, 0x04, 0x29, 0x5A, 0x18, 0x04, 0x27, 0x84, 0x01, + 0xEB, 0x05, 0xEB, 0x30, 0xEB, 0x40, 0xDD, 0x4C, 0xFE, 0x0F, 0x2E, 0x17, 0xF9, 0x6D, 0x2E, 0x27, + 0xF9, 0x6E, 0xEA, 0x67, 0xFE, 0x57, 0xE2, 0x20, 0x3C, 0x08, 0x08, 0x5B, 0x40, 0x00, 0xBC, 0x1A, + 0xEA, 0x95, 0x2E, 0x07, 0xF9, 0x74, 0x3C, 0x18, 0x08, 0x5C, 0x96, 0x1F, 0xEA, 0x76, 0x2E, 0x07, + 0xF9, 0x75, 0x96, 0x06, 0x3E, 0x00, 0x0F, 0x8D, 0x2E, 0x07, 0xF9, 0x75, 0x54, 0x00, 0x00, 0x0E, + 0x90, 0x01, 0x3E, 0x07, 0xF7, 0x68, 0xD5, 0x0A, 0xEB, 0x30, 0xEB, 0x40, 0xDD, 0x4C, 0xFE, 0x0F, + 0xEA, 0x95, 0x2E, 0x07, 0xF9, 0x6D, 0x96, 0x1F, 0xEA, 0x76, 0xEA, 0x21, 0xC8, 0x11, 0xEB, 0x1E, + 0xEA, 0x36, 0xD8, 0x03, 0x84, 0x1F, 0xD5, 0x0A, 0x80, 0x05, 0x2E, 0x60, 0x10, 0xBB, 0xDD, 0x58, + 0xF0, 0x81, 0xF1, 0x01, 0x80, 0x06, 0x49, 0xFF, 0xF3, 0xBF, 0xEA, 0x76, 0xD5, 0x03, 0x5A, 0x00, + 0x0F, 0xF3, 0xEA, 0x21, 0xE6, 0x02, 0xE8, 0x08, 0x84, 0x01, 0x3E, 0x00, 0x0F, 0x98, 0x84, 0x1F, + 0xEA, 0x76, 0x84, 0x1F, 0xEA, 0x95, 0xFC, 0x81, 0xFC, 0x00, 0xDD, 0x54, 0x84, 0x21, 0xEA, 0x2C, + 0x84, 0x20, 0xDD, 0x54, 0xEA, 0x2C, 0x84, 0x01, 0xEA, 0x3C, 0xDD, 0x54, 0x84, 0x21, 0xEA, 0x2C, + 0x44, 0x00, 0x00, 0x51, 0xEA, 0x25, 0xFC, 0x80, 0xFC, 0x41, 0xB6, 0x1F, 0x80, 0xC1, 0xF2, 0x81, + 0x81, 0x04, 0x81, 0x45, 0x00, 0x9F, 0x80, 0x28, 0x00, 0x7F, 0x80, 0x2C, 0x5A, 0x30, 0xFF, 0x05, + 0x80, 0x02, 0x84, 0x20, 0xEA, 0x38, 0x5A, 0x88, 0x0F, 0x04, 0x5A, 0xA0, 0x01, 0x06, 0x84, 0x00, + 0xEA, 0x46, 0x84, 0x00, 0xEA, 0x96, 0x5A, 0x98, 0x0F, 0x04, 0x5A, 0x70, 0x0F, 0x03, 0xEB, 0x3A, + 0xEA, 0x36, 0x4C, 0x60, 0x00, 0x0B, 0x80, 0x26, 0xB4, 0x1F, 0xDD, 0x4B, 0x80, 0x06, 0xDD, 0x58, + 0xF0, 0x81, 0xF1, 0x01, 0xB4, 0x1F, 0xEA, 0x29, 0x84, 0x03, 0xEB, 0x09, 0xEA, 0x31, 0x84, 0x01, + 0x80, 0x60, 0x80, 0xA0, 0xFA, 0x2F, 0xEA, 0x68, 0xEA, 0x81, 0xDD, 0x46, 0x84, 0x61, 0x84, 0x0E, + 0xFA, 0x2F, 0xEA, 0x7B, 0xEA, 0x7F, 0x80, 0xA3, 0xDD, 0x46, 0xFC, 0xC1, 0xFC, 0x42, 0x80, 0xC1, + 0xF2, 0x81, 0x80, 0xE0, 0x80, 0x23, 0x83, 0x84, 0x00, 0x2F, 0x80, 0x30, 0x00, 0x8F, 0x80, 0x34, + 0x00, 0xAF, 0x80, 0x38, 0x00, 0x9F, 0x80, 0x3C, 0x5A, 0x30, 0xFF, 0x06, 0xF0, 0x01, 0xF2, 0x82, + 0xEA, 0x38, 0xF2, 0x02, 0x5A, 0x28, 0x01, 0x07, 0x5B, 0xC0, 0x0F, 0x05, 0x80, 0x1C, 0x49, 0xFF, + 0xE7, 0x79, 0x5A, 0x80, 0x0F, 0x04, 0x80, 0x08, 0xEA, 0x61, 0x5A, 0xA0, 0x0F, 0x05, 0x80, 0x0A, + 0x49, 0xFF, 0xDD, 0xC7, 0x3C, 0x10, 0x08, 0x5A, 0x5A, 0x90, 0x01, 0x05, 0xEA, 0x36, 0x4C, 0x10, + 0x00, 0x3B, 0xEA, 0x36, 0x4C, 0x10, 0x00, 0x17, 0x80, 0x07, 0xDD, 0x4B, 0x3C, 0x00, 0x08, 0x5A, + 0xDD, 0x58, 0xF0, 0x81, 0xF1, 0x01, 0x80, 0x07, 0xEA, 0x29, 0xCF, 0x0C, 0x3C, 0x10, 0x08, 0x5A, + 0x84, 0x02, 0xDD, 0x4B, 0x3C, 0x00, 0x08, 0x5A, 0xDD, 0x58, 0xF0, 0x81, 0xF1, 0x01, 0x84, 0x02, + 0xEA, 0x29, 0x5A, 0x60, 0xFF, 0x10, 0xE6, 0xD5, 0xE9, 0x02, 0xFA, 0xC3, 0x44, 0xA2, 0x0D, 0x20, + 0x80, 0x07, 0x38, 0x15, 0x19, 0x01, 0xEA, 0x29, 0xCF, 0x05, 0x84, 0x02, 0x38, 0x15, 0x19, 0x01, + 0xEA, 0x29, 0x5A, 0x98, 0x01, 0x11, 0xEA, 0x20, 0xEB, 0x47, 0xEA, 0x78, 0xF0, 0x81, 0x49, 0xFF, + 0xFB, 0x8F, 0xF0, 0x82, 0x49, 0xFF, 0xFB, 0x8F, 0xF0, 0x83, 0xF1, 0x02, 0xF0, 0x01, 0xF2, 0x03, + 0xEA, 0xD5, 0xDD, 0x5A, 0xFC, 0xC2, 0xFC, 0x01, 0x80, 0xC0, 0xF1, 0x81, 0xEA, 0x78, 0x5A, 0x08, + 0x01, 0x07, 0x2E, 0x07, 0xF5, 0x38, 0x44, 0x12, 0x0D, 0x00, 0xD5, 0x05, 0x2E, 0x07, 0xF5, 0x94, + 0x44, 0x12, 0x0D, 0x5C, 0x00, 0x20, 0x80, 0x09, 0x9E, 0xF1, 0xE0, 0x43, 0xE8, 0x03, 0x9D, 0x91, + 0xD5, 0x04, 0xE0, 0x06, 0xE9, 0x03, 0x9D, 0x81, 0x97, 0xB0, 0x80, 0x41, 0x84, 0x00, 0x08, 0x51, + 0x00, 0x01, 0x8C, 0xA1, 0xDE, 0x04, 0xF1, 0x01, 0xEA, 0x24, 0xFC, 0x81, 0x9C, 0x41, 0x96, 0x08, + 0x5A, 0x08, 0x0A, 0xF7, 0xFC, 0x81, 0xFC, 0x00, 0xEA, 0x21, 0x5A, 0x00, 0x0F, 0x0B, 0xDD, 0x56, + 0x83, 0x80, 0xB9, 0x22, 0xB8, 0x23, 0x3C, 0x0E, 0x03, 0xE4, 0x3C, 0x1E, 0x03, 0xE5, 0xFC, 0x80, + 0xEA, 0x51, 0x5A, 0x00, 0x06, 0xF6, 0xEA, 0x51, 0x5A, 0x00, 0x05, 0xF3, 0xFC, 0x80, 0xEB, 0x0C, + 0xEA, 0xCC, 0xEA, 0xCA, 0xD0, 0x0E, 0xFC, 0x01, 0x44, 0x52, 0x28, 0x96, 0xB6, 0xBF, 0x9E, 0x2E, + 0x9E, 0x6D, 0x9E, 0xAC, 0x9E, 0xEB, 0x9F, 0x2A, 0x8E, 0xA1, 0x49, 0xFF, 0xE7, 0x45, 0xFC, 0x81, + 0xDD, 0x9E, 0xFC, 0x03, 0xF0, 0x85, 0xEA, 0x21, 0x5A, 0x00, 0xFF, 0x09, 0x84, 0x20, 0xEA, 0x91, + 0xEA, 0x21, 0x84, 0x23, 0xEA, 0x91, 0xEA, 0x21, 0xD5, 0x0B, 0xEA, 0x51, 0x5A, 0x08, 0x06, 0x0C, + 0x84, 0x03, 0x84, 0x20, 0xEA, 0x91, 0x84, 0x03, 0x80, 0x20, 0xEA, 0x91, 0x84, 0x03, 0x84, 0x22, + 0xEA, 0x91, 0xD5, 0x04, 0xEA, 0x51, 0x5A, 0x00, 0x05, 0xF5, 0xEB, 0x0C, 0xEA, 0xCC, 0xEA, 0xCA, + 0xD0, 0x0B, 0x84, 0x41, 0x2E, 0x00, 0x10, 0xC6, 0x2E, 0x10, 0x10, 0xC7, 0xB6, 0x5F, 0x84, 0x65, + 0x84, 0x80, 0x80, 0xA2, 0xEB, 0x24, 0x2E, 0x07, 0xF7, 0x69, 0x5A, 0x00, 0x03, 0x2C, 0xEA, 0x31, + 0x2E, 0x67, 0xF7, 0x69, 0x5A, 0x68, 0x01, 0x13, 0xEA, 0x81, 0x80, 0x06, 0xEA, 0xC8, 0xFA, 0x2F, + 0xEA, 0x68, 0x80, 0x66, 0x58, 0x42, 0x00, 0x08, 0x80, 0xA6, 0xDD, 0x46, 0xEA, 0x7F, 0x84, 0x0E, + 0xFA, 0x2F, 0xEA, 0x7B, 0x80, 0x66, 0x97, 0x0F, 0xD5, 0x13, 0xCE, 0x14, 0xEA, 0x81, 0x84, 0x01, + 0xEA, 0xC8, 0x80, 0x60, 0xFA, 0x2F, 0xEA, 0x68, 0x58, 0x42, 0x00, 0x04, 0x80, 0xA0, 0xDD, 0x46, + 0xEA, 0x7F, 0x84, 0x0E, 0xFA, 0x2F, 0xEA, 0x7B, 0x84, 0x61, 0x58, 0x42, 0x00, 0xFC, 0x80, 0xA3, + 0xDD, 0x46, 0xDD, 0x4D, 0xF1, 0x05, 0xB6, 0x1F, 0xEA, 0x5E, 0xEA, 0x72, 0xF0, 0x81, 0xEA, 0x80, + 0xEA, 0x8E, 0xF0, 0x82, 0x84, 0x00, 0xF0, 0x83, 0x80, 0x40, 0x80, 0xA0, 0x49, 0xFF, 0xFE, 0xE8, + 0xDD, 0x4D, 0x84, 0x42, 0xB6, 0x1F, 0xEA, 0x5E, 0xEA, 0x72, 0xF0, 0x81, 0xEA, 0x80, 0xEA, 0x8E, + 0xF0, 0x82, 0x2E, 0x00, 0x10, 0xBB, 0xF1, 0x05, 0xF0, 0x83, 0x80, 0xA2, 0x84, 0x04, 0x49, 0xFF, + 0xFE, 0xD7, 0xFC, 0x83, 0xFC, 0x01, 0xEA, 0x21, 0x5A, 0x00, 0x0F, 0x0B, 0x3C, 0x1C, 0x03, 0xE4, + 0xDD, 0x56, 0x3C, 0x2C, 0x03, 0xE5, 0x83, 0x80, 0xBA, 0xA2, 0xB9, 0xA3, 0xD5, 0x07, 0xEA, 0x51, + 0x5A, 0x00, 0x06, 0xF6, 0xEA, 0x51, 0x5A, 0x00, 0x05, 0xF3, 0xEB, 0x0C, 0xEA, 0xCC, 0xEA, 0xCA, + 0xD0, 0x11, 0x2E, 0x60, 0x10, 0xCE, 0x2E, 0x00, 0x10, 0xC8, 0x2E, 0x10, 0x10, 0xC9, 0x2E, 0x20, + 0x10, 0xCA, 0x2E, 0x30, 0x10, 0xCB, 0x2E, 0x40, 0x10, 0xCC, 0x2E, 0x50, 0x10, 0xCD, 0xB6, 0xDF, + 0xEB, 0x24, 0xEA, 0x5E, 0x3C, 0x13, 0xF7, 0xF2, 0xB6, 0x1F, 0xEA, 0x80, 0xEA, 0x72, 0xF0, 0x81, + 0x84, 0x00, 0x80, 0x40, 0xEA, 0x8E, 0xEB, 0x27, 0xEB, 0x29, 0xEA, 0x5E, 0x3C, 0x13, 0xF7, 0xF4, + 0xB6, 0x1F, 0xEA, 0x80, 0xEA, 0x72, 0xF0, 0x81, 0xEA, 0x8E, 0xEB, 0x27, 0x84, 0x04, 0x84, 0x42, + 0xEB, 0x29, 0xFC, 0x81, 0xFC, 0x43, 0x84, 0x00, 0xF0, 0x84, 0xF0, 0x85, 0x10, 0x0F, 0x80, 0x0D, + 0x2E, 0x67, 0xF9, 0x6E, 0xEA, 0x7E, 0xEA, 0x6D, 0xDD, 0x4D, 0x97, 0xB0, 0xC8, 0x02, 0xEB, 0x21, + 0xEA, 0x22, 0x96, 0x06, 0xC0, 0x03, 0x84, 0x01, 0xEA, 0x26, 0xEA, 0xAE, 0xEA, 0x94, 0xEA, 0xBA, + 0xDD, 0x4D, 0x5A, 0x08, 0x02, 0x0F, 0x84, 0x00, 0xEA, 0x61, 0xB0, 0x04, 0xB0, 0x45, 0x50, 0x2F, + 0x80, 0x0D, 0x49, 0xFF, 0xE7, 0x18, 0x54, 0x03, 0x00, 0x70, 0x92, 0x04, 0x49, 0xFF, 0xE6, 0x22, + 0xEA, 0xC9, 0xEA, 0xB4, 0xEA, 0xC5, 0x84, 0x00, 0x12, 0x0F, 0x80, 0x07, 0x84, 0xE0, 0x84, 0xC0, + 0x2E, 0x17, 0xEF, 0xF3, 0xEA, 0x83, 0x40, 0x00, 0x04, 0x16, 0x90, 0x01, 0xE0, 0xC0, 0xE8, 0x5E, + 0x54, 0xA3, 0x00, 0xFF, 0x40, 0x05, 0x1C, 0x00, 0x54, 0x90, 0x00, 0xFF, 0x85, 0x00, 0x2E, 0x07, + 0xEF, 0xF3, 0x92, 0x01, 0xE3, 0x00, 0xE8, 0x4F, 0x55, 0xC4, 0x00, 0xFF, 0xB0, 0x03, 0x50, 0x2F, + 0x80, 0x0E, 0x50, 0x3F, 0x80, 0x09, 0x50, 0x4F, 0x80, 0x0A, 0xB6, 0x1F, 0x80, 0x3C, 0x80, 0x0A, + 0x50, 0x5F, 0x80, 0x0B, 0x49, 0xFF, 0xE7, 0x0E, 0x40, 0x1E, 0x04, 0x08, 0x8C, 0x21, 0x96, 0x48, + 0x80, 0x09, 0x49, 0xFF, 0xF9, 0xA3, 0x00, 0x2F, 0x80, 0x0A, 0x00, 0x1F, 0x80, 0x09, 0x54, 0x31, + 0x00, 0x20, 0x54, 0x40, 0x80, 0x20, 0x96, 0xA7, 0x94, 0xDA, 0xFE, 0xD7, 0x95, 0x22, 0x54, 0x20, + 0x80, 0x1F, 0x40, 0x12, 0x08, 0x04, 0xEB, 0x2C, 0xEA, 0x67, 0xFE, 0x5F, 0xEB, 0x42, 0x8D, 0x01, + 0x2E, 0x07, 0xEF, 0xF3, 0x40, 0x14, 0x04, 0x08, 0xE0, 0x01, 0xE9, 0x1A, 0x54, 0x10, 0x80, 0xFE, + 0x80, 0x09, 0x49, 0xFF, 0xF9, 0x83, 0x00, 0x2F, 0x80, 0x0C, 0x00, 0x1F, 0x80, 0x0B, 0x54, 0x31, + 0x00, 0x20, 0x54, 0x40, 0x80, 0x20, 0x96, 0xA7, 0x94, 0xDA, 0xFE, 0xD7, 0x95, 0x22, 0x54, 0x20, + 0x80, 0x1F, 0x40, 0x12, 0x08, 0x04, 0xEB, 0x2C, 0xEA, 0x67, 0xFE, 0x5F, 0xEB, 0x42, 0x40, 0x84, + 0x00, 0x13, 0xD5, 0xAE, 0x8C, 0xC1, 0x97, 0xB1, 0xD5, 0x9C, 0x8C, 0xE6, 0x44, 0x00, 0x02, 0x00, + 0x97, 0xF8, 0x12, 0x0F, 0x80, 0x07, 0x5A, 0x78, 0x0C, 0x94, 0xEA, 0xA9, 0xEA, 0xB1, 0xEA, 0x22, + 0x96, 0x06, 0xC0, 0x03, 0x84, 0x00, 0xEA, 0x26, 0xDD, 0x4D, 0x5A, 0x08, 0x02, 0x0A, 0x84, 0x03, + 0xEA, 0x61, 0xB0, 0x04, 0xB0, 0x45, 0x50, 0x2F, 0x80, 0x0D, 0x49, 0xFF, 0xE6, 0x55, 0xEA, 0xA4, + 0xDD, 0x4D, 0xC8, 0x02, 0xEA, 0xE5, 0xEA, 0x8B, 0xEA, 0x59, 0xFC, 0xC3, 0xFC, 0x48, 0xFD, 0x30, + 0x00, 0x0F, 0x80, 0x60, 0xF3, 0x81, 0xF4, 0x83, 0x81, 0x05, 0xF2, 0x82, 0xF0, 0x84, 0x49, 0xFF, + 0xF9, 0x08, 0x83, 0x80, 0xF2, 0x02, 0xFD, 0x03, 0x49, 0xFF, 0xE9, 0x0E, 0x84, 0x02, 0xF1, 0x02, + 0xDD, 0x4B, 0xEA, 0x20, 0xEA, 0x8C, 0xDD, 0x5A, 0x80, 0x1C, 0xF1, 0x03, 0x84, 0x40, 0x49, 0xFF, + 0xF0, 0xC3, 0xF1, 0x01, 0xFA, 0x02, 0xFE, 0x44, 0xF1, 0x85, 0xFE, 0x44, 0xF1, 0x86, 0xF1, 0x01, + 0xF0, 0x83, 0x8E, 0x21, 0xFE, 0x44, 0xFE, 0x44, 0xDD, 0x56, 0x50, 0x00, 0x01, 0x2C, 0xF0, 0x8B, + 0xF0, 0x01, 0xF1, 0x87, 0x5C, 0x00, 0x00, 0x02, 0x84, 0x20, 0xF1, 0x82, 0xF0, 0x8C, 0xF1, 0x03, + 0xF0, 0x02, 0x02, 0x9F, 0x80, 0x04, 0x40, 0x00, 0x04, 0xF6, 0x84, 0x03, 0x40, 0x14, 0x80, 0x17, + 0x54, 0xA0, 0x00, 0xFF, 0xF0, 0x04, 0xC8, 0x2E, 0xF0, 0x05, 0x94, 0x79, 0x88, 0xE0, 0x95, 0xF9, + 0x88, 0x3C, 0x88, 0xE8, 0xF0, 0x04, 0x5C, 0x94, 0x80, 0x09, 0x4E, 0x92, 0x00, 0x05, 0x4E, 0xA2, + 0x00, 0x05, 0xD5, 0x08, 0x5A, 0xA8, 0x02, 0x07, 0xE6, 0x12, 0xE8, 0x0E, 0xEA, 0xC0, 0xAC, 0xB8, + 0xD5, 0x0B, 0x5A, 0xA0, 0x01, 0x04, 0x48, 0x00, 0x00, 0xAF, 0xE6, 0x09, 0x4E, 0xF2, 0x00, 0xA4, + 0xEA, 0xC0, 0x12, 0x23, 0x81, 0x44, 0x8C, 0x01, 0x96, 0x00, 0x50, 0x10, 0x80, 0x24, 0x50, 0x73, + 0x80, 0x48, 0x5A, 0x08, 0x1B, 0xE4, 0xF0, 0x02, 0x8C, 0x01, 0xF0, 0x82, 0x5A, 0x08, 0x12, 0xC9, + 0xFC, 0xC8, 0xF0, 0x04, 0x5A, 0x08, 0x01, 0x2D, 0xF0, 0x06, 0x94, 0x79, 0x98, 0xB8, 0xF0, 0x07, + 0x94, 0x91, 0x88, 0xE0, 0x95, 0xF9, 0x40, 0x3E, 0x04, 0x00, 0x88, 0x48, 0x88, 0x28, 0x88, 0xE8, + 0x84, 0x00, 0xE7, 0x29, 0xE8, 0x04, 0x4E, 0xA2, 0x00, 0x05, 0xD5, 0x09, 0x5A, 0xA8, 0x02, 0x08, + 0xF4, 0x0C, 0xC4, 0x11, 0xEB, 0x1C, 0x38, 0x41, 0x00, 0x09, 0xD5, 0x0D, 0x5A, 0xA0, 0x01, 0x04, + 0x48, 0x00, 0x00, 0x8A, 0xF4, 0x01, 0x4E, 0x43, 0x00, 0x7F, 0x38, 0x51, 0x80, 0x11, 0x99, 0x08, + 0x12, 0x52, 0x01, 0x44, 0x50, 0x00, 0x00, 0x24, 0x5A, 0x0A, 0x88, 0xE6, 0xD5, 0xCD, 0xF0, 0x04, + 0x5A, 0x08, 0x02, 0xCB, 0xDD, 0x56, 0x50, 0x00, 0x01, 0x34, 0x94, 0xF9, 0xB4, 0x00, 0x40, 0x5E, + 0x0C, 0x00, 0xDD, 0x47, 0x92, 0x0A, 0xF0, 0x88, 0xF0, 0x0B, 0x88, 0x68, 0x84, 0x80, 0xB4, 0x00, + 0xF0, 0x89, 0xE7, 0x29, 0x14, 0xFF, 0x80, 0x0A, 0x80, 0x44, 0xF0, 0x09, 0xF1, 0x08, 0xF3, 0x8F, + 0xF5, 0x8E, 0x97, 0xA0, 0xF4, 0x8D, 0x49, 0x00, 0x10, 0x42, 0x96, 0x06, 0xF4, 0x0D, 0xF5, 0x0E, + 0xF3, 0x0F, 0xC0, 0x38, 0xF0, 0x0A, 0xC0, 0x04, 0x4E, 0xA2, 0x00, 0x05, 0xD5, 0x1C, 0x5A, 0xA8, + 0x02, 0x1B, 0xEA, 0xE8, 0xE8, 0x2F, 0x5A, 0x90, 0x03, 0x04, 0x5A, 0x98, 0x0E, 0x0F, 0xE6, 0xCC, + 0xE8, 0x04, 0x52, 0x63, 0x00, 0x0B, 0xD5, 0x08, 0xE6, 0xD8, 0xE8, 0x04, 0x52, 0x63, 0x00, 0x23, + 0xD5, 0x03, 0x52, 0x63, 0x00, 0x3B, 0x97, 0xB0, 0xF1, 0x03, 0x80, 0x07, 0xEA, 0xC4, 0x38, 0x1E, + 0x01, 0x11, 0xD5, 0x16, 0x5A, 0xA8, 0x01, 0x62, 0xE6, 0xD2, 0x5A, 0x90, 0x04, 0x3C, 0x5A, 0x90, + 0x0D, 0x3A, 0xE8, 0x48, 0xE6, 0xC6, 0xE8, 0x43, 0x52, 0x63, 0x00, 0x05, 0xF1, 0x03, 0x97, 0xB0, + 0x8C, 0xD2, 0x80, 0x07, 0xEA, 0xC4, 0x50, 0x10, 0x7E, 0xBC, 0x38, 0x1E, 0x05, 0x11, 0x38, 0x14, + 0x01, 0x09, 0x8C, 0x81, 0x50, 0x52, 0x80, 0x24, 0x50, 0x31, 0x80, 0x24, 0x5A, 0x48, 0x36, 0xB6, + 0x48, 0xFF, 0xFF, 0x6B, 0xE6, 0x12, 0x4E, 0xF3, 0xFF, 0x60, 0xEA, 0xC0, 0x12, 0x23, 0xFD, 0x78, + 0x48, 0xFF, 0xFF, 0x5B, 0xE6, 0x09, 0x4E, 0xF3, 0xFF, 0x58, 0xEA, 0xC0, 0x12, 0x23, 0xFE, 0xBC, + 0x48, 0xFF, 0xFF, 0x53, 0xF4, 0x01, 0x5A, 0x40, 0x02, 0x03, 0xEA, 0xEB, 0xEB, 0x1C, 0x38, 0x40, + 0x80, 0x09, 0xEA, 0xEB, 0xF4, 0x01, 0x4E, 0x42, 0xFF, 0x7F, 0xEB, 0x1C, 0x38, 0x43, 0x80, 0x09, + 0xEA, 0xEB, 0xE8, 0x06, 0x22, 0x02, 0x80, 0x00, 0x12, 0x01, 0x81, 0x32, 0xD5, 0xD3, 0xEA, 0xE8, + 0xE9, 0xD1, 0x22, 0x02, 0x80, 0x00, 0x12, 0x01, 0xFD, 0x78, 0xD5, 0xCC, 0x52, 0x63, 0x00, 0x17, + 0xD5, 0xBE, 0xEA, 0xE8, 0xE9, 0xC7, 0x5C, 0xF3, 0x00, 0x30, 0xE8, 0x04, 0x52, 0x63, 0x00, 0x53, + 0xD5, 0x03, 0x52, 0x63, 0x00, 0x65, 0xF1, 0x03, 0x97, 0xB0, 0x50, 0x63, 0x7F, 0xDC, 0x80, 0x07, + 0xEA, 0xC4, 0x50, 0x10, 0x02, 0x88, 0xD5, 0xB2, 0xE6, 0xD2, 0xE9, 0xB4, 0x5A, 0x90, 0x05, 0x04, + 0x5A, 0x98, 0x0C, 0x10, 0xE6, 0xDE, 0xE8, 0x04, 0x52, 0x63, 0x00, 0x2F, 0xD5, 0x09, 0x5C, 0xF3, + 0x00, 0x2A, 0xE8, 0x04, 0x52, 0x63, 0x00, 0x47, 0xD5, 0x03, 0x52, 0x63, 0x00, 0x5F, 0x97, 0xB0, + 0xF1, 0x03, 0x8E, 0xD2, 0x80, 0x07, 0xEA, 0xC4, 0x50, 0x10, 0x01, 0x44, 0xD5, 0x97, 0xFC, 0x40, + 0x51, 0xFF, 0xF5, 0x10, 0xEA, 0x22, 0x96, 0x06, 0xC0, 0x03, 0x84, 0x01, 0xEA, 0x26, 0xEA, 0xC2, + 0xF0, 0x83, 0x84, 0x20, 0x44, 0x20, 0x05, 0x10, 0xB0, 0x34, 0xDD, 0x42, 0x44, 0x20, 0x05, 0x10, + 0x84, 0x20, 0x50, 0x0F, 0x85, 0xE0, 0xDD, 0x42, 0x85, 0x40, 0xB0, 0x0D, 0xB0, 0x4E, 0x14, 0xAF, + 0x80, 0x0D, 0x14, 0xAF, 0x80, 0x0E, 0x49, 0xFF, 0xE8, 0x57, 0x44, 0x00, 0x7A, 0xA8, 0x50, 0x8F, + 0x80, 0x48, 0xEA, 0x97, 0x51, 0xCF, 0x80, 0x3C, 0x44, 0x00, 0x7A, 0xB8, 0x80, 0x3C, 0x3A, 0x24, + 0x14, 0x20, 0xEA, 0xE4, 0xEA, 0xAC, 0xA4, 0x00, 0x2E, 0x77, 0xF5, 0x94, 0xAC, 0x08, 0x84, 0x02, + 0x49, 0xFF, 0xE2, 0xE6, 0xF0, 0x8B, 0x44, 0x0F, 0xFF, 0xCD, 0x3E, 0x07, 0xEF, 0x8B, 0x2E, 0x67, + 0xF9, 0x74, 0xEA, 0x6D, 0x3C, 0x03, 0x31, 0x02, 0x2E, 0x16, 0x62, 0x00, 0xFA, 0x48, 0xFE, 0x0C, + 0x96, 0x01, 0xF0, 0x85, 0x80, 0x2A, 0xB0, 0x16, 0xDD, 0x42, 0x85, 0x27, 0x84, 0x01, 0x10, 0x0F, + 0x80, 0x59, 0x10, 0x9F, 0x80, 0x5F, 0x10, 0x9F, 0x80, 0x65, 0x10, 0x0F, 0x80, 0x6B, 0x84, 0x22, + 0x50, 0x9F, 0x80, 0x70, 0x44, 0x00, 0x7A, 0xC4, 0x10, 0x1F, 0x80, 0x5A, 0x10, 0x1F, 0x80, 0x6A, + 0x84, 0x43, 0x84, 0x64, 0x84, 0x85, 0x84, 0xA6, 0x80, 0x29, 0x10, 0x2F, 0x80, 0x5B, 0x10, 0x3F, + 0x80, 0x5C, 0x10, 0x4F, 0x80, 0x5D, 0x10, 0x5F, 0x80, 0x5E, 0x85, 0xE8, 0x10, 0x5F, 0x80, 0x66, + 0x10, 0x4F, 0x80, 0x67, 0x10, 0x3F, 0x80, 0x68, 0x10, 0x2F, 0x80, 0x69, 0xEA, 0x79, 0x10, 0xFF, + 0x80, 0x60, 0x10, 0xFF, 0x80, 0x64, 0xEA, 0x60, 0xEA, 0x79, 0xEA, 0x60, 0xEA, 0x97, 0x3A, 0x20, + 0x94, 0x20, 0xB0, 0x28, 0x80, 0x2A, 0xEA, 0x49, 0xDD, 0x42, 0x44, 0x03, 0xF0, 0x3F, 0xF0, 0xA8, + 0xEA, 0xB2, 0x94, 0x06, 0xF0, 0xA9, 0xF1, 0xAB, 0xEA, 0xC7, 0xEA, 0xA5, 0xF1, 0xAC, 0x94, 0x46, + 0xF0, 0xAA, 0xF1, 0xAD, 0xDD, 0x4F, 0xDD, 0x47, 0xF0, 0xAF, 0xF1, 0xAE, 0xEA, 0x7E, 0x2E, 0x07, + 0xF7, 0x69, 0x8C, 0xE1, 0x97, 0xF8, 0x92, 0xC4, 0x5A, 0x00, 0x03, 0x2D, 0xEA, 0x31, 0x2E, 0xA7, + 0xF7, 0x69, 0x5A, 0xA8, 0x01, 0x13, 0xEA, 0x81, 0x80, 0x0A, 0xEA, 0xC8, 0xFA, 0x2F, 0xEA, 0x68, + 0x80, 0x6A, 0x58, 0x42, 0x00, 0x08, 0x80, 0xAA, 0xDD, 0x46, 0xEA, 0x7F, 0x84, 0x0E, 0xFA, 0x2F, + 0xEA, 0x7B, 0x80, 0x6A, 0x97, 0x0F, 0xD5, 0x14, 0x4E, 0xA3, 0x00, 0x15, 0xEA, 0x81, 0x84, 0x01, + 0xEA, 0xC8, 0x80, 0x60, 0xFA, 0x2F, 0xEA, 0x68, 0x58, 0x42, 0x00, 0x04, 0x80, 0xA0, 0xDD, 0x46, + 0xEA, 0x7F, 0x84, 0x0E, 0xFA, 0x2F, 0xEA, 0x7B, 0x84, 0x61, 0x58, 0x42, 0x00, 0xFC, 0x80, 0xA3, + 0xDD, 0x46, 0x84, 0x00, 0xEA, 0xCD, 0x84, 0x03, 0xEA, 0x75, 0x84, 0x03, 0x49, 0xFF, 0xD9, 0x21, + 0xF5, 0x03, 0x84, 0x21, 0x50, 0x02, 0x85, 0x10, 0x1A, 0x12, 0x80, 0x01, 0xD8, 0xFE, 0x80, 0x1C, + 0x49, 0xFF, 0xD8, 0x94, 0x84, 0x08, 0xEA, 0x4B, 0x84, 0x09, 0x49, 0xFF, 0xE6, 0x15, 0x84, 0x09, + 0xEA, 0x90, 0x80, 0x09, 0xEA, 0x47, 0xB0, 0x16, 0xDD, 0x5D, 0x84, 0x03, 0xEB, 0x33, 0x84, 0x00, + 0x49, 0xFF, 0xDC, 0x6C, 0x84, 0x00, 0x49, 0xFF, 0xE5, 0xAE, 0x84, 0x00, 0xEB, 0x35, 0xEA, 0x5E, + 0x2E, 0x10, 0x10, 0xC3, 0x49, 0xFF, 0xD9, 0xE9, 0x2E, 0x07, 0xF7, 0x68, 0x5A, 0x00, 0x07, 0x11, + 0xDD, 0x43, 0x96, 0x0F, 0x83, 0x82, 0xB9, 0x38, 0x92, 0x2E, 0x96, 0x4F, 0xF1, 0x8A, 0xBB, 0x38, + 0x40, 0x10, 0x38, 0x08, 0xEA, 0xE1, 0xFE, 0x1E, 0xFE, 0x0F, 0xB8, 0xB8, 0xD5, 0x03, 0x84, 0x00, + 0xF0, 0x8A, 0xEA, 0x62, 0xEB, 0x2E, 0x83, 0x81, 0xBA, 0x75, 0xFE, 0x16, 0xB8, 0xF5, 0x84, 0x01, + 0x49, 0xFF, 0xDD, 0xD2, 0xEA, 0x8A, 0xEA, 0x2D, 0x84, 0x41, 0x04, 0x00, 0x83, 0x97, 0x80, 0x62, + 0x58, 0x00, 0x00, 0x40, 0x14, 0x00, 0x83, 0x97, 0x50, 0x00, 0x8A, 0x5C, 0x50, 0x10, 0x86, 0x5C, + 0xDD, 0x40, 0x2E, 0x07, 0xEF, 0x8B, 0xEB, 0x1A, 0x2E, 0x00, 0x10, 0xC6, 0x2E, 0x10, 0x10, 0xC7, + 0x2E, 0x20, 0x10, 0xBD, 0x49, 0xFF, 0xE7, 0x59, 0x84, 0x20, 0x84, 0x01, 0x80, 0x41, 0xEA, 0xBE, + 0x3C, 0x00, 0x08, 0x5B, 0x44, 0x10, 0xFF, 0xFF, 0x3C, 0x50, 0x08, 0x5C, 0x4C, 0x00, 0x80, 0x0F, + 0xD1, 0x0D, 0xE2, 0xA0, 0x81, 0x25, 0x40, 0x90, 0x3C, 0x1B, 0xE2, 0x05, 0x40, 0x50, 0x3C, 0x1B, + 0x80, 0x09, 0xF5, 0x82, 0xDD, 0x58, 0x81, 0x40, 0xD5, 0x08, 0x44, 0x00, 0x00, 0x6E, 0x44, 0xA0, + 0x01, 0x06, 0xF0, 0x82, 0x44, 0x90, 0x00, 0xB4, 0x84, 0x02, 0x80, 0x29, 0xDD, 0x4B, 0x80, 0x2A, + 0x84, 0x02, 0xEA, 0x29, 0x84, 0x00, 0x84, 0x22, 0xEA, 0x24, 0x80, 0x2A, 0x84, 0x03, 0xEA, 0x29, + 0x84, 0x03, 0x80, 0x29, 0xDD, 0x4B, 0x49, 0xFF, 0xE4, 0x21, 0x84, 0x01, 0x84, 0x20, 0x2E, 0x27, + 0xEF, 0x9B, 0x2E, 0x37, 0xEF, 0x9A, 0x44, 0x40, 0x00, 0x30, 0xFA, 0xA0, 0x49, 0xFF, 0xDE, 0x2A, + 0x84, 0x00, 0x84, 0x21, 0x49, 0xFF, 0xE7, 0x56, 0xEA, 0x21, 0x85, 0x48, 0xF0, 0x84, 0x96, 0x1F, + 0x5A, 0x00, 0x0F, 0x04, 0x04, 0xAF, 0x80, 0x04, 0x84, 0x00, 0x80, 0x20, 0x44, 0x32, 0x0E, 0x8C, + 0x38, 0x21, 0x80, 0x00, 0x8C, 0x01, 0xE2, 0x22, 0x40, 0x11, 0x3C, 0x1B, 0x5A, 0x08, 0x0A, 0xFA, + 0x45, 0xC2, 0x0D, 0x5C, 0x38, 0x0E, 0x04, 0x00, 0x8C, 0x01, 0xE0, 0x0A, 0xE8, 0x03, 0x54, 0xA0, + 0x00, 0xFF, 0x84, 0x00, 0xDD, 0x48, 0x80, 0x08, 0x49, 0xFF, 0xE7, 0x49, 0xEA, 0x20, 0x84, 0x01, + 0xDD, 0x48, 0x40, 0x75, 0x1C, 0x01, 0x5A, 0x68, 0x0F, 0x0E, 0x84, 0xC4, 0xE0, 0xE6, 0xE9, 0x0F, + 0xEA, 0x8C, 0xDD, 0x5A, 0x49, 0xFF, 0xDE, 0x2D, 0xC0, 0x0A, 0x8C, 0xC1, 0x97, 0xB0, 0xEA, 0x20, + 0xD5, 0xF6, 0xF0, 0x04, 0xE2, 0x06, 0xE8, 0x03, 0x9F, 0x81, 0x97, 0xB0, 0xDD, 0x5A, 0x84, 0x00, + 0xDD, 0x48, 0xE0, 0xC7, 0xE9, 0x02, 0x97, 0xB8, 0x84, 0x02, 0x80, 0x26, 0xEA, 0xBC, 0xE0, 0xE6, + 0xE9, 0x10, 0x84, 0x20, 0x40, 0x65, 0x18, 0x01, 0x38, 0x5E, 0x04, 0x00, 0x96, 0x09, 0x8C, 0xA1, + 0xDE, 0x05, 0x96, 0x00, 0x84, 0x22, 0xEA, 0x24, 0xD5, 0x04, 0x8C, 0x21, 0x5A, 0x18, 0x0A, 0xF6, + 0xEA, 0x64, 0xEA, 0x55, 0xB4, 0x41, 0x85, 0x40, 0xFE, 0x17, 0x84, 0x41, 0xB6, 0x01, 0x80, 0x62, + 0xDD, 0x59, 0xEA, 0x23, 0xDD, 0x40, 0xEA, 0xF5, 0x46, 0x00, 0x0E, 0x00, 0xB4, 0x41, 0xFE, 0x17, + 0x84, 0x41, 0xB6, 0x01, 0x80, 0x62, 0xEA, 0x5B, 0xEA, 0x70, 0xDD, 0x40, 0x84, 0x01, 0xDD, 0x48, + 0x84, 0x00, 0x3E, 0x07, 0xF9, 0x08, 0xF0, 0x05, 0x92, 0x01, 0xF0, 0x86, 0x46, 0x05, 0x55, 0x55, + 0x46, 0x10, 0x01, 0x55, 0x40, 0x35, 0x00, 0x13, 0x80, 0x4A, 0x50, 0x00, 0x05, 0x55, 0x50, 0x10, + 0x85, 0x55, 0xF3, 0x88, 0xEA, 0xD9, 0x83, 0x80, 0x81, 0x01, 0xF0, 0x12, 0xF1, 0x13, 0x84, 0xE0, + 0xB1, 0xB4, 0x40, 0x00, 0x70, 0x02, 0x40, 0x10, 0xA0, 0x02, 0x80, 0x49, 0xF3, 0x08, 0xF4, 0x06, + 0x80, 0xA6, 0xB6, 0xFF, 0xEA, 0x52, 0xF0, 0x12, 0xF1, 0x13, 0xB6, 0xFF, 0x40, 0x00, 0x70, 0x02, + 0x40, 0x10, 0xA0, 0x02, 0xF2, 0x02, 0xF3, 0x08, 0xF4, 0x06, 0xEA, 0xFD, 0xEA, 0x52, 0x5A, 0xA0, + 0x01, 0x04, 0x85, 0x41, 0xD5, 0xD4, 0x80, 0x06, 0xEB, 0x07, 0xF2, 0x03, 0xEB, 0x41, 0xF0, 0x05, + 0x87, 0x83, 0x3E, 0xA7, 0xF9, 0x08, 0x3E, 0x77, 0xF9, 0x07, 0x41, 0xC0, 0x73, 0x97, 0xFA, 0x42, + 0x85, 0x01, 0x40, 0xA3, 0x80, 0x13, 0xFE, 0xBC, 0x44, 0x03, 0xFF, 0xFF, 0x84, 0x20, 0xEA, 0xD9, + 0x80, 0x49, 0x80, 0x6A, 0x80, 0x9C, 0x80, 0xA6, 0xB7, 0x1F, 0xF0, 0x86, 0xF1, 0x87, 0xEA, 0x52, + 0xF0, 0x06, 0xB7, 0x1F, 0xF1, 0x07, 0xF2, 0x02, 0x80, 0x6A, 0x80, 0x9C, 0xEA, 0xFD, 0xEA, 0x52, + 0x2E, 0x07, 0xF9, 0x07, 0x88, 0xE8, 0x88, 0x08, 0x3E, 0x07, 0xF9, 0x07, 0x5A, 0x78, 0x03, 0xE1, + 0x80, 0x06, 0xEB, 0x07, 0xF2, 0x03, 0xEB, 0x41, 0x84, 0x02, 0x3E, 0x07, 0xF9, 0x08, 0x84, 0xE0, + 0xF6, 0x86, 0xEA, 0xDD, 0x80, 0x47, 0x40, 0xA3, 0x80, 0x13, 0x84, 0xC2, 0x8C, 0x03, 0x44, 0x10, + 0x00, 0x30, 0xEA, 0xD9, 0x80, 0x49, 0x80, 0x6A, 0xF4, 0x05, 0xF5, 0x06, 0xB6, 0xDF, 0xF0, 0x88, + 0xF1, 0x89, 0x88, 0xE6, 0xEA, 0x52, 0xB6, 0xDF, 0xF0, 0x08, 0xF1, 0x09, 0xF2, 0x02, 0x80, 0x6A, + 0xF4, 0x05, 0xEA, 0xFD, 0xEA, 0x52, 0x5A, 0x78, 0x12, 0xE6, 0xEB, 0x07, 0xF2, 0x03, 0xF0, 0x06, + 0xEB, 0x41, 0x84, 0x00, 0xDD, 0x48, 0xEA, 0x64, 0xDD, 0x55, 0xB4, 0x41, 0xFE, 0x16, 0x84, 0x41, + 0xB6, 0x01, 0x80, 0x62, 0xDD, 0x59, 0xEA, 0x23, 0xDD, 0x40, 0xEA, 0xF5, 0x46, 0x0F, 0xF1, 0xFF, + 0xB4, 0x41, 0xDD, 0x41, 0xFE, 0x16, 0x84, 0x41, 0x80, 0x62, 0xB6, 0x01, 0xEA, 0x70, 0xEA, 0x5B, + 0xDD, 0x40, 0x84, 0x00, 0xEB, 0x01, 0xEA, 0x2D, 0x84, 0x1F, 0x83, 0x81, 0xB8, 0xCB, 0xB8, 0xCC, + 0xBA, 0x4D, 0x92, 0x0A, 0xFE, 0x87, 0xBA, 0xCD, 0xBA, 0x48, 0xFE, 0x17, 0xB8, 0xC8, 0x84, 0x00, + 0x3E, 0x07, 0xEF, 0x8B, 0x84, 0x00, 0xEB, 0x1A, 0xB0, 0x12, 0x49, 0xFF, 0xE6, 0x6C, 0x84, 0x00, + 0x80, 0x20, 0x49, 0xFF, 0xE6, 0x2F, 0x84, 0x01, 0xEA, 0x40, 0xEA, 0x83, 0xEB, 0x35, 0xF0, 0x0D, + 0xF1, 0x0E, 0x49, 0xFF, 0xE6, 0x79, 0x84, 0x41, 0x80, 0x62, 0xEA, 0x53, 0xEA, 0x43, 0xDD, 0x40, + 0x84, 0x41, 0x80, 0x62, 0xEA, 0xAF, 0xEA, 0xB8, 0xDD, 0x40, 0x84, 0x00, 0xEA, 0x6F, 0x84, 0x01, + 0xEB, 0x33, 0xB0, 0x28, 0xEA, 0x47, 0x44, 0x02, 0x0E, 0x68, 0xDD, 0x5D, 0x80, 0x06, 0x49, 0xFF, + 0xE4, 0x43, 0x80, 0x06, 0x84, 0x20, 0xEA, 0xBC, 0x84, 0x20, 0x84, 0x01, 0xEA, 0x38, 0xEB, 0x3A, + 0x84, 0x00, 0xEA, 0x4A, 0x84, 0x00, 0x49, 0xFF, 0xF5, 0xB8, 0x2E, 0x57, 0xF9, 0x65, 0xD6, 0x05, + 0x84, 0x00, 0xEA, 0xE2, 0x49, 0xFF, 0xE2, 0x84, 0x84, 0x00, 0xEA, 0x6E, 0xF0, 0x04, 0x5A, 0x00, + 0x0F, 0x05, 0xF0, 0x0B, 0x84, 0x22, 0xEA, 0x24, 0xEA, 0x5E, 0x3C, 0x13, 0xF7, 0xEF, 0xB6, 0x1F, + 0xEA, 0x80, 0xEA, 0x72, 0xEA, 0x8E, 0xEB, 0x27, 0x84, 0x41, 0xF0, 0x81, 0x84, 0x02, 0xEB, 0x29, + 0x84, 0x01, 0xEA, 0xCD, 0x84, 0x01, 0xEA, 0x75, 0xEA, 0x8B, 0xEA, 0x59, 0xEA, 0x22, 0x96, 0x06, + 0xC0, 0x03, 0x84, 0x00, 0xEA, 0x26, 0x2E, 0x07, 0xF7, 0x68, 0x5A, 0x00, 0x07, 0x0C, 0xDD, 0x43, + 0xF0, 0x0A, 0x83, 0x82, 0xBB, 0x38, 0x40, 0x10, 0x38, 0x08, 0xEA, 0xE1, 0xFE, 0x1E, 0xFE, 0x0F, + 0xB8, 0xB8, 0x51, 0xFF, 0x8A, 0xF0, 0xFC, 0xC0, 0xFC, 0x22, 0x84, 0x00, 0xF0, 0x82, 0xF0, 0x83, + 0xEA, 0x63, 0x2E, 0x77, 0xF9, 0x6E, 0xEA, 0x7E, 0xEA, 0x6D, 0xEA, 0xBA, 0xEA, 0xC9, 0xEA, 0xAE, + 0xEA, 0x94, 0xDD, 0x4D, 0x97, 0xF8, 0xC8, 0x02, 0xEB, 0x21, 0xEA, 0x22, 0x96, 0x06, 0xC0, 0x03, + 0x84, 0x01, 0xEA, 0x26, 0x2E, 0x67, 0xF9, 0x75, 0xDD, 0x53, 0x97, 0xB0, 0x5A, 0x08, 0x05, 0x13, + 0x84, 0x20, 0x80, 0x41, 0x84, 0x01, 0xEA, 0xBE, 0x84, 0x00, 0x80, 0x20, 0xEA, 0x38, 0x84, 0x01, + 0xEA, 0x46, 0x84, 0x00, 0x84, 0x21, 0xEB, 0x1F, 0xDD, 0x4D, 0xC0, 0x04, 0x84, 0x00, 0x80, 0x20, + 0xDD, 0x5F, 0x84, 0x00, 0xEA, 0x89, 0x84, 0x00, 0xEA, 0x74, 0x84, 0x00, 0xEA, 0x77, 0xDD, 0x53, + 0x5A, 0x08, 0x08, 0x12, 0xDD, 0x4D, 0x5A, 0x08, 0x02, 0x0F, 0x84, 0x00, 0xEA, 0x61, 0xB0, 0x02, + 0xB0, 0x43, 0x50, 0x2F, 0x80, 0x07, 0x49, 0xFF, 0xE1, 0xFE, 0x54, 0x03, 0x80, 0x70, 0x92, 0x04, + 0x49, 0xFF, 0xE1, 0x08, 0xEA, 0xB4, 0xEA, 0xC5, 0xDD, 0x53, 0x5A, 0x08, 0x08, 0x10, 0xEB, 0x02, + 0xC8, 0x0B, 0x84, 0x01, 0x40, 0x13, 0x18, 0x09, 0x54, 0x23, 0x00, 0x3E, 0xFE, 0x46, 0x40, 0x21, + 0x00, 0x0D, 0xEA, 0xBE, 0xD5, 0x03, 0x84, 0x00, 0xEA, 0x6F, 0xEA, 0x20, 0x84, 0x01, 0xDD, 0x48, + 0xEA, 0x8C, 0xDD, 0x5A, 0xEA, 0xA7, 0x84, 0x00, 0xDD, 0x48, 0x84, 0x01, 0xEA, 0x89, 0x84, 0x01, + 0xEA, 0x74, 0x84, 0x01, 0xEA, 0x77, 0xDD, 0x53, 0x5A, 0x08, 0x08, 0x06, 0x84, 0x00, 0xDD, 0x48, + 0xDD, 0x5A, 0xD5, 0x0F, 0xDD, 0x53, 0x5A, 0x08, 0x05, 0x0D, 0x84, 0x00, 0xEA, 0x6F, 0x84, 0x00, + 0xEA, 0x46, 0x84, 0x00, 0xEA, 0x96, 0xDD, 0x4D, 0xC0, 0x04, 0x84, 0x00, 0x80, 0x20, 0xDD, 0x5F, + 0xDD, 0x53, 0x5A, 0x08, 0x08, 0x05, 0xEB, 0x02, 0xC8, 0x02, 0xEA, 0x6F, 0xDD, 0x53, 0x5A, 0x08, + 0x08, 0x0D, 0xDD, 0x4D, 0x5A, 0x08, 0x02, 0x0A, 0x84, 0x03, 0xEA, 0x61, 0xB0, 0x02, 0xB0, 0x43, + 0x50, 0x2F, 0x80, 0x07, 0x49, 0xFF, 0xE1, 0x78, 0xEA, 0xA9, 0xEA, 0xB1, 0xEA, 0xA4, 0xEA, 0x22, + 0x96, 0x06, 0xC0, 0x03, 0x84, 0x00, 0xEA, 0x26, 0xDD, 0x4D, 0xC8, 0x02, 0xEA, 0xE5, 0xEA, 0x8B, + 0xEA, 0x59, 0xFC, 0xA2, 0xFC, 0x40, 0x84, 0x61, 0x84, 0x80, 0x8E, 0x21, 0xE0, 0x81, 0xE8, 0x1D, + 0x5A, 0x38, 0x01, 0x1C, 0x84, 0x60, 0x80, 0xA3, 0x40, 0xA0, 0x90, 0x01, 0xE0, 0xAA, 0xE8, 0x12, + 0x94, 0xA9, 0x99, 0xC2, 0x8C, 0x42, 0x88, 0x40, 0x22, 0x63, 0x80, 0x00, 0x22, 0x91, 0x00, 0x00, + 0xE0, 0xC9, 0xE8, 0x05, 0x12, 0x93, 0x80, 0x00, 0x84, 0x61, 0xAD, 0x90, 0x8C, 0xA1, 0x97, 0x68, + 0xD5, 0xEE, 0x8C, 0x81, 0x97, 0x20, 0xD5, 0xE3, 0xFC, 0xC0, 0xFC, 0x4A, 0x51, 0xCF, 0x80, 0x70, + 0x2E, 0x17, 0xF9, 0x74, 0x2E, 0xA6, 0x61, 0xFE, 0x54, 0x90, 0x80, 0xFF, 0x2E, 0x66, 0x61, 0xFF, + 0x2E, 0x17, 0xF9, 0x75, 0x42, 0x25, 0x18, 0x24, 0x94, 0x11, 0x96, 0x48, 0x8C, 0x08, 0x14, 0x1E, + 0x7F, 0xF3, 0x92, 0x03, 0x84, 0x2C, 0x94, 0x03, 0xFE, 0x54, 0xEA, 0x54, 0x8C, 0x2A, 0x15, 0xFE, + 0x7F, 0xF2, 0x92, 0x23, 0xEA, 0x54, 0x94, 0x4B, 0x15, 0xFE, 0x7F, 0xF1, 0xEA, 0x54, 0x15, 0xFE, + 0x7F, 0xF0, 0x41, 0xFF, 0x84, 0x01, 0x80, 0xFF, 0xEA, 0x54, 0x15, 0xFE, 0x7F, 0xEA, 0xEA, 0x54, + 0x15, 0xFE, 0x7F, 0xE9, 0xEA, 0x7E, 0xEA, 0x6D, 0x2E, 0x07, 0xF9, 0x76, 0x96, 0x00, 0x14, 0x0E, + 0x7F, 0xEE, 0xEA, 0x22, 0x96, 0x06, 0xC0, 0x07, 0x84, 0x01, 0x84, 0x20, 0x84, 0x44, 0xEA, 0xBE, + 0x84, 0x01, 0xEA, 0x26, 0x84, 0x00, 0xEA, 0x89, 0x84, 0x00, 0xEA, 0x74, 0x84, 0x00, 0xEA, 0x77, + 0xEA, 0xBA, 0xEA, 0xAE, 0xEA, 0x94, 0xEA, 0xC9, 0x80, 0x09, 0xEA, 0xC5, 0x44, 0x10, 0x00, 0x32, + 0x84, 0x01, 0xEB, 0x19, 0x84, 0x01, 0xEA, 0x4C, 0x44, 0x04, 0x80, 0x90, 0x44, 0x1F, 0xFF, 0xDF, + 0xB4, 0x40, 0xFE, 0x56, 0xB6, 0x20, 0xB4, 0x40, 0x44, 0x1F, 0xFF, 0xBF, 0xFE, 0x56, 0xB6, 0x20, + 0xEA, 0x20, 0x84, 0x01, 0xDD, 0x48, 0xDD, 0x44, 0xC8, 0x02, 0xEA, 0xCB, 0x84, 0x00, 0xEA, 0x84, + 0xEA, 0x69, 0xC0, 0x10, 0x42, 0x65, 0x18, 0x24, 0x40, 0x93, 0x04, 0x08, 0xEA, 0xA7, 0xEB, 0x0A, + 0x80, 0x49, 0x04, 0x0E, 0x7F, 0xF2, 0xEA, 0x41, 0xDD, 0x44, 0xC8, 0x0B, 0x84, 0x01, 0xEA, 0xCB, + 0xD5, 0x08, 0xEA, 0x5D, 0x5A, 0x00, 0x01, 0xF0, 0xEA, 0x4F, 0xEA, 0x2E, 0xC0, 0xEA, 0xD5, 0xEB, + 0x84, 0x00, 0xEA, 0x84, 0xEA, 0x69, 0xC0, 0x0D, 0xEA, 0xA7, 0x80, 0x49, 0x04, 0x0E, 0x7F, 0xF1, + 0xEB, 0x0A, 0xEA, 0x41, 0xEA, 0x2E, 0x54, 0x90, 0x00, 0xFF, 0x4E, 0x93, 0x00, 0x34, 0xD5, 0x08, + 0xEA, 0x5D, 0x5A, 0x00, 0x01, 0xF3, 0xEA, 0x4F, 0xEA, 0x2E, 0xC0, 0xED, 0xD5, 0xEE, 0x84, 0x4C, + 0x44, 0x10, 0x00, 0xFF, 0xFE, 0xB4, 0x80, 0x07, 0xDD, 0x42, 0x81, 0x1C, 0xB2, 0x13, 0x84, 0xC0, + 0x8E, 0x01, 0x96, 0x00, 0x5C, 0xF0, 0x00, 0xFE, 0xB2, 0x13, 0x40, 0x04, 0xBC, 0x1A, 0x14, 0x0E, + 0x7F, 0xF3, 0x2E, 0x06, 0x61, 0xFE, 0x14, 0x0E, 0x7F, 0xEF, 0xEB, 0x44, 0x14, 0x0E, 0x7F, 0xEC, + 0xB2, 0x2C, 0xB2, 0x0F, 0xFE, 0x0C, 0x14, 0x0E, 0x7F, 0xEB, 0x46, 0x00, 0x25, 0x87, 0x50, 0x00, + 0x08, 0x00, 0x14, 0x0E, 0x7F, 0xE7, 0xEA, 0x9E, 0x04, 0x1E, 0x7F, 0xF3, 0x88, 0x01, 0xE2, 0xC0, + 0xE9, 0x16, 0xDD, 0x5A, 0x84, 0x00, 0xDD, 0x48, 0x84, 0x00, 0xEA, 0x4C, 0x84, 0x00, 0xEA, 0x6F, + 0x84, 0x01, 0xEA, 0x89, 0x84, 0x01, 0xEA, 0x74, 0x84, 0x01, 0xEA, 0x77, 0xEA, 0x8B, 0xEA, 0x59, + 0x84, 0x01, 0x80, 0x20, 0xEB, 0x4A, 0x84, 0xC0, 0x48, 0x00, 0x01, 0xA8, 0xDD, 0x44, 0xC8, 0x06, + 0x54, 0x13, 0x00, 0x01, 0xC1, 0x02, 0x84, 0x01, 0xEA, 0xCB, 0x84, 0x00, 0xEA, 0x84, 0xEA, 0x69, + 0xC0, 0x13, 0xEA, 0xA7, 0x04, 0x0E, 0x7F, 0xF3, 0xE2, 0xC0, 0x4E, 0xF3, 0x01, 0x8B, 0x84, 0xA0, + 0x3C, 0x3C, 0x04, 0x2C, 0xEB, 0x43, 0x81, 0x25, 0x44, 0xA0, 0x88, 0xB8, 0x44, 0x82, 0x28, 0x24, + 0x55, 0xE3, 0x00, 0x01, 0xD5, 0x31, 0xEA, 0x5D, 0x5A, 0x00, 0x01, 0xED, 0xEA, 0x4F, 0xEA, 0x2E, + 0xC0, 0xE7, 0xD5, 0xE8, 0x04, 0x1E, 0x7F, 0xEF, 0x44, 0x40, 0x00, 0x5A, 0x40, 0x22, 0x84, 0x57, + 0x52, 0x11, 0x00, 0x23, 0x81, 0xEA, 0x42, 0xF0, 0x90, 0x75, 0x04, 0x4E, 0x7F, 0xE7, 0x40, 0x17, + 0x84, 0x0A, 0x88, 0x24, 0x40, 0x10, 0xBC, 0x36, 0x38, 0x14, 0x09, 0x09, 0x38, 0xF1, 0x95, 0x01, + 0x4F, 0xE3, 0x00, 0x17, 0x04, 0x2E, 0x7F, 0xF2, 0x38, 0x21, 0x15, 0x01, 0x96, 0x49, 0x8A, 0x4F, + 0xAC, 0x80, 0x2A, 0x20, 0x00, 0x01, 0xFE, 0x54, 0x90, 0x2A, 0xE0, 0x29, 0x40, 0x14, 0xBC, 0x1B, + 0x40, 0x90, 0x80, 0x11, 0x8C, 0xA1, 0x04, 0x1E, 0x7F, 0xEB, 0xD9, 0xD5, 0xD5, 0x04, 0x04, 0x2E, + 0x7F, 0xF1, 0xD5, 0xEB, 0x04, 0x0E, 0x7F, 0xEE, 0x96, 0x0E, 0xC8, 0x05, 0xEB, 0x43, 0x84, 0x21, + 0x49, 0xFF, 0xD1, 0x92, 0x04, 0x0E, 0x7F, 0xEE, 0x96, 0x06, 0xC8, 0x16, 0x5E, 0xF4, 0x80, 0x46, + 0xE8, 0x13, 0xEB, 0x02, 0xC8, 0x06, 0x02, 0x0E, 0x7F, 0xD6, 0x04, 0x1E, 0x7F, 0xF2, 0xD5, 0x06, + 0x81, 0x1C, 0xB2, 0x2F, 0xB2, 0x0C, 0xFE, 0x0C, 0xB2, 0x31, 0x84, 0x61, 0xEB, 0x2C, 0x84, 0x88, + 0x80, 0xA3, 0x49, 0xFF, 0xEA, 0xBF, 0xEB, 0x44, 0x2E, 0x16, 0x61, 0xFE, 0x50, 0x3E, 0x7F, 0xA0, + 0x04, 0x8E, 0x7F, 0xE9, 0xFE, 0x0C, 0xB6, 0x03, 0x46, 0x0C, 0x00, 0xFF, 0xDD, 0x41, 0xA0, 0x9A, + 0x85, 0x20, 0xA8, 0x1D, 0x04, 0x0E, 0x7F, 0xE8, 0xE3, 0x20, 0x4E, 0xF2, 0x01, 0x13, 0xEB, 0x43, + 0x38, 0xA0, 0x25, 0x11, 0x04, 0x0E, 0x7F, 0xF3, 0x4C, 0x60, 0x40, 0x19, 0xEA, 0x9E, 0x12, 0xA4, + 0x00, 0x00, 0x12, 0xA1, 0x00, 0x00, 0x5A, 0x00, 0x01, 0x03, 0xEB, 0x14, 0xEA, 0xB3, 0x40, 0x14, + 0x84, 0x08, 0x88, 0x20, 0xA4, 0x08, 0x8A, 0x0A, 0x96, 0x01, 0x96, 0xC3, 0x4E, 0x35, 0x00, 0x04, + 0xAC, 0xC8, 0xEB, 0x14, 0xFE, 0x02, 0xAC, 0x08, 0xEB, 0x14, 0x84, 0x0C, 0x80, 0x67, 0x42, 0x34, + 0x80, 0x73, 0xA0, 0x19, 0x22, 0x14, 0x00, 0x00, 0x92, 0x14, 0xDD, 0x50, 0x9B, 0x08, 0xE0, 0x8A, + 0xE8, 0x5D, 0x97, 0x09, 0x9A, 0x20, 0x14, 0x2E, 0x7F, 0xE5, 0x12, 0xAE, 0x7F, 0xEE, 0x12, 0x0E, + 0x7F, 0xED, 0xA0, 0x19, 0x92, 0x0A, 0xDD, 0x50, 0x9A, 0x20, 0x12, 0x0E, 0x7F, 0xEC, 0xA0, 0x19, + 0x12, 0x1E, 0x7F, 0xEA, 0xDD, 0x50, 0x8A, 0x80, 0x84, 0x25, 0x50, 0x0E, 0x7F, 0xD4, 0x14, 0x3E, + 0x7F, 0xE6, 0x12, 0x4E, 0x7F, 0xEB, 0x49, 0xFF, 0xFE, 0x3F, 0x22, 0x0E, 0x7F, 0xEA, 0x22, 0x4E, + 0x7F, 0xEB, 0x12, 0x04, 0x00, 0x00, 0x9B, 0x04, 0x5E, 0xF2, 0x04, 0x00, 0x04, 0x3E, 0x7F, 0xE6, + 0x04, 0x2E, 0x7F, 0xE5, 0xE9, 0x03, 0x44, 0x40, 0x03, 0xFF, 0xA0, 0x59, 0x54, 0x42, 0x03, 0xFF, + 0x92, 0x2A, 0xEA, 0x37, 0xFE, 0x67, 0xA8, 0x59, 0x80, 0x87, 0x84, 0x2C, 0x42, 0x44, 0x84, 0x73, + 0x22, 0x1E, 0x7F, 0xEC, 0x9A, 0x41, 0x5E, 0xF0, 0x84, 0x00, 0xE9, 0x03, 0x44, 0x10, 0x03, 0xFF, + 0xA0, 0xE1, 0x46, 0x5F, 0xFF, 0x00, 0xEA, 0x2B, 0x50, 0x52, 0x83, 0xFF, 0xFE, 0xEE, 0xEA, 0x37, + 0xFE, 0x5F, 0xA8, 0x61, 0x80, 0x67, 0x84, 0x2C, 0x42, 0x34, 0x84, 0x73, 0x80, 0x23, 0x22, 0x3E, + 0x7F, 0xED, 0x8A, 0x03, 0xEB, 0x1B, 0xE9, 0x02, 0xEA, 0x9B, 0xA0, 0xC9, 0x04, 0x4E, 0x7F, 0xED, + 0xDD, 0x50, 0xEA, 0x3A, 0xFE, 0xE6, 0xFE, 0x1F, 0xA8, 0x09, 0x84, 0x0C, 0x80, 0x67, 0x42, 0x34, + 0x80, 0x73, 0xB4, 0x03, 0x22, 0x11, 0x00, 0x00, 0x92, 0x14, 0xDD, 0x50, 0x99, 0x08, 0xE1, 0x44, + 0xE8, 0x58, 0x97, 0x09, 0x88, 0x04, 0x14, 0x2E, 0x7F, 0xE5, 0x12, 0xAE, 0x7F, 0xEE, 0x12, 0x0E, + 0x7F, 0xED, 0xB4, 0x03, 0x92, 0x0A, 0xDD, 0x50, 0x88, 0x04, 0x12, 0x0E, 0x7F, 0xEC, 0xB4, 0x03, + 0x12, 0x1E, 0x7F, 0xEA, 0xDD, 0x50, 0x88, 0x80, 0x84, 0x25, 0x50, 0x0E, 0x7F, 0xD4, 0x14, 0x3E, + 0x7F, 0xE6, 0x12, 0x4E, 0x7F, 0xEB, 0x49, 0xFF, 0xFD, 0xD7, 0x22, 0x4E, 0x7F, 0xEE, 0x22, 0x1E, + 0x7F, 0xED, 0x04, 0x2E, 0x7F, 0xE5, 0x8A, 0x24, 0x5E, 0xF0, 0x84, 0x00, 0xAD, 0x10, 0x04, 0x3E, + 0x7F, 0xE6, 0xE9, 0x03, 0x44, 0x10, 0x03, 0xFF, 0xB4, 0x03, 0xEA, 0x2B, 0x92, 0x0A, 0xDD, 0x47, + 0xFE, 0x0F, 0xB6, 0x03, 0x80, 0x27, 0x84, 0x0C, 0x42, 0x14, 0x80, 0x73, 0x22, 0x0E, 0x7F, 0xEC, + 0x8A, 0x04, 0xEB, 0x1B, 0xE9, 0x02, 0xEA, 0x9B, 0xB4, 0x61, 0x46, 0x5F, 0xFF, 0x00, 0xDD, 0x50, + 0x50, 0x52, 0x83, 0xFF, 0xDD, 0x47, 0xFE, 0xEE, 0xFE, 0x1F, 0xB6, 0x01, 0x84, 0x0C, 0x80, 0x27, + 0x42, 0x14, 0x80, 0x73, 0x22, 0x0E, 0x7F, 0xEB, 0x8A, 0x04, 0xEB, 0x1B, 0xE9, 0x02, 0xEA, 0x9B, + 0xB4, 0x61, 0x04, 0x4E, 0x7F, 0xED, 0xDD, 0x50, 0xEA, 0x3A, 0xFE, 0xE6, 0xFE, 0x1F, 0xB6, 0x01, + 0xEA, 0x9E, 0x04, 0x1E, 0x7F, 0xF3, 0x8E, 0x01, 0x88, 0x01, 0x4C, 0x60, 0x40, 0x1E, 0xEA, 0xB3, + 0x40, 0x34, 0x84, 0x08, 0x88, 0x60, 0x80, 0x87, 0x84, 0x0C, 0x42, 0x44, 0x80, 0x73, 0xA0, 0x21, + 0x02, 0x14, 0x00, 0x00, 0x92, 0x14, 0xDD, 0x50, 0x9A, 0x08, 0xA4, 0x50, 0x9A, 0x41, 0xB4, 0x04, + 0x92, 0x14, 0xDD, 0x50, 0x9A, 0x08, 0x96, 0x01, 0x96, 0x43, 0x4E, 0x15, 0x00, 0x04, 0xAC, 0x58, + 0xD5, 0x03, 0xFE, 0x02, 0xAC, 0x18, 0x8D, 0x21, 0x8D, 0x02, 0x8C, 0x42, 0x48, 0xFF, 0xFE, 0xEC, + 0x8C, 0xC1, 0x48, 0xFF, 0xFE, 0x4A, 0x84, 0x01, 0x49, 0x00, 0x04, 0x32, 0x5A, 0x08, 0x01, 0x0A, + 0x8C, 0xC1, 0xEA, 0xDC, 0x97, 0xB0, 0xEA, 0x59, 0x49, 0xFF, 0xED, 0x91, 0xC0, 0xF5, 0xD5, 0x03, + 0xE6, 0xC3, 0xE9, 0xFB, 0x3C, 0x5C, 0x04, 0x29, 0xC5, 0x07, 0xEA, 0x22, 0x96, 0x06, 0xC0, 0x0F, + 0x84, 0x00, 0xEA, 0x26, 0xD5, 0x0C, 0xEB, 0x44, 0x2E, 0x16, 0x61, 0xFE, 0x80, 0x45, 0xFE, 0x0C, + 0xEB, 0x0A, 0xD0, 0xF4, 0x38, 0x20, 0x95, 0x09, 0x8C, 0xA1, 0xD5, 0xFC, 0xEA, 0xA9, 0xEA, 0xB1, + 0xEA, 0xA4, 0x51, 0xFE, 0x7F, 0xE0, 0xFC, 0xC0, 0xFC, 0x40, 0x51, 0xFF, 0xE9, 0xD8, 0xDD, 0x56, + 0x2E, 0x77, 0xF9, 0x75, 0x04, 0x00, 0x00, 0x39, 0x84, 0xC3, 0x92, 0x10, 0x96, 0x0F, 0xF0, 0x81, + 0x49, 0xFF, 0xD3, 0xC7, 0xF0, 0x82, 0x84, 0x20, 0xFA, 0x48, 0xB0, 0x08, 0xDD, 0x42, 0x84, 0x01, + 0x84, 0x62, 0x84, 0x44, 0x84, 0x25, 0x10, 0x0F, 0x80, 0x21, 0x10, 0x0F, 0x80, 0x23, 0x10, 0x0F, + 0x80, 0x25, 0x10, 0x0F, 0x80, 0x2D, 0x10, 0x0F, 0x80, 0x2F, 0x10, 0x0F, 0x80, 0x31, 0x10, 0x3F, + 0x80, 0x26, 0x10, 0x2F, 0x80, 0x28, 0x10, 0x1F, 0x80, 0x29, 0x10, 0x3F, 0x80, 0x32, 0x10, 0x2F, + 0x80, 0x34, 0x10, 0x1F, 0x80, 0x35, 0x10, 0x6F, 0x80, 0x27, 0x10, 0x6F, 0x80, 0x33, 0xEA, 0x7E, + 0xEA, 0x6D, 0xDD, 0x4D, 0x97, 0xF8, 0xC8, 0x02, 0xEB, 0x21, 0xEA, 0x22, 0x96, 0x06, 0xC0, 0x03, + 0x84, 0x01, 0xEA, 0x26, 0xEA, 0xC2, 0x3C, 0x0E, 0x04, 0x2C, 0x84, 0x01, 0xEA, 0x46, 0xEA, 0xBA, + 0xEA, 0xAE, 0xEA, 0x94, 0xEA, 0xC9, 0xDD, 0x44, 0x5A, 0x08, 0x01, 0x0A, 0xDD, 0x43, 0xEA, 0xCE, + 0x83, 0x82, 0xB9, 0x39, 0xFE, 0x0E, 0xEB, 0x3F, 0xFE, 0x0F, 0xB8, 0xB9, 0xEA, 0xB4, 0xEA, 0xC5, + 0xDD, 0x53, 0x5A, 0x08, 0x33, 0x3E, 0xEB, 0x1E, 0xEA, 0x36, 0xD8, 0x29, 0xEA, 0x56, 0xDD, 0x58, + 0xF0, 0x83, 0xF1, 0x03, 0x84, 0x00, 0x49, 0xFF, 0xE9, 0x47, 0xEA, 0x76, 0xEA, 0x56, 0xDD, 0x58, + 0xF0, 0x83, 0xF1, 0x03, 0x84, 0x04, 0xEA, 0x29, 0x84, 0x04, 0xEA, 0x27, 0xDD, 0x4B, 0xEA, 0x21, + 0xE4, 0x04, 0xE9, 0x15, 0x84, 0x20, 0x44, 0x22, 0x0D, 0x5C, 0x8E, 0x02, 0x38, 0x51, 0x04, 0x00, + 0x97, 0x89, 0x8C, 0xA1, 0xD8, 0x09, 0x97, 0xB0, 0x80, 0x06, 0x84, 0x23, 0xEA, 0x24, 0x80, 0x06, + 0x84, 0x20, 0xEA, 0x24, 0xD5, 0x04, 0x8C, 0x21, 0x5A, 0x18, 0x0A, 0xF2, 0xEA, 0x2A, 0x84, 0x03, + 0x83, 0x86, 0xB9, 0x21, 0x92, 0x30, 0xEA, 0x82, 0xEA, 0x29, 0xB9, 0x31, 0x84, 0x03, 0x92, 0x30, + 0xEA, 0x2B, 0xDD, 0x4B, 0x49, 0xFF, 0xDE, 0xA2, 0x84, 0x03, 0x84, 0x22, 0xEA, 0xBC, 0x84, 0x03, + 0xEB, 0x33, 0x84, 0x00, 0x49, 0xFF, 0xD6, 0x72, 0x49, 0x00, 0x02, 0x70, 0xEA, 0xDE, 0x49, 0xFF, + 0xF0, 0x13, 0x84, 0x00, 0xEA, 0x4C, 0x49, 0xFF, 0xE6, 0x9E, 0xF0, 0x83, 0x84, 0x00, 0xEA, 0xA6, + 0x84, 0x07, 0xEA, 0x4A, 0x84, 0x04, 0xEA, 0x90, 0x84, 0x03, 0xEA, 0x4B, 0xB0, 0x08, 0xDD, 0x5D, + 0x46, 0x20, 0x00, 0x80, 0xEA, 0xC6, 0x83, 0x82, 0xB9, 0x70, 0xDD, 0x41, 0xFE, 0x0E, 0x44, 0x13, + 0x00, 0x00, 0xFE, 0x0F, 0xB8, 0xF0, 0x2E, 0x07, 0xEF, 0x61, 0x94, 0x01, 0x54, 0x00, 0x00, 0xFE, + 0x49, 0xFF, 0xE4, 0x80, 0x84, 0x00, 0xEA, 0xF2, 0x49, 0xFF, 0xE4, 0x55, 0x84, 0x01, 0x49, 0xFF, + 0xE4, 0x68, 0x84, 0x01, 0x49, 0xFF, 0xD8, 0xE1, 0x49, 0xFF, 0xD7, 0x8A, 0x5A, 0x00, 0x01, 0xFE, + 0xEA, 0x20, 0x84, 0x01, 0xDD, 0x48, 0xDD, 0x53, 0x5A, 0x00, 0x32, 0x04, 0x48, 0x00, 0x00, 0xDA, + 0x3C, 0x23, 0xF7, 0xA9, 0x84, 0x63, 0x94, 0x91, 0xEA, 0xB3, 0x84, 0x20, 0xFE, 0x9C, 0xDD, 0x42, + 0xEA, 0x2E, 0x96, 0x00, 0xC0, 0x31, 0x84, 0x00, 0xDD, 0x48, 0x84, 0x00, 0x49, 0xFF, 0xE4, 0x49, + 0x84, 0x00, 0x49, 0xFF, 0xD8, 0xC2, 0x49, 0xFF, 0xE4, 0x2E, 0x84, 0x01, 0xEA, 0xF2, 0x84, 0x00, + 0xEA, 0x46, 0xF0, 0x03, 0xEA, 0xA6, 0x84, 0x01, 0xEA, 0x4C, 0xF0, 0x02, 0xEA, 0x75, 0x84, 0x00, + 0xEA, 0x4A, 0x84, 0x00, 0xEA, 0x6E, 0x84, 0x00, 0xEB, 0x01, 0xDD, 0x43, 0xF0, 0x01, 0x83, 0x82, + 0xBB, 0x39, 0xDD, 0x49, 0xEA, 0xCE, 0xFE, 0x1E, 0xFE, 0x0F, 0xB8, 0xB9, 0x44, 0x02, 0x0E, 0x68, + 0xDD, 0x5D, 0x84, 0x03, 0x84, 0x20, 0xEA, 0xBC, 0xDD, 0x53, 0x5A, 0x00, 0x33, 0x04, 0x48, 0x00, + 0x00, 0xF6, 0x48, 0x00, 0x00, 0xDD, 0x9E, 0x79, 0x96, 0x48, 0x5C, 0xF0, 0x80, 0xFE, 0x40, 0x70, + 0x3C, 0x1A, 0x84, 0xC0, 0x50, 0x9F, 0x81, 0xE8, 0xEA, 0x9E, 0x8C, 0x02, 0x88, 0x07, 0xE2, 0xC0, + 0xE8, 0xC3, 0x84, 0x01, 0xEA, 0x65, 0x54, 0xA3, 0x00, 0x01, 0xDD, 0x44, 0xC8, 0x05, 0x4E, 0xA2, + 0x00, 0x03, 0x84, 0x01, 0xEA, 0xCB, 0xEA, 0x8C, 0x49, 0xFF, 0xE4, 0x0E, 0xC8, 0x04, 0xEA, 0x4F, + 0xEA, 0x2E, 0xC0, 0xFB, 0x49, 0xFF, 0xDF, 0xDE, 0x84, 0x00, 0xEA, 0x65, 0x9C, 0x39, 0xE0, 0x06, + 0xE8, 0x74, 0x50, 0x8F, 0x80, 0x38, 0x80, 0x08, 0x3C, 0x13, 0xF7, 0xA9, 0x49, 0xFF, 0xE8, 0x1A, + 0x3D, 0xEC, 0x04, 0x29, 0x44, 0x40, 0x02, 0x88, 0x50, 0x0F, 0x00, 0x01, 0x88, 0x07, 0xF0, 0x85, + 0x9C, 0x3A, 0xF0, 0x86, 0x9C, 0x3B, 0x3D, 0xCC, 0x04, 0x2C, 0x84, 0x20, 0x50, 0x3F, 0x8C, 0x08, + 0xF0, 0x87, 0x42, 0x45, 0x10, 0x24, 0x3C, 0x03, 0xF7, 0xA9, 0xE2, 0x20, 0xE8, 0x56, 0x84, 0x06, + 0x40, 0x20, 0x80, 0x56, 0x84, 0x0C, 0xFE, 0x84, 0xF0, 0x06, 0x96, 0x91, 0x4C, 0x60, 0x40, 0x19, + 0x99, 0x61, 0x38, 0x04, 0x05, 0x11, 0x38, 0x01, 0x95, 0x09, 0x38, 0x04, 0x95, 0x09, 0x5B, 0xE8, + 0x01, 0x42, 0x88, 0x41, 0x94, 0x91, 0x88, 0x5C, 0xA5, 0x50, 0x9A, 0x28, 0x96, 0x01, 0x97, 0x43, + 0x4E, 0x55, 0x00, 0x04, 0xAD, 0x50, 0xD5, 0x36, 0xFE, 0x02, 0xAC, 0x10, 0xD5, 0x33, 0xF0, 0x07, + 0x4C, 0x60, 0x40, 0x0A, 0x98, 0x21, 0x38, 0x24, 0x05, 0x11, 0x38, 0x21, 0x81, 0x09, 0x38, 0x24, + 0x81, 0x09, 0xD5, 0x28, 0x99, 0x61, 0x38, 0x04, 0x05, 0x11, 0x38, 0xA1, 0x95, 0x11, 0xE1, 0x40, + 0xE8, 0x03, 0x38, 0x01, 0x95, 0x09, 0x99, 0x61, 0x38, 0xF4, 0x95, 0x11, 0xE0, 0x0F, 0xE8, 0x03, + 0x38, 0x04, 0x95, 0x09, 0x50, 0x50, 0x82, 0x88, 0x38, 0xA4, 0x85, 0x11, 0x38, 0x01, 0x95, 0x11, + 0x38, 0xF4, 0x95, 0x11, 0xF0, 0x84, 0xF0, 0x05, 0x38, 0x51, 0x85, 0x11, 0x4C, 0x60, 0x40, 0x0B, + 0xF0, 0x04, 0x8A, 0xAA, 0x8A, 0x0F, 0x88, 0x41, 0xE0, 0x05, 0x40, 0x02, 0xBC, 0x1B, 0x38, 0x0E, + 0x09, 0x09, 0x8C, 0x21, 0x96, 0x49, 0xD5, 0xA8, 0x8C, 0xC1, 0x97, 0xB1, 0x48, 0xFF, 0xFF, 0x6E, + 0xDD, 0x53, 0x5A, 0x00, 0x33, 0x04, 0x48, 0xFF, 0xFF, 0x30, 0x84, 0x01, 0xEA, 0x65, 0xEA, 0x2E, + 0xC0, 0x17, 0x84, 0x00, 0xB1, 0x8E, 0xEA, 0x65, 0x80, 0x06, 0x3C, 0x13, 0xF7, 0xA9, 0x49, 0xFF, + 0xE7, 0x99, 0x3C, 0x23, 0xF7, 0xA9, 0x84, 0x63, 0x94, 0x91, 0x84, 0x20, 0xFE, 0x9C, 0xEA, 0xB3, + 0xDD, 0x42, 0x3C, 0x3C, 0x04, 0x2C, 0x84, 0x20, 0x84, 0x86, 0x84, 0xAC, 0xD5, 0x0F, 0x84, 0xC3, + 0xEA, 0x8C, 0x49, 0xFF, 0xE3, 0x69, 0xC8, 0x04, 0xEA, 0x4F, 0xEA, 0x2E, 0xC0, 0xFB, 0x8E, 0xC1, + 0x97, 0xB1, 0x49, 0xFF, 0xDF, 0x37, 0xCE, 0xF5, 0xD5, 0xDD, 0x3C, 0x03, 0xF7, 0xA9, 0xE2, 0x20, + 0x4E, 0xF2, 0xFF, 0x03, 0x40, 0x20, 0x90, 0x56, 0xFE, 0xAC, 0x96, 0x91, 0x88, 0x41, 0x38, 0x03, + 0x05, 0x11, 0x8C, 0x21, 0x38, 0x01, 0x89, 0x09, 0x96, 0x49, 0xD5, 0xF0, 0xEB, 0x1E, 0xEA, 0x36, + 0xD8, 0x15, 0xEA, 0x21, 0x84, 0x20, 0x44, 0x22, 0x0D, 0x5C, 0x38, 0x51, 0x04, 0x00, 0x97, 0x89, + 0x8C, 0xA1, 0xD8, 0x09, 0x97, 0xB0, 0x80, 0x06, 0x84, 0x23, 0xEA, 0x24, 0x80, 0x06, 0x84, 0x20, + 0xEA, 0x24, 0xD5, 0x04, 0x8C, 0x21, 0x5A, 0x18, 0x0A, 0xF2, 0xEA, 0xDE, 0xEA, 0x22, 0x96, 0x06, + 0xC0, 0x03, 0x84, 0x00, 0xEA, 0x26, 0xEA, 0xA9, 0xEA, 0xB1, 0xEA, 0xA4, 0xDD, 0x4D, 0xC8, 0x02, + 0xEA, 0xE5, 0xEA, 0x8B, 0xEA, 0x59, 0x51, 0xFF, 0x96, 0x28, 0xFC, 0xC0, 0xFC, 0x00, 0x84, 0x20, + 0x80, 0xC0, 0xDD, 0x54, 0xEA, 0x2C, 0x84, 0x00, 0x3C, 0x0E, 0x03, 0xE2, 0x3C, 0x0C, 0x03, 0xE2, + 0xE2, 0x06, 0xE8, 0x07, 0x3C, 0x1C, 0x03, 0xE2, 0x8C, 0x21, 0x3C, 0x1E, 0x03, 0xE2, 0xD5, 0xF7, + 0xDD, 0x54, 0x84, 0x21, 0xEA, 0x2C, 0xFC, 0x80, 0xFC, 0x00, 0x49, 0xFF, 0xE1, 0xB1, 0xFC, 0x80, + 0xFC, 0x00, 0xEA, 0x31, 0xFC, 0x80, 0xFC, 0x00, 0x49, 0xFF, 0xD0, 0x57, 0x49, 0xFF, 0xD4, 0x68, + 0x84, 0x01, 0x49, 0xFF, 0xDE, 0xF2, 0x49, 0xFF, 0xDE, 0xDA, 0x84, 0x01, 0x49, 0xFF, 0xDE, 0xED, + 0x49, 0xFF, 0xDE, 0xFD, 0x46, 0x00, 0x03, 0x33, 0x50, 0x00, 0x03, 0x33, 0x49, 0xFF, 0xE0, 0x96, + 0x49, 0xFF, 0xDE, 0xF6, 0x84, 0x0A, 0x49, 0xFF, 0xDE, 0xF9, 0x84, 0x00, 0x49, 0xFF, 0xD5, 0xA6, + 0x84, 0x02, 0x49, 0xFF, 0xD8, 0x2D, 0xEA, 0x58, 0x5A, 0x08, 0x1F, 0x06, 0x84, 0x00, 0xEA, 0x85, + 0x84, 0x04, 0xD5, 0x04, 0x84, 0x00, 0xEA, 0x85, 0x84, 0x00, 0xEA, 0xFC, 0x84, 0x41, 0xEA, 0x53, + 0xEA, 0x43, 0x80, 0x62, 0xDD, 0x40, 0x49, 0xFF, 0xDE, 0xEA, 0x84, 0x00, 0x49, 0xFF, 0xDF, 0x1B, + 0xFC, 0x80, 0xFC, 0x00, 0x84, 0x00, 0xEA, 0x61, 0x84, 0x02, 0x49, 0xFF, 0xD1, 0xB6, 0x84, 0x00, + 0x49, 0xFF, 0xD1, 0xBF, 0x84, 0x02, 0x49, 0xFF, 0xD1, 0xCD, 0x84, 0x00, 0x49, 0xFF, 0xD1, 0xD6, + 0x84, 0x01, 0x49, 0xFF, 0xD1, 0xF3, 0x84, 0x01, 0x49, 0xFF, 0xD2, 0x05, 0xFC, 0x80, 0xFC, 0x00, + 0x84, 0x00, 0xEA, 0x27, 0xDD, 0x4B, 0x84, 0x02, 0xEA, 0x27, 0xDD, 0x4B, 0x84, 0x01, 0xEA, 0x27, + 0xDD, 0x4B, 0x84, 0x03, 0xEA, 0x27, 0xDD, 0x4B, 0xEA, 0x27, 0x84, 0x04, 0xDD, 0x4B, 0x84, 0x01, + 0xEA, 0x46, 0x84, 0x02, 0x84, 0x2A, 0xEB, 0x1F, 0x84, 0x00, 0x84, 0x22, 0xDD, 0x5F, 0x84, 0x00, + 0x84, 0x22, 0xEA, 0x38, 0x84, 0x01, 0x84, 0x22, 0xEA, 0x38, 0x84, 0x02, 0x80, 0x20, 0xEA, 0x38, + 0xFC, 0x80, 0xFC, 0x00, 0x80, 0xC0, 0x49, 0xFF, 0xDE, 0x37, 0x5A, 0x68, 0x01, 0x05, 0x84, 0x00, + 0x80, 0x20, 0xD5, 0x03, 0x84, 0x01, 0x84, 0x20, 0x49, 0xFF, 0xDE, 0x46, 0xFC, 0x80, 0xFC, 0x01, + 0x80, 0xC0, 0xF1, 0x81, 0xEA, 0x31, 0xC6, 0x0C, 0x54, 0x33, 0x00, 0xFD, 0x5A, 0x38, 0x01, 0x09, + 0x84, 0x05, 0xFA, 0x2F, 0x44, 0x20, 0x00, 0x69, 0xF4, 0x01, 0x80, 0xA3, 0xDD, 0x46, 0xFC, 0x81, + 0xFC, 0x00, 0x5A, 0x10, 0x02, 0x04, 0xC9, 0x04, 0x84, 0x03, 0x49, 0xFF, 0xE0, 0x1E, 0x84, 0x46, + 0x44, 0x04, 0x58, 0x90, 0x44, 0x14, 0x55, 0x10, 0x80, 0x62, 0xDD, 0x40, 0xFC, 0x80, 0xFC, 0x00, + 0x84, 0x01, 0x49, 0xFF, 0xD5, 0x53, 0x84, 0x01, 0x49, 0xFF, 0xCF, 0xC9, 0xFA, 0x22, 0x84, 0x01, + 0x49, 0xFF, 0xD3, 0xE9, 0x84, 0x00, 0xEA, 0xEA, 0x84, 0x00, 0xEA, 0x6E, 0x84, 0x01, 0xEA, 0x40, + 0x84, 0x01, 0xEA, 0xEC, 0x84, 0x01, 0x49, 0xFF, 0xD3, 0x03, 0x84, 0x01, 0x49, 0xFF, 0xD9, 0x6B, + 0x84, 0x01, 0xEA, 0x89, 0x84, 0x01, 0xEA, 0x74, 0x84, 0x01, 0xEA, 0x77, 0x49, 0xFF, 0xD3, 0xC8, + 0x84, 0x41, 0x44, 0x10, 0x00, 0x69, 0x84, 0x05, 0xEA, 0x45, 0xEA, 0x31, 0x84, 0x00, 0x84, 0x22, + 0xEA, 0x86, 0x84, 0x00, 0x49, 0xFF, 0xE1, 0x02, 0xEA, 0x58, 0x5A, 0x08, 0x1F, 0x0E, 0xEA, 0x71, + 0xE6, 0x02, 0xE9, 0x0A, 0x84, 0x01, 0x49, 0xFF, 0xE1, 0x06, 0x84, 0x01, 0x49, 0xFF, 0xE1, 0x0F, + 0x84, 0x00, 0x49, 0xFF, 0xE1, 0x18, 0xFC, 0x80, 0xFC, 0x22, 0x44, 0x62, 0x07, 0x00, 0x49, 0xFF, + 0xE1, 0x2D, 0x44, 0x10, 0x79, 0xC0, 0x02, 0x23, 0x00, 0x0D, 0xA6, 0x0E, 0xA6, 0x4F, 0x49, 0xFF, + 0xE1, 0x4D, 0x00, 0x03, 0x00, 0xBB, 0x49, 0xFF, 0xE2, 0x0B, 0x00, 0x03, 0x00, 0x1D, 0x00, 0x13, + 0x00, 0x1C, 0x00, 0x23, 0x00, 0x24, 0x49, 0xFF, 0xE1, 0xB7, 0x22, 0x73, 0x00, 0x09, 0x00, 0x03, + 0x00, 0x25, 0x00, 0x13, 0x00, 0x26, 0x00, 0x23, 0x00, 0x27, 0x00, 0x33, 0x00, 0x28, 0x22, 0x43, + 0x00, 0x07, 0x22, 0x53, 0x00, 0x08, 0xB6, 0xFF, 0x22, 0x73, 0x00, 0x0A, 0xF7, 0x81, 0x22, 0x73, + 0x00, 0x0B, 0xF7, 0x82, 0x22, 0x63, 0x00, 0x0C, 0xF6, 0x83, 0x49, 0xFF, 0xE1, 0x6C, 0x84, 0x00, + 0xEA, 0xF2, 0xFC, 0xA2, 0xFC, 0x02, 0xF0, 0x83, 0xF1, 0x81, 0xFD, 0x01, 0xF2, 0x82, 0xB6, 0x7F, + 0x49, 0xFF, 0xE3, 0x23, 0xF0, 0x01, 0xB4, 0x3F, 0x49, 0xFF, 0xE3, 0x33, 0xF0, 0x03, 0x3C, 0x53, + 0xFA, 0xD3, 0xF1, 0x01, 0xF2, 0x02, 0xB4, 0x7F, 0x3C, 0x4D, 0xFD, 0xA0, 0x49, 0xFF, 0xE3, 0x50, + 0xB4, 0x1F, 0x49, 0xFF, 0xE3, 0x79, 0xFC, 0x82, 0xFC, 0x00, 0x49, 0xFF, 0xDD, 0x58, 0x44, 0x00, + 0x69, 0x22, 0x49, 0xFF, 0xE3, 0x07, 0x84, 0x20, 0x80, 0x61, 0x84, 0x41, 0xDD, 0x57, 0xEA, 0x5C, + 0x84, 0x00, 0x80, 0x20, 0xEA, 0xB6, 0x84, 0x00, 0x80, 0x20, 0x49, 0xFF, 0xD6, 0x48, 0x84, 0x00, + 0x49, 0xFF, 0xE3, 0x95, 0x84, 0x20, 0x84, 0x01, 0xEA, 0xE0, 0x84, 0x00, 0x49, 0xFF, 0xE3, 0x6E, + 0x84, 0x40, 0x84, 0x61, 0x3C, 0x03, 0xF7, 0xE6, 0x84, 0x27, 0xEA, 0x5C, 0x84, 0x00, 0x84, 0x21, + 0xEA, 0xB6, 0x84, 0x01, 0x80, 0x20, 0x49, 0xFF, 0xD6, 0x32, 0x49, 0x00, 0x00, 0x5F, 0xFC, 0x80, + 0xFC, 0x00, 0x80, 0xC0, 0x5A, 0x08, 0x01, 0x0C, 0x84, 0x00, 0x3E, 0x07, 0xF9, 0x02, 0x3C, 0x13, + 0xF7, 0xFC, 0x84, 0x02, 0xEB, 0x19, 0x84, 0x02, 0x80, 0x26, 0xD5, 0x03, 0x84, 0x02, 0x84, 0x20, + 0xEB, 0x4A, 0xFC, 0x80, 0xFC, 0x00, 0x2E, 0x07, 0xF9, 0x02, 0xC0, 0x06, 0x84, 0x02, 0xEA, 0xDC, + 0x84, 0x00, 0x3E, 0x07, 0xF9, 0x02, 0x84, 0x02, 0x49, 0x00, 0x00, 0x6A, 0x5A, 0x08, 0x01, 0x04, + 0x3E, 0x07, 0xF9, 0x01, 0xFC, 0x80, 0xFC, 0x00, 0x49, 0xFF, 0xE3, 0xC0, 0xFC, 0x80, 0xFC, 0x20, + 0x3C, 0x53, 0xFA, 0xD3, 0x80, 0xE0, 0xEA, 0x36, 0x80, 0xC1, 0xD8, 0x0D, 0x49, 0xFF, 0xE3, 0xA8, + 0xFA, 0x4E, 0x42, 0x13, 0x08, 0x24, 0x44, 0x60, 0x00, 0x64, 0x40, 0x03, 0x00, 0x0C, 0x40, 0x10, + 0x80, 0x37, 0xD5, 0x0C, 0x3C, 0x23, 0xFA, 0xD3, 0xFF, 0x94, 0x49, 0xFF, 0xE3, 0x99, 0x44, 0x10, + 0x00, 0x64, 0x40, 0x00, 0x80, 0x0C, 0x40, 0x13, 0x00, 0x37, 0x96, 0x49, 0x5A, 0x78, 0x01, 0x0B, + 0xFE, 0x0B, 0x96, 0x01, 0x49, 0xFF, 0xE3, 0x92, 0x49, 0xFF, 0xE3, 0x9E, 0x49, 0xFF, 0xE3, 0x96, + 0xFC, 0xA0, 0x49, 0xFF, 0xE3, 0xA5, 0xFC, 0xA0, 0x3C, 0x00, 0x08, 0x10, 0x3C, 0x10, 0x08, 0x10, + 0x96, 0x01, 0x4C, 0x00, 0xFF, 0xFB, 0xDD, 0x9E, 0x84, 0x00, 0x3C, 0x0E, 0x03, 0xE7, 0xDD, 0x9E, + 0x44, 0x22, 0x27, 0x68, 0xEB, 0x42, 0xDD, 0x9E, 0xFC, 0x00, 0x80, 0xC0, 0x49, 0xFF, 0xFF, 0xEE, + 0x44, 0x12, 0x27, 0xA8, 0x38, 0x00, 0x99, 0x09, 0xFC, 0x80, 0x80, 0x60, 0x5A, 0x18, 0x01, 0x0E, + 0xFC, 0x20, 0x80, 0xE0, 0x80, 0xC1, 0xEA, 0xDC, 0x3C, 0x0C, 0x03, 0xE7, 0x40, 0x13, 0x1C, 0x0C, + 0xFE, 0x47, 0x3C, 0x1E, 0x03, 0xE7, 0xFC, 0xA0, 0x84, 0x41, 0x3C, 0x0C, 0x03, 0xE7, 0x40, 0x11, + 0x0C, 0x0C, 0xFE, 0x4B, 0xFE, 0x46, 0x3C, 0x1E, 0x03, 0xE7, 0xDD, 0x9E, 0x3C, 0x2C, 0x03, 0xE7, + 0x84, 0x21, 0x40, 0x10, 0x80, 0x0C, 0xFE, 0x56, 0xC9, 0x03, 0x80, 0x01, 0xDD, 0x9E, 0xFC, 0x00, + 0x80, 0xC0, 0x49, 0xFF, 0xFF, 0xC3, 0x44, 0x12, 0x27, 0xA8, 0x44, 0x22, 0x27, 0x68, 0x38, 0x10, + 0x99, 0x01, 0x38, 0x21, 0x19, 0x01, 0x8A, 0x01, 0x96, 0x01, 0xE2, 0x02, 0x56, 0x07, 0x80, 0x01, + 0xFC, 0x80, 0x3C, 0x00, 0x08, 0x10, 0x8C, 0x01, 0x96, 0x01, 0x3C, 0x08, 0x08, 0x10, 0xDD, 0x9E, + 0x3A, 0x1F, 0xA4, 0x3C, 0x3A, 0xFF, 0xBF, 0xBC, 0x42, 0x6E, 0x80, 0x20, 0x3A, 0x6F, 0x98, 0x3C, + 0x64, 0x62, 0xA4, 0x02, 0x9D, 0xB4, 0x64, 0x72, 0x04, 0x02, 0x3A, 0x6F, 0x9C, 0x3C, 0x64, 0x62, + 0x00, 0x02, 0x9F, 0xB2, 0x64, 0x62, 0x00, 0x03, 0x64, 0x00, 0x00, 0x08, 0x49, 0x00, 0x02, 0x62, + 0x3A, 0x6F, 0x9C, 0x04, 0x64, 0x62, 0xA4, 0x03, 0x64, 0x72, 0x04, 0x03, 0x3A, 0x6F, 0x98, 0x04, + 0x42, 0x6E, 0x80, 0x21, 0x3A, 0xFF, 0xBF, 0x84, 0x3A, 0x1F, 0xA4, 0x04, 0x64, 0x00, 0x00, 0x04, + 0x3A, 0x1F, 0xA4, 0x3C, 0x3A, 0xFF, 0xBF, 0xBC, 0x42, 0x6E, 0x80, 0x20, 0x3A, 0x6F, 0x98, 0x3C, + 0x64, 0x62, 0xA4, 0x02, 0x9D, 0xB4, 0x64, 0x72, 0x04, 0x02, 0x3A, 0x6F, 0x9C, 0x3C, 0x64, 0x62, + 0x00, 0x02, 0x9F, 0xB2, 0x64, 0x62, 0x00, 0x03, 0x64, 0x00, 0x00, 0x08, 0x49, 0x00, 0x02, 0x3B, + 0x3A, 0x6F, 0x9C, 0x04, 0x64, 0x62, 0xA4, 0x03, 0x64, 0x72, 0x04, 0x03, 0x3A, 0x6F, 0x98, 0x04, + 0x42, 0x6E, 0x80, 0x21, 0x3A, 0xFF, 0xBF, 0x84, 0x3A, 0x1F, 0xA4, 0x04, 0x64, 0x00, 0x00, 0x04, + 0x3A, 0x1F, 0xA4, 0x3C, 0x3A, 0xFF, 0xBF, 0xBC, 0x42, 0x6E, 0x80, 0x20, 0x3A, 0x6F, 0x98, 0x3C, + 0x64, 0x62, 0xA4, 0x02, 0x9D, 0xB4, 0x64, 0x72, 0x04, 0x02, 0x3A, 0x6F, 0x9C, 0x3C, 0x64, 0x62, + 0x00, 0x02, 0x9F, 0xB2, 0x64, 0x62, 0x00, 0x03, 0x64, 0x00, 0x00, 0x08, 0x49, 0x00, 0x02, 0x14, + 0x3A, 0x6F, 0x9C, 0x04, 0x64, 0x62, 0xA4, 0x03, 0x64, 0x72, 0x04, 0x03, 0x3A, 0x6F, 0x98, 0x04, + 0x42, 0x6E, 0x80, 0x21, 0x3A, 0xFF, 0xBF, 0x84, 0x3A, 0x1F, 0xA4, 0x04, 0x64, 0x00, 0x00, 0x04, + 0x3A, 0x1F, 0xA4, 0x3C, 0x3A, 0xFF, 0xBF, 0xBC, 0x42, 0x6E, 0x80, 0x20, 0x3A, 0x6F, 0x98, 0x3C, + 0x64, 0x62, 0xA4, 0x02, 0x9D, 0xB4, 0x64, 0x72, 0x04, 0x02, 0x3A, 0x6F, 0x9C, 0x3C, 0x64, 0x62, + 0x00, 0x02, 0x9F, 0xB2, 0x64, 0x62, 0x00, 0x03, 0x64, 0x00, 0x00, 0x08, 0x49, 0x00, 0x01, 0xED, + 0x3A, 0x6F, 0x9C, 0x04, 0x64, 0x62, 0xA4, 0x03, 0x64, 0x72, 0x04, 0x03, 0x3A, 0x6F, 0x98, 0x04, + 0x42, 0x6E, 0x80, 0x21, 0x3A, 0xFF, 0xBF, 0x84, 0x3A, 0x1F, 0xA4, 0x04, 0x64, 0x00, 0x00, 0x04, + 0x3A, 0x1F, 0xA4, 0x3C, 0x3A, 0xFF, 0xBF, 0xBC, 0x42, 0x6E, 0x80, 0x20, 0x3A, 0x6F, 0x98, 0x3C, + 0x64, 0x62, 0xA4, 0x02, 0x9D, 0xB4, 0x64, 0x72, 0x04, 0x02, 0x3A, 0x6F, 0x9C, 0x3C, 0x64, 0x62, + 0x00, 0x02, 0x9F, 0xB2, 0x64, 0x62, 0x00, 0x03, 0x64, 0x00, 0x00, 0x08, 0x49, 0x00, 0x01, 0xC6, + 0x3A, 0x6F, 0x9C, 0x04, 0x64, 0x62, 0xA4, 0x03, 0x64, 0x72, 0x04, 0x03, 0x3A, 0x6F, 0x98, 0x04, + 0x42, 0x6E, 0x80, 0x21, 0x3A, 0xFF, 0xBF, 0x84, 0x3A, 0x1F, 0xA4, 0x04, 0x64, 0x00, 0x00, 0x04, + 0x3A, 0x1F, 0xA4, 0x3C, 0x3A, 0xFF, 0xBF, 0xBC, 0x42, 0x6E, 0x80, 0x20, 0x3A, 0x6F, 0x98, 0x3C, + 0x64, 0x62, 0xA4, 0x02, 0x9D, 0xB4, 0x64, 0x72, 0x04, 0x02, 0x3A, 0x6F, 0x9C, 0x3C, 0x64, 0x62, + 0x00, 0x02, 0x9F, 0xB2, 0x64, 0x62, 0x00, 0x03, 0x64, 0x00, 0x00, 0x08, 0x49, 0x00, 0x01, 0x9F, + 0x3A, 0x6F, 0x9C, 0x04, 0x64, 0x62, 0xA4, 0x03, 0x64, 0x72, 0x04, 0x03, 0x3A, 0x6F, 0x98, 0x04, + 0x42, 0x6E, 0x80, 0x21, 0x3A, 0xFF, 0xBF, 0x84, 0x3A, 0x1F, 0xA4, 0x04, 0x64, 0x00, 0x00, 0x04, + 0x3A, 0x1F, 0xA4, 0x3C, 0x3A, 0xFF, 0xBF, 0xBC, 0x42, 0x6E, 0x80, 0x20, 0x3A, 0x6F, 0x98, 0x3C, + 0x64, 0x62, 0xA4, 0x02, 0x9D, 0xB4, 0x64, 0x72, 0x04, 0x02, 0x3A, 0x6F, 0x9C, 0x3C, 0x64, 0x62, + 0x00, 0x02, 0x9F, 0xB2, 0x64, 0x62, 0x00, 0x03, 0x64, 0x00, 0x00, 0x08, 0x49, 0x00, 0x01, 0x78, + 0x3A, 0x6F, 0x9C, 0x04, 0x64, 0x62, 0xA4, 0x03, 0x64, 0x72, 0x04, 0x03, 0x3A, 0x6F, 0x98, 0x04, + 0x42, 0x6E, 0x80, 0x21, 0x3A, 0xFF, 0xBF, 0x84, 0x3A, 0x1F, 0xA4, 0x04, 0x64, 0x00, 0x00, 0x04, + 0x3A, 0x1F, 0xA4, 0x3C, 0x3A, 0xFF, 0xBF, 0xBC, 0x42, 0x6E, 0x80, 0x20, 0x3A, 0x6F, 0x98, 0x3C, + 0x64, 0x62, 0xA4, 0x02, 0x9D, 0xB4, 0x64, 0x72, 0x04, 0x02, 0x3A, 0x6F, 0x9C, 0x3C, 0x64, 0x62, + 0x00, 0x02, 0x9F, 0xB2, 0x64, 0x62, 0x00, 0x03, 0x64, 0x00, 0x00, 0x08, 0x49, 0x00, 0x01, 0x51, + 0x3A, 0x6F, 0x9C, 0x04, 0x64, 0x62, 0xA4, 0x03, 0x64, 0x72, 0x04, 0x03, 0x3A, 0x6F, 0x98, 0x04, + 0x42, 0x6E, 0x80, 0x21, 0x3A, 0xFF, 0xBF, 0x84, 0x3A, 0x1F, 0xA4, 0x04, 0x64, 0x00, 0x00, 0x04, + 0x3A, 0x1F, 0x94, 0x3C, 0x3A, 0xFF, 0xBF, 0xBC, 0x42, 0x2E, 0x80, 0x20, 0x3A, 0x2F, 0x8C, 0x3C, + 0x64, 0x12, 0xA4, 0x02, 0x64, 0x22, 0x04, 0x02, 0x3A, 0x1F, 0x88, 0x3C, 0x64, 0x12, 0x00, 0x02, + 0x9E, 0x4A, 0x64, 0x12, 0x00, 0x03, 0x44, 0x10, 0x00, 0xA4, 0x38, 0x10, 0x82, 0x02, 0xDD, 0x21, + 0x3A, 0x0F, 0x84, 0x04, 0x64, 0x02, 0x00, 0x43, 0x64, 0x00, 0x00, 0x08, 0x64, 0x02, 0xA4, 0x03, + 0x64, 0x12, 0x04, 0x03, 0x3A, 0x2F, 0x8C, 0x04, 0x42, 0x2E, 0x80, 0x21, 0x3A, 0xFF, 0xBF, 0x84, + 0x3A, 0x1F, 0x94, 0x04, 0x3A, 0x0F, 0x80, 0x04, 0x64, 0x00, 0x00, 0x04, 0x3A, 0x1F, 0x94, 0x3C, + 0x3A, 0xFF, 0xBF, 0xBC, 0x42, 0x2E, 0x80, 0x20, 0x3A, 0x2F, 0x8C, 0x3C, 0x44, 0x10, 0x00, 0xA4, + 0x38, 0x10, 0x82, 0x02, 0xDD, 0x21, 0x3A, 0x2F, 0x8C, 0x04, 0x42, 0x2E, 0x80, 0x21, 0x3A, 0xFF, + 0xBF, 0x84, 0x3A, 0x1F, 0x94, 0x04, 0x3A, 0x0F, 0x80, 0x04, 0x64, 0x00, 0x00, 0x04, 0xD5, 0x00, + 0x3A, 0x0F, 0x80, 0x3C, 0x84, 0x00, 0xD5, 0xE3, 0x3A, 0x0F, 0x80, 0x3C, 0x84, 0x01, 0xD5, 0xDF, + 0x3A, 0x0F, 0x80, 0x3C, 0x84, 0x02, 0xD5, 0xDB, 0x3A, 0x0F, 0x80, 0x3C, 0x84, 0x03, 0xD5, 0xD7, + 0x3A, 0x0F, 0x80, 0x3C, 0x84, 0x04, 0xD5, 0xD3, 0x3A, 0x0F, 0x80, 0x3C, 0x84, 0x05, 0xD5, 0xCF, + 0x3A, 0x0F, 0x80, 0x3C, 0x84, 0x06, 0xD5, 0xCB, 0x3A, 0x0F, 0x80, 0x3C, 0x84, 0x07, 0xD5, 0xC7, + 0x3A, 0x0F, 0x80, 0x3C, 0x84, 0x08, 0xD5, 0xC3, 0x3A, 0x0F, 0x80, 0x3C, 0x84, 0x09, 0xD5, 0xBF, + 0x3A, 0x0F, 0x80, 0x3C, 0x84, 0x0A, 0xD5, 0xBB, 0x3A, 0x0F, 0x80, 0x3C, 0x84, 0x0B, 0xD5, 0xB7, + 0x3A, 0x0F, 0x80, 0x3C, 0x84, 0x0C, 0xD5, 0xB3, 0x3A, 0x0F, 0x80, 0x3C, 0x84, 0x0D, 0xD5, 0xAF, + 0x3A, 0x0F, 0x80, 0x3C, 0x84, 0x0E, 0xD5, 0xAB, 0x3A, 0x0F, 0x80, 0x3C, 0x84, 0x0F, 0xD5, 0xA7, + 0x3A, 0x0F, 0x80, 0x3C, 0xFA, 0x00, 0xD5, 0xA3, 0x3A, 0x0F, 0x80, 0x3C, 0xFA, 0x01, 0xD5, 0x9F, + 0x3A, 0x0F, 0x80, 0x3C, 0xFA, 0x02, 0xD5, 0x9B, 0x3A, 0x0F, 0x80, 0x3C, 0xFA, 0x03, 0xD5, 0x97, + 0x3A, 0x0F, 0x80, 0x3C, 0xFA, 0x04, 0xD5, 0x93, 0x3A, 0x0F, 0x80, 0x3C, 0xFA, 0x05, 0xD5, 0x8F, + 0x3A, 0x0F, 0x80, 0x3C, 0xFA, 0x06, 0xD5, 0x8B, 0x3A, 0x0F, 0x80, 0x3C, 0xFA, 0x07, 0xD5, 0x87, + 0x3A, 0x0F, 0x80, 0x3C, 0xFA, 0x08, 0xD5, 0x83, 0x3A, 0x0F, 0x80, 0x3C, 0xFA, 0x09, 0x48, 0xFF, + 0xFF, 0x7F, 0x3A, 0x0F, 0x80, 0x3C, 0xFA, 0x0A, 0x48, 0xFF, 0xFF, 0x7A, 0x3A, 0x0F, 0x80, 0x3C, + 0xFA, 0x0B, 0x48, 0xFF, 0xFF, 0x75, 0x3A, 0x0F, 0x80, 0x3C, 0xFA, 0x0C, 0x48, 0xFF, 0xFF, 0x70, + 0x3A, 0x0F, 0x80, 0x3C, 0xFA, 0x0D, 0x48, 0xFF, 0xFF, 0x6B, 0x3A, 0x0F, 0x80, 0x3C, 0xFA, 0x0E, + 0x48, 0xFF, 0xFF, 0x66, 0x3A, 0x0F, 0x80, 0x3C, 0x44, 0x00, 0x00, 0x1F, 0x48, 0xFF, 0xFF, 0x60, + 0x84, 0x01, 0x64, 0x04, 0xC0, 0x02, 0x44, 0x02, 0x00, 0x01, 0x64, 0x04, 0xE0, 0x03, 0x45, 0xD2, + 0x17, 0xC8, 0x3F, 0xC8, 0x00, 0x00, 0x45, 0xF2, 0x77, 0xF8, 0x44, 0x00, 0x74, 0x80, 0x42, 0x0E, + 0x00, 0x21, 0x49, 0x00, 0x00, 0x44, 0x49, 0x00, 0x03, 0x05, 0xD5, 0x00, 0xFC, 0x00, 0xDD, 0x54, + 0x84, 0x20, 0x49, 0xFF, 0xD1, 0x5C, 0xDD, 0x54, 0x84, 0x20, 0x49, 0xFF, 0xD1, 0x6D, 0x84, 0x21, + 0xDD, 0x54, 0xEA, 0x2C, 0x84, 0x00, 0x49, 0xFF, 0xD1, 0xB7, 0x44, 0x02, 0x07, 0x00, 0x44, 0x22, + 0x0F, 0x50, 0x44, 0x10, 0x7B, 0x00, 0x8A, 0x40, 0xEA, 0x41, 0xEA, 0x58, 0x5A, 0x08, 0x1C, 0x08, + 0x84, 0x00, 0x49, 0xFF, 0xDD, 0x5A, 0xEA, 0xB9, 0xFA, 0x30, 0xAE, 0x40, 0x44, 0x02, 0x0F, 0x50, + 0x44, 0x22, 0x28, 0x9C, 0x84, 0x20, 0x8A, 0x40, 0xDD, 0x42, 0xFC, 0x80, 0x84, 0x00, 0x64, 0x05, + 0xE4, 0x03, 0x84, 0x1F, 0x64, 0x03, 0x04, 0x03, 0x64, 0x03, 0x24, 0x03, 0x64, 0x12, 0x24, 0x02, + 0x44, 0x0F, 0x0F, 0xFF, 0xFE, 0x0E, 0x64, 0x02, 0x24, 0x03, 0x64, 0x12, 0x00, 0x02, 0x84, 0x18, + 0xFE, 0x0E, 0x64, 0x02, 0x00, 0x03, 0xEA, 0x66, 0xDD, 0x9E, 0xFC, 0x00, 0x49, 0xFF, 0xFF, 0xE8, + 0x64, 0x00, 0x80, 0x02, 0x92, 0x1E, 0xC0, 0x06, 0x64, 0x00, 0x84, 0x02, 0x96, 0x2E, 0xC0, 0x02, + 0xD5, 0x00, 0x49, 0xFF, 0xFF, 0xB5, 0x64, 0x12, 0x00, 0x43, 0xEA, 0x66, 0xEA, 0x66, 0xFC, 0x80, + 0xDD, 0x9E, 0xDD, 0x9E, 0xDD, 0x9E, 0xDD, 0x9E, 0xDD, 0x9E, 0xDD, 0x9E, 0xDD, 0x9E, 0xDD, 0x9E, + 0xDD, 0x9E, 0x44, 0x04, 0x80, 0x04, 0xB4, 0x00, 0x92, 0x08, 0x96, 0x06, 0xC0, 0x05, 0x44, 0x04, + 0x80, 0x05, 0x84, 0x21, 0xAE, 0x40, 0xDD, 0x9E, 0xFC, 0x01, 0xEA, 0x50, 0x44, 0x14, 0x80, 0x81, + 0xA6, 0x00, 0xA6, 0x48, 0xFE, 0x0E, 0xEA, 0x63, 0xEA, 0xD3, 0xC0, 0x03, 0x49, 0xFF, 0xD9, 0x28, + 0xFC, 0x81, 0xFC, 0x00, 0xEA, 0xE6, 0xB4, 0x00, 0x49, 0xFF, 0xE0, 0x41, 0xFC, 0x80, 0x44, 0x14, + 0x80, 0x04, 0x44, 0x04, 0x80, 0x84, 0xB4, 0x41, 0xB4, 0x00, 0x96, 0x06, 0xFE, 0x16, 0xC0, 0x03, + 0x84, 0x01, 0xAE, 0x08, 0xDD, 0x9E, 0xFC, 0x00, 0xEA, 0xE6, 0xB4, 0x00, 0x49, 0xFF, 0xE0, 0x42, + 0xFC, 0x80, 0x44, 0x04, 0x80, 0x14, 0xB4, 0x20, 0x96, 0x46, 0xC1, 0x03, 0x84, 0x21, 0xAE, 0x40, + 0xB4, 0x00, 0x92, 0x01, 0x96, 0x06, 0xC0, 0x05, 0x44, 0x04, 0x80, 0x14, 0x84, 0x22, 0xAE, 0x40, + 0xDD, 0x9E, 0xFC, 0x00, 0x49, 0xFF, 0xCD, 0xF3, 0xFC, 0x80, 0x44, 0x04, 0x80, 0x04, 0xB4, 0x00, + 0x92, 0x13, 0x96, 0x06, 0xC0, 0x04, 0xEA, 0x7C, 0x84, 0x28, 0xAE, 0x40, 0xDD, 0x9E, 0x44, 0x14, + 0x80, 0x04, 0xB4, 0x01, 0x92, 0x19, 0x96, 0x06, 0xC0, 0x04, 0xEA, 0x7D, 0x84, 0x42, 0xAE, 0x80, + 0xB4, 0x01, 0x92, 0x18, 0x96, 0x06, 0xC0, 0x04, 0xEA, 0x7D, 0x84, 0x21, 0xAE, 0x40, 0x44, 0x14, + 0x80, 0x04, 0xB4, 0x01, 0x92, 0x1A, 0x96, 0x06, 0xC0, 0x04, 0xEA, 0x7D, 0x84, 0x44, 0xAE, 0x80, + 0xB4, 0x01, 0x92, 0x1B, 0x96, 0x06, 0xC0, 0x04, 0xEA, 0x7D, 0x84, 0x28, 0xAE, 0x40, 0xEB, 0x0F, + 0xB4, 0x00, 0x92, 0x1C, 0x96, 0x06, 0xC0, 0x04, 0xEA, 0x7D, 0xFA, 0x20, 0xAE, 0x40, 0xDD, 0x9E, + 0x44, 0x04, 0x80, 0x08, 0xB4, 0x20, 0x92, 0x24, 0x96, 0x46, 0xC1, 0x03, 0xFA, 0x20, 0xAE, 0x40, + 0xB4, 0x00, 0x84, 0x21, 0x96, 0x06, 0xC0, 0x05, 0xEA, 0x35, 0xAE, 0x40, 0x3E, 0x17, 0xF9, 0x0A, + 0xEA, 0x35, 0xB4, 0x20, 0x92, 0x21, 0x96, 0x46, 0xC1, 0x06, 0x84, 0x22, 0xAE, 0x40, 0x84, 0x21, + 0x3E, 0x17, 0xF9, 0x09, 0xB4, 0x00, 0x92, 0x02, 0x96, 0x06, 0xC0, 0x04, 0xEA, 0x35, 0x84, 0x24, + 0xAE, 0x40, 0x44, 0x04, 0x80, 0x14, 0xB4, 0x00, 0x92, 0x08, 0x96, 0x06, 0xC0, 0x05, 0x44, 0x04, + 0x80, 0x15, 0x84, 0x21, 0xAE, 0x40, 0xDD, 0x9E, 0x44, 0x04, 0x80, 0x9C, 0xB4, 0x00, 0x92, 0x02, + 0x96, 0x06, 0xC0, 0x08, 0xEB, 0x15, 0xB4, 0x01, 0x92, 0x02, 0x96, 0x06, 0xC0, 0x03, 0x84, 0x04, + 0xAE, 0x08, 0xDD, 0x9E, 0xFC, 0x00, 0x49, 0xFF, 0xCC, 0x7B, 0xFC, 0x80, 0xFC, 0x00, 0x49, 0xFF, + 0xCC, 0x85, 0xFC, 0x80, 0xFC, 0x00, 0x49, 0xFF, 0xCC, 0x82, 0xFC, 0x80, 0x44, 0x14, 0x80, 0x08, + 0xB4, 0x01, 0x92, 0x08, 0x96, 0x06, 0xC0, 0x04, 0xEA, 0xB9, 0x84, 0x41, 0xAE, 0x80, 0xB4, 0x01, + 0x92, 0x09, 0x96, 0x06, 0xC0, 0x04, 0xEA, 0xB9, 0x84, 0x22, 0xAE, 0x40, 0x44, 0x14, 0x80, 0x08, + 0xB4, 0x01, 0x40, 0x20, 0x34, 0x09, 0xEA, 0x9A, 0xB4, 0x00, 0x92, 0x0D, 0x96, 0x06, 0xFE, 0x16, + 0xC0, 0x08, 0xEA, 0xB9, 0xFA, 0x50, 0xAE, 0x80, 0xB4, 0x01, 0x92, 0x0D, 0x96, 0x06, 0xC8, 0xFD, + 0xDD, 0x9E, 0xFC, 0x00, 0xEA, 0x35, 0xB4, 0x00, 0x92, 0x12, 0x96, 0x06, 0xC0, 0x4C, 0x44, 0x14, + 0x80, 0x88, 0xB4, 0x01, 0x92, 0x12, 0x96, 0x06, 0xC0, 0x46, 0xEA, 0x7A, 0x84, 0x44, 0xAE, 0x80, + 0xB4, 0x41, 0x44, 0x0D, 0xFF, 0xFF, 0xFE, 0x16, 0x44, 0x67, 0x30, 0x04, 0xB6, 0x01, 0xB4, 0x26, + 0x84, 0x1E, 0xFE, 0x0E, 0xB6, 0x06, 0x84, 0x0A, 0xDD, 0x51, 0xB4, 0x06, 0xDD, 0x45, 0xB6, 0x06, + 0x84, 0x0A, 0xDD, 0x51, 0x49, 0xFF, 0xDD, 0xD9, 0x44, 0x00, 0x00, 0x87, 0x49, 0xFF, 0xDD, 0xCF, + 0xEA, 0xF3, 0xB4, 0x01, 0x96, 0x06, 0xC0, 0xFE, 0xEA, 0xF3, 0xB4, 0x01, 0x92, 0x03, 0x96, 0x06, + 0x5A, 0x00, 0x01, 0xFD, 0x44, 0x67, 0x30, 0x04, 0x84, 0x0A, 0xDD, 0x51, 0xB4, 0x26, 0x84, 0x1E, + 0xFE, 0x0E, 0xB6, 0x06, 0x84, 0x0A, 0xDD, 0x51, 0xB4, 0x06, 0xDD, 0x45, 0xB6, 0x06, 0x84, 0x0A, + 0xDD, 0x51, 0x44, 0x14, 0x80, 0x88, 0x84, 0x01, 0x3E, 0x07, 0xF9, 0x10, 0xB4, 0x41, 0xEA, 0xA2, + 0xFE, 0x17, 0xB6, 0x01, 0xEA, 0x7A, 0x84, 0x22, 0xAE, 0x40, 0x3C, 0x0D, 0xFE, 0x43, 0x8C, 0x01, + 0x3C, 0x0F, 0xFE, 0x43, 0xEA, 0x35, 0x84, 0x21, 0xB4, 0x00, 0x92, 0x10, 0x96, 0x06, 0xC0, 0x0A, + 0xEA, 0x9A, 0xB4, 0x00, 0x92, 0x10, 0x96, 0x06, 0xC0, 0x05, 0xEA, 0x7A, 0x3E, 0x17, 0xF9, 0x11, + 0xAE, 0x40, 0xEA, 0x35, 0xB4, 0x00, 0x92, 0x11, 0x96, 0x06, 0xC0, 0x09, 0xEA, 0x9A, 0xB4, 0x00, + 0x92, 0x11, 0x96, 0x06, 0xC0, 0x04, 0xEA, 0x7A, 0x84, 0x22, 0xAE, 0x40, 0xFC, 0x80, 0xFC, 0x00, + 0x44, 0x14, 0x80, 0x08, 0x80, 0xC1, 0xB4, 0x01, 0x92, 0x18, 0x96, 0x06, 0xC0, 0x05, 0xEA, 0xAB, + 0x84, 0x21, 0xAE, 0x40, 0xEA, 0x39, 0xB4, 0x06, 0x92, 0x19, 0x96, 0x06, 0xC0, 0x0C, 0xEA, 0xAB, + 0x84, 0x22, 0xAE, 0x40, 0xEA, 0x39, 0xC8, 0x07, 0xEA, 0x2D, 0xDD, 0x52, 0x83, 0x81, 0xBA, 0x1C, + 0xFE, 0x16, 0xB8, 0x9C, 0xEA, 0x35, 0xB4, 0x00, 0x92, 0x1A, 0x96, 0x06, 0xC0, 0x0C, 0x44, 0x14, + 0x70, 0x08, 0xB4, 0x01, 0x92, 0x10, 0xDD, 0x4E, 0x58, 0x00, 0x78, 0x23, 0xB6, 0x01, 0xEA, 0xAB, + 0x84, 0x24, 0xAE, 0x40, 0xEA, 0x35, 0xB4, 0x00, 0x92, 0x1B, 0x96, 0x06, 0xC0, 0x04, 0xEA, 0xAB, + 0x84, 0x28, 0xAE, 0x40, 0xFC, 0x80, 0x44, 0x04, 0x80, 0x04, 0xB4, 0x00, 0x92, 0x14, 0x96, 0x06, + 0xC0, 0x04, 0xEA, 0x7C, 0xFA, 0x20, 0xAE, 0x40, 0xDD, 0x9E, 0xDD, 0x9E, 0xDD, 0x9E, 0xDD, 0x9E, + 0x44, 0x14, 0x80, 0x1C, 0xB4, 0x01, 0x92, 0x03, 0x96, 0x06, 0xC0, 0x03, 0x84, 0x08, 0xAE, 0x08, + 0xDD, 0x9E, 0x44, 0x14, 0x80, 0x1C, 0xB4, 0x01, 0x92, 0x01, 0x96, 0x06, 0xC0, 0x03, 0x84, 0x02, + 0xAE, 0x08, 0xEA, 0x5A, 0xB4, 0x00, 0x92, 0x0C, 0x96, 0x06, 0xC0, 0x04, 0xEA, 0xD4, 0xFA, 0x20, + 0xAE, 0x40, 0xDD, 0x9E, 0x44, 0x24, 0x80, 0x10, 0x84, 0x01, 0xB4, 0x22, 0x96, 0x46, 0xC1, 0x06, + 0x3E, 0x07, 0xF7, 0x98, 0xAE, 0x10, 0x3E, 0x07, 0xF9, 0x05, 0xDD, 0x9E, 0xFC, 0x00, 0xEA, 0x5A, + 0xB4, 0x00, 0x92, 0x0A, 0x96, 0x06, 0xC0, 0x0D, 0xEA, 0xD4, 0x84, 0x24, 0xAE, 0x40, 0x49, 0xFF, + 0xCF, 0x2D, 0x44, 0x07, 0x20, 0x00, 0xB4, 0x00, 0x92, 0x08, 0x96, 0x06, 0x49, 0xFF, 0xCE, 0x7C, + 0xEB, 0x15, 0xB4, 0x01, 0x92, 0x05, 0x96, 0x06, 0xC0, 0x03, 0xFA, 0x10, 0xAE, 0x08, 0xFC, 0x80, + 0x44, 0x14, 0x80, 0x10, 0xB4, 0x01, 0x92, 0x07, 0x96, 0x06, 0xC0, 0x07, 0x44, 0x0F, 0xFF, 0x80, + 0xAE, 0x08, 0x84, 0x01, 0x3E, 0x07, 0xF7, 0xA0, 0xDD, 0x9E, 0x44, 0x04, 0x80, 0x10, 0xB4, 0x20, + 0x92, 0x25, 0x96, 0x46, 0xC1, 0x06, 0xFA, 0x30, 0xAE, 0x40, 0x84, 0x21, 0x3E, 0x17, 0xF7, 0x8B, + 0xB4, 0x00, 0x92, 0x06, 0x96, 0x06, 0xC0, 0x07, 0xEA, 0x5A, 0xEB, 0x22, 0xAE, 0x40, 0x84, 0x01, + 0x3E, 0x07, 0xF7, 0x89, 0xDD, 0x9E, 0x44, 0x24, 0x80, 0x10, 0x84, 0x21, 0xB4, 0x02, 0x92, 0x04, + 0x96, 0x06, 0xC0, 0x12, 0xFC, 0x00, 0xFA, 0x00, 0x3E, 0x17, 0xF7, 0x99, 0xAE, 0x10, 0xDD, 0x56, + 0x3E, 0x17, 0xF9, 0x04, 0x3E, 0x17, 0xF9, 0x02, 0x04, 0x00, 0x00, 0xF0, 0x92, 0x03, 0x96, 0x06, + 0x49, 0xFF, 0xCE, 0x3A, 0xFC, 0x80, 0xDD, 0x9E, 0x44, 0x04, 0x80, 0x10, 0xB4, 0x20, 0x92, 0x23, + 0x96, 0x46, 0xC1, 0x03, 0x84, 0x28, 0xAE, 0x40, 0xB4, 0x00, 0x92, 0x02, 0x96, 0x06, 0xC0, 0x04, + 0xEA, 0x5A, 0x84, 0x24, 0xAE, 0x40, 0x44, 0x04, 0x80, 0x1C, 0xB4, 0x20, 0x96, 0x46, 0xC1, 0x03, + 0x84, 0x21, 0xAE, 0x40, 0xB4, 0x00, 0x92, 0x06, 0x96, 0x06, 0xC0, 0x05, 0x44, 0x04, 0x80, 0x1C, + 0xEB, 0x22, 0xAE, 0x40, 0xDD, 0x9E, 0x44, 0x14, 0x80, 0x10, 0xB4, 0x01, 0x92, 0x01, 0x96, 0x06, + 0xC0, 0x0C, 0x44, 0x04, 0x80, 0x90, 0xB4, 0x00, 0x92, 0x01, 0x96, 0x06, 0x5A, 0x08, 0x01, 0x06, + 0x84, 0x42, 0xAE, 0x88, 0x3E, 0x07, 0xF9, 0x00, 0xDD, 0x9E, 0x44, 0x04, 0x80, 0x10, 0xB4, 0x00, + 0x92, 0x0B, 0x96, 0x06, 0xC0, 0x04, 0xEA, 0xD4, 0x84, 0x28, 0xAE, 0x40, 0xEB, 0x15, 0xB4, 0x01, + 0x92, 0x04, 0x96, 0x06, 0xC0, 0x03, 0xFA, 0x00, 0xAE, 0x08, 0xDD, 0x9E, 0x84, 0x2A, 0xFE, 0x0C, + 0x8E, 0x01, 0x5A, 0x07, 0xFF, 0x04, 0xEA, 0xF6, 0xD5, 0xFC, 0xDD, 0x9E, 0x44, 0x15, 0x00, 0x08, + 0xB4, 0x21, 0x96, 0x46, 0xC1, 0x2D, 0x44, 0x25, 0x00, 0x04, 0xB4, 0x22, 0x96, 0x49, 0xC1, 0x28, + 0xFC, 0x02, 0xB4, 0x22, 0x96, 0x49, 0xFE, 0x0C, 0xB6, 0x1F, 0xB4, 0x02, 0x92, 0x10, 0xF0, 0x81, + 0x84, 0x00, 0xF0, 0x83, 0xB4, 0x02, 0x92, 0x10, 0xF0, 0x82, 0xF1, 0x01, 0xF0, 0x02, 0xE2, 0x20, + 0xE9, 0x07, 0xF1, 0x01, 0xF3, 0x02, 0xF0, 0x03, 0x88, 0x01, 0x8A, 0x03, 0xD5, 0x09, 0xF3, 0x01, + 0xF4, 0x02, 0xB4, 0x22, 0xF0, 0x03, 0x96, 0x49, 0x88, 0x03, 0x88, 0x01, 0x8A, 0x04, 0xF0, 0x83, + 0xF1, 0x03, 0xB4, 0x1F, 0xE2, 0x20, 0xE8, 0x0D, 0xF0, 0x02, 0xF0, 0x81, 0xD5, 0xE4, 0x44, 0x10, + 0x29, 0xCC, 0xFE, 0x0C, 0x8E, 0x01, 0x5A, 0x07, 0xFF, 0x04, 0xEA, 0xF6, 0xD5, 0xFC, 0xDD, 0x9E, + 0xFC, 0x82, 0xFC, 0x00, 0x44, 0x11, 0x86, 0xA0, 0x84, 0x00, 0x49, 0xFF, 0xFA, 0x6A, 0x84, 0x01, + 0x49, 0xFF, 0xD6, 0xD6, 0x49, 0xFF, 0xD0, 0xB7, 0x49, 0xFF, 0xE2, 0x79, 0x84, 0x01, 0x49, 0xFF, + 0xD7, 0xBB, 0xEA, 0x31, 0x49, 0xFF, 0xC7, 0xA6, 0x49, 0xFF, 0xC8, 0x6A, 0x84, 0x00, 0xFC, 0x80, + 0xFC, 0x00, 0x49, 0xFF, 0xFF, 0xE8, 0x84, 0x00, 0xFC, 0x80, 0xC2, 0x13, 0x52, 0x31, 0x00, 0x20, + 0x4E, 0x36, 0x00, 0x07, 0xFE, 0xDA, 0x84, 0x80, 0x40, 0x00, 0x8C, 0x0D, 0xD5, 0x09, 0x40, 0x40, + 0x88, 0x0D, 0x40, 0x30, 0x8C, 0x0C, 0x40, 0x20, 0x08, 0x0D, 0x40, 0x01, 0x88, 0x04, 0x80, 0x24, + 0xDD, 0x9E, 0xC2, 0x12, 0x52, 0x31, 0x00, 0x20, 0x4E, 0x36, 0x00, 0x07, 0xFE, 0xDA, 0x84, 0x80, + 0x40, 0x10, 0x0C, 0x0C, 0xD5, 0x08, 0x40, 0x30, 0x0C, 0x0D, 0x40, 0x10, 0x88, 0x0C, 0x40, 0x40, + 0x08, 0x0C, 0xFE, 0x5F, 0x80, 0x04, 0xDD, 0x9E, 0x80, 0x60, 0xE6, 0x44, 0xE9, 0x1C, 0x54, 0x41, + 0x80, 0x03, 0x54, 0x50, 0x80, 0x03, 0xDC, 0x17, 0x4E, 0x52, 0x00, 0x0C, 0x52, 0x52, 0x80, 0x04, + 0x9A, 0x95, 0x99, 0x69, 0x08, 0x40, 0x80, 0x01, 0x18, 0x41, 0x80, 0x01, 0x4C, 0x12, 0xFF, 0xFC, + 0x40, 0x51, 0x08, 0x09, 0xC5, 0x08, 0x95, 0x6A, 0x99, 0x69, 0x96, 0x8F, 0xA3, 0x09, 0xAB, 0x19, + 0x4C, 0x12, 0xFF, 0xFE, 0xC2, 0x08, 0x99, 0x4A, 0x08, 0x40, 0x80, 0x01, 0x18, 0x41, 0x80, 0x01, + 0x4C, 0x12, 0xFF, 0xFC, 0xDD, 0x9E, 0x92, 0x00, 0x80, 0x60, 0xE6, 0x44, 0xE9, 0x1C, 0x54, 0x51, + 0x80, 0x03, 0xC5, 0x09, 0x52, 0x52, 0x80, 0x04, 0x9A, 0x95, 0x99, 0x68, 0x18, 0x11, 0x80, 0x01, + 0x4C, 0x32, 0xFF, 0xFE, 0x96, 0x48, 0x40, 0x40, 0xA0, 0x08, 0xFE, 0x67, 0x40, 0x40, 0xC0, 0x08, + 0x40, 0x10, 0x90, 0x04, 0x40, 0x51, 0x08, 0x09, 0xC5, 0x06, 0x95, 0x6A, 0x99, 0x6B, 0x96, 0x8F, + 0xAA, 0x59, 0xDB, 0xFF, 0xC2, 0x06, 0x99, 0x5A, 0x18, 0x11, 0x80, 0x01, 0x4C, 0x32, 0xFF, 0xFE, + 0xDD, 0x9E, 0x92, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x49, 0x00, 0x09, 0x77, 0x50, 0x00, 0x0F, 0xFF, 0x49, 0x00, 0x3A, 0x14, 0x46, 0x20, 0x00, 0x81, + 0x49, 0x00, 0x1B, 0x1F, 0x58, 0x00, 0x00, 0x01, 0x49, 0x00, 0x15, 0xFA, 0x40, 0x00, 0x28, 0x08, + 0x49, 0x00, 0x23, 0x18, 0x40, 0x10, 0x40, 0x08, 0x50, 0x10, 0x8F, 0xFF, 0x49, 0x00, 0x0D, 0x6D, + 0x40, 0x00, 0x20, 0x08, 0x2E, 0x00, 0x10, 0xC0, 0x40, 0x00, 0x40, 0x08, 0x40, 0x10, 0x20, 0x08, + 0x54, 0x00, 0x03, 0xFF, 0x49, 0x00, 0x39, 0x66, 0x44, 0x0F, 0xFE, 0xFF, 0x2E, 0x07, 0xF9, 0x69, + 0x44, 0x00, 0x01, 0x00, 0x44, 0x0E, 0xFF, 0xFF, 0x46, 0x00, 0x00, 0x81, 0x44, 0x00, 0x00, 0x64, + 0x49, 0x00, 0x1A, 0x08, 0x44, 0x04, 0x28, 0x00, 0x49, 0x00, 0x22, 0x04, 0x2E, 0x00, 0x00, 0x51, + 0x44, 0x00, 0x00, 0x50, 0x49, 0x00, 0x0C, 0x05, 0x40, 0x10, 0xC0, 0x08, 0x49, 0x00, 0x02, 0x74, + 0x49, 0x00, 0x22, 0x0C, 0x2E, 0x00, 0x10, 0xBA, 0x2E, 0x07, 0xF9, 0x6A, 0x44, 0x14, 0x24, 0x00, + 0x49, 0x00, 0x0D, 0x1E, 0x3E, 0x07, 0xF6, 0xD8, 0x49, 0x00, 0x16, 0xAF, 0x44, 0x10, 0x00, 0x96, + 0x2E, 0x07, 0xFF, 0xBD, 0x49, 0x00, 0x23, 0xEE, 0x46, 0x60, 0x00, 0x81, 0x54, 0x10, 0x83, 0xFF, + 0x49, 0x00, 0x08, 0x47, 0x46, 0x10, 0x00, 0x81, 0x2E, 0x07, 0xF9, 0x01, 0x49, 0x00, 0x15, 0xBD, + 0x49, 0x00, 0x1B, 0x55, 0x49, 0x00, 0x16, 0x5B, 0x49, 0x00, 0x15, 0xC3, 0x40, 0x00, 0x58, 0x08, + 0x48, 0x00, 0x1D, 0xCD, 0x44, 0x04, 0x80, 0x08, 0x44, 0x00, 0xFF, 0xFF, 0x40, 0x10, 0xA8, 0x08, + 0x49, 0x00, 0x0E, 0x0C, 0x49, 0x00, 0x04, 0xE3, 0x40, 0x00, 0x50, 0x08, 0x44, 0x04, 0x80, 0x03, + 0x49, 0x00, 0x39, 0x6E, 0x04, 0x31, 0x00, 0x12, 0x14, 0x01, 0x00, 0x12, 0x3E, 0x00, 0x00, 0x4C, + 0x49, 0x00, 0x0C, 0x93, 0x49, 0x00, 0x39, 0xEC, 0x54, 0x00, 0x0F, 0xFF, 0x44, 0x14, 0x24, 0x14, + 0x46, 0x0F, 0xEF, 0xFF, 0x49, 0x00, 0x16, 0x44, 0x49, 0x00, 0x02, 0x65, 0x49, 0x00, 0x0B, 0xD8, + 0x40, 0x00, 0x30, 0x08, 0x44, 0x20, 0x00, 0x30, 0x49, 0x00, 0x22, 0x32, 0x49, 0x00, 0x03, 0xD8, + 0x49, 0x00, 0x07, 0xDD, 0x44, 0x08, 0xFF, 0xFF, 0x49, 0x00, 0x0C, 0x57, 0x49, 0x00, 0x34, 0x02, + 0x44, 0x04, 0x80, 0x01, 0x49, 0x00, 0x1D, 0xDA, 0x49, 0x00, 0x28, 0xCE, 0x44, 0x04, 0x28, 0x14, + 0x41, 0xFF, 0x80, 0x01, 0x44, 0x01, 0x00, 0x00, 0x44, 0x00, 0x00, 0x96, 0x58, 0x00, 0x01, 0x00, + 0x49, 0x00, 0x11, 0x3C, 0x49, 0x00, 0x26, 0x64, 0x44, 0x04, 0x80, 0x10, 0x44, 0x04, 0x28, 0x34, + 0x49, 0x00, 0x33, 0xAA, 0x2E, 0x00, 0x00, 0x4E, 0x2E, 0x00, 0x10, 0xC2, 0x49, 0x00, 0x03, 0x19, + 0x3A, 0x20, 0x94, 0x24, 0x49, 0x00, 0x04, 0x78, 0x46, 0x10, 0x00, 0x80, 0x10, 0x0F, 0x80, 0x07, + 0x44, 0x14, 0x2C, 0x00, 0x49, 0x00, 0x23, 0x10, 0x64, 0x00, 0x00, 0x08, 0x40, 0x10, 0xA0, 0x08, + 0x44, 0x20, 0x00, 0xB3, 0x2E, 0x07, 0xF9, 0x04, 0x40, 0x00, 0x70, 0x08, 0x44, 0x11, 0x00, 0x00, + 0x3A, 0x20, 0x14, 0x24, 0x49, 0x00, 0x25, 0xAD, 0x49, 0x00, 0x21, 0x74, 0x49, 0x00, 0x03, 0x1F, + 0x44, 0x14, 0x24, 0x34, 0x49, 0x00, 0x11, 0x37, 0x2E, 0x30, 0x10, 0xBD, 0x14, 0x01, 0x00, 0x10, + 0x49, 0x00, 0x07, 0x92, 0x49, 0x00, 0x04, 0x27, 0x3E, 0x00, 0x10, 0xBA, 0x49, 0x00, 0x07, 0xA7, + 0x49, 0x00, 0x22, 0x94, 0x3A, 0x20, 0x14, 0x04, 0x44, 0x04, 0x80, 0x0A, 0x44, 0x20, 0x00, 0xBD, + 0x44, 0x04, 0x80, 0x06, 0x44, 0x04, 0x80, 0x07, 0x49, 0x00, 0x25, 0x23, 0x2E, 0x40, 0x0F, 0x8E, + 0x2E, 0x00, 0x10, 0xC3, 0x2E, 0x40, 0x0F, 0x8F, 0x54, 0x10, 0x87, 0xFF, 0x44, 0x00, 0x02, 0x88, + 0x3E, 0x07, 0xF9, 0x04, 0x49, 0x00, 0x02, 0x93, 0x49, 0x00, 0x33, 0x28, 0x58, 0x00, 0x00, 0x02, + 0x3A, 0x20, 0x94, 0x04, 0x49, 0x00, 0x07, 0x83, 0x49, 0x00, 0x09, 0x82, 0x49, 0x00, 0x1D, 0xE1, + 0x49, 0x00, 0x25, 0x0F, 0x44, 0x24, 0x2C, 0x34, 0x2E, 0x40, 0x10, 0xD0, 0x49, 0x00, 0x05, 0x2F, + 0x49, 0x00, 0x03, 0xCF, 0x49, 0x00, 0x27, 0x13, 0x46, 0x30, 0x00, 0x81, 0x49, 0x00, 0x15, 0xB1, + 0x49, 0x00, 0x0F, 0x3E, 0x3C, 0x08, 0x08, 0x5A, 0x49, 0x00, 0x22, 0x9C, 0x3A, 0x20, 0x14, 0x00, + 0x40, 0x10, 0xB0, 0x08, 0x49, 0x00, 0x10, 0x91, 0x44, 0x04, 0x80, 0x88, 0x44, 0x00, 0x03, 0xFF, + 0x46, 0x0F, 0xDF, 0xFF, 0x49, 0x00, 0x06, 0x44, 0x3C, 0x0C, 0x04, 0x29, 0x51, 0xC3, 0x0E, 0x94, + 0x3A, 0x20, 0x14, 0x20, 0x49, 0x00, 0x03, 0x71, 0x44, 0x02, 0x00, 0x00, 0x3E, 0x07, 0xF9, 0x7C, + 0x49, 0x00, 0x27, 0xDA, 0x44, 0x13, 0x00, 0x30, 0x49, 0x00, 0x17, 0xA0, 0x49, 0x00, 0x21, 0xCE, + 0x40, 0x10, 0x28, 0x08, 0x3C, 0x0C, 0x04, 0x2A, 0x49, 0x00, 0x09, 0x88, 0x44, 0x04, 0x80, 0x0B, + 0x3A, 0x20, 0x8C, 0x24, 0x14, 0x01, 0x00, 0x11, 0x44, 0x02, 0x28, 0x70, 0x44, 0x14, 0x24, 0x1C, + 0x49, 0x00, 0x09, 0x11, 0x49, 0x00, 0x0F, 0x48, 0x44, 0x10, 0xC0, 0x0C, 0x3C, 0x0C, 0x04, 0x2C, + 0x44, 0x00, 0x00, 0xFF, 0x50, 0x63, 0x0F, 0xFF, 0x49, 0x00, 0x17, 0x5E, 0x40, 0x52, 0xD8, 0x08, + 0x44, 0x04, 0x28, 0x1C, 0x44, 0x04, 0x80, 0x09, 0x49, 0x00, 0x27, 0x3B, 0x44, 0x1E, 0xFF, 0xFF, + 0x49, 0x00, 0x0D, 0xA9, 0x49, 0x00, 0x15, 0xE5, 0x49, 0x00, 0x03, 0x2E, 0x48, 0x00, 0x1D, 0xD1, + 0x22, 0x20, 0x80, 0x00, 0x49, 0x00, 0x07, 0x60, 0x49, 0x00, 0x21, 0xE2, 0x40, 0x10, 0x10, 0x09, + 0x42, 0x03, 0x04, 0x73, 0x49, 0x00, 0x27, 0x61, 0x46, 0x0F, 0xFF, 0x0F, 0x44, 0x00, 0x30, 0x03, + 0x54, 0x42, 0x00, 0xF3, 0x49, 0x00, 0x27, 0x4F, 0x40, 0x52, 0xC0, 0x08, 0x49, 0x00, 0x04, 0x56, + 0x44, 0x0F, 0x00, 0x00, 0x49, 0x00, 0x04, 0x1A, 0x44, 0x0C, 0xFF, 0xFF, 0x40, 0x10, 0x30, 0x09, + 0x44, 0x14, 0x01, 0x08, 0x46, 0x30, 0x00, 0x80, 0x38, 0x20, 0x19, 0x01, 0x00, 0x0F, 0x80, 0x07, + 0x44, 0x04, 0x80, 0x11, 0x49, 0x00, 0x22, 0xB8, 0x3A, 0x20, 0x94, 0x00, 0x40, 0x10, 0x60, 0x08, + 0x40, 0x00, 0x60, 0x08, 0x49, 0x00, 0x39, 0xD9, 0x50, 0x00, 0x0F, 0xC0, 0x44, 0x14, 0x00, 0x00, + 0x49, 0x00, 0x34, 0x54, 0x46, 0x00, 0x00, 0xC0, 0x49, 0x00, 0x21, 0x2D, 0x14, 0x11, 0x80, 0x49, + 0x49, 0x00, 0x16, 0xF8, 0x44, 0x0F, 0x3F, 0xFF, 0x49, 0x00, 0x23, 0xF1, 0x50, 0x21, 0x0F, 0xFF, + 0x3A, 0x20, 0x0C, 0x04, 0x49, 0x00, 0x25, 0x6C, 0x44, 0x04, 0x80, 0x00, 0x46, 0x0F, 0x00, 0x0F, + 0x5C, 0xF3, 0x00, 0x24, 0x49, 0x00, 0x08, 0xE3, 0x49, 0x00, 0x21, 0x87, 0x48, 0x00, 0x29, 0x62, + 0x49, 0x00, 0x0C, 0xA0, 0x40, 0x00, 0xE0, 0x08, 0x58, 0x31, 0x81, 0x00, 0x14, 0x10, 0x00, 0x71, + 0x49, 0x00, 0x33, 0x17, 0x2E, 0x07, 0xF9, 0x70, 0x49, 0x00, 0x14, 0x95, 0x44, 0x17, 0x30, 0x10, + 0x2E, 0x07, 0xF9, 0x50, 0x44, 0x14, 0x2C, 0x34, 0x40, 0x00, 0x00, 0x09, 0x49, 0x00, 0x1A, 0xAD, + 0x40, 0x10, 0x58, 0x08, 0x14, 0x00, 0x80, 0x30, 0x40, 0x00, 0x04, 0x0C, 0x58, 0x00, 0x04, 0x00, + 0x49, 0x00, 0x02, 0x9C, 0x50, 0x5F, 0x85, 0xE0, 0x40, 0x10, 0xD8, 0x08, 0x40, 0x10, 0x28, 0x09, + 0x44, 0x0F, 0xFD, 0xFF, 0x49, 0x00, 0x21, 0x7D, 0x54, 0x03, 0x00, 0x01, 0x04, 0x31, 0x00, 0x39, + 0x49, 0x00, 0x15, 0xDB, 0x3E, 0x00, 0x10, 0xBB, 0x3C, 0x1D, 0xFB, 0xEF, 0x50, 0x1F, 0x85, 0xE0, + 0x49, 0x00, 0x22, 0xE2, 0x3E, 0x07, 0xF7, 0x69, 0x3C, 0x1C, 0x04, 0x2C, 0x40, 0x21, 0x40, 0x08, + 0x3C, 0x50, 0x08, 0x63, 0x58, 0x00, 0x10, 0x00, 0x04, 0x11, 0x80, 0x49, 0x44, 0x04, 0x80, 0x04, + 0x49, 0x00, 0x08, 0xF2, 0x44, 0x0F, 0xFF, 0xEF, 0x14, 0x01, 0x80, 0x57, 0x49, 0x00, 0x07, 0xFA, + 0x48, 0x00, 0x30, 0x3B, 0x44, 0x14, 0x80, 0x1C, 0x50, 0x03, 0x0A, 0x98, 0x40, 0x10, 0x48, 0x08, + 0x3C, 0x0D, 0xFD, 0xA2, 0x49, 0x00, 0x34, 0x50, 0x49, 0x00, 0x0D, 0x62, 0x5E, 0xF0, 0x04, 0x00, + 0x38, 0x41, 0x80, 0x11, 0x44, 0x16, 0x34, 0x20, 0x3C, 0x50, 0x08, 0x5A, 0x49, 0x00, 0x0D, 0xCB, + 0x3C, 0x0D, 0xFD, 0xA1, 0x49, 0x00, 0x25, 0x33, 0x44, 0x10, 0x00, 0x40, 0x44, 0x14, 0x80, 0x84, + 0x49, 0x00, 0x0E, 0xC8, 0x40, 0x20, 0xA8, 0x09, 0x49, 0x00, 0x15, 0xD1, 0x2E, 0x50, 0x10, 0xC0, + 0x38, 0x94, 0x1A, 0x01, 0x49, 0x00, 0x26, 0x74, 0x04, 0x31, 0x00, 0x0F, 0x46, 0x00, 0x10, 0x00, + 0x3C, 0x2C, 0x04, 0x2C, 0x44, 0x17, 0x10, 0x18, 0x44, 0x0F, 0xFB, 0xFF, 0x46, 0x0F, 0xF3, 0xFF, + 0x2E, 0x07, 0xF9, 0x6B, 0x46, 0x0F, 0xF0, 0x0F, 0x40, 0x21, 0x20, 0x08, 0x49, 0x00, 0x21, 0xBE, + 0x49, 0x00, 0x03, 0xAB, 0x49, 0x00, 0x10, 0xCB, 0x44, 0x0F, 0xFF, 0x3F, 0x50, 0x00, 0x00, 0xFF, + 0x49, 0x00, 0x03, 0xB4, 0x44, 0x0B, 0xFF, 0xFF, 0x49, 0x00, 0x32, 0xD1, 0x04, 0x31, 0x00, 0x28, + 0x40, 0x31, 0xA0, 0x08, 0x14, 0x01, 0x00, 0x0F, 0x48, 0x00, 0x1D, 0xD8, 0x44, 0x12, 0x00, 0x00, + 0x2E, 0x17, 0xF9, 0x6C, 0x49, 0x00, 0x24, 0xC2, 0x38, 0x11, 0x01, 0x09, 0x04, 0x0E, 0x7F, 0xF0, + 0x2E, 0x06, 0x61, 0xFF, 0x04, 0x31, 0x00, 0x29, 0x50, 0x13, 0x06, 0x94, 0x49, 0x00, 0x23, 0x6A, + 0x49, 0x00, 0x07, 0xF1, 0x49, 0x00, 0x0A, 0x31, 0x49, 0x00, 0x34, 0x5D, 0x40, 0x00, 0xC0, 0x08, + 0x50, 0x13, 0x06, 0x98, 0x40, 0x31, 0xC0, 0x08, 0x46, 0x1F, 0xF0, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, + 0x74, 0x1A, 0xC9, 0x3A, 0x10, 0x80, 0x12, 0x24, 0x12, 0x24, 0x0C, 0x00, 0x36, 0x00, 0xFF, 0x07, + 0xFF, 0x07, 0x38, 0x04, 0x60, 0x09, 0x05, 0x0A, 0x0B, 0x01, 0x00, 0x00, 0x5A, 0x00, 0x4A, 0x04, + 0x40, 0x0E, 0x02, 0x00, 0x38, 0x0E, 0x02, 0x00, 0x2C, 0x0E, 0x02, 0x00, 0x20, 0x0E, 0x02, 0x00, + 0x10, 0x0E, 0x02, 0x00, 0x00, 0x0E, 0x02, 0x00, 0xEC, 0x0D, 0x02, 0x00, 0xD8, 0x0D, 0x02, 0x00, + 0xC0, 0x0D, 0x02, 0x00, 0xA4, 0x0D, 0x02, 0x00, 0x0A, 0x0B, 0x0B, 0x0B, 0x0C, 0x0C, 0x0C, 0x0C, + 0x0C, 0x0D, 0x00, 0x00, 0x01, 0x05, 0x00, 0x07, 0x02, 0x06, 0x04, 0x08, 0x03, 0x09, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xA2, 0x00, 0x00, 0x00, 0xA2, 0x00, 0x00, 0x00, 0xE0, 0x00, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x88, 0x02, 0x88, 0x02, 0x00, 0x00, 0xD8, 0x00, 0xD8, 0x00, 0x40, 0x00, 0x40, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x88, 0x02, 0x00, 0x00, 0x88, 0x02, 0x00, 0x00, 0x92, 0x02, 0x00, 0x00, 0xD2, 0x02, 0x00, 0x00, + 0x00, 0x06, 0x06, 0x00, 0x02, 0x02, 0x01, 0x01, 0x00, 0x01, 0x02, 0x03, 0x04, 0x00, 0x01, 0x02, + 0x03, 0x04, 0x00, 0x00, 0x3F, 0xF0, 0x03, 0x00, 0xC0, 0x0F, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x00, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x00, 0x00, 0x01, 0x00, 0x80, 0x00, 0x06, 0x00, 0x60, 0x00, 0x08, 0x00, 0x10, 0x00, + 0x10, 0x00, 0x08, 0x00, 0x60, 0x00, 0x06, 0x00, 0x80, 0x00, 0x01, 0x00, 0x00, 0x81, 0x00, 0x00, + 0x00, 0x66, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD0, 0x07, 0x84, 0x03, 0x50, 0x00, + 0x64, 0x00, 0xB0, 0xFF, 0x9C, 0xFF, 0x0A, 0x00, 0x01, 0x00, 0xD8, 0x00, 0x01, 0x01, 0x01, 0x24, + 0x01, 0x12, 0x01, 0x06, 0x01, 0x50, 0x64, 0xB0, 0x9C, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xAA, 0x00, 0x1E, 0x00, 0xCC, 0x01, 0x03, 0x02, 0x02, 0x01, 0x1E, 0x00, 0x5E, 0x01, 0x64, 0x00, + 0x8A, 0x00, 0x28, 0x00, 0x00, 0x50, 0x27, 0x0E, 0x09, 0x64, 0x48, 0x02, 0x01, 0x08, 0x00, 0x02, + 0x3F, 0x01, 0x02, 0x04, 0x03, 0x03, 0x0A, 0x04, 0x04, 0x04, 0x02, 0x02, 0x03, 0x08, 0x02, 0x6C, + 0x02, 0x01, 0x00, 0x03, 0x30, 0x0A, 0x0A, 0x06, 0x04, 0xC8, 0x14, 0x10, 0x0C, 0x19, 0x19, 0x00, + 0x88, 0x02, 0x00, 0x00, 0x0A, 0x39, 0x01, 0x00, 0xA0, 0x86, 0x01, 0x00, 0x55, 0x00, 0x2D, 0x00, + 0x41, 0x00, 0x0A, 0x00, 0x0A, 0x00, 0xC8, 0x00, 0x15, 0x16, 0xA4, 0x29, 0xC2, 0x11, 0x51, 0x25, + 0xCC, 0x01, 0x90, 0x01, 0xD0, 0x07, 0x96, 0x00, 0xC2, 0x01, 0xC2, 0x01, 0x96, 0x00, 0x96, 0x00, + 0x96, 0x00, 0x01, 0x64, 0x0B, 0x0B, 0x36, 0x6E, 0x00, 0x02, 0x6C, 0x36, 0x02, 0x08, 0x06, 0x00, + 0xF4, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x77, 0x02, 0x53, 0x02, 0x2F, 0x02, 0x0B, 0x02, + 0xE7, 0x01, 0xC3, 0x01, 0x9F, 0x01, 0x7B, 0x01, 0x57, 0x01, 0x33, 0x01, 0x0F, 0x01, 0xEB, 0x00, + 0xC7, 0x00, 0xA3, 0x00, 0x7F, 0x00, 0x5B, 0x00, 0x37, 0x00, 0x13, 0x00, 0x78, 0x02, 0x54, 0x02, + 0x30, 0x02, 0x0C, 0x02, 0xE8, 0x01, 0xC4, 0x01, 0xA0, 0x01, 0x7C, 0x01, 0x58, 0x01, 0x34, 0x01, + 0x10, 0x01, 0xEC, 0x00, 0xC8, 0x00, 0xA4, 0x00, 0x80, 0x00, 0x5C, 0x00, 0x38, 0x00, 0x14, 0x00, + 0x79, 0x02, 0x55, 0x02, 0x31, 0x02, 0x0D, 0x02, 0xE9, 0x01, 0xC5, 0x01, 0xA1, 0x01, 0x7D, 0x01, + 0x59, 0x01, 0x35, 0x01, 0x11, 0x01, 0xED, 0x00, 0xC9, 0x00, 0xA5, 0x00, 0x81, 0x00, 0x5D, 0x00, + 0x39, 0x00, 0x15, 0x00, 0x7A, 0x02, 0x56, 0x02, 0x32, 0x02, 0x0E, 0x02, 0xEA, 0x01, 0xC6, 0x01, + 0xA2, 0x01, 0x7E, 0x01, 0x5A, 0x01, 0x36, 0x01, 0x12, 0x01, 0xEE, 0x00, 0xCA, 0x00, 0xA6, 0x00, + 0x82, 0x00, 0x5E, 0x00, 0x3A, 0x00, 0x16, 0x00, 0x7B, 0x02, 0x57, 0x02, 0x33, 0x02, 0x0F, 0x02, + 0xEB, 0x01, 0xC7, 0x01, 0xA3, 0x01, 0x7F, 0x01, 0x5B, 0x01, 0x37, 0x01, 0x13, 0x01, 0xEF, 0x00, + 0xCB, 0x00, 0xA7, 0x00, 0x83, 0x00, 0x5F, 0x00, 0x3B, 0x00, 0x17, 0x00, 0x7C, 0x02, 0x58, 0x02, + 0x34, 0x02, 0x10, 0x02, 0xEC, 0x01, 0xC8, 0x01, 0xA4, 0x01, 0x80, 0x01, 0x5C, 0x01, 0x38, 0x01, + 0x14, 0x01, 0xF0, 0x00, 0xCC, 0x00, 0xA8, 0x00, 0x84, 0x00, 0x60, 0x00, 0x3C, 0x00, 0x18, 0x00, + 0x7D, 0x02, 0x59, 0x02, 0x35, 0x02, 0x11, 0x02, 0xED, 0x01, 0xC9, 0x01, 0xA5, 0x01, 0x81, 0x01, + 0x5D, 0x01, 0x39, 0x01, 0x15, 0x01, 0xF1, 0x00, 0xCD, 0x00, 0xA9, 0x00, 0x85, 0x00, 0x61, 0x00, + 0x3D, 0x00, 0x19, 0x00, 0x7E, 0x02, 0x5A, 0x02, 0x36, 0x02, 0x12, 0x02, 0xEE, 0x01, 0xCA, 0x01, + 0xA6, 0x01, 0x82, 0x01, 0x5E, 0x01, 0x3A, 0x01, 0x16, 0x01, 0xF2, 0x00, 0xCE, 0x00, 0xAA, 0x00, + 0x86, 0x00, 0x62, 0x00, 0x3E, 0x00, 0x1A, 0x00, 0x7F, 0x02, 0x5B, 0x02, 0x37, 0x02, 0x13, 0x02, + 0xEF, 0x01, 0xCB, 0x01, 0xA7, 0x01, 0x83, 0x01, 0x5F, 0x01, 0x3B, 0x01, 0x17, 0x01, 0xF3, 0x00, + 0xCF, 0x00, 0xAB, 0x00, 0x87, 0x00, 0x63, 0x00, 0x3F, 0x00, 0x1B, 0x00, 0x80, 0x02, 0x5C, 0x02, + 0x38, 0x02, 0x14, 0x02, 0xF0, 0x01, 0xCC, 0x01, 0xA8, 0x01, 0x84, 0x01, 0x60, 0x01, 0x3C, 0x01, + 0x18, 0x01, 0xF4, 0x00, 0xD0, 0x00, 0xAC, 0x00, 0x88, 0x00, 0x64, 0x00, 0x40, 0x00, 0x1C, 0x00, + 0x81, 0x02, 0x5D, 0x02, 0x39, 0x02, 0x15, 0x02, 0xF1, 0x01, 0xCD, 0x01, 0xA9, 0x01, 0x85, 0x01, + 0x61, 0x01, 0x3D, 0x01, 0x19, 0x01, 0xF5, 0x00, 0xD1, 0x00, 0xAD, 0x00, 0x89, 0x00, 0x65, 0x00, + 0x41, 0x00, 0x1D, 0x00, 0x82, 0x02, 0x5E, 0x02, 0x3A, 0x02, 0x16, 0x02, 0xF2, 0x01, 0xCE, 0x01, + 0xAA, 0x01, 0x86, 0x01, 0x62, 0x01, 0x3E, 0x01, 0x1A, 0x01, 0xF6, 0x00, 0xD2, 0x00, 0xAE, 0x00, + 0x8A, 0x00, 0x66, 0x00, 0x42, 0x00, 0x1E, 0x00, 0x83, 0x02, 0x5F, 0x02, 0x3B, 0x02, 0x17, 0x02, + 0xF3, 0x01, 0xCF, 0x01, 0xAB, 0x01, 0x87, 0x01, 0x63, 0x01, 0x3F, 0x01, 0x1B, 0x01, 0xF7, 0x00, + 0xD3, 0x00, 0xAF, 0x00, 0x8B, 0x00, 0x67, 0x00, 0x43, 0x00, 0x1F, 0x00, 0x84, 0x02, 0x60, 0x02, + 0x3C, 0x02, 0x18, 0x02, 0xF4, 0x01, 0xD0, 0x01, 0xAC, 0x01, 0x88, 0x01, 0x64, 0x01, 0x40, 0x01, + 0x1C, 0x01, 0xF8, 0x00, 0xD4, 0x00, 0xB0, 0x00, 0x8C, 0x00, 0x68, 0x00, 0x44, 0x00, 0x20, 0x00, + 0x85, 0x02, 0x61, 0x02, 0x3D, 0x02, 0x19, 0x02, 0xF5, 0x01, 0xD1, 0x01, 0xAD, 0x01, 0x89, 0x01, + 0x65, 0x01, 0x41, 0x01, 0x1D, 0x01, 0xF9, 0x00, 0xD5, 0x00, 0xB1, 0x00, 0x8D, 0x00, 0x69, 0x00, + 0x45, 0x00, 0x21, 0x00, 0x86, 0x02, 0x62, 0x02, 0x3E, 0x02, 0x1A, 0x02, 0xF6, 0x01, 0xD2, 0x01, + 0xAE, 0x01, 0x8A, 0x01, 0x66, 0x01, 0x42, 0x01, 0x1E, 0x01, 0xFA, 0x00, 0xD6, 0x00, 0xB2, 0x00, + 0x8E, 0x00, 0x6A, 0x00, 0x46, 0x00, 0x22, 0x00, 0x87, 0x02, 0x63, 0x02, 0x3F, 0x02, 0x1B, 0x02, + 0xF7, 0x01, 0xD3, 0x01, 0xAF, 0x01, 0x8B, 0x01, 0x67, 0x01, 0x43, 0x01, 0x1F, 0x01, 0xFB, 0x00, + 0xD7, 0x00, 0xB3, 0x00, 0x8F, 0x00, 0x6B, 0x00, 0x47, 0x00, 0x23, 0x00, 0x88, 0x02, 0x64, 0x02, + 0x40, 0x02, 0x1C, 0x02, 0xF8, 0x01, 0xD4, 0x01, 0xB0, 0x01, 0x8C, 0x01, 0x68, 0x01, 0x44, 0x01, + 0x20, 0x01, 0xFC, 0x00, 0xD8, 0x00, 0xB4, 0x00, 0x90, 0x00, 0x6C, 0x00, 0x48, 0x00, 0x24, 0x00, + 0x65, 0x02, 0x41, 0x02, 0x1D, 0x02, 0xF9, 0x01, 0xD5, 0x01, 0xB1, 0x01, 0x8D, 0x01, 0x69, 0x01, + 0x45, 0x01, 0x21, 0x01, 0xFD, 0x00, 0xD9, 0x00, 0xB5, 0x00, 0x91, 0x00, 0x6D, 0x00, 0x49, 0x00, + 0x25, 0x00, 0x01, 0x00, 0x66, 0x02, 0x42, 0x02, 0x1E, 0x02, 0xFA, 0x01, 0xD6, 0x01, 0xB2, 0x01, + 0x8E, 0x01, 0x6A, 0x01, 0x46, 0x01, 0x22, 0x01, 0xFE, 0x00, 0xDA, 0x00, 0xB6, 0x00, 0x92, 0x00, + 0x6E, 0x00, 0x4A, 0x00, 0x26, 0x00, 0x02, 0x00, 0x67, 0x02, 0x43, 0x02, 0x1F, 0x02, 0xFB, 0x01, + 0xD7, 0x01, 0xB3, 0x01, 0x8F, 0x01, 0x6B, 0x01, 0x47, 0x01, 0x23, 0x01, 0xFF, 0x00, 0xDB, 0x00, + 0xB7, 0x00, 0x93, 0x00, 0x6F, 0x00, 0x4B, 0x00, 0x27, 0x00, 0x03, 0x00, 0x68, 0x02, 0x44, 0x02, + 0x20, 0x02, 0xFC, 0x01, 0xD8, 0x01, 0xB4, 0x01, 0x90, 0x01, 0x6C, 0x01, 0x48, 0x01, 0x24, 0x01, + 0x00, 0x01, 0xDC, 0x00, 0xB8, 0x00, 0x94, 0x00, 0x70, 0x00, 0x4C, 0x00, 0x28, 0x00, 0x04, 0x00, + 0x69, 0x02, 0x45, 0x02, 0x21, 0x02, 0xFD, 0x01, 0xD9, 0x01, 0xB5, 0x01, 0x91, 0x01, 0x6D, 0x01, + 0x49, 0x01, 0x25, 0x01, 0x01, 0x01, 0xDD, 0x00, 0xB9, 0x00, 0x95, 0x00, 0x71, 0x00, 0x4D, 0x00, + 0x29, 0x00, 0x05, 0x00, 0x6A, 0x02, 0x46, 0x02, 0x22, 0x02, 0xFE, 0x01, 0xDA, 0x01, 0xB6, 0x01, + 0x92, 0x01, 0x6E, 0x01, 0x4A, 0x01, 0x26, 0x01, 0x02, 0x01, 0xDE, 0x00, 0xBA, 0x00, 0x96, 0x00, + 0x72, 0x00, 0x4E, 0x00, 0x2A, 0x00, 0x06, 0x00, 0x6B, 0x02, 0x47, 0x02, 0x23, 0x02, 0xFF, 0x01, + 0xDB, 0x01, 0xB7, 0x01, 0x93, 0x01, 0x6F, 0x01, 0x4B, 0x01, 0x27, 0x01, 0x03, 0x01, 0xDF, 0x00, + 0xBB, 0x00, 0x97, 0x00, 0x73, 0x00, 0x4F, 0x00, 0x2B, 0x00, 0x07, 0x00, 0x6C, 0x02, 0x48, 0x02, + 0x24, 0x02, 0x00, 0x02, 0xDC, 0x01, 0xB8, 0x01, 0x94, 0x01, 0x70, 0x01, 0x4C, 0x01, 0x28, 0x01, + 0x04, 0x01, 0xE0, 0x00, 0xBC, 0x00, 0x98, 0x00, 0x74, 0x00, 0x50, 0x00, 0x2C, 0x00, 0x08, 0x00, + 0x6D, 0x02, 0x49, 0x02, 0x25, 0x02, 0x01, 0x02, 0xDD, 0x01, 0xB9, 0x01, 0x95, 0x01, 0x71, 0x01, + 0x4D, 0x01, 0x29, 0x01, 0x05, 0x01, 0xE1, 0x00, 0xBD, 0x00, 0x99, 0x00, 0x75, 0x00, 0x51, 0x00, + 0x2D, 0x00, 0x09, 0x00, 0x6E, 0x02, 0x4A, 0x02, 0x26, 0x02, 0x02, 0x02, 0xDE, 0x01, 0xBA, 0x01, + 0x96, 0x01, 0x72, 0x01, 0x4E, 0x01, 0x2A, 0x01, 0x06, 0x01, 0xE2, 0x00, 0xBE, 0x00, 0x9A, 0x00, + 0x76, 0x00, 0x52, 0x00, 0x2E, 0x00, 0x0A, 0x00, 0x6F, 0x02, 0x4B, 0x02, 0x27, 0x02, 0x03, 0x02, + 0xDF, 0x01, 0xBB, 0x01, 0x97, 0x01, 0x73, 0x01, 0x4F, 0x01, 0x2B, 0x01, 0x07, 0x01, 0xE3, 0x00, + 0xBF, 0x00, 0x9B, 0x00, 0x77, 0x00, 0x53, 0x00, 0x2F, 0x00, 0x0B, 0x00, 0x70, 0x02, 0x4C, 0x02, + 0x28, 0x02, 0x04, 0x02, 0xE0, 0x01, 0xBC, 0x01, 0x98, 0x01, 0x74, 0x01, 0x50, 0x01, 0x2C, 0x01, + 0x08, 0x01, 0xE4, 0x00, 0xC0, 0x00, 0x9C, 0x00, 0x78, 0x00, 0x54, 0x00, 0x30, 0x00, 0x0C, 0x00, + 0x71, 0x02, 0x4D, 0x02, 0x29, 0x02, 0x05, 0x02, 0xE1, 0x01, 0xBD, 0x01, 0x99, 0x01, 0x75, 0x01, + 0x51, 0x01, 0x2D, 0x01, 0x09, 0x01, 0xE5, 0x00, 0xC1, 0x00, 0x9D, 0x00, 0x79, 0x00, 0x55, 0x00, + 0x31, 0x00, 0x0D, 0x00, 0x72, 0x02, 0x4E, 0x02, 0x2A, 0x02, 0x06, 0x02, 0xE2, 0x01, 0xBE, 0x01, + 0x9A, 0x01, 0x76, 0x01, 0x52, 0x01, 0x2E, 0x01, 0x0A, 0x01, 0xE6, 0x00, 0xC2, 0x00, 0x9E, 0x00, + 0x7A, 0x00, 0x56, 0x00, 0x32, 0x00, 0x0E, 0x00, 0x73, 0x02, 0x4F, 0x02, 0x2B, 0x02, 0x07, 0x02, + 0xE3, 0x01, 0xBF, 0x01, 0x9B, 0x01, 0x77, 0x01, 0x53, 0x01, 0x2F, 0x01, 0x0B, 0x01, 0xE7, 0x00, + 0xC3, 0x00, 0x9F, 0x00, 0x7B, 0x00, 0x57, 0x00, 0x33, 0x00, 0x0F, 0x00, 0x74, 0x02, 0x50, 0x02, + 0x2C, 0x02, 0x08, 0x02, 0xE4, 0x01, 0xC0, 0x01, 0x9C, 0x01, 0x78, 0x01, 0x54, 0x01, 0x30, 0x01, + 0x0C, 0x01, 0xE8, 0x00, 0xC4, 0x00, 0xA0, 0x00, 0x7C, 0x00, 0x58, 0x00, 0x34, 0x00, 0x10, 0x00, + 0x75, 0x02, 0x51, 0x02, 0x2D, 0x02, 0x09, 0x02, 0xE5, 0x01, 0xC1, 0x01, 0x9D, 0x01, 0x79, 0x01, + 0x55, 0x01, 0x31, 0x01, 0x0D, 0x01, 0xE9, 0x00, 0xC5, 0x00, 0xA1, 0x00, 0x7D, 0x00, 0x59, 0x00, + 0x35, 0x00, 0x11, 0x00, 0x76, 0x02, 0x52, 0x02, 0x2E, 0x02, 0x0A, 0x02, 0xE6, 0x01, 0xC2, 0x01, + 0x9E, 0x01, 0x7A, 0x01, 0x56, 0x01, 0x32, 0x01, 0x0E, 0x01, 0xEA, 0x00, 0xC6, 0x00, 0xA2, 0x00, + 0x7E, 0x00, 0x5A, 0x00, 0x36, 0x00, 0x12, 0x00, 0xE2, 0x00, 0xE2, 0x00, 0xE2, 0x00, 0xE2, 0x00, + 0xE4, 0x00, 0xFC, 0x00, 0x44, 0x01, 0xF0, 0x00, 0x2C, 0x01, 0x62, 0x01, 0xE4, 0x00, 0xFC, 0x00, + 0x44, 0x01, 0xF0, 0x00, 0x2C, 0x01, 0x62, 0x01, 0xE4, 0x00, 0xFC, 0x00, 0x44, 0x01, 0xF0, 0x00, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0B, 0x0C, 0x00, 0x00, 0x06, 0x06, 0x06, 0x06, + 0x09, 0x08, 0x06, 0x08, 0x07, 0x05, 0x09, 0x08, 0x06, 0x08, 0x07, 0x05, 0x09, 0x08, 0x06, 0x08, + 0xE4, 0x00, 0x12, 0x01, 0x3E, 0x01, 0x74, 0x01, 0xBA, 0x01, 0x84, 0x01, 0x58, 0x01, 0xF0, 0x00, + 0xCE, 0x01, 0x8E, 0x01, 0xF8, 0x00, 0x00, 0x01, 0x08, 0x01, 0xE2, 0x00, 0x16, 0x01, 0xE4, 0x00, + 0x12, 0x01, 0x3E, 0x01, 0x74, 0x01, 0xBA, 0x01, 0x03, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, + 0x00, 0x00, 0x02, 0x02, 0x02, 0x03, 0x02, 0x03, 0x02, 0x01, 0x00, 0x00, 0x02, 0x03, 0x04, 0x05, + 0x06, 0x07, 0x08, 0x09, 0x0B, 0x0C, 0x00, 0x00, 0x41, 0x01, 0x01, 0x01, 0x01, 0x01, 0xFF, 0xFF, + 0x0A, 0x0B, 0x0B, 0x0B, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0D, 0x00, 0x00, 0x40, 0x0E, 0x02, 0x00, + 0x38, 0x0E, 0x02, 0x00, 0x2C, 0x0E, 0x02, 0x00, 0x20, 0x0E, 0x02, 0x00, 0x10, 0x0E, 0x02, 0x00, + 0x00, 0x0E, 0x02, 0x00, 0xEC, 0x0D, 0x02, 0x00, 0xD8, 0x0D, 0x02, 0x00, 0xC0, 0x0D, 0x02, 0x00, + 0xA4, 0x0D, 0x02, 0x00, 0xB6, 0x00, 0x7B, 0x00, 0x9F, 0x00, 0xC7, 0x00, 0xF1, 0x00, 0x1B, 0x01, + 0x44, 0x01, 0x6B, 0x01, 0x8E, 0x01, 0xAC, 0x01, 0xC4, 0x01, 0xD4, 0x01, 0xDC, 0x01, 0x00, 0x00, + 0x5D, 0x00, 0x44, 0x00, 0x5A, 0x00, 0x72, 0x00, 0x8A, 0x00, 0xA4, 0x00, 0xBC, 0x00, 0xD1, 0x00, + 0xE4, 0x00, 0xF3, 0x00, 0xFE, 0x00, 0x03, 0x01, 0x65, 0x00, 0x58, 0x00, 0x79, 0x00, 0x9D, 0x00, + 0xC2, 0x00, 0xE4, 0x00, 0x03, 0x01, 0x1D, 0x01, 0x2F, 0x01, 0x38, 0x01, 0x6A, 0x00, 0x67, 0x00, + 0x91, 0x00, 0xBE, 0x00, 0xEB, 0x00, 0x14, 0x01, 0x36, 0x01, 0x4F, 0x01, 0x5C, 0x01, 0x00, 0x00, + 0x72, 0x00, 0x7C, 0x00, 0xB2, 0x00, 0xEB, 0x00, 0x24, 0x01, 0x53, 0x01, 0x76, 0x01, 0x88, 0x01, + 0x7C, 0x00, 0x99, 0x00, 0xE2, 0x00, 0x2E, 0x01, 0x73, 0x01, 0xA6, 0x01, 0xC2, 0x01, 0x00, 0x00, + 0x45, 0x00, 0x63, 0x00, 0x96, 0x00, 0xC9, 0x00, 0xF1, 0x00, 0x08, 0x01, 0x51, 0x00, 0x88, 0x00, + 0xD4, 0x00, 0x16, 0x01, 0x3D, 0x01, 0x00, 0x00, 0x67, 0x00, 0xCD, 0x00, 0x41, 0x01, 0x8B, 0x01, + 0x4C, 0x00, 0xB1, 0x00, 0x03, 0x01, 0x00, 0x00, 0x30, 0x75, 0x00, 0x00, 0x80, 0x00, 0x08, 0x00, + 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x00, 0x00, 0x01, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0B, 0x0C, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00, + 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x02, 0x02, 0x02, 0x03, 0x02, 0x03, 0x02, 0x01, 0x00, 0x00, + 0x52, 0x01, 0x00, 0x00, 0xF1, 0x3A, 0x04, 0xA4, 0x00, 0x6E, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x96, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF1, 0x30, 0x00, 0x0A, + 0xA0, 0x02, 0x01, 0x00, 0x1E, 0x00, 0x96, 0xFF, 0x00, 0x64, 0x01, 0xCC, 0x00, 0x64, 0x01, 0xCC, + 0x02, 0x03, 0x01, 0x02, 0x00, 0x00, 0x00, 0x28, 0x00, 0x8A, 0x06, 0x30, 0x0A, 0x01, 0x12, 0x04, + 0x00, 0x50, 0x00, 0x00, 0x37, 0x20, 0x00, 0x00, 0x29, 0x04, 0x38, 0x09, 0x60, 0x00, 0x00, 0x00, + 0x28, 0x02, 0x00, 0x08, 0x2C, 0x02, 0x00, 0x08, 0x2C, 0x01, 0x00, 0x0C, 0x00, 0x02, 0x00, 0x08, + 0x00, 0x00, 0x00, 0x00, 0x24, 0x01, 0x04, 0x06, 0x08, 0x00, 0x00, 0x00, 0x23, 0x01, 0x04, 0x06, + 0x22, 0x05, 0x06, 0x00, 0x21, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0xFF, 0x07, 0xFF, 0x07, 0x12, 0x24, 0x0A, 0x00, 0x12, 0x24, 0x00, 0x00, 0x00, + 0x07, 0x03, 0xFF, 0xFF, 0x04, 0x00, 0x04, 0x00, 0x02, 0x00, 0x08, 0x2C, 0x02, 0x00, 0x08, 0x2C, + 0x01, 0x00, 0x0C, 0x00, 0x02, 0x00, 0x08, 0x00, 0x01, 0x04, 0x06, 0x08, 0x05, 0x06, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0x50, 0x52, 0x4F, 0x44, 0x55, 0x43, 0x54, 0x00, 0x00, 0x5F, 0x42, 0x4F, + 0x45, 0x5F, 0x5F, 0x00, 0x00, 0x00, 0x5F, 0x47, 0x4C, 0x53, 0x5F, 0x52, 0x4C, 0x4D, 0x5F, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x01, 0x00, 0x00, 0x24, 0x01, 0x00, 0x00, + 0x04, 0x00, 0x03, 0x00, 0x02, 0x00, 0x08, 0x2C, 0x02, 0x00, 0x08, 0x2C, 0x01, 0x00, 0x0C, 0x00, + 0x02, 0x00, 0x08, 0x00, 0x01, 0x04, 0x06, 0x08, 0x05, 0x06, 0x00, 0x00, 0xAF, 0x6B, 0x88, 0xEA, + 0x03, 0xFF, 0xFF, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x3E, 0x00, 0x00, 0x00, 0x3E, 0x00, 0xC9, 0x3A, 0x00, 0x00, 0xC9, 0x3A, 0x10, 0x00, 0x00, 0x00, + 0x36, 0x1A, 0x00, 0x00, 0x74, 0x1A, 0x00, 0x00, 0x74, 0x1A, 0xC9, 0x3A, 0x36, 0x1A, 0xC9, 0x3A, + 0x10, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0xBB, 0x00, 0x00, 0x00, 0xBB, 0x00, 0xC9, 0x3A, + 0x3E, 0x00, 0xC9, 0x3A, 0x0A, 0x00, 0x00, 0x00, 0xB9, 0x19, 0x00, 0x00, 0x36, 0x1A, 0x00, 0x00, + 0x36, 0x1A, 0xC9, 0x3A, 0xB9, 0x19, 0xC9, 0x3A, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8A, 0x2E, + 0x78, 0x01, 0x8A, 0x2E, 0x78, 0x01, 0xC9, 0x3A, 0x00, 0x00, 0xC9, 0x3A, 0x00, 0x00, 0x00, 0x00, + 0xFC, 0x18, 0x8A, 0x2E, 0x74, 0x1A, 0x8A, 0x2E, 0x74, 0x1A, 0xC9, 0x3A, 0xFC, 0x18, 0xC9, 0x3A, + 0x00, 0x00, 0x00, 0x00, 0x78, 0x01, 0x1D, 0x37, 0xF0, 0x02, 0x1D, 0x37, 0xF0, 0x02, 0xC9, 0x3A, + 0x78, 0x01, 0xC9, 0x3A, 0x00, 0x00, 0x00, 0x00, 0x84, 0x17, 0x1D, 0x37, 0xFC, 0x18, 0x1D, 0x37, + 0xFC, 0x18, 0xC9, 0x3A, 0x84, 0x17, 0xC9, 0x3A, 0x00, 0x00, 0x00, 0x00, 0x01, 0x06, 0x06, 0x01, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x74, 0x1A, 0x3E, 0x00, 0x74, 0x1A, 0xBB, 0x00, + 0x00, 0x00, 0xBB, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x3A, 0x74, 0x1A, 0x0E, 0x3A, + 0x74, 0x1A, 0x8B, 0x3A, 0x00, 0x00, 0x8B, 0x3A, 0x0A, 0x00, 0x00, 0x00, 0xB9, 0x19, 0x00, 0x00, + 0x36, 0x1A, 0x00, 0x00, 0x36, 0x1A, 0xC9, 0x3A, 0xB9, 0x19, 0xC9, 0x3A, 0x0A, 0x00, 0x00, 0x00, + 0xB9, 0x19, 0x00, 0x00, 0x36, 0x1A, 0x00, 0x00, 0x36, 0x1A, 0xC9, 0x3A, 0xB9, 0x19, 0xC9, 0x3A, + 0x0A, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0xBB, 0x00, 0x00, 0x00, 0xBB, 0x00, 0xC9, 0x3A, + 0x3E, 0x00, 0xC9, 0x3A, 0x0A, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0xBB, 0x00, 0x00, 0x00, + 0xBB, 0x00, 0xC9, 0x3A, 0x3E, 0x00, 0xC9, 0x3A, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x74, 0x1A, 0x00, 0x00, 0x74, 0x1A, 0x3E, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x8B, 0x3A, 0x74, 0x1A, 0x8B, 0x3A, 0x74, 0x1A, 0xC9, 0x3A, 0x00, 0x00, 0xC9, 0x3A, + 0x10, 0x00, 0x00, 0x00, 0x36, 0x1A, 0x00, 0x00, 0x74, 0x1A, 0x00, 0x00, 0x74, 0x1A, 0xC9, 0x3A, + 0x36, 0x1A, 0xC9, 0x3A, 0x10, 0x00, 0x00, 0x00, 0x36, 0x1A, 0x00, 0x00, 0x74, 0x1A, 0x00, 0x00, + 0x74, 0x1A, 0xC9, 0x3A, 0x36, 0x1A, 0xC9, 0x3A, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x3E, 0x00, 0x00, 0x00, 0x3E, 0x00, 0xC9, 0x3A, 0x00, 0x00, 0xC9, 0x3A, 0x10, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x3E, 0x00, 0xC9, 0x3A, 0x00, 0x00, 0xC9, 0x3A, + 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x0C, 0x00, 0x00, 0x3F, 0x0C, 0xF0, 0x02, + 0x00, 0x00, 0xF0, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD9, 0x37, 0x3F, 0x0C, 0xD9, 0x37, + 0x3F, 0x0C, 0xC9, 0x3A, 0x00, 0x00, 0xC9, 0x3A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x06, 0x06, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x3A, + 0x74, 0x1A, 0x0E, 0x3A, 0x74, 0x1A, 0x8B, 0x3A, 0x00, 0x00, 0x8B, 0x3A, 0x0A, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3E, 0x00, 0x74, 0x1A, 0x3E, 0x00, 0x74, 0x1A, 0xBB, 0x00, 0x00, 0x00, 0xBB, 0x00, + 0x0A, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0xBB, 0x00, 0x00, 0x00, 0xBB, 0x00, 0xC9, 0x3A, + 0x3E, 0x00, 0xC9, 0x3A, 0x0A, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0xBB, 0x00, 0x00, 0x00, + 0xBB, 0x00, 0xC9, 0x3A, 0x3E, 0x00, 0xC9, 0x3A, 0x0A, 0x00, 0x00, 0x00, 0xB9, 0x19, 0x00, 0x00, + 0x36, 0x1A, 0x00, 0x00, 0x36, 0x1A, 0xC9, 0x3A, 0xB9, 0x19, 0xC9, 0x3A, 0x0A, 0x00, 0x00, 0x00, + 0xB9, 0x19, 0x00, 0x00, 0x36, 0x1A, 0x00, 0x00, 0x36, 0x1A, 0xC9, 0x3A, 0xB9, 0x19, 0xC9, 0x3A, + 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8B, 0x3A, 0x74, 0x1A, 0x8B, 0x3A, 0x74, 0x1A, 0xC9, 0x3A, + 0x00, 0x00, 0xC9, 0x3A, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x74, 0x1A, 0x00, 0x00, + 0x74, 0x1A, 0x3E, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x3E, 0x00, 0x00, 0x00, 0x3E, 0x00, 0xC9, 0x3A, 0x00, 0x00, 0xC9, 0x3A, 0x10, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x3E, 0x00, 0xC9, 0x3A, 0x00, 0x00, 0xC9, 0x3A, + 0x10, 0x00, 0x00, 0x00, 0x36, 0x1A, 0x00, 0x00, 0x74, 0x1A, 0x00, 0x00, 0x74, 0x1A, 0xC9, 0x3A, + 0x36, 0x1A, 0xC9, 0x3A, 0x10, 0x00, 0x00, 0x00, 0x36, 0x1A, 0x00, 0x00, 0x74, 0x1A, 0x00, 0x00, + 0x74, 0x1A, 0xC9, 0x3A, 0x36, 0x1A, 0xC9, 0x3A, 0x10, 0x00, 0x00, 0x00, 0x35, 0x0E, 0xD9, 0x37, + 0x74, 0x1A, 0xD9, 0x37, 0x74, 0x1A, 0xC9, 0x3A, 0x35, 0x0E, 0xC9, 0x3A, 0x00, 0x00, 0x00, 0x00, + 0x35, 0x0E, 0x00, 0x00, 0x74, 0x1A, 0x00, 0x00, 0x74, 0x1A, 0xF0, 0x02, 0x35, 0x0E, 0xF0, 0x02, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x00, 0x64, 0x00, + 0x10, 0x1A, 0x65, 0x3A, 0x2C, 0x01, 0x14, 0x00, 0x3F, 0x00, 0x0F, 0x00, 0x53, 0x01, 0x32, 0x01, + 0x01, 0x00, 0x23, 0x00, 0x0C, 0x08, 0x14, 0x05, 0xD0, 0x07, 0x84, 0x03, 0x50, 0x00, 0x64, 0x00, + 0xB0, 0xFF, 0x9C, 0xFF, 0x0A, 0x00, 0x01, 0x00, 0xD8, 0x00, 0x01, 0x01, 0x01, 0x24, 0x01, 0x12, + 0x01, 0x06, 0x01, 0x02, 0x2C, 0x01, 0x88, 0x13, 0xE8, 0x03, 0x88, 0x13, 0x2C, 0x01, 0xF4, 0x01, + 0xE8, 0x03, 0xE8, 0x03, 0xD0, 0x07, 0xD0, 0x07, 0x3C, 0x05, 0xAA, 0x00, 0x1E, 0x00, 0xCC, 0x01, + 0x03, 0x02, 0x02, 0x01, 0x1E, 0x00, 0x5E, 0x01, 0x64, 0x00, 0x8A, 0x00, 0x28, 0x00, 0x00, 0x50, + 0x27, 0x0E, 0x09, 0x64, 0x48, 0x02, 0x01, 0x08, 0x00, 0x02, 0x3F, 0x01, 0x02, 0x04, 0x03, 0x03, + 0x0A, 0x04, 0x04, 0x04, 0x02, 0x02, 0x03, 0x08, 0x02, 0x6C, 0x02, 0x01, 0x00, 0x03, 0x30, 0x0A, + 0x0A, 0x06, 0x04, 0xC8, 0x14, 0x10, 0x0C, 0x19, 0x19, 0x00, 0x00, 0x00, 0x88, 0x02, 0x00, 0x00, + 0x0A, 0x39, 0x01, 0x00, 0xA0, 0x86, 0x01, 0x00, 0x55, 0x00, 0x2D, 0x00, 0x41, 0x00, 0x0A, 0x00, + 0x0A, 0x00, 0x37, 0x00, 0xC8, 0x00, 0x15, 0x16, 0xA4, 0x29, 0xC2, 0x11, 0x51, 0x25, 0xCC, 0x01, + 0x90, 0x01, 0xD0, 0x07, 0x96, 0x00, 0xC2, 0x01, 0xC2, 0x01, 0x96, 0x00, 0x96, 0x00, 0x96, 0x00, + 0x01, 0x64, 0x0B, 0x0B, 0x36, 0x6E, 0x00, 0x02, 0x6C, 0x36, 0x02, 0x08, 0x06, 0x00, 0xF4, 0x01, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, + 0x24, 0x00, 0x00, 0x00, 0xC8, 0x0D, 0x02, 0x00, 0x08, 0x13, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x14, 0x00, 0xEC, 0xFF, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5A, 0x03, + 0xFC, 0x12, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0xEC, 0xFF, 0x14, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5A, 0x03, 0xF0, 0x12, 0x02, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x14, 0x00, 0xEC, 0xFF, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5A, 0x03, + 0x44, 0x22, 0x02, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0xEC, 0xFF, 0x14, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5A, 0x03, 0xE4, 0x12, 0x02, 0x00, 0x0B, 0x00, 0x00, 0x00, + 0x28, 0x00, 0x5A, 0x00, 0xA6, 0xFF, 0xD8, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x03, + 0xD8, 0x12, 0x02, 0x00, 0x08, 0x00, 0x00, 0x00, 0x32, 0x00, 0x6E, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x26, 0x3A, 0x41, 0x09, 0xC4, 0x12, 0x02, 0x00, 0x09, 0x01, 0x00, 0x00, + 0x3C, 0x00, 0xB4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x26, 0x3A, 0x41, 0x09, + 0xB0, 0x12, 0x02, 0x00, 0x09, 0x01, 0x00, 0x00, 0x3C, 0x00, 0xB4, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x26, 0x3A, 0x41, 0x09, 0xA4, 0x12, 0x02, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x3C, 0x00, 0xB4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x26, 0x3A, 0x41, 0x09, + 0x98, 0x12, 0x02, 0x00, 0x08, 0x00, 0x00, 0x00, 0x3C, 0x00, 0xB4, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x26, 0x3A, 0x41, 0x09, 0x8C, 0x12, 0x02, 0x00, 0x05, 0x00, 0x00, 0x00, + 0x32, 0x00, 0x6E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x1A, 0x46, 0x09, + 0x80, 0x12, 0x02, 0x00, 0x06, 0x00, 0x00, 0x00, 0x64, 0x00, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x01, 0x6C, 0x12, 0x02, 0x00, 0x07, 0x01, 0x00, 0x00, + 0x64, 0x00, 0xBE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x01, + 0x58, 0x12, 0x02, 0x00, 0x07, 0x01, 0x00, 0x00, 0x64, 0x00, 0xBE, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x01, 0x44, 0x12, 0x02, 0x00, 0x07, 0x01, 0x00, 0x00, + 0x64, 0x00, 0xBE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x01, + 0x38, 0x12, 0x02, 0x00, 0x05, 0x00, 0x00, 0x00, 0x32, 0x00, 0x6E, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x06, 0x1A, 0x46, 0x09, 0x2C, 0x12, 0x02, 0x00, 0x05, 0x00, 0x00, 0x00, + 0x32, 0x00, 0x6E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x1A, 0x46, 0x09, + 0x20, 0x12, 0x02, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x5A, 0x00, 0xF1, 0xFF, 0x1E, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x03, 0x14, 0x12, 0x02, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x1E, 0x00, 0x46, 0x00, 0xF6, 0xFF, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x03, + 0x08, 0x12, 0x02, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0F, 0x00, 0xA5, 0x00, 0x26, 0x3A, 0x3C, 0x0D, 0xFC, 0x11, 0x02, 0x00, 0x11, 0x00, 0x00, 0x00, + 0x0A, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x00, 0xA5, 0x00, 0x06, 0x1A, 0x3C, 0x0D, + 0xF0, 0x11, 0x02, 0x00, 0x12, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0F, 0x00, 0xA5, 0x00, 0x16, 0x2A, 0x3C, 0x0D, 0xE4, 0x11, 0x02, 0x00, 0x13, 0x00, 0x00, 0x00, + 0x0A, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x00, 0xA5, 0x00, 0x36, 0x4A, 0x3C, 0x0D, + 0xD8, 0x11, 0x02, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x28, 0x00, 0x80, 0x00, 0x80, 0xFF, 0xD8, 0xFF, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x03, 0xCC, 0x11, 0x02, 0x00, 0x0E, 0x00, 0x00, 0x00, + 0x28, 0x00, 0x80, 0x00, 0x28, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x03, + 0xC0, 0x11, 0x02, 0x00, 0x15, 0x00, 0x00, 0x00, 0x28, 0x00, 0x64, 0x00, 0xC4, 0xFF, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x10, 0x30, 0x3C, 0x0B, 0xB4, 0x11, 0x02, 0x00, 0x15, 0x00, 0x00, 0x00, + 0x28, 0x00, 0x64, 0x00, 0xC4, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x30, 0x3C, 0x0B, + 0xA8, 0x11, 0x02, 0x00, 0x16, 0x00, 0x00, 0x00, 0x32, 0x00, 0x64, 0x00, 0x00, 0x00, 0x32, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x30, 0x40, 0x3C, 0x0B, 0x94, 0x11, 0x02, 0x00, 0x17, 0x01, 0x00, 0x00, + 0x64, 0x00, 0xBE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x01, + 0x80, 0x11, 0x02, 0x00, 0x17, 0x01, 0x00, 0x00, 0x64, 0x00, 0xBE, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x01, 0x6C, 0x11, 0x02, 0x00, 0x17, 0x01, 0x00, 0x00, + 0x6E, 0x00, 0xB4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x01, + 0x58, 0x11, 0x02, 0x00, 0x17, 0x01, 0x00, 0x00, 0x6E, 0x00, 0xB4, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x01, 0x4C, 0x11, 0x02, 0x00, 0x0C, 0x00, 0x00, 0x00, + 0x0A, 0x00, 0x2D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x00, 0xA5, 0x00, 0x26, 0x3A, 0x3C, 0x0D, + 0x40, 0x11, 0x02, 0x00, 0x11, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0F, 0x00, 0xA5, 0x00, 0x06, 0x1A, 0x3C, 0x0D, 0x28, 0x11, 0x02, 0x00, 0x12, 0x00, 0x00, 0x00, + 0x0A, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x00, 0xA5, 0x00, 0x16, 0x2A, 0x3C, 0x0D, + 0x34, 0x11, 0x02, 0x00, 0x13, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0F, 0x00, 0xA5, 0x00, 0x36, 0x4A, 0x3C, 0x0D, 0x3A, 0x39, 0x38, 0x36, 0x35, 0x2B, 0x26, 0x26, + 0x26, 0x26, 0x00, 0x00, 0x23, 0x24, 0x26, 0x28, 0x2D, 0x38, 0x38, 0x39, 0x39, 0x3A, 0x00, 0x00, + 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x16, 0x16, 0x16, 0x16, 0x16, 0x00, 0x00, 0x15, 0x16, 0x16, 0x16, + 0x19, 0x29, 0x2A, 0x2A, 0x2B, 0x2B, 0x00, 0x00, 0x22, 0x17, 0x0F, 0x01, 0x36, 0x38, 0x0B, 0x10, + 0x18, 0x1F, 0x25, 0x2B, 0x31, 0x35, 0x39, 0x3E, 0x05, 0x0C, 0x11, 0x14, 0x21, 0x16, 0x07, 0x39, + 0x3F, 0x0E, 0x13, 0x1B, 0x24, 0x2A, 0x2F, 0x34, 0x38, 0x3C, 0x02, 0x08, 0x0E, 0x13, 0x17, 0x1A, + 0x1F, 0x15, 0x0A, 0x3A, 0x36, 0x0D, 0x04, 0x35, 0x2F, 0x2A, 0x22, 0x1C, 0x17, 0x14, 0x10, 0x0C, + 0x06, 0x3E, 0x39, 0x36, 0x22, 0x19, 0x11, 0x02, 0x38, 0x35, 0x11, 0x09, 0x39, 0x32, 0x2D, 0x26, + 0x1F, 0x1A, 0x16, 0x12, 0x0D, 0x06, 0x3F, 0x3A, 0x21, 0x15, 0x0E, 0x0E, 0x10, 0x19, 0x28, 0x33, + 0x3A, 0x3D, 0x00, 0x00, 0x00, 0x3B, 0x35, 0x2F, 0x1D, 0x14, 0x11, 0x0F, 0x0F, 0x10, 0x00, 0x00, + 0x3E, 0x3A, 0x32, 0x23, 0x15, 0x10, 0x0E, 0x10, 0x16, 0x21, 0x00, 0x00, 0x1E, 0x2A, 0x30, 0x33, + 0x37, 0x01, 0x0A, 0x10, 0x13, 0x15, 0x00, 0x00, 0x19, 0x14, 0x10, 0x06, 0x3D, 0x39, 0x34, 0x2B, + 0x24, 0x20, 0x00, 0x00, 0x1B, 0x1B, 0x1A, 0x1A, 0x16, 0x0A, 0x05, 0x05, 0x05, 0x05, 0x00, 0x00, + 0x04, 0x04, 0x05, 0x06, 0x0B, 0x15, 0x19, 0x1A, 0x1A, 0x1A, 0x00, 0x00, 0x34, 0x34, 0x35, 0x35, + 0x35, 0x00, 0x0D, 0x0E, 0x0D, 0x0E, 0x00, 0x00, 0x0B, 0x0B, 0x0A, 0x0A, 0x09, 0x39, 0x36, 0x36, + 0x36, 0x35, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x16, 0x18, 0x18, 0x11, 0x03, 0x00, 0x3F, 0x00, 0x00, + 0x22, 0x1C, 0x15, 0x0D, 0x08, 0x09, 0x0E, 0x16, 0x1D, 0x22, 0x00, 0x00, 0x35, 0x31, 0x32, 0x3A, + 0x10, 0x10, 0x10, 0x32, 0x38, 0x0E, 0x00, 0x00, 0x32, 0x38, 0x0E, 0x35, 0x31, 0x32, 0x3A, 0x10, + 0x10, 0x10, 0x00, 0x00, 0x3F, 0x0C, 0x0D, 0x12, 0x25, 0x33, 0x36, 0x3C, 0x08, 0x0F, 0x0C, 0x19, + 0x34, 0x35, 0x39, 0x0A, 0x0D, 0x0E, 0x01, 0x3A, 0x36, 0x3F, 0x0E, 0x11, 0x11, 0x0C, 0x32, 0x33, + 0x36, 0x04, 0x0E, 0x10, 0x0D, 0x33, 0x33, 0x37, 0x07, 0x0E, 0x0E, 0x07, 0x0B, 0x0F, 0x11, 0x0E, + 0x33, 0x33, 0x35, 0x3B, 0x0A, 0x10, 0x11, 0x10, 0x34, 0x34, 0x37, 0x02, 0x0C, 0x0F, 0x0D, 0x0B, + 0x0E, 0x10, 0x31, 0x35, 0x0A, 0x0F, 0x32, 0x37, 0x0C, 0x0E, 0x00, 0x00, 0x32, 0x34, 0x3E, 0x0C, + 0x08, 0x36, 0x36, 0x04, 0x0E, 0x0E, 0x00, 0x00, 0x0E, 0x0E, 0x0E, 0x34, 0x36, 0x30, 0x32, 0x0D, + 0x32, 0x34, 0x00, 0x00, 0x0E, 0x3E, 0x34, 0x0B, 0x0E, 0x0E, 0x3B, 0x32, 0x32, 0x32, 0x00, 0x00, + 0x0E, 0x0F, 0x0F, 0x0D, 0x02, 0x36, 0x33, 0x33, 0x35, 0x08, 0x0E, 0x0E, 0x0B, 0x04, 0x39, 0x33, + 0x32, 0x33, 0x36, 0x3E, 0x3D, 0x09, 0x0F, 0x10, 0x10, 0x0A, 0x39, 0x34, 0x34, 0x35, 0x03, 0x0D, + 0x0F, 0x0D, 0x06, 0x37, 0x34, 0x33, 0x33, 0x36, 0x0F, 0x0C, 0x3F, 0x35, 0x3C, 0x0C, 0x08, 0x3A, + 0x34, 0x34, 0x00, 0x00, 0x3D, 0x39, 0x31, 0x22, 0x1A, 0x15, 0x10, 0x08, 0x02, 0x3D, 0x00, 0x00, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x00, 0x00, 0xFF, 0x7F, 0x70, 0x0C, 0x34, 0x03, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0xC9, 0x3A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x74, 0x1A, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x0B, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0B, 0x02, 0x05, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x1B, 0x01, 0x40, 0x02, + 0xAC, 0x03, 0x1F, 0x05, 0x94, 0x06, 0x09, 0x08, 0x88, 0x09, 0x00, 0x0B, 0x78, 0x0C, 0xF0, 0x0D, + 0x69, 0x0F, 0xE1, 0x10, 0x59, 0x12, 0xD1, 0x13, 0x4A, 0x15, 0xC2, 0x16, 0x38, 0x18, 0x9B, 0x19, + 0xD1, 0x00, 0x73, 0x02, 0x15, 0x04, 0xB7, 0x05, 0x59, 0x07, 0xFB, 0x08, 0x9D, 0x0A, 0x3F, 0x0C, + 0xE2, 0x0D, 0x84, 0x0F, 0x25, 0x11, 0xC7, 0x12, 0x69, 0x14, 0x0B, 0x16, 0xAD, 0x17, 0x4F, 0x19, + 0xF1, 0x1A, 0x8E, 0x1C, 0x2F, 0x1E, 0xD7, 0x1F, 0x79, 0x21, 0x1B, 0x23, 0xBD, 0x24, 0x5F, 0x26, + 0x01, 0x28, 0xA2, 0x29, 0x33, 0x2B, 0xDE, 0x2C, 0x89, 0x2E, 0x2B, 0x30, 0xCE, 0x31, 0x70, 0x33, + 0x12, 0x35, 0xB3, 0x36, 0x55, 0x38, 0xF7, 0x39, 0xBC, 0x00, 0x33, 0x02, 0xA8, 0x03, 0x1F, 0x05, + 0x8D, 0x06, 0x05, 0x08, 0x89, 0x09, 0x01, 0x0B, 0x70, 0x0C, 0xE6, 0x0D, 0x6A, 0x0F, 0xE3, 0x10, + 0x53, 0x12, 0xC5, 0x13, 0x4B, 0x15, 0xC4, 0x16, 0x3E, 0x18, 0xB7, 0x19, 0x77, 0x02, 0x53, 0x02, + 0x2F, 0x02, 0x0B, 0x02, 0xE7, 0x01, 0xC3, 0x01, 0x9F, 0x01, 0x7B, 0x01, 0x57, 0x01, 0x33, 0x01, + 0x0F, 0x01, 0xEB, 0x00, 0xC7, 0x00, 0xA3, 0x00, 0x7F, 0x00, 0x5B, 0x00, 0x37, 0x00, 0x13, 0x00, + 0x78, 0x02, 0x54, 0x02, 0x30, 0x02, 0x0C, 0x02, 0xE8, 0x01, 0xC4, 0x01, 0xA0, 0x01, 0x7C, 0x01, + 0x58, 0x01, 0x34, 0x01, 0x10, 0x01, 0xEC, 0x00, 0xC8, 0x00, 0xA4, 0x00, 0x80, 0x00, 0x5C, 0x00, + 0x38, 0x00, 0x14, 0x00, 0x79, 0x02, 0x55, 0x02, 0x31, 0x02, 0x0D, 0x02, 0xE9, 0x01, 0xC5, 0x01, + 0xA1, 0x01, 0x7D, 0x01, 0x59, 0x01, 0x35, 0x01, 0x11, 0x01, 0xED, 0x00, 0xC9, 0x00, 0xA5, 0x00, + 0x81, 0x00, 0x5D, 0x00, 0x39, 0x00, 0x15, 0x00, 0x7A, 0x02, 0x56, 0x02, 0x32, 0x02, 0x0E, 0x02, + 0xEA, 0x01, 0xC6, 0x01, 0xA2, 0x01, 0x7E, 0x01, 0x5A, 0x01, 0x36, 0x01, 0x12, 0x01, 0xEE, 0x00, + 0xCA, 0x00, 0xA6, 0x00, 0x82, 0x00, 0x5E, 0x00, 0x3A, 0x00, 0x16, 0x00, 0x7B, 0x02, 0x57, 0x02, + 0x33, 0x02, 0x0F, 0x02, 0xEB, 0x01, 0xC7, 0x01, 0xA3, 0x01, 0x7F, 0x01, 0x5B, 0x01, 0x37, 0x01, + 0x13, 0x01, 0xEF, 0x00, 0xCB, 0x00, 0xA7, 0x00, 0x83, 0x00, 0x5F, 0x00, 0x3B, 0x00, 0x17, 0x00, + 0x7C, 0x02, 0x58, 0x02, 0x34, 0x02, 0x10, 0x02, 0xEC, 0x01, 0xC8, 0x01, 0xA4, 0x01, 0x80, 0x01, + 0x5C, 0x01, 0x38, 0x01, 0x14, 0x01, 0xF0, 0x00, 0xCC, 0x00, 0xA8, 0x00, 0x84, 0x00, 0x60, 0x00, + 0x3C, 0x00, 0x18, 0x00, 0x7D, 0x02, 0x59, 0x02, 0x35, 0x02, 0x11, 0x02, 0xED, 0x01, 0xC9, 0x01, + 0xA5, 0x01, 0x81, 0x01, 0x5D, 0x01, 0x39, 0x01, 0x15, 0x01, 0xF1, 0x00, 0xCD, 0x00, 0xA9, 0x00, + 0x85, 0x00, 0x61, 0x00, 0x3D, 0x00, 0x19, 0x00, 0x7E, 0x02, 0x5A, 0x02, 0x36, 0x02, 0x12, 0x02, + 0xEE, 0x01, 0xCA, 0x01, 0xA6, 0x01, 0x82, 0x01, 0x5E, 0x01, 0x3A, 0x01, 0x16, 0x01, 0xF2, 0x00, + 0xCE, 0x00, 0xAA, 0x00, 0x86, 0x00, 0x62, 0x00, 0x3E, 0x00, 0x1A, 0x00, 0x7F, 0x02, 0x5B, 0x02, + 0x37, 0x02, 0x13, 0x02, 0xEF, 0x01, 0xCB, 0x01, 0xA7, 0x01, 0x83, 0x01, 0x5F, 0x01, 0x3B, 0x01, + 0x17, 0x01, 0xF3, 0x00, 0xCF, 0x00, 0xAB, 0x00, 0x87, 0x00, 0x63, 0x00, 0x3F, 0x00, 0x1B, 0x00, + 0x80, 0x02, 0x5C, 0x02, 0x38, 0x02, 0x14, 0x02, 0xF0, 0x01, 0xCC, 0x01, 0xA8, 0x01, 0x84, 0x01, + 0x60, 0x01, 0x3C, 0x01, 0x18, 0x01, 0xF4, 0x00, 0xD0, 0x00, 0xAC, 0x00, 0x88, 0x00, 0x64, 0x00, + 0x40, 0x00, 0x1C, 0x00, 0x81, 0x02, 0x5D, 0x02, 0x39, 0x02, 0x15, 0x02, 0xF1, 0x01, 0xCD, 0x01, + 0xA9, 0x01, 0x85, 0x01, 0x61, 0x01, 0x3D, 0x01, 0x19, 0x01, 0xF5, 0x00, 0xD1, 0x00, 0xAD, 0x00, + 0x89, 0x00, 0x65, 0x00, 0x41, 0x00, 0x1D, 0x00, 0x82, 0x02, 0x5E, 0x02, 0x3A, 0x02, 0x16, 0x02, + 0xF2, 0x01, 0xCE, 0x01, 0xAA, 0x01, 0x86, 0x01, 0x62, 0x01, 0x3E, 0x01, 0x1A, 0x01, 0xF6, 0x00, + 0xD2, 0x00, 0xAE, 0x00, 0x8A, 0x00, 0x66, 0x00, 0x42, 0x00, 0x1E, 0x00, 0x83, 0x02, 0x5F, 0x02, + 0x3B, 0x02, 0x17, 0x02, 0xF3, 0x01, 0xCF, 0x01, 0xAB, 0x01, 0x87, 0x01, 0x63, 0x01, 0x3F, 0x01, + 0x1B, 0x01, 0xF7, 0x00, 0xD3, 0x00, 0xAF, 0x00, 0x8B, 0x00, 0x67, 0x00, 0x43, 0x00, 0x1F, 0x00, + 0x84, 0x02, 0x60, 0x02, 0x3C, 0x02, 0x18, 0x02, 0xF4, 0x01, 0xD0, 0x01, 0xAC, 0x01, 0x88, 0x01, + 0x64, 0x01, 0x40, 0x01, 0x1C, 0x01, 0xF8, 0x00, 0xD4, 0x00, 0xB0, 0x00, 0x8C, 0x00, 0x68, 0x00, + 0x44, 0x00, 0x20, 0x00, 0x85, 0x02, 0x61, 0x02, 0x3D, 0x02, 0x19, 0x02, 0xF5, 0x01, 0xD1, 0x01, + 0xAD, 0x01, 0x89, 0x01, 0x65, 0x01, 0x41, 0x01, 0x1D, 0x01, 0xF9, 0x00, 0xD5, 0x00, 0xB1, 0x00, + 0x8D, 0x00, 0x69, 0x00, 0x45, 0x00, 0x21, 0x00, 0x86, 0x02, 0x62, 0x02, 0x3E, 0x02, 0x1A, 0x02, + 0xF6, 0x01, 0xD2, 0x01, 0xAE, 0x01, 0x8A, 0x01, 0x66, 0x01, 0x42, 0x01, 0x1E, 0x01, 0xFA, 0x00, + 0xD6, 0x00, 0xB2, 0x00, 0x8E, 0x00, 0x6A, 0x00, 0x46, 0x00, 0x22, 0x00, 0x87, 0x02, 0x63, 0x02, + 0x3F, 0x02, 0x1B, 0x02, 0xF7, 0x01, 0xD3, 0x01, 0xAF, 0x01, 0x8B, 0x01, 0x67, 0x01, 0x43, 0x01, + 0x1F, 0x01, 0xFB, 0x00, 0xD7, 0x00, 0xB3, 0x00, 0x8F, 0x00, 0x6B, 0x00, 0x47, 0x00, 0x23, 0x00, + 0x88, 0x02, 0x64, 0x02, 0x40, 0x02, 0x1C, 0x02, 0xF8, 0x01, 0xD4, 0x01, 0xB0, 0x01, 0x8C, 0x01, + 0x68, 0x01, 0x44, 0x01, 0x20, 0x01, 0xFC, 0x00, 0xD8, 0x00, 0xB4, 0x00, 0x90, 0x00, 0x6C, 0x00, + 0x48, 0x00, 0x24, 0x00, 0x65, 0x02, 0x41, 0x02, 0x1D, 0x02, 0xF9, 0x01, 0xD5, 0x01, 0xB1, 0x01, + 0x8D, 0x01, 0x69, 0x01, 0x45, 0x01, 0x21, 0x01, 0xFD, 0x00, 0xD9, 0x00, 0xB5, 0x00, 0x91, 0x00, + 0x6D, 0x00, 0x49, 0x00, 0x25, 0x00, 0x01, 0x00, 0x66, 0x02, 0x42, 0x02, 0x1E, 0x02, 0xFA, 0x01, + 0xD6, 0x01, 0xB2, 0x01, 0x8E, 0x01, 0x6A, 0x01, 0x46, 0x01, 0x22, 0x01, 0xFE, 0x00, 0xDA, 0x00, + 0xB6, 0x00, 0x92, 0x00, 0x6E, 0x00, 0x4A, 0x00, 0x26, 0x00, 0x02, 0x00, 0x67, 0x02, 0x43, 0x02, + 0x1F, 0x02, 0xFB, 0x01, 0xD7, 0x01, 0xB3, 0x01, 0x8F, 0x01, 0x6B, 0x01, 0x47, 0x01, 0x23, 0x01, + 0xFF, 0x00, 0xDB, 0x00, 0xB7, 0x00, 0x93, 0x00, 0x6F, 0x00, 0x4B, 0x00, 0x27, 0x00, 0x03, 0x00, + 0x68, 0x02, 0x44, 0x02, 0x20, 0x02, 0xFC, 0x01, 0xD8, 0x01, 0xB4, 0x01, 0x90, 0x01, 0x6C, 0x01, + 0x48, 0x01, 0x24, 0x01, 0x00, 0x01, 0xDC, 0x00, 0xB8, 0x00, 0x94, 0x00, 0x70, 0x00, 0x4C, 0x00, + 0x28, 0x00, 0x04, 0x00, 0x69, 0x02, 0x45, 0x02, 0x21, 0x02, 0xFD, 0x01, 0xD9, 0x01, 0xB5, 0x01, + 0x91, 0x01, 0x6D, 0x01, 0x49, 0x01, 0x25, 0x01, 0x01, 0x01, 0xDD, 0x00, 0xB9, 0x00, 0x95, 0x00, + 0x71, 0x00, 0x4D, 0x00, 0x29, 0x00, 0x05, 0x00, 0x6A, 0x02, 0x46, 0x02, 0x22, 0x02, 0xFE, 0x01, + 0xDA, 0x01, 0xB6, 0x01, 0x92, 0x01, 0x6E, 0x01, 0x4A, 0x01, 0x26, 0x01, 0x02, 0x01, 0xDE, 0x00, + 0xBA, 0x00, 0x96, 0x00, 0x72, 0x00, 0x4E, 0x00, 0x2A, 0x00, 0x06, 0x00, 0x6B, 0x02, 0x47, 0x02, + 0x23, 0x02, 0xFF, 0x01, 0xDB, 0x01, 0xB7, 0x01, 0x93, 0x01, 0x6F, 0x01, 0x4B, 0x01, 0x27, 0x01, + 0x03, 0x01, 0xDF, 0x00, 0xBB, 0x00, 0x97, 0x00, 0x73, 0x00, 0x4F, 0x00, 0x2B, 0x00, 0x07, 0x00, + 0x6C, 0x02, 0x48, 0x02, 0x24, 0x02, 0x00, 0x02, 0xDC, 0x01, 0xB8, 0x01, 0x94, 0x01, 0x70, 0x01, + 0x4C, 0x01, 0x28, 0x01, 0x04, 0x01, 0xE0, 0x00, 0xBC, 0x00, 0x98, 0x00, 0x74, 0x00, 0x50, 0x00, + 0x2C, 0x00, 0x08, 0x00, 0x6D, 0x02, 0x49, 0x02, 0x25, 0x02, 0x01, 0x02, 0xDD, 0x01, 0xB9, 0x01, + 0x95, 0x01, 0x71, 0x01, 0x4D, 0x01, 0x29, 0x01, 0x05, 0x01, 0xE1, 0x00, 0xBD, 0x00, 0x99, 0x00, + 0x75, 0x00, 0x51, 0x00, 0x2D, 0x00, 0x09, 0x00, 0x6E, 0x02, 0x4A, 0x02, 0x26, 0x02, 0x02, 0x02, + 0xDE, 0x01, 0xBA, 0x01, 0x96, 0x01, 0x72, 0x01, 0x4E, 0x01, 0x2A, 0x01, 0x06, 0x01, 0xE2, 0x00, + 0xBE, 0x00, 0x9A, 0x00, 0x76, 0x00, 0x52, 0x00, 0x2E, 0x00, 0x0A, 0x00, 0x6F, 0x02, 0x4B, 0x02, + 0x27, 0x02, 0x03, 0x02, 0xDF, 0x01, 0xBB, 0x01, 0x97, 0x01, 0x73, 0x01, 0x4F, 0x01, 0x2B, 0x01, + 0x07, 0x01, 0xE3, 0x00, 0xBF, 0x00, 0x9B, 0x00, 0x77, 0x00, 0x53, 0x00, 0x2F, 0x00, 0x0B, 0x00, + 0x70, 0x02, 0x4C, 0x02, 0x28, 0x02, 0x04, 0x02, 0xE0, 0x01, 0xBC, 0x01, 0x98, 0x01, 0x74, 0x01, + 0x50, 0x01, 0x2C, 0x01, 0x08, 0x01, 0xE4, 0x00, 0xC0, 0x00, 0x9C, 0x00, 0x78, 0x00, 0x54, 0x00, + 0x30, 0x00, 0x0C, 0x00, 0x71, 0x02, 0x4D, 0x02, 0x29, 0x02, 0x05, 0x02, 0xE1, 0x01, 0xBD, 0x01, + 0x99, 0x01, 0x75, 0x01, 0x51, 0x01, 0x2D, 0x01, 0x09, 0x01, 0xE5, 0x00, 0xC1, 0x00, 0x9D, 0x00, + 0x79, 0x00, 0x55, 0x00, 0x31, 0x00, 0x0D, 0x00, 0x72, 0x02, 0x4E, 0x02, 0x2A, 0x02, 0x06, 0x02, + 0xE2, 0x01, 0xBE, 0x01, 0x9A, 0x01, 0x76, 0x01, 0x52, 0x01, 0x2E, 0x01, 0x0A, 0x01, 0xE6, 0x00, + 0xC2, 0x00, 0x9E, 0x00, 0x7A, 0x00, 0x56, 0x00, 0x32, 0x00, 0x0E, 0x00, 0x73, 0x02, 0x4F, 0x02, + 0x2B, 0x02, 0x07, 0x02, 0xE3, 0x01, 0xBF, 0x01, 0x9B, 0x01, 0x77, 0x01, 0x53, 0x01, 0x2F, 0x01, + 0x0B, 0x01, 0xE7, 0x00, 0xC3, 0x00, 0x9F, 0x00, 0x7B, 0x00, 0x57, 0x00, 0x33, 0x00, 0x0F, 0x00, + 0x74, 0x02, 0x50, 0x02, 0x2C, 0x02, 0x08, 0x02, 0xE4, 0x01, 0xC0, 0x01, 0x9C, 0x01, 0x78, 0x01, + 0x54, 0x01, 0x30, 0x01, 0x0C, 0x01, 0xE8, 0x00, 0xC4, 0x00, 0xA0, 0x00, 0x7C, 0x00, 0x58, 0x00, + 0x34, 0x00, 0x10, 0x00, 0x75, 0x02, 0x51, 0x02, 0x2D, 0x02, 0x09, 0x02, 0xE5, 0x01, 0xC1, 0x01, + 0x9D, 0x01, 0x79, 0x01, 0x55, 0x01, 0x31, 0x01, 0x0D, 0x01, 0xE9, 0x00, 0xC5, 0x00, 0xA1, 0x00, + 0x7D, 0x00, 0x59, 0x00, 0x35, 0x00, 0x11, 0x00, 0x76, 0x02, 0x52, 0x02, 0x2E, 0x02, 0x0A, 0x02, + 0xE6, 0x01, 0xC2, 0x01, 0x9E, 0x01, 0x7A, 0x01, 0x56, 0x01, 0x32, 0x01, 0x0E, 0x01, 0xEA, 0x00, + 0xC6, 0x00, 0xA2, 0x00, 0x7E, 0x00, 0x5A, 0x00, 0x36, 0x00, 0x12, 0x00, 0xD7, 0x00, 0x87, 0x02, + 0xAE, 0x01, 0xD5, 0x00, 0x85, 0x02, 0xAC, 0x01, 0xD3, 0x00, 0x83, 0x02, 0xAA, 0x01, 0xB5, 0x01, + 0x05, 0x00, 0xDC, 0x00, 0xB3, 0x01, 0x03, 0x00, 0xDA, 0x00, 0xB1, 0x01, 0x01, 0x00, 0xD8, 0x00, + 0xCB, 0x00, 0x7B, 0x02, 0xA2, 0x01, 0xC9, 0x00, 0x79, 0x02, 0xA0, 0x01, 0xC7, 0x00, 0x77, 0x02, + 0x9E, 0x01, 0xC1, 0x01, 0x11, 0x00, 0xE8, 0x00, 0xBF, 0x01, 0x0F, 0x00, 0xE6, 0x00, 0xBD, 0x01, + 0x0D, 0x00, 0xE4, 0x00, 0xBF, 0x00, 0x6F, 0x02, 0x96, 0x01, 0xBD, 0x00, 0x6D, 0x02, 0x94, 0x01, + 0xBB, 0x00, 0x6B, 0x02, 0x92, 0x01, 0xCD, 0x01, 0x1D, 0x00, 0xF4, 0x00, 0xCB, 0x01, 0x1B, 0x00, + 0xF2, 0x00, 0xC9, 0x01, 0x19, 0x00, 0xF0, 0x00, 0xB3, 0x00, 0x63, 0x02, 0x8A, 0x01, 0xB1, 0x00, + 0x61, 0x02, 0x88, 0x01, 0xAF, 0x00, 0x5F, 0x02, 0x86, 0x01, 0xD9, 0x01, 0x29, 0x00, 0x00, 0x01, + 0xD7, 0x01, 0x27, 0x00, 0xFE, 0x00, 0xD5, 0x01, 0x25, 0x00, 0xFC, 0x00, 0xA7, 0x00, 0x57, 0x02, + 0x7E, 0x01, 0xA5, 0x00, 0x55, 0x02, 0x7C, 0x01, 0xA3, 0x00, 0x53, 0x02, 0x7A, 0x01, 0xE5, 0x01, + 0x35, 0x00, 0x0C, 0x01, 0xE3, 0x01, 0x33, 0x00, 0x0A, 0x01, 0xE1, 0x01, 0x31, 0x00, 0x08, 0x01, + 0x9B, 0x00, 0x4B, 0x02, 0x72, 0x01, 0x99, 0x00, 0x49, 0x02, 0x70, 0x01, 0x97, 0x00, 0x47, 0x02, + 0x6E, 0x01, 0xF1, 0x01, 0x41, 0x00, 0x18, 0x01, 0xEF, 0x01, 0x3F, 0x00, 0x16, 0x01, 0xED, 0x01, + 0x3D, 0x00, 0x14, 0x01, 0x8F, 0x00, 0x3F, 0x02, 0x66, 0x01, 0x8D, 0x00, 0x3D, 0x02, 0x64, 0x01, + 0x8B, 0x00, 0x3B, 0x02, 0x62, 0x01, 0xFD, 0x01, 0x4D, 0x00, 0x24, 0x01, 0xFB, 0x01, 0x4B, 0x00, + 0x22, 0x01, 0xF9, 0x01, 0x49, 0x00, 0x20, 0x01, 0x83, 0x00, 0x33, 0x02, 0x5A, 0x01, 0x81, 0x00, + 0x31, 0x02, 0x58, 0x01, 0x7F, 0x00, 0x2F, 0x02, 0x56, 0x01, 0x09, 0x02, 0x59, 0x00, 0x30, 0x01, + 0x07, 0x02, 0x57, 0x00, 0x2E, 0x01, 0x05, 0x02, 0x55, 0x00, 0x2C, 0x01, 0x77, 0x00, 0x27, 0x02, + 0x4E, 0x01, 0x75, 0x00, 0x25, 0x02, 0x4C, 0x01, 0x73, 0x00, 0x23, 0x02, 0x4A, 0x01, 0x15, 0x02, + 0x65, 0x00, 0x3C, 0x01, 0x13, 0x02, 0x63, 0x00, 0x3A, 0x01, 0x11, 0x02, 0x61, 0x00, 0x38, 0x01, + 0x6B, 0x00, 0x1B, 0x02, 0x42, 0x01, 0x69, 0x00, 0x19, 0x02, 0x40, 0x01, 0x67, 0x00, 0x17, 0x02, + 0x3E, 0x01, 0x21, 0x02, 0x71, 0x00, 0x48, 0x01, 0x1F, 0x02, 0x6F, 0x00, 0x46, 0x01, 0x1D, 0x02, + 0x6D, 0x00, 0x44, 0x01, 0x5F, 0x00, 0x0F, 0x02, 0x36, 0x01, 0x5D, 0x00, 0x0D, 0x02, 0x34, 0x01, + 0x5B, 0x00, 0x0B, 0x02, 0x32, 0x01, 0x2D, 0x02, 0x7D, 0x00, 0x54, 0x01, 0x2B, 0x02, 0x7B, 0x00, + 0x52, 0x01, 0x29, 0x02, 0x79, 0x00, 0x50, 0x01, 0x53, 0x00, 0x03, 0x02, 0x2A, 0x01, 0x51, 0x00, + 0x01, 0x02, 0x28, 0x01, 0x4F, 0x00, 0xFF, 0x01, 0x26, 0x01, 0x39, 0x02, 0x89, 0x00, 0x60, 0x01, + 0x37, 0x02, 0x87, 0x00, 0x5E, 0x01, 0x35, 0x02, 0x85, 0x00, 0x5C, 0x01, 0x47, 0x00, 0xF7, 0x01, + 0x1E, 0x01, 0x45, 0x00, 0xF5, 0x01, 0x1C, 0x01, 0x43, 0x00, 0xF3, 0x01, 0x1A, 0x01, 0x45, 0x02, + 0x95, 0x00, 0x6C, 0x01, 0x43, 0x02, 0x93, 0x00, 0x6A, 0x01, 0x41, 0x02, 0x91, 0x00, 0x68, 0x01, + 0x3B, 0x00, 0xEB, 0x01, 0x12, 0x01, 0x39, 0x00, 0xE9, 0x01, 0x10, 0x01, 0x37, 0x00, 0xE7, 0x01, + 0x0E, 0x01, 0x51, 0x02, 0xA1, 0x00, 0x78, 0x01, 0x4F, 0x02, 0x9F, 0x00, 0x76, 0x01, 0x4D, 0x02, + 0x9D, 0x00, 0x74, 0x01, 0x2F, 0x00, 0xDF, 0x01, 0x06, 0x01, 0x2D, 0x00, 0xDD, 0x01, 0x04, 0x01, + 0x2B, 0x00, 0xDB, 0x01, 0x02, 0x01, 0x5D, 0x02, 0xAD, 0x00, 0x84, 0x01, 0x5B, 0x02, 0xAB, 0x00, + 0x82, 0x01, 0x59, 0x02, 0xA9, 0x00, 0x80, 0x01, 0x23, 0x00, 0xD3, 0x01, 0xFA, 0x00, 0x21, 0x00, + 0xD1, 0x01, 0xF8, 0x00, 0x1F, 0x00, 0xCF, 0x01, 0xF6, 0x00, 0x69, 0x02, 0xB9, 0x00, 0x90, 0x01, + 0x67, 0x02, 0xB7, 0x00, 0x8E, 0x01, 0x65, 0x02, 0xB5, 0x00, 0x8C, 0x01, 0x17, 0x00, 0xC7, 0x01, + 0xEE, 0x00, 0x15, 0x00, 0xC5, 0x01, 0xEC, 0x00, 0x13, 0x00, 0xC3, 0x01, 0xEA, 0x00, 0x75, 0x02, + 0xC5, 0x00, 0x9C, 0x01, 0x73, 0x02, 0xC3, 0x00, 0x9A, 0x01, 0x71, 0x02, 0xC1, 0x00, 0x98, 0x01, + 0x0B, 0x00, 0xBB, 0x01, 0xE2, 0x00, 0x09, 0x00, 0xB9, 0x01, 0xE0, 0x00, 0x07, 0x00, 0xB7, 0x01, + 0xDE, 0x00, 0x81, 0x02, 0xD1, 0x00, 0xA8, 0x01, 0x7F, 0x02, 0xCF, 0x00, 0xA6, 0x01, 0x7D, 0x02, + 0xCD, 0x00, 0xA4, 0x01, 0xAF, 0x01, 0xD6, 0x00, 0x86, 0x02, 0xAD, 0x01, 0xD4, 0x00, 0x84, 0x02, + 0xAB, 0x01, 0xD2, 0x00, 0x82, 0x02, 0xDD, 0x00, 0xB4, 0x01, 0x04, 0x00, 0xDB, 0x00, 0xB2, 0x01, + 0x02, 0x00, 0xD9, 0x00, 0xB0, 0x01, 0x00, 0x00, 0xA3, 0x01, 0xCA, 0x00, 0x7A, 0x02, 0xA1, 0x01, + 0xC8, 0x00, 0x78, 0x02, 0x9F, 0x01, 0xC6, 0x00, 0x76, 0x02, 0xE9, 0x00, 0xC0, 0x01, 0x10, 0x00, + 0xE7, 0x00, 0xBE, 0x01, 0x0E, 0x00, 0xE5, 0x00, 0xBC, 0x01, 0x0C, 0x00, 0x97, 0x01, 0xBE, 0x00, + 0x6E, 0x02, 0x95, 0x01, 0xBC, 0x00, 0x6C, 0x02, 0x93, 0x01, 0xBA, 0x00, 0x6A, 0x02, 0xF5, 0x00, + 0xCC, 0x01, 0x1C, 0x00, 0xF3, 0x00, 0xCA, 0x01, 0x1A, 0x00, 0xF1, 0x00, 0xC8, 0x01, 0x18, 0x00, + 0x8B, 0x01, 0xB2, 0x00, 0x62, 0x02, 0x89, 0x01, 0xB0, 0x00, 0x60, 0x02, 0x87, 0x01, 0xAE, 0x00, + 0x5E, 0x02, 0x01, 0x01, 0xD8, 0x01, 0x28, 0x00, 0xFF, 0x00, 0xD6, 0x01, 0x26, 0x00, 0xFD, 0x00, + 0xD4, 0x01, 0x24, 0x00, 0x7F, 0x01, 0xA6, 0x00, 0x56, 0x02, 0x7D, 0x01, 0xA4, 0x00, 0x54, 0x02, + 0x7B, 0x01, 0xA2, 0x00, 0x52, 0x02, 0x0D, 0x01, 0xE4, 0x01, 0x34, 0x00, 0x0B, 0x01, 0xE2, 0x01, + 0x32, 0x00, 0x09, 0x01, 0xE0, 0x01, 0x30, 0x00, 0x73, 0x01, 0x9A, 0x00, 0x4A, 0x02, 0x71, 0x01, + 0x98, 0x00, 0x48, 0x02, 0x6F, 0x01, 0x96, 0x00, 0x46, 0x02, 0x19, 0x01, 0xF0, 0x01, 0x40, 0x00, + 0x17, 0x01, 0xEE, 0x01, 0x3E, 0x00, 0x15, 0x01, 0xEC, 0x01, 0x3C, 0x00, 0x67, 0x01, 0x8E, 0x00, + 0x3E, 0x02, 0x65, 0x01, 0x8C, 0x00, 0x3C, 0x02, 0x63, 0x01, 0x8A, 0x00, 0x3A, 0x02, 0x25, 0x01, + 0xFC, 0x01, 0x4C, 0x00, 0x23, 0x01, 0xFA, 0x01, 0x4A, 0x00, 0x21, 0x01, 0xF8, 0x01, 0x48, 0x00, + 0x5B, 0x01, 0x82, 0x00, 0x32, 0x02, 0x59, 0x01, 0x80, 0x00, 0x30, 0x02, 0x57, 0x01, 0x7E, 0x00, + 0x2E, 0x02, 0x31, 0x01, 0x08, 0x02, 0x58, 0x00, 0x2F, 0x01, 0x06, 0x02, 0x56, 0x00, 0x2D, 0x01, + 0x04, 0x02, 0x54, 0x00, 0x4F, 0x01, 0x76, 0x00, 0x26, 0x02, 0x4D, 0x01, 0x74, 0x00, 0x24, 0x02, + 0x4B, 0x01, 0x72, 0x00, 0x22, 0x02, 0x3D, 0x01, 0x14, 0x02, 0x64, 0x00, 0x3B, 0x01, 0x12, 0x02, + 0x62, 0x00, 0x39, 0x01, 0x10, 0x02, 0x60, 0x00, 0x43, 0x01, 0x6A, 0x00, 0x1A, 0x02, 0x41, 0x01, + 0x68, 0x00, 0x18, 0x02, 0x3F, 0x01, 0x66, 0x00, 0x16, 0x02, 0x49, 0x01, 0x20, 0x02, 0x70, 0x00, + 0x47, 0x01, 0x1E, 0x02, 0x6E, 0x00, 0x45, 0x01, 0x1C, 0x02, 0x6C, 0x00, 0x37, 0x01, 0x5E, 0x00, + 0x0E, 0x02, 0x35, 0x01, 0x5C, 0x00, 0x0C, 0x02, 0x33, 0x01, 0x5A, 0x00, 0x0A, 0x02, 0x55, 0x01, + 0x2C, 0x02, 0x7C, 0x00, 0x53, 0x01, 0x2A, 0x02, 0x7A, 0x00, 0x51, 0x01, 0x28, 0x02, 0x78, 0x00, + 0x2B, 0x01, 0x52, 0x00, 0x02, 0x02, 0x29, 0x01, 0x50, 0x00, 0x00, 0x02, 0x27, 0x01, 0x4E, 0x00, + 0xFE, 0x01, 0x61, 0x01, 0x38, 0x02, 0x88, 0x00, 0x5F, 0x01, 0x36, 0x02, 0x86, 0x00, 0x5D, 0x01, + 0x34, 0x02, 0x84, 0x00, 0x1F, 0x01, 0x46, 0x00, 0xF6, 0x01, 0x1D, 0x01, 0x44, 0x00, 0xF4, 0x01, + 0x1B, 0x01, 0x42, 0x00, 0xF2, 0x01, 0x6D, 0x01, 0x44, 0x02, 0x94, 0x00, 0x6B, 0x01, 0x42, 0x02, + 0x92, 0x00, 0x69, 0x01, 0x40, 0x02, 0x90, 0x00, 0x13, 0x01, 0x3A, 0x00, 0xEA, 0x01, 0x11, 0x01, + 0x38, 0x00, 0xE8, 0x01, 0x0F, 0x01, 0x36, 0x00, 0xE6, 0x01, 0x79, 0x01, 0x50, 0x02, 0xA0, 0x00, + 0x77, 0x01, 0x4E, 0x02, 0x9E, 0x00, 0x75, 0x01, 0x4C, 0x02, 0x9C, 0x00, 0x07, 0x01, 0x2E, 0x00, + 0xDE, 0x01, 0x05, 0x01, 0x2C, 0x00, 0xDC, 0x01, 0x03, 0x01, 0x2A, 0x00, 0xDA, 0x01, 0x85, 0x01, + 0x5C, 0x02, 0xAC, 0x00, 0x83, 0x01, 0x5A, 0x02, 0xAA, 0x00, 0x81, 0x01, 0x58, 0x02, 0xA8, 0x00, + 0xFB, 0x00, 0x22, 0x00, 0xD2, 0x01, 0xF9, 0x00, 0x20, 0x00, 0xD0, 0x01, 0xF7, 0x00, 0x1E, 0x00, + 0xCE, 0x01, 0x91, 0x01, 0x68, 0x02, 0xB8, 0x00, 0x8F, 0x01, 0x66, 0x02, 0xB6, 0x00, 0x8D, 0x01, + 0x64, 0x02, 0xB4, 0x00, 0xEF, 0x00, 0x16, 0x00, 0xC6, 0x01, 0xED, 0x00, 0x14, 0x00, 0xC4, 0x01, + 0xEB, 0x00, 0x12, 0x00, 0xC2, 0x01, 0x9D, 0x01, 0x74, 0x02, 0xC4, 0x00, 0x9B, 0x01, 0x72, 0x02, + 0xC2, 0x00, 0x99, 0x01, 0x70, 0x02, 0xC0, 0x00, 0xE3, 0x00, 0x0A, 0x00, 0xBA, 0x01, 0xE1, 0x00, + 0x08, 0x00, 0xB8, 0x01, 0xDF, 0x00, 0x06, 0x00, 0xB6, 0x01, 0xA9, 0x01, 0x80, 0x02, 0xD0, 0x00, + 0xA7, 0x01, 0x7E, 0x02, 0xCE, 0x00, 0xA5, 0x01, 0x7C, 0x02, 0xCC, 0x00, 0xFF, 0xFF, 0x00, 0x00, + 0xF1, 0xD8, 0xFF, 0xFF, 0xF1, 0xD8, 0xFF, 0xFF, 0xF1, 0xD8, 0xFF, 0xFF, 0xF1, 0xD8, 0xFF, 0xFF, + 0x01, 0x00, 0x00, 0x00, 0xE2, 0x00, 0xE2, 0x00, 0xE2, 0x00, 0xE2, 0x00, 0xE4, 0x00, 0xFC, 0x00, + 0x44, 0x01, 0xF0, 0x00, 0x2C, 0x01, 0x62, 0x01, 0xE4, 0x00, 0xFC, 0x00, 0x44, 0x01, 0xF0, 0x00, + 0x2C, 0x01, 0x62, 0x01, 0xE4, 0x00, 0xFC, 0x00, 0x44, 0x01, 0xF0, 0x00, 0x02, 0x03, 0x04, 0x05, + 0x06, 0x07, 0x08, 0x09, 0x0B, 0x0C, 0x00, 0x00, 0x06, 0x06, 0x06, 0x06, 0x09, 0x08, 0x06, 0x08, + 0x07, 0x05, 0x09, 0x08, 0x06, 0x08, 0x07, 0x05, 0x09, 0x08, 0x06, 0x08, 0xE4, 0x00, 0x12, 0x01, + 0x3E, 0x01, 0x74, 0x01, 0xBA, 0x01, 0x84, 0x01, 0x58, 0x01, 0xF0, 0x00, 0xCE, 0x01, 0x8E, 0x01, + 0xF8, 0x00, 0x00, 0x01, 0x08, 0x01, 0xE2, 0x00, 0x16, 0x01, 0xE4, 0x00, 0x12, 0x01, 0x3E, 0x01, + 0x74, 0x01, 0xBA, 0x01, 0x03, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x02, 0x02, + 0x02, 0x03, 0x02, 0x03, 0x02, 0x01, 0x00, 0x00, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0B, 0x0C, 0x00, 0x00, 0x01, 0x04, 0x01, 0xFF, 0x01, 0x01, 0x01, 0x41, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0xFF, 0xFF, 0x02, 0x00, 0x00, 0x00, 0x0A, 0x0B, 0x0B, 0x0B, 0x0C, 0x0C, 0x0C, 0x0C, + 0x0C, 0x0D, 0x00, 0x00, 0xA8, 0x1F, 0x02, 0x00, 0xA0, 0x1F, 0x02, 0x00, 0x94, 0x1F, 0x02, 0x00, + 0x88, 0x1F, 0x02, 0x00, 0x78, 0x1F, 0x02, 0x00, 0x68, 0x1F, 0x02, 0x00, 0x54, 0x1F, 0x02, 0x00, + 0x40, 0x1F, 0x02, 0x00, 0x28, 0x1F, 0x02, 0x00, 0x0C, 0x1F, 0x02, 0x00, 0xB6, 0x00, 0x7B, 0x00, + 0x9F, 0x00, 0xC7, 0x00, 0xF1, 0x00, 0x1B, 0x01, 0x44, 0x01, 0x6B, 0x01, 0x8E, 0x01, 0xAC, 0x01, + 0xC4, 0x01, 0xD4, 0x01, 0xDC, 0x01, 0x00, 0x00, 0x5D, 0x00, 0x44, 0x00, 0x5A, 0x00, 0x72, 0x00, + 0x8A, 0x00, 0xA4, 0x00, 0xBC, 0x00, 0xD1, 0x00, 0xE4, 0x00, 0xF3, 0x00, 0xFE, 0x00, 0x03, 0x01, + 0x65, 0x00, 0x58, 0x00, 0x79, 0x00, 0x9D, 0x00, 0xC2, 0x00, 0xE4, 0x00, 0x03, 0x01, 0x1D, 0x01, + 0x2F, 0x01, 0x38, 0x01, 0x6A, 0x00, 0x67, 0x00, 0x91, 0x00, 0xBE, 0x00, 0xEB, 0x00, 0x14, 0x01, + 0x36, 0x01, 0x4F, 0x01, 0x5C, 0x01, 0x00, 0x00, 0x72, 0x00, 0x7C, 0x00, 0xB2, 0x00, 0xEB, 0x00, + 0x24, 0x01, 0x53, 0x01, 0x76, 0x01, 0x88, 0x01, 0x7C, 0x00, 0x99, 0x00, 0xE2, 0x00, 0x2E, 0x01, + 0x73, 0x01, 0xA6, 0x01, 0xC2, 0x01, 0x00, 0x00, 0x45, 0x00, 0x63, 0x00, 0x96, 0x00, 0xC9, 0x00, + 0xF1, 0x00, 0x08, 0x01, 0x51, 0x00, 0x88, 0x00, 0xD4, 0x00, 0x16, 0x01, 0x3D, 0x01, 0x00, 0x00, + 0x67, 0x00, 0xCD, 0x00, 0x41, 0x01, 0x8B, 0x01, 0x4C, 0x00, 0xB1, 0x00, 0x03, 0x01, 0x00, 0x00, + 0x30, 0x75, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x03, 0x04, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x08, 0x00, 0x10, 0x00, 0x01, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x00, 0x00, 0x01, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x37, 0x20, 0x00, 0x00, 0x29, 0x04, 0x38, 0x09, + 0x60, 0x00, 0x00, 0x00, 0x28, 0x02, 0x00, 0x08, 0x2C, 0x02, 0x00, 0x08, 0x2C, 0x01, 0x00, 0x0C, + 0x00, 0x02, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x24, 0x01, 0x04, 0x06, 0x08, 0x00, 0x00, 0x00, + 0x23, 0x01, 0x04, 0x06, 0x22, 0x05, 0x06, 0x00, 0x21, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x03, + 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0xFF, 0x07, 0xFF, 0x07, 0x12, 0x24, 0x0A, 0x00, 0x12, + 0x24, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0x04, 0x00, 0x03, 0x00, 0x02, 0x00, 0x08, 0x2C, + 0x02, 0x00, 0x08, 0x2C, 0x01, 0x00, 0x0C, 0x00, 0x02, 0x00, 0x08, 0x00, 0x01, 0x04, 0x06, 0x08, + 0x05, 0x06, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x8E, 0xAC, 0x24, + 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5A, 0x00, 0x4A, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x54, 0x01, 0x00, 0x00, 0x50, 0x00, 0x6E, 0x00, 0x2C, 0x01, 0xAF, 0x00, 0x6E, 0x00, 0x96, 0x00, + 0x23, 0x46, 0x41, 0x1E, 0x0F, 0x46, 0x37, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xBC, 0x02, 0x00, 0x00, 0xC8, 0x00, 0xDC, 0x00, 0x58, 0x02, 0xAF, 0x00, 0x6E, 0x00, 0xDC, 0x00, + 0x23, 0x46, 0x46, 0x0F, 0x14, 0x5A, 0x37, 0x11, 0x19, 0x00, 0x64, 0x55, 0x00, 0x00, 0x00, 0x00, + 0x19, 0x00, 0x64, 0x55, 0x00, 0x00, 0x00, 0x00, 0x96, 0x00, 0xC8, 0x00, 0x32, 0x00, 0x00, 0x00, + 0x0B, 0x0F, 0x23, 0x46, 0x96, 0x00, 0xC8, 0x00, 0x32, 0x00, 0x00, 0x00, 0x06, 0x0A, 0x32, 0x46, + 0x5A, 0x00, 0x0A, 0x00, 0xB4, 0x00, 0x82, 0x00, 0x20, 0x00, 0x00, 0x0A, 0x02, 0x50, 0x24, 0x05, + 0x5A, 0x00, 0x0A, 0x00, 0xB4, 0x00, 0x82, 0x00, 0x20, 0x00, 0x00, 0x0A, 0x02, 0x50, 0x24, 0x05, + 0xDC, 0x05, 0x00, 0x00, 0x50, 0x00, 0x78, 0x00, 0x26, 0x02, 0x01, 0x00, 0x5E, 0x01, 0x04, 0x00, + 0x26, 0x02, 0x00, 0x00, 0x78, 0x00, 0x20, 0x03, 0x26, 0x02, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x92, 0x09, 0x00, 0x00, 0xDC, 0x05, 0x00, 0x00, 0xB0, 0x04, 0x00, 0x00, 0x2C, 0x01, 0x00, 0x00, + 0xB8, 0x0B, 0x00, 0x00, 0x01, 0x04, 0x19, 0x00, 0xBC, 0x00, 0xB8, 0x19, 0xD1, 0x00, 0xF8, 0x39, + 0x00, 0x00, 0x00, 0x00, 0xD0, 0x00, 0xD1, 0x00, 0x5C, 0x02, 0x88, 0x01, 0x00, 0x00, 0x00, 0x00, + 0xE5, 0x00, 0xE6, 0x00, 0xBE, 0x01, 0x8E, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x3E, 0x00, 0x00, 0xC8, 0x00, 0x64, 0x00, 0x50, 0x00, 0x2C, 0x01, 0x32, 0x00, 0x02, 0x01, + 0x09, 0x10, 0x07, 0x19, 0x19, 0x00, 0x01, 0x03, 0x5E, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xF4, 0x01, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0xD0, 0x07, 0x8C, 0x0A, 0xD8, 0x0E, 0x57, 0x00, + 0xFF, 0x00, 0x14, 0x00, 0x06, 0x00, 0x06, 0x00, 0x20, 0x00, 0x20, 0x00, 0x50, 0x00, 0x40, 0x01, + 0x64, 0x00, 0x90, 0x01, 0x14, 0x0A, 0x04, 0x02, 0x0F, 0x0A, 0x28, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xC8, 0x00, 0x90, 0x01, 0x06, 0x00, 0x01, 0x0A, 0x96, 0x00, 0xE8, 0x03, 0x18, 0xFC, 0xC8, 0x00, + 0x50, 0x00, 0x6E, 0x00, 0xCE, 0xFF, 0x5A, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x96, 0x00, 0xB0, 0x04, 0xB0, 0x04, 0xC8, 0x00, 0x01, 0x00, 0x2C, 0x01, 0x96, 0x00, 0x0A, 0x00, + 0x54, 0x07, 0x58, 0x02, 0x96, 0x00, 0x02, 0x02, 0xD0, 0x07, 0xD0, 0x07, 0x50, 0x00, 0x64, 0x00, + 0x50, 0x00, 0x9C, 0xFF, 0xB0, 0xFF, 0x00, 0x00, 0x96, 0x00, 0x00, 0x00, 0x32, 0x00, 0x50, 0x00, + 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x34, 0x03, 0x70, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3B, 0x11, 0x10, 0x90, +}; + diff --git a/drivers/iommu/io-pgtable-arm.c b/drivers/iommu/io-pgtable-arm.c index a6fad3ab7315..bb2d9ebaf6cd 100644 --- a/drivers/iommu/io-pgtable-arm.c +++ b/drivers/iommu/io-pgtable-arm.c @@ -29,6 +29,7 @@ #include #include #include +#include #include @@ -525,6 +526,7 @@ static int __arm_lpae_map(struct arm_lpae_io_pgtable *data, unsigned long iova, pte = arm_lpae_install_table(cptep, ptep, 0, cfg, 0); if (pte) __arm_lpae_free_pages(cptep, tblsz, cfg, cookie); + trace_io_pgtable_install(cptep, ptep, *ptep, 0); } else if (!(cfg->quirks & IO_PGTABLE_QUIRK_NO_DMA) && !(pte & ARM_LPAE_PTE_SW_SYNC)) { @@ -790,6 +792,7 @@ static size_t arm_lpae_split_blk_unmap(struct arm_lpae_io_pgtable *data, } pte = arm_lpae_install_table(tablep, ptep, blk_pte, cfg, child_cnt); + trace_io_pgtable_install(tablep, ptep, *ptep, 1); if (pte != blk_pte) { __arm_lpae_free_pages(tablep, tablesz, cfg, cookie); /* @@ -827,11 +830,14 @@ static size_t __arm_lpae_unmap(struct arm_lpae_io_pgtable *data, /* If the size matches this level, we're in the right place */ if (size == ARM_LPAE_BLOCK_SIZE(lvl, data)) { + arm_lpae_iopte *blk_table = ptep; __arm_lpae_set_pte(ptep, 0, &iop->cfg); if (!iopte_leaf(pte, lvl)) { /* Also flush any partial walks */ ptep = iopte_deref(pte, data); + trace_io_pgtable_free(ptep, blk_table, pte, iova, 1); + io_pgtable_tlb_flush_all(&data->iop); __arm_lpae_free_pgtable(data, lvl + 1, ptep); } @@ -864,7 +870,9 @@ static size_t __arm_lpae_unmap(struct arm_lpae_io_pgtable *data, iopte_tblcnt_sub(ptep, entries); if (!iopte_tblcnt(*ptep)) { /* no valid mappings left under this table. free it. */ + trace_io_pgtable_free(table_base, ptep, *ptep, iova, 0); __arm_lpae_set_pte(ptep, 0, &iop->cfg); + io_pgtable_tlb_flush_all(&data->iop); __arm_lpae_free_pgtable(data, lvl + 1, table_base); } diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c index fd8d7879f8d0..6b4ba1ab6577 100644 --- a/drivers/irqchip/irq-gic-v3.c +++ b/drivers/irqchip/irq-gic-v3.c @@ -1,5 +1,6 @@ /* * Copyright (C) 2013-2017 ARM Limited, All Rights Reserved. + * Copyright (C) 2020 Oplus. All rights reserved. * Author: Marc Zyngier * * This program is free software; you can redistribute it and/or modify @@ -43,8 +44,16 @@ #include +#ifdef OPLUS_FEATURE_POWERINFO_STANDBY +#include +#endif /* OPLUS_FEATURE_POWERINFO_STANDBY */ + #include "irq-gic-common.h" +//#ifdef OPLUS_FEATURE_NWPOWER +#include +//#endif /* OPLUS_FEATURE_NWPOWER */ + struct redist_region { void __iomem *redist_base; phys_addr_t phys_base; @@ -69,6 +78,7 @@ static DEFINE_STATIC_KEY_TRUE(supports_deactivate_key); static struct gic_kvm_info gic_v3_kvm_info; static DEFINE_PER_CPU(bool, has_rss); +extern is_first_ipcc_msg; #define MPIDR_RS(mpidr) (((mpidr) & 0xF0UL) >> 4) #define gic_data_rdist() (this_cpu_ptr(gic_data.rdists.rdist)) @@ -377,6 +387,10 @@ static void gic_show_resume_irq(struct gic_chip_data *gic) if (!msm_show_resume_irq_mask) return; + #ifdef OPLUS_FEATURE_POWERINFO_STANDBY + wakeup_reasons_statics(IRQ_NAME_WAKE_SUM, WS_CNT_SUM); + #endif /* OPLUS_FEATURE_POWERINFO_STANDBY */ + for (i = 0; i * 32 < gic->irq_nr; i++) { enabled = readl_relaxed(base + GICD_ICENABLER + i * 4); pending[i] = readl_relaxed(base + GICD_ISPENDR + i * 4); @@ -394,8 +408,37 @@ static void gic_show_resume_irq(struct gic_chip_data *gic) name = "stray irq"; else if (desc->action && desc->action->name) name = desc->action->name; - pr_warn("%s: %d triggered %s\n", __func__, irq, name); + + #ifdef OPLUS_FEATURE_POWERINFO_STANDBY + do { + int platform_id = get_cached_platform_id(); + if (platform_id == KONA) { + if (irq >= 154 && irq <= 185) { /*pcie2 is modem*/ + name = IRQ_NAME_MODEM_QMI; + //#ifdef OPLUS_FEATURE_NWPOWER + oplus_match_modem_wakeup(); + //#endif /* OPLUS_FEATURE_NWPOWER */ + } else if (irq >= 85 && irq <= 116) {/*pcie0 is wlan*/ + name = IRQ_NAME_WLAN_IPCC_DATA; + //#ifdef OPLUS_FEATURE_NWPOWER + oplus_match_wlan_wakeup(); + //#endif /* OPLUS_FEATURE_NWPOWER */ + } + } else if (platform_id == LITO || platform_id == LAGOON) { + if (!strcmp(name, IRQ_NAME_MODEM_MODEM)) { + name = IRQ_NAME_MODEM_QMI; + } + //#ifdef OPLUS_FEATURE_NWPOWER + if (strncmp(name, "ipcc_1", strlen("ipcc_1")) == 0) { + is_first_ipcc_msg = 1; + oplus_match_modem_wakeup(); + } + //#endif /* OPLUS_FEATURE_NWPOWER */ + } + wakeup_reasons_statics(name, WS_CNT_MODEM|WS_CNT_WLAN|WS_CNT_ADSP|WS_CNT_CDSP|WS_CNT_SLPI); + } while(0); + #endif /* OPLUS_FEATURE_POWERINFO_STANDBY */ } } diff --git a/drivers/irqchip/msm_show_resume_irq.c b/drivers/irqchip/msm_show_resume_irq.c index 1bf7040249ff..22120e243edd 100644 --- a/drivers/irqchip/msm_show_resume_irq.c +++ b/drivers/irqchip/msm_show_resume_irq.c @@ -7,7 +7,11 @@ #include #include +#ifndef OPLUS_FEATURE_POWERINFO_STANDBY int msm_show_resume_irq_mask; +#else +int msm_show_resume_irq_mask = 1; +#endif /*OPLUS_FEATURE_POWERINFO_STANDBY*/ module_param_named( debug_mask, msm_show_resume_irq_mask, int, 0664); diff --git a/drivers/leds/leds-qpnp-vibrator-ldo.c b/drivers/leds/leds-qpnp-vibrator-ldo.c index 484715646cbd..b6da07e191f4 100644 --- a/drivers/leds/leds-qpnp-vibrator-ldo.c +++ b/drivers/leds/leds-qpnp-vibrator-ldo.c @@ -32,7 +32,9 @@ * Define vibration periods: default(5sec), min(50ms), max(15sec) and * overdrive(30ms). */ -#define QPNP_VIB_MIN_PLAY_MS 50 +#ifdef OPLUS_FEATURE_CHG_BASIC +#define QPNP_VIB_MIN_PLAY_MS 35 +#endif #define QPNP_VIB_PLAY_MS 5000 #define QPNP_VIB_MAX_PLAY_MS 15000 #define QPNP_VIB_OVERDRIVE_PLAY_MS 30 @@ -198,7 +200,11 @@ static enum hrtimer_restart vib_stop_timer(struct hrtimer *timer) stop_timer); chip->state = 0; +#ifdef OPLUS_FEATURE_CHG_BASIC + queue_work(system_unbound_wq, &chip->vib_work); +#else schedule_work(&chip->vib_work); +#endif return HRTIMER_NORESTART; } @@ -323,12 +329,24 @@ static ssize_t qpnp_vib_store_activate(struct device *dev, if (val != 0 && val != 1) return count; +#ifdef OPLUS_FEATURE_CHG_BASIC + if ((hrtimer_active(&chip->stop_timer))&& + (chip->vib_play_ms == QPNP_VIB_MIN_PLAY_MS)) + return count; +#endif + mutex_lock(&chip->lock); hrtimer_cancel(&chip->stop_timer); chip->state = val; - pr_debug("state = %d, time = %llums\n", chip->state, chip->vib_play_ms); +#ifdef OPLUS_FEATURE_CHG_BASIC + pr_info("state = %d, time = %llums\n", chip->state, chip->vib_play_ms); +#endif mutex_unlock(&chip->lock); +#ifdef OPLUS_FEATURE_CHG_BASIC + queue_work(system_unbound_wq, &chip->vib_work); +#else schedule_work(&chip->vib_work); +#endif return count; } diff --git a/drivers/md/dm-android-verity.c b/drivers/md/dm-android-verity.c index 20e05936551f..6943452c223a 100644 --- a/drivers/md/dm-android-verity.c +++ b/drivers/md/dm-android-verity.c @@ -505,7 +505,11 @@ static void handle_error(void) int mode = verity_mode(); if (mode == DM_VERITY_MODE_RESTART) { DMERR("triggering restart"); +#ifdef OPLUS_BUG_STABILITY + panic("dm-verity device corrupted"); +#else kernel_restart("dm-verity device corrupted"); +#endif /* OPLUS_BUG_STABILITY */ } else { DMERR("Mounting verity root failed"); } diff --git a/drivers/md/dm-verity-target.c b/drivers/md/dm-verity-target.c index dd349d0bc03e..5b19a9a89ec2 100644 --- a/drivers/md/dm-verity-target.c +++ b/drivers/md/dm-verity-target.c @@ -255,7 +255,12 @@ out: #ifdef CONFIG_DM_VERITY_AVB dm_verity_avb_error_handler(); #endif + +#ifdef OPLUS_BUG_STABILITY + panic("dm-verity device corrupted"); +#else kernel_restart("dm-verity device corrupted"); +#endif /* OPLUS_BUG_STABILITY */ } return 1; diff --git a/drivers/media/platform/msm/cvp/cvp_hfi.c b/drivers/media/platform/msm/cvp/cvp_hfi.c index bb520c1910de..68802dc69d46 100644 --- a/drivers/media/platform/msm/cvp/cvp_hfi.c +++ b/drivers/media/platform/msm/cvp/cvp_hfi.c @@ -349,7 +349,7 @@ int get_pkt_index(struct cvp_hal_session_cmd_pkt *hdr) return -EINVAL; } - +#ifndef OPLUS_FEATURE_CAMERA_COMMON int set_feature_bitmask(int pkt_idx, unsigned long *bitmask) { if (!bitmask) { @@ -375,7 +375,7 @@ int set_feature_bitmask(int pkt_idx, unsigned long *bitmask) dprintk(CVP_ERR, "%s: invalid pkt_idx %d\n", __func__, pkt_idx); return -EINVAL; } - +#endif int get_hfi_version(void) { struct msm_cvp_core *core; @@ -825,18 +825,30 @@ static int __read_queue(struct cvp_iface_q_info *qinfo, u8 *packet, * so that iris reads the updated header values */ mb(); - *pb_tx_req_is_set = 0; - if (write_idx != queue->qhdr_write_idx) { - queue->qhdr_rx_req = 0; - } else { - spin_unlock(&qinfo->hfi_lock); - dprintk(CVP_DBG, - "%s queue is empty, rx_req = %u, tx_req = %u, read_idx = %u\n", - receive_request ? "message" : "debug", - queue->qhdr_rx_req, queue->qhdr_tx_req, - queue->qhdr_read_idx); - return -ENODATA; +#ifdef OPLUS_FEATURE_CAMERA_COMMON + *pb_tx_req_is_set = 1; + if(write_idx != queue->qhdr_write_idx) { + queue->qhdr_rx_req = 0; } + else { + spin_unlock(&qinfo->hfi_lock); + dprintk(CVP_DBG, + "%s queue is empty, rx_req = %u, tx_req = %u, read_idx = %u\n", + receive_request ? "message" : "debug", + queue->qhdr_rx_req, queue->qhdr_tx_req, + queue->qhdr_read_idx); + return -ENODATA; + } +#else + *pb_tx_req_is_set = 0; + spin_unlock(&qinfo->hfi_lock); + dprintk(CVP_DBG, + "%s queue is empty, rx_req = %u, tx_req = %u, read_idx = %u\n", + receive_request ? "message" : "debug", + queue->qhdr_rx_req, queue->qhdr_tx_req, + queue->qhdr_read_idx); + return -ENODATA; +#endif } read_ptr = (u32 *)((qinfo->q_array.align_virtual_addr) + @@ -4534,7 +4546,11 @@ static void power_off_iris2(struct iris_hfi_device *device) static inline int __resume(struct iris_hfi_device *device) { int rc = 0; +#ifdef OPLUS_FEATURE_CAMERA_COMMON + u32 flags = 0, reg_gdsc, reg_cbcr; +#else u32 flags = 0; +#endif if (!device) { dprintk(CVP_ERR, "Invalid params: %pK\n", device); @@ -4552,6 +4568,13 @@ static inline int __resume(struct iris_hfi_device *device) dprintk(CVP_ERR, "Failed to power on cvp\n"); goto err_iris_power_on; } +#ifdef OPLUS_FEATURE_CAMERA_COMMON + reg_gdsc = __read_register(device, CVP_CC_MVS1C_GDSCR); + reg_cbcr = __read_register(device, CVP_CC_MVS1C_CBCR); + if (!(reg_gdsc & 0x80000000) || (reg_cbcr & 0x80000000)) + dprintk(CVP_ERR, "CVP power on failed gdsc %x cbcr %x\n", + reg_gdsc, reg_cbcr); +#endif /* Reboot the firmware */ rc = __tzbsp_set_cvp_state(TZ_SUBSYS_STATE_RESUME); diff --git a/drivers/media/platform/msm/cvp/cvp_hfi_api.h b/drivers/media/platform/msm/cvp/cvp_hfi_api.h index 736038efe40e..89a21882a7ad 100644 --- a/drivers/media/platform/msm/cvp/cvp_hfi_api.h +++ b/drivers/media/platform/msm/cvp/cvp_hfi_api.h @@ -98,12 +98,13 @@ #define HFI_MODEL_BUFFERS_OFFSET 7 #define HFI_MODEL_BUF_NUM 1 +#ifndef OPLUS_FEATURE_CAMERA_COMMON #define DFS_BIT_OFFSET (CVP_KMD_HFI_DFS_FRAME_CMD - CVP_KMD_CMD_START) #define DME_BIT_OFFSET (CVP_KMD_HFI_DME_FRAME_CMD - CVP_KMD_CMD_START) #define PERSIST_BIT_OFFSET (CVP_KMD_HFI_PERSIST_CMD - CVP_KMD_CMD_START) #define ICA_BIT_OFFSET (CVP_KMD_HFI_ICA_FRAME_CMD - CVP_KMD_CMD_START) #define FD_BIT_OFFSET (CVP_KMD_HFI_FD_FRAME_CMD - CVP_KMD_CMD_START) - +#endif #define HFI_VERSION_MAJOR_MASK 0xFF000000 #define HFI_VERSION_MAJOR_SHFIT 24 #define HFI_VERSION_MINOR_MASK 0x00FFFFE0 @@ -428,7 +429,9 @@ void cvp_hfi_deinitialize(enum msm_cvp_hfi_type hfi_type, int get_pkt_index(struct cvp_hal_session_cmd_pkt *hdr); int get_signal_from_pkt_type(unsigned int type); +#ifndef OPLUS_FEATURE_CAMERA_COMMON int set_feature_bitmask(int pkt_index, unsigned long *bitmask); +#endif int get_hfi_version(void); unsigned int get_msg_size(void); unsigned int get_msg_session_id(void *msg); diff --git a/drivers/media/platform/msm/cvp/cvp_hfi_helper.h b/drivers/media/platform/msm/cvp/cvp_hfi_helper.h index f8fe274ed70d..fa171404a241 100644 --- a/drivers/media/platform/msm/cvp/cvp_hfi_helper.h +++ b/drivers/media/platform/msm/cvp/cvp_hfi_helper.h @@ -287,11 +287,19 @@ struct cvp_hfi_client { u32 transaction_id; u32 data1; u32 data2; +#ifdef OPLUS_FEATURE_CAMERA_COMMON + u64 kdata; +#else u32 kdata1; u32 kdata2; +#endif u32 reserved1; u32 reserved2; +#ifdef OPLUS_FEATURE_CAMERA_COMMON +} __packed; +#else }; +#endif struct cvp_hfi_client_d { u32 transaction_id; @@ -319,7 +327,11 @@ struct cvp_hfi_cmd_session_set_buffers_packet { u32 session_id; struct cvp_hfi_client client_data; struct cvp_hfi_buf_type buf_type; +#ifdef OPLUS_FEATURE_CAMERA_COMMON +} __packed; +#else }; +#endif struct cvp_hfi_cmd_session_set_buffers_packet_d { u32 size; @@ -339,7 +351,11 @@ struct cvp_session_release_buffers_packet { u32 buffer_type; u32 num_buffers; u32 buffer_idx; +#ifdef OPLUS_FEATURE_CAMERA_COMMON +} __packed; +#else }; +#endif struct cvp_session_release_buffers_packet_d { u32 size; @@ -357,7 +373,11 @@ struct cvp_hfi_cmd_session_hdr { u32 session_id; struct cvp_hfi_client client_data; u32 stream_idx; +#ifdef OPLUS_FEATURE_CAMERA_COMMON +} __packed; +#else }; +#endif struct cvp_hfi_msg_session_hdr { u32 size; @@ -366,7 +386,11 @@ struct cvp_hfi_msg_session_hdr { u32 error_type; struct cvp_hfi_client client_data; u32 stream_idx; +#ifdef OPLUS_FEATURE_CAMERA_COMMON +} __packed; +#else }; +#endif struct cvp_hfi_msg_session_hdr_d { u32 size; @@ -417,7 +441,11 @@ struct cvp_hfi_msg_session_op_cfg_packet { struct cvp_hfi_client client_data; u32 stream_idx; u32 op_conf_id; +#ifdef OPLUS_FEATURE_CAMERA_COMMON +} __packed; +#else }; +#endif struct cvp_hfi_msg_release_buffer_ref_event_packet { u32 packet_buffer; diff --git a/drivers/media/platform/msm/cvp/hfi_response_handler.c b/drivers/media/platform/msm/cvp/hfi_response_handler.c index e6ef20647100..5d7e72142e12 100644 --- a/drivers/media/platform/msm/cvp/hfi_response_handler.c +++ b/drivers/media/platform/msm/cvp/hfi_response_handler.c @@ -17,12 +17,12 @@ #include "msm_cvp_common.h" extern struct msm_cvp_drv *cvp_driver; - +#ifndef OPLUS_FEATURE_CAMERA_COMMON static int _deprecated_hfi_msg_process(u32 device_id, struct cvp_hfi_msg_session_hdr *pkt, struct msm_cvp_cb_info *info, struct msm_cvp_inst *inst); - +#endif static enum cvp_status hfi_map_err_status(u32 hfi_err) { enum cvp_status cvp_err; @@ -443,6 +443,7 @@ retry: } +#ifndef OPLUS_FEATURE_CAMERA_COMMON static int __dme_output_cache_operation(struct cvp_hfi_msg_session_hdr *pkt) { struct cvp_hfi_msg_dme_pkt *dme_pkt; @@ -472,7 +473,7 @@ static int __dme_output_cache_operation(struct cvp_hfi_msg_session_hdr *pkt) return rc; } - +#endif static int hfi_process_session_cvp_msg(u32 device_id, struct cvp_hfi_msg_session_hdr *pkt, struct msm_cvp_cb_info *info) @@ -481,6 +482,9 @@ static int hfi_process_session_cvp_msg(u32 device_id, struct msm_cvp_inst *inst = NULL; struct msm_cvp_core *core; void *session_id; +#ifdef OPLUS_FEATURE_CAMERA_COMMON + struct cvp_session_queue *sq; +#endif if (!pkt) { dprintk(CVP_ERR, "%s: invalid param\n", __func__); @@ -497,7 +501,7 @@ static int hfi_process_session_cvp_msg(u32 device_id, dprintk(CVP_ERR, "%s: invalid session\n", __func__); return -EINVAL; } - +#ifndef OPLUS_FEATURE_CAMERA_COMMON if (inst->deprecate_bitmask) { if (pkt->packet_type == HFI_MSG_SESSION_CVP_DME || pkt->packet_type == HFI_MSG_SESSION_CVP_ICA @@ -521,6 +525,12 @@ static int hfi_process_session_cvp_msg(u32 device_id, dprintk(CVP_ERR, "Invalid deprecate_bitmask %#x\n", inst->deprecate_bitmask); } +#else + if (pkt->client_data.kdata & FENCE_BIT) + sq = &inst->session_queue_fence; + else + sq = &inst->session_queue; +#endif sess_msg = kmem_cache_alloc(cvp_driver->msg_cache, GFP_KERNEL); if (sess_msg == NULL) { @@ -535,27 +545,46 @@ static int hfi_process_session_cvp_msg(u32 device_id, __func__, pkt->packet_type, hfi_map_err_status(get_msg_errorcode(pkt)), session_id); +#ifdef OPLUS_FEATURE_CAMERA_COMMON + spin_lock(&sq->lock); + if (sq->msg_count >= MAX_NUM_MSGS_PER_SESSION) { +#else spin_lock(&inst->session_queue.lock); if (inst->session_queue.msg_count >= MAX_NUM_MSGS_PER_SESSION) { +#endif dprintk(CVP_ERR, "Reached session queue size limit\n"); goto error_handle_msg; } +#ifdef OPLUS_FEATURE_CAMERA_COMMON + list_add_tail(&sess_msg->node, &sq->msgs); + sq->msg_count++; + spin_unlock(&sq->lock); +#else list_add_tail(&sess_msg->node, &inst->session_queue.msgs); inst->session_queue.msg_count++; spin_unlock(&inst->session_queue.lock); +#endif +#ifdef OPLUS_FEATURE_CAMERA_COMMON + wake_up_all(&sq->wq); +#else wake_up_all(&inst->session_queue.wq); - +#endif info->response_type = HAL_NO_RESP; return 0; error_handle_msg: +#ifdef OPLUS_FEATURE_CAMERA_COMMON + spin_unlock(&sq->lock); +#else spin_unlock(&inst->session_queue.lock); +#endif kmem_cache_free(cvp_driver->msg_cache, sess_msg); return -ENOMEM; } +#ifndef OPLUS_FEATURE_CAMERA_COMMON static int hfi_process_session_cvp_dme(u32 device_id, struct cvp_hfi_msg_session_hdr *pkt, struct msm_cvp_cb_info *info) @@ -667,6 +696,7 @@ static int _deprecated_hfi_msg_process(u32 device_id, pkt->packet_type, inst->deprecate_bitmask); return -EINVAL; } +#endif static void hfi_process_sys_get_prop_image_version( struct cvp_hfi_msg_sys_property_info_packet *pkt) diff --git a/drivers/media/platform/msm/cvp/msm_cvp.c b/drivers/media/platform/msm/cvp/msm_cvp.c index 1ac16e349e1d..e42b74e12dd0 100644 --- a/drivers/media/platform/msm/cvp/msm_cvp.c +++ b/drivers/media/platform/msm/cvp/msm_cvp.c @@ -3,9 +3,18 @@ * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. */ +#ifdef OPLUS_FEATURE_CAMERA_COMMON +#include +#include +#include +#include +#include +#endif #include "msm_cvp.h" #include "cvp_hfi.h" +#ifndef OPLUS_FEATURE_CAMERA_COMMON #include +#endif #include "cvp_core_hfi.h" #include "cvp_hfi_helper.h" @@ -186,9 +195,8 @@ static int msm_cvp_map_buf_dsp(struct msm_cvp_inst *inst, } cbuf = kmem_cache_zalloc(cvp_driver->internal_buf_cache, GFP_KERNEL); - if (!cbuf) { + if (!cbuf) return -ENOMEM; - } memcpy(&cbuf->buf, buf, sizeof(struct cvp_kmd_buffer)); cbuf->smem.buffer_type = get_hal_buftype(__func__, buf->type); @@ -557,6 +565,9 @@ static void __unmap_buf(struct msm_cvp_inst *inst, if (cbuf->smem.dma_buf == buf->dbuf && cbuf->buf.size == buf->size && cbuf->buf.offset == buf->offset) { +#ifdef OPLUS_FEATURE_CAMERA_COMMON + __msm_cvp_cache_operations(cbuf); +#endif list_del(&cbuf->list); print_internal_buffer(CVP_DBG, "unmap", inst, cbuf); msm_cvp_smem_unmap_dma_buf(inst, &cbuf->smem); @@ -577,8 +588,11 @@ void msm_cvp_unmap_buf_cpu(struct msm_cvp_inst *inst, u64 ktid) dprintk(CVP_ERR, "%s: invalid params\n", __func__); return; } - +#ifdef OPLUS_FEATURE_CAMERA_COMMON + ktid &= (FENCE_BIT - 1); +#endif dprintk(CVP_DBG, "%s: unmap frame %llu\n", __func__, ktid); + found = false; mutex_lock(&inst->frames.lock); list_for_each_entry_safe(frame, dummy1, &inst->frames.list, list) { @@ -606,7 +620,88 @@ void msm_cvp_unmap_buf_cpu(struct msm_cvp_inst *inst, u64 ktid) __func__, ktid); } } +#ifdef OPLUS_FEATURE_CAMERA_COMMON +static bool cvp_msg_pending(struct cvp_session_queue *sq, + struct cvp_session_msg **msg, u64 *ktid) +{ + struct cvp_session_msg *mptr, *dummy; + bool result = false; + mptr = NULL; + spin_lock(&sq->lock); + if (sq->state != QUEUE_ACTIVE) { + /* The session is being deleted */ + spin_unlock(&sq->lock); + *msg = NULL; + return true; + } + result = list_empty(&sq->msgs); + if (!result) { + if (!ktid) { + mptr = + list_first_entry(&sq->msgs, struct cvp_session_msg, + node); + list_del_init(&mptr->node); + sq->msg_count--; + } else { + result = true; + list_for_each_entry_safe(mptr, dummy, &sq->msgs, node) { + if (*ktid == mptr->pkt.client_data.kdata) { + list_del_init(&mptr->node); + sq->msg_count--; + result = false; + break; + } + } + if (result) + mptr = NULL; + } + } + spin_unlock(&sq->lock); + *msg = mptr; + return !result; +} + +static int cvp_wait_process_message(struct msm_cvp_inst *inst, + struct cvp_session_queue *sq, u64 *ktid, + unsigned long timeout, + struct cvp_kmd_hfi_packet *out) +{ + struct cvp_session_msg *msg = NULL; + int rc = 0; + + if (wait_event_timeout(sq->wq, + cvp_msg_pending(sq, &msg, ktid), timeout) == 0) { + dprintk(CVP_WARN, "session queue wait timeout\n"); + rc = -ETIMEDOUT; + goto exit; + } + + if (msg == NULL) { + dprintk(CVP_WARN, "%s: queue state %d, msg cnt %d\n", __func__, + sq->state, sq->msg_count); + + if (inst->state >= MSM_CVP_CLOSE_DONE || + sq->state != QUEUE_ACTIVE) { + rc = -ECONNRESET; + goto exit; + } + + msm_cvp_comm_kill_session(inst); + goto exit; + } + + msm_cvp_unmap_buf_cpu(inst, msg->pkt.client_data.kdata); + if (out) + memcpy(out, &msg->pkt, sizeof(struct cvp_hfi_msg_session_hdr)); + + kmem_cache_free(cvp_driver->msg_cache, msg); + +exit: + return rc; +} + +#else static bool _cvp_msg_pending(struct msm_cvp_inst *inst, struct cvp_session_queue *sq, struct cvp_session_msg **msg) @@ -632,18 +727,23 @@ static bool _cvp_msg_pending(struct msm_cvp_inst *inst, *msg = mptr; return !result; } - - +#endif static int msm_cvp_session_receive_hfi(struct msm_cvp_inst *inst, struct cvp_kmd_hfi_packet *out_pkt) { unsigned long wait_time; +#ifndef OPLUS_FEATURE_CAMERA_COMMON struct cvp_session_msg *msg = NULL; +#endif struct cvp_session_queue *sq; +#ifndef OPLUS_FEATURE_CAMERA_COMMON struct cvp_kmd_session_control *sc; +#endif struct msm_cvp_inst *s; int rc = 0; +#ifndef OPLUS_FEATURE_CAMERA_COMMON u32 version; +#endif if (!inst) { dprintk(CVP_ERR, "%s invalid session\n", __func__); @@ -655,11 +755,12 @@ static int msm_cvp_session_receive_hfi(struct msm_cvp_inst *inst, return -ECONNRESET; s->cur_cmd_type = CVP_KMD_RECEIVE_MSG_PKT; +#ifndef OPLUS_FEATURE_CAMERA_COMMON sq = &inst->session_queue; sc = (struct cvp_kmd_session_control *)out_pkt; - +#endif wait_time = msecs_to_jiffies(CVP_MAX_WAIT_TIME); - +#ifndef OPLUS_FEATURE_CAMERA_COMMON if (wait_event_timeout(sq->wq, _cvp_msg_pending(inst, sq, &msg), wait_time) == 0) { dprintk(CVP_WARN, "session queue wait timeout\n"); @@ -700,6 +801,12 @@ static int msm_cvp_session_receive_hfi(struct msm_cvp_inst *inst, } exit: +#else + sq = &inst->session_queue; + + rc = cvp_wait_process_message(inst, sq, NULL, wait_time, out_pkt); + +#endif s->cur_cmd_type = 0; cvp_put_inst(inst); return rc; @@ -775,8 +882,13 @@ static int msm_cvp_map_buf(struct msm_cvp_inst *inst, cmd_hdr = (struct cvp_hfi_cmd_session_hdr *)in_pkt; ktid = atomic64_inc_return(&inst->core->kernel_trans_id); +#ifdef OPLUS_FEATURE_CAMERA_COMMON + ktid &= (FENCE_BIT - 1); + cmd_hdr->client_data.kdata = ktid; +#else cmd_hdr->client_data.kdata1 = (u32)ktid; cmd_hdr->client_data.kdata2 = (u32)(ktid >> 32); +#endif frame = kmem_cache_zalloc(cvp_driver->frame_cache, GFP_KERNEL); if (!frame) @@ -991,6 +1103,37 @@ exit: return rc; } +#ifdef OPLUS_FEATURE_CAMERA_COMMON +static bool cvp_fence_wait(struct cvp_fence_queue *q, + struct msm_cvp_fence_thread_data **fence, + enum queue_state *state) +{ + struct msm_cvp_fence_thread_data *f; + + *fence = NULL; + spin_lock(&q->lock); + *state = q->state; + if (*state != QUEUE_ACTIVE) { + spin_unlock(&q->lock); + return true; + } + + if (list_empty(&q->wait_list)) { + spin_unlock(&q->lock); + return false; + } + + f = list_first_entry(&q->wait_list, + struct msm_cvp_fence_thread_data, list); + list_del_init(&f->list); + list_add_tail(&q->sched_list, &f->list); + + spin_unlock(&q->lock); + *fence = f; + + return true; +} +#endif #define CVP_FENCE_RUN 0x100 static int msm_cvp_thread_fence_run(void *data) { @@ -1002,22 +1145,39 @@ static int msm_cvp_thread_fence_run(void *data) struct cvp_kmd_hfi_fence_packet *in_fence_pkt; struct cvp_kmd_hfi_packet *in_pkt; struct msm_cvp_inst *inst; +#ifdef OPLUS_FEATURE_CAMERA_COMMON + struct sched_param param = {.sched_priority = 64 }; +#endif int *fence; int ica_enabled = 0; int pkt_idx; int synx_state = SYNX_STATE_SIGNALED_SUCCESS; +#ifdef OPLUS_FEATURE_CAMERA_COMMON + u64 ktid; + struct cvp_hfi_cmd_session_hdr *cmd_hdr; + + sched_setscheduler(current, SCHED_FIFO, ¶m); +#endif if (!data) { dprintk(CVP_ERR, "%s Wrong input data %pK\n", __func__, data); +#ifdef OPLUS_FEATURE_CAMERA_COMMON + return -EINVAL; +#else do_exit(-EINVAL); +#endif } fence_thread_data = data; inst = fence_thread_data->inst; if (!inst) { dprintk(CVP_ERR, "%s Wrong inst %pK\n", __func__, inst); +#ifdef OPLUS_FEATURE_CAMERA_COMMON + return -EINVAL; +#else rc = -EINVAL; return rc; +#endif } inst->cur_cmd_type = CVP_FENCE_RUN; in_fence_pkt = (struct cvp_kmd_hfi_fence_packet *) @@ -1035,6 +1195,10 @@ static int msm_cvp_thread_fence_run(void *data) fence = (int *)(in_fence_pkt->fence_data); hdev = inst->core->device; +#ifdef OPLUS_FEATURE_CAMERA_COMMON + cmd_hdr = (struct cvp_hfi_cmd_session_hdr *)in_pkt; + ktid = cmd_hdr->client_data.kdata; +#endif //wait on synx before signaling HFI switch (cvp_hfi_defs[pkt_idx].type) { @@ -1076,7 +1240,9 @@ static int msm_cvp_thread_fence_run(void *data) } if (synx_state != SYNX_STATE_SIGNALED_ERROR) { +#ifndef OPLUS_FEATURE_CAMERA_COMMON mutex_lock(&inst->fence_lock); +#endif rc = call_hfi_op(hdev, session_send, (void *)inst->session, in_pkt); if (rc) { @@ -1086,16 +1252,23 @@ static int msm_cvp_thread_fence_run(void *data) in_pkt->pkt_data[1]); synx_state = SYNX_STATE_SIGNALED_ERROR; } - +#ifdef OPLUS_FEATURE_CAMERA_COMMON + rc = cvp_wait_process_message(inst, + &inst->session_queue_fence, + &ktid, timeout_ms, NULL); +#else rc = wait_for_sess_signal_receipt_fence(inst, HAL_SESSION_DME_FRAME_CMD_DONE); +#endif if (rc) { dprintk(CVP_ERR, "%s: wait for signal failed, rc %d\n", __func__, rc); synx_state = SYNX_STATE_SIGNALED_ERROR; } +#ifndef OPLUS_FEATURE_CAMERA_COMMON mutex_unlock(&inst->fence_lock); +#endif } if (ica_enabled) { @@ -1140,6 +1313,7 @@ static int msm_cvp_thread_fence_run(void *data) } break; } +#ifndef OPLUS_FEATURE_CAMERA_COMMON case HFI_CMD_SESSION_CVP_ICA_FRAME: { for (i = 0; i < cvp_hfi_defs[pkt_idx].buf_num-1; i++) { @@ -1216,6 +1390,7 @@ static int msm_cvp_thread_fence_run(void *data) } break; } +#endif case HFI_CMD_SESSION_CVP_FD_FRAME: { int in_fence_num = fence[0]; @@ -1249,7 +1424,9 @@ static int msm_cvp_thread_fence_run(void *data) } } +#ifndef OPLUS_FEATURE_CAMERA_COMMON mutex_lock(&inst->fence_lock); +#endif rc = call_hfi_op(hdev, session_send, (void *)inst->session, in_pkt); if (rc) { @@ -1260,6 +1437,16 @@ static int msm_cvp_thread_fence_run(void *data) synx_state = SYNX_STATE_SIGNALED_ERROR; } +#ifdef OPLUS_FEATURE_CAMERA_COMMON + rc = cvp_wait_process_message(inst, &inst->session_queue_fence, + &ktid, timeout_ms, NULL); + if (rc) { + dprintk(CVP_ERR, + "%s: wait for signal failed, rc %d\n", + __func__, rc); + synx_state = SYNX_STATE_SIGNALED_ERROR; + } +#else if (synx_state != SYNX_STATE_SIGNALED_ERROR) { rc = wait_for_sess_signal_receipt_fence(inst, HAL_SESSION_FD_FRAME_CMD_DONE); @@ -1271,6 +1458,7 @@ static int msm_cvp_thread_fence_run(void *data) } } mutex_unlock(&inst->fence_lock); +#endif for (i = start_out; i < start_out + out_fence_num; i++) { if (fence[(i<<1)]) { @@ -1311,24 +1499,84 @@ static int msm_cvp_thread_fence_run(void *data) exit: kmem_cache_free(cvp_driver->fence_data_cache, fence_thread_data); inst->cur_cmd_type = 0; +#ifdef OPLUS_FEATURE_CAMERA_COMMON + return rc; +#else + cvp_put_inst(inst); + do_exit(rc); +#endif +} + +#ifdef OPLUS_FEATURE_CAMERA_COMMON +static int cvp_fence_thread(void *data) +{ + int rc = 0; + struct msm_cvp_inst *inst; + struct cvp_fence_queue *q; + enum queue_state state; + struct msm_cvp_fence_thread_data *fence_data; + + dprintk(CVP_DBG, "Enter %s\n", current->comm); + + inst = (struct msm_cvp_inst *)data; + if (!inst || !inst->core || !inst->core->device) { + dprintk(CVP_ERR, "%s invalid inst %pK\n", current->comm, inst); + rc = -EINVAL; + goto exit; + } + + q = &inst->fence_cmd_queue; + +wait: + dprintk(CVP_DBG, "%s starts wait\n", current->comm); + + fence_data = NULL; + wait_event_interruptible(q->wq, cvp_fence_wait(q, &fence_data, &state)); + if (state != QUEUE_ACTIVE) + goto exit; + + if (!fence_data) + goto wait; + + rc = msm_cvp_thread_fence_run(fence_data); + if (rc) + goto exit; + + goto wait; +exit: + dprintk(CVP_DBG, "%s exit\n", current->comm); cvp_put_inst(inst); do_exit(rc); } +#endif +#ifdef OPLUS_FEATURE_CAMERA_COMMON +static int msm_cvp_session_process_hfi_fence(struct msm_cvp_inst *inst, + struct cvp_kmd_arg *arg) +#else static int msm_cvp_session_process_hfi_fence( struct msm_cvp_inst *inst, struct cvp_kmd_arg *arg) +#endif { +#ifndef OPLUS_FEATURE_CAMERA_COMMON static int thread_num; struct task_struct *thread; +#endif int rc = 0; +#ifndef OPLUS_FEATURE_CAMERA_COMMON char thread_fence_name[32]; +#endif int pkt_idx; struct cvp_kmd_hfi_packet *in_pkt; unsigned int signal, offset, buf_num, in_offset, in_buf_num; struct msm_cvp_inst *s; unsigned int max_buf_num; struct msm_cvp_fence_thread_data *fence_thread_data; +#ifdef OPLUS_FEATURE_CAMERA_COMMON + struct cvp_fence_queue *q; + struct cvp_hfi_cmd_session_hdr *cmd_hdr; +#endif dprintk(CVP_DBG, "%s: Enter inst = %#x", __func__, inst); @@ -1386,13 +1634,24 @@ static int msm_cvp_session_process_hfi_fence( rc = msm_cvp_map_buf(inst, in_pkt, offset, buf_num); if (rc) goto free_and_exit; - - thread_num = thread_num + 1; +#ifdef OPLUS_FEATURE_CAMERA_COMMON + cmd_hdr = (struct cvp_hfi_cmd_session_hdr *)in_pkt; + cmd_hdr->client_data.kdata |= FENCE_BIT; fence_thread_data->inst = inst; fence_thread_data->device_id = (unsigned int)inst->core->id; memcpy(&fence_thread_data->in_fence_pkt, &arg->data.hfi_fence_pkt, sizeof(struct cvp_kmd_hfi_fence_packet)); fence_thread_data->arg_type = arg->type; + + q = &inst->fence_cmd_queue; + spin_lock(&q->lock); + list_add_tail(&fence_thread_data->list, &q->wait_list); + spin_unlock(&q->lock); + + wake_up(&inst->fence_cmd_queue.wq); + + goto exit; +#else snprintf(thread_fence_name, sizeof(thread_fence_name), "thread_fence_%d", thread_num); thread = kthread_run(msm_cvp_thread_fence_run, @@ -1404,6 +1663,7 @@ static int msm_cvp_session_process_hfi_fence( } return 0; +#endif free_and_exit: kmem_cache_free(cvp_driver->fence_data_cache, fence_thread_data); @@ -1412,7 +1672,7 @@ exit: cvp_put_inst(s); return rc; } - +#ifndef OPLUS_FEATURE_CAMERA_COMMON static int msm_cvp_session_cvp_dfs_frame_response( struct msm_cvp_inst *inst, struct cvp_kmd_hfi_packet *dfs_frame) @@ -1444,6 +1704,7 @@ static int msm_cvp_send_cmd(struct msm_cvp_inst *inst, return 0; } +#endif static inline int div_by_1dot5(unsigned int a) { @@ -1935,6 +2196,81 @@ static int session_state_check_init(struct msm_cvp_inst *inst) return msm_cvp_session_create(inst); } +#ifdef OPLUS_FEATURE_CAMERA_COMMON +static int cvp_fence_thread_start(struct msm_cvp_inst *inst) +{ + u32 tnum = 0; + u32 i = 0; + int rc = 0; + char tname[16]; + struct task_struct *thread; + struct cvp_fence_queue *q; + struct cvp_session_queue *sq; + + if (!inst->prop.fthread_nr) + return 0; + + q = &inst->fence_cmd_queue; + spin_lock(&q->lock); + q->state = QUEUE_ACTIVE; + spin_unlock(&q->lock); + + for (i = 0; i < inst->prop.fthread_nr; ++i) { + if (!cvp_get_inst_validate(inst->core, inst)) { + rc = -ECONNRESET; + goto exit; + } + + snprintf(tname, sizeof(tname), "fthread_%d", tnum++); + thread = kthread_run(cvp_fence_thread, inst, tname); + if (!thread) { + dprintk(CVP_ERR, "%s create %s fail", __func__, tname); + rc = -ECHILD; + goto exit; + } + } + + sq = &inst->session_queue_fence; + spin_lock(&sq->lock); + sq->state = QUEUE_ACTIVE; + spin_unlock(&sq->lock); + +exit: + if (rc) { + spin_lock(&q->lock); + q->state = QUEUE_STOP; + spin_unlock(&q->lock); + wake_up_all(&q->wq); + } + return rc; +} + +static int cvp_fence_thread_stop(struct msm_cvp_inst *inst) +{ + struct cvp_fence_queue *q; + struct cvp_session_queue *sq; + + if (!inst->prop.fthread_nr) + return 0; + + q = &inst->fence_cmd_queue; + + spin_lock(&q->lock); + q->state = QUEUE_STOP; + spin_unlock(&q->lock); + + sq = &inst->session_queue_fence; + spin_lock(&sq->lock); + sq->state = QUEUE_STOP; + spin_unlock(&sq->lock); + + wake_up_all(&q->wq); + wake_up_all(&sq->wq); + + return 0; +} +#endif + static int msm_cvp_session_start(struct msm_cvp_inst *inst, struct cvp_kmd_arg *arg) { @@ -1950,10 +2286,38 @@ static int msm_cvp_session_start(struct msm_cvp_inst *inst, } sq->state = QUEUE_ACTIVE; spin_unlock(&sq->lock); - +#ifdef OPLUS_FEATURE_CAMERA_COMMON + return cvp_fence_thread_start(inst); +#else return 0; +#endif } +#ifdef OPLUS_FEATURE_CAMERA_COMMON +int msm_cvp_session_queue_stop(struct msm_cvp_inst *inst) +{ + struct cvp_session_queue *sq; + + sq = &inst->session_queue; + spin_lock(&sq->lock); + + if (sq->state == QUEUE_STOP) { + spin_unlock(&sq->lock); + return 0; + } + sq->state = QUEUE_STOP; + + dprintk(CVP_ERR, "Stop session queue: %pK session_id = %d\n", + inst, hash32_ptr(inst->session)); + + spin_unlock(&sq->lock); + + wake_up_all(&inst->session_queue.wq); + + return cvp_fence_thread_stop(inst); +} +#endif + static int msm_cvp_session_stop(struct msm_cvp_inst *inst, struct cvp_kmd_arg *arg) { @@ -1975,8 +2339,11 @@ static int msm_cvp_session_stop(struct msm_cvp_inst *inst, spin_unlock(&sq->lock); wake_up_all(&inst->session_queue.wq); - +#ifdef OPLUS_FEATURE_CAMERA_COMMON + return cvp_fence_thread_stop(inst); +#else return 0; +#endif } static int msm_cvp_session_ctrl(struct msm_cvp_inst *inst, @@ -2199,6 +2566,7 @@ int msm_cvp_handle_syscall(struct msm_cvp_inst *inst, struct cvp_kmd_arg *arg) rc = msm_cvp_unregister_buffer(inst, buf); break; } +#ifndef OPLUS_FEATURE_CAMERA_COMMON case CVP_KMD_HFI_SEND_CMD: { struct cvp_kmd_send_cmd *send_cmd = @@ -2207,6 +2575,7 @@ int msm_cvp_handle_syscall(struct msm_cvp_inst *inst, struct cvp_kmd_arg *arg) rc = msm_cvp_send_cmd(inst, send_cmd); break; } +#endif case CVP_KMD_RECEIVE_MSG_PKT: { struct cvp_kmd_hfi_packet *out_pkt = @@ -2215,12 +2584,14 @@ int msm_cvp_handle_syscall(struct msm_cvp_inst *inst, struct cvp_kmd_arg *arg) break; } case CVP_KMD_SEND_CMD_PKT: +#ifndef OPLUS_FEATURE_CAMERA_COMMON case CVP_KMD_HFI_DFS_CONFIG_CMD: case CVP_KMD_HFI_DFS_FRAME_CMD: case CVP_KMD_HFI_DME_CONFIG_CMD: case CVP_KMD_HFI_DME_FRAME_CMD: case CVP_KMD_HFI_FD_FRAME_CMD: case CVP_KMD_HFI_PERSIST_CMD: +#endif { struct cvp_kmd_hfi_packet *in_pkt = (struct cvp_kmd_hfi_packet *)&arg->data.hfi_pkt; @@ -2229,6 +2600,7 @@ int msm_cvp_handle_syscall(struct msm_cvp_inst *inst, struct cvp_kmd_arg *arg) arg->buf_offset, arg->buf_num); break; } +#ifndef OPLUS_FEATURE_CAMERA_COMMON case CVP_KMD_HFI_DFS_FRAME_CMD_RESPONSE: { struct cvp_kmd_hfi_packet *dfs_frame = @@ -2254,6 +2626,7 @@ int msm_cvp_handle_syscall(struct msm_cvp_inst *inst, struct cvp_kmd_arg *arg) break; } case CVP_KMD_HFI_DME_FRAME_FENCE_CMD: +#endif case CVP_KMD_SEND_FENCE_CMD_PKT: { rc = msm_cvp_session_process_hfi_fence(inst, arg); @@ -2386,6 +2759,9 @@ int msm_cvp_session_init(struct msm_cvp_inst *inst) inst->prop.priority = 0; inst->prop.is_secure = 0; inst->prop.dsp_mask = 0; +#ifdef OPLUS_FEATURE_CAMERA_COMMON + inst->prop.fthread_nr = 2; +#endif return rc; } diff --git a/drivers/media/platform/msm/cvp/msm_cvp.h b/drivers/media/platform/msm/cvp/msm_cvp.h index 8b95b8ad66ee..a0ec2eec3eaa 100644 --- a/drivers/media/platform/msm/cvp/msm_cvp.h +++ b/drivers/media/platform/msm/cvp/msm_cvp.h @@ -14,4 +14,7 @@ int msm_cvp_handle_syscall(struct msm_cvp_inst *inst, struct cvp_kmd_arg *arg); int msm_cvp_session_init(struct msm_cvp_inst *inst); int msm_cvp_session_deinit(struct msm_cvp_inst *inst); +#ifdef OPLUS_FEATURE_CAMERA_COMMON +int msm_cvp_session_queue_stop(struct msm_cvp_inst *inst); +#endif #endif diff --git a/drivers/media/platform/msm/cvp/msm_cvp_common.c b/drivers/media/platform/msm/cvp/msm_cvp_common.c index 9999225cdf47..82aab73040c6 100644 --- a/drivers/media/platform/msm/cvp/msm_cvp_common.c +++ b/drivers/media/platform/msm/cvp/msm_cvp_common.c @@ -405,7 +405,7 @@ int wait_for_sess_signal_receipt(struct msm_cvp_inst *inst, } return rc; } - +#ifndef OPLUS_FEATURE_CAMERA_COMMON int wait_for_sess_signal_receipt_fence(struct msm_cvp_inst *inst, enum hal_command_response cmd) { @@ -453,7 +453,7 @@ int wait_for_sess_signal_receipt_fence(struct msm_cvp_inst *inst, return rc; } - +#endif static int wait_for_state(struct msm_cvp_inst *inst, enum instance_state flipped_state, enum instance_state desired_state, @@ -773,14 +773,14 @@ static void handle_session_close(enum hal_command_response cmd, void *data) show_stats(inst); cvp_put_inst(inst); } - +#ifndef OPLUS_FEATURE_CAMERA_COMMON static void handle_operation_config(enum hal_command_response cmd, void *data) { dprintk(CVP_ERR, "%s: is called\n", __func__); } - +#endif void cvp_handle_cmd_response(enum hal_command_response cmd, void *data) { dprintk(CVP_DBG, "Command response = %d\n", cmd); @@ -794,9 +794,10 @@ void cvp_handle_cmd_response(enum hal_command_response cmd, void *data) case HAL_SESSION_INIT_DONE: handle_session_init_done(cmd, data); break; +#ifndef OPLUS_FEATURE_CAMERA_COMMON case HAL_SESSION_CVP_OPERATION_CONFIG: handle_operation_config(cmd, data); - break; +#endif case HAL_SESSION_RELEASE_RESOURCE_DONE: handle_release_res_done(cmd, data); break; diff --git a/drivers/media/platform/msm/cvp/msm_cvp_common.h b/drivers/media/platform/msm/cvp/msm_cvp_common.h index 2322a98985d0..2454563f5ea5 100644 --- a/drivers/media/platform/msm/cvp/msm_cvp_common.h +++ b/drivers/media/platform/msm/cvp/msm_cvp_common.h @@ -41,8 +41,10 @@ void print_cvp_buffer(u32 tag, const char *str, struct msm_cvp_internal_buffer *cbuf); int wait_for_sess_signal_receipt(struct msm_cvp_inst *inst, enum hal_command_response cmd); +#ifndef OPLUS_FEATURE_CAMERA_COMMON int wait_for_sess_signal_receipt_fence(struct msm_cvp_inst *inst, enum hal_command_response cmd); +#endif int cvp_comm_set_arp_buffers(struct msm_cvp_inst *inst); int cvp_comm_release_persist_buffers(struct msm_cvp_inst *inst); void print_client_buffer(u32 tag, const char *str, diff --git a/drivers/media/platform/msm/cvp/msm_cvp_core.c b/drivers/media/platform/msm/cvp/msm_cvp_core.c index f970d1df4b98..7db0caadad81 100644 --- a/drivers/media/platform/msm/cvp/msm_cvp_core.c +++ b/drivers/media/platform/msm/cvp/msm_cvp_core.c @@ -220,8 +220,8 @@ static bool msm_cvp_check_for_inst_overload(struct msm_cvp_core *core) overload = true; return overload; } - -static int _init_session_queue(struct msm_cvp_inst *inst) +#ifdef OPLUS_FEATURE_CAMERA_COMMON +static int __init_session_queue(struct msm_cvp_inst *inst) { spin_lock_init(&inst->session_queue.lock); INIT_LIST_HEAD(&inst->session_queue.msgs); @@ -231,6 +231,32 @@ static int _init_session_queue(struct msm_cvp_inst *inst) return 0; } +static void __init_fence_queue(struct msm_cvp_inst *inst) +{ + spin_lock_init(&inst->fence_cmd_queue.lock); + INIT_LIST_HEAD(&inst->fence_cmd_queue.wait_list); + INIT_LIST_HEAD(&inst->fence_cmd_queue.sched_list); + init_waitqueue_head(&inst->fence_cmd_queue.wq); + inst->fence_cmd_queue.state = QUEUE_ACTIVE; + + spin_lock_init(&inst->session_queue_fence.lock); + INIT_LIST_HEAD(&inst->session_queue_fence.msgs); + inst->session_queue_fence.msg_count = 0; + init_waitqueue_head(&inst->session_queue_fence.wq); + inst->session_queue_fence.state = QUEUE_ACTIVE; +} + +#else +static int _init_session_queue(struct msm_cvp_inst *inst) +{ + spin_lock_init(&inst->session_queue.lock); + INIT_LIST_HEAD(&inst->session_queue.msgs); + inst->session_queue.msg_count = 0; + init_waitqueue_head(&inst->session_queue.wq); + inst->session_queue.state = QUEUE_ACTIVE; + return 0; +} +#endif static void _deinit_session_queue(struct msm_cvp_inst *inst) { struct cvp_session_msg *msg, *tmpmsg; @@ -291,9 +317,12 @@ void *msm_cvp_open(int core_id, int session_type) pr_info(CVP_DBG_TAG "Opening cvp instance: %pK\n", "info", inst); mutex_init(&inst->sync_lock); mutex_init(&inst->lock); +#ifndef OPLUS_FEATURE_CAMERA_COMMON mutex_init(&inst->fence_lock); +#endif spin_lock_init(&inst->event_handler.lock); + INIT_MSM_CVP_LIST(&inst->persistbufs); INIT_MSM_CVP_LIST(&inst->cvpcpubufs); INIT_MSM_CVP_LIST(&inst->cvpdspbufs); @@ -314,7 +343,9 @@ void *msm_cvp_open(int core_id, int session_type) inst->clk_data.sys_cache_bw = 0; inst->clk_data.bitrate = 0; inst->clk_data.core_id = 0; +#ifndef OPLUS_FEATURE_CAMERA_COMMON inst->deprecate_bitmask = 0; +#endif for (i = SESSION_MSG_INDEX(SESSION_MSG_START); i <= SESSION_MSG_INDEX(SESSION_MSG_END); i++) { @@ -326,8 +357,13 @@ void *msm_cvp_open(int core_id, int session_type) mutex_lock(&core->lock); list_add_tail(&inst->list, &core->instances); mutex_unlock(&core->lock); +#ifdef OPLUS_FEATURE_CAMERA_COMMON + __init_fence_queue(inst); + rc = __init_session_queue(inst); +#else rc = _init_session_queue(inst); +#endif if (rc) goto fail_init; @@ -349,7 +385,9 @@ fail_init: mutex_unlock(&core->lock); mutex_destroy(&inst->sync_lock); mutex_destroy(&inst->lock); +#ifndef OPLUS_FEATURE_CAMERA_COMMON mutex_destroy(&inst->fence_lock); +#endif DEINIT_MSM_CVP_LIST(&inst->persistbufs); DEINIT_MSM_CVP_LIST(&inst->cvpcpubufs); @@ -398,7 +436,9 @@ wait: if (cvp_comm_release_persist_buffers(inst)) dprintk(CVP_ERR, "Failed to release persist buffers\n"); - +#ifdef OPLUS_FEATURE_CAMERA_COMMON + msm_cvp_session_queue_stop(inst); +#endif dprintk(CVP_DBG, "Done cvp cleanup instance\n"); } @@ -427,7 +467,9 @@ int msm_cvp_destroy(struct msm_cvp_inst *inst) mutex_destroy(&inst->sync_lock); mutex_destroy(&inst->lock); +#ifndef OPLUS_FEATURE_CAMERA_COMMON mutex_destroy(&inst->fence_lock); +#endif msm_cvp_debugfs_deinit_inst(inst); _deinit_session_queue(inst); diff --git a/drivers/media/platform/msm/cvp/msm_cvp_internal.h b/drivers/media/platform/msm/cvp/msm_cvp_internal.h index 0a27a827be3e..a0159b38958a 100644 --- a/drivers/media/platform/msm/cvp/msm_cvp_internal.h +++ b/drivers/media/platform/msm/cvp/msm_cvp_internal.h @@ -24,6 +24,9 @@ #include #include #include "cvp_hfi_api.h" +#ifdef OPLUS_FEATURE_CAMERA_COMMON +#include +#endif #define MAX_SUPPORTED_INSTANCES 16 #define MAX_NAME_LENGTH 64 @@ -31,6 +34,13 @@ #define MAX_DSP_INIT_ATTEMPTS 16 #define FENCE_WAIT_SIGNAL_TIMEOUT 100 #define FENCE_WAIT_SIGNAL_RETRY_TIMES 20 +#ifdef OPLUS_FEATURE_CAMERA_COMMON +#define FENCE_BIT (1ULL << 63) + +#define FENCE_DME_ICA_ENABLED_IDX 0 +#define FENCE_DME_DS_IDX 1 +#define FENCE_DME_OUTPUT_IDX 7 +#endif #define SYS_MSG_START HAL_SYS_INIT_DONE #define SYS_MSG_END HAL_SYS_ERROR @@ -251,6 +261,9 @@ struct cvp_session_prop { u32 priority; u32 is_secure; u32 dsp_mask; +#ifdef OPLUS_FEATURE_CAMERA_COMMON + u32 fthread_nr; +#endif u32 fdu_cycles; u32 od_cycles; u32 mpu_cycles; @@ -267,6 +280,16 @@ struct cvp_session_prop { u32 ddr_op_cache; }; +#ifdef OPLUS_FEATURE_CAMERA_COMMON +struct cvp_fence_queue { + spinlock_t lock; + enum queue_state state; + struct list_head wait_list; + wait_queue_head_t wq; + struct list_head sched_list; +}; +#endif + enum cvp_event_t { CVP_NO_EVENT, CVP_SSR_EVENT = 1, @@ -317,6 +340,9 @@ struct msm_cvp_inst { struct msm_cvp_core *core; enum session_type session_type; struct cvp_session_queue session_queue; +#ifdef OPLUS_FEATURE_CAMERA_COMMON + struct cvp_session_queue session_queue_fence; +#endif struct cvp_session_event event_handler; void *session; enum instance_state state; @@ -332,14 +358,23 @@ struct msm_cvp_inst { enum msm_cvp_modes flags; struct msm_cvp_capability capability; struct kref kref; +#ifndef OPLUS_FEATURE_CAMERA_COMMON unsigned long deprecate_bitmask; +#endif struct cvp_kmd_request_power power; struct cvp_session_prop prop; u32 cur_cmd_type; +#ifdef OPLUS_FEATURE_CAMERA_COMMON + struct cvp_fence_queue fence_cmd_queue; +#else struct mutex fence_lock; +#endif }; struct msm_cvp_fence_thread_data { +#ifdef OPLUS_FEATURE_CAMERA_COMMON + struct list_head list; +#endif struct msm_cvp_inst *inst; unsigned int device_id; struct cvp_kmd_hfi_fence_packet in_fence_pkt; @@ -352,6 +387,7 @@ void cvp_handle_cmd_response(enum hal_command_response cmd, void *data); int msm_cvp_trigger_ssr(struct msm_cvp_core *core, enum hal_ssr_trigger_type type); int msm_cvp_noc_error_info(struct msm_cvp_core *core); +#ifndef OPLUS_FEATURE_CAMERA_COMMON void msm_cvp_queue_v4l2_event(struct msm_cvp_inst *inst, int event_type); enum msm_cvp_flags { @@ -359,7 +395,7 @@ enum msm_cvp_flags { MSM_CVP_FLAG_RBR_PENDING = BIT(1), MSM_CVP_FLAG_QUEUED = BIT(2), }; - +#endif struct msm_cvp_internal_buffer { struct list_head list; struct msm_cvp_smem smem; diff --git a/drivers/media/platform/msm/cvp/msm_v4l2_private.c b/drivers/media/platform/msm/cvp/msm_v4l2_private.c index a3e65a14a0fe..0ead5369b0d3 100644 --- a/drivers/media/platform/msm/cvp/msm_v4l2_private.c +++ b/drivers/media/platform/msm/cvp/msm_v4l2_private.c @@ -164,7 +164,7 @@ static int _copy_sysprop_to_user(struct cvp_kmd_arg *kp, return 0; } - +#ifndef OPLUS_FEATURE_CAMERA_COMMON static void _set_deprecate_bitmask(struct cvp_kmd_arg *kp, struct msm_cvp_inst *inst) { @@ -195,7 +195,7 @@ static void _set_deprecate_bitmask(struct cvp_kmd_arg *kp, break; } } - +#endif static void print_hfi_short(struct cvp_kmd_arg __user *up) { struct cvp_kmd_hfi_packet *pkt; @@ -261,9 +261,9 @@ static int convert_from_user(struct cvp_kmd_arg *kp, if (get_user(kp->type, &up->type)) return -EFAULT; - +#ifndef OPLUS_FEATURE_CAMERA_COMMON _set_deprecate_bitmask(kp, inst); - +#endif if (get_user(kp->buf_offset, &up->buf_offset) || get_user(kp->buf_num, &up->buf_num)) return -EFAULT; @@ -336,7 +336,8 @@ static int convert_from_user(struct cvp_kmd_arg *kp, return -EFAULT; break; } - case CVP_KMD_HFI_SEND_CMD: +#ifdef OPLUS_FEATURE_CAMERA_COMMON +case CVP_KMD_HFI_SEND_CMD: { struct cvp_kmd_send_cmd *k, *u; @@ -350,13 +351,16 @@ static int convert_from_user(struct cvp_kmd_arg *kp, return -EFAULT; break; } +#endif case CVP_KMD_SEND_CMD_PKT: +#ifndef OPLUS_FEATURE_CAMERA_COMMON case CVP_KMD_HFI_DFS_CONFIG_CMD: case CVP_KMD_HFI_DFS_FRAME_CMD: case CVP_KMD_HFI_DME_CONFIG_CMD: case CVP_KMD_HFI_DME_FRAME_CMD: case CVP_KMD_HFI_PERSIST_CMD: case CVP_KMD_HFI_FD_FRAME_CMD: +#endif { if (_get_pkt_hdr_from_user(up, &pkt_hdr)) { dprintk(CVP_ERR, "Invalid syscall: %x, %x, %x\n", @@ -368,7 +372,9 @@ static int convert_from_user(struct cvp_kmd_arg *kp, break; } case CVP_KMD_SEND_FENCE_CMD_PKT: +#ifndef OPLUS_FEATURE_CAMERA_COMMON case CVP_KMD_HFI_DME_FRAME_FENCE_CMD: +#endif { if (_get_fence_pkt_hdr_from_user(up, &pkt_hdr)) { dprintk(CVP_ERR, "Invalid syscall: %x, %x, %x\n", @@ -386,15 +392,17 @@ static int convert_from_user(struct cvp_kmd_arg *kp, pkt_hdr.packet_type); return -EFAULT; } - +#ifndef OPLUS_FEATURE_CAMERA_COMMON set_feature_bitmask(pkt_idx, &inst->deprecate_bitmask); - +#endif rc = _copy_fence_pkt_from_user(kp, up, (pkt_hdr.size >> 2)); break; } +#ifndef OPLUS_FEATURE_CAMERA_COMMON case CVP_KMD_HFI_DFS_FRAME_CMD_RESPONSE: case CVP_KMD_HFI_DME_FRAME_CMD_RESPONSE: case CVP_KMD_HFI_PERSIST_CMD_RESPONSE: +#endif case CVP_KMD_RECEIVE_MSG_PKT: break; case CVP_KMD_SESSION_CONTROL: @@ -529,6 +537,7 @@ static int convert_to_user(struct cvp_kmd_arg *kp, unsigned long arg) return -EFAULT; break; } +#ifndef OPLUS_FEATURE_CAMERA_COMMON case CVP_KMD_HFI_SEND_CMD: { struct cvp_kmd_send_cmd *k, *u; @@ -546,7 +555,9 @@ static int convert_to_user(struct cvp_kmd_arg *kp, unsigned long arg) return -EFAULT; break; } +#endif case CVP_KMD_SEND_CMD_PKT: +#ifndef OPLUS_FEATURE_CAMERA_COMMON case CVP_KMD_HFI_DFS_CONFIG_CMD: case CVP_KMD_HFI_DFS_FRAME_CMD: case CVP_KMD_HFI_DFS_FRAME_CMD_RESPONSE: @@ -556,6 +567,7 @@ static int convert_to_user(struct cvp_kmd_arg *kp, unsigned long arg) case CVP_KMD_HFI_PERSIST_CMD: case CVP_KMD_HFI_PERSIST_CMD_RESPONSE: case CVP_KMD_HFI_FD_FRAME_CMD: +#endif { if (_get_pkt_hdr_from_user(up, &pkt_hdr)) return -EFAULT; @@ -566,7 +578,9 @@ static int convert_to_user(struct cvp_kmd_arg *kp, unsigned long arg) break; } case CVP_KMD_SEND_FENCE_CMD_PKT: +#ifndef OPLUS_FEATURE_CAMERA_COMMON case CVP_KMD_HFI_DME_FRAME_FENCE_CMD: +#endif { if (_get_fence_pkt_hdr_from_user(up, &pkt_hdr)) return -EFAULT; diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index cddb56da62a8..0660da335bc2 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -545,6 +545,13 @@ config UID_SYS_STATS_DEBUG help Per TASK based io statistics exported to /proc/uid_io +config OPLUS_FEATURE_UID_PERF + bool "Per-TASK perf_event statistics" + depends on UID_SYS_STATS + default n + help + Per TASK based on perf_event + config MEMORY_STATE_TIME tristate "Memory freq/bandwidth time statistics" depends on PROFILING @@ -631,6 +638,36 @@ config KINECTICS_XR_NORDIC this also parses the gpios and interrupts from device tree and sets the gpios and interrupt handler for handling the interrupt. +#ifdef OPLUS_FEATURE_TP_BASIC +config OPLUS_RF_CABLE_MONITOR + bool "OPLUS rf cable monitor system" + depends on OF + select PINMUX + default n + help + Say Y here to enable OPLUS rf cable monitor system support +#endif /* OPLUS_FEATURE_TP_BASIC */ + +#ifdef OPLUS_FEATURE_SIM_DETECT +config SIM_DETECT + tristate "SIM_DETECT system" + default n + help + Say Y here to enable sim detect system support +config HAPTIC_FEEDBACK + tristate "Haptic driver feedback for awinic aw8697 series" + help + This option enables support for aw8697 series Haptic Driver Feedback. +#endif /* OPLUS_FEATURE_SIM_DETECT */ + +#ifdef OPLUS_FEATURE_SIM_DETECT +config OEM_QMI + tristate "oem qmi feature" + default n + help + Say Y here to enable oem qmi support +#endif /* OPLUS_FEATURE_SIM_DETECT */ + source "drivers/misc/c2port/Kconfig" source "drivers/misc/eeprom/Kconfig" source "drivers/misc/cb710/Kconfig" @@ -645,6 +682,17 @@ source "drivers/misc/echo/Kconfig" source "drivers/misc/cxl/Kconfig" source "drivers/misc/ocxl/Kconfig" source "drivers/misc/cardreader/Kconfig" +source "drivers/misc/tri_state_key/Kconfig" +#ifdef OPLUS_FEATURE_TP_BASIC +source "drivers/misc/cs_press/Kconfig" +#endif +#ifdef OPLUS_FEATURE_TP_BASIC +source "drivers/misc/colorctrl/Kconfig" +source "drivers/misc/colorctrl_v2/Kconfig" +#endif /* OPLUS_FEATURE_TP_BASIC */ +#ifdef OPLUS_FEATURE_TP_BASIC//Qingjun.Wang@BSP.Haptic,add 2020/03/17 for vib aw8697 +source "drivers/misc/aw8697_haptic/Kconfig" +#endif source "drivers/misc/fpr_FingerprintCard/Kconfig" source "drivers/misc/qrc/Kconfig" endmenu diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 93fda83f75c1..442e24b0b20d 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -49,6 +49,7 @@ obj-$(CONFIG_LATTICE_ECP3_CONFIG) += lattice-ecp3-config.o obj-$(CONFIG_SRAM) += sram.o obj-$(CONFIG_SRAM_EXEC) += sram-exec.o obj-y += mic/ +obj-y += tri_state_key/ obj-$(CONFIG_GENWQE) += genwqe/ obj-$(CONFIG_HDCP_QSEECOM) += hdcp_qseecom.o obj-$(CONFIG_HDCP_QSEECOM) += msm_hdcp.o @@ -75,6 +76,33 @@ obj-$(CONFIG_OKL4_LINK_SHBUF) += okl4-link-shbuf.o obj-$(CONFIG_WIGIG_SENSING_SPI) += wigig_sensing.o obj-$(CONFIG_QTI_MAXIM_FAN_CONTROLLER) += max31760.o obj-$(CONFIG_QTI_XR_SMRTVWR_MISC) += qxr-stdalonevwr.o + +# ifdef OPLUS_FEATURE_TP_BASIC +obj-$(CONFIG_CS_F61_NDT) += cs_press/ +# endif /* OPLUS_FEATURE_TP_BASIC */ + +#ifdef OPLUS_FEATURE_TP_BASIC +obj-$(CONFIG_COLOR_CTRL) += colorctrl/ +obj-$(CONFIG_COLOR_CTRL_V2) += colorctrl_v2/ +#endif /* OPLUS_FEATURE_TP_BASIC */ + +#ifdef VENDOR_EDIT//Qingjun.Wang@BSP.Haptic,add 2020/03/17 for vib aw8697 +obj-$(CONFIG_AW8697_HAPTIC) += aw8697_haptic/ +#endif + obj-$(CONFIG_FPR_FPC) += fpr_FingerprintCard/ + +#ifdef OPLUS_FEATURE_RF_CABLE_DETECT +obj-$(CONFIG_OPLUS_RF_CABLE_MONITOR) += oplus_rf_cable_monitor.o +obj-$(CONFIG_OPLUS_RF_CABLE_MONITOR) += op_ant_detect.o +#endif /* OPLUS_FEATURE_RF_CABLE_DETECT */ + +#ifdef OPLUS_FEATURE_SIM_DETECT +obj-$(CONFIG_SIM_DETECT) += sim_detect.o +#endif + +#ifdef OPLUS_FEATURE_SIM_DETECT +obj-$(CONFIG_OEM_QMI) += oem_qmi_client.o +#endif obj-y += qrc/ obj-$(CONFIG_KINECTICS_XR_NORDIC) += kxrctrl/ diff --git a/drivers/misc/aw8697_haptic b/drivers/misc/aw8697_haptic new file mode 120000 index 000000000000..f7b8bf6891c4 --- /dev/null +++ b/drivers/misc/aw8697_haptic @@ -0,0 +1 @@ +../../../../vendor/oplus/kernel/vibrator/aw8697_haptic/ \ No newline at end of file diff --git a/drivers/misc/colorctrl b/drivers/misc/colorctrl new file mode 120000 index 000000000000..a42f3cd1a936 --- /dev/null +++ b/drivers/misc/colorctrl @@ -0,0 +1 @@ +../../../../vendor/oplus/kernel/colorctrl/colorctrl \ No newline at end of file diff --git a/drivers/misc/colorctrl_v2 b/drivers/misc/colorctrl_v2 new file mode 120000 index 000000000000..5f3fc6b2e083 --- /dev/null +++ b/drivers/misc/colorctrl_v2 @@ -0,0 +1 @@ +../../../../vendor/oplus/kernel/colorctrl/colorctrl_v2 \ No newline at end of file diff --git a/drivers/misc/cs_press/Kconfig b/drivers/misc/cs_press/Kconfig new file mode 100644 index 000000000000..94ffdb7ea7a1 --- /dev/null +++ b/drivers/misc/cs_press/Kconfig @@ -0,0 +1,8 @@ +config CS_F61_NDT + bool "chip sea F61 press sensor" + default n + help + Say Y here if you have a cs press connected + to your system. + + If unsure, say N. \ No newline at end of file diff --git a/drivers/misc/cs_press/Makefile b/drivers/misc/cs_press/Makefile new file mode 100644 index 000000000000..27ed74d3fb79 --- /dev/null +++ b/drivers/misc/cs_press/Makefile @@ -0,0 +1,7 @@ +# +# Makefile for press driver +# + + +obj-$(CONFIG_CS_F61_NDT) += cs_press_f61.o + diff --git a/drivers/misc/cs_press/cs_press_f61.c b/drivers/misc/cs_press/cs_press_f61.c new file mode 100644 index 000000000000..d9a140a482d1 --- /dev/null +++ b/drivers/misc/cs_press/cs_press_f61.c @@ -0,0 +1,1626 @@ +/* drivers/misc/cs_press/cs_press_f61.c*/ +/************************************************************ + * Copyright 2018 OPLUS Mobile Comm Corp., Ltd. + * All rights reserved. + * + * Description : driver for chip sea IC + * History : ( ID, Date, Author, Description) + * Data : 2018/11/03 + ************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "cs_press_f61.h" + +#define CS_LOG(a, arg...) pr_err("[cs_press]: " a, ##arg) +#define CS_CHRDEV_NAME "cs_press" +#define FW_PATH "press/19065/FW_F61_NDT.nfw" + +__attribute__((weak)) void external_report_touch(int id, bool down_status, int x, int y) {return;} + +/** + * cs_i2c_read - Using for read data through i2c + * @cd: cd press device handler + * @reg: register for start reading + * @datbuf: buffer for stroring data read from IC + * @byte_len: data length we want to read + * + * Actully, This function call i2c_transfer for IIC transfer, + * Returning transfer length(transfer success) or most likely negative errno(transfer error) + */ +static int cs_i2c_read(struct cs_device* cd, unsigned char reg, unsigned char *datbuf, int byte_len) +{ + struct i2c_msg msg[2]; + int ret = 0; + int i = IIC_MAX_TRSANFER; + + msg[0].addr = cd->client->addr; + msg[0].flags = 0; + msg[0].len = 1; + msg[0].buf = ® + + msg[1].addr = cd->client->addr; + msg[1].flags = I2C_M_RD; + msg[1].len = byte_len; + msg[1].buf = datbuf; + + mutex_lock(&cd->i2c_mutex); + do { + ret = i2c_transfer(cd->client->adapter, msg, 2); + if ((ret <= 0) && (i < 4)) { + CS_LOG("i2c_transfer Error, err_code:%d,i=%d\n", ret, i); + } else { + break; + } + + i--; + } while (i > 0); + mutex_unlock(&cd->i2c_mutex); + + return ret; +} + +/** + * cs_i2c_write - Using for write data through i2c + * @cd: cd press device handler + * @reg: register for start writing + * @datbuf: buffer for stroring writing data + * @byte_len: data length we want to write + * + * Actully, This function call i2c_transfer for IIC transfer, + * Returning transfer length(transfer success) or most likely negative errno(transfer error) + */ +static int cs_i2c_write(struct cs_device* cd, unsigned char reg, unsigned char *datbuf, int byte_len) +{ + unsigned char *buf = NULL; + struct i2c_msg msg; + int ret = 0; + int i = IIC_MAX_TRSANFER; + + if (!datbuf || byte_len <= 0) + return -1; + + buf = (unsigned char *)kmalloc(byte_len + 1, GFP_KERNEL); + if (!buf) + return -1; + + memset(buf, 0, byte_len + 1); + buf[0] = reg; + memcpy(buf + 1, datbuf, byte_len); + + msg.addr = cd->client->addr; + msg.flags = 0; + msg.len = byte_len + 1; + msg.buf = buf; + + mutex_lock(&cd->i2c_mutex); + do { + ret = i2c_transfer(cd->client->adapter, &msg, 1); + if ((ret <= 0) && (i < 4)) { + CS_LOG("i2c_transfer Error! err_code:%d,i=%d\n", ret, i); + } else { + break; + } + + i--; + } while (i > 0); + mutex_unlock(&cd->i2c_mutex); + + kfree(buf); + + return ret; +} + +static int cs_read_eeprom(struct cs_device *cd, unsigned short reg, unsigned char *datbuf, int byte_len) +{ + struct i2c_msg msg[2]; + int ret = 0; + unsigned char reg16[2]; + + if (!datbuf) + return -1; + + reg16[0] = (reg >> 8) & 0xff; + reg16[1] = reg & 0xff; + + msg[0].addr = cd->client->addr; + msg[0].flags = 0; + msg[0].len = sizeof(reg16); + msg[0].buf = reg16; + + msg[1].addr = cd->client->addr; + msg[1].flags = I2C_M_RD; + msg[1].len = byte_len; + msg[1].buf = datbuf; + + mutex_lock(&cd->i2c_mutex); + ret = i2c_transfer(cd->client->adapter, msg, 2); + if (ret < 0) { + CS_LOG("i2c_transfer Error, err_code:%d\n", ret); + } + mutex_unlock(&cd->i2c_mutex); + + return ret; +} + +static int cs_write_eeprom(struct cs_device *cd, unsigned short reg, unsigned char *datbuf, int byte_len) +{ + unsigned char *buf = NULL; + struct i2c_msg msg; + int ret = 0; + + if (!datbuf || byte_len <= 0) + return -1; + buf = (unsigned char *)kmalloc(byte_len + sizeof(reg), GFP_KERNEL); + if (!buf) + return -1; + + memset(buf, 0, byte_len + sizeof(reg)); + buf[0] = (reg >> 8) & 0xff; + buf[1] = reg & 0xff; + memcpy(buf + sizeof(reg), datbuf, byte_len); + + msg.addr = cd->client->addr; + msg.flags = 0; + msg.len = byte_len + sizeof(reg); + msg.buf = buf; + + mutex_lock(&cd->i2c_mutex); + ret = i2c_transfer(cd->client->adapter, &msg, 1); + if (ret < 0) { + CS_LOG("i2c_master_send Error, err_code:%d\n", ret); + } + mutex_unlock(&cd->i2c_mutex); + + kfree(buf); + return ret; +} + +static int cs_eeprom_erase(struct cs_device *cd) +{ + unsigned char erase_cmd[] = {0xAA, 0x55, 0xA5, 0x5A}; + + /*erase flash*/ + if (cs_write_eeprom(cd, IIC_EEPROM, erase_cmd, sizeof(erase_cmd)) <= 0) { + CS_LOG("cs_write_eeprom fails in cs_eeprom_erase\n"); + return -1; + } + + msleep(2000); + return 0; +} + +int cs_eeprom_skip(struct cs_device *cd) +{ + unsigned char skip_cmd[] = {0x7E, 0xE7, 0xEE, 0x77}; + + if (cs_write_eeprom(cd, IIC_EEPROM, skip_cmd, sizeof(skip_cmd)) <= 0) { + CS_LOG("cs_write_eeprom fails in cs_eeprom_skip\n"); + return -1; + } + + return 0; +} + +int cs_eeprom_read(struct cs_device *cd) +{ + unsigned char cmd[] = {0xA7, 0x00, 0x00, 0x59}; + + if (cs_write_eeprom(cd, IIC_RESETCMD, cmd, sizeof(cmd)) <= 0) { + CS_LOG("cs_write_eeprom fail !\n"); + return -1; + } + + return 0; +} + +int wake_up_fw(struct cs_device *cd) +{ + int i = 5; + int ret = 0; + char reg_data[2] = {0}; + + do { + ret = cs_i2c_read(cd, IIC_MANU_ID, reg_data, 1); + i--; + } while (ret <= 0 && i > 0); + + return 0; +} + +/** + * cs_mode_switch - for switch work mode + * cd : cs press handler + * mode : 0 for normal mode, 1 for standby mode. + */ +static int cs_mode_switch(struct cs_device *cd, int mode) +{ + int ret = 0; + int retry = 5; + unsigned char data[1] = {0}; + + wake_up_fw(cd); //wakeup i2c + + if (0 == mode) { + data[0] = 0x00; //scan freq auto + } else if (1 == mode) { + data[0] = 0x01; //max scan freq:100hz + } else if (2 == mode) { + data[0] = 0x02; //min scan freq:10hz + } else if (3 == mode) { + data[0] = 0x03; //sleep mode + } else { + CS_LOG("not support mode(%d).\n", mode); + } + ret = cs_i2c_write(cd, IIC_WORK_MODE, data, sizeof(data)); + data[0] = 0x02; + ret |= cs_i2c_write(cd, 0x0F, data, sizeof(data)); + if (ret <= 0) { + CS_LOG("send mode switch cmd:%d failed.\n", data[0]); + return ret; + } + + while (retry) { + msleep(10); + ret = cs_i2c_read(cd, 0x0F, data, sizeof(data)); + if ((ret > 0) && (0x00 == data[0])) { + break; + } + retry--; + } + CS_LOG("wait mode(%d) switch left %d ms.\n", mode, retry*10); + + return ret; +} + +/** +* cs_parse_dt - parse dts of cs press, acquire harware resource +* @cd: cs press handler, init it's harfware member +*/ +static int cs_parse_dt(struct cs_device *cd) +{ + int ret = 0; + + cd->vdd_2v8 = regulator_get(cd->dev, "vdd_2v8"); + if(IS_ERR_OR_NULL(cd->vdd_2v8)) { + CS_LOG("cs press regulator no defined.\n"); + } else { + if (regulator_count_voltages(cd->vdd_2v8) > 0) { + ret = regulator_set_voltage(cd->vdd_2v8, 2800000, 3300000); + if (ret) { + CS_LOG("Regulator set_vtg failed vdd ret=%d\n", ret); + } + } + } + + cd->irq_gpio = of_get_named_gpio_flags(cd->dev->of_node, "press,irq-gpio", 0, &cd->irq_flag); + if(!gpio_is_valid(cd->irq_gpio)) { + CS_LOG("cspress request_irq IRQ fail.\n"); + } else { + ret = gpio_request(cd->irq_gpio, "press,irq-gpio"); + if(ret) { + CS_LOG("cs press request_irq IRQ fail, ret=%d.\n", ret); + } + } + + cd->reset_gpio = of_get_named_gpio(cd->dev->of_node, "press,rst-gpio", 0); + if(!gpio_is_valid(cd->reset_gpio)) { + CS_LOG("cs_press request_rst fail.\n"); + } else { + ret = gpio_request(cd->reset_gpio, "press,rst-gpio"); + if(ret) { + CS_LOG("cs_press request rst fail, ret=%d.\n", ret); + } + } + + return 0; +} + +/** +* cs_power_control - interface for power on and power off +* @cd: cs press handler +* @on: true for power on, false for power off +*/ +static int cs_power_control(struct cs_device *cd, bool on) +{ + int ret = 0; + + if (on) { + if (!IS_ERR_OR_NULL(cd->vdd_2v8)) { + ret = regulator_enable(cd->vdd_2v8); //power on + if (ret) { + CS_LOG("cs press power on failed(%d).\n", ret); + } + } + + if (gpio_is_valid(cd->reset_gpio)) { + gpio_direction_output(cd->reset_gpio, 0); //default to low state + } + } else { + if (gpio_is_valid(cd->reset_gpio)) { + gpio_direction_output(cd->reset_gpio, 1); //pull to reset state + } + + if (!IS_ERR_OR_NULL(cd->vdd_2v8)) { + ret = regulator_disable(cd->vdd_2v8); //power off + if (ret) { + CS_LOG("cs press power off failed(%d).\n", ret); + } + } + } + CS_LOG("%s state: %d.\n", __func__, on); + + return ret; +} + +/** +* cs_reset - interface for reset +* @cd: cs press handler +* @shval: 0 for hardware reset, 1 for software reset, 2 for defalut reset +*/ +static int cs_reset(struct cs_device *cd) +{ + unsigned char erase_cmd[] = {0xA0, 0x00, 0x00, 0x60}; + + if(gpio_is_valid(cd->reset_gpio)) { + gpio_direction_output(cd->reset_gpio, 1); + msleep(10); + gpio_direction_output(cd->reset_gpio, 0); + CS_LOG("harware reset.\n"); + } else { + cs_write_eeprom(cd, IIC_RESETCMD, erase_cmd, sizeof(erase_cmd)); + CS_LOG("software reset.\n"); + } + + return 0; +} + +/** +* cs_i2c_check - interface for reset +* @cd: cs press handler +*/ +int cs_i2c_check(struct cs_device *cd) +{ + int retry = 4; + unsigned char rbuf[2] = {0}; + int ret = 0; + + do { + wake_up_fw(cd); + if (cs_i2c_read(cd, IIC_MANU_ID, rbuf, 1) > 0) { + CS_LOG("i2c check success.\n"); + if (!rbuf[0]) { + CS_LOG("read no fw id, need do force update.\n"); + cd->force_update = true; + } + return 0; + } else { + cs_reset(cd); + msleep(300); + } + + retry--; + } while (retry > 0); + + if (retry <= 0) { + ret = -1; + CS_LOG("i2c check failed.\n"); + } + + return ret; +} + +/** +* init_input_device - init input device for reporting +* @cd: cs press handler +*/ +static int init_input_device(struct cs_device *cd) +{ + int ret = 0; + + cd->input_dev = input_allocate_device(); + if (cd->input_dev == NULL) { + ret = -ENOMEM; + CS_LOG("Failed to allocate input device\n"); + return ret; + } + + cd->input_dev->name = "cs_press"; + set_bit(EV_SYN, cd->input_dev->evbit); + set_bit(EV_KEY, cd->input_dev->evbit); + set_bit(KEY_POWER, cd->input_dev->keybit); + set_bit(KEY_HOMEPAGE, cd->input_dev->keybit); + set_bit(KEY_BACK, cd->input_dev->keybit); + set_bit(KEY_F24, cd->input_dev->keybit); + + ret = input_register_device(cd->input_dev); + if (ret) { + input_free_device(cd->input_dev); + cd->input_dev = NULL; + CS_LOG("Failed to register input device.\n"); + } else { + CS_LOG("success to register input device.\n"); + } + + return ret; +} + +static int fw_burn(struct cs_device *cd, unsigned char *buf, int len) +{ + unsigned short reg = 0; + int byte_len = 0, pos = 0; + unsigned char *read_buf; + int ret = 0, i = 0, err_len = 0, number = 0; + bool i2c_ok = true; + int page_end = len%256; + char err_buf[256*3+3] = {0}; + + if (len % 128) { + CS_LOG("burn len is not 128*\n"); + return -1; + } + CS_LOG("write len:%d, read page_end:%d\n", len, page_end); + read_buf = (unsigned char *)kmalloc(len, GFP_KERNEL); + if (!read_buf) { + CS_LOG("kmalloc for read_buf fails\n"); + return -1; + } + + do { + cs_reset(cd); + msleep(60); + + i2c_ok = true; + ret = cs_eeprom_erase(cd); + if (ret < 0) { + i2c_ok = false; + goto I2C_BAD_OUT; + } + + /*write eeprom*/ + pos = 0; + reg = 0x00; + byte_len = 128; + while (pos < len) { + ret = cs_write_eeprom(cd, pos, buf + pos, byte_len); + if (ret < 0) { + CS_LOG("cs_write_eeprom fails, page:%d\n", reg); + i2c_ok = false; + goto I2C_BAD_OUT; + } + pos += byte_len; + reg++; + msleep(15); + } + + /*read eeprom*/ + pos = 0; + reg = 0x00; + byte_len = 256; + while (pos < len) { + ret = cs_read_eeprom(cd, pos, read_buf + pos, byte_len); + if (ret < 0) { + CS_LOG("read page fail, page:%d\n", reg); + i2c_ok = false; + goto I2C_BAD_OUT; + } + /*check*/ + if ((page_end > 0) && (reg >= len/256)) + byte_len = page_end; + if (memcmp(buf + pos, read_buf + pos, byte_len)) { + CS_LOG("read page cmp fail, page:%d\n", reg); + i2c_ok = false; + + err_len = 0; + for (i = 0; i < byte_len; i++) + err_len += sprintf(err_buf + err_len, "%02x ", read_buf[pos + i]); + err_len += sprintf(err_buf + err_len, "\n"); + CS_LOG("buf=%s\n", err_buf); + + goto I2C_BAD_OUT; + } + pos += byte_len; + reg++; + msleep(15); + } +I2C_BAD_OUT: + number++; + } while ( number < 3 && !i2c_ok); + + + if (!i2c_ok) + CS_LOG("burn firmware err.\n"); + else + CS_LOG("burn firmware success.\n"); + + msleep(100); + cs_reset(cd); + msleep(100); + cs_eeprom_skip(cd); + if (read_buf) + kfree(read_buf); + + return ret; +} + +/** +* cs_set_press_threshold - set corresponding channel touchdown and touchup threshold +* @cd: cs press handler +* @touchTh: touchdown threshold +* @leaveTh: touchup threshold +* @channel: channel number we want to write +*/ +static int set_press_threshold(struct cs_device *cd, int touchTh, int leaveTh, char channel) +{ + int ret = 0; + unsigned char datbuf[8] = {0}; + + CS_LOG("set TouchTh: %d, LeaveTh: %d, channel: %d\n", touchTh, leaveTh, channel); + if (leaveTh > touchTh) { + CS_LOG("incorrect TouchTh and LeaveTh, return.\n"); + return -1; + } + + wake_up_fw(cd); + + datbuf[0] = touchTh & 0xff; + datbuf[1] = (touchTh >> 8) & 0xff; + ret = cs_i2c_write(cd, IIC_DOWN_THD, datbuf, 2); + + datbuf[0] = leaveTh & 0xff; + datbuf[1] = (leaveTh >> 8) & 0xff; + ret |= cs_i2c_write(cd, IIC_UP_THD, datbuf, 2); + + datbuf[0] = 0x01; + ret |= cs_i2c_write(cd, 0x0f, datbuf, 1); + + return ret; +} + +/** +* cs_get_press_threshold - acquire corresponding channel touchdown and touchup threshold +* @cd: cs press handler +* @*touchTh: pointer for store touchdown threshold +* @*leaveTh: pointer for store touchup threshold +* @channel: channel number we want to read +*/ +static int get_press_threshold(struct cs_device *cd, unsigned int *touchTh, unsigned int *leaveTh, char channel) +{ + int ret = 0; + unsigned char datbuf[8] = {0}; + + wake_up_fw(cd); + + memset(datbuf, 0, 8*sizeof(unsigned char)); + ret = cs_i2c_read(cd, IIC_DOWN_THD, datbuf, 2); + *touchTh = (unsigned int)(short)(datbuf[0] | ((datbuf[1]<<8)&0xff00)); + + memset(datbuf, 0, 8*sizeof(unsigned char)); + ret |= cs_i2c_read(cd, IIC_UP_THD, datbuf, 2); + *leaveTh = (unsigned int)(short)(datbuf[0] | ((datbuf[1]<<8)&0xff00)); + CS_LOG("get TouchTh: %d, LeaveTh: %d\n", *touchTh, *leaveTh); + + return ret; +} + +/** +* cs_get_pressure - acquire current pressure +* @cd: cs press handler +*/ +int cs_get_pressure(struct cs_device *cd) +{ + char reg_addr = 0x20; + char reg_data[2] = {0}; + int pressdata = 0; + + if (cs_i2c_read(cd, reg_addr, reg_data, 1) < 0) { + CS_LOG("err: reg=0x%02x, data=0x%02x\n", reg_addr, reg_data[0]); + } + if (reg_data[0] != 0) { + reg_addr = 0x21; + if (cs_i2c_read(cd, reg_addr, reg_data, 2) < 0) { + CS_LOG("err: reg=0x%02x,data0=0x%02x,data1=0x%02x\n", reg_addr, reg_data[0], reg_data[1]); + } + } else { + CS_LOG("err: regdata is 0\n"); + return 0; + } + + pressdata = ((int)(reg_data[0] & 0xff) | ((int)(reg_data[1] & 0xff) << 8)); + return pressdata; +} + +int read_eeprom_data(struct cs_device *cd, char *buf) +{ + unsigned char datbuf[33]; + int i; + int len = 33; + int ret = 1; + + datbuf[0] = 0x00; + cs_i2c_write(cd, 0x80, datbuf, 1); + + datbuf[0] = 0x40; + cs_i2c_write(cd, 0x80, datbuf, 1); + msleep(30); + + memset(datbuf, 0, len * sizeof(unsigned char)); + cs_i2c_read(cd, 0x81, datbuf, len); + CS_LOG("R 81:%02x,%02x \n", datbuf[0], datbuf[1]); + if (datbuf[0] == len-1) { + CS_LOG("Read eeprom 32 Data:\n"); + for (i = 0; i < datbuf[0]; i++) + CS_LOG("%d %02x\n", i, datbuf[i]); + } + + for (i = 0; i < len; i++) + ret += sprintf(buf + 3 * i, "%02x ", datbuf[i]); + ret += sprintf(buf + 3 * i, "\n"); + + return ret; +} + +static int cs_write_calibrate_param(struct cs_device *cd, unsigned int data1, char channel) +{ + unsigned char datbuf[8] = {0}; + + CS_LOG("w calibrate_param:%d,channel:%d\n", data1, channel); + datbuf[0] = 0x00; + cs_i2c_write(cd, 0x80, datbuf, 1); + + datbuf[0] = 0x30; + cs_i2c_write(cd, 0x80, datbuf, 1); + + datbuf[0] = channel; + datbuf[1] = 0x00; + datbuf[2] = data1 & 0xff; + datbuf[3] = (data1 >> 8) & 0xff; + datbuf[4] = (data1 >> 16) & 0xff; + datbuf[5] = (data1 >> 24) & 0xff; + datbuf[6] = datbuf[0] + datbuf[1] + datbuf[2] + datbuf[3] + datbuf[4] + datbuf[5]; /*checksum*/ + cs_i2c_write(cd, 0x82, datbuf, 7); + + datbuf[0] = 0x07; + cs_i2c_write(cd, 0x81, datbuf, 1); + + return 0; + +} + +static int cs_read_calibrate_param(struct cs_device *cd, unsigned int *data, char channel) +{ + unsigned char datbuf[8] = {0}; + + datbuf[0] = 0x00; + cs_i2c_write(cd, 0x80, datbuf, 1); + + datbuf[0] = 0x31; + cs_i2c_write(cd, 0x80, datbuf, 1); + + datbuf[0] = channel; + datbuf[1] = 0x00; + cs_i2c_write(cd, 0x82, datbuf, 2); + + datbuf[0] = 0x02; + cs_i2c_write(cd, 0x81, datbuf, 1); + msleep(30); + + memset(datbuf, 0, 8 * sizeof(unsigned char)); + cs_i2c_read(cd, 0x81, datbuf, 5); + CS_LOG("R:%02x,%02x,%02x,%02x,%02x\n", datbuf[0], datbuf[1], datbuf[2], datbuf[3], datbuf[4]); + if (datbuf[0] == 4) { + *data = (unsigned int)(datbuf[1] + (datbuf[2] << 8) + (datbuf[3]<<16) + (datbuf[4] << 24)); + CS_LOG("R calibrate_param:%d\n", *data); + return 0; + } + return -1; +} + +int cs_compare_cali_param(struct cs_device *cd) +{ + char temp[256] = {0}; + int is_cal = 0; + char count = 5; + unsigned int cali_ic0[2]; + unsigned int cali_ic1[2]; + unsigned int cali_data1 = 0; + int slp1 = 0, itr1 = 0, slp2 = 0, itr2 = 0, ret = 0; + + sprintf(temp, "1 4567 -100 -4668 -200"); + ret = sscanf(temp, "%d %d %d %d %d", &is_cal, &slp1, &itr1, &slp2, &itr2); + CS_LOG("read ROM Cali:%d %d %d %d %d\n", is_cal, slp1, itr1, slp2, itr2); + + if (is_cal == 1) { + /*ch0*/ + count = 5; + cali_data1 = (unsigned int)(slp1 + (itr1 << 16)); + do { + cs_read_calibrate_param(cd, cali_ic0, 0); + CS_LOG("read Cali CH0 : 0x%08x\n", cali_ic0[0]); + + if (cali_data1 == cali_ic0[0]) { + CS_LOG("CH0 is Same!\n"); + break; + } + + cs_write_calibrate_param(cd, cali_data1, 0); + CS_LOG("write Cali CH0 : 0x%08x\n", cali_data1); + msleep(20); + + count--; + } while (count); + + /*ch1*/ + count = 5; + cali_data1 = (unsigned int)(slp2 + (itr2 << 16)); + do { + cs_read_calibrate_param(cd, cali_ic1, 1); + CS_LOG("read Cali CH1 : 0x%08x\n", cali_ic1[0]); + + if (cali_data1 == cali_ic1[0]) { + CS_LOG("CH1 is Same!\n"); + break; + } + + cs_write_calibrate_param(cd, cali_data1, 1); + CS_LOG("write Cali CH1 : 0x%08x\n", cali_data1); + msleep(20); + + count--; + } while (count); + } + + return 0; +} + +static irqreturn_t cs_irq_thread_func(int irq, void *dev_id) +{ + uint8_t key_status = 0; + struct cs_device *cd = (struct cs_device *)dev_id; + + mutex_lock(&cd->mutex); + + cs_i2c_read(cd, IIC_KEY_STATUS, &key_status, 1); + CS_LOG("%s: keystatus:%d.\n", __func__, key_status); + + if (MODE_REPORT_KEY == cd->report_mode) { + input_report_key(cd->input_dev, KEY_F24, key_status > 0); + input_sync(cd->input_dev); + } else if (MODE_REPORT_TOUCH == cd->report_mode) { + external_report_touch(10, key_status > 0, cd->current_point.x, cd->current_point.y); + } else if (MODE_REPORT_POWER == cd->report_mode) { + input_report_key(cd->input_dev, KEY_POWER, key_status > 0); + input_sync(cd->input_dev); + } else if (MODE_REPORT_HOME == cd->report_mode) { + input_report_key(cd->input_dev, KEY_HOMEPAGE, key_status > 0); + input_sync(cd->input_dev); + } else if (MODE_REPORT_BACK == cd->report_mode) { + input_report_key(cd->input_dev, KEY_BACK, key_status > 0); + input_sync(cd->input_dev); + } else { + CS_LOG("%s: no handle.\n", __func__); + } + + mutex_unlock(&cd->mutex); + + return IRQ_HANDLED; +} + +static ssize_t cs_read(struct file *file, char __user *buf, size_t count, loff_t *offset) +{ + int err = 0; + char *kbuf = NULL; + char reg = 0; + struct miscdevice *mc = file->private_data; + struct cs_device *cd = container_of(mc, struct cs_device, cs_misc); + + kbuf = kzalloc(count, GFP_KERNEL); + if (!kbuf) { + err = -ENOMEM; + goto exit; + } + + /*get reg addr buf[0]*/ + if (copy_from_user(®, buf, 1)) { + err = -EFAULT; + CS_LOG("%s, copy reg:0x%02x from user failed.\n", __func__, reg); + goto exit_kfree; + } + + mutex_lock(&cd->mutex); + err = cs_i2c_read(cd, reg, kbuf, count); + mutex_unlock(&cd->mutex); + if (err < 0) { + CS_LOG("%s, read reg:0x%02x failed.\n", __func__, reg); + goto exit_kfree; + } + + if (copy_to_user(buf+1, kbuf, count)) { + CS_LOG("%s, copy to user failed.\n", __func__); + err = -EFAULT; + } + +exit_kfree: + kfree(kbuf); + +exit: + return err < 0 ? err : count; +} + +static ssize_t cs_write(struct file *file, const char __user *buf, size_t count, loff_t *offset) +{ + int err = 0; + char *kbuf = NULL; + char reg = 0; + struct miscdevice *mc = file->private_data; + struct cs_device *cd = container_of(mc, struct cs_device, cs_misc); + + kbuf = kzalloc(count, GFP_KERNEL); + if (!kbuf) { + err = -ENOMEM; + goto exit; + } + + if (copy_from_user(®, buf, 1) || copy_from_user(kbuf, buf+1, count)) { + err = -EFAULT; + CS_LOG("%s, w reg:0x%02x failed.\n", __func__, reg); + goto exit_kfree; + } + + mutex_lock(&cd->mutex); + err = cs_i2c_write(cd, reg, kbuf, count); + mutex_unlock(&cd->mutex); + +exit_kfree: + kfree(kbuf); + +exit: + return err < 0 ? err : count; +} + +static const struct file_operations cs_fops = { + .owner = THIS_MODULE, + .open = simple_open, + .read = cs_read, + .write = cs_write, +}; + +static ssize_t proc_fw_update_write(struct file *file, const char __user *page, size_t size, loff_t *lo) +{ + char buf[4] = {0}; + int val = 0, ret = 0; + uint32_t fw_len = 0; + const struct firmware *fw = NULL; + uint16_t ic_version = 0, image_version = 0; + struct cs_device *cd = PDE_DATA(file_inode(file)); + + if (!cd) + return size; + if (size > 2) + return size; + + if (copy_from_user(buf, page, size)) { + CS_LOG("%s: read proc input error.\n", __func__); + return size; + } + + sscanf(buf, "%d", &val); + + disable_irq(cd->irq); /*close enit irq.*/ + mutex_lock(&cd->mutex); + + ret = request_firmware(&fw, FW_PATH, cd->dev); + if (ret < 0) { + CS_LOG("%s request fw failed,ret:%d\n", __func__, ret); + goto out; + } + + wake_up_fw(cd); + memset(buf, 0, CS_FWID_LEN); + ret = cs_i2c_read(cd, IIC_FW_VER, buf, CS_FWID_LEN); + if (ret < 0) { + CS_LOG("%s read fw version,ret:%d\n", __func__, ret); + goto out; + } + ic_version = buf[0] | (buf[1] << 8); + image_version = (fw->data[CS_FW_VERPOS] << 8) | fw->data[CS_FW_VERPOS+1]; + CS_LOG("fw ic version:0x%04x, fw image version:0x%04x\n", ic_version, image_version); + + if ((image_version == ic_version) && !cd->force_update && !val) { + CS_LOG("no need do fw update.\n"); + goto out; + } + + fw_len = fw->data[CS_FW_LENPOS+3] | (fw->data[CS_FW_LENPOS+2] << 8) | (fw->data[CS_FW_LENPOS+1] << 16) | (fw->data[CS_FW_LENPOS] << 24); + ret = fw_burn(cd, (unsigned char *)&fw->data[CS_FW_STARTPOS], fw_len); + if (ret < 0) { + CS_LOG("%s: fw burn failed.\n", __func__); + goto out; + } + + CS_LOG("fw update finished\n"); +out: + if (fw) { + release_firmware(fw); + fw = NULL; + } + mutex_unlock(&cd->mutex); + enable_irq(cd->irq); /*open enit irq.*/ + + return size; +} + +static const struct file_operations proc_fw_update_ops = +{ + .write = proc_fw_update_write, + .open = simple_open, + .owner = THIS_MODULE, +}; + +static int fw_info_read_func(struct seq_file *s, void *v) +{ + int i = 0; + unsigned char buf[32] = {0}; + struct cs_device *cd = s->private; + + if (!cd) + return 0; + + disable_irq(cd->irq); + mutex_lock(&cd->mutex); + + cs_i2c_read(cd, IIC_DEV_ID, buf, CS_DEVID_LEN); + seq_printf(s, "Device ID:"); + for (i = 0; i < CS_DEVID_LEN; i++) + seq_printf(s, "%02x ", buf[i]); + seq_printf(s, "\n"); + + cs_i2c_read(cd, IIC_MANU_ID, buf, CS_MANUID_LEN); + seq_printf(s, "Manu ID:"); + for (i = 0; i < CS_MANUID_LEN; i++) + seq_printf(s, "%02x ", buf[i]); + seq_printf(s, "\n"); + + cs_i2c_read(cd, IIC_MODULE_ID, buf, CS_MODULEID_LEN); + seq_printf(s, "Module ID:"); + for (i = 0; i < CS_MODULEID_LEN; i++) + seq_printf(s, "%02x ", buf[i]); + seq_printf(s, "\n"); + + cs_i2c_read(cd, IIC_FW_VER, buf, CS_FWID_LEN); + seq_printf(s, "Fw ID:"); + for (i = 0; i < CS_FWID_LEN; i++) + seq_printf(s, "%02x ", buf[i]); + seq_printf(s, "\n"); + + cs_i2c_read(cd, IIC_WORK_MODE, buf, 1); + seq_printf(s, "WORK MODE:"); + for (i = 0; i < 1; i++) + seq_printf(s, "%02x ", buf[i]); + seq_printf(s, "\n"); + + mutex_unlock(&cd->mutex); + enable_irq(cd->irq); + + return 0; +} + +static int fw_info_open(struct inode *inode, struct file *file) +{ + return single_open(file, fw_info_read_func, PDE_DATA(inode)); +} + +static const struct file_operations proc_fw_info_ops = +{ + .owner = THIS_MODULE, + .read = seq_read, + .open = fw_info_open, + .release = single_release, +}; + +static int rawdata_read_func(struct seq_file *s, void *v) +{ + char reg_addr = 0; + char reg_data[32] = {0}; + int i = 0,len = 0; + int16_t raw_data = 0; + struct cs_device *cd = s->private; + + if (!cd) + return 0; + + disable_irq(cd->irq); + mutex_lock(&cd->mutex); + + wake_up_fw(cd); + + reg_addr = 0x80; + len = 1; + reg_data[0] = 0x10; + if (cs_i2c_write(cd, reg_addr, reg_data, len) <= 0) { + CS_LOG("reg=0x%02x,data=0x%02x,count=%d,err\n", reg_addr, reg_data[0], len); + } + + reg_addr = 0x81; + len = 1; + reg_data[0] = 0x0; + if (cs_i2c_write(cd, reg_addr, reg_data, len) <= 0) { + CS_LOG("reg=0x%02x,data=0x%02x,count=%d,err\n", reg_addr, reg_data[0], len); + } + i=50; + do { + reg_addr = 0x81; + len = 1; + reg_data[0] = 0x0; + if (cs_i2c_read(cd, reg_addr, reg_data, len) <= 0) { + CS_LOG("reg=0x%02x,d0=0x%02x,count=%d,err\n", reg_addr, reg_data[0], len); + } + len = reg_data[0]; + if (len != 0) { + reg_addr = 0x82; + if (cs_i2c_read(cd, reg_addr, reg_data, len) <= 0) { + CS_LOG("reg=0x%02x,d0=0x%02x,d1=0x%02x,count=%d\n", reg_addr, reg_data[0], reg_data[1], len); + } + } else { + msleep(5); + } + i--; + } while(len == 0 && i > 0); + + if (len == 0) { + seq_printf(s, "read rawdata length is zero.\n"); + } + + for (i = 0; i < len/2; i++) { + raw_data = ((reg_data[i*2] & 0xff) | ((reg_data[i*2 + 1] & 0xff) << 8)); + seq_printf(s, "rawdata[%d]: %d\n", i, raw_data); + } + + reg_addr = 0x80; + len = 1; + reg_data[0] = 0x00; + cs_i2c_write(cd, reg_addr, reg_data, len); + + mutex_unlock(&cd->mutex); + enable_irq(cd->irq); + + return 0; +} + +static int rawdata_open(struct inode *inode, struct file *file) +{ + return single_open(file, rawdata_read_func, PDE_DATA(inode)); +} + +static const struct file_operations proc_rawdata_ops = +{ + .owner = THIS_MODULE, + .read = seq_read, + .open = rawdata_open, + .release = single_release, +}; + +static int diffdata_read_func(struct seq_file *s, void *v) +{ + char reg_addr = 0; + char reg_data[64] = {0}; + int i = 0,len = 0; + int16_t diff_data = 0; + struct cs_device *cd = s->private; + + if (!cd) + return 0; + + disable_irq(cd->irq); + mutex_lock(&cd->mutex); + + wake_up_fw(cd); + + reg_addr = 0x80; + len = 1; + reg_data[0] = 0x20; + if (cs_i2c_write(cd, reg_addr, reg_data, len) <= 0) { + CS_LOG("reg=0x%02x,data=0x%02x,count=%d,err\n", reg_addr, reg_data[0], len); + } + + reg_addr = 0x81; + len = 1; + reg_data[0] = 0x0; + if (cs_i2c_write(cd, reg_addr, reg_data, len) <= 0) { + CS_LOG("reg=0x%02x,data=0x%02x,count=%d,err\n", reg_addr, reg_data[0], len); + } + i=50; + do { + reg_addr = 0x81; + len = 1; + reg_data[0] = 0x0; + if (cs_i2c_read(cd, reg_addr, reg_data, len) <= 0) { + CS_LOG("reg=0x%02x,d0=0x%02x,count=%d,err\n", reg_addr, reg_data[0], len); + } + len = reg_data[0]; + if (len != 0) { + reg_addr = 0x82; + if (cs_i2c_read(cd, reg_addr, reg_data, len) <= 0) { + CS_LOG("reg=0x%02x,d0=0x%02x,d1=0x%02x,count=%d\n", reg_addr, reg_data[0], reg_data[1], len); + } + } else { + msleep(5); + } + i--; + } while(len == 0 && i > 0); + + if (len == 0) { + seq_printf(s, "read diffdata length is zero.\n"); + } + + for (i = 0; i < len/2; i++) { + diff_data = ((reg_data[i*2] & 0xff) | ((reg_data[i*2 + 1] & 0xff) << 8)); + seq_printf(s, "diffdata[%d]: %d\n", i, diff_data); + } + + reg_addr = 0x80; + len = 1; + reg_data[0] = 0x00; + cs_i2c_write(cd, reg_addr, reg_data, len); + + mutex_unlock(&cd->mutex); + enable_irq(cd->irq); + + return 0; +} + +static int diffdata_open(struct inode *inode, struct file *file) +{ + return single_open(file, diffdata_read_func, PDE_DATA(inode)); +} + +static const struct file_operations proc_diffdata_ops = +{ + .owner = THIS_MODULE, + .read = seq_read, + .open = diffdata_open, + .release = single_release, +}; + +static ssize_t proc_debug_th_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) +{ + char buf[128]; + int ret = 0, channel = 0, touch_th = 0, leave_th = 0; + struct cs_device *cd = PDE_DATA(file_inode(file)); + + if (!cd) + return count; + + sscanf(buf, "%d,%d,%d", &channel, &touch_th, &leave_th); + mutex_lock(&cd->mutex); + ret = get_press_threshold(cd, &touch_th, &leave_th, channel); + if (ret < 0) { + CS_LOG("%s: get pressure failed.\n", __func__); + } + mutex_unlock(&cd->mutex); + + sprintf(buf, "touch_th: %d, leave_th: %d\n", touch_th, leave_th); + ret = simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf)); + return ret; +} + +static ssize_t proc_debug_th_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) +{ + char buf[64]; + int ret = 0, channel = 0, touch_th = 0, leave_th = 0; + struct cs_device *cd = PDE_DATA(file_inode(file)); + + if (!cd) + return count; + + if (!buffer || count <= 0) { + CS_LOG("%s, argument err.\n", __func__); + return count; + } + + if (copy_from_user(buf, buffer, count)) { + CS_LOG("%s: read proc input error.\n", __func__); + return count; + } + + sscanf(buf, "%d,%d,%d", &channel, &touch_th, &leave_th); + mutex_lock(&cd->mutex); + ret = set_press_threshold(cd, touch_th, leave_th, channel); + mutex_unlock(&cd->mutex); + + return ret < 0 ? ret : count; +} + +static const struct file_operations proc_debug_th_ops = +{ + .read = proc_debug_th_read, + .write = proc_debug_th_write, + .open = simple_open, + .owner = THIS_MODULE, +}; + +static ssize_t proc_report_switch_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) +{ + char buf[64]; + int val = 0; + struct cs_device *cd = PDE_DATA(file_inode(file)); + + if (!cd) + return count; + + if (!buffer || count <= 0) { + CS_LOG("%s, argument err.\n", __func__); + return count; + } + + if (copy_from_user(buf, buffer, count)) { + CS_LOG("%s: read proc input error.\n", __func__); + return count; + } + + sscanf(buf, "%d", &val); + CS_LOG("%s: set mode %d.\n", __func__, val); + + mutex_lock(&cd->mutex); + if (val == cd->report_mode) { + mutex_unlock(&cd->mutex); + return count; + } + if (MODE_SLEEP_IN == val) { + disable_irq(cd->irq); + cs_mode_switch(cd, 3); + } else if (MODE_SLEEP_IN == cd->report_mode) { + cs_mode_switch(cd, 0); + enable_irq(cd->irq); + } + cd->report_mode = val; //set report mode + mutex_unlock(&cd->mutex); + + return count; +} + +static ssize_t proc_report_switch_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) +{ + char buf[16]; + int ret = 0; + struct cs_device *cd = PDE_DATA(file_inode(file)); + + if (!cd) + return count; + + sprintf(buf, "%d\n", cd->report_mode); + ret = simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf)); + return ret; +} + +static const struct file_operations proc_report_switch_ops = +{ + .read = proc_report_switch_read, + .write = proc_report_switch_write, + .open = simple_open, + .owner = THIS_MODULE, +}; + +static ssize_t proc_coordinate_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) +{ + char buf[64]; + int val_x = 0, val_y = 0; + struct cs_device *cd = PDE_DATA(file_inode(file)); + + if (!cd) + return count; + + if (!buffer || count <= 0) { + CS_LOG("%s, argument err.\n", __func__); + return count; + } + + if (copy_from_user(buf, buffer, count)) { + CS_LOG("%s: read proc input error.\n", __func__); + return count; + } + + sscanf(buf, "%d,%d", &val_x, &val_y); + CS_LOG("%s, set x:%d, y:%d.\n", __func__, val_x, val_y); + + mutex_lock(&cd->mutex); + cd->current_point.x = val_x; + cd->current_point.y = val_y; + mutex_unlock(&cd->mutex); + + return count; +} + +static ssize_t proc_coordinate_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) +{ + char buf[16]; + int ret = 0; + struct cs_device *cd = PDE_DATA(file_inode(file)); + + if (!cd) + return count; + + sprintf(buf, "x:%d, y:%d\n", cd->current_point.x, cd->current_point.y); + ret = simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf)); + return ret; +} + +static const struct file_operations proc_coordinate_ops = +{ + .read = proc_coordinate_read, + .write = proc_coordinate_write, + .open = simple_open, + .owner = THIS_MODULE, +}; + +static int cs_init_proc(struct cs_device *cd) +{ + int ret = 0; + struct proc_dir_entry *ptr_cs = NULL, *ptr_tmp = NULL; + + ptr_cs = proc_mkdir("press", NULL); + if (ptr_cs == NULL) { + CS_LOG("%s: Couldn't create cs proc entry\n", __func__); + return -ENOMEM; + } + + ptr_tmp = proc_create_data("fw_update", 0666, ptr_cs, &proc_fw_update_ops, cd); + if (ptr_tmp == NULL) { + ret = -ENOMEM; + CS_LOG("%s: Couldn't create proc entry, %d\n", __func__, __LINE__); + } + + ptr_tmp = proc_create_data("fw_info", 0444, ptr_cs, &proc_fw_info_ops, cd); + if (ptr_tmp == NULL) { + ret = -ENOMEM; + CS_LOG("%s: Couldn't create proc entry, %d\n", __func__, __LINE__); + } + + ptr_tmp = proc_create_data("rawdata", 0444, ptr_cs, &proc_rawdata_ops, cd); + if (ptr_tmp == NULL) { + ret = -ENOMEM; + CS_LOG("%s: Couldn't create proc entry, %d\n", __func__, __LINE__); + } + + ptr_tmp = proc_create_data("diffdata", 0444, ptr_cs, &proc_diffdata_ops, cd); + if (ptr_tmp == NULL) { + ret = -ENOMEM; + CS_LOG("%s: Couldn't create proc entry, %d\n", __func__, __LINE__); + } + + ptr_tmp = proc_create_data("press_thd", 0666, ptr_cs, &proc_debug_th_ops, cd); + if (ptr_tmp == NULL) { + ret = -ENOMEM; + CS_LOG("%s: Couldn't create proc entry, %d\n", __func__, __LINE__); + } + + ptr_tmp = proc_create_data("report_mode", 0666, ptr_cs, &proc_report_switch_ops, cd); + if (ptr_tmp == NULL) { + ret = -ENOMEM; + CS_LOG("%s: Couldn't create proc entry, %d\n", __func__, __LINE__); + } + + ptr_tmp = proc_create_data("touch_coordinate", 0666, ptr_cs, &proc_coordinate_ops, cd); + if (ptr_tmp == NULL) { + ret = -ENOMEM; + CS_LOG("%s: Couldn't create proc entry, %d\n", __func__, __LINE__); + } + + CS_LOG("%s: init proc file %s.\n", __func__, ret == 0 ? "susccess" : "failed"); + return ret; +} + +static int cs_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ + int ret = 0; + struct cs_device *cd = NULL; + + CS_LOG(" %s start.\n", __func__); + + //1. malloc mem for cs device + cd = kzalloc(sizeof(struct cs_device), GFP_KERNEL); + if (!cd) { + CS_LOG("malloc space for cs device failed.\n"); + return -ENOMEM; + } + memset(cd, 0, sizeof(*cd)); + + //2. init cs device member + cd->client = client; + cd->irq = client->irq; + cd->dev = &client->dev; + mutex_init(&cd->mutex); + mutex_init(&cd->i2c_mutex); + i2c_set_clientdata(client, cd); + + //3. parse dts + cs_parse_dt(cd); + + //4. power on + ret = cs_power_control(cd, true); + if (ret) { + ret= -1; + goto power_on_failed; + } + + //5. init input device + ret = init_input_device(cd); + if (ret) { + goto input_register_failed; + } + + //6. ic fw check + ret = cs_i2c_check(cd); + if (ret) { + CS_LOG("fw check failed, need do force update\n"); + goto irq_register_failed; + } + + //7. register irq handler + ret = request_threaded_irq(cd->irq, NULL, cs_irq_thread_func, + cd->irq_flag | IRQF_ONESHOT, CS_CHRDEV_NAME, cd); + if (ret) { + CS_LOG("requst irq failed:%d\n", ret); + goto irq_register_failed; + } + + //8. register misc device + cd->cs_misc.minor = MISC_DYNAMIC_MINOR; + cd->cs_misc.name = "ndt"; + cd->cs_misc.fops = &cs_fops; + misc_register(&cd->cs_misc); + + //9. create proc file + cs_init_proc(cd); + + CS_LOG(" %s normal end.\n", __func__); + return 0; + +irq_register_failed: + input_unregister_device(cd->input_dev); + cd->input_dev = NULL; +input_register_failed: + cs_power_control(cd, false); +power_on_failed: + if (!IS_ERR_OR_NULL(cd->vdd_2v8)) { + regulator_put(cd->vdd_2v8); + cd->vdd_2v8 = NULL; + } + + if (gpio_is_valid(cd->irq_gpio)) { + gpio_free(cd->irq_gpio); + } + + if (gpio_is_valid(cd->reset_gpio)) { + gpio_free(cd->reset_gpio); + } + + if (cd) { + kfree(cd); + cd = NULL; + } + + return ret; + +} + +static int cs_remove(struct i2c_client *client) +{ + struct cs_device *cd = i2c_get_clientdata(client); + + i2c_unregister_device(client); + misc_deregister(&cd->cs_misc); + kfree(cd); + + return 0; +} + +static int cs_suspend(struct device *device) +{ + struct cs_device *cd = dev_get_drvdata(device); + + disable_irq(cd->irq); + cs_mode_switch(cd, 3); + return 0; +} + +static int cs_resume(struct device *device) +{ + struct cs_device *cd = dev_get_drvdata(device); + + cs_mode_switch(cd, 0); + enable_irq(cd->irq); + return 0; +} + +static const struct dev_pm_ops cs_pm_ops = { + .suspend = cs_suspend, + .resume = cs_resume, +}; + +static const struct i2c_device_id cs_id_table[] = { + {CS_CHRDEV_NAME, 0}, + {}, +}; + +static struct of_device_id cs_match_table[] = { + { .compatible = "qcom,cs_press", }, + {}, +}; +MODULE_DEVICE_TABLE(i2c, cs_id_table); + +static struct i2c_driver cs_driver = { + .id_table = cs_id_table, + .probe = cs_probe, + .remove = cs_remove, + .driver = { + .owner = THIS_MODULE, + .name = CS_CHRDEV_NAME, + .of_match_table = cs_match_table, + .pm = &cs_pm_ops, + }, +}; + +static int __init cs_init(void) +{ + int ret = 0; + + CS_LOG(" %s start.\n", __func__); + ret = i2c_add_driver(&cs_driver); + if (ret < 0) { + CS_LOG("i2c_add_driver fail,status=%d\n", ret); + } + + return 0; +} + +static void __exit cs_exit(void) +{ + i2c_del_driver(&cs_driver); +} + +module_init(cs_init); +module_exit(cs_exit); + +MODULE_AUTHOR("ChipSea, Inc."); +MODULE_DESCRIPTION("cs press Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/misc/cs_press/cs_press_f61.h b/drivers/misc/cs_press/cs_press_f61.h new file mode 100644 index 000000000000..5c67947ce615 --- /dev/null +++ b/drivers/misc/cs_press/cs_press_f61.h @@ -0,0 +1,76 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2018-2020 Oplus. All rights reserved. + */ + +#ifndef _CS_PRESS_H +#define _CS_PRESS_H + + +/*IIC REG*/ +#define IIC_EEPROM 0x00 +#define IIC_DEV_ID 0x02 +#define IIC_MANU_ID 0x03 +#define IIC_MODULE_ID 0x04 +#define IIC_FW_VER 0x05 +#define IIC_WAKE_UP 0x06 +#define IIC_SLEEP 0x07 +#define IIC_GREEN 0x08 +#define IIC_GREEN2NORMAL 0x10 +#define IIC_HOSTSTATUS 0x50 +#define IIC_DEBUG_MODE 0x60 +#define IIC_DATA_READY 0x61 +#define IIC_DEBUG_DATA1 0x62 +#define IIC_DEBUG_DATA2 0x63 +#define IIC_DEBUG_DATA3 0x64 +#define IIC_DEBUG_DATA4 0x65 +#define IIC_KEY_SEN 0xD0 +#define IIC_KEY_STATUS 0xD3 +#define IIC_DOWN_THD 0x90 +#define IIC_UP_THD 0x91 +#define IIC_WORK_MODE 0x99 + +#define IIC_RESETCMD 0xf17c + +#define CS_DEVID_LEN 0xA /* device id length */ +#define CS_MANUID_LEN 0x2 /* manufacture id length */ +#define CS_MODULEID_LEN 0x2 /* module id length */ +#define CS_FWID_LEN 0x2 /* firmware image length */ +#define CS_FW_LENPOS 0x0c +#define CS_FW_VERPOS 0x08 +#define CS_FW_STARTPOS 0x100 + +#define IIC_MAX_TRSANFER 5 + +enum mode { + MODE_REPORT_KEY, + MODE_REPORT_TOUCH, + MODE_SLEEP_IN = 10, + MODE_REPORT_POWER = 100, + MODE_REPORT_HOME = 101, + MODE_REPORT_BACK = 102, +}; + +struct point { + uint16_t x; + uint16_t y; +}; + +struct cs_device { + int irq; //press irq number + uint32_t irq_flag; //irq trigger flasg + int irq_gpio; //irq gpio num + int reset_gpio; //Reset gpio + bool force_update; //set to 1 when fw check failed + struct regulator *vdd_2v8; //press power + struct i2c_client *client; //i2c client + struct device *dev; //the device structure + struct mutex mutex; //mutex for control operate flow + struct mutex i2c_mutex; //mutex for control i2c opearation + struct input_dev *input_dev; //input device for report event + struct miscdevice cs_misc; //misc device + int report_mode; //shows which event should report + struct point current_point; //point this key want to report +}; + +#endif/*_CS_PRESS_H*/ diff --git a/drivers/misc/oem_qmi_client.c b/drivers/misc/oem_qmi_client.c new file mode 120000 index 000000000000..349e94978dc5 --- /dev/null +++ b/drivers/misc/oem_qmi_client.c @@ -0,0 +1 @@ +../../../../vendor/oplus/kernel/misc/oem_qmi_client.c \ No newline at end of file diff --git a/drivers/misc/op_ant_detect.c b/drivers/misc/op_ant_detect.c new file mode 100644 index 000000000000..1e3c7061083d --- /dev/null +++ b/drivers/misc/op_ant_detect.c @@ -0,0 +1,361 @@ +/*For OEM project monitor RF cable connection status, + * and config different RF configuration + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define RF_CABLE_STATE_ACTIVE "oem_rf_cable_active" + +static struct class *rf_uevent_class; +static struct device *rf_uevent_device; + +#define CABLE_GPIO_NUM 5 +#define PAGESIZE 512 +struct cable_data { + int irq[CABLE_GPIO_NUM]; + int cable_gpio[CABLE_GPIO_NUM]; + int support_timer; + int gpio_num; + struct delayed_work work; + struct workqueue_struct *wqueue; + struct device *dev; + int rf_state; + int rf_state_pre; + spinlock_t lock; + int enable; + int is_rf_factory_mode; + int gpio_state; + struct pinctrl *gpio_pinctrl; + struct pinctrl_state *gpio_pinctrl_active; + struct pinctrl_state *gpio_pinctrl_suspend; + bool connected; + bool uevent_feature; +}; +static struct cable_data *rf_cable_data; + +int local_pow(int x,int y) +{ + int i = 0; + int val = 1; + for(i = 0; i< y; i++) { + val = val*x; + } + return val; +} + +int get_all_gpio_val(void) +{ + int i = 0; + int gpiostate = 0; + for (i = 0; i < rf_cable_data->gpio_num; i++) { + gpiostate = gpiostate + (gpio_get_value(rf_cable_data->cable_gpio[i]) *local_pow(10, rf_cable_data->gpio_num - i - 1)); + } + return gpiostate; +} + +static void irq_cable_enable(int enable) +{ + unsigned long flags; + int i = 0; + if (!rf_cable_data->support_timer) { + spin_lock_irqsave(&rf_cable_data->lock, flags); + if (enable) { + for (i = 0; i < rf_cable_data->gpio_num; i++) + enable_irq(rf_cable_data->irq[i]); + } else { + for (i = 0; i < rf_cable_data->gpio_num; i++) + disable_irq_nosync(rf_cable_data->irq[i]); + } + spin_unlock_irqrestore(&rf_cable_data->lock, flags); + } +} + +static void cable_connect_state(int enable) +{ + char *connected[2] = { "CABLE_STATE=CONNECTED", NULL }; + char *disconnected[2] = { "CABLE_STATE=DISCONNECTED", NULL }; + + if (rf_cable_data->uevent_feature) { + if (enable) { + kobject_uevent_env(&rf_uevent_device->kobj, KOBJ_CHANGE, connected); + rf_cable_data->connected = true; + pr_err("%s: sent uevent %s\n", __func__, connected[0]); + } else { + kobject_uevent_env(&rf_uevent_device->kobj, KOBJ_CHANGE, disconnected); + pr_err("%s: sent uevent %s\n", __func__, disconnected[0]); + rf_cable_data->connected = false; + } + } +} +static void rc_cable_state_change(int state,int restart) +{ + cable_connect_state(state); +} + +static void rf_cable_work(struct work_struct *work) +{ + int current_gpio_state = 0; + + irq_cable_enable(0); + current_gpio_state = get_all_gpio_val(); + + pr_err("%s rf_state_pre=%d, rf_state=%d gpio=%2d,\n", __func__, rf_cable_data->rf_state_pre, rf_cable_data->rf_state, current_gpio_state); + + if (rf_cable_data->gpio_state != current_gpio_state) { + pr_err("%s gpio_state=%d, current_gpio_state=%d ignore\n", __func__, rf_cable_data->gpio_state, current_gpio_state); + goto out; + } + + rf_cable_data->rf_state = current_gpio_state; + + if (rf_cable_data->rf_state != rf_cable_data->rf_state_pre) { + rc_cable_state_change(rf_cable_data->rf_state,1); + } + rf_cable_data->rf_state_pre =current_gpio_state; + +out: + irq_cable_enable(1); + + if (rf_cable_data->support_timer) { + queue_delayed_work(rf_cable_data->wqueue, &rf_cable_data->work, msecs_to_jiffies(2*HZ)); + } +} + +irqreturn_t cable_interrupt(int irq, void *_dev) +{ + rf_cable_data->gpio_state = get_all_gpio_val(); + + queue_delayed_work(rf_cable_data->wqueue, &rf_cable_data->work, msecs_to_jiffies(500)); + return IRQ_HANDLED; +} + +static ssize_t cable_read_proc(struct file *file, char __user *buf, size_t count, loff_t *off) +{ + char page[PAGESIZE]; + int len; + + len = scnprintf(page, sizeof(page), "%d\n", rf_cable_data->rf_state); + return simple_read_from_buffer(buf, count, off, page, len); +} + + +static struct file_operations cable_proc_fops_cable = { + .read = cable_read_proc, +}; + +int create_rf_cable_procfs(void) +{ + int ret = 0; + struct proc_dir_entry *oplus_rf = NULL; + + oplus_rf = proc_mkdir("oplus_rf", NULL); + if (!oplus_rf) { + pr_err("can't create oplus_rf proc.\n"); + ret = -1; + } + + proc_create_data("rf_cable", S_IRUGO, oplus_rf, &cable_proc_fops_cable, rf_cable_data); + + return ret; +} + +static int op_rf_request_named_gpio(const char *label, int *gpio) +{ + struct device *dev = rf_cable_data->dev; + struct device_node *np = dev->of_node; + int rc = of_get_named_gpio(np, label, 0); + + if (rc < 0) { + dev_err(dev, "failed to get '%s'\n", label); + *gpio = rc; + return rc; + } + *gpio = rc; + rc = devm_gpio_request(dev, *gpio, label); + if (rc) { + dev_err(dev, "failed to request gpio %d, rc=%d\n", *gpio, rc); + return rc; + } + dev_info(dev, "%s - gpio: %d\n", label, *gpio); + return 0; +} +static int rf_cable_gpio_pinctrl_init(struct platform_device *pdev) +{ + int retval; + + dev_dbg(&pdev->dev, "%s\n", __func__); + + rf_cable_data->gpio_pinctrl = devm_pinctrl_get(&(pdev->dev)); + if (IS_ERR_OR_NULL(rf_cable_data->gpio_pinctrl)) { + retval = PTR_ERR(rf_cable_data->gpio_pinctrl); + dev_dbg(&pdev->dev, "Target does not use pinctrl %d\n", retval); + goto err_pinctrl_get; + } + + rf_cable_data->gpio_pinctrl_active = pinctrl_lookup_state(rf_cable_data->gpio_pinctrl, RF_CABLE_STATE_ACTIVE); + if (IS_ERR_OR_NULL(rf_cable_data->gpio_pinctrl_active)) { + retval = PTR_ERR(rf_cable_data->gpio_pinctrl_active); + dev_err(&pdev->dev, "Can not lookup %s pinstate %d\n", RF_CABLE_STATE_ACTIVE, retval); + goto err_pinctrl_lookup; + } + + if (rf_cable_data->gpio_pinctrl) { + retval = pinctrl_select_state(rf_cable_data->gpio_pinctrl, rf_cable_data->gpio_pinctrl_active); + if (retval < 0) { + dev_err(&pdev->dev, "failed to select pin to active state"); + } + } + + return 0; + + err_pinctrl_lookup:devm_pinctrl_put(rf_cable_data->gpio_pinctrl); + err_pinctrl_get:rf_cable_data->gpio_pinctrl = NULL; + return retval; +} + +static int op_rf_cable_probe(struct platform_device *pdev) +{ + int rc = 0; + struct device *dev = &pdev->dev; + int cable_state = 0; + int i; + + rf_cable_data = kzalloc(sizeof(struct cable_data), GFP_KERNEL); + if (!rf_cable_data) + goto exit; + + rf_cable_data->dev = dev; + dev_set_drvdata(dev, rf_cable_data); + + rf_cable_data->uevent_feature = of_property_read_bool(pdev->dev.of_node, "oem,rf_uevent_feature_enable"); + + rc = of_property_read_u32(pdev->dev.of_node, "rf,cable-support-timer", &rf_cable_data->support_timer); + if (rc) { + pr_err("%s: cable-support-timer fail\n", __func__); + goto exit_gpio; + } + + rc = of_property_read_u32(pdev->dev.of_node, "rf,cable-gpio-num", &rf_cable_data->gpio_num); + if (rc) { + pr_err("%s: cable-gpio-num\n", __func__); + goto exit_gpio; + } + + rf_cable_gpio_pinctrl_init(pdev); + + rf_cable_data->wqueue = create_singlethread_workqueue("op_rf_cable_wqueue"); + INIT_DELAYED_WORK(&rf_cable_data->work, rf_cable_work); + + if (rf_cable_data->support_timer) + queue_delayed_work(rf_cable_data->wqueue, &rf_cable_data->work, msecs_to_jiffies(HZ)); + + pr_err("cable uevent init\n"); + rf_uevent_class = class_create(THIS_MODULE, "sdx5x_rf_cable"); + if (IS_ERR(rf_uevent_class)) { + pr_err("%s: class_create fail - %d!\n", __func__, PTR_ERR(rf_uevent_class)); + return PTR_ERR(rf_uevent_class); + } + + rf_uevent_device = device_create(rf_uevent_class, rf_cable_data->dev, MKDEV(0, 0), NULL, "rf_cable"); + if (IS_ERR(rf_uevent_device)) { + pr_err("%s: rf_uevent_device fail - %d!\n", __func__, PTR_ERR(rf_uevent_device)); + return PTR_ERR(rf_uevent_device); + } + + spin_lock_init(&rf_cable_data->lock); + + for (i = 0; i < rf_cable_data->gpio_num; i++) { + + char cable[PAGESIZE]; + memset(cable, 0, sizeof(cable)); + scnprintf(cable, sizeof(cable), "rf,cable-gpio-%d", i); + + rc = op_rf_request_named_gpio(cable, &rf_cable_data->cable_gpio[i]); + if (rc) { + pr_err("%s: op_rf_request_named_gpio gpio-%d fail\n", __func__, i); + goto exit_gpio; + } + gpio_direction_input(rf_cable_data->cable_gpio[i]); + + rf_cable_data->irq[i] = gpio_to_irq(rf_cable_data->cable_gpio[i]); + if (rf_cable_data->irq[i] < 0) { + pr_err("Unable to get irq number for GPIO %d, error %d\n", rf_cable_data->cable_gpio[i], rf_cable_data->irq[i]); + rc = rf_cable_data->irq[i]; + goto exit_gpio; + } + rc = request_irq(rf_cable_data->irq[i], cable_interrupt, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, "rf,cable-gpio", rf_cable_data); + if (rc) { + pr_err("could not request irq %d\n", rf_cable_data->irq[i]); + goto exit_gpio; + } + pr_err("requested irq %d\n", rf_cable_data->irq[i]); + enable_irq_wake(rf_cable_data->irq[i]); + } + create_rf_cable_procfs(); + cable_state = get_all_gpio_val(); + rf_cable_data->rf_state = cable_state; + pr_err("%s gpio=%d ,\n", __func__, cable_state); + rc_cable_state_change(cable_state,0); + pr_err("%s: probe success!\n", __func__); + return 0; + +exit_gpio: + kfree(rf_cable_data); +exit: + pr_err("%s: probe Fail!\n", __func__); + + return rc; +} + +static const struct of_device_id rf_of_match[] = { + { .compatible = "oem,rf_cable", }, + {} +}; +MODULE_DEVICE_TABLE(of, rf_of_match); + +static struct platform_driver op_rf_cable_driver = { + .driver = { + .name = "op_rf_cable", + .owner = THIS_MODULE, + .of_match_table = rf_of_match, + }, + .probe = op_rf_cable_probe, +}; + +static int __init op_rf_cable_init(void) +{ + int ret; + + pr_info("%s: enter\n", __func__); + ret = platform_driver_register(&op_rf_cable_driver); + if (ret) + pr_err("rf_cable_driver register failed: %d\n", ret); + + return ret; +} + +MODULE_LICENSE("GPL v2"); +late_initcall(op_rf_cable_init); + diff --git a/drivers/misc/oplus_rf_cable_monitor.c b/drivers/misc/oplus_rf_cable_monitor.c new file mode 120000 index 000000000000..ef3e39232f1c --- /dev/null +++ b/drivers/misc/oplus_rf_cable_monitor.c @@ -0,0 +1 @@ +../../../../vendor/oplus/kernel/misc/oplus_rf_cable_monitor.c \ No newline at end of file diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c index 5d35f4be132e..f34b4c186a2b 100644 --- a/drivers/misc/qseecom.c +++ b/drivers/misc/qseecom.c @@ -2624,6 +2624,14 @@ err_resp: case QSEOS_RESULT_CBACK_REQUEST: pr_warn("get cback req app_id = %d, resp->data = %d\n", data->client.app_id, resp->data); +//#ifdef OPLUS_BUG_COMPATIBILITY + //resp->resp_type = SMCINVOKE_RESULT_INBOUND_REQ_NEEDED; + /* We are here because scm call sent to TZ has requested + * for another callback request. This call has been a + * success and hence setting result = 0 + */ + //resp->result = 0; +//#endif /* OPLUS_BUG_COMPATIBILITY */ break; default: pr_err("fail:resp res= %d,app_id = %d,lstr = %d\n", @@ -5367,8 +5375,10 @@ int qseecom_process_listener_from_smcinvoke(struct scm_desc *desc) pr_err("Failed on cmd %d for lsnr %d session %d, ret = %d\n", (int)desc->ret[0], (int)desc->ret[2], (int)desc->ret[1], ret); +//#ifdef OPLUS_BUG_COMPATIBILITY desc->ret[0] = resp.result; desc->ret[1] = resp.resp_type; +//#endif /* OPLUS_BUG_COMPATIBILITY */ desc->ret[2] = resp.data; return ret; } diff --git a/drivers/misc/sim_detect.c b/drivers/misc/sim_detect.c new file mode 120000 index 000000000000..4c7ee34bba97 --- /dev/null +++ b/drivers/misc/sim_detect.c @@ -0,0 +1 @@ +../../../../vendor/oplus/kernel/misc/sim_detect.c \ No newline at end of file diff --git a/drivers/misc/tri_state_key/Kconfig b/drivers/misc/tri_state_key/Kconfig new file mode 100644 index 000000000000..a7cd38c5878f --- /dev/null +++ b/drivers/misc/tri_state_key/Kconfig @@ -0,0 +1,20 @@ +config OPLUS_TRIKEY_HALL + tristate "hall ic support" + default n + help + Say Y here if you want to enable the feature. + +config OPLUS_TRIKEY_MAIN + tristate "tri state key support" + default n + help + Say Y here if you want to enable the feature. + +config OPLUS_TRI_STATE_KEY + tristate "oplus tri state key support" + default n + help + Say Y here if you want to enable the feature. + +source "drivers/misc/tri_state_key/ist_hall_ic/Kconfig" +source "drivers/misc/tri_state_key/hall_ic/Kconfig" diff --git a/drivers/misc/tri_state_key/Makefile b/drivers/misc/tri_state_key/Makefile new file mode 100644 index 000000000000..a011c9f4a16b --- /dev/null +++ b/drivers/misc/tri_state_key/Makefile @@ -0,0 +1,5 @@ +obj-$(CONFIG_OPLUS_TRIKEY_HALL) += ist_hall_ic/ +obj-$(CONFIG_OPLUS_TRIKEY_HALL) += hall_ic/ +oplus_bsp_tri_key-y += oplus_tri_key.o +obj-$(CONFIG_OPLUS_TRIKEY_MAIN) += oplus_bsp_tri_key.o +obj-$(CONFIG_OPLUS_TRI_STATE_KEY) += tri_state_key.o \ No newline at end of file diff --git a/drivers/misc/tri_state_key/hall_ic/Kconfig b/drivers/misc/tri_state_key/hall_ic/Kconfig new file mode 100644 index 000000000000..a8daa3c7b3a0 --- /dev/null +++ b/drivers/misc/tri_state_key/hall_ic/Kconfig @@ -0,0 +1,11 @@ +config MXM_UP + tristate "hall up ic support" + default n + help + Say Y here to enable mxm1120 up. + +config MXM_DOWN + tristate "hall down ic support" + default n + help + Say Y here to enable mxm1120 down. diff --git a/drivers/misc/tri_state_key/hall_ic/Makefile b/drivers/misc/tri_state_key/hall_ic/Makefile new file mode 100644 index 000000000000..b9a28d64751c --- /dev/null +++ b/drivers/misc/tri_state_key/hall_ic/Makefile @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# Makefile for the touchscreen drivers. +# + +# Each configuration option enables a list of files. +oplus_bsp_mxm_up-y += hall_mxm1120_up.o +obj-$(CONFIG_MXM_UP) += oplus_bsp_mxm_up.o +oplus_bsp_mxm_down-y += hall_mxm1120_down.o +obj-$(CONFIG_MXM_DOWN) += oplus_bsp_mxm_down.o diff --git a/drivers/misc/tri_state_key/hall_ic/hall_mxm1120.h b/drivers/misc/tri_state_key/hall_ic/hall_mxm1120.h new file mode 100644 index 000000000000..24b821709e55 --- /dev/null +++ b/drivers/misc/tri_state_key/hall_ic/hall_mxm1120.h @@ -0,0 +1,319 @@ +/* SPDX-License-Identifier: GPL-2.0-only*/ +/* + * Copyright (C) 2018-2020 Oplus. All rights reserved. + * File: oplus_tri_key.c + * + * Description: + * Definitions for m1120 tri_state_key data process. + * + * Version: 1.0 + */ + +#ifndef __MXM1120_H__ +#define __MXM1120_H__ + +#include +#include + +/* ********************************************************* */ +/* feature of ic revision */ +/* ********************************************************* */ +#define M1120_REV_0_2 (0x02) +#define M1120_REV_1_0 (0x10) +#define M1120_REV M1120_REV_1_0 +#define M1120_DRIVER_VERSION "Ver1.04-140226" +/* ********************************************************* */ + +/* ********************************************************* */ +/* property of driver */ +/* ********************************************************* */ +#define M1120_DRIVER_NAME_UP "hall_m1120_up" +#define M1120_DRIVER_NAME_MIDDLE "m1120_middle" +#define M1120_DRIVER_NAME_DOWN "hall_m1120_down" +#define M1120_IRQ_NAME "m1120-irq" +#define M1120_PATH "/dev/m1120" + +/* + *SAD1 SAD0 == 00 0001100 R/W (7bits)0x0C (8bits)0x18 + *SAD1 SAD0 == 01 0001101 R/W (7bits)0x0D (8bits)0x1A + *SAD1 SAD0 == 10 0001110 R/W (7bits)0x0E (8bits)0x1C + *SAD1 SAD0 == 11 0001111 R/W (7bits)0x0F (8bits)0x1E + */ +#define M1120_SLAVE_ADDR (0x18) +/* ********************************************************* */ + +/* ********************************************************* */ +/* register map */ +/* ********************************************************* */ +#define M1120_REG_PERSINT (0x00) +#define M1120_VAL_PERSINT_COUNT(n) (n<<4) +#define M1120_VAL_PERSINT_INTCLR (0x01) +/* + *[7:4] PERS : interrupt persistence count + *[0] INTCLR = 1 : interrupt clear + */ +/* --------------------------------------------------------- */ +#define M1120_REG_INTSRS (0x01) +#define M1120_VAL_INTSRS_INT_ON (0x80) +#define M1120_DETECTION_MODE_INTERRUPT M1120_VAL_INTSRS_INT_ON +#define M1120_VAL_INTSRS_INT_OFF (0x00) +#define M1120_DETECTION_MODE_POLLING M1120_VAL_INTSRS_INT_OFF +#define M1120_VAL_INTSRS_INTTYPE_BESIDE (0x00) +#define M1120_VAL_INTSRS_INTTYPE_WITHIN (0x10) +#define M1120_VAL_INTSRS_SRS_10BIT_0_068mT (0x00) +#define M1120_VAL_INTSRS_SRS_10BIT_0_034mT (0x01) +#define M1120_VAL_INTSRS_SRS_10BIT_0_017mT (0x02) +#define M1120_VAL_INTSRS_SRS_10BIT_0_009mT (0x03) +#define M1120_VAL_INTSRS_SRS_10BIT_0_004mT (0x04) +#define M1120_VAL_INTSRS_SRS_8BIT_0_272mT (0x00) +#define M1120_VAL_INTSRS_SRS_8BIT_0_136mT (0x01) +#define M1120_VAL_INTSRS_SRS_8BIT_0_068mT (0x02) +#define M1120_VAL_INTSRS_SRS_8BIT_0_036mT (0x03) +#define M1120_VAL_INTSRS_SRS_8BIT_0_016mT (0x04) + +/* + *[7] INTON = 0 : disable interrupt + *[7] INTON = 1 : enable interrupt + *[4] INT_TYP = 0 : generate interrupt when raw data is beside range of threshold + *[4] INT_TYP = 1 : generate interrupt when raw data is within range of threshold + *[2:0] SRS : select sensitivity type when M1120_VAL_OPF_BIT_10 + *000 : 0.068 (mT/LSB) + *001 : 0.034 (mT/LSB) + *010 : 0.017 (mT/LSB) + *011 : 0.009 (mT/LSB) + *100 : 0.004 (mT/LSB) + *101 : 0.017 (mT/LSB) + *110 : 0.017 (mT/LSB) + *111 : 0.017 (mT/LSB) + *[2:0] SRS : select sensitivity type when M1120_VAL_OPF_BIT_8 + *000 : 0.272 (mT/LSB) + *001 : 0.136 (mT/LSB) + *010 : 0.068 (mT/LSB) + *011 : 0.036 (mT/LSB) + *100 : 0.016 (mT/LSB) + *101 : 0.068 (mT/LSB) + *110 : 0.068 (mT/LSB) + *111 : 0.068 (mT/LSB) + */ +/* --------------------------------------------------------- */ +#define M1120_REG_LTHL (0x02) +/* + *[7:0] LTHL : low byte of low threshold value + */ +/* --------------------------------------------------------- */ +#define M1120_REG_LTHH (0x03) +/* + *[7:6] LTHH : high 2bits of low threshold value with sign + */ +/* --------------------------------------------------------- */ +#define M1120_REG_HTHL (0x04) +/* + *[7:0] HTHL : low byte of high threshold value + */ +/* --------------------------------------------------------- */ +#define M1120_REG_HTHH (0x05) +/* + *[7:6] HTHH : high 2bits of high threshold value with sign + */ +/* --------------------------------------------------------- */ +#define M1120_REG_I2CDIS (0x06) +#define M1120_VAL_I2CDISABLE (0x37) +/* + *[7:0] I2CDIS : disable i2c + */ +/* --------------------------------------------------------- */ +#define M1120_REG_SRST (0x07) +#define M1120_VAL_SRST_RESET (0x01) +/* + *[0] SRST = 1 : soft reset + */ +/* --------------------------------------------------------- */ +#define M1120_REG_OPF (0x08) +#define M1120_VAL_OPF_FREQ_20HZ (0x00) +#define M1120_VAL_OPF_FREQ_10HZ (0x10) +#define M1120_VAL_OPF_FREQ_6_7HZ (0x20) +#define M1120_VAL_OPF_FREQ_5HZ (0x30) +#define M1120_VAL_OPF_FREQ_80HZ (0x40) +#define M1120_VAL_OPF_FREQ_40HZ (0x50) +#define M1120_VAL_OPF_FREQ_26_7HZ (0x60) +#define M1120_VAL_OPF_EFRD_ON (0x08) +#define M1120_VAL_OPF_BIT_8 (0x02) +#define M1120_VAL_OPF_BIT_10 (0x00) +#define M1120_VAL_OPF_HSSON_ON (0x01) +#define M1120_VAL_OPF_HSSON_OFF (0x00) +/* + *[6:4] OPF : operation frequency + *000 : 20 (Hz) + *001 : 10 (Hz) + *010 : 6.7 (Hz) + *011 : 5 (Hz) + *100 : 80 (Hz) + *101 : 40 (Hz) + *110 : 26.7 (Hz) + *111 : 20 (Hz) + *[3] EFRD = 0 : keep data without accessing eFuse + *[3] EFRD = 1 : update data after accessing eFuse + *[1] BIT = 0 : 10 bit resolution + *[1] BIT = 1 : 8 bit resolution + *[0] HSSON = 0 : Off power down mode + *[0] HSSON = 1 : On power down mode + */ +/* --------------------------------------------------------- */ +#define M1120_REG_DID (0x09) +#define M1120_VAL_DID (0x9C) +/* + *[7:0] DID : Device ID + */ +/* --------------------------------------------------------- */ +#define M1120_REG_INFO (0x0A) +/* + *[7:0] INFO : Information about IC + */ +/* --------------------------------------------------------- */ +#define M1120_REG_ASA (0x0B) +/* + *[7:0] ASA : Hall Sensor sensitivity adjustment + */ +/* --------------------------------------------------------- */ +#define M1120_REG_ST1 (0x10) +#define M1120_VAL_ST1_DRDY (0x01) +/* + *[4] INTM : status of interrupt mode + *[1] BITM : status of resolution + *[0] DRDY : status of data ready + */ +/* --------------------------------------------------------- */ +#define M1120_REG_HSL (0x11) + +/*[7:0] HSL : low byte of hall sensor measurement data*/ + +/* --------------------------------------------------------- */ +#define M1120_REG_HSH (0x12) + +/*[7:6] HSL : high 2bits of hall sensor measurement data with sign*/ + +/* ********************************************************* */ + + +/* ********************************************************* */ + + +/* ********************************************************* */ +/* ioctl command */ +/* ********************************************************* */ +#define M1120_IOCTL_BASE (0x80) +#define M1120_IOCTL_SET_ENABLE _IOW(M1120_IOCTL_BASE, 0x00, int) +#define M1120_IOCTL_GET_ENABLE _IOR(M1120_IOCTL_BASE, 0x01, int) +#define M1120_IOCTL_SET_DELAY _IOW(M1120_IOCTL_BASE, 0x02, int) +#define M1120_IOCTL_GET_DELAY _IOR(M1120_IOCTL_BASE, 0x03, int) +#define M1120_IOCTL_SET_CALIBRATION _IOW(M1120_IOCTL_BASE, 0x04, int*) +#define M1120_IOCTL_GET_CALIBRATED_DATA _IOR(M1120_IOCTL_BASE, 0x05, int*) +#define M1120_IOCTL_SET_INTERRUPT _IOW(M1120_IOCTL_BASE, 0x06, unsigned int) +#define M1120_IOCTL_GET_INTERRUPT _IOR(M1120_IOCTL_BASE, 0x07, unsigned int*) +#define M1120_IOCTL_SET_THRESHOLD_HIGH _IOW(M1120_IOCTL_BASE, 0x08, unsigned int) +#define M1120_IOCTL_GET_THRESHOLD_HIGH _IOR(M1120_IOCTL_BASE, 0x09, unsigned int*) +#define M1120_IOCTL_SET_THRESHOLD_LOW _IOW(M1120_IOCTL_BASE, 0x0A, unsigned int) +#define M1120_IOCTL_GET_THRESHOLD_LOW _IOR(M1120_IOCTL_BASE, 0x0B, unsigned int*) +#define M1120_IOCTL_SET_REG _IOW(M1120_IOCTL_BASE, 0x0C, int) +#define M1120_IOCTL_GET_REG _IOR(M1120_IOCTL_BASE, 0x0D, int) +/* ********************************************************* */ + + +/* ********************************************************* */ +/* event property */ +/* ********************************************************* */ +#define DEFAULT_EVENT_TYPE EV_ABS +#define DEFAULT_EVENT_CODE ABS_X +#define DEFAULT_EVENT_DATA_CAPABILITY_MIN (-32768) +#define DEFAULT_EVENT_DATA_CAPABILITY_MAX (32767) +/* ********************************************************* */ +/* delay property */ +/* ********************************************************* */ +#define M1120_DELAY_MAX (200) // ms +#define M1120_DELAY_MIN (20) // ms +#define M1120_DELAY_FOR_READY (10) // ms +/* ********************************************************* */ + + +/* ********************************************************* */ +/* data type for driver */ +/* ********************************************************* */ + +enum { + OPERATION_MODE_POWERDOWN_M, + OPERATION_MODE_MEASUREMENT_M, + OPERATION_MODE_FUSEROMACCESS_M +}; + +#define M1120_REG_NUM (15) +union m1120_reg_t { + struct { + unsigned char persint; + unsigned char intsrs; + unsigned char lthl; + unsigned char lthh; + unsigned char hthl; + unsigned char hthh; + unsigned char i2cdis; + unsigned char srst; + unsigned char opf; + unsigned char did; + unsigned char info; + unsigned char asa; + unsigned char st1; + unsigned char hsl; + unsigned char hsh; + } map; + unsigned char array[M1120_REG_NUM]; +}; + +struct m1120_mutex_t { + struct mutex enable; + struct mutex data; +}; + +struct m1120_atomic_t { + atomic_t enable; + atomic_t delay; + atomic_t debug; +}; + +struct m1120_platform_data_t { + int power_vi2c; + int power_vdd; + int interrupt_gpio; + int interrupt_irq; +}; + +struct m1120_data_t { + struct i2c_client *client; + struct input_dev *input_dev; + struct device *dev; + struct m1120_mutex_t mtx; + struct m1120_atomic_t atm; + union m1120_reg_t reg; + bool irq_enabled; + int calibrated_data; + int last_data; + short thrhigh; + short thrlow; + bool irq_first; + + struct delayed_work work; + + int power_vi2c; + int power_vdd; + int igpio; + int int_en; + int irq; + int irq_gpio; + int use_hrtimer; + struct regulator *vdd; + struct regulator *vio; + int power_enabled; + struct wakeup_source source; +}; +/* ************************ */ + +#endif /* __MXM1120_H__ */ + diff --git a/drivers/misc/tri_state_key/hall_ic/hall_mxm1120_down.c b/drivers/misc/tri_state_key/hall_ic/hall_mxm1120_down.c new file mode 100644 index 000000000000..e2174d6a3547 --- /dev/null +++ b/drivers/misc/tri_state_key/hall_ic/hall_mxm1120_down.c @@ -0,0 +1,1066 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2018-2020 Oplus. All rights reserved. + * File: oplus_tri_key.c + * + * Description: + * Definitions for m1120 tri_state_key data process. + * + * Version: 1.0 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "hall_mxm1120.h" +#include "../oplus_tri_key.h" + +#define M1120_DBG_ENABLE +#define M1120_DETECTION_MODE M1120_DETECTION_MODE_INTERRUPT +#define M1120_INTERRUPT_TYPE M1120_VAL_INTSRS_INTTYPE_BESIDE +/*#define M1120_INTERRUPT_TYPE M1120_VAL_INTSRS_INTTYPE_WITHIN*/ +#define M1120_SENSITIVITY_TYPE M1120_VAL_INTSRS_SRS_10BIT_0_068mT +#define M1120_PERSISTENCE_COUNT M1120_VAL_PERSINT_COUNT(15) +#define M1120_OPERATION_FREQUENCY M1120_VAL_OPF_FREQ_80HZ +#define M1120_OPERATION_RESOLUTION M1120_VAL_OPF_BIT_10 +#define M1120_DETECT_RANGE_HIGH (60)/*Need change via test.*/ +#define M1120_DETECT_RANGE_LOW (50)/*Need change via test.*/ +#define M1120_RESULT_STATUS_A (0x01)/*result status A 180Degree*/ +#define M1120_RESULT_STATUS_B (0x02)/*result status B 180Degree*/ +#define M1120_EVENT_TYPE EV_ABS +#define M1120_EVENT_CODE ABS_X +#define M1120_EVENT_DATA_CAPABILITY_MIN (-32768) +#define M1120_EVENT_DATA_CAPABILITY_MAX (32767) + +#define M1120_VDD_MIN_UV 2700000 +#define M1120_VDD_MAX_UV 3600000 +#define M1120_VIO_MIN_UV 1650000 +#define M1120_VIO_MAX_UV 3600000 + +#define HALL_MXM1120_DOWN "oplus,hall-mxm1120,down" + +#define TRI_KEY_TAG "[tri_state_key] " +#define TRI_KEY_ERR(fmt, args...)\ + pr_info(TRI_KEY_TAG" %s : "fmt, __func__, ##args) +#define TRI_KEY_LOG(fmt, args...)\ + pr_info(TRI_KEY_TAG" %s : "fmt, __func__, ##args) + +static struct m1120_data_t *p_m1120_data; + +static DEFINE_MUTEX(hall_m1120_down_i2c_mutex); + +/*i2c interface*/ +static int m1120_i2c_read_block(struct m1120_data_t *m1120_data, u8 addr, u8 *data, u8 len); +static int m1120_i2c_write_block(struct m1120_data_t *m1120_data, u8 addr, u8 *data, u8 len); +static void m1120_short_to_2byte(struct m1120_data_t *m1120_data, short x, u8 *hbyte, u8 *lbyte); +static short m1120_2byte_to_short(struct m1120_data_t *m1120_data, u8 hbyte, u8 lbyte); +/*vdd vid power control*/ +static int m1120_set_power(bool on); + + +static int m1120_get_enable(struct m1120_data_t *p_data); +static void m1120_set_enable(struct m1120_data_t *p_data, int enable); +static void m1120_set_delay(struct m1120_data_t *p_data, int delay); +static void m1120_set_debug(struct m1120_data_t *p_data, int debug); +static int m1120_clear_interrupt(struct m1120_data_t *p_data); +static int m1120_set_operation_mode(struct m1120_data_t *p_data, int mode); +static int m1120_init_device(struct m1120_data_t *p_data); +static int m1120_reset_device(struct m1120_data_t *p_data); +static int m1120_power_ctl(struct m1120_data_t *data, bool on); +static int m1120_get_data(short *data); + +/*functions for i2c interface*/ + +#define M1120_I2C_BUF_SIZE (17) + + +static int m1120_i2c_read_block(struct m1120_data_t *m1120_data, u8 addr, u8 *data, u8 len) +{ + u8 reg_addr = addr; + int err = 0; + struct i2c_client *client = NULL; + struct i2c_msg msgs[2] = {{0}, {0}}; + + if (!m1120_data) { + TRI_KEY_ERR("m1120_data == NULL\n"); + return -EINVAL; + } + client = m1120_data->client; + + if (!client) { + TRI_KEY_ERR("client null\n"); + return -EINVAL; + } else if (len >= M1120_I2C_BUF_SIZE) { + TRI_KEY_ERR(" length %d exceeds %d\n", len, M1120_I2C_BUF_SIZE); + return -EINVAL; + } + mutex_lock(&hall_m1120_down_i2c_mutex); + + msgs[0].addr = client->addr; + msgs[0].flags = 0; + msgs[0].len = 1; + msgs[0].buf = ®_addr; + + msgs[1].addr = client->addr; + msgs[1].flags = I2C_M_RD; + msgs[1].len = len; + msgs[1].buf = data; + + err = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); + + if (err < 0) { + TRI_KEY_ERR("i2c_transfer error: (%d %p %d) %d\n", addr, data, len, err); + err = -EIO; + } else { + err = 0; + } + mutex_unlock(&hall_m1120_down_i2c_mutex); + + return err; + +} + +static int m1120_i2c_write_block(struct m1120_data_t *m1120_data, u8 addr, u8 *data, u8 len) +{ + int err = 0; + int idx = 0; + int num = 0; + char buf[M1120_I2C_BUF_SIZE] = {0}; + struct i2c_client *client = NULL; + + if (!m1120_data) { + TRI_KEY_ERR("m1120_data == NULL\n"); + return -EINVAL; + } + client = m1120_data->client; + + if (!client) { + TRI_KEY_ERR("client null\n"); + return -EINVAL; + } else if (len >= M1120_I2C_BUF_SIZE) { + TRI_KEY_ERR(" length %d exceeds %d\n", len, M1120_I2C_BUF_SIZE); + return -EINVAL; + } + + mutex_lock(&hall_m1120_down_i2c_mutex); + + buf[num++] = addr; + for (idx = 0; idx < len; idx++) + buf[num++] = data[idx]; + + err = i2c_master_send(client, buf, num); + if (err < 0) + TRI_KEY_ERR("send command error!! %d\n", err); + + //store reg written + if (len == 1) { + switch (addr) { + case M1120_REG_PERSINT: + m1120_data->reg.map.persint = data[0]; + break; + case M1120_REG_INTSRS: + m1120_data->reg.map.intsrs = data[0]; + break; + case M1120_REG_LTHL: + m1120_data->reg.map.lthl = data[0]; + break; + case M1120_REG_LTHH: + m1120_data->reg.map.lthh = data[0]; + break; + case M1120_REG_HTHL: + m1120_data->reg.map.hthl = data[0]; + break; + case M1120_REG_HTHH: + m1120_data->reg.map.hthh = data[0]; + break; + case M1120_REG_I2CDIS: + m1120_data->reg.map.i2cdis = data[0]; + break; + case M1120_REG_SRST: + m1120_data->reg.map.srst = data[0]; + break; + case M1120_REG_OPF: + m1120_data->reg.map.opf = data[0]; + break; + } + } + + mutex_unlock(&hall_m1120_down_i2c_mutex); + return err; +} + +static void m1120_short_to_2byte(struct m1120_data_t *m1120_data, short x, u8 *hbyte, u8 *lbyte) +{ + if (!m1120_data) { + TRI_KEY_ERR("m1120_data == NULL\n"); + return; + } + + if ((m1120_data->reg.map.opf & M1120_VAL_OPF_BIT_8) == M1120_VAL_OPF_BIT_8) { + /* 8 bit resolution */ + if (x < -128) + x = -128; + else if (x > 127) + x = 127; + + if (x >= 0) + *lbyte = x & 0x7F; + else + *lbyte = ((0x80 - (x * (-1))) & 0x7F) | 0x80; + *hbyte = 0x00; + } else { + /* 10 bit resolution */ + if (x < -512) + x = -512; + else if (x > 511) + x = 511; + + if (x >= 0) { + *lbyte = x & 0xFF; + *hbyte = (((x & 0x100) >> 8) & 0x01) << 6; + } else { + *lbyte = (0x0200 - (x*(-1))) & 0xFF; + *hbyte = ((((0x0200 - (x*(-1))) & 0x100) >> 8) << 6) | 0x80; + } + } +} + +static short m1120_2byte_to_short(struct m1120_data_t *m1120_data, u8 hbyte, u8 lbyte) +{ + short x = 0; + + if (!m1120_data) { + TRI_KEY_ERR("m1120_data == NULL\n"); + return -EINVAL; + } + + if ((m1120_data->reg.map.opf & M1120_VAL_OPF_BIT_8) == M1120_VAL_OPF_BIT_8) { + /* 8 bit resolution */ + x = lbyte & 0x7F; + if (lbyte & 0x80) + x -= 0x80; + } else { + /* 10 bit resolution */ + x = (((hbyte & 0x40) >> 6) << 8) | lbyte; + if (hbyte & 0x80) + x -= 0x200; + } + + return x; +} + +static int m1120_set_power(bool on) +{ + m1120_power_ctl(p_m1120_data, on); + + return 0; +} + +static irqreturn_t m1120_down_irq_handler(int irq, void *dev_id) +{ + TRI_KEY_LOG("call\n"); + + if (!p_m1120_data) { + TRI_KEY_LOG("p_m1120_data NULL\n"); + return -EINVAL; + } + + disable_irq_nosync(p_m1120_data->irq); + __pm_wakeup_event(&p_m1120_data->source, 2000); + oplus_hall_irq_handler(1); + + return IRQ_HANDLED; +} + + +static int m1120_get_enable(struct m1120_data_t *p_data) +{ + return atomic_read(&p_data->atm.enable); +} + + +static void m1120_set_enable(struct m1120_data_t *p_data, int enable) +{ + mutex_lock(&p_data->mtx.enable); + TRI_KEY_LOG("enable : %d\n", enable); + if (enable) {/*enable if state will be changed*/ + if (!atomic_cmpxchg(&p_data->atm.enable, 0, 1)) + m1120_set_operation_mode(p_data, OPERATION_MODE_MEASUREMENT_M); + } else {/*disable if state will be changed*/ + if (atomic_cmpxchg(&p_data->atm.enable, 1, 0)) + m1120_set_operation_mode(p_data, OPERATION_MODE_POWERDOWN_M); + } + atomic_set(&p_data->atm.enable, enable); + + mutex_unlock(&p_data->mtx.enable); +} + + +static void m1120_set_delay(struct m1120_data_t *p_data, int delay) +{ + if (delay < M1120_DELAY_MIN) + delay = M1120_DELAY_MIN; + atomic_set(&p_data->atm.delay, delay); + + mutex_lock(&p_data->mtx.enable); + + if (m1120_get_enable(p_data)) { + if (!(p_data->reg.map.intsrs & M1120_DETECTION_MODE_INTERRUPT)) { + cancel_delayed_work_sync(&p_data->work); + schedule_delayed_work(&p_data->work, msecs_to_jiffies(delay)); + } + } + + mutex_unlock(&p_data->mtx.enable); +} + + +static void m1120_set_debug(struct m1120_data_t *p_data, int debug) +{ + atomic_set(&p_data->atm.debug, debug); +} + +static int m1120_clear_interrupt(struct m1120_data_t *p_data) +{ + int ret = 0; + u8 data = 0x00; + + data = p_data->reg.map.persint | 0x01; + ret = m1120_i2c_write_block(p_data, M1120_REG_PERSINT, &data, 1); + + return ret; +} + +static int m1120_set_operation_mode(struct m1120_data_t *p_data, int mode) +{ + u8 opf = p_data->reg.map.opf; + int err = -1; + + switch (mode) { + case OPERATION_MODE_POWERDOWN_M: + opf &= (0xFF - M1120_VAL_OPF_HSSON_ON); + err = m1120_i2c_write_block(p_data, M1120_REG_OPF, &opf, 1); + TRI_KEY_LOG("operation mode was OPERATION_MODE_POWERDOWN_M"); + break; + case OPERATION_MODE_MEASUREMENT_M: + opf &= (0xFF - M1120_VAL_OPF_EFRD_ON); + opf |= M1120_VAL_OPF_HSSON_ON; + err = m1120_i2c_write_block(p_data, M1120_REG_OPF, &opf, 1); + + TRI_KEY_LOG("operation mode was OPERATION_MODE_MEASUREMENT_M"); + break; + case OPERATION_MODE_FUSEROMACCESS_M: + opf |= M1120_VAL_OPF_EFRD_ON; + opf |= M1120_VAL_OPF_HSSON_ON; + err = m1120_i2c_write_block(p_data, M1120_REG_OPF, &opf, 1); + TRI_KEY_LOG("operation mode was OPERATION_MODE_FUSEROMACCESS_M"); + break; + } + TRI_KEY_LOG("opf = ox%x\n", opf); + return err; +} + +static int m1120_init_device(struct m1120_data_t *p_data) +{ + int err = -1; + + /*(1) vdd and vid power up*/ + err = m1120_set_power(1); + if (err) { + TRI_KEY_LOG("m1120 power-on was failed (%d)", err); + return err; + } + + /*(2) init variables*/ + atomic_set(&p_data->atm.enable, 0); + atomic_set(&p_data->atm.delay, M1120_DELAY_MIN); +#ifdef M1120_DBG_ENABLE + atomic_set(&p_data->atm.debug, 1); +#else + atomic_set(&p_data->atm.debug, 0); +#endif + p_data->calibrated_data = 0; + p_data->last_data = 0; + p_data->irq_enabled = 0; + p_data->irq_first = 1; + p_data->thrhigh = M1120_DETECT_RANGE_HIGH; + p_data->thrlow = M1120_DETECT_RANGE_LOW; + m1120_set_delay(p_data, M1120_DELAY_MAX); + m1120_set_debug(p_data, 0); + + /*(3) reset registers*/ + err = m1120_reset_device(p_data); + if (err < 0) { + TRI_KEY_ERR("m1120_reset_device was failed (%d)", err); + return err; + } + + TRI_KEY_LOG("initializing device was success"); + + return 0; +} + +static int m1120_reset_device(struct m1120_data_t *p_data) +{ + int err = 0; + u8 id = 0xFF, data = 0x00; + + if ((p_data == NULL) || (p_data->client == NULL)) + return -ENODEV; + + /*(1) sw reset*/ + data = M1120_VAL_SRST_RESET; + err = m1120_i2c_write_block(p_data, M1120_REG_SRST, &data, 1); + if (err < 0) { + TRI_KEY_ERR("sw-reset was failed(%d)", err); + return err; + } + msleep(20); + + /*(2) check id*/ + err = m1120_i2c_read_block(p_data, M1120_REG_DID, &id, 1); + if (err < 0) + return err; + if (id != M1120_VAL_DID) { + TRI_KEY_ERR("current device id(0x%02X) is not M1120 device id(0x%02X)", + id, M1120_VAL_DID); + return -ENXIO; + } + + /*(3) init variables*/ + /*(3-1) persint*/ + data = M1120_PERSISTENCE_COUNT; + err = m1120_i2c_write_block(p_data, M1120_REG_PERSINT, &data, 1); + if (err < 0) { + TRI_KEY_ERR("cm1120_i2c_write_block error, data : %d", data); + return err; + } + /*(3-2) intsrs*/ + data = M1120_DETECTION_MODE | M1120_SENSITIVITY_TYPE; + if (data & M1120_DETECTION_MODE_INTERRUPT) + data |= M1120_INTERRUPT_TYPE; + + err = m1120_i2c_write_block(p_data, M1120_REG_INTSRS, &data, 1); + if (err < 0) { + TRI_KEY_LOG("cm1120_i2c_write_block error, data : %d", data); + return err; + } + /*(3-3) opf*/ + data = M1120_OPERATION_FREQUENCY | M1120_OPERATION_RESOLUTION; + err = m1120_i2c_write_block(p_data, M1120_REG_OPF, &data, 1); + if (err < 0) { + TRI_KEY_LOG("cm1120_i2c_write_block error, data : %d", data); + return err; + } + + /*(5) set power-on mode*/ + err = m1120_set_operation_mode(p_data, OPERATION_MODE_MEASUREMENT_M); + if (err < 0) { + TRI_KEY_ERR("m1120_set_detection_mode was failed(%d)", err); + return err; + } + + return err; +} + +static int m1120_input_dev_init(struct m1120_data_t *p_data) +{ + struct input_dev *dev; + int err; + + dev = input_allocate_device(); + if (!dev) + return -ENOMEM; + + dev->name = M1120_DRIVER_NAME_DOWN; + dev->id.bustype = BUS_I2C; + +#if (M1120_EVENT_TYPE == EV_ABS) + input_set_drvdata(dev, p_data); + input_set_capability(dev, M1120_EVENT_TYPE, ABS_MISC); + input_set_abs_params(dev, M1120_EVENT_CODE, M1120_EVENT_DATA_CAPABILITY_MIN, + M1120_EVENT_DATA_CAPABILITY_MAX, 0, 0); +#elif (M1120_EVENT_TYPE == EV_KEY) + input_set_drvdata(dev, p_data); + input_set_capability(dev, M1120_EVENT_TYPE, M1120_EVENT_CODE); +#else +#error ("[ERR] M1120_EVENT_TYPE is not defined.") +#endif + + err = input_register_device(dev); + if (err < 0) { + input_free_device(dev); + return err; + } + + p_data->input_dev = dev; + + return 0; +} + +static void m1120_input_dev_terminate(struct m1120_data_t *p_data) +{ + struct input_dev *dev = p_data->input_dev; + + input_unregister_device(dev); + input_free_device(dev); +} + +static int m1120_power_ctl(struct m1120_data_t *data, bool on) +{ + int ret = 0; + int err = 0; + + if (!on && data->power_enabled) { + ret = regulator_disable(data->vdd); + if (ret) { + TRI_KEY_ERR("Regulator vdd disable failed ret=%d\n", ret); + return ret; + } + + ret = regulator_disable(data->vio); + if (ret) { + TRI_KEY_ERR("Regulator vio disable failed ret=%d\n", ret); + err = regulator_enable(data->vdd); + return ret; + } + data->power_enabled = on; + } else if (on && !data->power_enabled) { + ret = regulator_enable(data->vdd); + if (ret) { + TRI_KEY_ERR("Regulator vdd enable failed ret=%d\n", ret); + return ret; + } + msleep(20); + ret = regulator_enable(data->vio); + if (ret) { + TRI_KEY_ERR("Regulator vio enable failed ret=%d\n", ret); + err = regulator_disable(data->vdd); + return ret; + } + msleep(20); + data->power_enabled = on; + } else { + dev_info(&data->client->dev, + "Power on=%d. enabled=%d\n", + on, data->power_enabled); +} + +return ret; +} + +static int m1120_power_init(struct m1120_data_t *data) +{ + int ret; + + data->vdd = regulator_get(&data->client->dev, "vdd"); + if (IS_ERR(data->vdd)) { + ret = PTR_ERR(data->vdd); + TRI_KEY_ERR("Regulator get failed vdd ret=%d\n", ret); + return ret; + } + + if (regulator_count_voltages(data->vdd) > 0) { + ret = regulator_set_voltage(data->vdd, + M1120_VDD_MIN_UV, + M1120_VDD_MAX_UV); + if (ret) { + TRI_KEY_ERR("Regulator set failed vdd ret=%d\n", ret); + goto reg_vdd_put; + } + } + + data->vio = regulator_get(&data->client->dev, "vio"); + if (IS_ERR(data->vio)) { + ret = PTR_ERR(data->vio); + TRI_KEY_ERR("Regulator get failed vio ret=%d\n", ret); + goto reg_vdd_set; + } + + if (regulator_count_voltages(data->vio) > 0) { + ret = regulator_set_voltage(data->vio, + M1120_VIO_MIN_UV, + M1120_VIO_MAX_UV); + if (ret) { + TRI_KEY_ERR("Regulator set failed vio ret=%d\n", ret); + goto reg_vio_put; + } + } + + return 0; + +reg_vio_put: + regulator_put(data->vio); +reg_vdd_set: + if (regulator_count_voltages(data->vdd) > 0) + regulator_set_voltage(data->vdd, 0, M1120_VDD_MAX_UV); +reg_vdd_put: + regulator_put(data->vdd); + return ret; +} + + +static int tri_key_m1120_parse_dt(struct device *dev, + struct m1120_data_t *p_data) +{ + struct device_node *np = dev->of_node; + struct pinctrl *key_pinctrl; + struct pinctrl_state *set_state; + u32 temp_val; + int rc; + + TRI_KEY_LOG("%s", __func__); + rc = of_property_read_u32(np, "magnachip,init-interval", &temp_val); + if (rc && (rc != -EINVAL)) + TRI_KEY_ERR("Unable to read init-interval\n"); + else { + if (temp_val < M1120_DELAY_MIN) + temp_val = M1120_DELAY_MIN; + atomic_set(&p_data->atm.delay, temp_val); + } + + p_data->int_en = of_property_read_bool(np, "magnachip,use-interrupt"); + + p_data->igpio = of_get_named_gpio_flags(dev->of_node, + "magnachip,gpio-int", 0, NULL); + + p_data->irq_gpio = of_get_named_gpio(np, "dhall,irq-gpio", 0); + TRI_KEY_LOG("irq_gpio : %d", p_data->irq_gpio); + + p_data->use_hrtimer = of_property_read_bool(np, "magnachip,use-hrtimer"); + + key_pinctrl = devm_pinctrl_get(dev); + + if (IS_ERR_OR_NULL(key_pinctrl)) + TRI_KEY_ERR("Failed to get pinctrl\n"); + + set_state = pinctrl_lookup_state(key_pinctrl, + "downhall_tri_state_key_active"); + if (IS_ERR_OR_NULL(set_state)) + TRI_KEY_ERR("Failed to lookup_state\n"); + + pinctrl_select_state(key_pinctrl, set_state); + + + return 0; +} + +static int m1120_get_data(short *data) +{ + int err = 0; + u8 buf[3] = {0}; + short value = 0; + + if (!p_m1120_data) { + TRI_KEY_ERR("p_m1120_data == NULL"); + return -EINVAL; + } + + err = m1120_i2c_read_block(p_m1120_data, M1120_REG_ST1, buf, sizeof(buf)); + if (err < 0) { + TRI_KEY_LOG("fail %d\n", err); + return err; + } + + if (buf[0] & 0x01) + value = m1120_2byte_to_short(p_m1120_data, buf[2], buf[1]); + else + return err; + *data = value; + + return 0; +} + +static int m1120_enable_irq(bool enable) +{ + TRI_KEY_LOG("%s", __func__); + + if (p_m1120_data == NULL) { + TRI_KEY_ERR("p_m1120_data == NULL"); + return -EINVAL; + } + + if (enable) + enable_irq(p_m1120_data->irq); + else + disable_irq_nosync(p_m1120_data->irq); + + return 0; +} + +static int m1120_clear_irq(void) +{ + TRI_KEY_LOG("%s", __func__); + if (p_m1120_data == NULL) { + TRI_KEY_ERR("p_m1120_data == NULL"); + return -EINVAL; + } + + m1120_clear_interrupt(p_m1120_data); + return 0; +} + +static int m1120_get_irq_state(void) +{ + TRI_KEY_LOG("%s", __func__); + if (p_m1120_data == NULL) { + TRI_KEY_ERR("p_m1120_data == NULL"); + return -EINVAL; + } + + return ((p_m1120_data->reg.map.intsrs & M1120_DETECTION_MODE_INTERRUPT) ? 1 : 0); +} + +static bool m1120_update_threshold(int position, short lowthd, short highthd) +{ + + u8 lthh, lthl, hthh, hthl; + int err = 0; + + TRI_KEY_LOG("%s", __func__); + if (p_m1120_data == NULL) { + TRI_KEY_LOG("p_m1120_data == NULL\n"); + return -EINVAL; + } + + TRI_KEY_LOG("m1120_down ,low:%d, high:%d\n", lowthd, highthd); + + err = m1120_clear_interrupt(p_m1120_data); + + if (p_m1120_data->reg.map.intsrs & M1120_DETECTION_MODE_INTERRUPT) { + TRI_KEY_LOG("dn hallthreshold, lowthd=%d, highthd=%d.\n", lowthd, highthd); + m1120_short_to_2byte(p_m1120_data, highthd, &hthh, &hthl); + m1120_short_to_2byte(p_m1120_data, lowthd, <hh, <hl); + + err |= m1120_i2c_write_block(p_m1120_data, M1120_REG_HTHH, &hthh, 1); + err |= m1120_i2c_write_block(p_m1120_data, M1120_REG_HTHL, &hthl, 1); + err |= m1120_i2c_write_block(p_m1120_data, M1120_REG_LTHH, <hh, 1); + err |= m1120_i2c_write_block(p_m1120_data, M1120_REG_LTHL, <hl, 1); + } + + if (err < 0) { + TRI_KEY_ERR("tri_key:fail %d\n", err); + return false; + } else { + return true; + } + + return true; +} + +static void m1120_dump_reg(u8 *buf) +{ + int i, err; + u8 val; + u8 buffer[512] = {0}; + u8 _buf[20] = {0}; + + TRI_KEY_LOG("%s", __func__); + if (p_m1120_data == NULL) { + TRI_KEY_LOG("p_m1120_data == NULL\n"); + return; + } + + for (i = 0; i <= 0x12; i++) { + memset(_buf, 0, sizeof(_buf)); + + err = m1120_i2c_read_block(p_m1120_data, i, &val, 1); + if (err < 0) { + snprintf(buf, PAGE_SIZE, "read reg error!\n"); + return; + } + + snprintf(_buf, sizeof(_buf), "reg 0x%x:0x%x\n", i, val); + strcat(buffer, _buf); + } + snprintf(buf, PAGE_SIZE, "%s\n", buffer); + TRI_KEY_LOG("%s\n", buf); +} + +static bool m1120_is_power_on(void) +{ + TRI_KEY_LOG("%s", __func__); + if (p_m1120_data == NULL) { + TRI_KEY_LOG("p_m1120_data == NULL\n"); + return false; + } + + return p_m1120_data->power_enabled > 0 ? true : false; +} + +static int m1120_set_detection_mode_1(u8 mode) +{ + u8 data = 0; + int err = 0; + + TRI_KEY_LOG("======> %s", __func__); + if (p_m1120_data == NULL) { + TRI_KEY_ERR("p_m1120_data == NULL"); + return -EINVAL; + } + + TRI_KEY_LOG("m1120 down detection mode : %s\n", (mode == 0) ? "POLLING":"INTERRUPT"); + + if (mode & DETECTION_MODE_INTERRUPT) { /*interrupt mode*/ + if (!p_m1120_data->irq_enabled) { + data = p_m1120_data->reg.map.intsrs | M1120_DETECTION_MODE_INTERRUPT; + + err = m1120_i2c_write_block(p_m1120_data, M1120_REG_INTSRS, &data, 1); + if (err < 0) { + TRI_KEY_ERR("config interrupt fail %d\n", err); + return err; + } + + err = m1120_clear_interrupt(p_m1120_data); + if (err < 0) { + TRI_KEY_ERR("clear interrupt fail %d\n", err); + return err; + } + + /* request irq */ + TRI_KEY_LOG("m1120 down enter irq handler\n"); + if (request_irq(p_m1120_data->irq, &m1120_down_irq_handler, + IRQ_TYPE_LEVEL_LOW, "hall_m1120_down", + (void *)p_m1120_data->client)) { + TRI_KEY_ERR("IRQ LINE NOT AVAILABLE!!\n"); + return -EINVAL; + } + irq_set_irq_wake(p_m1120_data->irq, 1); + + p_m1120_data->irq_enabled = 1; + } + } else { /*polling mode*/ + if (p_m1120_data->irq_enabled) { + data = p_m1120_data->reg.map.intsrs & + (0xFF - M1120_DETECTION_MODE_INTERRUPT); + + err = m1120_i2c_write_block(p_m1120_data, M1120_REG_INTSRS, &data, 1); + if (err < 0) { + TRI_KEY_ERR("config interrupt fail %d\n", err); + return err; + } + + disable_irq(p_m1120_data->irq); + free_irq(p_m1120_data->irq, NULL); + + p_m1120_data->irq_enabled = 0; + } + } + + return 0; +} + +static int m1120_set_reg_1(int reg, int val) +{ + + u8 data = (u8)val; + + TRI_KEY_LOG("======> %s", __func__); + if (p_m1120_data == NULL) { + TRI_KEY_ERR("p_m1120_data == NULL"); + return -EINVAL; + } + + m1120_i2c_write_block(p_m1120_data, (u8)reg, &data, 1); + return 0; +} + +struct dhall_operations m1120_downs_ops = { + .get_data = m1120_get_data, + .enable_irq = m1120_enable_irq, + .clear_irq = m1120_clear_irq, + .get_irq_state = m1120_get_irq_state, + .set_detection_mode = m1120_set_detection_mode_1, + .update_threshold = m1120_update_threshold, + .dump_regs = m1120_dump_reg, + .set_reg = m1120_set_reg_1, + .is_power_on = m1120_is_power_on +}; + +static int tri_key_m1120_i2c_drv_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ + struct m1120_data_t *p_data; + struct extcon_dev_data *hall_dev = NULL; + int err = 0; + + TRI_KEY_LOG("allocation memory for p_m1120_data down %s\n", __func__); + /*(1) allocation memory for p_m1120_data*/ + p_data = kzalloc(sizeof(struct m1120_data_t), GFP_KERNEL); + if (!p_data) { + TRI_KEY_ERR("kernel memory alocation was failed"); + err = -ENOMEM; + goto error_0; + } + hall_dev = kzalloc(sizeof(struct extcon_dev_data), GFP_KERNEL); + if (!hall_dev) { + TRI_KEY_ERR("kernel memory alocation was failed\n"); + kfree(p_data); + return -ENOMEM; + } + /*(2) init mutex variable*/ + mutex_init(&p_data->mtx.enable); + mutex_init(&p_data->mtx.data); + p_data->power_enabled = false; + TRI_KEY_LOG("init mutex variable\n"); + /*(3) config i2c client*/ + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + TRI_KEY_ERR("i2c_check_functionality was failed"); + err = -ENODEV; + goto error_1; + } + hall_dev->client = client; + i2c_set_clientdata(client, hall_dev); + hall_dev->dev = &client->dev; + p_data->client = client; + p_data->dev = &client->dev; + p_m1120_data = p_data; + + if (client->dev.of_node) { + TRI_KEY_LOG("Use client->dev.of_node\n"); + err = tri_key_m1120_parse_dt(&client->dev, p_data); + if (err) { + TRI_KEY_ERR("Failed to parse device tree\n"); + err = -EINVAL; + goto error_1; + } + } + + if (gpio_is_valid(p_data->irq_gpio)) { + err = gpio_request(p_data->irq_gpio, "m1120_down_irq"); + if (err) { + TRI_KEY_LOG("unable to request gpio [%d]", p_data->irq_gpio); + } else { + err = gpio_direction_input(p_data->irq_gpio); + msleep(50); + p_data->irq = gpio_to_irq(p_data->irq_gpio); + TRI_KEY_LOG("======> irq : %d", p_data->irq); + } + + } + + err = m1120_power_init(p_data); + if (err) { + TRI_KEY_ERR("Failed to get sensor regulators\n"); + err = -EINVAL; + goto error_1; + } + err = m1120_power_ctl(p_data, true); + if (err) { + TRI_KEY_ERR("Failed to enable sensor power\n"); + err = -EINVAL; + goto error_1; + } + + + /*(6) reset and init device*/ + err = m1120_init_device(p_data); + if (err) { + TRI_KEY_ERR("m1120_init_device was failed(%d)", err); + goto error_1; + } + TRI_KEY_LOG("%s was found", id->name); + + /*(8) init input device*/ + err = m1120_input_dev_init(p_data); + if (err) { + TRI_KEY_ERR("m1120_input_dev_init was failed(%d)", err); + goto error_1; + } + TRI_KEY_LOG("%s was initialized", M1120_DRIVER_NAME_DOWN); + + wakeup_source_add(&p_m1120_data->source); + + /*(12) imigrate p_data to p_m1120_data*/ + TRI_KEY_LOG("%s : %s was probed.\n", __func__, M1120_DRIVER_NAME_DOWN); + + + oplus_register_hall("hall_down", &m1120_downs_ops, hall_dev); + return 0; + +error_1: + if (gpio_is_valid(p_data->irq_gpio)) + gpio_free(p_data->irq_gpio); + + kfree(p_data); + kfree(hall_dev); + +error_0: + p_m1120_data = NULL; + return err; +} + +static int m1120_i2c_drv_remove(struct i2c_client *client) +{ + struct m1120_data_t *p_data = i2c_get_clientdata(client); + + m1120_set_enable(p_data, 0); + m1120_input_dev_terminate(p_data); + if (p_data->igpio != -1) + gpio_free(p_data->igpio); + + kfree(p_data); + + return 0; +} + +static const struct i2c_device_id m1120_i2c_drv_id_table[] = { + {"hall_m1120_down", 0 }, + { } +}; + + +static const struct of_device_id m1120_of_match[] = { + { .compatible = HALL_MXM1120_DOWN, }, + { }, +}; + +struct i2c_driver m1120_i2c_down_driver = { + .driver = { + .owner = THIS_MODULE, + .name = M1120_DRIVER_NAME_DOWN, + .of_match_table = m1120_of_match, + }, + .probe = tri_key_m1120_i2c_drv_probe, + .remove = m1120_i2c_drv_remove, + .id_table = m1120_i2c_drv_id_table, +}; + +static int __init tri_key_m1120_driver_init_down(void) +{ + int res = 0; + + TRI_KEY_LOG("log %s\n", __func__); + res = i2c_add_driver(&m1120_i2c_down_driver); + TRI_KEY_LOG("log %s, res : %d\n", __func__, res); + return res; +} +late_initcall(tri_key_m1120_driver_init_down); + +static void __exit m1120_driver_exit_down(void) +{ + TRI_KEY_LOG("%s\n", __func__); + i2c_del_driver(&m1120_i2c_down_driver); +} +module_exit(m1120_driver_exit_down); + +MODULE_DESCRIPTION("M1120 hallswitch driver"); +MODULE_LICENSE("GPL"); + diff --git a/drivers/misc/tri_state_key/hall_ic/hall_mxm1120_up.c b/drivers/misc/tri_state_key/hall_ic/hall_mxm1120_up.c new file mode 100644 index 000000000000..9e880ee3cdea --- /dev/null +++ b/drivers/misc/tri_state_key/hall_ic/hall_mxm1120_up.c @@ -0,0 +1,1067 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2018-2020 Oplus. All rights reserved. + * File: oplus_tri_key.c + * + * Description: + * Definitions for m1120 tri_state_key data process. + * + * Version: 1.0 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "hall_mxm1120.h" +#include "../oplus_tri_key.h" + +#define M1120_DBG_ENABLE +#define M1120_DETECTION_MODE M1120_DETECTION_MODE_INTERRUPT +#define M1120_INTERRUPT_TYPE M1120_VAL_INTSRS_INTTYPE_BESIDE +/*#define M1120_INTERRUPT_TYPE M1120_VAL_INTSRS_INTTYPE_WITHIN*/ +#define M1120_SENSITIVITY_TYPE M1120_VAL_INTSRS_SRS_10BIT_0_068mT +#define M1120_PERSISTENCE_COUNT M1120_VAL_PERSINT_COUNT(15) +#define M1120_OPERATION_FREQUENCY M1120_VAL_OPF_FREQ_80HZ +#define M1120_OPERATION_RESOLUTION M1120_VAL_OPF_BIT_10 +#define M1120_DETECT_RANGE_HIGH (60)/*Need change via test.*/ +#define M1120_DETECT_RANGE_LOW (50)/*Need change via test.*/ +#define M1120_RESULT_STATUS_A (0x01)/*result status A 180Degree*/ +#define M1120_RESULT_STATUS_B (0x02)/*result status B 180Degree*/ +#define M1120_EVENT_TYPE EV_ABS +#define M1120_EVENT_CODE ABS_X +#define M1120_EVENT_DATA_CAPABILITY_MIN (-32768) +#define M1120_EVENT_DATA_CAPABILITY_MAX (32767) + +#define M1120_VDD_MIN_UV 2700000 +#define M1120_VDD_MAX_UV 3600000 +#define M1120_VIO_MIN_UV 1650000 +#define M1120_VIO_MAX_UV 3600000 + +#define HALL_MXM1120_UP "oplus,hall-mxm1120,up" + +#define TRI_KEY_TAG "[tri_state_key] " +#define TRI_KEY_ERR(fmt, args...)\ + pr_info(TRI_KEY_TAG" %s : "fmt, __func__, ##args) +#define TRI_KEY_LOG(fmt, args...)\ + pr_info(TRI_KEY_TAG" %s : "fmt, __func__, ##args) + +static struct m1120_data_t *p_m1120_data; + +static DEFINE_MUTEX(hall_m1120_up_i2c_mutex); + +/*i2c interface*/ +static int m1120_i2c_read_block(struct m1120_data_t *m1120_data, u8 addr, u8 *data, u8 len); +static int m1120_i2c_write_block(struct m1120_data_t *m1120_data, u8 addr, u8 *data, u8 len); +static void m1120_short_to_2byte(struct m1120_data_t *m1120_data, short x, u8 *hbyte, u8 *lbyte); +static short m1120_2byte_to_short(struct m1120_data_t *m1120_data, u8 hbyte, u8 lbyte); +/*vdd vid power control*/ +static int m1120_set_power(bool on); + + +static int m1120_get_enable(struct m1120_data_t *p_data); +static void m1120_set_enable(struct m1120_data_t *p_data, int enable); +static void m1120_set_delay(struct m1120_data_t *p_data, int delay); +static void m1120_set_debug(struct m1120_data_t *p_data, int debug); +static int m1120_clear_interrupt(struct m1120_data_t *p_data); +static int m1120_set_operation_mode(struct m1120_data_t *p_data, int mode); +static int m1120_init_device(struct m1120_data_t *p_data); +static int m1120_reset_device(struct m1120_data_t *p_data); +static int m1120_power_ctl(struct m1120_data_t *data, bool on); +static int m1120_get_data(short *data); + +/*functions for i2c interface*/ + +#define M1120_I2C_BUF_SIZE (17) + + +static int m1120_i2c_read_block(struct m1120_data_t *m1120_data, u8 addr, u8 *data, u8 len) +{ + u8 reg_addr = addr; + int err = 0; + struct i2c_client *client = NULL; + struct i2c_msg msgs[2] = {{0}, {0}}; + + if (!m1120_data) { + TRI_KEY_ERR("m1120_data == NULL\n"); + return -EINVAL; + } + client = m1120_data->client; + + if (!client) { + TRI_KEY_ERR("client null\n"); + return -EINVAL; + } else if (len >= M1120_I2C_BUF_SIZE) { + TRI_KEY_ERR(" length %d exceeds %d\n", len, M1120_I2C_BUF_SIZE); + return -EINVAL; + } + mutex_lock(&hall_m1120_up_i2c_mutex); + + msgs[0].addr = client->addr; + msgs[0].flags = 0; + msgs[0].len = 1; + msgs[0].buf = ®_addr; + + msgs[1].addr = client->addr; + msgs[1].flags = I2C_M_RD; + msgs[1].len = len; + msgs[1].buf = data; + + err = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); + + if (err < 0) { + TRI_KEY_ERR("i2c_transfer error: (%d %p %d) %d\n", addr, data, len, err); + err = -EIO; + } else { + err = 0; + } + mutex_unlock(&hall_m1120_up_i2c_mutex); + + return err; + +} + +static int m1120_i2c_write_block(struct m1120_data_t *m1120_data, u8 addr, u8 *data, u8 len) +{ + int err = 0; + int idx = 0; + int num = 0; + char buf[M1120_I2C_BUF_SIZE] = {0}; + struct i2c_client *client = NULL; + + if (!m1120_data) { + TRI_KEY_ERR("m1120_data == NULL\n"); + return -EINVAL; + } + client = m1120_data->client; + + if (!client) { + TRI_KEY_ERR("client null\n"); + return -EINVAL; + } else if (len >= M1120_I2C_BUF_SIZE) { + TRI_KEY_ERR(" length %d exceeds %d\n", len, M1120_I2C_BUF_SIZE); + return -EINVAL; + } + + mutex_lock(&hall_m1120_up_i2c_mutex); + + buf[num++] = addr; + for (idx = 0; idx < len; idx++) + buf[num++] = data[idx]; + + err = i2c_master_send(client, buf, num); + if (err < 0) + TRI_KEY_ERR("send command error!! %d\n", err); + + //store reg written + if (len == 1) { + switch (addr) { + case M1120_REG_PERSINT: + m1120_data->reg.map.persint = data[0]; + break; + case M1120_REG_INTSRS: + m1120_data->reg.map.intsrs = data[0]; + break; + case M1120_REG_LTHL: + m1120_data->reg.map.lthl = data[0]; + break; + case M1120_REG_LTHH: + m1120_data->reg.map.lthh = data[0]; + break; + case M1120_REG_HTHL: + m1120_data->reg.map.hthl = data[0]; + break; + case M1120_REG_HTHH: + m1120_data->reg.map.hthh = data[0]; + break; + case M1120_REG_I2CDIS: + m1120_data->reg.map.i2cdis = data[0]; + break; + case M1120_REG_SRST: + m1120_data->reg.map.srst = data[0]; + break; + case M1120_REG_OPF: + m1120_data->reg.map.opf = data[0]; + break; + } + } + + mutex_unlock(&hall_m1120_up_i2c_mutex); + return err; +} + +static void m1120_short_to_2byte(struct m1120_data_t *m1120_data, short x, u8 *hbyte, u8 *lbyte) +{ + if (!m1120_data) { + TRI_KEY_ERR("m1120_data == NULL\n"); + return; + } + + if ((m1120_data->reg.map.opf & M1120_VAL_OPF_BIT_8) == M1120_VAL_OPF_BIT_8) { + /* 8 bit resolution */ + if (x < -128) + x = -128; + else if (x > 127) + x = 127; + + if (x >= 0) + *lbyte = x & 0x7F; + else + *lbyte = ((0x80 - (x * (-1))) & 0x7F) | 0x80; + *hbyte = 0x00; + } else { + /* 10 bit resolution */ + if (x < -512) + x = -512; + else if (x > 511) + x = 511; + + if (x >= 0) { + *lbyte = x & 0xFF; + *hbyte = (((x & 0x100) >> 8) & 0x01) << 6; + } else { + *lbyte = (0x0200 - (x*(-1))) & 0xFF; + *hbyte = ((((0x0200 - (x*(-1))) & 0x100) >> 8) << 6) | 0x80; + } + } +} + +static short m1120_2byte_to_short(struct m1120_data_t *m1120_data, u8 hbyte, u8 lbyte) +{ + short x = 0; + + if (!m1120_data) { + TRI_KEY_ERR("m1120_data == NULL\n"); + return -EINVAL; + } + + if ((m1120_data->reg.map.opf & M1120_VAL_OPF_BIT_8) == M1120_VAL_OPF_BIT_8) { + /* 8 bit resolution */ + x = lbyte & 0x7F; + if (lbyte & 0x80) + x -= 0x80; + } else { + /* 10 bit resolution */ + x = (((hbyte & 0x40) >> 6) << 8) | lbyte; + if (hbyte & 0x80) + x -= 0x200; + } + + return x; +} + +static int m1120_set_power(bool on) +{ + m1120_power_ctl(p_m1120_data, on); + + return 0; +} + +static irqreturn_t m1120_up_irq_handler(int irq, void *dev_id) +{ + TRI_KEY_LOG("call\n"); + + if (!p_m1120_data) { + TRI_KEY_LOG("p_m1120_data NULL\n"); + return -EINVAL; + } + + disable_irq_nosync(p_m1120_data->irq); + __pm_wakeup_event(&p_m1120_data->source, 2000); + oplus_hall_irq_handler(0); + + return IRQ_HANDLED; +} + + +static int m1120_get_enable(struct m1120_data_t *p_data) +{ + return atomic_read(&p_data->atm.enable); +} + + +static void m1120_set_enable(struct m1120_data_t *p_data, int enable) +{ + mutex_lock(&p_data->mtx.enable); + TRI_KEY_LOG("enable : %d\n", enable); + if (enable) {/*enable if state will be changed*/ + if (!atomic_cmpxchg(&p_data->atm.enable, 0, 1)) + m1120_set_operation_mode(p_data, OPERATION_MODE_MEASUREMENT_M); + } else {/*disable if state will be changed*/ + if (atomic_cmpxchg(&p_data->atm.enable, 1, 0)) + m1120_set_operation_mode(p_data, OPERATION_MODE_POWERDOWN_M); + } + atomic_set(&p_data->atm.enable, enable); + + mutex_unlock(&p_data->mtx.enable); +} + + +static void m1120_set_delay(struct m1120_data_t *p_data, int delay) +{ + if (delay < M1120_DELAY_MIN) + delay = M1120_DELAY_MIN; + atomic_set(&p_data->atm.delay, delay); + + mutex_lock(&p_data->mtx.enable); + + if (m1120_get_enable(p_data)) { + if (!(p_data->reg.map.intsrs & M1120_DETECTION_MODE_INTERRUPT)) { + cancel_delayed_work_sync(&p_data->work); + schedule_delayed_work(&p_data->work, msecs_to_jiffies(delay)); + } + } + + mutex_unlock(&p_data->mtx.enable); +} + + +static void m1120_set_debug(struct m1120_data_t *p_data, int debug) +{ + atomic_set(&p_data->atm.debug, debug); +} + +static int m1120_clear_interrupt(struct m1120_data_t *p_data) +{ + int ret = 0; + u8 data = 0x00; + + data = p_data->reg.map.persint | 0x01; + ret = m1120_i2c_write_block(p_data, M1120_REG_PERSINT, &data, 1); + + return ret; +} + +static int m1120_set_operation_mode(struct m1120_data_t *p_data, int mode) +{ + u8 opf = p_data->reg.map.opf; + int err = -1; + + switch (mode) { + case OPERATION_MODE_POWERDOWN_M: + opf &= (0xFF - M1120_VAL_OPF_HSSON_ON); + err = m1120_i2c_write_block(p_data, M1120_REG_OPF, &opf, 1); + TRI_KEY_LOG("operation mode was OPERATION_MODE_POWERDOWN_M"); + break; + case OPERATION_MODE_MEASUREMENT_M: + opf &= (0xFF - M1120_VAL_OPF_EFRD_ON); + opf |= M1120_VAL_OPF_HSSON_ON; + err = m1120_i2c_write_block(p_data, M1120_REG_OPF, &opf, 1); + + TRI_KEY_LOG("operation mode was OPERATION_MODE_MEASUREMENT_M"); + break; + case OPERATION_MODE_FUSEROMACCESS_M: + opf |= M1120_VAL_OPF_EFRD_ON; + opf |= M1120_VAL_OPF_HSSON_ON; + err = m1120_i2c_write_block(p_data, M1120_REG_OPF, &opf, 1); + TRI_KEY_LOG("operation mode was OPERATION_MODE_FUSEROMACCESS_M"); + break; + } + TRI_KEY_LOG("opf = ox%x\n", opf); + return err; +} + +static int m1120_init_device(struct m1120_data_t *p_data) +{ + int err = -1; + + /*(1) vdd and vid power up*/ + err = m1120_set_power(1); + if (err) { + TRI_KEY_LOG("m1120 power-on was failed (%d)", err); + return err; + } + + /*(2) init variables*/ + atomic_set(&p_data->atm.enable, 0); + atomic_set(&p_data->atm.delay, M1120_DELAY_MIN); +#ifdef M1120_DBG_ENABLE + atomic_set(&p_data->atm.debug, 1); +#else + atomic_set(&p_data->atm.debug, 0); +#endif + p_data->calibrated_data = 0; + p_data->last_data = 0; + p_data->irq_enabled = 0; + p_data->irq_first = 1; + p_data->thrhigh = M1120_DETECT_RANGE_HIGH; + p_data->thrlow = M1120_DETECT_RANGE_LOW; + m1120_set_delay(p_data, M1120_DELAY_MAX); + m1120_set_debug(p_data, 0); + + /*(3) reset registers*/ + err = m1120_reset_device(p_data); + if (err < 0) { + TRI_KEY_ERR("m1120_reset_device was failed (%d)", err); + return err; + } + + TRI_KEY_LOG("initializing device was success"); + + return 0; +} + +static int m1120_reset_device(struct m1120_data_t *p_data) +{ + int err = 0; + u8 id = 0xFF, data = 0x00; + + if ((p_data == NULL) || (p_data->client == NULL)) + return -ENODEV; + + /*(1) sw reset*/ + data = M1120_VAL_SRST_RESET; + err = m1120_i2c_write_block(p_data, M1120_REG_SRST, &data, 1); + if (err < 0) { + TRI_KEY_ERR("sw-reset was failed(%d)", err); + return err; + } + msleep(20); + + /*(2) check id*/ + err = m1120_i2c_read_block(p_data, M1120_REG_DID, &id, 1); + if (err < 0) + return err; + if (id != M1120_VAL_DID) { + TRI_KEY_ERR("current device id(0x%02X) is not M1120 device id(0x%02X)", + id, M1120_VAL_DID); + return -ENXIO; + } + + /*(3) init variables*/ + /*(3-1) persint*/ + data = M1120_PERSISTENCE_COUNT; + err = m1120_i2c_write_block(p_data, M1120_REG_PERSINT, &data, 1); + if (err < 0) { + TRI_KEY_ERR("cm1120_i2c_write_block error, data : %d", data); + return err; + } + /*(3-2) intsrs*/ + data = M1120_DETECTION_MODE | M1120_SENSITIVITY_TYPE; + if (data & M1120_DETECTION_MODE_INTERRUPT) + data |= M1120_INTERRUPT_TYPE; + + err = m1120_i2c_write_block(p_data, M1120_REG_INTSRS, &data, 1); + if (err < 0) { + TRI_KEY_LOG("cm1120_i2c_write_block error, data : %d", data); + return err; + } + /*(3-3) opf*/ + data = M1120_OPERATION_FREQUENCY | M1120_OPERATION_RESOLUTION; + err = m1120_i2c_write_block(p_data, M1120_REG_OPF, &data, 1); + if (err < 0) { + TRI_KEY_LOG("cm1120_i2c_write_block error, data : %d", data); + return err; + } + + /*(5) set power-on mode*/ + err = m1120_set_operation_mode(p_data, OPERATION_MODE_MEASUREMENT_M); + if (err < 0) { + TRI_KEY_ERR("m1120_set_detection_mode was failed(%d)", err); + return err; + } + + return err; +} + +static int m1120_input_dev_init(struct m1120_data_t *p_data) +{ + struct input_dev *dev; + int err; + + dev = input_allocate_device(); + if (!dev) + return -ENOMEM; + + dev->name = M1120_DRIVER_NAME_UP; + dev->id.bustype = BUS_I2C; + +#if (M1120_EVENT_TYPE == EV_ABS) + input_set_drvdata(dev, p_data); + input_set_capability(dev, M1120_EVENT_TYPE, ABS_MISC); + input_set_abs_params(dev, M1120_EVENT_CODE, M1120_EVENT_DATA_CAPABILITY_MIN, + M1120_EVENT_DATA_CAPABILITY_MAX, 0, 0); +#elif (M1120_EVENT_TYPE == EV_KEY) + input_set_drvdata(dev, p_data); + input_set_capability(dev, M1120_EVENT_TYPE, M1120_EVENT_CODE); +#else +#error ("[ERR] M1120_EVENT_TYPE is not defined.") +#endif + + err = input_register_device(dev); + if (err < 0) { + input_free_device(dev); + return err; + } + + p_data->input_dev = dev; + + return 0; +} + +static void m1120_input_dev_terminate(struct m1120_data_t *p_data) +{ + struct input_dev *dev = p_data->input_dev; + + input_unregister_device(dev); + input_free_device(dev); +} + +static int m1120_power_ctl(struct m1120_data_t *data, bool on) +{ + int ret = 0; + int err = 0; + + if (!on && data->power_enabled) { + ret = regulator_disable(data->vdd); + if (ret) { + TRI_KEY_ERR("Regulator vdd disable failed ret=%d\n", ret); + return ret; + } + + ret = regulator_disable(data->vio); + if (ret) { + TRI_KEY_ERR("Regulator vio disable failed ret=%d\n", ret); + err = regulator_enable(data->vdd); + return ret; + } + data->power_enabled = on; + } else if (on && !data->power_enabled) { + ret = regulator_enable(data->vdd); + if (ret) { + TRI_KEY_ERR("Regulator vdd enable failed ret=%d\n", ret); + return ret; + } + msleep(20); + ret = regulator_enable(data->vio); + if (ret) { + TRI_KEY_ERR("Regulator vio enable failed ret=%d\n", ret); + err = regulator_disable(data->vdd); + return ret; + } + msleep(20); + data->power_enabled = on; + } else { + dev_info(&data->client->dev, + "Power on=%d. enabled=%d\n", + on, data->power_enabled); +} + +return ret; +} + +static int m1120_power_init(struct m1120_data_t *data) +{ + int ret; + + data->vdd = regulator_get(&data->client->dev, "vdd"); + if (IS_ERR(data->vdd)) { + ret = PTR_ERR(data->vdd); + TRI_KEY_ERR("Regulator get failed vdd ret=%d\n", ret); + return ret; + } + + if (regulator_count_voltages(data->vdd) > 0) { + ret = regulator_set_voltage(data->vdd, + M1120_VDD_MIN_UV, + M1120_VDD_MAX_UV); + if (ret) { + TRI_KEY_ERR("Regulator set failed vdd ret=%d\n", ret); + goto reg_vdd_put; + } + } + + data->vio = regulator_get(&data->client->dev, "vio"); + if (IS_ERR(data->vio)) { + ret = PTR_ERR(data->vio); + TRI_KEY_ERR("Regulator get failed vio ret=%d\n", ret); + goto reg_vdd_set; + } + + if (regulator_count_voltages(data->vio) > 0) { + ret = regulator_set_voltage(data->vio, + M1120_VIO_MIN_UV, + M1120_VIO_MAX_UV); + if (ret) { + TRI_KEY_ERR("Regulator set failed vio ret=%d\n", ret); + goto reg_vio_put; + } + } + + return 0; + +reg_vio_put: + regulator_put(data->vio); +reg_vdd_set: + if (regulator_count_voltages(data->vdd) > 0) + regulator_set_voltage(data->vdd, 0, M1120_VDD_MAX_UV); +reg_vdd_put: + regulator_put(data->vdd); + return ret; +} + + +static int tri_key_m1120_parse_dt(struct device *dev, + struct m1120_data_t *p_data) +{ + struct device_node *np = dev->of_node; + struct pinctrl *key_pinctrl; + struct pinctrl_state *set_state; + u32 temp_val; + int rc; + + TRI_KEY_LOG("%s", __func__); + rc = of_property_read_u32(np, "magnachip,init-interval", &temp_val); + if (rc && (rc != -EINVAL)) + TRI_KEY_ERR("Unable to read init-interval\n"); + else { + if (temp_val < M1120_DELAY_MIN) + temp_val = M1120_DELAY_MIN; + atomic_set(&p_data->atm.delay, temp_val); + } + + p_data->int_en = of_property_read_bool(np, "magnachip,use-interrupt"); + + p_data->igpio = of_get_named_gpio_flags(dev->of_node, + "magnachip,gpio-int", 0, NULL); + + p_data->irq_gpio = of_get_named_gpio(np, "dhall,irq-gpio", 0); + TRI_KEY_LOG("irq_gpio : %d", p_data->irq_gpio); + + p_data->use_hrtimer = of_property_read_bool(np, "magnachip,use-hrtimer"); + + key_pinctrl = devm_pinctrl_get(dev); + + if (IS_ERR_OR_NULL(key_pinctrl)) + TRI_KEY_ERR("Failed to get pinctrl\n"); + + set_state = pinctrl_lookup_state(key_pinctrl, + "uphall_tri_state_key_active"); + if (IS_ERR_OR_NULL(set_state)) + TRI_KEY_ERR("Failed to lookup_state\n"); + + pinctrl_select_state(key_pinctrl, set_state); + + + return 0; +} + +static int m1120_get_data(short *data) +{ + int err = 0; + u8 buf[3] = {0}; + short value = 0; + + if (!p_m1120_data) { + TRI_KEY_ERR("p_m1120_data == NULL"); + return -EINVAL; + } + + err = m1120_i2c_read_block(p_m1120_data, M1120_REG_ST1, buf, sizeof(buf)); + if (err < 0) { + TRI_KEY_LOG("fail %d\n", err); + return err; + } + + if (buf[0] & 0x01) + value = m1120_2byte_to_short(p_m1120_data, buf[2], buf[1]); + else + return err; + *data = value; + + return 0; +} + +static int m1120_enable_irq(bool enable) +{ + TRI_KEY_LOG("%s", __func__); + + if (p_m1120_data == NULL) { + TRI_KEY_ERR("p_m1120_data == NULL"); + return -EINVAL; + } + + if (enable) + enable_irq(p_m1120_data->irq); + else + disable_irq_nosync(p_m1120_data->irq); + + return 0; +} + +static int m1120_clear_irq(void) +{ + TRI_KEY_LOG("%s", __func__); + if (p_m1120_data == NULL) { + TRI_KEY_ERR("p_m1120_data == NULL"); + return -EINVAL; + } + + m1120_clear_interrupt(p_m1120_data); + return 0; +} + +static int m1120_get_irq_state(void) +{ + TRI_KEY_LOG("%s", __func__); + if (p_m1120_data == NULL) { + TRI_KEY_ERR("p_m1120_data == NULL"); + return -EINVAL; + } + + return ((p_m1120_data->reg.map.intsrs & M1120_DETECTION_MODE_INTERRUPT) ? 1 : 0); +} + +static bool m1120_update_threshold(int position, short lowthd, short highthd) +{ + + u8 lthh, lthl, hthh, hthl; + int err = 0; + + TRI_KEY_LOG("%s", __func__); + if (p_m1120_data == NULL) { + TRI_KEY_LOG("p_m1120_data == NULL\n"); + return -EINVAL; + } + + TRI_KEY_LOG("m1120_up ,low:%d, high:%d\n", lowthd, highthd); + + err = m1120_clear_interrupt(p_m1120_data); + + if (p_m1120_data->reg.map.intsrs & M1120_DETECTION_MODE_INTERRUPT) { + TRI_KEY_LOG("up hallthreshold, lowthd=%d, highthd=%d.\n", lowthd, highthd); + m1120_short_to_2byte(p_m1120_data, highthd, &hthh, &hthl); + m1120_short_to_2byte(p_m1120_data, lowthd, <hh, <hl); + + err |= m1120_i2c_write_block(p_m1120_data, M1120_REG_HTHH, &hthh, 1); + err |= m1120_i2c_write_block(p_m1120_data, M1120_REG_HTHL, &hthl, 1); + err |= m1120_i2c_write_block(p_m1120_data, M1120_REG_LTHH, <hh, 1); + err |= m1120_i2c_write_block(p_m1120_data, M1120_REG_LTHL, <hl, 1); + } + + if (err < 0) { + TRI_KEY_ERR("tri_key:fail %d\n", err); + return false; + } else { + return true; + } + + return true; +} + +static void m1120_dump_reg(u8 *buf) +{ + int i, err; + u8 val; + u8 buffer[512] = {0}; + u8 _buf[20] = {0}; + + TRI_KEY_LOG("%s", __func__); + if (p_m1120_data == NULL) { + TRI_KEY_LOG("p_m1120_data == NULL\n"); + return; + } + + for (i = 0; i <= 0x12; i++) { + memset(_buf, 0, sizeof(_buf)); + + err = m1120_i2c_read_block(p_m1120_data, i, &val, 1); + if (err < 0) { + snprintf(buf, PAGE_SIZE, "read reg error!\n"); + return; + } + + snprintf(_buf, sizeof(_buf), "reg 0x%x:0x%d\n", i, val); + strcat(buffer, _buf); + } + snprintf(buf, PAGE_SIZE, "%s\n", buffer); + TRI_KEY_LOG("%s\n", buf); +} + +static bool m1120_is_power_on(void) +{ + TRI_KEY_LOG("%s", __func__); + if (p_m1120_data == NULL) { + TRI_KEY_LOG("p_m1120_data == NULL\n"); + return false; + } + + return p_m1120_data->power_enabled > 0 ? true : false; +} + +static int m1120_set_detection_mode_1(u8 mode) +{ + u8 data = 0; + int err = 0; + + TRI_KEY_LOG("======> %s", __func__); + if (p_m1120_data == NULL) { + TRI_KEY_ERR("p_m1120_data == NULL"); + return -EINVAL; + } + + TRI_KEY_LOG("m1120 up detection mode : %s\n", (mode == 0) ? "POLLING":"INTERRUPT"); + + if (mode & DETECTION_MODE_INTERRUPT) { /*interrupt mode*/ + if (!p_m1120_data->irq_enabled) { + data = p_m1120_data->reg.map.intsrs | M1120_DETECTION_MODE_INTERRUPT; + + err = m1120_i2c_write_block(p_m1120_data, M1120_REG_INTSRS, &data, 1); + if (err < 0) { + TRI_KEY_ERR("config interrupt fail %d\n", err); + return err; + } + + err = m1120_clear_interrupt(p_m1120_data); + if (err < 0) { + TRI_KEY_ERR("clear interrupt fail %d\n", err); + return err; + } + + /* request irq */ + TRI_KEY_LOG("m1120 down enter irq handler\n"); + if (request_irq(p_m1120_data->irq, &m1120_up_irq_handler, + IRQ_TYPE_LEVEL_LOW, "hall_m1120_up", + (void *)p_m1120_data->client)) { + TRI_KEY_ERR("IRQ LINE NOT AVAILABLE!!\n"); + return -EINVAL; + } + irq_set_irq_wake(p_m1120_data->irq, 1); + + p_m1120_data->irq_enabled = 1; + } + } else { /*polling mode*/ + if (p_m1120_data->irq_enabled) { + data = p_m1120_data->reg.map.intsrs & + (0xFF - M1120_DETECTION_MODE_INTERRUPT); + + err = m1120_i2c_write_block(p_m1120_data, M1120_REG_INTSRS, &data, 1); + if (err < 0) { + TRI_KEY_ERR("config interrupt fail %d\n", err); + return err; + } + + disable_irq(p_m1120_data->irq); + free_irq(p_m1120_data->irq, NULL); + + p_m1120_data->irq_enabled = 0; + } + } + + return 0; +} + +static int m1120_set_reg_1(int reg, int val) +{ + + u8 data = (u8)val; + + TRI_KEY_LOG("======> %s", __func__); + if (p_m1120_data == NULL) { + TRI_KEY_ERR("p_m1120_data == NULL"); + return -EINVAL; + } + + m1120_i2c_write_block(p_m1120_data, (u8)reg, &data, 1); + return 0; +} + +struct dhall_operations m1120_ups_ops = { + .get_data = m1120_get_data, + .enable_irq = m1120_enable_irq, + .clear_irq = m1120_clear_irq, + .get_irq_state = m1120_get_irq_state, + .set_detection_mode = m1120_set_detection_mode_1, + .update_threshold = m1120_update_threshold, + .dump_regs = m1120_dump_reg, + .set_reg = m1120_set_reg_1, + .is_power_on = m1120_is_power_on +}; + +static int tri_key_m1120_i2c_drv_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ + struct m1120_data_t *p_data; + struct extcon_dev_data *hall_dev = NULL; + int err = 0; + + TRI_KEY_LOG("allocation memory for p_m1120_data up %s\n", __func__); + /*(1) allocation memory for p_m1120_data*/ + p_data = kzalloc(sizeof(struct m1120_data_t), GFP_KERNEL); + if (!p_data) { + TRI_KEY_ERR("kernel memory alocation was failed"); + err = -ENOMEM; + goto error_0; + } + hall_dev = kzalloc(sizeof(struct extcon_dev_data), GFP_KERNEL); + if (!hall_dev) { + TRI_KEY_ERR("kernel memory alocation was failed\n"); + kfree(p_data); + return -ENOMEM; + } + /*(2) init mutex variable*/ + mutex_init(&p_data->mtx.enable); + mutex_init(&p_data->mtx.data); + p_data->power_enabled = false; + TRI_KEY_LOG("init mutex variable\n"); + /*(3) config i2c client*/ + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + TRI_KEY_ERR("i2c_check_functionality was failed"); + err = -ENODEV; + goto error_1; + } + hall_dev->client = client; + i2c_set_clientdata(client, hall_dev); + hall_dev->dev = &client->dev; + p_data->client = client; + p_data->dev = &client->dev; + p_m1120_data = p_data; + + if (client->dev.of_node) { + TRI_KEY_LOG("Use client->dev.of_node\n"); + err = tri_key_m1120_parse_dt(&client->dev, p_data); + if (err) { + TRI_KEY_ERR("Failed to parse device tree\n"); + err = -EINVAL; + goto error_1; + } + } + + if (gpio_is_valid(p_data->irq_gpio)) { + err = gpio_request(p_data->irq_gpio, "m1120_up_irq"); + if (err) { + TRI_KEY_LOG("unable to request gpio [%d]", p_data->irq_gpio); + } else { + err = gpio_direction_input(p_data->irq_gpio); + msleep(50); + p_data->irq = gpio_to_irq(p_data->irq_gpio); + TRI_KEY_LOG("======> irq : %d", p_data->irq); + } + + } + + err = m1120_power_init(p_data); + if (err) { + TRI_KEY_ERR("Failed to get sensor regulators\n"); + err = -EINVAL; + goto error_1; + } + err = m1120_power_ctl(p_data, true); + if (err) { + TRI_KEY_ERR("Failed to enable sensor power\n"); + err = -EINVAL; + goto error_1; + } + + + /*(6) reset and init device*/ + err = m1120_init_device(p_data); + if (err) { + TRI_KEY_ERR("m1120_init_device was failed(%d)", err); + goto error_1; + } + TRI_KEY_LOG("%s was found", id->name); + + /*(8) init input device*/ + err = m1120_input_dev_init(p_data); + if (err) { + TRI_KEY_ERR("m1120_input_dev_init was failed(%d)", err); + goto error_1; + } + TRI_KEY_LOG("%s was initialized", M1120_DRIVER_NAME_UP); + + wakeup_source_add(&p_m1120_data->source); + + /*(12) imigrate p_data to p_m1120_data*/ + TRI_KEY_LOG("%s : %s was probed.\n", __func__, M1120_DRIVER_NAME_UP); + + oplus_register_hall("hall_up", &m1120_ups_ops, hall_dev); + + return 0; + +error_1: + if (gpio_is_valid(p_data->irq_gpio)) + gpio_free(p_data->irq_gpio); + + kfree(p_data); + kfree(hall_dev); + +error_0: + p_m1120_data = NULL; + return err; +} + +static int m1120_i2c_drv_remove(struct i2c_client *client) +{ + struct m1120_data_t *p_data = i2c_get_clientdata(client); + + m1120_set_enable(p_data, 0); + m1120_input_dev_terminate(p_data); + if (p_data->igpio != -1) + gpio_free(p_data->igpio); + + kfree(p_data); + + return 0; +} + +static const struct i2c_device_id m1120_i2c_drv_id_table[] = { + {"hall_m1120_up", 0 }, + { } +}; + + +static const struct of_device_id m1120_of_match[] = { + { .compatible = HALL_MXM1120_UP, }, + { }, +}; + +struct i2c_driver m1120_i2c_up_driver = { + .driver = { + .owner = THIS_MODULE, + .name = M1120_DRIVER_NAME_UP, + .of_match_table = m1120_of_match, + }, + .probe = tri_key_m1120_i2c_drv_probe, + .remove = m1120_i2c_drv_remove, + .id_table = m1120_i2c_drv_id_table, +}; + + +static int __init tri_key_m1120_driver_init_up(void) +{ + int res = 0; + + TRI_KEY_LOG("log %s\n", __func__); + res = i2c_add_driver(&m1120_i2c_up_driver); + TRI_KEY_LOG("log %s, res : %d\n", __func__, res); + return res; +} +late_initcall(tri_key_m1120_driver_init_up); + +static void __exit m1120_driver_exit_up(void) +{ + TRI_KEY_LOG("%s\n", __func__); + i2c_del_driver(&m1120_i2c_up_driver); +} +module_exit(m1120_driver_exit_up); + +MODULE_DESCRIPTION("M1120 hallswitch driver"); +MODULE_LICENSE("GPL"); + diff --git a/drivers/misc/tri_state_key/ist_hall_ic/Kconfig b/drivers/misc/tri_state_key/ist_hall_ic/Kconfig new file mode 100644 index 000000000000..b12f02a58580 --- /dev/null +++ b/drivers/misc/tri_state_key/ist_hall_ic/Kconfig @@ -0,0 +1,11 @@ +config IST_UP + tristate "hall up ic support" + default n + help + Say Y here to enable ist8801 up. + +config IST_DOWN + tristate "hall down ic support" + default n + help + Say Y here to enable ist8801 down. diff --git a/drivers/misc/tri_state_key/ist_hall_ic/Makefile b/drivers/misc/tri_state_key/ist_hall_ic/Makefile new file mode 100644 index 000000000000..388a83e0f845 --- /dev/null +++ b/drivers/misc/tri_state_key/ist_hall_ic/Makefile @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# Makefile for the touchscreen drivers. +# + +# Each configuration option enables a list of files. +oplus_bsp_ist_up-y += hall_ist8801_up.o +obj-$(CONFIG_IST_UP) += oplus_bsp_ist_up.o +oplus_bsp_ist_down-y += hall_ist8801_down.o +obj-$(CONFIG_IST_DOWN) += oplus_bsp_ist_down.o diff --git a/drivers/misc/tri_state_key/ist_hall_ic/hall_ist8801.h b/drivers/misc/tri_state_key/ist_hall_ic/hall_ist8801.h new file mode 100644 index 000000000000..70d54c6b713c --- /dev/null +++ b/drivers/misc/tri_state_key/ist_hall_ic/hall_ist8801.h @@ -0,0 +1,317 @@ +/* SPDX-License-Identifier: GPL-2.0-only*/ +/* + * Copyright (C) 2018-2020 Oplus. All rights reserved. + * File: oplus_tri_key.c + * + * Description: + * Definitions for m1120 tri_state_key data process. + * + * Version: 1.0 + */ +#ifndef __IST8801_H__ +#define __IST8801_H__ + +#include +#include +#include + + +/* ***************************************** */ +/* feature of ic revision */ +/* ***************************************** */ +#define IST8801_REV_0_2 (0x02) +#define IST8801_REV_1_0 (0x10) +#define IST8801_REV IST8801_REV_1_0 +#define IST8801_DRIVER_VERSION "Ver1.00-190222" +/* ********************************************************* */ + + +/* + *SAD1 SAD0 == 00 0001100 R/W (7bits)0x0C (8bits)0x18 + *SAD1 SAD0 == 01 0001101 R/W (7bits)0x0D (8bits)0x1A + *SAD1 SAD0 == 10 0001110 R/W (7bits)0x0E (8bits)0x1C + *SAD1 SAD0 == 11 0001111 R/W (7bits)0x0F (8bits)0x1E + */ +/* ******************************** */ + +/* ******************************** */ +/* register map */ +/* ******************************* */ +#define IST8801_REG_PERSINT (0x00) +#define IST8801_VAL_PERSINT_COUNT(n) (n << 4) + +/* + *[7:4] PERS : interrupt persistence count + *[0] INTCLR = 1 : interrupt clear + */ +/* ------------------------------------ */ +#define IST8801_REG_INTSRS (0x01) +#define IST8801_VAL_INTSRS_INT_ON (0x80) +#define IST8801_DETECTION_MODE_INTERRUPT IST8801_VAL_INTSRS_INT_ON +#define IST8801_VAL_INTSRS_INT_OFF (0x00) +#define IST8801_DETECTION_MODE_POLLING IST8801_VAL_INTSRS_INT_OFF +#define IST8801_VAL_INTSRS_INTTYPE_BESIDE (0x00) +#define IST8801_VAL_INTSRS_INTTYPE_WITHIN (0x10) +#define IST8801_VAL_INTSRS_ZGAIN (0x00) +#define IST8801_VAL_INTSRS_ZGAIN_DIV_2 (0x01) +#define IST8801_VAL_INTSRS_ZGAIN_DIV_4 (0x02) +#define IST8801_VAL_INTSRS_ZGAIN_DIV_8 (0x03) +#define IST8801_VAL_INTSRS_ZGAIN_DIV_16 (0x04) +/* + *[7] INTON = 0 : disable interrupt + *[7] INTON = 1 : enable interrupt + *[4] INT_TYP = 0 : generate interrupt when + *raw data is beside range of threshold + *[4] INT_TYP = 1 : generate interrupt when + * raw data is within range of threshold + *[2:0] SRS : Sensitivity range and resolution : default 010 + *000 : GAIN= ZGAIN (Register 0x54) + *001 : GAIN= ZGAIN / 2 + *010 : GAIN= ZGAIN / 4 + *011 : GAIN= ZGAIN / 8 + *100 : GAIN= ZGAIN / 16 + *Others : GAIN= ZGAIN / 4 + */ +/* ----------------------------------------- */ +#define IST8801_REG_LTHL (0x02) +/* + *[7:0] LTHL : low byte of low threshold value + */ +/* ---------------------------------- */ +#define IST8801_REG_LTHH (0x03) +/* + *[7:0] LTHH : high byte of low threshold value with sign + */ +/* ------------------------------------ */ +#define IST8801_REG_HTHL (0x04) +/* + *[7:0] HTHL : low byte of high threshold value + */ +/* ------------------------------ */ +#define IST8801_REG_HTHH (0x05) +/* + *[7:0] HTHH : high bye of high threshold value with sign + */ +/* ------------------------------------ */ +#define IST8801_REG_I2CDIS (0x06) +#define IST8801_VAL_I2CDISABLE (0x37) +/* + *[7:0] I2CDIS : disable i2c + */ +/* -------------------------------------- */ +#define IST8801_REG_SRST (0x07) +#define IST8801_VAL_SRST_RESET (0x01) +/* + *[0] SRST = 1 : soft reset + */ +/* --------------------------------------- */ +#define IST8801_REG_OPF (0x08) +#define IST8801_VAL_OPF_STANDBY (0x00) +#define IST8801_VAL_OPF_FREQ_10HZ (0x10) +#define IST8801_VAL_OPF_FREQ_6_7HZ (0x20) +#define IST8801_VAL_OPF_FREQ_5HZ (0x30) +#define IST8801_VAL_OPF_FREQ_80HZ (0x40) +#define IST8801_VAL_OPF_FREQ_40HZ (0x50) +#define IST8801_VAL_OPF_FREQ_26_7HZ (0x60) +#define IST8801_VAL_OPF_FREQ_20HZ (0x70) +#define IST8801_VAL_OPF_SINGLE_MODE (0x80) +#define IST8801_VAL_OPF_FREQ_100HZ (0x90) +#define IST8801_VAL_OPF_FREQ_50HZ (0xA0) +#define IST8801_VAL_OPF_FREQ_1HZ (0xB0) +#define IST8801_VAL_OPF_FREQ_200HZ (0xC0) +#define IST8801_VAL_OPF_FREQ_250HZ (0xD0) +#define IST8801_VAL_OPF_FREQ_320HZ (0xE0) +#define IST8801_VAL_OPF_FREQ_500HZ (0xF0) +/* + *[7:4] OPF : operation frequency + *00 : Standby mode + *10 : 10 (Hz) + *20 : 6.7 (Hz) + *30 : 5 (Hz) + *40 : 80 (Hz) + *50 : 40 (Hz) + *60 : 26.7 (Hz) + *70 : 20 (Hz) + *80 : Single mode + *90 : 100 (Hz) + *A0 : 50 (Hz) + *B0 : 1 (Hz) + *C0 : 200 (Hz) + *D0 : 250 (Hz) + *E0 : 320 (Hz) + *F0 : 500 (Hz) + */ +/* ----------------------------------- */ +#define IST8801_REG_DID (0x09) +#define IST8801_VAL_DID (0x81) +/* + *[7:0] DID : Device ID by OTP + */ +/* --------------------------------------- */ +#define IST8801_REG_ST1 (0x10) +#define IST8801_VAL_ST1_DRDY (0x01) +/* + *[4] INTM : status of interrupt mode + *[2] DORZ : 0 = no data overrun, 1 = data is overrun + *[0] DRDY : status of data ready + */ +/* -------------------------------------- */ +#define IST8801_REG_HSL (0x11) +/* + *[7:0] HSL : low byte of hall sensor measurement data + */ +/* ------------------------------------ */ +#define IST8801_REG_HSH (0x12) +/* + *[7:0] HSL : high byte of hall sensor measurement data with sign + */ +/* --------------------------------------- */ +#define IST8801_REG_TDATAL (0x13) +/* + *[7:6] HSL : Temperature Data, Low Byte + */ +/* --------------------------------- */ +#define IST8801_REG_TDATAH (0x14) +/* + *[7:6] HSL : Temperature Data, High Byte + */ +/* ---------------------------------------- */ +#define IST8801_REG_USR_ODR_L (0x1A) +/* + *[7:6] HSL : More User ODR Mode, Low Byte + */ +/* ----------------------------------------- */ +#define IST8801_REG_USR_ODR_H (0x1B) +/* + *[7:6] HSL : More User ODR Mode, High Byte + */ +/* --------------------------------------- */ +#define IST8801_REG_ACTION (0x20) +/* + *[1] ACTR : Action Register + */ +/* ************************************ */ + +/* ------------------------------------ */ +#define IST8801_REG_CNTL2 (0x0D) +#define GAIN_1_TIME (0x0 << 5) +#define GAIN_2_TIME (0x1 << 5) +#define GAIN_4_TIME (0x2 << 5) +#define GAIN_8_TIME (0x3 << 5) +#define ADC_RES_15_BIT (0x1 << 1) +#define ADC_RES_14_BIT (0x2 << 1) +#define ADC_RES_13_BIT (0x3 << 1) +#define ADC_RES_12_BIT (0x4 << 1) +#define ADC_RES_11_BIT (0x5 << 1) +#define ADC_RES_10_BIT (0x6 << 1) +#define ADC_RES_9_BIT (0x7 << 1) +#define ADC_RES_8_BIT (0x8 << 1) +#define ADC_RES_16_BIT (0x9 << 1) +/* + *[6:5] GAIN : 1 times/2 times/4 times/8 times + *[4:1] ADC_RS : 15/14/13/12/11/10/9/8 bits + */ +/********************************************* */ +#define IST8801_REG_IFCNTL (0x40) +/********************************************* */ +#define IST8801_REG_GAINCNTL (0x54) +/********************************************* */ +#define IST8801_REG_TSTCNTL (0x76) +/********************************************* */ +#define IST8801_REG_OSRCNTL (0x6c) +/********************************************* */ +#define IST8801_REG_INFO (0x87) +/********************************************* */ +/*data type for driver */ +/******************************************** */ + +enum { + OPERATION_MODE_POWERDOWN, + OPERATION_MODE_MEASUREMENT, + OPERATION_MODE_LOWPOWER_MEASUREMENT, + OPERATION_MODE_FUSEROMACCESS, + OPERATION_MODE_SUSPEND +}; + +struct hall_srs { + char name[12]; + uint8_t value; + bool bias; + uint32_t ratio; +}; + +/* ********************************************************* */ +/* Need to set parameter for ist8801 driver */ +/* ********************************************************* */ +#define CURRENT_LOAD_UA (100000) +#define IST8801_INTERRUPT_TYPE IST8801_VAL_INTSRS_INTTYPE_BESIDE +#define IST8801_PERSISTENCE_COUNT IST8801_VAL_PERSINT_COUNT(2) +#define IST8801_SENSITIVITY_TYPE 0 +#define IST8801_DETECTION_MODE IST8801_DETECTION_MODE_INTERRUPT +#define IST8801_REG_NUM (16) +#define FREQUENCY IST8801_VAL_OPF_FREQ_20HZ +#define LOWPOWER_FREQUENCY IST8801_VAL_OPF_FREQ_40HZ +#define DYNAMIC_GAIN_ADC_BIT (GAIN_4_TIME | ADC_RES_10_BIT) +#define ENABLE_FILTER 0 +#define FILTER_MODE 0 +#define DISABLE_TEMP_CONPEN 0 +/* ********************************************************* */ + + +union ist8801_reg_t { + struct { + unsigned char persint; + unsigned char intsrs; + unsigned char lthl; + unsigned char lthh; + unsigned char hthl; + unsigned char hthh; + unsigned char i2cdis; + unsigned char srst; + unsigned char opf; + unsigned char did; + unsigned char info; + unsigned char asa; + unsigned char st1; + unsigned char hsl; + unsigned char hsh; + unsigned char range; + } map; + unsigned char array[IST8801_REG_NUM]; +}; + + +struct ist8801_data_t { + struct i2c_client *client; + struct pinctrl *pctrl; + struct pinctrl_state *power_state; + struct pinctrl_state *irq_state; + union ist8801_reg_t reg; + bool irq_enabled; + unsigned int id; + int calibrated_data; + int irq_source; + short value_30degree; + short value_70degree; + short thrhigh; + short thrlow; + bool last_state; + struct delayed_work work; + struct device *dev; + struct input_dev *input_dev; + struct regulator *power_1v8; + struct regulator *power_2v8; + int irq_gpio; + int irq; + unsigned int power_gpio; + bool is_power_on; + bool enable_hidden; + unsigned int bias_ratio; + uint8_t origin_gain; + uint8_t origin_osr; + uint8_t origin_info; + struct wakeup_source source; +}; +/* ********************************************************* */ + +#endif /* __IST8801_H__ */ diff --git a/drivers/misc/tri_state_key/ist_hall_ic/hall_ist8801_down.c b/drivers/misc/tri_state_key/ist_hall_ic/hall_ist8801_down.c new file mode 100644 index 000000000000..b31fba008e2d --- /dev/null +++ b/drivers/misc/tri_state_key/ist_hall_ic/hall_ist8801_down.c @@ -0,0 +1,1098 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2018-2020 Oplus. All rights reserved. + * File: oplus_tri_key.c + * + * Description: + * Definitions for m1120 tri_state_key data process. + * + * Version: 1.0 + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "hall_ist8801.h" +#include "../oplus_tri_key.h" + +#define IST8801_I2C_BUF_SIZE (17) + +#define HALL_IST8801_DOWN "oplus,hall-ist8801,down" +#define TRI_KEY_TAG "[tri_state_key] " +#define TRI_KEY_ERR(fmt, args...)\ + pr_info(TRI_KEY_TAG" %s : "fmt, __func__, ##args) +#define TRI_KEY_LOG(fmt, args...)\ + pr_info(TRI_KEY_TAG" %s : "fmt, __func__, ##args) + +static struct ist8801_data_t *g_ist8801_data; + +static struct hall_srs ist8801_ranges_1[] = { + {"40mT", GAIN_2_TIME, false, 0}, + {"35mT", GAIN_2_TIME, false, 10}, + {"20mT", GAIN_2_TIME, false, 28}, + {"15mT", GAIN_4_TIME, false, 17}, + {"10mT", GAIN_8_TIME, false, 0}, +}; + +static struct hall_srs ist8801_ranges_2[] = { + {"40mT", GAIN_2_TIME, false, 0}, + {"35mT", GAIN_2_TIME, false, 6}, + {"20mT", GAIN_2_TIME, false, 24}, + {"15mT", GAIN_4_TIME, false, 13}, + {"10mT", GAIN_8_TIME, false, 0}, +}; + + +static DEFINE_MUTEX(ist8801_i2c_mutex); +__attribute__((weak)) void ist8801_reconfig(struct ist8801_data_t *chip) {return; } + +static int ist8801_i2c_read_block(struct ist8801_data_t *ist8801_data, + u8 addr, u8 *data, u8 len) +{ + u8 reg_addr = addr; + int err = 0; + struct i2c_client *client = ist8801_data->client; + struct i2c_msg msgs[2] = {{0}, {0}}; + + if (!client) { + TRI_KEY_ERR("client null\n"); + return -EINVAL; + } else if (len >= IST8801_I2C_BUF_SIZE) { + TRI_KEY_ERR(" length %d exceeds %d\n", + len, IST8801_I2C_BUF_SIZE); + return -EINVAL; + } + mutex_lock(&ist8801_i2c_mutex); + + msgs[0].addr = client->addr; + msgs[0].flags = 0; + msgs[0].len = 1; + msgs[0].buf = ®_addr; + + msgs[1].addr = client->addr; + msgs[1].flags = I2C_M_RD; + msgs[1].len = len; + msgs[1].buf = data; + + err = i2c_transfer(client->adapter, msgs, + ARRAY_SIZE(msgs)); + + if (err < 0) { + TRI_KEY_ERR("i2c_transfer error: (%d %p %d) %d\n", + addr, data, len, err); + err = -EIO; + } else + err = 0; + mutex_unlock(&ist8801_i2c_mutex); + + return err; +} + +static int ist8801_i2c_write_block(struct ist8801_data_t *ist8801_data, + u8 addr, u8 *data, u8 len) +{ + int err = 0; + int idx = 0; + int num = 0; + char buf[IST8801_I2C_BUF_SIZE] = {0}; + struct i2c_client *client = ist8801_data->client; + + if (!client) { + TRI_KEY_ERR("client null\n"); + return -EINVAL; + } else if (len >= IST8801_I2C_BUF_SIZE) { + TRI_KEY_ERR(" length %d exceeds %d\n", + len, IST8801_I2C_BUF_SIZE); + return -EINVAL; + } + + mutex_lock(&ist8801_i2c_mutex); + + buf[num++] = addr; + for (idx = 0; idx < len; idx++) + buf[num++] = data[idx]; + + err = i2c_master_send(client, buf, num); + if (err < 0) + TRI_KEY_ERR("send command error!! %d\n", err); + + if (len == 1) { + switch (addr) { + case IST8801_REG_PERSINT: + ist8801_data->reg.map.persint = data[0]; + break; + case IST8801_REG_INTSRS: + ist8801_data->reg.map.intsrs = data[0]; + break; + case IST8801_REG_LTHL: + ist8801_data->reg.map.lthl = data[0]; + break; + case IST8801_REG_LTHH: + ist8801_data->reg.map.lthh = data[0]; + break; + case IST8801_REG_HTHL: + ist8801_data->reg.map.hthl = data[0]; + break; + case IST8801_REG_HTHH: + ist8801_data->reg.map.hthh = data[0]; + break; + case IST8801_REG_I2CDIS: + ist8801_data->reg.map.i2cdis = data[0]; + break; + case IST8801_REG_SRST: + ist8801_data->reg.map.srst = data[0]; + break; + case IST8801_REG_OPF: + ist8801_data->reg.map.opf = data[0]; + break; + } + } + + mutex_unlock(&ist8801_i2c_mutex); + return err; +} + +static void ist8801_short_to_2byte(struct ist8801_data_t *ist8801_data, + short x, u8 *hbyte, u8 *lbyte) +{ + unsigned short temp; + + if (x >= 0) + temp = x; + else + temp = 65536 + x; + + *lbyte = temp & 0x00ff; + *hbyte = (temp & 0xff00) >> 8; +} + +static short ist8801_2byte_to_short(struct ist8801_data_t *ist8801_data, + u8 hbyte, u8 lbyte) +{ + short x = 0; + + x = (short) ((hbyte << 8) | lbyte); + + return x; +} +#if ENABLE_FILTER +static void moving_average_0(u8 *data_hi, u8 *data_lo, u8 mode) +{ + static int first_0; + int x, y; + static int temp_0; + + x = 0; + y = 0; + x = (int) ist8801_2byte_to_short(NULL, *data_hi, *data_lo); + + if (!first_0) { + if (mode == 0) { + y = x; + temp_0 = 4*x; + } else { + y = x; + temp_0 = 2*x; + } + } else { + if (mode == 0) { + temp_0 = (temp_0>>2) + 3*x; + y = temp_0 >> 2; + } else { + temp_0 = 2*x + temp_0; + y = temp_0 >> 2; + temp_0 = temp_0 >> 1; + } + } + + first_0 = 1; + + if (y > 32767) + y = 32767; + else if (y <= -32768) + y = -32768; + + ist8801_short_to_2byte(NULL, (short) y, data_hi, data_lo); +} + +#endif + +static int ist8801_get_id(struct ist8801_data_t *ist8801_data) +{ + u8 data = 0; + + ist8801_i2c_read_block(ist8801_data, IST8801_REG_DID, &data, 1); + TRI_KEY_LOG("id = 0x%x\n", data); + + return data; +} + +static int ist8801_get_data(short *data) +{ + int err = 0; + u8 buf[3] = {0}; + short value = 0; + static short pre_value; + + if (g_ist8801_data == NULL) { + TRI_KEY_LOG("g_ist8801_data NULL\n"); + return -EINVAL; + } + + err = ist8801_i2c_read_block(g_ist8801_data, + IST8801_REG_ST1, buf, sizeof(buf)); + if (err < 0) { + TRI_KEY_LOG("fail %d\n", err); + return err; + } + + if ((buf[0] & 0x01) | (buf[0] & 0x4)) { +#if ENABLE_FILTER + moving_average_0(&buf[2], &buf[1], FILTER_MODE); +#endif + + value = ist8801_2byte_to_short(g_ist8801_data, buf[2], buf[1]); + } else { + *data = pre_value; + return err; + } + + *data = value; + pre_value = value; + + return 0; +} + +static void ist8801_dump_reg(u8 *buf) +{ + int i, err; + u8 val; + u8 buffer[512] = {0}; + u8 _buf[20] = {0}; + + if (g_ist8801_data == NULL) { + TRI_KEY_LOG("g_ist8801_data NULL\n"); + return; + } + + for (i = 0; i <= 0x12; i++) { + memset(_buf, 0, sizeof(_buf)); + + err = ist8801_i2c_read_block(g_ist8801_data, i, &val, 1); + if (err < 0) { + sprintf(buf, "read reg error!\n"); + return; + } + + sprintf(_buf, "reg 0x%x:0x%x\n", i, val); + strcat(buffer, _buf); + } + + err = ist8801_i2c_read_block(g_ist8801_data, 0x54, &val, 1); + if (err < 0) { + sprintf(buf, "read reg error!\n"); + return; + } + sprintf(_buf, "reg 0x%x:0x%x\n", 0x54, val); + strcat(buffer, _buf); + + sprintf(buf, "%s\n", buffer); + TRI_KEY_LOG("%s\n", buf); +} + +static int ist8801_set_reg(int reg, int val) +{ + u8 data = (u8)val; + + if (g_ist8801_data == NULL) { + TRI_KEY_LOG("g_ist8801_data NULL\n"); + return -EINVAL; + } + + ist8801_i2c_write_block(g_ist8801_data, (u8)reg, &data, 1); + + return 0; +} + + +static bool ist8801_is_power_on(void) +{ + if (g_ist8801_data == NULL) { + TRI_KEY_LOG("g_ist8801_data NULL\n"); + return false; + } + + return g_ist8801_data->is_power_on; +} + +static int ist8801_set_power(struct ist8801_data_t *ist8801_data, bool on) +{ + int ret = 0; + + if (IS_ERR_OR_NULL(ist8801_data->power_2v8)) { + TRI_KEY_ERR("vdd_2v8 invalid\n"); + return -EINVAL; + } + + if (IS_ERR_OR_NULL(ist8801_data->power_1v8)) { + TRI_KEY_ERR("vdd1v8 invalid\n"); + return -EINVAL; + } + + if (on) { + if (regulator_count_voltages(ist8801_data->power_2v8) > 0) { + ret = regulator_set_voltage(ist8801_data->power_2v8, + 2856000, 3104000); + if (ret) { + TRI_KEY_LOG("Regulator failed vdd\n", ret); + return ret; + } + + ret = regulator_set_load(ist8801_data->power_2v8, + CURRENT_LOAD_UA); + if (ret) { + TRI_KEY_LOG("Regulator failed vdd\n"); + return ret; + } + } + if (regulator_count_voltages(ist8801_data->power_1v8) > 0) { + ret = regulator_set_voltage(ist8801_data->power_1v8, + 1800000, 1800000); + if (ret) { + TRI_KEY_LOG("Regulator failed vcc_i2c\n"); + return ret; + } + } + + ret = regulator_enable(ist8801_data->power_2v8); + if (ret) { + TRI_KEY_LOG("Regulator vdd enable failed\n"); + return ret; + } + + msleep(20); + + ret = regulator_enable(ist8801_data->power_1v8); + if (ret) { + TRI_KEY_LOG("Regulator vcc_i2c enable failed\n"); + regulator_disable(ist8801_data->power_2v8); + return ret; + } + + ist8801_data->is_power_on = true; + + } else { + ret = regulator_disable(ist8801_data->power_1v8); + if (ret) { + TRI_KEY_LOG("Regulator vcc_i2c disable failed\n"); + ret = regulator_enable(ist8801_data->power_2v8); + return ret; + } + + msleep(20); + ret = regulator_disable(ist8801_data->power_2v8); + if (ret) { + TRI_KEY_LOG("Regulator vdd disable failed\n"); + return ret; + } + } + + return 0; +} + +static int ist8801_clear_interrupt(struct ist8801_data_t *ist8801_data) +{ + int ret = 0; + + u8 data = ist8801_data->reg.map.persint | 0x01; + + ret = ist8801_i2c_write_block(ist8801_data, + IST8801_REG_PERSINT, &data, 1); + + ist8801_data->reg.map.persint = ist8801_data->reg.map.persint & 0xfe; + data = ist8801_data->reg.map.persint; + + ret = ist8801_i2c_write_block(ist8801_data, + IST8801_REG_PERSINT, &data, 1); + + return ret; +} + +/* + *IST8801_ADC_BIT_NUM + *8-bit:0x10 : threshold range: 127~-128 + *9-bit:0x0e : threshold range: 255~-256 + *10-bit:0x0c : threshold range: 511~-512 + *11-bit:0x0a : threshold range: 1023~-1024 + *12-bit:0x08 : threshold range: 2047~-2048 + *13-bit:0x06 : threshold range: 4095~-4096 + *14-bit:0x04 : threshold range: 8191~-8192 + *15-bit:0x02 : threshold range: 16383~-16384 + *16-bit: other : threshold range: 32767~-32768 + */ +static bool ist8801_down_update_threshold(int position, + short lowthd, short highthd) +{ + u8 lthh, lthl, hthh, hthl; + int err = 0; + + if (g_ist8801_data == NULL) { + TRI_KEY_LOG("g_ist8801_data NULL\n"); + return -EINVAL; + } + + TRI_KEY_LOG("low:%d, high:%d\n", lowthd, highthd); + + err = ist8801_clear_interrupt(g_ist8801_data); + + if (g_ist8801_data->reg.map.intsrs & IST8801_DETECTION_MODE_INTERRUPT) { + ist8801_short_to_2byte(g_ist8801_data, highthd, &hthh, &hthl); + ist8801_short_to_2byte(g_ist8801_data, lowthd, <hh, <hl); + + err |= ist8801_i2c_write_block(g_ist8801_data, + IST8801_REG_HTHH, &hthh, 1); + err |= ist8801_i2c_write_block(g_ist8801_data, + IST8801_REG_HTHL, &hthl, 1); + err |= ist8801_i2c_write_block(g_ist8801_data, + IST8801_REG_LTHH, <hh, 1); + err |= ist8801_i2c_write_block(g_ist8801_data, + IST8801_REG_LTHL, <hl, 1); + } + + if (err < 0) { + TRI_KEY_ERR("fail %d\n", err); + return false; + } else { + return true; + } +} + +static int ist8801_set_operation_mode(struct ist8801_data_t *ist8801_data, + int mode) +{ + u8 opf = 0; + int ret = 0; + u8 ifcntl = 0; + + switch (mode) { + case OPERATION_MODE_POWERDOWN: + opf = 0; + ifcntl = 0; + ret = ist8801_i2c_write_block(ist8801_data, + IST8801_REG_OPF, &opf, 1); + + ret = ist8801_i2c_read_block(ist8801_data, + IST8801_REG_IFCNTL, &ifcntl, 1); + ifcntl |= 0x04; + ret = ist8801_i2c_write_block(ist8801_data, + IST8801_REG_IFCNTL, &ifcntl, 1); + TRI_KEY_ERR("operation ERATION_MODE_POWERDOWN\n"); + break; + case OPERATION_MODE_MEASUREMENT: + opf = 0x00; + TRI_KEY_ERR("opf = 0x%x\n", opf); + + ret = ist8801_i2c_write_block(ist8801_data, + IST8801_REG_ACTION, &opf, 1); + + usleep_range(5000, 5100); + + opf = 0x00; + ret = ist8801_i2c_write_block(ist8801_data, + IST8801_REG_OPF, &opf, 1); + + ret = ist8801_i2c_read_block(ist8801_data, + IST8801_REG_IFCNTL, &ifcntl, 1); + ifcntl |= 0x04; + ret = ist8801_i2c_write_block(ist8801_data, + IST8801_REG_IFCNTL, &ifcntl, 1); + + opf = FREQUENCY; + TRI_KEY_ERR("opf = 0x%x\n", opf); + ret = ist8801_i2c_write_block(ist8801_data, + IST8801_REG_OPF, &opf, 1); + TRI_KEY_ERR("=OPERATION_MODE_MEASUREMENT\n"); + break; + case OPERATION_MODE_LOWPOWER_MEASUREMENT: + opf = 0x00; + TRI_KEY_ERR("opf = 0x%x\n", opf); + + ret = ist8801_i2c_write_block(ist8801_data, + IST8801_REG_ACTION, &opf, 1); + + usleep_range(5000, 5100); + + opf = 0x00; + ret = ist8801_i2c_write_block(ist8801_data, + IST8801_REG_OPF, &opf, 1); + + ret = ist8801_i2c_read_block(ist8801_data, + IST8801_REG_IFCNTL, &ifcntl, 1); + ifcntl |= 0x04; + ret = ist8801_i2c_write_block(ist8801_data, + IST8801_REG_IFCNTL, &ifcntl, 1); + + opf = LOWPOWER_FREQUENCY; + TRI_KEY_ERR("opf = 0x%x\n", opf); + ret = ist8801_i2c_write_block(ist8801_data, + IST8801_REG_OPF, &opf, 1); + TRI_KEY_ERR("operation mode LOWPOWER_MEASUREMENT\n"); + break; + + case OPERATION_MODE_SUSPEND: + opf = 0x00; + TRI_KEY_ERR("opf = 0x%x\n", opf); + ret = ist8801_i2c_write_block(ist8801_data, + IST8801_REG_OPF, &opf, 1); + + ret = ist8801_i2c_read_block(ist8801_data, + IST8801_REG_IFCNTL, &ifcntl, 1); + ifcntl |= 0x04; + ret = ist8801_i2c_write_block(ist8801_data, + IST8801_REG_IFCNTL, &ifcntl, 1); + + opf = 0x02; + TRI_KEY_ERR("opf = 0x%x\n", opf); + + ret = ist8801_i2c_write_block(ist8801_data, + IST8801_REG_ACTION, &opf, 1); + TRI_KEY_ERR("operation mode :OPERATION_MODE_SUSPEND\n"); + + usleep_range(5000, 5100); + break; + } + + TRI_KEY_ERR("opf = 0x%x\n", opf); + + return ret; +} + + +/* functions for interrupt handler */ +static irqreturn_t ist8801_down_irq_handler(int irq, void *dev_id) +{ + TRI_KEY_LOG("call\n"); + + if (!g_ist8801_data) { + TRI_KEY_LOG("g_ist8801_data NULL\n"); + return -EINVAL; + } + + disable_irq_nosync(g_ist8801_data->irq); + __pm_wakeup_event(&g_ist8801_data->source, 2000); + oplus_hall_irq_handler(1); + + return IRQ_HANDLED; +} + +static int ist8801_setup_eint(struct ist8801_data_t *ist8801_data) +{ + int ret = 0; + + if (gpio_is_valid(ist8801_data->irq_gpio)) { + ret = gpio_request(ist8801_data->irq_gpio, "ist8801_down_irq"); + if (ret) + TRI_KEY_LOG("unable to request gpio [%d]\n", + ist8801_data->irq_gpio); + else { + ret = gpio_direction_input(ist8801_data->irq_gpio); + msleep(50); + ist8801_data->irq = gpio_to_irq(ist8801_data->irq_gpio); + } + } + TRI_KEY_ERR("GPIO %d irq:%d\n", ist8801_data->irq_gpio, + ist8801_data->irq); + + return 0; +} + +static int ist8801_set_detection_mode(u8 mode) +{ + u8 data = 0; + int err = 0; + + if (g_ist8801_data == NULL) { + TRI_KEY_LOG("g_ist8801_data NULL\n"); + return -EINVAL; + } + + TRI_KEY_LOG("ist8801 detection mode : %s\n", + (mode == 0) ? "POLLING":"INTERRUPT"); + + if (mode & DETECTION_MODE_INTERRUPT) { + if (!g_ist8801_data->irq_enabled) { + data = g_ist8801_data->reg.map.intsrs | + IST8801_DETECTION_MODE_INTERRUPT; + err = ist8801_i2c_write_block(g_ist8801_data, + IST8801_REG_INTSRS, &data, 1); + if (err < 0) { + TRI_KEY_ERR("config interrupt fail %d\n", err); + return err; + } + + err = ist8801_clear_interrupt(g_ist8801_data); + if (err < 0) { + TRI_KEY_ERR("clear interrupt fail %d\n", err); + return err; + } + + /* request irq */ + err = request_threaded_irq(g_ist8801_data->irq, NULL, + &ist8801_down_irq_handler, + IRQ_TYPE_LEVEL_LOW | IRQF_ONESHOT, + "ist8801_down", (void *)g_ist8801_data->client); + if (err < 0) { + TRI_KEY_ERR("IRQ LINE NOT AVAILABLE!!\n"); + return -EINVAL; + } + irq_set_irq_wake(g_ist8801_data->irq, 1); + + g_ist8801_data->irq_enabled = 1; + } + } else { + if (g_ist8801_data->irq_enabled) { + data = g_ist8801_data->reg.map.intsrs & + (0xFF - IST8801_DETECTION_MODE_INTERRUPT); + + err = ist8801_i2c_write_block(g_ist8801_data, + IST8801_REG_INTSRS, &data, 1); + if (err < 0) { + TRI_KEY_ERR("config interrupt fail %d\n", err); + return err; + } + + disable_irq(g_ist8801_data->irq); + free_irq(g_ist8801_data->irq, NULL); + + g_ist8801_data->irq_enabled = 0; + } + } + + return 0; +} + +static int ist8801_enable_irq(bool enable) +{ + if (g_ist8801_data == NULL) { + TRI_KEY_LOG("g_ist8801_data NULL\n"); + return -EINVAL; + } + + if (enable) + enable_irq(g_ist8801_data->irq); + else + disable_irq_nosync(g_ist8801_data->irq); + return 0; +} + +static int ist8801_clear_irq(void) +{ + if (g_ist8801_data == NULL) { + TRI_KEY_LOG("g_ist8801_data NULL =\n"); + return -EINVAL; + } + + ist8801_clear_interrupt(g_ist8801_data); + + return 0; +} + +static int ist8801_get_irq_state(void) +{ + if (g_ist8801_data == NULL) { + TRI_KEY_LOG("g_ist8801_data NULL =\n"); + return -EINVAL; + } + + return ((g_ist8801_data->reg.map.intsrs & + IST8801_DETECTION_MODE_INTERRUPT) ? 1 : 0); +} + +static void ist8801_set_sensitivity(char *value) +{ + int i = 0; + uint8_t rwdata; + struct hall_srs *srs = NULL, *ist8801_ranges = NULL; + int len1 = 0, len2 = 0, len = 0; + uint8_t temp_opf, err; + + if (g_ist8801_data == NULL) { + TRI_KEY_LOG("g_ist8801_data NULL\n"); + return; + } + + + len1 = sizeof(ist8801_ranges_1)/sizeof(struct hall_srs); + len2 = sizeof(ist8801_ranges_2)/sizeof(struct hall_srs); + + if (g_ist8801_data->origin_info == 0x01) { + len = len1; + ist8801_ranges = ist8801_ranges_1; + } else { + len = len2; + ist8801_ranges = ist8801_ranges_2; + } + + for (i = 0; i < len; i++) { + srs = &ist8801_ranges[i]; + if (!strncmp(srs->name, value, strlen(srs->name))) + break; + } + if (i == len) + srs = NULL; + + if (!srs) { + TRI_KEY_ERR("%s not match\n", value); + return; + } + temp_opf = 0x00; + err = ist8801_i2c_read_block(g_ist8801_data, + IST8801_REG_OPF, &temp_opf, 1); + + rwdata = 0x00; + ist8801_i2c_write_block(g_ist8801_data, IST8801_REG_OPF, &rwdata, 1); + + err = ist8801_i2c_read_block(g_ist8801_data, + IST8801_REG_IFCNTL, &rwdata, 1); + rwdata |= 0x04; + ist8801_i2c_write_block(g_ist8801_data, IST8801_REG_IFCNTL, &rwdata, 1); + + rwdata = ((DYNAMIC_GAIN_ADC_BIT & 0x1E) | srs->value); + ist8801_i2c_write_block(g_ist8801_data, IST8801_REG_CNTL2, &rwdata, 1); + + TRI_KEY_LOG("set sensitivity IST8801_REG_CNTL2 = 0x%x\n", rwdata); + + rwdata = 0; + ist8801_i2c_read_block(g_ist8801_data, IST8801_REG_CNTL2, &rwdata, 1); + + TRI_KEY_LOG("get sensitivity IST8801_REG_CNTL2 = 0x%x\n", rwdata); + + rwdata = ((uint8_t) srs->ratio) + g_ist8801_data->origin_gain; + TRI_KEY_LOG("set sensitivity IST8801_REG_GAINCNTL = %d\n", rwdata); + + ist8801_i2c_write_block(g_ist8801_data, + IST8801_REG_GAINCNTL, &rwdata, 1); + + rwdata = 0; + err = ist8801_i2c_read_block(g_ist8801_data, + IST8801_REG_GAINCNTL, &rwdata, 1); + + TRI_KEY_LOG("get sensitivity IST8801_REG_GAINCNTL = %d\n", rwdata); + + rwdata = temp_opf; + ist8801_i2c_write_block(g_ist8801_data, IST8801_REG_OPF, &rwdata, 1); +} +/* + *IST8801_ADC_BIT_NUM + *8-bit:0x10 + *9-bit:0x0e + *10-bit:0x0c + *11-bit:0x0a + *12-bit:0x08 + *13-bit:0x06 + *14-bit:0x04 + *15-bit:0x02 + *16-bit: other + */ +static int ist8801_reset_device(struct ist8801_data_t *ist8801_data) +{ + int err = 0; + u8 data = 0; + + data = IST8801_VAL_SRST_RESET; + err = ist8801_i2c_write_block(ist8801_data, IST8801_REG_SRST, &data, 1); + + if (err < 0) { + TRI_KEY_ERR("sw-reset failed(%d)", err); + return err; + } + msleep(20); + + err = ist8801_i2c_read_block(ist8801_data, IST8801_REG_DID, &data, 1); + if (err < 0) { + TRI_KEY_ERR("read IST8801_REG_DID failed(%d)", err); + return err; + } + if (data != IST8801_VAL_DID) { + TRI_KEY_ERR("current device id(0x%02X)", data, + "is not IST8801 device id(0x%02X)", + IST8801_VAL_DID); + } + + data = 0x04; + err = ist8801_i2c_write_block(ist8801_data, + IST8801_REG_TSTCNTL, &data, 1); + + data = 0x05; + err = ist8801_i2c_write_block(ist8801_data, + IST8801_REG_OSRCNTL, &data, 1); + + data = 0x00; + ist8801_i2c_read_block(ist8801_data, IST8801_REG_GAINCNTL, &data, 1); + ist8801_data->origin_gain = data; + + TRI_KEY_LOG("ist8801_data->origin_gain = %d\n", + ist8801_data->origin_gain); + + data = 0x00; + ist8801_i2c_read_block(ist8801_data, IST8801_REG_OSRCNTL, &data, 1); + ist8801_data->origin_osr = data; + + TRI_KEY_LOG("ist8801_data->origin_osr = %d\n", + ist8801_data->origin_osr); + + data = 0x00; + ist8801_i2c_read_block(ist8801_data, IST8801_REG_INFO, &data, 1); + ist8801_data->origin_info = data; + + TRI_KEY_LOG("ist8801_data->origin_info = %d\n", + ist8801_data->origin_info); + + ist8801_data->reg.map.persint = IST8801_PERSISTENCE_COUNT; + data = ist8801_data->reg.map.persint; + err = ist8801_i2c_write_block(ist8801_data, + IST8801_REG_PERSINT, &data, 1); + + + ist8801_data->reg.map.intsrs = IST8801_DETECTION_MODE | + ist8801_data->reg.map.range; + if (ist8801_data->reg.map.intsrs & IST8801_DETECTION_MODE_INTERRUPT) + ist8801_data->reg.map.intsrs |= IST8801_INTERRUPT_TYPE; + + data = ist8801_data->reg.map.intsrs; + err = ist8801_i2c_write_block(ist8801_data, + IST8801_REG_INTSRS, &data, 1); + +#if DISABLE_TEMP_CONPEN + data = 0x01; + err = ist8801_i2c_write_block(ist8801_data, + IST8801_REG_CHIP_TEST, &data, 1); + if (err < 0) { + TRI_KEY_ERR("IST8801_REG_CHIP_TEST failed(%d)", err); + return err; + } +#endif + err = ist8801_set_operation_mode(ist8801_data, + OPERATION_MODE_MEASUREMENT); + if (err < 0) { + TRI_KEY_ERR("ist8801_set_operation_mode was failed(%d)", err); + return err; + } + + return err; +} + +static int ist8801_parse_dts(struct device *dev, struct ist8801_data_t *p_data) +{ + struct device_node *np = dev->of_node; + int rc = 0; + uint32_t data_range; + uint32_t value; + + rc = of_property_read_u32(np, "data-range", &data_range); + if (rc) { + p_data->reg.map.range = IST8801_SENSITIVITY_TYPE; + TRI_KEY_LOG("use default value:0x%x\n", + p_data->reg.map.range); + } else { + p_data->reg.map.range = (uint8_t)data_range; + TRI_KEY_LOG("data-range is 0x%x\n", p_data->reg.map.range); + } + + p_data->irq_gpio = of_get_named_gpio(np, "dhall,irq-gpio", 0); + + p_data->power_2v8 = regulator_get(&p_data->client->dev, "vdd"); + if (IS_ERR_OR_NULL(p_data->power_2v8)) { + TRI_KEY_ERR("Regulator get failed vdd_2v8\n"); + goto err; + } + + p_data->power_1v8 = regulator_get(&p_data->client->dev, "vio"); + if (IS_ERR_OR_NULL(p_data->power_1v8)) { + TRI_KEY_ERR("Regulator get failed vcc_1v8\n"); + goto err; + } + + p_data->pctrl = devm_pinctrl_get(&p_data->client->dev); + if (IS_ERR_OR_NULL(p_data->pctrl)) { + TRI_KEY_ERR("failed to get pinctrl\n"); + goto err; + } + + p_data->irq_state = pinctrl_lookup_state(p_data->pctrl, + "ist8801_hall_down_active"); + if (IS_ERR_OR_NULL(p_data->irq_state)) { + rc = PTR_ERR(p_data->irq_state); + TRI_KEY_ERR("pinctrl_lookup_state, err:%d\n", rc); + goto err; + } else { + pinctrl_select_state(p_data->pctrl, p_data->irq_state); + } + + p_data->enable_hidden = of_property_read_bool(np, "hall,bias_support"); + if (p_data->enable_hidden) { + rc = of_property_read_u32(np, "hall,bias-ratio", &value); + if (rc) + p_data->bias_ratio = 100; + else + p_data->bias_ratio = value; + } + return 0; +err: + return rc; +}; + +struct dhall_operations ist8801_down_ops = { + .get_data = ist8801_get_data, + .enable_irq = ist8801_enable_irq, + .clear_irq = ist8801_clear_irq, + .get_irq_state = ist8801_get_irq_state, + .set_detection_mode = ist8801_set_detection_mode, + .update_threshold = ist8801_down_update_threshold, + .dump_regs = ist8801_dump_reg, + .set_reg = ist8801_set_reg, + .is_power_on = ist8801_is_power_on, + .set_sensitivity = ist8801_set_sensitivity, +}; + +static int ist8801_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct ist8801_data_t *p_data = NULL; + struct extcon_dev_data *hall_dev = NULL; + u8 dev_id = 0xFF; + int err = 0; + + TRI_KEY_LOG("call\n"); + + p_data = devm_kzalloc(&client->dev, sizeof(struct ist8801_data_t), + GFP_KERNEL); + if (!p_data) { + TRI_KEY_ERR("kernel memory alocation was failed\n"); + return -ENOMEM; + } + + hall_dev = kzalloc(sizeof(struct extcon_dev_data), GFP_KERNEL); + if (!hall_dev) { + TRI_KEY_ERR("kernel memory alocation was failed\n"); + devm_kfree(&client->dev, p_data); + return -ENOMEM; + } + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + TRI_KEY_LOG("i2c unsupported\n"); + devm_kfree(&client->dev, p_data); + kfree(hall_dev); + return -EOPNOTSUPP; + } + p_data->client = client; + p_data->dev = &client->dev; + g_ist8801_data = p_data; + hall_dev->client = client; + i2c_set_clientdata(client, hall_dev); + hall_dev->dev = &client->dev; + if (client->dev.of_node) { + err = ist8801_parse_dts(&client->dev, p_data); + if (err) + TRI_KEY_ERR("failed to parse device tree\n"); + } + ist8801_reconfig(p_data); + + err = ist8801_set_power(p_data, 1); + + dev_id = ist8801_get_id(p_data); + if (dev_id != IST8801_VAL_DID) { + TRI_KEY_ERR("current device id(0x%02x)", dev_id, + "is not ist8801 device id(0x%02x)\n", + IST8801_VAL_DID); + goto fail; + } + + err = ist8801_reset_device(p_data); + if (err < 0) { + TRI_KEY_ERR("ist8801_reset_device fail\n"); + goto fail; + } + + err = ist8801_setup_eint(p_data); + + wakeup_source_add(&g_ist8801_data->source); + + ist8801_set_sensitivity("40mT"); + oplus_register_hall("hall_down", &ist8801_down_ops, hall_dev); + TRI_KEY_LOG("success.\n"); + return 0; +fail: + TRI_KEY_LOG("fail.\n"); + if (gpio_is_valid(p_data->irq_gpio)) + gpio_free(p_data->irq_gpio); + + devm_kfree(&client->dev, p_data); + kfree(hall_dev); + return -ENXIO; +} + +static int ist8801_i2c_remove(struct i2c_client *client) +{ + return 0; +} + +static const struct of_device_id ist8801_match[] = { + { .compatible = HALL_IST8801_DOWN, }, + {}, +}; + +static const struct i2c_device_id ist8801_id[] = { + {"hall_ist8801_down", 0 }, + {}, +}; + +/* + *static const struct dev_pm_ops ist8801_pm_ops = { + *.suspend = ist8801_i2c_suspend, + *.resume = ist8801_i2c_resume, + *}; + */ +struct i2c_driver ist8801_i2c_down_driver = { + .driver = { + .name = "hall-ist8801-down", + .of_match_table = ist8801_match, + }, + .probe = ist8801_i2c_probe, + .remove = ist8801_i2c_remove, + .id_table = ist8801_id, +}; + +static int __init ist8801_down_init(void) +{ + TRI_KEY_LOG("call\n"); + i2c_add_driver(&ist8801_i2c_down_driver); + return 0; +} +late_initcall(ist8801_down_init); + +static void __exit ist8801_down_exit(void) +{ + TRI_KEY_LOG("call\n"); + i2c_del_driver(&ist8801_i2c_down_driver); +} + +module_exit(ist8801_down_exit); + +MODULE_DESCRIPTION("ist8801 hallswitch driver"); +MODULE_LICENSE("GPL"); + diff --git a/drivers/misc/tri_state_key/ist_hall_ic/hall_ist8801_up.c b/drivers/misc/tri_state_key/ist_hall_ic/hall_ist8801_up.c new file mode 100644 index 000000000000..3916e7d18cb6 --- /dev/null +++ b/drivers/misc/tri_state_key/ist_hall_ic/hall_ist8801_up.c @@ -0,0 +1,1100 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2018-2020 Oplus. All rights reserved. + * File: oplus_tri_key.c + * + * Description: + * Definitions for m1120 tri_state_key data process. + * + * Version: 1.0 + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "hall_ist8801.h" +#include "../oplus_tri_key.h" + +#define IST8801_I2C_BUF_SIZE (17) + +#define HALL_IST8801_UP "oplus,hall-ist8801,up" +#define TRI_KEY_TAG "[tri_state_key] " +#define TRI_KEY_ERR(fmt, args...)\ + pr_info(TRI_KEY_TAG" %s : "fmt, __func__, ##args) +#define TRI_KEY_LOG(fmt, args...)\ + pr_info(TRI_KEY_TAG" %s : "fmt, __func__, ##args) + +static struct ist8801_data_t *g_ist8801_data; + +static struct hall_srs ist8801_ranges_1[] = { + {"40mT", GAIN_2_TIME, false, 0}, + {"35mT", GAIN_2_TIME, false, 10}, + {"20mT", GAIN_2_TIME, false, 28}, + {"15mT", GAIN_4_TIME, false, 17}, + {"10mT", GAIN_8_TIME, false, 0}, +}; + +static struct hall_srs ist8801_ranges_2[] = { + {"40mT", GAIN_2_TIME, false, 0}, + {"35mT", GAIN_2_TIME, false, 6}, + {"20mT", GAIN_2_TIME, false, 24}, + {"15mT", GAIN_4_TIME, false, 13}, + {"10mT", GAIN_8_TIME, false, 0}, +}; + + +static DEFINE_MUTEX(ist8801_i2c_mutex); +__attribute__((weak)) void ist8801_reconfig(struct ist8801_data_t *chip) { return; } + +static int ist8801_i2c_read_block(struct ist8801_data_t *ist8801_data, + u8 addr, u8 *data, u8 len) +{ + u8 reg_addr = addr; + int err = 0; + struct i2c_client *client = ist8801_data->client; + struct i2c_msg msgs[2] = {{0}, {0}}; + + if (!client) { + TRI_KEY_ERR("client null\n"); + return -EINVAL; + } else if (len >= IST8801_I2C_BUF_SIZE) { + TRI_KEY_ERR(" length %d exceeds %d\n", + len, IST8801_I2C_BUF_SIZE); + return -EINVAL; + } + mutex_lock(&ist8801_i2c_mutex); + + msgs[0].addr = client->addr; + msgs[0].flags = 0; + msgs[0].len = 1; + msgs[0].buf = ®_addr; + + msgs[1].addr = client->addr; + msgs[1].flags = I2C_M_RD; + msgs[1].len = len; + msgs[1].buf = data; + + err = i2c_transfer(client->adapter, msgs, + ARRAY_SIZE(msgs)); + + if (err < 0) { + TRI_KEY_ERR("i2c_transfer error: (%d %p %d) %d\n", + addr, data, len, err); + err = -EIO; + } else + err = 0; + mutex_unlock(&ist8801_i2c_mutex); + + return err; +} + +static int ist8801_i2c_write_block(struct ist8801_data_t *ist8801_data, + u8 addr, u8 *data, u8 len) +{ + int err = 0; + int idx = 0; + int num = 0; + char buf[IST8801_I2C_BUF_SIZE] = {0}; + struct i2c_client *client = ist8801_data->client; + + if (!client) { + TRI_KEY_ERR("client null\n"); + return -EINVAL; + } else if (len >= IST8801_I2C_BUF_SIZE) { + TRI_KEY_ERR(" length %d exceeds %d\n", + len, IST8801_I2C_BUF_SIZE); + return -EINVAL; + } + + mutex_lock(&ist8801_i2c_mutex); + + buf[num++] = addr; + for (idx = 0; idx < len; idx++) + buf[num++] = data[idx]; + + err = i2c_master_send(client, buf, num); + if (err < 0) + TRI_KEY_ERR("send command error!! %d\n", err); + + if (len == 1) { + switch (addr) { + case IST8801_REG_PERSINT: + ist8801_data->reg.map.persint = data[0]; + break; + case IST8801_REG_INTSRS: + ist8801_data->reg.map.intsrs = data[0]; + break; + case IST8801_REG_LTHL: + ist8801_data->reg.map.lthl = data[0]; + break; + case IST8801_REG_LTHH: + ist8801_data->reg.map.lthh = data[0]; + break; + case IST8801_REG_HTHL: + ist8801_data->reg.map.hthl = data[0]; + break; + case IST8801_REG_HTHH: + ist8801_data->reg.map.hthh = data[0]; + break; + case IST8801_REG_I2CDIS: + ist8801_data->reg.map.i2cdis = data[0]; + break; + case IST8801_REG_SRST: + ist8801_data->reg.map.srst = data[0]; + break; + case IST8801_REG_OPF: + ist8801_data->reg.map.opf = data[0]; + break; + } + } + + mutex_unlock(&ist8801_i2c_mutex); + return err; +} + +static void ist8801_short_to_2byte(struct ist8801_data_t *ist8801_data, + short x, u8 *hbyte, u8 *lbyte) +{ + unsigned short temp; + + if (x >= 0) + temp = x; + else + temp = 65536 + x; + + *lbyte = temp & 0x00ff; + *hbyte = (temp & 0xff00) >> 8; +} + +static short ist8801_2byte_to_short(struct ist8801_data_t *ist8801_data, + u8 hbyte, u8 lbyte) +{ + short x = 0; + + x = (short) ((hbyte << 8) | lbyte); + + return x; +} +#if ENABLE_FILTER +static void moving_average_1(u8 *data_hi, u8 *data_lo, u8 mode) +{ + static int first_1; + int x, y; + static int temp_1; + + x = 0; + y = 0; + x = (int) ist8801_2byte_to_short(NULL, *data_hi, *data_lo); + + if (!first_1) { + if (mode == 0) { + y = x; + temp_1 = 4*x; + } else { + y = x; + temp_1 = 2*x; + } + } else { + if (mode == 0) { + temp_1 = (temp_1>>2) + 3*x; + y = temp_1 >> 2; + } else { + temp_1 = 2*x + temp_1; + y = temp_1 >> 2; + temp_1 = temp_1 >> 1; + } + } + + first_1 = 1; + + if (y > 32767) + y = 32767; + else if (y <= -32768) + y = -32768; + + ist8801_short_to_2byte(NULL, (short) y, data_hi, data_lo); +} + +#endif + +static int ist8801_get_id(struct ist8801_data_t *ist8801_data) +{ + u8 data = 0; + + ist8801_i2c_read_block(ist8801_data, IST8801_REG_DID, &data, 1); + TRI_KEY_LOG("id = 0x%x\n", data); + + return data; +} + +static int ist8801_get_data(short *data) +{ + int err = 0; + u8 buf[3] = {0}; + short value = 0; + static short pre_value; + + if (g_ist8801_data == NULL) { + TRI_KEY_LOG("g_ist8801_data NULL\n"); + return -EINVAL; + } + + err = ist8801_i2c_read_block(g_ist8801_data, + IST8801_REG_ST1, buf, sizeof(buf)); + if (err < 0) { + TRI_KEY_LOG("fail %d\n", err); + return err; + } + + if ((buf[0] & 0x01) | (buf[0] & 0x4)) { +#if ENABLE_FILTER + moving_average_1(&buf[2], &buf[1], FILTER_MODE); +#endif + + value = ist8801_2byte_to_short(g_ist8801_data, buf[2], buf[1]); + } else { + *data = pre_value; + return err; + } + + *data = value; + pre_value = value; + + return 0; +} + +static void ist8801_dump_reg(u8 *buf) +{ + int i, err; + u8 val; + u8 buffer[512] = {0}; + u8 _buf[20] = {0}; + + if (g_ist8801_data == NULL) { + TRI_KEY_LOG("g_ist8801_data NULL\n"); + return; + } + + for (i = 0; i <= 0x12; i++) { + memset(_buf, 0, sizeof(_buf)); + + err = ist8801_i2c_read_block(g_ist8801_data, i, &val, 1); + if (err < 0) { + sprintf(buf, "read reg error!\n"); + return; + } + + sprintf(_buf, "reg 0x%x:0x%x\n", i, val); + strcat(buffer, _buf); + } + + err = ist8801_i2c_read_block(g_ist8801_data, 0x54, &val, 1); + if (err < 0) { + sprintf(buf, "read reg error!\n"); + return; + } + sprintf(_buf, "reg 0x%x:0x%x\n", 0x54, val); + strcat(buffer, _buf); + + sprintf(buf, "%s\n", (char*)buffer); + TRI_KEY_LOG("%s\n", buf); +} + +static int ist8801_set_reg(int reg, int val) +{ + u8 data = (u8)val; + + if (g_ist8801_data == NULL) { + TRI_KEY_LOG("g_ist8801_data NULL\n"); + return -EINVAL; + } + + ist8801_i2c_write_block(g_ist8801_data, (u8)reg, &data, 1); + + return 0; +} + + +static bool ist8801_is_power_on(void) +{ + if (g_ist8801_data == NULL) { + TRI_KEY_LOG("g_ist8801_data NULL\n"); + return false; + } + + return g_ist8801_data->is_power_on; +} + +static int ist8801_set_power(struct ist8801_data_t *ist8801_data, bool on) +{ + int ret = 0; + + if (IS_ERR_OR_NULL(ist8801_data->power_2v8)) { + TRI_KEY_ERR("vdd_2v8 invalid\n"); + return -EINVAL; + } + + if (IS_ERR_OR_NULL(ist8801_data->power_1v8)) { + TRI_KEY_ERR("vdd1v8 invalid\n"); + return -EINVAL; + } + + if (on) { + if (regulator_count_voltages(ist8801_data->power_2v8) > 0) { + ret = regulator_set_voltage(ist8801_data->power_2v8, + 2856000, 3104000); + if (ret) { + TRI_KEY_LOG("Regulator failed vdd\n", ret); + return ret; + } + + ret = regulator_set_load(ist8801_data->power_2v8, + CURRENT_LOAD_UA); + if (ret) { + TRI_KEY_LOG("Regulator failed vdd\n"); + return ret; + } + } + if (regulator_count_voltages(ist8801_data->power_1v8) > 0) { + ret = regulator_set_voltage(ist8801_data->power_1v8, + 1800000, 1800000); + if (ret) { + TRI_KEY_LOG("Regulator failed vcc_i2c\n"); + return ret; + } + } + ret = regulator_enable(ist8801_data->power_2v8); + if (ret) { + TRI_KEY_LOG("Regulator vdd enable failed\n"); + return ret; + } + + msleep(20); + + ret = regulator_enable(ist8801_data->power_1v8); + if (ret) { + TRI_KEY_LOG("Regulator vcc_i2c enable failed\n"); + regulator_disable(ist8801_data->power_2v8); + return ret; + } + + ist8801_data->is_power_on = true; + + } else { + ret = regulator_disable(ist8801_data->power_1v8); + if (ret) { + TRI_KEY_LOG("Regulator vcc_i2c disable failed\n"); + ret = regulator_enable(ist8801_data->power_2v8); + return ret; + } + + msleep(20); + ret = regulator_disable(ist8801_data->power_2v8); + if (ret) { + TRI_KEY_LOG("Regulator vdd disable failed\n"); + return ret; + } + } + + return 0; +} + +static int ist8801_clear_interrupt(struct ist8801_data_t *ist8801_data) +{ + int ret = 0; + + u8 data = ist8801_data->reg.map.persint | 0x01; + + ret = ist8801_i2c_write_block(ist8801_data, + IST8801_REG_PERSINT, &data, 1); + + ist8801_data->reg.map.persint = ist8801_data->reg.map.persint & 0xfe; + data = ist8801_data->reg.map.persint; + + ret = ist8801_i2c_write_block(ist8801_data, + IST8801_REG_PERSINT, &data, 1); + + return ret; +} + +/* + *IST8801_ADC_BIT_NUM + *8-bit:0x10 : threshold range: 127~-128 + *9-bit:0x0e : threshold range: 255~-256 + *10-bit:0x0c : threshold range: 511~-512 + *11-bit:0x0a : threshold range: 1023~-1024 + *12-bit:0x08 : threshold range: 2047~-2048 + *13-bit:0x06 : threshold range: 4095~-4096 + *14-bit:0x04 : threshold range: 8191~-8192 + *15-bit:0x02 : threshold range: 16383~-16384 + *16-bit: other : threshold range: 32767~-32768 + */ +static bool ist8801_up_update_threshold(int position, + short lowthd, short highthd) +{ + u8 lthh, lthl, hthh, hthl; + int err = 0; + + if (g_ist8801_data == NULL) { + TRI_KEY_LOG("g_ist8801_data NULL\n"); + return -EINVAL; + } + + TRI_KEY_LOG("low:%d, high:%d\n", lowthd, highthd); + + err = ist8801_clear_interrupt(g_ist8801_data); + + if (g_ist8801_data->reg.map.intsrs & IST8801_DETECTION_MODE_INTERRUPT) { + ist8801_short_to_2byte(g_ist8801_data, highthd, &hthh, &hthl); + ist8801_short_to_2byte(g_ist8801_data, lowthd, <hh, <hl); + + err |= ist8801_i2c_write_block(g_ist8801_data, + IST8801_REG_HTHH, &hthh, 1); + err |= ist8801_i2c_write_block(g_ist8801_data, + IST8801_REG_HTHL, &hthl, 1); + err |= ist8801_i2c_write_block(g_ist8801_data, + IST8801_REG_LTHH, <hh, 1); + err |= ist8801_i2c_write_block(g_ist8801_data, + IST8801_REG_LTHL, <hl, 1); + } + + if (err < 0) { + TRI_KEY_ERR("fail %d\n", err); + return false; + } else { + return true; + } +} + +static int ist8801_set_operation_mode(struct ist8801_data_t *ist8801_data, + int mode) +{ + u8 opf = 0; + int ret = 0; + u8 ifcntl = 0; + + switch (mode) { + case OPERATION_MODE_POWERDOWN: + opf = 0; + ifcntl = 0; + ret = ist8801_i2c_write_block(ist8801_data, + IST8801_REG_OPF, &opf, 1); + + ret = ist8801_i2c_read_block(ist8801_data, + IST8801_REG_IFCNTL, &ifcntl, 1); + ifcntl |= 0x04; + ret = ist8801_i2c_write_block(ist8801_data, + IST8801_REG_IFCNTL, &ifcntl, 1); + TRI_KEY_ERR("operation ERATION_MODE_POWERDOWN\n"); + break; + case OPERATION_MODE_MEASUREMENT: + opf = 0x00; + TRI_KEY_ERR("opf = 0x%x\n", opf); + + ret = ist8801_i2c_write_block(ist8801_data, + IST8801_REG_ACTION, &opf, 1); + + usleep_range(5000, 5100); + + opf = 0x00; + ret = ist8801_i2c_write_block(ist8801_data, + IST8801_REG_OPF, &opf, 1); + + ret = ist8801_i2c_read_block(ist8801_data, + IST8801_REG_IFCNTL, &ifcntl, 1); + ifcntl |= 0x04; + ret = ist8801_i2c_write_block(ist8801_data, + IST8801_REG_IFCNTL, &ifcntl, 1); + + opf = FREQUENCY; + TRI_KEY_ERR("opf = 0x%x\n", opf); + ret = ist8801_i2c_write_block(ist8801_data, + IST8801_REG_OPF, &opf, 1); + TRI_KEY_ERR("=OPERATION_MODE_MEASUREMENT\n"); + break; + case OPERATION_MODE_LOWPOWER_MEASUREMENT: + opf = 0x00; + TRI_KEY_ERR("opf = 0x%x\n", opf); + + ret = ist8801_i2c_write_block(ist8801_data, + IST8801_REG_ACTION, &opf, 1); + + usleep_range(5000, 5100); + + opf = 0x00; + ret = ist8801_i2c_write_block(ist8801_data, + IST8801_REG_OPF, &opf, 1); + + ret = ist8801_i2c_read_block(ist8801_data, + IST8801_REG_IFCNTL, &ifcntl, 1); + ifcntl |= 0x04; + ret = ist8801_i2c_write_block(ist8801_data, + IST8801_REG_IFCNTL, &ifcntl, 1); + + opf = LOWPOWER_FREQUENCY; + TRI_KEY_ERR("opf = 0x%x\n", opf); + ret = ist8801_i2c_write_block(ist8801_data, + IST8801_REG_OPF, &opf, 1); + TRI_KEY_ERR("operation mode LOWPOWER_MEASUREMENT\n"); + break; + + case OPERATION_MODE_SUSPEND: + opf = 0x00; + TRI_KEY_ERR("opf = 0x%x\n", opf); + ret = ist8801_i2c_write_block(ist8801_data, + IST8801_REG_OPF, &opf, 1); + + ret = ist8801_i2c_read_block(ist8801_data, + IST8801_REG_IFCNTL, &ifcntl, 1); + ifcntl |= 0x04; + ret = ist8801_i2c_write_block(ist8801_data, + IST8801_REG_IFCNTL, &ifcntl, 1); + + opf = 0x02; + TRI_KEY_ERR("opf = 0x%x\n", opf); + + ret = ist8801_i2c_write_block(ist8801_data, + IST8801_REG_ACTION, &opf, 1); + TRI_KEY_ERR("operation mode :OPERATION_MODE_SUSPEND\n"); + + usleep_range(5000, 5100); + break; + } + + TRI_KEY_ERR("opf = 0x%x\n", opf); + + return ret; +} + + +/* functions for interrupt handler */ +static irqreturn_t ist8801_up_irq_handler(int irq, void *dev_id) +{ + TRI_KEY_LOG("call\n"); + + if (!g_ist8801_data) { + TRI_KEY_LOG("g_ist8801_data NULL\n"); + return -EINVAL; + } + + disable_irq_nosync(g_ist8801_data->irq); + __pm_wakeup_event(&g_ist8801_data->source, 2000); + oplus_hall_irq_handler(0); + + return IRQ_HANDLED; +} + +static int ist8801_setup_eint(struct ist8801_data_t *ist8801_data) +{ + int ret = 0; + + if (gpio_is_valid(ist8801_data->irq_gpio)) { + ret = gpio_request(ist8801_data->irq_gpio, "ist8801_up_irq"); + if (ret) + TRI_KEY_LOG("unable to request gpio [%d]\n", + ist8801_data->irq_gpio); + else { + ret = gpio_direction_input(ist8801_data->irq_gpio); + msleep(50); + ist8801_data->irq = gpio_to_irq(ist8801_data->irq_gpio); + } + } + TRI_KEY_ERR("GPIO %d irq:%d\n", ist8801_data->irq_gpio, + ist8801_data->irq); + + return 0; +} + +static int ist8801_set_detection_mode(u8 mode) +{ + u8 data = 0; + int err = 0; + + if (g_ist8801_data == NULL) { + TRI_KEY_LOG("g_ist8801_data NULL\n"); + return -EINVAL; + } + + TRI_KEY_LOG("ist8801 detection mode : %s\n", + (mode == 0) ? "POLLING":"INTERRUPT"); + + if (mode & DETECTION_MODE_INTERRUPT) { + if (!g_ist8801_data->irq_enabled) { + data = g_ist8801_data->reg.map.intsrs | + IST8801_DETECTION_MODE_INTERRUPT; + err = ist8801_i2c_write_block(g_ist8801_data, + IST8801_REG_INTSRS, &data, 1); + if (err < 0) { + TRI_KEY_ERR("config interrupt fail %d\n", err); + return err; + } + + err = ist8801_clear_interrupt(g_ist8801_data); + if (err < 0) { + TRI_KEY_ERR("clear interrupt fail %d\n", err); + return err; + } + + err = request_threaded_irq(g_ist8801_data->irq, NULL, + &ist8801_up_irq_handler, + IRQ_TYPE_LEVEL_LOW | IRQF_ONESHOT, + "ist8801_up", (void *)g_ist8801_data->client); + if (err < 0) { + TRI_KEY_ERR("IRQ LINE NOT AVAILABLE!!\n"); + return -EINVAL; + } + irq_set_irq_wake(g_ist8801_data->irq, 1); + + g_ist8801_data->irq_enabled = 1; + } + } else { + if (g_ist8801_data->irq_enabled) { + data = g_ist8801_data->reg.map.intsrs & + (0xFF - IST8801_DETECTION_MODE_INTERRUPT); + + err = ist8801_i2c_write_block(g_ist8801_data, + IST8801_REG_INTSRS, &data, 1); + if (err < 0) { + TRI_KEY_ERR("config interrupt fail %d\n", err); + return err; + } + + disable_irq(g_ist8801_data->irq); + free_irq(g_ist8801_data->irq, NULL); + + g_ist8801_data->irq_enabled = 0; + } + } + + return 0; +} + +static int ist8801_enable_irq(bool enable) +{ + if (g_ist8801_data == NULL) { + TRI_KEY_LOG("g_ist8801_data NULL\n"); + return -EINVAL; + } + + if (enable) + enable_irq(g_ist8801_data->irq); + else + disable_irq_nosync(g_ist8801_data->irq); + return 0; +} + +static int ist8801_clear_irq(void) +{ + if (g_ist8801_data == NULL) { + TRI_KEY_LOG("g_ist8801_data NULL =\n"); + return -EINVAL; + } + + ist8801_clear_interrupt(g_ist8801_data); + + return 0; +} + +static int ist8801_get_irq_state(void) +{ + if (g_ist8801_data == NULL) { + TRI_KEY_LOG("g_ist8801_data NULL =\n"); + return -EINVAL; + } + + return ((g_ist8801_data->reg.map.intsrs & + IST8801_DETECTION_MODE_INTERRUPT) ? 1 : 0); +} + +static void ist8801_set_sensitivity(char *value) +{ + int i = 0; + uint8_t rwdata; + struct hall_srs *srs = NULL, *ist8801_ranges = NULL; + int len1 = 0, len2 = 0, len = 0; + uint8_t temp_opf, err; + + if (g_ist8801_data == NULL) { + TRI_KEY_LOG("g_ist8801_data NULL\n"); + return; + } + + + len1 = sizeof(ist8801_ranges_1)/sizeof(struct hall_srs); + len2 = sizeof(ist8801_ranges_2)/sizeof(struct hall_srs); + + if (g_ist8801_data->origin_info == 0x01) { + len = len1; + ist8801_ranges = ist8801_ranges_1; + } else { + len = len2; + ist8801_ranges = ist8801_ranges_2; + } + + for (i = 0; i < len; i++) { + srs = &ist8801_ranges[i]; + if (!strncmp(srs->name, value, strlen(srs->name))) + break; + } + if (i == len) + srs = NULL; + + if (!srs) { + TRI_KEY_ERR("%s not match\n", value); + return; + } + + temp_opf = 0x00; + err = ist8801_i2c_read_block(g_ist8801_data, + IST8801_REG_OPF, &temp_opf, 1); + + rwdata = 0x00; + ist8801_i2c_write_block(g_ist8801_data, IST8801_REG_OPF, &rwdata, 1); + + err = ist8801_i2c_read_block(g_ist8801_data, + IST8801_REG_IFCNTL, &rwdata, 1); + rwdata |= 0x04; + ist8801_i2c_write_block(g_ist8801_data, IST8801_REG_IFCNTL, &rwdata, 1); + + rwdata = ((DYNAMIC_GAIN_ADC_BIT & 0x1E) | srs->value); + ist8801_i2c_write_block(g_ist8801_data, IST8801_REG_CNTL2, &rwdata, 1); + + TRI_KEY_LOG("set sensitivity IST8801_REG_CNTL2 = 0x%x\n", rwdata); + + rwdata = 0; + ist8801_i2c_read_block(g_ist8801_data, IST8801_REG_CNTL2, &rwdata, 1); + + TRI_KEY_LOG("get sensitivity IST8801_REG_CNTL2 = 0x%x\n", rwdata); + + rwdata = ((uint8_t) srs->ratio) + g_ist8801_data->origin_gain; + TRI_KEY_LOG("set sensitivity IST8801_REG_GAINCNTL = %d\n", rwdata); + + ist8801_i2c_write_block(g_ist8801_data, + IST8801_REG_GAINCNTL, &rwdata, 1); + + rwdata = 0; + err = ist8801_i2c_read_block(g_ist8801_data, + IST8801_REG_GAINCNTL, &rwdata, 1); + + TRI_KEY_LOG("get sensitivity IST8801_REG_GAINCNTL = %d\n", rwdata); + + rwdata = temp_opf; + ist8801_i2c_write_block(g_ist8801_data, IST8801_REG_OPF, &rwdata, 1); +} +/* + *IST8801_ADC_BIT_NUM + *8-bit:0x10 + *9-bit:0x0e + *10-bit:0x0c + *11-bit:0x0a + *12-bit:0x08 + *13-bit:0x06 + *14-bit:0x04 + *15-bit:0x02 + *16-bit: other + */ +static int ist8801_reset_device(struct ist8801_data_t *ist8801_data) +{ + int err = 0; + u8 data = 0; + + data = IST8801_VAL_SRST_RESET; + err = ist8801_i2c_write_block(ist8801_data, IST8801_REG_SRST, &data, 1); + + if (err < 0) { + TRI_KEY_ERR("sw-reset failed(%d)", err); + return err; + } + msleep(20); + + err = ist8801_i2c_read_block(ist8801_data, IST8801_REG_DID, &data, 1); + if (err < 0) { + TRI_KEY_ERR("read IST8801_REG_DID failed(%d)", err); + return err; + } + if (data != IST8801_VAL_DID) { + TRI_KEY_ERR("current device id(0x%02X)", data, + "is not IST8801 device id(0x%02X)", + IST8801_VAL_DID); + } + + data = 0x04; + err = ist8801_i2c_write_block(ist8801_data, + IST8801_REG_TSTCNTL, &data, 1); + + data = 0x05; + err = ist8801_i2c_write_block(ist8801_data, + IST8801_REG_OSRCNTL, &data, 1); + + data = 0x00; + ist8801_i2c_read_block(ist8801_data, IST8801_REG_GAINCNTL, &data, 1); + ist8801_data->origin_gain = data; + + TRI_KEY_LOG("ist8801_data->origin_gain = %d\n", + ist8801_data->origin_gain); + + data = 0x00; + ist8801_i2c_read_block(ist8801_data, IST8801_REG_OSRCNTL, &data, 1); + ist8801_data->origin_osr = data; + + TRI_KEY_LOG("ist8801_data->origin_osr = %d\n", + ist8801_data->origin_osr); + + data = 0x00; + ist8801_i2c_read_block(ist8801_data, IST8801_REG_INFO, &data, 1); + ist8801_data->origin_info = data; + + TRI_KEY_LOG("ist8801_data->origin_info = %d\n", + ist8801_data->origin_info); + + ist8801_data->reg.map.persint = IST8801_PERSISTENCE_COUNT; + data = ist8801_data->reg.map.persint; + err = ist8801_i2c_write_block(ist8801_data, + IST8801_REG_PERSINT, &data, 1); + + + ist8801_data->reg.map.intsrs = IST8801_DETECTION_MODE | + ist8801_data->reg.map.range; + if (ist8801_data->reg.map.intsrs & IST8801_DETECTION_MODE_INTERRUPT) + ist8801_data->reg.map.intsrs |= IST8801_INTERRUPT_TYPE; + + data = ist8801_data->reg.map.intsrs; + err = ist8801_i2c_write_block(ist8801_data, + IST8801_REG_INTSRS, &data, 1); + +#if DISABLE_TEMP_CONPEN + data = 0x01; + err = ist8801_i2c_write_block(ist8801_data, + IST8801_REG_CHIP_TEST, &data, 1); + if (err < 0) { + TRI_KEY_ERR("IST8801_REG_CHIP_TEST failed(%d)", err); + return err; + } +#endif + err = ist8801_set_operation_mode(ist8801_data, + OPERATION_MODE_MEASUREMENT); + if (err < 0) { + TRI_KEY_ERR("ist8801_set_operation_mode was failed(%d)", err); + return err; + } + + return err; +} + +static int ist8801_parse_dts(struct device *dev, struct ist8801_data_t *p_data) +{ + struct device_node *np = dev->of_node; + int rc = 0; + uint32_t data_range; + uint32_t value; + + rc = of_property_read_u32(np, "data-range", &data_range); + if (rc) { + p_data->reg.map.range = IST8801_SENSITIVITY_TYPE; + TRI_KEY_LOG("use default value:0x%x\n", + p_data->reg.map.range); + } else { + p_data->reg.map.range = (uint8_t)data_range; + TRI_KEY_LOG("data-range is 0x%x\n", p_data->reg.map.range); + } + + p_data->irq_gpio = of_get_named_gpio(np, "dhall,irq-gpio", 0); + + p_data->power_2v8 = regulator_get(&p_data->client->dev, "vdd"); + if (IS_ERR_OR_NULL(p_data->power_2v8)) { + TRI_KEY_ERR("Regulator get failed vdd_2v8\n"); + goto err; + } + + p_data->power_1v8 = regulator_get(&p_data->client->dev, "vio"); + if (IS_ERR_OR_NULL(p_data->power_1v8)) { + TRI_KEY_ERR("Regulator get failed vcc_1v8\n"); + goto err; + } + + p_data->pctrl = devm_pinctrl_get(&p_data->client->dev); + if (IS_ERR_OR_NULL(p_data->pctrl)) { + TRI_KEY_ERR("failed to get pinctrl\n"); + goto err; + } + + p_data->irq_state = pinctrl_lookup_state(p_data->pctrl, + "ist8801_hall_up_active"); + if (IS_ERR_OR_NULL(p_data->irq_state)) { + rc = PTR_ERR(p_data->irq_state); + TRI_KEY_ERR("pinctrl_lookup_state, err:%d\n", rc); + goto err; + } else { + pinctrl_select_state(p_data->pctrl, p_data->irq_state); + } + + p_data->enable_hidden = of_property_read_bool(np, "hall,bias_support"); + if (p_data->enable_hidden) { + rc = of_property_read_u32(np, "hall,bias-ratio", &value); + if (rc) + p_data->bias_ratio = 100; + else + p_data->bias_ratio = value; + } + return 0; +err: + return rc; +}; + +struct dhall_operations ist8801_up_ops = { + .get_data = ist8801_get_data, + .enable_irq = ist8801_enable_irq, + .clear_irq = ist8801_clear_irq, + .get_irq_state = ist8801_get_irq_state, + .set_detection_mode = ist8801_set_detection_mode, + .update_threshold = ist8801_up_update_threshold, + .dump_regs = ist8801_dump_reg, + .set_reg = ist8801_set_reg, + .is_power_on = ist8801_is_power_on, + .set_sensitivity = ist8801_set_sensitivity, +}; + +static int ist8801_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct ist8801_data_t *p_data = NULL; + struct extcon_dev_data *hall_dev = NULL; + u8 dev_id = 0xFF; + int err = 0; + + TRI_KEY_LOG("call\n"); + + p_data = devm_kzalloc(&client->dev, sizeof(struct ist8801_data_t), + GFP_KERNEL); + if (!p_data) { + TRI_KEY_ERR("kernel memory alocation was failed\n"); + return -ENOMEM; + } + + hall_dev = kzalloc(sizeof(struct extcon_dev_data), GFP_KERNEL); + if (!hall_dev) { + TRI_KEY_ERR("kernel memory alocation was failed\n"); + devm_kfree(&client->dev, p_data); + return -ENOMEM; + } + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + TRI_KEY_LOG("i2c unsupported\n"); + devm_kfree(&client->dev, p_data); + kfree(hall_dev); + return -EOPNOTSUPP; + } + p_data->client = client; + p_data->dev = &client->dev; + g_ist8801_data = p_data; + hall_dev->client = client; + i2c_set_clientdata(client, hall_dev); + hall_dev->dev = &client->dev; + if (client->dev.of_node) { + err = ist8801_parse_dts(&client->dev, p_data); + if (err) + TRI_KEY_ERR("failed to parse device tree\n"); + } + ist8801_reconfig(p_data); + + err = ist8801_set_power(p_data, 1); + + dev_id = ist8801_get_id(p_data); + if (dev_id != IST8801_VAL_DID) { + TRI_KEY_ERR("current device id(0x%02x)", dev_id, + "is not ist8801 device id(0x%02x)\n", + IST8801_VAL_DID); + goto fail; + } + + err = ist8801_reset_device(p_data); + if (err < 0) { + TRI_KEY_ERR("ist8801_reset_device fail\n"); + goto fail; + } + + err = ist8801_setup_eint(p_data); + + wakeup_source_add(&g_ist8801_data->source); + + ist8801_set_sensitivity("40mT"); + + oplus_register_hall("hall_up", &ist8801_up_ops, hall_dev); + + TRI_KEY_LOG("success.\n"); + return 0; +fail: + TRI_KEY_LOG("fail.\n"); + if (gpio_is_valid(p_data->irq_gpio)) + gpio_free(p_data->irq_gpio); + + devm_kfree(&client->dev, p_data); + kfree(hall_dev); + return -ENXIO; +} + +static int ist8801_i2c_remove(struct i2c_client *client) +{ + return 0; +} + +static const struct of_device_id ist8801_match[] = { + { .compatible = HALL_IST8801_UP, }, + {}, +}; + +static const struct i2c_device_id ist8801_id[] = { + {"hall_ist8801_up", 0 }, + {}, +}; + +/* + *static const struct dev_pm_ops ist8801_pm_ops = { + *.suspend = ist8801_i2c_suspend, + *.resume = ist8801_i2c_resume, + *}; + */ +struct i2c_driver ist8801_i2c_up_driver = { + .driver = { + .name = "hall-ist8801-up", + .of_match_table = ist8801_match, + }, + .probe = ist8801_i2c_probe, + .remove = ist8801_i2c_remove, + .id_table = ist8801_id, +}; + +static int __init ist8801_up_init(void) +{ + TRI_KEY_LOG("call\n"); + i2c_add_driver(&ist8801_i2c_up_driver); + return 0; +} +late_initcall(ist8801_up_init); + +static void __exit ist8801_up_exit(void) +{ + TRI_KEY_LOG("call\n"); + i2c_del_driver(&ist8801_i2c_up_driver); +} + +module_exit(ist8801_up_exit); + +MODULE_DESCRIPTION("ist8801 hallswitch driver"); +MODULE_LICENSE("GPL"); + + diff --git a/drivers/misc/tri_state_key/oplus_tri_key.c b/drivers/misc/tri_state_key/oplus_tri_key.c new file mode 100644 index 000000000000..ef0a3bd4304e --- /dev/null +++ b/drivers/misc/tri_state_key/oplus_tri_key.c @@ -0,0 +1,1418 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2018-2020 Oplus. All rights reserved. + * File: oplus_tri_key.c + * + * Description: + * Definitions for m1120 tri_state_key data process. + * + * Version: 1.0 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include +#include + +#include "oplus_tri_key.h" +#include "../../extcon/extcon.h" + +#define TRI_KEY_DEVICE "oplus,hall_tri_state_key" +#define TRI_KEY_TAG "[tri_state_key] " +#define TRI_KEY_ERR(fmt, args...)\ + pr_info(TRI_KEY_TAG" %s : "fmt, __func__, ##args) +#define TRI_KEY_LOG(fmt, args...)\ + pr_info(TRI_KEY_TAG" %s : "fmt, __func__, ##args) +#define TRI_KEY_DEBUG(fmt, args...)\ + do {\ + if (tri_key_debug == LEVEL_DEBUG)\ + pr_info(TRI_KEY_TAG " %s: " fmt, __func__, ##args);\ + } while (0) +enum { + MODE_UNKNOWN, + MODE_MUTE, + MODE_DO_NOT_DISTURB, + MODE_NORMAL, + MODE_MAX_NUM + } tri_mode; + + +unsigned int tristate_extcon_tab[] = { + MODE_MUTE, + MODE_DO_NOT_DISTURB, + MODE_NORMAL, + }; + +static struct hrtimer tri_key_timer; +struct work_struct tri_key_timeout_work; + + + +static struct extcon_dev_data *g_the_chip; +static struct extcon_dev_data *g_hall_dev; +static int last_d0; +static int last_d1; +static int last_position = -1; +static int last_interf = -1; +static int interf_count; +static int time = 1; +unsigned int tri_key_debug; + +static short tol0 = 15; +static short tol2 = 40; +static short up_mid_tol = 15; +static short up_tolerance = 15; +static short down_tolerance = 15; +static short mid_down_tol = 15; +static short up_mid_distance; +static short mid_down_distance; +static short calib_UpValueSum, calib_MdValueSum, calib_DnValueSum; +static short calib_UpValueMin, calib_MdValueMin, calib_DnValueMin; +static short calib_dnHall_UM_distance, calib_dnHall_MD_distance; +static short calib_upHall_UM_distance, calib_upHall_MD_distance; +static short calib_upHall_UD_distance, calib_dnHall_UD_distance; + +void oplus_hall_disable_irq(bool enable) +{ + oplus_hall_clear_irq(DHALL_0); + oplus_hall_clear_irq(DHALL_1); + + g_the_chip->dhall_down_ops->enable_irq(enable); + g_the_chip->dhall_up_ops->enable_irq(enable); +} + +int oplus_hall_enable_irq(unsigned int id, bool enable) +{ + if (!g_the_chip) + return -EINVAL; + + switch (id) { + case DHALL_0: + if (!g_the_chip->dhall_down_ops || + !g_the_chip->dhall_down_ops->enable_irq) + TRI_KEY_ERR("enable hall0 irq error\n"); + else { + oplus_hall_clear_irq(DHALL_0); + oplus_hall_clear_irq(DHALL_1); + return g_the_chip->dhall_down_ops->enable_irq(enable); + } + case DHALL_1: + if (!g_the_chip->dhall_up_ops || + !g_the_chip->dhall_up_ops->enable_irq) + TRI_KEY_ERR("enable hall1 irq error\n"); + else { + oplus_hall_clear_irq(DHALL_0); + oplus_hall_clear_irq(DHALL_1); + return g_the_chip->dhall_up_ops->enable_irq(enable); + } + default: + TRI_KEY_ERR("id : %d is not correct\n", id); + return -EINVAL; + } + + return -EINVAL; +} + +int oplus_hall_clear_irq(unsigned int id) +{ + if (!g_the_chip) + return -EINVAL; + + TRI_KEY_DEBUG("dhall_clear_irq\n"); + switch (id) { + case DHALL_0: + if (!g_the_chip->dhall_down_ops || + !g_the_chip->dhall_down_ops->enable_irq) + return -EINVAL; + else + return g_the_chip->dhall_down_ops->clear_irq(); + + case DHALL_1: + if (!g_the_chip->dhall_up_ops || + !g_the_chip->dhall_up_ops->enable_irq) + return -EINVAL; + else + return g_the_chip->dhall_up_ops->clear_irq(); + default: + TRI_KEY_ERR("id : %d is not correct\n", id); + return -EINVAL; + } + + return -EINVAL; +} + +int oplus_hall_get_data(unsigned int id) +{ + if (!g_the_chip) + return -EINVAL; + + switch (id) { + case DHALL_0: + if (!g_the_chip->dhall_down_ops || + !g_the_chip->dhall_down_ops->get_data) + TRI_KEY_ERR("get hall0 data error\n"); + else { + g_the_chip->dhall_down_ops->get_data( + &g_the_chip->dhall_data0); + return true; + } + case DHALL_1: + if (!g_the_chip->dhall_up_ops || + !g_the_chip->dhall_up_ops->get_data) + TRI_KEY_ERR("get hall1 data error\n"); + else { + g_the_chip->dhall_up_ops->get_data( + &g_the_chip->dhall_data1); + return true; + } + default: + TRI_KEY_ERR("id : %d is not correct\n", id); + return -EINVAL; + } +} + +bool oplus_hall_update_threshold(unsigned int id, int position, + short lowthd, short highthd) +{ + if (!g_the_chip) + return -EINVAL; + + switch (id) { + case DHALL_0: + if (!g_the_chip->dhall_down_ops || + !g_the_chip->dhall_down_ops->update_threshold) + TRI_KEY_ERR("update hall0 threshold error\n"); + else { + g_the_chip->dhall_down_ops->update_threshold(position, + lowthd, highthd); + return true; + } + case DHALL_1: + if (!g_the_chip->dhall_up_ops || + !g_the_chip->dhall_up_ops->update_threshold) + TRI_KEY_ERR("update hall1 threshold error\n"); + else { + g_the_chip->dhall_up_ops->update_threshold(position, + lowthd, highthd); + return true; + } + default: + TRI_KEY_ERR("id : %d is not correct\n", id); + return -EINVAL; + } +} + +int oplus_hall_set_detection_mode(unsigned int id, u8 mode) +{ + if (!g_the_chip) + return -EINVAL; + + switch (id) { + case DHALL_0: + if (!g_the_chip->dhall_down_ops || + !g_the_chip->dhall_down_ops->set_detection_mode) + TRI_KEY_ERR("set hall 0 error\n"); + else { + g_the_chip->dhall_down_ops->set_detection_mode(mode); + return true; + } + case DHALL_1: + if (!g_the_chip->dhall_up_ops || + !g_the_chip->dhall_up_ops->set_detection_mode) + TRI_KEY_ERR("set error\n"); + else { + g_the_chip->dhall_up_ops->set_detection_mode(mode); + return true; + } + default: + TRI_KEY_ERR("id : %d is not correct\n", id); + return -EINVAL; + } +} + +int oplus_hall_get_irq_state(unsigned int id) +{ + if (!g_the_chip) + return -EINVAL; + + switch (id) { + case DHALL_0: + if (!g_the_chip->dhall_down_ops || + !g_the_chip->dhall_down_ops->get_irq_state) + return -EINVAL; + else + return g_the_chip->dhall_down_ops->get_irq_state(); + case DHALL_1: + if (!g_the_chip->dhall_up_ops || + !g_the_chip->dhall_up_ops->get_irq_state) + return -EINVAL; + else + return g_the_chip->dhall_up_ops->get_irq_state(); + default: + TRI_KEY_ERR("id : %d is not correct\n", id); + return -EINVAL; + } +} + + + +void oplus_hall_dump_regs(unsigned int id, u8 *buf) +{ + if (!g_the_chip) + return; + + switch (id) { + case DHALL_0: + if (!g_the_chip->dhall_down_ops || + !g_the_chip->dhall_down_ops->dump_regs) + TRI_KEY_ERR("dump hall0 error\n"); + else + g_the_chip->dhall_down_ops->dump_regs(buf); + break; + case DHALL_1: + if (!g_the_chip->dhall_up_ops || + !g_the_chip->dhall_up_ops->dump_regs) + TRI_KEY_ERR("dump hall1 error\n"); + else + g_the_chip->dhall_up_ops->dump_regs(buf); + break; + default: + TRI_KEY_ERR("id : %d is not correct\n", id); + return; + } +} + +int oplus_hall_set_reg(unsigned int id, int reg, int val) +{ + if (!g_the_chip) + return -EINVAL; + + switch (id) { + case DHALL_0: + if (!g_the_chip->dhall_down_ops || + !g_the_chip->dhall_down_ops->set_reg) + return -EINVAL; + else + return g_the_chip->dhall_down_ops->set_reg(reg, val); + case DHALL_1: + if (!g_the_chip->dhall_up_ops || + !g_the_chip->dhall_up_ops->set_reg) + return -EINVAL; + else + return g_the_chip->dhall_up_ops->set_reg(reg, val); + default: + TRI_KEY_ERR("id : %d is not correct\n", id); + return -EINVAL; + } +} + +bool oplus_hall_is_power_on(void) +{ + if (!g_the_chip || !g_the_chip->dhall_down_ops || + !g_the_chip->dhall_down_ops->is_power_on || + !g_the_chip->dhall_up_ops || + !g_the_chip->dhall_up_ops->is_power_on) { + } else { + if (g_the_chip->dhall_down_ops->is_power_on() || + g_the_chip->dhall_up_ops->is_power_on()) + return true; + else + return false; + } + return false; +} +static void reboot_get_position(struct extcon_dev_data *chip) +{ + short delta; + short up_data1; + short down_data1; + + if (chip->dhall_data1 < 0 || chip->dhall_data0 < 0) { + up_data1 = -chip->dhall_data1; + down_data1 = -chip->dhall_data0; + delta = up_data1 - down_data1; + } else + delta = chip->dhall_data1 - chip->dhall_data0; + if (delta > 30) + chip->position = UP_STATE; + else if (-delta > 30) + chip->position = DOWN_STATE; + else + chip->position = MID_STATE; + last_position = chip->position; +} + +static int interf_get_position(struct extcon_dev_data *chip) +{ + short delta0; + short delta1; + + delta0 = chip->dhall_data0 - last_d0; + delta1 = chip->dhall_data1 - last_d1; + TRI_KEY_LOG("tri_key: delta0 is %d ,delta1 is %d,last_postion is %d\n", + delta0, delta1, last_position); + if ((delta1 > calib_upHall_UM_distance - tol0 && + delta1 < calib_upHall_UM_distance + tol0) && + ((delta0 > calib_dnHall_UM_distance - tol0) && + (delta0 < calib_dnHall_UM_distance + tol0))) { + if (last_position == MID_STATE) + return UP_STATE; + } + if ((delta1 > calib_upHall_UD_distance - tol0 && + delta1 < calib_upHall_UD_distance + tol0) && + ((delta0 > calib_dnHall_UD_distance - tol0) && + (delta0 < calib_dnHall_UD_distance + tol0))) + return UP_STATE; + if ((delta1 > -calib_upHall_MD_distance - tol0 && + delta1 < -calib_upHall_MD_distance + tol0) && + ((delta0 > -calib_dnHall_MD_distance - tol0) && + (delta0 < -calib_dnHall_MD_distance + tol0))) { + if (last_position == MID_STATE) + return DOWN_STATE; + } + if ((delta1 > -calib_upHall_UD_distance - tol0 && + delta1 < -calib_upHall_UD_distance + tol0) && + ((delta0 > -calib_dnHall_UD_distance - tol0) && + (delta0 < -calib_dnHall_UD_distance + tol0))) + return DOWN_STATE; + if ((delta1 > -calib_upHall_UM_distance - tol0 && + delta1 < -calib_upHall_UM_distance + tol0) && + ((delta0 > -calib_dnHall_UM_distance - tol0) && + (delta0 < -calib_dnHall_UM_distance + tol0))) { + if (last_position == UP_STATE) + return MID_STATE; + } + if ((delta1 > calib_upHall_MD_distance - tol0 && + delta1 < calib_upHall_MD_distance + tol0) && + ((delta0 > calib_dnHall_MD_distance - tol0) && + (delta0 < calib_dnHall_MD_distance + tol0))) { + if (last_position == DOWN_STATE) + return MID_STATE; + } + return -EINVAL; +} + +static int get_position(struct extcon_dev_data *chip) +{ + short diff; + + diff = chip->dhall_data1 - chip->dhall_data0; + if (chip->dhall_data0 > 0) { + if (diff > calib_UpValueMin - up_mid_tol && + diff < calib_UpValueMin + up_tolerance) + chip->position = UP_STATE; + if (calib_MdValueMin < 0) { + if (diff > calib_MdValueMin - mid_down_tol && + diff < calib_MdValueMin + up_mid_tol) + chip->position = MID_STATE; + } + if (calib_MdValueMin > 0 || calib_MdValueMin == 0) { + if (diff > calib_MdValueMin - mid_down_tol && + diff < calib_MdValueMin + up_mid_tol) + chip->position = MID_STATE; + } + if (diff > calib_DnValueMin - down_tolerance && + diff < calib_DnValueMin + mid_down_tol) + chip->position = DOWN_STATE; + } else { + if (diff > calib_UpValueMin - up_tolerance && + diff < calib_UpValueMin + up_mid_tol) + chip->position = UP_STATE; + if (calib_MdValueMin < 0) { + if (diff > calib_MdValueMin - mid_down_tol && + diff < calib_MdValueMin + up_mid_tol) + chip->position = MID_STATE; + } + if (calib_MdValueMin > 0 || calib_MdValueMin == 0) { + if (diff > calib_MdValueMin - mid_down_tol && + diff < calib_MdValueMin + up_mid_tol) + chip->position = MID_STATE; + } + if (diff > calib_DnValueMin - mid_down_tol && + diff < calib_DnValueMin + down_tolerance) + chip->position = DOWN_STATE; + } + return 0; +} + +static int judge_interference(struct extcon_dev_data *chip) +{ + short delta; + short sum; + + delta = chip->dhall_data1 - chip->dhall_data0; + TRI_KEY_LOG("tri_key:delta is %d\n", delta); + sum = chip->dhall_data0 + chip->dhall_data1; + TRI_KEY_LOG("tri_key:sum is %d\n", sum); + if (chip->dhall_data1 > 0) {/*positive number*/ + if (delta > calib_UpValueMin - up_mid_tol && + delta < calib_UpValueMin + up_tolerance) { + TRI_KEY_LOG("calib_Min:%d,calib_Sum:%d\n", + calib_UpValueMin, calib_UpValueSum); + if (sum < calib_UpValueSum - tol2 || + sum > calib_UpValueSum + tol2) { + chip->interf = 1; + chip->state = 1; + } else { + chip->interf = 0; + chip->state = 1; + } + return 0; + } + if (calib_MdValueMin < 0) { + if (delta > calib_MdValueMin - mid_down_tol && + delta < calib_MdValueMin + up_mid_tol) { + TRI_KEY_LOG("calibMin:%d,calib_Sum:%d\n", + calib_MdValueMin, calib_MdValueSum); + + if (sum > calib_MdValueSum + tol2 || + sum < calib_MdValueSum - tol2) { + chip->interf = 1; + chip->state = 2; + } else { + chip->interf = 0; + chip->state = 2; + } + return 0; + } + } + if (calib_MdValueMin > 0 || calib_MdValueMin == 0) { + if (delta > calib_MdValueMin - mid_down_tol && + delta < calib_MdValueMin + up_mid_tol) { + TRI_KEY_LOG("calib_Min:%d,calib_Sum:%d\n", + calib_MdValueMin, calib_MdValueSum); + + if (sum > calib_MdValueSum + tol2 || + sum < calib_MdValueSum - tol2) { + chip->interf = 1; + chip->state = 2; + } else { + chip->interf = 0; + chip->state = 2; + } + return 0; + } + } + if (delta > calib_DnValueMin - down_tolerance && + delta < calib_DnValueMin + mid_down_tol) { + TRI_KEY_LOG("calib_Min:%d,calib_Sum:%d\n", + calib_DnValueMin, calib_DnValueSum); + + if (sum < calib_DnValueSum - tol2 || + sum > calib_DnValueSum + tol2) { + chip->interf = 1; + chip->state = 3; + } else { + chip->interf = 0; + chip->state = 3; + } + return 0; + } + chip->interf = 1; + chip->state = 0; + } else {/*the hall data is negative number*/ + if (delta > calib_UpValueMin - up_tolerance && + delta < calib_UpValueMin + up_mid_tol) { + TRI_KEY_LOG("calib_Min:%d,calib_Sum:%d\n", + calib_UpValueMin, calib_UpValueSum); + + if (sum < calib_UpValueSum - tol2 || + sum > calib_UpValueSum + tol2) { + chip->interf = 1; + chip->state = 1; + } else { + chip->interf = 0; + chip->state = 1; + } + return 0; + } + if (calib_MdValueMin < 0) { + if (delta > calib_MdValueMin - mid_down_tol && + delta < calib_MdValueMin + up_mid_tol) { + TRI_KEY_LOG("calib_Min:%d,calib_Sum:%d\n", + calib_MdValueMin, calib_MdValueSum); + + if (sum > calib_MdValueSum + tol2 || + sum < calib_MdValueSum - tol2) { + chip->interf = 1; + chip->state = 2; + } else { + chip->interf = 0; + chip->state = 2; + } + return 0; + } + } + if (calib_MdValueMin > 0 || calib_MdValueMin == 0) { + if (delta > calib_MdValueMin - mid_down_tol && + delta < calib_MdValueMin + up_mid_tol) { + TRI_KEY_LOG("calib_Min:%d,calib_Sum:%d\n", + calib_MdValueMin, calib_MdValueSum); + + if (sum > calib_MdValueSum + tol2 || + sum < calib_MdValueSum - tol2) { + chip->interf = 1; + chip->state = 2; + } else { + chip->interf = 0; + chip->state = 2; + } + return 0; + } + } + if (delta > calib_DnValueMin - mid_down_tol && + delta < calib_DnValueMin + down_tolerance) { + TRI_KEY_LOG("tri_key:calib_Min:%d,calib_Sum:%d\n", + calib_DnValueMin, calib_DnValueSum); + + if (sum < calib_DnValueSum - tol2 || + sum > calib_DnValueSum + tol2) { + chip->interf = 1; + chip->state = 3; + } else { + chip->interf = 0; + chip->state = 3; + } + return 0; + } + chip->interf = 1; + chip->state = 0; + } + return -EINVAL; +} + + +static int oplus_get_data(struct extcon_dev_data *chip) +{ + int res = 0; + + res = oplus_hall_get_data(DHALL_0); + if (res < 0) { + TRI_KEY_LOG("tri_key:get DHALL_0 data failed,res =%d\n", res); + return res; + } + res = oplus_hall_get_data(DHALL_1); + if (res < 0) { + TRI_KEY_LOG("tri_key:get DHALL_1 data failed,res =%d\n", res); + return res; + } + + return res; +} + +static int reupdata_threshold(struct extcon_dev_data *chip) +{ + int res = 0; + int tolen = 22; + + switch (chip->position) { + case UP_STATE: + res = oplus_hall_update_threshold(DHALL_1, UP_STATE, + chip->dhall_data1-tolen, chip->dhall_data1+tolen); + if (res < 0) { + TRI_KEY_LOG("updata_threshold fail:%d\n", res); + goto fail; + } + res = oplus_hall_update_threshold(DHALL_0, UP_STATE, + -500, 500); + if (res < 0) { + TRI_KEY_LOG("updata_threshold fail:%d\n", res); + goto fail; + } + TRI_KEY_LOG("tri_key:updata_threshold up:low:%d,high: %d\n", + chip->dhall_data1-tolen, chip->dhall_data1+tolen); + oplus_hall_clear_irq(DHALL_1); + oplus_hall_clear_irq(DHALL_0); + break; + case MID_STATE: + if (chip->dhall_data0 < 0 || chip->dhall_data1 < 0) { + res = oplus_hall_update_threshold(DHALL_1, MID_STATE, + chip->dhall_data1 - tolen, chip->dhall_data1 + tolen); + if (res < 0) { + TRI_KEY_LOG("updata_threshold fail:%d\n", res); + goto fail; + } + TRI_KEY_LOG("tri_key:updata_threshold up:low:%d,high:%d\n", + chip->dhall_data1 - tolen, chip->dhall_data1 + tolen); + } else { + res = oplus_hall_update_threshold(DHALL_1, MID_STATE, + chip->dhall_data1 - tolen, chip->dhall_data1 + tolen); + if (res < 0) { + TRI_KEY_LOG("updata_threshold fail:%d\n", res); + goto fail; + } + TRI_KEY_LOG("tri_key:updata_threshold up:low:%d,high:%d\n", + chip->dhall_data1 - tolen, chip->dhall_data1 + tolen); + } + oplus_hall_clear_irq(DHALL_1); + if (chip->dhall_data0 < 0 || chip->dhall_data1 < 0) { + res = oplus_hall_update_threshold(DHALL_0, MID_STATE, + chip->dhall_data0 - tolen, chip->dhall_data0 + tolen); + if (res < 0) { + TRI_KEY_LOG("updata_threshold fail:%d\n", res); + goto fail; + } + TRI_KEY_LOG("tri_key:updata_threshold down:low:%d,high:%d\n", + chip->dhall_data0 - tolen, chip->dhall_data0 + tolen); + } else { + res = oplus_hall_update_threshold(DHALL_0, MID_STATE, + chip->dhall_data0 - tolen, chip->dhall_data0 + tolen); + if (res < 0) { + TRI_KEY_LOG("updata_threshold fail:%d\n", res); + goto fail; + } + TRI_KEY_LOG("tri_key:updata_threshold down:low:%d,high:%d\n", + chip->dhall_data0 - tolen, chip->dhall_data0 + tolen); + } + oplus_hall_clear_irq(DHALL_0); + break; + case DOWN_STATE: + res = oplus_hall_update_threshold(DHALL_0, DOWN_STATE, + chip->dhall_data0 - tolen, chip->dhall_data0 + tolen); + if (res < 0) { + TRI_KEY_LOG("updata_threshold fail:%d\n", res); + goto fail; + } + TRI_KEY_LOG("tri_key:updata_threshold down:low:%d,high:%d\n", + chip->dhall_data0 - tolen, chip->dhall_data0 + tolen); + res = oplus_hall_update_threshold(DHALL_1, DOWN_STATE, + -500, 500); + if (res < 0) { + TRI_KEY_LOG("updata_threshold fail:%d\n", res); + goto fail; + } + + oplus_hall_clear_irq(DHALL_0); + oplus_hall_clear_irq(DHALL_1); + break; + } +fail: + last_d0 = chip->dhall_data0; + last_d1 = chip->dhall_data1; + last_interf = chip->interf; + TRI_KEY_LOG("tri_key:last_d0 is %d ,last_d1 is %d\n", + last_d0, last_d1); + oplus_hall_clear_irq(DHALL_0); + oplus_hall_clear_irq(DHALL_1); + return res; +} + +static void report_key_value(struct extcon_dev_data *chip) +{ + if (chip->position == DOWN_STATE) { + chip->state = 3; + input_report_key(chip->input_dev, KEY_F3, 3); + input_sync(chip->input_dev); + input_report_key(chip->input_dev, KEY_F3, 0); + input_sync(chip->input_dev); + TRI_KEY_LOG("tri_key: report down key successful!\n"); + } + if (chip->position == UP_STATE) { + chip->state = 1; + TRI_KEY_LOG("tri_key: report up key successful!\n"); + input_report_key(chip->input_dev, KEY_F3, 1); + input_sync(chip->input_dev); + input_report_key(chip->input_dev, KEY_F3, 0); + input_sync(chip->input_dev); + } + if (chip->position == MID_STATE) { + chip->state = 2; + TRI_KEY_LOG("tri_key: report mid key successful!\n"); + input_report_key(chip->input_dev, KEY_F3, 2); + input_sync(chip->input_dev); + input_report_key(chip->input_dev, KEY_F3, 0); + input_sync(chip->input_dev); + } else + TRI_KEY_LOG("no report\n"); +} + +static int report_calibration_location(struct extcon_dev_data *chip) +{ + oplus_get_data(chip); + get_position(chip); + reupdata_threshold(chip); + if (chip->position == last_position) { + TRI_KEY_LOG("no report\n"); + goto err; + } else + report_key_value(chip); + last_position = chip->position; + return 0; +err: + return -EINVAL; +} + +static int judge_calibration_data(struct extcon_dev_data *chip) +{ + if (calib_UpValueMin == 0 || calib_UpValueSum == 0 || + calib_MdValueSum == 0 || calib_DnValueMin == 0 + || calib_DnValueSum == 0) { + oplus_get_data(chip); + reboot_get_position(chip); + if (chip->position == UP_STATE) { + calib_UpValueMin = chip->dhall_data1 - + chip->dhall_data0; + calib_UpValueSum = chip->dhall_data1 + + chip->dhall_data0; + TRI_KEY_LOG("UP_MIN is%d,UP_SUM is %d\n", + calib_UpValueMin, calib_UpValueSum); + } + if (chip->position == MID_STATE) { + calib_MdValueMin = chip->dhall_data1 - + chip->dhall_data0; + calib_MdValueSum = chip->dhall_data1 + + chip->dhall_data0; + TRI_KEY_LOG("MID_MIN is%d,MID_SUM is %d\n", + calib_MdValueMin, calib_MdValueSum); + } + if (chip->position == DOWN_STATE) { + calib_DnValueMin = chip->dhall_data1 - + chip->dhall_data0; + calib_DnValueSum = chip->dhall_data1 + + chip->dhall_data0; + TRI_KEY_LOG("UP_MIN is%d,UP_SUM is %d\n", + calib_DnValueMin, calib_DnValueSum); + } + report_key_value(chip); + reupdata_threshold(chip); + return -EINVAL; + } + return 0; +} + + +int oplus_hall_irq_handler(unsigned int id) +{ + TRI_KEY_LOG("%d tri_key:call :%s\n", id, __func__); + if (!g_the_chip) + TRI_KEY_LOG("g_the_chip null\n "); + else + schedule_work(&g_the_chip->dwork); + return IRQ_HANDLED; +} +EXPORT_SYMBOL(oplus_hall_irq_handler); + +static void tri_key_dev_work(struct work_struct *work) +{ + struct extcon_dev_data *chip = container_of(work, + struct extcon_dev_data, dwork); + int res = 0; + int position = -1; + int diff0 = 0; + int diff1 = 0; + int count = 0; + int dhall0_sum = 0; + int dhall1_sum = 0; + int aver0 = 0; + int aver1 = 0; + ktime_t starttime, endtime; + u64 usecs64; + int usecs; + + mutex_lock(&chip->mtx); + + starttime = ktime_get(); + msleep(50); + res = judge_calibration_data(chip); + if (res < 0) + goto FINAL; + +/*get data*/ + res = oplus_get_data(chip); + if (res < 0) { + TRI_KEY_LOG("tri_key:get hall data failed!\n"); + goto fail; + } + TRI_KEY_LOG("tri_key:data1 is %d, data0 is %d\n", + chip->dhall_data1, chip->dhall_data0); + +/*judge interference*/ + res = judge_interference(chip); + TRI_KEY_LOG("tri_key:chip->interf is %d ,chip->state is %d\n", + chip->interf, chip->state); + if (!last_interf && chip->interf) { + msleep(200); + oplus_get_data(chip); + TRI_KEY_LOG("tri_key:data1 is %d, data0 is %d\n", + chip->dhall_data1, chip->dhall_data0); + + judge_interference(chip); + } +/*get position*/ + if (!chip->interf) { + hrtimer_cancel(&tri_key_timer); + time = 1; + if (!last_interf) { + interf_count = 0; + get_position(chip); + TRI_KEY_LOG("tri_key:the position is %d\n", chip->position); + } else { + msleep(50); + oplus_get_data(chip); + judge_interference(chip); + if (chip->interf) + goto FINAL; + else + get_position(chip); + } + } + else { + hrtimer_cancel(&tri_key_timer); + TRI_KEY_LOG("tri_key:time0 is %d\n", time); + hrtimer_start(&tri_key_timer, ktime_set(time, 0), + HRTIMER_MODE_REL); + while (count < 4) { + msleep(35); + oplus_hall_get_data(DHALL_0); + oplus_hall_get_data(DHALL_1); + dhall0_sum += chip->dhall_data0; + dhall1_sum += chip->dhall_data1; + count++; + } + aver0 = dhall0_sum / 4; + aver1 = dhall1_sum / 4; + if (!last_interf) { + diff0 = aver0 - chip->dhall_data0; + diff1 = aver1 - chip->dhall_data1; + TRI_KEY_LOG("tri_key:diff0 is %d,diff1 is %d\n", + diff0, diff1); + if ((diff0 > -10 && diff0 < 10) && + (diff1 > -10 && diff1 < 10)) { + chip->position = last_position; + goto UPDATA_HTRES; + } else {/*inconstant interference*/ + last_interf = chip->interf; + goto FINAL; + } + } + diff0 = aver0 - chip->dhall_data0; + diff1 = aver1 - chip->dhall_data1; + TRI_KEY_LOG("tri_key:diff0 is %d,diff1 is %d\n", + diff0, diff1); + +/*inconstantly interference*/ + if ((diff0 < -10 || diff0 > 10) && + (diff1 < -10 || diff1 > 10)) { + interf_count++; + if (interf_count == 15) { + TRI_KEY_LOG("tri_key:count = 15,msleep 5s\n"); + msleep(5000); + interf_count = 0; + goto FINAL; + } + TRI_KEY_LOG("tri_key:inconstantlt interference\n"); + reupdata_threshold(chip); + goto FINAL; + } + + chip->dhall_data0 = aver0; + chip->dhall_data1 = aver1; + position = interf_get_position(chip); + if (position == -22) + TRI_KEY_LOG("tri_key:get position failed\n"); + else + chip->position = position; + } + TRI_KEY_LOG("tri_key:t_diff0 is %d,t_diff1 is %d\n", + chip->dhall_data0 - last_d0, chip->dhall_data1 - last_d1); +/*updata threshold*/ +UPDATA_HTRES: + res = reupdata_threshold(chip); + if (res < 0) { + TRI_KEY_LOG("tri_key:updata_threshold failed!\n"); + goto fail; + } + +/*report key value*/ + if (chip->position == last_position) + goto FINAL; + else { + report_key_value(chip); + last_position = chip->position; + endtime = ktime_get(); + usecs64 = ktime_to_ns(ktime_sub(endtime, starttime)); + do_div(usecs64, NSEC_PER_USEC); + usecs = usecs64; + if (usecs == 0) + usecs = 1; + TRI_KEY_LOG("report key after %ld.%03ld msecs\n", + usecs / USEC_PER_MSEC, usecs % USEC_PER_MSEC); + } +fail: + if (res < 0) + TRI_KEY_LOG("tri_key:dev_work failed,res =%d\n", res); +FINAL: + oplus_hall_disable_irq(1); + + TRI_KEY_LOG("%s achieve\n", __func__); + mutex_unlock(&chip->mtx); +} + +static enum hrtimer_restart tri_key_status_timeout(struct hrtimer *timer) +{ + schedule_work(&tri_key_timeout_work); + return HRTIMER_NORESTART; +} + +static void tri_key_timeout_work_func(struct work_struct *work) +{ + oplus_get_data(g_the_chip); + judge_interference(g_the_chip); + if (g_the_chip->interf) { + time = time * 2; + TRI_KEY_LOG("tri_key:time1 is %d\n", time); + if (time > 2) + time = 2; + } + else { + get_position(g_the_chip); + if (g_the_chip->position == last_position) + return; + reupdata_threshold(g_the_chip); + report_key_value(g_the_chip); + last_position = g_the_chip->position; + time = 1; + } +} + + +static short Sum(short value0, short value1) +{ + short sum = 0; + + sum = value0 + value1; + return sum; +} +static short Minus(short value0, short value1) +{ + short minus = 0; + + minus = value0 - value1; + return minus; +} + +void initialCalibValue(short calib_dnHall_UpV, short calib_dnHall_MdV, + short calib_dnHall_DnV, short calib_upHall_UpV, + short calib_upHall_MdV, short calib_upHall_DnV) +{ + calib_UpValueSum = Sum(calib_dnHall_UpV, calib_upHall_UpV); + calib_MdValueSum = Sum(calib_dnHall_MdV, calib_upHall_MdV); + calib_DnValueSum = Sum(calib_dnHall_DnV, calib_upHall_DnV); + calib_UpValueMin = Minus(calib_upHall_UpV, calib_dnHall_UpV); + calib_MdValueMin = Minus(calib_upHall_MdV, calib_dnHall_MdV); + calib_DnValueMin = Minus(calib_upHall_DnV, calib_dnHall_DnV); + calib_upHall_UM_distance = Minus(calib_upHall_UpV, calib_upHall_MdV); + calib_upHall_MD_distance = Minus(calib_upHall_MdV, calib_upHall_DnV); + calib_dnHall_UM_distance = Minus(calib_dnHall_UpV, calib_dnHall_MdV); + calib_dnHall_MD_distance = Minus(calib_dnHall_MdV, calib_dnHall_DnV); + calib_upHall_UD_distance = Minus(calib_upHall_UpV, calib_upHall_DnV); + calib_dnHall_UD_distance = Minus(calib_dnHall_UpV, calib_dnHall_DnV); + up_mid_tol = (short)(abs(calib_UpValueMin - calib_MdValueMin) + * 4 / 10); + up_tolerance = (short)(abs(calib_UpValueMin - calib_MdValueMin) + * 11 / 10); + mid_down_tol = (short)(abs(calib_MdValueMin - calib_DnValueMin) + * 4 / 10); + down_tolerance = (short)(abs(calib_MdValueMin - + calib_DnValueMin) * 11 / 10); + up_mid_distance = (short)(abs(calib_UpValueMin - + calib_MdValueMin) * 2 / 10); + mid_down_distance = (short)(abs(calib_MdValueMin - + calib_DnValueMin) * 2 / 10); + TRI_KEY_LOG("Upmin:%d, Mdmin:%d, Dnmin:%d\n", + calib_UpValueMin, calib_MdValueMin, calib_DnValueMin); + TRI_KEY_LOG("up_mid_tol:%d, mid_down_tol:%d\n", + up_mid_tol, mid_down_tol); +} + +static ssize_t proc_hall_data_read(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + int ret = 0; + char page[20] = {0}; + + if (!g_the_chip) { + TRI_KEY_ERR("g_the_chip null\n"); + snprintf(page, sizeof(page), "%d\n", -1); + } else { + oplus_hall_get_data(DHALL_0); + oplus_hall_get_data(DHALL_1); + + snprintf(page, sizeof(page), "%d, %d\n", + g_the_chip->dhall_data0, g_the_chip->dhall_data1); + } + ret = simple_read_from_buffer(user_buf, count, ppos, page, strlen(page)); + return ret; +} + +static const struct file_operations proc_hall_data_ops = { + .read = proc_hall_data_read, + .open = simple_open, + .owner = THIS_MODULE, +}; + +static ssize_t proc_tri_state_read(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + int ret = 0; + char page[6] = {0}; + + if (!g_the_chip) { + TRI_KEY_ERR("g_the_chip null\n"); + snprintf(page, sizeof(page), "%d\n", -1); + } else { + oplus_hall_get_data(DHALL_0); + oplus_hall_get_data(DHALL_1); + snprintf(page, sizeof(page), "%d\n", g_the_chip->state); + } + ret = simple_read_from_buffer(user_buf, count, ppos, page, strlen(page)); + return ret; +} + +static const struct file_operations proc_tri_state_ops = { + .read = proc_tri_state_read, + .open = simple_open, + .owner = THIS_MODULE, +}; + +static ssize_t proc_hall_data_calib_read(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + int ret = 0; + char page[50] = {0}; + + if (!g_the_chip) { + TRI_KEY_ERR("g_the_chip null\n"); + snprintf(page, sizeof(page), "%d\n", -1); + } else { + snprintf(page, sizeof(page), "%d,%d,%d,%d,%d,%d,%d,%d\n", + g_the_chip->dnHall_UpV, g_the_chip->upHall_UpV, + g_the_chip->dnHall_MdV, g_the_chip->upHall_MdV, + g_the_chip->dnHall_DnV, g_the_chip->upHall_DnV, + up_mid_tol, mid_down_tol); + } + ret = simple_read_from_buffer(user_buf, count, ppos, page, strlen(page)); + return ret; +} + +static ssize_t proc_hall_data_calib_write(struct file *file, const char __user *buffer, + size_t count, loff_t *ppos) +{ + int data[6] = {0}; + char temp[35] = {0}; + int ret = -1; + + if (!g_the_chip) { + TRI_KEY_ERR("g_the_chip null\n"); + return count; + } + ret = copy_from_user(temp, buffer, count); + if (ret) { + TRI_KEY_ERR("%s: read proc input error.\n", __func__); + return count; + } + TRI_KEY_LOG("temp is %s:\n", temp); + if (sscanf(temp, "%d,%d,%d,%d,%d,%d", &data[0], &data[1], &data[2], + &data[3], &data[4], &data[5]) == 6) { + g_the_chip->dnHall_UpV = data[0]; + g_the_chip->upHall_UpV = data[1]; + g_the_chip->dnHall_MdV = data[2]; + g_the_chip->upHall_MdV = data[3]; + g_the_chip->dnHall_DnV = data[4]; + g_the_chip->upHall_DnV = data[5]; + TRI_KEY_ERR("data[%d %d %d %d %d %d]\n", data[0], data[1], + data[2], data[3], data[4], data[5]); + } else + TRI_KEY_ERR("fail\n"); + + initialCalibValue(g_the_chip->dnHall_UpV, g_the_chip->dnHall_MdV, + g_the_chip->dnHall_DnV, g_the_chip->upHall_UpV, + g_the_chip->upHall_MdV, g_the_chip->upHall_DnV); + report_calibration_location(g_the_chip); + return count; +} + +static const struct file_operations proc_hall_data_calib_ops = { + .write = proc_hall_data_calib_write, + .read = proc_hall_data_calib_read, + .open = simple_open, + .owner = THIS_MODULE, +}; + +static ssize_t proc_hall_debug_info_write(struct file *file, const char __user *buffer, + size_t count, loff_t *ppos) +{ + int tmp = 0; + char buf[4] = {0}; + + if (count > 2) + return count; + copy_from_user(buf, buffer, count); + if (!kstrtoint(buf, 0, &tmp)) + tri_key_debug = tmp; + else + TRI_KEY_DEBUG("invalid content: '%s', length = %zd\n", + buf, count); + + return count; +} +static ssize_t proc_hall_debug_info_read(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + int ret = -1; + char page[6] = {0}; + + if (!g_the_chip) { + TRI_KEY_ERR("g_the_chip null\n"); + snprintf(page, sizeof(page), "%d\n", -1); + } else + snprintf(page, sizeof(page), "%d\n", tri_key_debug); + + ret = simple_read_from_buffer(user_buf, count, ppos, page, strlen(page)); + return ret; +} + +static const struct file_operations proc_hall_debug_info_ops = { + .write = proc_hall_debug_info_write, + .read = proc_hall_debug_info_read, + .open = simple_open, + .owner = THIS_MODULE, +}; + +static int init_trikey_proc(struct extcon_dev_data *hall_dev) +{ + int ret = 0; + struct proc_dir_entry *prEntry_trikey = NULL; + struct proc_dir_entry *prEntry_tmp = NULL; + + TRI_KEY_LOG("%s entry\n", __func__); + prEntry_trikey = proc_mkdir("tristatekey", NULL); + if (prEntry_trikey == NULL) { + ret = -ENOMEM; + TRI_KEY_ERR("%s: Couldn't create trikey proc entry\n", __func__); + } + + prEntry_tmp = proc_create("hall_data", 0644, prEntry_trikey, &proc_hall_data_ops); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + TRI_KEY_ERR("%s: Couldn't create proc entry, %d\n", __func__, __LINE__); + } + + prEntry_tmp = proc_create("tri_state", 0644, prEntry_trikey, &proc_tri_state_ops); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + TRI_KEY_ERR("%s: Couldn't create proc entry, %d\n", __func__, __LINE__); + } + + prEntry_tmp = proc_create("hall_data_calib", 0666, prEntry_trikey, + &proc_hall_data_calib_ops); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + TRI_KEY_ERR("%s: Couldn't create proc entry, %d\n", __func__, __LINE__); + } + + prEntry_tmp = proc_create("hall_debug_info", 0666, prEntry_trikey, + &proc_hall_debug_info_ops); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + TRI_KEY_ERR("%s: Couldn't create proc entry, %d\n", __func__, __LINE__); + } + + return ret; + +} +static void register_tri_key_dev_work(struct work_struct *work) +{ + struct extcon_dev_data *chip = container_of(work, struct extcon_dev_data, + register_work); + struct extcon_dev_data *pdev; + int err = 0; + int res = 0; + + TRI_KEY_LOG("call %s\n", __func__); + + if (!g_the_chip) { + chip = kzalloc(sizeof(struct extcon_dev_data), GFP_KERNEL); + if (!chip) { + TRI_KEY_ERR("kzalloc err\n"); + return; + } + g_the_chip = chip; + } else { + chip = g_the_chip; + } + pdev = g_hall_dev; + chip->input_dev = pdev->input_dev; + chip->input_dev = input_allocate_device(); + if (chip->input_dev == NULL) { + res = -ENOMEM; + TRI_KEY_ERR("Failed to allocate input device\n"); + goto fail; + } + chip->input_dev->name = TRI_KEY_DEVICE; + + set_bit(EV_SYN, chip->input_dev->evbit); + set_bit(EV_KEY, chip->input_dev->evbit); + set_bit(KEY_F3, chip->input_dev->keybit); + res = input_register_device(chip->input_dev); + if (res) { + TRI_KEY_ERR("%s: Failed to register input device\n", __func__); + input_free_device(chip->input_dev); + goto fail; + } + res = init_trikey_proc(pdev); + if (res < 0) { + TRI_KEY_ERR("create trikey proc fail\n"); + goto fail; + } + + if (0 && (!chip->dhall_up_ops || !chip->dhall_down_ops)) { + TRI_KEY_ERR("no dhall available\n"); + goto fail; + } + + + + INIT_WORK(&chip->dwork, tri_key_dev_work); + hrtimer_init(&tri_key_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + tri_key_timer.function = tri_key_status_timeout; + INIT_WORK(&tri_key_timeout_work, tri_key_timeout_work_func); +/*get data when reboot*/ + res = oplus_get_data(chip); + if (res < 0) { + TRI_KEY_LOG("tri_key:get hall data failed!\n"); + goto fail; + } + TRI_KEY_LOG("tri_key:data1 is %d, data0 is %d\n", + chip->dhall_data1, chip->dhall_data0); + +/*get position when reboot*/ + reboot_get_position(chip); +/*set threshold when reboot;*/ + err = reupdata_threshold(chip); + if (err < 1) { + TRI_KEY_ERR("%s reupdata_threshold failed\n", __func__); + goto fail; + } +/*report key value*/ + report_key_value(chip); + last_position = chip->position; + err = oplus_hall_set_detection_mode(DHALL_0, + DETECTION_MODE_INTERRUPT); + TRI_KEY_LOG("tri_key:set 0 detection mode\n"); + if (err < 0) { + TRI_KEY_ERR("%s set HALL0 detection mode failed %d\n", + __func__, err); + goto fail; + } + err = oplus_hall_set_detection_mode(DHALL_1, + DETECTION_MODE_INTERRUPT); + TRI_KEY_LOG("tri_key:set 1 detection mode\n"); + if (err < 0) { + TRI_KEY_ERR("%s set HALL1 detection mode failed %d\n", + __func__, err); + goto fail; + } + TRI_KEY_LOG("%s probe success.\n", __func__); + return; + +fail: + kfree(chip); + g_the_chip = NULL; + TRI_KEY_LOG("fail\n"); +} + +int oplus_register_hall(const char *name, struct dhall_operations *ops, + struct extcon_dev_data *hall_dev_t) +{ + static int hall_count; + struct extcon_dev_data *hall_dev = hall_dev_t; + + if (!name || !ops) { + TRI_KEY_ERR("name is NULL or ops is NULL,", + "would not register digital hall\n"); + return -EINVAL; + } + + if (!g_the_chip) { + struct extcon_dev_data *chip = kzalloc(sizeof(struct + extcon_dev_data), GFP_KERNEL); + if (!chip) { + TRI_KEY_ERR("kzalloc err\n"); + return -ENOMEM; + } + g_the_chip = chip; + g_hall_dev = hall_dev; + } + TRI_KEY_LOG("name : %s\n", name); + if (strcmp(name, "hall_down") == 0) { + TRI_KEY_LOG("name == hall_down"); + if (!g_the_chip->dhall_down_ops) { + if (ops) { + g_the_chip->dhall_down_ops = ops; + g_the_chip->d_name = name; + hall_count++; + } else { + TRI_KEY_ERR("dhall_down_ops NULL\n"); + return -EINVAL; + } + } else { + TRI_KEY_ERR("dhall_down_ops has been register\n"); + return -EINVAL; + } + } + if (strcmp(name, "hall_up") == 0) { + TRI_KEY_LOG("name == hall_up"); + if (!g_the_chip->dhall_up_ops) { + if (ops) { + g_the_chip->dhall_up_ops = ops; + g_the_chip->d_name = name; + hall_count++; + } else { + TRI_KEY_ERR("dhall_up_ops NULL\n"); + return -EINVAL; + } + } else { + TRI_KEY_ERR("dhall_up_ops has been register\n"); + return -EINVAL; + } + } + if (hall_count > 1) { + INIT_WORK(&g_the_chip->register_work, register_tri_key_dev_work); + schedule_work(&g_the_chip->register_work); + } + return 0; +} +EXPORT_SYMBOL(oplus_register_hall); + + diff --git a/drivers/misc/tri_state_key/oplus_tri_key.h b/drivers/misc/tri_state_key/oplus_tri_key.h new file mode 100644 index 000000000000..970f9c368d55 --- /dev/null +++ b/drivers/misc/tri_state_key/oplus_tri_key.h @@ -0,0 +1,116 @@ +/* SPDX-License-Identifier: GPL-2.0-only*/ +/* + * Copyright (C) 2018-2020 Oplus. All rights reserved. + * File: oplus_tri_key.c + * + * Description: + * Definitions for m1120 tri_state_key data process. + * + * Version: 1.0 + */ +#ifndef __TRIKEY_H__ +#define __TRIKEY_H__ + +#include +#include +#include "ist_hall_ic/hall_ist8801.h" + +enum debug_level { + LEVEL_BASIC, + LEVEL_DEBUG, +}; + +enum dhall_id { + DHALL_0 = 0, + DHALL_1, +}; + +enum dhall_detection_mode { + DETECTION_MODE_POLLING = 0, + DETECTION_MODE_INTERRUPT, + DETECTION_MODE_INVALID, +}; + +enum motor_direction { + MOTOR_DOWN = 0, + MOTOR_UPWARD, +}; + +enum tri_key_position { + UP_STATE, + DOWN_STATE, + MID_STATE, +}; + +extern unsigned int tristate_extcon_tab[]; +extern unsigned int tri_key_debug; + +struct dhall_data_t { + short data0; + short data1; +}; + +struct dhall_operations { + int (*get_data)(short *data); + int (*set_detection_mode)(u8 mode); + int (*enable_irq)(bool enable); + int (*clear_irq)(void); + int (*get_irq_state)(void); + bool (*update_threshold)(int position, short lowthd, short highthd); + void (*dump_regs)(u8 *buf); + int (*set_reg)(int reg, int val); + bool (*is_power_on)(void); + void (*set_sensitivity)(char *data); +}; + +struct extcon_dev_data { + struct work_struct dwork; + struct work_struct register_work; + struct extcon_dev *edev; + struct device *dev; + struct i2c_client *client; + struct input_dev *input_dev; + struct timer_list s_timer; + struct pinctrl *key_pinctrl; + struct pinctrl_state *set_state; + struct delayed_work up_work; + struct delayed_work down_work; + struct dhall_operations *dhall_up_ops; + struct dhall_operations *dhall_down_ops; + struct mutex mtx; + const char *d_name; + const char *m_name; + int position; + int last_position; + int project_info; + int interf; + short state; + short dhall_data0; + short dhall_data1; + short dnHall_UpV; + short dnHall_MdV; + short dnHall_DnV; + short upHall_UpV; + short upHall_MdV; + short upHall_DnV; + int manual2auto_up_switch; + int manual2auto_down_switch; + int irq; +}; + +extern int oplus_register_hall(const char *name, + struct dhall_operations *ops, struct extcon_dev_data *hall_dev); +extern int oplus_hall_get_data(unsigned int id); +extern int oplus_hall_set_detection_mode(unsigned int id, u8 mode); +extern int oplus_hall_enable_irq(unsigned int id, bool enable); +extern int oplus_hall_clear_irq(unsigned int id); +extern int oplus_hall_irq_handler(unsigned int id); +extern int oplus_hall_get_irq_state(unsigned int id); +extern void oplus_hall_dump_regs(unsigned int id, u8 *buf); +extern int oplus_hall_set_reg(unsigned int id, int reg, int val); +extern bool oplus_hall_update_threshold(unsigned int id, + int position, short lowthd, short highthd); +extern bool oplus_hall_is_power_on(void); +extern int aw8697_op_haptic_stop(void); + +#endif /* __TRIKEY_H__ */ diff --git a/drivers/misc/tri_state_key/tri_state_key.c b/drivers/misc/tri_state_key/tri_state_key.c new file mode 100644 index 000000000000..2a0c3fea625f --- /dev/null +++ b/drivers/misc/tri_state_key/tri_state_key.c @@ -0,0 +1,462 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2018-2021 Oplus. All rights reserved. + * File: oplus_tri_key.c + * + * Description: + * Mechanical tri_state_key driver code. + * + * Version: 1.0 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRV_NAME "tri_state_key" +#define TRI_KEY_DEVICE "oplus,tri-state-key" + +#define TRI_KEY_TAG "[tri_state_key] " +#define TRI_KEY_ERR(fmt, args...)\ + pr_info(TRI_KEY_TAG" %s : "fmt, __func__, ##args) +#define TRI_KEY_LOG(fmt, args...)\ + pr_info(TRI_KEY_TAG" %s : "fmt, __func__, ##args) +#define TRI_KEY_DEBUG(fmt, args...)\ + do {\ + if (tri_key_debug == LEVEL_DEBUG)\ + pr_info(TRI_KEY_TAG " %s: " fmt, __func__, ##args);\ + } while (0) + +/* + * KEY1(GPIO10) KEY2(GPIO83) KEY3(GPIO69) + * 1 1 0 | Silent + * 1 0 1 | Vibrate + * 0 1 1 | Ring + */ + +struct trikey_dev_data { + int irq_key3; + int irq_key2; + int irq_key1; + int key1_gpio; + int key2_gpio; + int key3_gpio; + short state; + + struct regulator *vdd_io; + + struct work_struct work; + struct device *dev; + struct input_dev *input_dev; + + struct timer_list s_timer; + struct pinctrl *key_pinctrl; + struct pinctrl_state *set_state; +}; + +static struct trikey_dev_data *trikey_data; + +static int set_gpio_by_pinctrl(void) +{ + return pinctrl_select_state(trikey_data->key_pinctrl, + trikey_data->set_state); +} + +static void tri_key_dev_work(struct work_struct *work) +{ + int key[3] = {0, 0, 0}; + /*op add to fix ISTRACKING-34823 begin*/ + static int pre_key0, pre_key1, pre_key2; + /*op add to fix ISTRACKING-34823 end*/ + key[0] = gpio_get_value(trikey_data->key1_gpio); + key[1] = gpio_get_value(trikey_data->key2_gpio); + key[2] = gpio_get_value(trikey_data->key3_gpio); + TRI_KEY_LOG("key[0]=%d,key[1]=%d,key[2]=%d\n", + key[0], key[1], key[2]); + /*op add to fix ISTRACKING-34823 begin*/ + if (!key[0] || !key[1] || !key[2]) { + if (pre_key0 == key[0] && pre_key1 == key[1] + && pre_key2 == key[2]) { + pre_key0 = key[0]; + pre_key1 = key[1]; + pre_key2 = key[2]; + return; + } + } + /*op add to fix ISTRACKING-34823 end*/ + /*op add to fix GCE-7551 begin*/ + if (key[0] && key[1] && key[2]) { + TRI_KEY_LOG("key[0]=%d,key[1]=%d,key[2]=%d***pre_key0=%d, pre_key1=%d, pre_key2=%d\n", + key[0], key[1], key[2], pre_key0, pre_key1, pre_key2); + if (pre_key0 == 1 && pre_key1 == 1 && pre_key2 == 0) + return; + if (pre_key0 && pre_key1 && pre_key2) { + trikey_data->state = 3; + TRI_KEY_LOG("Debounce timeout: Set the tri key state to 0,1,1\n"); + input_report_key(trikey_data->input_dev, KEY_F3, 3); + input_sync(trikey_data->input_dev); + input_report_key(trikey_data->input_dev, KEY_F3, 0); + input_sync(trikey_data->input_dev); + TRI_KEY_LOG("report down key successful!\n"); + } else { + mod_timer(&trikey_data->s_timer, jiffies + HZ/5); + pre_key0 = key[0]; + pre_key1 = key[1]; + pre_key2 = key[2]; + TRI_KEY_LOG("Wait for debounce timeout\n"); + } + return; + } else { + if (!del_timer(&trikey_data->s_timer)) + TRI_KEY_LOG("timer already expired for floating state\n"); + } + if (!key[0] && !key[1] && !key[2]) + return; + if (!key[0] && !key[1] && key[2]) + return; + if (!key[0] && key[1] && !key[2]) + return; + if (key[0] && !key[1] && !key[2]) + return; + /*op add to fix GCE-7551 end*/ + if(key[0] == 1 && key[1] == 1 && key[2] == 0) { + trikey_data->state = 1; + input_report_key(trikey_data->input_dev, KEY_F3, 1); + input_sync(trikey_data->input_dev); + input_report_key(trikey_data->input_dev, KEY_F3, 0); + input_sync(trikey_data->input_dev); + TRI_KEY_LOG("report up key successful!\n"); + } + + if(key[0] == 1 && key[1] == 0 && key[2] == 1) { + trikey_data->state = 2; + input_report_key(trikey_data->input_dev, KEY_F3, 2); + input_sync(trikey_data->input_dev); + input_report_key(trikey_data->input_dev, KEY_F3, 0); + input_sync(trikey_data->input_dev); + TRI_KEY_LOG("report mid key successful!\n"); + } + + if(key[0] == 0 && key[1] == 1 && key[2] == 1) { + trikey_data->state = 3; + input_report_key(trikey_data->input_dev, KEY_F3, 3); + input_sync(trikey_data->input_dev); + input_report_key(trikey_data->input_dev, KEY_F3, 0); + input_sync(trikey_data->input_dev); + TRI_KEY_LOG("report down key successful!\n"); + } + + /*op add to fix GCE-7551 begin*/ + /*if (!key[2] || !key[1]) + aw8697_op_haptic_stop();*/ + /*op add to fix GCE-7551 end*/ + /*op add to fix ISTRACKING-34823 begin*/ + if (!key[0] || !key[1] || !key[2]) { + pre_key0 = key[0]; + pre_key1 = key[1]; + pre_key2 = key[2]; + } + /*op add to fix ISTRACKING-34823 end*/ +} + + +static irqreturn_t tri_key_dev_interrupt(int irq, void *_dev) +{ + schedule_work(&trikey_data->work); + return IRQ_HANDLED; +} + +static void timer_handle(struct timer_list *t) +{ + schedule_work(&trikey_data->work); +} + +#ifdef CONFIG_OF +static int dev_get_devtree_pdata(struct device *dev) +{ + struct device_node *node; + + node = dev->of_node; + if (!node) + return -EINVAL; + + trikey_data->key3_gpio = + of_get_named_gpio(node, "tristate,gpio_key3", 0); + if ((!gpio_is_valid(trikey_data->key3_gpio))) + return -EINVAL; + TRI_KEY_LOG("trikey_data->key3_gpio=%d\n", trikey_data->key3_gpio); + + trikey_data->key2_gpio = + of_get_named_gpio(node, "tristate,gpio_key2", 0); + if ((!gpio_is_valid(trikey_data->key2_gpio))) + return -EINVAL; + TRI_KEY_LOG("trikey_data->key2_gpio=%d\n", trikey_data->key2_gpio); + + trikey_data->key1_gpio = + of_get_named_gpio(node, "tristate,gpio_key1", 0); + if ((!gpio_is_valid(trikey_data->key1_gpio))) + return -EINVAL; + TRI_KEY_LOG("trikey_data->key1_gpio=%d\n", trikey_data->key1_gpio); + + return 0; +} +#else +static inline int +dev_get_devtree_pdata(struct device *dev) +{ + TRI_KEY_LOG("inline function\n"); + return 0; +} +#endif + +static ssize_t proc_tri_state_read(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + int ret = 0; + char page[6] = {0}; + TRI_KEY_LOG("Called\n"); + snprintf(page, sizeof(page), "%d\n", trikey_data->state); + ret = simple_read_from_buffer(user_buf, count, ppos, page, strlen(page)); + return ret; +} + +static const struct file_operations proc_tri_state_ops = { + .read = proc_tri_state_read, + .open = simple_open, + .owner = THIS_MODULE, +}; + +static int init_trikey_proc(struct trikey_dev_data *trikey_data) +{ + int ret = 0; + struct proc_dir_entry *prEntry_trikey = NULL; + struct proc_dir_entry *prEntry_tmp = NULL; + TRI_KEY_LOG("entry\n"); + + prEntry_trikey = proc_mkdir("tristatekey", NULL); + if (prEntry_trikey == NULL) { + ret = -ENOMEM; + TRI_KEY_ERR("Couldn't create trikey proc entry\n"); + } + + prEntry_tmp = proc_create("tri_state", 0644, prEntry_trikey, &proc_tri_state_ops); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + TRI_KEY_ERR("Couldn't create proc entry, %d\n"); + } + + return ret; +} + +static int tri_key_dev_probe(struct platform_device *pdev) +{ + struct device *dev; + int ret = 0; + TRI_KEY_LOG("called\n"); + dev = &pdev->dev; + + trikey_data = kzalloc(sizeof(struct trikey_dev_data), GFP_KERNEL); + if (!trikey_data) { + TRI_KEY_ERR("kzalloc err\n"); + return -ENOMEM; + } + + trikey_data->dev = dev; + + trikey_data->key_pinctrl = devm_pinctrl_get(trikey_data->dev); + + if (IS_ERR_OR_NULL(trikey_data->key_pinctrl)) { + TRI_KEY_ERR("Failed to get pinctrl\n"); + goto fail; + } + trikey_data->set_state = pinctrl_lookup_state(trikey_data->key_pinctrl, + "pmx_tri_state_key_active"); + if (IS_ERR_OR_NULL(trikey_data->set_state)) { + TRI_KEY_ERR("Failed to lookup_state\n"); + goto fail; + } + + set_gpio_by_pinctrl(); + + ret = dev_get_devtree_pdata(dev); + if (ret) { + TRI_KEY_ERR("parse device tree fail!!!\n"); + goto fail; + } + + /* input registration */ + trikey_data->input_dev = input_allocate_device(); + if (trikey_data->input_dev == NULL) { + ret = -ENOMEM; + TRI_KEY_ERR("Failed to allocate input device\n"); + goto fail; + } + trikey_data->input_dev->name = TRI_KEY_DEVICE; + + set_bit(EV_SYN, trikey_data->input_dev->evbit); + set_bit(EV_KEY, trikey_data->input_dev->evbit); + set_bit(KEY_F3, trikey_data->input_dev->keybit); + + ret = input_register_device(trikey_data->input_dev); + if (ret) { + TRI_KEY_ERR("Failed to register input device\n"); + input_free_device(trikey_data->input_dev); + goto fail; + } + + ret = init_trikey_proc(trikey_data); + if (ret < 0) { + TRI_KEY_ERR("create trikey proc fail\n"); + goto proc_fail; + } + + /*config irq gpio and request irq */ + ret = gpio_request(trikey_data->key1_gpio, "tristate_key1"); + if (ret < 0) + goto err_request_gpio; + + ret = gpio_direction_input(trikey_data->key1_gpio); + if (ret < 0) + goto err_set_gpio_input; + + trikey_data->irq_key1 = gpio_to_irq(trikey_data->key1_gpio); + if (trikey_data->irq_key1 < 0) { + ret = trikey_data->irq_key1; + goto err_detect_irq_num_failed; + } + + ret = request_irq(trikey_data->irq_key1, tri_key_dev_interrupt, + IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING, + "tristate_key1", trikey_data); + if (ret < 0) + goto err_request_irq; + + ret = gpio_request(trikey_data->key2_gpio, + "tristate_key2"); + if (ret < 0) + goto err_request_gpio; + + ret = gpio_direction_input(trikey_data->key2_gpio); + if (ret < 0) + goto err_set_gpio_input; + + trikey_data->irq_key2 = gpio_to_irq(trikey_data->key2_gpio); + if (trikey_data->irq_key2 < 0) { + ret = trikey_data->irq_key2; + goto err_detect_irq_num_failed; + } + + ret = request_irq(trikey_data->irq_key2, tri_key_dev_interrupt, + IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING, + "tristate_key2", trikey_data); + if (ret < 0) + goto err_request_irq; + + ret = gpio_request(trikey_data->key3_gpio, + "tristate_key3"); + if (ret < 0) + goto err_request_gpio; + + ret = gpio_direction_input(trikey_data->key3_gpio); + if (ret < 0) + goto err_set_gpio_input; + + trikey_data->irq_key3 = gpio_to_irq(trikey_data->key3_gpio); + if (trikey_data->irq_key3 < 0) { + ret = trikey_data->irq_key3; + goto err_detect_irq_num_failed; + } + + ret = request_irq(trikey_data->irq_key3, tri_key_dev_interrupt, + IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING, + "tristate_key3", trikey_data); + if (ret < 0) + goto err_request_irq; + + INIT_WORK(&trikey_data->work, tri_key_dev_work); + + /*init_timer(&trikey_data->s_timer);*/ + __init_timer(&trikey_data->s_timer, timer_handle, 0); + /*trikey_data->s_timer.function = &timer_handle;*/ + trikey_data->s_timer.expires = jiffies + 5*HZ; + + add_timer(&trikey_data->s_timer); + + enable_irq_wake(trikey_data->irq_key1); + enable_irq_wake(trikey_data->irq_key2); + enable_irq_wake(trikey_data->irq_key3); + + return 0; + +err_request_gpio: +err_request_irq: +err_detect_irq_num_failed: +err_set_gpio_input: + gpio_free(trikey_data->key2_gpio); + gpio_free(trikey_data->key1_gpio); + gpio_free(trikey_data->key3_gpio); +proc_fail: + input_unregister_device(trikey_data->input_dev); +fail: + kfree(trikey_data); + + return ret; +} + +static int tri_key_dev_remove(struct platform_device *pdev) +{ + cancel_work_sync(&trikey_data->work); + gpio_free(trikey_data->key1_gpio); + gpio_free(trikey_data->key2_gpio); + gpio_free(trikey_data->key3_gpio); + input_unregister_device(trikey_data->input_dev); + kfree(trikey_data); + return 0; +} +#ifdef CONFIG_OF +static const struct of_device_id tri_key_dev_of_match[] = { + { .compatible = "oplus, tri-state-key", }, + { }, +}; +MODULE_DEVICE_TABLE(of, tri_key_dev_of_match); +#endif + +static struct platform_driver tristate_dev_driver = { + .probe = tri_key_dev_probe, + .remove = tri_key_dev_remove, + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, + .of_match_table = tri_key_dev_of_match, + }, +}; +static int __init tri_state_key_init(void) +{ + return platform_driver_register(&tristate_dev_driver); +} +module_init(tri_state_key_init); + +static void __exit tri_state_key_exit(void) +{ + platform_driver_unregister(&tristate_dev_driver); +} +module_exit(tri_state_key_exit); +MODULE_DESCRIPTION("mechanical tri_state_key driver"); +MODULE_LICENSE("GPL v2"); + diff --git a/drivers/misc/uid_sys_stats.c b/drivers/misc/uid_sys_stats.c index cb027ed1f8c3..03f264761e03 100644 --- a/drivers/misc/uid_sys_stats.c +++ b/drivers/misc/uid_sys_stats.c @@ -29,6 +29,14 @@ #include #include +#ifdef CONFIG_OPLUS_FEATURE_UID_PERF +#include +#include +#include +#include +#include +#include +#endif #define UID_HASH_BITS 10 DECLARE_HASHTABLE(hash_table, UID_HASH_BITS); @@ -76,6 +84,11 @@ struct uid_entry { #ifdef CONFIG_UID_SYS_STATS_DEBUG DECLARE_HASHTABLE(task_entries, UID_HASH_BITS); #endif +#ifdef CONFIG_OPLUS_FEATURE_UID_PERF + long long counts[UID_PERF_EVENTS]; + atomic64_t checkout[UID_PERF_EVENTS]; + atomic64_t cg_checkout[UID_GROUP_SIZE]; /* MUSTFIX only inst pevent for calc */ +#endif }; static u64 compute_write_bytes(struct task_struct *task) @@ -329,6 +342,534 @@ static struct uid_entry *find_or_register_uid(uid_t uid) return uid_entry; } + +#ifdef CONFIG_OPLUS_FEATURE_UID_PERF +static bool uid_perf_debug; +module_param_named(uid_perf_debug, uid_perf_debug, bool, 0664); + +static bool uid_perf_enable; + +static int uid_perf_event_id[UID_PERF_EVENTS] = { + 0x8, /* "raw-inst-retired" */ + 0x11, /* "raw-cpu-cycles" */ + 0x24 /* "raw-stall-backend" */ +}; + +static int uid_perf_event_type[UID_PERF_EVENTS] = { + PERF_TYPE_RAW, + PERF_TYPE_RAW, + PERF_TYPE_RAW +}; + +static int uid_perf_event_pin[UID_PERF_EVENTS] = { + 0, + 0, + 0 +}; + +module_param_array(uid_perf_event_id, int, NULL, 0664); +module_param_array(uid_perf_event_type, int, NULL, 0664); +module_param_array(uid_perf_event_pin, int, NULL, 0664); + +static DEFINE_SPINLOCK(uid_perf_lock); +static struct task_struct *uid_perf_add_thread; +static struct task_struct *uid_perf_remove_thread; +static struct list_head uid_perf_add_list = LIST_HEAD_INIT(uid_perf_add_list); +static struct list_head uid_perf_remove_list = LIST_HEAD_INIT(uid_perf_remove_list); + +static bool snapshot_active = false; +bool get_uid_perf_enable(void) +{ + return (uid_perf_enable && snapshot_active); +} + +struct uid_work { + struct task_struct *task; + struct list_head node; +}; + +void uid_perf_work_add(struct task_struct *task, bool force) +{ + unsigned long flag; + struct uid_work *work; + + if (!uid_perf_enable && !force) + return; + + work = kmalloc(sizeof(struct uid_work), GFP_ATOMIC); + if (!work) + return; + + if (uid_perf_debug) + pr_err("add task %s %d to add list\n", task->comm, task->pid); + + spin_lock_irqsave(&uid_perf_lock, flag); + get_task_struct(task); + work->task = task; + list_add_tail(&work->node, &uid_perf_add_list); + spin_unlock_irqrestore(&uid_perf_lock, flag); + + wake_up_process(uid_perf_add_thread); +} + +static void uid_perf_work_remove(struct task_struct *task) +{ + unsigned long flag; + struct uid_work *work; + + work = kmalloc(sizeof(struct uid_work), GFP_ATOMIC); + if (!work) + return; + + if (uid_perf_debug) + pr_err("add task %s %d to remove list\n", task->comm, task->pid); + + spin_lock_irqsave(&uid_perf_lock, flag); + get_task_struct(task); + work->task = task; + list_add_tail(&work->node, &uid_perf_remove_list); + spin_unlock_irqrestore(&uid_perf_lock, flag); + + wake_up_process(uid_perf_remove_thread); +} + +static inline void reset_group_data(struct task_struct *task) +{ + int i; + + for (i = 0; i < UID_GROUP_SIZE; ++i) { + task->uid_group_prev_counts[i] = 0; + task->uid_group[i] = 0; + } +} + +static inline void uid_remove_and_disable_one_pevent(struct task_struct *task, int idx) +{ + if (!task->uid_pevents[idx]) + return; + + perf_event_disable(task->uid_pevents[idx]); + perf_event_release_kernel(task->uid_pevents[idx]); + task->uid_prev_counts[idx] = 0; + task->uid_pevents[idx] = NULL; + reset_group_data(task); + + if (uid_perf_debug) + pr_err("task %s %d disable pevent %d\n", task->comm, task->pid, idx); +} + +static void uid_create_and_enable_one_pevent(struct task_struct *task, int idx, bool grouping) +{ + struct perf_event *pevent; + struct perf_event_attr attr; + + if (uid_perf_event_id[idx] == -1) + return; + + if (!task->uid_pevents[idx]) { + memset(&attr, 0, sizeof(struct perf_event_attr)); + attr.size = sizeof(struct perf_event_attr); + attr.inherit = 0; + attr.read_format = 7; + attr.sample_type = 455; + attr.config = uid_perf_event_id[idx]; + attr.type = uid_perf_event_type[idx]; + attr.pinned = uid_perf_event_pin[idx]; + if (grouping) { + attr.read_format = PERF_FORMAT_GROUP; + attr.inherit = 1; + } + + /* TODO add overflow handler */ + pevent = perf_event_create_kernel_counter(&attr, -1, task, NULL, NULL); + if (IS_ERR(pevent)) { + pr_err("task %s %d pevent %d create failed\n", task->comm, task->pid, idx); + } else { + task->uid_pevents[idx] = pevent; + if (uid_perf_debug) + pr_err("task %s %d pevent %d created\n", + task->comm, task->pid, idx); + } + } +} + +void uid_check_out_pevent(struct task_struct *task) +{ + struct uid_entry *uid_entry = NULL; + u64 val, enabled, running, delta, cg_delta; + uid_t uid; + int i, idx; + struct task_struct *tgid = NULL; + + for (i = 0; i < UID_PERF_EVENTS; ++i) { + if (task->uid_pevents[i]) { + val = perf_event_read_value(task->uid_pevents[i], &enabled, &running); + delta = val - task->uid_prev_counts[i]; + /* MUSTFIX only calc instruction counter for cpuset */ + if (i == 0) { + idx = cpuset_get_cgrp_idx(task); + if (idx > -1) + cg_delta = val - task->uid_group_prev_counts[idx]; + else + pr_err("%s: idx is invalid value idx=%d task=%s pid=%d", __func__, idx, task->comm, task->pid); + } + uid_remove_and_disable_one_pevent(task, i); + + /* add back to tgid entry */ + if (!tgid) { + rcu_read_lock(); + tgid = find_task_by_vpid(task->tgid); + if (tgid) + get_task_struct(tgid); + rcu_read_unlock(); + } + + if (tgid) { + /* 2 cases + 1. normal task leave, add delta to tgid + 2. leader task leave, add delta to uid entry + */ + if (tgid->pid == task->pid) { + if (!uid_entry) { + uid = from_kuid_munged(current_user_ns(), task_uid(tgid)); + uid_entry = find_uid_entry(uid); + } + + if (uid_entry) { + atomic64_add(delta, &uid_entry->checkout[i]); + /* MUSTFIX cgroup only calc instruction pevent */ + if (i == 0 && idx > -1) { + atomic64_add(cg_delta, &uid_entry->cg_checkout[idx]); + if (uid_perf_debug) { + pr_err("%s: task %s %d %d %d val: %llu cg_delta: %llu cg_prev: %llu\n", + __func__, task->comm, task->pid, task->tgid, + uid, val, + cg_delta, (val - cg_delta)); + } + } + if (uid_perf_debug) { + pr_err("task %s %d %d %d leave event %d val: %llu delta: %llu prev: %llu\n", + task->comm, task->pid, task->tgid, + uid, i, val, delta, + task->uid_prev_counts[i]); + } + } + } else { + /* TODO change to atomic */ + tgid->uid_leaving_counts[i] += delta; + /* MUSTFIX cpuset checkout pevent conter only for instructions */ + if (i == 0 & idx > -1) { + if (uid_perf_debug) + pr_err("%s: tgid leaving task=%d tgid=%d cg_delta=%llu idx=%d tgid original count=%llu", + __func__, task->pid, tgid->pid, cg_delta, idx, tgid->uid_group[idx]); + + tgid->uid_group[idx] += cg_delta; + } + } + + if (uid_perf_debug) + pr_err("task %s %d %d uid %d leave event %d val: %llu cur %llu\n", task->comm, task->pid, task->tgid, uid, i, delta, tgid->uid_leaving_counts[i]); + } + } + } + + if (tgid) + put_task_struct(tgid); +} + +struct cpufreq_stats { + unsigned int total_trans; + unsigned long long last_time; + unsigned int max_state; + unsigned int state_num; + unsigned int last_index; + u64 *time_in_state; + spinlock_t lock; + unsigned int *freq_table; + unsigned int *trans_table; +}; + +static inline void uid_cpufreq_stats_update(struct cpufreq_stats *st) +{ + unsigned long long cur_time; + unsigned long flags; + + spin_lock_irqsave(&st->lock, flags); + cur_time = get_jiffies_64(); + st->time_in_state[st->last_index] += cur_time - st->last_time; + st->last_time = cur_time; + spin_unlock_irqrestore(&st->lock, flags); +} + +static u64 uid_get_norm_cpu_time(void) +{ + struct cpufreq_policy *pol; + struct cpufreq_stats *st; + int i = 0, j; + u64 total = 0, cur_time; + u64 norm_freq = UINT_MAX, cur_freq; + + if (1) + return 0; + + while (i != nr_cpu_ids) { + pol = cpufreq_cpu_get(i); + if (!pol) + continue; + st = (struct cpufreq_stats *) pol->stats; + + /* update state */ + uid_cpufreq_stats_update(st); + + for (j = 0; j < st->state_num; ++j) { + cur_freq = st->freq_table[j]; + norm_freq = min(norm_freq, cur_freq); + cur_time = st->time_in_state[j]; + total += cur_time * cur_freq / norm_freq; + if (uid_perf_debug) { + pr_err("norm_count: cpu %d freq %llu norm %llu st %llu total %llu\n", + i, cur_freq, norm_freq, cur_time, total); + } + } + i += cpumask_weight(pol->related_cpus); + cpufreq_cpu_put(pol); + } + return total; +} + +static int uid_perf_show(struct seq_file *m, void *v) +{ + struct task_struct *task, *temp; + struct user_namespace *user_ns = current_user_ns(); + unsigned long bkt; + struct uid_entry *uid_entry = NULL; + uid_t uid; + u64 enabled, running; + int i, idx, j; + u64 val[UID_PERF_EVENTS]; + s64 time = ktime_to_ms(ktime_get()); + + rcu_read_lock(); + do_each_thread(temp, task) { + uid = from_kuid_munged(user_ns, task_uid(task)); + + /* avoid double accounting of dying threads */ + if (!(task->flags & PF_EXITING)) { + get_task_struct(task); + rcu_read_unlock(); + + seq_printf(m, "%s,%d,%d,%d", task->comm, task->pid, task->tgid, uid); + for (i = 0; i < UID_PERF_EVENTS; ++i) { + val[i] = 0; + + if (task->uid_pevents[i]) { + val[i] = perf_event_read_value(task->uid_pevents[i], + &enabled, &running); + task->uid_prev_counts[i] = val[i]; + } + seq_printf(m, ",%llu", val[i] + task->uid_leaving_counts[i]); + } + + /* get current cgroup which task is belong to. */ + idx = cpuset_get_cgrp_idx_locked(task); + if (idx > -1) { + /* MUSTFIX only inst event in the cpuset */ + for (i = 0; i < 1; ++i) { + if (val[i] == 0) + continue; + /* update the pevent counter in current cgroup */ + if (task->uid_group_prev_counts[idx] > 0) { + task->uid_group[idx] += (val[i] - task->uid_group_prev_counts[idx]); + if (uid_perf_debug) + pr_err("%s: pid=%d comm=%s val=%llu cgid_idx=%d prev_count=%llu uid_group=%llu", + __func__, + task->pid, + task->comm, + val[i], + idx, + task->uid_group_prev_counts[idx], + task->uid_group[idx]); + } else { + /* first snapshot in the current cgroup */ + task->uid_group_prev_counts[idx] = val[i]; + if (uid_perf_debug) + pr_err("%s: pid=%d comm=%s val=%llu cgid_idx=%d prev_count=%llu", + __func__, + task->pid, + task->comm, + val[i], + idx, + task->uid_group_prev_counts[idx]); + } + } + } + /* output all counter of all groups */ + for (j = 0; j < UID_GROUP_SIZE; ++j) + seq_printf(m, ",%llu", task->uid_group[j]); + + seq_puts(m, "\n"); + + rcu_read_lock(); + if (snapshot_active) + reset_group_data(task); + put_task_struct(task); + } + } while_each_thread(temp, task); + rcu_read_unlock(); + + /* FIXME for some reasons this functions will be called while use 'cat' */ + /* update early leave counter */ + hash_for_each(hash_table, bkt, uid_entry, hash) { + seq_printf(m, "uid-%d,0,0,%d", uid_entry->uid, uid_entry->uid); + for (i = 0; i < UID_PERF_EVENTS; ++i) + seq_printf(m, ",%llu", atomic64_read(&uid_entry->checkout[i])); + /* cgroup counters */ + for (i = 0; i < UID_GROUP_SIZE; ++i) + seq_printf(m, ",%llu", atomic64_read(&uid_entry->cg_checkout[i])); + seq_puts(m, "\n"); + } + /*cpuset switch counting will be align snapshot_active scope */ + snapshot_active = !snapshot_active; + + seq_printf(m, "%lld,%llu\n", time, uid_get_norm_cpu_time()); + return 0; +} + +static int uid_perf_open(struct inode *inode, struct file *file) +{ + return single_open_size(file, uid_perf_show, NULL, 0x1 << 20); +} + +static const struct file_operations uid_perf_fops = { + .open = uid_perf_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int uid_perf_enable_store(const char *buf, const struct kernel_param *kp) +{ + struct task_struct *task, *temp; + int val; + + if (sscanf(buf, "%d\n", &val) <= 0) + return 0; + + if (uid_perf_enable == val) + return 0; + + if (val == 0) + uid_perf_enable = val; + + /* TODO should protect from race */ + read_lock(&tasklist_lock); + for_each_process_thread(temp, task) { + if (val) { + /* quick check if has any pevent exists, check next */ + if (task->flags & PF_EXITING || task->uid_pevents[0]) + continue; + + uid_perf_work_add(task, true); + } else { + if (task->flags & PF_EXITING) + continue; + uid_perf_work_remove(task); + } + } + read_unlock(&tasklist_lock); + + if (val == 1) + uid_perf_enable = val; + + if (val) + wake_up_process(uid_perf_add_thread); + else + wake_up_process(uid_perf_remove_thread); + + return 0; +} + +static int uid_perf_enable_show(char *buf, const struct kernel_param *kp) +{ + return snprintf(buf, PAGE_SIZE, "%d\n", uid_perf_enable); +} + +static struct kernel_param_ops uid_perf_enable_ops = { + .set = uid_perf_enable_store, + .get = uid_perf_enable_show, +}; +module_param_cb(uid_perf_enable, &uid_perf_enable_ops, NULL, 0664); + +static int __uid_perf_add_work(void *unused) +{ + unsigned long flag; + int i; + + while (!kthread_should_stop()) { + set_current_state(TASK_RUNNING); + spin_lock_irqsave(&uid_perf_lock, flag); + while (!list_empty(&uid_perf_add_list)) { + struct uid_work *work = + list_first_entry(&uid_perf_add_list, struct uid_work, node); + struct task_struct *task = work->task; + + list_del(&work->node); + kfree(work); + spin_unlock_irqrestore(&uid_perf_lock, flag); + + /* init perf event */ + if (task && !(task->flags & PF_EXITING)) { + for (i = 0; i < UID_PERF_EVENTS; ++i) + uid_create_and_enable_one_pevent(task, i, false); + } + put_task_struct(task); + spin_lock_irqsave(&uid_perf_lock, flag); + } + + spin_unlock_irqrestore(&uid_perf_lock, flag); + + set_current_state(TASK_INTERRUPTIBLE); + freezable_schedule(); + } + + return 0; +} + +static int __uid_perf_remove_work(void *unused) +{ + unsigned long flag; + int i; + + while (!kthread_should_stop()) { + set_current_state(TASK_RUNNING); + spin_lock_irqsave(&uid_perf_lock, flag); + while (!list_empty(&uid_perf_remove_list)) { + struct uid_work *work = + list_first_entry(&uid_perf_remove_list, struct uid_work, node); + struct task_struct *task = work->task; + + list_del(&work->node); + kfree(work); + spin_unlock_irqrestore(&uid_perf_lock, flag); + + /* remove perf event */ + if (task && !(task->flags & PF_EXITING)) { + for (i = 0; i < UID_PERF_EVENTS; ++i) + uid_remove_and_disable_one_pevent(task, i); + } + put_task_struct(task); + spin_lock_irqsave(&uid_perf_lock, flag); + } + + spin_unlock_irqrestore(&uid_perf_lock, flag); + + set_current_state(TASK_INTERRUPTIBLE); + freezable_schedule(); + } + + return 0; +} +#endif static int uid_cputime_show(struct seq_file *m, void *v) { struct uid_entry *uid_entry = NULL; @@ -677,6 +1218,13 @@ static int __init proc_uid_sys_stats_init(void) proc_create_data("show_uid_stat", 0444, cpu_parent, &uid_cputime_fops, NULL); +#ifdef CONFIG_OPLUS_FEATURE_UID_PERF + proc_create_data("show_uid_perf", 0444, cpu_parent, + &uid_perf_fops, NULL); + uid_perf_add_thread = kthread_create(__uid_perf_add_work, NULL, "uid_add_thread"); + uid_perf_remove_thread = kthread_create(__uid_perf_remove_work, NULL, "uid_remove_thread"); +#endif + io_parent = proc_mkdir("uid_io", NULL); if (!io_parent) { pr_err("%s: failed to create uid_io proc entry\n", diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig index ec21388311db..30de856b1538 100644 --- a/drivers/mmc/Kconfig +++ b/drivers/mmc/Kconfig @@ -18,4 +18,10 @@ source "drivers/mmc/core/Kconfig" source "drivers/mmc/host/Kconfig" +config EMMC_SDCARD_OPTIMIZE + tristate "emmc sdcard optimize" + default n + help + emmc sdcard optimize. + endif # MMC diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c index b454e954e2ad..0f4aa49dd2d7 100644 --- a/drivers/mmc/core/block.c +++ b/drivers/mmc/core/block.c @@ -79,6 +79,14 @@ MODULE_ALIAS("mmc:block"); (rq_data_dir(req) == WRITE)) static DEFINE_MUTEX(block_mutex); +#ifdef OPLUS_FEATURE_EMMC_DRIVER +/* add for emmc device in /proc/devinfo */ +int __attribute__((weak)) register_device_proc(char *name, char *version, char *vendor) +{ + return 0; +} +#endif + /* * The defaults come from config options but can be overriden by module * or bootarg options. @@ -136,6 +144,11 @@ struct mmc_blk_data { /* debugfs files (only in main mmc_blk_data) */ struct dentry *status_dentry; struct dentry *ext_csd_dentry; +#ifdef OPLUS_FEATURE_EMMC_DRIVER +/* add for emmc lifetime */ + struct dentry *sector_count_dentry; + struct dentry *life_time_dentry; +#endif }; /* Device type for RPMB character devices */ @@ -512,7 +525,14 @@ static int __mmc_blk_ioctl_cmd(struct mmc_card *card, struct mmc_blk_data *md, struct mmc_command cmd = {}, sbc = {}; struct mmc_data data = {}; struct mmc_request mrq = {}; +#ifndef OPLUS_FEATURE_STORAGE_TOOL +/* If data size in ioctl too large ,kernel will panic */ struct scatterlist sg; +#else + struct scatterlist sg[16],*isg=0; + unsigned int i,sg_len,size; + unsigned int item_len = queue_max_segment_size(md->queue.queue); +#endif int err; unsigned int target_part; @@ -538,12 +558,34 @@ static int __mmc_blk_ioctl_cmd(struct mmc_card *card, struct mmc_blk_data *md, cmd.flags = idata->ic.flags; if (idata->buf_bytes) { +#ifndef OPLUS_FEATURE_STORAGE_TOOL +/* If data size in ioctl too large ,kernel will panic */ data.sg = &sg; data.sg_len = 1; +#else + sg_len = (idata->buf_bytes+item_len-1)/item_len; + pr_err("mmc sg_len:%d\n",sg_len); + data.sg = sg; + data.sg_len = sg_len; + +#endif data.blksz = idata->ic.blksz; data.blocks = idata->ic.blocks; +#ifndef OPLUS_FEATURE_STORAGE_TOOL +/* If data size in ioctl too large ,kernel will panic */ sg_init_one(data.sg, idata->buf, idata->buf_bytes); +#else + sg_init_table(data.sg, sg_len); + for_each_sg(data.sg, isg, sg_len, i){ + size = item_len; + if(sg_is_last(isg)){ + size = idata->buf_bytes-(i*item_len); + } + pr_err("mmc size:%d\n",size); + sg_set_buf(isg, idata->buf+(i*item_len), size); + } +#endif if (idata->ic.write_flag) data.flags = MMC_DATA_WRITE; @@ -1080,6 +1122,16 @@ static void mmc_blk_issue_drv_op(struct mmc_queue *mq, struct request *req) if (ret) break; } +#ifndef OPLUS_FEATURE_STORAGE_TOOL +/* If data size in ioctl too large ,kernel will panic */ + pr_err("mmc __mmc_blk_ioctl_cmd enter cardState 0x%x ,cmdq(%d %d %d) , adma2len %d\n", + card->state, + card->ext_csd.cmdq_en, + card->ext_csd.cmdq_depth, + card->ext_csd.cmdq_support, + card->host->max_seg_size + ); +#endif /* fallthrough */ case MMC_DRV_OP_IOCTL_RPMB: idata = mq_rq->drv_op_data; @@ -2916,6 +2968,180 @@ static const struct file_operations mmc_dbg_ext_csd_fops = { .llseek = default_llseek, }; +#ifdef OPLUS_FEATURE_EMMC_DRIVER +/* add for emmc lifetime */ +#define SECTOR_COUNT_BUF_LEN 16 +static int mmc_sector_count_open(struct inode *inode, struct file *filp) +{ + struct mmc_card *card = inode->i_private; + struct mmc_blk_data *md = dev_get_drvdata(&card->dev); + struct mmc_queue *mq = &md->queue; + struct request *req; + char *buf; + ssize_t n = 0; + u8 *ext_csd; + int err; + unsigned int sector_count = 0; + + buf = kmalloc(SECTOR_COUNT_BUF_LEN + 1, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + /* Ask the block layer for the EXT CSD */ + req = blk_get_request(mq->queue, REQ_OP_DRV_IN, __GFP_RECLAIM); + if (IS_ERR(req)) { + err = PTR_ERR(req); + goto out_free; + } + req_to_mmc_queue_req(req)->drv_op = MMC_DRV_OP_GET_EXT_CSD; + req_to_mmc_queue_req(req)->drv_op_data = &ext_csd; + blk_execute_rq(mq->queue, NULL, req, 0); + err = req_to_mmc_queue_req(req)->drv_op_result; + blk_put_request(req); + if (err) { + pr_err("FAILED %d\n", err); + goto out_free; + } + + sector_count = (ext_csd[215]<<24) |(ext_csd[214]<<16)| + (ext_csd[213]<<8)|(ext_csd[212]); + n = sprintf(buf, "0x%08x\n", sector_count); + + if (n > SECTOR_COUNT_BUF_LEN) { + err = -EINVAL; + kfree(ext_csd); + goto out_free; + } + + filp->private_data = buf; + + kfree(ext_csd); + return 0; + +out_free: + kfree(buf); + return err; +} + +static ssize_t mmc_sector_count_read(struct file *filp, char __user *ubuf, + size_t cnt, loff_t *ppos) +{ + char *buf = filp->private_data; + int len = strlen(buf); + return simple_read_from_buffer(ubuf, cnt, ppos, + buf, len); +} + +static int mmc_sector_count_release(struct inode *inode, struct file *file) +{ + kfree(file->private_data); + return 0; +} + +static const struct file_operations mmc_dbg_sector_count_fops = { + .open = mmc_sector_count_open, + .read = mmc_sector_count_read, + .release = mmc_sector_count_release, + .llseek = default_llseek, +}; + +#define LIFE_TIME_BUF_LEN 256 +static char* life_time_table[]={ + "Not defined", + "0%-10% device life time used", + "10%-20% device life time used", + "20%-30% device life time used", + "30%-40% device life time used", + "30%-40% device life time used", + "40%-50% device life time used", + "60%-70% device life time used", + "80%-90% device life time used", + "90%-100% device life time used", + "Exceeded its maximum estimated device life time", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", +}; + +static int mmc_life_time_open(struct inode *inode, struct file *filp) +{ + struct mmc_card *card = inode->i_private; + struct mmc_blk_data *md = dev_get_drvdata(&card->dev); + struct mmc_queue *mq = &md->queue; + struct request *req; + char *buf; + ssize_t n = 0; + u8 *ext_csd; + int err; + unsigned char life_time_A = 0; + unsigned char life_time_B = 0; + + buf = kmalloc(LIFE_TIME_BUF_LEN + 1, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + /* Ask the block layer for the EXT CSD */ + req = blk_get_request(mq->queue, REQ_OP_DRV_IN, __GFP_RECLAIM); + if (IS_ERR(req)) { + err = PTR_ERR(req); + goto out_free; + } + req_to_mmc_queue_req(req)->drv_op = MMC_DRV_OP_GET_EXT_CSD; + req_to_mmc_queue_req(req)->drv_op_data = &ext_csd; + blk_execute_rq(mq->queue, NULL, req, 0); + err = req_to_mmc_queue_req(req)->drv_op_result; + blk_put_request(req); + if (err) { + pr_err("FAILED %d\n", err); + goto out_free; + } + + life_time_A = ext_csd[268]; + life_time_B = ext_csd[269]; + n = sprintf(buf, "type A:%s\n\rtype B:%s\n\r", + life_time_table[life_time_A],life_time_table[life_time_B]); + + if (n > LIFE_TIME_BUF_LEN) { + err = -EINVAL; + kfree(ext_csd); + goto out_free; + } + + filp->private_data = buf; + + kfree(ext_csd); + return 0; + +out_free: + kfree(buf); + return err; +} + +static ssize_t mmc_life_time_read(struct file *filp, char __user *ubuf, + size_t cnt, loff_t *ppos) +{ + char *buf = filp->private_data; + int len = strlen(buf); + + return simple_read_from_buffer(ubuf, cnt, ppos, + buf, len); +} + +static int mmc_life_time_release(struct inode *inode, struct file *file) +{ + kfree(file->private_data); + return 0; +} + +static const struct file_operations mmc_dbg_life_time_fops = { + .open = mmc_life_time_open, + .read = mmc_life_time_read, + .release = mmc_life_time_release, + .llseek = default_llseek, +}; +#endif static int mmc_blk_add_debugfs(struct mmc_card *card, struct mmc_blk_data *md) { struct dentry *root; @@ -2940,7 +3166,24 @@ static int mmc_blk_add_debugfs(struct mmc_card *card, struct mmc_blk_data *md) if (!md->ext_csd_dentry) return -EIO; } +#ifdef OPLUS_FEATURE_EMMC_DRIVER +/* add for emmc lifetime */ + if (mmc_card_mmc(card)) { + md->sector_count_dentry = + debugfs_create_file("sector_count", S_IRUSR, root, card, + &mmc_dbg_sector_count_fops); + if (!md->sector_count_dentry) + return -EIO; + } + if (mmc_card_mmc(card)) { + md->life_time_dentry = + debugfs_create_file("life_time", (S_IRUSR|S_IRGRP|S_IROTH), root, card, + &mmc_dbg_life_time_fops); + if (!md->life_time_dentry) + return -EIO; + } +#endif return 0; } @@ -2979,13 +3222,53 @@ static int mmc_blk_probe(struct mmc_card *card) { struct mmc_blk_data *md, *part_md; char cap_str[10]; +#ifdef OPLUS_FEATURE_EMMC_DRIVER +/* Add for eMMC and DDR device information */ + char * manufacturerid; + static char temp_version[30] = {0}; +#endif /* * Check that the card supports the command class(es) we need. */ +#ifndef CONFIG_EMMC_SDCARD_OPTIMIZE +/* remove for can not initialize specific sdcard(CSD info mismatch card real capability) */ if (!(card->csd.cmdclass & CCC_BLOCK_READ)) return -ENODEV; +#endif +#ifdef OPLUS_FEATURE_EMMC_DRIVER +/* Add for eMMC and DDR device information */ + switch (card->cid.manfid) { + case 0x11: + manufacturerid = "TOSHIBA"; + break; + case 0x15: + manufacturerid = "SAMSUNG"; + break; + case 0x45: + manufacturerid = "SANDISK"; + break; + case 0x90: + manufacturerid = "HYNIX"; + break; + case 0xFE: + manufacturerid = "ELPIDA"; + break; + case 0x13: + manufacturerid = "MICRON"; + break; + default: + printk("mmc_blk_probe unknown card->cid.manfid is %x\n",card->cid.manfid); + manufacturerid = "unknown"; + break; + } + if ((!strcmp(mmc_card_id(card), "mmc0:0001"))&&(!mmc_card_is_removable(card->host))) { + sprintf(temp_version,"0x%02x,0x%llx",card->cid.prv,*(unsigned long long*)card->ext_csd.fwrev); + register_device_proc("emmc", mmc_card_name(card), manufacturerid); + register_device_proc("emmc_version", mmc_card_name(card), temp_version); + } +#endif mmc_fixup_device(card, mmc_blk_fixups); card->complete_wq = alloc_workqueue("mmc_complete", @@ -3042,6 +3325,17 @@ static int mmc_blk_probe(struct mmc_card *card) return 0; } +#ifdef CONFIG_EMMC_SDCARD_OPTIMIZE +char *capacity_string(struct mmc_card *card){ + static char cap_str[10] = "unknown"; + struct mmc_blk_data *md = (struct mmc_blk_data *)card->dev.driver_data; + if(md==NULL){ + return 0; + } + string_get_size((u64)get_capacity(md->disk), 512, STRING_UNITS_2, cap_str, sizeof(cap_str)); + return cap_str; +} +#endif static void mmc_blk_remove(struct mmc_card *card) { struct mmc_blk_data *md = dev_get_drvdata(&card->dev); diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 215c8ffadd19..5192682f430a 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -3717,7 +3717,11 @@ void mmc_stop_host(struct mmc_host *host) } host->rescan_disable = 1; +#ifndef CONFIG_EMMC_SDCARD_OPTIMIZE cancel_delayed_work_sync(&host->detect); +#else + cancel_delayed_work(&host->detect); +#endif /* clear pm flags now and let card drivers set them as needed */ host->pm_flags = 0; diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c index 634590686cbe..ea2de592e186 100644 --- a/drivers/mmc/core/host.c +++ b/drivers/mmc/core/host.c @@ -459,6 +459,9 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev) INIT_DELAYED_WORK(&host->sdio_irq_work, sdio_irq_work); timer_setup(&host->retune_timer, mmc_retune_timer, 0); +#ifdef CONFIG_EMMC_SDCARD_OPTIMIZE + host->detect_change_retry = 5; +#endif /* CONFIG_EMMC_SDCARD_OPTIMIZE */ /* * By default, hosts do not support SGIO or large requests. * They have to set these according to their abilities. diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c index 2b8b82c47c22..ba5b243b56bc 100644 --- a/drivers/mmc/core/sd.c +++ b/drivers/mmc/core/sd.c @@ -28,6 +28,44 @@ #include "mmc_ops.h" #include "sd.h" #include "sd_ops.h" +#ifdef CONFIG_EMMC_SDCARD_OPTIMIZE +struct menfinfo { + unsigned int manfid; + char *manfstring; +}; + +struct menfinfo manufacturers[] = { + {0x41, "KINGSTONE"}, + {0x1b, "SAMSUNG"}, + {0x03, "SANDISK"}, + {0x02, "TOSHIBA"} +}; +#define MANFINFS_SIZE (sizeof(manufacturers)/sizeof(struct menfinfo)) + +const char *string_class[] = { + "Class 0", + "Class 2", + "Class 4", + "Class 6", + "Class 10" +}; +#define CLASS_TYPE_SIZE (sizeof(string_class)/sizeof(const char*)) + +struct card_blk_data { + spinlock_t lock; + struct gendisk *disk; +}; + +#define STR_OTHER "other" +#define STR_UNKNOW "unknown" +#define STR_TYPE_SDXC "SDXC" +#define STR_TYPE_SDHC "SDHC" +#define STR_TYPE_SD "SD" + +#define STR_SPEED_UHS "ultra high speed " +#define STR_SPEED_HS "high speed " + +#endif /* CONFIG_EMMC_SDCARD_OPTIMIZE */ static const unsigned int tran_exp[] = { 10000, 100000, 1000000, 10000000, @@ -94,6 +132,7 @@ void mmc_decode_cid(struct mmc_card *card) card->cid.month = UNSTUFF_BITS(resp, 8, 4); card->cid.year += 2000; /* SD cards year offset */ + } /* @@ -274,6 +313,9 @@ static int mmc_read_ssr(struct mmc_card *card) card->ssr.au = sd_au_size[au]; es = UNSTUFF_BITS(card->raw_ssr, 408 - 384, 16); et = UNSTUFF_BITS(card->raw_ssr, 402 - 384, 6); +#ifdef CONFIG_EMMC_SDCARD_OPTIMIZE + card->ssr.speed_class = UNSTUFF_BITS(card->raw_ssr, 440 - 384, 8); +#endif /* CONFIG_EMMC_SDCARD_OPTIMIZE */ if (es && et) { eo = UNSTUFF_BITS(card->raw_ssr, 400 - 384, 2); card->ssr.erase_timeout = (et * 1000) / es; @@ -756,6 +798,45 @@ out: return err; } +#ifdef CONFIG_EMMC_SDCARD_OPTIMIZE +const char *manfinfo_string(struct mmc_card *card) { + int i = 0; + for (i = 0; i < MANFINFS_SIZE ; i++) { + if(card->cid.manfid == manufacturers[i].manfid) { + return manufacturers[i].manfstring; + } + } + return STR_OTHER; +} + +extern char *capacity_string(struct mmc_card *card); + +const char *type_string(struct mmc_card *card){ + if(card==NULL || card->type!=MMC_TYPE_SD) + return STR_UNKNOW; + if (mmc_card_blockaddr(card)) { + if (mmc_card_ext_capacity(card)) + return STR_TYPE_SDXC; + else + return STR_TYPE_SDHC; + } + return STR_TYPE_SD; +} + +const char *uhs_string(struct mmc_card *card){ + return mmc_card_uhs(card) ? STR_SPEED_UHS: (mmc_card_hs(card) ? STR_SPEED_HS : ""); +} + +const char *speed_class_string(struct mmc_card *card){ + if(card->ssr.speed_class > (CLASS_TYPE_SIZE-1)){ + return STR_UNKNOW; + } + return string_class[card->ssr.speed_class]; +} + +MMC_DEV_ATTR(devinfo, " manufacturer: %s\n size: %s\n type: %s\n speed: %s\n class: %s\n", + manfinfo_string(card), capacity_string(card), type_string(card), uhs_string(card), speed_class_string(card)); +#endif /* CONFIG_EMMC_SDCARD_OPTIMIZE */ MMC_DEV_ATTR(cid, "%08x%08x%08x%08x\n", card->raw_cid[0], card->raw_cid[1], card->raw_cid[2], card->raw_cid[3]); MMC_DEV_ATTR(csd, "%08x%08x%08x%08x\n", card->raw_csd[0], card->raw_csd[1], @@ -799,6 +880,9 @@ static ssize_t mmc_dsr_show(struct device *dev, static DEVICE_ATTR(dsr, S_IRUGO, mmc_dsr_show, NULL); static struct attribute *sd_std_attrs[] = { +#ifdef CONFIG_EMMC_SDCARD_OPTIMIZE + &dev_attr_devinfo.attr, +#endif /* CONFIG_EMMC_SDCARD_OPTIMIZE */ &dev_attr_cid.attr, &dev_attr_csd.attr, &dev_attr_scr.attr, @@ -1490,8 +1574,17 @@ int mmc_attach_sd(struct mmc_host *host) int err; u32 ocr, rocr; +#ifdef CONFIG_EMMC_SDCARD_OPTIMIZE + int retries; +#endif WARN_ON(!host->claimed); +#ifdef CONFIG_EMMC_SDCARD_OPTIMIZE + if (!host->detect_change_retry) { + pr_err("%s have init error 5 times\n", __func__); + return -ETIMEDOUT; + } +#endif /* CONFIG_EMMC_SDCARD_OPTIMIZE */ err = mmc_send_app_op_cond(host, 0, &ocr); if (err) return err; @@ -1530,6 +1623,12 @@ int mmc_attach_sd(struct mmc_host *host) /* * Detect and init the card. */ +#ifdef CONFIG_EMMC_SDCARD_OPTIMIZE + if (host->detect_change_retry < 5) + retries = 1; + else + retries = 5; +#endif /* CONFIG_EMMC_SDCARD_OPTIMIZE */ err = mmc_sd_init_card(host, rocr, NULL); if (err) goto err; @@ -1547,6 +1646,10 @@ int mmc_attach_sd(struct mmc_host *host) goto remove_card; } +#ifdef CONFIG_EMMC_SDCARD_OPTIMIZE +/* Add for retry 5 times when new sdcard init error */ + host->detect_change_retry = 5; +#endif /* CONFIG_EMMC_SDCARD_OPTIMIZE */ return 0; remove_card: @@ -1556,6 +1659,11 @@ remove_card: err: mmc_detach_bus(host); +#ifdef CONFIG_EMMC_SDCARD_OPTIMIZE + if (err) + host->detect_change_retry--; + pr_err("detect_change_retry = %d !!!,err = %d\n", host->detect_change_retry,err); +#endif /* CONFIG_EMMC_SDCARD_OPTIMIZE */ pr_err("%s: error %d whilst initialising SD card\n", mmc_hostname(host), err); diff --git a/drivers/mmc/core/sd_ops.c b/drivers/mmc/core/sd_ops.c index 5accfb354612..53b18dd04bbe 100644 --- a/drivers/mmc/core/sd_ops.c +++ b/drivers/mmc/core/sd_ops.c @@ -151,7 +151,12 @@ int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr) cmd.arg = ocr; cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R3 | MMC_CMD_BCR; +#ifdef CONFIG_EMMC_SDCARD_OPTIMIZE + for (i = 200; i; i--) { +#else for (i = 100; i; i--) { +#endif + err = mmc_wait_for_app_cmd(host, NULL, &cmd, MMC_CMD_RETRIES); if (err) break; diff --git a/drivers/mmc/core/slot-gpio.c b/drivers/mmc/core/slot-gpio.c index 274a7114ef98..0aef72176028 100644 --- a/drivers/mmc/core/slot-gpio.c +++ b/drivers/mmc/core/slot-gpio.c @@ -43,6 +43,9 @@ static irqreturn_t mmc_gpio_cd_irqt(int irq, void *dev_id) mmc_hostname(host), present, present?"INSERT":"REMOVAL"); host->trigger_card_event = true; +#ifdef CONFIG_EMMC_SDCARD_OPTIMIZE + host->detect_change_retry = 5; +#endif /* CONFIG_EMMC_SDCARD_OPTIMIZE */ mmc_detect_change(host, msecs_to_jiffies(ctx->cd_debounce_delay_ms)); return IRQ_HANDLED; diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 7f044ab6c6b3..8e02fc3f9bd9 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -76,6 +76,14 @@ static void sdhci_dump_state(struct sdhci_host *host) void sdhci_dumpregs(struct sdhci_host *host) { +#ifdef CONFIG_EMMC_SDCARD_OPTIMIZE +/* modify for disable sdcard log */ + static int flag = 0; + if(!flag) + flag++; + else + return; +#endif mmc_log_string(host->mmc, "BLOCK_SIZE=0x%08x BLOCK_COUNT=0x%08x COMMAND=0x%08x INT_STATUS=0x%08x INT_ENABLE=0x%08x SIGNAL_ENABLE=0x%08x\n", sdhci_readw(host, SDHCI_BLOCK_SIZE), diff --git a/drivers/net/wireless/cnss2/main.c b/drivers/net/wireless/cnss2/main.c index eff54c674e43..055f66a4f37e 100644 --- a/drivers/net/wireless/cnss2/main.c +++ b/drivers/net/wireless/cnss2/main.c @@ -12,6 +12,17 @@ #include #include #include +#include +#include +#ifdef OPLUS_BUG_STABILITY +//Add for: disable wifi while power off charging because modem img will not mount +#include +#endif /* OPLUS_BUG_STABILITY */ + +#ifdef CONFIG_OPLUS_KEVENT_UPLOAD +//Add for: pcie self recovery statistics +#include +#endif /* CONFIG_OPLUS_KEVENT_UPLOAD */ #include "main.h" #include "bus.h" @@ -66,6 +77,49 @@ struct cnss_driver_event { void *data; }; +#ifdef OPLUS_FEATURE_WIFI_DCS_SWITCH +//Add for wifi switch monitor +static unsigned int cnssprobestate = 0; +#endif /* OPLUS_FEATURE_WIFI_DCS_SWITCH */ + +#ifdef CONFIG_OPLUS_KEVENT_UPLOAD +//Add for: pcie self recovery statistics +int cnss_stats_self_recovery(void) +{ + const char* cnss_event_tag = "wifi_fool_proof"; + const char* cnss_event_id = "wifi_pci_linkdown"; + const char* cnss_event_payload = "cnss_pcie_self_recovery"; + struct kernel_packet_info* cnss_event; + void *buffer = NULL; + int len, size; + cnss_pr_err("%s\n", __func__); + + len = strlen(cnss_event_payload); + size = sizeof(struct kernel_packet_info) + len + 1; + + buffer = kmalloc(size, GFP_KERNEL); + if (!buffer) { + cnss_pr_err("%s: Allocation failed\n", __func__); + return -ENOMEM; + } + + memset(buffer, 0, size); + cnss_event = (struct kernel_packet_info *)buffer; + cnss_event->type = 1; + + memcpy(cnss_event->log_tag, cnss_event_tag, strlen(cnss_event_tag) + 1); + memcpy(cnss_event->event_id, cnss_event_id, strlen(cnss_event_id) + 1); + + cnss_event->payload_length = len + 1; + memcpy(cnss_event->payload, cnss_event_payload, cnss_event->payload_length); + + kevent_send_to_user(cnss_event); + kfree(buffer); + + return 0; +} +#endif /* CONFIG_OPLUS_KEVENT_UPLOAD */ + static void cnss_set_plat_priv(struct platform_device *plat_dev, struct cnss_plat_data *plat_priv) { @@ -1172,6 +1226,11 @@ self_recovery: cnss_bus_dev_powerup(plat_priv); + #ifdef CONFIG_OPLUS_KEVENT_UPLOAD + //Add for: pcie self recovery statistics + cnss_stats_self_recovery(); + #endif /* CONFIG_OPLUS_KEVENT_UPLOAD */ + return 0; } @@ -2609,6 +2668,10 @@ static void cnss_init_control_params(struct cnss_plat_data *plat_priv) "cnss-daemon-support")) plat_priv->ctrl_params.quirks |= BIT(ENABLE_DAEMON_SUPPORT); + if (of_property_read_bool(plat_priv->plat_dev->dev.of_node, + "cnss-enable-self-recovery")) + plat_priv->ctrl_params.quirks |= BIT(LINK_DOWN_SELF_RECOVERY); + plat_priv->ctrl_params.mhi_timeout = CNSS_MHI_TIMEOUT_DEFAULT; plat_priv->ctrl_params.mhi_m2_timeout = CNSS_MHI_M2_TIMEOUT_DEFAULT; plat_priv->ctrl_params.qmi_timeout = CNSS_QMI_TIMEOUT_DEFAULT; @@ -2658,6 +2721,49 @@ static const struct of_device_id cnss_of_match_table[] = { }; MODULE_DEVICE_TABLE(of, cnss_of_match_table); +#ifdef OPLUS_FEATURE_WIFI_DCS_SWITCH +//Add for wifi switch monitor +static void icnss_create_fw_state_kobj(void); +static void icnss_remove_fw_state_kobj(void); +static ssize_t icnss_show_fw_ready(struct device_driver *driver, char *buf) +{ + bool firmware_ready = false; + bool bdfloadsuccess = false; + bool regdbloadsuccess = false; + bool cnssprobesuccess = false; + if (!plat_env) { + cnss_pr_err("icnss_show_fw_ready plat_env is NULL!\n"); + } else { + firmware_ready = test_bit(CNSS_FW_READY, &plat_env->driver_state); + regdbloadsuccess = test_bit(CNSS_LOAD_REGDB_SUCCESS, &plat_env->loadRegdbState); + bdfloadsuccess = test_bit(CNSS_LOAD_BDF_SUCCESS, &plat_env->loadBdfState); + #ifdef OPLUS_FEATURE_WIFI_DCS_SWITCH + //avoid wifi firmware ready check fail when idle shutdown + cnss_pr_info("firmware_ready: %d; power_on: %d", firmware_ready, plat_env->powered_on); + if (!firmware_ready && !plat_env->powered_on && regdbloadsuccess && bdfloadsuccess) { + firmware_ready = true; + } + #endif /* OPLUS_FEATURE_WIFI_DCS_SWITCH */ + } + cnssprobesuccess = (cnssprobestate == CNSS_PROBE_SUCCESS); + return sprintf(buf, "%s:%s:%s:%s", + (firmware_ready ? "fwstatus_ready" : "fwstatus_not_ready"), + (regdbloadsuccess ? "regdb_loadsuccess" : "regdb_loadfail"), + (bdfloadsuccess ? "bdf_loadsuccess" : "bdf_loadfail"), + (cnssprobesuccess ? "cnssprobe_success" : "cnssprobe_fail") + ); +} + +struct driver_attribute fw_ready_attr = { + .attr = { + .name = "firmware_ready", + .mode = S_IRUGO, + }, + .show = icnss_show_fw_ready, + //read only so we don't need to impl store func +}; +#endif /* VENDOR_EDIT */ + static inline bool cnss_use_nv_mac(struct cnss_plat_data *plat_priv) { @@ -2672,6 +2778,16 @@ static int cnss_probe(struct platform_device *plat_dev) const struct of_device_id *of_id; const struct platform_device_id *device_id; +#ifdef OPLUS_BUG_STABILITY + //Add for: disable wifi while power off charging because modem img will not mount + if (qpnp_is_power_off_charging() && + (get_boot_mode() != MSM_BOOT_MODE__WLAN) && + (get_boot_mode() != MSM_BOOT_MODE__RF)) { + cnss_pr_err("charge mode do not load wifi!\n"); + goto out; + } +#endif /* OPLUS_BUG_STABILITY */ + if (cnss_get_plat_priv(plat_dev)) { cnss_pr_err("Driver is already initialized!\n"); ret = -EEXIST; @@ -2709,6 +2825,11 @@ static int cnss_probe(struct platform_device *plat_dev) cnss_get_cpr_info(plat_priv); cnss_init_control_params(plat_priv); + #ifdef OPLUS_FEATURE_WIFI_DCS_SWITCH + //Add for wifi switch monitor + icnss_create_fw_state_kobj(); + #endif /* OPLUS_FEATURE_WIFI_DCS_SWITCH */ + ret = cnss_get_resources(plat_priv); if (ret) goto reset_ctx; @@ -2756,6 +2877,11 @@ static int cnss_probe(struct platform_device *plat_dev) if (ret < 0) cnss_pr_err("CNSS genl init failed %d\n", ret); + #ifdef OPLUS_FEATURE_WIFI_DCS_SWITCH + //Add for wifi switch monitor + cnssprobestate = CNSS_PROBE_SUCCESS; + #endif /* OPLUS_FEATURE_WIFI_DCS_SWITCH */ + cnss_pr_info("Platform driver probed successfully.\n"); return 0; @@ -2780,9 +2906,17 @@ power_off: free_res: cnss_put_resources(plat_priv); reset_ctx: + #ifdef OPLUS_FEATURE_WIFI_DCS_SWITCH + //Add for wifi switch monitor + icnss_remove_fw_state_kobj(); + #endif /* OPLUS_FEATURE_WIFI_DCS_SWITCH */ platform_set_drvdata(plat_dev, NULL); cnss_set_plat_priv(plat_dev, NULL); out: + #ifdef OPLUS_FEATURE_WIFI_DCS_SWITCH + //Add for wifi switch monitor + cnssprobestate = CNSS_PROBE_FAIL; + #endif /* OPLUS_FEATURE_WIFI_DCS_SWITCH */ return ret; } @@ -2820,6 +2954,19 @@ static struct platform_driver cnss_platform_driver = { }, }; +#ifdef OPLUS_FEATURE_WIFI_DCS_SWITCH +//Add for wifi switch monitor +static void icnss_create_fw_state_kobj(void) { + if (driver_create_file(&(cnss_platform_driver.driver), &fw_ready_attr)) { + cnss_pr_info("failed to create %s", fw_ready_attr.attr.name); + } +} + +static void icnss_remove_fw_state_kobj(void) { + driver_remove_file(&(cnss_platform_driver.driver), &fw_ready_attr); +} +#endif /* OPLUS_FEATURE_WIFI_DCS_SWITCH */ + static int __init cnss_initialize(void) { int ret = 0; diff --git a/drivers/net/wireless/cnss2/main.h b/drivers/net/wireless/cnss2/main.h index 4bc74a3e6801..f10473329b4c 100644 --- a/drivers/net/wireless/cnss2/main.h +++ b/drivers/net/wireless/cnss2/main.h @@ -419,8 +419,27 @@ struct cnss_plat_data { u8 fw_pcie_gen_switch; u8 pcie_gen_speed; int power_up_error; + + #ifdef OPLUS_FEATURE_WIFI_DCS_SWITCH + //Add for wifi switch monitor + unsigned long loadBdfState; + unsigned long loadRegdbState; + #endif /* OPLUS_FEATURE_WIFI_DCS_SWITCH */ }; +#ifdef OPLUS_FEATURE_WIFI_DCS_SWITCH +//Add for wifi switch monitor +enum cnss_load_state { + CNSS_LOAD_BDF_FAIL = 1, + CNSS_LOAD_BDF_SUCCESS, + CNSS_LOAD_REGDB_FAIL, + CNSS_LOAD_REGDB_SUCCESS, + CNSS_PROBE_FAIL, + CNSS_PROBE_SUCCESS, +}; + +#endif /* OPLUS_FEATURE_WIFI_DCS_SWITCH */ + #ifdef CONFIG_ARCH_QCOM static inline u64 cnss_get_host_timestamp(struct cnss_plat_data *plat_priv) { diff --git a/drivers/net/wireless/cnss2/pci.c b/drivers/net/wireless/cnss2/pci.c index 66b2bbe24443..ce6fdc1815df 100644 --- a/drivers/net/wireless/cnss2/pci.c +++ b/drivers/net/wireless/cnss2/pci.c @@ -74,7 +74,7 @@ static DEFINE_SPINLOCK(time_sync_lock); #define POWER_ON_RETRY_DELAY_MS 200 #define LINK_TRAINING_RETRY_MAX_TIMES 3 -#define LINK_TRAINING_RETRY_DELAY_MS 500 +#define LINK_TRAINING_RETRY_DELAY_MS 500 #define HANG_DATA_LENGTH 384 #define HST_HANG_DATA_OFFSET ((3 * 1024 * 1024) - HANG_DATA_LENGTH) @@ -1006,6 +1006,17 @@ int cnss_pci_link_down(struct device *dev) return -ENODEV; } + if (pci_priv->drv_connected_last && + of_property_read_bool(plat_priv->plat_dev->dev.of_node, + "cnss-enable-self-recovery")) + plat_priv->ctrl_params.quirks |= BIT(LINK_DOWN_SELF_RECOVERY); + + plat_priv = pci_priv->plat_priv; + if (!plat_priv) { + cnss_pr_err("plat_priv is NULL\n"); + return -ENODEV; + } + if (pci_priv->drv_connected_last && of_property_read_bool(plat_priv->plat_dev->dev.of_node, "cnss-enable-self-recovery")) @@ -1020,7 +1031,7 @@ int cnss_pci_link_down(struct device *dev) cnss_pci_handle_linkdown(pci_priv); return ret; -} + } EXPORT_SYMBOL(cnss_pci_link_down); int cnss_pci_get_reg_dump(struct device *dev, uint8_t *buffer, uint32_t len) @@ -2404,6 +2415,7 @@ int cnss_wlan_register_driver(struct cnss_wlan_driver *driver_ops) struct cnss_pci_data *pci_priv; unsigned int timeout; struct cnss_cal_info *cal_info; + u16 wlan_driver_delay_time = 1000; if (!plat_priv) { cnss_pr_err("plat_priv is NULL\n"); @@ -2458,6 +2470,8 @@ int cnss_wlan_register_driver(struct cnss_wlan_driver *driver_ops) } register_driver: + cnss_pr_dbg("Delay %dms before probe WLAN driver\n", wlan_driver_delay_time); + msleep(wlan_driver_delay_time); reinit_completion(&plat_priv->power_up_complete); ret = cnss_driver_event_post(plat_priv, CNSS_DRIVER_EVENT_REGISTER_DRIVER, diff --git a/drivers/net/wireless/cnss2/power.c b/drivers/net/wireless/cnss2/power.c index 1a8d88c3a465..3f327f171cf5 100644 --- a/drivers/net/wireless/cnss2/power.c +++ b/drivers/net/wireless/cnss2/power.c @@ -8,6 +8,7 @@ #include #include #include +#include #include "main.h" #include "debug.h" @@ -802,6 +803,13 @@ static int cnss_select_pinctrl_enable(struct cnss_plat_data *plat_priv) if (bt_en_gpio < 0) goto set_wlan_en; + switch (plat_priv->device_id) { + case QCA6390_DEVICE_ID: + case QCA6490_DEVICE_ID: + break; + default: + goto set_wlan_en; + } switch (plat_priv->device_id) { case QCA6390_DEVICE_ID: diff --git a/drivers/net/wireless/cnss2/qmi.c b/drivers/net/wireless/cnss2/qmi.c index 8873c01c8e28..8785f97414e8 100644 --- a/drivers/net/wireless/cnss2/qmi.c +++ b/drivers/net/wireless/cnss2/qmi.c @@ -5,6 +5,13 @@ #include #include +#ifdef OPLUS_FEATURE_WIFI_BDF +// +// +#include +#include +#endif /* OPLUS_FEATURE_WIFI_BDF */ + #include "bus.h" #include "debug.h" #include "main.h" @@ -578,6 +585,149 @@ static int cnss_get_bdf_file_name(struct cnss_plat_data *plat_priv, return ret; } +#ifdef OPLUS_FEATURE_WIFI_BDF +// check if read bdf is not complete through compare the size with odm/etc/wifi bdf file +// return 0 if everything ok, otherwise return a non-zero value +#define FILE_NAME_LENGTH 128 +#define BDF_FILEPATH "/mnt/vendor/persist/" +#define BDF_ODM_FILEPATH "/odm/etc/wifi/" +#define BDF_VERSION_FILE "bin_version" + +/* string is in decimal */ +static bool get_integer_from_string(const u8 *str, int *pint) +{ + u16 i = 0; + *pint = 0; + + while (str[i] != '\0') { + if (str[i] >= '0' && str[i] <= '9') { + *pint *= 10; + *pint += (str[i] - '0'); + } else { + return false; + } + ++i; + } + + return true; +} + +static int read_file(char *file_name, u8 *file_buf) +{ + int ret = 0; + struct file *filp = NULL; + struct inode *inode; + mm_segment_t old_fs; + loff_t pos; + loff_t file_len = 0; + + if ((NULL == file_name) || (NULL == file_buf)) { + cnss_pr_err("filename/filebuf is NULL"); + return -EINVAL; + } + + filp = filp_open(file_name, O_RDONLY, 0); + if (IS_ERR(filp)) { + cnss_pr_err("open %s file fail", file_name); + return -ENOENT; + } + +#if 1 + inode = filp->f_inode; +#else + /* reserved for linux earlier verion */ + inode = filp->f_dentry->d_inode; +#endif + + file_len = inode->i_size; + + old_fs = get_fs(); + set_fs(KERNEL_DS); + pos = 0; + ret = vfs_read(filp, file_buf, file_len , &pos); + if (ret < 0) + cnss_pr_err("read file fail"); + cnss_pr_dbg("file len:%d read len:%d pos:%d", (u32)file_len, ret, (u32)pos); + filp_close(filp, NULL); + set_fs(old_fs); + + return ret; +} + +int check_bdf_version(struct cnss_plat_data *plat_priv, char *file_name) +{ + int ret = -1; + const struct firmware *fw_entry = NULL; + const u8 *temp; + unsigned int remaining; + u8 fw_file_buf[FILE_NAME_LENGTH] = { '\0' }; + char file_path[FILE_NAME_LENGTH] = { '\0' }; + int odm_verison = 0; + int persist_version = 0; + + cnss_pr_dbg("start check with bdf version"); + + snprintf(file_path, FILE_NAME_LENGTH, "%s%s", BDF_ODM_FILEPATH, file_name); + ret = read_file(file_path, fw_file_buf); + if (ret < 0) { + cnss_pr_err("Failed to load: %s\n", file_path); + return ret; + } else { + temp = fw_file_buf; + get_integer_from_string(temp, &odm_verison); + cnss_pr_dbg("read odm_verison %x\n", odm_verison); + } + + ret = request_firmware_no_cache(&fw_entry, file_name, &plat_priv->plat_dev->dev); + if (ret) { + cnss_pr_err("Failed to load: %s\n", file_name); + return ret; + } else { + temp = fw_entry->data; + remaining = fw_entry->size; + get_integer_from_string(temp, &persist_version); + cnss_pr_dbg("read persist_version %x\n", persist_version); + } + + if ((persist_version > 0) && (odm_verison > 0) && (persist_version >= odm_verison)) + ret = 0; + + cnss_pr_dbg("persist version: %x, odm verison: %x", persist_version, odm_verison); + + return ret; +} + +int check_bdf_size(unsigned int download_bdf_size, char* bdf_file_name) { + char str[48]; + struct kstat* stat = NULL; + int ret = 0; + + snprintf(str, sizeof(str), "%s%s", BDF_ODM_FILEPATH, bdf_file_name); + cnss_pr_dbg("vendor file name: %s", str); + stat = (struct kstat*) kzalloc(sizeof(struct kstat), GFP_KERNEL); + if (!stat) + return -ENOMEM; + + ret = vfs_stat(str, stat); + if (ret < 0) { + cnss_pr_dbg("stat: %s fail %d", str, ret); + if (-ENOENT == ret) { + ret = 0; + } + goto out; + } + + cnss_pr_dbg("dl size: %d, stat size: %d", download_bdf_size, stat->size); + if (download_bdf_size < stat->size) { + ret = -1; + } + +out: + kfree(stat); + return ret; +} +#endif /* OPLUS_FEATURE_WIFI_BDF */ + int cnss_wlfw_bdf_dnld_send_sync(struct cnss_plat_data *plat_priv, u32 bdf_type) { @@ -589,6 +739,10 @@ int cnss_wlfw_bdf_dnld_send_sync(struct cnss_plat_data *plat_priv, const u8 *temp; unsigned int remaining; int ret = 0; +#ifdef OPLUS_FEATURE_WIFI_BDF +//Modify for: multi projects using different bdf + int loading_bdf_retry_cnt = 5; +#endif /* OPLUS_FEATURE_WIFI_BDF */ cnss_pr_dbg("Sending BDF download message, state: 0x%lx, type: %d\n", plat_priv->driver_state, bdf_type); @@ -613,7 +767,13 @@ int cnss_wlfw_bdf_dnld_send_sync(struct cnss_plat_data *plat_priv, goto err_req_fw; } +#ifdef OPLUS_FEATURE_WIFI_BDF +//Modify for: multi projects using different bdf +request_bdf: + ret = request_firmware_no_cache(&fw_entry, filename, &plat_priv->plat_dev->dev); +#else /* OPLUS_FEATURE_WIFI_BDF */ ret = request_firmware(&fw_entry, filename, &plat_priv->plat_dev->dev); +#endif /* OPLUS_FEATURE_WIFI_BDF */ if (ret) { cnss_pr_err("Failed to load BDF: %s\n", filename); goto err_req_fw; @@ -623,8 +783,32 @@ int cnss_wlfw_bdf_dnld_send_sync(struct cnss_plat_data *plat_priv, remaining = fw_entry->size; bypass_bdf: + #ifdef OPLUS_FEATURE_WIFI_DCS_SWITCH + //Add for wifi switch monitor + if (bdf_type == CNSS_BDF_REGDB) { + set_bit(CNSS_LOAD_REGDB_SUCCESS, &plat_priv->loadRegdbState); + } else if (bdf_type == CNSS_BDF_ELF){ + set_bit(CNSS_LOAD_BDF_SUCCESS, &plat_priv->loadBdfState); + } + #endif /* OPLUS_FEATURE_WIFI_DCS_SWITCH */ + cnss_pr_dbg("Downloading BDF: %s, size: %u\n", filename, remaining); +#ifdef OPLUS_FEATURE_WIFI_BDF +//Modify for: multi projects using different bdf + if (strncmp(filename, "bdwlan", 6) == 0 + && check_bdf_version(plat_priv, BDF_VERSION_FILE) + && check_bdf_size(remaining, filename) && loading_bdf_retry_cnt > 0) { + loading_bdf_retry_cnt -= 1; + cnss_pr_dbg("bdf size is too small, maybe bdf is under transfer, retry loading.."); + // sleep 400 ms + msleep_interruptible(400); + goto request_bdf; + } + // reset counter + loading_bdf_retry_cnt = 5; +#endif /* OPLUS_FEATURE_WIFI_BDF */ + while (remaining) { req->valid = 1; req->file_id_valid = 1; @@ -696,6 +880,14 @@ err_send: if (bdf_type != CNSS_BDF_DUMMY) release_firmware(fw_entry); err_req_fw: +#ifdef OPLUS_FEATURE_WIFI_DCS_SWITCH + //Add for wifi switch monitor + if (bdf_type == CNSS_BDF_REGDB) { + set_bit(CNSS_LOAD_REGDB_FAIL, &plat_priv->loadRegdbState); + } else if (bdf_type == CNSS_BDF_ELF){ + set_bit(CNSS_LOAD_BDF_FAIL, &plat_priv->loadBdfState); + } +#endif /* OPLUS_FEATURE_WIFI_DCS_SWITCH */ if (bdf_type != CNSS_BDF_REGDB) CNSS_QMI_ASSERT(); @@ -2083,17 +2275,19 @@ static void cnss_wlfw_respond_get_info_ind_cb(struct qmi_handle *qmi_wlfw, struct cnss_plat_data *plat_priv = container_of(qmi_wlfw, struct cnss_plat_data, qmi_wlfw); const struct wlfw_respond_get_info_ind_msg_v01 *ind_msg = data; - + #ifndef OPLUS_BUG_STABILITY cnss_pr_vdbg("Received QMI WLFW respond get info indication\n"); + #endif /*OPLUS_BUG_STABILITY*/ if (!txn) { cnss_pr_err("Spurious indication\n"); return; } - + #ifndef OPLUS_BUG_STABILITY cnss_pr_vdbg("Extract message with event length: %d, type: %d, is last: %d, seq no: %d\n", ind_msg->data_len, ind_msg->type, ind_msg->is_last, ind_msg->seq_no); + #endif /*OPLUS_BUG_STABILITY*/ if (plat_priv->get_info_cb_ctx && plat_priv->get_info_cb) plat_priv->get_info_cb(plat_priv->get_info_cb_ctx, diff --git a/drivers/nfc/Kconfig b/drivers/nfc/Kconfig index 26e114f6c2e4..8ee96a7d393e 100644 --- a/drivers/nfc/Kconfig +++ b/drivers/nfc/Kconfig @@ -60,6 +60,8 @@ source "drivers/nfc/s3fwrn5/Kconfig" source "drivers/nfc/st95hf/Kconfig" endmenu +source "drivers/nfc/oplus_nfc/Kconfig" + config NFC_NQ tristate "QTI NCI based NFC Controller Driver for NQx" depends on I2C diff --git a/drivers/nfc/Makefile b/drivers/nfc/Makefile index 5661fd6adf96..0ca91cde29cb 100644 --- a/drivers/nfc/Makefile +++ b/drivers/nfc/Makefile @@ -18,3 +18,9 @@ obj-$(CONFIG_NFC_NXP_NCI) += nxp-nci/ obj-$(CONFIG_NFC_S3FWRN5) += s3fwrn5/ obj-$(CONFIG_NFC_ST95HF) += st95hf/ obj-$(CONFIG_NFC_NQ) += nq-nci.o +obj-$(CONFIG_OPLUS_NFC) += oplus_nfc/ +#ifdef OPLUS_NFC_BRINGUP +#Add for the kernel Macro for NXP PN557 NFC kernel +obj-$(CONFIG_NFC_PN553_DEVICES) += pn553-i2c/ +obj-$(CONFIG_NXP_P73_DEVICES) += p73-spi/ +#endif /*OPLUS_NFC_BRINGUP*/ diff --git a/drivers/nfc/nq-nci.c b/drivers/nfc/nq-nci.c index 247df3492835..0114637cb1d9 100644 --- a/drivers/nfc/nq-nci.c +++ b/drivers/nfc/nq-nci.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2020 Oplus. All rights reserved. */ #include @@ -22,8 +23,13 @@ #include #endif #include + +#include "oplus_nfc/oplus_nfc.h" + + #include + struct nqx_platform_data { unsigned int irq_gpio; unsigned int en_gpio; @@ -44,10 +50,20 @@ static const struct of_device_id msm_match_table[] = { MODULE_DEVICE_TABLE(of, msm_match_table); +#ifdef OPLUS_BUG_STABILITY +#define NCI_GET_FW_CMD_LEN 8 +#define NCI_GET_FW_RSP_LEN 14 +#endif /* OPLUS_BUG_STABILITY */ + + struct nqx_dev { wait_queue_head_t read_wq; wait_queue_head_t cold_reset_read_wq; struct mutex read_mutex; + #ifdef OPLUS_BUG_STABILITY + /* protect the access to spi_ven_enabled flag */ + struct mutex spi_mutex; + #endif /* OPLUS_BUG_STABILITY */ struct mutex dev_ref_mutex; struct i2c_client *client; dev_t devno; @@ -63,6 +79,10 @@ struct nqx_dev { unsigned int ese_gpio; /* NFC VEN pin state powered by Nfc */ bool nfc_ven_enabled; + #ifdef OPLUS_BUG_STABILITY + /* stores the VEN pin state powered by Spi */ + bool spi_ven_enabled; + #endif /* OPLUS_BUG_STABILITY */ /* NFC state reflected from MW */ bool nfc_enabled; /* NFC_IRQ state */ @@ -160,6 +180,21 @@ static irqreturn_t nqx_dev_irq_handler(int irq, void *dev_id) return IRQ_HANDLED; } +#ifdef OPLUS_BUG_STABILITY +static void sn100_access_lock(struct nqx_dev *nqx_dev) +{ + pr_info("%s: Enter\n", __func__); + mutex_lock(&nqx_dev->spi_mutex); + pr_info("%s: Exit\n", __func__); +} +static void sn100_access_unlock(struct nqx_dev *nqx_dev) +{ + pr_info("%s: Enter\n", __func__); + mutex_unlock(&nqx_dev->spi_mutex); + pr_info("%s: Exit\n", __func__); +} +#endif /* OPLUS_BUG_STABILITY */ + static int is_data_available_for_read(struct nqx_dev *nqx_dev) { int ret; @@ -361,7 +396,10 @@ static ssize_t nfc_write(struct file *filp, const char __user *buf, { struct nqx_dev *nqx_dev = filp->private_data; char *tmp = NULL; + char wakeup_cmd[1] = {0}; + int ret = 0; + int retrycount = 0; if (!nqx_dev) { ret = -ENODEV; @@ -382,6 +420,18 @@ static ssize_t nfc_write(struct file *filp, const char __user *buf, goto out; } + while (++retrycount < 6) { + ret = i2c_master_send(nqx_dev->client, wakeup_cmd, 1); + if (ret >= 0) { + break; + } + usleep_range(5000, 5100); + } + if (ret < 0) { + dev_err(&nqx_dev->client->dev, + "%s: failed to write wakeup_cmd : %d, retry for : %d times\n", __func__, ret, retrycount); + } + ret = i2c_master_send(nqx_dev->client, tmp, count); if (ret != count) { dev_err(&nqx_dev->client->dev, @@ -443,6 +493,11 @@ static int sn100_ese_pwr(struct nqx_dev *nqx_dev, unsigned long arg) { int r = -1; + #ifdef OPLUS_BUG_STABILITY + dev_err(&nqx_dev->client->dev,"%s:%d arg=%ld\n", __func__, __LINE__, arg); + sn100_access_lock(nqx_dev); + #endif /* OPLUS_BUG_STABILITY */ + if (arg == ESE_POWER_ON) { /** * Let's store the NFC VEN pin state @@ -453,6 +508,9 @@ static int sn100_ese_pwr(struct nqx_dev *nqx_dev, unsigned long arg) */ nqx_dev->nfc_ven_enabled = gpio_get_value(nqx_dev->en_gpio); + #ifdef OPLUS_BUG_STABILITY + nqx_dev->spi_ven_enabled = true; + #endif /* OPLUS_BUG_STABILITY */ if (!nqx_dev->nfc_ven_enabled) { dev_dbg(&nqx_dev->client->dev, "eSE HAL service setting en_gpio HIGH\n"); gpio_set_value(nqx_dev->en_gpio, 1); @@ -464,6 +522,9 @@ static int sn100_ese_pwr(struct nqx_dev *nqx_dev, unsigned long arg) nqx_dev->is_ese_session_active = true; r = 0; } else if (arg == ESE_POWER_OFF) { + #ifdef OPLUS_BUG_STABILITY + nqx_dev->spi_ven_enabled = false; + #endif /* OPLUS_BUG_STABILITY */ if (!nqx_dev->nfc_ven_enabled) { dev_dbg(&nqx_dev->client->dev, "NFC not enabled, disabling en_gpio\n"); gpio_set_value(nqx_dev->en_gpio, 0); @@ -510,7 +571,16 @@ static int sn100_ese_pwr(struct nqx_dev *nqx_dev, unsigned long arg) } else if (arg == ESE_POWER_STATE) { // eSE power state r = gpio_get_value(nqx_dev->en_gpio); + #ifdef OPLUS_BUG_STABILITY + /* If NFC is enable, the VEN is hign, must set spi_ven_enabled to true because esehal will not ESE_SET_PWR=1 below such situation */ + nqx_dev->spi_ven_enabled = !!r; + dev_err(&nqx_dev->client->dev, "ven state r=%d,spi_ven_enabled=%d\n", r, nqx_dev->spi_ven_enabled); + #endif /* OPLUS_BUG_STABILITY */ } + + #ifdef OPLUS_BUG_STABILITY + sn100_access_unlock(nqx_dev); + #endif /* OPLUS_BUG_STABILITY */ return r; } @@ -815,6 +885,11 @@ int nfc_ioctl_power_states(struct file *filp, unsigned long arg) int r = 0; struct nqx_dev *nqx_dev = filp->private_data; + #ifdef OPLUS_BUG_STABILITY + dev_err(&nqx_dev->client->dev,"%s:%d arg=%ld\n", __func__, __LINE__, arg); + sn100_access_lock(nqx_dev); + #endif /* OPLUS_BUG_STABILITY */ + if (arg == NFC_POWER_OFF) { /* * We are attempting a hardware reset so let us disable @@ -838,11 +913,22 @@ int nfc_ioctl_power_states(struct file *filp, unsigned long arg) } else { dev_dbg(&nqx_dev->client->dev, "keeping en_gpio high\n"); } + #ifndef OPLUS_BUG_STABILITY } else { dev_dbg(&nqx_dev->client->dev, "ese_gpio invalid, set en_gpio to low\n"); gpio_set_value(nqx_dev->en_gpio, 0); usleep_range(10000, 10100); } + #else /* OPLUS_BUG_STABILITY */ + } else if(nqx_dev->spi_ven_enabled == false){ + dev_err(&nqx_dev->client->dev, "spi_ven_enabled is false, set en_gpio to low\n"); + gpio_set_value(nqx_dev->en_gpio, 0); + usleep_range(10000, 10100); + } else { + dev_err(&nqx_dev->client->dev, "hold ven state high(%d),spi_ven_enabled=%d\n", + gpio_get_value(nqx_dev->en_gpio), nqx_dev->spi_ven_enabled); + } + #endif /* OPLUS_BUG_STABILITY */ if (nqx_dev->pdata->clk_pin_voting) { r = nqx_clock_deselect(nqx_dev); if (r < 0) @@ -858,8 +944,19 @@ int nfc_ioctl_power_states(struct file *filp, unsigned long arg) gpio_set_value(nqx_dev->firm_gpio, 0); usleep_range(10000, 10100); } + + #ifndef OPLUS_BUG_STABILITY gpio_set_value(nqx_dev->en_gpio, 1); usleep_range(10000, 10100); + #else /* OPLUS_BUG_STABILITY */ + if (gpio_get_value(nqx_dev->en_gpio) || nqx_dev->spi_ven_enabled) { + dev_err(&nqx_dev->client->dev, "VEN gpio already high\n"); + } else { + gpio_set_value(nqx_dev->en_gpio, 1); + usleep_range(10000, 10100); + } + #endif /* OPLUS_BUG_STABILITY */ + if (nqx_dev->pdata->clk_pin_voting) { r = nqx_clock_select(nqx_dev); if (r < 0) @@ -867,6 +964,17 @@ int nfc_ioctl_power_states(struct file *filp, unsigned long arg) } nqx_dev->nfc_ven_enabled = true; } else if (arg == NFC_FW_DWL_VEN_TOGGLE) { + #ifdef OPLUS_BUG_STABILITY + if(nqx_dev->spi_ven_enabled){ + /* NFCC fw/download should not be allowed if ese is used + * by SPI + */ + dev_err(&nqx_dev->client->dev,"%s NFCC should not be allowed to reset/FW download \n", __func__); + + sn100_access_unlock(nqx_dev); + return -EBUSY; /* Device or resource busy */ + } + #endif /* OPLUS_BUG_STABILITY */ /* * We are switching to Dowload Mode, toggle the enable pin * in order to set the NFCC in the new mode @@ -900,7 +1008,21 @@ int nfc_ioctl_power_states(struct file *filp, unsigned long arg) } else dev_err(&nqx_dev->client->dev, "firm_gpio is invalid\n"); - } else if (arg == NFC_FW_DWL_LOW) { + } + #ifdef OPLUS_BUG_STABILITY + else if (arg == 5) { + if(nqx_dev->spi_ven_enabled == false){ + dev_err(&nqx_dev->client->dev, "spi_ven_enabled is false, VEN reset START\n"); + msleep(10); + gpio_set_value(nqx_dev->en_gpio, 0); + msleep(10); + gpio_set_value(nqx_dev->en_gpio, 1); + msleep(10); + dev_err(&nqx_dev->client->dev,"%s VEN reset DONE >>>>>>>\n", __func__); + } + } + #endif /* OPLUS_BUG_STABILITY */ + else if (arg == NFC_FW_DWL_LOW) { /* * Setting firmware download gpio to LOW for SN100U * FW download finished @@ -927,6 +1049,9 @@ int nfc_ioctl_power_states(struct file *filp, unsigned long arg) r = -ENOIOCTLCMD; } + #ifdef OPLUS_BUG_STABILITY + sn100_access_unlock(nqx_dev); + #endif /* OPLUS_BUG_STABILITY */ return r; } @@ -935,6 +1060,9 @@ static long nfc_compat_ioctl(struct file *pfile, unsigned int cmd, unsigned long arg) { long r = 0; + #ifdef OPLUS_BUG_STABILITY + struct nqx_dev *nqx_dev = pfile->private_data; + #endif /* OPLUS_BUG_STABILITY */ arg = (compat_u64)arg; switch (cmd) { @@ -942,10 +1070,28 @@ static long nfc_compat_ioctl(struct file *pfile, unsigned int cmd, nfc_ioctl_power_states(pfile, arg); break; case ESE_SET_PWR: + #ifndef OPLUS_BUG_STABILITY nqx_ese_pwr(pfile->private_data, arg); + #else /* OPLUS_BUG_STABILITY */ + if ((nqx_dev->nqx_info.info.chip_type == NFCC_SN100_A) || + (nqx_dev->nqx_info.info.chip_type == NFCC_SN100_B)) { + r = sn100_ese_pwr(nqx_dev, arg); + } else { + r = nqx_ese_pwr(nqx_dev, arg); + } + #endif /* OPLUS_BUG_STABILITY */ break; case ESE_GET_PWR: + #ifndef OPLUS_BUG_STABILITY nqx_ese_pwr(pfile->private_data, 3); + #else /* OPLUS_BUG_STABILITY */ + if ((nqx_dev->nqx_info.info.chip_type == NFCC_SN100_A) || + (nqx_dev->nqx_info.info.chip_type == NFCC_SN100_B)) { + r = sn100_ese_pwr(nqx_dev, 3); + } else { + r = nqx_ese_pwr(nqx_dev, 3); + } + #endif /* OPLUS_BUG_STABILITY */ break; case SET_RX_BLOCK: break; @@ -1050,6 +1196,7 @@ static const struct file_operations nfc_dev_fops = { #endif }; +#if 0 /* * function: get_nfcc_hw_info() * @@ -1178,12 +1325,16 @@ err_nfcc_hw_info: return ret; } +#endif /* Check for availability of NQ_ NFC controller hardware */ static int nfcc_hw_check(struct i2c_client *client, struct nqx_dev *nqx_dev) { int ret = 0; + int gpio_retry_count = 0; +#ifndef OPLUS_BUG_STABILITY + unsigned char reset_ntf_len = 0; unsigned int enable_gpio = nqx_dev->en_gpio; char *nci_reset_cmd = NULL; @@ -1309,9 +1460,8 @@ static int nfcc_hw_check(struct i2c_client *client, struct nqx_dev *nqx_dev) goto err_nfcc_hw_check; } - /* Retrieve NFCC HW info */ - ret = get_nfcc_hw_info(client, nqx_dev, - nci_reset_rsp[NCI_PAYLOAD_LENGTH_INDEX]); + /* Read Notification of RESET command */ + ret = i2c_master_recv(client, nci_reset_ntf, NCI_RESET_NTF_LEN); if (ret < 0) { dev_dbg(&client->dev, "%s: - Error in getting NFCC HW info\n", __func__); @@ -1370,6 +1520,83 @@ done: kfree(nci_reset_cmd); kfree(nci_get_version_cmd); kfree(nci_get_version_rsp); +#else /* OPLUS_BUG_STABILITY */ + unsigned int enable_gpio = nqx_dev->en_gpio; + unsigned int firm_gpio = nqx_dev->firm_gpio; + char *nci_get_fw_cmd = NULL; + char *nci_get_fw_rsp = NULL; + + nci_get_fw_cmd = kzalloc(NCI_GET_FW_CMD_LEN + 1, GFP_DMA | GFP_KERNEL); + if (!nci_get_fw_cmd) { + ret = -ENOMEM; + goto done; + } + + nci_get_fw_rsp = kzalloc(NCI_GET_FW_RSP_LEN + 1, GFP_DMA | GFP_KERNEL); + if (!nci_get_fw_rsp) { + ret = -ENOMEM; + goto done; + } + +reset_enable_gpio: + gpio_set_value(firm_gpio, 1); + /* hardware dependent delay */ + usleep_range(10000, 10100); + /* making sure that the NFCC starts in a clean state. */ + gpio_set_value(enable_gpio, 0);/* ULPM: Disable */ + /* hardware dependent delay */ + usleep_range(10000, 10100); + gpio_set_value(enable_gpio, 1);/* HPD : Enable*/ + /* hardware dependent delay */ + usleep_range(10000, 10100); + + nci_get_fw_cmd[0] = 0x00; + nci_get_fw_cmd[1] = 0x04; + nci_get_fw_cmd[2] = 0xF1; + nci_get_fw_cmd[3] = 0x00; + nci_get_fw_cmd[4] = 0x00; + nci_get_fw_cmd[5] = 0x00; + nci_get_fw_cmd[6] = 0x6E; + nci_get_fw_cmd[7] = 0xEF; + + /*send get FW Version CMD */ + ret = i2c_master_send(client, nci_get_fw_cmd, NCI_GET_FW_CMD_LEN); + if (ret < 0) { + pr_err("%s: - i2c_master_send get fw version Error\n", __func__); + goto err_nfcc_hw_check; + } + pr_err("%s: raw_fw_get_version success----\n", __func__); + /* hardware dependent delay */ + msleep(50); + + /* Read Response of FW Version CMD */ + ret = i2c_master_recv(client, nci_get_fw_rsp, NCI_GET_FW_RSP_LEN); + if (ret < 0) { + dev_err(&client->dev, + "%s: - i2c_master_recv Error\n", __func__); + gpio_retry_count = gpio_retry_count + 1; + if (gpio_retry_count < MAX_RETRY_COUNT) + goto reset_enable_gpio; + goto err_nfcc_hw_check; + } + + ret = 0; + + dev_err(&client->dev,"%s:%d FW: %02x.%02x.%02x",__func__, __LINE__, nci_get_fw_rsp[4], + nci_get_fw_rsp[7], nci_get_fw_rsp[6]); + goto done; + +err_nfcc_hw_check: + ret = -ENXIO; + pr_err("%s: - NFCC HW not available\n", __func__); + +done: + gpio_set_value(firm_gpio, 0); + /* make sure NFCC is not enabled */ + gpio_set_value(enable_gpio, 0); + kfree(nci_get_fw_rsp); + kfree(nci_get_fw_cmd); +#endif /* OPLUS_BUG_STABILITY */ return ret; } @@ -1503,6 +1730,10 @@ static int nqx_probe(struct i2c_client *client, struct nqx_platform_data *platform_data; struct nqx_dev *nqx_dev; + //#ifdef OPLUS_FEATURE_CONNFCSOFT + CHECK_NFC_CHIP(SN100T); + //#endif /* OPLUS_FEATURE_CONNFCSOFT */ + dev_dbg(&client->dev, "%s: enter\n", __func__); if (client->dev.of_node) { platform_data = devm_kzalloc(&client->dev, @@ -1680,6 +1911,10 @@ static int nqx_probe(struct i2c_client *client, mutex_init(&nqx_dev->read_mutex); mutex_init(&nqx_dev->dev_ref_mutex); spin_lock_init(&nqx_dev->irq_enabled_lock); + #ifdef OPLUS_BUG_STABILITY + mutex_init(&nqx_dev->spi_mutex); /* init spi_ven_enabled to false */ + nqx_dev->spi_ven_enabled = false; + #endif /* OPLUS_BUG_STABILITY */ r = alloc_chrdev_region(&nqx_dev->devno, 0, DEV_COUNT, DEVICE_NAME); if (r < 0) { @@ -1733,12 +1968,18 @@ static int nqx_probe(struct i2c_client *client, */ r = nfcc_hw_check(client, nqx_dev); if (r) { + #ifndef OPLUS_BUG_STABILITY /* make sure NFCC is not enabled */ gpio_set_value(platform_data->en_gpio, 0); /* We don't think there is hardware switch NFC OFF */ goto err_request_hw_check_failed; + #endif /* OPLUS_BUG_STABILITY */ } + #ifdef OPLUS_BUG_STABILITY + nqx_dev->nqx_info.info.chip_type = NFCC_SN100_B; + #endif /* OPLUS_BUG_STABILITY */ + /* Register reboot notifier here */ r = register_reboot_notifier(&nfcc_notifier); if (r) { @@ -1795,6 +2036,9 @@ err_class_create: unregister_chrdev_region(nqx_dev->devno, DEV_COUNT); err_char_dev_register: mutex_destroy(&nqx_dev->read_mutex); + #ifdef OPLUS_BUG_STABILITY + mutex_destroy(&nqx_dev->spi_mutex); + #endif /* OPLUS_BUG_STABILITY */ err_clkreq_gpio: gpio_free(platform_data->clkreq_gpio); err_ese_gpio: @@ -1848,6 +2092,12 @@ static int nqx_remove(struct i2c_client *client) class_destroy(nqx_dev->nqx_class); unregister_chrdev_region(nqx_dev->devno, DEV_COUNT); mutex_destroy(&nqx_dev->read_mutex); + #ifdef OPLUS_BUG_STABILITY + mutex_destroy(&nqx_dev->spi_mutex); + nqx_dev->nfc_ven_enabled = false; + nqx_dev->spi_ven_enabled = false; + #endif /* OPLUS_BUG_STABILITY */ + mutex_destroy(&nqx_dev->dev_ref_mutex); gpio_free(nqx_dev->clkreq_gpio); /* optional gpio, not sure was configured in probe */ diff --git a/drivers/nfc/oplus_nfc/Kconfig b/drivers/nfc/oplus_nfc/Kconfig new file mode 100644 index 000000000000..5fbd03e13afa --- /dev/null +++ b/drivers/nfc/oplus_nfc/Kconfig @@ -0,0 +1,5 @@ +config OPLUS_NFC + bool "config oplus nfc chipset" + default y + help + define this config to get chipset version from dts. diff --git a/drivers/nfc/oplus_nfc/Makefile b/drivers/nfc/oplus_nfc/Makefile new file mode 100644 index 000000000000..a136d89e34de --- /dev/null +++ b/drivers/nfc/oplus_nfc/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_OPLUS_NFC) += oplus_nfc.o diff --git a/drivers/nfc/oplus_nfc/oplus_nfc.c b/drivers/nfc/oplus_nfc/oplus_nfc.c new file mode 100644 index 000000000000..d933e869740c --- /dev/null +++ b/drivers/nfc/oplus_nfc/oplus_nfc.c @@ -0,0 +1,198 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "oplus_nfc.h" + +#define NFC_CHIPSET_VERSION (0x1) + +static char current_chipset[32]; +static bool support_nfc = false; + +bool is_nfc_support() +{ + return support_nfc; +} + +bool is_support_chip(chip_type chip) +{ + bool ret = false; + const char* target_chipset; + + if (!support_nfc) + { + pr_err("%s, nfc not supported, or oplus_nfc has not started", __func__); + return false; + } + + switch(chip) { + case NQ330: + target_chipset = "NQ330"; + break; + case SN100T: + target_chipset = "SN100T"; + break; + case SN100F: + target_chipset = "SN100F"; + break; + case ST21H: + target_chipset = "ST21H"; + break; + case ST54H: + target_chipset = "ST54H"; + break; + case PN557: + target_chipset = "PN557|NQ330"; + break; + default: + target_chipset = "UNKNOWN"; + break; + } + + if (strstr(target_chipset, current_chipset) != NULL) + { + ret = true; + } + + pr_err("oplus_nfc target_chipset = %s, current_chipset = %s \n", target_chipset, current_chipset); + return ret; +} + +static int nfc_read_func(struct seq_file *s, void *v) +{ + void *p = s->private; + + switch((uint32_t)(p)) { + case NFC_CHIPSET_VERSION: + seq_printf(s, "%s", current_chipset); + break; + default: + seq_printf(s, "not support\n"); + break; + } + + return 0; +} + +static int nfc_open(struct inode *inode, struct file *file) +{ + return single_open(file, nfc_read_func, PDE_DATA(inode)); +} + +static const struct file_operations nfc_info_fops = { + .owner = THIS_MODULE, + .open = nfc_open, + .read = seq_read, + .release = single_release, +}; + +static int oplus_nfc_probe(struct platform_device *pdev) +{ + struct device_node *np; + struct device* dev; + unsigned int project; + char prop_name[32]; + const char *chipset_node; + struct proc_dir_entry *p_entry; + static struct proc_dir_entry *nfc_info = NULL; + + pr_err("enter %s", __func__); + dev = &pdev->dev; + if (!dev) + { + pr_err("%s, no device", __func__); + goto error_init; + } + project = get_project(); + //project name consists of 5-symbol + //project contains letters is big then 0x10000 == 65536 + if (project > 0x10000) + { + snprintf(prop_name, sizeof(prop_name), "chipset-%X", project); + } else + { + snprintf(prop_name, sizeof(prop_name), "chipset-%u", project); + } + pr_err("%s, prop to be read = %s", __func__, prop_name); + np = dev->of_node; + + if (of_property_read_string(dev->of_node, prop_name, &chipset_node)) + { + snprintf(current_chipset, sizeof(current_chipset), "NULL"); + } else + { + pr_err("%s, get chipset_node content = %s", __func__, chipset_node); + strncpy(current_chipset, chipset_node, sizeof(current_chipset)); + support_nfc = true; + } + + nfc_info = proc_mkdir("oplus_nfc", NULL); + if (!nfc_info) + { + pr_err("%s, make oplus_nfc dir fail", __func__); + goto error_init; + } + + p_entry = proc_create_data("chipset", S_IRUGO, nfc_info, &nfc_info_fops, (uint32_t *)(NFC_CHIPSET_VERSION)); + if (!p_entry) + { + pr_err("%s, make chipset node fail", __func__); + goto error_init; + } + + return 0; + +error_init: + pr_err("%s error_init", __func__); + remove_proc_entry("oplus_nfc", NULL); + return -ENOENT; +} + +static int oplus_nfc_remove(struct platform_device *pdev) +{ + remove_proc_entry("oplus_nfc", NULL); + return 0; +} + +static const struct of_device_id onc[] = { + {.compatible = "oplus-nfc-chipset", }, + {}, +}; + +MODULE_DEVICE_TABLE(of, onc); + +static struct platform_driver oplus_nfc_driver = { + .probe = oplus_nfc_probe, + .remove = oplus_nfc_remove, + .driver = { + .name = "oplus-nfc-chipset", + .of_match_table = of_match_ptr(onc), + }, +}; + +static int __init oplus_nfc_init(void) +{ + pr_err("enter %s", __func__); + return platform_driver_register(&oplus_nfc_driver); +} + +subsys_initcall(oplus_nfc_init); + +static void __exit oplus_nfc_exit(void) +{ + platform_driver_unregister(&oplus_nfc_driver); +} +module_exit(oplus_nfc_exit); + +MODULE_DESCRIPTION("OPLUS nfc chipset version"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/nfc/oplus_nfc/oplus_nfc.h b/drivers/nfc/oplus_nfc/oplus_nfc.h new file mode 100644 index 000000000000..6e2814262ca8 --- /dev/null +++ b/drivers/nfc/oplus_nfc/oplus_nfc.h @@ -0,0 +1,26 @@ +#ifndef __OPLUS_NFC_H__ +#define __OPLUS_NFC_H__ + +#include + +#define CHECK_NFC_CHIP(chip) \ +pr_err("%s : enter\n", __func__); \ +if (!is_support_chip(chip)) { \ + pr_err("%s device not support, exit\n", __func__); \ + return -ENOMEM; \ +} + +typedef enum{ + UNKNOWN = 0, + NQ330, + SN100T, + SN100F, + ST21H, + ST54H, + PN557 +} chip_type; + +bool is_support_chip(chip_type chip); +bool is_nfc_support(void); + +#endif diff --git a/drivers/nfc/p73-spi/Kconfig b/drivers/nfc/p73-spi/Kconfig new file mode 100644 index 000000000000..ab45cc20c327 --- /dev/null +++ b/drivers/nfc/p73-spi/Kconfig @@ -0,0 +1,12 @@ +# +# Nxp SPi protocol (SPI) devices +# + +config NXP_P73_DEVICES + bool "Nxp P73 secure element protocol driver (SPI) devices" + default y + ---help--- + You'll have to say Y if your computer contains an SPI device that + you want to use under Linux. + + You can say N here if you don't have any SPI connected to your computer. diff --git a/drivers/nfc/p73-spi/Makefile b/drivers/nfc/p73-spi/Makefile new file mode 100644 index 000000000000..9fbf9b2dbe12 --- /dev/null +++ b/drivers/nfc/p73-spi/Makefile @@ -0,0 +1,7 @@ +# +# Makefile for embedded secure element devices +# + +obj-$(CONFIG_NXP_P73_DEVICES) += p73.o + +ccflags-$(CONFIG_NXP_P73_DEVICES) := -DDEBUG diff --git a/drivers/nfc/p73-spi/p73.c b/drivers/nfc/p73-spi/p73.c new file mode 100644 index 000000000000..0d1bfe0ddf88 --- /dev/null +++ b/drivers/nfc/p73-spi/p73.c @@ -0,0 +1,1076 @@ +/* + * Copyright (C) 2012-2014 NXP Semiconductors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /** + * \addtogroup spi_driver + * + * @{ */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "p73.h" +#include "../pn553-i2c/pn553.h" +//#ifdef VENDOR_EDIT +#include "../oplus_nfc/oplus_nfc.h" +//#endif /* VENDOR_EDIT */ + +extern long pn544_dev_ioctl(struct file *filp, unsigned int cmd, + unsigned long arg); + +#define DRAGON_P61 1 + +/* Device driver's configuration macro */ +/* Macro to configure poll/interrupt based req*/ +#undef P61_IRQ_ENABLE +//#define P61_IRQ_ENABLE + +/* Macro to configure Hard/Soft reset to P61 */ +//#define P61_HARD_RESET +#undef P61_HARD_RESET + +#ifdef P61_HARD_RESET +static struct regulator *p61_regulator = NULL; +#else +#endif + + +/* Macro to define SPI clock frequency */ + +//#define P61_SPI_CLOCK_7Mzh +#undef P61_SPI_CLOCK_7Mzh +#undef P61_SPI_CLOCK_10Mzh +#define P61_SPI_CLOCK_8Mzh + +#ifdef P61_SPI_CLOCK_7Mzh +#define P61_SPI_CLOCK 7000000L; +#else +#ifdef P61_SPI_CLOCK_8Mzh +#define P61_SPI_CLOCK 8000000L; +#else +#ifdef P61_SPI_CLOCK_10Mzh +#define P61_SPI_CLOCK 10000000L; +#else +#define P61_SPI_CLOCK 4000000L; +#endif +#endif +#endif + +/* size of maximum read/write buffer supported by driver */ +#define MAX_BUFFER_SIZE 258U + +/* Different driver debug lever */ +enum P61_DEBUG_LEVEL { + P61_DEBUG_OFF, + P61_FULL_DEBUG +}; + +#define READ_THROUGH_PUT 0x01 +#define WRITE_THROUGH_PUT 0x02 +#define MXAX_THROUGH_PUT_TIME 999000L +/* Variable to store current debug level request by ioctl */ +static unsigned char debug_level; + +#define P61_DBG_MSG(msg...) \ + switch(debug_level) \ + { \ + case P61_DEBUG_OFF: \ + break; \ + case P61_FULL_DEBUG: \ + printk(KERN_INFO "[NXP-P61] : " msg); \ + break; \ + default: \ + printk(KERN_ERR "[NXP-P61] : Wrong debug level %d", debug_level); \ + break; \ + } \ + +#define P61_ERR_MSG(msg...) printk(KERN_ERR "[NFC-P61] : " msg ); + +/* Device specific macro and structure */ +struct p61_dev { + wait_queue_head_t read_wq; /* wait queue for read interrupt */ + struct mutex read_mutex; /* read mutex */ + struct mutex write_mutex; /* write mutex */ + struct spi_device *spi; /* spi device structure */ + struct miscdevice p61_device; /* char device as misc driver */ + unsigned int rst_gpio; /* SW Reset gpio */ + unsigned int irq_gpio; /* P61 will interrupt DH for any ntf */ + bool irq_enabled; /* flag to indicate irq is used */ + unsigned char enable_poll_mode; /* enable the poll mode */ + spinlock_t irq_enabled_lock; /*spin lock for read irq */ + //#ifdef VENDOR_EDIT + //Add for buf for transceive SPI data + /* read buffer */ + size_t kbuflen; + u8 *kbuf; + //#endif /* VENDOR_EDIT */ +}; + +/* T==1 protocol specific global data */ +const unsigned char SOF = 0xA5u; +struct p61_through_put { + struct timeval rstart_tv; + struct timeval rstop_tv; + struct timeval wstart_tv; + struct timeval wstop_tv; + unsigned long total_through_put_wbytes; + unsigned long total_through_put_rbytes; + unsigned long total_through_put_rtime; + unsigned long total_through_put_wtime; + bool enable_through_put_measure; +}; +static struct p61_through_put p61_through_put_t; + +static void p61_start_throughput_measurement(unsigned int type); +static void p61_stop_throughput_measurement(unsigned int type, int no_of_bytes); + +static void p61_start_throughput_measurement(unsigned int type) +{ + if (type == READ_THROUGH_PUT) + { + memset(&p61_through_put_t.rstart_tv, 0x00, sizeof(struct timeval)); + do_gettimeofday(&p61_through_put_t.rstart_tv); + } + else if (type == WRITE_THROUGH_PUT) + { + memset(&p61_through_put_t.wstart_tv, 0x00, sizeof(struct timeval)); + do_gettimeofday(&p61_through_put_t.wstart_tv); + + } + else + { + P61_DBG_MSG(KERN_ALERT " p61_start_throughput_measurement: wrong type = %d", type); + } + +} +static void p61_stop_throughput_measurement(unsigned int type, int no_of_bytes) +{ + if (type == READ_THROUGH_PUT) + { + memset(&p61_through_put_t.rstop_tv, 0x00, sizeof(struct timeval)); + do_gettimeofday(&p61_through_put_t.rstop_tv); + p61_through_put_t.total_through_put_rbytes += no_of_bytes; + p61_through_put_t.total_through_put_rtime += (p61_through_put_t.rstop_tv.tv_usec - + p61_through_put_t.rstart_tv.tv_usec) + + ((p61_through_put_t.rstop_tv.tv_sec - + p61_through_put_t.rstart_tv.tv_sec) * 1000000); + + if(p61_through_put_t.total_through_put_rtime >= MXAX_THROUGH_PUT_TIME) + { + printk(KERN_ALERT " **************** Read Throughput: **************"); + printk(KERN_ALERT " No of Read Bytes = %ld", p61_through_put_t.total_through_put_rbytes); + printk(KERN_ALERT " Total Read Time (uSec) = %ld", p61_through_put_t.total_through_put_rtime); + p61_through_put_t.total_through_put_rbytes = 0; + p61_through_put_t.total_through_put_rtime = 0; + printk(KERN_ALERT " **************** Read Throughput: **************"); + } + printk(KERN_ALERT " No of Read Bytes = %ld", p61_through_put_t.total_through_put_rbytes); + printk(KERN_ALERT " Total Read Time (uSec) = %ld", p61_through_put_t.total_through_put_rtime); + } + else if (type == WRITE_THROUGH_PUT) + { + memset(&p61_through_put_t.wstop_tv, 0x00, sizeof(struct timeval)); + do_gettimeofday(&p61_through_put_t.wstop_tv); + p61_through_put_t.total_through_put_wbytes += no_of_bytes; + p61_through_put_t.total_through_put_wtime += (p61_through_put_t.wstop_tv.tv_usec - + p61_through_put_t.wstart_tv.tv_usec) + + ((p61_through_put_t.wstop_tv.tv_sec - + p61_through_put_t.wstart_tv.tv_sec) * 1000000); + + if(p61_through_put_t.total_through_put_wtime >= MXAX_THROUGH_PUT_TIME) + { + printk(KERN_ALERT " **************** Write Throughput: **************"); + printk(KERN_ALERT " No of Write Bytes = %ld", p61_through_put_t.total_through_put_wbytes); + printk(KERN_ALERT " Total Write Time (uSec) = %ld", p61_through_put_t.total_through_put_wtime); + p61_through_put_t.total_through_put_wbytes = 0; + p61_through_put_t.total_through_put_wtime = 0; + printk(KERN_ALERT " **************** WRITE Throughput: **************"); + } + printk(KERN_ALERT " No of Write Bytes = %ld", p61_through_put_t.total_through_put_wbytes); + printk(KERN_ALERT " Total Write Time (uSec) = %ld", p61_through_put_t.total_through_put_wtime); + } + else + { + printk(KERN_ALERT " p61_stop_throughput_measurement: wrong type = %d", type); + } +} +/** + * \ingroup spi_driver + * \brief Called from SPI LibEse to initilaize the P61 device + * + * \param[in] struct inode * + * \param[in] struct file * + * + * \retval 0 if ok. + * +*/ + +static int p61_dev_open(struct inode *inode, struct file *filp) { + + struct p61_dev + *p61_dev = container_of(filp->private_data, + struct p61_dev, + p61_device); + + filp->private_data = p61_dev; + P61_DBG_MSG( + "%s : Major No: %d, Minor No: %d\n", __func__, imajor(inode), iminor(inode)); + + return 0; +} + +/** + * \ingroup spi_driver + * \brief To configure the P61_SET_PWR/P61_SET_DBG/P61_SET_POLL + * \n P61_SET_PWR - hard reset (arg=2), soft reset (arg=1) + * \n P61_SET_DBG - Enable/Disable (based on arg value) the driver logs + * \n P61_SET_POLL - Configure the driver in poll (arg = 1), interrupt (arg = 0) based read operation + * \param[in] struct file * + * \param[in] unsigned int + * \param[in] unsigned long + * + * \retval 0 if ok. + * +*/ + +static long p61_dev_ioctl(struct file *filp, unsigned int cmd, + unsigned long arg) +{ + int ret = 0; + struct p61_dev *p61_dev = NULL; + + unsigned char buf[100]; + + + P61_DBG_MSG(KERN_ALERT "p61_dev_ioctl-Enter %u arg = %ld\n", cmd, arg); + p61_dev = filp->private_data; + + switch (cmd) { + case P61_SET_PWR: + if (arg == 2) + { +#ifdef P61_HARD_RESET + P61_DBG_MSG(KERN_ALERT " Disabling p61_regulator"); + if (p61_regulator != NULL) + { + regulator_disable(p61_regulator); + msleep(50); + regulator_enable(p61_regulator); + P61_DBG_MSG(KERN_ALERT " Enabling p61_regulator"); + } + else + { + P61_ERR_MSG(KERN_ALERT " ERROR : p61_regulator is not enabled"); + } +#endif + + } + else if (arg == 1) + { + P61_DBG_MSG(KERN_ALERT " Soft Reset"); + //gpio_set_value(p61_dev->rst_gpio, 1); + //msleep(20); + gpio_set_value(p61_dev->rst_gpio, 0); + msleep(50); + ret = spi_read (p61_dev -> spi,(void *) buf, sizeof(buf)); + msleep(50); + gpio_set_value(p61_dev->rst_gpio, 1); + msleep(20); + + } + break; + + case P61_SET_DBG: + debug_level = (unsigned char )arg; + P61_DBG_MSG(KERN_INFO"[NXP-P61] - Debug level %d", debug_level); + break; + + case P61_SET_POLL: + + p61_dev-> enable_poll_mode = (unsigned char )arg; + if (p61_dev-> enable_poll_mode == 0) + { + P61_DBG_MSG(KERN_INFO"[NXP-P61] - IRQ Mode is set \n"); + } + else + { + P61_DBG_MSG(KERN_INFO"[NXP-P61] - Poll Mode is set \n"); + p61_dev->enable_poll_mode = 1; + } + break; + case P61_SET_SPM_PWR: + P61_DBG_MSG(KERN_ALERT " P61_SET_SPM_PWR: enter"); + ret = pn544_dev_ioctl(filp, P61_SET_SPI_PWR, arg); + P61_DBG_MSG(KERN_ALERT " P61_SET_SPM_PWR: exit"); + break; + case P61_GET_SPM_STATUS: + P61_DBG_MSG(KERN_ALERT " P61_GET_SPM_STATUS: enter"); + ret = pn544_dev_ioctl(filp, P61_GET_PWR_STATUS, arg); + P61_DBG_MSG(KERN_ALERT " P61_GET_SPM_STATUS: exit"); + break; + case P61_SET_DWNLD_STATUS: + P61_DBG_MSG(KERN_ALERT " P61_SET_DWNLD_STATUS: enter"); + ret = pn544_dev_ioctl(filp, PN544_SET_DWNLD_STATUS, arg); + P61_DBG_MSG(KERN_ALERT " P61_SET_DWNLD_STATUS: =%lu exit",arg); + break; + case P61_SET_THROUGHPUT: + p61_through_put_t.enable_through_put_measure = true; + P61_DBG_MSG(KERN_INFO"[NXP-P61] - P61_SET_THROUGHPUT enable %d", p61_through_put_t.enable_through_put_measure); + break; + case P61_GET_ESE_ACCESS: + P61_DBG_MSG(KERN_ALERT " P61_GET_ESE_ACCESS: enter"); + ret = pn544_dev_ioctl(filp, P544_GET_ESE_ACCESS, arg); + P61_DBG_MSG(KERN_ALERT " P61_GET_ESE_ACCESS ret: %d exit",ret); + break; + case P61_SET_POWER_SCHEME: + P61_DBG_MSG(KERN_ALERT " P61_SET_POWER_SCHEME: enter"); + ret = pn544_dev_ioctl(filp, P544_SET_POWER_SCHEME, arg); + P61_DBG_MSG(KERN_ALERT " P61_SET_POWER_SCHEME ret: %d exit",ret); + break; + case P61_INHIBIT_PWR_CNTRL: + P61_DBG_MSG(KERN_ALERT " P61_INHIBIT_PWR_CNTRL: enter"); + ret = pn544_dev_ioctl(filp, P544_SECURE_TIMER_SESSION, arg); + P61_DBG_MSG(KERN_ALERT " P61_INHIBIT_PWR_CNTRL ret: %d exit", ret); + break; + default: + P61_DBG_MSG(KERN_ALERT " Error case"); + ret = -EINVAL; + } + + P61_DBG_MSG(KERN_ALERT "p61_dev_ioctl-exit %u arg = %lu\n", cmd, arg); + return ret; +} + +/** + * \ingroup spi_driver + * \brief Write data to P61 on SPI + * + * \param[in] struct file * + * \param[in] const char * + * \param[in] size_t + * \param[in] loff_t * + * + * \retval data size + * +*/ + +static ssize_t p61_dev_write(struct file *filp, const char *buf, size_t count, + loff_t *offset) +{ + + int ret = -1; + struct p61_dev *p61_dev; + //#ifndef VENDOR_EDIT + //Mod for buf for transceive SPI data + //unsigned char tx_buffer[MAX_BUFFER_SIZE]; + //#else /* VENDOR_EDIT */ + char *tmp = NULL; + //#endif /* VENDOR_EDIT */ + + P61_DBG_MSG(KERN_ALERT "p61_dev_write -Enter count %zu\n", count); + + p61_dev = filp->private_data; + + mutex_lock(&p61_dev->write_mutex); + if (count > MAX_BUFFER_SIZE) + count = MAX_BUFFER_SIZE; + + //#ifdef VENDOR_EDIT + //Add for buf for transceive SPI data + /*memset(&tx_buffer[0], 0, sizeof(tx_buffer)); + if (copy_from_user(&tx_buffer[0], &buf[0], count)) + { + P61_ERR_MSG("%s : failed to copy from user space\n", __func__); + mutex_unlock(&p61_dev->write_mutex); + return -EFAULT; + } + */ + //#else /* VENDOR_EDIT */ + tmp = memdup_user(buf, count); + if (IS_ERR(tmp)) { + pr_info("%s: memdup_user failed\n", __func__); + mutex_unlock(&p61_dev->write_mutex); + ret = PTR_ERR(tmp); + return ret; + } + //#endif /* VENDOR_EDIT */ + if(p61_through_put_t.enable_through_put_measure) + p61_start_throughput_measurement(WRITE_THROUGH_PUT); + /* Write data */ + //#ifndef VENDOR_EDIT + //Mod for buf for transceive SPI data + //ret = spi_write(p61_dev->spi, &tx_buffer[0], count); + //#else /* VENDOR_EDIT */ + ret = spi_write(p61_dev->spi, tmp, count); + //#endif /* VENDOR_EDIT */ + if (ret < 0) + { + ret = -EIO; + } + else + { + ret = count; + if(p61_through_put_t.enable_through_put_measure) + p61_stop_throughput_measurement(WRITE_THROUGH_PUT, ret); + } + + //#ifdef VENDOR_EDIT + //Add for buf for transceive SPI data + kfree(tmp); + //#endif /* VENDOR_EDIT */ + mutex_unlock(&p61_dev->write_mutex); + P61_DBG_MSG(KERN_ALERT "p61_dev_write ret %d- Exit \n", ret); + return ret; +} + +#ifdef P61_IRQ_ENABLE + +/** + * \ingroup spi_driver + * \brief To disable IRQ + * + * \param[in] struct p61_dev * + * + * \retval void + * +*/ + +static void p61_disable_irq(struct p61_dev *p61_dev) +{ + unsigned long flags; + + P61_DBG_MSG("Entry : %s\n", __FUNCTION__); + + spin_lock_irqsave(&p61_dev->irq_enabled_lock, flags); + if (p61_dev->irq_enabled) + { + disable_irq_nosync(p61_dev->spi->irq); + p61_dev->irq_enabled = false; + } + spin_unlock_irqrestore(&p61_dev->irq_enabled_lock, flags); + + P61_DBG_MSG("Exit : %s\n", __FUNCTION__); +} + +/** + * \ingroup spi_driver + * \brief Will get called when interrupt line asserted from P61 + * + * \param[in] int + * \param[in] void * + * + * \retval IRQ handle + * +*/ + +static irqreturn_t p61_dev_irq_handler(int irq, void *dev_id) +{ + struct p61_dev *p61_dev = dev_id; + + P61_DBG_MSG("Entry : %s\n", __FUNCTION__); + p61_disable_irq(p61_dev); + + /* Wake up waiting readers */ + wake_up(&p61_dev->read_wq); + + P61_DBG_MSG("Exit : %s\n", __FUNCTION__); + return IRQ_HANDLED; +} +#endif + +/** + * \ingroup spi_driver + * \brief Used to read data from P61 in Poll/interrupt mode configured using ioctl call + * + * \param[in] struct file * + * \param[in] char * + * \param[in] size_t + * \param[in] loff_t * + * + * \retval read size + * +*/ + +static ssize_t p61_dev_read(struct file *filp, char *buf, size_t count, + loff_t *offset) +{ + int ret = -EIO; + struct p61_dev *p61_dev = filp->private_data; + //#ifndef VENDOR_EDIT + //Mod for buf for transceive SPI data + //unsigned char rx_buffer[MAX_BUFFER_SIZE]; + //#else /* VENDOR_EDIT */ + unsigned char *tmp = NULL; + //#endif /* VENDOR_EDIT */ + + P61_DBG_MSG("p61_dev_read count %zu - Enter \n", count); + + mutex_lock(&p61_dev->read_mutex); + if (count > MAX_BUFFER_SIZE) + { + count = MAX_BUFFER_SIZE; + } + + //#ifndef VENDOR_EDIT + //Mod for buf for transceive SPI data + //memset(&rx_buffer[0], 0x00, sizeof(rx_buffer)); + //#else /* VENDOR_EDIT */ + tmp = p61_dev->kbuf; + if (!tmp) { + pr_info("%s: device doesn't exist anymore.\n", __func__); + ret = -ENODEV; + goto fail; + } + memset(tmp, 0x00, MAX_BUFFER_SIZE); + //#endif /* VENDOR_EDIT */ + if (p61_dev->enable_poll_mode) + { + P61_DBG_MSG(" %s Poll Mode Enabled \n", __FUNCTION__); + + P61_DBG_MSG(KERN_INFO"SPI_READ returned 0x%zx", count); + //#ifndef VENDOR_EDIT + //Mod for buf for transceive SPI data + //ret = spi_read(p61_dev->spi, (void *)&rx_buffer[0], count); + //#else /* VENDOR_EDIT */ + ret = spi_read(p61_dev->spi, tmp, count); + //#endif /* VENDOR_EDIT */ + if (0 > ret) + { + P61_ERR_MSG(KERN_ALERT "spi_read failed [SOF] \n"); + goto fail; + } + } + else + { +#ifdef P61_IRQ_ENABLE + P61_DBG_MSG(" %s Interrrupt Mode Enabled \n", __FUNCTION__); + if (!gpio_get_value(p61_dev->irq_gpio)) + { + if (filp->f_flags & O_NONBLOCK) + { + ret = -EAGAIN; + goto fail; + } + while (1) + { + P61_DBG_MSG(" %s waiting for interrupt \n", __FUNCTION__); + p61_dev->irq_enabled = true; + enable_irq(p61_dev->spi->irq); + ret = wait_event_interruptible(p61_dev->read_wq,!p61_dev->irq_enabled); + p61_disable_irq(p61_dev); + if (ret) + { + P61_ERR_MSG("wait_event_interruptible() : Failed\n"); + goto fail; + } + + if (gpio_get_value(p61_dev->irq_gpio)) + break; + + P61_ERR_MSG("%s: spurious interrupt detected\n", __func__); + } + } +#else + P61_DBG_MSG(" %s P61_IRQ_ENABLE not Enabled \n", __FUNCTION__); +#endif + //#ifndef VENDOR_EDIT + //Mod for buf for transceive SPI data + //ret = spi_read(p61_dev->spi, (void *)&rx_buffer[0], count); + //#else /* VENDOR_EDIT */ + ret = spi_read(p61_dev->spi, tmp, count); + //#endif /* VENDOR_EDIT */ + if (0 > ret) + { + P61_DBG_MSG(KERN_INFO"SPI_READ returned 0x%x", ret); + ret = -EIO; + goto fail; + } + } + + + if(p61_through_put_t.enable_through_put_measure) + p61_start_throughput_measurement(READ_THROUGH_PUT); + + if(p61_through_put_t.enable_through_put_measure) + p61_stop_throughput_measurement (READ_THROUGH_PUT, count); + P61_DBG_MSG(KERN_INFO"total_count = %zu", count); + + //#ifndef VENDOR_EDIT + //Mod for buf for transceive SPI data + //if (copy_to_user(buf, &rx_buffer[0], count)) + //#else /* VENDOR_EDIT */ + if (copy_to_user(buf, tmp, count)) + //#endif /* VENDOR_EDIT */ + { + P61_ERR_MSG("%s : failed to copy to user space\n", __func__); + ret = -EFAULT; + goto fail; + } + P61_DBG_MSG("p61_dev_read ret %d Exit\n", ret); + //#ifndef VENDOR_EDIT + //Mod for buf for transceive SPI data + //P61_DBG_MSG("p61_dev_read ret %d Exit\n", rx_buffer[0]); + //#endif /* VENDOR_EDIT */ + + mutex_unlock(&p61_dev->read_mutex); + + return ret; + + fail: + P61_ERR_MSG("Error p61_dev_read ret %d Exit\n", ret); + mutex_unlock(&p61_dev->read_mutex); + return ret; +} + +/** + * \ingroup spi_driver + * \brief It will configure the GPIOs required for soft reset, read interrupt & regulated power supply to P61. + * + * \param[in] struct p61_spi_platform_data * + * \param[in] struct p61_dev * + * \param[in] struct spi_device * + * + * \retval 0 if ok. + * +*/ + +static int p61_hw_setup(struct p61_spi_platform_data *platform_data, + struct p61_dev *p61_dev, struct spi_device *spi) +{ + int ret = -1; + + P61_DBG_MSG("Entry : %s\n", __FUNCTION__); +#ifdef P61_IRQ_ENABLE + ret = gpio_request(platform_data->irq_gpio, "p61 irq"); + if (ret < 0) + { + P61_ERR_MSG("gpio request failed gpio = 0x%x\n", platform_data->irq_gpio); + goto fail; + } + + ret = gpio_direction_input(platform_data->irq_gpio); + if (ret < 0) + { + P61_ERR_MSG("gpio request failed gpio = 0x%x\n", platform_data->irq_gpio); + goto fail_irq; + } +#endif + +#ifdef P61_HARD_RESET + /* RC : platform specific settings need to be declare */ +#if !DRAGON_P61 + p61_regulator = regulator_get( &spi->dev, "vaux3"); +#else + p61_regulator = regulator_get( &spi->dev, "8941_l18"); +#endif + if (IS_ERR(p61_regulator)) + { + ret = PTR_ERR(p61_regulator); +#if !DRAGON_P61 + P61_ERR_MSG(" Error to get vaux3 (error code) = %d\n", ret); +#else + P61_ERR_MSG(" Error to get 8941_l18 (error code) = %d\n", ret); +#endif + return -ENODEV; + } + else + { + P61_DBG_MSG("successfully got regulator\n"); + } + + ret = regulator_set_voltage(p61_regulator, 1800000, 1800000); + if (ret != 0) + { + P61_ERR_MSG("Error setting the regulator voltage %d\n", ret); + regulator_put(p61_regulator); + return ret; + } + else + { + regulator_enable(p61_regulator); + P61_DBG_MSG("successfully set regulator voltage\n"); + + } +#endif + + ret = 0; + P61_DBG_MSG("Exit : %s\n", __FUNCTION__); + return ret; +} + +/** + * \ingroup spi_driver + * \brief Set the P61 device specific context for future use. + * + * \param[in] struct spi_device * + * \param[in] void * + * + * \retval void + * +*/ + +static inline void p61_set_data(struct spi_device *spi, void *data) +{ + dev_set_drvdata(&spi->dev, data); +} + +/** + * \ingroup spi_driver + * \brief Get the P61 device specific context. + * + * \param[in] const struct spi_device * + * + * \retval Device Parameters + * +*/ + +static inline void *p61_get_data(const struct spi_device *spi) +{ + return dev_get_drvdata(&spi->dev); +} + +/* possible fops on the p61 device */ +static const struct file_operations p61_dev_fops = { + .owner = THIS_MODULE, + .read = p61_dev_read, + .write = p61_dev_write, + .open = p61_dev_open, + .unlocked_ioctl = p61_dev_ioctl, +}; +#if DRAGON_P61 +static int p61_parse_dt(struct device *dev, + struct p61_spi_platform_data *data) +{ + int errorno = 0; + + return errorno; +} +#endif + +/** + * \ingroup spi_driver + * \brief To probe for P61 SPI interface. If found initialize the SPI clock, bit rate & SPI mode. + It will create the dev entry (P61) for user space. + * + * \param[in] struct spi_device * + * + * \retval 0 if ok. + * +*/ + +static int p61_probe(struct spi_device *spi) +{ + int ret = -1; + struct p61_spi_platform_data *platform_data = NULL; + struct p61_spi_platform_data platform_data1 = { + .irq_gpio = 0, + .rst_gpio = 0 + }; + struct p61_dev *p61_dev = NULL; +#ifdef P61_IRQ_ENABLE + unsigned int irq_flags; +#endif + + //#ifdef OPLUS_FEATURE_NFC_CONSOFT + //Add for : ST NXP chip common software + CHECK_NFC_CHIP(NQ330); + //#endif /* OPLUS_FEATURE_NFC_CONSOFT */ + + P61_DBG_MSG("%s chip select : %d , bus number = %d \n", + __FUNCTION__, spi->chip_select, spi->master->bus_num); +#if !DRAGON_P61 + platform_data = spi->dev.platform_data; + if (platform_data == NULL) + { + /* RC : rename the platformdata1 name */ + /* TBD: This is only for Panda as we are passing NULL for platform data */ + P61_ERR_MSG("%s : p61 probe fail\n", __func__); + platform_data1.irq_gpio = P61_IRQ; + platform_data1.rst_gpio = P61_RST; + platform_data = &platform_data1; + P61_ERR_MSG("%s : p61 probe fail1\n", __func__); + //return -ENODEV; + } +#else + ret = p61_parse_dt(&spi->dev, &platform_data1); + if (ret) { + pr_err("%s - Failed to parse DT\n", __func__); + goto err_exit; + } + platform_data = &platform_data1; +#endif + p61_dev = kzalloc(sizeof(*p61_dev), GFP_KERNEL); + if (p61_dev == NULL) + { + P61_ERR_MSG("failed to allocate memory for module data\n"); + ret = -ENOMEM; + goto err_exit; + } + + //#ifdef VENDOR_EDIT + //Add for buf for transceive SPI data + p61_dev->kbuflen = MAX_BUFFER_SIZE; + p61_dev->kbuf = kzalloc(MAX_BUFFER_SIZE, GFP_KERNEL); + if (!p61_dev->kbuf) { + pr_err("failed to allocate memory for p61_dev->kbuf"); + ret = -ENOMEM; + goto err_free_dev; + } + //#endif /* VENDOR_EDIT */ + ret = p61_hw_setup (platform_data, p61_dev, spi); + if (ret < 0) + { + P61_ERR_MSG("Failed to p61_enable_P61_IRQ_ENABLE\n"); + goto err_exit0; + } + + spi->bits_per_word = 8; + spi->mode = SPI_MODE_0; + spi->max_speed_hz = P61_SPI_CLOCK; + //spi->chip_select = SPI_NO_CS; + ret = spi_setup(spi); + if (ret < 0) + { + P61_ERR_MSG("failed to do spi_setup()\n"); + goto err_exit0; + } + + p61_dev -> spi = spi; + p61_dev -> p61_device.minor = MISC_DYNAMIC_MINOR; + p61_dev -> p61_device.name = "p73"; + p61_dev -> p61_device.fops = &p61_dev_fops; + p61_dev -> p61_device.parent = &spi->dev; + p61_dev->irq_gpio = platform_data->irq_gpio; + p61_dev->rst_gpio = platform_data->rst_gpio; + + + dev_set_drvdata(&spi->dev, p61_dev); + + /* init mutex and queues */ + init_waitqueue_head(&p61_dev->read_wq); + mutex_init(&p61_dev->read_mutex); + mutex_init(&p61_dev->write_mutex); + + +#ifdef P61_IRQ_ENABLE + spin_lock_init(&p61_dev->irq_enabled_lock); +#endif + + ret = misc_register(&p61_dev->p61_device); + if (ret < 0) + { + P61_ERR_MSG("misc_register failed! %d\n", ret); + goto err_exit0; + } + +#ifdef P61_IRQ_ENABLE + p61_dev->spi->irq = gpio_to_irq(platform_data->irq_gpio); + + if ( p61_dev->spi->irq < 0) + { + P61_ERR_MSG("gpio_to_irq request failed gpio = 0x%x\n", platform_data->irq_gpio); + goto err_exit1; + } + /* request irq. the irq is set whenever the chip has data available + * for reading. it is cleared when all data has been read. + */ + p61_dev->irq_enabled = true; + p61_through_put_t.enable_through_put_measure = false; + irq_flags = IRQF_TRIGGER_RISING | IRQF_ONESHOT; + + ret = request_irq(p61_dev->spi->irq, p61_dev_irq_handler, + irq_flags, p61_dev -> p61_device.name, p61_dev); + if (ret) + { + P61_ERR_MSG("request_irq failed\n"); + goto err_exit1; + } + p61_disable_irq(p61_dev); + +#endif + + p61_dev-> enable_poll_mode = 0; /* Default IRQ read mode */ + P61_DBG_MSG("Exit : %s\n", __FUNCTION__); + return ret; + //#ifndef VENDOR_EDIT + //Modify for coverity:777213, not need code + //err_exit1: + //misc_deregister(&p61_dev->p61_device); + //#else /* VENDOR_EDIT */ +#ifdef P61_IRQ_ENABLE + err_exit1: + misc_deregister(&p61_dev->p61_device); +#endif + //#endif /* VENDOR_EDIT */ + err_exit0: + mutex_destroy(&p61_dev->read_mutex); + mutex_destroy(&p61_dev->write_mutex); + //#ifdef VENDOR_EDIT + //Add for buf for transceive SPI data + kfree(p61_dev->kbuf); + err_free_dev: + //#endif /* VENDOR_EDIT */ + if(p61_dev != NULL) + kfree(p61_dev); + err_exit: + P61_DBG_MSG("ERROR: Exit : %s ret %d\n", __FUNCTION__, ret); + return ret; +} + +/** + * \ingroup spi_driver + * \brief Will get called when the device is removed to release the resources. + * + * \param[in] struct spi_device + * + * \retval 0 if ok. + * +*/ + +static int p61_remove(struct spi_device *spi) +{ + struct p61_dev *p61_dev = p61_get_data(spi); + P61_DBG_MSG("Entry : %s\n", __FUNCTION__); + +#ifdef P61_HARD_RESET + if (p61_regulator != NULL) + { + regulator_disable(p61_regulator); + regulator_put(p61_regulator); + } + else + { + P61_ERR_MSG("ERROR %s p61_regulator not enabled \n", __FUNCTION__); + } +#endif + //#ifndef VENDOR_EDIT + //Mod for coverity:776436, to judge p61_dev before use + //gpio_free(p61_dev->rst_gpio); + //#else /* VENDOR_EDIT */ + if (p61_dev != NULL && p61_dev->rst_gpio) { + gpio_free(p61_dev->rst_gpio); + } + //#endif /* VENDOR_EDIT */ + +#ifdef P61_IRQ_ENABLE + free_irq(p61_dev->spi->irq, p61_dev); + gpio_free(p61_dev->irq_gpio); +#endif + + //#ifndef VENDOR_EDIT + //Mod for coverity:784378, to judge p61_dev before use + /* + mutex_destroy(&p61_dev->read_mutex); + misc_deregister(&p61_dev->p61_device); + + if(p61_dev != NULL) + kfree(p61_dev); + */ + //#else /* VENDOR_EDIT */ + if(p61_dev != NULL) { + mutex_destroy(&p61_dev->read_mutex); + misc_deregister(&p61_dev->p61_device); + kfree(p61_dev); + } + //#endif /* VENDOR_EDIT */ + P61_DBG_MSG("Exit : %s\n", __FUNCTION__); + return 0; +} +#if DRAGON_P61 +static struct of_device_id p61_dt_match[] = { + { + .compatible = "nxp,p61", + }, + {} +}; +#endif +static struct spi_driver p61_driver = { + .driver = { + .name = "p61", + .bus = &spi_bus_type, + .owner = THIS_MODULE, +#if DRAGON_P61 + .of_match_table = p61_dt_match, +#endif + }, + .probe = p61_probe, + .remove = (p61_remove), +}; + +/** + * \ingroup spi_driver + * \brief Module init interface + * + * \param[in] void + * + * \retval handle + * +*/ + +static int __init p61_dev_init(void) +{ + debug_level = P61_DEBUG_OFF; + + P61_DBG_MSG("Entry : %s\n", __FUNCTION__); + + return spi_register_driver(&p61_driver); + + P61_DBG_MSG("Exit : %s\n", __FUNCTION__); +} +module_init( p61_dev_init); + +/** + * \ingroup spi_driver + * \brief Module exit interface + * + * \param[in] void + * + * \retval void + * +*/ + +static void __exit p61_dev_exit(void) +{ + P61_DBG_MSG("Entry : %s\n", __FUNCTION__); + + spi_unregister_driver(&p61_driver); + P61_DBG_MSG("Exit : %s\n", __FUNCTION__); +} +module_exit( p61_dev_exit); + +MODULE_AUTHOR("BHUPENDRA PAWAR"); +MODULE_DESCRIPTION("NXP P61 SPI driver"); +MODULE_LICENSE("GPL"); + +/** @} */ diff --git a/drivers/nfc/p73-spi/p73.h b/drivers/nfc/p73-spi/p73.h new file mode 100644 index 000000000000..911d8e617631 --- /dev/null +++ b/drivers/nfc/p73-spi/p73.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2012-2014 NXP Semiconductors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define P61_MAGIC 0xEA +#define P61_SET_PWR _IOW(P61_MAGIC, 0x01, long) +#define P61_SET_DBG _IOW(P61_MAGIC, 0x02, long) +#define P61_SET_POLL _IOW(P61_MAGIC, 0x03, long) +/* + * SPI Request NFCC to enable p61 power, only in param + * Only for SPI + * level 1 = Enable power + * level 0 = Disable power + */ +#define P61_SET_SPM_PWR _IOW(P61_MAGIC, 0x04, long) + +/* SPI or DWP can call this ioctl to get the current + * power state of P61 + * +*/ +#define P61_GET_SPM_STATUS _IOR(P61_MAGIC, 0x05, long) + +#define P61_SET_THROUGHPUT _IOW(P61_MAGIC, 0x06, long) +#define P61_GET_ESE_ACCESS _IOW(P61_MAGIC, 0x07, long) + +#define P61_SET_POWER_SCHEME _IOW(P61_MAGIC, 0x08, long) + +#define P61_SET_DWNLD_STATUS _IOW(P61_MAGIC, 0x09, long) + +#define P61_INHIBIT_PWR_CNTRL _IOW(P61_MAGIC, 0x0A, long) +struct p61_spi_platform_data { + unsigned int irq_gpio; + unsigned int rst_gpio; +}; diff --git a/drivers/nfc/pn553-i2c/Kconfig b/drivers/nfc/pn553-i2c/Kconfig new file mode 100644 index 000000000000..878e4a816910 --- /dev/null +++ b/drivers/nfc/pn553-i2c/Kconfig @@ -0,0 +1,13 @@ +# +# Nxp Nci protocol (I2C) devices +# + +config NFC_PN553_DEVICES + bool "Nxp pn553 NCI protocol driver (I2C) devices" + default y + ---help--- + You'll have to say Y if your computer contains an I2C device that + you want to use under Linux. + + You can say N here if you don't have any SPI connected to your computer. + diff --git a/drivers/nfc/pn553-i2c/Makefile b/drivers/nfc/pn553-i2c/Makefile new file mode 100644 index 000000000000..357913b46c8f --- /dev/null +++ b/drivers/nfc/pn553-i2c/Makefile @@ -0,0 +1,7 @@ +# +# Makefile for nfc devices +# + +obj-$(CONFIG_NFC_PN553_DEVICES) += pn553.o + +ccflags-$(CONFIG_NFC_PN553_DEVICES) := -DDEBUG \ No newline at end of file diff --git a/drivers/nfc/pn553-i2c/pn553.c b/drivers/nfc/pn553-i2c/pn553.c new file mode 100644 index 000000000000..583940aae7dd --- /dev/null +++ b/drivers/nfc/pn553-i2c/pn553.c @@ -0,0 +1,2069 @@ +/* + * Copyright (C) 2010 Trusted Logic S.A. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ +/****************************************************************************** + * + * The original Work has been changed by NXP Semiconductors. + * + * Copyright (C) 2013-2018 NXP Semiconductors + * * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + ******************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +// #include +#include +#include +/* HiKey Compilation fix */ +#define HiKey_620_COMPILATION_FIX 1 +#ifndef HiKey_620_COMPILATION_FIX +#include +#endif + +#include +#include +#include "pn553.h" + +#include "../oplus_nfc/oplus_nfc.h" + +#define NEXUS5x 0 +#define HWINFO 0 +//#ifdef VENDOR_EDIT + //#if NEXUS5x + //#undef ISO_RST + //#else + //#define ISO_RST + //#endif +//#else /* VENDOR_EDIT */ +#undef ISO_RST +//#endif /* VENDOR_EDIT */ +#define DRAGON_NFC 1 +#define SIG_NFC 44 +#define MAX_BUFFER_SIZE 512 +#define MAX_SECURE_SESSIONS 1 +//#ifdef VENDOR_EDIT +//Add for :when phone is in sleep,wakeup AP +#define WAKEUP_SRC_TIMEOUT (2000) +//#endif /* VENDOR_EDIT */ +/* Macro added to disable SVDD power toggling */ +/* #define JCOP_4X_VALIDATION */ + +//#ifdef VENDOR_EDIT +//Add for : NFC_BAT_SCL(GPIO40) Electric leakage +#define MAX_RETRY_COUNT 3 +#define NCI_RESET_CMD_LEN 4 +#define NCI_INIT_CMD_LEN 3 +#define NCI_RESET_RSP_LEN 6 +#define NCI_INIT_RSP_LEN 28 +#define NCI_GET_FW_CMD_LEN 8 +#define NCI_GET_FW_RSP_LEN 14 +//#endif /* VENDOR_EDIT */ +//#ifdef VENDOR_EDIT +//Add for :control warnning print +#define DEBUG_GPIO_SWITCH 0 +//#endif /* VENDOR_EDIT */ +struct pn544_dev { + wait_queue_head_t read_wq; + struct mutex read_mutex; + //#ifdef VENDOR_EDIT + //Add for: Add mutex to prevent re-init of dwp_onoff_sema + struct mutex dwp_mutex; + //#endif /* VENDOR_EDIT */ + struct i2c_client *client; + struct miscdevice pn544_device; + unsigned int ven_gpio; + unsigned int firm_gpio; + unsigned int irq_gpio; + unsigned int clkreq_gpio; + unsigned int ese_pwr_gpio; /* gpio used by SPI to provide power to p61 via NFCC */ +#ifdef ISO_RST + unsigned int iso_rst_gpio; /* ISO-RST pin gpio*/ +#endif + p61_access_state_t p61_current_state; /* stores the current P61 state */ + bool nfc_ven_enabled; /* stores the VEN pin state powered by Nfc */ + bool spi_ven_enabled; /* stores the VEN pin state powered by Spi */ + //#ifndef VENDOR_EDIT + //Modify for :when phone is in sleep,wakeup AP + //bool irq_enabled; + //#else + volatile bool irq_enabled; + /* NFC_IRQ wake-up state */ + unsigned int count_irq; + bool irq_wake_up; +//#endif /* VENDOR_EDIT */ + spinlock_t irq_enabled_lock; + long nfc_service_pid; /*used to signal the nfc the nfc service */ + chip_pwr_scheme_t chip_pwr_scheme; + unsigned int secure_timer_cnt; + unsigned long dwpLinkUpdateStat; /*DWP link update status*/ + struct workqueue_struct *pSecureTimerCbWq; + struct work_struct wq_task; + /* read buffer*/ + size_t kbuflen; + u8 *kbuf; +}; +/* HiKey Compilation fix */ +#ifndef HiKey_620_COMPILATION_FIX +struct wake_lock nfc_wake_lock; +#if HWINFO +struct hw_type_info hw_info; +#endif +static bool sIsWakeLocked = false; +#endif +static struct pn544_dev *pn544_dev; +static struct semaphore ese_access_sema; +static struct semaphore svdd_sync_onoff_sema; +/*semaphore to wait till JNI operation is completed for SPI on/off*/ +static struct completion dwp_onoff_sema; +/* semaphore to lock SPI open request until signal handling is complete */ +static struct semaphore dwp_onoff_release_sema; +//static struct timer_list secure_timer; +static void release_ese_lock(p61_access_state_t p61_current_state); +int get_ese_lock(p61_access_state_t p61_current_state, int timeout); +static long set_jcop_download_state(unsigned long arg); +//static long start_seccure_timer(unsigned long timer_value); +//static long secure_timer_operation(struct pn544_dev *pn544_dev, unsigned long arg); +#if HWINFO +static void check_hw_info(void); +#endif +#define SECURE_TIMER_WORK_QUEUE "SecTimerCbWq" + +//#ifndef VENDOR_EDIT +//Add for :when phone is in sleep,wakeup AP +static void pn544_enable_irq(struct pn544_dev *pn544_dev) { + unsigned long flags; + spin_lock_irqsave(&pn544_dev->irq_enabled_lock, flags); + if(!pn544_dev->irq_enabled) { + pr_info("%s: enable irq", __func__); + pn544_dev->irq_enabled = true; + enable_irq(pn544_dev->client->irq); + } + spin_unlock_irqrestore(&pn544_dev->irq_enabled_lock, flags); +} +//#endif /* VENDOR_EDIT */ + +static void pn544_disable_irq(struct pn544_dev *pn544_dev) +{ + unsigned long flags; + + spin_lock_irqsave(&pn544_dev->irq_enabled_lock, flags); + if (pn544_dev->irq_enabled) { + disable_irq_nosync(pn544_dev->client->irq); + //#ifndef VENDOR_EDIT + //Remove for :when phone is in sleep,wakeup AP + //disable_irq_wake(pn544_dev->client->irq); + //#endif /* VENDOR_EDIT */ + pn544_dev->irq_enabled = false; + } + spin_unlock_irqrestore(&pn544_dev->irq_enabled_lock, flags); +} + +static irqreturn_t pn544_dev_irq_handler(int irq, void *dev_id) +{ + struct pn544_dev *pn544_dev = dev_id; + + //#ifdef VENDOR_EDIT + //Add for :when phone is in sleep,wakeup AP + unsigned long flags; + if (device_may_wakeup(&pn544_dev->client->dev)) + { + pm_wakeup_event(&pn544_dev->client->dev, WAKEUP_SRC_TIMEOUT); + } + //#endif /* VENDOR_EDIT */ + pn544_disable_irq(pn544_dev); + + //#ifdef VENDOR_EDIT + //Add for :when phone is in sleep,wakeup AP + spin_lock_irqsave(&pn544_dev->irq_enabled_lock, flags); + pn544_dev->count_irq++; + spin_unlock_irqrestore(&pn544_dev->irq_enabled_lock, flags); + //#endif /* VENDOR_EDIT */ + /* HiKey Compilation fix */ + #ifndef HiKey_620_COMPILATION_FIX + if (sIsWakeLocked == false) + { + wake_lock(&nfc_wake_lock); + sIsWakeLocked = true; + } else { + pr_debug("%s already wake locked!\n", __func__); + } + #endif + /* Wake up waiting readers */ + wake_up(&pn544_dev->read_wq); + //#ifdef VENDOR_EDIT + //Add for :when phone is in sleep,wakeup AP + printk("%s : IRQ trigger!\n", __func__); + //#endif /* VENDOR_EDIT */ + + return IRQ_HANDLED; +} + +static ssize_t pn544_dev_read(struct file *filp, char __user *buf, + size_t count, loff_t *offset) +{ + struct pn544_dev *pn544_dev = filp->private_data; + unsigned char *tmp = NULL; + int ret; + + if (count > pn544_dev->kbuflen) + count = pn544_dev->kbuflen; + + //pr_debug("%s : reading %zu bytes.\n", __func__, count); + + mutex_lock(&pn544_dev->read_mutex); + + if (!gpio_get_value(pn544_dev->irq_gpio)) { + if (filp->f_flags & O_NONBLOCK) { + ret = -EAGAIN; + goto fail; + } + + while (1) { + //#ifndef VENDOR_EDIT + //Modify for :when phone is in sleep,wakeup AP + //pn544_dev->irq_enabled = true; + //enable_irq(pn544_dev->client->irq); + //enable_irq_wake(pn544_dev->client->irq); + //#else + pn544_enable_irq(pn544_dev); + //#endif /* VENDOR_EDIT */ + ret = wait_event_interruptible( + pn544_dev->read_wq, + !pn544_dev->irq_enabled); + + //#ifndef VENDOR_EDIT + //Remove for :when phone is in sleep,wakeup AP + //pn544_disable_irq(pn544_dev); + //#endif /* VENDOR_EDIT */ + + if (ret) + goto fail; + + //#ifndef VENDOR_EDIT + //Add for :when phone is in sleep,wakeup AP + pn544_disable_irq(pn544_dev); + //#endif /* VENDOR_EDIT */ + + if (gpio_get_value(pn544_dev->irq_gpio)) + break; + + pr_warning("%s: spurious interrupt detected\n", __func__); + } + } + + tmp = pn544_dev->kbuf; + if (!tmp) { + pr_info("%s: device doesn't exist anymore\n", __func__); + ret = -ENODEV; + goto fail; + } + memset(tmp, 0x00, count); + + /* Read data */ + ret = i2c_master_recv(pn544_dev->client, tmp, count); + #ifndef HiKey_620_COMPILATION_FIX + /* HiKey Compilation fix */ + if (sIsWakeLocked == true) { + wake_unlock(&nfc_wake_lock); + sIsWakeLocked = false; + } + #endif + mutex_unlock(&pn544_dev->read_mutex); + + /* pn544 seems to be slow in handling I2C read requests + * so add 1ms delay after recv operation */ +#if !NEXUS5x + udelay(1000); +#endif + + if (ret < 0) { + pr_err("%s: i2c_master_recv returned %d\n", __func__, ret); + return ret; + } + if (ret > count) { + pr_err("%s: received too many bytes from i2c (%d)\n", + __func__, ret); + return -EIO; + } + if (copy_to_user(buf, tmp, ret)) { + pr_warning("%s : failed to copy to user space\n", __func__); + return -EFAULT; + } + return ret; + + fail: + mutex_unlock(&pn544_dev->read_mutex); + return ret; +} + +static ssize_t pn544_dev_write(struct file *filp, const char __user *buf, + size_t count, loff_t *offset) +{ + struct pn544_dev *pn544_dev; + char *tmp = NULL; + int ret; + + pn544_dev = filp->private_data; + + if (count > pn544_dev->kbuflen) { + pr_err("%s: out of memory\n", __func__); + ret = -ENOMEM; + goto out; + } + + tmp = memdup_user(buf, count); + if (IS_ERR(tmp)) { + pr_info("%s: memdup_user failed\n", __func__); + ret = PTR_ERR(tmp); + goto out; + } + + //pr_debug("%s : writing %zu bytes.\n", __func__, count); + /* Write data */ + ret = i2c_master_send(pn544_dev->client, tmp, count); + if (ret != count) { + pr_err("%s : i2c_master_send returned %d\n", __func__, ret); + ret = -EIO; + } + + /* pn544 seems to be slow in handling I2C write requests + * so add 1ms delay after I2C send oparation */ + udelay(1000); + kfree(tmp); +out: + return ret; +} + +static void p61_update_access_state(struct pn544_dev *pn544_dev, p61_access_state_t current_state, bool set) +{ + //pr_info("%s: Enter current_state = %x\n", __func__, pn544_dev->p61_current_state); + if (current_state) + { + if(set){ + if(pn544_dev->p61_current_state == P61_STATE_IDLE) + pn544_dev->p61_current_state = P61_STATE_INVALID; + pn544_dev->p61_current_state |= current_state; + } + else{ + pn544_dev->p61_current_state ^= current_state; + if(!pn544_dev->p61_current_state) + pn544_dev->p61_current_state = P61_STATE_IDLE; + } + } + //pr_info("%s: Exit current_state = %x\n", __func__, pn544_dev->p61_current_state); +} + +static void p61_get_access_state(struct pn544_dev *pn544_dev, p61_access_state_t *current_state) +{ + + if (current_state == NULL) { + //*current_state = P61_STATE_INVALID; + //pr_err("%s : invalid state of p61_access_state_t current state \n", __func__); + } else { + *current_state = pn544_dev->p61_current_state; + } +} + +static int signal_handler(int state, long nfc_pid) +{ + struct siginfo sinfo; + pid_t pid; + struct task_struct *task; + int sigret = 0, ret = 0; + //pr_info("%s: Enter\n", __func__); + + if(nfc_pid == 0) + { + pr_info("nfc_pid is clear don't call signal_handler.\n"); + } + else + { + memset(&sinfo, 0, sizeof(struct siginfo)); + sinfo.si_signo = SIG_NFC; + sinfo.si_code = SI_QUEUE; + sinfo.si_int = state; + pid = nfc_pid; + + task = pid_task(find_vpid(pid), PIDTYPE_PID); + if(task) + { + pr_info("%s.\n", task->comm); + sigret = force_sig_info(SIG_NFC, &sinfo, task); + if(sigret < 0){ + pr_info("send_sig_info failed..... sigret %d.\n", sigret); + ret = -1; + //msleep(60); + } + } + else{ + pr_info("finding task from PID failed\r\n"); + ret = -1; + } + } + //pr_info("%s: Exit ret = %d\n", __func__, ret); + return ret; +} +static STATUS svdd_sync_onoff(long nfc_service_pid, p61_access_state_t origin) +{ + int timeout = 4500; // 4500 ms timeout + unsigned long tempJ = msecs_to_jiffies(timeout); + //pr_info("%s: Enter nfc_service_pid: %ld\n", __func__, nfc_service_pid); + sema_init(&svdd_sync_onoff_sema, 0); + if (nfc_service_pid) { + if (0 == signal_handler(origin, nfc_service_pid)) { + pr_info("Waiting for svdd protection response"); + if (down_timeout(&svdd_sync_onoff_sema, tempJ) != 0) { + pr_info("svdd wait protection: Timeout"); + return STATUS_FAILED; + } + msleep(10); + //pr_info("svdd wait protection : released"); + } + } + return (pn544_dev->dwpLinkUpdateStat == 0x00) ? STATUS_SUCCESS : STATUS_FAILED; + //pr_info("%s: Exit\n", __func__); +} +static int release_svdd_wait(void) +{ + //pr_info("%s: Enter \n", __func__); + up(&svdd_sync_onoff_sema); + //pr_info("%s: Exit\n", __func__); + return 0; +} + +static STATUS dwp_OnOff(long nfc_service_pid, p61_access_state_t origin) +{ + int timeout = 4500; // 4500 ms timeout + unsigned long tempJ = msecs_to_jiffies(timeout); + init_completion(&dwp_onoff_sema); + if (nfc_service_pid) { + if (0 == signal_handler(origin, nfc_service_pid)) { + if (wait_for_completion_timeout(&dwp_onoff_sema, tempJ) == 0) { + pr_info("Dwp On/off wait protection: Timeout"); + return STATUS_FAILED; + } + //pr_info("Dwp On/Off wait protection : released"); + } + } + return (pn544_dev->dwpLinkUpdateStat == 0x00) ? STATUS_SUCCESS : STATUS_FAILED; +} +static int release_dwpOnOff_wait(void) +{ + int timeout = 500; // 500 ms timeout + unsigned long tempJ = msecs_to_jiffies(timeout); + pr_info("%s: Enter \n", __func__); + complete(&dwp_onoff_sema); + { + sema_init(&dwp_onoff_release_sema, 0); + /*release JNI only after all the SPI On related actions are completed*/ + if (down_timeout(&dwp_onoff_release_sema, tempJ) != 0) { + //pr_info("Dwp On/off release wait protection: Timeout"); + } + //pr_info("Dwp On/Off release wait protection : released"); + } + return 0; +} + +//#ifdef VENDOR_EDIT +//Add for :when phone is in sleep,wakeup AP +static void pn544_init_stat(struct pn544_dev *pn544_dev) +{ + pn544_dev->count_irq = 0; +} +//#endif /* VENDOR_EDIT */ +static int pn544_dev_open(struct inode *inode, struct file *filp) +{ + struct pn544_dev *pn544_dev = container_of(filp->private_data, + struct pn544_dev, + pn544_device); + + filp->private_data = pn544_dev; + //#ifdef VENDOR_EDIT + //Add for :when phone is in sleep,wakeup AP + pn544_init_stat(pn544_dev); + //#endif /* VENDOR_EDIT */ + + pr_debug("%s : %d,%d\n", __func__, imajor(inode), iminor(inode)); + + return 0; +} + +static int set_nfc_pid(unsigned long arg) +{ + //pr_info("%s : The NFC Service PID is %ld\n", __func__, arg); + pn544_dev->nfc_service_pid = arg; + return 0; +} + +long pn544_dev_ioctl(struct file *filp, unsigned int cmd, + unsigned long arg) +{ + pr_info("%s :enter cmd = %u, arg = %ld\n", __func__, cmd, arg); + + /* Free pass autobahn area, not protected. Use it carefullly. START */ + switch(cmd) + { + case P544_GET_ESE_ACCESS: + return get_ese_lock(P61_STATE_WIRED, arg); + break; + case P544_REL_SVDD_WAIT: + //ESE power-on failure sometimes + //pn544_dev->dwpLinkUpdateStat = arg; + return release_svdd_wait(); + break; + case P544_SET_NFC_SERVICE_PID: + return set_nfc_pid(arg); + break; + case P544_REL_DWPONOFF_WAIT: + //ESE power-on failure sometimes + //pn544_dev->dwpLinkUpdateStat = arg; + return release_dwpOnOff_wait(); + break; + default: + break; + } + /* Free pass autobahn area, not protected. Use it carefullly. END */ + + switch (cmd) { + case PN544_SET_PWR: + { + p61_access_state_t current_state = P61_STATE_INVALID; + p61_get_access_state(pn544_dev, ¤t_state); + if (arg == 2) { + if (current_state & (P61_STATE_SPI|P61_STATE_SPI_PRIO) && (pn544_dev->chip_pwr_scheme != PN80T_EXT_PMU_SCHEME)) + { + /* NFCC fw/download should not be allowed if p61 is used + * by SPI + */ + pr_info("%s NFCC should not be allowed to reset/FW download \n", __func__); + return -EBUSY; /* Device or resource busy */ + } + pn544_dev->nfc_ven_enabled = true; + if ((pn544_dev->spi_ven_enabled == false && !(pn544_dev->secure_timer_cnt)) + || (pn544_dev->chip_pwr_scheme == PN80T_EXT_PMU_SCHEME)) + { + /* power on with firmware download (requires hw reset) + */ + pr_info("%s power on with firmware\n", __func__); + gpio_set_value(pn544_dev->ven_gpio, 1); + msleep(10); + if (pn544_dev->firm_gpio) { + p61_update_access_state(pn544_dev, P61_STATE_DWNLD, true); + gpio_set_value(pn544_dev->firm_gpio, 1); + } + msleep(10); + gpio_set_value(pn544_dev->ven_gpio, 0); + msleep(10); + gpio_set_value(pn544_dev->ven_gpio, 1); + msleep(10); + } + } else if (arg == 1) { + /* power on */ + pr_info("%s power on\n", __func__); + if (pn544_dev->firm_gpio) { + if ((current_state & (P61_STATE_WIRED|P61_STATE_SPI|P61_STATE_SPI_PRIO))== 0){ + p61_update_access_state(pn544_dev, P61_STATE_IDLE, true); + } + if(current_state & P61_STATE_DWNLD){ + p61_update_access_state(pn544_dev, P61_STATE_DWNLD, false); + } + gpio_set_value(pn544_dev->firm_gpio, 0); + } + + pn544_dev->nfc_ven_enabled = true; + if (pn544_dev->spi_ven_enabled == false || (pn544_dev->chip_pwr_scheme == PN80T_EXT_PMU_SCHEME)) { + gpio_set_value(pn544_dev->ven_gpio, 1); + } + } else if (arg == 0) { + /* power off */ + pr_info("%s power off\n", __func__); + if (pn544_dev->firm_gpio) { + if ((current_state & (P61_STATE_WIRED|P61_STATE_SPI|P61_STATE_SPI_PRIO))== 0){ + p61_update_access_state(pn544_dev, P61_STATE_IDLE, true); + } + gpio_set_value(pn544_dev->firm_gpio, 0); + } + + pn544_dev->nfc_ven_enabled = false; + /* Don't change Ven state if spi made it high */ + if ((pn544_dev->spi_ven_enabled == false && !(pn544_dev->secure_timer_cnt)) + || (pn544_dev->chip_pwr_scheme == PN80T_EXT_PMU_SCHEME)) { + gpio_set_value(pn544_dev->ven_gpio, 0); + } + /* HiKey Compilation fix */ + #ifndef HiKey_620_COMPILATION_FIX + if (sIsWakeLocked == true) { + wake_unlock(&nfc_wake_lock); + sIsWakeLocked = false; + } + #endif + } else if (arg == 3) { + /*NFC Service called ISO-RST*/ + p61_access_state_t current_state = P61_STATE_INVALID; + p61_get_access_state(pn544_dev, ¤t_state); + if(current_state & (P61_STATE_SPI|P61_STATE_SPI_PRIO)) { + return -EPERM; /* Operation not permitted */ + } + if(current_state & P61_STATE_WIRED) { + p61_update_access_state(pn544_dev, P61_STATE_WIRED, false); + } +#ifdef ISO_RST + gpio_set_value(pn544_dev->iso_rst_gpio, 0); + msleep(50); + gpio_set_value(pn544_dev->iso_rst_gpio, 1); + msleep(50); + pr_info("%s ISO RESET from DWP DONE\n", __func__); +#endif + } else if (arg == 4) { + pr_info("%s FW dwldioctl called from NFC \n", __func__); + /*NFC Service called FW dwnld*/ + if (pn544_dev->firm_gpio) { + p61_update_access_state(pn544_dev, P61_STATE_DWNLD, true); + gpio_set_value(pn544_dev->firm_gpio, 1); + msleep(10); + } + } + else { + pr_err("%s bad arg %lu\n", __func__, arg); + /* changed the p61 state to idle*/ + return -EINVAL; + } + } + break; + case P61_SET_SPI_PWR: + { + bool isSignalTriggerReqd = !(arg & 0x10); + unsigned long pwrLevel = arg & 0x0F; + p61_access_state_t current_state = P61_STATE_INVALID; + p61_get_access_state(pn544_dev, ¤t_state); + /*For chipType pn557 (5th bit of arg) do not trigger signal*/ + if (pwrLevel == 1) { + //pr_info("%s : PN61_SET_SPI_PWR - power on ese\n", __func__); + if (((current_state & (P61_STATE_SPI|P61_STATE_SPI_PRIO)) == 0) || (current_state & P61_STATE_SPI_FAILED)) + { + /*To handle triple mode protection signal + NFC service when SPI session started*/ + if (isSignalTriggerReqd && !(current_state & P61_STATE_JCP_DWNLD)){ + if(pn544_dev->nfc_service_pid){ + //pr_info("nfc service pid %s ---- %ld", __func__, pn544_dev->nfc_service_pid); + //#ifndef VENDOR_EDIT + //Modify for: Add mutex to prevent re-init of dwp_onoff_sema + /* + STATUS stat = dwp_OnOff(pn544_dev->nfc_service_pid, P61_STATE_SPI); + */ + //#else + STATUS stat; + mutex_lock(&pn544_dev->dwp_mutex); + stat = dwp_OnOff(pn544_dev->nfc_service_pid, P61_STATE_SPI); + mutex_unlock(&pn544_dev->dwp_mutex); + //#endif /* VENDOR_EDIT */ + if(stat != STATUS_SUCCESS) { + pr_info(" %s DWP link activation failed. Returning..", __func__); + p61_update_access_state(pn544_dev, P61_STATE_SPI_FAILED, true); + return stat; + } + } + else{ + pr_info(" invalid nfc service pid....signalling failed%s ---- %ld", __func__, pn544_dev->nfc_service_pid); + } + } + + pn544_dev->spi_ven_enabled = true; + + if(pn544_dev->chip_pwr_scheme == PN80T_EXT_PMU_SCHEME) + break; + + if (pn544_dev->nfc_ven_enabled == false) + { + /* provide power to NFCC if, NFC service not provided */ + gpio_set_value(pn544_dev->ven_gpio, 1); + msleep(10); + } + /* pull the gpio to high once NFCC is power on*/ + gpio_set_value(pn544_dev->ese_pwr_gpio, 1); + + /* Delay (10ms) after SVDD_PWR_ON to allow JCOP to bootup (5ms jcop boot time + 5ms guard time) */ + usleep_range(10000, 12000); + if(current_state & P61_STATE_SPI_FAILED){ + p61_update_access_state(pn544_dev, P61_STATE_SPI_FAILED, false); + } + p61_update_access_state(pn544_dev, P61_STATE_SPI, true); + if (pn544_dev->nfc_service_pid) { + up(&dwp_onoff_release_sema); + } + + } else if ((current_state & (P61_STATE_SPI|P61_STATE_SPI_PRIO)) + && (gpio_get_value(pn544_dev->ese_pwr_gpio)) && (gpio_get_value(pn544_dev->ven_gpio))) { + /* Returning success if SET_SPM_POWER called while already SPI is open */ + return 0; + } else { + pr_info("%s : PN61_SET_SPI_PWR - power on ese failed \n", __func__); + return -EBUSY; /* Device or resource busy */ + } + } else if (pwrLevel == 0) { + //pr_info("%s : PN61_SET_SPI_PWR - power off ese\n", __func__); + if(current_state & P61_STATE_SPI_PRIO){ + p61_update_access_state(pn544_dev, P61_STATE_SPI_PRIO, false); + if (!(current_state & P61_STATE_JCP_DWNLD)) + { + if(pn544_dev->nfc_service_pid){ + //pr_info("nfc service pid %s ---- %ld", __func__, pn544_dev->nfc_service_pid); + if(!(current_state & P61_STATE_WIRED)) + { + svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_START | + P61_STATE_SPI_PRIO_END); + }else { + signal_handler(P61_STATE_SPI_PRIO_END, pn544_dev->nfc_service_pid); + } + } + else{ + pr_info(" invalid nfc service pid....signalling failed%s ---- %ld", __func__, pn544_dev->nfc_service_pid); + } + } else if (!(current_state & P61_STATE_WIRED)) { + svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_START); + } + pn544_dev->spi_ven_enabled = false; + + if(pn544_dev->chip_pwr_scheme == PN80T_EXT_PMU_SCHEME) + break; + + /* if secure timer is running, Delay the SPI close by 25ms after sending End of Apdu to enable eSE go into DPD + gracefully (20ms after EOS + 5ms DPD settlement time) */ + if(pn544_dev->secure_timer_cnt) + usleep_range(25000, 30000); + + if (!(current_state & P61_STATE_WIRED) && !(pn544_dev->secure_timer_cnt)) + { +#ifndef JCOP_4X_VALIDATION + gpio_set_value(pn544_dev->ese_pwr_gpio, 0); + /* Delay (2.5ms) after SVDD_PWR_OFF for the shutdown settlement time */ + usleep_range(2500, 3000); +#endif + svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_END); + } +#ifndef JCOP_4X_VALIDATION + if ((pn544_dev->nfc_ven_enabled == false) && !(pn544_dev->secure_timer_cnt)) { + gpio_set_value(pn544_dev->ven_gpio, 0); + msleep(10); + } +#endif + }else if((current_state & P61_STATE_SPI) || (current_state & P61_STATE_SPI_FAILED)){ + if (!(current_state & P61_STATE_WIRED) && + (pn544_dev->chip_pwr_scheme != PN80T_EXT_PMU_SCHEME) && + !(current_state & P61_STATE_JCP_DWNLD)) + { + if(isSignalTriggerReqd) { + if(pn544_dev->nfc_service_pid){ + //pr_info("nfc service pid %s ---- %ld", __func__, pn544_dev->nfc_service_pid); + STATUS stat = svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_START | P61_STATE_SPI_END); + if(stat != STATUS_SUCCESS) { + pr_info(" %s DWP link deactivation Failed. Returning..", __func__); + p61_update_access_state(pn544_dev, P61_STATE_SPI_FAILED, true); + return stat; + } + } + else{ + pr_info(" invalid nfc service pid....signalling failed%s ---- %ld", __func__, pn544_dev->nfc_service_pid); + } + } + + /* if secure timer is running, Delay the SPI close by 25ms after sending End of Apdu to enable eSE go into DPD + gracefully (20ms after EOS + 5ms DPD settlement time) */ + if(pn544_dev->secure_timer_cnt) + usleep_range(25000, 30000); + + if (!(pn544_dev->secure_timer_cnt)) { +#ifndef JCOP_4X_VALIDATION + gpio_set_value(pn544_dev->ese_pwr_gpio, 0); + /* Delay (2.5ms) after SVDD_PWR_OFF for the shutdown settlement time */ + usleep_range(2500, 3000); +#endif + if(current_state & P61_STATE_SPI_FAILED) { + p61_update_access_state(pn544_dev, P61_STATE_SPI_FAILED, false); + } + if(current_state & P61_STATE_SPI) { + p61_update_access_state(pn544_dev, P61_STATE_SPI, false); + } + if(isSignalTriggerReqd) + svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_END); + } + } + /*If JCOP3.2 or 3.3 for handling triple mode + protection signal NFC service */ + else + { + if(isSignalTriggerReqd) { + if (!(current_state & P61_STATE_JCP_DWNLD)) + { + if(pn544_dev->nfc_service_pid){ + //pr_info("nfc service pid %s ---- %ld", __func__, pn544_dev->nfc_service_pid); + if(pn544_dev->chip_pwr_scheme == PN80T_LEGACY_PWR_SCHEME) + { + STATUS stat = svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_START | P61_STATE_SPI_END); + if(stat != STATUS_SUCCESS) { + pr_info(" %s DWP link deactivation Failed. Returning..", __func__); + p61_update_access_state(pn544_dev, P61_STATE_SPI_FAILED, true); + return stat; + } + } else { + signal_handler(P61_STATE_SPI_END, pn544_dev->nfc_service_pid); + } + } + else{ + pr_info(" invalid nfc service pid....signalling failed%s ---- %ld", __func__, pn544_dev->nfc_service_pid); + } + } else if (pn544_dev->chip_pwr_scheme == PN80T_LEGACY_PWR_SCHEME) { + svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_START); + } + } + if(pn544_dev->chip_pwr_scheme == PN80T_LEGACY_PWR_SCHEME) + { +#ifndef JCOP_4X_VALIDATION + gpio_set_value(pn544_dev->ese_pwr_gpio, 0); +#endif + if(current_state & P61_STATE_SPI_FAILED){ + p61_update_access_state(pn544_dev, P61_STATE_SPI_FAILED, false); + } + if(current_state & P61_STATE_SPI) { + p61_update_access_state(pn544_dev, P61_STATE_SPI, false); + } + if(isSignalTriggerReqd) + svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_END); + //pr_info("PN80T legacy ese_pwr_gpio off %s", __func__); + } + } + pn544_dev->spi_ven_enabled = false; + if (pn544_dev->nfc_ven_enabled == false && (pn544_dev->chip_pwr_scheme != PN80T_EXT_PMU_SCHEME) + && !(pn544_dev->secure_timer_cnt)) { + gpio_set_value(pn544_dev->ven_gpio, 0); + msleep(10); + } + } else { + pr_err("%s : PN61_SET_SPI_PWR - failed, current_state = %x \n", + __func__, pn544_dev->p61_current_state); + return -EPERM; /* Operation not permitted */ + } + }else if (arg == 2) { + pr_info("%s : PN61_SET_SPI_PWR - reset\n", __func__); + if (current_state & (P61_STATE_IDLE|P61_STATE_SPI|P61_STATE_SPI_PRIO)) { + if (pn544_dev->spi_ven_enabled == false) + { + pn544_dev->spi_ven_enabled = true; + if ((pn544_dev->nfc_ven_enabled == false) && (pn544_dev->chip_pwr_scheme != PN80T_EXT_PMU_SCHEME)) { + /* provide power to NFCC if, NFC service not provided */ + gpio_set_value(pn544_dev->ven_gpio, 1); + msleep(10); + } + } + if(pn544_dev->chip_pwr_scheme != PN80T_EXT_PMU_SCHEME && !(pn544_dev->secure_timer_cnt)) + { + svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_START); +#ifndef JCOP_4X_VALIDATION + gpio_set_value(pn544_dev->ese_pwr_gpio, 0); +#endif + svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_END); + msleep(10); + if(!gpio_get_value(pn544_dev->ese_pwr_gpio)) + gpio_set_value(pn544_dev->ese_pwr_gpio, 1); + msleep(10); + } + } else { + pr_info("%s : PN61_SET_SPI_PWR - reset failed \n", __func__); + return -EBUSY; /* Device or resource busy */ + } + }else if (arg == 3) { + pr_info("%s : PN61_SET_SPI_PWR - Prio Session Start power on ese\n", __func__); + if ((current_state & (P61_STATE_SPI|P61_STATE_SPI_PRIO)) == 0) { + p61_update_access_state(pn544_dev, P61_STATE_SPI_PRIO, true); + if (current_state & P61_STATE_WIRED){ + if(pn544_dev->nfc_service_pid){ + pr_info("nfc service pid %s ---- %ld", __func__, pn544_dev->nfc_service_pid); + /*signal_handler(P61_STATE_SPI_PRIO, pn544_dev->nfc_service_pid);*/ + dwp_OnOff(pn544_dev->nfc_service_pid, P61_STATE_SPI_PRIO); + } + else{ + pr_info(" invalid nfc service pid....signalling failed%s ---- %ld", __func__, pn544_dev->nfc_service_pid); + } + } + pn544_dev->spi_ven_enabled = true; + if(pn544_dev->chip_pwr_scheme != PN80T_EXT_PMU_SCHEME) + { + if (pn544_dev->nfc_ven_enabled == false) { + /* provide power to NFCC if, NFC service not provided */ + gpio_set_value(pn544_dev->ven_gpio, 1); + msleep(10); + } + /* pull the gpio to high once NFCC is power on*/ + gpio_set_value(pn544_dev->ese_pwr_gpio, 1); + + /* Delay (10ms) after SVDD_PWR_ON to allow JCOP to bootup (5ms jcop boot time + 5ms guard time) */ + usleep_range(10000, 12000); + } + }else { + pr_info("%s : Prio Session Start power on ese failed \n", __func__); + return -EBUSY; /* Device or resource busy */ + } + }else if (arg == 4) { + if (current_state & P61_STATE_SPI_PRIO) + { + pr_info("%s : PN61_SET_SPI_PWR - Prio Session Ending...\n", __func__); + p61_update_access_state(pn544_dev, P61_STATE_SPI_PRIO, false); + /*after SPI prio timeout, the state is changing from SPI prio to SPI */ + p61_update_access_state(pn544_dev, P61_STATE_SPI, true); + if (current_state & P61_STATE_WIRED) + { + if(pn544_dev->nfc_service_pid){ + pr_info("nfc service pid %s ---- %ld", __func__, pn544_dev->nfc_service_pid); + signal_handler(P61_STATE_SPI_PRIO_END, pn544_dev->nfc_service_pid); + } + else{ + pr_info(" invalid nfc service pid....signalling failed%s ---- %ld", __func__, pn544_dev->nfc_service_pid); + } + } + } + else + { + pr_info("%s : PN61_SET_SPI_PWR - Prio Session End failed \n", __func__); + return -EBADRQC; /* Device or resource busy */ + } + } else if(arg == 5){ + release_ese_lock(P61_STATE_SPI); + } else if (arg == 6) { + /*SPI Service called ISO-RST*/ + p61_access_state_t current_state = P61_STATE_INVALID; + p61_get_access_state(pn544_dev, ¤t_state); + if(current_state & P61_STATE_WIRED) { + return -EPERM; /* Operation not permitted */ + } + if(current_state & P61_STATE_SPI) { + p61_update_access_state(pn544_dev, P61_STATE_SPI, false); + }else if(current_state & P61_STATE_SPI_PRIO) { + p61_update_access_state(pn544_dev, P61_STATE_SPI_PRIO, false); + } +#ifdef ISO_RST + gpio_set_value(pn544_dev->iso_rst_gpio, 0); + msleep(50); + gpio_set_value(pn544_dev->iso_rst_gpio, 1); + msleep(50); + pr_info("%s ISO RESET from SPI DONE\n", __func__); +#endif + } + else { + pr_info("%s bad ese pwr arg %lu\n", __func__, arg); + return -EBADRQC; /* Invalid request code */ + } + } + break; + + case P61_GET_PWR_STATUS: + { + p61_access_state_t current_state = P61_STATE_INVALID; + p61_get_access_state(pn544_dev, ¤t_state); + //pr_info("%s: P61_GET_PWR_STATUS = %x",__func__, current_state); + put_user(current_state, (int __user *)arg); + } + break; + + case PN544_SET_DWNLD_STATUS: + { + long ret; + ret = set_jcop_download_state(arg); + if(ret < 0) + { + return ret; + } + } + break; + + case P61_SET_WIRED_ACCESS: + { + p61_access_state_t current_state = P61_STATE_INVALID; + p61_get_access_state(pn544_dev, ¤t_state); + if (arg == 1) + { + if (current_state) + { + //pr_info("%s : P61_SET_WIRED_ACCESS - enabling\n", __func__); + p61_update_access_state(pn544_dev, P61_STATE_WIRED, true); + if (current_state & P61_STATE_SPI_PRIO) + { + if(pn544_dev->nfc_service_pid){ + //pr_info("nfc service pid %s ---- %ld", __func__, pn544_dev->nfc_service_pid); + signal_handler(P61_STATE_SPI_PRIO, pn544_dev->nfc_service_pid); + } + else{ + pr_info(" invalid nfc service pid....signalling failed%s ---- %ld", __func__, pn544_dev->nfc_service_pid); + } + } + if((current_state & (P61_STATE_SPI|P61_STATE_SPI_PRIO)) == 0 && (pn544_dev->chip_pwr_scheme == PN67T_PWR_SCHEME)) + gpio_set_value(pn544_dev->ese_pwr_gpio, 1); + } else { + pr_info("%s : P61_SET_WIRED_ACCESS - enabling failed \n", __func__); + return -EBUSY; /* Device or resource busy */ + } + } else if (arg == 0) { + //pr_info("%s : P61_SET_WIRED_ACCESS - disabling \n", __func__); + if (current_state & P61_STATE_WIRED){ + p61_update_access_state(pn544_dev, P61_STATE_WIRED, false); + if((current_state & (P61_STATE_SPI|P61_STATE_SPI_PRIO)) == 0 && (pn544_dev->chip_pwr_scheme == PN67T_PWR_SCHEME)) + { + svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_START); + gpio_set_value(pn544_dev->ese_pwr_gpio, 0); + svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_END); + } + } else { + pr_err("%s : P61_SET_WIRED_ACCESS - failed, current_state = %x \n", + __func__, pn544_dev->p61_current_state); + return -EPERM; /* Operation not permitted */ + } + } + else if(arg == 2) + { + //pr_info("%s : P61_ESE_GPIO_LOW \n", __func__); + if(pn544_dev->chip_pwr_scheme == PN67T_PWR_SCHEME) + { + svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_START); + gpio_set_value(pn544_dev->ese_pwr_gpio, 0); + svdd_sync_onoff(pn544_dev->nfc_service_pid, P61_STATE_SPI_SVDD_SYNC_END); + } + } + else if(arg == 3) + { + //pr_info("%s : P61_ESE_GPIO_HIGH \n", __func__); + if(pn544_dev->chip_pwr_scheme == PN67T_PWR_SCHEME) + gpio_set_value(pn544_dev->ese_pwr_gpio, 1); + } + else if(arg == 4) + { + release_ese_lock(P61_STATE_WIRED); + } + else if(arg == 5) + { + gpio_set_value(pn544_dev->ese_pwr_gpio, 1); + if (gpio_get_value(pn544_dev->ese_pwr_gpio)) { + pr_info("%s: ese_pwr gpio is enabled\n", __func__); + } + } + else if(arg == 6) + { + gpio_set_value(pn544_dev->ese_pwr_gpio, 0); + pr_info("%s: ese_pwr gpio set to low\n", __func__); + } + else { + pr_info("%s P61_SET_WIRED_ACCESS - bad arg %lu\n", __func__, arg); + return -EBADRQC; /* Invalid request code */ + } + } + break; + case P544_SET_POWER_SCHEME: + { + if(arg == PN67T_PWR_SCHEME) + { + pn544_dev->chip_pwr_scheme = PN67T_PWR_SCHEME; + //pr_info("%s : The power scheme is set to PN67T legacy \n", __func__); + } + else if(arg == PN80T_LEGACY_PWR_SCHEME) + { + pn544_dev->chip_pwr_scheme = PN80T_LEGACY_PWR_SCHEME; + //pr_info("%s : The power scheme is set to PN80T_LEGACY_PWR_SCHEME,\n", __func__); + } + else if(arg == PN80T_EXT_PMU_SCHEME) + { + pn544_dev->chip_pwr_scheme = PN80T_EXT_PMU_SCHEME; + //pr_info("%s : The power scheme is set to PN80T_EXT_PMU_SCHEME,\n", __func__); + } + else + { + pr_info("%s : The power scheme is invalid,\n", __func__); + } + } + break; + case P544_SECURE_TIMER_SESSION: + { + //secure_timer_operation(pn544_dev, arg); + } + break; + default: + pr_err("%s bad ioctl %u\n", __func__, cmd); + return -EINVAL; + } + pr_info("%s :exit cmd = %u, arg = %ld\n", __func__, cmd, arg); + return 0; +} +EXPORT_SYMBOL(pn544_dev_ioctl); + +static void secure_timer_workqueue(struct work_struct *Wq) +{ + p61_access_state_t current_state = P61_STATE_INVALID; + printk( KERN_INFO "secure_timer_callback: called (%lu).\n", jiffies); + /* Locking the critical section: ESE_PWR_OFF to allow eSE to shutdown peacefully :: START */ + get_ese_lock(P61_STATE_WIRED, MAX_ESE_ACCESS_TIME_OUT_MS); + p61_update_access_state(pn544_dev, P61_STATE_SECURE_MODE, false); + p61_get_access_state(pn544_dev, ¤t_state); + + if((current_state & (P61_STATE_SPI|P61_STATE_SPI_PRIO)) == 0) + { + printk( KERN_INFO "secure_timer_callback: make se_pwer_gpio low, state = %d", current_state); + gpio_set_value(pn544_dev->ese_pwr_gpio, 0); + /* Delay (2.5ms) after SVDD_PWR_OFF for the shutdown settlement time */ + usleep_range(2500, 3000); + if(pn544_dev->nfc_service_pid == 0x00) + { + gpio_set_value(pn544_dev->ven_gpio, 0); + printk( KERN_INFO "secure_timer_callback :make ven_gpio low, state = %d", current_state); + } + } + pn544_dev->secure_timer_cnt = 0; + /* Locking the critical section: ESE_PWR_OFF to allow eSE to shutdown peacefully :: END */ + release_ese_lock(P61_STATE_WIRED); + return; +} + +//static void secure_timer_callback( unsigned long data ) +//{ + /* Flush and push the timer callback event to the bottom half(work queue) + to be executed later, at a safer time */ +// flush_workqueue(pn544_dev->pSecureTimerCbWq); +// queue_work(pn544_dev->pSecureTimerCbWq, &pn544_dev->wq_task); +// return; +//} + + +//static long start_seccure_timer(unsigned long timer_value) +//{ +// long ret = -EINVAL; +// pr_info("start_seccure_timer: enter\n"); + /* Delete the timer if timer pending */ + //if(timer_pending(&secure_timer) == 1) + //{ + // pr_info("start_seccure_timer: delete pending timer \n"); + /* delete timer if already pending */ + // del_timer(&secure_timer); + //} + /* Start the timer if timer value is non-zero */ +/* if(timer_value) + { + init_timer(&secure_timer); + setup_timer( &secure_timer, secure_timer_callback, 0 ); + + pr_info("start_seccure_timer: timeout %lums (%lu)\n",timer_value, jiffies ); + ret = mod_timer( &secure_timer, jiffies + msecs_to_jiffies(timer_value)); + if (ret) + pr_info("start_seccure_timer: Error in mod_timer\n"); + } + return ret; +} +*/ +/* +static long secure_timer_operation(struct pn544_dev *pn544_dev, unsigned long arg) +{ + long ret = -EINVAL; + unsigned long timer_value = arg; + + printk( KERN_INFO "secure_timer_operation, %d\n",pn544_dev->chip_pwr_scheme); + if(pn544_dev->chip_pwr_scheme == PN80T_LEGACY_PWR_SCHEME) + { + ret = start_seccure_timer(timer_value); + if(!ret) + { + pn544_dev->secure_timer_cnt = 1; + p61_update_access_state(pn544_dev, P61_STATE_SECURE_MODE, true); + } + else + { + pn544_dev->secure_timer_cnt = 0; + p61_update_access_state(pn544_dev, P61_STATE_SECURE_MODE, false); + pr_info("%s :Secure timer reset \n", __func__); + } + } + else + { + pr_info("%s :Secure timer session not applicable \n", __func__); + } + return ret; +} +*/ +static long set_jcop_download_state(unsigned long arg) +{ + p61_access_state_t current_state = P61_STATE_INVALID; + long ret = 0; + p61_get_access_state(pn544_dev, ¤t_state); + pr_info("%s:Enter PN544_SET_DWNLD_STATUS:JCOP Dwnld state arg = %ld",__func__, arg); + if(arg == JCP_DWNLD_INIT) + { + if(pn544_dev->nfc_service_pid) + { + pr_info("nfc service pid %s ---- %ld", __func__, pn544_dev->nfc_service_pid); + signal_handler(JCP_DWNLD_INIT, pn544_dev->nfc_service_pid); + } + else + { + if (current_state & P61_STATE_JCP_DWNLD) + { + ret = -EINVAL; + } + else + { + p61_update_access_state(pn544_dev, P61_STATE_JCP_DWNLD, true); + } + } + } + else if (arg == JCP_DWNLD_START) + { + if (current_state & P61_STATE_JCP_DWNLD) + { + ret = -EINVAL; + } + else + { + p61_update_access_state(pn544_dev, P61_STATE_JCP_DWNLD, true); + } + } + else if (arg == JCP_SPI_DWNLD_COMPLETE) + { + if(pn544_dev->nfc_service_pid) + { + signal_handler(JCP_DWP_DWNLD_COMPLETE, pn544_dev->nfc_service_pid); + } + p61_update_access_state(pn544_dev, P61_STATE_JCP_DWNLD, false); + } + else if (arg == JCP_DWP_DWNLD_COMPLETE) + { + p61_update_access_state(pn544_dev, P61_STATE_JCP_DWNLD, false); + } + else + { + pr_info("%s bad ese pwr arg %lu\n", __func__, arg); + return -EBADRQC; /* Invalid request code */ + } + pr_info("%s: PN544_SET_DWNLD_STATUS = %x",__func__, current_state); + + return ret; +} + +int get_ese_lock(p61_access_state_t p61_current_state, int timeout) +{ + unsigned long tempJ = msecs_to_jiffies(timeout); + if(down_timeout(&ese_access_sema, tempJ) != 0) + { + printk("get_ese_lock: timeout p61_current_state = %d\n", p61_current_state); + return -EBUSY; + } + return 0; +} +EXPORT_SYMBOL(get_ese_lock); + +static void release_ese_lock(p61_access_state_t p61_current_state) +{ + up(&ese_access_sema); +} + + +static const struct file_operations pn544_dev_fops = { + .owner = THIS_MODULE, + .llseek = no_llseek, + .read = pn544_dev_read, + .write = pn544_dev_write, + .open = pn544_dev_open, + .unlocked_ioctl = pn544_dev_ioctl, +}; +#if DRAGON_NFC +static int pn544_parse_dt(struct device *dev, + struct pn544_i2c_platform_data *data) +{ + struct device_node *np = dev->of_node; + int errorno = 0; + +#if !NEXUS5x + data->irq_gpio = of_get_named_gpio(np, "nxp,pn544-irq", 0); + if ((!gpio_is_valid(data->irq_gpio))) + { + pr_info("%s data->irq_gpio failed data->irq_gpio= %d", __func__ , data->irq_gpio); + return -EINVAL; + } + + data->ven_gpio = of_get_named_gpio(np, "nxp,pn544-ven", 0); + if ((!gpio_is_valid(data->ven_gpio))) + { + pr_info("%s data->irq_gpio failed data->irq_gpio= %d", __func__ , data->irq_gpio); + return -EINVAL; + } + + data->firm_gpio = of_get_named_gpio(np, "nxp,pn544-fw-dwnld", 0); + if ((!gpio_is_valid(data->firm_gpio))) + { + pr_info("%s data->firm_gpio failed data->firm_gpio= %d", __func__ , data->firm_gpio); + return -EINVAL; + } + + data->ese_pwr_gpio = of_get_named_gpio(np, "nxp,pn544-ese-pwr", 0); + if ((!gpio_is_valid(data->ese_pwr_gpio))) + { + pr_info("%s data->ese_pwr_gpio failed data->ese_pwr_gpio= %d", __func__ , data->ese_pwr_gpio); + //return -EINVAL; + } + + data->iso_rst_gpio = of_get_named_gpio(np, "nxp,pn544-iso-pwr-rst", 0); + if ((!gpio_is_valid(data->iso_rst_gpio))) + { + //#ifdef VENDOR_EDIT + //Add for :control warnning print + #if DEBUG_GPIO_SWITCH + pr_info("%s data->iso_rst_gpio failed data->iso_rst_gpio= %d", __func__ , data->iso_rst_gpio); + //return -EINVAL; + #endif + //#endif VENDOR_EDIT + } + +#else + data->ven_gpio = of_get_named_gpio_flags(np, + "nxp,gpio_ven", 0, NULL); + data->firm_gpio = of_get_named_gpio_flags(np, + "nxp,gpio_mode", 0, NULL); + data->irq_gpio = of_get_named_gpio_flags(np, + "nxp,gpio_irq", 0, NULL); +#endif + //#ifdef VENDOR_EDIT + //Add for :control warnning print + //#if DEBUG_GPIO_SWITCH + pr_info("%s: %d, %d, %d, %d, %d error:%d\n", __func__, + data->irq_gpio, data->ven_gpio, data->firm_gpio, data->iso_rst_gpio, + data->ese_pwr_gpio, errorno); + //#endif + //#endif VENDOR_EDIT + + return errorno; +} +#endif + + +//#ifdef VENDOR_EDIT +//Add for : NFC_BAT_SCL(GPIO40) Electric leakage +/** + * nqx_standby_write() + * @buf: pointer to data buffer + * @len: # of bytes need to transfer + * + * write data buffer over I2C and retry + * if NFCC is in stand by mode + * + * Return: # of bytes written or -ve value in case of error + */ +/* +static int nqx_standby_write(struct pn544_dev *nqx_dev, + const unsigned char *buf, size_t len) +{ + int ret = -EINVAL; + int retry_cnt; + + for (retry_cnt = 1; retry_cnt <= MAX_RETRY_COUNT; retry_cnt++) { + ret = i2c_master_send(nqx_dev->client, buf, len); + if (ret < 0) { + pr_err("%s: write failed, Maybe in Standby Mode - Retry(%d)\n",__func__, retry_cnt); + usleep_range(1000, 1100); + } else if (ret == len) { + break; + } + } + return ret; +} +*/ +/* Check for availability of NQ_ NFC controller hardware */ +static int nfcc_hw_check(struct i2c_client *client, struct pn544_dev *nqx_dev) +{ + int ret = 0; + #if 0 + //#ifndef VENDOR_EDIT + //Modify for : send get firmware version + int gpio_retry_count = 0; + unsigned int enable_gpio = nqx_dev->ven_gpio; + char *nci_reset_cmd = NULL; + char *nci_init_cmd = NULL; + char *nci_init_rsp = NULL; + char *nci_reset_rsp = NULL; + + nci_reset_cmd = kzalloc(NCI_RESET_CMD_LEN + 1, GFP_DMA | GFP_KERNEL); + if (!nci_reset_cmd) { + ret = -ENOMEM; + goto done; + } + + nci_reset_rsp = kzalloc(NCI_RESET_RSP_LEN + 1, GFP_DMA | GFP_KERNEL); + if (!nci_reset_rsp) { + ret = -ENOMEM; + goto done; + } + + nci_init_cmd = kzalloc(NCI_INIT_CMD_LEN + 1, GFP_DMA | GFP_KERNEL); + if (!nci_init_cmd) { + ret = -ENOMEM; + goto done; + } + + nci_init_rsp = kzalloc(NCI_INIT_RSP_LEN + 1, GFP_DMA | GFP_KERNEL); + if (!nci_init_rsp) { + ret = -ENOMEM; + goto done; + } + +reset_enable_gpio: + /* making sure that the NFCC starts in a clean state. */ + gpio_set_value(enable_gpio, 0);/* ULPM: Disable */ + /* hardware dependent delay */ + usleep_range(10000, 10100); + gpio_set_value(enable_gpio, 1);/* HPD : Enable*/ + /* hardware dependent delay */ + usleep_range(10000, 10100); + + nci_reset_cmd[0] = 0x20; + nci_reset_cmd[1] = 0x00; + nci_reset_cmd[2] = 0x01; + nci_reset_cmd[3] = 0x00; + /* send NCI CORE RESET CMD with Keep Config parameters */ + ret = i2c_master_send(client, nci_reset_cmd, NCI_RESET_CMD_LEN); + if (ret < 0) { + pr_err("%s: - i2c_master_send core reset Error\n", __func__); + } + /* hardware dependent delay */ + msleep(30); + + /* Read Response of RESET command */ + ret = i2c_master_recv(client, nci_reset_rsp, NCI_RESET_RSP_LEN); + if (ret < 0) { + pr_err("%s: - i2c_master_recv Error\n", __func__); + gpio_retry_count = gpio_retry_count + 1; + if (gpio_retry_count < MAX_RETRY_COUNT) + goto reset_enable_gpio; + goto err_nfcc_hw_check; + } + nci_init_cmd[0] = 0x20; + nci_init_cmd[1] = 0x01; + nci_init_cmd[2] = 0x00; + + ret = nqx_standby_write(nqx_dev, nci_init_cmd, NCI_INIT_CMD_LEN); + if (ret < 0) { + pr_err("%s: - i2c_master_send failed for Core INIT\n", __func__); + goto err_nfcc_core_init_fail; + } + /* hardware dependent delay */ + msleep(30); + /* Read Response of INIT command */ + ret = i2c_master_recv(client, nci_init_rsp, NCI_INIT_RSP_LEN); + if (ret < 0) { + pr_err("%s: - i2c_master_recv Error\n", __func__); + goto err_nfcc_core_init_fail; + } + gpio_set_value(enable_gpio, 0); + goto done; + +err_nfcc_core_init_fail: + pr_err("%s: err_nfcc_core_init_fail\n",__func__); + +err_nfcc_hw_check: + ret = -ENXIO; + pr_err("%s: - NFCC HW not available\n", __func__); + +done: + kfree(nci_reset_rsp); + kfree(nci_init_rsp); + kfree(nci_init_cmd); + kfree(nci_reset_cmd); +#else + unsigned int enable_gpio = nqx_dev->ven_gpio; + unsigned int firm_gpio = nqx_dev->firm_gpio; + char *nci_get_fw_cmd = NULL; + char *nci_get_fw_rsp = NULL; + + nci_get_fw_cmd = kzalloc(NCI_GET_FW_CMD_LEN + 1, GFP_DMA | GFP_KERNEL); + if (!nci_get_fw_cmd) { + ret = -ENOMEM; + goto done; + } + + nci_get_fw_rsp = kzalloc(NCI_GET_FW_RSP_LEN + 1, GFP_DMA | GFP_KERNEL); + if (!nci_get_fw_rsp) { + ret = -ENOMEM; + goto done; + } + + gpio_set_value(firm_gpio, 1); + /* hardware dependent delay */ + usleep_range(10000, 10100); + /* making sure that the NFCC starts in a clean state. */ + gpio_set_value(enable_gpio, 0);/* ULPM: Disable */ + /* hardware dependent delay */ + usleep_range(10000, 10100); + gpio_set_value(enable_gpio, 1);/* HPD : Enable*/ + /* hardware dependent delay */ + usleep_range(10000, 10100); + + nci_get_fw_cmd[0] = 0x00; + nci_get_fw_cmd[1] = 0x04; + nci_get_fw_cmd[2] = 0xF1; + nci_get_fw_cmd[3] = 0x00; + nci_get_fw_cmd[4] = 0x00; + nci_get_fw_cmd[5] = 0x00; + nci_get_fw_cmd[6] = 0x6E; + nci_get_fw_cmd[7] = 0xEF; + + /*send get FW Version CMD */ + ret = i2c_master_send(client, nci_get_fw_cmd, NCI_GET_FW_CMD_LEN); + if (ret < 0) { + pr_err("%s: - i2c_master_send get fw version Error\n", __func__); + goto err_nfcc_hw_check; + } + pr_err("%s: raw_fw_get_version success----\n", __func__); + /* hardware dependent delay */ + msleep(30); + + /* Read Response of FW Version CMD */ + ret = i2c_master_recv(client, nci_get_fw_rsp, NCI_GET_FW_RSP_LEN); + if (ret < 0) { + pr_err("%s: - i2c_master_recv get fw version Error\n", __func__); + goto err_nfcc_hw_check; + } + gpio_set_value(firm_gpio, 0); + gpio_set_value(enable_gpio, 0); + ret = 0; + //pr_err("%s:%d FW: %02x.%02x.%02x",__func__, __LINE__, nci_get_fw_rsp[4], + // nci_get_fw_rsp[7], nci_get_fw_rsp[6]); + dev_err(&client->dev,"%s:%d FW: %02x.%02x.%02x",__func__, __LINE__, nci_get_fw_rsp[4], + nci_get_fw_rsp[7], nci_get_fw_rsp[6]); + goto done; + +err_nfcc_hw_check: + ret = -ENXIO; + pr_err("%s: - NFCC HW not available\n", __func__); + +done: + kfree(nci_get_fw_rsp); + kfree(nci_get_fw_cmd); +#endif /* VENDOR_EDIT */ + + return ret; +} +//#endif /* VENDOR_EDIT */ + +static int pn544_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int ret; + struct pn544_i2c_platform_data *platform_data; + //struct pn544_dev *pn544_dev; + +#if !DRAGON_NFC + platform_data = client->dev.platform_data; +#else + struct device_node *node = client->dev.of_node; + + //#ifdef OPLUS_FEATURE_CONNFCSOFT + CHECK_NFC_CHIP(PN557); + //#endif /* OPLUS_FEATURE_CONNFCSOFT */ + if (node) { + platform_data = devm_kzalloc(&client->dev, + sizeof(struct pn544_i2c_platform_data), GFP_KERNEL); + if (!platform_data) { + dev_err(&client->dev, + "nfc-nci probe: Failed to allocate memory\n"); + return -ENOMEM; + } + ret = pn544_parse_dt(&client->dev, platform_data); + if (ret) + { + pr_info("%s pn544_parse_dt failed", __func__); + } + client->irq = gpio_to_irq(platform_data->irq_gpio); + if (client->irq < 0) + { + pr_info("%s gpio to irq failed", __func__); + } + } else { + platform_data = client->dev.platform_data; + } +#endif + if (platform_data == NULL) { + pr_err("%s : nfc probe fail\n", __func__); + return -ENODEV; + } + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + pr_err("%s : need I2C_FUNC_I2C\n", __func__); + return -ENODEV; + } +#if !DRAGON_NFC + ret = gpio_request(platform_data->irq_gpio, "nfc_int"); + if (ret) + return -ENODEV; + ret = gpio_request(platform_data->ven_gpio, "nfc_ven"); + if (ret) + goto err_ven; + ret = gpio_request(platform_data->ese_pwr_gpio, "nfc_ese_pwr"); + if (ret) + goto err_ese_pwr; + if (platform_data->firm_gpio) { + ret = gpio_request(platform_data->firm_gpio, "nfc_firm"); + if (ret) + goto err_firm; + } +#ifdef ISO_RST + if(platform_data->iso_rst_gpio) { + ret = gpio_request(platform_data->iso_rst_gpio, "nfc_iso_rst"); + if (ret) + goto err_iso_rst; + } +#endif +#endif + pn544_dev = kzalloc(sizeof(*pn544_dev), GFP_KERNEL); + if (pn544_dev == NULL) { + dev_err(&client->dev, + "failed to allocate memory for module data\n"); + ret = -ENOMEM; + goto err_exit; + } + + pn544_dev->kbuflen = MAX_BUFFER_SIZE; + pn544_dev->kbuf = kzalloc(MAX_BUFFER_SIZE, GFP_KERNEL); + if (!pn544_dev->kbuf) { + pr_err("failed to allocate memory for pn544_dev->kbuf\n"); + ret = -ENOMEM; + goto err_free_dev; + } + + pn544_dev->irq_gpio = platform_data->irq_gpio; + pn544_dev->ven_gpio = platform_data->ven_gpio; + pn544_dev->firm_gpio = platform_data->firm_gpio; + pn544_dev->ese_pwr_gpio = platform_data->ese_pwr_gpio; +#ifdef ISO_RST + pn544_dev->iso_rst_gpio = platform_data->iso_rst_gpio; +#endif + pn544_dev->p61_current_state = P61_STATE_IDLE; + pn544_dev->nfc_ven_enabled = false; + pn544_dev->spi_ven_enabled = false; + pn544_dev->chip_pwr_scheme = PN67T_PWR_SCHEME; + pn544_dev->client = client; + pn544_dev->secure_timer_cnt = 0; + + ret = gpio_direction_input(pn544_dev->irq_gpio); + if (ret < 0) { + pr_err("%s :not able to set irq_gpio as input\n", __func__); + goto err_ven; + } + ret = gpio_direction_output(pn544_dev->ven_gpio, 0); + if (ret < 0) { + pr_err("%s : not able to set ven_gpio as output\n", __func__); + goto err_firm; + } + ret = gpio_direction_output(pn544_dev->ese_pwr_gpio, 0); + if (ret < 0) { + pr_err("%s : not able to set ese_pwr gpio as output\n", __func__); + goto err_ese_pwr; + } + if (platform_data->firm_gpio) { + ret = gpio_direction_output(pn544_dev->firm_gpio, 0); + if (ret < 0) { + pr_err("%s : not able to set firm_gpio as output\n", + __func__); + goto err_exit; + } + } +#ifdef ISO_RST + ret = gpio_direction_output(pn544_dev->iso_rst_gpio, 0); + if (ret < 0) { + pr_err("%s : not able to set iso rst gpio as output\n", __func__); + goto err_iso_rst; + } +#endif + /* init mutex and queues */ + init_waitqueue_head(&pn544_dev->read_wq); + mutex_init(&pn544_dev->read_mutex); + //#ifdef VENDOR_EDIT + //Add for: Add mutex to prevent re-init of dwp_onoff_sema + mutex_init(&pn544_dev->dwp_mutex); + //#endif /* VENDOR_EDIT */ + sema_init(&ese_access_sema, 1); + sema_init(&dwp_onoff_release_sema, 0); + spin_lock_init(&pn544_dev->irq_enabled_lock); + pn544_dev->pSecureTimerCbWq = create_workqueue(SECURE_TIMER_WORK_QUEUE); + INIT_WORK(&pn544_dev->wq_task, secure_timer_workqueue); + pn544_dev->pn544_device.minor = MISC_DYNAMIC_MINOR; + pn544_dev->pn544_device.name = "pn553"; + pn544_dev->pn544_device.fops = &pn544_dev_fops; + + ret = misc_register(&pn544_dev->pn544_device); + if (ret) { + pr_err("%s : misc_register failed\n", __FILE__); + goto err_misc_register; + } + /* HiKey Compilation fix */ + #ifndef HiKey_620_COMPILATION_FIX + wake_lock_init(&nfc_wake_lock, WAKE_LOCK_SUSPEND, "NFCWAKE"); + #endif +#ifdef ISO_RST + /* Setting ISO RESET pin high to power ESE during init */ + gpio_set_value(pn544_dev->iso_rst_gpio, 1); +#endif + /* request irq. the irq is set whenever the chip has data available + * for reading. it is cleared when all data has been read. + */ + //#ifdef VENDOR_EDIT + //Add for :control warnning print + #if DEBUG_GPIO_SWITCH + pr_info("%s : requesting IRQ %d\n", __func__, client->irq); + #endif + //#endif VENDOR_EDIT + pn544_dev->irq_enabled = true; + ret = request_irq(client->irq, pn544_dev_irq_handler, + IRQF_TRIGGER_HIGH, client->name, pn544_dev); + if (ret) { + dev_err(&client->dev, "request_irq failed\n"); + goto err_request_irq_failed; + } + enable_irq_wake(pn544_dev->client->irq); +//#ifdef VENDOR_EDIT +//Add for :when phone is in sleep,wakeup AP + device_init_wakeup(&client->dev, true); + device_set_wakeup_capable(&client->dev, true); +//#endif /* VENDOR_EDIT */ + pn544_disable_irq(pn544_dev); + i2c_set_clientdata(client, pn544_dev); + //#ifdef VENDOR_EDIT + //Add for : NFC_BAT_SCL(GPIO40) Electric leakage + /* + * To be efficient we need to test whether nfcc hardware is physically + * present before attempting further hardware initialisation. + * + */ + ret = nfcc_hw_check(client, pn544_dev); + if (ret < 0) { + pr_err("%s: - nfcc_hw_check fail \n", __func__); + /* make sure NFCC is not enabled */ + gpio_set_value(pn544_dev->firm_gpio, 0); + gpio_set_value(pn544_dev->ven_gpio, 0); + /* We don't think there is hardware switch NFC OFF */ + //#ifdef VENDOR_EDIT + //Del for : do not del the nfc node if nfcc_hw_check fail + //goto err_request_irq_failed; + //#endif /* VENDOR_EDIT */ + } + //#endif /* VENDOR_EDIT */ +#if HWINFO + /* + * This function is used only if + * hardware info is required during probe*/ + check_hw_info(); +#endif + + return 0; + + err_request_irq_failed: + misc_deregister(&pn544_dev->pn544_device); + err_misc_register: + mutex_destroy(&pn544_dev->read_mutex); + //#ifdef VENDOR_EDIT + //Add for: Add mutex to prevent re-init of dwp_onoff_sema + mutex_destroy(&pn544_dev->dwp_mutex); + //#endif /* VENDOR_EDIT */ + //#ifndef VENDOR_EDIT + //Mod for coverity:776320, do not kfree(pn544_dev) here,free it below err_free_dev + //kfree(pn544_dev); + //#endif /* VENDOR_EDIT */ + err_exit: + if (pn544_dev->firm_gpio) + gpio_free(platform_data->firm_gpio); + err_firm: + gpio_free(platform_data->ese_pwr_gpio); + err_ese_pwr: + gpio_free(platform_data->ven_gpio); + err_ven: + gpio_free(platform_data->irq_gpio); +#ifdef ISO_RST + err_iso_rst: + gpio_free(platform_data->iso_rst_gpio); +#endif + kfree(pn544_dev->kbuf); +err_free_dev: + kfree(pn544_dev); + return ret; +} + +static int pn544_remove(struct i2c_client *client) +{ + struct pn544_dev *pn544_dev; + + pn544_dev = i2c_get_clientdata(client); + free_irq(client->irq, pn544_dev); + misc_deregister(&pn544_dev->pn544_device); + mutex_destroy(&pn544_dev->read_mutex); + //#ifdef VENDOR_EDIT + //Add for: Add mutex to prevent re-init of dwp_onoff_sema + mutex_destroy(&pn544_dev->dwp_mutex); + //#endif /* VENDOR_EDIT */ + gpio_free(pn544_dev->irq_gpio); + gpio_free(pn544_dev->ven_gpio); + gpio_free(pn544_dev->ese_pwr_gpio); + destroy_workqueue(pn544_dev->pSecureTimerCbWq); +#ifdef ISO_RST + gpio_free(pn544_dev->iso_rst_gpio); +#endif + pn544_dev->p61_current_state = P61_STATE_INVALID; + pn544_dev->nfc_ven_enabled = false; + pn544_dev->spi_ven_enabled = false; + + if (pn544_dev->firm_gpio) + gpio_free(pn544_dev->firm_gpio); + kfree(pn544_dev->kbuf); + kfree(pn544_dev); + + return 0; +} + +//#ifdef VENDOR_EDIT +//Add for :when phone is in sleep,wakeup AP +static int pn544_suspend(struct device *device) +{ + struct i2c_client *client = to_i2c_client(device); + pn544_dev = i2c_get_clientdata(client); + + if (pn544_dev->nfc_ven_enabled && gpio_get_value(pn544_dev->irq_gpio)) { + pm_wakeup_event(&pn544_dev->client->dev, WAKEUP_SRC_TIMEOUT); + return -1; + } + + return 0; +} + +static int pn544_resume(struct device *device) +{ + return 0; +} + +static const struct dev_pm_ops nfc_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(pn544_suspend, pn544_resume) +}; +//#endif /* VENDOR_EDIT */ +static const struct i2c_device_id pn544_id[] = { +#if NEXUS5x + { "pn548", 0 }, +#else + { "pn544", 0 }, +#endif + { } +}; +#if DRAGON_NFC +static struct of_device_id pn544_i2c_dt_match[] = { + { +#if NEXUS5x + .compatible = "nxp,pn548", +#else + .compatible = "nxp,pn544", +#endif + }, + {} +}; +#endif +static struct i2c_driver pn544_driver = { + .id_table = pn544_id, + .probe = pn544_probe, + .remove = pn544_remove, + .driver = { + .owner = THIS_MODULE, +#if NEXUS5x + .name = "pn553", +#else + .name = "pn553", +#endif +#if DRAGON_NFC + .of_match_table = pn544_i2c_dt_match, +#endif + //#ifdef VENDOR_EDIT + //Add for :when phone is in sleep,wakeup AP + .pm = &nfc_pm_ops, + //#endif /* VENDOR_EDIT */ + }, +}; +#if HWINFO +/****************************************************************************** + * Function check_hw_info + * + * Description This function is called during pn544_probe to retrieve + * HW info. + * Useful get HW information in case of previous FW download is + * interrupted and core reset is not allowed. + * This function checks if core reset is allowed, if not + * sets DWNLD_REQ(firm_gpio) , ven reset and sends firmware + * get version command. + * In response HW information will be received. + * + * Returns None + * + ******************************************************************************/ +static void check_hw_info() { + char read_data[20]; + int ret, get_version_len = 8, retry_count = 0; + static uint8_t cmd_reset_nci[] = {0x20, 0x00, 0x01, 0x00}; + char get_version_cmd[] = + {0x00, 0x04, 0xF1, 0x00, 0x00, 0x00, 0x6E, 0xEF}; + + pr_info("%s :Enter\n", __func__); + + /* + * Ven Reset before sending core Reset + * This is to check core reset is allowed or not. + * If not allowed then previous FW download is interrupted in between + * */ + pr_info("%s :Ven Reset \n", __func__); + gpio_set_value(pn544_dev->ven_gpio, 1); + msleep(10); + gpio_set_value(pn544_dev->ven_gpio, 0); + msleep(10); + gpio_set_value(pn544_dev->ven_gpio, 1); + msleep(10); + ret = i2c_master_send(pn544_dev->client, cmd_reset_nci, 4); + + if (ret == 4) { + pr_info("%s : core reset write success\n", __func__); + } else { + + /* + * Core reset failed. + * set the DWNLD_REQ , do ven reset + * send firmware download info command + * */ + pr_err("%s : write failed\n", __func__); + pr_info("%s power on with firmware\n", __func__); + gpio_set_value(pn544_dev->ven_gpio, 1); + msleep(10); + if (pn544_dev->firm_gpio) { + p61_update_access_state(pn544_dev, P61_STATE_DWNLD, true); + gpio_set_value(pn544_dev->firm_gpio, 1); + } + msleep(10); + gpio_set_value(pn544_dev->ven_gpio, 0); + msleep(10); + gpio_set_value(pn544_dev->ven_gpio, 1); + msleep(10); + ret = i2c_master_send(pn544_dev->client, get_version_cmd, get_version_len); + if (ret != get_version_len) { + ret = -EIO; + pr_err("%s : write_failed \n", __func__); + } + else { + pr_info("%s :data sent\n", __func__); + } + + ret = 0; + + while (retry_count < 10) { + + /* + * Wait for read interrupt + * If spurious interrupt is received retry again + * */ + pn544_dev->irq_enabled = true; + enable_irq(pn544_dev->client->irq); + //#ifndef VENDOR_EDIT + //Remove for :when phone is in sleep,wakeup AP + //enable_irq_wake(pn544_dev->client->irq); + //endif VENDOR_EDIT + ret = wait_event_interruptible( + pn544_dev->read_wq, + !pn544_dev->irq_enabled); + + pn544_disable_irq(pn544_dev); + + if (gpio_get_value(pn544_dev->irq_gpio)) + break; + + pr_warning("%s: spurious interrupt detected\n", __func__); + retry_count ++; + } + + if(ret) { + return; + } + + /* + * Read response data and copy into hw_type_info + * */ + ret = i2c_master_recv(pn544_dev->client, read_data, 14); + + if(ret) { + memcpy(hw_info.data, read_data, ret); + hw_info.len = ret; + pr_info("%s :data received len : %d\n", __func__,hw_info.len); + } + else { + pr_err("%s :Read Failed\n", __func__); + } + } +} +#endif +/* + * module load/unload record keeping + */ + +static int __init pn544_dev_init(void) +{ + pr_info("Loading pn544 driver\n"); + return i2c_add_driver(&pn544_driver); +} +module_init(pn544_dev_init); + +static void __exit pn544_dev_exit(void) +{ + pr_info("Unloading pn544 driver\n"); + i2c_del_driver(&pn544_driver); +} +module_exit(pn544_dev_exit); + +MODULE_AUTHOR("Sylvain Fonteneau"); +MODULE_DESCRIPTION("NFC PN544 driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/nfc/pn553-i2c/pn553.h b/drivers/nfc/pn553-i2c/pn553.h new file mode 100644 index 000000000000..eaf705e59ac1 --- /dev/null +++ b/drivers/nfc/pn553-i2c/pn553.h @@ -0,0 +1,171 @@ +/* + * Copyright (C) 2010 Trusted Logic S.A. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +/****************************************************************************** + * + * The original Work has been changed by NXP Semiconductors. + * + * Copyright (C) 2013-2014 NXP Semiconductors + * * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + ******************************************************************************/ +#ifndef _PN553_H_ +#define _PN553_H_ +#define PN544_MAGIC 0xE9 + +/* + * PN544 power control via ioctl + * PN544_SET_PWR(0): power off + * PN544_SET_PWR(1): power on + * PN544_SET_PWR(2): reset and power on with firmware download enabled + */ +#define PN544_SET_PWR _IOW(PN544_MAGIC, 0x01, int) + +/* + * SPI Request NFCC to enable p61 power, only in param + * Only for SPI + * level 1 = Enable power + * level 0 = Disable power + */ +#define P61_SET_SPI_PWR _IOW(PN544_MAGIC, 0x02, int) + +/* SPI or DWP can call this ioctl to get the current + * power state of P61 + * +*/ +#define P61_GET_PWR_STATUS _IOR(PN544_MAGIC, 0x03, int) + +/* DWP side this ioctl will be called + * level 1 = Wired access is enabled/ongoing + * level 0 = Wired access is disalbed/stopped +*/ +#define P61_SET_WIRED_ACCESS _IOW(PN544_MAGIC, 0x04, int) + +/* + NFC Init will call the ioctl to register the PID with the i2c driver +*/ +#define P544_SET_NFC_SERVICE_PID _IOW(PN544_MAGIC, 0x05, int) + +/* + NFC and SPI will call the ioctl to get the i2c/spi bus access +*/ +#define P544_GET_ESE_ACCESS _IOW(PN544_MAGIC, 0x06, int) +/* + NFC and SPI will call the ioctl to update the power scheme +*/ +#define P544_SET_POWER_SCHEME _IOW(PN544_MAGIC, 0x07, int) + +/* + NFC will call the ioctl to release the svdd protection +*/ +#define P544_REL_SVDD_WAIT _IOW(PN544_MAGIC, 0x08, int) + +/* SPI or DWP can call this ioctl to get the current + * power state of P61 + * +*/ +#define PN544_SET_DWNLD_STATUS _IOW(PN544_MAGIC, 0x09, int) +/* + NFC will call the ioctl to release the dwp on/off protection +*/ +#define P544_REL_DWPONOFF_WAIT _IOW(PN544_MAGIC, 0x0A, int) + +/* + NFC will call the ioctl to start Secure Timer +*/ + +#define P544_SECURE_TIMER_SESSION _IOW(PN544_MAGIC, 0x0B, int) + +#define MAX_ESE_ACCESS_TIME_OUT_MS 200 /*100 milliseconds*/ + +typedef enum p61_access_state{ + P61_STATE_INVALID = 0x0000, + P61_STATE_IDLE = 0x0100, /* p61 is free to use */ + P61_STATE_WIRED = 0x0200, /* p61 is being accessed by DWP (NFCC)*/ + P61_STATE_SPI = 0x0400, /* P61 is being accessed by SPI */ + P61_STATE_DWNLD = 0x0800, /* NFCC fw download is in progress */ + P61_STATE_SPI_PRIO = 0x1000, /*Start of p61 access by SPI on priority*/ + P61_STATE_SPI_PRIO_END = 0x2000, /*End of p61 access by SPI on priority*/ + P61_STATE_SPI_END = 0x4000, + P61_STATE_JCP_DWNLD = 0x8000,/* JCOP downlad in progress */ + P61_STATE_SECURE_MODE = 0x100000, /* secure mode state*/ + P61_STATE_SPI_SVDD_SYNC_START = 0x0001, /*ESE_VDD Low req by SPI*/ + P61_STATE_SPI_SVDD_SYNC_END = 0x0002, /*ESE_VDD is Low by SPI*/ + P61_STATE_DWP_SVDD_SYNC_START = 0x0004, /*ESE_VDD Low req by Nfc*/ + P61_STATE_DWP_SVDD_SYNC_END = 0x0008, /*ESE_VDD is Low by Nfc*/ + P61_STATE_SPI_FAILED = 0x0010 /*SPI open/close failed*/ +}p61_access_state_t; + +typedef enum chip_type_pwr_scheme{ + PN67T_PWR_SCHEME = 0x01, + PN80T_LEGACY_PWR_SCHEME, + PN80T_EXT_PMU_SCHEME, +}chip_pwr_scheme_t; + +typedef enum { + STATUS_FAILED = -1, + STATUS_SUCCESS = (0x0000), +} STATUS; + +typedef enum jcop_dwnld_state{ + JCP_DWNLD_IDLE = P61_STATE_JCP_DWNLD, /* jcop dwnld is ongoing*/ + JCP_DWNLD_INIT=0x8010, /* jcop dwonload init state*/ + JCP_DWNLD_START=0x8020, /* download started */ + JCP_SPI_DWNLD_COMPLETE=0x8040, /* jcop download complete in spi interface*/ + JCP_DWP_DWNLD_COMPLETE=0x8080, /* jcop download complete */ +} jcop_dwnld_state_t; + +struct pn544_i2c_platform_data { + unsigned int irq_gpio; + unsigned int ven_gpio; + unsigned int firm_gpio; + unsigned int clkreq_gpio; + unsigned int ese_pwr_gpio; /* gpio to give power to p61, only TEE should use this */ + unsigned int iso_rst_gpio; /* gpio used for ISO hard reset P73*/ +}; + +struct hw_type_info { + /* + * Response of get_version_cmd will be stored in data + * byte structure : + * byte 0-1 : Header + * byte 2 : Status + * byte 3 : Hardware Version + * byte 4 : ROM code + * byte 5 : 0x00 constant + * byte 6-7 : Protected data version + * byte 8-9 : Trim data version + * byte 10-11 : FW version + * byte 12-13 : CRC + * */ + char data[20]; + int len; +}; +#endif diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index 9d0090df5eac..1fce390718c0 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -32,6 +32,10 @@ #include "of_private.h" +#ifdef CONFIG_PARAM_READ_WRITE +void init_param_mem_base_size(phys_addr_t base, unsigned long size); +#endif + /* * of_fdt_limit_memory - limit the number of regions in the /memory node * @limit: maximum entries @@ -675,6 +679,11 @@ static int __init __reserved_mem_reserve_reg(unsigned long node, pr_info("Reserved memory: failed to reserve memory for node '%s': base %pa, size %lu MiB\n", uname, &base, (unsigned long)(size / SZ_1M)); + #ifdef CONFIG_PARAM_READ_WRITE + if (!strncmp(uname, "param_mem", 9)) + init_param_mem_base_size(base, size); + #endif + len -= t_len; if (first) { fdt_reserved_mem_save_node(node, uname, base, size); diff --git a/drivers/of/of_reserved_mem.c b/drivers/of/of_reserved_mem.c index b6feee55686f..77af226a87af 100644 --- a/drivers/of/of_reserved_mem.c +++ b/drivers/of/of_reserved_mem.c @@ -26,6 +26,10 @@ static struct reserved_mem reserved_mem[MAX_RESERVED_REGIONS]; static int reserved_mem_count; +#ifdef OPLUS_FEATURE_LOWMEM_DBG +static unsigned long reserved_mem_size; +#endif /* OPLUS_FEATURE_LOWMEM_DBG */ + #if defined(CONFIG_HAVE_MEMBLOCK) #include int __init __weak early_init_dt_alloc_reserved_memory_arch(phys_addr_t size, @@ -289,6 +293,9 @@ void __init fdt_init_reserved_mem(void) &rmem->base, &rmem->size); if (err == 0) __reserved_mem_init_node(rmem); +#ifdef OPLUS_FEATURE_LOWMEM_DBG + reserved_mem_size += rmem->size; +#endif /* OPLUS_FEATURE_LOWMEM_DBG */ } } @@ -406,6 +413,13 @@ void of_reserved_mem_device_release(struct device *dev) } EXPORT_SYMBOL_GPL(of_reserved_mem_device_release); +#ifdef OPLUS_FEATURE_LOWMEM_DBG +unsigned long dt_memory_reserved_pages(void) +{ + return reserved_mem_size >> PAGE_SHIFT; +} +#endif /* OPLUS_FEATURE_LOWMEM_DBG */ + /** * of_reserved_mem_lookup() - acquire reserved_mem from a device node * @np: node pointer of the desired reserved-memory region diff --git a/drivers/ommc b/drivers/ommc new file mode 120000 index 000000000000..6e42465182e4 --- /dev/null +++ b/drivers/ommc @@ -0,0 +1 @@ +../../../vendor/oplus/kernel_4.19/mmc \ No newline at end of file diff --git a/drivers/pci/controller/pci-msm.c b/drivers/pci/controller/pci-msm.c index 89656663fa32..0c1b7083e4d5 100644 --- a/drivers/pci/controller/pci-msm.c +++ b/drivers/pci/controller/pci-msm.c @@ -3219,12 +3219,12 @@ static inline int msm_pcie_oper_conf(struct pci_bus *bus, u32 devfn, int oper, if (dev->shadow_en) { if (rd_val == PCIE_LINK_DOWN && - (readl_relaxed(config_base) == PCIE_LINK_DOWN)) + (readl_relaxed(config_base) == PCIE_LINK_DOWN)) PCIE_ERR(dev, "Read of RC%d %d:0x%02x + 0x%04x[%d] is all FFs\n", rc_idx, bus->number, devfn, where, size); - else + else msm_pcie_save_shadow(dev, word_offset, wr_val, bdf, rc); } @@ -3236,7 +3236,7 @@ static inline int msm_pcie_oper_conf(struct pci_bus *bus, u32 devfn, int oper, } if (rd_val == PCIE_LINK_DOWN && - (readl_relaxed(config_base) == PCIE_LINK_DOWN)) { + (readl_relaxed(config_base) == PCIE_LINK_DOWN)) { if (dev->config_recovery) { PCIE_ERR(dev, "RC%d link recovery schedule\n", @@ -3245,7 +3245,6 @@ static inline int msm_pcie_oper_conf(struct pci_bus *bus, u32 devfn, int oper, schedule_work(&dev->link_recover_wq); } } - unlock: spin_unlock_irqrestore(&dev->cfg_lock, dev->irqsave_flags); out: @@ -4419,6 +4418,8 @@ static int msm_pcie_link_train(struct msm_pcie_dev_t *dev) val = readl_relaxed(dev->elbi + PCIE20_ELBI_SYS_STTS); PCIE_DBG(dev, "PCIe RC%d: LTSSM_STATE: %s\n", dev->rc_idx, TO_LTSSM_STR((val >> 12) & 0x3f)); + if ((link_check_count % 10) == 0) + pr_err("PCIe RC%d: LTSSM_STATE: %s\n",dev->rc_idx, TO_LTSSM_STR((val >> 12) & 0x3f)); } while ((!(val & XMLH_LINK_UP) || !msm_pcie_confirm_linkup(dev, false, false, NULL)) && (link_check_count++ < dev->link_check_max_count)); diff --git a/drivers/pinctrl/pinmux.c b/drivers/pinctrl/pinmux.c index 5780442c068b..4abbbb70bcca 100644 --- a/drivers/pinctrl/pinmux.c +++ b/drivers/pinctrl/pinmux.c @@ -497,11 +497,21 @@ void pinmux_disable_setting(const struct pinctrl_setting *setting) gname = pctlops->get_group_name(pctldev, setting->data.mux.group); +#ifndef OPLUS_FEATURE_CHG_BASIC dev_warn(pctldev->dev, "not freeing pin %d (%s) as part of " "deactivating group %s - it is already " "used for some other setting", pins[i], desc->name, gname); +#else + if (printk_ratelimit()) { + dev_warn(pctldev->dev, + "not freeing pin %d (%s) as part of " + "deactivating group %s - it is already " + "used for some other setting", + pins[i], desc->name, gname); + } +#endif } } } diff --git a/drivers/pinctrl/qcom/pinctrl-lagoon.c b/drivers/pinctrl/qcom/pinctrl-lagoon.c index dcf3d2609fe4..81f24f0c7497 100644 --- a/drivers/pinctrl/qcom/pinctrl-lagoon.c +++ b/drivers/pinctrl/qcom/pinctrl-lagoon.c @@ -1616,9 +1616,15 @@ static const struct msm_pingroup lagoon_groups[] = { [163] = UFS_RESET(ufs_reset, 0xae000), }; +#ifdef OPLUS_FEATURE_CHG_BASIC +static const int lagoon_reserved_gpios[] = { + 13, 14, 15, 16, 56, 57, -1 +}; +#else static const int lagoon_reserved_gpios[] = { 13, 14, 15, 16, 45, 46, 56, 57, -1 }; +#endif static struct msm_dir_conn lagoon_dir_conn[] = { {-1, 0}, {-1, 0}, {-1, 0}, {-1, 0}, {-1, 0}, diff --git a/drivers/pinctrl/qcom/pinctrl-msm.c b/drivers/pinctrl/qcom/pinctrl-msm.c index f8ce0eac1ae8..e7b2629e192b 100644 --- a/drivers/pinctrl/qcom/pinctrl-msm.c +++ b/drivers/pinctrl/qcom/pinctrl-msm.c @@ -486,6 +486,20 @@ static int msm_gpio_get(struct gpio_chip *chip, unsigned offset) val = readl(pctrl->regs + g->io_reg); return !!(val & BIT(g->in_bit)); } +#ifdef OPLUS_FEATURE_CHG_BASIC +static int msm_gpio_get_oplus_vooc(struct gpio_chip *chip, unsigned offset) +{ + const struct msm_pingroup *g; + struct msm_pinctrl *pctrl = gpiochip_get_data(chip); + u32 val; + + //pr_err("%s enter\n", __func__); + g = &pctrl->soc->groups[offset]; + + val = readl_oplus_vooc(pctrl->regs + g->io_reg); + return !!(val & BIT(g->in_bit)); +} +#endif /* OPLUS_FEATURE_CHG_BASIC */ static void msm_gpio_set(struct gpio_chip *chip, unsigned offset, int value) { @@ -507,7 +521,28 @@ static void msm_gpio_set(struct gpio_chip *chip, unsigned offset, int value) raw_spin_unlock_irqrestore(&pctrl->lock, flags); } +#ifdef OPLUS_FEATURE_CHG_BASIC +static void msm_gpio_set_oplus_vooc(struct gpio_chip *chip, unsigned offset, int value) +{ + const struct msm_pingroup *g; + struct msm_pinctrl *pctrl = gpiochip_get_data(chip); + u32 val; + //pr_err("%s enter\n", __func__); + g = &pctrl->soc->groups[offset]; + + //spin_lock_irqsave(&pctrl->lock, flags); + + val = readl_oplus_vooc(pctrl->regs + g->io_reg); + if (value) + val |= BIT(g->out_bit); + else + val &= ~BIT(g->out_bit); + writel_oplus_vooc(val, pctrl->regs + g->io_reg); + + //spin_unlock_irqrestore(&pctrl->lock, flags); +} +#endif /* OPLUS_FEATURE_CHG_BASIC */ #ifdef CONFIG_DEBUG_FS #include @@ -527,16 +562,16 @@ static void msm_gpio_dbg_show_one(struct seq_file *s, u32 ctl_reg, io_reg; static const char * const pulls_keeper[] = { - "no pull", - "pull down", + "no-pull", + "pull-down", "keeper", - "pull up" + "pull-up" }; static const char * const pulls_no_keeper[] = { - "no pull", - "pull down", - "pull up", + "no-pull", + "pull-down", + "pull-up", }; if (!gpiochip_line_is_valid(chip, offset)) @@ -571,8 +606,18 @@ static void msm_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) unsigned gpio = chip->base; unsigned i; - for (i = 0; i < chip->ngpio; i++, gpio++) + for (i = 0; i < chip->ngpio; i++, gpio++) { + if (i == 28 || + i == 29 || + i == 30 || + i == 31 || + i == 40 || + i == 41 || + i == 42 || + i == 43) + continue; msm_gpio_dbg_show_one(s, NULL, chip, i, gpio); + } } #else @@ -584,7 +629,13 @@ static const struct gpio_chip msm_gpio_template = { .direction_output = msm_gpio_direction_output, .get_direction = msm_gpio_get_direction, .get = msm_gpio_get, +#ifdef OPLUS_FEATURE_CHG_BASIC + .get_oplus_vooc = msm_gpio_get_oplus_vooc, +#endif /* OPLUS_FEATURE_CHG_BASIC */ .set = msm_gpio_set, +#ifdef OPLUS_FEATURE_CHG_BASIC + .set_oplus_vooc = msm_gpio_set_oplus_vooc, +#endif /* OPLUS_FEATURE_CHG_BASIC */ .request = gpiochip_generic_request, .free = gpiochip_generic_free, .dbg_show = msm_gpio_dbg_show, diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c b/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c index bb96cfb6be6a..7c8762e25721 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c @@ -1252,6 +1252,7 @@ static ssize_t ipa3_read_stats(struct file *file, char __user *ubuf, "flow_disable=%u\n" "rx_page_drop_cnt=%u\n" "zero_len_frag_pkt_cnt=%u\n", + "lower_order=%u\n", ipa3_ctx->stats.tx_sw_pkts, ipa3_ctx->stats.tx_hw_pkts, ipa3_ctx->stats.tx_non_linear, @@ -1269,7 +1270,9 @@ static ssize_t ipa3_read_stats(struct file *file, char __user *ubuf, ipa3_ctx->stats.flow_enable, ipa3_ctx->stats.flow_disable, ipa3_ctx->stats.rx_page_drop_cnt, - ipa3_ctx->stats.zero_len_frag_pkt_cnt); + ipa3_ctx->stats.zero_len_frag_pkt_cnt, + ipa3_ctx->stats.lower_order + ); cnt += nbytes; for (i = 0; i < IPAHAL_PKT_STATUS_EXCEPTION_MAX; i++) { diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c index 1c0333a74f65..4cacbc1653eb 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c @@ -1922,6 +1922,38 @@ fail_kmem_cache_alloc: goto begin; } } +static struct page *ipa3_alloc_page( + gfp_t flag, u32 *page_order, bool try_lower, bool is_tmp_alloc) +{ + struct page *page = NULL; + u32 p_order = *page_order; + + /* For temporary allocations, avoid triggering OOM Killer. */ + if (is_tmp_alloc) { + flag |= __GFP_RETRY_MAYFAIL | __GFP_NOWARN; + } + + page = __dev_alloc_pages(flag, p_order); + /* We will only try 1 page order lower. */ + if (unlikely(!page)) { + if (try_lower && p_order > 0) { + p_order = p_order - 1; + + // #ifdef OPLUS_BUG_DEBUG + if (p_order < IPA_WAN_PAGE_ORDER) { + flag &= ~(__GFP_RETRY_MAYFAIL | __GFP_NOWARN); + } + //pr_err_ratelimited("ipa3_alloc_page: trying lower order, order=%d, flag=%0x\n", p_order, flag); + // #endif + + page = __dev_alloc_pages(flag, p_order); + if (likely(page)) + ipa3_ctx->stats.lower_order++; + } + } + *page_order = p_order; + return page; +} static struct ipa3_rx_pkt_wrapper *ipa3_alloc_rx_pkt_page( gfp_t flag, bool is_tmp_alloc) @@ -1933,12 +1965,17 @@ static struct ipa3_rx_pkt_wrapper *ipa3_alloc_rx_pkt_page( flag); if (unlikely(!rx_pkt)) return NULL; - rx_pkt->len = PAGE_SIZE << IPA_WAN_PAGE_ORDER; - rx_pkt->page_data.page = __dev_alloc_pages(flag, - IPA_WAN_PAGE_ORDER); + rx_pkt->page_data.page_order = IPA_WAN_PAGE_ORDER; + + /* Try a lower order page for order 3 pages in case allocation fails. */ + rx_pkt->page_data.page = ipa3_alloc_page(flag, + &rx_pkt->page_data.page_order, + (is_tmp_alloc && rx_pkt->page_data.page_order == IPA_WAN_PAGE_ORDER), is_tmp_alloc); if (unlikely(!rx_pkt->page_data.page)) goto fail_page_alloc; + rx_pkt->len = PAGE_SIZE << rx_pkt->page_data.page_order; + rx_pkt->page_data.dma_addr = dma_map_page(ipa3_ctx->pdev, rx_pkt->page_data.page, 0, rx_pkt->len, DMA_FROM_DEVICE); @@ -1956,7 +1993,7 @@ static struct ipa3_rx_pkt_wrapper *ipa3_alloc_rx_pkt_page( return rx_pkt; fail_dma_mapping: - __free_pages(rx_pkt->page_data.page, IPA_WAN_PAGE_ORDER); + __free_pages(rx_pkt->page_data.page, rx_pkt->page_data.page_order); fail_page_alloc: kmem_cache_free(ipa3_ctx->rx_pkt_wrapper_cache, rx_pkt); return NULL; @@ -2643,8 +2680,7 @@ static void free_rx_page(void *chan_user_data, void *xfer_user_data) } dma_unmap_page(ipa3_ctx->pdev, rx_pkt->page_data.dma_addr, rx_pkt->len, DMA_FROM_DEVICE); - __free_pages(rx_pkt->page_data.page, - IPA_WAN_PAGE_ORDER); + __free_pages(rx_pkt->page_data.page, rx_pkt->page_data.page_order); kmem_cache_free(ipa3_ctx->rx_pkt_wrapper_cache, rx_pkt); } @@ -2695,8 +2731,7 @@ static void ipa3_cleanup_rx(struct ipa3_sys_context *sys) rx_pkt->page_data.dma_addr, rx_pkt->len, DMA_FROM_DEVICE); - __free_pages(rx_pkt->page_data.page, - IPA_WAN_PAGE_ORDER); + __free_pages(rx_pkt->page_data.page, rx_pkt->page_data.page_order); } kmem_cache_free(ipa3_ctx->rx_pkt_wrapper_cache, rx_pkt); @@ -2716,7 +2751,7 @@ static void ipa3_cleanup_rx(struct ipa3_sys_context *sys) rx_pkt->len, DMA_FROM_DEVICE); __free_pages(rx_pkt->page_data.page, - IPA_WAN_PAGE_ORDER); + rx_pkt->page_data.page_order); kmem_cache_free( ipa3_ctx->rx_pkt_wrapper_cache, rx_pkt); @@ -3488,8 +3523,7 @@ static struct sk_buff *handle_page_completion(struct gsi_chan_xfer_notify } else { dma_unmap_page(ipa3_ctx->pdev, rx_page.dma_addr, rx_pkt->len, DMA_FROM_DEVICE); - __free_pages(rx_pkt->page_data.page, - IPA_WAN_PAGE_ORDER); + __free_pages(rx_pkt->page_data.page, rx_pkt->page_data.page_order); } rx_pkt->sys->free_rx_wrapper(rx_pkt); IPA_STATS_INC_CNT(ipa3_ctx->stats.rx_page_drop_cnt); @@ -3516,8 +3550,7 @@ static struct sk_buff *handle_page_completion(struct gsi_chan_xfer_notify dma_unmap_page(ipa3_ctx->pdev, rx_page.dma_addr, rx_pkt->len, DMA_FROM_DEVICE); - __free_pages(rx_pkt->page_data.page, - IPA_WAN_PAGE_ORDER); + __free_pages(rx_pkt->page_data.page, rx_pkt->page_data.page_order); } rx_pkt->sys->free_rx_wrapper(rx_pkt); } @@ -3542,7 +3575,7 @@ static struct sk_buff *handle_page_completion(struct gsi_chan_xfer_notify skb_shinfo(rx_skb)->nr_frags, rx_page.page, 0, notify->bytes_xfered, - PAGE_SIZE << IPA_WAN_PAGE_ORDER); + PAGE_SIZE << rx_page.page_order); } } else { return NULL; diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h index 162af354b2dd..1628eae14278 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h @@ -1382,6 +1382,7 @@ struct ipa3_stats { u32 tx_non_linear; u32 rx_page_drop_cnt; u32 zero_len_frag_pkt_cnt; + u64 lower_order; struct ipa3_page_recycle_stats page_recycle_stats[2]; }; diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig index 63454b5cac27..504e58a28dbc 100644 --- a/drivers/power/Kconfig +++ b/drivers/power/Kconfig @@ -1,3 +1,91 @@ source "drivers/power/avs/Kconfig" source "drivers/power/reset/Kconfig" source "drivers/power/supply/Kconfig" + +#ifdef OPLUS_FEATURE_CHG_BASIC +config OPLUS_SM8250_CHARGER + tristate "OPLUS SM8150 charger driver" + depends on MFD_SPMI_PMIC + help + Enables support for the oplus charging framework + +config OPLUS_SM7250R_CHARGER + tristate "OPLUS SM7250R charger driver" + depends on MFD_SPMI_PMIC + help + Enables support for the oplus charging framework + +config OPLUS_CHARGER_OPTIGA + bool "OPLUS OPTIGA soc node" + help + Say Y to include support + +config OPLUS_SHORT_C_BATT_CHECK + tristate "OPLUS_SHORT_C_BATT CHECK SUPPORT" + default n + depends on MFD_SPMI_PMIC + help + Say Y to include support + +config OPLUS_CALL_MODE_SUPPORT + bool "OPLUS call mode support" + help + Say Y to include support + +config OPLUS_SMART_CHARGER_SUPPORT + bool "OPLUS smart charger support" + help + Say Y to include support + +config OPLUS_SHORT_HW_CHECK + tristate "OPLUS_SHORT_HW CHECK SUPPORT" + default n + depends on MFD_SPMI_PMIC + help + Say Y to include support + +config OPLUS_CHIP_SOC_NODE + bool "OPLUS chip soc node" + help + Say Y to include support + + +config OPLUS_SHORT_IC_CHECK + tristate "OPLUS_SHORT_IC CHECK SUPPORT" + default n + depends on MFD_SPMI_PMIC + help + Say Y to include support + +config OPLUS_SHORT_USERSPACE + bool "OPLUS batt userspace" + help + Say Y to include support + +config OPLUS_RTC_DET_SUPPORT + tristate "OPLUS RTC DET SUPPORT" + default n + depends on MFD_SPMI_PMIC + help + Say Y to include support + +config OPLUS_CHECK_CHARGERID_VOLT + tristate "OPLUS CHECK CHARGERID VOLT" + default n + depends on MFD_SPMI_PMIC + help + Say Y to include support + +config OPLUS_SHIP_MODE_SUPPORT + tristate "OPLUS_SHIP_MODE_SUPPORT" + default n + depends on MFD_SPMI_PMIC + help + Say Y to include support +config OPLUS_CHARGER_WIRELESS_PEN + bool "OPLUS charger wireless pen" + help + Say Y to include support + +source "drivers/power/oplus/Kconfig" +#endif diff --git a/drivers/power/Makefile b/drivers/power/Makefile index ff35c712d824..f08750e68d22 100644 --- a/drivers/power/Makefile +++ b/drivers/power/Makefile @@ -1,3 +1,7 @@ obj-$(CONFIG_POWER_AVS) += avs/ obj-$(CONFIG_POWER_RESET) += reset/ obj-$(CONFIG_POWER_SUPPLY) += supply/ +#ifdef OPLUS_FEATURE_CHG_BASIC +obj-$(CONFIG_OPLUS_SM7250R_CHARGER) += oplus/ +obj-$(CONFIG_OPLUS_SM8250_CHARGER) += oplus/ +#endif diff --git a/drivers/power/oplus b/drivers/power/oplus new file mode 120000 index 000000000000..cc5b7bf59f7c --- /dev/null +++ b/drivers/power/oplus @@ -0,0 +1 @@ +../../../../vendor/oplus/kernel/charger/ \ No newline at end of file diff --git a/drivers/power/reset/msm-poweroff.c b/drivers/power/reset/msm-poweroff.c index c1b0799963e6..c974ab613f73 100644 --- a/drivers/power/reset/msm-poweroff.c +++ b/drivers/power/reset/msm-poweroff.c @@ -27,6 +27,15 @@ #include #include +#ifdef CONFIG_OPLUS_FEATURE_QCOM_MINIDUMP_ENHANCE +#include +#include +#endif + +#ifdef CONFIG_OPLUS_FEATURE_MISC +#include +#endif + #define EMERGENCY_DLOAD_MAGIC1 0x322A4F99 #define EMERGENCY_DLOAD_MAGIC2 0xC67E4350 #define EMERGENCY_DLOAD_MAGIC3 0x77777777 @@ -66,7 +75,13 @@ static int download_mode = 1; static struct kobject dload_kobj; static int in_panic; + +#ifndef CONFIG_OPLUS_FEATURE_QCOM_MINIDUMP_ENHANCE static int dload_type = SCM_DLOAD_FULLDUMP; +#else +int dload_type = SCM_DLOAD_FULLDUMP; +#endif + static void *dload_mode_addr; static bool dload_mode_enabled; static void *emergency_dload_mode_addr; @@ -74,6 +89,14 @@ static bool scm_dload_supported; static bool force_warm_reboot; +bool oem_is_fulldump(void) +{ + return download_mode && (dload_type & SCM_DLOAD_FULLDUMP); +} +#ifdef OPLUS_ARCH_EXTENDS +EXPORT_SYMBOL(oem_is_fulldump); +#endif /* OPLUS_ARCH_EXTENDS */ + /* interface for exporting attributes */ struct reset_attribute { struct attribute attr; @@ -162,6 +185,43 @@ int scm_set_dload_mode(int arg1, int arg2) &desc); } +#ifdef OPLUS_BUG_STABILITY +bool is_fulldump_enable(void) +{ + return download_mode && (dload_type & SCM_DLOAD_FULLDUMP); +} + +void oplus_switch_fulldump(int on) +{ + int ret; + + if (dload_mode_addr) { + __raw_writel(0xE47B337D, dload_mode_addr); + __raw_writel(0xCE14091A, + dload_mode_addr + sizeof(unsigned int)); + mb(); + } + if(on){ + ret = scm_set_dload_mode(SCM_DLOAD_FULLDUMP, 0); + if (ret) + pr_err("Failed to set secure DLOAD mode: %d\n", ret); + dload_type = SCM_DLOAD_FULLDUMP; + }else{ + ret = scm_set_dload_mode(SCM_DLOAD_MINIDUMP, 0); + if (ret) + pr_err("Failed to set secure DLOAD mode: %d\n", ret); + dload_type = SCM_DLOAD_MINIDUMP; + } + + if(dload_type == SCM_DLOAD_MINIDUMP) + __raw_writel(EMMC_DLOAD_TYPE, dload_type_addr); + else + __raw_writel(0, dload_type_addr); + dload_mode_enabled = on; +} +EXPORT_SYMBOL(oplus_switch_fulldump); +#endif /* OPLUS_BUG_STABILITY */ + static void set_dload_mode(int on) { int ret; @@ -178,6 +238,13 @@ static void set_dload_mode(int on) if (ret) pr_err("Failed to set secure DLOAD mode: %d\n", ret); +#ifdef CONFIG_OPLUS_FEATURE_QCOM_MINIDUMP_ENHANCE + if(dload_type == SCM_DLOAD_MINIDUMP) + __raw_writel(EMMC_DLOAD_TYPE, dload_type_addr); + else + __raw_writel(0, dload_type_addr); +#endif /* CONFIG_OPLUS_FEATURE_QCOM_MINIDUMP_ENHANCE */ + dload_mode_enabled = on; } @@ -485,7 +552,26 @@ static void msm_restart_prepare(const char *cmd) need_warm_reset = (get_dload_mode() || (cmd != NULL && cmd[0] != '\0')); } +#ifdef OPLUS_BUG_STABILITY + if (in_panic){ + //warm reset + qpnp_pon_system_pwr_off(PON_POWER_OFF_WARM_RESET); + qpnp_pon_set_restart_reason( + PON_RESTART_REASON_KERNEL); +#ifdef CONFIG_OPLUS_FEATURE_QCOM_MINIDUMP_ENHANCE + if (get_eng_version() == AGING || get_eng_version() == FACTORY) { + oplus_switch_fulldump(1); + } +#endif + flush_cache_all(); + /*outer_flush_all is not supported by 64bit kernel*/ +#ifndef CONFIG_ARM64 + outer_flush_all(); +#endif + return; + } +#endif /* OPLUS_BUG_STABILITY */ if (force_warm_reboot) pr_info("Forcing a warm reset of the system\n"); @@ -520,6 +606,22 @@ static void msm_restart_prepare(const char *cmd) qpnp_pon_set_restart_reason( PON_RESTART_REASON_KEYS_CLEAR); __raw_writel(0x7766550a, restart_reason); + #ifdef OPLUS_FEATURE_AGINGTEST + } else if(!strcmp(cmd, "sbllowmemtest")){ + qpnp_pon_set_restart_reason( + PON_RESTART_REASON_SBL_DDR_CUS); + __raw_writel(0x7766550b, restart_reason); + }else if (!strcmp(cmd, "sblmemtest")){//factory aging test + printk("[%s:%d] lunch ddr test!!\n", current->comm, current->pid); + qpnp_pon_set_restart_reason( + PON_RESTART_REASON_SBL_DDRTEST); + __raw_writel(0x7766550b, restart_reason); + } else if(!strcmp(cmd, "usermemaging")){ + printk("[%s:%d] lunch user memory test!!\n", current->comm, current->pid); + qpnp_pon_set_restart_reason( + PON_RESTART_REASON_MEM_AGING); + __raw_writel(0x7766550b, restart_reason); + #endif } else if (!strncmp(cmd, "oem-", 4)) { unsigned long code; int ret; @@ -530,10 +632,57 @@ static void msm_restart_prepare(const char *cmd) restart_reason); } else if (!strncmp(cmd, "edl", 3)) { enable_emergency_dload_mode(); - } else { + } + #ifdef OPLUS_BUG_STABILITY + else if (!strncmp(cmd, "rf", 2)) { + qpnp_pon_set_restart_reason( + PON_RESTART_REASON_RF); + } else if (!strncmp(cmd, "wlan",4)) { + qpnp_pon_set_restart_reason( + PON_RESTART_REASON_WLAN); + #ifdef USE_MOS_MODE + } else if (!strncmp(cmd, "mos", 3)) { + qpnp_pon_set_restart_reason( + PON_RESTART_REASON_MOS); + #endif + } else if (!strncmp(cmd, "ftm", 3)) { + qpnp_pon_set_restart_reason( + PON_RESTART_REASON_FACTORY); + } else if (!strncmp(cmd, "kernel", 6)) { + qpnp_pon_set_restart_reason( + PON_RESTART_REASON_KERNEL); + } else if (!strncmp(cmd, "modem", 5)) { + qpnp_pon_set_restart_reason( + PON_RESTART_REASON_MODEM); + } else if (!strncmp(cmd, "android", 7)) { + qpnp_pon_set_restart_reason( + PON_RESTART_REASON_ANDROID); + } else if (!strncmp(cmd, "silence", 7)) { + qpnp_pon_set_restart_reason( + PON_RESTART_REASON_SILENCE); + } else if (!strncmp(cmd, "sau", 3)) { + qpnp_pon_set_restart_reason( + PON_RESTART_REASON_SAU); + } else if (!strncmp(cmd, "safe", 4)) { + qpnp_pon_set_restart_reason( + PON_RESTART_REASON_SAFE); + } else if (!strncmp(cmd, "novib", 5)) { + qpnp_pon_set_restart_reason( + PON_RESTART_REASON_REBOOT_NO_VIBRATION); + } + #endif + else { + qpnp_pon_set_restart_reason( + PON_RESTART_REASON_NORMAL); __raw_writel(0x77665501, restart_reason); } } + #ifdef OPLUS_BUG_STABILITY + else { + qpnp_pon_set_restart_reason( + PON_RESTART_REASON_NORMAL); + } + #endif flush_cache_all(); @@ -610,6 +759,13 @@ static int msm_restart_probe(struct platform_device *pdev) struct device_node *np; int ret = 0; +#ifdef CONFIG_OPLUS_FEATURE_QCOM_MINIDUMP_ENHANCE + if (oplus_daily_build() == true || get_eng_version() == AGING || get_eng_version() == FACTORY) + dload_type = SCM_DLOAD_FULLDUMP; + else + dload_type = SCM_DLOAD_MINIDUMP; +#endif + setup_dload_mode_support(); np = of_find_compatible_node(NULL, NULL, diff --git a/drivers/power/supply/power_supply_sysfs.c b/drivers/power/supply/power_supply_sysfs.c index a8ad7464e251..947cc1b26a52 100644 --- a/drivers/power/supply/power_supply_sysfs.c +++ b/drivers/power/supply/power_supply_sysfs.c @@ -46,7 +46,7 @@ static const char * const power_supply_type_text[] = { "USB_PD", "USB_PD_DRP", "BrickID", "USB_HVDCP", "USB_HVDCP_3", "USB_HVDCP_3P5", "Wireless", "USB_FLOAT", "BMS", "Parallel", "Main", "USB_C_UFP", "USB_C_DFP", - "Charge_Pump", + "Charge_Pump","DASH","BPP", "EPP", "FAST" }; static const char * const power_supply_usb_type_text[] = { @@ -181,6 +181,9 @@ static ssize_t power_supply_show_property(struct device *dev, break; case POWER_SUPPLY_PROP_TYPE: case POWER_SUPPLY_PROP_REAL_TYPE: +#ifdef OPLUS_CUSTOM_OP_DEF + case POWER_SUPPLY_PROP_WIRELESS_TYPE: +#endif ret = sprintf(buf, "%s\n", power_supply_type_text[value.intval]); break; @@ -214,6 +217,9 @@ static ssize_t power_supply_show_property(struct device *dev, case POWER_SUPPLY_PROP_CHARGE_COUNTER_EXT: ret = sprintf(buf, "%lld\n", value.int64val); break; +#ifdef OPLUS_CUSTOM_OP_DEF + case POWER_SUPPLY_PROP_WIRELESS_MODE: +#endif case POWER_SUPPLY_PROP_MODEL_NAME ... POWER_SUPPLY_PROP_SERIAL_NUMBER: ret = sprintf(buf, "%s\n", value.strval); break; @@ -281,6 +287,30 @@ static ssize_t power_supply_store_property(struct device *dev, /* Must be in the same order as POWER_SUPPLY_PROP_* */ static struct device_attribute power_supply_attrs[] = { /* Properties of type `int' */ +#ifdef OPLUS_FEATURE_CHG_BASIC + POWER_SUPPLY_ATTR(charge_technology), + POWER_SUPPLY_ATTR(fastcharger), + POWER_SUPPLY_ATTR(mmi_charging_enable), + POWER_SUPPLY_ATTR(otg_switch), + POWER_SUPPLY_ATTR(otg_online), + POWER_SUPPLY_ATTR(fast_chg_type), + POWER_SUPPLY_ATTR(batt_fcc), + POWER_SUPPLY_ATTR(batt_soh), + POWER_SUPPLY_ATTR(batt_cc), + POWER_SUPPLY_ATTR(batt_rm), + POWER_SUPPLY_ATTR(batt_soc), + POWER_SUPPLY_ATTR(authenticate), + POWER_SUPPLY_ATTR(charge_timeout), + POWER_SUPPLY_ATTR(notify_code), + POWER_SUPPLY_ATTR(cool_down), + POWER_SUPPLY_ATTR(usb_status), + POWER_SUPPLY_ATTR(em_mode), + POWER_SUPPLY_ATTR(sub_current), + POWER_SUPPLY_ATTR(usbtemp_volt_l), + POWER_SUPPLY_ATTR(usbtemp_volt_r), + POWER_SUPPLY_ATTR(battery_info), + POWER_SUPPLY_ATTR(battery_info_id), +#endif /* OPLUS_FEATURE_CHG_BASIC */ POWER_SUPPLY_ATTR(status), POWER_SUPPLY_ATTR(charge_type), POWER_SUPPLY_ATTR(health), @@ -374,6 +404,7 @@ static struct device_attribute power_supply_attrs[] = { POWER_SUPPLY_ATTR(temp_cold), POWER_SUPPLY_ATTR(temp_hot), POWER_SUPPLY_ATTR(system_temp_level), + POWER_SUPPLY_ATTR(op_disable_charge), POWER_SUPPLY_ATTR(resistance), POWER_SUPPLY_ATTR(resistance_capacitive), POWER_SUPPLY_ATTR(resistance_id), @@ -486,12 +517,58 @@ static struct device_attribute power_supply_attrs[] = { POWER_SUPPLY_ATTR(charger_status), /* Local extensions of type int64_t */ POWER_SUPPLY_ATTR(charge_counter_ext), +#ifdef OPLUS_FEATURE_CHG_BASIC + POWER_SUPPLY_ATTR(adapter_fw_update), + POWER_SUPPLY_ATTR(voocchg_ing), + POWER_SUPPLY_ATTR(chargerid_volt), + POWER_SUPPLY_ATTR(ship_mode), + POWER_SUPPLY_ATTR(call_mode), +#ifdef CONFIG_OPLUS_CHIP_SOC_NODE + POWER_SUPPLY_ATTR(chip_soc), +#endif +#ifdef CONFIG_OPLUS_SMOOTH_SOC + POWER_SUPPLY_ATTR(smooth_soc), + POWER_SUPPLY_ATTR(smooth_switch), +#endif + +#ifdef CONFIG_OPLUS_SHORT_USERSPACE + POWER_SUPPLY_ATTR(short_c_batt_limit_chg), + POWER_SUPPLY_ATTR(short_c_batt_limit_rechg), +#else + POWER_SUPPLY_ATTR(short_c_batt_update_change), + POWER_SUPPLY_ATTR(short_c_batt_in_idle), + POWER_SUPPLY_ATTR(short_c_batt_cv_status), +#endif /*CONFIG_OPLUS_SHORT_USERSPACE*/ +#ifdef CONFIG_OPLUS_SHORT_HW_CHECK + POWER_SUPPLY_ATTR(short_c_hw_feature), + POWER_SUPPLY_ATTR(short_c_hw_status), +#endif +#ifdef CONFIG_OPLUS_SHORT_IC_CHECK + POWER_SUPPLY_ATTR(short_ic_otp_status), + POWER_SUPPLY_ATTR(short_ic_volt_thresh), + POWER_SUPPLY_ATTR(short_ic_otp_value), +#endif + POWER_SUPPLY_ATTR(cp_disable_cur_sens), +// add by huangtongfeng for wireless file + POWER_SUPPLY_ATTR(tx_voltage_now), + POWER_SUPPLY_ATTR(tx_current_now), + POWER_SUPPLY_ATTR(cp_voltage_now), + POWER_SUPPLY_ATTR(cp_current_now), + POWER_SUPPLY_ATTR(wireless_mode), + POWER_SUPPLY_ATTR(wireless_type), + POWER_SUPPLY_ATTR(cep_info), +// wireless file end +#endif /*OPLUS_FEATURE_CHG_BASIC*/ /* Properties of type `const char *' */ POWER_SUPPLY_ATTR(model_name), POWER_SUPPLY_ATTR(manufacturer), POWER_SUPPLY_ATTR(battery_type), POWER_SUPPLY_ATTR(cycle_counts), POWER_SUPPLY_ATTR(serial_number), +#ifdef OPLUS_FEATURE_CHG_BASIC + POWER_SUPPLY_ATTR(parallel_current_now), + POWER_SUPPLY_ATTR(smb1355_test), +#endif }; static struct attribute * @@ -516,6 +593,11 @@ static umode_t power_supply_attr_is_visible(struct kobject *kobj, if (psy->desc->property_is_writeable && psy->desc->property_is_writeable(psy, property) > 0) mode |= S_IWUSR; +#ifdef OPLUS_FEATURE_CHG_BASIC + if (property == POWER_SUPPLY_PROP_SMB1355_TEST) + mode |= S_IWGRP; +#endif + return mode; } @@ -585,6 +667,11 @@ int power_supply_uevent(struct device *dev, struct kobj_uevent_env *env) struct device_attribute *attr; char *line; +#ifdef OPLUS_FEATURE_CHG_BASIC + if (((psy->desc->properties[j] == POWER_SUPPLY_PROP_VOLTAGE_NOW) && (psy->desc->type == POWER_SUPPLY_TYPE_USB)) + || ((psy->desc->properties[j] == POWER_SUPPLY_PROP_CHARGE_NOW) && (psy->desc->type == POWER_SUPPLY_TYPE_BATTERY))) + continue; +#endif attr = &power_supply_attrs[psy->desc->properties[j]]; ret = power_supply_show_property(dev, attr, prop_buf); diff --git a/drivers/power/supply/qcom/Kconfig b/drivers/power/supply/qcom/Kconfig index 9581455fc4d2..91b7ac897ccb 100644 --- a/drivers/power/supply/qcom/Kconfig +++ b/drivers/power/supply/qcom/Kconfig @@ -141,8 +141,8 @@ config QPNP_FG_GEN4 reported through a BMS power supply property and also sends uevents when the capacity is updated. -config QPNP_QG - bool "QPNP Qgauge driver" +config OPLUS_QPNP_QG + bool "OPLUS QPNP Qgauge driver" depends on MFD_SPMI_PMIC help Say Y here to enable the Qualcomm Technologies, Inc. QGauge driver diff --git a/drivers/power/supply/qcom/Makefile b/drivers/power/supply/qcom/Makefile index b9cc5e6b00f2..ff60609cbdd4 100644 --- a/drivers/power/supply/qcom/Makefile +++ b/drivers/power/supply/qcom/Makefile @@ -1,6 +1,15 @@ # SPDX-License-Identifier: GPL-2.0-only + + +#ifdef OPLUS_FEATURE_CHG_BASIC +obj-$(CONFIG_QPNP_SMB5) += step-chg-jeita.o battery.o pmic-voter.o storm-watch.o schgm-flash.o +#else +#obj-$(CONFIG_QPNP_SMB5) += step-chg-jeita.o battery.o qpnp-smb5.o smb5-lib.o pmic-voter.o storm-watch.o schgm-flash.o +#endif + obj-$(CONFIG_SMB1360_CHARGER_FG) += smb1360-charger-fg.o -obj-$(CONFIG_QPNP_SMB5) += step-chg-jeita.o battery.o qpnp-smb5.o smb5-lib.o pmic-voter.o storm-watch.o schgm-flash.o +#obj-$(CONFIG_QPNP_SMB5) += step-chg-jeita.o battery.o qpnp-smb5.o smb5-lib.o pmic-voter.o storm-watch.o schgm-flash.o + obj-$(CONFIG_SMB1390_CHARGE_PUMP_PSY) += smb1390-charger-psy.o pmic-voter.o obj-$(CONFIG_SMB1355_SLAVE_CHARGER) += smb1355-charger.o pmic-voter.o obj-$(CONFIG_SMB1351_USB_CHARGER) += smb1351-charger.o pmic-voter.o battery.o @@ -9,7 +18,10 @@ obj-$(CONFIG_SMB138X_CHARGER) += step-chg-jeita.o smb138x-charger.o smb-lib.o p obj-$(CONFIG_QPNP_FG_GEN3) += qpnp-fg-gen3.o fg-memif.o fg-util.o obj-$(CONFIG_QPNP_QNOVO5) += qpnp-qnovo5.o battery.o pmic-voter.o obj-$(CONFIG_QPNP_FG_GEN4) += qpnp-fg-gen4.o fg-memif.o fg-util.o fg-alg.o pmic-voter.o -obj-$(CONFIG_QPNP_QG) += qpnp-qg.o pmic-voter.o qg-util.o qg-soc.o qg-sdam.o qg-battery-profile.o qg-profile-lib.o fg-alg.o +#ifdef OPLUS_FEATURE_CHG_BASIC +obj-$(CONFIG_OPLUS_QPNP_QG) += oplus_qpnp_qg.o pmic-voter.o qg-soc.o qg-sdam.o qg-battery-profile.o qg-profile-lib.o fg-alg.o +#obj-$(CONFIG_QPNP_QG) += qpnp-qg.o pmic-voter.o qg-util.o qg-soc.o qg-sdam.o qg-battery-profile.o qg-profile-lib.o fg-alg.o +#endif obj-$(CONFIG_HL6111R) += hl6111r.o obj-$(CONFIG_SMB1398_CHARGER) += smb1398-charger.o pmic-voter.o obj-$(CONFIG_QPNP_SMBLITE) += step-chg-jeita.o battery.o qpnp-smblite.o smblite-lib.o pmic-voter.o storm-watch.o schgm-flashlite.o diff --git a/drivers/power/supply/qcom/oplus_qpnp_qg.c b/drivers/power/supply/qcom/oplus_qpnp_qg.c new file mode 100644 index 000000000000..9ec495dc24bd --- /dev/null +++ b/drivers/power/supply/qcom/oplus_qpnp_qg.c @@ -0,0 +1,6029 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2018-2020 The Linux Foundation. All rights reserved. + */ + +#define pr_fmt(fmt) "QG-K: %s: " fmt, __func__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "fg-alg.h" +#include "qg-sdam.h" +#include "qg-core.h" +#include "qg-reg.h" +//#include "qg-util.h" +#include "qg-soc.h" +#include "qg-battery-profile.h" +#include "qg-defs.h" +#ifdef OPLUS_FEATURE_CHG_BASIC +#include +#include "../../oplus/oplus_gauge.h" +#include +#include +//#include +#include "../../oplus/oplus_charger.h" +#endif + +#ifdef OPLUS_FEATURE_CHG_BASIC +#include +#endif + + + +#ifdef OPLUS_FEATURE_CHG_BASIC +static struct qpnp_qg *qpnp_gauge_ic = NULL; +#endif + +#ifdef OPLUS_FEATURE_CHG_BASIC +static bool is_batt_id_valid(struct qpnp_qg *chip); +#endif + + +static int qg_debug_mask; + +static int qg_esr_mod_count = 30; +static ssize_t esr_mod_count_show(struct device *dev, struct device_attribute + *attr, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%d\n", qg_esr_mod_count); +} + +static ssize_t esr_mod_count_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int val; + + if (kstrtos32(buf, 0, &val)) + return -EINVAL; + + qg_esr_mod_count = val; + + return count; +} +static DEVICE_ATTR_RW(esr_mod_count); + +static int qg_esr_count = 3; +static ssize_t esr_count_show(struct device *dev, struct device_attribute + *attr, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%d\n", qg_esr_count); +} + +static ssize_t esr_count_store(struct device *dev, struct device_attribute + *attr, const char *buf, size_t count) +{ + int val; + + if (kstrtos32(buf, 0, &val)) + return -EINVAL; + + qg_esr_count = val; + + return count; +} + +#ifdef OPLUS_FEATURE_CHG_BASIC +static inline bool is_sticky_register(u32 addr) +{ + if ((addr & 0xFF) == QG_STATUS2_REG) + return true; + + return false; +} + +int qg_read(struct qpnp_qg *chip, u32 addr, u8 *val, int len) +{ + int rc, i; + u32 dummy = 0; + + rc = regmap_bulk_read(chip->regmap, addr, val, len); + if (rc < 0) { + pr_err("Failed regmap_read for address %04x rc=%d\n", addr, rc); + return rc; + } + + if (is_sticky_register(addr)) { + /* write to the sticky register to clear it */ + rc = regmap_write(chip->regmap, addr, dummy); + if (rc < 0) { + pr_err("Failed regmap_write for %04x rc=%d\n", + addr, rc); + return rc; + } + } + + if (*chip->debug_mask & QG_DEBUG_BUS_READ) { + pr_info("length %d addr=%04x\n", len, addr); + for (i = 0; i < len; i++) + pr_info("val[%d]: %02x\n", i, val[i]); + } + + return 0; +} + +int qg_write(struct qpnp_qg *chip, u32 addr, u8 *val, int len) +{ + int rc, i; + + mutex_lock(&chip->bus_lock); + + if (len > 1) + rc = regmap_bulk_write(chip->regmap, addr, val, len); + else + rc = regmap_write(chip->regmap, addr, *val); + + if (rc < 0) { + pr_err("Failed regmap_write for address %04x rc=%d\n", + addr, rc); + goto out; + } + + if (*chip->debug_mask & QG_DEBUG_BUS_WRITE) { + pr_info("length %d addr=%04x\n", len, addr); + for (i = 0; i < len; i++) + pr_info("val[%d]: %02x\n", i, val[i]); + } +out: + mutex_unlock(&chip->bus_lock); + return rc; +} + +int qg_masked_write(struct qpnp_qg *chip, int addr, u32 mask, u32 val) +{ + int rc; + + mutex_lock(&chip->bus_lock); + + rc = regmap_update_bits(chip->regmap, addr, mask, val); + if (rc < 0) { + pr_err("Failed regmap_update_bits for address %04x rc=%d\n", + addr, rc); + goto out; + } + + if (*chip->debug_mask & QG_DEBUG_BUS_WRITE) + pr_info("addr=%04x mask: %02x val: %02x\n", addr, mask, val); + +out: + mutex_unlock(&chip->bus_lock); + return rc; +} + +int qg_read_raw_data(struct qpnp_qg *chip, int addr, u32 *data) +{ + int rc; + u8 reg[2] = {0}; + + rc = qg_read(chip, chip->qg_base + addr, ®[0], 2); + if (rc < 0) { + pr_err("Failed to read QG addr %d rc=%d\n", addr, rc); + return rc; + } + + *data = reg[0] | (reg[1] << 8); + + return rc; +} + +s64 qg_iraw_to_ua(struct qpnp_qg *chip, int iraw) +{ + if (chip->qg_subtype == QG_ADC_IBAT_5A) + return div_s64(152588LL * (s64)iraw, 1000); + else + return div_s64(305176LL * (s64)iraw, 1000); +} + +int get_fifo_length(struct qpnp_qg *chip, u32 *fifo_length, bool rt) +{ + int rc; + u8 reg = 0; + u32 addr; + + addr = rt ? QG_STATUS3_REG : QG_S2_NORMAL_MEAS_CTL2_REG; + rc = qg_read(chip, chip->qg_base + addr, ®, 1); + if (rc < 0) { + pr_err("Failed to read FIFO length rc=%d\n", rc); + return rc; + } + + if (rt) { + *fifo_length = reg & COUNT_FIFO_RT_MASK; + } else { + *fifo_length = (reg & FIFO_LENGTH_MASK) >> FIFO_LENGTH_SHIFT; + *fifo_length += 1; + } + + return rc; +} + +int get_sample_count(struct qpnp_qg *chip, u32 *sample_count) +{ + int rc; + u8 reg = 0; + + rc = qg_read(chip, chip->qg_base + QG_S2_NORMAL_MEAS_CTL2_REG, + ®, 1); + if (rc < 0) { + pr_err("Failed to read FIFO sample count rc=%d\n", rc); + return rc; + } + + *sample_count = 1 << ((reg & NUM_OF_ACCUM_MASK) + 1); + + return rc; +} + +#define QG_CLK_RATE 32000 +#define QG_ACTUAL_CLK_RATE 32764 +int get_sample_interval(struct qpnp_qg *chip, u32 *sample_interval) +{ + int rc; + u8 reg = 0; + + rc = qg_read(chip, chip->qg_base + QG_S2_NORMAL_MEAS_CTL3_REG, + ®, 1); + if (rc < 0) { + pr_err("Failed to read FIFO sample interval rc=%d\n", rc); + return rc; + } + + *sample_interval = reg * 10; + + if (chip->wa_flags & QG_CLK_ADJUST_WA) { + *sample_interval = DIV_ROUND_CLOSEST( + *sample_interval * QG_CLK_RATE, QG_ACTUAL_CLK_RATE); + } + + return rc; +} + +int get_rtc_time(unsigned long *rtc_time) +{ + struct rtc_time tm; + struct rtc_device *rtc; + int rc; + + rtc = rtc_class_open(CONFIG_RTC_HCTOSYS_DEVICE); + if (rtc == NULL) { + pr_err("Failed to open rtc device (%s)\n", + CONFIG_RTC_HCTOSYS_DEVICE); + return -EINVAL; + } + + rc = rtc_read_time(rtc, &tm); + if (rc) { + pr_err("Failed to read rtc time (%s) : %d\n", + CONFIG_RTC_HCTOSYS_DEVICE, rc); + goto close_time; + } + + rc = rtc_valid_tm(&tm); + if (rc) { + pr_err("Invalid RTC time (%s): %d\n", + CONFIG_RTC_HCTOSYS_DEVICE, rc); + goto close_time; + } + rtc_tm_to_time(&tm, rtc_time); + +close_time: + rtc_class_close(rtc); + return rc; +} + +int get_fifo_done_time(struct qpnp_qg *chip, bool rt, int *time_ms) +{ + int rc, length = 0; + u32 sample_count = 0, sample_interval = 0, acc_count = 0; + + rc = get_fifo_length(chip, &length, rt ? true : false); + if (rc < 0) + return rc; + + rc = get_sample_count(chip, &sample_count); + if (rc < 0) + return rc; + + rc = get_sample_interval(chip, &sample_interval); + if (rc < 0) + return rc; + + *time_ms = length * sample_count * sample_interval; + + if (rt) { + rc = qg_read(chip, chip->qg_base + QG_ACCUM_CNT_RT_REG, + (u8 *)&acc_count, 1); + if (rc < 0) + return rc; + + *time_ms += ((sample_count - acc_count) * sample_interval); + } + + return 0; +} + +static bool is_usb_available(struct qpnp_qg *chip) +{ + if (chip->usb_psy) + return true; + + chip->usb_psy = power_supply_get_by_name("usb"); + if (!chip->usb_psy) + return false; + + return true; +} + +static bool is_dc_available(struct qpnp_qg *chip) +{ + if (chip->dc_psy) + return true; + + chip->dc_psy = power_supply_get_by_name("dc"); + if (!chip->dc_psy) + return false; + + return true; +} + +bool is_usb_present(struct qpnp_qg *chip) +{ + union power_supply_propval pval = {0, }; + + if (is_usb_available(chip)) + power_supply_get_property(chip->usb_psy, + POWER_SUPPLY_PROP_PRESENT, &pval); + + return pval.intval ? true : false; +} + +bool is_dc_present(struct qpnp_qg *chip) +{ + union power_supply_propval pval = {0, }; + + if (is_dc_available(chip)) + power_supply_get_property(chip->dc_psy, + POWER_SUPPLY_PROP_PRESENT, &pval); + + return pval.intval ? true : false; +} + +bool is_input_present(struct qpnp_qg *chip) +{ + return is_usb_present(chip) || is_dc_present(chip); +} + +static bool is_parallel_available(struct qpnp_qg *chip) +{ + if (chip->parallel_psy) + return true; + + chip->parallel_psy = power_supply_get_by_name("parallel"); + if (!chip->parallel_psy) + return false; + + return true; +} + +bool is_cp_available(struct qpnp_qg *chip) +{ + if (chip->cp_psy) + return true; + + chip->cp_psy = power_supply_get_by_name("charge_pump_master"); + if (!chip->cp_psy) + return false; + + return true; +} + +bool is_parallel_enabled(struct qpnp_qg *chip) +{ + union power_supply_propval pval = {0, }; + + if (is_parallel_available(chip)) { + power_supply_get_property(chip->parallel_psy, + POWER_SUPPLY_PROP_CHARGING_ENABLED, &pval); + } + + return pval.intval ? true : false; +} + +int qg_write_monotonic_soc(struct qpnp_qg *chip, int msoc) +{ + u8 reg = 0; + int rc; + + reg = (msoc * 255) / 100; + rc = qg_write(chip, chip->qg_base + QG_SOC_MONOTONIC_REG, + ®, 1); + if (rc < 0) + pr_err("Failed to update QG_SOC_MONOTINIC reg rc=%d\n", rc); + + return rc; +} +#endif + +#ifdef OPLUS_FEATURE_CHG_BASIC +int qg_get_parallel_current_now(struct qpnp_qg *chip, int *parallel_val) +{ + int rc; + if (chip->parallel_isense_chan == NULL) { + *parallel_val = 0; + pr_err("Failed to get PARALLEL_ISENSE channel\n"); + return 0; + } + rc = iio_read_channel_processed(chip->parallel_isense_chan, parallel_val); + if (rc < 0) { + pr_err("Failed reading PARALLEL_SENSE over ADC rc=%d\n", rc); + return rc; + } + pr_info("parallel_isense = %d\n", *parallel_val); + return 0; +} +#endif + +#ifdef OPLUS_FEATURE_CHG_BASIC +static int oplus_iio_channel_read(struct iio_channel *chan, int *val, int *val2, + enum iio_chan_info_enum info) +{ + int unused; + int vals[INDIO_MAX_RAW_ELEMENTS]; + int ret; + int val_len = 2; + + if (val2 == NULL) + val2 = &unused; + + if (chan->indio_dev->info->read_raw_multi) { + ret = chan->indio_dev->info->read_raw_multi(chan->indio_dev, + chan->channel, INDIO_MAX_RAW_ELEMENTS, + vals, &val_len, info); + *val = vals[0]; + *val2 = vals[1]; + } else + ret = chan->indio_dev->info->read_raw(chan->indio_dev, + chan->channel, val, val2, info); + + return ret; +} + +int oplus_iio_read_channel_processed(struct iio_channel *chan, int *val, int compen_volt) +{ + int ret; + + mutex_lock(&chan->indio_dev->info_exist_lock); + if (chan->indio_dev->info == NULL) { + ret = -ENODEV; + goto err_unlock; + } + + ret = oplus_iio_channel_read(chan, val, &compen_volt, + IIO_CHAN_INFO_OFFSET); + +err_unlock: + mutex_unlock(&chan->indio_dev->info_exist_lock); + + return ret; +} +#endif + +#ifdef OPLUS_FEATURE_CHG_BASIC +int qg_get_battery_current(struct qpnp_qg *chip, int *ibat_ua) +{ + int rc = 0, last_ibat = 0; + + if (chip->battery_missing) { + *ibat_ua = 0; + return 0; + } + + /* hold data */ + rc = qg_masked_write(chip, chip->qg_base + QG_DATA_CTL2_REG, + BURST_AVG_HOLD_FOR_READ_BIT, + BURST_AVG_HOLD_FOR_READ_BIT); + if (rc < 0) { + pr_err("Failed to hold burst-avg data rc=%d\n", rc); + goto release; + } + + rc = qg_read(chip, chip->qg_base + QG_LAST_BURST_AVG_I_DATA0_REG, + (u8 *)&last_ibat, 2); + if (rc < 0) { + pr_err("Failed to read LAST_BURST_AVG_I reg, rc=%d\n", rc); + goto release; + } + + last_ibat = sign_extend32(last_ibat, 15); + *ibat_ua = qg_iraw_to_ua(chip, last_ibat); + +release: + /* release */ + qg_masked_write(chip, chip->qg_base + QG_DATA_CTL2_REG, + BURST_AVG_HOLD_FOR_READ_BIT, 0); + return rc; +} + +int qg_get_battery_temp(struct qpnp_qg *chip, int *temp) +{ + int rc = 0; + +#ifndef OPLUS_FEATURE_CHG_BASIC + if (chip->battery_missing) { + *temp = 250; + return 0; + } +#else + int ibat = 0, compen_volt = 0; + if (chip->batt_therm_chan == NULL) { + *temp = 250; + return 0; + } + if ((chip->battery_missing) && (!is_batt_id_valid(chip))) { + *temp = -400; + return 0; + } +#endif + +#ifdef OPLUS_FEATURE_CHG_BASIC + if (chip->adc_compensation_enabled) { + qg_get_battery_current(chip, &ibat); + if (ibat < 0) {// only compensation in charge mode + compen_volt = chip->compensation_impedance * ibat / 1000; + } else { + compen_volt = 0; + } + rc = oplus_iio_read_channel_processed(chip->batt_therm_chan, temp, compen_volt); + if (rc < 0) { + pr_err("Failed reading BAT_TEMP over ADC rc = %d, compen_volt=%d\n", rc, compen_volt); + } + pr_err("batt_temp after Batt_NTC ADC compensation = %d, compen_volt=%d\n", *temp, compen_volt); + } else { + rc = iio_read_channel_processed(chip->batt_therm_chan, temp); + if (rc < 0) { + pr_err("Failed reading BAT_TEMP over ADC rc = %d\n", rc); + return rc; + } + pr_err("batt_temp = %d\n", *temp); + } +#else + rc = iio_read_channel_processed(chip->batt_therm_chan, temp); + if (rc < 0) { + pr_err("Failed reading BAT_TEMP over ADC rc=%d\n", rc); + return rc; + } + pr_err("batt_temp = %d\n", *temp); +#endif + +#ifdef OPLUS_FEATURE_CHG_BASIC +/* BSP.CHG.Basic, 2021/03/07, add Batt_NTC for small board NTC ADC */ + if (chip->oplus_small_board_temp) { + *temp /= 100; + pr_err("batt_temp = %d\n", *temp); + } +#endif + + return 0; +} + +int qg_get_battery_voltage(struct qpnp_qg *chip, int *vbat_uv) +{ + int rc = 0; + u64 last_vbat = 0; + + if (chip->battery_missing) { + *vbat_uv = 3700000; + return 0; + } + + rc = qg_read(chip, chip->qg_base + QG_LAST_ADC_V_DATA0_REG, + (u8 *)&last_vbat, 2); + if (rc < 0) { + pr_err("Failed to read LAST_ADV_V reg, rc=%d\n", rc); + return rc; + } + + *vbat_uv = V_RAW_TO_UV(last_vbat); + + return rc; +} + +int qg_get_vbat_avg(struct qpnp_qg *chip, int *vbat_uv) +{ + int rc = 0; + u64 last_vbat = 0; + + rc = qg_read(chip, chip->qg_base + QG_S2_NORMAL_AVG_V_DATA0_REG, + (u8 *)&last_vbat, 2); + if (rc < 0) { + pr_err("Failed to read S2_NORMAL_AVG_V reg, rc=%d\n", rc); + return rc; + } + + *vbat_uv = V_RAW_TO_UV(last_vbat); + + return 0; +} + +int qg_get_ibat_avg(struct qpnp_qg *chip, int *ibat_ua) +{ + int rc = 0; + int last_ibat = 0; + + rc = qg_read(chip, chip->qg_base + QG_S2_NORMAL_AVG_I_DATA0_REG, + (u8 *)&last_ibat, 2); + if (rc < 0) { + pr_err("Failed to read S2_NORMAL_AVG_I reg, rc=%d\n", rc); + return rc; + } + + last_ibat = sign_extend32(last_ibat, 15); + *ibat_ua = qg_iraw_to_ua(chip, last_ibat); + + return 0; +} +#endif + +static DEVICE_ATTR_RW(esr_count); + +static struct attribute *qg_attrs[] = { + &dev_attr_esr_mod_count.attr, + &dev_attr_esr_count.attr, + &dev_attr_soc_interval_ms.attr, + &dev_attr_soc_cold_interval_ms.attr, + &dev_attr_maint_soc_update_ms.attr, + &dev_attr_fvss_delta_soc_interval_ms.attr, + &dev_attr_fvss_vbat_scaling.attr, + &dev_attr_qg_ss_feature.attr, + NULL, +}; +ATTRIBUTE_GROUPS(qg); + +static int qg_process_rt_fifo(struct qpnp_qg *chip); +static int qg_load_battery_profile(struct qpnp_qg *chip); + +static bool is_battery_present(struct qpnp_qg *chip) +{ + bool present = true; + u8 reg = 0; + int rc; + + if (chip->qg_version == QG_LITE) { + rc = qg_read(chip, chip->qg_base + QG_STATUS2_REG, ®, 1); + if (rc < 0) + pr_err("Failed to read battery presence, rc=%d\n", rc); + else + present = !(reg & BATTERY_MISSING_BIT); + } else { + rc = qg_read(chip, chip->qg_base + QG_STATUS1_REG, ®, 1); + if (rc < 0) + pr_err("Failed to read battery presence, rc=%d\n", rc); + else + present = !!(reg & BATTERY_PRESENT_BIT); + } + + return present; +} + +#ifndef OPLUS_FEATURE_CHG_BASIC +#define DEBUG_BATT_ID_LOW 6000 +#define DEBUG_BATT_ID_HIGH 8500 +#else +#define DEBUG_BATT_ID_LOW 0 +#define DEBUG_BATT_ID_HIGH 1000 +#endif +static bool is_debug_batt_id(struct qpnp_qg *chip) +{ + if (is_between(DEBUG_BATT_ID_LOW, DEBUG_BATT_ID_HIGH, + chip->batt_id_ohm)) + return true; + + return false; +} + +static int qg_read_ocv(struct qpnp_qg *chip, u32 *ocv_uv, u32 *ocv_raw, u8 type) +{ + int rc, addr; + u64 temp = 0; + char ocv_name[20]; + + switch (type) { + case S3_GOOD_OCV: + addr = QG_S3_GOOD_OCV_V_DATA0_REG; + strlcpy(ocv_name, "S3_GOOD_OCV", 20); + break; + case S7_PON_OCV: + addr = QG_S7_PON_OCV_V_DATA0_REG; + strlcpy(ocv_name, "S7_PON_OCV", 20); + break; + case S3_LAST_OCV: + addr = QG_LAST_S3_SLEEP_V_DATA0_REG; + strlcpy(ocv_name, "S3_LAST_OCV", 20); + break; + case SDAM_PON_OCV: + addr = QG_SDAM_PON_OCV_OFFSET; + strlcpy(ocv_name, "SDAM_PON_OCV", 20); + break; + default: + pr_err("Invalid OCV type %d\n", type); + return -EINVAL; + } + + if (type == SDAM_PON_OCV) { + rc = qg_sdam_read(SDAM_PON_OCV_UV, ocv_raw); + if (rc < 0) { + pr_err("Failed to read SDAM PON OCV rc=%d\n", rc); + return rc; + } + } else { + rc = qg_read(chip, chip->qg_base + addr, (u8 *)ocv_raw, 2); + if (rc < 0) { + pr_err("Failed to read ocv, rc=%d\n", rc); + return rc; + } + } + + temp = *ocv_raw; + *ocv_uv = V_RAW_TO_UV(temp); + + pr_debug("%s: OCV_RAW=%x OCV=%duV\n", ocv_name, *ocv_raw, *ocv_uv); + + return rc; +} + +#define DEFAULT_S3_FIFO_LENGTH 3 +static int qg_update_fifo_length(struct qpnp_qg *chip, u8 length) +{ + int rc; + u8 s3_entry_fifo_length = 0; + + if (!length || length > chip->max_fifo_length) { + pr_err("Invalid FIFO length %d\n", length); + return -EINVAL; + } + + rc = qg_masked_write(chip, chip->qg_base + QG_S2_NORMAL_MEAS_CTL2_REG, + FIFO_LENGTH_MASK, (length - 1) << FIFO_LENGTH_SHIFT); + if (rc < 0) + pr_err("Failed to write S2 FIFO length, rc=%d\n", rc); + + /* update the S3 FIFO length, when S2 length is updated */ + if (length > 3 && !chip->dt.qg_sleep_config) + s3_entry_fifo_length = (chip->dt.s3_entry_fifo_length > 0) ? + chip->dt.s3_entry_fifo_length : DEFAULT_S3_FIFO_LENGTH; + else /* Use S3 length as 1 for any S2 length <= 3 */ + s3_entry_fifo_length = 1; + + rc = qg_masked_write(chip, + chip->qg_base + QG_S3_SLEEP_OCV_IBAT_CTL1_REG, + SLEEP_IBAT_QUALIFIED_LENGTH_MASK, + s3_entry_fifo_length - 1); + if (rc < 0) + pr_err("Failed to write S3-entry fifo-length, rc=%d\n", + rc); + + return rc; +} + +static int qg_master_hold(struct qpnp_qg *chip, bool hold) +{ + int rc; + + /* clear the master */ + rc = qg_masked_write(chip, chip->qg_base + QG_DATA_CTL1_REG, + MASTER_HOLD_OR_CLR_BIT, 0); + if (rc < 0) + return rc; + + if (hold) { + /* 0 -> 1, hold the master */ + rc = qg_masked_write(chip, chip->qg_base + QG_DATA_CTL1_REG, + MASTER_HOLD_OR_CLR_BIT, + MASTER_HOLD_OR_CLR_BIT); + if (rc < 0) + return rc; + } + + qg_dbg(chip, QG_DEBUG_STATUS, "Master hold = %d\n", hold); + + return rc; +} + +static void qg_notify_charger(struct qpnp_qg *chip) +{ + union power_supply_propval prop = {0, }; + int rc; + + if (!chip->batt_psy) + return; + + if (is_debug_batt_id(chip)) { + prop.intval = 1; + power_supply_set_property(chip->batt_psy, + POWER_SUPPLY_PROP_DEBUG_BATTERY, &prop); + return; + } + + if (!chip->profile_loaded) + return; +#ifdef OPLUS_FEATURE_CHG_BASIC +#else + prop.intval = chip->bp.float_volt_uv; + rc = power_supply_set_property(chip->batt_psy, + POWER_SUPPLY_PROP_VOLTAGE_MAX, &prop); +#endif + if (rc < 0) { + pr_err("Failed to set voltage_max property on batt_psy, rc=%d\n", + rc); + return; + } + + prop.intval = chip->bp.fastchg_curr_ma * 1000; + rc = power_supply_set_property(chip->batt_psy, + POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, &prop); + if (rc < 0) { + pr_err("Failed to set constant_charge_current_max property on batt_psy, rc=%d\n", + rc); + return; + } + + pr_debug("Notified charger on float voltage and FCC\n"); + + rc = power_supply_get_property(chip->batt_psy, + POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT, &prop); + if (rc < 0) { + pr_err("Failed to get charge term current, rc=%d\n", rc); + return; + } + chip->chg_iterm_ma = prop.intval; +} + +static bool is_batt_available(struct qpnp_qg *chip) +{ + if (chip->batt_psy) + return true; + + chip->batt_psy = power_supply_get_by_name("battery"); + if (!chip->batt_psy) + return false; + + /* batt_psy is initialized, set the fcc and fv */ + qg_notify_charger(chip); + + return true; +} + +static int qg_store_soc_params(struct qpnp_qg *chip) +{ + int rc, batt_temp = 0, i; + unsigned long rtc_sec = 0; + u32 flash_ocv = 0; + + rc = get_rtc_time(&rtc_sec); + if (rc < 0) + pr_err("Failed to get RTC time, rc=%d\n", rc); + else + chip->sdam_data[SDAM_TIME_SEC] = rtc_sec; + + rc = qg_get_battery_temp(chip, &batt_temp); + if (rc < 0) + pr_err("Failed to get battery-temp, rc = %d\n", rc); + else + chip->sdam_data[SDAM_TEMP] = (u32)batt_temp; + + for (i = 0; i <= SDAM_TIME_SEC; i++) { + rc |= qg_sdam_write(i, chip->sdam_data[i]); + qg_dbg(chip, QG_DEBUG_STATUS, "SDAM write param %d value=%d\n", + i, chip->sdam_data[i]); + } + + /* store the SDAM OCV */ + flash_ocv = chip->sdam_data[SDAM_OCV_UV] / 20000; + rc = qg_sdam_write(SDAM_FLASH_OCV, flash_ocv); + if (rc < 0) + pr_err("Failed to update flash-ocv rc=%d\n", rc); + + return rc; +} + +#define MAX_FIFO_CNT_FOR_ESR 50 +static int qg_config_s2_state(struct qpnp_qg *chip, + enum s2_state requested_state, bool state_enable, + bool process_fifo) +{ + int rc, acc_interval, acc_length; + u8 fifo_length, reg = 0, state = S2_DEFAULT; + + if ((chip->s2_state_mask & requested_state) && (state_enable == true)) + return 0; /* No change in state */ + + if (!(chip->s2_state_mask & requested_state) && (state_enable == false)) + return 0; /* No change in state */ + + if (state_enable) + chip->s2_state_mask |= requested_state; + else + chip->s2_state_mask &= ~requested_state; + + /* define the priority of the states */ + if (chip->s2_state_mask & S2_FAST_CHARGING) + state = S2_FAST_CHARGING; + else if (chip->s2_state_mask & S2_LOW_VBAT) + state = S2_LOW_VBAT; + else if (chip->s2_state_mask & S2_SLEEP) + state = S2_SLEEP; + else + state = S2_DEFAULT; + + if (state == chip->s2_state) + return 0; + + switch (state) { + case S2_FAST_CHARGING: + fifo_length = chip->dt.fast_chg_s2_fifo_length; + acc_interval = chip->dt.s2_acc_intvl_ms; + acc_length = chip->dt.s2_acc_length; + break; + case S2_LOW_VBAT: + fifo_length = chip->dt.s2_vbat_low_fifo_length; + acc_interval = chip->dt.s2_acc_intvl_ms; + acc_length = chip->dt.s2_acc_length; + break; + case S2_SLEEP: + fifo_length = chip->dt.sleep_s2_fifo_length; + acc_interval = chip->dt.sleep_s2_acc_intvl_ms; + acc_length = chip->dt.sleep_s2_acc_length; + break; + case S2_DEFAULT: +#ifdef OPLUS_FEATURE_CHG_BASIC + if(chip->asic_with_internal_gauge) + fifo_length = chip->dt.fast_chg_s2_fifo_length; + else + fifo_length = chip->dt.s2_fifo_length; +#else + fifo_length = chip->dt.s2_fifo_length; +#endif + + acc_interval = chip->dt.s2_acc_intvl_ms; + acc_length = chip->dt.s2_acc_length; + break; + default: + pr_err("Invalid S2 state %d\n", state); + return -EINVAL; + } + + if (fifo_length) + qg_esr_mod_count = MAX_FIFO_CNT_FOR_ESR / fifo_length; + + rc = qg_master_hold(chip, true); + if (rc < 0) { + pr_err("Failed to hold master, rc=%d\n", rc); + return rc; + } + + if (process_fifo) { + rc = qg_process_rt_fifo(chip); + if (rc < 0) { + pr_err("Failed to process FIFO real-time, rc=%d\n", rc); + goto done; + } + } + + rc = qg_update_fifo_length(chip, fifo_length); + if (rc < 0) { + pr_err("Failed to update S2 fifo-length, rc=%d\n", rc); + goto done; + } + + reg = acc_interval / 10; + rc = qg_write(chip, chip->qg_base + QG_S2_NORMAL_MEAS_CTL3_REG, + ®, 1); + if (rc < 0) { + pr_err("Failed to update S2 acc intrvl, rc=%d\n", rc); + goto done; + } + + reg = ilog2(acc_length) - 1; + rc = qg_masked_write(chip, chip->qg_base + QG_S2_NORMAL_MEAS_CTL2_REG, + NUM_OF_ACCUM_MASK, reg); + if (rc < 0) { + pr_err("Failed to update S2 ACC length, rc=%d\n", rc); + goto done; + } + + chip->s2_state = state; + + qg_dbg(chip, QG_DEBUG_STATUS, "S2 New state=%x fifo_length=%d interval=%d acc_length=%d\n", + state, fifo_length, acc_interval, acc_length); + +done: + qg_master_hold(chip, false); + /* FIFO restarted */ + chip->last_fifo_update_time = ktime_get_boottime(); + return rc; +} + +static int qg_process_fifo(struct qpnp_qg *chip, u32 fifo_length) +{ + int rc = 0, i, j = 0, temp; + u8 v_fifo[MAX_FIFO_LENGTH * 2], i_fifo[MAX_FIFO_LENGTH * 2]; + u32 sample_interval = 0, sample_count = 0, fifo_v = 0, fifo_i = 0; + unsigned long rtc_sec = 0; + bool qg_v_mode = (chip->qg_mode == QG_V_MODE); + + rc = get_rtc_time(&rtc_sec); + if (rc < 0) + pr_err("Failed to get RTC time, rc=%d\n", rc); + + chip->kdata.fifo_time = (u32)rtc_sec; + + if (!fifo_length) { + pr_debug("No FIFO data\n"); + return 0; + } + + qg_dbg(chip, QG_DEBUG_FIFO, "FIFO length=%d\n", fifo_length); + + rc = get_sample_interval(chip, &sample_interval); + if (rc < 0) { + pr_err("Failed to get FIFO sample interval, rc=%d\n", rc); + return rc; + } + + rc = get_sample_count(chip, &sample_count); + if (rc < 0) { + pr_err("Failed to get FIFO sample count, rc=%d\n", rc); + return rc; + } + + /* + * If there is pending data from suspend, append the new FIFO + * data to it. Only do this if we can accomadate 8 FIFOs + */ + if (chip->suspend_data && + (chip->kdata.fifo_length < (MAX_FIFO_LENGTH / 2))) { + j = chip->kdata.fifo_length; /* append the data */ + chip->suspend_data = false; + qg_dbg(chip, QG_DEBUG_FIFO, + "Pending suspend-data FIFO length=%d\n", j); + } else { + /* clear any old pending data */ + chip->kdata.fifo_length = 0; + } + + for (i = 0; i < fifo_length * 2; i = i + 2, j++) { + rc = qg_read(chip, chip->qg_base + QG_V_FIFO0_DATA0_REG + i, + &v_fifo[i], 2); + if (rc < 0) { + pr_err("Failed to read QG_V_FIFO, rc=%d\n", rc); + return rc; + } + rc = qg_read(chip, chip->qg_base + QG_I_FIFO0_DATA0_REG + i, + &i_fifo[i], 2); + if (rc < 0) { + pr_err("Failed to read QG_I_FIFO, rc=%d\n", rc); + return rc; + } + + fifo_v = v_fifo[i] | (v_fifo[i + 1] << 8); + fifo_i = i_fifo[i] | (i_fifo[i + 1] << 8); + + if (fifo_v == FIFO_V_RESET_VAL || + (fifo_i == FIFO_I_RESET_VAL && !qg_v_mode)) { + pr_err("Invalid FIFO data V_RAW=%x I_RAW=%x - FIFO rejected\n", + fifo_v, fifo_i); + return -EINVAL; + } + + temp = sign_extend32(fifo_i, 15); + + chip->kdata.fifo[j].v = V_RAW_TO_UV(fifo_v); + chip->kdata.fifo[j].i = + qg_v_mode ? 0 : qg_iraw_to_ua(chip, temp); + chip->kdata.fifo[j].interval = sample_interval; + chip->kdata.fifo[j].count = sample_count; + + chip->last_fifo_v_uv = chip->kdata.fifo[j].v; + chip->last_fifo_i_ua = chip->kdata.fifo[j].i; + + qg_dbg(chip, QG_DEBUG_FIFO, "FIFO %d raw_v=%d uV=%d raw_i=%d uA=%d interval=%d count=%d\n", + j, fifo_v, + chip->kdata.fifo[j].v, + qg_v_mode ? 0 : fifo_i, + (int)chip->kdata.fifo[j].i, + chip->kdata.fifo[j].interval, + chip->kdata.fifo[j].count); + } + + chip->kdata.fifo_length += fifo_length; + chip->kdata.seq_no = chip->seq_no++ % U32_MAX; + + return rc; +} + +static int qg_process_accumulator(struct qpnp_qg *chip) +{ + int rc, sample_interval = 0; + u8 count, index = chip->kdata.fifo_length; + u64 acc_v = 0, acc_i = 0; + s64 temp = 0; + bool qg_v_mode = (chip->qg_mode == QG_V_MODE); + + rc = qg_read(chip, chip->qg_base + QG_ACCUM_CNT_RT_REG, + &count, 1); + if (rc < 0) { + pr_err("Failed to read ACC count, rc=%d\n", rc); + return rc; + } + + if (!count || count < 10) { /* Ignore small accumulator data */ + pr_debug("No ACCUMULATOR data!\n"); + return 0; + } + + rc = get_sample_interval(chip, &sample_interval); + if (rc < 0) { + pr_err("Failed to get ACC sample interval, rc=%d\n", rc); + return 0; + } + + rc = qg_read(chip, chip->qg_base + QG_V_ACCUM_DATA0_RT_REG, + (u8 *)&acc_v, 3); + if (rc < 0) { + pr_err("Failed to read ACC RT V data, rc=%d\n", rc); + return rc; + } + + rc = qg_read(chip, chip->qg_base + QG_I_ACCUM_DATA0_RT_REG, + (u8 *)&acc_i, 3); + if (rc < 0) { + pr_err("Failed to read ACC RT I data, rc=%d\n", rc); + return rc; + } + + temp = sign_extend64(acc_i, 23); + + chip->kdata.fifo[index].v = V_RAW_TO_UV(div_u64(acc_v, count)); + chip->kdata.fifo[index].i = qg_v_mode ? + 0 : qg_iraw_to_ua(chip, div_s64(temp, count)); + chip->kdata.fifo[index].interval = sample_interval; + chip->kdata.fifo[index].count = count; + chip->kdata.fifo_length++; + if (chip->kdata.fifo_length == MAX_FIFO_LENGTH) + chip->kdata.fifo_length = MAX_FIFO_LENGTH - 1; + + chip->last_fifo_v_uv = chip->kdata.fifo[index].v; + chip->last_fifo_i_ua = chip->kdata.fifo[index].i; + + if (chip->kdata.fifo_length == 1) /* Only accumulator data */ + chip->kdata.seq_no = chip->seq_no++ % U32_MAX; + + qg_dbg(chip, QG_DEBUG_FIFO, "ACC v_avg=%duV i_avg=%duA interval=%d count=%d\n", + chip->kdata.fifo[index].v, + (int)chip->kdata.fifo[index].i, + chip->kdata.fifo[index].interval, + chip->kdata.fifo[index].count); + + return rc; +} + +static int qg_process_rt_fifo(struct qpnp_qg *chip) +{ + int rc; + u32 fifo_length = 0; + + /* Get the real-time FIFO length */ + rc = get_fifo_length(chip, &fifo_length, true); + if (rc < 0) { + pr_err("Failed to read RT FIFO length, rc=%d\n", rc); + return rc; + } + + rc = qg_process_fifo(chip, fifo_length); + if (rc < 0) { + pr_err("Failed to process FIFO data, rc=%d\n", rc); + return rc; + } + + rc = qg_process_accumulator(chip); + if (rc < 0) { + pr_err("Failed to process ACC data, rc=%d\n", rc); + return rc; + } + + return rc; +} + +#define MIN_FIFO_FULL_TIME_MS 12000 +static int process_rt_fifo_data(struct qpnp_qg *chip, bool update_smb) +{ + int rc = 0; + ktime_t now = ktime_get_boottime(); + s64 time_delta; + + /* + * Reject the FIFO read event if there are back-to-back requests + * This is done to gaurantee that there is always a minimum FIFO + * data to be processed, ignore this if vbat_low is set. + */ + time_delta = ktime_ms_delta(now, chip->last_user_update_time); + + qg_dbg(chip, QG_DEBUG_FIFO, "time_delta=%lld ms update_smb=%d\n", + time_delta, update_smb); + + if (time_delta > MIN_FIFO_FULL_TIME_MS || update_smb) { + rc = qg_master_hold(chip, true); + if (rc < 0) { + pr_err("Failed to hold master, rc=%d\n", rc); + goto done; + } + + rc = qg_process_rt_fifo(chip); + if (rc < 0) { + pr_err("Failed to process FIFO real-time, rc=%d\n", rc); + goto done; + } + + if (update_smb) { + rc = qg_masked_write(chip, chip->qg_base + + QG_MODE_CTL1_REG, PARALLEL_IBAT_SENSE_EN_BIT, + chip->parallel_enabled ? + PARALLEL_IBAT_SENSE_EN_BIT : 0); + if (rc < 0) { + pr_err("Failed to update SMB_EN, rc=%d\n", rc); + goto done; + } + qg_dbg(chip, QG_DEBUG_STATUS, "Parallel SENSE %d\n", + chip->parallel_enabled); + } + + rc = qg_master_hold(chip, false); + if (rc < 0) { + pr_err("Failed to release master, rc=%d\n", rc); + goto done; + } + /* FIFOs restarted */ + chip->last_fifo_update_time = ktime_get_boottime(); + + /* signal the read thread */ + chip->data_ready = true; + wake_up_interruptible(&chip->qg_wait_q); + chip->last_user_update_time = now; + + /* vote to stay awake until userspace reads data */ + vote(chip->awake_votable, FIFO_RT_DONE_VOTER, true, 0); + } else { + qg_dbg(chip, QG_DEBUG_FIFO, "FIFO processing too early time_delta=%lld\n", + time_delta); + } +done: + qg_master_hold(chip, false); + return rc; +} + +#define VBAT_LOW_HYST_UV 50000 /* 50mV */ +static int qg_vbat_low_wa(struct qpnp_qg *chip) +{ + int rc, i, temp = 0; + u32 vbat_low_uv = 0; + + if (chip->wa_flags & QG_VBAT_LOW_WA) { + rc = qg_get_battery_temp(chip, &temp); + if (rc < 0) { + pr_err("Failed to read batt_temp rc=%d\n", rc); + temp = 250; + } + + vbat_low_uv = 1000 * ((temp < chip->dt.cold_temp_threshold) ? + chip->dt.vbatt_low_cold_mv : + chip->dt.vbatt_low_mv); + + for (i = 0; i < chip->kdata.fifo_length; i++) { + if ((chip->kdata.fifo[i].v > (vbat_low_uv + + VBAT_LOW_HYST_UV)) && chip->vbat_low) { + chip->vbat_low = false; + pr_info("Exit VBAT_LOW vbat_avg=%duV vbat_low=%duV\n", + chip->kdata.fifo[i].v, vbat_low_uv); + break; + } else if ((chip->kdata.fifo[i].v < vbat_low_uv) && + !chip->vbat_low) { + chip->vbat_low = true; + pr_info("Enter VBAT_LOW vbat_avg=%duV vbat_low=%duV\n", + chip->kdata.fifo[i].v, vbat_low_uv); + break; + } + } + } + + rc = qg_config_s2_state(chip, S2_LOW_VBAT, + chip->vbat_low ? true : false, false); + if (rc < 0) + pr_err("Failed to configure for VBAT_LOW rc=%d\n", rc); + + return rc; +} + +static int qg_vbat_thresholds_config(struct qpnp_qg *chip) +{ + int rc, temp = 0, vbat_mv; + u8 reg; + + rc = qg_get_battery_temp(chip, &temp); + if (rc < 0) { + pr_err("Failed to read batt_temp rc=%d\n", rc); + return rc; + } + + vbat_mv = (temp < chip->dt.cold_temp_threshold) ? + chip->dt.vbatt_empty_cold_mv : + chip->dt.vbatt_empty_mv; + + rc = qg_read(chip, chip->qg_base + QG_VBAT_EMPTY_THRESHOLD_REG, + ®, 1); + if (rc < 0) { + pr_err("Failed to read vbat-empty, rc=%d\n", rc); + return rc; + } + + if (vbat_mv == (reg * 50)) /* No change */ + goto config_vbat_low; + + reg = vbat_mv / 50; + rc = qg_write(chip, chip->qg_base + QG_VBAT_EMPTY_THRESHOLD_REG, + ®, 1); + if (rc < 0) { + pr_err("Failed to write vbat-empty, rc=%d\n", rc); + return rc; + } + + qg_dbg(chip, QG_DEBUG_STATUS, + "VBAT EMPTY threshold updated to %dmV temp=%d\n", + vbat_mv, temp); + +config_vbat_low: + if (chip->qg_version == QG_LITE) + return 0; + + vbat_mv = (temp < chip->dt.cold_temp_threshold) ? + chip->dt.vbatt_low_cold_mv : + chip->dt.vbatt_low_mv; + + rc = qg_read(chip, chip->qg_base + QG_VBAT_LOW_THRESHOLD_REG, + ®, 1); + if (rc < 0) { + pr_err("Failed to read vbat-low, rc=%d\n", rc); + return rc; + } + + if (vbat_mv == (reg * 50)) /* No change */ + return 0; + + reg = vbat_mv / 50; + rc = qg_write(chip, chip->qg_base + QG_VBAT_LOW_THRESHOLD_REG, + ®, 1); + if (rc < 0) { + pr_err("Failed to write vbat-low, rc=%d\n", rc); + return rc; + } + + qg_dbg(chip, QG_DEBUG_STATUS, + "VBAT LOW threshold updated to %dmV temp=%d\n", + vbat_mv, temp); + + return rc; +} + +static int qg_fast_charge_config(struct qpnp_qg *chip) +{ + int rc = 0; + + if (!chip->dt.qg_fast_chg_cfg) + return 0; + + rc = qg_config_s2_state(chip, S2_FAST_CHARGING, + (chip->charge_status == POWER_SUPPLY_STATUS_CHARGING) + ? true : false, false); + if (rc < 0) + pr_err("Failed to exit S2_SLEEP rc=%d\n", rc); + + return rc; +} + +static void qg_retrieve_esr_params(struct qpnp_qg *chip) +{ + u32 data = 0; + int rc; + + rc = qg_sdam_read(SDAM_ESR_CHARGE_DELTA, &data); + if (!rc && data) { + chip->kdata.param[QG_ESR_CHARGE_DELTA].data = data; + chip->kdata.param[QG_ESR_CHARGE_DELTA].valid = true; + qg_dbg(chip, QG_DEBUG_ESR, + "ESR_CHARGE_DELTA SDAM=%d\n", data); + } else if (rc < 0) { + pr_err("Failed to read ESR_CHARGE_DELTA rc=%d\n", rc); + } + + rc = qg_sdam_read(SDAM_ESR_DISCHARGE_DELTA, &data); + if (!rc && data) { + chip->kdata.param[QG_ESR_DISCHARGE_DELTA].data = data; + chip->kdata.param[QG_ESR_DISCHARGE_DELTA].valid = true; + qg_dbg(chip, QG_DEBUG_ESR, + "ESR_DISCHARGE_DELTA SDAM=%d\n", data); + } else if (rc < 0) { + pr_err("Failed to read ESR_DISCHARGE_DELTA rc=%d\n", rc); + } + + rc = qg_sdam_read(SDAM_ESR_CHARGE_SF, &data); + if (!rc && data) { + data = CAP(QG_ESR_SF_MIN, QG_ESR_SF_MAX, data); + chip->kdata.param[QG_ESR_CHARGE_SF].data = data; + chip->kdata.param[QG_ESR_CHARGE_SF].valid = true; + qg_dbg(chip, QG_DEBUG_ESR, + "ESR_CHARGE_SF SDAM=%d\n", data); + } else if (rc < 0) { + pr_err("Failed to read ESR_CHARGE_SF rc=%d\n", rc); + } + + rc = qg_sdam_read(SDAM_ESR_DISCHARGE_SF, &data); + if (!rc && data) { + data = CAP(QG_ESR_SF_MIN, QG_ESR_SF_MAX, data); + chip->kdata.param[QG_ESR_DISCHARGE_SF].data = data; + chip->kdata.param[QG_ESR_DISCHARGE_SF].valid = true; + qg_dbg(chip, QG_DEBUG_ESR, + "ESR_DISCHARGE_SF SDAM=%d\n", data); + } else if (rc < 0) { + pr_err("Failed to read ESR_DISCHARGE_SF rc=%d\n", rc); + } +} + +static void qg_store_esr_params(struct qpnp_qg *chip) +{ + unsigned int esr; + + if (chip->udata.param[QG_ESR_CHARGE_DELTA].valid) { + esr = chip->udata.param[QG_ESR_CHARGE_DELTA].data; + qg_sdam_write(SDAM_ESR_CHARGE_DELTA, esr); + qg_dbg(chip, QG_DEBUG_ESR, + "SDAM store ESR_CHARGE_DELTA=%d\n", esr); + } + + if (chip->udata.param[QG_ESR_DISCHARGE_DELTA].valid) { + esr = chip->udata.param[QG_ESR_DISCHARGE_DELTA].data; + qg_sdam_write(SDAM_ESR_DISCHARGE_DELTA, esr); + qg_dbg(chip, QG_DEBUG_ESR, + "SDAM store ESR_DISCHARGE_DELTA=%d\n", esr); + } + + if (chip->udata.param[QG_ESR_CHARGE_SF].valid) { + esr = chip->udata.param[QG_ESR_CHARGE_SF].data; + qg_sdam_write(SDAM_ESR_CHARGE_SF, esr); + qg_dbg(chip, QG_DEBUG_ESR, + "SDAM store ESR_CHARGE_SF=%d\n", esr); + } + + if (chip->udata.param[QG_ESR_DISCHARGE_SF].valid) { + esr = chip->udata.param[QG_ESR_DISCHARGE_SF].data; + qg_sdam_write(SDAM_ESR_DISCHARGE_SF, esr); + qg_dbg(chip, QG_DEBUG_ESR, + "SDAM store ESR_DISCHARGE_SF=%d\n", esr); + } +} + +#define MAX_ESR_RETRY_COUNT 10 +#define ESR_SD_PERCENT 10 +static int qg_process_esr_data(struct qpnp_qg *chip) +{ + int i; + int pre_i, post_i, pre_v, post_v, first_pre_i = 0; + int diff_v, diff_i, esr_avg = 0, count = 0; + + for (i = 0; i < qg_esr_count; i++) { + if (!chip->esr_data[i].valid) + continue; + + pre_i = chip->esr_data[i].pre_esr_i; + pre_v = chip->esr_data[i].pre_esr_v; + post_i = chip->esr_data[i].post_esr_i; + post_v = chip->esr_data[i].post_esr_v; + + /* + * Check if any of the pre/post readings have changed + * signs by comparing it with the first valid + * pre_i value. + */ + if (!first_pre_i) + first_pre_i = pre_i; + + if ((first_pre_i < 0 && pre_i > 0) || + (first_pre_i > 0 && post_i < 0) || + (first_pre_i < 0 && post_i > 0)) { + qg_dbg(chip, QG_DEBUG_ESR, + "ESR-sign mismatch %d reject all data\n", i); + esr_avg = count = 0; + break; + } + + /* calculate ESR */ + diff_v = abs(post_v - pre_v); + diff_i = abs(post_i - pre_i); + + if (!diff_v || !diff_i || + (diff_i < chip->dt.esr_qual_i_ua) || + (diff_v < chip->dt.esr_qual_v_uv)) { + qg_dbg(chip, QG_DEBUG_ESR, + "ESR (%d) V/I %duA %duV fails qualification\n", + i, diff_i, diff_v); + chip->esr_data[i].valid = false; + continue; + } + + chip->esr_data[i].esr = + DIV_ROUND_CLOSEST(diff_v * 1000, diff_i); + qg_dbg(chip, QG_DEBUG_ESR, + "ESR qualified: i=%d pre_i=%d pre_v=%d post_i=%d post_v=%d esr_diff_v=%d esr_diff_i=%d esr=%d\n", + i, pre_i, pre_v, post_i, post_v, + diff_v, diff_i, chip->esr_data[i].esr); + + esr_avg += chip->esr_data[i].esr; + count++; + } + + if (!count) { + qg_dbg(chip, QG_DEBUG_ESR, + "No ESR samples qualified, ESR not found\n"); + chip->esr_avg = 0; + return 0; + } + + esr_avg /= count; + qg_dbg(chip, QG_DEBUG_ESR, + "ESR all sample average=%d count=%d apply_SD=%d\n", + esr_avg, count, (esr_avg * ESR_SD_PERCENT) / 100); + + /* + * Reject ESR samples which do not fall in + * 10% the standard-deviation + */ + count = 0; + for (i = 0; i < qg_esr_count; i++) { + if (!chip->esr_data[i].valid) + continue; + + if ((abs(chip->esr_data[i].esr - esr_avg) <= + (esr_avg * ESR_SD_PERCENT) / 100)) { + /* valid ESR */ + chip->esr_avg += chip->esr_data[i].esr; + count++; + qg_dbg(chip, QG_DEBUG_ESR, + "Valid ESR after SD (%d) %d mOhm\n", + i, chip->esr_data[i].esr); + } else { + qg_dbg(chip, QG_DEBUG_ESR, + "ESR (%d) %d falls-out of SD(%d)\n", + i, chip->esr_data[i].esr, ESR_SD_PERCENT); + } + } + + if (count >= QG_MIN_ESR_COUNT) { + chip->esr_avg /= count; + qg_dbg(chip, QG_DEBUG_ESR, "Average estimated ESR %d mOhm\n", + chip->esr_avg); + } else { + qg_dbg(chip, QG_DEBUG_ESR, + "Not enough ESR samples, ESR not found\n"); + chip->esr_avg = 0; + } + + return 0; +} + +#ifdef OPLUS_FEATURE_CHG_BASIC +extern int oplus_chg_get_ffc_status(void);//kilody +extern bool oplus_vooc_get_fastchg_ing(void); +#endif +static int qg_esr_estimate(struct qpnp_qg *chip) +{ +#ifdef OPLUS_FEATURE_CHG_BASIC + int rc, i, ibat = 0, temp = 0; +#else + int rc, i, ibat = 0; +#endif + u8 esr_done_count, reg0 = 0, reg1 = 0; + bool is_charging = false; + + if (chip->dt.esr_disable) + return 0; +#ifdef OPLUS_FEATURE_CHG_BASIC + if (chip->asic_with_internal_gauge){ + if(oplus_vooc_get_fastchg_ing()) + return 0; + } +#endif + + /* + * Charge - enable ESR estimation if IBAT > MIN_IBAT. + * Discharge - enable ESR estimation only if enabled via DT. + */ + rc = qg_get_battery_current(chip, &ibat); + if (rc < 0) + return rc; + if (chip->charge_status == POWER_SUPPLY_STATUS_CHARGING && + ibat > chip->dt.esr_min_ibat_ua) { + qg_dbg(chip, QG_DEBUG_ESR, + "Skip CHG ESR, Fails IBAT ibat(%d) min_ibat(%d)\n", + ibat, chip->dt.esr_min_ibat_ua); + return 0; + } + + if (chip->charge_status != POWER_SUPPLY_STATUS_CHARGING && + !chip->dt.esr_discharge_enable) + return 0; + + /* Ignore ESR if battery-temp is below a threshold */ + rc = qg_get_battery_temp(chip, &temp); + if (rc < 0) + return rc; + if (temp < chip->dt.esr_low_temp_threshold) { + qg_dbg(chip, QG_DEBUG_ESR, + "Battery temperature(%d) below threshold(%d) for ESR\n", + temp, chip->dt.esr_low_temp_threshold); + return 0; + } + + if (chip->batt_soc != INT_MIN && (chip->batt_soc < + chip->dt.esr_disable_soc)) { + qg_dbg(chip, QG_DEBUG_ESR, + "Skip ESR, batt-soc below %d\n", + chip->dt.esr_disable_soc); + return 0; + } + + qg_dbg(chip, QG_DEBUG_ESR, "FIFO done count=%d ESR mod count=%d\n", + chip->fifo_done_count, qg_esr_mod_count); + + if ((chip->fifo_done_count % qg_esr_mod_count) != 0) + return 0; + + if (qg_esr_count > QG_MAX_ESR_COUNT) + qg_esr_count = QG_MAX_ESR_COUNT; + + if (qg_esr_count < QG_MIN_ESR_COUNT) + qg_esr_count = QG_MIN_ESR_COUNT; + + /* clear all data */ + chip->esr_avg = 0; + memset(&chip->esr_data, 0, sizeof(chip->esr_data)); + + rc = qg_master_hold(chip, true); + if (rc < 0) { + pr_err("Failed to hold master, rc=%d\n", rc); + goto done; + } + + for (i = 0; i < qg_esr_count; i++) { + /* Fire ESR measurement */ + rc = qg_masked_write(chip, + chip->qg_base + QG_ESR_MEAS_TRIG_REG, + HW_ESR_MEAS_START_BIT, HW_ESR_MEAS_START_BIT); + if (rc < 0) { + pr_err("Failed to start ESR rc=%d\n", rc); + continue; + } + + esr_done_count = reg0 = reg1 = 0; + do { + /* delay for ESR processing to complete */ + msleep(50); + + esr_done_count++; + + rc = qg_read(chip, + chip->qg_base + QG_STATUS1_REG, ®0, 1); + if (rc < 0) + continue; + + rc = qg_read(chip, + chip->qg_base + QG_STATUS4_REG, ®1, 1); + if (rc < 0) + continue; + + /* check ESR-done status */ + if (!(reg1 & ESR_MEAS_IN_PROGRESS_BIT) && + (reg0 & ESR_MEAS_DONE_BIT)) { + qg_dbg(chip, QG_DEBUG_ESR, + "ESR measurement done %d count %d\n", + i, esr_done_count); + break; + } + } while (esr_done_count < MAX_ESR_RETRY_COUNT); + + if (esr_done_count == MAX_ESR_RETRY_COUNT) { + pr_err("Failed to get ESR done for %d iteration\n", i); + continue; + } else { + /* found a valid ESR, read pre-post data */ + rc = qg_read_raw_data(chip, QG_PRE_ESR_V_DATA0_REG, + &chip->esr_data[i].pre_esr_v); + if (rc < 0) + goto done; + + rc = qg_read_raw_data(chip, QG_PRE_ESR_I_DATA0_REG, + &chip->esr_data[i].pre_esr_i); + if (rc < 0) + goto done; + + rc = qg_read_raw_data(chip, QG_POST_ESR_V_DATA0_REG, + &chip->esr_data[i].post_esr_v); + if (rc < 0) + goto done; + + rc = qg_read_raw_data(chip, QG_POST_ESR_I_DATA0_REG, + &chip->esr_data[i].post_esr_i); + if (rc < 0) + goto done; + + chip->esr_data[i].pre_esr_v = + V_RAW_TO_UV(chip->esr_data[i].pre_esr_v); + ibat = sign_extend32(chip->esr_data[i].pre_esr_i, 15); + chip->esr_data[i].pre_esr_i = qg_iraw_to_ua(chip, ibat); + chip->esr_data[i].post_esr_v = + V_RAW_TO_UV(chip->esr_data[i].post_esr_v); + ibat = sign_extend32(chip->esr_data[i].post_esr_i, 15); + chip->esr_data[i].post_esr_i = + qg_iraw_to_ua(chip, ibat); + + chip->esr_data[i].valid = true; + + if ((int)chip->esr_data[i].pre_esr_i < 0) + is_charging = true; + + qg_dbg(chip, QG_DEBUG_ESR, + "ESR values for %d iteration pre_v=%d pre_i=%d post_v=%d post_i=%d\n", + i, chip->esr_data[i].pre_esr_v, + (int)chip->esr_data[i].pre_esr_i, + chip->esr_data[i].post_esr_v, + (int)chip->esr_data[i].post_esr_i); + } + /* delay before the next ESR measurement */ + msleep(200); + } + + rc = qg_process_esr_data(chip); + if (rc < 0) + pr_err("Failed to process ESR data rc=%d\n", rc); + + rc = qg_master_hold(chip, false); + if (rc < 0) { + pr_err("Failed to release master, rc=%d\n", rc); + goto done; + } + /* FIFOs restarted */ + chip->last_fifo_update_time = ktime_get_boottime(); + + if (chip->esr_avg) { + chip->kdata.param[QG_ESR].data = chip->esr_avg; + chip->kdata.param[QG_ESR].valid = true; + qg_dbg(chip, QG_DEBUG_ESR, "ESR_SW=%d during %s\n", + chip->esr_avg, is_charging ? "CHARGE" : "DISCHARGE"); + qg_retrieve_esr_params(chip); + chip->esr_actual = chip->esr_avg; + } + + return 0; +done: + qg_master_hold(chip, false); + return rc; +} + +static void process_udata_work(struct work_struct *work) +{ + struct qpnp_qg *chip = container_of(work, + struct qpnp_qg, udata_work); + int rc; + + if (chip->udata.param[QG_CC_SOC].valid) + chip->cc_soc = chip->udata.param[QG_CC_SOC].data; + + if (chip->udata.param[QG_BATT_SOC].valid) + chip->batt_soc = chip->udata.param[QG_BATT_SOC].data; + + if (chip->udata.param[QG_FULL_SOC].valid) + chip->full_soc = chip->udata.param[QG_FULL_SOC].data; + + if (chip->udata.param[QG_V_IBAT].valid) + chip->qg_v_ibat = chip->udata.param[QG_V_IBAT].data; + + if (chip->udata.param[QG_SOC].valid || + chip->udata.param[QG_SYS_SOC].valid) { + + qg_dbg(chip, QG_DEBUG_SOC, "udata update: QG_SOC=%d QG_SYS_SOC=%d last_catchup_soc=%d\n", + chip->udata.param[QG_SOC].valid ? + chip->udata.param[QG_SOC].data : -EINVAL, + chip->udata.param[QG_SYS_SOC].valid ? + chip->udata.param[QG_SYS_SOC].data : -EINVAL, + chip->catch_up_soc); + + if (chip->udata.param[QG_SYS_SOC].valid) { + chip->sys_soc = chip->udata.param[QG_SYS_SOC].data; + chip->catch_up_soc = qg_adjust_sys_soc(chip); + } else { + chip->catch_up_soc = chip->udata.param[QG_SOC].data; + } + + qg_scale_soc(chip, chip->force_soc); + chip->force_soc = false; + + /* update parameters to SDAM */ + chip->sdam_data[SDAM_SOC] = chip->msoc; + chip->sdam_data[SDAM_OCV_UV] = + chip->udata.param[QG_OCV_UV].data; + chip->sdam_data[SDAM_RBAT_MOHM] = + chip->udata.param[QG_RBAT_MOHM].data; + chip->sdam_data[SDAM_VALID] = 1; + + rc = qg_store_soc_params(chip); + if (rc < 0) + pr_err("Failed to update SDAM params, rc=%d\n", rc); + } + + if (chip->udata.param[QG_ESR].valid) + chip->esr_last = chip->udata.param[QG_ESR].data; + + if (chip->esr_actual != -EINVAL && chip->udata.param[QG_ESR].valid) { + chip->esr_nominal = chip->udata.param[QG_ESR].data; + if (chip->qg_psy) + power_supply_changed(chip->qg_psy); + } + + if (!chip->dt.esr_disable) + qg_store_esr_params(chip); + + qg_dbg(chip, QG_DEBUG_STATUS, "udata update: batt_soc=%d cc_soc=%d full_soc=%d qg_esr=%d\n", + (chip->batt_soc != INT_MIN) ? chip->batt_soc : -EINVAL, + (chip->cc_soc != INT_MIN) ? chip->cc_soc : -EINVAL, + chip->full_soc, chip->esr_last); + vote(chip->awake_votable, UDATA_READY_VOTER, false, 0); +} + +#define MAX_FIFO_DELTA_PERCENT 10 +static irqreturn_t qg_fifo_update_done_handler(int irq, void *data) +{ + ktime_t now = ktime_get_boottime(); + int rc, hw_delta_ms = 0, margin_ms = 0; + u32 fifo_length = 0; + s64 time_delta_ms = 0; + struct qpnp_qg *chip = data; + + time_delta_ms = ktime_ms_delta(now, chip->last_fifo_update_time); + chip->last_fifo_update_time = now; + + qg_dbg(chip, QG_DEBUG_IRQ, "IRQ triggered\n"); + mutex_lock(&chip->data_lock); + + rc = get_fifo_length(chip, &fifo_length, false); + if (rc < 0) { + pr_err("Failed to get FIFO length, rc=%d\n", rc); + goto done; + } + + rc = qg_process_fifo(chip, fifo_length); + if (rc < 0) { + pr_err("Failed to process QG FIFO, rc=%d\n", rc); + goto done; + } + + if (++chip->fifo_done_count == U32_MAX) + chip->fifo_done_count = 0; + + rc = qg_vbat_thresholds_config(chip); + if (rc < 0) + pr_err("Failed to apply VBAT EMPTY config rc=%d\n", rc); + + rc = qg_fast_charge_config(chip); + if (rc < 0) + pr_err("Failed to apply fast-charge config rc=%d\n", rc); + + rc = qg_vbat_low_wa(chip); + if (rc < 0) { + pr_err("Failed to apply VBAT LOW WA, rc=%d\n", rc); + goto done; + } + + rc = qg_esr_estimate(chip); + if (rc < 0) { + pr_err("Failed to estimate ESR, rc=%d\n", rc); + goto done; + } + + rc = get_fifo_done_time(chip, false, &hw_delta_ms); + if (rc < 0) + hw_delta_ms = 0; + else + margin_ms = (hw_delta_ms * MAX_FIFO_DELTA_PERCENT) / 100; + + if (abs(hw_delta_ms - time_delta_ms) < margin_ms) { + chip->kdata.param[QG_FIFO_TIME_DELTA].data = time_delta_ms; + chip->kdata.param[QG_FIFO_TIME_DELTA].valid = true; + qg_dbg(chip, QG_DEBUG_FIFO, "FIFO_done time_delta_ms=%lld\n", + time_delta_ms); + } + + /* signal the read thread */ + chip->data_ready = true; + wake_up_interruptible(&chip->qg_wait_q); + + /* vote to stay awake until userspace reads data */ + vote(chip->awake_votable, FIFO_DONE_VOTER, true, 0); + +done: + mutex_unlock(&chip->data_lock); + return IRQ_HANDLED; +} + +static irqreturn_t qg_vbat_low_handler(int irq, void *data) +{ + int rc; + struct qpnp_qg *chip = data; + u8 status = 0; + + qg_dbg(chip, QG_DEBUG_IRQ, "IRQ triggered\n"); + mutex_lock(&chip->data_lock); + + rc = qg_read(chip, chip->qg_base + QG_INT_RT_STS_REG, &status, 1); + if (rc < 0) { + pr_err("Failed to read RT status, rc=%d\n", rc); + goto done; + } + /* ignore VBAT low if battery is missing */ + if ((status & BATTERY_MISSING_INT_RT_STS_BIT) || + chip->battery_missing) + goto done; + + chip->vbat_low = !!(status & VBAT_LOW_INT_RT_STS_BIT); + + qg_dbg(chip, QG_DEBUG_IRQ, "VBAT_LOW = %d\n", chip->vbat_low); +done: + mutex_unlock(&chip->data_lock); + return IRQ_HANDLED; +} + +static irqreturn_t qg_vbat_empty_handler(int irq, void *data) +{ + struct qpnp_qg *chip = data; + u32 ocv_uv = 0; + int rc; + u8 status = 0; + + qg_dbg(chip, QG_DEBUG_IRQ, "IRQ triggered\n"); + + rc = qg_read(chip, chip->qg_base + QG_INT_RT_STS_REG, &status, 1); + if (rc < 0) + pr_err("Failed to read RT status rc=%d\n", rc); + + /* ignore VBAT empty if battery is missing */ + if ((status & BATTERY_MISSING_INT_RT_STS_BIT) || + chip->battery_missing) + return IRQ_HANDLED; + +#ifdef OPLUS_FEATURE_CHG_BASIC + pr_warn("VBATT EMPTY, do nothing, do not set SOC to 0\n"); + return IRQ_HANDLED; +#endif + pr_warn("VBATT EMPTY SOC = 0\n"); + + chip->catch_up_soc = 0; + qg_scale_soc(chip, true); + + qg_sdam_read(SDAM_OCV_UV, &ocv_uv); + chip->sdam_data[SDAM_SOC] = 0; + chip->sdam_data[SDAM_OCV_UV] = ocv_uv; + chip->sdam_data[SDAM_VALID] = 1; + + qg_store_soc_params(chip); + + if (chip->qg_psy) + power_supply_changed(chip->qg_psy); + + return IRQ_HANDLED; +} + +static irqreturn_t qg_good_ocv_handler(int irq, void *data) +{ + int rc; + u8 status = 0; + u32 ocv_uv = 0, ocv_raw = 0; + struct qpnp_qg *chip = data; + unsigned long rtc_sec = 0; + + qg_dbg(chip, QG_DEBUG_IRQ, "IRQ triggered\n"); + + mutex_lock(&chip->data_lock); + + rc = qg_read(chip, chip->qg_base + QG_STATUS2_REG, &status, 1); + if (rc < 0) { + pr_err("Failed to read status2 register rc=%d\n", rc); + goto done; + } + + if (!(status & GOOD_OCV_BIT)) + goto done; + + rc = qg_read_ocv(chip, &ocv_uv, &ocv_raw, S3_GOOD_OCV); + if (rc < 0) { + pr_err("Failed to read good_ocv, rc=%d\n", rc); + goto done; + } + + get_rtc_time(&rtc_sec); + chip->kdata.fifo_time = (u32)rtc_sec; + chip->kdata.param[QG_GOOD_OCV_UV].data = ocv_uv; + chip->kdata.param[QG_GOOD_OCV_UV].valid = true; + + vote(chip->awake_votable, GOOD_OCV_VOTER, true, 0); + + /* signal the readd thread */ + chip->data_ready = true; + wake_up_interruptible(&chip->qg_wait_q); +done: + mutex_unlock(&chip->data_lock); + return IRQ_HANDLED; +} + +static struct qg_irq_info qg_irqs[] = { + [QG_BATT_MISSING_IRQ] = { + .name = "qg-batt-missing", + }, + [QG_VBATT_LOW_IRQ] = { + .name = "qg-vbat-low", + .handler = qg_vbat_low_handler, + .wake = true, + }, + [QG_VBATT_EMPTY_IRQ] = { + .name = "qg-vbat-empty", + .handler = qg_vbat_empty_handler, + .wake = true, + }, + [QG_FIFO_UPDATE_DONE_IRQ] = { + .name = "qg-fifo-done", + .handler = qg_fifo_update_done_handler, + .wake = true, + }, + [QG_GOOD_OCV_IRQ] = { + .name = "qg-good-ocv", + .handler = qg_good_ocv_handler, + .wake = true, + }, + [QG_FSM_STAT_CHG_IRQ] = { + .name = "qg-fsm-state-chg", + }, + [QG_EVENT_IRQ] = { + .name = "qg-event", + }, +}; + +static int qg_awake_cb(struct votable *votable, void *data, int awake, + const char *client) +{ + struct qpnp_qg *chip = data; + + /* ignore if the QG device is not open */ + if (!chip->qg_device_open) + return 0; + + if (awake) + pm_stay_awake(chip->dev); + else + pm_relax(chip->dev); + + pr_debug("client: %s awake: %d\n", client, awake); + return 0; +} + +static int qg_fifo_irq_disable_cb(struct votable *votable, void *data, + int disable, const char *client) +{ + if (disable) { + if (qg_irqs[QG_FIFO_UPDATE_DONE_IRQ].wake) + disable_irq_wake( + qg_irqs[QG_FIFO_UPDATE_DONE_IRQ].irq); + if (qg_irqs[QG_FIFO_UPDATE_DONE_IRQ].irq) + disable_irq_nosync( + qg_irqs[QG_FIFO_UPDATE_DONE_IRQ].irq); + } else { + if (qg_irqs[QG_FIFO_UPDATE_DONE_IRQ].irq) + enable_irq(qg_irqs[QG_FIFO_UPDATE_DONE_IRQ].irq); + if (qg_irqs[QG_FIFO_UPDATE_DONE_IRQ].wake) + enable_irq_wake( + qg_irqs[QG_FIFO_UPDATE_DONE_IRQ].irq); + } + + return 0; +} + +static int qg_vbatt_irq_disable_cb(struct votable *votable, void *data, + int disable, const char *client) +{ + if (disable) { + if (qg_irqs[QG_VBATT_LOW_IRQ].wake) + disable_irq_wake(qg_irqs[QG_VBATT_LOW_IRQ].irq); + if (qg_irqs[QG_VBATT_EMPTY_IRQ].wake) + disable_irq_wake(qg_irqs[QG_VBATT_EMPTY_IRQ].irq); + if (qg_irqs[QG_VBATT_LOW_IRQ].irq) + disable_irq_nosync(qg_irqs[QG_VBATT_LOW_IRQ].irq); + if (qg_irqs[QG_VBATT_EMPTY_IRQ].irq) + disable_irq_nosync(qg_irqs[QG_VBATT_EMPTY_IRQ].irq); + } else { + if (qg_irqs[QG_VBATT_LOW_IRQ].irq) + enable_irq(qg_irqs[QG_VBATT_LOW_IRQ].irq); + if (qg_irqs[QG_VBATT_EMPTY_IRQ].irq) + enable_irq(qg_irqs[QG_VBATT_EMPTY_IRQ].irq); + if (qg_irqs[QG_VBATT_LOW_IRQ].wake) + enable_irq_wake(qg_irqs[QG_VBATT_LOW_IRQ].irq); + if (qg_irqs[QG_VBATT_EMPTY_IRQ].wake) + enable_irq_wake(qg_irqs[QG_VBATT_EMPTY_IRQ].irq); + } + + return 0; +} + +static int qg_good_ocv_irq_disable_cb(struct votable *votable, void *data, + int disable, const char *client) +{ + if (disable) { + if (qg_irqs[QG_GOOD_OCV_IRQ].wake) + disable_irq_wake(qg_irqs[QG_GOOD_OCV_IRQ].irq); + if (qg_irqs[QG_GOOD_OCV_IRQ].irq) + disable_irq_nosync(qg_irqs[QG_GOOD_OCV_IRQ].irq); + } else { + if (qg_irqs[QG_GOOD_OCV_IRQ].irq) + enable_irq(qg_irqs[QG_GOOD_OCV_IRQ].irq); + if (qg_irqs[QG_GOOD_OCV_IRQ].wake) + enable_irq_wake(qg_irqs[QG_GOOD_OCV_IRQ].irq); + } + + return 0; +} + +/* ALG callback functions below */ + +static int qg_get_learned_capacity(void *data, int64_t *learned_cap_uah) +{ + struct qpnp_qg *chip = data; + int16_t cc_mah; + int rc; + + if (!chip) + return -ENODEV; + + if (chip->battery_missing || !chip->profile_loaded) + return -ENODEV; + + rc = qg_sdam_multibyte_read(QG_SDAM_LEARNED_CAPACITY_OFFSET, + (u8 *)&cc_mah, 2); + if (rc < 0) { + pr_err("Error in reading learned_capacity, rc=%d\n", rc); + return rc; + } + *learned_cap_uah = cc_mah * 1000; + + return 0; +} + +static int qg_store_learned_capacity(void *data, int64_t learned_cap_uah) +{ + struct qpnp_qg *chip = data; + int16_t cc_mah; + int rc; + + if (!chip) + return -ENODEV; + + if (chip->battery_missing || !learned_cap_uah) + return -ENODEV; + + cc_mah = div64_s64(learned_cap_uah, 1000); + rc = qg_sdam_multibyte_write(QG_SDAM_LEARNED_CAPACITY_OFFSET, + (u8 *)&cc_mah, 2); + if (rc < 0) { + pr_err("Error in writing learned_capacity, rc=%d\n", rc); + return rc; + } + + qg_dbg(chip, QG_DEBUG_ALG_CL, "Stored learned capacity %llduah\n", + learned_cap_uah); + return 0; +} + +static int qg_get_batt_age_level(void *data, u32 *batt_age_level) +{ + struct qpnp_qg *chip = data; + int rc; + + if (!chip) + return -ENODEV; + + if (chip->battery_missing || is_debug_batt_id(chip)) + return -ENODEV; + + *batt_age_level = 0; + rc = qg_sdam_read(SDAM_BATT_AGE_LEVEL, batt_age_level); + if (rc < 0) { + pr_err("Error in reading batt_age_level, rc=%d\n", rc); + return rc; + } + + return 0; +} + +static int qg_store_batt_age_level(void *data, u32 batt_age_level) +{ + struct qpnp_qg *chip = data; + int rc; + + if (!chip) + return -ENODEV; + + if (chip->battery_missing) + return -ENODEV; + + rc = qg_sdam_write(SDAM_BATT_AGE_LEVEL, batt_age_level); + if (rc < 0) { + pr_err("Error in writing batt_age_level, rc=%d\n", rc); + return rc; + } + + return 0; +} + +static int qg_get_cc_soc(void *data, int *cc_soc) +{ + struct qpnp_qg *chip = data; + + if (!chip) + return -ENODEV; + + if (is_debug_batt_id(chip) || chip->battery_missing) { + *cc_soc = -EINVAL; + return 0; + } + + if (chip->cc_soc == INT_MIN) + *cc_soc = -EINVAL; + else + *cc_soc = chip->cc_soc; + + return 0; +} + +static int qg_restore_cycle_count(void *data, u16 *buf, int length) +{ + struct qpnp_qg *chip = data; + int id, rc = 0; + u8 tmp[2]; + + if (!chip) + return -ENODEV; + + if (chip->battery_missing || !chip->profile_loaded) + return -ENODEV; + + if (!buf || length > BUCKET_COUNT) + return -EINVAL; + + for (id = 0; id < length; id++) { + rc = qg_sdam_multibyte_read( + QG_SDAM_CYCLE_COUNT_OFFSET + (id * 2), + (u8 *)tmp, 2); + if (rc < 0) { + pr_err("failed to read bucket %d rc=%d\n", id, rc); + return rc; + } + *buf++ = tmp[0] | tmp[1] << 8; + } + + return rc; +} + +static int qg_store_cycle_count(void *data, u16 *buf, int id, int length) +{ + struct qpnp_qg *chip = data; + int rc = 0; + + if (!chip) + return -ENODEV; + + if (chip->battery_missing || !chip->profile_loaded) + return -ENODEV; + + if (!buf || length > BUCKET_COUNT * 2 || id < 0 || + id > BUCKET_COUNT - 1 || + (((id * 2) + length) > BUCKET_COUNT * 2)) + return -EINVAL; + + rc = qg_sdam_multibyte_write( + QG_SDAM_CYCLE_COUNT_OFFSET + (id * 2), + (u8 *)buf, length); + if (rc < 0) + pr_err("failed to write bucket %d rc=%d\n", id, rc); + + return rc; +} + +#define DEFAULT_BATT_TYPE "Unknown Battery" +#define MISSING_BATT_TYPE "Missing Battery" +#define DEBUG_BATT_TYPE "Debug Board" +static const char *qg_get_battery_type(struct qpnp_qg *chip) +{ + if (chip->battery_missing) + return MISSING_BATT_TYPE; + + if (is_debug_batt_id(chip)) + return DEBUG_BATT_TYPE; + + if (chip->bp.batt_type_str) { + if (chip->profile_loaded) + return chip->bp.batt_type_str; + } + + return DEFAULT_BATT_TYPE; +} + +#define DEBUG_BATT_SOC 67 +#define BATT_MISSING_SOC 50 +#define EMPTY_SOC 0 +#define FULL_SOC 100 +static int qg_get_battery_capacity(struct qpnp_qg *chip, int *soc) +{ + if (is_debug_batt_id(chip)) { + *soc = DEBUG_BATT_SOC; + return 0; + } + + if (chip->battery_missing || !chip->profile_loaded) { + *soc = BATT_MISSING_SOC; + return 0; + } + + if (chip->charge_full) { + *soc = FULL_SOC; + return 0; + } + + mutex_lock(&chip->soc_lock); + + if (chip->dt.linearize_soc && chip->maint_soc > 0) + *soc = chip->maint_soc; + else + *soc = chip->msoc; + + mutex_unlock(&chip->soc_lock); + + return 0; +} + +static int qg_get_battery_capacity_real(struct qpnp_qg *chip, int *soc) +{ + mutex_lock(&chip->soc_lock); + *soc = chip->msoc; + mutex_unlock(&chip->soc_lock); + + return 0; +} + +static int qg_get_charge_counter(struct qpnp_qg *chip, int *charge_counter) +{ + int rc, cc_soc = 0; + int64_t temp = 0; + + if (is_debug_batt_id(chip) || chip->battery_missing) { + *charge_counter = -EINVAL; + return 0; + } + + rc = qg_get_learned_capacity(chip, &temp); + if (rc < 0 || !temp) + rc = qg_get_nominal_capacity((int *)&temp, 250, true); + + if (rc < 0) { + pr_err("Failed to get FCC for charge-counter rc=%d\n", rc); + return rc; + } + + cc_soc = CAP(0, 100, DIV_ROUND_CLOSEST(chip->cc_soc, 100)); + *charge_counter = div_s64(temp * cc_soc, 100); + + return 0; +} + +static int qg_get_power(struct qpnp_qg *chip, int *val, bool average) +{ + int rc, v_min, v_ocv, rbatt = 0, esr = 0; + s64 power; + + if (is_debug_batt_id(chip)) { + *val = -EINVAL; + return 0; + } + + v_min = chip->dt.sys_min_volt_mv * 1000; + + rc = qg_sdam_read(SDAM_OCV_UV, &v_ocv); + if (rc < 0) { + pr_err("Failed to read OCV rc=%d\n", rc); + return rc; + } + + rc = qg_sdam_read(SDAM_RBAT_MOHM, &rbatt); + if (rc < 0) { + pr_err("Failed to read T_RBAT rc=%d\n", rc); + return rc; + } + + rbatt *= 1000; /* uohms */ + esr = chip->esr_last * 1000; + + if (rbatt <= 0 || esr <= 0) { + pr_debug("Invalid rbatt/esr rbatt=%d esr=%d\n", rbatt, esr); + *val = -EINVAL; + return 0; + } + + power = (s64)v_min * (v_ocv - v_min); + + if (average) + power = div_s64(power, rbatt); + else + power = div_s64(power, esr); + + *val = power; + + qg_dbg(chip, QG_DEBUG_STATUS, "v_min=%d v_ocv=%d rbatt=%d esr=%d power=%lld\n", + v_min, v_ocv, rbatt, esr, power); + + return 0; +} + +static int qg_get_ttf_param(void *data, enum ttf_param param, int *val) +{ + union power_supply_propval prop = {0, }; + struct qpnp_qg *chip = data; + int rc = 0; + int64_t temp = 0; + + if (!chip) + return -ENODEV; + + switch (param) { + case TTF_TTE_VALID: + *val = 1; + if (chip->battery_missing || is_debug_batt_id(chip)) + *val = 0; + break; + case TTF_MSOC: + rc = qg_get_battery_capacity(chip, val); + break; + case TTF_VBAT: + rc = qg_get_battery_voltage(chip, val); + break; + case TTF_IBAT: + rc = qg_get_battery_current(chip, val); + break; + case TTF_FCC: + if (chip->qg_psy) { + rc = power_supply_get_property(chip->qg_psy, + POWER_SUPPLY_PROP_CHARGE_FULL, &prop); + if (rc >= 0) { + temp = div64_u64(prop.intval, 1000); + *val = div64_u64(chip->full_soc * temp, + QG_SOC_FULL); + } + } + break; + case TTF_MODE: + if (chip->ttf->step_chg_cfg_valid) + *val = TTF_MODE_VBAT_STEP_CHG; + else + *val = TTF_MODE_NORMAL; + break; + case TTF_ITERM: + if (chip->chg_iterm_ma == INT_MIN) + *val = 0; + else + *val = chip->chg_iterm_ma; + break; + case TTF_RBATT: + rc = qg_sdam_read(SDAM_RBAT_MOHM, val); + if (!rc) + *val *= 1000; + break; + case TTF_VFLOAT: + *val = chip->bp.float_volt_uv; + break; + case TTF_CHG_TYPE: + *val = chip->charge_type; + break; + case TTF_CHG_STATUS: + *val = chip->charge_status; + break; + case TTF_CHG_DONE: + *val = chip->charge_done; + break; + default: + pr_err("Unsupported property %d\n", param); + rc = -EINVAL; + break; + } + + return rc; +} + +static int qg_ttf_awake_voter(void *data, bool val) +{ + struct qpnp_qg *chip = data; + + if (!chip) + return -ENODEV; + + if (chip->battery_missing || !chip->profile_loaded) + return -ENODEV; + + vote(chip->awake_votable, TTF_AWAKE_VOTER, val, 0); + + return 0; +} + +#define MAX_QG_OK_RETRIES 20 +static int qg_reset(struct qpnp_qg *chip) +{ + int rc = 0, count = 0, soc = 0; + u32 ocv_uv = 0, ocv_raw = 0; + u8 reg = 0; + + qg_dbg(chip, QG_DEBUG_STATUS, "QG RESET triggered\n"); + + mutex_lock(&chip->data_lock); + + /* hold and release master to clear FIFO's */ + rc = qg_master_hold(chip, true); + if (rc < 0) { + pr_err("Failed to hold master, rc=%d\n", rc); + goto done; + } + + /* delay for the master-hold */ + msleep(20); + + rc = qg_master_hold(chip, false); + if (rc < 0) { + pr_err("Failed to release master, rc=%d\n", rc); + goto done; + } + + /* delay for master to settle */ + msleep(20); + + qg_get_battery_voltage(chip, &rc); + qg_get_battery_capacity(chip, &soc); + qg_dbg(chip, QG_DEBUG_STATUS, "VBAT=%duV SOC=%d\n", rc, soc); + + /* Trigger S7 */ + rc = qg_masked_write(chip, chip->qg_base + QG_STATE_TRIG_CMD_REG, + S7_PON_OCV_START, S7_PON_OCV_START); + if (rc < 0) { + pr_err("Failed to trigger S7, rc=%d\n", rc); + goto done; + } + + /* poll for QG OK */ + do { + rc = qg_read(chip, chip->qg_base + QG_STATUS1_REG, ®, 1); + if (rc < 0) { + pr_err("Failed to read STATUS1_REG rc=%d\n", rc); + goto done; + } + + if (reg & QG_OK_BIT) + break; + + msleep(200); + count++; + } while (count < MAX_QG_OK_RETRIES); + + if (count == MAX_QG_OK_RETRIES) { + qg_dbg(chip, QG_DEBUG_STATUS, "QG_OK not set\n"); + goto done; + } + + /* read S7 PON OCV */ + rc = qg_read_ocv(chip, &ocv_uv, &ocv_raw, S7_PON_OCV); + if (rc < 0) { + pr_err("Failed to read PON OCV rc=%d\n", rc); + goto done; + } + + qg_dbg(chip, QG_DEBUG_STATUS, "S7_OCV = %duV\n", ocv_uv); + + chip->kdata.param[QG_GOOD_OCV_UV].data = ocv_uv; + chip->kdata.param[QG_GOOD_OCV_UV].valid = true; + /* clear all the userspace data */ + chip->kdata.param[QG_CLEAR_LEARNT_DATA].data = 1; + chip->kdata.param[QG_CLEAR_LEARNT_DATA].valid = true; + + vote(chip->awake_votable, GOOD_OCV_VOTER, true, 0); + /* signal the read thread */ + chip->data_ready = true; + chip->force_soc = true; + wake_up_interruptible(&chip->qg_wait_q); + +done: + mutex_unlock(&chip->data_lock); + return rc; +} + +static int qg_setprop_batt_age_level(struct qpnp_qg *chip, int batt_age_level) +{ + int rc = 0; + u16 data = 0; + + if (!chip->dt.multi_profile_load) + return 0; + + if (batt_age_level < 0) { + pr_err("Invalid age-level %d\n", batt_age_level); + return -EINVAL; + } + + if (chip->batt_age_level == batt_age_level) { + qg_dbg(chip, QG_DEBUG_PROFILE, "Same age-level %d\n", + chip->batt_age_level); + return 0; + } + + chip->batt_age_level = batt_age_level; + rc = qg_load_battery_profile(chip); + if (rc < 0) { + pr_err("failed to load profile\n"); + } else { + rc = qg_store_batt_age_level(chip, batt_age_level); + if (rc < 0) + pr_err("error in storing batt_age_level rc =%d\n", rc); + } + + /* Clear the learned capacity on loading a new profile */ + rc = qg_sdam_multibyte_write(QG_SDAM_LEARNED_CAPACITY_OFFSET, + (u8 *)&data, 2); + + if (rc < 0) + pr_err("Failed to clear SDAM learnt capacity rc=%d\n", rc); + + qg_dbg(chip, QG_DEBUG_PROFILE, "Profile with batt_age_level = %d loaded\n", + chip->batt_age_level); + + return rc; +} + +static int qg_psy_set_property(struct power_supply *psy, + enum power_supply_property psp, + const union power_supply_propval *pval) +{ + struct qpnp_qg *chip = power_supply_get_drvdata(psy); + int rc = 0; + + switch (psp) { + case POWER_SUPPLY_PROP_CHARGE_FULL: + if (chip->dt.cl_disable) { + pr_warn("Capacity learning disabled!\n"); + return 0; + } + if (chip->cl->active) { + pr_warn("Capacity learning active!\n"); + return 0; + } + if (pval->intval <= 0 || pval->intval > chip->cl->nom_cap_uah) { + pr_err("charge_full is out of bounds\n"); + return -EINVAL; + } + mutex_lock(&chip->cl->lock); + rc = qg_store_learned_capacity(chip, pval->intval); + if (!rc) + chip->cl->learned_cap_uah = pval->intval; + mutex_unlock(&chip->cl->lock); + break; + case POWER_SUPPLY_PROP_SOH: + chip->soh = pval->intval; + qg_dbg(chip, QG_DEBUG_STATUS, "SOH update: SOH=%d esr_actual=%d esr_nominal=%d\n", + chip->soh, chip->esr_actual, chip->esr_nominal); + if (chip->sp) + soh_profile_update(chip->sp, chip->soh); + break; + case POWER_SUPPLY_PROP_ESR_ACTUAL: + chip->esr_actual = pval->intval; + break; + case POWER_SUPPLY_PROP_ESR_NOMINAL: + chip->esr_nominal = pval->intval; + break; + case POWER_SUPPLY_PROP_FG_RESET: + qg_reset(chip); + break; + case POWER_SUPPLY_PROP_BATT_AGE_LEVEL: + rc = qg_setprop_batt_age_level(chip, pval->intval); + break; + default: + break; + } + return 0; +} + +static int qg_psy_get_property(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *pval) +{ + struct qpnp_qg *chip = power_supply_get_drvdata(psy); + int rc = 0; + int64_t temp = 0; + + pval->intval = 0; + + switch (psp) { + case POWER_SUPPLY_PROP_CAPACITY: + rc = qg_get_battery_capacity(chip, &pval->intval); + break; + case POWER_SUPPLY_PROP_CAPACITY_RAW: + pval->intval = chip->sys_soc; + break; + case POWER_SUPPLY_PROP_REAL_CAPACITY: + rc = qg_get_battery_capacity_real(chip, &pval->intval); + break; + case POWER_SUPPLY_PROP_VOLTAGE_NOW: + rc = qg_get_battery_voltage(chip, &pval->intval); + break; + case POWER_SUPPLY_PROP_CURRENT_NOW: + rc = qg_get_battery_current(chip, &pval->intval); + break; + case POWER_SUPPLY_PROP_VOLTAGE_OCV: + rc = qg_sdam_read(SDAM_OCV_UV, &pval->intval); + break; + case POWER_SUPPLY_PROP_TEMP: + rc = qg_get_battery_temp(chip, &pval->intval); + break; + case POWER_SUPPLY_PROP_RESISTANCE_ID: + #ifdef OPLUS_FEATURE_CHG_BASIC + pval->intval = chip->batt_id_kohm * 1000; + #else + pval->intval = chip->batt_id_ohm; + #endif + break; + case POWER_SUPPLY_PROP_DEBUG_BATTERY: + pval->intval = is_debug_batt_id(chip); + break; + case POWER_SUPPLY_PROP_RESISTANCE: + rc = qg_sdam_read(SDAM_RBAT_MOHM, &pval->intval); + if (!rc) + pval->intval *= 1000; + break; + case POWER_SUPPLY_PROP_RESISTANCE_NOW: + pval->intval = chip->esr_last; + break; + case POWER_SUPPLY_PROP_SOC_REPORTING_READY: + pval->intval = chip->soc_reporting_ready; + break; + case POWER_SUPPLY_PROP_RESISTANCE_CAPACITIVE: + pval->intval = chip->dt.rbat_conn_mohm; + break; + case POWER_SUPPLY_PROP_BATTERY_TYPE: + pval->strval = qg_get_battery_type(chip); + break; + case POWER_SUPPLY_PROP_VOLTAGE_MIN: + pval->intval = chip->dt.vbatt_cutoff_mv * 1000; + break; + case POWER_SUPPLY_PROP_VOLTAGE_MAX: +#ifdef OPLUS_FEATURE_CHG_BASIC + if (chip->asic_with_internal_gauge){ + if(oplus_vooc_get_fastchg_ing()) { + chip->bp.float_volt_uv = 4400000; + } else if (0 == oplus_chg_get_ffc_status()){ + chip->bp.float_volt_uv = 4400000; + } + pr_err("kilody: float_volt_uv=%d\n", chip->bp.float_volt_uv); + } +#endif + pval->intval = chip->bp.float_volt_uv; + break; + case POWER_SUPPLY_PROP_BATT_FULL_CURRENT: + pval->intval = chip->dt.iterm_ma * 1000; + break; + case POWER_SUPPLY_PROP_BATT_PROFILE_VERSION: + pval->intval = chip->bp.qg_profile_version; + break; + case POWER_SUPPLY_PROP_CHARGE_COUNTER: + rc = qg_get_charge_counter(chip, &pval->intval); + break; + case POWER_SUPPLY_PROP_CHARGE_FULL: + if (!chip->dt.cl_disable && chip->dt.cl_feedback_on) + rc = qg_get_learned_capacity(chip, &temp); + else + rc = qg_get_nominal_capacity((int *)&temp, 250, true); + if (!rc) + pval->intval = (int)temp; + break; + case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: + rc = qg_get_nominal_capacity((int *)&temp, 250, true); + if (!rc) + pval->intval = (int)temp; + break; + case POWER_SUPPLY_PROP_CYCLE_COUNTS: + rc = get_cycle_counts(chip->counter, &pval->strval); + if (rc < 0) + pval->strval = NULL; + break; + case POWER_SUPPLY_PROP_CYCLE_COUNT: + rc = get_cycle_count(chip->counter, &pval->intval); + break; + case POWER_SUPPLY_PROP_TIME_TO_FULL_AVG: + rc = ttf_get_time_to_full(chip->ttf, &pval->intval); + break; + case POWER_SUPPLY_PROP_TIME_TO_FULL_NOW: + rc = ttf_get_time_to_full(chip->ttf, &pval->intval); + break; + case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG: + rc = ttf_get_time_to_empty(chip->ttf, &pval->intval); + break; + case POWER_SUPPLY_PROP_ESR_ACTUAL: + pval->intval = (chip->esr_actual == -EINVAL) ? -EINVAL : + (chip->esr_actual * 1000); + break; + case POWER_SUPPLY_PROP_ESR_NOMINAL: + pval->intval = (chip->esr_nominal == -EINVAL) ? -EINVAL : + (chip->esr_nominal * 1000); + break; + case POWER_SUPPLY_PROP_SOH: + pval->intval = chip->soh; + break; + case POWER_SUPPLY_PROP_CC_SOC: + rc = qg_get_cc_soc(chip, &pval->intval); + break; + case POWER_SUPPLY_PROP_VOLTAGE_AVG: + rc = qg_get_vbat_avg(chip, &pval->intval); + break; + case POWER_SUPPLY_PROP_CURRENT_AVG: + rc = qg_get_ibat_avg(chip, &pval->intval); + break; + case POWER_SUPPLY_PROP_POWER_NOW: + rc = qg_get_power(chip, &pval->intval, false); + break; + case POWER_SUPPLY_PROP_POWER_AVG: + rc = qg_get_power(chip, &pval->intval, true); + break; + case POWER_SUPPLY_PROP_SCALE_MODE_EN: + pval->intval = chip->fvss_active; + break; + case POWER_SUPPLY_PROP_BATT_AGE_LEVEL: + pval->intval = chip->batt_age_level; + break; +#ifdef OPLUS_FEATURE_CHG_BASIC + case POWER_SUPPLY_PROP_PARALLEL_CURRENT_NOW: + rc = qg_get_parallel_current_now(chip, &pval->intval); + break; +#endif + default: + pr_debug("Unsupported property %d\n", psp); + break; + } + + return rc; +} + +static int qg_property_is_writeable(struct power_supply *psy, + enum power_supply_property psp) +{ + switch (psp) { + case POWER_SUPPLY_PROP_CHARGE_FULL: + case POWER_SUPPLY_PROP_ESR_ACTUAL: + case POWER_SUPPLY_PROP_ESR_NOMINAL: + case POWER_SUPPLY_PROP_SOH: + case POWER_SUPPLY_PROP_FG_RESET: + case POWER_SUPPLY_PROP_BATT_AGE_LEVEL: + return 1; + default: + break; + } + return 0; +} + +static enum power_supply_property qg_psy_props[] = { + POWER_SUPPLY_PROP_CAPACITY, + POWER_SUPPLY_PROP_CAPACITY_RAW, + POWER_SUPPLY_PROP_REAL_CAPACITY, + POWER_SUPPLY_PROP_TEMP, + POWER_SUPPLY_PROP_VOLTAGE_NOW, + POWER_SUPPLY_PROP_VOLTAGE_OCV, + POWER_SUPPLY_PROP_CURRENT_NOW, + POWER_SUPPLY_PROP_CHARGE_COUNTER, + POWER_SUPPLY_PROP_RESISTANCE, + POWER_SUPPLY_PROP_RESISTANCE_ID, + POWER_SUPPLY_PROP_RESISTANCE_NOW, + POWER_SUPPLY_PROP_SOC_REPORTING_READY, + POWER_SUPPLY_PROP_RESISTANCE_CAPACITIVE, + POWER_SUPPLY_PROP_DEBUG_BATTERY, + POWER_SUPPLY_PROP_BATTERY_TYPE, + POWER_SUPPLY_PROP_VOLTAGE_MIN, + POWER_SUPPLY_PROP_VOLTAGE_MAX, + POWER_SUPPLY_PROP_BATT_FULL_CURRENT, + POWER_SUPPLY_PROP_BATT_PROFILE_VERSION, + POWER_SUPPLY_PROP_CYCLE_COUNT, + POWER_SUPPLY_PROP_CYCLE_COUNTS, + POWER_SUPPLY_PROP_CHARGE_FULL, + POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, + POWER_SUPPLY_PROP_TIME_TO_FULL_AVG, + POWER_SUPPLY_PROP_TIME_TO_FULL_NOW, + POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG, + POWER_SUPPLY_PROP_ESR_ACTUAL, + POWER_SUPPLY_PROP_ESR_NOMINAL, + POWER_SUPPLY_PROP_SOH, + POWER_SUPPLY_PROP_CC_SOC, + POWER_SUPPLY_PROP_FG_RESET, + POWER_SUPPLY_PROP_VOLTAGE_AVG, + POWER_SUPPLY_PROP_CURRENT_AVG, + POWER_SUPPLY_PROP_POWER_AVG, + POWER_SUPPLY_PROP_POWER_NOW, + POWER_SUPPLY_PROP_SCALE_MODE_EN, + POWER_SUPPLY_PROP_BATT_AGE_LEVEL, +#ifdef OPLUS_FEATURE_CHG_BASIC + POWER_SUPPLY_PROP_PARALLEL_CURRENT_NOW, +#endif +}; + +static const struct power_supply_desc qg_psy_desc = { + .name = "bms", + .type = POWER_SUPPLY_TYPE_BMS, + .properties = qg_psy_props, + .num_properties = ARRAY_SIZE(qg_psy_props), + .get_property = qg_psy_get_property, + .set_property = qg_psy_set_property, + .property_is_writeable = qg_property_is_writeable, +}; + +#define DEFAULT_CL_BEGIN_IBAT_UA (-100000) +static bool qg_cl_ok_to_begin(void *data) +{ + struct qpnp_qg *chip = data; + + if (chip->last_fifo_i_ua < DEFAULT_CL_BEGIN_IBAT_UA) + return true; + + return false; +} + +#define DEFAULT_RECHARGE_SOC 95 +static int qg_charge_full_update(struct qpnp_qg *chip) +{ + union power_supply_propval prop = {0, }; + int rc, recharge_soc, health; + + if (!chip->dt.hold_soc_while_full) + goto out; + + rc = power_supply_get_property(chip->batt_psy, + POWER_SUPPLY_PROP_HEALTH, &prop); + if (rc < 0) { + pr_err("Failed to get battery health, rc=%d\n", rc); + goto out; + } + health = prop.intval; + + rc = power_supply_get_property(chip->batt_psy, + POWER_SUPPLY_PROP_RECHARGE_SOC, &prop); + if (rc < 0 || prop.intval < 0) { + pr_debug("Failed to get recharge-soc\n"); + recharge_soc = DEFAULT_RECHARGE_SOC; + } else { + recharge_soc = prop.intval; + } + chip->recharge_soc = recharge_soc; + + qg_dbg(chip, QG_DEBUG_STATUS, "msoc=%d health=%d charge_full=%d charge_done=%d\n", + chip->msoc, health, chip->charge_full, + chip->charge_done); + if (chip->charge_done && !chip->charge_full) { +#ifdef OPLUS_FEATURE_CHG_BASIC + if (chip->msoc >= 99 && (health == POWER_SUPPLY_HEALTH_GOOD || health == POWER_SUPPLY_HEALTH_COOL)) { +#else + if (chip->msoc >= 99 && health == POWER_SUPPLY_HEALTH_GOOD) { +#endif + chip->charge_full = true; + qg_dbg(chip, QG_DEBUG_STATUS, "Setting charge_full (0->1) @ msoc=%d\n", + chip->msoc); + } else if (health != POWER_SUPPLY_HEALTH_GOOD) { + /* terminated in JEITA */ + qg_dbg(chip, QG_DEBUG_STATUS, "Terminated charging @ msoc=%d\n", + chip->msoc); + } + } else if ((!chip->charge_done || chip->msoc <= recharge_soc) + && chip->charge_full) { + + bool input_present = is_input_present(chip); + + /* + * force a recharge only if SOC <= recharge SOC and + * we have not started charging. + */ + if ((chip->wa_flags & QG_RECHARGE_SOC_WA) && + input_present && chip->msoc <= recharge_soc && + chip->charge_status != POWER_SUPPLY_STATUS_CHARGING) { + /* Force recharge */ + prop.intval = 0; + rc = power_supply_set_property(chip->batt_psy, + POWER_SUPPLY_PROP_FORCE_RECHARGE, &prop); + if (rc < 0) + pr_err("Failed to force recharge rc=%d\n", rc); + else + qg_dbg(chip, QG_DEBUG_STATUS, "Forced recharge\n"); + } + + + if (chip->charge_done) + return 0; /* wait for recharge */ + + /* + * If SOC has indeed dropped below recharge-SOC or + * the input is removed, if linearize-soc is set scale + * msoc from 100% for better UX. + */ + if (chip->msoc < recharge_soc || !input_present) { + if (chip->dt.linearize_soc) { + get_rtc_time(&chip->last_maint_soc_update_time); + chip->maint_soc = FULL_SOC; + qg_scale_soc(chip, false); + } + chip->charge_full = false; + qg_dbg(chip, QG_DEBUG_STATUS, "msoc=%d recharge_soc=%d charge_full (1->0)\n", + chip->msoc, recharge_soc); + } else { + /* continue with charge_full state */ + qg_dbg(chip, QG_DEBUG_STATUS, "msoc=%d recharge_soc=%d charge_full=%d input_present=%d\n", + chip->msoc, recharge_soc, + chip->charge_full, input_present); + } + } +out: + return 0; +} + +static int qg_parallel_status_update(struct qpnp_qg *chip) +{ + int rc; + bool parallel_enabled = is_parallel_enabled(chip); + bool update_smb = false; + + if (parallel_enabled == chip->parallel_enabled) + return 0; + + chip->parallel_enabled = parallel_enabled; + qg_dbg(chip, QG_DEBUG_STATUS, + "Parallel status changed Enabled=%d\n", parallel_enabled); + + mutex_lock(&chip->data_lock); + /* + * dt.qg_ext_sense = Uses external rsense, if defined do not + * enable SMB sensing (for non-CP parallel charger). + * dt.cp_iin_sns = Uses CP IIN_SNS, enable SMB sensing (for CP charger). + */ + if (is_cp_available(chip)) + update_smb = chip->dt.use_cp_iin_sns ? true : false; + else if (is_parallel_available(chip)) + update_smb = chip->dt.qg_ext_sense ? false : true; + + rc = process_rt_fifo_data(chip, update_smb); + if (rc < 0) + pr_err("Failed to process RT FIFO data, rc=%d\n", rc); + + mutex_unlock(&chip->data_lock); + + return 0; +} + +static int qg_input_status_update(struct qpnp_qg *chip) +{ + bool usb_present = is_usb_present(chip); + bool dc_present = is_dc_present(chip); + + if ((chip->usb_present != usb_present) || + (chip->dc_present != dc_present)) { + qg_dbg(chip, QG_DEBUG_STATUS, + "Input status changed usb_present=%d dc_present=%d\n", + usb_present, dc_present); + qg_scale_soc(chip, false); + } + + chip->usb_present = usb_present; + chip->dc_present = dc_present; + + return 0; +} + +static int qg_handle_battery_removal(struct qpnp_qg *chip) +{ + int rc, length = QG_SDAM_MAX_OFFSET - QG_SDAM_VALID_OFFSET; + u8 *data; + + /* clear SDAM */ + data = kcalloc(length, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + rc = qg_sdam_multibyte_write(QG_SDAM_VALID_OFFSET, data, length); + if (rc < 0) + pr_err("Failed to clear SDAM rc=%d\n", rc); + + return rc; +} + +static int qg_handle_battery_insertion(struct qpnp_qg *chip) +{ + int rc, count = 0; + u32 ocv_uv = 0, ocv_raw = 0; + u8 reg = 0; + + do { + rc = qg_read(chip, chip->qg_base + QG_STATUS1_REG, ®, 1); + if (rc < 0) { + pr_err("Failed to read STATUS1_REG rc=%d\n", rc); + return rc; + } + + if (reg & QG_OK_BIT) + break; + + msleep(200); + count++; + } while (count < MAX_QG_OK_RETRIES); + + if (count == MAX_QG_OK_RETRIES) { + qg_dbg(chip, QG_DEBUG_STATUS, "QG_OK not set!\n"); + return 0; + } + + /* read S7 PON OCV */ + rc = qg_read_ocv(chip, &ocv_uv, &ocv_raw, S7_PON_OCV); + if (rc < 0) { + pr_err("Failed to read PON OCV rc=%d\n", rc); + return rc; + } + + qg_dbg(chip, QG_DEBUG_STATUS, + "S7_OCV on battery insertion = %duV\n", ocv_uv); + + chip->kdata.param[QG_GOOD_OCV_UV].data = ocv_uv; + chip->kdata.param[QG_GOOD_OCV_UV].valid = true; + /* clear all the userspace data */ + chip->kdata.param[QG_CLEAR_LEARNT_DATA].data = 1; + chip->kdata.param[QG_CLEAR_LEARNT_DATA].valid = true; + + vote(chip->awake_votable, GOOD_OCV_VOTER, true, 0); + /* signal the read thread */ + chip->data_ready = true; + wake_up_interruptible(&chip->qg_wait_q); + + return 0; +} + +static int qg_battery_status_update(struct qpnp_qg *chip) +{ + int rc; + union power_supply_propval prop = {0, }; + + if (!is_batt_available(chip)) + return 0; + + mutex_lock(&chip->data_lock); + + rc = power_supply_get_property(chip->batt_psy, + POWER_SUPPLY_PROP_PRESENT, &prop); + if (rc < 0) { + pr_err("Failed to get battery-present, rc=%d\n", rc); + goto done; + } + + #ifdef OPLUS_FEATURE_CHG_BASIC + if (prop.intval) //battery present + { + if (!is_batt_id_valid(chip)) { + prop.intval = 0; + } + } + #endif + + if (chip->battery_missing && prop.intval) { + pr_warn("Battery inserted!\n"); + rc = qg_handle_battery_insertion(chip); + if (rc < 0) + pr_err("Failed in battery-insertion rc=%d\n", rc); + } else if (!chip->battery_missing && !prop.intval) { + pr_warn("Battery removed!\n"); + rc = qg_handle_battery_removal(chip); + if (rc < 0) + pr_err("Failed in battery-removal rc=%d\n", rc); + } + pr_info("qg_battery_status_update battery_missing = %d prop.intval = %d is_batt_id_valid = %d\n",chip->battery_missing, prop.intval,is_batt_id_valid(chip)); + + chip->battery_missing = !prop.intval; + +done: + mutex_unlock(&chip->data_lock); + return rc; +} + +static void qg_sleep_exit_work(struct work_struct *work) +{ + int rc; + struct qpnp_qg *chip = container_of(work, + struct qpnp_qg, qg_sleep_exit_work.work); + + vote(chip->awake_votable, SLEEP_EXIT_VOTER, true, 0); + + mutex_lock(&chip->data_lock); + /* + * if this work is executing, the system has been active + * for a while. So, force back the S2 active configuration + */ + qg_dbg(chip, QG_DEBUG_STATUS, "sleep_exit_work: exit S2_SLEEP\n"); + rc = qg_config_s2_state(chip, S2_SLEEP, false, true); + if (rc < 0) + pr_err("Failed to exit S2_SLEEP rc=%d\n", rc); + + vote(chip->awake_votable, SLEEP_EXIT_DATA_VOTER, true, 0); + /* signal the read thread */ + chip->data_ready = true; + wake_up_interruptible(&chip->qg_wait_q); + + mutex_unlock(&chip->data_lock); + + vote(chip->awake_votable, SLEEP_EXIT_VOTER, false, 0); +} +static int qg_charge_done_update(struct qpnp_qg *chip) +{ + union power_supply_propval prop = {0,}; + int rc, health; + unsigned long rtc_sec = 0; + + rc = power_supply_get_property(chip->batt_psy, POWER_SUPPLY_PROP_HEALTH, &prop); + if (rc < 0) { + pr_err("Failed to get battery health, rc=%d\n", rc); + goto out; + } + health = prop.intval; + mutex_lock(&chip->data_lock); + + if (chip->charge_done && chip->catch_up_soc != 100 && chip->msoc >= 90 && health == POWER_SUPPLY_HEALTH_GOOD) { + chg_err("qg_charge_done_update in\n"); + + get_rtc_time(&rtc_sec); + chip->kdata.fifo_time = (u32)rtc_sec; + chip->kdata.param[QG_GOOD_OCV_UV].data = 4415000; + chip->kdata.param[QG_GOOD_OCV_UV].valid = true; + + vote(chip->awake_votable,GOOD_OCV_VOTER,true,0); + + // signal the read thread + chip->data_ready = true; + wake_up_interruptible(&chip->qg_wait_q); + } + mutex_unlock(&chip->data_lock); +out: + return 0; +} + +static void qg_status_change_work(struct work_struct *work) +{ + struct qpnp_qg *chip = container_of(work, + struct qpnp_qg, qg_status_change_work); + union power_supply_propval prop = {0, }; + int rc = 0, batt_temp = 0; + bool input_present = false; + + if (!is_batt_available(chip)) { + pr_debug("batt-psy not available\n"); + goto out; + } + + rc = qg_battery_status_update(chip); + if (rc < 0) + pr_err("Failed to process battery status update rc=%d\n", rc); + + rc = power_supply_get_property(chip->batt_psy, + POWER_SUPPLY_PROP_CHARGE_TYPE, &prop); + if (rc < 0) + pr_err("Failed to get charge-type, rc=%d\n", rc); + else + chip->charge_type = prop.intval; + + rc = power_supply_get_property(chip->batt_psy, + POWER_SUPPLY_PROP_STATUS, &prop); + if (rc < 0) + pr_err("Failed to get charger status, rc=%d\n", rc); + else + chip->charge_status = prop.intval; + + rc = power_supply_get_property(chip->batt_psy, + POWER_SUPPLY_PROP_CHARGE_DONE, &prop); + if (rc < 0) + pr_err("Failed to get charge done status, rc=%d\n", rc); + else + chip->charge_done = prop.intval; + + qg_dbg(chip, QG_DEBUG_STATUS, "charge_status=%d charge_done=%d\n", + chip->charge_status, chip->charge_done); + + rc = qg_parallel_status_update(chip); + if (rc < 0) + pr_err("Failed to update parallel-status, rc=%d\n", rc); + + rc = qg_input_status_update(chip); + if (rc < 0) + pr_err("Failed to update input status, rc=%d\n", rc); + + /* get input status */ + input_present = is_input_present(chip); + + cycle_count_update(chip->counter, + DIV_ROUND_CLOSEST(chip->msoc * 255, 100), + chip->charge_status, chip->charge_done, + input_present); + + if (!chip->dt.cl_disable) { + rc = qg_get_battery_temp(chip, &batt_temp); + if (rc < 0) { + pr_err("Failed to read BATT_TEMP at PON rc=%d\n", rc); + } else if (chip->batt_soc >= 0) { + cap_learning_update(chip->cl, batt_temp, chip->batt_soc, + chip->charge_status, chip->charge_done, + input_present, false); + } + } + rc = qg_charge_full_update(chip); + if (rc < 0) + pr_err("Failed in charge_full_update, rc=%d\n", rc); + if (chip->asic_with_internal_gauge) + qg_charge_done_update(chip); + ttf_update(chip->ttf, input_present); +out: + pm_relax(chip->dev); +} + +static int qg_notifier_cb(struct notifier_block *nb, + unsigned long event, void *data) +{ + struct power_supply *psy = data; + struct qpnp_qg *chip = container_of(nb, struct qpnp_qg, nb); + + if (event != PSY_EVENT_PROP_CHANGED) + return NOTIFY_OK; + + if (work_pending(&chip->qg_status_change_work)) + return NOTIFY_OK; + + if ((strcmp(psy->desc->name, "battery") == 0) + || (strcmp(psy->desc->name, "parallel") == 0) + || (strcmp(psy->desc->name, "usb") == 0) + || (strcmp(psy->desc->name, "dc") == 0) + || (strcmp(psy->desc->name, "charge_pump_master") == 0)) { + /* + * We cannot vote for awake votable here as that takes + * a mutex lock and this is executed in an atomic context. + */ + pm_stay_awake(chip->dev); + schedule_work(&chip->qg_status_change_work); + } + + return NOTIFY_OK; +} + +static int qg_init_psy(struct qpnp_qg *chip) +{ + struct power_supply_config qg_psy_cfg = {}; + int rc; + + qg_psy_cfg.drv_data = chip; + qg_psy_cfg.of_node = chip->dev->of_node; + chip->qg_psy = devm_power_supply_register(chip->dev, + &qg_psy_desc, &qg_psy_cfg); + if (IS_ERR_OR_NULL(chip->qg_psy)) { + pr_err("Failed to register qg_psy rc = %ld\n", + PTR_ERR(chip->qg_psy)); + return -ENODEV; + } + + chip->nb.notifier_call = qg_notifier_cb; + rc = power_supply_reg_notifier(&chip->nb); + if (rc < 0) + pr_err("Failed register psy notifier rc = %d\n", rc); + + return rc; +} + +static ssize_t qg_device_read(struct file *file, char __user *buf, size_t count, + loff_t *ppos) +{ + int rc; + struct qpnp_qg *chip = file->private_data; + unsigned long data_size = sizeof(chip->kdata); + + if (count < data_size) { + pr_err("Invalid datasize %lu, expected lesser then %zu\n", + data_size, count); + return -EINVAL; + } + + /* non-blocking access, return */ + if (!chip->data_ready && (file->f_flags & O_NONBLOCK)) + return 0; + + /* blocking access wait on data_ready */ + if (!(file->f_flags & O_NONBLOCK)) { + rc = wait_event_interruptible(chip->qg_wait_q, + chip->data_ready); + if (rc < 0) { + pr_debug("Failed wait! rc=%d\n", rc); + return rc; + } + } + + mutex_lock(&chip->data_lock); + + if (!chip->data_ready) { + pr_debug("No Data, false wakeup\n"); + rc = -EFAULT; + goto fail_read; + } + + + if (copy_to_user(buf, &chip->kdata, data_size)) { + pr_err("Failed in copy_to_user\n"); + rc = -EFAULT; + goto fail_read; + } + chip->data_ready = false; + + /* release all wake sources */ + vote(chip->awake_votable, GOOD_OCV_VOTER, false, 0); + vote(chip->awake_votable, FIFO_DONE_VOTER, false, 0); + vote(chip->awake_votable, FIFO_RT_DONE_VOTER, false, 0); + vote(chip->awake_votable, SUSPEND_DATA_VOTER, false, 0); + vote(chip->awake_votable, SLEEP_EXIT_DATA_VOTER, false, 0); + + qg_dbg(chip, QG_DEBUG_DEVICE, + "QG device read complete Seq_no=%u Size=%ld\n", + chip->kdata.seq_no, data_size); + + /* clear data */ + memset(&chip->kdata, 0, sizeof(chip->kdata)); + + mutex_unlock(&chip->data_lock); + + return data_size; + +fail_read: + mutex_unlock(&chip->data_lock); + return rc; +} + +static ssize_t qg_device_write(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) +{ + int rc = -EINVAL; + struct qpnp_qg *chip = file->private_data; + unsigned long data_size = sizeof(chip->udata); + + mutex_lock(&chip->data_lock); + if (count == 0) { + pr_err("No data!\n"); + goto fail; + } + + if (count != 0 && count < data_size) { + pr_err("Invalid datasize %zu expected %lu\n", count, data_size); + goto fail; + } + + if (copy_from_user(&chip->udata, buf, data_size)) { + pr_err("Failed in copy_from_user\n"); + rc = -EFAULT; + goto fail; + } + + rc = data_size; + vote(chip->awake_votable, UDATA_READY_VOTER, true, 0); + schedule_work(&chip->udata_work); + qg_dbg(chip, QG_DEBUG_DEVICE, "QG write complete size=%d\n", rc); +fail: + mutex_unlock(&chip->data_lock); + return rc; +} + +static unsigned int qg_device_poll(struct file *file, poll_table *wait) +{ + struct qpnp_qg *chip = file->private_data; + unsigned int mask = 0; + + poll_wait(file, &chip->qg_wait_q, wait); + + if (chip->data_ready) + mask = POLLIN | POLLRDNORM; + + return mask; +} + +static int qg_device_open(struct inode *inode, struct file *file) +{ + struct qpnp_qg *chip = container_of(inode->i_cdev, + struct qpnp_qg, qg_cdev); + + file->private_data = chip; + chip->qg_device_open = true; + qg_dbg(chip, QG_DEBUG_DEVICE, "QG device opened!\n"); + + return 0; +} + +static int qg_device_release(struct inode *inode, struct file *file) +{ + struct qpnp_qg *chip = container_of(inode->i_cdev, + struct qpnp_qg, qg_cdev); + + file->private_data = chip; + chip->qg_device_open = false; + qg_dbg(chip, QG_DEBUG_DEVICE, "QG device closed!\n"); + + return 0; +} + +static const struct file_operations qg_fops = { + .owner = THIS_MODULE, + .open = qg_device_open, + .release = qg_device_release, + .read = qg_device_read, + .write = qg_device_write, + .poll = qg_device_poll, +}; + +static int qg_register_device(struct qpnp_qg *chip) +{ + int rc; + + rc = alloc_chrdev_region(&chip->dev_no, 0, 1, "qg"); + if (rc < 0) { + pr_err("Failed to allocate chardev rc=%d\n", rc); + return rc; + } + + cdev_init(&chip->qg_cdev, &qg_fops); + rc = cdev_add(&chip->qg_cdev, chip->dev_no, 1); + if (rc < 0) { + pr_err("Failed to cdev_add rc=%d\n", rc); + goto unregister_chrdev; + } + + chip->qg_class = class_create(THIS_MODULE, "qg"); + if (IS_ERR_OR_NULL(chip->qg_class)) { + pr_err("Failed to create qg class\n"); + rc = -EINVAL; + goto delete_cdev; + } + chip->qg_device = device_create(chip->qg_class, NULL, chip->dev_no, + NULL, "qg"); + if (IS_ERR(chip->qg_device)) { + pr_err("Failed to create qg_device\n"); + rc = -EINVAL; + goto destroy_class; + } + + qg_dbg(chip, QG_DEBUG_DEVICE, "'/dev/qg' successfully created\n"); + + return 0; + +destroy_class: + class_destroy(chip->qg_class); +delete_cdev: + cdev_del(&chip->qg_cdev); +unregister_chrdev: + unregister_chrdev_region(chip->dev_no, 1); + return rc; +} + +#define BID_RPULL_OHM 100000 +#define BID_VREF_MV 1875 +static int get_batt_id_ohm(struct qpnp_qg *chip, u32 *batt_id_ohm) +{ + int rc, batt_id_mv; + int64_t denom; + + /* Read battery-id */ + rc = iio_read_channel_processed(chip->batt_id_chan, &batt_id_mv); + if (rc < 0) { + pr_err("Failed to read BATT_ID over ADC, rc=%d\n", rc); + return rc; + } + + batt_id_mv = div_s64(batt_id_mv, 1000); + if (batt_id_mv == 0) { + pr_debug("batt_id_mv = 0 from ADC\n"); + return 0; + } + + denom = div64_s64(BID_VREF_MV * 1000, batt_id_mv) - 1000; + if (denom <= 0) { + /* batt id connector might be open, return 0 kohms */ + return 0; + } + + *batt_id_ohm = div64_u64(BID_RPULL_OHM * 1000 + denom / 2, denom); + + qg_dbg(chip, QG_DEBUG_PROFILE, "batt_id_mv=%d, batt_id_ohm=%d\n", + batt_id_mv, *batt_id_ohm); + + return 0; +} + +#ifdef OPLUS_FEATURE_CHG_BASIC +static int get_batt_id_voltage(struct qpnp_qg *chip) +{ + int rc, batt_id_mv; + + /* Read battery-id */ + rc = iio_read_channel_processed(chip->batt_id_chan, &batt_id_mv); + if (rc < 0) { + pr_err("Failed to read BATT_ID over ADC, rc=%d\n", rc); + return rc; + } + + batt_id_mv = div_s64(batt_id_mv, 1000); + qg_dbg(chip, QG_DEBUG_PROFILE, "batt_id_mv=%d from ADC\n",batt_id_mv); + + return batt_id_mv; +} + +struct batt_info +{ + u32 batt_id_ohm; + int batt_id_mv[2]; + char *batt_vendor; + char *batt_version; +}; + +struct proj_batt_info +{ + struct batt_info* batt_info; + int batt_vendor_count; + bool batt_devinfo_registered; +}; + +static struct batt_info rum_batt_info[1] = +{ + {100000, {790, 1040}, "ATL", "V1.0"} +}; + +static struct proj_batt_info proj_batterys = +{ + .batt_info = NULL, + .batt_vendor_count = 0, + .batt_devinfo_registered = false, +}; + +static bool is_batt_id_valid(struct qpnp_qg *chip) +{ + int id, rc, batt_id_voltage; + bool batt_id_valid = false; + unsigned int project_num = 0; + + batt_id_voltage = get_batt_id_voltage(chip); + if (batt_id_voltage < 0) { + pr_err("Failed to detect batt_id rc=%d\n", rc); + return true; + } + + project_num = get_project(); + if (project_num == 0) { + pr_err("Faile to get project number\n"); + return true; + } + + pr_debug("id_batt_id_valid project number=%u, battery id voltage=%d\n", + project_num, batt_id_voltage); + + proj_batterys.batt_info = rum_batt_info; + proj_batterys.batt_vendor_count = sizeof(rum_batt_info) / sizeof(struct batt_info); + + for (id = 0; id < proj_batterys.batt_vendor_count; id++) { + if(batt_id_voltage >= proj_batterys.batt_info[id].batt_id_mv[0] + && batt_id_voltage <= proj_batterys.batt_info[id].batt_id_mv[1]) { + if (!proj_batterys.batt_devinfo_registered) { + rc = register_device_proc("battery", "V1.0", proj_batterys.batt_info[id].batt_vendor); + if (rc) + pr_err("register_battery_devinfo fail\n"); + proj_batterys.batt_devinfo_registered = true; + } + batt_id_valid = true; + break; + } + } + return batt_id_valid; +} +#endif + +static int qg_load_battery_profile(struct qpnp_qg *chip) +{ + struct device_node *node = chip->dev->of_node; + struct device_node *profile_node; + int rc, tuple_len, len, i, avail_age_level = 0; + + chip->batt_node = of_find_node_by_name(node, "qcom,battery-data"); + if (!chip->batt_node) { + pr_err("Batterydata not available\n"); + return -ENXIO; + } + + if (chip->dt.multi_profile_load) { + if (chip->batt_age_level == -EINVAL) { + rc = qg_get_batt_age_level(chip, &chip->batt_age_level); + if (rc < 0) { + pr_err("error in retrieving batt age level rc=%d\n", + rc); + return rc; + } + } + profile_node = of_batterydata_get_best_aged_profile( + chip->batt_node, + chip->batt_id_ohm / 1000, + chip->batt_age_level, + &avail_age_level); + if (chip->batt_age_level != avail_age_level) { + qg_dbg(chip, QG_DEBUG_PROFILE, "Batt_age_level %d doesn't exist, using %d\n", + chip->batt_age_level, avail_age_level); + chip->batt_age_level = avail_age_level; + } + } else { + #ifdef OPLUS_FEATURE_CHG_BASIC + /* profile_node = of_batterydata_get_best_profile(chip->batt_node, + chip->batt_id_ohm / 1000, NULL); */ + profile_node = of_batterydata_get_best_profile(chip->batt_node, + chip->batt_id_kohm, NULL); + #endif + } + + if (IS_ERR(profile_node)) { + rc = PTR_ERR(profile_node); + pr_err("Failed to detect valid QG battery profile %d\n", rc); + return rc; + } + + rc = of_property_read_string(profile_node, "qcom,battery-type", + &chip->bp.batt_type_str); + if (rc < 0) { + pr_err("Failed to detect battery type rc:%d\n", rc); + return rc; + } + + rc = qg_batterydata_init(profile_node); + if (rc < 0) { + pr_err("Failed to initialize battery-profile rc=%d\n", rc); + return rc; + } + + rc = of_property_read_u32(profile_node, "qcom,max-voltage-uv", + &chip->bp.float_volt_uv); + if (rc < 0) { + pr_err("Failed to read battery float-voltage rc:%d\n", rc); + chip->bp.float_volt_uv = -EINVAL; + } + + rc = of_property_read_u32(profile_node, "qcom,fastchg-current-ma", + &chip->bp.fastchg_curr_ma); + if (rc < 0) { + pr_err("Failed to read battery fastcharge current rc:%d\n", rc); + chip->bp.fastchg_curr_ma = -EINVAL; + } + + /* + * Update the max fcc values based on QG subtype including + * error margins. + */ + chip->bp.fastchg_curr_ma = min(chip->max_fcc_limit_ma, + chip->bp.fastchg_curr_ma); + + rc = of_property_read_u32(profile_node, "qcom,qg-batt-profile-ver", + &chip->bp.qg_profile_version); + if (rc < 0) { + pr_err("Failed to read QG profile version rc:%d\n", rc); + chip->bp.qg_profile_version = -EINVAL; + } + + /* + * Currently step charging thresholds should be read only for Vbatt + * based and not for SOC based. + */ + if (!of_property_read_bool(profile_node, "qcom,soc-based-step-chg") && + of_find_property(profile_node, "qcom,step-chg-ranges", &len) && + chip->bp.float_volt_uv > 0 && chip->bp.fastchg_curr_ma > 0) { + len /= sizeof(u32); + tuple_len = len / (sizeof(struct range_data) / sizeof(u32)); + if (tuple_len <= 0 || tuple_len > MAX_STEP_CHG_ENTRIES) + return -EINVAL; + + mutex_lock(&chip->ttf->lock); + chip->ttf->step_chg_cfg = + kcalloc(len, sizeof(*chip->ttf->step_chg_cfg), + GFP_KERNEL); + if (!chip->ttf->step_chg_cfg) { + mutex_unlock(&chip->ttf->lock); + return -ENOMEM; + } + + chip->ttf->step_chg_data = + kcalloc(tuple_len, sizeof(*chip->ttf->step_chg_data), + GFP_KERNEL); + if (!chip->ttf->step_chg_data) { + kfree(chip->ttf->step_chg_cfg); + mutex_unlock(&chip->ttf->lock); + return -ENOMEM; + } + + rc = read_range_data_from_node(profile_node, + "qcom,step-chg-ranges", + chip->ttf->step_chg_cfg, + chip->bp.float_volt_uv, + chip->bp.fastchg_curr_ma * 1000); + if (rc < 0) { + pr_err("Error in reading qcom,step-chg-ranges from battery profile, rc=%d\n", + rc); + kfree(chip->ttf->step_chg_data); + kfree(chip->ttf->step_chg_cfg); + chip->ttf->step_chg_cfg = NULL; + mutex_unlock(&chip->ttf->lock); + return rc; + } + + chip->ttf->step_chg_num_params = tuple_len; + chip->ttf->step_chg_cfg_valid = true; + mutex_unlock(&chip->ttf->lock); + + if (chip->ttf->step_chg_cfg_valid) { + for (i = 0; i < tuple_len; i++) + pr_debug("Vbatt_low: %d Vbatt_high: %d FCC: %d\n", + chip->ttf->step_chg_cfg[i].low_threshold, + chip->ttf->step_chg_cfg[i].high_threshold, + chip->ttf->step_chg_cfg[i].value); + } + } + + qg_dbg(chip, QG_DEBUG_PROFILE, "profile=%s FV=%duV FCC=%dma\n", + chip->bp.batt_type_str, chip->bp.float_volt_uv, + chip->bp.fastchg_curr_ma); + + return 0; +} + +static int qg_setup_battery(struct qpnp_qg *chip) +{ + int rc; + + if (!is_battery_present(chip)) { + qg_dbg(chip, QG_DEBUG_PROFILE, "Battery Missing!\n"); + chip->battery_missing = true; + chip->profile_loaded = false; + chip->soc_reporting_ready = true; + } else { + /* battery present */ + rc = get_batt_id_ohm(chip, &chip->batt_id_ohm); + if (rc < 0) { + pr_err("Failed to detect batt_id rc=%d\n", rc); + chip->profile_loaded = false; + } else { +#ifdef OPLUS_FEATURE_CHG_BASIC + if(((chip->batt_id_ohm % 1000) > 500) || ((chip->batt_id_ohm % 1000) == 500)) { + chip->batt_id_kohm = (chip->batt_id_ohm / 1000) + 1; + } else { + chip->batt_id_kohm = chip->batt_id_ohm / 1000; + }; + pr_info("Battery id in ohm is %d, in kohm is %d\n", chip->batt_id_ohm, chip->batt_id_kohm); + //chip->batt_id_kohm = 100; + //chip->batt_id_ohm = 100000; +#endif + rc = qg_load_battery_profile(chip); + if (rc < 0) { + pr_err("Failed to load battery-profile rc=%d\n", + rc); + chip->profile_loaded = false; + chip->soc_reporting_ready = true; + } else { + chip->profile_loaded = true; + } + } + } + + qg_dbg(chip, QG_DEBUG_PROFILE, "battery_missing=%d batt_id_ohm=%d Ohm profile_loaded=%d profile=%s\n", + chip->battery_missing, chip->batt_id_ohm, + chip->profile_loaded, chip->bp.batt_type_str); + + return 0; +} + +static struct ocv_all ocv[] = { + [S7_PON_OCV] = { 0, 0, "S7_PON_OCV"}, + [S3_GOOD_OCV] = { 0, 0, "S3_GOOD_OCV"}, + [S3_LAST_OCV] = { 0, 0, "S3_LAST_OCV"}, + [SDAM_PON_OCV] = { 0, 0, "SDAM_PON_OCV"}, +}; + +#define S7_ERROR_MARGIN_UV 20000 +static int qg_determine_pon_soc(struct qpnp_qg *chip) +{ + int rc = 0, batt_temp = 0, i, shutdown_temp = 0; + bool use_pon_ocv = true; + unsigned long rtc_sec = 0; + u32 ocv_uv = 0, soc = 0, pon_soc = 0, full_soc = 0, cutoff_soc = 0; + u32 shutdown[SDAM_MAX] = {0}, soc_raw = 0; + char ocv_type[20] = "NONE"; + + if (!chip->profile_loaded) { + qg_dbg(chip, QG_DEBUG_PON, "No Profile, skipping PON soc\n"); + return 0; + } + + /* read all OCVs */ + for (i = S7_PON_OCV; i < PON_OCV_MAX; i++) { + rc = qg_read_ocv(chip, &ocv[i].ocv_uv, + &ocv[i].ocv_raw, i); + if (rc < 0) + pr_err("Failed to read %s OCV rc=%d\n", + ocv[i].ocv_type, rc); + else + qg_dbg(chip, QG_DEBUG_PON, "%s OCV=%d\n", + ocv[i].ocv_type, ocv[i].ocv_uv); + } + + rc = qg_get_battery_temp(chip, &batt_temp); + if (rc < 0) { + pr_err("Failed to read BATT_TEMP at PON rc=%d\n", rc); + goto done; + } + + rc = get_rtc_time(&rtc_sec); + if (rc < 0) { + pr_err("Failed to read RTC time rc=%d\n", rc); + goto use_pon_ocv; + } + + rc = qg_sdam_read_all(shutdown); + if (rc < 0) { + pr_err("Failed to read shutdown params rc=%d\n", rc); + goto use_pon_ocv; + } + shutdown_temp = sign_extend32(shutdown[SDAM_TEMP], 15); + + rc = lookup_soc_ocv(&pon_soc, ocv[S7_PON_OCV].ocv_uv, batt_temp, false); + if (rc < 0) { + pr_err("Failed to lookup S7_PON SOC rc=%d\n", rc); + goto done; + } + + qg_dbg(chip, QG_DEBUG_PON, "Shutdown: Valid=%d SOC=%d OCV=%duV time=%dsecs temp=%d, time_now=%ldsecs temp_now=%d S7_soc=%d\n", + shutdown[SDAM_VALID], + shutdown[SDAM_SOC], + shutdown[SDAM_OCV_UV], + shutdown[SDAM_TIME_SEC], + shutdown_temp, + rtc_sec, batt_temp, + pon_soc); + /* + * Use the shutdown SOC if + * 1. SDAM read is a success & SDAM data is valid + * 2. The device was powered off for < ignore_shutdown_time + * 2. Batt temp has not changed more than shutdown_temp_diff + */ + if (!shutdown[SDAM_VALID]) + goto use_pon_ocv; + + if (!is_between(0, chip->dt.ignore_shutdown_soc_secs, + (rtc_sec - shutdown[SDAM_TIME_SEC]))) + goto use_pon_ocv; + + if (!is_between(0, chip->dt.shutdown_temp_diff, + abs(shutdown_temp - batt_temp)) && + (shutdown_temp < 0 || batt_temp < 0)) + goto use_pon_ocv; + + if ((chip->dt.shutdown_soc_threshold != -EINVAL) && + !is_between(0, chip->dt.shutdown_soc_threshold, + abs(pon_soc - shutdown[SDAM_SOC]))) + goto use_pon_ocv; + + use_pon_ocv = false; + ocv_uv = shutdown[SDAM_OCV_UV]; + soc = shutdown[SDAM_SOC]; + soc_raw = shutdown[SDAM_SOC] * 100; + strlcpy(ocv_type, "SHUTDOWN_SOC", 20); + qg_dbg(chip, QG_DEBUG_PON, "Using SHUTDOWN_SOC @ PON\n"); + +use_pon_ocv: + if (use_pon_ocv == true) { + if (chip->wa_flags & QG_PON_OCV_WA) { + if (ocv[S3_LAST_OCV].ocv_raw == FIFO_V_RESET_VAL) { + if (!ocv[SDAM_PON_OCV].ocv_uv) { + strlcpy(ocv_type, "S7_PON_SOC", 20); + ocv_uv = ocv[S7_PON_OCV].ocv_uv; + } else if (ocv[SDAM_PON_OCV].ocv_uv <= + ocv[S7_PON_OCV].ocv_uv) { + strlcpy(ocv_type, "S7_PON_SOC", 20); + ocv_uv = ocv[S7_PON_OCV].ocv_uv; + } else if (!shutdown[SDAM_VALID] && + ((ocv[SDAM_PON_OCV].ocv_uv - + ocv[S7_PON_OCV].ocv_uv) > + S7_ERROR_MARGIN_UV)) { + strlcpy(ocv_type, "S7_PON_SOC", 20); + ocv_uv = ocv[S7_PON_OCV].ocv_uv; + } else { + strlcpy(ocv_type, "SDAM_PON_SOC", 20); + ocv_uv = ocv[SDAM_PON_OCV].ocv_uv; + } + } else { + if (ocv[S3_LAST_OCV].ocv_uv >= + ocv[S7_PON_OCV].ocv_uv) { + strlcpy(ocv_type, "S3_LAST_SOC", 20); + ocv_uv = ocv[S3_LAST_OCV].ocv_uv; + } else { + strlcpy(ocv_type, "S7_PON_SOC", 20); + ocv_uv = ocv[S7_PON_OCV].ocv_uv; + } + } + } else { + /* Use S7 PON OCV */ + strlcpy(ocv_type, "S7_PON_SOC", 20); + ocv_uv = ocv[S7_PON_OCV].ocv_uv; + } + + ocv_uv = CAP(QG_MIN_OCV_UV, QG_MAX_OCV_UV, ocv_uv); + rc = lookup_soc_ocv(&pon_soc, ocv_uv, batt_temp, false); + if (rc < 0) { + pr_err("Failed to lookup SOC@PON rc=%d\n", rc); + goto done; + } + + rc = lookup_soc_ocv(&full_soc, chip->bp.float_volt_uv, + batt_temp, true); + if (rc < 0) { + pr_err("Failed to lookup FULL_SOC@PON rc=%d\n", rc); + goto done; + } + full_soc = CAP(0, 99, full_soc); + + rc = lookup_soc_ocv(&cutoff_soc, + chip->dt.vbatt_cutoff_mv * 1000, + batt_temp, false); + if (rc < 0) { + pr_err("Failed to lookup CUTOFF_SOC@PON rc=%d\n", rc); + goto done; + } + + if ((full_soc > cutoff_soc) && (pon_soc > cutoff_soc)) { + soc = DIV_ROUND_UP(((pon_soc - cutoff_soc) * 100), + (full_soc - cutoff_soc)); + soc = CAP(0, 100, soc); + soc_raw = soc * 100; + } else { + soc_raw = pon_soc * 100; + soc = pon_soc; + } + + qg_dbg(chip, QG_DEBUG_PON, "v_float=%d v_cutoff=%d FULL_SOC=%d CUTOFF_SOC=%d PON_SYS_SOC=%d pon_soc=%d\n", + chip->bp.float_volt_uv, chip->dt.vbatt_cutoff_mv * 1000, + full_soc, cutoff_soc, soc, pon_soc); + } +done: + if (rc < 0) { + pr_err("Failed to get %s @ PON, rc=%d\n", ocv_type, rc); + return rc; + } + + if (chip->qg_mode == QG_V_I_MODE) + chip->cc_soc = soc_raw; + chip->sys_soc = soc_raw; + chip->last_adj_ssoc = chip->catch_up_soc = chip->msoc = soc; + chip->kdata.param[QG_PON_OCV_UV].data = ocv_uv; + chip->kdata.param[QG_PON_OCV_UV].valid = true; + + /* write back to SDAM */ + chip->sdam_data[SDAM_SOC] = soc; + chip->sdam_data[SDAM_OCV_UV] = ocv_uv; + chip->sdam_data[SDAM_VALID] = 1; + + rc = qg_write_monotonic_soc(chip, chip->msoc); + if (rc < 0) + pr_err("Failed to update MSOC register rc=%d\n", rc); + + rc = qg_store_soc_params(chip); + if (rc < 0) + pr_err("Failed to update sdam params rc=%d\n", rc); + + pr_info("using %s @ PON ocv_uv=%duV soc=%d\n", + ocv_type, ocv_uv, chip->msoc); + + /* SOC reporting is now ready */ + chip->soc_reporting_ready = 1; + + return 0; +} + +static int qg_set_wa_flags(struct qpnp_qg *chip) +{ + switch (chip->pmic_rev_id->pmic_subtype) { + case PMI632_SUBTYPE: + chip->wa_flags |= QG_RECHARGE_SOC_WA; + if (!chip->dt.use_s7_ocv) + chip->wa_flags |= QG_PON_OCV_WA; + if (chip->pmic_rev_id->rev4 == PMI632_V1P0_REV4) + chip->wa_flags |= QG_VBAT_LOW_WA; + break; + case PM6150_SUBTYPE: + chip->wa_flags |= QG_CLK_ADJUST_WA | + QG_RECHARGE_SOC_WA; + qg_esr_mod_count = 10; + break; + case PM7250B_SUBTYPE: +#ifdef OPLUS_FEATURE_CHG_BASIC + if (chip->asic_with_internal_gauge) + qg_esr_mod_count = 5; + else + qg_esr_mod_count = 10; +#else + qg_esr_mod_count = 10; +#endif + break; + case PM2250_SUBTYPE: + chip->wa_flags |= QG_CLK_ADJUST_WA | + QG_RECHARGE_SOC_WA | + QG_VBAT_LOW_WA; + break; + default: + pr_err("Unsupported PMIC subtype %d\n", + chip->pmic_rev_id->pmic_subtype); + return -EINVAL; + } + + qg_dbg(chip, QG_DEBUG_PON, "wa_flags = %x\n", chip->wa_flags); + + return 0; +} + +#define SDAM_MAGIC_NUMBER 0x12345678 +static int qg_sanitize_sdam(struct qpnp_qg *chip) +{ + int rc = 0; + u32 data = 0; + + rc = qg_sdam_read(SDAM_MAGIC, &data); + if (rc < 0) { + pr_err("Failed to read SDAM rc=%d\n", rc); + return rc; + } + + if (data == SDAM_MAGIC_NUMBER) { + qg_dbg(chip, QG_DEBUG_PON, "SDAM valid\n"); + } else if (data == 0) { + rc = qg_sdam_write(SDAM_MAGIC, SDAM_MAGIC_NUMBER); + if (!rc) + qg_dbg(chip, QG_DEBUG_PON, "First boot. SDAM initilized\n"); + } else { + /* SDAM has invalid value */ + rc = qg_sdam_clear(); + if (!rc) { + pr_err("SDAM uninitialized, SDAM reset\n"); + rc = qg_sdam_write(SDAM_MAGIC, SDAM_MAGIC_NUMBER); + } + } + + if (rc < 0) + pr_err("Failed in SDAM operation, rc=%d\n", rc); + + return rc; +} + +#define ADC_CONV_DLY_512MS 0xA +#define IBAT_5A_FCC_MA 4800 +#define IBAT_10A_FCC_MA 9600 +static int qg_hw_init(struct qpnp_qg *chip) +{ + int rc, temp; + u8 reg; + + /* read STATUS2 register to clear its last state */ + qg_read(chip, chip->qg_base + QG_STATUS2_REG, ®, 1); + + /* read the QG perph_subtype */ + rc = qg_read(chip, chip->qg_base + PERPH_SUBTYPE_REG, + &chip->qg_subtype, 1); + if (rc < 0) { + pr_err("Failed to read QG subtype rc=%d\n", rc); + return rc; + } + + if (chip->qg_subtype == QG_ADC_IBAT_5A) + chip->max_fcc_limit_ma = IBAT_5A_FCC_MA; + else + chip->max_fcc_limit_ma = IBAT_10A_FCC_MA; + + if (chip->qg_version == QG_LITE) { + rc = qg_read(chip, chip->qg_base + QG_MODE_CTL2_REG, ®, 1); + if (rc < 0) { + pr_err("Failed to read QG mode rc=%d\n", rc); + return rc; + } + chip->qg_mode = (reg & VI_MODE_BIT) ? QG_V_I_MODE : QG_V_MODE; + } else { + chip->qg_mode = QG_V_I_MODE; + } + + if (chip->qg_mode == QG_V_MODE) { + chip->dt.esr_disable = true; + chip->dt.cl_disable = true; + chip->dt.tcss_enable = false; + chip->dt.bass_enable = false; + } + + rc = qg_set_wa_flags(chip); + if (rc < 0) { + pr_err("Failed to update PMIC type flags, rc=%d\n", rc); + return rc; + } + + rc = qg_master_hold(chip, true); + if (rc < 0) { + pr_err("Failed to hold master, rc=%d\n", rc); + goto done_fifo; + } + + rc = qg_process_rt_fifo(chip); + if (rc < 0) { + pr_err("Failed to process FIFO real-time, rc=%d\n", rc); + goto done_fifo; + } + + /* update the changed S2 fifo DT parameters */ + if (chip->dt.s2_fifo_length > 0) { + rc = qg_update_fifo_length(chip, chip->dt.s2_fifo_length); + if (rc < 0) + goto done_fifo; + } + + if (chip->dt.s2_acc_length > 0) { + reg = ilog2(chip->dt.s2_acc_length) - 1; + rc = qg_masked_write(chip, chip->qg_base + + QG_S2_NORMAL_MEAS_CTL2_REG, + NUM_OF_ACCUM_MASK, reg); + if (rc < 0) { + pr_err("Failed to write S2 ACC length, rc=%d\n", rc); + goto done_fifo; + } + } + + if (chip->dt.s2_acc_intvl_ms > 0) { + reg = chip->dt.s2_acc_intvl_ms / 10; + rc = qg_write(chip, chip->qg_base + + QG_S2_NORMAL_MEAS_CTL3_REG, + ®, 1); + if (rc < 0) { + pr_err("Failed to write S2 ACC intrvl, rc=%d\n", rc); + goto done_fifo; + } + } + + chip->s2_state = S2_DEFAULT; + chip->s2_state_mask |= S2_DEFAULT; + /* signal the read thread */ + chip->data_ready = true; + wake_up_interruptible(&chip->qg_wait_q); + +done_fifo: + rc = qg_master_hold(chip, false); + if (rc < 0) { + pr_err("Failed to release master, rc=%d\n", rc); + return rc; + } + chip->last_fifo_update_time = ktime_get_boottime(); + + if (chip->dt.ocv_timer_expiry_min != -EINVAL && + chip->qg_version != QG_LITE) { + if (chip->dt.ocv_timer_expiry_min < 2) + chip->dt.ocv_timer_expiry_min = 2; + else if (chip->dt.ocv_timer_expiry_min > 30) + chip->dt.ocv_timer_expiry_min = 30; + + reg = (chip->dt.ocv_timer_expiry_min - 2) / 4; + rc = qg_masked_write(chip, + chip->qg_base + QG_S3_SLEEP_OCV_MEAS_CTL4_REG, + SLEEP_IBAT_QUALIFIED_LENGTH_MASK, reg); + if (rc < 0) { + pr_err("Failed to write OCV timer, rc=%d\n", rc); + return rc; + } + } + + if (chip->dt.ocv_tol_threshold_uv != -EINVAL) { + if (chip->dt.ocv_tol_threshold_uv < 0) + chip->dt.ocv_tol_threshold_uv = 0; + else if (chip->dt.ocv_tol_threshold_uv > 12262) + chip->dt.ocv_tol_threshold_uv = 12262; + + reg = chip->dt.ocv_tol_threshold_uv / 195; + rc = qg_masked_write(chip, + chip->qg_base + QG_S3_SLEEP_OCV_TREND_CTL2_REG, + TREND_TOL_MASK, reg); + if (rc < 0) { + pr_err("Failed to write OCV tol-thresh, rc=%d\n", rc); + return rc; + } + } + + if (chip->dt.s3_entry_fifo_length != -EINVAL) { + if (chip->dt.s3_entry_fifo_length < 1) + chip->dt.s3_entry_fifo_length = 1; + else if (chip->dt.s3_entry_fifo_length > + chip->max_fifo_length) + chip->dt.s3_entry_fifo_length = + chip->max_fifo_length; + + reg = chip->dt.s3_entry_fifo_length - 1; + rc = qg_masked_write(chip, + chip->qg_base + QG_S3_SLEEP_OCV_IBAT_CTL1_REG, + SLEEP_IBAT_QUALIFIED_LENGTH_MASK, reg); + if (rc < 0) { + pr_err("Failed to write S3-entry fifo-length, rc=%d\n", + rc); + return rc; + } + } + + if (chip->dt.s3_entry_ibat_ua != -EINVAL) { + if (chip->dt.s3_entry_ibat_ua < 0) + chip->dt.s3_entry_ibat_ua = 0; + else if (chip->dt.s3_entry_ibat_ua > 155550) + chip->dt.s3_entry_ibat_ua = 155550; + + reg = chip->dt.s3_entry_ibat_ua / 610; + rc = qg_write(chip, chip->qg_base + + QG_S3_ENTRY_IBAT_THRESHOLD_REG, + ®, 1); + if (rc < 0) { + pr_err("Failed to write S3-entry ibat-uA, rc=%d\n", rc); + return rc; + } + } + + if (chip->dt.s3_exit_ibat_ua != -EINVAL) { + if (chip->dt.s3_exit_ibat_ua < 0) + chip->dt.s3_exit_ibat_ua = 0; + else if (chip->dt.s3_exit_ibat_ua > 155550) + chip->dt.s3_exit_ibat_ua = 155550; + + rc = qg_read(chip, chip->qg_base + + QG_S3_ENTRY_IBAT_THRESHOLD_REG, + ®, 1); + if (rc < 0) { + pr_err("Failed to read S3-entry ibat-uA, rc=%d\n", rc); + return rc; + } + temp = reg * 610; + if (chip->dt.s3_exit_ibat_ua < temp) + chip->dt.s3_exit_ibat_ua = temp; + else + chip->dt.s3_exit_ibat_ua -= temp; + + reg = chip->dt.s3_exit_ibat_ua / 610; + rc = qg_write(chip, + chip->qg_base + QG_S3_EXIT_IBAT_THRESHOLD_REG, + ®, 1); + if (rc < 0) { + pr_err("Failed to write S3-entry ibat-uA, rc=%d\n", rc); + return rc; + } + } + + /* vbat based configs */ + if (chip->dt.vbatt_low_mv < 0) + chip->dt.vbatt_low_mv = 0; + else if (chip->dt.vbatt_low_mv > 12750) + chip->dt.vbatt_low_mv = 12750; + + if (chip->dt.vbatt_empty_mv < 0) + chip->dt.vbatt_empty_mv = 0; + else if (chip->dt.vbatt_empty_mv > 12750) + chip->dt.vbatt_empty_mv = 12750; + + if (chip->dt.vbatt_empty_cold_mv < 0) + chip->dt.vbatt_empty_cold_mv = 0; + else if (chip->dt.vbatt_empty_cold_mv > 12750) + chip->dt.vbatt_empty_cold_mv = 12750; + + rc = qg_vbat_thresholds_config(chip); + if (rc < 0) { + pr_err("Failed to configure VBAT empty/low rc=%d\n", rc); + return rc; + } + + if (chip->qg_version != QG_LITE) { + /* disable S5 */ + rc = qg_masked_write(chip, chip->qg_base + + QG_S5_OCV_VALIDATE_MEAS_CTL1_REG, + ALLOW_S5_BIT, 0); + if (rc < 0) + pr_err("Failed to disable S5 rc=%d\n", rc); + } + + /* change PON OCV time to 512ms */ + rc = qg_masked_write(chip, chip->qg_base + + QG_S7_PON_OCV_MEAS_CTL1_REG, + ADC_CONV_DLY_MASK, + ADC_CONV_DLY_512MS); + if (rc < 0) + pr_err("Failed to reconfigure S7-delay rc=%d\n", rc); + + + return 0; +} + +static int qg_soh_batt_profile_init(struct qpnp_qg *chip) +{ + int rc = 0; + + if (!chip->dt.multi_profile_load) + return 0; + + if (is_debug_batt_id(chip) || chip->battery_missing) + return 0; + + if (!chip->sp) + chip->sp = devm_kzalloc(chip->dev, sizeof(*chip->sp), + GFP_KERNEL); + if (!chip->sp) + return -ENOMEM; + + if (!chip->sp->initialized) { + chip->sp->batt_id_kohms = chip->batt_id_ohm / 1000; + chip->sp->bp_node = chip->batt_node; + chip->sp->last_batt_age_level = chip->batt_age_level; + chip->sp->bms_psy = chip->qg_psy; + rc = soh_profile_init(chip->dev, chip->sp); + if (rc < 0) { + devm_kfree(chip->dev, chip->sp); + chip->sp = NULL; + } else { + qg_dbg(chip, QG_DEBUG_PROFILE, "SOH profile count: %d\n", + chip->sp->profile_count); + } + } + + return rc; +} + +static int qg_post_init(struct qpnp_qg *chip) +{ + int rc = 0; + + /* disable all IRQs if profile is not loaded */ + if (!chip->profile_loaded) { + vote(chip->vbatt_irq_disable_votable, + PROFILE_IRQ_DISABLE, true, 0); + vote(chip->fifo_irq_disable_votable, + PROFILE_IRQ_DISABLE, true, 0); + vote(chip->good_ocv_irq_disable_votable, + PROFILE_IRQ_DISABLE, true, 0); + } + + /* restore ESR data */ + if (!chip->dt.esr_disable) + qg_retrieve_esr_params(chip); + + /*soh based multi profile init */ + rc = qg_soh_batt_profile_init(chip); + if (rc < 0) { + pr_err("Failed to initialize battery based on soh rc=%d\n", + rc); + return rc; + } + + return 0; +} + +static int qg_get_irq_index_byname(const char *irq_name) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(qg_irqs); i++) { + if (strcmp(qg_irqs[i].name, irq_name) == 0) + return i; + } + + return -ENOENT; +} + +static int qg_request_interrupt(struct qpnp_qg *chip, + struct device_node *node, const char *irq_name) +{ + int rc, irq, irq_index; + + irq = of_irq_get_byname(node, irq_name); + if (irq < 0) { + pr_err("Failed to get irq %s byname\n", irq_name); + return irq; + } + + irq_index = qg_get_irq_index_byname(irq_name); + if (irq_index < 0) { + pr_err("%s is not a defined irq\n", irq_name); + return irq_index; + } + + if (!qg_irqs[irq_index].handler) + return 0; + + rc = devm_request_threaded_irq(chip->dev, irq, NULL, + qg_irqs[irq_index].handler, + IRQF_ONESHOT, irq_name, chip); + if (rc < 0) { + pr_err("Failed to request irq %d\n", irq); + return rc; + } + + qg_irqs[irq_index].irq = irq; + if (qg_irqs[irq_index].wake) + enable_irq_wake(irq); + + qg_dbg(chip, QG_DEBUG_PON, "IRQ %s registered wakeable=%d\n", + qg_irqs[irq_index].name, qg_irqs[irq_index].wake); + + return 0; +} + +static int qg_request_irqs(struct qpnp_qg *chip) +{ + struct device_node *node = chip->dev->of_node; + struct device_node *child; + const char *name; + struct property *prop; + int rc = 0; + + for_each_available_child_of_node(node, child) { + of_property_for_each_string(child, "interrupt-names", + prop, name) { + rc = qg_request_interrupt(chip, child, name); + if (rc < 0) + return rc; + } + } + + + return 0; +} + +#define QG_TTF_ITERM_DELTA_MA 1 +static int qg_alg_init(struct qpnp_qg *chip) +{ + struct cycle_counter *counter; + struct cap_learning *cl; + struct ttf *ttf; + struct device_node *node = chip->dev->of_node; + int rc; + + counter = devm_kzalloc(chip->dev, sizeof(*counter), GFP_KERNEL); + if (!counter) + return -ENOMEM; + + counter->restore_count = qg_restore_cycle_count; + counter->store_count = qg_store_cycle_count; + counter->data = chip; + + rc = cycle_count_init(counter); + if (rc < 0) { + dev_err(chip->dev, "Error in initializing cycle counter, rc:%d\n", + rc); + counter->data = NULL; + devm_kfree(chip->dev, counter); + return rc; + } + + chip->counter = counter; + + ttf = devm_kzalloc(chip->dev, sizeof(*ttf), GFP_KERNEL); + if (!ttf) + return -ENOMEM; + + ttf->get_ttf_param = qg_get_ttf_param; + ttf->awake_voter = qg_ttf_awake_voter; + ttf->iterm_delta = QG_TTF_ITERM_DELTA_MA; + ttf->data = chip; + + rc = ttf_tte_init(ttf); + if (rc < 0) { + dev_err(chip->dev, "Error in initializing ttf, rc:%d\n", + rc); + ttf->data = NULL; + counter->data = NULL; + devm_kfree(chip->dev, ttf); + devm_kfree(chip->dev, counter); + return rc; + } + + chip->ttf = ttf; + + chip->dt.cl_disable = of_property_read_bool(node, + "qcom,cl-disable"); + + /*Return if capacity learning is disabled*/ + if (chip->dt.cl_disable) + return 0; + + cl = devm_kzalloc(chip->dev, sizeof(*cl), GFP_KERNEL); + if (!cl) + return -ENOMEM; + + cl->cc_soc_max = QG_SOC_FULL; + cl->get_cc_soc = qg_get_cc_soc; + cl->get_learned_capacity = qg_get_learned_capacity; + cl->store_learned_capacity = qg_store_learned_capacity; + cl->ok_to_begin = qg_cl_ok_to_begin; + cl->data = chip; + + rc = cap_learning_init(cl); + if (rc < 0) { + dev_err(chip->dev, "Error in initializing capacity learning, rc:%d\n", + rc); + counter->data = NULL; + cl->data = NULL; + devm_kfree(chip->dev, counter); + devm_kfree(chip->dev, ttf); + devm_kfree(chip->dev, cl); + return rc; + } + + chip->cl = cl; + return 0; +} + +#ifdef CONFIG_DEBUG_FS +static void qg_create_debugfs(struct qpnp_qg *chip) +{ + struct dentry *entry; + + chip->dfs_root = debugfs_create_dir("qgauge", NULL); + if (IS_ERR_OR_NULL(chip->dfs_root)) { + pr_err("Failed to create debugfs directory rc=%ld\n", + (long)chip->dfs_root); + return; + } + + entry = debugfs_create_u32("debug_mask", 0600, chip->dfs_root, + &qg_debug_mask); + if (IS_ERR_OR_NULL(entry)) { + pr_err("Failed to create debug_mask rc=%ld\n", (long)entry); + debugfs_remove_recursive(chip->dfs_root); + } +} +#else +static void qg_create_debugfs(struct qpnp_qg *chip) +{ +} +#endif + +#define DEFAULT_S2_FIFO_LENGTH 5 +#define DEFAULT_S2_VBAT_LOW_LENGTH 2 +#define DEFAULT_S2_ACC_LENGTH 128 +#define DEFAULT_S2_ACC_INTVL_MS 100 +#define DEFAULT_SLEEP_S2_FIFO_LENGTH 8 +#define DEFAULT_SLEEP_S2_ACC_LENGTH 256 +#define DEFAULT_SLEEP_S2_ACC_INTVL_MS 200 +#define DEFAULT_FAST_CHG_S2_FIFO_LENGTH 1 +static int qg_parse_s2_dt(struct qpnp_qg *chip) +{ + int rc; + struct device_node *node = chip->dev->of_node; + u32 temp; + + /* S2 state params */ + rc = of_property_read_u32(node, "qcom,s2-fifo-length", &temp); + if (rc < 0) + chip->dt.s2_fifo_length = DEFAULT_S2_FIFO_LENGTH; + else + chip->dt.s2_fifo_length = temp; + + if (chip->dt.s2_fifo_length > chip->max_fifo_length) { + pr_err("Invalid S2 fifo-length=%d max_length=%d\n", + chip->dt.s2_fifo_length, + chip->max_fifo_length); + return -EINVAL; + } + + rc = of_property_read_u32(node, "qcom,s2-vbat-low-fifo-length", &temp); + if (rc < 0) + chip->dt.s2_vbat_low_fifo_length = DEFAULT_S2_VBAT_LOW_LENGTH; + else + chip->dt.s2_vbat_low_fifo_length = temp; + + rc = of_property_read_u32(node, "qcom,s2-acc-length", &temp); + if (rc < 0) + chip->dt.s2_acc_length = DEFAULT_S2_ACC_LENGTH; + else + chip->dt.s2_acc_length = temp; + + rc = of_property_read_u32(node, "qcom,s2-acc-interval-ms", &temp); + if (rc < 0) + chip->dt.s2_acc_intvl_ms = DEFAULT_S2_ACC_INTVL_MS; + else + chip->dt.s2_acc_intvl_ms = temp; + + qg_dbg(chip, QG_DEBUG_PON, "DT: S2 FIFO length=%d low_vbat_length=%d acc_length=%d acc_interval=%d\n", + chip->dt.s2_fifo_length, chip->dt.s2_vbat_low_fifo_length, + chip->dt.s2_acc_length, chip->dt.s2_acc_intvl_ms); + + if (of_property_read_bool(node, "qcom,qg-sleep-config")) { + + chip->dt.qg_sleep_config = true; + + rc = of_property_read_u32(node, + "qcom,sleep-s2-fifo-length", &temp); + if (rc < 0) + chip->dt.sleep_s2_fifo_length = + DEFAULT_SLEEP_S2_FIFO_LENGTH; + else + chip->dt.sleep_s2_fifo_length = temp; + + if (chip->dt.s2_fifo_length > chip->max_fifo_length) { + pr_err("Invalid S2 sleep-fifo-length=%d max_length=%d\n", + chip->dt.sleep_s2_fifo_length, + chip->max_fifo_length); + return -EINVAL; + } + + rc = of_property_read_u32(node, + "qcom,sleep-s2-acc-length", &temp); + if (rc < 0) + chip->dt.sleep_s2_acc_length = + DEFAULT_SLEEP_S2_ACC_LENGTH; + else + chip->dt.sleep_s2_acc_length = temp; + + rc = of_property_read_u32(node, + "qcom,sleep-s2-acc-intvl-ms", &temp); + if (rc < 0) + chip->dt.sleep_s2_acc_intvl_ms = + DEFAULT_SLEEP_S2_ACC_INTVL_MS; + else + chip->dt.sleep_s2_acc_intvl_ms = temp; + } + + if (of_property_read_bool(node, "qcom,qg-fast-chg-config")) { + + chip->dt.qg_fast_chg_cfg = true; + + rc = of_property_read_u32(node, + "qcom,fast-chg-s2-fifo-length", &temp); + if (rc < 0) + chip->dt.fast_chg_s2_fifo_length = + DEFAULT_FAST_CHG_S2_FIFO_LENGTH; + else + chip->dt.fast_chg_s2_fifo_length = temp; + + if (chip->dt.fast_chg_s2_fifo_length > chip->max_fifo_length) { + pr_err("Invalid S2 fast-fifo-length=%d max_length=%d\n", + chip->dt.fast_chg_s2_fifo_length, + chip->max_fifo_length); + return -EINVAL; + } + } + + return 0; +} + +#define DEFAULT_CL_MIN_START_SOC 10 +#define DEFAULT_CL_MAX_START_SOC 15 +#define DEFAULT_CL_MIN_TEMP_DECIDEGC 150 +#define DEFAULT_CL_MAX_TEMP_DECIDEGC 500 +#define DEFAULT_CL_MAX_INC_DECIPERC 10 +#define DEFAULT_CL_MAX_DEC_DECIPERC 20 +#define DEFAULT_CL_MIN_LIM_DECIPERC 500 +#define DEFAULT_CL_MAX_LIM_DECIPERC 100 +#define DEFAULT_CL_DELTA_BATT_SOC 10 +#define DEFAULT_CL_WT_START_SOC 15 +static int qg_parse_cl_dt(struct qpnp_qg *chip) +{ + int rc; + struct device_node *node = chip->dev->of_node; + u32 temp; + + if (chip->dt.cl_disable) + return 0; + + chip->dt.cl_feedback_on = of_property_read_bool(node, + "qcom,cl-feedback-on"); + + rc = of_property_read_u32(node, "qcom,cl-min-start-soc", &temp); + if (rc < 0) + chip->cl->dt.min_start_soc = DEFAULT_CL_MIN_START_SOC; + else + chip->cl->dt.min_start_soc = temp; + + rc = of_property_read_u32(node, "qcom,cl-max-start-soc", &temp); + if (rc < 0) + chip->cl->dt.max_start_soc = DEFAULT_CL_MAX_START_SOC; + else + chip->cl->dt.max_start_soc = temp; + + rc = of_property_read_u32(node, "qcom,cl-min-temp", &temp); + if (rc < 0) + chip->cl->dt.min_temp = DEFAULT_CL_MIN_TEMP_DECIDEGC; + else + chip->cl->dt.min_temp = temp; + + rc = of_property_read_u32(node, "qcom,cl-max-temp", &temp); + if (rc < 0) + chip->cl->dt.max_temp = DEFAULT_CL_MAX_TEMP_DECIDEGC; + else + chip->cl->dt.max_temp = temp; + + rc = of_property_read_u32(node, "qcom,cl-max-increment", &temp); + if (rc < 0) + chip->cl->dt.max_cap_inc = DEFAULT_CL_MAX_INC_DECIPERC; + else + chip->cl->dt.max_cap_inc = temp; + + rc = of_property_read_u32(node, "qcom,cl-max-decrement", &temp); + if (rc < 0) + chip->cl->dt.max_cap_dec = DEFAULT_CL_MAX_DEC_DECIPERC; + else + chip->cl->dt.max_cap_dec = temp; + + rc = of_property_read_u32(node, "qcom,cl-min-limit", &temp); + if (rc < 0) + chip->cl->dt.min_cap_limit = + DEFAULT_CL_MIN_LIM_DECIPERC; + else + chip->cl->dt.min_cap_limit = temp; + + rc = of_property_read_u32(node, "qcom,cl-max-limit", &temp); + if (rc < 0) + chip->cl->dt.max_cap_limit = + DEFAULT_CL_MAX_LIM_DECIPERC; + else + chip->cl->dt.max_cap_limit = temp; + + chip->cl->dt.min_delta_batt_soc = DEFAULT_CL_DELTA_BATT_SOC; + /* read from DT property and update, if value exists */ + of_property_read_u32(node, "qcom,cl-min-delta-batt-soc", + &chip->cl->dt.min_delta_batt_soc); + + if (of_property_read_bool(node, "qcom,cl-wt-enable")) { + chip->cl->dt.cl_wt_enable = true; + chip->cl->dt.min_start_soc = DEFAULT_CL_WT_START_SOC; + chip->cl->dt.max_start_soc = -EINVAL; + } + + qg_dbg(chip, QG_DEBUG_PON, "DT: cl_min_start_soc=%d cl_max_start_soc=%d cl_min_temp=%d cl_max_temp=%d chip->cl->dt.cl_wt_enable=%d\n", + chip->cl->dt.min_start_soc, chip->cl->dt.max_start_soc, + chip->cl->dt.min_temp, chip->cl->dt.max_temp, + chip->cl->dt.cl_wt_enable); + + return 0; +} + +#define DEFAULT_VBATT_EMPTY_MV 3200 +#define DEFAULT_VBATT_EMPTY_COLD_MV 3000 +#define DEFAULT_VBATT_CUTOFF_MV 3400 +#define DEFAULT_VBATT_LOW_MV 3500 +#define DEFAULT_VBATT_LOW_COLD_MV 3800 +#define DEFAULT_ITERM_MA 100 +#define DEFAULT_DELTA_SOC 1 +#define DEFAULT_SHUTDOWN_SOC_SECS 360 +#define DEFAULT_COLD_TEMP_THRESHOLD 0 +#define DEFAULT_SHUTDOWN_TEMP_DIFF 60 /* 6 degC */ +#define DEFAULT_ESR_QUAL_CURRENT_UA 130000 +#define DEFAULT_ESR_QUAL_VBAT_UV 7000 +#define DEFAULT_ESR_DISABLE_SOC 1000 +#define ESR_CHG_MIN_IBAT_UA (-450000) +#define DEFAULT_SLEEP_TIME_SECS 1800 /* 30 mins */ +#define DEFAULT_SYS_MIN_VOLT_MV 2800 +#define DEFAULT_FVSS_VBAT_MV 3500 +#define DEFAULT_TCSS_ENTRY_SOC 90 +#define DEFAULT_ESR_LOW_TEMP_THRESHOLD 100 /* 10 deg */ +static int qg_parse_dt(struct qpnp_qg *chip) +{ + int rc = 0; + struct device_node *revid_node, *child, *node = chip->dev->of_node; + u32 base, temp; + u8 type; + + if (!node) { + pr_err("Failed to find device-tree node\n"); + return -ENXIO; + } + + revid_node = of_parse_phandle(node, "qcom,pmic-revid", 0); + if (!revid_node) { + pr_err("Missing qcom,pmic-revid property - driver failed\n"); + return -EINVAL; + } +#ifndef OPLUS_FEATURE_CHG_BASIC + chip->enable_qpnp_qg= of_property_read_bool(node,"qcom,enable-qpnp-qg"); + pr_debug("qg_parse_dt enable_qpnp_qg = %d\n",chip->enable_qpnp_qg); +#endif + chip->pmic_rev_id = get_revid_data(revid_node); + of_node_put(revid_node); + if (IS_ERR_OR_NULL(chip->pmic_rev_id)) { + pr_err("Failed to get pmic_revid, rc=%ld\n", + PTR_ERR(chip->pmic_rev_id)); + /* + * the revid peripheral must be registered, any failure + * here only indicates that the rev-id module has not + * probed yet. + */ + return -EPROBE_DEFER; + } + + qg_dbg(chip, QG_DEBUG_PON, "PMIC subtype %d Digital major %d\n", + chip->pmic_rev_id->pmic_subtype, chip->pmic_rev_id->rev4); + + for_each_available_child_of_node(node, child) { + rc = of_property_read_u32(child, "reg", &base); + if (rc < 0) { + pr_err("Failed to read base address, rc=%d\n", rc); + return rc; + } + + rc = qg_read(chip, base + PERPH_TYPE_REG, &type, 1); + if (rc < 0) { + pr_err("Failed to read type, rc=%d\n", rc); + return rc; + } + + switch (type) { + case QG_TYPE: + chip->qg_base = base; + break; + default: + break; + } + } + + if (!chip->qg_base) { + pr_err("QG device node missing\n"); + return -EINVAL; + } + + rc = qg_parse_s2_dt(chip); + if (rc < 0) + pr_err("Failed to parse S2 DT params rc=%d\n", rc); + + rc = qg_parse_cl_dt(chip); + if (rc < 0) + pr_err("Failed to parse CL parameters rc=%d\n", rc); + + /* OCV params */ + rc = of_property_read_u32(node, "qcom,ocv-timer-expiry-min", &temp); + if (rc < 0) + chip->dt.ocv_timer_expiry_min = -EINVAL; + else + chip->dt.ocv_timer_expiry_min = temp; + + rc = of_property_read_u32(node, "qcom,ocv-tol-threshold-uv", &temp); + if (rc < 0) + chip->dt.ocv_tol_threshold_uv = -EINVAL; + else + chip->dt.ocv_tol_threshold_uv = temp; + + qg_dbg(chip, QG_DEBUG_PON, "DT: OCV timer_expiry =%dmin ocv_tol_threshold=%duV\n", + chip->dt.ocv_timer_expiry_min, chip->dt.ocv_tol_threshold_uv); + + /* S3 sleep configuration */ + rc = of_property_read_u32(node, "qcom,s3-entry-fifo-length", &temp); + if (rc < 0) + chip->dt.s3_entry_fifo_length = -EINVAL; + else + chip->dt.s3_entry_fifo_length = temp; + + rc = of_property_read_u32(node, "qcom,s3-entry-ibat-ua", &temp); + if (rc < 0) + chip->dt.s3_entry_ibat_ua = -EINVAL; + else + chip->dt.s3_entry_ibat_ua = temp; + + rc = of_property_read_u32(node, "qcom,s3-exit-ibat-ua", &temp); + if (rc < 0) + chip->dt.s3_exit_ibat_ua = -EINVAL; + else + chip->dt.s3_exit_ibat_ua = temp; + + /* VBAT thresholds */ + rc = of_property_read_u32(node, "qcom,vbatt-empty-mv", &temp); + if (rc < 0) + chip->dt.vbatt_empty_mv = DEFAULT_VBATT_EMPTY_MV; + else + chip->dt.vbatt_empty_mv = temp; + + rc = of_property_read_u32(node, "qcom,vbatt-empty-cold-mv", &temp); + if (rc < 0) + chip->dt.vbatt_empty_cold_mv = DEFAULT_VBATT_EMPTY_COLD_MV; + else + chip->dt.vbatt_empty_cold_mv = temp; + + rc = of_property_read_u32(node, "qcom,cold-temp-threshold", &temp); + if (rc < 0) + chip->dt.cold_temp_threshold = DEFAULT_COLD_TEMP_THRESHOLD; + else + chip->dt.cold_temp_threshold = temp; + + rc = of_property_read_u32(node, "qcom,vbatt-low-mv", &temp); + if (rc < 0) + chip->dt.vbatt_low_mv = DEFAULT_VBATT_LOW_MV; + else + chip->dt.vbatt_low_mv = temp; + + rc = of_property_read_u32(node, "qcom,vbatt-low-cold-mv", &temp); + if (rc < 0) + chip->dt.vbatt_low_cold_mv = DEFAULT_VBATT_LOW_COLD_MV; + else + chip->dt.vbatt_low_cold_mv = temp; + + rc = of_property_read_u32(node, "qcom,vbatt-cutoff-mv", &temp); + if (rc < 0) + chip->dt.vbatt_cutoff_mv = DEFAULT_VBATT_CUTOFF_MV; + else + chip->dt.vbatt_cutoff_mv = temp; + /* IBAT thresholds */ + rc = of_property_read_u32(node, "qcom,qg-iterm-ma", &temp); + if (rc < 0) + chip->dt.iterm_ma = DEFAULT_ITERM_MA; + else + chip->dt.iterm_ma = temp; + + rc = of_property_read_u32(node, "qcom,delta-soc", &temp); + if (rc < 0) + chip->dt.delta_soc = DEFAULT_DELTA_SOC; + else + chip->dt.delta_soc = temp; + + rc = of_property_read_u32(node, "qcom,ignore-shutdown-soc-secs", &temp); + if (rc < 0) + chip->dt.ignore_shutdown_soc_secs = DEFAULT_SHUTDOWN_SOC_SECS; + else + chip->dt.ignore_shutdown_soc_secs = temp; + + rc = of_property_read_u32(node, "qcom,shutdown-temp-diff", &temp); + if (rc < 0) + chip->dt.shutdown_temp_diff = DEFAULT_SHUTDOWN_TEMP_DIFF; + else + chip->dt.shutdown_temp_diff = temp; + + chip->dt.hold_soc_while_full = of_property_read_bool(node, + "qcom,hold-soc-while-full"); + + chip->dt.linearize_soc = of_property_read_bool(node, + "qcom,linearize-soc"); + + rc = of_property_read_u32(node, "qcom,rbat-conn-mohm", &temp); + if (rc < 0) + chip->dt.rbat_conn_mohm = 0; + else + chip->dt.rbat_conn_mohm = (int)temp; + + /* esr */ + chip->dt.esr_disable = of_property_read_bool(node, + "qcom,esr-disable"); + + chip->dt.esr_discharge_enable = of_property_read_bool(node, + "qcom,esr-discharge-enable"); + + rc = of_property_read_u32(node, "qcom,esr-qual-current-ua", &temp); + if (rc < 0) + chip->dt.esr_qual_i_ua = DEFAULT_ESR_QUAL_CURRENT_UA; + else + chip->dt.esr_qual_i_ua = temp; + + rc = of_property_read_u32(node, "qcom,esr-qual-vbatt-uv", &temp); + if (rc < 0) + chip->dt.esr_qual_v_uv = DEFAULT_ESR_QUAL_VBAT_UV; + else + chip->dt.esr_qual_v_uv = temp; + + rc = of_property_read_u32(node, "qcom,esr-disable-soc", &temp); + if (rc < 0) + chip->dt.esr_disable_soc = DEFAULT_ESR_DISABLE_SOC; + else + chip->dt.esr_disable_soc = temp * 100; + + rc = of_property_read_u32(node, "qcom,esr-chg-min-ibat-ua", &temp); + if (rc < 0) + chip->dt.esr_min_ibat_ua = ESR_CHG_MIN_IBAT_UA; + else + chip->dt.esr_min_ibat_ua = (int)temp; + + rc = of_property_read_u32(node, "qcom,esr-low-temp-threshold", &temp); + if (rc < 0) + chip->dt.esr_low_temp_threshold = + DEFAULT_ESR_LOW_TEMP_THRESHOLD; + else + chip->dt.esr_low_temp_threshold = (int)temp; + + rc = of_property_read_u32(node, "qcom,shutdown_soc_threshold", &temp); + if (rc < 0) + chip->dt.shutdown_soc_threshold = -EINVAL; + else + chip->dt.shutdown_soc_threshold = temp; + + rc = of_property_read_u32(node, "qcom,qg-sys-min-voltage", &temp); + if (rc < 0) + chip->dt.sys_min_volt_mv = DEFAULT_SYS_MIN_VOLT_MV; + else + chip->dt.sys_min_volt_mv = temp; + + chip->dt.qg_ext_sense = of_property_read_bool(node, "qcom,qg-ext-sns"); + + chip->dt.use_cp_iin_sns = of_property_read_bool(node, + "qcom,use-cp-iin-sns"); + + chip->dt.use_s7_ocv = of_property_read_bool(node, "qcom,qg-use-s7-ocv"); + + rc = of_property_read_u32(node, "qcom,min-sleep-time-secs", &temp); + if (rc < 0) + chip->dt.min_sleep_time_secs = DEFAULT_SLEEP_TIME_SECS; + else + chip->dt.min_sleep_time_secs = temp; + + if (of_property_read_bool(node, "qcom,fvss-enable")) { + + chip->dt.fvss_enable = true; + + rc = of_property_read_u32(node, + "qcom,fvss-vbatt-mv", &temp); + if (rc < 0) + chip->dt.fvss_vbat_mv = DEFAULT_FVSS_VBAT_MV; + else + chip->dt.fvss_vbat_mv = temp; + } +#ifdef OPLUS_FEATURE_CHG_BASIC + /* Zejin.Yang BSP.CHG.Basic 2021-04-12 For oplus svooc/vooc chg project*/ + if (of_property_read_bool(node, "qcom,asic-with-internal-gauge")) { + chip->asic_with_internal_gauge = true; + pr_err("need configure QG electricity meter parameters"); + } +#endif + if (of_property_read_bool(node, "qcom,tcss-enable")) { + +#ifdef OPLUS_FEATURE_CHG_BASIC + if (chip->asic_with_internal_gauge) + chip->dt.tcss_enable = false; + else + chip->dt.tcss_enable = true; +#else + chip->dt.tcss_enable = true; +#endif + + rc = of_property_read_u32(node, + "qcom,tcss-entry-soc", &temp); + if (rc < 0) + chip->dt.tcss_entry_soc = DEFAULT_TCSS_ENTRY_SOC; + else + chip->dt.tcss_entry_soc = temp; + } + +#ifdef OPLUS_FEATURE_CHG_BASIC + if (of_property_read_bool(node, "qcom,adc-compensation-enable")) { + + chip->adc_compensation_enabled = true; + + rc = of_property_read_u32(node, + "qcom,compensation-impedance", &temp); + if (rc < 0) + chip->compensation_impedance = 0; + else + chip->compensation_impedance = temp; + pr_debug("adc_compensation_enabled = %d, compensation_impedance = %d\n", + chip->adc_compensation_enabled, chip->compensation_impedance); + } +#endif + +#ifdef OPLUS_FEATURE_CHG_BASIC +/* BSP.CHG.Basic, 2021/03/07, add Batt_NTC for small board NTC ADC flag */ + if (of_property_read_bool(node, "qcom,oplus_small_board_temp")) { + chip->oplus_small_board_temp = true; + pr_err("add oplus_small_board_temp flag"); + } +#endif + + chip->dt.bass_enable = of_property_read_bool(node, "qcom,bass-enable"); + + chip->dt.multi_profile_load = of_property_read_bool(node, + "qcom,multi-profile-load"); + + qg_dbg(chip, QG_DEBUG_PON, "DT: vbatt_empty_mv=%dmV vbatt_low_mv=%dmV delta_soc=%d ext-sns=%d\n", + chip->dt.vbatt_empty_mv, chip->dt.vbatt_low_mv, + chip->dt.delta_soc, chip->dt.qg_ext_sense); + + return 0; +} + +#ifdef OPLUS_FEATURE_CHG_BASIC +static int charge_qg_parse_dt(struct qpnp_qg *chip) +{ + struct device_node *node = chip->dev->of_node; + + if (!node) { + pr_err("Failed to find device-tree node\n"); + return -ENXIO; + } + + chip->qpnp_qg_feture = of_property_read_bool(node,"qcom,pm7250b-qg-feture"); + pr_debug("qg_parse_dt qpnp_qg_feture = %d\n", (int)chip->qpnp_qg_feture); + + return 0; +} +#endif + +static int process_suspend(struct qpnp_qg *chip) +{ + u8 status = 0; + int rc; + u32 fifo_rt_length = 0, sleep_fifo_length = 0; + + /* skip if profile is not loaded */ + if (!chip->profile_loaded) + return 0; + + cancel_delayed_work_sync(&chip->ttf->ttf_work); + + chip->suspend_data = false; + + /* read STATUS2 register to clear its last state */ + qg_read(chip, chip->qg_base + QG_STATUS2_REG, &status, 1); + + /* ignore any suspend processing if we are charging */ + if (chip->charge_status == POWER_SUPPLY_STATUS_CHARGING) { + /* Reset the sleep config if we are charging */ + if (chip->dt.qg_sleep_config) { + qg_dbg(chip, QG_DEBUG_STATUS, "Suspend: Charging - Exit S2_SLEEP\n"); + rc = qg_config_s2_state(chip, S2_SLEEP, false, true); + if (rc < 0) + pr_err("Failed to exit S2-sleep rc=%d\n", rc); + } + qg_dbg(chip, QG_DEBUG_PM, "Charging @ suspend - ignore processing\n"); + return 0; + } + + rc = get_fifo_length(chip, &fifo_rt_length, true); + if (rc < 0) { + pr_err("Failed to read FIFO RT count, rc=%d\n", rc); + return rc; + } + + rc = qg_read(chip, chip->qg_base + QG_S3_SLEEP_OCV_IBAT_CTL1_REG, + (u8 *)&sleep_fifo_length, 1); + if (rc < 0) { + pr_err("Failed to read sleep FIFO count, rc=%d\n", rc); + return rc; + } + sleep_fifo_length &= SLEEP_IBAT_QUALIFIED_LENGTH_MASK; + sleep_fifo_length++; + + if (chip->dt.qg_sleep_config) { + qg_dbg(chip, QG_DEBUG_STATUS, "Suspend: Forcing S2_SLEEP\n"); + rc = qg_config_s2_state(chip, S2_SLEEP, true, true); + if (rc < 0) + pr_err("Failed to config S2_SLEEP rc=%d\n", rc); + if (chip->kdata.fifo_length > 0) + chip->suspend_data = true; + } else if (fifo_rt_length >= + (chip->dt.s2_fifo_length - sleep_fifo_length)) { + /* + * If the real-time FIFO count is greater than + * the the #fifo to enter sleep, save the FIFO data + * and reset the fifo count. This is avoid a gauranteed wakeup + * due to fifo_done event as the curent FIFO length is already + * beyond the sleep length. + */ + rc = qg_master_hold(chip, true); + if (rc < 0) { + pr_err("Failed to hold master, rc=%d\n", rc); + return rc; + } + + rc = qg_process_rt_fifo(chip); + if (rc < 0) { + pr_err("Failed to process FIFO real-time, rc=%d\n", rc); + qg_master_hold(chip, false); + return rc; + } + + rc = qg_master_hold(chip, false); + if (rc < 0) { + pr_err("Failed to release master, rc=%d\n", rc); + return rc; + } + /* FIFOs restarted */ + chip->last_fifo_update_time = ktime_get_boottime(); + + chip->suspend_data = true; + } + + get_rtc_time(&chip->suspend_time); + + qg_dbg(chip, QG_DEBUG_PM, "FIFO rt_length=%d sleep_fifo_length=%d default_s2_count=%d suspend_data=%d time=%d\n", + fifo_rt_length, sleep_fifo_length, + chip->dt.s2_fifo_length, chip->suspend_data, + chip->suspend_time); + + return rc; +} + +#define QG_SLEEP_EXIT_TIME_MS 15000 /* 15 secs */ +static int process_resume(struct qpnp_qg *chip) +{ + u8 status2 = 0, rt_status = 0; + u32 ocv_uv = 0, ocv_raw = 0; + int rc; + unsigned long rtc_sec = 0, sleep_time_secs = 0; + + /* skip if profile is not loaded */ + if (!chip->profile_loaded) + return 0; + + get_rtc_time(&rtc_sec); + sleep_time_secs = rtc_sec - chip->suspend_time; + + if (chip->dt.qg_sleep_config) + schedule_delayed_work(&chip->qg_sleep_exit_work, + msecs_to_jiffies(QG_SLEEP_EXIT_TIME_MS)); + + rc = qg_read(chip, chip->qg_base + QG_STATUS2_REG, &status2, 1); + if (rc < 0) { + pr_err("Failed to read status2 register, rc=%d\n", rc); + return rc; + } + + if (status2 & GOOD_OCV_BIT) { + rc = qg_read_ocv(chip, &ocv_uv, &ocv_raw, S3_GOOD_OCV); + if (rc < 0) { + pr_err("Failed to read good_ocv, rc=%d\n", rc); + return rc; + } + + /* Clear suspend data as there has been a GOOD OCV */ + memset(&chip->kdata, 0, sizeof(chip->kdata)); + chip->kdata.fifo_time = (u32)rtc_sec; + chip->kdata.param[QG_GOOD_OCV_UV].data = ocv_uv; + chip->kdata.param[QG_GOOD_OCV_UV].valid = true; + chip->suspend_data = false; + + /* allow SOC jump if we have slept longer */ + if (sleep_time_secs >= chip->dt.min_sleep_time_secs) + chip->force_soc = true; + + qg_dbg(chip, QG_DEBUG_PM, "GOOD OCV @ resume good_ocv=%d uV\n", + ocv_uv); + } + + rc = qg_read(chip, chip->qg_base + QG_INT_LATCHED_STS_REG, + &rt_status, 1); + if (rc < 0) { + pr_err("Failed to read latched status register, rc=%d\n", rc); + return rc; + } + rt_status &= FIFO_UPDATE_DONE_INT_LAT_STS_BIT; + + qg_dbg(chip, QG_DEBUG_PM, "FIFO_DONE_STS=%d suspend_data=%d good_ocv=%d sleep_time=%d secs\n", + !!rt_status, chip->suspend_data, + chip->kdata.param[QG_GOOD_OCV_UV].valid, + sleep_time_secs); + /* + * If this is not a wakeup from FIFO-done, + * process the data immediately if - we have data from + * suspend or there is a good OCV. + */ + if (!rt_status && (chip->suspend_data || + chip->kdata.param[QG_GOOD_OCV_UV].valid)) { + vote(chip->awake_votable, SUSPEND_DATA_VOTER, true, 0); + /* signal the read thread */ + chip->data_ready = true; + wake_up_interruptible(&chip->qg_wait_q); + chip->suspend_data = false; + } + + schedule_delayed_work(&chip->ttf->ttf_work, 0); + + return rc; +} + +static int qpnp_qg_suspend_noirq(struct device *dev) +{ + int rc; + struct qpnp_qg *chip = dev_get_drvdata(dev); + + /* cancel any pending sleep_exit work */ + cancel_delayed_work_sync(&chip->qg_sleep_exit_work); + + mutex_lock(&chip->data_lock); + + rc = process_suspend(chip); + if (rc < 0) + pr_err("Failed to process QG suspend, rc=%d\n", rc); + + mutex_unlock(&chip->data_lock); + + return 0; +} + +static int qpnp_qg_resume_noirq(struct device *dev) +{ + int rc; + struct qpnp_qg *chip = dev_get_drvdata(dev); + + mutex_lock(&chip->data_lock); + + rc = process_resume(chip); + if (rc < 0) + pr_err("Failed to process QG resume, rc=%d\n", rc); + + mutex_unlock(&chip->data_lock); + + return 0; +} + +static int qpnp_qg_suspend(struct device *dev) +{ + struct qpnp_qg *chip = dev_get_drvdata(dev); + + /* skip if profile is not loaded */ + if (!chip->profile_loaded) + return 0; + + /* disable GOOD_OCV IRQ in sleep */ + vote(chip->good_ocv_irq_disable_votable, + QG_INIT_STATE_IRQ_DISABLE, true, 0); + + return 0; +} + +static int qpnp_qg_resume(struct device *dev) +{ + struct qpnp_qg *chip = dev_get_drvdata(dev); + + /* skip if profile is not loaded */ + if (!chip->profile_loaded) + return 0; + + /* enable GOOD_OCV IRQ when active */ + vote(chip->good_ocv_irq_disable_votable, + QG_INIT_STATE_IRQ_DISABLE, false, 0); + + return 0; +} + +static const struct dev_pm_ops qpnp_qg_pm_ops = { + .suspend_noirq = qpnp_qg_suspend_noirq, + .resume_noirq = qpnp_qg_resume_noirq, + .suspend = qpnp_qg_suspend, + .resume = qpnp_qg_resume, +}; + +#ifdef OPLUS_FEATURE_CHG_BASIC + +#define DEFAULT_BATT_SOC 50 +#define MAX_WAIT_FOR_HEALTHD_COUNT 12 + +static int oplus_get_battery_voltage(void) +{ + int voltage = 0; + int rc = 0; + rc = qg_get_battery_voltage(qpnp_gauge_ic, &voltage); + pr_debug("oplus_get_battery_voltage = %d, rc= %d\n",voltage,rc); + return voltage/1000; +} + +static int oplus_get_prev_battery_mvolts_2cell_max(void) +{ + int voltage = 0; + int rc = 0; + rc = qg_get_battery_voltage(qpnp_gauge_ic, &voltage); + pr_debug("oplus_get_battery_voltage = %d, rc= %d\n",voltage,rc); + return voltage/1000; +} + +static int oplus_get_prev_battery_mvolts_2cell_min(void) +{ + int voltage = 0; + int rc = 0; + rc = qg_get_battery_voltage(qpnp_gauge_ic, &voltage); + pr_debug("oplus_get_battery_voltage = %d, rc= %d\n",voltage,rc); + return voltage/1000; +} + +#define TEMP_AVERAGE_SIZE 5 +static int oplus_get_battery_temperature(void) +{ + int i, curr_temp, avg_temp; + static int init_temp = true; + static int last_temp; + static int battTempBuffer[TEMP_AVERAGE_SIZE]; + static int temperature_sum; + static u8 tempIndex; + + qg_get_battery_temp(qpnp_gauge_ic, &curr_temp); + + if (init_temp == true) { + for (i = 0; i < TEMP_AVERAGE_SIZE; i++) + battTempBuffer[i] = curr_temp; + + last_temp = curr_temp; + temperature_sum = curr_temp * TEMP_AVERAGE_SIZE; + init_temp = false; + } + temperature_sum -= battTempBuffer[tempIndex]; + temperature_sum += curr_temp; + battTempBuffer[tempIndex] = curr_temp; + avg_temp = (temperature_sum) / TEMP_AVERAGE_SIZE; + + tempIndex = (tempIndex + 1) % TEMP_AVERAGE_SIZE; + + pr_debug("oplus_get_battery_temperature avg_temp = %d, curr_temp = %d\n",avg_temp,curr_temp); + return avg_temp; +} + +static int oplus_get_battery_current(void) +{ + int bat_current = 0; + int rc = 0; + qg_get_battery_current(qpnp_gauge_ic, &bat_current); + pr_debug("oplus_get_battery_current = %d, rc= %d\n",bat_current,rc); + return bat_current/1000; +} + +static int oplus_get_sub_current(void) +{ + int sub_current = 0; + int rc = 0; + qg_get_parallel_current_now(qpnp_gauge_ic, &sub_current); + pr_debug("oplus_get_sub_current = %d, rc= %d\n",sub_current,rc); + return sub_current/1000; +} + +static int oplus_get_battery_capacity(void) +{ + int capacity = 0; + int rc = 0; + rc = qg_get_battery_capacity(qpnp_gauge_ic, &capacity); + if (rc < 0) { + pr_err("failed to get battery soc, return 50!\n"); + return DEFAULT_BATT_SOC; + } + if (get_boot_mode() == MSM_BOOT_MODE__RECOVERY) { + return capacity; + } + + pr_debug("oplus_get_battery_capacity = %d, rc= %d\n",capacity,rc); + return capacity; +} + + +static int oplus_get_battery_cc(void) +{ + int batt_cc = 3500; + return batt_cc; +} + +static int oplus_get_battery_fcc(void) +{ + int64_t batt_fcc = 0; + int rc = 0; + rc = qg_get_learned_capacity(qpnp_gauge_ic, &batt_fcc); + if (rc < 0 || !batt_fcc) { + rc = qg_get_nominal_capacity((int *)&batt_fcc, 250, true); + } + + batt_fcc = batt_fcc / 1000; + + return batt_fcc; +} + +static int oplus_get_battery_remain_capacity(void) +{ + int remain_capacity = -1; + + qg_get_charge_counter(qpnp_gauge_ic, &remain_capacity); + remain_capacity = remain_capacity / 1000; + + return remain_capacity; +} + +static int oplus_get_battery_soh(void) +{ + int soh = 100; + return soh; +} + +static void oplus_set_battery_full(bool full) +{ + /* Do nothing */ +} + +static int oplus_update_battery_dod0(void) +{ + return 0; +} + +static bool oplus_get_battery_authenticate(void) +{ + bool rc = 0; + rc = is_batt_id_valid(qpnp_gauge_ic); + + return rc; +} + +static int oplus_update_soc_smooth_parameter(void) +{ + return 0; +} + +static struct oplus_gauge_operations qonp_gauge_ops = { + .get_battery_mvolts = oplus_get_battery_voltage, + .get_battery_temperature = oplus_get_battery_temperature, + .get_batt_remaining_capacity = oplus_get_battery_remain_capacity, + .get_battery_soc = oplus_get_battery_capacity, + .get_average_current = oplus_get_battery_current, + .get_sub_current = oplus_get_sub_current, + .get_battery_fcc = oplus_get_battery_fcc, + .get_prev_batt_fcc = oplus_get_battery_fcc, + .get_battery_cc = oplus_get_battery_cc, + .get_battery_soh = oplus_get_battery_soh, + .get_battery_authenticate = oplus_get_battery_authenticate, + .get_prev_battery_mvolts = oplus_get_battery_voltage, + .get_prev_battery_temperature = oplus_get_battery_temperature, + .set_battery_full = oplus_set_battery_full, + .get_prev_battery_soc = oplus_get_battery_capacity, + .get_prev_average_current = oplus_get_battery_current, + .get_prev_batt_remaining_capacity = oplus_get_battery_remain_capacity, + .get_battery_mvolts_2cell_max = oplus_get_battery_voltage, + .get_battery_mvolts_2cell_min = oplus_get_battery_voltage, + .get_prev_battery_mvolts_2cell_max = oplus_get_prev_battery_mvolts_2cell_max, + .get_prev_battery_mvolts_2cell_min = oplus_get_prev_battery_mvolts_2cell_min, + .update_battery_dod0 = oplus_update_battery_dod0, + .update_soc_smooth_parameter = oplus_update_soc_smooth_parameter, +}; +#endif +static int qpnp_qg_probe(struct platform_device *pdev) +{ + int rc = 0, soc = 0, nom_cap_uah; + struct qpnp_qg *chip; +#ifdef OPLUS_FEATURE_CHG_BASIC + struct oplus_gauge_chip *oplus_chip; +#endif + chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL); + if (!chip) + return -ENOMEM; + + chip->regmap = dev_get_regmap(pdev->dev.parent, NULL); + if (!chip->regmap) { + pr_err("Parent regmap is unavailable\n"); + return -ENXIO; + } + +#ifdef OPLUS_FEATURE_CHG_BASIC + qpnp_gauge_ic= chip; +#endif + + /* ADC for BID & THERM */ + chip->batt_id_chan = iio_channel_get(&pdev->dev, "batt-id"); + if (IS_ERR(chip->batt_id_chan)) { + rc = PTR_ERR(chip->batt_id_chan); + if (rc != -EPROBE_DEFER) + pr_err("batt-id channel unavailable, rc=%d\n", rc); + chip->batt_id_chan = NULL; + return rc; + } +#ifdef OPLUS_FEATURE_CHG_BASIC + chip->dev = &pdev->dev; + rc = charge_qg_parse_dt(chip); + if (rc < 0) { + pr_err("Failed to parse qpnp_qg_feture of DT, rc=%d\n", rc); + return rc; + } + + if(!chip->qpnp_qg_feture) { + chip->batt_therm_chan = iio_channel_get(&pdev->dev, "batt-therm_30k"); + }else { + chip->batt_therm_chan = iio_channel_get(&pdev->dev, "batt-therm"); + } +#else + chip->batt_therm_chan = iio_channel_get(&pdev->dev, "batt-therm"); +#endif + if (IS_ERR(chip->batt_therm_chan)) { + rc = PTR_ERR(chip->batt_therm_chan); + if (rc != -EPROBE_DEFER) + pr_err("batt-therm channel unavailable, rc=%d\n", rc); + chip->batt_therm_chan = NULL; + return rc; + } + +#ifdef OPLUS_FEATURE_CHG_BASIC + if(!chip->qpnp_qg_feture) + { + chip->parallel_isense_chan = iio_channel_get(&pdev->dev, "parallel_isense"); + if (IS_ERR(chip->parallel_isense_chan)) { + rc = PTR_ERR(chip->parallel_isense_chan); + if (rc != -EPROBE_DEFER) + pr_err("parallel_isense channel unavailable, rc=%d\n", rc); + chip->parallel_isense_chan = NULL; + return rc; + } + } +#endif + + chip->dev = &pdev->dev; + chip->debug_mask = &qg_debug_mask; + platform_set_drvdata(pdev, chip); + INIT_WORK(&chip->udata_work, process_udata_work); + INIT_WORK(&chip->qg_status_change_work, qg_status_change_work); + INIT_DELAYED_WORK(&chip->qg_sleep_exit_work, qg_sleep_exit_work); + mutex_init(&chip->bus_lock); + mutex_init(&chip->soc_lock); + mutex_init(&chip->data_lock); + init_waitqueue_head(&chip->qg_wait_q); + chip->maint_soc = -EINVAL; + chip->batt_soc = INT_MIN; + chip->cc_soc = INT_MIN; + chip->sys_soc = INT_MIN; + chip->full_soc = QG_SOC_FULL; + chip->chg_iterm_ma = INT_MIN; + chip->soh = -EINVAL; + chip->esr_actual = -EINVAL; + chip->esr_nominal = -EINVAL; + chip->batt_age_level = -EINVAL; + chip->qg_version = (u8)of_device_get_match_data(&pdev->dev); + + switch (chip->qg_version) { + case QG_LITE: + chip->max_fifo_length = 5; + break; + default: + chip->max_fifo_length = 8; + break; + } + + qg_create_debugfs(chip); + + rc = qg_alg_init(chip); + if (rc < 0) { + pr_err("Error in alg_init, rc:%d\n", rc); + return rc; + } + + rc = qg_parse_dt(chip); + if (rc < 0) { + pr_err("Failed to parse DT, rc=%d\n", rc); + return rc; + } + + rc = qg_hw_init(chip); + if (rc < 0) { + pr_err("Failed to hw_init, rc=%d\n", rc); + return rc; + } + + rc = qg_sdam_init(chip->dev); + if (rc < 0) { + pr_err("Failed to initialize QG SDAM, rc=%d\n", rc); + return rc; + } + + rc = qg_setup_battery(chip); + if (rc < 0) { + pr_err("Failed to setup battery, rc=%d\n", rc); + return rc; + } + + rc = qg_register_device(chip); + if (rc < 0) { + pr_err("Failed to register QG char device, rc=%d\n", rc); + return rc; + } + + rc = qg_sanitize_sdam(chip); + if (rc < 0) { + pr_err("Failed to sanitize SDAM, rc=%d\n", rc); + return rc; + } + + rc = qg_soc_init(chip); + if (rc < 0) { + pr_err("Failed to initialize SOC scaling init rc=%d\n", rc); + return rc; + } + + if (chip->profile_loaded) { + if (!chip->dt.cl_disable) { + /* + * Use FCC @ 25 C and charge-profile for + * Nominal Capacity + */ + rc = qg_get_nominal_capacity(&nom_cap_uah, 250, true); + if (!rc) { + rc = cap_learning_post_profile_init(chip->cl, + nom_cap_uah); + if (rc < 0) { + pr_err("Error in cap_learning_post_profile_init rc=%d\n", + rc); + return rc; + } + } + } + rc = restore_cycle_count(chip->counter); + if (rc < 0) { + pr_err("Error in restoring cycle_count, rc=%d\n", rc); + return rc; + } + schedule_delayed_work(&chip->ttf->ttf_work, 10000); + } + + rc = qg_determine_pon_soc(chip); + if (rc < 0) { + pr_err("Failed to determine initial state, rc=%d\n", rc); + goto fail_device; + } + + chip->awake_votable = create_votable("QG_WS", VOTE_SET_ANY, + qg_awake_cb, chip); + if (IS_ERR(chip->awake_votable)) { + rc = PTR_ERR(chip->awake_votable); + chip->awake_votable = NULL; + goto fail_device; + } + + chip->vbatt_irq_disable_votable = create_votable("QG_VBATT_IRQ_DISABLE", + VOTE_SET_ANY, qg_vbatt_irq_disable_cb, chip); + if (IS_ERR(chip->vbatt_irq_disable_votable)) { + rc = PTR_ERR(chip->vbatt_irq_disable_votable); + chip->vbatt_irq_disable_votable = NULL; + goto fail_device; + } + + chip->fifo_irq_disable_votable = create_votable("QG_FIFO_IRQ_DISABLE", + VOTE_SET_ANY, qg_fifo_irq_disable_cb, chip); + if (IS_ERR(chip->fifo_irq_disable_votable)) { + rc = PTR_ERR(chip->fifo_irq_disable_votable); + chip->fifo_irq_disable_votable = NULL; + goto fail_device; + } + + chip->good_ocv_irq_disable_votable = + create_votable("QG_GOOD_IRQ_DISABLE", + VOTE_SET_ANY, qg_good_ocv_irq_disable_cb, chip); + if (IS_ERR(chip->good_ocv_irq_disable_votable)) { + rc = PTR_ERR(chip->good_ocv_irq_disable_votable); + chip->good_ocv_irq_disable_votable = NULL; + goto fail_device; + } + + rc = qg_init_psy(chip); + if (rc < 0) { + pr_err("Failed to initialize QG psy, rc=%d\n", rc); + goto fail_votable; + } + + rc = qg_request_irqs(chip); + if (rc < 0) { + pr_err("Failed to register QG interrupts, rc=%d\n", rc); + goto fail_votable; + } + + rc = qg_post_init(chip); + if (rc < 0) { + pr_err("Failed in qg_post_init rc=%d\n", rc); + goto fail_votable; + } + + rc = sysfs_create_groups(&chip->dev->kobj, qg_groups); + if (rc < 0) { + pr_err("Failed to create sysfs files rc=%d\n", rc); + goto fail_votable; + } + + qg_get_battery_capacity(chip, &soc); + + pr_info("QG initialized! battery_profile=%s SOC=%d QG_subtype=%d QG_version=%s QG_mode=%s\n", + qg_get_battery_type(chip), soc, chip->qg_subtype, + (chip->qg_version == QG_LITE) ? "QG_LITE" : "QG_PMIC5", + (chip->qg_mode == QG_V_I_MODE) ? "QG_V_I" : "QG_V"); + +#ifdef OPLUS_FEATURE_CHG_BASIC + //if(chip->enable_qpnp_qg){ + oplus_chip = devm_kzalloc(&pdev->dev, + sizeof(struct oplus_gauge_chip), GFP_KERNEL); + if (!oplus_chip) { + qpnp_gauge_ic = NULL; + pr_err("oplus_chip kzalloc failed.\n"); + return -ENOMEM; + } + oplus_chip->dev = &pdev->dev; + oplus_chip->gauge_ops = &qonp_gauge_ops; + oplus_gauge_init(oplus_chip); + //}else{ + //pr_info("qpnp_qg_probe oplus_gauge is not enable\n"); + //} +#endif + return rc; + +fail_votable: + destroy_votable(chip->awake_votable); +fail_device: + device_destroy(chip->qg_class, chip->dev_no); + cdev_del(&chip->qg_cdev); + unregister_chrdev_region(chip->dev_no, 1); + return rc; +} + +static int qpnp_qg_remove(struct platform_device *pdev) +{ + struct qpnp_qg *chip = platform_get_drvdata(pdev); + + qg_batterydata_exit(); + qg_soc_exit(chip); + + cancel_delayed_work_sync(&chip->qg_sleep_exit_work); + cancel_work_sync(&chip->udata_work); + cancel_work_sync(&chip->qg_status_change_work); + sysfs_remove_groups(&chip->dev->kobj, qg_groups); + debugfs_remove_recursive(chip->dfs_root); + device_destroy(chip->qg_class, chip->dev_no); + cdev_del(&chip->qg_cdev); + unregister_chrdev_region(chip->dev_no, 1); + mutex_destroy(&chip->bus_lock); + mutex_destroy(&chip->data_lock); + mutex_destroy(&chip->soc_lock); + if (chip->awake_votable) + destroy_votable(chip->awake_votable); + + return 0; +} + +static void qpnp_qg_shutdown(struct platform_device *pdev) +{ + struct qpnp_qg *chip = platform_get_drvdata(pdev); + bool input_present = is_input_present(chip); + + if (!input_present || !chip->profile_loaded) + return; + /* + * Charging status doesn't matter when the device shuts down and we + * have to treat this as charge done. Hence pass charge_done as true. + */ + cycle_count_update(chip->counter, + DIV_ROUND_CLOSEST(chip->msoc * 255, 100), + POWER_SUPPLY_STATUS_NOT_CHARGING, + true, input_present); +} + +static const struct of_device_id match_table[] = { + { .compatible = "qcom,qpnp-qg", .data = (void *)QG_PMIC5, }, + { .compatible = "qcom,qpnp-qg-lite", .data = (void *)QG_LITE, }, + { }, +}; + +static struct platform_driver qpnp_qg_driver = { + .driver = { + .name = "qcom,qpnp-qg", + .of_match_table = match_table, + .pm = &qpnp_qg_pm_ops, + }, + .probe = qpnp_qg_probe, + .remove = qpnp_qg_remove, + .shutdown = qpnp_qg_shutdown, +}; +module_platform_driver(qpnp_qg_driver); + +MODULE_DESCRIPTION("QPNP QG Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/power/supply/qcom/qg-core.h b/drivers/power/supply/qcom/qg-core.h index 6b7432746fbe..853580e09e35 100644 --- a/drivers/power/supply/qcom/qg-core.h +++ b/drivers/power/supply/qcom/qg-core.h @@ -6,6 +6,14 @@ #ifndef __QG_CORE_H__ #define __QG_CORE_H__ +#ifdef OPLUS_FEATURE_CHG_BASIC +/* Yichun.Chen PSW.BSP.CHG 2018-05-04 Add for debug */ +#define qg_debug(fmt, ...) \ + printk(KERN_NOTICE "[OPLUS_CHG][%s]"fmt, __func__, ##__VA_ARGS__) + +#define qg_err(fmt, ...) \ + printk(KERN_ERR "[OPLUS_CHG][%s]"fmt, __func__, ##__VA_ARGS__) +#endif #include #include "fg-alg.h" #include "qg-defs.h" @@ -118,6 +126,9 @@ struct qpnp_qg { /* local data variables */ u32 batt_id_ohm; + #ifdef OPLUS_FEATURE_CHG_BASIC + u32 batt_id_kohm; + #endif struct qg_kernel_data kdata; struct qg_user_data udata; struct power_supply *batt_psy; @@ -143,6 +154,16 @@ struct qpnp_qg { bool charge_full; bool force_soc; bool fvss_active; +#ifndef OPLUS_FEATURE_CHG_BASIC + bool enable_qpnp_qg; +#endif +#ifdef OPLUS_FEATURE_CHG_BASIC + bool adc_compensation_enabled; +#endif +#ifdef OPLUS_FEATURE_CHG_BASIC +/* BSP.CHG.Basic, 2021/03/07, add Batt_NTC for small board NTC ADC flag */ + bool oplus_small_board_temp; +#endif bool tcss_active; bool bass_active; bool first_profile_load; @@ -164,6 +185,9 @@ struct qpnp_qg { int max_fcc_limit_ma; int bsoc_bass_entry; int qg_v_ibat; +#ifdef OPLUS_FEATURE_CHG_BASIC + int compensation_impedance; +#endif int qg_charge_counter; u32 fifo_done_count; u32 wa_flags; @@ -182,7 +206,10 @@ struct qpnp_qg { unsigned long suspend_time; struct iio_channel *batt_therm_chan; struct iio_channel *batt_id_chan; - +#ifdef OPLUS_FEATURE_CHG_BASIC + struct iio_channel *parallel_isense_chan; + bool qpnp_qg_feture; +#endif /* soc params */ int catch_up_soc; int maint_soc; @@ -207,6 +234,15 @@ struct qpnp_qg { struct cycle_counter *counter; /* ttf */ struct ttf *ttf; +#ifdef OPLUS_FEATURE_CHG_BASIC + /* Yichun.Chen PSW.BSP.CHG 2018-06-13 avoid when reboot soc reduce 1% */ + int skip_scale_soc_count; +#endif +#ifdef OPLUS_FEATURE_CHG_BASIC + /* Zejin.Yang BSP.CHG.Basic 2021-04-12 For oplus svooc/vooc chg project*/ + int asic_with_internal_gauge; +#endif + }; struct ocv_all { diff --git a/drivers/power/supply/qcom/qg-soc.c b/drivers/power/supply/qcom/qg-soc.c index 5b6a70bce855..bf6a5fed2b48 100644 --- a/drivers/power/supply/qcom/qg-soc.c +++ b/drivers/power/supply/qcom/qg-soc.c @@ -297,8 +297,17 @@ static int qg_process_tcss_soc(struct qpnp_qg *chip, int sys_soc) QG_MAX_SOC, qg_iterm_ua, chip->prev_fifo_i_ua); +#ifdef OPLUS_FEATURE_CHG_BASIC + if (chip->asic_with_internal_gauge){ + if(chip->prev_fifo_i_ua >= qg_iterm_ua) + soc_ibat = QG_MAX_SOC; + } +#endif + soc_ibat = CAP(QG_MIN_SOC, QG_MAX_SOC, soc_ibat); +#ifndef OPLUS_FEATURE_CHG_BASIC + wt_ibat = qg_linear_interpolate(1, chip->soc_tcss_entry, 10000, 10000, soc_ibat); wt_ibat = CAP(QG_MIN_SOC, QG_MAX_SOC, wt_ibat); @@ -307,6 +316,20 @@ static int qg_process_tcss_soc(struct qpnp_qg *chip, int sys_soc) chip->soc_tcss = DIV_ROUND_CLOSEST((soc_ibat * wt_ibat) + (wt_sys * sys_soc), 10000); chip->soc_tcss = CAP(QG_MIN_SOC, QG_MAX_SOC, chip->soc_tcss); +#else + if (chip->asic_with_internal_gauge){ + chip->soc_tcss = soc_ibat; + }else{ + wt_ibat = qg_linear_interpolate(1, chip->soc_tcss_entry, + 10000, 10000, soc_ibat); + wt_ibat = CAP(QG_MIN_SOC, QG_MAX_SOC, wt_ibat); + wt_sys = 10000 - wt_ibat; + + chip->soc_tcss = DIV_ROUND_CLOSEST((soc_ibat * wt_ibat) + + (wt_sys * sys_soc), 10000); + chip->soc_tcss = CAP(QG_MIN_SOC, QG_MAX_SOC, chip->soc_tcss); + } +#endif qg_dbg(chip, QG_DEBUG_SOC, "TCSS: fifo_i=%d prev_fifo_i=%d ibatt_tcss_entry=%d qg_term=%d soc_tcss_entry=%d sys_soc=%d soc_ibat=%d wt_ibat=%d wt_sys=%d soc_tcss=%d\n", @@ -384,7 +407,20 @@ int qg_adjust_sys_soc(struct qpnp_qg *chip) /* TCSS */ chip->sys_soc = qg_process_tcss_soc(chip, chip->sys_soc); - if (chip->sys_soc == QG_MAX_SOC) { +#ifdef OPLUS_FEATURE_CHG_BASIC + if (chip->sys_soc <= 50 && chip->asic_with_internal_gauge) { /* 0.5% */ + /* Hold SOC to 1% of VBAT has not dropped below cutoff */ + rc = qg_get_battery_voltage(chip, &vbat_uv); + if (!rc && vbat_uv >= (vcutoff_uv + VBAT_LOW_HYST_UV)) + soc = 1; + else + soc = 0; + } + else if (chip->sys_soc == QG_MAX_SOC) { +#else + if (chip->sys_soc == QG_MAX_SOC) { +#endif + soc = FULL_SOC; } else if (chip->sys_soc >= (QG_MAX_SOC - 100)) { /* Hold SOC to 100% if we are dropping from 100 to 99 */ @@ -462,6 +498,17 @@ static void get_next_update_time(struct qpnp_qg *chip) static bool is_scaling_required(struct qpnp_qg *chip) { bool input_present = is_input_present(chip); +#ifdef OPLUS_FEATURE_CHG_BASIC + int ibat = 0; + int rc; + if (chip->asic_with_internal_gauge){ + rc = qg_get_battery_current(chip, &ibat); + if(!rc){ + if (chip->catch_up_soc < chip->msoc && is_usb_present(chip) && ibat < 0) + return false; //charger inserted and has charging current, msoc don't drop. + } + } +#endif if (!chip->profile_loaded) return false; diff --git a/drivers/power/supply/qcom/qg-util.c b/drivers/power/supply/qcom/qg-util.c index 36b5fefa42aa..5749fa928309 100644 --- a/drivers/power/supply/qcom/qg-util.c +++ b/drivers/power/supply/qcom/qg-util.c @@ -364,17 +364,61 @@ int qg_get_battery_temp(struct qpnp_qg *chip, int *temp) { int rc = 0; +#ifdef OPLUS_FEATURE_CHG_BASIC + int pre_result = 0 , result = 0; + int pre_voltage = 0, voltage = 0; +#endif + + +#ifndef OPLUS_FEATURE_CHG_BASIC if (chip->battery_missing) { *temp = 250; return 0; } +#else + if (chip->batt_therm_chan == NULL) { + *temp = 250; + return 0; + } + if ((chip->battery_missing) && (!is_batt_id_valid(chip))) { + *temp = -400; + return 0; + } +#endif +#ifndef OPLUS_FEATURE_CHG_BASIC rc = iio_read_channel_processed(chip->batt_therm_chan, temp); if (rc < 0) { pr_err("Failed reading BAT_TEMP over ADC rc=%d\n", rc); return rc; } pr_debug("batt_temp = %d\n", *temp); +#else + rc = iio_read_channel_processed(chip->batt_therm_chan, &voltage); + if (rc < 0) { + pr_err("Failed reading BAT_TEMP over ADC rc=%d, voltage=%d\n", rc, voltage); + return rc; + } + + pre_voltage = voltage; + pre_voltage = div64_s64(pre_voltage, 1000); + rc = oplus_asic_vadc_map_voltage_temp(adcmap_batt_therm_asic, + ARRAY_SIZE(adcmap_batt_therm_asic), + pre_voltage, &pre_result); + + if(g_oplus_qg_ibta < -6000000) + g_oplus_qg_ibta = -6000000; + if(g_oplus_qg_ibta > 6000000) + g_oplus_qg_ibta = 6000000; + voltage = voltage + g_oplus_qg_ibta * 6; + voltage = div64_s64(voltage, 1000); + rc = oplus_asic_vadc_map_voltage_temp(adcmap_batt_therm_asic, + ARRAY_SIZE(adcmap_batt_therm_asic), + voltage, &result); + + *temp = result; + pr_err("v_temp = %d, ichg = %d, temp_before = %d, temp_after = %d\n",voltage, g_oplus_qg_ibta, pre_result, result); +#endif return 0; } diff --git a/drivers/power/supply/qcom/qpnp-fg-gen4.c b/drivers/power/supply/qcom/qpnp-fg-gen4.c index fcd26de667bf..6aa5e08e5cf6 100644 --- a/drivers/power/supply/qcom/qpnp-fg-gen4.c +++ b/drivers/power/supply/qcom/qpnp-fg-gen4.c @@ -21,6 +21,11 @@ #include "fg-core.h" #include "fg-reg.h" #include "fg-alg.h" +#ifdef OPLUS_FEATURE_CHG_BASIC +/* wangjiayuan_wt, BSP.CHG.Basic, 2021/9/2, Add for 21027 */ +#include "../../oplus/oplus_gauge.h" +#include +#endif #define FG_GEN4_DEV_NAME "qcom,fg-gen4" #define TTF_AWAKE_VOTER "fg_ttf_awake" @@ -204,6 +209,21 @@ #define MONOTONIC_SOC_v2_OFFSET 0 #define FIRST_LOG_CURRENT_v2_WORD 471 #define FIRST_LOG_CURRENT_v2_OFFSET 0 +#ifdef OPLUS_FEATURE_CHG_BASIC +#define BATTERY_SOC_JUMP 5 +#define BATTERY_SOC_JUMP_COUNT 2 +#endif +#ifdef OPLUS_FEATURE_CHG_BASIC +/* Add for oplus_gauge && batt ID check*/ +struct fg_gen4_chip *fg_gauge_ic; +static bool is_batt_id_valid(struct fg_gen4_chip *chip); +#endif + +#ifdef OPLUS_FEATURE_CHG_BASIC +/* Add for soc hop*/ +static int first_boot = 0; +static int pre_cap = 0; +#endif static struct fg_irq_info fg_irqs[FG_GEN4_IRQ_MAX]; @@ -266,6 +286,9 @@ struct fg_gen4_chip { struct fg_dev fg; struct fg_dt_props dt; struct iio_channel *batt_id_chan; +#ifdef OPLUS_FEATURE_CHG_BASIC + struct iio_channel *batt_therm_chan; +#endif struct cycle_counter *counter; struct cap_learning *cl; struct ttf *ttf; @@ -807,6 +830,14 @@ static int fg_gen4_get_battery_temp(struct fg_dev *fg, int *val) int rc = 0; u16 buf; +#ifdef OPLUS_FEATURE_CHG_BASIC +/* While batt_NTC & batt_ID both invalid return -40C */ + if ((fg->battery_missing) && (!is_batt_id_valid(fg_gauge_ic))) { + *val = -400; + return 0; + } +#endif + rc = fg_sram_read(fg, BATT_TEMP_WORD, BATT_TEMP_OFFSET, (u8 *)&buf, 2, FG_IMA_DEFAULT); if (rc < 0) { @@ -971,7 +1002,11 @@ static int fg_gen4_get_prop_capacity(struct fg_dev *fg, int *val) { struct fg_gen4_chip *chip = container_of(fg, struct fg_gen4_chip, fg); int rc, msoc; - +#ifdef OPLUS_FEATURE_CHG_BASIC +/* Add for soc hop*/ + static int count = 0; + static int soc_jump_count = 0; +#endif if (is_debug_batt_id(fg)) { *val = DEBUG_BATT_SOC; return 0; @@ -983,10 +1018,25 @@ static int fg_gen4_get_prop_capacity(struct fg_dev *fg, int *val) } if (fg->battery_missing || !fg->soc_reporting_ready) { - *val = BATT_MISS_SOC; - return 0; +#ifdef OPLUS_FEATURE_CHG_BASIC +/* Add for soc hop*/ + if (first_boot == 1) { + count++; + if (count > 3 ) { + *val = BATT_MISS_SOC; + count = 0; + first_boot = 0; + return 0; + } + } else { +#endif + *val = BATT_MISS_SOC; + return 0; +#ifdef OPLUS_FEATURE_CHG_BASIC +/* Add for soc hop*/ + } +#endif } - if (chip->vbatt_low) { *val = EMPTY_SOC; return 0; @@ -1005,10 +1055,26 @@ static int fg_gen4_get_prop_capacity(struct fg_dev *fg, int *val) rc = fg_get_msoc(fg, &msoc); if (rc < 0) return rc; - if (chip->dt.linearize_soc && fg->delta_soc > 0) +#ifndef OPLUS_FEATURE_CHG_BASIC + if (chip->dt.linearize_soc && fg->delta_soc > 0) { *val = fg->maint_soc; - else + } else { *val = msoc; + } +#else + if (chip->dt.linearize_soc && fg->delta_soc > 0) { + *val = fg->maint_soc; + } else { + if(msoc == 0 && pre_cap > BATTERY_SOC_JUMP) { + if(soc_jump_count < BATTERY_SOC_JUMP_COUNT) { + msoc = pre_cap; + soc_jump_count++; + } + } + *val = msoc; + pre_cap = msoc; + } +#endif } return 0; @@ -1551,7 +1617,7 @@ static int fg_gen4_adjust_ki_coeff_full_soc(struct fg_gen4_chip *chip, u8 val; if ((batt_temp < 0) || - (fg->charge_status == POWER_SUPPLY_STATUS_DISCHARGING)) { + (fg->charge_status == POWER_SUPPLY_STATUS_DISCHARGING) || (fg->charge_status == POWER_SUPPLY_STATUS_NOT_CHARGING)) { ki_coeff_full_soc_norm = 0; ki_coeff_full_soc_low = 0; } else if (fg->charge_status == POWER_SUPPLY_STATUS_CHARGING) { @@ -1662,7 +1728,7 @@ static int fg_gen4_adjust_ki_coeff_dischg(struct fg_dev *fg) return rc; } - if (fg->charge_status == POWER_SUPPLY_STATUS_DISCHARGING) { + if (fg->charge_status == POWER_SUPPLY_STATUS_DISCHARGING || fg->charge_status == POWER_SUPPLY_STATUS_NOT_CHARGING) { for (i = KI_COEFF_SOC_LEVELS - 1; i >= 0; i--) { if (msoc < chip->dt.ki_coeff_soc[i]) { ki_coeff_low = chip->dt.ki_coeff_low_dischg[i]; @@ -3386,8 +3452,8 @@ static int fg_gen4_validate_soc_scale_mode(struct fg_gen4_chip *chip) goto fail_soc_scale; } - if (!chip->soc_scale_mode && fg->charge_status == - POWER_SUPPLY_STATUS_DISCHARGING && + if (!chip->soc_scale_mode && (fg->charge_status == + POWER_SUPPLY_STATUS_DISCHARGING || fg->charge_status == POWER_SUPPLY_STATUS_NOT_CHARGING )&& chip->vbatt_avg < chip->dt.vbatt_scale_thr_mv) { rc = fg_gen4_enter_soc_scale(chip); if (rc < 0) { @@ -6007,6 +6073,20 @@ static int fg_gen4_parse_dt(struct fg_gen4_chip *chip) } } + rc = of_property_match_string(fg->dev->of_node, "io-channel-names", + "batt-therm"); + + if (rc >= 0) { + chip->batt_therm_chan = iio_channel_get(fg->dev, "batt-therm"); + if (IS_ERR(chip->batt_therm_chan)) { + rc = PTR_ERR(chip->batt_therm_chan); + if (rc != -EPROBE_DEFER) + pr_err("batt-therm channel unavailable, rc=%d\n", rc); + chip->batt_therm_chan = NULL; + return rc; + } + } + rc = fg_gen4_parse_child_nodes_dt(chip); if (rc < 0) return rc; @@ -6209,17 +6289,545 @@ static void fg_gen4_post_init(struct fg_gen4_chip *chip) fg_dbg(fg, FG_STATUS, "Disabled wakeable irqs for debug board\n"); } +#ifdef OPLUS_FEATURE_CHG_BASIC +/* Add battery id check */ +static int get_batt_id_voltage(struct fg_gen4_chip *chip) +{ + int rc, batt_id_mv; + + /* Read battery-id */ + rc = iio_read_channel_processed(chip->batt_id_chan, &batt_id_mv); + if (rc < 0) { + pr_err("Failed to read BATT_ID over ADC, rc=%d\n", rc); + return rc; + } + + batt_id_mv = div_s64(batt_id_mv, 1000); + pr_err("fg get batt_id_mv=%d from ADC\n",batt_id_mv); + + return batt_id_mv; +} + +struct batt_info +{ + u32 batt_id_ohm; + int batt_id_mv[2]; + char *batt_vendor; + char *batt_version; +}; + +struct proj_batt_info +{ + struct batt_info* batt_info; + int batt_vendor_count; + bool batt_devinfo_registered; +}; + +static struct batt_info rum_batt_info[1] = +{ + {100000, {550, 820}, "ATL", "V1.0"} +}; + +static struct proj_batt_info proj_batterys = +{ + .batt_info = NULL, + .batt_vendor_count = 0, + .batt_devinfo_registered = false, +}; + +static bool is_batt_id_valid(struct fg_gen4_chip *chip) +{ + int id, rc, batt_id_voltage; + bool batt_id_valid = false; + unsigned int project_num = 0; +/*avoid for bootup*/ + if (!chip) { + pr_err("chip is null, skip battid check temporary\n"); + return true; + } + + if (!chip->batt_id_chan) { + pr_err("batt_id_chan is null,skip battid temporary\n"); + return true; + } +/*avoid for bootup*/ + batt_id_voltage = get_batt_id_voltage(chip); + if (batt_id_voltage < 0) { + pr_err("Failed to detect batt_id rc=%d\n", rc); + return true; + } + + project_num = get_project(); + if (project_num == 0) { + pr_err("Faile to get project number\n"); + return true; + } + + pr_err("id_batt_id_valid project number=%u, battery id voltage=%d\n", + project_num, batt_id_voltage); + + proj_batterys.batt_info = rum_batt_info; + proj_batterys.batt_vendor_count = sizeof(rum_batt_info) / sizeof(struct batt_info); + + for (id = 0; id < proj_batterys.batt_vendor_count; id++) { + if(batt_id_voltage >= proj_batterys.batt_info[id].batt_id_mv[0] + && batt_id_voltage <= proj_batterys.batt_info[id].batt_id_mv[1]) { + /*if (!proj_batterys.batt_devinfo_registered) { + rc = register_device_proc("battery", "V1.0", proj_batterys.batt_info[id].batt_vendor); + if (rc) + pr_err("register_battery_devinfo fail\n"); + proj_batterys.batt_devinfo_registered = true; + }*/ + batt_id_valid = true; + break; + } + } + return batt_id_valid; +} +#endif + +#ifdef OPLUS_FEATURE_CHG_BASIC +/* wangjiayuan_wt, BSP.CHG.Basic, 2021/9/2, Add for 21027 fg platform */ +static struct fg_gen4_chip *fg_chip; +#define DEFAULT_BATT_TEMP -400 +#define DEFAULT_BATT_VOLT 3800 +#define DEFAULT_BATT_SOC 50 +#define DEFAULT_BATT_CURRENT 500 +#define VBAT_HIGH_THRESHOLD 4500 +#define TBAT_LOW_THRESHOLD -190 +#define TBAT_HIGH_THRESHOLD 550 + +static int oplus_fg_get_battery_mvolts(void) +{ + int rc = 0, uv_bat = 0; + + if (!fg_chip) { + return DEFAULT_BATT_VOLT; + } + + rc = fg_get_battery_voltage(&fg_chip->fg, &uv_bat); + if (rc < 0) { + pr_debug("failed to get battery voltage, return 3800mV\n"); + return DEFAULT_BATT_VOLT; + } + + /* if abnormal, read again */ + if (uv_bat > VBAT_HIGH_THRESHOLD * 1000) { + msleep(80); + fg_get_battery_voltage(&fg_chip->fg, &uv_bat); + if (rc < 0) { + pr_debug("failed to get battery voltage, return 3800mV\n"); + return DEFAULT_BATT_VOLT; + } + } + + return uv_bat / 1000; +} + +#ifdef OPLUS_FEATURE_CHG_BASIC +struct vadc_map_pt { + s32 x; + s32 y; +}; + +static const struct vadc_map_pt adcmap_100k_vref[] = { + {1840, -400}, + {1835, -380}, + {1828, -360}, + {1821, -340}, + {1813, -320}, + {1790, -300}, + {1778, -280}, + {1766, -260}, + {1752, -240}, + {1737, -220}, + {1720, -200}, + {1702, -180}, + {1682, -160}, + {1660, -140}, + {1637, -120}, + {1612, -100}, + {1585, -80}, + {1557, -60}, + {1526, -40}, + {1494, -20}, + {1460, 0}, + {1424, 20}, + {1387, 40}, + {1348, 60}, + {1308, 80}, + {1267, 100}, + {1225, 120}, + {1183, 140}, + {1139, 160}, + {1095, 180}, + {1052, 200}, + {1008, 220}, + {964, 240}, + {920, 260}, + {878, 280}, + {836, 300}, + {795, 320}, + {755, 340}, + {716, 360}, + {678, 380}, + {642, 400}, + {607, 420}, + {574, 440}, + {542, 460}, + {511, 480}, + {482, 500}, + {455, 520}, + {428, 540}, + {404, 560}, + {380, 580}, + {358, 600}, + {337, 620}, + {318, 640}, + {299, 660}, + {282, 680}, + {266, 700}, + {250, 720}, + {236, 740}, + {223, 760}, + {210, 780}, + {198, 800}, + {187, 820}, + {177, 840}, + {167, 860}, + {158, 880}, + {150, 900}, + {142, 920}, + {135, 940}, + {128, 960}, + {121, 980} + +}; + +static int qcom_vadc_map_voltage_temp(const struct vadc_map_pt *pts, + u32 tablesize, s32 input, s64 *output) +{ + bool descending = 1; + u32 i = 0; + + if (!pts) + return -EINVAL; + + /* Check if table is descending or ascending */ + if (tablesize > 1) { + if (pts[0].x < pts[1].x) + descending = 0; + } + + while (i < tablesize) { + if ((descending) && (pts[i].x < input)) { + /* table entry is less than measured*/ + /* value and table is descending, stop */ + break; + } else if ((!descending) && + (pts[i].x > input)) { + /* table entry is greater than measured*/ + /*value and table is ascending, stop */ + break; + } + i++; + } + + if (i == 0) { + *output = pts[0].y; + } else if (i == tablesize) { + *output = pts[tablesize - 1].y; + } else { + /* result is between search_index and search_index-1 */ + /* interpolate linearly */ + *output = (((s32)((pts[i].y - pts[i - 1].y) * + (input - pts[i - 1].x)) / + (pts[i].x - pts[i - 1].x)) + + pts[i - 1].y); + } + + return 0; +} +#endif + +static int oplus_fg_get_battery_temperature(void) +{ +#ifdef OPLUS_FEATURE_CHG_BASIC + int adc_code; + s32 voltage = 0; + s64 bat_temp = 0; +#endif + int rc = 0, temp_bat = 0; + + if (!fg_chip) { + return DEFAULT_BATT_TEMP; + } + + if(get_PCB_Version() < DVT1){ + return 250; + } +#ifdef OPLUS_FEATURE_CHG_BASIC + if(fg_chip->batt_therm_chan && get_PCB_Version() >= DVT1) { + rc = iio_read_channel_processed(fg_chip->batt_therm_chan, &adc_code); + if (rc < 0) { + pr_err("Failed reading BAT_TEMP over ADC rc=%d\n", rc); + return DEFAULT_BATT_TEMP; + } + + voltage = adc_code / 1000; + + rc = qcom_vadc_map_voltage_temp(adcmap_100k_vref, ARRAY_SIZE(adcmap_100k_vref),voltage,&bat_temp); + + /* if abnormal, read again */ + if (bat_temp < TBAT_LOW_THRESHOLD || bat_temp > TBAT_HIGH_THRESHOLD) { + msleep(80); + rc = qcom_vadc_map_voltage_temp(adcmap_100k_vref, ARRAY_SIZE(adcmap_100k_vref),voltage,&bat_temp); + if (rc < 0) { + pr_debug("failed to get battery temp, return 25C\n"); + return DEFAULT_BATT_TEMP; + } + } + return (int)bat_temp; + } else { +#endif + rc = fg_gen4_get_battery_temp(&fg_chip->fg, &temp_bat); + if (rc < 0) { + pr_debug("failed to get battery temp, return 25C\n"); + return DEFAULT_BATT_TEMP; + } + + /* if abnormal, read again */ + if (temp_bat < TBAT_LOW_THRESHOLD || temp_bat > TBAT_HIGH_THRESHOLD) { + msleep(80); + rc = fg_gen4_get_battery_temp(&fg_chip->fg, &temp_bat); + if (rc < 0) { + pr_debug("failed to get battery temp, return 25C\n"); + return DEFAULT_BATT_TEMP; + } + } + + return temp_bat; +#ifdef OPLUS_FEATURE_CHG_BASIC + } +#endif +} + +static int oplus_fg_get_batt_remaining_capacity(void) +{ + int soc_bat = -1; + + fg_gen4_get_charge_counter_shadow(fg_chip, &soc_bat); + soc_bat = soc_bat/1000; + + return soc_bat; +} + +static int oplus_fg_get_battery_soc(void) +{ + int soc_bat = 0; + + if (!fg_chip) { + return DEFAULT_BATT_SOC; + } + + fg_gen4_get_prop_capacity(&fg_chip->fg, &soc_bat); + + return soc_bat; +} + +static int oplus_fg_get_average_current(void) +{ + int ua_bat = 0; + int rc = 0; + + if (!fg_chip) { + return DEFAULT_BATT_CURRENT; + } + + rc = fg_get_battery_current(&fg_chip->fg, &ua_bat); + + return ua_bat/1000; +} + +static int oplus_fg_get_battery_fcc(void) +{ + int rc = 0; + int64_t temp = 0; + + rc = fg_gen4_get_learned_capacity(fg_chip, &temp); + if (rc < 0 || !temp) { + rc = fg_gen4_get_nominal_capacity(fg_chip, &temp); + } + temp = temp/1000; + + return temp; +} + +static int oplus_fg_get_battery_cc(void) +{ + int cc_soc = 0; + int rc = 0; + + rc = fg_gen4_get_cc_soc_sw(fg_chip, &cc_soc); + /*pr_err("kilody: rc=%d,cc_soc=%d\n", rc,cc_soc);*/ + + return cc_soc; +} + +static int oplus_fg_get_battery_soh(void) +{ + return fg_chip->soh; +} + +static bool oplus_fg_get_battery_authenticate(void) +{ + bool rc = 0; + + if (get_PCB_Version() < DVT1) { + pr_err("EVT skip batt id check\n"); + return true; + } else { + rc = is_batt_id_valid(fg_gauge_ic); + return rc; + } +} + +static int oplus_fg_get_prev_battery_mvolts(void) +{ + int uv_bat = 3800; + + uv_bat = oplus_fg_get_battery_mvolts(); + + return uv_bat; +} + +static int oplus_fg_get_prev_battery_temperature(void) +{ + int temp_bat = 250; + + temp_bat = oplus_fg_get_battery_temperature(); + + return temp_bat; +} + +static int oplus_fg_get_prev_battery_soc(void) +{ + int soc_bat = 0; + + soc_bat = oplus_fg_get_battery_soc(); + + return soc_bat; +} + +static int oplus_fg_get_prev_average_current(void) +{ + int current_bat = 1000; + + current_bat = oplus_fg_get_average_current(); + + return current_bat; +} + +static int oplus_fg_get_prev_batt_remaining_capacity(void) +{ + int soc_bat = -1; + + fg_gen4_get_charge_counter_shadow(fg_chip, &soc_bat); + soc_bat = soc_bat/1000; + + return soc_bat; +} + +static int oplus_fg_get_battery_mvolts_2cell_max(void) +{ + return oplus_fg_get_battery_mvolts(); +} + +static int oplus_fg_get_battery_mvolts_2cell_min(void) +{ + return oplus_fg_get_battery_mvolts(); +} + +static int oplus_fg_prev_battery_mvolts_2cell_max(void) +{ + return 3800; +} + +static int oplus_fg_prev_battery_mvolts_2cell_min(void) +{ + return 3800; +} + +static void oplus_fg_set_battery_full(bool enable) +{ + /* Do nothing */ +} + +static int oplus_fg_modify_dod0(void) +{ + return 0; +} + +static int oplus_fg_update_soc_smooth_parameter(void) +{ + return 0; +} + +void oplus_set_float_uv_ma(int iterm_ma, int float_volt_uv) +{ + struct fg_dev *fg; + //fg_chip->fg->dt.iterm_ma = iterm_ma; + fg->bp.float_volt_uv = float_volt_uv; + pr_err("kilody: oplus_set_float_uv_ma float_volt_uv=%d\n", float_volt_uv); +} + +static struct oplus_gauge_operations oplus_gauge_ops = { + .get_battery_mvolts = oplus_fg_get_battery_mvolts, + .get_battery_temperature = oplus_fg_get_battery_temperature, + .get_batt_remaining_capacity = oplus_fg_get_batt_remaining_capacity, + .get_battery_soc = oplus_fg_get_battery_soc, + .get_average_current = oplus_fg_get_average_current, + .set_battery_full = oplus_fg_set_battery_full, + .get_battery_fcc = oplus_fg_get_battery_fcc, + .get_prev_batt_fcc = oplus_fg_get_battery_fcc, + .get_battery_cc = oplus_fg_get_battery_cc, + .get_battery_soh = oplus_fg_get_battery_soh, + .get_battery_authenticate = oplus_fg_get_battery_authenticate, + .get_prev_battery_mvolts = oplus_fg_get_prev_battery_mvolts, + .get_prev_battery_temperature = oplus_fg_get_prev_battery_temperature, + .get_prev_battery_soc = oplus_fg_get_prev_battery_soc, + .get_prev_average_current = oplus_fg_get_prev_average_current, + .get_prev_batt_remaining_capacity = oplus_fg_get_prev_batt_remaining_capacity, + .get_battery_mvolts_2cell_max = oplus_fg_get_battery_mvolts_2cell_max, + .get_battery_mvolts_2cell_min = oplus_fg_get_battery_mvolts_2cell_min, + .get_prev_battery_mvolts_2cell_max = oplus_fg_prev_battery_mvolts_2cell_max, + .get_prev_battery_mvolts_2cell_min = oplus_fg_prev_battery_mvolts_2cell_min, + .update_battery_dod0 = oplus_fg_modify_dod0, + .update_soc_smooth_parameter = oplus_fg_update_soc_smooth_parameter, + .set_float_uv_ma = oplus_set_float_uv_ma, +}; +#endif + static int fg_gen4_probe(struct platform_device *pdev) { struct fg_gen4_chip *chip; struct fg_dev *fg; struct power_supply_config fg_psy_cfg = {}; +#ifdef OPLUS_FEATURE_CHG_BASIC +/* wangjiayuan_wt, BSP.CHG.Basic, 2021/9/2, Add for 21027 */ + struct oplus_gauge_chip *fg_oplus_gauge_chip = NULL; +#endif int rc, msoc, volt_uv, batt_temp; chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL); if (!chip) return -ENOMEM; +#ifdef OPLUS_FEATURE_CHG_BASIC + /* Add for oplus_gauge*/ + fg_gauge_ic = chip; +#endif + fg = &chip->fg; fg->dev = &pdev->dev; fg->debug_mask = &fg_gen4_debug_mask; @@ -6232,6 +6840,10 @@ static int fg_gen4_probe(struct platform_device *pdev) chip->esr_soh_cycle_count = -EINVAL; chip->calib_level = -EINVAL; chip->soh = -EINVAL; +#ifdef OPLUS_FEATURE_CHG_BASIC +/* Add for soc hop*/ + first_boot = 1; +#endif fg->regmap = dev_get_regmap(fg->dev->parent, NULL); if (!fg->regmap) { dev_err(fg->dev, "Parent regmap is unavailable\n"); @@ -6389,6 +7001,22 @@ static int fg_gen4_probe(struct platform_device *pdev) /* Keep MEM_ATTN_IRQ disabled until we require it */ vote(chip->mem_attn_irq_en_votable, MEM_ATTN_IRQ_VOTER, false, 0); +#ifdef OPLUS_FEATURE_CHG_BASIC + /* wangjiayuan_wt, BSP.CHG.Basic, 2021/9/2, Add for 21027 */ + fg_chip = chip; + fg_oplus_gauge_chip = devm_kzalloc(fg->dev, + sizeof(struct oplus_gauge_chip), GFP_KERNEL); + if (!fg_oplus_gauge_chip) { + pr_err("kzalloc() failed.\n"); + fg_chip = NULL; + return -ENOMEM; + } else { + fg_oplus_gauge_chip->dev = fg->dev; + fg_oplus_gauge_chip->gauge_ops = &oplus_gauge_ops; + oplus_gauge_init(fg_oplus_gauge_chip); + } +#endif + fg_debugfs_create(fg); rc = sysfs_create_groups(&fg->dev->kobj, fg_groups); @@ -6429,7 +7057,7 @@ static int fg_gen4_probe(struct platform_device *pdev) fg_gen4_post_init(chip); - pr_debug("FG GEN4 driver probed successfully\n"); + pr_info("FG GEN4 driver probed successfully\n"); return 0; exit: fg_gen4_cleanup(chip); diff --git a/drivers/power/supply/qcom/qpnp-qg.c b/drivers/power/supply/qcom/qpnp-qg.c index 0032df497d2a..1326ee87e3a9 100644 --- a/drivers/power/supply/qcom/qpnp-qg.c +++ b/drivers/power/supply/qcom/qpnp-qg.c @@ -37,7 +37,7 @@ #include "qg-battery-profile.h" #include "qg-defs.h" -static int qg_debug_mask; +static int qg_debug_mask = 0x7ff; static int qg_esr_mod_count = 30; static ssize_t esr_mod_count_show(struct device *dev, struct device_attribute diff --git a/drivers/power/supply/qcom/schgm-flash.c b/drivers/power/supply/qcom/schgm-flash.c index b92ace1d4300..11cf6a0f2b40 100644 --- a/drivers/power/supply/qcom/schgm-flash.c +++ b/drivers/power/supply/qcom/schgm-flash.c @@ -15,7 +15,9 @@ #include #include #include +#ifndef OPLUS_FEATURE_CHG_BASIC #include "smb5-lib.h" +#endif #include "schgm-flash.h" #define IS_BETWEEN(left, right, value) \ diff --git a/drivers/power/supply/qcom/schgm-flash.h b/drivers/power/supply/qcom/schgm-flash.h index 1294467fbacd..ef40c88980a3 100644 --- a/drivers/power/supply/qcom/schgm-flash.h +++ b/drivers/power/supply/qcom/schgm-flash.h @@ -7,7 +7,16 @@ #define __SCHGM_FLASH_H__ #include +#ifdef OPLUS_FEATURE_CHG_BASIC +#if defined(CONFIG_OPLUS_SM8250_CHARGER) +#include "../../oplus/charger_ic/oplus_battery_msm8250.h" +#elif defined(CONFIG_OPLUS_SM7250R_CHARGER) +#include "../../oplus/charger_ic/oplus_battery_msm7250_R.h" +#endif +#endif +#ifndef __SCHGM_FLASH_SUB_H__ +#define __SCHGM_FLASH_SUB_H__ #define SCHGM_FLASH_BASE 0xA600 #define SCHGM_FLASH_STATUS_2_REG (SCHGM_FLASH_BASE + 0x07) @@ -51,4 +60,5 @@ bool is_flash_active(struct smb_charger *chg); irqreturn_t schgm_flash_default_irq_handler(int irq, void *data); irqreturn_t schgm_flash_ilim2_irq_handler(int irq, void *data); irqreturn_t schgm_flash_state_change_irq_handler(int irq, void *data); +#endif /*__SCHGM_FLASH_SUB_H__*/ #endif /* __SCHGM_FLASH_H__ */ diff --git a/drivers/power/supply/qcom/smb1355-charger.c b/drivers/power/supply/qcom/smb1355-charger.c index c479865209c8..163e5722a039 100644 --- a/drivers/power/supply/qcom/smb1355-charger.c +++ b/drivers/power/supply/qcom/smb1355-charger.c @@ -179,6 +179,10 @@ #define PARALLEL_ENABLE_VOTER "PARALLEL_ENABLE_VOTER" +#ifdef OPLUS_FEATURE_CHG_BASIC +static int factory_test_lock = 0; +#endif + struct smb_chg_param { const char *name; u16 reg; @@ -381,7 +385,13 @@ static int smb1355_set_charge_param(struct smb1355 *chip, param->name, val_u, param->min_u, param->max_u); return -EINVAL; } - +#ifdef OPLUS_FEATURE_CHG_BASIC + else + { + pr_debug("%s: %d is in range [%d, %d]\n", + param->name, val_u, param->min_u, param->max_u); + } +#endif val_raw = (val_u - param->min_u) / param->step_u; rc = smb1355_write(chip, param->reg, val_raw); @@ -408,6 +418,8 @@ static int smb1355_get_charge_param(struct smb1355 *chip, } *val_u = val_raw * param->step_u + param->min_u; + pr_info("%s: %d \n", + param->name, val_u); return rc; } @@ -574,6 +586,9 @@ static enum power_supply_property smb1355_parallel_props[] = { POWER_SUPPLY_PROP_CURRENT_MAX, POWER_SUPPLY_PROP_SET_SHIP_MODE, POWER_SUPPLY_PROP_DIE_HEALTH, +#ifdef OPLUS_FEATURE_CHG_BASIC + POWER_SUPPLY_PROP_SMB1355_TEST, +#endif }; static int smb1355_get_prop_batt_charge_type(struct smb1355 *chip, @@ -850,6 +865,11 @@ static int smb1355_parallel_get_prop(struct power_supply *psy, /* Not in ship mode as long as device is active */ val->intval = 0; break; +#ifdef OPLUS_FEATURE_CHG_BASIC + case POWER_SUPPLY_PROP_SMB1355_TEST: + val->intval = factory_test_lock; + break; +#endif default: pr_err_ratelimited("parallel psy get prop %d not supported\n", prop); @@ -867,6 +887,7 @@ static int smb1355_parallel_get_prop(struct power_supply *psy, static int smb1355_set_parallel_charging(struct smb1355 *chip, bool disable) { int rc; + pr_debug("%s start chip->dt.pl_mode = %d disable = %d\n",__func__, chip->dt.pl_mode, disable); if (chip->disabled == disable) return 0; @@ -937,10 +958,11 @@ static int smb1355_set_parallel_charging(struct smb1355 *chip, bool disable) static int smb1355_set_current_max(struct smb1355 *chip, int curr) { int rc = 0; + pr_debug("%s start chip->dt.pl_mode = %d\n",__func__, chip->dt.pl_mode); if (!IS_USBIN(chip->dt.pl_mode)) return 0; - + pr_debug("%s start curr = %d\n",__func__, curr); if ((curr / 1000) < 100) { /* disable parallel path (ICL < 100mA) */ rc = smb1355_set_parallel_charging(chip, true); @@ -948,6 +970,7 @@ static int smb1355_set_current_max(struct smb1355 *chip, int curr) rc = smb1355_set_parallel_charging(chip, false); if (rc < 0) return rc; + pr_err("%s start rc =%d\n",__func__, rc); rc = smb1355_set_charge_param(chip, &chip->param.usb_icl, curr); @@ -988,15 +1011,28 @@ static int smb1355_parallel_set_prop(struct power_supply *psy, rc = smb1355_set_parallel_charging(chip, (bool)val->intval); break; case POWER_SUPPLY_PROP_CURRENT_MAX: +#ifdef OPLUS_FEATURE_CHG_BASIC + //if (factory_test_lock == 0) + rc = smb1355_set_current_max(chip, val->intval); +#else rc = smb1355_set_current_max(chip, val->intval); +#endif break; case POWER_SUPPLY_PROP_VOLTAGE_MAX: rc = smb1355_set_charge_param(chip, &chip->param.ov, val->intval); break; case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX: +#ifdef OPLUS_FEATURE_CHG_BASIC + //if (factory_test_lock == 0) { + pr_err("%s POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX val->intval = %d\n",__func__,val->intval); + rc = smb1355_set_charge_param(chip, &chip->param.fcc, + val->intval); + //} +#else rc = smb1355_set_charge_param(chip, &chip->param.fcc, val->intval); +#endif break; case POWER_SUPPLY_PROP_CONNECTOR_HEALTH: chip->c_health = val->intval; @@ -1009,6 +1045,25 @@ static int smb1355_parallel_set_prop(struct power_supply *psy, break; rc = smb1355_clk_request(chip, false); break; +#ifdef OPLUS_FEATURE_CHG_BASIC + case POWER_SUPPLY_PROP_SMB1355_TEST: + pr_err("%s POWER_SUPPLY_PROP_SMB1355_TEST val->intval = %d\n",__func__,val->intval); + if (val->intval == 1) { + factory_test_lock = 1; + rc = smb1355_set_charge_param(chip, &chip->param.fcc, 1000000); + rc = smb1355_set_charge_param(chip, &chip->param.usb_icl, 1000000); + rc = smb1355_masked_write(chip, CHGR_CFG2_REG, CHG_EN_POLARITY_BIT | CHG_EN_SRC_BIT, 0); + rc = smb1355_masked_write(chip, CHGR_CHARGING_ENABLE_CMD_REG, CHARGING_ENABLE_CMD_BIT, CHARGING_ENABLE_CMD_BIT); + } else if (val->intval == 0) { + rc = smb1355_set_charge_param(chip, &chip->param.fcc, 0); + rc = smb1355_set_charge_param(chip, &chip->param.usb_icl, 0); + rc = smb1355_masked_write(chip, CHGR_CFG2_REG, CHG_EN_POLARITY_BIT | CHG_EN_SRC_BIT, 0); + rc = smb1355_masked_write(chip, CHGR_CHARGING_ENABLE_CMD_REG, CHARGING_ENABLE_CMD_BIT, 0); + factory_test_lock = 0; + } + pr_err("factory_test_lock = %d\n", factory_test_lock); + break; +#endif default: pr_debug("parallel power supply set prop %d not supported\n", prop); @@ -1025,6 +1080,10 @@ static int smb1355_parallel_prop_is_writeable(struct power_supply *psy, switch (prop) { case POWER_SUPPLY_PROP_CONNECTOR_HEALTH: return 1; +#ifdef OPLUS_FEATURE_CHG_BASIC + case POWER_SUPPLY_PROP_SMB1355_TEST: + return 1; +#endif default: break; } @@ -1374,8 +1433,13 @@ static int smb1355_init_hw(struct smb1355 *chip) /* USBIN-USBIN configuration */ if (IS_USBIN(chip->dt.pl_mode)) { /* set swicther clock frequency to 700kHz */ +#ifdef OPLUS_FEATURE_CHG_BASIC + rc = smb1355_masked_write(chip, MISC_CUST_SDCDC_CLK_CFG_REG, + SWITCHER_CLK_FREQ_MASK, 0x0a); +#else rc = smb1355_masked_write(chip, MISC_CUST_SDCDC_CLK_CFG_REG, SWITCHER_CLK_FREQ_MASK, 0x03); +#endif if (rc < 0) { pr_err("Couldn't set MISC_CUST_SDCDC_CLK_CFG rc=%d\n", rc); diff --git a/drivers/power/supply/qcom/smb5-reg.h b/drivers/power/supply/qcom/smb5-reg.h index 311e810c31c0..198151d4b14c 100644 --- a/drivers/power/supply/qcom/smb5-reg.h +++ b/drivers/power/supply/qcom/smb5-reg.h @@ -58,6 +58,18 @@ enum { #define BAT_TEMP_STATUS_TOO_HOT_AFP_BIT BIT(1) #define BAT_TEMP_STATUS_TOO_COLD_AFP_BIT BIT(0) +#ifdef OPLUS_FEATURE_CHG_BASIC +#define BATTERY_CHARGER_STATUS_8_REG (CHGR_BASE + 0x0E) +//#define PRE_FAST_BIT BIT(7) +#define PRE_FULLON_BIT BIT(6) +//#define PRE_RCHG_BIT BIT(5) +#define PRE_INHIBIT_BIT BIT(3) +#define PRE_OVRV_BIT BIT(4) +#define PRE_TERM_BIT BIT(2) +//#define BAT_ID_BMISS_CMP_BIT BIT(1) +//#define THERM_CMP_BIT BIT(0) +#endif + #define CHARGING_ENABLE_CMD_REG (CHGR_BASE + 0x42) #define CHARGING_ENABLE_CMD_BIT BIT(0) @@ -71,6 +83,10 @@ enum { #define CHARGER_INHIBIT_BIT BIT(0) #define CHGR_FAST_CHARGE_CURRENT_CFG_REG (CHGR_BASE + 0x61) +#ifdef OPLUS_FEATURE_CHG_BASIC +#define TCCC_CHARGE_CURRENT_TERMINATION_CFG_REG (CHGR_BASE + 0x63) +#define TCCC_CHARGE_CURRENT_TERMINATION_SETTING_MASK GENMASK(3, 0) +#endif #define CHGR_ADC_ITERM_UP_THD_MSB_REG (CHGR_BASE + 0x67) #define CHGR_ADC_ITERM_UP_THD_LSB_REG (CHGR_BASE + 0x68) @@ -102,6 +118,7 @@ enum { #define CHGR_ADC_RECHARGE_THRESHOLD_LSB_REG (CHGR_BASE + 0x7F) #define JEITA_EN_CFG_REG (CHGR_BASE + 0x90) +#define JEITA_EN_HARDLIMIT_BIT BIT(4) #define JEITA_EN_HOT_SL_FCV_BIT BIT(3) #define JEITA_EN_COLD_SL_FCV_BIT BIT(2) #define JEITA_EN_HOT_SL_CCC_BIT BIT(1) @@ -143,9 +160,14 @@ enum { #define DCDC_CMD_OTG_REG (DCDC_BASE + 0x40) #define OTG_EN_BIT BIT(0) +#define DCDC_VBOOST_CFG (DCDC_BASE + 0x86) + #define DCDC_FSW_SEL_REG (DCDC_BASE + 0x50) #define DCDC_OTG_CURRENT_LIMIT_CFG_REG (DCDC_BASE + 0x52) +#ifdef OPLUS_FEATURE_CHG_BASIC +#define DCDC_OTG_CURRENT_LIMIT_1000MA_BIT BIT(2) +#endif /* OPLUS_FEATURE_CHG_BASIC */ #define DCDC_OTG_CFG_REG (DCDC_BASE + 0x53) #define OTG_EN_SRC_CFG_BIT BIT(1) @@ -260,6 +282,12 @@ enum { #define FORCE_5V BIT(0) #define FORCE_NULL 0 +#define USBIN_ADAPTER_ALLOW_OVERRIDE_REG (USBIN_BASE + 0x44) +#define USBIN_ADAPTER_CONTINUOUS_BIT BIT(3) +#define USBIN_ADAPTER_FORCE_9V_BIT BIT(1) +#define USBIN_ADAPTER_FORCE_5V_BIT BIT(0) + + #define USB_CMD_PULLDOWN_REG (USBIN_BASE + 0x45) #define EN_PULLDOWN_USB_IN_BIT BIT(0) @@ -275,6 +303,19 @@ enum { HVDCP_PULSE_COUNT_MAX_QC2_INVALID = 0xC0 }; +#define USBIN_ADAPTER_ALLOW_CFG_REG (USBIN_BASE + 0x60) +enum { + USBIN_ADAPTER_ALLOW_5V = 0, + USBIN_ADAPTER_ALLOW_9V = 2, + USBIN_ADAPTER_ALLOW_5V_OR_9V = 3, + USBIN_ADAPTER_ALLOW_12V = 4, + USBIN_ADAPTER_ALLOW_5V_OR_12V = 5, + USBIN_ADAPTER_ALLOW_9V_TO_12V = 6, + USBIN_ADAPTER_ALLOW_5V_OR_9V_TO_12V = 7, + USBIN_ADAPTER_ALLOW_5V_TO_9V = 8, + USBIN_ADAPTER_ALLOW_5V_TO_12V = 12, +}; + #define USBIN_OPTIONS_1_CFG_REG (USBIN_BASE + 0x62) #define HVDCP_AUTH_ALG_EN_CFG_BIT BIT(6) #define HVDCP_AUTONOMOUS_MODE_EN_CFG_BIT BIT(5) @@ -302,9 +343,22 @@ enum { #define USBIN_AICL_OPTIONS_CFG_REG (USBIN_BASE + 0x80) #define SUSPEND_ON_COLLAPSE_USBIN_BIT BIT(7) +#ifdef OPLUS_FEATURE_CHG_BASIC +#define USBIN_AICL_HDC_EN_BIT BIT(6) +#define USBIN_AICL_START_AT_MAX_BIT BIT(5) +#endif #define USBIN_AICL_PERIODIC_RERUN_EN_BIT BIT(4) #define USBIN_AICL_ADC_EN_BIT BIT(3) #define USBIN_AICL_EN_BIT BIT(2) +#ifdef OPLUS_FEATURE_CHG_BASIC +#define USBIN_HV_COLLAPSE_RESPONSE_BIT BIT(1) +#define USBIN_LV_COLLAPSE_RESPONSE_BIT BIT(0) +#endif + +#ifdef OPLUS_FEATURE_CHG_BASIC +#define TYPE_C_CFG_REG (USBIN_BASE + 0x58) +#define APSD_START_ON_CC_BIT BIT(7) +#endif #define USB_ENG_SSUPPLY_USB2_REG (USBIN_BASE + 0xC0) #define ENG_SSUPPLY_12V_OV_OPT_BIT BIT(1) @@ -395,6 +449,10 @@ enum { #define TYPEC_CCOUT_VALUE_BIT BIT(1) #define TYPEC_CCOUT_SRC_BIT BIT(0) +#ifdef OPLUS_FEATURE_CHG_BASIC +#define DEBUG_ACCESS_SNK_CFG_REG (TYPEC_BASE + 0x4a) +#endif + #define DEBUG_ACCESS_SRC_CFG_REG (TYPEC_BASE + 0x4C) #define EN_UNORIENTED_DEBUG_ACCESS_SRC_BIT BIT(0) @@ -417,6 +475,9 @@ enum { TYPEC_SRC_RP_MAX_ELEMENTS }; +#define TYPE_C_CC_CURRSRC_CONTROL_REG (TYPEC_BASE + 0x5C) +#define TYPE_C_CC_CURRSRC_CONTROL_MASK GENMASK(3, 0) + #define TYPE_C_INTERRUPT_EN_CFG_1_REG (TYPEC_BASE + 0x5E) #define TYPEC_LEGACY_CABLE_INT_EN_BIT BIT(7) #define TYPEC_NONCOMPLIANT_LEGACY_CABLE_INT_EN_BIT BIT(6) @@ -498,6 +559,9 @@ enum { #define AICL_CMD_REG (MISC_BASE + 0x44) #define RESTART_AICL_BIT BIT(1) #define RERUN_AICL_BIT BIT(0) +#ifdef OPLUS_FEATURE_CHG_BASIC +#define RESTART_AICL_BIT BIT(1) +#endif #define MISC_SMB_EN_CMD_REG (MISC_BASE + 0x48) #define SMB_EN_OVERRIDE_VALUE_BIT BIT(4) diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index 45394b845245..5b61d182953e 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -82,7 +82,12 @@ obj-$(CONFIG_REGULATOR_QCOM_RPM) += qcom_rpm-regulator.o obj-$(CONFIG_REGULATOR_QCOM_RPMH) += qcom-rpmh-regulator.o obj-$(CONFIG_REGULATOR_QCOM_SMD_RPM) += qcom_smd-regulator.o obj-$(CONFIG_REGULATOR_RPM_SMD) += rpm-smd-regulator.o +#use variable concatination for logical and BRAND_SHOW_FLAG=oneplus CONFIG_ARCH_LITO=y +ifeq ($(BRAND_SHOW_FLAG)$(CONFIG_ARCH_LITO), oneplusy) +obj-$(CONFIG_REGULATOR_PM8008) += qcom_pm8008-regulator-nord.o +else obj-$(CONFIG_REGULATOR_PM8008) += qcom_pm8008-regulator.o +endif obj-$(CONFIG_REGULATOR_QCOM_SPMI) += qcom_spmi-regulator.o obj-$(CONFIG_REGULATOR_QPNP_LABIBB) += qpnp-labibb-regulator.o obj-$(CONFIG_REGULATOR_QPNP_LCDB) += qpnp-lcdb-regulator.o diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 7632edbe0a20..db28c8299400 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -5328,6 +5328,16 @@ void regulator_debug_print_enabled(void) } EXPORT_SYMBOL(regulator_debug_print_enabled); +#ifdef OPLUS_FEATURE_POWERINFO_RPMH +void oplus_show_regulator_list(void) +{ + pr_info("oplus_show_regulator_list:Enabled regulators\n"); + class_for_each_device(®ulator_class, NULL, NULL, + _regulator_debug_print_enabled); +} +EXPORT_SYMBOL(oplus_show_regulator_list); +#endif + static int __init regulator_init(void) { int ret; @@ -5458,4 +5468,5 @@ static int __init regulator_init_complete(void) return 0; } + late_initcall_sync(regulator_init_complete); diff --git a/drivers/regulator/qcom_pm8008-regulator-nord.c b/drivers/regulator/qcom_pm8008-regulator-nord.c new file mode 100644 index 000000000000..61c67004397f --- /dev/null +++ b/drivers/regulator/qcom_pm8008-regulator-nord.c @@ -0,0 +1,1061 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright (c) 2019-2021, The Linux Foundation. All rights reserved. */ + +#define pr_fmt(fmt) "PM8008: %s: " fmt, __func__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define pm8008_err(reg, message, ...) \ + pr_err("%s: " message, (reg)->rdesc.name, ##__VA_ARGS__) +#define pm8008_debug(reg, message, ...) \ + pr_debug("%s: " message, (reg)->rdesc.name, ##__VA_ARGS__) + +#define STARTUP_DELAY_USEC 20 +#define VSET_STEP_SIZE_MV 1 +#define VSET_STEP_MV 8 +#define VSET_STEP_UV (VSET_STEP_MV * 1000) + +#define MISC_BASE 0x900 + +#define MISC_CHIP_ENABLE_REG (MISC_BASE + 0x50) +#define CHIP_ENABLE_BIT BIT(0) + +#define MISC_SHUTDOWN_CTRL_REG (MISC_BASE + 0x59) +#define IGNORE_LDO_OCP_SHUTDOWN BIT(3) + +#define LDO_ENABLE_REG(base) (base + 0x46) +#define ENABLE_BIT BIT(7) + +#define LDO_STATUS1_REG(base) (base + 0x08) +#define VREG_OCP_BIT BIT(5) +#define VREG_READY_BIT BIT(7) +#define MODE_STATE_MASK GENMASK(1, 0) +#define MODE_STATE_NPM 3 +#define MODE_STATE_LPM 2 +#define MODE_STATE_BYPASS 0 + +#define LDO_VSET_LB_REG(base) (base + 0x40) + +#define LDO_MODE_CTL1_REG(base) (base + 0x45) +#define MODE_PRIMARY_MASK GENMASK(2, 0) +#define LDO_MODE_NPM 7 +#define LDO_MODE_LPM 4 +#define FORCED_BYPASS 2 + +#define LDO_OCP_CTL1_REG(base) (base + 0x88) +#define VREG_OCP_STATUS_CLR BIT(1) +#define LDO_OCP_BROADCAST_EN_BIT BIT(2) + +#define LDO_STEPPER_CTL_REG(base) (base + 0x3b) +#define STEP_RATE_MASK GENMASK(1, 0) +/* Step rate in uV/us */ +#define PM8010_STEP_RATE 4800 + +#define LDO_PD_CTL_REG(base) (base + 0xA0) +#define STRONG_PD_EN_BIT BIT(7) + +#define MAX_REG_NAME 20 +#define PM8008_MAX_LDO 7 + +enum pmic_subtype { + PM8008_SUBTYPE, + PM8010_SUBTYPE, +}; + +struct pm8008_chip { + struct device *dev; + struct regmap *regmap; + struct regulator_dev *rdev; + struct regulator_desc rdesc; + int ocp_irq; +}; + +struct reg_init_data { + u8 offset; + u8 data; +}; + +struct regulator_data { + char *name; + char *supply_name; + int min_uv; + int max_uv; + int hpm_min_load_ua; + int min_dropout_uv; + const struct reg_init_data *reg_init; + unsigned int reg_init_size; +}; + +struct pm8008_regulator { + struct device *dev; + struct regmap *regmap; + struct regulator_desc rdesc; + struct regulator_dev *rdev; + struct regulator *parent_supply; + struct regulator *en_supply; + struct device_node *of_node; + struct notifier_block nb; + u16 base; + int hpm_min_load_ua; + int min_dropout_uv; + int step_rate; + bool enable_ocp_broadcast; + enum pmic_subtype pmic_subtype; +}; + +static const struct regulator_data pm8008_reg_data[PM8008_MAX_LDO] = { + /* name parent min_uv max_uv hpm_load headroom_uv */ + {"l1", "vdd_l1_l2", 528000, 1504000, 30000, 225000}, + {"l2", "vdd_l1_l2", 528000, 1504000, 30000, 225000}, + {"l3", "vdd_l3_l4", 1504000, 3400000, 10000, 200000}, + {"l4", "vdd_l3_l4", 1504000, 3400000, 10000, 200000}, + {"l5", "vdd_l5", 1504000, 3400000, 10000, 300000}, + {"l6", "vdd_l6", 1504000, 3400000, 10000, 300000}, + {"l7", "vdd_l7", 1504000, 3400000, 10000, 300000}, +}; + +static const struct reg_init_data pm8010_p300_reg_init_data[] = { + {0x55, 0x8A}, + {0x77, 0x03}, +}; + +static const struct reg_init_data pm8010_p600_reg_init_data[] = { + {0x76, 0x07}, + {0x77, 0x03}, +}; + +/* + * PM8010 LDOs 3, 4, and 6 can physically output a minimum of 1808 mV. However, + * 1504 mV is specified here to match PM8008 and to avoid the parent supply of + * these regulators being stuck at an unnecessarily high voltage as a result of + * the framework maintaining a minimum vote of 1808 mV + headroom at all times + * (even when the LDOs are OFF). This would waste power. The LDO hardware + * automatically rounds up programmed voltages to supported set points. + */ +static const struct regulator_data pm8010_reg_data[PM8008_MAX_LDO] = { + /* name parent min_uv max_uv hpm_load headroom_uv */ + {"l1", "vdd_l1_l2", 528000, 1544000, 30000, 100000}, + {"l2", "vdd_l1_l2", 528000, 1544000, 30000, 100000}, + {"l3", "vdd_l3_l4", 1504000, 3312000, 10000, 300000, + pm8010_p300_reg_init_data, ARRAY_SIZE(pm8010_p300_reg_init_data)}, + {"l4", "vdd_l3_l4", 1504000, 3312000, 10000, 300000, + pm8010_p300_reg_init_data, ARRAY_SIZE(pm8010_p300_reg_init_data)}, + {"l5", "vdd_l5", 1504000, 3544000, 10000, 300000, + pm8010_p600_reg_init_data, ARRAY_SIZE(pm8010_p600_reg_init_data)}, + {"l6", "vdd_l6", 1504000, 3312000, 10000, 300000, + pm8010_p300_reg_init_data, ARRAY_SIZE(pm8010_p300_reg_init_data)}, + {"l7", "vdd_l7", 1504000, 3544000, 10000, 300000, + pm8010_p600_reg_init_data, ARRAY_SIZE(pm8010_p600_reg_init_data)}, +}; + +/* common functions */ +static int pm8008_read(struct regmap *regmap, u16 reg, u8 *val, int count) +{ + int rc; + + rc = regmap_bulk_read(regmap, reg, val, count); + if (rc < 0) + pr_err("failed to read 0x%04x\n", reg); + + return rc; +} + +static int pm8008_write(struct regmap *regmap, u16 reg, const u8 *val, + int count) +{ + int rc; + + pr_debug("Writing 0x%02x to 0x%04x\n", val, reg); + rc = regmap_bulk_write(regmap, reg, val, count); + if (rc < 0) + pr_err("failed to write 0x%04x\n", reg); + + return rc; +} + +static int pm8008_masked_write(struct regmap *regmap, u16 reg, u8 mask, + u8 val) +{ + int rc; + + pr_debug("Writing 0x%02x to 0x%04x with mask 0x%02x\n", val, reg, mask); + rc = regmap_update_bits(regmap, reg, mask, val); + if (rc < 0) + pr_err("failed to write 0x%02x to 0x%04x with mask 0x%02x\n", + val, reg, mask); + + return rc; +} + +/* PM8008 LDO Regulator callbacks */ +static int pm8008_regulator_get_voltage(struct regulator_dev *rdev) +{ + struct pm8008_regulator *pm8008_reg = rdev_get_drvdata(rdev); + u8 vset_raw[2]; + int rc; + + rc = pm8008_read(pm8008_reg->regmap, + LDO_VSET_LB_REG(pm8008_reg->base), + vset_raw, 2); + if (rc < 0) { + pm8008_err(pm8008_reg, + "failed to read regulator voltage rc=%d\n", rc); + return rc; + } + + pm8008_debug(pm8008_reg, "VSET read [%x][%x]\n", + vset_raw[1], vset_raw[0]); + return (vset_raw[1] << 8 | vset_raw[0]) * 1000; +} + +static int pm8008_regulator_is_enabled(struct regulator_dev *rdev) +{ + struct pm8008_regulator *pm8008_reg = rdev_get_drvdata(rdev); + int rc; + u8 reg; + + rc = pm8008_read(pm8008_reg->regmap, + LDO_ENABLE_REG(pm8008_reg->base), ®, 1); + if (rc < 0) { + pm8008_err(pm8008_reg, "failed to read enable reg rc=%d\n", rc); + return rc; + } + + return !!(reg & ENABLE_BIT); +} + +static int pm8008_regulator_enable(struct regulator_dev *rdev) +{ + struct pm8008_regulator *pm8008_reg = rdev_get_drvdata(rdev); + int rc, rc2, current_uv, delay_us, delay_ms, retry_count = 10; + u8 reg; + + current_uv = pm8008_regulator_get_voltage(rdev); + if (current_uv < 0) { + pm8008_err(pm8008_reg, "failed to get current voltage rc=%d\n", + current_uv); + return current_uv; + } + + rc = regulator_enable(pm8008_reg->en_supply); + if (rc < 0) { + pm8008_err(pm8008_reg, + "failed to enable en_supply rc=%d\n", rc); + return rc; + } + + if (pm8008_reg->parent_supply) { + rc = regulator_set_voltage(pm8008_reg->parent_supply, + current_uv + pm8008_reg->min_dropout_uv, + INT_MAX); + if (rc < 0) { + pm8008_err(pm8008_reg, "failed to request parent supply voltage rc=%d\n", + rc); + goto remove_en; + } + + rc = regulator_enable(pm8008_reg->parent_supply); + if (rc < 0) { + pm8008_err(pm8008_reg, + "failed to enable parent rc=%d\n", rc); + regulator_set_voltage(pm8008_reg->parent_supply, 0, + INT_MAX); + goto remove_en; + } + } + + rc = pm8008_masked_write(pm8008_reg->regmap, + LDO_ENABLE_REG(pm8008_reg->base), + ENABLE_BIT, ENABLE_BIT); + if (rc < 0) { + pm8008_err(pm8008_reg, + "failed to enable regulator rc=%d\n", rc); + goto remove_vote; + } + + /* + * Wait for the VREG_READY status bit to be set using a timeout delay + * calculated from the current commanded voltage. + */ + delay_us = STARTUP_DELAY_USEC + + DIV_ROUND_UP(current_uv, pm8008_reg->step_rate); + delay_ms = DIV_ROUND_UP(delay_us, 1000); + + /* Retry 10 times for VREG_READY before bailing out */ + while (retry_count--) { + if (delay_ms > 20) + msleep(delay_ms); + else + usleep_range(delay_us, delay_us + 100); + + rc = pm8008_read(pm8008_reg->regmap, + LDO_STATUS1_REG(pm8008_reg->base), ®, 1); + if (rc < 0) { + pm8008_err(pm8008_reg, + "failed to read regulator status rc=%d\n", rc); + goto disable_ldo; + } + if (reg & VREG_READY_BIT) { + pm8008_debug(pm8008_reg, "regulator enabled\n"); + return 0; + } + } + + pm8008_err(pm8008_reg, "failed to enable regulator, VREG_READY not set\n"); + rc = -ETIME; + +disable_ldo: + pm8008_masked_write(pm8008_reg->regmap, + LDO_ENABLE_REG(pm8008_reg->base), ENABLE_BIT, 0); + +remove_vote: + if (pm8008_reg->parent_supply) { + rc2 = regulator_disable(pm8008_reg->parent_supply); + if (rc2 < 0) + pm8008_err(pm8008_reg, "failed to disable parent supply rc=%d\n", + rc2); + rc2 = regulator_set_voltage(pm8008_reg->parent_supply, 0, + INT_MAX); + if (rc2 < 0) + pm8008_err(pm8008_reg, "failed to remove voltage vote for parent supply rc=%d\n", + rc2); + } + +remove_en: + rc2 = regulator_disable(pm8008_reg->en_supply); + if (rc2 < 0) + pm8008_err(pm8008_reg, "failed to disable en_supply rc=%d\n", + rc2); + + return rc; +} + +static int pm8008_regulator_disable(struct regulator_dev *rdev) +{ + struct pm8008_regulator *pm8008_reg = rdev_get_drvdata(rdev); + int rc; + + rc = pm8008_masked_write(pm8008_reg->regmap, + LDO_ENABLE_REG(pm8008_reg->base), + ENABLE_BIT, 0); + if (rc < 0) { + pm8008_err(pm8008_reg, + "failed to disable regulator rc=%d\n", rc); + return rc; + } + + /* remove voltage vote from parent regulator */ + if (pm8008_reg->parent_supply) { + rc = regulator_disable(pm8008_reg->parent_supply); + if (rc < 0) { + pm8008_err(pm8008_reg, "failed to disable parent rc=%d\n", + rc); + return rc; + } + rc = regulator_set_voltage(pm8008_reg->parent_supply, + 0, INT_MAX); + if (rc < 0) { + pm8008_err(pm8008_reg, "failed to remove parent voltage rc=%d\n", + rc); + return rc; + } + } + + /* remove vote from chip enable regulator */ + rc = regulator_disable(pm8008_reg->en_supply); + if (rc < 0) { + pm8008_err(pm8008_reg, "failed to disable en_supply rc=%d\n", + rc); + return rc; + } + + pm8008_debug(pm8008_reg, "regulator disabled\n"); + return 0; +} + +static int pm8008_write_voltage(struct pm8008_regulator *pm8008_reg, int min_uv, + int max_uv) +{ + int rc = 0, mv; + u8 vset_raw[2]; + + mv = DIV_ROUND_UP(min_uv, 1000); + if (mv * 1000 > max_uv) { + pm8008_err(pm8008_reg, + "requested voltage above maximum limit\n"); + return -EINVAL; + } + + /* + * Each LSB of regulator is 1mV and the voltage setpoint + * should be multiple of 8mV(step). + */ + mv = DIV_ROUND_UP(DIV_ROUND_UP(mv, VSET_STEP_MV) * VSET_STEP_MV, + VSET_STEP_SIZE_MV); + + vset_raw[0] = mv & 0xff; + vset_raw[1] = (mv & 0xff00) >> 8; + rc = pm8008_write(pm8008_reg->regmap, LDO_VSET_LB_REG(pm8008_reg->base), + vset_raw, 2); + if (rc < 0) { + pm8008_err(pm8008_reg, "failed to write voltage rc=%d\n", rc); + return rc; + } + + pm8008_debug(pm8008_reg, "VSET=[%x][%x]\n", vset_raw[1], vset_raw[0]); + return 0; +} + +static int pm8008_regulator_set_voltage_time(struct regulator_dev *rdev, + int old_uV, int new_uv) +{ + struct pm8008_regulator *pm8008_reg = rdev_get_drvdata(rdev); + + return DIV_ROUND_UP(abs(new_uv - old_uV), pm8008_reg->step_rate); +} + +static int pm8008_regulator_set_voltage(struct regulator_dev *rdev, + int min_uv, int max_uv, unsigned int *selector) +{ + struct pm8008_regulator *pm8008_reg = rdev_get_drvdata(rdev); + int rc = 0, current_uv = 0, rounded_uv = 0, enabled = 0; + + if (pm8008_reg->parent_supply) { + enabled = pm8008_regulator_is_enabled(rdev); + if (enabled < 0) { + return enabled; + } else if (enabled) { + current_uv = pm8008_regulator_get_voltage(rdev); + if (current_uv < 0) + return current_uv; + rounded_uv = roundup(min_uv, VSET_STEP_UV); + } + } + + /* + * Set the parent_supply voltage before changing the LDO voltage when + * the LDO voltage is being increased. + */ + if (pm8008_reg->parent_supply && enabled && rounded_uv >= current_uv) { + /* Request parent voltage with headroom */ + rc = regulator_set_voltage(pm8008_reg->parent_supply, + rounded_uv + pm8008_reg->min_dropout_uv, + INT_MAX); + if (rc < 0) { + pm8008_err(pm8008_reg, "failed to request parent supply voltage rc=%d\n", + rc); + return rc; + } + } + + rc = pm8008_write_voltage(pm8008_reg, min_uv, max_uv); + if (rc < 0) + return rc; + + /* + * Set the parent_supply voltage after changing the LDO voltage when + * the LDO voltage is being reduced. + */ + if (pm8008_reg->parent_supply && enabled && rounded_uv < current_uv) { + /* + * Ensure sufficient time for the LDO voltage to slew down + * before reducing the parent supply voltage. The regulator + * framework will add the same delay after this function returns + * in all cases (i.e. enabled/disabled and increasing/decreasing + * voltage). + */ + udelay(pm8008_regulator_set_voltage_time(rdev, rounded_uv, + current_uv)); + + /* Request parent voltage with headroom */ + rc = regulator_set_voltage(pm8008_reg->parent_supply, + rounded_uv + pm8008_reg->min_dropout_uv, + INT_MAX); + if (rc < 0) { + pm8008_err(pm8008_reg, "failed to request parent supply voltage rc=%d\n", + rc); + return rc; + } + } + + pm8008_debug(pm8008_reg, "voltage set to %d\n", min_uv); + return rc; +} + +static int pm8008_regulator_set_mode(struct regulator_dev *rdev, + unsigned int mode) +{ + struct pm8008_regulator *pm8008_reg = rdev_get_drvdata(rdev); + int rc; + u8 val = LDO_MODE_LPM; + + if (mode == REGULATOR_MODE_NORMAL) + val = LDO_MODE_NPM; + else if (mode == REGULATOR_MODE_IDLE) + val = LDO_MODE_LPM; + + rc = pm8008_masked_write(pm8008_reg->regmap, + LDO_MODE_CTL1_REG(pm8008_reg->base), + MODE_PRIMARY_MASK, val); + if (!rc) + pm8008_debug(pm8008_reg, "mode set to %d\n", val); + + return rc; +} + +static unsigned int pm8008_regulator_get_mode(struct regulator_dev *rdev) +{ + struct pm8008_regulator *pm8008_reg = rdev_get_drvdata(rdev); + int rc; + u8 reg; + + rc = pm8008_read(pm8008_reg->regmap, + LDO_STATUS1_REG(pm8008_reg->base), ®, 1); + if (rc < 0) { + pm8008_err(pm8008_reg, "failed to get mode rc=%d\n", rc); + return rc; + } + + return ((reg & MODE_STATE_MASK) == MODE_STATE_NPM) + ? REGULATOR_MODE_NORMAL : REGULATOR_MODE_IDLE; +} + +static int pm8008_regulator_set_load(struct regulator_dev *rdev, int load_uA) +{ + struct pm8008_regulator *pm8008_reg = rdev_get_drvdata(rdev); + int mode; + + if (load_uA >= pm8008_reg->hpm_min_load_ua) + mode = REGULATOR_MODE_NORMAL; + else + mode = REGULATOR_MODE_IDLE; + + return pm8008_regulator_set_mode(rdev, mode); +} + +static struct regulator_ops pm8008_regulator_ops = { + .enable = pm8008_regulator_enable, + .disable = pm8008_regulator_disable, + .is_enabled = pm8008_regulator_is_enabled, + .set_voltage = pm8008_regulator_set_voltage, + .get_voltage = pm8008_regulator_get_voltage, + .set_mode = pm8008_regulator_set_mode, + .get_mode = pm8008_regulator_get_mode, + .set_load = pm8008_regulator_set_load, + .set_voltage_time = pm8008_regulator_set_voltage_time, +}; + +static int pm8008_ldo_cb(struct notifier_block *nb, ulong event, void *data) +{ + struct pm8008_regulator *pm8008_reg = container_of(nb, + struct pm8008_regulator, nb); + u8 val; + int rc; + + if (event != REGULATOR_EVENT_OVER_CURRENT) + return NOTIFY_OK; + + rc = pm8008_read(pm8008_reg->regmap, + LDO_STATUS1_REG(pm8008_reg->base), &val, 1); + if (rc < 0) { + pm8008_err(pm8008_reg, + "failed to read regulator status rc=%d\n", rc); + goto error; + } + + if (!(val & VREG_OCP_BIT)) + return NOTIFY_OK; + + pr_err("OCP triggered on %s\n", pm8008_reg->rdesc.name); + /* + * Toggle the OCP_STATUS_CLR bit to re-arm the OCP status for + * the next OCP event + */ + rc = pm8008_masked_write(pm8008_reg->regmap, + LDO_OCP_CTL1_REG(pm8008_reg->base), + VREG_OCP_STATUS_CLR, VREG_OCP_STATUS_CLR); + if (rc < 0) { + pm8008_err(pm8008_reg, "failed to write OCP_STATUS_CLR rc=%d\n", + rc); + goto error; + } + + rc = pm8008_masked_write(pm8008_reg->regmap, + LDO_OCP_CTL1_REG(pm8008_reg->base), + VREG_OCP_STATUS_CLR, 0); + if (rc < 0) { + pm8008_err(pm8008_reg, "failed to write OCP_STATUS_CLR rc=%d\n", + rc); + goto error; + } + + /* Notify the consumers about the OCP event */ + mutex_lock(&pm8008_reg->rdev->mutex); + regulator_notifier_call_chain(pm8008_reg->rdev, + REGULATOR_EVENT_OVER_CURRENT, NULL); + mutex_unlock(&pm8008_reg->rdev->mutex); + +error: + return NOTIFY_OK; +} + +static int pm8008_regulator_register_init(struct pm8008_regulator *pm8008_reg, + const struct regulator_data *reg_data) +{ + int i, rc; + + if (!reg_data->reg_init) + return 0; + + for (i = 0; i < reg_data->reg_init_size; i++) { + rc = pm8008_write(pm8008_reg->regmap, + pm8008_reg->base + reg_data->reg_init[i].offset, + ®_data->reg_init[i].data, 1); + if (rc < 0) + return rc; + } + + return 0; +} + +static int pm8008_register_ldo(struct pm8008_regulator *pm8008_reg, + const char *name) +{ + struct regulator_config reg_config = {}; + struct regulator_init_data *init_data; + struct device *dev = pm8008_reg->dev; + struct device_node *reg_node = pm8008_reg->of_node; + char buff[MAX_REG_NAME]; + const struct regulator_data *reg_data; + int rc, i, init_voltage; + u32 base = 0; + u8 reg; + + reg_data = pm8008_reg->pmic_subtype == PM8008_SUBTYPE ? pm8008_reg_data + : pm8010_reg_data; + + /* get regulator data */ + for (i = 0; i < PM8008_MAX_LDO; i++) + if (strstr(name, reg_data[i].name)) + break; + + if (i == PM8008_MAX_LDO) { + pr_err("Invalid regulator name %s\n", name); + return -EINVAL; + } + + rc = of_property_read_u32(reg_node, "reg", &base); + if (rc < 0) { + pr_err("%s: failed to get regulator base rc=%d\n", name, rc); + return rc; + } + pm8008_reg->base = base; + + rc = pm8008_regulator_register_init(pm8008_reg, ®_data[i]); + if (rc) + return rc; + + pm8008_reg->min_dropout_uv = reg_data[i].min_dropout_uv; + of_property_read_u32(reg_node, "qcom,min-dropout-voltage", + &pm8008_reg->min_dropout_uv); + + pm8008_reg->hpm_min_load_ua = reg_data[i].hpm_min_load_ua; + of_property_read_u32(reg_node, "qcom,hpm-min-load", + &pm8008_reg->hpm_min_load_ua); + init_voltage = -EINVAL; + of_property_read_u32(reg_node, "qcom,init-voltage", &init_voltage); + + if (of_property_read_bool(reg_node, "qcom,strong-pd")) { + rc = pm8008_masked_write(pm8008_reg->regmap, + LDO_PD_CTL_REG(pm8008_reg->base), + STRONG_PD_EN_BIT, STRONG_PD_EN_BIT); + if (rc < 0) { + pr_err("%s: failed to configure pull down rc=%d\n", + name, rc); + return rc; + } + } + + if (pm8008_reg->enable_ocp_broadcast) { + rc = pm8008_masked_write(pm8008_reg->regmap, + LDO_OCP_CTL1_REG(pm8008_reg->base), + LDO_OCP_BROADCAST_EN_BIT, + LDO_OCP_BROADCAST_EN_BIT); + if (rc < 0) { + pr_err("%s: failed to configure ocp broadcast rc=%d\n", + name, rc); + return rc; + } + } + + /* get slew rate */ + if (pm8008_reg->pmic_subtype == PM8008_SUBTYPE) { + rc = pm8008_read(pm8008_reg->regmap, + LDO_STEPPER_CTL_REG(pm8008_reg->base), ®, 1); + if (rc < 0) { + pr_err("%s: failed to read step rate configuration rc=%d\n", + name, rc); + return rc; + } + pm8008_reg->step_rate = 38400 >> (reg & STEP_RATE_MASK); + } else { + pm8008_reg->step_rate = PM8010_STEP_RATE; + } + + scnprintf(buff, MAX_REG_NAME, "%s-supply", reg_data[i].supply_name); + if (of_find_property(dev->of_node, buff, NULL)) { + pm8008_reg->parent_supply = devm_regulator_get(dev, + reg_data[i].supply_name); + if (IS_ERR(pm8008_reg->parent_supply)) { + rc = PTR_ERR(pm8008_reg->parent_supply); + if (rc != -EPROBE_DEFER) + pr_err("%s: failed to get parent regulator rc=%d\n", + name, rc); + return rc; + } + } + + /* pm8008_en should be present otherwise fail the regulator probe */ + pm8008_reg->en_supply = devm_regulator_get(dev, "pm8008_en"); + if (IS_ERR(pm8008_reg->en_supply)) { + rc = PTR_ERR(pm8008_reg->en_supply); + pr_err("%s: failed to get chip_en supply\n", name); + return rc; + } + + init_data = of_get_regulator_init_data(dev, reg_node, + &pm8008_reg->rdesc); + if (init_data == NULL) { + pr_err("%s: failed to get regulator data\n", name); + return -ENODATA; + } + if (!init_data->constraints.name) { + pr_err("%s: regulator name missing\n", name); + return -EINVAL; + } + + /* configure the initial voltage for the regulator */ + if (init_voltage > 0) { + rc = pm8008_write_voltage(pm8008_reg, init_voltage, + init_data->constraints.max_uV); + if (rc < 0) + pr_err("%s: failed to set initial voltage rc=%d\n", + name, rc); + } + + init_data->constraints.input_uV = init_data->constraints.max_uV; + init_data->constraints.valid_ops_mask |= REGULATOR_CHANGE_STATUS + | REGULATOR_CHANGE_VOLTAGE + | REGULATOR_CHANGE_MODE + | REGULATOR_CHANGE_DRMS; + reg_config.dev = dev; + reg_config.init_data = init_data; + reg_config.driver_data = pm8008_reg; + reg_config.of_node = reg_node; + + pm8008_reg->rdesc.owner = THIS_MODULE; + pm8008_reg->rdesc.type = REGULATOR_VOLTAGE; + pm8008_reg->rdesc.ops = &pm8008_regulator_ops; + pm8008_reg->rdesc.name = init_data->constraints.name; + pm8008_reg->rdesc.n_voltages = 1; + + pm8008_reg->rdev = devm_regulator_register(dev, &pm8008_reg->rdesc, + ®_config); + if (IS_ERR(pm8008_reg->rdev)) { + rc = PTR_ERR(pm8008_reg->rdev); + pr_err("%s: failed to register regulator rc=%d\n", + pm8008_reg->rdesc.name, rc); + return rc; + } + + if (pm8008_reg->enable_ocp_broadcast) { + pm8008_reg->nb.notifier_call = pm8008_ldo_cb; + rc = devm_regulator_register_notifier(pm8008_reg->en_supply, + &pm8008_reg->nb); + if (rc < 0) { + pr_err("Failed to register a regulator notifier rc=%d\n", + rc); + return rc; + } + } + + pr_debug("%s regulator registered\n", name); + + return 0; +} + +static const struct of_device_id pm8008_regulator_match_table[] = { + { + .compatible = "qcom,pm8008-regulator", + .data = (void *)(uintptr_t)PM8008_SUBTYPE, + }, + { + .compatible = "qcom,pm8010-regulator", + .data = (void *)(uintptr_t)PM8010_SUBTYPE, + }, + { }, +}; + +/* PMIC probe and helper function */ +static int pm8008_parse_regulator(struct regmap *regmap, struct device *dev) +{ + int rc = 0; + const char *name; + struct device_node *child; + struct pm8008_regulator *pm8008_reg; + const struct of_device_id *match; + enum pmic_subtype pmic_subtype; + bool ocp; + + match = of_match_node(pm8008_regulator_match_table, dev->of_node); + if (match) { + pmic_subtype = (uintptr_t)match->data; + } else { + dev_err(dev, "could not find compatible string match\n"); + return -ENODEV; + } + + ocp = of_property_read_bool(dev->of_node, "qcom,enable-ocp-broadcast"); + + /* parse each subnode and register regulator for regulator child */ + for_each_available_child_of_node(dev->of_node, child) { + pm8008_reg = devm_kzalloc(dev, sizeof(*pm8008_reg), GFP_KERNEL); + if (!pm8008_reg) + return -ENOMEM; + + pm8008_reg->regmap = regmap; + pm8008_reg->of_node = child; + pm8008_reg->dev = dev; + pm8008_reg->enable_ocp_broadcast = ocp; + pm8008_reg->pmic_subtype = pmic_subtype; + + rc = of_property_read_string(child, "regulator-name", &name); + if (rc) + continue; + + rc = pm8008_register_ldo(pm8008_reg, name); + if (rc < 0) { + pr_err("failed to register regulator %s rc=%d\n", + name, rc); + return rc; + } + } + + return 0; +} + +static int pm8008_regulator_probe(struct platform_device *pdev) +{ + int rc = 0; + struct regmap *regmap; + + regmap = dev_get_regmap(pdev->dev.parent, NULL); + if (!regmap) { + pr_err("parent regmap is missing\n"); + return -EINVAL; + } + + rc = pm8008_parse_regulator(regmap, &pdev->dev); + if (rc < 0) { + pr_err("failed to parse device tree rc=%d\n", rc); + return rc; + } + + return 0; +} + +/* PM8008 chip enable regulator callbacks */ +static int pm8008_enable_regulator_enable(struct regulator_dev *rdev) +{ + struct pm8008_chip *chip = rdev_get_drvdata(rdev); + int rc; + + rc = pm8008_masked_write(chip->regmap, MISC_CHIP_ENABLE_REG, + CHIP_ENABLE_BIT, CHIP_ENABLE_BIT); + if (rc < 0) { + pm8008_err(chip, "failed to enable chip rc=%d\n", rc); + return rc; + } + + pm8008_debug(chip, "regulator enabled\n"); + return 0; +} + +static int pm8008_enable_regulator_disable(struct regulator_dev *rdev) +{ + struct pm8008_chip *chip = rdev_get_drvdata(rdev); + int rc; + + rc = pm8008_masked_write(chip->regmap, MISC_CHIP_ENABLE_REG, + CHIP_ENABLE_BIT, 0); + if (rc < 0) { + pm8008_err(chip, "failed to disable chip rc=%d\n", rc); + return rc; + } + + pm8008_debug(chip, "regulator disabled\n"); + return 0; +} + +static int pm8008_enable_regulator_is_enabled(struct regulator_dev *rdev) +{ + struct pm8008_chip *chip = rdev_get_drvdata(rdev); + int rc; + u8 reg; + + rc = pm8008_read(chip->regmap, MISC_CHIP_ENABLE_REG, ®, 1); + if (rc < 0) { + pm8008_err(chip, "failed to get chip state rc=%d\n", rc); + return rc; + } + + return !!(reg & CHIP_ENABLE_BIT); +} + +static struct regulator_ops pm8008_enable_reg_ops = { + .enable = pm8008_enable_regulator_enable, + .disable = pm8008_enable_regulator_disable, + .is_enabled = pm8008_enable_regulator_is_enabled, +}; + +static int pm8008_init_enable_regulator(struct pm8008_chip *chip) +{ + struct regulator_config cfg = {}; + int rc = 0; + + cfg.dev = chip->dev; + cfg.driver_data = chip; + + chip->rdesc.owner = THIS_MODULE; + chip->rdesc.type = REGULATOR_VOLTAGE; + chip->rdesc.ops = &pm8008_enable_reg_ops; + chip->rdesc.of_match = "qcom,pm8008-chip-en"; + chip->rdesc.name = "qcom,pm8008-chip-en"; + + chip->rdev = devm_regulator_register(chip->dev, &chip->rdesc, &cfg); + if (IS_ERR(chip->rdev)) { + rc = PTR_ERR(chip->rdev); + chip->rdev = NULL; + return rc; + } + + return 0; +} + +static irqreturn_t pm8008_ocp_irq(int irq, void *_chip) +{ + struct pm8008_chip *chip = _chip; + + mutex_lock(&chip->rdev->mutex); + regulator_notifier_call_chain(chip->rdev, REGULATOR_EVENT_OVER_CURRENT, + NULL); + mutex_unlock(&chip->rdev->mutex); + + return IRQ_HANDLED; +} + +static int pm8008_chip_probe(struct platform_device *pdev) +{ + int rc = 0; + struct pm8008_chip *chip; + + chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL); + if (!chip) + return -ENOMEM; + + chip->regmap = dev_get_regmap(pdev->dev.parent, NULL); + if (!chip->regmap) { + pr_err("parent regmap is missing\n"); + return -EINVAL; + } + chip->dev = &pdev->dev; + + /* Register chip enable regulator */ + rc = pm8008_init_enable_regulator(chip); + if (rc < 0) { + pr_err("Failed to register chip enable regulator rc=%d\n", rc); + return rc; + } + + chip->ocp_irq = of_irq_get_byname(chip->dev->of_node, "ocp"); + if (chip->ocp_irq < 0) { + pr_debug("Failed to get pm8008-ocp-irq\n"); + } else { + rc = devm_request_threaded_irq(chip->dev, chip->ocp_irq, NULL, + pm8008_ocp_irq, IRQF_ONESHOT, + "ocp", chip); + if (rc < 0) { + pr_err("Failed to request 'pm8008-ocp-irq' rc=%d\n", + rc); + return rc; + } + + /* Ignore PMIC shutdown for LDO OCP event */ + rc = pm8008_masked_write(chip->regmap, MISC_SHUTDOWN_CTRL_REG, + IGNORE_LDO_OCP_SHUTDOWN, IGNORE_LDO_OCP_SHUTDOWN); + if (rc < 0) { + pr_err("Failed to write MISC_SHUTDOWN register rc=%d\n", + rc); + return rc; + } + } + + pr_debug("PM8008 chip registered\n"); + return 0; +} + +static int pm8008_chip_remove(struct platform_device *pdev) +{ + struct pm8008_chip *chip = platform_get_drvdata(pdev); + int rc; + + rc = pm8008_masked_write(chip->regmap, MISC_CHIP_ENABLE_REG, + CHIP_ENABLE_BIT, 0); + if (rc < 0) + pr_err("failed to disable chip rc=%d\n", rc); + + return 0; +} + +static struct platform_driver pm8008_regulator_driver = { + .driver = { + .name = "qcom,pm8008-regulator", + .owner = THIS_MODULE, + .of_match_table = pm8008_regulator_match_table, + }, + .probe = pm8008_regulator_probe, +}; +module_platform_driver(pm8008_regulator_driver); + +static const struct of_device_id pm8008_chip_match_table[] = { + { + .compatible = "qcom,pm8008-chip", + }, + { }, +}; + +static struct platform_driver pm8008_chip_driver = { + .driver = { + .name = "qcom,pm8008-chip", + .owner = THIS_MODULE, + .of_match_table = pm8008_chip_match_table, + }, + .probe = pm8008_chip_probe, + .remove = pm8008_chip_remove, +}; +module_platform_driver(pm8008_chip_driver); + +MODULE_DESCRIPTION("QPNP PM8008 PMIC Regulator Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/regulator/qcom_pm8008-regulator.c b/drivers/regulator/qcom_pm8008-regulator.c index 1fa15a9aacf1..cd6b7b3e78ac 100644 --- a/drivers/regulator/qcom_pm8008-regulator.c +++ b/drivers/regulator/qcom_pm8008-regulator.c @@ -4,7 +4,6 @@ #define pr_fmt(fmt) "PM8008: %s: " fmt, __func__ -#include #include #include #include @@ -26,7 +25,6 @@ #define STARTUP_DELAY_USEC 20 #define VSET_STEP_SIZE_MV 1 #define VSET_STEP_MV 8 -#define VSET_STEP_UV (VSET_STEP_MV * 1000) #define MISC_BASE 0x900 @@ -241,16 +239,9 @@ static int pm8008_regulator_is_enabled(struct regulator_dev *rdev) static int pm8008_regulator_enable(struct regulator_dev *rdev) { struct pm8008_regulator *pm8008_reg = rdev_get_drvdata(rdev); - int rc, rc2, current_uv, delay_us, delay_ms, retry_count = 10; + int rc, init_mv, delay_us, delay_ms, retry_count = 10; u8 reg; - current_uv = pm8008_regulator_get_voltage(rdev); - if (current_uv < 0) { - pm8008_err(pm8008_reg, "failed to get current voltage rc=%d\n", - current_uv); - return current_uv; - } - rc = regulator_enable(pm8008_reg->en_supply); if (rc < 0) { pm8008_err(pm8008_reg, @@ -259,22 +250,12 @@ static int pm8008_regulator_enable(struct regulator_dev *rdev) } if (pm8008_reg->parent_supply) { - rc = regulator_set_voltage(pm8008_reg->parent_supply, - current_uv + pm8008_reg->min_dropout_uv, - INT_MAX); - if (rc < 0) { - pm8008_err(pm8008_reg, "failed to request parent supply voltage rc=%d\n", - rc); - goto remove_en; - } - rc = regulator_enable(pm8008_reg->parent_supply); if (rc < 0) { pm8008_err(pm8008_reg, "failed to enable parent rc=%d\n", rc); - regulator_set_voltage(pm8008_reg->parent_supply, 0, - INT_MAX); - goto remove_en; + regulator_disable(pm8008_reg->en_supply); + return rc; } } @@ -288,14 +269,20 @@ static int pm8008_regulator_enable(struct regulator_dev *rdev) } /* - * Wait for the VREG_READY status bit to be set using a timeout delay - * calculated from the current commanded voltage. + * wait for VREG_OK + * Read voltage and calculate the delay. */ + init_mv = pm8008_regulator_get_voltage(rdev) / 1000; + if (init_mv < 0) { + pm8008_err(pm8008_reg, + "failed to get regulator voltage rc=%d\n", rc); + goto out; + } delay_us = STARTUP_DELAY_USEC - + DIV_ROUND_UP(current_uv, pm8008_reg->step_rate); + + DIV_ROUND_UP(init_mv * 1000, pm8008_reg->step_rate); delay_ms = DIV_ROUND_UP(delay_us, 1000); - /* Retry 10 times for VREG_READY before bailing out */ + /* Retry 10 times for VREG_OK before bailing out */ while (retry_count--) { if (delay_ms > 20) msleep(delay_ms); @@ -307,7 +294,7 @@ static int pm8008_regulator_enable(struct regulator_dev *rdev) if (rc < 0) { pm8008_err(pm8008_reg, "failed to read regulator status rc=%d\n", rc); - goto disable_ldo; + goto out; } if (reg & VREG_READY_BIT) { pm8008_debug(pm8008_reg, "regulator enabled\n"); @@ -315,33 +302,20 @@ static int pm8008_regulator_enable(struct regulator_dev *rdev) } } - pm8008_err(pm8008_reg, "failed to enable regulator, VREG_READY not set\n"); - rc = -ETIME; - -disable_ldo: + pm8008_err(pm8008_reg, + "failed to enable regulator VREG_READY not set\n"); +out: pm8008_masked_write(pm8008_reg->regmap, LDO_ENABLE_REG(pm8008_reg->base), ENABLE_BIT, 0); - remove_vote: - if (pm8008_reg->parent_supply) { - rc2 = regulator_disable(pm8008_reg->parent_supply); - if (rc2 < 0) - pm8008_err(pm8008_reg, "failed to disable parent supply rc=%d\n", - rc2); - rc2 = regulator_set_voltage(pm8008_reg->parent_supply, 0, - INT_MAX); - if (rc2 < 0) - pm8008_err(pm8008_reg, "failed to remove voltage vote for parent supply rc=%d\n", - rc2); - } + rc = regulator_disable(pm8008_reg->en_supply); + if (pm8008_reg->parent_supply) + rc |= regulator_disable(pm8008_reg->parent_supply); + if (rc < 0) + pm8008_err(pm8008_reg, + "failed to disable parent regulator rc=%d\n", rc); -remove_en: - rc2 = regulator_disable(pm8008_reg->en_supply); - if (rc2 < 0) - pm8008_err(pm8008_reg, "failed to disable en_supply rc=%d\n", - rc2); - - return rc; + return -ETIME; } static int pm8008_regulator_disable(struct regulator_dev *rdev) @@ -358,29 +332,28 @@ static int pm8008_regulator_disable(struct regulator_dev *rdev) return rc; } - /* remove voltage vote from parent regulator */ - if (pm8008_reg->parent_supply) { - rc = regulator_disable(pm8008_reg->parent_supply); - if (rc < 0) { - pm8008_err(pm8008_reg, "failed to disable parent rc=%d\n", - rc); - return rc; - } - rc = regulator_set_voltage(pm8008_reg->parent_supply, - 0, INT_MAX); - if (rc < 0) { - pm8008_err(pm8008_reg, "failed to remove parent voltage rc=%d\n", - rc); - return rc; - } - } - /* remove vote from chip enable regulator */ rc = regulator_disable(pm8008_reg->en_supply); if (rc < 0) { - pm8008_err(pm8008_reg, "failed to disable en_supply rc=%d\n", - rc); - return rc; + pm8008_err(pm8008_reg, + "failed to disable en_supply rc=%d\n", rc); + } + + /* remove voltage vote from parent regulator */ + if (pm8008_reg->parent_supply) { + rc = regulator_set_voltage(pm8008_reg->parent_supply, + 0, INT_MAX); + if (rc < 0) { + pm8008_err(pm8008_reg, + "failed to remove parent voltage rc=%d\n", rc); + return rc; + } + rc = regulator_disable(pm8008_reg->parent_supply); + if (rc < 0) { + pm8008_err(pm8008_reg, + "failed to disable parent rc=%d\n", rc); + return rc; + } } pm8008_debug(pm8008_reg, "regulator disabled\n"); @@ -420,76 +393,31 @@ static int pm8008_write_voltage(struct pm8008_regulator *pm8008_reg, int min_uv, return 0; } -static int pm8008_regulator_set_voltage_time(struct regulator_dev *rdev, - int old_uV, int new_uv) -{ - struct pm8008_regulator *pm8008_reg = rdev_get_drvdata(rdev); - - return DIV_ROUND_UP(abs(new_uv - old_uV), pm8008_reg->step_rate); -} - static int pm8008_regulator_set_voltage(struct regulator_dev *rdev, int min_uv, int max_uv, unsigned int *selector) { struct pm8008_regulator *pm8008_reg = rdev_get_drvdata(rdev); - int rc = 0, current_uv = 0, rounded_uv = 0, enabled = 0; + int rc = 0; if (pm8008_reg->parent_supply) { - enabled = pm8008_regulator_is_enabled(rdev); - if (enabled < 0) { - return enabled; - } else if (enabled) { - current_uv = pm8008_regulator_get_voltage(rdev); - if (current_uv < 0) - return current_uv; - rounded_uv = roundup(min_uv, VSET_STEP_UV); - } - } - - /* - * Set the parent_supply voltage before changing the LDO voltage when - * the LDO voltage is being increased. - */ - if (pm8008_reg->parent_supply && enabled && rounded_uv >= current_uv) { - /* Request parent voltage with headroom */ + /* request on parent regulator with headroom */ rc = regulator_set_voltage(pm8008_reg->parent_supply, - rounded_uv + pm8008_reg->min_dropout_uv, + pm8008_reg->min_dropout_uv + min_uv, INT_MAX); if (rc < 0) { - pm8008_err(pm8008_reg, "failed to request parent supply voltage rc=%d\n", + pm8008_err(pm8008_reg, + "failed to request parent supply voltage rc=%d\n", rc); return rc; } } rc = pm8008_write_voltage(pm8008_reg, min_uv, max_uv); - if (rc < 0) - return rc; - - /* - * Set the parent_supply voltage after changing the LDO voltage when - * the LDO voltage is being reduced. - */ - if (pm8008_reg->parent_supply && enabled && rounded_uv < current_uv) { - /* - * Ensure sufficient time for the LDO voltage to slew down - * before reducing the parent supply voltage. The regulator - * framework will add the same delay after this function returns - * in all cases (i.e. enabled/disabled and increasing/decreasing - * voltage). - */ - udelay(pm8008_regulator_set_voltage_time(rdev, rounded_uv, - current_uv)); - - /* Request parent voltage with headroom */ - rc = regulator_set_voltage(pm8008_reg->parent_supply, - rounded_uv + pm8008_reg->min_dropout_uv, - INT_MAX); - if (rc < 0) { - pm8008_err(pm8008_reg, "failed to request parent supply voltage rc=%d\n", - rc); - return rc; - } + if (rc < 0) { + /* remove parent's voltage vote */ + if (pm8008_reg->parent_supply) + regulator_set_voltage(pm8008_reg->parent_supply, + 0, INT_MAX); } pm8008_debug(pm8008_reg, "voltage set to %d\n", min_uv); @@ -547,6 +475,14 @@ static int pm8008_regulator_set_load(struct regulator_dev *rdev, int load_uA) return pm8008_regulator_set_mode(rdev, mode); } +static int pm8008_regulator_set_voltage_time(struct regulator_dev *rdev, + int old_uV, int new_uv) +{ + struct pm8008_regulator *pm8008_reg = rdev_get_drvdata(rdev); + + return DIV_ROUND_UP(abs(new_uv - old_uV), pm8008_reg->step_rate); +} + static struct regulator_ops pm8008_regulator_ops = { .enable = pm8008_regulator_enable, .disable = pm8008_regulator_disable, @@ -650,7 +586,6 @@ static int pm8008_register_ldo(struct pm8008_regulator *pm8008_reg, char buff[MAX_REG_NAME]; const struct regulator_data *reg_data; int rc, i, init_voltage; - u32 base = 0; u8 reg; reg_data = pm8008_reg->pmic_subtype == PM8008_SUBTYPE ? pm8008_reg_data @@ -666,12 +601,11 @@ static int pm8008_register_ldo(struct pm8008_regulator *pm8008_reg, return -EINVAL; } - rc = of_property_read_u32(reg_node, "reg", &base); + rc = of_property_read_u16(reg_node, "reg", &pm8008_reg->base); if (rc < 0) { pr_err("%s: failed to get regulator base rc=%d\n", name, rc); return rc; } - pm8008_reg->base = base; rc = pm8008_regulator_register_init(pm8008_reg, ®_data[i]); if (rc) @@ -891,7 +825,7 @@ static int pm8008_regulator_probe(struct platform_device *pdev) /* PM8008 chip enable regulator callbacks */ static int pm8008_enable_regulator_enable(struct regulator_dev *rdev) { - struct pm8008_chip *chip = rdev_get_drvdata(rdev); + struct pm8008_regulator *chip = rdev_get_drvdata(rdev); int rc; rc = pm8008_masked_write(chip->regmap, MISC_CHIP_ENABLE_REG, @@ -907,7 +841,7 @@ static int pm8008_enable_regulator_enable(struct regulator_dev *rdev) static int pm8008_enable_regulator_disable(struct regulator_dev *rdev) { - struct pm8008_chip *chip = rdev_get_drvdata(rdev); + struct pm8008_regulator *chip = rdev_get_drvdata(rdev); int rc; rc = pm8008_masked_write(chip->regmap, MISC_CHIP_ENABLE_REG, @@ -923,7 +857,7 @@ static int pm8008_enable_regulator_disable(struct regulator_dev *rdev) static int pm8008_enable_regulator_is_enabled(struct regulator_dev *rdev) { - struct pm8008_chip *chip = rdev_get_drvdata(rdev); + struct pm8008_regulator *chip = rdev_get_drvdata(rdev); int rc; u8 reg; diff --git a/drivers/regulator/tps65132-regulator.c b/drivers/regulator/tps65132-regulator.c index 73978dd440f7..889a5621931e 100644 --- a/drivers/regulator/tps65132-regulator.c +++ b/drivers/regulator/tps65132-regulator.c @@ -1,284 +1,414 @@ /* - * TI TPS65132 Regulator driver + * TI TPS65132 Driver * - * Copyright (C) 2017 NVIDIA CORPORATION. All rights reserved. + * Copyright 2018 Texas Instruments * - * Author: Venkat Reddy Talla - * Laxman Dewangan + * Author: LiPing-m * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind, - * whether express or implied; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. */ -#include +#include #include -#include #include +#include #include +#include +#include +#include #include -#include -#include +#include +#include -#define TPS65132_REG_VPOS 0x00 -#define TPS65132_REG_VNEG 0x01 -#define TPS65132_REG_APPS_DISP_DISN 0x03 -#define TPS65132_REG_CONTROL 0x0FF +#include +#include -#define TPS65132_VOUT_MASK 0x1F -#define TPS65132_VOUT_N_VOLTAGE 0x15 -#define TPS65132_VOUT_VMIN 4000000 -#define TPS65132_VOUT_VMAX 6000000 -#define TPS65132_VOUT_STEP 100000 +#include +#include +#include +#include -#define TPS65132_REG_APPS_DIS_VPOS BIT(0) -#define TPS65132_REG_APPS_DIS_VNEG BIT(1) -#define TPS65132_REGULATOR_ID_VPOS 0 -#define TPS65132_REGULATOR_ID_VNEG 1 -#define TPS65132_MAX_REGULATORS 2 +/* Registers */ +#define TPS65132_REG_OUTPUT_CFG 0x10 -#define TPS65132_ACT_DIS_TIME_SLACK 1000 +#define TPS65132_REG_BRT_CFG 0x16 -struct tps65132_reg_pdata { - struct gpio_desc *en_gpiod; - struct gpio_desc *act_dis_gpiod; - unsigned int act_dis_time_us; - int ena_gpio_state; +#define TPS65132_REG_BOOST_CTL 0x1A +#define TPS65132_REG_BOOST 0x06 + +#define TPS65132_REG_PWM_CFG 0x1C + +#define TPS65132_REG_IMAX_A 0x17 +#define TPS65132_REG_IMAX_B 0x18 + +#define TPS65132_REG_BRT_A_LSB 0x00 +#define TPS65132_REG_BRT_A_MSB 0x01 +#define TPS65132_REG_BRT_B_LSB 0x22 +#define TPS65132_REG_BRT_B_MSB 0x23 +#define TPS65132_BRT_LSB_MASK (BIT(0) | BIT(1) | BIT(2)) +#define TPS65132_BRT_MSB_SHIFT 3 + +#define TPS65132_REG_ENABLE 0x24 + +/* Other definitions */ +#define TPS65132_PWM_ID 1 +#define TPS65132_MAX_REGISTERS 0xB4 +#define TPS65132_MAX_STRINGS 3 +#define TPS65132_MAX_BRIGHTNESS 2047 +#define TPS65132_IMAX_OFFSET 6 + +#define TPS65132_EXPONENTIAL 1 +#define TPS65132_LINEAR 0 +#define TPS65132_LEVEL_2048_SUPPROT 1 + +#define REG_PWM 0x1C +#define TPS65132_MIN_BRIGHTNESS 6 +#define FILTER_STR 0x50 +#define RUN_RAMP 0x08 +#define REG_REVISION 0x1F + + +struct tps65132_pw_platform_data { + const char *name; + unsigned long bl_string; + unsigned int init_brightness; + + /* Only valid in case of PWM mode */ + unsigned int pwm_period; }; -struct tps65132_regulator { - struct device *dev; - struct regmap *rmap; - struct regulator_desc *rdesc[TPS65132_MAX_REGULATORS]; - struct tps65132_reg_pdata reg_pdata[TPS65132_MAX_REGULATORS]; - struct regulator_dev *rdev[TPS65132_MAX_REGULATORS]; +/* + * struct TPS65132_platform_data + * @enn_gpio: GPIO for HWEN pin + * @bl_pdata: Backlight platform data + * @num_backlights: Number of backlight outputs + */ +struct tps65132_platform_data { + int enn_gpio; + int enp_gpio; + struct tps65132_pw_platform_data *bl_pdata; + int num_backlights; +}; +enum TPS65132_bl_ctrl_mode { + BL_REGISTER_BASED, + BL_PWM_BASED, }; -static int tps65132_regulator_enable(struct regulator_dev *rdev) +/* + * struct TPS65132_pw_chip + * @dev: Parent device structure + * @regmap: Used for I2C register access + * @pdata: TPS65132 platform data + */ +struct TPS65132_pw_chip { + struct device *dev; + struct tps65132_platform_data *pdata; + struct regmap *regmap; +}; + +/* + * struct TPS65132_pw + * @bank_id: Control bank ID. BANK A or BANK A and B + * @bl_dev: Backlight device structure + * @chip: TPS65132 backlight chip structure for low level access + * @bl_pdata: TPS65132 backlight platform data + * @mode: Backlight control mode + * @pwm: PWM device structure. Only valid in PWM control mode + * @pwm_name: PWM device name + */ +struct TPS65132_pw { + int bank_id; + struct backlight_device *bl_dev; + struct TPS65132_pw_chip *chip; + struct tps65132_pw_platform_data *bl_pdata; + enum TPS65132_bl_ctrl_mode mode; + struct pwm_device *pwm; + char pwm_name[20]; +}; + +static struct TPS65132_pw_chip *TPS65132_pchip; + +static int TPS65132_dt(struct device *dev, struct tps65132_platform_data *pdata) { - struct tps65132_regulator *tps = rdev_get_drvdata(rdev); - int id = rdev_get_id(rdev); - struct tps65132_reg_pdata *rpdata = &tps->reg_pdata[id]; - int ret; + struct device_node *np = dev->of_node; - if (!IS_ERR(rpdata->en_gpiod)) { - gpiod_set_value_cansleep(rpdata->en_gpiod, 1); - rpdata->ena_gpio_state = 1; - } + pdata->enn_gpio = of_get_named_gpio(np, "ti,enable_neg-gpio", 0); + pr_err("%s enn_gpio =%d\n", __func__, pdata->enn_gpio); - /* Hardware automatically enable discharge bit in enable */ - if (rdev->constraints->active_discharge == - REGULATOR_ACTIVE_DISCHARGE_DISABLE) { - ret = regulator_set_active_discharge_regmap(rdev, false); - if (ret < 0) { - dev_err(tps->dev, "Failed to disable active discharge: %d\n", - ret); - return ret; - } - } + if (!gpio_is_valid(pdata->enn_gpio)) + pr_err("%s:%d, tps65132_enn gpio not specified\n", __func__, __LINE__); - return 0; + pdata->enp_gpio = of_get_named_gpio(np, "ti,enable_pos-gpio", 0); + pr_err("%s enp_gpio =%d\n", __func__, pdata->enp_gpio); + + if (!gpio_is_valid(pdata->enp_gpio)) + pr_err("%s:%d, tps65132_enp gpio not specified\n", __func__, __LINE__); + + return 0; } -static int tps65132_regulator_disable(struct regulator_dev *rdev) +int TPS65132_reg_init(void) { - struct tps65132_regulator *tps = rdev_get_drvdata(rdev); - int id = rdev_get_id(rdev); - struct tps65132_reg_pdata *rpdata = &tps->reg_pdata[id]; + struct TPS65132_pw_chip *pchip = TPS65132_pchip; + int ret =0; - if (!IS_ERR(rpdata->en_gpiod)) { - gpiod_set_value_cansleep(rpdata->en_gpiod, 0); - rpdata->ena_gpio_state = 0; - } + if(!pchip || !TPS65132_pchip){ + pr_err("TPS65132_reg_init pdata is null\n"); + return 0; + } - if (!IS_ERR(rpdata->act_dis_gpiod)) { - gpiod_set_value_cansleep(rpdata->act_dis_gpiod, 1); - usleep_range(rpdata->act_dis_time_us, rpdata->act_dis_time_us + - TPS65132_ACT_DIS_TIME_SLACK); - gpiod_set_value_cansleep(rpdata->act_dis_gpiod, 0); - } + if (!pchip->regmap || !TPS65132_pchip->regmap || !TPS65132_pchip->pdata) { + pr_err("%s pchip->regmap is NULL.\n", __func__); + return 0; + } - return 0; + pr_err("%s: init TPS65132 reg\n", __func__); + + ret = regmap_write(pchip->regmap, 0x00, 0x0F); //5V + if (ret < 0) { + pr_err("%s: regmap_write 0x00 failed, ret = %d", __func__, ret); + goto out; + } + ret = regmap_write(pchip->regmap, 0x01, 0x0F); //-5V + if (ret < 0) { + pr_err("%s: regmap_write 0x01 failed, ret = %d", __func__, ret); + goto out; + } + ret = regmap_write(pchip->regmap, 0x03, 0x43); + if (ret < 0){ + pr_err("%s: regmap_write 0x03 failed, ret = %d", __func__, ret); + goto out; + } + + return ret; +out: + pr_err("i2c failed to access register\n"); + return ret; +} +EXPORT_SYMBOL(TPS65132_reg_init); + +void TPS65132_pw_enable(int enable) +{ + struct TPS65132_pw_chip *pchip = TPS65132_pchip; + + if(!pchip || !TPS65132_pchip){ + pr_err("TPS65132_pw_enable pdata is null\n"); + return; + } + if (!pchip->regmap || !TPS65132_pchip->regmap || !TPS65132_pchip->pdata) { + pr_err("%s pchip->regmap is NULL.\n", __func__); + return; + } + + pr_err("mdss %s = %d\n", __func__, enable); + + if(enable){ + if (gpio_is_valid(pchip->pdata->enn_gpio)){ + gpio_set_value((pchip->pdata->enn_gpio), 1); + }else{ + pr_err("%s: enable enn_gpio failed", __func__); + } + if (gpio_is_valid(pchip->pdata->enp_gpio)){ + gpio_set_value((pchip->pdata->enp_gpio), 1); + }else{ + pr_err("%s: enable enp_gpio failed", __func__); + } + }else{ + if (gpio_is_valid(pchip->pdata->enn_gpio)){ + gpio_set_value((pchip->pdata->enn_gpio), 0); + }else{ + pr_err("%s: disable enn_gpio failed", __func__); + } + if (gpio_is_valid(pchip->pdata->enp_gpio)){ + gpio_set_value((pchip->pdata->enp_gpio), 0); + }else{ + pr_err("%s: disable enp_gpio failed", __func__); + } + } +} +EXPORT_SYMBOL(TPS65132_pw_enable); + +static int TPS65132_chip_init(struct TPS65132_pw_chip *pchip){ + int ret = 0; + + ret = regmap_write(pchip->regmap, 0x00, 0x0F); //5V + if (ret < 0) + goto out; + ret = regmap_write(pchip->regmap, 0x01, 0x0F); //-5V + if (ret < 0) + goto out; + ret = regmap_write(pchip->regmap, 0x03, 0x03); + if (ret < 0) + goto out; + + return ret; + +out: + pr_err("TPS65132_chip_init i2c failed to access register\n"); + return ret; } -static int tps65132_regulator_is_enabled(struct regulator_dev *rdev) +static struct regmap_config TPS65132_regmap = { + .reg_bits = 8, + .val_bits = 8, +}; + +static int TPS65132_bl_probe(struct i2c_client *client, + const struct i2c_device_id *id) { - struct tps65132_regulator *tps = rdev_get_drvdata(rdev); - int id = rdev_get_id(rdev); - struct tps65132_reg_pdata *rpdata = &tps->reg_pdata[id]; + struct tps65132_platform_data *pdata = client->dev.platform_data; + struct TPS65132_pw_chip *pchip; + int ret = 0; - if (!IS_ERR(rpdata->en_gpiod)) - return rpdata->ena_gpio_state; + pr_err("%s Enter\n", __func__); - return 1; + if (client->dev.of_node) { + pdata = devm_kzalloc(&client->dev, + sizeof(struct tps65132_platform_data), GFP_KERNEL); + if (!pdata) { + pr_err("Failed to allocate memory\n"); + return -ENOMEM; + } + + ret = TPS65132_dt(&client->dev, pdata); + if (ret) + return ret; + } else + pdata = client->dev.platform_data; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + pr_err("fail : i2c functionality check...\n"); + return -EOPNOTSUPP; + } + + if (pdata == NULL) { + pr_err("fail : no platform data.\n"); + return -ENODATA; + } + + pchip = devm_kzalloc(&client->dev, sizeof(struct TPS65132_pw_chip), + GFP_KERNEL); + if (!pchip) { + pr_err("no memory to alloc struct TPS65132_pw_chip\n"); + return -ENOMEM; + } + TPS65132_pchip = pchip; + + + pchip->pdata = pdata; + pchip->dev = &client->dev; + + ret = gpio_request(pdata->enn_gpio, "tps65132-neg"); + if (ret) { + pr_err("request tps65132_enn_enable gpio failed, ret=%d\n", ret); + } + ret = gpio_request(pdata->enp_gpio, "tps65132-pos"); + if (ret) { + pr_err("request tps65132_enp_enable gpio failed, ret=%d\n", ret); + } + + if (gpio_is_valid(pdata->enn_gpio)){ + gpio_set_value((pdata->enn_gpio), 1); + gpio_direction_output((pdata->enn_gpio), 1); + pr_err("%s tps65132_enn_enable =%d\n", __func__, pdata->enn_gpio); + } + + if (gpio_is_valid(pdata->enp_gpio)){ + gpio_set_value((pdata->enp_gpio), 1); + gpio_direction_output((pdata->enp_gpio), 1); + pr_err("%s tps65132_enp_enable =%d\n", __func__, pdata->enp_gpio); + } + + msleep(5); + pchip->regmap = devm_regmap_init_i2c(client, &TPS65132_regmap); + if (IS_ERR(pchip->regmap)) { + ret = PTR_ERR(pchip->regmap); + pr_err("fail : allocate register map: %d\n", + ret); + return ret; + } + + msleep(5); + i2c_set_clientdata(client, pchip); + + /* chip initialize */ + msleep(5); + ret = TPS65132_chip_init(pchip); + if (ret < 0) { + pr_err("fail : init chip\n"); + goto error_enable; + } + + pr_info("%s : probe done\n", __func__); + + return 0; + +error_enable: + + devm_kfree(&client->dev, pchip->pdata); + devm_kfree(&client->dev, pchip); + pr_err("%s : probe failed\n", __func__); + return ret; } -static struct regulator_ops tps65132_regulator_ops = { - .enable = tps65132_regulator_enable, - .disable = tps65132_regulator_disable, - .is_enabled = tps65132_regulator_is_enabled, - .list_voltage = regulator_list_voltage_linear, - .map_voltage = regulator_map_voltage_linear, - .get_voltage_sel = regulator_get_voltage_sel_regmap, - .set_voltage_sel = regulator_set_voltage_sel_regmap, - .set_active_discharge = regulator_set_active_discharge_regmap, -}; +static int TPS65132_bl_remove(struct i2c_client *client){ + struct TPS65132_pw_chip *pchip = i2c_get_clientdata(client); + int ret = 0; -static int tps65132_of_parse_cb(struct device_node *np, - const struct regulator_desc *desc, - struct regulator_config *config) -{ - struct tps65132_regulator *tps = config->driver_data; - struct tps65132_reg_pdata *rpdata = &tps->reg_pdata[desc->id]; - int ret; - - rpdata->en_gpiod = devm_fwnode_get_index_gpiod_from_child(tps->dev, - "enable", 0, &np->fwnode, 0, "enable"); - if (IS_ERR(rpdata->en_gpiod)) { - ret = PTR_ERR(rpdata->en_gpiod); - - /* Ignore the error other than probe defer */ - if (ret == -EPROBE_DEFER) - return ret; - return 0; + if(!pchip || !pchip->regmap || !pchip->pdata) { + pr_err("%s, have null pointer!\n", __func__); + return -1; } - rpdata->act_dis_gpiod = devm_fwnode_get_index_gpiod_from_child( - tps->dev, "active-discharge", 0, - &np->fwnode, 0, "active-discharge"); - if (IS_ERR(rpdata->act_dis_gpiod)) { - ret = PTR_ERR(rpdata->act_dis_gpiod); + dev_info(pchip->dev, "%s : failed\n", __func__); - /* Ignore the error other than probe defer */ - if (ret == -EPROBE_DEFER) - return ret; + ret = regmap_write(pchip->regmap, TPS65132_REG_BRT_A_LSB, 0); + if (ret < 0) + pr_err("i2c failed to access register\n"); - return 0; - } + ret = regmap_write(pchip->regmap, TPS65132_REG_BRT_A_MSB, 0); + if (ret < 0) + pr_err("i2c failed to access register\n"); - ret = of_property_read_u32(np, "ti,active-discharge-time-us", - &rpdata->act_dis_time_us); - if (ret < 0) { - dev_err(tps->dev, "Failed to read active discharge time:%d\n", - ret); - return ret; - } + if (gpio_is_valid(pchip->pdata->enn_gpio)){ + gpio_set_value(pchip->pdata->enn_gpio, 0); + gpio_free(pchip->pdata->enn_gpio); + } + if (gpio_is_valid(pchip->pdata->enp_gpio)){ + gpio_set_value(pchip->pdata->enp_gpio, 0); + gpio_free(pchip->pdata->enp_gpio); + } - return 0; + return 0; } -#define TPS65132_REGULATOR_DESC(_id, _name) \ - [TPS65132_REGULATOR_ID_##_id] = { \ - .name = "tps65132-"#_name, \ - .supply_name = "vin", \ - .id = TPS65132_REGULATOR_ID_##_id, \ - .of_match = of_match_ptr(#_name), \ - .of_parse_cb = tps65132_of_parse_cb, \ - .ops = &tps65132_regulator_ops, \ - .n_voltages = TPS65132_VOUT_N_VOLTAGE, \ - .min_uV = TPS65132_VOUT_VMIN, \ - .uV_step = TPS65132_VOUT_STEP, \ - .enable_time = 500, \ - .vsel_mask = TPS65132_VOUT_MASK, \ - .vsel_reg = TPS65132_REG_##_id, \ - .active_discharge_off = 0, \ - .active_discharge_on = TPS65132_REG_APPS_DIS_##_id, \ - .active_discharge_mask = TPS65132_REG_APPS_DIS_##_id, \ - .active_discharge_reg = TPS65132_REG_APPS_DISP_DISN, \ - .type = REGULATOR_VOLTAGE, \ - .owner = THIS_MODULE, \ - } - -static struct regulator_desc tps_regs_desc[TPS65132_MAX_REGULATORS] = { - TPS65132_REGULATOR_DESC(VPOS, outp), - TPS65132_REGULATOR_DESC(VNEG, outn), +static const struct i2c_device_id TPS65132_bl_ids[] = { + { "ti,tps65132", 0 }, + { } }; -static const struct regmap_range tps65132_no_reg_ranges[] = { - regmap_reg_range(TPS65132_REG_APPS_DISP_DISN + 1, - TPS65132_REG_CONTROL - 1), -}; - -static const struct regmap_access_table tps65132_no_reg_table = { - .no_ranges = tps65132_no_reg_ranges, - .n_no_ranges = ARRAY_SIZE(tps65132_no_reg_ranges), -}; - -static const struct regmap_config tps65132_regmap_config = { - .reg_bits = 8, - .val_bits = 8, - .max_register = TPS65132_REG_CONTROL, - .cache_type = REGCACHE_NONE, - .rd_table = &tps65132_no_reg_table, - .wr_table = &tps65132_no_reg_table, -}; - -static int tps65132_probe(struct i2c_client *client, - const struct i2c_device_id *client_id) -{ - struct device *dev = &client->dev; - struct tps65132_regulator *tps; - struct regulator_config config = { }; - int id; - int ret; - - tps = devm_kzalloc(dev, sizeof(*tps), GFP_KERNEL); - if (!tps) - return -ENOMEM; - - tps->rmap = devm_regmap_init_i2c(client, &tps65132_regmap_config); - if (IS_ERR(tps->rmap)) { - ret = PTR_ERR(tps->rmap); - dev_err(dev, "regmap init failed: %d\n", ret); - return ret; - } - - i2c_set_clientdata(client, tps); - tps->dev = dev; - - for (id = 0; id < TPS65132_MAX_REGULATORS; ++id) { - tps->rdesc[id] = &tps_regs_desc[id]; - - config.regmap = tps->rmap; - config.dev = dev; - config.driver_data = tps; - - tps->rdev[id] = devm_regulator_register(dev, - tps->rdesc[id], &config); - if (IS_ERR(tps->rdev[id])) { - ret = PTR_ERR(tps->rdev[id]); - dev_err(dev, "regulator %s register failed: %d\n", - tps->rdesc[id]->name, ret); - return ret; - } - } - return 0; -} - -static const struct i2c_device_id tps65132_id[] = { - {.name = "tps65132",}, +static const struct of_device_id tps65132_of_match[] = { + { .compatible = "ti,tps65132",}, {}, }; -MODULE_DEVICE_TABLE(i2c, tps65132_id); -static struct i2c_driver tps65132_i2c_driver = { - .driver = { - .name = "tps65132", - }, - .probe = tps65132_probe, - .id_table = tps65132_id, +static struct i2c_driver TPS65132_i2c_driver = { + .probe = TPS65132_bl_probe, + .remove = TPS65132_bl_remove, + .driver = { + .name = "tps65132", + .of_match_table = tps65132_of_match, + .owner = THIS_MODULE, + }, + .id_table = TPS65132_bl_ids, }; -module_i2c_driver(tps65132_i2c_driver); +module_i2c_driver(TPS65132_i2c_driver); -MODULE_DESCRIPTION("tps65132 regulator driver"); -MODULE_AUTHOR("Venkat Reddy Talla "); -MODULE_AUTHOR("Laxman Dewangan "); -MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("TPS65132 Power Driver"); +MODULE_AUTHOR("LiPing-M"); +MODULE_LICENSE("GPL"); diff --git a/drivers/rtc/rtc-pm8xxx.c b/drivers/rtc/rtc-pm8xxx.c index f5d40c6de54c..67bc979f14bb 100644 --- a/drivers/rtc/rtc-pm8xxx.c +++ b/drivers/rtc/rtc-pm8xxx.c @@ -12,7 +12,12 @@ #include #include #include - +#ifdef OPLUS_FEATURE_CHG_BASIC +#ifdef dev_dbg +#undef dev_dbg +#endif +#define dev_dbg dev_err +#endif /* RTC Register offsets from RTC CTRL REG */ #define PM8XXX_ALARM_CTRL_OFFSET 0x01 #define PM8XXX_RTC_WRITE_OFFSET 0x02 diff --git a/drivers/rtc/rtc-proc.c b/drivers/rtc/rtc-proc.c index b8c5b93102ce..58b58d2657aa 100644 --- a/drivers/rtc/rtc-proc.c +++ b/drivers/rtc/rtc-proc.c @@ -109,6 +109,11 @@ static int rtc_proc_show(struct seq_file *seq, void *offset) void rtc_proc_add_device(struct rtc_device *rtc) { +#ifdef OPLUS_FEATURE_SAUPWK + extern void __attribute__((weak)) saupwk_rtc_proc_add_device(struct rtc_device *rtc); + if(saupwk_rtc_proc_add_device) + saupwk_rtc_proc_add_device(rtc); +#endif if (is_rtc_hctosys(rtc)) proc_create_single_data("driver/rtc", 0, NULL, rtc_proc_show, rtc); @@ -116,6 +121,11 @@ void rtc_proc_add_device(struct rtc_device *rtc) void rtc_proc_del_device(struct rtc_device *rtc) { +#ifdef OPLUS_FEATURE_SAUPWK + extern void __attribute__((weak)) saupwk_rtc_proc_del_device(struct rtc_device *rtc); + if(saupwk_rtc_proc_del_device) + saupwk_rtc_proc_del_device(rtc); +#endif if (is_rtc_hctosys(rtc)) remove_proc_entry("driver/rtc", NULL); } diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig index 7cb6e2b9e180..b5431d351f84 100644 --- a/drivers/scsi/Kconfig +++ b/drivers/scsi/Kconfig @@ -512,6 +512,7 @@ source "drivers/scsi/esas2r/Kconfig" source "drivers/scsi/megaraid/Kconfig.megaraid" source "drivers/scsi/mpt3sas/Kconfig" source "drivers/scsi/smartpqi/Kconfig" +source "drivers/scsi/oufs/Kconfig" source "drivers/scsi/ufs/Kconfig" config SCSI_HPTIOP diff --git a/drivers/scsi/oufs b/drivers/scsi/oufs new file mode 120000 index 000000000000..45b421ef4bc9 --- /dev/null +++ b/drivers/scsi/oufs @@ -0,0 +1 @@ +../../../../vendor/oplus/kernel_4.19/ufs \ No newline at end of file diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index faf8b3a8eaac..404f07cb9218 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -2033,13 +2033,24 @@ sd_spinup_disk(struct scsi_disk *sdkp) * doesn't have any media in it, don't bother * with any more polling. */ +#ifdef OPLUS_FEATURE_CHG_BASIC + if (retries > 25) { + if (media_not_present(sdkp, &sshdr)) + return; + } +#else if (media_not_present(sdkp, &sshdr)) return; +#endif if (the_result) sense_valid = scsi_sense_valid(&sshdr); retries++; - } while (retries < 3 && +#ifdef OPLUS_FEATURE_CHG_BASIC + } while (retries < 30 && +#else + } while (retries < 3 && +#endif (!scsi_status_is_good(the_result) || ((driver_byte(the_result) == DRIVER_SENSE) && sense_valid && sshdr.sense_key == UNIT_ATTENTION))); diff --git a/drivers/scsi/ufs/Kconfig b/drivers/scsi/ufs/Kconfig index f1aae8beff9e..8c9aba9b44c9 100644 --- a/drivers/scsi/ufs/Kconfig +++ b/drivers/scsi/ufs/Kconfig @@ -3,6 +3,7 @@ # # This code is based on drivers/scsi/ufs/Kconfig # Copyright (C) 2011-2013 Samsung India Software Operations +# Copyright (C) 2020 Oplus. All rights reserved. # # Authors: # Santosh Yaraganavi @@ -148,3 +149,60 @@ config SCSI_UFS_CRYPTO_QTI Enable Vendor Crypto Engine Support in UFS Enabling this allows kernel to use UFS crypto operations defined and implemented by QTI. + +#ifdef OPLUS_FEATURE_UFSPLUS +config UFSFEATURE + bool "UFS feature activate" + depends on SCSI_UFSHCD + ---help--- + UFS feature activate such as hpb, tw and etc. + +config UFSHPB + bool "UFS Host Performance Booster support" + depends on SCSI_UFSHCD && UFSFEATURE + ---help--- + UFS HPB Feature Enable + +config HPB_ERR_INJECTION + bool "HPB ERROR INJECTION" + depends on SCSI_UFSHCD && UFSFEATURE && UFSHPB + ---help--- + error injection for checking HPB entry integrity + +config UFSTW + bool "UFS Turbo Write support" + depends on SCSI_UFSHCD && UFSFEATURE + ---help--- + UFS TW Feature Enable + +config UFSTW_IGNORE_GUARANTEE_BIT + bool "Ignore UFS Turbo Write Life Time Guarantee bit for POC" + default n + depends on SCSI_UFSHCD && UFSFEATURE && UFSTW + ---help--- + ignore the guarantee bit[31] of dTurboWriteBufferLifeTimeEst for PoC + +config UFSTW_BOOT_ENABLED + bool "Turbo Write enabled at boot time" + default y + depends on SCSI_UFSHCD && UFSFEATURE && UFSTW + ---help--- + fTurboWriteEn and fTurboWriteBufferFlushDuringHibnerEnter flags + are enabled at boot time. + +config UFSHID + bool "UFS Host Initiated Defrag support" + depends on SCSI_UFSHCD && UFSFEATURE + ---help--- + UFS HID Feature Enable + +config UFSHID_POC + bool "UFSHID_POC test" + depends on SCSI_UFSHCD && UFSFEATURE && UFSHID + ---help--- + UFS HID POC test + 1. block to enter suspend state + 2. auto_hibern8 enable/disable (HCI) + 3. set flag bDefragOperation + 4. debug msg enable (default : disable) +#endif /*OPLUS_FEATURE_UFSPLUS*/ diff --git a/drivers/scsi/ufs/Makefile b/drivers/scsi/ufs/Makefile index e7294e6f42a3..fb41345bf397 100644 --- a/drivers/scsi/ufs/Makefile +++ b/drivers/scsi/ufs/Makefile @@ -6,6 +6,18 @@ obj-$(CONFIG_SCSI_UFS_QCOM) += ufs-qcom.o obj-$(CONFIG_SCSI_UFS_QCOM_ICE) += ufs-qcom-ice.o obj-$(CONFIG_SCSI_UFSHCD) += ufshcd-core.o ufshcd-core-objs := ufshcd.o ufs-sysfs.o +ifneq ($(OPLUS_FEATURE_UFS_SHOW_LATENCY),) +ufshcd-core-objs += ufs_latency_hist.o +endif # OPLUS_FEATURE_UFS_SHOW_LATENCY +ifneq ($(OPLUS_FEATURE_PADL_STATISTICS),) +ufshcd-core-objs += ufs_signal_quality.o +endif # OPLUS_FEATURE_PADL_STATISTICS +ifneq ($(OPLUS_FEATURE_UFSPLUS),) +obj-$(CONFIG_UFSFEATURE) += ufsfeature.o +obj-$(CONFIG_UFSHPB) += ufshpb.o +obj-$(CONFIG_UFSTW) += ufstw.o +obj-$(CONFIG_UFSHID) += ufshid.o +endif #OPLUS_FEATURE_UFSPLUS obj-$(CONFIG_SCSI_UFSHCD_PCI) += ufshcd-pci.o obj-$(CONFIG_SCSI_UFSHCD_PLATFORM) += ufshcd-pltfrm.o obj-$(CONFIG_SCSI_UFS_TEST) += ufs_test.o diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c index ae08086dcd23..bfdf069ca434 100644 --- a/drivers/scsi/ufs/ufs-qcom.c +++ b/drivers/scsi/ufs/ufs-qcom.c @@ -1502,8 +1502,12 @@ static void ufs_qcom_set_caps(struct ufs_hba *hba) hba->caps |= UFSHCD_CAP_AUTO_BKOPS_SUSPEND; if (host->hw_ver.major >= 0x2) { + /* remove the power off/on during H8, avoid 7250 core hang issue + add by yanghao@PSW.Kernel.Stability 2020-8-25 */ + #ifndef OPLUS_BUG_STABILITY if (!host->disable_lpm) hba->caps |= UFSHCD_CAP_POWER_COLLAPSE_DURING_HIBERN8; + #endif host->caps = UFS_QCOM_CAP_QUNIPRO | UFS_QCOM_CAP_RETAIN_SEC_CFG_AFTER_PWR_COLLAPSE; } diff --git a/drivers/scsi/ufs/ufs-sysfs.c b/drivers/scsi/ufs/ufs-sysfs.c index 4ac38aee5d93..a362b9687edb 100644 --- a/drivers/scsi/ufs/ufs-sysfs.c +++ b/drivers/scsi/ufs/ufs-sysfs.c @@ -9,6 +9,10 @@ #include "ufs.h" #include "ufs-sysfs.h" +#ifdef OPLUS_FEATURE_UFS_SHOW_LATENCY +#include "ufs_latency_hist.h" +#endif + static const char *ufschd_uic_link_state_to_string( enum uic_link_state state) { @@ -210,6 +214,55 @@ static ssize_t auto_hibern8_store(struct device *dev, return count; } +#ifdef OPLUS_FEATURE_UFS_SHOW_LATENCY +//add latency_hist node for ufs latency calculate in sysfs. +/* +* Values permitted 0, 1, 2. +* 0 -> Disable IO latency histograms (default) +* 1 -> Enable IO latency histograms +* 2 -> Zero out IO latency histograms +*/ +static ssize_t +latency_hist_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct ufs_hba *hba = dev_get_drvdata(dev); + long value; + int old_status; + + if (kstrtol(buf, 0, &value)) + return -EINVAL; + if (value == IO_LAT_HIST_ZERO) { + old_status = hba->latency_hist_enabled; + hba->latency_hist_enabled = 0; + memset(&hba->io_lat_read, 0, sizeof(hba->io_lat_read)); + memset(&hba->io_lat_write, 0, sizeof(hba->io_lat_write)); + memset(&hba->io_lat_other, 0, sizeof(hba->io_lat_other)); + hba->latency_hist_enabled = old_status; + } else if (value == IO_LAT_HIST_ENABLE || + value == IO_LAT_HIST_DISABLE) + hba->latency_hist_enabled = value; + return count; +} + +ssize_t +latency_hist_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct ufs_hba *hba = dev_get_drvdata(dev); + size_t written_bytes = 0; + + written_bytes += io_latency_hist_show("Read", &hba->io_lat_read, + buf + written_bytes, 8192 - written_bytes); + written_bytes += io_latency_hist_show("Write", &hba->io_lat_write, + buf + written_bytes, 8192 - written_bytes); + written_bytes += io_latency_hist_show("Other", &hba->io_lat_other, + buf + written_bytes, 8192 - written_bytes); + + return written_bytes; +} +#endif + static DEVICE_ATTR_RW(rpm_lvl); static DEVICE_ATTR_RO(rpm_target_dev_state); static DEVICE_ATTR_RO(rpm_target_link_state); @@ -217,6 +270,10 @@ static DEVICE_ATTR_RW(spm_lvl); static DEVICE_ATTR_RO(spm_target_dev_state); static DEVICE_ATTR_RO(spm_target_link_state); static DEVICE_ATTR_RW(auto_hibern8); +#ifdef OPLUS_FEATURE_UFS_SHOW_LATENCY +//add latency_hist node for ufs latency calculate in sysfs. +static DEVICE_ATTR_RW(latency_hist); +#endif static struct attribute *ufs_sysfs_ufshcd_attrs[] = { &dev_attr_rpm_lvl.attr, @@ -226,6 +283,10 @@ static struct attribute *ufs_sysfs_ufshcd_attrs[] = { &dev_attr_spm_target_dev_state.attr, &dev_attr_spm_target_link_state.attr, &dev_attr_auto_hibern8.attr, +#ifdef OPLUS_FEATURE_UFS_SHOW_LATENCY +//add latency_hist node for ufs latency calculate in sysfs. + &dev_attr_latency_hist.attr, +#endif NULL }; diff --git a/drivers/scsi/ufs/ufs.h b/drivers/scsi/ufs/ufs.h index cededde98be3..0f72c4afdafe 100644 --- a/drivers/scsi/ufs/ufs.h +++ b/drivers/scsi/ufs/ufs.h @@ -137,11 +137,11 @@ enum desc_header_offset { }; enum ufs_desc_def_size { - QUERY_DESC_DEVICE_DEF_SIZE = 0x59, - QUERY_DESC_CONFIGURATION_DEF_SIZE = 0x90, - QUERY_DESC_UNIT_DEF_SIZE = 0x23, - QUERY_DESC_INTERCONNECT_DEF_SIZE = 0x06, - QUERY_DESC_GEOMETRY_DEF_SIZE = 0x48, + QUERY_DESC_DEVICE_DEF_SIZE = 0x5F, + QUERY_DESC_CONFIGURATION_DEF_SIZE = 0xE6, + QUERY_DESC_UNIT_DEF_SIZE = 0x2D, + QUERY_DESC_INTERCONNECT_DEF_SIZE = 0x06, + QUERY_DESC_GEOMETRY_DEF_SIZE = 0x59, QUERY_DESC_POWER_DEF_SIZE = 0x62, QUERY_DESC_HEALTH_DEF_SIZE = 0x25, }; @@ -165,6 +165,13 @@ enum unit_desc_param { UNIT_DESC_PARAM_PHY_MEM_RSRC_CNT = 0x18, UNIT_DESC_PARAM_CTX_CAPABILITIES = 0x20, UNIT_DESC_PARAM_LARGE_UNIT_SIZE_M1 = 0x22, +#ifdef OPLUS_FEATURE_UFSPLUS +#if defined(CONFIG_UFSHPB) + UNIT_DESC_HPB_LU_MAX_ACTIVE_REGIONS = 0x23, + UNIT_DESC_HPB_LU_PIN_REGION_START_OFFSET = 0x25, + UNIT_DESC_HPB_LU_NUM_PIN_REGIONS = 0x27, +#endif +#endif UNIT_DESC_PARAM_WB_BUF_ALLOC_UNITS = 0x29, }; @@ -205,10 +212,23 @@ enum device_desc_param { DEVICE_DESC_PARAM_PSA_MAX_DATA = 0x25, DEVICE_DESC_PARAM_PSA_TMT = 0x29, DEVICE_DESC_PARAM_PRDCT_REV = 0x2A, +#ifdef OPLUS_FEATURE_UFSPLUS +#if defined(CONFIG_UFSHPB) + DEVICE_DESC_PARAM_HPB_VER = 0x40, + DEVICE_DESC_PARAM_HPB_CONTROL = 0x42, +#endif +#if defined(CONFIG_UFSTW) + DEVICE_DESC_PARAM_TW_VER = 0x4D, + DEVICE_DESC_PARAM_TW_VER_3_0 = 0x55, +#endif +#endif DEVICE_DESC_PARAM_EXT_UFS_FEATURE_SUP = 0x4F, DEVICE_DESC_PARAM_WB_US_RED_EN = 0x53, DEVICE_DESC_PARAM_WB_TYPE = 0x54, DEVICE_DESC_PARAM_WB_SHARED_ALLOC_UNITS = 0x55, +#if defined(CONFIG_UFSHID) + DEVICE_DESC_PARAM_HID_VER = 0x59, +#endif }; /* Interconnect descriptor parameters offsets in bytes*/ @@ -253,6 +273,17 @@ enum geometry_desc_param { GEOMETRY_DESC_PARAM_ENM4_MAX_NUM_UNITS = 0x3E, GEOMETRY_DESC_PARAM_ENM4_CAP_ADJ_FCTR = 0x42, GEOMETRY_DESC_PARAM_OPT_LOG_BLK_SIZE = 0x44, +#ifdef OPLUS_FEATURE_UFSPLUS +#if defined(CONFIG_UFSHPB) + GEOMETRY_DESC_HPB_REGION_SIZE = 0x48, + GEOMETRY_DESC_HPB_NUMBER_LU = 0x49, + GEOMETRY_DESC_HPB_SUBREGION_SIZE = 0x4A, + GEOMETRY_DESC_HPB_DEVICE_MAX_ACTIVE_REGIONS = 0x4B, +#endif +#if defined(CONFIG_UFSTW) + GEOMETRY_DESC_TW_GROUP_NUM_CAP = 0x4E, +#endif +#endif GEOMETRY_DESC_PARAM_WB_MAX_ALLOC_UNITS = 0x4F, GEOMETRY_DESC_PARAM_WB_MAX_WB_LUNS = 0x53, GEOMETRY_DESC_PARAM_WB_BUFF_CAP_ADJ = 0x54, @@ -310,6 +341,11 @@ enum power_desc_param_offset { enum { MASK_EE_STATUS = 0xFFFF, MASK_EE_URGENT_BKOPS = (1 << 2), +#ifdef OPLUS_FEATURE_UFSPLUS +#if defined(CONFIG_UFSTW) + MASK_EE_TW = (1 << 5), +#endif +#endif }; /* Background operation status */ diff --git a/drivers/scsi/ufs/ufs_latency_hist.c b/drivers/scsi/ufs/ufs_latency_hist.c new file mode 100644 index 000000000000..09ea861796e6 --- /dev/null +++ b/drivers/scsi/ufs/ufs_latency_hist.c @@ -0,0 +1,71 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2018-2020 Oplus. All rights reserved. + */ + +#include "ufs_latency_hist.h" +#include +/* add latency_hist node for ufs latency calculate in sysfs */ +/* + * Blk IO latency support. We want this to be as cheap as possible, so doing + * this lockless (and avoiding atomics), a few off by a few errors in this + * code is not harmful, and we don't want to do anything that is + * perf-impactful. + * TODO : If necessary, we can make the histograms per-cpu and aggregate + * them when printing them out. + */ +ssize_t +io_latency_hist_show(char *name, struct io_latency_state *s, char *buf, + int buf_size) +{ + int i; + int bytes_written = 0; + u_int64_t num_elem, elem; + int pct; + u_int64_t average; + + num_elem = s->latency_elems; + if (num_elem > 0) { + average = div64_u64(s->latency_sum, s->latency_elems); + bytes_written += scnprintf(buf + bytes_written, + buf_size - bytes_written, + "IO %s(count = %llu," + " average = %lluus)\t0\t4k\t8k\t8-32k\t32-64k\t64-128k\t128-256k\t>256k:\n", name, num_elem, average); + for (i = 0;i < ARRAY_SIZE(latency_x_axis_us);i++) { + elem = s->latency_y_axis[i].latency_axis; + pct = div64_u64(elem * 100, num_elem); + bytes_written += scnprintf(buf + bytes_written, + 8192 - bytes_written, + "\t< %6lluus\t%llu\t%d%%\t%llu\t%llu\t%llu\t%llu\t%llu\t%llu\t%llu\t\t%llu\n", + latency_x_axis_us[i], + elem, pct, + s->latency_y_axis[i].chunk_0_count, + s->latency_y_axis[i].chunk_4k_count, + s->latency_y_axis[i].chunk_8k_count, + s->latency_y_axis[i].chunk_8_32k_count, + s->latency_y_axis[i].chunk_32_64k_count, + s->latency_y_axis[i].chunk_64_128k_count, + s->latency_y_axis[i].chunk_128_256k_count, + s->latency_y_axis[i].chunk_above_256k_count); + } + /* Last element in y-axis table is overflow */ + elem = s->latency_y_axis[i].latency_axis; + pct = div64_u64(elem * 100, num_elem); + bytes_written += scnprintf(buf + bytes_written, + 8192 - bytes_written, + "\t>=%6lluus\t%llu\t%d%%\t%llu\t%llu\t%llu\t%llu\t%llu\t%llu\t%llu\t\t%llu\n", + latency_x_axis_us[i - 1], + elem, pct, + s->latency_y_axis[i].chunk_0_count, + s->latency_y_axis[i].chunk_4k_count, + s->latency_y_axis[i].chunk_8k_count, + s->latency_y_axis[i].chunk_8_32k_count, + s->latency_y_axis[i].chunk_32_64k_count, + s->latency_y_axis[i].chunk_64_128k_count, + s->latency_y_axis[i].chunk_128_256k_count, + s->latency_y_axis[i].chunk_above_256k_count); + } + + return bytes_written; +} + diff --git a/drivers/scsi/ufs/ufs_latency_hist.h b/drivers/scsi/ufs/ufs_latency_hist.h new file mode 100644 index 000000000000..4bb8d51ec395 --- /dev/null +++ b/drivers/scsi/ufs/ufs_latency_hist.h @@ -0,0 +1,115 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2018-2020 Oplus. All rights reserved. + */ + +#ifndef _UFS_LATENCY_HIST_ +#define _UFS_LATENCY_HIST_ + +#include +#include + +/* add latency_hist node for ufs latency calculate in sysfs */ +/* + * X-axis for IO latency histogram support. + */ +static const u_int64_t latency_x_axis_us[] = { + 100, + 200, + 300, + 400, + 500, + 600, + 700, + 800, + 900, + 1000, + 2000, + 3000, + 4000, + 5000, + 6000, + 7000, + 8000, + 9000, + 10000, + 20000, + 30000, + 40000, + 50000, + 100000, + 200000, + 300000, + 400000, + 500000, + 600000, + 700000, + 800000, + 900000, + 1000000, + 1500000, + 2000000 +}; + +#define IO_LAT_HIST_DISABLE 0 +#define IO_LAT_HIST_ENABLE 1 +#define IO_LAT_HIST_ZERO 2 +#define CHUNCK_SIZE_4K 8 +#define CHUNCK_SIZE_8K 16 +#define CHUNCK_SIZE_32K 64 +#define CHUNCK_SIZE_64K 128 +#define CHUNCK_SIZE_128K 256 +#define CHUNCK_SIZE_256K 512 + +struct io_latency_chunck_size { + u_int64_t chunk_0_count; + u_int64_t chunk_4k_count; + u_int64_t chunk_8k_count; + u_int64_t chunk_8_32k_count; + u_int64_t chunk_32_64k_count; + u_int64_t chunk_64_128k_count; + u_int64_t chunk_128_256k_count; + u_int64_t chunk_above_256k_count; + u_int64_t latency_axis; +}; + +struct io_latency_state { + struct io_latency_chunck_size latency_y_axis[ARRAY_SIZE(latency_x_axis_us) + 1]; + u_int64_t latency_elems; + u_int64_t latency_sum; +}; + +static inline void +io_update_latency_hist(struct io_latency_state *s, u_int64_t delta_us, unsigned int length) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(latency_x_axis_us); i++) + if (delta_us < (u_int64_t)latency_x_axis_us[i]) + break; + s->latency_y_axis[i].latency_axis++; + if(!length) { + s->latency_y_axis[i].chunk_0_count++; + } else if (length > CHUNCK_SIZE_256K) { + s->latency_y_axis[i].chunk_above_256k_count++; + } else if (length > CHUNCK_SIZE_128K) { + s->latency_y_axis[i].chunk_128_256k_count++; + } else if (length > CHUNCK_SIZE_64K) { + s->latency_y_axis[i].chunk_64_128k_count++; + } else if (length > CHUNCK_SIZE_32K) { + s->latency_y_axis[i].chunk_32_64k_count++; + } else if (length > CHUNCK_SIZE_8K) { + s->latency_y_axis[i].chunk_8_32k_count++; + } else if (length == CHUNCK_SIZE_8K) { + s->latency_y_axis[i].chunk_8k_count++; + } else if (length == CHUNCK_SIZE_4K) { + s->latency_y_axis[i].chunk_4k_count++; + } + s->latency_elems++; + s->latency_sum += delta_us; +} + +ssize_t io_latency_hist_show(char *name, struct io_latency_state *s, + char *buf, int buf_size); + +#endif /* _UFS_LATENCY_HIST_ */ diff --git a/drivers/scsi/ufs/ufs_signal_quality.c b/drivers/scsi/ufs/ufs_signal_quality.c new file mode 100644 index 000000000000..e67c0d665cb1 --- /dev/null +++ b/drivers/scsi/ufs/ufs_signal_quality.c @@ -0,0 +1,283 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2018-2020 Oplus. All rights reserved. + */ + +/**************************************************************** + ** File: - ufs_signal_quality.c + ** Description: record ufs error interrupt information + ** Version: 1.0 + ** Date : 2020-08-27 + ** + ** ----------------------Revision History: -------------------- + ** + ** jason.wu 2020-08-27 1.0 add this module + ****************************************************************/ +#include +#include "ufs_signal_quality.h" +#include "ufshci.h" + +static void recordTimeStamp( + struct signal_quality *record, + enum unipro_err_type type +) { + ktime_t cur_time = ktime_get(); + switch (type) { + case UNIPRO_ERR_PA: + case UNIPRO_ERR_DL: + case UNIPRO_ERR_NL: + case UNIPRO_ERR_TL: + case UNIPRO_ERR_DME: + if (STAMP_RECORD_MAX <= record->stamp_pos) { + return; + } + if (0 == record->stamp_pos) { + record->stamp[0] = cur_time; + } else if (cur_time > (record->stamp[record->stamp_pos - 1] + + STAMP_MIN_INTERVAL)) { + record->stamp[record->stamp_pos++] = cur_time; + } + return; + default: + return; + } +} + +void recordUniproErr( + struct unipro_signal_quality_ctrl *signalCtrl, + u32 reg, + enum unipro_err_type type +) { + unsigned long err_bits; + int ec; + struct signal_quality *rec = &signalCtrl->record; + recordTimeStamp(rec, type); + switch (type) { + case UNIPRO_ERR_FATAL: + if (DEVICE_FATAL_ERROR & reg) { + rec->ufs_device_err_cnt++; + } + if (CONTROLLER_FATAL_ERROR & reg) { + rec->ufs_host_err_cnt++; + } + if (SYSTEM_BUS_FATAL_ERROR & reg) { + rec->ufs_bus_err_cnt++; + } + if (CRYPTO_ENGINE_FATAL_ERROR & reg) { + rec->ufs_crypto_err_cnt++; + } + break; + case UNIPRO_ERR_LINK: + if (UIC_LINK_LOST & reg) { + rec->ufs_link_lost_cnt++; + } + break; + case UNIPRO_ERR_PA: + err_bits = reg & UIC_PHY_ADAPTER_LAYER_ERROR_CODE_MASK; + for_each_set_bit(ec, &err_bits, UNIPRO_PA_ERR_MAX) { + rec->unipro_PA_err_total_cnt++; + rec->unipro_PA_err_cnt[ec]++; + } + break; + case UNIPRO_ERR_DL: + err_bits = reg & UIC_DATA_LINK_LAYER_ERROR_CODE_MASK; + for_each_set_bit(ec, &err_bits, UNIPRO_DL_ERR_MAX) { + rec->unipro_DL_err_total_cnt++; + rec->unipro_DL_err_cnt[ec]++; + } + break; + case UNIPRO_ERR_NL: + err_bits = reg & UIC_NETWORK_LAYER_ERROR_CODE_MASK; + for_each_set_bit(ec, &err_bits, UNIPRO_NL_ERR_MAX) { + rec->unipro_NL_err_total_cnt++; + rec->unipro_NL_err_cnt[ec]++; + } + break; + case UNIPRO_ERR_TL: + err_bits = reg & UIC_TRANSPORT_LAYER_ERROR_CODE_MASK; + for_each_set_bit(ec, &err_bits, UNIPRO_TL_ERR_MAX) { + rec->unipro_TL_err_total_cnt++; + rec->unipro_TL_err_cnt[ec]++; + } + break; + case UNIPRO_ERR_DME: + err_bits = reg & UIC_DME_ERROR_CODE_MASK; + for_each_set_bit(ec, &err_bits, UNIPRO_DME_ERR_MAX) { + rec->unipro_DME_err_total_cnt++; + rec->unipro_DME_err_cnt[ec]++; + } + break; + default: + break; + } +} + +#define SEQ_EASY_PRINT(x) seq_printf(s, #x"\t%d\n", signalCtrl->record.x) +#define SEQ_PA_PRINT(x) \ + seq_printf(s, #x"\t%d\n", signalCtrl->record.unipro_PA_err_cnt[x]) +#define SEQ_DL_PRINT(x) \ + seq_printf(s, #x"\t%d\n", signalCtrl->record.unipro_DL_err_cnt[x]) +#define SEQ_NL_PRINT(x) \ + seq_printf(s, #x"\t%d\n", signalCtrl->record.unipro_NL_err_cnt[x]) +#define SEQ_TL_PRINT(x) \ + seq_printf(s, #x"\t%d\n", signalCtrl->record.unipro_TL_err_cnt[x]) +#define SEQ_DME_PRINT(x) \ + seq_printf(s, #x"\t%d\n", signalCtrl->record.unipro_DME_err_cnt[x]) +#define SEQ_STAMP_PRINT(x) \ + seq_printf(s, #x"\t%lld\n", signalCtrl->record.stamp[x]) +#define SEQ_U64_PRINT(x) seq_printf(s, #x"\t%lld\n", signalCtrl->record.x) + +static int record_read_func(struct seq_file *s, void *v) +{ + struct unipro_signal_quality_ctrl *signalCtrl = + (struct unipro_signal_quality_ctrl *)(s->private); + if (!signalCtrl) { + return -EINVAL; + } + SEQ_EASY_PRINT(ufs_device_err_cnt); + SEQ_EASY_PRINT(ufs_host_err_cnt); + SEQ_EASY_PRINT(ufs_bus_err_cnt); + SEQ_EASY_PRINT(ufs_crypto_err_cnt); + SEQ_EASY_PRINT(ufs_link_lost_cnt); + SEQ_EASY_PRINT(unipro_PA_err_total_cnt); + SEQ_PA_PRINT(UNIPRO_PA_LANE0_ERR_CNT); + SEQ_PA_PRINT(UNIPRO_PA_LANE1_ERR_CNT); + SEQ_PA_PRINT(UNIPRO_PA_LANE2_ERR_CNT); + SEQ_PA_PRINT(UNIPRO_PA_LANE3_ERR_CNT); + SEQ_PA_PRINT(UNIPRO_PA_LINE_RESET); + SEQ_EASY_PRINT(unipro_DL_err_total_cnt); + SEQ_DL_PRINT(UNIPRO_DL_NAC_RECEIVED); + SEQ_DL_PRINT(UNIPRO_DL_TCX_REPLAY_TIMER_EXPIRED); + SEQ_DL_PRINT(UNIPRO_DL_AFCX_REQUEST_TIMER_EXPIRED); + SEQ_DL_PRINT(UNIPRO_DL_FCX_PROTECTION_TIMER_EXPIRED); + SEQ_DL_PRINT(UNIPRO_DL_CRC_ERROR); + SEQ_DL_PRINT(UNIPRO_DL_RX_BUFFER_OVERFLOW); + SEQ_DL_PRINT(UNIPRO_DL_MAX_FRAME_LENGTH_EXCEEDED); + SEQ_DL_PRINT(UNIPRO_DL_WRONG_SEQUENCE_NUMBER); + SEQ_DL_PRINT(UNIPRO_DL_AFC_FRAME_SYNTAX_ERROR); + SEQ_DL_PRINT(UNIPRO_DL_NAC_FRAME_SYNTAX_ERROR); + SEQ_DL_PRINT(UNIPRO_DL_EOF_SYNTAX_ERROR); + SEQ_DL_PRINT(UNIPRO_DL_FRAME_SYNTAX_ERROR); + SEQ_DL_PRINT(UNIPRO_DL_BAD_CTRL_SYMBOL_TYPE); + SEQ_DL_PRINT(UNIPRO_DL_PA_INIT_ERROR); + SEQ_DL_PRINT(UNIPRO_DL_PA_ERROR_IND_RECEIVED); + SEQ_DL_PRINT(UNIPRO_DL_PA_INIT); + SEQ_EASY_PRINT(unipro_NL_err_total_cnt); + SEQ_NL_PRINT(UNIPRO_NL_UNSUPPORTED_HEADER_TYPE); + SEQ_NL_PRINT(UNIPRO_NL_BAD_DEVICEID_ENC); + SEQ_NL_PRINT(UNIPRO_NL_LHDR_TRAP_PACKET_DROPPING); + SEQ_EASY_PRINT(unipro_TL_err_total_cnt); + SEQ_TL_PRINT(UNIPRO_TL_UNSUPPORTED_HEADER_TYPE); + SEQ_TL_PRINT(UNIPRO_TL_UNKNOWN_CPORTID); + SEQ_TL_PRINT(UNIPRO_TL_NO_CONNECTION_RX); + SEQ_TL_PRINT(UNIPRO_TL_CONTROLLED_SEGMENT_DROPPING); + SEQ_TL_PRINT(UNIPRO_TL_BAD_TC); + SEQ_TL_PRINT(UNIPRO_TL_E2E_CREDIT_OVERFLOW); + SEQ_TL_PRINT(UNIPRO_TL_SAFETY_VALVE_DROPPING); + SEQ_EASY_PRINT(unipro_DME_err_total_cnt); + SEQ_DME_PRINT(UNIPRO_DME_GENERIC); + SEQ_DME_PRINT(UNIPRO_DME_TX_QOS); + SEQ_DME_PRINT(UNIPRO_DME_RX_QOS); + SEQ_DME_PRINT(UNIPRO_DME_PA_INIT_QOS); + SEQ_STAMP_PRINT(UNIPRO_0_STAMP); + SEQ_STAMP_PRINT(UNIPRO_1_STAMP); + SEQ_STAMP_PRINT(UNIPRO_2_STAMP); + SEQ_STAMP_PRINT(UNIPRO_3_STAMP); + SEQ_STAMP_PRINT(UNIPRO_4_STAMP); + SEQ_STAMP_PRINT(UNIPRO_5_STAMP); + SEQ_STAMP_PRINT(UNIPRO_6_STAMP); + SEQ_STAMP_PRINT(UNIPRO_7_STAMP); + SEQ_STAMP_PRINT(UNIPRO_8_STAMP); + SEQ_STAMP_PRINT(UNIPRO_9_STAMP); + SEQ_U64_PRINT(request_cnt); + return 0; +} + +static int record_open(struct inode *inode, struct file *file) +{ + return single_open(file, record_read_func, PDE_DATA(inode)); +} + +static const struct file_operations record_fops = { + .owner = THIS_MODULE, + .open = record_open, + .read = seq_read, + .release = single_release, +}; + +#define SEQ_UPLOAD_PRINT(x) \ + seq_printf(s, #x": %d\n", signalCtrl->record.x \ + -signalCtrl->record_upload.x);\ + signalCtrl->record_upload.x = signalCtrl->record.x; +#define SEQ_UPLOAD_STAMP_PRINT(x) \ + seq_printf(s, #x": %lld\n", signalCtrl->record.stamp[x] \ + -signalCtrl->record_upload.stamp[x]);\ + signalCtrl->record_upload.stamp[x] = signalCtrl->record.stamp[x]; +#define SEQ_UPLOAD_U64_PRINT(x) \ + seq_printf(s, #x": %lld\n", signalCtrl->record.x \ + -signalCtrl->record_upload.x);\ + signalCtrl->record_upload.x = signalCtrl->record.x; +static int record_upload_read_func(struct seq_file *s, void *v) +{ + struct unipro_signal_quality_ctrl *signalCtrl = + (struct unipro_signal_quality_ctrl *)(s->private); + if (!signalCtrl) { + return -EINVAL; + } + SEQ_UPLOAD_PRINT(ufs_device_err_cnt); + SEQ_UPLOAD_PRINT(ufs_host_err_cnt); + SEQ_UPLOAD_PRINT(ufs_bus_err_cnt); + SEQ_UPLOAD_PRINT(ufs_crypto_err_cnt); + SEQ_UPLOAD_PRINT(ufs_link_lost_cnt); + SEQ_UPLOAD_PRINT(unipro_PA_err_total_cnt); + SEQ_UPLOAD_PRINT(unipro_DL_err_total_cnt); + SEQ_UPLOAD_PRINT(unipro_NL_err_total_cnt); + SEQ_UPLOAD_PRINT(unipro_TL_err_total_cnt); + SEQ_UPLOAD_PRINT(unipro_DME_err_total_cnt); + SEQ_UPLOAD_STAMP_PRINT(UNIPRO_0_STAMP); + SEQ_UPLOAD_U64_PRINT(request_cnt); + return 0; +} + +static int record_upload_open(struct inode *inode, struct file *file) +{ + return single_open(file, record_upload_read_func, PDE_DATA(inode)); +} + +static const struct file_operations record_upload_fops = { + .owner = THIS_MODULE, + .open = record_upload_open, + .read = seq_read, + .release = single_release, +}; + +int create_signal_quality_proc(struct unipro_signal_quality_ctrl *signalCtrl) +{ + struct proc_dir_entry *d_entry; + signalCtrl->ctrl_dir = proc_mkdir("ufs_signalShow", NULL); + if (!signalCtrl->ctrl_dir) { + return -ENOMEM; + } + d_entry = proc_create_data("record", S_IRUGO, signalCtrl->ctrl_dir, + &record_fops, signalCtrl); + if (!d_entry) { + return -ENOMEM; + } + d_entry = proc_create_data("record_upload", S_IRUGO, signalCtrl->ctrl_dir, + &record_upload_fops, signalCtrl); + if (!d_entry) { + return -ENOMEM; + } + return 0; +} + +void remove_signal_quality_proc(struct unipro_signal_quality_ctrl *signalCtrl) +{ + if (signalCtrl->ctrl_dir) { + remove_proc_entry("record", signalCtrl->ctrl_dir); + remove_proc_entry("record_upload", signalCtrl->ctrl_dir); + } + return; +} + + diff --git a/drivers/scsi/ufs/ufs_signal_quality.h b/drivers/scsi/ufs/ufs_signal_quality.h new file mode 100644 index 000000000000..5ba63c0d774a --- /dev/null +++ b/drivers/scsi/ufs/ufs_signal_quality.h @@ -0,0 +1,146 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2018-2020 Oplus. All rights reserved. + */ + +/**************************************************************** + ** File: - ufs_signal_quality.h + ** Description: record ufs error interrupt information + ** Version: 1.0 + ** Date : 2020-08-27 + ** + ** ----------------------Revision History: -------------------- + ** + ** jason.wu 2020-08-27 1.0 add this module + ****************************************************************/ +#ifndef __UFS_SIGNAL_QUALITY_H__ +#define __UFS_SIGNAL_QUALITY_H__ + +#include +#include +#include +#include + +enum unipro_pa_errCode { + UNIPRO_PA_LANE0_ERR_CNT, + UNIPRO_PA_LANE1_ERR_CNT, + UNIPRO_PA_LANE2_ERR_CNT, + UNIPRO_PA_LANE3_ERR_CNT, + UNIPRO_PA_LINE_RESET, + UNIPRO_PA_ERR_MAX +}; + +enum unipro_dl_errCode { + UNIPRO_DL_NAC_RECEIVED, + UNIPRO_DL_TCX_REPLAY_TIMER_EXPIRED, + UNIPRO_DL_AFCX_REQUEST_TIMER_EXPIRED, + UNIPRO_DL_FCX_PROTECTION_TIMER_EXPIRED, + UNIPRO_DL_CRC_ERROR, + UNIPRO_DL_RX_BUFFER_OVERFLOW, + UNIPRO_DL_MAX_FRAME_LENGTH_EXCEEDED, + UNIPRO_DL_WRONG_SEQUENCE_NUMBER, + UNIPRO_DL_AFC_FRAME_SYNTAX_ERROR, + UNIPRO_DL_NAC_FRAME_SYNTAX_ERROR, + UNIPRO_DL_EOF_SYNTAX_ERROR, + UNIPRO_DL_FRAME_SYNTAX_ERROR, + UNIPRO_DL_BAD_CTRL_SYMBOL_TYPE, + UNIPRO_DL_PA_INIT_ERROR, + UNIPRO_DL_PA_ERROR_IND_RECEIVED, + UNIPRO_DL_PA_INIT, + UNIPRO_DL_ERR_MAX +}; + +enum unipro_nl_errCode { + UNIPRO_NL_UNSUPPORTED_HEADER_TYPE, + UNIPRO_NL_BAD_DEVICEID_ENC, + UNIPRO_NL_LHDR_TRAP_PACKET_DROPPING, + UNIPRO_NL_ERR_MAX +}; + +enum unipro_tl_errCode { + UNIPRO_TL_UNSUPPORTED_HEADER_TYPE, + UNIPRO_TL_UNKNOWN_CPORTID, + UNIPRO_TL_NO_CONNECTION_RX, + UNIPRO_TL_CONTROLLED_SEGMENT_DROPPING, + UNIPRO_TL_BAD_TC, + UNIPRO_TL_E2E_CREDIT_OVERFLOW, + UNIPRO_TL_SAFETY_VALVE_DROPPING, + UNIPRO_TL_ERR_MAX +}; + +enum unipro_dme_errCode { + UNIPRO_DME_GENERIC, + UNIPRO_DME_TX_QOS, + UNIPRO_DME_RX_QOS, + UNIPRO_DME_PA_INIT_QOS, + UNIPRO_DME_ERR_MAX +}; + +enum unipro_err_type { + UNIPRO_ERR_FATAL, + UNIPRO_ERR_LINK, + UNIPRO_ERR_PA, + UNIPRO_ERR_DL, + UNIPRO_ERR_NL, + UNIPRO_ERR_TL, + UNIPRO_ERR_DME +}; + +enum unipro_err_time_stamp { + UNIPRO_0_STAMP, + UNIPRO_1_STAMP, + UNIPRO_2_STAMP, + UNIPRO_3_STAMP, + UNIPRO_4_STAMP, + UNIPRO_5_STAMP, + UNIPRO_6_STAMP, + UNIPRO_7_STAMP, + UNIPRO_8_STAMP, + UNIPRO_9_STAMP, + STAMP_RECORD_MAX +}; +#define STAMP_MIN_INTERVAL ((ktime_t)600000000000) /*ns, 10min*/ + +struct signal_quality { + u32 ufs_device_err_cnt; + u32 ufs_host_err_cnt; + u32 ufs_bus_err_cnt; + u32 ufs_crypto_err_cnt; + u32 ufs_link_lost_cnt; + u32 unipro_PA_err_total_cnt; + u32 unipro_PA_err_cnt[UNIPRO_PA_ERR_MAX]; + u32 unipro_DL_err_total_cnt; + u32 unipro_DL_err_cnt[UNIPRO_DL_ERR_MAX]; + u32 unipro_NL_err_total_cnt; + u32 unipro_NL_err_cnt[UNIPRO_NL_ERR_MAX]; + u32 unipro_TL_err_total_cnt; + u32 unipro_TL_err_cnt[UNIPRO_TL_ERR_MAX]; + u32 unipro_DME_err_total_cnt; + u32 unipro_DME_err_cnt[UNIPRO_DME_ERR_MAX]; + u64 request_cnt; +/* first 10 error cnt, interval is 10min at least */ + ktime_t stamp[STAMP_RECORD_MAX]; + int stamp_pos; +}; + +struct unipro_signal_quality_ctrl { + struct proc_dir_entry *ctrl_dir; + struct signal_quality record; + struct signal_quality record_upload; +}; + +void recordUniproErr( + struct unipro_signal_quality_ctrl *signalCtrl, + u32 reg, + enum unipro_err_type type +); +static inline void recordRequestCnt(struct unipro_signal_quality_ctrl *signalCtrl) +{ + signalCtrl->record.request_cnt++; +} + +int create_signal_quality_proc(struct unipro_signal_quality_ctrl *signalCtrl); +void remove_signal_quality_proc(struct unipro_signal_quality_ctrl *signalCtrl); + +#endif /* __UFS_SIGNAL_QUALITY_H__ */ + diff --git a/drivers/scsi/ufs/ufsfeature.c b/drivers/scsi/ufs/ufsfeature.c new file mode 100644 index 000000000000..e0df258bda1b --- /dev/null +++ b/drivers/scsi/ufs/ufsfeature.c @@ -0,0 +1,855 @@ +/* + * Universal Flash Storage Feature Support + * + * Copyright (C) 2017-2018 Samsung Electronics Co., Ltd. + * Copyright (C) 2020 Oplus. All rights reserved. + * + * Authors: + * Yongmyung Lee + * Jinyoung Choi + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * See the COPYING file in the top-level directory or visit + * + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * This program is provided "AS IS" and "WITH ALL FAULTS" and + * without warranty of any kind. You are solely responsible for + * determining the appropriateness of using and distributing + * the program and assume all risks associated with your exercise + * of rights with respect to the program, including but not limited + * to infringement of third party rights, the risks and costs of + * program errors, damage to or loss of data, programs or equipment, + * and unavailability or interruption of operations. Under no + * circumstances will the contributor of this Program be liable for + * any damages of any kind arising from your use or distribution of + * this program. + * + * The Linux Foundation chooses to take subject only to the GPLv2 + * license terms, and distributes only under these terms. + */ + +#include + +#include "ufsfeature.h" +#include "ufshcd.h" +#include "ufs_quirks.h" + +#define QUERY_REQ_TIMEOUT 1500 /* msec */ + +struct ufsf_feature_para ufsf_para; + +static inline void ufsf_init_query(struct ufs_hba *hba, + struct ufs_query_req **request, + struct ufs_query_res **response, + enum query_opcode opcode, u8 idn, + u8 index, u8 selector) +{ + *request = &hba->dev_cmd.query.request; + *response = &hba->dev_cmd.query.response; + memset(*request, 0, sizeof(struct ufs_query_req)); + memset(*response, 0, sizeof(struct ufs_query_res)); + (*request)->upiu_req.opcode = opcode; + (*request)->upiu_req.idn = idn; + (*request)->upiu_req.index = index; + (*request)->upiu_req.selector = selector; +} + +/* + * ufs feature common functions. + */ +int ufsf_query_flag(struct ufs_hba *hba, enum query_opcode opcode, + enum flag_idn idn, u8 index, bool *flag_res) +{ + struct ufs_query_req *request = NULL; + struct ufs_query_res *response = NULL; + int err; + u8 selector = 0x1; + + BUG_ON(!hba); + + ufshcd_hold_all(hba); + mutex_lock(&hba->dev_cmd.lock); + + /*ERR_MSG("%s: hba->dev_info.w_manufacturer_id %x\n", __func__, hba->dev_info.w_manufacturer_id);*/ + switch (hba->dev_info.w_manufacturer_id) { + case UFS_VENDOR_SAMSUNG: + selector = 0x1; + break; + case UFS_VENDOR_TOSHIBA: + case UFS_VENDOR_SKHYNIX: + case UFS_VENDOR_WDC: + case UFS_VENDOR_MICRON: + selector = 0x0; + break; + default: + break; + } + /*ERR_MSG("%s:selector %x\n", __func__, selector);*/ + + /* + * Init the query response and request parameters + */ + ufsf_init_query(hba, &request, &response, opcode, idn, index, selector); + + switch (opcode) { + case UPIU_QUERY_OPCODE_SET_FLAG: + case UPIU_QUERY_OPCODE_CLEAR_FLAG: + case UPIU_QUERY_OPCODE_TOGGLE_FLAG: + request->query_func = UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST; + break; + case UPIU_QUERY_OPCODE_READ_FLAG: + request->query_func = UPIU_QUERY_FUNC_STANDARD_READ_REQUEST; + if (!flag_res) { + /* No dummy reads */ + dev_err(hba->dev, "%s: Invalid argument for read request\n", + __func__); + err = -EINVAL; + goto out_unlock; + } + break; + default: + dev_err(hba->dev, + "%s: Expected query flag opcode but got = %d\n", + __func__, opcode); + err = -EINVAL; + goto out_unlock; + } + + /* Send query request */ + err = ufshcd_exec_dev_cmd(hba, DEV_CMD_TYPE_QUERY, QUERY_REQ_TIMEOUT); + if (err) { + dev_err(hba->dev, + "%s: Sending flag query for idn %d failed, err = %d\n", + __func__, idn, err); + goto out_unlock; + } + + if (flag_res) + *flag_res = (be32_to_cpu(response->upiu_res.value) & + MASK_QUERY_UPIU_FLAG_LOC) & 0x1; + +out_unlock: + mutex_unlock(&hba->dev_cmd.lock); + ufshcd_release_all(hba); + return err; +} + +int ufsf_query_flag_retry(struct ufs_hba *hba, enum query_opcode opcode, + enum flag_idn idn, u8 idx, bool *flag_res) +{ + int ret; + int retries; + + BUG_ON(idx > 7); + + for (retries = 0; retries < UFSF_QUERY_REQ_RETRIES; retries++) { + ret = ufsf_query_flag(hba, opcode, idn, idx, flag_res); + if (ret) + dev_dbg(hba->dev, + "%s: failed with error %d, retries %d\n", + __func__, ret, retries); + else + break; + } + if (ret) + dev_err(hba->dev, + "%s: query flag, opcode %d, idn %d, failed with error %d after %d retires\n", + __func__, opcode, idn, ret, retries); + return ret; +} + +int ufsf_query_attr_retry(struct ufs_hba *hba, enum query_opcode opcode, + enum attr_idn idn, u8 idx, u32 *attr_val) +{ + int ret; + int retries; + u8 selector = 0x1; + + ERR_MSG("%s: hba->dev_info.w_manufacturer_id %x\n", __func__, hba->dev_info.w_manufacturer_id); + switch (hba->dev_info.w_manufacturer_id) { + case UFS_VENDOR_SAMSUNG: + selector = 0x1; + break; + case UFS_VENDOR_TOSHIBA: + case UFS_VENDOR_SKHYNIX: + case UFS_VENDOR_WDC: + case UFS_VENDOR_MICRON: + selector = 0x0; + break; + default: + break; + } + ERR_MSG("%s:selector %x\n", __func__, selector); + + for (retries = 0; retries < UFSF_QUERY_REQ_RETRIES; retries++) { + ret = ufshcd_query_attr(hba, opcode, idn, idx, + selector, attr_val); + if (ret) + dev_dbg(hba->dev, + "%s: failed with error %d, retries %d\n", + __func__, ret, retries); + else + break; + } + if (ret) + dev_err(hba->dev, + "%s: query attr, opcode %d, idn %d, failed with error %d after %d retires\n", + __func__, opcode, idn, ret, retries); + return ret; +} + +static int ufsf_read_desc(struct ufs_hba *hba, u8 desc_id, u8 desc_index, + u8 selector, u8 *desc_buf, u32 size) +{ + int err = 0; + + pm_runtime_get_sync(hba->dev); + + err = ufshcd_query_descriptor_retry(hba, UPIU_QUERY_OPCODE_READ_DESC, + desc_id, desc_index, + selector, + desc_buf, &size); + if (err) + ERR_MSG("reading Device Desc failed. err = %d", err); + + pm_runtime_put_sync(hba->dev); + + return err; +} + +static int ufsf_read_dev_desc(struct ufsf_feature *ufsf, u8 selector) +{ + u8 desc_buf[UFSF_QUERY_DESC_DEVICE_MAX_SIZE]; + int ret; + + ret = ufsf_read_desc(ufsf->hba, QUERY_DESC_IDN_DEVICE, 0, selector, + desc_buf, UFSF_QUERY_DESC_DEVICE_MAX_SIZE); + if (ret) + return ret; + + ufsf->num_lu = desc_buf[DEVICE_DESC_PARAM_NUM_LU]; + INFO_MSG("device lu count %d", ufsf->num_lu); + + INFO_MSG("sel=%u length=%u(0x%x) bSupport=0x%.2x, extend=0x%.2x_%.2x", + selector, desc_buf[DEVICE_DESC_PARAM_LEN], + desc_buf[DEVICE_DESC_PARAM_LEN], + desc_buf[DEVICE_DESC_PARAM_EXT_UFS_FEATURE_SUP], + desc_buf[DEVICE_DESC_PARAM_EXT_UFS_FEATURE_SUP+2], + desc_buf[DEVICE_DESC_PARAM_EXT_UFS_FEATURE_SUP+3]); + +#if defined(CONFIG_UFSHPB) + ufshpb_get_dev_info(ufsf, desc_buf); +#endif + +#if defined(CONFIG_UFSTW) + ufstw_get_dev_info(ufsf, desc_buf); +#endif + +#if defined(CONFIG_UFSHID) + ufshid_get_dev_info(ufsf, desc_buf); +#endif + return 0; +} + +static int ufsf_read_geo_desc(struct ufsf_feature *ufsf, u8 selector) +{ + u8 geo_buf[UFSF_QUERY_DESC_GEOMETRY_MAX_SIZE]; + int ret; + + ret = ufsf_read_desc(ufsf->hba, QUERY_DESC_IDN_GEOMETRY, 0, selector, + geo_buf, UFSF_QUERY_DESC_GEOMETRY_MAX_SIZE); + if (ret) + return ret; + +#if defined(CONFIG_UFSHPB) + if (ufshpb_get_state(ufsf) == HPB_NEED_INIT) + ufshpb_get_geo_info(ufsf, geo_buf); +#endif + +#if defined(CONFIG_UFSTW) + if (ufstw_get_state(ufsf) == TW_NEED_INIT) + ufstw_get_geo_info(ufsf, geo_buf); +#endif + return 0; +} + +static void ufsf_read_unit_desc(struct ufsf_feature *ufsf, int lun, u8 selector) +{ + u8 unit_buf[UFSF_QUERY_DESC_UNIT_MAX_SIZE]; + int lu_enable, ret = 0; + + ret = ufsf_read_desc(ufsf->hba, QUERY_DESC_IDN_UNIT, lun, selector, + unit_buf, UFSF_QUERY_DESC_UNIT_MAX_SIZE); + if (ret) { + ERR_MSG("read unit desc failed. ret (%d)", ret); + goto out; + } + + lu_enable = unit_buf[UNIT_DESC_PARAM_LU_ENABLE]; + if (!lu_enable) + return; + +#if defined(CONFIG_UFSHPB) + if (ufshpb_get_state(ufsf) == HPB_NEED_INIT) + ufshpb_get_lu_info(ufsf, lun, unit_buf); +#endif + +#if defined(CONFIG_UFSTW) + if (ufstw_get_state(ufsf) == TW_NEED_INIT) + ufstw_alloc_lu(ufsf, lun, unit_buf); +#endif +out: + return; +} + +void ufsf_device_check(struct ufs_hba *hba) +{ + struct ufsf_feature *ufsf = &hba->ufsf; + int ret, lun; + u8 selector = 0x1; + /*u32 status;*/ + + ufsf->hba = hba; + + /*ufshcd_query_attr(ufsf->hba, UPIU_QUERY_OPCODE_READ_ATTR, + QUERY_ATTR_IDN_SUP_VENDOR_OPTIONS, 0, 0, &status); + INIT_INFO("UFS FEATURE SELECTOR Dev %d - D/D %d", status, + UFSFEATURE_SELECTOR);*/ + + ERR_MSG("%s: hba->dev_info.w_manufacturer_id %x\n", __func__, hba->dev_info.w_manufacturer_id); + switch (hba->dev_info.w_manufacturer_id) { + case UFS_VENDOR_SAMSUNG: + selector = 0x1; + break; + case UFS_VENDOR_TOSHIBA: + case UFS_VENDOR_SKHYNIX: + case UFS_VENDOR_WDC: + case UFS_VENDOR_MICRON: + selector = 0x0; + break; + default: + break; + } + ERR_MSG("%s:selector %x\n", __func__, selector); + + ret = ufsf_read_dev_desc(ufsf, selector); + if (ret) + return; + + ret = ufsf_read_geo_desc(ufsf, selector); + if (ret) + return; + + seq_scan_lu(lun) + ufsf_read_unit_desc(ufsf, lun, selector); + + create_ufsplus_ctrl_proc(ufsf); +} + +static void ufsf_print_query_buf(unsigned char *field, int size) +{ + unsigned char buf[255]; + int count = 0; + int i; + + count += snprintf(buf, 8, "(0x00):"); + + for (i = 0; i < size; i++) { + count += snprintf(buf + count, 4, " %.2X", field[i]); + + if ((i + 1) % 16 == 0) { + buf[count] = '\n'; + buf[count + 1] = '\0'; + printk(buf); + count = 0; + count += snprintf(buf, 8, "(0x%.2X):", i + 1); + } else if ((i + 1) % 4 == 0) + count += snprintf(buf + count, 3, " :"); + } + buf[count] = '\n'; + buf[count + 1] = '\0'; + printk(buf); +} + +inline int ufsf_check_query(__u32 opcode) +{ + return (opcode & 0xffff0000) >> 16 == UFSFEATURE_QUERY_OPCODE; +} + +static inline void ufsf_set_read10_debug_cmd(unsigned char *cdb, int lba, + int len) +{ + cdb[0] = READ_10; + cdb[1] = 0x02; + cdb[2] = GET_BYTE_3(lba); + cdb[3] = GET_BYTE_2(lba); + cdb[4] = GET_BYTE_1(lba); + cdb[5] = GET_BYTE_0(lba); + cdb[6] = GET_BYTE_2(len); + cdb[7] = GET_BYTE_1(len); + cdb[8] = GET_BYTE_0(len); +} + +static int ufsf_execute_read10_debug(struct ufsf_feature *ufsf, int lun, + unsigned char *cdb, void *buf, int len) +{ + struct scsi_sense_hdr sshdr; + struct scsi_device *sdev; + int ret = 0; + + sdev = ufsf->sdev_ufs_lu[lun]; + if (!sdev) { + ERR_MSG("cannot find scsi_device"); + return -ENODEV; + } + + ret = ufsf_get_scsi_device(ufsf->hba, sdev); + if (ret) + return ret; + + ufsf->issue_read10_debug = true; + + ret = scsi_execute(sdev, cdb, DMA_FROM_DEVICE, buf, len, NULL, &sshdr, + msecs_to_jiffies(30000), 3, 0, 0, NULL); + + ufsf->issue_read10_debug = false; + + scsi_device_put(sdev); + + return ret; +} + +int ufsf_issue_read10_debug(struct ufsf_feature *ufsf, int lun, + unsigned char *buf, int buf_len) +{ + unsigned char cdb[10] = { 0 }; + int cmd_len = buf_len >> OS_PAGE_SHIFT; + int ret = 0; + + ufsf_set_read10_debug_cmd(cdb, READ10_DEBUG_LBA, cmd_len); + + ret = ufsf_execute_read10_debug(ufsf, lun, cdb, buf, buf_len); + + if (ret < 0) + ERR_MSG("failed with err %d", ret); + + return ret; +} + +int ufsf_query_ioctl(struct ufsf_feature *ufsf, int lun, void __user *buffer, + struct ufs_ioctl_query_data *ioctl_data, u8 selector) +{ + unsigned char *kernel_buf; + int opcode; + int err = 0; + int index = 0; + int length = 0; + int buf_len = 0; + + opcode = ioctl_data->opcode & 0xffff; + + INFO_MSG("op %u idn %u sel %u size %u(0x%X)", opcode, ioctl_data->idn, + selector, ioctl_data->buf_size, ioctl_data->buf_size); + + buf_len = (ioctl_data->idn == QUERY_DESC_IDN_STRING) ? + IOCTL_DEV_CTX_MAX_SIZE : QUERY_DESC_MAX_SIZE; + + kernel_buf = kzalloc(buf_len, GFP_KERNEL); + if (!kernel_buf) { + err = -ENOMEM; + goto out; + } + + switch (opcode) { + case UPIU_QUERY_OPCODE_WRITE_DESC: + err = copy_from_user(kernel_buf, buffer + + sizeof(struct ufs_ioctl_query_data), + ioctl_data->buf_size); + INFO_MSG("buf size %d", ioctl_data->buf_size); + ufsf_print_query_buf(kernel_buf, ioctl_data->buf_size); + if (err) + goto out_release_mem; + break; + + case UPIU_QUERY_OPCODE_READ_DESC: + switch (ioctl_data->idn) { + case QUERY_DESC_IDN_UNIT: + if (!ufs_is_valid_unit_desc_lun(lun)) { + ERR_MSG("No unit descriptor for lun 0x%x", lun); + err = -EINVAL; + goto out_release_mem; + } + index = lun; + INFO_MSG("read lu desc lun: %d", index); + break; + + case QUERY_DESC_IDN_STRING: + if (!ufs_is_valid_unit_desc_lun(lun)) { + ERR_MSG("No unit descriptor for lun 0x%x", lun); + err = -EINVAL; + goto out_release_mem; + } + err = ufsf_issue_read10_debug(ufsf, lun, kernel_buf, + ioctl_data->buf_size); + if (err < 0) + goto out_release_mem; + + goto copy_buffer; + case QUERY_DESC_IDN_DEVICE: + case QUERY_DESC_IDN_GEOMETRY: + case QUERY_DESC_IDN_CONFIGURATION: + break; + + default: + ERR_MSG("invalid idn %d", ioctl_data->idn); + err = -EINVAL; + goto out_release_mem; + } + break; + default: + ERR_MSG("invalid opcode %d", opcode); + err = -EINVAL; + goto out_release_mem; + } + + length = ioctl_data->buf_size; + + err = ufshcd_query_descriptor_retry(ufsf->hba, opcode, ioctl_data->idn, + index, selector, kernel_buf, + &length); + if (err) + goto out_release_mem; + +copy_buffer: + if (opcode == UPIU_QUERY_OPCODE_READ_DESC) { + err = copy_to_user(buffer, ioctl_data, + sizeof(struct ufs_ioctl_query_data)); + if (err) + ERR_MSG("Failed copying back to user."); + + err = copy_to_user(buffer + sizeof(struct ufs_ioctl_query_data), + kernel_buf, ioctl_data->buf_size); + if (err) + ERR_MSG("Fail: copy rsp_buffer to user space."); + } +out_release_mem: + kfree(kernel_buf); +out: + return err; +} + +inline int ufsf_get_scsi_device(struct ufs_hba *hba, struct scsi_device *sdev) +{ + unsigned long flags; + int ret; + + spin_lock_irqsave(hba->host->host_lock, flags); + ret = scsi_device_get(sdev); + if (!ret && !scsi_device_online(sdev)) { + spin_unlock_irqrestore(hba->host->host_lock, flags); + scsi_device_put(sdev); + ERR_MSG("scsi_device_get failed.(%d)", ret); + return -ENODEV; + } + spin_unlock_irqrestore(hba->host->host_lock, flags); + + return ret; +} + +inline bool ufsf_is_valid_lun(int lun) +{ + return lun < UFS_UPIU_MAX_GENERAL_LUN; +} + +inline void ufsf_slave_configure(struct ufsf_feature *ufsf, + struct scsi_device *sdev) +{ + if (ufsf_is_valid_lun(sdev->lun)) { + ufsf->sdev_ufs_lu[sdev->lun] = sdev; + ufsf->slave_conf_cnt++; + INFO_MSG("lun[%d] sdev(%p) q(%p) slave_conf_cnt(%d/%d)", + (int)sdev->lun, sdev, sdev->request_queue, + ufsf->slave_conf_cnt, ufsf->num_lu); + +#if defined(CONFIG_UFSHPB) + if (ufsf->num_lu == ufsf->slave_conf_cnt) { + if (ufshpb_get_state(ufsf) == HPB_NEED_INIT) { + INFO_MSG("wakeup ufshpb_init_handler"); + wake_up(&ufsf->hpb_wait); + } + } +#endif + } +} + +inline int ufsf_get_ee_status(struct ufs_hba *hba, u32 *status) +{ + return ufsf_query_attr_retry(hba, UPIU_QUERY_OPCODE_READ_ATTR, + QUERY_ATTR_IDN_EE_STATUS, 0, status); +} + +inline void ufsf_change_read10_debug_lun(struct ufsf_feature *ufsf, + struct ufshcd_lrb *lrbp) +{ + int ctx_lba = LI_EN_32(lrbp->cmd->cmnd + 2); + + if (ufsf->issue_read10_debug == true && ctx_lba == READ10_DEBUG_LBA) { + lrbp->lun = READ10_DEBUG_LUN; + INFO_MSG("lun 0x%X lba 0x%X", lrbp->lun, ctx_lba); + } +} + + +inline void ufsf_prep_fn(struct ufsf_feature *ufsf, + struct ufshcd_lrb *lrbp) +{ +#if defined(CONFIG_UFSHPB) + if (ufshpb_get_state(ufsf) == HPB_PRESENT && + ufsf->issue_read10_debug == false) + ufshpb_prep_fn(ufsf, lrbp); +#endif + +#if defined(CONFIG_UFSTW) + if (ufstw_get_state(ufsf) == TW_PRESENT) + ufstw_prep_fn(ufsf, lrbp); +#endif +} + +inline void ufsf_reset_lu(struct ufsf_feature *ufsf) +{ +#if defined(CONFIG_UFSTW) + INFO_MSG("run reset_lu.. tw_state(%d) -> TW_RESET", + ufstw_get_state(ufsf)); + ufstw_set_state(ufsf, TW_RESET); + ufstw_reset(ufsf, false); +#endif +} + +inline void ufsf_reset_host(struct ufsf_feature *ufsf) +{ +#if defined(CONFIG_UFSHPB) + INFO_MSG("run reset_host.. hpb_state(%d) -> HPB_RESET", + ufshpb_get_state(ufsf)); + if (ufshpb_get_state(ufsf) == HPB_PRESENT) + ufshpb_reset_host(ufsf); +#endif + +#if defined(CONFIG_UFSTW) + INFO_MSG("run reset_host.. tw_state(%d) -> TW_RESET", + ufstw_get_state(ufsf)); + if (ufstw_get_state(ufsf) == TW_PRESENT) + ufstw_reset_host(ufsf); +#endif +#if defined(CONFIG_UFSHID) + INFO_MSG("run reset_host.. hid_state(%d) -> HID_RESET", + ufshid_get_state(ufsf)); + if (ufshid_get_state(ufsf) == HID_PRESENT) + ufshid_reset_host(ufsf); +#endif +} + +inline void ufsf_init(struct ufsf_feature *ufsf) +{ +#if defined(CONFIG_UFSHPB) + if (ufshpb_get_state(ufsf) == HPB_NEED_INIT) { + INFO_MSG("init start.. hpb_state (%d)", HPB_NEED_INIT); + schedule_work(&ufsf->hpb_init_work); + } +#endif + +#if defined(CONFIG_UFSTW) + if (ufstw_get_state(ufsf) == TW_NEED_INIT) + ufstw_init(ufsf); +#endif +#if defined(CONFIG_UFSHID) + if (ufshid_get_state(ufsf) == HID_NEED_INIT) + ufshid_init(ufsf); +#endif +} + +inline void ufsf_reset(struct ufsf_feature *ufsf) +{ +#if defined(CONFIG_UFSHPB) + if (ufshpb_get_state(ufsf) == HPB_RESET) { + INFO_MSG("reset start.. hpb_state %d", HPB_RESET); + ufshpb_reset(ufsf); + } +#endif + +#if defined(CONFIG_UFSTW) + if (ufstw_get_state(ufsf) == TW_RESET && + !ufsf->hba->pm_op_in_progress) { + INFO_MSG("reset start.. tw_state %d", + ufstw_get_state(ufsf)); + ufstw_reset(ufsf, false); + } +#endif +#if defined(CONFIG_UFSHID) + if (ufshid_get_state(ufsf) == HID_RESET) + ufshid_reset(ufsf); +#endif +} + +inline void ufsf_remove(struct ufsf_feature *ufsf) +{ +#if defined(CONFIG_UFSHPB) + if (ufshpb_get_state(ufsf) == HPB_PRESENT) + ufshpb_remove(ufsf, HPB_NEED_INIT); +#endif + +#if defined(CONFIG_UFSTW) + if (ufstw_get_state(ufsf) == TW_PRESENT) + ufstw_remove(ufsf); +#endif +#if defined(CONFIG_UFSHID) + if (ufshid_get_state(ufsf) == HID_PRESENT) + ufshid_remove(ufsf); +#endif +} + +inline void ufsf_set_init_state(struct ufsf_feature *ufsf) +{ + ufsf->slave_conf_cnt = 0; + ufsf->issue_read10_debug = false; +#if defined(CONFIG_UFSHPB) + ufshpb_set_state(ufsf, HPB_NEED_INIT); + INIT_WORK(&ufsf->hpb_init_work, ufshpb_init_handler); + init_waitqueue_head(&ufsf->hpb_wait); +#endif +#if defined(CONFIG_UFSW) + ufstw_set_state(ufsf, TW_NEED_INIT); +#endif +#if defined(CONFIG_UFSHID) + ufshid_set_state(ufsf, HID_NEED_INIT); +#endif +} + +inline void ufsf_resume(struct ufsf_feature *ufsf) +{ +#if defined(CONFIG_UFSHPB) + if (ufshpb_get_state(ufsf) == HPB_SUSPEND || + ufshpb_get_state(ufsf) == HPB_PRESENT) { + if (ufshpb_get_state(ufsf) == HPB_PRESENT) + WARN_MSG("warning.. hpb state PRESENT in resuming"); + ufshpb_resume(ufsf); + } +#endif + +#if defined(CONFIG_UFSTW) + if (ufstw_get_state(ufsf) == HPB_RESET) + ufstw_reset(ufsf, true); +#endif +} + +inline void ufsf_on_idle(struct ufsf_feature *ufsf, bool scsi_req) +{ +#if defined(CONFIG_UFSHID) + if (ufshid_get_state(ufsf) == HID_PRESENT && + !ufsf->hba->outstanding_reqs && scsi_req) + ufshid_on_idle(ufsf); +#endif +} + +/* + * Wrapper functions for ufshpb. + */ +#if defined(CONFIG_UFSHPB) +inline int ufsf_hpb_prepare_pre_req(struct ufsf_feature *ufsf, + struct scsi_cmnd *cmd, int lun) +{ + if (ufshpb_get_state(ufsf) == HPB_PRESENT) + return ufshpb_prepare_pre_req(ufsf, cmd, lun); + return -ENODEV; +} + +inline int ufsf_hpb_prepare_add_lrbp(struct ufsf_feature *ufsf, int add_tag) +{ + if (ufshpb_get_state(ufsf) == HPB_PRESENT) + return ufshpb_prepare_add_lrbp(ufsf, add_tag); + return -ENODEV; +} + +inline void ufsf_hpb_end_pre_req(struct ufsf_feature *ufsf, + struct request *req) +{ + ufshpb_end_pre_req(ufsf, req); +} + +inline void ufsf_hpb_noti_rb(struct ufsf_feature *ufsf, struct ufshcd_lrb *lrbp) +{ + if (ufshpb_get_state(ufsf) == HPB_PRESENT) + ufshpb_rsp_upiu(ufsf, lrbp); +} + +inline void ufsf_hpb_suspend(struct ufsf_feature *ufsf) +{ + /* + * if suspend failed, pm could call the suspend function again, + * in this case, ufshpb state already had been changed to SUSPEND state. + * so, we will not call ufshpb_suspend. + */ + if (ufshpb_get_state(ufsf) == HPB_PRESENT) + ufshpb_suspend(ufsf); +} +#else +inline int ufsf_hpb_prepare_pre_req(struct ufsf_feature *ufsf, + struct scsi_cmnd *cmd, int lun) +{ + return 0; +} + +inline int ufsf_hpb_prepare_add_lrbp(struct ufsf_feature *ufsf, int add_tag) +{ + return 0; +} + +inline void ufsf_hpb_end_pre_req(struct ufsf_feature *ufsf, + struct request *req) {} +inline void ufsf_hpb_noti_rb(struct ufsf_feature *ufsf, + struct ufshcd_lrb *lrbp) {} +inline void ufsf_hpb_suspend(struct ufsf_feature *ufsf) {} +#endif + +#if defined(CONFIG_UFSTW) +inline void ufsf_tw_enable(struct ufsf_feature *ufsf, bool enable) +{ + if (atomic_read(&ufsf->tw_state) == TW_PRESENT) { + ufstw_enable_tw(ufsf, enable); + } else { + INFO_MSG("tw_state != TW_PRESENT (%d)\n", atomic_read(&ufsf->tw_state)); + } +} +#else +inline void ufsf_tw_enable(struct ufsf_feature *ufsf, bool enable) {} +#endif +int create_ufsplus_ctrl_proc(struct ufsf_feature *ufsf) +{ + ufsf_para.ctrl_dir = NULL; + ufsf_para.ufsf = NULL; + + ufsf_para.ctrl_dir = proc_mkdir("ufsplus_ctrl", NULL); + if (!ufsf_para.ctrl_dir) + return -ENOMEM; + ufsf_para.ufsf = ufsf; + + return 0; +} + +void remove_ufsplus_ctrl_proc(void) +{ + if (ufsf_para.ctrl_dir) { + remove_proc_entry("ufsplus_ctrl", NULL); + ufsf_para.ctrl_dir = NULL; + ufsf_para.ufsf = NULL; + } + + return; +} diff --git a/drivers/scsi/ufs/ufsfeature.h b/drivers/scsi/ufs/ufsfeature.h new file mode 100644 index 000000000000..02d52cbaa2a0 --- /dev/null +++ b/drivers/scsi/ufs/ufsfeature.h @@ -0,0 +1,252 @@ +/* + * Universal Flash Storage Feature Support + * + * Copyright (C) 2017-2018 Samsung Electronics Co., Ltd. + * Copyright (C) 2020 Oplus. All rights reserved. + * + * Authors: + * Yongmyung Lee + * Jinyoung Choi + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * See the COPYING file in the top-level directory or visit + * + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * This program is provided "AS IS" and "WITH ALL FAULTS" and + * without warranty of any kind. You are solely responsible for + * determining the appropriateness of using and distributing + * the program and assume all risks associated with your exercise + * of rights with respect to the program, including but not limited + * to infringement of third party rights, the risks and costs of + * program errors, damage to or loss of data, programs or equipment, + * and unavailability or interruption of operations. Under no + * circumstances will the contributor of this Program be liable for + * any damages of any kind arising from your use or distribution of + * this program. + * + * The Linux Foundation chooses to take subject only to the GPLv2 + * license terms, and distributes only under these terms. + */ + +#ifndef _UFSFEATURE_H_ +#define _UFSFEATURE_H_ + +#include +#include +#include + +#include "ufs.h" + +#include "ufshpb.h" +#include "ufstw.h" +#include +#include "ufshid.h" + +/* Constant value*/ +#define SECTOR 512 +#define BLOCK 4096 +#define SECTORS_PER_BLOCK (BLOCK / SECTOR) +#define BITS_PER_DWORD 32 +#define sects_per_blk_shift 3 +#define bits_per_dword_shift 5 +#define bits_per_dword_mask 0x1F +#define bits_per_byte_shift 3 + +#define IOCTL_DEV_CTX_MAX_SIZE OS_PAGE_SIZE +#define OS_PAGE_SIZE 4096 +#define OS_PAGE_SHIFT 12 + +#define UFSF_QUERY_REQ_RETRIES 1 + +/* Description */ +#define UFSF_QUERY_DESC_DEVICE_MAX_SIZE 0x5F +#define UFSF_QUERY_DESC_CONFIGURAION_MAX_SIZE 0xE6 +#define UFSF_QUERY_DESC_UNIT_MAX_SIZE 0x2D +#define UFSF_QUERY_DESC_GEOMETRY_MAX_SIZE 0x59 + +#define UFSFEATURE_SELECTOR_SAMSUNG 0x01 +#define UFSFEATURE_SELECTOR_SKHYNIX 0x0 +#define UFSFEATURE_SELECTOR_MICRON 0x0 +#define UFSFEATURE_SELECTOR_TOSHIBA 0x0 + +/* query_flag */ +#define MASK_QUERY_UPIU_FLAG_LOC 0xFF + +/* For read10 debug */ +#define READ10_DEBUG_LUN 0x7F +#define READ10_DEBUG_LBA 0x48504230 + +/* BIG -> LI */ +#define LI_EN_16(x) be16_to_cpu(*(__be16 *)(x)) +#define LI_EN_32(x) be32_to_cpu(*(__be32 *)(x)) +#define LI_EN_64(x) be64_to_cpu(*(__be64 *)(x)) + +/* LI -> BIG */ +#define GET_BYTE_0(num) (((num) >> 0) & 0xff) +#define GET_BYTE_1(num) (((num) >> 8) & 0xff) +#define GET_BYTE_2(num) (((num) >> 16) & 0xff) +#define GET_BYTE_3(num) (((num) >> 24) & 0xff) +#define GET_BYTE_4(num) (((num) >> 32) & 0xff) +#define GET_BYTE_5(num) (((num) >> 40) & 0xff) +#define GET_BYTE_6(num) (((num) >> 48) & 0xff) +#define GET_BYTE_7(num) (((num) >> 56) & 0xff) + +#define INFO_MSG(msg, args...) pr_info("%s:%d info: " msg "\n", \ + __func__, __LINE__, ##args) +#define ERR_MSG(msg, args...) pr_err("%s:%d err: " msg "\n", \ + __func__, __LINE__, ##args) +#define WARN_MSG(msg, args...) pr_warn("%s:%d warn: " msg "\n", \ + __func__, __LINE__, ##args) + +#define seq_scan_lu(lun) for (lun = 0; lun < UFS_UPIU_MAX_GENERAL_LUN; lun = lun + 1) + +#define TMSG(ufsf, lun, msg, args...) \ + do { if (ufsf->sdev_ufs_lu[lun] && \ + ufsf->sdev_ufs_lu[lun]->request_queue) \ + blk_add_trace_msg(ufsf->sdev_ufs_lu[lun]->request_queue, \ + msg, ##args); \ + } while (0) \ + +struct ufsf_lu_desc { + /* Common info */ + int lu_enable; /* 03h bLUEnable */ + int lu_queue_depth; /* 06h lu queue depth info*/ + int lu_logblk_size; /* 0Ah bLogicalBlockSize. default 0x0C = 4KB */ + u64 lu_logblk_cnt; /* 0Bh qLogicalBlockCount. */ + +#if defined(CONFIG_UFSHPB) + u16 lu_max_active_hpb_rgns; /* 23h:24h wLUMaxActiveHPBRegions */ + u16 lu_hpb_pinned_rgn_startidx; /* 25h:26h wHPBPinnedRegionStartIdx */ + u16 lu_num_hpb_pinned_rgns; /* 27h:28h wNumHPBPinnedRegions */ + int lu_hpb_pinned_end_offset; +#endif +#if defined(CONFIG_UFSTW) + unsigned int tw_lu_buf_size; +#endif +}; + +struct ufsf_feature { + struct ufs_hba *hba; + int num_lu; + int slave_conf_cnt; + struct scsi_device *sdev_ufs_lu[UFS_UPIU_MAX_GENERAL_LUN]; + bool issue_read10_debug; + +#if defined(CONFIG_UFSHPB) + struct ufshpb_dev_info hpb_dev_info; + struct ufshpb_lu *hpb_lup[UFS_UPIU_MAX_GENERAL_LUN]; + struct work_struct hpb_init_work; + struct work_struct hpb_eh_work; + wait_queue_head_t hpb_wait; + atomic_t hpb_state; + struct kref hpb_kref; +#endif +#if defined(CONFIG_UFSTW) + struct ufstw_dev_info tw_dev_info; + struct ufstw_lu *tw_lup[UFS_UPIU_MAX_GENERAL_LUN]; + atomic_t tw_state; +#endif +#if defined(CONFIG_UFSHID) + atomic_t hid_state; + struct ufshid_dev *hid_dev; +#endif +}; + +struct ufsf_feature_para { +#if defined(CONFIG_UFSHPB) + u64 hit; + u64 miss; + u64 hit_4k; + u64 hit_8_32k; + u64 span; + u64 span_hit; + u64 noti; + u64 noti_act; + u64 noti_inact; + u64 rgn_act; + u64 map_req; + u64 pre_req; + u16 hpb_rgns; +#endif + +#if defined(CONFIG_UFSTW) + u64 tw_state_ts; + u64 tw_enable_ms; + u64 tw_disable_ms; + u64 tw_write_secs; + u64 total_write_secs; + u64 tw_enable_count; + u64 tw_disable_count; + u64 tw_setflag_error_count; + bool tw_info_disable; + u32 tw_lifetime; + bool tw_enable; + unsigned int buffer_size; +#endif + u64 hibern8_amount_ms; + u64 hibern8_enter_count; + u64 hibern8_amount_ms_100ms; + u64 hibern8_enter_count_100ms; + u64 hibern8_max_ms; + ktime_t hibern8_enter_ts; + struct timespec timestamp; + + struct proc_dir_entry *ctrl_dir; + struct ufsf_feature *ufsf; +}; + +struct ufs_hba; +struct ufshcd_lrb; + +void ufsf_device_check(struct ufs_hba *hba); +int ufsf_check_query(__u32 opcode); +int ufsf_query_ioctl(struct ufsf_feature *ufsf, int lun, void __user *buffer, + struct ufs_ioctl_query_data *ioctl_data, + u8 selector); +int ufsf_query_flag_retry(struct ufs_hba *hba, enum query_opcode opcode, + enum flag_idn idn, u8 idx, bool *flag_res); +int ufsf_query_attr_retry(struct ufs_hba *hba, enum query_opcode opcode, + enum attr_idn idn, u8 idx, u32 *attr_val); +int ufsf_get_scsi_device(struct ufs_hba *hba, struct scsi_device *sdev); +bool ufsf_is_valid_lun(int lun); +void ufsf_slave_configure(struct ufsf_feature *ufsf, struct scsi_device *sdev); +int ufsf_get_ee_status(struct ufs_hba *hba, u32 *status); + +void ufsf_change_read10_debug_lun(struct ufsf_feature *ufsf, + struct ufshcd_lrb *lrbp); +void ufsf_prep_fn(struct ufsf_feature *ufsf, struct ufshcd_lrb *lrbp); +void ufsf_reset_lu(struct ufsf_feature *ufsf); +void ufsf_reset_host(struct ufsf_feature *ufsf); +void ufsf_init(struct ufsf_feature *ufsf); +void ufsf_reset(struct ufsf_feature *ufsf); +void ufsf_remove(struct ufsf_feature *ufsf); +void ufsf_set_init_state(struct ufsf_feature *ufsf); +void ufsf_resume(struct ufsf_feature *ufsf); +void ufsf_on_idle(struct ufsf_feature *ufsf, bool scsi_req); + +/* for hpb */ +int ufsf_hpb_prepare_pre_req(struct ufsf_feature *ufsf, struct scsi_cmnd *cmd, + int lun); +int ufsf_hpb_prepare_add_lrbp(struct ufsf_feature *ufsf, int add_tag); +void ufsf_hpb_end_pre_req(struct ufsf_feature *ufsf, struct request *req); +void ufsf_hpb_noti_rb(struct ufsf_feature *ufsf, struct ufshcd_lrb *lrbp); +void ufsf_hpb_suspend(struct ufsf_feature *ufsf); +void ufsf_hpb_release(struct ufsf_feature *ufsf); + +/*for tw*/ +void ufsf_tw_enable(struct ufsf_feature *ufsf, bool enable); + +extern struct ufsf_feature_para ufsf_para; + +int create_ufsplus_ctrl_proc(struct ufsf_feature *ufsf); +void remove_ufsplus_ctrl_proc(void); + +#endif /* End of Header */ diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index b1b3eb1bd60b..a7b4cf836f0c 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -58,6 +58,18 @@ static int ufshcd_wb_buf_flush_disable(struct ufs_hba *hba); static bool ufshcd_wb_is_buf_flush_needed(struct ufs_hba *hba); static int ufshcd_wb_toggle_flush_during_h8(struct ufs_hba *hba, bool set); +#ifdef OPLUS_FEATURE_UFSPLUS +/* Add TAG for UFS plus */ +#if defined(CONFIG_UFSFEATURE) +int ufsplus_hpb_status = 0; +EXPORT_SYMBOL(ufsplus_hpb_status); +#endif +#if defined(CONFIG_UFSFEATURE) && defined(CONFIG_UFSTW) +int ufsplus_tw_status = 0; +EXPORT_SYMBOL(ufsplus_tw_status); +#endif +#endif + #ifdef CONFIG_DEBUG_FS static int ufshcd_tag_req_type(struct request *rq) @@ -485,8 +497,6 @@ static int ufshcd_disable_clocks(struct ufs_hba *hba, bool is_gating_context); static int ufshcd_disable_clocks_keep_link_active(struct ufs_hba *hba, bool is_gating_context); -static void ufshcd_hold_all(struct ufs_hba *hba); -static void ufshcd_release_all(struct ufs_hba *hba); static int ufshcd_set_vccq_rail_unused(struct ufs_hba *hba, bool unused); static inline void ufshcd_add_delay_before_dme_cmd(struct ufs_hba *hba); static inline void ufshcd_save_tstamp_of_last_dme_cmd(struct ufs_hba *hba); @@ -494,8 +504,19 @@ static int ufshcd_host_reset_and_restore(struct ufs_hba *hba); static void ufshcd_resume_clkscaling(struct ufs_hba *hba); static void ufshcd_suspend_clkscaling(struct ufs_hba *hba); static void __ufshcd_suspend_clkscaling(struct ufs_hba *hba); +#ifdef OPLUS_FEATURE_UFSPLUS +/* Add TAG for UFS plus */ +#if defined(CONFIG_UFSFEATURE) +void ufshcd_hold_all(struct ufs_hba *hba); +void ufshcd_release_all(struct ufs_hba *hba); +#else static void ufshcd_hold_all(struct ufs_hba *hba); static void ufshcd_release_all(struct ufs_hba *hba); +#endif +#else +static void ufshcd_hold_all(struct ufs_hba *hba); +static void ufshcd_release_all(struct ufs_hba *hba); +#endif static void ufshcd_hba_vreg_set_lpm(struct ufs_hba *hba); static void ufshcd_hba_vreg_set_hpm(struct ufs_hba *hba); static int ufshcd_devfreq_target(struct device *dev, @@ -1747,7 +1768,17 @@ out: static int ufshcd_clock_scaling_prepare(struct ufs_hba *hba) { +#ifdef OPLUS_FEATURE_UFSPLUS +/* Add TAG for UFS plus */ +#if defined(CONFIG_UFSFEATURE) + #define DOORBELL_CLR_TOUT_US (1500 * 1000) /* 1.5 sec */ +#else #define DOORBELL_CLR_TOUT_US (1000 * 1000) /* 1 sec */ +#endif +#else + #define DOORBELL_CLR_TOUT_US (1000 * 1000) /* 1 sec */ +#endif + int ret = 0; /* * make sure that there are no outstanding requests when @@ -1846,6 +1877,11 @@ static int ufshcd_devfreq_scale(struct ufs_hba *hba, bool scale_up) /* Enable Write Booster if we have scaled up else disable it */ up_write(&hba->lock); ufshcd_wb_ctrl(hba, scale_up); +#if defined(OPLUS_FEATURE_UFSPLUS) +#if defined(CONFIG_UFSTW) + ufsf_tw_enable(&hba->ufsf, scale_up); +#endif +#endif down_write(&hba->lock); goto clk_scaling_unprepare; @@ -2142,6 +2178,87 @@ out: return count; } +#ifdef OPLUS_FEATURE_MIDAS +/* Add t for ufs transmission_status for midas */ +static ssize_t ufshcd_transmission_status_data_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ufs_hba *hba = dev_get_drvdata(dev); + + return snprintf(buf, PAGE_SIZE, + "transmission_status_enable:%u\n" + "gear_min_write_sec:%llu\n" + "gear_max_write_sec:%llu\n" + "gear_min_read_sec:%llu\n" + "gear_max_read_sec:%llu\n" + "gear_min_write_us:%llu\n" + "gear_max_write_us:%llu\n" + "gear_min_read_us:%llu\n" + "gear_max_read_us:%llu\n" + "gear_min_dev_us:%llu\n" + "gear_max_dev_us:%llu\n" + "gear_min_other_sec:%llu\n" + "gear_max_other_sec:%llu\n" + "gear_min_other_us:%llu\n" + "gear_max_other_us:%llu\n" + "scsi_send_count:%llu\n" + "dev_cmd_count:%llu\n", + hba->ufs_transmission_status.transmission_status_enable, + hba->ufs_transmission_status.gear_min_write_sec, + hba->ufs_transmission_status.gear_max_write_sec, + hba->ufs_transmission_status.gear_min_read_sec, + hba->ufs_transmission_status.gear_max_read_sec, + hba->ufs_transmission_status.gear_min_write_us, + hba->ufs_transmission_status.gear_max_write_us, + hba->ufs_transmission_status.gear_min_read_us, + hba->ufs_transmission_status.gear_max_read_us, + hba->ufs_transmission_status.gear_min_dev_us, + hba->ufs_transmission_status.gear_max_dev_us, + hba->ufs_transmission_status.gear_min_other_sec, + hba->ufs_transmission_status.gear_max_other_sec, + hba->ufs_transmission_status.gear_min_other_us, + hba->ufs_transmission_status.gear_max_other_us, + hba->ufs_transmission_status.scsi_send_count, + hba->ufs_transmission_status.dev_cmd_count); +} + +static ssize_t ufshcd_transmission_status_data_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct ufs_hba *hba = dev_get_drvdata(dev); + u32 value; + + if (kstrtou32(buf, 0, &value)) + return -EINVAL; + + value = !!value; + + if (value) { + hba->ufs_transmission_status.transmission_status_enable = 1; + } else { + hba->ufs_transmission_status.transmission_status_enable = 0; + memset(&hba->ufs_transmission_status, 0, sizeof(struct ufs_transmission_status_t)); + } + + return count; +} + +static void ufshcd_transmission_status_init_sysfs(struct ufs_hba *hba) +{ + hba->ufs_transmission_status_attr.show = ufshcd_transmission_status_data_show; + hba->ufs_transmission_status_attr.store = ufshcd_transmission_status_data_store; + sysfs_attr_init(&hba->ufs_transmission_status_attr.attr); + hba->ufs_transmission_status_attr.attr.name = "ufs_transmission_status"; + hba->ufs_transmission_status_attr.attr.mode = 0644; + if (device_create_file(hba->dev, &hba->ufs_transmission_status_attr)) + dev_err(hba->dev, "Failed to create sysfs for ufs_transmission_status_attr\n"); + + /*init the struct ufs_transmission_status*/ + memset(&hba->ufs_transmission_status, 0, sizeof(struct ufs_transmission_status_t)); + hba->ufs_transmission_status.transmission_status_enable = 1; +} +#endif /*OPLUS_FEATURE_MIDAS*/ + static void ufshcd_clkscaling_init_sysfs(struct ufs_hba *hba) { hba->clk_scaling.enable_attr.show = ufshcd_clkscale_enable_show; @@ -2675,7 +2792,16 @@ static void ufshcd_exit_clk_gating(struct ufs_hba *hba) * * Return 0 on success, non-zero on failure. */ +#ifdef OPLUS_FEATURE_UFSPLUS +/* Add TAG for UFS plus */ +#if defined(CONFIG_UFSFEATURE) +int ufshcd_hibern8_hold(struct ufs_hba *hba, bool async) +#else static int ufshcd_hibern8_hold(struct ufs_hba *hba, bool async) +#endif +#else +static int ufshcd_hibern8_hold(struct ufs_hba *hba, bool async) +#endif { int rc = 0; unsigned long flags; @@ -2998,7 +3124,6 @@ static void ufshcd_init_hibern8(struct ufs_hba *hba) h8->enable_attr.attr.mode = 0644; if (device_create_file(hba->dev, &h8->enable_attr)) dev_err(hba->dev, "Failed to create sysfs for hibern8_on_idle_enable\n"); - } } @@ -3011,13 +3136,31 @@ static void ufshcd_exit_hibern8_on_idle(struct ufs_hba *hba) device_remove_file(hba->dev, &hba->hibern8_on_idle.enable_attr); } +#ifdef OPLUS_FEATURE_UFSPLUS +/* Add TAG for UFS plus */ +#if defined (CONFIG_UFSFEATURE) +void ufshcd_hold_all(struct ufs_hba *hba) +#else static void ufshcd_hold_all(struct ufs_hba *hba) +#endif +#else +static void ufshcd_hold_all(struct ufs_hba *hba) +#endif { ufshcd_hold(hba, false); ufshcd_hibern8_hold(hba, false); } +#ifdef OPLUS_FEATURE_UFSPLUS +/* Add TAG for UFS plus */ +#if defined (CONFIG_UFSFEATURE) +void ufshcd_release_all(struct ufs_hba *hba) +#else static void ufshcd_release_all(struct ufs_hba *hba) +#endif +#else +static void ufshcd_release_all(struct ufs_hba *hba) +#endif { ufshcd_hibern8_release(hba, false); ufshcd_release(hba, false); @@ -3081,10 +3224,24 @@ int ufshcd_send_command(struct ufs_hba *hba, unsigned int task_tag) hba->lrb[task_tag].cmd ? "scsi_send" : "dev_cmd_send"); ufshcd_clk_scaling_start_busy(hba); __set_bit(task_tag, &hba->outstanding_reqs); +#ifdef OPLUS_FEATURE_PADL_STATISTICS +/* add request count information*/ + recordRequestCnt(&hba->signalCtrl); +#endif ufshcd_writel(hba, 1 << task_tag, REG_UTP_TRANSFER_REQ_DOOR_BELL); /* Make sure that doorbell is committed immediately */ wmb(); ufshcd_update_tag_stats(hba, task_tag); +#ifdef OPLUS_FEATURE_MIDAS +/* Add t for ufs transmission_status for midas */ + if (hba->ufs_transmission_status.transmission_status_enable) { + if(hba->lrb[task_tag].cmd) { + hba->ufs_transmission_status.scsi_send_count++; + } else { + hba->ufs_transmission_status.dev_cmd_count++; + } + } +#endif return 0; } @@ -3316,7 +3473,16 @@ ufshcd_send_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd) * * Returns 0 in case of success, non-zero value in case of failure */ +#ifdef OPLUS_FEATURE_UFSPLUS +/* Add TAG for UFS plus */ +#if defined(CONFIG_UFSFEATURE) +int ufshcd_map_sg(struct ufs_hba *hba, struct ufshcd_lrb *lrbp) +#else static int ufshcd_map_sg(struct ufs_hba *hba, struct ufshcd_lrb *lrbp) +#endif +#else +static int ufshcd_map_sg(struct ufs_hba *hba, struct ufshcd_lrb *lrbp) +#endif { struct ufshcd_sg_entry *prd; struct scatterlist *sg; @@ -3587,7 +3753,16 @@ static int ufshcd_comp_devman_upiu(struct ufs_hba *hba, struct ufshcd_lrb *lrbp) * @hba: per adapter instance * @lrbp: pointer to local reference block */ +#ifdef OPLUS_FEATURE_UFSPLUS +/* Add TAG for UFS plus */ +#if defined(CONFIG_UFSFEATURE) +int ufshcd_comp_scsi_upiu(struct ufs_hba *hba, struct ufshcd_lrb *lrbp) +#else static int ufshcd_comp_scsi_upiu(struct ufs_hba *hba, struct ufshcd_lrb *lrbp) +#endif +#else +static int ufshcd_comp_scsi_upiu(struct ufs_hba *hba, struct ufshcd_lrb *lrbp) +#endif { u32 upiu_flags; int ret = 0; @@ -3599,6 +3774,13 @@ static int ufshcd_comp_scsi_upiu(struct ufs_hba *hba, struct ufshcd_lrb *lrbp) lrbp->command_type = UTP_CMD_TYPE_UFS_STORAGE; if (likely(lrbp->cmd)) { +#ifdef OPLUS_FEATURE_UFSPLUS +/* Add TAG for UFS plus */ +#if defined(CONFIG_UFSFEATURE) + ufsf_change_read10_debug_lun(&hba->ufsf, lrbp); + ufsf_prep_fn(&hba->ufsf, lrbp); +#endif +#endif ret = ufshcd_prepare_req_desc_hdr(hba, lrbp, &upiu_flags, lrbp->cmd->sc_data_direction); ufshcd_prepare_utp_scsi_cmd_upiu(lrbp, upiu_flags); @@ -3690,6 +3872,16 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd) int tag; int err = 0; bool has_read_lock = false; +#ifdef OPLUS_FEATURE_UFSPLUS +/* Add TAG for UFS plus */ +#if defined(CONFIG_UFSFEATURE) && defined(CONFIG_UFSHPB) + struct scsi_cmnd *pre_cmd; + struct ufshcd_lrb *add_lrbp; + int add_tag; + int pre_req_err = -EBUSY; + int lun = ufshcd_scsi_to_upiu_lun(cmd->device->lun); +#endif +#endif hba = shost_priv(host); @@ -3799,7 +3991,29 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd) } if (ufshcd_is_hibern8_on_idle_allowed(hba)) WARN_ON(hba->hibern8_on_idle.state != HIBERN8_EXITED); +#ifdef OPLUS_FEATURE_UFSPLUS +/* Add TAG for UFS plus */ +#if defined(CONFIG_UFSFEATURE) && defined(CONFIG_UFSHPB) + add_tag = ufsf_hpb_prepare_pre_req(&hba->ufsf, cmd, lun); + if (add_tag == -EAGAIN) { + clear_bit_unlock(tag, &hba->lrb_in_use); + err = SCSI_MLQUEUE_HOST_BUSY; + ufshcd_release_all(hba); + goto out; + } + if (add_tag < 0) { + hba->lrb[tag].hpb_ctx_id = MAX_HPB_CONTEXT_ID; + goto send_orig_cmd; + } + add_lrbp = &hba->lrb[add_tag]; + + pre_req_err = ufsf_hpb_prepare_add_lrbp(&hba->ufsf, add_tag); + if (pre_req_err) + hba->lrb[tag].hpb_ctx_id = MAX_HPB_CONTEXT_ID; +send_orig_cmd: +#endif +#endif /* Vote PM QoS for the request */ ufshcd_vops_pm_qos_req_start(hba, cmd->request); @@ -3853,6 +4067,18 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd) /* issue command to the controller */ spin_lock_irqsave(hba->host->host_lock, flags); +#ifdef OPLUS_FEATURE_UFSPLUS +/* Add TAG for UFS plus */ +#if defined(CONFIG_UFSFEATURE) && defined(CONFIG_UFSHPB) + if (!pre_req_err) { + ufshcd_vops_setup_xfer_req(hba, add_tag, (add_lrbp->cmd ? true : false)); + ufshcd_send_command(hba, add_tag); + pre_req_err = -EBUSY; + atomic64_inc(&hba->ufsf.hpb_lup[add_lrbp->lun]->pre_req_cnt); + ufsf_para.pre_req++; + } +#endif +#endif ufshcd_vops_setup_xfer_req(hba, tag, (lrbp->cmd ? true : false)); err = ufshcd_send_command(hba, tag); @@ -3872,6 +4098,20 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd) out_unlock: spin_unlock_irqrestore(hba->host->host_lock, flags); out: +#ifdef OPLUS_FEATURE_UFSPLUS +/* Add TAG for UFS plus */ +#if defined(CONFIG_UFSFEATURE) && defined(CONFIG_UFSHPB) + if (!pre_req_err) { + pre_cmd = add_lrbp->cmd; + scsi_dma_unmap(pre_cmd); + add_lrbp->cmd = NULL; + clear_bit_unlock(add_tag, &hba->lrb_in_use); + ufshcd_release_all(hba); + ufshcd_vops_pm_qos_req_end(hba, pre_cmd->request, true); + ufsf_hpb_end_pre_req(&hba->ufsf, pre_cmd->request); + } +#endif +#endif if (has_read_lock) ufshcd_put_read_lock(hba); return err; @@ -4060,8 +4300,19 @@ static inline void ufshcd_put_dev_cmd_tag(struct ufs_hba *hba, int tag) * NOTE: Since there is only one available tag for device management commands, * it is expected you hold the hba->dev_cmd.lock mutex. */ +#ifdef OPLUS_FEATURE_UFSPLUS +/* Add TAG for UFS plus */ +#if defined(CONFIG_UFSFEATURE) +int ufshcd_exec_dev_cmd(struct ufs_hba *hba, + enum dev_cmd_type cmd_type, int timeout) +#else static int ufshcd_exec_dev_cmd(struct ufs_hba *hba, enum dev_cmd_type cmd_type, int timeout) +#endif +#else +static int ufshcd_exec_dev_cmd(struct ufs_hba *hba, + enum dev_cmd_type cmd_type, int timeout) +#endif { struct ufshcd_lrb *lrbp; int err; @@ -6211,6 +6462,12 @@ static int ufshcd_slave_configure(struct scsi_device *sdev) struct ufs_hba *hba = shost_priv(sdev->host); struct request_queue *q = sdev->request_queue; +#ifdef OPLUS_FEATURE_UFSPLUS +/* Add TAG for UFS plus */ +#if defined(CONFIG_UFSFEATURE) + ufsf_slave_configure(&hba->ufsf, sdev); +#endif +#endif blk_queue_update_dma_pad(q, PRDT_DATA_BYTE_COUNT_PAD - 1); blk_queue_max_segment_size(q, PRDT_DATA_BYTE_COUNT_MAX); @@ -6383,6 +6640,13 @@ ufshcd_transfer_rsp_status(struct ufs_hba *hba, struct ufshcd_lrb *lrbp) &hba->eeh_work)) pm_runtime_get_noresume(hba->dev); } +#ifdef OPLUS_FEATURE_UFSPLUS +/* Add TAG for UFS plus */ +#if defined(CONFIG_UFSFEATURE) + if (scsi_status == SAM_STAT_GOOD) + ufsf_hpb_noti_rb(&hba->ufsf, lrbp); +#endif +#endif break; case UPIU_TRANSACTION_REJECT_UPIU: /* TODO: handle Reject UPIU Response */ @@ -6496,6 +6760,62 @@ static irqreturn_t ufshcd_uic_cmd_compl(struct ufs_hba *hba, u32 intr_status) return retval; } +#ifdef OPLUS_FEATURE_MIDAS +/* Add t for ufs transmission_status for midas */ +static void ufshcd_lrb_scsicmd_time_statistics(struct ufs_hba *hba, struct ufshcd_lrb *lrbp) +{ + if (lrbp->cmd->cmnd[0] == WRITE_10 || lrbp->cmd->cmnd[0] == WRITE_16) { + if (hba->pwr_info.gear_tx == 1) { + hba->ufs_transmission_status.gear_min_write_sec += blk_rq_sectors(lrbp->cmd->request); + hba->ufs_transmission_status.gear_min_write_us += + ktime_us_delta(lrbp->compl_time_stamp, lrbp->issue_time_stamp); + } + + if (hba->pwr_info.gear_tx == 3 || hba->pwr_info.gear_tx == 4) { + hba->ufs_transmission_status.gear_max_write_sec += blk_rq_sectors(lrbp->cmd->request); + hba->ufs_transmission_status.gear_max_write_us += + ktime_us_delta(lrbp->compl_time_stamp, lrbp->issue_time_stamp); + } + } else if (lrbp->cmd->cmnd[0] == READ_10 || lrbp->cmd->cmnd[0] == READ_16) { + if (hba->pwr_info.gear_rx == 1) { + hba->ufs_transmission_status.gear_min_read_sec += blk_rq_sectors(lrbp->cmd->request); + hba->ufs_transmission_status.gear_min_read_us += + ktime_us_delta(lrbp->compl_time_stamp, lrbp->issue_time_stamp); + } + + if (hba->pwr_info.gear_rx == 3 || hba->pwr_info.gear_rx == 4) { + hba->ufs_transmission_status.gear_max_read_sec += blk_rq_sectors(lrbp->cmd->request); + hba->ufs_transmission_status.gear_max_read_us += + ktime_us_delta(lrbp->compl_time_stamp, lrbp->issue_time_stamp); + } + } else { + if (hba->pwr_info.gear_rx == 1) { + hba->ufs_transmission_status.gear_min_other_sec += blk_rq_sectors(lrbp->cmd->request); + hba->ufs_transmission_status.gear_min_other_us += ktime_us_delta(lrbp->compl_time_stamp, lrbp->issue_time_stamp); + } + + if (hba->pwr_info.gear_rx == 3 || hba->pwr_info.gear_rx == 4) { + hba->ufs_transmission_status.gear_max_other_sec += blk_rq_sectors(lrbp->cmd->request); + hba->ufs_transmission_status.gear_max_other_us += ktime_us_delta(lrbp->compl_time_stamp, lrbp->issue_time_stamp); + } + } + + return; +} + +static void ufshcd_lrb_devcmd_time_statistics(struct ufs_hba *hba, struct ufshcd_lrb *lrbp) +{ + if (hba->pwr_info.gear_tx == 1) { + hba->ufs_transmission_status.gear_min_dev_us += + ktime_us_delta(lrbp->compl_time_stamp, lrbp->issue_time_stamp); + } + + if (hba->pwr_info.gear_tx == 3 || hba->pwr_info.gear_tx == 4) { + hba->ufs_transmission_status.gear_max_dev_us += + ktime_us_delta(lrbp->compl_time_stamp, lrbp->issue_time_stamp); + } +} +#endif /*OPLUS_FEATURE_MIDAS*/ /** * __ufshcd_transfer_req_compl - handle SCSI and query command completion * @hba: per adapter instance @@ -6508,6 +6828,9 @@ static void __ufshcd_transfer_req_compl(struct ufs_hba *hba, struct scsi_cmnd *cmd; int result; int index; +#if defined (CONFIG_UFSFEATURE) + bool scsi_req = false; +#endif for_each_set_bit(index, &completed_reqs, hba->nutrs) { lrbp = &hba->lrb[index]; @@ -6519,6 +6842,12 @@ static void __ufshcd_transfer_req_compl(struct ufs_hba *hba, scsi_dma_unmap(cmd); cmd->result = result; lrbp->compl_time_stamp = ktime_get(); +#ifdef OPLUS_FEATURE_MIDAS +/* Add t for ufs transmission_status for midas */ + if (hba->ufs_transmission_status.transmission_status_enable) { + ufshcd_lrb_scsicmd_time_statistics(hba, lrbp); + } +#endif update_req_stats(hba, lrbp); ufshcd_complete_lrbp_crypto(hba, cmd, lrbp); /* Mark completed command as NULL in LRB */ @@ -6533,7 +6862,34 @@ static void __ufshcd_transfer_req_compl(struct ufs_hba *hba, ufshcd_vops_pm_qos_req_end(hba, cmd->request, false); } - +#ifdef OPLUS_FEATURE_UFS_SHOW_LATENCY +/* add latency_hist node for ufs latency calculate in sysfs. */ + if (cmd->request) { + /* Update IO svc time latency histogram */ + u_int64_t delta_us = ktime_us_delta(lrbp->compl_time_stamp, lrbp->issue_time_stamp); + struct request *req = cmd->request; + unsigned int option = req_op(req); + if (hba->latency_hist_enabled &&(!blk_rq_is_passthrough(req))) { + if (option == REQ_OP_WRITE || option == REQ_OP_WRITE_SAME) { + io_update_latency_hist(&hba->io_lat_write, delta_us, blk_rq_sectors(req)); + } else if (option == REQ_OP_READ) { + io_update_latency_hist(&hba->io_lat_read, delta_us, blk_rq_sectors(req)); + } else { + io_update_latency_hist(&hba->io_lat_other, delta_us, blk_rq_sectors(req)); + } + } +#ifdef CONFIG_TRACEPOINTS + if(trace_ufshcd_command_enabled()) { + if ((5000 < delta_us) && bio_has_data(req->bio)) { + trace_printk("ufs_io_latency:%06lld us, io_type:%s, LBA:%08x, size:%d\n", + delta_us, (rq_data_dir(req) == READ) ? "R" : "W", + (unsigned int)req->bio->bi_iter.bi_sector, + cmd->sdb.length); + } + } +#endif + } +#endif clear_bit_unlock(index, &hba->lrb_in_use); /* *__ufshcd_release and __ufshcd_hibern8_release is @@ -6549,9 +6905,18 @@ static void __ufshcd_transfer_req_compl(struct ufs_hba *hba, /* Do not touch lrbp after scsi done */ cmd->scsi_done(cmd); +#if defined (CONFIG_UFSFEATURE) + scsi_req = true; +#endif } else if (lrbp->command_type == UTP_CMD_TYPE_DEV_MANAGE || lrbp->command_type == UTP_CMD_TYPE_UFS_STORAGE) { lrbp->compl_time_stamp = ktime_get(); +#ifdef OPLUS_FEATURE_MIDAS +/* Add t for ufs transmission_status for midas */ + if (hba->ufs_transmission_status.transmission_status_enable) { + ufshcd_lrb_devcmd_time_statistics(hba, lrbp); + } +#endif if (hba->dev_cmd.complete) { ufshcd_cond_add_cmd_trace(hba, index, "dev_cmd_cmpl"); @@ -6569,6 +6934,9 @@ static void __ufshcd_transfer_req_compl(struct ufs_hba *hba, /* we might have free'd some tags above */ wake_up(&hba->dev_cmd.tag_wq); +#if defined(CONFIG_UFSFEATURE) + ufsf_on_idle(&hba->ufsf, scsi_req); +#endif } /** @@ -6942,6 +7310,12 @@ out: static bool ufshcd_wb_sup(struct ufs_hba *hba) { +#ifdef OPLUS_FEATURE_UFSPLUS +/* Add TAG for UFS plus */ +#if defined(CONFIG_UFSTW) + return false; +#endif +#endif return ((hba->dev_info.d_ext_ufs_feature_sup & UFS_DEV_WRITE_BOOSTER_SUP) && (hba->dev_info.b_wb_buffer_type @@ -7447,7 +7821,18 @@ static void ufshcd_rls_handler(struct work_struct *work) hba = container_of(work, struct ufs_hba, rls_work); pm_runtime_get_sync(hba->dev); +#ifndef OPLUS_BUG_STABILITY +/* add for fix dead lock between ufshcd_rls_handler/ufshcd_link_recovery */ down_write(&hba->lock); +#else + ret = down_write_trylock(&hba->lock); + if (0 == ret) { + usleep_range(500000, 500000); + queue_work(hba->recovery_wq, &hba->rls_work); + pm_runtime_put_sync(hba->dev); + return; + } +#endif ufshcd_scsi_block_requests(hba); if (ufshcd_is_shutdown_ongoing(hba)) goto out; @@ -7512,6 +7897,10 @@ static irqreturn_t ufshcd_update_uic_error(struct ufs_hba *hba) */ dev_dbg(hba->dev, "%s: UIC Lane error reported, reg 0x%x\n", __func__, reg); +#ifdef OPLUS_FEATURE_PADL_STATISTICS +/* add unipro statistic information */ + recordUniproErr(&hba->signalCtrl, reg, UNIPRO_ERR_PA); +#endif ufshcd_update_uic_error_cnt(hba, reg, UFS_UIC_ERROR_PA); ufshcd_update_uic_reg_hist(&hba->ufs_stats.pa_err, reg); @@ -7539,6 +7928,10 @@ static irqreturn_t ufshcd_update_uic_error(struct ufs_hba *hba) reg = ufshcd_readl(hba, REG_UIC_ERROR_CODE_DATA_LINK_LAYER); if ((reg & UIC_DATA_LINK_LAYER_ERROR) && (reg & UIC_DATA_LINK_LAYER_ERROR_CODE_MASK)) { +#ifdef OPLUS_FEATURE_PADL_STATISTICS +/* add unipro statistic information */ + recordUniproErr(&hba->signalCtrl, reg, UNIPRO_ERR_DL); +#endif ufshcd_update_uic_error_cnt(hba, reg, UFS_UIC_ERROR_DL); ufshcd_update_uic_reg_hist(&hba->ufs_stats.dl_err, reg); @@ -7561,6 +7954,10 @@ static irqreturn_t ufshcd_update_uic_error(struct ufs_hba *hba) reg = ufshcd_readl(hba, REG_UIC_ERROR_CODE_NETWORK_LAYER); if ((reg & UIC_NETWORK_LAYER_ERROR) && (reg & UIC_NETWORK_LAYER_ERROR_CODE_MASK)) { +#ifdef OPLUS_FEATURE_PADL_STATISTICS +/* add unipro statistic information */ + recordUniproErr(&hba->signalCtrl, reg, UNIPRO_ERR_NL); +#endif ufshcd_update_uic_reg_hist(&hba->ufs_stats.nl_err, reg); hba->uic_error |= UFSHCD_UIC_NL_ERROR; retval |= IRQ_HANDLED; @@ -7569,6 +7966,10 @@ static irqreturn_t ufshcd_update_uic_error(struct ufs_hba *hba) reg = ufshcd_readl(hba, REG_UIC_ERROR_CODE_TRANSPORT_LAYER); if ((reg & UIC_TRANSPORT_LAYER_ERROR) && (reg & UIC_TRANSPORT_LAYER_ERROR_CODE_MASK)) { +#ifdef OPLUS_FEATURE_PADL_STATISTICS +/* add unipro statistic information */ + recordUniproErr(&hba->signalCtrl, reg, UNIPRO_ERR_TL); +#endif ufshcd_update_uic_reg_hist(&hba->ufs_stats.tl_err, reg); hba->uic_error |= UFSHCD_UIC_TL_ERROR; retval |= IRQ_HANDLED; @@ -7577,6 +7978,10 @@ static irqreturn_t ufshcd_update_uic_error(struct ufs_hba *hba) reg = ufshcd_readl(hba, REG_UIC_ERROR_CODE_DME); if ((reg & UIC_DME_ERROR) && (reg & UIC_DME_ERROR_CODE_MASK)) { +#ifdef OPLUS_FEATURE_PADL_STATISTICS +/* add unipro statistic information */ + recordUniproErr(&hba->signalCtrl, reg, UNIPRO_ERR_DME); +#endif ufshcd_update_uic_error_cnt(hba, reg, UFS_UIC_ERROR_DME); ufshcd_update_uic_reg_hist(&hba->ufs_stats.dme_err, reg); hba->uic_error |= UFSHCD_UIC_DME_ERROR; @@ -7601,10 +8006,18 @@ static irqreturn_t ufshcd_check_errors(struct ufs_hba *hba) bool queue_eh_work = false; irqreturn_t retval = IRQ_NONE; - if (hba->errors & INT_FATAL_ERRORS || hba->ce_error) + if (hba->errors & INT_FATAL_ERRORS || hba->ce_error) { +#ifdef OPLUS_FEATURE_PADL_STATISTICS +/* add unipro statistic information */ + recordUniproErr(&hba->signalCtrl, hba->errors, UNIPRO_ERR_FATAL); +#endif queue_eh_work = true; - + } if (hba->errors & UIC_LINK_LOST) { +#ifdef OPLUS_FEATURE_PADL_STATISTICS +/* add unipro statistic information */ + recordUniproErr(&hba->signalCtrl, hba->errors, UNIPRO_ERR_LINK); +#endif dev_err(hba->dev, "%s: UIC_LINK_LOST received, errors 0x%x\n", __func__, hba->errors); queue_eh_work = true; @@ -7837,6 +8250,10 @@ static int ufshcd_issue_tm_cmd(struct ufs_hba *hba, int lun_id, int task_id, __set_bit(free_slot, &hba->outstanding_tasks); /* Make sure descriptors are ready before ringing the task doorbell */ +#ifdef OPLUS_FEATURE_PADL_STATISTICS + /* add request count information */ + recordRequestCnt(&hba->signalCtrl); +#endif wmb(); ufshcd_writel(hba, 1 << free_slot, REG_UTP_TASK_REQ_DOOR_BELL); @@ -7918,6 +8335,12 @@ static int ufshcd_eh_device_reset_handler(struct scsi_cmnd *cmd) out: hba->req_abort_count = 0; if (!err) { +#ifdef OPLUS_FEATURE_UFSPLUS +/* Add TAG for UFS plus */ +#if defined(CONFIG_UFSFEATURE) + ufsf_reset_lu(&hba->ufsf); +#endif +#endif err = SUCCESS; } else { dev_err(hba->dev, "%s: failed with err %d\n", __func__, err); @@ -8139,6 +8562,12 @@ static int ufshcd_host_reset_and_restore(struct ufs_hba *hba) int err; unsigned long flags; +#ifdef OPLUS_FEATURE_UFSPLUS +/* Add TAG for UFS plus */ +#if defined(CONFIG_UFSFEATURE) + ufsf_reset_host(&hba->ufsf); +#endif +#endif /* * Stop the host controller and complete the requests * cleared by h/w @@ -8469,11 +8898,30 @@ static int ufshcd_set_low_vcc_level(struct ufs_hba *hba, * Returns zero on success (all required W-LUs are added successfully), * non-zero error value on failure (if failed to add any of the required W-LU). */ +#ifdef OPLUS_FEATURE_UFS_DRIVER +int __attribute__((weak)) register_device_proc(char *name, char *version, char *vendor) +{ + return 0; +} + +int __attribute__((weak)) register_device_proc_for_ufsplus(char *name, int *hpb_status, int *tw_status) +{ + return 0; +} +#endif + + static int ufshcd_scsi_add_wlus(struct ufs_hba *hba) { int ret = 0; struct scsi_device *sdev_rpmb = NULL; struct scsi_device *sdev_boot = NULL; +#ifdef OPLUS_FEATURE_UFS_DRIVER + /* add for ufs device in /proc/devinfo */ + static char temp_version[5] = {0}; + static char vendor[9] = {0}; + static char model[17] = {0}; +#endif hba->sdev_ufs_device = __scsi_add_device(hba->host, 0, 0, ufshcd_upiu_wlun_to_scsi_wlun(UFS_UPIU_UFS_DEVICE_WLUN), NULL); @@ -8503,6 +8951,16 @@ static int ufshcd_scsi_add_wlus(struct ufs_hba *hba) remove_sdev_ufs_device: scsi_remove_device(hba->sdev_ufs_device); out: +#ifdef OPLUS_FEATURE_UFS_DRIVER +/* add for ufs device in /proc/devinfo */ + strncpy(temp_version, hba->sdev_ufs_device->rev, 4); + strncpy(vendor, hba->sdev_ufs_device->vendor, 8); + strncpy(model, hba->sdev_ufs_device->model, 16); + register_device_proc("ufs_version", temp_version, vendor); + register_device_proc("ufs", model, vendor); + /* add for ufsplus status node in /proc/devinfo */ + /* register_device_proc_for_ufsplus("ufsplus_status", &ufsplus_hpb_status,&ufsplus_tw_status); */ +#endif return ret; } @@ -9213,6 +9671,19 @@ reinit: } scsi_scan_host(hba->host); +#ifdef OPLUS_FEATURE_UFSPLUS +/* Add TAG for UFS plus */ +#if defined(CONFIG_UFSFEATURE) + ufsf_device_check(hba); + ufsf_init(&hba->ufsf); + +#if defined(CONFIG_UFSHPB) + /*temporary for hynix 2.2 tw function*/ + if(hba->dev_info.w_manufacturer_id == 0x1AD && hba->dev_info.w_spec_version == 0x220) + ufsplus_hpb_status = 1; +#endif +#endif +#endif pm_runtime_put_sync(hba->dev); } @@ -9231,7 +9702,12 @@ out: ufshcd_exit_clk_scaling(hba); ufshcd_hba_exit(hba); } - +#ifdef OPLUS_FEATURE_UFSPLUS +/* Add TAG for UFS plus */ +#if defined(CONFIG_UFSFEATURE) + ufsf_reset(&hba->ufsf); +#endif +#endif trace_ufshcd_init(dev_name(hba->dev), ret, ktime_to_us(ktime_sub(ktime_get(), start)), hba->curr_dev_pwr_mode, hba->uic_link_state); @@ -9312,6 +9788,12 @@ static int ufshcd_query_ioctl(struct ufs_hba *hba, u8 lun, void __user *buffer) u32 att; u8 index; u8 *desc = NULL; +#ifdef OPLUS_FEATURE_UFSPLUS +/* Add TAG for UFS plus */ +#if defined(CONFIG_UFSFEATURE) + u8 selector = 0x1; +#endif +#endif ioctl_data = kzalloc(sizeof(struct ufs_ioctl_query_data), GFP_KERNEL); if (!ioctl_data) { @@ -9329,6 +9811,33 @@ static int ufshcd_query_ioctl(struct ufs_hba *hba, u8 lun, void __user *buffer) goto out_release_mem; } +#ifdef OPLUS_FEATURE_UFSPLUS +/* Add TAG for UFS plus */ +#if defined(CONFIG_UFSFEATURE) + dev_err(hba->dev, "%s: hba->dev_info.w_manufacturer_id %x\n", __func__, hba->dev_info.w_manufacturer_id); + switch (hba->dev_info.w_manufacturer_id) { + case UFS_VENDOR_SAMSUNG: + selector = 0x1; + break; + case UFS_VENDOR_TOSHIBA: + case UFS_VENDOR_SKHYNIX: + case UFS_VENDOR_WDC: + case UFS_VENDOR_MICRON: + selector = 0x0; + break; + default: + break; + } + + dev_err(hba->dev, "%s:selector %x\n", __func__, selector); + + if (ufsf_check_query(ioctl_data->opcode)) { + err = ufsf_query_ioctl(&hba->ufsf, lun, buffer, ioctl_data, + selector); + goto out_release_mem; + } +#endif +#endif /* verify legal parameters & send query */ switch (ioctl_data->opcode) { case UPIU_QUERY_OPCODE_READ_DESC: @@ -9338,6 +9847,10 @@ static int ufshcd_query_ioctl(struct ufs_hba *hba, u8 lun, void __user *buffer) case QUERY_DESC_IDN_INTERCONNECT: case QUERY_DESC_IDN_GEOMETRY: case QUERY_DESC_IDN_POWER: +#ifdef OPLUS_FEATURE_STORAGE_TOOL + /* add for read healthy desc by ioctl */ + case QUERY_DESC_IDN_HEALTH: +#endif index = 0; break; case QUERY_DESC_IDN_UNIT: @@ -9381,6 +9894,11 @@ static int ufshcd_query_ioctl(struct ufs_hba *hba, u8 lun, void __user *buffer) case QUERY_ATTR_IDN_EE_CONTROL: case QUERY_ATTR_IDN_EE_STATUS: case QUERY_ATTR_IDN_SECONDS_PASSED: +#ifdef OPLUS_FEATURE_STORAGE_TOOL + /* add for read ffu status attribute by ioctl */ + case QUERY_ATTR_IDN_FFU_STATUS: +#endif + index = 0; break; case QUERY_ATTR_IDN_DYN_CAP_NEEDED: @@ -9515,14 +10033,13 @@ static int ufshcd_ioctl(struct scsi_device *dev, int cmd, void __user *buffer) int err = 0; BUG_ON(!hba); + if (!buffer) { + dev_err(hba->dev, "%s: User buffer is NULL!\n", __func__); + return -EINVAL; + } switch (cmd) { case UFS_IOCTL_QUERY: - if (!buffer) { - dev_err(hba->dev, "%s: User buffer is NULL!\n", - __func__); - return -EINVAL; - } pm_runtime_get_sync(hba->dev); err = ufshcd_query_ioctl(hba, ufshcd_scsi_to_upiu_lun(dev->lun), buffer); @@ -10272,12 +10789,30 @@ static void ufshcd_vreg_set_lpm(struct ufs_hba *hba) else ufshcd_config_vreg_lpm(hba, hba->vreg_info.vccq2); } else if (!ufshcd_is_ufs_dev_active(hba)) { +#ifdef OPLUS_FEATURE_UFSPLUS +/* Add TAG for UFS plus */ +#if defined(CONFIG_UFSFEATURE) + /* + * Because the Turbo Write feature need flush the data from SLC buffer + * to TLC, When the device enter Hibern8. SO We keep the VCC votage alive, + * and VCCQ VCCQ2 not enter LPM. + */ +#else if (!hba->dev_info.keep_vcc_on) ufshcd_toggle_vreg(hba->dev, hba->vreg_info.vcc, false); if (!ufshcd_is_link_active(hba)) { ufshcd_config_vreg_lpm(hba, hba->vreg_info.vccq); ufshcd_config_vreg_lpm(hba, hba->vreg_info.vccq2); } +#endif +#else + if (!hba->dev_info.keep_vcc_on) + ufshcd_toggle_vreg(hba->dev, hba->vreg_info.vcc, false); + if (!ufshcd_is_link_active(hba)) { + ufshcd_config_vreg_lpm(hba, hba->vreg_info.vccq); + ufshcd_config_vreg_lpm(hba, hba->vreg_info.vccq2); + } +#endif } } @@ -10385,6 +10920,13 @@ static int ufshcd_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op) req_link_state = UIC_LINK_OFF_STATE; } +#ifdef OPLUS_FEATURE_UFSPLUS +/* Add TAG for UFS plus */ +#if defined(CONFIG_UFSFEATURE) + ufsf_hpb_suspend(&hba->ufsf); +#endif +#endif + ret = ufshcd_crypto_suspend(hba, pm_op); if (ret) goto out; @@ -10528,6 +11070,14 @@ enable_gating: hba->clk_gating.is_suspended = false; ufshcd_release_all(hba); ufshcd_crypto_resume(hba, pm_op); + +#ifdef OPLUS_FEATURE_UFSPLUS +/* Add TAG for UFS plus */ +#if defined(CONFIG_UFSFEATURE) + ufsf_resume(&hba->ufsf); +#endif +#endif + out: hba->pm_op_in_progress = 0; @@ -10651,7 +11201,12 @@ static int ufshcd_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op) if (hba->clk_scaling.is_allowed) ufshcd_resume_clkscaling(hba); - +#ifdef OPLUS_FEATURE_UFSPLUS +/* Add TAG for UFS plus */ +#if defined(CONFIG_UFSFEATURE) + ufsf_resume(&hba->ufsf); +#endif +#endif /* Set Auto-Hibernate timer if supported */ ufshcd_set_auto_hibern8_timer(hba); @@ -10932,6 +11487,18 @@ EXPORT_SYMBOL(ufshcd_shutdown); */ void ufshcd_remove(struct ufs_hba *hba) { +#ifdef OPLUS_FEATURE_UFSPLUS +/* Add TAG for UFS plus */ +#if defined(CONFIG_UFSFEATURE) + ufsf_remove(&hba->ufsf); +/* Add for UFS+ RUS */ + remove_ufsplus_ctrl_proc(); +#endif +#endif +#ifdef OPLUS_FEATURE_PADL_STATISTICS +/* add unipro statistic information */ + remove_signal_quality_proc(&hba->signalCtrl); +#endif ufs_sysfs_remove_nodes(hba->dev); scsi_remove_host(hba->host); /* disable interrupts */ @@ -11232,6 +11799,21 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq) ufshcd_cmd_log_init(hba); +#ifdef OPLUS_FEATURE_MIDAS +/* Add t for ufs transmission_status for midas */ + ufshcd_transmission_status_init_sysfs(hba); +#endif + +#ifdef OPLUS_FEATURE_UFSPLUS +/* Add TAG for UFS plus */ +#if defined(CONFIG_UFSFEATURE) + ufsf_set_init_state(&hba->ufsf); +#endif +#endif +#ifdef OPLUS_FEATURE_PADL_STATISTICS +/* add unipro statistic information */ + create_signal_quality_proc(&hba->signalCtrl); +#endif async_schedule(ufshcd_async_scan, hba); ufsdbg_add_debugfs(hba); diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h index ccdcfa4ed1ac..e56a61f1f591 100644 --- a/drivers/scsi/ufs/ufshcd.h +++ b/drivers/scsi/ufs/ufshcd.h @@ -76,6 +76,15 @@ #include "ufs.h" #include "ufshci.h" +#ifdef OPLUS_FEATURE_UFS_SHOW_LATENCY +#include "ufs_latency_hist.h" +#endif +#if defined(CONFIG_UFSFEATURE) +#include "ufsfeature.h" +#endif +#ifdef OPLUS_FEATURE_PADL_STATISTICS +#include "ufs_signal_quality.h" +#endif #define UFSHCD "ufshcd" #define UFSHCD_DRIVER_VERSION "0.3" @@ -232,6 +241,9 @@ struct ufshcd_lrb { #endif /* CONFIG_SCSI_UFS_CRYPTO */ bool req_abort_skip; +#if defined(CONFIG_UFSFEATURE) && defined(CONFIG_UFSHPB) + int hpb_ctx_id; +#endif }; /** @@ -748,6 +760,35 @@ struct ufshcd_cmd_log { u32 seq_num; }; +#ifdef OPLUS_FEATURE_MIDAS +/* Add t for ufs transmission_status for midas */ +struct ufs_transmission_status_t +{ + u8 transmission_status_enable; + + u64 gear_min_write_sec; + u64 gear_max_write_sec; + u64 gear_min_read_sec; + u64 gear_max_read_sec; + + u64 gear_min_write_us; + u64 gear_max_write_us; + u64 gear_min_read_us; + u64 gear_max_read_us; + + u64 gear_min_dev_us; + u64 gear_max_dev_us; + + u64 gear_min_other_sec; + u64 gear_max_other_sec; + u64 gear_min_other_us; + u64 gear_max_other_us; + + u64 scsi_send_count; + u64 dev_cmd_count; +}; +#endif /*OPLUS_FEATURE_MIDAS*/ + /** * struct ufs_hba - per adapter private structure * @mmio_base: UFSHCI base register address @@ -1021,6 +1062,13 @@ struct ufs_hba { #ifdef CONFIG_DEBUG_FS struct debugfs_files debugfs_files; #endif +#ifdef OPLUS_FEATURE_UFS_SHOW_LATENCY +/* add latency_hist node for ufs latency calculate in sysfs */ + int latency_hist_enabled; + struct io_latency_state io_lat_read; + struct io_latency_state io_lat_write; + struct io_latency_state io_lat_other; +#endif struct ufs_vreg_info vreg_info; struct list_head clk_list_head; @@ -1114,6 +1162,13 @@ struct ufs_hba { bool phy_init_g4; bool force_g4; +#if defined(CONFIG_UFSFEATURE) + struct ufsf_feature ufsf; +#endif +#ifdef OPLUS_FEATURE_PADL_STATISTICS +/* add unipro statistic information */ + struct unipro_signal_quality_ctrl signalCtrl; +#endif bool wb_enabled; #ifdef CONFIG_SCSI_UFS_CRYPTO @@ -1124,6 +1179,12 @@ struct ufs_hba { struct keyslot_manager *ksm; #endif /* CONFIG_SCSI_UFS_CRYPTO */ +#ifdef OPLUS_FEATURE_MIDAS +/* Add t for ufs transmission_status for midas */ + struct ufs_transmission_status_t ufs_transmission_status; + struct device_attribute ufs_transmission_status_attr; +#endif + ANDROID_KABI_RESERVE(1); ANDROID_KABI_RESERVE(2); ANDROID_KABI_RESERVE(3); @@ -1410,6 +1471,15 @@ u32 ufshcd_get_local_unipro_ver(struct ufs_hba *hba); void ufshcd_scsi_block_requests(struct ufs_hba *hba); void ufshcd_scsi_unblock_requests(struct ufs_hba *hba); +#if defined(CONFIG_UFSFEATURE) +int ufshcd_exec_dev_cmd(struct ufs_hba *hba, + enum dev_cmd_type cmd_type, int timeout); +int ufshcd_hibern8_hold(struct ufs_hba *hba, bool async); +void ufshcd_hold_all(struct ufs_hba *hba); +void ufshcd_release_all(struct ufs_hba *hba); +int ufshcd_comp_scsi_upiu(struct ufs_hba *hba, struct ufshcd_lrb *lrbp); +int ufshcd_map_sg(struct ufs_hba *hba, struct ufshcd_lrb *lrbp); +#endif /* Wrapper functions for safely calling variant operations */ static inline const char *ufshcd_get_var_name(struct ufs_hba *hba) diff --git a/drivers/scsi/ufs/ufshid.c b/drivers/scsi/ufs/ufshid.c new file mode 100644 index 000000000000..6a6c63a3e7e8 --- /dev/null +++ b/drivers/scsi/ufs/ufshid.c @@ -0,0 +1,813 @@ +/* + * Universal Flash Storage Host Initiated Defrag (UFS HID) + * + * Copyright (C) 2019-2019 Samsung Electronics Co., Ltd. + * + * Authors: + * Yongmyung Lee + * Jieon Seol + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * See the COPYING file in the top-level directory or visit + * + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * This program is provided "AS IS" and "WITH ALL FAULTS" and + * without warranty of any kind. You are solely responsible for + * determining the appropriateness of using and distributing + * the program and assume all risks associated with your exercise + * of rights with respect to the program, including but not limited + * to infringement of third party rights, the risks and costs of + * program errors, damage to or loss of data, programs or equipment, + * and unavailability or interruption of operations. Under no + * circumstances will the contributor of this Program be liable for + * any damages of any kind arising from your use or distribution of + * this program. + * + * The Linux Foundation chooses to take subject only to the GPLv2 + * license terms, and distributes only under these terms. + */ + +#include "ufshcd.h" +#include "ufshid.h" + +static int ufshid_create_sysfs(struct ufshid_dev *hid); +static void ufshid_remove_sysfs(struct ufshid_dev *hid); + +inline int ufshid_get_state(struct ufsf_feature *ufsf) +{ + return atomic_read(&ufsf->hid_state); +} + +inline void ufshid_set_state(struct ufsf_feature *ufsf, int state) +{ + atomic_set(&ufsf->hid_state, state); +} + +static inline int ufshid_is_not_present(struct ufshid_dev *hid) +{ + enum UFSHID_STATE cur_state = ufshid_get_state(hid->ufsf); + + if (cur_state != HID_PRESENT) { + INFO_MSG("hid_state != HID_PRESENT (%d)", cur_state); + return -ENODEV; + } + return 0; +} + +static int ufshid_read_attr(struct ufshid_dev *hid, u8 idn, u32 *attr_val) +{ + struct ufs_hba *hba = hid->ufsf->hba; + int ret = 0; + + pm_runtime_get_sync(hba->dev); + + ret = ufsf_query_attr_retry(hba, UPIU_QUERY_OPCODE_READ_ATTR, idn, 0, + attr_val); + if (ret) { + ERR_MSG("read attr [0x%.2X] fail. (%d)", idn, ret); + goto err_out; + } + + HID_DEBUG(hid, "hid_attr read [0x%.2X] %u (0x%X)", idn, *attr_val, + *attr_val); + TMSG(hid->ufsf, 0, "[ufshid] read_attr IDN %s (%d)", + idn == QUERY_ATTR_IDN_HID_OPERATION ? "HID_OP" : + idn == QUERY_ATTR_IDN_HID_FRAG_LEVEL ? "HID_LEV" : "UNKNOWN", idn); +err_out: + pm_runtime_put_sync(hba->dev); + return ret; +} + +static int ufshid_write_attr(struct ufshid_dev *hid, u8 idn, u32 val) +{ + struct ufs_hba *hba = hid->ufsf->hba; + int ret = 0; + + pm_runtime_get_sync(hba->dev); + + ret = ufsf_query_attr_retry(hba, UPIU_QUERY_OPCODE_WRITE_ATTR, idn, 0, + &val); + if (ret) { + ERR_MSG("write attr [0x%.2X] fail. (%d)", idn, ret); + goto err_out; + } + + HID_DEBUG(hid, "hid_attr write [0x%.2X] %u (0x%X)", idn, val, val); + TMSG(hid->ufsf, 0, "[ufshid] write_attr IDN %s (%d)", + idn == QUERY_ATTR_IDN_HID_OPERATION ? "HID_OP" : + idn == QUERY_ATTR_IDN_HID_FRAG_LEVEL ? "HID_LEV" : "UNKNOWN", idn); +err_out: + pm_runtime_put_sync(hba->dev); + return ret; +} + +static inline int ufshid_version_check(int spec_version) +{ + INFO_MSG("Support HID Spec : Driver = (%.4x), Device = (%.4x)", + UFSHID_VER, spec_version); + INFO_MSG("HID Driver version (%.6X%s)", + UFSHID_DD_VER, UFSHID_DD_VER_POST); + + if (spec_version != UFSHID_VER) { + ERR_MSG("UFS HID version mismatched"); + return -ENODEV; + } + return 0; +} + +void ufshid_get_dev_info(struct ufsf_feature *ufsf, u8 *desc_buf) +{ + int ret = 0, spec_version; + + ufsf->hid_dev = NULL; + + if (!(LI_EN_32(&desc_buf[DEVICE_DESC_PARAM_EXT_UFS_FEATURE_SUP]) & + UFS_FEATURE_SUPPORT_HID_BIT)) { + INFO_MSG("bUFSExFeaturesSupport: HID not support"); + goto err_out; + } + + INFO_MSG("bUFSExFeaturesSupport: HID support"); + spec_version = + LI_EN_16(&desc_buf[DEVICE_DESC_PARAM_HID_VER]); + ret = ufshid_version_check(spec_version); + if (ret) + goto err_out; + + ufsf->hid_dev = kzalloc(sizeof(struct ufshid_dev), GFP_KERNEL); + if (!ufsf->hid_dev) { + ERR_MSG("hid_dev memalloc fail"); + goto err_out; + } + + ufsf->hid_dev->ufsf = ufsf; + return; +err_out: + ufshid_set_state(ufsf, HID_FAILED); +} + +static int ufshid_get_analyze_and_issue_execute(struct ufshid_dev *hid) +{ + u32 attr_val; + int frag_level; + + if (ufshid_write_attr(hid, QUERY_ATTR_IDN_HID_OPERATION, + HID_OP_EXECUTE)) + return -EINVAL; + if (ufshid_read_attr(hid, QUERY_ATTR_IDN_HID_FRAG_LEVEL, &attr_val)) + return -EINVAL; + + frag_level = attr_val & HID_FRAG_LEVEL_MASK; + HID_DEBUG(hid, "Frag_lv %d Freg_stat %d HID_need_exec %d", + frag_level, HID_FRAG_UPDATE_STAT(attr_val), + HID_EXECUTE_REQ_STAT(attr_val)); + + if (frag_level == HID_LEV_GRAY) + return -EAGAIN; + + return (HID_EXECUTE_REQ_STAT(attr_val)) ? + HID_REQUIRED : HID_NOT_REQUIRED; +} + +static int ufshid_issue_disable(struct ufshid_dev *hid) +{ + u32 attr_val; + + if (ufshid_write_attr(hid, QUERY_ATTR_IDN_HID_OPERATION, + HID_OP_DISABLE)) + return -EINVAL; + if (ufshid_read_attr(hid, QUERY_ATTR_IDN_HID_FRAG_LEVEL, &attr_val)) + return -EINVAL; + + HID_DEBUG(hid, "Frag_lv %d Freg_stat %d HID_need_exec %d", + attr_val & HID_FRAG_LEVEL_MASK, + HID_FRAG_UPDATE_STAT(attr_val), + HID_EXECUTE_REQ_STAT(attr_val)); + + return 0; +} + +/* + * Lock status: hid_sysfs lock was held when called. + */ +static void ufshid_auto_hibern8_enable(struct ufshid_dev *hid, + unsigned int val) +{ + struct ufs_hba *hba = hid->ufsf->hba; + unsigned long flags; + u32 reg; + + val = !!val; + + /* Update auto hibern8 timer value if supported */ + if (!ufshcd_is_auto_hibern8_supported(hba)) + return; + + pm_runtime_get_sync(hba->dev); + ufshcd_hold_all(hba); + down_write(&hba->lock); + ufshcd_scsi_block_requests(hba); + /* wait for all the outstanding requests to finish */ + ufshcd_wait_for_doorbell_clr(hba, U64_MAX); + spin_lock_irqsave(hba->host->host_lock, flags); + + reg = ufshcd_readl(hba, REG_AUTO_HIBERNATE_IDLE_TIMER); + INFO_MSG("ahit-reg 0x%X", reg); + + if (val ^ (reg == hba->ahit)) { + ufshcd_writel(hba, val ? hba->ahit : HID_AUTO_HIBERN8_DISABLE, + REG_AUTO_HIBERNATE_IDLE_TIMER); + /* Make sure the timer gets applied before further operations */ + mb(); + + INFO_MSG("[Before] is_auto_enabled %d", hid->is_auto_enabled); + hid->is_auto_enabled = val; + + reg = ufshcd_readl(hba, REG_AUTO_HIBERNATE_IDLE_TIMER); + INFO_MSG("[After] is_auto_enabled %d ahit-reg 0x%X", + hid->is_auto_enabled, reg); + } else { + INFO_MSG("is_auto_enabled %d. so it does not changed", + hid->is_auto_enabled); + } + + spin_unlock_irqrestore(hba->host->host_lock, flags); + ufshcd_scsi_unblock_requests(hba); + up_write(&hba->lock); + ufshcd_release_all(hba); + pm_runtime_put_sync(hba->dev); +} + +static void ufshid_block_enter_suspend(struct ufshid_dev *hid) +{ + struct ufs_hba *hba = hid->ufsf->hba; + unsigned long flags; + + pm_runtime_get_sync(hba->dev); + ufshcd_hold_all(hba); + + spin_lock_irqsave(hba->host->host_lock, flags); + HID_DEBUG(hid, + "dev->power.usage_count %d hba->clk_gating.active_reqs %d " + "hba->hibern8_on_idle.active_reqs %d", + atomic_read(&hba->dev->power.usage_count), + hba->clk_gating.active_reqs, + hba->hibern8_on_idle.active_reqs); + spin_unlock_irqrestore(hba->host->host_lock, flags); +} + +/* + * Lock status: hid_sysfs lock was held when called. + */ +static void ufshid_trigger_on(struct ufshid_dev *hid) +{ + hid->hid_trigger = true; + HID_DEBUG(hid, "trigger 0 -> 1"); + + ufshid_block_enter_suspend(hid); + + ufshid_auto_hibern8_enable(hid, 0); + + schedule_delayed_work(&hid->hid_trigger_work, 0); +} + +static void ufshid_allow_enter_suspend(struct ufshid_dev *hid) +{ + struct ufs_hba *hba = hid->ufsf->hba; + unsigned long flags; + + ufshcd_release_all(hba); + pm_runtime_mark_last_busy(hba->dev); + pm_runtime_put_noidle(hba->dev); + + spin_lock_irqsave(hba->host->host_lock, flags); + HID_DEBUG(hid, + "dev->power.usage_count %d hba->clk_gating.active_reqs %d " + "hba->hibern8_on_idle.active_reqs %d", + atomic_read(&hba->dev->power.usage_count), + hba->clk_gating.active_reqs, + hba->hibern8_on_idle.active_reqs); + spin_unlock_irqrestore(hba->host->host_lock, flags); +} + +/* + * Lock status: hid_sysfs lock was held when called. + */ +static void ufshid_trigger_off(struct ufshid_dev *hid) +{ + hid->hid_trigger = false; + HID_DEBUG(hid, "hid_trigger 1 -> 0"); + + ufshid_issue_disable(hid); + + ufshid_auto_hibern8_enable(hid, 1); + + ufshid_allow_enter_suspend(hid); +} + +static void ufshid_trigger_work_fn(struct work_struct *dwork) +{ + struct ufshid_dev *hid; + struct ufs_hba *hba; + int ret; + + hid = container_of(dwork, struct ufshid_dev, hid_trigger_work.work); + hba = hid->ufsf->hba; + + if (ufshid_is_not_present(hid)) + return; + + HID_DEBUG(hid, "start hid_trigger_work_fn"); + + ret = ufshid_get_analyze_and_issue_execute(hid); + + mutex_lock(&hid->sysfs_lock); + if (!hid->hid_trigger) { + HID_DEBUG(hid, "hid_trigger == false, return"); + mutex_unlock(&hid->sysfs_lock); + return; + } + + if (ret == HID_NOT_REQUIRED) { + ufshid_trigger_off(hid); + mutex_unlock(&hid->sysfs_lock); + return; + } else if (ret == HID_REQUIRED) { + HID_DEBUG(hid, "HID_REQUIRED, so sched (%d ms)", + hid->hid_trigger_delay); + } else { + HID_DEBUG(hid, "issue_HID ERR(%X), so resched for retry", + ret); + } + mutex_unlock(&hid->sysfs_lock); + + schedule_delayed_work(&hid->hid_trigger_work, + msecs_to_jiffies(hid->hid_trigger_delay)); + + HID_DEBUG(hid, "end hid_trigger_work_fn"); +} + +void ufshid_set_init_state(struct ufsf_feature *ufsf) +{ + ufshid_set_state(ufsf, HID_NEED_INIT); +} + +void ufshid_init(struct ufsf_feature *ufsf) +{ + struct ufshid_dev *hid; + + INFO_MSG("HID_INIT_START"); + + hid = ufsf->hid_dev; + BUG_ON(!hid); + + hid->hid_trigger = false; + hid->hid_trigger_delay = HID_TRIGGER_WORKER_DELAY_MS_DEFAULT; + INIT_DELAYED_WORK(&hid->hid_trigger_work, ufshid_trigger_work_fn); + + hid->hid_debug = false; +#if defined(CONFIG_UFSHID_POC) + hid->hid_debug = true; + hid->block_suspend = false; +#endif + + /* If HCI supports auto hibern8, UFS Driver use it default */ + if (ufshcd_is_auto_hibern8_supported(ufsf->hba)) + hid->is_auto_enabled = true; + else + hid->is_auto_enabled = false; + + if (ufshid_create_sysfs(hid)) { + ERR_MSG("sysfs init fail. so hid driver disabled"); + kfree(ufsf->hid_dev); + ufshid_set_state(ufsf, HID_FAILED); + return; + } + + INFO_MSG("UFS HID create sysfs finished"); + + ufshid_set_state(ufsf, HID_PRESENT); +} + +void ufshid_reset_host(struct ufsf_feature *ufsf) +{ + struct ufshid_dev *hid = ufsf->hid_dev; + + if (!hid) + return; + + ufshid_set_state(ufsf, HID_RESET); + cancel_delayed_work_sync(&hid->hid_trigger_work); +} + +void ufshid_reset(struct ufsf_feature *ufsf) +{ + struct ufshid_dev *hid = ufsf->hid_dev; + + if (!hid) + return; + + ufshid_set_state(ufsf, HID_PRESENT); + + /* + * hid_trigger will be checked under sysfs_lock in worker. + */ + if (hid->hid_trigger) + schedule_delayed_work(&hid->hid_trigger_work, 0); + + INFO_MSG("reset completed."); +} + +void ufshid_remove(struct ufsf_feature *ufsf) +{ + struct ufshid_dev *hid = ufsf->hid_dev; + + if (!hid) + return; + + INFO_MSG("start HID release"); + + ufshid_set_state(ufsf, HID_FAILED); + + ufshid_remove_sysfs(hid); + + kfree(hid); + + INFO_MSG("end HID release"); +} + +/* + * this function is called in irq context. + * so cancel_delayed_work_sync() do not use due to waiting. + */ +void ufshid_on_idle(struct ufsf_feature *ufsf) +{ + struct ufshid_dev *hid = ufsf->hid_dev; + + if (!hid) + return; + /* + * When hid_trigger_work will be scheduled, + * check hid_trigger under sysfs_lock. + */ + if (!hid->hid_trigger) + return; + + if (delayed_work_pending(&hid->hid_trigger_work)) + cancel_delayed_work(&hid->hid_trigger_work); + + schedule_delayed_work(&hid->hid_trigger_work, 0); +} + +/* sysfs function */ +static ssize_t ufshid_sysfs_show_version(struct ufshid_dev *hid, char *buf) +{ + INFO_MSG("HID version (%.4X) D/D version (%.6X%s)", + UFSHID_VER, UFSHID_DD_VER, UFSHID_DD_VER_POST); + + return snprintf(buf, PAGE_SIZE, + "HID version (%.4X) D/D version (%.6X%s)\n", + UFSHID_VER, UFSHID_DD_VER, UFSHID_DD_VER_POST); +} + +static ssize_t ufshid_sysfs_show_trigger(struct ufshid_dev *hid, char *buf) +{ + INFO_MSG("hid_trigger %d", hid->hid_trigger); + + return snprintf(buf, PAGE_SIZE, "%d\n", hid->hid_trigger); +} + +static ssize_t ufshid_sysfs_store_trigger(struct ufshid_dev *hid, + const char *buf, size_t count) +{ + unsigned long val; + struct ufs_hba *hba; + + if (kstrtoul(buf, 0, &val)) + return -EINVAL; + + if (val != 0 && val != 1) + return -EINVAL; + + hba = hid->ufsf->hba; + + INFO_MSG("HID_trigger(input) %lu", val); + + if (val == hid->hid_trigger) + return count; + + if (!val) { + if (hid->hid_trigger) + ufshid_trigger_off(hid); + } else { + ufshid_trigger_on(hid); + } + + return count; +} + +static ssize_t ufshid_sysfs_show_trigger_interval(struct ufshid_dev *hid, + char *buf) +{ + INFO_MSG("hid_trigger_interval %d", hid->hid_trigger_delay); + + return snprintf(buf, PAGE_SIZE, "%d\n", hid->hid_trigger_delay); +} + +static ssize_t ufshid_sysfs_store_trigger_interval(struct ufshid_dev *hid, + const char *buf, + size_t count) +{ + unsigned long val; + + if (kstrtoul(buf, 0, &val)) + return -EINVAL; + + if (val < HID_TRIGGER_WORKER_DELAY_MS_MIN || + val > HID_TRIGGER_WORKER_DELAY_MS_MAX) { + INFO_MSG("hid_trigger_interval (min) %4dms ~ (max) %4dms", + HID_TRIGGER_WORKER_DELAY_MS_MIN, + HID_TRIGGER_WORKER_DELAY_MS_MAX); + return -EINVAL; + } + + hid->hid_trigger_delay = (unsigned int)val; + INFO_MSG("hid_trigger_interval %d", hid->hid_trigger_delay); + + return count; +} + +static ssize_t ufshid_sysfs_show_debug(struct ufshid_dev *hid, char *buf) +{ + INFO_MSG("debug %d", hid->hid_debug); + + return snprintf(buf, PAGE_SIZE, "%d\n", hid->hid_debug); +} + +static ssize_t ufshid_sysfs_store_debug(struct ufshid_dev *hid, const char *buf, + size_t count) +{ + unsigned long val; + + if (kstrtoul(buf, 0, &val)) + return -EINVAL; + + if (val != 0 && val != 1) + return -EINVAL; + + INFO_MSG("debug %d", hid->hid_debug); + + return count; +} + +static ssize_t ufshid_sysfs_show_color(struct ufshid_dev *hid, char *buf) +{ + u32 attr_val; + int frag_level; + + if (ufshid_write_attr(hid, QUERY_ATTR_IDN_HID_OPERATION, + HID_OP_ANALYZE)) { + ERR_MSG("query HID_OPERATION fail"); + return -EINVAL; + } + + if (ufshid_read_attr(hid, QUERY_ATTR_IDN_HID_FRAG_LEVEL, &attr_val)) { + ERR_MSG("query HID_FRAG_LEVEL fail"); + return -EINVAL; + } + + frag_level = attr_val & HID_FRAG_LEVEL_MASK; + INFO_MSG("Frag_lv %d Freg_stat %d HID_need_exec %d", frag_level, + HID_FRAG_UPDATE_STAT(attr_val), + HID_EXECUTE_REQ_STAT(attr_val)); + + return snprintf(buf, PAGE_SIZE, "%s\n", + frag_level == HID_LEV_RED ? "RED" : + frag_level == HID_LEV_YELLOW ? "YELLOW" : + frag_level == HID_LEV_GREEN ? "GREEN" : + frag_level == HID_LEV_GRAY ? "GRAY" : "UNKNOWN"); +} + +#if defined(CONFIG_UFSHID_POC) +static ssize_t ufshid_sysfs_show_debug_op(struct ufshid_dev *hid, char *buf) +{ + u32 attr_val; + + if (ufshid_read_attr(hid, QUERY_ATTR_IDN_HID_OPERATION, &attr_val)) + return -EINVAL; + + INFO_MSG("hid_op %d", attr_val); + + return snprintf(buf, PAGE_SIZE, "%d\n", attr_val); +} + +static ssize_t ufshid_sysfs_store_debug_op(struct ufshid_dev *hid, + const char *buf, size_t count) +{ + unsigned long val; + + if (kstrtoul(buf, 0, &val)) + return -EINVAL; + + if (hid->hid_trigger) { + ERR_MSG("debug_op cannot change, current hid_trigger is ON"); + return -EINVAL; + } + + if (val >= HID_OP_MAX) + return -EINVAL; + + if (ufshid_write_attr(hid, QUERY_ATTR_IDN_HID_OPERATION, val)) + return -EINVAL; + + INFO_MSG("hid_op %ld is set!", val); + return count; +} + +static ssize_t ufshid_sysfs_show_block_suspend(struct ufshid_dev *hid, + char *buf) +{ + INFO_MSG("block suspend %d", hid->block_suspend); + + return snprintf(buf, PAGE_SIZE, "%d\n", hid->block_suspend); +} + +static ssize_t ufshid_sysfs_store_block_suspend(struct ufshid_dev *hid, + const char *buf, size_t count) +{ + unsigned long val; + struct ufs_hba *hba; + + if (kstrtoul(buf, 0, &val)) + return -EINVAL; + + if (val != 0 && val != 1) + return -EINVAL; + + hba = hid->ufsf->hba; + + if (hid->block_suspend ^ val) { + if (val) + ufshid_block_enter_suspend(hid); + else + ufshid_allow_enter_suspend(hid); + + INFO_MSG("[Before] block_suspend %d", hid->block_suspend); + hid->block_suspend = val; + INFO_MSG("[After] block_suspend %d", hid->block_suspend); + } else { + INFO_MSG("block_suspend %d. so it does not changed", + hid->block_suspend); + } + + return count; +} + +static ssize_t ufshid_sysfs_show_auto_hibern8_enable(struct ufshid_dev *hid, + char *buf) +{ + INFO_MSG("HCI auto hibern8 %d", hid->is_auto_enabled); + + return snprintf(buf, PAGE_SIZE, "%d\n", hid->is_auto_enabled); +} + +static ssize_t ufshid_sysfs_store_auto_hibern8_enable(struct ufshid_dev *hid, + const char *buf, + size_t count) +{ + unsigned long val; + + if (kstrtoul(buf, 0, &val)) + return -EINVAL; + + if (val != 0 && val != 1) + return -EINVAL; + + ufshid_auto_hibern8_enable(hid, val); + + return count; +} +#endif + +/* SYSFS DEFINE */ +#define define_sysfs_ro(_name) __ATTR(_name, 0444, \ + ufshid_sysfs_show_##_name, NULL) +#define define_sysfs_rw(_name) __ATTR(_name, 0644, \ + ufshid_sysfs_show_##_name, \ + ufshid_sysfs_store_##_name) + +static struct ufshid_sysfs_entry ufshid_sysfs_entries[] = { + define_sysfs_ro(version), + define_sysfs_ro(color), + + define_sysfs_rw(trigger), + define_sysfs_rw(trigger_interval), + + /* debug */ + define_sysfs_rw(debug), +#if defined(CONFIG_UFSHID_POC) + /* Attribute (RAW) */ + define_sysfs_rw(debug_op), + define_sysfs_rw(block_suspend), + define_sysfs_rw(auto_hibern8_enable), +#endif + __ATTR_NULL +}; + +static ssize_t ufshid_attr_show(struct kobject *kobj, struct attribute *attr, + char *page) +{ + struct ufshid_sysfs_entry *entry; + struct ufshid_dev *hid; + ssize_t error; + + entry = container_of(attr, struct ufshid_sysfs_entry, attr); + if (!entry->show) + return -EIO; + + hid = container_of(kobj, struct ufshid_dev, kobj); + if (ufshid_is_not_present(hid)) + return -ENODEV; + + mutex_lock(&hid->sysfs_lock); + error = entry->show(hid, page); + mutex_unlock(&hid->sysfs_lock); + + return error; +} + +static ssize_t ufshid_attr_store(struct kobject *kobj, struct attribute *attr, + const char *page, size_t length) +{ + struct ufshid_sysfs_entry *entry; + struct ufshid_dev *hid; + ssize_t error; + + entry = container_of(attr, struct ufshid_sysfs_entry, attr); + if (!entry->store) + return -EIO; + + hid = container_of(kobj, struct ufshid_dev, kobj); + if (ufshid_is_not_present(hid)) + return -ENODEV; + + mutex_lock(&hid->sysfs_lock); + error = entry->store(hid, page, length); + mutex_unlock(&hid->sysfs_lock); + + return error; +} + +static const struct sysfs_ops ufshid_sysfs_ops = { + .show = ufshid_attr_show, + .store = ufshid_attr_store, +}; + +static struct kobj_type ufshid_ktype = { + .sysfs_ops = &ufshid_sysfs_ops, + .release = NULL, +}; + +static int ufshid_create_sysfs(struct ufshid_dev *hid) +{ + struct device *dev = hid->ufsf->hba->dev; + struct ufshid_sysfs_entry *entry; + int err; + + hid->sysfs_entries = ufshid_sysfs_entries; + + kobject_init(&hid->kobj, &ufshid_ktype); + mutex_init(&hid->sysfs_lock); + + INFO_MSG("ufshid creates sysfs ufshid %p dev->kobj %p", + &hid->kobj, &dev->kobj); + + err = kobject_add(&hid->kobj, kobject_get(&dev->kobj), "ufshid"); + if (!err) { + for (entry = hid->sysfs_entries; entry->attr.name != NULL; + entry++) { + INFO_MSG("ufshid sysfs attr creates: %s", + entry->attr.name); + if (sysfs_create_file(&hid->kobj, &entry->attr)) + break; + } + INFO_MSG("ufshid sysfs adds uevent"); + kobject_uevent(&hid->kobj, KOBJ_ADD); + } + return err; +} + +static inline void ufshid_remove_sysfs(struct ufshid_dev *hid) +{ + kobject_uevent(&hid->kobj, KOBJ_REMOVE); + INFO_MSG("ufshid_dev removes sysfs %p", &hid->kobj); + kobject_del(&hid->kobj); +} diff --git a/drivers/scsi/ufs/ufshid.h b/drivers/scsi/ufs/ufshid.h new file mode 100644 index 000000000000..caaef4f7fdcf --- /dev/null +++ b/drivers/scsi/ufs/ufshid.h @@ -0,0 +1,143 @@ +/* + * Universal Flash Storage Host Initiated Defrag (UFS HID) + * + * Copyright (C) 2019-2019 Samsung Electronics Co., Ltd. + * + * Authors: + * Yongmyung Lee + * Jieon Seol + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * See the COPYING file in the top-level directory or visit + * + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * This program is provided "AS IS" and "WITH ALL FAULTS" and + * without warranty of any kind. You are solely responsible for + * determining the appropriateness of using and distributing + * the program and assume all risks associated with your exercise + * of rights with respect to the program, including but not limited + * to infringement of third party rights, the risks and costs of + * program errors, damage to or loss of data, programs or equipment, + * and unavailability or interruption of operations. Under no + * circumstances will the contributor of this Program be liable for + * any damages of any kind arising from your use or distribution of + * this program. + * + * The Linux Foundation chooses to take subject only to the GPLv2 + * license terms, and distributes only under these terms. + */ + +#ifndef _UFSHID_H_ +#define _UFSHID_H_ + +#include +#include +#include +#include +#include +#include + +#include "../../../block/blk.h" + +#define UFSHID_VER 0x0101 +#define UFSHID_DD_VER 0x010200 +#define UFSHID_DD_VER_POST "" + +#define UFS_FEATURE_SUPPORT_HID_BIT 0x400 + +#define HID_TRIGGER_WORKER_DELAY_MS_DEFAULT 2000 +#define HID_TRIGGER_WORKER_DELAY_MS_MIN 100 +#define HID_TRIGGER_WORKER_DELAY_MS_MAX 10000 + +#define HID_FRAG_LEVEL_MASK 0xF +#define HID_FRAG_UPDATE_STAT_SHIFT 30 +#define HID_EXECUTE_REQ_STAT_SHIFT 31 +#define HID_FRAG_UPDATE_STAT(val) ((val >> HID_FRAG_UPDATE_STAT_SHIFT) & 0x1) +#define HID_EXECUTE_REQ_STAT(val) ((val >> HID_EXECUTE_REQ_STAT_SHIFT) & 0x1) + +#define HID_AUTO_HIBERN8_DISABLE (FIELD_PREP(UFSHCI_AHIBERN8_TIMER_MASK, 0) | \ + FIELD_PREP(UFSHCI_AHIBERN8_SCALE_MASK, 3)) + + +#define HID_DEBUG(hid, msg, args...) \ + do { if (hid->hid_debug) \ + pr_err("%40s:%3d [%01d%02d%02d] " msg "\n", \ + __func__, __LINE__, \ + hid->hid_trigger, \ + atomic_read(&hid->ufsf->hba->dev->power.usage_count), \ + hid->ufsf->hba->clk_gating.active_reqs, ##args); \ + } while (0) + +enum UFSHID_STATE { + HID_NEED_INIT = 0, + HID_PRESENT = 1, + HID_FAILED = -2, + HID_RESET = -3, +}; + +enum { + HID_OP_DISABLE = 0, + HID_OP_ANALYZE = 1, + HID_OP_EXECUTE = 2, + HID_OP_MAX +}; + +enum { + HID_NOT_REQUIRED = 0, + HID_REQUIRED = 1 +}; + +enum { + HID_LEV_GRAY = 0, + HID_LEV_GREEN = 1, + HID_LEV_YELLOW = 2, + HID_LEV_RED = 3, +}; + +struct ufshid_dev { + struct ufsf_feature *ufsf; + + struct work_struct hid_reset_work; + + unsigned int hid_trigger; /* default value is false */ + struct delayed_work hid_trigger_work; + unsigned int hid_trigger_delay; + + bool is_auto_enabled; + + /* for sysfs */ + struct kobject kobj; + struct mutex sysfs_lock; + struct ufshid_sysfs_entry *sysfs_entries; + + /* for debug */ + bool hid_debug; +#if defined(CONFIG_UFSHID_POC) + bool block_suspend; +#endif +}; + +struct ufshid_sysfs_entry { + struct attribute attr; + ssize_t (*show)(struct ufshid_dev *hid, char *buf); + ssize_t (*store)(struct ufshid_dev *hid, const char *buf, size_t count); +}; + +int ufshid_get_state(struct ufsf_feature *ufsf); +void ufshid_set_state(struct ufsf_feature *ufsf, int state); +void ufshid_get_dev_info(struct ufsf_feature *ufsf, u8 *desc_buf); +void ufshid_set_init_state(struct ufsf_feature *ufsf); +void ufshid_init(struct ufsf_feature *ufsf); +void ufshid_reset(struct ufsf_feature *ufsf); +void ufshid_reset_host(struct ufsf_feature *ufsf); +void ufshid_remove(struct ufsf_feature *ufsf); +void ufshid_on_idle(struct ufsf_feature *ufsf); +#endif /* End of Header */ diff --git a/drivers/scsi/ufs/ufshpb.c b/drivers/scsi/ufs/ufshpb.c new file mode 100644 index 000000000000..825c04b07a8c --- /dev/null +++ b/drivers/scsi/ufs/ufshpb.c @@ -0,0 +1,3938 @@ +/* + * Universal Flash Storage Host Performance Booster + * + * Copyright (C) 2017-2018 Samsung Electronics Co., Ltd. + * Copyright (C) 2020 Oplus. All rights reserved. + * + * Authors: + * Yongmyung Lee + * Jinyoung Choi + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * See the COPYING file in the top-level directory or visit + * + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * This program is provided "AS IS" and "WITH ALL FAULTS" and + * without warranty of any kind. You are solely responsible for + * determining the appropriateness of using and distributing + * the program and assume all risks associated with your exercise + * of rights with respect to the program, including but not limited + * to infringement of third party rights, the risks and costs of + * program errors, damage to or loss of data, programs or equipment, + * and unavailability or interruption of operations. Under no + * circumstances will the contributor of this Program be liable for + * any damages of any kind arising from your use or distribution of + * this program. + * + * The Linux Foundation chooses to take subject only to the GPLv2 + * license terms, and distributes only under these terms. + */ + +#include "ufshcd.h" +#include "ufshpb.h" + +#define UFSHCD_REQ_SENSE_SIZE 18 + +static int ufshpb_create_sysfs(struct ufsf_feature *ufsf, + struct ufshpb_lu *hpb); +static void ufshpb_remove_sysfs(struct ufshpb_lu *hpb); + +static int create_hpbfn_enable_proc(void); +static void remove_hpbfn_enable_proc(void); + +static inline void +ufshpb_get_pos_from_lpn(struct ufshpb_lu *hpb, unsigned long lpn, int *rgn_idx, + int *srgn_idx, int *offset) +{ + int rgn_offset; + + *rgn_idx = lpn >> hpb->entries_per_rgn_shift; + rgn_offset = lpn & hpb->entries_per_rgn_mask; + *srgn_idx = rgn_offset >> hpb->entries_per_srgn_shift; + *offset = rgn_offset & hpb->entries_per_srgn_mask; +} + +inline int ufshpb_valid_srgn(struct ufshpb_region *rgn, + struct ufshpb_subregion *srgn) +{ + return rgn->rgn_state != HPB_RGN_INACTIVE && + srgn->srgn_state == HPB_SRGN_CLEAN; +} + +/* Must be held hpb_lock */ +static bool ufshpb_ppn_dirty_check(struct ufshpb_lu *hpb, unsigned long lpn, + int transfer_len) +{ + struct ufshpb_region *rgn; + struct ufshpb_subregion *srgn; + unsigned long cur_lpn = lpn; + int rgn_idx, srgn_idx, srgn_offset, find_size; + int scan_cnt = transfer_len; + + do { + ufshpb_get_pos_from_lpn(hpb, cur_lpn, &rgn_idx, &srgn_idx, + &srgn_offset); + rgn = hpb->rgn_tbl + rgn_idx; + srgn = rgn->srgn_tbl + srgn_idx; + + if (!ufshpb_valid_srgn(rgn, srgn)) + return true; + + if (unlikely(!srgn->mctx || !srgn->mctx->ppn_dirty)) + return true; + + if (hpb->entries_per_srgn < srgn_offset + scan_cnt) { + int cnt = hpb->entries_per_srgn - srgn_offset; + + find_size = hpb->entries_per_srgn; + scan_cnt -= cnt; + cur_lpn += cnt; + } else { + find_size = srgn_offset + scan_cnt; + scan_cnt = 0; + } + + srgn_offset = + find_next_bit((unsigned long *)srgn->mctx->ppn_dirty, + hpb->entries_per_srgn, srgn_offset); + + if (srgn_offset < hpb->entries_per_srgn) + return srgn_offset < find_size; + } while (scan_cnt); + + return false; +} + +static void ufshpb_set_read16_cmd(struct ufshpb_lu *hpb, + struct ufshcd_lrb *lrbp, + u64 ppn, + unsigned int transfer_len) +{ + unsigned char *cdb = lrbp->cmd->cmnd; + + cdb[0] = READ_16; + cdb[2] = lrbp->cmd->cmnd[2]; + cdb[3] = lrbp->cmd->cmnd[3]; + cdb[4] = lrbp->cmd->cmnd[4]; + cdb[5] = lrbp->cmd->cmnd[5]; + cdb[6] = GET_BYTE_7(ppn); + cdb[7] = GET_BYTE_6(ppn); + cdb[8] = GET_BYTE_5(ppn); + cdb[9] = GET_BYTE_4(ppn); + cdb[10] = GET_BYTE_3(ppn); + cdb[11] = GET_BYTE_2(ppn); + cdb[12] = GET_BYTE_1(ppn); + cdb[13] = GET_BYTE_0(ppn); + + if (lrbp->hpb_ctx_id < MAX_HPB_CONTEXT_ID) + cdb[14] = (1 << 7) | lrbp->hpb_ctx_id; + else + cdb[14] = UFSHPB_GROUP_NUMBER; + + cdb[15] = transfer_len; + + lrbp->cmd->cmd_len = MAX_CDB_SIZE; +} + +/* called with hpb_lock (irq) */ +static inline void +ufshpb_set_dirty_bits(struct ufshpb_lu *hpb, struct ufshpb_region *rgn, + struct ufshpb_subregion *srgn, int dword, int offset, + unsigned int cnt) +{ + const unsigned long mask = ((1UL << cnt) - 1) & 0xffffffff; + + if (rgn->rgn_state == HPB_RGN_INACTIVE) + return; + + BUG_ON(!srgn->mctx); + srgn->mctx->ppn_dirty[dword] |= (mask << offset); +} + +static inline void ufshpb_get_bit_offset(struct ufshpb_lu *hpb, int srgn_offset, + int *dword, int *offset) +{ + *dword = srgn_offset >> bits_per_dword_shift; + *offset = srgn_offset & bits_per_dword_mask; +} + +static void ufshpb_set_dirty(struct ufshpb_lu *hpb, struct ufshcd_lrb *lrbp, + int rgn_idx, int srgn_idx, int srgn_offset) +{ + struct ufshpb_region *rgn; + struct ufshpb_subregion *srgn; + int cnt, bit_cnt, bit_dword, bit_offset; + + cnt = blk_rq_sectors(lrbp->cmd->request) >> sects_per_blk_shift; + ufshpb_get_bit_offset(hpb, srgn_offset, &bit_dword, &bit_offset); + + do { + bit_cnt = min(cnt, BITS_PER_DWORD - bit_offset); + + rgn = hpb->rgn_tbl + rgn_idx; + srgn = rgn->srgn_tbl + srgn_idx; + + ufshpb_set_dirty_bits(hpb, rgn, srgn, bit_dword, bit_offset, + bit_cnt); + + bit_offset = 0; + bit_dword++; + + if (bit_dword == hpb->dwords_per_srgn) { + bit_dword = 0; + srgn_idx++; + + if (srgn_idx == hpb->srgns_per_rgn) { + srgn_idx = 0; + rgn_idx++; + } + } + cnt -= bit_cnt; + } while (cnt); + + BUG_ON(cnt < 0); +} + +static inline bool ufshpb_is_read_cmd(struct scsi_cmnd *cmd) +{ + if (cmd->cmnd[0] == READ_10 || cmd->cmnd[0] == READ_16) + return true; + + return false; +} + +static inline bool ufshpb_is_write_discard_lrbp(struct ufshcd_lrb *lrbp) +{ + if (lrbp->cmd->cmnd[0] == WRITE_10 || lrbp->cmd->cmnd[0] == WRITE_16 || + lrbp->cmd->cmnd[0] == UNMAP) + return true; + + return false; +} + +static u64 ufshpb_get_ppn(struct ufshpb_map_ctx *mctx, int pos, int *error) +{ + u64 *ppn_table; + struct page *page = NULL; + int index, offset; + + index = pos / HPB_ENTREIS_PER_OS_PAGE; + offset = pos % HPB_ENTREIS_PER_OS_PAGE; + + page = mctx->m_page[index]; + if (unlikely(!page)) { + *error = -ENOMEM; + ERR_MSG("mctx %p cannot get m_page", mctx); + return 0; + } + + ppn_table = page_address(page); + if (unlikely(!ppn_table)) { + *error = -ENOMEM; + ERR_MSG("mctx %p cannot get ppn_table vm", mctx); + return 0; + } + + return ppn_table[offset]; +} + +#if defined(CONFIG_HPB_ERR_INJECTION) +static u64 ufshpb_get_bitflip_ppn(struct ufshpb_lu *hpb, u64 ppn) +{ + return (ppn ^ hpb->err_injection_bitflip); +} + +static u64 ufshpb_get_offset_ppn(struct ufshpb_lu *hpb, u64 ppn) +{ + return (ppn + hpb->err_injection_offset); +} + +static u64 ufshpb_get_random_ppn(struct ufshpb_lu *hpb, u64 ppn) +{ + u64 random_ppn = 0; + + if (!hpb->err_injection_random) + return ppn; + + get_random_bytes(&random_ppn, sizeof(random_ppn)); + + return random_ppn; +} + +static u64 ufshpb_get_err_injection_ppn(struct ufshpb_lu *hpb, u64 ppn) +{ + u64 new_ppn = 0; + + if (hpb->err_injection_select == HPB_ERR_INJECTION_BITFLIP) + new_ppn = ufshpb_get_bitflip_ppn(hpb, ppn); + else if (hpb->err_injection_select == HPB_ERR_INJECTION_OFFSET) + new_ppn = ufshpb_get_offset_ppn(hpb, ppn); + else if (hpb->err_injection_select == HPB_ERR_INJECTION_RANDOM) + new_ppn = ufshpb_get_random_ppn(hpb, ppn); + + return new_ppn; +} +#endif + +inline int ufshpb_get_state(struct ufsf_feature *ufsf) +{ + return atomic_read(&ufsf->hpb_state); +} + +inline void ufshpb_set_state(struct ufsf_feature *ufsf, int state) +{ + atomic_set(&ufsf->hpb_state, state); +} + +static inline int ufshpb_lu_get(struct ufshpb_lu *hpb) +{ + if (!hpb || ufshpb_get_state(hpb->ufsf) != HPB_PRESENT) + return -ENODEV; + + kref_get(&hpb->ufsf->hpb_kref); + return 0; +} + +static inline void ufshpb_schedule_error_handler(struct kref *kref) +{ + struct ufsf_feature *ufsf; + + ufsf = container_of(kref, struct ufsf_feature, hpb_kref); + schedule_work(&ufsf->hpb_eh_work); +} + +static inline void ufshpb_lu_put(struct ufshpb_lu *hpb) +{ + kref_put(&hpb->ufsf->hpb_kref, ufshpb_schedule_error_handler); +} + +static void ufshpb_failed(struct ufshpb_lu *hpb, const char *f) +{ + ERR_MSG("ufshpb_driver failed. function (%s)", f); + ufshpb_set_state(hpb->ufsf, HPB_FAILED); + ufshpb_lu_put(hpb); +} + +static inline void ufshpb_put_pre_req(struct ufshpb_lu *hpb, + struct ufshpb_req *pre_req) +{ + list_add_tail(&pre_req->list_req, &hpb->lh_pre_req_free); + hpb->num_inflight_pre_req--; +} + +static struct ufshpb_req *ufshpb_get_pre_req(struct ufshpb_lu *hpb) +{ + struct ufshpb_req *pre_req; + + if (hpb->num_inflight_pre_req >= hpb->throttle_pre_req) { + HPB_DEBUG(hpb, "pre_req throttle. inflight %d throttle %d", + hpb->num_inflight_pre_req, hpb->throttle_pre_req); + return NULL; + } + + pre_req = list_first_entry_or_null(&hpb->lh_pre_req_free, + struct ufshpb_req, + list_req); + if (!pre_req) { + HPB_DEBUG(hpb, "There is no pre_req"); + return NULL; + } + + list_del_init(&pre_req->list_req); + hpb->num_inflight_pre_req++; + + return pre_req; +} + +static void ufshpb_pre_req_compl_fn(struct request *req, blk_status_t error) +{ + struct ufshpb_req *pre_req = (struct ufshpb_req *)req->end_io_data; + struct ufshpb_lu *hpb = pre_req->hpb; + unsigned long flags; + struct scsi_sense_hdr sshdr; + + if (error) { + ERR_MSG("block status %d", error); + scsi_normalize_sense(pre_req->sense, SCSI_SENSE_BUFFERSIZE, + &sshdr); + ERR_MSG("code %x sense_key %x asc %x ascq %x", + sshdr.response_code, + sshdr.sense_key, sshdr.asc, sshdr.ascq); + ERR_MSG("byte4 %x byte5 %x byte6 %x additional_len %x", + sshdr.byte4, sshdr.byte5, + sshdr.byte6, sshdr.additional_length); + } + + spin_lock_irqsave(&hpb->hpb_lock, flags); + ufshpb_put_pre_req(pre_req->hpb, pre_req); + spin_unlock_irqrestore(&hpb->hpb_lock, flags); + + ufshpb_lu_put(pre_req->hpb); +} + +static int ufshpb_prep_entry(struct ufshpb_req *pre_req, struct page *page) +{ + struct ufshpb_lu *hpb = pre_req->hpb; + struct ufshpb_region *rgn; + struct ufshpb_subregion *srgn; + u64 *addr; + u64 entry_ppn = 0; + unsigned long lpn = pre_req->wb.lpn; + int rgn_idx, srgn_idx, srgn_offset; + int i, error = 0; + unsigned long flags; + + addr = page_address(page); + + spin_lock_irqsave(&hpb->hpb_lock, flags); + for (i = 0; i < pre_req->wb.len; i++, lpn++) { + ufshpb_get_pos_from_lpn(hpb, lpn, &rgn_idx, &srgn_idx, + &srgn_offset); + + rgn = hpb->rgn_tbl + rgn_idx; + srgn = rgn->srgn_tbl + srgn_idx; + + if (!ufshpb_valid_srgn(rgn, srgn)) + goto mctx_error; + + BUG_ON(!srgn->mctx); + + entry_ppn = ufshpb_get_ppn(srgn->mctx, srgn_offset, &error); + if (error) + goto mctx_error; + +#if defined(CONFIG_HPB_ERR_INJECTION) + if (hpb->err_injection_select != HPB_ERR_INJECTION_DISABLE) + entry_ppn = + ufshpb_get_err_injection_ppn(hpb, entry_ppn); +#endif + + addr[i] = entry_ppn; + } + spin_unlock_irqrestore(&hpb->hpb_lock, flags); + return 0; +mctx_error: + spin_unlock_irqrestore(&hpb->hpb_lock, flags); + return -ENOMEM; +} + +static int ufshpb_pre_req_add_bio_page(struct request_queue *q, + struct ufshpb_req *pre_req) +{ + struct page *page = pre_req->wb.m_page; + struct bio *bio = pre_req->bio; + int ret; + + BUG_ON(!page); + + bio_reset(bio); + + ret = ufshpb_prep_entry(pre_req, page); + if (ret) + return ret; + + ret = bio_add_pc_page(q, bio, page, OS_PAGE_SIZE, 0); + if (ret != OS_PAGE_SIZE) { + ERR_MSG("bio_add_pc_page fail: %d", ret); + return -ENOMEM; + } + + return 0; +} + +static void ufshpb_init_cmd_errh(struct scsi_cmnd *cmd) +{ + cmd->serial_number = 0; + scsi_set_resid(cmd, 0); + memset(cmd->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE); + if (cmd->cmd_len == 0) + cmd->cmd_len = scsi_command_size(cmd->cmnd); +} + +static void ufshpb_pre_req_done(struct scsi_cmnd *cmd) +{ + blk_complete_request(cmd->request); +} + +static inline unsigned long ufshpb_get_lpn(struct request *rq) +{ + return blk_rq_pos(rq) / SECTORS_PER_BLOCK; +} + +static inline unsigned int ufshpb_get_len(struct request *rq) +{ + return blk_rq_sectors(rq) / SECTORS_PER_BLOCK; +} + +static inline unsigned int ufshpb_is_unaligned(struct request *rq) +{ + return blk_rq_sectors(rq) % SECTORS_PER_BLOCK; +} + +static inline int ufshpb_issue_ctx_id_ticket(struct ufshpb_lu *hpb) +{ + int hpb_ctx_id; + + hpb->ctx_id_ticket++; + if (hpb->ctx_id_ticket >= MAX_HPB_CONTEXT_ID) + hpb->ctx_id_ticket = 0; + hpb_ctx_id = hpb->ctx_id_ticket; + + return hpb_ctx_id; +} + +static inline void ufshpb_set_write_buf_cmd(unsigned char *cdb, + unsigned long lpn, unsigned int len, + int hpb_ctx_id) +{ + int len_byte = len * HPB_ENTRY_SIZE; + + cdb[0] = UFSHPB_WRITE_BUFFER; + cdb[1] = UFSHPB_WRITE_BUFFER_ID; + cdb[2] = GET_BYTE_3(lpn); + cdb[3] = GET_BYTE_2(lpn); + cdb[4] = GET_BYTE_1(lpn); + cdb[5] = GET_BYTE_0(lpn); + cdb[6] = (1 << 7) | hpb_ctx_id; + cdb[7] = GET_BYTE_1(len_byte); + cdb[8] = GET_BYTE_0(len_byte); + cdb[9] = 0x00; /* Control = 0x00 */ +} + +static void ufshpb_mimic_scsi_release_buffers(struct scsi_cmnd *cmd) +{ + if (cmd->sdb.table.nents) + sg_free_table_chained(&cmd->sdb.table, false); + + memset(&cmd->sdb, 0, sizeof(cmd->sdb)); + + if (scsi_prot_sg_count(cmd)) + sg_free_table_chained(&cmd->prot_sdb->table, false); +} + +static inline void ufshpb_mimic_scsi_dispatch_cmd(struct scsi_cmnd *cmd) +{ + atomic_inc(&cmd->device->iorequest_cnt); + + scsi_log_send(cmd); + + cmd->scsi_done = ufshpb_pre_req_done; +} + +static int ufshpb_mimic_scsi_request_fn(struct ufshpb_lu *hpb, + struct request *req) +{ + struct request_queue *q = req->q; + struct scsi_device *sdev = q->queuedata; + struct Scsi_Host *shost = sdev->host; + struct scsi_cmnd *cmd; + unsigned long flags; + unsigned int busy; + int ret = 0; + + spin_lock_irqsave(q->queue_lock, flags); + req->rq_flags |= RQF_STARTED; + + ret = q->prep_rq_fn(q, req); + if (unlikely(ret != BLKPREP_OK)) { + HPB_DEBUG(hpb, "scsi_prep_fn is fail"); + ret = -EIO; + goto prep_err; + } + cmd = req->special; + if (unlikely(!cmd)) + BUG(); + + busy = atomic_inc_return(&sdev->device_busy) - 1; + if (busy >= sdev->queue_depth) { + ret = -EAGAIN; + goto finish_cmd; + } + + /* lh_pre_req_free list is dummy head for blk_dequeue_request() */ + list_add_tail(&req->queuelist, &hpb->lh_pre_req_dummy); + ret = blk_queue_start_tag(q, req); + if (ret) { + list_del_init(&req->queuelist); + ret = -EAGAIN; + goto finish_cmd; + } + spin_unlock_irqrestore(q->queue_lock, flags); + + /* + * UFS device has multi luns, so starget is not used. + * In case of UFS, starget->can_queue <= 0. + */ + if (unlikely(scsi_target(sdev)->can_queue > 0)) + atomic_inc(&scsi_target(sdev)->target_busy); + atomic_inc(&shost->host_busy); + + ufshpb_init_cmd_errh(cmd); + + ufshpb_mimic_scsi_dispatch_cmd(cmd); + + return ret; +finish_cmd: + ufshpb_mimic_scsi_release_buffers(cmd); + scsi_put_command(cmd); + put_device(&sdev->sdev_gendev); + req->special = NULL; + atomic_dec(&sdev->device_busy); +prep_err: + spin_unlock_irqrestore(q->queue_lock, flags); + return ret; +} + +static int ufshpb_set_pre_req(struct ufshpb_lu *hpb, struct scsi_cmnd *cmd, + struct ufshpb_req *pre_req, int hpb_ctx_id) +{ + struct scsi_device *sdev = cmd->device; + struct request_queue *q = sdev->request_queue; + struct request *req; + struct scsi_request *rq; + struct scsi_cmnd *scmd; + struct bio *bio = pre_req->bio; + int ret = 0; + + pre_req->hpb = hpb; + pre_req->wb.lpn = ufshpb_get_lpn(cmd->request); + pre_req->wb.len = ufshpb_get_len(cmd->request); + ret = ufshpb_pre_req_add_bio_page(q, pre_req); + if (ret) + return ret; + + req = pre_req->req; + + /* + * blk_init_rl() -> alloc_request_size(). + * q->init_rq_fn = scsi_old_init_rq behavior. + */ + scmd = (struct scsi_cmnd *)(req + 1); + memset(scmd, 0, sizeof(*scmd)); + scmd->sense_buffer = pre_req->sense; + scmd->req.sense = scmd->sense_buffer; + + /* blk_get_request behavior */ + blk_rq_init(q, req); + q->initialize_rq_fn(req); + + /* 1. request setup */ + blk_rq_append_bio(req, &bio); + req->cmd_flags = REQ_OP_WRITE | REQ_SYNC | REQ_OP_SCSI_OUT; + req->rq_flags = RQF_QUIET | RQF_PREEMPT; + req->timeout = msecs_to_jiffies(30000); + req->end_io_data = (void *)pre_req; + req->end_io = ufshpb_pre_req_compl_fn; + + /* 2. scsi_request setup */ + rq = scsi_req(req); + ufshpb_set_write_buf_cmd(rq->cmd, pre_req->wb.lpn, pre_req->wb.len, + hpb_ctx_id); + rq->cmd_len = scsi_command_size(rq->cmd); + + ret = ufshpb_mimic_scsi_request_fn(hpb, req); + + return ret; +} + +static inline bool ufshpb_is_support_chunk(int transfer_len) +{ + return transfer_len <= HPB_MULTI_CHUNK_HIGH; +} + +static int ufshpb_check_pre_req_cond(struct ufshpb_lu *hpb, + struct scsi_cmnd *cmd) +{ + struct request *rq = cmd->request; + unsigned long flags; + unsigned int transfer_len; + unsigned int lpn; + + if (!ufshpb_is_read_cmd(cmd)) + return -EINVAL; + + if (ufshpb_is_unaligned(rq)) + return -EINVAL; + + transfer_len = ufshpb_get_len(rq); + if (!transfer_len) + return -EINVAL; + + if (!ufshpb_is_support_chunk(transfer_len)) + return -EINVAL; + + /* + * WRITE_BUFFER CMD support 36K (len=9) ~ 512K (len=128) default. + * it is possible to change range of transfer_len through sysfs. + */ + if (transfer_len < hpb->pre_req_min_tr_len || + transfer_len > hpb->pre_req_max_tr_len) + return -EINVAL; + + lpn = ufshpb_get_lpn(cmd->request); + + spin_lock_irqsave(&hpb->hpb_lock, flags); + if (ufshpb_ppn_dirty_check(hpb, lpn, transfer_len)) { + spin_unlock_irqrestore(&hpb->hpb_lock, flags); + return -EINVAL; + } + spin_unlock_irqrestore(&hpb->hpb_lock, flags); + + return 0; +} + +void ufshpb_end_pre_req(struct ufsf_feature *ufsf, struct request *req) +{ + struct scsi_cmnd *scmd = (struct scsi_cmnd *)(req + 1); + + set_host_byte(scmd, DID_OK); + + scmd->scsi_done(scmd); +} + +int ufshpb_prepare_pre_req(struct ufsf_feature *ufsf, struct scsi_cmnd *cmd, + int lun) +{ + struct ufs_hba *hba = ufsf->hba; + struct ufshpb_lu *hpb; + struct ufshpb_req *pre_req; + struct ufshcd_lrb *add_lrbp; + struct ufshcd_lrb *orig_lrbp = &hba->lrb[cmd->request->tag]; + struct scsi_cmnd *pre_cmd; + unsigned long flags; + int add_tag, hpb_ctx_id; + int ret = 0; + + /* WKLU could not be HPB-LU */ + if (!ufsf_is_valid_lun(lun)) + return -ENODEV; + + hpb = ufsf->hpb_lup[lun]; + ret = ufshpb_lu_get(hpb); + if (unlikely(ret)) + return ret; + + if (hpb->force_disable) { + ret = -ENODEV; + goto put_hpb; + } + + ret = ufshpb_check_pre_req_cond(hpb, cmd); + if (ret) + goto put_hpb; + + spin_lock_irqsave(&hpb->hpb_lock, flags); + pre_req = ufshpb_get_pre_req(hpb); + if (!pre_req) { + spin_unlock_irqrestore(&hpb->hpb_lock, flags); + ret = -ENOMEM; + goto put_hpb; + } + + hpb_ctx_id = ufshpb_issue_ctx_id_ticket(hpb); + spin_unlock_irqrestore(&hpb->hpb_lock, flags); + + ret = ufshpb_set_pre_req(hpb, cmd, pre_req, hpb_ctx_id); + if (ret) + goto put_pre_req; + + add_tag = pre_req->req->tag; + if (test_and_set_bit_lock(add_tag, &hba->lrb_in_use)) { + ufshpb_end_pre_req(ufsf, pre_req->req); + return -EIO; + } + + add_lrbp = &hba->lrb[add_tag]; + WARN_ON(add_lrbp->cmd); + + pre_cmd = pre_req->req->special; + add_lrbp->cmd = pre_cmd; + add_lrbp->sense_bufflen = UFSHCD_REQ_SENSE_SIZE; + add_lrbp->sense_buffer = pre_cmd->sense_buffer; + add_lrbp->task_tag = add_tag; + add_lrbp->lun = lun; + add_lrbp->intr_cmd = !ufshcd_is_intr_aggr_allowed(hba) ? true : false; + add_lrbp->req_abort_skip = false; + + orig_lrbp->hpb_ctx_id = hpb_ctx_id; + + return add_tag; +put_pre_req: + spin_lock_irqsave(&hpb->hpb_lock, flags); + ufshpb_put_pre_req(hpb, pre_req); + spin_unlock_irqrestore(&hpb->hpb_lock, flags); +put_hpb: + ufshpb_lu_put(hpb); + return ret; +} + +int ufshpb_prepare_add_lrbp(struct ufsf_feature *ufsf, int add_tag) +{ + struct ufs_hba *hba = ufsf->hba; + struct ufshcd_lrb *add_lrbp; + struct scsi_cmnd *pre_cmd; + int err = 0; + + add_lrbp = &hba->lrb[add_tag]; + + pre_cmd = add_lrbp->cmd; + + err = ufshcd_hold(hba, true); + if (err) + goto hold_err; + + err = ufshcd_hibern8_hold(hba, true); + if (err) { + ufshcd_release(hba, true); + goto hold_err; + } + + /* Vote PM QoS for the pre_req */ + ufshcd_vops_pm_qos_req_start(hba, pre_cmd->request); + + err = ufshcd_comp_scsi_upiu(hba, add_lrbp); + if (err) + goto map_err; + + err = ufshcd_map_sg(hba, add_lrbp); + if (err) + goto map_err; + + return 0; + + scsi_dma_unmap(pre_cmd); +map_err: + ufshcd_vops_pm_qos_req_end(hba, pre_cmd->request, true); + ufshcd_release_all(hba); +hold_err: + add_lrbp->cmd = NULL; + clear_bit_unlock(add_tag, &hba->lrb_in_use); + ufsf_hpb_end_pre_req(&hba->ufsf, pre_cmd->request); + return -EIO; +} + +/* routine : READ10 -> HPB_READ */ +void ufshpb_prep_fn(struct ufsf_feature *ufsf, struct ufshcd_lrb *lrbp) +{ + struct ufshpb_lu *hpb; + struct ufshpb_region *rgn; + struct ufshpb_subregion *srgn; + struct request *rq; + u64 ppn = 0; + unsigned long lpn, flags; + int transfer_len = TRANSFER_LEN; + int rgn_idx, srgn_idx, srgn_offset, ret, error = 0; + bool span_flag = false; + + /* WKLU could not be HPB-LU */ + if (!lrbp || !ufsf_is_valid_lun(lrbp->lun)) + return; + + if (!ufshpb_is_write_discard_lrbp(lrbp) && + !ufshpb_is_read_cmd(lrbp->cmd)) + return; + + rq = lrbp->cmd->request; + hpb = ufsf->hpb_lup[lrbp->lun]; + ret = ufshpb_lu_get(hpb); + if (unlikely(ret)) + return; + + if (hpb->force_disable) { + if (ufshpb_is_read_cmd(lrbp->cmd)) + TMSG(ufsf, hpb->lun, "%llu + %u READ_10", + (unsigned long long) blk_rq_pos(rq), + (unsigned int) blk_rq_sectors(rq)); + goto put_hpb; + } + + lpn = ufshpb_get_lpn(rq); + if (abs(lpn-hpb->lpn_last) > 1024) { + ufsf_para.span++; + span_flag = true; + } + hpb->lpn_last = lpn; + ufshpb_get_pos_from_lpn(hpb, lpn, &rgn_idx, &srgn_idx, &srgn_offset); + rgn = hpb->rgn_tbl + rgn_idx; + srgn = rgn->srgn_tbl + srgn_idx; + + /* + * If cmd type is WRITE, bitmap set to dirty. + */ + if (ufshpb_is_write_discard_lrbp(lrbp)) { + spin_lock_irqsave(&hpb->hpb_lock, flags); + if (rgn->rgn_state == HPB_RGN_INACTIVE) { + spin_unlock_irqrestore(&hpb->hpb_lock, flags); + goto put_hpb; + } + ufshpb_set_dirty(hpb, lrbp, rgn_idx, srgn_idx, srgn_offset); + spin_unlock_irqrestore(&hpb->hpb_lock, flags); + goto put_hpb; + } + + if (!ufshpb_is_read_cmd(lrbp->cmd)) + goto put_hpb; + + if (unlikely(ufshpb_is_unaligned(rq))) { + TMSG_CMD(hpb, "READ_10 not aligned 4KB", rq, rgn_idx, srgn_idx); + goto put_hpb; + } + + transfer_len = ufshpb_get_len(rq); + if (unlikely(!transfer_len)) + goto put_hpb; + + if (!ufshpb_is_support_chunk(transfer_len)) { + TMSG_CMD(hpb, "READ_10 doesn't support chunk size", + rq, rgn_idx, srgn_idx); + goto put_hpb; + } + + spin_lock_irqsave(&hpb->hpb_lock, flags); + if (ufshpb_ppn_dirty_check(hpb, lpn, transfer_len)) { + atomic64_inc(&hpb->miss); + ufsf_para.miss++; + TMSG_CMD(hpb, "READ_10 E_D", rq, rgn_idx, srgn_idx); + spin_unlock_irqrestore(&hpb->hpb_lock, flags); + goto put_hpb; + } + + ppn = ufshpb_get_ppn(srgn->mctx, srgn_offset, &error); +#if defined(CONFIG_HPB_ERR_INJECTION) + if (hpb->err_injection_select != HPB_ERR_INJECTION_DISABLE) + ppn = ufshpb_get_err_injection_ppn(hpb, ppn); +#endif + spin_unlock_irqrestore(&hpb->hpb_lock, flags); + if (unlikely(error)) { + ERR_MSG("get_ppn failed.. err %d region %d subregion %d", + error, rgn_idx, srgn_idx); + ufshpb_lu_put(hpb); + goto wakeup_ee_worker; + } + + ufshpb_set_read16_cmd(hpb, lrbp, ppn, transfer_len); + TMSG(ufsf, hpb->lun, "%llu + %u HPB_READ %d - %d context_id %d", + (unsigned long long) blk_rq_pos(lrbp->cmd->request), + (unsigned int) blk_rq_sectors(lrbp->cmd->request), rgn_idx, + srgn_idx, lrbp->hpb_ctx_id); + + atomic64_inc(&hpb->hit); + ufsf_para.hit++; + if(span_flag) + ufsf_para.span_hit++; + if (transfer_len == HPB_4_CHUNK_LEN) + ufsf_para.hit_4k++; + else if (transfer_len <= HPB_32_CHUNK_LEN) + ufsf_para.hit_8_32k++; + +put_hpb: + ufshpb_lu_put(hpb); + return; +wakeup_ee_worker: + ufshpb_failed(hpb, __func__); +} + +static inline void ufshpb_put_map_req(struct ufshpb_lu *hpb, + struct ufshpb_req *map_req) +{ + list_add_tail(&map_req->list_req, &hpb->lh_map_req_free); + hpb->num_inflight_map_req--; +} + +static struct ufshpb_req *ufshpb_get_map_req(struct ufshpb_lu *hpb) +{ + struct ufshpb_req *map_req; + + if (hpb->num_inflight_map_req >= hpb->throttle_map_req) { + HPB_DEBUG(hpb, "map_req throttle. inflight %d throttle %d", + hpb->num_inflight_map_req, hpb->throttle_map_req); + return NULL; + } + + map_req = list_first_entry_or_null(&hpb->lh_map_req_free, + struct ufshpb_req, list_req); + if (!map_req) { + HPB_DEBUG(hpb, "There is no map_req"); + return NULL; + } + + list_del_init(&map_req->list_req); + hpb->num_inflight_map_req++; + + return map_req; +} + +static int ufshpb_clean_dirty_bitmap(struct ufshpb_lu *hpb, + struct ufshpb_subregion *srgn) +{ + struct ufshpb_region *rgn; + + BUG_ON(!srgn->mctx); + + rgn = hpb->rgn_tbl + srgn->rgn_idx; + + if (rgn->rgn_state == HPB_RGN_INACTIVE) { + HPB_DEBUG(hpb, "%d - %d evicted", srgn->rgn_idx, + srgn->srgn_idx); + return -EINVAL; + } + + memset(srgn->mctx->ppn_dirty, 0x00, + hpb->entries_per_srgn >> bits_per_byte_shift); + + return 0; +} + +static void ufshpb_clean_active_subregion(struct ufshpb_lu *hpb, + struct ufshpb_subregion *srgn) +{ + struct ufshpb_region *rgn; + + BUG_ON(!srgn->mctx); + + rgn = hpb->rgn_tbl + srgn->rgn_idx; + + if (rgn->rgn_state == HPB_RGN_INACTIVE) { + HPB_DEBUG(hpb, "%d - %d evicted", srgn->rgn_idx, + srgn->srgn_idx); + return; + } + srgn->srgn_state = HPB_SRGN_CLEAN; +} + +static void ufshpb_error_active_subregion(struct ufshpb_lu *hpb, + struct ufshpb_subregion *srgn) +{ + struct ufshpb_region *rgn; + + BUG_ON(!srgn->mctx); + + rgn = hpb->rgn_tbl + srgn->rgn_idx; + + if (rgn->rgn_state == HPB_RGN_INACTIVE) { + ERR_MSG("%d - %d evicted", srgn->rgn_idx, srgn->srgn_idx); + return; + } + srgn->srgn_state = HPB_SRGN_DIRTY; +} + +static void ufshpb_check_ppn(struct ufshpb_lu *hpb, int rgn_idx, int srgn_idx, + struct ufshpb_map_ctx *mctx, const char *str) +{ + int error = 0; + u64 val[2]; + + BUG_ON(!mctx); + + val[0] = ufshpb_get_ppn(mctx, 0, &error); + if (!error) + val[1] = ufshpb_get_ppn(mctx, hpb->entries_per_srgn - 1, + &error); + if (error) + val[0] = val[1] = 0; + + HPB_DEBUG(hpb, "%s READ BUFFER %d - %d ( %llx ~ %llx )", str, rgn_idx, + srgn_idx, val[0], val[1]); +} + +static void ufshpb_map_compl_process(struct ufshpb_req *map_req) +{ + struct ufshpb_lu *hpb = map_req->hpb; + struct ufshpb_subregion *srgn; + unsigned long flags; + + srgn = hpb->rgn_tbl[map_req->rb.rgn_idx].srgn_tbl + + map_req->rb.srgn_idx; + + if (hpb->debug) + ufshpb_check_ppn(hpb, srgn->rgn_idx, srgn->srgn_idx, srgn->mctx, + "COMPL"); + + TMSG(hpb->ufsf, hpb->lun, "Noti: C RB %d - %d", map_req->rb.rgn_idx, + map_req->rb.srgn_idx); + + spin_lock_irqsave(&hpb->hpb_lock, flags); + ufshpb_clean_active_subregion(hpb, srgn); + spin_unlock_irqrestore(&hpb->hpb_lock, flags); +} + +static void ufshpb_update_active_info(struct ufshpb_lu *hpb, int rgn_idx, + int srgn_idx) +{ + struct ufshpb_region *rgn; + struct ufshpb_subregion *srgn; + + rgn = hpb->rgn_tbl + rgn_idx; + srgn = rgn->srgn_tbl + srgn_idx; + + list_del_init(&rgn->list_inact_rgn); + + if (list_empty(&srgn->list_act_srgn)) + list_add_tail(&srgn->list_act_srgn, &hpb->lh_act_srgn); +} + +static void ufshpb_update_inactive_info(struct ufshpb_lu *hpb, int rgn_idx) +{ + struct ufshpb_region *rgn; + struct ufshpb_subregion *srgn; + int srgn_idx; + + rgn = hpb->rgn_tbl + rgn_idx; + + for (srgn_idx = 0; srgn_idx < rgn->srgn_cnt; srgn_idx++) { + srgn = rgn->srgn_tbl + srgn_idx; + + list_del_init(&srgn->list_act_srgn); + } + + if (list_empty(&rgn->list_inact_rgn)) + list_add_tail(&rgn->list_inact_rgn, &hpb->lh_inact_rgn); +} + +static int ufshpb_map_req_error(struct ufshpb_req *map_req) +{ + struct ufshpb_lu *hpb = map_req->hpb; + struct ufshpb_region *rgn; + struct ufshpb_subregion *srgn; + struct scsi_sense_hdr sshdr; + unsigned long flags; + + rgn = hpb->rgn_tbl + map_req->rb.rgn_idx; + srgn = rgn->srgn_tbl + map_req->rb.srgn_idx; + + scsi_normalize_sense(map_req->sense, SCSI_SENSE_BUFFERSIZE, &sshdr); + + ERR_MSG("code %x sense_key %x asc %x ascq %x", sshdr.response_code, + sshdr.sense_key, sshdr.asc, sshdr.ascq); + ERR_MSG("byte4 %x byte5 %x byte6 %x additional_len %x", sshdr.byte4, + sshdr.byte5, sshdr.byte6, sshdr.additional_length); + + if (sshdr.sense_key != ILLEGAL_REQUEST) + return 0; + + spin_lock_irqsave(&hpb->hpb_lock, flags); + if (rgn->rgn_state == HPB_RGN_PINNED) { + if (sshdr.asc == 0x06 && sshdr.ascq == 0x01) { + HPB_DEBUG(hpb, "retry pinned rb %d - %d", + map_req->rb.rgn_idx, map_req->rb.srgn_idx); + + spin_unlock_irqrestore(&hpb->hpb_lock, flags); + spin_lock(&hpb->retry_list_lock); + list_add_tail(&map_req->list_req, + &hpb->lh_map_req_retry); + spin_unlock(&hpb->retry_list_lock); + + schedule_delayed_work(&hpb->retry_work, + msecs_to_jiffies(RETRY_DELAY_MS)); + return -EAGAIN; + } + HPB_DEBUG(hpb, "pinned rb %d - %d(dirty)", + map_req->rb.rgn_idx, map_req->rb.srgn_idx); + + ufshpb_error_active_subregion(hpb, srgn); + spin_unlock_irqrestore(&hpb->hpb_lock, flags); + } else { + ufshpb_error_active_subregion(hpb, srgn); + + spin_unlock_irqrestore(&hpb->hpb_lock, flags); + + spin_lock_irqsave(&hpb->rsp_list_lock, flags); + ufshpb_update_inactive_info(hpb, map_req->rb.rgn_idx); + spin_unlock_irqrestore(&hpb->rsp_list_lock, flags); + + HPB_DEBUG(hpb, "Non-pinned rb %d will be inactive", + map_req->rb.rgn_idx); + + schedule_work(&hpb->task_work); + } + + return 0; +} + +#ifdef CONFIG_PM +static inline void ufshpb_mimic_blk_pm_put_request(struct request *rq) +{ + if (rq->q->dev && !(rq->rq_flags & RQF_PM) && !--rq->q->nr_pending) + pm_runtime_mark_last_busy(rq->q->dev); +} +#endif + +/* routine : map_req compl */ +static void ufshpb_map_req_compl_fn(struct request *req, blk_status_t error) +{ + struct ufshpb_req *map_req = (struct ufshpb_req *) req->end_io_data; + struct ufshpb_lu *hpb = map_req->hpb; + unsigned long flags; + int ret; + +#ifdef CONFIG_PM + ufshpb_mimic_blk_pm_put_request(req); +#endif + if (ufshpb_get_state(hpb->ufsf) != HPB_PRESENT) + goto free_map_req; + + if (error) { + ERR_MSG("COMP_NOTI: RB number %d ( %d - %d )", error, + map_req->rb.rgn_idx, map_req->rb.srgn_idx); + + ret = ufshpb_map_req_error(map_req); + if (ret) + goto retry_map_req; + } else + ufshpb_map_compl_process(map_req); + +free_map_req: + spin_lock_irqsave(&hpb->hpb_lock, flags); + ufshpb_put_map_req(map_req->hpb, map_req); + spin_unlock_irqrestore(&hpb->hpb_lock, flags); +retry_map_req: + scsi_device_put(hpb->ufsf->sdev_ufs_lu[hpb->lun]); + ufshpb_lu_put(hpb); +} + +static inline void ufshpb_set_read_buf_cmd(unsigned char *cdb, int rgn_idx, + int srgn_idx, int srgn_mem_size) +{ + cdb[0] = UFSHPB_READ_BUFFER; + cdb[1] = UFSHPB_READ_BUFFER_ID; + cdb[2] = GET_BYTE_1(rgn_idx); + cdb[3] = GET_BYTE_0(rgn_idx); + cdb[4] = GET_BYTE_1(srgn_idx); + cdb[5] = GET_BYTE_0(srgn_idx); + cdb[6] = GET_BYTE_2(srgn_mem_size); + cdb[7] = GET_BYTE_1(srgn_mem_size); + cdb[8] = GET_BYTE_0(srgn_mem_size); + cdb[9] = 0x00; +} + +static int ufshpb_map_req_add_bio_page(struct ufshpb_lu *hpb, + struct request_queue *q, struct bio *bio, + struct ufshpb_map_ctx *mctx) +{ + struct page *page = NULL; + int i, ret = 0; + + bio_reset(bio); + + for (i = 0; i < hpb->mpages_per_srgn; i++) { + /* virt_to_page(p + (OS_PAGE_SIZE * i)); */ + page = mctx->m_page[i]; + if (!page) + return -ENOMEM; + + ret = bio_add_pc_page(q, bio, page, hpb->mpage_bytes, 0); + + if (ret != hpb->mpage_bytes) { + ERR_MSG("bio_add_pc_page fail: %d", ret); + return -ENOMEM; + } + } + + return 0; +} + +static int ufshpb_execute_map_req(struct ufshpb_lu *hpb, + struct ufshpb_req *map_req) +{ + struct scsi_device *sdev; + struct request_queue *q; + struct request *req; + struct scsi_cmnd *scmd; + struct bio *bio = map_req->bio; + struct scsi_request *rq; + int ret = 0; + + sdev = hpb->ufsf->sdev_ufs_lu[hpb->lun]; + if (!sdev) { + ERR_MSG("cannot find scsi_device"); + return -ENODEV; + } + + ret = ufsf_get_scsi_device(hpb->ufsf->hba, sdev); + if (ret) + return ret; + + q = sdev->request_queue; + + ret = ufshpb_map_req_add_bio_page(hpb, q, bio, map_req->rb.mctx); + if (ret) { + scsi_device_put(sdev); + return ret; + } + + req = map_req->req; + + /* + * blk_init_rl() -> alloc_request_size(). + * q->init_rq_fn = scsi_old_init_rq behavior. + */ + scmd = (struct scsi_cmnd *)(req + 1); + memset(scmd, 0, sizeof(*scmd)); + scmd->sense_buffer = map_req->sense; + scmd->req.sense = scmd->sense_buffer; + + /* blk_get_request behavior */ + blk_rq_init(q, req); + q->initialize_rq_fn(req); + + /* 1. request setup */ + blk_rq_append_bio(req, &bio); /* req->__data_len is setted */ + req->cmd_flags = REQ_OP_READ | REQ_OP_SCSI_IN; + req->rq_flags = RQF_QUIET | RQF_PREEMPT; + req->timeout = msecs_to_jiffies(30000); + req->end_io_data = (void *)map_req; + + /* 2. scsi_request setup */ + rq = scsi_req(req); + ufshpb_set_read_buf_cmd(rq->cmd, map_req->rb.rgn_idx, + map_req->rb.srgn_idx, hpb->srgn_mem_size); + rq->cmd_len = scsi_command_size(rq->cmd); + + if (hpb->debug) + ufshpb_check_ppn(hpb, map_req->rb.rgn_idx, map_req->rb.srgn_idx, + map_req->rb.mctx, "ISSUE"); + + TMSG(hpb->ufsf, hpb->lun, "Noti: I RB %d - %d", map_req->rb.rgn_idx, + map_req->rb.srgn_idx); + + blk_execute_rq_nowait(q, NULL, req, 1, ufshpb_map_req_compl_fn); + + atomic64_inc(&hpb->map_req_cnt); + ufsf_para.map_req++; + + return 0; +} + +static inline void ufshpb_set_map_req(struct ufshpb_lu *hpb, int rgn_idx, + int srgn_idx, struct ufshpb_map_ctx *mctx, + struct ufshpb_req *map_req) +{ + map_req->hpb = hpb; + map_req->rb.rgn_idx = rgn_idx; + map_req->rb.srgn_idx = srgn_idx; + map_req->rb.mctx = mctx; + map_req->rb.lun = hpb->lun; +} + +static struct ufshpb_map_ctx *ufshpb_get_map_ctx(struct ufshpb_lu *hpb, + int *err) +{ + struct ufshpb_map_ctx *mctx; + + mctx = list_first_entry_or_null(&hpb->lh_map_ctx_free, + struct ufshpb_map_ctx, list_table); + if (mctx) { + list_del_init(&mctx->list_table); + hpb->debug_free_table--; + return mctx; + } + *err = -ENOMEM; + return NULL; +} + +static inline void ufshpb_add_lru_info(struct victim_select_info *lru_info, + struct ufshpb_region *rgn) +{ + rgn->rgn_state = HPB_RGN_ACTIVE; + list_add_tail(&rgn->list_lru_rgn, &lru_info->lh_lru_rgn); + atomic64_inc(&lru_info->active_cnt); + ufsf_para.rgn_act++; +} + +static inline int ufshpb_add_region(struct ufshpb_lu *hpb, + struct ufshpb_region *rgn) +{ + struct victim_select_info *lru_info; + int srgn_idx; + int err = 0; + + lru_info = &hpb->lru_info; + + for (srgn_idx = 0; srgn_idx < rgn->srgn_cnt; srgn_idx++) { + struct ufshpb_subregion *srgn; + + srgn = rgn->srgn_tbl + srgn_idx; + + srgn->mctx = ufshpb_get_map_ctx(hpb, &err); + if (!srgn->mctx) { + HPB_DEBUG(hpb, "get mctx err %d srgn %d free_table %d", + err, srgn_idx, hpb->debug_free_table); + goto out; + } + + srgn->srgn_state = HPB_SRGN_DIRTY; + } + HPB_DEBUG(hpb, "\x1b[44m\x1b[32m E->active region: %d \x1b[0m", + rgn->rgn_idx); + TMSG(hpb->ufsf, hpb->lun, "Noti: ACT RG: %d", rgn->rgn_idx); + + ufshpb_add_lru_info(lru_info, rgn); +out: + return err; +} + +static inline void ufshpb_put_map_ctx(struct ufshpb_lu *hpb, + struct ufshpb_map_ctx *mctx) +{ + list_add(&mctx->list_table, &hpb->lh_map_ctx_free); + hpb->debug_free_table++; +} + +static inline void ufshpb_purge_active_subregion(struct ufshpb_lu *hpb, + struct ufshpb_subregion *srgn, + int state) +{ + if (state == HPB_SRGN_UNUSED) { + ufshpb_put_map_ctx(hpb, srgn->mctx); + srgn->mctx = NULL; + } + + srgn->srgn_state = state; +} + +static inline void ufshpb_cleanup_lru_info(struct victim_select_info *lru_info, + struct ufshpb_region *rgn) +{ + list_del_init(&rgn->list_lru_rgn); + rgn->rgn_state = HPB_RGN_INACTIVE; + atomic64_dec(&lru_info->active_cnt); + ufsf_para.rgn_act--; +} + +static void __ufshpb_evict_region(struct ufshpb_lu *hpb, + struct ufshpb_region *rgn) +{ + struct victim_select_info *lru_info; + struct ufshpb_subregion *srgn; + int srgn_idx; + + lru_info = &hpb->lru_info; + + HPB_DEBUG(hpb, "\x1b[41m\x1b[33m C->EVICT region: %d \x1b[0m", + rgn->rgn_idx); + TMSG(hpb->ufsf, hpb->lun, "Noti: EVIC RG: %d", rgn->rgn_idx); + + ufshpb_cleanup_lru_info(lru_info, rgn); + + for (srgn_idx = 0; srgn_idx < rgn->srgn_cnt; srgn_idx++) { + srgn = rgn->srgn_tbl + srgn_idx; + + ufshpb_purge_active_subregion(hpb, srgn, HPB_SRGN_UNUSED); + } +} + +static void ufshpb_hit_lru_info(struct victim_select_info *lru_info, + struct ufshpb_region *rgn) +{ + switch (lru_info->selection_type) { + case LRU: + list_move_tail(&rgn->list_lru_rgn, &lru_info->lh_lru_rgn); + break; + default: + break; + } +} + +/* + * Must be held hpb_lock before call this func. + */ +static int ufshpb_check_issue_state_srgns(struct ufshpb_lu *hpb, + struct ufshpb_region *rgn) +{ + struct ufshpb_subregion *srgn; + int srgn_idx; + + for (srgn_idx = 0; srgn_idx < rgn->srgn_cnt; srgn_idx++) { + srgn = rgn->srgn_tbl + srgn_idx; + + if (srgn->srgn_state == HPB_SRGN_ISSUED) + return -EPERM; + } + return 0; +} + +static struct ufshpb_region *ufshpb_victim_lru_info(struct ufshpb_lu *hpb) +{ + struct victim_select_info *lru_info = &hpb->lru_info; + struct ufshpb_region *rgn; + struct ufshpb_region *victim_rgn = NULL; + + switch (lru_info->selection_type) { + case LRU: + list_for_each_entry(rgn, &lru_info->lh_lru_rgn, list_lru_rgn) { + if (!rgn) + break; + + if (ufshpb_check_issue_state_srgns(hpb, rgn)) + continue; + + victim_rgn = rgn; + break; + } + break; + default: + break; + } + + return victim_rgn; +} + +static int ufshpb_evict_region(struct ufshpb_lu *hpb, struct ufshpb_region *rgn) +{ + unsigned long flags; + + spin_lock_irqsave(&hpb->hpb_lock, flags); + if (rgn->rgn_state == HPB_RGN_PINNED) { + /* + * Pinned active-block should not drop-out. + * But if so, it would treat error as critical, + * and it will run hpb_eh_work + */ + ERR_MSG("pinned active-block drop-out error"); + goto out; + } + + if (!list_empty(&rgn->list_lru_rgn)) { + if (ufshpb_check_issue_state_srgns(hpb, rgn)) + goto evict_fail; + + __ufshpb_evict_region(hpb, rgn); + } +out: + spin_unlock_irqrestore(&hpb->hpb_lock, flags); + return 0; +evict_fail: + spin_unlock_irqrestore(&hpb->hpb_lock, flags); + return -EPERM; +} + +static inline struct +ufshpb_rsp_field *ufshpb_get_hpb_rsp(struct ufshcd_lrb *lrbp) +{ + return (struct ufshpb_rsp_field *)&lrbp->ucd_rsp_ptr->sr.sense_data_len; +} + +static int ufshpb_issue_map_req(struct ufshpb_lu *hpb, + struct ufshpb_subregion *srgn) +{ + struct ufshpb_req *map_req; + unsigned long flags; + int ret = 0; + + spin_lock_irqsave(&hpb->hpb_lock, flags); + + if (srgn->srgn_state == HPB_SRGN_ISSUED) { + ret = -EAGAIN; + goto unlock_out; + } + + map_req = ufshpb_get_map_req(hpb); + if (!map_req) { + ret = -ENOMEM; + goto unlock_out; + } + + srgn->srgn_state = HPB_SRGN_ISSUED; + + ret = ufshpb_clean_dirty_bitmap(hpb, srgn); + if (ret) { + ufshpb_put_map_req(hpb, map_req); + goto unlock_out; + } + spin_unlock_irqrestore(&hpb->hpb_lock, flags); + + ufshpb_set_map_req(hpb, srgn->rgn_idx, srgn->srgn_idx, + srgn->mctx, map_req); + + ret = ufshpb_lu_get(hpb); + if (unlikely(ret)) { + ERR_MSG("ufshpb_lu_get failed. (%d)", ret); + spin_lock_irqsave(&hpb->hpb_lock, flags); + ufshpb_put_map_req(hpb, map_req); + goto unlock_out; + } + + ret = ufshpb_execute_map_req(hpb, map_req); + if (ret) { + ERR_MSG("issue map_req failed. [%d-%d] err %d", + srgn->rgn_idx, srgn->srgn_idx, ret); + ufshpb_lu_put(hpb); + goto wakeup_ee_worker; + } + return ret; +unlock_out: + spin_unlock_irqrestore(&hpb->hpb_lock, flags); + return ret; +wakeup_ee_worker: + ufshpb_failed(hpb, __func__); + return ret; +} + +static int ufshpb_load_region(struct ufshpb_lu *hpb, struct ufshpb_region *rgn) +{ + struct ufshpb_region *victim_rgn; + struct victim_select_info *lru_info = &hpb->lru_info; + unsigned long flags; + int ret = 0; + + /* + * if already region is added to lru_list, + * just initiate the information of lru. + * because the region already has the map ctx. + * (!list_empty(&rgn->list_region) == region->state=active...) + */ + spin_lock_irqsave(&hpb->hpb_lock, flags); + if (!list_empty(&rgn->list_lru_rgn)) { + ufshpb_hit_lru_info(lru_info, rgn); + goto out; + } + + if (rgn->rgn_state == HPB_RGN_INACTIVE) { + if (atomic64_read(&lru_info->active_cnt) + == lru_info->max_lru_active_cnt) { + victim_rgn = ufshpb_victim_lru_info(hpb); + if (!victim_rgn) { + HPB_DEBUG(hpb, "UFSHPB victim_rgn is NULL"); + ret = -ENOMEM; + goto out; + } + TMSG(hpb->ufsf, hpb->lun, "Noti: VT RG %d", + victim_rgn->rgn_idx); + HPB_DEBUG(hpb, "LRU MAX(=%lld). victim choose %d", + (long long)atomic64_read(&lru_info->active_cnt), + victim_rgn->rgn_idx); + + __ufshpb_evict_region(hpb, victim_rgn); + } + + ret = ufshpb_add_region(hpb, rgn); + if (ret) { + ERR_MSG("UFSHPB memory allocation failed"); + spin_unlock_irqrestore(&hpb->hpb_lock, flags); + goto wakeup_ee_worker; + } + } +out: + spin_unlock_irqrestore(&hpb->hpb_lock, flags); + return ret; +wakeup_ee_worker: + ufshpb_failed(hpb, __func__); + return ret; +} + +static void ufshpb_rsp_req_region_update(struct ufshpb_lu *hpb, + struct ufshpb_rsp_field *rsp_field) +{ + int num, rgn_idx, srgn_idx; + + /* + * If active rgn = inactive rgn, choose inactive rgn. + * So, active process -> inactive process + */ + spin_lock(&hpb->rsp_list_lock); + for (num = 0; num < rsp_field->active_rgn_cnt; num++) { + rgn_idx = be16_to_cpu(rsp_field->hpb_active_field[num].active_rgn); + srgn_idx = be16_to_cpu(rsp_field->hpb_active_field[num].active_srgn); + + HPB_DEBUG(hpb, "act num: %d, region: %d, subregion: %d", + num + 1, rgn_idx, srgn_idx); + ufshpb_update_active_info(hpb, rgn_idx, srgn_idx); + atomic64_inc(&hpb->rb_active_cnt); + ufsf_para.noti_act++; + } + + for (num = 0; num < rsp_field->inactive_rgn_cnt; num++) { + rgn_idx = be16_to_cpu(rsp_field->hpb_inactive_field[num]); + HPB_DEBUG(hpb, "inact num: %d, region: %d", num + 1, rgn_idx); + ufshpb_update_inactive_info(hpb, rgn_idx); + atomic64_inc(&hpb->rb_inactive_cnt); + ufsf_para.noti_inact++; + } + spin_unlock(&hpb->rsp_list_lock); + + TMSG(hpb->ufsf, hpb->lun, "Noti: #ACT %u, #INACT %u", + rsp_field->active_rgn_cnt, rsp_field->inactive_rgn_cnt); + + schedule_work(&hpb->task_work); +} + +static inline int ufshpb_may_field_valid(struct ufshcd_lrb *lrbp, + struct ufshpb_rsp_field *rsp_field) +{ + if (be16_to_cpu(rsp_field->sense_data_len) != DEV_SENSE_SEG_LEN || + rsp_field->desc_type != DEV_DES_TYPE || + rsp_field->additional_len != DEV_ADDITIONAL_LEN || + rsp_field->hpb_type == HPB_RSP_NONE || + rsp_field->active_rgn_cnt > MAX_ACTIVE_NUM || + rsp_field->inactive_rgn_cnt > MAX_INACTIVE_NUM || + (!rsp_field->active_rgn_cnt && !rsp_field->inactive_rgn_cnt)) + return -EINVAL; + + if (!ufsf_is_valid_lun(lrbp->lun)) { + ERR_MSG("LU(%d) is not supported", lrbp->lun); + return -EINVAL; + } + + return 0; +} + +static bool ufshpb_is_empty_rsp_lists(struct ufshpb_lu *hpb) +{ + bool ret = true; + unsigned long flags; + + spin_lock_irqsave(&hpb->rsp_list_lock, flags); + if (!list_empty(&hpb->lh_inact_rgn) || !list_empty(&hpb->lh_act_srgn)) + ret = false; + spin_unlock_irqrestore(&hpb->rsp_list_lock, flags); + + return ret; +} + +/* routine : isr (ufs) */ +void ufshpb_rsp_upiu(struct ufsf_feature *ufsf, struct ufshcd_lrb *lrbp) +{ + struct ufshpb_lu *hpb; + struct ufshpb_rsp_field *rsp_field; + int data_seg_len, ret; + + data_seg_len = be32_to_cpu(lrbp->ucd_rsp_ptr->header.dword_2) + & MASK_RSP_UPIU_DATA_SEG_LEN; + + if (!data_seg_len) { + bool do_task_work = false; + + if (!ufsf_is_valid_lun(lrbp->lun)) + return; + + hpb = ufsf->hpb_lup[lrbp->lun]; + ret = ufshpb_lu_get(hpb); + if (unlikely(ret)) + return; + + do_task_work = !ufshpb_is_empty_rsp_lists(hpb); + if (do_task_work) + schedule_work(&hpb->task_work); + + goto put_hpb; + } + + rsp_field = ufshpb_get_hpb_rsp(lrbp); + + if (ufshpb_may_field_valid(lrbp, rsp_field)) { + WARN_ON(rsp_field->additional_len != DEV_ADDITIONAL_LEN); + return; + } + + hpb = ufsf->hpb_lup[lrbp->lun]; + ret = ufshpb_lu_get(hpb); + if (unlikely(ret)) { + ERR_MSG("ufshpb_lu_get failed. (%d)", ret); + return; + } + + if (hpb->force_map_req_disable) + goto put_hpb; + + HPB_DEBUG(hpb, "**** HPB Noti %u LUN %u Seg-Len %u, #ACT %u, #INACT %u", + rsp_field->hpb_type, lrbp->lun, + be32_to_cpu(lrbp->ucd_rsp_ptr->header.dword_2) & + MASK_RSP_UPIU_DATA_SEG_LEN, rsp_field->active_rgn_cnt, + rsp_field->inactive_rgn_cnt); + atomic64_inc(&hpb->rb_noti_cnt); + ufsf_para.noti++; + + switch (rsp_field->hpb_type) { + case HPB_RSP_REQ_REGION_UPDATE: + WARN_ON(data_seg_len != DEV_DATA_SEG_LEN); + ufshpb_rsp_req_region_update(hpb, rsp_field); + goto put_hpb; + default: + HPB_DEBUG(hpb, "hpb_type is not available : %d", + rsp_field->hpb_type); + goto put_hpb; + } + +put_hpb: + ufshpb_lu_put(hpb); +} + +static int ufshpb_execute_map_req_wait(struct ufshpb_lu *hpb, + unsigned char *cmd, + struct ufshpb_subregion *srgn) +{ + struct ufsf_feature *ufsf = hpb->ufsf; + struct scsi_device *sdev; + struct request_queue *q; + struct request *req; + struct scsi_request *rq; + struct bio *bio; + struct scsi_sense_hdr sshdr; + unsigned long flags; + int ret = 0; + + sdev = ufsf->sdev_ufs_lu[hpb->lun]; + if (!sdev) { + ERR_MSG("cannot find scsi_device"); + return -ENODEV; + } + + q = sdev->request_queue; + + ret = ufsf_get_scsi_device(ufsf->hba, sdev); + if (ret) + return ret; + + req = blk_get_request(q, REQ_OP_SCSI_IN, GFP_KERNEL); + if (IS_ERR(req)) { + ERR_MSG("cannot get request"); + ret = -EIO; + goto sdev_put_out; + } + + bio = bio_kmalloc(GFP_KERNEL, hpb->mpages_per_srgn); + if (!bio) { + ret = -ENOMEM; + goto req_put_out; + } + + ret = ufshpb_map_req_add_bio_page(hpb, q, bio, srgn->mctx); + if (ret) + goto mem_free_out; + + /* 1. request setup*/ + blk_rq_append_bio(req, &bio); /* req->__data_len */ + req->timeout = msecs_to_jiffies(30000); + req->cmd_flags |= REQ_OP_READ; + req->rq_flags |= RQF_QUIET | RQF_PREEMPT; + + /* 2. scsi_request setup */ + rq = scsi_req(req); + rq->cmd_len = scsi_command_size(cmd); + memcpy(rq->cmd, cmd, rq->cmd_len); + + blk_execute_rq(q, NULL, req, 1); + if (rq->result) { + ret = -EIO; + scsi_normalize_sense(rq->sense, SCSI_SENSE_BUFFERSIZE, &sshdr); + ERR_MSG("code %x sense_key %x asc %x ascq %x", + sshdr.response_code, sshdr.sense_key, sshdr.asc, + sshdr.ascq); + ERR_MSG("byte4 %x byte5 %x byte6 %x additional_len %x", + sshdr.byte4, sshdr.byte5, sshdr.byte6, + sshdr.additional_length); + spin_lock_irqsave(&hpb->hpb_lock, flags); + ufshpb_error_active_subregion(hpb, srgn); + spin_unlock_irqrestore(&hpb->hpb_lock, flags); + } +mem_free_out: + bio_put(bio); +req_put_out: + blk_put_request(req); +sdev_put_out: + scsi_device_put(sdev); + return ret; +} + +static int ufshpb_issue_map_req_from_list(struct ufshpb_lu *hpb) +{ + struct ufshpb_subregion *srgn; + unsigned long flags; + int ret; + + spin_lock_irqsave(&hpb->rsp_list_lock, flags); + + while ((srgn = list_first_entry_or_null(&hpb->lh_pinned_srgn, + struct ufshpb_subregion, + list_act_srgn))) { + unsigned char cmd[10] = { 0 }; + + list_del_init(&srgn->list_act_srgn); + spin_unlock_irqrestore(&hpb->rsp_list_lock, flags); + + ufshpb_set_read_buf_cmd(cmd, srgn->rgn_idx, srgn->srgn_idx, + hpb->srgn_mem_size); + + if (hpb->debug) + ufshpb_check_ppn(hpb, srgn->rgn_idx, srgn->srgn_idx, + srgn->mctx, "ISSUE"); + + TMSG(hpb->ufsf, hpb->lun, "Noti: I RB %d - %d", + srgn->rgn_idx, srgn->srgn_idx); + + ret = ufshpb_execute_map_req_wait(hpb, cmd, srgn); + if (ret < 0) { + ERR_MSG("region %d sub %d failed with err %d", + srgn->rgn_idx, srgn->srgn_idx, ret); + spin_lock_irqsave(&hpb->rsp_list_lock, flags); + if (list_empty(&srgn->list_act_srgn)) + list_add(&srgn->list_act_srgn, + &hpb->lh_pinned_srgn); + continue; + } + + TMSG(hpb->ufsf, hpb->lun, "Noti: C RB %d - %d", + srgn->rgn_idx, srgn->srgn_idx); + + if (hpb->debug) + ufshpb_check_ppn(hpb, srgn->rgn_idx, srgn->srgn_idx, + srgn->mctx, "COMPL"); + + spin_lock_irqsave(&hpb->hpb_lock, flags); + ufshpb_clean_active_subregion(hpb, srgn); + spin_unlock_irqrestore(&hpb->hpb_lock, flags); + + spin_lock_irqsave(&hpb->rsp_list_lock, flags); + } + + spin_unlock_irqrestore(&hpb->rsp_list_lock, flags); + + return 0; +} + +static void ufshpb_pinned_work_handler(struct work_struct *work) +{ + struct ufshpb_lu *hpb; + int ret; + + hpb = container_of(work, struct ufshpb_lu, pinned_work); + HPB_DEBUG(hpb, "worker start for pinned region"); + + pm_runtime_get_sync(hpb->ufsf->hba->dev); + ufshpb_lu_get(hpb); + + if (!list_empty(&hpb->lh_pinned_srgn)) { + ret = ufshpb_issue_map_req_from_list(hpb); + /* + * if its function failed at init time, + * ufshpb-device will request map-req, + * so it is not critical-error, and just finish work-handler + */ + if (ret) + HPB_DEBUG(hpb, "failed map-issue. ret %d", ret); + } + ufshpb_lu_put(hpb); + pm_runtime_put_sync(hpb->ufsf->hba->dev); + HPB_DEBUG(hpb, "worker end"); +} + +static int ufshpb_check_pm(struct ufshpb_lu *hpb) +{ + struct ufs_hba *hba = hpb->ufsf->hba; + + if (hba->pm_op_in_progress || + hba->curr_dev_pwr_mode != UFS_ACTIVE_PWR_MODE) { + INFO_MSG("hba current power state %d pm_progress %d", + hba->curr_dev_pwr_mode, + hba->pm_op_in_progress); + return -ENODEV; + } + return 0; +} + +static void ufshpb_retry_work_handler(struct work_struct *work) +{ + struct ufshpb_lu *hpb; + struct delayed_work *dwork = to_delayed_work(work); + struct ufshpb_req *map_req, *next; + unsigned long flags; + bool do_retry = false; + int ret = 0; + + LIST_HEAD(retry_list); + + hpb = container_of(dwork, struct ufshpb_lu, retry_work); + + if (ufshpb_check_pm(hpb)) + return; + + ret = ufshpb_lu_get(hpb); + if (unlikely(ret)) { + ERR_MSG("ufshpb_lu_get failed. (%d)", ret); + return; + } + + HPB_DEBUG(hpb, "retry worker start"); + + spin_lock_bh(&hpb->retry_list_lock); + list_splice_init(&hpb->lh_map_req_retry, &retry_list); + spin_unlock_bh(&hpb->retry_list_lock); + + list_for_each_entry_safe(map_req, next, &retry_list, list_req) { + if (ufshpb_get_state(hpb->ufsf) == HPB_SUSPEND) { + INFO_MSG("suspend state. Issue READ_BUFFER in the next turn"); + spin_lock_bh(&hpb->retry_list_lock); + list_splice_init(&retry_list, &hpb->lh_map_req_retry); + spin_unlock_bh(&hpb->retry_list_lock); + do_retry = true; + break; + } + + list_del_init(&map_req->list_req); + + ret = ufshpb_lu_get(hpb); + if (unlikely(ret)) { + WARN_MSG("ufshpb_lu_get failed (%d)", ret); + spin_lock_irqsave(&hpb->hpb_lock, flags); + ufshpb_put_map_req(hpb, map_req); + spin_unlock_irqrestore(&hpb->hpb_lock, flags); + continue; + } + + ret = ufshpb_execute_map_req(hpb, map_req); + if (ret) { + ERR_MSG("issue map_req failed. [%d-%d] err %d", + map_req->rb.rgn_idx, map_req->rb.srgn_idx, ret); + ufshpb_lu_put(hpb); + goto wakeup_ee_worker; + } + } + HPB_DEBUG(hpb, "worker end"); + ufshpb_lu_put(hpb); + + if (do_retry) + schedule_delayed_work(&hpb->retry_work, + msecs_to_jiffies(RETRY_DELAY_MS)); + return; +wakeup_ee_worker: + ufshpb_lu_put(hpb); + ufshpb_failed(hpb, __func__); +} + +static void ufshpb_add_starved_list(struct ufshpb_lu *hpb, + struct ufshpb_region *rgn, + struct list_head *starved_list) +{ + struct ufshpb_subregion *srgn; + int srgn_idx; + + if (!list_empty(&rgn->list_inact_rgn)) + return; + + for (srgn_idx = 0; srgn_idx < rgn->srgn_cnt; srgn_idx++) { + srgn = rgn->srgn_tbl + srgn_idx; + + if (!list_empty(&srgn->list_act_srgn)) + return; + } + + list_add_tail(&rgn->list_inact_rgn, starved_list); +} + +static void ufshpb_run_inactive_region_list(struct ufshpb_lu *hpb) +{ + struct ufshpb_region *rgn; + unsigned long flags; + int ret; + LIST_HEAD(starved_list); + + spin_lock_irqsave(&hpb->rsp_list_lock, flags); + while ((rgn = list_first_entry_or_null(&hpb->lh_inact_rgn, + struct ufshpb_region, + list_inact_rgn))) { + if (ufshpb_get_state(hpb->ufsf) == HPB_SUSPEND) { + INFO_MSG("suspend state. Inactivate rgn the next turn"); + break; + } + + list_del_init(&rgn->list_inact_rgn); + spin_unlock_irqrestore(&hpb->rsp_list_lock, flags); + + ret = ufshpb_evict_region(hpb, rgn); + if (ret) { + spin_lock_irqsave(&hpb->rsp_list_lock, flags); + ufshpb_add_starved_list(hpb, rgn, &starved_list); + spin_unlock_irqrestore(&hpb->rsp_list_lock, flags); + } + + spin_lock_irqsave(&hpb->rsp_list_lock, flags); + } + + list_splice(&starved_list, &hpb->lh_inact_rgn); + spin_unlock_irqrestore(&hpb->rsp_list_lock, flags); +} + +static void ufshpb_add_active_list(struct ufshpb_lu *hpb, + struct ufshpb_region *rgn, + struct ufshpb_subregion *srgn) +{ + if (!list_empty(&rgn->list_inact_rgn)) + return; + + if (!list_empty(&srgn->list_act_srgn)) { + list_move(&srgn->list_act_srgn, &hpb->lh_act_srgn); + return; + } + + list_add(&srgn->list_act_srgn, &hpb->lh_act_srgn); +} + +static void ufshpb_run_active_subregion_list(struct ufshpb_lu *hpb) +{ + struct ufshpb_region *rgn; + struct ufshpb_subregion *srgn; + unsigned long flags; + int ret = 0; + + spin_lock_irqsave(&hpb->rsp_list_lock, flags); + while ((srgn = list_first_entry_or_null(&hpb->lh_act_srgn, + struct ufshpb_subregion, + list_act_srgn))) { + if (ufshpb_get_state(hpb->ufsf) == HPB_SUSPEND) { + INFO_MSG("suspend state. Issuing READ_BUFFER the next turn"); + break; + } + + list_del_init(&srgn->list_act_srgn); + + if (hpb->force_map_req_disable) { + HPB_DEBUG(hpb, "map_req disabled"); + continue; + } + + spin_unlock_irqrestore(&hpb->rsp_list_lock, flags); + + rgn = hpb->rgn_tbl + srgn->rgn_idx; + + ret = ufshpb_load_region(hpb, rgn); + if (ret) + break; + + ret = ufshpb_issue_map_req(hpb, srgn); + if (ret) + break; + + spin_lock_irqsave(&hpb->rsp_list_lock, flags); + } + + if (ret) { + spin_lock_irqsave(&hpb->rsp_list_lock, flags); + ufshpb_add_active_list(hpb, rgn, srgn); + } + spin_unlock_irqrestore(&hpb->rsp_list_lock, flags); +} + +static void ufshpb_task_work_handler(struct work_struct *work) +{ + struct ufshpb_lu *hpb; + int ret; + + hpb = container_of(work, struct ufshpb_lu, task_work); + ret = ufshpb_lu_get(hpb); + if (unlikely(ret)) { + if (hpb) + WARN_MSG("lu_get failed.. hpb_state %d", + ufshpb_get_state(hpb->ufsf)); + WARN_MSG("warning: ufshpb_lu_get failed %d..", ret); + return; + } + + ufshpb_run_inactive_region_list(hpb); + ufshpb_run_active_subregion_list(hpb); + + ufshpb_lu_put(hpb); +} + +static inline void ufshpb_map_req_mempool_remove(struct ufshpb_lu *hpb) +{ + int i; + + for (i = 0; i < hpb->qd; i++) { + kfree(hpb->map_req[i].req); + bio_put(hpb->map_req[i].bio); + } + + kfree(hpb->map_req); +} + +static inline void ufshpb_pre_req_mempool_remove(struct ufshpb_lu *hpb) +{ + int i; + + for (i = 0; i < hpb->qd; i++) { + kfree(hpb->pre_req[i].req); + bio_put(hpb->pre_req[i].bio); + __free_page(hpb->pre_req[i].wb.m_page); + } + + kfree(hpb->pre_req); +} + +static void ufshpb_table_mempool_remove(struct ufshpb_lu *hpb) +{ + struct ufshpb_map_ctx *mctx, *next; + int i; + + /* + * the mctx in the lh_map_ctx_free has been allocated completely. + */ + list_for_each_entry_safe(mctx, next, &hpb->lh_map_ctx_free, + list_table) { + for (i = 0; i < hpb->mpages_per_srgn; i++) + __free_page(mctx->m_page[i]); + + vfree(mctx->ppn_dirty); + kfree(mctx->m_page); + kfree(mctx); + hpb->alloc_mctx--; + } +} + +/* + * this function doesn't need to hold lock due to be called in init. + * (hpb_lock, rsp_list_lock, etc..) + */ +static int ufshpb_init_pinned_active_region(struct ufshpb_lu *hpb, + struct ufshpb_region *rgn) +{ + struct ufshpb_subregion *srgn; + int srgn_idx, j; + int err = 0; + + for (srgn_idx = 0; srgn_idx < rgn->srgn_cnt; srgn_idx++) { + srgn = rgn->srgn_tbl + srgn_idx; + + srgn->mctx = ufshpb_get_map_ctx(hpb, &err); + if (err) { + ERR_MSG("get mctx err %d srgn %d free_table %d", + err, srgn_idx, hpb->debug_free_table); + goto release; + } + + srgn->srgn_state = HPB_SRGN_ISSUED; + /* + * no need to clean ppn_dirty bitmap + * because it is vzalloc-ed @ufshpb_table_mempool_init() + */ + list_add_tail(&srgn->list_act_srgn, &hpb->lh_pinned_srgn); + } + + rgn->rgn_state = HPB_RGN_PINNED; + + return 0; + +release: + for (j = 0; j < srgn_idx; j++) { + srgn = rgn->srgn_tbl + j; + ufshpb_put_map_ctx(hpb, srgn->mctx); + } + + return err; +} + +static inline bool ufshpb_is_pinned_region(struct ufshpb_lu *hpb, int rgn_idx) +{ + if (hpb->lu_pinned_end_offset != -1 && + rgn_idx >= hpb->lu_pinned_rgn_startidx && + rgn_idx <= hpb->lu_pinned_end_offset) + return true; + + return false; +} + +static inline void ufshpb_init_jobs(struct ufshpb_lu *hpb) +{ + INIT_WORK(&hpb->pinned_work, ufshpb_pinned_work_handler); + INIT_DELAYED_WORK(&hpb->retry_work, ufshpb_retry_work_handler); + INIT_WORK(&hpb->task_work, ufshpb_task_work_handler); +} + +static inline void ufshpb_cancel_jobs(struct ufshpb_lu *hpb) +{ + cancel_work_sync(&hpb->pinned_work); + cancel_delayed_work_sync(&hpb->retry_work); + cancel_work_sync(&hpb->task_work); +} + +static void ufshpb_init_subregion_tbl(struct ufshpb_lu *hpb, + struct ufshpb_region *rgn) +{ + int srgn_idx; + + for (srgn_idx = 0; srgn_idx < rgn->srgn_cnt; srgn_idx++) { + struct ufshpb_subregion *srgn = rgn->srgn_tbl + srgn_idx; + + INIT_LIST_HEAD(&srgn->list_act_srgn); + + srgn->rgn_idx = rgn->rgn_idx; + srgn->srgn_idx = srgn_idx; + srgn->srgn_state = HPB_SRGN_UNUSED; + } +} + +static inline int ufshpb_alloc_subregion_tbl(struct ufshpb_lu *hpb, + struct ufshpb_region *rgn, + int srgn_cnt) +{ + rgn->srgn_tbl = + kzalloc(sizeof(struct ufshpb_subregion) * srgn_cnt, GFP_KERNEL); + if (!rgn->srgn_tbl) + return -ENOMEM; + + rgn->srgn_cnt = srgn_cnt; + return 0; +} + +static int ufshpb_table_mempool_init(struct ufshpb_lu *hpb) +{ + struct ufshpb_map_ctx *mctx = NULL; + int i, j, k; + + INIT_LIST_HEAD(&hpb->lh_map_ctx_free); + + hpb->alloc_mctx = hpb->lu_max_active_rgns * hpb->srgns_per_rgn; + + for (i = 0; i < hpb->alloc_mctx; i++) { + mctx = kmalloc(sizeof(struct ufshpb_map_ctx), GFP_KERNEL); + if (!mctx) + goto release_mem; + + mctx->m_page = + kzalloc(sizeof(struct page *) * hpb->mpages_per_srgn, + GFP_KERNEL); + if (!mctx->m_page) + goto release_mem; + + mctx->ppn_dirty = vzalloc(hpb->entries_per_srgn >> + bits_per_byte_shift); + if (!mctx->ppn_dirty) + goto release_mem; + + for (j = 0; j < hpb->mpages_per_srgn; j++) { + mctx->m_page[j] = alloc_page(GFP_KERNEL | __GFP_ZERO); + if (!mctx->m_page[j]) { + for (k = 0; k < j; k++) + __free_page(mctx->m_page[k]); + goto release_mem; + } + } + + INIT_LIST_HEAD(&mctx->list_table); + list_add(&mctx->list_table, &hpb->lh_map_ctx_free); + + hpb->debug_free_table++; + } + + INFO_MSG("The number of mctx = (%d). debug_free_table (%d)", + hpb->alloc_mctx, hpb->debug_free_table); + return 0; +release_mem: + /* + * mctxs already added in lh_map_ctx_free will be removed + * in the caller function. + */ + if (mctx) { + kfree(mctx->m_page); + vfree(mctx->ppn_dirty); + kfree(mctx); + } + return -ENOMEM; +} + +static int +ufshpb_map_req_mempool_init(struct ufshpb_lu *hpb) +{ + struct scsi_device *sdev; + struct request_queue *q; + struct ufshpb_req *map_req = NULL; + int qd = hpb->qd; + int i, j; + + sdev = hpb->ufsf->sdev_ufs_lu[hpb->lun]; + q = sdev->request_queue; + + INIT_LIST_HEAD(&hpb->lh_map_req_free); + INIT_LIST_HEAD(&hpb->lh_map_req_retry); + + hpb->map_req = kzalloc(sizeof(struct ufshpb_req) * qd, GFP_KERNEL); + if (!hpb->map_req) + goto release_mem; + + /* + * q->cmd_size: sizeof(struct scsi_cmd) + shost->hostt->cmd_size + */ + for (i = 0; i < qd; i++) { + map_req = hpb->map_req + i; + INIT_LIST_HEAD(&map_req->list_req); + map_req->req = kzalloc(sizeof(struct request) + q->cmd_size, + GFP_KERNEL); + if (!map_req->req) { + for (j = 0; j < i; j++) + kfree(hpb->map_req[j].req); + goto release_mem; + } + + map_req->bio = bio_kmalloc(GFP_KERNEL, hpb->mpages_per_srgn); + if (!map_req->bio) { + kfree(hpb->map_req[i].req); + for (j = 0; j < i; j++) { + kfree(hpb->map_req[j].req); + bio_put(hpb->map_req[j].bio); + } + goto release_mem; + } + list_add_tail(&map_req->list_req, &hpb->lh_map_req_free); + } + + return 0; +release_mem: + kfree(hpb->map_req); + return -ENOMEM; +} + +static int +ufshpb_pre_req_mempool_init(struct ufshpb_lu *hpb) +{ + struct scsi_device *sdev; + struct request_queue *q; + struct ufshpb_req *pre_req = NULL; + int qd = hpb->qd; + int i, j; + + INIT_LIST_HEAD(&hpb->lh_pre_req_free); + INIT_LIST_HEAD(&hpb->lh_pre_req_dummy); + + sdev = hpb->ufsf->sdev_ufs_lu[hpb->lun]; + q = sdev->request_queue; + + hpb->pre_req = kzalloc(sizeof(struct ufshpb_req) * qd, GFP_KERNEL); + if (!hpb->pre_req) + goto release_mem; + + /* + * q->cmd_size: sizeof(struct scsi_cmd) + shost->hostt->cmd_size + */ + for (i = 0; i < qd; i++) { + pre_req = hpb->pre_req + i; + INIT_LIST_HEAD(&pre_req->list_req); + pre_req->req = kzalloc(sizeof(struct request) + q->cmd_size, + GFP_KERNEL); + if (!pre_req->req) { + for (j = 0; j < i; j++) + kfree(hpb->pre_req[j].req); + goto release_mem; + } + + pre_req->bio = bio_kmalloc(GFP_KERNEL, 1); + if (!pre_req->bio) { + kfree(hpb->pre_req[i].req); + for (j = 0; j < i; j++) { + kfree(hpb->pre_req[j].req); + bio_put(hpb->pre_req[j].bio); + } + goto release_mem; + } + + pre_req->wb.m_page = alloc_page(GFP_KERNEL | __GFP_ZERO); + if (!pre_req->wb.m_page) { + kfree(hpb->pre_req[i].req); + bio_put(hpb->pre_req[i].bio); + for (j = 0; j < i; j++) { + kfree(hpb->pre_req[j].req); + bio_put(hpb->pre_req[j].bio); + __free_page(hpb->pre_req[j].wb.m_page); + } + goto release_mem; + } + list_add_tail(&pre_req->list_req, &hpb->lh_pre_req_free); + } + + return 0; +release_mem: + kfree(hpb->pre_req); + return -ENOMEM; +} + +static void ufshpb_find_lu_qd(struct ufshpb_lu *hpb) +{ + struct scsi_device *sdev; + struct ufs_hba *hba; + + sdev = hpb->ufsf->sdev_ufs_lu[hpb->lun]; + hba = hpb->ufsf->hba; + + /* + * ufshcd_slave_alloc(sdev) -> ufshcd_set_queue_depth(sdev) + * a lu-queue-depth compared with lu_info and hba->nutrs + * is selected in ufshcd_set_queue_depth() + */ + hpb->qd = sdev->queue_depth; + INFO_MSG("lu (%d) queue_depth (%d)", hpb->lun, hpb->qd); + if (!hpb->qd) { + hpb->qd = hba->nutrs; + INFO_MSG("lu_queue_depth is 0. we use device's queue info."); + INFO_MSG("hba->nutrs = (%d)", hba->nutrs); + } + + hpb->throttle_map_req = hpb->qd; + hpb->throttle_pre_req = hpb->qd; + hpb->num_inflight_map_req = 0; + hpb->num_inflight_pre_req = 0; +} + +static void ufshpb_init_lu_constant(struct ufshpb_dev_info *hpb_dev_info, + struct ufshpb_lu *hpb) +{ + unsigned long long rgn_unit_size, rgn_mem_size; + int entries_per_rgn; + + hpb->debug = false; + + ufshpb_find_lu_qd(hpb); + + /* for pre_req */ + hpb->pre_req_min_tr_len = HPB_MULTI_CHUNK_LOW; + hpb->pre_req_max_tr_len = HPB_MULTI_CHUNK_HIGH; + hpb->ctx_id_ticket = 0; + + /* From descriptors */ + rgn_unit_size = (unsigned long long) + SECTOR * (0x01 << hpb_dev_info->rgn_size); + rgn_mem_size = rgn_unit_size / BLOCK * HPB_ENTRY_SIZE; + + hpb->srgn_unit_size = (unsigned long long) + SECTOR * (0x01 << hpb_dev_info->srgn_size); + hpb->srgn_mem_size = hpb->srgn_unit_size / BLOCK * HPB_ENTRY_SIZE; + + /* relation : lu <-> region <-> sub region <-> entry */ + entries_per_rgn = rgn_mem_size / HPB_ENTRY_SIZE; + hpb->entries_per_srgn = hpb->srgn_mem_size / HPB_ENTRY_SIZE; + hpb->srgns_per_rgn = rgn_mem_size / hpb->srgn_mem_size; + + /* + * regions_per_lu = (lu_num_blocks * 4096) / region_unit_size + * = (lu_num_blocks * HPB_ENTRY_SIZE) / region_mem_size + */ + hpb->rgns_per_lu = + ((unsigned long long)hpb->lu_num_blocks + + (rgn_mem_size / HPB_ENTRY_SIZE) - 1) + / (rgn_mem_size / HPB_ENTRY_SIZE); + hpb->srgns_per_lu = + ((unsigned long long)hpb->lu_num_blocks + + (hpb->srgn_mem_size / HPB_ENTRY_SIZE) - 1) + / (hpb->srgn_mem_size / HPB_ENTRY_SIZE); + + /* mempool info */ + hpb->mpage_bytes = OS_PAGE_SIZE; + hpb->mpages_per_srgn = hpb->srgn_mem_size / hpb->mpage_bytes; + + /* Bitmask Info. */ + hpb->dwords_per_srgn = hpb->entries_per_srgn / BITS_PER_DWORD; + hpb->entries_per_rgn_shift = ffs(entries_per_rgn) - 1; + hpb->entries_per_rgn_mask = entries_per_rgn - 1; + hpb->entries_per_srgn_shift = ffs(hpb->entries_per_srgn) - 1; + hpb->entries_per_srgn_mask = hpb->entries_per_srgn - 1; + + INFO_MSG("===== From Device Descriptor! ====="); + INFO_MSG("hpb_region_size = (%d), hpb_subregion_size = (%d)", + hpb_dev_info->rgn_size, hpb_dev_info->srgn_size); + INFO_MSG("===== Constant Values(LU) ====="); + INFO_MSG("region_unit_size = (%lld), region_mem_size (%lld)", + rgn_unit_size, rgn_mem_size); + INFO_MSG("subregion_unit_size = (%lld), subregion_mem_size (%d)", + hpb->srgn_unit_size, hpb->srgn_mem_size); + + INFO_MSG("lu_num_blocks = (%d)", hpb->lu_num_blocks); + INFO_MSG("regions_per_lu = (%d), subregions_per_lu = (%d)", + hpb->rgns_per_lu, hpb->srgns_per_lu); + + INFO_MSG("subregions_per_region = %d", hpb->srgns_per_rgn); + INFO_MSG("entries_per_region (%u) shift (%u) mask (0x%X)", + entries_per_rgn, hpb->entries_per_rgn_shift, + hpb->entries_per_rgn_mask); + INFO_MSG("entries_per_subregion (%u) shift (%u) mask (0x%X)", + hpb->entries_per_srgn, hpb->entries_per_srgn_shift, + hpb->entries_per_srgn_mask); + INFO_MSG("mpages_per_subregion : (%d)", hpb->mpages_per_srgn); + INFO_MSG("==================================="); +} + +static int ufshpb_lu_hpb_init(struct ufsf_feature *ufsf, int lun) +{ + struct ufshpb_lu *hpb = ufsf->hpb_lup[lun]; + struct ufshpb_region *rgn_table, *rgn; + struct ufshpb_subregion *srgn; + int rgn_idx, srgn_idx, total_srgn_cnt, srgn_cnt, i, ret = 0; + bool do_work_handler = false; + + ufshpb_init_lu_constant(&ufsf->hpb_dev_info, hpb); + + rgn_table = kzalloc(sizeof(struct ufshpb_region) * hpb->rgns_per_lu, + GFP_KERNEL); + if (!rgn_table) { + ret = -ENOMEM; + goto out; + } + + INFO_MSG("active_region_table bytes: (%lu)", + (sizeof(struct ufshpb_region) * hpb->rgns_per_lu)); + + hpb->rgn_tbl = rgn_table; + + spin_lock_init(&hpb->hpb_lock); + spin_lock_init(&hpb->retry_list_lock); + spin_lock_init(&hpb->rsp_list_lock); + + /* init lru information */ + INIT_LIST_HEAD(&hpb->lru_info.lh_lru_rgn); + hpb->lru_info.selection_type = LRU; + + INIT_LIST_HEAD(&hpb->lh_pinned_srgn); + INIT_LIST_HEAD(&hpb->lh_act_srgn); + INIT_LIST_HEAD(&hpb->lh_inact_rgn); + + INIT_LIST_HEAD(&hpb->lh_map_ctx_free); + + ufshpb_init_jobs(hpb); + + ret = ufshpb_map_req_mempool_init(hpb); + if (ret) { + ERR_MSG("map_req_mempool init fail!"); + goto release_rgn_table; + } + + ret = ufshpb_pre_req_mempool_init(hpb); + if (ret) { + ERR_MSG("pre_req_mempool init fail!"); + goto release_map_req_mempool; + } + + ret = ufshpb_table_mempool_init(hpb); + if (ret) { + ERR_MSG("ppn table mempool init fail!"); + ufshpb_table_mempool_remove(hpb); + goto release_pre_req_mempool; + } + + total_srgn_cnt = hpb->srgns_per_lu; + INFO_MSG("total_subregion_count: (%d)", total_srgn_cnt); + for (rgn_idx = 0, srgn_cnt = 0; rgn_idx < hpb->rgns_per_lu; + rgn_idx++, total_srgn_cnt -= srgn_cnt) { + rgn = rgn_table + rgn_idx; + rgn->rgn_idx = rgn_idx; + + INIT_LIST_HEAD(&rgn->list_inact_rgn); + + /* init lru region information*/ + INIT_LIST_HEAD(&rgn->list_lru_rgn); + + srgn_cnt = min(total_srgn_cnt, hpb->srgns_per_rgn); + + ret = ufshpb_alloc_subregion_tbl(hpb, rgn, srgn_cnt); + if (ret) + goto release_srgns; + ufshpb_init_subregion_tbl(hpb, rgn); + + if (ufshpb_is_pinned_region(hpb, rgn_idx)) { + ret = ufshpb_init_pinned_active_region(hpb, rgn); + if (ret) + goto release_srgns; + + do_work_handler = true; + } else { + rgn->rgn_state = HPB_RGN_INACTIVE; + } + } + + if (total_srgn_cnt != 0) { + ERR_MSG("error total_subregion_count: %d", + total_srgn_cnt); + goto release_srgns; + } + + /* + * even if creating sysfs failed, ufshpb could run normally. + * so we don't deal with error handling + */ + ufshpb_create_sysfs(ufsf, hpb); + + return 0; +release_srgns: + for (i = 0; i < rgn_idx; i++) { + rgn = rgn_table + i; + if (rgn->srgn_tbl) { + for (srgn_idx = 0; srgn_idx < rgn->srgn_cnt; + srgn_idx++) { + srgn = rgn->srgn_tbl + srgn_idx; + if (srgn->mctx) + ufshpb_put_map_ctx(hpb, srgn->mctx); + } + kfree(rgn->srgn_tbl); + } + } + + ufshpb_table_mempool_remove(hpb); +release_pre_req_mempool: + ufshpb_pre_req_mempool_remove(hpb); +release_map_req_mempool: + ufshpb_map_req_mempool_remove(hpb); +release_rgn_table: + kfree(rgn_table); +out: + return ret; +} + +static inline int ufshpb_version_check(struct ufshpb_dev_info *hpb_dev_info) +{ + INFO_MSG("Support HPB Spec : UFSHPB_VER_2_0_0 = (%.4X) UFSHPB_VER_2_0_1 = (%.4X) Device = (%.4X)", + UFSHPB_VER_2_0_0, UFSHPB_VER_2_0_1, hpb_dev_info->version); + + INFO_MSG("HPB Driver Version : (%.6X%s)", UFSHPB_DD_VER, UFSHPB_DD_VER_POST); + + if (hpb_dev_info->version != UFSHPB_VER_2_0_0 && + hpb_dev_info->version != UFSHPB_VER_2_0_1 && hpb_dev_info->version != UFSHPB_VER_2_2_1) { + ERR_MSG("ERROR: HPB Spec Version mismatch. So HPB disabled."); + return -ENODEV; + } + return 0; +} + +void ufshpb_get_dev_info(struct ufsf_feature *ufsf, u8 *desc_buf) +{ + struct ufshpb_dev_info *hpb_dev_info = &ufsf->hpb_dev_info; + int ret; + + if (desc_buf[DEVICE_DESC_PARAM_UFS_FEAT] & UFS_FEATURE_SUPPORT_HPB_BIT) + INFO_MSG("bUFSFeaturesSupport: HPB is set"); + else { + INFO_MSG("bUFSFeaturesSupport: HPB not support"); + ufshpb_set_state(ufsf, HPB_FAILED); + return; + } + + hpb_dev_info->version = LI_EN_16(desc_buf + DEVICE_DESC_PARAM_HPB_VER); + + ret = ufshpb_version_check(hpb_dev_info); + if (ret) + ufshpb_set_state(ufsf, HPB_FAILED); +} + +void ufshpb_get_geo_info(struct ufsf_feature *ufsf, u8 *geo_buf) +{ + struct ufshpb_dev_info *hpb_dev_info = &ufsf->hpb_dev_info; + int hpb_device_max_active_rgns = 0; + + hpb_dev_info->num_lu = geo_buf[GEOMETRY_DESC_HPB_NUMBER_LU]; + if (hpb_dev_info->num_lu == 0) { + ERR_MSG("Don't have a lu for hpb."); + ufshpb_set_state(ufsf, HPB_FAILED); + return; + } + + hpb_dev_info->rgn_size = geo_buf[GEOMETRY_DESC_HPB_REGION_SIZE]; + hpb_dev_info->srgn_size = geo_buf[GEOMETRY_DESC_HPB_SUBREGION_SIZE]; + hpb_device_max_active_rgns = + LI_EN_16(geo_buf + GEOMETRY_DESC_HPB_DEVICE_MAX_ACTIVE_REGIONS); + + INFO_MSG("[48] bHPBRegionSiz (%u)", hpb_dev_info->rgn_size); + INFO_MSG("[49] bHPBNumberLU (%u)", hpb_dev_info->num_lu); + INFO_MSG("[4A] bHPBSubRegionSize (%u)", hpb_dev_info->srgn_size); + INFO_MSG("[4B:4C] wDeviceMaxActiveHPBRegions (%u)", + hpb_device_max_active_rgns); + + if (hpb_dev_info->rgn_size == 0 || hpb_dev_info->srgn_size == 0 || + hpb_device_max_active_rgns == 0) { + ERR_MSG("HPB NOT normally supported by device"); + ufshpb_set_state(ufsf, HPB_FAILED); + } +} + +void ufshpb_get_lu_info(struct ufsf_feature *ufsf, int lun, u8 *unit_buf) +{ + struct ufsf_lu_desc lu_desc; + struct ufshpb_lu *hpb; + + lu_desc.lu_enable = unit_buf[UNIT_DESC_PARAM_LU_ENABLE]; + lu_desc.lu_queue_depth = unit_buf[UNIT_DESC_PARAM_LU_Q_DEPTH]; + lu_desc.lu_logblk_size = unit_buf[UNIT_DESC_PARAM_LOGICAL_BLK_SIZE]; + lu_desc.lu_logblk_cnt = + LI_EN_64(unit_buf + UNIT_DESC_PARAM_LOGICAL_BLK_COUNT); + lu_desc.lu_max_active_hpb_rgns = + LI_EN_16(unit_buf + UNIT_DESC_HPB_LU_MAX_ACTIVE_REGIONS); + lu_desc.lu_hpb_pinned_rgn_startidx = + LI_EN_16(unit_buf + UNIT_DESC_HPB_LU_PIN_REGION_START_OFFSET); + lu_desc.lu_num_hpb_pinned_rgns = + LI_EN_16(unit_buf + UNIT_DESC_HPB_LU_NUM_PIN_REGIONS); + + if (lu_desc.lu_num_hpb_pinned_rgns > 0) { + lu_desc.lu_hpb_pinned_end_offset = + lu_desc.lu_hpb_pinned_rgn_startidx + + lu_desc.lu_num_hpb_pinned_rgns - 1; + } else + lu_desc.lu_hpb_pinned_end_offset = PINNED_NOT_SET; + + INFO_MSG("LUN(%d) [0A] bLogicalBlockSize (%d)", + lun, lu_desc.lu_logblk_size); + INFO_MSG("LUN(%d) [0B] qLogicalBlockCount (%llu)", + lun, lu_desc.lu_logblk_cnt); + INFO_MSG("LUN(%d) [03] bLuEnable (%d)", lun, lu_desc.lu_enable); + INFO_MSG("LUN(%d) [06] bLuQueueDepth (%d)", lun, lu_desc.lu_queue_depth); + INFO_MSG("LUN(%d) [23:24] wLUMaxActiveHPBRegions (%d)", + lun, lu_desc.lu_max_active_hpb_rgns); + INFO_MSG("LUN(%d) [25:26] wHPBPinnedRegionStartIdx (%d)", + lun, lu_desc.lu_hpb_pinned_rgn_startidx); + INFO_MSG("LUN(%d) [27:28] wNumHPBPinnedRegions (%d)", + lun, lu_desc.lu_num_hpb_pinned_rgns); + INFO_MSG("LUN(%d) PINNED Start (%d) End (%d)", + lun, lu_desc.lu_hpb_pinned_rgn_startidx, + lu_desc.lu_hpb_pinned_end_offset); + + ufsf->hpb_lup[lun] = NULL; + + if (lu_desc.lu_enable == 0x02 && lu_desc.lu_max_active_hpb_rgns) { + ufsf->hpb_lup[lun] = kzalloc(sizeof(struct ufshpb_lu), + GFP_KERNEL); + if (!ufsf->hpb_lup[lun]) { + ERR_MSG("hpb_lup[%d] alloc failed", lun); + return; + } + + hpb = ufsf->hpb_lup[lun]; + hpb->ufsf = ufsf; + hpb->lun = lun; + hpb->lu_num_blocks = lu_desc.lu_logblk_cnt; + hpb->lu_max_active_rgns = lu_desc.lu_max_active_hpb_rgns; + hpb->lru_info.max_lru_active_cnt = + lu_desc.lu_max_active_hpb_rgns - + lu_desc.lu_num_hpb_pinned_rgns; + hpb->lu_pinned_rgn_startidx = + lu_desc.lu_hpb_pinned_rgn_startidx; + hpb->lu_pinned_end_offset = lu_desc.lu_hpb_pinned_end_offset; + } else { + INFO_MSG("===== LU (%d) is hpb-disabled.", lun); + } +} + +static void ufshpb_error_handler(struct work_struct *work) +{ + struct ufsf_feature *ufsf; + + ufsf = container_of(work, struct ufsf_feature, hpb_eh_work); + + WARN_MSG("driver has failed. but UFSHCD can run without UFSHPB"); + WARN_MSG("UFSHPB will be removed from the kernel"); + + ufshpb_remove(ufsf, HPB_FAILED); +} + +extern int ufsplus_hpb_status; +static int ufshpb_init(struct ufsf_feature *ufsf) +{ + int lun, ret; + struct ufshpb_lu *hpb; + int hpb_enabled_lun = 0; + + seq_scan_lu(lun) { + if (!ufsf->hpb_lup[lun]) + continue; + + /* + * HPB need info about request queue in order to issue + * RB-CMD for pinned region. + */ + if (!ufsf->sdev_ufs_lu[lun]) { + WARN_MSG("lun (%d) don't have scsi_device", lun); + continue; + } + + ret = ufshpb_lu_hpb_init(ufsf, lun); + if (ret) { + kfree(ufsf->hpb_lup[lun]); + continue; + } + hpb_enabled_lun++; + } + + if(hpb_enabled_lun) + ufsplus_hpb_status = 1; + + if (hpb_enabled_lun == 0) { + ERR_MSG("No UFSHPB LU to init"); + ret = -ENODEV; + goto hpb_failed; + } + + INIT_WORK(&ufsf->hpb_eh_work, ufshpb_error_handler); + + kref_init(&ufsf->hpb_kref); + ufshpb_set_state(ufsf, HPB_PRESENT); + + seq_scan_lu(lun) + if (ufsf->hpb_lup[lun]) { + hpb = ufsf->hpb_lup[lun]; + + INFO_MSG("UFSHPB LU %d working", lun); + if (hpb->lu_pinned_end_offset != PINNED_NOT_SET) + schedule_work(&hpb->pinned_work); + } + create_hpbfn_enable_proc(); + + return 0; +hpb_failed: + ufshpb_set_state(ufsf, HPB_FAILED); + return ret; +} + +static void ufshpb_drop_retry_list(struct ufshpb_lu *hpb) +{ + struct ufshpb_req *map_req, *next; + unsigned long flags; + + if (list_empty(&hpb->lh_map_req_retry)) + return; + + spin_lock_irqsave(&hpb->hpb_lock, flags); + list_for_each_entry_safe(map_req, next, &hpb->lh_map_req_retry, + list_req) { + INFO_MSG("drop map_req %p ( %d - %d )", map_req, + map_req->rb.rgn_idx, map_req->rb.srgn_idx); + + list_del_init(&map_req->list_req); + + ufshpb_put_map_req(hpb, map_req); + } + spin_unlock_irqrestore(&hpb->hpb_lock, flags); +} + +static void ufshpb_drop_rsp_lists(struct ufshpb_lu *hpb) +{ + struct ufshpb_region *rgn, *next_rgn; + struct ufshpb_subregion *srgn, *next_srgn; + unsigned long flags; + + spin_lock_irqsave(&hpb->rsp_list_lock, flags); + list_for_each_entry_safe(rgn, next_rgn, &hpb->lh_inact_rgn, + list_inact_rgn) { + list_del_init(&rgn->list_inact_rgn); + } + + list_for_each_entry_safe(srgn, next_srgn, &hpb->lh_act_srgn, + list_act_srgn) { + list_del_init(&srgn->list_act_srgn); + } + spin_unlock_irqrestore(&hpb->rsp_list_lock, flags); +} + +static void ufshpb_destroy_subregion_tbl(struct ufshpb_lu *hpb, + struct ufshpb_region *rgn) +{ + int srgn_idx; + + for (srgn_idx = 0; srgn_idx < rgn->srgn_cnt; srgn_idx++) { + struct ufshpb_subregion *srgn; + + srgn = rgn->srgn_tbl + srgn_idx; + srgn->srgn_state = HPB_SRGN_UNUSED; + + ufshpb_put_map_ctx(hpb, srgn->mctx); + } + + kfree(rgn->srgn_tbl); +} + +static void ufshpb_destroy_region_tbl(struct ufshpb_lu *hpb) +{ + int rgn_idx; + + INFO_MSG("Start"); + + for (rgn_idx = 0; rgn_idx < hpb->rgns_per_lu; rgn_idx++) { + struct ufshpb_region *rgn; + + rgn = hpb->rgn_tbl + rgn_idx; + if (rgn->rgn_state == HPB_RGN_PINNED || + rgn->rgn_state == HPB_RGN_ACTIVE) { + rgn->rgn_state = HPB_RGN_INACTIVE; + + ufshpb_destroy_subregion_tbl(hpb, rgn); + } + } + + ufshpb_table_mempool_remove(hpb); + kfree(hpb->rgn_tbl); + + INFO_MSG("End"); +} + +void ufshpb_remove(struct ufsf_feature *ufsf, int state) +{ + struct ufshpb_lu *hpb; + int lun; + + INFO_MSG("start release"); + ufshpb_set_state(ufsf, HPB_FAILED); + + INFO_MSG("kref count (%d)", + atomic_read(&ufsf->hpb_kref.refcount.refs)); + + remove_hpbfn_enable_proc(); + seq_scan_lu(lun) { + hpb = ufsf->hpb_lup[lun]; + + INFO_MSG("lun (%d) (%p)", lun, hpb); + + ufsf->hpb_lup[lun] = NULL; + + if (!hpb) + continue; + + ufshpb_cancel_jobs(hpb); + + ufshpb_destroy_region_tbl(hpb); + if (hpb->alloc_mctx != 0) + WARN_MSG("warning: alloc_mctx (%d)", hpb->alloc_mctx); + + ufshpb_map_req_mempool_remove(hpb); + + ufshpb_pre_req_mempool_remove(hpb); + + ufshpb_remove_sysfs(hpb); + + kfree(hpb); + } + + ufshpb_set_state(ufsf, state); + + INFO_MSG("end release"); +} + +void ufshpb_reset(struct ufsf_feature *ufsf) +{ + ufshpb_set_state(ufsf, HPB_PRESENT); +} + +void ufshpb_reset_host(struct ufsf_feature *ufsf) +{ + struct ufshpb_lu *hpb; + int lun; + + ufshpb_set_state(ufsf, HPB_RESET); + seq_scan_lu(lun) { + hpb = ufsf->hpb_lup[lun]; + if (hpb) { + INFO_MSG("UFSHPB lun %d reset", lun); + ufshpb_cancel_jobs(hpb); + ufshpb_drop_retry_list(hpb); + ufshpb_drop_rsp_lists(hpb); + } + } +} + +static inline int ufshpb_probe_lun_done(struct ufsf_feature *ufsf) +{ + return (ufsf->num_lu == ufsf->slave_conf_cnt); +} + +void ufshpb_init_handler(struct work_struct *work) +{ + struct ufsf_feature *ufsf; + int ret = 0; + + ufsf = container_of(work, struct ufsf_feature, hpb_init_work); + + INFO_MSG("probe_done(%d)", ufshpb_probe_lun_done(ufsf)); + + ret = wait_event_timeout(ufsf->hpb_wait, + ufshpb_probe_lun_done(ufsf), + msecs_to_jiffies(10000)); + if (ret == 0) + ERR_MSG("Probing LU is not fully complete."); + + INFO_MSG("probe_done(%d) ret(%d)", ufshpb_probe_lun_done(ufsf), ret); + INFO_MSG("HPB_INIT_START"); + + ret = ufshpb_init(ufsf); + if (ret) + ERR_MSG("UFSHPB driver init failed. (%d)", ret); +} + +void ufshpb_suspend(struct ufsf_feature *ufsf) +{ + struct ufshpb_lu *hpb; + int lun; + + seq_scan_lu(lun) { + hpb = ufsf->hpb_lup[lun]; + if (hpb) { + INFO_MSG("ufshpb_lu %d goto suspend", lun); + INFO_MSG("ufshpb_lu %d changes suspend state", lun); + ufshpb_set_state(ufsf, HPB_SUSPEND); + ufshpb_cancel_jobs(hpb); + } + } +} + +void ufshpb_resume(struct ufsf_feature *ufsf) +{ + struct ufshpb_lu *hpb; + int lun; + + seq_scan_lu(lun) { + hpb = ufsf->hpb_lup[lun]; + if (hpb) { + bool do_task_work = false; + bool do_retry_work = false; + + ufshpb_set_state(ufsf, HPB_PRESENT); + + do_task_work = !ufshpb_is_empty_rsp_lists(hpb); + do_retry_work = + !list_empty_careful(&hpb->lh_map_req_retry); + + INFO_MSG("ufshpb_lu %d resume. do_task_work %d retry %d", + lun, do_task_work, do_retry_work); + + if (do_task_work) + schedule_work(&hpb->task_work); + if (do_retry_work) + schedule_delayed_work(&hpb->retry_work, + msecs_to_jiffies(100)); + } + } +} + +static void ufshpb_stat_init(struct ufshpb_lu *hpb) +{ + atomic64_set(&hpb->hit, 0); + atomic64_set(&hpb->miss, 0); + atomic64_set(&hpb->rb_noti_cnt, 0); + atomic64_set(&hpb->rb_active_cnt, 0); + atomic64_set(&hpb->rb_inactive_cnt, 0); + atomic64_set(&hpb->map_req_cnt, 0); + atomic64_set(&hpb->pre_req_cnt, 0); + ufsf_para.hit = 0; + ufsf_para.miss = 0; + ufsf_para.hit_4k = 0; + ufsf_para.hit_8_32k = 0; + ufsf_para.span = 0; + ufsf_para.span_hit = 0; + ufsf_para.noti = 0; + ufsf_para.noti_act = 0; + ufsf_para.noti_inact = 0; + ufsf_para.rgn_act = 0; + ufsf_para.map_req = 0; + ufsf_para.pre_req = 0; +} + +/* SYSFS functions */ +static ssize_t ufshpb_sysfs_prep_disable_show(struct ufshpb_lu *hpb, char *buf) +{ + int ret; + + ret = snprintf(buf, PAGE_SIZE, "force_hpb_read_disable %d\n", + hpb->force_disable); + + INFO_MSG("force_hpb_read_disable %d", hpb->force_disable); + return ret; +} + +static ssize_t ufshpb_sysfs_prep_disable_store(struct ufshpb_lu *hpb, + const char *buf, size_t cnt) +{ + unsigned long value; + + if (kstrtoul(buf, 0, &value)) + return -EINVAL; + + if (value > 1) + return -EINVAL; + + if (value == 1) + hpb->force_disable = true; + else if (value == 0) + hpb->force_disable = false; + + INFO_MSG("force_hpb_read_disable %d", hpb->force_disable); + + return cnt; +} + +static ssize_t ufshpb_sysfs_map_disable_show(struct ufshpb_lu *hpb, char *buf) +{ + int ret; + + ret = snprintf(buf, PAGE_SIZE, "force_map_req_disable %d\n", + hpb->force_map_req_disable); + + INFO_MSG("force_map_req_disable %d", hpb->force_map_req_disable); + + return ret; +} + +static ssize_t ufshpb_sysfs_map_disable_store(struct ufshpb_lu *hpb, + const char *buf, size_t cnt) +{ + unsigned long value; + + if (kstrtoul(buf, 0, &value)) + return -EINVAL; + + if (value > 1) + return -EINVAL; + + if (value == 1) + hpb->force_map_req_disable = true; + else if (value == 0) + hpb->force_map_req_disable = false; + + INFO_MSG("force_map_req_disable %d", hpb->force_map_req_disable); + + return cnt; +} + +static ssize_t ufshpb_sysfs_throttle_map_req_show(struct ufshpb_lu *hpb, + char *buf) +{ + int ret; + + ret = snprintf(buf, PAGE_SIZE, "throttle_map_req %d\n", + hpb->throttle_map_req); + + INFO_MSG("throttle_map_req %d", hpb->throttle_map_req); + + return ret; +} + +static ssize_t ufshpb_sysfs_throttle_map_req_store(struct ufshpb_lu *hpb, + const char *buf, size_t cnt) +{ + unsigned long throttle_map_req; + + if (kstrtoul(buf, 0, &throttle_map_req)) + return -EINVAL; + + hpb->throttle_map_req = (int)throttle_map_req; + + INFO_MSG("throttle_map_req %d", hpb->throttle_map_req); + + return cnt; +} + +static ssize_t ufshpb_sysfs_throttle_pre_req_show(struct ufshpb_lu *hpb, + char *buf) +{ + int ret; + + ret = snprintf(buf, PAGE_SIZE, "throttle_pre_req %d\n", + hpb->throttle_pre_req); + + INFO_MSG("throttle_pre_req %d", hpb->throttle_pre_req); + + return ret; +} + +static ssize_t ufshpb_sysfs_throttle_pre_req_store(struct ufshpb_lu *hpb, + const char *buf, size_t cnt) +{ + unsigned long throttle_pre_req; + + if (kstrtoul(buf, 0, &throttle_pre_req)) + return -EINVAL; + + hpb->throttle_pre_req = (int)throttle_pre_req; + + INFO_MSG("throttle_pre_req %d", hpb->throttle_pre_req); + + return cnt; +} + +static ssize_t ufshpb_sysfs_pre_req_min_tr_len_show(struct ufshpb_lu *hpb, + char *buf) +{ + int ret; + + ret = snprintf(buf, PAGE_SIZE, "%d", hpb->pre_req_min_tr_len); + INFO_MSG("pre_req min transfer len %d", hpb->pre_req_min_tr_len); + + return ret; +} + +static ssize_t ufshpb_sysfs_pre_req_min_tr_len_store(struct ufshpb_lu *hpb, + const char *buf, + size_t count) +{ + unsigned long val; + + if (kstrtoul(buf, 0, &val)) + return -EINVAL; + + if (val < 0) + val = 0; + + if (hpb->pre_req_max_tr_len < val || val < HPB_MULTI_CHUNK_LOW) + INFO_MSG("value is wrong. pre_req transfer len %d ~ %d", + HPB_MULTI_CHUNK_LOW, hpb->pre_req_max_tr_len); + else + hpb->pre_req_min_tr_len = val; + + INFO_MSG("pre_req min transfer len %d", hpb->pre_req_min_tr_len); + + return count; +} + +static ssize_t ufshpb_sysfs_pre_req_max_tr_len_show(struct ufshpb_lu *hpb, + char *buf) +{ + int ret; + + ret = snprintf(buf, PAGE_SIZE, "%d", hpb->pre_req_max_tr_len); + INFO_MSG("pre_req max transfer len %d", hpb->pre_req_max_tr_len); + + return ret; +} + +static ssize_t ufshpb_sysfs_pre_req_max_tr_len_store(struct ufshpb_lu *hpb, + const char *buf, + size_t count) +{ + unsigned long val; + + if (kstrtoul(buf, 0, &val)) + return -EINVAL; + + if (hpb->pre_req_min_tr_len > val || val > HPB_MULTI_CHUNK_HIGH) + INFO_MSG("value is wrong. pre_req transfer len %d ~ %d", + hpb->pre_req_min_tr_len, HPB_MULTI_CHUNK_HIGH); + else + hpb->pre_req_max_tr_len = val; + + INFO_MSG("pre_req max transfer len %d", hpb->pre_req_max_tr_len); + + return count; +} + +static ssize_t ufshpb_sysfs_debug_show(struct ufshpb_lu *hpb, char *buf) +{ + int ret; + + ret = snprintf(buf, PAGE_SIZE, "debug %d\n", hpb->debug); + + INFO_MSG("debug %d", hpb->debug); + + return ret; +} + +static ssize_t ufshpb_sysfs_debug_store(struct ufshpb_lu *hpb, + const char *buf, size_t cnt) +{ + unsigned long debug; + + if (kstrtoul(buf, 0, &debug)) + return -EINVAL; + + if (debug >= 1) + hpb->debug = 1; + else + hpb->debug = 0; + + INFO_MSG("debug %d", hpb->debug); + + return cnt; +} + +#if defined(CONFIG_HPB_ERR_INJECTION) +static ssize_t ufshpb_sysfs_err_injection_select_show(struct ufshpb_lu *hpb, + char *buf) +{ + char error_injection[8]; + int ret; + + if (hpb->err_injection_select == HPB_ERR_INJECTION_DISABLE) + strlcpy(error_injection, "disable", 8); + else if (hpb->err_injection_select == HPB_ERR_INJECTION_BITFLIP) + strlcpy(error_injection, "bitflip", 8); + else if (hpb->err_injection_select == HPB_ERR_INJECTION_OFFSET) + strlcpy(error_injection, "offset", 7); + else if (hpb->err_injection_select == HPB_ERR_INJECTION_RANDOM) + strlcpy(error_injection, "random", 7); + + ret = snprintf(buf, PAGE_SIZE, "err_injection_select %s\n", + error_injection); + + INFO_MSG("err_injection_select %s", error_injection); + + return ret; +} + +static ssize_t ufshpb_sysfs_err_injection_select_store(struct ufshpb_lu *hpb, + const char *buf, + size_t cnt) +{ + char error_injection[8]; + int ret; + + error_injection[7] = '\0'; + + ret = sscanf(buf, "%7s", error_injection); + if (!ret) { + INFO_MSG("input failed..."); + return cnt; + } + + if (!strncmp(error_injection, "disable", 7)) + hpb->err_injection_select = HPB_ERR_INJECTION_DISABLE; + else if (!strncmp(error_injection, "bitflip", 7)) + hpb->err_injection_select = HPB_ERR_INJECTION_BITFLIP; + else if (!strncmp(error_injection, "offset", 6)) + hpb->err_injection_select = HPB_ERR_INJECTION_OFFSET; + else if (!strncmp(error_injection, "random", 6)) + hpb->err_injection_select = HPB_ERR_INJECTION_RANDOM; + else { + hpb->err_injection_select = HPB_ERR_INJECTION_DISABLE; + strlcpy(error_injection, "disable", 8); + } + + INFO_MSG("err_injection_select %s", error_injection); + + return cnt; +} + +static ssize_t ufshpb_sysfs_err_injection_bitflip_show(struct ufshpb_lu *hpb, + char *buf) +{ + int ret; + + ret = snprintf(buf, PAGE_SIZE, "err_injection_bitflip %llx\n", + hpb->err_injection_bitflip); + + INFO_MSG("err_injection_bitflip %llx", hpb->err_injection_bitflip); + + return ret; +} + +static ssize_t ufshpb_sysfs_err_injection_bitflip_store(struct ufshpb_lu *hpb, + const char *buf, + size_t cnt) +{ + unsigned long long err_injection_bitflip; + + if (kstrtoull(buf, 0, &err_injection_bitflip)) + return -EINVAL; + + hpb->err_injection_bitflip = err_injection_bitflip; + + INFO_MSG("err_injection_bitflip %llx", hpb->err_injection_bitflip); + + return cnt; +} + +static ssize_t ufshpb_sysfs_err_injection_offset_show(struct ufshpb_lu *hpb, + char *buf) +{ + int ret; + + ret = snprintf(buf, PAGE_SIZE, "err_injection_offset %lld\n", + hpb->err_injection_offset); + + INFO_MSG("err_injection_offset %lld", hpb->err_injection_offset); + + return ret; +} + +static ssize_t ufshpb_sysfs_err_injection_offset_store(struct ufshpb_lu *hpb, + const char *buf, + size_t cnt) +{ + unsigned long long err_injection_offset; + + if (kstrtoull(buf, 0, &err_injection_offset)) + return -EINVAL; + + hpb->err_injection_offset = err_injection_offset; + + INFO_MSG("err_injection_offset %lld", hpb->err_injection_offset); + + return cnt; +} + +static ssize_t ufshpb_sysfs_err_injection_random_show(struct ufshpb_lu *hpb, + char *buf) +{ + int ret; + + ret = snprintf(buf, PAGE_SIZE, "err_injection_random %d\n", + hpb->err_injection_random); + + INFO_MSG("err_injection_random %d", hpb->err_injection_random); + + return ret; +} + +static ssize_t ufshpb_sysfs_err_injection_random_store(struct ufshpb_lu *hpb, + const char *buf, + size_t cnt) +{ + unsigned long err_injection_random; + + if (kstrtoul(buf, 0, &err_injection_random)) + return -EINVAL; + + if (err_injection_random >= 1) + hpb->err_injection_random = 1; + else + hpb->err_injection_random = 0; + + INFO_MSG("err_injection_random %d", hpb->err_injection_random); + + return cnt; +} +#endif + +static ssize_t ufshpb_sysfs_version_show(struct ufshpb_lu *hpb, char *buf) +{ + int ret; + + ret = snprintf(buf, PAGE_SIZE, "HPB version %.4X D/D version %.6X%s\n", + hpb->ufsf->hpb_dev_info.version, + UFSHPB_DD_VER, UFSHPB_DD_VER_POST); + + INFO_MSG("HPB version %.4X D/D version %.6X%s", + hpb->ufsf->hpb_dev_info.version, + UFSHPB_DD_VER, UFSHPB_DD_VER_POST); + + return ret; +} + +static ssize_t ufshpb_sysfs_hit_show(struct ufshpb_lu *hpb, char *buf) +{ + long long hit_cnt, hit_4k_cnt, hit_8_32k_cnt, span_cnt, span_hit_cnt; + int ret; + + hit_cnt = atomic64_read(&hpb->hit); + hit_4k_cnt = ufsf_para.hit_4k; + hit_8_32k_cnt = ufsf_para.hit_8_32k; + span_cnt = ufsf_para.span; + span_hit_cnt = ufsf_para.span_hit; + + ret = snprintf(buf, PAGE_SIZE, + "hit_count %lld hit_4k_count %lld hit_8-32k_count %lld" + " span_cnt %lld span_hit_cnt %lld\n", hit_cnt, + hit_4k_cnt, hit_8_32k_cnt, span_cnt, span_hit_cnt); + INFO_MSG("%s", buf); + + return ret; +} + +static ssize_t ufshpb_sysfs_miss_show(struct ufshpb_lu *hpb, char *buf) +{ + long long miss_cnt; + int ret; + + miss_cnt = atomic64_read(&hpb->miss); + + ret = snprintf(buf, PAGE_SIZE, "miss_count %lld\n", miss_cnt); + + INFO_MSG("miss_count %lld", miss_cnt); + + return ret; +} + +static ssize_t ufshpb_sysfs_map_req_show(struct ufshpb_lu *hpb, char *buf) +{ + long long rb_noti_cnt, rb_active_cnt, rb_inactive_cnt, map_req_cnt; + int ret; + + rb_noti_cnt = atomic64_read(&hpb->rb_noti_cnt); + rb_active_cnt = atomic64_read(&hpb->rb_active_cnt); + rb_inactive_cnt = atomic64_read(&hpb->rb_inactive_cnt); + map_req_cnt = atomic64_read(&hpb->map_req_cnt); + + ret = snprintf(buf, PAGE_SIZE, + "rb_noti %lld ACT %lld INACT %lld map_req_count %lld\n", + rb_noti_cnt, rb_active_cnt, rb_inactive_cnt, + map_req_cnt); + + INFO_MSG("rb_noti %lld ACT %lld INACT %lld map_req_count %lld", + rb_noti_cnt, rb_active_cnt, rb_inactive_cnt, + map_req_cnt); + + return ret; +} + +static ssize_t ufshpb_sysfs_pre_req_show(struct ufshpb_lu *hpb, char *buf) +{ + long long pre_req_cnt; + int ret; + + pre_req_cnt = atomic64_read(&hpb->pre_req_cnt); + + ret = snprintf(buf, PAGE_SIZE, "pre_req_count %lld\n", pre_req_cnt); + + INFO_MSG("pre_req_count %lld", pre_req_cnt); + + return ret; +} + +static ssize_t ufshpb_sysfs_region_stat_show(struct ufshpb_lu *hpb, char *buf) +{ + int ret, pin_cnt = 0, act_cnt = 0, inact_cnt = 0, rgn_idx; + enum HPB_RGN_STATE state; + + for (rgn_idx = 0; rgn_idx < hpb->rgns_per_lu; rgn_idx++) { + state = hpb->rgn_tbl[rgn_idx].rgn_state; + if (state == HPB_RGN_PINNED) + pin_cnt++; + else if (state == HPB_RGN_ACTIVE) + act_cnt++; + else if (state == HPB_RGN_INACTIVE) + inact_cnt++; + } + + ret = snprintf(buf, PAGE_SIZE, + "Total %d pinned %d active %d inactive %d\n", + hpb->rgns_per_lu, pin_cnt, act_cnt, inact_cnt); + + INFO_MSG("Total %d pinned %d active %d inactive %d", + hpb->rgns_per_lu, pin_cnt, act_cnt, inact_cnt); + + return ret; +} + +static ssize_t ufshpb_sysfs_count_reset_store(struct ufshpb_lu *hpb, + const char *buf, size_t cnt) +{ + unsigned long debug; + + if (kstrtoul(buf, 0, &debug)) + return -EINVAL; + + INFO_MSG("Stat Init"); + + ufshpb_stat_init(hpb); + + return cnt; +} + +static ssize_t ufshpb_sysfs_info_lba_store(struct ufshpb_lu *hpb, + const char *buf, size_t cnt) +{ + struct ufshpb_region *rgn; + struct ufshpb_subregion *srgn; + u64 ppn = 0; + unsigned long value, lpn, flags; + int rgn_idx, srgn_idx, srgn_offset, error = 0; + + if (kstrtoul(buf, 0, &value)) { + ERR_MSG("kstrtoul error"); + return -EINVAL; + } + + if (value > hpb->lu_num_blocks * SECTORS_PER_BLOCK) { + ERR_MSG("value %lu > lu_num_blocks %d error", + value, hpb->lu_num_blocks); + return -EINVAL; + } + + lpn = value / SECTORS_PER_BLOCK; + + ufshpb_get_pos_from_lpn(hpb, lpn, &rgn_idx, &srgn_idx, &srgn_offset); + + rgn = hpb->rgn_tbl + rgn_idx; + srgn = rgn->srgn_tbl + srgn_idx; + + spin_lock_irqsave(&hpb->hpb_lock, flags); + INFO_MSG("lba %lu lpn %lu region %d state %d subregion %d state %d", + value, lpn, rgn_idx, rgn->rgn_state, srgn_idx, + srgn->srgn_state); + + if (!ufshpb_valid_srgn(rgn, srgn)) { + INFO_MSG("[region %d subregion %d] has not valid hpb info.", + rgn_idx, srgn_idx); + goto out; + } + + if (!srgn->mctx) { + INFO_MSG("mctx is NULL"); + goto out; + } + + ppn = ufshpb_get_ppn(srgn->mctx, srgn_offset, &error); + if (error) { + INFO_MSG("getting ppn is fail from a page."); + goto out; + } + + INFO_MSG("ppn %llx is_dirty %d", ppn, + ufshpb_ppn_dirty_check(hpb, lpn, 1)); +out: + spin_unlock_irqrestore(&hpb->hpb_lock, flags); + return cnt; +} + +static ssize_t ufshpb_sysfs_info_region_store(struct ufshpb_lu *hpb, + const char *buf, size_t cnt) +{ + unsigned long rgn_idx; + int srgn_idx; + + if (kstrtoul(buf, 0, &rgn_idx)) + return -EINVAL; + + if (rgn_idx >= hpb->rgns_per_lu) + ERR_MSG("error region %ld max %d", rgn_idx, hpb->rgns_per_lu); + else { + INFO_MSG("(region state : PINNED=%d ACTIVE=%d INACTIVE=%d)", + HPB_RGN_PINNED, HPB_RGN_ACTIVE, HPB_RGN_INACTIVE); + + INFO_MSG("region %ld state %d", rgn_idx, + hpb->rgn_tbl[rgn_idx].rgn_state); + + for (srgn_idx = 0; srgn_idx < hpb->rgn_tbl[rgn_idx].srgn_cnt; + srgn_idx++) { + INFO_MSG("--- subregion %d state %d", srgn_idx, + hpb->rgn_tbl[rgn_idx].srgn_tbl[srgn_idx].srgn_state); + } + } + + return cnt; +} + +static ssize_t ufshpb_sysfs_ufshpb_release_store(struct ufshpb_lu *hpb, + const char *buf, size_t cnt) +{ + unsigned long value; + + INFO_MSG("start release function"); + + if (kstrtoul(buf, 0, &value)) { + ERR_MSG("kstrtoul error"); + return -EINVAL; + } + + if (value == 0xab) { + INFO_MSG("magic number %lu release start", value); + goto err_out; + } else + INFO_MSG("wrong magic number %lu", value); + + return cnt; +err_out: + INFO_MSG("ref_cnt %d", + atomic_read(&hpb->ufsf->hpb_kref.refcount.refs)); + ufshpb_failed(hpb, __func__); + + return cnt; +} + +static struct ufshpb_sysfs_entry ufshpb_sysfs_entries[] = { + __ATTR(hpb_read_disable, 0644, + ufshpb_sysfs_prep_disable_show, ufshpb_sysfs_prep_disable_store), + __ATTR(map_cmd_disable, 0644, + ufshpb_sysfs_map_disable_show, ufshpb_sysfs_map_disable_store), + __ATTR(throttle_map_req, 0644, + ufshpb_sysfs_throttle_map_req_show, + ufshpb_sysfs_throttle_map_req_store), + __ATTR(throttle_pre_req, 0644, + ufshpb_sysfs_throttle_pre_req_show, + ufshpb_sysfs_throttle_pre_req_store), + __ATTR(pre_req_min_tr_len, 0644, + ufshpb_sysfs_pre_req_min_tr_len_show, + ufshpb_sysfs_pre_req_min_tr_len_store), + __ATTR(pre_req_max_tr_len, 0644, + ufshpb_sysfs_pre_req_max_tr_len_show, + ufshpb_sysfs_pre_req_max_tr_len_store), + __ATTR(debug, 0644, + ufshpb_sysfs_debug_show, ufshpb_sysfs_debug_store), +#if defined(CONFIG_HPB_ERR_INJECTION) + __ATTR(err_injection_select, 0644, + ufshpb_sysfs_err_injection_select_show, + ufshpb_sysfs_err_injection_select_store), + __ATTR(err_injection_bitflip, 0644, + ufshpb_sysfs_err_injection_bitflip_show, + ufshpb_sysfs_err_injection_bitflip_store), + __ATTR(err_injection_offset, 0644, + ufshpb_sysfs_err_injection_offset_show, + ufshpb_sysfs_err_injection_offset_store), + __ATTR(err_injection_random, 0644, + ufshpb_sysfs_err_injection_random_show, + ufshpb_sysfs_err_injection_random_store), +#endif + __ATTR(hpb_version, 0444, ufshpb_sysfs_version_show, NULL), + __ATTR(hit_count, 0444, ufshpb_sysfs_hit_show, NULL), + __ATTR(miss_count, 0444, ufshpb_sysfs_miss_show, NULL), + __ATTR(map_req_count, 0444, ufshpb_sysfs_map_req_show, NULL), + __ATTR(pre_req_count, 0444, ufshpb_sysfs_pre_req_show, NULL), + __ATTR(region_stat_count, 0444, ufshpb_sysfs_region_stat_show, NULL), + __ATTR(count_reset, 0200, NULL, ufshpb_sysfs_count_reset_store), + __ATTR(get_info_from_lba, 0200, NULL, ufshpb_sysfs_info_lba_store), + __ATTR(get_info_from_region, 0200, NULL, + ufshpb_sysfs_info_region_store), + __ATTR(release, 0200, NULL, ufshpb_sysfs_ufshpb_release_store), + __ATTR_NULL +}; + +static ssize_t ufshpb_attr_show(struct kobject *kobj, struct attribute *attr, + char *page) +{ + struct ufshpb_sysfs_entry *entry; + struct ufshpb_lu *hpb; + ssize_t error; + + entry = container_of(attr, struct ufshpb_sysfs_entry, attr); + hpb = container_of(kobj, struct ufshpb_lu, kobj); + + if (!entry->show) + return -EIO; + + mutex_lock(&hpb->sysfs_lock); + error = entry->show(hpb, page); + mutex_unlock(&hpb->sysfs_lock); + return error; +} + +static ssize_t ufshpb_attr_store(struct kobject *kobj, struct attribute *attr, + const char *page, size_t len) +{ + struct ufshpb_sysfs_entry *entry; + struct ufshpb_lu *hpb; + ssize_t error; + + entry = container_of(attr, struct ufshpb_sysfs_entry, attr); + hpb = container_of(kobj, struct ufshpb_lu, kobj); + + if (!entry->store) + return -EIO; + + mutex_lock(&hpb->sysfs_lock); + error = entry->store(hpb, page, len); + mutex_unlock(&hpb->sysfs_lock); + return error; +} + +static const struct sysfs_ops ufshpb_sysfs_ops = { + .show = ufshpb_attr_show, + .store = ufshpb_attr_store, +}; + +static struct kobj_type ufshpb_ktype = { + .sysfs_ops = &ufshpb_sysfs_ops, + .release = NULL, +}; + +static int ufshpb_create_sysfs(struct ufsf_feature *ufsf, struct ufshpb_lu *hpb) +{ + struct device *dev = ufsf->hba->dev; + struct ufshpb_sysfs_entry *entry; + int err; + + hpb->sysfs_entries = ufshpb_sysfs_entries; + + ufshpb_stat_init(hpb); + + kobject_init(&hpb->kobj, &ufshpb_ktype); + mutex_init(&hpb->sysfs_lock); + + INFO_MSG("ufshpb creates sysfs lu %d %p dev->kobj %p", hpb->lun, + &hpb->kobj, &dev->kobj); + + err = kobject_add(&hpb->kobj, kobject_get(&dev->kobj), + "ufshpb_lu%d", hpb->lun); + if (!err) { + for (entry = hpb->sysfs_entries; entry->attr.name != NULL; + entry++) { + INFO_MSG("ufshpb_lu%d sysfs attr creates: %s", + hpb->lun, entry->attr.name); + if (sysfs_create_file(&hpb->kobj, &entry->attr)) + break; + } + INFO_MSG("ufshpb_lu%d sysfs adds uevent", hpb->lun); + kobject_uevent(&hpb->kobj, KOBJ_ADD); + } + + return err; +} + +static inline void ufshpb_remove_sysfs(struct ufshpb_lu *hpb) +{ + kobject_uevent(&hpb->kobj, KOBJ_REMOVE); + INFO_MSG("ufshpb removes sysfs lu %d %p ", hpb->lun, &hpb->kobj); + kobject_del(&hpb->kobj); +} + +static inline void hpbfn_enable_ctrl(struct ufshpb_lu *hpb, long val) +{ + switch (val) { + case 0: + hpb->force_map_req_disable = true; + hpb->force_disable = true; + break; + case 1: + hpb->force_map_req_disable = false; + hpb->force_disable = false; + break; + case 2: + ufshpb_failed(hpb, __func__); + break; + default: + break; + } + + return; +} + +static ssize_t hpbfn_enable_write(struct file *filp, const char *ubuf, + size_t cnt, loff_t *data) +{ + char buf[64] = {0}; + long val = 64; + int lun; + + if (!ufsf_para.ufsf) + return -EFAULT; + if (cnt >= sizeof(buf)) + return -EINVAL; + if (copy_from_user(&buf, ubuf, cnt)) + return -EFAULT; + + if (buf[0] == '0') + val = 0; + else if (buf[0] == '1') + val = 1; + else if (buf[0] == '2') + val = 2; + else + val = 64; + + seq_scan_lu(lun) { + if (ufsf_para.ufsf->hpb_lup[lun]) + hpbfn_enable_ctrl(ufsf_para.ufsf->hpb_lup[lun], + val); + } + + return cnt; +} + +static const struct file_operations hpbfn_enable_fops = { + .write = hpbfn_enable_write, +}; + +static int create_hpbfn_enable_proc(void) +{ + struct proc_dir_entry *d_entry; + + if (!ufsf_para.ctrl_dir) + return -EFAULT; + + d_entry = proc_create("hpbfn_enable", S_IWUGO, ufsf_para.ctrl_dir, + &hpbfn_enable_fops); + if(!d_entry) + return -ENOMEM; + + return 0; +} + +static void remove_hpbfn_enable_proc(void) +{ + if (ufsf_para.ctrl_dir) + remove_proc_entry("hpbfn_enable", ufsf_para.ctrl_dir); + + return; +} diff --git a/drivers/scsi/ufs/ufshpb.h b/drivers/scsi/ufs/ufshpb.h new file mode 100644 index 000000000000..ae488fbdb987 --- /dev/null +++ b/drivers/scsi/ufs/ufshpb.h @@ -0,0 +1,349 @@ +/* + * Universal Flash Storage Host Performance Booster + * + * Copyright (C) 2017-2018 Samsung Electronics Co., Ltd. + * Copyright (C) 2020 Oplus. All rights reserved. + * + * Authors: + * Yongmyung Lee + * Jinyoung Choi + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * See the COPYING file in the top-level directory or visit + * + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * This program is provided "AS IS" and "WITH ALL FAULTS" and + * without warranty of any kind. You are solely responsible for + * determining the appropriateness of using and distributing + * the program and assume all risks associated with your exercise + * of rights with respect to the program, including but not limited + * to infringement of third party rights, the risks and costs of + * program errors, damage to or loss of data, programs or equipment, + * and unavailability or interruption of operations. Under no + * circumstances will the contributor of this Program be liable for + * any damages of any kind arising from your use or distribution of + * this program. + * + * The Linux Foundation chooses to take subject only to the GPLv2 + * license terms, and distributes only under these terms. + */ + +#ifndef _UFSHPB_H_ +#define _UFSHPB_H_ + +#include +#include +#include +#include +#include +#include + +#if defined(CONFIG_HPB_ERR_INJECTION) +#include +#endif + +#include "../../../block/blk.h" +#include "../../../drivers/scsi/scsi_priv.h" + +/* Version info*/ +#define UFSHPB_VER_2_0_0 0x0200 +#define UFSHPB_VER_2_0_1 0x0201 +#define UFSHPB_VER_2_2_1 0x0221 +#define UFSHPB_DD_VER 0x020400 +#define UFSHPB_DD_VER_POST "_RC03" + +/* Constant value*/ +#define MAX_ACTIVE_NUM 2 +#define MAX_INACTIVE_NUM 2 + +#define HPB_ENTRY_SIZE 0x08 +#define HPB_ENTREIS_PER_OS_PAGE (OS_PAGE_SIZE / HPB_ENTRY_SIZE) + +#define RETRY_DELAY_MS 5000 + +/* HPB Support Chunk Size */ +#define HPB_4_CHUNK_LEN 1 +#define HPB_32_CHUNK_LEN 8 +#define HPB_512_CHUNK_LEN 128 +#define HPB_MULTI_CHUNK_LOW 9 +#define HPB_MULTI_CHUNK_HIGH 128 +#define MAX_HPB_CONTEXT_ID 0x7f + +/* Description */ +#define UFS_FEATURE_SUPPORT_HPB_BIT 0x80 + +/* Response UPIU types */ +#define HPB_RSP_NONE 0x00 +#define HPB_RSP_REQ_REGION_UPDATE 0x01 + +/* Vender defined OPCODE */ +#define UFSHPB_READ_BUFFER 0xF9 +#define UFSHPB_WRITE_BUFFER 0xFA + +#define UFSHPB_GROUP_NUMBER 0x11 +#define UFSHPB_READ_BUFFER_ID 0x01 +#define UFSHPB_WRITE_BUFFER_ID 0x02 +#define TRANSFER_LEN 0x01 + +#define DEV_DATA_SEG_LEN 0x14 +#define DEV_SENSE_SEG_LEN 0x12 +#define DEV_DES_TYPE 0x80 +#define DEV_ADDITIONAL_LEN 0x10 + +#define PINNED_NOT_SET (-1) +/* + * UFSHPB DEBUG + */ + +#define HPB_DEBUG(hpb, msg, args...) \ + do { if (hpb->debug) \ + printk(KERN_ERR "%s:%d " msg "\n", \ + __func__, __LINE__, ##args); \ + } while (0) + +#define TMSG_CMD(hpb, msg, rq, rgn, srgn) \ + do { if (hpb->ufsf->sdev_ufs_lu[hpb->lun] && \ + hpb->ufsf->sdev_ufs_lu[hpb->lun]->request_queue) \ + blk_add_trace_msg(hpb->ufsf->sdev_ufs_lu[hpb->lun]->request_queue, \ + "%llu + %u " msg " %d - %d", \ + (unsigned long long) blk_rq_pos(rq), \ + (unsigned int) blk_rq_sectors(rq), rgn, srgn); \ + } while (0) + +enum UFSHPB_STATE { + HPB_PRESENT = 1, + HPB_SUSPEND = 2, + HPB_FAILED = -2, + HPB_NEED_INIT = 0, + HPB_RESET = -3, +}; + +enum HPB_RGN_STATE { + HPB_RGN_INACTIVE, + HPB_RGN_ACTIVE, + HPB_RGN_PINNED, +}; + +enum HPB_SRGN_STATE { + HPB_SRGN_UNUSED, + HPB_SRGN_DIRTY, + HPB_SRGN_CLEAN, + HPB_SRGN_ISSUED, +}; + +#if defined(CONFIG_HPB_ERR_INJECTION) +enum HPB_ERR_INJECTION_SELECT { + HPB_ERR_INJECTION_DISABLE, + HPB_ERR_INJECTION_BITFLIP, + HPB_ERR_INJECTION_OFFSET, + HPB_ERR_INJECTION_RANDOM, +}; +#endif + +struct ufshpb_dev_info { + int num_lu; + int version; + int rgn_size; + int srgn_size; +}; + +struct ufshpb_active_field { + __be16 active_rgn; + __be16 active_srgn; +} __packed; + +struct ufshpb_rsp_field { + __be16 sense_data_len; + u8 desc_type; + u8 additional_len; + u8 hpb_type; + u8 reserved; + u8 active_rgn_cnt; + u8 inactive_rgn_cnt; + struct ufshpb_active_field hpb_active_field[2]; + __be16 hpb_inactive_field[2]; +} __packed; + +struct ufshpb_map_ctx { + struct page **m_page; + unsigned int *ppn_dirty; + + struct list_head list_table; +}; + +struct ufshpb_subregion { + struct ufshpb_map_ctx *mctx; + enum HPB_SRGN_STATE srgn_state; + int rgn_idx; + int srgn_idx; + + /* below information is used by rsp_list */ + struct list_head list_act_srgn; +}; + +struct ufshpb_region { + struct ufshpb_subregion *srgn_tbl; + enum HPB_RGN_STATE rgn_state; + int rgn_idx; + int srgn_cnt; + + /* below information is used by rsp_list */ + struct list_head list_inact_rgn; + + /* below information is used by lru */ + struct list_head list_lru_rgn; +}; + +struct ufshpb_req { + struct request *req; + struct bio *bio; + struct ufshpb_lu *hpb; + struct list_head list_req; + void (*end_io)(struct request *rq, int err); + void *end_io_data; + char sense[SCSI_SENSE_BUFFERSIZE]; + + union { + struct { + struct ufshpb_map_ctx *mctx; + unsigned int rgn_idx; + unsigned int srgn_idx; + unsigned int lun; + } rb; + struct { + struct page *m_page; + unsigned int len; + unsigned long lpn; + } wb; + }; +}; + +enum selection_type { + LRU = 1, +}; + +struct victim_select_info { + int selection_type; + struct list_head lh_lru_rgn; + int max_lru_active_cnt; /* supported hpb #region - pinned #region */ + atomic64_t active_cnt; +}; + +struct ufshpb_lu { + struct ufsf_feature *ufsf; + int lun; + int qd; + struct ufshpb_region *rgn_tbl; + + spinlock_t hpb_lock; + + spinlock_t retry_list_lock; + struct ufshpb_req *map_req; + int num_inflight_map_req; + int throttle_map_req; + struct list_head lh_map_req_free; + struct list_head lh_map_req_retry; + struct list_head lh_map_ctx_free; + + spinlock_t rsp_list_lock; + struct list_head lh_pinned_srgn; + struct list_head lh_act_srgn; + struct list_head lh_inact_rgn; + + struct kobject kobj; + struct mutex sysfs_lock; + struct ufshpb_sysfs_entry *sysfs_entries; + + struct ufshpb_req *pre_req; + int num_inflight_pre_req; + int throttle_pre_req; + struct list_head lh_pre_req_free; + struct list_head lh_pre_req_dummy; /* dummy for blk_start_requests() */ + int ctx_id_ticket; + int pre_req_min_tr_len; + int pre_req_max_tr_len; + + struct work_struct pinned_work; + struct delayed_work retry_work; + struct work_struct task_work; + + /* for selecting victim */ + struct victim_select_info lru_info; + + int lu_max_active_rgns; + int lu_pinned_rgn_startidx; + int lu_pinned_end_offset; + int srgns_per_lu; + int rgns_per_lu; + int srgns_per_rgn; + int srgn_mem_size; + int entries_per_rgn_shift; + int entries_per_rgn_mask; + int entries_per_srgn; + int entries_per_srgn_shift; + int entries_per_srgn_mask; + int dwords_per_srgn; + unsigned long long srgn_unit_size; + int mpage_bytes; + int mpages_per_srgn; + int lu_num_blocks; + + /* for debug */ + int alloc_mctx; + int debug_free_table; + bool force_disable; + bool force_map_req_disable; + bool debug; + atomic64_t hit; + atomic64_t miss; + atomic64_t rb_noti_cnt; + atomic64_t rb_active_cnt; + atomic64_t rb_inactive_cnt; + atomic64_t map_req_cnt; + atomic64_t pre_req_cnt; + unsigned long lpn_last; +#if defined(CONFIG_HPB_ERR_INJECTION) + enum HPB_ERR_INJECTION_SELECT err_injection_select; + u64 err_injection_bitflip; + u64 err_injection_offset; + int err_injection_random; +#endif +}; + +struct ufshpb_sysfs_entry { + struct attribute attr; + ssize_t (*show)(struct ufshpb_lu *hpb, char *buf); + ssize_t (*store)(struct ufshpb_lu *hpb, const char *, size_t); +}; + +struct ufs_hba; +struct ufshcd_lrb; + +int ufshpb_get_state(struct ufsf_feature *ufsf); +void ufshpb_set_state(struct ufsf_feature *ufsf, int state); +int ufshpb_prepare_pre_req(struct ufsf_feature *ufsf, struct scsi_cmnd *cmd, + int lun); +int ufshpb_prepare_add_lrbp(struct ufsf_feature *ufsf, int add_tag); +void ufshpb_end_pre_req(struct ufsf_feature *ufsf, struct request *req); +void ufshpb_get_dev_info(struct ufsf_feature *ufsf, u8 *desc_buf); +void ufshpb_get_geo_info(struct ufsf_feature *ufsf, u8 *geo_buf); +void ufshpb_get_lu_info(struct ufsf_feature *ufsf, int lun, u8 *unit_buf); +void ufshpb_init_handler(struct work_struct *work); +void ufshpb_rsp_upiu(struct ufsf_feature *ufsf, struct ufshcd_lrb *lrbp); +int ufshpb_issue_req_dev_ctx(struct ufshpb_lu *hpb, unsigned char *buf, + int buf_length); +void ufshpb_resume(struct ufsf_feature *ufsf); +void ufshpb_suspend(struct ufsf_feature *ufsf); +void ufshpb_reset_host(struct ufsf_feature *ufsf); +void ufshpb_reset(struct ufsf_feature *ufsf); +void ufshpb_prep_fn(struct ufsf_feature *ufsf, struct ufshcd_lrb *lrbp); +void ufshpb_remove(struct ufsf_feature *ufsf, int state); +#endif /* End of Header */ diff --git a/drivers/scsi/ufs/ufstw.c b/drivers/scsi/ufs/ufstw.c new file mode 100644 index 000000000000..cae22c0b7b28 --- /dev/null +++ b/drivers/scsi/ufs/ufstw.c @@ -0,0 +1,1224 @@ +/* + * Universal Flash Storage Turbo Write + * + * Copyright (C) 2017-2018 Samsung Electronics Co., Ltd. + * Copyright (C) 2020 Oplus. All rights reserved. + * + * Authors: + * Yongmyung Lee + * Jinyoung Choi + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * See the COPYING file in the top-level directory or visit + * + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * This program is provided "AS IS" and "WITH ALL FAULTS" and + * without warranty of any kind. You are solely responsible for + * determining the appropriateness of using and distributing + * the program and assume all risks associated with your exercise + * of rights with respect to the program, including but not limited + * to infringement of third party rights, the risks and costs of + * program errors, damage to or loss of data, programs or equipment, + * and unavailability or interruption of operations. Under no + * circumstances will the contributor of this Program be liable for + * any damages of any kind arising from your use or distribution of + * this program. + * + * The Linux Foundation chooses to take subject only to the GPLv2 + * license terms, and distributes only under these terms. + */ + +#include + +#include "ufshcd.h" +#include "ufstw.h" + +static int ufstw_create_sysfs(struct ufsf_feature *ufsf, struct ufstw_lu *tw); +static int create_wbfn_enable(void); +static void remove_wbfn_enable(void); +static int create_wbfn_dynamic_tw_enable(void); +static void remove_wbfn_dynamic_tw_enable(void); +inline int ufstw_get_state(struct ufsf_feature *ufsf) +{ + return atomic_read(&ufsf->tw_state); +} + +inline void ufstw_set_state(struct ufsf_feature *ufsf, int state) +{ + atomic_set(&ufsf->tw_state, state); +} + +static int ufstw_is_not_present(struct ufsf_feature *ufsf) +{ + enum UFSTW_STATE cur_state = ufstw_get_state(ufsf); + + if (cur_state != TW_PRESENT) { + INFO_MSG("tw_state != TW_PRESENT (%d)", cur_state); + return -ENODEV; + } + return 0; +} + +#define FLAG_IDN_NAME(idn) \ + (idn == QUERY_FLAG_IDN_WB_EN ? "tw_enable" : \ + idn == QUERY_FLAG_IDN_WB_BUFF_FLUSH_EN ? "flush_enable" : \ + idn == QUERY_FLAG_IDN_WB_BUFF_FLUSH_DURING_HIBERN8 ? \ + "flush_hibern" : "unknown") + +#define ATTR_IDN_NAME(idn) \ + (idn == QUERY_ATTR_IDN_WB_FLUSH_STATUS ? "flush_status" : \ + idn == QUERY_ATTR_IDN_AVAIL_WB_BUFF_SIZE ? "avail_buffer_size" :\ + idn == QUERY_ATTR_IDN_WB_BUFF_LIFE_TIME_EST ? "lifetime_est" : \ + idn == QUERY_ATTR_IDN_CURR_WB_BUFF_SIZE ? "current_buf_size" : \ + "unknown") + +static int ufstw_read_lu_attr(struct ufstw_lu *tw, u8 idn, u32 *attr_val) +{ + struct ufs_hba *hba = tw->ufsf->hba; + int err = 0, lun; + u32 val; + + lun = (tw->lun == TW_LU_SHARED) ? 0 : tw->lun; + err = ufsf_query_attr_retry(hba, UPIU_QUERY_OPCODE_READ_ATTR, idn, + (u8)lun, &val); + if (err) { + ERR_MSG("read attr [0x%.2X](%s) failed. (%d)", idn, + ATTR_IDN_NAME(idn), err); + goto out; + } + + *attr_val = val; + + INFO_MSG("read attr LUN(%d) [0x%.2X](%s) success (%u)", + lun, idn, ATTR_IDN_NAME(idn), *attr_val); +out: + return err; +} + +static int ufstw_set_lu_flag_dynamic_tw(struct ufstw_lu *tw, u8 idn, bool *flag_res) +{ + struct ufs_hba *hba = tw->ufsf->hba; + int err = 0, lun; + + /* ufstw_lu_get(tw); */ + lun = (tw->lun == TW_LU_SHARED) ? 0 : tw->lun; + err = ufsf_query_flag_retry(hba, UPIU_QUERY_OPCODE_SET_FLAG, idn, + (u8)lun, NULL); + if (err) { + ERR_MSG("set flag [0x%.2X] failed...err %d", idn, err); + /* ufstw_lu_put(tw); */ + return err; + } + + *flag_res = true; + blk_add_trace_msg(tw->ufsf->sdev_ufs_lu[lun]->request_queue, + "%s:%d IDN %s (%d)", __func__, __LINE__, + idn == QUERY_FLAG_IDN_WB_EN ? "TW_EN" : + idn == QUERY_FLAG_IDN_WB_BUFF_FLUSH_EN ? "FLUSH_EN" : + idn == QUERY_FLAG_IDN_WB_BUFF_FLUSH_DURING_HIBERN8 ? + "HIBERN_EN" : "UNKNOWN", idn); + + /*INFO_MSG("tw_flag LUN(%d) [0x%.2X] %u", lun, idn,*flag_res);*/ + + switch(idn) { + case QUERY_FLAG_IDN_WB_EN: + ufsf_para.tw_enable = true; + break; + default: + break; + } + + /* ufstw_lu_put(tw); */ + + return 0; +} + +static int ufstw_clear_lu_flag_dynamic_tw(struct ufstw_lu *tw, u8 idn, bool *flag_res) +{ + struct ufs_hba *hba = tw->ufsf->hba; + int err = 0, lun; + + /* ufstw_lu_get(tw); */ + lun = (tw->lun == TW_LU_SHARED) ? 0 : tw->lun; + err = ufsf_query_flag_retry(hba, UPIU_QUERY_OPCODE_CLEAR_FLAG, idn, + (u8)lun, NULL); + if (err) { + ERR_MSG("clear flag [0x%.2X] failed...err%d", idn, err); + /* ufstw_lu_put(tw); */ + return err; + } + + *flag_res = false; + + blk_add_trace_msg(tw->ufsf->sdev_ufs_lu[lun]->request_queue, + "%s:%d IDN %s (%d)", __func__, __LINE__, + idn == QUERY_FLAG_IDN_WB_EN ? "TW_EN" : + idn == QUERY_FLAG_IDN_WB_BUFF_FLUSH_EN ? "FLUSH_EN" : + idn == QUERY_FLAG_IDN_WB_BUFF_FLUSH_DURING_HIBERN8 ? "HIBERN_EN" : + "UNKNOWN", idn); + INFO_MSG("tw_flag LUN(%d) [0x%.2X] %u", lun, idn, *flag_res); + + switch(idn) { + case QUERY_FLAG_IDN_WB_EN: + ufsf_para.tw_enable = false; + break; + default: + break; + } + + /* ufstw_lu_put(tw); */ + + return 0; +} + +static int ufstw_set_lu_flag(struct ufstw_lu *tw, u8 idn, bool *flag_res) +{ + struct ufs_hba *hba = tw->ufsf->hba; + int err = 0, lun; + + lun = (tw->lun == TW_LU_SHARED) ? 0 : tw->lun; + err = ufsf_query_flag_retry(hba, UPIU_QUERY_OPCODE_SET_FLAG, idn, + (u8)lun, NULL); + if (err) { + ERR_MSG("set flag [0x%.2X](%s) failed. (%d)", idn, + FLAG_IDN_NAME(idn), err); + goto out; + } + + *flag_res = true; + + INFO_MSG("set flag LUN(%d) [0x%.2X](%s) success. (%u)", + lun, idn, FLAG_IDN_NAME(idn), *flag_res); +out: + return err; +} + +static int ufstw_clear_lu_flag(struct ufstw_lu *tw, u8 idn, bool *flag_res) +{ + struct ufs_hba *hba = tw->ufsf->hba; + int err = 0, lun; + + lun = (tw->lun == TW_LU_SHARED) ? 0 : tw->lun; + err = ufsf_query_flag_retry(hba, UPIU_QUERY_OPCODE_CLEAR_FLAG, idn, + (u8)lun, NULL); + if (err) { + ERR_MSG("clear flag [0x%.2X](%s) failed. (%d)", idn, + FLAG_IDN_NAME(idn), err); + goto out; + } + + *flag_res = false; + + INFO_MSG("clear flag LUN(%d) [0x%.2X](%s) success. (%u)", + lun, idn, FLAG_IDN_NAME(idn), *flag_res); +out: + return err; +} + +static int ufstw_read_lu_flag(struct ufstw_lu *tw, u8 idn, bool *flag_res) +{ + struct ufs_hba *hba = tw->ufsf->hba; + int err = 0, lun; + bool val; + + lun = (tw->lun == TW_LU_SHARED) ? 0 : tw->lun; + err = ufsf_query_flag_retry(hba, UPIU_QUERY_OPCODE_READ_FLAG, idn, + (u8)lun, &val); + if (err) { + ERR_MSG("read flag [0x%.2X](%s) failed. (%d)", idn, + FLAG_IDN_NAME(idn), err); + goto out; + } + + *flag_res = val; + + INFO_MSG("read flag LUN(%d) [0x%.2X](%s) success. (%u)", + lun, idn, FLAG_IDN_NAME(idn), *flag_res); +out: + return err; +} + +static inline bool ufstw_is_write_lrbp(struct ufshcd_lrb *lrbp) +{ + if (lrbp->cmd->cmnd[0] == WRITE_10 || lrbp->cmd->cmnd[0] == WRITE_16) + return true; + + return false; +} + +static void ufstw_switch_disable_state(struct ufstw_lu *tw) +{ + int err = 0; + + WARN_MSG("dTurboWriteBUfferLifeTImeEst (0x%.2X)", tw->lifetime_est); + WARN_MSG("tw-mode will change to disable-mode"); + + mutex_lock(&tw->sysfs_lock); + ufstw_set_state(tw->ufsf, TW_FAILED); + mutex_unlock(&tw->sysfs_lock); + + if (tw->tw_enable) { + pm_runtime_get_sync(tw->ufsf->hba->dev); + err = ufstw_clear_lu_flag(tw, QUERY_FLAG_IDN_WB_EN, + &tw->tw_enable); + pm_runtime_put_sync(tw->ufsf->hba->dev); + if (err) + WARN_MSG("tw_enable flag clear failed"); + } +} + +static int ufstw_check_lifetime_not_guarantee(struct ufstw_lu *tw) +{ + bool disable_flag = false; + unsigned int lifetime_guarantee = MASK_UFSTW_LIFETIME_NOT_GUARANTEE_1_0_1; + + if(tw->ufsf->tw_dev_info.tw_ver == UFSTW_VER_1_1_0) + lifetime_guarantee = MASK_UFSTW_LIFETIME_NOT_GUARANTEE_1_1_0; + WARN_MSG("dTurboWriteBUfferLifeTImeEst (0x%.2X),lifetime_guarantee=0x%x", tw->lifetime_est, lifetime_guarantee); + if (tw->lifetime_est & lifetime_guarantee) { + if (tw->lun == TW_LU_SHARED) + WARN_MSG("lun-shared lifetime_est[31] (1)"); + else + WARN_MSG("lun %d lifetime_est[31] (1)", + tw->lun); + + WARN_MSG("Device not guarantee the lifetime of TW Buffer"); +#if defined(CONFIG_UFSTW_IGNORE_GUARANTEE_BIT) + WARN_MSG("but we will ignore them for PoC"); +#else + disable_flag = true; +#endif + } + + if (disable_flag || + (tw->lifetime_est & ~lifetime_guarantee) >= + UFSTW_MAX_LIFETIME_VALUE) { + ufstw_switch_disable_state(tw); + return -ENODEV; + } + + return 0; +} + +static void ufstw_lifetime_work_fn(struct work_struct *work) +{ + struct ufstw_lu *tw; + int ret; + + tw = container_of(work, struct ufstw_lu, tw_lifetime_work); + + if (ufstw_is_not_present(tw->ufsf)) + return; + + pm_runtime_get_sync(tw->ufsf->hba->dev); + ret = ufstw_read_lu_attr(tw, QUERY_ATTR_IDN_WB_BUFF_LIFE_TIME_EST, + &tw->lifetime_est); + pm_runtime_put_sync(tw->ufsf->hba->dev); + if (ret) + return; + + ufstw_check_lifetime_not_guarantee(tw); +} + +void ufstw_prep_fn(struct ufsf_feature *ufsf, struct ufshcd_lrb *lrbp) +{ + struct ufstw_lu *tw; + + if (!lrbp || !ufsf_is_valid_lun(lrbp->lun)) + return; + + if (!ufstw_is_write_lrbp(lrbp)) + return; + + ufsf_para.total_write_secs += blk_rq_sectors(lrbp->cmd->request); + + tw = ufsf->tw_lup[lrbp->lun]; + if (!tw) + return; + + if (!tw->tw_enable) + return; + + spin_lock_bh(&tw->lifetime_lock); + tw->stat_write_sec += blk_rq_sectors(lrbp->cmd->request); + + if (tw->stat_write_sec > UFSTW_LIFETIME_SECT) { + tw->stat_write_sec = 0; + spin_unlock_bh(&tw->lifetime_lock); + schedule_work(&tw->tw_lifetime_work); + return; + } + spin_unlock_bh(&tw->lifetime_lock); + + TMSG(tw->ufsf, lrbp->lun, "%s:%d tw_lifetime_work %u", + __func__, __LINE__, tw->stat_write_sec); +} + +static inline void ufstw_init_lu_jobs(struct ufstw_lu *tw) +{ + INIT_WORK(&tw->tw_lifetime_work, ufstw_lifetime_work_fn); +} + +static inline void ufstw_cancel_lu_jobs(struct ufstw_lu *tw) +{ + int ret; + + ret = cancel_work_sync(&tw->tw_lifetime_work); + INFO_MSG("cancel_work_sync(tw_lifetime_work) ufstw_lu[%d] (%d)", + tw->lun, ret); +} + +static inline int ufstw_version_mismatched(struct ufstw_dev_info *tw_dev_info) +{ + INFO_MSG("Support TW Spec : UFSTW_VER_1_0_1 = %.4X, UFSTW_VER_1_1_0 = %.4X, Device = %.4X", + UFSTW_VER_1_0_1 , UFSTW_VER_1_1_0, tw_dev_info->tw_ver); + + INFO_MSG("TW Driver Version : %.6X%s", UFSTW_DD_VER, + UFSTW_DD_VER_POST); + + if (tw_dev_info->tw_ver != UFSTW_VER_1_0_1 && + tw_dev_info->tw_ver != UFSTW_VER_1_1_0) + return -ENODEV; + + + return 0; +} + +void ufstw_get_dev_info(struct ufsf_feature *ufsf, u8 *desc_buf) +{ + struct ufstw_dev_info *tw_dev_info = &ufsf->tw_dev_info; + u16 wspecversion; + u16 w_manufacturer_id; + if (LI_EN_32(&desc_buf[DEVICE_DESC_PARAM_EXT_UFS_FEATURE_SUP]) & + UFS_FEATURE_SUPPORT_TW_BIT) { + INFO_MSG("bUFSExFeaturesSupport: TW is set"); + } else { + ERR_MSG("bUFSExFeaturesSupport: TW not support"); + ufstw_set_state(ufsf, TW_FAILED); + return; + } + tw_dev_info->tw_buf_no_reduct = + desc_buf[DEVICE_DESC_PARAM_WB_US_RED_EN]; + tw_dev_info->tw_buf_type = desc_buf[DEVICE_DESC_PARAM_WB_TYPE]; + tw_dev_info->tw_shared_buf_alloc_units = + LI_EN_32(&desc_buf[DEVICE_DESC_PARAM_WB_SHARED_ALLOC_UNITS]); + wspecversion = desc_buf[DEVICE_DESC_PARAM_SPEC_VER] << 8 | + desc_buf[DEVICE_DESC_PARAM_SPEC_VER + 1]; + + w_manufacturer_id = desc_buf[DEVICE_DESC_PARAM_MANF_ID] << 8 | + desc_buf[DEVICE_DESC_PARAM_MANF_ID + 1]; + INFO_MSG("dev_desc wspecversion 0x%x\n", wspecversion); + if(wspecversion == 0x310 || wspecversion == 0x220) + tw_dev_info->tw_ver = LI_EN_16(&desc_buf[DEVICE_DESC_PARAM_TW_VER]); + else + tw_dev_info->tw_ver = LI_EN_16(&desc_buf[DEVICE_DESC_PARAM_TW_VER_3_0]); + /*temporary for hynix 2.2 tw function*/ + if (wspecversion == 0x220 && w_manufacturer_id == 0x1AD) + tw_dev_info->tw_ver = UFSTW_VER_1_1_0; + /*temporary for micron 3.1 tw function*/ + if (wspecversion == 0x310 && w_manufacturer_id == 0x12C) + tw_dev_info->tw_ver = UFSTW_VER_1_1_0; + + if (ufstw_version_mismatched(tw_dev_info)) { + ERR_MSG("TW Spec Version mismatch. TW disabled"); + ufstw_set_state(ufsf, TW_FAILED); + return; + } + + INFO_MSG("tw_dev [53] bTurboWriteBufferNoUserSpaceReductionEn (%u)", + tw_dev_info->tw_buf_no_reduct); + INFO_MSG("tw_dev [54] bTurboWriteBufferType (%u)", + tw_dev_info->tw_buf_type); + INFO_MSG("tw_dev [55] dNumSharedTUrboWriteBufferAllocUnits (%u)", + tw_dev_info->tw_shared_buf_alloc_units); + + if (tw_dev_info->tw_buf_type == TW_BUF_TYPE_SHARED && + tw_dev_info->tw_shared_buf_alloc_units == 0) { + ERR_MSG("TW use shared buffer. But alloc unit is (0)"); + ufstw_set_state(ufsf, TW_FAILED); + return; + } +} + +void ufstw_get_geo_info(struct ufsf_feature *ufsf, u8 *geo_buf) +{ + struct ufstw_dev_info *tw_dev_info = &ufsf->tw_dev_info; + + tw_dev_info->tw_number_lu = geo_buf[GEOMETRY_DESC_PARAM_WB_MAX_WB_LUNS]; + if (tw_dev_info->tw_number_lu == 0) { + ERR_MSG("Turbo Write is not supported"); + ufstw_set_state(ufsf, TW_FAILED); + return; + } + + INFO_MSG("tw_geo [4F:52] dTurboWriteBufferMaxNAllocUnits (%u)", + LI_EN_32(&geo_buf[GEOMETRY_DESC_PARAM_WB_MAX_ALLOC_UNITS])); + INFO_MSG("tw_geo [53] bDeviceMaxTurboWriteLUs (%u)", + tw_dev_info->tw_number_lu); + INFO_MSG("tw_geo [54] bTurboWriteBufferCapAdjFac (%u)", + geo_buf[GEOMETRY_DESC_PARAM_WB_BUFF_CAP_ADJ]); + INFO_MSG("tw_geo [55] bSupportedTWBufferUserSpaceReductionTypes (%u)", + geo_buf[GEOMETRY_DESC_PARAM_WB_SUP_RED_TYPE]); + INFO_MSG("tw_geo [56] bSupportedTurboWriteBufferTypes (%u)", + geo_buf[GEOMETRY_DESC_PARAM_WB_SUP_WB_TYPE]); +} + +static void ufstw_alloc_shared_lu(struct ufsf_feature *ufsf) +{ + struct ufstw_lu *tw; + + tw = kzalloc(sizeof(struct ufstw_lu), GFP_KERNEL); + if (!tw) { + ERR_MSG("ufstw_lu[shared] memory alloc failed"); + return; + } + + tw->lun = TW_LU_SHARED; + tw->ufsf = ufsf; + ufsf->tw_lup[0] = tw; + + INFO_MSG("ufstw_lu[shared] is TurboWrite-Enabled"); +} + +static void ufstw_get_lu_info(struct ufsf_feature *ufsf, int lun, u8 *lu_buf) +{ + struct ufsf_lu_desc lu_desc; + struct ufstw_lu *tw; + + lu_desc.tw_lu_buf_size = + LI_EN_32(&lu_buf[UNIT_DESC_PARAM_WB_BUF_ALLOC_UNITS]); + + ufsf->tw_lup[lun] = NULL; + + if (lu_desc.tw_lu_buf_size) { + ufsf->tw_lup[lun] = + kzalloc(sizeof(struct ufstw_lu), GFP_KERNEL); + if (!ufsf->tw_lup[lun]) { + ERR_MSG("ufstw_lu[%d] memory alloc faield", lun); + return; + } + + tw = ufsf->tw_lup[lun]; + tw->ufsf = ufsf; + tw->lun = lun; + INFO_MSG("ufstw_lu[%d] [29:2C] dLUNumTWBufferAllocUnits (%u)", + lun, lu_desc.tw_lu_buf_size); + INFO_MSG("ufstw_lu[%d] is TurboWrite-Enabled.", lun); + } else { + INFO_MSG("ufstw_lu[%d] [29:2C] dLUNumTWBufferAllocUnits (%u)", + lun, lu_desc.tw_lu_buf_size); + INFO_MSG("ufstw_lu[%d] is TurboWrite-disabled", lun); + } +} + +inline void ufstw_alloc_lu(struct ufsf_feature *ufsf, + int lun, u8 *lu_buf) +{ + if (ufsf->tw_dev_info.tw_buf_type == TW_BUF_TYPE_SHARED && + !ufsf->tw_lup[0]) + ufstw_alloc_shared_lu(ufsf); + else if (ufsf->tw_dev_info.tw_buf_type == TW_BUF_TYPE_LU) + ufstw_get_lu_info(ufsf, lun, lu_buf); +} + +static inline void ufstw_print_lu_flag_attr(struct ufstw_lu *tw) +{ + char lun_str[20] = { 0 }; + + if (tw->lun == TW_LU_SHARED) + snprintf(lun_str, 7, "shared"); + else + snprintf(lun_str, 2, "%d", tw->lun); + + INFO_MSG("tw_flag ufstw_lu[%s] IDN (0x%.2X) tw_enable (%d)", + lun_str, QUERY_FLAG_IDN_WB_EN, tw->tw_enable); + INFO_MSG("tw_flag ufstw_lu[%s] IDN (0x%.2X) flush_enable (%d)", + lun_str, QUERY_FLAG_IDN_WB_BUFF_FLUSH_EN, + tw->flush_enable); + INFO_MSG("tw_flag ufstw_lu[%s] IDN (0x%.2X) flush_hibern (%d)", + lun_str, QUERY_FLAG_IDN_WB_BUFF_FLUSH_DURING_HIBERN8, + tw->flush_during_hibern_enter); + + INFO_MSG("tw_attr ufstw_lu[%s] IDN (0x%.2X) flush_status (%u)", + lun_str, QUERY_ATTR_IDN_WB_FLUSH_STATUS, tw->flush_status); + INFO_MSG("tw_attr ufstw_lu[%s] IDN (0x%.2X) buffer_size (%u)", + lun_str, QUERY_ATTR_IDN_AVAIL_WB_BUFF_SIZE, + tw->available_buffer_size); + INFO_MSG("tw_attr ufstw_lu[%s] IDN (0x%.2X) buffer_lifetime (0x%.2X)", + lun_str, QUERY_ATTR_IDN_WB_BUFF_LIFE_TIME_EST, + tw->lifetime_est); +} + +static inline void ufstw_lu_update(struct ufstw_lu *tw) +{ + /* Flag */ + pm_runtime_get_sync(tw->ufsf->hba->dev); + if (ufstw_read_lu_flag(tw, QUERY_FLAG_IDN_WB_EN, &tw->tw_enable)) + goto error_put; + + if (ufstw_read_lu_flag(tw, QUERY_FLAG_IDN_WB_BUFF_FLUSH_EN, + &tw->flush_enable)) + goto error_put; + + if (ufstw_read_lu_flag(tw, QUERY_FLAG_IDN_WB_BUFF_FLUSH_DURING_HIBERN8, + &tw->flush_during_hibern_enter)) + goto error_put; + + /* Attribute */ + if (ufstw_read_lu_attr(tw, QUERY_ATTR_IDN_WB_FLUSH_STATUS, + &tw->flush_status)) + goto error_put; + + if (ufstw_read_lu_attr(tw, QUERY_ATTR_IDN_AVAIL_WB_BUFF_SIZE, + &tw->available_buffer_size)) + goto error_put; + + ufstw_read_lu_attr(tw, QUERY_ATTR_IDN_WB_BUFF_LIFE_TIME_EST, + &tw->lifetime_est); +error_put: + pm_runtime_put_sync(tw->ufsf->hba->dev); +} + +int ufstw_enable_tw_lun(struct ufstw_lu *tw, bool enable) +{ + ssize_t ret = 0; + + if (!tw->dynamic_tw_enable) { + return 0; + } + + /* mutex_lock(&tw->mode_lock); */ + if (enable) { + if (ufstw_set_lu_flag_dynamic_tw(tw, QUERY_FLAG_IDN_WB_EN, + &tw->tw_enable)) { + ret = -EINVAL; + goto failed; + } + } else { + if (ufstw_clear_lu_flag_dynamic_tw(tw, QUERY_FLAG_IDN_WB_EN, + &tw->tw_enable)) { + ret = -EINVAL; + goto failed; + } + } + +failed: + /* mutex_unlock(&tw->mode_lock); */ + + return ret; +} + +void ufstw_enable_tw(struct ufsf_feature *ufsf, bool enable) +{ + int ret; + int lun; + + if (!ufsf) { + ERR_MSG("ERROR: ufsf is NULL!"); + return; + } + + seq_scan_lu(lun) { + if (!ufsf->tw_lup[lun]) + continue; + + ret = ufstw_enable_tw_lun(ufsf->tw_lup[lun], enable); + if (ret) { + ERR_MSG("ERROR: UFSTW LU %d enable failed!", lun); + continue; + } + } +} + + +static int ufstw_lu_init(struct ufsf_feature *ufsf, int lun) +{ + struct ufstw_lu *tw; + int ret = 0; + + if (lun == TW_LU_SHARED) + tw = ufsf->tw_lup[0]; + else + tw = ufsf->tw_lup[lun]; + + tw->ufsf = ufsf; + spin_lock_init(&tw->lifetime_lock); + + ufstw_lu_update(tw); + + ret = ufstw_check_lifetime_not_guarantee(tw); + if (ret) + goto err_out; + + ufstw_print_lu_flag_attr(tw); + + tw->stat_write_sec = 0; + + ufstw_init_lu_jobs(tw); + +#if defined(CONFIG_UFSTW_BOOT_ENABLED) + pm_runtime_get_sync(ufsf->hba->dev); + ufstw_set_lu_flag(tw, QUERY_FLAG_IDN_WB_EN, &tw->tw_enable); + ufstw_set_lu_flag(tw, QUERY_FLAG_IDN_WB_BUFF_FLUSH_DURING_HIBERN8, + &tw->flush_during_hibern_enter); + pm_runtime_put_sync(ufsf->hba->dev); +#endif + ret = ufstw_create_sysfs(ufsf, tw); + if (ret) + ERR_MSG("create sysfs failed"); +err_out: + return ret; +} + +extern int ufsplus_tw_status; +void ufstw_init(struct ufsf_feature *ufsf) +{ + int lun, ret = 0; + unsigned int tw_enabled_lun = 0; + + INFO_MSG("init start.. tw_state (%d)", ufstw_get_state(ufsf)); + + if (ufsf->tw_dev_info.tw_buf_type == TW_BUF_TYPE_SHARED) { + if (!ufsf->tw_lup[0]) { + ERR_MSG("tw_lup memory allocation failed"); + goto out; + } + BUG_ON(ufsf->tw_lup[0]->lun != TW_LU_SHARED); + + ret = ufstw_lu_init(ufsf, TW_LU_SHARED); + if (ret) + goto out_free_mem; + ufsf->tw_lup[0]->dynamic_tw_enable = true; + INFO_MSG("ufstw_lu[shared] working"); + tw_enabled_lun++; + } else { + seq_scan_lu(lun) { + if (!ufsf->tw_lup[lun]) + continue; + + ret = ufstw_lu_init(ufsf, lun); + if (ret) + goto out_free_mem; + ufsf->tw_lup[lun]->dynamic_tw_enable = true; + INFO_MSG("ufstw_lu[%d] working", lun); + tw_enabled_lun++; + } + if (tw_enabled_lun > ufsf->tw_dev_info.tw_number_lu) { + ERR_MSG("lu count mismatched"); + goto out_free_mem; + } + } + + if (tw_enabled_lun) { + ufsplus_tw_status = 1; + } + + if (tw_enabled_lun == 0) { + ERR_MSG("tw_enabled_lun count zero"); + goto out_free_mem; + } + + ufstw_set_state(ufsf, TW_PRESENT); + create_wbfn_enable(); + create_wbfn_dynamic_tw_enable(); + return; +out_free_mem: + seq_scan_lu(lun) { + kfree(ufsf->tw_lup[lun]); + ufsf->tw_lup[lun] = NULL; + } +out: + ERR_MSG("Turbo write intialization failed"); + + ufstw_set_state(ufsf, TW_FAILED); +} + +static inline void ufstw_remove_sysfs(struct ufstw_lu *tw) +{ + int ret; + + ret = kobject_uevent(&tw->kobj, KOBJ_REMOVE); + INFO_MSG("kobject removed (%d)", ret); + kobject_del(&tw->kobj); +} + +void ufstw_remove(struct ufsf_feature *ufsf) +{ + struct ufstw_lu *tw; + int lun; + + dump_stack(); + INFO_MSG("start release"); + + ufstw_set_state(ufsf, TW_FAILED); + + if (ufsf->tw_dev_info.tw_buf_type == TW_BUF_TYPE_SHARED) { + tw = ufsf->tw_lup[0]; + INFO_MSG("ufstw_lu[shared] %p", tw); + ufsf->tw_lup[0] = NULL; + ufstw_cancel_lu_jobs(tw); + ufstw_remove_sysfs(tw); + kfree(tw); + } else { + remove_wbfn_enable(); + remove_wbfn_dynamic_tw_enable(); + seq_scan_lu(lun) { + tw = ufsf->tw_lup[lun]; + INFO_MSG("ufstw_lu[%d] %p", lun, tw); + + if (!tw) + continue; + ufsf->tw_lup[lun] = NULL; + ufstw_cancel_lu_jobs(tw); + ufstw_remove_sysfs(tw); + kfree(tw); + } + } + + INFO_MSG("end release"); +} + +static void ufstw_reset_query_handling(struct ufstw_lu *tw) +{ + int ret; + + if (tw->tw_enable) { + ret = ufstw_set_lu_flag(tw, QUERY_FLAG_IDN_WB_EN, + &tw->tw_enable); + if (ret) + tw->tw_enable = false; + } + + if (tw->flush_enable) { + ret = ufstw_set_lu_flag(tw, QUERY_FLAG_IDN_WB_BUFF_FLUSH_EN, + &tw->flush_enable); + if (ret) + tw->flush_enable = false; + } + + if (tw->flush_during_hibern_enter) { + ret = ufstw_set_lu_flag(tw, + QUERY_FLAG_IDN_WB_BUFF_FLUSH_DURING_HIBERN8, + &tw->flush_during_hibern_enter); + if (ret) + tw->flush_during_hibern_enter = false; + } +} + +void ufstw_reset_host(struct ufsf_feature *ufsf) +{ + struct ufstw_lu *tw; + int lun; + + if (ufstw_is_not_present(ufsf)) + return; + + ufstw_set_state(ufsf, TW_RESET); + if (ufsf->tw_dev_info.tw_buf_type == TW_BUF_TYPE_SHARED) { + tw = ufsf->tw_lup[0]; + + INFO_MSG("ufstw_lu[shared] cancel jobs"); + ufstw_cancel_lu_jobs(tw); + } else { + seq_scan_lu(lun) { + tw = ufsf->tw_lup[lun]; + if (!tw) + continue; + + INFO_MSG("ufstw_lu[%d] cancel jobs", lun); + ufstw_cancel_lu_jobs(tw); + } + } +} + +void ufstw_reset(struct ufsf_feature *ufsf, bool resume) +{ + struct ufstw_lu *tw; + int lun; + + INFO_MSG("ufstw reset start. reason: %s", + resume ? "resume" : "reset"); + if (ufstw_get_state(ufsf) != TW_RESET) { + ERR_MSG("tw_state error (%d)", ufstw_get_state(ufsf)); + return; + } + + if (ufsf->tw_dev_info.tw_buf_type == TW_BUF_TYPE_SHARED) { + tw = ufsf->tw_lup[0]; + + INFO_MSG("ufstw_lu[shared] reset"); + ufstw_reset_query_handling(tw); + } else { + seq_scan_lu(lun) { + tw = ufsf->tw_lup[lun]; + if (!tw) + continue; + + INFO_MSG("ufstw_lu[%d] reset", lun); + ufstw_reset_query_handling(tw); + } + } + + ufstw_set_state(ufsf, TW_PRESENT); + INFO_MSG("ufstw reset finish"); +} + +#define ufstw_sysfs_attr_show_func(_query, _name, _IDN, hex) \ +static ssize_t ufstw_sysfs_show_##_name(struct ufstw_lu *tw, char *buf) \ +{ \ + int ret; \ + \ + pm_runtime_get_sync(tw->ufsf->hba->dev); \ + if (ufstw_is_not_present(tw->ufsf)) { \ + pm_runtime_put_sync(tw->ufsf->hba->dev); \ + return -ENODEV; \ + } \ + \ + ret = ufstw_read_lu_##_query(tw, _IDN, &tw->_name); \ + pm_runtime_put_sync(tw->ufsf->hba->dev); \ + if (ret) \ + return -ENODEV; \ + \ + INFO_MSG("read "#_query" "#_name" %u (0x%X)", \ + tw->_name, tw->_name); \ + if (hex) \ + return snprintf(buf, PAGE_SIZE, "0x%.2X\n", tw->_name); \ + return snprintf(buf, PAGE_SIZE, "%u\n", tw->_name); \ +} + +#define ufstw_sysfs_attr_store_func(_name, _IDN) \ +static ssize_t ufstw_sysfs_store_##_name(struct ufstw_lu *tw, \ + const char *buf, \ + size_t count) \ +{ \ + unsigned long val; \ + ssize_t ret = count; \ + \ + if (kstrtoul(buf, 0, &val)) \ + return -EINVAL; \ + \ + if (!(val == 0 || val == 1)) \ + return -EINVAL; \ + \ + INFO_MSG("val %lu", val); \ + pm_runtime_get_sync(tw->ufsf->hba->dev); \ + if (ufstw_is_not_present(tw->ufsf)) { \ + pm_runtime_put_sync(tw->ufsf->hba->dev); \ + return -ENODEV; \ + } \ + \ + if (val) { \ + if (ufstw_set_lu_flag(tw, _IDN, &tw->_name)) \ + ret = -ENODEV; \ + } else { \ + if (ufstw_clear_lu_flag(tw, _IDN, &tw->_name)) \ + ret = -ENODEV; \ + } \ + pm_runtime_put_sync(tw->ufsf->hba->dev); \ + \ + INFO_MSG(#_name " query success"); \ + return ret; \ +} + +ufstw_sysfs_attr_show_func(flag, tw_enable, QUERY_FLAG_IDN_WB_EN, 0); +ufstw_sysfs_attr_store_func(tw_enable, QUERY_FLAG_IDN_WB_EN); +ufstw_sysfs_attr_show_func(flag, flush_enable, + QUERY_FLAG_IDN_WB_BUFF_FLUSH_EN, 0); +ufstw_sysfs_attr_store_func(flush_enable, QUERY_FLAG_IDN_WB_BUFF_FLUSH_EN); +ufstw_sysfs_attr_show_func(flag, flush_during_hibern_enter, + QUERY_FLAG_IDN_WB_BUFF_FLUSH_DURING_HIBERN8, 0); +ufstw_sysfs_attr_store_func(flush_during_hibern_enter, + QUERY_FLAG_IDN_WB_BUFF_FLUSH_DURING_HIBERN8); + +ufstw_sysfs_attr_show_func(attr, flush_status, + QUERY_ATTR_IDN_WB_FLUSH_STATUS, 0); +ufstw_sysfs_attr_show_func(attr, available_buffer_size, + QUERY_ATTR_IDN_AVAIL_WB_BUFF_SIZE, 0); +ufstw_sysfs_attr_show_func(attr, lifetime_est, + QUERY_ATTR_IDN_WB_BUFF_LIFE_TIME_EST, 1); +ufstw_sysfs_attr_show_func(attr, curr_buffer_size, + QUERY_ATTR_IDN_CURR_WB_BUFF_SIZE, 0); + +#define ufstw_sysfs_attr_ro(_name) __ATTR(_name, 0444, \ + ufstw_sysfs_show_##_name, NULL) +#define ufstw_sysfs_attr_rw(_name) __ATTR(_name, 0644, \ + ufstw_sysfs_show_##_name, \ + ufstw_sysfs_store_##_name) + +static struct ufstw_sysfs_entry ufstw_sysfs_entries[] = { + /* Flag */ + ufstw_sysfs_attr_rw(tw_enable), + ufstw_sysfs_attr_rw(flush_enable), + ufstw_sysfs_attr_rw(flush_during_hibern_enter), + /* Attribute */ + ufstw_sysfs_attr_ro(flush_status), + ufstw_sysfs_attr_ro(available_buffer_size), + ufstw_sysfs_attr_ro(lifetime_est), + ufstw_sysfs_attr_ro(curr_buffer_size), + __ATTR_NULL +}; + +static ssize_t ufstw_attr_show(struct kobject *kobj, struct attribute *attr, + char *page) +{ + struct ufstw_sysfs_entry *entry; + struct ufstw_lu *tw; + ssize_t error; + + entry = container_of(attr, struct ufstw_sysfs_entry, attr); + tw = container_of(kobj, struct ufstw_lu, kobj); + if (!entry->show) + return -EIO; + + mutex_lock(&tw->sysfs_lock); + error = entry->show(tw, page); + mutex_unlock(&tw->sysfs_lock); + return error; +} + +static ssize_t ufstw_attr_store(struct kobject *kobj, struct attribute *attr, + const char *page, size_t length) +{ + struct ufstw_sysfs_entry *entry; + struct ufstw_lu *tw; + ssize_t error; + + entry = container_of(attr, struct ufstw_sysfs_entry, attr); + tw = container_of(kobj, struct ufstw_lu, kobj); + + if (!entry->store) + return -EIO; + + mutex_lock(&tw->sysfs_lock); + error = entry->store(tw, page, length); + mutex_unlock(&tw->sysfs_lock); + return error; +} + +static const struct sysfs_ops ufstw_sysfs_ops = { + .show = ufstw_attr_show, + .store = ufstw_attr_store, +}; + +static struct kobj_type ufstw_ktype = { + .sysfs_ops = &ufstw_sysfs_ops, + .release = NULL, +}; + +static int ufstw_create_sysfs(struct ufsf_feature *ufsf, struct ufstw_lu *tw) +{ + struct device *dev = ufsf->hba->dev; + struct ufstw_sysfs_entry *entry; + int err; + char lun_str[20] = { 0 }; + + tw->sysfs_entries = ufstw_sysfs_entries; + + kobject_init(&tw->kobj, &ufstw_ktype); + mutex_init(&tw->sysfs_lock); + + if (tw->lun == TW_LU_SHARED) { + snprintf(lun_str, 6, "ufstw"); + INFO_MSG("ufstw creates sysfs ufstw-shared"); + } else { + snprintf(lun_str, 10, "ufstw_lu%d", tw->lun); + INFO_MSG("ufstw creates sysfs ufstw_lu%d", tw->lun); + } + + err = kobject_add(&tw->kobj, kobject_get(&dev->kobj), lun_str); + if (!err) { + for (entry = tw->sysfs_entries; entry->attr.name != NULL; + entry++) { + if (tw->lun == TW_LU_SHARED) + INFO_MSG("ufstw-shared sysfs attr creates: %s", + entry->attr.name); + else + INFO_MSG("ufstw_lu(%d) sysfs attr creates: %s", + tw->lun, entry->attr.name); + + err = sysfs_create_file(&tw->kobj, &entry->attr); + if (err) { + ERR_MSG("create entry(%s) failed", + entry->attr.name); + goto kobj_del; + } + } + kobject_uevent(&tw->kobj, KOBJ_ADD); + } else { + ERR_MSG("kobject_add failed"); + } + + return err; +kobj_del: + err = kobject_uevent(&tw->kobj, KOBJ_REMOVE); + INFO_MSG("kobject removed (%d)", err); + kobject_del(&tw->kobj); + return -EINVAL; +} + +static inline void wbfn_enable_ctrl(struct ufstw_lu *tw, long val) +{ + switch (val) { + case 0: + ufstw_clear_lu_flag(tw, QUERY_FLAG_IDN_WB_EN, + &tw->tw_enable); + break; + case 1: + ufstw_set_lu_flag(tw, QUERY_FLAG_IDN_WB_EN, + &tw->tw_enable); + break; + default: + break; + } + return; +} + +static ssize_t wbfn_enable_write(struct file *filp, const char *ubuf, + size_t cnt, loff_t *data) +{ + char buf[64] = {0}; + long val = 64; + int lun; + + if (!ufsf_para.ufsf) + return -EFAULT; + if (cnt >= sizeof(buf)) + return -EINVAL; + if (copy_from_user(&buf, ubuf, cnt)) + return -EFAULT; + + if (buf[0] == '0') + val = 0; + else if (buf[0] == '1') + val = 1; + else + val = 64; + + seq_scan_lu(lun) { + if (ufsf_para.ufsf->tw_lup[lun]) + wbfn_enable_ctrl(ufsf_para.ufsf->tw_lup[lun], val); + } + + return cnt; +} + +static const struct file_operations wbfn_enable_fops = { + .write = wbfn_enable_write, +}; + +static int create_wbfn_enable(void) +{ + struct proc_dir_entry *d_entry; + + if (!ufsf_para.ctrl_dir) + return -EFAULT; + + d_entry = proc_create("wbfn_enable", S_IWUGO, ufsf_para.ctrl_dir, + &wbfn_enable_fops); + if(!d_entry) + return -ENOMEM; + + return 0; +} + +static void remove_wbfn_enable(void) +{ + if (ufsf_para.ctrl_dir) + remove_proc_entry("wbfn_enable", ufsf_para.ctrl_dir); + + return; +} + +/* For the RUS gate of dynamic tw */ +static inline void wbfn_dynamic_tw_enable_ctrl(struct ufstw_lu *tw, long val) +{ + int ret = 0; + + if (atomic_read(&tw->ufsf->tw_state) == TW_PRESENT) { + INFO_MSG("val: %lu\n", val); + switch (val) { + case 0: + tw->dynamic_tw_enable = false; + /* mutex_lock(&tw->mode_lock); */ + ret = ufstw_set_lu_flag(tw, QUERY_FLAG_IDN_WB_EN, &tw->tw_enable); + if(ret == 0) { + INFO_MSG("ufstw_set_lu_flag success"); + } + /* utex_unlock(&tw->mode_lock); */ + break; + case 1: + tw->dynamic_tw_enable = true; + break; + default: + break; + } + } else { + INFO_MSG("tw_state != TW_PRESENT (%d)\n", atomic_read(&tw->ufsf->tw_state)); + } + + return; +} + +static ssize_t wbfn_dynamic_tw_enable_write(struct file *filp, const char *ubuf, + size_t cnt, loff_t *data) +{ + char buf[64] = {0}; + long val = 64; + int lun; + + if (!ufsf_para.ufsf) + return -EFAULT; + if (cnt >= sizeof(buf)) + return -EINVAL; + if (copy_from_user(&buf, ubuf, cnt)) + return -EFAULT; + + if (buf[0] == '0') + val = 0; + else if (buf[0] == '1') + val = 1; + else + val = 64; + + seq_scan_lu(lun) { + if (ufsf_para.ufsf->tw_lup[lun]) + wbfn_dynamic_tw_enable_ctrl(ufsf_para.ufsf->tw_lup[lun], val); + } + + return cnt; +} + +static const struct file_operations wbfn_dynamic_tw_enable_fops = { + .write = wbfn_dynamic_tw_enable_write, +}; + +static int create_wbfn_dynamic_tw_enable(void) +{ + struct proc_dir_entry *d_entry; + + if (!ufsf_para.ctrl_dir) + return -EFAULT; + + d_entry = proc_create("wbfn_dynamic_tw_enable", S_IWUGO, ufsf_para.ctrl_dir, + &wbfn_dynamic_tw_enable_fops); + if(!d_entry) + return -ENOMEM; + + return 0; +} + +static void remove_wbfn_dynamic_tw_enable(void) +{ + if (ufsf_para.ctrl_dir) + remove_proc_entry("wbfn_dynamic_tw_enable", ufsf_para.ctrl_dir); + + return; +} diff --git a/drivers/scsi/ufs/ufstw.h b/drivers/scsi/ufs/ufstw.h new file mode 100644 index 000000000000..0912b5d2bade --- /dev/null +++ b/drivers/scsi/ufs/ufstw.h @@ -0,0 +1,134 @@ +/* + * Universal Flash Storage tw Write + * + * Copyright (C) 2017-2018 Samsung Electronics Co., Ltd. + * Copyright (C) 2020 Oplus. All rights reserved. + * + * Authors: + * Yongmyung Lee + * Jinyoung Choi + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * See the COPYING file in the top-level directory or visit + * + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * This program is provided "AS IS" and "WITH ALL FAULTS" and + * without warranty of any kind. You are solely responsible for + * determining the appropriateness of using and distributing + * the program and assume all risks associated with your exercise + * of rights with respect to the program, including but not limited + * to infringement of third party rights, the risks and costs of + * program errors, damage to or loss of data, programs or equipment, + * and unavailability or interruption of operations. Under no + * circumstances will the contributor of this Program be liable for + * any damages of any kind arising from your use or distribution of + * this program. + * + * The Linux Foundation chooses to take subject only to the GPLv2 + * license terms, and distributes only under these terms. + */ + +#ifndef _UFSTW_H_ +#define _UFSTW_H_ + +#include +#include +#include +#include +#include + +#include "../../../block/blk.h" + +#define UFSTW_VER_1_0_1 0x0101 +#define UFSTW_VER_1_1_0 0x0110 + +#define UFSTW_DD_VER 0x010300 +#define UFSTW_DD_VER_POST "_RC03" + +#define UFSTW_LIFETIME_SECT 2097152 /* 1GB */ +#define UFSTW_MAX_LIFETIME_VALUE 0x0B +#define MASK_UFSTW_LIFETIME_NOT_GUARANTEE_1_0_1 0x80000000 +#define MASK_UFSTW_LIFETIME_NOT_GUARANTEE_1_1_0 0x80 +#define UFS_FEATURE_SUPPORT_TW_BIT 0x100 + +#define TW_LU_SHARED -1 + +enum UFSTW_STATE { + TW_NEED_INIT = 0, + TW_PRESENT = 1, + TW_RESET = -3, + TW_FAILED = -4 +}; + +enum { + TW_BUF_TYPE_LU = 0, + TW_BUF_TYPE_SHARED, +}; + +struct ufstw_dev_info { + /* from Device Descriptor */ + u16 tw_ver; + u32 tw_shared_buf_alloc_units; + u8 tw_buf_no_reduct; + u8 tw_buf_type; + + /* from Geometry Descriptor */ + u8 tw_number_lu; +}; + +struct ufstw_lu { + struct ufsf_feature *ufsf; + + int lun; + + bool tw_enable; + bool flush_enable; + bool flush_during_hibern_enter; + + unsigned int flush_status; + unsigned int available_buffer_size; + unsigned int curr_buffer_size; + + unsigned int lifetime_est; + spinlock_t lifetime_lock; + u32 stat_write_sec; + struct work_struct tw_lifetime_work; + + /* for sysfs */ + struct kobject kobj; + struct mutex sysfs_lock; + struct ufstw_sysfs_entry *sysfs_entries; + + /*for dynamic tw*/ + bool dynamic_tw_enable; +}; + +struct ufstw_sysfs_entry { + struct attribute attr; + ssize_t (*show)(struct ufstw_lu *tw, char *buf); + ssize_t (*store)(struct ufstw_lu *tw, const char *buf, size_t count); +}; + +struct ufshcd_lrb; + +int ufstw_get_state(struct ufsf_feature *ufsf); +void ufstw_set_state(struct ufsf_feature *ufsf, int state); +void ufstw_get_dev_info(struct ufsf_feature *ufsf, u8 *desc_buf); +void ufstw_get_geo_info(struct ufsf_feature *ufsf, u8 *geo_buf); +void ufstw_alloc_lu(struct ufsf_feature *ufsf, int lun, u8 *lu_buf); + +void ufstw_prep_fn(struct ufsf_feature *ufsf, struct ufshcd_lrb *lrbp); +void ufstw_init(struct ufsf_feature *ufsf); +void ufstw_remove(struct ufsf_feature *ufsf); +void ufstw_reset_host(struct ufsf_feature *ufsf); +void ufstw_reset(struct ufsf_feature *ufsf, bool resume); +void ufstw_enable_tw(struct ufsf_feature *ufsf, bool enable); +#endif /* _UFSTW_H_ */ diff --git a/drivers/sensors/Kconfig b/drivers/sensors/Kconfig index 9a3e410cb237..4e9ddd4d8d9e 100644 --- a/drivers/sensors/Kconfig +++ b/drivers/sensors/Kconfig @@ -5,3 +5,8 @@ config SENSORS_SSC Add support for sensors SSC driver. This driver is used for exercising sensors use case, time syncing with ADSP clock. + +config SENSORS_SIMULATED_HALL + bool "Enable SIMULATED_HALL Driver" + help + Add support for SIMULATED HALL SENSOR. \ No newline at end of file diff --git a/drivers/sensors/Makefile b/drivers/sensors/Makefile index 7b1b327f25c2..25ea46c17ce3 100644 --- a/drivers/sensors/Makefile +++ b/drivers/sensors/Makefile @@ -1,2 +1,3 @@ # SPDX-License-Identifier: GPL-2.0-only obj-$(CONFIG_SENSORS_SSC) += sensors_ssc.o +obj-$(CONFIG_SENSORS_SIMULATED_HALL) += sensors_simulated_hall.o \ No newline at end of file diff --git a/drivers/sensors/sensors_simulated_hall.c b/drivers/sensors/sensors_simulated_hall.c new file mode 100644 index 000000000000..9f75147d2ff0 --- /dev/null +++ b/drivers/sensors/sensors_simulated_hall.c @@ -0,0 +1,308 @@ +/* + * + * Copyright (c) 2014-2015, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sensors_simulated_hall.h" + +#define HALL_DEV_NAME "oplus,simulated_hall" +#define MHALL_DEBUG +#define MHALL_TAG "[MHALL]" +#if defined(MHALL_DEBUG) +#define MHALL_ERR(fmt, args...) printk(KERN_ERR MHALL_TAG"%s %d : "fmt, __FUNCTION__, __LINE__, ##args) +#define MHALL_LOG(fmt, args...) printk(KERN_INFO MHALL_TAG"%s(%d):" fmt, __FUNCTION__, __LINE__, ##args) +#else +#define MHALL_CHG_REAR_ERR(fmt, args...) +#define MHALL_CHG_REAR_LOG(fmt, args...) +#endif + +struct blocking_notifier_head hall_notifier = BLOCKING_NOTIFIER_INIT(hall_notifier); + +static void hall_optional_handle(struct hall_simulated_data *hall_data, hall_status status) +{ + static struct hall_simulated_data *last_hall = NULL; + bool need_report = false; + if (!hall_data) { + return; + } + if (last_hall != NULL && last_hall != hall_data) { + MHALL_ERR("%d--anather hall near now ,return , status = %d" ,hall_data->id, TYPE_HALL_NEAR == status ? 1 : 0); + return; + } else if (last_hall == NULL && status == TYPE_HALL_NEAR) { + last_hall = hall_data; + need_report = true; + } else if (last_hall != NULL && status == TYPE_HALL_FAR && last_hall == hall_data) { + last_hall = NULL; + need_report = true; + } + if (need_report) { + if (TYPE_HANDLE_NOTIFY_WIRELESS == hall_data->handle_option) { + blocking_notifier_call_chain(&hall_notifier, TYPE_HALL_NEAR == status ? 1 : 0, NULL); + MHALL_ERR("%d--TYPE_HANDLE_NOTIFY_WIRELESS , %d" ,hall_data->id, TYPE_HALL_NEAR == status ? 1 : 0); + + } else if (TYPE_HANDLE_REPORT_KEYS == hall_data->handle_option) { + input_report_switch(hall_data->hall_input_dev, SW_PEN_INSERTED, TYPE_HALL_NEAR == status ? 1 : 0); + input_sync(hall_data->hall_input_dev); + MHALL_ERR("%d--TYPE_HANDLE_REPORT_KEYS , %d" ,hall_data->id, TYPE_HALL_NEAR == status ? 1 : 0); + + } else { + MHALL_ERR("handle_option=0 noritify charge and android"); + // blocking_notifier_call_chain(&hall_notifier, TYPE_HALL_NEAR == status ? 1 : 0, NULL); + input_report_switch(hall_data->hall_input_dev, SW_PEN_INSERTED, TYPE_HALL_NEAR == status ? 1 : 0); + input_sync(hall_data->hall_input_dev); + MHALL_ERR("%d--double report, %d" ,hall_data->id, TYPE_HALL_NEAR == status ? 1 : 0); + } + } + + return; +} + +static irqreturn_t hall_interrupt_handler_func(int irq, void *dev) +{ + int val = 0; + struct hall_simulated_data *hall_data = dev; + + mutex_lock(&hall_data->report_mutex); + + val = gpio_get_value(hall_data->irq_gpio); + if (hall_data->active_low) { + if ((TYPE_HALL_NEAR == hall_data->hall_status) && val) { + hall_data->hall_status = TYPE_HALL_FAR; + hall_optional_handle(hall_data, TYPE_HALL_FAR); + } else if ((TYPE_HALL_FAR == hall_data->hall_status) && !val) { + hall_data->hall_status = TYPE_HALL_NEAR; + hall_optional_handle(hall_data, TYPE_HALL_NEAR); + } else { + hall_data->hall_status = (0 == val ? TYPE_HALL_NEAR : TYPE_HALL_FAR); + MHALL_ERR("[logic wrong]%s hall_status:%d, gpio_val:%d.",hall_data->DEV_NAME, hall_data->hall_status, val); + if (hall_data->hall_status == TYPE_HALL_NEAR) { + hall_optional_handle(hall_data, hall_data->hall_status); + } + } + } else { + MHALL_ERR("[%s]not support non active low handle yet.", hall_data->DEV_NAME); + } + + mutex_unlock(&hall_data->report_mutex); + + return IRQ_HANDLED; +} + +static int hall_int_gpio_init(struct device *dev, struct hall_simulated_data *hall_data) +{ + char pinctrl_status[64] = {0}; + + hall_data->hall_pinctrl = devm_pinctrl_get(dev); + if (hall_data->hall_pinctrl == NULL) { + MHALL_ERR("get pinctrl fail\n"); + return -EINVAL; + } + + sprintf(pinctrl_status , "wireless_chg_hall%d_active" , hall_data->id); + MHALL_ERR("pinctrl_status:%s\n" , pinctrl_status); + + hall_data->hall_int_active = + pinctrl_lookup_state(hall_data->hall_pinctrl, pinctrl_status); + if (hall_data->hall_int_active == NULL) { + MHALL_ERR("get hall_int_active fail\n"); + return -EINVAL; + } + MHALL_ERR("get %s success!\n" , pinctrl_status); + sprintf(pinctrl_status , "wireless_chg_hall%d_sleep" , hall_data->id); + MHALL_ERR("pinctrl_status:%s\n" , pinctrl_status); + hall_data->hall_int_sleep = + pinctrl_lookup_state(hall_data->hall_pinctrl, pinctrl_status); + if (hall_data->hall_int_sleep == NULL) { + MHALL_ERR("get hall_int_sleep fail\n"); + return -EINVAL; + } + MHALL_ERR("get %s success!\n" , pinctrl_status); + + if (hall_data->irq_gpio > 0) { + gpio_direction_input(hall_data->irq_gpio); + } + + MHALL_ERR("pinctrl_select_state wireless_chg_hall1_active !\n"); + pinctrl_select_state(hall_data->hall_pinctrl, hall_data->hall_int_active); + + return 0; +} + +static int hall_parse_dt(struct device *dev, struct hall_simulated_data *hall_data) +{ + int rc = 0; + struct device_node *np = dev->of_node; + + hall_data->irq_gpio = of_get_named_gpio_flags(np, "irq-gpio", 0, &(hall_data->irq_flags)); + + hall_data->active_low = of_property_read_bool(np, "irq_active_low"); + rc = of_property_read_u32(np, "optional-handle-type", &hall_data->handle_option); + if (rc) { + MHALL_ERR("handle option not specified.\n"); + return rc; + } + + rc = of_property_read_u32(np, "hall-id", &hall_data->id); + if (rc) { + MHALL_ERR("handle id not specified.\n"); + return rc; + } + sprintf(hall_data->DEV_NAME , "%s_%d" , HALL_DEV_NAME , hall_data->id); + rc = hall_int_gpio_init(dev, hall_data); + if (rc) { + MHALL_ERR("gpio init fail.\n"); + return rc; + } + hall_data->irq_number = gpio_to_irq(hall_data->irq_gpio); + MHALL_LOG("gpio %d hall_irq %d, flags = %d\n",hall_data->irq_gpio , hall_data->irq_number, hall_data->irq_flags); + return 0; +} + +static struct platform_driver simulated_hall_driver; +static int hall_simulated_driver_probe(struct platform_device *dev) +{ + int err = 0; + struct hall_simulated_data *hall_data = NULL; + + MHALL_LOG("simulated_hall_driver probe\n"); + hall_data = devm_kzalloc(&dev->dev, sizeof(*hall_data), GFP_KERNEL); + if (hall_data == NULL) { + MHALL_ERR("failed to allocate memory %d\n", err); + err = -ENOMEM; + goto return_err; + } + dev_set_drvdata(&dev->dev, hall_data); + + if (dev->dev.of_node) { + err = hall_parse_dt(&dev->dev, hall_data); + if (err) { + dev_err(&dev->dev, "Failed to parse device tree\n"); + goto free_hall_data; + } + } else if (dev->dev.platform_data != NULL) { + memcpy(hall_data, dev->dev.platform_data, sizeof(*hall_data)); + } else { + MHALL_ERR("No valid platform data, probe failed.\n"); + err = -ENODEV; + goto free_hall_data; + } + + /*** creat mhall input_dev ***/ + hall_data->hall_input_dev = input_allocate_device(); + if (NULL == hall_data->hall_input_dev) { + err = -ENOMEM; + MHALL_ERR(" failed to allocate input device for hall\n"); + goto free_hall_data; + } + hall_data->hall_input_dev->name = hall_data->DEV_NAME; + __set_bit(EV_SW, hall_data->hall_input_dev->evbit); + input_set_capability(hall_data->hall_input_dev, EV_SW, SW_PEN_INSERTED); + err = input_register_device(hall_data->hall_input_dev); + if(err){ + MHALL_ERR("failed to register mhall input device\n"); + err = -ENODEV; + goto free_input_device; + } + + hall_data->hall_status = TYPE_HALL_FAR; + mutex_init(&hall_data->report_mutex); + + /*** register irq handler ***/ + err = request_threaded_irq(hall_data->irq_number, NULL, hall_interrupt_handler_func, hall_data->irq_flags, hall_data->DEV_NAME, hall_data); + if (err < 0) { + MHALL_ERR("request irq handler failed.\n"); + err = -ENODEV; + goto exit; + } + enable_irq_wake(hall_data->irq_number); + + MHALL_LOG("simulated mhall probe ok\n"); + hall_interrupt_handler_func(hall_data->irq_number , hall_data); + MHALL_LOG("simulated mhall_%d update first status ok\n" , hall_data->id); + return 0; +exit: +free_input_device: + input_free_device(hall_data->hall_input_dev); +free_hall_data: + kfree(hall_data); +return_err: + return err; +} + +static int hall_simulated_driver_remove(struct platform_device *dev) +{ + struct hall_simulated_data *hall_data = dev_get_drvdata(&dev->dev); + + input_unregister_device(hall_data->hall_input_dev); + kfree(hall_data); + + return 0; +} + +static struct platform_device_id hall_simulated_id[] = { + {HALL_DEV_NAME, 0 }, + { }, +}; + +static struct of_device_id hall_sensor_match_table[] = { + {.compatible = HALL_DEV_NAME, }, + { }, +}; + +static struct platform_driver simulated_hall_driver = { + .driver = { + .name = HALL_DEV_NAME, + .owner = THIS_MODULE, + .of_match_table = hall_sensor_match_table, + }, + .probe = hall_simulated_driver_probe, + .remove = hall_simulated_driver_remove, + .id_table = hall_simulated_id, +}; + +static int __init simulated_hall_init(void) +{ + MHALL_LOG("simulated hall sensor start init.\n"); + platform_driver_register(&simulated_hall_driver); + return 0; +} + +static void __exit simulated_hall_exit(void) +{ + platform_driver_unregister(&simulated_hall_driver); +} + +//module_init(simulated_hall_init); +late_initcall(simulated_hall_init); +module_exit(simulated_hall_exit); +MODULE_DESCRIPTION("Simulated Hall sensor driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/sensors/sensors_simulated_hall.h b/drivers/sensors/sensors_simulated_hall.h new file mode 100644 index 000000000000..fd241dcfc960 --- /dev/null +++ b/drivers/sensors/sensors_simulated_hall.h @@ -0,0 +1,36 @@ +#ifndef __HALL_SIMULATED_H__ +#define __HALL_SIMULATED_H__ + +struct hall_simulated_data { + int id; /* show the current id */ + char DEV_NAME[64]; + + int irq_gpio; /* device use gpio number */ + int irq_number; /* device request irq number */ + uint32_t irq_flags; /* device irq flags */ + int active_low; /* gpio active high or low for valid value */ + + int hall_status; /* device status of latest */ + int handle_option; /* different option set about hall status*/ + + struct mutex report_mutex; + struct input_dev *hall_input_dev; + struct pinctrl *hall_pinctrl; + struct pinctrl_state *hall_int_active; + struct pinctrl_state *hall_int_sleep; +}; + +typedef enum { + TYPE_HALL_UNDEFINED, + TYPE_HALL_NEAR = 1, /*means in near status*/ + TYPE_HALL_FAR, /*means in far status*/ +} hall_status; + +typedef enum { + TYPE_HANDLE_UNDEFINED, + TYPE_HANDLE_NOTIFY_WIRELESS = 1, /*means notify wireless charge*/ + TYPE_HANDLE_REPORT_KEYS = 2, /*means report keys to android*/ +} handle_option_type; + +#endif + diff --git a/drivers/sensors/sensors_ssc.c b/drivers/sensors/sensors_ssc.c index fa9a68ce7604..9df19c7efcbb 100644 --- a/drivers/sensors/sensors_ssc.c +++ b/drivers/sensors/sensors_ssc.c @@ -21,6 +21,7 @@ #include #include +#include #include #define IMAGE_LOAD_CMD 1 @@ -349,6 +350,10 @@ static int sensors_ssc_probe(struct platform_device *pdev) { int ret = slpi_loader_init_sysfs(pdev); +#ifdef OPLUS_BUG_STABILITY + struct regulator *vdd_2v8 = NULL; + struct regulator *vddio_1v8 = NULL; +#endif if (ret != 0) { dev_err(&pdev->dev, "%s: Error in initing sysfs\n", __func__); return ret; @@ -389,6 +394,32 @@ static int sensors_ssc_probe(struct platform_device *pdev) } INIT_WORK(&slpi_ldr_work, slpi_load_fw); +#ifdef OPLUS_BUG_STABILITY + vdd_2v8 = regulator_get(&pdev->dev, "vdd"); + vddio_1v8 = regulator_get(&pdev->dev, "vddio"); + + if (vdd_2v8 != NULL) { + dev_err(&pdev->dev,"%s: vdd_2v8 is not NULL\n", __func__); + regulator_set_voltage(vdd_2v8, 2800000, 3104000); + regulator_set_load(vdd_2v8, 200000); + ret = regulator_enable(vdd_2v8); + if (ret) + dev_err(&pdev->dev,"%s: vdd_2v8 enable fail\n", __func__); + } else { + dev_err(&pdev->dev,"%s: vdd_2v8 is NULL\n", __func__); + } + msleep(10); + if (vddio_1v8 != NULL) { + dev_err(&pdev->dev,"%s: vddio_1v8 is not NULL\n", __func__); + regulator_set_voltage(vddio_1v8, 1800000, 1952000); + regulator_set_load(vddio_1v8, 200000); + ret = regulator_enable(vddio_1v8); + if (ret) + dev_err(&pdev->dev,"%s: vddio_1v8 enable fail\n", __func__); + } else { + dev_err(&pdev->dev,"%s: vddio_1v8 is NULL\n", __func__); + } +#endif//OPLUS_BUG_STABILITY return 0; diff --git a/drivers/soc/Kconfig b/drivers/soc/Kconfig index c07b4a85253f..f7dd07043f52 100644 --- a/drivers/soc/Kconfig +++ b/drivers/soc/Kconfig @@ -18,5 +18,48 @@ source "drivers/soc/ux500/Kconfig" source "drivers/soc/versatile/Kconfig" source "drivers/soc/xilinx/Kconfig" source "drivers/soc/zte/Kconfig" +source "drivers/soc/oplus/Kconfig" +#ifdef OPLUS_FEATURE_IOMONITOR +source "drivers/soc/oplus/iomonitor/Kconfig" +#endif /*OPLUS_FEATURE_IOMONITOR*/ +#ifdef VENDOR_EDIT +source "drivers/soc/oplus/system/Kconfig" +#endif /* VENDOR_EDIT */ +#ifdef OPLUS_FEATURE_HEALTHINFO +source "drivers/soc/oplus/healthinfo/Kconfig" +#endif /* OPLUS_FEATURE_HEALTHINFO */ + +#ifdef OPLUS_FEATURE_POWERINFO_STANDBY +source "drivers/soc/oplus/owakelock/Kconfig" +#endif /* OPLUS_FEATURE_POWERINFO_STANDBY */ + +#ifdef OPLUS_FEATURE_SENSOR_SMEM +source "drivers/soc/oplus/sensor/Kconfig" +#endif /* OPLUS_FEATURE_SENSOR_SMEM */ + +#ifdef OPLUS_FEATURE_ESIM +source "drivers/soc/oplus/misc/Kconfig" +#endif /* OPLUS_FEATURE_ESIM */ + +#ifdef OPLUS_FEATURE_TPP +#jacky.ho@optimization add for tpp module +source "drivers/soc/oplus/tpp/Kconfig" +#endif /* OPLUS_FEATURE_IM */ + +#ifdef OPLUS_FEATURE_IM +#ted.lin@optimization add for im module +source "drivers/soc/oplus/im/Kconfig" +#endif /* OPLUS_FEATURE_IM */ + +#ifdef OPLUS_FEATURE_TPD +source "drivers/soc/oplus/tpd/Kconfig" +#endif + +#Add for NandSwap +source "drivers/soc/oplus/oplus_nandswap/Kconfig" + +#ifdef OPLUS_FEATURE_GAME_OPT +source "drivers/soc/oplus/game_opt/Kconfig" +#endif /* OPLUS_FEATURE_GAME_OPT */ endmenu diff --git a/drivers/soc/Makefile b/drivers/soc/Makefile index f0d46b16e08c..daa2d094b9f6 100644 --- a/drivers/soc/Makefile +++ b/drivers/soc/Makefile @@ -25,3 +25,52 @@ obj-$(CONFIG_ARCH_U8500) += ux500/ obj-$(CONFIG_PLAT_VERSATILE) += versatile/ obj-y += xilinx/ obj-$(CONFIG_ARCH_ZX) += zte/ +obj-y += oplus/ +#ifdef VENDOR_EDIT +obj-$(CONFIG_OPLUS_SYSTEM_KERNEL) += oplus/system/ +#endif /* VENDOR_EDIT */ + +#ifdef OPLUS_FEATURE_IOMONITOR +obj-$(CONFIG_IOMONITOR) += oplus/iomonitor/ +#endif /*OPLUS_FEATURE_IOMONITOR*/ + +#ifdef OPLUS_FEATURE_SENSOR_SMEM +obj-y += oplus/sensor/ +#endif +#ifdef OPLUS_FEATURE_SENSOR_CRASH_MONITOR +obj-$(CONFIG_OPLUS_FEATURE_SENSOR_CRASH_MONITOR) += oplus/oplus_slpirst/ +#endif + + +#ifdef OPLUS_FEATURE_HEALTHINFO +obj-y += oplus/healthinfo/ +#endif /* OPLUS_FEATURE_HEALTHINFO */ + +#ifdef OPLUS_FEATURE_POWERINFO_STANDBY +obj-$(CONFIG_OPLUS_WAKELOCK_PROFILER) += oplus/owakelock/ +#endif /* OPLUS_FEATURE_POWERINFO_STANDBY */ + +#ifdef OPLUS_FEATURE_ESIM +obj-y += oplus/misc/ +#endif /* OPLUS_FEATURE_ESIM */ + +#ifdef OPLUS_FEATURE_TPP +#jacky.ho@optimization add for tpp module +obj-$(CONFIG_OPLUS_FEATURE_TPP) += oplus/tpp/ +#endif /* OPLUS_FEATURE_TPP */ + +#ifdef OPLUS_FEATURE_IM +#ted.lin@optimization add for im module +obj-$(CONFIG_OPLUS_FEATURE_IM) += oplus/im/ +#endif /* OPLUS_FEATURE_IM */ + +#ifdef OPLUS_FEATURE_TPD +obj-$(CONFIG_OPLUS_FEATURE_TPD) += oplus/tpd/ +#endif + +#Add for NandSwap +obj-$(CONFIG_NANDSWAP) += oplus/oplus_nandswap/ + +#ifdef OPLUS_FEATURE_GAME_OPT +obj-$(CONFIG_OPLUS_FEATURE_GAME_OPT) += oplus/game_opt/ +#endif /* OPLUS_FEATURE_GAME_OPT */ diff --git a/drivers/soc/oplus/Kconfig b/drivers/soc/oplus/Kconfig new file mode 100644 index 000000000000..cc24a5c66006 --- /dev/null +++ b/drivers/soc/oplus/Kconfig @@ -0,0 +1,36 @@ +#ifdef OPLUS_FEATURE_TP_BASIC +config OPLUS_COMMON_SOFT + bool "config oplus common software" + help + define this config to get project verion from sharemem. + Maybe this value is from CDT or dynamic identify by hardware + id. + +source "drivers/soc/oplus/device_info/Kconfig" +#endif /* OPLUS_FEATURE_TP_BASIC */ + + +#ifdef OPLUS_FEATURE_GPIO_NC +config OPLUS_GPIO_NC + bool "config oplus gpio nc" + help + define this config to compile oplus_gpio.c for device register +#endif + +#ifdef OPLUS_FEATURE_LOWMEM_DBG +#Add for dump memory usage when lowmmem occurs. +source "drivers/soc/oplus/lowmem_dbg/Kconfig" +##endif /* OPLUS_FEATURE_LOWMEM_DBG */ + +#ifdef OPLUS_FEATURE_MIDAS +source "drivers/soc/oplus/midas/Kconfig" +#endif + +#ifdef OPLUS_FEATURE_MEMLEAK_DETECT +#Add for svelte +source "drivers/soc/oplus/svelte/Kconfig" +#endif /* OPLUS_FEATURE_MEMLEAK_DETECT */ + +#ifdef OPLUS_FEATURE_THERMAL_HORAE +source "drivers/soc/oplus/thermal/Kconfig" +#endif /* OPLUS_FEATURE_THERMAL_HORAE */ diff --git a/drivers/soc/oplus/Makefile b/drivers/soc/oplus/Makefile new file mode 100644 index 000000000000..3b5174c6ae50 --- /dev/null +++ b/drivers/soc/oplus/Makefile @@ -0,0 +1,25 @@ +obj-$(CONFIG_OPLUS_COMMON_SOFT) += device_info/ + +#ifdef OPLUS_FEATURE_LOWMEM_DBG +#Add for dump mem when shrink +obj-$(CONFIG_OPLUS_FEATURE_LOWMEM_DBG) += lowmem_dbg/ +#endif /* OPLUS_FEATURE_LOWMEM_DBG */ + +#ifdef VENDOR_EDIT +obj-$(CONFIG_OPLUS_FEATURE_MIDAS) += midas/ +#endif /* VENDOR_EDIT */ + +#ifdef OPLUS_FEATURE_MEMLEAK_DETECT +#Add for svelte logging +obj-$(CONFIG_SVELTE) += svelte/ +#endif /* OPLUS_FEATURE_MEMLEAK_DETECT */ + + +#ifdef OPLUS_FEATURE_THERMAL_HORAE +obj-$(CONFIG_HORAE_THERMAL_SHELL) += thermal/ +#endif /* OPLUS_FEATURE_THERMAL_HORAE */ + +#ifdef OPLUS_FEATURE_GPIO_NC +obj-$(CONFIG_OPLUS_GPIO_NC) += oplus_gpio/ +#endif + diff --git a/drivers/soc/oplus/device_info b/drivers/soc/oplus/device_info new file mode 120000 index 000000000000..4a2c7e7f135c --- /dev/null +++ b/drivers/soc/oplus/device_info @@ -0,0 +1 @@ +../../../../../vendor/oplus/kernel/device_info/device_info \ No newline at end of file diff --git a/drivers/soc/oplus/game_opt/Kconfig b/drivers/soc/oplus/game_opt/Kconfig new file mode 100644 index 000000000000..9a608f961320 --- /dev/null +++ b/drivers/soc/oplus/game_opt/Kconfig @@ -0,0 +1,5 @@ +config OPLUS_FEATURE_GAME_OPT + tristate "game optimization" + default n + help + game optimization support diff --git a/drivers/soc/oplus/game_opt/Makefile b/drivers/soc/oplus/game_opt/Makefile new file mode 100644 index 000000000000..0a9d899e3d23 --- /dev/null +++ b/drivers/soc/oplus/game_opt/Makefile @@ -0,0 +1,2 @@ +obj-$(CONFIG_OPLUS_FEATURE_GAME_OPT) += game_opt.o +game_opt-y := game_ctrl.o cpu_load.o cpufreq_limits.o task_util.o rt_info.o dstate_dump.o diff --git a/drivers/soc/oplus/game_opt/cpu_load.c b/drivers/soc/oplus/game_opt/cpu_load.c new file mode 100644 index 000000000000..d124af45cf40 --- /dev/null +++ b/drivers/soc/oplus/game_opt/cpu_load.c @@ -0,0 +1,263 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2022 Oplus. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "game_ctrl.h" + +#define KHZ_PER_MHZ 1000 + +struct time_in_state { + spinlock_t lock; + u64 last_read; + u64 last_update; + unsigned int *freq_table; /* mHz */ + u64 *time; + unsigned int time_byte_size; + unsigned int max_freq; /* mHz */ + unsigned int max_freq_state; + unsigned int max_idle_state; + /* 0=active 1=idle */ + unsigned int cur_idle_idx; + /* 0~freq_num-1 */ + unsigned int cur_freq_idx; +}; + +static DEFINE_PER_CPU(struct time_in_state, stats_info); + +static bool initialized = false; + +/* called with icpu->lock held */ +static void inline update_cur_state(struct time_in_state *icpu, u64 now) +{ + u64 delta_time; + unsigned int pos; + + delta_time = now - icpu->last_update; + pos = icpu->cur_idle_idx * icpu->max_freq_state + icpu->cur_freq_idx; + icpu->time[pos] += delta_time; + icpu->last_update = now; +} + +/* called with icpu->lock held */ +static void inline reset_cur_state_after_read(struct time_in_state *icpu, u64 now) +{ + memset(icpu->time, 0, icpu->time_byte_size); + icpu->last_read = icpu->last_update = now; +} + +static int cpufreq_table_get_index(struct time_in_state *stats, unsigned int freq) +{ + int index; + freq /= KHZ_PER_MHZ; + for (index = 0; index < stats->max_freq_state; index++) + if (stats->freq_table[index] == freq) + return index; + return -1; +} + +static void get_cpu_load(int cpu, int *util_pct, int *busy_pct) +{ + unsigned int i; + u64 now, delta_time, delta_idle = 0, timeadjfreq = 0; + struct time_in_state *icpu = per_cpu_ptr(&stats_info, cpu); + unsigned long flags; + + if (!initialized) + return; + + now = ktime_to_us(ktime_get()); + + spin_lock_irqsave(&icpu->lock, flags); + + update_cur_state(icpu, now); + + delta_time = now - icpu->last_read; + for (i = 0; i < icpu->max_freq_state; i++) + timeadjfreq += icpu->freq_table[i] * icpu->time[i]; + for (i = 0; i < icpu->max_freq_state; i++) + delta_idle += icpu->time[icpu->max_freq_state + i]; + + if (timeadjfreq <= 0) + *util_pct = 0; + else + *util_pct = div64_u64(100 * timeadjfreq, delta_time * icpu->max_freq); + + if (delta_time <= delta_idle) + *busy_pct = 0; + else + *busy_pct = div64_u64(100 * (delta_time - delta_idle), delta_time); + + reset_cur_state_after_read(icpu, now); + + spin_unlock_irqrestore(&icpu->lock, flags); +} + +void g_time_in_state_update_idle(int cpu, unsigned int new_idle_index) +{ + struct time_in_state *icpu = NULL; + unsigned long flags; + + if (!initialized || cpu < 0 || cpu >= nr_cpu_ids) + return; + + icpu = per_cpu_ptr(&stats_info, cpu); + if (new_idle_index >= icpu->max_idle_state) + return; + + spin_lock_irqsave(&icpu->lock, flags); + update_cur_state(icpu, ktime_to_us(ktime_get())); + icpu->cur_idle_idx = new_idle_index; + spin_unlock_irqrestore(&icpu->lock, flags); +} + +static int time_in_state_update_freq(struct notifier_block *nb, unsigned long event, void *v) +{ + struct cpufreq_freqs *freqs = (struct cpufreq_freqs*)v; + const struct cpumask *cpus = cpumask_of(freqs->cpu); + unsigned int new_freq = freqs->new; + int cpu; + unsigned int new_freq_index; + struct time_in_state *icpu = NULL; + u64 now; + unsigned long flags; + + if (event == CPUFREQ_POSTCHANGE) { + if (!initialized || cpus == NULL || cpumask_empty(cpus)) + return 0; + + icpu = per_cpu_ptr(&stats_info, cpumask_first(cpus)); + new_freq_index = cpufreq_table_get_index(icpu, new_freq); + if (new_freq_index < 0 || new_freq_index >= icpu->max_freq_state) + return 0; + + now = ktime_to_us(ktime_get()); + for_each_cpu(cpu, cpus) { + icpu = per_cpu_ptr(&stats_info, cpu); + spin_lock_irqsave(&icpu->lock, flags); + update_cur_state(icpu, now); + icpu->cur_freq_idx = new_freq_index; + spin_unlock_irqrestore(&icpu->lock, flags); + } + } + return 0; +} + +static struct notifier_block cpufreq_transition_notifier = { + .notifier_call = time_in_state_update_freq, +}; + +static int time_in_state_init(void) +{ + int cpu, ret, freq_index; + struct time_in_state *icpu = NULL; + struct cpufreq_policy policy; + unsigned int alloc_size, i, count; + struct cpufreq_frequency_table *pos = NULL; + + for_each_present_cpu(cpu) { + icpu = per_cpu_ptr(&stats_info, cpu); + + icpu->max_idle_state = 2; /* 0 active, 1 idle */ + icpu->cur_idle_idx = 0; + + ret = cpufreq_get_policy(&policy, cpu); + if (ret != 0) + goto err_out; + + icpu->max_freq = policy.cpuinfo.max_freq / KHZ_PER_MHZ; + + count = cpufreq_table_count_valid_entries(&policy); + if (!count) + goto err_out; + + icpu->max_freq_state = count; + icpu->time_byte_size = icpu->max_idle_state * count * sizeof(u64); + alloc_size = count * sizeof(int) + icpu->time_byte_size; + icpu->freq_table = kzalloc(alloc_size, GFP_KERNEL); + if (icpu->freq_table == NULL) { + pr_err("time in stats alloc fail for cpu:%d\n", cpu); + goto err_out; + } + icpu->time = (u64 *)(icpu->freq_table + icpu->max_freq_state); + + i = 0; + cpufreq_for_each_valid_entry(pos, policy.freq_table) + icpu->freq_table[i++] = pos->frequency / KHZ_PER_MHZ; + + freq_index = cpufreq_table_get_index(icpu, policy.cur); + if (freq_index < 0) + goto err_out; + icpu->cur_freq_idx = freq_index; + + spin_lock_init(&icpu->lock); + icpu->last_read = icpu->last_update = ktime_to_us(ktime_get()); + } + + cpufreq_register_notifier(&cpufreq_transition_notifier, CPUFREQ_TRANSITION_NOTIFIER); + + initialized = true; + +err_out: + if (!initialized) { + for_each_present_cpu(cpu) { + icpu = per_cpu_ptr(&stats_info, cpu); + + if (icpu->freq_table != NULL) { + kfree(icpu->freq_table); + icpu->freq_table = NULL; + } + } + } + + return 0; +} + +static int cpu_load_show(struct seq_file *m, void *v) +{ + int cpu; + int util_pct, busy_pct; + + for_each_possible_cpu(cpu) { + get_cpu_load(cpu, &util_pct, &busy_pct); + seq_printf(m, "CPU:%d busy_pct:%d util_pct:%d\n", cpu, busy_pct, util_pct); + } + + return 0; +} + +static int cpu_load_proc_open(struct inode *inode, struct file *filp) +{ + return single_open(filp, cpu_load_show, inode); +} + +static const struct file_operations cpu_load_proc_ops = { + .open = cpu_load_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +int cpu_load_init() +{ + if (unlikely(!game_opt_dir)) + return -ENOTDIR; + + time_in_state_init(); + + proc_create_data("cpu_load", 0444, game_opt_dir, &cpu_load_proc_ops, NULL); + + return 0; +} diff --git a/drivers/soc/oplus/game_opt/cpufreq_limits.c b/drivers/soc/oplus/game_opt/cpufreq_limits.c new file mode 100644 index 000000000000..fd0a279c4794 --- /dev/null +++ b/drivers/soc/oplus/game_opt/cpufreq_limits.c @@ -0,0 +1,269 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2022 Oplus. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "game_ctrl.h" + +/* To handle cpufreq min/max request */ +struct cpu_freq_status { + unsigned int min; + unsigned int max; +}; + +static DEFINE_PER_CPU(struct cpu_freq_status, game_cpu_stats); + +static cpumask_var_t limit_mask_min; +static cpumask_var_t limit_mask_max; + +static ssize_t set_cpu_min_freq(const char *buf, size_t count) +{ + int i, j, ntokens = 0; + unsigned int val, cpu; + unsigned int min_freq; + const char *cp = buf; + struct cpu_freq_status *i_cpu_stats; + struct cpufreq_policy policy; + + while ((cp = strpbrk(cp + 1, " :"))) + ntokens++; + + /* CPU:value pair */ + if (!(ntokens % 2)) + return -EINVAL; + + cp = buf; + cpumask_clear(limit_mask_min); + for (i = 0; i < ntokens; i += 2) { + if (sscanf(cp, "%u:%u", &cpu, &val) != 2) + return -EINVAL; + if (cpu > (num_present_cpus() - 1)) + return -EINVAL; + + i_cpu_stats = &per_cpu(game_cpu_stats, cpu); + + i_cpu_stats->min = val; + cpumask_set_cpu(cpu, limit_mask_min); + + cp = strnchr(cp, strlen(cp), ' '); + cp++; + } + + /* + * Since on synchronous systems policy is shared amongst multiple + * CPUs only one CPU needs to be updated for the limit to be + * reflected for the entire cluster. We can avoid updating the policy + * of other CPUs in the cluster once it is done for at least one CPU + * in the cluster + */ + get_online_cpus(); + for_each_cpu(i, limit_mask_min) { + i_cpu_stats = &per_cpu(game_cpu_stats, i); + min_freq = i_cpu_stats->min; + + if (cpufreq_get_policy(&policy, i)) + continue; + + if (cpu_online(i) && (policy.min != i_cpu_stats->min)) + cpufreq_update_policy(i); + + for_each_cpu(j, policy.related_cpus) { + cpumask_clear_cpu(j, limit_mask_min); + i_cpu_stats = &per_cpu(game_cpu_stats, j); + i_cpu_stats->min = min_freq; + } + } + put_online_cpus(); + + return count; +} + +static ssize_t cpu_min_freq_proc_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) +{ + char page[256] = {0}; + int ret; + + ret = simple_write_to_buffer(page, sizeof(page) - 1, ppos, buf, count); + if (ret <= 0) + return ret; + + return set_cpu_min_freq(page, ret); +} + +static int cpu_min_freq_show(struct seq_file *m, void *v) +{ + int cpu; + + for_each_present_cpu(cpu) + seq_printf(m, "%d:%u ", cpu, per_cpu(game_cpu_stats, cpu).min); + seq_printf(m, "\n"); + + return 0; +} + +static int cpu_min_freq_proc_open(struct inode *inode, struct file *filp) +{ + return single_open(filp, cpu_min_freq_show, inode); +} + +static const struct file_operations cpu_min_freq_proc_ops = { + .open = cpu_min_freq_proc_open, + .write = cpu_min_freq_proc_write, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static ssize_t set_cpu_max_freq(const char *buf, size_t count) +{ + int i, j, ntokens = 0; + unsigned int val, cpu; + unsigned int max_freq; + const char *cp = buf; + struct cpu_freq_status *i_cpu_stats; + struct cpufreq_policy policy; + + while ((cp = strpbrk(cp + 1, " :"))) + ntokens++; + + /* CPU:value pair */ + if (!(ntokens % 2)) + return -EINVAL; + + cp = buf; + cpumask_clear(limit_mask_max); + for (i = 0; i < ntokens; i += 2) { + if (sscanf(cp, "%u:%u", &cpu, &val) != 2) + return -EINVAL; + if (cpu > (num_present_cpus() - 1)) + return -EINVAL; + + i_cpu_stats = &per_cpu(game_cpu_stats, cpu); + + i_cpu_stats->max = val; + cpumask_set_cpu(cpu, limit_mask_max); + + cp = strnchr(cp, strlen(cp), ' '); + cp++; + } + + get_online_cpus(); + for_each_cpu(i, limit_mask_max) { + i_cpu_stats = &per_cpu(game_cpu_stats, i); + max_freq = i_cpu_stats->max; + if (cpufreq_get_policy(&policy, i)) + continue; + + if (cpu_online(i) && (policy.max != i_cpu_stats->max)) + cpufreq_update_policy(i); + + for_each_cpu(j, policy.related_cpus) { + cpumask_clear_cpu(j, limit_mask_max); + i_cpu_stats = &per_cpu(game_cpu_stats, j); + i_cpu_stats->max = max_freq; + } + } + put_online_cpus(); + + return count; +} + +static ssize_t cpu_max_freq_proc_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) +{ + char page[256] = {0}; + int ret; + + ret = simple_write_to_buffer(page, sizeof(page) - 1, ppos, buf, count); + if (ret <= 0) + return ret; + + return set_cpu_max_freq(page, ret); +} + +static int cpu_max_freq_show(struct seq_file *m, void *v) +{ + int cpu; + + for_each_present_cpu(cpu) + seq_printf(m, "%d:%u ", cpu, per_cpu(game_cpu_stats, cpu).max); + seq_printf(m, "\n"); + + return 0; +} + +static int cpu_max_freq_proc_open(struct inode *inode, struct file *filp) +{ + return single_open(filp, cpu_max_freq_show, inode); +} + +static const struct file_operations cpu_max_freq_proc_ops = { + .open = cpu_max_freq_proc_open, + .write = cpu_max_freq_proc_write, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int game_stat_adjust_notify(struct notifier_block *nb, unsigned long val, + void *data) +{ + struct cpufreq_policy *policy = data; + unsigned int cpu = policy->cpu; + struct cpu_freq_status *cpu_st = &per_cpu(game_cpu_stats, cpu); + unsigned int min = cpu_st->min, max = cpu_st->max; + + if (val != CPUFREQ_ADJUST) + return NOTIFY_OK; + + pr_debug("game_cpu_stats: CPU%u policy before: %u:%u kHz\n", cpu, + policy->min, policy->max); + pr_debug("game_cpu_stats: CPU%u seting min:max %u:%u kHz\n", cpu, min, max); + + cpufreq_verify_within_limits(policy, min, max); + + pr_debug("game_cpu_stats: CPU%u policy after: %u:%u kHz\n", cpu, + policy->min, policy->max); + + return NOTIFY_OK; +} + +static struct notifier_block game_stat_cpufreq_nb = { + .notifier_call = game_stat_adjust_notify, +}; + +int cpufreq_limits_init() +{ + unsigned int cpu; + + if (unlikely(!game_opt_dir)) + return -ENOTDIR; + + if (!alloc_cpumask_var(&limit_mask_min, GFP_KERNEL)) + return -ENOMEM; + + if (!alloc_cpumask_var(&limit_mask_max, GFP_KERNEL)) { + free_cpumask_var(limit_mask_min); + return -ENOMEM; + } + cpufreq_register_notifier(&game_stat_cpufreq_nb, CPUFREQ_POLICY_NOTIFIER); + + for_each_present_cpu(cpu) { + per_cpu(game_cpu_stats, cpu).max = UINT_MAX; + per_cpu(game_cpu_stats, cpu).min = 0; + } + + proc_create_data("cpu_min_freq", 0664, game_opt_dir, &cpu_min_freq_proc_ops, NULL); + proc_create_data("cpu_max_freq", 0664, game_opt_dir, &cpu_max_freq_proc_ops, NULL); + + return 0; +} diff --git a/drivers/soc/oplus/game_opt/dstate_dump.c b/drivers/soc/oplus/game_opt/dstate_dump.c new file mode 100644 index 000000000000..c267848e547d --- /dev/null +++ b/drivers/soc/oplus/game_opt/dstate_dump.c @@ -0,0 +1,275 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2022 Oplus. All rights reserved. + */ + +#include +#include +#include +#include + +#include "game_ctrl.h" + +#define MAX_INTERESTED_THREAD_NUM 10 +#define MAX_DSTATE_STACK_TRACE_DEPTH 32 + +static DEFINE_RAW_SPINLOCK(lock); +static atomic_t dump_enable = ATOMIC_INIT(1); /* default enable */ +static atomic_t dstate_duration = ATOMIC_INIT(5); /* default 5ms */ +static pid_t rt_interested_threads[MAX_RT_NUM]; +static int rt_thread_num = 0; +static pid_t interested_threads[MAX_INTERESTED_THREAD_NUM]; +static int thread_num = 0; +static struct proc_dir_entry *dstate_dir = NULL; + +static void g_dump_waker_stack(unsigned int waker_nr_entries, unsigned long *waker_entries) +{ + int i; + char buf[128]; + + for (i = waker_nr_entries - 1; i >= 0; i--) { + snprintf(buf, sizeof(buf), "%pS\n", (void *)waker_entries[i]); + trace_printk(buf); + } +} + +static void g_dump_wakee_stack(unsigned int wakee_nr_entries, unsigned long *wakee_entries) +{ + int i; + char buf[128]; + + for (i = wakee_nr_entries - 1; i >= 0; i--) { + snprintf(buf, sizeof(buf), "%pS\n", (void *)wakee_entries[i]); + trace_printk(buf); + } +} + +static void g_dstate_dump_stack(struct task_struct *task, u64 delay_ms) +{ + void * caller; + unsigned int waker_nr_entries; + unsigned long waker_entries[MAX_DSTATE_STACK_TRACE_DEPTH]; + unsigned int wakee_nr_entries; + unsigned long wakee_entries[MAX_DSTATE_STACK_TRACE_DEPTH]; + char buf[256]; + + struct stack_trace waker_dummy; + struct stack_trace wakee_dummy; + waker_dummy.nr_entries = 0; + waker_dummy.max_entries = MAX_DSTATE_STACK_TRACE_DEPTH; + waker_dummy.entries = &waker_entries[0]; + waker_dummy.skip = 0; + save_stack_trace(&waker_dummy); + waker_nr_entries = waker_dummy.nr_entries; + + wakee_dummy.nr_entries = 0; + wakee_dummy.max_entries = MAX_DSTATE_STACK_TRACE_DEPTH; + wakee_dummy.entries = &wakee_entries[0]; + wakee_dummy.skip = 0; + save_stack_trace_tsk(task, &wakee_dummy); + wakee_nr_entries = wakee_dummy.nr_entries; + caller = (void *)get_wchan(task); + + snprintf(buf, sizeof(buf), "delay_ms=%d, waker_nr_entries=%d, wakee_nr_entries=%d," + " waker:%s tid:%d pid:%d, wakee:%s tid:%d pid:%d, blocked_func=%pS\n", + delay_ms, waker_nr_entries, wakee_nr_entries, + current->comm, current->pid, current->tgid, task->comm, task->pid, task->tgid, caller); + trace_printk(buf); + + g_dump_waker_stack(waker_nr_entries, waker_entries); + g_dump_wakee_stack(wakee_nr_entries, wakee_entries); +} + +void rt_set_dstate_interested_threads(pid_t *tids, int num) { + int i; + + num = min(num, MAX_RT_NUM); + raw_spin_lock(&lock); + for (i = 0; i < num; i++) + rt_interested_threads[i] = tids[i]; + rt_thread_num = num; + raw_spin_unlock(&lock); +} + +static bool is_dstate_interested_threads(pid_t tid) { + int i; + bool ret = false; + + raw_spin_lock(&lock); + for (i = 0; i < rt_thread_num; i++) { + if (tid == rt_interested_threads[i]) { + ret = true; + goto unlock; + } + } + for (i = 0; i < thread_num; i++) { + if (tid == interested_threads[i]) { + ret = true; + break; + } + } +unlock: + raw_spin_unlock(&lock); + + return ret; +} + +void g_sched_stat_blocked(struct task_struct *task, u64 delay_ns) +{ + u64 delay_ms = delay_ns >> 20; + + if (atomic_read(&dump_enable) && + !task->in_iowait && + delay_ms >= atomic_read(&dstate_duration) && + is_dstate_interested_threads(task->pid)) { + g_dstate_dump_stack(task, delay_ms); + } +} + +static ssize_t dump_enable_proc_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) +{ + char page[32] = {0}; + int ret, enable; + + ret = simple_write_to_buffer(page, sizeof(page), ppos, buf, count); + if (ret <= 0) + return -EINVAL; + + ret = sscanf(page, "%d", &enable); + if (ret != 1) + return -EINVAL; + + if (enable > 0) + atomic_set(&dump_enable, 1); + else + atomic_set(&dump_enable, 0); + + return count; +} + +static ssize_t dump_enable_proc_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) +{ + char page[32] = {0}; + int len; + + len = sprintf(page, "%d\n", atomic_read(&dump_enable)); + return simple_read_from_buffer(buf, count, ppos, page, len); +} + +static const struct file_operations dump_enable_proc_ops = { + .write = dump_enable_proc_write, + .read = dump_enable_proc_read, +}; + +static ssize_t duration_proc_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) +{ + char page[32] = {0}; + int ret, duration; + + ret = simple_write_to_buffer(page, sizeof(page), ppos, buf, count); + if (ret <= 0) + return -EINVAL; + + ret = sscanf(page, "%d", &duration); + if (ret != 1) + return -EINVAL; + + if (duration >= 0) + atomic_set(&dstate_duration, duration); + + return count; +} + +static ssize_t duration_proc_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) +{ + char page[32] = {0}; + int len; + + len = sprintf(page, "%d\n", atomic_read(&dstate_duration)); + + return simple_read_from_buffer(buf, count, ppos, page, len); +} + +static const struct file_operations duration_proc_ops = { + .write = duration_proc_write, + .read = duration_proc_read, +}; + +static ssize_t interested_tids_proc_write(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) +{ + char page[256] = {0}; + char *iter = page; + pid_t tid; + pid_t tids[MAX_INTERESTED_THREAD_NUM]; + int num, i, ret; + + if (count > sizeof(page) - 1) + count = sizeof(page) - 1; + if (copy_from_user(page, buf, count)) + return -EFAULT; + + num = 0; + while (iter != NULL) { + /* input should be "123 234 ..." */ + ret = sscanf(iter, "%d", &tid); + if (ret != 1) + break; + + iter = strchr(iter + 1, ' '); + + tids[num++] = tid; + if (num >= MAX_INTERESTED_THREAD_NUM) + break; + } + + raw_spin_lock(&lock); + for (i = 0; i < num; i++) + interested_threads[i] = tids[i]; + thread_num = num; + raw_spin_unlock(&lock); + + return count; +} + +static ssize_t interested_tids_proc_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + char page[256] = {0}; + ssize_t len = 0; + int i; + + raw_spin_lock(&lock); + for (i = 0; i < thread_num; i++) + len += snprintf(page + len, sizeof(page) - len, "%d ", interested_threads[i]); + if (thread_num > 0) + len += snprintf(page + len, sizeof(page) - len, "\n"); + else + len += snprintf(page + len, sizeof(page) - len, "0\n"); + raw_spin_unlock(&lock); + + return simple_read_from_buffer(buf, count, ppos, page, len); +} + +static const struct file_operations interested_tids_proc_ops = { + .write = interested_tids_proc_write, + .read = interested_tids_proc_read, +}; + +int dstate_dump_init(void) +{ + if (unlikely(!game_opt_dir)) + return -ENOTDIR; + + dstate_dir = proc_mkdir("dstate", game_opt_dir); + if (!dstate_dir) { + pr_err("fail to mkdir /proc/game_opt/dstate\n"); + return -ENOMEM; + } + + proc_create_data("dump_enable", 0664, dstate_dir, &dump_enable_proc_ops, NULL); + proc_create_data("duration", 0664, dstate_dir, &duration_proc_ops, NULL); + proc_create_data("interested_tids", 0664, dstate_dir, &interested_tids_proc_ops, NULL); + + return 0; +} diff --git a/drivers/soc/oplus/game_opt/game_ctrl.c b/drivers/soc/oplus/game_opt/game_ctrl.c new file mode 100644 index 000000000000..2ce98f315001 --- /dev/null +++ b/drivers/soc/oplus/game_opt/game_ctrl.c @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2022 Oplus. All rights reserved. + */ + +#include +#include +#include +#include + +#include "game_ctrl.h" + +struct proc_dir_entry *game_opt_dir = NULL; + +static int __init game_ctrl_init(void) +{ + game_opt_dir = proc_mkdir("game_opt", NULL); + if (!game_opt_dir) { + pr_err("fail to mkdir /proc/game_opt\n"); + return -ENOMEM; + } + + cpu_load_init(); + cpufreq_limits_init(); + task_util_init(); + rt_info_init(); + dstate_dump_init(); + + return 0; +} + +static void __exit game_ctrl_exit(void) +{ +} + +module_init(game_ctrl_init); +module_exit(game_ctrl_exit); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/soc/oplus/game_opt/game_ctrl.h b/drivers/soc/oplus/game_opt/game_ctrl.h new file mode 100644 index 000000000000..1aab72c427ad --- /dev/null +++ b/drivers/soc/oplus/game_opt/game_ctrl.h @@ -0,0 +1,90 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2022 Oplus. All rights reserved. + */ + +#ifndef __GAME_CTRL_H__ +#define __GAME_CTRL_H__ + +#include +#include +#include +#include +#include "../../../../kernel/sched/sched.h" + +#define GAME_CTRL_MAGIC 'x' + +#define MAX_CPU_NR 8 +#define MAX_TASK_NR 10 +#define MAX_TID_COUNT 256 +#define MAX_TASK_INACTIVE_TIME 1000000000 /* 1s */ +#define MAX_RT_NUM 2 + +enum { + GET_CPU_LOAD = 1, + SET_GAME_PID, + GET_TASK_UTIL, + SET_CPU_MIN_FREQ, + SET_CPU_MAX_FREQ, + GAME_CTRL_MAX_NR +}; + +struct cpu_load_info { + int busy_pct; + int util_pct; +}; + +struct cpu_load { + struct cpu_load_info info[MAX_CPU_NR]; +}; + +struct game_pid { + pid_t pid; +}; + +struct task_util_info { + pid_t tid; + char comm[TASK_COMM_LEN]; + u16 util; +}; + +struct task_util { + int num; + struct task_util_info info[MAX_TASK_NR]; +}; + +struct cpu_freq_info { + /* ex: 0:960000 4:1440000 7:2284800 */ + char buf[128]; +}; + +#define GAME_GET_CPU_LOAD \ + _IOWR(GAME_CTRL_MAGIC, GET_CPU_LOAD, struct cpu_load) + +#define GAME_SET_GAME_PID \ + _IOWR(GAME_CTRL_MAGIC, SET_GAME_PID, struct game_pid) + +#define GAME_GET_TASK_UTIL \ + _IOWR(GAME_CTRL_MAGIC, GET_TASK_UTIL, struct task_util) + +#define GAME_SET_CPU_MIN_FREQ \ + _IOWR(GAME_CTRL_MAGIC, SET_CPU_MIN_FREQ, struct cpu_freq_info) + +#define GAME_SET_CPU_MAX_FREQ \ + _IOWR(GAME_CTRL_MAGIC, SET_CPU_MAX_FREQ, struct cpu_freq_info) + +extern struct proc_dir_entry *game_opt_dir; + +int cpu_load_init(void); +int cpufreq_limits_init(void); +int task_util_init(void); +int rt_info_init(void); +void rt_task_dead(struct task_struct *task); +int dstate_dump_init(void); +void rt_set_dstate_interested_threads(pid_t *tids, int num); +extern void g_time_in_state_update_idle(int cpu, unsigned int new_idle_index); +extern void g_rt_try_to_wake_up(struct task_struct *task); +extern void g_update_task_runtime(struct task_struct *task, u64 runtime); +extern void g_rt_task_dead(struct task_struct *task); +extern void g_sched_stat_blocked(struct task_struct *task, u64 delay_ns); +#endif /*__GAME_CTRL_H__*/ diff --git a/drivers/soc/oplus/game_opt/rt_info.c b/drivers/soc/oplus/game_opt/rt_info.c new file mode 100644 index 000000000000..a9048506e381 --- /dev/null +++ b/drivers/soc/oplus/game_opt/rt_info.c @@ -0,0 +1,441 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2022 Oplus. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "game_ctrl.h" + +/* + * render thread information + */ +struct render_thread_info_t { + pid_t rt_tid; + struct task_struct *rt_task; + struct list_head waker_list; +} render_thread_info[MAX_RT_NUM]; + +/* + * render thread waker information + */ +struct rt_waker_info_t { + struct list_head node; + pid_t waker_tid; + u64 total; + u32 increment; + u64 last_wake_ts; +}; + +static DEFINE_RWLOCK(rt_info_rwlock); +static atomic_t need_stat_wake = ATOMIC_INIT(0); +static unsigned int rt_num = 0; + +static struct rt_waker_info_t *g_waker_mempool = NULL; +static struct list_head g_mempool_list; +static struct list_head *g_mempool_list_ptr = &g_mempool_list; + +static struct rt_waker_info_t *waker_mempool_create(void) +{ + struct rt_waker_info_t *waker_mempool = NULL; + + waker_mempool = kzalloc(sizeof(struct rt_waker_info_t) * MAX_TID_COUNT, GFP_ATOMIC); + + return waker_mempool; +} + +static void waker_mempool_init(struct rt_waker_info_t *waker_mempool) +{ + int i; + + if (likely(waker_mempool)) { + INIT_LIST_HEAD(g_mempool_list_ptr); + for (i = 0; i < MAX_TID_COUNT; i++) + list_add_tail(&waker_mempool[i].node, g_mempool_list_ptr); + } +} + +static struct rt_waker_info_t *waker_mempool_alloc_one(void) +{ + struct list_head *pos; + struct rt_waker_info_t *waker = NULL; + + if (!list_empty(g_mempool_list_ptr)) { + pos = g_mempool_list_ptr->next; + list_del(pos); + waker = list_entry(pos, struct rt_waker_info_t, node); + } + + return waker; +} + +static void waker_mempool_free_one(struct rt_waker_info_t *waker) +{ + if (likely(waker)) { + list_del(&waker->node); + list_add_tail(&waker->node, g_mempool_list_ptr); + } +} + +static void waker_mempool_destory(struct rt_waker_info_t *waker_mempool) +{ + if (likely(waker_mempool)) + kfree(waker_mempool); +} + +static void add_rt_waker_stat(struct render_thread_info_t *info) +{ + struct list_head *pos; + struct rt_waker_info_t *waker; + struct rt_waker_info_t *new_waker; + pid_t waker_tid = current->pid; + u64 ts = ktime_get_ns(); + + list_for_each(pos, &info->waker_list) { + waker = list_entry(pos, struct rt_waker_info_t, node); + if (waker->waker_tid == waker_tid) { + waker->total++; + waker->increment++; + waker->last_wake_ts = ts; + return; + } + } + + new_waker = waker_mempool_alloc_one(); + if (new_waker) { + new_waker->waker_tid = waker_tid; + new_waker->total = 1; + new_waker->increment = 1; + new_waker->last_wake_ts = ts; + list_add_tail(&new_waker->node, &info->waker_list); + } +} + +void g_rt_try_to_wake_up(struct task_struct *task) +{ + int i; + pid_t wakee_tid = task->pid; + unsigned long flags; + + if (atomic_read(&need_stat_wake) == 0) + return; + + /* + * only update waker stat when lock is available, + * if not available, skip these information + */ + if (write_trylock_irqsave(&rt_info_rwlock, flags)) { + for (i = 0; i < rt_num; i++) { + if (wakee_tid == render_thread_info[i].rt_tid) { + /* waker and wakee belongs to same pid */ + if (current->tgid == render_thread_info[i].rt_task->tgid) + add_rt_waker_stat(&render_thread_info[i]); + break; + } + } + write_unlock_irqrestore(&rt_info_rwlock, flags); + } +} + +void rt_task_dead(struct task_struct *task) +{ + int i; + struct list_head *pos, *n; + struct rt_waker_info_t *waker; + unsigned long flags; + + if (atomic_read(&need_stat_wake) == 0) + return; + + if (write_trylock_irqsave(&rt_info_rwlock, flags)) { + for (i = 0; i < rt_num; i++) { + if (task->tgid == render_thread_info[i].rt_tid) { + list_for_each_safe(pos, n, &render_thread_info[i].waker_list) { + waker = list_entry(pos, struct rt_waker_info_t, node); + if (task->pid == waker->waker_tid) { + waker_mempool_free_one(waker); + break; + } + } + } + } + write_unlock_irqrestore(&rt_info_rwlock, flags); + } +} + +/* + * Ascending order by increment + */ +static int cmp_task_wake_inc(const void *a, const void *b) +{ + struct rt_waker_info_t *prev, *next; + + prev = (struct rt_waker_info_t *)a; + next = (struct rt_waker_info_t *)b; + if (unlikely(!prev || !next)) + return 0; + + return next->increment - prev->increment; +} + +static bool get_task_name(pid_t tid, char *name) { + struct task_struct * task = NULL; + bool ret = false; + + rcu_read_lock(); + task = find_task_by_vpid(tid); + if (task) { + strncpy(name, task->comm, TASK_COMM_LEN); + ret = true; + } + rcu_read_unlock(); + + return ret; +} + +#define RT_PAGE_SIZE 2048 +static int rt_info_show(struct seq_file *m, void *v) +{ + unsigned long flags; + struct rt_waker_info_t *results1, *results2; + int i, num1 = 0, num2 = 0; + pid_t wakee1_tid, wakee2_tid; + struct list_head *pos, *n; + struct rt_waker_info_t *waker; + char *page; + char waker_name[TASK_COMM_LEN]; + ssize_t len = 0; + u64 ts = ktime_get_ns(); + + page = kzalloc(RT_PAGE_SIZE, GFP_KERNEL); + if (!page) + return -ENOMEM; + results1 = kmalloc(sizeof(struct rt_waker_info_t) * MAX_TID_COUNT, GFP_KERNEL); + if (!results1) { + kfree(page); + return -ENOMEM; + } + + read_lock_irqsave(&rt_info_rwlock, flags); + if (rt_num >= 1) { + wakee1_tid = render_thread_info[0].rt_tid; + list_for_each_safe(pos, n, &render_thread_info[0].waker_list) { + waker = list_entry(pos, struct rt_waker_info_t, node); + if (waker->increment) { + results1[num1].waker_tid = waker->waker_tid; + results1[num1].total = waker->total; + results1[num1].increment = waker->increment; + waker->increment = 0; + num1++; + } else if (ts - waker->last_wake_ts > MAX_TASK_INACTIVE_TIME) { + waker_mempool_free_one(waker); + } + } + } + if (rt_num >= 2 && likely(num1 < MAX_TID_COUNT)) { + wakee2_tid = render_thread_info[1].rt_tid; + results2 = &results1[num1]; + list_for_each_safe(pos, n, &render_thread_info[1].waker_list) { + waker = list_entry(pos, struct rt_waker_info_t, node); + if (waker->increment) { + results2[num2].waker_tid = waker->waker_tid; + results2[num2].total = waker->total; + results2[num2].increment = waker->increment; + waker->increment = 0; + num2++; + if (unlikely(num1 + num2 >= MAX_TID_COUNT)) + break; + } else if (ts - waker->last_wake_ts > MAX_TASK_INACTIVE_TIME) { + waker_mempool_free_one(waker); + } + } + } + read_unlock_irqrestore(&rt_info_rwlock, flags); + + if (num1 > 0) { + sort(results1, num1, sizeof(struct rt_waker_info_t), &cmp_task_wake_inc, NULL); + num1 = min(num1, MAX_TASK_NR); + for (i = 0; i < num1; i++) { + if (get_task_name(results1[i].waker_tid, waker_name)) { + len += snprintf(page + len, RT_PAGE_SIZE - len, "%d;%s;%d;%d;%d\n", + results1[i].waker_tid, waker_name, wakee1_tid, + results1[i].total, results1[i].increment); + } + } + } + if (num2 > 0) { + sort(results2, num2, sizeof(struct rt_waker_info_t), &cmp_task_wake_inc, NULL); + num2 = min(num2, MAX_TASK_NR); + for (i = 0; i < num2; i++) { + if (get_task_name(results2[i].waker_tid, waker_name)) { + len += snprintf(page + len, RT_PAGE_SIZE - len, "%d;%s;%d;%d;%d\n", + results2[i].waker_tid, waker_name, wakee2_tid, + results2[i].total, results2[i].increment); + } + } + } + if (len > 0) + seq_puts(m, page); + + kfree(results1); + kfree(page); + + return 0; +} + +static int rt_info_proc_open(struct inode *inode, struct file *filp) +{ + return single_open(filp, rt_info_show, inode); +} + +static ssize_t rt_info_proc_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) +{ + unsigned long flags; + int i, ret; + char page[128] = {0}; + char *iter = page; + struct task_struct *task; + pid_t tid; + pid_t tids[MAX_RT_NUM]; + + if (count > sizeof(page) - 1) + count = sizeof(page) - 1; + if (copy_from_user(page, buf, count)) + return -EFAULT; + + atomic_set(&need_stat_wake, 0); + + write_lock_irqsave(&rt_info_rwlock, flags); + + for (i = 0; i < rt_num; i++) { + if (render_thread_info[i].rt_task) + put_task_struct(render_thread_info[i].rt_task); + } + + rt_num = 0; + while (iter != NULL) { + /* input should be "123 234" */ + ret = sscanf(iter, "%d", &tid); + if (ret != 1) + break; + + iter = strchr(iter + 1, ' '); + + rcu_read_lock(); + task = find_task_by_vpid(tid); + if (task) + get_task_struct(task); + rcu_read_unlock(); + + if (task) { + tids[rt_num] = tid; + + render_thread_info[rt_num].rt_tid = tid; + render_thread_info[rt_num].rt_task = task; + INIT_LIST_HEAD(&render_thread_info[rt_num].waker_list); + + rt_num++; + if (rt_num >= MAX_RT_NUM) + break; + } + } + + if (rt_num) { + if (!g_waker_mempool) { + g_waker_mempool = waker_mempool_create(); + if (!g_waker_mempool) { + rt_num = 0; + write_unlock_irqrestore(&rt_info_rwlock, flags); + return -ENOMEM; + } + } + waker_mempool_init(g_waker_mempool); + atomic_set(&need_stat_wake, 1); + } else { + if (g_waker_mempool) { + waker_mempool_destory(g_waker_mempool); + g_waker_mempool = NULL; + } + } + + if (rt_num) + rt_set_dstate_interested_threads(tids, rt_num); + + write_unlock_irqrestore(&rt_info_rwlock, flags); + + return count; +} + +static const struct file_operations rt_info_proc_ops = { + .open = rt_info_proc_open, + .write = rt_info_proc_write, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int rt_num_show(struct seq_file *m, void *v) +{ + unsigned long flags; + char page[256] = {0}; + int i, available = 0; + struct list_head *pos; + ssize_t len = 0; + + read_lock_irqsave(&rt_info_rwlock, flags); + + len += snprintf(page + len, sizeof(page) - len, "rt_num %d\n", rt_num); + for (i = 0; i < rt_num; i++) { + len += snprintf(page + len, sizeof(page) - len, "pid:%d tid:%d comm:%s\n", + render_thread_info[i].rt_task->tgid, render_thread_info[i].rt_task->pid, + render_thread_info[i].rt_task->comm); + } + if (rt_num) { + list_for_each(pos, g_mempool_list_ptr) + available++; + len += snprintf(page + len, sizeof(page) - len, + "waker_mempool total:%d available:%d\n", MAX_TID_COUNT, available); + } + + read_unlock_irqrestore(&rt_info_rwlock, flags); + + seq_puts(m, page); + + return 0; +} + +static int rt_num_proc_open(struct inode *inode, struct file *filp) +{ + return single_open(filp, rt_num_show, inode); +} + +static const struct file_operations rt_num_proc_ops = { + .open = rt_num_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +int rt_info_init() +{ + if (unlikely(!game_opt_dir)) + return -ENOTDIR; + + proc_create_data("render_thread_info", 0664, game_opt_dir, &rt_info_proc_ops, NULL); + proc_create_data("rt_num", 0444, game_opt_dir, &rt_num_proc_ops, NULL); + + return 0; +} diff --git a/drivers/soc/oplus/game_opt/task_util.c b/drivers/soc/oplus/game_opt/task_util.c new file mode 100644 index 000000000000..bc3e3d3d25dd --- /dev/null +++ b/drivers/soc/oplus/game_opt/task_util.c @@ -0,0 +1,419 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2022 Oplus. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "game_ctrl.h" + +struct task_runtime_info { + struct list_head node; + pid_t tid; + u64 sum_exec_scale; + u64 last_update_ts; +}; + +static LIST_HEAD(running_task_list); + +/* exclusive file ops */ +static DEFINE_MUTEX(g_mutex); +static DEFINE_RAW_SPINLOCK(g_lock); + +static atomic_t need_stat_runtime = ATOMIC_INIT(0); +static struct task_struct *game_leader = NULL; +static u64 window_start; + +static struct task_runtime_info *g_rinfo_mempool = NULL; +static struct list_head g_mempool_list; +static struct list_head *g_mempool_list_ptr = &g_mempool_list; + +static struct task_runtime_info *rinfo_mempool_create(void) +{ + struct task_runtime_info *rinfo_mempool = NULL; + + rinfo_mempool = kzalloc(sizeof(struct task_runtime_info) * MAX_TID_COUNT, GFP_ATOMIC); + + return rinfo_mempool; +} + +static void rinfo_mempool_init(struct task_runtime_info *rinfo_mempool) +{ + int i; + + if (likely(rinfo_mempool)) { + INIT_LIST_HEAD(g_mempool_list_ptr); + for (i = 0; i < MAX_TID_COUNT; i++) + list_add_tail(&rinfo_mempool[i].node, g_mempool_list_ptr); + } +} + +static struct task_runtime_info *rinfo_mempool_alloc_one(void) +{ + struct list_head *pos; + struct task_runtime_info *rinfo = NULL; + + if (!list_empty(g_mempool_list_ptr)) { + pos = g_mempool_list_ptr->next; + list_del(pos); + rinfo = list_entry(pos, struct task_runtime_info, node); + } + + return rinfo; +} + +static void rinfo_mempool_free_one(struct task_runtime_info *rinfo) +{ + if (likely(rinfo)) { + list_del(&rinfo->node); + list_add_tail(&rinfo->node, g_mempool_list_ptr); + } +} + +static void rinfo_mempool_destory(struct task_runtime_info *rinfo_mempool) +{ + if (likely(rinfo_mempool)) + kfree(rinfo_mempool); +} + +static ssize_t game_pid_proc_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) +{ + char page[32] = {0}; + int ret, pid; + struct task_struct *leader = NULL; + unsigned long flags; + + mutex_lock(&g_mutex); + + ret = simple_write_to_buffer(page, sizeof(page), ppos, buf, count); + if (ret <= 0) + goto munlock; + + ret = sscanf(page, "%d", &pid); + if (ret != 1) { + ret = -EINVAL; + goto munlock; + } + + atomic_set(&need_stat_runtime, 0); + + raw_spin_lock_irqsave(&g_lock, flags); + + /* release */ + if (pid <= 0) { + if (game_leader) { + put_task_struct(game_leader); + game_leader = NULL; + INIT_LIST_HEAD(&running_task_list); + rinfo_mempool_destory(g_rinfo_mempool); + g_rinfo_mempool = NULL; + } + ret = count; + goto rsunlock; + } + + /* acquire */ + rcu_read_lock(); + leader = find_task_by_vpid(pid); + if (!leader || leader->pid != leader->tgid) { /* must be process id */ + rcu_read_unlock(); + ret = -EINVAL; + goto rsunlock; + } else { + if (game_leader) + put_task_struct(game_leader); + game_leader = leader; + get_task_struct(game_leader); + rcu_read_unlock(); + } + + if (!g_rinfo_mempool) { + g_rinfo_mempool = rinfo_mempool_create(); + if (!g_rinfo_mempool) { + put_task_struct(game_leader); + game_leader = NULL; + ret = -ENOMEM; + goto rsunlock; + } + } + rinfo_mempool_init(g_rinfo_mempool); + + INIT_LIST_HEAD(&running_task_list); + window_start = ktime_get_ns(); + atomic_set(&need_stat_runtime, 1); + + ret = count; +rsunlock: + raw_spin_unlock_irqrestore(&g_lock, flags); +munlock: + mutex_unlock(&g_mutex); + return ret; +} + +static ssize_t game_pid_proc_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) +{ + char page[32] = {0}; + int len, ret, pid; + + mutex_lock(&g_mutex); + + if (game_leader) + pid = game_leader->pid; + else + pid = -1; + + len = sprintf(page, "%d\n", pid); + + ret = simple_read_from_buffer(buf, count, ppos, page, len); + + mutex_unlock(&g_mutex); + return ret; +} + +static const struct file_operations game_pid_proc_ops = { + .write = game_pid_proc_write, + .read = game_pid_proc_read, +}; + +/* + * Ascending order by util + */ +static int cmp_task_util(const void *a, const void *b) +{ + struct task_util_info *prev, *next; + + prev = (struct task_util_info *)a; + next = (struct task_util_info *)b; + if (unlikely(!prev || !next)) + return 0; + + return next->util - prev->util; +} + +static inline u16 cal_util(u64 sum_exec_scale, u64 window_size) +{ + u16 util; + + util = sum_exec_scale / (window_size >> 10); + if (util > 1024) + util = 1024; + + return util; +} + +static bool get_task_name(pid_t tid, char *name) { + struct task_struct * task = NULL; + bool ret = false; + + rcu_read_lock(); + task = find_task_by_vpid(tid); + if (task) { + strncpy(name, task->comm, TASK_COMM_LEN); + ret = true; + } + rcu_read_unlock(); + + return ret; +} + +static int heavy_task_info_show(struct seq_file *m, void *v) +{ + unsigned long flags; + struct task_util_info *results; + struct list_head *pos, *n; + struct task_runtime_info *rinfo; + int i, num = 0, ret = 0; + char page[1024] = {0}; + char task_name[TASK_COMM_LEN]; + ssize_t len = 0; + u64 now; + + mutex_lock(&g_mutex); + + if (!game_leader) { + ret = -ESRCH; + goto munlock; + } + + results = kmalloc(sizeof(struct task_util_info) * MAX_TID_COUNT, GFP_KERNEL); + if (!results) { + ret = -ENOMEM; + goto munlock; + } + + atomic_set(&need_stat_runtime, 0); + + raw_spin_lock_irqsave(&g_lock, flags); + now = ktime_get_ns(); + + list_for_each_safe(pos, n, &running_task_list) { + rinfo = list_entry(pos, struct task_runtime_info, node); + if (now - rinfo->last_update_ts < MAX_TASK_INACTIVE_TIME) { + results[num].tid = rinfo->tid; + results[num].util = cal_util(rinfo->sum_exec_scale, now - window_start); + rinfo->sum_exec_scale = 0; + num++; + } else { + rinfo_mempool_free_one(rinfo); + } + } + raw_spin_unlock_irqrestore(&g_lock, flags); + + sort(results, num, sizeof(struct task_util_info), &cmp_task_util, NULL); + num = min(num, MAX_TASK_NR); + for (i = 0; i < num; i++) { + if (results[i].util <= 0) + break; + if (get_task_name(results[i].tid, task_name)) { + len += snprintf(page + len, sizeof(page) - len, "%d;%s;%d\n", + results[i].tid, task_name, results[i].util); + } + } + if (len > 0) + seq_puts(m, page); + + kfree(results); + + now = ktime_get_ns(); + window_start = now; + atomic_set(&need_stat_runtime, 1); + +munlock: + mutex_unlock(&g_mutex); + return ret; +} + +static int heavy_task_info_proc_open(struct inode *inode, struct file *filp) +{ + return single_open(filp, heavy_task_info_show, inode); +} + +static const struct file_operations heavy_task_info_proc_ops = { + .open = heavy_task_info_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static inline unsigned int get_cur_freq(unsigned int cpu) +{ + struct cpufreq_policy *policy = cpufreq_cpu_get_raw(cpu); + + return (policy == NULL) ? 0 : policy->cur; +} + +static inline unsigned int get_max_freq(unsigned int cpu) +{ + struct cpufreq_policy *policy = cpufreq_cpu_get_raw(cpu); + + return (policy == NULL) ? 0 : policy->cpuinfo.max_freq; +} + +#define DIV64_U64_ROUNDUP(X, Y) div64_u64((X) + (Y - 1), Y) +static inline u64 scale_exec_time(u64 delta, struct rq *rq) +{ + u64 task_exec_scale; + unsigned int cur_freq, max_freq; + int cpu = cpu_of(rq); + + cur_freq = get_cur_freq(cpu); + max_freq = get_max_freq(cpu); + + if (unlikely(cur_freq <= 0) || unlikely(max_freq <= 0) || unlikely(cur_freq > max_freq)) + return delta; + + task_exec_scale = DIV64_U64_ROUNDUP(cur_freq * + arch_scale_cpu_capacity(NULL, cpu), + max_freq); + + return (delta * task_exec_scale) >> 10; +} + +void g_update_task_runtime(struct task_struct *task, u64 runtime) +{ + unsigned long flags; + u64 now, exec_scale; + struct list_head *pos; + struct task_runtime_info *rinfo; + struct task_runtime_info *new_rinfo; + struct rq *rq = task_rq(task); + + if (atomic_read(&need_stat_runtime) == 0) + return; + + raw_spin_lock_irqsave(&g_lock, flags); + + if (!game_leader || task->tgid != game_leader->tgid) + goto rsunlock; + + now = ktime_get_ns(); + exec_scale = scale_exec_time(runtime, rq); + + list_for_each(pos, &running_task_list) { + rinfo = list_entry(pos, struct task_runtime_info, node); + if (rinfo->tid == task->pid) { + rinfo->sum_exec_scale += exec_scale; + rinfo->last_update_ts = now; + goto rsunlock; + } + } + + new_rinfo = rinfo_mempool_alloc_one(); + if (new_rinfo) { + new_rinfo->tid = task->pid; + new_rinfo->sum_exec_scale = exec_scale; + new_rinfo->last_update_ts = now; + list_add_tail(&new_rinfo->node, &running_task_list); + } + +rsunlock: + raw_spin_unlock_irqrestore(&g_lock, flags); +} + +void g_rt_task_dead(struct task_struct *task) +{ + unsigned long flags; + struct list_head *pos, *n; + struct task_runtime_info *rinfo; + + if (atomic_read(&need_stat_runtime) == 0) + return; + + raw_spin_lock_irqsave(&g_lock, flags); + + if (!game_leader || task->tgid != game_leader->tgid) + goto rsunlock; + + list_for_each_safe(pos, n, &running_task_list) { + rinfo = list_entry(pos, struct task_runtime_info, node); + if (rinfo->tid == task->pid) { + rinfo_mempool_free_one(rinfo); + break; + } + } + +rsunlock: + raw_spin_unlock_irqrestore(&g_lock, flags); +} + +int task_util_init(void) +{ + if (unlikely(!game_opt_dir)) + return -ENOTDIR; + proc_create_data("game_pid", 0664, game_opt_dir, &game_pid_proc_ops, NULL); + proc_create_data("heavy_task_info", 0444, game_opt_dir, &heavy_task_info_proc_ops, NULL); + + return 0; +} diff --git a/drivers/soc/oplus/healthinfo b/drivers/soc/oplus/healthinfo new file mode 120000 index 000000000000..27a64445cdb5 --- /dev/null +++ b/drivers/soc/oplus/healthinfo @@ -0,0 +1 @@ +../../../../../vendor/oplus/kernel/oplus_performance/healthinfo/main/ \ No newline at end of file diff --git a/drivers/soc/oplus/im b/drivers/soc/oplus/im new file mode 120000 index 000000000000..ae8d6db02b55 --- /dev/null +++ b/drivers/soc/oplus/im @@ -0,0 +1 @@ +../../../../../vendor/oplus/kernel/oplus_performance/im \ No newline at end of file diff --git a/drivers/soc/oplus/iomonitor b/drivers/soc/oplus/iomonitor new file mode 120000 index 000000000000..bbbc2d7d3da8 --- /dev/null +++ b/drivers/soc/oplus/iomonitor @@ -0,0 +1 @@ +../../../../../vendor/oplus/kernel/oplus_performance/iomonitor \ No newline at end of file diff --git a/drivers/soc/oplus/lowmem_dbg b/drivers/soc/oplus/lowmem_dbg new file mode 120000 index 000000000000..4a5fc41f7247 --- /dev/null +++ b/drivers/soc/oplus/lowmem_dbg @@ -0,0 +1 @@ +../../../../../vendor/oplus/kernel/oplus_performance/lowmem_dbg/ \ No newline at end of file diff --git a/drivers/soc/oplus/midas b/drivers/soc/oplus/midas new file mode 120000 index 000000000000..8b57bbc45706 --- /dev/null +++ b/drivers/soc/oplus/midas @@ -0,0 +1 @@ +../../../../../vendor/oplus/kernel/power/midas \ No newline at end of file diff --git a/drivers/soc/oplus/misc b/drivers/soc/oplus/misc new file mode 120000 index 000000000000..1c949323c3ee --- /dev/null +++ b/drivers/soc/oplus/misc @@ -0,0 +1 @@ +../../../../../vendor/oplus/kernel/misc \ No newline at end of file diff --git a/drivers/soc/oplus/oplus_gpio/Makefile b/drivers/soc/oplus/oplus_gpio/Makefile new file mode 100644 index 000000000000..4db6727d0abc --- /dev/null +++ b/drivers/soc/oplus/oplus_gpio/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_OPLUS_GPIO_NC) += oplus_gpio.o diff --git a/drivers/soc/oplus/oplus_gpio/oplus_gpio.c b/drivers/soc/oplus/oplus_gpio/oplus_gpio.c new file mode 100644 index 000000000000..5246cbf28b93 --- /dev/null +++ b/drivers/soc/oplus/oplus_gpio/oplus_gpio.c @@ -0,0 +1,76 @@ +#include +#include +#include +#include +#include +#include + +#include + +#define TAG "oplus_gpio:" + +#define __OF_GPIO_MATCH(p) \ + struct of_device_id p[] = {\ + { .compatible = #p},\ + {},\ + } + +#define __OPLUS_PLATEFORM_DRIVER(p) \ + { .probe = oplus_gpio_probe, \ + .remove = oplus_gpio_remove \ + } + +#define __OPLUS_GPIO_DRIVER(p) \ + static struct platform_driver p = __OPLUS_PLATEFORM_DRIVER(p) + +#define OPLUS_GPIO_DRIVER(d) \ + __OF_GPIO_MATCH(oplus_##d);\ + __OPLUS_GPIO_DRIVER(d); + +#define GPIO_DO_DRIVER_INIT(d) \ + do {\ + d.driver.name = #d;\ + d.driver.of_match_table = oplus_##d;\ + } while(0) + +static int oplus_gpio_probe(struct platform_device *pdev) +{ + pr_info(TAG "oplus_gpio_probe call %d %s\n",get_PCB_Version(),pdev->name); + return 0; +} + +static int oplus_gpio_remove(struct platform_device *pdev) +{ + pr_info(TAG "oplus_gpio_remove call \n"); + return 0; +} + +OPLUS_GPIO_DRIVER(gpio_evt); +OPLUS_GPIO_DRIVER(gpio_dvt); +OPLUS_GPIO_DRIVER(gpio_pvt); + +static int __init oplus_gpio_init(void) +{ + pr_info(TAG "oplus_gpio_init call \n"); + + GPIO_DO_DRIVER_INIT(gpio_evt); + GPIO_DO_DRIVER_INIT(gpio_dvt); + GPIO_DO_DRIVER_INIT(gpio_pvt); + + if (get_PCB_Version() <= EVT6) { + platform_driver_register(&gpio_evt); + } + else if ((get_PCB_Version() > EVT6) && (get_PCB_Version() <= DVT6)) { + platform_driver_register(&gpio_dvt); + } + else { + platform_driver_register(&gpio_pvt); + } + + return 0; +} + +late_initcall_sync(oplus_gpio_init); +MODULE_DESCRIPTION("nc gpio config"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("mofei@oplus.com"); diff --git a/drivers/soc/oplus/oplus_nandswap b/drivers/soc/oplus/oplus_nandswap new file mode 120000 index 000000000000..a98e125c78e5 --- /dev/null +++ b/drivers/soc/oplus/oplus_nandswap @@ -0,0 +1 @@ +../../../../../vendor/oplus/kernel/oplus_performance/oplus_nandswap/ \ No newline at end of file diff --git a/drivers/soc/oplus/sensor b/drivers/soc/oplus/sensor new file mode 120000 index 000000000000..befdfa5ad34f --- /dev/null +++ b/drivers/soc/oplus/sensor @@ -0,0 +1 @@ +../../../../../vendor/oplus/sensor/kernel/qcom/sensor/ \ No newline at end of file diff --git a/drivers/soc/oplus/svelte b/drivers/soc/oplus/svelte new file mode 120000 index 000000000000..d1947ecc19d2 --- /dev/null +++ b/drivers/soc/oplus/svelte @@ -0,0 +1 @@ +../../../../../vendor/oplus/kernel/oplus_performance/memleak_detect/svelte \ No newline at end of file diff --git a/drivers/soc/oplus/system b/drivers/soc/oplus/system new file mode 120000 index 000000000000..ecdcb26c267f --- /dev/null +++ b/drivers/soc/oplus/system @@ -0,0 +1 @@ +../../../../../vendor/oplus/kernel/system/ \ No newline at end of file diff --git a/drivers/soc/oplus/thermal b/drivers/soc/oplus/thermal new file mode 120000 index 000000000000..8c669a034ec3 --- /dev/null +++ b/drivers/soc/oplus/thermal @@ -0,0 +1 @@ +../../../../../vendor/oplus/kernel/thermal/ \ No newline at end of file diff --git a/drivers/soc/oplus/tpd b/drivers/soc/oplus/tpd new file mode 120000 index 000000000000..0bee884b5811 --- /dev/null +++ b/drivers/soc/oplus/tpd @@ -0,0 +1 @@ +../../../../../vendor/oplus/kernel/oplus_performance/tpd \ No newline at end of file diff --git a/drivers/soc/oplus/tpp b/drivers/soc/oplus/tpp new file mode 120000 index 000000000000..5f862db32ccd --- /dev/null +++ b/drivers/soc/oplus/tpp @@ -0,0 +1 @@ +../../../../../vendor/oplus/kernel/oplus_performance/tpp \ No newline at end of file diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig index 19079745c6cc..938edf1c2e72 100644 --- a/drivers/soc/qcom/Kconfig +++ b/drivers/soc/qcom/Kconfig @@ -831,6 +831,14 @@ config QTI_RPM_STATS_LOG the low power modes that RPM enters. The drivers outputs the message via a sysfs node. +config RPMH_MODEM_SLEEPINFO_BUFFER + bool 'modem sleepinfo backup support' + default y + help + This option enables support for the function that make a buffer of + modem subsystem sleep info. + If unsure, say `N'. + config QTI_DDR_STATS_LOG tristate "Qualcomm Technologies Inc (QTI) DDR Stats Driver" depends on QCOM_RPMH diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile index 3fe90e5ab8e5..8d60872bef06 100644 --- a/drivers/soc/qcom/Makefile +++ b/drivers/soc/qcom/Makefile @@ -1,4 +1,8 @@ CFLAGS_rpmh-rsc.o := -I$(src) +ccflags-y += -I$(srctree)/include/drm -I$(srctree)/techpack/display/msm -I$(srctree)/techpack/display/msm/dsi -I$(srctree)/techpack/display/msm/dp +ccflags-y += -I$(srctree)/techpack/display/msm/sde +ccflags-y += -I$(srctree)/techpack/display/rotator +ccflags-y += -I$(srctree)/techpack/display/oplus obj-$(CONFIG_QCOM_COMMAND_DB) += cmd-db.o obj-$(CONFIG_QCOM_GLINK_SSR) += glink_ssr.o obj-$(CONFIG_QCOM_CPUSS_DUMP) += cpuss_dump.o @@ -64,7 +68,8 @@ ifdef CONFIG_MSM_SUBSYSTEM_RESTART endif obj-$(CONFIG_QCOM_EUD) += eud.o obj-$(CONFIG_SOC_BUS) += socinfo.o -obj-$(CONFIG_QCOM_WATCHDOG_V2) += watchdog_v2.o +#modify for oplus watchdog +obj-$(CONFIG_QCOM_WATCHDOG_V2) += watchdog_v2.o oplus_watchdog_util.o obj-$(CONFIG_QCOM_SDM845_LLCC) += llcc-sdm845.o CFLAGS_rpmh-rsc.o := -I$(src) obj-$(CONFIG_QCOM_BUS_SCALING) += msm_bus/ @@ -86,6 +91,9 @@ ifdef CONFIG_QCOM_RPMH else obj-$(CONFIG_QTI_RPM_STATS_LOG) += rpm_master_stat.o endif +#ifdef OPLUS_FEATURE_POWERINFO_RPMH +obj-$(CONFIG_RPMH_MODEM_SLEEPINFO_BUFFER) += rpmh_modem_sleepinfo.o +#endif /* OPLUS_FEATURE_POWERINFO_RPMH */ obj-$(CONFIG_QCOM_DCC) += dcc.o obj-$(CONFIG_QTI_RPM_STATS_LOG) += rpm_stats.o obj-$(CONFIG_QCOM_MEM_OFFLINE) += mem-offline.o @@ -110,3 +118,4 @@ obj-$(CONFIG_QTI_CRYPTO_TZ) += crypto-qti-tz.o obj-$(CONFIG_QTI_HW_KEY_MANAGER) += hwkm_qti.o hwkm_qti-y += hwkm.o obj-$(CONFIG_MSM_BAM_DMUX) += bam_dmux.o +obj-y += serial_num.o diff --git a/drivers/soc/qcom/crypto-qti-common.c b/drivers/soc/qcom/crypto-qti-common.c index 51a4a9beb10c..f70ec71ac449 100644 --- a/drivers/soc/qcom/crypto-qti-common.c +++ b/drivers/soc/qcom/crypto-qti-common.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2020, Linux Foundation. All rights reserved. + * Copyright (C) 2021 Oplus. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -410,8 +411,7 @@ int crypto_qti_keyslot_program(void *priv_data, err1 = crypto_qti_program_key(ice_entry, key, slot, data_unit_mask, capid); if (err1) { - pr_err("%s: program key failed with error %d\n", - __func__, err1); + pr_err("%s: program key failed with error %d\n", __func__, err1); err2 = crypto_qti_invalidate_key(ice_entry, slot); if (err2) { pr_err("%s: invalidate key failed with error %d\n", diff --git a/drivers/soc/qcom/fsa4480-i2c.c b/drivers/soc/qcom/fsa4480-i2c.c index 562509e3b018..62ac18b05242 100644 --- a/drivers/soc/qcom/fsa4480-i2c.c +++ b/drivers/soc/qcom/fsa4480-i2c.c @@ -9,11 +9,20 @@ #include #include #include +#include "dsi/dsi_display.h" + +#ifdef OPLUS_ARCH_EXTENDS +#include +#include +#endif /* OPLUS_ARCH_EXTENDS */ #define FSA4480_I2C_NAME "fsa4480-driver" #define FSA4480_SWITCH_SETTINGS 0x04 #define FSA4480_SWITCH_CONTROL 0x05 +#ifdef OPLUS_ARCH_EXTENDS +#define FSA4480_SWITCH_STATUS0 0x06 +#endif /* OPLUS_ARCH_EXTENDS */ #define FSA4480_SWITCH_STATUS1 0x07 #define FSA4480_SLOW_L 0x08 #define FSA4480_SLOW_R 0x09 @@ -24,8 +33,24 @@ #define FSA4480_DELAY_L_MIC 0x0E #define FSA4480_DELAY_L_SENSE 0x0F #define FSA4480_DELAY_L_AGND 0x10 +#ifdef OPLUS_ARCH_EXTENDS +#define FSA4480_FUN_EN 0x12 +#define FSA4480_JACK_STATUS 0x17 +#endif /* OPLUS_ARCH_EXTENDS */ #define FSA4480_RESET 0x1E +#ifdef OPLUS_BUG_STABILITY +/* + * 0x1~0xff == 100us~25500us + */ +#define DEFAULT_SWITCH_DELAY 0x12 +#endif /* OPLUS_BUG_STABILITY */ + +#ifdef OPLUS_ARCH_EXTENDS +#undef dev_dbg +#define dev_dbg dev_info +#endif /* OPLUS_ARCH_EXTENDS */ + struct fsa4480_priv { struct regmap *regmap; struct device *dev; @@ -35,6 +60,9 @@ struct fsa4480_priv { struct work_struct usbc_analog_work; struct blocking_notifier_head fsa4480_notifier; struct mutex notification_lock; + #ifdef OPLUS_ARCH_EXTENDS + unsigned int hs_det_pin; + #endif /* OPLUS_ARCH_EXTENDS */ }; struct fsa4480_reg_val { @@ -49,13 +77,20 @@ static const struct regmap_config fsa4480_regmap_config = { }; static const struct fsa4480_reg_val fsa_reg_i2c_defaults[] = { + #ifdef OPLUS_BUG_STABILITY + {FSA4480_SWITCH_CONTROL, 0x18}, + #endif /* OPLUS_BUG_STABILITY */ {FSA4480_SLOW_L, 0x00}, {FSA4480_SLOW_R, 0x00}, {FSA4480_SLOW_MIC, 0x00}, {FSA4480_SLOW_SENSE, 0x00}, {FSA4480_SLOW_GND, 0x00}, {FSA4480_DELAY_L_R, 0x00}, +#ifdef OPLUS_BUG_STABILITY + {FSA4480_DELAY_L_MIC, DEFAULT_SWITCH_DELAY}, +#else {FSA4480_DELAY_L_MIC, 0x00}, +#endif /* OPLUS_BUG_STABILITY */ {FSA4480_DELAY_L_SENSE, 0x00}, {FSA4480_DELAY_L_AGND, 0x09}, {FSA4480_SWITCH_SETTINGS, 0x98}, @@ -74,6 +109,9 @@ static void fsa4480_usbc_update_settings(struct fsa4480_priv *fsa_priv, /* FSA4480 chip hardware requirement */ usleep_range(50, 55); regmap_write(fsa_priv->regmap, FSA4480_SWITCH_SETTINGS, switch_enable); +#ifdef OPLUS_BUG_STABILITY + usleep_range(DEFAULT_SWITCH_DELAY*100, DEFAULT_SWITCH_DELAY*100+50); +#endif /* OPLUS_BUG_STABILITY */ } static int fsa4480_usbc_event_changed(struct notifier_block *nb, @@ -131,6 +169,10 @@ static int fsa4480_usbc_analog_setup_switches(struct fsa4480_priv *fsa_priv) int rc = 0; union power_supply_propval mode; struct device *dev; + #ifdef OPLUS_ARCH_EXTENDS + unsigned int switch_status = 0; + unsigned int jack_status = 0; + #endif /* OPLUS_ARCH_EXTENDS */ if (!fsa_priv) return -EINVAL; @@ -150,17 +192,53 @@ static int fsa4480_usbc_analog_setup_switches(struct fsa4480_priv *fsa_priv) dev_dbg(dev, "%s: setting GPIOs active = %d\n", __func__, mode.intval != POWER_SUPPLY_TYPEC_NONE); + #ifdef OPLUS_ARCH_EXTENDS + dev_info(dev, "%s: USB mode %d\n", __func__, mode.intval); + #endif /* OPLUS_ARCH_EXTENDS */ + switch (mode.intval) { /* add all modes FSA should notify for in here */ case POWER_SUPPLY_TYPEC_SINK_AUDIO_ADAPTER: /* activate switches */ fsa4480_usbc_update_settings(fsa_priv, 0x00, 0x9F); + #ifdef OPLUS_ARCH_EXTENDS + usleep_range(1000, 1005); + regmap_write(fsa_priv->regmap, FSA4480_FUN_EN, 0x45); + usleep_range(4000, 4005); + dev_info(dev, "%s: set reg[0x%x] done.\n", __func__, FSA4480_FUN_EN); + + regmap_read(fsa_priv->regmap, FSA4480_JACK_STATUS, &jack_status); + dev_info(dev, "%s: reg[0x%x]=0x%x.\n", __func__, FSA4480_JACK_STATUS, jack_status); + if (jack_status & 0x2) { + //for 3 pole, mic switch to SBU2 + dev_info(dev, "%s: set mic to sbu2 for 3 pole.\n", __func__); + fsa4480_usbc_update_settings(fsa_priv, 0x00, 0x9F); + usleep_range(4000, 4005); + } + + regmap_read(fsa_priv->regmap, FSA4480_SWITCH_STATUS0, &switch_status); + dev_info(dev, "%s: reg[0x%x]=0x%x.\n", __func__, FSA4480_SWITCH_STATUS0, switch_status); + regmap_read(fsa_priv->regmap, FSA4480_SWITCH_STATUS1, &switch_status); + dev_info(dev, "%s: reg[0x%x]=0x%x.\n", __func__, FSA4480_SWITCH_STATUS1, switch_status); + #endif /* OPLUS_ARCH_EXTENDS */ /* notify call chain on event */ blocking_notifier_call_chain(&fsa_priv->fsa4480_notifier, mode.intval, NULL); + #ifdef OPLUS_ARCH_EXTENDS + if (gpio_is_valid(fsa_priv->hs_det_pin)) { + dev_info(dev, "%s: set hs_det_pin to low.\n", __func__); + gpio_direction_output(fsa_priv->hs_det_pin, 0); + } + #endif /* OPLUS_ARCH_EXTENDS */ break; case POWER_SUPPLY_TYPEC_NONE: + #ifdef OPLUS_ARCH_EXTENDS + if (gpio_is_valid(fsa_priv->hs_det_pin)) { + dev_info(dev, "%s: set hs_det_pin to high.\n", __func__); + gpio_direction_output(fsa_priv->hs_det_pin, 1); + } + #endif /* OPLUS_ARCH_EXTENDS */ /* notify call chain on event */ blocking_notifier_call_chain(&fsa_priv->fsa4480_notifier, POWER_SUPPLY_TYPEC_NONE, NULL); @@ -192,6 +270,9 @@ int fsa4480_reg_notifier(struct notifier_block *nb, int rc = 0; struct i2c_client *client = of_find_i2c_device_by_node(node); struct fsa4480_priv *fsa_priv; + #ifdef OPLUS_ARCH_EXTENDS + union power_supply_propval mode; + #endif /* OPLUS_ARCH_EXTENDS */ if (!client) return -EINVAL; @@ -205,6 +286,20 @@ int fsa4480_reg_notifier(struct notifier_block *nb, if (rc) return rc; + #ifdef OPLUS_ARCH_EXTENDS + rc = power_supply_get_property(fsa_priv->usb_psy, + POWER_SUPPLY_PROP_TYPEC_MODE, &mode); + if (rc) { + dev_err(fsa_priv->dev, "%s: Unable to read USB TYPEC_MODE: %d\n", + __func__, rc); + } else if ((mode.intval == POWER_SUPPLY_TYPEC_SINK_AUDIO_ADAPTER) + || (mode.intval == POWER_SUPPLY_TYPEC_NONE)) { + dev_info(fsa_priv->dev, "%s: initial state: supply mode %d, usbc mode %d\n", + __func__, mode.intval, fsa_priv->usbc_mode.counter); + atomic_set(&(fsa_priv->usbc_mode), mode.intval); + } + #endif /* OPLUS_ARCH_EXTENDS */ + /* * as part of the init sequence check if there is a connected * USB C analog adapter @@ -292,6 +387,12 @@ int fsa4480_switch_event(struct device_node *node, int switch_control = 0; struct i2c_client *client = of_find_i2c_device_by_node(node); struct fsa4480_priv *fsa_priv; + #ifdef OPLUS_ARCH_EXTENDS + unsigned int setting_reg_val = 0, control_reg_val = 0; + #endif /* OPLUS_ARCH_EXTENDS */ + struct dsi_display *display = get_main_display(); + struct dsi_parser_utils *utils = &display->panel->utils; + bool oplus_dp_support = utils->read_bool(utils->data, "oplus,dp-support-customized"); if (!client) return -EINVAL; @@ -302,8 +403,22 @@ int fsa4480_switch_event(struct device_node *node, if (!fsa_priv->regmap) return -EINVAL; + #ifdef OPLUS_ARCH_EXTENDS + pr_info("%s - switch event: %d\n", __func__, event); + #endif /* OPLUS_ARCH_EXTENDS */ + switch (event) { case FSA_MIC_GND_SWAP: + #ifdef OPLUS_ARCH_EXTENDS + if (fsa_priv->usbc_mode.counter != POWER_SUPPLY_TYPEC_SINK_AUDIO_ADAPTER) { + regmap_read(fsa_priv->regmap, FSA4480_SWITCH_SETTINGS, &setting_reg_val); + regmap_read(fsa_priv->regmap, FSA4480_SWITCH_CONTROL, &control_reg_val); + pr_err("%s: error mode, reg[0x%x]=0x%x, reg[0x%x]=0x%x\n", __func__, + FSA4480_SWITCH_SETTINGS, setting_reg_val, FSA4480_SWITCH_CONTROL, control_reg_val); + break; + } + #endif /* OPLUS_ARCH_EXTENDS */ + regmap_read(fsa_priv->regmap, FSA4480_SWITCH_CONTROL, &switch_control); if ((switch_control & 0x07) == 0x07) @@ -311,12 +426,31 @@ int fsa4480_switch_event(struct device_node *node, else switch_control = 0x7; fsa4480_usbc_update_settings(fsa_priv, switch_control, 0x9F); + #ifdef OPLUS_ARCH_EXTENDS + pr_err("fsa4480 fsa_mic_gnd_swap.\n"); + #endif /* OPLUS_ARCH_EXTENDS */ break; case FSA_USBC_ORIENTATION_CC1: + #ifndef OPLUS_ARCH_EXTENDS fsa4480_usbc_update_settings(fsa_priv, 0x18, 0xF8); + #else + if (oplus_dp_support) { + fsa4480_usbc_update_settings(fsa_priv, 0x18, 0xF8); + } else { + fsa4480_usbc_update_settings(fsa_priv, 0x78, 0xF8); + } + #endif /* OPLUS_ARCH_EXTENDS */ return fsa4480_validate_display_port_settings(fsa_priv); case FSA_USBC_ORIENTATION_CC2: + #ifndef OPLUS_ARCH_EXTENDS fsa4480_usbc_update_settings(fsa_priv, 0x78, 0xF8); + #else + if (oplus_dp_support) { + fsa4480_usbc_update_settings(fsa_priv, 0x78, 0xF8); + } else { + fsa4480_usbc_update_settings(fsa_priv, 0x18, 0xF8); + } + #endif /* OPLUS_ARCH_EXTENDS */ return fsa4480_validate_display_port_settings(fsa_priv); case FSA_USBC_DISPLAYPORT_DISCONNECTED: fsa4480_usbc_update_settings(fsa_priv, 0x18, 0x98); @@ -329,6 +463,39 @@ int fsa4480_switch_event(struct device_node *node, } EXPORT_SYMBOL(fsa4480_switch_event); +#ifdef OPLUS_ARCH_EXTENDS +static int fsa4480_parse_dt(struct fsa4480_priv *fsa_priv, + struct device *dev) +{ + struct device_node *dNode = dev->of_node; + int ret = 0; + + if (dNode == NULL) + return -ENODEV; + + if (!fsa_priv) { + pr_err("%s: fsa_priv is NULL\n", __func__); + return -ENOMEM; + } + + fsa_priv->hs_det_pin = of_get_named_gpio(dNode, + "fsa4480,hs-det-gpio", 0); + if (!gpio_is_valid(fsa_priv->hs_det_pin)) { + pr_warning("%s: hs-det-gpio in dt node is missing\n", __func__); + return -ENODEV; + } + ret = gpio_request(fsa_priv->hs_det_pin, "fsa4480_hs_det"); + if (ret) { + pr_warning("%s: hs-det-gpio request fail\n", __func__); + return ret; + } + + gpio_direction_output(fsa_priv->hs_det_pin, 1); + + return ret; +} +#endif /* OPLUS_ARCH_EXTENDS */ + static void fsa4480_usbc_analog_work_fn(struct work_struct *work) { struct fsa4480_priv *fsa_priv = @@ -356,7 +523,9 @@ static int fsa4480_probe(struct i2c_client *i2c, { struct fsa4480_priv *fsa_priv; int rc = 0; - + #ifdef OPLUS_ARCH_EXTENDS + pr_err("%s enter fsa4480_probe\n", __func__); + #endif /* OPLUS_ARCH_EXTENDS */ fsa_priv = devm_kzalloc(&i2c->dev, sizeof(*fsa_priv), GFP_KERNEL); if (!fsa_priv) @@ -364,6 +533,10 @@ static int fsa4480_probe(struct i2c_client *i2c, fsa_priv->dev = &i2c->dev; + #ifdef OPLUS_ARCH_EXTENDS + fsa4480_parse_dt(fsa_priv, &i2c->dev); + #endif /* OPLUS_ARCH_EXTENDS */ + fsa_priv->usb_psy = power_supply_get_by_name("usb"); if (!fsa_priv->usb_psy) { rc = -EPROBE_DEFER; @@ -409,6 +582,11 @@ static int fsa4480_probe(struct i2c_client *i2c, err_supply: power_supply_put(fsa_priv->usb_psy); err_data: + #ifdef OPLUS_ARCH_EXTENDS + if (gpio_is_valid(fsa_priv->hs_det_pin)) { + gpio_free(fsa_priv->hs_det_pin); + } + #endif /* OPLUS_ARCH_EXTENDS */ devm_kfree(&i2c->dev, fsa_priv); return rc; } @@ -428,6 +606,12 @@ static int fsa4480_remove(struct i2c_client *i2c) power_supply_unreg_notifier(&fsa_priv->psy_nb); power_supply_put(fsa_priv->usb_psy); mutex_destroy(&fsa_priv->notification_lock); + #ifdef OPLUS_ARCH_EXTENDS + if (gpio_is_valid(fsa_priv->hs_det_pin)) { + gpio_free(fsa_priv->hs_det_pin); + } + devm_kfree(&i2c->dev, fsa_priv); + #endif /* OPLUS_ARCH_EXTENDS */ dev_set_drvdata(&i2c->dev, NULL); return 0; diff --git a/drivers/soc/qcom/minidump_log.c b/drivers/soc/qcom/minidump_log.c index 1f9da04132a8..6f3bf1bfd4ab 100644 --- a/drivers/soc/qcom/minidump_log.c +++ b/drivers/soc/qcom/minidump_log.c @@ -18,6 +18,9 @@ #include #include #include +#ifdef CONFIG_OPLUS_FEATURE_QCOM_MINIDUMP_ENHANCE +#include +#endif static bool is_vmap_stack __read_mostly; @@ -365,6 +368,9 @@ static int __init msm_minidump_log_init(void) register_current_stack(); #endif register_log_buf(); +#ifdef CONFIG_OPLUS_FEATURE_QCOM_MINIDUMP_ENHANCE + register_cpu_contex(); +#endif /* CONFIG_OPLUS_FEATURE_QCOM_MINIDUMP_ENHANCE */ return 0; } subsys_initcall(msm_minidump_log_init); diff --git a/drivers/soc/qcom/msm_minidump.c b/drivers/soc/qcom/msm_minidump.c index a2de6fc57d71..71c8785141cf 100644 --- a/drivers/soc/qcom/msm_minidump.c +++ b/drivers/soc/qcom/msm_minidump.c @@ -551,7 +551,7 @@ static int __init msm_minidump_init(void) minidump_table.revision = md_global_toc->md_revision; md_ss_toc = &md_global_toc->md_ss_toc[MD_SS_HLOS_ID]; - md_ss_toc->encryption_status = MD_SS_ENCR_NONE; + md_ss_toc->encryption_status = MD_SS_ENCR_DONE; md_ss_toc->encryption_required = MD_SS_ENCR_REQ; minidump_table.md_ss_toc = md_ss_toc; diff --git a/drivers/soc/qcom/oplus_watchdog_util.c b/drivers/soc/qcom/oplus_watchdog_util.c new file mode 100644 index 000000000000..824e420b0ed5 --- /dev/null +++ b/drivers/soc/qcom/oplus_watchdog_util.c @@ -0,0 +1,249 @@ +/********************************************************************************** +* Copyright (c) 2008-2016 Oplus., All rights reserved. +* Description: Provide some utils for watchdog to enhance log and action after wdt +* Version : 1.0 +***********************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include "oplus_watchdog_util.h" + +#define MASK_SIZE 32 +#define MAX_IRQ_NO 1200 + +extern struct task_struct *oplus_get_cpu_task(int cpu); +extern int oplus_get_work_cpu(struct work_struct *work); +extern int cpu_idle_pc_state[NR_CPUS]; + +unsigned int smp_call_any_cpu; +unsigned long smp_call_many_cpumask; +int recovery_tried; +static oplus_print_utc_cnt = 0; + +static const char *recoverable_procs[] = {"SearchDaemon", "libsu.so", "NotificationObs"}; + +struct oplus_irq_counter { + unsigned int all_irqs_last; + unsigned int all_irqs_delta; + unsigned int *irqs_last; + unsigned int *irqs_delta; +}; + +static struct oplus_irq_counter o_irq_counter; +static int irqno_sort[10]; + +int init_oplus_watchlog(void) +{ + if (!o_irq_counter.irqs_last) { + o_irq_counter.irqs_last = (unsigned int *)kzalloc( + sizeof(unsigned int)*MAX_IRQ_NO, + GFP_KERNEL); + if (!o_irq_counter.irqs_last) { + return -ENOMEM; + } + } + + if (!o_irq_counter.irqs_delta) { + o_irq_counter.irqs_delta = (unsigned int *)kzalloc( + sizeof(unsigned int)*MAX_IRQ_NO, + GFP_KERNEL); + if (!o_irq_counter.irqs_delta) { + kfree(o_irq_counter.irqs_last); + return -ENOMEM; + } + } + + return 0; +} + +/* replace android trigger utc time show, using watchdog print + * petwatchdog 9s, 4 times print once + */ +void oplus_show_utc_time(void) +{ + struct timespec ts; + struct rtc_time tm; + if(oplus_print_utc_cnt > 2) + oplus_print_utc_cnt = 0; + else { + oplus_print_utc_cnt ++; + return; + } + getnstimeofday(&ts); + rtc_time_to_tm(ts.tv_sec, &tm); + pr_warn("!@WatchDog: %d-%02d-%02d %02d:%02d:%02d.%09lu UTC\n", + tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, + tm.tm_hour, tm.tm_min, tm.tm_sec, ts.tv_nsec); +} +EXPORT_SYMBOL(oplus_show_utc_time); + +static void update_irq_counter(void) +{ + int n; + struct irq_desc *desc; + unsigned int all_count = 0; + unsigned int irq_count = 0; + + BUG_ON(nr_irqs > MAX_IRQ_NO); + + if (!o_irq_counter.irqs_delta || !o_irq_counter.irqs_last) + return; + + for_each_irq_desc(n, desc) { + irq_count = kstat_irqs(n); + if (!desc->action && !irq_count) + continue; + + if (irq_count <= o_irq_counter.irqs_last[n]) + o_irq_counter.irqs_delta[n] = 0; + else + o_irq_counter.irqs_delta[n] = irq_count - o_irq_counter.irqs_last[n]; + + o_irq_counter.irqs_last[n] = irq_count; + all_count += irq_count; + } + o_irq_counter.all_irqs_delta = all_count - o_irq_counter.all_irqs_last; + o_irq_counter.all_irqs_last = all_count; +} + +static void insert_irqno(int no, int i, int size) +{ + int n; + for (n = size-1; n > i; n--) { + irqno_sort[n] = irqno_sort[n-1]; + } + irqno_sort[i] = no; +} + +static void sort_irqs_delta(void) +{ + int irq, i; + + for (i = 0; i < 10; i++) { + irqno_sort[i] = -1; + } + + for_each_irq_nr(irq) { + for (i = 0; i < 10; i++) { + if (irqno_sort[i] == -1) { + irqno_sort[i] = irq; + break; + } + + if (o_irq_counter.irqs_delta[irq] > o_irq_counter.irqs_delta[irqno_sort[i]]) { + insert_irqno(irq, i, 10); + break; + } + } + } +} + +static void print_top10_irqs(void) +{ + sort_irqs_delta(); + printk(KERN_INFO "Top10 irqs since last: %d:%u; %d:%u; %d:%u; %d:%u; %d:%u; %d:%u; %d:%u; %d:%u; %d:%u; %d:%u; Total: %u\n", + irqno_sort[0], o_irq_counter.irqs_delta[irqno_sort[0]], irqno_sort[1], o_irq_counter.irqs_delta[irqno_sort[1]], + irqno_sort[2], o_irq_counter.irqs_delta[irqno_sort[2]], irqno_sort[3], o_irq_counter.irqs_delta[irqno_sort[3]], + irqno_sort[4], o_irq_counter.irqs_delta[irqno_sort[4]], irqno_sort[5], o_irq_counter.irqs_delta[irqno_sort[5]], + irqno_sort[6], o_irq_counter.irqs_delta[irqno_sort[6]], irqno_sort[7], o_irq_counter.irqs_delta[irqno_sort[7]], + irqno_sort[8], o_irq_counter.irqs_delta[irqno_sort[8]], irqno_sort[9], o_irq_counter.irqs_delta[irqno_sort[9]], o_irq_counter.all_irqs_delta); +} + +void dump_cpu_online_mask() +{ + static char alive_mask_buf[MASK_SIZE]; + struct cpumask avail_mask; + cpumask_andnot(&avail_mask, cpu_online_mask, cpu_isolated_mask); + scnprintf(alive_mask_buf, MASK_SIZE, "%*pb1", cpumask_pr_args(&avail_mask)); + printk(KERN_INFO "cpu avail mask %s\n", alive_mask_buf); +} + +void get_cpu_ping_mask(cpumask_t *pmask) +{ + int cpu; + struct cpumask avail_mask; + update_irq_counter(); + cpumask_copy(pmask, cpu_online_mask); + cpumask_andnot(&avail_mask, cpu_online_mask, cpu_isolated_mask); + + for_each_cpu(cpu, cpu_online_mask) { + if (cpu_idle_pc_state[cpu] || cpu_isolated(cpu)) + cpumask_clear_cpu(cpu, pmask); + } + printk(KERN_INFO "[wdog_util]cpu avail mask: 0x%lx; ping mask: 0x%lx; irqs since last: %u\n", + *cpumask_bits(&avail_mask), *cpumask_bits(pmask), o_irq_counter.all_irqs_delta); +} + +void print_smp_call_cpu() +{ + printk(KERN_INFO "cpu of last smp_call_function_any: %d\n", + smp_call_any_cpu); + printk(KERN_INFO "cpumask of last smp_call_function_many: 0x%lx\n", + smp_call_many_cpumask); +} + +void dump_wdog_cpu(struct task_struct *w_task) +{ + int work_cpu = 0; + int wdog_busy = 0; + struct pt_regs *regs = get_irq_regs(); + + update_irq_counter(); + print_top10_irqs(); + work_cpu = task_cpu(w_task); + wdog_busy = task_curr(w_task); + if (wdog_busy) + printk(KERN_EMERG "Watchdog work is running at CPU(%d)\n", work_cpu); + else + printk(KERN_EMERG "Watchdog work is pending at CPU(%d)\n", work_cpu); + + if (regs) + show_regs(regs); +} + +static int match_recoverable_procs(char *comm) +{ + const char *p; + int count = sizeof(recoverable_procs)/sizeof(char *); + int i = 0; + while(i < count) { + p = recoverable_procs[i]; + if(!strncmp(comm, p, TASK_COMM_LEN)) + return 1; + i++; + } + return 0; +} + +int try_to_recover_pending(struct task_struct *w_task) +{ + int work_cpu = 0; + struct task_struct *p; + + if (recovery_tried) + return 0; + + if (task_curr(w_task)) + return 0; + + work_cpu = task_cpu(w_task); + p = oplus_get_cpu_task(work_cpu); + if (match_recoverable_procs(p->comm)) { + printk(KERN_EMERG "[wdog_util]Try to kill [%s] to recover WDT\n", p->comm); + do_send_sig_info(SIGKILL, SEND_SIG_FORCED, p, true); + wake_up_process(p); + recovery_tried = 1; + return 1; + } + return 0; +} + +void reset_recovery_tried() +{ + recovery_tried = 0; +} diff --git a/drivers/soc/qcom/oplus_watchdog_util.h b/drivers/soc/qcom/oplus_watchdog_util.h new file mode 100644 index 000000000000..eb8492a712c4 --- /dev/null +++ b/drivers/soc/qcom/oplus_watchdog_util.h @@ -0,0 +1,21 @@ +/********************************************************************************** +* Copyright (c) 2008-2016 Oplus ., All rights reserved. +* Description: Provide some utils for watchdog to enhance log and action after wdt +* Version : 1.0 +***********************************************************************************/ + +#ifndef _OPLUS_WATCHDOG_UTIL_H_ +#define _OPLUS_WATCHDOG_UTIL_H_ + +#include +#include + +extern void dump_cpu_online_mask(void); +extern void get_cpu_ping_mask(cpumask_t *pmask); +extern void print_smp_call_cpu(void); +extern void dump_wdog_cpu(struct task_struct *w_task); +extern int try_to_recover_pending(struct task_struct *w_task); +extern void reset_recovery_tried(void); +int init_oplus_watchlog(void); + +#endif /*_OPLUS_WATCHDOG_UTIL_H_*/ diff --git a/drivers/soc/qcom/peripheral-loader.c b/drivers/soc/qcom/peripheral-loader.c index 9a3c53721a42..0741cfb20ed2 100644 --- a/drivers/soc/qcom/peripheral-loader.c +++ b/drivers/soc/qcom/peripheral-loader.c @@ -413,6 +413,10 @@ setup_fail: return ret; } +#ifdef OPLUS_FEATURE_SSR +#define CAUSENAME_SIZE 128 +#endif /*OPLUS_FEATURE_SSR*/ + /** * print_aux_minidump_tocs() - Print the ToC for an auxiliary minidump entry * @desc: PIL descriptor for the subsystem for which minidump is collected @@ -440,6 +444,35 @@ static void print_aux_minidump_tocs(struct pil_desc *desc) } } +#ifdef OPLUS_FEATURE_SSR +void __adsp_send_uevent(struct device *dev, char *reason) +{ + int ret_val; + char adsp_event[] = "ADSP_EVENT=adsp_crash"; + char adsp_reason[300] = {0}; + char *envp[3]; + + envp[0] = (char *)&adsp_event; + if(reason){ + snprintf(adsp_reason, sizeof(adsp_reason),"ADSP_REASON=%s", reason); + }else{ + snprintf(adsp_reason, sizeof(adsp_reason),"ADSP_REASON=unkown"); + } + adsp_reason[299] = 0; + envp[1] = (char *)&adsp_reason; + envp[2] = 0; + + if(dev){ + ret_val = kobject_uevent_env(&(dev->kobj), KOBJ_CHANGE, envp); + if(!ret_val){ + pr_info("adsp_crash:kobject_uevent_env success!\n"); + }else{ + pr_info("adsp_crash:kobject_uevent_env fail,error=%d!\n", ret_val); + } + } +} +#endif /*OPLUS_FEATURE_SSR*/ + /** * pil_do_ramdump() - Ramdump an image * @desc: descriptor from pil_desc_init() @@ -456,16 +489,29 @@ int pil_do_ramdump(struct pil_desc *desc, struct pil_seg *seg; int count = 0, ret; +#ifdef OPLUS_FEATURE_SSR + unsigned char payload[100] = ""; +#endif /*OPLUS_FEATURE_SSR*/ + if (desc->minidump_ss) { - pr_debug("Minidump : md_ss_toc->md_ss_toc_init is 0x%x\n", +#ifdef OPLUS_FEATURE_MODEM_MINIDUMP + //Add for customized subsystem ramdump to skip generate dump cause by SAU + if (SKIP_GENERATE_RAMDUMP) { + pil_err(desc, "%s: Skip ramdump cuase by ap normal trigger.\n %s", + __func__, desc->name); + SKIP_GENERATE_RAMDUMP = false; + return -1; + } +#endif + pr_info("Minidump : md_ss_toc->md_ss_toc_init is 0x%x\n", (unsigned int)desc->minidump_ss->md_ss_toc_init); - pr_debug("Minidump : md_ss_toc->md_ss_enable_status is 0x%x\n", + pr_info("Minidump : md_ss_toc->md_ss_enable_status is 0x%x\n", (unsigned int)desc->minidump_ss->md_ss_enable_status); - pr_debug("Minidump : md_ss_toc->encryption_status is 0x%x\n", + pr_info("Minidump : md_ss_toc->encryption_status is 0x%x\n", (unsigned int)desc->minidump_ss->encryption_status); - pr_debug("Minidump : md_ss_toc->ss_region_count is 0x%x\n", + pr_info("Minidump : md_ss_toc->ss_region_count is 0x%x\n", (unsigned int)desc->minidump_ss->ss_region_count); - pr_debug("Minidump : md_ss_toc->md_ss_smem_regions_baseptr is 0x%x\n", + pr_info("Minidump : md_ss_toc->md_ss_smem_regions_baseptr is 0x%x\n", (unsigned int) desc->minidump_ss->md_ss_smem_regions_baseptr); @@ -479,12 +525,19 @@ int pil_do_ramdump(struct pil_desc *desc, (desc->minidump_ss->md_ss_toc_init == true) && (desc->minidump_ss->md_ss_enable_status == MD_SS_ENABLED)) { + #ifndef OPLUS_FEATURE_MODEM_MINIDUMP + //Add for skip mini dump encryption if (desc->minidump_ss->encryption_status == MD_SS_ENCR_DONE) { - pr_debug("Dumping Minidump for %s\n", + pr_info("Dumping Minidump for %s\n", desc->name); return pil_do_minidump(desc, minidump_dev); } + #else + pr_debug("Minidump : Dumping for %s\n", + desc->name); + return pil_do_minidump(desc, minidump_dev); + #endif pr_debug("Minidump aborted for %s\n", desc->name); return -EINVAL; } @@ -515,6 +568,15 @@ int pil_do_ramdump(struct pil_desc *desc, pil_err(desc, "%s: Ramdump collection failed for subsys %s rc:%d\n", __func__, desc->name, ret); +#ifdef OPLUS_FEATURE_SSR + if(strlen(desc->name) > 0 && (strncmp(desc->name,"adsp",strlen(desc->name)) == 0)) { + scnprintf(payload, sizeof(payload), "payload@@%s", desc->name); + if(desc->dev){ + __adsp_send_uevent(desc->dev, payload); + } + } +#endif /* OPLUS_FEATURE_SSR */ + if (desc->subsys_vmid > 0) ret = pil_assign_mem_to_subsys(desc, priv->region_start, (priv->region_end - priv->region_start)); diff --git a/drivers/soc/qcom/qcom_ipcc.c b/drivers/soc/qcom/qcom_ipcc.c index 663375676ba0..5a210ece4fa5 100644 --- a/drivers/soc/qcom/qcom_ipcc.c +++ b/drivers/soc/qcom/qcom_ipcc.c @@ -12,6 +12,9 @@ #include #include +#ifdef OPLUS_FEATURE_POWERINFO_STANDBY +#include +#endif /* OPLUS_FEATURE_POWERINFO_STANDBY */ /* IPCC Register offsets */ #define IPCC_REG_SEND_ID 0x0C #define IPCC_REG_RECV_ID 0x10 @@ -25,7 +28,7 @@ #define IPCC_CLIENT_ID_SHIFT 16 #define IPCC_NO_PENDING_IRQ (~(u32)0) - +int is_first_ipcc_msg = 0; /** * struct ipcc_protocol_data - Per-protocol data * @irq_domain: irq_domain associated with this protocol-id @@ -334,6 +337,27 @@ static void msm_ipcc_resume(void) name = desc->action->name; pr_warn("%s: %d triggered %s\n", __func__, virq, name); + + #ifdef OPLUS_FEATURE_POWERINFO_STANDBY + do { + int platform_id = get_cached_platform_id(); + if (platform_id == KONA) { + wakeup_reasons_statics(IRQ_NAME_GLINK, WS_CNT_GLINK); + wakeup_reasons_statics(name, WS_CNT_WLAN|WS_CNT_ADSP|WS_CNT_CDSP|WS_CNT_SLPI); + } else if (platform_id == LITO) { + if (!strcmp(name, IRQ_NAME_MODEM_GLINK)) { + wakeup_reasons_statics(IRQ_NAME_MODEM_QMI, WS_CNT_MODEM); + } + } else if (platform_id == LAGOON) { + if (is_first_ipcc_msg == 1) { + do { + wakeup_reasons_statics(name, WS_CNT_MODEM|WS_CNT_WLAN|WS_CNT_ADSP|WS_CNT_CDSP|WS_CNT_SLPI); + } while(0); + is_first_ipcc_msg = 0; + } + } + } while(0); + #endif /* OPLUS_FEATURE_POWERINFO_STANDBY */ } #else #define msm_ipcc_suspend NULL diff --git a/drivers/soc/qcom/qdss_bridge.c b/drivers/soc/qcom/qdss_bridge.c index 7cb6fcb55d95..a4d8d238570a 100644 --- a/drivers/soc/qcom/qdss_bridge.c +++ b/drivers/soc/qcom/qdss_bridge.c @@ -713,10 +713,10 @@ static ssize_t mhi_uci_read(struct file *file, pr_err("Failed to recycle element, ret: %d\n", ret); qdss_del_buf_tbl_entry(drvdata, uci_buf->buf); uci_buf->buf = NULL; - kfree(uci_buf); + kfree(uci_buf); return ret; } - kfree(uci_buf); + kfree(uci_buf); } pr_debug("Returning %lu bytes\n", to_copy); @@ -922,11 +922,18 @@ static int qdss_mhi_probe(struct mhi_device *mhi_dev, return ret; } + drvdata->cdev = cdev_alloc(); + if (!drvdata->cdev) { + ret = -ENOMEM; + return ret; + } + ret = alloc_chrdev_region(&dev, baseminor, count, "mhi_qdss"); if (ret < 0) { pr_err("alloc_chrdev_region failed %d\n", ret); return ret; } + //cdev_init(&drvdata->cdev, &mhidev_fops); drvdata->cdev->owner = THIS_MODULE; drvdata->cdev->ops = &mhidev_fops; diff --git a/drivers/soc/qcom/rpm_stats.c b/drivers/soc/qcom/rpm_stats.c index 079ec84890fc..946ee8321ca6 100644 --- a/drivers/soc/qcom/rpm_stats.c +++ b/drivers/soc/qcom/rpm_stats.c @@ -19,6 +19,14 @@ #define RPM_STATS_NUM_REC 2 #define MSM_ARCH_TIMER_FREQ 19200000 +#ifdef OPLUS_FEATURE_POWERINFO_RPMH +void __iomem *rpm_phys_addr = NULL; +#endif /* OPLUS_FEATURE_POWERINFO_RPMH */ + +#ifdef OPLUS_FEATURE_POWERINFO_RPMH +static u32 num_records_backup = 0; +#endif + #define GET_PDATA_OF_ATTR(attr) \ (container_of(attr, struct msm_rpmstats_kobj_attr, ka)->pd) @@ -68,7 +76,7 @@ static inline u64 get_time_in_sec(u64 counter) return counter; } - +#ifndef OPLUS_FEATURE_POWERINFO_RPMH static inline u64 get_time_in_msec(u64 counter) { do_div(counter, MSM_ARCH_TIMER_FREQ); @@ -76,6 +84,13 @@ static inline u64 get_time_in_msec(u64 counter) return counter; } +#else +static inline u64 get_time_in_msec(u64 counter) +{ + do_div(counter, (MSM_ARCH_TIMER_FREQ/MSEC_PER_SEC)); + return counter; +} +#endif /* OPLUS_FEATURE_POWERINFO_RPMH */ static inline int msm_rpmstats_append_data_to_buf(char *buf, struct msm_rpm_stats_data *data, int buflength) @@ -111,6 +126,25 @@ static inline int msm_rpmstats_append_data_to_buf(char *buf, #endif } +#ifdef OPLUS_FEATURE_POWERINFO_RPMH +static inline int oplus_rpmstats_append_data_to_buf(char *buf, + struct msm_rpm_stats_data *data, int buflength,int i) +{ + u64 actual_last_sleep; + + actual_last_sleep = get_time_in_msec(data->accumulated); + if(i == 0) { + return snprintf(buf, buflength, + "vlow:%x:%llx\n", + data->count, actual_last_sleep); + } else { + return snprintf(buf, buflength, + "vmin:%x:%llx\r\n", + data->count, actual_last_sleep); + } +} +#endif /* OPLUS_FEATURE_POWERINFO_RPMH */ + static inline u32 msm_rpmstats_read_long_register(void __iomem *regbase, int index, int offset) { @@ -167,6 +201,64 @@ static inline int msm_rpmstats_copy_stats( return length; } +#ifdef OPLUS_FEATURE_POWERINFO_RPMH +static inline int oplus_rpmstats_copy_stats( + struct msm_rpmstats_private_data *prvdata) +{ + void __iomem *reg; + struct msm_rpm_stats_data data; + int i, length; + + reg = prvdata->reg_base; + + for (i = 0, length = 0; i < prvdata->num_records; i++) { + data.count = msm_rpmstats_read_long_register(reg, i, + offsetof(struct msm_rpm_stats_data, count)); + data.accumulated = msm_rpmstats_read_quad_register(reg, + i, offsetof(struct msm_rpm_stats_data, + accumulated)); + + length += oplus_rpmstats_append_data_to_buf(prvdata->buf + length, + &data, sizeof(prvdata->buf) - length,i); + prvdata->read_idx++; + } + + return length; +} +#endif /* OPLUS_FEATURE_POWERINFO_RPMH */ + + +#ifdef OPLUS_FEATURE_POWERINFO_RPMH +int get_rpmh_deep_sleep_info(u64 *aosd, u64 *cxsd) +{ + u64 accumulated_aosd = 0; + u64 accumulated_cxsd = 0; + + if(rpm_phys_addr == NULL) { + pr_info("%s %d : rpm_phys_addr is null\n", __func__, __LINE__); + return -1; + } + if(num_records_backup < 2) { + pr_info("%s %d : num_records_backup is %d, force return\n", __func__, __LINE__, num_records_backup); + return -1; + } + + accumulated_aosd = msm_rpmstats_read_quad_register(rpm_phys_addr, + 0, offsetof(struct msm_rpm_stats_data,//0:aosd + accumulated)); + + accumulated_cxsd = msm_rpmstats_read_quad_register(rpm_phys_addr, + 1, offsetof(struct msm_rpm_stats_data,//1:cxsd + accumulated)); + + *aosd = get_time_in_msec(accumulated_aosd); + *cxsd = get_time_in_msec(accumulated_cxsd); + pr_info("%s %d : aosd=%llumS, cxsd=%llumS\n", __func__, __LINE__, *aosd, *cxsd); + return 0; +} +EXPORT_SYMBOL(get_rpmh_deep_sleep_info); +#endif + static ssize_t rpmstats_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { @@ -195,6 +287,32 @@ static ssize_t rpmstats_show(struct kobject *kobj, iounmap(prvdata.reg_base); return length; } +#ifdef OPLUS_FEATURE_POWERINFO_RPMH +static ssize_t oplus_rpmstats_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + struct msm_rpmstats_private_data prvdata; + struct msm_rpmstats_platform_data *pdata = NULL; + + if (rpm_phys_addr == NULL) + { + return 0; + } + pdata = GET_PDATA_OF_ATTR(attr); + prvdata.reg_base =rpm_phys_addr; + + + prvdata.read_idx = prvdata.len = 0; + prvdata.platform_data = pdata; + prvdata.num_records = RPM_STATS_NUM_REC; + + if (prvdata.read_idx < prvdata.num_records) + prvdata.len = oplus_rpmstats_copy_stats(&prvdata); + + return snprintf(buf, prvdata.len, "%s", prvdata.buf); +} + +#endif /* OPLUS_FEATURE_POWERINFO_RPMH */ static int msm_rpmstats_create_sysfs(struct platform_device *pdev, struct msm_rpmstats_platform_data *pd) @@ -202,6 +320,9 @@ static int msm_rpmstats_create_sysfs(struct platform_device *pdev, struct kobject *rpmstats_kobj = NULL; struct msm_rpmstats_kobj_attr *rpms_ka = NULL; int ret = 0; +#ifdef OPLUS_FEATURE_POWERINFO_RPMH + struct msm_rpmstats_kobj_attr *oplus_rpms_ka = NULL; +#endif /* OPLUS_FEATURE_POWERINFO_RPMH */ rpmstats_kobj = kobject_create_and_add("system_sleep", power_kobj); if (!rpmstats_kobj) { @@ -228,6 +349,23 @@ static int msm_rpmstats_create_sysfs(struct platform_device *pdev, ret = sysfs_create_file(rpmstats_kobj, &rpms_ka->ka.attr); platform_set_drvdata(pdev, rpms_ka); +#ifdef OPLUS_FEATURE_POWERINFO_RPMH + oplus_rpms_ka = kzalloc(sizeof(*oplus_rpms_ka), GFP_KERNEL); + if (!oplus_rpms_ka) { + kobject_put(rpmstats_kobj); + ret = -ENOMEM; + goto fail; + } + + sysfs_attr_init(&oplus_rpms_ka->ka.attr); + oplus_rpms_ka->pd = pd; + oplus_rpms_ka->ka.attr.mode = 0444; + oplus_rpms_ka->ka.attr.name = "oplus_rpmh_stats"; + oplus_rpms_ka->ka.show = oplus_rpmstats_show; + oplus_rpms_ka->ka.store = NULL; + + ret = sysfs_create_file(rpmstats_kobj, &oplus_rpms_ka->ka.attr); +#endif /* OPLUS_FEATURE_POWERINFO_RPMH */ fail: return ret; @@ -272,6 +410,21 @@ static int msm_rpmstats_probe(struct platform_device *pdev) msm_rpmstats_create_sysfs(pdev, pdata); + +#ifdef OPLUS_FEATURE_POWERINFO_RPMH + num_records_backup = pdata->num_records; +#endif + +#ifdef OPLUS_FEATURE_POWERINFO_RPMH + rpm_phys_addr= ioremap_nocache(pdata->phys_addr_base, + pdata->phys_size); + if (!rpm_phys_addr) { + pr_err("%s: ERROR could not ioremap start=%pa, len=%u\n", + __func__, &pdata->phys_addr_base, + pdata->phys_size); + return -ENODEV; + } +#endif /* OPLUS_FEATURE_POWERINFO_RPMH */ return 0; } diff --git a/drivers/soc/qcom/rpmh-rsc.c b/drivers/soc/qcom/rpmh-rsc.c index daffd30d37e2..8a5f6754cba7 100644 --- a/drivers/soc/qcom/rpmh-rsc.c +++ b/drivers/soc/qcom/rpmh-rsc.c @@ -462,7 +462,7 @@ int rpmh_rsc_send_data(struct rsc_drv *drv, const struct tcs_request *msg) do { ret = tcs_write(drv, msg); if (ret == -EBUSY) { - pr_info_ratelimited("DRV:%s TCS Busy, retrying RPMH message send: addr=%#x\n", + pr_devel_ratelimited("DRV:%s TCS Busy, retrying RPMH message send: addr=%#x\n", drv->name, msg->cmds[0].addr); udelay(10); } diff --git a/drivers/soc/qcom/rpmh_master_stat.c b/drivers/soc/qcom/rpmh_master_stat.c index d4418baaa1ab..bafdd021298b 100644 --- a/drivers/soc/qcom/rpmh_master_stat.c +++ b/drivers/soc/qcom/rpmh_master_stat.c @@ -88,6 +88,10 @@ struct msm_rpmh_profile_unit { struct rpmh_master_stats_prv_data { struct kobj_attribute ka; struct kobject *kobj; +#ifdef OPLUS_FEATURE_POWERINFO_RPMH + struct kobj_attribute opluska; + struct kobject *opluskobj; +#endif /* OPLUS_FEATURE_POWERINFO_RPMH */ }; static struct msm_rpmh_master_stats apss_master_stats; @@ -95,6 +99,38 @@ static void __iomem *rpmh_unit_base; static DEFINE_MUTEX(rpmh_stats_mutex); +#ifdef OPLUS_FEATURE_POWERINFO_RPMH +static DEFINE_MUTEX(oplus_rpmh_stats_mutex); + +#define MSM_ARCH_TIMER_FREQ 19200000 +static inline u64 get_time_in_msec(u64 counter) +{ + do_div(counter, (MSM_ARCH_TIMER_FREQ/MSEC_PER_SEC)); + return counter; +} +static ssize_t oplus_rpmh_master_stats_print_data(char *prvbuf, ssize_t length, + struct msm_rpmh_master_stats *record, + const char *name) +{ + uint64_t accumulated_duration = record->accumulated_duration; + /* + * If a master is in sleep when reading the sleep stats from SMEM + * adjust the accumulated sleep duration to show actual sleep time. + * This ensures that the displayed stats are real when used for + * the purpose of computing battery utilization. + */ + if (record->last_entered > record->last_exited) + accumulated_duration += + (arch_counter_get_cntvct() + - record->last_entered); + + return snprintf(prvbuf, length, "%s:%x:%llx\n", + name,record->counts, + get_time_in_msec(accumulated_duration)); +} +#endif /* OPLUS_FEATURE_POWERINFO_RPMH */ + + static ssize_t msm_rpmh_master_stats_print_data(char *prvbuf, ssize_t length, struct msm_rpmh_master_stats *record, const char *name) @@ -110,7 +146,7 @@ static ssize_t msm_rpmh_master_stats_print_data(char *prvbuf, ssize_t length, accumulated_duration += (arch_counter_get_cntvct() - record->last_entered); - +#ifndef OPLUS_FEATURE_POWERINFO_RPMH return scnprintf(prvbuf, length, "%s\n\tVersion:0x%x\n" "\tSleep Count:0x%x\n" "\tSleep Last Entered At:0x%llx\n" @@ -119,6 +155,18 @@ static ssize_t msm_rpmh_master_stats_print_data(char *prvbuf, ssize_t length, name, record->version_id, record->counts, record->last_entered, record->last_exited, accumulated_duration); +#else + return snprintf(prvbuf, length, "%s\n\tVersion:0x%x\n" + "\tSleep Count:0x%x\n" + "\tSleep Last Entered At:0x%llx\n" + "\tSleep Last Exited At:0x%llx\n" + "\tSleep Accumulated Duration:0x%llx\n" + "\tSleep Accumulated Duration(mS):0x%llx\n" + "\tSleep Accumulated Duration(mS):%llu\n\n", + name, record->version_id, record->counts, + record->last_entered, record->last_exited, + accumulated_duration, get_time_in_msec(accumulated_duration), get_time_in_msec(accumulated_duration)); +#endif /* OPLUS_FEATURE_POWERINFO_RPMH */ } static ssize_t msm_rpmh_master_stats_show(struct kobject *kobj, @@ -153,6 +201,97 @@ static ssize_t msm_rpmh_master_stats_show(struct kobject *kobj, return length; } +#ifdef OPLUS_FEATURE_POWERINFO_RPMH +static ssize_t oplus_rpmh_master_stats_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + ssize_t length = 0; + int i = 0; + size_t size = 0; + struct msm_rpmh_master_stats *record = NULL; + + mutex_lock(&oplus_rpmh_stats_mutex); + + /* First Read APSS master stats */ + + length = oplus_rpmh_master_stats_print_data(buf, PAGE_SIZE, + &apss_master_stats, "APSS"); + + /* + * Read SMEM data written by masters + */ + + + + for (i = 0; i < ARRAY_SIZE(rpmh_masters); i++) { + record = (struct msm_rpmh_master_stats *) qcom_smem_get( + rpmh_masters[i].pid, + rpmh_masters[i].smem_id, &size); + if (!IS_ERR_OR_NULL(record) && (PAGE_SIZE - length > 0)) + length += oplus_rpmh_master_stats_print_data( + buf + length, PAGE_SIZE - length, + record, + rpmh_masters[i].master_name); + } + + mutex_unlock(&oplus_rpmh_stats_mutex); + + return length; +} +#endif /* OPLUS_FEATURE_POWERINFO_RPMH */ + + + +#ifdef OPLUS_FEATURE_POWERINFO_RPMH +u64 oplus_rpmh_master_get_sleeptime(struct msm_rpmh_master_stats *record) +{ + uint64_t accumulated_duration = record->accumulated_duration; + /* + * If a master is in sleep when reading the sleep stats from SMEM + * adjust the accumulated sleep duration to show actual sleep time. + * This ensures that the displayed stats are real when used for + * the purpose of computing battery utilization. + */ + if (record->last_entered > record->last_exited) + accumulated_duration += + (arch_counter_get_cntvct() + - record->last_entered); + + return get_time_in_msec(accumulated_duration); +} +EXPORT_SYMBOL(oplus_rpmh_master_get_sleeptime); +int oplus_subsystem_sleeptime(char *name, u64 *sleeptime) +{ + int i = 0, found = 0; + size_t size = 0; + struct msm_rpmh_master_stats *record = NULL; + + if((name == NULL) || (sleeptime == NULL)) + return 0; + + mutex_lock(&oplus_rpmh_stats_mutex); + for (i = 0; i < ARRAY_SIZE(rpmh_masters); i++) { + if(strncmp(rpmh_masters[i].master_name, name, strlen(name)) != 0){ + continue; + } + record = (struct msm_rpmh_master_stats *) qcom_smem_get(rpmh_masters[i].pid, rpmh_masters[i].smem_id, &size); + if (!IS_ERR_OR_NULL(record)) { + pr_info("%s : %s:0x%x\n", __func__, rpmh_masters[i].master_name, record->counts); + pr_info("%s found: %s:0x%x\n", __func__, rpmh_masters[i].master_name, record->counts); + found = 1; + *sleeptime = oplus_rpmh_master_get_sleeptime(record); + goto finish; + } + } +finish: + mutex_unlock(&oplus_rpmh_stats_mutex); + return found; +} +EXPORT_SYMBOL(oplus_subsystem_sleeptime); +#endif + + + static inline void msm_rpmh_apss_master_stats_update( struct msm_rpmh_profile_unit *profile_unit) { @@ -225,6 +364,22 @@ static int msm_rpmh_master_stats_probe(struct platform_device *pdev) goto fail_sysfs; } +#ifdef OPLUS_FEATURE_POWERINFO_RPMH + prvdata->opluskobj = rpmh_master_stats_kobj; + + sysfs_attr_init(&prvdata->opluska.attr); + prvdata->opluska.attr.mode = 0444; + prvdata->opluska.attr.name = "oplus_rpmh_master_stats"; + prvdata->opluska.show = oplus_rpmh_master_stats_show; + prvdata->opluska.store = NULL; + + ret = sysfs_create_file(prvdata->opluskobj, &prvdata->opluska.attr); + if (ret) { + pr_err("sysfs_create_file oplus failed\n"); + goto fail_sysfs_oplus; + } +#endif /* OPLUS_FEATURE_POWERINFO_RPMH */ + rpmh_unit_base = of_iomap(pdev->dev.of_node, 0); if (!rpmh_unit_base) { pr_err("Failed to get rpmh_unit_base\n"); @@ -237,6 +392,10 @@ static int msm_rpmh_master_stats_probe(struct platform_device *pdev) return ret; fail_iomap: +#ifdef OPLUS_FEATURE_POWERINFO_RPMH + sysfs_remove_file(prvdata->opluskobj, &prvdata->opluska.attr); +fail_sysfs_oplus: +#endif /* OPLUS_FEATURE_POWERINFO_RPMH */ sysfs_remove_file(prvdata->kobj, &prvdata->ka.attr); fail_sysfs: kobject_put(prvdata->kobj); @@ -249,7 +408,9 @@ static int msm_rpmh_master_stats_remove(struct platform_device *pdev) prvdata = (struct rpmh_master_stats_prv_data *) platform_get_drvdata(pdev); - +#ifdef OPLUS_FEATURE_POWERINFO_RPMH + sysfs_remove_file(prvdata->opluskobj, &prvdata->opluska.attr); +#endif /* OPLUS_FEATURE_POWERINFO_RPMH */ sysfs_remove_file(prvdata->kobj, &prvdata->ka.attr); kobject_put(prvdata->kobj); platform_set_drvdata(pdev, NULL); diff --git a/drivers/soc/qcom/rpmh_modem_sleepinfo.c b/drivers/soc/qcom/rpmh_modem_sleepinfo.c new file mode 100644 index 000000000000..aded32d9a1b8 --- /dev/null +++ b/drivers/soc/qcom/rpmh_modem_sleepinfo.c @@ -0,0 +1,168 @@ +/*********************************************************** +** Copyright (C), 2008-2019, OPLUS Mobile Comm Corp., Ltd. +** OPLUS_FEATURE_POWERINFO_RPMH +** File: - rpmh_modem_sleepinfo.c +** Description: Add a proc node to support the function that make +** a buffer of modem subsystem sleep info +** +** Version: 1.0 +** Date : 2019/12/31 +** +** ------------------ Revision History:------------------------ +** +** zengyunqing 2019/12/31 1.0 build this module +****************************************************************/ + +#include +#include +#include +#include +#include +#include +#include + +#define MODEM_SLEEPINFO_BUFFER_SIZE (1024*100) +#define MODEM_SLEEPINFO_BUFFER_RESERVED (10) +struct modem_sleepinfo_buffer_desc { + bool enabled; + char *buf_base; + unsigned int buf_size; + unsigned int wr_offset; + struct mutex buf_mlock; +}; + +static struct modem_sleepinfo_buffer_desc modeminfo_stats; +static struct proc_dir_entry *basic_procdir; + +static struct proc_dir_entry *modem_sleepinfo_node; +static unsigned int proc_modemsleep_perms = S_IRUGO; + +int rpmh_modem_sleepinfo_buffer_clear(void) +{ + pr_info("%s: wr_offset restart\n", __func__); + mutex_lock(&modeminfo_stats.buf_mlock); + modeminfo_stats.wr_offset = 0; + snprintf(modeminfo_stats.buf_base, modeminfo_stats.buf_size, "restart state\n"); + mutex_unlock(&modeminfo_stats.buf_mlock); + return 0; +} +EXPORT_SYMBOL(rpmh_modem_sleepinfo_buffer_clear); + +static int inner_rpmh_modem_sleepinfo_buffer_clear(void) +{ + pr_info("%s: wr_offset restart\n", __func__); + modeminfo_stats.wr_offset = 0; + snprintf(modeminfo_stats.buf_base, modeminfo_stats.buf_size, "restart state\n"); + return 0; +} + +static int modem_sleepinfo_proc_show(struct seq_file *m, void *v) +{ + mutex_lock(&modeminfo_stats.buf_mlock); + if(modeminfo_stats.enabled) { + seq_printf(m, "%s", modeminfo_stats.buf_base); + } else { + seq_printf(m, "%s", "init buffer error\n"); + } + mutex_unlock(&modeminfo_stats.buf_mlock); + return 0; +} + +static char restart_string[] = "OPLUS_MARK_RESTART"; +static char command_string_user[sizeof(restart_string)]; +static ssize_t modem_sleepinfo_proc_write(struct file *file, + const char __user *buffer, size_t count, loff_t *ppos) +{ + signed int cp_count = 0, cmd_real_len = 0; + signed long ret_count = 0, real_write = 0; + + mutex_lock(&modeminfo_stats.buf_mlock); + if(count == sizeof(restart_string)) { + memset(command_string_user, 0, sizeof(command_string_user)); + cmd_real_len = sizeof(command_string_user) < count ? sizeof(command_string_user) : count ; + if(!copy_from_user(command_string_user, buffer, cmd_real_len)) { + if(!memcmp(restart_string, command_string_user, cmd_real_len - 1)) { + inner_rpmh_modem_sleepinfo_buffer_clear(); + mutex_unlock(&modeminfo_stats.buf_mlock); + return count; + } + } else { + pr_info("%s: warning line%d\n", __func__, __LINE__); + } + } + + cp_count = count < modeminfo_stats.buf_size - modeminfo_stats.wr_offset ? count : modeminfo_stats.buf_size - modeminfo_stats.wr_offset; + if(cp_count < 0) + cp_count = 0; + + ret_count = copy_from_user(&modeminfo_stats.buf_base[modeminfo_stats.wr_offset], buffer, cp_count); + if(ret_count >= 0) { + real_write = cp_count - ret_count; + } + + modeminfo_stats.wr_offset += real_write; + if(modeminfo_stats.wr_offset > modeminfo_stats.buf_size) { + modeminfo_stats.wr_offset = modeminfo_stats.buf_size; + } + + modeminfo_stats.buf_base[modeminfo_stats.wr_offset] = '\0'; + mutex_unlock(&modeminfo_stats.buf_mlock); + return count; +} + +static int modem_sleepinfo_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, modem_sleepinfo_proc_show, PDE_DATA(inode)); +} + + +static const struct file_operations modem_sleepinfo_proc_fops = { + .open = modem_sleepinfo_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .write = modem_sleepinfo_proc_write, +}; + + +static int __init rpmh_modem_sleepinfo_init(void) +{ + mutex_init(&modeminfo_stats.buf_mlock); + + basic_procdir = proc_mkdir("rpmh_modem", NULL); + if(!basic_procdir) { + pr_err("%s: failed to new basic_procdir\n", __func__); + goto basic_procdir_null; + } + + modeminfo_stats.buf_base = (char*)kzalloc(MODEM_SLEEPINFO_BUFFER_SIZE, GFP_KERNEL); + if(!modeminfo_stats.buf_base) { + pr_err("%s: malloc buffer failed\n", __func__); + goto modeminfo_stats_buf_base_error; + } else { + modeminfo_stats.buf_size = MODEM_SLEEPINFO_BUFFER_SIZE - MODEM_SLEEPINFO_BUFFER_RESERVED; + snprintf(modeminfo_stats.buf_base, modeminfo_stats.buf_size, "init_state\n"); + modeminfo_stats.wr_offset = 0; + modeminfo_stats.enabled = true; + } + + modem_sleepinfo_node = proc_create_data("sleepinfo", proc_modemsleep_perms, + basic_procdir, &modem_sleepinfo_proc_fops, NULL); + if (!modem_sleepinfo_node) { + pr_err("%s: failed to create rpmh_modem/sleepinfo file\n", __func__); + goto modem_sleepinfo_node_error; + } + + return 0; + +modem_sleepinfo_node_error: + kfree(modeminfo_stats.buf_base); + +modeminfo_stats_buf_base_error: + +basic_procdir_null: + + return 0; +} + +late_initcall(rpmh_modem_sleepinfo_init); diff --git a/drivers/soc/qcom/serial_num.c b/drivers/soc/qcom/serial_num.c new file mode 100644 index 000000000000..8261fb28601f --- /dev/null +++ b/drivers/soc/qcom/serial_num.c @@ -0,0 +1,123 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define sn_readl(drvdata, off) __raw_readl(drvdata->base + off) + +#define SERIAL_NUM (0x000) + +static uint32_t sn = 0; + +struct sn_drvdata { + void __iomem *base; + struct device *dev; +}; + +static struct sn_drvdata *sndrvdata; + +static int sn_read(struct seq_file *m, void *v) +{ + struct sn_drvdata *drvdata = sndrvdata; + + if (!drvdata) + return false; + + if (sn == 0) + sn = sn_readl(drvdata, SERIAL_NUM); + + dev_dbg(drvdata->dev, "serial num: %x\n", sn); + + seq_printf(m, "0x%x\n", sn); + + return 0; + +} + +static int sn_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, sn_read, NULL); +} + +static const struct file_operations sn_fops = { + .open = sn_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static void sn_create_proc(void) +{ + struct proc_dir_entry *entry; + entry = proc_create("serial_num", 0 /* default mode */, + NULL /* parent dir */, &sn_fops); +} + +static int sn_fuse_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct sn_drvdata *drvdata; + struct resource *res; + + drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL); + if (!drvdata) + return -ENOMEM; + /* Store the driver data pointer for use in exported functions */ + sndrvdata = drvdata; + drvdata->dev = &pdev->dev; + platform_set_drvdata(pdev, drvdata); + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "sec_boot_base"); + if (!res) + return -ENODEV; + + drvdata->base = devm_ioremap(dev, res->start, resource_size(res)); + if (!drvdata->base) + return -ENOMEM; + + sn_create_proc(); + dev_info(dev, "SN interface initialized\n"); + return 0; +} + +static int sn_fuse_remove(struct platform_device *pdev) +{ + return 0; +} + +static struct of_device_id sn_fuse_match[] = { + {.compatible = "qcom,sec-boot-fuse"}, + {} +}; + +static struct platform_driver sn_fuse_driver = { + .probe = sn_fuse_probe, + .remove = sn_fuse_remove, + .driver = { + .name = "msm-sn-fuse", + .owner = THIS_MODULE, + .of_match_table = sn_fuse_match, + }, +}; + +static int __init sn_fuse_init(void) +{ + return platform_driver_register(&sn_fuse_driver); +} +arch_initcall(sn_fuse_init); + +static void __exit sn_fuse_exit(void) +{ + platform_driver_unregister(&sn_fuse_driver); +} +module_exit(sn_fuse_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("JTag Fuse driver"); diff --git a/drivers/soc/qcom/smem.c b/drivers/soc/qcom/smem.c index ee005e1a8552..dfb8b41b0b19 100644 --- a/drivers/soc/qcom/smem.c +++ b/drivers/soc/qcom/smem.c @@ -13,6 +13,13 @@ #include #include +#ifdef OPLUS_FEATURE_AGINGTEST +#include +#include + +#define SMEM_DUMP_INFO 129 +#endif /*OPLUS_FEATURE_AGINGTEST*/ + /* * The Qualcomm shared memory system is a allocate only heap structure that * consists of one of more memory areas that can be accessed by the processors @@ -777,6 +784,69 @@ phys_addr_t qcom_smem_virt_to_phys(void *p) } EXPORT_SYMBOL(qcom_smem_virt_to_phys); +#ifdef OPLUS_FEATURE_AGINGTEST +static char caller_function_name[KSYM_SYMBOL_LEN]; +char *parse_function_builtin_return_address(unsigned long function_address) +{ + char *cur = caller_function_name; + + if (!function_address) + return NULL; + + sprint_symbol(caller_function_name, function_address); + strsep(&cur, "+"); + + return caller_function_name; +} +EXPORT_SYMBOL(parse_function_builtin_return_address); + +void save_dump_reason_to_smem(char *reason, char *function_name) +{ + int reason_len = 0, name_len = 0; + int ret; + size_t size; + static int flag = 0; + struct dump_info *dp_info; + + if (flag) + return; + + size = sizeof(struct dump_info); + ret = qcom_smem_alloc(QCOM_SMEM_HOST_ANY, SMEM_DUMP_INFO, size); + if (ret < 0 && ret != -EEXIST) { + pr_err("%s:unable to allocate dp_info \n", __func__); + return; + } + + dp_info = qcom_smem_get(QCOM_SMEM_HOST_ANY, SMEM_DUMP_INFO, &size); + if (IS_ERR_OR_NULL(dp_info)) + pr_err("%s: get dp_info failure\n", __func__); + else { + if (reason != NULL) { + pr_err("%s: info : %s\n",__func__, reason); + reason_len = strlen(reason); + reason_len = (reason_len < DUMP_REASON_SIZE)? reason_len:DUMP_REASON_SIZE; + if (((strlen(dp_info->dump_reason) + reason_len) < DUMP_REASON_SIZE)) { + strcat(dp_info->dump_reason, reason); + } + } + if (function_name != NULL) { + name_len = strlen(function_name); + name_len = (name_len < DUMP_REASON_SIZE)? name_len:DUMP_REASON_SIZE; + if (((strlen(dp_info->dump_reason) + name_len + 1) < DUMP_REASON_SIZE)) { + strcat(dp_info->dump_reason, ":"); + strcat(dp_info->dump_reason, function_name); + } + } + } + pr_err("\r%s: dump_reason : %s reason_len=%d function caused panic :%s name_len=%d \n", __func__, + (reason != NULL)?reason:"unknown", reason_len, (function_name != NULL)?function_name:"unknown", name_len); + /* Make sure save_dump_reason_to_smem() is called only once during subsystem crash */ + flag++; +} +EXPORT_SYMBOL(save_dump_reason_to_smem); +#endif /*OPLUS_FEATURE_AGINGTEST*/ + static int qcom_smem_get_sbl_version(struct qcom_smem *smem) { struct smem_header *header; diff --git a/drivers/soc/qcom/socinfo.c b/drivers/soc/qcom/socinfo.c index 4c5619593a6f..67777edceada 100644 --- a/drivers/soc/qcom/socinfo.c +++ b/drivers/soc/qcom/socinfo.c @@ -23,6 +23,8 @@ #include #include +#include + #define BUILD_ID_LENGTH 32 #define CHIP_ID_LENGTH 32 #define SMEM_IMAGE_VERSION_BLOCKS_COUNT 32 @@ -230,6 +232,18 @@ static union { /* max socinfo format version supported */ #define MAX_SOCINFO_FORMAT SOCINFO_VERSION(0, 15) +#ifdef OPLUS_ARCH_EXTENDS +static char *fake_cpu_id = "SM8150"; +#ifdef CONFIG_ARCH_LITO +static char *real_cpu_id = "SDM765G 5G"; +#else +static char *real_cpu_id = "SM8250"; +#endif /*CONFIG_ARCH_LITO*/ +static char *real_cpu_id_20161_models = "SM8250_AC"; +static char *real_cpu_id_20057_20058 = "SDM750G"; +static char *real_cpu_id_20669_20750_20751 = "SDM750G"; +#endif /*OPLUS_ARCH_EXTENDS*/ + static struct msm_soc_info cpu_of_id[] = { [0] = {MSM_CPU_UNKNOWN, "Unknown CPU"}, /* 8960 IDs */ @@ -329,8 +343,11 @@ static struct msm_soc_info cpu_of_id[] = { [548] = {MSM_CPU_KONA_IOT, "KONA-7230-IOT"}, /* Lito ID */ +#ifdef OPLUS_ARCH_EXTENDS + [400] = {MSM_CPU_LITO, "SDM765G 5G"}, +#else [400] = {MSM_CPU_LITO, "LITO"}, - [440] = {MSM_CPU_LITO, "LITO"}, +#endif /* Orchid ID */ [476] = {MSM_CPU_ORCHID, "ORCHID"}, @@ -404,7 +421,36 @@ static struct msm_soc_info cpu_of_id[] = { * considered as unknown CPU. */ }; +#ifdef OPLUS_ARCH_EXTENDS +static struct msm_soc_info cpu_of_id_19125 = { + .generic_soc_type = MSM_CPU_LITO, + .soc_id_string = "SDM765 5G" +}; +static struct msm_soc_info cpu_of_id_21615 = { + .generic_soc_type = MSM_CPU_KONA, + .soc_id_string = "SM8250_AC" +}; +static struct msm_soc_info cpu_of_id_20828 = { + .generic_soc_type = MSM_CPU_KONA, + .soc_id_string = "SM8250_AC" +}; + +static struct msm_soc_info cpu_of_id_op8 = { + .generic_soc_type = MSM_CPU_KONA, + .soc_id_string = "SM8250" +}; + +static struct msm_soc_info cpu_of_id_20127 = { + .generic_soc_type = MSM_CPU_LITO, + .soc_id_string = "SDM768G 5G" +}; + +static struct msm_soc_info cpu_of_id_2065c = { + .generic_soc_type = MSM_CPU_LITO, + .soc_id_string = "SDM768G" +}; +#endif static enum msm_cpu cur_cpu; static int current_image; static uint32_t socinfo_format; @@ -422,6 +468,26 @@ EXPORT_SYMBOL(socinfo_get_id); char *socinfo_get_id_string(void) { +#ifdef OPLUS_ARCH_EXTENDS + if((get_project() == 19125) ||(get_project() == 19126)){ + return cpu_of_id_19125.soc_id_string; + } + if (!is_confidential() && get_project() == 20127){ + return cpu_of_id_20127.soc_id_string; + } + if (!is_confidential() && (get_project() == 132700 || get_project() == 132701)){ + return cpu_of_id_2065c.soc_id_string; + } + if ((get_project() == 21615)||(get_project() == 21619)||(get_project() == 0x2161A)||(get_project() == 0x2169A)||(get_project() == 0x2169B)||(get_project() == 21623)||(get_project() == 21732)||(get_project() == 21733) || (get_project() == 22671) ) { + return cpu_of_id_21615.soc_id_string; + } + if ((get_project() == 19811) || (get_project() == 19821) || (get_project() == 19805) || (get_project() == 19855) || (get_project() == 20809)) { + return cpu_of_id_op8.soc_id_string; + } + if (get_project() == 20828) { + return cpu_of_id_20828.soc_id_string; + } +#endif return (socinfo) ? cpu_of_id[socinfo->v0_1.id].soc_id_string : NULL; } EXPORT_SYMBOL(socinfo_get_id_string); @@ -448,9 +514,36 @@ static char *msm_read_hardware_id(void) goto err_path; if (!cpu_of_id[socinfo->v0_1.id].soc_id_string) goto err_path; - - ret = strlcat(msm_soc_str, cpu_of_id[socinfo->v0_1.id].soc_id_string, - sizeof(msm_soc_str)); +#ifdef OPLUS_ARCH_EXTENDS + if((get_project() == 19125) ||(get_project() == 19126)){ + ret = strlcat(msm_soc_str, cpu_of_id_19125.soc_id_string, + sizeof(msm_soc_str)); + } + else if (!is_confidential() && get_project() == 20127) { + ret = strlcat(msm_soc_str, cpu_of_id_20127.soc_id_string, + sizeof(msm_soc_str)); + } + else if (!is_confidential() && (get_project() == 132700 || get_project() == 132701)) { + ret = strlcat(msm_soc_str, cpu_of_id_2065c.soc_id_string, + sizeof(msm_soc_str)); + } + else if ((get_project() == 21615)||(get_project() == 21619)||(get_project() == 0x2161A)||(get_project() == 0x2169A)||(get_project() == 0x2169B)||(get_project() == 21623)||(get_project() == 21732)||(get_project() == 21733)||(get_project() == 22671)) { + ret = strlcat(msm_soc_str, cpu_of_id_21615.soc_id_string, + sizeof(msm_soc_str)); + } + else if ((get_project() == 19811) || (get_project() == 19821) || (get_project() == 19805) || (get_project() == 19855) || (get_project() == 20809)) { + ret = strlcat(msm_soc_str, cpu_of_id_op8.soc_id_string, + sizeof(msm_soc_str)); + } + else if (get_project() == 20828){ + ret = strlcat(msm_soc_str, cpu_of_id_20828.soc_id_string, + sizeof(msm_soc_str)); + } + else{ +#endif + ret = strlcat(msm_soc_str, cpu_of_id[socinfo->v0_1.id].soc_id_string, + sizeof(msm_soc_str)); + } if (ret > sizeof(msm_soc_str)) goto err_path; @@ -1839,6 +1932,41 @@ int __init socinfo_init(void) pr_warn("New IDs added! ID => CPU mapping needs an update.\n"); cur_cpu = cpu_of_id[socinfo->v0_1.id].generic_soc_type; +#ifdef OPLUS_ARCH_EXTENDS + if (is_confidential()) { +#if defined(CONFIG_ARCH_LITO) + if((get_project() == 19191) || (get_project() == 19192) + || (get_project() == 19015) || (get_project() == 19016) + || (get_project() == 19591) || (get_project() == 19525) + || (get_project() == 19101) || (get_project() == 19102) + || (get_project() == 19501) || (get_project() == 19125) + || (get_project() == 19126) || (get_project() == 19127) + || (get_project() == 19128) || (get_project() == 19521) + || (get_project() == 19335) || (get_project() == 20801) + || (get_project() == 20804)) + cpu_of_id[socinfo->v0_1.id].soc_id_string = real_cpu_id; + else if((get_project() == 20057) || (get_project() == 20058 + || get_project() == 20813) || get_project() == 20814) + cpu_of_id[socinfo->v0_1.id].soc_id_string = real_cpu_id_20057_20058; + else if((get_project() == 20669) || (get_project() == 20750) || (get_project() == 20751)) + cpu_of_id[socinfo->v0_1.id].soc_id_string = real_cpu_id_20669_20750_20751; + else + cpu_of_id[socinfo->v0_1.id].soc_id_string = fake_cpu_id; +#else + cpu_of_id[socinfo->v0_1.id].soc_id_string = fake_cpu_id; +#endif + } else { + if((get_project() == 20057) || (get_project() == 20058 + || get_project() == 20813) || get_project() == 20814) + cpu_of_id[socinfo->v0_1.id].soc_id_string = real_cpu_id_20057_20058; + else if((get_project() == 20669) || (get_project() == 20750) || (get_project() == 20751)) + cpu_of_id[socinfo->v0_1.id].soc_id_string = real_cpu_id_20669_20750_20751; + else if((get_project() == 20061) || (get_project() == 20161) || (get_project() == 20163) || (get_project() == 20351) || (get_project() == 21027)) + cpu_of_id[socinfo->v0_1.id].soc_id_string = real_cpu_id_20161_models; + else + cpu_of_id[socinfo->v0_1.id].soc_id_string = real_cpu_id; + } +#endif boot_stats_init(); socinfo_print(); arch_read_hardware_id = msm_read_hardware_id; diff --git a/drivers/soc/qcom/subsys-pil-tz.c b/drivers/soc/qcom/subsys-pil-tz.c index 68ea839c6355..b1f87e1e4672 100644 --- a/drivers/soc/qcom/subsys-pil-tz.c +++ b/drivers/soc/qcom/subsys-pil-tz.c @@ -26,6 +26,13 @@ #include #include "peripheral-loader.h" +//#ifdef OPLUS_FEATURE_SENSOR +#include +//#endif + +#ifdef OPLUS_FEATURE_MM_FEEDBACK +#include +#endif #define XO_FREQ 19200000 #define PROXY_TIMEOUT_MS 10000 @@ -724,6 +731,11 @@ static int pil_shutdown_trusted(struct pil_desc *pil) u32 proc, scm_ret = 0; int rc; struct scm_desc desc = {0}; + #ifdef OPLUS_FEATURE_MODEM_MINIDUMP + //Add for skip mini dump encryption + int i = 0; + struct md_ss_toc *toc = NULL; + #endif if (d->subsys_desc.no_auth) return 0; @@ -745,10 +757,39 @@ static int pil_shutdown_trusted(struct pil_desc *pil) if (rc) goto err_clks; + #ifdef OPLUS_FEATURE_MODEM_MINIDUMP + //Add for skip mini dump encryption + //disable for TZ don't encryption + if ( pil->minidump_id ==3 ) { //only check for modem . currently 3 is modem + pil->minidump_ss->md_ss_enable_status = 0; + pil->minidump_ss->encryption_status = 0; + + for ( i = 0; i < pil->num_aux_minidump_ids; i++ ) { + toc = pil->aux_minidump[i]; + toc->md_ss_enable_status = 0; + toc->encryption_status = 0; + } + } + #endif rc = scm_call2(SCM_SIP_FNID(SCM_SVC_PIL, PAS_SHUTDOWN_CMD), &desc); scm_ret = desc.ret[0]; + #ifdef OPLUS_FEATURE_MODEM_MINIDUMP + //Add for skip mini dump encryption + //disable for TZ don't encryption + //set back for miindump flow + if( pil->minidump_id == 3 ) { //only check for modem . currently 3 is modem + pil->minidump_ss->md_ss_enable_status =MD_SS_ENABLED; + pil->minidump_ss->encryption_status =MD_SS_ENCR_DONE; + + for (i = 0; i < pil->num_aux_minidump_ids; i++) { + toc = pil->aux_minidump[i]; + toc->md_ss_enable_status = MD_SS_ENABLED; + toc->encryption_status = MD_SS_ENCR_DONE; + } + } + #endif disable_unprepare_clocks(d->proxy_clks, d->proxy_clk_count); disable_regulators(d, d->proxy_regs, d->proxy_reg_count, false); @@ -801,11 +842,22 @@ static struct pil_reset_ops pil_ops_trusted = { .proxy_unvote = pil_remove_proxy_vote, .deinit_image = pil_deinit_image_trusted, }; +//#ifdef OPLUS_FEATURE_SENSOR +extern void set_subsys_crash_cause(char *reason); +//#endif +#ifdef OPLUS_FEATURE_MODEM_MINIDUMP +//Add for customized subsystem ramdump to skip generate dump cause by SAU +bool SKIP_GENERATE_RAMDUMP = false; +extern void mdmreason_set(char * buf); +#endif static void log_failure_reason(const struct pil_tz_data *d) { size_t size; char *smem_reason, reason[MAX_SSR_REASON_LEN]; + #ifdef OPLUS_FEATURE_AGINGTEST + char *function_name; + #endif /*OPLUS_FEATURE_AGINGTEST*/ const char *name = d->subsys_desc.name; if (d->smem_id == -1) @@ -817,13 +869,79 @@ static void log_failure_reason(const struct pil_tz_data *d) name); return; } + + strlcpy(reason, smem_reason, min(size, (size_t)MAX_SSR_REASON_LEN)); if (!smem_reason[0]) { pr_err("%s SFR: (unknown, empty string found).\n", name); + #ifdef OPLUS_FEATURE_MODEM_MINIDUMP + if (subsys_get_crash_status(d->subsys) == CRASH_STATUS_ERR_FATAL) { + if (!strncmp(name, "modem", 5)) { + subsystem_send_uevent(d->subsys, 0); + } + } + #endif /*OPLUS_FEATURE_MODEM_MINIDUMP*/ + #ifdef OPLUS_FEATURE_WIFI_DCS_SWITCH + if (subsys_get_crash_status(d->subsys) == CRASH_STATUS_ERR_FATAL) { + pr_info("log_failure_reason wlan send uevent"); + wlan_subsystem_send_uevent(d->subsys, reason, name); + } + #endif /* OPLUS_FEATURE_WIFI_DCS_SWITCH */ return; } - strlcpy(reason, smem_reason, min(size, (size_t)MAX_SSR_REASON_LEN)); + pr_info("Restart sequence requested test"); + + #ifdef OPLUS_FEATURE_WIFI_DCS_SWITCH + if (subsys_get_crash_status(d->subsys) == CRASH_STATUS_ERR_FATAL) { + pr_info("log_failure_reason wlan send uevent"); + wlan_subsystem_send_uevent(d->subsys, reason, name); + } + #endif /* OPLUS_FEATURE_WIFI_DCS_SWITCH */ + + #ifdef OPLUS_FEATURE_AGINGTEST + function_name = parse_function_builtin_return_address((unsigned long)__builtin_return_address(0)); + save_dump_reason_to_smem(reason, function_name); + #endif /*OPLUS_FEATURE_AGINGTEST*/ + + //#ifdef OPLUS_FEATURE_SENSOR + set_subsys_crash_cause(reason); + if((strncmp(name, "slpi", strlen("slpi")) == 0) + || (strncmp(name, "cdsp", strlen("cdsp")) == 0) + || (strncmp(name, "adsp", strlen("adsp")) == 0)){ + strcat(reason, "$$module@@"); + strcat(reason, name); + oplus_kevent_fb_str(FB_SENSOR, FB_SENSOR_ID_CRASH, reason); + } + //#endif + #ifdef OPLUS_FEATURE_MM_FEEDBACK + if(strncmp(name, "adsp", strlen("adsp")) == 0){ + mm_fb_audio_kevent_named(OPLUS_AUDIO_EVENTID_ADSP_CRASH, \ + MM_FB_KEY_RATELIMIT_5MIN, "payload@@%s$$fid@@123456", reason); + } + #endif pr_err("%s subsystem failure reason: %s.\n", name, reason); + + #ifdef OPLUS_FEATURE_MODEM_MINIDUMP + //Add for customized subsystem ramdump to skip generate dump cause by SAU + if (!strncmp(name, "modem", 4)) { + mdmreason_set(reason); + + pr_err("oplus debug modem subsystem failure reason: %s.\n", reason); + + if(strstr(reason, "OPLUS_MODEM_NO_RAMDUMP_EXPECTED") || strstr(reason, "oppomsg:go_to_error_fatal")){ + pr_err("%s will subsys reset",__func__); + SKIP_GENERATE_RAMDUMP = true; + } + } + #endif + + #ifdef OPLUS_FEATURE_MODEM_MINIDUMP + if (subsys_get_crash_status(d->subsys) == CRASH_STATUS_ERR_FATAL) { + if (!strncmp(name, "modem", 5)) { + subsystem_send_uevent(d->subsys, reason); + } + } + #endif /*OPLUS_FEATURE_MODEM_MINIDUMP*/ } static int subsys_shutdown(const struct subsys_desc *subsys, bool force_stop) diff --git a/drivers/soc/qcom/subsystem_restart.c b/drivers/soc/qcom/subsystem_restart.c index 2479632e103b..b4be023046eb 100644 --- a/drivers/soc/qcom/subsystem_restart.c +++ b/drivers/soc/qcom/subsystem_restart.c @@ -33,8 +33,19 @@ #include #include #include +#include +#include #include "peripheral-loader.h" +#ifdef OPLUS_BUG_STABILITY +/*Add for disable dump for subsys crash*/ +#include +extern bool oem_is_fulldump(void); +bool delay_panic = false; +#endif +#ifdef OPLUS_BUG_STABILITY +bool direct_panic = false; +#endif #define DISABLE_SSR 0x9889deed /* If set to 0x9889deed, call to subsystem_restart_dev() returns immediately */ @@ -43,6 +54,9 @@ module_param(disable_restart_work, uint, 0644); static int enable_debug; module_param(enable_debug, int, 0644); +//#ifdef OPLUS_FEATURE_SENSOR +static DEFINE_MUTEX(subsys_list_lock); +//#endif /* The maximum shutdown timeout is the product of MAX_LOOPS and DELAY_MS. */ #define SHUTDOWN_ACK_MAX_LOOPS 100 @@ -205,6 +219,25 @@ struct subsys_device { struct list_head list; }; +#ifdef OPLUS_FEATURE_ADSP_RECOVERY +static bool oplus_adsp_ssr = false; + +void oplus_set_ssr_state(bool ssr_state) +{ + oplus_adsp_ssr = ssr_state; + pr_err("%s():oplus_adsp_ssr=%d\n", __func__, oplus_adsp_ssr); + +} +EXPORT_SYMBOL(oplus_set_ssr_state); + +bool oplus_get_ssr_state(void) +{ + pr_err("%s():oplus_adsp_ssr=%d\n", __func__, oplus_adsp_ssr); + return oplus_adsp_ssr; +} +EXPORT_SYMBOL(oplus_get_ssr_state); +#endif /* OPLUS_FEATURE_ADSP_RECOVERY */ + static struct subsys_device *to_subsys(struct device *d) { return container_of(d, struct subsys_device, dev); @@ -276,7 +309,16 @@ static ssize_t restart_level_store(struct device *dev, if (!strncasecmp(buf, restart_levels[i], count)) { pil_ipc("[%s]: change restart level to %d\n", subsys->desc->name, i); - subsys->restart_level = i; + //#ifdef OPLUS_BUG_STABILITY + if(PREVERSION == get_eng_version()){ + pr_info("preversion \n"); + subsys->restart_level = RESET_SUBSYS_COUPLED; + } else { + subsys->restart_level = i; + } + //#else + //subsys->restart_level = i; + //#endif /*OPLUS_BUG_STABILITY*/ return orig_count; } return -EPERM; @@ -343,7 +385,40 @@ static ssize_t system_debug_store(struct device *dev, return orig_count; } static DEVICE_ATTR_RW(system_debug); +//#ifdef OPLUS_FEATURE_SENSOR +#define CRASH_CAUSE_BUF_LEN 128 +char crash_case_buf[CRASH_CAUSE_BUF_LEN] = {0}; +void set_subsys_crash_cause(char *str){ + int len = 0; + len = strlen(str); + if(len >= CRASH_CAUSE_BUF_LEN) + len = CRASH_CAUSE_BUF_LEN -1; + //mutex_lock(&subsys_list_lock); + memcpy(crash_case_buf, str, len); + crash_case_buf[len] = '\0'; + //mutex_unlock(&subsys_list_lock); +} +EXPORT_SYMBOL(set_subsys_crash_cause); + +static ssize_t crash_cause_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int ret = 0; + mutex_lock(&subsys_list_lock); + ret = snprintf(buf, PAGE_SIZE, "%s\n", crash_case_buf); + mutex_unlock(&subsys_list_lock); + return ret; +} + +static ssize_t crash_cause_store(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) +{ + return count; +} +static DEVICE_ATTR_RW(crash_cause); +//#endif int subsys_get_restart_level(struct subsys_device *dev) { return dev->restart_level; @@ -386,6 +461,9 @@ static struct attribute *subsys_attrs[] = { &dev_attr_restart_level.attr, &dev_attr_firmware_name.attr, &dev_attr_system_debug.attr, + //#ifdef OPLUS_FEATURE_SENSOR + &dev_attr_crash_cause.attr, + //#endif NULL, }; @@ -413,7 +491,9 @@ static LIST_HEAD(subsys_list); static LIST_HEAD(ssr_order_list); static DEFINE_MUTEX(soc_order_reg_lock); static DEFINE_MUTEX(restart_log_mutex); -static DEFINE_MUTEX(subsys_list_lock); +//#ifdef OPLUS_FEATURE_SENSOR +//static DEFINE_MUTEX(subsys_list_lock); +//#endif static DEFINE_MUTEX(char_device_lock); static DEFINE_MUTEX(ssr_order_mutex); @@ -831,6 +911,30 @@ struct subsys_device *find_subsys_device(const char *str) } EXPORT_SYMBOL(find_subsys_device); +#ifdef OPLUS_BUG_STABILITY +int op_restart_modem(struct subsys_device *subsys) +{ + int restart_level; + + if (!subsys) { + return -ENODEV; + } + + pr_err("%s\n", __func__); + + restart_level = subsys->restart_level; + subsys->restart_level = RESET_SUBSYS_COUPLED; + if (subsys->desc->force_reset) { + subsys->desc->force_reset(subsys->desc); + } + + subsys->restart_level = restart_level; + + return 0; +} +EXPORT_SYMBOL(op_restart_modem); +#endif /* OPLUS_BUG_STABILITY */ + static int subsys_start(struct subsys_device *subsys) { int ret; @@ -1209,6 +1313,117 @@ static void device_restart_work_hdlr(struct work_struct *work) dev->desc->name); } +#ifdef OPLUS_FEATURE_MODEM_MINIDUMP +unsigned int getBKDRHash(char *str, unsigned int len) +{ + unsigned int seed = 131; /* 31 131 1313 13131 131313 etc.. */ + unsigned int hash = 0; + unsigned int i = 0; + if (str == NULL) { + return 0; + } + for(i = 0; i < len; str++, i++) { + hash = (hash * seed) + (*str); + } + return hash; +} +EXPORT_SYMBOL(getBKDRHash); + +void __subsystem_send_uevent(struct device *dev, char *reason) +{ + int ret_val; + char modem_event[] = "MODEM_EVENT=modem_failure"; + char modem_reason[300] = {0}; + char modem_hashreason[MAX_REASON_LEN] = {0}; + char *envp[4]; + unsigned int hashid = 0; + + envp[0] = (char *)&modem_event; + if(reason){ + snprintf(modem_reason, sizeof(modem_reason),"MODEM_REASON=%s", reason); + }else{ + snprintf(modem_reason, sizeof(modem_reason),"MODEM_REASON=unkown"); + } + modem_reason[299] = 0; + envp[1] = (char *)&modem_reason; + + hashid = getBKDRHash(reason, strlen(reason)); + snprintf(modem_hashreason, sizeof(modem_hashreason), "MODEM_HASH_REASON=fid:%u;cause:%s", hashid, reason); + modem_hashreason[MAX_REASON_LEN - 1] = 0; + pr_info("__subsystem_send_uevent: modem_hashreason: %s\n", modem_hashreason); + envp[2] = (char *)&modem_hashreason; + + envp[3] = 0; + + if(dev){ + ret_val = kobject_uevent_env(&(dev->kobj), KOBJ_CHANGE, envp); + if(!ret_val){ + pr_info("modem crash:kobject_uevent_env success!\n"); + }else{ + pr_info("modem crash:kobject_uevent_env fail,error=%d!\n", ret_val); + } + } +} +EXPORT_SYMBOL(__subsystem_send_uevent); + +void subsystem_send_uevent(struct subsys_device *dev, char *reason) +{ + __subsystem_send_uevent(&(dev->dev), reason); + return; +} +EXPORT_SYMBOL(subsystem_send_uevent); +#endif /*OPLUS_FEATURE_MODEM_MINIDUMP*/ + +#ifdef OPLUS_FEATURE_WIFI_DCS_SWITCH +#define WCNSS_CRASH_REASON_SMEM 422 +#include +#include +void __wlan_subsystem_send_uevent(struct device *dev, char *reason, const char *name) +{ + int ret_val; + char event[] = "WLAN_SWITCH_EVENT=Subsystem"; + char fw_Reason[300] = {0}; + char sub_name[300] = {0}; + char *envp[4]; + + if (name) { + snprintf(sub_name, sizeof(sub_name), "subsystem_name=%s", name); + } else { + snprintf(sub_name, sizeof(sub_name), "subsystem_name=unkown"); + } + + if (reason) { + snprintf(fw_Reason, sizeof(fw_Reason), "WLAN_MONITER_REASON=%s", reason); + } else { + snprintf(fw_Reason, sizeof(fw_Reason), "WLAN_MONITER_REASON=unkown"); + } + + envp[0] = (char *)&event; + + fw_Reason[299] = 0; + envp[1] = (char *)&fw_Reason; + envp[2] = (char *)&sub_name; + envp[3] = 0; + + if (dev) { + ret_val = kobject_uevent_env(&(dev->kobj), KOBJ_CHANGE, envp); + if (!ret_val) { + pr_info("wlan crash:kobject_uevent_env success!\n"); + } else { + pr_info("wlan crash:kobject_uevent_env fail,error=%d!\n", ret_val); + } + } +} +EXPORT_SYMBOL(__wlan_subsystem_send_uevent); + +void wlan_subsystem_send_uevent(struct subsys_device *dev, char *reason, const char *name) +{ + __wlan_subsystem_send_uevent(&(dev->dev), reason, name); + return; +} +EXPORT_SYMBOL(wlan_subsystem_send_uevent); +#endif /* OPLUS_FEATURE_WIFI_DCS_SWITCH */ + int subsystem_restart_dev(struct subsys_device *dev) { const char *name; @@ -1223,6 +1438,22 @@ int subsystem_restart_dev(struct subsys_device *dev) name = dev->desc->name; +#ifdef OPLUS_FEATURE_ADSP_RECOVERY + if (name && !strcmp(name, "adsp")) { + if (oplus_get_ssr_state()) { + pr_err("%s: adsp restarting, Ignoring request\n", __func__); + return 0; + } else { + oplus_set_ssr_state(true); + } + } +#endif +#ifdef OPLUS_FEATURE_WIFI_DCS_SWITCH + if (subsys_get_crash_status(dev) == CRASH_STATUS_ERR_FATAL) { + pr_info("subsystem_restart_dev wlan send uevent"); + __wlan_subsystem_send_uevent(&(dev->dev), "", dev->desc->name); + } +#endif /* OPLUS_FEATURE_WIFI_DCS_SWITCH */ send_early_notifications(dev->early_notify); /* @@ -1251,8 +1482,23 @@ int subsystem_restart_dev(struct subsys_device *dev) __subsystem_restart_dev(dev); break; case RESET_SOC: + #ifdef VENDOR_EDIT + if (!strcmp(name, "esoc0") && oem_is_fulldump()) { + if (!direct_panic) { + delay_panic = true; + } + direct_panic = false; + __subsystem_restart_dev(dev); + break; + } else { + direct_panic = false; + __pm_stay_awake(dev->ssr_wlock); + schedule_work(&dev->device_restart_work); + } + #else __pm_stay_awake(dev->ssr_wlock); schedule_work(&dev->device_restart_work); + #endif return 0; default: panic("subsys-restart: Unknown restart level!\n"); @@ -1821,6 +2067,10 @@ struct subsys_device *subsys_register(struct subsys_desc *desc) subsys->dev.bus = &subsys_bus_type; subsys->dev.release = subsys_device_release; subsys->notif_state = -1; +#ifdef OPLUS_BUG_STABILITY + if(!oplus_daily_build() && !(get_eng_version() == AGING)) + subsys->restart_level = RESET_SUBSYS_COUPLED; +#endif /*OPLUS_BUG_STABILITY */ subsys->desc->sysmon_pid = -1; subsys->desc->state = NULL; strlcpy(subsys->desc->fw_name, desc->name, @@ -1978,10 +2228,66 @@ static struct notifier_block panic_nb = { .notifier_call = ssr_panic_handler, }; +extern bool ts_wait_error; +extern bool ts_send_error; +#ifdef CONFIG_ESOC_MDM_4x +extern bool modem_force_rst; +#endif + +static ssize_t force_rst_write(struct file *file, + const char __user *buf, + size_t count, + loff_t *lo) +{ + char read_buf[4] = {0}; + struct subsys_device *subsys = find_subsys_device("esoc0"); + + if (!subsys) + return 0; + + if (copy_from_user(read_buf, buf, 1)) { + pr_err("%s: failed to copy from user.\n", __func__); + return count; + } + + pr_info("%s: %s\n", __func__, read_buf); + + if (!strncmp(read_buf, "2", 1)) { + panic("force esoc crash"); + } + + if (!strncmp(read_buf, "1", 1) && (ts_send_error || ts_wait_error)) { +#ifdef CONFIG_ESOC_MDM_4x + modem_force_rst = true; +#endif + ts_wait_error = false; + ts_send_error = false; + pr_err("force to reset modem\n"); + op_restart_modem(subsys); + } + + return count; +} + +static ssize_t force_rst_read(struct file *file, + char __user *buf, + size_t count, + loff_t *ppos) +{ + return count; +} + +static const struct file_operations esoc_force_rst_fops = { + .write = force_rst_write, + .read = force_rst_read, + .open = simple_open, + .owner = THIS_MODULE, +}; + static int __init subsys_restart_init(void) { int ret; - + struct proc_dir_entry *d_entry = NULL; ssr_wq = alloc_workqueue("ssr_wq", WQ_UNBOUND | WQ_HIGHPRI | WQ_CPU_INTENSIVE, 0); BUG_ON(!ssr_wq); @@ -2002,6 +2308,11 @@ static int __init subsys_restart_init(void) if (ret) goto err_soc; + d_entry = proc_create_data("force_reset", 0666, NULL, &esoc_force_rst_fops, NULL); + if (!d_entry) { + goto err_soc; + } + return 0; err_soc: diff --git a/drivers/soc/qcom/sysmon-qmi.c b/drivers/soc/qcom/sysmon-qmi.c index 0d55f7b21a0f..72546b1b4d01 100644 --- a/drivers/soc/qcom/sysmon-qmi.c +++ b/drivers/soc/qcom/sysmon-qmi.c @@ -38,6 +38,7 @@ #define QMI_SSCTL_SUBSYS_EVENT_REQ_LENGTH 40 #define QMI_SSCTL_RESP_MSG_LENGTH 7 #define QMI_SSCTL_EMPTY_MSG_LENGTH 0 + #define QMI_SSCTL_MAX_MSG_LENGTH 362 #define SSCTL_SERVICE_ID 0x2B diff --git a/drivers/soc/qcom/watchdog_v2.c b/drivers/soc/qcom/watchdog_v2.c index c9996ffafb01..8247bca51e5b 100644 --- a/drivers/soc/qcom/watchdog_v2.c +++ b/drivers/soc/qcom/watchdog_v2.c @@ -31,6 +31,10 @@ #include #include #include + +/*use self-defined utils*/ +#include "oplus_watchdog_util.h" + #ifdef CONFIG_QCOM_INITIAL_LOGBUF #include #include @@ -58,6 +62,7 @@ #define COMPARE_RET -1 typedef int (*compare_t) (const void *lhs, const void *rhs); +extern void oplus_show_utc_time(void); #ifdef CONFIG_QCOM_INITIAL_LOGBUF #define LOGBUF_TIMEOUT 100000U @@ -69,8 +74,12 @@ static dma_addr_t log_buf_paddr; #endif static struct msm_watchdog_data *wdog_data; - +#ifndef OPLUS_BUG_STABILITY +/*use self-defined utils*/ static int cpu_idle_pc_state[NR_CPUS]; +#else +int cpu_idle_pc_state[NR_CPUS]; +#endif struct irq_info { unsigned int irq; @@ -410,13 +419,26 @@ static void keep_alive_response(void *info) * If this function does not return, it implies one of the * other cpu's is not responsive. */ +#ifdef OPLUS_BUG_STABILITY +/*add for debug cpu hang */ +static int wdog_cpu = 0; +#endif /* OPLUS_BUG_STABILITY */ static void ping_other_cpus(struct msm_watchdog_data *wdog_dd) { +#ifndef OPLUS_BUG_STABILITY +/* add for debug cpu hang */ int cpu; - +#endif /* OPLUS_BUG_STABILITY */ +#ifdef OPLUS_BUG_STABILITY +/* print more info on pet watchdog */ + cpumask_t mask; + get_cpu_ping_mask(&mask); +#endif /*OPLUS_BUG_STABILITY*/ cpumask_clear(&wdog_dd->alive_mask); /* Make sure alive mask is cleared and set in order */ smp_mb(); +#ifndef OPLUS_BUG_STABILITY +/* only ping cpu need ping */ for_each_cpu(cpu, cpu_online_mask) { if (!cpu_idle_pc_state[cpu] && !cpu_isolated(cpu)) { wdog_dd->ping_start[cpu] = sched_clock(); @@ -424,6 +446,15 @@ static void ping_other_cpus(struct msm_watchdog_data *wdog_dd) wdog_dd, 1); } } +#else + for_each_cpu(wdog_cpu, &mask) { + if (!cpu_idle_pc_state[wdog_cpu] && !cpu_isolated(wdog_cpu)) { + wdog_dd->ping_start[wdog_cpu] = sched_clock(); + smp_call_function_single(wdog_cpu, keep_alive_response, + wdog_dd, 1); + } + } +#endif /* OPLUS_BUG_STABILITY */ } static void pet_task_wakeup(struct timer_list *t) @@ -646,6 +677,10 @@ static __ref int watchdog_kthread(void *arg) delay_time = msecs_to_jiffies(wdog_dd->pet_time); pet_watchdog(wdog_dd); } +#ifdef OPLUS_BUG_STABILITY + /* for UCT time print, over 30s print once */ + oplus_show_utc_time(); +#endif /* Check again before scheduling * Could have been changed on other cpu */ @@ -759,10 +794,29 @@ static irqreturn_t wdog_bark_handler(int irq, void *dev_id) nanosec_rem = do_div(wdog_dd->last_pet, 1000000000); dev_info(wdog_dd->dev, "Watchdog last pet at %lu.%06lu\n", (unsigned long) wdog_dd->last_pet, nanosec_rem / 1000); - if (wdog_dd->do_ipi_ping) + if (wdog_dd->do_ipi_ping) { dump_cpu_alive_mask(wdog_dd); +#ifdef OPLUS_BUG_STABILITY +/* print online cpu */ + dump_cpu_online_mask(); +#endif + } +#ifdef OPLUS_BUG_STABILITY +/*print more info about cpu the wdog on */ + if (try_to_recover_pending(wdog_dd->watchdog_task)) { + pet_watchdog(wdog_dd); + return IRQ_HANDLED; + } + print_smp_call_cpu(); + dump_wdog_cpu(wdog_dd->watchdog_task); +#endif +#ifdef OPLUS_BUG_STABILITY +/*delete trigger wdog bite, panic will trigger wdog if in dload mode*/ + panic("Handle a watchdog bite! - Falling back to kernel panic!"); +#else msm_trigger_wdog_bite(); +#endif return IRQ_HANDLED; } @@ -1052,6 +1106,14 @@ static int msm_watchdog_probe(struct platform_device *pdev) if (msm_minidump_add_region(&md_entry) < 0) pr_info("Failed to add Watchdog data in Minidump\n"); +#ifdef OPLUS_BUG_STABILITY + /* Add for init oplus watch dog log, checklist 64*/ + ret = init_oplus_watchlog(); + if (ret < 0) { + pr_info("Failed to init oplus watchlog"); + } +#endif + return 0; err: kzfree(wdog_dd); diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 4a5e250702a9..0a035a5ec661 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -1054,7 +1054,13 @@ static int spi_transfer_one_message(struct spi_controller *ctlr, ret = 0; ms = 8LL * 1000LL * xfer->len; do_div(ms, xfer->speed_hz); + + #ifndef OPLUS_FEATURE_TP_BASIC ms += ms + 200; /* some tolerance */ + #else + ms += ms + 1500; /* some tolerance */ + #endif /* OPLUS_FEATURE_TP_BASIC */ + if (ms > UINT_MAX) ms = UINT_MAX; diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig index 2aa7ef0b0318..201a29fd4e99 100644 --- a/drivers/staging/Kconfig +++ b/drivers/staging/Kconfig @@ -122,7 +122,7 @@ source "drivers/staging/gasket/Kconfig" source "drivers/staging/axis-fifo/Kconfig" -source "drivers/staging/erofs/Kconfig" +#source "drivers/staging/erofs/Kconfig" source "drivers/staging/qcacld-3.0/Kconfig" diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile index 4a63d6132b01..46de5c2a1e9d 100644 --- a/drivers/staging/Makefile +++ b/drivers/staging/Makefile @@ -51,5 +51,5 @@ obj-$(CONFIG_SOC_MT7621) += mt7621-eth/ obj-$(CONFIG_SOC_MT7621) += mt7621-dts/ obj-$(CONFIG_STAGING_GASKET_FRAMEWORK) += gasket/ obj-$(CONFIG_XIL_AXIS_FIFO) += axis-fifo/ -obj-$(CONFIG_EROFS_FS) += erofs/ +#obj-$(CONFIG_EROFS_FS) += erofs/ obj-$(CONFIG_QCA_CLD_WLAN) += qcacld-3.0/ diff --git a/drivers/staging/android/Kconfig b/drivers/staging/android/Kconfig index 17c5587805f5..dfdf6912c835 100644 --- a/drivers/staging/android/Kconfig +++ b/drivers/staging/android/Kconfig @@ -23,6 +23,13 @@ config ANDROID_VSOC a 'cuttlefish' Android image inside QEmu. The driver interacts with a QEmu ivshmem device. If built as a module, it will be called vsoc. +#ifdef OPLUS_FEATURE_HANS_FREEZE +config OPLUS_HANS + bool "HANS kernel and HANS native communication channel" + default n + ---help--- + Key events (signal/network package/binder) report to HAS native. +#endif /*OPLUS_FEATURE_HANS_FREEZE*/ source "drivers/staging/android/ion/Kconfig" endif # if ANDROID diff --git a/drivers/staging/android/Makefile b/drivers/staging/android/Makefile index 90e6154f11a4..e5d0df45081f 100644 --- a/drivers/staging/android/Makefile +++ b/drivers/staging/android/Makefile @@ -4,3 +4,7 @@ obj-y += ion/ obj-$(CONFIG_ASHMEM) += ashmem.o obj-$(CONFIG_ANDROID_VSOC) += vsoc.o +#ifdef OPLUS_FEATURE_HANS_FREEZE +obj-$(CONFIG_OPLUS_HANS) += hans.o +obj-$(CONFIG_OPLUS_HANS) += hans_netfilter.o +#endif /*OPLUS_FEATURE_HANS_FREEZE*/ diff --git a/drivers/staging/android/hans.c b/drivers/staging/android/hans.c new file mode 100644 index 000000000000..9852e77a6db7 --- /dev/null +++ b/drivers/staging/android/hans.c @@ -0,0 +1,209 @@ +/*********************************************************** +** Copyright (C), 2008-2019, OPLUS Mobile Comm Corp., Ltd. +** File: hans.c +** Description: Add for hans freeze manager +** +** Version: 1.0 +** Date : 2019/09/23 +** +** ------------------ Revision History:------------------------ +** +** Kun Zhou 2019/09/23 1.0 OPLUS_ARCH_EXTENDS +** Kun Zhou 2020/05/27 1.1 OPLUS_FEATURE_HANS_FREEZE +****************************************************************/ + +#include +#include +#include +#include +#include +#include + +#define NETLINK_PORT_HANS (0x15356) + +static struct sock *sock_handle = NULL; +static atomic_t hans_deamon_port; + +/* + *reuse LOOPBACK and FROZEN_TRANS channel to notify framework whether kernel support cgroupv2 or not + */ +static void hans_kern_support_cgrpv2() { + /*notify framework that kernel support cgroupv2*/ + hans_report(PKG, -1, -1, -1, -1, "PKG", HANS_USE_CGRPV2); + printk(KERN_ERR "%s: hans support cgroupv2\n", __func__); +} + +/* + * netlink report function to tell HANS native deamon unfreeze process info + * if the parameters is empty, fill it with (pid/uid with -1) + */ +int hans_report(enum message_type type, int caller_pid, int caller_uid, int target_pid, int target_uid, const char *rpc_name, int code) +{ + int len = 0; + int ret = 0; + struct hans_message *data = NULL; + struct sk_buff *skb = NULL; + struct nlmsghdr *nlh = NULL; + + if (atomic_read(&hans_deamon_port) == -1) { + pr_err("%s: hans_deamon_port invalid!\n", __func__); + return HANS_ERROR; + } + + if (sock_handle == NULL) { + pr_err("%s: sock_handle invalid!\n", __func__); + return HANS_ERROR; + } + + if (type >= TYPE_MAX) { + pr_err("%s: type = %d invalid!\n", __func__, type); + return HANS_ERROR; + } + + len = sizeof(struct hans_message); + skb = nlmsg_new(len, GFP_ATOMIC); + if (skb == NULL) { + pr_err("%s: type =%d, nlmsg_new failed!\n", __func__, type); + return HANS_ERROR; + } + + nlh = nlmsg_put(skb, 0, 0, 0, len, 0); + if (nlh == NULL) { + pr_err("%s: type =%d, nlmsg_put failed!\n", __func__, type); + kfree_skb(skb); + return HANS_ERROR; + } + + data = nlmsg_data(nlh); + if(data == NULL) { + pr_err("%s: type =%d, nlmsg_data failed!\n", __func__, type); + return HANS_ERROR; + } + data->type = type; + data->port = NETLINK_PORT_HANS; + data->caller_pid = caller_pid; + data->caller_uid = caller_uid; + data->target_pid = target_pid; + data->target_uid = target_uid; + data->pkg_cmd = -1; //invalid package cmd + data->code = code; + strlcpy(data->rpc_name, rpc_name, INTERFACETOKEN_BUFF_SIZE); + nlmsg_end(skb, nlh); + + if ((ret = nlmsg_unicast(sock_handle, skb, (u32)atomic_read(&hans_deamon_port))) < 0) { + pr_err("%s: nlmsg_unicast failed! err = %d\n", __func__ , ret); + return HANS_ERROR; + } + + return HANS_NOERROR; +} + +// HANS kernel module handle the message from HANS native deamon +static void hans_handler(struct sk_buff *skb) +{ + struct hans_message *data = NULL; + struct nlmsghdr *nlh = NULL; + unsigned int len = 0; + int uid = -1; + + if (!skb) { + pr_err("%s: recv skb NULL!\n", __func__); + return; + } + + uid = (*NETLINK_CREDS(skb)).uid.val; + //only allow native deamon talk with HANS kernel. + if (uid != 1000) { + pr_err("%s: uid: %d, permission denied\n", __func__, uid); + return; + } + + if (skb->len >= NLMSG_SPACE(0)) { + nlh = nlmsg_hdr(skb); + len = NLMSG_PAYLOAD(nlh, 0); + data = (struct hans_message *)NLMSG_DATA(nlh); + + if (len < sizeof (struct hans_message)) { + pr_err("%s: hans_message len check faied! len = %d min_expected_len = %lu!\n", __func__, len, sizeof(struct hans_message)); + return; + } + + if (data->port < 0) { + pr_err("%s: portid = %d invalid!\n", __func__, data->port); + return; + } + if (data->type >= TYPE_MAX) { + pr_err("%s: type = %d invalid!\n", __func__, data->type); + return; + } + if (atomic_read(&hans_deamon_port) == -1 && data->type != LOOP_BACK) { + pr_err("%s: handshake not setup, type = %d!\n", __func__, data->type); + return; + } + + switch (data->type) { + case LOOP_BACK: /*Loop back message, only for native deamon and kernel handshake*/ + atomic_set(&hans_deamon_port, data->port); + hans_report(LOOP_BACK, -1, -1, -1, -1, "loop back", CPUCTL_VERSION); + printk(KERN_ERR "%s: --> LOOP_BACK, port = %d\n", __func__, data->port); + hans_kern_support_cgrpv2(); + break; + case PKG: + printk(KERN_ERR "%s: --> PKG, uid = %d, pkg_cmd = %d\n", __func__, data->target_uid, data->pkg_cmd); + hans_network_cmd_parse(data->target_uid, data->pkg_cmd); + break; + case FROZEN_TRANS: + case CPUCTL_TRANS: + if (CHECK_KERN_SUPPORT_CGRPV2 == data->target_uid) { + hans_kern_support_cgrpv2(); + } else { + printk(KERN_ERR "%s: --> FROZEN_TRANS, uid = %d\n", __func__, data->target_uid); + hans_check_frozen_transcation(data->target_uid, data->type); + } + break; + + default: + pr_err("%s: hans_messag type invalid %d\n", __func__, data->type); + break; + } + } +} + +static int __init hans_core_init(void) +{ + struct netlink_kernel_cfg cfg = { + .input = hans_handler, + }; + + atomic_set(&hans_deamon_port, -1); + + sock_handle = netlink_kernel_create(&init_net, NETLINK_OPLUS_HANS, &cfg); + if (sock_handle == NULL) { + pr_err("%s: create netlink socket failed!\n", __func__); + return HANS_ERROR; + } + + if (hans_netfilter_init() == HANS_ERROR) { + pr_err("%s: netfilter init failed!\n", __func__); + netlink_kernel_release(sock_handle); //release socket + return HANS_ERROR; + } + + printk(KERN_INFO "%s: -\n", __func__); + return HANS_NOERROR; +} + +static void __exit hans_core_exit(void) +{ + if (sock_handle) + netlink_kernel_release(sock_handle); + + hans_netfilter_deinit(); + printk(KERN_INFO "%s: -\n", __func__); + +} + +module_init(hans_core_init); +module_exit(hans_core_exit); + +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/android/hans_netfilter.c b/drivers/staging/android/hans_netfilter.c new file mode 100644 index 000000000000..4a7664b62780 --- /dev/null +++ b/drivers/staging/android/hans_netfilter.c @@ -0,0 +1,240 @@ +/*********************************************************** +** Copyright (C), 2008-2019, OPLUS Mobile Comm Corp., Ltd. +** File: hans_netfilter.c +** Description: Add for hans freeze manager +** +** Version: 1.0 +** Date : 2019/09/23 +** +** ------------------ Revision History:------------------------ +** +** Kun Zhou 2019/09/23 1.0 OPLUS_ARCH_EXTENDS +** Kun Zhou 2019/09/23 1.1 OPLUS_FEATURE_HANS_FREEZE +****************************************************************/ + +#include +#include +#include +#include +#include +#include +#include + +#define MAX_SLOT (100) +static uid_t monitored_uids[MAX_SLOT]; +spinlock_t uids_lock; + +static inline uid_t sock2uid(struct sock *sk) +{ + if(sk && sk->sk_socket) + return SOCK_INODE(sk->sk_socket)->i_uid.val; + else + return 0; +} + +// Add netlink monitor uid. When the monitored UID has incoming network package, tell HANS native deamon +static void hans_add_monitored_uid(uid_t target_uid) +{ + int i = 0; + int fisrt_empty_slot = MAX_SLOT; + unsigned long flags; + + spin_lock_irqsave(&uids_lock, flags); + for (i = 0; i < MAX_SLOT; i++) { + if (monitored_uids[i] == target_uid) { //already in the monitored array + spin_unlock_irqrestore(&uids_lock, flags); + //printk(KERN_WARNING "%s: uid = %d already in array\n", __func__, target_uid); + return; + } else if (monitored_uids[i] == 0 && fisrt_empty_slot == MAX_SLOT) { // first empty slot for monitoring uid + fisrt_empty_slot = i; + } + } + + if (fisrt_empty_slot >= MAX_SLOT) { + spin_unlock_irqrestore(&uids_lock, flags); + pr_err("%s: monitored uid = %d add failed!\n", __func__, target_uid); + return; + } + monitored_uids[fisrt_empty_slot] = target_uid; + spin_unlock_irqrestore(&uids_lock, flags); +} + +static void hans_remove_monitored_uid(uid_t target_uid) +{ + int i = 0; + unsigned long flags; + + spin_lock_irqsave(&uids_lock, flags); + for (i = 0; i < MAX_SLOT; i++) { + if (monitored_uids[i] == target_uid) { + monitored_uids[i] = 0; + spin_unlock_irqrestore(&uids_lock, flags); + return; + } + } + spin_unlock_irqrestore(&uids_lock, flags); + printk(KERN_WARNING "%s: uid = %d remove uid not found\n", __func__, target_uid); +} + +static void hans_remove_all_monitored_uid(void) +{ + int i; + unsigned long flags; + + spin_lock_irqsave(&uids_lock, flags); + for (i = 0; i < MAX_SLOT; i++) { + monitored_uids[i] = 0; + } + spin_unlock_irqrestore(&uids_lock, flags); +} + +static bool hans_find_remove_monitored_uid(uid_t target_uid) +{ + bool found = false; + int i = 0; + unsigned long flags; + + spin_lock_irqsave(&uids_lock, flags); + for (i = 0; i < MAX_SLOT; i++) { + if (unlikely (monitored_uids[i] == target_uid)) { + found = true; + monitored_uids[i] = 0; + break; + } + } + spin_unlock_irqrestore(&uids_lock, flags); + + if (found) + printk(KERN_WARNING "%s: uid = %d found and removed\n", __func__, target_uid); + return found; +} + +void hans_network_cmd_parse(uid_t uid, enum pkg_cmd cmd) +{ + switch (cmd) { + case ADD_ONE_UID: + hans_add_monitored_uid(uid); + break; + case DEL_ONE_UID: + hans_remove_monitored_uid(uid); + break; + case DEL_ALL_UID: + hans_remove_all_monitored_uid(); + break; + default: + pr_err("%s: pkg_cmd type invalid %d\n", __func__, cmd); + break; + } +} + +// Moniter the uid by netlink filter hook function. +static unsigned int hans_nf_ipv4v6_in(void *priv, + struct sk_buff *skb, + const struct nf_hook_state *state) +{ + struct sock *sk; + uid_t uid; + unsigned int thoff = 0; + unsigned short frag_off = 0; + bool found = false; + uint hook; + struct net_device *dev = NULL; + + /* skb protection code */ + if (!skb || !skb->len || !state) { + pr_err("%s, buffer empty\n", __func__); + return NF_ACCEPT; + } + + hook = state->hook; + if (NF_INET_LOCAL_IN == hook) { + dev = state->in; + } + if (NULL == dev) { + return NF_ACCEPT; + } + /* skb protection code end */ + + if (ip_hdr(skb)->version == 4) { + if (ip_hdr(skb)->protocol != IPPROTO_TCP) + return NF_ACCEPT; +#if IS_ENABLED(CONFIG_IPV6) + } else if (ip_hdr(skb)->version == 6) { + if (ipv6_find_hdr(skb, &thoff, -1, &frag_off, NULL) != IPPROTO_TCP) + return NF_ACCEPT; +#endif + } else { + return NF_ACCEPT; + } + + sk = skb_to_full_sk(skb); + if (sk == NULL) return NF_ACCEPT; + if (!sk_fullsock(sk)) return NF_ACCEPT; + + uid = sock2uid(sk); + if (uid < MIN_USERAPP_UID) return NF_ACCEPT; + + // Find the monitored UID and clear it from the monitor array + found = hans_find_remove_monitored_uid(uid); + if (!found) + return NF_ACCEPT; + if (hans_report(PKG, -1, -1, -1, uid, "PKG", -1) != HANS_NOERROR) + pr_err("%s: hans_report PKG failed!, uid = %d\n", __func__, uid); + + return NF_ACCEPT; +} + +//Only monitor input network packages +static struct nf_hook_ops hans_nf_ops[] = { + + { + .hook = hans_nf_ipv4v6_in, + .pf = NFPROTO_IPV4, + .hooknum = NF_INET_LOCAL_IN, + .priority = NF_IP_PRI_SELINUX_LAST + 1, + }, +#if IS_ENABLED(CONFIG_IPV6) + { + .hook = hans_nf_ipv4v6_in, + .pf = NFPROTO_IPV6, + .hooknum = NF_INET_LOCAL_IN, + .priority = NF_IP6_PRI_SELINUX_LAST + 1, + }, +#endif +}; + +void hans_netfilter_deinit(void) +{ + struct net *net; + + rtnl_lock(); + for_each_net(net) { + nf_unregister_net_hooks(net, hans_nf_ops, ARRAY_SIZE(hans_nf_ops)); + } + rtnl_unlock(); +} + +int hans_netfilter_init(void) +{ + struct net *net = NULL; + int err = 0; + + spin_lock_init(&uids_lock); + hans_remove_all_monitored_uid(); + + rtnl_lock(); + for_each_net(net) { + err = nf_register_net_hooks(net, hans_nf_ops, ARRAY_SIZE(hans_nf_ops)); + if (err != 0) { + pr_err("%s: register netfilter hooks failed!\n", __func__); + break; + } + } + rtnl_unlock(); + + if (err != 0) { + hans_netfilter_deinit(); + return HANS_ERROR; + } + return HANS_NOERROR; +} diff --git a/drivers/staging/android/ion/Kconfig b/drivers/staging/android/ion/Kconfig index 813407f45741..93c0e18775d4 100644 --- a/drivers/staging/android/ion/Kconfig +++ b/drivers/staging/android/ion/Kconfig @@ -78,6 +78,12 @@ config ION_POOL_AUTO_REFILL when the pool count reaches below low mark. if you're not sure say Y here. +config OPLUS_ION_BOOSTPOOL + bool "Support ION Boost pool" + default n + help + This driver supports ION boost pool. + config ION_POOL_FILL_MARK int "ion pool fillmark size in MB" depends on ION_POOL_AUTO_REFILL diff --git a/drivers/staging/android/ion/Makefile b/drivers/staging/android/ion/Makefile index dc638f080d7f..1138eb3f294b 100644 --- a/drivers/staging/android/ion/Makefile +++ b/drivers/staging/android/ion/Makefile @@ -5,3 +5,8 @@ obj-$(CONFIG_ION) += ion.o ion-ioctl.o ion_heap.o \ ion_system_secure_heap.o ion_cma_heap.o \ ion_secure_util.o ion_cma_secure_heap.o msm/ +obj-$(CONFIG_OPLUS_ION_BOOSTPOOL) += oplus_ion_boost_pool.o + +#ifdef OPLUS_FEATURE_HEALTHINFO +obj-y += ion/ +#endif /* OPLUS_FEATURE_HEALTHINFO */ diff --git a/drivers/staging/android/ion/ion b/drivers/staging/android/ion/ion new file mode 120000 index 000000000000..420625f1ec8b --- /dev/null +++ b/drivers/staging/android/ion/ion @@ -0,0 +1 @@ +../../../../../../vendor/oplus/kernel/oplus_performance/healthinfo/ion/ \ No newline at end of file diff --git a/drivers/staging/android/ion/ion.c b/drivers/staging/android/ion/ion.c index 0a0fc1623909..76e85c160872 100644 --- a/drivers/staging/android/ion/ion.c +++ b/drivers/staging/android/ion/ion.c @@ -38,6 +38,16 @@ #include "ion.h" #include "ion_secure_util.h" +#ifdef OPLUS_FEATURE_HEALTHINFO +#if defined(CONFIG_OPLUS_HEALTHINFO) && defined (CONFIG_OPLUS_MEM_MONITOR) +#include +#endif +#endif /* OPLUS_FEATURE_HEALTHINFO */ + +#ifdef OPLUS_FEATURE_HEALTHINFO +#include +#endif /* OPLUS_FEATURE_HEALTHINFO */ + static struct ion_device *internal_dev; static atomic_long_t total_heap_bytes; @@ -157,10 +167,28 @@ static struct ion_buffer *ion_buffer_create(struct ion_heap *heap, } } +#if defined(OPLUS_FEATURE_MEMLEAK_DETECT) && defined(CONFIG_DUMP_TASKS_MEM) + /* upate ion buffer informaction + * of the task. + */ + buffer->tsk = current->group_leader; + get_task_struct(buffer->tsk); + atomic64_add(buffer->size, &buffer->tsk->ions); +#endif +#if defined(OPLUS_FEATURE_MEMLEAK_DETECT) && defined(CONFIG_MEMLEAK_DETECT_THREAD) + /* add record the buffer + * create time and calc the buffer age on dump. + */ + buffer->jiffies = jiffies; +#endif mutex_lock(&dev->buffer_lock); ion_buffer_add(dev, buffer); mutex_unlock(&dev->buffer_lock); atomic_long_add(len, &heap->total_allocated); +#ifdef OPLUS_FEATURE_HEALTHINFO + if (ion_cnt_enable) + atomic_long_add(buffer->size, &ion_total_size); +#endif /* OPLUS_FEATURE_HEALTHINFO */ atomic_long_add(len, &total_heap_bytes); return buffer; @@ -177,6 +205,17 @@ void ion_buffer_destroy(struct ion_buffer *buffer) pr_warn_ratelimited("ION client likely missing a call to dma_buf_kunmap or dma_buf_vunmap\n"); buffer->heap->ops->unmap_kernel(buffer->heap, buffer); } +#ifdef OPLUS_FEATURE_HEALTHINFO + if (ion_cnt_enable) + atomic_long_sub(buffer->size, &ion_total_size); +#endif /* OPLUS_FEATURE_HEALTHINFO */ +#if defined(OPLUS_FEATURE_MEMLEAK_DETECT) && defined(CONFIG_DUMP_TASKS_MEM) + if (buffer->tsk) { + atomic64_sub(buffer->size, &buffer->tsk->ions); + put_task_struct(buffer->tsk); + buffer->tsk = NULL; + } +#endif /* OPLUS_FEATURE_MEMLEAK_DETECT && CONFIG_MEMLEAK_DETECT_THREAD */ buffer->heap->ops->free(buffer); kfree(buffer); } @@ -1033,6 +1072,26 @@ static const struct dma_buf_ops dma_buf_ops = { .get_flags = ion_dma_buf_get_flags, }; +#ifdef CONFIG_OPLUS_ION_BOOSTPOOL +pid_t alloc_svc_tgid; + +/* TODO use task comm may not safe. */ +inline is_allocator_svc(struct task_struct *tsk) +{ + return (tsk->tgid == alloc_svc_tgid); +} + +static inline unsigned int boost_pool_extra_flags(unsigned int heap_id_mask) +{ + unsigned int extra_flags = 0; + + if ((heap_id_mask & (1 << ION_CAMERA_HEAP_ID)) || is_allocator_svc(current)) + extra_flags |= ION_FLAG_CAMERA_BUFFER; + + return extra_flags; +} +#endif /* CONFIG_OPLUS_ION_BOOSTPOOL */ + struct dma_buf *ion_alloc_dmabuf(size_t len, unsigned int heap_id_mask, unsigned int flags) { @@ -1042,6 +1101,15 @@ struct dma_buf *ion_alloc_dmabuf(size_t len, unsigned int heap_id_mask, DEFINE_DMA_BUF_EXPORT_INFO(exp_info); struct dma_buf *dmabuf; char task_comm[TASK_COMM_LEN]; +#ifdef CONFIG_OPLUS_ION_BOOSTPOOL + unsigned int extra_flags = boost_pool_extra_flags(heap_id_mask); +#endif /* CONFIG_OPLUS_ION_BOOSTPOOL */ + +#ifdef OPLUS_FEATURE_HEALTHINFO +#if defined(CONFIG_OPLUS_HEALTHINFO) && defined (CONFIG_OPLUS_MEM_MONITOR) + unsigned long oplus_ionwait_start = jiffies; +#endif +#endif /* OPLUS_FEATURE_HEALTHINFO */ pr_debug("%s: len %zu heap_id_mask %u flags %x\n", __func__, len, heap_id_mask, flags); @@ -1056,17 +1124,32 @@ struct dma_buf *ion_alloc_dmabuf(size_t len, unsigned int heap_id_mask, if (!len) return ERR_PTR(-EINVAL); +#ifdef CONFIG_OPLUS_ION_BOOSTPOOL + trace_ion_alloc_start(len, heap_id_mask, flags, + extra_flags ? "true" : "false"); +#endif /* CONFIG_OPLUS_ION_BOOSTPOOL */ + down_read(&dev->lock); plist_for_each_entry(heap, &dev->heaps, node) { /* if the caller didn't specify this heap id */ if (!((1 << heap->id) & heap_id_mask)) continue; +#ifdef CONFIG_OPLUS_ION_BOOSTPOOL + if (heap->id == ION_SYSTEM_HEAP_ID) { + buffer = ion_buffer_create(heap, dev, len, + flags | extra_flags); + } else +#endif buffer = ion_buffer_create(heap, dev, len, flags); if (!IS_ERR(buffer) || PTR_ERR(buffer) == -EINTR) break; } up_read(&dev->lock); +#ifdef CONFIG_OPLUS_ION_BOOSTPOOL + trace_ion_alloc_end(len, heap_id_mask, flags, ""); +#endif /* CONFIG_OPLUS_ION_BOOSTPOOL */ + if (!buffer) return ERR_PTR(-ENODEV); @@ -1087,7 +1170,11 @@ struct dma_buf *ion_alloc_dmabuf(size_t len, unsigned int heap_id_mask, _ion_buffer_destroy(buffer); kfree(exp_info.exp_name); } - +#ifdef OPLUS_FEATURE_HEALTHINFO +#if defined(CONFIG_OPLUS_HEALTHINFO) && defined (CONFIG_OPLUS_MEM_MONITOR) + ionwait_monitor(jiffies_to_msecs(jiffies - oplus_ionwait_start)); +#endif +#endif /* OPLUS_FEATURE_HEALTHINFO */ return dmabuf; } @@ -1399,3 +1486,9 @@ err_reg: return ERR_PTR(ret); } EXPORT_SYMBOL(ion_device_create); +#if defined(OPLUS_FEATURE_MEMLEAK_DETECT) && defined(CONFIG_MEMLEAK_DETECT_THREAD) && defined(CONFIG_SVELTE) +/* add ion memleak detect dameon, + * need CONFIG_DUMP_TASKS_MEM first. + */ +#include "ion_track/ion_track.c" +#endif diff --git a/drivers/staging/android/ion/ion.h b/drivers/staging/android/ion/ion.h index da143d3e49fb..5c0c3fddc8b7 100644 --- a/drivers/staging/android/ion/ion.h +++ b/drivers/staging/android/ion/ion.h @@ -144,6 +144,16 @@ struct ion_buffer { struct sg_table *sg_table; struct list_head attachments; struct list_head vmas; +#if defined(OPLUS_FEATURE_MEMLEAK_DETECT) && defined(CONFIG_DUMP_TASKS_MEM) + /* ion buffer allocator */ + struct task_struct *tsk; +#endif +#if defined(OPLUS_FEATURE_MEMLEAK_DETECT) && defined(CONFIG_MEMLEAK_DETECT_THREAD) + /* add record the buffer + * create time and calc the buffer age on dump. + */ + unsigned long jiffies; +#endif }; void ion_buffer_destroy(struct ion_buffer *buffer); @@ -443,6 +453,7 @@ struct ion_page_pool { struct mutex mutex; gfp_t gfp_mask; unsigned int order; + bool graphic_buffer_flag; struct plist_node list; struct device *dev; }; @@ -461,6 +472,7 @@ void ion_page_pool_free_immediate(struct ion_page_pool *pool, int ion_page_pool_total(struct ion_page_pool *pool, bool high); size_t ion_system_heap_secure_page_pool_total(struct ion_heap *heap, int vmid); +inline struct page *ion_page_pool_alloc_pages(struct ion_page_pool *pool); #ifdef CONFIG_ION_SYSTEM_HEAP long ion_page_pool_nr_pages(void); #else diff --git a/drivers/staging/android/ion/ion_heap.c b/drivers/staging/android/ion/ion_heap.c index 054001c209c0..3cdbf63da5c0 100644 --- a/drivers/staging/android/ion/ion_heap.c +++ b/drivers/staging/android/ion/ion_heap.c @@ -14,6 +14,11 @@ #include #include #include +#if defined(OPLUS_FEATURE_MEMLEAK_DETECT) && defined(CONFIG_DUMP_TASKS_MEM) +#include +#include +#include +#endif #include "ion.h" void *ion_heap_map_kernel(struct ion_heap *heap, @@ -154,6 +159,13 @@ int ion_heap_pages_zero(struct page *page, size_t size, pgprot_t pgprot) void ion_heap_freelist_add(struct ion_heap *heap, struct ion_buffer *buffer) { +#if defined(OPLUS_FEATURE_MEMLEAK_DETECT) && defined(CONFIG_DUMP_TASKS_MEM) + if (buffer->tsk) { + atomic64_sub(buffer->size, &buffer->tsk->ions); + put_task_struct(buffer->tsk); + buffer->tsk = NULL; + } +#endif spin_lock(&heap->free_lock); list_add(&buffer->list, &heap->free_list); heap->free_list_size += buffer->size; diff --git a/drivers/staging/android/ion/ion_page_pool.c b/drivers/staging/android/ion/ion_page_pool.c index 5b86c5fbbe41..e8d7730aa663 100644 --- a/drivers/staging/android/ion/ion_page_pool.c +++ b/drivers/staging/android/ion/ion_page_pool.c @@ -54,7 +54,7 @@ static bool pool_refill_ok(struct ion_page_pool *pool) return true; } -static inline struct page *ion_page_pool_alloc_pages(struct ion_page_pool *pool) +inline struct page *ion_page_pool_alloc_pages(struct ion_page_pool *pool) { if (fatal_signal_pending(current)) return NULL; @@ -70,6 +70,10 @@ static void ion_page_pool_free_pages(struct ion_page_pool *pool, static void ion_page_pool_add(struct ion_page_pool *pool, struct page *page) { mutex_lock(&pool->mutex); +#ifdef OPLUS_FEATURE_HEALTHINFO + zone_page_state_add(1L << pool->order, page_zone(page), + NR_IONCACHE_PAGES); +#endif /* OPLUS_FEATURE_HEALTHINFO */ if (PageHighMem(page)) { list_add_tail(&page->lru, &pool->high_items); pool->high_count++; @@ -121,6 +125,11 @@ static struct page *ion_page_pool_remove(struct ion_page_pool *pool, bool high) pool->low_count--; } +#ifdef OPLUS_FEATURE_HEALTHINFO + zone_page_state_add(-(1L << pool->order), page_zone(page), + NR_IONCACHE_PAGES); +#endif /* OPLUS_FEATURE_HEALTHINFO */ + atomic_dec(&pool->count); list_del(&page->lru); nr_total_pages -= 1 << pool->order; @@ -138,14 +147,23 @@ struct page *ion_page_pool_alloc(struct ion_page_pool *pool, bool *from_pool) if (fatal_signal_pending(current)) return ERR_PTR(-EINTR); - if (*from_pool && mutex_trylock(&pool->mutex)) { - if (pool->high_count) - page = ion_page_pool_remove(pool, true); - else if (pool->low_count) - page = ion_page_pool_remove(pool, false); - mutex_unlock(&pool->mutex); + if (*from_pool) { + if (pool->graphic_buffer_flag) { + mutex_lock(&pool->mutex); + if (pool->high_count) + page = ion_page_pool_remove(pool, true); + else if (pool->low_count) + page = ion_page_pool_remove(pool, false); + mutex_unlock(&pool->mutex); + } else if (mutex_trylock(&pool->mutex)) { + if (pool->high_count) + page = ion_page_pool_remove(pool, true); + else if (pool->low_count) + page = ion_page_pool_remove(pool, false); + mutex_unlock(&pool->mutex); + } } - if (!page) { + if (!page && !(pool->graphic_buffer_flag)) { page = ion_page_pool_alloc_pages(pool); *from_pool = false; } diff --git a/drivers/staging/android/ion/ion_system_heap.c b/drivers/staging/android/ion/ion_system_heap.c index 6754d1367359..15a1ce77330d 100644 --- a/drivers/staging/android/ion/ion_system_heap.c +++ b/drivers/staging/android/ion/ion_system_heap.c @@ -18,6 +18,13 @@ #include #include #include + +#ifndef CONFIG_OPLUS_ION_BOOSTPOOL +#include +#include +#include +#endif + #include #include "ion_system_heap.h" #include "ion.h" @@ -25,6 +32,16 @@ #include "ion_system_secure_heap.h" #include "ion_secure_util.h" +#ifdef CONFIG_OPLUS_ION_BOOSTPOOL +#include "oplus_ion_boost_pool.h" +#include +#endif /* CONFIG_OPLUS_ION_BOOSTPOOL */ + +#ifndef CONFIG_OPLUS_ION_BOOSTPOOL +#define MIN_ION_POOL_PAGES 51200 /*Maintain 200 MB Min ION pool size */ +#define MIN_ION_POOL_PAGES_BOOTUP 102400 /*Allocate 400 MB each ION pool size during bootup */ +#endif + static gfp_t high_order_gfp_flags = (GFP_HIGHUSER | __GFP_ZERO | __GFP_NOWARN | __GFP_NORETRY) & ~__GFP_RECLAIM; static gfp_t low_order_gfp_flags = GFP_HIGHUSER | __GFP_ZERO; @@ -32,6 +49,31 @@ static gfp_t low_order_gfp_flags = GFP_HIGHUSER | __GFP_ZERO; bool pool_auto_refill_en __read_mostly = IS_ENABLED(CONFIG_ION_POOL_AUTO_REFILL); +#ifdef CONFIG_OPLUS_ION_BOOSTPOOL +static struct ion_boost_pool *has_boost_pool(struct ion_system_heap *sys_heap, + struct ion_buffer *buffer) +{ + int vmid = get_secure_vmid(buffer->flags); + + if (vmid > 0) + return NULL; + + if ((buffer->flags & ION_FLAG_POOL_FORCE_ALLOC) || + (buffer->private_flags & ION_PRIV_FLAG_SHRINKER_FREE)) + return NULL; + + if (buffer->flags & ION_FLAG_CAMERA_BUFFER) { + int cached = (int)ion_buffer_cached(buffer); + + if (cached) + return sys_heap->cam_pool; + else + return sys_heap->uncached_boost_pool; + } + return NULL; +} +#endif /* CONFIG_OPLUS_ION_BOOSTPOOL */ + int order_to_index(unsigned int order) { int i; @@ -104,6 +146,18 @@ void free_buffer_page(struct ion_system_heap *heap, bool cached = ion_buffer_cached(buffer); int vmid = get_secure_vmid(buffer->flags); +#ifdef CONFIG_OPLUS_ION_BOOSTPOOL + struct ion_boost_pool *boost_pool = has_boost_pool(heap, buffer); + + if (boost_pool) { + if (0 == boost_pool_free(boost_pool, page, order)) { + mod_node_page_state(page_pgdat(page), NR_UNRECLAIMABLE_PAGES, + -(1 << order)); + return; + } + } +#endif + if (!(buffer->flags & ION_FLAG_POOL_FORCE_ALLOC)) { struct ion_page_pool *pool; @@ -295,6 +349,14 @@ static int ion_system_heap_allocate(struct ion_heap *heap, unsigned int sz; int vmid = get_secure_vmid(buffer->flags); +#ifdef CONFIG_OPLUS_ION_BOOSTPOOL + struct ion_boost_pool *boost_pool = has_boost_pool(sys_heap, buffer); +#ifdef BOOSTPOOL_DEBUG + int boostpool_order[3] = {0}; + unsigned long alloc_start = jiffies; +#endif /* BOOSTPOOL_DEBUG */ +#endif /* CONFIG_OPLUS_ION_BOOSTPOOL */ + if (size / PAGE_SIZE > totalram_pages / 2) return -ENOMEM; @@ -309,6 +371,56 @@ static int ion_system_heap_allocate(struct ion_heap *heap, INIT_LIST_HEAD(&pages); INIT_LIST_HEAD(&pages_from_pool); +#ifdef CONFIG_OPLUS_ION_BOOSTPOOL + if (size < SZ_1M) + boost_pool = NULL; + + if (boost_pool) { + unsigned int alloc_sz = 0; + while (size_remaining > 0) { + +#ifdef OPLUS_FEATURE_UIFIRST + current->static_ux = 2; +#endif /* OPLUS_FEATURE_UIFIRST */ + info = boost_pool_allocate(boost_pool, + size_remaining, + max_order); +#ifdef OPLUS_FEATURE_UIFIRST + current->static_ux = 0; +#endif /* OPLUS_FEATURE_UIFIRST */ + if (!info) + break; + sz = (1 << info->order) * PAGE_SIZE; + alloc_sz += sz; +#ifdef BOOSTPOOL_DEBUG + boostpool_order[order_to_index(info->order)] += 1; +#endif /* BOOSTPOOL_DEBUG */ + + list_add_tail(&info->list, &pages_from_pool); + + mod_node_page_state(page_pgdat(info->page), + NR_UNRECLAIMABLE_PAGES, + (1 << (info->order))); + + size_remaining -= sz; + max_order = info->order; + i++; + } + max_order = orders[0]; + + boost_pool_dec_high(boost_pool, alloc_sz >> PAGE_SHIFT); +#ifdef BOOSTPOOL_DEBUG + if (size_remaining != 0) { + pr_info("boostpool %s alloc failed. alloc_sz: %d size: %d orders(%d, %d, %d) %d ms\n", + boost_pool->name, alloc_sz, (int) size, + boostpool_order[0], boostpool_order[1], + boostpool_order[2], + jiffies_to_msecs(jiffies - alloc_start)); + } +#endif /* BOOSTPOOL_DEBUG */ + } +#endif /* CONFIG_OPLUS_ION_BOOSTPOOL */ + while (size_remaining > 0) { if (is_secure_vmid_valid(vmid)) info = alloc_from_pool_preferred(sys_heap, buffer, @@ -406,6 +518,10 @@ static int ion_system_heap_allocate(struct ion_heap *heap, if (nents_sync) sg_free_table(&table_sync); ion_heap_free_pages_mem(&data); +#ifdef CONFIG_OPLUS_ION_BOOSTPOOL + if (boost_pool) + boost_pool_wakeup_process(boost_pool); +#endif /* CONFIG_OPLUS_ION_BOOSTPOOL */ return 0; err_free_sg2: @@ -475,6 +591,9 @@ static int ion_system_heap_shrink(struct ion_heap *heap, gfp_t gfp_mask, int i, j, nr_freed = 0; int only_scan = 0; struct ion_page_pool *pool; +#ifdef CONFIG_OPLUS_ION_BOOSTPOOL + struct ion_boost_pool *boost_pool; +#endif /* CONFIG_OPLUS_ION_BOOSTPOOL */ sys_heap = container_of(heap, struct ion_system_heap, heap); @@ -484,6 +603,30 @@ static int ion_system_heap_shrink(struct ion_heap *heap, gfp_t gfp_mask, /* shrink the pools starting from lower order ones */ for (i = NUM_ORDERS - 1; i >= 0; i--) { nr_freed = 0; +#ifndef CONFIG_OPLUS_ION_BOOSTPOOL + /* + * Keep minimum 200 MB in the pool so that camera launch latency would remain + * low under heavy memory pressure also. + */ + if (global_zone_page_state(NR_IONCACHE_PAGES) < MIN_ION_POOL_PAGES) + break; +#endif +#ifdef CONFIG_OPLUS_ION_BOOSTPOOL + if (sys_heap->uncached_boost_pool) { + boost_pool = sys_heap->uncached_boost_pool; + nr_freed += boost_pool_shrink(boost_pool, + boost_pool->pools[i], + gfp_mask, + nr_to_scan); + } + if (sys_heap->cam_pool) { + boost_pool = sys_heap->cam_pool; + nr_freed += boost_pool_shrink(boost_pool, + boost_pool->pools[i], + gfp_mask, + nr_to_scan); + } +#endif /* CONFIG_OPLUS_ION_BOOSTPOOL */ for (j = 0; j < VMID_LAST; j++) { if (is_secure_vmid_valid(j)) @@ -619,7 +762,7 @@ static int ion_system_heap_debug_show(struct ion_heap *heap, struct seq_file *s, return 0; } -static void ion_system_heap_destroy_pools(struct ion_page_pool **pools) +void ion_system_heap_destroy_pools(struct ion_page_pool **pools) { int i; @@ -637,9 +780,9 @@ static void ion_system_heap_destroy_pools(struct ion_page_pool **pools) * nothing. If it succeeds you'll eventually need to use * ion_system_heap_destroy_pools to destroy the pools. */ -static int ion_system_heap_create_pools(struct ion_system_heap *sys_heap, +int ion_system_heap_create_pools(struct ion_system_heap *sys_heap, struct ion_page_pool **pools, - bool cached) + bool cached, bool graphic_buffer_flag) { int i; @@ -653,6 +796,7 @@ static int ion_system_heap_create_pools(struct ion_system_heap *sys_heap, if (!pool) goto err_create_pool; pool->dev = sys_heap->heap.priv; + pool->graphic_buffer_flag = graphic_buffer_flag; pools[i] = pool; } return 0; @@ -712,12 +856,68 @@ static struct task_struct *ion_create_kworker(struct ion_page_pool **pools, return thread; } +#ifndef CONFIG_OPLUS_ION_BOOSTPOOL +static int fill_page_pool(struct device *dev, struct ion_page_pool *pool) +{ + struct page *page; + if (NULL == pool) { + pr_err("%s: pool is NULL!\n", __func__); + return -ENOENT; + } + + page = ion_page_pool_alloc_pages(pool); + if (NULL == page) + return -ENOMEM; + + ion_pages_sync_for_device(dev, page, + PAGE_SIZE << pool->order, + DMA_BIDIRECTIONAL); + + ion_page_pool_free(pool, page); + + return 0; +} + +static int fill_pool_kworkthread(void *p) +{ + int i; + struct ion_system_heap * sh; + sh = (struct ion_system_heap *) p; + + pr_info("boot time ION pool filling started\n"); + + for (i = 0; i < NUM_ORDERS; i++) { + while (global_zone_page_state(NR_IONCACHE_PAGES) < + MIN_ION_POOL_PAGES_BOOTUP) { + if (fill_page_pool(sh->heap.priv, sh->cached_pools[i]) < 0) + break; + } + } + + for (i = 0; i < NUM_ORDERS; i++) { + while (global_zone_page_state(NR_IONCACHE_PAGES) < + (2 * MIN_ION_POOL_PAGES_BOOTUP)) { + if (fill_page_pool(sh->heap.priv, sh->uncached_pools[i]) < 0) + break; + } + } + + pr_info("boot time ION pool filling ended\n"); + return 0; +} +#endif struct ion_heap *ion_system_heap_create(struct ion_platform_heap *data) { struct ion_system_heap *heap; int ret = -ENOMEM; int i; +#ifndef CONFIG_OPLUS_ION_BOOSTPOOL + struct task_struct *tsk; +#endif +#ifdef CONFIG_OPLUS_ION_BOOSTPOOL + struct proc_dir_entry *boost_root_dir; +#endif /* CONFIG_OPLUS_ION_BOOSTPOOL */ heap = kzalloc(sizeof(*heap), GFP_KERNEL); if (!heap) @@ -731,13 +931,13 @@ struct ion_heap *ion_system_heap_create(struct ion_platform_heap *data) if (is_secure_vmid_valid(i)) if (ion_system_heap_create_pools(heap, heap->secure_pools[i], - false)) + false, false)) goto destroy_secure_pools; - if (ion_system_heap_create_pools(heap, heap->uncached_pools, false)) + if (ion_system_heap_create_pools(heap, heap->uncached_pools, false, false)) goto destroy_secure_pools; - if (ion_system_heap_create_pools(heap, heap->cached_pools, true)) + if (ion_system_heap_create_pools(heap, heap->cached_pools, true, false)) goto destroy_uncached_pools; if (pool_auto_refill_en) { @@ -756,9 +956,50 @@ struct ion_heap *ion_system_heap_create(struct ion_platform_heap *data) } } +#ifdef CONFIG_OPLUS_ION_BOOSTPOOL + if (kcrit_scene_init()) { + boost_root_dir = proc_mkdir("boost_pool", NULL); + if (!IS_ERR_OR_NULL(boost_root_dir)) { + unsigned long cam_sz = 32 * 256, uncached_sz = 32 * 256; + + /* on low memory target, we should not set 128Mib on camera pool. */ + /* TODO set by total ram pages */ + if (totalram_pages > (SZ_4G >> PAGE_SHIFT)) { + cam_sz = 128 * 256; + uncached_sz = 64 * 256; + } + + heap->uncached_boost_pool = boost_pool_create(heap, + 0, + uncached_sz, + boost_root_dir, + "ion_uncached"); + if (!heap->uncached_boost_pool) + pr_err("%s: create boost_pool ion_uncached failed!\n", + __func__); + + /* on low memory target, we should not set 128Mib on camera pool. */ + /* TODO set by total ram pages */ + heap->cam_pool = boost_pool_create(heap, ION_FLAG_CACHED, + cam_sz, + boost_root_dir, "camera"); + if (!heap->cam_pool) + pr_err("%s: create boost_pool camera failed!\n", + __func__); + } + } else { + pr_err("boostpool kcrit_scene init failed.\n"); + } +#endif /* CONFIG_OPLUS_ION_BOOSTPOOL */ mutex_init(&heap->split_page_mutex); heap->heap.debug_show = ion_system_heap_debug_show; +#ifndef CONFIG_OPLUS_ION_BOOSTPOOL + // Fill ION Pool during boot time + tsk = kthread_run(fill_pool_kworkthread, heap, "ion_pool_refill"); + if (IS_ERR(tsk)) + pr_err("kthread_run fill_pool_kworkthread failed!\n"); +#endif return &heap->heap; destroy_pools: ion_system_heap_destroy_pools(heap->cached_pools); diff --git a/drivers/staging/android/ion/ion_system_heap.h b/drivers/staging/android/ion/ion_system_heap.h index 45daa485fa15..8a56c9c4b75b 100644 --- a/drivers/staging/android/ion/ion_system_heap.h +++ b/drivers/staging/android/ion/ion_system_heap.h @@ -37,6 +37,9 @@ struct ion_system_heap { struct ion_page_pool *secure_pools[VMID_LAST][MAX_ORDER]; /* Prevents unnecessary page splitting */ struct mutex split_page_mutex; +#ifdef CONFIG_OPLUS_ION_BOOSTPOOL + struct ion_boost_pool *uncached_boost_pool, *cam_pool; +#endif /* CONFIG_OPLUS_ION_BOOSTPOOL */ }; struct page_info { @@ -51,5 +54,10 @@ int order_to_index(unsigned int order); void free_buffer_page(struct ion_system_heap *heap, struct ion_buffer *buffer, struct page *page, unsigned int order); +int ion_system_heap_create_pools(struct ion_system_heap *sys_heap, + struct ion_page_pool **pools, + bool cached, bool graphic_buffer_flag); + +void ion_system_heap_destroy_pools(struct ion_page_pool **pools); #endif /* _ION_SYSTEM_HEAP_H */ diff --git a/drivers/staging/android/ion/ion_track b/drivers/staging/android/ion/ion_track new file mode 120000 index 000000000000..9af963f367ce --- /dev/null +++ b/drivers/staging/android/ion/ion_track @@ -0,0 +1 @@ +../../../../../../vendor/oplus/kernel/oplus_performance/memleak_detect/ion_track \ No newline at end of file diff --git a/drivers/staging/android/ion/oplus_ion_boost_pool.c b/drivers/staging/android/ion/oplus_ion_boost_pool.c new file mode 120000 index 000000000000..6db43e11e07e --- /dev/null +++ b/drivers/staging/android/ion/oplus_ion_boost_pool.c @@ -0,0 +1 @@ +../../../../../../vendor/oplus/kernel/oplus_performance/ion_boost_pool/oplus_ion_boost_pool_qcom_4.19.c \ No newline at end of file diff --git a/drivers/staging/android/ion/oplus_ion_boost_pool.h b/drivers/staging/android/ion/oplus_ion_boost_pool.h new file mode 120000 index 000000000000..7edd5e846a19 --- /dev/null +++ b/drivers/staging/android/ion/oplus_ion_boost_pool.h @@ -0,0 +1 @@ +../../../../../../vendor/oplus/kernel/oplus_performance/ion_boost_pool/oplus_ion_boost_pool_qcom_4.19.h \ No newline at end of file diff --git a/drivers/staging/android/uapi/msm_ion.h b/drivers/staging/android/uapi/msm_ion.h index da8c3f1d6ff6..7f4ba2481583 100644 --- a/drivers/staging/android/uapi/msm_ion.h +++ b/drivers/staging/android/uapi/msm_ion.h @@ -73,6 +73,9 @@ enum ion_heap_ids { #define ION_FLAG_CP_CDSP ION_BIT(29) #define ION_FLAG_CP_SPSS_HLOS_SHARED ION_BIT(30) +/* boost pool flag. */ +#define ION_FLAG_CAMERA_BUFFER ION_BIT(13) + #define ION_FLAGS_CP_MASK 0x6FFE0000 /** diff --git a/drivers/thermal/qcom/bcl_peripheral.c b/drivers/thermal/qcom/bcl_peripheral.c index a9cf4f5e1155..aea76598b5db 100644 --- a/drivers/thermal/qcom/bcl_peripheral.c +++ b/drivers/thermal/qcom/bcl_peripheral.c @@ -617,6 +617,7 @@ static void bcl_probe_soc(struct platform_device *pdev) soc_data->ops.get_temp = bcl_read_soc; soc_data->ops.set_trips = bcl_set_soc; INIT_WORK(&bcl_perph->soc_eval_work, bcl_evaluate_soc); +#ifndef OPLUS_BUG_STABILITY bcl_perph->psy_nb.notifier_call = battery_supply_callback; ret = power_supply_reg_notifier(&bcl_perph->psy_nb); if (ret < 0) { @@ -631,6 +632,22 @@ static void bcl_probe_soc(struct platform_device *pdev) return; } thermal_zone_device_update(soc_data->tz_dev, THERMAL_DEVICE_UP); +#else + soc_data->tz_dev = thermal_zone_of_sensor_register(&pdev->dev, + BCL_SOC_MONITOR, soc_data, &soc_data->ops); + if (IS_ERR(soc_data->tz_dev)) { + pr_err("vbat register failed. err:%ld\n", + PTR_ERR(soc_data->tz_dev)); + return; + } + thermal_zone_device_update(soc_data->tz_dev, THERMAL_DEVICE_UP); + bcl_perph->psy_nb.notifier_call = battery_supply_callback; + ret = power_supply_reg_notifier(&bcl_perph->psy_nb); + if (ret < 0) { + pr_err("Unable to register soc notifier. err:%d\n", ret); + return; + } +#endif schedule_work(&bcl_perph->soc_eval_work); } diff --git a/drivers/thermal/qcom/bcl_soc.c b/drivers/thermal/qcom/bcl_soc.c index a375f43ee2a5..bb4c966c511c 100644 --- a/drivers/thermal/qcom/bcl_soc.c +++ b/drivers/thermal/qcom/bcl_soc.c @@ -137,6 +137,8 @@ static int bcl_soc_probe(struct platform_device *pdev) bcl_perph->ops.get_temp = bcl_read_soc; bcl_perph->ops.set_trips = bcl_set_soc; INIT_WORK(&bcl_perph->soc_eval_work, bcl_evaluate_soc); +#ifndef OPLUS_BUG_STABILITY +// Bin.Xu @ BSP.Kernel.Stability, 2020/4/3, add checklist: Fix dump caused by bcl bcl_perph->psy_nb.notifier_call = battery_supply_callback; ret = power_supply_reg_notifier(&bcl_perph->psy_nb); if (ret < 0) { @@ -155,6 +157,26 @@ static int bcl_soc_probe(struct platform_device *pdev) goto bcl_soc_probe_exit; } thermal_zone_device_update(bcl_perph->tz_dev, THERMAL_DEVICE_UP); +#else + bcl_perph->tz_dev = thermal_zone_of_sensor_register(&pdev->dev, + 0, bcl_perph, &bcl_perph->ops); + if (IS_ERR(bcl_perph->tz_dev)) { + pr_err("soc TZ register failed. err:%ld\n", + PTR_ERR(bcl_perph->tz_dev)); + ret = PTR_ERR(bcl_perph->tz_dev); + bcl_perph->tz_dev = NULL; + goto bcl_soc_probe_exit; + } + thermal_zone_device_update(bcl_perph->tz_dev, THERMAL_DEVICE_UP); + bcl_perph->psy_nb.notifier_call = battery_supply_callback; + ret = power_supply_reg_notifier(&bcl_perph->psy_nb); + if (ret < 0) { + pr_err("soc notifier registration error. defer. err:%d\n", + ret); + ret = -EPROBE_DEFER; + goto bcl_soc_probe_exit; + } +#endif /* OPLUS_BUG_STABILITY */ schedule_work(&bcl_perph->soc_eval_work); dev_set_drvdata(&pdev->dev, bcl_perph); diff --git a/drivers/thermal/qcom/qmi_cooling.c b/drivers/thermal/qcom/qmi_cooling.c index 4960d41ea96f..b0146f1ab4ae 100644 --- a/drivers/thermal/qcom/qmi_cooling.c +++ b/drivers/thermal/qcom/qmi_cooling.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include "thermal_mitigation_device_service_v01.h" @@ -244,6 +245,9 @@ static int qmi_set_cur_or_min_state(struct qmi_cooling_device *qmi_cdev, if (!tmd) return -EINVAL; + if (get_eng_version() == HIGH_TEMP_AGING) + return ret; + if (qmi_cdev->mtgn_state == state) return ret; diff --git a/drivers/thermal/qcom/qmi_sensors.c b/drivers/thermal/qcom/qmi_sensors.c index a145040ff5cc..10713fff796d 100644 --- a/drivers/thermal/qcom/qmi_sensors.c +++ b/drivers/thermal/qcom/qmi_sensors.c @@ -250,6 +250,10 @@ void qmi_ts_ind_cb(struct qmi_handle *qmi, struct sockaddr_qrtr *sq, pr_err("Error invalid temperature field.\n"); } +bool ts_wait_error = false, ts_send_error = false; +#ifdef CONFIG_ESOC_MDM_4x +extern bool modem_force_rst; +#endif static int qmi_ts_request(struct qmi_sensor *qmi_sens, bool send_current_temp_report) { @@ -259,9 +263,16 @@ static int qmi_ts_request(struct qmi_sensor *qmi_sens, struct qmi_ts_instance *ts = qmi_sens->ts; struct qmi_txn txn; + static int i = 0, j = 0; + memset(&req, 0, sizeof(req)); memset(&resp, 0, sizeof(resp)); - +#ifdef CONFIG_ESOC_MDM_4x + if (modem_force_rst) { + i = 0; + j = 0; + } +#endif strlcpy(req.sensor_id.sensor_id, qmi_sens->qmi_name, QMI_TS_SENSOR_ID_LENGTH_MAX_V01); req.seq_num = 0; @@ -304,14 +315,26 @@ static int qmi_ts_request(struct qmi_sensor *qmi_sens, if (ret < 0) { pr_err("qmi txn send failed for %s ret:%d\n", qmi_sens->qmi_name, ret); + + if ((ret == -5 || ret == -11 || ret == -12 || ret == -110) && i++ >= 15) { + ts_send_error = true; + i = 0; + } qmi_txn_cancel(&txn); goto qmi_send_exit; + } else { + ts_send_error = false; + i = 0; } ret = qmi_txn_wait(&txn, QMI_TS_RESP_TOUT); if (ret < 0) { pr_err("qmi txn wait failed for %s ret:%d\n", qmi_sens->qmi_name, ret); + if ((ret == -11 || ret == -12 || ret == -110) && j++ >= 15) { + ts_wait_error = true; + j = 0; + } goto qmi_send_exit; } if (resp.resp.result != QMI_RESULT_SUCCESS_V01) { @@ -319,9 +342,20 @@ static int qmi_ts_request(struct qmi_sensor *qmi_sens, pr_err("qmi NOT success for %s ret:%d\n", qmi_sens->qmi_name, ret); goto qmi_send_exit; + } else { + ts_wait_error = false; + j = 0; } - ret = 0; + if (resp.resp.result != QMI_RESULT_SUCCESS_V01) { + ret = resp.resp.result; + pr_err("qmi NOT success for %s ret:%d\n", + qmi_sens->qmi_name, ret); + goto qmi_send_exit; + } + + ret = 0; + qmi_send_exit: mutex_unlock(&ts->mutex); return ret; diff --git a/drivers/thermal/thermal_helpers.c b/drivers/thermal/thermal_helpers.c index 80955c55543a..c0549c719969 100644 --- a/drivers/thermal/thermal_helpers.c +++ b/drivers/thermal/thermal_helpers.c @@ -22,6 +22,11 @@ #include "thermal_core.h" +#ifdef OPLUS_BUG_STABILITY +#include +#include +#endif + int get_tz_trend(struct thermal_zone_device *tz, int trip) { enum thermal_trend trend; @@ -113,6 +118,59 @@ exit: } EXPORT_SYMBOL_GPL(thermal_zone_get_temp); +#ifdef OPLUS_BUG_STABILITY +int thermal_zone_get_temp_workaround(struct thermal_zone_device *tz, int *temp) +{ + int ret = -EINVAL; + int count; + int crit_temp = INT_MAX; + enum thermal_trip_type type; + int i = 30; + + if (!tz || IS_ERR(tz) || !tz->ops->get_temp) + goto exit; + + while(!mutex_trylock(&tz->lock)) + { + if(--i <= 0) + goto last_exit; + msleep(100); + } + + ret = tz->ops->get_temp(tz, temp); + + if (IS_ENABLED(CONFIG_THERMAL_EMULATION) && tz->emul_temperature) { + for (count = 0; count < tz->trips; count++) { + ret = tz->ops->get_trip_type(tz, count, &type); + if (!ret && type == THERMAL_TRIP_CRITICAL) { + ret = tz->ops->get_trip_temp(tz, count, + &crit_temp); + break; + } + } + + /* + * Only allow emulating a temperature when the real temperature + * is below the critical temperature so that the emulation code + * cannot hide critical conditions. + */ + if (!ret && *temp < crit_temp) + *temp = tz->emul_temperature; + } + trace_thermal_query_temp(tz, *temp); + mutex_unlock(&tz->lock); +exit: + return ret; +last_exit: + *temp = tz->last_temperature; + if (tz->last_temperature == THERMAL_TEMP_INVALID || tz->last_temperature == THERMAL_TEMP_INVALID_LOW) + *temp = 0; + printk("QMI arount: Can not get lock, goto last_exit\n"); + return 0; +} +EXPORT_SYMBOL_GPL(thermal_zone_get_temp_workaround); +#endif + void thermal_zone_set_trips(struct thermal_zone_device *tz) { int low = -INT_MAX; diff --git a/drivers/thermal/thermal_sysfs.c b/drivers/thermal/thermal_sysfs.c index f0653d82f205..aa01dc861d2d 100644 --- a/drivers/thermal/thermal_sysfs.c +++ b/drivers/thermal/thermal_sysfs.c @@ -23,6 +23,10 @@ /* sys I/F for thermal zone */ +#ifdef OPLUS_BUG_STABILITY +#include +#endif /* OPLUS_BUG_STABILITY */ + static ssize_t type_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -37,7 +41,11 @@ temp_show(struct device *dev, struct device_attribute *attr, char *buf) struct thermal_zone_device *tz = to_thermal_zone(dev); int temperature, ret; +#ifdef OPLUS_BUG_STABILITY + ret = thermal_zone_get_temp_workaround(tz, &temperature); +#else ret = thermal_zone_get_temp(tz, &temperature); +#endif if (ret) return ret; @@ -1065,6 +1073,12 @@ static void cooling_device_stats_setup(struct thermal_cooling_device *cdev) var += sizeof(*stats->trans_table) * states * states; stats = kzalloc(var, GFP_KERNEL); +#ifdef OPLUS_BUG_STABILITY + if (!stats) { + dev_err(&cdev->device, "need buffer size=%d, try to the vzalloc() func!\n", var); + stats = vzalloc(var); + } +#endif if (!stats) goto out; diff --git a/drivers/tty/serial/msm_geni_serial.c b/drivers/tty/serial/msm_geni_serial.c index d8bd1e55bc32..8e3783dc9034 100644 --- a/drivers/tty/serial/msm_geni_serial.c +++ b/drivers/tty/serial/msm_geni_serial.c @@ -152,6 +152,30 @@ #define DMA_RX_BUF_SIZE (2048) #define UART_CONSOLE_RX_WM (2) +#define CREATE_TRACE_POINTS +#include "serial_trace.h" + +/* FTRACE Logging */ +static void __ftrace_dbg(struct device *dev, const char *fmt, ...) +{ + struct va_format vaf = { + .fmt = fmt, + }; + va_list args; + + va_start(args, fmt); + vaf.va = &args; + trace_serial_info(dev_name(dev), &vaf); + va_end(args); +} + +#define UART_LOG_DBG(ctxt, dev, fmt...) do { \ + ipc_log_string(ctxt, fmt); \ + ftrace_dbg(dev, fmt); \ +} while (0) \ + +#define ftrace_dbg(dev, fmt, ...) \ + __ftrace_dbg(dev, fmt, ##__VA_ARGS__) \ enum uart_error_code { UART_ERROR_DEFAULT, @@ -429,6 +453,20 @@ bool geni_wait_for_cmd_done(struct uart_port *uport, bool is_irq_masked) return timeout ? 0 : 1; } +#ifdef OPLUS_FEATURE_CHG_BASIC +static struct pinctrl *serial_pinctrl = NULL; +static struct pinctrl_state *serial_pinctrl_state_disable = NULL; +#endif +#ifdef OPLUS_FEATURE_CHG_BASIC +extern bool oem_disable_uart(void); +bool boot_with_console(void) +{ + return !oem_disable_uart(); +} + +EXPORT_SYMBOL(boot_with_console); +#endif + static void msm_geni_serial_config_port(struct uart_port *uport, int cfg_flags) { if (cfg_flags & UART_CONFIG_TYPE) @@ -460,8 +498,8 @@ static ssize_t loopback_store(struct device *dev, static DEVICE_ATTR_RW(loopback); -static void dump_ipc(void *ipc_ctx, char *prefix, char *string, - u64 addr, int size) +static void dump_ipc(struct uart_port *uport, void *ipc_ctx, char *prefix, + char *string, u64 addr, int size) { char buf[DATA_BYTES_PER_LINE * 2]; @@ -472,7 +510,7 @@ static void dump_ipc(void *ipc_ctx, char *prefix, char *string, len = min(size, DATA_BYTES_PER_LINE); hex_dump_to_buffer(string, len, DATA_BYTES_PER_LINE, 1, buf, sizeof(buf), false); - ipc_log_string(ipc_ctx, "%s[0x%.10x:%d] : %s", prefix, + UART_LOG_DBG(ipc_ctx, uport->dev, "%s[0x%.10x:%d] : %s", prefix, (unsigned int)addr, size, buf); } @@ -522,6 +560,7 @@ static void wait_for_transfers_inflight(struct uart_port *uport) int iter = 0; struct msm_geni_serial_port *port = GET_DEV_PORT(uport); unsigned int geni_status; + bool CTS, RX; geni_status = geni_read_reg_nolog(uport->membase, SE_GENI_STATUS); /* Possible stop rx is called before this. */ @@ -538,6 +577,19 @@ static void wait_for_transfers_inflight(struct uart_port *uport) } } if (check_transfers_inflight(uport)) { + u32 geni_status = geni_read_reg_nolog(uport->membase, + SE_GENI_STATUS); + u32 geni_ios = geni_read_reg_nolog(uport->membase, SE_GENI_IOS); + u32 rx_fifo_status = geni_read_reg_nolog(uport->membase, + SE_GENI_RX_FIFO_STATUS); + u32 rx_dma = + geni_read_reg_nolog(uport->membase, SE_DMA_RX_LEN_IN); + CTS = geni_ios & BIT(1); // b[1] = UART CTS <- Peer RFR + RX = geni_ios & BIT(0); // b[0] = UART RX <- Peer TX + + UART_LOG_DBG(port->ipc_log_misc, uport->dev, + "%s: geni=0x%x rx_fifo=0x%x rx_dma=0x%x, CTS_IO=%d, RX_IO=%d\n", + __func__, geni_status, rx_fifo_status, rx_dma, CTS, RX); geni_se_dump_dbg_regs(&port->serial_rsc, uport->membase, port->ipc_log_misc); } @@ -558,7 +610,7 @@ static int vote_clock_on(struct uart_port *uport) port->ioctl_count++; usage_count = atomic_read(&uport->dev->power.usage_count); geni_ios = geni_read_reg_nolog(uport->membase, SE_GENI_IOS); - IPC_LOG_MSG(port->ipc_log_pwr, + UART_LOG_DBG(port->ipc_log_pwr, uport->dev, "%s :%s ioctl:%d usage_count:%d edge-Count:%d geni_ios:0x%x\n", __func__, current->comm, port->ioctl_count, usage_count, port->edge_count, geni_ios); @@ -577,7 +629,7 @@ static int vote_clock_off(struct uart_port *uport) if (!port->ioctl_count) { dev_warn(uport->dev, "%s:Imbalanced vote off ioctl %d\n", __func__, port->ioctl_count); - IPC_LOG_MSG(port->ipc_log_pwr, + UART_LOG_DBG(port->ipc_log_pwr, uport->dev, "%s:Imbalanced vote_off from userspace. %d", __func__, port->ioctl_count); return -EPERM; @@ -586,7 +638,7 @@ static int vote_clock_off(struct uart_port *uport) port->ioctl_count--; msm_geni_serial_power_off(uport); usage_count = atomic_read(&uport->dev->power.usage_count); - IPC_LOG_MSG(port->ipc_log_pwr, "%s:%s ioctl:%d usage_count:%d\n", + UART_LOG_DBG(port->ipc_log_pwr, uport->dev, "%s:%s ioctl:%d usage_count:%d\n", __func__, current->comm, port->ioctl_count, usage_count); return 0; }; @@ -648,7 +700,7 @@ static void msm_geni_serial_break_ctl(struct uart_port *uport, int ctl) struct msm_geni_serial_port *port = GET_DEV_PORT(uport); if (!uart_console(uport) && device_pending_suspend(uport)) { - IPC_LOG_MSG(port->ipc_log_misc, + UART_LOG_DBG(port->ipc_log_misc, uport->dev, "%s.Device is suspended, %s\n", __func__, current->comm); return; @@ -676,7 +728,7 @@ static unsigned int msm_geni_serial_get_mctrl(struct uart_port *uport) struct msm_geni_serial_port *port = GET_DEV_PORT(uport); if (!uart_console(uport) && device_pending_suspend(uport)) { - IPC_LOG_MSG(port->ipc_log_misc, + UART_LOG_DBG(port->ipc_log_misc, uport->dev, "%s.Device is suspended, %s\n", __func__, current->comm); return TIOCM_DSR | TIOCM_CAR | TIOCM_CTS; @@ -685,11 +737,7 @@ static unsigned int msm_geni_serial_get_mctrl(struct uart_port *uport) geni_ios = geni_read_reg_nolog(uport->membase, SE_GENI_IOS); if (!(geni_ios & IO2_DATA_IN)) mctrl |= TIOCM_CTS; - else - msm_geni_update_uart_error_code(port, - SOC_ERROR_START_TX_IOS_SOC_RFR_HIGH); - - IPC_LOG_MSG(port->ipc_log_misc, "%s: geni_ios:0x%x, mctrl:0x%x\n", + UART_LOG_DBG(port->ipc_log_misc, uport->dev, "%s: geni_ios:0x%x, mctrl:0x%x\n", __func__, geni_ios, mctrl); return mctrl; } @@ -706,7 +754,7 @@ static void msm_geni_serial_set_mctrl(struct uart_port *uport, struct msm_geni_serial_port *port = GET_DEV_PORT(uport); if (device_pending_suspend(uport)) { - IPC_LOG_MSG(port->ipc_log_misc, + UART_LOG_DBG(port->ipc_log_misc, uport->dev, "%s.Device is suspended, %s: mctrl=0x%x\n", __func__, current->comm, mctrl); return; @@ -721,7 +769,7 @@ static void msm_geni_serial_set_mctrl(struct uart_port *uport, SE_UART_MANUAL_RFR); /* Write to flow control must complete before return to client*/ mb(); - IPC_LOG_MSG(port->ipc_log_misc, + UART_LOG_DBG(port->ipc_log_misc, uport->dev, "%s:%s, mctrl=0x%x, manual_rfr=0x%x, flow=%s\n", __func__, current->comm, mctrl, uart_manual_rfr, (port->manual_flow ? "OFF" : "ON")); @@ -762,12 +810,12 @@ static int msm_geni_serial_power_on(struct uart_port *uport) struct tty_port *tport = &state->port; int lock = mutex_trylock(&tport->mutex); - IPC_LOG_MSG(port->ipc_log_pwr, + UART_LOG_DBG(port->ipc_log_pwr, uport->dev, "%s:Manual resume\n", __func__); pm_runtime_disable(uport->dev); ret = msm_geni_serial_runtime_resume(uport->dev); if (ret) { - IPC_LOG_MSG(port->ipc_log_pwr, + UART_LOG_DBG(port->ipc_log_pwr, uport->dev, "%s:Manual RPM CB failed %d\n", __func__, ret); } else { @@ -781,7 +829,7 @@ static int msm_geni_serial_power_on(struct uart_port *uport) } else { ret = pm_runtime_get_sync(uport->dev); if (ret < 0) { - IPC_LOG_MSG(port->ipc_log_pwr, "%s Err\n", __func__); + UART_LOG_DBG(port->ipc_log_pwr, uport->dev, "%s Err\n", __func__); WARN_ON_ONCE(1); pm_runtime_put_noidle(uport->dev); pm_runtime_set_suspended(uport->dev); @@ -797,7 +845,7 @@ static void msm_geni_serial_power_off(struct uart_port *uport) int usage_count = atomic_read(&uport->dev->power.usage_count); if (!usage_count) { - IPC_LOG_MSG(port->ipc_log_pwr, "%s: Usage Count is already 0\n", + UART_LOG_DBG(port->ipc_log_pwr, uport->dev, "%s: Usage Count is already 0\n", __func__); return; } @@ -966,6 +1014,12 @@ __msm_geni_serial_console_write(struct uart_port *uport, const char *s, int fifo_depth = DEF_FIFO_DEPTH_WORDS; int tx_wm = DEF_TX_WM; +#ifdef OPLUS_FEATURE_CHG_BASIC + if (!boot_with_console()) { + return; + } +#endif + for (i = 0; i < count; i++) { if (s[i] == '\n') new_line++; @@ -1056,11 +1110,12 @@ static void msm_geni_serial_console_write(struct console *co, const char *s, reinit_completion(&port->m_cmd_timeout); geni_abort_m_cmd(uport->membase); timeout = geni_wait_for_cmd_done(uport, true); - if (timeout) + if (timeout){ IPC_LOG_MSG(port->console_log, "%s: tx abort failed 0x%x\n", __func__, geni_read_reg_nolog(uport->membase, SE_GENI_STATUS)); + } } msm_geni_serial_enable_interrupts(uport); @@ -1160,7 +1215,7 @@ static int msm_geni_serial_prep_dma_tx(struct uart_port *uport) if (!xmit_size) return ret; - dump_ipc(msm_port->ipc_log_tx, "DMA Tx", + dump_ipc(uport, msm_port->ipc_log_tx, "DMA Tx", (char *)&xmit->buf[xmit->tail], 0, xmit_size); msm_geni_serial_setup_tx(uport, xmit_size); ret = geni_se_tx_dma_prep(msm_port->wrapper_dev, uport->membase, @@ -1169,7 +1224,7 @@ static int msm_geni_serial_prep_dma_tx(struct uart_port *uport) if (!ret) { msm_port->xmit_size = xmit_size; } else { - IPC_LOG_MSG(msm_port->ipc_log_misc, + UART_LOG_DBG(msm_port->ipc_log_misc, uport->dev, "%s: TX DMA map Fail %d\n", __func__, ret); msm_geni_update_uart_error_code(msm_port, UART_ERROR_TX_DMA_MAP_FAIL); @@ -1192,7 +1247,7 @@ static int msm_geni_serial_prep_dma_tx(struct uart_port *uport) "%s: tx_cancel fail 0x%x\n", __func__, geni_read_reg_nolog(uport->membase, SE_GENI_STATUS)); - IPC_LOG_MSG(msm_port->ipc_log_misc, + UART_LOG_DBG(msm_port->ipc_log_misc, uport->dev, "%s: tx_cancel failed 0x%x\n", __func__, geni_read_reg_nolog(uport->membase, SE_GENI_STATUS)); msm_geni_update_uart_error_code(msm_port, @@ -1210,7 +1265,7 @@ static int msm_geni_serial_prep_dma_tx(struct uart_port *uport) "%s: tx abort failed 0x%x\n", __func__, geni_read_reg_nolog(uport->membase, SE_GENI_STATUS)); - IPC_LOG_MSG(msm_port->ipc_log_misc, + UART_LOG_DBG(msm_port->ipc_log_misc, uport->dev, "%s: tx abort failed 0x%x\n", __func__, geni_read_reg_nolog(uport->membase, SE_GENI_STATUS)); @@ -1230,8 +1285,8 @@ static int msm_geni_serial_prep_dma_tx(struct uart_port *uport) timeout = geni_wait_for_cmd_done(uport, is_irq_masked); - if (timeout) { - IPC_LOG_MSG(msm_port->ipc_log_misc, + if (timeout){ + UART_LOG_DBG(msm_port->ipc_log_misc, uport->dev, "%s: tx fsm reset failed\n", __func__); msm_geni_update_uart_error_code( msm_port, UART_ERROR_TX_FSM_RESET_FAIL); @@ -1262,14 +1317,14 @@ static void msm_geni_serial_start_tx(struct uart_port *uport) static unsigned int ios_log_limit; if (!uart_console(uport) && !pm_runtime_active(uport->dev)) { - IPC_LOG_MSG(msm_port->ipc_log_misc, + UART_LOG_DBG(msm_port->ipc_log_misc, uport->dev, "%s.Putting in async RPM vote\n", __func__); pm_runtime_get(uport->dev); goto exit_start_tx; } if (!uart_console(uport)) { - IPC_LOG_MSG(msm_port->ipc_log_misc, + UART_LOG_DBG(msm_port->ipc_log_misc, uport->dev, "%s.Power on.\n", __func__); pm_runtime_get(uport->dev); } @@ -1303,7 +1358,7 @@ static void msm_geni_serial_start_tx(struct uart_port *uport) check_flow_ctrl: geni_ios = geni_read_reg_nolog(uport->membase, SE_GENI_IOS); if (++ios_log_limit % 5 == 0) { - IPC_LOG_MSG(msm_port->ipc_log_misc, "%s: ios: 0x%08x\n", + UART_LOG_DBG(msm_port->ipc_log_misc, uport->dev, "%s: ios: 0x%08x\n", __func__, geni_ios); ios_log_limit = 0; } @@ -1324,7 +1379,7 @@ static void stop_tx_sequencer(struct uart_port *uport) if (!(geni_status & M_GENI_CMD_ACTIVE)) return; - IPC_LOG_MSG(port->ipc_log_misc, + UART_LOG_DBG(port->ipc_log_misc, uport->dev, "%s: Start GENI: 0x%x\n", __func__, geni_status); port->m_cmd_done = false; @@ -1342,7 +1397,7 @@ static void stop_tx_sequencer(struct uart_port *uport) if (timeout) { IPC_LOG_MSG(port->console_log, "%s: tx_cancel failed 0x%x\n", __func__, geni_read_reg_nolog(uport->membase, SE_GENI_STATUS)); - IPC_LOG_MSG(port->ipc_log_misc, "%s: tx_cancel failed 0x%x\n", + UART_LOG_DBG(port->ipc_log_misc, uport->dev, "%s: tx_cancel failed 0x%x\n", __func__, geni_read_reg_nolog(uport->membase, SE_GENI_STATUS)); msm_geni_update_uart_error_code(port, UART_ERROR_TX_CANCEL_FAIL); @@ -1356,7 +1411,7 @@ static void stop_tx_sequencer(struct uart_port *uport) IPC_LOG_MSG(port->console_log, "%s: tx abort failed 0x%x\n", __func__, geni_read_reg_nolog(uport->membase, SE_GENI_STATUS)); - IPC_LOG_MSG(port->ipc_log_misc, + UART_LOG_DBG(port->ipc_log_misc, uport->dev, "%s: tx abort failed 0x%x\n", __func__, geni_read_reg_nolog(uport->membase, SE_GENI_STATUS)); msm_geni_update_uart_error_code(port, @@ -1374,8 +1429,8 @@ static void stop_tx_sequencer(struct uart_port *uport) timeout = geni_wait_for_cmd_done(uport, is_irq_masked); - if (timeout) { - IPC_LOG_MSG(port->ipc_log_misc, + if (timeout){ + UART_LOG_DBG(port->ipc_log_misc, uport->dev, "%s: tx fsm reset failed\n", __func__); msm_geni_update_uart_error_code(port, UART_ERROR_TX_FSM_RESET_FAIL); @@ -1401,12 +1456,12 @@ static void stop_tx_sequencer(struct uart_port *uport) * this out, remove the vote put in during start_tx(). */ if (!uart_console(uport)) { - IPC_LOG_MSG(port->ipc_log_misc, "%s:Removing vote\n", __func__); + UART_LOG_DBG(port->ipc_log_misc, uport->dev, "%s:Removing vote\n", __func__); msm_geni_serial_power_off(uport); } geni_status = geni_read_reg_nolog(uport->membase, SE_GENI_STATUS); - IPC_LOG_MSG(port->ipc_log_misc, "%s: End GENI:0x%x\n", + UART_LOG_DBG(port->ipc_log_misc, uport->dev, "%s: End GENI:0x%x\n", __func__, geni_status); } @@ -1416,7 +1471,7 @@ static void msm_geni_serial_stop_tx(struct uart_port *uport) if (!uart_console(uport) && device_pending_suspend(uport)) { dev_err(uport->dev, "%s.Device is suspended.\n", __func__); - IPC_LOG_MSG(port->ipc_log_misc, + UART_LOG_DBG(port->ipc_log_misc, uport->dev, "%s.Device is suspended.\n", __func__); return; } @@ -1433,14 +1488,13 @@ static void start_rx_sequencer(struct uart_port *uport) return; geni_status = geni_read_reg_nolog(uport->membase, SE_GENI_STATUS); - IPC_LOG_MSG(port->ipc_log_misc, "%s: 0x%x\n", + UART_LOG_DBG(port->ipc_log_misc, uport->dev, "%s: geni_status 0x%x\n", __func__, geni_status); if (geni_status & S_GENI_CMD_ACTIVE) { if (port->xfer_mode == SE_DMA) { - IPC_LOG_MSG(port->ipc_log_misc, - "%s: mapping rx dma GENI: 0x%x\n", - __func__, geni_status); + UART_LOG_DBG(port->ipc_log_misc, uport->dev, + "%s: GENI: 0x%x\n", __func__, geni_status); geni_se_rx_dma_start(uport->membase, DMA_RX_BUF_SIZE, &port->rx_dma); } @@ -1461,7 +1515,7 @@ static void start_rx_sequencer(struct uart_port *uport) /* Ensure that the above writes go through */ mb(); geni_status = geni_read_reg_nolog(uport->membase, SE_GENI_STATUS); - IPC_LOG_MSG(port->ipc_log_misc, "%s: 0x%x, dma_dbg:0x%x\n", __func__, + UART_LOG_DBG(port->ipc_log_misc, uport->dev, "%s: 0x%x, dma_dbg:0x%x\n", __func__, geni_status, geni_read_reg(uport->membase, SE_DMA_DEBUG_REG0)); } @@ -1471,7 +1525,7 @@ static void msm_geni_serial_start_rx(struct uart_port *uport) if (!uart_console(uport) && device_pending_suspend(uport)) { dev_err(uport->dev, "%s.Device is suspended.\n", __func__); - IPC_LOG_MSG(port->ipc_log_misc, + UART_LOG_DBG(port->ipc_log_misc, uport->dev, "%s.Device is suspended.\n", __func__); return; } @@ -1498,7 +1552,7 @@ static void msm_geni_serial_set_manual_flow(bool enable, * doing a stop_rx. */ mb(); - IPC_LOG_MSG(port->ipc_log_misc, + UART_LOG_DBG(port->ipc_log_misc, port->uport.dev, "%s: Manual Flow Enabled, HW Flow OFF\n", __func__); } else { geni_write_reg_nolog(0, port->uport.membase, @@ -1507,7 +1561,7 @@ static void msm_geni_serial_set_manual_flow(bool enable, mb(); uart_manual_rfr = geni_read_reg_nolog(port->uport.membase, SE_UART_MANUAL_RFR); - IPC_LOG_MSG(port->ipc_log_misc, + UART_LOG_DBG(port->ipc_log_misc, port->uport.dev, "%s: Manual Flow Disabled, HW Flow ON rfr = 0x%x\n", __func__, uart_manual_rfr); } @@ -1524,12 +1578,12 @@ static int stop_rx_sequencer(struct uart_port *uport) int usage_count; int iter = 0; - IPC_LOG_MSG(port->ipc_log_misc, "%s\n", __func__); + UART_LOG_DBG(port->ipc_log_misc, uport->dev, "%s\n", __func__); geni_status = geni_read_reg_nolog(uport->membase, SE_GENI_STATUS); /* Possible stop rx is called multiple times. */ if (!(geni_status & S_GENI_CMD_ACTIVE)) { - IPC_LOG_MSG(port->ipc_log_misc, + UART_LOG_DBG(port->ipc_log_misc, uport->dev, "%s: RX is Inactive, geni_sts: 0x%x\n", __func__, geni_status); return 0; @@ -1564,7 +1618,7 @@ static int stop_rx_sequencer(struct uart_port *uport) SE_GENI_S_IRQ_CLEAR); geni_se_dump_dbg_regs(&port->serial_rsc, uport->membase, port->ipc_log_misc); - IPC_LOG_MSG(port->ipc_log_misc, "%s: Interrupt delay\n", + UART_LOG_DBG(port->ipc_log_misc, uport->dev, "%s: Interrupt delay\n", __func__); handle_rx_dma_xfer(s_irq_status, uport); if (!port->ioctl_count) { @@ -1579,7 +1633,7 @@ static int stop_rx_sequencer(struct uart_port *uport) } } - IPC_LOG_MSG(port->ipc_log_misc, "%s: Start 0x%x\n", + UART_LOG_DBG(port->ipc_log_misc, uport->dev, "%s: Start 0x%x\n", __func__, geni_status); /* * Try disabling interrupts before giving the @@ -1602,10 +1656,10 @@ static int stop_rx_sequencer(struct uart_port *uport) geni_status = geni_read_reg_nolog(uport->membase, SE_GENI_STATUS); is_rx_active = geni_status & S_GENI_CMD_ACTIVE; - IPC_LOG_MSG(port->ipc_log_misc, "%s: 0x%x, dma_dbg:0x%x\n", __func__, + UART_LOG_DBG(port->ipc_log_misc, uport->dev, "%s: 0x%x, dma_dbg:0x%x\n", __func__, geni_status, geni_read_reg(uport->membase, SE_DMA_DEBUG_REG0)); if (timeout || is_rx_active) { - IPC_LOG_MSG(port->ipc_log_misc, + UART_LOG_DBG(port->ipc_log_misc, uport->dev, "%s cancel failed timeout:%d is_rx_active:%d 0x%x\n", __func__, timeout, is_rx_active, geni_status); IPC_LOG_MSG(port->console_log, @@ -1639,7 +1693,7 @@ static int stop_rx_sequencer(struct uart_port *uport) if (timeout || is_rx_active) { geni_status = geni_read_reg_nolog(uport->membase, SE_GENI_STATUS); - IPC_LOG_MSG(port->ipc_log_misc, + UART_LOG_DBG(port->ipc_log_misc, uport->dev, "%s abort fail timeout:%d is_rx_active:%d 0x%x\n", __func__, timeout, is_rx_active, geni_status); IPC_LOG_MSG(port->console_log, @@ -1659,8 +1713,8 @@ static int stop_rx_sequencer(struct uart_port *uport) timeout = geni_wait_for_cmd_done(uport, is_irq_masked); - if (timeout) { - IPC_LOG_MSG(port->ipc_log_misc, + if (timeout){ + UART_LOG_DBG(port->ipc_log_misc, uport->dev, "%s: rx fsm reset failed\n", __func__); msm_geni_update_uart_error_code(port, UART_ERROR_RX_FSM_RESET_FAIL); @@ -1676,7 +1730,7 @@ exit_rx_seq: msm_geni_serial_set_manual_flow(true, port); geni_status = geni_read_reg_nolog(uport->membase, SE_GENI_STATUS); - IPC_LOG_MSG(port->ipc_log_misc, "%s: End 0x%x dma_dbg:0x%x\n", + UART_LOG_DBG(port->ipc_log_misc, uport->dev, "%s: End 0x%x dma_dbg:0x%x\n", __func__, geni_status, geni_read_reg(uport->membase, SE_DMA_DEBUG_REG0)); @@ -1693,13 +1747,13 @@ static void msm_geni_serial_stop_rx(struct uart_port *uport) int ret; if (!uart_console(uport) && device_pending_suspend(uport)) { - IPC_LOG_MSG(port->ipc_log_misc, + UART_LOG_DBG(port->ipc_log_misc, uport->dev, "%s.Device is suspended.\n", __func__); return; } ret = stop_rx_sequencer(uport); if (ret) - IPC_LOG_MSG(port->ipc_log_misc, "%s: stop rx failed %d\n", + UART_LOG_DBG(port->ipc_log_misc, uport->dev, "%s: stop rx failed %d\n", __func__, ret); } @@ -1736,7 +1790,7 @@ static int handle_rx_hs(struct uart_port *uport, } uport->icount.rx += ret; tty_flip_buffer_push(tport); - dump_ipc(msm_port->ipc_log_rx, "Rx", (char *)msm_port->rx_fifo, 0, + dump_ipc(uport, msm_port->ipc_log_rx, "Rx", (char *)msm_port->rx_fifo, 0, rx_bytes); return ret; } @@ -1910,20 +1964,20 @@ static int msm_geni_serial_handle_dma_rx(struct uart_port *uport, bool drop_rx) geni_status = geni_read_reg_nolog(uport->membase, SE_GENI_STATUS); /* Possible stop rx is called */ if (!(geni_status & S_GENI_CMD_ACTIVE)) { - IPC_LOG_MSG(msm_port->ipc_log_misc, + UART_LOG_DBG(msm_port->ipc_log_misc, uport->dev, "%s: GENI: 0x%x\n", __func__, geni_status); return 0; } if (unlikely(!msm_port->rx_buf)) { - IPC_LOG_MSG(msm_port->ipc_log_rx, "%s: NULL Rx_buf\n", + UART_LOG_DBG(msm_port->ipc_log_rx, uport->dev, "%s: NULL Rx_buf\n", __func__); return 0; } rx_bytes = geni_read_reg_nolog(uport->membase, SE_DMA_RX_LEN_IN); if (unlikely(!rx_bytes)) { - IPC_LOG_MSG(msm_port->ipc_log_rx, "%s: Size %d\n", + UART_LOG_DBG(msm_port->ipc_log_rx, uport->dev, "%s: Size %d\n", __func__, rx_bytes); goto exit_handle_dma_rx; } @@ -1944,7 +1998,7 @@ static int msm_geni_serial_handle_dma_rx(struct uart_port *uport, bool drop_rx) } uport->icount.rx += ret; tty_flip_buffer_push(tport); - dump_ipc(msm_port->ipc_log_rx, "DMA Rx", (char *)msm_port->rx_buf, 0, + dump_ipc(uport, msm_port->ipc_log_rx, "DMA Rx", (char *)msm_port->rx_buf, 0, rx_bytes); /* @@ -1979,7 +2033,7 @@ static int msm_geni_serial_handle_dma_tx(struct uart_port *uport) * allowing the device to suspend. */ if (!uart_console(uport)) { - IPC_LOG_MSG(msm_port->ipc_log_misc, + UART_LOG_DBG(msm_port->ipc_log_misc, uport->dev, "%s.Tx sent out, Power off\n", __func__); msm_geni_serial_power_off(uport); } @@ -2004,7 +2058,7 @@ static bool handle_rx_dma_xfer(u32 s_irq_status, struct uart_port *uport) SE_DMA_RX_IRQ_CLR); if (dma_rx_status & RX_RESET_DONE) { - IPC_LOG_MSG(msm_port->ipc_log_misc, + UART_LOG_DBG(msm_port->ipc_log_misc, uport->dev, "%s.Reset done. 0x%x.\n", __func__, dma_rx_status); ret = true; goto exit; @@ -2013,7 +2067,7 @@ static bool handle_rx_dma_xfer(u32 s_irq_status, struct uart_port *uport) if (dma_rx_status & UART_DMA_RX_ERRS) { if (dma_rx_status & UART_DMA_RX_PARITY_ERR) uport->icount.parity++; - IPC_LOG_MSG(msm_port->ipc_log_misc, + UART_LOG_DBG(msm_port->ipc_log_misc, uport->dev, "%s.Rx Errors. 0x%x parity:%d\n", __func__, dma_rx_status, uport->icount.parity); @@ -2022,7 +2076,7 @@ static bool handle_rx_dma_xfer(u32 s_irq_status, struct uart_port *uport) drop_rx = true; } else if (dma_rx_status & UART_DMA_RX_BREAK) { uport->icount.brk++; - IPC_LOG_MSG(msm_port->ipc_log_misc, + UART_LOG_DBG(msm_port->ipc_log_misc, uport->dev, "%s.Rx Errors. 0x%x break:%d\n", __func__, dma_rx_status, uport->icount.brk); @@ -2040,13 +2094,13 @@ static bool handle_rx_dma_xfer(u32 s_irq_status, struct uart_port *uport) geni_se_rx_dma_start(uport->membase, DMA_RX_BUF_SIZE, &msm_port->rx_dma); } else { - IPC_LOG_MSG(msm_port->ipc_log_misc, + UART_LOG_DBG(msm_port->ipc_log_misc, uport->dev, "%s. not mapping rx dma\n", __func__); } } if (dma_rx_status & RX_SBE) { - IPC_LOG_MSG(msm_port->ipc_log_misc, + UART_LOG_DBG(msm_port->ipc_log_misc, uport->dev, "%s.Rx Errors. 0x%x\n", __func__, dma_rx_status); msm_geni_update_uart_error_code(msm_port, @@ -2117,13 +2171,17 @@ static void msm_geni_serial_handle_isr(struct uart_port *uport, goto exit_geni_serial_isr; } - if (m_irq_status & (M_IO_DATA_ASSERT_EN | M_IO_DATA_DEASSERT_EN)) + if (m_irq_status & (M_IO_DATA_ASSERT_EN | M_IO_DATA_DEASSERT_EN)){ uport->icount.cts++; + UART_LOG_DBG(msm_port->ipc_log_misc, uport->dev, + "%s. cts counter:%d\n", __func__, + uport->icount.cts); + } if (s_irq_status & S_RX_FIFO_WR_ERR_EN) { uport->icount.overrun++; tty_insert_flip_char(tport, 0, TTY_OVERRUN); - IPC_LOG_MSG(msm_port->ipc_log_misc, + UART_LOG_DBG(msm_port->ipc_log_misc, uport->dev, "%s.sirq 0x%x buf_overrun:%d\n", __func__, s_irq_status, uport->icount.buf_overrun); msm_geni_update_uart_error_code(msm_port, @@ -2146,13 +2204,13 @@ static void msm_geni_serial_handle_isr(struct uart_port *uport, if (s_irq_status & (S_GP_IRQ_0_EN | S_GP_IRQ_1_EN)) { if (s_irq_status & S_GP_IRQ_0_EN) uport->icount.parity++; - IPC_LOG_MSG(msm_port->ipc_log_misc, + UART_LOG_DBG(msm_port->ipc_log_misc, uport->dev, "%s.sirq 0x%x parity:%d\n", __func__, s_irq_status, uport->icount.parity); drop_rx = true; } else if (s_irq_status & (S_GP_IRQ_2_EN | S_GP_IRQ_3_EN)) { uport->icount.brk++; - IPC_LOG_MSG(msm_port->ipc_log_misc, + UART_LOG_DBG(msm_port->ipc_log_misc, uport->dev, "%s.sirq 0x%x break:%d\n", __func__, s_irq_status, uport->icount.brk); } @@ -2203,7 +2261,7 @@ static void msm_geni_serial_handle_isr(struct uart_port *uport, msm_geni_serial_handle_dma_tx(uport); } - if (m_irq_status & (M_CMD_CANCEL_EN | M_CMD_ABORT_EN)) + if (m_irq_status & (M_CMD_CANCEL_EN | M_CMD_ABORT_EN)) m_cmd_done = true; if (dma_rx_status) @@ -2211,6 +2269,7 @@ static void msm_geni_serial_handle_isr(struct uart_port *uport, if (s_irq_status & (S_CMD_CANCEL_EN | S_CMD_ABORT_EN)) s_cmd_done = true; + } exit_geni_serial_isr: @@ -2244,12 +2303,12 @@ static irqreturn_t msm_geni_wakeup_isr(int isr, void *dev) unsigned long flags; spin_lock_irqsave(&uport->lock, flags); - IPC_LOG_MSG(port->ipc_log_rx, "%s: Edge-Count %d\n", __func__, + UART_LOG_DBG(port->ipc_log_rx, uport->dev, "%s: Edge-Count %d\n", __func__, port->edge_count); if (port->wakeup_byte && (port->edge_count == 2)) { tty = uport->state->port.tty; tty_insert_flip_char(tty->port, port->wakeup_byte, TTY_NORMAL); - IPC_LOG_MSG(port->ipc_log_rx, "%s: Inject 0x%x\n", + UART_LOG_DBG(port->ipc_log_rx, uport->dev, "%s: Inject 0x%x\n", __func__, port->wakeup_byte); port->edge_count = 0; tty_flip_buffer_push(tty->port); @@ -2315,7 +2374,7 @@ static void msm_geni_serial_shutdown(struct uart_port *uport) struct msm_geni_serial_port *msm_port = GET_DEV_PORT(uport); int ret; - IPC_LOG_MSG(msm_port->ipc_log_misc, "%s:\n", __func__); + UART_LOG_DBG(msm_port->ipc_log_misc, uport->dev, "%s:\n", __func__); /* Stop the console before stopping the current tx */ if (uart_console(uport)) { console_stop(uport->cons); @@ -2331,7 +2390,7 @@ static void msm_geni_serial_shutdown(struct uart_port *uport) int i; for (i = 0; i < msm_port->ioctl_count; i++) { - IPC_LOG_MSG(msm_port->ipc_log_pwr, + UART_LOG_DBG(msm_port->ipc_log_pwr, uport->dev, "%s IOCTL vote present. Forcing off\n", __func__); msm_geni_serial_power_off(uport); @@ -2342,7 +2401,7 @@ static void msm_geni_serial_shutdown(struct uart_port *uport) flush_workqueue(msm_port->qwork); ret = pm_runtime_put_sync_suspend(uport->dev); if (ret) { - IPC_LOG_MSG(msm_port->ipc_log_pwr, + UART_LOG_DBG(msm_port->ipc_log_pwr, uport->dev, "%s: Failed to suspend:%d\n", __func__, ret); } @@ -2355,7 +2414,7 @@ static void msm_geni_serial_shutdown(struct uart_port *uport) /* Reset UART error to default during port_close() */ msm_port->uart_error = UART_ERROR_DEFAULT; } - IPC_LOG_MSG(msm_port->ipc_log_misc, "%s: End\n", __func__); + UART_LOG_DBG(msm_port->ipc_log_misc, uport->dev, "%s: End\n", __func__); } static int msm_geni_serial_port_setup(struct uart_port *uport) @@ -2449,7 +2508,7 @@ static int msm_geni_serial_startup(struct uart_port *uport) int ret = 0; struct msm_geni_serial_port *msm_port = GET_DEV_PORT(uport); - IPC_LOG_MSG(msm_port->ipc_log_misc, "%s:\n", __func__); + UART_LOG_DBG(msm_port->ipc_log_misc, uport->dev, "%s: Start\n", __func__); msm_port->startup_in_progress = true; @@ -2466,7 +2525,7 @@ static int msm_geni_serial_startup(struct uart_port *uport) if (!msm_port->port_setup) { ret = msm_geni_serial_port_setup(uport); if (ret) { - IPC_LOG_MSG(msm_port->ipc_log_misc, + UART_LOG_DBG(msm_port->ipc_log_misc, uport->dev, "%s: port_setup Fail ret:%d\n", __func__, ret); goto exit_startup; @@ -2510,7 +2569,7 @@ exit_startup: if (likely(!uart_console(uport))) msm_geni_serial_power_off(&msm_port->uport); msm_port->startup_in_progress = false; - IPC_LOG_MSG(msm_port->ipc_log_misc, "%s: ret:%d\n", __func__, ret); + UART_LOG_DBG(msm_port->ipc_log_misc, uport->dev, "%s: ret:%d\n", __func__, ret); return ret; } @@ -2617,7 +2676,7 @@ static void msm_geni_serial_set_termios(struct uart_port *uport, int ret = msm_geni_serial_power_on(uport); if (ret) { - IPC_LOG_MSG(port->ipc_log_misc, + UART_LOG_DBG(port->ipc_log_misc, uport->dev, "%s: Failed to vote clock on:%d\n", __func__, ret); return; @@ -2656,7 +2715,7 @@ static void msm_geni_serial_set_termios(struct uart_port *uport, clk_freq_diff = (desired_rate - (clk_rate / clk_div)); if (clk_freq_diff) - IPC_LOG_MSG(port->ipc_log_misc, + UART_LOG_DBG(port->ipc_log_misc, uport->dev, "src_clk freq_diff:%d baud:%d clk_rate:%d clk_div:%d\n", clk_freq_diff, baud, clk_rate, clk_div); @@ -2738,16 +2797,16 @@ static void msm_geni_serial_set_termios(struct uart_port *uport, if (termios->c_cflag & CRTSCTS) { geni_write_reg_nolog(0x0, uport->membase, SE_UART_MANUAL_RFR); - IPC_LOG_MSG(port->ipc_log_misc, + UART_LOG_DBG(port->ipc_log_misc, uport->dev, "%s: Manual flow Disabled, HW Flow ON\n", __func__); } - IPC_LOG_MSG(port->ipc_log_misc, "%s: baud %d\n", __func__, baud); - IPC_LOG_MSG(port->ipc_log_misc, "Tx: trans_cfg%d parity %d\n", + UART_LOG_DBG(port->ipc_log_misc, uport->dev, "%s: baud %d\n", __func__, baud); + UART_LOG_DBG(port->ipc_log_misc, uport->dev, "Tx: trans_cfg%d parity %d\n", tx_trans_cfg, tx_parity_cfg); - IPC_LOG_MSG(port->ipc_log_misc, "Rx: trans_cfg%d parity %d", + UART_LOG_DBG(port->ipc_log_misc, uport->dev, "Rx: trans_cfg%d parity %d\n", rx_trans_cfg, rx_parity_cfg); - IPC_LOG_MSG(port->ipc_log_misc, "BitsChar%d stop bit%d\n", + UART_LOG_DBG(port->ipc_log_misc, uport->dev, "BitsChar%d stop bit%d\n", bits_per_char, stop_bit_len); exit_set_termios: msm_geni_serial_start_rx(uport); @@ -3261,7 +3320,7 @@ static int msm_geni_serial_get_ver_info(struct uart_port *uport) msm_port->ver_info.m_fw_ver = get_se_m_fw(uport->membase); msm_port->ver_info.s_fw_ver = get_se_s_fw(uport->membase); - IPC_LOG_MSG(msm_port->ipc_log_misc, "%s: FW Ver:0x%x%x\n", + UART_LOG_DBG(msm_port->ipc_log_misc, uport->dev, "%s: FW Ver:0x%x%x\n", __func__, msm_port->ver_info.m_fw_ver, msm_port->ver_info.s_fw_ver); @@ -3273,7 +3332,7 @@ static int msm_geni_serial_get_ver_info(struct uart_port *uport) dev_err(uport->dev, "%s:Err getting HW version %d\n", __func__, hw_ver); else - IPC_LOG_MSG(msm_port->ipc_log_misc, "%s: HW Ver:%x.%x.%x\n", + UART_LOG_DBG(msm_port->ipc_log_misc, uport->dev, "%s: HW Ver:%x.%x.%x\n", __func__, msm_port->ver_info.hw_major_ver, msm_port->ver_info.hw_minor_ver, msm_port->ver_info.hw_step_ver); @@ -3285,6 +3344,30 @@ exit_ver_info: return ret; } +#ifdef OPLUS_FEATURE_CHG_BASIC +static bool oplus_charge_id_reconfig(struct platform_device *pdev, struct uart_driver *drv) +{ + //TODO: add charger id control here + if (drv == &msm_geni_console_driver) { + pr_err("%s: console start get pinctrl\n", __FUNCTION__); + serial_pinctrl = devm_pinctrl_get(&pdev->dev); + if (IS_ERR_OR_NULL(serial_pinctrl)) { + dev_err(&pdev->dev, "No serial_pinctrl config specified!\n"); + } else { + serial_pinctrl_state_disable = + pinctrl_lookup_state(serial_pinctrl, PINCTRL_SLEEP); + if (IS_ERR_OR_NULL(serial_pinctrl_state_disable)) { + dev_err(&pdev->dev, "No serial_pinctrl_state_disable config specified!\n"); + } else { + pinctrl_select_state(serial_pinctrl, serial_pinctrl_state_disable); + } + } + return true; + } + return false; +} +#endif + static int msm_geni_serial_probe(struct platform_device *pdev) { int ret = 0; @@ -3308,6 +3391,13 @@ static int msm_geni_serial_probe(struct platform_device *pdev) __func__); return -ENODEV; } + + +#ifdef OPLUS_FEATURE_CHG_BASIC + if (!boot_with_console() && oplus_charge_id_reconfig(pdev, drv)) { + return -ENODEV; + } +#endif if (pdev->dev.of_node) { if (drv->cons) { @@ -3571,10 +3661,12 @@ static int msm_geni_serial_probe(struct platform_device *pdev) ret = uart_add_one_port(drv, uport); if (ret) goto exit_workqueue_destroy; - if (!uart_console(uport)) spin_lock_init(&dev_port->rx_lock); + + + /* * Earlyconsole to kernel console will switch happen after * uart_add_one_port. Hence marking is_earlycon to false here. @@ -3582,7 +3674,8 @@ static int msm_geni_serial_probe(struct platform_device *pdev) if (is_console) is_earlycon = false; - IPC_LOG_MSG(dev_port->ipc_log_misc, "%s: port:%s irq:%d\n", __func__, + + UART_LOG_DBG(dev_port->ipc_log_misc, uport->dev, "%s: port:%s irq:%d\n", __func__, uport->name, uport->irq); return 0; @@ -3594,7 +3687,7 @@ exit_wakeup_unregister: if (!is_console) wakeup_source_unregister(dev_port->geni_wake); exit_geni_serial_probe: - IPC_LOG_MSG(dev_port->ipc_log_misc, "%s: ret:%d\n", __func__, ret); + UART_LOG_DBG(dev_port->ipc_log_misc, &pdev->dev, "%s: ret:%d\n", __func__, ret); return ret; } @@ -3629,7 +3722,7 @@ static void msm_geni_serial_allow_rx(struct msm_geni_serial_port *port) mb(); uart_manual_rfr = geni_read_reg_nolog(port->uport.membase, SE_UART_MANUAL_RFR); - IPC_LOG_MSG(port->ipc_log_misc, "%s(): rfr = 0x%x\n", + UART_LOG_DBG(port->ipc_log_misc, port->uport.dev, "%s(): rfr = 0x%x\n", __func__, uart_manual_rfr); /* To give control of RFR back to HW */ @@ -3655,7 +3748,7 @@ static int msm_geni_serial_runtime_suspend(struct device *dev) */ ret = stop_rx_sequencer(&port->uport); if (ret) { - IPC_LOG_MSG(port->ipc_log_pwr, "%s: stop rx failed %d\n", + UART_LOG_DBG(port->ipc_log_pwr, dev, "%s: stop rx failed %d\n", __func__, ret); /* Flow on from UART */ msm_geni_serial_allow_rx(port); @@ -3686,7 +3779,7 @@ static int msm_geni_serial_runtime_suspend(struct device *dev) port->edge_count = 0; enable_irq(port->wakeup_irq); } - IPC_LOG_MSG(port->ipc_log_pwr, "%s: End\n", __func__); + UART_LOG_DBG(port->ipc_log_pwr, dev, "%s: End\n", __func__); __pm_relax(port->geni_wake); exit_runtime_suspend: return ret; @@ -3698,6 +3791,7 @@ static int msm_geni_serial_runtime_resume(struct device *dev) struct msm_geni_serial_port *port = platform_get_drvdata(pdev); int ret = 0; + UART_LOG_DBG(port->ipc_log_pwr, dev, "%s: Start\n", __func__); /* * Do an unconditional relax followed by a stay awake in case the * wake source is activated by the wakeup isr. @@ -3726,7 +3820,7 @@ static int msm_geni_serial_runtime_resume(struct device *dev) /* Enable interrupt */ enable_irq(port->uport.irq); - IPC_LOG_MSG(port->ipc_log_pwr, "%s:\n", __func__); + UART_LOG_DBG(port->ipc_log_pwr, dev, "%s: End\n", __func__); exit_runtime_resume: return ret; } @@ -3748,13 +3842,13 @@ static int msm_geni_serial_sys_suspend_noirq(struct device *dev) if (!pm_runtime_status_suspended(dev)) { dev_err(dev, "%s:Active userspace vote; ioctl_cnt %d\n", __func__, port->ioctl_count); - IPC_LOG_MSG(port->ipc_log_pwr, + UART_LOG_DBG(port->ipc_log_pwr, dev, "%s:Active userspace vote; ioctl_cnt %d\n", __func__, port->ioctl_count); mutex_unlock(&tty_port->mutex); return -EBUSY; } - IPC_LOG_MSG(port->ipc_log_pwr, "%s\n", __func__); + UART_LOG_DBG(port->ipc_log_pwr, dev, "%s\n", __func__); mutex_unlock(&tty_port->mutex); } return 0; @@ -3839,6 +3933,12 @@ static int __init msm_geni_serial_init(void) msm_geni_console_port.uport.line = i; } +#ifdef OPLUS_FEATURE_CHG_BASIC + if (!boot_with_console()) { + msm_geni_console_driver.cons = NULL; + } +#endif + ret = console_register(&msm_geni_console_driver); if (ret) return ret; diff --git a/drivers/tty/serial/serial_trace.h b/drivers/tty/serial/serial_trace.h new file mode 100644 index 000000000000..9f80b64e5a2f --- /dev/null +++ b/drivers/tty/serial/serial_trace.h @@ -0,0 +1,39 @@ +/* SPDX-License-Identifier: GPL-2.0-only + * + * Copyright (c) 2021, The Linux Foundation. All rights reserved. + */ + +#undef TRACE_SYSTEM +#define TRACE_SYSTEM serial + +#if !defined(_TRACE_SERIAL_TRACE_H) || defined(TRACE_HEADER_MULTI_READ) +#define _TRACE_SERIAL_TRACE_H + +#include +#include + +#define MAX_MSG_LEN 200 + +TRACE_EVENT(serial_info, + TP_PROTO(const char *name, struct va_format *vaf), + TP_ARGS(name, vaf), + TP_STRUCT__entry( + __string(name, name) + __dynamic_array(char, msg, MAX_MSG_LEN) + ), + TP_fast_assign( + __assign_str(name, name); + WARN_ON_ONCE(vsnprintf(__get_dynamic_array(msg), + MAX_MSG_LEN, vaf->fmt, + *vaf->va) >= MAX_MSG_LEN); + ), + TP_printk("%s: %s", __get_str(name), __get_str(msg)) +); + +#endif /* _TRACE_SERIAL_TRACE_H */ + +/* This part must be outside protection */ +#undef TRACE_INCLUDE_PATH +#define TRACE_INCLUDE_PATH . +#define TRACE_INCLUDE_FILE serial_trace +#include diff --git a/drivers/tty/sysrq.c b/drivers/tty/sysrq.c index 8b4a46ae7400..426161951db9 100644 --- a/drivers/tty/sysrq.c +++ b/drivers/tty/sysrq.c @@ -134,9 +134,16 @@ static struct sysrq_key_op sysrq_unraw_op = { static void sysrq_handle_crash(int key) { + + struct task_struct *tsk = NULL; + /* release the RCU read lock before crashing */ rcu_read_unlock(); - +#ifdef OPLUS_BUG_STABILITY +/* modify for show the murderer*/ + tsk = current->group_leader; + pr_info("BUG:%s:%d call sysrq-trigger, GroupLeader is %s:%d\n", current->comm, task_pid_nr(current), tsk->comm, task_pid_nr(tsk)); +#endif /*OPLUS_BUG_STABILITY*/ panic("sysrq triggered crash\n"); } static struct sysrq_key_op sysrq_crash_op = { @@ -158,7 +165,20 @@ static struct sysrq_key_op sysrq_reboot_op = { .action_msg = "Resetting", .enable_mask = SYSRQ_ENABLE_BOOT, }; +#ifdef CONFIG_OPLUS_FEATURE_PANIC_FLUSH +extern int panic_flush_device_cache(int timeout); +static void sysrq_handle_flush(int key) +{ + panic_flush_device_cache(0); +} +static struct sysrq_key_op sysrq_flush_op = { + .handler = sysrq_handle_flush, + .help_msg = "flush(y)", + .action_msg = "Emergency Flush", + .enable_mask = SYSRQ_ENABLE_SYNC, +}; +#endif static void sysrq_handle_sync(int key) { emergency_sync(); @@ -482,7 +502,11 @@ static struct sysrq_key_op *sysrq_key_table[36] = { /* x: May be registered on sparc64 for global PMU dump */ NULL, /* x */ /* y: May be registered on sparc64 for global register dump */ +#ifdef CONFIG_OPLUS_FEATURE_PANIC_FLUSH + &sysrq_flush_op, /* y */ +#else NULL, /* y */ +#endif &sysrq_ftrace_dump_op, /* z */ }; diff --git a/drivers/tty/tty_jobctrl.c b/drivers/tty/tty_jobctrl.c index ffcab80ba77d..19bff5ecb17c 100644 --- a/drivers/tty/tty_jobctrl.c +++ b/drivers/tty/tty_jobctrl.c @@ -493,6 +493,7 @@ static int tiocspgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t retval = -ENOTTY; goto out_unlock_ctrl; } + rcu_read_lock(); pgrp = find_vpid(pgrp_nr); retval = -ESRCH; diff --git a/drivers/uio/msm_sharedmem/msm_sharedmem.c b/drivers/uio/msm_sharedmem/msm_sharedmem.c index 64c20deada1c..31eed8b37a7e 100644 --- a/drivers/uio/msm_sharedmem/msm_sharedmem.c +++ b/drivers/uio/msm_sharedmem/msm_sharedmem.c @@ -17,6 +17,10 @@ #define CLIENT_ID_PROP "qcom,client-id" #define MPSS_RMTS_CLIENT_ID 1 +#ifdef OPLUS_BUG_STABILITY +//add for nv backup and restore +#define MPSS_OEMBACK_CLIENT_ID 4 +#endif /* OPLUS_BUG_STABILITY */ static int uio_get_mem_index(struct uio_info *info, struct vm_area_struct *vma) { @@ -74,10 +78,14 @@ static int setup_shared_ram_perms(u32 client_id, phys_addr_t addr, u32 size, int ret = -EINVAL; u32 source_vmlist[1] = {VMID_HLOS}; - if (client_id != MPSS_RMTS_CLIENT_ID) { - pr_err("invalid client id %u\n", client_id); + #ifndef OPLUS_BUG_STABILITY + //add for nv backup and restore + //if (client_id != MPSS_RMTS_CLIENT_ID) + //pr_err("invalid client id %u\n", client_id); + #else /* OPLUS_BUG_STABILITY */ + if ((client_id != MPSS_RMTS_CLIENT_ID) && (client_id != MPSS_OEMBACK_CLIENT_ID)) + #endif /* OPLUS_BUG_STABILITY */ return ret; - } if (vm_nav_path) { int dest_vmids[3] = {VMID_HLOS, VMID_MSS_MSA, VMID_NAV}; diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 6f24d564a6b6..e4ef3bfbe2d2 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -4523,6 +4523,7 @@ static int hub_set_address(struct usb_device *udev, int devnum) * device says it supports the new USB 2.0 Link PM errata by setting the BESL * support bit in the BOS descriptor. */ + #ifndef OPLUS_FEATURE_CHG_BASIC static void hub_set_initial_usb2_lpm_policy(struct usb_device *udev) { struct usb_hub *hub = usb_hub_to_struct_hub(udev->parent); @@ -4540,6 +4541,7 @@ static void hub_set_initial_usb2_lpm_policy(struct usb_device *udev) usb_enable_usb2_hardware_lpm(udev); } } +#endif static int hub_enable_device(struct usb_device *udev) { @@ -4901,7 +4903,9 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1, /* notify HCD that we have a device connected and addressed */ if (hcd->driver->update_device) hcd->driver->update_device(hcd, udev); +#ifndef OPLUS_FEATURE_CHG_BASIC hub_set_initial_usb2_lpm_policy(udev); +#endif fail: if (retval) { hub_port_disable(hub, port1, 0); diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c index ed4502d37f42..058bf6ce07bc 100644 --- a/drivers/usb/dwc3/dwc3-msm.c +++ b/drivers/usb/dwc3/dwc3-msm.c @@ -4635,6 +4635,13 @@ static int dwc3_msm_gadget_vbus_draw(struct dwc3_msm *mdwc, unsigned int mA) if (mdwc->max_power == mA || psy_type != POWER_SUPPLY_TYPE_USB) return 0; +#ifdef OPLUS_FEATURE_CHG_BASIC + dev_info(mdwc->dev, "Avail curr from USB = %u, pre max_power = %u\n", mA, mdwc->max_power); + if (mA == 0 || mA == 2) { + return 0; + } +#endif + /* Set max current limit in uA */ pval.intval = 1000 * mA; @@ -4651,7 +4658,10 @@ set_prop: return 0; } - +#ifdef OPLUS_FEATURE_CHG_BASIC +#define DWC3_DCTL 0xc704 +#define DWC3_DCTL_RUN_STOP BIT(31) +#endif /** * dwc3_otg_sm_work - workqueue function. * @@ -4736,6 +4746,16 @@ static void dwc3_otg_sm_work(struct work_struct *w) atomic_read(&mdwc->dev->power.usage_count)); dwc3_otg_start_peripheral(mdwc, 1); mdwc->drd_state = DRD_STATE_PERIPHERAL; +#ifdef OPLUS_FEATURE_CHG_BASIC + if(!dwc->softconnect && get_psy_type(mdwc) == POWER_SUPPLY_TYPE_USB_CDP) { + u32 reg; + dbg_event(0xFF, "cdp pullup dp", 0); + reg = dwc3_readl(dwc->regs, DWC3_DCTL); + reg |= DWC3_DCTL_RUN_STOP; + dwc3_writel(dwc->regs, DWC3_DCTL, reg); + break; + } +#endif work = 1; } else { if (mdwc->usb_data_enabled) diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index 66339ff389a4..100d1bdeabc6 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -401,6 +401,9 @@ static int dwc3_ep0_handle_status(struct dwc3 *dwc, dwc->ep0_usb_req.request.length = sizeof(*response_pkt); dwc->ep0_usb_req.request.buf = dwc->setup_buf; dwc->ep0_usb_req.request.complete = dwc3_ep0_status_cmpl; +#ifdef OPLUS_FEATURE_CHG_BASIC + dwc->ep0_usb_req.request.dma = DMA_ERROR_CODE; +#endif return __dwc3_gadget_ep0_queue(dep, &dwc->ep0_usb_req); } @@ -807,6 +810,9 @@ static int dwc3_ep0_set_sel(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl) dwc->ep0_usb_req.request.length = dep->endpoint.maxpacket; dwc->ep0_usb_req.request.buf = dwc->setup_buf; dwc->ep0_usb_req.request.complete = dwc3_ep0_set_sel_cmpl; +#ifdef OPLUS_FEATURE_CHG_BASIC + dwc->ep0_usb_req.request.dma = DMA_ERROR_CODE; +#endif return __dwc3_gadget_ep0_queue(dep, &dwc->ep0_usb_req); } diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 5b1bcfe558bb..c27d78725fab 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -833,9 +833,12 @@ static void dwc3_remove_requests(struct dwc3 *dwc, struct dwc3_ep *dep) { int retries = 40; struct dwc3_request *req; + int ret; dbg_log_string("START for %s(%d)", dep->name, dep->number); - dwc3_stop_active_transfer(dwc, dep->number, true, false); + ret = dwc3_stop_active_transfer(dwc, dep->number, true, false); + if (ret) + return; if (dep->number == 0) { unsigned int dir; @@ -2271,11 +2274,16 @@ done: } #define MIN_RUN_STOP_DELAY_MS 50 - +#ifdef OPLUS_FEATURE_CHG_BASIC +#define DWC3_SOFT_RESET_TIMEOUT 10 +#endif static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on, int suspend) { u32 reg, reg1; u32 timeout = 1500; +#ifdef OPLUS_FEATURE_CHG_BASIC + ktime_t start, diff; +#endif dbg_event(0xFF, "run_stop", is_on); reg = dwc3_readl(dwc->regs, DWC3_DCTL); @@ -2288,6 +2296,24 @@ static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on, int suspend) if (dwc->revision >= DWC3_REVISION_194A) reg &= ~DWC3_DCTL_KEEP_CONNECT; +#ifdef OPLUS_FEATURE_CHG_BASIC + start = ktime_get(); + /* issue device SoftReset */ + dwc3_writel(dwc->regs, DWC3_DCTL, reg | DWC3_DCTL_CSFTRST); + do { + reg = dwc3_readl(dwc->regs, DWC3_DCTL); + if (!(reg & DWC3_DCTL_CSFTRST)) + break; + diff = ktime_sub(ktime_get(), start); + /* poll for max. 10ms */ + if (ktime_to_ms(diff) > DWC3_SOFT_RESET_TIMEOUT) { + printk_ratelimited(KERN_ERR"%s:core Reset Timed Out\n", __func__); + break; + } + cpu_relax(); + } while (true); +#endif + dwc3_event_buffers_setup(dwc); __dwc3_gadget_start(dwc); @@ -3440,19 +3466,19 @@ static void dwc3_reset_gadget(struct dwc3 *dwc) } } -void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum, bool force, +int dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum, bool force, bool interrupt) { struct dwc3_ep *dep; struct dwc3_gadget_ep_cmd_params params; u32 cmd; - int ret; + int ret = 0; dep = dwc->eps[epnum]; if ((dep->flags & DWC3_EP_END_TRANSFER_PENDING) || !dep->resource_index) - return; + return ret; if (dep->endpoint.endless) dwc3_notify_event(dwc, DWC3_CONTROLLER_NOTIFY_DISABLE_UPDXFER, @@ -3505,6 +3531,7 @@ void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum, bool force, } dbg_log_string("%s(%d): endxfer ret:%d)", dep->name, dep->number, ret); + return ret; } int dwc3_stop_active_transfer_noioc(struct dwc3 *dwc, u32 epnum, bool force) diff --git a/drivers/usb/dwc3/gadget.h b/drivers/usb/dwc3/gadget.h index 844a416cbbcf..91391bb68e60 100644 --- a/drivers/usb/dwc3/gadget.h +++ b/drivers/usb/dwc3/gadget.h @@ -125,7 +125,7 @@ int dwc3_gadget_ep0_set_halt(struct usb_ep *ep, int value); int dwc3_gadget_ep0_queue(struct usb_ep *ep, struct usb_request *request, gfp_t gfp_flags); int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value, int protocol); -void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum, bool force, bool interrupt); +int dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum, bool force, bool interrupt); int dwc3_stop_active_transfer_noioc(struct dwc3 *dwc, u32 epnum, bool force); void dwc3_ep_inc_enq(struct dwc3_ep *dep); void dwc3_ep_inc_deq(struct dwc3_ep *dep); diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index b69f5b2e2620..5114ae838f4d 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -20,6 +20,12 @@ #include "u_os_desc.h" +#ifdef OPLUS_FEATURE_CHG_BASIC +static bool enable_l1_for_hs; +module_param(enable_l1_for_hs, bool, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(enable_l1_for_hs, "Enable support for L1 LPM for HS devices"); +#endif + /** * struct usb_os_string - represents OS String to be reported by a gadget * @bLength: total length of the entire descritor, always 0x12 @@ -1817,12 +1823,23 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) cdev->desc.bMaxPacketSize0 = cdev->gadget->ep0->maxpacket; if (gadget_is_superspeed(gadget)) { +#ifdef OPLUS_FEATURE_CHG_BASIC + if (gadget->speed >= USB_SPEED_SUPER) { + cdev->desc.bcdUSB = cpu_to_le16(0x0320); + cdev->desc.bMaxPacketSize0 = 9; + } else if (gadget->lpm_capable || enable_l1_for_hs) { + cdev->desc.bcdUSB = cpu_to_le16(0x0210); + } else { + cdev->desc.bcdUSB = cpu_to_le16(0x0200); + } +#else if (gadget->speed >= USB_SPEED_SUPER) { cdev->desc.bcdUSB = cpu_to_le16(0x0320); cdev->desc.bMaxPacketSize0 = 9; } else { cdev->desc.bcdUSB = cpu_to_le16(0x0210); } +#endif } else { if (gadget->lpm_capable) cdev->desc.bcdUSB = cpu_to_le16(0x0201); @@ -1860,7 +1877,11 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) value = min(w_length, (u16) value); break; case USB_DT_BOS: +#ifdef OPLUS_FEATURE_CHG_BASIC + if ((gadget_is_superspeed(gadget) && (gadget->speed >= USB_SPEED_SUPER)) || +#else if (gadget_is_superspeed(gadget) || +#endif gadget->lpm_capable) { value = bos_desc(cdev); value = min(w_length, (u16) value); diff --git a/drivers/usb/gadget/function/f_accessory.c b/drivers/usb/gadget/function/f_accessory.c index 7d046e28047e..1a7d30fafe09 100644 --- a/drivers/usb/gadget/function/f_accessory.c +++ b/drivers/usb/gadget/function/f_accessory.c @@ -346,6 +346,9 @@ static void acc_complete_set_string(struct usb_ep *ep, struct usb_request *req) struct acc_dev *dev = ep->driver_data; char *string_dest = NULL; int length = req->actual; +#ifdef OPLUS_FEATURE_CHG_BASIC + unsigned long flags; +#endif if (req->status != 0) { pr_err("acc_complete_set_string, err %d\n", req->status); @@ -371,7 +374,31 @@ static void acc_complete_set_string(struct usb_ep *ep, struct usb_request *req) case ACCESSORY_STRING_SERIAL: string_dest = dev->serial; break; +#ifdef OPLUS_FEATURE_CHG_BASIC + default: + pr_err("unknown accessory string index %d\n", + dev->string_index); + return; +#endif } + +#ifdef OPLUS_FEATURE_CHG_BASIC + if (!length) { + pr_debug("zero length for accessory string index %d\n", + dev->string_index); + return; + } + + if (length >= ACC_STRING_SIZE) + length = ACC_STRING_SIZE - 1; + + spin_lock_irqsave(&dev->lock, flags); + memcpy(string_dest, req->buf, length); + /* ensure zero termination */ + string_dest[length] = 0; + spin_unlock_irqrestore(&dev->lock, flags); + +#else if (string_dest) { unsigned long flags; @@ -387,6 +414,7 @@ static void acc_complete_set_string(struct usb_ep *ep, struct usb_request *req) pr_err("unknown accessory string index %d\n", dev->string_index); } +#endif } static void acc_complete_set_hid_report_desc(struct usb_ep *ep, diff --git a/drivers/usb/gadget/function/f_mtp.c b/drivers/usb/gadget/function/f_mtp.c index f78fa6d63f15..04f3deb5ec79 100644 --- a/drivers/usb/gadget/function/f_mtp.c +++ b/drivers/usb/gadget/function/f_mtp.c @@ -125,7 +125,9 @@ struct mtp_dev { wait_queue_head_t read_wq; wait_queue_head_t write_wq; +#ifndef OPLUS_FEATURE_CHG_BASIC wait_queue_head_t intr_wq; +#endif struct usb_request *rx_req[RX_REQ_MAX]; int rx_done; @@ -381,6 +383,10 @@ struct mtp_instance { /* temporary variable used between mtp_open() and mtp_gadget_bind() */ static struct mtp_dev *_mtp_dev; +#ifdef OPLUS_FEATURE_CHG_BASIC +static ATOMIC_NOTIFIER_HEAD(mtp_rw_notifier); +#endif + static inline struct mtp_dev *func_to_mtp(struct usb_function *f) { return container_of(f, struct mtp_dev, function); @@ -487,7 +493,9 @@ static void mtp_complete_intr(struct usb_ep *ep, struct usb_request *req) mtp_req_put(dev, &dev->intr_idle, req); +#ifndef OPLUS_FEATURE_CHG_BASIC wake_up(&dev->intr_wq); +#endif } static int mtp_create_bulk_endpoints(struct mtp_dev *dev, @@ -1037,11 +1045,19 @@ static int mtp_send_event(struct mtp_dev *dev, struct mtp_event *event) if (dev->state == STATE_OFFLINE) return -ENODEV; +#ifndef OPLUS_FEATURE_CHG_BASIC ret = wait_event_interruptible_timeout(dev->intr_wq, (req = mtp_req_get(dev, &dev->intr_idle)), msecs_to_jiffies(1000)); +#else + req = mtp_req_get(dev, &dev->intr_idle); +#endif if (!req) +#ifndef OPLUS_FEATURE_CHG_BASIC return -ETIME; +#else + return -EBUSY; +#endif if (copy_from_user(req->buf, (void __user *)event->data, length)) { mtp_req_put(dev, &dev->intr_idle, req); @@ -1052,6 +1068,10 @@ static int mtp_send_event(struct mtp_dev *dev, struct mtp_event *event) if (ret) mtp_req_put(dev, &dev->intr_idle, req); +#ifdef OPLUS_FEATURE_CHG_BASIC + mtp_log("exit: (%d)\n", ret); +#endif + return ret; } @@ -1063,6 +1083,10 @@ static long mtp_send_receive_ioctl(struct file *fp, unsigned int code, struct work_struct *work; int ret = -EINVAL; +#ifdef OPLUS_FEATURE_CHG_BASIC + mtp_log("entering ioctl with state: %d\n", dev->state); +#endif + if (mtp_lock(&dev->ioctl_excl)) { mtp_log("ioctl returning EBUSY state:%d\n", dev->state); return -EBUSY; @@ -1098,6 +1122,10 @@ static long mtp_send_receive_ioctl(struct file *fp, unsigned int code, /* make sure write is done before parameters are read */ smp_wmb(); +#ifdef OPLUS_FEATURE_CHG_BASIC + atomic_notifier_call_chain(&mtp_rw_notifier, code, (void *)&mfr); +#endif + if (code == MTP_SEND_FILE_WITH_HEADER) { work = &dev->send_file_work; dev->xfer_send_header = 1; @@ -1118,6 +1146,9 @@ static long mtp_send_receive_ioctl(struct file *fp, unsigned int code, /* wait for operation to complete */ flush_workqueue(dev->wq); fput(filp); +#ifdef OPLUS_FEATURE_CHG_BASIC + atomic_notifier_call_chain(&mtp_rw_notifier, code | 0x8000, (void *)&mfr); +#endif /* read the result */ smp_rmb(); @@ -1136,6 +1167,21 @@ out: return ret; } +#ifdef OPLUS_FEATURE_CHG_BASIC +int mtp_register_notifier(struct notifier_block *nb) +{ + return atomic_notifier_chain_register(&mtp_rw_notifier, nb); +} +EXPORT_SYMBOL(mtp_register_notifier); + +int mtp_unregister_notifier(struct notifier_block *nb) +{ + return atomic_notifier_chain_unregister(&mtp_rw_notifier, nb); +} +EXPORT_SYMBOL(mtp_unregister_notifier); +#endif /*OPLUS_FEATURE_CHG_BASIC*/ + + static long mtp_ioctl(struct file *fp, unsigned int code, unsigned long value) { struct mtp_dev *dev = fp->private_data; @@ -1671,7 +1717,9 @@ static int __mtp_setup(struct mtp_instance *fi_mtp) spin_lock_init(&dev->lock); init_waitqueue_head(&dev->read_wq); init_waitqueue_head(&dev->write_wq); +#ifndef OPLUS_FEATURE_CHG_BASIC init_waitqueue_head(&dev->intr_wq); +#endif atomic_set(&dev->open_excl, 0); atomic_set(&dev->ioctl_excl, 0); INIT_LIST_HEAD(&dev->tx_idle); diff --git a/drivers/usb/pd/policy_engine.c b/drivers/usb/pd/policy_engine.c index 6dca69d619b4..cc1ba5949164 100644 --- a/drivers/usb/pd/policy_engine.c +++ b/drivers/usb/pd/policy_engine.c @@ -10,8 +10,10 @@ #include #include #include +#include #include #include +#include #include #include #include @@ -22,6 +24,16 @@ #include #include "usbpd.h" +#ifdef OPLUS_FEATURE_CHG_BASIC +/* To start USB stack for USB3.1 compliance testing */ +static bool usb_compliance_mode; +module_param(usb_compliance_mode, bool, 0644); +MODULE_PARM_DESC(usb_compliance_mode, "USB3.1 compliance testing"); +#endif + +extern void oplus_wpc_set_wrx_en_value(int value); +extern int switch_to_otg_mode(bool enable); + enum usbpd_state { PE_UNKNOWN, PE_ERROR_RECOVERY, @@ -404,9 +416,15 @@ struct usbpd { int requested_current; /* mA */ bool pd_connected; bool in_explicit_contract; +#ifdef OPLUS_FEATURE_CHG_BASIC + bool in_good_connect; +#endif bool peer_usb_comm; bool peer_pr_swap; bool peer_dr_swap; +#ifdef OPLUS_CUSTOM_OP_DEF + bool probe_done; +#endif bool no_usb3dp_concurrency; bool pd20_source_only; @@ -447,8 +465,14 @@ struct usbpd { struct regulator *vbus; struct regulator *vconn; + + int vbus_gpio; + int otg_en_gpio; + bool vbus_enabled; bool vconn_enabled; + bool is_otg_mode; + bool use_external_boost; u8 tx_msgid[SOPII_MSG + 1]; u8 rx_msgid[SOPII_MSG + 1]; @@ -486,9 +510,17 @@ struct usbpd { u32 battery_sts_dobj; bool typec_analog_audio_connected; }; +#ifdef OPLUS_FEATURE_CHG_BASIC +struct usbpd *pd_lobal; +#endif static LIST_HEAD(_usbpd); /* useful for debugging */ +#ifdef OPLUS_FEATURE_CHG_BASIC +int oplus_usbpd_send_svdm(u16 svid, u8 cmd, enum usbpd_svdm_cmd_type cmd_type, + int obj_pos, const u32 *vdos, int num_vdos); +#endif + static const unsigned int usbpd_extcon_cable[] = { EXTCON_USB, EXTCON_USB_HOST, @@ -891,6 +923,11 @@ static int pd_select_pdo(struct usbpd *pd, int pdo_pos, int uv, int ua) return 0; } +#ifdef OPLUS_FEATURE_CHG_BASIC +/* Yichun.Chen PSW.BSP.CHG 2019-08-19 for c to c */ +extern void opchg_set_pd_sdp(bool pd_sdp); +#endif + static int pd_eval_src_caps(struct usbpd *pd) { int i; @@ -928,7 +965,14 @@ static int pd_eval_src_caps(struct usbpd *pd) POWER_SUPPLY_PD_ACTIVE; power_supply_set_property(pd->usb_psy, POWER_SUPPLY_PROP_PD_ACTIVE, &val); - +#ifdef OPLUS_FEATURE_CHG_BASIC +/* Yichun.Chen PSW.BSP.CHG 2019-08-19 for c to c */ + if (pd->peer_usb_comm && pd->current_dr == DR_UFP && !pd->pd_connected) { + printk("set opluschg_pd_sdp = true\n"); + opchg_set_pd_sdp(true); + //opluschg_pd_sdp = true; + } +#endif /* First time connecting to a PD source and it supports USB data */ if (pd->peer_usb_comm && pd->current_dr == DR_UFP && !pd->pd_connected) start_usb_peripheral(pd); @@ -1233,7 +1277,19 @@ static void phy_shutdown(struct usbpd *pd) } if (pd->vbus_enabled) { - regulator_disable(pd->vbus); + if (pd->use_external_boost) { + gpio_set_value_cansleep(pd->otg_en_gpio, 0); + gpio_set_value_cansleep(pd->vbus_gpio, 0); + msleep(20); +#ifdef OPLUS_CUSTOM_OP_DEF + switch_to_otg_mode(false); +#else + oplus_wpc_set_wrx_en_value(0); +#endif // OPLUS_CUSTOM_OP_DEF + } else { + regulator_disable(pd->vbus); + } + pd->is_otg_mode = false; pd->vbus_enabled = false; } } @@ -1384,6 +1440,13 @@ int usbpd_send_vdm(struct usbpd *pd, u32 vdm_hdr, const u32 *vdos, int num_vdos) kfree(pd->vdm_tx); pd->vdm_tx = NULL; } +#ifdef OPLUS_FEATURE_CHG_BASIC + if (pd->current_state != PE_SRC_READY && + pd->current_state != PE_SNK_READY) { + usbpd_err(&pd->dev, "VDM not allowed: PD not in Ready state\n"); + return -EAGAIN; + } +#endif vdm_tx = kzalloc(sizeof(*vdm_tx), GFP_KERNEL); if (!vdm_tx) @@ -1429,6 +1492,9 @@ void usbpd_vdm_in_suspend(struct usbpd *pd, bool in_suspend) } EXPORT_SYMBOL(usbpd_vdm_in_suspend); +#ifdef OPLUS_FEATURE_CHG_BASIC +#define OPLUS_SVID 0x22d9 +#endif static void handle_vdm_resp_ack(struct usbpd *pd, u32 *vdos, u8 num_vdos, u16 vdm_hdr) { @@ -1436,6 +1502,10 @@ static void handle_vdm_resp_ack(struct usbpd *pd, u32 *vdos, u8 num_vdos, u16 svid, *psvid; u8 cmd = SVDM_HDR_CMD(vdm_hdr); struct usbpd_svid_handler *handler; +#ifdef OPLUS_FEATURE_CHG_BASIC + u8 cmd_type = SVDM_HDR_CMD_TYPE(vdm_hdr); + u32 oplus_svid; +#endif switch (cmd) { case USBPD_SVDM_DISCOVER_IDENTITY: @@ -1447,6 +1517,26 @@ static void handle_vdm_resp_ack(struct usbpd *pd, u32 *vdos, u8 num_vdos, break; } +#ifdef OPLUS_FEATURE_CHG_BASIC + pr_info("handle_vdm_resp_ack num_vdos:%d\n",num_vdos); + if (num_vdos == 3){ + oplus_svid = vdos[0] & 0xffff; + pr_info("handle_vdm_resp_ack oplus_svid:%d\n",oplus_svid); + if(oplus_svid == OPLUS_SVID){ + handler = find_svid_handler(pd, oplus_svid); + if (handler) { + usbpd_err(&pd->dev, "oplus_svid SVID: 0x%04x vdos1: %x vdos2 %x connect\n", + handler->svid, vdos[1], vdos[2]); + handler->connect(handler, + pd->peer_usb_comm); + handler->discovered = true; + handler->svdm_received(handler,cmd,cmd_type,vdos,num_vdos); + break; + } + } + } +#endif + if (ID_HDR_PRODUCT_TYPE(vdos[0]) == ID_HDR_PRODUCT_VPD) { usbpd_dbg(&pd->dev, "VPD detected turn off vbus\n"); @@ -1978,10 +2068,14 @@ static void vconn_swap(struct usbpd *pd) pd->vconn_enabled = true; +#ifndef OPLUS_FEATURE_CHG_BASIC + //pd_phy_update_frame_filter(FRAME_FILTER_EN_SOP | + // FRAME_FILTER_EN_SOPI | + // FRAME_FILTER_EN_HARD_RESET); +#else pd_phy_update_frame_filter(FRAME_FILTER_EN_SOP | - FRAME_FILTER_EN_SOPI | FRAME_FILTER_EN_HARD_RESET); - +#endif /* * Small delay to ensure Vconn has ramped up. This is well * below tVCONNSourceOn (100ms) so we still send PS_RDY within @@ -1997,6 +2091,14 @@ static void vconn_swap(struct usbpd *pd) } } +bool typec_is_otg_mode(void) +{ + if (pd_lobal != NULL) + return pd_lobal->is_otg_mode; + else + return false; +} + static int enable_vbus(struct usbpd *pd) { union power_supply_propval val = {0}; @@ -2019,18 +2121,34 @@ static int enable_vbus(struct usbpd *pd) if (count < 99) msleep(100); /* need to wait an additional tCCDebounce */ - if (!pd->vbus) { - pd->vbus = devm_regulator_get(pd->dev.parent, "vbus"); - if (IS_ERR(pd->vbus)) { - usbpd_err(&pd->dev, "Unable to get vbus\n"); - return -EAGAIN; + if (pd->use_external_boost) { + pd->is_otg_mode = true; +#ifdef OPLUS_CUSTOM_OP_DEF + switch_to_otg_mode(true); +#else + oplus_wpc_set_wrx_en_value(1); +#endif // OPLUS_CUSTOM_OP_DEF + msleep(20); + gpio_set_value_cansleep(pd->vbus_gpio, 1); + msleep(100); + gpio_set_value_cansleep(pd->otg_en_gpio, 1); + pd->vbus_enabled = true; + } else { + if (!pd->vbus) { + pd->vbus = devm_regulator_get(pd->dev.parent, "vbus"); + if (IS_ERR(pd->vbus)) { + usbpd_err(&pd->dev, "Unable to get vbus\n"); + return -EAGAIN; + } + } + ret = regulator_enable(pd->vbus); + if (ret) { + usbpd_err(&pd->dev, "Unable to enable vbus (%d)\n", ret); + } else { + pd->is_otg_mode = false; + pd->vbus_enabled = true; } } - ret = regulator_enable(pd->vbus); - if (ret) - usbpd_err(&pd->dev, "Unable to enable vbus (%d)\n", ret); - else - pd->vbus_enabled = true; count = 10; /* @@ -2152,8 +2270,10 @@ static int usbpd_startup_common(struct usbpd *pd, phy_params->data_role = pd->current_dr; phy_params->power_role = pd->current_pr; - if (pd->vconn_enabled) - phy_params->frame_filter_val |= FRAME_FILTER_EN_SOPI; +#ifndef OPLUS_FEATURE_CHG_BASIC + //if (pd->vconn_enabled) + // phy_params->frame_filter_val |= FRAME_FILTER_EN_SOPI; +#endif ret = pd_phy_open(phy_params); if (ret) { @@ -2553,6 +2673,9 @@ static void enter_state_hard_reset(struct usbpd *pd) pd_send_hard_reset(pd); pd->in_explicit_contract = false; +#ifdef OPLUS_FEATURE_CHG_BASIC + pd->in_good_connect = false; +#endif pd->rdo = 0; rx_msg_cleanup(pd); reset_vdm_state(pd); @@ -2592,8 +2715,21 @@ static void handle_state_src_transition_to_default(struct usbpd *pd, regulator_disable(pd->vconn); pd->vconn_enabled = false; - if (pd->vbus_enabled) - regulator_disable(pd->vbus); + if (pd->vbus_enabled) { + if (pd->use_external_boost) { + gpio_set_value_cansleep(pd->otg_en_gpio, 0); + gpio_set_value_cansleep(pd->vbus_gpio, 0); + msleep(20); +#ifdef OPLUS_CUSTOM_OP_DEF + switch_to_otg_mode(false); +#else + oplus_wpc_set_wrx_en_value(0); +#endif // OPLUS_CUSTOM_OP_DEF + } else { + regulator_disable(pd->vbus); + } + } + pd->is_otg_mode = false; pd->vbus_enabled = false; if (pd->current_dr != DR_DFP) { @@ -2739,6 +2875,15 @@ static void handle_state_snk_wait_for_capabilities(struct usbpd *pd, usbpd_set_state(pd, PE_SNK_EVALUATE_CAPABILITY); } else if (pd->hard_reset_count < 3) { +#ifdef OPLUS_CUSTOM_OP_DEF + if (pd->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_HIGH && pd->probe_done) { + usbpd_err(&pd->dev, "Didn't receive source cap when probe, reset rd!\n"); + pd->probe_done = false; + val.intval = 0xf; + power_supply_set_property(pd->usb_psy, + POWER_SUPPLY_PROP_RESET_RD, &val); + } +#endif usbpd_set_state(pd, PE_SNK_HARD_RESET); } else { usbpd_dbg(&pd->dev, "Sink hard reset count exceeded, disabling PD\n"); @@ -2886,6 +3031,11 @@ static void handle_state_snk_transition_sink(struct usbpd *pd, static void enter_state_snk_ready(struct usbpd *pd) { pd->in_explicit_contract = true; +#ifdef OPLUS_FEATURE_CHG_BASIC + pd->in_good_connect = true; + oplus_usbpd_send_svdm(USBPD_SID, USBPD_SVDM_DISCOVER_IDENTITY, + SVDM_CMD_TYPE_INITIATOR, 0, NULL, 0); +#endif if (pd->vdm_tx) kick_sm(pd, 0); @@ -3318,7 +3468,19 @@ static void handle_state_prs_src_snk_transition_to_off(struct usbpd *pd, int ret; if (pd->vbus_enabled) { - regulator_disable(pd->vbus); + if (pd->use_external_boost) { + gpio_set_value_cansleep(pd->otg_en_gpio, 0); + gpio_set_value_cansleep(pd->vbus_gpio, 0); + msleep(20); +#ifdef OPLUS_CUSTOM_OP_DEF + switch_to_otg_mode(false); +#else + oplus_wpc_set_wrx_en_value(0); +#endif // OPLUS_CUSTOM_OP_DEF + } else { + regulator_disable(pd->vbus); + } + pd->is_otg_mode = false; pd->vbus_enabled = false; } @@ -3494,6 +3656,9 @@ static void handle_disconnect(struct usbpd *pd) pd->in_pr_swap = false; pd->pd_connected = false; pd->in_explicit_contract = false; +#ifdef OPLUS_FEATURE_CHG_BASIC + pd->in_good_connect = false; +#endif pd->hard_reset_recvd = false; pd->caps_count = 0; pd->hard_reset_count = 0; @@ -3515,7 +3680,19 @@ static void handle_disconnect(struct usbpd *pd) POWER_SUPPLY_PROP_PD_ACTIVE, &val); if (pd->vbus_enabled) { - regulator_disable(pd->vbus); + if (pd->use_external_boost) { + gpio_set_value_cansleep(pd->otg_en_gpio, 0); + gpio_set_value_cansleep(pd->vbus_gpio, 0); + msleep(20); +#ifdef OPLUS_CUSTOM_OP_DEF + switch_to_otg_mode(false); +#else + oplus_wpc_set_wrx_en_value(0); +#endif // OPLUS_CUSTOM_OP_DEF + } else { + regulator_disable(pd->vbus); + } + pd->is_otg_mode = false; pd->vbus_enabled = false; } @@ -3585,6 +3762,9 @@ static void handle_hard_reset(struct usbpd *pd) POWER_SUPPLY_PROP_PR_SWAP, &val); pd->in_explicit_contract = false; +#ifdef OPLUS_FEATURE_CHG_BASIC + pd->in_good_connect = false; +#endif pd->selected_pdo = pd->requested_pdo = 0; pd->rdo = 0; rx_msg_cleanup(pd); @@ -3825,7 +4005,17 @@ static int psy_changed(struct notifier_block *nb, unsigned long evt, void *ptr) ret); return ret; } - +#ifdef OPLUS_FEATURE_CHG_BASIC + if (val.intval == POWER_SUPPLY_TYPE_USB || + val.intval == POWER_SUPPLY_TYPE_USB_CDP || + val.intval == POWER_SUPPLY_TYPE_USB_FLOAT || + usb_compliance_mode) { + usbpd_info(&pd->dev, "typec mode:%d type:%d\n", + typec_mode, val.intval); + pd->typec_mode = typec_mode; + queue_work(pd->wq, &pd->start_periph_work); + } +#else if (val.intval == POWER_SUPPLY_TYPE_USB || val.intval == POWER_SUPPLY_TYPE_USB_CDP || val.intval == POWER_SUPPLY_TYPE_USB_FLOAT) { @@ -3834,10 +4024,17 @@ static int psy_changed(struct notifier_block *nb, unsigned long evt, void *ptr) pd->typec_mode = typec_mode; queue_work(pd->wq, &pd->start_periph_work); } - +#endif return 0; } +#ifdef OPLUS_FEATURE_CHG_BASIC + if (usb_compliance_mode) { + usbpd_err(&pd->dev, "start usb peripheral for testing"); + ///start_usb_peripheral(pd); + } +#endif + ret = power_supply_get_property(pd->usb_psy, POWER_SUPPLY_PROP_PRESENT, &val); if (ret) { @@ -4277,6 +4474,11 @@ static ssize_t select_pdo_store(struct device *dev, int pdo, uv = 0, ua = 0; int ret; +#ifdef OPLUS_FEATURE_CHG_BASIC +/* BSP.CHG.Basic, 2021/10/27, hvdcp_opti return */ + return size; +#endif + mutex_lock(&pd->swap_lock); /* Only allowed if we are already in explicit sink contract */ @@ -4689,6 +4891,104 @@ static void usbpd_release(struct device *dev) kfree(pd); } +#ifdef OPLUS_FEATURE_CHG_BASIC +int oplus_usbpd_send_svdm(u16 svid, u8 cmd, enum usbpd_svdm_cmd_type cmd_type, + int obj_pos, const u32 *vdos, int num_vdos) { + struct usbpd *pd = pd_lobal; + u32 svdm_hdr = SVDM_HDR(svid, 0, obj_pos, cmd_type, cmd); + + return usbpd_send_vdm(pd, svdm_hdr, vdos, num_vdos); +} + +bool oplus_check_pd_state_ready(void) +{ + return (pd_lobal->in_good_connect); +} +EXPORT_SYMBOL(oplus_check_pd_state_ready); + +int oplus_pdo_select(int vbus_mv, int ibus_ma) +{ + int i = 0; + int rc = 0; + u32 pdo = 0; + struct usbpd *pd = pd_lobal; + + for (i = 0; i < ARRAY_SIZE(pd->received_pdos); i++) { + pdo = pd->received_pdos[i]; + if (vbus_mv == PD_SRC_PDO_FIXED_VOLTAGE(pdo) * 50 || pdo == 0) + break; + } + + mutex_lock(&pd->swap_lock); + + /* Only allowed if we are already in explicit sink contract */ + if (pd->current_state != PE_SNK_READY || !is_sink_tx_ok(pd)) { + printk(KERN_ERR "%s: cannot select new pdo yet\n", __func__); + rc = -EBUSY; + goto out; + } + + if (i > 7) { + printk(KERN_ERR "%s: inval pdo[0x%x]\n", __func__, pdo); + rc = -EINVAL; + goto out; + } + + if (vbus_mv != PD_SRC_PDO_FIXED_VOLTAGE(pdo) * 50) { + if (i > 0) { + printk(KERN_ERR "%s: can not find vbus_mv[%d], the last pdos[%d]=[%d]\n", __func__, + vbus_mv, i -1, PD_SRC_PDO_FIXED_VOLTAGE(pd->received_pdos[i - 1]) * 50); + } else { + printk(KERN_ERR "%s: can not find vbus_mv[%d], pdos0=[%d]\n", __func__, + vbus_mv, PD_SRC_PDO_FIXED_VOLTAGE(pd->received_pdos[i]) * 50); + } + rc = -EINVAL; + goto out; + } + + rc = pd_select_pdo(pd, i + 1, vbus_mv * 1000, ibus_ma * 1000); + if (rc) { + printk(KERN_ERR "%s: pd_select_pdo fail, rc=%d\n", __func__, rc); + goto out; + } + + reinit_completion(&pd->is_ready); + pd->send_request = true; + kick_sm(pd, 0); + + /* wait for operation to complete */ + if (!wait_for_completion_timeout(&pd->is_ready, msecs_to_jiffies(1000))) { + printk(KERN_ERR "%s: pdo[%d], vbus_mv[%d], ibus_ma[%d] request timed out\n", + __func__, i, vbus_mv, ibus_ma); + rc = -ETIMEDOUT; + goto out; + } + + /* determine if request was accepted/rejected */ + if (pd->selected_pdo != pd->requested_pdo || + pd->current_voltage != pd->requested_voltage) { + printk(KERN_ERR "%s: request rejected\n", __func__); + rc = -EINVAL; + } + printk(KERN_ERR "%s: pdo[%d], vbus_mv[%d], ibus_ma[%d]\n", + __func__, i, vbus_mv, ibus_ma); + +out: + pd->send_request = false; + mutex_unlock(&pd->swap_lock); + return rc; +} +EXPORT_SYMBOL(oplus_pdo_select); + +bool oplus_is_use_external_boost(void) +{ + if (pd_lobal != NULL) + return pd_lobal->use_external_boost; + else + return false; +} +EXPORT_SYMBOL(oplus_is_use_external_boost); +#endif /*OPLUS_FEATURE_CHG_BASIC*/ static int num_pd_instances; @@ -4730,10 +5030,41 @@ struct usbpd *usbpd_create(struct device *parent) if (ret) goto free_pd; + pd->use_external_boost = of_property_read_bool(parent->of_node, "otg-use_external_boost"); + if (pd->use_external_boost) { + usbpd_info(&pd->dev, "wkcs: otg use external boost\n"); + pd->vbus_gpio = of_get_named_gpio(parent->of_node, "vbus-gpio", 0); + if (!gpio_is_valid(pd->vbus_gpio)) { + usbpd_err(&pd->dev, "wkcs: can't find vbus-gpio\n"); + goto del_pd; + } + ret = devm_gpio_request_one(&pd->dev, pd->vbus_gpio, GPIOF_OUT_INIT_LOW, + "vbus-gpio"); + if (ret) { + usbpd_err(&pd->dev, "wkcs: can't request vbus gpio %d", pd->vbus_gpio); + goto del_pd; + } + pd->otg_en_gpio = of_get_named_gpio(parent->of_node, "otg_en-gpio", 0); + if (!gpio_is_valid(pd->otg_en_gpio)) { + usbpd_err(&pd->dev, "wkcs: can't find otg_en-gpio\n"); + goto free_vbus_gpio; + } + ret = devm_gpio_request_one(&pd->dev, pd->otg_en_gpio, GPIOF_OUT_INIT_LOW, + "otg_en-gpio"); + if (ret) { + usbpd_err(&pd->dev, "wkcs: can't request vbus gpio %d", pd->otg_en_gpio); + goto free_vbus_gpio; + } + } + pd->is_otg_mode = false; + pd->wq = alloc_ordered_workqueue("usbpd_wq", WQ_FREEZABLE | WQ_HIGHPRI); if (!pd->wq) { ret = -ENOMEM; - goto del_pd; + if (pd->use_external_boost) + goto free_otg_en_gpio; + else + goto del_pd; } INIT_WORK(&pd->sm_work, usbpd_sm); INIT_WORK(&pd->start_periph_work, start_usb_peripheral_work); @@ -4863,6 +5194,9 @@ struct usbpd *usbpd_create(struct device *parent) } } +#ifdef OPLUS_CUSTOM_OP_DEF + pd->probe_done = true; +#endif pd->pps_disabled = device_property_read_bool(parent, "qcom,pps-disabled"); pd->current_pr = PR_NONE; @@ -4883,6 +5217,10 @@ struct usbpd *usbpd_create(struct device *parent) /* force read initial power_supply values */ psy_changed(&pd->psy_nb, PSY_EVENT_PROP_CHANGED, pd->usb_psy); +#ifdef OPLUS_FEATURE_CHG_BASIC + pd_lobal = pd; +#endif + return pd; del_inst: @@ -4891,6 +5229,13 @@ put_psy: power_supply_put(pd->usb_psy); destroy_wq: destroy_workqueue(pd->wq); +free_otg_en_gpio: + if (pd->use_external_boost && gpio_is_valid(pd->otg_en_gpio)) + devm_gpio_free(&pd->dev, pd->otg_en_gpio); +free_vbus_gpio: + if (pd->use_external_boost && gpio_is_valid(pd->vbus_gpio)) + devm_gpio_free(&pd->dev, pd->vbus_gpio); + del_pd: device_del(&pd->dev); free_pd: diff --git a/drivers/usb/phy/phy-msm-snps-hs.c b/drivers/usb/phy/phy-msm-snps-hs.c index b9cf8dd83163..6676113f1dd9 100644 --- a/drivers/usb/phy/phy-msm-snps-hs.c +++ b/drivers/usb/phy/phy-msm-snps-hs.c @@ -82,6 +82,28 @@ #define USB_HSPHY_1P8_VOL_MIN 1704000 /* uV */ #define USB_HSPHY_1P8_VOL_MAX 1800000 /* uV */ #define USB_HSPHY_1P8_HPM_LOAD 19000 /* uA */ +#ifdef OPLUS_FEATURE_CHG_BASIC + +#define QUSB2PHY_PORT_TUNE1 0x6c // PARAMETER_OVERRIDE_X0 +#define QUSB2PHY_PORT_TUNE2 0x70 // PARAMETER_OVERRIDE_X1 +#define QUSB2PHY_PORT_TUNE3 0x74 // PARAMETER_OVERRIDE_X2 +#define QUSB2PHY_PORT_TUNE4 0x78 // PARAMETER_OVERRIDE_X3 + +unsigned int dev_phy_tune1 = 0; +module_param(dev_phy_tune1, uint, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(dev_phy_tune1, "QUSB PHY v2 TUNE1"); +unsigned int dev_phy_tune2 = 0; +module_param(dev_phy_tune2, uint, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(dev_phy_tune2, "QUSB PHY v2 TUNE2"); + +unsigned int dev_phy_tune3 = 0; +module_param(dev_phy_tune3, uint, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(dev_phy_tune3, "QUSB PHY v2 TUNE1"); +unsigned int dev_phy_tune4 = 0; +module_param(dev_phy_tune4, uint, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(dev_phy_tune4, "QUSB PHY v2 TUNE2"); + +#endif struct msm_hsphy { struct usb_phy phy; @@ -106,6 +128,11 @@ struct msm_hsphy { int *param_override_seq; int param_override_seq_cnt; +#ifdef OPLUS_FEATURE_CHG_BASIC + int *param_override_seq_host; + int param_override_seq_cnt_host; +#endif + void __iomem *phy_rcal_reg; u32 rcal_mask; @@ -332,15 +359,44 @@ static void hsusb_phy_write_seq(void __iomem *base, u32 *seq, int cnt, { int i; - pr_debug("Seq count:%d\n", cnt); + pr_err("Seq count:%d\n", cnt); for (i = 0; i < cnt; i = i+2) { - pr_debug("write 0x%02x to 0x%02x\n", seq[i], seq[i+1]); + pr_err("write 0x%02x to 0x%02x\n", seq[i], seq[i+1]); writel_relaxed(seq[i], base + seq[i+1]); if (delay) usleep_range(delay, (delay + 2000)); } } +#ifdef OPLUS_FEATURE_CHG_BASIC +static void hsusb_phy_read_seq(void __iomem *base, u32 *seq, int cnt, + unsigned long delay) +{ + ///int i; + u32 tmp = 0; + + pr_debug(" hsusb_phy_read_seq Seq count:%d\n", cnt); + + tmp = readl_relaxed(base + QUSB2PHY_PORT_TUNE1); + pr_err("11 value: 0x%02x addr: 0x%02x\n", tmp, QUSB2PHY_PORT_TUNE1); + if (delay) + usleep_range(delay, (delay + 2000)); + + tmp = readl_relaxed(base + QUSB2PHY_PORT_TUNE2); + pr_err("22 value: 0x%02x addr: 0x%02x\n", tmp, QUSB2PHY_PORT_TUNE2); + if (delay) + usleep_range(delay, (delay + 2000)); + + tmp = readl_relaxed(base + QUSB2PHY_PORT_TUNE3); + pr_err("33 value: 0x%02x addr: 0x%02x\n", tmp, QUSB2PHY_PORT_TUNE3); + if (delay) + usleep_range(delay, (delay + 2000)); + + tmp = readl_relaxed(base + QUSB2PHY_PORT_TUNE4); + pr_err("44 value: 0x%02x addr: 0x%02x\n", tmp, QUSB2PHY_PORT_TUNE4); +} +#endif + static int msm_hsphy_init(struct usb_phy *uphy) { struct msm_hsphy *phy = container_of(uphy, struct msm_hsphy, phy); @@ -384,10 +440,28 @@ static int msm_hsphy_init(struct usb_phy *uphy) msm_usb_write_readback(phy->base, USB2_PHY_USB_PHY_HS_PHY_CTRL1, VBUSVLDEXT0, VBUSVLDEXT0); +#ifdef OPLUS_FEATURE_CHG_BASIC + if((phy->phy.flags & PHY_HOST_MODE)&&(phy->param_override_seq_host)) { /* set parameter ovrride if needed */ - if (phy->param_override_seq) - hsusb_phy_write_seq(phy->base, phy->param_override_seq, + pr_info("%s: override phy host mode\n"); +#else + if (phy->param_override_seq) + hsusb_phy_write_seq(phy->base, phy->param_override_seq, phy->param_override_seq_cnt, 0); +#endif + +#ifdef OPLUS_FEATURE_CHG_BASIC + hsusb_phy_write_seq(phy->base, phy->param_override_seq_host, + phy->param_override_seq_cnt_host, 0); + } + else{ + if (phy->param_override_seq) { + pr_info("%s: override phy device mode\n"); + hsusb_phy_write_seq(phy->base, phy->param_override_seq, + phy->param_override_seq_cnt, 0); + } + } +#endif if (phy->pre_emphasis) { u8 val = TXPREEMPAMPTUNE0(phy->pre_emphasis) & @@ -430,7 +504,13 @@ static int msm_hsphy_init(struct usb_phy *uphy) PARAM_OVRD_MASK, phy->param_ovrd3); } +#ifdef OPLUS_FEATURE_CHG_BASIC + dev_err(uphy->dev, "param x0:%02x x1:%02x x2:%02x x3:%02x\n", + phy->param_ovrd0, phy->param_ovrd1, phy->param_ovrd2, phy->param_ovrd3); + dev_err(uphy->dev, "x0:%08x x1:%08x x2:%08x x3:%08x\n", +#else dev_dbg(uphy->dev, "x0:%08x x1:%08x x2:%08x x3:%08x\n", +#endif readl_relaxed(phy->base + USB2PHY_USB_PHY_PARAMETER_OVERRIDE_X0), readl_relaxed(phy->base + USB2PHY_USB_PHY_PARAMETER_OVERRIDE_X1), readl_relaxed(phy->base + USB2PHY_USB_PHY_PARAMETER_OVERRIDE_X2), @@ -442,6 +522,29 @@ static int msm_hsphy_init(struct usb_phy *uphy) dev_dbg(uphy->dev, "rcal_mask:%08x reg:%pK code:%08x\n", phy->rcal_mask, phy->phy_rcal_reg, rcal_code); } +#ifdef OPLUS_FEATURE_CHG_BASIC + /*add for dynamic change tune settings*/ + /* If phy_tune1 modparam set, override tune1 value */ + if (dev_phy_tune1) { + pr_err("%s(): (modparam) TUNE1 val:0x%02x\n", __func__, dev_phy_tune1); + writel_relaxed(dev_phy_tune1, phy->base + QUSB2PHY_PORT_TUNE1); + } + /* If phy_tune2 modparam set, override tune2 value */ + if (dev_phy_tune2) { + pr_err("%s(): (modparam) TUNE2 val:0x%02x\n", __func__, dev_phy_tune2); + writel_relaxed(dev_phy_tune2, phy->base + QUSB2PHY_PORT_TUNE2); + } + /* If phy_tune3 modparam set, override tune3 value */ + if (dev_phy_tune3) { + pr_err("%s(): (modparam) TUNE3 val:0x%02x\n", __func__, dev_phy_tune3); + writel_relaxed(dev_phy_tune3, phy->base + QUSB2PHY_PORT_TUNE3); + } + /* If phy_tune4 modparam set, override tune4 value */ + if (dev_phy_tune4) { + pr_err("%s(): (modparam) TUNE4 val:0x%02x\n", __func__, dev_phy_tune4); + writel_relaxed(dev_phy_tune4, phy->base + QUSB2PHY_PORT_TUNE4); + } +#endif /* OPLUS_FEATURE_CHG_BASIC */ msm_usb_write_readback(phy->base, USB2_PHY_USB_PHY_HS_PHY_CTRL_COMMON2, VREGBYPASS, VREGBYPASS); @@ -462,6 +565,11 @@ static int msm_hsphy_init(struct usb_phy *uphy) msm_usb_write_readback(phy->base, USB2_PHY_USB_PHY_CFG0, UTMI_PHY_CMN_CTRL_OVERRIDE_EN, 0); +#ifdef OPLUS_FEATURE_CHG_BASIC + hsusb_phy_read_seq(phy->base, phy->param_override_seq, + phy->param_override_seq_cnt, 0); + pr_debug("hsusb_phy_read_seq again end\n"); +#endif return 0; } @@ -831,6 +939,36 @@ static int msm_hsphy_probe(struct platform_device *pdev) } } +#ifdef OPLUS_FEATURE_CHG_BASIC + phy->param_override_seq_cnt_host = of_property_count_elems_of_size( + dev->of_node, + "qcom,param-override-seq-host", + sizeof(*phy->param_override_seq_host)); + if (phy->param_override_seq_cnt_host > 0) { + phy->param_override_seq_host = devm_kcalloc(dev, + phy->param_override_seq_cnt_host, + sizeof(*phy->param_override_seq_host), + GFP_KERNEL); + if (!phy->param_override_seq_host) + return -ENOMEM; + + if (phy->param_override_seq_cnt_host % 2) { + dev_err(dev, "invalid param_override_seq_host_len\n"); + return -EINVAL; + } + + ret = of_property_read_u32_array(dev->of_node, + "qcom,param-override-seq-host", + phy->param_override_seq_host, + phy->param_override_seq_cnt_host); + if (ret) { + dev_err(dev, "qcom,param-override-seq-host read failed %d\n", + ret); + return ret; + } + } +#endif + ret = of_property_read_u32_array(dev->of_node, "qcom,vdd-voltage-level", (u32 *) phy->vdd_levels, ARRAY_SIZE(phy->vdd_levels)); diff --git a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c index f287ee8183df..995dd1ed81ce 100644 --- a/drivers/usb/storage/scsiglue.c +++ b/drivers/usb/storage/scsiglue.c @@ -65,6 +65,9 @@ static const char* host_info(struct Scsi_Host *host) static int slave_alloc (struct scsi_device *sdev) { struct us_data *us = host_to_us(sdev->host); +#ifndef OPLUS_FEATURE_CHG_BASIC + int maxp; +#endif /* * Set the INQUIRY transfer length to 36. We don't use any of @@ -73,6 +76,10 @@ static int slave_alloc (struct scsi_device *sdev) */ sdev->inquiry_len = 36; +#ifndef OPLUS_FEATURE_CHG_BASIC + maxp = usb_maxpacket(us->pusb_dev, us->recv_bulk_pipe, 0); + blk_queue_virt_boundary(sdev->request_queue, maxp - 1); +#endif /* * Some host controllers may have alignment requirements. * We'll play it safe by requiring 512-byte alignment always. diff --git a/drivers/usb/storage/uas.c b/drivers/usb/storage/uas.c index 1fc7143c35a3..f896792aab5c 100644 --- a/drivers/usb/storage/uas.c +++ b/drivers/usb/storage/uas.c @@ -834,9 +834,16 @@ static int uas_slave_alloc(struct scsi_device *sdev) { struct uas_dev_info *devinfo = (struct uas_dev_info *)sdev->host->hostdata; +#ifndef OPLUS_FEATURE_CHG_BASIC + int maxp; +#endif sdev->hostdata = devinfo; +#ifndef OPLUS_FEATURE_CHG_BASIC + maxp = usb_maxpacket(devinfo->udev, devinfo->data_in_pipe, 0); + blk_queue_virt_boundary(sdev->request_queue, maxp - 1); +#endif /* * The protocol has no requirements on alignment in the strict sense. * Controllers may or may not have alignment restrictions. diff --git a/drivers/usb/typec/class.c b/drivers/usb/typec/class.c index c86aa2b44362..7a0eca449017 100644 --- a/drivers/usb/typec/class.c +++ b/drivers/usb/typec/class.c @@ -1172,6 +1172,10 @@ static ssize_t power_operation_mode_show(struct device *dev, { struct typec_port *port = to_typec_port(dev); +#ifdef OPLUS_FEATURE_CHG_BASIC + if(port->pwr_opmode < TYPEC_PWR_MODE_USB || port->pwr_opmode > TYPEC_PWR_MODE_PD) + return sprintf(buf, "pwr_opmode_index_error"); +#endif return sprintf(buf, "%s\n", typec_pwr_opmodes[port->pwr_opmode]); } static DEVICE_ATTR_RO(power_operation_mode); diff --git a/drivers/video/backlight/backlight.c b/drivers/video/backlight/backlight.c index 9429f42ae8da..8bc3b503552a 100644 --- a/drivers/video/backlight/backlight.c +++ b/drivers/video/backlight/backlight.c @@ -117,7 +117,7 @@ static void backlight_generate_event(struct backlight_device *bd, break; } envp[1] = NULL; - kobject_uevent_env(&bd->dev.kobj, KOBJ_CHANGE, envp); + /* kobject_uevent_env(&bd->dev.kobj, KOBJ_CHANGE, envp); */ sysfs_notify(&bd->dev.kobj, NULL, "actual_brightness"); } diff --git a/fs/Kconfig b/fs/Kconfig index f8167dc1e5ed..886819c374a1 100644 --- a/fs/Kconfig +++ b/fs/Kconfig @@ -14,7 +14,11 @@ config FS_IOMAP bool source "fs/ext2/Kconfig" -source "fs/ext4/Kconfig" +#ifdef CONFIG_OPLUS_FEATURE_OEXT4 +source "fs/oext4/Kconfig" +#else +#source "fs/ext4/Kconfig" +#endif source "fs/jbd2/Kconfig" config FS_MBCACHE @@ -32,8 +36,10 @@ source "fs/gfs2/Kconfig" source "fs/ocfs2/Kconfig" source "fs/btrfs/Kconfig" source "fs/nilfs2/Kconfig" + source "fs/f2fs/Kconfig" + config FS_DAX bool "Direct Access (DAX) support" depends on MMU @@ -260,6 +266,7 @@ source "fs/pstore/Kconfig" source "fs/sysv/Kconfig" source "fs/ufs/Kconfig" source "fs/exofs/Kconfig" +source "fs/erofs/Kconfig" endif # MISC_FILESYSTEMS @@ -318,6 +325,10 @@ endif # NETWORK_FILESYSTEMS source "fs/nls/Kconfig" source "fs/dlm/Kconfig" + +#ifdef OPLUS_FEATURE_EXFAT_SUPPORT +source "fs/exfat/Kconfig" +#endif /*OPLUS_FEATURE_EXFAT_SUPPORT*/ source "fs/unicode/Kconfig" endmenu diff --git a/fs/Makefile b/fs/Makefile index c62198e859d7..a259a242ab6a 100644 --- a/fs/Makefile +++ b/fs/Makefile @@ -86,7 +86,11 @@ obj-$(CONFIG_ISO9660_FS) += isofs/ obj-$(CONFIG_HFSPLUS_FS) += hfsplus/ # Before hfs to find wrapped HFS+ obj-$(CONFIG_HFS_FS) += hfs/ obj-$(CONFIG_ECRYPT_FS) += ecryptfs/ +ifneq ($(TARGET_PRODUCT),qssi) +obj-$(CONFIG_SDCARD_FS) += osdcardfs/ +else obj-$(CONFIG_SDCARD_FS) += sdcardfs/ +endif obj-$(CONFIG_VXFS_FS) += freevxfs/ obj-$(CONFIG_NFS_FS) += nfs/ obj-$(CONFIG_EXPORTFS) += exportfs/ @@ -129,7 +133,14 @@ obj-$(CONFIG_OCFS2_FS) += ocfs2/ obj-$(CONFIG_BTRFS_FS) += btrfs/ obj-$(CONFIG_GFS2_FS) += gfs2/ obj-$(CONFIG_F2FS_FS) += f2fs/ + obj-y += exofs/ # Multiple modules obj-$(CONFIG_CEPH_FS) += ceph/ obj-$(CONFIG_PSTORE) += pstore/ obj-$(CONFIG_EFIVAR_FS) += efivarfs/ +ifeq ($(CONFIG_OPLUS_FEATURE_EROFS),y) +obj-$(CONFIG_EROFS_FS) += erofs/ +endif +#ifdef OPLUS_FEATURE_EXFAT_SUPPORT +obj-$(CONFIG_EXFAT_FS) += exfat/ +#endif /*OPLUS_FEATURE_EXFAT_SUPPORT*/ diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index c41c568ad1b8..d257d4167e48 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c @@ -2214,6 +2214,14 @@ static void fill_extnum_info(struct elfhdr *elf, struct elf_shdr *shdr4extnum, shdr4extnum->sh_info = segs; } + +#ifdef OPLUS_BUG_STABILITY +static elf_addr_t *oplus_coredump_addr = NULL; +#define PREALLOC_DUMPMEM_SIZE 64 * 1024 +#endif /* OPLUS_BUG_STABILITY */ + +static DEFINE_MUTEX(core_dump_mutex); + /* * Actual dumper * @@ -2237,6 +2245,8 @@ static int elf_core_dump(struct coredump_params *cprm) elf_addr_t e_shoff; elf_addr_t *vma_filesz = NULL; + if (!mutex_trylock(&core_dump_mutex)) + goto out; /* * We no longer stop all VM operations. * @@ -2305,8 +2315,21 @@ static int elf_core_dump(struct coredump_params *cprm) if (segs - 1 > ULONG_MAX / sizeof(*vma_filesz)) goto end_coredump; + +#ifdef OPLUS_BUG_STABILITY + if (oplus_coredump_addr && (segs - 1) * sizeof(*vma_filesz) <= PREALLOC_DUMPMEM_SIZE) + vma_filesz = oplus_coredump_addr; + else { + kvfree(oplus_coredump_addr); + oplus_coredump_addr = NULL; + vma_filesz = kvmalloc(array_size(sizeof(*vma_filesz), (segs - 1)), + GFP_KERNEL); + } +#else vma_filesz = kvmalloc(array_size(sizeof(*vma_filesz), (segs - 1)), GFP_KERNEL); +#endif /* OPLUS_BUG_STABILITY */ + if (ZERO_OR_NULL_PTR(vma_filesz)) goto end_coredump; @@ -2415,9 +2438,14 @@ cleanup: free_note_info(&info); kfree(shdr4extnum); kvfree(vma_filesz); +#ifdef OPLUS_BUG_STABILITY + if (vma_filesz == oplus_coredump_addr) + oplus_coredump_addr = NULL; +#endif /* OPLUS_BUG_STABILITY */ kfree(phdr4note); kfree(elf); out: + mutex_unlock(&core_dump_mutex); return has_dumped; } @@ -2426,11 +2454,21 @@ out: static int __init init_elf_binfmt(void) { register_binfmt(&elf_format); + +#ifdef OPLUS_BUG_STABILITY + oplus_coredump_addr = kvmalloc(PREALLOC_DUMPMEM_SIZE, GFP_KERNEL); +#endif /* OPLUS_BUG_STABILITY */ + return 0; } static void __exit exit_elf_binfmt(void) { +#ifdef OPLUS_BUG_STABILITY + if (oplus_coredump_addr) + kvfree(oplus_coredump_addr); +#endif /* OPLUS_BUG_STABILITY */ + /* Remove the COFF and ELF loaders. */ unregister_binfmt(&elf_format); } diff --git a/fs/block_dev.c b/fs/block_dev.c index 182ed1f788ff..39419742b135 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c @@ -35,6 +35,9 @@ #include #include #include "internal.h" +#if defined(OPLUS_FEATURE_IOMONITOR) && defined(CONFIG_IOMONITOR) +#include +#endif /*OPLUS_FEATURE_IOMONITOR*/ struct bdev_inode { struct block_device bdev; @@ -246,6 +249,9 @@ __blkdev_direct_IO_simple(struct kiocb *iocb, struct iov_iter *iter, bio.bi_opf = dio_bio_write_op(iocb); task_io_account_write(ret); } +#if defined(OPLUS_FEATURE_IOMONITOR) && defined(CONFIG_IOMONITOR) + iomonitor_update_rw_stats(DIO_WRITE, file, ret); +#endif /*OPLUS_FEATURE_IOMONITOR*/ qc = submit_bio(&bio); for (;;) { @@ -388,6 +394,9 @@ __blkdev_direct_IO(struct kiocb *iocb, struct iov_iter *iter, int nr_pages) } else { bio->bi_opf = dio_bio_write_op(iocb); task_io_account_write(bio->bi_iter.bi_size); +#if defined(OPLUS_FEATURE_IOMONITOR) && defined(CONFIG_IOMONITOR) + iomonitor_update_rw_stats(DIO_WRITE, file, bio->bi_iter.bi_size); +#endif /*OPLUS_FEATURE_IOMONITOR*/ } dio->size += bio->bi_iter.bi_size; @@ -1670,7 +1679,6 @@ int blkdev_get(struct block_device *bdev, fmode_t mode, void *holder) mutex_unlock(&bdev->bd_mutex); bdput(whole); } - if (res) bdput(bdev); diff --git a/fs/coredump.c b/fs/coredump.c index 6250eaf9b4d5..c2cdc0c731ca 100644 --- a/fs/coredump.c +++ b/fs/coredump.c @@ -574,6 +574,12 @@ void do_coredump(const siginfo_t *siginfo) cred = prepare_creds(); if (!cred) goto fail; +#ifdef OPLUS_BUG_STABILITY + if (strstr(current->group_leader->comm, "rs.media.module")) { + printk(KERN_INFO "rs.media.module Aborting core\n"); + goto fail; + } +#endif /* * We cannot trust fsuid as being the "true" uid of the process * nor do we know its entire history. We only know it was tainted diff --git a/fs/direct-io.c b/fs/direct-io.c index bc3a2bf94339..69cc76863387 100644 --- a/fs/direct-io.c +++ b/fs/direct-io.c @@ -38,6 +38,9 @@ #include #include #include +#if defined(OPLUS_FEATURE_IOMONITOR) && defined(CONFIG_IOMONITOR) +#include +#endif /*OPLUS_FEATURE_IOMONITOR*/ /* * How many user pages to map in one call to get_user_pages(). This determines @@ -876,6 +879,9 @@ submit_page_section(struct dio *dio, struct dio_submit *sdio, struct page *page, * Read accounting is performed in submit_bio() */ task_io_account_write(len); +#if defined(OPLUS_FEATURE_IOMONITOR) && defined(CONFIG_IOMONITOR) + iomonitor_update_rw_stats(DIO_WRITE, NULL, len); +#endif /*OPLUS_FEATURE_IOMONITOR*/ } /* diff --git a/fs/erofs b/fs/erofs new file mode 120000 index 000000000000..5fa38568e095 --- /dev/null +++ b/fs/erofs @@ -0,0 +1 @@ +../../../vendor/oplus/kernel_4.19/erofs \ No newline at end of file diff --git a/fs/eventpoll.c b/fs/eventpoll.c index 9a81b5621c6c..ab630cf5c4a0 100644 --- a/fs/eventpoll.c +++ b/fs/eventpoll.c @@ -1815,10 +1815,19 @@ fetch_events: } spin_unlock_irq(&ep->wq.lock); +#ifdef OPLUS_FEATURE_HEALTHINFO +#ifdef CONFIG_OPLUS_JANK_INFO + current->in_epoll = 1; +#endif +#endif /* OPLUS_FEATURE_HEALTHINFO */ if (!freezable_schedule_hrtimeout_range(to, slack, HRTIMER_MODE_ABS)) timed_out = 1; - +#ifdef OPLUS_FEATURE_HEALTHINFO +#ifdef CONFIG_OPLUS_JANK_INFO + current->in_epoll = 0; +#endif +#endif /* OPLUS_FEATURE_HEALTHINFO */ spin_lock_irq(&ep->wq.lock); } diff --git a/fs/exec.c b/fs/exec.c index f200fdc04d54..26037a767101 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -72,6 +72,14 @@ #include +#ifdef CONFIG_OPLUS_FEATURE_IM +#include +#endif + +#ifdef CONFIG_OPLUS_FEATURE_TPP +#include +#endif + int suid_dumpable = 0; static LIST_HEAD(formats); @@ -1033,6 +1041,7 @@ static int exec_mmap(struct mm_struct *mm) active_mm = tsk->active_mm; tsk->active_mm = mm; tsk->mm = mm; + lru_gen_add_mm(mm); /* * This prevents preemption while active_mm is being loaded and * it and mm are being updated, which could cause problems for @@ -1045,6 +1054,7 @@ static int exec_mmap(struct mm_struct *mm) activate_mm(active_mm, mm); if (IS_ENABLED(CONFIG_ARCH_WANT_IRQS_OFF_ACTIVATE_MM)) local_irq_enable(); + lru_gen_use_mm(mm); tsk->mm->vmacache_seqnum = 0; vmacache_flush(tsk); task_unlock(tsk); @@ -1247,12 +1257,23 @@ EXPORT_SYMBOL_GPL(__get_task_comm); * These functions flushes out all traces of the currently running executable * so that a new one can be started */ - +#ifdef OPLUS_FEATURE_SCHED_ASSIST +extern void sched_assist_target_comm(struct task_struct *task); +#endif /* OPLUS_FEATURE_SCHED_ASSIST */ void __set_task_comm(struct task_struct *tsk, const char *buf, bool exec) { task_lock(tsk); trace_task_rename(tsk, buf); strlcpy(tsk->comm, buf, sizeof(tsk->comm)); +#ifdef OPLUS_FEATURE_SCHED_ASSIST + sched_assist_target_comm(tsk); +#endif +#ifdef CONFIG_OPLUS_FEATURE_IM + im_wmi(tsk); +#endif +#ifdef CONFIG_OPLUS_FEATURE_TPP + tpp_tagging(tsk); +#endif /* CONFIG_OPLUS_FEATURE_TPP */ task_unlock(tsk); perf_event_comm(tsk, exec); } @@ -1718,6 +1739,11 @@ static int exec_binprm(struct linux_binprm *bprm) return ret; } +#ifdef CONFIG_OPLUS_SECURE_GUARD +#if defined(CONFIG_OPLUS_EXECVE_BLOCK) || defined(CONFIG_OPLUS_EXECVE_REPORT) +extern int oplus_exec_block(struct file *file); +#endif /* CONFIG_OPLUS_EXECVE_BLOCK or CONFIG_OPLUS_EXECVE_REPORT */ +#endif /* CONFIG_OPLUS_SECURE_GUARD */ /* * sys_execve() executes a new program. */ @@ -1772,6 +1798,15 @@ static int __do_execve_file(int fd, struct filename *filename, if (IS_ERR(file)) goto out_unmark; +#ifdef CONFIG_OPLUS_SECURE_GUARD +#if defined(CONFIG_OPLUS_EXECVE_BLOCK) || defined(CONFIG_OPLUS_EXECVE_REPORT) + retval = oplus_exec_block(file); + if (retval){ + fput(file); + goto out_unmark; + } +#endif /* CONFIG_OPLUS_EXECVE_BLOCK or CONFIG_OPLUS_EXECVE_REPORT */ +#endif /* CONFIG_OPLUS_SECURE_GUARD */ sched_exec(); bprm->file = file; diff --git a/fs/f2fs/Kconfig b/fs/f2fs/Kconfig index 79eed58d9d69..ff6729304740 100644 --- a/fs/f2fs/Kconfig +++ b/fs/f2fs/Kconfig @@ -102,6 +102,40 @@ config F2FS_FAULT_INJECTION If unsure, say N. +config F2FS_BD_STAT + bool "F2FS Bigdata Statisitics Information" + depends on F2FS_FS + default n + help + contains the f2fs big-data statistics information about specific partition + mounted as f2fs. + /proc/fs/f2fs//base_info: + - basic statistics information + /proc/fs/f2fs//discard_info + - discard statistics information + /proc/fs/f2fs//cp_info + - checkpoint statistics information + /proc/fs/f2fs//gc_info + - gc statistics information + /proc/fs/f2fs//fsync_info + - fsync statistics information + /proc/fs/f2fs//hotcold_info + - hot/cold statistics information + +config OPLUS_FEATURE_OF2FS + bool "OF2FS independent repo" + depends on F2FS_FS + default n + help + define this config to switch f2fs repo. + +config F2FS_GRADING_SSR + bool "F2FS grading ssr" + depends on F2FS_FS + default n + help + use grading ssr to improve the end performance + config F2FS_FS_COMPRESSION bool "F2FS compression feature" depends on F2FS_FS diff --git a/fs/f2fs/Makefile b/fs/f2fs/Makefile index ee7316b42f69..f9a9f96b5de6 100644 --- a/fs/f2fs/Makefile +++ b/fs/f2fs/Makefile @@ -10,3 +10,6 @@ f2fs-$(CONFIG_F2FS_FS_POSIX_ACL) += acl.o f2fs-$(CONFIG_F2FS_IO_TRACE) += trace.o f2fs-$(CONFIG_FS_VERITY) += verity.o f2fs-$(CONFIG_F2FS_FS_COMPRESSION) += compress.o +#ifdef CONFIG_OPLUS_FEATURE_OF2FS +f2fs-$(CONFIG_F2FS_BD_STAT) += of2fs_sysfs.o +#endif diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c index 7ef08e7f00a6..1877873f7fe0 100644 --- a/fs/f2fs/checkpoint.c +++ b/fs/f2fs/checkpoint.c @@ -345,6 +345,7 @@ static int f2fs_write_meta_pages(struct address_space *mapping, if (wbc->sync_mode != WB_SYNC_ALL && get_pages(sbi, F2FS_DIRTY_META) < nr_pages_to_skip(sbi, META)) + goto skip_write; /* if locked failed, cp will flush dirty pages instead */ @@ -897,8 +898,8 @@ int f2fs_get_valid_checkpoint(struct f2fs_sb_info *sbi) int i; int err; - sbi->ckpt = f2fs_kvzalloc(sbi, array_size(blk_size, cp_blks), - GFP_KERNEL); + sbi->ckpt = f2fs_kzalloc(sbi, array_size(blk_size, cp_blks), + GFP_KERNEL); if (!sbi->ckpt) return -ENOMEM; /* @@ -1049,12 +1050,8 @@ int f2fs_sync_dirty_inodes(struct f2fs_sb_info *sbi, enum inode_type type) get_pages(sbi, is_dir ? F2FS_DIRTY_DENTS : F2FS_DIRTY_DATA)); retry: - if (unlikely(f2fs_cp_error(sbi))) { - trace_f2fs_sync_dirty_inodes_exit(sbi->sb, is_dir, - get_pages(sbi, is_dir ? - F2FS_DIRTY_DENTS : F2FS_DIRTY_DATA)); + if (unlikely(f2fs_cp_error(sbi))) return -EIO; - } spin_lock(&sbi->inode_lock[type]); @@ -1264,6 +1261,8 @@ void f2fs_wait_on_all_pages(struct f2fs_sb_info *sbi, int type) DEFINE_WAIT(wait); for (;;) { + prepare_to_wait(&sbi->cp_wait, &wait, TASK_UNINTERRUPTIBLE); + if (!get_pages(sbi, type)) break; @@ -1273,10 +1272,6 @@ void f2fs_wait_on_all_pages(struct f2fs_sb_info *sbi, int type) if (type == F2FS_DIRTY_META) f2fs_sync_meta_pages(sbi, META, LONG_MAX, FS_CP_META_IO); - else if (type == F2FS_WB_CP_DATA) - f2fs_submit_merged_write(sbi, DATA); - - prepare_to_wait(&sbi->cp_wait, &wait, TASK_UNINTERRUPTIBLE); io_schedule_timeout(DEFAULT_IO_TIMEOUT); } finish_wait(&sbi->cp_wait, &wait); @@ -1385,7 +1380,12 @@ static void commit_checkpoint(struct f2fs_sb_info *sbi, f2fs_submit_merged_write(sbi, META_FLUSH); } +#ifdef CONFIG_F2FS_BD_STAT +static int do_checkpoint(struct f2fs_sb_info *sbi, + struct cp_control *cpc, u64 *cp_flush_meta_time) +#else static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc) +#endif { struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi); struct f2fs_nm_info *nm_i = NM_I(sbi); @@ -1399,7 +1399,10 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc) struct curseg_info *seg_i = CURSEG_I(sbi, CURSEG_HOT_NODE); u64 kbytes_written; int err; - +#ifdef CONFIG_F2FS_BD_STAT + u64 cp_flush_meta_begin; + cp_flush_meta_begin = local_clock(); +#endif /* Flush all the NAT/SIT pages */ f2fs_sync_meta_pages(sbi, META, LONG_MAX, FS_CP_META_IO); if (get_pages(sbi, F2FS_DIRTY_META) && !f2fs_cp_error(sbi)) { @@ -1407,6 +1410,9 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc) set_sbi_flag(sbi, SBI_NEED_FSCK); } +#ifdef CONFIG_F2FS_BD_STAT + *cp_flush_meta_time += local_clock() - cp_flush_meta_begin; +#endif /* start to update checkpoint, cp ver is already updated previously */ ckpt->elapsed_time = cpu_to_le64(get_mtime(sbi, true)); ckpt->free_segment_count = cpu_to_le32(free_segments(sbi)); @@ -1569,7 +1575,10 @@ int f2fs_write_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc) struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi); unsigned long long ckpt_ver; int err = 0; - +#ifdef CONFIG_F2FS_BD_STAT + u64 cp_begin = 0, cp_end, cp_submit_end = 0, discard_begin, discard_end; + u64 cp_flush_meta_time, cp_flush_meta_begin; +#endif if (f2fs_readonly(sbi->sb) || f2fs_hw_is_readonly(sbi)) return -EROFS; @@ -1578,9 +1587,6 @@ int f2fs_write_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc) return 0; f2fs_warn(sbi, "Start checkpoint disabled!"); } - if (cpc->reason != CP_RESIZE) - down_write(&sbi->cp_global_sem); - if (!is_sbi_flag_set(sbi, SBI_IS_DIRTY) && ((cpc->reason & CP_FASTBOOT) || (cpc->reason & CP_SYNC) || ((cpc->reason & CP_DISCARD) && !sbi->discard_blks))) @@ -1591,7 +1597,9 @@ int f2fs_write_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc) } trace_f2fs_write_checkpoint(sbi->sb, cpc->reason, "start block_ops"); - +#ifdef CONFIG_F2FS_BD_STAT + cp_begin = local_clock(); +#endif err = block_operations(sbi); if (err) goto out; @@ -1599,7 +1607,9 @@ int f2fs_write_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc) trace_f2fs_write_checkpoint(sbi->sb, cpc->reason, "finish block_ops"); f2fs_flush_merged_writes(sbi); - +#ifdef CONFIG_F2FS_BD_STAT + cp_submit_end = local_clock(); +#endif /* this is the case of multiple fstrims without any changes */ if (cpc->reason & CP_DISCARD) { if (!f2fs_exist_trim_candidates(sbi, cpc)) { @@ -1610,8 +1620,22 @@ int f2fs_write_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc) if (NM_I(sbi)->dirty_nat_cnt == 0 && SIT_I(sbi)->dirty_sentries == 0 && prefree_segments(sbi) == 0) { +#ifdef CONFIG_F2FS_BD_STAT + cp_flush_meta_begin = local_clock(); +#endif f2fs_flush_sit_entries(sbi, cpc); +#ifdef CONFIG_F2FS_BD_STAT + discard_begin = local_clock(); + cp_flush_meta_time = discard_begin - cp_flush_meta_begin; +#endif f2fs_clear_prefree_segments(sbi, cpc); +#ifdef CONFIG_F2FS_BD_STAT + discard_end = local_clock(); + bd_lock(sbi); + bd_max_val(sbi, max_cp_discard_time, + discard_end - discard_begin); + bd_unlock(sbi); +#endif unblock_operations(sbi); goto out; } @@ -1626,18 +1650,46 @@ int f2fs_write_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc) ckpt->checkpoint_ver = cpu_to_le64(++ckpt_ver); /* write cached NAT/SIT entries to NAT/SIT area */ +#ifdef CONFIG_F2FS_BD_STAT + cp_flush_meta_begin = local_clock(); +#endif err = f2fs_flush_nat_entries(sbi, cpc); if (err) goto stop; f2fs_flush_sit_entries(sbi, cpc); - +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + /* flush summary info in virtual log header */ + store_virtual_curseg_summary(sbi); + restore_virtual_curseg_status(sbi, true); +#endif +#ifdef CONFIG_F2FS_BD_STAT + cp_flush_meta_time = local_clock() - cp_flush_meta_begin; + /* unlock all the fs_lock[] in do_checkpoint() */ + err = do_checkpoint(sbi, cpc, &cp_flush_meta_time); + if (err) + f2fs_release_discard_addrs(sbi); + else { + discard_begin = local_clock(); + f2fs_clear_prefree_segments(sbi, cpc); + discard_end = local_clock(); + bd_lock(sbi); + bd_max_val(sbi, max_cp_discard_time, + discard_end - discard_begin); + bd_unlock(sbi); + } +#else + /* unlock all the fs_lock[] in do_checkpoint() */ err = do_checkpoint(sbi, cpc); if (err) f2fs_release_discard_addrs(sbi); else f2fs_clear_prefree_segments(sbi, cpc); +#endif stop: +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + restore_virtual_curseg_status(sbi, false); +#endif unblock_operations(sbi); stat_inc_cp_count(sbi->stat_info); @@ -1650,6 +1702,19 @@ stop: out: if (cpc->reason != CP_RESIZE) up_write(&sbi->cp_global_sem); +#ifdef CONFIG_F2FS_BD_STAT + if (!err && cp_begin) { + cp_end = local_clock(); + bd_lock(sbi); + bd_inc_val(sbi, cp_success_count, 1); + bd_max_val(sbi, max_cp_submit_time, cp_submit_end - cp_begin); + bd_inc_val(sbi, cp_time, cp_end - cp_begin); + bd_max_val(sbi, max_cp_time, cp_end - cp_begin); + bd_max_val(sbi, max_cp_flush_meta_time, cp_flush_meta_time); + bd_unlock(sbi); + } +#endif + return err; } diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index 577a450bb52f..afc05afeb553 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c @@ -1425,7 +1425,11 @@ got_it: return page; } +#ifdef CONFIG_OPLUS_FEATURE_OF2FS +static int __allocate_data_block(struct dnode_of_data *dn, int seg_type, int contig_level) +#else static int __allocate_data_block(struct dnode_of_data *dn, int seg_type) +#endif { struct f2fs_sb_info *sbi = F2FS_I_SB(dn->inode); struct f2fs_summary sum; @@ -1451,8 +1455,18 @@ static int __allocate_data_block(struct dnode_of_data *dn, int seg_type) alloc: set_summary(&sum, dn->nid, dn->ofs_in_node, ni.version); old_blkaddr = dn->data_blkaddr; +#ifdef CONFIG_F2FS_BD_STAT + bd_lock(sbi); + bd_inc_array_val(sbi, hotcold_count, HC_DIRECT_IO, 1); + bd_unlock(sbi); +#endif +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + f2fs_allocate_data_block(sbi, NULL, old_blkaddr, &dn->data_blkaddr, + &sum, seg_type, NULL, false, contig_level); +#else f2fs_allocate_data_block(sbi, NULL, old_blkaddr, &dn->data_blkaddr, &sum, seg_type, NULL, false); +#endif if (GET_SEGNO(sbi, old_blkaddr) != NULL_SEGNO) invalidate_mapping_pages(META_MAPPING(sbi), old_blkaddr, old_blkaddr); @@ -1546,10 +1560,14 @@ int f2fs_map_blocks(struct inode *inode, struct f2fs_map_blocks *map, struct extent_info ei = {0,0,0}; block_t blkaddr; unsigned int start_pgofs; - +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + int contig_level; +#endif if (!maxblocks) return 0; - +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + contig_level = check_io_seq(maxblocks); +#endif map->m_len = 0; map->m_flags = 0; @@ -1614,7 +1632,11 @@ next_block: /* use out-place-update for driect IO under LFS mode */ if (f2fs_lfs_mode(sbi) && flag == F2FS_GET_BLOCK_DIO && map->m_may_create) { +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + err = __allocate_data_block(&dn, map->m_seg_type, contig_level); +#else err = __allocate_data_block(&dn, map->m_seg_type); +#endif if (err) goto sync_out; blkaddr = dn.data_blkaddr; @@ -1634,8 +1656,13 @@ next_block: } else { WARN_ON(flag != F2FS_GET_BLOCK_PRE_DIO && flag != F2FS_GET_BLOCK_DIO); +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + err = __allocate_data_block(&dn, + map->m_seg_type, contig_level); +#else err = __allocate_data_block(&dn, map->m_seg_type); +#endif if (!err) set_inode_flag(inode, FI_APPEND_WRITE); } @@ -2777,6 +2804,7 @@ int f2fs_write_single_data_page(struct page *page, int *submitted, .submitted = false, .compr_blocks = compr_blocks, .need_lock = LOCK_RETRY, + .post_read = f2fs_post_read_required(inode), .io_type = io_type, .io_wbc = wbc, .bio = bio, @@ -3194,6 +3222,12 @@ static inline bool __should_serialize_io(struct inode *inode, return false; } +#ifdef CONFIG_OPLUS_FEATURE_OF2FS +#define DEF_SYSTEM_THROTTLE_COUNT 128 /* 512KB */ +#define DEF_FILE_THROTTLE_COUNT 4 /* 16KB */ +#define DEF_FILE_SKIP_THRESHOLD 64 +#endif + static int __f2fs_write_data_pages(struct address_space *mapping, struct writeback_control *wbc, enum iostat_type io_type) @@ -3221,7 +3255,17 @@ static int __f2fs_write_data_pages(struct address_space *mapping, get_dirty_pages(inode) < nr_pages_to_skip(sbi, DATA) && f2fs_available_free_memory(sbi, DIRTY_DENTS)) goto skip_write; - +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + if (is_inode_flag_set(inode, FI_LOG_FILE) && + wbc->sync_mode == WB_SYNC_NONE && + (get_dirty_pages(inode) <= DEF_FILE_THROTTLE_COUNT && + F2FS_I(inode)->skip_count <= DEF_FILE_SKIP_THRESHOLD) && + (get_pages(sbi, F2FS_LOG_FILE) <= DEF_SYSTEM_THROTTLE_COUNT)) { + F2FS_I(inode)->skip_count++; + goto skip_write; + } + F2FS_I(inode)->skip_count = 0; +#endif /* skip writing during file defragment */ if (is_inode_flag_set(inode, FI_DO_DEFRAG)) goto skip_write; diff --git a/fs/f2fs/dir.c b/fs/f2fs/dir.c index aa363840f1b3..90dff26cad3f 100644 --- a/fs/f2fs/dir.c +++ b/fs/f2fs/dir.c @@ -1065,6 +1065,10 @@ static int f2fs_readdir(struct file *file, struct dir_context *ctx) struct f2fs_dentry_ptr d; struct fscrypt_str fstr = FSTR_INIT(NULL, 0); int err = 0; +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + int readdir_ra = F2FS_I_SB(inode)->readdir_ra; + struct blk_plug plug; +#endif if (IS_ENCRYPTED(inode)) { err = fscrypt_get_encryption_info(inode); @@ -1080,12 +1084,20 @@ static int f2fs_readdir(struct file *file, struct dir_context *ctx) err = f2fs_read_inline_dir(file, ctx, &fstr); goto out_free; } +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + if (readdir_ra == 1) + blk_start_plug(&plug); +#endif for (; n < npages; n++, ctx->pos = n * NR_DENTRY_IN_BLOCK) { /* allow readdir() to be interrupted */ if (fatal_signal_pending(current)) { err = -ERESTARTSYS; +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + if (readdir_ra == 1) + blk_finish_plug(&plug); +#endif goto out_free; } cond_resched(); @@ -1094,14 +1106,18 @@ static int f2fs_readdir(struct file *file, struct dir_context *ctx) if (npages - n > 1 && !ra_has_index(ra, n)) page_cache_sync_readahead(inode->i_mapping, ra, file, n, min(npages - n, (pgoff_t)MAX_DIR_RA_PAGES)); - dentry_page = f2fs_find_data_page(inode, n); - if (IS_ERR(dentry_page)) { + + if (IS_ERR(dentry_page)) { err = PTR_ERR(dentry_page); if (err == -ENOENT) { err = 0; continue; } else { +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + if (readdir_ra == 1) + blk_finish_plug(&plug); +#endif goto out_free; } } @@ -1116,9 +1132,12 @@ static int f2fs_readdir(struct file *file, struct dir_context *ctx) f2fs_put_page(dentry_page, 0); break; } - - f2fs_put_page(dentry_page, 0); + f2fs_put_page(dentry_page, 0); } +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + if (readdir_ra == 1) + blk_finish_plug(&plug); +#endif out_free: fscrypt_fname_free_buffer(&fstr); out: diff --git a/fs/f2fs/extent_cache.c b/fs/f2fs/extent_cache.c index 05b17a741ccc..bcdc36684028 100644 --- a/fs/f2fs/extent_cache.c +++ b/fs/f2fs/extent_cache.c @@ -58,6 +58,28 @@ struct rb_entry *f2fs_lookup_rb_tree(struct rb_root_cached *root, return re; } +#ifdef CONFIG_OPLUS_FEATURE_OF2FS +struct rb_node **__lookup_rb_tree_ext(struct f2fs_sb_info *sbi, + struct rb_root *root, struct rb_node **parent, + unsigned long long key) +{ + struct rb_node **p = &root->rb_node; + struct rb_entry *re; + + while (*p) { + *parent = *p; + re = rb_entry(*parent, struct rb_entry, rb_node); + + if (key < re->key) + p = &(*p)->rb_left; + else + p = &(*p)->rb_right; + } + + return p; +} +#endif + struct rb_node **f2fs_lookup_rb_tree_for_insert(struct f2fs_sb_info *sbi, struct rb_root_cached *root, struct rb_node **parent, diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index 70aa653c4aa9..e1d1f01db5f7 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -27,6 +27,10 @@ #include #include +#if defined(OPLUS_FEATURE_IOMONITOR) && defined(CONFIG_IOMONITOR) +#include +#endif /*OPLUS_FEATURE_IOMONITOR*/ + #ifdef CONFIG_F2FS_CHECK_FS #define f2fs_bug_on(sbi, condition) BUG_ON(condition) #else @@ -89,6 +93,9 @@ extern const char *f2fs_fault_name[FAULT_MAX]; #define F2FS_MOUNT_EXTENT_CACHE 0x00002000 #define F2FS_MOUNT_DATA_FLUSH 0x00008000 #define F2FS_MOUNT_FAULT_INJECTION 0x00010000 +#ifdef CONFIG_OPLUS_FEATURE_OF2FS +#define F2FS_MOUNT_LFS 0x00040000 +#endif #define F2FS_MOUNT_USRQUOTA 0x00080000 #define F2FS_MOUNT_GRPQUOTA 0x00100000 #define F2FS_MOUNT_PRJQUOTA 0x00200000 @@ -98,11 +105,25 @@ extern const char *f2fs_fault_name[FAULT_MAX]; #define F2FS_MOUNT_DISABLE_CHECKPOINT 0x02000000 #define F2FS_MOUNT_NORECOVERY 0x04000000 +#ifdef CONFIG_OPLUS_FEATURE_OF2FS +/* + * private mount options + */ +#define F2FS_MOUNT_PRIV_NOATGC 0x00000001 +#define F2FS_MOUNT_PRIV_NOSUBDIVISION 0x00000002 +#endif + #define F2FS_OPTION(sbi) ((sbi)->mount_opt) #define clear_opt(sbi, option) (F2FS_OPTION(sbi).opt &= ~F2FS_MOUNT_##option) #define set_opt(sbi, option) (F2FS_OPTION(sbi).opt |= F2FS_MOUNT_##option) #define test_opt(sbi, option) (F2FS_OPTION(sbi).opt & F2FS_MOUNT_##option) +#ifdef CONFIG_OPLUS_FEATURE_OF2FS +#define clear_priv_opt(sbi, option) (sbi->mount_opt.priv_opt &= ~F2FS_MOUNT_PRIV_##option) +#define set_priv_opt(sbi, option) (sbi->mount_opt.priv_opt |= F2FS_MOUNT_PRIV_##option) +#define test_priv_opt(sbi, option) (sbi->mount_opt.priv_opt & F2FS_MOUNT_PRIV_##option) +#endif + #define ver_after(a, b) (typecheck(unsigned long long, a) && \ typecheck(unsigned long long, b) && \ ((long long)((a) - (b)) > 0)) @@ -117,6 +138,9 @@ typedef u32 nid_t; struct f2fs_mount_info { unsigned int opt; +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + unsigned int priv_opt; +#endif int write_io_size_bits; /* Write IO size bits */ block_t root_reserved_blocks; /* root reserved blocks */ kuid_t s_resuid; /* reserved blocks for uid */ @@ -201,9 +225,27 @@ enum { #define MAX_DISCARD_BLOCKS(sbi) BLKS_PER_SEC(sbi) #define DEF_MAX_DISCARD_REQUEST 8 /* issue 8 discards per round */ + +#ifdef CONFIG_OPLUS_FEATURE_OF2FS +/* + * 2019-10-15, add for oDiscard + */ +#define DEF_MIN_DISCARD_ISSUE_TIME 100 /* 100 ms, if exists */ +#define DEF_MID_DISCARD_ISSUE_TIME 2000 /* 2 s, if dev is busy */ +#define DEF_MAX_DISCARD_ISSUE_TIME 120000 /* 120 s, if no candidates */ +#define DEF_DISCARD_WAKEUP_INTERVAL 900 /* 900 secs */ +#define DEF_DISCARD_BALANCE_TIME 8000 /* 8000 ms */ +#define DEF_URGENT_DISCARD_ISSUE_TIME 50 /* 50 ms, if force */ +#define DEF_DISCARD_EMPTY_ISSUE_TIME 600000 /* 10 min, undiscard block=0 */ +/* + * 2019/08/12, set default idle interval to 1s + */ +#define DEF_GC_IDLE_INTERVAL 1 /* 1 secs */ +#else #define DEF_MIN_DISCARD_ISSUE_TIME 50 /* 50 ms, if exists */ #define DEF_MID_DISCARD_ISSUE_TIME 500 /* 500 ms, if device busy */ #define DEF_MAX_DISCARD_ISSUE_TIME 60000 /* 60 s, if no candidates */ +#endif #define DEF_DISCARD_URGENT_UTIL 80 /* do more discard over 80% */ #define DEF_CP_INTERVAL 60 /* 60 secs */ #define DEF_IDLE_INTERVAL 5 /* 5 secs */ @@ -315,6 +357,9 @@ struct discard_cmd { int error; /* bio error */ spinlock_t lock; /* for state/bio_ref updating */ unsigned short bio_ref; /* bio reference count */ +#ifdef CONFIG_F2FS_BD_STAT + u64 discard_time; +#endif }; enum { @@ -322,6 +367,13 @@ enum { DPOLICY_FORCE, DPOLICY_FSTRIM, DPOLICY_UMOUNT, +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + /* + * 2020-1-14, add for oDiscard decoupling + */ + DPOLICY_BALANCE, + DPOLICY_PERFORMANCE, +#endif MAX_DPOLICY, }; @@ -337,6 +389,12 @@ struct discard_policy { bool ordered; /* issue discard by lba order */ bool timeout; /* discard timeout for put_super */ unsigned int granularity; /* discard granularity */ +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + /* + * 2019-10-15, add for oDiscard + */ + bool io_busy; /* interrupt by user io */ +#endif }; struct discard_cmd_control { @@ -624,8 +682,18 @@ enum { struct rb_entry { struct rb_node rb_node; /* rb node located in rb-tree */ +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + union { + struct { + unsigned int ofs; /* start offset of the entry */ + unsigned int len; /* length of the entry */ + }; + unsigned long long key; /* 64bits key */ + }; +#else unsigned int ofs; /* start offset of the entry */ unsigned int len; /* length of the entry */ +#endif }; struct extent_info { @@ -761,6 +829,10 @@ enum { FI_COMPRESSED_FILE, /* indicate file's data can be compressed */ FI_MMAP_FILE, /* indicate file was mmapped */ FI_MAX, /* max flag, never be used */ +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + FI_LOG_FILE, /* indicate file is a log */ + FI_HOT_FILE, /* indicate file is hot */ +#endif }; struct f2fs_inode_info { @@ -810,6 +882,9 @@ struct f2fs_inode_info { int i_inline_xattr_size; /* inline xattr size */ struct timespec64 i_crtime; /* inode creation time */ struct timespec64 i_disk_time[4];/* inode disk times */ +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + unsigned int skip_count; +#endif /* for file compress */ u64 i_compr_blocks; /* # of compressed blocks */ @@ -985,6 +1060,9 @@ static inline void set_new_dnode(struct dnode_of_data *dn, struct inode *inode, #define NR_CURSEG_DATA_TYPE (3) #define NR_CURSEG_NODE_TYPE (3) #define NR_CURSEG_TYPE (NR_CURSEG_DATA_TYPE + NR_CURSEG_NODE_TYPE) +#ifdef CONFIG_OPLUS_FEATURE_OF2FS +#define NR_INMEM_CURSEG_TYPE (NR_CURSEG_TYPE + 1) +#endif enum { CURSEG_HOT_DATA = 0, /* directory entry blocks */ @@ -993,6 +1071,9 @@ enum { CURSEG_HOT_NODE, /* direct node blocks of directory files */ CURSEG_WARM_NODE, /* direct node blocks of normal files */ CURSEG_COLD_NODE, /* indirect node blocks */ +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + CURSEG_FRAGMENT_DATA, /* do SSR located in hot/warm/cold data area */ +#endif NO_CHECK_TYPE, CURSEG_COLD_DATA_PINNED,/* cold data for pinned file */ }; @@ -1077,6 +1158,9 @@ enum count_type { F2FS_RD_META, F2FS_DIO_WRITE, F2FS_DIO_READ, +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + F2FS_LOG_FILE, +#endif NR_COUNT_TYPE, }; @@ -1184,6 +1268,7 @@ struct f2fs_io_info { bool retry; /* need to reallocate block address */ int compr_blocks; /* # of compressed block addresses */ bool encrypted; /* indicate file is encrypted */ + bool post_read; /* require post read */ enum iostat_type io_type; /* io type */ struct writeback_control *io_wbc; /* writeback control */ struct bio **bio; /* bio for ipu */ @@ -1271,6 +1356,9 @@ enum { GC_NORMAL, GC_IDLE_CB, GC_IDLE_GREEDY, +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + GC_IDLE_AT, +#endif GC_URGENT, }; @@ -1324,6 +1412,20 @@ enum fsync_mode { #define DUMMY_ENCRYPTION_ENABLED(sbi) (0) #endif +#ifdef CONFIG_OPLUS_FEATURE_OF2FS +struct f2fs_hot_cold_params { + unsigned int enable; + unsigned int hot_data_lower_limit; + unsigned int hot_data_waterline; + unsigned int warm_data_lower_limit; + unsigned int warm_data_waterline; + unsigned int hot_node_lower_limit; + unsigned int hot_node_waterline; + unsigned int warm_node_lower_limit; + unsigned int warm_node_waterline; +}; +#endif + /* For compression */ enum compress_algorithm_type { COMPRESS_LZO, @@ -1556,7 +1658,10 @@ struct f2fs_sb_info { unsigned int ndirty_inode[NR_INODE_TYPE]; /* # of dirty inodes */ #endif spinlock_t stat_lock; /* lock for stat operations */ - +#ifdef CONFIG_F2FS_BD_STAT + spinlock_t bd_lock; + struct f2fs_bigdata_info *bd_info; /* big data collections */ +#endif /* For app/fs IO statistics */ spinlock_t iostat_lock; unsigned long long rw_iostat[NR_IO_TYPE]; @@ -1593,6 +1698,30 @@ struct f2fs_sb_info { __u32 s_chksum_seed; struct workqueue_struct *post_read_wq; /* post read workqueue */ +#ifdef CONFIG_F2FS_GRADING_SSR + struct f2fs_hot_cold_params hot_cold_params; +#endif +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + /* for GC_AT */ + bool atgc_enabled; + /* + * 2019/08/13, add code to optimize gc + * 2019/08/14, add need_SSR GC + */ + bool is_frag; /* urgent gc flag */ + unsigned long last_frag_check; /* last urgent check jiffies */ + atomic_t need_ssr_gc; /* ssr gc count */ + /* + * 2019/10/15, control of2fs gc code, will remove + */ + bool gc_opt_enable; + /* + * 2020-1-14, add for oDiscard decoupling + */ + bool dc_opt_enable; + int dpolicy_expect; + bool fsync_protect; +#endif struct kmem_cache *inline_xattr_slab; /* inline xattr entry */ unsigned int inline_xattr_slab_size; /* default inline xattr slab size */ @@ -3079,6 +3208,12 @@ static inline void f2fs_update_iostat(struct f2fs_sb_info *sbi, return; spin_lock(&sbi->iostat_lock); sbi->rw_iostat[type] += io_bytes; +#if defined(OPLUS_FEATURE_IOMONITOR) && defined(CONFIG_IOMONITOR) + if (type == FS_GC_DATA_IO || type == FS_GC_NODE_IO) + iomonitor_update_fs_stats(FS_GC_OPT, 1); + else if (type == FS_DISCARD) + iomonitor_update_fs_stats(FS_DISCARD_OPT, 1); +#endif /*OPLUS_FEATURE_IOMONITOR*/ if (type == APP_WRITE_IO || type == APP_DIRECT_IO) sbi->rw_iostat[APP_BUFFERED_IO] = @@ -3327,6 +3462,10 @@ bool f2fs_is_checkpointed_data(struct f2fs_sb_info *sbi, block_t blkaddr); void f2fs_drop_discard_cmd(struct f2fs_sb_info *sbi); void f2fs_stop_discard_thread(struct f2fs_sb_info *sbi); bool f2fs_issue_discard_timeout(struct f2fs_sb_info *sbi); +#ifdef CONFIG_OPLUS_FEATURE_OF2FS +void refresh_sit_entry(struct f2fs_sb_info *sbi, block_t old, block_t new, + bool from_gc); +#endif void f2fs_clear_prefree_segments(struct f2fs_sb_info *sbi, struct cp_control *cpc); void f2fs_dirty_to_prefree(struct f2fs_sb_info *sbi); @@ -3336,6 +3475,12 @@ void f2fs_release_discard_addrs(struct f2fs_sb_info *sbi); int f2fs_npages_for_summary_flush(struct f2fs_sb_info *sbi, bool for_ra); void allocate_segment_for_resize(struct f2fs_sb_info *sbi, int type, unsigned int start, unsigned int end); +#ifdef CONFIG_OPLUS_FEATURE_OF2FS +void get_new_segment(struct f2fs_sb_info *sbi, + unsigned int *newseg, bool new_sec, int dir); +void store_virtual_curseg_summary(struct f2fs_sb_info *sbi); +void restore_virtual_curseg_status(struct f2fs_sb_info * sbi, bool recover); +#endif void f2fs_allocate_new_segments(struct f2fs_sb_info *sbi, int type); int f2fs_trim_fs(struct f2fs_sb_info *sbi, struct fstrim_range *range); bool f2fs_exist_trim_candidates(struct f2fs_sb_info *sbi, @@ -3349,22 +3494,40 @@ void f2fs_do_write_node_page(unsigned int nid, struct f2fs_io_info *fio); void f2fs_outplace_write_data(struct dnode_of_data *dn, struct f2fs_io_info *fio); int f2fs_inplace_write_data(struct f2fs_io_info *fio); +#ifdef CONFIG_OPLUS_FEATURE_OF2FS +void f2fs_do_replace_block(struct f2fs_sb_info *sbi, struct f2fs_summary *sum, + block_t old_blkaddr, block_t new_blkaddr, + bool recover_curseg, bool recover_newaddr, + bool from_gc); +#else void f2fs_do_replace_block(struct f2fs_sb_info *sbi, struct f2fs_summary *sum, block_t old_blkaddr, block_t new_blkaddr, bool recover_curseg, bool recover_newaddr); +#endif void f2fs_replace_block(struct f2fs_sb_info *sbi, struct dnode_of_data *dn, block_t old_addr, block_t new_addr, unsigned char version, bool recover_curseg, bool recover_newaddr); +#ifdef CONFIG_OPLUS_FEATURE_OF2FS +void f2fs_allocate_data_block(struct f2fs_sb_info *sbi, struct page *page, + block_t old_blkaddr, block_t *new_blkaddr, + struct f2fs_summary *sum, int type, + struct f2fs_io_info *fio, bool add_list, + int contig_level); +#else void f2fs_allocate_data_block(struct f2fs_sb_info *sbi, struct page *page, block_t old_blkaddr, block_t *new_blkaddr, struct f2fs_summary *sum, int type, struct f2fs_io_info *fio, bool add_list); +#endif void f2fs_wait_on_page_writeback(struct page *page, enum page_type type, bool ordered, bool locked); void f2fs_wait_on_block_writeback(struct inode *inode, block_t blkaddr); void f2fs_wait_on_block_writeback_range(struct inode *inode, block_t blkaddr, block_t len); +#ifdef CONFIG_OPLUS_FEATURE_OF2FS +void init_virtual_curseg(struct f2fs_sb_info *sbi); +#endif void f2fs_write_data_summaries(struct f2fs_sb_info *sbi, block_t start_blk); void f2fs_write_node_summaries(struct f2fs_sb_info *sbi, block_t start_blk); int f2fs_lookup_journal_in_cursum(struct f2fs_journal *journal, int type, @@ -3493,6 +3656,10 @@ void f2fs_stop_gc_thread(struct f2fs_sb_info *sbi); block_t f2fs_start_bidx_of_node(unsigned int node_ofs, struct inode *inode); int f2fs_gc(struct f2fs_sb_info *sbi, bool sync, bool background, unsigned int segno); +#ifdef CONFIG_OPLUS_FEATURE_OF2FS +int __init create_garbage_collection_cache(void); +void destroy_garbage_collection_cache(void); +#endif void f2fs_build_gc_manager(struct f2fs_sb_info *sbi); int f2fs_resize_fs(struct f2fs_sb_info *sbi, __u64 block_count); @@ -3543,10 +3710,15 @@ struct f2fs_stat_info { int tot_blks, data_blks, node_blks; int bg_data_blks, bg_node_blks; unsigned long long skipped_atomic_files[2]; +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + int curseg[NR_INMEM_CURSEG_TYPE]; + int cursec[NR_INMEM_CURSEG_TYPE]; + int curzone[NR_INMEM_CURSEG_TYPE]; +#else int curseg[NR_CURSEG_TYPE]; int cursec[NR_CURSEG_TYPE]; int curzone[NR_CURSEG_TYPE]; - +#endif unsigned int meta_count[META_MAX]; unsigned int segment_count[2]; unsigned int block_count[2]; @@ -3732,6 +3904,12 @@ static inline void f2fs_destroy_root_stats(void) { } static inline void f2fs_update_sit_info(struct f2fs_sb_info *sbi) {} #endif +#ifdef CONFIG_F2FS_BD_STAT +#include "of2fs_bigdata.h" +void f2fs_build_bd_stat(struct f2fs_sb_info *sbi); +void f2fs_destroy_bd_stat(struct f2fs_sb_info *sbi); +#endif + extern const struct file_operations f2fs_dir_operations; extern const struct file_operations f2fs_file_operations; extern const struct inode_operations f2fs_file_inode_operations; @@ -3790,6 +3968,11 @@ void f2fs_leave_shrinker(struct f2fs_sb_info *sbi); */ struct rb_entry *f2fs_lookup_rb_tree(struct rb_root_cached *root, struct rb_entry *cached_re, unsigned int ofs); +#ifdef CONFIG_OPLUS_FEATURE_OF2FS +struct rb_node **__lookup_rb_tree_ext(struct f2fs_sb_info *sbi, + struct rb_root *root, struct rb_node **parent, + unsigned long long key); +#endif struct rb_node **f2fs_lookup_rb_tree_for_insert(struct f2fs_sb_info *sbi, struct rb_root_cached *root, struct rb_node **parent, @@ -4135,6 +4318,31 @@ static inline bool is_journalled_quota(struct f2fs_sb_info *sbi) #endif return false; } +#ifdef CONFIG_OPLUS_FEATURE_OF2FS +/* + * 2019-10-15, add for oDiscard + */ +#define F2FS_FS_FREE_PERCENT 20 +#define F2FS_DEVICE_FREE_PERCENT 10 + +/* + * 2020-1-14, add for oDiscard decoupling + */ +static inline bool f2fs_is_space_free(struct f2fs_sb_info *sbi) +{ + struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info; + block_t user_blocks = sbi->user_block_count; + block_t ovp_cnt = SM_I(sbi)->ovp_segments << sbi->log_blocks_per_seg; + block_t avail_block = user_blocks - valid_user_blocks(sbi) + ovp_cnt; + block_t fs_threshold = (block_t)(SM_I(sbi)->main_segments * + sbi->blocks_per_seg * F2FS_FS_FREE_PERCENT) / 100; + block_t device_threshold = (block_t)(SM_I(sbi)->main_segments * + sbi->blocks_per_seg * F2FS_DEVICE_FREE_PERCENT) / 100; + + return avail_block > fs_threshold && + avail_block - dcc->undiscard_blks > device_threshold; +} +#endif #define EFSBADCRC EBADMSG /* Bad CRC detected */ #define EFSCORRUPTED EUCLEAN /* Filesystem is corrupted */ diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index 23b0de78e80d..24dd5f774a1a 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -257,6 +257,11 @@ static int f2fs_do_sync_file(struct file *file, loff_t start, loff_t end, .for_reclaim = 0, }; unsigned int seq_id = 0; +#ifdef CONFIG_F2FS_BD_STAT + u64 fsync_begin = 0, fsync_end = 0, wr_file_end, cp_begin = 0, + cp_end = 0, sync_node_begin = 0, sync_node_end = 0, + flush_begin = 0, flush_end = 0; +#endif if (unlikely(f2fs_readonly(inode->i_sb))) return 0; @@ -275,11 +280,18 @@ static int f2fs_do_sync_file(struct file *file, loff_t start, loff_t end, if (S_ISDIR(inode->i_mode)) goto go_write; +#ifdef CONFIG_F2FS_BD_STAT + fsync_begin = local_clock(); +#endif + /* if fdatasync is triggered, let's do in-place-update */ if (datasync || get_dirty_pages(inode) <= SM_I(sbi)->min_fsync_blocks) set_inode_flag(inode, FI_NEED_IPU); ret = file_write_and_wait_range(file, start, end); clear_inode_flag(inode, FI_NEED_IPU); +#ifdef CONFIG_F2FS_BD_STAT + wr_file_end = local_clock(); +#endif if (ret || is_sbi_flag_set(sbi, SBI_CP_DISABLED)) { trace_f2fs_sync_file_exit(inode, cp_reason, datasync, ret); @@ -318,7 +330,13 @@ go_write: if (cp_reason) { /* all the dirty node pages should be flushed for POR */ +#ifdef CONFIG_F2FS_BD_STAT + cp_begin = local_clock(); +#endif ret = f2fs_sync_fs(inode->i_sb, 1); +#ifdef CONFIG_F2FS_BD_STAT + cp_end = local_clock(); +#endif /* * We've secured consistency through sync_fs. Following pino @@ -330,9 +348,15 @@ go_write: goto out; } sync_nodes: +#ifdef CONFIG_F2FS_BD_STAT + sync_node_begin = local_clock(); +#endif atomic_inc(&sbi->wb_sync_req[NODE]); ret = f2fs_fsync_node_pages(sbi, inode, &wbc, atomic, &seq_id); atomic_dec(&sbi->wb_sync_req[NODE]); +#ifdef CONFIG_F2FS_BD_STAT + sync_node_end = local_clock(); +#endif if (ret) goto out; @@ -366,8 +390,24 @@ sync_nodes: f2fs_remove_ino_entry(sbi, ino, APPEND_INO); clear_inode_flag(inode, FI_APPEND_WRITE); flush_out: +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + /* + * 2019/09/13, fsync nobarrier protection + */ + if (!atomic && (F2FS_OPTION(sbi).fsync_mode != FSYNC_MODE_NOBARRIER || + sbi->fsync_protect)) +#else if (!atomic && F2FS_OPTION(sbi).fsync_mode != FSYNC_MODE_NOBARRIER) +#endif + { +#ifdef CONFIG_F2FS_BD_STAT + flush_begin = local_clock(); +#endif ret = f2fs_issue_flush(sbi, inode->i_ino); +#ifdef CONFIG_F2FS_BD_STAT + flush_end = local_clock(); +#endif + } if (!ret) { f2fs_remove_ino_entry(sbi, ino, UPDATE_INO); clear_inode_flag(inode, FI_UPDATE_WRITE); @@ -379,6 +419,31 @@ out: f2fs_trace_ios(NULL, 1); trace_android_fs_fsync_end(inode, start, end - start); +#ifdef CONFIG_F2FS_BD_STAT + if (!ret && fsync_begin) { + fsync_end = local_clock(); + bd_lock(sbi); + if (S_ISREG(inode->i_mode)) + bd_inc_val(sbi, fsync_reg_file_count, 1); + else if (S_ISDIR(inode->i_mode)) + bd_inc_val(sbi, fsync_dir_count, 1); + bd_inc_val(sbi, fsync_time, fsync_end - fsync_begin); + bd_max_val(sbi, max_fsync_time, fsync_end - fsync_begin); + bd_inc_val(sbi, fsync_wr_file_time, wr_file_end - fsync_begin); + bd_max_val(sbi, max_fsync_wr_file_time, wr_file_end - fsync_begin); + bd_inc_val(sbi, fsync_cp_time, cp_end - cp_begin); + bd_max_val(sbi, max_fsync_cp_time, cp_end - cp_begin); + if (sync_node_end) { + bd_inc_val(sbi, fsync_sync_node_time, + sync_node_end - sync_node_begin); + bd_max_val(sbi, max_fsync_sync_node_time, + sync_node_end - sync_node_begin); + } + bd_inc_val(sbi, fsync_flush_time, flush_end - flush_begin); + bd_max_val(sbi, max_fsync_flush_time, flush_end - flush_begin); + bd_unlock(sbi); + } +#endif return ret; } @@ -3950,6 +4015,12 @@ static ssize_t f2fs_file_write_iter(struct kiocb *iocb, struct iov_iter *from) if (!f2fs_force_buffered_io(inode, iocb, from) && allow_outplace_dio(inode, iocb, from)) goto write; + +#ifdef CONFIG_HYBRIDSWAP_CORE + if (f2fs_overwrite_io(inode, iocb->ki_pos, + iov_iter_count(from))) + goto write; +#endif } preallocated = true; target_size = iocb->ki_pos + iov_iter_count(from); diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c index e3d8b2f3daa6..cb683c633e88 100644 --- a/fs/f2fs/gc.c +++ b/fs/f2fs/gc.c @@ -21,6 +21,168 @@ #include "gc.h" #include +#ifdef CONFIG_OPLUS_FEATURE_OF2FS +static struct kmem_cache *victim_entry_slab; +/* + * 2019/08/13, add code to optimize gc + */ +#define MIN_WAIT_MS 1000 +#define DEF_GC_BALANCE_MIN_SLEEP_TIME 10000 /* milliseconds */ +#define DEF_GC_FRAG_MIN_SLEEP_TIME 2000 /* milliseconds */ +#define GC_URGENT_CHECK_TIME (10*60*1000) /* milliseconds */ +#define GC_URGENT_DISABLE_BLOCKS (16<<18) /* 16G */ +#define GC_URGENT_DISABLE_FREE_BLOCKS (10<<18) /* 10G */ + +extern block_t of2fs_seg_freefrag(struct f2fs_sb_info *sbi, + unsigned int segno, block_t* blocks, unsigned int n); +static inline bool __is_frag_urgent(struct f2fs_sb_info *sbi) +{ + block_t total_blocks, valid_blocks; + block_t blocks[9]; + unsigned int i; + + total_blocks = le64_to_cpu(sbi->raw_super->block_count); + valid_blocks = valid_user_blocks(sbi); + + if (total_blocks < GC_URGENT_DISABLE_BLOCKS || + total_blocks - valid_blocks > GC_URGENT_DISABLE_FREE_BLOCKS) + return false; + + total_blocks = 0; + memset(blocks, 0, sizeof(blocks)); + for (i = 0; i < MAIN_SEGS(sbi); i++) { + total_blocks += of2fs_seg_freefrag(sbi, i, + blocks, ARRAY_SIZE(blocks)); + cond_resched(); + } + + f2fs_info(sbi, "Extent Size Range: Free Blocks"); + for (i = 0; i < ARRAY_SIZE(blocks); i++) { + if (!blocks[i]) + continue; + else if (i < 8) + f2fs_info(sbi, "%dK...%dK-: %u", 4<= (total_blocks >> 1); +} + +static inline bool is_frag_urgent(struct f2fs_sb_info *sbi) +{ + unsigned long next_check = sbi->last_frag_check + + msecs_to_jiffies(GC_URGENT_CHECK_TIME); + if (time_after(jiffies, next_check)) { + sbi->last_frag_check = jiffies; + sbi->is_frag = __is_frag_urgent(sbi); + } + return sbi->is_frag; +} + +/* + * GC tuning ratio [0, 100] in performance mode + */ +static inline int gc_perf_ratio(struct f2fs_sb_info *sbi) +{ + block_t reclaimable_user_blocks = sbi->user_block_count - + written_block_count(sbi); + return reclaimable_user_blocks == 0 ? 100 : + 100ULL * free_user_blocks(sbi) / reclaimable_user_blocks; +} + +/* invaild blocks is more than 10% of total free space */ +static inline bool is_invaild_blocks_enough(struct f2fs_sb_info *sbi) +{ + block_t reclaimable_user_blocks = sbi->user_block_count - + written_block_count(sbi); + + return free_user_blocks(sbi) / 90 < reclaimable_user_blocks / 100; +} + +static inline bool is_gc_frag(struct f2fs_sb_info *sbi) +{ + return is_frag_urgent(sbi) && + free_segments(sbi) < 3 * overprovision_segments(sbi) && + is_invaild_blocks_enough(sbi); +} + +static inline bool is_gc_perf(struct f2fs_sb_info *sbi) +{ + return gc_perf_ratio(sbi) < 10 && + free_segments(sbi) < 3 * overprovision_segments(sbi); +} + +/* more than 90% of main area are valid blocks */ +static inline bool is_gc_lifetime(struct f2fs_sb_info *sbi) +{ + return written_block_count(sbi) / 90 > sbi->user_block_count / 100; +} + +static inline void of2fs_tune_wait_ms(struct f2fs_sb_info *sbi, unsigned int *wait_ms) +{ + unsigned int min_wait_ms; + struct f2fs_gc_kthread *gc_th = sbi->gc_thread; + if (sbi->gc_mode == GC_URGENT) { + // do nothing in GC_URGENT mode + return ; + } else if (is_gc_frag(sbi)) { + *wait_ms = DEF_GC_FRAG_MIN_SLEEP_TIME; + } else if (is_gc_lifetime(sbi)) { + gc_th->min_sleep_time = DEF_GC_THREAD_MIN_SLEEP_TIME; + } else if (is_gc_perf(sbi)) { + *wait_ms = max(DEF_GC_THREAD_MAX_SLEEP_TIME * + gc_perf_ratio(sbi) / 100, MIN_WAIT_MS); + } else { + gc_th->min_sleep_time = DEF_GC_BALANCE_MIN_SLEEP_TIME; + } + min_wait_ms = f2fs_time_to_wait(sbi, GC_TIME); + if (*wait_ms < min_wait_ms) + *wait_ms = min_wait_ms; +} + +static inline bool of2fs_gc_wait(struct f2fs_sb_info *sbi, wait_queue_head_t *wq, unsigned int *wait_ms) +{ + struct f2fs_gc_kthread *gc_th = sbi->gc_thread; + wait_queue_head_t *fggc_wq = &gc_th->fggc_wait_queue_head; + + if (!sbi->gc_opt_enable) { + wait_event_interruptible_timeout(*wq, + kthread_should_stop() || freezing(current) || + gc_th->gc_wake, + msecs_to_jiffies(*wait_ms)); + return false; + } + + of2fs_tune_wait_ms(sbi, wait_ms); + wait_event_interruptible_timeout(*wq, + kthread_should_stop() || freezing(current) || + atomic_read(&sbi->need_ssr_gc) > 0 || + waitqueue_active(fggc_wq) || + gc_th->gc_wake, + msecs_to_jiffies(*wait_ms)); + if (atomic_read(&sbi->need_ssr_gc) > 0) { + f2fs_info(sbi, "need_SSR GC triggered!"); + down_write(&sbi->gc_lock); + f2fs_gc(sbi, true, false, NULL_SEGNO); + atomic_dec(&sbi->need_ssr_gc); + if (!has_not_enough_free_secs(sbi, 0, 0) && + waitqueue_active(fggc_wq)) { + wake_up_all(fggc_wq); + } + return true; + } else if (waitqueue_active(fggc_wq)) { + f2fs_info(sbi, "FG GC triggered!"); + down_write(&sbi->gc_lock); + f2fs_gc(sbi, false, false, NULL_SEGNO); + wake_up_all(fggc_wq); + return true; + } + + return false; +} +#endif + static int gc_thread_func(void *data) { struct f2fs_sb_info *sbi = data; @@ -33,12 +195,20 @@ static int gc_thread_func(void *data) set_freezable(); do { bool sync_mode; - +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + /* + * 2019/08/13, add code to optimize gc. + * 2019/08/14, add need_SSR GC. + * 2019/08/14, do FG GC in GC thread. + */ + if (of2fs_gc_wait(sbi, wq, &wait_ms)) + continue; +#else wait_event_interruptible_timeout(*wq, kthread_should_stop() || freezing(current) || gc_th->gc_wake, msecs_to_jiffies(wait_ms)); - +#endif /* give it a try one time */ if (gc_th->gc_wake) gc_th->gc_wake = 0; @@ -140,9 +310,24 @@ int f2fs_start_gc_thread(struct f2fs_sb_info *sbi) gc_th->no_gc_sleep_time = DEF_GC_THREAD_NOGC_SLEEP_TIME; gc_th->gc_wake= 0; +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + gc_th->root = RB_ROOT; + INIT_LIST_HEAD(&gc_th->victim_list); + gc_th->victim_count = 0; + gc_th->age_threshold = DEF_GC_THREAD_AGE_THRESHOLD; + gc_th->dirty_rate_threshold = DEF_GC_THREAD_DIRTY_RATE_THRESHOLD; + gc_th->dirty_count_threshold = DEF_GC_THREAD_DIRTY_COUNT_THRESHOLD; + gc_th->age_weight = DEF_GC_THREAD_AGE_WEIGHT; +#endif sbi->gc_thread = gc_th; init_waitqueue_head(&sbi->gc_thread->gc_wait_queue_head); +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + /* + * 2019/08/14, do FG GC in GC thread. + */ + init_waitqueue_head(&sbi->gc_thread->fggc_wait_queue_head); +#endif sbi->gc_thread->f2fs_gc_task = kthread_run(gc_thread_func, sbi, "f2fs_gc-%u:%u", MAJOR(dev), MINOR(dev)); if (IS_ERR(gc_th->f2fs_gc_task)) { @@ -166,8 +351,11 @@ void f2fs_stop_gc_thread(struct f2fs_sb_info *sbi) static int select_gc_type(struct f2fs_sb_info *sbi, int gc_type) { +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + int gc_mode = (gc_type == BG_GC) ? GC_AT : GC_GREEDY; +#else int gc_mode = (gc_type == BG_GC) ? GC_CB : GC_GREEDY; - +#endif switch (sbi->gc_mode) { case GC_IDLE_CB: gc_mode = GC_CB; @@ -176,6 +364,11 @@ static int select_gc_type(struct f2fs_sb_info *sbi, int gc_type) case GC_URGENT: gc_mode = GC_GREEDY; break; +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + case GC_IDLE_AT: + gc_mode = GC_AT; + break; +#endif } return gc_mode; } @@ -184,11 +377,23 @@ static void select_policy(struct f2fs_sb_info *sbi, int gc_type, int type, struct victim_sel_policy *p) { struct dirty_seglist_info *dirty_i = DIRTY_I(sbi); - +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + int dirty_type = type; +#endif if (p->alloc_mode == SSR) { p->gc_mode = GC_GREEDY; +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + p->dirty_segmap = dirty_i->dirty_segmap[dirty_type]; + p->max_search = dirty_i->nr_dirty[dirty_type]; + p->ofs_unit = 1; + } else if (p->alloc_mode == ASSR) { + p->gc_mode = GC_GREEDY; + p->dirty_segmap = dirty_i->dirty_segmap[dirty_type]; + p->max_search = dirty_i->nr_dirty[dirty_type]; +#else p->dirty_segmap = dirty_i->dirty_segmap[type]; p->max_search = dirty_i->nr_dirty[type]; +#endif p->ofs_unit = 1; } else { p->gc_mode = select_gc_type(sbi, gc_type); @@ -201,9 +406,17 @@ static void select_policy(struct f2fs_sb_info *sbi, int gc_type, * adjust candidates range, should select all dirty segments for * foreground GC and urgent GC cases. */ +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + if (gc_type != FG_GC && + p->gc_mode != GC_AT && + p->alloc_mode != ASSR && + (sbi->gc_mode != GC_URGENT) && + p->max_search > sbi->max_victim_search) +#else if (gc_type != FG_GC && (sbi->gc_mode != GC_URGENT) && p->max_search > sbi->max_victim_search) +#endif p->max_search = sbi->max_victim_search; /* let's select beginning hot/small space first in no_heap mode*/ @@ -220,10 +433,18 @@ static unsigned int get_max_cost(struct f2fs_sb_info *sbi, /* SSR allocates in a segment unit */ if (p->alloc_mode == SSR) return sbi->blocks_per_seg; +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + else if (p->alloc_mode == ASSR) + return UINT_MAX; +#endif if (p->gc_mode == GC_GREEDY) return 2 * sbi->blocks_per_seg * p->ofs_unit; else if (p->gc_mode == GC_CB) return UINT_MAX; +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + else if (p->gc_mode == GC_AT) + return UINT_MAX; +#endif else /* No other gc_mode */ return 0; } @@ -254,6 +475,9 @@ static unsigned int get_cb_cost(struct f2fs_sb_info *sbi, unsigned int segno) unsigned int start = GET_SEG_FROM_SEC(sbi, secno); unsigned long long mtime = 0; unsigned int vblocks; +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + unsigned int max_age; +#endif unsigned char age = 0; unsigned char u; unsigned int i; @@ -272,10 +496,18 @@ static unsigned int get_cb_cost(struct f2fs_sb_info *sbi, unsigned int segno) sit_i->min_mtime = mtime; if (mtime > sit_i->max_mtime) sit_i->max_mtime = mtime; + +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + /* Reduce the cost weight of age when free blocks less than 10% */ + max_age = is_gc_perf(sbi) ? max(10 * gc_perf_ratio(sbi), 1) : 100; + if (sit_i->max_mtime != sit_i->min_mtime) + age = max_age - div64_u64(max_age * (mtime - sit_i->min_mtime), + sit_i->max_mtime - sit_i->min_mtime); +#else if (sit_i->max_mtime != sit_i->min_mtime) age = 100 - div64_u64(100 * (mtime - sit_i->min_mtime), sit_i->max_mtime - sit_i->min_mtime); - +#endif return UINT_MAX - ((100 * (100 - u) * age) / (100 + u)); } @@ -303,7 +535,297 @@ static unsigned int count_bits(const unsigned long *addr, } return sum; } +#ifdef CONFIG_OPLUS_FEATURE_OF2FS +static struct victim_entry *attach_victim_entry(struct f2fs_sb_info *sbi, + unsigned long long mtime, unsigned int segno, + struct rb_node *parent, struct rb_node **p) +{ + struct f2fs_gc_kthread *gc_th = sbi->gc_thread; + struct victim_entry *ve; + ve = f2fs_kmem_cache_alloc(victim_entry_slab, GFP_NOFS); + + ve->mtime = mtime; + ve->segno = segno; + + rb_link_node(&ve->rb_node, parent, p); + rb_insert_color(&ve->rb_node, &gc_th->root); + + list_add_tail(&ve->list, &gc_th->victim_list); + + gc_th->victim_count++; + + return ve; +} + +static void insert_victim_entry(struct f2fs_sb_info *sbi, + unsigned long long mtime, unsigned int segno) +{ + struct f2fs_gc_kthread *gc_th = sbi->gc_thread; + struct rb_node **p; + struct rb_node *parent = NULL; + struct victim_entry *ve = NULL; + + p = __lookup_rb_tree_ext(sbi, &gc_th->root, &parent, mtime); + ve = attach_victim_entry(sbi, mtime, segno, parent, p); +} + +static void record_victim_entry(struct f2fs_sb_info *sbi, + struct victim_sel_policy *p, unsigned int segno) +{ + struct sit_info *sit_i = SIT_I(sbi); + unsigned int secno = segno / sbi->segs_per_sec; + unsigned int start = secno * sbi->segs_per_sec; + unsigned long long mtime = 0; + unsigned int i; + + for (i = 0; i < sbi->segs_per_sec; i++) + mtime += get_seg_entry(sbi, start + i)->mtime; + mtime = div_u64(mtime, sbi->segs_per_sec); + + /* Handle if the system time has changed by the user */ + if (mtime < sit_i->dirty_min_mtime) + sit_i->dirty_min_mtime = mtime; + if (mtime > sit_i->dirty_max_mtime) + sit_i->dirty_max_mtime = mtime; + if (mtime < sit_i->min_mtime) + sit_i->min_mtime = mtime; + if (mtime > sit_i->max_mtime) + sit_i->max_mtime = mtime; + /* don't choose young section as candidate */ + if (sit_i->dirty_max_mtime - mtime < p->age_threshold) + return; + + insert_victim_entry(sbi, mtime, segno); +} + +static struct rb_node *lookup_central_victim(struct f2fs_sb_info *sbi, + struct victim_sel_policy *p) +{ + struct f2fs_gc_kthread *gc_th = sbi->gc_thread; + struct rb_node *parent = NULL; + + __lookup_rb_tree_ext(sbi, &gc_th->root, &parent, p->age); + + return parent; +} + +static void lookup_victim_atgc(struct f2fs_sb_info *sbi, + struct victim_sel_policy *p) +{ + struct sit_info *sit_i = SIT_I(sbi); + struct f2fs_gc_kthread *gc_th = sbi->gc_thread; + struct rb_root *root = &gc_th->root; + struct rb_node *node; + struct rb_entry *re; + struct victim_entry *ve; + unsigned long long total_time; + unsigned long long age, u, accu; + unsigned long long max_mtime = sit_i->dirty_max_mtime; + unsigned long long min_mtime = sit_i->dirty_min_mtime; + unsigned int sec_blocks = sbi->segs_per_sec * sbi->blocks_per_seg; + unsigned int vblocks; + unsigned int dirty_threshold = max(gc_th->dirty_count_threshold, + gc_th->dirty_rate_threshold * + gc_th->victim_count / 100); + unsigned int age_weight = gc_th->age_weight; + unsigned int cost; + unsigned int iter = 0; + + if (max_mtime < min_mtime) + return; + + max_mtime += 1; + total_time = max_mtime - min_mtime; + accu = min_t(unsigned long long, + ULLONG_MAX / total_time / 100, + DEFAULT_ACCURACY_CLASS); + + node = rb_first(root); +next: + re = rb_entry_safe(node, struct rb_entry, rb_node); + if (!re) + return; + + ve = (struct victim_entry *)re; + + if (ve->mtime >= max_mtime || ve->mtime < min_mtime) + goto skip; + + /* age = 10000 * x% * 60 */ + age = div64_u64(accu * (max_mtime - ve->mtime), total_time) * + age_weight; + + vblocks = get_valid_blocks(sbi, ve->segno, true); + f2fs_bug_on(sbi, !vblocks || vblocks == sec_blocks); + + /* u = 10000 * x% * 40 */ + u = div64_u64(accu * (sec_blocks - vblocks), sec_blocks) * + (100 - age_weight); + + f2fs_bug_on(sbi, age + u >= UINT_MAX); + + cost = UINT_MAX - (age + u); + iter++; + + if (cost < p->min_cost || + (cost == p->min_cost && age > p->oldest_age)) { + p->min_cost = cost; + p->oldest_age = age; + p->min_segno = ve->segno; + } +skip: + if (iter < dirty_threshold) { + node = rb_next(node); + goto next; + } +} + +/* + * select candidates around source section in range of + * [target - dirty_threshold, target + dirty_threshold] + */ +static void lookup_victim_assr(struct f2fs_sb_info *sbi, + struct victim_sel_policy *p) +{ + struct sit_info *sit_i = SIT_I(sbi); + struct f2fs_gc_kthread *gc_th = sbi->gc_thread; + struct rb_node *node; + struct rb_entry *re; + struct victim_entry *ve; + unsigned long long total_time; + unsigned long long age; + unsigned long long max_mtime = sit_i->dirty_max_mtime; + unsigned long long min_mtime = sit_i->dirty_min_mtime; + unsigned int seg_blocks = sbi->blocks_per_seg; + unsigned int vblocks; + unsigned int dirty_threshold = max(gc_th->dirty_count_threshold, + gc_th->dirty_rate_threshold * + gc_th->victim_count / 100); + unsigned int cost; + unsigned int iter = 0; + int stage = 0; + + if (max_mtime < min_mtime) + return; + + max_mtime += 1; + total_time = max_mtime - min_mtime; +next_stage: + node = lookup_central_victim(sbi, p); +next_node: + re = rb_entry_safe(node, struct rb_entry, rb_node); + if (!re) { + if (stage == 0) + goto skip_stage; + return; + } + + ve = (struct victim_entry *)re; + + if (ve->mtime >= max_mtime || ve->mtime < min_mtime) + goto skip_node; + + age = max_mtime - ve->mtime; + + vblocks = get_seg_entry(sbi, ve->segno)->ckpt_valid_blocks; + f2fs_bug_on(sbi, !vblocks); + + /* rare case */ + if (vblocks == seg_blocks) + goto skip_node; + + iter++; + + age = max_mtime - abs(p->age - age); + cost = UINT_MAX - vblocks; + + if (cost < p->min_cost || + (cost == p->min_cost && age > p->oldest_age)) { + p->min_cost = cost; + p->oldest_age = age; + p->min_segno = ve->segno; + } +skip_node: + if (iter < dirty_threshold) { + if (stage == 0) + node = rb_prev(node); + else if (stage == 1) + node = rb_next(node); + goto next_node; + } +skip_stage: + if (stage < 1) { + stage++; + iter = 0; + goto next_stage; + } +} + +bool check_rb_tree_consistence(struct f2fs_sb_info *sbi, + struct rb_root *root) +{ +#ifdef CONFIG_F2FS_CHECK_FS + struct rb_node *cur = rb_first(root), *next; + struct rb_entry *cur_re, *next_re; + + if (!cur) + return true; + + while (cur) { + next = rb_next(cur); + if (!next) + return true; + + cur_re = rb_entry(cur, struct rb_entry, rb_node); + next_re = rb_entry(next, struct rb_entry, rb_node); + + if (cur_re->key > next_re->key) { + f2fs_err(sbi, "inconsistent rbtree, " + "cur(%llu) next(%llu)", + cur_re->key, + next_re->key); + return false; + } + + cur = next; + } +#endif + return true; +} + +static void lookup_victim_by_time(struct f2fs_sb_info *sbi, + struct victim_sel_policy *p) +{ + bool consistent = check_rb_tree_consistence(sbi, &sbi->gc_thread->root); + + WARN_ON(!consistent); + + if (p->gc_mode == GC_AT) + lookup_victim_atgc(sbi, p); + else if (p->alloc_mode == ASSR) + lookup_victim_assr(sbi, p); + else + f2fs_bug_on(sbi, 1); +} + +void release_victim_entry(struct f2fs_sb_info *sbi) +{ + struct f2fs_gc_kthread *gc_th = sbi->gc_thread; + struct victim_entry *ve, *tmp; + + list_for_each_entry_safe(ve, tmp, &gc_th->victim_list, list) { + list_del(&ve->list); + kmem_cache_free(victim_entry_slab, ve); + gc_th->victim_count--; + } + + gc_th->root = RB_ROOT; + + f2fs_bug_on(sbi, gc_th->victim_count); + f2fs_bug_on(sbi, !list_empty(&gc_th->victim_list)); +} +#endif /* * This function is called from two paths. * One is garbage collection and the other is SSR segment selection. @@ -312,8 +834,14 @@ static unsigned int count_bits(const unsigned long *addr, * When it is called from SSR segment selection, it finds a segment * which has minimum valid blocks and removes it from dirty seglist. */ +#ifdef CONFIG_OPLUS_FEATURE_OF2FS +static int get_victim_by_default(struct f2fs_sb_info *sbi, + unsigned int *result, int gc_type, int type, + char alloc_mode, unsigned long long age) +#else static int get_victim_by_default(struct f2fs_sb_info *sbi, unsigned int *result, int gc_type, int type, char alloc_mode) +#endif { struct dirty_seglist_info *dirty_i = DIRTY_I(sbi); struct sit_info *sm = SIT_I(sbi); @@ -321,19 +849,46 @@ static int get_victim_by_default(struct f2fs_sb_info *sbi, unsigned int secno, last_victim; unsigned int last_segment; unsigned int nsearched = 0; - +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + bool is_atgc = false; +#endif mutex_lock(&dirty_i->seglist_lock); last_segment = MAIN_SECS(sbi) * sbi->segs_per_sec; p.alloc_mode = alloc_mode; +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + p.age = age; + if (sbi->gc_thread) + p.age_threshold = sbi->gc_thread->age_threshold; + +retry: +#endif select_policy(sbi, gc_type, type, &p); p.min_segno = NULL_SEGNO; +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + p.oldest_age = 0; +#endif p.min_cost = get_max_cost(sbi, &p); +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + if (sbi->gc_thread) + is_atgc = (p.gc_mode == GC_AT || p.alloc_mode == ASSR); + else + is_atgc = false; + nsearched = 0; + if (is_atgc) + SIT_I(sbi)->dirty_min_mtime = ULLONG_MAX; +#endif if (*result != NULL_SEGNO) { +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + if (IS_DATASEG(get_seg_entry(sbi, *result)->type) && + get_valid_blocks(sbi, *result, false) && + !sec_usage_check(sbi, GET_SEC_FROM_SEG(sbi, *result))) +#else if (get_valid_blocks(sbi, *result, false) && !sec_usage_check(sbi, GET_SEC_FROM_SEG(sbi, *result))) +#endif p.min_segno = *result; goto out; } @@ -411,7 +966,12 @@ static int get_victim_by_default(struct f2fs_sb_info *sbi, goto next; if (gc_type == BG_GC && test_bit(secno, dirty_i->victim_secmap)) goto next; - +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + if (is_atgc) { + record_victim_entry(sbi, &p, segno); + goto next; + } +#endif cost = get_gc_cost(sbi, segno, &p); if (p.min_cost > cost) { @@ -429,6 +989,20 @@ next: break; } } +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + /* get victim for GC_AT/ASSR */ + if (is_atgc) { + lookup_victim_by_time(sbi, &p); + release_victim_entry(sbi); + } + + if (is_atgc && p.min_segno == NULL_SEGNO && + sm->dirty_max_mtime - sm->dirty_min_mtime < p.age_threshold) { + /* set temp age threshold to get some victims */ + p.age_threshold = 0; + goto retry; + } +#endif if (p.min_segno != NULL_SEGNO) { got_it: *result = (p.min_segno / p.ofs_unit) * p.ofs_unit; @@ -520,7 +1094,9 @@ static int gc_node_segment(struct f2fs_sb_info *sbi, int phase = 0; bool fggc = (gc_type == FG_GC); int submitted = 0; - +#ifdef CONFIG_F2FS_BD_STAT + int gc_blks = 0; +#endif start_addr = START_BLOCK(sbi, segno); next_step: @@ -536,9 +1112,18 @@ next_step: int err; /* stop BG_GC if there is not enough free sections. */ +#ifdef CONFIG_F2FS_BD_STAT + if (gc_type == BG_GC && has_not_enough_free_secs(sbi, 0, 0)) { + bd_lock(sbi); + bd_inc_array_val(sbi, gc_node_blocks, gc_type, gc_blks); + bd_inc_array_val(sbi, hotcold_count, HC_GC_COLD_DATA, gc_blks); + bd_unlock(sbi); + return submitted; + } +#else if (gc_type == BG_GC && has_not_enough_free_secs(sbi, 0, 0)) return submitted; - +#endif if (check_valid_map(sbi, segno, off) == 0) continue; @@ -577,6 +1162,10 @@ next_step: err = f2fs_move_node_page(node_page, gc_type); if (!err && gc_type == FG_GC) submitted++; +#ifdef CONFIG_F2FS_BD_STAT + if (!err) + gc_blks++; +#endif stat_inc_node_blk_count(sbi, 1, gc_type); } @@ -780,7 +1369,12 @@ static int move_data_block(struct inode *inode, block_t bidx, block_t newaddr; int err = 0; bool lfs_mode = f2fs_lfs_mode(fio.sbi); - +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + int type = fio.sbi && fio.sbi->atgc_enabled && gc_type == BG_GC && + (fio.sbi->gc_mode == GC_IDLE_AT || + fio.sbi->gc_mode == GC_NORMAL) ? + CURSEG_FRAGMENT_DATA : CURSEG_COLD_DATA; +#endif /* do not read out */ page = f2fs_grab_cache_page(inode->i_mapping, bidx, false); if (!page) @@ -862,10 +1456,13 @@ static int move_data_block(struct inode *inode, block_t bidx, goto up_out; } } - +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + f2fs_allocate_data_block(fio.sbi, NULL, fio.old_blkaddr, &newaddr, + &sum, type, NULL, false, SEQ_NONE); +#else f2fs_allocate_data_block(fio.sbi, NULL, fio.old_blkaddr, &newaddr, &sum, CURSEG_COLD_DATA, NULL, false); - +#endif fio.encrypted_page = f2fs_pagecache_get_page(META_MAPPING(fio.sbi), newaddr, FGP_LOCK | FGP_CREAT, GFP_NOFS); if (!fio.encrypted_page) { @@ -913,8 +1510,13 @@ put_page_out: f2fs_put_page(fio.encrypted_page, 1); recover_block: if (err) +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + f2fs_do_replace_block(fio.sbi, &sum, newaddr, fio.old_blkaddr, + true, true, true); +#else f2fs_do_replace_block(fio.sbi, &sum, newaddr, fio.old_blkaddr, true, true); +#endif up_out: if (lfs_mode) up_write(&fio.sbi->io_order_lock); @@ -1020,7 +1622,9 @@ static int gc_data_segment(struct f2fs_sb_info *sbi, struct f2fs_summary *sum, int off; int phase = 0; int submitted = 0; - +#ifdef CONFIG_F2FS_BD_STAT + int gc_blks = 0; +#endif start_addr = START_BLOCK(sbi, segno); next_step: @@ -1152,7 +1756,10 @@ next_step: up_write(&fi->i_gc_rwsem[WRITE]); up_write(&fi->i_gc_rwsem[READ]); } - +#ifdef CONFIG_F2FS_BD_STAT + if (!err) + gc_blks++; +#endif stat_inc_data_blk_count(sbi, 1, gc_type); } } @@ -1160,6 +1767,13 @@ next_step: if (++phase < 5) goto next_step; +#ifdef CONFIG_F2FS_BD_STAT + bd_lock(sbi); + bd_inc_array_val(sbi, gc_data_blocks, gc_type, gc_blks); + bd_inc_array_val(sbi, hotcold_count, HC_GC_COLD_DATA, gc_blks); + bd_unlock(sbi); +#endif + return submitted; } @@ -1170,8 +1784,13 @@ static int __get_victim(struct f2fs_sb_info *sbi, unsigned int *victim, int ret; down_write(&sit_i->sentry_lock); +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + ret = DIRTY_I(sbi)->v_ops->get_victim(sbi, victim, gc_type, + NO_CHECK_TYPE, LFS, 0); +#else ret = DIRTY_I(sbi)->v_ops->get_victim(sbi, victim, gc_type, NO_CHECK_TYPE, LFS); +#endif up_write(&sit_i->sentry_lock); return ret; } @@ -1189,7 +1808,9 @@ static int do_garbage_collect(struct f2fs_sb_info *sbi, unsigned char type = IS_DATASEG(get_seg_entry(sbi, segno)->type) ? SUM_TYPE_DATA : SUM_TYPE_NODE; int submitted = 0; - +#ifdef CONFIG_F2FS_BD_STAT + int hc_type = get_seg_entry(sbi, segno)->type; +#endif if (__is_large_section(sbi)) end_segno = rounddown(end_segno, sbi->segs_per_sec); @@ -1263,7 +1884,19 @@ freed: if (gc_type == FG_GC && get_valid_blocks(sbi, segno, false) == 0) seg_freed++; - +#ifdef CONFIG_F2FS_BD_STAT + bd_lock(sbi); + if (gc_type == BG_GC || get_valid_blocks(sbi, segno, 1) == 0) { + if (type == SUM_TYPE_NODE) + bd_inc_array_val(sbi, gc_node_segments, gc_type, 1); + else + bd_inc_array_val(sbi, gc_data_segments, gc_type, 1); + bd_inc_array_val(sbi, hotcold_gc_segments, hc_type + 1, 1); + } + bd_inc_array_val(sbi, hotcold_gc_blocks, hc_type + 1, + (unsigned long)get_valid_blocks(sbi, segno, 1)); + bd_unlock(sbi); +#endif if (__is_large_section(sbi) && segno + 1 < end_segno) sbi->next_victim_seg[gc_type] = segno + 1; skip: @@ -1296,7 +1929,11 @@ int f2fs_gc(struct f2fs_sb_info *sbi, bool sync, unsigned long long last_skipped = sbi->skipped_atomic_files[FG_GC]; unsigned long long first_skipped; unsigned int skipped_round = 0, round = 0; - +#ifdef CONFIG_F2FS_BD_STAT + bool gc_completed = false; + u64 fggc_begin, fggc_end; + fggc_begin = local_clock(); +#endif trace_f2fs_gc_begin(sbi->sb, sync, background, get_pages(sbi, F2FS_DIRTY_NODES), get_pages(sbi, F2FS_DIRTY_DENTS), @@ -1349,7 +1986,9 @@ gc_more: if (gc_type == FG_GC && seg_freed == sbi->segs_per_sec) sec_freed++; total_freed += seg_freed; - +#ifdef CONFIG_F2FS_BD_STAT + gc_completed = true; +#endif if (gc_type == FG_GC) { if (sbi->skipped_atomic_files[FG_GC] > last_skipped || sbi->skipped_gc_rwsem) @@ -1395,7 +2034,18 @@ stop: prefree_segments(sbi)); up_write(&sbi->gc_lock); - +#ifdef CONFIG_F2FS_BD_STAT + if (gc_completed) { + fggc_end = gc_type == FG_GC ? local_clock() : 0; + bd_lock(sbi); + if (fggc_end) + bd_inc_val(sbi, fggc_time, fggc_end - fggc_begin); + bd_inc_array_val(sbi, gc_count, gc_type, 1); + if (ret) + bd_inc_array_val(sbi, gc_fail_count, gc_type, 1); + bd_unlock(sbi); + } +#endif put_gc_inode(&gc_list); if (sync && !ret) @@ -1403,12 +2053,35 @@ stop: return ret; } +#ifdef CONFIG_OPLUS_FEATURE_OF2FS +int __init create_garbage_collection_cache(void) +{ + victim_entry_slab = f2fs_kmem_cache_create("victim_entry", + sizeof(struct victim_entry)); + if (!victim_entry_slab) + return -ENOMEM; + return 0; +} + +void destroy_garbage_collection_cache(void) +{ + kmem_cache_destroy(victim_entry_slab); +} +#endif + void f2fs_build_gc_manager(struct f2fs_sb_info *sbi) { DIRTY_I(sbi)->v_ops = &default_v_ops; sbi->gc_pin_file_threshold = DEF_GC_FAILED_PINNED_FILES; +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + /* + * 2019/08/14, add need_SSR GC. + */ + atomic_set(&sbi->need_ssr_gc, 0); + sbi->gc_opt_enable = true; +#endif /* give warm/cold data area from slower device */ if (f2fs_is_multi_device(sbi) && !__is_large_section(sbi)) SIT_I(sbi)->last_victim[ALLOC_NEXT] = diff --git a/fs/f2fs/gc.h b/fs/f2fs/gc.h index db3c61046aa4..7c96241b9015 100644 --- a/fs/f2fs/gc.h +++ b/fs/f2fs/gc.h @@ -14,6 +14,16 @@ #define DEF_GC_THREAD_MIN_SLEEP_TIME 30000 /* milliseconds */ #define DEF_GC_THREAD_MAX_SLEEP_TIME 60000 #define DEF_GC_THREAD_NOGC_SLEEP_TIME 300000 /* wait 5 min */ + +#ifdef CONFIG_OPLUS_FEATURE_OF2FS +/* choose candidates from sections which has age of more than 1 day */ +#define DEF_GC_THREAD_AGE_THRESHOLD (60 * 60 * 24 * 1) +#define DEF_GC_THREAD_DIRTY_RATE_THRESHOLD 20 /* select 20% oldest dirty section */ +#define DEF_GC_THREAD_DIRTY_COUNT_THRESHOLD 10 /* select at least 10 dirty section */ +#define DEF_GC_THREAD_AGE_WEIGHT 60 /* age weight */ +#define DEFAULT_ACCURACY_CLASS 10000 +#endif + #define LIMIT_INVALID_BLOCK 40 /* percentage over total user space */ #define LIMIT_FREE_BLOCK 40 /* percentage over invalid + free space */ @@ -25,7 +35,12 @@ struct f2fs_gc_kthread { struct task_struct *f2fs_gc_task; wait_queue_head_t gc_wait_queue_head; - +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + /* + * 2019/08/14, do FG GC in GC thread + */ + wait_queue_head_t fggc_wait_queue_head; +#endif /* for gc sleep time */ unsigned int urgent_sleep_time; unsigned int min_sleep_time; @@ -34,6 +49,16 @@ struct f2fs_gc_kthread { /* for changing gc mode */ unsigned int gc_wake; +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + /* for GC_AT */ + struct rb_root root; /* root of victim rb-tree */ + struct list_head victim_list; /* linked with all victim entries */ + unsigned int victim_count; /* victim count in rb-tree */ + unsigned int dirty_count_threshold; + unsigned int dirty_rate_threshold; + unsigned long long age_threshold; + unsigned int age_weight; +#endif }; struct gc_inode_list { @@ -41,6 +66,26 @@ struct gc_inode_list { struct radix_tree_root iroot; }; +#ifdef CONFIG_OPLUS_FEATURE_OF2FS +struct victim_info { + unsigned long long mtime; /* mtime of section */ + unsigned int segno; /* section No. */ +}; + +struct victim_entry { + struct rb_node rb_node; /* rb node located in rb-tree */ + union { + struct { + unsigned long long mtime; /* mtime of section */ + unsigned int segno; /* segment No. */ + }; + struct victim_info vi; /* victim info */ + }; + struct list_head list; + //unsigned int vblocks; +}; +#endif + /* * inline functions */ diff --git a/fs/f2fs/namei.c b/fs/f2fs/namei.c index 61965b813ecf..83d6b989a3c8 100644 --- a/fs/f2fs/namei.c +++ b/fs/f2fs/namei.c @@ -270,6 +270,13 @@ int f2fs_update_extension_list(struct f2fs_sb_info *sbi, const char *name, return 0; } +#ifdef CONFIG_OPLUS_FEATURE_OF2FS +static bool is_log_file(const char *filename) +{ + return is_extension_exist(filename, "log"); +} +#endif + static void set_compress_inode(struct f2fs_sb_info *sbi, struct inode *inode, const unsigned char *name) { @@ -333,6 +340,10 @@ static int f2fs_create(struct inode *dir, struct dentry *dentry, umode_t mode, if (!test_opt(sbi, DISABLE_EXT_IDENTIFY)) set_file_temperature(sbi, inode, dentry->d_name.name); +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + if (is_log_file(dentry->d_name.name)) + set_inode_flag(inode, FI_LOG_FILE); +#endif set_compress_inode(sbi, inode, dentry->d_name.name); inode->i_op = &f2fs_file_inode_operations; @@ -483,7 +494,9 @@ static struct dentry *f2fs_lookup(struct inode *dir, struct dentry *dentry, int err = 0; unsigned int root_ino = F2FS_ROOT_INO(F2FS_I_SB(dir)); struct f2fs_filename fname; - +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + struct f2fs_sb_info *sbi = F2FS_I_SB(dir); +#endif trace_f2fs_lookup_start(dir, dentry, flags); if (dentry->d_name.len > F2FS_NAME_LEN) { @@ -537,6 +550,13 @@ static struct dentry *f2fs_lookup(struct inode *dir, struct dentry *dentry, err = -EPERM; goto out_iput; } + +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + if (is_log_file(dentry->d_name.name)) + set_inode_flag(inode, FI_LOG_FILE); + if (!test_opt(sbi, DISABLE_EXT_IDENTIFY) && !file_is_cold(inode)) + set_file_temperature(sbi, inode, dentry->d_name.name); +#endif out_splice: #ifdef CONFIG_UNICODE if (!inode && IS_CASEFOLDED(dir)) { diff --git a/fs/f2fs/node.c b/fs/f2fs/node.c index 709ea4ae95de..73a44997c770 100644 --- a/fs/f2fs/node.c +++ b/fs/f2fs/node.c @@ -1404,6 +1404,9 @@ page_hit: nid, nid_of_node(page), ino_of_node(page), ofs_of_node(page), cpver_of_node(page), next_blkaddr_of_node(page)); +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + set_sbi_flag(sbi, SBI_NEED_FSCK); +#endif err = -EINVAL; out_err: ClearPageUptodate(page); diff --git a/fs/f2fs/of2fs_bigdata.h b/fs/f2fs/of2fs_bigdata.h new file mode 100644 index 000000000000..b51ae885ed3c --- /dev/null +++ b/fs/f2fs/of2fs_bigdata.h @@ -0,0 +1,117 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2018-2020 Oplus. All rights reserved. + */ + +#ifndef _OF2FS_BIGDATA_H +#define _OF2FS_BIGDATA_H +/* unit for time: ns */ +enum { + HC_UNSET, + HC_HOT_DATA, + HC_WARM_DATA, + HC_COLD_DATA, + HC_HOT_NODE, + HC_WARM_NODE, + HC_COLD_NODE, + NR_CURSEG, + HC_META = NR_CURSEG, + HC_META_SB, + HC_META_CP, + HC_META_SIT, + HC_META_NAT, + HC_META_SSA, + HC_DIRECT_IO, + HC_GC_COLD_DATA, + HC_REWRITE_HOT_DATA, + HC_REWRITE_WARM_DATA, + NR_HOTCOLD_TYPE, +}; + +struct f2fs_bigdata_info { + /* CP info + * avg_cp_time = cp_time / cp_count + */ + unsigned int cp_count, cp_success_count; + u64 cp_time, max_cp_time, max_cp_submit_time, + max_cp_flush_meta_time, max_cp_discard_time; + + + /* Discard info + * avg_discard_time = discard_time / discard_count + */ + unsigned int discard_count, discard_blocks, + undiscard_count, undiscard_blocks; + u64 discard_time, max_discard_time; + + /* GC info: BG_GC = 0, FG_GC = 1 + * avg_[bg|fg]gc_data_segments = [bg|fg]gc_data_segments / [bg|fg]gc_data_count + * avg_[bg|fg]gc_data_blocks = [bg|fg]gc_data_blocks / [bg|fg]gc_data_count + * avg_fggc_time = fggc_time / fggc_count + * + */ + unsigned int gc_count[2], gc_fail_count[2], + gc_data_count[2], gc_node_count[2]; + unsigned int gc_data_segments[2], gc_data_blocks[2], + gc_node_segments[2], gc_node_blocks[2]; + u64 fggc_time; + + + /* Node alloc info: LFS = 0, SSR = 1 */ + unsigned int node_alloc_count[2], data_alloc_count[2], data_ipu_count; + + unsigned long last_node_alloc_count, last_data_alloc_count; + unsigned long curr_node_alloc_count, curr_data_alloc_count; + unsigned long ssr_last_jiffies; + + /* Fsync info */ + unsigned int fsync_reg_file_count, fsync_dir_count; + u64 fsync_time, max_fsync_time, fsync_cp_time, max_fsync_cp_time, + fsync_wr_file_time, max_fsync_wr_file_time, fsync_sync_node_time, + max_fsync_sync_node_time, fsync_flush_time, max_fsync_flush_time; + + /* Hot cold info */ + unsigned long hotcold_count[NR_HOTCOLD_TYPE]; + unsigned long hotcold_gc_segments[NR_CURSEG]; + unsigned long hotcold_gc_blocks[NR_CURSEG]; +}; + +static inline struct f2fs_bigdata_info *F2FS_BD_STAT(struct f2fs_sb_info *sbi) +{ + return (struct f2fs_bigdata_info *)sbi->bd_info; +} + +#define bd_inc_val(sbi, member, val) do { \ + struct f2fs_bigdata_info *bd = F2FS_BD_STAT(sbi); \ + if (bd) \ + bd->member += (val); \ +} while (0) +#define bd_inc_array_val(sbi, member, idx, val) do { \ + struct f2fs_bigdata_info *bd = F2FS_BD_STAT(sbi); \ + if (bd) \ + bd->member[(idx)] += (val); \ +} while (0) + +#define bd_set_val(sbi, member, val) do { \ + struct f2fs_bigdata_info *bd = F2FS_BD_STAT(sbi); \ + if (bd) \ + bd->member = (val); \ +} while (0) +#define bd_set_array_val(sbi, member, idx, val) do { \ + struct f2fs_bigdata_info *bd = F2FS_BD_STAT(sbi); \ + if (bd) \ + bd->member[(idx)] = (val); \ +} while (0) + +#define bd_max_val(sbi, member, val) do { \ + struct f2fs_bigdata_info *bd = F2FS_BD_STAT(sbi); \ + if (bd) { \ + if (bd->member < (val)) \ + bd->member = (val); \ + } \ +} while (0) + +#define bd_lock_init(sbi) spin_lock_init(&(sbi)->bd_lock) +#define bd_lock(sbi) spin_lock(&(sbi)->bd_lock) +#define bd_unlock(sbi) spin_unlock(&(sbi)->bd_lock) +#endif diff --git a/fs/f2fs/of2fs_sysfs.c b/fs/f2fs/of2fs_sysfs.c new file mode 100644 index 000000000000..c9e6653e64fa --- /dev/null +++ b/fs/f2fs/of2fs_sysfs.c @@ -0,0 +1,404 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2018-2020 Oplus. All rights reserved. + */ + +#include +#include +#include + +#include "f2fs.h" +#include "segment.h" +#include "gc.h" + +#include "of2fs_bigdata.h" + +/* f2fs big-data statistics */ +#define OF2FS_PROC_DEF(_name) \ +static int of2fs_##_name##_open(struct inode *inode, struct file *file) \ +{ \ + return single_open(file, of2fs_##_name##_show, PDE_DATA(inode)); \ +} \ + \ +static const struct file_operations of2fs_##_name##_fops = { \ + .owner = THIS_MODULE, \ + .open = of2fs_##_name##_open, \ + .read = seq_read, \ + .write = of2fs_##_name##_write, \ + .llseek = seq_lseek, \ + .release = single_release, \ +}; + +static int of2fs_base_info_show(struct seq_file *seq, void *p) +{ + struct super_block *sb = seq->private; + struct f2fs_sb_info *sbi = F2FS_SB(sb); + + /* + * each column indicates: block_count fs_block_count + * free_segment_count reserved_segment_count + * valid_user_blocks + */ + seq_printf(seq, "%llu %llu %u %u %u\n", + le64_to_cpu(sbi->raw_super->block_count), + le64_to_cpu(sbi->raw_super->block_count) - le32_to_cpu(sbi->raw_super->main_blkaddr), + free_segments(sbi), reserved_segments(sbi), + valid_user_blocks(sbi)); + return 0; +} + +static ssize_t of2fs_base_info_write(struct file *file, + const char __user *buf, + size_t length, loff_t *ppos) +{ + return length; +} + +static int of2fs_discard_info_show(struct seq_file *seq, void *p) +{ + struct super_block *sb = seq->private; + struct f2fs_sb_info *sbi = F2FS_SB(sb); + struct f2fs_bigdata_info *bd = F2FS_BD_STAT(sbi); + + /* + * each colum indicates: discard_count discard_blocks undiscard_count + * undiscard_blocks discard_time max_discard_time + */ + bd_lock(sbi); + if (SM_I(sbi)->dcc_info) { + bd->undiscard_count = atomic_read(&SM_I(sbi)->dcc_info->discard_cmd_cnt); + bd->undiscard_blocks = SM_I(sbi)->dcc_info->undiscard_blks; + } + seq_printf(seq, "%u %u %u %u %llu %llu\n", bd->discard_count, + bd->discard_blocks, bd->undiscard_count, + bd->undiscard_blocks, bd->discard_time, + bd->max_discard_time); + bd_unlock(sbi); + return 0; +} + +static ssize_t of2fs_discard_info_write(struct file *file, + const char __user *buf, + size_t length, loff_t *ppos) +{ + struct seq_file *seq = file->private_data; + struct super_block *sb = seq->private; + struct f2fs_sb_info *sbi = F2FS_SB(sb); + struct f2fs_bigdata_info *bd = F2FS_BD_STAT(sbi); + char buffer[3] = {0}; + + if (!buf || length > 2 || length <= 0) + return -EINVAL; + + if (copy_from_user(&buffer, buf, length)) + return -EFAULT; + + if (buffer[0] != '0') + return -EINVAL; + + bd_lock(sbi); + bd->discard_count = 0; + bd->discard_blocks = 0; + bd->undiscard_count = 0; + bd->undiscard_blocks = 0; + bd->discard_time = 0; + bd->max_discard_time = 0; + bd_unlock(sbi); + + return length; +} + +static int of2fs_cp_info_show(struct seq_file *seq, void *p) +{ + struct super_block *sb = seq->private; + struct f2fs_sb_info *sbi = F2FS_SB(sb); + struct f2fs_bigdata_info *bd = F2FS_BD_STAT(sbi); + + /* + * each column indicates: cp_count cp_success_count cp_time max_cp_time + * max_cp_submit_time max_cp_flush_meta_time max_cp_discard_time + */ + bd_lock(sbi); +#ifdef CONFIG_F2FS_STAT_FS + bd->cp_count = sbi->stat_info->cp_count; +#else + bd->cp_count = 0; +#endif + seq_printf(seq, "%u %u %llu %llu %llu %llu %llu\n", bd->cp_count, + bd->cp_success_count, bd->cp_time, bd->max_cp_time, + bd->max_cp_submit_time, bd->max_cp_flush_meta_time, + bd->max_cp_discard_time); + bd_unlock(sbi); + return 0; +} + +static ssize_t of2fs_cp_info_write(struct file *file, + const char __user *buf, + size_t length, loff_t *ppos) +{ + struct seq_file *seq = file->private_data; + struct super_block *sb = seq->private; + struct f2fs_sb_info *sbi = F2FS_SB(sb); + struct f2fs_bigdata_info *bd = F2FS_BD_STAT(sbi); + char buffer[3] = {0}; + + if (!buf || length > 2 || length <= 0) + return -EINVAL; + + if (copy_from_user(&buffer, buf, length)) + return -EFAULT; + + if (buffer[0] != '0') + return -EINVAL; + + bd_lock(sbi); + bd->cp_count = 0; + bd->cp_success_count = 0; + bd->cp_time = 0; + bd->max_cp_time = 0; + bd->max_cp_submit_time = 0; + bd->max_cp_flush_meta_time = 0; + bd->max_cp_discard_time = 0; + bd_unlock(sbi); + + return length; +} + +static int of2fs_gc_info_show(struct seq_file *seq, void *p) +{ + struct super_block *sb = seq->private; + struct f2fs_sb_info *sbi = F2FS_SB(sb); + struct f2fs_bigdata_info *bd = F2FS_BD_STAT(sbi); + + /* + * each column indicates: bggc_cnt bggc_fail_cnt fggc_cnt fggc_fail_cnt + * bggc_data_seg_cnt bggc_data_blk_cnt bggc_node_seg_cnt bggc_node_blk_cnt + * fggc_data_seg_cnt fggc_data_blk_cnt fggc_node_seg_cnt fggc_node_blk_cnt + * node_ssr_cnt data_ssr_cnt node_lfs_cnt data_lfs_cnt data_ipu_cnt + * fggc_time + */ + bd_lock(sbi); + seq_printf(seq, "%u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %llu\n", + bd->gc_count[BG_GC], bd->gc_fail_count[BG_GC], + bd->gc_count[FG_GC], bd->gc_fail_count[FG_GC], + bd->gc_data_segments[BG_GC], bd->gc_data_blocks[BG_GC], + bd->gc_node_segments[BG_GC], bd->gc_node_blocks[BG_GC], + bd->gc_data_segments[FG_GC], bd->gc_data_blocks[FG_GC], + bd->gc_node_segments[FG_GC], bd->gc_node_blocks[FG_GC], + bd->data_alloc_count[SSR], bd->node_alloc_count[SSR], + bd->data_alloc_count[LFS], bd->node_alloc_count[LFS], + bd->data_ipu_count, bd->fggc_time); + bd_unlock(sbi); + return 0; +} + +static ssize_t of2fs_gc_info_write(struct file *file, + const char __user *buf, + size_t length, loff_t *ppos) +{ + struct seq_file *seq = file->private_data; + struct super_block *sb = seq->private; + struct f2fs_sb_info *sbi = F2FS_SB(sb); + struct f2fs_bigdata_info *bd = F2FS_BD_STAT(sbi); + int i; + char buffer[3] = {0}; + + if (!buf || length > 2 || length <= 0) + return -EINVAL; + + if (copy_from_user(&buffer, buf, length)) + return -EFAULT; + + if (buffer[0] != '0') + return -EINVAL; + + bd_lock(sbi); + for (i = BG_GC; i <= FG_GC; i++) { + bd->gc_count[i] = 0; + bd->gc_fail_count[i] = 0; + bd->gc_data_count[i] = 0; + bd->gc_node_count[i] = 0; + bd->gc_data_segments[i] = 0; + bd->gc_data_blocks[i] = 0; + bd->gc_node_segments[i] = 0; + bd->gc_node_blocks[i] = 0; + } + bd->fggc_time = 0; + for (i = LFS; i <= SSR; i++) { + bd->node_alloc_count[i] = 0; + bd->data_alloc_count[i] = 0; + } + bd->data_ipu_count = 0; + bd_unlock(sbi); + + return length; +} + +static int of2fs_fsync_info_show(struct seq_file *seq, void *p) +{ + struct super_block *sb = seq->private; + struct f2fs_sb_info *sbi = F2FS_SB(sb); + struct f2fs_bigdata_info *bd = F2FS_BD_STAT(sbi); + + /* + * eacho column indicates: fsync_reg_file_cnt fsync_dir_cnt fsync_time + * max_fsync_time fsync_wr_file_time max_fsync_wr_file_time + * fsync_cp_time max_fsync_cp_time fsync_sync_node_time + * max_fsync_sync_node_time fsync_flush_time max_fsync_flush_time + */ + bd_lock(sbi); + seq_printf(seq, "%u %u %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu\n", + bd->fsync_reg_file_count, bd->fsync_dir_count, bd->fsync_time, + bd->max_fsync_time, bd->fsync_wr_file_time, + bd->max_fsync_wr_file_time, bd->fsync_cp_time, + bd->max_fsync_cp_time, bd->fsync_sync_node_time, + bd->max_fsync_sync_node_time, bd->fsync_flush_time, + bd->max_fsync_flush_time); + bd_unlock(sbi); + return 0; +} + +static ssize_t of2fs_fsync_info_write(struct file *file, + const char __user *buf, + size_t length, loff_t *ppos) +{ + struct seq_file *seq = file->private_data; + struct super_block *sb = seq->private; + struct f2fs_sb_info *sbi = F2FS_SB(sb); + struct f2fs_bigdata_info *bd = F2FS_BD_STAT(sbi); + char buffer[3] = {0}; + + if (!buf || length > 2 || length <= 0) + return -EINVAL; + + if (copy_from_user(&buffer, buf, length)) + return -EFAULT; + + if (buffer[0] != '0') + return -EINVAL; + + bd_lock(sbi); + bd->fsync_reg_file_count = 0; + bd->fsync_dir_count = 0; + bd->fsync_time = 0; + bd->max_fsync_time = 0; + bd->fsync_cp_time = 0; + bd->max_fsync_cp_time = 0; + bd->fsync_wr_file_time = 0; + bd->max_fsync_wr_file_time = 0; + bd->fsync_sync_node_time = 0; + bd->max_fsync_sync_node_time = 0; + bd->fsync_flush_time = 0; + bd->max_fsync_flush_time = 0; + bd_unlock(sbi); + + return length; +} + +static int of2fs_hotcold_info_show(struct seq_file *seq, void *p) +{ + struct super_block *sb = seq->private; + struct f2fs_sb_info *sbi = F2FS_SB(sb); + struct f2fs_bigdata_info *bd = F2FS_BD_STAT(sbi); + + bd_lock(sbi); + /* + * each colum indicates: hot_data_cnt, warm_data_cnt, cold_data_cnt, hot_node_cnt, + * warm_node_cnt, cold_node_cnt, meta_cp_cnt, meta_sit_cnt, meta_nat_cnt, meta_ssa_cnt, + * directio_cnt, gc_cold_data_cnt, rewrite_hot_data_cnt, rewrite_warm_data_cnt, + * gc_segment_hot_data_cnt, gc_segment_warm_data_cnt, gc_segment_cold_data_cnt, + * gc_segment_hot_node_cnt, gc_segment_warm_node_cnt, gc_segment_cold_node_cnt, + * gc_block_hot_data_cnt, gc_block_warm_data_cnt, gc_block_cold_data_cnt, + * gc_block_hot_node_cnt, gc_block_warm_node_cnt, gc_block_cold_node_cnt + */ + seq_printf(seq, "%lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu " + "%lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu\n", + bd->hotcold_count[HC_HOT_DATA], bd->hotcold_count[HC_WARM_DATA], + bd->hotcold_count[HC_COLD_DATA], bd->hotcold_count[HC_HOT_NODE], + bd->hotcold_count[HC_WARM_NODE], bd->hotcold_count[HC_COLD_NODE], + bd->hotcold_count[HC_META], bd->hotcold_count[HC_META_SB], + bd->hotcold_count[HC_META_CP], bd->hotcold_count[HC_META_SIT], + bd->hotcold_count[HC_META_NAT], bd->hotcold_count[HC_META_SSA], + bd->hotcold_count[HC_DIRECT_IO], bd->hotcold_count[HC_GC_COLD_DATA], + bd->hotcold_count[HC_REWRITE_HOT_DATA], + bd->hotcold_count[HC_REWRITE_WARM_DATA], + bd->hotcold_gc_segments[HC_HOT_DATA], + bd->hotcold_gc_segments[HC_WARM_DATA], + bd->hotcold_gc_segments[HC_COLD_DATA], + bd->hotcold_gc_segments[HC_HOT_NODE], + bd->hotcold_gc_segments[HC_WARM_NODE], + bd->hotcold_gc_segments[HC_COLD_NODE], + bd->hotcold_gc_blocks[HC_HOT_DATA], + bd->hotcold_gc_blocks[HC_WARM_DATA], + bd->hotcold_gc_blocks[HC_COLD_DATA], + bd->hotcold_gc_blocks[HC_HOT_NODE], + bd->hotcold_gc_blocks[HC_WARM_NODE], + bd->hotcold_gc_blocks[HC_COLD_NODE]); + bd_unlock(sbi); + return 0; +} + +static ssize_t of2fs_hotcold_info_write(struct file *file, + const char __user *buf, + size_t length, loff_t *ppos) +{ + struct seq_file *seq = file->private_data; + struct super_block *sb = seq->private; + struct f2fs_sb_info *sbi = F2FS_SB(sb); + struct f2fs_bigdata_info *bd = F2FS_BD_STAT(sbi); + char buffer[3] = {0}; + int i; + + if (!buf || length > 2 || length <= 0) + return -EINVAL; + + if (copy_from_user(&buffer, buf, length)) + return -EFAULT; + + if (buffer[0] != '0') + return -EINVAL; + + bd_lock(sbi); + for (i = 0; i < NR_HOTCOLD_TYPE; i++) + bd->hotcold_count[i] = 0; + for (i = 0; i < NR_CURSEG; i++) { + bd->hotcold_gc_segments[i] = 0; + bd->hotcold_gc_blocks[i] = 0; + } + bd_unlock(sbi); + + return length; +} + +OF2FS_PROC_DEF(base_info); +OF2FS_PROC_DEF(discard_info); +OF2FS_PROC_DEF(gc_info); +OF2FS_PROC_DEF(cp_info); +OF2FS_PROC_DEF(fsync_info); +OF2FS_PROC_DEF(hotcold_info); + +void f2fs_build_bd_stat(struct f2fs_sb_info *sbi) +{ + struct super_block *sb = sbi->sb; + + proc_create_data("base_info", S_IRUGO | S_IWUGO, sbi->s_proc, + &of2fs_base_info_fops, sb); + proc_create_data("discard_info", S_IRUGO | S_IWUGO, sbi->s_proc, + &of2fs_discard_info_fops, sb); + proc_create_data("cp_info", S_IRUGO | S_IWUGO, sbi->s_proc, + &of2fs_cp_info_fops, sb); + proc_create_data("gc_info", S_IRUGO | S_IWUGO, sbi->s_proc, + &of2fs_gc_info_fops, sb); + proc_create_data("fsync_info", S_IRUGO | S_IWUGO, sbi->s_proc, + &of2fs_fsync_info_fops, sb); + proc_create_data("hotcold_info", S_IRUGO | S_IWUGO, sbi->s_proc, + &of2fs_hotcold_info_fops, sb); +} + +void f2fs_destroy_bd_stat(struct f2fs_sb_info *sbi) +{ + if (sbi->bd_info) { + kfree(sbi->bd_info); + sbi->bd_info = NULL; + } +} diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index 9ceb43207072..8bc2f869852a 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -23,6 +23,13 @@ #include "trace.h" #include +#ifdef CONFIG_OPLUS_FEATURE_OF2FS +/* + * 2019/08/16, trigger need_SSR GC base on bigdata stats + */ +#include +#endif + #define __reverse_ffz(x) __reverse_ffs(~(x)) static struct kmem_cache *discard_entry_slab; @@ -182,7 +189,91 @@ bool f2fs_need_SSR(struct f2fs_sb_info *sbi) return free_sections(sbi) <= (node_secs + 2 * dent_secs + imeta_secs + SM_I(sbi)->min_ssr_sections + reserved_sections(sbi)); } +#ifdef CONFIG_F2FS_GRADING_SSR +static inline bool need_SSR_by_type(struct f2fs_sb_info *sbi , int type, int contig_level) +{ + int node_secs = get_blocktype_secs(sbi, F2FS_DIRTY_NODES); + int dent_secs = get_blocktype_secs(sbi, F2FS_DIRTY_DENTS); + int imeta_secs = get_blocktype_secs(sbi, F2FS_DIRTY_IMETA); + u64 valid_blocks = sbi->total_valid_block_count; + u64 total_blocks = MAIN_SEGS(sbi) << sbi->log_blocks_per_seg; + u64 left_space = (total_blocks - valid_blocks)<<2; + unsigned int free_segs = free_segments(sbi); + unsigned int ovp_segments = overprovision_segments(sbi); + unsigned int lower_limit = 0; + unsigned int waterline = 0; + int dirty_sum = node_secs + 2 * dent_secs + imeta_secs; + left_space = left_space - ovp_segments*KBS_PER_SEGMENT; + if (test_opt(sbi, LFS)) + return false; + if (sbi->gc_mode == GC_URGENT) + return true; + if (contig_level == SEQ_256BLKS && type == CURSEG_WARM_DATA && free_sections(sbi) > dirty_sum + 3 * reserved_sections(sbi) / 2) + return false; + if (free_sections(sbi) <= (unsigned int)(dirty_sum + 2 * reserved_sections(sbi))){ + return true; + } + if (sbi->hot_cold_params.enable == GRADING_SSR_OFF) + return false; + if (contig_level >= SEQ_32BLKS) + return false; + switch (type) { + case CURSEG_HOT_DATA: + lower_limit = sbi->hot_cold_params.hot_data_lower_limit; + waterline = sbi->hot_cold_params.hot_data_waterline; + break; + case CURSEG_WARM_DATA: + lower_limit = sbi->hot_cold_params.warm_data_lower_limit; + waterline = sbi->hot_cold_params.warm_data_waterline; + break; + case CURSEG_HOT_NODE: + lower_limit = sbi->hot_cold_params.hot_node_lower_limit; + waterline = sbi->hot_cold_params.hot_node_waterline; + break; + case CURSEG_WARM_NODE: + lower_limit = sbi->hot_cold_params.warm_node_lower_limit; + waterline = sbi->hot_cold_params.warm_node_waterline; + break; + default: + return false; + } + if (left_space > lower_limit) + return false; + if (unlikely(0 == left_space/KBS_PER_SEGMENT)) + return false; + return (free_segs-ovp_segments) * 100 / (left_space/KBS_PER_SEGMENT) <= waterline; +} +#endif + +#ifdef CONFIG_OPLUS_FEATURE_OF2FS +/* + * 2019/08/13, add code to optimize gc + */ +block_t of2fs_seg_freefrag(struct f2fs_sb_info *sbi, unsigned int segno, + block_t* blocks, unsigned int n) +{ + struct seg_entry *se = get_seg_entry(sbi, segno); + unsigned long *cur_map = (unsigned long *)se->cur_valid_map; + unsigned int pos, pos0; + block_t total_blocks = 0; + // free and valid segment is not fragment + if (!se->valid_blocks || se->valid_blocks == sbi->blocks_per_seg) + return total_blocks; + pos0 = __find_rev_next_zero_bit(cur_map, sbi->blocks_per_seg, 0); + while (pos0 < sbi->blocks_per_seg) { + unsigned int blks, order; + pos = __find_rev_next_bit(cur_map, sbi->blocks_per_seg, pos0 + 1); + blks = pos - pos0; + order = ilog2(blks); + if (order < n) + blocks[order] += blks; + total_blocks += blks; + pos0 = __find_rev_next_zero_bit(cur_map, sbi->blocks_per_seg, pos + 1); + } + return total_blocks; +} +#endif void f2fs_register_inmem_page(struct inode *inode, struct page *page) { struct inmem_pages *new; @@ -485,6 +576,110 @@ int f2fs_commit_inmem_pages(struct inode *inode) return err; } +#ifdef CONFIG_OPLUS_FEATURE_OF2FS +/* + * 2019/08/14, add need_SSR GC + * 2019/08/14, do FG GC in GC thread + * 2019/08/16, trigger need_SSR GC base on bigdata stats + */ +#define DEF_DIRTY_STAT_INTERVAL 15 /* 15 secs */ +static inline bool of2fs_need_balance_dirty(struct f2fs_sb_info *sbi) +{ +#ifdef CONFIG_F2FS_BD_STAT + struct dirty_seglist_info *dirty_i = DIRTY_I(sbi); + struct timespec ts = {DEF_DIRTY_STAT_INTERVAL, 0}; + unsigned long interval = timespec_to_jiffies(&ts); + struct f2fs_bigdata_info *bd = F2FS_BD_STAT(sbi); + unsigned long last_jiffies; + int dirty_node = 0, dirty_data = 0, all_dirty; + long node_cnt, data_cnt; + int i; + + if (IS_ERR_OR_NULL(bd)) + return false; + last_jiffies = bd->ssr_last_jiffies; + + if (time_before(jiffies, last_jiffies + interval)) + return false; + + for (i = CURSEG_HOT_DATA; i <= CURSEG_COLD_DATA; i++) + dirty_data += dirty_i->nr_dirty[i]; + for (i = CURSEG_HOT_NODE; i <= CURSEG_COLD_NODE; i++) + dirty_node += dirty_i->nr_dirty[i]; + all_dirty = dirty_data + dirty_node; + if (!all_dirty) + return false; + + /* how many blocks are consumed during this interval */ + bd_lock(sbi); + node_cnt = (long)(bd->curr_node_alloc_count - bd->last_node_alloc_count); + data_cnt = (long)(bd->curr_data_alloc_count - bd->last_data_alloc_count); + + bd->last_node_alloc_count = bd->curr_node_alloc_count; + bd->last_data_alloc_count = bd->curr_data_alloc_count; + bd->ssr_last_jiffies = jiffies; + bd_unlock(sbi); + + + if (dirty_data < reserved_sections(sbi) && + data_cnt > (long)sbi->blocks_per_seg) { + int randnum = prandom_u32_max(100); + int ratio = dirty_data * 100 / all_dirty; + if (randnum > ratio) + return true; + } + + if (dirty_node < reserved_sections(sbi) && + node_cnt > (long)sbi->blocks_per_seg) { + int randnum = prandom_u32_max(100); + int ratio = dirty_node * 100 / all_dirty; + if (randnum > ratio) + return true; + } +#endif + return false; +} + +static inline void of2fs_balance_fs(struct f2fs_sb_info *sbi) +{ + if (!sbi->gc_opt_enable) { + /* + * We should do GC or end up with checkpoint, if there are so many dirty + * dir/node pages without enough free segments. + */ + if (has_not_enough_free_secs(sbi, 0, 0)) { + down_write(&sbi->gc_lock); + f2fs_gc(sbi, false, false, NULL_SEGNO); + } + return ; + } + + /* + * We should do GC or end up with checkpoint, if there are so many dirty + * dir/node pages without enough free segments. + */ + if (has_not_enough_free_secs(sbi, 0, 0)) { + struct f2fs_gc_kthread *gc_th = sbi->gc_thread; + if (NULL != gc_th) { + DEFINE_WAIT(__wait); + prepare_to_wait(&gc_th->fggc_wait_queue_head, + &__wait, TASK_UNINTERRUPTIBLE); + wake_up(&gc_th->gc_wait_queue_head); + schedule(); + finish_wait(&gc_th->fggc_wait_queue_head, &__wait); + } else { + down_write(&sbi->gc_lock); + f2fs_gc(sbi, false, false, NULL_SEGNO); + } + } else if (f2fs_need_SSR(sbi) && of2fs_need_balance_dirty(sbi)) { + struct f2fs_gc_kthread *gc_th = sbi->gc_thread; + if (NULL != gc_th) { + atomic_inc(&sbi->need_ssr_gc); + wake_up(&gc_th->gc_wait_queue_head); + } + } +} +#endif /* * This function balances dirty node and dentry pages. @@ -503,15 +698,21 @@ void f2fs_balance_fs(struct f2fs_sb_info *sbi, bool need) if (!f2fs_is_checkpoint_ready(sbi)) return; - +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + /* + * 2019/08/14, add need_SSR GC + */ + of2fs_balance_fs(sbi); /* * We should do GC or end up with checkpoint, if there are so many dirty * dir/node pages without enough free segments. */ +#else if (has_not_enough_free_secs(sbi, 0, 0)) { down_write(&sbi->gc_lock); f2fs_gc(sbi, false, false, NULL_SEGNO); } +#endif } void f2fs_balance_fs_bg(struct f2fs_sb_info *sbi, bool from_bg) @@ -944,7 +1145,11 @@ static struct discard_cmd *__create_discard_cmd(struct f2fs_sb_info *sbi, struct discard_cmd *dc; f2fs_bug_on(sbi, !len); - +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + if (!len) { + return NULL; + } +#endif pend_list = &dcc->pend_list[plist_idx(len)]; dc = f2fs_kmem_cache_alloc(discard_cmd_slab, GFP_NOFS); @@ -957,6 +1162,9 @@ static struct discard_cmd *__create_discard_cmd(struct f2fs_sb_info *sbi, dc->state = D_PREP; dc->queued = 0; dc->error = 0; +#ifdef CONFIG_F2FS_BD_STAT + dc->discard_time = 0; +#endif init_completion(&dc->wait); list_add_tail(&dc->list, pend_list); spin_lock_init(&dc->lock); @@ -1015,7 +1223,16 @@ static void __remove_discard_cmd(struct f2fs_sb_info *sbi, spin_unlock_irqrestore(&dc->lock, flags); f2fs_bug_on(sbi, dc->ref); - +#ifdef CONFIG_F2FS_BD_STAT + if (dc->state == D_DONE && !dc->error && dc->discard_time) { + bd_lock(sbi); + bd_inc_val(sbi, discard_blocks, dc->len); + bd_inc_val(sbi, discard_count, 1); + bd_inc_val(sbi, discard_time, dc->discard_time); + bd_max_val(sbi, max_discard_time, dc->discard_time); + bd_unlock(sbi); + } +#endif if (dc->error == -EOPNOTSUPP) dc->error = 0; @@ -1038,6 +1255,15 @@ static void f2fs_submit_discard_endio(struct bio *bio) dc->bio_ref--; if (!dc->bio_ref && dc->state == D_SUBMIT) { dc->state = D_DONE; +#ifdef CONFIG_F2FS_BD_STAT + if (dc->discard_time) { + u64 discard_end_time = (u64)ktime_get(); + if (discard_end_time > dc->discard_time) + dc->discard_time = discard_end_time - dc->discard_time; + else + dc->discard_time = 0; + } +#endif complete_all(&dc->wait); } spin_unlock_irqrestore(&dc->lock, flags); @@ -1086,7 +1312,12 @@ static void __init_discard_policy(struct f2fs_sb_info *sbi, dpolicy->max_requests = DEF_MAX_DISCARD_REQUEST; dpolicy->io_aware_gran = MAX_PLIST_NUM; dpolicy->timeout = false; - +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + /* + * 2019-10-15, add for oDiscard + */ + dpolicy->io_busy = false; +#endif if (discard_type == DPOLICY_BG) { dpolicy->min_interval = DEF_MIN_DISCARD_ISSUE_TIME; dpolicy->mid_interval = DEF_MID_DISCARD_ISSUE_TIME; @@ -1101,7 +1332,14 @@ static void __init_discard_policy(struct f2fs_sb_info *sbi, DEF_MIN_DISCARD_ISSUE_TIME; } } else if (discard_type == DPOLICY_FORCE) { +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + /* + * 2019-10-15, add for oDiscard + */ + dpolicy->min_interval = DEF_URGENT_DISCARD_ISSUE_TIME; +#else dpolicy->min_interval = DEF_MIN_DISCARD_ISSUE_TIME; +#endif dpolicy->mid_interval = DEF_MID_DISCARD_ISSUE_TIME; dpolicy->max_interval = DEF_MAX_DISCARD_ISSUE_TIME; dpolicy->io_aware = false; @@ -1111,6 +1349,18 @@ static void __init_discard_policy(struct f2fs_sb_info *sbi, dpolicy->io_aware = false; /* we need to issue all to keep CP_TRIMMED_FLAG */ dpolicy->granularity = 1; +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + } else if (discard_type == DPOLICY_BALANCE || + discard_type == DPOLICY_PERFORMANCE) { + /* + * 2019-10-15, add for oDiscard + */ + dpolicy->granularity = 1; + dpolicy->min_interval = 0; + dpolicy->mid_interval = 500; + dpolicy->max_interval = DEF_DISCARD_EMPTY_ISSUE_TIME; + dpolicy->io_aware = true; +#endif dpolicy->timeout = true; } } @@ -1192,6 +1442,10 @@ submit: * right away */ spin_lock_irqsave(&dc->lock, flags); +#ifdef CONFIG_F2FS_BD_STAT + if (dc->state == D_PREP) + dc->discard_time = (u64)ktime_get(); +#endif if (last) dc->state = D_SUBMIT; else @@ -1438,6 +1692,14 @@ static unsigned int __issue_discard_cmd_orderly(struct f2fs_sb_info *sbi, goto next; if (dpolicy->io_aware && !is_idle(sbi, DISCARD_TIME)) { +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + /* + * 2019-10-15, add for oDiscard + */ + if (sbi->dc_opt_enable) { + dpolicy->io_busy = true; + } +#endif io_interrupted = true; break; } @@ -1514,6 +1776,14 @@ retry: if (dpolicy->io_aware && i < dpolicy->io_aware_gran && !is_idle(sbi, DISCARD_TIME)) { io_interrupted = true; +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + /* + * 2019-10-15, add for oDiscard + */ + if (sbi->dc_opt_enable) { + dpolicy->io_busy = true; + } +#endif break; } @@ -1702,6 +1972,26 @@ bool f2fs_issue_discard_timeout(struct f2fs_sb_info *sbi) return dropped; } +#ifdef CONFIG_OPLUS_FEATURE_OF2FS +/* + * 2020-1-14, add for oDiscard decoupling + */ +static inline void check_dpolicy_expect(struct f2fs_sb_info *sbi, int *dpolicy_curr) +{ + if (!sbi->dc_opt_enable) + return; + + if (!f2fs_is_space_free(sbi)) { + *dpolicy_curr = DPOLICY_FORCE; + return; + } + + if (*dpolicy_curr != sbi->dpolicy_expect) + *dpolicy_curr = DPOLICY_BG; + + return; +} +#endif static int issue_discard_thread(void *data) { struct f2fs_sb_info *sbi = data; @@ -1710,7 +2000,13 @@ static int issue_discard_thread(void *data) struct discard_policy dpolicy; unsigned int wait_ms = DEF_MIN_DISCARD_ISSUE_TIME; int issued; - +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + /* + * 2020-1-14, add for oDiscard decoupling + */ + int dpolicy_curr = DPOLICY_BG; + unsigned long balance_end_time = 0; +#endif set_freezable(); do { @@ -1729,9 +2025,30 @@ static int issue_discard_thread(void *data) dcc->discard_wake, msecs_to_jiffies(wait_ms)); - if (dcc->discard_wake) + if (dcc->discard_wake) { +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + /* + * 2020-1-14, add for oDiscard decoupling + */ + switch (dcc->discard_wake) { + case 1: + if (sbi->dpolicy_expect == DPOLICY_BG) + dpolicy_curr = DPOLICY_BG; + break; + case DPOLICY_BALANCE: + balance_end_time = jiffies + + msecs_to_jiffies(DEF_DISCARD_BALANCE_TIME); + dpolicy_curr = DPOLICY_BALANCE; + break; + case DPOLICY_PERFORMANCE: + dpolicy_curr = DPOLICY_PERFORMANCE; + break; + default: + break; + } +#endif dcc->discard_wake = 0; - + } /* clean up pending candidates before going to sleep */ if (atomic_read(&dcc->queued_discard)) __wait_all_discard_cmd(sbi, NULL); @@ -1743,16 +2060,66 @@ static int issue_discard_thread(void *data) if (kthread_should_stop()) return 0; if (is_sbi_flag_set(sbi, SBI_NEED_FSCK)) { +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + /* + * 2020-1-14, add for oDiscard decoupling + */ + wait_ms = DEF_MAX_DISCARD_ISSUE_TIME; +#else wait_ms = dpolicy.max_interval; continue; +#endif } +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + /* + * 2020-1-14, add for oDiscard decoupling + */ + if (dpolicy_curr == DPOLICY_BALANCE) { + if (time_after(jiffies, balance_end_time)) { + wait_ms = DEF_MAX_DISCARD_ISSUE_TIME; + dpolicy_curr = DPOLICY_BG; + sbi->dpolicy_expect = DPOLICY_BG; + continue; + } + } +#endif + if (sbi->gc_mode == GC_URGENT) +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + { + /* + * 2020-1-14, add for oDiscard decoupling + */ + if (sbi->dc_opt_enable) + dpolicy_curr = DPOLICY_FORCE; +#endif + __init_discard_policy(sbi, &dpolicy, DPOLICY_FORCE, 1); +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + } else { + /* + * 2020-1-14, add for oDiscard decoupling + */ + check_dpolicy_expect(sbi, &dpolicy_curr); + __init_discard_policy(sbi, &dpolicy, dpolicy_curr, + dcc->discard_granularity); + } +#endif sb_start_intwrite(sbi->sb); issued = __issue_discard_cmd(sbi, &dpolicy); if (issued > 0) { __wait_all_discard_cmd(sbi, &dpolicy); wait_ms = dpolicy.min_interval; +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + /* + * 2020-1-14, add for oDiscard decoupling + */ + if (dpolicy.io_busy) { + wait_ms = f2fs_time_to_wait(sbi, DISCARD_TIME); + if (!wait_ms) + wait_ms = dpolicy.mid_interval; + } +#endif } else if (issued == -1){ wait_ms = f2fs_time_to_wait(sbi, DISCARD_TIME); if (!wait_ms) @@ -2235,6 +2602,55 @@ static void update_sit_entry(struct f2fs_sb_info *sbi, block_t blkaddr, int del) get_sec_entry(sbi, segno)->valid_blocks += del; } +#ifdef CONFIG_OPLUS_FEATURE_OF2FS +static inline unsigned long long get_segment_mtime(struct f2fs_sb_info *sbi, + block_t blkaddr) +{ + return get_seg_entry(sbi, GET_SEGNO(sbi, blkaddr))->mtime; +} + +void update_segment_mtime(struct f2fs_sb_info *sbi, block_t blkaddr, + unsigned long long old_mtime, bool del) +{ + struct seg_entry *se; + unsigned int segno; + unsigned long long ctime = get_mtime(sbi, false); + unsigned long long mtime = old_mtime ? old_mtime : ctime; + unsigned old_valid_blocks, total_valid; + + segno = GET_SEGNO(sbi, blkaddr); + se = get_seg_entry(sbi, segno); + if (!se->mtime) { + se->mtime = mtime; + } else { + old_valid_blocks = del ? + (se->valid_blocks - 1) : se->valid_blocks; + total_valid = old_valid_blocks + 1; + se->mtime = (se->mtime * old_valid_blocks + mtime) / + total_valid; + } + if (ctime > SIT_I(sbi)->max_mtime) + SIT_I(sbi)->max_mtime = ctime; +} + +void refresh_sit_entry(struct f2fs_sb_info *sbi, block_t old, block_t new, + bool from_gc) +{ + unsigned long long old_mtime = 0; + bool old_exist = (GET_SEGNO(sbi, old) != NULL_SEGNO); + + if (old_exist && from_gc) + old_mtime = get_segment_mtime(sbi, old); + update_sit_entry(sbi, new, 1); + update_segment_mtime(sbi, new, old_mtime, true); + if (old_exist) { + update_sit_entry(sbi, old, -1); + if (!from_gc) + update_segment_mtime(sbi, old, 0, false); + } +} +#endif + void f2fs_invalidate_blocks(struct f2fs_sb_info *sbi, block_t addr) { unsigned int segno = GET_SEGNO(sbi, addr); @@ -2250,7 +2666,9 @@ void f2fs_invalidate_blocks(struct f2fs_sb_info *sbi, block_t addr) down_write(&sit_i->sentry_lock); update_sit_entry(sbi, addr, -1); - +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + update_segment_mtime(sbi, addr, 0, false); +#endif /* add it into dirty seglist */ locate_dirty_segment(sbi, segno); @@ -2388,8 +2806,13 @@ static int is_next_segment_free(struct f2fs_sb_info *sbi, int type) * Find a new segment from the free segments bitmap to right order * This function should be returned with success, otherwise BUG */ +#ifdef CONFIG_OPLUS_FEATURE_OF2FS +void get_new_segment(struct f2fs_sb_info *sbi, + unsigned int *newseg, bool new_sec, int dir) +#else static void get_new_segment(struct f2fs_sb_info *sbi, unsigned int *newseg, bool new_sec, int dir) +#endif { struct free_segmap_info *free_i = FREE_I(sbi); unsigned int segno, secno, zoneno; @@ -2452,11 +2875,19 @@ skip_left: if (go_left && zoneno == 0) goto got_it; } +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + for (i = 0; i < NR_INMEM_CURSEG_TYPE; i++) +#else for (i = 0; i < NR_CURSEG_TYPE; i++) +#endif if (CURSEG_I(sbi, i)->zone == zoneno) break; +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + if (i < NR_INMEM_CURSEG_TYPE) { +#else if (i < NR_CURSEG_TYPE) { +#endif /* zone is in user, try another */ if (go_left) hint = zoneno * sbi->secs_per_zone - 1; @@ -2474,10 +2905,14 @@ got_it: *newseg = segno; spin_unlock(&free_i->segmap_lock); } - +#ifdef CONFIG_OPLUS_FEATURE_OF2FS +static void __reset_curseg(struct f2fs_sb_info *sbi, struct curseg_info *curseg, int type, int modified) +{ +#else static void reset_curseg(struct f2fs_sb_info *sbi, int type, int modified) { struct curseg_info *curseg = CURSEG_I(sbi, type); +#endif struct summary_footer *sum_footer; curseg->segno = curseg->next_segno; @@ -2491,9 +2926,17 @@ static void reset_curseg(struct f2fs_sb_info *sbi, int type, int modified) SET_SUM_TYPE(sum_footer, SUM_TYPE_DATA); if (IS_NODESEG(type)) SET_SUM_TYPE(sum_footer, SUM_TYPE_NODE); +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + f2fs_bug_on(sbi, type == CURSEG_FRAGMENT_DATA); +#endif __set_sit_entry_type(sbi, type, curseg->segno, modified); } - +#ifdef CONFIG_OPLUS_FEATURE_OF2FS +static void reset_curseg(struct f2fs_sb_info *sbi, int type, int modified) +{ + __reset_curseg(sbi, CURSEG_I(sbi, type), type, modified); +} +#endif static unsigned int __get_next_segno(struct f2fs_sb_info *sbi, int type) { /* if segs_per_sec is large than 1, we need to keep original policy. */ @@ -2521,9 +2964,15 @@ static unsigned int __get_next_segno(struct f2fs_sb_info *sbi, int type) * Allocate a current working segment. * This function always allocates a free segment in LFS manner. */ +#ifdef CONFIG_OPLUS_FEATURE_OF2FS +static void __new_curseg(struct f2fs_sb_info *sbi, struct curseg_info *curseg, + int type, bool new_sec) +{ +#else static void new_curseg(struct f2fs_sb_info *sbi, int type, bool new_sec) { struct curseg_info *curseg = CURSEG_I(sbi, type); +#endif unsigned int segno = curseg->segno; int dir = ALLOC_LEFT; @@ -2536,11 +2985,25 @@ static void new_curseg(struct f2fs_sb_info *sbi, int type, bool new_sec) dir = ALLOC_RIGHT; segno = __get_next_segno(sbi, type); +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + SIT_I(sbi)->s_ops->get_new_segment(sbi, &segno, new_sec, dir); +#else get_new_segment(sbi, &segno, new_sec, dir); +#endif curseg->next_segno = segno; +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + __reset_curseg(sbi, curseg, type, 1); +#else reset_curseg(sbi, type, 1); +#endif curseg->alloc_type = LFS; } +#ifdef CONFIG_OPLUS_FEATURE_OF2FS +static void new_curseg(struct f2fs_sb_info *sbi, int type, bool new_sec) +{ + __new_curseg(sbi, CURSEG_I(sbi, type), type, new_sec); +} +#endif static void __next_free_blkoff(struct f2fs_sb_info *sbi, struct curseg_info *seg, block_t start) @@ -2578,15 +3041,24 @@ static void __refresh_next_blkoff(struct f2fs_sb_info *sbi, * This function always allocates a used segment(from dirty seglist) by SSR * manner, so it should recover the existing segment information of valid blocks */ +#ifdef CONFIG_OPLUS_FEATURE_OF2FS +static void __change_curseg(struct f2fs_sb_info *sbi, struct curseg_info *curseg, + int type, bool flush_summary) +{ +#else static void change_curseg(struct f2fs_sb_info *sbi, int type) { + struct curseg_info *curseg = CURSEG_I(sbi, type); +#endif struct dirty_seglist_info *dirty_i = DIRTY_I(sbi); - struct curseg_info *curseg = CURSEG_I(sbi, type); unsigned int new_segno = curseg->next_segno; struct f2fs_summary_block *sum_node; struct page *sum_page; - write_sum_page(sbi, curseg->sum_blk, +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + if (flush_summary) +#endif + write_sum_page(sbi, curseg->sum_blk, GET_SUM_BLOCK(sbi, curseg->segno)); __set_test_and_inuse(sbi, new_segno); @@ -2594,8 +3066,11 @@ static void change_curseg(struct f2fs_sb_info *sbi, int type) __remove_dirty_segment(sbi, new_segno, PRE); __remove_dirty_segment(sbi, new_segno, DIRTY); mutex_unlock(&dirty_i->seglist_lock); - +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + __reset_curseg(sbi, curseg, type, 1); +#else reset_curseg(sbi, type, 1); +#endif curseg->alloc_type = SSR; __next_free_blkoff(sbi, curseg, 0); @@ -2605,17 +3080,78 @@ static void change_curseg(struct f2fs_sb_info *sbi, int type) memcpy(curseg->sum_blk, sum_node, SUM_ENTRY_SIZE); f2fs_put_page(sum_page, 1); } +#ifdef CONFIG_OPLUS_FEATURE_OF2FS +static void change_curseg(struct f2fs_sb_info *sbi, int type, bool flush_summary) +{ + __change_curseg(sbi, CURSEG_I(sbi, type), type, flush_summary); +} + +static inline void __restore_virtual_curseg_status(struct f2fs_sb_info *sbi, + int type, bool recover) +{ + struct curseg_info *curseg = CURSEG_I(sbi, type); + + mutex_lock(&curseg->curseg_mutex); + down_write(&SIT_I(sbi)->sentry_lock); + if (curseg->inited && !get_valid_blocks(sbi, curseg->segno, false)) { + if (recover) + __set_test_and_free(sbi, curseg->segno); + else + __set_test_and_inuse(sbi, curseg->segno); + } + up_write(&SIT_I(sbi)->sentry_lock); + mutex_unlock(&curseg->curseg_mutex); +} + +void restore_virtual_curseg_status(struct f2fs_sb_info *sbi, bool recover) +{ + if (sbi->atgc_enabled) + __restore_virtual_curseg_status(sbi, CURSEG_FRAGMENT_DATA, + recover); +} + +static inline void __store_virtual_curseg_summary(struct f2fs_sb_info *sbi, + int type) +{ + struct curseg_info *curseg = CURSEG_I(sbi, type); + + mutex_lock(&curseg->curseg_mutex); + down_write(&SIT_I(sbi)->sentry_lock); + if (curseg->inited) + write_sum_page(sbi, curseg->sum_blk, + GET_SUM_BLOCK(sbi, curseg->segno)); + + up_write(&SIT_I(sbi)->sentry_lock); + mutex_unlock(&curseg->curseg_mutex); +} + +void store_virtual_curseg_summary(struct f2fs_sb_info *sbi) +{ + if (sbi->atgc_enabled) + __store_virtual_curseg_summary(sbi, CURSEG_FRAGMENT_DATA); +} +#endif +#ifdef CONFIG_OPLUS_FEATURE_OF2FS +static int __get_ssr_segment(struct f2fs_sb_info *sbi, struct curseg_info *curseg, + int type, int alloc_mode, unsigned long long age) +{ +#else static int get_ssr_segment(struct f2fs_sb_info *sbi, int type) { struct curseg_info *curseg = CURSEG_I(sbi, type); +#endif const struct victim_selection *v_ops = DIRTY_I(sbi)->v_ops; unsigned segno = NULL_SEGNO; int i, cnt; bool reversed = false; /* f2fs_need_SSR() already forces to do this */ +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + if (v_ops->get_victim(sbi, &segno, BG_GC, type, alloc_mode, age)) { +#else if (v_ops->get_victim(sbi, &segno, BG_GC, type, SSR)) { +#endif curseg->next_segno = segno; return 1; } @@ -2642,7 +3178,11 @@ static int get_ssr_segment(struct f2fs_sb_info *sbi, int type) for (; cnt-- > 0; reversed ? i-- : i++) { if (i == type) continue; +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + if (v_ops->get_victim(sbi, &segno, BG_GC, i, alloc_mode, age)) { +#else if (v_ops->get_victim(sbi, &segno, BG_GC, i, SSR)) { +#endif curseg->next_segno = segno; return 1; } @@ -2658,16 +3198,37 @@ static int get_ssr_segment(struct f2fs_sb_info *sbi, int type) } return 0; } +#ifdef CONFIG_OPLUS_FEATURE_OF2FS +static int get_ssr_segment(struct f2fs_sb_info *sbi, int type, + int alloc_mode, unsigned long long age) +{ + return __get_ssr_segment(sbi, CURSEG_I(sbi, type), type, alloc_mode, age); +} +#endif /* * flush out current segment and replace it with new segment * This function should be returned with success, otherwise BUG */ +#ifdef CONFIG_OPLUS_FEATURE_OF2FS +static void allocate_segment_by_default(struct f2fs_sb_info *sbi, + int type, bool force, int contig_level) +#else static void allocate_segment_by_default(struct f2fs_sb_info *sbi, int type, bool force) +#endif { struct curseg_info *curseg = CURSEG_I(sbi, type); - +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + if (force) + SIT_I(sbi)->s_ops->new_curseg(sbi, type, true); + else if (!is_set_ckpt_flags(sbi, CP_CRC_RECOVERY_FLAG) && + type == CURSEG_WARM_NODE) + SIT_I(sbi)->s_ops->new_curseg(sbi, type, false); + else if (curseg->alloc_type == LFS && is_next_segment_free(sbi, type) && + likely(!is_sbi_flag_set(sbi, SBI_CP_DISABLED))) + SIT_I(sbi)->s_ops->new_curseg(sbi, type, false); +#else if (force) new_curseg(sbi, type, true); else if (!is_set_ckpt_flags(sbi, CP_CRC_RECOVERY_FLAG) && @@ -2676,11 +3237,27 @@ static void allocate_segment_by_default(struct f2fs_sb_info *sbi, else if (curseg->alloc_type == LFS && is_next_segment_free(sbi, type) && likely(!is_sbi_flag_set(sbi, SBI_CP_DISABLED))) new_curseg(sbi, type, false); - else if (f2fs_need_SSR(sbi) && get_ssr_segment(sbi, type)) - change_curseg(sbi, type); - else - new_curseg(sbi, type, false); +#endif + +#ifdef CONFIG_OPLUS_FEATURE_OF2FS +#ifdef CONFIG_F2FS_GRADING_SSR + else if (need_SSR_by_type(sbi, type, contig_level) && get_ssr_segment(sbi, type, SSR, 0)) +#else + else if (f2fs_need_SSR(sbi) && get_ssr_segment(sbi, type, SSR, 0)) +#endif +#else + else if (f2fs_need_SSR(sbi) && get_ssr_segment(sbi, type)) +#endif +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + change_curseg(sbi, type, true); + else + SIT_I(sbi)->s_ops->new_curseg(sbi, type, false); +#else + change_curseg(sbi, type); + else + new_curseg(sbi, type, false); +#endif stat_inc_seg_type(sbi, curseg); } @@ -2697,15 +3274,33 @@ void allocate_segment_for_resize(struct f2fs_sb_info *sbi, int type, segno = CURSEG_I(sbi, type)->segno; if (segno < start || segno > end) goto unlock; +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + if (type >= CURSEG_HOT_DATA && type <= CURSEG_COLD_NODE) { + if (f2fs_need_SSR(sbi) && get_ssr_segment(sbi, type, SSR, 0)) + change_curseg(sbi, type, true); + else + SIT_I(sbi)->s_ops->new_curseg(sbi, type, true); + } else if (type == CURSEG_FRAGMENT_DATA) { + int type2; + type2 = get_seg_entry(sbi, segno)->type; + SIT_I(sbi)->s_ops->new_curseg(sbi, type2, true); + } else { + f2fs_bug_on(sbi, 1); + } +#else if (f2fs_need_SSR(sbi) && get_ssr_segment(sbi, type)) change_curseg(sbi, type); else new_curseg(sbi, type, true); - +#endif stat_inc_seg_type(sbi, curseg); locate_dirty_segment(sbi, segno); +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + if (get_valid_blocks(sbi, segno, false) == 0) + __set_test_and_free(sbi, segno); +#endif unlock: up_write(&SIT_I(sbi)->sentry_lock); @@ -2734,7 +3329,11 @@ void f2fs_allocate_new_segments(struct f2fs_sb_info *sbi, int type) get_valid_blocks(sbi, curseg->segno, false) || get_ckpt_valid_blocks(sbi, curseg->segno)) { old_segno = curseg->segno; +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + SIT_I(sbi)->s_ops->allocate_segment(sbi, i, true, true); +#else SIT_I(sbi)->s_ops->allocate_segment(sbi, i, true); +#endif locate_dirty_segment(sbi, old_segno); } } @@ -2744,8 +3343,213 @@ void f2fs_allocate_new_segments(struct f2fs_sb_info *sbi, int type) static const struct segment_allocation default_salloc_ops = { .allocate_segment = allocate_segment_by_default, +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + .get_new_segment = get_new_segment, + .new_curseg = new_curseg, + .__new_curseg = __new_curseg, + +#endif }; +#ifdef CONFIG_OPLUS_FEATURE_OF2FS +#define F2FS_SPREAD_RADIUS_SIZE 8 /* 8 section */ + +/* + * @newsec: force to allocate in a new section. + */ +static void get_new_segment_subdivision(struct f2fs_sb_info *sbi, + unsigned int *newseg, bool new_sec, int dir) +{ + struct free_segmap_info *free_i = FREE_I(sbi); + unsigned int segno, zoneno; + unsigned int secno = NULL_SECNO; + unsigned int total_zones; + unsigned int hint = GET_SEC_FROM_SEG(sbi, *newseg); + unsigned int old_zoneno = GET_ZONE_FROM_SEG(sbi, *newseg); + unsigned int left_start = hint, right_start, start, end; + unsigned int start_sec = 0; + unsigned int end_sec; + bool init = true; + int go_left = 0; + int i; + + spin_lock(&free_i->segmap_lock); + total_zones = MAIN_SECS(sbi) / sbi->secs_per_zone; + end_sec = MAIN_SECS(sbi); + + /* + * if we don't force to allocate a new section, and there is still + * free space in current section, then do allocation. + * No logic change here. + */ + if (!new_sec && ((*newseg + 1) % sbi->segs_per_sec)) { + segno = find_next_zero_bit(free_i->free_segmap, + GET_SEG_FROM_SEC(sbi, hint + 1), *newseg + 1); + if (segno < GET_SEG_FROM_SEC(sbi, hint + 1)) + goto got_it; + } +find_other_zone: + if (dir == ALLOC_RIGHT) { + secno = find_next_zero_bit(free_i->free_secmap, + end_sec, start_sec); + f2fs_bug_on(sbi, secno >= end_sec); + } else if (dir == ALLOC_LEFT) { + left_start = end_sec - 1; + do { + if (!test_bit(left_start, free_i->free_secmap)) + break; + + f2fs_bug_on(sbi, left_start == start_sec); + } while (left_start-- > start_sec); + secno = left_start; + } else {/* ALLOC_SPREAD */ + bool rightward = true; + + left_start = right_start = end_sec / 2; + + while (left_start > start_sec || right_start < end_sec) { + if (rightward) { + if (right_start == end_sec) + goto next; + end = min_t(unsigned int, + end_sec, right_start + + F2FS_SPREAD_RADIUS_SIZE); + secno = find_next_zero_bit(free_i->free_secmap, + end, right_start); + if (secno >= end) { + right_start = end; + goto next; + } + break; + } else { + if (left_start == start_sec) + goto next; + start = min_t(int, start_sec, left_start - + F2FS_SPREAD_RADIUS_SIZE); + secno = find_next_zero_bit(free_i->free_secmap, + left_start, start); + if (secno >= left_start) { + left_start = start; + goto next; + } + break; + } +next: + rightward = !rightward; + } + } + + /* zone allocation policy */ + segno = GET_SEG_FROM_SEC(sbi, secno); + zoneno = GET_ZONE_FROM_SEC(sbi, secno); + + /* give up on finding another zone */ + if (!init) + goto got_it; + if (sbi->secs_per_zone == 1) + goto got_it; + if (zoneno == old_zoneno) + goto got_it; + if (dir == ALLOC_LEFT) { + if (!go_left && zoneno + 1 >= total_zones) + goto got_it; + if (go_left && zoneno == 0) + goto got_it; + } + for (i = 0; i < NR_CURSEG_TYPE; i++) + if (CURSEG_I(sbi, i)->zone == zoneno) + break; + + if (i < NR_CURSEG_TYPE) { + /* zone is in user, try another */ + if (go_left) + hint = zoneno * sbi->secs_per_zone - 1; + else if (zoneno + 1 >= total_zones) + hint = 0; + else + hint = (zoneno + 1) * sbi->secs_per_zone; + init = false; + goto find_other_zone; + } +got_it: + /* set it as dirty segment in free segmap */ + f2fs_bug_on(sbi, test_bit(segno, free_i->free_segmap)); + __set_inuse(sbi, segno); + *newseg = segno; + spin_unlock(&free_i->segmap_lock); +} + +static void __new_curseg_subdivision(struct f2fs_sb_info *sbi, + struct curseg_info *curseg, int type, bool new_sec) +{ + unsigned int segno = curseg->segno; + int dir; + + write_sum_page(sbi, curseg->sum_blk, + GET_SUM_BLOCK(sbi, segno)); + + switch (type) { + case CURSEG_HOT_NODE: + case CURSEG_WARM_NODE: + case CURSEG_HOT_DATA: + dir = ALLOC_RIGHT; + break; + case CURSEG_WARM_DATA: + dir = ALLOC_SPREAD; + break; + case CURSEG_COLD_NODE: + case CURSEG_COLD_DATA: + dir = ALLOC_LEFT; + break; + default: + dir = ALLOC_RIGHT; + f2fs_bug_on(sbi, 1); + } + + SIT_I(sbi)->s_ops->get_new_segment(sbi, &segno, new_sec, dir); + curseg->next_segno = segno; + __reset_curseg(sbi, curseg, type, 1); + curseg->alloc_type = LFS; +} + +static void new_curseg_subdivision(struct f2fs_sb_info *sbi, + int type, bool new_sec) +{ + __new_curseg_subdivision(sbi, CURSEG_I(sbi, type), type, new_sec); +} + +static void allocate_segment_subdivision(struct f2fs_sb_info *sbi, + int type, bool force, int contig_level) +{ + struct curseg_info *curseg = CURSEG_I(sbi, type); + if (force) + SIT_I(sbi)->s_ops->new_curseg(sbi, type, true); + else if (!is_set_ckpt_flags(sbi, CP_CRC_RECOVERY_FLAG) && + type == CURSEG_WARM_NODE) + SIT_I(sbi)->s_ops->new_curseg(sbi, type, true); + else if (curseg->alloc_type == LFS && is_next_segment_free(sbi, type)) + SIT_I(sbi)->s_ops->new_curseg(sbi, type, true); +#ifdef CONFIG_F2FS_GRADING_SSR + else if (need_SSR_by_type(sbi, type, contig_level) && get_ssr_segment(sbi, type, SSR, 0)) +#else + else if (f2fs_need_SSR(sbi) && get_ssr_segment(sbi, type, SSR, 0)) +#endif + change_curseg(sbi, type, true); + else + SIT_I(sbi)->s_ops->new_curseg(sbi, type, false); + + stat_inc_seg_type(sbi, curseg); +} + +static const struct segment_allocation subdivision_salloc_ops = { + .allocate_segment = allocate_segment_subdivision, + .get_new_segment = get_new_segment_subdivision, + .new_curseg = new_curseg_subdivision, + .__new_curseg = __new_curseg_subdivision, +}; + +#endif + bool f2fs_exist_trim_candidates(struct f2fs_sb_info *sbi, struct cp_control *cpc) { @@ -2889,9 +3693,16 @@ int f2fs_trim_fs(struct f2fs_sb_info *sbi, struct fstrim_range *range) * discard option. User configuration looks like using runtime discard * or periodic fstrim instead of it. */ - if (f2fs_realtime_discard_enable(sbi)) - goto out; - + if (f2fs_realtime_discard_enable(sbi)) { +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + /* + * 2019-10-15, add for oDiscard + */ + if (sbi->dc_opt_enable) + wake_up_discard_thread_aggressive(sbi, DPOLICY_PERFORMANCE); +#endif + goto out; + } start_block = START_BLOCK(sbi, start_segno); end_block = START_BLOCK(sbi, end_segno + 1); @@ -3051,10 +3862,23 @@ static int __get_segment_type_6(struct f2fs_io_info *fio) { if (fio->type == DATA) { struct inode *inode = fio->page->mapping->host; - +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + if (is_cold_data(fio->page)) { + if (fio->sbi && fio->sbi->atgc_enabled && + fio->io_type == FS_DATA_IO && + (fio->sbi->gc_mode == GC_IDLE_AT || + fio->sbi->gc_mode == GC_NORMAL)) + return CURSEG_FRAGMENT_DATA; + else + return CURSEG_COLD_DATA; + } + else if (file_is_cold(inode)) + return CURSEG_COLD_DATA; +#else if (is_cold_data(fio->page) || file_is_cold(inode) || f2fs_compressed_file(inode)) return CURSEG_COLD_DATA; +#endif if (file_is_hot(inode) || is_inode_flag_set(inode, FI_HOT_DATA) || f2fs_is_atomic_file(inode) || @@ -3096,14 +3920,32 @@ static int __get_segment_type(struct f2fs_io_info *fio) return type; } +#ifdef CONFIG_OPLUS_FEATURE_OF2FS +void f2fs_allocate_data_block(struct f2fs_sb_info *sbi, struct page *page, + block_t old_blkaddr, block_t *new_blkaddr, + struct f2fs_summary *sum, int type, + struct f2fs_io_info *fio, bool add_list, + int contig_level) +#else void f2fs_allocate_data_block(struct f2fs_sb_info *sbi, struct page *page, block_t old_blkaddr, block_t *new_blkaddr, struct f2fs_summary *sum, int type, struct f2fs_io_info *fio, bool add_list) +#endif { struct sit_info *sit_i = SIT_I(sbi); struct curseg_info *curseg = CURSEG_I(sbi, type); bool put_pin_sem = false; +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + bool from_gc = (type == CURSEG_FRAGMENT_DATA); + struct seg_entry *se; +#endif +#ifdef CONFIG_F2FS_GRADING_SSR + struct inode *inode = NULL; +#endif +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + int contig = SEQ_NONE; +#endif if (type == CURSEG_COLD_DATA) { /* GC during CURSEG_COLD_DATA_PINNED allocation */ @@ -3130,8 +3972,17 @@ void f2fs_allocate_data_block(struct f2fs_sb_info *sbi, struct page *page, mutex_lock(&curseg->curseg_mutex); down_write(&sit_i->sentry_lock); +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + if (from_gc) { + f2fs_bug_on(sbi, GET_SEGNO(sbi, old_blkaddr) == NULL_SEGNO); + se = get_seg_entry(sbi, GET_SEGNO(sbi, old_blkaddr)); + f2fs_bug_on(sbi, IS_NODESEG(se->type)); + } +#endif *new_blkaddr = NEXT_FREE_BLKADDR(sbi, curseg); - +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + f2fs_bug_on(sbi, curseg->next_blkoff >= sbi->blocks_per_seg); +#endif f2fs_wait_discard_bio(sbi, *new_blkaddr); /* @@ -3144,18 +3995,64 @@ void f2fs_allocate_data_block(struct f2fs_sb_info *sbi, struct page *page, __refresh_next_blkoff(sbi, curseg); stat_inc_block_count(sbi, curseg); - +#ifdef CONFIG_F2FS_BD_STAT + bd_lock(sbi); + if (type >= CURSEG_HOT_DATA && type <= CURSEG_COLD_DATA) { + bd_inc_array_val(sbi, data_alloc_count, curseg->alloc_type, 1); + bd_inc_val(sbi, curr_data_alloc_count, 1); + } else if (type >= CURSEG_HOT_NODE && type <= CURSEG_COLD_NODE) { + bd_inc_array_val(sbi, node_alloc_count, curseg->alloc_type, 1); + bd_inc_val(sbi, curr_node_alloc_count, 1); + } + bd_inc_array_val(sbi, hotcold_count, type + 1, 1UL); + bd_unlock(sbi); +#endif /* * SIT information should be updated before segment allocation, * since SSR needs latest valid block information. */ +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + refresh_sit_entry(sbi, old_blkaddr, *new_blkaddr, from_gc); + + if (!__has_curseg_space(sbi, type)) { + if (from_gc && sbi->atgc_enabled) { + if (__get_ssr_segment(sbi, curseg, se->type, ASSR, se->mtime)) { + f2fs_bug_on(sbi, curseg->next_segno == + CURSEG_I(sbi, type)->segno); + se = get_seg_entry(sbi, curseg->next_segno); + __change_curseg(sbi, curseg, se->type, true); + } else { + sit_i->s_ops->__new_curseg(sbi, curseg, se->type, false); + } + stat_inc_seg_type(sbi, curseg); + } else { +#ifdef CONFIG_F2FS_GRADING_SSR + if (contig_level != SEQ_NONE) { + contig = contig_level; + goto allocate_label; + } + + if (page && page->mapping && page->mapping != NODE_MAPPING(sbi) && + page->mapping != META_MAPPING(sbi)) { + inode = page->mapping->host; + + contig = check_io_seq(get_dirty_pages(inode)); + } +allocate_label: +#endif + + sit_i->s_ops->allocate_segment(sbi, type, false, contig); + + } + } +#else update_sit_entry(sbi, *new_blkaddr, 1); if (GET_SEGNO(sbi, old_blkaddr) != NULL_SEGNO) update_sit_entry(sbi, old_blkaddr, -1); if (!__has_curseg_space(sbi, type)) sit_i->s_ops->allocate_segment(sbi, type, false); - +#endif /* * segment dirty status should be updated after segment allocation, * so we just need to update status only one time after previous @@ -3226,8 +4123,13 @@ static void do_write_page(struct f2fs_summary *sum, struct f2fs_io_info *fio) if (keep_order) down_read(&fio->sbi->io_order_lock); reallocate: +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + f2fs_allocate_data_block(fio->sbi, fio->page, fio->old_blkaddr, + &fio->new_blkaddr, sum, type, fio, true, SEQ_NONE); +#else f2fs_allocate_data_block(fio->sbi, fio->page, fio->old_blkaddr, &fio->new_blkaddr, sum, type, fio, true); +#endif if (GET_SEGNO(fio->sbi, fio->old_blkaddr) != NULL_SEGNO) invalidate_mapping_pages(META_MAPPING(fio->sbi), fio->old_blkaddr, fio->old_blkaddr); @@ -3270,6 +4172,19 @@ void f2fs_do_write_meta_page(struct f2fs_sb_info *sbi, struct page *page, stat_inc_meta_count(sbi, page->index); f2fs_update_iostat(sbi, io_type, F2FS_BLKSIZE); +#ifdef CONFIG_F2FS_BD_STAT + bd_lock(sbi); + if (fio.new_blkaddr >= le32_to_cpu(F2FS_RAW_SUPER(sbi)->cp_blkaddr) && + (fio.new_blkaddr < le32_to_cpu(F2FS_RAW_SUPER(sbi)->sit_blkaddr))) + bd_inc_array_val(sbi, hotcold_count, HC_META_CP, 1); + else if (fio.new_blkaddr < le32_to_cpu(F2FS_RAW_SUPER(sbi)->nat_blkaddr)) + bd_inc_array_val(sbi, hotcold_count, HC_META_SIT, 1); + else if (fio.new_blkaddr < le32_to_cpu(F2FS_RAW_SUPER(sbi)->ssa_blkaddr)) + bd_inc_array_val(sbi, hotcold_count, HC_META_NAT, 1); + else if (fio.new_blkaddr < le32_to_cpu(F2FS_RAW_SUPER(sbi)->main_blkaddr)) + bd_inc_array_val(sbi, hotcold_count, HC_META_SSA, 1); + bd_unlock(sbi); +#endif } void f2fs_do_write_node_page(unsigned int nid, struct f2fs_io_info *fio) @@ -3315,8 +4230,16 @@ int f2fs_inplace_write_data(struct f2fs_io_info *fio) return -EFSCORRUPTED; } - stat_inc_inplace_blocks(fio->sbi); + if (fio->post_read) + invalidate_mapping_pages(META_MAPPING(sbi), + fio->new_blkaddr, fio->new_blkaddr); + stat_inc_inplace_blocks(fio->sbi); +#ifdef CONFIG_F2FS_BD_STAT + bd_lock(sbi); + bd_inc_val(sbi, data_ipu_count, 1); + bd_unlock(sbi); +#endif if (fio->bio && !(SM_I(sbi)->ipu_policy & (1 << F2FS_IPU_NOCACHE))) err = f2fs_merge_page_bio(fio); else @@ -3340,10 +4263,16 @@ static inline int __f2fs_get_curseg(struct f2fs_sb_info *sbi, } return i; } - +#ifdef CONFIG_OPLUS_FEATURE_OF2FS +void f2fs_do_replace_block(struct f2fs_sb_info *sbi, struct f2fs_summary *sum, + block_t old_blkaddr, block_t new_blkaddr, + bool recover_curseg, bool recover_newaddr, + bool from_gc) +#else void f2fs_do_replace_block(struct f2fs_sb_info *sbi, struct f2fs_summary *sum, block_t old_blkaddr, block_t new_blkaddr, bool recover_curseg, bool recover_newaddr) +#endif { struct sit_info *sit_i = SIT_I(sbi); struct curseg_info *curseg; @@ -3388,20 +4317,39 @@ void f2fs_do_replace_block(struct f2fs_sb_info *sbi, struct f2fs_summary *sum, /* change the current segment */ if (segno != curseg->segno) { curseg->next_segno = segno; +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + __change_curseg(sbi, curseg, type, true); +#else change_curseg(sbi, type); +#endif } curseg->next_blkoff = GET_BLKOFF_FROM_SEG0(sbi, new_blkaddr); __add_sum_entry(sbi, type, sum); - if (!recover_curseg || recover_newaddr) +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + if (!recover_curseg || recover_newaddr) { + update_sit_entry(sbi, new_blkaddr, 1); + if (!from_gc) + update_segment_mtime(sbi, new_blkaddr, 0, true); + } + + if (GET_SEGNO(sbi, old_blkaddr) != NULL_SEGNO) { + invalidate_mapping_pages(META_MAPPING(sbi), + old_blkaddr, old_blkaddr); + update_sit_entry(sbi, old_blkaddr, -1); + if (!from_gc) + update_segment_mtime(sbi, new_blkaddr, 0, false); + } +#else +if (!recover_curseg || recover_newaddr) update_sit_entry(sbi, new_blkaddr, 1); if (GET_SEGNO(sbi, old_blkaddr) != NULL_SEGNO) { invalidate_mapping_pages(META_MAPPING(sbi), old_blkaddr, old_blkaddr); update_sit_entry(sbi, old_blkaddr, -1); } - +#endif locate_dirty_segment(sbi, GET_SEGNO(sbi, old_blkaddr)); locate_dirty_segment(sbi, GET_SEGNO(sbi, new_blkaddr)); @@ -3410,7 +4358,11 @@ void f2fs_do_replace_block(struct f2fs_sb_info *sbi, struct f2fs_summary *sum, if (recover_curseg) { if (old_cursegno != curseg->segno) { curseg->next_segno = old_cursegno; +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + __change_curseg(sbi, curseg, type, true); +#else change_curseg(sbi, type); +#endif } curseg->next_blkoff = old_blkoff; } @@ -3429,9 +4381,13 @@ void f2fs_replace_block(struct f2fs_sb_info *sbi, struct dnode_of_data *dn, set_summary(&sum, dn->nid, dn->ofs_in_node, version); +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + f2fs_do_replace_block(sbi, &sum, old_addr, new_addr, + recover_curseg, recover_newaddr, false); +#else f2fs_do_replace_block(sbi, &sum, old_addr, new_addr, recover_curseg, recover_newaddr); - +#endif f2fs_update_data_blkaddr(dn, new_addr); } @@ -3475,10 +4431,16 @@ void f2fs_wait_on_block_writeback(struct inode *inode, block_t blkaddr) void f2fs_wait_on_block_writeback_range(struct inode *inode, block_t blkaddr, block_t len) { + struct f2fs_sb_info *sbi = F2FS_I_SB(inode); block_t i; + if (!f2fs_post_read_required(inode)) + return; + for (i = 0; i < len; i++) f2fs_wait_on_block_writeback(inode, blkaddr + i); + + invalidate_mapping_pages(META_MAPPING(sbi), blkaddr, blkaddr + len - 1); } static int read_compacted_summaries(struct f2fs_sb_info *sbi) @@ -3659,6 +4621,44 @@ static int restore_curseg_summaries(struct f2fs_sb_info *sbi) return 0; } +#ifdef CONFIG_OPLUS_FEATURE_OF2FS +void init_virtual_curseg(struct f2fs_sb_info *sbi) +{ + struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_FRAGMENT_DATA); + + sbi->atgc_enabled = test_priv_opt(sbi, NOATGC) ? false : true; + if (!sbi->atgc_enabled) + return; + + down_read(&SM_I(sbi)->curseg_lock); + + mutex_lock(&curseg->curseg_mutex); + down_write(&SIT_I(sbi)->sentry_lock); + + if (__get_ssr_segment(sbi, curseg, CURSEG_COLD_DATA, SSR, 0)) { + struct seg_entry *se; + + se = get_seg_entry(sbi, curseg->next_segno); + __change_curseg(sbi, curseg, se->type, false); + } else { + unsigned int segno; + + segno = CURSEG_I(sbi, CURSEG_COLD_DATA)->segno; + SIT_I(sbi)->s_ops->get_new_segment(sbi, &segno, false, ALLOC_LEFT); + curseg->next_segno = segno; + __reset_curseg(sbi, curseg, CURSEG_COLD_DATA, 1); + curseg->alloc_type = LFS; + } + stat_inc_seg_type(sbi, curseg); + + curseg->inited = true; + + up_write(&SIT_I(sbi)->sentry_lock); + mutex_unlock(&curseg->curseg_mutex); + + up_read(&SM_I(sbi)->curseg_lock); +} +#endif static void write_compacted_summaries(struct f2fs_sb_info *sbi, block_t blkaddr) { @@ -3935,6 +4935,9 @@ void f2fs_flush_sit_entries(struct f2fs_sb_info *sbi, struct cp_control *cpc) /* flush dirty sit entries in region of current sit set */ for_each_set_bit_from(segno, bitmap, end) { +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + struct dirty_seglist_info *dirty_i = DIRTY_I(sbi); +#endif int offset, sit_offset; se = get_seg_entry(sbi, segno); @@ -3950,6 +4953,17 @@ void f2fs_flush_sit_entries(struct f2fs_sb_info *sbi, struct cp_control *cpc) add_discard_addrs(sbi, cpc, false); } +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + /* + * force mtime to 0 for reclaiming case, then mtime + * can be updated correctly, instead of being disturbed + * by history time. + */ + mutex_lock(&dirty_i->seglist_lock); + if (test_bit(segno, dirty_i->dirty_segmap[PRE])) + se->mtime = 0; + mutex_unlock(&dirty_i->seglist_lock); +#endif if (to_journal) { offset = f2fs_lookup_journal_in_cursum(journal, SIT_JOURNAL, segno, 1); @@ -4090,8 +5104,14 @@ static int build_sit_info(struct f2fs_sb_info *sbi) #endif /* init SIT information */ +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + if (test_priv_opt(sbi, NOSUBDIVISION)) + sit_i->s_ops = &default_salloc_ops; + else + sit_i->s_ops = &subdivision_salloc_ops; +#else sit_i->s_ops = &default_salloc_ops; - +#endif sit_i->sit_base_addr = le32_to_cpu(raw_super->sit_blkaddr); sit_i->sit_blocks = sit_segs << sbi->log_blocks_per_seg; sit_i->written_valid_blocks = 0; @@ -4142,15 +5162,22 @@ static int build_curseg(struct f2fs_sb_info *sbi) { struct curseg_info *array; int i; - +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + array = f2fs_kzalloc(sbi, array_size(NR_INMEM_CURSEG_TYPE, sizeof(*array)), + GFP_KERNEL); +#else array = f2fs_kzalloc(sbi, array_size(NR_CURSEG_TYPE, sizeof(*array)), GFP_KERNEL); +#endif if (!array) return -ENOMEM; SM_I(sbi)->curseg_array = array; - +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + for (i = 0; i < NR_INMEM_CURSEG_TYPE; i++) { +#else for (i = 0; i < NR_CURSEG_TYPE; i++) { +#endif mutex_init(&array[i].curseg_mutex); array[i].sum_blk = f2fs_kzalloc(sbi, PAGE_SIZE, GFP_KERNEL); if (!array[i].sum_blk) @@ -4371,7 +5398,11 @@ static int sanity_check_curseg(struct f2fs_sb_info *sbi) * In LFS/SSR curseg, .next_blkoff should point to an unused blkaddr; * In LFS curseg, all blkaddr after .next_blkoff should be unused. */ +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + for (i = 0; i < NR_CURSEG_TYPE; i++) { +#else for (i = 0; i < NO_CHECK_TYPE; i++) { +#endif struct curseg_info *curseg = CURSEG_I(sbi, i); struct seg_entry *se = get_seg_entry(sbi, curseg->segno); unsigned int blkofs = curseg->next_blkoff; @@ -4407,7 +5438,9 @@ static void init_min_max_mtime(struct f2fs_sb_info *sbi) down_write(&sit_i->sentry_lock); sit_i->min_mtime = ULLONG_MAX; - +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + sit_i->dirty_max_mtime = 0; +#endif for (segno = 0; segno < MAIN_SEGS(sbi); segno += sbi->segs_per_sec) { unsigned int i; unsigned long long mtime = 0; @@ -4450,7 +5483,13 @@ int f2fs_build_segment_manager(struct f2fs_sb_info *sbi) sm_info->rec_prefree_segments = DEF_MAX_RECLAIM_PREFREE_SEGMENTS; if (!f2fs_lfs_mode(sbi)) +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + sm_info->ipu_policy = 1 << F2FS_IPU_FSYNC | + 1 << F2FS_IPU_ASYNC | + 1 << F2FS_IPU_SSR_UTIL; +#else sm_info->ipu_policy = 1 << F2FS_IPU_FSYNC; +#endif sm_info->min_ipu_util = DEF_MIN_IPU_UTIL; sm_info->min_fsync_blocks = DEF_MIN_FSYNC_BLOCKS; sm_info->min_seq_blocks = sbi->blocks_per_seg * sbi->segs_per_sec; @@ -4541,7 +5580,11 @@ static void destroy_curseg(struct f2fs_sb_info *sbi) if (!array) return; SM_I(sbi)->curseg_array = NULL; +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + for (i = 0; i < NR_INMEM_CURSEG_TYPE; i++) { +#else for (i = 0; i < NR_CURSEG_TYPE; i++) { +#endif kvfree(array[i].sum_blk); kvfree(array[i].journal); } diff --git a/fs/f2fs/segment.h b/fs/f2fs/segment.h index 3764165ceff5..ccd7ca352e83 100644 --- a/fs/f2fs/segment.h +++ b/fs/f2fs/segment.h @@ -22,12 +22,25 @@ #define GET_R2L_SEGNO(free_i, segno) ((segno) + (free_i)->start_segno) #define IS_DATASEG(t) ((t) <= CURSEG_COLD_DATA) +#ifdef CONFIG_OPLUS_FEATURE_OF2FS +#define IS_NODESEG(t) ((t) >= CURSEG_HOT_NODE && (t) <= CURSEG_COLD_NODE) +#else #define IS_NODESEG(t) ((t) >= CURSEG_HOT_NODE) - +#endif #define IS_HOT(t) ((t) == CURSEG_HOT_NODE || (t) == CURSEG_HOT_DATA) #define IS_WARM(t) ((t) == CURSEG_WARM_NODE || (t) == CURSEG_WARM_DATA) #define IS_COLD(t) ((t) == CURSEG_COLD_NODE || (t) == CURSEG_COLD_DATA) +#ifdef CONFIG_OPLUS_FEATURE_OF2FS +#define IS_CURSEG(sbi, seg) \ + (((seg) == CURSEG_I(sbi, CURSEG_HOT_DATA)->segno) || \ + ((seg) == CURSEG_I(sbi, CURSEG_WARM_DATA)->segno) || \ + ((seg) == CURSEG_I(sbi, CURSEG_COLD_DATA)->segno) || \ + ((seg) == CURSEG_I(sbi, CURSEG_HOT_NODE)->segno) || \ + ((seg) == CURSEG_I(sbi, CURSEG_WARM_NODE)->segno) || \ + ((seg) == CURSEG_I(sbi, CURSEG_COLD_NODE)->segno) || \ + ((seg) == CURSEG_I(sbi, CURSEG_FRAGMENT_DATA)->segno)) +#else #define IS_CURSEG(sbi, seg) \ (((seg) == CURSEG_I(sbi, CURSEG_HOT_DATA)->segno) || \ ((seg) == CURSEG_I(sbi, CURSEG_WARM_DATA)->segno) || \ @@ -35,7 +48,24 @@ ((seg) == CURSEG_I(sbi, CURSEG_HOT_NODE)->segno) || \ ((seg) == CURSEG_I(sbi, CURSEG_WARM_NODE)->segno) || \ ((seg) == CURSEG_I(sbi, CURSEG_COLD_NODE)->segno)) - +#endif +#ifdef CONFIG_OPLUS_FEATURE_OF2FS +#define IS_CURSEC(sbi, secno) \ + (((secno) == CURSEG_I(sbi, CURSEG_HOT_DATA)->segno / \ + (sbi)->segs_per_sec) || \ + ((secno) == CURSEG_I(sbi, CURSEG_WARM_DATA)->segno / \ + (sbi)->segs_per_sec) || \ + ((secno) == CURSEG_I(sbi, CURSEG_COLD_DATA)->segno / \ + (sbi)->segs_per_sec) || \ + ((secno) == CURSEG_I(sbi, CURSEG_HOT_NODE)->segno / \ + (sbi)->segs_per_sec) || \ + ((secno) == CURSEG_I(sbi, CURSEG_WARM_NODE)->segno / \ + (sbi)->segs_per_sec) || \ + ((secno) == CURSEG_I(sbi, CURSEG_COLD_NODE)->segno / \ + (sbi)->segs_per_sec) || \ + ((secno) == CURSEG_I(sbi, CURSEG_FRAGMENT_DATA)->segno / \ + (sbi)->segs_per_sec)) +#else #define IS_CURSEC(sbi, secno) \ (((secno) == CURSEG_I(sbi, CURSEG_HOT_DATA)->segno / \ (sbi)->segs_per_sec) || \ @@ -48,7 +78,8 @@ ((secno) == CURSEG_I(sbi, CURSEG_WARM_NODE)->segno / \ (sbi)->segs_per_sec) || \ ((secno) == CURSEG_I(sbi, CURSEG_COLD_NODE)->segno / \ - (sbi)->segs_per_sec)) \ + (sbi)->segs_per_sec)) +#endif #define MAIN_BLKADDR(sbi) \ (SM_I(sbi) ? SM_I(sbi)->main_blkaddr : \ @@ -118,6 +149,20 @@ #define SECTOR_TO_BLOCK(sectors) \ ((sectors) >> F2FS_LOG_SECTORS_PER_BLOCK) +#ifdef CONFIG_F2FS_GRADING_SSR +#define KBS_PER_SEGMENT 2048 +#endif +#ifdef CONFIG_OPLUS_FEATURE_OF2FS +#define SSR_CONTIG_DIRTY_NUMS 32 /*Dirty pages for LFS alloction in grading ssr . */ +#define SSR_CONTIG_LARGE 256 /*Larege files */ + +enum { + SEQ_NONE, + SEQ_32BLKS, + SEQ_256BLKS +}; +#endif + /* * indicate a block allocation direction: RIGHT and LEFT. * RIGHT means allocating new sections towards the end of volume. @@ -125,7 +170,10 @@ */ enum { ALLOC_RIGHT = 0, - ALLOC_LEFT + ALLOC_LEFT, +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + ALLOC_SPREAD, /* for subdivision allocation only */ +#endif }; /* @@ -135,7 +183,10 @@ enum { */ enum { LFS = 0, - SSR + SSR, +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + ASSR, /*ASSR (Age based Slack Space Recycle) merges fragments into fragmented segment which has similar aging degree.*/ +#endif }; /* @@ -146,6 +197,9 @@ enum { enum { GC_CB = 0, GC_GREEDY, +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + GC_AT, /*GC_AT is based on age-threshold algorithm.*/ +#endif ALLOC_NEXT, FLUSH_DEVICE, MAX_GC_POLICY, @@ -161,7 +215,12 @@ enum { FG_GC, FORCE_FG_GC, }; - +#ifdef CONFIG_F2FS_GRADING_SSR +enum { + GRADING_SSR_OFF = 0, + GRADING_SSR_ON +}; +#endif /* for a function parameter to select a victim segment */ struct victim_sel_policy { int alloc_mode; /* LFS or SSR */ @@ -171,7 +230,14 @@ struct victim_sel_policy { unsigned int offset; /* last scanned bitmap offset */ unsigned int ofs_unit; /* bitmap search unit */ unsigned int min_cost; /* minimum cost */ +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + unsigned long long oldest_age; /* oldest age of segments having the same min cost */ +#endif unsigned int min_segno; /* segment # having min. cost */ +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + unsigned long long age; /* mtime of GCed section*/ + unsigned long long age_threshold;/* age threshold */ +#endif }; struct seg_entry { @@ -197,7 +263,15 @@ struct sec_entry { }; struct segment_allocation { +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + void (*allocate_segment)(struct f2fs_sb_info *, int, bool, int); + void (*get_new_segment)(struct f2fs_sb_info *, + unsigned int *, bool , int); + void (*new_curseg)(struct f2fs_sb_info *, int, bool); + void (*__new_curseg)(struct f2fs_sb_info *, struct curseg_info *,int, bool); +#else void (*allocate_segment)(struct f2fs_sb_info *, int, bool); +#endif }; #define MAX_SKIP_GC_COUNT 16 @@ -236,8 +310,13 @@ struct sit_info { unsigned long long elapsed_time; /* elapsed time after mount */ unsigned long long mounted_time; /* mount time */ unsigned long long min_mtime; /* min. modification time */ +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + unsigned long long dirty_min_mtime; /* rerange candidates in GC_AT */ +#endif unsigned long long max_mtime; /* max. modification time */ - +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + unsigned long long dirty_max_mtime; /* rerange candidates in GC_AT */ +#endif unsigned int last_victim[MAX_GC_POLICY]; /* last victim segment # */ }; @@ -273,8 +352,13 @@ struct dirty_seglist_info { /* victim selection function for cleaning and SSR */ struct victim_selection { - int (*get_victim)(struct f2fs_sb_info *, unsigned int *, +#ifdef CONFIG_OPLUS_FEATURE_OF2FS +int (*get_victim)(struct f2fs_sb_info *, unsigned int *, + int, int, char, unsigned long long); +#else +int (*get_victim)(struct f2fs_sb_info *, unsigned int *, int, int, char); +#endif }; /* for active log information */ @@ -288,6 +372,10 @@ struct curseg_info { unsigned short next_blkoff; /* next block offset to write */ unsigned int zone; /* current zone number */ unsigned int next_segno; /* preallocated segment */ +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + bool inited; /* indicate inmem log is inited */ + char type; +#endif }; struct sit_entry_set { @@ -621,7 +709,14 @@ static inline int utilization(struct f2fs_sb_info *sbi) * F2FS_IPUT_DISABLE - disable IPU. (=default option in LFS mode) */ #define DEF_MIN_IPU_UTIL 70 +#ifdef CONFIG_OPLUS_FEATURE_OF2FS +/* + * 2019/08/12, enlarge min_fsync_blocks to optimize performance + */ +#define DEF_MIN_FSYNC_BLOCKS 20 +#else #define DEF_MIN_FSYNC_BLOCKS 8 +#endif #define DEF_MIN_HOT_BLOCKS 16 #define SMALL_VOLUME_SEGMENTS (16 * 512) /* 16GB */ @@ -874,3 +969,29 @@ wake_up: dcc->discard_wake = 1; wake_up_interruptible_all(&dcc->discard_wait_queue); } +#ifdef CONFIG_OPLUS_FEATURE_OF2FS +/* +* 2020-1-14, add for oDiscard decoupling +*/ +static inline void wake_up_discard_thread_aggressive(struct f2fs_sb_info *sbi, + int policy) +{ + struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info; + + if (!sbi->dc_opt_enable) + return; + + dcc->discard_wake = policy; + wake_up_interruptible_all(&dcc->discard_wait_queue); +} + +static inline int check_io_seq(int blks) +{ + if (blks >= SSR_CONTIG_LARGE) + return SEQ_256BLKS; + else if (blks >= SSR_CONTIG_DIRTY_NUMS) + return SEQ_32BLKS; + else + return SEQ_NONE; +} +#endif diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index 1ddf626bfccc..3688162e9ed6 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -34,7 +34,18 @@ #define CREATE_TRACE_POINTS #include - +#ifdef CONFIG_F2FS_GRADING_SSR +#define SSR_DEFALT_SPACE_LIMIT (5<<20) /* 5G default space limit */ +#define SSR_DEFALT_WATERLINE 80 /* 80% default waterline */ +#define SSR_HN_SAPCE_LIMIT_128G (8<<20) /* 8G default sapce limit for 128G devices */ +#define SSR_HN_WATERLINE_128G 80 /* 80% default hot node waterline for 128G devices */ +#define SSR_WN_SAPCE_LIMIT_128G (5<<20) /* 5G default warm node sapce limit for 128G devices */ +#define SSR_WN_WATERLINE_128G 70 /* 70% default warm node waterline for 128G devices */ +#define SSR_HD_SAPCE_LIMIT_128G (8<<20) /* 8G default hot data sapce limit for 128G devices */ +#define SSR_HD_WATERLINE_128G 65 /* 65% default hot data waterline for 128G devices */ +#define SSR_WD_SAPCE_LIMIT_128G (5<<20) /* 5G default warm data sapce limit for 128G devices */ +#define SSR_WD_WATERLINE_128G 60 /* 60% default warm data waterline for 128G devices */ +#endif static struct kmem_cache *f2fs_inode_cachep; #ifdef CONFIG_F2FS_FAULT_INJECTION @@ -145,6 +156,10 @@ enum { Opt_compress_algorithm, Opt_compress_log_size, Opt_compress_extension, +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + Opt_noatgc, + Opt_nosubdivision, +#endif Opt_err, }; @@ -212,6 +227,10 @@ static match_table_t f2fs_tokens = { {Opt_compress_algorithm, "compress_algorithm=%s"}, {Opt_compress_log_size, "compress_log_size=%u"}, {Opt_compress_extension, "compress_extension=%s"}, +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + {Opt_noatgc, "noatgc"}, + {Opt_nosubdivision, "nosubdivision"}, +#endif {Opt_err, NULL}, }; @@ -861,6 +880,14 @@ static int parse_options(struct super_block *sb, char *options, bool is_remount) case Opt_checkpoint_enable: clear_opt(sbi, DISABLE_CHECKPOINT); break; +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + case Opt_noatgc: + set_priv_opt(sbi, NOATGC); + break; + case Opt_nosubdivision: + set_priv_opt(sbi, NOSUBDIVISION); + break; +#endif case Opt_compress_algorithm: if (!f2fs_sb_has_compression(sbi)) { f2fs_err(sbi, "Compression feature if off"); @@ -1188,9 +1215,11 @@ static void f2fs_put_super(struct super_block *sb) /* unregister procfs/sysfs entries in advance to avoid race case */ f2fs_unregister_sysfs(sbi); - f2fs_quota_off_umount(sb); +#ifdef CONFIG_F2FS_BD_STAT + f2fs_destroy_bd_stat(sbi); +#endif /* prevent remaining shrinker jobs */ mutex_lock(&sbi->umount_mutex); @@ -1583,6 +1612,12 @@ static int f2fs_show_options(struct seq_file *seq, struct dentry *root) F2FS_OPTION(sbi).fault_info.inject_type); } #endif +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + if (test_priv_opt(sbi, NOATGC)) + seq_puts(seq, ",noatgc"); + if (test_priv_opt(sbi, NOSUBDIVISION)) + seq_puts(seq, ",nosubdivision"); +#endif #ifdef CONFIG_QUOTA if (test_opt(sbi, QUOTA)) seq_puts(seq, ",quota"); @@ -1649,9 +1684,17 @@ static void default_options(struct f2fs_sb_info *sbi) set_opt(sbi, EXTENT_CACHE); set_opt(sbi, NOHEAP); clear_opt(sbi, DISABLE_CHECKPOINT); +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + set_priv_opt(sbi, NOATGC); +#endif F2FS_OPTION(sbi).unusable_cap = 0; sbi->sb->s_flags |= SB_LAZYTIME; - set_opt(sbi, FLUSH_MERGE); +#ifndef CONFIG_OPLUS_FEATURE_OF2FS + /* + * 2019/08/15, no need to flush_merge as we have reduced most flushes + */ + set_opt(sbi, FLUSH_MERGE); +#endif set_opt(sbi, DISCARD); if (f2fs_sb_has_blkzoned(sbi)) F2FS_OPTION(sbi).fs_mode = FS_MODE_LFS; @@ -2707,6 +2750,11 @@ static inline bool sanity_check_area_boundary(struct f2fs_sb_info *sbi, } else { err = __f2fs_commit_super(bh, NULL); res = err ? "failed" : "done"; +#ifdef CONFIG_F2FS_BD_STAT + bd_lock(sbi); + bd_inc_array_val(sbi, hotcold_count, HC_META_SB, 1); + bd_unlock(sbi); +#endif } f2fs_info(sbi, "Fix alignment : %s, start(%u) end(%u) block(%u)", res, main_blkaddr, @@ -3057,6 +3105,9 @@ static void init_sb_info(struct f2fs_sb_info *sbi) sbi->migration_granularity = sbi->segs_per_sec; sbi->dir_level = DEF_DIR_LEVEL; +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + sbi->readdir_ra = 0; +#endif sbi->interval_time[CP_TIME] = DEF_CP_INTERVAL; sbi->interval_time[REQ_TIME] = DEF_IDLE_INTERVAL; sbi->interval_time[DISCARD_TIME] = DEF_IDLE_INTERVAL; @@ -3253,6 +3304,11 @@ int f2fs_commit_super(struct f2fs_sb_info *sbi, bool recover) if (!bh) return -EIO; err = __f2fs_commit_super(bh, F2FS_RAW_SUPER(sbi)); +#ifdef CONFIG_F2FS_BD_STAT + bd_lock(sbi); + bd_inc_array_val(sbi, hotcold_count, HC_META_SB, 1); + bd_unlock(sbi); +#endif brelse(bh); /* if we are in recovery path, skip writing valid superblock */ @@ -3264,6 +3320,11 @@ int f2fs_commit_super(struct f2fs_sb_info *sbi, bool recover) if (!bh) return -EIO; err = __f2fs_commit_super(bh, F2FS_RAW_SUPER(sbi)); +#ifdef CONFIG_F2FS_BD_STAT + bd_lock(sbi); + bd_inc_array_val(sbi, hotcold_count, HC_META_SB, 1); + bd_unlock(sbi); +#endif brelse(bh); return err; } @@ -3414,6 +3475,35 @@ static void f2fs_tuning_parameters(struct f2fs_sb_info *sbi) sbi->readdir_ra = 1; } +#ifdef CONFIG_F2FS_GRADING_SSR +static int f2fs_init_grading_ssr(struct f2fs_sb_info *sbi) +{ + u32 total_blocks = sbi->raw_super->block_count>>18; + if (total_blocks > 64) { /* 64G */ + sbi->hot_cold_params.hot_data_lower_limit = SSR_HD_SAPCE_LIMIT_128G; + sbi->hot_cold_params.hot_data_waterline = SSR_HD_WATERLINE_128G; + sbi->hot_cold_params.warm_data_lower_limit = SSR_WD_SAPCE_LIMIT_128G; + sbi->hot_cold_params.warm_data_waterline = SSR_WD_WATERLINE_128G; + sbi->hot_cold_params.hot_node_lower_limit = SSR_HD_SAPCE_LIMIT_128G; + sbi->hot_cold_params.hot_node_waterline = SSR_HN_WATERLINE_128G; + sbi->hot_cold_params.warm_node_lower_limit = SSR_WN_SAPCE_LIMIT_128G; + sbi->hot_cold_params.warm_node_waterline = SSR_WN_WATERLINE_128G; + sbi->hot_cold_params.enable = GRADING_SSR_OFF; + } else { + sbi->hot_cold_params.hot_data_lower_limit = SSR_DEFALT_SPACE_LIMIT; + sbi->hot_cold_params.hot_data_waterline = SSR_DEFALT_WATERLINE; + sbi->hot_cold_params.warm_data_lower_limit = SSR_DEFALT_SPACE_LIMIT; + sbi->hot_cold_params.warm_data_waterline = SSR_DEFALT_WATERLINE; + sbi->hot_cold_params.hot_node_lower_limit = SSR_DEFALT_SPACE_LIMIT; + sbi->hot_cold_params.hot_node_waterline = SSR_DEFALT_WATERLINE; + sbi->hot_cold_params.warm_node_lower_limit = SSR_DEFALT_SPACE_LIMIT; + sbi->hot_cold_params.warm_node_waterline = SSR_DEFALT_WATERLINE; + sbi->hot_cold_params.enable = GRADING_SSR_OFF; + } + return 0; +} +#endif + static int f2fs_fill_super(struct super_block *sb, void *data, int silent) { struct f2fs_sb_info *sbi; @@ -3436,7 +3526,15 @@ try_onemore: sbi = kzalloc(sizeof(struct f2fs_sb_info), GFP_KERNEL); if (!sbi) return -ENOMEM; - +#ifdef CONFIG_F2FS_BD_STAT + sbi->bd_info = kzalloc(sizeof(struct f2fs_bigdata_info), GFP_KERNEL); + if (!sbi->bd_info) { + err = -ENOMEM; + goto free_sbi; + } + sbi->bd_info->ssr_last_jiffies = jiffies; + bd_lock_init(sbi); +#endif sbi->sb = sb; /* Load the checksum driver */ @@ -3540,7 +3638,14 @@ try_onemore: /* disallow all the data/node/meta page writes */ set_sbi_flag(sbi, SBI_POR_DOING); spin_lock_init(&sbi->stat_lock); - +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + /* + * 2020-1-14, add for oDiscard decoupling + */ + sbi->dc_opt_enable = true; + sbi->dpolicy_expect = DPOLICY_BG; + sbi->fsync_protect = false; +#endif /* init iostat info */ spin_lock_init(&sbi->iostat_lock); sbi->iostat_enable = false; @@ -3715,7 +3820,9 @@ try_onemore: err = -ENOMEM; goto free_node_inode; } - +#ifdef CONFIG_F2FS_GRADING_SSR + f2fs_init_grading_ssr(sbi); +#endif err = f2fs_register_sysfs(sbi); if (err) goto free_root_inode; @@ -3778,6 +3885,9 @@ try_onemore: } } reset_checkpoint: +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + init_virtual_curseg(sbi); +#endif /* f2fs_recover_fsync_data() cleared this already */ clear_sbi_flag(sbi, SBI_POR_DOING); @@ -3839,6 +3949,9 @@ free_meta: truncate_inode_pages_final(META_MAPPING(sbi)); /* evict some inodes being cached by GC */ evict_inodes(sb); +#ifdef CONFIG_F2FS_BD_STAT + f2fs_destroy_bd_stat(sbi); +#endif f2fs_unregister_sysfs(sbi); free_root_inode: dput(sb->s_root); @@ -3986,9 +4099,18 @@ static int __init init_f2fs_fs(void) err = f2fs_init_sysfs(); if (err) goto free_extent_cache; +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + err = create_garbage_collection_cache(); + if (err) + goto free_sysfs; + err = register_shrinker(&f2fs_shrinker_info); + if (err) + goto free_garbage_collection_cache; +#else err = register_shrinker(&f2fs_shrinker_info); if (err) goto free_sysfs; +#endif err = register_filesystem(&f2fs_fs_type); if (err) goto free_shrinker; @@ -4017,6 +4139,10 @@ free_root_stats: unregister_filesystem(&f2fs_fs_type); free_shrinker: unregister_shrinker(&f2fs_shrinker_info); +#ifdef CONFIG_OPLUS_FEATURE_OF2FS +free_garbage_collection_cache: + destroy_garbage_collection_cache(); +#endif free_sysfs: f2fs_exit_sysfs(); free_extent_cache: @@ -4043,6 +4169,9 @@ static void __exit exit_f2fs_fs(void) unregister_filesystem(&f2fs_fs_type); unregister_shrinker(&f2fs_shrinker_info); f2fs_exit_sysfs(); +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + destroy_garbage_collection_cache(); +#endif f2fs_destroy_extent_cache(); f2fs_destroy_checkpoint_caches(); f2fs_destroy_segment_manager_caches(); diff --git a/fs/f2fs/sysfs.c b/fs/f2fs/sysfs.c index d90bf4cb6333..283d1d66ccac 100644 --- a/fs/f2fs/sysfs.c +++ b/fs/f2fs/sysfs.c @@ -34,6 +34,9 @@ enum { FAULT_INFO_TYPE, /* struct f2fs_fault_info */ #endif RESERVED_BLOCKS, /* struct f2fs_sb_info */ +#ifdef CONFIG_F2FS_GRADING_SSR + F2FS_HOT_COLD_PARAMS, +#endif }; struct f2fs_attr { @@ -61,6 +64,10 @@ static unsigned char *__struct_ptr(struct f2fs_sb_info *sbi, int struct_type) return (unsigned char *)NM_I(sbi); else if (struct_type == F2FS_SBI || struct_type == RESERVED_BLOCKS) return (unsigned char *)sbi; +#ifdef CONFIG_F2FS_GRADING_SSR + else if (struct_type == F2FS_HOT_COLD_PARAMS) + return (unsigned char*)&sbi->hot_cold_params; +#endif #ifdef CONFIG_F2FS_FAULT_INJECTION else if (struct_type == FAULT_INFO_RATE || struct_type == FAULT_INFO_TYPE) @@ -370,6 +377,10 @@ out: sbi->gc_mode = GC_IDLE_CB; else if (t == GC_IDLE_GREEDY) sbi->gc_mode = GC_IDLE_GREEDY; +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + else if (t == GC_IDLE_AT) + sbi->gc_mode = GC_IDLE_AT; +#endif else sbi->gc_mode = GC_NORMAL; return count; @@ -390,7 +401,34 @@ out: spin_unlock(&sbi->iostat_lock); return count; } +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + /* + * 2020-1-14, add for oDiscard decoupling + */ + if (!strcmp(a->attr.name, "fsync_protect")) { + sbi->fsync_protect = !!t; + return count; + } + if (!strcmp(a->attr.name, "dpolicy_expect")) { + if (!sbi->dc_opt_enable) + return count; + + if (t == DPOLICY_BG) + sbi->dpolicy_expect = DPOLICY_BG; + else if (t == DPOLICY_BALANCE) { + sbi->dpolicy_expect= DPOLICY_BALANCE; + wake_up_discard_thread_aggressive(sbi, + DPOLICY_BALANCE); + } + else if (t == DPOLICY_PERFORMANCE) { + sbi->dpolicy_expect= DPOLICY_PERFORMANCE; + wake_up_discard_thread_aggressive(sbi, + DPOLICY_PERFORMANCE); + } + return count; + } +#endif *ui = (unsigned int)t; return count; @@ -525,6 +563,10 @@ F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, gc_idle, gc_mode); F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, gc_urgent, gc_mode); F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, reclaim_segments, rec_prefree_segments); F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, main_blkaddr, main_blkaddr); +#ifdef CONFIG_OPLUS_FEATURE_OF2FS +F2FS_RW_ATTR(GC_THREAD, f2fs_gc_kthread, gc_age_threshold, age_threshold); +F2FS_RW_ATTR(GC_THREAD, f2fs_gc_kthread, gc_dirty_rate_threshold, dirty_rate_threshold); +#endif F2FS_RW_ATTR(DCC_INFO, discard_cmd_control, max_small_discards, max_discards); F2FS_RW_ATTR(DCC_INFO, discard_cmd_control, discard_granularity, discard_granularity); F2FS_RW_ATTR(RESERVED_BLOCKS, f2fs_sb_info, reserved_blocks, reserved_blocks); @@ -553,6 +595,27 @@ F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, iostat_period_ms, iostat_period_ms); F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, readdir_ra, readdir_ra); F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, gc_pin_file_thresh, gc_pin_file_threshold); F2FS_RW_ATTR(F2FS_SBI, f2fs_super_block, extension_list, extension_list); +#ifdef CONFIG_OPLUS_FEATURE_OF2FS +/* + * 2020-1-14, add for oDiscard decoupling + */ +F2FS_ATTR_OFFSET(F2FS_SBI, fsync_protect, 0666, f2fs_sbi_show, f2fs_sbi_store, + offsetof(struct f2fs_sb_info, fsync_protect)); +F2FS_ATTR_OFFSET(F2FS_SBI, dpolicy_expect, 0666, f2fs_sbi_show, f2fs_sbi_store, + offsetof(struct f2fs_sb_info, dpolicy_expect)); +#endif +#ifdef CONFIG_F2FS_GRADING_SSR +F2FS_RW_ATTR(F2FS_HOT_COLD_PARAMS, f2fs_hot_cold_params, hc_hot_data_lower_limit, hot_data_lower_limit); +F2FS_RW_ATTR(F2FS_HOT_COLD_PARAMS, f2fs_hot_cold_params, hc_hot_data_waterline, hot_data_waterline); +F2FS_RW_ATTR(F2FS_HOT_COLD_PARAMS, f2fs_hot_cold_params, hc_warm_data_lower_limit, warm_data_lower_limit); +F2FS_RW_ATTR(F2FS_HOT_COLD_PARAMS, f2fs_hot_cold_params, hc_warm_data_waterline, warm_data_waterline); +F2FS_RW_ATTR(F2FS_HOT_COLD_PARAMS, f2fs_hot_cold_params, hc_hot_node_lower_limit, hot_node_lower_limit); +F2FS_RW_ATTR(F2FS_HOT_COLD_PARAMS, f2fs_hot_cold_params, hc_hot_node_waterline, hot_node_waterline); +F2FS_RW_ATTR(F2FS_HOT_COLD_PARAMS, f2fs_hot_cold_params, hc_warm_node_lower_limit, warm_node_lower_limit); +F2FS_RW_ATTR(F2FS_HOT_COLD_PARAMS, f2fs_hot_cold_params, hc_warm_node_waterline, warm_node_waterline); +F2FS_RW_ATTR(F2FS_HOT_COLD_PARAMS, f2fs_hot_cold_params, hc_enable, enable); +#endif + #ifdef CONFIG_F2FS_FAULT_INJECTION F2FS_RW_ATTR(FAULT_INFO_RATE, f2fs_fault_info, inject_rate, inject_rate); F2FS_RW_ATTR(FAULT_INFO_TYPE, f2fs_fault_info, inject_type, inject_type); @@ -609,6 +672,10 @@ static struct attribute *f2fs_attrs[] = { ATTR_LIST(gc_no_gc_sleep_time), ATTR_LIST(gc_idle), ATTR_LIST(gc_urgent), +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + ATTR_LIST(gc_age_threshold), + ATTR_LIST(gc_dirty_rate_threshold), +#endif ATTR_LIST(reclaim_segments), ATTR_LIST(main_blkaddr), ATTR_LIST(max_small_discards), @@ -636,6 +703,25 @@ static struct attribute *f2fs_attrs[] = { ATTR_LIST(readdir_ra), ATTR_LIST(gc_pin_file_thresh), ATTR_LIST(extension_list), +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + /* + * 2020-1-14, add for oDiscard decoupling + */ + ATTR_LIST(fsync_protect), + ATTR_LIST(dpolicy_expect), +#endif +#ifdef CONFIG_F2FS_GRADING_SSR + ATTR_LIST(hc_hot_data_lower_limit), + ATTR_LIST(hc_hot_data_waterline), + ATTR_LIST(hc_warm_data_lower_limit), + ATTR_LIST(hc_warm_data_waterline), + ATTR_LIST(hc_hot_node_lower_limit), + ATTR_LIST(hc_hot_node_waterline), + ATTR_LIST(hc_warm_node_lower_limit), + ATTR_LIST(hc_warm_node_waterline), + ATTR_LIST(hc_enable), +#endif + #ifdef CONFIG_F2FS_FAULT_INJECTION ATTR_LIST(inject_rate), ATTR_LIST(inject_type), @@ -885,7 +971,223 @@ static int __maybe_unused victim_bits_seq_show(struct seq_file *seq, } return 0; } +#ifdef CONFIG_OPLUS_FEATURE_OF2FS +/* + * 2019/09/11, add f2fs frag_score and undiscard_score + */ +extern block_t of2fs_seg_freefrag(struct f2fs_sb_info *sbi, + unsigned int segno, block_t* blocks, unsigned int n); +static int frag_score_seq_show(struct seq_file *seq, void *offset) +{ + struct super_block *sb = seq->private; + struct f2fs_sb_info *sbi = F2FS_SB(sb); + unsigned int i, total_segs = + le32_to_cpu(sbi->raw_super->segment_count_main); + block_t blocks[9], total_blocks = 0; + unsigned int score; + memset(blocks, 0, sizeof(blocks)); + for (i = 0; i < total_segs; i++) { + total_blocks += of2fs_seg_freefrag(sbi, i, + blocks, ARRAY_SIZE(blocks)); + cond_resched(); + } + + f2fs_info(sbi, "Extent Size Range: Free Blocks"); + for (i = 0; i < ARRAY_SIZE(blocks); i++) { + if (!blocks[i]) + continue; + else if (i < 8) + f2fs_info(sbi, "%dK...%dK-: %u", 4<private; + struct f2fs_sb_info *sbi = F2FS_SB(sb); + unsigned int i, total_segs = + le32_to_cpu(sbi->raw_super->segment_count_main); + block_t blocks[10], total_blocks = 0; + memset(blocks, 0, sizeof(blocks)); + for (i = 0; i < total_segs; i++) { + total_blocks += of2fs_seg_freefrag(sbi, i, + blocks, ARRAY_SIZE(blocks)); + cond_resched(); + } + + blocks[9] = free_segments(sbi) * (1<<(sbi)->log_blocks_per_seg); + total_blocks += blocks[9]; + + for (i = 0; i < ARRAY_SIZE(blocks); i++) { + if (!blocks[i]) + continue; + else if (i < 8) + seq_printf(seq, "%dKto%dK:%u\n", 4<private; + struct f2fs_sb_info *sbi = F2FS_SB(sb); + unsigned int undiscard_blks = 0; + unsigned int free_blks = sbi->user_block_count - valid_user_blocks(sbi); + unsigned int score; + if (SM_I(sbi) && SM_I(sbi)->dcc_info) + undiscard_blks = SM_I(sbi)->dcc_info->undiscard_blks; + score = free_blks ? undiscard_blks * 100ULL / free_blks : 0; + seq_printf(seq, "%u\n", score < 100 ? score : 100); + return 0; +} + +static int undiscard_score_open(struct inode *inode, struct file *file) +{ + return single_open(file, undiscard_score_seq_show, PDE_DATA(inode)); +} + +static const struct file_operations f2fs_seq_undiscard_score_fops = { + .open = undiscard_score_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int gc_opt_enable_seq_show(struct seq_file *seq, void *p) +{ + struct super_block *sb = seq->private; + struct f2fs_sb_info *sbi = F2FS_SB(sb); + seq_printf(seq, "%d\n", sbi->gc_opt_enable); + return 0; +} + +static ssize_t gc_opt_enable_write(struct file *filp, const char __user *ubuf, + size_t cnt, loff_t *ppos) +{ + char buf[8] = { 0 }; + ssize_t buf_size; + struct seq_file *seq = filp->private_data; + struct super_block *sb = seq->private; + struct f2fs_sb_info *sbi = F2FS_SB(sb); + + if (!cnt) { + return 0; + } + + buf_size = min(cnt, (size_t)(sizeof(buf)-1)); + if (copy_from_user(buf, ubuf, buf_size)) { + return -EFAULT; + } + buf[buf_size-1] = 0; + + if (buf[0] == '0') { + sbi->gc_opt_enable = false; + sbi->interval_time[GC_TIME] = DEF_IDLE_INTERVAL; + } else { + sbi->gc_opt_enable = true; + sbi->interval_time[GC_TIME] = DEF_GC_IDLE_INTERVAL; + } + + return cnt; +} + +static int gc_opt_enable_open(struct inode *inode, struct file *file) +{ + return single_open(file, gc_opt_enable_seq_show, PDE_DATA(inode)); +} + +static const struct file_operations f2fs_seq_gc_opt_enable_fops = { + .open = gc_opt_enable_open, + .read = seq_read, + .write = gc_opt_enable_write, + .llseek = seq_lseek, + .release = single_release, +}; + +/* + * 2019-08-14, add for oDiscard + */ +static int f2fs_dc_opt_enable_seq_show(struct seq_file *seq, void *p) +{ + struct super_block *sb = seq->private; + struct f2fs_sb_info *sbi = F2FS_SB(sb); + seq_printf(seq, "%d\n", sbi->dc_opt_enable); + return 0; +} + +static ssize_t f2fs_dc_opt_enable_write(struct file *filp, const char __user *ubuf, + size_t cnt, loff_t *ppos) +{ + char buf[8] = { 0 }; + ssize_t buf_size; + struct seq_file *seq = filp->private_data; + struct super_block *sb = seq->private; + struct f2fs_sb_info *sbi = F2FS_SB(sb); + + if (!cnt) { + return 0; + } + + buf_size = min(cnt, (size_t)(sizeof(buf)-1)); + if (copy_from_user(buf, ubuf, buf_size)) { + return -EFAULT; + } + buf[buf_size-1] = 0; + + if (buf[0] == '0') { + sbi->dc_opt_enable = false; + sbi->dpolicy_expect = DPOLICY_BG; + } else + sbi->dc_opt_enable = true; + + return cnt; +} +static int f2fs_dc_opt_enable_open(struct inode *inode, struct file *file) +{ + return single_open(file, f2fs_dc_opt_enable_seq_show, PDE_DATA(inode)); +} + +static const struct file_operations f2fs_dc_opt_enable_fops = { + .open = f2fs_dc_opt_enable_open, + .read = seq_read, + .write = f2fs_dc_opt_enable_write, + .llseek = seq_lseek, + .release = single_release, +}; +#endif int __init f2fs_init_sysfs(void) { int ret; @@ -942,6 +1244,27 @@ int f2fs_register_sysfs(struct f2fs_sb_info *sbi) iostat_info_seq_show, sb); proc_create_single_data("victim_bits", S_IRUGO, sbi->s_proc, victim_bits_seq_show, sb); +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + /* + * 2019/09/11, add f2fs frag_score and undiscard_score + */ + proc_create_data("frag_score", S_IRUGO, sbi->s_proc, + &f2fs_seq_frag_score_fops, sb); + proc_create_data("free_frag", S_IRUGO, sbi->s_proc, + &f2fs_seq_free_frag_score_fops, sb); + proc_create_data("undiscard_score", S_IRUGO, sbi->s_proc, + &f2fs_seq_undiscard_score_fops, sb); + proc_create_data("gc_opt_enable", S_IRUGO | S_IWUGO, sbi->s_proc, + &f2fs_seq_gc_opt_enable_fops, sb); + /* + * 2019-08-14, add for oDiscard + */ + proc_create_data("dc_enable", S_IRUGO | S_IWUGO, sbi->s_proc, + &f2fs_dc_opt_enable_fops, sb); +#endif +#ifdef CONFIG_F2FS_BD_STAT + f2fs_build_bd_stat(sbi); +#endif } return 0; } @@ -949,10 +1272,31 @@ int f2fs_register_sysfs(struct f2fs_sb_info *sbi) void f2fs_unregister_sysfs(struct f2fs_sb_info *sbi) { if (sbi->s_proc) { +#ifdef CONFIG_F2FS_BD_STAT + remove_proc_entry("base_info", sbi->s_proc); + remove_proc_entry("discard_info", sbi->s_proc); + remove_proc_entry("cp_info", sbi->s_proc); + remove_proc_entry("gc_info", sbi->s_proc); + remove_proc_entry("fsync_info", sbi->s_proc); + remove_proc_entry("hotcold_info", sbi->s_proc); +#endif remove_proc_entry("iostat_info", sbi->s_proc); remove_proc_entry("segment_info", sbi->s_proc); remove_proc_entry("segment_bits", sbi->s_proc); remove_proc_entry("victim_bits", sbi->s_proc); +#ifdef CONFIG_OPLUS_FEATURE_OF2FS + /* + * 2019/09/11, add f2fs frag_score and undiscard_score + */ + remove_proc_entry("gc_opt_enable", sbi->s_proc); + remove_proc_entry("undiscard_score", sbi->s_proc); + remove_proc_entry("frag_score", sbi->s_proc); + remove_proc_entry("free_frag", sbi->s_proc); + /* + * 2019-08-14, add for oDiscard + */ + remove_proc_entry("dc_enable", sbi->s_proc); +#endif remove_proc_entry(sbi->sb->s_id, f2fs_proc_root); } kobject_del(&sbi->s_kobj); diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c index 4d687e2e2373..3920d7e4ddc3 100644 --- a/fs/fs-writeback.c +++ b/fs/fs-writeback.c @@ -29,6 +29,9 @@ #include #include #include "internal.h" +#if defined(OPLUS_FEATURE_IOMONITOR) && defined(CONFIG_IOMONITOR) +#include +#endif /*OPLUS_FEATURE_IOMONITOR*/ /* * 4MB minimal write chunk size @@ -2019,7 +2022,9 @@ void wb_workfn(struct work_struct *work) WB_REASON_FORKER_THREAD); trace_writeback_pages_written(pages_written); } - +#if defined(OPLUS_FEATURE_IOMONITOR) && defined(CONFIG_IOMONITOR) + iomonitor_update_fs_stats(FS_DIRTY_PAGES, pages_written); +#endif /*OPLUS_FEATURE_IOMONITOR*/ if (!list_empty(&wb->work_list)) wb_wakeup(wb); else if (wb_has_dirty_io(wb) && dirty_writeback_interval) diff --git a/fs/fuse/Kconfig b/fs/fuse/Kconfig index 76f09ce7e5b2..8d6ed0905837 100644 --- a/fs/fuse/Kconfig +++ b/fs/fuse/Kconfig @@ -26,3 +26,4 @@ config CUSE If you want to develop or use a userspace character device based on CUSE, answer Y or M. + diff --git a/fs/fuse/Makefile b/fs/fuse/Makefile index 60da84a86dab..199bcfa9076d 100644 --- a/fs/fuse/Makefile +++ b/fs/fuse/Makefile @@ -6,3 +6,5 @@ obj-$(CONFIG_FUSE_FS) += fuse.o obj-$(CONFIG_CUSE) += cuse.o fuse-objs := dev.o dir.o file.o inode.o control.o xattr.o acl.o +fuse-objs += passthrough.o + diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c index 34fc2e845db1..10a93b325da9 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c @@ -333,10 +333,12 @@ static void queue_request(struct fuse_iqueue *fiq, struct fuse_req *req, req->in.h.len = sizeof(struct fuse_in_header) + len_args(req->in.numargs, (struct fuse_arg *) req->in.args); list_add_tail(&req->list, &fiq->pending); + if (sync) wake_up_sync(&fiq->waitq); else wake_up(&fiq->waitq); + kill_fasync(&fiq->fasync, SIGIO, POLL_IN); } @@ -423,7 +425,7 @@ static void request_end(struct fuse_conn *fc, struct fuse_req *req) flush_bg_queue(fc); spin_unlock(&fc->lock); } - wake_up(&req->waitq); + wake_up_sync(&req->waitq); if (req->end) req->end(fc, req); put_request: @@ -844,7 +846,8 @@ static int fuse_check_page(struct page *page) 1 << PG_lru | 1 << PG_active | 1 << PG_reclaim | - 1 << PG_waiters))) { + 1 << PG_waiters | + LRU_GEN_MASK | LRU_REFS_MASK))) { printk(KERN_WARNING "fuse: trying to steal weird page\n"); printk(KERN_WARNING " page=%p index=%li flags=%08lx, count=%i, mapcount=%i, mapping=%p\n", page, page->index, page->flags, page_count(page), page_mapcount(page), page->mapping); return 1; @@ -1047,20 +1050,25 @@ static int fuse_copy_pages(struct fuse_copy_state *cs, unsigned nbytes, { unsigned i; struct fuse_req *req = cs->req; + int err; + if (req->ff) + spin_lock(&req->ff->fc->lock); for (i = 0; i < req->num_pages && (nbytes || zeroing); i++) { - int err; unsigned offset = req->page_descs[i].offset; unsigned count = min(nbytes, req->page_descs[i].length); err = fuse_copy_page(cs, &req->pages[i], offset, count, zeroing); if (err) - return err; + goto err; nbytes -= count; } - return 0; +err: + if (req->ff) + spin_unlock(&req->ff->fc->lock); + return err; } /* Copy a single argument in the request to/from userspace buffer */ @@ -1353,6 +1361,9 @@ static ssize_t fuse_dev_do_read(struct fuse_dev *fud, struct file *file, clear_bit(FR_LOCKED, &req->flags); if (!fpq->connected) { err = (fc->aborted && fc->abort_err) ? -ECONNABORTED : -ENODEV; + /* Assign abnormal value to req->error when fpq disconnected */ + if (req->in.h.opcode == FUSE_CANONICAL_PATH) + req->out.h.error = -ECONNABORTED; goto out_end; } if (err) { @@ -1897,6 +1908,7 @@ static ssize_t fuse_dev_do_write(struct fuse_dev *fud, struct fuse_req *req; struct fuse_out_header oh; + if (nbytes < sizeof(struct fuse_out_header)) return -EINVAL; @@ -1972,8 +1984,12 @@ static ssize_t fuse_dev_do_write(struct fuse_dev *fud, spin_lock(&fpq->lock); clear_bit(FR_LOCKED, &req->flags); - if (!fpq->connected) + if (!fpq->connected) { + /* Assign abnormal value to req->error when fpq disconnected */ + if (req->in.h.opcode == FUSE_CANONICAL_PATH) + req->out.h.error = -ECONNABORTED; err = -ENOENT; + } else if (err) req->out.h.error = -EIO; if (!test_bit(FR_PRIVATE, &req->flags)) @@ -2289,37 +2305,50 @@ static int fuse_device_clone(struct fuse_conn *fc, struct file *new) static long fuse_dev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { - int err = -ENOTTY; + int res; + int oldfd; + struct fuse_dev *fud = NULL; - if (cmd == FUSE_DEV_IOC_CLONE) { - int oldfd; - - err = -EFAULT; - if (!get_user(oldfd, (__u32 __user *) arg)) { + switch (cmd) { + case FUSE_DEV_IOC_CLONE: + res = -EFAULT; + if (!get_user(oldfd, (__u32 __user *)arg)) { struct file *old = fget(oldfd); - err = -EINVAL; + res = -EINVAL; if (old) { - struct fuse_dev *fud = NULL; - /* * Check against file->f_op because CUSE * uses the same ioctl handler. */ if (old->f_op == file->f_op && - old->f_cred->user_ns == file->f_cred->user_ns) + old->f_cred->user_ns == + file->f_cred->user_ns) fud = fuse_get_dev(old); if (fud) { mutex_lock(&fuse_mutex); - err = fuse_device_clone(fud->fc, file); + res = fuse_device_clone(fud->fc, file); mutex_unlock(&fuse_mutex); } fput(old); } } + break; + case FUSE_DEV_IOC_PASSTHROUGH_OPEN: + res = -EFAULT; + if (!get_user(oldfd, (__u32 __user *)arg)) { + res = -EINVAL; + fud = fuse_get_dev(file); + if (fud) + res = fuse_passthrough_open(fud, oldfd); + } + break; + default: + res = -ENOTTY; + break; } - return err; + return res; } const struct file_operations fuse_dev_operations = { diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index 160f7d1d2370..f5416e5b7cc8 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c @@ -16,6 +16,11 @@ #include #include +#ifdef CONFIG_OPLUS_FEATURE_ACM +#include +#define ACM_DELETE_ERR 999 +#endif + static bool fuse_use_readdirplus(struct inode *dir, struct dir_context *ctx) { struct fuse_conn *fc = get_fuse_conn(dir); @@ -329,7 +334,6 @@ const struct dentry_operations fuse_dentry_operations = { const struct dentry_operations fuse_root_dentry_operations = { .d_init = fuse_dentry_init, .d_release = fuse_dentry_release, - .d_canonical_path = fuse_dentry_canonical_path, }; int fuse_valid_type(int m) @@ -479,6 +483,8 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, mode &= ~current_umask(); flags &= ~O_NOCTTY; + + memset(&inarg, 0, sizeof(inarg)); memset(&outentry, 0, sizeof(outentry)); inarg.flags = flags; @@ -508,6 +514,7 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, ff->fh = outopen.fh; ff->nodeid = outentry.nodeid; ff->open_flags = outopen.open_flags; + fuse_passthrough_setup(fc, ff, &outopen); inode = fuse_iget(dir->i_sb, outentry.nodeid, outentry.generation, &outentry.attr, entry_attr_timeout(&outentry), 0); if (!inode) { @@ -528,6 +535,9 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, file->private_data = ff; fuse_finish_open(inode, file); } +#ifdef CONFIG_OPLUS_FEATURE_ACM + monitor_acm2(entry, NULL, args.in.h.opcode); +#endif return err; out_free_ff: @@ -641,6 +651,11 @@ static int create_new_entry(struct fuse_conn *fc, struct fuse_args *args, fuse_change_entry_timeout(entry, &outarg); } fuse_invalidate_attr(dir); +#ifdef CONFIG_OPLUS_FEATURE_ACM + if ((args->in.h.opcode == FUSE_MKNOD) || + (args->in.h.opcode == FUSE_MKDIR)) + monitor_acm2(entry, NULL, args->in.h.opcode); +#endif return 0; out_put_forget_req: @@ -744,6 +759,13 @@ static int fuse_unlink(struct inode *dir, struct dentry *entry) args.in.numargs = 1; args.in.args[0].size = entry->d_name.len + 1; args.in.args[0].value = entry->d_name.name; +#ifdef CONFIG_OPLUS_FEATURE_ACM + err = monitor_acm2(entry, NULL, args.in.h.opcode); + if (err) { + err = ACM_DELETE_ERR; + return err; + } +#endif err = fuse_simple_request(fc, &args); if (!err) { struct inode *inode = d_inode(entry); @@ -783,6 +805,13 @@ static int fuse_rmdir(struct inode *dir, struct dentry *entry) args.in.numargs = 1; args.in.args[0].size = entry->d_name.len + 1; args.in.args[0].value = entry->d_name.name; +#ifdef CONFIG_OPLUS_FEATURE_ACM + err = monitor_acm2(entry, NULL, args.in.h.opcode); + if (err) { + err = ACM_DELETE_ERR; + return err; + } +#endif err = fuse_simple_request(fc, &args); if (!err) { clear_nlink(d_inode(entry)); @@ -845,7 +874,9 @@ static int fuse_rename_common(struct inode *olddir, struct dentry *oldent, if (d_really_is_positive(newent)) fuse_invalidate_entry(newent); } - +#ifdef CONFIG_OPLUS_FEATURE_ACM + monitor_acm2(oldent, newent, args.in.h.opcode); +#endif return err; } @@ -878,7 +909,6 @@ static int fuse_rename2(struct inode *olddir, struct dentry *oldent, FUSE_RENAME, sizeof(struct fuse_rename_in)); } - return err; } diff --git a/fs/fuse/file.c b/fs/fuse/file.c index 1fc7d5690ddd..115c58829e90 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c @@ -137,6 +137,7 @@ int fuse_do_open(struct fuse_conn *fc, u64 nodeid, struct file *file, ff->fh = outarg.fh; ff->open_flags = outarg.open_flags; + fuse_passthrough_setup(fc, ff, &outarg); } else if (err != -ENOSYS || isdir) { fuse_file_free(ff); return err; @@ -264,6 +265,8 @@ void fuse_release_common(struct file *file, bool isdir) struct fuse_req *req = ff->reserved_req; int opcode = isdir ? FUSE_RELEASEDIR : FUSE_RELEASE; + fuse_passthrough_release(&ff->passthrough); + fuse_prepare_release(ff, file->f_flags, opcode); if (ff->flock) { @@ -933,6 +936,7 @@ static ssize_t fuse_file_read_iter(struct kiocb *iocb, struct iov_iter *to) { struct inode *inode = iocb->ki_filp->f_mapping->host; struct fuse_conn *fc = get_fuse_conn(inode); + struct fuse_file *ff = iocb->ki_filp->private_data; if (fuse_is_bad(inode)) return -EIO; @@ -950,7 +954,11 @@ static ssize_t fuse_file_read_iter(struct kiocb *iocb, struct iov_iter *to) return err; } - return generic_file_read_iter(iocb, to); + if (ff && ff->passthrough.filp) + return fuse_passthrough_read_iter(iocb, to); + else + return generic_file_read_iter(iocb, to); + } static void fuse_write_fill(struct fuse_req *req, struct fuse_file *ff, @@ -1188,6 +1196,7 @@ static ssize_t fuse_file_write_iter(struct kiocb *iocb, struct iov_iter *from) { struct file *file = iocb->ki_filp; struct address_space *mapping = file->f_mapping; + struct fuse_file *ff = file->private_data; ssize_t written = 0; ssize_t written_buffered = 0; struct inode *inode = mapping->host; @@ -1197,6 +1206,15 @@ static ssize_t fuse_file_write_iter(struct kiocb *iocb, struct iov_iter *from) if (fuse_is_bad(inode)) return -EIO; + if (ff && ff->passthrough.filp) { + /* Update size (EOF optimization) and mode (SUID clearing) */ + err = fuse_update_attributes(mapping->host, file); + if (err) + return err; + + return fuse_passthrough_write_iter(iocb, from); + } + if (get_fuse_conn(inode)->writeback_cache) { /* Update size (EOF optimization) and mode (SUID clearing) */ err = fuse_update_attributes(mapping->host, file); @@ -2108,6 +2126,11 @@ static const struct vm_operations_struct fuse_file_vm_ops = { static int fuse_file_mmap(struct file *file, struct vm_area_struct *vma) { + struct fuse_file *ff = file->private_data; + + if (ff->passthrough.filp) + return fuse_passthrough_mmap(file, vma); + if ((vma->vm_flags & VM_SHARED) && (vma->vm_flags & VM_MAYWRITE)) fuse_link_write_file(file); diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index 3704ae529737..698c2e65072b 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -123,6 +123,16 @@ enum { }; struct fuse_conn; +/** + * Reference to lower filesystem file for read/write operations handled in + * passthrough mode. + * This struct also tracks the credentials to be used for handling read/write + * operations. + */ +struct fuse_passthrough { + struct file *filp; + struct cred *cred; +}; /** FUSE specific file data */ struct fuse_file { @@ -158,6 +168,9 @@ struct fuse_file { /** Has flock been performed on this file? */ bool flock:1; + + /** Container for data related to the passthrough functionality */ + struct fuse_passthrough passthrough; }; /** One input argument of a request */ @@ -392,6 +405,7 @@ struct fuse_req { /** Request is stolen from fuse_file->reserved_req */ struct file *stolen_file; + }; struct fuse_iqueue { @@ -564,6 +578,8 @@ struct fuse_conn { /** handle fs handles killing suid/sgid/cap on write/chown/trunc */ unsigned handle_killpriv:1; + /** Passthrough mode for read/write IO */ + unsigned int passthrough:1; /* * The following bitfields are only for optimization purposes * and hence races in setting them will not cause malfunction @@ -688,6 +704,12 @@ struct fuse_conn { /** List of device instances belonging to this connection */ struct list_head devices; + + /** IDR for passthrough requests */ + struct idr passthrough_req; + + /** Protects passthrough_req */ + spinlock_t passthrough_req_lock; }; static inline struct fuse_conn *get_fuse_conn_super(struct super_block *sb) @@ -1019,4 +1041,18 @@ struct posix_acl; struct posix_acl *fuse_get_acl(struct inode *inode, int type); int fuse_set_acl(struct inode *inode, struct posix_acl *acl, int type); +/* passthrough.c */ +int fuse_passthrough_open(struct fuse_dev *fud, u32 lower_fd); +int fuse_passthrough_setup(struct fuse_conn *fc, struct fuse_file *ff, + struct fuse_open_out *openarg); +void fuse_passthrough_release(struct fuse_passthrough *passthrough); +ssize_t fuse_passthrough_read_iter(struct kiocb *iocb, struct iov_iter *to); +ssize_t fuse_passthrough_write_iter(struct kiocb *iocb, struct iov_iter *from); +ssize_t fuse_passthrough_mmap(struct file *file, struct vm_area_struct *vma); + +#ifdef CONFIG_OPLUS_FEATURE_ACM +void acm_fuse_init_cache(void); +void acm_fuse_free_cache(void); +#endif + #endif /* _FS_FUSE_I_H */ diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index 57208ff9ccc8..7e8a25700411 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c @@ -49,6 +49,7 @@ MODULE_PARM_DESC(max_user_congthresh, "Global limit for the maximum congestion threshold an " "unprivileged user can set"); + #define FUSE_SUPER_MAGIC 0x65735546 #define FUSE_DEFAULT_BLKSIZE 512 @@ -615,6 +616,7 @@ void fuse_conn_init(struct fuse_conn *fc, struct user_namespace *user_ns) { memset(fc, 0, sizeof(*fc)); spin_lock_init(&fc->lock); + spin_lock_init(&fc->passthrough_req_lock); init_rwsem(&fc->killsb); refcount_set(&fc->count, 1); atomic_set(&fc->dev_count, 1); @@ -624,6 +626,7 @@ void fuse_conn_init(struct fuse_conn *fc, struct user_namespace *user_ns) INIT_LIST_HEAD(&fc->bg_queue); INIT_LIST_HEAD(&fc->entry); INIT_LIST_HEAD(&fc->devices); + idr_init(&fc->passthrough_req); atomic_set(&fc->num_waiting, 0); fc->max_background = FUSE_DEFAULT_MAX_BACKGROUND; fc->congestion_threshold = FUSE_DEFAULT_CONGESTION_THRESHOLD; @@ -923,6 +926,12 @@ static void process_init_reply(struct fuse_conn *fc, struct fuse_req *req) fc->async_dio = 1; if (arg->flags & FUSE_WRITEBACK_CACHE) fc->writeback_cache = 1; + if (arg->flags & FUSE_PASSTHROUGH) { + fc->passthrough = 1; + /* Prevent further stacking */ + fc->sb->s_stack_depth = + FILESYSTEM_MAX_STACK_DEPTH; + } if (arg->flags & FUSE_PARALLEL_DIROPS) fc->parallel_dirops = 1; if (arg->flags & FUSE_HANDLE_KILLPRIV) @@ -967,7 +976,8 @@ static void fuse_send_init(struct fuse_conn *fc, struct fuse_req *req) FUSE_DO_READDIRPLUS | FUSE_READDIRPLUS_AUTO | FUSE_ASYNC_DIO | FUSE_WRITEBACK_CACHE | FUSE_NO_OPEN_SUPPORT | FUSE_PARALLEL_DIROPS | FUSE_HANDLE_KILLPRIV | FUSE_POSIX_ACL | - FUSE_ABORT_ERROR; + FUSE_PASSTHROUGH; + req->in.h.opcode = FUSE_INIT; req->in.numargs = 1; req->in.args[0].size = sizeof(*arg); @@ -983,9 +993,21 @@ static void fuse_send_init(struct fuse_conn *fc, struct fuse_req *req) fuse_request_send_background(fc, req); } +static int free_fuse_passthrough(int id, void *p, void *data) +{ + struct fuse_passthrough *passthrough = (struct fuse_passthrough *)p; + + fuse_passthrough_release(passthrough); + kfree(p); + + return 0; +} + static void fuse_free_conn(struct fuse_conn *fc) { WARN_ON(!list_empty(&fc->devices)); + idr_for_each(&fc->passthrough_req, free_fuse_passthrough, NULL); + idr_destroy(&fc->passthrough_req); kfree_rcu(fc, rcu); } @@ -1197,6 +1219,10 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent) fuse_send_init(fc, init_req); +#ifdef CONFIG_OPLUS_FEATURE_ACM + acm_fuse_init_cache(); +#endif + return 0; err_unlock: @@ -1228,6 +1254,9 @@ static void fuse_sb_destroy(struct super_block *sb) struct fuse_conn *fc = get_fuse_conn_super(sb); if (fc) { +#ifdef CONFIG_OPLUS_FEATURE_ACM + acm_fuse_free_cache(); +#endif fuse_send_destroy(fc); fuse_abort_conn(fc, false); diff --git a/fs/fuse/passthrough.c b/fs/fuse/passthrough.c new file mode 100644 index 000000000000..4116a087c054 --- /dev/null +++ b/fs/fuse/passthrough.c @@ -0,0 +1,293 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include "fuse_i.h" + +#include +#include +#include +#include + +#define PASSTHROUGH_IOCB_MASK \ + (IOCB_APPEND | IOCB_DSYNC | IOCB_HIPRI | IOCB_NOWAIT | IOCB_SYNC) + +struct fuse_aio_req { + struct kiocb iocb; + struct kiocb *iocb_fuse; +}; + +static void fuse_file_accessed(struct file *dst_file, struct file *src_file) +{ + struct inode *dst_inode; + struct inode *src_inode; + + if (dst_file->f_flags & O_NOATIME) + return; + + dst_inode = file_inode(dst_file); + src_inode = file_inode(src_file); + + if ((!timespec64_equal(&dst_inode->i_mtime, &src_inode->i_mtime) || + !timespec64_equal(&dst_inode->i_ctime, &src_inode->i_ctime))) { + dst_inode->i_mtime = src_inode->i_mtime; + dst_inode->i_ctime = src_inode->i_ctime; + } + + touch_atime(&dst_file->f_path); +} + +static void fuse_copyattr(struct file *dst_file, struct file *src_file) +{ + struct inode *dst = file_inode(dst_file); + struct inode *src = file_inode(src_file); + + dst->i_atime = src->i_atime; + dst->i_mtime = src->i_mtime; + dst->i_ctime = src->i_ctime; + i_size_write(dst, i_size_read(src)); +} + +static void fuse_aio_cleanup_handler(struct fuse_aio_req *aio_req) +{ + struct kiocb *iocb = &aio_req->iocb; + struct kiocb *iocb_fuse = aio_req->iocb_fuse; + + if (iocb->ki_flags & IOCB_WRITE) { + __sb_writers_acquired(file_inode(iocb->ki_filp)->i_sb, + SB_FREEZE_WRITE); + file_end_write(iocb->ki_filp); + fuse_copyattr(iocb_fuse->ki_filp, iocb->ki_filp); + } + + iocb_fuse->ki_pos = iocb->ki_pos; + kfree(aio_req); +} + +static void fuse_aio_rw_complete(struct kiocb *iocb, long res, long res2) +{ + struct fuse_aio_req *aio_req = + container_of(iocb, struct fuse_aio_req, iocb); + struct kiocb *iocb_fuse = aio_req->iocb_fuse; + + fuse_aio_cleanup_handler(aio_req); + iocb_fuse->ki_complete(iocb_fuse, res, res2); +} + +ssize_t fuse_passthrough_read_iter(struct kiocb *iocb_fuse, + struct iov_iter *iter) +{ + ssize_t ret; + const struct cred *old_cred; + struct file *fuse_filp = iocb_fuse->ki_filp; + struct fuse_file *ff = fuse_filp->private_data; + struct file *passthrough_filp = ff->passthrough.filp; + + if (!iov_iter_count(iter)) + return 0; + + old_cred = override_creds(ff->passthrough.cred); + if (is_sync_kiocb(iocb_fuse)) { + ret = vfs_iter_read(passthrough_filp, iter, &iocb_fuse->ki_pos, + iocb_to_rw_flags(iocb_fuse->ki_flags, + PASSTHROUGH_IOCB_MASK)); + } else { + struct fuse_aio_req *aio_req; + + aio_req = kmalloc(sizeof(struct fuse_aio_req), GFP_KERNEL); + if (!aio_req) { + ret = -ENOMEM; + goto out; + } + + aio_req->iocb_fuse = iocb_fuse; + kiocb_clone(&aio_req->iocb, iocb_fuse, passthrough_filp); + aio_req->iocb.ki_complete = fuse_aio_rw_complete; + ret = call_read_iter(passthrough_filp, &aio_req->iocb, iter); + if (ret != -EIOCBQUEUED) + fuse_aio_cleanup_handler(aio_req); + } +out: + revert_creds(old_cred); + + fuse_file_accessed(fuse_filp, passthrough_filp); + + return ret; +} + +ssize_t fuse_passthrough_write_iter(struct kiocb *iocb_fuse, + struct iov_iter *iter) +{ + ssize_t ret; + const struct cred *old_cred; + struct file *fuse_filp = iocb_fuse->ki_filp; + struct fuse_file *ff = fuse_filp->private_data; + struct inode *fuse_inode = file_inode(fuse_filp); + struct file *passthrough_filp = ff->passthrough.filp; + struct inode *passthrough_inode = file_inode(passthrough_filp); + + if (!iov_iter_count(iter)) + return 0; + + inode_lock(fuse_inode); + + fuse_copyattr(fuse_filp, passthrough_filp); + + old_cred = override_creds(ff->passthrough.cred); + if (is_sync_kiocb(iocb_fuse)) { + file_start_write(passthrough_filp); + ret = vfs_iter_write(passthrough_filp, iter, &iocb_fuse->ki_pos, + iocb_to_rw_flags(iocb_fuse->ki_flags, + PASSTHROUGH_IOCB_MASK)); + file_end_write(passthrough_filp); + if (ret > 0) + fuse_copyattr(fuse_filp, passthrough_filp); + } else { + struct fuse_aio_req *aio_req; + + aio_req = kmalloc(sizeof(struct fuse_aio_req), GFP_KERNEL); + if (!aio_req) { + ret = -ENOMEM; + goto out; + } + + file_start_write(passthrough_filp); + __sb_writers_release(passthrough_inode->i_sb, SB_FREEZE_WRITE); + + aio_req->iocb_fuse = iocb_fuse; + kiocb_clone(&aio_req->iocb, iocb_fuse, passthrough_filp); + aio_req->iocb.ki_complete = fuse_aio_rw_complete; + ret = call_write_iter(passthrough_filp, &aio_req->iocb, iter); + if (ret != -EIOCBQUEUED) + fuse_aio_cleanup_handler(aio_req); + } +out: + revert_creds(old_cred); + inode_unlock(fuse_inode); + return ret; +} + +ssize_t fuse_passthrough_mmap(struct file *file, struct vm_area_struct *vma) +{ + int ret; + const struct cred *old_cred; + struct fuse_file *ff = file->private_data; + struct file *passthrough_filp = ff->passthrough.filp; + + if (!passthrough_filp->f_op->mmap) + return -ENODEV; + + if (WARN_ON(file != vma->vm_file)) + return -EIO; + + vma->vm_file = get_file(passthrough_filp); + + old_cred = override_creds(ff->passthrough.cred); + ret = call_mmap(vma->vm_file, vma); + revert_creds(old_cred); + + if (ret) + fput(passthrough_filp); + else + fput(file); + + fuse_file_accessed(file, passthrough_filp); + + return ret; +} + +int fuse_passthrough_open(struct fuse_dev *fud, u32 lower_fd) +{ + int res; + struct file *passthrough_filp; + struct fuse_conn *fc = fud->fc; + struct inode *passthrough_inode; + struct super_block *passthrough_sb; + struct fuse_passthrough *passthrough; + + if (!fc->passthrough) + return -EPERM; + + passthrough_filp = fget(lower_fd); + if (!passthrough_filp) { + pr_err("FUSE: invalid file descriptor for passthrough.\n"); + return -EBADF; + } + + if (!passthrough_filp->f_op->read_iter || + !passthrough_filp->f_op->write_iter) { + pr_err("FUSE: passthrough file misses file operations.\n"); + res = -EBADF; + goto err_free_file; + } + + passthrough_inode = file_inode(passthrough_filp); + passthrough_sb = passthrough_inode->i_sb; + if (passthrough_sb->s_stack_depth >= FILESYSTEM_MAX_STACK_DEPTH) { + pr_err("FUSE: fs stacking depth exceeded for passthrough\n"); + res = -EINVAL; + goto err_free_file; + } + + passthrough = kmalloc(sizeof(struct fuse_passthrough), GFP_KERNEL); + if (!passthrough) { + res = -ENOMEM; + goto err_free_file; + } + + passthrough->filp = passthrough_filp; + passthrough->cred = prepare_creds(); + + idr_preload(GFP_KERNEL); + spin_lock(&fc->passthrough_req_lock); + res = idr_alloc(&fc->passthrough_req, passthrough, 1, 0, GFP_ATOMIC); + spin_unlock(&fc->passthrough_req_lock); + idr_preload_end(); + + if (res > 0) + return res; + + fuse_passthrough_release(passthrough); + kfree(passthrough); + +err_free_file: + fput(passthrough_filp); + + return res; +} + +int fuse_passthrough_setup(struct fuse_conn *fc, struct fuse_file *ff, + struct fuse_open_out *openarg) +{ + struct fuse_passthrough *passthrough; + int passthrough_fh = openarg->passthrough_fh; + + if (!fc->passthrough) + return -EPERM; + + /* Default case, passthrough is not requested */ + if (passthrough_fh <= 0) + return -EINVAL; + + spin_lock(&fc->passthrough_req_lock); + passthrough = idr_remove(&fc->passthrough_req, passthrough_fh); + spin_unlock(&fc->passthrough_req_lock); + + if (!passthrough) + return -EINVAL; + + ff->passthrough = *passthrough; + kfree(passthrough); + + return 0; +} + +void fuse_passthrough_release(struct fuse_passthrough *passthrough) +{ + if (passthrough->filp) { + fput(passthrough->filp); + passthrough->filp = NULL; + } + if (passthrough->cred) { + put_cred(passthrough->cred); + passthrough->cred = NULL; + } +} diff --git a/fs/iomap.c b/fs/iomap.c index 881c2fb14bca..9a20f76ac997 100644 --- a/fs/iomap.c +++ b/fs/iomap.c @@ -32,6 +32,9 @@ #include #include #include +#if defined(OPLUS_FEATURE_IOMONITOR) && defined(CONFIG_IOMONITOR) +#include +#endif /*OPLUS_FEATURE_IOMONITOR*/ #include "internal.h" @@ -1711,6 +1714,9 @@ iomap_dio_bio_actor(struct inode *inode, loff_t pos, loff_t length, else dio->flags &= ~IOMAP_DIO_WRITE_FUA; task_io_account_write(n); +#if defined(OPLUS_FEATURE_IOMONITOR) && defined(CONFIG_IOMONITOR) + iomonitor_update_rw_stats(DIO_WRITE, NULL, n); +#endif /*OPLUS_FEATURE_IOMONITOR*/ } else { bio->bi_opf = REQ_OP_READ; if (dio->flags & IOMAP_DIO_DIRTY) diff --git a/fs/namespace.c b/fs/namespace.c index 5e94ec9f45d4..d8e09dbe3e80 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -30,6 +30,14 @@ #include "pnode.h" #include "internal.h" +#ifdef CONFIG_OPLUS_SECURE_GUARD +#ifdef CONFIG_OPLUS_MOUNT_BLOCK +#ifdef CONFIG_OPLUS_KEVENT_UPLOAD +#include +#endif /* CONFIG_OPLUS_KEVENT_UPLOAD */ +#endif /* CONFIG_OPLUS_MOUNT_BLOCK */ +#endif /* CONFIG_OPLUS_SECURE_GUARD*/ + /* Maximum number of mounts in a mount namespace */ unsigned int sysctl_mount_max __read_mostly = 100000; @@ -2754,6 +2762,11 @@ char *copy_mount_string(const void __user *data) return data ? strndup_user(data, PAGE_SIZE) : NULL; } +#ifdef CONFIG_OPLUS_SECURE_GUARD +#ifdef CONFIG_OPLUS_MOUNT_BLOCK +extern int oplus_mount_block(const char __user *dir_name, unsigned long flags); +#endif /* CONFIG_OPLUS_MOUNT_BLOCK */ +#endif /* CONFIG_OPLUS_SECURE_GUARD */ /* * Flags is a 32-bit value that allows up to 31 non-fs dependent flags to * be given to the mount() call (ie: read-only, no-dev, no-suid etc). @@ -2775,6 +2788,14 @@ long do_mount(const char *dev_name, const char __user *dir_name, unsigned int mnt_flags = 0, sb_flags; int retval = 0; +#ifdef CONFIG_OPLUS_SECURE_GUARD +#ifdef CONFIG_OPLUS_MOUNT_BLOCK + retval = oplus_mount_block(dir_name, flags); + if (retval < 0){ + return -EPERM; + } +#endif /* CONFIG_OPLUS_MOUNT_BLOCK */ +#endif /* CONFIG_OPLUS_SECURE_GUARD */ /* Discard magic */ if ((flags & MS_MGC_MSK) == MS_MGC_VAL) flags &= ~MS_MGC_MSK; diff --git a/fs/notify/inotify/inotify_user.c b/fs/notify/inotify/inotify_user.c index 4037dd1b7d1e..49e89394275b 100644 --- a/fs/notify/inotify/inotify_user.c +++ b/fs/notify/inotify/inotify_user.c @@ -583,6 +583,10 @@ static int inotify_new_watch(struct fsnotify_group *group, /* increment the number of watches the user has */ if (!inc_inotify_watches(group->inotify_data.ucounts)) { +#ifdef VENDOR_EDIT + if (printk_ratelimit()) + printk(KERN_ERR "inotify_new_watch:return false,uid=%ul\n", current_uid()); +#endif inotify_remove_from_idr(group, tmp_i_mark); ret = -ENOSPC; goto out_err; diff --git a/fs/oext4 b/fs/oext4 new file mode 120000 index 000000000000..b12610365acd --- /dev/null +++ b/fs/oext4 @@ -0,0 +1 @@ +../../../vendor/oplus/kernel_4.19/ext4/ \ No newline at end of file diff --git a/fs/of2fs b/fs/of2fs new file mode 120000 index 000000000000..f6ff66a20124 --- /dev/null +++ b/fs/of2fs @@ -0,0 +1 @@ +../../../vendor/oplus/kernel/of2fs/ \ No newline at end of file diff --git a/fs/osdcardfs b/fs/osdcardfs new file mode 120000 index 000000000000..53ab38673e0f --- /dev/null +++ b/fs/osdcardfs @@ -0,0 +1 @@ +../../../vendor/oplus/kernel_4.19/sdcardfs \ No newline at end of file diff --git a/fs/overlayfs/file.c b/fs/overlayfs/file.c index 818a8ee4357b..4738f45028c8 100644 --- a/fs/overlayfs/file.c +++ b/fs/overlayfs/file.c @@ -13,7 +13,7 @@ #include #include #include "overlayfs.h" - +#define OVL_IOCB_MASK (IOCB_DSYNC | IOCB_HIPRI | IOCB_NOWAIT | IOCB_SYNC) static char ovl_whatisit(struct inode *inode, struct inode *realinode) { if (realinode != ovl_inode_upper(inode)) @@ -213,22 +213,6 @@ static void ovl_file_accessed(struct file *file) touch_atime(&file->f_path); } -static rwf_t ovl_iocb_to_rwf(struct kiocb *iocb) -{ - int ifl = iocb->ki_flags; - rwf_t flags = 0; - - if (ifl & IOCB_NOWAIT) - flags |= RWF_NOWAIT; - if (ifl & IOCB_HIPRI) - flags |= RWF_HIPRI; - if (ifl & IOCB_DSYNC) - flags |= RWF_DSYNC; - if (ifl & IOCB_SYNC) - flags |= RWF_SYNC; - - return flags; -} static ssize_t ovl_read_iter(struct kiocb *iocb, struct iov_iter *iter) { @@ -246,7 +230,8 @@ static ssize_t ovl_read_iter(struct kiocb *iocb, struct iov_iter *iter) old_cred = ovl_override_creds(file_inode(file)->i_sb); ret = vfs_iter_read(real.file, iter, &iocb->ki_pos, - ovl_iocb_to_rwf(iocb)); + iocb_to_rw_flags(iocb->ki_flags, + OVL_IOCB_MASK)); ovl_revert_creds(old_cred); ovl_file_accessed(file); @@ -281,7 +266,7 @@ static ssize_t ovl_write_iter(struct kiocb *iocb, struct iov_iter *iter) old_cred = ovl_override_creds(file_inode(file)->i_sb); file_start_write(real.file); ret = vfs_iter_write(real.file, iter, &iocb->ki_pos, - ovl_iocb_to_rwf(iocb)); + iocb_to_rw_flags(iocb->ki_flags, OVL_IOCB_MASK)); file_end_write(real.file); ovl_revert_creds(old_cred); diff --git a/fs/proc/Kconfig b/fs/proc/Kconfig index cad2c60b8656..2bc0e021f77f 100644 --- a/fs/proc/Kconfig +++ b/fs/proc/Kconfig @@ -103,3 +103,14 @@ config PROC_UID depends on PROC_FS && RT_MUTEXES help Provides aggregated per-uid information under /proc/uid. + +#ifdef OPLUS_FEATURE_CPU_JANKINFO +source "fs/proc/cpu_jankinfo/Kconfig" +#endif /* OPLUS_FEATURE_CPU_JANKINFO */ +#ifdef OPLUS_FEATURE_TASK_CPUSTATS +source "fs/proc/task_cpustats/Kconfig" +#endif /* OPLUS_FEATURE_TASK_CPUSTATS */ + +#ifdef OPLUS_FEATURE_HEALTHINFO +source fs/proc/healthinfo/Kconfig +#endif /* OPLUS_FEATURE_HEALTHINFO */ diff --git a/fs/proc/Makefile b/fs/proc/Makefile index 3f849ca0edce..c5499e2247cc 100644 --- a/fs/proc/Makefile +++ b/fs/proc/Makefile @@ -34,3 +34,10 @@ proc-$(CONFIG_PROC_KCORE) += kcore.o proc-$(CONFIG_PROC_VMCORE) += vmcore.o proc-$(CONFIG_PRINTK) += kmsg.o proc-$(CONFIG_PROC_PAGE_MONITOR) += page.o +#ifdef OPLUS_FEATURE_HEALTHINFO +obj-y += healthinfo/ +#endif /* OPLUS_FEATURE_HEALTHINFO */ +#ifdef OPLUS_FEATURE_TASK_CPUSTATS +obj-y += task_cpustats/ +#endif /* OPLUS_FEATURE_TASK_CPUSTATS */ +obj-$(CONFIG_OPLUS_FEATURE_CPU_JANKINFO) += cpu_jankinfo/ diff --git a/fs/proc/array.c b/fs/proc/array.c index 9eb99a43f849..c27be8e64a7c 100644 --- a/fs/proc/array.c +++ b/fs/proc/array.c @@ -91,7 +91,6 @@ #include #include #include - #include #include #include "internal.h" @@ -650,6 +649,25 @@ int proc_pid_statm(struct seq_file *m, struct pid_namespace *ns, return 0; } +#ifdef OPLUS_FEATURE_PERFORMANCE +int proc_pid_statm_as(struct seq_file *m, struct pid_namespace *ns, + struct pid *pid, struct task_struct *task) +{ + unsigned long size = 0; + struct mm_struct *mm = get_task_mm(task); + + if (mm) { + size = get_mm_counter(mm, MM_ANONPAGES) + + get_mm_counter(mm, MM_SWAPENTS); + mmput(mm); + } + seq_put_decimal_ull(m, "", size); + seq_putc(m, '\n'); + + return 0; +} +#endif /* OPLUS_FEATURE_PERFORMANCE */ + #ifdef CONFIG_PROC_CHILDREN static struct pid * get_children_pid(struct inode *inode, struct pid *pid_prev, loff_t pos) diff --git a/fs/proc/base.c b/fs/proc/base.c index 1c45c20bc5aa..908d2366be75 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -101,6 +101,22 @@ #include "../../lib/kstrtox.h" +#ifdef OPLUS_FEATURE_HEALTHINFO +#ifdef CONFIG_OPLUS_JANK_INFO +#include +#endif +#endif /* OPLUS_FEATURE_HEALTHINFO */ +#ifdef CONFIG_OPLUS_FEATURE_IM +#include +#endif + +#ifdef OPLUS_FEATURE_SCHED_ASSIST +#define GLOBAL_SYSTEM_UID KUIDT_INIT(1000) +#define GLOBAL_SYSTEM_GID KGIDT_INIT(1000) +extern const struct file_operations proc_ux_state_operations; +extern bool is_special_entry(struct dentry *dentry, const char* special_proc); +#endif /* OPLUS_FEATURE_SCHED_ASSIST */ + /* NOTE: * Implementing inode permission operations in /proc is almost * certainly an error. Permission checks need to happen during @@ -2088,6 +2104,13 @@ static int pid_revalidate(struct dentry *dentry, unsigned int flags) if (task) { pid_update_inode(task, inode); +#ifdef OPLUS_FEATURE_SCHED_ASSIST + if (is_special_entry(dentry, "ux_state")) { + inode->i_uid = GLOBAL_SYSTEM_UID; + inode->i_gid = GLOBAL_SYSTEM_GID; + } +#endif /* OPLUS_FEATURE_SCHED_ASSIST */ + put_task_struct(task); return 1; } @@ -3362,12 +3385,175 @@ static int proc_pid_patch_state(struct seq_file *m, struct pid_namespace *ns, } #endif /* CONFIG_LIVEPATCH */ +#ifdef CONFIG_OPLUS_FEATURE_IM +static int proc_im_flag(struct seq_file *m, struct pid_namespace *ns, + struct pid *pid, struct task_struct *task) +{ +#define IM_TAG_DESC_LEN (128) + char desc[IM_TAG_DESC_LEN] = {0}; + int arg = 0; + +#ifdef CONFIG_OPLUS_FEATURE_TPD + arg = task->tpd_st; +#endif + + im_to_str(task->im_flag, desc, IM_TAG_DESC_LEN); + desc[IM_TAG_DESC_LEN - 1] = '\0'; + seq_printf(m, "%d %s (%d)", + task->im_flag, desc, arg); + return 0; +} + +#endif /* CONFIG_OPLUS_FEATURE_IM */ + +#ifdef CONFIG_OPLUS_FEATURE_TPD +static ssize_t +tpd_write(struct file *file, const char __user *buf, + size_t count, loff_t *offset) +{ + struct task_struct *task; + char buffer[PROC_NUMBUF]; + int err, tpdecision; + + memset(buffer, 0, sizeof(buffer)); + if (count > sizeof(buffer) - 1) + count = sizeof(buffer) - 1; + if (copy_from_user(buffer, buf, count)) + return -EFAULT; + + err = kstrtoint(strstrip(buffer), 0, &tpdecision); + if (err) + return err; + task = get_proc_task(file_inode(file)); + if (!task) + return -ESRCH; + task->tpd = (tpdecision != 0) ? tpdecision : 0; + put_task_struct(task); + return count; +} + +static int tpd_show(struct seq_file *m, void *v) +{ + struct inode *inode = m->private; + struct task_struct *p; + + p = get_proc_task(inode); + if (!p) + return -ESRCH; + seq_printf(m, "%d\n", p->tpd); + put_task_struct(p); + return 0; +} + +static int tpd_open(struct inode *inode, struct file *filp) +{ + return single_open(filp, tpd_show, inode); +} + +static ssize_t tpd_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + char buffer[PROC_NUMBUF]; + struct task_struct *task = NULL; + int tpdecision; + size_t len = 0; + + task = get_proc_task(file_inode(file)); + if (!task) + return -ESRCH; + tpdecision = task->tpd; + put_task_struct(task); + len = snprintf(buffer, sizeof(buffer), "%d\n", tpdecision); + return simple_read_from_buffer(buf, count, ppos, buffer, len); +} + +static const struct file_operations proc_tpd_operation = { + .open = tpd_open, + .read = tpd_read, + .write = tpd_write, + .llseek = seq_lseek, + .release = single_release, +}; +/* system thread for cpu affinity */ +static ssize_t +st_tpd_write(struct file *file, const char __user *buf, + size_t count, loff_t *offset) +{ + struct task_struct *task; + char buffer[PROC_NUMBUF]; + int err, tpdecision; + + memset(buffer, 0, sizeof(buffer)); + if (count > sizeof(buffer) - 1) + count = sizeof(buffer) - 1; + if (copy_from_user(buffer, buf, count)) + return -EFAULT; + + err = kstrtoint(strstrip(buffer), 0, &tpdecision); + if (err) + return err; + task = get_proc_task(file_inode(file)); + if (!task) + return -ESRCH; + task->tpd_st = (tpdecision != 0) ? tpdecision : 0; + put_task_struct(task); + return count; +} + +static int st_tpd_show(struct seq_file *m, void *v) +{ + struct inode *inode = m->private; + struct task_struct *p; + + p = get_proc_task(inode); + if (!p) + return -ESRCH; + seq_printf(m, "%d\n", p->tpd_st); + put_task_struct(p); + return 0; +} + +static int st_tpd_open(struct inode *inode, struct file *filp) +{ + return single_open(filp, st_tpd_show, inode); +} + +static ssize_t st_tpd_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + char buffer[PROC_NUMBUF]; + struct task_struct *task = NULL; + int tpdecision; + size_t len = 0; + + task = get_proc_task(file_inode(file)); + if (!task) + return -ESRCH; + tpdecision = task->tpd_st; + put_task_struct(task); + len = snprintf(buffer, sizeof(buffer), "%d\n", tpdecision); + return simple_read_from_buffer(buf, count, ppos, buffer, len); +} + +static const struct file_operations proc_st_tpd_operation = { + .open = st_tpd_open, + .read = st_tpd_read, + .write = st_tpd_write, + .llseek = seq_lseek, + .release = single_release, +}; +#endif /* CONFIG_OPLUS_FEATURE_TPD */ + /* * Thread groups */ static const struct file_operations proc_task_operations; static const struct inode_operations proc_task_inode_operations; +#if defined(OPLUS_FEATURE_VIRTUAL_RESERVE_MEMORY) && defined(CONFIG_VIRTUAL_RESERVE_MEMORY) +#include "va_feature_node.h" +#endif + static const struct pid_entry tgid_base_stuff[] = { DIR("task", S_IRUGO|S_IXUGO, proc_task_inode_operations, proc_task_operations), DIR("fd", S_IRUSR|S_IXUSR, proc_fd_inode_operations, proc_fd_operations), @@ -3405,6 +3591,9 @@ static const struct pid_entry tgid_base_stuff[] = { REG("cmdline", S_IRUGO, proc_pid_cmdline_ops), ONE("stat", S_IRUGO, proc_tgid_stat), ONE("statm", S_IRUGO, proc_pid_statm), +#ifdef OPLUS_FEATURE_PERFORMANCE + ONE("statm_as", S_IRUGO, proc_pid_statm_as), +#endif /* OPLUS_FEATURE_PERFORMANCE */ REG("maps", S_IRUGO, proc_pid_maps_operations), #ifdef CONFIG_NUMA REG("numa_maps", S_IRUGO, proc_pid_numa_maps_operations), @@ -3483,6 +3672,22 @@ static const struct pid_entry tgid_base_stuff[] = { #ifdef CONFIG_CPU_FREQ_TIMES ONE("time_in_state", 0444, proc_time_in_state_show), #endif +#ifdef OPLUS_FEATURE_HEALTHINFO +#ifdef CONFIG_OPLUS_JANK_INFO + REG("jank_info", S_IRUGO | S_IWUGO, proc_jank_trace_operations), +#endif +#endif /* OPLUS_FEATURE_HEALTHINFO */ +#if defined(OPLUS_FEATURE_VIRTUAL_RESERVE_MEMORY) && defined(CONFIG_VIRTUAL_RESERVE_MEMORY) + REG("va_feature", 0666, proc_va_feature_operations), +#endif +#ifdef CONFIG_OPLUS_FEATURE_IM + ONE("im_flag", 0444, proc_im_flag), +#endif + +#ifdef CONFIG_OPLUS_FEATURE_TPD + REG("tpd", 0644, proc_tpd_operation), + REG("tpd_st", 0644, proc_st_tpd_operation), +#endif }; static int proc_tgid_base_readdir(struct file *file, struct dir_context *ctx) @@ -3807,6 +4012,9 @@ static const struct pid_entry tid_base_stuff[] = { REG("cmdline", S_IRUGO, proc_pid_cmdline_ops), ONE("stat", S_IRUGO, proc_tid_stat), ONE("statm", S_IRUGO, proc_pid_statm), +#ifdef OPLUS_FEATURE_PERFORMANCE + ONE("statm_as", S_IRUGO, proc_pid_statm_as), +#endif /* OPLUS_FEATURE_PERFORMANCE */ REG("maps", S_IRUGO, proc_pid_maps_operations), #ifdef CONFIG_PROC_CHILDREN REG("children", S_IRUGO, proc_tid_children_operations), @@ -3877,6 +4085,17 @@ static const struct pid_entry tid_base_stuff[] = { #ifdef CONFIG_CPU_FREQ_TIMES ONE("time_in_state", 0444, proc_time_in_state_show), #endif +#ifdef OPLUS_FEATURE_SCHED_ASSIST + REG("ux_state", S_IRUGO | S_IWUGO, proc_ux_state_operations), +#endif /* OPLUS_FEATURE_SCHED_ASSIST */ +#ifdef CONFIG_OPLUS_FEATURE_IM + ONE("im_flag", 0444, proc_im_flag), +#endif + +#ifdef CONFIG_OPLUS_FEATURE_TPD + REG("tpd", 0644, proc_tpd_operation), + REG("tpd_st", 0644, proc_st_tpd_operation), +#endif }; static int proc_tid_base_readdir(struct file *file, struct dir_context *ctx) diff --git a/fs/proc/cpu_jankinfo b/fs/proc/cpu_jankinfo new file mode 120000 index 000000000000..ed2469f1bbbe --- /dev/null +++ b/fs/proc/cpu_jankinfo @@ -0,0 +1 @@ +../../../../vendor/oplus/kernel/oplus_performance/cpu_jankinfo/ \ No newline at end of file diff --git a/fs/proc/healthinfo b/fs/proc/healthinfo new file mode 120000 index 000000000000..076ec464d161 --- /dev/null +++ b/fs/proc/healthinfo @@ -0,0 +1 @@ +../../../../vendor/oplus/kernel/oplus_performance/healthinfo/fs/ \ No newline at end of file diff --git a/fs/proc/internal.h b/fs/proc/internal.h index e05deaee80d9..6e3ff20fae41 100644 --- a/fs/proc/internal.h +++ b/fs/proc/internal.h @@ -151,6 +151,10 @@ extern int proc_pid_status(struct seq_file *, struct pid_namespace *, struct pid *, struct task_struct *); extern int proc_pid_statm(struct seq_file *, struct pid_namespace *, struct pid *, struct task_struct *); +#ifdef OPLUS_FEATURE_PERFORMANCE +extern int proc_pid_statm_as(struct seq_file *m, struct pid_namespace *ns, + struct pid *pid, struct task_struct *task); +#endif /* OPLUS_FEATURE_PERFORMANCE */ /* * base.c diff --git a/fs/proc/meminfo.c b/fs/proc/meminfo.c index f2dab6c2edb3..6d2a867419d0 100644 --- a/fs/proc/meminfo.c +++ b/fs/proc/meminfo.c @@ -21,6 +21,15 @@ #include #include "internal.h" +//#ifdef OPLUS_FEATURE_HEALTHINFO +#include +//#endif /* OPLUS_FEATURE_HEALTHINFO */ +#include + +#ifdef OPLUS_FEATURE_HEALTHINFO +extern unsigned long gpu_total(void); +#endif /* OPLUS_FEATURE_HEALTHINFO */ + void __attribute__((weak)) arch_report_meminfo(struct seq_file *m) { } @@ -148,9 +157,24 @@ static int meminfo_proc_show(struct seq_file *m, void *v) global_zone_page_state(NR_FREE_CMA_PAGES)); #endif +#if defined(OPLUS_FEATURE_MEMORY_ISOLATE) && defined(CONFIG_OPLUS_MEMORY_ISOLATE) + show_val_kb(m, "Oplus2Free: ", + global_zone_page_state(NR_FREE_OPLUS2_PAGES)); +#endif /* OPLUS_FEATURE_MEMORY_ISOLATE */ + +#ifdef OPLUS_FEATURE_HEALTHINFO +#ifdef CONFIG_ION + show_val_kb(m, "IonTotalCache: ", global_zone_page_state(NR_IONCACHE_PAGES));; + show_val_kb(m, "IonTotalUsed: ", ion_total() >> PAGE_SHIFT); +#endif +#endif /* OPLUS_FEATURE_HEALTHINFO */ +#ifdef OPLUS_FEATURE_HEALTHINFO + show_val_kb(m, "GPUTotalUsed: ", gpu_total() >> PAGE_SHIFT); +#endif /* OPLUS_FEATURE_HEALTHINFO */ hugetlb_report_meminfo(m); arch_report_meminfo(m); + trace_android_vh_meminfo_proc_show(m); return 0; } diff --git a/fs/proc/stat.c b/fs/proc/stat.c index 535eda7857cf..afb930a88f12 100644 --- a/fs/proc/stat.c +++ b/fs/proc/stat.c @@ -23,7 +23,7 @@ #ifdef arch_idle_time -static u64 get_idle_time(int cpu) +u64 get_idle_time(int cpu) { u64 idle; @@ -33,7 +33,7 @@ static u64 get_idle_time(int cpu) return idle; } -static u64 get_iowait_time(int cpu) +u64 get_iowait_time(int cpu) { u64 iowait; @@ -45,7 +45,7 @@ static u64 get_iowait_time(int cpu) #else -static u64 get_idle_time(int cpu) +u64 get_idle_time(int cpu) { u64 idle, idle_usecs = -1ULL; @@ -61,7 +61,7 @@ static u64 get_idle_time(int cpu) return idle; } -static u64 get_iowait_time(int cpu) +u64 get_iowait_time(int cpu) { u64 iowait, iowait_usecs = -1ULL; diff --git a/fs/proc/task_cpustats b/fs/proc/task_cpustats new file mode 120000 index 000000000000..a7fe8a99d553 --- /dev/null +++ b/fs/proc/task_cpustats @@ -0,0 +1 @@ +../../../../vendor/oplus/kernel/oplus_performance/task_cpustats \ No newline at end of file diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c index 470455388dfc..ba28c216b25c 100644 --- a/fs/proc/task_mmu.c +++ b/fs/proc/task_mmu.c @@ -850,6 +850,24 @@ static int show_smap(struct seq_file *m, void *v) smap_gather_stats(vma, &mss); + #ifdef OPLUS_FEATURE_PERFORMANCE + if (strcmp(current->comm, "android.bg") == 0) { + if ((unsigned long)(mss.pss >> (10 + PSS_SHIFT)) > 0) { + SEQ_PUT_DEC(" kB\nPss: ", mss.pss >> PSS_SHIFT); + } + if ((mss.private_clean >> 10) > 0) { + SEQ_PUT_DEC(" kB\nPrivate_Clean: ", mss.private_clean); + } + if ((mss.private_dirty >> 10) > 0) { + SEQ_PUT_DEC(" kB\nPrivate_Dirty: ", mss.private_dirty); + } + + seq_puts(m, " kB\n"); + m_cache_vma(m, vma); + return 0; + } + #endif /*OPLUS_FEATURE_PERFORMANCE*/ + show_map_vma(m, vma); if (vma_get_anon_name(vma)) { seq_puts(m, "Name: "); @@ -1727,7 +1745,14 @@ int reclaim_address_space(struct address_space *mapping, } } rcu_read_unlock(); - reclaimed = reclaim_pages_from_list(&page_list, NULL); +#if defined(OPLUS_FEATURE_PROCESS_RECLAIM) && defined(CONFIG_PROCESS_RECLAIM_ENHANCE) + /* relciam memory with scan walk info + * while PROCESS_RECLAIM_ENHANCE is enabled. + */ + reclaimed = reclaimed = reclaim_pages_from_list(&page_list, NULL, NULL); +#else + reclaimed = reclaimed = reclaim_pages_from_list(&page_list, NULL); +#endif rp->nr_reclaimed += reclaimed; if (rp->nr_scanned >= rp->nr_to_reclaim) @@ -1787,7 +1812,12 @@ cont: break; } pte_unmap_unlock(pte - 1, ptl); +#if defined(OPLUS_FEATURE_PROCESS_RECLAIM) && defined(CONFIG_PROCESS_RECLAIM_ENHANCE) + reclaimed = reclaim_pages_from_list(&page_list, vma, NULL); +#else reclaimed = reclaim_pages_from_list(&page_list, vma); +#endif + rp->nr_reclaimed += reclaimed; rp->nr_to_reclaim -= reclaimed; if (rp->nr_to_reclaim < 0) diff --git a/fs/proc/va_feature_node.h b/fs/proc/va_feature_node.h new file mode 120000 index 000000000000..d63f0af85d25 --- /dev/null +++ b/fs/proc/va_feature_node.h @@ -0,0 +1 @@ +../../../../vendor/oplus/kernel/oplus_performance/gloom_new/va_feature_node.h \ No newline at end of file diff --git a/fs/pstore/inode.c b/fs/pstore/inode.c index 6f51c6d7b965..6627adb60652 100644 --- a/fs/pstore/inode.c +++ b/fs/pstore/inode.c @@ -372,6 +372,11 @@ int pstore_mkfile(struct dentry *root, struct pstore_record *record) scnprintf(name, sizeof(name), "powerpc-opal-%s-%llu", record->psi->name, record->id); break; +#ifdef OPLUS_FEATURE_DUMPDEVICE + case PSTORE_TYPE_DEVICE_INFO: + scnprintf(name, sizeof(name), "device-info-%s-%lld", record->psi->name, record->id); + break; +#endif case PSTORE_TYPE_UNKNOWN: scnprintf(name, sizeof(name), "unknown-%s-%llu", record->psi->name, record->id); diff --git a/fs/pstore/platform.c b/fs/pstore/platform.c index 904c2a60f5ba..52802b1ed6f8 100644 --- a/fs/pstore/platform.c +++ b/fs/pstore/platform.c @@ -491,7 +491,35 @@ static void pstore_console_write(struct console *con, const char *s, unsigned c) record.size = c; psinfo->write(&record); } +#ifdef OPLUS_FEATURE_DUMPDEVICE +static void pstore_console_init(void ) +{ + size_t oldsize; + size_t size =0; + struct ramoops_context *cxt = psinfo->data; + struct pstore_record record; + if (psinfo == NULL) + return; + + size = cxt->console_size; + + pstore_record_init(&record, psinfo); + record.type = PSTORE_TYPE_CONSOLE; + record.buf = psinfo->buf; + record.size = size; + + oldsize = psinfo->bufsize; + + if (size > psinfo->bufsize) + size = psinfo->bufsize; + memset(record.buf, ' ', size); + + psinfo->write(&record); + + psinfo->bufsize = oldsize ; +} +#endif static struct console pstore_console = { .name = "pstore", .write = pstore_console_write, @@ -501,6 +529,10 @@ static struct console pstore_console = { static void pstore_register_console(void) { +#ifdef OPLUS_FEATURE_DUMPDEVICE + /*pstore memset befor use*/ + pstore_console_init(); +#endif register_console(&pstore_console); } diff --git a/fs/pstore/ram.c b/fs/pstore/ram.c index bafbab2dd039..20aa75295845 100644 --- a/fs/pstore/ram.c +++ b/fs/pstore/ram.c @@ -52,6 +52,12 @@ static ulong ramoops_ftrace_size = MIN_MEM_SIZE; module_param_named(ftrace_size, ramoops_ftrace_size, ulong, 0400); MODULE_PARM_DESC(ftrace_size, "size of ftrace log"); +#ifdef OPLUS_FEATURE_DUMPDEVICE +static ulong ramoops_device_info_size = MIN_MEM_SIZE; +module_param_named(device_info_size, ramoops_device_info_size, ulong, 0400); +MODULE_PARM_DESC(device_info_size, "size of device info"); +#endif /* OPLUS_FEATURE_DUMPDEVICE */ + static ulong ramoops_pmsg_size = MIN_MEM_SIZE; module_param_named(pmsg_size, ramoops_pmsg_size, ulong, 0400); MODULE_PARM_DESC(pmsg_size, "size of user space message log"); @@ -82,7 +88,8 @@ MODULE_PARM_DESC(ramoops_ecc, "if non-zero, the option enables ECC support and specifies " "ECC buffer size in bytes (1 is a special value, means 16 " "bytes ECC)"); - +#ifndef OPLUS_FEATURE_DUMPDEVICE +/*move this define to pstore.h*/ struct ramoops_context { struct persistent_ram_zone **dprzs; /* Oops dump zones */ struct persistent_ram_zone *cprz; /* Console zone */ @@ -106,8 +113,10 @@ struct ramoops_context { unsigned int max_ftrace_cnt; unsigned int ftrace_read_cnt; unsigned int pmsg_read_cnt; + struct pstore_info pstore; }; +#endif static struct platform_device *dummy; static struct ramoops_platform_data *dummy_data; @@ -120,6 +129,9 @@ static int ramoops_pstore_open(struct pstore_info *psi) cxt->console_read_cnt = 0; cxt->ftrace_read_cnt = 0; cxt->pmsg_read_cnt = 0; +#ifdef OPLUS_FEATURE_DUMPDEVICE + cxt->device_info_read_cnt = 0; +#endif /* OPLUS_FEATURE_DUMPDEVICE */ return 0; } @@ -284,6 +296,13 @@ static ssize_t ramoops_pstore_read(struct pstore_record *record) 1, &record->id, &record->type, PSTORE_TYPE_PMSG, 0); +#ifdef OPLUS_FEATURE_DUMPDEVICE + if (!prz_ok(prz)) + prz = ramoops_get_next_prz(&cxt->dprz, &cxt->device_info_read_cnt, + 1, &record->id, &record->type, + PSTORE_TYPE_DEVICE_INFO, 0); +#endif /* OPLUS_FEATURE_DUMPDEVICE */ + /* ftrace is last since it may want to dynamically allocate memory. */ if (!prz_ok(prz)) { if (!(cxt->flags & RAMOOPS_FLAG_FTRACE_PER_CPU)) { @@ -301,7 +320,6 @@ static ssize_t ramoops_pstore_read(struct pstore_record *record) GFP_KERNEL); if (!tmp_prz) return -ENOMEM; - prz = tmp_prz; free_prz = true; while (cxt->ftrace_read_cnt < cxt->max_ftrace_cnt) { @@ -324,6 +342,7 @@ static ssize_t ramoops_pstore_read(struct pstore_record *record) goto out; } record->id = 0; + prz = tmp_prz; } } @@ -406,6 +425,13 @@ static int notrace ramoops_pstore_write(struct pstore_record *record) } else if (record->type == PSTORE_TYPE_PMSG) { pr_warn_ratelimited("PMSG shouldn't call %s\n", __func__); return -EINVAL; +#ifdef OPLUS_FEATURE_DUMPDEVICE + } else if (record->type == PSTORE_TYPE_DEVICE_INFO) { + if (!cxt->dprz) + return -ENOMEM; + persistent_ram_write(cxt->dprz, record->buf, record->size); + return 0; +#endif /* OPLUS_FEATURE_DUMPDEVICE */ } if (record->type != PSTORE_TYPE_DMESG) @@ -437,17 +463,6 @@ static int notrace ramoops_pstore_write(struct pstore_record *record) prz = cxt->dprzs[cxt->dump_write_cnt]; - /* - * Since this is a new crash dump, we need to reset the buffer in - * case it still has an old dump present. Without this, the new dump - * will get appended, which would seriously confuse anything trying - * to check dump file contents. Specifically, ramoops_read_kmsg_hdr() - * expects to find a dump header in the beginning of buffer data, so - * we must to reset the buffer values, in order to ensure that the - * header will be written to the beginning of the buffer. - */ - persistent_ram_zap(prz); - /* Build header and append record contents. */ hlen = ramoops_write_kmsg_hdr(prz, record); size = record->size; @@ -496,6 +511,11 @@ static int ramoops_pstore_erase(struct pstore_record *record) case PSTORE_TYPE_PMSG: prz = cxt->mprz; break; +#ifdef OPLUS_FEATURE_DUMPDEVICE + case PSTORE_TYPE_DEVICE_INFO: + prz = cxt->dprz; + break; +#endif /* OPLUS_FEATURE_DUMPDEVICE */ default: return -EINVAL; } @@ -714,6 +734,9 @@ static int ramoops_parse_dt(struct platform_device *pdev, parse_size("console-size", pdata->console_size); parse_size("ftrace-size", pdata->ftrace_size); parse_size("pmsg-size", pdata->pmsg_size); +#ifdef OPLUS_FEATURE_DUMPDEVICE + parse_size("devinfo-size", pdata->device_info_size); +#endif /* OPLUS_FEATURE_DUMPDEVICE */ parse_size("ecc-size", pdata->ecc_info.ecc_size); parse_size("flags", pdata->flags); @@ -757,7 +780,9 @@ static int ramoops_probe(struct platform_device *pdev) } if (!pdata->mem_size || (!pdata->record_size && !pdata->console_size && - !pdata->ftrace_size && !pdata->pmsg_size)) { +#ifdef OPLUS_FEATURE_DUMPDEVICE + !pdata->ftrace_size && !pdata->pmsg_size && !pdata->device_info_size)) { +#endif /* OPLUS_FEATURE_DUMPDEVICE */ pr_err("The memory size and the record/console size must be " "non-zero\n"); goto fail_out; @@ -771,6 +796,10 @@ static int ramoops_probe(struct platform_device *pdev) pdata->ftrace_size = rounddown_pow_of_two(pdata->ftrace_size); if (pdata->pmsg_size && !is_power_of_2(pdata->pmsg_size)) pdata->pmsg_size = rounddown_pow_of_two(pdata->pmsg_size); +#ifdef OPLUS_FEATURE_DUMPDEVICE + if (pdata->device_info_size && !is_power_of_2(pdata->device_info_size)) + pdata->device_info_size = rounddown_pow_of_two(pdata->device_info_size); +#endif /* OPLUS_FEATURE_DUMPDEVICE */ cxt->size = pdata->mem_size; cxt->phys_addr = pdata->mem_address; @@ -782,11 +811,16 @@ static int ramoops_probe(struct platform_device *pdev) cxt->dump_oops = pdata->dump_oops; cxt->flags = pdata->flags; cxt->ecc_info = pdata->ecc_info; +#ifdef OPLUS_FEATURE_DUMPDEVICE + cxt->device_info_size = pdata->device_info_size; +#endif /* OPLUS_FEATURE_DUMPDEVICE */ paddr = cxt->phys_addr; dump_mem_sz = cxt->size - cxt->console_size - cxt->ftrace_size - - cxt->pmsg_size; +#ifdef OPLUS_FEATURE_DUMPDEVICE + - cxt->pmsg_size - cxt->device_info_size; +#endif /* OPLUS_FEATURE_DUMPDEVICE */ err = ramoops_init_przs("dump", dev, cxt, &cxt->dprzs, &paddr, dump_mem_sz, cxt->record_size, &cxt->max_dump_cnt, 0, 0); @@ -813,7 +847,13 @@ static int ramoops_probe(struct platform_device *pdev) cxt->pmsg_size, 0); if (err) goto fail_init_mprz; - + +#ifdef OPLUS_FEATURE_DUMPDEVICE + err = ramoops_init_prz("devinfo", dev, cxt, &cxt->dprz, &paddr, + cxt->device_info_size, 0); + if (err) + goto fail_init_dprz; +#endif /* OPLUS_FEATURE_DUMPDEVICE */ cxt->pstore.data = cxt; /* * Prepare frontend flags based on which areas are initialized. @@ -864,6 +904,10 @@ static int ramoops_probe(struct platform_device *pdev) ramoops_pmsg_size = pdata->pmsg_size; ramoops_ftrace_size = pdata->ftrace_size; +#ifdef OPLUS_FEATURE_DUMPDEVICE + ramoops_device_info_size = pdata->device_info_size; +#endif /* OPLUS_FEATURE_DUMPDEVICE */ + pr_info("attached 0x%lx@0x%llx, ecc: %d/%d\n", cxt->size, (unsigned long long)cxt->phys_addr, cxt->ecc_info.ecc_size, cxt->ecc_info.block_size); @@ -875,6 +919,10 @@ fail_buf: fail_clear: cxt->pstore.bufsize = 0; persistent_ram_free(cxt->mprz); +#ifdef OPLUS_FEATURE_DUMPDEVICE +fail_init_dprz: + persistent_ram_free(cxt->dprz); +#endif /* OPLUS_FEATURE_DUMPDEVICE */ fail_init_mprz: fail_init_fprz: persistent_ram_free(cxt->cprz); @@ -895,6 +943,9 @@ static int ramoops_remove(struct platform_device *pdev) persistent_ram_free(cxt->mprz); persistent_ram_free(cxt->cprz); +#ifdef OPLUS_FEATURE_DUMPDEVICE + persistent_ram_free(cxt->dprz); +#endif /* OPLUS_FEATURE_DUMPDEVICE */ ramoops_free_przs(cxt); return 0; @@ -947,6 +998,9 @@ static void __init ramoops_register_dummy(void) dummy_data->record_size = record_size; dummy_data->console_size = ramoops_console_size; dummy_data->ftrace_size = ramoops_ftrace_size; +#ifdef OPLUS_FEATURE_DUMPDEVICE + dummy_data->device_info_size = ramoops_device_info_size; +#endif /* OPLUS_FEATURE_DUMPDEVICE */ dummy_data->pmsg_size = ramoops_pmsg_size; dummy_data->dump_oops = dump_oops; dummy_data->flags = RAMOOPS_FLAG_FTRACE_PER_CPU; diff --git a/fs/read_write.c b/fs/read_write.c index 650fc7e0f3a6..c90cfb8de203 100644 --- a/fs/read_write.c +++ b/fs/read_write.c @@ -24,6 +24,12 @@ #include #include +#if defined(OPLUS_FEATURE_IOMONITOR) && defined(CONFIG_IOMONITOR) +#include +#include +DEFINE_TRACE(syscall_read_timeout); +DEFINE_TRACE(syscall_write_timeout); +#endif /*OPLUS_FEATURE_IOMONITOR*/ const struct file_operations generic_ro_fops = { .llseek = generic_file_llseek, @@ -430,6 +436,9 @@ ssize_t kernel_read(struct file *file, void *buf, size_t count, loff_t *pos) /* The cast to a user pointer is valid due to the set_fs() */ result = vfs_read(file, (void __user *)buf, count, pos); set_fs(old_fs); +#if defined(OPLUS_FEATURE_IOMONITOR) && defined(CONFIG_IOMONITOR) + iomonitor_update_rw_stats(KERNEL_READ, file, result); +#endif /*OPLUS_FEATURE_IOMONITOR*/ return result; } EXPORT_SYMBOL(kernel_read); @@ -510,6 +519,11 @@ ssize_t __kernel_write(struct file *file, const void *buf, size_t count, loff_t fsnotify_modify(file); add_wchar(current, ret); } +#if defined(OPLUS_FEATURE_IOMONITOR) && defined(CONFIG_IOMONITOR) + if(ret > 0) { + iomonitor_update_rw_stats(KERNEL_WRITE, file, ret); + } +#endif /*OPLUS_FEATURE_IOMONITOR*/ inc_syscw(current); return ret; } @@ -526,7 +540,9 @@ ssize_t kernel_write(struct file *file, const void *buf, size_t count, /* The cast to a user pointer is valid due to the set_fs() */ res = vfs_write(file, (__force const char __user *)buf, count, pos); set_fs(old_fs); - +#if defined(OPLUS_FEATURE_IOMONITOR) && defined(CONFIG_IOMONITOR) + iomonitor_update_rw_stats(KERNEL_WRITE, file, res); +#endif /*OPLUS_FEATURE_IOMONITOR*/ return res; } EXPORT_SYMBOL(kernel_write); @@ -575,12 +591,20 @@ ssize_t ksys_read(unsigned int fd, char __user *buf, size_t count) { struct fd f = fdget_pos(fd); ssize_t ret = -EBADF; - +#if defined(OPLUS_FEATURE_IOMONITOR) && defined(CONFIG_IOMONITOR) + unsigned long read_time = jiffies; +#endif /*OPLUS_FEATURE_IOMONITOR*/ if (f.file) { loff_t pos = file_pos_read(f.file); ret = vfs_read(f.file, buf, count, &pos); if (ret >= 0) file_pos_write(f.file, pos); +#if defined(OPLUS_FEATURE_IOMONITOR) && defined(CONFIG_IOMONITOR) + if (ret > 0) { + iomonitor_update_rw_stats(USER_READ, f.file, ret); + trace_syscall_read_timeout(f.file, jiffies_to_msecs(jiffies - read_time)); + } +#endif /*OPLUS_FEATURE_IOMONITOR*/ fdput_pos(f); } return ret; @@ -595,12 +619,20 @@ ssize_t ksys_write(unsigned int fd, const char __user *buf, size_t count) { struct fd f = fdget_pos(fd); ssize_t ret = -EBADF; - +#if defined(OPLUS_FEATURE_IOMONITOR) && defined(CONFIG_IOMONITOR) + unsigned long write_time = jiffies; +#endif /*OPLUS_FEATURE_IOMONITOR*/ if (f.file) { loff_t pos = file_pos_read(f.file); ret = vfs_write(f.file, buf, count, &pos); if (ret >= 0) file_pos_write(f.file, pos); +#if defined(OPLUS_FEATURE_IOMONITOR) && defined(CONFIG_IOMONITOR) + if (ret > 0) { + iomonitor_update_rw_stats(USER_WRITE, f.file, ret); + trace_syscall_write_timeout(f.file, jiffies_to_msecs(jiffies - write_time)); + } +#endif /*OPLUS_FEATURE_IOMONITOR*/ fdput_pos(f); } @@ -629,7 +661,10 @@ ssize_t ksys_pread64(unsigned int fd, char __user *buf, size_t count, ret = vfs_read(f.file, buf, count, &pos); fdput(f); } - +#if defined(OPLUS_FEATURE_IOMONITOR) && defined(CONFIG_IOMONITOR) + if (ret > 0) + iomonitor_update_rw_stats(USER_READ, f.file, ret); +#endif /*OPLUS_FEATURE_IOMONITOR*/ return ret; } @@ -655,7 +690,10 @@ ssize_t ksys_pwrite64(unsigned int fd, const char __user *buf, ret = vfs_write(f.file, buf, count, &pos); fdput(f); } - +#if defined(OPLUS_FEATURE_IOMONITOR) && defined(CONFIG_IOMONITOR) + if (ret > 0) + iomonitor_update_rw_stats(USER_WRITE, f.file, ret); +#endif /*OPLUS_FEATURE_IOMONITOR*/ return ret; } @@ -1027,6 +1065,10 @@ static ssize_t do_readv(unsigned long fd, const struct iovec __user *vec, if (ret > 0) add_rchar(current, ret); +#if defined(OPLUS_FEATURE_IOMONITOR) && defined(CONFIG_IOMONITOR) + if (ret > 0) + iomonitor_update_rw_stats(USER_READ, f.file, ret); +#endif /*OPLUS_FEATURE_IOMONITOR*/ inc_syscr(current); return ret; } @@ -1047,6 +1089,10 @@ static ssize_t do_writev(unsigned long fd, const struct iovec __user *vec, if (ret > 0) add_wchar(current, ret); +#if defined(OPLUS_FEATURE_IOMONITOR) && defined(CONFIG_IOMONITOR) + if (ret > 0) + iomonitor_update_rw_stats(USER_WRITE, f.file, ret); +#endif /*OPLUS_FEATURE_IOMONITOR*/ inc_syscw(current); return ret; } @@ -1076,6 +1122,10 @@ static ssize_t do_preadv(unsigned long fd, const struct iovec __user *vec, if (ret > 0) add_rchar(current, ret); +#if defined(OPLUS_FEATURE_IOMONITOR) && defined(CONFIG_IOMONITOR) + if (ret > 0) + iomonitor_update_rw_stats(USER_READ, f.file, ret); +#endif /*OPLUS_FEATURE_IOMONITOR*/ inc_syscr(current); return ret; } @@ -1099,6 +1149,10 @@ static ssize_t do_pwritev(unsigned long fd, const struct iovec __user *vec, if (ret > 0) add_wchar(current, ret); +#if defined(OPLUS_FEATURE_IOMONITOR) && defined(CONFIG_IOMONITOR) + if (ret > 0) + iomonitor_update_rw_stats(USER_WRITE, f.file, ret); +#endif /*OPLUS_FEATURE_IOMONITOR*/ inc_syscw(current); return ret; } @@ -1172,6 +1226,10 @@ static size_t compat_readv(struct file *file, } if (ret > 0) add_rchar(current, ret); +#if defined(OPLUS_FEATURE_IOMONITOR) && defined(CONFIG_IOMONITOR) + if (ret > 0) + iomonitor_update_rw_stats(USER_READ, file, ret); +#endif /*OPLUS_FEATURE_IOMONITOR*/ inc_syscr(current); return ret; } @@ -1282,6 +1340,10 @@ static size_t compat_writev(struct file *file, } if (ret > 0) add_wchar(current, ret); +#if defined(OPLUS_FEATURE_IOMONITOR) && defined(CONFIG_IOMONITOR) + if (ret > 0) + iomonitor_update_rw_stats(USER_WRITE, file, ret); +#endif /*OPLUS_FEATURE_IOMONITOR*/ inc_syscw(current); return ret; } @@ -1460,7 +1522,12 @@ static ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos, else in.file->f_pos = pos; } - +#if defined(OPLUS_FEATURE_IOMONITOR) && defined(CONFIG_IOMONITOR) + if (retval > 0) { + iomonitor_update_rw_stats(USER_READ, in.file, retval); + iomonitor_update_rw_stats(USER_WRITE,in.file, retval); + } +#endif /*OPLUS_FEATURE_IOMONITOR*/ inc_syscr(current); inc_syscw(current); if (pos > max) @@ -1623,7 +1690,12 @@ done: fsnotify_modify(file_out); add_wchar(current, ret); } - +#if defined(OPLUS_FEATURE_IOMONITOR) && defined(CONFIG_IOMONITOR) + if (ret > 0) { + iomonitor_update_rw_stats(USER_READ, file_in, ret); + iomonitor_update_rw_stats(USER_WRITE,file_in, ret); + } +#endif /*OPLUS_FEATURE_IOMONITOR*/ inc_syscr(current); inc_syscw(current); diff --git a/fs/sdcardfs/file.c b/fs/sdcardfs/file.c index 271c4c4cb760..1094b5b9b2bf 100644 --- a/fs/sdcardfs/file.c +++ b/fs/sdcardfs/file.c @@ -236,6 +236,10 @@ static int sdcardfs_open(struct inode *inode, struct file *file) struct dentry *parent = dget_parent(dentry); struct sdcardfs_sb_info *sbi = SDCARDFS_SB(dentry->d_sb); const struct cred *saved_cred = NULL; +#ifdef CONFIG_OPLUS_FEATURE_FUSE_FS_SHORTCIRCUIT + struct fuse_package *fp = current->fpack; + char *iname; +#endif /* CONFIG_OPLUS_FEATURE_FUSE_FS_SHORTCIRCUIT */ /* don't open unhashed/deleted files */ if (d_unhashed(dentry)) { @@ -275,6 +279,17 @@ static int sdcardfs_open(struct inode *inode, struct file *file) } } else { sdcardfs_set_lower_file(file, lower_file); +#ifdef CONFIG_OPLUS_FEATURE_FUSE_FS_SHORTCIRCUIT + if (!err && fp && fp->fuse_open_req && !fp->filp && fp->iname) { + iname = inode_name(inode); + if (iname && !strcasecmp(iname, fp->iname)) { + fp->filp = file; + get_file(file); + } + if (iname) + __putname(iname); + } +#endif /* CONFIG_OPLUS_FEATURE_FUSE_FS_SHORTCIRCUIT */ } if (err) diff --git a/fs/sdcardfs/main.c b/fs/sdcardfs/main.c index cb668f72ee23..ebb977196b8d 100644 --- a/fs/sdcardfs/main.c +++ b/fs/sdcardfs/main.c @@ -165,7 +165,7 @@ int parse_options_remount(struct super_block *sb, char *options, int silent, char *p; substring_t args[MAX_OPT_ARGS]; int option; - int debug; + int debug = 0; if (!options) return 0; diff --git a/fs/sync.c b/fs/sync.c index 055daab8652a..74345e23124a 100644 --- a/fs/sync.c +++ b/fs/sync.c @@ -17,6 +17,17 @@ #include #include #include "internal.h" +#ifdef OPLUS_FEATURE_HEALTHINFO +// Add for get cpu load +#ifdef CONFIG_OPLUS_HEALTHINFO +#include +#endif +#endif /* OPLUS_FEATURE_HEALTHINFO */ +#if defined(OPLUS_FEATURE_IOMONITOR) && defined(CONFIG_IOMONITOR) +#include +#include +DEFINE_TRACE(syscall_sync_timeout); +#endif /*OPLUS_FEATURE_IOMONITOR*/ #define VALID_FLAGS (SYNC_FILE_RANGE_WAIT_BEFORE|SYNC_FILE_RANGE_WRITE| \ SYNC_FILE_RANGE_WAIT_AFTER) @@ -216,12 +227,27 @@ static int do_fsync(unsigned int fd, int datasync) { struct fd f = fdget(fd); int ret = -EBADF; - +#ifdef OPLUS_FEATURE_HEALTHINFO +// Add for record fsync time +#ifdef CONFIG_OPLUS_HEALTHINFO + unsigned long fsync_time = jiffies; +#endif +#endif /* OPLUS_FEATURE_HEALTHINFO */ if (f.file) { ret = vfs_fsync(f.file, datasync); fdput(f); +#if defined(OPLUS_FEATURE_IOMONITOR) && defined(CONFIG_IOMONITOR) && defined(CONFIG_OPLUS_HEALTHINFO) + iomonitor_update_fs_stats(FS_FSYNC, 1); + trace_syscall_sync_timeout(f.file, jiffies_to_msecs(jiffies - fsync_time)); +#endif /*OPLUS_FEATURE_IOMONITOR & CONFIG_OPLUS_HEALTHINFO*/ inc_syscfs(current); } +#ifdef OPLUS_FEATURE_HEALTHINFO +// Add for record fsync time +#ifdef CONFIG_OPLUS_HEALTHINFO + ohm_schedstats_record(OHM_SCHED_FSYNC, current, jiffies_to_msecs(jiffies - fsync_time)); +#endif +#endif /* OPLUS_FEATURE_HEALTHINFO */ return ret; } diff --git a/fs/xattr.c b/fs/xattr.c index e1f041e9b3b0..cd07a9c11d05 100644 --- a/fs/xattr.c +++ b/fs/xattr.c @@ -265,7 +265,10 @@ retry_deleg: } EXPORT_SYMBOL_GPL(vfs_setxattr); -static ssize_t +#ifndef OPLUS_FEATURE_SDCARDFS_SUPPORT +static +#endif +ssize_t xattr_getsecurity(struct inode *inode, const char *name, void *value, size_t size) { @@ -290,7 +293,9 @@ out: out_noalloc: return len; } - +#ifdef OPLUS_FEATURE_SDCARDFS_SUPPORT +EXPORT_SYMBOL_GPL(xattr_getsecurity); +#endif /* * vfs_getxattr_alloc - allocate memory, if necessary, before calling getxattr * diff --git a/gen_headers_arm.bp b/gen_headers_arm.bp index 2894fb4a72f1..6b7458e650c4 100644 --- a/gen_headers_arm.bp +++ b/gen_headers_arm.bp @@ -109,6 +109,7 @@ gen_headers_out_arm = [ "drm/via_drm.h", "drm/virtgpu_drm.h", "drm/vmwgfx_drm.h", + "drm/msm_drm_iris.h", "linux/acct.h", "linux/adb.h", "linux/adfs_fs.h", diff --git a/gen_headers_arm64.bp b/gen_headers_arm64.bp index f90c1b771b13..3cd6ecbe4997 100644 --- a/gen_headers_arm64.bp +++ b/gen_headers_arm64.bp @@ -104,6 +104,7 @@ gen_headers_out_arm64 = [ "drm/via_drm.h", "drm/virtgpu_drm.h", "drm/vmwgfx_drm.h", + "drm/msm_drm_iris.h", "linux/acct.h", "linux/adb.h", "linux/adfs_fs.h", diff --git a/include/asm-generic/pgtable.h b/include/asm-generic/pgtable.h index 1544331bec27..cfb1ee2b14f0 100644 --- a/include/asm-generic/pgtable.h +++ b/include/asm-generic/pgtable.h @@ -74,7 +74,7 @@ static inline int ptep_test_and_clear_young(struct vm_area_struct *vma, #endif #ifndef __HAVE_ARCH_PMDP_TEST_AND_CLEAR_YOUNG -#ifdef CONFIG_TRANSPARENT_HUGEPAGE +#if defined(CONFIG_TRANSPARENT_HUGEPAGE) || defined(CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG) static inline int pmdp_test_and_clear_young(struct vm_area_struct *vma, unsigned long address, pmd_t *pmdp) @@ -95,7 +95,7 @@ static inline int pmdp_test_and_clear_young(struct vm_area_struct *vma, BUILD_BUG(); return 0; } -#endif /* CONFIG_TRANSPARENT_HUGEPAGE */ +#endif /* CONFIG_TRANSPARENT_HUGEPAGE || CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG */ #endif #ifndef __HAVE_ARCH_PTEP_CLEAR_YOUNG_FLUSH @@ -121,6 +121,19 @@ static inline int pmdp_clear_flush_young(struct vm_area_struct *vma, #endif /* CONFIG_TRANSPARENT_HUGEPAGE */ #endif +#ifndef arch_has_hw_pte_young +/* + * Return whether the accessed bit is supported on the local CPU. + * + * This stub assumes accessing through an old PTE triggers a page fault. + * Architectures that automatically set the access bit should overwrite it. + */ +static inline bool arch_has_hw_pte_young(void) +{ + return false; +} +#endif + #ifndef __HAVE_ARCH_PTEP_GET_AND_CLEAR static inline pte_t ptep_get_and_clear(struct mm_struct *mm, unsigned long address, diff --git a/include/linux/acm_fs.h b/include/linux/acm_fs.h new file mode 100644 index 000000000000..2184fb4b21b1 --- /dev/null +++ b/include/linux/acm_fs.h @@ -0,0 +1,6 @@ +#ifndef __ACM_FS_H__ +#define __ACM_FS_H__ + +int monitor_acm2(struct dentry *dentry, struct dentry *dentry2, int op); + +#endif /* __ACM_FS_H__ */ diff --git a/include/linux/backing-dev-defs.h b/include/linux/backing-dev-defs.h index 07e02d6df5ad..57c8ec1f25c9 100644 --- a/include/linux/backing-dev-defs.h +++ b/include/linux/backing-dev-defs.h @@ -210,6 +210,12 @@ struct backing_dev_info { enum { BLK_RW_ASYNC = 0, BLK_RW_SYNC = 1, +#ifdef OPLUS_FEATURE_HEALTHINFO +// Add for ioqueue + BLK_RW_UX = 2, + BLK_RW_FG = 3, + BLK_RW_BG = 4, +#endif /* OPLUS_FEATURE_HEALTHINFO */ }; void clear_wb_congested(struct bdi_writeback_congested *congested, int sync); diff --git a/include/linux/blk_types.h b/include/linux/blk_types.h index fd69cfdc2081..b2f83e651045 100644 --- a/include/linux/blk_types.h +++ b/include/linux/blk_types.h @@ -334,6 +334,10 @@ enum req_flag_bits { __REQ_INTEGRITY, /* I/O includes block integrity payload */ __REQ_FUA, /* forced unit access */ __REQ_PREFLUSH, /* request for cache flush */ +#ifdef OPLUS_FEATURE_SCHED_ASSIST + __REQ_UX, /* ux activity */ + __REQ_FG, /* foreground activity */ +#endif __REQ_RAHEAD, /* read ahead, can fail anytime */ __REQ_BACKGROUND, /* background IO */ __REQ_NOWAIT, /* Don't wait if request will block */ @@ -361,6 +365,10 @@ enum req_flag_bits { #define REQ_INTEGRITY (1ULL << __REQ_INTEGRITY) #define REQ_FUA (1ULL << __REQ_FUA) #define REQ_PREFLUSH (1ULL << __REQ_PREFLUSH) +#ifdef OPLUS_FEATURE_SCHED_ASSIST +#define REQ_UX (1ULL << __REQ_UX) +#define REQ_FG (1ULL << __REQ_FG) +#endif #define REQ_RAHEAD (1ULL << __REQ_RAHEAD) #define REQ_BACKGROUND (1ULL << __REQ_BACKGROUND) #define REQ_NOWAIT (1ULL << __REQ_NOWAIT) diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 5e5f600ba5d0..0b2b2ca8a681 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -165,7 +165,12 @@ struct request { int cpu; unsigned int cmd_flags; /* op and common flags */ req_flags_t rq_flags; - +#if defined(OPLUS_FEATURE_IOMONITOR) && defined(CONFIG_IOMONITOR) + ktime_t req_tg; + ktime_t req_ti; + ktime_t req_td; + ktime_t req_tc; +#endif /*OPLUS_FEATURE_IOMONITOR*/ int internal_tag; /* the following two fields are internal, NEVER access directly */ @@ -177,7 +182,9 @@ struct request { struct bio *biotail; struct list_head queuelist; - +#if defined(OPLUS_FEATURE_SCHED_ASSIST) && defined(CONFIG_OPLUS_FEATURE_UXIO_FIRST) + struct list_head ux_fg_bg_list; +#endif /* * The hash is used inside the scheduler, and killed once the * request reaches the dispatch list. The ipi_list is only used @@ -353,6 +360,9 @@ struct blk_queue_tag { unsigned long *tag_map; /* bit map of free/busy tags */ int max_depth; /* what we will send to device */ int real_max_depth; /* what the array can hold */ +#if defined(OPLUS_FEATURE_SCHED_ASSIST) && defined(CONFIG_OPLUS_FEATURE_UXIO_FIRST) + int bg_max_depth; /* max depth for bg thread */ +#endif atomic_t refcnt; /* map can be shared */ int alloc_policy; /* tag allocation policy */ int next_tag; /* next tag */ @@ -446,6 +456,11 @@ struct request_queue { * Together with queue_head for cacheline sharing */ struct list_head queue_head; +#if defined(OPLUS_FEATURE_SCHED_ASSIST) && defined(CONFIG_OPLUS_FEATURE_UXIO_FIRST) + struct list_head ux_head; + struct list_head fg_head; + struct list_head bg_head; +#endif /*VENDOR*/ struct request *last_merge; struct elevator_queue *elevator; int nr_rqs[2]; /* # allocated [a]sync rqs */ @@ -577,8 +592,12 @@ struct request_queue { struct blk_queue_tag *queue_tags; unsigned int nr_sorted; +#if !defined (OPLUS_FEATURE_HEALTHINFO) && !defined (CONFIG_OPLUS_HEALTHINFO) +// Modify for ioqueue unsigned int in_flight[2]; - +#else /* OPLUS_FEATURE_HEALTHINFO && CONFIG_OPLUS_HEALTHINFO */ + unsigned int in_flight[5]; +#endif /* OPLUS_FEATURE_HEALTHINFO && CONFIG_OPLUS_HEALTHINFO*/ /* * Number of active block driver functions for which blk_drain_queue() * must wait. Must be incremented around functions that unlock the @@ -731,6 +750,24 @@ void blk_queue_flag_clear(unsigned int flag, struct request_queue *q); bool blk_queue_flag_test_and_set(unsigned int flag, struct request_queue *q); bool blk_queue_flag_test_and_clear(unsigned int flag, struct request_queue *q); +#if defined(OPLUS_FEATURE_SCHED_ASSIST) && defined(CONFIG_OPLUS_FEATURE_UXIO_FIRST) +extern void ohm_ioqueue_add_inflight(struct request_queue *q, + struct request *rq); +extern void ohm_ioqueue_dec_inflight(struct request_queue *q, + struct request *rq); +#else +static inline void ohm_ioqueue_add_inflight(struct request_queue *q, + struct request *rq) +{ + +} +static inline void ohm_ioqueue_dec_inflight(struct request_queue *q, + struct request *rq) +{ + +} +#endif /* OPLUS_FEATURE_HEALTHINFO */ + #define blk_queue_tagged(q) test_bit(QUEUE_FLAG_QUEUED, &(q)->queue_flags) #define blk_queue_stopped(q) test_bit(QUEUE_FLAG_STOPPED, &(q)->queue_flags) #define blk_queue_dying(q) test_bit(QUEUE_FLAG_DYING, &(q)->queue_flags) diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h index 0d9f2148cb3e..43fbb5adfc05 100644 --- a/include/linux/cgroup.h +++ b/include/linux/cgroup.h @@ -423,6 +423,18 @@ static inline void cgroup_put(struct cgroup *cgrp) css_put(&cgrp->self); } +extern struct mutex cgroup_mutex; + +static inline void cgroup_lock(void) +{ + mutex_lock(&cgroup_mutex); +} + +static inline void cgroup_unlock(void) +{ + mutex_unlock(&cgroup_mutex); +} + /** * task_css_set_check - obtain a task's css_set with extra access conditions * @task: the task to obtain css_set for @@ -437,7 +449,6 @@ static inline void cgroup_put(struct cgroup *cgrp) * as locks used during the cgroup_subsys::attach() methods. */ #ifdef CONFIG_PROVE_RCU -extern struct mutex cgroup_mutex; extern spinlock_t css_set_lock; #define task_css_set_check(task, __c) \ rcu_dereference_check((task)->cgroups, \ @@ -701,6 +712,8 @@ struct cgroup_subsys_state; struct cgroup; static inline void css_put(struct cgroup_subsys_state *css) {} +static inline void cgroup_lock(void) {} +static inline void cgroup_unlock(void) {} static inline int cgroup_attach_task_all(struct task_struct *from, struct task_struct *t) { return 0; } static inline int cgroupstats_build(struct cgroupstats *stats, diff --git a/include/linux/coresight.h b/include/linux/coresight.h index ec296134755d..e8374220ed29 100644 --- a/include/linux/coresight.h +++ b/include/linux/coresight.h @@ -325,22 +325,22 @@ static inline void coresight_abort(void) {} static inline void coresight_disable_reg_clk(struct coresight_device *csdev) {} static inline int coresight_enable_reg_clk(struct coresight_device *csdev) { return -EINVAL; } -static inline void coresight_disable_all_source_link(void) {}; -static inline void coresight_enable_all_source_link(void) {}; -static inline int coresight_claim_device_unlocked(void __iomem *base) +void coresight_disable_all_source_link(void) {}; +void coresight_enable_all_source_link(void) {}; +inline int coresight_claim_device_unlocked(void __iomem *base) { return -EINVAL; } -static inline int coresight_claim_device(void __iomem *base) +inline int coresight_claim_device(void __iomem *base) { return -EINVAL; } -static inline void coresight_disclaim_device(void __iomem *base) {} -static inline void coresight_disclaim_device_unlocked(void __iomem *base) {} +inline void coresight_disclaim_device(void __iomem *base) {} +inline void coresight_disclaim_device_unlocked(void __iomem *base) {} -static inline bool coresight_loses_context_with_cpu(struct device *dev) +inline bool coresight_loses_context_with_cpu(struct device *dev) { return false; } diff --git a/include/linux/cpu_jankinfo b/include/linux/cpu_jankinfo new file mode 120000 index 000000000000..ed2469f1bbbe --- /dev/null +++ b/include/linux/cpu_jankinfo @@ -0,0 +1 @@ +../../../../vendor/oplus/kernel/oplus_performance/cpu_jankinfo/ \ No newline at end of file diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h index 12cec9cd4dc0..87bdb5428c8b 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h @@ -151,6 +151,13 @@ struct cpufreq_policy { /* For cpufreq driver's internal use */ void *driver_data; +#ifdef OPLUS_FEATURE_HEALTHINFO +#ifdef CONFIG_OPLUS_HEALTHINFO + /* For get changed freq info */ + char change_comm[TASK_COMM_LEN]; + unsigned int org_max; +#endif +#endif /* OPLUS_FEATURE_HEALTHINFO */ }; /* Only for ACPI */ @@ -948,6 +955,10 @@ extern void arch_set_freq_scale(struct cpumask *cpus, unsigned long cur_freq, extern void arch_set_max_freq_scale(struct cpumask *cpus, unsigned long policy_max_freq); +#ifdef OPLUS_FEATURE_HEALTHINFO +struct list_head *get_cpufreq_policy_list(void); +#endif /* OPLUS_FEATURE_HEALTHINFO */ + /* the following are really really optional */ extern struct freq_attr cpufreq_freq_attr_scaling_available_freqs; extern struct freq_attr cpufreq_freq_attr_scaling_boost_freqs; diff --git a/include/linux/cpuset.h b/include/linux/cpuset.h index 7f1478c26a33..3cb8cddf7938 100644 --- a/include/linux/cpuset.h +++ b/include/linux/cpuset.h @@ -160,6 +160,14 @@ static inline void set_mems_allowed(nodemask_t nodemask) task_unlock(current); } +#ifdef CONFIG_OPLUS_FEATURE_UID_PERF +extern bool get_uid_perf_enable(void); +extern int get_cpuset_cgrp_idx_by_name(const char *name); +extern void cpuset_add_cg(int cgid, char* name); +extern int cpuset_get_cgrp_idx(struct task_struct *task); +extern int cpuset_get_cgrp_idx_locked(struct task_struct *task); +#endif + #else /* !CONFIG_CPUSETS */ static inline bool cpusets_enabled(void) { return false; } @@ -275,6 +283,14 @@ static inline bool read_mems_allowed_retry(unsigned int seq) return false; } +#ifdef CONFIG_OPLUS_FEATURE_UID_PERF +static inline bool get_uid_perf_enable(void) { return false; } +static inline int get_cpuset_cgrp_idx_by_name(const char *name) { return -1; } +static inline void cpuset_add_cg(int cgid, char* name) { return; } +static inline int cpuset_get_cgrp_idx(struct task_struct *task) { return -1; } +static inline int cpuset_get_cgrp_idx_locked(struct task_struct *task) { return -1; } +#endif + #endif /* !CONFIG_CPUSETS */ #endif /* _LINUX_CPUSET_H */ diff --git a/include/linux/damon.h b/include/linux/damon.h new file mode 100644 index 000000000000..96af9586f00d --- /dev/null +++ b/include/linux/damon.h @@ -0,0 +1,522 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * DAMON api + * + * Author: SeongJae Park + */ + +#ifndef _DAMON_H_ +#define _DAMON_H_ + +#include +#include +#include +#include + +/* Minimal region size. Every damon_region is aligned by this. */ +#define DAMON_MIN_REGION PAGE_SIZE +/* Max priority score for DAMON-based operation schemes */ +#define DAMOS_MAX_SCORE (99) + +/* Get a random number in [l, r) */ +static inline unsigned long damon_rand(unsigned long l, unsigned long r) +{ + return l + prandom_u32_max(r - l); +} + +/** + * struct damon_addr_range - Represents an address region of [@start, @end). + * @start: Start address of the region (inclusive). + * @end: End address of the region (exclusive). + */ +struct damon_addr_range { + unsigned long start; + unsigned long end; +}; + +/** + * struct damon_region - Represents a monitoring target region. + * @ar: The address range of the region. + * @sampling_addr: Address of the sample for the next access check. + * @nr_accesses: Access frequency of this region. + * @list: List head for siblings. + * @age: Age of this region. + * + * @age is initially zero, increased for each aggregation interval, and reset + * to zero again if the access frequency is significantly changed. If two + * regions are merged into a new region, both @nr_accesses and @age of the new + * region are set as region size-weighted average of those of the two regions. + */ +struct damon_region { + struct damon_addr_range ar; + unsigned long sampling_addr; + unsigned int nr_accesses; + struct list_head list; + + unsigned int age; +/* private: Internal value for age calculation. */ + unsigned int last_nr_accesses; +}; + +/** + * struct damon_target - Represents a monitoring target. + * @pid: The PID of the virtual address space to monitor. + * @nr_regions: Number of monitoring target regions of this target. + * @regions_list: Head of the monitoring target regions of this target. + * @list: List head for siblings. + * + * Each monitoring context could have multiple targets. For example, a context + * for virtual memory address spaces could have multiple target processes. The + * @pid should be set for appropriate &struct damon_operations including the + * virtual address spaces monitoring operations. + */ +struct damon_target { + struct pid *pid; + unsigned int nr_regions; + struct list_head regions_list; + struct list_head list; +}; + +/** + * enum damos_action - Represents an action of a Data Access Monitoring-based + * Operation Scheme. + * + * @DAMOS_WILLNEED: Call ``madvise()`` for the region with MADV_WILLNEED. + * @DAMOS_COLD: Call ``madvise()`` for the region with MADV_COLD. + * @DAMOS_PAGEOUT: Call ``madvise()`` for the region with MADV_PAGEOUT. + * @DAMOS_HUGEPAGE: Call ``madvise()`` for the region with MADV_HUGEPAGE. + * @DAMOS_NOHUGEPAGE: Call ``madvise()`` for the region with MADV_NOHUGEPAGE. + * @DAMOS_STAT: Do nothing but count the stat. + * @NR_DAMOS_ACTIONS: Total number of DAMOS actions + */ +enum damos_action { + DAMOS_WILLNEED, + DAMOS_COLD, + DAMOS_PAGEOUT, + DAMOS_HUGEPAGE, + DAMOS_NOHUGEPAGE, + DAMOS_STAT, /* Do nothing but only record the stat */ + NR_DAMOS_ACTIONS, +}; + +/** + * struct damos_quota - Controls the aggressiveness of the given scheme. + * @ms: Maximum milliseconds that the scheme can use. + * @sz: Maximum bytes of memory that the action can be applied. + * @reset_interval: Charge reset interval in milliseconds. + * + * @weight_sz: Weight of the region's size for prioritization. + * @weight_nr_accesses: Weight of the region's nr_accesses for prioritization. + * @weight_age: Weight of the region's age for prioritization. + * + * To avoid consuming too much CPU time or IO resources for applying the + * &struct damos->action to large memory, DAMON allows users to set time and/or + * size quotas. The quotas can be set by writing non-zero values to &ms and + * &sz, respectively. If the time quota is set, DAMON tries to use only up to + * &ms milliseconds within &reset_interval for applying the action. If the + * size quota is set, DAMON tries to apply the action only up to &sz bytes + * within &reset_interval. + * + * Internally, the time quota is transformed to a size quota using estimated + * throughput of the scheme's action. DAMON then compares it against &sz and + * uses smaller one as the effective quota. + * + * For selecting regions within the quota, DAMON prioritizes current scheme's + * target memory regions using the &struct damon_operations->get_scheme_score. + * You could customize the prioritization logic by setting &weight_sz, + * &weight_nr_accesses, and &weight_age, because monitoring operations are + * encouraged to respect those. + */ +struct damos_quota { + unsigned long ms; + unsigned long sz; + unsigned long reset_interval; + + unsigned int weight_sz; + unsigned int weight_nr_accesses; + unsigned int weight_age; + +/* private: */ + /* For throughput estimation */ + unsigned long total_charged_sz; + unsigned long total_charged_ns; + + unsigned long esz; /* Effective size quota in bytes */ + + /* For charging the quota */ + unsigned long charged_sz; + unsigned long charged_from; + struct damon_target *charge_target_from; + unsigned long charge_addr_from; + + /* For prioritization */ + unsigned long histogram[DAMOS_MAX_SCORE + 1]; + unsigned int min_score; +}; + +/** + * enum damos_wmark_metric - Represents the watermark metric. + * + * @DAMOS_WMARK_NONE: Ignore the watermarks of the given scheme. + * @DAMOS_WMARK_FREE_MEM_RATE: Free memory rate of the system in [0,1000]. + * @DAMOS_WMARK_OPLUS: Wake up short-term reclamation when Free memory drops. + * @DAMOS_WMARK_SLEEP: Sleep for call from upper layer. + */ +enum damos_wmark_metric { + DAMOS_WMARK_NONE, + DAMOS_WMARK_FREE_MEM_RATE, + DAMOS_WMARK_OPLUS, + DAMOS_WMARK_SLEEP, + NR_DAMOS_WMARK_METRICS, +}; + +/** + * struct damos_watermarks - Controls when a given scheme should be activated. + * @metric: Metric for the watermarks. + * @interval: Watermarks check time interval in microseconds. + * @high: High watermark. + * @mid: Middle watermark. + * @low: Low watermark. + * + * If &metric is &DAMOS_WMARK_NONE, the scheme is always active. Being active + * means DAMON does monitoring and applying the action of the scheme to + * appropriate memory regions. Else, DAMON checks &metric of the system for at + * least every &interval microseconds and works as below. + * + * If &metric is higher than &high, the scheme is inactivated. If &metric is + * between &mid and &low, the scheme is activated. If &metric is lower than + * &low, the scheme is inactivated. + */ +struct damos_watermarks { + enum damos_wmark_metric metric; + unsigned long interval; + unsigned long high; + unsigned long mid; + unsigned long low; + +/* private: */ + bool activated; +}; + +/** + * struct damos_stat - Statistics on a given scheme. + * @nr_tried: Total number of regions that the scheme is tried to be applied. + * @sz_tried: Total size of regions that the scheme is tried to be applied. + * @nr_applied: Total number of regions that the scheme is applied. + * @sz_applied: Total size of regions that the scheme is applied. + * @qt_exceeds: Total number of times the quota of the scheme has exceeded. + */ +struct damos_stat { + unsigned long nr_tried; + unsigned long sz_tried; + unsigned long nr_applied; + unsigned long sz_applied; + unsigned long qt_exceeds; +}; + +/** + * struct damos - Represents a Data Access Monitoring-based Operation Scheme. + * @min_sz_region: Minimum size of target regions. + * @max_sz_region: Maximum size of target regions. + * @min_nr_accesses: Minimum ``->nr_accesses`` of target regions. + * @max_nr_accesses: Maximum ``->nr_accesses`` of target regions. + * @min_age_region: Minimum age of target regions. + * @max_age_region: Maximum age of target regions. + * @action: &damo_action to be applied to the target regions. + * @quota: Control the aggressiveness of this scheme. + * @wmarks: Watermarks for automated (in)activation of this scheme. + * @stat: Statistics of this scheme. + * @list: List head for siblings. + * + * For each aggregation interval, DAMON finds regions which fit in the + * condition (&min_sz_region, &max_sz_region, &min_nr_accesses, + * &max_nr_accesses, &min_age_region, &max_age_region) and applies &action to + * those. To avoid consuming too much CPU time or IO resources for the + * &action, "a is used. + * + * To do the work only when needed, schemes can be activated for specific + * system situations using &wmarks. If all schemes that registered to the + * monitoring context are inactive, DAMON stops monitoring either, and just + * repeatedly checks the watermarks. + * + * If all schemes that registered to a &struct damon_ctx are inactive, DAMON + * stops monitoring and just repeatedly checks the watermarks. + * + * After applying the &action to each region, &stat_count and &stat_sz is + * updated to reflect the number of regions and total size of regions that the + * &action is applied. + */ +struct damos { + unsigned long min_sz_region; + unsigned long max_sz_region; + unsigned int min_nr_accesses; + unsigned int max_nr_accesses; + unsigned int min_age_region; + unsigned int max_age_region; + enum damos_action action; + struct damos_quota quota; + struct damos_watermarks wmarks; + struct damos_stat stat; + struct list_head list; +}; + +/** + * enum damon_ops_id - Identifier for each monitoring operations implementation + * + * @DAMON_OPS_VADDR: Monitoring operations for virtual address spaces + * @DAMON_OPS_PADDR: Monitoring operations for the physical address space + */ +enum damon_ops_id { + DAMON_OPS_VADDR, + DAMON_OPS_PADDR, + NR_DAMON_OPS, +}; + +struct damon_ctx; + +/** + * struct damon_operations - Monitoring operations for given use cases. + * + * @id: Identifier of this operations set. + * @init: Initialize operations-related data structures. + * @update: Update operations-related data structures. + * @prepare_access_checks: Prepare next access check of target regions. + * @check_accesses: Check the accesses to target regions. + * @reset_aggregated: Reset aggregated accesses monitoring results. + * @get_scheme_score: Get the score of a region for a scheme. + * @apply_scheme: Apply a DAMON-based operation scheme. + * @target_valid: Determine if the target is valid. + * @cleanup: Clean up the context. + * + * DAMON can be extended for various address spaces and usages. For this, + * users should register the low level operations for their target address + * space and usecase via the &damon_ctx.ops. Then, the monitoring thread + * (&damon_ctx.kdamond) calls @init and @prepare_access_checks before starting + * the monitoring, @update after each &damon_ctx.ops_update_interval, and + * @check_accesses, @target_valid and @prepare_access_checks after each + * &damon_ctx.sample_interval. Finally, @reset_aggregated is called after each + * &damon_ctx.aggr_interval. + * + * Each &struct damon_operations instance having valid @id can be registered + * via damon_register_ops() and selected by damon_select_ops() later. + * @init should initialize operations-related data structures. For example, + * this could be used to construct proper monitoring target regions and link + * those to @damon_ctx.adaptive_targets. + * @update should update the operations-related data structures. For example, + * this could be used to update monitoring target regions for current status. + * @prepare_access_checks should manipulate the monitoring regions to be + * prepared for the next access check. + * @check_accesses should check the accesses to each region that made after the + * last preparation and update the number of observed accesses of each region. + * It should also return max number of observed accesses that made as a result + * of its update. The value will be used for regions adjustment threshold. + * @reset_aggregated should reset the access monitoring results that aggregated + * by @check_accesses. + * @get_scheme_score should return the priority score of a region for a scheme + * as an integer in [0, &DAMOS_MAX_SCORE]. + * @apply_scheme is called from @kdamond when a region for user provided + * DAMON-based operation scheme is found. It should apply the scheme's action + * to the region and return bytes of the region that the action is successfully + * applied. + * @target_valid should check whether the target is still valid for the + * monitoring. + * @cleanup is called from @kdamond just before its termination. + */ +struct damon_operations { + enum damon_ops_id id; + void (*init)(struct damon_ctx *context); + void (*update)(struct damon_ctx *context); + void (*prepare_access_checks)(struct damon_ctx *context); + unsigned int (*check_accesses)(struct damon_ctx *context); + void (*reset_aggregated)(struct damon_ctx *context); + int (*get_scheme_score)(struct damon_ctx *context, + struct damon_target *t, struct damon_region *r, + struct damos *scheme); + unsigned long (*apply_scheme)(struct damon_ctx *context, + struct damon_target *t, struct damon_region *r, + struct damos *scheme); + bool (*target_valid)(void *target); + void (*cleanup)(struct damon_ctx *context); +}; + +/** + * struct damon_callback - Monitoring events notification callbacks. + * + * @before_start: Called before starting the monitoring. + * @after_sampling: Called after each sampling. + * @after_aggregation: Called after each aggregation. + * @before_terminate: Called before terminating the monitoring. + * @private: User private data. + * + * The monitoring thread (&damon_ctx.kdamond) calls @before_start and + * @before_terminate just before starting and finishing the monitoring, + * respectively. Therefore, those are good places for installing and cleaning + * @private. + * + * The monitoring thread calls @after_sampling and @after_aggregation for each + * of the sampling intervals and aggregation intervals, respectively. + * Therefore, users can safely access the monitoring results without additional + * protection. For the reason, users are recommended to use these callback for + * the accesses to the results. + * + * If any callback returns non-zero, monitoring stops. + */ +struct damon_callback { + void *private; + + int (*before_start)(struct damon_ctx *context); + int (*after_sampling)(struct damon_ctx *context); + int (*after_aggregation)(struct damon_ctx *context); + void (*before_terminate)(struct damon_ctx *context); +}; + +/** + * struct damon_ctx - Represents a context for each monitoring. This is the + * main interface that allows users to set the attributes and get the results + * of the monitoring. + * + * @sample_interval: The time between access samplings. + * @aggr_interval: The time between monitor results aggregations. + * @ops_update_interval: The time between monitoring operations updates. + * + * For each @sample_interval, DAMON checks whether each region is accessed or + * not. It aggregates and keeps the access information (number of accesses to + * each region) for @aggr_interval time. DAMON also checks whether the target + * memory regions need update (e.g., by ``mmap()`` calls from the application, + * in case of virtual memory monitoring) and applies the changes for each + * @ops_update_interval. All time intervals are in micro-seconds. + * Please refer to &struct damon_operations and &struct damon_callback for more + * detail. + * + * @kdamond: Kernel thread who does the monitoring. + * @kdamond_stop: Notifies whether kdamond should stop. + * @kdamond_lock: Mutex for the synchronizations with @kdamond. + * + * For each monitoring context, one kernel thread for the monitoring is + * created. The pointer to the thread is stored in @kdamond. + * + * Once started, the monitoring thread runs until explicitly required to be + * terminated or every monitoring target is invalid. The validity of the + * targets is checked via the &damon_operations.target_valid of @ops. The + * termination can also be explicitly requested by writing non-zero to + * @kdamond_stop. The thread sets @kdamond to NULL when it terminates. + * Therefore, users can know whether the monitoring is ongoing or terminated by + * reading @kdamond. Reads and writes to @kdamond and @kdamond_stop from + * outside of the monitoring thread must be protected by @kdamond_lock. + * + * Note that the monitoring thread protects only @kdamond and @kdamond_stop via + * @kdamond_lock. Accesses to other fields must be protected by themselves. + * + * @ops: Set of monitoring operations for given use cases. + * @callback: Set of callbacks for monitoring events notifications. + * + * @min_nr_regions: The minimum number of adaptive monitoring regions. + * @max_nr_regions: The maximum number of adaptive monitoring regions. + * @adaptive_targets: Head of monitoring targets (&damon_target) list. + * @schemes: Head of schemes (&damos) list. + */ +struct damon_ctx { + unsigned long sample_interval; + unsigned long aggr_interval; + unsigned long ops_update_interval; + +/* private: internal use only */ + unsigned long punish_interval; + struct timespec64 last_aggregation; + struct timespec64 last_ops_update; + +/* public: */ + struct task_struct *kdamond; + struct mutex kdamond_lock; + + struct damon_operations ops; + struct damon_callback callback; + + unsigned long min_nr_regions; + unsigned long max_nr_regions; + struct list_head adaptive_targets; + struct list_head schemes; +}; + +static inline struct damon_region *damon_next_region(struct damon_region *r) +{ + return container_of(r->list.next, struct damon_region, list); +} + +static inline struct damon_region *damon_prev_region(struct damon_region *r) +{ + return container_of(r->list.prev, struct damon_region, list); +} + +static inline struct damon_region *damon_last_region(struct damon_target *t) +{ + return list_last_entry(&t->regions_list, struct damon_region, list); +} + +#define damon_for_each_region(r, t) \ + list_for_each_entry(r, &t->regions_list, list) + +#define damon_for_each_region_safe(r, next, t) \ + list_for_each_entry_safe(r, next, &t->regions_list, list) + +#define damon_for_each_target(t, ctx) \ + list_for_each_entry(t, &(ctx)->adaptive_targets, list) + +#define damon_for_each_target_safe(t, next, ctx) \ + list_for_each_entry_safe(t, next, &(ctx)->adaptive_targets, list) + +#define damon_for_each_scheme(s, ctx) \ + list_for_each_entry(s, &(ctx)->schemes, list) + +#define damon_for_each_scheme_safe(s, next, ctx) \ + list_for_each_entry_safe(s, next, &(ctx)->schemes, list) + +#ifdef CONFIG_DAMON + +struct damon_region *damon_new_region(unsigned long start, unsigned long end); +/* + * Add a region between two other regions + */ +static inline void damon_insert_region(struct damon_region *r, + struct damon_region *prev, struct damon_region *next, + struct damon_target *t) +{ + __list_add(&r->list, &prev->list, &next->list); + t->nr_regions++; +} +void damon_add_region(struct damon_region *r, struct damon_target *t); +void damon_destroy_region(struct damon_region *r, struct damon_target *t); + +struct damos *damon_new_scheme( + unsigned long min_sz_region, unsigned long max_sz_region, + unsigned int min_nr_accesses, unsigned int max_nr_accesses, + unsigned int min_age_region, unsigned int max_age_region, + enum damos_action action, struct damos_quota *quota, + struct damos_watermarks *wmarks); +void damon_add_scheme(struct damon_ctx *ctx, struct damos *s); +void damon_destroy_scheme(struct damos *s); + +struct damon_target *damon_new_target(void); +void damon_add_target(struct damon_ctx *ctx, struct damon_target *t); +bool damon_targets_empty(struct damon_ctx *ctx); +void damon_free_target(struct damon_target *t); +void damon_destroy_target(struct damon_target *t); +unsigned int damon_nr_regions(struct damon_target *t); + +struct damon_ctx *damon_new_ctx(void); +void damon_destroy_ctx(struct damon_ctx *ctx); +int damon_set_attrs(struct damon_ctx *ctx, unsigned long sample_int, + unsigned long aggr_int, unsigned long ops_upd_int, + unsigned long min_nr_reg, unsigned long max_nr_reg); +int damon_set_schemes(struct damon_ctx *ctx, + struct damos **schemes, ssize_t nr_schemes); +int damon_nr_running_ctxs(void); +int damon_register_ops(struct damon_operations *ops); +int damon_select_ops(struct damon_ctx *ctx, enum damon_ops_id id); + +int damon_start(struct damon_ctx **ctxs, int nr_ctxs, bool exclusive); +int damon_stop(struct damon_ctx **ctxs, int nr_ctxs); + +#endif /* CONFIG_DAMON */ + +#endif /* _DAMON_H */ diff --git a/include/linux/delay.h b/include/linux/delay.h index b78bab4395d8..cdb25d83397a 100644 --- a/include/linux/delay.h +++ b/include/linux/delay.h @@ -20,6 +20,7 @@ */ #include +#include extern unsigned long loops_per_jiffy; @@ -57,8 +58,15 @@ extern unsigned long lpj_fine; void calibrate_delay(void); void msleep(unsigned int msecs); unsigned long msleep_interruptible(unsigned int msecs); +void usleep_range_state(unsigned long min, unsigned long max, + unsigned int state); void usleep_range(unsigned long min, unsigned long max); +static inline void usleep_idle_range(unsigned long min, unsigned long max) +{ + usleep_range_state(min, max, TASK_IDLE); +} + static inline void ssleep(unsigned int seconds) { msleep(seconds * 1000); diff --git a/include/linux/firmware.h b/include/linux/firmware.h index 2dd566c91d44..fe684fea9527 100644 --- a/include/linux/firmware.h +++ b/include/linux/firmware.h @@ -54,6 +54,11 @@ int request_firmware_into_buf(const struct firmware **firmware_p, const char *name, struct device *device, void *buf, size_t size); void release_firmware(const struct firmware *fw); +#ifdef OPLUS_FEATURE_WIFI_BDF +//Add for: reload wlan bdf without using cache +int request_firmware_no_cache(const struct firmware **firmware_p, const char *name, + struct device *device); +#endif /* OPLUS_FEATURE_WIFI_BDF */ #else static inline int request_firmware(const struct firmware **fw, const char *name, diff --git a/include/linux/fs.h b/include/linux/fs.h index b151563effc7..bb11fa71e3e5 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -299,14 +299,21 @@ enum rw_hint { WRITE_LIFE_EXTREME = RWH_WRITE_LIFE_EXTREME, }; -#define IOCB_EVENTFD (1 << 0) -#define IOCB_APPEND (1 << 1) -#define IOCB_DIRECT (1 << 2) -#define IOCB_HIPRI (1 << 3) -#define IOCB_DSYNC (1 << 4) -#define IOCB_SYNC (1 << 5) -#define IOCB_WRITE (1 << 6) -#define IOCB_NOWAIT (1 << 7) +/* Match RWF_* bits to IOCB bits */ +#define IOCB_HIPRI (__force int) RWF_HIPRI +#define IOCB_DSYNC (__force int) RWF_DSYNC +#define IOCB_SYNC (__force int) RWF_SYNC +#define IOCB_NOWAIT (__force int) RWF_NOWAIT +#define IOCB_APPEND (__force int) RWF_APPEND + +/* non-RWF related bits - start at 16 */ +#define IOCB_EVENTFD (1 << 16) +#define IOCB_DIRECT (1 << 17) +#define IOCB_WRITE (1 << 18) +/* iocb->ki_waitq is valid */ +#define IOCB_WAITQ (1 << 19) +#define IOCB_NOIO (1 << 20) + struct kiocb { struct file *ki_filp; @@ -2082,6 +2089,18 @@ static inline void init_sync_kiocb(struct kiocb *kiocb, struct file *filp) }; } +static inline void kiocb_clone(struct kiocb *kiocb, struct kiocb *kiocb_src, + struct file *filp) +{ + *kiocb = (struct kiocb) { + .ki_filp = filp, + .ki_flags = kiocb_src->ki_flags, + .ki_hint = kiocb_src->ki_hint, + .ki_ioprio = kiocb_src->ki_ioprio, + .ki_pos = kiocb_src->ki_pos, + }; +} + /* * Inode state bits. Protected by inode->i_lock * @@ -3400,25 +3419,34 @@ static inline int iocb_flags(struct file *file) static inline int kiocb_set_rw_flags(struct kiocb *ki, rwf_t flags) { + int kiocb_flags = 0; + + /* make sure there's no overlap between RWF and private IOCB flags */ + BUILD_BUG_ON((__force int) RWF_SUPPORTED & IOCB_EVENTFD); + + if (!flags) + return 0; if (unlikely(flags & ~RWF_SUPPORTED)) return -EOPNOTSUPP; if (flags & RWF_NOWAIT) { if (!(ki->ki_filp->f_mode & FMODE_NOWAIT)) return -EOPNOTSUPP; - ki->ki_flags |= IOCB_NOWAIT; + kiocb_flags |= IOCB_NOIO; } - if (flags & RWF_HIPRI) - ki->ki_flags |= IOCB_HIPRI; - if (flags & RWF_DSYNC) - ki->ki_flags |= IOCB_DSYNC; + kiocb_flags |= (__force int) (flags & RWF_SUPPORTED); if (flags & RWF_SYNC) - ki->ki_flags |= (IOCB_DSYNC | IOCB_SYNC); - if (flags & RWF_APPEND) - ki->ki_flags |= IOCB_APPEND; + kiocb_flags |= IOCB_DSYNC; + + ki->ki_flags |= kiocb_flags; return 0; } +static inline rwf_t iocb_to_rw_flags(int ifl, int iocb_mask) +{ + return ifl & iocb_mask; +} + static inline ino_t parent_ino(struct dentry *dentry) { ino_t res; diff --git a/include/linux/fscrypt.h b/include/linux/fscrypt.h index 76ef59d10c7d..eae9f27e3663 100644 --- a/include/linux/fscrypt.h +++ b/include/linux/fscrypt.h @@ -64,6 +64,7 @@ struct fscrypt_operations { void *fs_data); const union fscrypt_context *(*get_dummy_context)( struct super_block *sb); + bool (*dummy_context)(struct inode *); bool (*empty_dir)(struct inode *inode); unsigned int max_namelen; bool (*has_stable_inodes)(struct super_block *sb); diff --git a/include/linux/gfp.h b/include/linux/gfp.h index a377c258bf0d..bd76984b66c3 100644 --- a/include/linux/gfp.h +++ b/include/linux/gfp.h @@ -45,6 +45,8 @@ struct vm_area_struct; #define ___GFP_NOLOCKDEP 0 #endif #define ___GFP_CMA 0x1000000u +#define ___GFP_HIGH_ATOMIC_ZRAM 0x2000000u + /* If the above are modified, __GFP_BITS_SHIFT may need updating */ /* @@ -219,7 +221,7 @@ struct vm_area_struct; #define __GFP_NOLOCKDEP ((__force gfp_t)___GFP_NOLOCKDEP) /* Room for N __GFP_FOO bits */ -#define __GFP_BITS_SHIFT (25) +#define __GFP_BITS_SHIFT (26) #ifdef CONFIG_LOCKDEP #define __GFP_BITS_MASK ((__force gfp_t)((1 << __GFP_BITS_SHIFT) - 1)) #else diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h index 6e0774d18d41..16efc2b222af 100644 --- a/include/linux/gpio/driver.h +++ b/include/linux/gpio/driver.h @@ -255,6 +255,10 @@ struct gpio_chip { unsigned offset, int value); int (*get)(struct gpio_chip *chip, unsigned offset); +#ifdef OPLUS_FEATURE_CHG_BASIC + int (*get_oplus_vooc)(struct gpio_chip *chip, + unsigned offset); +#endif /* OPLUS_FEATURE_CHG_BASIC */ int (*get_multiple)(struct gpio_chip *chip, unsigned long *mask, unsigned long *bits); @@ -263,6 +267,10 @@ struct gpio_chip { void (*set_multiple)(struct gpio_chip *chip, unsigned long *mask, unsigned long *bits); +#ifdef OPLUS_FEATURE_CHG_BASIC + void (*set_oplus_vooc)(struct gpio_chip *chip, + unsigned offset, int value); +#endif /* OPLUS_FEATURE_CHG_BASIC */ int (*set_config)(struct gpio_chip *chip, unsigned offset, unsigned long config); diff --git a/include/linux/hans.h b/include/linux/hans.h new file mode 100644 index 000000000000..3b45e0137f53 --- /dev/null +++ b/include/linux/hans.h @@ -0,0 +1,118 @@ +/*********************************************************** +** Copyright (C), 2008-2019, OPLUS Mobile Comm Corp., Ltd. +** File: hans.h +** Description: Add for hans freeze manager +** +** Version: 1.0 +** Date : 2019/09/23 +** +** ------------------ Revision History:------------------------ +** +** Kun Zhou 2019/09/23 1.0 OPLUS_ARCH_EXTENDS +** Kun Zhou 2019/09/23 1.1 OPLUS_FEATURE_HANS_FREEZE +****************************************************************/ + +#ifndef _HANS_H +#define _HANS_H + +#include +#include +#include "../../kernel/sched/sched.h" + +#define HANS_NOERROR (0) +#define HANS_ERROR (-1) +#define MIN_USERAPP_UID (10000) +#define HANS_SYSTEM_UID (1000) +#define INTERFACETOKEN_BUFF_SIZE (140) +#define PARCEL_OFFSET (16) // sync with the writeInterfaceToken +#define CPUCTL_VERSION (2) +#define CHECK_KERN_SUPPORT_CGRPV2 (-8000) +#define HANS_USE_CGRPV2 (-99) + +/* hans_message for comunication with HANS native deamon + * type: async binder/sync binder/signal/pkg/loopback + * Only loop back type is duplex (native deamon <---> kernel) for handshake + * port: native deamon pid + * caller_pid: binder, caller -> unfreeze (target) UID + * target_uid: UID want to be unfrozen + * pkg_cmd: Add/Remove monitored UID + */ +struct hans_message { + int type; + int port; // pid + + int caller_uid; + int caller_pid; // caller -> unfreeze UID + int target_pid; + int target_uid; // unfreeze UID, pkg add/remove UID + + int pkg_cmd; //Add/remove monitored uid + + int code; + char rpc_name[INTERFACETOKEN_BUFF_SIZE]; +}; + +// hans message type definition +enum message_type { + //kernel --> native deamon + ASYNC_BINDER, + SYNC_BINDER, + FROZEN_TRANS, + SIGNAL, + PKG, + SYNC_BINDER_CPUCTL, + SIGNAL_CPUCTL, + CPUCTL_TRANS, + + // kernel <--> native deamon + LOOP_BACK, + TYPE_MAX +}; + +// pkg cmd type +enum pkg_cmd { + ADD_ONE_UID, + DEL_ONE_UID, + DEL_ALL_UID, + + PKG_CMD_MAX +}; + +//Check if the thread group is frozen +static inline bool is_jobctl_frozen(struct task_struct *task) +{ + return ((task->jobctl & JOBCTL_TRAP_FREEZE) != 0); +} +static inline bool is_frozen_tg(struct task_struct* task) +{ + return ((cgroup_task_frozen(task) && is_jobctl_frozen(task)) || frozen(task->group_leader) || freezing(task->group_leader)); +} + +int hans_report(enum message_type type, int caller_pid, int caller_uid, int target_pid, int target_uid, const char *rpc_name, int code); +void hans_network_cmd_parse(uid_t uid, enum pkg_cmd cmd); +void hans_check_frozen_transcation(uid_t uid, enum message_type type); +int hans_netfilter_init(void); +void hans_netfilter_deinit(void); + +#if defined(CONFIG_CFS_BANDWIDTH) +static inline bool is_belong_cpugrp(struct task_struct *task) +{ + if (task->sched_task_group != NULL) { + struct cfs_bandwidth cfs_b = task->sched_task_group->cfs_bandwidth; + if (cfs_b.quota != -1) { + return true; + } else if (cfs_b.quota == -1) { + return false; + } + } + + return false; +} +#else +static inline bool is_belong_cpugrp(struct task_struct *task) +{ + return false; +} +#endif + +#endif diff --git a/include/linux/healthinfo b/include/linux/healthinfo new file mode 120000 index 000000000000..270d8269905e --- /dev/null +++ b/include/linux/healthinfo @@ -0,0 +1 @@ +../../../../vendor/oplus/kernel/oplus_performance/healthinfo/include/ \ No newline at end of file diff --git a/include/linux/im b/include/linux/im new file mode 120000 index 000000000000..630a80dd1b93 --- /dev/null +++ b/include/linux/im @@ -0,0 +1 @@ +../../../../vendor/oplus/kernel/oplus_performance/im \ No newline at end of file diff --git a/include/linux/input/qpnp-power-on.h b/include/linux/input/qpnp-power-on.h index d80ab2b31d43..0b0ad996f13b 100644 --- a/include/linux/input/qpnp-power-on.h +++ b/include/linux/input/qpnp-power-on.h @@ -54,8 +54,85 @@ enum pon_restart_reason { PON_RESTART_REASON_DMVERITY_CORRUPTED = 0x04, PON_RESTART_REASON_DMVERITY_ENFORCE = 0x05, PON_RESTART_REASON_KEYS_CLEAR = 0x06, +#ifdef OPLUS_BUG_STABILITY +/* Add for oplus boot mode*/ + PON_RESTART_REASON_SILENCE = 0x21, + PON_RESTART_REASON_SAU = 0x22, + PON_RESTART_REASON_RF = 0x23, + PON_RESTART_REASON_WLAN = 0x24, + PON_RESTART_REASON_MOS = 0x25, + PON_RESTART_REASON_FACTORY = 0x26, + PON_RESTART_REASON_KERNEL = 0x27, + PON_RESTART_REASON_MODEM = 0x28, + PON_RESTART_REASON_ANDROID = 0x29, + PON_RESTART_REASON_SAFE = 0x2A, + #ifdef OPLUS_FEATURE_AGINGTEST + //Add for factory agingtest + PON_RESTART_REASON_SBL_DDRTEST = 0x2B, + PON_RESTART_REASON_SBL_DDR_CUS = 0x2C, + PON_RESTART_REASON_MEM_AGING = 0x2D, + //0x2E is SBLTEST FAIL, just happen in ddrtest fail when xbl setup + #endif + PON_RESTART_REASON_REBOOT_NO_VIBRATION = 0x2F, + PON_RESTART_REASON_NORMAL = 0x3E, +#endif }; +#ifdef OPLUS_FEATURE_QCOM_PMICWD +#ifdef CONFIG_OPLUS_FEATURE_QCOM_PMICWD +struct qpnp_pon { + struct device *dev; + struct regmap *regmap; + struct input_dev *pon_input; + struct qpnp_pon_config *pon_cfg; + struct pon_regulator *pon_reg_cfg; + struct list_head list; + struct delayed_work bark_work; +#ifdef CONFIG_OPLUS_FEATURE_MISC + struct delayed_work press_work; +#endif + struct dentry *debugfs; + struct task_struct *wd_task; + struct mutex wd_task_mutex; + unsigned int pmicwd_state;//|reserver|rst type|timeout|enable| + u8 suspend_state;//record the suspend state + u16 base; + u8 subtype; + u8 pon_ver; + u8 warm_reset_reason1; + u8 warm_reset_reason2; + int num_pon_config; + int num_pon_reg; + int pon_trigger_reason; + int pon_power_off_reason; + u32 dbc_time_us; + u32 uvlo; + int warm_reset_poff_type; + int hard_reset_poff_type; + int shutdown_poff_type; + int resin_warm_reset_type; + int resin_hard_reset_type; + int resin_shutdown_type; + bool is_spon; + bool store_hard_reset_reason; + bool resin_hard_reset_disable; + bool resin_shutdown_disable; + bool ps_hold_hard_reset_disable; + bool ps_hold_shutdown_disable; + bool kpdpwr_dbc_enable; + bool resin_pon_reset; + ktime_t kpdpwr_last_release_time; + bool log_kpd_event; +}; + +extern const struct dev_pm_ops qpnp_pm_ops; +extern struct qpnp_pon *sys_reset_dev; +int qpnp_pon_masked_write(struct qpnp_pon *pon, u16 addr, u8 mask, u8 val); +void pmicwd_init(struct platform_device *pdev, struct qpnp_pon *pon, bool sys_reset); +void kpdpwr_init(struct qpnp_pon *pon, bool sys_reset); +#endif +#endif /* OPLUS_FEATURE_QCOM_PMICWD */ + #ifdef CONFIG_INPUT_QPNP_POWER_ON int qpnp_pon_system_pwr_off(enum pon_power_off_type type); int qpnp_pon_is_warm_reset(void); diff --git a/include/linux/iomonitor b/include/linux/iomonitor new file mode 120000 index 000000000000..0548c0e043d2 --- /dev/null +++ b/include/linux/iomonitor @@ -0,0 +1 @@ +../../../../vendor/oplus/kernel/oplus_performance/iomonitor/include/ \ No newline at end of file diff --git a/include/linux/ipa.h b/include/linux/ipa.h index af4e599a7cc8..afc380d35e07 100644 --- a/include/linux/ipa.h +++ b/include/linux/ipa.h @@ -890,11 +890,13 @@ struct ipa_rx_data { * @page: skb page * @dma_addr: DMA address of this Rx packet * @is_tmp_alloc: skb page from tmp_alloc or recycle_list + * @page_order: page order associated with the page. */ struct ipa_rx_page_data { struct page *page; dma_addr_t dma_addr; bool is_tmp_alloc; + u32 page_order; }; diff --git a/include/linux/kobject.h b/include/linux/kobject.h index d0034c374a8b..313d88863be4 100644 --- a/include/linux/kobject.h +++ b/include/linux/kobject.h @@ -30,7 +30,11 @@ #include #define UEVENT_HELPER_PATH_LEN 256 +#ifdef OPLUS_FEATURE_CHG_BASIC +#define UEVENT_NUM_ENVP 128 /* number of env pointers */ +#else #define UEVENT_NUM_ENVP 64 /* number of env pointers */ +#endif #define UEVENT_BUFFER_SIZE 4096 /* buffer for the variables */ #ifdef CONFIG_UEVENT_HELPER diff --git a/include/linux/memcontrol.h b/include/linux/memcontrol.h index cc6b6532eb56..a65bd41ddb47 100644 --- a/include/linux/memcontrol.h +++ b/include/linux/memcontrol.h @@ -311,6 +311,13 @@ struct mem_cgroup { struct list_head event_list; spinlock_t event_list_lock; + u64 android_oem_data1; + +#ifdef CONFIG_LRU_GEN + /* per-memcg mm_struct list */ + struct lru_gen_mm_list mm_list; +#endif + struct mem_cgroup_per_node *nodeinfo[0]; /* WARNING: nodeinfo must be the last member here */ }; @@ -559,6 +566,23 @@ struct mem_cgroup *lock_page_memcg(struct page *page); void __unlock_page_memcg(struct mem_cgroup *memcg); void unlock_page_memcg(struct page *page); +/* try to stablize page_memcg() for all the pages in a memcg */ +static inline bool mem_cgroup_trylock_pages(struct mem_cgroup *memcg) +{ + rcu_read_lock(); + + if (mem_cgroup_disabled() || !atomic_read(&memcg->moving_account)) + return true; + + rcu_read_unlock(); + return false; +} + +static inline void mem_cgroup_unlock_pages(void) +{ + rcu_read_unlock(); +} + /* * idx can be of type enum memcg_stat_item or node_stat_item. * Keep in sync with memcg_exact_page_state(). @@ -990,6 +1014,18 @@ static inline void unlock_page_memcg(struct page *page) { } +static inline bool mem_cgroup_trylock_pages(struct mem_cgroup *memcg) +{ + /* to match page_memcg_rcu() */ + rcu_read_lock(); + return true; +} + +static inline void mem_cgroup_unlock_pages(void) +{ + rcu_read_unlock(); +} + static inline void mem_cgroup_handle_over_high(void) { } @@ -1094,6 +1130,12 @@ static inline void mem_cgroup_split_huge_fixup(struct page *head) { } +static inline void __count_memcg_events(struct mem_cgroup *memcg, + enum vm_event_item idx, + unsigned long count) +{ +} + static inline void count_memcg_events(struct mem_cgroup *memcg, enum vm_event_item idx, unsigned long count) diff --git a/include/linux/memleak_stackdepot.h b/include/linux/memleak_stackdepot.h new file mode 120000 index 000000000000..32c19f510018 --- /dev/null +++ b/include/linux/memleak_stackdepot.h @@ -0,0 +1 @@ +../../../../vendor/oplus/kernel/oplus_performance/memleak_detect/stack_depot/memleak_stackdepot.h \ No newline at end of file diff --git a/include/linux/memory_isolate.h b/include/linux/memory_isolate.h new file mode 100644 index 000000000000..540624f80b53 --- /dev/null +++ b/include/linux/memory_isolate.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2018-2020 Oplus. All rights reserved. + */ + +#ifndef __OPLUS_MEMORY_ISOLATE__ +#define __OPLUS_MEMORY_ISOLATE__ + +#define OPLUS2_ORDER 2 + +#define is_oplus2_order(order) \ + unlikely(OPLUS2_ORDER == order) + +#define is_migrate_oplus2(mt) \ + unlikely(mt == MIGRATE_OPLUS2) + +extern void setup_zone_migrate_oplus(struct zone *zone, int reserve_migratetype); + +#endif /*__OPLUS_MEMORY_ISOLATE__*/ diff --git a/include/linux/midas_proc.h b/include/linux/midas_proc.h new file mode 100644 index 000000000000..96fdf77cf2b6 --- /dev/null +++ b/include/linux/midas_proc.h @@ -0,0 +1,40 @@ +/* + * SPDX-License-Identifier: GPL-2.0-only + * + * Copyright (C) 2019-2020 Oplus. All rights reserved. + */ + +#ifndef __MIDAS_PROC_H__ +#define __MIDAS_PROC_H__ + +#include + +#define STATE_MAX 60 +#define CNT_MAX 1024 + +enum { + TYPE_UID = 0, + TYPE_RPID, + TYPE_SPID, + TYPE_TOTAL, +}; + +enum { + ID_PID = 0, + ID_TGID, + ID_UID, + ID_TOTAL, +}; + +struct state_inst { + unsigned int id[ID_TOTAL]; + char name[TASK_COMM_LEN]; + unsigned long long time_in_state[STATE_MAX]; +}; + +struct midas_id_state { + unsigned int cnt; + struct state_inst insts[CNT_MAX]; +}; + +#endif diff --git a/include/linux/mm.h b/include/linux/mm.h index 880ae8794bb5..2d011ffa3a6e 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -851,6 +851,8 @@ vm_fault_t finish_mkwrite_fault(struct vm_fault *vmf); #define ZONES_PGOFF (NODES_PGOFF - ZONES_WIDTH) #define LAST_CPUPID_PGOFF (ZONES_PGOFF - LAST_CPUPID_WIDTH) #define KASAN_TAG_PGOFF (LAST_CPUPID_PGOFF - KASAN_TAG_WIDTH) +#define LRU_GEN_PGOFF (KASAN_TAG_PGOFF - LRU_GEN_WIDTH) +#define LRU_REFS_PGOFF (LRU_GEN_PGOFF - LRU_REFS_WIDTH) /* * Define the bit shifts to access each section. For non-existent @@ -1461,6 +1463,8 @@ void unmap_vmas(struct mmu_gather *tlb, struct vm_area_struct *start_vma, * (see the comment on walk_page_range() for more details) */ struct mm_walk { + int (*p4d_entry)(p4d_t *p4d, unsigned long addr, + unsigned long next, struct mm_walk *walk); int (*pud_entry)(pud_t *pud, unsigned long addr, unsigned long next, struct mm_walk *walk); int (*pmd_entry)(pmd_t *pmd, unsigned long addr, @@ -2564,7 +2568,7 @@ int __must_check write_one_page(struct page *page); void task_dirty_inc(struct task_struct *tsk); /* readahead.c */ -#define VM_MAX_READAHEAD 512 /* kbytes */ +#define VM_MAX_READAHEAD (totalram_pages > 0x100000 ? 512 : 128) /* kbytes */ #define VM_MIN_READAHEAD 16 /* kbytes (includes current page) */ int force_page_cache_readahead(struct address_space *mapping, struct file *filp, @@ -3038,6 +3042,10 @@ struct reclaim_param { int nr_to_reclaim; /* pages reclaimed */ int nr_reclaimed; +#if defined(OPLUS_FEATURE_PROCESS_RECLAIM) && defined(CONFIG_PROCESS_RECLAIM_ENHANCE) + bool inactive_lru; + struct task_struct *reclaimed_task; +#endif }; extern struct reclaim_param reclaim_task_anon(struct task_struct *task, int nr_to_reclaim); diff --git a/include/linux/mm_inline.h b/include/linux/mm_inline.h index 10191c28fc04..0739dea3518a 100644 --- a/include/linux/mm_inline.h +++ b/include/linux/mm_inline.h @@ -29,6 +29,8 @@ static __always_inline void __update_lru_size(struct lruvec *lruvec, { struct pglist_data *pgdat = lruvec_pgdat(lruvec); + lockdep_assert_held(&pgdat->lru_lock); + __mod_node_page_state(pgdat, NR_LRU_BASE + lru, nr_pages); __mod_zone_page_state(&pgdat->node_zones[zid], NR_ZONE_LRU_BASE + lru, nr_pages); @@ -44,64 +46,22 @@ static __always_inline void update_lru_size(struct lruvec *lruvec, #endif } -static __always_inline void add_page_to_lru_list(struct page *page, - struct lruvec *lruvec, enum lru_list lru) -{ - update_lru_size(lruvec, lru, page_zonenum(page), hpage_nr_pages(page)); - list_add(&page->lru, &lruvec->lists[lru]); -} - -static __always_inline void add_page_to_lru_list_tail(struct page *page, - struct lruvec *lruvec, enum lru_list lru) -{ - update_lru_size(lruvec, lru, page_zonenum(page), hpage_nr_pages(page)); - list_add_tail(&page->lru, &lruvec->lists[lru]); -} - -static __always_inline void del_page_from_lru_list(struct page *page, - struct lruvec *lruvec, enum lru_list lru) -{ - list_del(&page->lru); - update_lru_size(lruvec, lru, page_zonenum(page), -hpage_nr_pages(page)); -} - /** - * page_lru_base_type - which LRU list type should a page be on? - * @page: the page to test - * - * Used for LRU list index arithmetic. - * - * Returns the base LRU type - file or anon - @page should be on. + * __clear_page_lru_flags - clear page lru flags before releasing a page + * @page: the page that was on lru and now has a zero reference */ -static inline enum lru_list page_lru_base_type(struct page *page) +static __always_inline void __clear_page_lru_flags(struct page *page) { - if (page_is_file_cache(page)) - return LRU_INACTIVE_FILE; - return LRU_INACTIVE_ANON; -} + VM_BUG_ON_PAGE(!PageLRU(page), page); -/** - * page_off_lru - which LRU list was page on? clearing its lru flags. - * @page: the page to test - * - * Returns the LRU list a page was on, as an index into the array of LRU - * lists; and clears its Unevictable or Active flags, ready for freeing. - */ -static __always_inline enum lru_list page_off_lru(struct page *page) -{ - enum lru_list lru; + __ClearPageLRU(page); - if (PageUnevictable(page)) { - __ClearPageUnevictable(page); - lru = LRU_UNEVICTABLE; - } else { - lru = page_lru_base_type(page); - if (PageActive(page)) { - __ClearPageActive(page); - lru += LRU_ACTIVE; - } - } - return lru; + /* this shouldn't happen, so leave the flags to bad_page() */ + if (PageActive(page) && PageUnevictable(page)) + return; + + __ClearPageActive(page); + __ClearPageUnevictable(page); } /** @@ -115,16 +75,247 @@ static __always_inline enum lru_list page_lru(struct page *page) { enum lru_list lru; + VM_BUG_ON_PAGE(PageActive(page) && PageUnevictable(page), page); + if (PageUnevictable(page)) - lru = LRU_UNEVICTABLE; - else { - lru = page_lru_base_type(page); - if (PageActive(page)) - lru += LRU_ACTIVE; - } + return LRU_UNEVICTABLE; + + lru = page_is_file_cache(page) ? LRU_INACTIVE_FILE : LRU_INACTIVE_ANON; + if (PageActive(page)) + lru += LRU_ACTIVE; + return lru; } #define lru_to_page(head) (list_entry((head)->prev, struct page, lru)) +#ifdef CONFIG_LRU_GEN + +static inline bool lru_gen_enabled(void) +{ +#ifdef CONFIG_LRU_GEN_ENABLED + DECLARE_STATIC_KEY_TRUE(lru_gen_caps[NR_LRU_GEN_CAPS]); + + return static_branch_likely(&lru_gen_caps[LRU_GEN_CORE]); +#else + DECLARE_STATIC_KEY_FALSE(lru_gen_caps[NR_LRU_GEN_CAPS]); + + return static_branch_unlikely(&lru_gen_caps[LRU_GEN_CORE]); +#endif +} + +static inline bool lru_gen_in_fault(void) +{ + return current->in_lru_fault; +} + +static inline int lru_gen_from_seq(unsigned long seq) +{ + return seq % MAX_NR_GENS; +} + +static inline int lru_hist_from_seq(unsigned long seq) +{ + return seq % NR_HIST_GENS; +} + +static inline int lru_tier_from_refs(int refs) +{ + VM_BUG_ON(refs > BIT(LRU_REFS_WIDTH)); + + /* see the comment on MAX_NR_TIERS */ + return order_base_2(refs + 1); +} + +static inline bool lru_gen_is_active(struct lruvec *lruvec, int gen) +{ + unsigned long max_seq = lruvec->lrugen.max_seq; + + VM_BUG_ON(gen >= MAX_NR_GENS); + + /* see the comment on MIN_NR_GENS */ + return gen == lru_gen_from_seq(max_seq) || gen == lru_gen_from_seq(max_seq - 1); +} + +static inline void lru_gen_update_size(struct lruvec *lruvec, struct page *page, + int old_gen, int new_gen) +{ + int type = page_is_file_cache(page); + int zone = page_zonenum(page); + int delta = hpage_nr_pages(page); + enum lru_list lru = type * LRU_INACTIVE_FILE; + struct lru_gen_struct *lrugen = &lruvec->lrugen; + + VM_BUG_ON(old_gen != -1 && old_gen >= MAX_NR_GENS); + VM_BUG_ON(new_gen != -1 && new_gen >= MAX_NR_GENS); + VM_BUG_ON(old_gen == -1 && new_gen == -1); + + if (old_gen >= 0) + WRITE_ONCE(lrugen->nr_pages[old_gen][type][zone], + lrugen->nr_pages[old_gen][type][zone] - delta); + if (new_gen >= 0) + WRITE_ONCE(lrugen->nr_pages[new_gen][type][zone], + lrugen->nr_pages[new_gen][type][zone] + delta); + + /* addition */ + if (old_gen < 0) { + if (lru_gen_is_active(lruvec, new_gen)) + lru += LRU_ACTIVE; + update_lru_size(lruvec, lru, zone, delta); + return; + } + + /* deletion */ + if (new_gen < 0) { + if (lru_gen_is_active(lruvec, old_gen)) + lru += LRU_ACTIVE; + update_lru_size(lruvec, lru, zone, -delta); + return; + } + + /* promotion */ + if (!lru_gen_is_active(lruvec, old_gen) && lru_gen_is_active(lruvec, new_gen)) { + update_lru_size(lruvec, lru, zone, -delta); + update_lru_size(lruvec, lru + LRU_ACTIVE, zone, delta); + } + + /* demotion requires isolation, e.g., lru_deactivate_fn() */ + VM_BUG_ON(lru_gen_is_active(lruvec, old_gen) && !lru_gen_is_active(lruvec, new_gen)); +} + +static inline bool lru_gen_add_page(struct lruvec *lruvec, struct page *page, bool reclaiming) +{ + int gen; + unsigned long old_flags, new_flags; + int type = page_is_file_cache(page); + int zone = page_zonenum(page); + struct lru_gen_struct *lrugen = &lruvec->lrugen; + + if (PageUnevictable(page) || !lrugen->enabled) + return false; + /* + * There are three common cases for this page: + * 1. If it's hot, e.g., freshly faulted in or previously hot and + * migrated, add it to the youngest generation. + * 2. If it's cold but can't be evicted immediately, i.e., an anon page + * not in swapcache or a dirty page pending writeback, add it to the + * second oldest generation. + * 3. Everything else (clean, cold) is added to the oldest generation. + */ + if (PageActive(page)) + gen = lru_gen_from_seq(lrugen->max_seq); + else if ((type == LRU_GEN_ANON && !PageSwapCache(page)) || + (PageReclaim(page) && (PageDirty(page) || PageWriteback(page)))) + gen = lru_gen_from_seq(lrugen->min_seq[type] + 1); + else + gen = lru_gen_from_seq(lrugen->min_seq[type]); + + do { + new_flags = old_flags = READ_ONCE(page->flags); + VM_BUG_ON_PAGE(new_flags & LRU_GEN_MASK, page); + + /* see the comment on MIN_NR_GENS */ + new_flags &= ~(LRU_GEN_MASK | BIT(PG_active)); + new_flags |= (gen + 1UL) << LRU_GEN_PGOFF; + } while (cmpxchg(&page->flags, old_flags, new_flags) != old_flags); + + lru_gen_update_size(lruvec, page, -1, gen); + /* for rotate_reclaimable_page() */ + if (reclaiming) + list_add_tail(&page->lru, &lrugen->lists[gen][type][zone]); + else + list_add(&page->lru, &lrugen->lists[gen][type][zone]); + + return true; +} + +static inline bool lru_gen_del_page(struct lruvec *lruvec, struct page *page, bool reclaiming) +{ + int gen; + unsigned long old_flags, new_flags; + + do { + new_flags = old_flags = READ_ONCE(page->flags); + if (!(new_flags & LRU_GEN_MASK)) + return false; + + VM_BUG_ON_PAGE(PageActive(page), page); + VM_BUG_ON_PAGE(PageUnevictable(page), page); + + gen = ((new_flags & LRU_GEN_MASK) >> LRU_GEN_PGOFF) - 1; + + new_flags &= ~LRU_GEN_MASK; + if (!(new_flags & BIT(PG_referenced))) + new_flags &= ~(LRU_REFS_MASK | LRU_REFS_FLAGS); + /* for shrink_page_list() */ + if (reclaiming) + new_flags &= ~(BIT(PG_referenced) | BIT(PG_reclaim)); + else if (lru_gen_is_active(lruvec, gen)) + new_flags |= BIT(PG_active); + } while (cmpxchg(&page->flags, old_flags, new_flags) != old_flags); + + lru_gen_update_size(lruvec, page, gen, -1); + list_del(&page->lru); + + return true; +} + +#else + +static inline bool lru_gen_enabled(void) +{ + return false; +} + +static inline bool lru_gen_in_fault(void) +{ + return false; +} + +static inline bool lru_gen_add_page(struct lruvec *lruvec, struct page *page, bool reclaiming) +{ + return false; +} + +static inline bool lru_gen_del_page(struct lruvec *lruvec, struct page *page, bool reclaiming) +{ + return false; +} + +#endif /* CONFIG_LRU_GEN */ + +static __always_inline void add_page_to_lru_list(struct page *page, + struct lruvec *lruvec) +{ + enum lru_list lru = page_lru(page); + + if (lru_gen_add_page(lruvec, page, false)) + return; + + update_lru_size(lruvec, lru, page_zonenum(page), hpage_nr_pages(page)); + list_add(&page->lru, &lruvec->lists[lru]); +} + +static __always_inline void add_page_to_lru_list_tail(struct page *page, + struct lruvec *lruvec) +{ + enum lru_list lru = page_lru(page); + + if (lru_gen_add_page(lruvec, page, true)) + return; + + update_lru_size(lruvec, lru, page_zonenum(page), hpage_nr_pages(page)); + list_add_tail(&page->lru, &lruvec->lists[lru]); +} + +static __always_inline void del_page_from_lru_list(struct page *page, + struct lruvec *lruvec) +{ + if (lru_gen_del_page(lruvec, page, false)) + return; + + list_del(&page->lru); + update_lru_size(lruvec, page_lru(page), page_zonenum(page), + -hpage_nr_pages(page)); +} #endif diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h index 61e2b8b6f22e..1bfc74dceb1c 100644 --- a/include/linux/mm_types.h +++ b/include/linux/mm_types.h @@ -3,6 +3,7 @@ #define _LINUX_MM_TYPES_H #include +#include #include #include @@ -14,6 +15,8 @@ #include #include #include +#include +#include #include #include @@ -511,11 +514,41 @@ struct mm_struct { atomic_long_t hugetlb_usage; #endif struct work_struct async_put_work; - +#if defined(OPLUS_FEATURE_VIRTUAL_RESERVE_MEMORY) && defined(CONFIG_VIRTUAL_RESERVE_MEMORY) + struct vm_area_struct *reserve_vma; + struct vm_area_struct *reserve_mmap; + struct rb_root reserve_mm_rb; + unsigned long reserve_highest_vm_end; + int reserve_map_count; + int do_reserve_mmap; + bool vm_search_two_way; +#endif #if IS_ENABLED(CONFIG_HMM) /* HMM needs to track a few things per mm */ struct hmm *hmm; #endif +#if defined(OPLUS_FEATURE_VIRTUAL_RESERVE_MEMORY) && defined(CONFIG_VIRTUAL_RESERVE_MEMORY) + unsigned long va_feature_rnd; + unsigned int zygoteheap_in_MB; + int va_feature; +#endif + +#ifdef CONFIG_LRU_GEN + struct { + /* this mm_struct is on lru_gen_mm_list */ + struct list_head list; +#ifdef CONFIG_MEMCG + /* points to the memcg of "owner" above */ + struct mem_cgroup *memcg; +#endif + /* + * Set when switching to this mm_struct, as a hint of + * whether it has been used since the last time per-node + * page table walkers cleared the corresponding bits. + */ + nodemask_t nodes; + } lru_gen; +#endif /* CONFIG_LRU_GEN */ } __randomize_layout; /* @@ -542,6 +575,65 @@ static inline cpumask_t *mm_cpumask(struct mm_struct *mm) return (struct cpumask *)&mm->cpu_bitmap; } +#ifdef CONFIG_LRU_GEN + +struct lru_gen_mm_list { + /* mm_struct list for page table walkers */ + struct list_head fifo; + /* protects the list above */ + spinlock_t lock; +}; + +void lru_gen_add_mm(struct mm_struct *mm); +void lru_gen_del_mm(struct mm_struct *mm); +#ifdef CONFIG_MEMCG +void lru_gen_migrate_mm(struct mm_struct *mm); +#endif + +static inline void lru_gen_init_mm(struct mm_struct *mm) +{ + INIT_LIST_HEAD(&mm->lru_gen.list); +#ifdef CONFIG_MEMCG + mm->lru_gen.memcg = NULL; +#endif + nodes_clear(mm->lru_gen.nodes); +} + +static inline void lru_gen_use_mm(struct mm_struct *mm) +{ + /* unlikely but not a bug when racing with lru_gen_migrate_mm() */ + VM_WARN_ON(list_empty(&mm->lru_gen.list)); + + if (!(current->flags & PF_KTHREAD) && !nodes_full(mm->lru_gen.nodes)) + nodes_setall(mm->lru_gen.nodes); +} + +#else /* !CONFIG_LRU_GEN */ + +static inline void lru_gen_add_mm(struct mm_struct *mm) +{ +} + +static inline void lru_gen_del_mm(struct mm_struct *mm) +{ +} + +#ifdef CONFIG_MEMCG +static inline void lru_gen_migrate_mm(struct mm_struct *mm) +{ +} +#endif + +static inline void lru_gen_init_mm(struct mm_struct *mm) +{ +} + +static inline void lru_gen_use_mm(struct mm_struct *mm) +{ +} + +#endif /* CONFIG_LRU_GEN */ + struct mmu_gather; extern void tlb_gather_mmu(struct mmu_gather *tlb, struct mm_struct *mm, unsigned long start, unsigned long end); diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h index 5a73f0c6e41d..023ea5443d35 100644 --- a/include/linux/mmc/card.h +++ b/include/linux/mmc/card.h @@ -159,6 +159,9 @@ struct sd_ssr { unsigned int au; /* In sectors */ unsigned int erase_timeout; /* In milliseconds */ unsigned int erase_offset; /* In milliseconds */ +#ifdef OPLUS_FEATURE_EMMC_SDCARD_OPTIMIZE + unsigned int speed_class; /* speed_class */ +#endif /* OPLUS_FEATURE_EMMC_SDCARD_OPTIMIZE */ }; struct sd_switch_caps { diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index 2f14afff1d33..aa1559486f55 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h @@ -549,6 +549,9 @@ struct mmc_host { struct delayed_work detect; int detect_change; /* card detect flag */ +#ifdef OPLUS_FEATURE_EMMC_SDCARD_OPTIMIZE + int detect_change_retry; +#endif struct mmc_slot slot; const struct mmc_bus_ops *bus_ops; /* current bus driver */ diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h index 9d1d2796cc44..a551f8998556 100644 --- a/include/linux/mmzone.h +++ b/include/linux/mmzone.h @@ -21,6 +21,10 @@ #include #include +#if defined(OPLUS_FEATURE_MULTI_KSWAPD) && defined(CONFIG_OPLUS_MULTI_KSWAPD) +#include +#endif + /* Free memory management - zoned buddy allocator. */ #ifndef CONFIG_FORCE_MAX_ZONEORDER #define MAX_ORDER 11 @@ -29,6 +33,9 @@ #endif #define MAX_ORDER_NR_PAGES (1 << (MAX_ORDER - 1)) +#if defined(OPLUS_FEATURE_MULTI_FREEAREA) && defined(CONFIG_PHYSICAL_ANTI_FRAGMENTATION) +#define FREE_AREA_COUNTS 4 +#endif /* * PAGE_ALLOC_COSTLY_ORDER is the order at which allocations are deemed * costly to service. That is between allocation orders which should @@ -59,6 +66,12 @@ enum migratetype { */ MIGRATE_CMA, #endif +#if defined(OPLUS_FEATURE_MEMORY_ISOLATE) && defined(CONFIG_OPLUS_MEMORY_ISOLATE) +/* + * Add a migrate type to manage special page alloc/free + */ + MIGRATE_OPLUS2, +#endif /* OPLUS_FEATURE_MEMORY_ISOLATE */ MIGRATE_PCPTYPES, /* the number of types on the pcp lists */ MIGRATE_HIGHATOMIC = MIGRATE_PCPTYPES, #ifdef CONFIG_MEMORY_ISOLATION @@ -156,6 +169,15 @@ enum zone_stat_item { NR_ZSPAGES, /* allocated in zsmalloc */ #endif NR_FREE_CMA_PAGES, +#if defined(OPLUS_FEATURE_MEMORY_ISOLATE) && defined(CONFIG_OPLUS_MEMORY_ISOLATE) +/* + * Account free pages for MIGRATE_OPLUS + */ + NR_FREE_OPLUS2_PAGES, +#endif /* OPLUS_FEATURE_MEMORY_ISOLATE */ +#ifdef OPLUS_FEATURE_HEALTHINFO + NR_IONCACHE_PAGES, +#endif /* OPLUS_FEATURE_HEALTHINFO */ NR_VM_ZONE_STAT_ITEMS }; enum node_stat_item { @@ -233,19 +255,231 @@ static inline int is_active_lru(enum lru_list lru) return (lru == LRU_ACTIVE_ANON || lru == LRU_ACTIVE_FILE); } +#define ANON_AND_FILE 2 + struct zone_reclaim_stat { /* * The pageout code in vmscan.c keeps track of how many of the * mem/swap backed and file backed pages are referenced. * The higher the rotated/scanned ratio, the more valuable * that cache is. - * - * The anon LRU stats live in [0], file LRU stats in [1] */ - unsigned long recent_rotated[2]; - unsigned long recent_scanned[2]; + unsigned long recent_rotated[ANON_AND_FILE]; + unsigned long recent_scanned[ANON_AND_FILE]; }; +#endif /* !__GENERATING_BOUNDS_H */ + +/* + * Evictable pages are divided into multiple generations. The youngest and the + * oldest generation numbers, max_seq and min_seq, are monotonically increasing. + * They form a sliding window of a variable size [MIN_NR_GENS, MAX_NR_GENS]. An + * offset within MAX_NR_GENS, gen, indexes the LRU list of the corresponding + * generation. The gen counter in page->flags stores gen+1 while a page is on + * one of lrugen->lists[]. Otherwise it stores 0. + * + * A page is added to the youngest generation on faulting. The aging needs to + * check the accessed bit at least twice before handing this page over to the + * eviction. The first check takes care of the accessed bit set on the initial + * fault; the second check makes sure this page hasn't been used since then. + * This process, AKA second chance, requires a minimum of two generations, + * hence MIN_NR_GENS. And to maintain ABI compatibility with the active/inactive + * LRU, these two generations are considered active; the rest of generations, if + * they exist, are considered inactive. See lru_gen_is_active(). PG_active is + * always cleared while a page is on one of lrugen->lists[] so that the aging + * needs not to worry about it. And it's set again when a page considered active + * is isolated for non-reclaiming purposes, e.g., migration. See + * lru_gen_add_page() and lru_gen_del_page(). + * + * MAX_NR_GENS is set to 4 so that the multi-gen LRU can support twice of the + * categories of the active/inactive LRU when keeping track of accesses through + * page tables. It requires order_base_2(MAX_NR_GENS+1) bits in page->flags. + */ +#define MIN_NR_GENS 2U +#define MAX_NR_GENS 4U + +/* + * Each generation is divided into multiple tiers. Tiers represent different + * ranges of numbers of accesses through file descriptors. A page accessed N + * times through file descriptors is in tier order_base_2(N). A page in the + * first tier (N=0,1) is marked by PG_referenced unless it was faulted in + * though page tables or read ahead. A page in any other tier (N>1) is marked + * by PG_referenced and PG_workingset. + * + * In contrast to moving across generations which requires the LRU lock, moving + * across tiers only requires operations on page->flags and therefore has a + * negligible cost in the buffered access path. In the eviction path, + * comparisons of refaulted/(evicted+protected) from the first tier and the + * rest infer whether pages accessed multiple times through file descriptors + * are statistically hot and thus worth protecting. + * + * MAX_NR_TIERS is set to 4 so that the multi-gen LRU can support twice of the + * categories of the active/inactive LRU when keeping track of accesses through + * file descriptors. It requires MAX_NR_TIERS-2 additional bits in page->flags. + */ +#define MAX_NR_TIERS 4U + +#ifndef __GENERATING_BOUNDS_H + +struct lruvec; +struct mem_cgroup; +struct page_vma_mapped_walk; + +#define LRU_GEN_MASK ((BIT(LRU_GEN_WIDTH) - 1) << LRU_GEN_PGOFF) +#define LRU_REFS_MASK ((BIT(LRU_REFS_WIDTH) - 1) << LRU_REFS_PGOFF) +#define LRU_REFS_FLAGS (BIT(PG_referenced) | BIT(PG_workingset)) + +#ifdef CONFIG_LRU_GEN + +enum { + LRU_GEN_ANON, + LRU_GEN_FILE, +}; + +enum { + LRU_GEN_CORE, + LRU_GEN_MM_WALK, + LRU_GEN_NONLEAF_YOUNG, + NR_LRU_GEN_CAPS +}; + +#define MIN_LRU_BATCH BITS_PER_LONG +#define MAX_LRU_BATCH (MIN_LRU_BATCH * 128) + +/* whether to keep historical stats from evicted generations */ +#ifdef CONFIG_LRU_GEN_STATS +#define NR_HIST_GENS MAX_NR_GENS +#else +#define NR_HIST_GENS 1U +#endif + +/* + * The youngest generation number is stored in max_seq for both anon and file + * types as they are aged on an equal footing. The oldest generation numbers are + * stored in min_seq[] separately for anon and file types as clean file pages + * can be evicted regardless of swap constraints. + * + * Normally anon and file min_seq are in sync. But if swapping is constrained, + * e.g., out of swap space, file min_seq is allowed to advance and leave anon + * min_seq behind. + */ +struct lru_gen_struct { + /* the aging increments the youngest generation number */ + unsigned long max_seq; + /* the eviction increments the oldest generation numbers */ + unsigned long min_seq[ANON_AND_FILE]; + /* the birth time of each generation in jiffies */ + unsigned long timestamps[MAX_NR_GENS]; + /* the multi-gen LRU lists */ + struct list_head lists[MAX_NR_GENS][ANON_AND_FILE][MAX_NR_ZONES]; + /* the sizes of the above lists */ + unsigned long nr_pages[MAX_NR_GENS][ANON_AND_FILE][MAX_NR_ZONES]; + /* the exponential moving average of refaulted */ + unsigned long avg_refaulted[ANON_AND_FILE][MAX_NR_TIERS]; + /* the exponential moving average of evicted+protected */ + unsigned long avg_total[ANON_AND_FILE][MAX_NR_TIERS]; + /* the first tier doesn't need protection, hence the minus one */ + unsigned long protected[NR_HIST_GENS][ANON_AND_FILE][MAX_NR_TIERS - 1]; + /* can be modified without holding the LRU lock */ + atomic_long_t evicted[NR_HIST_GENS][ANON_AND_FILE][MAX_NR_TIERS]; + atomic_long_t refaulted[NR_HIST_GENS][ANON_AND_FILE][MAX_NR_TIERS]; + /* whether the multi-gen LRU is enabled */ + bool enabled; +}; + +enum { + MM_PTE_TOTAL, /* total leaf entries */ + MM_PTE_OLD, /* old leaf entries */ + MM_PTE_YOUNG, /* young leaf entries */ + MM_PMD_TOTAL, /* total non-leaf entries */ + MM_PMD_FOUND, /* non-leaf entries found in Bloom filters */ + MM_PMD_ADDED, /* non-leaf entries added to Bloom filters */ + NR_MM_STATS +}; + +/* mnemonic codes for the mm stats above */ +#define MM_STAT_CODES "toydfa" + +/* double-buffering Bloom filters */ +#define NR_BLOOM_FILTERS 2 + +struct lru_gen_mm_state { + /* set to max_seq after each iteration */ + unsigned long seq; + /* where the current iteration starts (inclusive) */ + struct list_head *head; + /* where the last iteration ends (exclusive) */ + struct list_head *tail; + /* to wait for the last page table walker to finish */ + struct wait_queue_head wait; + /* Bloom filters flip after each iteration */ + unsigned long *filters[NR_BLOOM_FILTERS]; + /* the mm stats for debugging */ + unsigned long stats[NR_HIST_GENS][NR_MM_STATS]; + /* the number of concurrent page table walkers */ + int nr_walkers; +}; + +struct lru_gen_mm_walk { + /* the lruvec under reclaim */ + struct lruvec *lruvec; + /* unstable max_seq from lru_gen_struct */ + unsigned long max_seq; + /* the next address within an mm to scan */ + unsigned long next_addr; + /* to batch page table entries */ + unsigned long bitmap[BITS_TO_LONGS(MIN_LRU_BATCH)]; + /* to batch promoted pages */ + int nr_pages[MAX_NR_GENS][ANON_AND_FILE][MAX_NR_ZONES]; + /* to batch the mm stats */ + int mm_stats[NR_MM_STATS]; + /* total batched items */ + int batched; + bool can_swap; + bool full_scan; +}; + +void lru_gen_init_lruvec(struct lruvec *lruvec); +void *lru_gen_eviction(struct page *page); +void lru_gen_refault(struct page *page, void *shadow); +void lru_gen_look_around(struct page_vma_mapped_walk *pvmw); + +#ifdef CONFIG_MEMCG +void lru_gen_init_memcg(struct mem_cgroup *memcg); +void lru_gen_exit_memcg(struct mem_cgroup *memcg); +#endif + +#else /* !CONFIG_LRU_GEN */ + +static inline void lru_gen_init_lruvec(struct lruvec *lruvec) +{ +} + +static inline void *lru_gen_eviction(struct page *page) +{ + return NULL; +} + +static inline void lru_gen_refault(struct page *page, void *shadow) +{ +} + +static inline void lru_gen_look_around(struct page_vma_mapped_walk *pvmw) +{ +} + +#ifdef CONFIG_MEMCG +static inline void lru_gen_init_memcg(struct mem_cgroup *memcg) +{ +} + +static inline void lru_gen_exit_memcg(struct mem_cgroup *memcg) +{ +} +#endif + +#endif /* CONFIG_LRU_GEN */ + struct lruvec { struct list_head lists[NR_LRU_LISTS]; struct zone_reclaim_stat reclaim_stat; @@ -253,6 +487,12 @@ struct lruvec { atomic_long_t inactive_age; /* Refaults at the time of last reclaim cycle */ unsigned long refaults; +#ifdef CONFIG_LRU_GEN + /* evictable pages divided into generations */ + struct lru_gen_struct lrugen; + /* to concurrently iterate lru_gen_mm_list */ + struct lru_gen_mm_state mm_state; +#endif #ifdef CONFIG_MEMCG struct pglist_data *pgdat; #endif @@ -280,10 +520,17 @@ enum zone_watermarks { NR_WMARK }; +#ifndef OPLUS_FEATURE_PERFORMANCE #define min_wmark_pages(z) (z->_watermark[WMARK_MIN] + z->watermark_boost) #define low_wmark_pages(z) (z->_watermark[WMARK_LOW] + z->watermark_boost) #define high_wmark_pages(z) (z->_watermark[WMARK_HIGH] + z->watermark_boost) #define wmark_pages(z, i) (z->_watermark[i] + z->watermark_boost) +#else +#define min_wmark_pages(z) (z->_watermark[WMARK_MIN] + z->watermark_boost/2) +#define low_wmark_pages(z) (z->_watermark[WMARK_LOW] + z->watermark_boost/2) +#define high_wmark_pages(z) (z->_watermark[WMARK_HIGH] + z->watermark_boost) +#define wmark_pages(z, i) (z->_watermark[i] + (((i) == WMARK_HIGH) ? (z->watermark_boost) : (z->watermark_boost / 2))) +#endif struct per_cpu_pages { int count; /* number of pages in the list */ @@ -370,6 +617,16 @@ enum zone_type { #ifndef __GENERATING_BOUNDS_H +#if defined(OPLUS_FEATURE_MULTI_FREEAREA) && defined(CONFIG_PHYSICAL_ANTI_FRAGMENTATION) +struct page_label { + unsigned long label; + unsigned long segment; +}; +#endif + + +#define ASYNC_AND_SYNC 2 + struct zone { /* Read-mostly fields */ @@ -378,7 +635,12 @@ struct zone { unsigned long watermark_boost; unsigned long nr_reserved_highatomic; - +#if defined(OPLUS_FEATURE_MEMORY_ISOLATE) && defined(CONFIG_OPLUS_MEMORY_ISOLATE) +/* + * Number of MIGRATE_OPLUS page block. + */ + unsigned long nr_migrate_oplus2_block; +#endif /* OPLUS_FEATURE_MEMORY_ISOLATE */ /* * We don't know if the memory that we're going to allocate will be * freeable or/and it will be released eventually, so to avoid totally @@ -455,7 +717,9 @@ struct zone { unsigned long managed_pages; unsigned long spanned_pages; unsigned long present_pages; - +#if defined(OPLUS_FEATURE_MULTI_FREEAREA) && defined(CONFIG_PHYSICAL_ANTI_FRAGMENTATION) + struct page_label zone_label[FREE_AREA_COUNTS]; +#endif const char *name; #ifdef CONFIG_MEMORY_ISOLATION @@ -478,7 +742,11 @@ struct zone { ZONE_PADDING(_pad1_) /* free areas of different sizes */ +#if defined(OPLUS_FEATURE_MULTI_FREEAREA) && defined(CONFIG_PHYSICAL_ANTI_FRAGMENTATION) + struct free_area free_area[FREE_AREA_COUNTS][MAX_ORDER]; +#else struct free_area free_area[MAX_ORDER]; +#endif /* zone flags, see below */ unsigned long flags; @@ -499,8 +767,8 @@ struct zone { #if defined CONFIG_COMPACTION || defined CONFIG_CMA /* pfn where compaction free scanner should start */ unsigned long compact_cached_free_pfn; - /* pfn where async and sync compaction migration scanner should start */ - unsigned long compact_cached_migrate_pfn[2]; + /* pfn where compaction migration scanner should start */ + unsigned long compact_cached_migrate_pfn[ASYNC_AND_SYNC]; unsigned long compact_init_migrate_pfn; unsigned long compact_init_free_pfn; #endif @@ -688,15 +956,20 @@ typedef struct pglist_data { int node_id; wait_queue_head_t kswapd_wait; wait_queue_head_t pfmemalloc_wait; +#if defined(OPLUS_FEATURE_MULTI_KSWAPD) && defined(CONFIG_OPLUS_MULTI_KSWAPD) + struct task_struct *kswapd[MAX_KSWAPD_THREADS]; +#else /* * Protected by mem_hotplug_begin/end() */ struct task_struct *kswapd[MAX_KSWAPD_THREADS]; +#endif int kswapd_order; enum zone_type kswapd_classzone_idx; int kswapd_failures; /* Number of 'reclaimed == 0' runs */ + u64 android_oem_data1; #ifdef CONFIG_COMPACTION int kcompactd_max_order; enum zone_type kcompactd_classzone_idx; @@ -742,11 +1015,16 @@ typedef struct pglist_data { unsigned long flags; +#ifdef CONFIG_LRU_GEN + /* kswap mm walk data */ + struct lru_gen_mm_walk mm_walk; +#endif + ZONE_PADDING(_pad2_) /* Per-node vmstats */ struct per_cpu_nodestat __percpu *per_cpu_nodestats; - atomic_long_t vm_stat[NR_VM_NODE_STAT_ITEMS]; + atomic_long_t vm_stat[NR_VM_NODE_STAT_ITEMS]; } pg_data_t; #define node_present_pages(nid) (NODE_DATA(nid)->node_present_pages) @@ -907,7 +1185,7 @@ static inline int is_highmem_idx(enum zone_type idx) } /** - * is_highmem - helper function to quickly check if a struct zone is a + * is_highmem - helper function to quickly check if a struct zone is a * highmem zone or not. This is an attempt to keep references * to ZONE_{DMA/NORMAL/HIGHMEM/etc} in general code to a minimum. * @zone - pointer to struct zone variable @@ -923,8 +1201,7 @@ static inline int is_highmem(struct zone *zone) /* These two functions are used to setup the per zone pages min values */ struct ctl_table; -int kswapd_threads_sysctl_handler(struct ctl_table *, int, - void __user *, size_t *, loff_t *); + int min_free_kbytes_sysctl_handler(struct ctl_table *, int, void __user *, size_t *, loff_t *); int watermark_boost_factor_sysctl_handler(struct ctl_table *, int, diff --git a/include/linux/msm_drm_notify.h b/include/linux/msm_drm_notify.h new file mode 100644 index 000000000000..7408c49184ec --- /dev/null +++ b/include/linux/msm_drm_notify.h @@ -0,0 +1,53 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ +#ifndef _MSM_DRM_NOTIFY_H_ +#define _MSM_DRM_NOTIFY_H_ + +#include + +/* A hardware display blank change occurred */ +#define MSM_DRM_EVENT_BLANK 0x01 +/* A hardware display blank early change occurred */ +#define MSM_DRM_EARLY_EVENT_BLANK 0x02 +#ifdef VENDOR_EDIT +/* event for onscreenfingerprint scene */ +#define MSM_DRM_ONSCREENFINGERPRINT_EVENT 0x10 +#endif /* VENDOR_EDIT */ + +enum { + /* panel: power on */ + MSM_DRM_BLANK_UNBLANK, + /* panel: power off */ + MSM_DRM_BLANK_POWERDOWN, +}; + +enum msm_drm_display_id { + /* primary display */ + MSM_DRM_PRIMARY_DISPLAY, + /* external display */ + MSM_DRM_EXTERNAL_DISPLAY, + MSM_DRM_DISPLAY_MAX +}; + +struct msm_drm_notifier { + enum msm_drm_display_id id; + void *data; +}; + +#ifdef CONFIG_DRM_MSM +int msm_drm_register_client(struct notifier_block *nb); +int msm_drm_unregister_client(struct notifier_block *nb); +#else +static inline int msm_drm_register_client(struct notifier_block *nb) +{ + return 0; +} + +static inline int msm_drm_unregister_client(struct notifier_block *nb) +{ + return 0; +} +#endif +#endif diff --git a/include/linux/multi_kswapd.h b/include/linux/multi_kswapd.h new file mode 100644 index 000000000000..bbc4b8195836 --- /dev/null +++ b/include/linux/multi_kswapd.h @@ -0,0 +1,33 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef __OPLUS_MULTI_KSWAPD__ +#define __OPLUS_MULTI_KSWAPD__ +#include + +#define MAX_KSWAPD_THREADS 16 + +extern int kswapd_threads; +extern int max_kswapd_threads; + +extern int kswapd_threads_sysctl_handler(struct ctl_table *, int, + void __user *, size_t *, loff_t *); +extern void update_kswapd_threads(void); +extern int kswapd_cpu_online_ext(unsigned int cpu); +extern int cpu_callback_ext(struct notifier_block *nfb, unsigned long action, + void *hcpu); +extern int kswapd_run_ext(int nid); +extern void kswapd_stop_ext(int nid); +extern int kswapd(void *p); + +#ifdef CONFIG_KSWAPD_UNBIND_MAX_CPU +extern int kswapd_unbind_cpu; +extern void upate_kswapd_unbind_cpu(void); + +static inline int kswapd_affinity_check(struct task_struct *p, const struct cpumask *mask) +{ + if (kswapd_unbind_cpu == -1) + return 0; + return (p->flags & PF_KSWAPD) && cpumask_test_cpu(kswapd_unbind_cpu, mask); +} +#endif +#endif /*__OPLUS_MULTI_KSWAPD__*/ diff --git a/include/linux/mutex.h b/include/linux/mutex.h index 8f7cdf83f359..5d6fb37fa45c 100644 --- a/include/linux/mutex.h +++ b/include/linux/mutex.h @@ -63,6 +63,9 @@ struct mutex { #ifdef CONFIG_DEBUG_LOCK_ALLOC struct lockdep_map dep_map; #endif +#ifdef OPLUS_FEATURE_SCHED_ASSIST + struct task_struct *ux_dep_task; +#endif /* OPLUS_FEATURE_SCHED_ASSIST */ }; /* @@ -88,6 +91,10 @@ struct mutex_waiter { #endif }; +#ifdef OPLUS_FEATURE_SCHED_ASSIST +#include +#endif /* OPLUS_FEATURE_SCHED_ASSIST */ + #ifdef CONFIG_DEBUG_MUTEXES #define __DEBUG_MUTEX_INITIALIZER(lockname) \ @@ -125,13 +132,22 @@ do { \ # define __DEP_MAP_MUTEX_INITIALIZER(lockname) #endif +#ifndef OPLUS_FEATURE_SCHED_ASSIST #define __MUTEX_INITIALIZER(lockname) \ { .owner = ATOMIC_LONG_INIT(0) \ , .wait_lock = __SPIN_LOCK_UNLOCKED(lockname.wait_lock) \ , .wait_list = LIST_HEAD_INIT(lockname.wait_list) \ __DEBUG_MUTEX_INITIALIZER(lockname) \ __DEP_MAP_MUTEX_INITIALIZER(lockname) } - +#else /* OPLUS_FEATURE_SCHED_ASSIST */ +#define __MUTEX_INITIALIZER(lockname) \ + { .owner = ATOMIC_LONG_INIT(0) \ + , .wait_lock = __SPIN_LOCK_UNLOCKED(lockname.wait_lock) \ + , .wait_list = LIST_HEAD_INIT(lockname.wait_list) \ + , .ux_dep_task = NULL \ + __DEBUG_MUTEX_INITIALIZER(lockname) \ + __DEP_MAP_MUTEX_INITIALIZER(lockname) } +#endif /* OPLUS_FEATURE_SCHED_ASSIST */ #define DEFINE_MUTEX(mutexname) \ struct mutex mutexname = __MUTEX_INITIALIZER(mutexname) diff --git a/include/linux/nodemask.h b/include/linux/nodemask.h index 326744b7d15e..eb8de9903c3c 100644 --- a/include/linux/nodemask.h +++ b/include/linux/nodemask.h @@ -484,6 +484,7 @@ static inline int num_node_state(enum node_states state) #define first_online_node 0 #define first_memory_node 0 #define next_online_node(nid) (MAX_NUMNODES) +#define next_memory_node(nid) (MAX_NUMNODES) #define nr_node_ids 1 #define nr_online_nodes 1 diff --git a/include/linux/of_reserved_mem.h b/include/linux/of_reserved_mem.h index 67ab8d271df3..eb9fc0372107 100644 --- a/include/linux/of_reserved_mem.h +++ b/include/linux/of_reserved_mem.h @@ -46,6 +46,10 @@ void fdt_init_reserved_mem(void); void fdt_reserved_mem_save_node(unsigned long node, const char *uname, phys_addr_t base, phys_addr_t size); struct reserved_mem *of_reserved_mem_lookup(struct device_node *np); + +#ifdef OPLUS_FEATURE_LOWMEM_DBG +unsigned long dt_memory_reserved_pages(void); +#endif /* OPLUS_FEATURE_LOWMEM_DBG */ #else static inline int of_reserved_mem_device_init_by_idx(struct device *dev, struct device_node *np, int idx) @@ -61,6 +65,12 @@ static inline struct reserved_mem *of_reserved_mem_lookup(struct device_node *np { return NULL; } + +#ifdef OPLUS_FEATURE_LOWMEM_DBG +unsigned long dt_memory_reserved_pages(void) { + return 0; +} +#endif /* OPLUS_FEATURE_LOWMEM_DBG */ #endif /** diff --git a/include/linux/oom.h b/include/linux/oom.h index 67093d6f6630..1134e7e4d528 100644 --- a/include/linux/oom.h +++ b/include/linux/oom.h @@ -148,4 +148,5 @@ extern int sysctl_reap_mem_on_sigkill; extern void add_to_oom_reaper(struct task_struct *p); extern void check_panic_on_foreground_kill(struct task_struct *p); #define ULMK_MAGIC "lmkd" +#define ATHENA_KILLER_MAGIC "athena_killer" #endif /* _INCLUDE_LINUX_OOM_H */ diff --git a/include/linux/oplus_kevent.h b/include/linux/oplus_kevent.h new file mode 100644 index 000000000000..e16c1db9046e --- /dev/null +++ b/include/linux/oplus_kevent.h @@ -0,0 +1,48 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/************************************************************** +* Copyright (c) 2008- 2020 Oplus. All rights reserved. +* VENDOR_EDIT +* File : oplus_kevent.h +* Description: For kevent action upload upload to user layer +* Version : 1.0 +* Date : 2019-12-19 +* Author : +* TAG : +****************************************************************/ +#ifndef __LINUX_OPLUS_KEVENT_H +#define __LINUX_OPLUS_KEVENT_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_OPLUS_KEVENT_UPLOAD + +#define NETLINK_OPLUS_KEVENT 34 + +struct kernel_packet_info +{ + int type; /* 0:root,1:only string,other number represent other type */ + char log_tag[32]; /* logTag */ + char event_id[20]; /*eventID */ + size_t payload_length; /* Length of packet data */ + unsigned char payload[0]; /* Optional packet data */ +}__attribute__((packed)); + +int kevent_send_to_user(struct kernel_packet_info *userinfo); +void kernel_kevent_receive(struct sk_buff *__skbbr); +#endif /* CONFIG_OPLUS_KEVENT_UPLOAD */ + +#ifdef CONFIG_OPLUS_KEVENT_TEST +ssize_t demo_kevent_write(struct file *filp, const char __user *buffer, size_t count, loff_t *f_pos); +#endif /* CONFIG_OPLUS_KEVENT_TEST */ +#endif /* __LINUX_OPLUS_KEVENT_H */ diff --git a/include/linux/oplus_memory_isolate.h b/include/linux/oplus_memory_isolate.h new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/include/linux/oplus_midas.h b/include/linux/oplus_midas.h new file mode 100644 index 000000000000..2f2b98b2fa2a --- /dev/null +++ b/include/linux/oplus_midas.h @@ -0,0 +1,20 @@ +/* + * SPDX-License-Identifier: GPL-2.0-only + * + * Copyright (C) 2019-2020 Oplus. All rights reserved. + */ + +#ifndef __OPLUS_MIDAS_H__ +#define __OPLUS_MIDAS_H__ + +#include + +#ifdef CONFIG_OPLUS_FEATURE_MIDAS +void midas_record_task_times(uid_t uid, u64 cputime, + struct task_struct *p, unsigned int state); +#else +static inline void midas_record_task_times(uid_t uid, u64 cputime, + struct task_struct *p, unsigned int state) { } +#endif + +#endif /* __OPLUS_MIDAS_H__ */ diff --git a/include/linux/page-flags-layout.h b/include/linux/page-flags-layout.h index 71283739ffd2..75d204d13b77 100644 --- a/include/linux/page-flags-layout.h +++ b/include/linux/page-flags-layout.h @@ -56,7 +56,8 @@ #define ZONES_WIDTH ZONES_SHIFT -#if SECTIONS_WIDTH+ZONES_WIDTH+NODES_SHIFT <= BITS_PER_LONG - NR_PAGEFLAGS +#if SECTIONS_WIDTH+ZONES_WIDTH+NODES_SHIFT+LRU_GEN_WIDTH+LRU_REFS_WIDTH \ + <= BITS_PER_LONG - NR_PAGEFLAGS #define NODES_WIDTH NODES_SHIFT #else #ifdef CONFIG_SPARSEMEM_VMEMMAP @@ -83,15 +84,15 @@ #define KASAN_TAG_WIDTH 0 #endif -#if SECTIONS_WIDTH+ZONES_WIDTH+NODES_SHIFT+LAST_CPUPID_SHIFT+KASAN_TAG_WIDTH \ - <= BITS_PER_LONG - NR_PAGEFLAGS +#if SECTIONS_WIDTH+ZONES_WIDTH+NODES_WIDTH+LRU_GEN_WIDTH+LRU_REFS_WIDTH+ \ + LAST_CPUPID_SHIFT+KASAN_TAG_WIDTH <= BITS_PER_LONG - NR_PAGEFLAGS #define LAST_CPUPID_WIDTH LAST_CPUPID_SHIFT #else #define LAST_CPUPID_WIDTH 0 #endif -#if SECTIONS_WIDTH+NODES_WIDTH+ZONES_WIDTH+LAST_CPUPID_WIDTH+KASAN_TAG_WIDTH \ - > BITS_PER_LONG - NR_PAGEFLAGS +#if SECTIONS_WIDTH+ZONES_WIDTH+NODES_WIDTH+LRU_GEN_WIDTH+LRU_REFS_WIDTH+ \ + LAST_CPUPID_WIDTH+KASAN_TAG_WIDTH > BITS_PER_LONG - NR_PAGEFLAGS #error "Not enough bits in page flags" #endif diff --git a/include/linux/page-flags.h b/include/linux/page-flags.h index 260c4421d3c0..caac400cce30 100644 --- a/include/linux/page-flags.h +++ b/include/linux/page-flags.h @@ -98,7 +98,7 @@ enum pageflags { #ifdef CONFIG_MEMORY_FAILURE PG_hwpoison, /* hardware poisoned page. Don't touch */ #endif -#if defined(CONFIG_IDLE_PAGE_TRACKING) && defined(CONFIG_64BIT) +#if defined(CONFIG_PAGE_IDLE_FLAG) && defined(CONFIG_64BIT) PG_young, PG_idle, #endif @@ -382,7 +382,7 @@ static inline bool set_hwpoison_free_buddy_page(struct page *page) #define __PG_HWPOISON 0 #endif -#if defined(CONFIG_IDLE_PAGE_TRACKING) && defined(CONFIG_64BIT) +#if defined(CONFIG_PAGE_IDLE_FLAG) && defined(CONFIG_64BIT) TESTPAGEFLAG(Young, young, PF_ANY) SETPAGEFLAG(Young, young, PF_ANY) TESTCLEARFLAG(Young, young, PF_ANY) @@ -770,7 +770,7 @@ static inline void ClearPageSlabPfmemalloc(struct page *page) 1UL << PG_private | 1UL << PG_private_2 | \ 1UL << PG_writeback | 1UL << PG_reserved | \ 1UL << PG_slab | 1UL << PG_active | \ - 1UL << PG_unevictable | __PG_MLOCKED) + 1UL << PG_unevictable | __PG_MLOCKED | LRU_GEN_MASK) /* * Flags checked when a page is prepped for return by the page allocator. @@ -781,7 +781,7 @@ static inline void ClearPageSlabPfmemalloc(struct page *page) * alloc-free cycle to prevent from reusing the page. */ #define PAGE_FLAGS_CHECK_AT_PREP \ - (((1UL << NR_PAGEFLAGS) - 1) & ~__PG_HWPOISON) + ((((1UL << NR_PAGEFLAGS) - 1) & ~__PG_HWPOISON) | LRU_GEN_MASK | LRU_REFS_MASK) #define PAGE_FLAGS_PRIVATE \ (1UL << PG_private | 1UL << PG_private_2) diff --git a/include/linux/page_ext.h b/include/linux/page_ext.h index 00e8988e5a84..fe28aaafd64d 100644 --- a/include/linux/page_ext.h +++ b/include/linux/page_ext.h @@ -20,7 +20,7 @@ enum page_ext_flags { PAGE_EXT_DEBUG_GUARD, PAGE_EXT_OWNER, PAGE_EXT_PG_FREE, -#if defined(CONFIG_IDLE_PAGE_TRACKING) && !defined(CONFIG_64BIT) +#if defined(CONFIG_PAGE_IDLE_FLAG) && !defined(CONFIG_64BIT) PAGE_EXT_YOUNG, PAGE_EXT_IDLE, #endif diff --git a/include/linux/page_idle.h b/include/linux/page_idle.h index 1e894d34bdce..d8a6aecf99cb 100644 --- a/include/linux/page_idle.h +++ b/include/linux/page_idle.h @@ -6,7 +6,7 @@ #include #include -#ifdef CONFIG_IDLE_PAGE_TRACKING +#ifdef CONFIG_PAGE_IDLE_FLAG #ifdef CONFIG_64BIT static inline bool page_is_young(struct page *page) @@ -106,7 +106,7 @@ static inline void clear_page_idle(struct page *page) } #endif /* CONFIG_64BIT */ -#else /* !CONFIG_IDLE_PAGE_TRACKING */ +#else /* !CONFIG_PAGE_IDLE_FLAG */ static inline bool page_is_young(struct page *page) { @@ -135,6 +135,6 @@ static inline void clear_page_idle(struct page *page) { } -#endif /* CONFIG_IDLE_PAGE_TRACKING */ +#endif /* CONFIG_PAGE_IDLE_FLAG */ #endif /* _LINUX_MM_PAGE_IDLE_H */ diff --git a/include/linux/pm_wakeup.h b/include/linux/pm_wakeup.h index 6e6a25220c56..74a57b05e791 100644 --- a/include/linux/pm_wakeup.h +++ b/include/linux/pm_wakeup.h @@ -62,6 +62,9 @@ struct wakeup_source { struct timer_list timer; unsigned long timer_expires; ktime_t total_time; + #ifdef OPLUS_FEATURE_POWERINFO_STANDBY + ktime_t total_time_backup; + #endif /*OPLUS_FEATURE_POWERINFO_STANDBY*/ ktime_t max_time; ktime_t last_time; ktime_t start_prevent_time; diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h index 72fe67bf5efc..452eb56184d6 100644 --- a/include/linux/power_supply.h +++ b/include/linux/power_supply.h @@ -163,7 +163,31 @@ enum { enum power_supply_property { /* Properties of type `int' */ - POWER_SUPPLY_PROP_STATUS = 0, +//#ifdef OPLUS_FEATURE_CHG_BASIC + POWER_SUPPLY_PROP_CHARGE_TECHNOLOGY = 0, + POWER_SUPPLY_PROP_FAST_CHARGE, + POWER_SUPPLY_PROP_MMI_CHARGING_ENABLE, + POWER_SUPPLY_PROP_OTG_SWITCH, + POWER_SUPPLY_PROP_OTG_ONLINE, + POWER_SUPPLY_PROP_FAST_CHG_TYPE, + POWER_SUPPLY_PROP_BATTERY_FCC, + POWER_SUPPLY_PROP_BATTERY_SOH, + POWER_SUPPLY_PROP_BATTERY_CC, + POWER_SUPPLY_PROP_BATTERY_RM, + POWER_SUPPLY_PROP_BATTERY_SOC, + POWER_SUPPLY_PROP_AUTHENTICATE, + POWER_SUPPLY_PROP_CHARGE_TIMEOUT, + POWER_SUPPLY_PROP_BATTERY_NOTIFY_CODE, + POWER_SUPPLY_PROP_COOL_DOWN, + POWER_SUPPLY_PROP_USB_STATUS, + POWER_SUPPLY_PROP_EM_MODE, + POWER_SUPPLY_PROP_SUB_CURRENT, + POWER_SUPPLY_PROP_USBTEMP_VOLT_L, + POWER_SUPPLY_PROP_USBTEMP_VOLT_R, + POWER_SUPPLY_PROP_BATTERY_INFO, + POWER_SUPPLY_PROP_BATTERY_INFO_ID, +//#endif /* OPLUS_FEATURE_CHG_BASIC */ + POWER_SUPPLY_PROP_STATUS, POWER_SUPPLY_PROP_CHARGE_TYPE, POWER_SUPPLY_PROP_HEALTH, POWER_SUPPLY_PROP_PRESENT, @@ -256,6 +280,7 @@ enum power_supply_property { POWER_SUPPLY_PROP_COLD_TEMP, POWER_SUPPLY_PROP_HOT_TEMP, POWER_SUPPLY_PROP_SYSTEM_TEMP_LEVEL, + POWER_SUPPLY_PROP_OP_DISABLE_CHARGE, POWER_SUPPLY_PROP_RESISTANCE, POWER_SUPPLY_PROP_RESISTANCE_CAPACITIVE, POWER_SUPPLY_PROP_RESISTANCE_ID, /* in Ohms */ @@ -368,6 +393,47 @@ enum power_supply_property { POWER_SUPPLY_PROP_CHARGER_STATUS, /* Local extensions of type int64_t */ POWER_SUPPLY_PROP_CHARGE_COUNTER_EXT, +//#ifdef OPLUS_FEATURE_CHG_BASIC + POWER_SUPPLY_PROP_ADAPTER_FW_UPDATE, + POWER_SUPPLY_PROP_VOOCCHG_ING, + POWER_SUPPLY_PROP_CHARGERID_VOLT, + POWER_SUPPLY_PROP_SHIP_MODE, + POWER_SUPPLY_PROP_CALL_MODE, +#ifdef CONFIG_OPLUS_CHIP_SOC_NODE + POWER_SUPPLY_PROP_CHIP_SOC, +#endif +#ifdef CONFIG_OPLUS_SMOOTH_SOC + POWER_SUPPLY_PROP_SMOOTH_SOC, + POWER_SUPPLY_PROP_SMOOTH_SWITCH, +#endif +#ifdef CONFIG_OPLUS_SHORT_USERSPACE + POWER_SUPPLY_PROP_SHORT_C_LIMIT_CHG, + POWER_SUPPLY_PROP_SHORT_C_LIMIT_RECHG, +#else + POWER_SUPPLY_PROP_SHORT_C_BATT_UPDATE_CHANGE, + POWER_SUPPLY_PROP_SHORT_C_BATT_IN_IDLE, + POWER_SUPPLY_PROP_SHORT_C_BATT_CV_STATUS, +#endif /*CONFIG_OPLUS_SHORT_USERSPACE*/ +#ifdef CONFIG_OPLUS_SHORT_HW_CHECK + POWER_SUPPLY_PROP_SHORT_C_HW_FEATURE, + POWER_SUPPLY_PROP_SHORT_C_HW_STATUS, +#endif +#ifdef CONFIG_OPLUS_SHORT_IC_CHECK + POWER_SUPPLY_PROP_SHORT_C_IC_OTP_STATUS, + POWER_SUPPLY_PROP_SHORT_C_IC_VOLT_THRESH, + POWER_SUPPLY_PROP_SHORT_C_IC_OTP_VALUE, +#endif + POWER_SUPPLY_PROP_CP_DISABLE_CUR_SENS, +// add by huangtongfeng for wireless file + POWER_SUPPLY_PROP_TX_VOLTAGE_NOW, + POWER_SUPPLY_PROP_TX_CURRENT_NOW, + POWER_SUPPLY_PROP_CP_VOLTAGE_NOW, + POWER_SUPPLY_PROP_CP_CURRENT_NOW, + POWER_SUPPLY_PROP_WIRELESS_MODE, + POWER_SUPPLY_PROP_WIRELESS_TYPE, + POWER_SUPPLY_PROP_CEP_INFO, +// wireless file end +//#endif /*OPLUS_FEATURE_CHG_BASIC*/ /* Properties of type `const char *' */ POWER_SUPPLY_PROP_MODEL_NAME, POWER_SUPPLY_PROP_MANUFACTURER, @@ -378,6 +444,14 @@ enum power_supply_property { * MODEL_NAME and SERIAL_NUMBER. Don't add below SERIAL_NUMBER. */ POWER_SUPPLY_PROP_SERIAL_NUMBER, +#ifdef OPLUS_CUSTOM_OP_DEF + POWER_SUPPLY_PROP_RESET_RD, +#endif +#ifdef OPLUS_FEATURE_CHG_BASIC + POWER_SUPPLY_PROP_PARALLEL_CURRENT_NOW, + POWER_SUPPLY_PROP_SMB1355_TEST, +#endif + POWER_SUPPLY_PROP_VBATDET, }; enum power_supply_type { @@ -405,6 +479,9 @@ enum power_supply_type { POWER_SUPPLY_TYPE_UFP, /* Type-C UFP */ POWER_SUPPLY_TYPE_DFP, /* Type-C DFP */ POWER_SUPPLY_TYPE_CHARGE_PUMP, /* Charge Pump */ + POWER_SUPPLY_WIRELESS_TYPE_BPP, + POWER_SUPPLY_WIRELESS_TYPE_EPP, + POWER_SUPPLY_WIRELESS_TYPE_FAST, }; enum power_supply_usb_type { diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h index c609d993511b..9ac671ffd7ab 100644 --- a/include/linux/proc_fs.h +++ b/include/linux/proc_fs.h @@ -76,6 +76,36 @@ struct proc_dir_entry *proc_create_net_single_write(const char *name, umode_t mo void *data); extern struct pid *tgid_pidfd_to_pid(const struct file *file); +#ifdef OPLUS_FEATURE_POWERINFO_RPMH +#define DEFINE_PROC_SHOW_ATTRIBUTE(__name) \ +static int __name ## _open(struct inode *inode, struct file *file)\ +{ \ + return single_open(file, __name ## _show, PDE_DATA(inode)); \ +} \ + \ +static const struct file_operations __name ## _fops = { \ + .owner = THIS_MODULE, \ + .open = __name ## _open, \ + .read = seq_read, \ + .llseek = seq_lseek, \ + .release = single_release, \ +} + +#define DEFINE_PROC_SHOW_STORE_ATTRIBUTE(__name) \ +static int __name ## _open(struct inode *inode, struct file *file)\ +{ \ + return single_open(file, __name ## _show, PDE_DATA(inode));\ +} \ + \ +static const struct file_operations __name ## _fops = {\ + .owner = THIS_MODULE, \ + .open = __name ## _open, \ + .read = seq_read, \ + .llseek = seq_lseek, \ + .release = single_release, \ + .write = __name ## _store, \ +} +#endif /*OPLUS_FEATURE_POWERINFO_RPMH*/ #else /* CONFIG_PROC_FS */ static inline void proc_root_init(void) diff --git a/include/linux/process_mm_reclaim.h b/include/linux/process_mm_reclaim.h new file mode 120000 index 000000000000..e75a7e35c1f2 --- /dev/null +++ b/include/linux/process_mm_reclaim.h @@ -0,0 +1 @@ +../../../../vendor/oplus/kernel/oplus_performance/process_reclaim/process_mm_reclaim.h \ No newline at end of file diff --git a/include/linux/pstore.h b/include/linux/pstore.h index de9093d6e660..e5002ac17c56 100644 --- a/include/linux/pstore.h +++ b/include/linux/pstore.h @@ -30,6 +30,10 @@ #include #include +#ifdef OPLUS_FEATURE_DUMPDEVICE +#include +#endif /* OPLUS_FEATURE_DUMPDEVICE */ + struct module; /* pstore record types (see fs/pstore/inode.c for filename templates) */ @@ -44,6 +48,7 @@ enum pstore_type_id { PSTORE_TYPE_PPC_COMMON = 6, PSTORE_TYPE_PMSG = 7, PSTORE_TYPE_PPC_OPAL = 8, + PSTORE_TYPE_DEVICE_INFO = 9, PSTORE_TYPE_UNKNOWN = 255 }; @@ -276,4 +281,36 @@ pstore_ftrace_write_timestamp(struct pstore_ftrace_record *rec, u64 val) } #endif +#ifdef OPLUS_FEATURE_DUMPDEVICE +/*move from ram.c*/ +struct ramoops_context { + struct persistent_ram_zone **dprzs; /* Oops dump zones */ + struct persistent_ram_zone *cprz; /* Console zone */ + struct persistent_ram_zone **fprzs; /* Ftrace zones */ + struct persistent_ram_zone *mprz; /* PMSG zone */ + struct persistent_ram_zone *dprz; + phys_addr_t phys_addr; + unsigned long size; + unsigned int memtype; + size_t record_size; + size_t console_size; + size_t ftrace_size; + size_t pmsg_size; + size_t device_info_size; + int dump_oops; + u32 flags; + struct persistent_ram_ecc_info ecc_info; + unsigned int max_dump_cnt; + unsigned int dump_write_cnt; + /* _read_cnt need clear on ramoops_pstore_open */ + unsigned int dump_read_cnt; + unsigned int console_read_cnt; + unsigned int max_ftrace_cnt; + unsigned int ftrace_read_cnt; + unsigned int pmsg_read_cnt; + unsigned int device_info_read_cnt; + struct pstore_info pstore; +}; +#endif + #endif /*_LINUX_PSTORE_H*/ diff --git a/include/linux/pstore_ram.h b/include/linux/pstore_ram.h index e6d226464838..3fac93da08ff 100644 --- a/include/linux/pstore_ram.h +++ b/include/linux/pstore_ram.h @@ -81,6 +81,9 @@ void persistent_ram_free_old(struct persistent_ram_zone *prz); ssize_t persistent_ram_ecc_string(struct persistent_ram_zone *prz, char *str, size_t len); +#ifdef OPLUS_FEATURE_DUMPDEVICE +void ramoops_console_write_buf(const char *buf, size_t size); +#endif /* OPLUS_FEATURE_DUMPDEVICE */ /* * Ramoops platform data * @mem_size memory size for ramoops @@ -97,6 +100,9 @@ struct ramoops_platform_data { unsigned long console_size; unsigned long ftrace_size; unsigned long pmsg_size; +#ifdef OPLUS_FEATURE_DUMPDEVICE + unsigned long device_info_size; +#endif /* OPLUS_FEATURE_DUMPDEVICE */ int dump_oops; u32 flags; struct persistent_ram_ecc_info ecc_info; diff --git a/include/linux/qcom-geni-se.h b/include/linux/qcom-geni-se.h index 3e2888af87c3..4c7a6e86a9bb 100644 --- a/include/linux/qcom-geni-se.h +++ b/include/linux/qcom-geni-se.h @@ -70,6 +70,10 @@ struct se_geni_rsc { struct pinctrl *geni_pinctrl; struct pinctrl_state *geni_gpio_active; struct pinctrl_state *geni_gpio_sleep; +#ifdef OPLUS_FEATURE_CHG_BASIC + struct pinctrl_state *geni_gpio_pulldown; + struct pinctrl_state *geni_gpio_pullup; +#endif int clk_freq_out; unsigned int num_clk_levels; unsigned long *clk_perf_tbl; @@ -78,6 +82,10 @@ struct se_geni_rsc { #define PINCTRL_DEFAULT "default" #define PINCTRL_ACTIVE "active" #define PINCTRL_SLEEP "sleep" +#ifdef OPLUS_FEATURE_CHG_BASIC +#define PINCTRL_PULLDOWN "pulldown" +#define PINCTRL_PULLUP "pullup" +#endif #define KHz(freq) (1000 * (freq)) @@ -678,6 +686,20 @@ int geni_se_clk_freq_match(struct se_geni_rsc *rsc, unsigned long req_freq, int geni_se_tx_dma_prep(struct device *wrapper_dev, void __iomem *base, void *tx_buf, int tx_len, dma_addr_t *tx_dma); +#ifdef OPLUS_FEATURE_CHG_BASIC +/** + * geni_se_rx_dma_start() - Prepare the Serial Engine registers for RX DMA + transfers. + * @base: Base address of the SE register block. + * @rx_len: Length of the RX buffer. + * @rx_dma: Pointer to store the mapped DMA address. + * + * This function is used to prepare the Serial Engine registers for DMA RX. + * + * Return: None. + */ +void geni_se_rx_dma_start(void __iomem *base, int rx_len, dma_addr_t *rx_dma); +#endif /** * geni_se_rx_dma_start() - Prepare the Serial Engine registers for RX DMA transfers. diff --git a/include/linux/ratelimit.h b/include/linux/ratelimit.h index 1df12e8dde6f..77c913a67ad3 100644 --- a/include/linux/ratelimit.h +++ b/include/linux/ratelimit.h @@ -6,6 +6,7 @@ #include #include + #define DEFAULT_RATELIMIT_INTERVAL (5 * HZ) #define DEFAULT_RATELIMIT_BURST 10 diff --git a/include/linux/reserve_area.h b/include/linux/reserve_area.h new file mode 120000 index 000000000000..5b92c2eb1af1 --- /dev/null +++ b/include/linux/reserve_area.h @@ -0,0 +1 @@ +../../../../vendor/oplus/kernel/oplus_performance/gloom_new/reserve_area.h \ No newline at end of file diff --git a/include/linux/resmap_account.h b/include/linux/resmap_account.h new file mode 120000 index 000000000000..f3c0664fa0da --- /dev/null +++ b/include/linux/resmap_account.h @@ -0,0 +1 @@ +../../../../vendor/oplus/kernel/oplus_performance/gloom/resmap_account.h \ No newline at end of file diff --git a/include/linux/rmap.h b/include/linux/rmap.h index 4e21a2cbf144..f0780b70cac8 100644 --- a/include/linux/rmap.h +++ b/include/linux/rmap.h @@ -14,8 +14,15 @@ extern int isolate_lru_page(struct page *page); extern void putback_lru_page(struct page *page); +#if defined(OPLUS_FEATURE_PROCESS_RECLAIM) && defined(CONFIG_PROCESS_RECLAIM_ENHANCE) extern unsigned long reclaim_pages_from_list(struct list_head *page_list, - struct vm_area_struct *vma); + struct vm_area_struct *vma, struct mm_walk *walk); +#else +extern unsigned long reclaim_pages_from_list(struct list_head *page_list, + struct vm_area_struct *vma); +#endif + +extern unsigned long reclaim_pages(struct list_head *page_list); /* * The anon_vma heads a list of private "related" vmas, to scan if diff --git a/include/linux/rwsem.h b/include/linux/rwsem.h index 4b3cfa53472c..5ec09f277741 100644 --- a/include/linux/rwsem.h +++ b/include/linux/rwsem.h @@ -22,6 +22,15 @@ struct rw_semaphore; +#ifdef OPLUS_FEATURE_SCHED_ASSIST +//#ifdef CONFIG_UXCHAIN_V2 +extern void uxchain_rwsem_wake(struct task_struct *tsk, + struct rw_semaphore *sem); +extern void uxchain_rwsem_down(struct rw_semaphore *sem); +extern void uxchain_rwsem_up(struct rw_semaphore *sem); +#define PREEMPT_DISABLE_RWSEM 3000000 +#endif + #ifdef CONFIG_RWSEM_GENERIC_SPINLOCK #include /* use a generic implementation */ #define __RWSEM_INIT_COUNT(name) .count = RWSEM_UNLOCKED_VALUE @@ -46,6 +55,9 @@ struct rw_semaphore { /* count for waiters preempt to queue in wait list */ long m_count; #endif +#ifdef OPLUS_FEATURE_SCHED_ASSIST + struct task_struct *ux_dep_task; +#endif /* OPLUS_FEATURE_SCHED_ASSIST */ }; /* @@ -61,6 +73,10 @@ extern struct rw_semaphore *rwsem_down_write_failed_killable(struct rw_semaphore extern struct rw_semaphore *rwsem_wake(struct rw_semaphore *); extern struct rw_semaphore *rwsem_downgrade_wake(struct rw_semaphore *sem); +#ifdef OPLUS_FEATURE_SCHED_ASSIST +#include +#endif /* OPLUS_FEATURE_SCHED_ASSIST */ + /* Include the arch specific part */ #include @@ -82,7 +98,11 @@ static inline int rwsem_is_locked(struct rw_semaphore *sem) #endif #ifdef CONFIG_RWSEM_SPIN_ON_OWNER +#ifndef OPLUS_FEATURE_SCHED_ASSIST #define __RWSEM_OPT_INIT(lockname) , .osq = OSQ_LOCK_UNLOCKED, .owner = NULL +#else /* OPLUS_FEATURE_SCHED_ASSIST */ +#define __RWSEM_OPT_INIT(lockname) , .osq = OSQ_LOCK_UNLOCKED, .owner = NULL, .ux_dep_task = NULL +#endif /* OPLUS_FEATURE_SCHED_ASSIST */ #else #define __RWSEM_OPT_INIT(lockname) #endif diff --git a/include/linux/sched.h b/include/linux/sched.h index 89bd6a449033..32b30e237dcd 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -6,7 +6,6 @@ * Define 'struct task_struct' and provide the main scheduler * APIs (schedule(), wakeup variants, etc.) */ - #include #include @@ -31,6 +30,24 @@ #include #include +#ifdef OPLUS_FEATURE_HEALTHINFO +#ifdef CONFIG_OPLUS_JANK_INFO +#include +#endif +#endif /* OPLUS_FEATURE_HEALTHINFO */ + +#ifdef VENDOR_EDIT +extern void show_regs(struct pt_regs *); +#endif /* VENDOR_EDIT */ + +#ifdef CONFIG_OPLUS_FEATURE_AUDIO_OPT +#include +#endif + +#ifdef CONFIG_OPLUS_FEATURE_INPUT_BOOST_V4 +#include +#endif /* CONFIG_OPLUS_FEATURE_INPUT_BOOST_V4 */ + /* task_struct member predeclarations (sorted alphabetically): */ struct audit_context; struct backing_dev_info; @@ -227,6 +244,22 @@ enum fps { #endif +#ifdef OPLUS_FEATURE_SCHED_ASSIST +extern int sysctl_sched_assist_enabled; +extern int sysctl_sched_assist_scene; +#endif /* OPLUS_FEATURE_SCHED_ASSIST */ +#ifdef OPLUS_FEATURE_SCHED_ASSIST +extern int sysctl_cpu_multi_thread; +#endif +#ifdef OPLUS_FEATURE_SCHED_ASSIST +extern int sysctl_slide_boost_enabled; +extern int sysctl_boost_task_threshold; +#endif /* OPLUS_FEATURE_SCHED_ASSIST */ +#ifdef OPLUS_FEATURE_SCHED_ASSIST +extern int sysctl_prefer_silver; +extern int sysctl_heavy_task_thresh; +extern int sysctl_cpu_util_thresh; +#endif /* OPLUS_FEATURE_SCHED_ASSIST */ /* Task command name length: */ #define TASK_COMM_LEN 16 @@ -645,6 +678,12 @@ struct ravg { u16 pred_demand_scaled; u64 active_time; u64 last_win_size; +#ifdef CONFIG_OPLUS_FEATURE_INPUT_BOOST_V4 + u64 curr_window_exec; + u64 prev_window_exec; + u64 curr_window_scale; + u64 prev_window_scale; +#endif /* CONFIG_OPLUS_FEATURE_INPUT_BOOST_V4 */ }; #else static inline void sched_exit(struct task_struct *p) { } @@ -806,6 +845,11 @@ union rcu_special { u32 s; /* Set of bits. */ }; +#ifdef CONFIG_OPLUS_FEATURE_RT_INFO +typedef void (*rt_info_handler)(void *task); +extern void register_rt_info_handler(rt_info_handler func); +#endif + enum perf_event_task_context { perf_invalid_context = -1, perf_hw_context = 0, @@ -817,6 +861,24 @@ struct wake_q_node { struct wake_q_node *next; }; +#if IS_ENABLED(CONFIG_OPLUS_FEATURE_CPU_JANKINFO) +#define OPLUS_NR_CPUS (8) +/* hot-thread */ +struct task_record { +#define RECOED_WINSIZE (1 << 8) +#define RECOED_WINIDX_MASK (RECOED_WINSIZE - 1) + u8 winidx; + u8 count; +}; +#endif + +#if defined(OPLUS_FEATURE_PROCESS_RECLAIM) && defined(CONFIG_PROCESS_RECLAIM_ENHANCE) +union reclaim_limit { + unsigned long stop_jiffies; + unsigned long stop_scan_addr; +}; +#endif + struct task_struct { #ifdef CONFIG_THREAD_INFO_IN_TASK /* @@ -840,6 +902,11 @@ struct task_struct { unsigned int flags; unsigned int ptrace; +#if defined(OPLUS_FEATURE_TASK_CPUSTATS) && defined(CONFIG_OPLUS_SCHED) + u64 wake_tid; + u64 running_start_time; +#endif /* defined(OPLUS_FEATURE_TASK_CPUSTATS) && defined(CONFIG_OPLUS_SCHED) */ + #ifdef CONFIG_SMP struct llist_node wake_entry; int on_cpu; @@ -989,6 +1056,10 @@ struct task_struct { unsigned memcg_kmem_skip_account:1; #endif #endif +#ifdef CONFIG_LRU_GEN + /* whether the LRU algorithm may apply to this access */ + unsigned in_lru_fault:1; +#endif #ifdef CONFIG_COMPAT_BRK unsigned brk_randomized:1; #endif @@ -1383,6 +1454,25 @@ struct task_struct { int latency_record_count; struct latency_record latency_record[LT_SAVECOUNT]; #endif +#if defined(OPLUS_FEATURE_MEMLEAK_DETECT) && defined(CONFIG_ION) && defined(CONFIG_DUMP_TASKS_MEM) + struct list_head user_tasks; + atomic64_t ions; +#endif + +#ifdef CONFIG_OPLUS_FEATURE_UID_PERF +#define UID_PERF_EVENTS 3 + struct perf_event* uid_pevents[UID_PERF_EVENTS]; + long long uid_counts[UID_PERF_EVENTS]; + long long uid_prev_counts[UID_PERF_EVENTS]; + long long uid_leaving_counts[UID_PERF_EVENTS]; + + /* define for grouping info */ +#define UID_GROUP_SIZE 8 + long long uid_group[UID_GROUP_SIZE]; + long long uid_group_prev_counts[UID_GROUP_SIZE]; + long long uid_group_snapshot_prev_counts[UID_GROUP_SIZE]; +#endif + /* * Time slack values; these are used to round up poll() and * select() etc timeout values. These are in nanoseconds. @@ -1460,7 +1550,9 @@ struct task_struct { #ifdef CONFIG_BLK_CGROUP struct request_queue *throttle_queue; #endif - +#if defined(OPLUS_FEATURE_PROCESS_RECLAIM) && defined(CONFIG_PROCESS_RECLAIM_ENHANCE) + union reclaim_limit reclaim; +#endif #ifdef CONFIG_UPROBES struct uprobe_task *utask; #endif @@ -1488,8 +1580,70 @@ struct task_struct { #ifdef CONFIG_SECURITY /* Used by LSM modules for access restriction: */ void *security; +#endif +#ifdef OPLUS_FEATURE_SCHED_ASSIST + int ux_state; + atomic64_t inherit_ux; + struct list_head ux_entry; + int ux_depth; + u64 enqueue_time; + u64 inherit_ux_start; +#ifdef CONFIG_OPLUS_FEATURE_SCHED_SPREAD + int lb_state; + int ld_flag; +#endif +#endif /* OPLUS_FEATURE_SCHED_ASSIST */ +#ifdef OPLUS_FEATURE_SCHED_ASSIST +//#ifdef CONFIG_UXCHAIN_V2 + int ux_once; + u64 get_mmlock_ts; + int get_mmlock; +#endif +#ifdef CONFIG_OPLUS_FEATURE_AUDIO_OPT + struct task_info oplus_task_info; +#endif + +#if IS_ENABLED(CONFIG_OPLUS_FEATURE_CPU_JANKINFO) + struct task_record record[OPLUS_NR_CPUS]; /* 2*u64 */ +#endif + +#ifdef OPLUS_FEATURE_HEALTHINFO +#ifdef CONFIG_OPLUS_JANK_INFO + int jank_trace; + struct jank_monitor_info jank_info; + unsigned in_mutex:1; + unsigned in_downread:1; + unsigned in_downwrite:1; + unsigned in_futex:1; + unsigned in_binder:1; + unsigned in_epoll:1; +#endif +#endif /* OPLUS_FEATURE_HEALTHINFO */ + +#ifdef CONFIG_OPLUS_FEATURE_TPP + int tpp_flag; +#endif /* CONFIG_OPLUS_FEATURE_TPP */ + +#ifdef CONFIG_OPLUS_FEATURE_IM + int im_flag; +#endif + +#ifdef CONFIG_OPLUS_FEATURE_TPD + int tpd; + int dtpd; /* dynamic tpd task */ + int dtpdg; /* dynamic tpd task group */ + int tpd_st; /* affinity decision from im */ +#endif +#ifdef CONFIG_OPLUS_FEATURE_INPUT_BOOST_V4 + struct frame_boost_group *fbg; + struct list_head fbg_list; + int fbg_depth; +#endif /* CONFIG_OPLUS_FEATURE_INPUT_BOOST_V4 */ +#if IS_ENABLED(CONFIG_OPLUS_FEATURE_FDLEAK_CHECK) + unsigned int fdleak_flag; #endif /* task is frozen/stopped (used by the cgroup freezer) */ + ANDROID_KABI_USE(1, unsigned frozen:1); /* 095444fad7e3 ("futex: Replace PF_EXITPIDONE with a state") */ @@ -1535,6 +1689,7 @@ struct task_struct { */ }; + static inline struct pid *task_pid(struct task_struct *task) { return task->thread_pid; @@ -1720,6 +1875,11 @@ extern struct pid *cad_pid; #define PF_MUTEX_TESTER 0x20000000 /* Thread belongs to the rt mutex tester */ #define PF_FREEZER_SKIP 0x40000000 /* Freezer should not count it as freezable */ #define PF_SUSPEND_TASK 0x80000000 /* This thread called freeze_processes() and should not be frozen */ +#if defined(OPLUS_FEATURE_PROCESS_RECLAIM) && defined(CONFIG_PROCESS_RECLAIM_ENHANCE) +#define PF_RECLAIM_SHRINK 0x02000000 /* Flag the task is memory compresser */ + +#define current_is_reclaimer() (current->flags & PF_RECLAIM_SHRINK) +#endif /* * Only the _current_ task can read/write to tsk->flags, but other @@ -1933,11 +2093,26 @@ extern void kick_process(struct task_struct *tsk); static inline void kick_process(struct task_struct *tsk) { } #endif -extern void __set_task_comm(struct task_struct *tsk, const char *from, bool exec); +#ifdef CONFIG_OPLUS_ION_BOOSTPOOL +extern pid_t alloc_svc_tgid; +#endif /* CONFIG_OPLUS_ION_BOOSTPOOL */ +extern void __set_task_comm(struct task_struct *tsk, const char *from, bool exec); +#if defined(OPLUS_FEATURE_TASK_CPUSTATS) && defined(CONFIG_OPLUS_SCHED) +extern void get_target_thread_pid(struct task_struct *p); +#endif /* defined(OPLUS_FEATURE_TASK_CPUSTATS) && defined(CONFIG_OPLUS_SCHED) */ static inline void set_task_comm(struct task_struct *tsk, const char *from) { __set_task_comm(tsk, from, false); + +#if defined(OPLUS_FEATURE_TASK_CPUSTATS) && defined(CONFIG_OPLUS_SCHED) + get_target_thread_pid(tsk); +#endif /* defined(OPLUS_FEATURE_TASK_CPUSTATS) && defined(CONFIG_OPLUS_SCHED) */ + +#ifdef CONFIG_OPLUS_ION_BOOSTPOOL + if (!strncmp(from, "allocator-servi", TASK_COMM_LEN)) + alloc_svc_tgid = tsk->tgid; +#endif /* CONFIG_OPLUS_ION_BOOSTPOOL */ } extern char *__get_task_comm(char *to, size_t len, struct task_struct *tsk); @@ -1989,6 +2164,8 @@ static inline int test_and_clear_tsk_thread_flag(struct task_struct *tsk, int fl static inline int test_tsk_thread_flag(struct task_struct *tsk, int flag) { + + //printk(KERN_ERR "++++++++++test_tsk_thread_flag++++++%ld\n",tsk->thread_info.flags); return test_ti_thread_flag(task_thread_info(tsk), flag); } diff --git a/include/linux/sched/cpufreq.h b/include/linux/sched/cpufreq.h index 1e2aac5ce077..5edadf043702 100644 --- a/include/linux/sched/cpufreq.h +++ b/include/linux/sched/cpufreq.h @@ -16,6 +16,15 @@ #define SCHED_CPUFREQ_EARLY_DET (1U << 6) #define SCHED_CPUFREQ_CONTINUE (1U << 8) +#ifdef OPLUS_FEATURE_SCHED_ASSIST +#define SCHED_CPUFREQ_RESET (1U << 7) +#define SCHED_CPUFREQ_BOOST (1U << 9) +#endif /* OPLUS_FEATURE_SCHED_ASSIST */ + +#ifdef CONFIG_OPLUS_FEATURE_INPUT_BOOST_V4 +#define SCHED_INPUT_BOOST (1U << 10) +#endif /* CONFIG_OPLUS_FEATURE_INPUT_BOOST_V4 */ + #ifdef CONFIG_CPU_FREQ struct cpufreq_policy; diff --git a/include/linux/sched/sysctl.h b/include/linux/sched/sysctl.h index 023c4824af37..9d5c402af0cf 100644 --- a/include/linux/sched/sysctl.h +++ b/include/linux/sched/sysctl.h @@ -47,6 +47,9 @@ extern unsigned int sysctl_sched_walt_rotate_big_tasks; extern unsigned int sysctl_sched_min_task_util_for_boost; extern unsigned int sysctl_sched_min_task_util_for_colocation; extern unsigned int sysctl_sched_asym_cap_sibling_freq_match_pct; +#ifdef CONFIG_SCHED_WALT_COBUCK +extern unsigned int __weak sysctl_sched_asym_cap_sibling_freq_match_en; +#endif extern unsigned int sysctl_sched_coloc_downmigrate_ns; extern unsigned int sysctl_sched_task_unfilter_period; extern unsigned int sysctl_sched_busy_hyst_enable_cpus; @@ -168,5 +171,9 @@ extern int sched_energy_aware_handler(struct ctl_table *table, int write, void __user *buffer, size_t *lenp, loff_t *ppos); #endif +#ifdef OPLUS_FEATURE_SCHED_ASSIST +extern int sysctl_sched_assist_scene_handler(struct ctl_table *table, int write, + void __user *buffer, size_t *lenp, loff_t *ppos); +#endif /* OPLUS_FEATURE_SCHED_ASSIST */ #endif /* _LINUX_SCHED_SYSCTL_H */ diff --git a/include/linux/sched_assist b/include/linux/sched_assist new file mode 120000 index 000000000000..a8e92d53c21b --- /dev/null +++ b/include/linux/sched_assist @@ -0,0 +1 @@ +../../../../vendor/oplus/kernel/oplus_performance/sched_assist/ \ No newline at end of file diff --git a/include/linux/security.h b/include/linux/security.h index 8c32a2f7b3c6..3206fdfae184 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -1848,6 +1848,17 @@ static inline void free_secdata(void *secdata) { } #endif /* CONFIG_SECURITY */ +#ifdef CONFIG_OPLUS_SECURE_GUARD +#ifdef CONFIG_SECURITY +extern int get_current_security_context(char **context, u32 *context_len); +#else +static inline int get_current_security_context(char **context, u32 *context_len) +{ + return -EOPNOTSUPP; +} +#endif +#endif /* CONFIG_OPLUS_SECURE_GUARD */ + #ifdef CONFIG_PERF_EVENTS struct perf_event_attr; struct perf_event; diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 2bb6429816b4..3c47c142907b 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -41,6 +41,7 @@ #include #include + /* The interface for checksum offload between the stack and networking drivers * is as follows... * @@ -787,6 +788,7 @@ struct sk_buff { __u8 offload_fwd_mark:1; __u8 offload_mr_fwd_mark:1; #endif + #ifdef CONFIG_NET_CLS_ACT __u8 tc_skip_classify:1; __u8 tc_at_ingress:1; @@ -979,6 +981,7 @@ void skb_tx_error(struct sk_buff *skb); void consume_skb(struct sk_buff *skb); void __consume_stateless_skb(struct sk_buff *skb); void __kfree_skb(struct sk_buff *skb); + extern struct kmem_cache *skbuff_head_cache; void kfree_skb_partial(struct sk_buff *skb, bool head_stolen); @@ -3949,10 +3952,12 @@ static inline void __nf_copy(struct sk_buff *dst, const struct sk_buff *src, dst->_nfct = src->_nfct; nf_conntrack_get(skb_nfct(src)); #endif + #if IS_ENABLED(CONFIG_BRIDGE_NETFILTER) dst->nf_bridge = src->nf_bridge; nf_bridge_get(src->nf_bridge); #endif + #if IS_ENABLED(CONFIG_NETFILTER_XT_TARGET_TRACE) || defined(CONFIG_NF_TABLES) if (copy) dst->nf_trace = src->nf_trace; diff --git a/include/linux/slab.h b/include/linux/slab.h index 1409faeaf199..6845f4fdc13f 100644 --- a/include/linux/slab.h +++ b/include/linux/slab.h @@ -311,6 +311,13 @@ enum kmalloc_cache_type { }; #ifndef CONFIG_SLOB +#if defined(OPLUS_FEATURE_MEMLEAK_DETECT) && defined(CONFIG_KMALLOC_DEBUG) +/* record the kmalloc cache with debug + * flag, such as SLAB_STORE_USER + */ +extern atomic64_t kmalloc_debug_caches[NR_KMALLOC_TYPES][KMALLOC_SHIFT_HIGH + 1]; +extern int kmalloc_debug_enable; +#endif extern struct kmem_cache * kmalloc_caches[NR_KMALLOC_TYPES][KMALLOC_SHIFT_HIGH + 1]; @@ -544,6 +551,17 @@ static __always_inline void *kmalloc(size_t size, gfp_t flags) if (!index) return ZERO_SIZE_PTR; +#if defined(OPLUS_FEATURE_MEMLEAK_DETECT) && defined(CONFIG_KMALLOC_DEBUG) + /* try to kmalloc from kmalloc_debug + * caches fisrt. + */ + if (unlikely(kmalloc_debug_enable)) { + struct kmem_cache *s; + s = (struct kmem_cache *)atomic64_read(&kmalloc_debug_caches[kmalloc_type(flags)][index]); + if (s) + return kmem_cache_alloc_trace(s, flags, size); + } +#endif return kmem_cache_alloc_trace( kmalloc_caches[kmalloc_type(flags)][index], diff --git a/include/linux/soc/qcom/smem.h b/include/linux/soc/qcom/smem.h index 86e1b358688a..886ebac41068 100644 --- a/include/linux/soc/qcom/smem.h +++ b/include/linux/soc/qcom/smem.h @@ -11,4 +11,15 @@ int qcom_smem_get_free_space(unsigned host); phys_addr_t qcom_smem_virt_to_phys(void *p); +#ifdef OPLUS_FEATURE_AGINGTEST +#define DUMP_REASON_SIZE 256 + +struct dump_info{ + char dump_reason[DUMP_REASON_SIZE]; //dump reason +}; + +char *parse_function_builtin_return_address(unsigned long function_address); +void save_dump_reason_to_smem(char *reason, char *function_name); +#endif /*OPLUS_FEATURE_AGINGTEST*/ + #endif diff --git a/include/linux/special_opt b/include/linux/special_opt new file mode 120000 index 000000000000..3f9848e5e82c --- /dev/null +++ b/include/linux/special_opt @@ -0,0 +1 @@ +../../../../vendor/oplus/kernel/oplus_performance/special_opt \ No newline at end of file diff --git a/include/linux/swap.h b/include/linux/swap.h index 83302aa822f7..5a8e922061cc 100644 --- a/include/linux/swap.h +++ b/include/linux/swap.h @@ -14,6 +14,11 @@ #include #include +#if defined(CONFIG_NANDSWAP) +#include <../drivers/soc/oplus/oplus_nandswap/nandswap.h> +#define SWAP_NANDSWAP_PRIO 2020 /* just a magic number */ +#endif + struct notifier_block; struct bio; @@ -128,6 +133,10 @@ union swap_header { */ struct reclaim_state { unsigned long reclaimed_slab; +#ifdef CONFIG_LRU_GEN + /* per-thread mm walk data */ + struct lru_gen_mm_walk *mm_walk; +#endif }; #ifdef __KERNEL__ @@ -173,7 +182,12 @@ enum { SWP_STABLE_WRITES = (1 << 10), /* no overwrite PG_writeback pages */ SWP_SYNCHRONOUS_IO = (1 << 11), /* synchronous IO is efficient */ /* add others here before... */ +#if defined(CONFIG_NANDSWAP) + SWP_NANDSWAP = (1 << 12), /* mark the device used for nandswap */ + SWP_SCANNING = (1 << 13), /* refcount in scan_swap_map */ +#else SWP_SCANNING = (1 << 12), /* refcount in scan_swap_map */ +#endif }; #define SWAP_CLUSTER_MAX 32UL @@ -377,6 +391,12 @@ extern int sysctl_swap_ratio; extern int sysctl_swap_ratio_enable; extern int remove_mapping(struct address_space *mapping, struct page *page); extern unsigned long vm_total_pages; +#ifdef CONFIG_DYNAMIC_TUNNING_SWAPPINESS +extern int vm_swappiness_threshold1; +extern int vm_swappiness_threshold2; +extern int swappiness_threshold1_size; +extern int swappiness_threshold2_size; +#endif #ifdef CONFIG_NUMA extern int node_reclaim_mode; @@ -421,9 +441,12 @@ extern unsigned long total_swapcache_pages(void); extern void show_swap_cache_info(void); extern int add_to_swap(struct page *page); extern int add_to_swap_cache(struct page *, swp_entry_t, gfp_t); -extern int __add_to_swap_cache(struct page *page, swp_entry_t entry); -extern void __delete_from_swap_cache(struct page *); +extern int __add_to_swap_cache(struct page *page, swp_entry_t entry, + void **shadowp); +extern void __delete_from_swap_cache(struct page *page, void *shadow); extern void delete_from_swap_cache(struct page *); +extern void clear_shadow_from_swap_cache(int type, unsigned long begin, + unsigned long end); extern void free_page_and_swap_cache(struct page *); extern void free_pages_and_swap_cache(struct page **, int); extern struct page *lookup_swap_cache(swp_entry_t entry, @@ -445,15 +468,38 @@ extern atomic_long_t nr_swap_pages; extern long total_swap_pages; extern atomic_t nr_rotate_swap; extern bool has_usable_swap(void); +#ifdef CONFIG_ZRAM +extern unsigned long znr_swap_pages; +extern bool is_enable_zlimit; +#endif + +#if defined(CONFIG_NANDSWAP) +extern struct swap_info_struct *nandswap_si; +#endif /* Swap 50% full? Release swapcache more aggressively.. */ static inline bool vm_swap_full(void) { +#if defined(CONFIG_NANDSWAP) + if (nandswap_si) + return (atomic_long_read(&nr_swap_pages) - + (nandswap_si->pages - nandswap_si->inuse_pages)) * 2 + < (total_swap_pages - nandswap_si->pages); +#endif return atomic_long_read(&nr_swap_pages) * 2 < total_swap_pages; } static inline long get_nr_swap_pages(void) { +#ifdef CONFIG_ZRAM + if (is_enable_zlimit) + return znr_swap_pages; +#endif +#if defined(CONFIG_NANDSWAP) + if (nandswap_si) + return atomic_long_read(&nr_swap_pages) - + (nandswap_si->pages - nandswap_si->inuse_pages); +#endif return atomic_long_read(&nr_swap_pages); } @@ -576,7 +622,7 @@ static inline int add_to_swap_cache(struct page *page, swp_entry_t entry, return -1; } -static inline void __delete_from_swap_cache(struct page *page) +static inline void __delete_from_swap_cache(struct page *page, void *shadow) { } @@ -584,6 +630,11 @@ static inline void delete_from_swap_cache(struct page *page) { } +static inline void clear_shadow_from_swap_cache(int type, unsigned long begin, + unsigned long end) +{ +} + static inline int page_swapcount(struct page *page) { return 0; diff --git a/include/linux/task_cpustats.h b/include/linux/task_cpustats.h new file mode 120000 index 000000000000..7ab746ed89c8 --- /dev/null +++ b/include/linux/task_cpustats.h @@ -0,0 +1 @@ +../../../../vendor/oplus/kernel/oplus_performance/task_cpustats/task_cpustats.h \ No newline at end of file diff --git a/include/linux/task_io_accounting_ops.h b/include/linux/task_io_accounting_ops.h index 733ab62ae141..4f52ae4329bf 100644 --- a/include/linux/task_io_accounting_ops.h +++ b/include/linux/task_io_accounting_ops.h @@ -6,11 +6,17 @@ #define __TASK_IO_ACCOUNTING_OPS_INCLUDED #include +#if defined(OPLUS_FEATURE_IOMONITOR) && defined(CONFIG_IOMONITOR) +#include +#endif /*OPLUS_FEATURE_IOMONITOR*/ #ifdef CONFIG_TASK_IO_ACCOUNTING static inline void task_io_account_read(size_t bytes) { current->ioac.read_bytes += bytes; +#if defined(OPLUS_FEATURE_IOMONITOR) && defined(CONFIG_IOMONITOR) + iomonitor_record_task_io(current, bytes, false); +#endif /*OPLUS_FEATURE_IOMONITOR*/ } /* @@ -25,6 +31,10 @@ static inline unsigned long task_io_get_inblock(const struct task_struct *p) static inline void task_io_account_write(size_t bytes) { current->ioac.write_bytes += bytes; +#if defined(OPLUS_FEATURE_IOMONITOR) && defined(CONFIG_IOMONITOR) + iomonitor_record_task_io(current, bytes, true); +#endif /*OPLUS_FEATURE_IOMONITOR*/ + } /* diff --git a/include/linux/task_sched_info.h b/include/linux/task_sched_info.h new file mode 120000 index 000000000000..78625ffc02d2 --- /dev/null +++ b/include/linux/task_sched_info.h @@ -0,0 +1 @@ +../../../../vendor/oplus/kernel/oplus_performance/task_cpustats/task_sched_info.h \ No newline at end of file diff --git a/include/linux/thermal.h b/include/linux/thermal.h index 61ed7429dfc4..83f3e0ab575b 100644 --- a/include/linux/thermal.h +++ b/include/linux/thermal.h @@ -531,6 +531,9 @@ void thermal_cooling_device_unregister(struct thermal_cooling_device *); struct thermal_zone_device *thermal_zone_get_zone_by_name(const char *name); struct thermal_cooling_device *thermal_zone_get_cdev_by_name(const char *name); int thermal_zone_get_temp(struct thermal_zone_device *tz, int *temp); +#ifdef OPLUS_BUG_STABILITY +int thermal_zone_get_temp_workaround(struct thermal_zone_device *tz, int *temp); +#endif int thermal_zone_get_slope(struct thermal_zone_device *tz); int thermal_zone_get_offset(struct thermal_zone_device *tz); @@ -600,6 +603,11 @@ static inline struct thermal_cooling_device *thermal_zone_get_cdev_by_name( static inline int thermal_zone_get_temp( struct thermal_zone_device *tz, int *temp) { return -ENODEV; } +#ifdef OPLUS_BUG_STABILITY +static inline int thermal_zone_get_temp_workaround( + struct thermal_zone_device *tz, int *temp) +{ return -ENODEV; } +#endif static inline int thermal_zone_get_slope( struct thermal_zone_device *tz) { return -ENODEV; } diff --git a/include/linux/tpd b/include/linux/tpd new file mode 120000 index 000000000000..ca17993e6cb9 --- /dev/null +++ b/include/linux/tpd @@ -0,0 +1 @@ +../../../../vendor/oplus/kernel/oplus_performance/tpd \ No newline at end of file diff --git a/include/linux/tpp b/include/linux/tpp new file mode 120000 index 000000000000..89062302e711 --- /dev/null +++ b/include/linux/tpp @@ -0,0 +1 @@ +../../../../vendor/oplus/kernel/oplus_performance/tpp \ No newline at end of file diff --git a/include/linux/tuning b/include/linux/tuning new file mode 120000 index 000000000000..8981232eac66 --- /dev/null +++ b/include/linux/tuning @@ -0,0 +1 @@ +../../../../vendor/oplus/kernel/oplus_performance/inputboost_v4 \ No newline at end of file diff --git a/include/linux/ufstw.h b/include/linux/ufstw.h new file mode 100644 index 000000000000..c0248727fb68 --- /dev/null +++ b/include/linux/ufstw.h @@ -0,0 +1,8 @@ +#ifndef _UFSTW_FS_H_ +#define _UFSTW_FS_H_ + +#if defined(CONFIG_UFSTW) +extern void bdev_set_turbo_write(struct block_device *bdev); +extern void bdev_clear_turbo_write(struct block_device *bdev); +#endif +#endif diff --git a/include/linux/vm_anti_fragment.h b/include/linux/vm_anti_fragment.h new file mode 120000 index 000000000000..02b6192da3e2 --- /dev/null +++ b/include/linux/vm_anti_fragment.h @@ -0,0 +1 @@ +../../../../vendor/oplus/kernel/oplus_performance/vm_anti_fragment/vm_anti_fragment.h \ No newline at end of file diff --git a/include/linux/vmalloc.h b/include/linux/vmalloc.h index bf452b946c09..40fed6e6a8c3 100644 --- a/include/linux/vmalloc.h +++ b/include/linux/vmalloc.h @@ -42,6 +42,10 @@ struct vm_struct { unsigned int nr_pages; phys_addr_t phys_addr; const void *caller; +#if defined(OPLUS_FEATURE_MEMLEAK_DETECT) && defined(CONFIG_VMALLOC_DEBUG) + /* record the stack hash. */ + unsigned int hash; +#endif }; struct vmap_area { diff --git a/include/linux/vmstat.h b/include/linux/vmstat.h index f25cef84b41d..f71e349b346f 100644 --- a/include/linux/vmstat.h +++ b/include/linux/vmstat.h @@ -382,6 +382,13 @@ static inline void __mod_zone_freepage_state(struct zone *zone, int nr_pages, __mod_zone_page_state(zone, NR_FREE_PAGES, nr_pages); if (is_migrate_cma(migratetype)) __mod_zone_page_state(zone, NR_FREE_CMA_PAGES, nr_pages); +#if defined(OPLUS_FEATURE_MEMORY_ISOLATE) && defined(CONFIG_OPLUS_MEMORY_ISOLATE) +/* + * Account free pages for MIGRATE_OPLUS + */ + if (migratetype == MIGRATE_OPLUS2) + __mod_zone_page_state(zone, NR_FREE_OPLUS2_PAGES, nr_pages); +#endif /* OPLUS_FEATURE_MEMORY_ISOLATE */ } extern const char * const vmstat_text[]; diff --git a/include/linux/wait.h b/include/linux/wait.h index 5e933ff7afba..32ba6c3101ad 100644 --- a/include/linux/wait.h +++ b/include/linux/wait.h @@ -200,6 +200,7 @@ void __wake_up_pollfree(struct wait_queue_head *wq_head); #define wake_up_locked(x) __wake_up_locked((x), TASK_NORMAL, 1) #define wake_up_all_locked(x) __wake_up_locked((x), TASK_NORMAL, 0) + #define wake_up_interruptible(x) __wake_up(x, TASK_INTERRUPTIBLE, 1, NULL) #define wake_up_interruptible_nr(x, nr) __wake_up(x, TASK_INTERRUPTIBLE, nr, NULL) #define wake_up_interruptible_all(x) __wake_up(x, TASK_INTERRUPTIBLE, 0, NULL) diff --git a/include/linux/workqueue.h b/include/linux/workqueue.h index 342f37479228..b2e3a8f5a54f 100644 --- a/include/linux/workqueue.h +++ b/include/linux/workqueue.h @@ -19,6 +19,7 @@ struct workqueue_struct; struct work_struct; + typedef void (*work_func_t)(struct work_struct *work); void delayed_work_timer_fn(struct timer_list *t); @@ -107,6 +108,11 @@ struct work_struct { #ifdef CONFIG_LOCKDEP struct lockdep_map lockdep_map; #endif + +#ifdef OPLUS_FEATURE_SCHED_ASSIST + int ux_work; +#endif + ANDROID_KABI_RESERVE(1); ANDROID_KABI_RESERVE(2); }; @@ -146,6 +152,9 @@ struct workqueue_attrs { */ int nice; +#ifdef OPLUS_FEATURE_SCHED_ASSIST + int ux_state; +#endif /** * @cpumask: allowed CPUs */ @@ -218,7 +227,8 @@ static inline unsigned int work_static(struct work_struct *work) return *work_data_bits(work) & WORK_STRUCT_STATIC; } #else -static inline void __init_work(struct work_struct *work, int onstack) { } +static inline void __init_work(struct work_struct *work, int onstack) { +} static inline void destroy_work_on_stack(struct work_struct *work) { } static inline void destroy_delayed_work_on_stack(struct delayed_work *work) { } static inline unsigned int work_static(struct work_struct *work) { return 0; } @@ -345,7 +355,9 @@ enum { * http://thread.gmane.org/gmane.linux.kernel/1480396 */ WQ_POWER_EFFICIENT = 1 << 7, - +#ifdef OPLUS_FEATURE_SCHED_ASSIST + WQ_UX = 1 << 15, +#endif __WQ_DRAINING = 1 << 16, /* internal: workqueue is draining */ __WQ_ORDERED = 1 << 17, /* internal: workqueue is ordered */ __WQ_LEGACY = 1 << 18, /* internal: create*_workqueue() */ @@ -390,6 +402,9 @@ enum { */ extern struct workqueue_struct *system_wq; extern struct workqueue_struct *system_highpri_wq; +#ifdef OPLUS_FEATURE_SCHED_ASSIST +extern struct workqueue_struct *system_ux_wq; +#endif extern struct workqueue_struct *system_long_wq; extern struct workqueue_struct *system_unbound_wq; extern struct workqueue_struct *system_freezable_wq; @@ -501,7 +516,11 @@ extern __printf(1, 2) void set_worker_desc(const char *fmt, ...); extern void print_worker_info(const char *log_lvl, struct task_struct *task); extern void show_workqueue_state(void); extern void wq_worker_comm(char *buf, size_t size, struct task_struct *task); - +#ifdef CONFIG_OPLUS_FEATURE_MIDAS +extern void get_worker_info(struct task_struct *task, char *buf); +#else +static inline void get_worker_info(struct task_struct *task, char *buf) { } +#endif /** * queue_work - queue work on a workqueue * @wq: workqueue to use diff --git a/include/linux/zram b/include/linux/zram new file mode 120000 index 000000000000..50691ab1d043 --- /dev/null +++ b/include/linux/zram @@ -0,0 +1 @@ +../../drivers/block/zram \ No newline at end of file diff --git a/include/net/netfilter/nf_conntrack.h b/include/net/netfilter/nf_conntrack.h index ac4d70aeee12..ea6e9f0a5afa 100644 --- a/include/net/netfilter/nf_conntrack.h +++ b/include/net/netfilter/nf_conntrack.h @@ -27,6 +27,7 @@ #include +#define OPLUS_FEATURE_WIFI_LUCKYMONEY /* per conntrack: protocol private data */ union nf_conntrack_proto { /* insert conntrack proto private data here */ @@ -87,6 +88,10 @@ struct nf_conn { /* all members below initialized via memset */ struct { } __nfct_init_offset; + #ifdef OPLUS_FEATURE_WIFI_LUCKYMONEY + u32 oplus_app_uid; + #endif /* OPLUS_FEATURE_WIFI_LUCKYMONEY */ + /* If we were expected by an expectation, this will be it */ struct nf_conn *master; diff --git a/include/net/netns/ipv4.h b/include/net/netns/ipv4.h index 366e2a60010e..ef85340edd1b 100644 --- a/include/net/netns/ipv4.h +++ b/include/net/netns/ipv4.h @@ -178,6 +178,10 @@ struct netns_ipv4 { int sysctl_udp_wmem_min; int sysctl_udp_rmem_min; + #ifdef OPLUS_BUG_STABILITY + int sysctl_tcp_random_timestamp; + #endif /* OPLUS_BUG_STABILITY */ + #ifdef CONFIG_NET_L3_MASTER_DEV int sysctl_udp_l3mdev_accept; #endif diff --git a/include/net/oplus/oplus_apps_monitor.h b/include/net/oplus/oplus_apps_monitor.h new file mode 100644 index 000000000000..2a27546c84a5 --- /dev/null +++ b/include/net/oplus/oplus_apps_monitor.h @@ -0,0 +1,41 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* +* Copyright (C) 2018-2020 Oplus. All rights reserved. +*/ + +#ifndef _OPLUS_APPS_MONITOR_H +#define _OPLUS_APPS_MONITOR_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +void statistics_monitor_apps_rtt_via_uid(int if_index, int rtt, struct sock *sk); + +#endif /* _OPLUS_APPS_MONITOR_H */ + diff --git a/include/net/oplus/oplus_apps_power_monitor.h b/include/net/oplus/oplus_apps_power_monitor.h new file mode 100644 index 000000000000..505cc1202394 --- /dev/null +++ b/include/net/oplus/oplus_apps_power_monitor.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* +* Copyright (C) 2018-2020 Oplus. All rights reserved. +*/ + +#ifndef _OPLUS_APPS_POWER_MONITOR_H +#define _OPLUS_APPS_POWER_MONITOR_H + +#include +#include +#include + +int app_monitor_dl_ctl_msg_handle(struct nlmsghdr *nlh); +int app_monitor_dl_report_msg_handle(struct nlmsghdr *nlh); +void oplus_app_power_monitor_init(void); +void oplus_app_power_monitor_fini(void); + +#endif /* _OPLUS_APPS_POWER_MONITOR_H */ diff --git a/include/net/oplus/oplus_kernel2user.h b/include/net/oplus/oplus_kernel2user.h new file mode 100644 index 000000000000..dfb8b0392e79 --- /dev/null +++ b/include/net/oplus/oplus_kernel2user.h @@ -0,0 +1,32 @@ +#ifndef _OPLUS_KERNEL2USER_H +#define _OPLUS_KERNEL2USER_H + +#include + +/*NLMSG_MIN_TYPE is 0x10,so user to kernel we start at 0x20,kernel to user we start at 0x30*/ +enum{ + OPLUS_FOREGROUND_ANDROID_UID = 0x20, + OPLUS_MPTCP_UID = 0x21, + OPLUS_SEND_TCP_RETRANSMIT = 0x30, + OPLUS_SEND_NETWORK_SCORE = 0x31, +}; + +#define MAX_PARA_LEN 100 +#define MAX_MPTCP_APP_LEN 100 +#define MAX_LINK_LEN 32 + +struct general_oplus_info { + u32 para_type; + u32 para_one; + u32 para_two; + u32 para_three; + char para_array[MAX_PARA_LEN]; +}; + +extern u32 oplus_foreground_uid; +extern int oplus_kernel_send_to_user(int msg_type, char *payload, int payload_len); +extern void oplus_handle_retransmit(const struct sock *sk, int type); +extern uid_t get_uid_from_sock(const struct sock *sk); +extern int get_link_index_from_sock(const struct sock *sk); + +#endif diff --git a/include/net/oplus/oplus_router_boost.h b/include/net/oplus/oplus_router_boost.h new file mode 100644 index 000000000000..70d819e8831a --- /dev/null +++ b/include/net/oplus/oplus_router_boost.h @@ -0,0 +1,59 @@ +/************************************************************************************ +** File: - oplus_router_boost.c +** VENDOR_EDIT +** Copyright (C), 2008-2020, OPLUS Mobile Comm Corp., Ltd +** +** Description: +** 1. Add for oplus router boost +** +** Version: 1.0 +** Date : 2020-05-09 +** TAG : OPLUS_FEATURE_WIFI_ROUTERBOOST +** +** ---------------------Revision History: --------------------- +** +** --------------------------------------------------------------- +** +************************************************************************************/ + +#ifndef _OPLUS_ROUTER_BOOST_H +#define _OPLUS_ROUTER_BOOST_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern int (*oplus_router_boost_handler)(struct sock *sk, struct sk_buff *skb); + +void oplus_router_boost_set_enable(struct nlmsghdr *nlh); +void oplus_router_boost_set_app_uid(struct nlmsghdr *nlh); +int oplus_router_boost_get_enable(void); +int oplus_router_boost_get_app_uid(void); +void oplus_router_boost_set_params(struct nlmsghdr * nlh); + +#endif /* _OPLUS_ROUTER_BOOST_H */ diff --git a/include/net/oplus/oplus_wfd_wlan.h b/include/net/oplus/oplus_wfd_wlan.h new file mode 100644 index 000000000000..362fc0f2d3a3 --- /dev/null +++ b/include/net/oplus/oplus_wfd_wlan.h @@ -0,0 +1,15 @@ +#ifndef _OPLUS_WFD_WLAN_H +#define _OPLUS_WFD_WLAN_H + +#include + +struct oplus_wfd_wlan_ops_t { + void (*remove_he_ie_from_probe_request)(int remove); + int (*get_dbs_capacity)(void); + int (*get_phy_capacity)(int band); + void (*get_supported_channels)(int band, int* len, int* freqs, int max_num); + void (*get_avoid_channels)(int* len, int* freqs, int max_num); +}; + +extern void register_oplus_wfd_wlan_ops(struct oplus_wfd_wlan_ops_t *ops); +#endif diff --git a/include/net/oplus_nwpower.h b/include/net/oplus_nwpower.h new file mode 100644 index 000000000000..125658e1556f --- /dev/null +++ b/include/net/oplus_nwpower.h @@ -0,0 +1,57 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2018-2020 Oplus. All rights reserved. + */ + +/**************************************************************** +** ------------------ Revision History:------------------------ +** +** Asiga 2019/07/31 1.0 build this module +****************************************************************/ +#ifndef __OPLUS_NWPOWER_H_ +#define __OPLUS_NWPOWER_H_ + +#include +#include + +#define OPLUS_TCP_TYPE_V4 1 +#define OPLUS_TCP_TYPE_V6 2 +#define OPLUS_NET_OUTPUT 0 +#define OPLUS_NET_INPUT 1 + +#define OPLUS_NW_WAKEUP_SUM 8 +#define OPLUS_NW_MPSS 0 +#define OPLUS_NW_QRTR 1 +#define OPLUS_NW_MD 2 +#define OPLUS_NW_WIFI 3 +#define OPLUS_NW_TCP_IN 4 +#define OPLUS_NW_TCP_OUT 5 +#define OPLUS_NW_TCP_RE_IN 6 +#define OPLUS_NW_TCP_RE_OUT 7 + +//Add for Mpss wakeup +extern void oplus_match_modem_wakeup(void); +extern void oplus_match_wlan_wakeup(void); + +//Add for QMI wakeup +extern void oplus_match_qrtr_service_port(int type, int id, int port); +extern void oplus_match_qrtr_wakeup(int src_node, int src_port, int dst_port, unsigned int arg1, unsigned int arg2); +extern void oplus_update_qrtr_flag(int val); + +//Add for IPA wakeup(tcp input) +extern void oplus_match_ipa_ip_wakeup(int type, struct sk_buff *skb); +extern void oplus_match_ipa_tcp_wakeup(int type, struct sock *sk); +extern void oplus_ipa_schedule_work(void); + +//Add for tcp output +extern void oplus_match_tcp_output(struct sock *sk); + +//Add for tcp retrans +extern void oplus_match_tcp_input_retrans(struct sock *sk); +extern void oplus_match_tcp_output_retrans(struct sock *sk); + +//#ifdef OPLUS_FEATURE_NWPOWER_NETCONTROLLER +extern bool oplus_check_socket_in_blacklist(int is_input, struct socket *sock); +//#endif /* OPLUS_FEATURE_NWPOWER_NETCONTROLLER */ + +#endif /* __OPLUS_NWPOWER_H_ */ \ No newline at end of file diff --git a/include/net/sock.h b/include/net/sock.h index 3847fe792e69..a3de4f3be7bf 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -188,6 +188,17 @@ struct sock_common { struct proto *skc_prot; possible_net_t skc_net; + //#ifdef VENDOR_EDIT + char skc_cmdline[TASK_COMM_LEN]; + //#enidf /* VENDOR_EDIT */ + + //#ifdef OPLUS_FEATURE_NWPOWER + u32 skc_oplus_pid; + u64 skc_oplus_last_rcv_stamp[2];//index 0 = last, index 1 = now + u64 skc_oplus_last_send_stamp[2];//index 0 = last, index 1 = now + //#endif /* OPLUS_FEATURE_NWPOWER */ + + #if IS_ENABLED(CONFIG_IPV6) struct in6_addr skc_v6_daddr; struct in6_addr skc_v6_rcv_saddr; @@ -365,6 +376,17 @@ struct sock { #define sk_flags __sk_common.skc_flags #define sk_rxhash __sk_common.skc_rxhash +//#ifdef VENDOR_EDIT +#define sk_cmdline __sk_common.skc_cmdline +//#enidf /* VENDOR_EDIT */ + +//#ifdef OPLUS_FEATURE_NWPOWER +#define sk_oplus_pid __sk_common.skc_oplus_pid +#define oplus_last_rcv_stamp __sk_common.skc_oplus_last_rcv_stamp +#define oplus_last_send_stamp __sk_common.skc_oplus_last_send_stamp +//#endif /* OPLUS_FEATURE_NWPOWER */ + + socket_lock_t sk_lock; atomic_t sk_drops; int sk_rcvlowat; @@ -1947,6 +1969,11 @@ static inline void sk_dst_confirm(struct sock *sk) static inline void sock_confirm_neigh(struct sk_buff *skb, struct neighbour *n) { + #ifdef OPLUS_BUG_STABILITY + //Remove for [1357567],some AP doesn't send arp when it needs to send data to DUT + //We remove this code to send arp more frequently to notify our mac to AP + return; + #endif /* OPLUS_BUG_STABILITY */ if (skb_get_dst_pending_confirm(skb)) { struct sock *sk = skb->sk; unsigned long now = jiffies; diff --git a/include/net/tcp.h b/include/net/tcp.h index c228edf3ea21..2211a25af406 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -262,6 +262,10 @@ extern int sysctl_tcp_use_userconfig; extern struct percpu_counter tcp_sockets_allocated; extern unsigned long tcp_memory_pressure; +#ifdef OPLUS_BUG_STABILITY +extern int sysctl_tcp_ts_control[2]; +#endif /* OPLUS_BUG_STABILITY */ + /* optimized version of sk_under_memory_pressure() for TCP sockets */ static inline bool tcp_under_memory_pressure(const struct sock *sk) { diff --git a/include/soc/oplus/boot_mode.h b/include/soc/oplus/boot_mode.h new file mode 100644 index 000000000000..e95f9643cd06 --- /dev/null +++ b/include/soc/oplus/boot_mode.h @@ -0,0 +1,40 @@ +/************************************************************************************ +** Copyright (C), 2008-2012, Oplus ., All rights reserved. +** +** Description: +** change define of boot_mode here for other place to use it +** Version: 1.0 +************************************************************************************/ +#ifndef _OPLUS_BOOT_H +#define _OPLUS_BOOT_H +enum{ + MSM_BOOT_MODE__NORMAL, + MSM_BOOT_MODE__FASTBOOT, + MSM_BOOT_MODE__RECOVERY, + MSM_BOOT_MODE__FACTORY, + MSM_BOOT_MODE__RF, + MSM_BOOT_MODE__WLAN, + MSM_BOOT_MODE__MOS, + MSM_BOOT_MODE__CHARGE, + MSM_BOOT_MODE__SILENCE, + MSM_BOOT_MODE__SAU, + //Add for factory agingtest + MSM_BOOT_MODE__AGING = 998, + MSM_BOOT_MODE__SAFE = 999, +}; + +extern int get_boot_mode(void); +#ifdef OPLUS_BUG_STABILITY +/*add for charge*/ +extern bool qpnp_is_power_off_charging(void); +#endif +#ifdef OPLUS_BUG_STABILITY +extern bool qpnp_is_charger_reboot(void); +#endif /*OPLUS_BUG_STABILITY*/ +#endif /*_OPLUS_BOOT_H*/ + +/* Add for kernel monitor whole bootup*/ +#ifdef PHOENIX_PROJECT +extern bool op_is_monitorable_boot(void); +#endif + diff --git a/include/soc/oplus/device_info.h b/include/soc/oplus/device_info.h new file mode 100644 index 000000000000..3790ff5f5a5a --- /dev/null +++ b/include/soc/oplus/device_info.h @@ -0,0 +1,57 @@ +/** + * Copyright 2008-2013 OPLUS Mobile Comm Corp., Ltd, All rights reserved. + * FileName:devinfo.h + * ModuleName:devinfo + * Create Date: 2013-10-23 + * Description:add interface to get device information. +*/ + +#ifndef _DEVICE_INFO_H +#define _DEVICE_INFO_H + +#include + +#define INFO_LEN 24 + +typedef enum +{ + DDR_TYPE_LPDDR1 = 0, /**< Low power DDR1. */ + DDR_TYPE_LPDDR2 = 2, /**< Low power DDR2 set to 2 for compatibility*/ + DDR_TYPE_PCDDR2 = 3, /**< Personal computer DDR2. */ + DDR_TYPE_PCDDR3 = 4, /**< Personal computer DDR3. */ + + DDR_TYPE_LPDDR3 = 5, /**< Low power DDR3. */ + DDR_TYPE_LPDDR4 = 6, /**< Low power DDR4. */ + DDR_TYPE_LPDDR4X = 7, /**< Low power DDR4x. */ + + DDR_TYPE_LPDDR5 = 8, /**< Low power DDR5. */ + DDR_TYPE_LPDDR5X = 9, /**< Low power DDR5x. */ + DDR_TYPE_UNUSED = 0x7FFFFFFF /**< For compatibility with deviceprogrammer(features not using DDR). */ +} DDR_TYPE; + +struct manufacture_info { + char name[INFO_LEN]; + char *version; + char *manufacture; + char *fw_path; +}; + +struct o_hw_id { + const char *label; + const char *match; + int id; + struct list_head list; +}; + +struct o_ufsplus_status { + int *hpb_status; + int *tw_status; +}; + + +int register_device_proc(char *name, char *version, char *vendor); +int register_device_proc_for_ufsplus(char *name, int *hpb_status,int *tw_status); +int register_devinfo(char *name, struct manufacture_info *info); +bool check_id_match(const char *label, const char *id_match, int id); + +#endif diff --git a/include/soc/oplus/dft/olc.h b/include/soc/oplus/dft/olc.h new file mode 100644 index 000000000000..8bbeb28f5c23 --- /dev/null +++ b/include/soc/oplus/dft/olc.h @@ -0,0 +1,67 @@ +#ifndef _LIBOLC_H_ +#define _LIBOLC_H_ +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#define LOG_KERNEL (0x1) +#define LOG_SYSTEM (0x1 << 1) +#define LOG_MAIN (0x1 << 2) +#define LOG_EVENTS (0x1 << 3) +#define LOG_RADIO (0x1 << 4) +#define LOG_ANDROID (0x1 << 5) +#define LOG_THEIA (0x1 << 6) +#define LOG_ADSP (0x1 << 7) +#define LOG_OBRAIN (0x1 << 8) +#define LOG_AUDIO (0x1 << 9) +#define LOG_BTHCI (0x1 << 10) +#define LOG_SYSTRACE (0x1 << 11) +#define LOG_HPROF (0x1 << 12) +#define LOG_QUALITYPROTECT (0x1 << 13) +#define LOG_OTRTA (0x1 << 14) +#define LOG_BATTERYSTATS (0x1 << 15) +#define LOG_NWATCHCALL (0x1 << 16) +#define LOG_VIDEO (0x1 << 17) +#define LOG_WIFI (0x1 << 18) +#define LOG_TCPDUMP (0x1 << 19) +#define LOG_MODEM (0x1 << 20) +#define LOG_WIFIMINIDUMP (0x1 << 21) +#define LOG_GPS (0x1 << 22) +#define LOG_SHUTDOWN_DETECT (0x1 << 23) +#define LOG_BTSSRDUMP (0x1 << 24) +#define LOG_BTSWITCH (0X1 << 25) +#define LOG_PHOENIX (0x1 << 26) +#define LOG_QCOM_MINIDUMP (0x1 << 27) + +#define EXP_LEVEL_CRITICAL 1 +#define EXP_LEVEL_IMPORTANT 2 +#define EXP_LEVEL_GENERAL 3 +#define EXP_LEVEL_INFO 4 +#define EXP_LEVEL_DEBUG 5 + +enum exception_type { + EXCEPTION_KERNEL, + EXCEPTION_NATIVE, + EXCEPTION_FRAMEWROK, + EXCEPTION_APP, +}; + +struct exception_info { + uint64_t time; // Exception time, Unix timestamp in seconds + uint32_t exceptionId; // ExceptionID 0x100XXYYY, XX is module identification, YY is specific exception identification + uint32_t exceptionType; // (Not used yet)exception type. eg: Kernel, Native + uint32_t level; // (Not used yet)exception level, eg: IMPORTTANT, CIRTAL + uint64_t atomicLogs; // atomic log types combination. eg: LOG_KERNEL, LOG_KERNEL|LOG_SYSTEM + char logParams[256]; // extra params of atomic log +}; + + +int olc_raise_exception(struct exception_info *exp); + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/include/soc/oplus/healthinfo.h b/include/soc/oplus/healthinfo.h new file mode 120000 index 000000000000..caa18740501c --- /dev/null +++ b/include/soc/oplus/healthinfo.h @@ -0,0 +1 @@ +../../../../../vendor/oplus/kernel/oplus_performance/healthinfo/main/healthinfo.h \ No newline at end of file diff --git a/include/soc/oplus/lowmem_dbg.h b/include/soc/oplus/lowmem_dbg.h new file mode 120000 index 000000000000..3c09367bde29 --- /dev/null +++ b/include/soc/oplus/lowmem_dbg.h @@ -0,0 +1 @@ +../../../../../vendor/oplus/kernel/oplus_performance/lowmem_dbg/lowmem_dbg.h \ No newline at end of file diff --git a/include/soc/oplus/oplus_project.h b/include/soc/oplus/oplus_project.h new file mode 100644 index 000000000000..6d5c824670d6 --- /dev/null +++ b/include/soc/oplus/oplus_project.h @@ -0,0 +1,113 @@ +#ifndef _OPLUS_PROJECT_H_ +#define _OPLUS_PROJECT_H_ + +#define MAX_OCP 6 +#define MAX_LEN 8 +#define FEATURE_COUNT 10 +#define ALIGN4(s) ((sizeof(s) + 3)&(~0x3)) + +#define FEATURE1_OPEARTOR_OPEN_MASK 0000 +#define FEATURE1_FOREIGN_MASK 0001 +#define FEATURE1_OPEARTOR_CMCC_MASK 0010 +#define FEATURE1_OPEARTOR_CT_MASK 0011 +#define FEATURE1_OPEARTOR_CU_MASK 0100 +#define FEATURE1_OPEARTOR_MAX_MASK 1111 + +enum { + OPLUS_UNKNOWN, +}; + +enum OPLUS_OPERATOR{ + OPERATOR_UNKOWN, +}; + +enum f_index { + IDX_1 = 1, + IDX_2, + IDX_3, + IDX_4, + IDX_5, + IDX_6, + IDX_7, + IDX_8, + IDX_9, + IDX_10, +}; + +enum PCB_VERSION { + PRE_EVB1 = 0, + PRE_EVB2, + EVB1, + EVB2, + T0, + T1, + T2, + T3, + EVT1, + EVT2, + EVT3, + EVT4, + DVT1, + DVT2, + DVT3, + DVT4, + PVT1, + PVT2, + PVT3, + MP1, + MP2, + MP3, + PCB_MAX, +}; + +enum OPLUS_ENG_VERSION { + RELEASE = 0x00, + AGING = 0x01, + CTA = 0x02, + PERFORMANCE = 0x03, + PREVERSION = 0x04, + ALL_NET_CMCC_TEST = 0x05, + ALL_NET_CMCC_FIELD = 0x06, + ALL_NET_CU_TEST = 0x07, + ALL_NET_CU_FIELD = 0x08, + ALL_NET_CT_TEST = 0x09, + ALL_NET_CT_FIELD = 0x0A, + HIGH_TEMP_AGING = 0x0B, + FACTORY = 0x0C +}; + +struct pcb_match { + enum PCB_VERSION version; + char *str; +}; + +typedef struct +{ + uint32_t nVerison; + uint32_t nProject; + uint32_t nDtsi; + uint32_t nAudio; + uint32_t nRF; + uint32_t nFeature[FEATURE_COUNT]; + uint32_t nOplusBootMode; + uint32_t nPCB; + uint8_t nPmicOcp[MAX_OCP]; + uint8_t reserved[16]; /*reseved[0] & reserved[1] used for compability of upgrade P->Q*/ +} ProjectInfoCDTType; + +typedef struct +{ + uint32_t version; + uint32_t is_confidential; +} EngInfoType; + +unsigned int get_project(void); +int get_PCB_Version(void); +int get_eng_version(void); +int32_t get_Modem_Version(void); +int32_t get_Operator_Version(void); +bool is_confidential(void); +bool oplus_daily_build(void); +uint32_t get_oplus_feature(enum f_index index); + +#endif diff --git a/include/soc/oplus/system b/include/soc/oplus/system new file mode 120000 index 000000000000..9dd8275c1815 --- /dev/null +++ b/include/soc/oplus/system @@ -0,0 +1 @@ +../../../../../vendor/oplus/kernel/system/include \ No newline at end of file diff --git a/include/soc/qcom/ramdump.h b/include/soc/qcom/ramdump.h index 11aa0d91d36e..95bcf0d62257 100644 --- a/include/soc/qcom/ramdump.h +++ b/include/soc/qcom/ramdump.h @@ -15,6 +15,10 @@ struct ramdump_segment { unsigned long size; }; +#ifdef OPLUS_FEATURE_MODEM_MINIDUMP +//Add for customized subsystem ramdump to skip generate dump cause by SAU +extern bool SKIP_GENERATE_RAMDUMP; +#endif #ifdef CONFIG_MSM_SUBSYSTEM_RESTART extern void *create_ramdump_device(const char *dev_name, struct device *parent); extern void destroy_ramdump_device(void *dev); diff --git a/include/soc/qcom/subsystem_restart.h b/include/soc/qcom/subsystem_restart.h index 989112764cb3..7ecf5fa0a815 100644 --- a/include/soc/qcom/subsystem_restart.h +++ b/include/soc/qcom/subsystem_restart.h @@ -91,6 +91,7 @@ struct subsys_desc { int (*shutdown)(const struct subsys_desc *desc, bool force_stop); int (*powerup)(const struct subsys_desc *desc); + void (*force_reset)(const struct subsys_desc *desc); void (*crash_shutdown)(const struct subsys_desc *desc); int (*ramdump)(int, const struct subsys_desc *desc); void (*free_memory)(const struct subsys_desc *desc); @@ -144,8 +145,24 @@ struct notif_data { #if defined(CONFIG_MSM_SUBSYSTEM_RESTART) +#ifdef OPLUS_FEATURE_ADSP_RECOVERY +extern void oplus_set_ssr_state(bool ssr_state); +extern bool oplus_get_ssr_state(void); +#endif /* OPLUS_FEATURE_ADSP_RECOVERY */ + extern int subsys_get_restart_level(struct subsys_device *dev); extern int subsystem_restart_dev(struct subsys_device *dev); +#ifdef OPLUS_FEATURE_MODEM_MINIDUMP +#define MAX_REASON_LEN 300 +extern void __subsystem_send_uevent(struct device *dev, char *reason); +extern void subsystem_send_uevent(struct subsys_device *dev, char *reason); +#endif /*OPLUS_FEATURE_MODEM_MINIDUMP*/ + +#ifdef OPLUS_FEATURE_WIFI_DCS_SWITCH +extern void __wlan_subsystem_send_uevent(struct device *dev, char *reason, const char *name); +extern void wlan_subsystem_send_uevent(struct subsys_device *dev, char *reason, const char *name); +#endif /*OPLUS_FEATURE_WIFI_DCS_SWITCH*/ + extern int subsystem_restart(const char *name); extern int subsystem_crashed(const char *name); @@ -170,6 +187,14 @@ struct subsys_device *find_subsys_device(const char *str); extern int wait_for_shutdown_ack(struct subsys_desc *desc); #else +#ifdef OPLUS_FEATURE_ADSP_RECOVERY +static inline void oplus_set_ssr_state(bool ssr_state) {} +static inline bool oplus_get_ssr_state(void) +{ + return false; +} +#endif /* OPLUS_FEATURE_ADSP_RECOVERY */ + static inline int subsys_get_restart_level(struct subsys_device *dev) { return 0; @@ -180,6 +205,17 @@ static inline int subsystem_restart_dev(struct subsys_device *dev) return 0; } +#ifdef OPLUS_FEATURE_MODEM_MINIDUMP +static inline void __subsystem_send_uevent(struct device *dev, char *reason) +{ + return; +} +static inline void subsystem_send_uevent(struct subsys_device *dev, char *reason) +{ + return; +} +#endif /*OPLUS_FEATURE_MODEM_MINIDUMP*/ + static inline int subsystem_restart(const char *name) { return 0; diff --git a/include/trace/events/damon.h b/include/trace/events/damon.h new file mode 100644 index 000000000000..0bc02e571267 --- /dev/null +++ b/include/trace/events/damon.h @@ -0,0 +1,82 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#undef TRACE_SYSTEM +#define TRACE_SYSTEM damon + +#if !defined(_TRACE_DAMON_H) || defined(TRACE_HEADER_MULTI_READ) +#define _TRACE_DAMON_H + +#include +#include +#include + +TRACE_EVENT(damon_aggregated, + + TP_PROTO(struct damon_target *t, unsigned int target_id, + struct damon_region *r, unsigned int nr_regions), + TP_ARGS(t, target_id, r, nr_regions), + + TP_STRUCT__entry( + __field(unsigned long, target_id) + __field(unsigned int, nr_regions) + __field(unsigned long, start) + __field(unsigned long, end) + __field(unsigned int, nr_accesses) + __field(unsigned int, age) + ), + + TP_fast_assign( + __entry->target_id = target_id; + __entry->nr_regions = nr_regions; + __entry->start = r->ar.start; + __entry->end = r->ar.end; + __entry->nr_accesses = r->nr_accesses; + __entry->age = r->age; + ), + + TP_printk("target_id=%lu nr_regions=%u %lu-%lu: %u %u", + __entry->target_id, __entry->nr_regions, + __entry->start, __entry->end, + __entry->nr_accesses, __entry->age) +); + +TRACE_EVENT(damon_reclaim_statistics, + + TP_PROTO(unsigned long nr_reclaim_tried_regions, + unsigned long bytes_reclaim_tried_regions, + unsigned long nr_reclaimed_regions, + unsigned long bytes_reclaimed_regions, + unsigned long nr_quota_exceeds), + TP_ARGS(nr_reclaim_tried_regions, + bytes_reclaim_tried_regions, + nr_reclaimed_regions, + bytes_reclaimed_regions, + nr_quota_exceeds), + + TP_STRUCT__entry( + __field(unsigned long, nr_reclaim_tried_regions) + __field(unsigned long, bytes_reclaim_tried_regions) + __field(unsigned long, nr_reclaimed_regions) + __field(unsigned long, bytes_reclaimed_regions) + __field(unsigned long, nr_quota_exceeds) + ), + + TP_fast_assign( + __entry->nr_reclaim_tried_regions = nr_reclaim_tried_regions; + __entry->bytes_reclaim_tried_regions = bytes_reclaim_tried_regions; + __entry->nr_reclaimed_regions = nr_reclaimed_regions; + __entry->bytes_reclaimed_regions = bytes_reclaimed_regions; + __entry->nr_quota_exceeds = nr_quota_exceeds; + ), + + TP_printk("nr_reclaim_tried_regions=%lu bytes_reclaim_tried_regions=%lu nr_reclaimed_regions=%lu, bytes_reclaimed_regions=%lu, nr_quota_exceeds=%lu", + __entry->nr_reclaim_tried_regions, + __entry->bytes_reclaim_tried_regions, + __entry->nr_reclaimed_regions, + __entry->bytes_reclaimed_regions, + __entry->nr_quota_exceeds) +); + +#endif /* _TRACE_DAMON_H */ + +/* This part must be outside protection */ +#include diff --git a/include/trace/events/erofs.h b/include/trace/events/erofs.h new file mode 100644 index 000000000000..27f5caa6299a --- /dev/null +++ b/include/trace/events/erofs.h @@ -0,0 +1,259 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#undef TRACE_SYSTEM +#define TRACE_SYSTEM erofs + +#if !defined(_TRACE_EROFS_H) || defined(TRACE_HEADER_MULTI_READ) +#define _TRACE_EROFS_H + +#include +#include + +struct erofs_map_blocks; + +#define show_dev(dev) MAJOR(dev), MINOR(dev) +#define show_dev_nid(entry) show_dev(entry->dev), entry->nid + +#define show_file_type(type) \ + __print_symbolic(type, \ + { 0, "FILE" }, \ + { 1, "DIR" }) + +#define show_map_flags(flags) __print_flags(flags, "|", \ + { EROFS_GET_BLOCKS_RAW, "RAW" }) + +#define show_mflags(flags) __print_flags(flags, "", \ + { EROFS_MAP_MAPPED, "M" }, \ + { EROFS_MAP_META, "I" }, \ + { EROFS_MAP_ZIPPED, "Z" }) + +TRACE_EVENT(erofs_lookup, + + TP_PROTO(struct inode *dir, struct dentry *dentry, unsigned int flags), + + TP_ARGS(dir, dentry, flags), + + TP_STRUCT__entry( + __field(dev_t, dev ) + __field(erofs_nid_t, nid ) + __field(const char *, name ) + __field(unsigned int, flags ) + ), + + TP_fast_assign( + __entry->dev = dir->i_sb->s_dev; + __entry->nid = EROFS_I(dir)->nid; + __entry->name = dentry->d_name.name; + __entry->flags = flags; + ), + + TP_printk("dev = (%d,%d), pnid = %llu, name:%s, flags:%x", + show_dev_nid(__entry), + __entry->name, + __entry->flags) +); + +TRACE_EVENT(erofs_fill_inode, + TP_PROTO(struct inode *inode, int isdir), + TP_ARGS(inode, isdir), + + TP_STRUCT__entry( + __field(dev_t, dev ) + __field(erofs_nid_t, nid ) + __field(erofs_blk_t, blkaddr ) + __field(unsigned int, ofs ) + __field(int, isdir ) + ), + + TP_fast_assign( + __entry->dev = inode->i_sb->s_dev; + __entry->nid = EROFS_I(inode)->nid; + __entry->blkaddr = erofs_blknr(iloc(EROFS_I_SB(inode), __entry->nid)); + __entry->ofs = erofs_blkoff(iloc(EROFS_I_SB(inode), __entry->nid)); + __entry->isdir = isdir; + ), + + TP_printk("dev = (%d,%d), nid = %llu, blkaddr %u ofs %u, isdir %d", + show_dev_nid(__entry), + __entry->blkaddr, __entry->ofs, + __entry->isdir) +); + +TRACE_EVENT(erofs_readpage, + + TP_PROTO(struct page *page, bool raw), + + TP_ARGS(page, raw), + + TP_STRUCT__entry( + __field(dev_t, dev ) + __field(erofs_nid_t, nid ) + __field(int, dir ) + __field(pgoff_t, index ) + __field(int, uptodate) + __field(bool, raw ) + ), + + TP_fast_assign( + __entry->dev = page->mapping->host->i_sb->s_dev; + __entry->nid = EROFS_I(page->mapping->host)->nid; + __entry->dir = S_ISDIR(page->mapping->host->i_mode); + __entry->index = page->index; + __entry->uptodate = PageUptodate(page); + __entry->raw = raw; + ), + + TP_printk("dev = (%d,%d), nid = %llu, %s, index = %lu, uptodate = %d " + "raw = %d", + show_dev_nid(__entry), + show_file_type(__entry->dir), + (unsigned long)__entry->index, + __entry->uptodate, + __entry->raw) +); + +TRACE_EVENT(erofs_readpages, + + TP_PROTO(struct inode *inode, struct page *page, unsigned int nrpage, + bool raw), + + TP_ARGS(inode, page, nrpage, raw), + + TP_STRUCT__entry( + __field(dev_t, dev ) + __field(erofs_nid_t, nid ) + __field(pgoff_t, start ) + __field(unsigned int, nrpage ) + __field(bool, raw ) + ), + + TP_fast_assign( + __entry->dev = inode->i_sb->s_dev; + __entry->nid = EROFS_I(inode)->nid; + __entry->start = page->index; + __entry->nrpage = nrpage; + __entry->raw = raw; + ), + + TP_printk("dev = (%d,%d), nid = %llu, start = %lu nrpage = %u raw = %d", + show_dev_nid(__entry), + (unsigned long)__entry->start, + __entry->nrpage, + __entry->raw) +); + +DECLARE_EVENT_CLASS(erofs__map_blocks_enter, + TP_PROTO(struct inode *inode, struct erofs_map_blocks *map, + unsigned int flags), + + TP_ARGS(inode, map, flags), + + TP_STRUCT__entry( + __field( dev_t, dev ) + __field( erofs_nid_t, nid ) + __field( erofs_off_t, la ) + __field( u64, llen ) + __field( unsigned int, flags ) + ), + + TP_fast_assign( + __entry->dev = inode->i_sb->s_dev; + __entry->nid = EROFS_I(inode)->nid; + __entry->la = map->m_la; + __entry->llen = map->m_llen; + __entry->flags = flags; + ), + + TP_printk("dev = (%d,%d), nid = %llu, la %llu llen %llu flags %s", + show_dev_nid(__entry), + __entry->la, __entry->llen, + __entry->flags ? show_map_flags(__entry->flags) : "NULL") +); + +DEFINE_EVENT(erofs__map_blocks_enter, erofs_map_blocks_flatmode_enter, + TP_PROTO(struct inode *inode, struct erofs_map_blocks *map, + unsigned flags), + + TP_ARGS(inode, map, flags) +); + +DEFINE_EVENT(erofs__map_blocks_enter, z_erofs_map_blocks_iter_enter, + TP_PROTO(struct inode *inode, struct erofs_map_blocks *map, + unsigned int flags), + + TP_ARGS(inode, map, flags) +); + +DECLARE_EVENT_CLASS(erofs__map_blocks_exit, + TP_PROTO(struct inode *inode, struct erofs_map_blocks *map, + unsigned int flags, int ret), + + TP_ARGS(inode, map, flags, ret), + + TP_STRUCT__entry( + __field( dev_t, dev ) + __field( erofs_nid_t, nid ) + __field( unsigned int, flags ) + __field( erofs_off_t, la ) + __field( erofs_off_t, pa ) + __field( u64, llen ) + __field( u64, plen ) + __field( unsigned int, mflags ) + __field( int, ret ) + ), + + TP_fast_assign( + __entry->dev = inode->i_sb->s_dev; + __entry->nid = EROFS_I(inode)->nid; + __entry->flags = flags; + __entry->la = map->m_la; + __entry->pa = map->m_pa; + __entry->llen = map->m_llen; + __entry->plen = map->m_plen; + __entry->mflags = map->m_flags; + __entry->ret = ret; + ), + + TP_printk("dev = (%d,%d), nid = %llu, flags %s " + "la %llu pa %llu llen %llu plen %llu mflags %s ret %d", + show_dev_nid(__entry), + __entry->flags ? show_map_flags(__entry->flags) : "NULL", + __entry->la, __entry->pa, __entry->llen, __entry->plen, + show_mflags(__entry->mflags), __entry->ret) +); + +DEFINE_EVENT(erofs__map_blocks_exit, erofs_map_blocks_flatmode_exit, + TP_PROTO(struct inode *inode, struct erofs_map_blocks *map, + unsigned flags, int ret), + + TP_ARGS(inode, map, flags, ret) +); + +DEFINE_EVENT(erofs__map_blocks_exit, z_erofs_map_blocks_iter_exit, + TP_PROTO(struct inode *inode, struct erofs_map_blocks *map, + unsigned int flags, int ret), + + TP_ARGS(inode, map, flags, ret) +); + +TRACE_EVENT(erofs_destroy_inode, + TP_PROTO(struct inode *inode), + + TP_ARGS(inode), + + TP_STRUCT__entry( + __field( dev_t, dev ) + __field( erofs_nid_t, nid ) + ), + + TP_fast_assign( + __entry->dev = inode->i_sb->s_dev; + __entry->nid = EROFS_I(inode)->nid; + ), + + TP_printk("dev = (%d,%d), nid = %llu", show_dev_nid(__entry)) +); + +#endif /* _TRACE_EROFS_H */ + + /* This part must be outside protection */ +#include diff --git a/include/trace/events/iommu.h b/include/trace/events/iommu.h index 0db6f7f86270..743aea34c779 100644 --- a/include/trace/events/iommu.h +++ b/include/trace/events/iommu.h @@ -168,6 +168,60 @@ TRACE_EVENT(map_sg, ) ); +TRACE_EVENT(io_pgtable_free, + + TP_PROTO(u64 *table_base, u64 *pudp, u64 pud, unsigned long iova, int block), + + TP_ARGS(table_base, pudp, pud, iova, block), + + TP_STRUCT__entry( + __field(u64*, table_base) + __field(u64*, pudp) + __field(u64, pud) + __field(u64, iova) + __field(int, block) + ), + + TP_fast_assign( + __entry->table_base = table_base; + __entry->pudp = pudp; + __entry->pud = pud; + __entry->iova = iova; + __entry->block = block; + ), + + TP_printk("IOMMU: Freeing %s io-pgtable at 0x%lx pud=0x%lx *pud=0x%lx iova=0x%lx blk=%d", + __entry->block ? "block" : "", __entry->table_base, __entry->pudp, + __entry->pud, __entry->iova, __entry->block + ) +); + +TRACE_EVENT(io_pgtable_install, + + TP_PROTO(u64 *table_base, u64 *pudp, u64 pud, int block), + + TP_ARGS(table_base, pudp, pud, block), + + TP_STRUCT__entry( + __field(u64*, table_base) + __field(u64*, pudp) + __field(u64, pud) + __field(int, block) + ), + + TP_fast_assign( + __entry->table_base = table_base; + __entry->pudp = pudp; + __entry->pud = pud; + __entry->block = block; + ), + + TP_printk("IOMMU: Installed %s io-pgtable at 0x%lx pud=0x%lx *pud=0x%lx blk=%d", + __entry->block ? "block" : "", __entry->table_base, __entry->pudp, + __entry->pud, __entry->block + ) +); + DECLARE_EVENT_CLASS(iommu_error, TP_PROTO(struct device *dev, unsigned long iova, int flags), diff --git a/include/trace/events/ion.h b/include/trace/events/ion.h index aa374b45ef8d..57df3c7b83b1 100644 --- a/include/trace/events/ion.h +++ b/include/trace/events/ion.h @@ -167,6 +167,58 @@ DEFINE_EVENT(ion_access_cmo_class, ion_end_cpu_access_notmapped, TP_ARGS(dev, name, cached, hlos_accessible, dir, only_mapped) ); + +#ifdef CONFIG_OPLUS_ION_BOOSTPOOL +DECLARE_EVENT_CLASS(oplus_ion_alloc, + + TP_PROTO(size_t len, + unsigned int mask, + unsigned int flags, + char *dbg_name), + + TP_ARGS(len, mask, flags, dbg_name), + + TP_STRUCT__entry( + __field(size_t, len) + __field(unsigned int, mask) + __field(unsigned int, flags) + __array(char, dbg_name, 8) + ), + + TP_fast_assign( + __entry->len = len; + __entry->mask = mask; + __entry->flags = flags; + strlcpy(__entry->dbg_name, dbg_name, 8); + ), + + TP_printk("len=%zu mask=0x%x flags=0x%x dbg_name=%s", + __entry->len, + __entry->mask, + __entry->flags, + __entry->dbg_name) +); + +DEFINE_EVENT(oplus_ion_alloc, ion_alloc_start, + + TP_PROTO(size_t len, + unsigned int mask, + unsigned int flags, + char *dbg_name), + + TP_ARGS(len, mask, flags, dbg_name) +); + +DEFINE_EVENT(oplus_ion_alloc, ion_alloc_end, + + TP_PROTO(size_t len, + unsigned int mask, + unsigned int flags, + char *dbg_name), + + TP_ARGS(len, mask, flags, dbg_name) +); +#endif /* CONFIG_OPLUS_ION_BOOSTPOOL */ #endif /* _TRACE_ION_H */ #include diff --git a/include/trace/events/mmflags.h b/include/trace/events/mmflags.h index a1675d43777e..0ec5ed90496a 100644 --- a/include/trace/events/mmflags.h +++ b/include/trace/events/mmflags.h @@ -73,7 +73,7 @@ #define IF_HAVE_PG_HWPOISON(flag,string) #endif -#if defined(CONFIG_IDLE_PAGE_TRACKING) && defined(CONFIG_64BIT) +#if defined(CONFIG_PAGE_IDLE_FLAG) && defined(CONFIG_64BIT) #define IF_HAVE_PG_IDLE(flag,string) ,{1UL << flag, string} #else #define IF_HAVE_PG_IDLE(flag,string) diff --git a/include/trace/events/pagemap.h b/include/trace/events/pagemap.h index 8fd1babae761..e1735fe7c76a 100644 --- a/include/trace/events/pagemap.h +++ b/include/trace/events/pagemap.h @@ -27,24 +27,21 @@ TRACE_EVENT(mm_lru_insertion, - TP_PROTO( - struct page *page, - int lru - ), + TP_PROTO(struct page *page), - TP_ARGS(page, lru), + TP_ARGS(page), TP_STRUCT__entry( __field(struct page *, page ) __field(unsigned long, pfn ) - __field(int, lru ) + __field(enum lru_list, lru ) __field(unsigned long, flags ) ), TP_fast_assign( __entry->page = page; __entry->pfn = page_to_pfn(page); - __entry->lru = lru; + __entry->lru = page_lru(page); __entry->flags = trace_pagemap_flags(page); ), diff --git a/include/trace/events/power.h b/include/trace/events/power.h index 53a3fcd4ea08..2755a28e6a20 100644 --- a/include/trace/events/power.h +++ b/include/trace/events/power.h @@ -627,6 +627,92 @@ TRACE_EVENT(sugov_next_freq, __entry->freq) ); +#ifdef OPLUS_FEATURE_POWER_CPUFREQ +TRACE_EVENT(sugov_next_freq_tl, + TP_PROTO(unsigned int cpu, unsigned long util, unsigned long max, + unsigned int freq, unsigned int laf, unsigned int prev_freq), + TP_ARGS(cpu, util, max, freq, laf, prev_freq), + TP_STRUCT__entry( + __field(unsigned int, cpu) + __field(unsigned long, util) + __field(unsigned long, max) + __field(unsigned int, freq) + __field(unsigned int, laf) + __field(unsigned int, prev_freq) + ), + TP_fast_assign( + __entry->cpu = cpu; + __entry->util = util; + __entry->max = max; + __entry->freq = freq; + __entry->laf = laf; + __entry->prev_freq = prev_freq; + ), + TP_printk("cpu=%u util=%lu max=%lu freq=%u laf=%u prev_freq=%u", + __entry->cpu, + __entry->util, + __entry->max, + __entry->freq, + __entry->laf, + __entry->prev_freq) +); + +TRACE_EVENT(choose_freq, + TP_PROTO(unsigned int freq, unsigned int prevfreq, unsigned int freqmax, + unsigned int freqmin, unsigned int tl, int index), + TP_ARGS(freq, prevfreq, freqmax, freqmin, tl, index), + TP_STRUCT__entry( + __field(unsigned int, freq) + __field(unsigned int, prevfreq) + __field(unsigned int, freqmax) + __field(unsigned int, freqmin) + __field(unsigned int, tl) + __field(int, index) + ), + TP_fast_assign( + __entry->freq = freq; + __entry->prevfreq = prevfreq; + __entry->freqmax = freqmax; + __entry->freqmin = freqmin; + __entry->tl = tl; + __entry->index = index; + ), + TP_printk("freq=%u prevfreq=%u freqmax=%u freqmin=%u tl=%u index=%d", + __entry->freq, + __entry->prevfreq, + __entry->freqmax, + __entry->freqmin, + __entry->tl, + __entry->index) +); + +TRACE_EVENT(sugov_time_limit, + TP_PROTO(unsigned int cpu, + const char *reason, + unsigned long long delta, + unsigned int curr, + unsigned int target), + TP_ARGS(cpu, reason, delta, curr, target), + TP_STRUCT__entry( + __field(unsigned int, cpu) + __string(reason, reason) + __field(unsigned long long, delta) + __field(unsigned int, curr) + __field(unsigned int, target) + ), + TP_fast_assign( + __entry->cpu = cpu; + __assign_str(reason, reason); + __entry->delta = delta; + __entry->curr = curr; + __entry->target = target; + ), + TP_printk("cpu=%u reason=%s delta_ns=%llu curr=%u target=%u", + __entry->cpu, __get_str(reason), + __entry->delta, __entry->curr, __entry->target) +); +#endif + TRACE_EVENT(bw_hwmon_meas, TP_PROTO(const char *name, unsigned long mbps, diff --git a/include/trace/events/sched.h b/include/trace/events/sched.h index f00fe85e6997..e85fc9d8ff06 100644 --- a/include/trace/events/sched.h +++ b/include/trace/events/sched.h @@ -1174,6 +1174,89 @@ TRACE_EVENT(sched_cpu_util, __entry->nr_rtg_high_prio_tasks) ); +#ifdef OPLUS_FEATURE_SCHED_ASSIST +TRACE_EVENT(sched_cpu_skip, + + TP_PROTO(struct task_struct *p, bool sysctl_prefer_silver, bool is_ux_task, bool check_freq, bool check_task_util, bool check_cpu_util, + bool skip_big_cluster), + + TP_ARGS(p, sysctl_prefer_silver, is_ux_task, check_freq, check_task_util, check_cpu_util, skip_big_cluster), + + TP_STRUCT__entry( + __field(int, pid) + __array(char, comm, TASK_COMM_LEN) + __field(bool, sysctl_prefer_silver) + __field(bool, is_ux_task) + __field(bool, check_freq) + __field(bool, check_task_util) + __field(bool, check_cpu_util) + __field(bool, skip_big_cluster) + ), + + TP_fast_assign( + __entry->pid = p ? p->pid : -1; + memcpy(__entry->comm, p ? p->comm:"NULL", TASK_COMM_LEN); + __entry->sysctl_prefer_silver = sysctl_prefer_silver; + __entry->is_ux_task = is_ux_task; + __entry->check_freq = check_freq; + __entry->check_task_util = check_task_util; + __entry->check_cpu_util = check_cpu_util; + __entry->skip_big_cluster = skip_big_cluster; + ), + + TP_printk("pid=%d comm=%s prefer_silver_enabled=%d is_ux_task=%d check_freq=%d check_task_util=%d check_cpu_util=%d skip_big_cluster=%d", + __entry->pid, __entry->comm, __entry->sysctl_prefer_silver, + __entry->is_ux_task, __entry->check_freq, + __entry->check_task_util, __entry->check_cpu_util, + __entry->skip_big_cluster) +); + +TRACE_EVENT(sched_cpu_sel, + + TP_PROTO(struct task_struct *p, int task_boost, bool task_skip_min, bool boosted, int boost_pol, + int task_util, int cpu_util, bool fit_small, bool sysctl_prefer_silver, bool is_ux_task, int start_cpu), + + TP_ARGS(p, task_boost, task_skip_min, boosted, boost_pol, task_util, cpu_util, fit_small, is_ux_task, sysctl_prefer_silver, start_cpu), + + TP_STRUCT__entry( + __field(int, pid) + __array(char, comm, TASK_COMM_LEN) + __field(int, task_boost) + __field(bool, task_skip_min) + __field(bool, boosted) + __field(int, boost_pol) + __field(int, task_util) + __field(int, cpu_util) + __field(bool, fit_small) + __field(bool, is_ux_task) + __field(bool, sysctl_prefer_silver) + __field(int, start_cpu) + ), + + TP_fast_assign( + __entry->pid = p ? p->pid : -1; + memcpy(__entry->comm, p ? p->comm:"NULL", TASK_COMM_LEN); + __entry->task_boost = task_boost; + __entry->task_skip_min = task_skip_min; + __entry->boosted = boosted; + __entry->boost_pol = boost_pol; + __entry->task_util = task_util; + __entry->cpu_util = cpu_util; + __entry->fit_small = fit_small; + __entry->is_ux_task = is_ux_task; + __entry->sysctl_prefer_silver = sysctl_prefer_silver; + __entry->start_cpu = start_cpu; + ), + + TP_printk("pid=%d comm=%s task_boost=%d skip_min=%d boosted=%d boost_pol=%d task_util=%d cpu_util=%d fit_small=%d is_ux_task=%d prefer_silver_enabled=%d start_cpu=%d", + __entry->pid, __entry->comm, __entry->task_boost, + __entry->task_skip_min, __entry->boosted, + __entry->boost_pol, __entry->task_util, + __entry->cpu_util, __entry->fit_small, __entry->is_ux_task, __entry->sysctl_prefer_silver, __entry->start_cpu) +); + +#endif + TRACE_EVENT(sched_compute_energy, TP_PROTO(struct task_struct *p, int eval_cpu, @@ -1664,6 +1747,253 @@ TRACE_EVENT(sched_isolate, __entry->time, __entry->isolate) ); +#ifdef CONFIG_OPLUS_FEATURE_INPUT_BOOST_V4 +TRACE_EVENT(sched_in_fbg, + TP_PROTO(struct task_struct *p, int grp), + + TP_ARGS(p, grp), + + TP_STRUCT__entry( + __array(char, comm, TASK_COMM_LEN) + __field(pid_t, pid) + __field(int, grp) + ), + + TP_fast_assign( + memcpy(__entry->comm, p->comm, TASK_COMM_LEN); + __entry->pid = p->pid; + __entry->grp = grp; + ), + + TP_printk("pid=%d comm=%s in_grp=%d", + __entry->pid, __entry->comm, __entry->grp) +); +TRACE_EVENT(sched_fbg_rt, + + TP_PROTO(struct task_struct *p, int orig_cpu, int fbg_cpu, unsigned long lowest_mask), + + TP_ARGS(p, orig_cpu, fbg_cpu, lowest_mask), + + TP_STRUCT__entry( + __field(int, pid) + __array(char, comm, TASK_COMM_LEN) + __field(int, orig_cpu) + __field(int, fbg_cpu) + __field(unsigned long, lowest_mask) + ), + + TP_fast_assign( + __entry->pid = p->pid; + memcpy(__entry->comm, p->comm, TASK_COMM_LEN); + __entry->orig_cpu = orig_cpu; + __entry->fbg_cpu = fbg_cpu; + __entry->lowest_mask = lowest_mask; + ), + + TP_printk("pid=%d comm=%s orig_cpu=%d fbg_cpu=%d lowest_mask=%#lx", + __entry->pid, __entry->comm, __entry->orig_cpu, __entry->fbg_cpu, __entry->lowest_mask + ) +); +TRACE_EVENT(fbg_tick_task, + TP_PROTO(struct task_struct *p, int depth), + + TP_ARGS(p, depth), + + TP_STRUCT__entry( + __array(char, comm, TASK_COMM_LEN) + __field(pid_t, pid) + __field(int, depth) + ), + + TP_fast_assign( + memcpy(__entry->comm, p->comm, TASK_COMM_LEN); + __entry->pid = p->pid; + __entry->depth = depth; + ), + + TP_printk("pid=%d comm=%s depth=%d", + __entry->pid, __entry->comm, __entry->depth) +); + +TRACE_EVENT(add_group_delta, + TP_PROTO(u64 wall_clock, u64 mark_start, u64 window_start, u64 exec, + u64 scale, u64 task_exec_scale), + + TP_ARGS(wall_clock, mark_start, window_start, exec, scale, task_exec_scale), + + TP_STRUCT__entry( + __field(u64, wall_clock) + __field(u64, mark_start) + __field(u64, window_start) + __field(u64, exec) + __field(u64, scale) + __field(u64, task_exec_scale) + ), + + TP_fast_assign( + __entry->wall_clock = wall_clock; + __entry->mark_start = mark_start; + __entry->window_start = window_start; + __entry->exec = exec; + __entry->scale = scale; + __entry->task_exec_scale = task_exec_scale; + ), + + TP_printk("wall_clock=%llu mark_start=%llu window_start=%llu curr_window_exec=%llu curr_window_scale=%llu task_exec_scale=%llu", + __entry->wall_clock, __entry->mark_start, __entry->window_start, __entry->exec, __entry->scale, __entry->task_exec_scale) +); +TRACE_EVENT(add_group_demand, + TP_PROTO(struct task_struct *p, int event, u64 scale, u64 task_exec_scale, int nr_running), + + TP_ARGS(p, event, scale, task_exec_scale, nr_running), + + TP_STRUCT__entry( + __array(char, comm, TASK_COMM_LEN) + __field(pid_t, pid) + __field(int, event) + __field(u64, scale) + __field(u64, task_exec_scale) + __field(int, nr_running) + ), + + TP_fast_assign( + memcpy(__entry->comm, p->comm, TASK_COMM_LEN); + __entry->pid = p->pid; + __entry->event = event; + __entry->scale = scale; + __entry->task_exec_scale = task_exec_scale; + __entry->nr_running = nr_running; + ), + + TP_printk("comm=%s pid=%d event=%d curr_window_scale=%llu task_exec_scale=%llu nr_running=%d", + __entry->comm, __entry->pid, __entry->event, __entry->scale, __entry->task_exec_scale, __entry->nr_running) +); + +TRACE_EVENT(frame_info_tick, + TP_PROTO(struct task_struct *p, u64 timeline, u64 exec, unsigned long curr_load, + unsigned long vload, bool use_vload, unsigned int qos, unsigned long util), + + TP_ARGS(p, timeline, exec, curr_load, vload, use_vload, qos, util), + + TP_STRUCT__entry( + __array(char, comm, TASK_COMM_LEN) + __field(pid_t, pid) + __field(u64, timeline) + __field(u64, exec) + __field(unsigned long, curr_load) + __field(unsigned long, vload) + __field(int, use_vload) + __field(unsigned int, qos) + __field(unsigned long, util) + ), + + TP_fast_assign( + memcpy(__entry->comm, p->comm, TASK_COMM_LEN); + __entry->pid = p->pid; + __entry->timeline = timeline; + __entry->exec = exec; + __entry->curr_load = curr_load; + __entry->vload = vload; + __entry->use_vload = use_vload; + __entry->qos = qos; + __entry->util = util; + ), + + TP_printk("comm=%s pid=%d timeline=%llu exec=%llu curr_load=%lu vload=%lu use_vload=%d qos=%u util=%lu", + __entry->comm, __entry->pid, __entry->timeline, __entry->exec, __entry->curr_load, __entry->vload, + __entry->use_vload, __entry->qos, __entry->util) +); + +TRACE_EVENT(task_exec_scale, + TP_PROTO(int cpu, u64 scale, u64 curr_freq, u64 capacity, u64 max_freq), + + TP_ARGS(cpu, scale, curr_freq, capacity, max_freq), + + TP_STRUCT__entry( + __field(int, cpu) + __field(u64, scale) + __field(u64, curr_freq) + __field(u64, capacity) + __field(u64, max_freq) + ), + + TP_fast_assign( + __entry->cpu = cpu; + __entry->scale = scale; + __entry->curr_freq = curr_freq; + __entry->capacity = capacity; + __entry->max_freq = max_freq; + ), + + TP_printk("cpu=%d scale=%llu curr_freq=%llu capacity=%llu max_freq=%llu", + __entry->cpu, __entry->scale, __entry->curr_freq, __entry->capacity, __entry->max_freq) +); + +TRACE_EVENT(select_fbg_cpu, + + TP_PROTO(struct task_struct *p, bool full_boost, bool launch, bool target, int cpu), + + TP_ARGS(p, full_boost, launch, target, cpu), + + TP_STRUCT__entry( + __array(char, comm, TASK_COMM_LEN) + __field(pid_t, pid) + __field(int, full_boost) + __field(int, launch) + __field(int, target) + __field(int, cpu) + ), + + TP_fast_assign( + memcpy(__entry->comm, p->comm, TASK_COMM_LEN); + __entry->pid = p->pid; + __entry->full_boost = full_boost; + __entry->launch = launch; + __entry->target = target; + __entry->cpu = cpu; + ), + + TP_printk("pid=%d comm=%s full_boost=%d launch=%d target=%d cpu=%d", + __entry->pid, __entry->comm, __entry->full_boost, __entry->launch, __entry->target, __entry->cpu) +); + +TRACE_EVENT(frame_status, + TP_PROTO(unsigned long frame_util), + + TP_ARGS(frame_util), + + TP_STRUCT__entry( + __field(unsigned long, frame_util) + ), + + TP_fast_assign( + __entry->frame_util = frame_util; + ), + + TP_printk("frame_util=%lu", __entry->frame_util) +); +#endif /* CONFIG_OPLUS_FEATURE_INPUT_BOOST_V4 */ + +#ifdef CONFIG_OPLUS_FEATURE_GAME_OPT +TRACE_EVENT(game_opt_info, + TP_PROTO(char * str, unsigned long frame_util), + + TP_ARGS(str, frame_util), + + TP_STRUCT__entry( + __array(char, name, TASK_COMM_LEN) + __field(unsigned long, frame_util) + ), + + TP_fast_assign( + __entry->frame_util = frame_util; + memcpy(__entry->name, str, strlen(str)); + ), + + TP_printk("name = %s, val =%lu",__entry->name, __entry->frame_util) +); +#endif + #include "walt.h" #endif /* CONFIG_SMP */ #endif /* _TRACE_SCHED_H */ diff --git a/include/trace/hooks/vendor_hooks.h b/include/trace/hooks/vendor_hooks.h new file mode 100644 index 000000000000..8a3fdb9222e5 --- /dev/null +++ b/include/trace/hooks/vendor_hooks.h @@ -0,0 +1,76 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +/* + * Note: we intentionally omit include file ifdef protection + * This is due to the way trace events work. If a file includes two + * trace event headers under one "CREATE_TRACE_POINTS" the first include + * will override the DECLARE_RESTRICTED_HOOK and break the second include. + */ + +#include + +#define DECLARE_HOOK DECLARE_TRACE + +#ifdef TRACE_HEADER_MULTI_READ + +#undef DECLARE_RESTRICTED_HOOK +#define DECLARE_RESTRICTED_HOOK(name, proto, args, cond) \ + DEFINE_TRACE(name) + + +/* prevent additional recursion */ +#undef TRACE_HEADER_MULTI_READ +#else /* TRACE_HEADER_MULTI_READ */ + +#define DO_HOOK(tp, proto, args, cond) \ + do { \ + struct tracepoint_func *it_func_ptr; \ + void *it_func; \ + void *__data; \ + \ + if (!(cond)) \ + return; \ + \ + it_func_ptr = (tp)->funcs; \ + if (it_func_ptr) { \ + it_func = (it_func_ptr)->func; \ + __data = (it_func_ptr)->data; \ + ((void(*)(proto))(it_func))(args); \ + WARN_ON(((++it_func_ptr)->func)); \ + } \ + } while (0) + +#define __DECLARE_HOOK(name, proto, args, cond, data_proto, data_args) \ + extern struct tracepoint __tracepoint_##name; \ + static inline void trace_##name(proto) \ + { \ + if (static_key_false(&__tracepoint_##name.key)) \ + DO_HOOK(&__tracepoint_##name, \ + TP_PROTO(data_proto), \ + TP_ARGS(data_args), \ + TP_CONDITION(cond)); \ + } \ + static inline bool \ + trace_##name##_enabled(void) \ + { \ + return static_key_false(&__tracepoint_##name.key); \ + } \ + static inline int \ + register_trace_##name(void (*probe)(data_proto), void *data) \ + { \ + /* only allow a single attachment */ \ + if (trace_##name##_enabled()) \ + return -EBUSY; \ + return tracepoint_probe_register(&__tracepoint_##name, \ + (void *)probe, data); \ + } \ + /* vendor hooks cannot be unregistered */ \ + +#undef DECLARE_RESTRICTED_HOOK +#define DECLARE_RESTRICTED_HOOK(name, proto, args, cond) \ + __DECLARE_HOOK(name, PARAMS(proto), PARAMS(args), \ + cond, \ + PARAMS(void *__data, proto), \ + PARAMS(__data, args)) + +#endif /* TRACE_HEADER_MULTI_READ */ diff --git a/include/trace/hooks/vh_vmscan.h b/include/trace/hooks/vh_vmscan.h new file mode 100644 index 000000000000..fc007d4a2322 --- /dev/null +++ b/include/trace/hooks/vh_vmscan.h @@ -0,0 +1,59 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#undef TRACE_SYSTEM +#define TRACE_SYSTEM vh_vmscan +#undef TRACE_INCLUDE_PATH +#define TRACE_INCLUDE_PATH trace/hooks +#if !defined(_TRACE_HOOK_VMSCAN_H) || defined(TRACE_HEADER_MULTI_READ) +#define _TRACE_HOOK_VMSCAN_H +#include +#include +/* + * Following tracepoints are not exported in tracefs and provide a + * mechanism for vendor modules to hook and extend functionality + */ +struct cftype; +struct cgroup_subsys_state; +struct cgroup_subsys; +DECLARE_HOOK(android_vh_mem_cgroup_alloc, + TP_PROTO(struct mem_cgroup *memcg), + TP_ARGS(memcg)); + +DECLARE_HOOK(android_vh_mem_cgroup_free, + TP_PROTO(struct mem_cgroup *memcg), + TP_ARGS(memcg)); + +DECLARE_HOOK(android_vh_mem_cgroup_id_remove, + TP_PROTO(struct mem_cgroup *memcg), + TP_ARGS(memcg)); + +DECLARE_HOOK(android_vh_mem_cgroup_css_online, + TP_PROTO(struct cgroup_subsys_state *css, + struct mem_cgroup *memcg), + TP_ARGS(css, memcg)); + +DECLARE_HOOK(android_vh_mem_cgroup_css_offline, + TP_PROTO(struct cgroup_subsys_state *css, + struct mem_cgroup *memcg), + TP_ARGS(css, memcg)); + +DECLARE_HOOK(android_vh_meminfo_proc_show, + TP_PROTO(struct seq_file *m), + TP_ARGS(m)); + +DECLARE_HOOK(android_vh_tune_scan_type, + TP_PROTO(char *scan_type), + TP_ARGS(scan_type)) + +DECLARE_HOOK(android_vh_alloc_pages_slowpath, + TP_PROTO(gfp_t gfp_mask, unsigned int order, unsigned long delta), + TP_ARGS(gfp_mask, order, delta)); + +DECLARE_HOOK(android_vh_rmqueue, + TP_PROTO(struct zone *preferred_zone, struct zone *zone, + unsigned int order, gfp_t gfp_flags, + unsigned int alloc_flags, int migratetype), + TP_ARGS(preferred_zone, zone, order, + gfp_flags, alloc_flags, migratetype)); +#endif /* _TRACE_HOOK_VMSCAN_H */ +/* This part must be outside protection */ +#include diff --git a/include/uapi/drm/drm_mode.h b/include/uapi/drm/drm_mode.h index 93333c05d86b..9f3e731b2f2b 100644 --- a/include/uapi/drm/drm_mode.h +++ b/include/uapi/drm/drm_mode.h @@ -122,7 +122,11 @@ extern "C" { #define DRM_MODE_FLAG_VID_MODE_PANEL (1<<29) #define DRM_MODE_FLAG_CMD_MODE_PANEL (1<<30) #define DRM_MODE_FLAG_SEAMLESS (1<<31) +#ifdef OPLUS_FEATURE_ADFR +#define DRM_MODE_FLAG_VSYNCE_SOURCE_MASK (0xf<<25) +#endif /*OPLUS_FEATURE_ADFR*/ +#ifdef OPLUS_FEATURE_ADFR #define DRM_MODE_FLAG_ALL (DRM_MODE_FLAG_PHSYNC | \ DRM_MODE_FLAG_NHSYNC | \ DRM_MODE_FLAG_PVSYNC | \ @@ -139,7 +143,27 @@ extern "C" { DRM_MODE_FLAG_SUPPORTS_YUV | \ DRM_MODE_FLAG_VID_MODE_PANEL | \ DRM_MODE_FLAG_CMD_MODE_PANEL | \ + DRM_MODE_FLAG_3D_MASK | \ + DRM_MODE_FLAG_VSYNCE_SOURCE_MASK) +#else /*OPLUS_FEATURE_ADFR*/ +#define DRM_MODE_FLAG_ALL (DRM_MODE_FLAG_PHSYNC | \ + DRM_MODE_FLAG_NHSYNC | \ + DRM_MODE_FLAG_PVSYNC | \ + DRM_MODE_FLAG_NVSYNC | \ + DRM_MODE_FLAG_INTERLACE | \ + DRM_MODE_FLAG_DBLSCAN | \ + DRM_MODE_FLAG_CSYNC | \ + DRM_MODE_FLAG_PCSYNC | \ + DRM_MODE_FLAG_NCSYNC | \ + DRM_MODE_FLAG_HSKEW | \ + DRM_MODE_FLAG_DBLCLK | \ + DRM_MODE_FLAG_CLKDIV2 | \ + DRM_MODE_FLAG_SUPPORTS_RGB | \ + DRM_MODE_FLAG_SUPPORTS_YUV | \ + DRM_MODE_FLAG_VID_MODE_PANEL | \ + DRM_MODE_FLAG_CMD_MODE_PANEL | \ DRM_MODE_FLAG_3D_MASK) +#endif /*OPLUS_FEATURE_ADFR*/ /* DPMS flags */ /* bit compatible with the xorg definitions. */ diff --git a/include/uapi/drm/msm_drm.h b/include/uapi/drm/msm_drm.h index 214bc1bc81fa..0bfcc58fa8e0 100644 --- a/include/uapi/drm/msm_drm.h +++ b/include/uapi/drm/msm_drm.h @@ -27,6 +27,9 @@ #include "drm.h" #include "sde_drm.h" +//#if defined(OPLUS_FEATURE_PXLW_IRIS5) +#include "msm_drm_iris.h" +//#endif /*OPLUS_FEATURE_PXLW_IRIS5*/ #if defined(__cplusplus) extern "C" { diff --git a/include/uapi/drm/msm_drm_iris.h b/include/uapi/drm/msm_drm_iris.h new file mode 100644 index 000000000000..0a93bf8e7f99 --- /dev/null +++ b/include/uapi/drm/msm_drm_iris.h @@ -0,0 +1,66 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2015-2019, The Linux Foundataion. All rights reserved. + * Copyright (c) 2017-2020, Pixelworks, Inc. + * + * These files contain modifications made by Pixelworks, Inc., in 2019-2020. + */ + +#ifndef __MSM_DRM_IRIS_H__ +#define __MSM_DRM_IRIS_H__ + +#define DRM_MSM_IRIS_OPERATE_CONF 0x50 +#define DRM_MSM_IRIS_OPERATE_TOOL 0x51 + +enum iris_oprt_type { + IRIS_OPRT_TOOL_DSI, + IRIS_OPRT_CONFIGURE, + IRIS_OPRT_CONFIGURE_NEW, + IRIS_OPRT_CONFIGURE_NEW_GET, + IRIS_OPRT_MAX_TYPE, +}; + +struct msmfb_mipi_dsi_cmd { + __u8 dtype; + __u8 vc; +#define MSMFB_MIPI_DSI_COMMAND_LAST 1 +#define MSMFB_MIPI_DSI_COMMAND_ACK 2 +#define MSMFB_MIPI_DSI_COMMAND_HS 4 +#define MSMFB_MIPI_DSI_COMMAND_BLLP 8 +#define MSMFB_MIPI_DSI_COMMAND_DEBUG 16 +#define MSMFB_MIPI_DSI_COMMAND_TO_PANEL 32 +#define MSMFB_MIPI_DSI_COMMAND_T 64 + + __u32 iris_ocp_type; + __u32 iris_ocp_addr; + __u32 iris_ocp_value; + __u32 iris_ocp_size; + + __u16 flags; + __u16 length; + __u8 *payload; + __u8 response[16]; +}; + +struct msm_iris_operate_value { + unsigned int type; + unsigned int count; + void *values; +}; + +struct msmfb_iris_ambient_info { + uint32_t ambient_lux; + uint32_t ambient_bl_ratio; + void *lut_lut2_payload; +}; + +struct msmfb_iris_maxcll_info { + uint32_t mMAXCLL; + void *lut_luty_payload; + void *lut_lutuv_payload; +}; + +#define DRM_IOCTL_MSM_IRIS_OPERATE_CONF DRM_IOW (DRM_COMMAND_BASE + DRM_MSM_IRIS_OPERATE_CONF, struct msm_iris_operate_value) +#define DRM_IOCTL_MSM_IRIS_OPERATE_TOOL DRM_IOW (DRM_COMMAND_BASE + DRM_MSM_IRIS_OPERATE_TOOL, struct msm_iris_operate_value) + +#endif /* __MSM_DRM_IRIS_H__ */ diff --git a/include/uapi/linux/fuse.h b/include/uapi/linux/fuse.h index 24af4edfc98c..7210b489c629 100644 --- a/include/uapi/linux/fuse.h +++ b/include/uapi/linux/fuse.h @@ -274,6 +274,7 @@ struct fuse_file_lock { #define FUSE_HANDLE_KILLPRIV (1 << 19) #define FUSE_POSIX_ACL (1 << 20) #define FUSE_ABORT_ERROR (1 << 21) +#define FUSE_PASSTHROUGH (1 << 31) /** * CUSE INIT request/reply flags @@ -506,7 +507,7 @@ struct fuse_create_in { struct fuse_open_out { uint64_t fh; uint32_t open_flags; - uint32_t padding; + uint32_t passthrough_fh; }; struct fuse_release_in { @@ -782,7 +783,11 @@ struct fuse_notify_retrieve_in { }; /* Device ioctls: */ -#define FUSE_DEV_IOC_CLONE _IOR(229, 0, uint32_t) +#define FUSE_DEV_IOC_MAGIC 229 +#define FUSE_DEV_IOC_CLONE _IOR(FUSE_DEV_IOC_MAGIC, 0, uint32_t) +/* 127 is reserved for the V1 interface implementation in Android (deprecated) */ +/* 126 is reserved for the V2 interface implementation in Android */ +#define FUSE_DEV_IOC_PASSTHROUGH_OPEN _IOW(FUSE_DEV_IOC_MAGIC, 126, __u32) struct fuse_lseek_in { uint64_t fh; diff --git a/include/uapi/linux/magic.h b/include/uapi/linux/magic.h index 291f3f49d8ab..7b5252f1595d 100644 --- a/include/uapi/linux/magic.h +++ b/include/uapi/linux/magic.h @@ -19,6 +19,7 @@ #define SQUASHFS_MAGIC 0x73717368 #define ECRYPTFS_SUPER_MAGIC 0xf15f #define EFS_SUPER_MAGIC 0x414A53 +#define EROFS_SUPER_MAGIC_V1 0xE0F5E1E2 #define EXT2_SUPER_MAGIC 0xEF53 #define EXT3_SUPER_MAGIC 0xEF53 #define XENFS_SUPER_MAGIC 0xabba1974 diff --git a/include/uapi/linux/netlink.h b/include/uapi/linux/netlink.h index d5ce61f86fd0..9b15a400be64 100644 --- a/include/uapi/linux/netlink.h +++ b/include/uapi/linux/netlink.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ #ifndef _UAPI__LINUX_NETLINK_H #define _UAPI__LINUX_NETLINK_H +#define OPLUS_FEATURE_WIFI_LUCKYMONEY #include #include /* for __kernel_sa_family_t */ @@ -32,7 +33,45 @@ #define NETLINK_SOCKEV 23 /* Socket Administrative Events */ #define NETLINK_INET_DIAG NETLINK_SOCK_DIAG -#define MAX_LINKS 32 +#ifdef OPLUS_FEATURE_WIFI_LUCKYMONEY +#define NETLINK_OPLUS_NF_HOOKS 32 +#endif /* OPLUS_FEATURE_WIFI_LUCKYMONEY */ + +#ifdef OPLUS_FEATURE_HANS_FREEZE +#define NETLINK_OPLUS_HANS 29 /* Socket for freezing solution*/ +#endif /*OPLUS_FEATURE_HANS_FREEZE*/ + +//Add for apps network monitors +#define NETLINK_OPLUS_APPS_MONITOR 35 /* Apps monitor NETLINK SOCK */ +//#endif /* VENDOR_EDIT */ + +//#ifdef OPLUS_FEATURE_NWPOWER +#define NETLINK_OPLUS_NWPOWERSTATE 36 /*OPLUS NW PowerState*/ +//#endif /* OPLUS_FEATURE_NWPOWER */ + +//#ifdef OPLUS_FEATURE_DATA_EVAL +#define NETLINK_OPLUS_KERNEL2USER 37 /* kernel data info to user space */ +//#endif /* OPLUS_FEATURE_DATA_EVAL */ + +//#ifdef OPLUS_FEATURE_DHCP +#define NETLINK_OPLUS_DHCP 38 +//#endif /* OPLUS_FEATURE_DHCP */ + +//#ifdef OPLUS_FEATURE_WIFI_CAPCENTER +#define NETLINK_OPLUS_WIFI_CAP_CENTER_SYNC 39 +#define NETLINK_OPLUS_WIFI_CAP_CENTER_ASYNC 40 + +//#ifdef OPLUS_FEATURE_IPV6_OPTIMIZE +#define NETLINK_OPLUS_IPV6_RTO 42 +//#endif /* OPLUS_FEATURE_IPV6_OPTIMIZE */ + +//#ifdef OPLUS_FEATURE_THEIA +//should match with oplus_theia/include/TheiaKeventThread.h define +#define OPLUS_NETLINK_THEIA_KEVENT 43 + +//#define MAX_LINKS 40 +#define MAX_LINKS 44 +//#endif /* OPLUS_FEATURE_WIFI_CAPCENTER */ struct sockaddr_nl { __kernel_sa_family_t nl_family; /* AF_NETLINK */ diff --git a/include/uapi/scsi/ufs/ioctl.h b/include/uapi/scsi/ufs/ioctl.h index a4c11c12fdf1..4c400a438d4f 100644 --- a/include/uapi/scsi/ufs/ioctl.h +++ b/include/uapi/scsi/ufs/ioctl.h @@ -9,7 +9,11 @@ * SCSI_IOCTL_GET_PCI */ #define UFS_IOCTL_QUERY 0x5388 - +#ifdef OPLUS_FEATURE_UFSPLUS +#if defined(CONFIG_UFSFEATURE) +#define UFSFEATURE_QUERY_OPCODE 0x5500 +#endif +#endif /** * struct ufs_ioctl_query_data - used to transfer data to and from user via * ioctl diff --git a/include/uapi/scsi/ufs/ufs.h b/include/uapi/scsi/ufs/ufs.h index 22a0a7e81860..6d5d5c74d229 100644 --- a/include/uapi/scsi/ufs/ufs.h +++ b/include/uapi/scsi/ufs/ufs.h @@ -20,6 +20,11 @@ enum flag_idn { QUERY_FLAG_IDN_WB_EN = 0x0E, QUERY_FLAG_IDN_WB_BUFF_FLUSH_EN = 0x0F, QUERY_FLAG_IDN_WB_BUFF_FLUSH_DURING_HIBERN8 = 0x10, +#ifdef OPLUS_FEATURE_UFSPLUS +#if defined(CONFIG_UFSHPB) + QUERY_FLAG_IDN_HPB_RESET = 0x11, +#endif +#endif }; /* Attribute idn for Query requests */ @@ -52,6 +57,15 @@ enum attr_idn { QUERY_ATTR_IDN_AVAIL_WB_BUFF_SIZE = 0x1D, QUERY_ATTR_IDN_WB_BUFF_LIFE_TIME_EST = 0x1E, QUERY_ATTR_IDN_CURR_WB_BUFF_SIZE = 0x1F, +#ifdef OPLUS_FEATURE_UFSPLUS +#if defined(CONFIG_UFSFEATURE) + QUERY_ATTR_IDN_SUP_VENDOR_OPTIONS = 0xFF, +#endif +#if defined(CONFIG_UFSHID) + QUERY_ATTR_IDN_HID_OPERATION = 0x20, + QUERY_ATTR_IDN_HID_FRAG_LEVEL = 0x21, +#endif +#endif }; #define QUERY_ATTR_IDN_BOOT_LU_EN_MAX 0x02 diff --git a/init/Kconfig b/init/Kconfig index 0682c5e83688..7609490318d4 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -441,6 +441,13 @@ config SCHED_WALT used to guide task placement as well as task frequency requirements for cpufreq governors. +config SCHED_WALT_COBUCK + bool "Support walt cobuck feature" + depends on SCHED_WALT + help + This feature will allow gold core freq based on the max loading of + prime core and gold core loading. + config HAVE_SCHED_AVG_IRQ def_bool y depends on IRQ_TIME_ACCOUNTING || PARAVIRT_TIME_ACCOUNTING @@ -764,6 +771,13 @@ config UCLAMP_BUCKETS_COUNT If in doubt, use the default value. +#ifdef OPLUS_FEATURE_SCHED_ASSIST +source "kernel/sched_assist/Kconfig" +#endif /* OPLUS_FEATURE_SCHED_ASSIST */ +#ifdef OPLUS_FEATURE_INPUT_BOOST_V4 +source "kernel/tuning/Kconfig" +#endif /* OPLUS_FEATURE_INPUT_BOOST_V4 */ + endmenu # diff --git a/init/main.c b/init/main.c index 492dbafe08c0..e394307d4b22 100644 --- a/init/main.c +++ b/init/main.c @@ -102,6 +102,10 @@ #define CREATE_TRACE_POINTS #include +#ifdef OPLUS_FEATURE_PHOENIX +#include "../drivers/soc/oplus/system/oplus_phoenix/oplus_phoenix.h" +#endif //OPLUS_FEATURE_PHOENIX + static int kernel_init(void *); extern void init_IRQ(void); @@ -610,6 +614,11 @@ asmlinkage __visible void __init start_kernel(void) trap_init(); mm_init(); +#ifdef OPLUS_FEATURE_PHOENIX + if(phx_set_boot_stage) + phx_set_boot_stage(KERNEL_MM_INIT_DONE); +#endif //OPLUS_FEATURE_PHOENIX + ftrace_init(); /* trace_printk can be enabled here */ @@ -681,6 +690,10 @@ asmlinkage __visible void __init start_kernel(void) early_boot_irqs_disabled = false; local_irq_enable(); +#ifdef OPLUS_FEATURE_PHOENIX + if(phx_set_boot_stage) + phx_set_boot_stage(KERNEL_LOCAL_IRQ_ENABLE); +#endif //OPLUS_FEATURE_PHOENIX kmem_cache_init_late(); @@ -755,6 +768,10 @@ asmlinkage __visible void __init start_kernel(void) taskstats_init_early(); delayacct_init(); +#ifdef OPLUS_FEATURE_PHOENIX + if(phx_set_boot_stage) + phx_set_boot_stage(KERNEL_DELAYACCT_INIT_DONE); +#endif //OPLUS_FEATURE_PHOENIX check_bugs(); acpi_subsystem_init(); @@ -1005,10 +1022,18 @@ static void __init do_basic_setup(void) cpuset_init_smp(); shmem_init(); driver_init(); +#ifdef OPLUS_FEATURE_PHOENIX + if(phx_set_boot_stage) + phx_set_boot_stage(KERNEL_DRIVER_INIT_DONE); +#endif //OPLUS_FEATURE_PHOENIX init_irq_proc(); do_ctors(); usermodehelper_enable(); do_initcalls(); +#ifdef OPLUS_FEATURE_PHOENIX + if(phx_set_boot_stage) + phx_set_boot_stage(KERNEL_DO_INITCALLS_DONE); +#endif //OPLUS_FEATURE_PHOENIX } static void __init do_pre_smp_initcalls(void) @@ -1090,6 +1115,10 @@ static inline void mark_readonly(void) } #endif +#if IS_BUILTIN(CONFIG_OPLUS_FEATURE_PHOENIX_REBOOT_SPEED) +extern void bootprof_log_boot(char *str); +#endif + static int __ref kernel_init(void *unused) { int ret; @@ -1113,6 +1142,13 @@ static int __ref kernel_init(void *unused) rcu_end_inkernel_boot(); +#ifdef OPLUS_FEATURE_PHOENIX + if(phx_set_boot_stage) + phx_set_boot_stage(KERNEL_INIT_DONE); +#endif //OPLUS_FEATURE_PHOENIX +#if IS_BUILTIN(CONFIG_OPLUS_FEATURE_PHOENIX_REBOOT_SPEED) + bootprof_log_boot("Kernel_init_done"); +#endif if (ramdisk_execute_command) { ret = run_init_process(ramdisk_execute_command); if (!ret) @@ -1179,6 +1215,10 @@ static noinline void __init kernel_init_freeable(void) do_basic_setup(); +#ifdef OPLUS_FEATURE_PHOENIX + if(phx_set_boot_stage) + phx_set_boot_stage(KERNEL_DO_BASIC_SETUP_DONE); +#endif //OPLUS_FEATURE_PHOENIX /* Open the /dev/console on the rootfs, this should never fail */ if (ksys_open((const char __user *) "/dev/console", O_RDWR, 0) < 0) pr_err("Warning: unable to open an initial console.\n"); diff --git a/kernel/Makefile b/kernel/Makefile index 983edaa82f4f..f27ba53aeb9c 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -12,6 +12,10 @@ obj-y = fork.o exec_domain.o panic.o \ notifier.o ksysfs.o cred.o reboot.o \ async.o range.o smpboot.o ucount.o +#ifdef CONFIG_OPLUS_FEATURE_PANIC_FLUSH +obj-y += panic_flush.o +#endif + obj-$(CONFIG_MODULES) += kmod.o obj-$(CONFIG_MULTIUSER) += groups.o @@ -52,6 +56,12 @@ obj-y += rcu/ obj-y += livepatch/ obj-y += dma/ + +#ifdef CONFIG_OPLUS_SECURE_GUARD +obj-$(CONFIG_OPLUS_SECURE_GUARD) += keventupload/ +#endif /* CONFIG_OPLUS_SECURE_GUARD */ + + obj-$(CONFIG_CHECKPOINT_RESTORE) += kcmp.o obj-$(CONFIG_FREEZER) += freezer.o obj-$(CONFIG_PROFILING) += profile.o @@ -125,6 +135,18 @@ obj-$(CONFIG_HAS_IOMEM) += iomem.o obj-$(CONFIG_ZONE_DEVICE) += memremap.o obj-$(CONFIG_RSEQ) += rseq.o +#ifdef OPLUS_FEATURE_SCHED_ASSIST +obj-y += sched_assist/ +#endif /* OPLUS_FEATURE_SCHED_ASSIST */ + +#ifdef OPLUS_FEATURE_INPUT_BOOST_V4 +obj-$(CONFIG_OPLUS_FEATURE_INPUT_BOOST_V4) += tuning/ +#endif /* OPLUS_FEATURE_INPUT_BOOST_V4 */ + +#ifdef OPLUS_FEATURE_SCHED_ASSIST +obj-y += special_opt/ +#endif /* OPLUS_FEATURE_SCHED_ASSIST */ + $(obj)/configs.o: $(obj)/config_data.h targets += config_data.gz diff --git a/kernel/bounds.c b/kernel/bounds.c index 9795d75b09b2..10dd9e6b03e5 100644 --- a/kernel/bounds.c +++ b/kernel/bounds.c @@ -22,6 +22,13 @@ int main(void) DEFINE(NR_CPUS_BITS, ilog2(CONFIG_NR_CPUS)); #endif DEFINE(SPINLOCK_SIZE, sizeof(spinlock_t)); +#ifdef CONFIG_LRU_GEN + DEFINE(LRU_GEN_WIDTH, order_base_2(MAX_NR_GENS + 1)); + DEFINE(LRU_REFS_WIDTH, MAX_NR_TIERS - 2); +#else + DEFINE(LRU_GEN_WIDTH, 0); + DEFINE(LRU_REFS_WIDTH, 0); +#endif /* End of constants */ return 0; diff --git a/kernel/cgroup/cgroup-internal.h b/kernel/cgroup/cgroup-internal.h index 33258e9a62a5..c741b7404cfc 100644 --- a/kernel/cgroup/cgroup-internal.h +++ b/kernel/cgroup/cgroup-internal.h @@ -144,7 +144,6 @@ struct cgroup_sb_opts { bool none; }; -extern struct mutex cgroup_mutex; extern spinlock_t css_set_lock; extern struct cgroup_subsys *cgroup_subsys[]; extern struct list_head cgroup_roots; diff --git a/kernel/cgroup/cgroup.c b/kernel/cgroup/cgroup.c index ed751199934c..76fd282ab60a 100644 --- a/kernel/cgroup/cgroup.c +++ b/kernel/cgroup/cgroup.c @@ -5134,6 +5134,9 @@ static struct cgroup_subsys_state *css_create(struct cgroup *cgrp, struct cgroup_subsys_state *parent_css = cgroup_css(parent, ss); struct cgroup_subsys_state *css; int err; +#ifdef CONFIG_OPLUS_FEATURE_UID_PERF + static char name[MAX_CGROUP_TYPE_NAMELEN]; +#endif lockdep_assert_held(&cgroup_mutex); @@ -5145,6 +5148,13 @@ static struct cgroup_subsys_state *css_create(struct cgroup *cgrp, init_and_link_css(css, ss, cgrp); +#ifdef CONFIG_OPLUS_FEATURE_UID_PERF + if(ss->id == cpuset_cgrp_id) { + cgroup_name(cgrp, name, MAX_CGROUP_TYPE_NAMELEN); + pr_warn("%s: cgroup=%s cgid=%d cgroup_subsys=%s ssid=%d cpuset_cgrp_id=%d", __func__, name, cgrp->id, ss->name, ss->id, cpuset_cgrp_id); + cpuset_add_cg(cgrp->id, name); + } +#endif err = percpu_ref_init(&css->refcnt, css_release, 0, GFP_KERNEL); if (err) goto err_free_css; diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c index b23f15d4956d..c0edf642c34c 100644 --- a/kernel/cgroup/cpuset.c +++ b/kernel/cgroup/cpuset.c @@ -64,6 +64,12 @@ #include #include +#ifdef CONFIG_OPLUS_FEATURE_UID_PERF +#include +#include +#include "cgroup-internal.h" +#endif + DEFINE_STATIC_KEY_FALSE(cpusets_pre_enable_key); DEFINE_STATIC_KEY_FALSE(cpusets_enabled_key); @@ -1476,6 +1482,306 @@ static int fmeter_getrate(struct fmeter *fmp) return val; } +#ifdef CONFIG_OPLUS_FEATURE_UID_PERF +#define CG_HASH_BITS 3 +#define MAX_BOOL_LEN 2 +static struct proc_dir_entry *cpu_parent; + +static bool dbg_enable; + +DECLARE_HASHTABLE(cg_hash_table, CG_HASH_BITS); +struct cg_entry { + int cgid; + char name[MAX_CGROUP_TYPE_NAMELEN]; + struct hlist_node hash; +}; + +/* + * get the index of the cgroup by cgid + */ +static int get_cpuset_cgrp_idx(int cgid) +{ + struct cg_entry* cg; + unsigned long bkt; + int idx = 0; + + hash_for_each(cg_hash_table, bkt, cg, hash) { + if (cg->cgid == cgid) + goto end; + idx++; + } + idx = -1; +end: + if (dbg_enable) + pr_err("%s: cgrp_id=%d return idx=%d", __func__, cgid, idx); + + return idx; +} + +/* + * get the index of the cgroup by name + */ +int get_cpuset_cgrp_idx_by_name(const char *cg_name) +{ + struct cg_entry* cg; + unsigned long bkt; + int idx = 0; + + hash_for_each(cg_hash_table, bkt, cg, hash) { + if (!strncmp(cg->name, cg_name, strlen(cg_name))) + goto end; + idx++; + } + idx = -1; +end: + if (dbg_enable) + pr_err("%s: cgrp_name=%s return idx=%d", __func__, cg_name, idx); + + return idx; +} + +static int hash_show(struct seq_file *m, void *v) +{ + struct cg_entry* cg; + unsigned long bkt; + int i; + + hash_for_each(cg_hash_table, bkt, cg, hash) { + seq_printf(m, "cgid=\"%d\",name=\"%s\",idx=\"%d\"\n", cg->cgid, cg->name, get_cpuset_cgrp_idx(cg->cgid)); + } + + seq_printf(m, "===========\n"); + + for(i = 2; i < 13; i++) { + seq_printf(m, "cgid = %d, idx = %d\n",i, get_cpuset_cgrp_idx(i)); + } + + return 0; +} + +static int hashdump_open(struct inode *inode, struct file *file) +{ + return single_open(file, hash_show, NULL); +} + +static const struct file_operations hashdump_fops = { + .open = hashdump_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int dbg_show(struct seq_file *m, void *v) +{ + seq_printf(m, "%d\n", dbg_enable); + return 0; +} + +static ssize_t dbg_proc_write(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) +{ + char buffer[MAX_BOOL_LEN]; + int err = 0; + int enable; + + memset(buffer, 0, sizeof(buffer)); + + if (count > sizeof(buffer) - 1) + count = sizeof(buffer) - 1; + + if (copy_from_user((void *)buffer, buf, count)) { + err = -EFAULT; + goto out; + } + err = kstrtoint(strstrip(buffer), 0, &enable); + if (err) + goto out; + + dbg_enable = enable; +out: + return err < 0 ? err : count; +} + +static int dbg_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, dbg_show, NULL); +} + +static const struct file_operations dbg_fops = { + .open = dbg_proc_open, + .write = dbg_proc_write, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +void cpuset_add_cg(int cgid, char* name) +{ + struct cg_entry* cg; + + /* MUSTFIX: cgroup array of task_struct only has 8 buckets */ + if (cgid > UID_GROUP_SIZE + 1) + return; + + cg = kzalloc(sizeof(struct cg_entry), GFP_ATOMIC); + if (!cg) + return; + + cg->cgid = cgid; + strncpy(cg->name, name, MAX_CGROUP_TYPE_NAMELEN); + hash_add(cg_hash_table, &cg->hash, cgid); +} + + +static void cpuset_calc_counter(struct task_struct *task) +{ + u64 enabled, running; + int i, src_idx = -1, dst_idx = -1; + struct css_set *cset; + char cg_src[MAX_CGROUP_TYPE_NAMELEN], cg_dst[MAX_CGROUP_TYPE_NAMELEN]; + u64 val; + + if (!get_uid_perf_enable()) + return; + + rcu_read_lock(); + spin_lock_irq(&css_set_lock); + + cset = task_css_set(task); + if (cset->mg_src_cgrp && cset->mg_dst_cgrp) { + cgroup_name(cset->mg_src_cgrp, cg_src, MAX_CGROUP_TYPE_NAMELEN); + cgroup_name(cset->mg_dst_cgrp, cg_dst, MAX_CGROUP_TYPE_NAMELEN); + if (dbg_enable) + pr_err("%s: src_cg = %s, id = %d, dst_cg = %s, id = %d, task = %s, pid=%d", + __func__, cg_src, cset->mg_src_cgrp->id, cg_dst, cset->mg_dst_cgrp->id, task->comm, task->pid); + + src_idx = get_cpuset_cgrp_idx(cset->mg_src_cgrp->id); + dst_idx = get_cpuset_cgrp_idx(cset->mg_dst_cgrp->id); + + if (src_idx == -1 || dst_idx == -1) { + pr_err("%s: src_cg = %s, id = %d, dst_cg = %s, id = %d, task = %s, pid=%d", + __func__, cg_src, cset->mg_src_cgrp->id, cg_dst, cset->mg_dst_cgrp->id, task->comm, task->pid); + } + + } else { + if (cset->mg_src_cgrp == NULL) + pr_err("%s: mg_src_cgrp is NULL", __func__); + else { + cgroup_name(cset->mg_src_cgrp, cg_src, MAX_CGROUP_TYPE_NAMELEN); + pr_err("%s: mg_src_cgrp is : %s", __func__, cg_src); + } + + if (cset->mg_dst_cgrp == NULL) + pr_err("%s: mg_dst_cgrp is NULL", __func__); + else { + cgroup_name(cset->mg_dst_cgrp, cg_dst, MAX_CGROUP_TYPE_NAMELEN); + pr_err("%s: mg_dst_cgrp is : %s", __func__, cg_dst); + } + } + + spin_unlock_irq(&css_set_lock); + + if (src_idx == -1 || dst_idx == -1) { + pr_err("%s: cannot calc counter", __func__); + rcu_read_unlock(); + return; + } + + if (!(task->flags & PF_EXITING)) { + get_task_struct(task); + rcu_read_unlock(); + + /* MUST FIX: calc the pevent only idx=0 instruction counters */ + for (i = 0; i < 1/*UID_PERF_EVENTS*/; ++i) { + val = 0; + + if (task->uid_pevents[i]) { + u64 tmp = 0; + /* settlement prev cgroup */ + val = perf_event_read_value(task->uid_pevents[i], &enabled, &running); + task->uid_group[src_idx] += (val - task->uid_group_prev_counts[src_idx]); + tmp = task->uid_group_prev_counts[src_idx]; + task->uid_group_prev_counts[src_idx] = 0; + + /* setup dst cgroup prev counters */ + task->uid_group_prev_counts[dst_idx] = val; + if (dbg_enable) + pr_err("%s: pid=%d comm=%s val=%llu uid_group[%d] = %llu uid_group_prev_counts[%d] = %llu uid_group_prev_counts[%d] = %llu", + __func__, task->pid, task->comm, val, + src_idx, task->uid_group[src_idx], + src_idx, tmp, + dst_idx, task->uid_group_prev_counts[dst_idx]); + + } + } + + rcu_read_lock(); + put_task_struct(task); + } + rcu_read_unlock(); +} + +int cpuset_get_cgrp_idx(struct task_struct *task) +{ + int cgrp_id = -1, idx = -1; + struct css_set *cset; + + if (!get_uid_perf_enable()) + return idx; + + rcu_read_lock(); + spin_lock_irq(&css_set_lock); + + cset = task_css_set(task); + if (cset->subsys[cpuset_cgrp_id] && cset->subsys[cpuset_cgrp_id]->cgroup) + cgrp_id = cset->subsys[cpuset_cgrp_id]->cgroup->id; + else + pr_err("%s: cannot get cgrp id", __func__); + + spin_unlock_irq(&css_set_lock); + rcu_read_unlock(); + + if (cgrp_id > 0) + idx = get_cpuset_cgrp_idx(cgrp_id); + + if (idx < 0) + if (dbg_enable) + pr_err("%s: cset->subsys[cpuset_cgrp_id]->cgroup->id = %d, array idx = %d", __func__, cgrp_id, idx); + + return idx; + +} + +int cpuset_get_cgrp_idx_locked(struct task_struct *task) +{ + int cgrp_id = -1, idx = -1; + struct css_set *cset; + + //if (!get_uid_perf_enable()) + // return idx; + + spin_lock_irq(&css_set_lock); + + cset = task_css_set(task); + if (cset->subsys[cpuset_cgrp_id] && cset->subsys[cpuset_cgrp_id]->cgroup) + cgrp_id = cset->subsys[cpuset_cgrp_id]->cgroup->id; + else + pr_err("%s: cannot get cgrp id", __func__); + + spin_unlock_irq(&css_set_lock); + + if (cgrp_id > 0) + idx = get_cpuset_cgrp_idx(cgrp_id); + + if (idx < 0) + if (dbg_enable) + pr_err("%s: cset->subsys->cgroup->id = %d, array idx = %d", __func__, cgrp_id, idx); + + return idx; + +} +#endif + static struct cpuset *cpuset_attach_old_cs; /* Called by cgroups to determine if a cpuset is usable; cpuset_mutex held */ @@ -1502,6 +1808,9 @@ static int cpuset_can_attach(struct cgroup_taskset *tset) ret = task_can_attach(task, cs->cpus_allowed); if (ret) goto out_unlock; +#ifdef CONFIG_OPLUS_FEATURE_UID_PERF + cpuset_calc_counter(task); +#endif ret = security_task_setscheduler(task); if (ret) goto out_unlock; @@ -2185,6 +2494,18 @@ int __init cpuset_init(void) BUG_ON(!alloc_cpumask_var(&cpus_attach, GFP_KERNEL)); +#ifdef CONFIG_OPLUS_FEATURE_UID_PERF + cpu_parent = proc_mkdir("cpuset_info", NULL); + if (!cpu_parent) { + pr_err("%s: failed to create cpuset_info proc entry\n", __func__); + remove_proc_subtree("cpuset_info", NULL); + goto end; + } + proc_create_data("show_hash", 0444, cpu_parent, &hashdump_fops, NULL); + proc_create_data("dbg_enable", 0644, cpu_parent, &dbg_fops, NULL); +end: +#endif + return 0; } diff --git a/kernel/cpu.c b/kernel/cpu.c index cef91ed60605..c0754fd53e12 100644 --- a/kernel/cpu.c +++ b/kernel/cpu.c @@ -41,6 +41,9 @@ #include #include "smpboot.h" +#ifdef OPLUS_FEATURE_SCHED_ASSIST +#include +#endif /** * cpuhp_cpu_state - Per cpu hotplug state storage @@ -1093,6 +1096,9 @@ static int do_cpu_down(unsigned int cpu, enum cpuhp_state target) * domain, those CPUs would not be visible when scheduling * happens on from other CPUs in the root domain. */ +#if defined(OPLUS_FEATURE_SCHED_ASSIST) && defined(CONFIG_OPLUS_FEATURE_SCHED_SPREAD) + init_rq_cpu(cpu); +#endif cpuset_wait_for_hotplug(); cpu_maps_update_begin(); diff --git a/kernel/events/core.c b/kernel/events/core.c index cbbfc9699763..9b23c9b93d4d 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -9041,6 +9041,7 @@ static void perf_addr_filters_splice(struct perf_event *event, * @filter; if so, adjust filter's address range. * Called with mm::mmap_sem down for reading. */ + static void perf_addr_filter_apply(struct perf_addr_filter *filter, struct mm_struct *mm, struct perf_addr_filter_range *fr) diff --git a/kernel/exit.c b/kernel/exit.c index 87b26d8dddd9..874a76e6b259 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -68,6 +68,22 @@ #include #include +#ifdef OPLUS_BUG_STABILITY +#include +#endif +#if defined(OPLUS_FEATURE_VIRTUAL_RESERVE_MEMORY) && defined(CONFIG_VIRTUAL_RESERVE_MEMORY) +//reserved area operations +#include +#endif + +#ifdef CONFIG_OPLUS_FEATURE_TPD +#include +#endif + +#ifdef CONFIG_OPLUS_FEATURE_UID_PERF +extern void uid_check_out_pevent(struct task_struct *task); +#endif + static void __unhash_process(struct task_struct *p, bool group_dead) { nr_threads--; @@ -78,6 +94,9 @@ static void __unhash_process(struct task_struct *p, bool group_dead) detach_pid(p, PIDTYPE_SID); list_del_rcu(&p->tasks); +#if defined(OPLUS_FEATURE_MEMLEAK_DETECT) && defined(CONFIG_ION) && defined(CONFIG_DUMP_TASKS_MEM) + list_del_rcu(&p->user_tasks); +#endif list_del_init(&p->sibling); __this_cpu_dec(process_counts); } @@ -176,6 +195,10 @@ static void delayed_put_task_struct(struct rcu_head *rhp) { struct task_struct *tsk = container_of(rhp, struct task_struct, rcu); +#ifdef CONFIG_OPLUS_FEATURE_TPD + tpd_tglist_del(tsk); +#endif + perf_event_delayed_put(tsk); trace_sched_process_free(tsk); put_task_struct(tsk); @@ -401,6 +424,12 @@ kill_orphaned_pgrp(struct task_struct *tsk, struct task_struct *parent) task_session(parent) == task_session(tsk) && will_become_orphaned_pgrp(pgrp, ignored_task) && has_stopped_jobs(pgrp)) { +#ifdef OPLUS_BUG_STABILITY + if (oplus_is_android_core_group(pgrp)) { + printk("kill_orphaned_pgrp: find android core process will be hungup, ignored it, only hungup itself:%s:%d , current=%d \n",tsk->comm,tsk->pid,current->pid); + return; + } +#endif /*OPLUS_BUG_STABILITY*/ __kill_pgrp_info(SIGHUP, SEND_SIG_PRIV, pgrp); __kill_pgrp_info(SIGCONT, SEND_SIG_PRIV, pgrp); } @@ -489,6 +518,7 @@ assign_new_owner: goto retry; } mm->owner = c; + lru_gen_migrate_mm(mm); task_unlock(c); put_task_struct(c); } @@ -551,6 +581,10 @@ static void exit_mm(void) enter_lazy_tlb(mm, current); task_unlock(current); mm_update_next_owner(mm); +#if defined(OPLUS_FEATURE_VIRTUAL_RESERVE_MEMORY) && defined(CONFIG_OPLUS_HEALTHINFO) && defined(CONFIG_VIRTUAL_RESERVE_MEMORY) + //Trigger and upload the event. + trigger_svm_oom_event(mm, false, false); +#endif mmput(mm); if (test_thread_flag(TIF_MEMDIE)) exit_oom_victim(); @@ -781,12 +815,18 @@ void __noreturn do_exit(long code) struct task_struct *tsk = current; int group_dead; +//#ifdef OPLUS_BUG_STABILITY + if (is_critial_process(tsk)) { + printk("critical svc %d:%s exit with %ld !\n", tsk->pid, tsk->comm,code); + } +//#endif /*OPLUS_BUG_STABILITY*/ + /* - * We can get here from a kernel oops, sometimes with preemption off. - * Start by checking for critical errors. - * Then fix up important state like USER_DS and preemption. - * Then do everything else. - */ + * We can get here from a kernel oops, sometimes with preemption off. + * Start by checking for critical errors. + * Then fix up important state like USER_DS and preemption. + * Then do everything else. + */ WARN_ON(blk_needs_flush_plug(tsk)); @@ -832,6 +872,10 @@ void __noreturn do_exit(long code) exit_signals(tsk); /* sets PF_EXITING */ sched_exit(tsk); +#ifdef CONFIG_OPLUS_FEATURE_UID_PERF + uid_check_out_pevent(tsk); +#endif + /* sync mm's RSS info before statistics gathering */ if (tsk->mm) sync_mm_rss(tsk->mm); diff --git a/kernel/fork.c b/kernel/fork.c index e4e6d424ba48..fcf65082e061 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -107,6 +107,21 @@ #define CREATE_TRACE_POINTS #include +#ifdef OPLUS_FEATURE_SCHED_ASSIST +#include +#endif /* OPLUS_FEATURE_SCHED_ASSIST */ +#ifdef OPLUS_FEATURE_HEALTHINFO +#ifdef CONFIG_OPLUS_JANK_INFO +#include +#endif +#endif /* OPLUS_FEATURE_HEALTHINFO */ +#ifdef CONFIG_OPLUS_FEATURE_IM +#include +#endif + +#ifdef CONFIG_OPLUS_FEATURE_INPUT_BOOST_V4 +#include +#endif /* CONFIG_OPLUS_FEATURE_INPUT_BOOST_V4 */ /* * Minimum number of threads to boot the kernel @@ -118,6 +133,10 @@ */ #define MAX_THREADS FUTEX_TID_MASK +#if defined(OPLUS_FEATURE_MEMLEAK_DETECT) && defined(CONFIG_ION) && defined(CONFIG_DUMP_TASKS_MEM) +/* update user tasklist */ +extern void update_user_tasklist(struct task_struct *tsk); +#endif /* * Protected counters by write_lock_irq(&tasklist_lock) */ @@ -169,6 +188,10 @@ static inline void free_task_struct(struct task_struct *tsk) #ifndef CONFIG_ARCH_THREAD_STACK_ALLOCATOR +#ifdef CONFIG_OPLUS_FEATURE_UID_PERF +extern void uid_perf_work_add(struct task_struct *task, bool force); +#endif + /* * Allocate pages if THREAD_SIZE is >= PAGE_SIZE, otherwise use a * kmemcache based allocator. @@ -571,6 +594,7 @@ static __latent_entropy int dup_mmap(struct mm_struct *mm, if (retval) goto out; } + /* a new mm has just been created */ retval = arch_dup_mmap(oldmm, mm); out: @@ -926,6 +950,13 @@ static struct task_struct *dup_task_struct(struct task_struct *orig, int node) #ifdef CONFIG_MEMCG tsk->active_memcg = NULL; #endif + +#ifdef CONFIG_OPLUS_FEATURE_TPD + tsk->tpd = 0; + tsk->dtpd = 0; + tsk->dtpdg = -1; + tsk->tpd_st = 0; /* for system thread affinity */ +#endif return tsk; free_stack: @@ -988,6 +1019,11 @@ static struct mm_struct *mm_init(struct mm_struct *mm, struct task_struct *p, mm->mmap = NULL; mm->mm_rb = RB_ROOT; mm->vmacache_seqnum = 0; +#if defined(OPLUS_FEATURE_VIRTUAL_RESERVE_MEMORY) && defined(CONFIG_VIRTUAL_RESERVE_MEMORY) + mm->va_feature = 0; + mm->va_feature_rnd = 0; + mm->zygoteheap_in_MB = 0; +#endif #ifdef CONFIG_SPECULATIVE_PAGE_FAULT rwlock_init(&mm->mm_rb_lock); #endif @@ -1031,6 +1067,7 @@ static struct mm_struct *mm_init(struct mm_struct *mm, struct task_struct *p, goto fail_nocontext; mm->user_ns = get_user_ns(user_ns); + lru_gen_init_mm(mm); return mm; fail_nocontext: @@ -1073,6 +1110,7 @@ static inline void __mmput(struct mm_struct *mm) } if (mm->binfmt) module_put(mm->binfmt->module); + lru_gen_del_mm(mm); mmdrop(mm); } @@ -2029,6 +2067,25 @@ static __latent_entropy struct task_struct *copy_process( p->sequential_io_avg = 0; #endif +#ifdef OPLUS_FEATURE_SCHED_ASSIST + init_task_ux_info(p); +#endif /* OPLUS_FEATURE_SCHED_ASSIST */ +#ifdef OPLUS_FEATURE_HEALTHINFO +#ifdef CONFIG_OPLUS_JANK_INFO + p->jank_trace = 0; + memset(&p->jank_info, 0, sizeof(struct jank_monitor_info)); +#endif +#endif /* OPLUS_FEATURE_HEALTHINFO */ + +#if defined(OPLUS_FEATURE_TASK_CPUSTATS) && defined(CONFIG_OPLUS_SCHED) + p->wake_tid = 0; + p->running_start_time = 0; +#endif /* defined(OPLUS_FEATURE_TASK_CPUSTATS) && defined(CONFIG_OPLUS_SCHED) */ + +#ifdef CONFIG_OPLUS_FEATURE_INPUT_BOOST_V4 + init_task_frame(p); +#endif + /* Perform scheduler related setup. Assign this task to a CPU. */ retval = sched_fork(clone_flags, p); if (retval) @@ -2204,6 +2261,17 @@ static __latent_entropy struct task_struct *copy_process( } +#ifdef CONFIG_OPLUS_FEATURE_UID_PERF + /* should init uid pevents before task added into any link */ + memset(p->uid_pevents, 0, sizeof(struct perf_event *) * UID_PERF_EVENTS); + memset(p->uid_counts, 0, sizeof(long long) * UID_PERF_EVENTS); + memset(p->uid_prev_counts, 0, sizeof(long long) * UID_PERF_EVENTS); + memset(p->uid_leaving_counts, 0, sizeof(long long) * UID_PERF_EVENTS); + memset(p->uid_group, 0, sizeof(long long) * UID_GROUP_SIZE); + memset(p->uid_group_prev_counts, 0, sizeof(long long) * UID_GROUP_SIZE); + memset(p->uid_group_snapshot_prev_counts, 0, sizeof(long long) * UID_GROUP_SIZE); +#endif + init_task_pid_links(p); if (likely(p->pid)) { ptrace_init_task(p, (clone_flags & CLONE_PTRACE) || trace); @@ -2229,6 +2297,11 @@ static __latent_entropy struct task_struct *copy_process( p->real_parent->signal->is_child_subreaper; list_add_tail(&p->sibling, &p->real_parent->children); list_add_tail_rcu(&p->tasks, &init_task.tasks); +#if defined(OPLUS_FEATURE_MEMLEAK_DETECT) && defined(CONFIG_ION) && defined(CONFIG_DUMP_TASKS_MEM) + /* init user tasklist */ + INIT_LIST_HEAD(&p->user_tasks); + update_user_tasklist(p); +#endif attach_pid(p, PIDTYPE_TGID); attach_pid(p, PIDTYPE_PGID); attach_pid(p, PIDTYPE_SID); @@ -2259,9 +2332,17 @@ static __latent_entropy struct task_struct *copy_process( trace_task_newtask(p, clone_flags); uprobe_copy_process(p, clone_flags); - copy_oom_score_adj(clone_flags, p); + if (!IS_ERR(p)) { +#ifdef CONFIG_OPLUS_FEATURE_IM + im_tsk_init_flag((void *) p); +#endif + } +#ifdef CONFIG_OPLUS_FEATURE_UID_PERF + if (!IS_ERR(p)) + uid_perf_work_add(p, false); +#endif return p; bad_fork_cancel_cgroup: @@ -2404,6 +2485,10 @@ long _do_fork(unsigned long clone_flags, pid = get_task_pid(p, PIDTYPE_PID); nr = pid_vnr(pid); +#if defined(OPLUS_FEATURE_MEMLEAK_DETECT) && defined(CONFIG_ION) && defined(CONFIG_DUMP_TASKS_MEM) + //accounts process-real-phymem + atomic64_set(&p->ions, 0); +#endif if (clone_flags & CLONE_PARENT_SETTID) put_user(nr, parent_tidptr); @@ -2412,6 +2497,13 @@ long _do_fork(unsigned long clone_flags, p->vfork_done = &vfork; init_completion(&vfork); get_task_struct(p); + + if (IS_ENABLED(CONFIG_LRU_GEN) && !(clone_flags & CLONE_VM)) { + /* lock the task to synchronize with memcg migration */ + task_lock(p); + lru_gen_add_mm(p->mm); + task_unlock(p); + } } wake_up_new_task(p); diff --git a/kernel/futex.c b/kernel/futex.c index 3c67da9b8408..4802e4d675d0 100644 --- a/kernel/futex.c +++ b/kernel/futex.c @@ -72,6 +72,9 @@ #include #include "locking/rtmutex_common.h" +#if IS_ENABLED(CONFIG_OPLUS_FEATURE_CPU_JANKINFO) +#include +#endif /* * READ this before attempting to hack on futexes! @@ -1697,6 +1700,7 @@ futex_wake(u32 __user *uaddr, unsigned int flags, int nr_wake, u32 bitset) continue; mark_wake_futex(&wake_q, this); + if (++ret >= nr_wake) break; } @@ -2718,8 +2722,22 @@ static void futex_wait_queue_me(struct futex_hash_bucket *hb, struct futex_q *q, * flagged for rescheduling. Only call schedule if there * is no timeout, or if it has yet to expire. */ - if (!timeout || timeout->task) + if (!timeout || timeout->task) { +#if IS_ENABLED(CONFIG_OPLUS_FEATURE_CPU_JANKINFO) + android_vh_futex_sleep_start_handelr(NULL, current); +#endif +#ifdef OPLUS_FEATURE_HEALTHINFO +#ifdef CONFIG_OPLUS_JANK_INFO + current->in_futex = 1; +#endif +#endif /* OPLUS_FEATURE_HEALTHINFO */ freezable_schedule(); +#ifdef OPLUS_FEATURE_HEALTHINFO +#ifdef CONFIG_OPLUS_JANK_INFO + current->in_futex = 0; +#endif +#endif /* OPLUS_FEATURE_HEALTHINFO */ + } } __set_current_state(TASK_RUNNING); } @@ -3886,7 +3904,7 @@ long do_futex(u32 __user *uaddr, int op, u32 val, ktime_t *timeout, val3 = FUTEX_BITSET_MATCH_ANY; /* fall through */ case FUTEX_WAIT_BITSET: - return futex_wait(uaddr, flags, val, timeout, val3); + return futex_wait(uaddr, flags, val, timeout, val3); case FUTEX_WAKE: val3 = FUTEX_BITSET_MATCH_ANY; /* fall through */ diff --git a/kernel/hung_task.c b/kernel/hung_task.c index 11f10e0169d0..c2b7c044ce7e 100644 --- a/kernel/hung_task.c +++ b/kernel/hung_task.c @@ -23,6 +23,10 @@ #include #include +#ifdef CONFIG_OPLUS_FEATURE_HUNG_TASK_ENHANCE +#include +#endif + /* * The number of tasks checked: */ @@ -92,6 +96,7 @@ static struct notifier_block panic_block = { .notifier_call = hung_task_panic, }; +#ifndef CONFIG_OPLUS_FEATURE_HUNG_TASK_ENHANCE static void check_hung_task(struct task_struct *t, unsigned long timeout) { unsigned long switch_count = t->nvcsw + t->nivcsw; @@ -148,6 +153,7 @@ static void check_hung_task(struct task_struct *t, unsigned long timeout) touch_nmi_watchdog(); } +#endif /* * To avoid extending the RCU grace period for an unbounded amount of time, @@ -183,6 +189,10 @@ static void check_hung_uninterruptible_tasks(unsigned long timeout) unsigned long last_break = jiffies; struct task_struct *g, *t; +#if defined(CONFIG_OPLUS_FEATURE_HUNG_TASK_ENHANCE) && defined(CONFIG_OPLUS_FEATURE_DEATH_HEALER) + unsigned int iowait_count = 0; +#endif + /* * If the system crashed already then all bets are off, * do not report extra hung tasks: @@ -200,14 +210,21 @@ static void check_hung_uninterruptible_tasks(unsigned long timeout) goto unlock; last_break = jiffies; } +#if defined(CONFIG_OPLUS_FEATURE_HUNG_TASK_ENHANCE) && defined(CONFIG_OPLUS_FEATURE_DEATH_HEALER) + io_check_hung_detection(t, timeout, &iowait_count, &hung_task_show_lock, &hung_task_call_panic); +#else /* use "==" to skip the TASK_KILLABLE tasks waiting on NFS */ if (t->state == TASK_UNINTERRUPTIBLE) /* Check for selective monitoring */ if (!sysctl_hung_task_selective_monitoring || t->hang_detection_enabled) check_hung_task(t, timeout); +#endif } unlock: +#if defined(CONFIG_OPLUS_FEATURE_HUNG_TASK_ENHANCE) && defined(CONFIG_OPLUS_FEATURE_DEATH_HEALER) + io_block_panic(&iowait_count, sysctl_hung_task_maxiowait_count); +#endif rcu_read_unlock(); if (hung_task_show_lock) debug_show_all_locks(); diff --git a/kernel/irq/cpuhotplug.c b/kernel/irq/cpuhotplug.c index b19a65999bb3..9f06f4bee685 100644 --- a/kernel/irq/cpuhotplug.c +++ b/kernel/irq/cpuhotplug.c @@ -15,6 +15,7 @@ #include #include "internals.h" +#include /* For !GENERIC_IRQ_EFFECTIVE_AFF_MASK this looks at general affinity mask */ static inline bool irq_needs_fixup(struct irq_data *d) @@ -199,7 +200,11 @@ void irq_migrate_all_off_this_cpu(void) affinity_broken = migrate_one_irq(desc); raw_spin_unlock(&desc->lock); +#ifdef VENDOR_EDIT + if (affinity_broken && (get_eng_version() == AGING || oplus_daily_build())) { +#else if (affinity_broken) { +#endif pr_info_ratelimited("IRQ %u: no longer affine to CPU%u\n", irq, smp_processor_id()); } diff --git a/kernel/irq/internals.h b/kernel/irq/internals.h index 10eccbc84686..aa20bd031912 100644 --- a/kernel/irq/internals.h +++ b/kernel/irq/internals.h @@ -62,6 +62,7 @@ enum { IRQS_PENDING = 0x00000200, IRQS_SUSPENDED = 0x00000800, IRQS_TIMINGS = 0x00001000, + IRQS_NMI = 0x00002000, }; #include "debug.h" diff --git a/kernel/keventupload b/kernel/keventupload new file mode 120000 index 000000000000..205c9943ea0c --- /dev/null +++ b/kernel/keventupload @@ -0,0 +1 @@ +../../../vendor/oplus/kernel/secureguard/keventupload \ No newline at end of file diff --git a/kernel/locking/mutex.c b/kernel/locking/mutex.c index c457d77c86a5..302ce6b6b992 100644 --- a/kernel/locking/mutex.c +++ b/kernel/locking/mutex.c @@ -36,6 +36,10 @@ # include "mutex.h" #endif +#ifdef CONFIG_OPLUS_FEATURE_HUNG_TASK_ENHANCE +#include +#endif + void __mutex_init(struct mutex *lock, const char *name, struct lock_class_key *key) { @@ -45,7 +49,9 @@ __mutex_init(struct mutex *lock, const char *name, struct lock_class_key *key) #ifdef CONFIG_MUTEX_SPIN_ON_OWNER osq_lock_init(&lock->osq); #endif - +#ifdef OPLUS_FEATURE_SCHED_ASSIST + lock->ux_dep_task = NULL; +#endif /* OPLUS_FEATURE_SCHED_ASSIST */ debug_mutex_init(lock, name, key); } EXPORT_SYMBOL(__mutex_init); @@ -184,7 +190,16 @@ __mutex_add_waiter(struct mutex *lock, struct mutex_waiter *waiter, { debug_mutex_add_waiter(lock, waiter, current); +#ifndef OPLUS_FEATURE_SCHED_ASSIST list_add_tail(&waiter->list, list); +#else /* OPLUS_FEATURE_SCHED_ASSIST */ + if (sysctl_sched_assist_enabled) { + mutex_list_add(current, &waiter->list, list, lock); + } else { + list_add_tail(&waiter->list, list); + } +#endif /* OPLUS_FEATURE_SCHED_ASSIST */ + if (__mutex_waiter_is_first(lock, waiter)) __mutex_set_flag(lock, MUTEX_FLAG_WAITERS); } @@ -1013,7 +1028,12 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass, * wait_lock. This ensures the lock cancellation is ordered * against mutex_unlock() and wake-ups do not go missing. */ +#ifdef CONFIG_OPLUS_FEATURE_HUNG_TASK_ENHANCE + if (unlikely(signal_pending_state(state, current)) + || hung_long_and_fatal_signal_pending(current)) { +#else if (unlikely(signal_pending_state(state, current))) { +#endif ret = -EINTR; goto err; } @@ -1023,9 +1043,27 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass, if (ret) goto err; } - +#ifdef OPLUS_FEATURE_SCHED_ASSIST + if (sysctl_sched_assist_enabled) { + mutex_set_inherit_ux(lock, current); + } +#endif /* OPLUS_FEATURE_SCHED_ASSIST */ spin_unlock(&lock->wait_lock); +#ifdef OPLUS_FEATURE_HEALTHINFO +#ifdef CONFIG_OPLUS_JANK_INFO + if (state & TASK_UNINTERRUPTIBLE) { + current->in_mutex = 1; + } +#endif +#endif /* OPLUS_FEATURE_HEALTHINFO */ schedule_preempt_disabled(); +#ifdef OPLUS_FEATURE_HEALTHINFO +#ifdef CONFIG_OPLUS_JANK_INFO + if (state & TASK_UNINTERRUPTIBLE) { + current->in_mutex = 0; + } +#endif +#endif /* OPLUS_FEATURE_HEALTHINFO */ first = __mutex_waiter_is_first(lock, &waiter); if (first) @@ -1247,6 +1285,11 @@ static noinline void __sched __mutex_unlock_slowpath(struct mutex *lock, unsigne spin_lock(&lock->wait_lock); debug_mutex_unlock(lock); +#ifdef OPLUS_FEATURE_SCHED_ASSIST + if (sysctl_sched_assist_enabled) { + mutex_unset_inherit_ux(lock, current); + } +#endif /* OPLUS_FEATURE_SCHED_ASSIST */ if (!list_empty(&lock->wait_list)) { /* get the first entry from the wait-list: */ struct mutex_waiter *waiter = diff --git a/kernel/locking/rwsem-xadd.c b/kernel/locking/rwsem-xadd.c index ddc9cbd7700b..ccef4421c877 100644 --- a/kernel/locking/rwsem-xadd.c +++ b/kernel/locking/rwsem-xadd.c @@ -21,6 +21,13 @@ #include "rwsem.h" +#ifdef OPLUS_FEATURE_SCHED_ASSIST +//#ifdef CONFIG_UXCHAIN_V2 +#include +#include +#include +extern u64 sysctl_mmapsem_uninterruptable_time; +#endif /* * Guide to the rw_semaphore's count field for common values. * (32-bit case illustrated, similar for 64-bit) @@ -93,6 +100,9 @@ void __init_rwsem(struct rw_semaphore *sem, const char *name, #ifdef CONFIG_RWSEM_PRIO_AWARE sem->m_count = 0; #endif +#ifdef OPLUS_FEATURE_SCHED_ASSIST + sem->ux_dep_task = NULL; +#endif /* OPLUS_FEATURE_SCHED_ASSIST */ } EXPORT_SYMBOL(__init_rwsem); @@ -132,6 +142,10 @@ static void __rwsem_mark_wake(struct rw_semaphore *sem, if (waiter->type == RWSEM_WAITING_FOR_WRITE) { if (wake_type == RWSEM_WAKE_ANY) { +#ifdef OPLUS_FEATURE_SCHED_ASSIST +//#ifdef CONFIG_UXCHAIN_V2 + uxchain_rwsem_wake(waiter->task, sem); +#endif /* * Mark writer at the front of the queue for wakeup. * Until the task is actually later awoken later by @@ -224,6 +238,10 @@ static void __rwsem_mark_wake(struct rw_semaphore *sem, * to the task to wakeup. */ smp_store_release(&waiter->task, NULL); +#ifdef OPLUS_FEATURE_SCHED_ASSIST +//#ifdef CONFIG_UXCHAIN_V2 + uxchain_rwsem_wake(tsk, sem); +#endif /* * Ensure issuing the wakeup (either by us or someone else) * after setting the reader waiter to nil. @@ -244,6 +262,11 @@ __rwsem_down_read_failed_common(struct rw_semaphore *sem, int state) struct rwsem_waiter waiter; DEFINE_WAKE_Q(wake_q); bool is_first_waiter = false; +#ifdef OPLUS_FEATURE_SCHED_ASSIST +//#ifdef CONFIG_UXCHAIN_V2 + int mem_sem_flag = 0; + u64 sleep_begin, sleep_end; +#endif waiter.task = current; waiter.type = RWSEM_WAITING_FOR_READ; @@ -270,11 +293,24 @@ __rwsem_down_read_failed_common(struct rw_semaphore *sem, int state) is_first_waiter))) __rwsem_mark_wake(sem, RWSEM_WAKE_ANY, &wake_q); +#ifdef OPLUS_FEATURE_SCHED_ASSIST + if (sysctl_sched_assist_enabled) { + rwsem_set_inherit_ux(current, waiter.task, READ_ONCE(sem->owner), sem); + } +#endif /* OPLUS_FEATURE_SCHED_ASSIST */ + raw_spin_unlock_irq(&sem->wait_lock); wake_up_q(&wake_q); /* wait to be given the lock */ while (true) { +#ifdef OPLUS_FEATURE_SCHED_ASSIST +//#ifdef CONFIG_UXCHAIN_V2 + if (current->mm && sem == &(current->mm->mmap_sem)) { + mem_sem_flag = 1; + sleep_begin = sched_clock(); + } +#endif set_current_state(state); if (!waiter.task) break; @@ -285,10 +321,28 @@ __rwsem_down_read_failed_common(struct rw_semaphore *sem, int state) raw_spin_unlock_irq(&sem->wait_lock); break; } +#ifdef OPLUS_FEATURE_HEALTHINFO +#ifdef CONFIG_OPLUS_JANK_INFO + current->in_downread = 1; +#endif +#endif /* OPLUS_FEATURE_HEALTHINFO */ schedule(); +#ifdef OPLUS_FEATURE_HEALTHINFO +#ifdef CONFIG_OPLUS_JANK_INFO + current->in_downread = 0; +#endif +#endif /* OPLUS_FEATURE_HEALTHINFO */ } __set_current_state(TASK_RUNNING); +#ifdef OPLUS_FEATURE_SCHED_ASSIST +//#ifdef CONFIG_UXCHAIN_V2 + if (mem_sem_flag) { + sleep_end = sched_clock(); + sysctl_mmapsem_uninterruptable_time += + (sleep_end - sleep_begin) >> 20; + } +#endif return sem; out_nolock: list_del(&waiter.list); @@ -519,6 +573,11 @@ __rwsem_down_write_failed_common(struct rw_semaphore *sem, int state) struct rw_semaphore *ret = sem; DEFINE_WAKE_Q(wake_q); bool is_first_waiter = false; +#ifdef OPLUS_FEATURE_SCHED_ASSIST +//#ifdef CONFIG_UXCHAIN_V2 + int mem_sem_flag = 0; + u64 sleep_begin, sleep_end; +#endif /* undo write bias from down_write operation, stop active locking */ count = atomic_long_sub_return(RWSEM_ACTIVE_WRITE_BIAS, &sem->count); @@ -575,6 +634,19 @@ __rwsem_down_write_failed_common(struct rw_semaphore *sem, int state) } else count = atomic_long_add_return(RWSEM_WAITING_BIAS, &sem->count); +#ifdef OPLUS_FEATURE_SCHED_ASSIST + if (sysctl_sched_assist_enabled) { + rwsem_set_inherit_ux(waiter.task, current, READ_ONCE(sem->owner), sem); + } +#endif /* OPLUS_FEATURE_SCHED_ASSIST */ + +#ifdef OPLUS_FEATURE_SCHED_ASSIST +//#ifdef CONFIG_UXCHAIN_V2 + if (current->mm && sem == &(current->mm->mmap_sem)) { + mem_sem_flag = 1; + sleep_begin = sched_clock(); + } +#endif /* wait until we successfully acquire the lock */ set_current_state(state); while (true) { @@ -586,8 +658,17 @@ __rwsem_down_write_failed_common(struct rw_semaphore *sem, int state) do { if (signal_pending_state(state, current)) goto out_nolock; - +#ifdef OPLUS_FEATURE_HEALTHINFO +#ifdef CONFIG_OPLUS_JANK_INFO + current->in_downwrite = 1; +#endif +#endif /* OPLUS_FEATURE_HEALTHINFO */ schedule(); +#ifdef OPLUS_FEATURE_HEALTHINFO +#ifdef CONFIG_OPLUS_JANK_INFO + current->in_downwrite = 0; +#endif +#endif /* OPLUS_FEATURE_HEALTHINFO */ set_current_state(state); } while ((count = atomic_long_read(&sem->count)) & RWSEM_ACTIVE_MASK); @@ -596,6 +677,14 @@ __rwsem_down_write_failed_common(struct rw_semaphore *sem, int state) __set_current_state(TASK_RUNNING); list_del(&waiter.list); raw_spin_unlock_irq(&sem->wait_lock); +#ifdef OPLUS_FEATURE_SCHED_ASSIST +//#ifdef CONFIG_UXCHAIN_V2 + if (mem_sem_flag) { + sleep_end = sched_clock(); + sysctl_mmapsem_uninterruptable_time += + (sleep_end - sleep_begin) >> 20; + } +#endif return ret; @@ -700,6 +789,12 @@ locked: if (!list_empty(&sem->wait_list)) __rwsem_mark_wake(sem, RWSEM_WAKE_ANY, &wake_q); +#ifdef OPLUS_FEATURE_SCHED_ASSIST + if (sysctl_sched_assist_enabled) { + rwsem_unset_inherit_ux(sem, current); + } +#endif /* OPLUS_FEATURE_SCHED_ASSIST */ + raw_spin_unlock_irqrestore(&sem->wait_lock, flags); wake_up_q(&wake_q); diff --git a/kernel/locking/rwsem.c b/kernel/locking/rwsem.c index 776308d2fa9e..1e336da5494e 100644 --- a/kernel/locking/rwsem.c +++ b/kernel/locking/rwsem.c @@ -15,6 +15,14 @@ #include "rwsem.h" +#ifdef OPLUS_FEATURE_SCHED_ASSIST +//#ifdef CONFIG_UXCHAIN_V2 +#include +#include +#include <../sched/sched.h> +#include +#endif + /* * lock for reading */ @@ -25,6 +33,10 @@ void __sched down_read(struct rw_semaphore *sem) LOCK_CONTENDED(sem, __down_read_trylock, __down_read); rwsem_set_reader_owned(sem); +#ifdef OPLUS_FEATURE_SCHED_ASSIST +//#ifdef CONFIG_UXCHAIN_V2 + uxchain_rwsem_down(sem); +#endif } EXPORT_SYMBOL(down_read); @@ -40,6 +52,11 @@ int __sched down_read_killable(struct rw_semaphore *sem) } rwsem_set_reader_owned(sem); +#ifdef OPLUS_FEATURE_SCHED_ASSIST +//#ifdef CONFIG_UXCHAIN_V2 + uxchain_rwsem_down(sem); +#endif + return 0; } @@ -55,6 +72,10 @@ int down_read_trylock(struct rw_semaphore *sem) if (ret == 1) { rwsem_acquire_read(&sem->dep_map, 0, 1, _RET_IP_); rwsem_set_reader_owned(sem); +#ifdef OPLUS_FEATURE_SCHED_ASSIST +//#ifdef CONFIG_UXCHAIN_V2 + uxchain_rwsem_down(sem); +#endif } return ret; } @@ -71,6 +92,10 @@ void __sched down_write(struct rw_semaphore *sem) LOCK_CONTENDED(sem, __down_write_trylock, __down_write); rwsem_set_owner(sem); +#ifdef OPLUS_FEATURE_SCHED_ASSIST +//#ifdef CONFIG_UXCHAIN_V2 + uxchain_rwsem_down(sem); +#endif } EXPORT_SYMBOL(down_write); @@ -89,6 +114,10 @@ int __sched down_write_killable(struct rw_semaphore *sem) } rwsem_set_owner(sem); +#ifdef OPLUS_FEATURE_SCHED_ASSIST +//#ifdef CONFIG_UXCHAIN_V2 + uxchain_rwsem_down(sem); +#endif return 0; } @@ -104,6 +133,10 @@ int down_write_trylock(struct rw_semaphore *sem) if (ret == 1) { rwsem_acquire(&sem->dep_map, 0, 1, _RET_IP_); rwsem_set_owner(sem); +#ifdef OPLUS_FEATURE_SCHED_ASSIST +//#ifdef CONFIG_UXCHAIN_V2 + uxchain_rwsem_down(sem); +#endif } return ret; @@ -120,6 +153,10 @@ void up_read(struct rw_semaphore *sem) DEBUG_RWSEMS_WARN_ON(sem->owner != RWSEM_READER_OWNED); __up_read(sem); +#ifdef OPLUS_FEATURE_SCHED_ASSIST +//#ifdef CONFIG_UXCHAIN_V2 + uxchain_rwsem_up(sem); +#endif } EXPORT_SYMBOL(up_read); @@ -134,6 +171,10 @@ void up_write(struct rw_semaphore *sem) rwsem_clear_owner(sem); __up_write(sem); +#ifdef OPLUS_FEATURE_SCHED_ASSIST +//#ifdef CONFIG_UXCHAIN_V2 + uxchain_rwsem_up(sem); +#endif } EXPORT_SYMBOL(up_write); @@ -161,6 +202,10 @@ void down_read_nested(struct rw_semaphore *sem, int subclass) LOCK_CONTENDED(sem, __down_read_trylock, __down_read); rwsem_set_reader_owned(sem); +#ifdef OPLUS_FEATURE_SCHED_ASSIST +//#ifdef CONFIG_UXCHAIN_V2 + uxchain_rwsem_down(sem); +#endif } EXPORT_SYMBOL(down_read_nested); @@ -172,6 +217,10 @@ void _down_write_nest_lock(struct rw_semaphore *sem, struct lockdep_map *nest) LOCK_CONTENDED(sem, __down_write_trylock, __down_write); rwsem_set_owner(sem); +#ifdef OPLUS_FEATURE_SCHED_ASSIST +//#ifdef CONFIG_UXCHAIN_V2 + uxchain_rwsem_down(sem); +#endif } EXPORT_SYMBOL(_down_write_nest_lock); @@ -182,6 +231,10 @@ void down_read_non_owner(struct rw_semaphore *sem) __down_read(sem); rwsem_set_reader_owned(sem); +#ifdef OPLUS_FEATURE_SCHED_ASSIST +//#ifdef CONFIG_UXCHAIN_V2 + uxchain_rwsem_down(sem); +#endif } EXPORT_SYMBOL(down_read_non_owner); @@ -193,6 +246,10 @@ void down_write_nested(struct rw_semaphore *sem, int subclass) LOCK_CONTENDED(sem, __down_write_trylock, __down_write); rwsem_set_owner(sem); +#ifdef OPLUS_FEATURE_SCHED_ASSIST +//#ifdef CONFIG_UXCHAIN_V2 + uxchain_rwsem_down(sem); +#endif } EXPORT_SYMBOL(down_write_nested); @@ -208,6 +265,10 @@ int __sched down_write_killable_nested(struct rw_semaphore *sem, int subclass) } rwsem_set_owner(sem); +#ifdef OPLUS_FEATURE_SCHED_ASSIST +//#ifdef CONFIG_UXCHAIN_V2 + uxchain_rwsem_down(sem); +#endif return 0; } @@ -217,6 +278,10 @@ void up_read_non_owner(struct rw_semaphore *sem) { DEBUG_RWSEMS_WARN_ON(sem->owner != RWSEM_READER_OWNED); __up_read(sem); +#ifdef OPLUS_FEATURE_SCHED_ASSIST +//#ifdef CONFIG_UXCHAIN_V2 + uxchain_rwsem_up(sem); +#endif } EXPORT_SYMBOL(up_read_non_owner); diff --git a/kernel/locking/rwsem.h b/kernel/locking/rwsem.h index ae2fb1924128..c27ee6a6c128 100644 --- a/kernel/locking/rwsem.h +++ b/kernel/locking/rwsem.h @@ -101,6 +101,9 @@ static inline void rwsem_set_reader_owned(struct rw_semaphore *sem) #define RWSEM_MAX_PREEMPT_ALLOWED 3000 +#ifdef OPLUS_FEATURE_SCHED_ASSIST +extern bool test_task_ux(struct task_struct *task); +#endif /* OPLUS_FEATURE_SCHED_ASSIST */ /* * Return true if current waiter is added in the front of the rwsem wait list. */ @@ -128,11 +131,25 @@ static inline bool rwsem_list_add_per_prio(struct rwsem_waiter *waiter_in, return true; } +#ifdef OPLUS_FEATURE_SCHED_ASSIST + if (sysctl_sched_assist_enabled) { + if (rwsem_list_add(waiter_in->task, &waiter_in->list, &sem->wait_list, sem)) { + return &waiter_in->list == head->next; + } + } +#endif /* OPLUS_FEATURE_SCHED_ASSIST */ + if (waiter_in->task->prio < DEFAULT_PRIO && sem->m_count < RWSEM_MAX_PREEMPT_ALLOWED) { list_for_each(pos, head) { waiter = list_entry(pos, struct rwsem_waiter, list); +#ifdef OPLUS_FEATURE_SCHED_ASSIST + if (sysctl_sched_assist_enabled && waiter_in->task->prio > MAX_RT_PRIO && + test_task_ux(waiter->task)) { + continue; + } +#endif /* OPLUS_FEATURE_SCHED_ASSIST */ if (waiter->task->prio > waiter_in->task->prio) { list_add(&waiter_in->list, pos->prev); sem->m_count++; diff --git a/kernel/locking/semaphore.c b/kernel/locking/semaphore.c index 561acdd39960..08bed12114df 100644 --- a/kernel/locking/semaphore.c +++ b/kernel/locking/semaphore.c @@ -34,6 +34,10 @@ #include #include +#ifdef CONFIG_OPLUS_FEATURE_HUNG_TASK_ENHANCE +#include +#endif + static noinline void __down(struct semaphore *sem); static noinline int __down_interruptible(struct semaphore *sem); static noinline int __down_killable(struct semaphore *sem); @@ -212,7 +216,11 @@ static inline int __sched __down_common(struct semaphore *sem, long state, waiter.up = false; for (;;) { +#ifdef CONFIG_OPLUS_FEATURE_HUNG_TASK_ENHANCE + if (signal_pending_state(state, current) || hung_long_and_fatal_signal_pending(current)) +#else if (signal_pending_state(state, current)) +#endif goto interrupted; if (unlikely(timeout <= 0)) goto timed_out; diff --git a/kernel/memremap.c b/kernel/memremap.c index 331baad8efec..0376ebb3a53f 100644 --- a/kernel/memremap.c +++ b/kernel/memremap.c @@ -392,8 +392,6 @@ void __put_devmap_managed_page(struct page *page) * holds a reference on the page. */ if (count == 1) { - /* Clear Active bit in case of parallel mark_page_accessed */ - __ClearPageActive(page); __ClearPageWaiters(page); mem_cgroup_uncharge(page); diff --git a/kernel/panic.c b/kernel/panic.c index 289f76e85db3..c9dff9220ac3 100644 --- a/kernel/panic.c +++ b/kernel/panic.c @@ -31,6 +31,9 @@ #include #include #include +#ifdef OPLUS_FEATURE_AGINGTEST +#include +#endif /*OPLUS_FEATURE_AGINGTEST*/ #define PANIC_TIMER_STEP 100 #define PANIC_BLINK_SPD 18 @@ -128,6 +131,10 @@ void nmi_panic(struct pt_regs *regs, const char *msg) } EXPORT_SYMBOL(nmi_panic); +#ifdef CONFIG_OPLUS_FEATURE_PANIC_FLUSH +extern int panic_flush_device_cache(int timeout); +#endif + /** * panic - halt the system * @fmt: The text string to print @@ -144,7 +151,9 @@ void panic(const char *fmt, ...) int state = 0; int old_cpu, this_cpu; bool _crash_kexec_post_notifiers = crash_kexec_post_notifiers; - +#ifdef OPLUS_FEATURE_AGINGTEST + char *function_name; +#endif /*OPLUS_FEATURE_AGINGTEST*/ /* * Disable local interrupts. This will prevent panic_smp_self_stop * from deadlocking the first cpu that invokes the panic, since @@ -181,9 +190,17 @@ void panic(const char *fmt, ...) vsnprintf(buf, sizeof(buf), fmt, args); va_end(args); dump_stack_minidump(0); +#ifdef CONFIG_OPLUS_FEATURE_PANIC_FLUSH + panic_flush_device_cache(2000); +#endif if (vendor_panic_cb) vendor_panic_cb(0); pr_emerg("Kernel panic - not syncing: %s\n", buf); +#ifdef OPLUS_FEATURE_AGINGTEST + function_name = parse_function_builtin_return_address((unsigned long)__builtin_return_address(0)); + save_dump_reason_to_smem(buf, function_name); +#endif /*OPLUS_FEATURE_AGINGTEST*/ + #ifdef CONFIG_DEBUG_BUGVERBOSE /* * Avoid nested stack-dumping if a panic occurs during oops processing diff --git a/kernel/panic_flush.c b/kernel/panic_flush.c new file mode 100644 index 000000000000..b53ab78d0446 --- /dev/null +++ b/kernel/panic_flush.c @@ -0,0 +1,121 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2018-2020 Oplus. All rights reserved. + */ + +#define DEBUG +#include +#include +#include +#include +#include +#include + +#define PANIC_FLUSH_POLL_MS (10) + + +struct panic_flush_control { + struct task_struct *flush_thread; + wait_queue_head_t flush_wq; + atomic_t flush_issuing; + atomic_t flush_issued; +}; + +static struct panic_flush_control *pfc; +static void panic_issue_flush(struct super_block *sb ,void *arg) +{ + int ret = -1; + int *flush_count = (int *)arg; + if (!(sb->s_flags & MS_RDONLY) && NULL != sb->s_bdev) { + ret = blkdev_issue_flush(sb->s_bdev, GFP_KERNEL, NULL); + } + if (!ret) { + (*flush_count)++; + pr_emerg("blkdev_issue_flush before panic return %d\n", *flush_count); + } +} + +static int panic_flush_thread(void *data) +{ + int flush_count = 0; +repeat: + if (kthread_should_stop()) + return 0; + wait_event(pfc->flush_wq, kthread_should_stop() || + atomic_read(&pfc->flush_issuing) > 0); + if (atomic_read(&pfc->flush_issuing) > 0) { + iterate_supers(panic_issue_flush, &flush_count); + pr_emerg("Up to now, total %d panic_issue_flush_count\n", flush_count); + atomic_inc(&pfc->flush_issued); + atomic_dec(&pfc->flush_issuing); + } + goto repeat; +} + +extern bool is_fulldump_enable(void); + +static inline bool need_flush_device_cache(void) +{ + if (is_fulldump_enable()) + return false; + return true; +} + +int panic_flush_device_cache(int timeout) +{ + pr_emerg("%s\n", __func__); + if (!need_flush_device_cache()) { + pr_emerg("%s: skip flush device cache\n", __func__); + return timeout; + } + + if (atomic_inc_return(&pfc->flush_issuing) == 1 && + waitqueue_active(&pfc->flush_wq)) { + pr_emerg("%s: flush device cache\n", __func__); + atomic_set(&pfc->flush_issued, 0); + wake_up(&pfc->flush_wq); + while (timeout > 0 && atomic_read(&pfc->flush_issued) == 0) { + mdelay(PANIC_FLUSH_POLL_MS); + timeout -= PANIC_FLUSH_POLL_MS; + } + pr_emerg("%s: remaining timeout = %d\n", __func__, timeout); + } + return timeout; +} + +static int __init create_panic_flush_control(void) +{ + int err = 0; + pr_debug("%s\n", __func__); + pfc = kzalloc(sizeof(*pfc), GFP_KERNEL); + if (!pfc) { + pr_err("%s: fail to allocate memory\n", __func__); + return -ENOMEM; + } + + init_waitqueue_head(&pfc->flush_wq); + atomic_set(&pfc->flush_issuing, 0); + atomic_set(&pfc->flush_issued, 0); + pfc->flush_thread = kthread_run(panic_flush_thread, pfc, "panic_flush"); + if (IS_ERR(pfc->flush_thread)) { + err = PTR_ERR(pfc->flush_thread); + kfree(pfc); + pfc = NULL; + } + return err; +} + +static void __exit destroy_panic_flush_control(void) +{ + pr_debug("%s\n", __func__); + if (pfc && pfc->flush_thread) { + pr_debug("%s: stop panic_flush thread\n", __func__); + kthread_stop(pfc->flush_thread); + kfree(pfc); + pfc = NULL; + } +} +module_init(create_panic_flush_control); +module_exit(destroy_panic_flush_control); +MODULE_DESCRIPTION("OPLUS panic flush control"); +MODULE_LICENSE("GPL v2"); diff --git a/kernel/power/main.c b/kernel/power/main.c index 1ee81334d689..28a50d5031ad 100644 --- a/kernel/power/main.c +++ b/kernel/power/main.c @@ -16,6 +16,9 @@ #include #include #include +#ifdef OPLUS_FEATURE_POWERINFO_STANDBY +#include +#endif /* OPLUS_FEATURE_POWERINFO_STANDBY */ #include "power.h" @@ -601,6 +604,10 @@ static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr, suspend_state_t state; int error; + #ifdef OPLUS_FEATURE_POWERINFO_STANDBY + pr_info("PM: enter state_store, buf=%s.\n", buf); + #endif /* OPLUS_FEATURE_POWERINFO_STANDBY */ + error = pm_autosleep_lock(); if (error) return error; @@ -657,7 +664,32 @@ power_attr(state); * is allowed to write to 'state', but the transition will be aborted if there * are any wakeup events detected after 'wakeup_count' was written to. */ +#ifdef OPLUS_FEATURE_POWERINFO_STANDBY +static void pm_wakeup_count_marker(char *annotation) +{ + struct timespec ts; + struct rtc_time tm; + getnstimeofday(&ts); + rtc_time_to_tm(ts.tv_sec, &tm); + pr_info("PM: wakeup_count %s %d-%02d-%02d %02d:%02d:%02d.%09lu UTC\n", + annotation, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, + tm.tm_hour, tm.tm_min, tm.tm_sec, ts.tv_nsec); +} + +static ssize_t wakeup_count_show(struct kobject *kobj, + struct kobj_attribute *attr, + char *buf) +{ + unsigned int val, error; + + pm_wakeup_count_marker("read enter"); + error = pm_get_wakeup_count(&val, true); + pm_wakeup_count_marker("read exit"); + + return error ? sprintf(buf, "%u\n", val) : -EINTR; +} +#else static ssize_t wakeup_count_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) @@ -667,6 +699,7 @@ static ssize_t wakeup_count_show(struct kobject *kobj, return pm_get_wakeup_count(&val, true) ? sprintf(buf, "%u\n", val) : -EINTR; } +#endif /* OPLUS_FEATURE_POWERINFO_STANDBY */ static ssize_t wakeup_count_store(struct kobject *kobj, struct kobj_attribute *attr, @@ -675,6 +708,10 @@ static ssize_t wakeup_count_store(struct kobject *kobj, unsigned int val; int error; + #ifdef OPLUS_FEATURE_POWERINFO_STANDBY + pm_wakeup_count_marker("store"); + #endif /* OPLUS_FEATURE_POWERINFO_STANDBY */ + error = pm_autosleep_lock(); if (error) return error; @@ -843,6 +880,38 @@ power_attr(pm_freeze_timeout); #endif /* CONFIG_FREEZER*/ +#ifdef OPLUS_BUG_STABILITY +char pon_reason[128]; +static ssize_t pon_reason_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + return sprintf(buf, "%s", pon_reason); +} + +static ssize_t pon_reason_store(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t n) +{ + return -EINVAL; +} +power_attr(pon_reason); + +char poff_reason[128]; +static ssize_t poff_reason_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + return sprintf(buf, "%s", poff_reason); +} + +static ssize_t poff_reason_store(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t n) +{ + return -EINVAL; +} +power_attr(poff_reason); +#endif /*OPLUS_BUG_STABILITY*/ + static struct attribute * g[] = { &state_attr.attr, #ifdef CONFIG_PM_TRACE @@ -872,6 +941,10 @@ static struct attribute * g[] = { #ifdef CONFIG_FREEZER &pm_freeze_timeout_attr.attr, #endif +#ifdef OPLUS_BUG_STABILITY + &pon_reason_attr.attr, + &poff_reason_attr.attr, +#endif /*OPLUS_BUG_STABILITY*/ NULL, }; diff --git a/kernel/power/process.c b/kernel/power/process.c index d76e61606f51..0c3278540204 100644 --- a/kernel/power/process.c +++ b/kernel/power/process.c @@ -26,7 +26,11 @@ /* * Timeout for stopping processes */ +#ifndef OPLUS_FEATURE_POWERINFO_STANDBY unsigned int __read_mostly freeze_timeout_msecs = 20 * MSEC_PER_SEC; +#else +unsigned int __read_mostly freeze_timeout_msecs = 2 * MSEC_PER_SEC; +#endif /*OPLUS_FEATURE_POWERINFO_STANDBY*/ static int try_to_freeze_tasks(bool user_only) { diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c index 365d1e81fed7..2b7bc57e5094 100644 --- a/kernel/power/suspend.c +++ b/kernel/power/suspend.c @@ -332,9 +332,18 @@ MODULE_PARM_DESC(pm_test_delay, static int suspend_test(int level) { #ifdef CONFIG_PM_DEBUG + #ifdef OPLUS_FEATURE_POWERINFO_STANDBY + pr_info("%s pm_test_level:%d, level:%d\n", __func__, + pm_test_level, level); + #endif /* OPLUS_FEATURE_POWERINFO_STANDBY */ if (pm_test_level == level) { + #ifndef OPLUS_FEATURE_POWERINFO_STANDBY pr_info("suspend debug: Waiting for %d second(s).\n", pm_test_delay); + #else + pr_err("suspend debug: Waiting for %d second(s).\n", + pm_test_delay); + #endif /* OPLUS_FEATURE_POWERINFO_STANDBY */ mdelay(pm_test_delay * 1000); return 1; } @@ -403,8 +412,15 @@ static int suspend_enter(suspend_state_t state, bool *wakeup) int error, last_dev; error = platform_suspend_prepare(state); + #ifndef OPLUS_FEATURE_POWERINFO_STANDBY if (error) goto Platform_finish; + #else + if (error) { + pr_info("%s platform_suspend_prepare fail\n", __func__); + goto Platform_finish; + } + #endif /* OPLUS_FEATURE_POWERINFO_STANDBY */ error = dpm_suspend_late(PMSG_SUSPEND); if (error) { @@ -416,8 +432,15 @@ static int suspend_enter(suspend_state_t state, bool *wakeup) goto Platform_finish; } error = platform_suspend_prepare_late(state); + #ifndef OPLUS_FEATURE_POWERINFO_STANDBY if (error) goto Devices_early_resume; + #else + if (error) { + pr_info("%s prepare late fail\n", __func__); + goto Devices_early_resume; + } + #endif /* OPLUS_FEATURE_POWERINFO_STANDBY */ if (state == PM_SUSPEND_TO_IDLE && pm_test_level != TEST_PLATFORM) { s2idle_loop(); @@ -434,11 +457,25 @@ static int suspend_enter(suspend_state_t state, bool *wakeup) goto Platform_early_resume; } error = platform_suspend_prepare_noirq(state); + #ifndef OPLUS_FEATURE_POWERINFO_STANDBY if (error) goto Platform_wake; + #else + if (error) { + pr_info("%s prepare_noirq fail\n", __func__); + goto Platform_wake; + } + #endif /* OPLUS_FEATURE_POWERINFO_STANDBY */ + #ifndef OPLUS_FEATURE_POWERINFO_STANDBY if (suspend_test(TEST_PLATFORM)) goto Platform_wake; + #else + if (suspend_test(TEST_PLATFORM)) { + pr_info("%s test_platform fail\n", __func__); + goto Platform_wake; + } + #endif /* OPLUS_FEATURE_POWERINFO_STANDBY */ error = disable_nonboot_cpus(); if (error || suspend_test(TEST_CPUS)) { @@ -448,6 +485,9 @@ static int suspend_enter(suspend_state_t state, bool *wakeup) arch_suspend_disable_irqs(); BUG_ON(!irqs_disabled()); + #ifdef OPLUS_FEATURE_POWERINFO_STANDBY + pr_info("%s syscore_suspend\n", __func__); + #endif /* OPLUS_FEATURE_POWERINFO_STANDBY */ system_state = SYSTEM_SUSPEND; @@ -498,14 +538,28 @@ int suspend_devices_and_enter(suspend_state_t state) int error; bool wakeup = false; + #ifndef OPLUS_FEATURE_POWERINFO_STANDBY if (!sleep_state_supported(state)) return -ENOSYS; + #else + if (!sleep_state_supported(state)) { + pr_info("sleep_state_supported false\n"); + return -ENOSYS; + } + #endif /* OPLUS_FEATURE_POWERINFO_STANDBY */ pm_suspend_target_state = state; error = platform_suspend_begin(state); + #ifndef OPLUS_FEATURE_POWERINFO_STANDBY if (error) goto Close; + #else + if (error) { + pr_info("%s platform_suspend_begin fail\n", __func__); + goto Close; + } + #endif /* OPLUS_FEATURE_POWERINFO_STANDBY */ suspend_console(); suspend_test_start(); @@ -517,13 +571,24 @@ int suspend_devices_and_enter(suspend_state_t state) goto Recover_platform; } suspend_test_finish("suspend devices"); + #ifndef OPLUS_FEATURE_POWERINFO_STANDBY if (suspend_test(TEST_DEVICES)) goto Recover_platform; + #else + if (suspend_test(TEST_DEVICES)) { + pr_info("%s TEST_DEVICES fail\n", __func__); + goto Recover_platform; + } + #endif /* OPLUS_FEATURE_POWERINFO_STANDBY */ do { error = suspend_enter(state, &wakeup); } while (!error && !wakeup && platform_suspend_again(state)); + #ifdef OPLUS_FEATURE_POWERINFO_STANDBY + pr_info("suspend_enter end, error:%d, wakeup:%d\n", error, wakeup); + #endif /* OPLUS_FEATURE_POWERINFO_STANDBY */ + Resume_devices: suspend_test_start(); dpm_resume_end(PMSG_RESUME); @@ -555,6 +620,68 @@ static void suspend_finish(void) pm_restore_console(); } +#ifdef OPLUS_BUG_STABILITY +/** +* Sync the filesystem in seperate workqueue. +* Then check it finishing or not periodically and +* abort if any wakeup source comes in. That can reduce +* the wakeup latency +* +*/ +static bool sys_sync_completed = false; +static void sys_sync_work_func(struct work_struct *work); +static DECLARE_WORK(sys_sync_work, sys_sync_work_func); +static DECLARE_WAIT_QUEUE_HEAD(sys_sync_wait); +static void sys_sync_work_func(struct work_struct *work) +{ + trace_suspend_resume(TPS("sync_filesystems"), 0, true); + pr_info(KERN_INFO "PM: Syncing filesystems ... "); + ksys_sync(); + pr_cont("done.\n"); + trace_suspend_resume(TPS("sync_filesystems"), 0, false); + sys_sync_completed = true; + wake_up(&sys_sync_wait); +} + +static int sys_sync_queue(void) +{ + int work_status = work_busy(&sys_sync_work); + + /*maybe some irq coming here before pending check*/ + pm_wakeup_clear(true); + + /*Check if the previous work still running.*/ + if (!(work_status & WORK_BUSY_PENDING)) { + if (work_status & WORK_BUSY_RUNNING) { + while (wait_event_timeout(sys_sync_wait, sys_sync_completed, + msecs_to_jiffies(100)) == 0) { + if (pm_wakeup_pending()) { + pr_info("PM: Pre-Syncing abort\n"); + goto abort; + } + } + pr_info("PM: Pre-Syncing done\n"); + } + sys_sync_completed = false; + schedule_work(&sys_sync_work); + } + + while (wait_event_timeout(sys_sync_wait, sys_sync_completed, + msecs_to_jiffies(100)) == 0) { + if (pm_wakeup_pending()) { + pr_info("PM: Syncing abort\n"); + goto abort; + } + } + + pr_info("PM: Syncing done\n"); + return 0; +abort: + return -EAGAIN; +} +#endif /*OPLUS_BUG_STABILITY*/ + + /** * enter_state - Do common work needed to enter system sleep state. * @state: System sleep state to enter. @@ -576,27 +703,57 @@ static int enter_state(suspend_state_t state) } #endif } else if (!valid_state(state)) { + #ifdef OPLUS_FEATURE_POWERINFO_STANDBY + pr_info("%s invalid_state\n", __func__); + #endif /* OPLUS_FEATURE_POWERINFO_STANDBY */ return -EINVAL; } + + #ifndef OPLUS_FEATURE_POWERINFO_STANDBY if (!mutex_trylock(&system_transition_mutex)) return -EBUSY; + #else + if (!mutex_trylock(&system_transition_mutex)) { + pr_info("%s mutex_trylock fail\n", __func__); + return -EBUSY; + } + #endif /* OPLUS_FEATURE_POWERINFO_STANDBY */ if (state == PM_SUSPEND_TO_IDLE) s2idle_begin(); #ifndef CONFIG_SUSPEND_SKIP_SYNC +#ifndef OPLUS_BUG_STABILITY trace_suspend_resume(TPS("sync_filesystems"), 0, true); pr_info("Syncing filesystems ... "); ksys_sync(); pr_cont("done.\n"); trace_suspend_resume(TPS("sync_filesystems"), 0, false); +#else + error = sys_sync_queue(); + if (error) { + pr_err("%s sys_sync_queue fail\n", __func__); + goto Unlock; + } +#endif /* OPLUS_BUG_STABILITY */ #endif pm_pr_dbg("Preparing system for sleep (%s)\n", mem_sleep_labels[state]); pm_suspend_clear_flags(); error = suspend_prepare(state); + #ifndef OPLUS_FEATURE_POWERINFO_STANDBY if (error) goto Unlock; + #else + if (error) { + pr_info("%s suspend_prepare error:%d\n", __func__, error); + goto Unlock; + } + #endif /* OPLUS_FEATURE_POWERINFO_STANDBY */ + + #ifdef OPLUS_FEATURE_POWERINFO_STANDBY + pr_info("%s suspend_prepare success\n", __func__); + #endif /* OPLUS_FEATURE_POWERINFO_STANDBY */ if (suspend_test(TEST_FREEZER)) goto Finish; @@ -606,6 +763,9 @@ static int enter_state(suspend_state_t state) pm_restrict_gfp_mask(); error = suspend_devices_and_enter(state); pm_restore_gfp_mask(); + #ifdef OPLUS_FEATURE_POWERINFO_STANDBY + pr_info("%s suspend_devices_and_enter end\n", __func__); + #endif /* OPLUS_FEATURE_POWERINFO_STANDBY */ Finish: events_check_enabled = false; diff --git a/kernel/power/wakeup_reason.c b/kernel/power/wakeup_reason.c index 3c118c044633..46a89c1c9adb 100644 --- a/kernel/power/wakeup_reason.c +++ b/kernel/power/wakeup_reason.c @@ -276,6 +276,10 @@ static void print_wakeup_sources(void) spin_unlock_irqrestore(&wakeup_reason_lock, flags); } +extern void bts_net_clear(void); +extern bool bts_net_exist(void); +extern ssize_t bts_net_fill(char * desc, ssize_t size); + static ssize_t last_resume_reason_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { @@ -292,11 +296,15 @@ static ssize_t last_resume_reason_show(struct kobject *kobj, return buf_offset; } + if(bts_net_exist()) { + buf_offset += bts_net_fill(buf + buf_offset, PAGE_SIZE - buf_offset); + bts_net_clear(); + } if (!list_empty(&leaf_irqs)) list_for_each_entry(n, &leaf_irqs, siblings) buf_offset += scnprintf(buf + buf_offset, PAGE_SIZE - buf_offset, - "%d %s\n", n->irq, n->irq_name); + "%d %s\n", n->irq, (strncmp(n->irq_name, "ipcc_1", strlen("ipcc_1")) == 0) ? "qmi" : n->irq_name); else if (abnormal_wake) buf_offset = scnprintf(buf, PAGE_SIZE, "-1 %s", non_irq_wake_reason); diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c index fafac7dd380d..b2262f32ff7b 100644 --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c @@ -57,6 +57,25 @@ #include "console_cmdline.h" #include "braille.h" #include "internal.h" +#ifdef OPLUS_BUG_STABILITY +/* Add for uart control via cmdline*/ +#include +static bool __read_mostly printk_disable_uart = true; /*set true avoid early console output*/ +static int __init printk_uart_disabled(char *str) +{ + if (str[0] == '1') + printk_disable_uart = true; + else + printk_disable_uart = false; + return 0; +} +early_param("printk.disable_uart", printk_uart_disabled); + +bool oem_disable_uart(void) +{ + return printk_disable_uart; +} +#endif /*VENDOR_EDIT*/ int console_printk[4] = { CONSOLE_LOGLEVEL_DEFAULT, /* console_loglevel */ @@ -609,6 +628,21 @@ static int log_store(int facility, int level, u32 size, pad_len; u16 trunc_msg_len = 0; +#ifdef VENDOR_EDIT + //part 1/2: add for add cpu number and current id and current comm to kmsg + int this_cpu = smp_processor_id(); + char tbuf[64]; + unsigned tlen; + + if (console_suspended == 0) { + tlen = snprintf(tbuf, sizeof(tbuf), " (%x)[%d:%s]", + this_cpu, current->pid, current->comm); + } else { + tlen = snprintf(tbuf, sizeof(tbuf), " %x)", this_cpu); + } + text_len += tlen; +#endif //add end part 1/3 + /* number of '\0' padding bytes to next message */ size = msg_used_size(text_len, dict_len, &pad_len); @@ -633,7 +667,13 @@ static int log_store(int facility, int level, /* fill message */ msg = (struct printk_log *)(log_buf + log_next_idx); +#ifndef VENDOR_EDIT +//part 2/2: add for add cpu number and current id and current comm to kmsg memcpy(log_text(msg), text, text_len); +#else + memcpy(log_text(msg), tbuf, tlen); + memcpy(log_text(msg) + tlen, text, text_len-tlen); +#endif //add end part 3/3 msg->text_len = text_len; if (trunc_msg_len) { memcpy(log_text(msg) + text_len, trunc_msg, trunc_msg_len); @@ -1753,6 +1793,14 @@ static void call_console_drivers(const char *ext_text, size_t ext_len, return; for_each_console(con) { +#ifdef VENDOR_EDIT + if ((con->flags & CON_CONSDEV) && + (printk_disable_uart || + get_boot_mode() == MSM_BOOT_MODE__FACTORY || + get_boot_mode() == MSM_BOOT_MODE__RF || + get_boot_mode() == MSM_BOOT_MODE__WLAN)) + continue; +#endif /*VENDOR_EDIT*/ if (exclusive_console && con != exclusive_console) continue; if (!(con->flags & CON_ENABLED)) @@ -3316,6 +3364,55 @@ out: } EXPORT_SYMBOL_GPL(kmsg_dump_get_buffer); +#ifdef CONFIG_OPLUS_FEATURE_UBOOT_LOG +#include +bool back_kmsg_dump_get_buffer(struct kmsg_dumper *dumper, bool syslog, + char *buf, size_t size, size_t *len) +{ + unsigned long flags; + u64 seq; + u32 idx; + size_t l = 0; + bool ret = false; + + logbuf_lock_irqsave(flags); + if (dumper->cur_seq < log_first_seq) { + l += scnprintf(buf + l, size - l, "Lost some logs: cur_seq:%lld, log_first_seq:%lld\n", dumper->cur_seq, log_first_seq); + //messages are gone, move to first available one + dumper->cur_seq = log_first_seq; + dumper->cur_idx = log_first_idx; + } + + // last entry + if (dumper->cur_seq >= dumper->next_seq) { + logbuf_unlock_irqrestore(flags); + goto out; + } + + + // record log form cur_seq until the buf is full + seq = dumper->cur_seq; + idx = dumper->cur_idx; + while (l + LOG_LINE_MAX + PREFIX_MAX < size && seq < dumper->next_seq) { + struct printk_log *msg = log_from_idx(idx); + + l += msg_print_text(msg, syslog, buf + l, size - l); + idx = log_next(idx); + seq++; + } + dumper->cur_seq = seq; + dumper->cur_idx = idx; + + ret = true; + logbuf_unlock_irqrestore(flags); +out: + if (len) + *len = l; + return ret; +} +EXPORT_SYMBOL(back_kmsg_dump_get_buffer); +#endif /*CONFIG_OPLUS_FEATURE_UBOOT_LOG*/ + /** * kmsg_dump_rewind_nolock - reset the interator (unlocked version) * @dumper: registered kmsg dumper diff --git a/kernel/sched/completion.c b/kernel/sched/completion.c index a1ad5b7d5521..8ceb079b2618 100644 --- a/kernel/sched/completion.c +++ b/kernel/sched/completion.c @@ -12,7 +12,9 @@ * Waiting for completion is a typically sync point, but not an exclusion point. */ #include "sched.h" - +#ifdef CONFIG_OPLUS_FEATURE_HUNG_TASK_ENHANCE +#include +#endif /** * complete: - signals a single thread waiting on this completion * @x: holds the state of this particular completion @@ -74,7 +76,11 @@ do_wait_for_common(struct completion *x, __add_wait_queue_entry_tail_exclusive(&x->wait, &wait); do { +#ifdef CONFIG_OPLUS_FEATURE_HUNG_TASK_ENHANCE + if (signal_pending_state(state, current) || hung_long_and_fatal_signal_pending(current)) { +#else if (signal_pending_state(state, current)) { +#endif timeout = -ERESTARTSYS; break; } diff --git a/kernel/sched/core.c b/kernel/sched/core.c index 254883d2c035..daa4938c678c 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -18,6 +18,10 @@ #include #include +#if defined(OPLUS_FEATURE_MULTI_KSWAPD) && defined(CONFIG_KSWAPD_UNBIND_MAX_CPU) +/*add multi kswapd support*/ +#include +#endif #include "../workqueue_internal.h" #include "../smpboot.h" @@ -28,6 +32,25 @@ #define CREATE_TRACE_POINTS #include +#ifdef OPLUS_FEATURE_SCHED_ASSIST +#include +#endif /* OPLUS_FEATURE_SCHED_ASSIST */ + +#if defined(OPLUS_FEATURE_TASK_CPUSTATS) && defined(CONFIG_OPLUS_SCHED) +#include +#endif /* defined(OPLUS_FEATURE_TASK_CPUSTATS) && defined(CONFIG_OPLUS_SCHED) */ + +#ifdef CONFIG_OPLUS_FEATURE_INPUT_BOOST_V4 +#include +#endif /* CONFIG_OPLUS_FEATURE_INPUT_BOOST_V4 */ + +#ifdef CONFIG_OPLUS_FEATURE_GAME_OPT +#include "../../drivers/soc/oplus/game_opt/game_ctrl.h" +#endif +#if IS_ENABLED(CONFIG_OPLUS_FEATURE_CPU_JANKINFO) +#include +#endif + DEFINE_PER_CPU_SHARED_ALIGNED(struct rq, runqueues); #ifdef CONFIG_SCHED_DEBUG @@ -1326,6 +1349,9 @@ static inline void enqueue_task(struct rq *rq, struct task_struct *p, int flags) } uclamp_rq_inc(rq, p); +#if IS_ENABLED(CONFIG_OPLUS_FEATURE_CPU_JANKINFO) + jankinfo_android_rvh_enqueue_task_handler(NULL, rq, p, flags); +#endif p->sched_class->enqueue_task(rq, p, flags); walt_update_last_enqueue(p); trace_sched_enq_deq_task(p, 1, cpumask_bits(&p->cpus_allowed)[0]); @@ -1452,6 +1478,17 @@ void check_preempt_curr(struct rq *rq, struct task_struct *p, int flags) { const struct sched_class *class; +#ifdef OPLUS_FEATURE_SCHED_ASSIST +//#ifdef CONFIG_UXCHAIN_V2 + u64 wallclock = sched_clock(); + + if (sysctl_uxchain_v2 && + wallclock - rq->curr->get_mmlock_ts < PREEMPT_DISABLE_RWSEM && + rq->curr->get_mmlock && + !(p->flags & PF_WQ_WORKER) && !task_has_rt_policy(p)) + return; +#endif + if (p->sched_class == rq->curr->sched_class) { rq->curr->sched_class->check_preempt_curr(rq, p, flags); } else { @@ -1631,6 +1668,10 @@ void do_set_cpus_allowed(struct task_struct *p, const struct cpumask *new_mask) bool queued, running; lockdep_assert_held(&p->pi_lock); +#if defined(OPLUS_FEATURE_MULTI_KSWAPD) && defined(CONFIG_KSWAPD_UNBIND_MAX_CPU) + if (kswapd_affinity_check(p, new_mask)) + return; +#endif queued = task_on_rq_queued(p); running = task_current(rq, p); @@ -2507,6 +2548,13 @@ static void ttwu_queue(struct task_struct *p, int cpu, int wake_flags) rq_unlock(rq, &rf); } +#ifdef CONFIG_OPLUS_FEATURE_RT_INFO +rt_info_handler rt_handler = NULL; +void register_rt_info_handler(rt_info_handler h) { + rt_handler = h; + pr_info("Add a rt_info handler\n"); +} +#endif /* * Notes on Program-Order guarantees on SMP systems. * @@ -2647,6 +2695,16 @@ try_to_wake_up(struct task_struct *p, unsigned int state, int wake_flags, { unsigned long flags; int cpu, success = 0; +#ifdef CONFIG_OPLUS_FEATURE_INPUT_BOOST_V4 + bool in_grp = false; + struct frame_boost_group *grp = NULL; + rcu_read_lock(); + grp = task_frame_boost_group(p); + rcu_read_unlock(); + if (grp) { + in_grp = true; + } +#endif /* CONFIG_OPLUS_FEATURE_INPUT_BOOST_V4 */ /* * If we are going to wake up a thread waiting for CONDITION we @@ -2661,6 +2719,18 @@ try_to_wake_up(struct task_struct *p, unsigned int state, int wake_flags, trace_sched_waking(p); +#if defined(OPLUS_FEATURE_TASK_CPUSTATS) && defined(CONFIG_OPLUS_SCHED) + update_wake_tid(p, current, other_runnable); +#endif /* defined(OPLUS_FEATURE_TASK_CPUSTATS) && defined(CONFIG_OPLUS_SCHED) */ + +#ifdef CONFIG_OPLUS_FEATURE_INPUT_BOOST_V4 + trace_sched_in_fbg(p, in_grp); +#endif /* CONFIG_OPLUS_FEATURE_INPUT_BOOST_V4 */ +#ifdef CONFIG_OPLUS_FEATURE_RT_INFO + if (rt_handler != NULL) + rt_handler(p); +#endif + /* We're going to change ->state: */ success = 1; cpu = task_cpu(p); @@ -2732,6 +2802,10 @@ try_to_wake_up(struct task_struct *p, unsigned int state, int wake_flags, atomic_dec(&task_rq(p)->nr_iowait); } +#ifdef CONFIG_OPLUS_FEATURE_GAME_OPT + g_rt_try_to_wake_up(p); +#endif + cpu = select_task_rq(p, p->wake_cpu, SD_BALANCE_WAKE, wake_flags, sibling_count_hint); if (task_cpu(p) != cpu) { @@ -2802,6 +2876,10 @@ static void try_to_wake_up_local(struct task_struct *p, struct rq_flags *rf) trace_sched_waking(p); +#if defined(OPLUS_FEATURE_TASK_CPUSTATS) && defined(CONFIG_OPLUS_SCHED) + update_wake_tid(p, current, other_runnable); +#endif /* defined(OPLUS_FEATURE_TASK_CPUSTATS) && defined(CONFIG_OPLUS_SCHED) */ + if (!task_on_rq_queued(p)) { u64 wallclock = sched_ktime_clock(); @@ -3436,6 +3514,13 @@ static struct rq *finish_task_switch(struct task_struct *prev) * task and put them back on the free list. */ kprobe_flush_task(prev); +#ifdef CONFIG_OPLUS_FEATURE_GAME_OPT + g_rt_task_dead(prev); +#endif + +#ifdef CONFIG_OPLUS_FEATURE_INPUT_BOOST_V4 + sched_set_frame_boost_group(prev, false); +#endif /* CONFIG_OPLUS_FEATURE_INPUT_BOOST_V4 */ /* Task is done with its stack. */ put_task_stack(prev); @@ -3543,8 +3628,10 @@ context_switch(struct rq *rq, struct task_struct *prev, next->active_mm = oldmm; mmgrab(oldmm); enter_lazy_tlb(oldmm, next); - } else + } else { switch_mm_irqs_off(oldmm, mm, next); + lru_gen_use_mm(mm); + } if (!prev->mm) { prev->active_mm = NULL; @@ -3766,7 +3853,50 @@ unsigned long long task_sched_runtime(struct task_struct *p) } unsigned int capacity_margin_freq = 1280; /* ~20% margin */ +#ifndef CONFIG_OPLUS_FEATURE_INPUT_BOOST_V4 +#ifdef OPLUS_FEATURE_SCHED_ASSIST +extern int sysctl_frame_rate; +extern unsigned int sched_ravg_window; +extern bool ux_task_misfit(struct task_struct *p, int cpu); +u64 ux_task_load[NR_CPUS] = {0}; +u64 ux_load_ts[NR_CPUS] = {0}; +static u64 calc_freq_ux_load(struct task_struct *p, u64 wallclock) +{ + unsigned int maxtime = 0, factor = 0; + unsigned int window_size = sched_ravg_window / NSEC_PER_MSEC; + u64 timeline = 0, freq_exec_load = 0, freq_ravg_load = 0; + u64 wakeclock = p->last_wake_ts; + if (wallclock < wakeclock) + return 0; + + switch (sysctl_frame_rate) { + case 60: + case 90: + maxtime = 5; + break; + case 120: + maxtime = 4; + break; + default: + return 0; + } + + timeline = wallclock - wakeclock; + factor = window_size / maxtime; + freq_exec_load = timeline * factor; + + if (freq_exec_load > sched_ravg_window) + freq_exec_load = sched_ravg_window; + + freq_ravg_load = (p->ravg.prev_window + p->ravg.curr_window) << 1; + if (freq_ravg_load > sched_ravg_window) + freq_ravg_load = sched_ravg_window; + + return max(freq_exec_load, freq_ravg_load); +} +#endif +#endif /* * This function gets called by the timer code, with HZ frequency. * We call it with interrupts disabled. @@ -3801,7 +3931,29 @@ void scheduler_tick(void) if (early_notif) flag = SCHED_CPUFREQ_WALT | SCHED_CPUFREQ_EARLY_DET; +#ifndef CONFIG_OPLUS_FEATURE_INPUT_BOOST_V4 +#ifdef OPLUS_FEATURE_SCHED_ASSIST + if (sched_assist_scene(SA_SLIDE)) { + if(rq->curr && is_heavy_ux_task(rq->curr) && !ux_task_misfit(rq->curr, cpu)) { + ux_task_load[cpu] = calc_freq_ux_load(rq->curr, wallclock); + ux_load_ts[cpu] = wallclock; + flag |= (SCHED_CPUFREQ_WALT | SCHED_CPUFREQ_BOOST); + } + else if (ux_task_load[cpu] != 0) { + ux_task_load[cpu] = 0; + ux_load_ts[cpu] = wallclock; + flag |= (SCHED_CPUFREQ_WALT | SCHED_CPUFREQ_RESET); + } + } else { + ux_task_load[cpu] = 0; + ux_load_ts[cpu] = 0; + } +#endif +#endif cpufreq_update_util(rq, flag); +#ifdef CONFIG_OPLUS_FEATURE_INPUT_BOOST_V4 + sched_update_fbg_tick(rq->curr, wallclock); +#endif /* CONFIG_OPLUS_FEATURE_INPUT_BOOST_V4 */ rq_unlock(rq, &rf); perf_event_task_tick(); @@ -3827,6 +3979,9 @@ void scheduler_tick(void) rq_unlock(rq, &rf); #endif +#if defined(OPLUS_FEATURE_SCHED_ASSIST) && defined(CONFIG_OPLUS_FEATURE_SCHED_SPREAD) + update_rq_nr_imbalance(cpu); +#endif } #ifdef CONFIG_NO_HZ_FULL @@ -4258,11 +4413,18 @@ static void __sched notrace __schedule(bool preempt) switch_count = &prev->nvcsw; } +#ifdef OPLUS_FEATURE_SCHED_ASSIST + prev->enqueue_time = rq->clock; +#endif /* OPLUS_FEATURE_SCHED_ASSIST */ + next = pick_next_task(rq, prev, &rf); clear_tsk_need_resched(prev); clear_preempt_need_resched(); wallclock = sched_ktime_clock(); +#if IS_ENABLED(CONFIG_OPLUS_FEATURE_CPU_JANKINFO) + jankinfo_android_rvh_schedule_handler(NULL, prev, next, rq); +#endif if (likely(prev != next)) { if (!prev->on_rq) prev->last_sleep_ts = wallclock; @@ -4289,6 +4451,11 @@ static void __sched notrace __schedule(bool preempt) trace_sched_switch(preempt, prev, next); +#if defined(OPLUS_FEATURE_TASK_CPUSTATS) && defined(CONFIG_OPLUS_SCHED) + update_wake_tid(prev, next, running_runnable); + update_running_start_time(prev, next); +#endif /* defined(OPLUS_FEATURE_TASK_CPUSTATS) && defined(CONFIG_OPLUS_SCHED) */ + /* Also unlocks the rq: */ rq = context_switch(rq, prev, next, &rf); update_md_current_stack(NULL); @@ -6822,6 +6989,11 @@ out: cpu_maps_update_done(); trace_sched_isolate(cpu, cpumask_bits(cpu_isolated_mask)[0], start_time, 1); + +#if defined(OPLUS_FEATURE_TASK_CPUSTATS) && defined(CONFIG_OPLUS_SCHED) + update_cpu_isolate_info(cpu, cpu_isolate); +#endif /* defined(OPLUS_FEATURE_TASK_CPUSTATS) && defined(CONFIG_OPLUS_SCHED) */ + return ret_code; } @@ -6866,6 +7038,9 @@ int sched_unisolate_cpu_unlocked(int cpu) out: trace_sched_isolate(cpu, cpumask_bits(cpu_isolated_mask)[0], start_time, 0); +#if defined(OPLUS_FEATURE_TASK_CPUSTATS) && defined(CONFIG_OPLUS_SCHED) + update_cpu_isolate_info(cpu, cpu_unisolate); +#endif /* defined(OPLUS_FEATURE_TASK_CPUSTATS) && defined(CONFIG_OPLUS_SCHED) */ return ret_code; } @@ -7112,6 +7287,9 @@ void __init sched_init_smp(void) cpumask_copy(¤t->cpus_requested, cpu_possible_mask); sched_init_granularity(); +#ifdef OPLUS_FEATURE_SCHED_ASSIST + ux_init_cpu_data(); +#endif /* OPLUS_FEATURE_SCHED_ASSIST */ init_sched_rt_class(); init_sched_dl_class(); @@ -7154,6 +7332,17 @@ static struct kmem_cache *task_group_cache __read_mostly; DECLARE_PER_CPU(cpumask_var_t, load_balance_mask); DECLARE_PER_CPU(cpumask_var_t, select_idle_mask); +#ifdef OPLUS_FEATURE_SCHED_ASSIST +void set_random_uxchain_v2(void) +{ + int rand = 1; + + get_random_bytes(&rand, 1); + printk("get_random_bytes %d\n", rand); + sysctl_uxchain_v2 = rand % 2; +} +#endif + void __init sched_init(void) { int i, j; @@ -7230,6 +7419,9 @@ void __init sched_init(void) init_cfs_rq(&rq->cfs); init_rt_rq(&rq->rt); init_dl_rq(&rq->dl); +#ifdef OPLUS_FEATURE_SCHED_ASSIST + ux_init_rq_data(rq); +#endif /* OPLUS_FEATURE_SCHED_ASSIST */ #ifdef CONFIG_FAIR_GROUP_SCHED root_task_group.shares = ROOT_TASK_GROUP_LOAD; INIT_LIST_HEAD(&rq->leaf_cfs_rq_list); @@ -7326,6 +7518,10 @@ void __init sched_init(void) init_uclamp(); +#ifdef OPLUS_FEATURE_SCHED_ASSIST + set_random_uxchain_v2(); +#endif + scheduler_running = 1; } @@ -8637,3 +8833,22 @@ void sched_exit(struct task_struct *p) #endif /* CONFIG_SCHED_WALT */ __read_mostly bool sched_predl = 1; +#ifdef VENDOR_EDIT +struct task_struct *oplus_get_cpu_task(int cpu) +{ + return cpu_curr(cpu); +} +#endif + +#ifdef CONFIG_KSWAPD_UNBIND_MAX_CPU +void upate_kswapd_unbind_cpu(void) +{ + struct root_domain *rd = NULL; + + rcu_read_lock(); + rd = cpu_rq(smp_processor_id())->rd; + if (rd->mid_cap_orig_cpu != -1 && rd->max_cap_orig_cpu != -1) + kswapd_unbind_cpu = rd->max_cap_orig_cpu; + rcu_read_unlock(); +} +#endif diff --git a/kernel/sched/cpufreq_schedutil.c b/kernel/sched/cpufreq_schedutil.c index f4e5b57a0c2e..55dd5fda39ad 100644 --- a/kernel/sched/cpufreq_schedutil.c +++ b/kernel/sched/cpufreq_schedutil.c @@ -17,6 +17,19 @@ #include #include +#if defined(OPLUS_FEATURE_TASK_CPUSTATS) && defined(CONFIG_OPLUS_SCHED) +#include +#endif /* defined(OPLUS_FEATURE_TASK_CPUSTATS) && defined(CONFIG_OPLUS_SCHED) */ + +#ifdef OPLUS_FEATURE_POWER_CPUFREQ +/* Target load. Lower values result in higher CPU speeds. */ +#define DEFAULT_TARGET_LOAD 80 +#define DEFAULT_RATE_LIMIT_US 0 +static unsigned int default_above_hispeed_delay[] = { + DEFAULT_RATE_LIMIT_US }; +static unsigned int default_target_loads[] = { DEFAULT_TARGET_LOAD }; +#endif + struct sugov_tunables { struct gov_attr_set attr_set; unsigned int up_rate_limit_us; @@ -25,6 +38,18 @@ struct sugov_tunables { unsigned int hispeed_freq; unsigned int rtg_boost_freq; bool pl; +#ifdef OPLUS_FEATURE_POWER_CPUFREQ + spinlock_t target_loads_lock; + unsigned int *target_loads; + int ntarget_loads; + /* + * Wait this long before raising speed above hispeed, by default a + * single timer interval. + */ + spinlock_t above_hispeed_delay_lock; + unsigned int *above_hispeed_delay; + int nabove_hispeed_delay; +#endif }; struct sugov_policy { @@ -59,6 +84,18 @@ struct sugov_policy { bool limits_changed; bool need_freq_update; +#ifdef OPLUS_FEATURE_POWER_CPUFREQ + u64 hispeed_validate_time; + u64 update_time; + /* used to detect freq locked */ + ktime_t start_time; + bool freq_locked; + unsigned int min_freq; + bool after_limits_changed; +#endif +#if defined(OPLUS_FEATURE_SCHED_ASSIST) || defined(CONFIG_OPLUS_FEATURE_INPUT_BOOST_V4) + unsigned int flags; +#endif }; struct sugov_cpu { @@ -125,6 +162,15 @@ static bool sugov_should_update_freq(struct sugov_policy *sg_policy, u64 time) * to the separate rate limits. */ +#ifdef CONFIG_OPLUS_FEATURE_INPUT_BOOST_V4 + if (sg_policy->flags & SCHED_INPUT_BOOST) + return true; +#else +#ifdef OPLUS_FEATURE_SCHED_ASSIST + if (sg_policy->flags & SCHED_CPUFREQ_BOOST) + return true; +#endif /* OPLUS_FEATURE_SCHED_ASSIST */ +#endif /* CONFIG_OPLUS_FEATURE_INPUT_BOOST_V4 */ delta_ns = time - sg_policy->last_freq_update_time; return delta_ns >= sg_policy->min_rate_limit_ns; } @@ -154,6 +200,16 @@ static bool sugov_up_down_rate_limit(struct sugov_policy *sg_policy, u64 time, delta_ns = time - sg_policy->last_freq_update_time; +#ifdef CONFIG_OPLUS_FEATURE_INPUT_BOOST_V4 + if (sg_policy->flags & SCHED_INPUT_BOOST) + return false; +#else +#ifdef OPLUS_FEATURE_SCHED_ASSIST + if (sg_policy->flags & SCHED_CPUFREQ_BOOST) + return false; +#endif /* OPLUS_FEATURE_SCHED_ASSIST */ +#endif /* CONFIG_OPLUS_FEATURE_INPUT_BOOST_V4 */ + if (next_freq > sg_policy->next_freq && delta_ns < sg_policy->up_rate_delay_ns) return true; @@ -255,6 +311,10 @@ static void sugov_fast_switch(struct sugov_policy *sg_policy, u64 time, policy->cur = next_freq; +#if defined(OPLUS_FEATURE_TASK_CPUSTATS) && defined(CONFIG_OPLUS_SCHED) + update_freq_info(policy); +#endif /* defined(OPLUS_FEATURE_TASK_CPUSTATS) && defined(CONFIG_OPLUS_SCHED) */ + if (trace_cpu_frequency_enabled()) { for_each_cpu(cpu, policy->cpus) trace_cpu_frequency(next_freq, cpu); @@ -273,6 +333,168 @@ static void sugov_deferred_update(struct sugov_policy *sg_policy, u64 time, } #define TARGET_LOAD 80 + +#ifdef OPLUS_FEATURE_POWER_CPUFREQ +static unsigned int freq_to_targetload( + struct sugov_tunables *tunables, unsigned int freq) +{ + int i; + unsigned int ret; + unsigned long flags; + + spin_lock_irqsave(&tunables->target_loads_lock, flags); + + for (i = 0; i < tunables->ntarget_loads - 1 && + freq >= tunables->target_loads[i+1]; i += 2) + ; + + ret = tunables->target_loads[i]; + spin_unlock_irqrestore(&tunables->target_loads_lock, flags); + return ret; +} + + +static unsigned int choose_freq(struct sugov_policy *sg_policy, + unsigned int loadadjfreq) +{ + struct cpufreq_policy *policy = sg_policy->policy; + unsigned int freq = policy->cur; + unsigned int prevfreq, freqmin, freqmax; + unsigned int tl; + int index; + + freqmin = 0; + freqmax = UINT_MAX; + + do { + prevfreq = freq; + tl = freq_to_targetload(sg_policy->tunables, freq); + + /* + * Find the lowest frequency where the computed load is less + * than or equal to the target load. + */ + + index = cpufreq_frequency_table_target(policy, + loadadjfreq / tl, + CPUFREQ_RELATION_L); + freq = policy->freq_table[index].frequency; + + trace_choose_freq(freq, prevfreq, freqmax, freqmin, tl, index); + + if (freq > prevfreq) { + /* The previous frequency is too low. */ + freqmin = prevfreq; + + if (freq >= freqmax) { + /* + * Find the highest frequency that is less + * than freqmax. + */ + index = cpufreq_frequency_table_target( + policy, + freqmax - 1, CPUFREQ_RELATION_H); + freq = policy->freq_table[index].frequency; + + if (freq == freqmin) { + /* + * The first frequency below freqmax + * has already been found to be too + * low. freqmax is the lowest speed + * we found that is fast enough. + */ + freq = freqmax; + break; + } + } + } else if (freq < prevfreq) { + /* The previous frequency is high enough. */ + freqmax = prevfreq; + + if (freq <= freqmin) { + /* + * Find the lowest frequency that is higher + * than freqmin. + */ + index = cpufreq_frequency_table_target( + policy, + freqmin + 1, CPUFREQ_RELATION_L); + freq = policy->freq_table[index].frequency; + + /* + * If freqmax is the first frequency above + * freqmin then we have already found that + * this speed is fast enough. + */ + if (freq == freqmax) + break; + } + } + + /* If same frequency chosen as previous then done. */ + } while (freq != prevfreq); + + return freq; +} + +static unsigned int freq_to_above_hispeed_delay(struct sugov_tunables *tunables, + unsigned int freq) +{ + unsigned long flags; + unsigned int ret; + int i; + + spin_lock_irqsave(&tunables->above_hispeed_delay_lock, flags); + + for (i = 0; i < tunables->nabove_hispeed_delay - 1 && + freq >= tunables->above_hispeed_delay[i + 1]; i += 2) + ; + + ret = tunables->above_hispeed_delay[i]; + spin_unlock_irqrestore(&tunables->above_hispeed_delay_lock, flags); + return ret; +} + +static bool sugov_time_limit(struct sugov_policy *sg_policy, + unsigned int next_freq, unsigned int flags) +{ + u64 delta_ns; + bool skip_hispeed_delay = false; + unsigned int delay; + +#ifdef OPLUS_FEATURE_SCHED_ASSIST + if((flags & SCHED_CPUFREQ_BOOST) || (flags & SCHED_CPUFREQ_RESET)) + return false; +#endif + if (flags & SCHED_CPUFREQ_EARLY_DET || + flags & SCHED_CPUFREQ_MIGRATION || + flags & SCHED_CPUFREQ_INTERCLUSTER_MIG) + skip_hispeed_delay = true; + + if (sg_policy->after_limits_changed) { + skip_hispeed_delay = true; + sg_policy->after_limits_changed = false; + } + + if (!skip_hispeed_delay && next_freq > sg_policy->next_freq && + sg_policy->next_freq >= sg_policy->tunables->hispeed_freq) { + delta_ns = sg_policy->update_time - + sg_policy->hispeed_validate_time; + delay = freq_to_above_hispeed_delay(sg_policy->tunables, + sg_policy->next_freq); + if (delta_ns < NSEC_PER_USEC * delay) { + trace_sugov_time_limit(cpumask_first(sg_policy->policy->cpus), + "above_hispeed_delay", delta_ns, + sg_policy->next_freq, next_freq); + return true; + } + } + + sg_policy->hispeed_validate_time = sg_policy->update_time; + return false; +} +#endif + /** * get_next_freq - Compute a new frequency for a given cpufreq policy. * @sg_policy: schedutil policy object to compute the new frequency for. @@ -302,8 +524,16 @@ static unsigned int get_next_freq(struct sugov_policy *sg_policy, unsigned int freq = arch_scale_freq_invariant() ? policy->cpuinfo.max_freq : policy->cur; +#ifdef OPLUS_FEATURE_POWER_CPUFREQ + unsigned int prev_freq = freq; + unsigned int prev_laf = prev_freq * util * 100 / max; + + freq = choose_freq(sg_policy, prev_laf); + trace_sugov_next_freq_tl(policy->cpu, util, max, freq, prev_laf, prev_freq); +#else freq = map_util_freq(util, freq, max); trace_sugov_next_freq(policy->cpu, util, max, freq); +#endif if (freq == sg_policy->cached_raw_freq && !sg_policy->need_freq_update) return sg_policy->next_freq; @@ -637,8 +867,15 @@ static void sugov_walt_adjust(struct sugov_cpu *sg_cpu, unsigned long *util, */ static inline void ignore_dl_rate_limit(struct sugov_cpu *sg_cpu, struct sugov_policy *sg_policy) { +#ifdef OPLUS_FEATURE_POWER_CPUFREQ + if (cpu_bw_dl(cpu_rq(sg_cpu->cpu)) > sg_cpu->bw_dl) { + sg_policy->limits_changed = true; + sg_policy->after_limits_changed = true; + } +#else if (cpu_bw_dl(cpu_rq(sg_cpu->cpu)) > sg_cpu->bw_dl) sg_policy->limits_changed = true; +#endif } static inline unsigned long target_util(struct sugov_policy *sg_policy, @@ -659,6 +896,12 @@ static void sugov_update_single(struct update_util_data *hook, u64 time, unsigned long util, max, hs_util, boost_util; unsigned int next_f; bool busy; +#ifdef CONFIG_OPLUS_FEATURE_INPUT_BOOST_V4 + struct cpufreq_policy *policy = sg_policy->policy; + unsigned long fbg_boost_util = 0; + unsigned long irq_flag; + sg_policy->flags = flags; +#endif /* CONFIG_OPLUS_FEATURE_INPUT_BOOST_V4 */ if (!sg_policy->tunables->pl && flags & SCHED_CPUFREQ_PL) return; @@ -668,6 +911,11 @@ static void sugov_update_single(struct update_util_data *hook, u64 time, ignore_dl_rate_limit(sg_cpu, sg_policy); +#ifdef OPLUS_FEATURE_SCHED_ASSIST +#ifndef CONFIG_OPLUS_FEATURE_INPUT_BOOST_V4 + sg_policy->flags = flags; +#endif +#endif if (!sugov_should_update_freq(sg_policy, time)) return; @@ -675,6 +923,9 @@ static void sugov_update_single(struct update_util_data *hook, u64 time, busy = use_pelt() && !sg_policy->need_freq_update && sugov_cpu_is_busy(sg_cpu); +#ifdef CONFIG_OPLUS_FEATURE_INPUT_BOOST_V4 + raw_spin_lock_irqsave(&sg_policy->update_lock, irq_flag); +#endif /* CONFIG_OPLUS_FEATURE_INPUT_BOOST_V4 */ sg_cpu->util = util = sugov_get_util(sg_cpu); max = sg_cpu->max; sg_cpu->flags = flags; @@ -700,6 +951,11 @@ static void sugov_update_single(struct update_util_data *hook, u64 time, sg_cpu->walt_load.rtgb_active, flags); sugov_walt_adjust(sg_cpu, &util, &max); +#ifdef CONFIG_OPLUS_FEATURE_INPUT_BOOST_V4 + fbg_boost_util = sched_get_group_util(policy->cpus); + util = max(util, fbg_boost_util); + raw_spin_unlock_irqrestore(&sg_policy->update_lock, irq_flag); +#endif /* CONFIG_OPLUS_FEATURE_INPUT_BOOST_V4 */ next_f = get_next_freq(sg_policy, util, max); /* * Do not reduce the frequency if the CPU has not been idle @@ -733,6 +989,9 @@ static unsigned int sugov_next_freq_shared(struct sugov_cpu *sg_cpu, u64 time) u64 last_freq_update_time = sg_policy->last_freq_update_time; unsigned long util = 0, max = 1; unsigned int j; +#ifdef CONFIG_OPLUS_FEATURE_INPUT_BOOST_V4 + unsigned long fbg_boost_util = 0; +#endif /* CONFIG_OPLUS_FEATURE_INPUT_BOOST_V4 */ for_each_cpu(j, policy->cpus) { struct sugov_cpu *j_sg_cpu = &per_cpu(sugov_cpu, j); @@ -772,6 +1031,10 @@ static unsigned int sugov_next_freq_shared(struct sugov_cpu *sg_cpu, u64 time) sugov_walt_adjust(j_sg_cpu, &util, &max); } +#ifdef CONFIG_OPLUS_FEATURE_INPUT_BOOST_V4 + fbg_boost_util = sched_get_group_util(policy->cpus); + util = max(util, fbg_boost_util); +#endif /* CONFIG_OPLUS_FEATURE_INPUT_BOOST_V4 */ return get_next_freq(sg_policy, util, max); } @@ -782,13 +1045,23 @@ sugov_update_shared(struct update_util_data *hook, u64 time, unsigned int flags) struct sugov_policy *sg_policy = sg_cpu->sg_policy; unsigned long hs_util, boost_util; unsigned int next_f; +#ifdef CONFIG_OPLUS_FEATURE_INPUT_BOOST_V4 + unsigned long irq_flag; +#endif /* CONFIG_OPLUS_FEATURE_INPUT_BOOST_V4 */ if (!sg_policy->tunables->pl && flags & SCHED_CPUFREQ_PL) return; +#ifdef CONFIG_OPLUS_FEATURE_INPUT_BOOST_V4 + raw_spin_lock_irqsave(&sg_policy->update_lock, irq_flag); + sg_cpu->util = sugov_get_util(sg_cpu); + sg_cpu->flags = flags; + sg_policy->flags = flags; +#else sg_cpu->util = sugov_get_util(sg_cpu); sg_cpu->flags = flags; raw_spin_lock(&sg_policy->update_lock); +#endif /* CONFIG_OPLUS_FEATURE_INPUT_BOOST_V4 */ if (sg_policy->max != sg_cpu->max) { sg_policy->max = sg_cpu->max; @@ -813,17 +1086,34 @@ sugov_update_shared(struct update_util_data *hook, u64 time, unsigned int flags) sg_cpu->walt_load.pl, sg_cpu->walt_load.rtgb_active, flags); +#ifdef OPLUS_FEATURE_SCHED_ASSIST +#ifndef CONFIG_OPLUS_FEATURE_INPUT_BOOST_V4 + sg_policy->flags = flags; +#endif /* CONFIG_OPLUS_FEATURE_INPUT_BOOST_V4 */ +#endif if (sugov_should_update_freq(sg_policy, time) && !(flags & SCHED_CPUFREQ_CONTINUE)) { next_f = sugov_next_freq_shared(sg_cpu, time); +#ifdef OPLUS_FEATURE_POWER_CPUFREQ + sg_policy->update_time = time; + if (sugov_time_limit(sg_policy, next_f, flags)) + goto out; +#endif if (sg_policy->policy->fast_switch_enabled) sugov_fast_switch(sg_policy, time, next_f); else sugov_deferred_update(sg_policy, time, next_f); } +#ifdef OPLUS_FEATURE_POWER_CPUFREQ +out: +#endif +#ifdef CONFIG_OPLUS_FEATURE_INPUT_BOOST_V4 + raw_spin_unlock_irqrestore(&sg_policy->update_lock, irq_flag); +#else raw_spin_unlock(&sg_policy->update_lock); +#endif /* CONFIG_OPLUS_FEATURE_INPUT_BOOST_V4 */ } static void sugov_work(struct kthread_work *work) @@ -1041,10 +1331,145 @@ static ssize_t pl_store(struct gov_attr_set *attr_set, const char *buf, return count; } +#ifdef OPLUS_FEATURE_POWER_CPUFREQ +static ssize_t target_loads_show(struct gov_attr_set *attr_set, char *buf) +{ + struct sugov_tunables *tunables = to_sugov_tunables(attr_set); + int i; + ssize_t ret = 0; + unsigned long flags; + + spin_lock_irqsave(&tunables->target_loads_lock, flags); + for (i = 0; i < tunables->ntarget_loads; i++) + ret += snprintf(buf + ret, sizeof(buf), "%u%s", tunables->target_loads[i], + i & 0x1 ? ":" : " "); + snprintf(buf + ret - 1, sizeof(buf), "\n"); + spin_unlock_irqrestore(&tunables->target_loads_lock, flags); + return ret; +} + +static unsigned int *get_tokenized_data(const char *buf, int *num_tokens) +{ + const char *cp; + int i; + int ntokens = 1; + unsigned int *tokenized_data; + int err = -EINVAL; + + cp = buf; + while ((cp = strpbrk(cp + 1, " :"))) + ntokens++; + + if (!(ntokens & 0x1)) + goto err; + + tokenized_data = kmalloc(ntokens * sizeof(unsigned int), GFP_KERNEL); + if (!tokenized_data) { + err = -ENOMEM; + goto err; + } + + cp = buf; + i = 0; + while (i < ntokens) { + if (sscanf(cp, "%u", &tokenized_data[i++]) != 1) + goto err_kfree; + + cp = strpbrk(cp, " :"); + if (!cp) + break; + cp++; + } + + if (i != ntokens) + goto err_kfree; + + *num_tokens = ntokens; + + return tokenized_data; +err_kfree: + kfree(tokenized_data); +err: + return ERR_PTR(err); +} + +static ssize_t target_loads_store(struct gov_attr_set *attr_set, const char *buf, + size_t count) +{ + int ntokens; + unsigned int *new_target_loads = NULL; + unsigned long flags; + struct sugov_tunables *tunables = to_sugov_tunables(attr_set); + + new_target_loads = get_tokenized_data(buf, &ntokens); + if (IS_ERR(new_target_loads)) + return PTR_ERR(new_target_loads); + + spin_lock_irqsave(&tunables->target_loads_lock, flags); + if (tunables->target_loads != default_target_loads) + kfree(tunables->target_loads); + + tunables->target_loads = new_target_loads; + tunables->ntarget_loads = ntokens; + spin_unlock_irqrestore(&tunables->target_loads_lock, flags); + + return count; +} + +static ssize_t above_hispeed_delay_store(struct gov_attr_set *attr_set, + const char *buf, size_t count) +{ + struct sugov_tunables *tunables = to_sugov_tunables(attr_set); + unsigned int *new_above_hispeed_delay = NULL; + unsigned long flags; + int ntokens; + + new_above_hispeed_delay = get_tokenized_data(buf, &ntokens); + if (IS_ERR(new_above_hispeed_delay)) + return PTR_ERR(new_above_hispeed_delay); + + spin_lock_irqsave(&tunables->above_hispeed_delay_lock, flags); + if (tunables->above_hispeed_delay != default_above_hispeed_delay) + kfree(tunables->above_hispeed_delay); + tunables->above_hispeed_delay = new_above_hispeed_delay; + tunables->nabove_hispeed_delay = ntokens; + spin_unlock_irqrestore(&tunables->above_hispeed_delay_lock, flags); + + return count; +} + +static ssize_t above_hispeed_delay_show(struct gov_attr_set *attr_set, + char *buf) +{ + struct sugov_tunables *tunables = to_sugov_tunables(attr_set); + unsigned long flags; + ssize_t ret = 0; + int i; + + spin_lock_irqsave(&tunables->above_hispeed_delay_lock, flags); + + for (i = 0; i < tunables->nabove_hispeed_delay; i++) + ret += snprintf(buf + ret, PAGE_SIZE - ret, "%u%s", + tunables->above_hispeed_delay[i], + i & 0x1 ? ":" : " "); + + snprintf(buf + ret - 1, PAGE_SIZE - ret + 1, "\n"); + spin_unlock_irqrestore(&tunables->above_hispeed_delay_lock, flags); + + return ret; +} +#endif + static struct governor_attr hispeed_load = __ATTR_RW(hispeed_load); static struct governor_attr hispeed_freq = __ATTR_RW(hispeed_freq); static struct governor_attr rtg_boost_freq = __ATTR_RW(rtg_boost_freq); static struct governor_attr pl = __ATTR_RW(pl); +#ifdef OPLUS_FEATURE_POWER_CPUFREQ +static struct governor_attr target_loads = + __ATTR(target_loads, 0664, target_loads_show, target_loads_store); +static struct governor_attr above_hispeed_delay = + __ATTR_RW(above_hispeed_delay); +#endif static struct attribute *sugov_attributes[] = { &up_rate_limit_us.attr, @@ -1053,6 +1478,10 @@ static struct attribute *sugov_attributes[] = { &hispeed_freq.attr, &rtg_boost_freq.attr, &pl.attr, +#ifdef OPLUS_FEATURE_POWER_CPUFREQ + &target_loads.attr, + &above_hispeed_delay.attr, +#endif NULL }; @@ -1177,6 +1606,10 @@ static void sugov_tunables_save(struct cpufreq_policy *policy, cached->hispeed_freq = tunables->hispeed_freq; cached->up_rate_limit_us = tunables->up_rate_limit_us; cached->down_rate_limit_us = tunables->down_rate_limit_us; +#ifdef OPLUS_FEATURE_POWER_CPUFREQ + cached->above_hispeed_delay = tunables->above_hispeed_delay; + cached->nabove_hispeed_delay = tunables->nabove_hispeed_delay; +#endif } static void sugov_clear_global_tunables(void) @@ -1200,6 +1633,10 @@ static void sugov_tunables_restore(struct cpufreq_policy *policy) tunables->hispeed_freq = cached->hispeed_freq; tunables->up_rate_limit_us = cached->up_rate_limit_us; tunables->down_rate_limit_us = cached->down_rate_limit_us; +#ifdef OPLUS_FEATURE_POWER_CPUFREQ + tunables->above_hispeed_delay = cached->above_hispeed_delay; + tunables->nabove_hispeed_delay = cached->nabove_hispeed_delay; +#endif } static int sugov_init(struct cpufreq_policy *policy) @@ -1249,6 +1686,15 @@ static int sugov_init(struct cpufreq_policy *policy) tunables->down_rate_limit_us = cpufreq_policy_transition_delay_us(policy); tunables->hispeed_load = DEFAULT_HISPEED_LOAD; tunables->hispeed_freq = 0; +#ifdef OPLUS_FEATURE_POWER_CPUFREQ + tunables->target_loads = default_target_loads; + tunables->ntarget_loads = ARRAY_SIZE(default_target_loads); + spin_lock_init(&tunables->target_loads_lock); + tunables->above_hispeed_delay = default_above_hispeed_delay; + tunables->nabove_hispeed_delay = + ARRAY_SIZE(default_above_hispeed_delay); + spin_lock_init(&tunables->above_hispeed_delay_lock); +#endif switch (policy->cpu) { default: @@ -1340,6 +1786,16 @@ static int sugov_start(struct cpufreq_policy *policy) sg_policy->limits_changed = false; sg_policy->need_freq_update = false; sg_policy->cached_raw_freq = 0; +#ifdef OPLUS_FEATURE_POWER_CPUFREQ + sg_policy->hispeed_validate_time = 0; + sg_policy->update_time = 0; + sg_policy->freq_locked = false; + sg_policy->min_freq = policy->min; + sg_policy->after_limits_changed = false; +#endif +#if defined(OPLUS_FEATURE_SCHED_ASSIST) || defined(CONFIG_OPLUS_FEATURE_INPUT_BOOST_V4) + sg_policy->flags = 0; +#endif sg_policy->prev_cached_raw_freq = 0; for_each_cpu(cpu, policy->cpus) { @@ -1385,6 +1841,9 @@ static void sugov_limits(struct cpufreq_policy *policy) struct sugov_policy *sg_policy = policy->governor_data; unsigned long flags, now; unsigned int freq; +#ifdef OPLUS_FEATURE_POWER_CPUFREQ + s64 delta; +#endif if (!policy->fast_switch_enabled) { mutex_lock(&sg_policy->work_lock); @@ -1409,6 +1868,23 @@ static void sugov_limits(struct cpufreq_policy *policy) raw_spin_unlock_irqrestore(&sg_policy->update_lock, flags); } +#ifdef OPLUS_FEATURE_POWER_CPUFREQ + if (policy->min == policy->cpuinfo.max_freq && + policy->min > sg_policy->min_freq) { + sg_policy->start_time = ktime_get(); + sg_policy->freq_locked = true; + } else if (sg_policy->freq_locked && policy->min < policy->max) { + now = ktime_get(); + delta = ktime_to_ns(ktime_sub(now, sg_policy->start_time)); + if (delta >= 8 * NSEC_PER_SEC) + pr_warn("policy%d's freq locked at max_freq for %lld(ns)", + cpumask_first(policy->related_cpus), delta); + sg_policy->freq_locked = false; + } + sg_policy->min_freq = policy->min; + sg_policy->after_limits_changed = true; +#endif + sg_policy->limits_changed = true; } diff --git a/kernel/sched/cpupri.c b/kernel/sched/cpupri.c index 8ad7003de0c9..123aec5c8cff 100644 --- a/kernel/sched/cpupri.c +++ b/kernel/sched/cpupri.c @@ -66,6 +66,12 @@ drop_nopreempt_cpus(struct cpumask *lowest_mask) } } +#ifdef OPLUS_FEATURE_SCHED_ASSIST +#include +extern void drop_ux_task_cpus(struct task_struct *p, struct cpumask *lowest_mask); +extern void kick_min_cpu_from_mask(struct cpumask *lowest_mask); +extern bool sf_task_misfit(struct task_struct *p); +#endif /* OPLUS_FEATURE_SCHED_ASSIST */ /** * cpupri_find - find the best (lowest-pri) CPU in the system * @cp: The cpupri context @@ -87,7 +93,9 @@ int cpupri_find(struct cpupri *cp, struct task_struct *p, int idx = 0; int task_pri = convert_prio(p->prio); bool drop_nopreempts = task_pri <= MAX_RT_PRIO; - +#ifdef OPLUS_FEATURE_SCHED_ASSIST + bool drop_uxtasks = sysctl_sched_assist_enabled; +#endif /* OPLUS_FEATURE_SCHED_ASSIST */ BUG_ON(task_pri >= CPUPRI_NR_PRIORITIES); retry: @@ -130,6 +138,12 @@ retry: cpu_isolated_mask); if (drop_nopreempts) drop_nopreempt_cpus(lowest_mask); +#ifdef OPLUS_FEATURE_SCHED_ASSIST + if (drop_uxtasks) + drop_ux_task_cpus(p, lowest_mask); + if (drop_uxtasks && sf_task_misfit(p)) + kick_min_cpu_from_mask(lowest_mask); +#endif /* OPLUS_FEATURE_SCHED_ASSIST */ /* * We have to ensure that we have at least one bit * still set in the array, since the map could have @@ -152,6 +166,13 @@ retry: drop_nopreempts = false; goto retry; } +#ifdef OPLUS_FEATURE_SCHED_ASSIST + if (drop_uxtasks) { + drop_uxtasks = false; + goto retry; + } +#endif /* OPLUS_FEATURE_SCHED_ASSIST */ + return 0; } diff --git a/kernel/sched/cputime.c b/kernel/sched/cputime.c index 4cfa1e980a83..7b2e58e55f15 100644 --- a/kernel/sched/cputime.c +++ b/kernel/sched/cputime.c @@ -4,6 +4,17 @@ #include #include "sched.h" #include "walt.h" +#ifdef OPLUS_FEATURE_TASK_CPUSTATS +#ifdef CONFIG_OPLUS_CTP +#include +#endif +#ifdef CONFIG_OPLUS_SCHED +#include +#endif +#endif +#if IS_ENABLED(CONFIG_OPLUS_FEATURE_CPU_JANKINFO) +#include +#endif #ifdef CONFIG_IRQ_TIME_ACCOUNTING @@ -402,15 +413,34 @@ static void irqtime_account_process_tick(struct task_struct *p, int user_tick, * Also, p->stime needs to be updated for ksoftirqd. */ account_system_index_time(p, cputime, CPUTIME_SOFTIRQ); +#ifdef OPLUS_FEATURE_TASK_CPUSTATS +/* stat cpu usage on each tick. */ + account_task_time(p, ticks, CPUTIME_SOFTIRQ); +#endif /* OPLUS_FEATURE_TASK_CPUSTATS */ } else if (user_tick) { account_user_time(p, cputime); +#ifdef OPLUS_FEATURE_TASK_CPUSTATS +/* stat cpu usage on each tick. */ + account_task_time(p, ticks, CPUTIME_USER); +#endif /* OPLUS_FEATURE_TASK_CPUSTATS */ } else if (p == rq->idle) { account_idle_time(cputime); } else if (p->flags & PF_VCPU) { /* System time or guest time */ account_guest_time(p, cputime); +#ifdef OPLUS_FEATURE_TASK_CPUSTATS +/* stat cpu usage on each tick. */ + account_task_time(p, ticks, CPUTIME_USER); +#endif /* OPLUS_FEATURE_TASK_CPUSTATS */ } else { account_system_index_time(p, cputime, CPUTIME_SYSTEM); +#ifdef OPLUS_FEATURE_TASK_CPUSTATS +/* stat cpu usage on each tick. */ + account_task_time(p, ticks, CPUTIME_SYSTEM); +#endif /* OPLUS_FEATURE_TASK_CPUSTATS */ } +#if IS_ENABLED(CONFIG_OPLUS_FEATURE_CPU_JANKINFO) + jankinfo_update_time_info(rq, p, ticks*TICK_NSEC); +#endif } static void irqtime_account_idle_ticks(int ticks) @@ -500,6 +530,13 @@ void account_process_tick(struct task_struct *p, int user_tick) u64 cputime, steal; struct rq *rq = this_rq(); +#if defined(OPLUS_FEATURE_TASK_CPUSTATS) && defined(CONFIG_OPLUS_SCHED) + if (ctp_send_message) { + sched_action_trig(); + ctp_send_message = false; + } +#endif /* defined(OPLUS_FEATURE_TASK_CPUSTATS) && defined(CONFIG_OPLUS_SCHED) */ + if (vtime_accounting_cpu_enabled()) return; diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index 99fe69597452..bfd5a9b93560 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -26,6 +26,47 @@ #include "walt.h" +#ifdef OPLUS_FEATURE_SCHED_ASSIST +#include +#include +#endif /* OPLUS_FEATURE_SCHED_ASSIST */ + +#ifdef OPLUS_FEATURE_SCHED_ASSIST +#include +#endif +#ifdef OPLUS_FEATURE_SCHED_ASSIST +extern unsigned int walt_scale_demand_divisor; +bool ux_task_misfit(struct task_struct *p, int cpu); +#define scale_demand(d) ((d)/walt_scale_demand_divisor) +#endif /* OPLUS_FEATURE_SCHED_ASSIST */ + +#ifdef CONFIG_OPLUS_FEATURE_GAME_OPT +#include "../../drivers/soc/oplus/game_opt/game_ctrl.h" +#endif + +#ifdef OPLUS_FEATURE_SCHED_ASSIST +bool prefer_silver_check_freq(int cpu); +bool prefer_silver_check_task_util(struct task_struct *p); +bool prefer_silver_check_cpu_util(int cpu); +#endif + +#ifdef OPLUS_FEATURE_HEALTHINFO +// Add for get cpu load +#ifdef CONFIG_OPLUS_HEALTHINFO +#include +#endif +#endif /* OPLUS_FEATURE_HEALTHINFO */ + +#if IS_ENABLED(CONFIG_OPLUS_FEATURE_CPU_JANKINFO) +#include +#endif +#if defined(OPLUS_FEATURE_TASK_CPUSTATS) && defined(CONFIG_OPLUS_SCHED) +#include +#endif /* defined(OPLUS_FEATURE_TASK_CPUSTATS) && defined(CONFIG_OPLUS_SCHED) */ + +#if defined(OPLUS_FEATURE_IOMONITOR) && defined(CONFIG_IOMONITOR) +#include +#endif /*OPLUS_FEATURE_IOMONITOR*/ #ifdef CONFIG_SMP static inline bool task_fits_max(struct task_struct *p, int cpu); #endif /* CONFIG_SMP */ @@ -61,6 +102,10 @@ walt_dec_cfs_rq_stats(struct cfs_rq *cfs_rq, struct task_struct *p) {} #endif +#ifdef CONFIG_OPLUS_FEATURE_TPD +#include +#endif + /* * Targeted preemption latency for CPU-bound tasks: * @@ -874,6 +919,15 @@ static void update_tg_load_avg(struct cfs_rq *cfs_rq, int force) { } #endif /* CONFIG_SMP */ +#ifdef OPLUS_FEATURE_HEALTHINFO +#ifdef CONFIG_OPLUS_JANK_INFO +extern void update_jank_trace_info(struct task_struct *tsk, int trace_type, unsigned int cpu, u64 delta); +#endif +#endif /* OPLUS_FEATURE_HEALTHINFO */ + +#ifdef CONFIG_OPLUS_FEATURE_TPP +#include +#endif /* CONFIG_OPLUS_FEATURE_TPP */ /* * Update the current task's runtime statistics. @@ -904,10 +958,20 @@ static void update_curr(struct cfs_rq *cfs_rq) if (entity_is_task(curr)) { struct task_struct *curtask = task_of(curr); - +#ifdef CONFIG_OPLUS_FEATURE_GAME_OPT + g_update_task_runtime(curtask, delta_exec); +#endif trace_sched_stat_runtime(curtask, delta_exec, curr->vruntime); +#if IS_ENABLED(CONFIG_OPLUS_FEATURE_CPU_JANKINFO) + jankinfo_tasktrack_update_time(curtask, TRACE_RUNNING, delta_exec); +#endif cgroup_account_cputime(curtask, delta_exec); account_group_exec_runtime(curtask, delta_exec); +#ifdef OPLUS_FEATURE_HEALTHINFO +#ifdef CONFIG_OPLUS_JANK_INFO + update_jank_trace_info(curtask, JANK_TRACE_RUNNING, cpu_of(rq_of(cfs_rq)), delta_exec); +#endif +#endif /* OPLUS_FEATURE_HEALTHINFO */ } account_cfs_rq_runtime(cfs_rq, delta_exec); @@ -959,6 +1023,28 @@ update_stats_wait_end(struct cfs_rq *cfs_rq, struct sched_entity *se) return; } trace_sched_stat_wait(p, delta); +#if IS_ENABLED(CONFIG_OPLUS_FEATURE_CPU_JANKINFO) + jankinfo_tasktrack_update_time(p, TRACE_RUNNABLE, delta); +#endif + +#if defined(OPLUS_FEATURE_TASK_CPUSTATS) && defined(CONFIG_OPLUS_SCHED) + update_task_sched_info(p, delta, task_sched_info_runnable, cpu_of(rq_of(cfs_rq))); +#endif /* defined(OPLUS_FEATURE_TASK_CPUSTATS) && defined(CONFIG_OPLUS_SCHED) */ + +#ifdef OPLUS_FEATURE_HEALTHINFO +// Add for get sched latency stat +#ifdef CONFIG_OPLUS_HEALTHINFO + ohm_schedstats_record(OHM_SCHED_SCHEDLATENCY, p, (delta >> 20)); +#endif +#endif /* OPLUS_FEATURE_HEALTHINFO */ +#ifdef OPLUS_FEATURE_HEALTHINFO +#ifdef CONFIG_OPLUS_JANK_INFO + update_jank_trace_info(p, JANK_TRACE_RUNNABLE, 0, delta); +#endif +#endif /* OPLUS_FEATURE_HEALTHINFO */ +#ifdef CONFIG_OPLUS_FEATURE_AUDIO_OPT + sched_assist_update_record(p, delta, TST_RUNNABLE); +#endif } __schedstat_set(se->statistics.wait_max, @@ -998,6 +1084,22 @@ update_stats_enqueue_sleeper(struct cfs_rq *cfs_rq, struct sched_entity *se) if (tsk) { account_scheduler_latency(tsk, delta >> 10, 1); trace_sched_stat_sleep(tsk, delta); +#if IS_ENABLED(CONFIG_OPLUS_FEATURE_CPU_JANKINFO) + jankinfo_tasktrack_update_time(tsk, TRACE_SLEEPING, delta); +#endif + +#if defined(OPLUS_FEATURE_TASK_CPUSTATS) && defined(CONFIG_OPLUS_SCHED) + update_task_sched_info(tsk, delta, task_sched_info_S, task_cpu(tsk)); +#endif /* defined(OPLUS_FEATURE_TASK_CPUSTATS) && defined(CONFIG_OPLUS_SCHED) */ + +#ifdef OPLUS_FEATURE_HEALTHINFO +#ifdef CONFIG_OPLUS_JANK_INFO + update_jank_trace_info(tsk, JANK_TRACE_SSTATE, 0, delta); +#endif +#endif /* OPLUS_FEATURE_HEALTHINFO */ +#ifdef CONFIG_OPLUS_FEATURE_AUDIO_OPT + sched_assist_update_record(tsk, delta, TST_SLEEP); +#endif } } if (block_start) { @@ -1009,6 +1111,13 @@ update_stats_enqueue_sleeper(struct cfs_rq *cfs_rq, struct sched_entity *se) if (unlikely(delta > schedstat_val(se->statistics.block_max))) __schedstat_set(se->statistics.block_max, delta); +#if defined(OPLUS_FEATURE_TASK_CPUSTATS) && defined(CONFIG_OPLUS_SCHED) + if (tsk->in_iowait) + update_task_sched_info(tsk, delta, task_sched_info_IO, task_cpu(tsk)); + else + update_task_sched_info(tsk, delta, task_sched_info_D, task_cpu(tsk)); +#endif /* defined(OPLUS_FEATURE_TASK_CPUSTATS) && defined(CONFIG_OPLUS_SCHED) */ + __schedstat_set(se->statistics.block_start, 0); __schedstat_add(se->statistics.sum_sleep_runtime, delta); @@ -1017,9 +1126,41 @@ update_stats_enqueue_sleeper(struct cfs_rq *cfs_rq, struct sched_entity *se) __schedstat_add(se->statistics.iowait_sum, delta); __schedstat_inc(se->statistics.iowait_count); trace_sched_stat_iowait(tsk, delta); +#if IS_ENABLED(CONFIG_OPLUS_FEATURE_CPU_JANKINFO) + jankinfo_tasktrack_update_time(tsk, TRACE_DISKSLEEP_INIOWAIT, delta); +#endif +#ifdef OPLUS_FEATURE_HEALTHINFO +// Add for get iowait +#ifdef CONFIG_OPLUS_HEALTHINFO + ohm_schedstats_record(OHM_SCHED_IOWAIT, tsk, (delta >> 20)); +#endif +#endif /* OPLUS_FEATURE_HEALTHINFO */ +#if defined(OPLUS_FEATURE_IOMONITOR) && defined(CONFIG_IOMONITOR) + iomonitor_record_iowait(tsk, (delta >> 20)); +#endif /*OPLUS_FEATURE_IOMONITOR*/ } - +#ifdef OPLUS_FEATURE_HEALTHINFO +#ifdef CONFIG_OPLUS_HEALTHINFO + if(!tsk->in_iowait) { + ohm_schedstats_record(OHM_SCHED_DSTATE, tsk, (delta >> 20)); + } +#endif +#endif /* OPLUS_FEATURE_HEALTHINFO */ +#ifdef OPLUS_FEATURE_HEALTHINFO +#ifdef CONFIG_OPLuS_JANK_INFO + update_jank_trace_info(tsk, JANK_TRACE_DSTATE, 0, delta); +#endif +#endif /* OPLUS_FEATURE_HEALTHINFO */ +#ifdef CONFIG_OPLUS_FEATURE_AUDIO_OPT + sched_assist_update_record(tsk, delta, TST_SLEEP); +#endif +#ifdef CONFIG_OPLUS_FEATURE_GAME_OPT + g_sched_stat_blocked(tsk, delta); +#endif trace_sched_stat_blocked(tsk, delta); +#if IS_ENABLED(CONFIG_OPLUS_FEATURE_CPU_JANKINFO) + jankinfo_tasktrack_update_time(tsk, TRACE_DISKSLEEP, delta); +#endif trace_sched_blocked_reason(tsk); /* @@ -3930,6 +4071,16 @@ bias_to_this_cpu(struct task_struct *p, int cpu, int start_cpu) bool start_cap_test = (capacity_orig_of(cpu) >= capacity_orig_of(start_cpu)); +#ifdef CONFIG_OPLUS_FEATURE_TPD + cpumask_t mask = CPU_MASK_ALL; + + if ((is_tpd_enable() && is_tpd_task(p)) || + (is_st_tpd_enable() && is_st_tpd_task(p))) { + tpd_mask(p, &mask); + + base_test = cpumask_test_cpu(cpu, &mask) && cpu_active(cpu); + } +#endif return base_test && start_cap_test; } @@ -3970,6 +4121,10 @@ static inline bool task_fits_max(struct task_struct *p, int cpu) if (task_boost > TASK_BOOST_ON_MID) return false; } +#ifdef OPLUS_FEATURE_SCHED_ASSIST + if (sched_assist_task_misfit(p, cpu, 0)) + return false; +#endif return task_fits_capacity(p, capacity, cpu); } @@ -4134,11 +4289,20 @@ place_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, int initial) vruntime -= thresh; #ifdef CONFIG_SCHED_WALT +#ifdef OPLUS_FEATURE_SCHED_ASSIST + if (entity_is_task(se)) { + if (((per_task_boost(task_of(se)) == + TASK_BOOST_STRICT_MAX) || + walt_low_latency_task(task_of(se)) || + task_rtg_high_prio(task_of(se))) && + !test_task_ux(task_of(se))) { +#else if (entity_is_task(se)) { if ((per_task_boost(task_of(se)) == TASK_BOOST_STRICT_MAX) || walt_low_latency_task(task_of(se)) || task_rtg_high_prio(task_of(se))) { +#endif vruntime -= sysctl_sched_latency; vruntime -= thresh; se->vruntime = vruntime; @@ -4150,6 +4314,9 @@ place_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, int initial) /* ensure we never gain time by being placed backwards. */ se->vruntime = max_vruntime(se->vruntime, vruntime); +#ifdef OPLUS_FEATURE_SCHED_ASSIST + place_entity_adjust_ux_task(cfs_rq, se, initial); +#endif } static void check_enqueue_throttle(struct cfs_rq *cfs_rq); @@ -4242,7 +4409,11 @@ enqueue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, int flags) enqueue_runnable_load_avg(cfs_rq, se); account_entity_enqueue(cfs_rq, se); +#if defined(OPLUS_FEATURE_SCHED_ASSIST) && defined(CONFIG_OPLUS_FEATURE_SCHED_SPREAD) + if (flags & ENQUEUE_WAKEUP || should_force_adjust_vruntime(se)) +#else if (flags & ENQUEUE_WAKEUP) +#endif place_entity(cfs_rq, se, 0); check_schedstat_required(); @@ -4369,6 +4540,11 @@ check_preempt_tick(struct cfs_rq *cfs_rq, struct sched_entity *curr) ideal_runtime = sched_slice(cfs_rq, curr); delta_exec = curr->sum_exec_runtime - curr->prev_sum_exec_runtime; +#ifdef OPLUS_FEATURE_SCHED_ASSIST + if (is_heavy_load_task(current)) + ideal_runtime = HEAVY_LOAD_RUNTIME; +#endif + if (delta_exec > ideal_runtime) { resched_curr(rq_of(cfs_rq)); /* @@ -4378,6 +4554,10 @@ check_preempt_tick(struct cfs_rq *cfs_rq, struct sched_entity *curr) clear_buddies(cfs_rq, curr); return; } +#ifdef OPLUS_FEATURE_SCHED_ASSIST + if (is_heavy_load_task(current)) + return; +#endif /* * Ensure that a task that missed wakeup preemption by a @@ -4453,6 +4633,16 @@ pick_next_entity(struct cfs_rq *cfs_rq, struct sched_entity *curr) left = curr; se = left; /* ideally we run the leftmost entity */ +#ifdef OPLUS_FEATURE_SCHED_ASSIST + if (should_ux_task_skip_further_check(se)) + return se; + +#ifdef CONFIG_OPLUS_FEATURE_AUDIO_OPT + if (sched_assist_pick_next_entity(cfs_rq, &se)) { + goto oplus_pick; + } +#endif /* CONFIG_OPLUS_FEATURE_AUDIO_OPT */ +#endif /* * Avoid running the skip buddy, if running something else can @@ -4485,6 +4675,9 @@ pick_next_entity(struct cfs_rq *cfs_rq, struct sched_entity *curr) if (cfs_rq->next && wakeup_preempt_entity(cfs_rq->next, left) < 1) se = cfs_rq->next; +#ifdef CONFIG_OPLUS_FEATURE_AUDIO_OPT +oplus_pick: +#endif /* CONFIG_OPLUS_FEATURE_AUDIO_OPT */ clear_buddies(cfs_rq, se); return se; @@ -5531,6 +5724,9 @@ enqueue_task_fair(struct rq *rq, struct task_struct *p, int flags) flags = ENQUEUE_WAKEUP; } +#ifdef OPLUS_FEATURE_SCHED_ASSIST + enqueue_ux_thread(rq, p); +#endif for_each_sched_entity(se) { cfs_rq = cfs_rq_of(se); @@ -5547,6 +5743,9 @@ enqueue_task_fair(struct rq *rq, struct task_struct *p, int flags) if (!se) { add_nr_running(rq, 1); inc_rq_walt_stats(rq, p); +#if defined(OPLUS_FEATURE_SCHED_ASSIST) && defined(CONFIG_OPLUS_FEATURE_SCHED_SPREAD) + inc_ld_stats(p, rq); +#endif /* * Since new tasks are assigned an initial util_avg equal to * half of the spare capacity of their CPU, tiny tasks have the @@ -5583,6 +5782,9 @@ enqueue_task_fair(struct rq *rq, struct task_struct *p, int flags) assert_list_leaf_cfs_rq(rq); hrtick_update(rq); +#ifdef CONFIG_OPLUS_FEATURE_TPP + tpp_enqueue(cpu_of(rq), p); +#endif /* CONFIG_OPLUS_FEATURE_TPP */ } static void set_next_buddy(struct sched_entity *se); @@ -5635,6 +5837,9 @@ static void dequeue_task_fair(struct rq *rq, struct task_struct *p, int flags) } flags |= DEQUEUE_SLEEP; } +#ifdef OPLUS_FEATURE_SCHED_ASSIST + dequeue_ux_thread(rq, p); +#endif for_each_sched_entity(se) { cfs_rq = cfs_rq_of(se); @@ -5651,10 +5856,21 @@ static void dequeue_task_fair(struct rq *rq, struct task_struct *p, int flags) if (!se) { sub_nr_running(rq, 1); dec_rq_walt_stats(rq, p); +#if defined(OPLUS_FEATURE_SCHED_ASSIST) && defined(CONFIG_OPLUS_FEATURE_SCHED_SPREAD) + dec_ld_stats(p, rq); +#endif +#ifdef CONFIG_OPLUS_FEATURE_AUDIO_OPT + if (task_sleep) { + sched_assist_update_record(p, p->se.sum_exec_runtime - p->se.prev_sum_exec_runtime, TST_EXEC); + } +#endif } util_est_dequeue(&rq->cfs, p, task_sleep); hrtick_update(rq); +#ifdef CONFIG_OPLUS_FEATURE_TPP + tpp_dequeue(cpu_of(rq), p); +#endif /* CONFIG_OPLUS_FEATURE_TPP */ } #ifdef CONFIG_SMP @@ -6214,7 +6430,11 @@ schedtune_cpu_margin_with(unsigned long util, int cpu, struct task_struct *p) static unsigned long cpu_util_without(int cpu, struct task_struct *p); +#ifdef CONFIG_OPLUS_FEATURE_INPUT_BOOST_V4 +unsigned long capacity_spare_without(int cpu, struct task_struct *p) +#else static unsigned long capacity_spare_without(int cpu, struct task_struct *p) +#endif /* CONFIG_OPLUS_FEATURE_INPUT_BOOST_V4 */ { return max_t(long, capacity_of(cpu) - cpu_util_without(cpu, p), 0); } @@ -6889,6 +7109,22 @@ static int get_start_cpu(struct task_struct *p) start_cpu = rd->mid_cap_orig_cpu == -1 ? rd->max_cap_orig_cpu : rd->mid_cap_orig_cpu; } +#ifdef OPLUS_FEATURE_SCHED_ASSIST + if (sched_assist_scene(SA_SLIDE) && is_heavy_ux_task(p) && (task_util(p) >= sysctl_boost_task_threshold || + scale_demand(p->ravg.sum) >= sysctl_boost_task_threshold)) { + start_cpu = rd->mid_cap_orig_cpu == -1 ? + rd->max_cap_orig_cpu : rd->mid_cap_orig_cpu; + } + + if (sysctl_prefer_silver && sysctl_sched_assist_enabled && !is_heavy_ux_task(p) && + prefer_silver_check_task_util(p)){ + start_cpu = rd->min_cap_orig_cpu; + } +#endif +#ifdef OPLUS_FEATURE_SCHED_ASSIST + if (sysctl_cpu_multi_thread && !is_heavy_load_task(p)) + return rd->min_cap_orig_cpu; +#endif if (task_boost > TASK_BOOST_ON_MID) { start_cpu = rd->max_cap_orig_cpu; @@ -6908,6 +7144,24 @@ static int get_start_cpu(struct task_struct *p) !task_demand_fits(p, start_cpu)) start_cpu = rd->max_cap_orig_cpu; +#ifdef CONFIG_OPLUS_FEATURE_TPD + if ((is_dynamic_tpd_task(p) || is_tpd_task(p)) && is_tpd_enable()) { + start_cpu = tpd_suggested(p, start_cpu); + } +#endif + + trace_sched_cpu_sel(p, + task_boost, + task_skip_min, + boosted, + task_boost_policy(p), + task_util(p), + cpu_util(task_cpu(p)), + test_task_ux(p), + task_demand_fits(p, rd->min_cap_orig_cpu), + sysctl_prefer_silver, + start_cpu); + return start_cpu; } @@ -6915,6 +7169,12 @@ enum fastpaths { NONE = 0, SYNC_WAKEUP, PREV_CPU_FASTPATH, +#if defined(OPLUS_FEATURE_SCHED_ASSIST) && defined(CONFIG_OPLUS_FEATURE_SCHED_SPREAD) + NR_WAKEUP_SELECT, +#endif +#ifdef CONFIG_OPLUS_FEATURE_INPUT_BOOST_V4 + FRAME_BOOST_GROUP, +#endif /* CONFIG_OPLUS_FEATURE_INPUT_BOOST_V4 */ }; static void find_best_target(struct sched_domain *sd, cpumask_t *cpus, @@ -6946,7 +7206,11 @@ static void find_best_target(struct sched_domain *sd, cpumask_t *cpus, int isolated_candidate = -1; unsigned int target_nr_rtg_high_prio = UINT_MAX; bool rtg_high_prio_task = task_rtg_high_prio(p); - + cpumask_t new_allowed_cpus; + bool skip_big_cluster = false; +#if defined(OPLUS_FEATURE_SCHED_ASSIST) && defined(CONFIG_OPLUS_FEATURE_SCHED_SPREAD) + bool strict = fbt_env->strict_max; +#endif /* * In most cases, target_capacity tracks capacity_orig of the most * energy efficient CPU candidate, thus requiring to minimise @@ -6961,7 +7225,11 @@ static void find_best_target(struct sched_domain *sd, cpumask_t *cpus, if (prefer_idle && boosted) target_capacity = 0; +#ifdef OPLUS_FEATURE_SCHED_ASSIST + if (fbt_env->strict_max || p->in_iowait ||(sysctl_cpu_multi_thread && !is_heavy_load_task(p))) +#else if (fbt_env->strict_max || p->in_iowait) +#endif most_spare_wake_cap = LONG_MIN; /* Find start CPU based on boost value */ @@ -6984,11 +7252,31 @@ static void find_best_target(struct sched_domain *sd, cpumask_t *cpus, goto target; } } - +#if defined(OPLUS_FEATURE_SCHED_ASSIST) && defined(CONFIG_OPLUS_FEATURE_SCHED_SPREAD) + /* enabled nr-balance to spread tasks */ + sched_assist_spread_tasks(p, p->cpus_allowed, fbt_env->start_cpu, fbt_env->skip_cpu, cpus, strict); + if (!cpumask_empty(cpus)) { + fbt_env->fastpath = NR_WAKEUP_SELECT; + goto out; + } +#endif /* Scan CPUs in all SDs */ sg = start_sd->groups; + + cpumask_copy(&new_allowed_cpus, &p->cpus_allowed); +#ifdef CONFIG_OPLUS_FEATURE_TPD + if ((is_tpd_enable() && is_tpd_task(p)) || + (is_st_tpd_enable() && is_st_tpd_task(p))) { + tpd_mask(p, &new_allowed_cpus); + } +#endif +#ifdef CONFIG_OPLUS_FEATURE_TPP + if (tpp_task(p)) { + cpumask_setall(&new_allowed_cpus); + } +#endif /* CONFIG_OPLUS_FEATURE_TPP */ do { - for_each_cpu_and(i, &p->cpus_allowed, sched_group_span(sg)) { + for_each_cpu_and(i, &new_allowed_cpus, sched_group_span(sg)) { unsigned long capacity_curr = capacity_curr_of(i); unsigned long capacity_orig = capacity_orig_of(i); unsigned long wake_util, new_util, new_util_cuml; @@ -7000,6 +7288,20 @@ static void find_best_target(struct sched_domain *sd, cpumask_t *cpus, if (!cpu_online(i) || cpu_isolated(i)) continue; +#ifdef OPLUS_FEATURE_SCHED_ASSIST + if (sysctl_prefer_silver && sysctl_sched_assist_enabled && !test_task_ux(p) && is_max_capacity_cpu(i)) { + if (prefer_silver_check_freq(start_cpu) && (prefer_silver_check_task_util(p) || + prefer_silver_check_cpu_util(start_cpu))) { + skip_big_cluster = true; + continue; + } + } +#endif /* OPLUS_FEATURE_SCHED_ASSIST */ +#ifdef OPLUS_FEATURE_SCHED_ASSIST + if (should_ux_task_skip_cpu(p, i)) + continue; +#endif /* OPLUS_FEATURE_SCHED_ASSIST */ + if (isolated_candidate == -1) isolated_candidate = i; @@ -7030,6 +7332,13 @@ static void find_best_target(struct sched_domain *sd, cpumask_t *cpus, most_spare_wake_cap = spare_wake_cap; most_spare_cap_cpu = i; } +#ifdef OPLUS_FEATURE_SCHED_ASSIST + else if (spare_wake_cap == most_spare_wake_cap && sysctl_cpu_multi_thread + && !is_heavy_load_task(p) + && cpu_rq(i)->nr_running < cpu_rq(most_spare_cap_cpu)->nr_running) { + most_spare_cap_cpu = i; + } +#endif if (per_task_boost(cpu_rq(i)->curr) == TASK_BOOST_STRICT_MAX) @@ -7281,7 +7590,6 @@ static void find_best_target(struct sched_domain *sd, cpumask_t *cpus, if (p->in_iowait && !next_group_higher_cap && most_spare_cap_cpu != -1) break; - /* * If we've found a cpu, but the boost is ON_ALL we continue * visiting other clusters. If the boost is ON_BIG we visit @@ -7319,6 +7627,13 @@ static void find_best_target(struct sched_domain *sd, cpumask_t *cpus, break; } } +#ifdef OPLUS_FEATURE_SCHED_ASSIST + if (sysctl_cpu_multi_thread && !is_heavy_load_task(p) + && next_group_higher_cap + && (best_idle_cpu != -1 || target_cpu != -1 || most_spare_cap_cpu != -1)) { + break; + } +#endif } while (sg = sg->next, sg != start_sd->groups); @@ -7347,6 +7662,18 @@ static void find_best_target(struct sched_domain *sd, cpumask_t *cpus, * b) IDLE CPU: best_idle_cpu */ +#ifdef OPLUS_FEATURE_SCHED_ASSIST + if (p) { + trace_sched_cpu_skip(p, + sysctl_prefer_silver, + test_task_ux(p), + prefer_silver_check_freq(start_cpu), + prefer_silver_check_task_util(p), + prefer_silver_check_cpu_util(start_cpu), + skip_big_cluster); + } +#endif + if (prefer_idle && (best_idle_cpu != -1)) { target_cpu = best_idle_cpu; goto target; @@ -7736,6 +8063,10 @@ static int find_energy_efficient_cpu(struct task_struct *p, int prev_cpu, int task_boost = per_task_boost(p); int boosted = (schedtune_task_boost(p) > 0) || (task_boost > 0); int start_cpu; +#ifdef CONFIG_OPLUS_FEATURE_INPUT_BOOST_V4 + int fbg_best_cpu; + struct cpumask *fbg_target = NULL; +#endif /* CONFIG_OPLUS_FEATURE_INPUT_BOOST_V4 */ if (is_many_wakeup(sibling_count_hint) && prev_cpu != cpu && cpumask_test_cpu(prev_cpu, &p->cpus_allowed)) @@ -7761,6 +8092,24 @@ static int find_energy_efficient_cpu(struct task_struct *p, int prev_cpu, if (sync && (need_idle || (is_rtg && curr_is_rtg))) sync = 0; +#ifdef CONFIG_OPLUS_FEATURE_INPUT_BOOST_V4 + if (!is_full_throttle_boost() && !sched_assist_scene(SA_LAUNCH)) { + fbg_target = find_rtg_target(p); + if (fbg_target) { + fbg_best_cpu = find_fbg_cpu(p); + if (fbg_best_cpu >= 0) { + best_energy_cpu = fbg_best_cpu; + fbt_env.fastpath = FRAME_BOOST_GROUP; + goto frame_done; + } + } + } +#endif /* CONFIG_OPLUS_FEATURE_INPUT_BOOST_V4 */ + +#ifdef OPLUS_FEATURE_SCHED_ASSIST + ux_skip_sync_wakeup(p, &sync); +#endif + if (sysctl_sched_sync_hint_enable && sync && bias_to_this_cpu(p, cpu, start_cpu)) { best_energy_cpu = cpu; @@ -7801,7 +8150,13 @@ static int find_energy_efficient_cpu(struct task_struct *p, int prev_cpu, } else { select_cpu_candidates(sd, candidates, pd, p, prev_cpu); } - +#if defined(OPLUS_FEATURE_SCHED_ASSIST) && defined(CONFIG_OPLUS_FEATURE_SCHED_SPREAD) + if (fbt_env.fastpath == NR_WAKEUP_SELECT) { + best_energy_cpu = cpumask_first(candidates); + rcu_read_unlock(); + goto oplus_done; + } +#endif /* Bail out if no candidate was found. */ weight = cpumask_weight(candidates); if (!weight) { @@ -7823,6 +8178,9 @@ static int find_energy_efficient_cpu(struct task_struct *p, int prev_cpu, } } } +#ifdef OPLUS_FEATURE_SCHED_ASSIST + set_ux_task_cpu_common_by_prio(p, &best_energy_cpu, true, false, 0); +#endif goto unlock; } @@ -7845,6 +8203,13 @@ static int find_energy_efficient_cpu(struct task_struct *p, int prev_cpu, goto unlock; } +#ifdef CONFIG_OPLUS_FEATURE_TPD + if (is_tpd_enable() && is_tpd_task(p)) { + best_energy_cpu = cpu; + goto unlock; + } +#endif + if (cpumask_test_cpu(prev_cpu, &p->cpus_allowed)) prev_energy = best_energy = compute_energy(p, prev_cpu, pd); else @@ -7881,7 +8246,30 @@ unlock: ((prev_energy - best_energy) <= prev_energy >> 4)) best_energy_cpu = prev_cpu; +#if defined(OPLUS_FEATURE_SCHED_ASSIST) && defined(CONFIG_OPLUS_FEATURE_SCHED_SPREAD) +oplus_done: +#endif + +#ifdef OPLUS_FEATURE_SCHED_ASSIST + if (!fbt_env.fastpath) + set_ux_task_to_prefer_cpu(p, &best_energy_cpu); +#endif /* OPLUS_FEATURE_SCHED_ASSIST */ +#ifdef OPLUS_FEATURE_SCHED_ASSIST + if (sched_assist_scene(SA_SLIDE) && is_heavy_ux_task(p) && + ux_task_misfit(p, best_energy_cpu)) { + find_ux_task_cpu(p, &best_energy_cpu); + } +#endif /* OPLUS_FEATURE_SCHED_ASSIST */ + +#ifdef CONFIG_OPLUS_FEATURE_TPP + if (tpp_task(p)) + tpp_find_cpu(&best_energy_cpu, p); +#endif /* CONFIG_OPLUS_FEATURE_TPP */ + done: +#ifdef CONFIG_OPLUS_FEATURE_INPUT_BOOST_V4 +frame_done: +#endif /* CONFIG_OPLUS_FEATURE_INPUT_BOOST_V4 */ trace_sched_task_util(p, cpumask_bits(candidates)[0], best_energy_cpu, sync, fbt_env.need_idle, fbt_env.fastpath, @@ -8150,6 +8538,10 @@ static void check_preempt_wakeup(struct rq *rq, struct task_struct *p, int wake_ if (unlikely(se == pse)) return; +#ifdef OPLUS_FEATURE_SCHED_ASSIST + if (is_heavy_load_task(current)) + return; +#endif /* * This is possible from callers such as attach_tasks(), in which we @@ -8193,6 +8585,19 @@ static void check_preempt_wakeup(struct rq *rq, struct task_struct *p, int wake_ find_matching_se(&se, &pse); update_curr(cfs_rq_of(se)); BUG_ON(!pse); +#ifdef CONFIG_OPLUS_FEATURE_AUDIO_OPT + if (unlikely(is_small_task(p))) { + if (!next_buddy_marked) + set_next_buddy(pse); + goto preempt; + } +#endif +#ifdef OPLUS_FEATURE_SCHED_ASSIST + if (should_ux_preempt_wakeup(p, curr)) + goto preempt; + else if (test_task_ux(curr)) + return; +#endif /* OPLUS_FEATURE_SCHED_ASSIST */ if (wakeup_preempt_entity(se, pse) == 1) { /* * Bias pick_next to pick the sched entity that is @@ -8230,6 +8635,9 @@ pick_next_task_fair(struct rq *rq, struct task_struct *prev, struct rq_flags *rf struct sched_entity *se; struct task_struct *p; int new_tasks; +#ifdef OPLUS_FEATURE_SCHED_ASSIST + struct task_struct *pos; +#endif again: if (!cfs_rq->nr_running) @@ -8283,6 +8691,9 @@ again: } while (cfs_rq); p = task_of(se); +#ifdef OPLUS_FEATURE_SCHED_ASSIST + pick_ux_thread(rq, &p, &se); +#endif /* * Since we haven't yet done put_prev_entity and if the selected task @@ -8318,11 +8729,23 @@ simple: do { se = pick_next_entity(cfs_rq, NULL); +#ifndef OPLUS_FEATURE_SCHED_ASSIST set_next_entity(cfs_rq, se); +#endif cfs_rq = group_cfs_rq(se); } while (cfs_rq); p = task_of(se); +#ifdef OPLUS_FEATURE_SCHED_ASSIST + pos = list_first_entry(&rq->cfs_tasks, typeof(*pos), se.group_node); + if (sysctl_cpu_multi_thread && is_heavy_load_task(pos) && p != pos) { + p = pos; + se = &p->se; + } + for_each_sched_entity(se) { + set_next_entity(cfs_rq_of(se), se); + } +#endif done: __maybe_unused; #ifdef CONFIG_SMP @@ -8695,6 +9118,15 @@ static inline int migrate_degrades_locality(struct task_struct *p, static inline bool can_migrate_boosted_task(struct task_struct *p, int src_cpu, int dst_cpu) { +#ifdef CONFIG_OPLUS_FEATURE_TPD + + if ((is_tpd_enable() && is_tpd_task(p)) || + (is_st_tpd_enable() && is_st_tpd_task(p))) { + /*avoid task migrate to wrong tpd suggested cpu*/ + if (tpd_check(p, dst_cpu)) + return false; + } +#endif if (per_task_boost(p) == TASK_BOOST_STRICT_MAX && task_in_related_thread_group(p) && (capacity_orig_of(dst_cpu) < capacity_orig_of(src_cpu))) @@ -8892,6 +9324,7 @@ static int detach_tasks(struct lb_env *env) int detached = 0; int orig_loop = env->loop; u64 start_t = rq_clock(env->src_rq); + bool skip_big_cluster = false; lockdep_assert_held(&env->src_rq->lock); @@ -8937,6 +9370,28 @@ redo: if (!can_migrate_task(p, env)) goto next; +#ifdef OPLUS_FEATURE_SCHED_ASSIST + if (sysctl_prefer_silver && sysctl_sched_assist_enabled && !test_task_ux(p) && is_max_capacity_cpu(env->dst_cpu)) { + if (prefer_silver_check_freq(env->src_cpu) && (prefer_silver_check_task_util(p) || + prefer_silver_check_cpu_util(env->src_cpu))) { + skip_big_cluster = true; + + trace_sched_cpu_skip(p, sysctl_prefer_silver, + test_task_ux(p), + prefer_silver_check_freq(env->src_cpu), + prefer_silver_check_task_util(p), + prefer_silver_check_cpu_util(env->src_cpu), + skip_big_cluster); + goto next; + } + } +#endif /* OPLUS_FEATURE_SCHED_ASSIST*/ + +#ifdef OPLUS_FEATURE_SCHED_ASSIST + if (should_ux_task_skip_cpu(p, env->dst_cpu)) + goto next; +#endif /* OPLUS_FEATURE_SCHED_ASSIST */ + /* * Depending of the number of CPUs and tasks and the * cgroup hierarchy, task_h_load() can return a null @@ -12977,6 +13432,56 @@ static inline void walt_check_for_rotation(struct rq *rq) { } #endif +#ifdef OPLUS_FEATURE_SCHED_ASSIST +bool ux_task_misfit(struct task_struct *p, int cpu) +{ + int num_mincpu = cpumask_weight(topology_core_cpumask(0)); + if ((scale_demand(p->ravg.sum) >= sysctl_boost_task_threshold || + task_util(p) >= sysctl_boost_task_threshold) && cpu < num_mincpu) + return true; + + return false; +} +#endif + +#ifdef OPLUS_FEATURE_SCHED_ASSIST +#define TRIGGER_FREQ 1516800 +bool prefer_silver_check_freq(int cpu) +{ + unsigned int freq = 0; + freq = cpufreq_quick_get(cpu); + + if (freq < TRIGGER_FREQ) { + return true; + } + + return false; +} + +bool prefer_silver_check_task_util(struct task_struct *p) +{ + int cpu; + unsigned long thresh_load; + struct reciprocal_value spc_rdiv = reciprocal_value(100); + + if (!p) + return false; + + cpu = task_cpu(p); + thresh_load = capacity_orig_of(cpu) * sysctl_heavy_task_thresh; + if(task_util(p) < reciprocal_divide(thresh_load,spc_rdiv) || + scale_demand(p->ravg.sum) < reciprocal_divide(thresh_load,spc_rdiv)) + return true; + + return false; +} + +bool prefer_silver_check_cpu_util(int cpu) +{ + return (capacity_orig_of(cpu) * sysctl_cpu_util_thresh) > + (cpu_util(cpu) * 100); +} +#endif static DEFINE_RAW_SPINLOCK(migration_lock); void check_for_migration(struct rq *rq, struct task_struct *p) @@ -12986,7 +13491,21 @@ void check_for_migration(struct rq *rq, struct task_struct *p) int prev_cpu = task_cpu(p); int ret; +#ifdef CONFIG_OPLUS_FEATURE_INPUT_BOOST_V4 + bool need_up_migrate = false; + struct cpumask *rtg_target = find_rtg_target(p); + if (rtg_target && (capacity_orig_of(prev_cpu) < capacity_orig_of(cpumask_first(rtg_target)))) { + need_up_migrate = true; + } + if (rq->misfit_task_load || need_up_migrate) { +#else +#ifdef OPLUS_FEATURE_SCHED_ASSIST + if (rq->misfit_task_load || (sched_assist_scene(SA_SLIDE) && + is_heavy_ux_task(p) && ux_task_misfit(p, prev_cpu))) { +#else if (rq->misfit_task_load) { +#endif /* OPLUS_FEATURE_SCHED_ASSIST */ +#endif /* CONFIG_OPLUS_FEATURE_INPUT_BOOST_V4 */ if (rq->curr->state != TASK_RUNNING || rq->curr->nr_cpus_allowed == 1) return; diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c index 834390c56b50..d0edeb6419f6 100644 --- a/kernel/sched/rt.c +++ b/kernel/sched/rt.c @@ -11,6 +11,10 @@ #include +#ifdef CONFIG_OPLUS_FEATURE_GAME_OPT +#include "../../drivers/soc/oplus/game_opt/game_ctrl.h" +#endif + #include "walt.h" int sched_rr_timeslice = RR_TIMESLICE; @@ -1056,6 +1060,9 @@ static void update_curr_rt(struct rq *rq) curr->se.exec_start = now; cgroup_account_cputime(curr, delta_exec); +#ifdef CONFIG_OPLUS_FEATURE_GAME_OPT + g_update_task_runtime(curr, delta_exec); +#endif if (!rt_bandwidth_enabled()) return; @@ -1879,6 +1886,10 @@ static int find_lowest_rq(struct task_struct *task) struct cpumask *lowest_mask = this_cpu_cpumask_var_ptr(local_cpu_mask); int this_cpu = smp_processor_id(); int cpu = -1; +#ifdef CONFIG_OPLUS_FEATURE_INPUT_BOOST_V4 + int fbg_best_cpu = -1; + struct cpumask *fbg_target = NULL; +#endif /* CONFIG_OPLUS_FEATURE_INPUT_BOOST_V4 */ /* Make sure the mask is initialized first */ if (unlikely(!lowest_mask)) @@ -1893,6 +1904,17 @@ static int find_lowest_rq(struct task_struct *task) if (static_branch_unlikely(&sched_energy_present)) cpu = rt_energy_aware_wake_cpu(task); +#ifdef CONFIG_OPLUS_FEATURE_INPUT_BOOST_V4 + fbg_target = find_rtg_target(task); + if(fbg_target) { + fbg_best_cpu = find_fbg_cpu(task); + if (fbg_best_cpu >= 0) { + trace_sched_fbg_rt(task, cpu, fbg_best_cpu, cpumask_bits(lowest_mask)[0]); + cpu = fbg_best_cpu; + } + } +#endif /* CONFIG_OPLUS_FEATURE_INPUT_BOOST_V4 */ + if (cpu == -1) cpu = task_cpu(task); diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h index 8b5047a5fbdf..4f0e6db302af 100644 --- a/kernel/sched/sched.h +++ b/kernel/sched/sched.h @@ -2,6 +2,9 @@ /* * Scheduler internal types and methods: */ +#ifndef __KERNEL_SCHED_H__ +#define __KERNEL_SCHED_H__ + #include #include @@ -152,6 +155,11 @@ extern cpumask_t asym_cap_sibling_cpus; #define TASK_ON_RQ_QUEUED 1 #define TASK_ON_RQ_MIGRATING 2 +#ifdef OPLUS_FEATURE_SCHED_ASSIST +//#ifdef CONFIG_UXCHAIN_V2 +extern int sysctl_uxchain_v2; +#endif + extern __read_mostly int scheduler_running; extern unsigned long calc_load_update; @@ -1121,6 +1129,9 @@ struct rq { struct cpuidle_state *idle_state; int idle_state_idx; #endif +#ifdef OPLUS_FEATURE_SCHED_ASSIST + struct list_head ux_thread_list; +#endif /* OPLUS_FEATURE_SCHED_ASSIST */ }; #ifdef CONFIG_FAIR_GROUP_SCHED @@ -2148,10 +2159,15 @@ static inline unsigned long capacity_orig_of(int cpu) { return cpu_rq(cpu)->cpu_capacity_orig; } - +#if defined OPLUS_FEATURE_SCHED_ASSIST +extern void sf_task_util_record(struct task_struct *p); +#endif static inline unsigned long task_util(struct task_struct *p) { #ifdef CONFIG_SCHED_WALT +#if defined OPLUS_FEATURE_SCHED_ASSIST + sf_task_util_record(p); +#endif return p->ravg.demand_scaled; #endif return READ_ONCE(p->se.avg.util_avg); @@ -3233,3 +3249,5 @@ struct sched_avg_stats { int nr_scaled; }; extern void sched_get_nr_running_avg(struct sched_avg_stats *stats); + +#endif // __KERNEL_SCHED_H__ \ No newline at end of file diff --git a/kernel/sched/topology.c b/kernel/sched/topology.c index c766d215d81f..0b19fe105f61 100644 --- a/kernel/sched/topology.c +++ b/kernel/sched/topology.c @@ -1927,6 +1927,9 @@ next_level: } +#ifdef OPLUS_FEATURE_SCHED_ASSIST +extern void update_ux_sched_cputopo(void); +#endif /* * Build sched domains for a given set of CPUs and attach the sched domains * to the individual CPUs @@ -2046,6 +2049,9 @@ build_sched_domains(const struct cpumask *cpu_map, struct sched_domain_attr *att static_branch_inc_cpuslocked(&sched_asym_cpucapacity); ret = 0; +#ifdef OPLUS_FEATURE_SCHED_ASSIST + update_ux_sched_cputopo(); +#endif error: __free_domain_allocs(&d, alloc_state, cpu_map); diff --git a/kernel/sched/tune.c b/kernel/sched/tune.c index 2f6e4cbb004c..3f25d1eb15a4 100644 --- a/kernel/sched/tune.c +++ b/kernel/sched/tune.c @@ -9,6 +9,9 @@ #include #include "sched.h" +#ifdef OPLUS_FEATURE_POWER_CPUFREQ +#include "walt.h" +#endif bool schedtune_initialized = false; extern struct reciprocal_value schedtune_spc_rdiv; @@ -113,6 +116,14 @@ struct schedtune { /* Hint to bias scheduling of tasks on that SchedTune CGroup * towards idle CPUs */ int prefer_idle; +#ifdef OPLUS_FEATURE_POWER_CPUFREQ + unsigned int window_policy; +#endif +#ifdef OPLUS_FEATURE_POWER_EFFICIENCY + bool discount_wait_time; + bool top_task_filter; + bool ed_task_filter; +#endif }; static inline struct schedtune *css_st(struct cgroup_subsys_state *css) @@ -147,6 +158,14 @@ root_schedtune = { .sched_boost_enabled = true, .colocate = false, .colocate_update_disabled = false, +#endif +#ifdef OPLUS_FEATURE_POWER_CPUFREQ + .window_policy = 3, +#endif +#ifdef OPLUS_FEATURE_POWER_EFFICIENCY + .discount_wait_time = false, + .top_task_filter = false, + .ed_task_filter = false, #endif .prefer_idle = 0, }; @@ -457,12 +476,15 @@ static int sched_colocate_write(struct cgroup_subsys_state *css, struct cftype *cft, u64 colocate) { struct schedtune *st = css_st(css); - +#ifndef OPLUS_FEATURE_POWER_CPUFREQ +//qiziyu@SH. add schedtune.colocation tuning. 2020.09.30 if (st->colocate_update_disabled) return -EPERM; - +#endif /* OPLUS_FEATURE_POWER_CPUFREQ */ st->colocate = !!colocate; +#ifndef CONFIG_OPLUS_FEATURE_INPUT_BOOST_V4 st->colocate_update_disabled = true; +#endif return 0; } @@ -701,6 +723,119 @@ boost_write(struct cgroup_subsys_state *css, struct cftype *cft, return 0; } +#ifdef OPLUS_FEATURE_POWER_CPUFREQ +unsigned int schedtune_window_policy(struct task_struct *p) +{ + struct schedtune *st; + unsigned int window_policy; + + if (unlikely(!schedtune_initialized)) + return 0; + + rcu_read_lock(); + st = task_schedtune(p); + window_policy = st->window_policy; + rcu_read_unlock(); + + return window_policy; +} + +unsigned int uclamp_discount_wait_time(struct task_struct *p) +{ + struct schedtune *st; + unsigned int ret; + + if (unlikely(!schedtune_initialized)) + return 0; + + rcu_read_lock(); + st = task_schedtune(p); + ret = st->discount_wait_time; + rcu_read_unlock(); + + return ret; +} + +unsigned int uclamp_top_task_filter(struct task_struct *p) +{ + struct schedtune *st; + unsigned int ret; + + if (unlikely(!schedtune_initialized)) + return 0; + + rcu_read_lock(); + st = task_schedtune(p); + ret = st->top_task_filter; + rcu_read_unlock(); + + return ret; +} + +unsigned int uclamp_ed_task_filter(struct task_struct *p) +{ + struct schedtune *st; + unsigned int ret; + + if (unlikely(!schedtune_initialized)) + return 0; + + rcu_read_lock(); + st = task_schedtune(p); + ret = st->ed_task_filter; + rcu_read_unlock(); + + return ret; +} + +static u64 +window_policy_read(struct cgroup_subsys_state *css, + struct cftype *cft) +{ + struct schedtune *st = css_st(css); + return st->window_policy; +} + +static int +window_policy_write(struct cgroup_subsys_state *css, struct cftype *cft, + u64 window_policy) +{ + struct schedtune *st = css_st(css); + + if (window_policy >= WINDOW_STATS_INVALID_POLICY) + return -EINVAL; + + st->window_policy = window_policy; + + return 0; +} +#endif + +#ifdef OPLUS_FEATURE_POWER_EFFICIENCY +#define PE_FUNC(NAME) \ +static u64 NAME##_read(struct cgroup_subsys_state *css, \ + struct cftype *cft) \ +{ \ + struct schedtune *st = css_st(css); \ + return st->NAME; \ +} \ + \ +static int \ +NAME##_write(struct cgroup_subsys_state *css, struct cftype *cft, \ + u64 NAME) \ +{ \ + struct schedtune *st = css_st(css); \ + \ + st->NAME = !!NAME; \ + \ + return 0; \ +} + +PE_FUNC(discount_wait_time) +PE_FUNC(top_task_filter) +PE_FUNC(ed_task_filter) +#endif /* OPLUS_FEATURE_POWER_EFFICIENCY */ + static struct cftype files[] = { #ifdef CONFIG_SCHED_WALT { @@ -724,6 +859,30 @@ static struct cftype files[] = { .read_u64 = prefer_idle_read, .write_u64 = prefer_idle_write, }, +#ifdef OPLUS_FEATURE_POWER_CPUFREQ + { + .name = "window_policy", + .read_u64 = window_policy_read, + .write_u64 = window_policy_write, + }, +#endif +#ifdef OPLUS_FEATURE_POWER_EFFICIENCY + { + .name = "discount_wait_time", + .read_u64 = discount_wait_time_read, + .write_u64 = discount_wait_time_write, + }, + { + .name = "top_task_filter", + .read_u64 = top_task_filter_read, + .write_u64 = top_task_filter_write, + }, + { + .name = "ed_task_filter", + .read_u64 = ed_task_filter_read, + .write_u64 = ed_task_filter_write, + }, +#endif /* OPLUS_FEATURE_POWER_EFFICIENCY */ { } /* terminate */ }; diff --git a/kernel/sched/tune.h b/kernel/sched/tune.h index 02409fc96ab5..41d92e0a131d 100644 --- a/kernel/sched/tune.h +++ b/kernel/sched/tune.h @@ -20,6 +20,13 @@ int schedtune_prefer_idle(struct task_struct *tsk); void schedtune_enqueue_task(struct task_struct *p, int cpu); void schedtune_dequeue_task(struct task_struct *p, int cpu); +#ifdef OPLUS_FEATURE_POWER_CPUFREQ +unsigned int schedtune_window_policy(struct task_struct *p); +unsigned int uclamp_discount_wait_time(struct task_struct *p); +unsigned int uclamp_top_task_filter(struct task_struct *p); +unsigned int uclamp_ed_task_filter(struct task_struct *p); +#endif + #else /* CONFIG_SCHED_TUNE */ #define schedtune_cpu_boost_with(cpu, p) 0 @@ -31,4 +38,9 @@ void schedtune_dequeue_task(struct task_struct *p, int cpu); #define schedtune_dequeue_task(task, cpu) do { } while (0) #define stune_util(cpu, other_util, walt_load) cpu_util_cfs(cpu_rq(cpu)) + +#ifdef OPLUS_FEATURE_POWER_CPUFREQ +#define schedtune_window_policy(tsk) 0 +#endif + #endif /* CONFIG_SCHED_TUNE */ diff --git a/kernel/sched/walt.c b/kernel/sched/walt.c index dca7f17cc51b..c906f5e7c893 100644 --- a/kernel/sched/walt.c +++ b/kernel/sched/walt.c @@ -13,6 +13,15 @@ #include "walt.h" #include +#ifdef OPLUS_FEATURE_SCHED_ASSIST +#include +#include +#ifndef CONFIG_OPLUS_FEATURE_INPUT_BOOST_V4 +extern u64 ux_task_load[]; +extern u64 ux_load_ts[]; +#define UX_LOAD_WINDOW 8000000 +#endif +#endif /* OPLUS_FEATURE_SCHED_ASSIST */ const char *task_event_names[] = {"PUT_PREV_TASK", "PICK_NEXT_TASK", "TASK_WAKE", "TASK_MIGRATE", "TASK_UPDATE", @@ -99,7 +108,13 @@ __read_mostly unsigned int sysctl_sched_cpu_high_irqload = TICK_NSEC; unsigned int sysctl_sched_walt_rotate_big_tasks; unsigned int walt_rotation_enabled; +#ifdef CONFIG_SCHED_WALT_COBUCK +__read_mostly unsigned int sysctl_sched_asym_cap_sibling_freq_match_pct = 75; +__read_mostly unsigned int sysctl_sched_asym_cap_sibling_freq_match_en = 1; +cpumask_t asym_freq_match_cpus = CPU_MASK_NONE; +#else __read_mostly unsigned int sysctl_sched_asym_cap_sibling_freq_match_pct = 100; +#endif __read_mostly unsigned int sched_ravg_hist_size = 5; static __read_mostly unsigned int sched_io_is_busy = 1; @@ -352,6 +367,10 @@ void clear_ed_task(struct task_struct *p, struct rq *rq) static inline bool is_ed_task(struct task_struct *p, u64 wallclock) { +#if defined(OPLUS_FEATURE_POWER_CPUFREQ) && defined(OPLUS_FEATURE_POWER_EFFICIENCY) + if (uclamp_ed_task_filter(p)) + return false; +#endif return (wallclock - p->last_wake_ts >= EARLY_DETECTION_DURATION); } @@ -515,7 +534,13 @@ static inline u64 freq_policy_load(struct rq *rq) u64 aggr_grp_load = cluster->aggr_grp_load; u64 load, tt_load = 0; struct task_struct *cpu_ksoftirqd = per_cpu(ksoftirqd, cpu_of(rq)); - +#ifdef OPLUS_FEATURE_SCHED_ASSIST +#ifndef CONFIG_OPLUS_FEATURE_INPUT_BOOST_V4 + u64 wallclock = sched_ktime_clock(); + u64 timeline = 0; + int cpu = cpu_of(rq); +#endif +#endif /* OPLUS_FEATURE_SCHED_ASSIST */ if (rq->ed_task != NULL) { load = sched_ravg_window; goto done; @@ -550,6 +575,16 @@ static inline u64 freq_policy_load(struct rq *rq) load = div64_u64(load * sysctl_sched_user_hint, (u64)100); } +#ifdef OPLUS_FEATURE_SCHED_ASSIST +#ifndef CONFIG_OPLUS_FEATURE_INPUT_BOOST_V4 + if (sched_assist_scene(SA_SLIDE) && ux_load_ts[cpu]) { + timeline = wallclock - ux_load_ts[cpu]; + if (timeline >= UX_LOAD_WINDOW) + ux_task_load[cpu] = 0; + load = max_t(u64, load, ux_task_load[cpu]); + } +#endif +#endif /* OPLUS_FEATURE_SCHED_ASSIST */ done: trace_sched_load_to_gov(rq, aggr_grp_load, tt_load, sched_freq_aggr_en, @@ -601,23 +636,53 @@ __cpu_util_freq_walt(int cpu, struct sched_walt_cpu_load *walt_load) unsigned long cpu_util_freq_walt(int cpu, struct sched_walt_cpu_load *walt_load) { +#ifdef CONFIG_SCHED_WALT_COBUCK + static unsigned long util_other; + static struct sched_walt_cpu_load wl_other; + unsigned long util = 0; + int mpct = sysctl_sched_asym_cap_sibling_freq_match_pct; + int max_cap_cpu; +#else struct sched_walt_cpu_load wl_other = {0}; unsigned long util = 0, util_other = 0; - unsigned long capacity = capacity_orig_of(cpu); int i, mpct = sysctl_sched_asym_cap_sibling_freq_match_pct; - +#endif + unsigned long capacity = capacity_orig_of(cpu); +#ifdef CONFIG_SCHED_WALT_COBUCK + if (!cpumask_test_cpu(cpu, &asym_freq_match_cpus) || + !sysctl_sched_asym_cap_sibling_freq_match_en) +#else if (!cpumask_test_cpu(cpu, &asym_cap_sibling_cpus)) +#endif return __cpu_util_freq_walt(cpu, walt_load); +#ifndef CONFIG_SCHED_WALT_COBUCK for_each_cpu(i, &asym_cap_sibling_cpus) { if (i == cpu) util = __cpu_util_freq_walt(cpu, walt_load); else util_other = __cpu_util_freq_walt(i, &wl_other); } +#endif + +#ifdef CONFIG_SCHED_WALT_COBUCK + /* FIXME: Prime always last cpu */ + max_cap_cpu = cpumask_last(&asym_freq_match_cpus); + util = __cpu_util_freq_walt(cpu, walt_load); + + if (cpu != max_cap_cpu) { + if (cpumask_first(&asym_freq_match_cpus) == cpu) + util_other = __cpu_util_freq_walt(max_cap_cpu, &wl_other); + else + goto out; + } else { + mpct = 100; + } +#else if (cpu == cpumask_last(&asym_cap_sibling_cpus)) mpct = 100; +#endif util = ADJUSTED_ASYM_CAP_CPU_UTIL(util, util_other, mpct); @@ -626,6 +691,23 @@ cpu_util_freq_walt(int cpu, struct sched_walt_cpu_load *walt_load) walt_load->pl = ADJUSTED_ASYM_CAP_CPU_UTIL(walt_load->pl, wl_other.pl, mpct); +#ifdef CONFIG_SCHED_WALT_COBUCK +out: + if (cpu != max_cap_cpu) { + if (util > util_other) { + util_other = util; + wl_other.nl = walt_load->nl; + } + + if (wl_other.pl < walt_load->pl) + wl_other.pl = walt_load->pl; + + } else { + util_other = 0; + memset(&wl_other, 0, sizeof(wl_other)); + } +#endif + return (util >= capacity) ? capacity : util; } @@ -881,7 +963,23 @@ migrate_top_tasks(struct task_struct *p, struct rq *src_rq, struct rq *dst_rq) src_rq->top_tasks_bitmap[src], top_index); } } +#ifdef OPLUS_FEATURE_EDTASK_IMPROVE +void migrate_ed_task(struct task_struct *p, u64 wallclock, + struct rq *src_rq, struct rq *dest_rq) +{ + int src_cpu = cpu_of(src_rq); + int dest_cpu = cpu_of(dest_rq); + /* For ed task, reset last_wake_ts if task migrate to faster cpu */ + if (capacity_orig_of(src_cpu) < capacity_orig_of(dest_cpu)) { + p->last_wake_ts = wallclock; + if(dest_rq->ed_task == p) { + dest_rq->ed_task = NULL; + } + } +} +extern int sysctl_ed_task_enabled; +#endif /* OPLUS_FEATURE_EDTASK_IMPROVE */ void fixup_busy_time(struct task_struct *p, int new_cpu) { struct rq *src_rq = task_rq(p); @@ -999,7 +1097,11 @@ void fixup_busy_time(struct task_struct *p, int new_cpu) dest_rq->ed_task = p; } } - +#ifdef OPLUS_FEATURE_EDTASK_IMPROVE + if(sysctl_ed_task_enabled) { + migrate_ed_task(p, wallclock, src_rq, dest_rq); + } +#endif /* OPLUS_FEATURE_EDTASK_IMPROVE */ done: if (p->state == TASK_WAKING) double_rq_unlock(src_rq, dest_rq); @@ -1251,6 +1353,10 @@ static void update_top_tasks(struct task_struct *p, struct rq *rq, u32 prev_window = p->ravg.prev_window; bool zero_index_update; +#if defined(OPLUS_FEATURE_POWER_CPUFREQ) && defined(OPLUS_FEATURE_POWER_EFFICIENCY) + if (uclamp_top_task_filter(p)) + return; +#endif if (old_curr_window == curr_window && !new_window) return; @@ -1766,10 +1872,16 @@ account_busy_for_task_demand(struct rq *rq, struct task_struct *p, int event) * when a task begins to run or is migrated, it is not running and * is completing a segment of non-busy time. */ +#if defined(OPLUS_FEATURE_POWER_CPUFREQ) && defined(OPLUS_FEATURE_POWER_EFFICIENCY) + if (event == TASK_WAKE || ((!SCHED_ACCOUNT_WAIT_TIME || + uclamp_discount_wait_time(p)) && + (event == PICK_NEXT_TASK || event == TASK_MIGRATE))) + return 0; +#else if (event == TASK_WAKE || (!SCHED_ACCOUNT_WAIT_TIME && (event == PICK_NEXT_TASK || event == TASK_MIGRATE))) return 0; - +#endif /* * The idle exit time is not accounted for the first task _picked_ up to * run on the idle CPU. @@ -1785,7 +1897,12 @@ account_busy_for_task_demand(struct rq *rq, struct task_struct *p, int event) if (rq->curr == p) return 1; +#if defined(OPLUS_FEATURE_POWER_CPUFREQ) && defined(OPLUS_FEATURE_POWER_EFFICIENCY) + return p->on_rq ? (SCHED_ACCOUNT_WAIT_TIME && + !uclamp_discount_wait_time(p)) : 0; +#else return p->on_rq ? SCHED_ACCOUNT_WAIT_TIME : 0; +#endif } return 1; @@ -1830,6 +1947,9 @@ static void update_history(struct rq *rq, struct task_struct *p, } p->ravg.sum = 0; +#ifdef OPLUS_FEATURE_POWER_CPUFREQ + sysctl_sched_window_stats_policy = schedtune_window_policy(p); +#endif if (sysctl_sched_window_stats_policy == WINDOW_STATS_RECENT) { demand = runtime; @@ -1880,6 +2000,10 @@ static void update_history(struct rq *rq, struct task_struct *p, p->unfilter = max_t(int, 0, p->unfilter - p->ravg.last_win_size); done: +#if defined(OPLUS_FEATURE_SCHED_ASSIST) && defined(CONFIG_OPLUS_FEATURE_SCHED_SPREAD) + if (p == rq->curr && p == current && event != PUT_PREV_TASK && p->sched_class == &fair_sched_class && p->ld_flag) + update_load_flag(p, rq); +#endif trace_sched_update_history(rq, p, runtime, samples, event); } @@ -1951,6 +2075,9 @@ static u64 update_task_demand(struct task_struct *p, struct rq *rq, int new_window, nr_full_windows; u32 window_size = sched_ravg_window; u64 runtime; +#ifdef CONFIG_OPLUS_FEATURE_INPUT_BOOST_V4 + update_group_demand(p, rq, event, wallclock); +#endif /* CONFIG_OPLUS_FEATURE_INPUT_BOOST_V4 */ new_window = mark_start < window_start; if (!account_busy_for_task_demand(rq, p, event)) { @@ -2096,6 +2223,9 @@ void update_task_ravg(struct task_struct *p, struct rq *rq, int event, lockdep_assert_held(&rq->lock); old_window_start = update_window_start(rq, wallclock, event); +#ifdef CONFIG_OPLUS_FEATURE_INPUT_BOOST_V4 + update_group_nr_running(p, event, wallclock); +#endif /* CONFIG_OPLUS_FEATURE_INPUT_BOOST_V4 */ if (!p->ravg.mark_start) { update_task_cpu_cycles(p, cpu_of(rq), wallclock); @@ -2258,7 +2388,11 @@ static void walt_cpus_capacity_changed(const cpumask_t *cpus) struct sched_cluster *sched_cluster[NR_CPUS]; +#ifdef CONFIG_OPLUS_FEATURE_INPUT_BOOST_V4 +__read_mostly int num_sched_clusters; +#else static int num_sched_clusters; +#endif /* CONFIG_OPLUS_FEATURE_INPUT_BOOST_V4 */ struct list_head cluster_head; cpumask_t asym_cap_sibling_cpus = CPU_MASK_NONE; @@ -2435,6 +2569,9 @@ void sort_clusters(void) move_list(&cluster_head, &new_head, false); } +#ifdef CONFIG_OPLUS_FEATURE_INPUT_BOOST_V4 +bool walt_clusters_parsed; +#endif static void update_all_clusters_stats(void) { struct sched_cluster *cluster; @@ -2505,6 +2642,9 @@ void update_cluster_topology(void) if (cpumask_weight(&asym_cap_sibling_cpus) == 1) cpumask_clear(&asym_cap_sibling_cpus); +#ifdef CONFIG_OPLUS_FEATURE_INPUT_BOOST_V4 + walt_clusters_parsed = true; +#endif } static unsigned long cpu_max_table_freq[NR_CPUS]; @@ -3361,6 +3501,14 @@ void walt_irq_work(struct irq_work *irq_work) int level = 0; unsigned long flags; +#ifdef CONFIG_SCHED_WALT_COBUCK + struct cpumask freq_match_cpus; + + if (sysctl_sched_asym_cap_sibling_freq_match_en) + cpumask_copy(&freq_match_cpus, &asym_freq_match_cpus); + else + cpumask_copy(&freq_match_cpus, &asym_cap_sibling_cpus); +#endif /* Am I the window rollover work or the migration work? */ if (irq_work == &walt_migration_irq_work) is_migration = true; @@ -3388,8 +3536,13 @@ void walt_irq_work(struct irq_work *irq_work) account_load_subtractions(rq); aggr_grp_load += rq->grp_time.prev_runnable_sum; } +#ifdef CONFIG_SCHED_WALT_COBUCK + if (is_migration && rq->notif_pending && + cpumask_test_cpu(cpu, &freq_match_cpus)) { +#else if (is_migration && rq->notif_pending && cpumask_test_cpu(cpu, &asym_cap_sibling_cpus)) { +#endif is_asym_migration = true; rq->notif_pending = false; } @@ -3404,11 +3557,19 @@ void walt_irq_work(struct irq_work *irq_work) } if (total_grp_load) { +#ifdef CONFIG_SCHED_WALT_COBUCK + if (cpumask_weight(&freq_match_cpus)) { +#else if (cpumask_weight(&asym_cap_sibling_cpus)) { +#endif u64 big_grp_load = total_grp_load - min_cluster_grp_load; +#ifdef CONFIG_SCHED_WALT_COBUCK + for_each_cpu(cpu, &freq_match_cpus) +#else for_each_cpu(cpu, &asym_cap_sibling_cpus) +#endif cpu_cluster(cpu)->aggr_grp_load = big_grp_load; } rtgb_active = is_rtgb_active(); @@ -3439,8 +3600,13 @@ void walt_irq_work(struct irq_work *irq_work) } } +#ifdef CONFIG_SCHED_WALT_COBUCK + if (is_asym_migration && cpumask_test_cpu(cpu, + &freq_match_cpus)) +#else if (is_asym_migration && cpumask_test_cpu(cpu, &asym_cap_sibling_cpus)) +#endif flag |= SCHED_CPUFREQ_INTERCLUSTER_MIG; if (i == num_cpus) diff --git a/kernel/sched/walt.h b/kernel/sched/walt.h index 36eaff2613c6..cd2bd086ee67 100644 --- a/kernel/sched/walt.h +++ b/kernel/sched/walt.h @@ -51,6 +51,9 @@ extern unsigned int max_possible_efficiency; extern unsigned int min_possible_efficiency; extern unsigned int max_possible_freq; extern unsigned int __read_mostly sched_load_granule; +#ifdef CONFIG_OPLUS_FEATURE_INPUT_BOOST_V4 +extern int __read_mostly num_sched_clusters; +#endif /* CONFIG_OPLUS_FEATURE_INPUT_BOOST_V4 */ extern u64 sched_ravg_window_change_time; extern struct mutex cluster_lock; diff --git a/kernel/sched_assist b/kernel/sched_assist new file mode 120000 index 000000000000..1be746c8da65 --- /dev/null +++ b/kernel/sched_assist @@ -0,0 +1 @@ +../../../vendor/oplus/kernel/oplus_performance/sched_assist/ \ No newline at end of file diff --git a/kernel/signal.c b/kernel/signal.c index bfd8f5fbe97f..6f1ee72d7d9c 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -56,6 +56,17 @@ #include #include #include "audit.h" /* audit_signal_info() */ +#ifdef OPLUS_FEATURE_HANS_FREEZE +#include +#endif /*OPLUS_FEATURE_HANS_FREEZE*/ + +#ifdef OPLUS_BUG_STABILITY +#include +#endif + +#if defined(OPLUS_FEATURE_SCHED_ASSIST) +#include +#endif /* OPLUS_FEATURE_SCHED_ASSIST */ /* * SLAB caches for signal bits. @@ -1093,10 +1104,40 @@ static int __send_signal(int sig, struct siginfo *info, struct task_struct *t, struct sigqueue *q; int override_rlimit; int ret = 0, result; +#if defined(VENDOR_EDIT) && defined(CONFIG_ELSA_STUB) + struct process_event_data pe_data; +#endif assert_spin_locked(&t->sighand->siglock); result = TRACE_SIGNAL_IGNORED; + +#ifdef OPLUS_BUG_STABILITY + if(1) { + /*add the SIGKILL print log for some debug*/ + if((sig == SIGHUP || sig == 33 || sig == SIGKILL || sig == SIGSTOP || sig == SIGABRT || sig == SIGTERM || sig == SIGCONT) && is_key_process(t)) { + //#ifdef OPLUS_BUG_STABILITY + //dump_stack(); + //#endif + printk("Some other process %d:%s want to send sig:%d to pid:%d tgid:%d comm:%s\n", current->pid, current->comm,sig, t->pid, t->tgid, t->comm); + } +#ifdef CONFIG_OPLUS_SPECIAL_BUILD + else if (sig == SIGSTOP){ + printk("Process %d:%s want to send SIGSTOP to %d:%s\n", current->pid, current->comm, t->pid, t->comm); + } +#endif + } +#endif + +#if defined(VENDOR_EDIT) && defined(CONFIG_ELSA_STUB) + if (sig == SIGKILL && (freezing(t) || frozen(t)) && cgroup_freezing(t)) { + pe_data.pid = task_pid_nr(t); + pe_data.uid = task_uid(t); + pe_data.reason = sig; + process_event_notifier_call_chain_atomic(PROCESS_EVENT_SIGNAL_FROZEN, &pe_data); + } +#endif + if (!prepare_signal(sig, t, from_ancestor_ns || (info == SEND_SIG_PRIV) || (info == SEND_SIG_FORCED))) goto ret; @@ -1270,6 +1311,27 @@ int do_send_sig_info(int sig, struct siginfo *info, struct task_struct *p, unsigned long flags; int ret = -ESRCH; +#ifdef OPLUS_FEATURE_HANS_FREEZE + if (is_frozen_tg(p) /*signal receiver thread group is frozen?*/ + && (sig == SIGKILL || sig == SIGTERM || sig == SIGABRT || sig == SIGQUIT)) { + if (hans_report(SIGNAL, task_tgid_nr(current), task_uid(current).val, task_tgid_nr(p), task_uid(p).val, "signal", -1) == HANS_ERROR) { + printk(KERN_ERR "HANS: report signal-freeze failed, sig = %d, caller = %d, target_uid = %d\n", sig, task_tgid_nr(current), task_uid(p).val); + } + } +#endif /*OPLUS_FEATURE_HANS_FREEZE*/ + +#if defined(CONFIG_CFS_BANDWIDTH) + if (is_belong_cpugrp(p) /*signal receiver thread group is cpuctl?*/ + && (sig == SIGKILL || sig == SIGTERM || sig == SIGABRT || sig == SIGQUIT)) { + if (hans_report(SIGNAL, task_tgid_nr(current), task_uid(current).val, task_tgid_nr(p), task_uid(p).val, "signal", -1) == HANS_ERROR) { + printk(KERN_ERR "HANS: report signal-cpuctl failed, sig = %d, caller = %d, target_uid = %d\n", sig, task_tgid_nr(current), task_uid(p).val); + } + } +#endif + +#if defined(OPLUS_FEATURE_SCHED_ASSIST) + oplus_boost_kill_signal(sig, current, p); +#endif if (lock_task_sighand(p, &flags)) { ret = send_signal(sig, info, p, type); unlock_task_sighand(p, &flags); @@ -1391,7 +1453,8 @@ int group_send_sig_info(int sig, struct siginfo *info, struct task_struct *p, check_panic_on_foreground_kill(p); ret = do_send_sig_info(sig, info, p, type); if (capable(CAP_KILL) && sig == SIGKILL) { - if (!strcmp(current->comm, ULMK_MAGIC)) + if (!strcmp(current->comm, ULMK_MAGIC) || + !strcmp(current->comm, ATHENA_KILLER_MAGIC)) add_to_oom_reaper(p); ulmk_update_last_kill(); } diff --git a/kernel/special_opt b/kernel/special_opt new file mode 120000 index 000000000000..e7f47cfea86a --- /dev/null +++ b/kernel/special_opt @@ -0,0 +1 @@ +../../../vendor/oplus/kernel/oplus_performance/special_opt \ No newline at end of file diff --git a/kernel/sysctl.c b/kernel/sysctl.c index a30c31704130..b622d9b70120 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -74,6 +74,11 @@ #include #include +#ifdef OPLUS_FEATURE_TASK_CPUSTATS +/* stat cpu usage on each tick. */ +#include +#endif /* OPLUS_FEATURE_TASK_CPUSTATS */ + #ifdef CONFIG_X86 #include #include @@ -99,8 +104,23 @@ #include #endif +#if defined(OPLUS_FEATURE_MULTI_KSWAPD) && defined(CONFIG_OPLUS_MULTI_KSWAPD) +#include +#endif + #if defined(CONFIG_SYSCTL) +#if defined(CONFIG_OPLUS_FEATURE_HUNG_TASK_ENHANCE) && defined(CONFIG_OPLUS_FEATURE_DEATH_HEALER) +#include +#endif + +#ifdef CONFIG_OPLUS_BINDER_STRATEGY +#include +extern int sysctl_ob_control_enable; +extern int ob_pid; +extern int sysctl_ob_control_handler(struct ctl_table *table, int write, void __user *buffer, size_t *lenp, loff_t *ppos); +#endif + /* External variables not in a header file. */ extern int suid_dumpable; #ifdef CONFIG_COREDUMP @@ -123,6 +143,12 @@ extern int sysctl_nr_trim_pages; static int sixty = 60; #endif +#ifdef OPLUS_FEATURE_SCHED_ASSIST +//#ifdef CONFIG_UXCHAIN_V2 +int sysctl_uxchain_v2 = 1; +u64 sysctl_mmapsem_uninterruptable_time; +#endif + static int __maybe_unused neg_one = -1; static int __maybe_unused neg_three = -3; @@ -135,14 +161,25 @@ static unsigned long zero_ul; static unsigned long one_ul = 1; static unsigned long long_max = LONG_MAX; static int one_hundred = 100; +#if defined(OPLUS_FEATURE_ZRAM_OPT) && defined(CONFIG_OPLUS_ZRAM_OPT) +extern int direct_vm_swappiness; +static int two_hundred = 200; +#endif /*OPLUS_FEATURE_ZRAM_OPT*/ + +#ifdef OPLUS_FEATURE_EDTASK_IMPROVE +int sysctl_ed_task_enabled = 1; +#endif /* OPLUS_FEATURE_EDTASK_IMPROVE */ static int one_thousand = 1000; +#if defined(OPLUS_FEATURE_SCHED_ASSIST) && defined(CONFIG_OPLUS_FEATURE_UXIO_FIRST) +unsigned int sysctl_uxio_io_opt = true; +bool sysctl_wbt_enable = true; +#endif #ifdef CONFIG_PRINTK static int ten_thousand = 10000; #endif #ifdef CONFIG_PERF_EVENTS static int six_hundred_forty_kb = 640 * 1024; #endif -static int max_kswapd_threads = MAX_KSWAPD_THREADS; static int two_hundred_fifty_five = 255; static int __maybe_unused two_hundred_million = 200000000; @@ -365,6 +402,33 @@ static int max_sched_tunable_scaling = SCHED_TUNABLESCALING_END-1; #endif /* CONFIG_SMP */ #endif /* CONFIG_SCHED_DEBUG */ +#ifdef OPLUS_FEATURE_SCHED_ASSIST +int sysctl_sched_assist_enabled = 1; +int sysctl_sched_assist_scene = 0; +int sysctl_prefer_silver = 0; +int sysctl_heavy_task_thresh = 50; +int sysctl_cpu_util_thresh = 85; +#endif /* OPLUS_FEATURE_SCHED_ASSIST */ +#ifdef OPLUS_FEATURE_SCHED_ASSIST +int sysctl_cpu_multi_thread = 0; +#endif +#ifdef OPLUS_FEATURE_SCHED_ASSIST +int sysctl_slide_boost_enabled = 0; +int sysctl_boost_task_threshold = 51; +int sysctl_frame_rate = 60; +int sched_frame_rate_handler(struct ctl_table *table, int write, void __user *buffer, size_t *lenp, loff_t *ppos) +{ + int ret; + + if (write && *ppos) + *ppos = 0; + + ret = proc_dointvec(table, write, buffer, lenp, ppos); + + return ret; +} +#endif /* OPLUS_FEATURE_SCHED_ASSIST */ + #ifdef CONFIG_COMPACTION static int min_extfrag_threshold; static int max_extfrag_threshold = 1000; @@ -502,6 +566,33 @@ static struct ctl_table kern_table[] = { .extra1 = &one, .extra2 = &one_hundred, }, +#ifdef CONFIG_SCHED_WALT_COBUCK + { + .procname = "sched_asym_cap_sibling_freq_match_enable", + .data = &sysctl_sched_asym_cap_sibling_freq_match_en, + .maxlen = sizeof(unsigned int), + .mode = 0644, + .proc_handler = proc_dointvec_minmax, + .extra1 = &zero, + .extra2 = &one, + }, +#endif +#if defined(OPLUS_FEATURE_SCHED_ASSIST) && defined(CONFIG_OPLUS_FEATURE_UXIO_FIRST) +{ + .procname = "uxio_first_opt", + .data = &sysctl_uxio_io_opt, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec, +}, +{ + .procname = "wbt_enable", + .data = &sysctl_wbt_enable, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec, +}, +#endif { .procname = "sched_coloc_downmigrate_ns", .data = &sysctl_sched_coloc_downmigrate_ns, @@ -621,6 +712,17 @@ static struct ctl_table kern_table[] = { .extra2 = &one_thousand, }, #endif + +#ifdef OPLUS_FEATURE_EDTASK_IMPROVE + { + .procname = "ed_task_enabled", + .data = &sysctl_ed_task_enabled, + .maxlen = sizeof(int), + .mode = 0666, + .proc_handler = proc_dointvec, + }, +#endif /* OPLUS_FEATURE_EDTASK_IMPROVE */ + { .procname = "sched_force_lb_enable", .data = &sysctl_sched_force_lb_enable, @@ -630,6 +732,7 @@ static struct ctl_table kern_table[] = { .extra1 = &zero, .extra2 = &one, }, + #ifdef CONFIG_SCHED_DEBUG { .procname = "sched_cstate_aware", @@ -1486,7 +1589,25 @@ static struct ctl_table kern_table[] = { .extra1 = &zero, .extra2 = &one, }, - +#if defined(CONFIG_OPLUS_FEATURE_HUNG_TASK_ENHANCE) && defined(CONFIG_OPLUS_FEATURE_DEATH_HEALER) +/* record the hung task killing */ + { + .procname = "hung_task_kill", + .data = &sysctl_hung_task_kill, + .maxlen = 128, + .mode = 0666, + .proc_handler = proc_dostring, + }, +/* Foreground background optimization,change max io count */ + { + .procname = "hung_task_maxiowait_count", + .data = &sysctl_hung_task_maxiowait_count, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec_minmax, + .extra1 = &five, + }, +#endif #endif #ifdef CONFIG_RT_MUTEXES { @@ -1610,6 +1731,22 @@ static struct ctl_table kern_table[] = { .extra2 = &one, }, #endif +#ifdef CONFIG_OPLUS_BINDER_STRATEGY + { + .procname = "oplus_binder_control_enabled", + .data = &sysctl_ob_control_enable, + .maxlen = sizeof(int), + .mode = 0660, + .proc_handler = sysctl_ob_control_handler, + }, + { + .procname = "oplus_bg_thread_pid", + .data = &ob_pid, + .maxlen = sizeof(int), + .mode = 0660, + .proc_handler = proc_dointvec, + }, +#endif #if defined(CONFIG_ARM) || defined(CONFIG_ARM64) { .procname = "boot_reason", @@ -1627,6 +1764,105 @@ static struct ctl_table kern_table[] = { .proc_handler = proc_dointvec, }, #endif +#ifdef OPLUS_FEATURE_SCHED_ASSIST + { + .procname = "sched_assist_enabled", + .data = &sysctl_sched_assist_enabled, + .maxlen = sizeof(int), + .mode = 0666, + .proc_handler = proc_dointvec, + }, + { + .procname = "sched_assist_scene", + .data = &sysctl_sched_assist_scene, + .maxlen = sizeof(int), + .mode = 0666, + .proc_handler = sysctl_sched_assist_scene_handler, + }, + { + .procname = "prefer_silver_enabled", + .data = &sysctl_prefer_silver, + .maxlen = sizeof(int), + .mode = 0666, + .proc_handler = proc_dointvec, + }, + { + .procname = "heavy_task_thresh", + .data = &sysctl_heavy_task_thresh, + .maxlen = sizeof(int), + .mode = 0666, + .proc_handler = proc_dointvec, + }, + { + .procname = "cpu_util_thresh", + .data = &sysctl_cpu_util_thresh, + .maxlen = sizeof(int), + .mode = 0666, + .proc_handler = proc_dointvec, + }, +#endif /* OPLUS_FEATURE_SCHED_ASSIST */ +#ifdef OPLUS_FEATURE_SCHED_ASSIST + { + .procname = "cpu_multi_thread", + .data = &sysctl_cpu_multi_thread, + .maxlen = sizeof(int), + .mode = 0666, + .proc_handler = proc_dointvec, + }, +#endif /* OPLUS_FEATURE_SCHED_ASSIST */ +#ifdef OPLUS_FEATURE_SCHED_ASSIST + { + .procname = "slide_boost_enabled", + .data = &sysctl_slide_boost_enabled, + .maxlen = sizeof(int), + .mode = 0666, + .proc_handler = proc_dointvec, + }, + { + .procname = "boost_task_threshold", + .data = &sysctl_boost_task_threshold, + .maxlen = sizeof(int), + .mode = 0666, + .proc_handler = proc_dointvec, + }, + { + .procname = "frame_rate", + .data = &sysctl_frame_rate, + .maxlen = sizeof(int), + .mode = 0666, + .proc_handler = sched_frame_rate_handler, + }, +#endif /* OPLUS_FEATURE_SCHED_ASSIST */ +#ifdef OPLUS_FEATURE_TASK_CPUSTATS +/* stat cpu usage on each tick. */ + { + .procname = "task_cpustats_enable", + .data = &sysctl_task_cpustats_enable, + .maxlen = sizeof(unsigned int), + .mode = 0666, + .proc_handler = proc_dointvec_minmax, + .extra1 = &zero, + .extra2 = &one, + }, +#endif /* OPLUS_FEATURE_TASK_CPUSTATS */ +#ifdef OPLUS_FEATURE_SCHED_ASSIST +//#ifdef CONFIG_UXCHAIN_V2 + { + .procname = "uxchain_v2", + .data = &sysctl_uxchain_v2, + .maxlen = sizeof(int), + .mode = 0666, + .proc_handler = proc_dointvec, + }, + { + .procname = "mmapsem_uninterruptable_time", + .data = &sysctl_mmapsem_uninterruptable_time, + .maxlen = sizeof(u64), + .mode = 0666, + .proc_handler = proc_dointvec, + }, +#endif + { } }; @@ -1685,7 +1921,7 @@ static struct ctl_table vm_table[] = { .proc_handler = overcommit_kbytes_handler, }, { - .procname = "page-cluster", + .procname = "page-cluster", .data = &page_cluster, .maxlen = sizeof(int), .mode = 0644, @@ -1756,8 +1992,59 @@ static struct ctl_table vm_table[] = { .mode = 0644, .proc_handler = proc_dointvec_minmax, .extra1 = &zero, +#if defined(OPLUS_FEATURE_ZRAM_OPT) && defined(CONFIG_OPLUS_ZRAM_OPT) + .extra2 = &two_hundred, +#else .extra2 = &one_hundred, +#endif /*OPLUS_FEATURE_ZRAM_OPT*/ }, +#ifdef CONFIG_DYNAMIC_TUNNING_SWAPPINESS + { + .procname = "vm_swappiness_threshold1", + .data = &vm_swappiness_threshold1, + .maxlen = sizeof(vm_swappiness_threshold1), + .mode = 0644, + .proc_handler = proc_dointvec_minmax, + .extra1 = &zero, + .extra2 = &two_hundred, + }, + { + .procname = "vm_swappiness_threshold2", + .data = &vm_swappiness_threshold2, + .maxlen = sizeof(vm_swappiness_threshold2), + .mode = 0644, + .proc_handler = proc_dointvec_minmax, + .extra1 = &zero, + .extra2 = &two_hundred, + }, + { + .procname = "swappiness_threshold1_size", + .data = &swappiness_threshold1_size, + .maxlen = sizeof(swappiness_threshold1_size), + .mode = 0644, + .proc_handler = proc_dointvec_minmax, + .extra1 = &zero, + }, + { + .procname = "swappiness_threshold2_size", + .data = &swappiness_threshold2_size, + .maxlen = sizeof(swappiness_threshold2_size), + .mode = 0644, + .proc_handler = proc_dointvec_minmax, + .extra1 = &zero, + }, +#endif +#if defined(OPLUS_FEATURE_ZRAM_OPT) && defined(CONFIG_OPLUS_ZRAM_OPT) + { + .procname = "direct_swappiness", + .data = &direct_vm_swappiness, + .maxlen = sizeof(direct_vm_swappiness), + .mode = 0644, + .proc_handler = proc_dointvec_minmax, + .extra1 = &zero, + .extra2 = &two_hundred, + }, +#endif { .procname = "want_old_faultaround_pte", .data = &want_old_faultaround_pte, @@ -1829,7 +2116,12 @@ static struct ctl_table vm_table[] = { .procname = "compact_memory", .data = &sysctl_compact_memory, .maxlen = sizeof(int), +#ifdef OPLUS_FEATURE_PERFORMANCE + .mode = 0222, +#else .mode = 0200, + +#endif /*OPLUS_FEATURE_PERFORMANCE*/ .proc_handler = sysctl_compaction_handler, }, { @@ -1868,6 +2160,7 @@ static struct ctl_table vm_table[] = { .proc_handler = watermark_boost_factor_sysctl_handler, .extra1 = &zero, }, +#if defined(OPLUS_FEATURE_MULTI_KSWAPD) && defined(CONFIG_OPLUS_MULTI_KSWAPD) { .procname = "kswapd_threads", .data = &kswapd_threads, @@ -1877,6 +2170,7 @@ static struct ctl_table vm_table[] = { .extra1 = &one, .extra2 = &max_kswapd_threads, }, +#endif { .procname = "watermark_scale_factor", .data = &watermark_scale_factor, @@ -2233,7 +2527,7 @@ static struct ctl_table fs_table[] = { .mode = 0555, .child = inotify_table, }, -#endif +#endif #ifdef CONFIG_EPOLL { .procname = "epoll", @@ -2714,12 +3008,12 @@ static int __do_proc_dointvec(void *tbl_data, struct ctl_table *table, int *i, vleft, first = 1, err = 0; size_t left; char *kbuf = NULL, *p; - + if (!tbl_data || !table->maxlen || !*lenp || (*ppos && !write)) { *lenp = 0; return 0; } - + i = (int *) tbl_data; vleft = table->maxlen / sizeof(*i); left = *lenp; @@ -2945,7 +3239,7 @@ static int do_proc_douintvec(struct ctl_table *table, int write, * @ppos: file position * * Reads/writes up to table->maxlen/sizeof(unsigned int) integer - * values from/to the user buffer, treated as an ASCII string. + * values from/to the user buffer, treated as an ASCII string. * * Returns 0 on success. */ @@ -3460,7 +3754,7 @@ static int do_proc_dointvec_ms_jiffies_conv(bool *negp, unsigned long *lvalp, * @ppos: file position * * Reads/writes up to table->maxlen/sizeof(unsigned int) integer - * values from/to the user buffer, treated as an ASCII string. + * values from/to the user buffer, treated as an ASCII string. * The values read are assumed to be in seconds, and are converted into * jiffies. * @@ -3482,8 +3776,8 @@ int proc_dointvec_jiffies(struct ctl_table *table, int write, * @ppos: pointer to the file position * * Reads/writes up to table->maxlen/sizeof(unsigned int) integer - * values from/to the user buffer, treated as an ASCII string. - * The values read are assumed to be in 1/USER_HZ seconds, and + * values from/to the user buffer, treated as an ASCII string. + * The values read are assumed to be in 1/USER_HZ seconds, and * are converted into jiffies. * * Returns 0 on success. @@ -3505,8 +3799,8 @@ int proc_dointvec_userhz_jiffies(struct ctl_table *table, int write, * @ppos: the current position in the file * * Reads/writes up to table->maxlen/sizeof(unsigned int) integer - * values from/to the user buffer, treated as an ASCII string. - * The values read are assumed to be in 1/1000 seconds, and + * values from/to the user buffer, treated as an ASCII string. + * The values read are assumed to be in 1/1000 seconds, and * are converted into jiffies. * * Returns 0 on success. diff --git a/kernel/time/alarmtimer.c b/kernel/time/alarmtimer.c index 730b834e6a1b..c16846900cf2 100644 --- a/kernel/time/alarmtimer.c +++ b/kernel/time/alarmtimer.c @@ -35,6 +35,10 @@ #define CREATE_TRACE_POINTS #include +#ifdef OPLUS_FEATURE_POWERINFO_STANDBY +#include +#endif /* OPLUS_FEATURE_POWERINFO_STANDBY */ + /** * struct alarm_base - Alarm timer bases * @lock: Lock for syncrhonized access to the base @@ -214,6 +218,10 @@ static enum hrtimer_restart alarmtimer_fired(struct hrtimer *timer) if (alarm->function) restart = alarm->function(alarm, base->gettime()); + #ifdef OPLUS_FEATURE_POWERINFO_STANDBY + alarmtimer_wakeup_count(alarm); + #endif /*OPLUS_FEATURE_POWERINFO_STANDBY*/ + spin_lock_irqsave(&base->lock, flags); if (restart != ALARMTIMER_NORESTART) { hrtimer_set_expires(&alarm->timer, alarm->node.expires); @@ -260,6 +268,10 @@ static int alarmtimer_suspend(struct device *dev) freezer_delta = 0; spin_unlock_irqrestore(&freezer_delta_lock, flags); + #ifdef OPLUS_FEATURE_POWERINFO_STANDBY + alarmtimer_suspend_flag_set(); + #endif /* OPLUS_FEATURE_POWERINFO_STANDBY */ + rtc = alarmtimer_get_rtcdev(); /* If we have no rtcdev, just return */ if (!rtc) @@ -288,6 +300,11 @@ static int alarmtimer_suspend(struct device *dev) if (ktime_to_ns(min) < 2 * NSEC_PER_SEC) { __pm_wakeup_event(ws, 2 * MSEC_PER_SEC); + #ifdef OPLUS_FEATURE_POWERINFO_STANDBY + alarmtimer_suspend_flag_clear(); + alarmtimer_busy_flag_set(); + pr_info("alarmtimer: keep system alive 2 seconds.\n"); + #endif /* OPLUS_FEATURE_POWERINFO_STANDBY */ return -EBUSY; } @@ -310,6 +327,9 @@ static int alarmtimer_resume(struct device *dev) { struct rtc_device *rtc; + #ifdef OPLUS_FEATURE_POWERINFO_STANDBY + alarmtimer_suspend_flag_clear(); + #endif /* OPLUS_FEATURE_POWERINFO_STANDBY */ rtc = alarmtimer_get_rtcdev(); if (rtc) rtc_timer_cancel(rtc, &rtctimer); diff --git a/kernel/time/timer.c b/kernel/time/timer.c index 88e99296f6c7..80a46c2d90db 100644 --- a/kernel/time/timer.c +++ b/kernel/time/timer.c @@ -2064,6 +2064,32 @@ unsigned long msleep_interruptible(unsigned int msecs) EXPORT_SYMBOL(msleep_interruptible); +/** + * usleep_range_state - Sleep for an approximate time in a given state + * @min: Minimum time in usecs to sleep + * @max: Maximum time in usecs to sleep + * @state: State of the current task that will be while sleeping + * + * In non-atomic context where the exact wakeup time is flexible, use + * usleep_range_state() instead of udelay(). The sleep improves responsiveness + * by avoiding the CPU-hogging busy-wait of udelay(), and the range reduces + * power usage by allowing hrtimers to take advantage of an already- + * scheduled interrupt instead of scheduling a new one just for this sleep. + */ +void __sched usleep_range_state(unsigned long min, unsigned long max, + unsigned int state) +{ + ktime_t exp = ktime_add_us(ktime_get(), min); + u64 delta = (u64)(max - min) * NSEC_PER_USEC; + + for (;;) { + __set_current_state(state); + /* Do not return before the requested sleep time has elapsed */ + if (!schedule_hrtimeout_range(&exp, delta, HRTIMER_MODE_ABS)) + break; + } +} + /** * usleep_range - Sleep for an approximate time * @min: Minimum time in usecs to sleep @@ -2077,14 +2103,6 @@ EXPORT_SYMBOL(msleep_interruptible); */ void __sched usleep_range(unsigned long min, unsigned long max) { - ktime_t exp = ktime_add_us(ktime_get(), min); - u64 delta = (u64)(max - min) * NSEC_PER_USEC; - - for (;;) { - __set_current_state(TASK_UNINTERRUPTIBLE); - /* Do not return before the requested sleep time has elapsed */ - if (!schedule_hrtimeout_range(&exp, delta, HRTIMER_MODE_ABS)) - break; - } + usleep_range_state(min, max, TASK_UNINTERRUPTIBLE); } EXPORT_SYMBOL(usleep_range); diff --git a/kernel/tuning b/kernel/tuning new file mode 120000 index 000000000000..e0823550971e --- /dev/null +++ b/kernel/tuning @@ -0,0 +1 @@ +../../../vendor/oplus/kernel/oplus_performance/inputboost_v4 \ No newline at end of file diff --git a/kernel/workqueue.c b/kernel/workqueue.c index b78c5f1a022a..4780010ba92c 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -85,8 +85,12 @@ enum { WORKER_NOT_RUNNING = WORKER_PREP | WORKER_CPU_INTENSIVE | WORKER_UNBOUND | WORKER_REBOUND, - +#ifdef OPLUS_FEATURE_SCHED_ASSIST + NR_STD_WORKER_POOLS = 3, /* # standard pools per cpu */ + UX_WORKER_POOL_INDEX = 2, /* last index of pools is ux type */ +#else NR_STD_WORKER_POOLS = 2, /* # standard pools per cpu */ +#endif UNBOUND_POOL_HASH_ORDER = 6, /* hashed by pool->attrs */ BUSY_WORKER_HASH_ORDER = 6, /* 64 pointers */ @@ -352,6 +356,10 @@ struct workqueue_struct *system_power_efficient_wq __read_mostly; EXPORT_SYMBOL_GPL(system_power_efficient_wq); struct workqueue_struct *system_freezable_power_efficient_wq __read_mostly; EXPORT_SYMBOL_GPL(system_freezable_power_efficient_wq); +#ifdef OPLUS_FEATURE_SCHED_ASSIST +struct workqueue_struct *system_ux_wq __read_mostly; +EXPORT_SYMBOL_GPL(system_ux_wq); +#endif static int worker_thread(void *__worker); static void workqueue_sysfs_unregister(struct workqueue_struct *wq); @@ -1337,6 +1345,7 @@ static void insert_work(struct pool_workqueue *pwq, struct work_struct *work, /* we own @work, set data and link */ set_work_pwq(work, pwq, extra_flags); list_add_tail(&work->entry, head); + get_pwq(pwq); /* @@ -1844,17 +1853,28 @@ static struct worker *create_worker(struct worker_pool *pool) worker->id = id; +#ifdef OPLUS_FEATURE_SCHED_ASSIST + if (pool->cpu >= 0) + snprintf(id_buf, sizeof(id_buf), "%d:%d%s", pool->cpu, id, + pool->attrs->ux_state > 0 ? "X" : pool->attrs->nice < 0 ? "H" : ""); + else + snprintf(id_buf, sizeof(id_buf), "%s%d:%d", pool->attrs->ux_state > 0 ? "X" : "u", pool->id, id); +#else if (pool->cpu >= 0) snprintf(id_buf, sizeof(id_buf), "%d:%d%s", pool->cpu, id, pool->attrs->nice < 0 ? "H" : ""); else snprintf(id_buf, sizeof(id_buf), "u%d:%d", pool->id, id); - +#endif worker->task = kthread_create_on_node(worker_thread, worker, pool->node, "kworker/%s", id_buf); if (IS_ERR(worker->task)) goto fail; +#ifdef OPLUS_FEATURE_SCHED_ASSIST + worker->task->ux_state = pool->attrs->ux_state; +#endif + set_user_nice(worker->task, pool->attrs->nice); kthread_bind_mask(worker->task, pool->attrs->cpumask); @@ -2092,6 +2112,7 @@ __acquires(&pool->lock) bool cpu_intensive = pwq->wq->flags & WQ_CPU_INTENSIVE; int work_color; struct worker *collision; + #ifdef CONFIG_LOCKDEP /* * It is permissible to free the struct work_struct from @@ -2188,9 +2209,11 @@ __acquires(&pool->lock) * flush_work() and complete() primitives (except for single-threaded * workqueues), so hiding them isn't a problem. */ + lockdep_invariant_state(true); trace_workqueue_execute_start(work); worker->current_func(work); + /* * While we must be careful to not use "work" after this, the trace * point will only record its address. @@ -3294,6 +3317,9 @@ static void copy_workqueue_attrs(struct workqueue_attrs *to, const struct workqueue_attrs *from) { to->nice = from->nice; +#ifdef OPLUS_FEATURE_SCHED_ASSIST + to->ux_state = from->ux_state; +#endif cpumask_copy(to->cpumask, from->cpumask); /* * Unlike hash and equality test, this function doesn't ignore @@ -3309,6 +3335,9 @@ static u32 wqattrs_hash(const struct workqueue_attrs *attrs) u32 hash = 0; hash = jhash_1word(attrs->nice, hash); +#ifdef OPLUS_FEATURE_SCHED_ASSIST + hash = jhash_1word(attrs->ux_state, hash); +#endif hash = jhash(cpumask_bits(attrs->cpumask), BITS_TO_LONGS(nr_cpumask_bits) * sizeof(long), hash); return hash; @@ -3320,6 +3349,10 @@ static bool wqattrs_equal(const struct workqueue_attrs *a, { if (a->nice != b->nice) return false; +#ifdef OPLUS_FEATURE_SCHED_ASSIST + if (a->ux_state != b->ux_state) + return false; +#endif if (!cpumask_equal(a->cpumask, b->cpumask)) return false; return true; @@ -4031,7 +4064,11 @@ out_unlock: static int alloc_and_link_pwqs(struct workqueue_struct *wq) { +#ifdef OPLUS_FEATURE_SCHED_ASSIST + int highpri = (wq->flags & WQ_UX) ? UX_WORKER_POOL_INDEX : (wq->flags & WQ_HIGHPRI) ? 1 : 0; +#else bool highpri = wq->flags & WQ_HIGHPRI; +#endif int cpu, ret; if (!(wq->flags & WQ_UNBOUND)) { @@ -4099,7 +4136,11 @@ static int init_rescuer(struct workqueue_struct *wq) kfree(rescuer); return ret; } - +#ifdef OPLUS_FEATURE_SCHED_ASSIST + if (wq->flags & WQ_UX) { + rescuer->task->ux_state = 1; + } +#endif wq->rescuer = rescuer; kthread_bind_mask(rescuer->task, cpu_possible_mask); wake_up_process(rescuer->task); @@ -4144,6 +4185,11 @@ struct workqueue_struct *__alloc_workqueue_key(const char *fmt, wq->unbound_attrs = alloc_workqueue_attrs(GFP_KERNEL); if (!wq->unbound_attrs) goto err_free_wq; +#ifdef OPLUS_FEATURE_SCHED_ASSIST + if (flags & WQ_UX) { + wq->unbound_attrs->ux_state = 1; + } +#endif } va_start(args, lock_name); @@ -4506,12 +4552,56 @@ void print_worker_info(const char *log_lvl, struct task_struct *task) } } +#ifdef CONFIG_OPLUS_FEATURE_MIDAS +void get_worker_info(struct task_struct *task, char *buf) +{ + work_func_t *fn = NULL; + char name[WQ_NAME_LEN] = { }; + char fn_name[WQ_NAME_LEN] = { }; + char desc[WORKER_DESC_LEN] = { }; + struct pool_workqueue *pwq = NULL; + struct workqueue_struct *wq = NULL; + struct worker *worker; + + if (!(task->flags & PF_WQ_WORKER)) + return; + + /* + * This function is called without any synchronization and @task + * could be in any state. Be careful with dereferences. + */ + worker = kthread_probe_data(task); + + /* + * Carefully copy the associated workqueue's workfn and name. Keep + * the original last '\0' in case the original contains garbage. + */ + probe_kernel_read(&fn, &worker->current_func, sizeof(fn)); + probe_kernel_read(&pwq, &worker->current_pwq, sizeof(pwq)); + probe_kernel_read(&wq, &pwq->wq, sizeof(wq)); + probe_kernel_read(name, wq->name, sizeof(name) - 1); + probe_kernel_read(desc, worker->desc, sizeof(desc) - 1); + + if (name[0]) { + strncpy(buf, name, sizeof(name)); + } else if (fn) { + snprintf(fn_name, sizeof(fn_name), "%pf", fn); + if (fn_name[0]) + strncpy(buf, fn_name, sizeof(fn_name)); + } +} +#endif + static void pr_cont_pool_info(struct worker_pool *pool) { pr_cont(" cpus=%*pbl", nr_cpumask_bits, pool->attrs->cpumask); if (pool->node != NUMA_NO_NODE) pr_cont(" node=%d", pool->node); +#ifdef OPLUS_FEATURE_SCHED_ASSIST + pr_cont(" flags=0x%x nice=%d ux=%d", pool->flags, pool->attrs->nice, pool->attrs->ux_state); +#else pr_cont(" flags=0x%x nice=%d", pool->flags, pool->attrs->nice); +#endif } static void pr_cont_work(bool comma, struct work_struct *work) @@ -5779,7 +5869,11 @@ static void __init wq_numa_init(void) */ int __init workqueue_init_early(void) { +#ifdef OPLUS_FEATURE_SCHED_ASSIST + int std_nice[NR_STD_WORKER_POOLS] = { 0, HIGHPRI_NICE_LEVEL, HIGHPRI_NICE_LEVEL }; +#else int std_nice[NR_STD_WORKER_POOLS] = { 0, HIGHPRI_NICE_LEVEL }; +#endif int hk_flags = HK_FLAG_DOMAIN | HK_FLAG_WQ; int i, cpu; @@ -5799,6 +5893,11 @@ int __init workqueue_init_early(void) BUG_ON(init_worker_pool(pool)); pool->cpu = cpu; cpumask_copy(pool->attrs->cpumask, cpumask_of(cpu)); +#ifdef OPLUS_FEATURE_SCHED_ASSIST + if (UX_WORKER_POOL_INDEX == i) { + pool->attrs->ux_state = 1; + } +#endif pool->attrs->nice = std_nice[i++]; pool->node = cpu_to_node(cpu); @@ -5814,6 +5913,11 @@ int __init workqueue_init_early(void) struct workqueue_attrs *attrs; BUG_ON(!(attrs = alloc_workqueue_attrs(GFP_KERNEL))); +#ifdef OPLUS_FEATURE_SCHED_ASSIST + if (UX_WORKER_POOL_INDEX == i) { + attrs->ux_state = 1; + } +#endif attrs->nice = std_nice[i]; unbound_std_wq_attrs[i] = attrs; @@ -5823,6 +5927,11 @@ int __init workqueue_init_early(void) * Turn off NUMA so that dfl_pwq is used for all nodes. */ BUG_ON(!(attrs = alloc_workqueue_attrs(GFP_KERNEL))); +#ifdef OPLUS_FEATURE_SCHED_ASSIST + if (UX_WORKER_POOL_INDEX == i) { + attrs->ux_state = 1; + } +#endif attrs->nice = std_nice[i]; attrs->no_numa = true; ordered_wq_attrs[i] = attrs; @@ -5830,6 +5939,9 @@ int __init workqueue_init_early(void) system_wq = alloc_workqueue("events", 0, 0); system_highpri_wq = alloc_workqueue("events_highpri", WQ_HIGHPRI, 0); +#ifdef OPLUS_FEATURE_SCHED_ASSIST + system_ux_wq = alloc_workqueue("events_ux", WQ_UX, 0); +#endif system_long_wq = alloc_workqueue("events_long", 0, 0); system_unbound_wq = alloc_workqueue("events_unbound", WQ_UNBOUND, WQ_UNBOUND_MAX_ACTIVE); @@ -5840,6 +5952,9 @@ int __init workqueue_init_early(void) system_freezable_power_efficient_wq = alloc_workqueue("events_freezable_power_efficient", WQ_FREEZABLE | WQ_POWER_EFFICIENT, 0); +#ifdef OPLUS_FEATURE_SCHED_ASSIST + BUG_ON(!system_ux_wq); +#endif BUG_ON(!system_wq || !system_highpri_wq || !system_long_wq || !system_unbound_wq || !system_freezable_wq || !system_power_efficient_wq || diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index da9e8f42319e..112272cb5df2 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -244,6 +244,10 @@ config ENABLE_MUST_CHECK config FRAME_WARN int "Warn for stack frames larger than (needs gcc 4.4)" range 0 8192 + #ifdef OPLUS_BUG_STABILITY + #Add for aging test, debug config + default 0 if KASAN + #endif default 2048 if GCC_PLUGIN_LATENT_ENTROPY default 2048 if PARISC default 1536 if (!64BIT && XTENSA) @@ -580,7 +584,9 @@ config HAVE_DEBUG_KMEMLEAK config DEBUG_KMEMLEAK bool "Kernel memory leak detector" depends on DEBUG_KERNEL && HAVE_DEBUG_KMEMLEAK - select DEBUG_FS +#ifdef OPLUS_BUG_STABILITY + #select DEBUG_FS +#endif select STACKTRACE if STACKTRACE_SUPPORT select KALLSYMS select CRC32 diff --git a/lib/Kconfig.kasan b/lib/Kconfig.kasan index 2a049c66dc0e..721524c97f60 100644 --- a/lib/Kconfig.kasan +++ b/lib/Kconfig.kasan @@ -105,7 +105,9 @@ endchoice config KASAN_STACK_ENABLE bool "Enable stack instrumentation (unsafe)" if CC_IS_CLANG && !COMPILE_TEST - depends on KASAN + #ifdef OPLUS_BUG_STABILITY + depends on !KASAN + #endif help The LLVM stack address sanitizer has a know problem that causes excessive stack usage in a lot of functions, see diff --git a/lib/Makefile b/lib/Makefile index 424494d6160d..d3e8d5b5e5f5 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -291,3 +291,8 @@ obj-$(CONFIG_GENERIC_LIB_LSHRDI3) += lshrdi3.o obj-$(CONFIG_GENERIC_LIB_MULDI3) += muldi3.o obj-$(CONFIG_GENERIC_LIB_CMPDI2) += cmpdi2.o obj-$(CONFIG_GENERIC_LIB_UCMPDI2) += ucmpdi2.o + +# ifdef OPLUS_FEATURE_MEMLEAK_DETECT +# /* add memleak detect stack depot */ +obj-$(CONFIG_VMALLOC_DEBUG) += memleak_debug_stackdepot.o +# endif diff --git a/lib/lz4/lz4_decompress.c b/lib/lz4/lz4_decompress.c index 141734d255e4..0c9d3ad17e0f 100644 --- a/lib/lz4/lz4_decompress.c +++ b/lib/lz4/lz4_decompress.c @@ -43,30 +43,36 @@ /*-***************************** * Decompression functions *******************************/ -/* LZ4_decompress_generic() : - * This generic decompression function cover all use cases. - * It shall be instantiated several times, using different sets of directives - * Note that it is important this generic function is really inlined, + +#define DEBUGLOG(l, ...) {} /* disabled */ + +#ifndef assert +#define assert(condition) ((void)0) +#endif + +/* + * LZ4_decompress_generic() : + * This generic decompression function covers all use cases. + * It shall be instantiated several times, using different sets of directives. + * Note that it is important for performance that this function really get inlined, * in order to remove useless branches during compilation optimization. */ static FORCE_INLINE int LZ4_decompress_generic( - const char * const source, - char * const dest, - int inputSize, + const char * const src, + char * const dst, + int srcSize, /* * If endOnInput == endOnInputSize, - * this value is the max size of Output Buffer. + * this value is `dstCapacity` */ int outputSize, /* endOnOutputSize, endOnInputSize */ - int endOnInput, + endCondition_directive endOnInput, /* full, partial */ - int partialDecoding, - /* only used if partialDecoding == partial */ - int targetOutputSize, + earlyEnd_directive partialDecoding, /* noDict, withPrefix64k, usingExtDict */ - int dict, - /* == dest when no prefix */ + dict_directive dict, + /* always <= dst, == dst when no prefix */ const BYTE * const lowPrefix, /* only if dict == usingExtDict */ const BYTE * const dictStart, @@ -74,35 +80,43 @@ static FORCE_INLINE int LZ4_decompress_generic( const size_t dictSize ) { - /* Local Variables */ - const BYTE *ip = (const BYTE *) source; - const BYTE * const iend = ip + inputSize; + const BYTE *ip = (const BYTE *) src; + const BYTE * const iend = ip + srcSize; - BYTE *op = (BYTE *) dest; + BYTE *op = (BYTE *) dst; BYTE * const oend = op + outputSize; BYTE *cpy; - BYTE *oexit = op + targetOutputSize; - const BYTE * const lowLimit = lowPrefix - dictSize; const BYTE * const dictEnd = (const BYTE *)dictStart + dictSize; - static const unsigned int dec32table[] = { 0, 1, 2, 1, 4, 4, 4, 4 }; - static const int dec64table[] = { 0, 0, 0, -1, 0, 1, 2, 3 }; + static const unsigned int inc32table[8] = {0, 1, 2, 1, 0, 4, 4, 4}; + static const int dec64table[8] = {0, 0, 0, -1, -4, 1, 2, 3}; const int safeDecode = (endOnInput == endOnInputSize); const int checkOffset = ((safeDecode) && (dictSize < (int)(64 * KB))); + /* Set up the "end" pointers for the shortcut. */ + const BYTE *const shortiend = iend - + (endOnInput ? 14 : 8) /*maxLL*/ - 2 /*offset*/; + const BYTE *const shortoend = oend - + (endOnInput ? 14 : 8) /*maxLL*/ - 18 /*maxML*/; + + DEBUGLOG(5, "%s (srcSize:%i, dstSize:%i)", __func__, + srcSize, outputSize); + /* Special cases */ - /* targetOutputSize too high => decode everything */ - if ((partialDecoding) && (oexit > oend - MFLIMIT)) - oexit = oend - MFLIMIT; + assert(lowPrefix <= op); + assert(src != NULL); /* Empty output buffer */ if ((endOnInput) && (unlikely(outputSize == 0))) - return ((inputSize == 1) && (*ip == 0)) ? 0 : -1; + return ((srcSize == 1) && (*ip == 0)) ? 0 : -1; if ((!endOnInput) && (unlikely(outputSize == 0))) return (*ip == 0 ? 1 : -1); + if ((endOnInput) && unlikely(srcSize == 0)) + return -1; + /* Main Loop : decode sequences */ while (1) { size_t length; @@ -111,12 +125,74 @@ static FORCE_INLINE int LZ4_decompress_generic( /* get literal length */ unsigned int const token = *ip++; - length = token>>ML_BITS; + /* ip < iend before the increment */ + assert(!endOnInput || ip <= iend); + + /* + * A two-stage shortcut for the most common case: + * 1) If the literal length is 0..14, and there is enough + * space, enter the shortcut and copy 16 bytes on behalf + * of the literals (in the fast mode, only 8 bytes can be + * safely copied this way). + * 2) Further if the match length is 4..18, copy 18 bytes + * in a similar manner; but we ensure that there's enough + * space in the output for those 18 bytes earlier, upon + * entering the shortcut (in other words, there is a + * combined check for both stages). + */ + if ((endOnInput ? length != RUN_MASK : length <= 8) + /* + * strictly "less than" on input, to re-enter + * the loop with at least one byte + */ + && likely((endOnInput ? ip < shortiend : 1) & + (op <= shortoend))) { + /* Copy the literals */ + memcpy(op, ip, endOnInput ? 16 : 8); + op += length; ip += length; + + /* + * The second stage: + * prepare for match copying, decode full info. + * If it doesn't work out, the info won't be wasted. + */ + length = token & ML_MASK; /* match length */ + offset = LZ4_readLE16(ip); + ip += 2; + match = op - offset; + assert(match <= op); /* check overflow */ + + /* Do not deal with overlapping matches. */ + if ((length != ML_MASK) && + (offset >= 8) && + (dict == withPrefix64k || match >= lowPrefix)) { + /* Copy the match. */ + memcpy(op + 0, match + 0, 8); + memcpy(op + 8, match + 8, 8); + memcpy(op + 16, match + 16, 2); + op += length + MINMATCH; + /* Both stages worked, load the next token. */ + continue; + } + + /* + * The second stage didn't work out, but the info + * is ready. Propel it right to the point of match + * copying. + */ + goto _copy_match; + } + + /* decode literal length */ if (length == RUN_MASK) { unsigned int s; + if (unlikely(endOnInput ? ip >= iend - RUN_MASK : 0)) { + /* overflow detection */ + goto _output_error; + } do { s = *ip++; length += s; @@ -125,14 +201,14 @@ static FORCE_INLINE int LZ4_decompress_generic( : 1) & (s == 255)); if ((safeDecode) - && unlikely( - (size_t)(op + length) < (size_t)(op))) { + && unlikely((uptrval)(op) + + length < (uptrval)(op))) { /* overflow detection */ goto _output_error; } if ((safeDecode) - && unlikely( - (size_t)(ip + length) < (size_t)(ip))) { + && unlikely((uptrval)(ip) + + length < (uptrval)(ip))) { /* overflow detection */ goto _output_error; } @@ -140,16 +216,19 @@ static FORCE_INLINE int LZ4_decompress_generic( /* copy literals */ cpy = op + length; - if (((endOnInput) && ((cpy > (partialDecoding ? oexit : oend - MFLIMIT)) + LZ4_STATIC_ASSERT(MFLIMIT >= WILDCOPYLENGTH); + + if (((endOnInput) && ((cpy > oend - MFLIMIT) || (ip + length > iend - (2 + 1 + LASTLITERALS)))) || ((!endOnInput) && (cpy > oend - WILDCOPYLENGTH))) { if (partialDecoding) { if (cpy > oend) { /* - * Error : - * write attempt beyond end of output buffer + * Partial decoding : + * stop in the middle of literal segment */ - goto _output_error; + cpy = oend; + length = oend - op; } if ((endOnInput) && (ip + length > iend)) { @@ -184,29 +263,43 @@ static FORCE_INLINE int LZ4_decompress_generic( memcpy(op, ip, length); ip += length; op += length; - /* Necessarily EOF, due to parsing restrictions */ - break; - } - LZ4_wildCopy(op, ip, cpy); - ip += length; - op = cpy; + /* Necessarily EOF, due to parsing restrictions */ + if (!partialDecoding || (cpy == oend)) + break; + } else { + /* may overwrite up to WILDCOPYLENGTH beyond cpy */ + LZ4_wildCopy(op, ip, cpy); + ip += length; + op = cpy; + } /* get offset */ offset = LZ4_readLE16(ip); ip += 2; match = op - offset; - if ((checkOffset) && (unlikely(match < lowLimit))) { + /* get matchlength */ + length = token & ML_MASK; + +_copy_match: + if ((checkOffset) && (unlikely(match + dictSize < lowPrefix))) { /* Error : offset outside buffers */ goto _output_error; } /* costs ~1%; silence an msan warning when offset == 0 */ - LZ4_write32(op, (U32)offset); + /* + * note : when partialDecoding, there is no guarantee that + * at least 4 bytes remain available in output buffer + */ + if (!partialDecoding) { + assert(oend > op); + assert(oend - op >= 4); + + LZ4_write32(op, (U32)offset); + } - /* get matchlength */ - length = token & ML_MASK; if (length == ML_MASK) { unsigned int s; @@ -221,7 +314,7 @@ static FORCE_INLINE int LZ4_decompress_generic( if ((safeDecode) && unlikely( - (size_t)(op + length) < (size_t)op)) { + (uptrval)(op) + length < (uptrval)op)) { /* overflow detection */ goto _output_error; } @@ -229,24 +322,26 @@ static FORCE_INLINE int LZ4_decompress_generic( length += MINMATCH; - /* check external dictionary */ + /* match starting within external dictionary */ if ((dict == usingExtDict) && (match < lowPrefix)) { if (unlikely(op + length > oend - LASTLITERALS)) { /* doesn't respect parsing restriction */ - goto _output_error; + if (!partialDecoding) + goto _output_error; + length = min(length, (size_t)(oend - op)); } if (length <= (size_t)(lowPrefix - match)) { /* - * match can be copied as a single segment - * from external dictionary + * match fits entirely within external + * dictionary : just copy */ memmove(op, dictEnd - (lowPrefix - match), length); op += length; } else { /* - * match encompass external + * match stretches into both external * dictionary and current block */ size_t const copySize = (size_t)(lowPrefix - match); @@ -254,7 +349,6 @@ static FORCE_INLINE int LZ4_decompress_generic( memcpy(op, dictEnd - copySize, copySize); op += copySize; - if (restSize > (size_t)(op - lowPrefix)) { /* overlap copy */ BYTE * const endOfMatch = op + restSize; @@ -267,23 +361,44 @@ static FORCE_INLINE int LZ4_decompress_generic( op += restSize; } } - continue; } /* copy match within block */ cpy = op + length; - if (unlikely(offset < 8)) { - const int dec64 = dec64table[offset]; + /* + * partialDecoding : + * may not respect endBlock parsing restrictions + */ + assert(op <= oend); + if (partialDecoding && + (cpy > oend - MATCH_SAFEGUARD_DISTANCE)) { + size_t const mlen = min(length, (size_t)(oend - op)); + const BYTE * const matchEnd = match + mlen; + BYTE * const copyEnd = op + mlen; + if (matchEnd > op) { + /* overlap copy */ + while (op < copyEnd) + *op++ = *match++; + } else { + memcpy(op, match, mlen); + } + op = copyEnd; + if (op == oend) + break; + continue; + } + + if (unlikely(offset < 8)) { op[0] = match[0]; op[1] = match[1]; op[2] = match[2]; op[3] = match[3]; - match += dec32table[offset]; + match += inc32table[offset]; memcpy(op + 4, match, 4); - match -= dec64; + match -= dec64table[offset]; } else { LZ4_copy8(op, match); match += 8; @@ -291,7 +406,7 @@ static FORCE_INLINE int LZ4_decompress_generic( op += 8; - if (unlikely(cpy > oend - 12)) { + if (unlikely(cpy > oend - MATCH_SAFEGUARD_DISTANCE)) { BYTE * const oCopyLimit = oend - (WILDCOPYLENGTH - 1); if (cpy > oend - LASTLITERALS) { @@ -307,60 +422,139 @@ static FORCE_INLINE int LZ4_decompress_generic( match += oCopyLimit - op; op = oCopyLimit; } - while (op < cpy) *op++ = *match++; } else { LZ4_copy8(op, match); - if (length > 16) LZ4_wildCopy(op + 8, match + 8, cpy); } - - op = cpy; /* correction */ + op = cpy; /* wildcopy correction */ } /* end of decoding */ if (endOnInput) { /* Nb of output bytes decoded */ - return (int) (((char *)op) - dest); + return (int) (((char *)op) - dst); } else { /* Nb of input bytes read */ - return (int) (((const char *)ip) - source); + return (int) (((const char *)ip) - src); } /* Overflow error detected */ _output_error: - return -1; + return (int) (-(((const char *)ip) - src)) - 1; } int LZ4_decompress_safe(const char *source, char *dest, int compressedSize, int maxDecompressedSize) { - return LZ4_decompress_generic(source, dest, compressedSize, - maxDecompressedSize, endOnInputSize, full, 0, - noDict, (BYTE *)dest, NULL, 0); + return LZ4_decompress_generic(source, dest, + compressedSize, maxDecompressedSize, + endOnInputSize, decode_full_block, + noDict, (BYTE *)dest, NULL, 0); } -int LZ4_decompress_safe_partial(const char *source, char *dest, - int compressedSize, int targetOutputSize, int maxDecompressedSize) +int LZ4_decompress_safe_partial(const char *src, char *dst, + int compressedSize, int targetOutputSize, int dstCapacity) { - return LZ4_decompress_generic(source, dest, compressedSize, - maxDecompressedSize, endOnInputSize, partial, - targetOutputSize, noDict, (BYTE *)dest, NULL, 0); + dstCapacity = min(targetOutputSize, dstCapacity); + return LZ4_decompress_generic(src, dst, compressedSize, dstCapacity, + endOnInputSize, partial_decode, + noDict, (BYTE *)dst, NULL, 0); } int LZ4_decompress_fast(const char *source, char *dest, int originalSize) { return LZ4_decompress_generic(source, dest, 0, originalSize, - endOnOutputSize, full, 0, withPrefix64k, - (BYTE *)(dest - 64 * KB), NULL, 64 * KB); + endOnOutputSize, decode_full_block, + withPrefix64k, + (BYTE *)dest - 64 * KB, NULL, 0); } +/* ===== Instantiate a few more decoding cases, used more than once. ===== */ + +int LZ4_decompress_safe_withPrefix64k(const char *source, char *dest, + int compressedSize, int maxOutputSize) +{ + return LZ4_decompress_generic(source, dest, + compressedSize, maxOutputSize, + endOnInputSize, decode_full_block, + withPrefix64k, + (BYTE *)dest - 64 * KB, NULL, 0); +} + +static int LZ4_decompress_safe_withSmallPrefix(const char *source, char *dest, + int compressedSize, + int maxOutputSize, + size_t prefixSize) +{ + return LZ4_decompress_generic(source, dest, + compressedSize, maxOutputSize, + endOnInputSize, decode_full_block, + noDict, + (BYTE *)dest - prefixSize, NULL, 0); +} + +int LZ4_decompress_safe_forceExtDict(const char *source, char *dest, + int compressedSize, int maxOutputSize, + const void *dictStart, size_t dictSize) +{ + return LZ4_decompress_generic(source, dest, + compressedSize, maxOutputSize, + endOnInputSize, decode_full_block, + usingExtDict, (BYTE *)dest, + (const BYTE *)dictStart, dictSize); +} + +static int LZ4_decompress_fast_extDict(const char *source, char *dest, + int originalSize, + const void *dictStart, size_t dictSize) +{ + return LZ4_decompress_generic(source, dest, + 0, originalSize, + endOnOutputSize, decode_full_block, + usingExtDict, (BYTE *)dest, + (const BYTE *)dictStart, dictSize); +} + +/* + * The "double dictionary" mode, for use with e.g. ring buffers: the first part + * of the dictionary is passed as prefix, and the second via dictStart + dictSize. + * These routines are used only once, in LZ4_decompress_*_continue(). + */ +static FORCE_INLINE +int LZ4_decompress_safe_doubleDict(const char *source, char *dest, + int compressedSize, int maxOutputSize, + size_t prefixSize, + const void *dictStart, size_t dictSize) +{ + return LZ4_decompress_generic(source, dest, + compressedSize, maxOutputSize, + endOnInputSize, decode_full_block, + usingExtDict, (BYTE *)dest - prefixSize, + (const BYTE *)dictStart, dictSize); +} + +static FORCE_INLINE +int LZ4_decompress_fast_doubleDict(const char *source, char *dest, + int originalSize, size_t prefixSize, + const void *dictStart, size_t dictSize) +{ + return LZ4_decompress_generic(source, dest, + 0, originalSize, + endOnOutputSize, decode_full_block, + usingExtDict, (BYTE *)dest - prefixSize, + (const BYTE *)dictStart, dictSize); +} + +/* ===== streaming decompression functions ===== */ + int LZ4_setStreamDecode(LZ4_streamDecode_t *LZ4_streamDecode, const char *dictionary, int dictSize) { - LZ4_streamDecode_t_internal *lz4sd = (LZ4_streamDecode_t_internal *) LZ4_streamDecode; + LZ4_streamDecode_t_internal *lz4sd = + &LZ4_streamDecode->internal_donotuse; lz4sd->prefixSize = (size_t) dictSize; lz4sd->prefixEnd = (const BYTE *) dictionary + dictSize; @@ -382,35 +576,51 @@ int LZ4_setStreamDecode(LZ4_streamDecode_t *LZ4_streamDecode, int LZ4_decompress_safe_continue(LZ4_streamDecode_t *LZ4_streamDecode, const char *source, char *dest, int compressedSize, int maxOutputSize) { - LZ4_streamDecode_t_internal *lz4sd = &LZ4_streamDecode->internal_donotuse; + LZ4_streamDecode_t_internal *lz4sd = + &LZ4_streamDecode->internal_donotuse; int result; - if (lz4sd->prefixEnd == (BYTE *)dest) { - result = LZ4_decompress_generic(source, dest, - compressedSize, - maxOutputSize, - endOnInputSize, full, 0, - usingExtDict, lz4sd->prefixEnd - lz4sd->prefixSize, - lz4sd->externalDict, - lz4sd->extDictSize); - + if (lz4sd->prefixSize == 0) { + /* The first call, no dictionary yet. */ + assert(lz4sd->extDictSize == 0); + result = LZ4_decompress_safe(source, dest, + compressedSize, maxOutputSize); + if (result <= 0) + return result; + lz4sd->prefixSize = result; + lz4sd->prefixEnd = (BYTE *)dest + result; + } else if (lz4sd->prefixEnd == (BYTE *)dest) { + /* They're rolling the current segment. */ + if (lz4sd->prefixSize >= 64 * KB - 1) + result = LZ4_decompress_safe_withPrefix64k(source, dest, + compressedSize, maxOutputSize); + else if (lz4sd->extDictSize == 0) + result = LZ4_decompress_safe_withSmallPrefix(source, + dest, compressedSize, maxOutputSize, + lz4sd->prefixSize); + else + result = LZ4_decompress_safe_doubleDict(source, dest, + compressedSize, maxOutputSize, + lz4sd->prefixSize, + lz4sd->externalDict, lz4sd->extDictSize); if (result <= 0) return result; - lz4sd->prefixSize += result; - lz4sd->prefixEnd += result; + lz4sd->prefixEnd += result; } else { + /* + * The buffer wraps around, or they're + * switching to another buffer. + */ lz4sd->extDictSize = lz4sd->prefixSize; lz4sd->externalDict = lz4sd->prefixEnd - lz4sd->extDictSize; - result = LZ4_decompress_generic(source, dest, + result = LZ4_decompress_safe_forceExtDict(source, dest, compressedSize, maxOutputSize, - endOnInputSize, full, 0, - usingExtDict, (BYTE *)dest, lz4sd->externalDict, lz4sd->extDictSize); if (result <= 0) return result; lz4sd->prefixSize = result; - lz4sd->prefixEnd = (BYTE *)dest + result; + lz4sd->prefixEnd = (BYTE *)dest + result; } return result; @@ -422,75 +632,66 @@ int LZ4_decompress_fast_continue(LZ4_streamDecode_t *LZ4_streamDecode, LZ4_streamDecode_t_internal *lz4sd = &LZ4_streamDecode->internal_donotuse; int result; - if (lz4sd->prefixEnd == (BYTE *)dest) { - result = LZ4_decompress_generic(source, dest, 0, originalSize, - endOnOutputSize, full, 0, - usingExtDict, - lz4sd->prefixEnd - lz4sd->prefixSize, - lz4sd->externalDict, lz4sd->extDictSize); - - if (result <= 0) - return result; - - lz4sd->prefixSize += originalSize; - lz4sd->prefixEnd += originalSize; - } else { - lz4sd->extDictSize = lz4sd->prefixSize; - lz4sd->externalDict = lz4sd->prefixEnd - lz4sd->extDictSize; - result = LZ4_decompress_generic(source, dest, 0, originalSize, - endOnOutputSize, full, 0, - usingExtDict, (BYTE *)dest, - lz4sd->externalDict, lz4sd->extDictSize); + if (lz4sd->prefixSize == 0) { + assert(lz4sd->extDictSize == 0); + result = LZ4_decompress_fast(source, dest, originalSize); if (result <= 0) return result; lz4sd->prefixSize = originalSize; - lz4sd->prefixEnd = (BYTE *)dest + originalSize; + lz4sd->prefixEnd = (BYTE *)dest + originalSize; + } else if (lz4sd->prefixEnd == (BYTE *)dest) { + if (lz4sd->prefixSize >= 64 * KB - 1 || + lz4sd->extDictSize == 0) + result = LZ4_decompress_fast(source, dest, + originalSize); + else + result = LZ4_decompress_fast_doubleDict(source, dest, + originalSize, lz4sd->prefixSize, + lz4sd->externalDict, lz4sd->extDictSize); + if (result <= 0) + return result; + lz4sd->prefixSize += originalSize; + lz4sd->prefixEnd += originalSize; + } else { + lz4sd->extDictSize = lz4sd->prefixSize; + lz4sd->externalDict = lz4sd->prefixEnd - lz4sd->extDictSize; + result = LZ4_decompress_fast_extDict(source, dest, + originalSize, lz4sd->externalDict, lz4sd->extDictSize); + if (result <= 0) + return result; + lz4sd->prefixSize = originalSize; + lz4sd->prefixEnd = (BYTE *)dest + originalSize; } - return result; } -/* - * Advanced decoding functions : - * *_usingDict() : - * These decoding functions work the same as "_continue" ones, - * the dictionary must be explicitly provided within parameters - */ -static FORCE_INLINE int LZ4_decompress_usingDict_generic(const char *source, - char *dest, int compressedSize, int maxOutputSize, int safe, - const char *dictStart, int dictSize) +int LZ4_decompress_safe_usingDict(const char *source, char *dest, + int compressedSize, int maxOutputSize, + const char *dictStart, int dictSize) { if (dictSize == 0) - return LZ4_decompress_generic(source, dest, - compressedSize, maxOutputSize, safe, full, 0, - noDict, (BYTE *)dest, NULL, 0); - if (dictStart + dictSize == dest) { - if (dictSize >= (int)(64 * KB - 1)) - return LZ4_decompress_generic(source, dest, - compressedSize, maxOutputSize, safe, full, 0, - withPrefix64k, (BYTE *)dest - 64 * KB, NULL, 0); - return LZ4_decompress_generic(source, dest, compressedSize, - maxOutputSize, safe, full, 0, noDict, - (BYTE *)dest - dictSize, NULL, 0); + return LZ4_decompress_safe(source, dest, + compressedSize, maxOutputSize); + if (dictStart+dictSize == dest) { + if (dictSize >= 64 * KB - 1) + return LZ4_decompress_safe_withPrefix64k(source, dest, + compressedSize, maxOutputSize); + return LZ4_decompress_safe_withSmallPrefix(source, dest, + compressedSize, maxOutputSize, dictSize); } - return LZ4_decompress_generic(source, dest, compressedSize, - maxOutputSize, safe, full, 0, usingExtDict, - (BYTE *)dest, (const BYTE *)dictStart, dictSize); -} - -int LZ4_decompress_safe_usingDict(const char *source, char *dest, - int compressedSize, int maxOutputSize, - const char *dictStart, int dictSize) -{ - return LZ4_decompress_usingDict_generic(source, dest, - compressedSize, maxOutputSize, 1, dictStart, dictSize); + return LZ4_decompress_safe_forceExtDict(source, dest, + compressedSize, maxOutputSize, dictStart, dictSize); } int LZ4_decompress_fast_usingDict(const char *source, char *dest, - int originalSize, const char *dictStart, int dictSize) + int originalSize, + const char *dictStart, int dictSize) { - return LZ4_decompress_usingDict_generic(source, dest, 0, - originalSize, 0, dictStart, dictSize); + if (dictSize == 0 || dictStart + dictSize == dest) + return LZ4_decompress_fast(source, dest, originalSize); + + return LZ4_decompress_fast_extDict(source, dest, originalSize, + dictStart, dictSize); } #ifndef STATIC diff --git a/lib/lz4/lz4defs.h b/lib/lz4/lz4defs.h index 00a0b58a0871..1a7fa9d9170f 100644 --- a/lib/lz4/lz4defs.h +++ b/lib/lz4/lz4defs.h @@ -75,6 +75,11 @@ typedef uintptr_t uptrval; #define WILDCOPYLENGTH 8 #define LASTLITERALS 5 #define MFLIMIT (WILDCOPYLENGTH + MINMATCH) +/* + * ensure it's possible to write 2 x wildcopyLength + * without overflowing output buffer + */ +#define MATCH_SAFEGUARD_DISTANCE ((2 * WILDCOPYLENGTH) - MINMATCH) /* Increase this value ==> compression run slower on incompressible data */ #define LZ4_SKIPTRIGGER 6 @@ -222,6 +227,8 @@ typedef enum { noDict = 0, withPrefix64k, usingExtDict } dict_directive; typedef enum { noDictIssue = 0, dictSmall } dictIssue_directive; typedef enum { endOnOutputSize = 0, endOnInputSize = 1 } endCondition_directive; -typedef enum { full = 0, partial = 1 } earlyEnd_directive; +typedef enum { decode_full_block = 0, partial_decode = 1 } earlyEnd_directive; + +#define LZ4_STATIC_ASSERT(c) BUILD_BUG_ON(!(c)) #endif diff --git a/lib/memleak_debug_stackdepot.c b/lib/memleak_debug_stackdepot.c new file mode 120000 index 000000000000..867809917b64 --- /dev/null +++ b/lib/memleak_debug_stackdepot.c @@ -0,0 +1 @@ +../../../vendor/oplus/kernel/oplus_performance/memleak_detect/stack_depot/memleak_debug_stackdepot.c \ No newline at end of file diff --git a/lib/show_mem.c b/lib/show_mem.c index 0beaa1d899aa..edb51c877ca9 100644 --- a/lib/show_mem.c +++ b/lib/show_mem.c @@ -9,6 +9,10 @@ #include #include +#ifdef OPLUS_FEATURE_HEALTHINFO +#include +#endif /* OPLUS_FEATURE_HEALTHINFO */ + void show_mem(unsigned int filter, nodemask_t *nodemask) { pg_data_t *pgdat; @@ -49,4 +53,7 @@ void show_mem(unsigned int filter, nodemask_t *nodemask) #ifdef CONFIG_MEMORY_FAILURE printk("%lu pages hwpoisoned\n", atomic_long_read(&num_poisoned_pages)); #endif +#ifdef OPLUS_FEATURE_HEALTHINFO + printk("%lu pages ion total used\n", ion_total()>> PAGE_SHIFT); +#endif /* OPLUS_FEATURE_HEALTHINFO */ } diff --git a/mm/Kconfig b/mm/Kconfig index b6dbab55f77a..b4ed9d5381a2 100644 --- a/mm/Kconfig +++ b/mm/Kconfig @@ -711,10 +711,19 @@ config DEFERRED_STRUCT_PAGE_INIT lifetime of the system until these kthreads finish the initialisation. +config PAGE_IDLE_FLAG + bool "Add PG_idle and PG_young flags" + default y + help + This feature adds PG_idle and PG_young flags in 'struct page'. PTE + Accessed bit writers can set the state of the bit in the flags to let + other PTE Accessed bit readers don't disturbed. + config IDLE_PAGE_TRACKING bool "Enable idle page tracking" depends on SYSFS && MMU select PAGE_EXTENSION if !64BIT + select PAGE_IDLE_FLAG help This feature allows to estimate the amount of user pages that have not been touched during a given period of time. This information can @@ -858,6 +867,19 @@ config GUP_BENCHMARK config ARCH_HAS_PTE_SPECIAL bool +source "mm/damon/Kconfig" + +# multi-gen LRU { +config LRU_GEN + bool "Multi-Gen LRU" + +config LRU_GEN_ENABLED + bool "Disable by default, Need switch by sysfs control" + +config LRU_GEN_STATS + bool "Full stats for debugging" +# } + endmenu config PROCESS_RECLAIM @@ -876,6 +898,62 @@ config PROCESS_RECLAIM Any other value is ignored. +#ifdef OPLUS_FEATURE_HEALTHINFO +source "mm/healthinfo/Kconfig" +#endif /* OPLUS_FEATURE_HEALTHINFO */ + +#ifdef OPLUS_FEATURE_MEMORY_ISOLATE +source "mm/memory_isolate/Kconfig" +#endif /*OPLUS_FEATURE_MEMORY_ISOLATE*/ + +#ifdef OPLUS_FEATURE_MULTI_KSWAPD +source "mm/multi_kswapd/Kconfig" +#endif /*OPLUS_FEATURE_MULTI_KSWAPD*/ + +# if defined(OPLUS_FEATURE_PROCESS_RECLAIM) +# inactive pages only +config PROCESS_RECLAIM_ENHANCE + bool "Enable process reclaim enchance" + depends on PROCESS_RECLAIM + default y + help + It allows to reclaim different type pages of the process by + /proc/process_reclaim. + + (echo inactive_file > /proc/PID/reclaim) reclaims inactive file-backed + pages only. + (echo inactive_anon > /proc/PID/reclaim) reclaims inactive anonymous + pages only. + (echo inactive > /proc/PID/reclaim) reclaims inactive file-backed and + anonymous pages only. + Any other vaule, please reference PROCESS_RECLAIM. +#endif /* OPLUS_FEATURE_PROCESS_RECLAIM */ + +#ifdef OPLUS_FEATURE_VIRTUAL_RESERVE_MEMORY +config VIRTUAL_RESERVE_MEMORY + bool "reserved vma for gpu emergency mmap" + default y + help + support reserved vma for gpu emergency mmap. +#endif +#ifdef OPLUS_FEATURE_MULTI_FREEAREA +config PHYSICAL_ANTI_FRAGMENTATION + bool "Physical memory anti-fragmentation" + default y + help + Turn on the function of Physical memory anti-fragmentation. +#endif /* OPLUS_FEATURE_MULTI_FREEAREA */ + +config DYNAMIC_TUNNING_SWAPPINESS + bool "tunning swappiess depends on file_pages size" + default n + help + tunning swappiess depends on file_pages size + +#ifdef OPLUS_FEATURE_MEMLEAK_DETECT +source "mm/malloc_track/Kconfig" +source "mm/task_mem/Kconfig" +#endif config FORCE_ALLOC_FROM_DMA_ZONE bool "Force certain memory allocators to always return ZONE_DMA32 memory" depends on ZONE_DMA32 diff --git a/mm/Makefile b/mm/Makefile index e4d01019dc67..e84f1c3ab108 100644 --- a/mm/Makefile +++ b/mm/Makefile @@ -109,3 +109,38 @@ obj-$(CONFIG_PERCPU_STATS) += percpu-stats.o obj-$(CONFIG_HMM) += hmm.o obj-$(CONFIG_MEMFD_CREATE) += memfd.o obj-$(CONFIG_PROCESS_RECLAIM) += process_reclaim.o +obj-$(CONFIG_DAMON) += damon/ + +#ifdef OPLUS_FEATURE_HEALTHINFO +obj-y += healthinfo/ +#endif /* OPLUS_FEATURE_HEALTHINFO */ + +#ifdef OPLUS_FEATURE_MEMORY_ISOLATE +obj-$(CONFIG_OPLUS_MEMORY_ISOLATE) += memory_isolate/ +#endif /*OPLUS_FEATURE_MEMORY_ISOLATE*/ + +#ifdef OPLUS_FEATURE_MULTI_KSWAPD +obj-$(CONFIG_OPLUS_MULTI_KSWAPD) += multi_kswapd/ +#endif /*OPLUS_FEATURE_MULTI_KSWAPD*/ + +#if defined(OPLUS_FEATURE_PROCESS_RECLAIM) +ifeq ($(OPLUS_FEATURE_PROCESS_RECLAIM), yes) +obj-$(CONFIG_PROCESS_RECLAIM_ENHANCE) += process_mm_reclaim.o +else +obj-$(CONFIG_PROCESS_RECLAIM_ENHANCE) += process_mm_reclaim_weak.o +endif +#endif /*defined(OPLUS_FEATURE_PROCESS_RECLAIM) + +#if defined(OPLUS_FEATURE_VIRTUAL_RESERVE_MEMORY) +obj-$(CONFIG_VIRTUAL_RESERVE_MEMORY) += reserve_area.o +#endif + +#if defined(OPLUS_FEATURE_MULTI_FREEAREA) +obj-$(CONFIG_PHYSICAL_ANTI_FRAGMENTATION) += multi_freearea.o +#endif + +#if defined(OPLUS_FEATURE_MEMLEAK_DETECT) +ifeq ($(OPLUS_FEATURE_MEMLEAK_DETECT), yes) +obj-$(CONFIG_DUMP_TASKS_MEM) += task_mem/ +endif +#endif /*defined(OPLUS_FEATURE_MEMLEAK_DETECT) diff --git a/mm/compaction.c b/mm/compaction.c index 3ac625bc1572..5a106f527d29 100644 --- a/mm/compaction.c +++ b/mm/compaction.c @@ -23,6 +23,9 @@ #include #include #include +#if defined(OPLUS_FEATURE_MULTI_FREEAREA) && defined(CONFIG_PHYSICAL_ANTI_FRAGMENTATION) +#include +#endif #include "internal.h" #ifdef CONFIG_COMPACTION @@ -984,7 +987,7 @@ isolate_migratepages_block(struct compact_control *cc, unsigned long low_pfn, VM_BUG_ON_PAGE(PageCompound(page), page); /* Successfully isolated */ - del_page_from_lru_list(page, lruvec, page_lru(page)); + del_page_from_lru_list(page, lruvec); inc_node_page_state(page, NR_ISOLATED_ANON + page_is_file_cache(page)); @@ -1282,6 +1285,9 @@ fast_isolate_freepages(struct compact_control *cc) struct page *page = NULL; bool scan_start = false; int order; +#if defined(OPLUS_FEATURE_MULTI_FREEAREA) && defined(CONFIG_PHYSICAL_ANTI_FRAGMENTATION) + int flc = 0; +#endif /* Full compaction passes in a negative order */ if (cc->order <= 0) @@ -1312,11 +1318,17 @@ fast_isolate_freepages(struct compact_control *cc) * order to search after a previous failure */ cc->search_order = min_t(unsigned int, cc->order - 1, cc->search_order); - +#if defined(OPLUS_FEATURE_MULTI_FREEAREA) && defined(CONFIG_PHYSICAL_ANTI_FRAGMENTATION) + for (flc = 0; flc < FREE_AREA_COUNTS; flc++) { +#endif for (order = cc->search_order; !page && order >= 0; order = next_search_order(cc, order)) { +#if defined(OPLUS_FEATURE_MULTI_FREEAREA) && defined(CONFIG_PHYSICAL_ANTI_FRAGMENTATION) + struct free_area *area = &cc->zone->free_area[flc][order]; +#else struct free_area *area = &cc->zone->free_area[order]; +#endif struct list_head *freelist; struct page *freepage; unsigned long flags; @@ -1327,6 +1339,13 @@ fast_isolate_freepages(struct compact_control *cc) spin_lock_irqsave(&cc->zone->lock, flags); freelist = &area->free_list[MIGRATE_MOVABLE]; +#if defined(OPLUS_FEATURE_MULTI_FREEAREA) && defined(CONFIG_PHYSICAL_ANTI_FRAGMENTATION) + if (list_empty(freelist)) { + spin_unlock_irqrestore(&cc->zone->lock, flags); + continue; + } +#endif + list_for_each_entry_reverse(freepage, freelist, lru) { unsigned long pfn; @@ -1390,6 +1409,9 @@ fast_isolate_freepages(struct compact_control *cc) if (order_scanned >= limit) limit = min(1U, limit >> 1); } +#if defined(OPLUS_FEATURE_MULTI_FREEAREA) && defined(CONFIG_PHYSICAL_ANTI_FRAGMENTATION) + } +#endif if (!page) { cc->fast_search_fail++; @@ -1629,6 +1651,9 @@ static unsigned long fast_find_migrateblock(struct compact_control *cc) unsigned long pfn = cc->migrate_pfn; unsigned long high_pfn; int order; +#if defined(OPLUS_FEATURE_MULTI_FREEAREA) && defined(CONFIG_PHYSICAL_ANTI_FRAGMENTATION) + int flc = 0; +#endif /* Skip hints are relied on to avoid repeats on the fast search */ if (cc->ignore_skip_hint) @@ -1670,10 +1695,17 @@ static unsigned long fast_find_migrateblock(struct compact_control *cc) distance >>= 2; high_pfn = pageblock_start_pfn(cc->migrate_pfn + distance); +#if defined(OPLUS_FEATURE_MULTI_FREEAREA) && defined(CONFIG_PHYSICAL_ANTI_FRAGMENTATION) + for (flc = 0; flc < FREE_AREA_COUNTS; flc++) { +#endif for (order = cc->order - 1; order >= PAGE_ALLOC_COSTLY_ORDER && pfn == cc->migrate_pfn && nr_scanned < limit; order--) { +#if defined(OPLUS_FEATURE_MULTI_FREEAREA) && defined(CONFIG_PHYSICAL_ANTI_FRAGMENTATION) + struct free_area *area = &cc->zone->free_area[flc][order]; +#else struct free_area *area = &cc->zone->free_area[order]; +#endif struct list_head *freelist; unsigned long flags; struct page *freepage; @@ -1683,6 +1715,12 @@ static unsigned long fast_find_migrateblock(struct compact_control *cc) spin_lock_irqsave(&cc->zone->lock, flags); freelist = &area->free_list[MIGRATE_MOVABLE]; +#if defined(OPLUS_FEATURE_MULTI_FREEAREA) && defined(CONFIG_PHYSICAL_ANTI_FRAGMENTATION) + if (list_empty(freelist)) { + spin_unlock_irqrestore(&cc->zone->lock, flags); + continue; + } +#endif list_for_each_entry(freepage, freelist, lru) { unsigned long free_pfn; @@ -1720,7 +1758,9 @@ static unsigned long fast_find_migrateblock(struct compact_control *cc) } spin_unlock_irqrestore(&cc->zone->lock, flags); } - +#if defined(OPLUS_FEATURE_MULTI_FREEAREA) && defined(CONFIG_PHYSICAL_ANTI_FRAGMENTATION) + } +#endif cc->total_migrate_scanned += nr_scanned; /* @@ -1852,6 +1892,10 @@ static enum compact_result __compact_finished(struct compact_control *cc) unsigned int order; const int migratetype = cc->migratetype; int ret; +#if defined(OPLUS_FEATURE_MULTI_FREEAREA) && defined(CONFIG_PHYSICAL_ANTI_FRAGMENTATION) + int flc = 0; +#endif + /* Compaction run completes if the migrate and free scanner meet */ if (compact_scanners_met(cc)) { @@ -1887,8 +1931,15 @@ static enum compact_result __compact_finished(struct compact_control *cc) /* Direct compactor: Is a suitable page free? */ ret = COMPACT_NO_SUITABLE_PAGE; +#if defined(OPLUS_FEATURE_MULTI_FREEAREA) && defined(CONFIG_PHYSICAL_ANTI_FRAGMENTATION) + for (flc = 0; flc < FREE_AREA_COUNTS; flc++) { +#endif for (order = cc->order; order < MAX_ORDER; order++) { +#if defined(OPLUS_FEATURE_MULTI_FREEAREA) && defined(CONFIG_PHYSICAL_ANTI_FRAGMENTATION) + struct free_area *area = &cc->zone->free_area[flc][order]; +#else struct free_area *area = &cc->zone->free_area[order]; +#endif bool can_steal; /* Job done if page is free of the right migratetype */ @@ -1930,7 +1981,9 @@ static enum compact_result __compact_finished(struct compact_control *cc) break; } } - +#if defined(OPLUS_FEATURE_MULTI_FREEAREA) && defined(CONFIG_PHYSICAL_ANTI_FRAGMENTATION) + } +#endif if (cc->contended || fatal_signal_pending(current)) ret = COMPACT_CONTENDED; diff --git a/mm/damon/Kconfig b/mm/damon/Kconfig new file mode 100644 index 000000000000..b70a4b753f5f --- /dev/null +++ b/mm/damon/Kconfig @@ -0,0 +1,20 @@ +# SPDX-License-Identifier: GPL-2.0-only + +menu "Data Access Monitoring" + +config DAMON + bool "DAMON: Data Access Monitoring Framework" + default y + +config DAMON_PADDR + bool "Data access monitoring operations for the physical address space" + depends on DAMON && MMU + select PAGE_IDLE_FLAG + default y + +config DAMON_RECLAIM + bool "Build DAMON-based reclaim (DAMON_RECLAIM)" + depends on DAMON_PADDR + default y + +endmenu diff --git a/mm/damon/Makefile b/mm/damon/Makefile new file mode 100644 index 000000000000..a38d1accc286 --- /dev/null +++ b/mm/damon/Makefile @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0 + +obj-$(CONFIG_DAMON) := core.o +obj-$(CONFIG_DAMON_PADDR) += ops-common.o paddr.o +obj-$(CONFIG_DAMON_RECLAIM) += reclaim.o diff --git a/mm/damon/core.c b/mm/damon/core.c new file mode 100644 index 000000000000..7f28d9c433c6 --- /dev/null +++ b/mm/damon/core.c @@ -0,0 +1,1177 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Data Access Monitor + * + * Author: SeongJae Park + */ + +#define pr_fmt(fmt) "damon: " fmt + +#include +#include +#include +#include +#include +#include + +#define CREATE_TRACE_POINTS +#include + +static DEFINE_MUTEX(damon_lock); +static int nr_running_ctxs; +static bool running_exclusive_ctxs; + +static DEFINE_MUTEX(damon_ops_lock); +static struct damon_operations damon_registered_ops[NR_DAMON_OPS]; + +static unsigned long last_metric; +static unsigned long active_interval; +static unsigned long active_cnt; + +extern int wmarks_metric; +extern unsigned long nr_reclaim_time; +extern unsigned long nr_reclaim_page; +extern unsigned long nr_damon_region; + +/* Should be called under damon_ops_lock with id smaller than NR_DAMON_OPS */ +static bool damon_registered_ops_id(enum damon_ops_id id) +{ + struct damon_operations empty_ops = {}; + + if (!memcmp(&empty_ops, &damon_registered_ops[id], sizeof(empty_ops))) + return false; + return true; +} + +/** + * damon_register_ops() - Register a monitoring operations set to DAMON. + * @ops: monitoring operations set to register. + * + * This function registers a monitoring operations set of valid &struct + * damon_operations->id so that others can find and use them later. + * + * Return: 0 on success, negative error code otherwise. + */ +int damon_register_ops(struct damon_operations *ops) +{ + int err = 0; + + if (ops->id >= NR_DAMON_OPS) + return -EINVAL; + mutex_lock(&damon_ops_lock); + /* Fail for already registered ops */ + if (damon_registered_ops_id(ops->id)) { + err = -EINVAL; + goto out; + } + damon_registered_ops[ops->id] = *ops; +out: + mutex_unlock(&damon_ops_lock); + return err; +} + +/** + * damon_select_ops() - Select a monitoring operations to use with the context. + * @ctx: monitoring context to use the operations. + * @id: id of the registered monitoring operations to select. + * + * This function finds registered monitoring operations set of @id and make + * @ctx to use it. + * + * Return: 0 on success, negative error code otherwise. + */ +int damon_select_ops(struct damon_ctx *ctx, enum damon_ops_id id) +{ + int err = 0; + + if (id >= NR_DAMON_OPS) + return -EINVAL; + + mutex_lock(&damon_ops_lock); + if (!damon_registered_ops_id(id)) + err = -EINVAL; + else + ctx->ops = damon_registered_ops[id]; + mutex_unlock(&damon_ops_lock); + return err; +} + +/* + * Construct a damon_region struct + * + * Returns the pointer to the new struct if success, or NULL otherwise + */ +struct damon_region *damon_new_region(unsigned long start, unsigned long end) +{ + struct damon_region *region; + + region = kmalloc(sizeof(*region), GFP_KERNEL); + if (!region) + return NULL; + + region->ar.start = start; + region->ar.end = end; + region->nr_accesses = 0; + INIT_LIST_HEAD(®ion->list); + + region->age = 0; + region->last_nr_accesses = 0; + + return region; +} + +void damon_add_region(struct damon_region *r, struct damon_target *t) +{ + list_add_tail(&r->list, &t->regions_list); + t->nr_regions++; +} + +static void damon_del_region(struct damon_region *r, struct damon_target *t) +{ + list_del(&r->list); + t->nr_regions--; +} + +static void damon_free_region(struct damon_region *r) +{ + kfree(r); +} + +void damon_destroy_region(struct damon_region *r, struct damon_target *t) +{ + damon_del_region(r, t); + damon_free_region(r); +} + +struct damos *damon_new_scheme( + unsigned long min_sz_region, unsigned long max_sz_region, + unsigned int min_nr_accesses, unsigned int max_nr_accesses, + unsigned int min_age_region, unsigned int max_age_region, + enum damos_action action, struct damos_quota *quota, + struct damos_watermarks *wmarks) +{ + struct damos *scheme; + + scheme = kmalloc(sizeof(*scheme), GFP_KERNEL); + if (!scheme) + return NULL; + scheme->min_sz_region = min_sz_region; + scheme->max_sz_region = max_sz_region; + scheme->min_nr_accesses = min_nr_accesses; + scheme->max_nr_accesses = max_nr_accesses; + scheme->min_age_region = min_age_region; + scheme->max_age_region = max_age_region; + scheme->action = action; + scheme->stat = (struct damos_stat){}; + INIT_LIST_HEAD(&scheme->list); + + scheme->quota.ms = quota->ms; + scheme->quota.sz = quota->sz; + scheme->quota.reset_interval = quota->reset_interval; + scheme->quota.weight_sz = quota->weight_sz; + scheme->quota.weight_nr_accesses = quota->weight_nr_accesses; + scheme->quota.weight_age = quota->weight_age; + scheme->quota.total_charged_sz = 0; + scheme->quota.total_charged_ns = 0; + scheme->quota.esz = 0; + scheme->quota.charged_sz = 0; + scheme->quota.charged_from = 0; + scheme->quota.charge_target_from = NULL; + scheme->quota.charge_addr_from = 0; + + scheme->wmarks.metric = wmarks->metric; + scheme->wmarks.interval = wmarks->interval; + scheme->wmarks.high = wmarks->high; + scheme->wmarks.mid = wmarks->mid; + scheme->wmarks.low = wmarks->low; + scheme->wmarks.activated = true; + + return scheme; +} + +void damon_add_scheme(struct damon_ctx *ctx, struct damos *s) +{ + list_add_tail(&s->list, &ctx->schemes); +} + +static void damon_del_scheme(struct damos *s) +{ + list_del(&s->list); +} + +static void damon_free_scheme(struct damos *s) +{ + kfree(s); +} + +void damon_destroy_scheme(struct damos *s) +{ + damon_del_scheme(s); + damon_free_scheme(s); +} + +/* + * Construct a damon_target struct + * + * Returns the pointer to the new struct if success, or NULL otherwise + */ +struct damon_target *damon_new_target(void) +{ + struct damon_target *t; + + t = kmalloc(sizeof(*t), GFP_KERNEL); + if (!t) + return NULL; + + t->pid = NULL; + t->nr_regions = 0; + INIT_LIST_HEAD(&t->regions_list); + + return t; +} + +void damon_add_target(struct damon_ctx *ctx, struct damon_target *t) +{ + list_add_tail(&t->list, &ctx->adaptive_targets); +} + +bool damon_targets_empty(struct damon_ctx *ctx) +{ + return list_empty(&ctx->adaptive_targets); +} + +static void damon_del_target(struct damon_target *t) +{ + list_del(&t->list); +} + +void damon_free_target(struct damon_target *t) +{ + struct damon_region *r, *next; + + damon_for_each_region_safe(r, next, t) + damon_free_region(r); + kfree(t); +} + +void damon_destroy_target(struct damon_target *t) +{ + damon_del_target(t); + damon_free_target(t); +} + +unsigned int damon_nr_regions(struct damon_target *t) +{ + return t->nr_regions; +} + +struct damon_ctx *damon_new_ctx(void) +{ + struct damon_ctx *ctx; + + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); + if (!ctx) + return NULL; + + ctx->sample_interval = 5 * 1000; + ctx->aggr_interval = 100 * 1000; + ctx->ops_update_interval = 60 * 1000 * 1000; + + ktime_get_coarse_ts64(&ctx->last_aggregation); + ctx->last_ops_update = ctx->last_aggregation; + + mutex_init(&ctx->kdamond_lock); + + ctx->min_nr_regions = 10; + ctx->max_nr_regions = 1000; + + INIT_LIST_HEAD(&ctx->adaptive_targets); + INIT_LIST_HEAD(&ctx->schemes); + + return ctx; +} + +static void damon_destroy_targets(struct damon_ctx *ctx) +{ + struct damon_target *t, *next_t; + + if (ctx->ops.cleanup) { + ctx->ops.cleanup(ctx); + return; + } + + damon_for_each_target_safe(t, next_t, ctx) + damon_destroy_target(t); +} + +void damon_destroy_ctx(struct damon_ctx *ctx) +{ + struct damos *s, *next_s; + + damon_destroy_targets(ctx); + + damon_for_each_scheme_safe(s, next_s, ctx) + damon_destroy_scheme(s); + + kfree(ctx); +} + +/** + * damon_set_attrs() - Set attributes for the monitoring. + * @ctx: monitoring context + * @sample_int: time interval between samplings + * @aggr_int: time interval between aggregations + * @ops_upd_int: time interval between monitoring operations updates + * @min_nr_reg: minimal number of regions + * @max_nr_reg: maximum number of regions + * + * This function should not be called while the kdamond is running. + * Every time interval is in micro-seconds. + * + * Return: 0 on success, negative error code otherwise. + */ +int damon_set_attrs(struct damon_ctx *ctx, unsigned long sample_int, + unsigned long aggr_int, unsigned long ops_upd_int, + unsigned long min_nr_reg, unsigned long max_nr_reg) +{ + if (min_nr_reg < 3) + return -EINVAL; + + if (min_nr_reg > max_nr_reg) + return -EINVAL; + + ctx->sample_interval = sample_int; + ctx->aggr_interval = aggr_int; + ctx->ops_update_interval = ops_upd_int; + ctx->min_nr_regions = min_nr_reg; + ctx->max_nr_regions = max_nr_reg; + + return 0; +} + +/** + * damon_set_schemes() - Set data access monitoring based operation schemes. + * @ctx: monitoring context + * @schemes: array of the schemes + * @nr_schemes: number of entries in @schemes + * + * This function should not be called while the kdamond of the context is + * running. + * + * Return: 0 if success, or negative error code otherwise. + */ +int damon_set_schemes(struct damon_ctx *ctx, struct damos **schemes, + ssize_t nr_schemes) +{ + struct damos *s, *next; + ssize_t i; + + damon_for_each_scheme_safe(s, next, ctx) + damon_destroy_scheme(s); + for (i = 0; i < nr_schemes; i++) + damon_add_scheme(ctx, schemes[i]); + return 0; +} + +/** + * damon_nr_running_ctxs() - Return number of currently running contexts. + */ +int damon_nr_running_ctxs(void) +{ + int nr_ctxs; + + mutex_lock(&damon_lock); + nr_ctxs = nr_running_ctxs; + mutex_unlock(&damon_lock); + + return nr_ctxs; +} + +/* Returns the size upper limit for each monitoring region */ +static unsigned long damon_region_sz_limit(struct damon_ctx *ctx) +{ + struct damon_target *t; + struct damon_region *r; + unsigned long sz = 0; + + damon_for_each_target(t, ctx) { + damon_for_each_region(r, t) + sz += r->ar.end - r->ar.start; + } + + if (ctx->min_nr_regions) + sz /= ctx->min_nr_regions; + if (sz < DAMON_MIN_REGION) + sz = DAMON_MIN_REGION; + + return sz; +} + +static int kdamond_fn(void *data); + +/* + * __damon_start() - Starts monitoring with given context. + * @ctx: monitoring context + * + * This function should be called while damon_lock is hold. + * + * Return: 0 on success, negative error code otherwise. + */ +static int __damon_start(struct damon_ctx *ctx) +{ + int err = -EBUSY; + + mutex_lock(&ctx->kdamond_lock); + if (!ctx->kdamond) { + err = 0; + ctx->kdamond = kthread_run(kdamond_fn, ctx, "kdamond.%d", + nr_running_ctxs); + if (IS_ERR(ctx->kdamond)) { + err = PTR_ERR(ctx->kdamond); + ctx->kdamond = NULL; + } + } + mutex_unlock(&ctx->kdamond_lock); + + return err; +} + +/** + * damon_start() - Starts the monitorings for a given group of contexts. + * @ctxs: an array of the pointers for contexts to start monitoring + * @nr_ctxs: size of @ctxs + * @exclusive: exclusiveness of this contexts group + * This function starts a group of monitoring threads for a group of monitoring + * contexts. One thread per each context is created and run in parallel. The + * caller should handle synchronization between the threads by itself. If + * @exclusive is true and a group of threads that created by other + * 'damon_start()' call is currently running, this function does nothing but + * returns -EBUSY. + * + * Return: 0 on success, negative error code otherwise. + */ +int damon_start(struct damon_ctx **ctxs, int nr_ctxs, bool exclusive) +{ + int i; + int err = 0; + + mutex_lock(&damon_lock); + if ((exclusive && nr_running_ctxs) || + (!exclusive && running_exclusive_ctxs)) { + mutex_unlock(&damon_lock); + return -EBUSY; + } + + for (i = 0; i < nr_ctxs; i++) { + err = __damon_start(ctxs[i]); + if (err) + break; + nr_running_ctxs++; + } + if (exclusive && nr_running_ctxs) + running_exclusive_ctxs = true; + mutex_unlock(&damon_lock); + + return err; +} + +/* + * __damon_stop() - Stops monitoring of a given context. + * @ctx: monitoring context + * + * Return: 0 on success, negative error code otherwise. + */ +static int __damon_stop(struct damon_ctx *ctx) +{ + struct task_struct *tsk; + + mutex_lock(&ctx->kdamond_lock); + tsk = ctx->kdamond; + if (tsk) { + get_task_struct(tsk); + mutex_unlock(&ctx->kdamond_lock); + kthread_stop(tsk); + put_task_struct(tsk); + return 0; + } + mutex_unlock(&ctx->kdamond_lock); + + return -EPERM; +} + +/** + * damon_stop() - Stops the monitorings for a given group of contexts. + * @ctxs: an array of the pointers for contexts to stop monitoring + * @nr_ctxs: size of @ctxs + * + * Return: 0 on success, negative error code otherwise. + */ +int damon_stop(struct damon_ctx **ctxs, int nr_ctxs) +{ + int i, err = 0; + + for (i = 0; i < nr_ctxs; i++) { + /* nr_running_ctxs is decremented in kdamond_fn */ + err = __damon_stop(ctxs[i]); + if (err) + break; + } + + return err; +} + +/* + * damon_check_reset_time_interval() - Check if a time interval is elapsed. + * @baseline: the time to check whether the interval has elapsed since + * @interval: the time interval (microseconds) + * + * See whether the given time interval has passed since the given baseline + * time. If so, it also updates the baseline to current time for next check. + * + * Return: true if the time interval has passed, or false otherwise. + */ +static bool damon_check_reset_time_interval(struct timespec64 *baseline, + unsigned long interval) +{ + struct timespec64 now; + + ktime_get_coarse_ts64(&now); + if ((timespec64_to_ns(&now) - timespec64_to_ns(baseline)) < + interval * 1000) + return false; + *baseline = now; + return true; +} + +/* + * Check whether it is time to flush the aggregated information + */ +static bool kdamond_aggregate_interval_passed(struct damon_ctx *ctx) +{ + return damon_check_reset_time_interval(&ctx->last_aggregation, + ctx->aggr_interval); +} + +/* + * Reset the aggregated monitoring results ('nr_accesses' of each region). + */ +static void kdamond_reset_aggregated(struct damon_ctx *c) +{ + struct damon_target *t; + unsigned int ti = 0; /* target's index */ + + damon_for_each_target(t, c) { + struct damon_region *r; + + damon_for_each_region(r, t) { + trace_damon_aggregated(t, ti, r, damon_nr_regions(t)); + r->last_nr_accesses = r->nr_accesses; + r->nr_accesses = 0; + } + ti++; + } +} + +static void damon_split_region_at(struct damon_ctx *ctx, + struct damon_target *t, struct damon_region *r, + unsigned long sz_r); + +static bool __damos_valid_target(struct damon_region *r, struct damos *s) +{ + unsigned long sz; + + sz = r->ar.end - r->ar.start; + return s->min_sz_region <= sz && sz <= s->max_sz_region && + s->min_nr_accesses <= r->nr_accesses && + r->nr_accesses <= s->max_nr_accesses && + s->min_age_region <= r->age && r->age <= s->max_age_region; +} + +static bool damos_valid_target(struct damon_ctx *c, struct damon_target *t, + struct damon_region *r, struct damos *s) +{ + bool ret = __damos_valid_target(r, s); + + if (!ret || !s->quota.esz || !c->ops.get_scheme_score) + return ret; + + return c->ops.get_scheme_score(c, t, r, s) >= s->quota.min_score; +} + +static void damon_do_apply_schemes(struct damon_ctx *c, + struct damon_target *t, + struct damon_region *r) +{ + struct damos *s; + + damon_for_each_scheme(s, c) { + struct damos_quota *quota = &s->quota; + unsigned long sz = r->ar.end - r->ar.start; + struct timespec64 begin, end; + unsigned long sz_applied = 0; + + if (!s->wmarks.activated) + continue; + + /* Check the quota */ + if (quota->esz && quota->charged_sz >= quota->esz) + continue; + + /* Skip previously charged regions */ + if (quota->charge_target_from) { + if (t != quota->charge_target_from) + continue; + if (r == damon_last_region(t)) { + quota->charge_target_from = NULL; + quota->charge_addr_from = 0; + continue; + } + if (quota->charge_addr_from && + r->ar.end <= quota->charge_addr_from) + continue; + + if (quota->charge_addr_from && r->ar.start < + quota->charge_addr_from) { + sz = ALIGN_DOWN(quota->charge_addr_from - + r->ar.start, DAMON_MIN_REGION); + if (!sz) { + if (r->ar.end - r->ar.start <= + DAMON_MIN_REGION) + continue; + sz = DAMON_MIN_REGION; + } + damon_split_region_at(c, t, r, sz); + r = damon_next_region(r); + sz = r->ar.end - r->ar.start; + } + quota->charge_target_from = NULL; + quota->charge_addr_from = 0; + } + + if (!damos_valid_target(c, t, r, s)) + continue; + + /* Apply the scheme */ + if (c->ops.apply_scheme) { + if (quota->esz && + quota->charged_sz + sz > quota->esz) { + sz = ALIGN_DOWN(quota->esz - quota->charged_sz, + DAMON_MIN_REGION); + if (!sz) + goto update_stat; + damon_split_region_at(c, t, r, sz); + } + ktime_get_coarse_ts64(&begin); + sz_applied = c->ops.apply_scheme(c, t, r, s); + ktime_get_coarse_ts64(&end); + quota->total_charged_ns += timespec64_to_ns(&end) - + timespec64_to_ns(&begin); + quota->charged_sz += sz; + if (quota->esz && quota->charged_sz >= quota->esz) { + quota->charge_target_from = t; + quota->charge_addr_from = r->ar.end + 1; + } + } + if (s->action != DAMOS_STAT) + r->age = 0; + +update_stat: + s->stat.nr_tried++; + s->stat.sz_tried += sz; + if (sz_applied) + s->stat.nr_applied++; + s->stat.sz_applied += sz_applied; + } +} + +/* Shouldn't be called if quota->ms and quota->sz are zero */ +static void damos_set_effective_quota(struct damos_quota *quota) +{ + unsigned long throughput; + unsigned long esz; + + if (!quota->ms) { + quota->esz = quota->sz; + return; + } + + if (quota->total_charged_ns) + throughput = quota->total_charged_sz * 1000000 / + quota->total_charged_ns; + else + throughput = PAGE_SIZE * 1024; + esz = throughput * quota->ms; + + if (quota->sz && quota->sz < esz) + esz = quota->sz; + quota->esz = esz; +} + +static void kdamond_apply_schemes(struct damon_ctx *c) +{ + struct damon_target *t; + struct damon_region *r, *next_r; + struct damos *s; + + damon_for_each_scheme(s, c) { + struct damos_quota *quota = &s->quota; + unsigned long cumulated_sz; + unsigned int score, max_score = 0; + + if (!s->wmarks.activated) + continue; + + if (!quota->ms && !quota->sz) + continue; + + /* New charge window starts */ + if (time_after_eq(jiffies, quota->charged_from + + msecs_to_jiffies( + quota->reset_interval))) { + if (quota->esz && quota->charged_sz >= quota->esz) + s->stat.qt_exceeds++; + quota->total_charged_sz += quota->charged_sz; + quota->charged_from = jiffies; + quota->charged_sz = 0; + damos_set_effective_quota(quota); + } + + if (!c->ops.get_scheme_score) + continue; + + /* Fill up the score histogram */ + memset(quota->histogram, 0, sizeof(quota->histogram)); + damon_for_each_target(t, c) { + damon_for_each_region(r, t) { + if (!__damos_valid_target(r, s)) + continue; + score = c->ops.get_scheme_score( + c, t, r, s); + quota->histogram[score] += + r->ar.end - r->ar.start; + if (score > max_score) + max_score = score; + } + } + + /* Set the min score limit */ + for (cumulated_sz = 0, score = max_score; ; score--) { + cumulated_sz += quota->histogram[score]; + if (cumulated_sz >= quota->esz || !score) + break; + } + quota->min_score = score; + } + + damon_for_each_target(t, c) { + damon_for_each_region_safe(r, next_r, t) + damon_do_apply_schemes(c, t, r); + } +} + +static inline unsigned long sz_damon_region(struct damon_region *r) +{ + return r->ar.end - r->ar.start; +} + +/* + * Merge two adjacent regions into one region + */ +static void damon_merge_two_regions(struct damon_target *t, + struct damon_region *l, struct damon_region *r) +{ + unsigned long sz_l = sz_damon_region(l), sz_r = sz_damon_region(r); + + l->nr_accesses = (l->nr_accesses * sz_l + r->nr_accesses * sz_r) / + (sz_l + sz_r); + l->age = (l->age * sz_l + r->age * sz_r) / (sz_l + sz_r); + l->ar.end = r->ar.end; + damon_destroy_region(r, t); +} + +/* + * Merge adjacent regions having similar access frequencies + * + * t target affected by this merge operation + * thres '->nr_accesses' diff threshold for the merge + * sz_limit size upper limit of each region + */ +static void damon_merge_regions_of(struct damon_target *t, unsigned int thres, + unsigned long sz_limit) +{ + struct damon_region *r, *prev = NULL, *next; + + damon_for_each_region_safe(r, next, t) { + if (abs(r->nr_accesses - r->last_nr_accesses) > thres) + r->age = 0; + else + r->age++; + + if (prev && prev->ar.end == r->ar.start && + abs(prev->nr_accesses - r->nr_accesses) <= thres && + sz_damon_region(prev) + sz_damon_region(r) <= sz_limit) + damon_merge_two_regions(t, prev, r); + else + prev = r; + } +} + +/* + * Merge adjacent regions having similar access frequencies + * + * threshold '->nr_accesses' diff threshold for the merge + * sz_limit size upper limit of each region + * + * This function merges monitoring target regions which are adjacent and their + * access frequencies are similar. This is for minimizing the monitoring + * overhead under the dynamically changeable access pattern. If a merge was + * unnecessarily made, later 'kdamond_split_regions()' will revert it. + */ +static void kdamond_merge_regions(struct damon_ctx *c, unsigned int threshold, + unsigned long sz_limit) +{ + struct damon_target *t; + + damon_for_each_target(t, c) + damon_merge_regions_of(t, threshold, sz_limit); +} + +/* + * Split a region in two + * + * r the region to be split + * sz_r size of the first sub-region that will be made + */ +static void damon_split_region_at(struct damon_ctx *ctx, + struct damon_target *t, struct damon_region *r, + unsigned long sz_r) +{ + struct damon_region *new; + + new = damon_new_region(r->ar.start + sz_r, r->ar.end); + if (!new) + return; + + r->ar.end = new->ar.start; + + new->age = r->age; + new->last_nr_accesses = r->last_nr_accesses; + + damon_insert_region(new, r, damon_next_region(r), t); +} + +/* Split every region in the given target into 'nr_subs' regions */ +static void damon_split_regions_of(struct damon_ctx *ctx, + struct damon_target *t, int nr_subs) +{ + struct damon_region *r, *next; + unsigned long sz_region, sz_sub = 0; + int i; + + damon_for_each_region_safe(r, next, t) { + sz_region = r->ar.end - r->ar.start; + + for (i = 0; i < nr_subs - 1 && + sz_region > 2 * DAMON_MIN_REGION; i++) { + /* + * Randomly select size of left sub-region to be at + * least 10 percent and at most 90% of original region + */ + sz_sub = ALIGN_DOWN(damon_rand(1, 10) * + sz_region / 10, DAMON_MIN_REGION); + /* Do not allow blank region */ + if (sz_sub == 0 || sz_sub >= sz_region) + continue; + + damon_split_region_at(ctx, t, r, sz_sub); + sz_region = sz_sub; + } + } +} + +/* + * Split every target region into randomly-sized small regions + * + * This function splits every target region into random-sized small regions if + * current total number of the regions is equal or smaller than half of the + * user-specified maximum number of regions. This is for maximizing the + * monitoring accuracy under the dynamically changeable access patterns. If a + * split was unnecessarily made, later 'kdamond_merge_regions()' will revert + * it. + */ +static void kdamond_split_regions(struct damon_ctx *ctx) +{ + struct damon_target *t; + unsigned int nr_regions = 0; + static unsigned int last_nr_regions; + int nr_subregions = 2; + + damon_for_each_target(t, ctx) + nr_regions += damon_nr_regions(t); + + if (nr_regions > ctx->max_nr_regions / 2) + return; + + /* Maybe the middle of the region has different access frequency */ + if (last_nr_regions == nr_regions && + nr_regions < ctx->max_nr_regions / 3) + nr_subregions = 3; + + damon_for_each_target(t, ctx) + damon_split_regions_of(ctx, t, nr_subregions); + + last_nr_regions = nr_regions; + nr_damon_region = nr_regions; +} + +/* + * Check whether current monitoring should be stopped + * + * The monitoring is stopped when either the user requested to stop, or all + * monitoring targets are invalid. + * + * Returns true if need to stop current monitoring. + */ +static bool kdamond_need_stop(struct damon_ctx *ctx) +{ + struct damon_target *t; + + if (kthread_should_stop()) + return true; + + if (!ctx->ops.target_valid) + return false; + + damon_for_each_target(t, ctx) { + if (ctx->ops.target_valid(t)) + return false; + } + + return true; +} + +static void kdamond_usleep(unsigned long usecs) +{ + /* See Documentation/timers/timers-howto.rst for the thresholds */ + if (usecs > 20 * USEC_PER_MSEC) + schedule_timeout_idle(usecs_to_jiffies(usecs)); + else + usleep_idle_range(usecs, usecs + 1); +} + +/* + * Returns zero if the scheme is active. Else, returns time to wait for next + * watermark check in micro-seconds. + */ +static unsigned long damos_wmark_wait_us(struct damos *scheme) +{ + unsigned long metric; + unsigned long diff; + struct sysinfo i; + + switch (wmarks_metric) { + case DAMOS_WMARK_NONE: + break; + + case DAMOS_WMARK_FREE_MEM_RATE: + si_meminfo(&i); + metric = i.freeram * 1000 / i.totalram; + /* higher than high watermark or lower than low watermark */ + if (metric > scheme->wmarks.high || scheme->wmarks.low > metric) { + if (scheme->wmarks.activated) + pr_debug("deactivate a scheme (%d) for %s wmark\n", + scheme->action, + metric > scheme->wmarks.high ? + "high" : "low"); + scheme->wmarks.activated = false; + return scheme->wmarks.interval; + } + + /* inactive and higher than middle watermark */ + if ((scheme->wmarks.high >= metric && metric >= scheme->wmarks.mid) && + !scheme->wmarks.activated) + return scheme->wmarks.interval; + + if (!scheme->wmarks.activated) + pr_debug("activate a scheme (%d)\n", scheme->action); + scheme->wmarks.activated = true; + return 0; + + case DAMOS_WMARK_OPLUS: + si_meminfo(&i); + metric = i.freeram * 1000 / i.totalram; + diff = abs(last_metric - metric); + + if (scheme->wmarks.activated) { + if (metric < 10) { + scheme->wmarks.activated = false; + nr_reclaim_time = 0; + nr_reclaim_page = 0; + printk("[damon_reclaim] sleep. need kswapd.\n"); + return scheme->wmarks.interval; + } + nr_reclaim_time = active_interval * active_cnt; // 10ms(0.01s) * cnt; + } + + // printk("[damon_reclaim] last: %d now: %d diff: %d activated: %d nr_reclaim_time: %d pages: %d \n", + // last_metric, metric, diff, scheme->wmarks.activated, nr_reclaim_time, nr_reclaim_page); + + last_metric = (2*last_metric + 8*metric)/10; // smooth filter + /* + Total RAM Activate FreeMem + ------------------------------- + 4 GB 80 MB + 6 GB 120 MB + 8 GB 160 MB + 12 GB 240 MB + 16 GB 320 MB + */ + if (diff <= 20 || last_metric < metric) { + + if (scheme->wmarks.activated) { + if (nr_reclaim_time >= 300000 || // time thresold: 5min = 5*60*1000 ms + nr_reclaim_page >= i.totalram * 20 / 1000 ) + { + scheme->wmarks.activated = false; + nr_reclaim_time = 0; + nr_reclaim_page = 0; + printk("[damon_reclaim] sleep. need to control quota.\n"); + return scheme->wmarks.interval; + } else { + ++active_cnt; + return 0; + } + } else { + // nothing + return scheme->wmarks.interval; + } + } + else { + if (scheme->wmarks.activated) { + //nothing + return 0; + } else { + active_cnt = 0; + scheme->wmarks.activated = true; + nr_reclaim_time = 0; + nr_reclaim_page = 0; + printk("[damon_reclaim] active. \n"); + kdamond_usleep(scheme->wmarks.interval); + return 0; + } + } + + case DAMOS_WMARK_SLEEP: + scheme->wmarks.activated = false; + nr_reclaim_time = 0; + nr_reclaim_page = 0; + printk("[damon_reclaim] sleep. call from upper layer.\n"); + return scheme->wmarks.interval; + + default: + break; + } + return 0; +} + +/* Returns negative error code if it's not activated but should return */ +static int kdamond_wait_activation(struct damon_ctx *ctx) +{ + struct damos *s; + unsigned long wait_time; + unsigned long min_wait_time = 0; + + while (!kdamond_need_stop(ctx)) { + damon_for_each_scheme(s, ctx) { + wait_time = damos_wmark_wait_us(s); + if (!min_wait_time || wait_time < min_wait_time) + min_wait_time = wait_time; + } + if (!min_wait_time) + return 0; + + kdamond_usleep(min_wait_time); + } + return -EBUSY; +} + +/* + * The monitoring daemon that runs as a kernel thread + */ +static int kdamond_fn(void *data) +{ + struct damon_ctx *ctx = (struct damon_ctx *)data; + struct damon_target *t; + struct damon_region *r, *next; + unsigned int max_nr_accesses = 0; + unsigned long sz_limit = 0; + bool done = false; + + pr_debug("kdamond (%d) starts\n", current->pid); + + if (ctx->ops.init) + ctx->ops.init(ctx); + if (ctx->callback.before_start && ctx->callback.before_start(ctx)) + done = true; + + sz_limit = damon_region_sz_limit(ctx); + + last_metric = 0; + active_interval = ctx->sample_interval / 1000; + active_cnt = 0; + nr_reclaim_page = 0; + + while (!kdamond_need_stop(ctx) && !done) { + if (kdamond_wait_activation(ctx)) + continue; + + if (ctx->ops.prepare_access_checks) + ctx->ops.prepare_access_checks(ctx); + if (ctx->callback.after_sampling && + ctx->callback.after_sampling(ctx)) + done = true; + + kdamond_usleep(ctx->sample_interval); + + if (ctx->ops.check_accesses) + max_nr_accesses = ctx->ops.check_accesses(ctx); + + if (kdamond_aggregate_interval_passed(ctx)) { + kdamond_merge_regions(ctx, + max_nr_accesses / 10, + sz_limit); + if (ctx->callback.after_aggregation && + ctx->callback.after_aggregation(ctx)) + done = true; + kdamond_apply_schemes(ctx); + kdamond_reset_aggregated(ctx); + kdamond_split_regions(ctx); + if (ctx->ops.reset_aggregated) + ctx->ops.reset_aggregated(ctx); + ctx->ops.update(ctx); + sz_limit = damon_region_sz_limit(ctx); + } + } + damon_for_each_target(t, ctx) { + damon_for_each_region_safe(r, next, t) + damon_destroy_region(r, t); + } + + if (ctx->callback.before_terminate) + ctx->callback.before_terminate(ctx); + if (ctx->ops.cleanup) + ctx->ops.cleanup(ctx); + + pr_debug("kdamond (%d) finishes\n", current->pid); + mutex_lock(&ctx->kdamond_lock); + ctx->kdamond = NULL; + mutex_unlock(&ctx->kdamond_lock); + + mutex_lock(&damon_lock); + nr_running_ctxs--; + if (!nr_running_ctxs && running_exclusive_ctxs) + running_exclusive_ctxs = false; + mutex_unlock(&damon_lock); + + return 0; +} diff --git a/mm/damon/ops-common.c b/mm/damon/ops-common.c new file mode 100644 index 000000000000..345e47dcd970 --- /dev/null +++ b/mm/damon/ops-common.c @@ -0,0 +1,135 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Common Operations for Data Access Monitoring + * + * Author: SeongJae Park + */ + +#include +#include +#include +#include + +#include "ops-common.h" + +/* + * Get an online page for a pfn if it's in the LRU list. Otherwise, returns + * NULL. + * + * The body of this function is stolen from the 'page_idle_get_page()'. We + * steal rather than reuse it because the code is quite simple. + */ +struct page *damon_get_page(unsigned long pfn) +{ + struct page *page = pfn_to_online_page(pfn); + + if (!page || !PageLRU(page) || !get_page_unless_zero(page)) + return NULL; + + if (unlikely(!PageLRU(page))) { + put_page(page); + page = NULL; + } + return page; +} + +void damon_ptep_mkold(pte_t *pte, struct mm_struct *mm, unsigned long addr) +{ + bool referenced = false; + struct page *page = damon_get_page(pte_pfn(*pte)); + + if (!page) + return; + + if (pte_young(*pte)) { + referenced = true; + *pte = pte_mkold(*pte); + } + +#ifdef CONFIG_MMU_NOTIFIER + if (mmu_notifier_clear_young(mm, addr, addr + PAGE_SIZE)) + referenced = true; +#endif /* CONFIG_MMU_NOTIFIER */ + + if (referenced) + set_page_young(page); + + set_page_idle(page); + put_page(page); +} + +void damon_pmdp_mkold(pmd_t *pmd, struct mm_struct *mm, unsigned long addr) +{ +#ifdef CONFIG_TRANSPARENT_HUGEPAGE + bool referenced = false; + struct page *page = damon_get_page(pmd_pfn(*pmd)); + + if (!page) + return; + + if (pmd_young(*pmd)) { + referenced = true; + *pmd = pmd_mkold(*pmd); + } + +#ifdef CONFIG_MMU_NOTIFIER + if (mmu_notifier_clear_young(mm, addr, + addr + ((1UL) << HPAGE_PMD_SHIFT))) + referenced = true; +#endif /* CONFIG_MMU_NOTIFIER */ + + if (referenced) + set_page_young(page); + + set_page_idle(page); + put_page(page); +#endif /* CONFIG_TRANSPARENT_HUGEPAGE */ +} + +#define DAMON_MAX_SUBSCORE (100) +#define DAMON_MAX_AGE_IN_LOG (32) + +int damon_pageout_score(struct damon_ctx *c, struct damon_region *r, + struct damos *s) +{ + unsigned int max_nr_accesses; + int freq_subscore; + unsigned int age_in_sec; + int age_in_log, age_subscore; + unsigned int freq_weight = s->quota.weight_nr_accesses; + unsigned int age_weight = s->quota.weight_age; + int hotness; + + max_nr_accesses = c->aggr_interval / c->sample_interval; + if (max_nr_accesses == 0) + max_nr_accesses = 1; + freq_subscore = r->nr_accesses * DAMON_MAX_SUBSCORE / max_nr_accesses; + + age_in_sec = (unsigned long)r->age * c->aggr_interval / 1000000; + for (age_in_log = 0; age_in_log < DAMON_MAX_AGE_IN_LOG && age_in_sec; + age_in_log++, age_in_sec >>= 1) + ; + + /* If frequency is 0, higher age means it's colder */ + if (freq_subscore == 0) + age_in_log *= -1; + + /* + * Now age_in_log is in [-DAMON_MAX_AGE_IN_LOG, DAMON_MAX_AGE_IN_LOG]. + * Scale it to be in [0, 100] and set it as age subscore. + */ + age_in_log += DAMON_MAX_AGE_IN_LOG; + age_subscore = age_in_log * DAMON_MAX_SUBSCORE / + DAMON_MAX_AGE_IN_LOG / 2; + + hotness = (freq_weight * freq_subscore + age_weight * age_subscore); + if (freq_weight + age_weight) + hotness /= freq_weight + age_weight; + /* + * Transform it to fit in [0, DAMOS_MAX_SCORE] + */ + hotness = hotness * DAMOS_MAX_SCORE / DAMON_MAX_SUBSCORE; + + /* Return coldness of the region */ + return DAMOS_MAX_SCORE - hotness; +} \ No newline at end of file diff --git a/mm/damon/ops-common.h b/mm/damon/ops-common.h new file mode 100644 index 000000000000..8d562105fc10 --- /dev/null +++ b/mm/damon/ops-common.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Common Operations for Data Access Monitoring + * + * Author: SeongJae Park + */ + +#include + +struct page *damon_get_page(unsigned long pfn); + +void damon_ptep_mkold(pte_t *pte, struct mm_struct *mm, unsigned long addr); +void damon_pmdp_mkold(pmd_t *pmd, struct mm_struct *mm, unsigned long addr); + +int damon_pageout_score(struct damon_ctx *c, struct damon_region *r, + struct damos *s); \ No newline at end of file diff --git a/mm/damon/paddr.c b/mm/damon/paddr.c new file mode 100644 index 000000000000..1615fbd0b366 --- /dev/null +++ b/mm/damon/paddr.c @@ -0,0 +1,317 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * DAMON Operations for The Physical Address Space + * + * Author: SeongJae Park + */ + +#define pr_fmt(fmt) "damon-pa: " fmt + +#include +#include +#include +#include + +#include "../internal.h" +#include "ops-common.h" + +extern unsigned long min_age; + +extern unsigned long quota_ms; +extern unsigned long quota_sz; +extern unsigned long quota_reset_interval_ms; + +extern unsigned long wmarks_interval; +extern unsigned long wmarks_high; +extern unsigned long wmarks_mid; +extern unsigned long wmarks_low; + +extern unsigned long sample_interval; +extern unsigned long aggr_interval; +extern unsigned long min_nr_regions; +extern unsigned long max_nr_regions; + +extern unsigned long nr_reclaim_page; + +static bool __damon_pa_mkold(struct page *page, struct vm_area_struct *vma, + unsigned long addr, void *arg) +{ + struct page_vma_mapped_walk pvmw = { + .page = page, + .vma = vma, + .address = addr, + }; + + while (page_vma_mapped_walk(&pvmw)) { + addr = pvmw.address; + if (pvmw.pte) + damon_ptep_mkold(pvmw.pte, vma->vm_mm, addr); + else + damon_pmdp_mkold(pvmw.pmd, vma->vm_mm, addr); + } + return true; +} + +static void damon_pa_mkold(unsigned long paddr) +{ + struct page *page = damon_get_page(PHYS_PFN(paddr)); + struct rmap_walk_control rwc = { + .rmap_one = __damon_pa_mkold, + .anon_lock = page_lock_anon_vma_read, + }; + bool need_lock; + + if (!page) + return; + + if (!page_mapped(page) || !page_rmapping(page)) { + set_page_idle(page); + goto out; + } + + need_lock = !PageAnon(page) || PageKsm(page); + if (need_lock && !trylock_page(page)) + goto out; + + rmap_walk(page, &rwc); + + if (need_lock) + unlock_page(page); + +out: + put_page(page); +} + +static void __damon_pa_prepare_access_check(struct damon_ctx *ctx, + struct damon_region *r) +{ + r->sampling_addr = damon_rand(r->ar.start, r->ar.end); + + damon_pa_mkold(r->sampling_addr); +} + +static void damon_pa_prepare_access_checks(struct damon_ctx *ctx) +{ + struct damon_target *t; + struct damon_region *r; + + damon_for_each_target(t, ctx) { + damon_for_each_region(r, t) + __damon_pa_prepare_access_check(ctx, r); + } +} + +struct damon_pa_access_chk_result { + unsigned long page_sz; + bool accessed; +}; + +static bool __damon_pa_young(struct page *page, struct vm_area_struct *vma, + unsigned long addr, void *arg) +{ + struct damon_pa_access_chk_result *result = arg; + struct page_vma_mapped_walk pvmw = { + .page = page, + .vma = vma, + .address = addr, + }; + + result->accessed = false; + result->page_sz = PAGE_SIZE; + while (page_vma_mapped_walk(&pvmw)) { + addr = pvmw.address; + if (pvmw.pte) { + result->accessed = pte_young(*pvmw.pte) || + !page_is_idle(page) || + mmu_notifier_test_young(vma->vm_mm, addr); + } else { +#ifdef CONFIG_TRANSPARENT_HUGEPAGE + result->accessed = pmd_young(*pvmw.pmd) || + !page_is_idle(page) || + mmu_notifier_test_young(vma->vm_mm, addr); + result->page_sz = ((1UL) << HPAGE_PMD_SHIFT); +#else + WARN_ON_ONCE(1); +#endif /* CONFIG_TRANSPARENT_HUGEPAGE */ + } + if (result->accessed) { + page_vma_mapped_walk_done(&pvmw); + break; + } + } + + /* If accessed, stop walking */ + return !result->accessed; +} + +static bool damon_pa_young(unsigned long paddr, unsigned long *page_sz) +{ + struct page *page = damon_get_page(PHYS_PFN(paddr)); + struct damon_pa_access_chk_result result = { + .page_sz = PAGE_SIZE, + .accessed = false, + }; + struct rmap_walk_control rwc = { + .arg = &result, + .rmap_one = __damon_pa_young, + .anon_lock = page_lock_anon_vma_read, + }; + bool need_lock; + + if (!page) + return false; + + if (!page_mapped(page) || !page_rmapping(page)) { + if (page_is_idle(page)) + result.accessed = false; + else + result.accessed = true; + put_page(page); + goto out; + } + + need_lock = !PageAnon(page) || PageKsm(page); + if (need_lock && !trylock_page(page)) { + put_page(page); + return NULL; + } + + rmap_walk(page, &rwc); + + if (need_lock) + unlock_page(page); + put_page(page); + +out: + *page_sz = result.page_sz; + return result.accessed; +} + +static void __damon_pa_check_access(struct damon_ctx *ctx, + struct damon_region *r) +{ + static unsigned long last_addr; + static unsigned long last_page_sz = PAGE_SIZE; + static bool last_accessed; + + /* If the region is in the last checked page, reuse the result */ + if (ALIGN_DOWN(last_addr, last_page_sz) == + ALIGN_DOWN(r->sampling_addr, last_page_sz)) { + if (last_accessed) + r->nr_accesses++; + return; + } + + last_accessed = damon_pa_young(r->sampling_addr, &last_page_sz); + if (last_accessed) + r->nr_accesses++; + + last_addr = r->sampling_addr; +} + +static unsigned int damon_pa_check_accesses(struct damon_ctx *ctx) +{ + struct damon_target *t; + struct damon_region *r; + unsigned int max_nr_accesses = 0; + + damon_for_each_target(t, ctx) { + damon_for_each_region(r, t) { + __damon_pa_check_access(ctx, r); + max_nr_accesses = max(r->nr_accesses, max_nr_accesses); + } + } + + return max_nr_accesses; +} + +static unsigned long damon_pa_apply_scheme(struct damon_ctx *ctx, + struct damon_target *t, struct damon_region *r, + struct damos *scheme) +{ + unsigned long addr, applied; + LIST_HEAD(page_list); + + if (scheme->action != DAMOS_PAGEOUT) + return 0; + + for (addr = r->ar.start; addr < r->ar.end; addr += PAGE_SIZE) { + struct page *page = damon_get_page(PHYS_PFN(addr)); + + if (!page) + continue; + + ClearPageReferenced(page); + test_and_clear_page_young(page); + if (isolate_lru_page(page)) { + put_page(page); + continue; + } + if (PageUnevictable(page)) { + putback_lru_page(page); + } else { + list_add(&page->lru, &page_list); + put_page(page); + } + } + applied = reclaim_pages(&page_list); + cond_resched(); + printk("[damon_reclaim] reclaimed %lld pages\n", applied); + nr_reclaim_page = nr_reclaim_page + applied; + return applied * PAGE_SIZE; +} + +static int damon_pa_scheme_score(struct damon_ctx *context, + struct damon_target *t, struct damon_region *r, + struct damos *scheme) +{ + switch (scheme->action) { + case DAMOS_PAGEOUT: + return damon_pageout_score(context, r, scheme); + default: + break; + } + + return DAMOS_MAX_SCORE; +} + +static void damon_update_param(struct damon_ctx *ctx) +{ + struct damos *s; + damon_for_each_scheme(s, ctx) { + s->min_age_region = min_age / aggr_interval; + + s->quota.ms = quota_ms; + s->quota.sz = quota_sz; + s->quota.reset_interval = quota_reset_interval_ms; + + s->wmarks.interval = wmarks_interval; + s->wmarks.high = wmarks_high; + s->wmarks.mid = wmarks_mid; + s->wmarks.low = wmarks_low; + } + ctx->sample_interval = sample_interval; + ctx->aggr_interval = aggr_interval; + ctx->min_nr_regions = min_nr_regions; + ctx->max_nr_regions = max_nr_regions; +} + +static int __init damon_pa_initcall(void) +{ + struct damon_operations ops = { + .id = DAMON_OPS_PADDR, + .init = NULL, + .update = damon_update_param, + .prepare_access_checks = damon_pa_prepare_access_checks, + .check_accesses = damon_pa_check_accesses, + .reset_aggregated = NULL, + .target_valid = NULL, + .cleanup = NULL, + .apply_scheme = damon_pa_apply_scheme, + .get_scheme_score = damon_pa_scheme_score, + }; + + return damon_register_ops(&ops); +}; + +subsys_initcall(damon_pa_initcall); diff --git a/mm/damon/reclaim.c b/mm/damon/reclaim.c new file mode 100644 index 000000000000..b277f8d1f49e --- /dev/null +++ b/mm/damon/reclaim.c @@ -0,0 +1,452 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * DAMON-based page reclamation + * + * Author: SeongJae Park + */ + +#define pr_fmt(fmt) "damon-reclaim: " fmt + +#include +#include +#include +#include +#include + +#include + +#ifdef MODULE_PARAM_PREFIX +#undef MODULE_PARAM_PREFIX +#endif +#define MODULE_PARAM_PREFIX "damon_reclaim." + +/* + * Enable or disable DAMON_RECLAIM. + * + * You can enable DAMON_RCLAIM by setting the value of this parameter as ``Y``. + * Setting it as ``N`` disables DAMON_RECLAIM. Note that DAMON_RECLAIM could + * do no real monitoring and reclamation due to the watermarks-based activation + * condition. Refer to below descriptions for the watermarks parameter for + * this. + */ +static bool enabled __read_mostly = false; + +/* + * Time threshold for cold memory regions identification in microseconds. + * + * If a memory region is not accessed for this or longer time, DAMON_RECLAIM + * identifies the region as cold, and reclaims. 120 seconds by default. + */ +unsigned long min_age __read_mostly = 120000000; +module_param(min_age, ulong, 0664); + +/* + * Limit of time for trying the reclamation in milliseconds. + * + * DAMON_RECLAIM tries to use only up to this time within a time window + * (quota_reset_interval_ms) for trying reclamation of cold pages. This can be + * used for limiting CPU consumption of DAMON_RECLAIM. If the value is zero, + * the limit is disabled. + * + * 10 ms by default. + */ +unsigned long quota_ms __read_mostly = 10; +module_param(quota_ms, ulong, 0664); + +/* + * Limit of size of memory for the reclamation in bytes. + * + * DAMON_RECLAIM charges amount of memory which it tried to reclaim within a + * time window (quota_reset_interval_ms) and makes no more than this limit is + * tried. This can be used for limiting consumption of CPU and IO. If this + * value is zero, the limit is disabled. + * + * 128 MiB by default. + */ +unsigned long quota_sz __read_mostly = 128 * 1024 * 1024; +module_param(quota_sz, ulong, 0664); + +/* + * The time/size quota charge reset interval in milliseconds. + * + * The charge reset interval for the quota of time (quota_ms) and size + * (quota_sz). That is, DAMON_RECLAIM does not try reclamation for more than + * quota_ms milliseconds or quota_sz bytes within quota_reset_interval_ms + * milliseconds. + * + * 1 second by default. + */ +unsigned long quota_reset_interval_ms __read_mostly = 1000; +module_param(quota_reset_interval_ms, ulong, 0664); + +/* + * The watermarks metric + * 0 = DAMOS_WMARK_NONE // always + * 1 = DAMOS_WMARK_FREE_MEM_RATE // usually + * 2 = DAMOS_WMARK_OPLUS // often + * 3 = DAMOS_WMARK_SLEEP // never + */ +int wmarks_metric __read_mostly = 2; +module_param(wmarks_metric, int, 0664); + +/* + * The watermarks check time interval in microseconds. + * + * Minimal time to wait before checking the watermarks, when DAMON_RECLAIM is + * enabled but inactive due to its watermarks rule. 5 seconds by default. + */ +unsigned long wmarks_interval __read_mostly = 5000000; +module_param(wmarks_interval, ulong, 0664); + +/* + * Memory rate (per thousand) for the high watermark. + * + * If free memory of the system in bytes per thousand bytes is higher than + * this, DAMON_RECLAIM becomes inactive, so it does nothing but periodically + * checks the watermarks. 500 (50%) by default. + */ +unsigned long wmarks_high __read_mostly = 500; +module_param(wmarks_high, ulong, 0664); + +/* + * Memory rate (per thousand) for the middle watermark. + * + * If free memory of the system in bytes per thousand bytes is between this and + * the low watermark, DAMON_RECLAIM becomes active, so starts the monitoring + * and the reclaiming. 400 (40%) by default. + */ +unsigned long wmarks_mid __read_mostly = 400; +module_param(wmarks_mid, ulong, 0664); + +/* + * Memory rate (per thousand) for the low watermark. + * + * If free memory of the system in bytes per thousand bytes is lower than this, + * DAMON_RECLAIM becomes inactive, so it does nothing but periodically checks + * the watermarks. In the case, the system falls back to the LRU-based page + * granularity reclamation logic. 200 (20%) by default. + */ +unsigned long wmarks_low __read_mostly = 40; +module_param(wmarks_low, ulong, 0664); + +/* + * Sampling interval for the monitoring in microseconds. + * + * The sampling interval of DAMON for the cold memory monitoring. Please refer + * to the DAMON documentation for more detail. 5 ms by default. + */ +unsigned long sample_interval __read_mostly = 500000; // 500ms +module_param(sample_interval, ulong, 0664); + +/* + * Aggregation interval for the monitoring in microseconds. + * + * The aggregation interval of DAMON for the cold memory monitoring. Please + * refer to the DAMON documentation for more detail. 100 ms by default. + */ +unsigned long aggr_interval __read_mostly = 5000000; // 5 sec +module_param(aggr_interval, ulong, 0664); + +/* + * Minimum number of monitoring regions. + * + * The minimal number of monitoring regions of DAMON for the cold memory + * monitoring. This can be used to set lower-bound of the monitoring quality. + * But, setting this too high could result in increased monitoring overhead. + * Please refer to the DAMON documentation for more detail. 10 by default. + */ +unsigned long min_nr_regions __read_mostly = 10; +module_param(min_nr_regions, ulong, 0664); + +/* + * Maximum number of monitoring regions. + * + * The maximum number of monitoring regions of DAMON for the cold memory + * monitoring. This can be used to set upper-bound of the monitoring overhead. + * However, setting this too low could result in bad monitoring quality. + * Please refer to the DAMON documentation for more detail. 1000 by default. + */ +unsigned long max_nr_regions __read_mostly = 1000; +module_param(max_nr_regions, ulong, 0664); + +/* + * Start of the target memory region in physical address. + * + * The start physical address of memory region that DAMON_RECLAIM will do work + * against. By default, biggest System RAM is used as the region. + */ +static unsigned long monitor_region_start __read_mostly; +module_param(monitor_region_start, ulong, 0664); + +/* + * End of the target memory region in physical address. + * + * The end physical address of memory region that DAMON_RECLAIM will do work + * against. By default, biggest System RAM is used as the region. + */ +static unsigned long monitor_region_end __read_mostly; +module_param(monitor_region_end, ulong, 0664); + +/* + * PID of the DAMON thread + * + * If DAMON_RECLAIM is enabled, this becomes the PID of the worker thread. + * Else, -1. + */ +static int kdamond_pid __read_mostly = -1; +module_param(kdamond_pid, int, 0400); + +/* + * Number of memory regions that tried to be reclaimed. + */ +static unsigned long nr_reclaim_tried_regions __read_mostly; +module_param(nr_reclaim_tried_regions, ulong, 0400); + +/* + * Total bytes of memory regions that tried to be reclaimed. + */ +static unsigned long bytes_reclaim_tried_regions __read_mostly; +module_param(bytes_reclaim_tried_regions, ulong, 0400); + +/* + * Number of memory regions that successfully be reclaimed. + */ +static unsigned long nr_reclaimed_regions __read_mostly; +module_param(nr_reclaimed_regions, ulong, 0400); + +/* + * Total bytes of memory regions that successfully be reclaimed. + */ +static unsigned long bytes_reclaimed_regions __read_mostly; +module_param(bytes_reclaimed_regions, ulong, 0400); + +/* + * Number of times that the time/space quota limits have exceeded + */ +static unsigned long nr_quota_exceeds __read_mostly; +module_param(nr_quota_exceeds, ulong, 0400); + +static struct damon_ctx *ctx; +static struct damon_target *target; + +struct damon_reclaim_ram_walk_arg { + unsigned long start; + unsigned long end; +}; + +unsigned long nr_reclaim_time __read_mostly; +module_param(nr_reclaim_time, ulong, 0400); + +unsigned long nr_reclaim_page __read_mostly; +module_param(nr_reclaim_page, ulong, 0400); + +unsigned long nr_damon_region __read_mostly; +module_param(nr_damon_region, ulong, 0400); + +static int walk_system_ram(struct resource *res, void *arg) +{ + struct damon_reclaim_ram_walk_arg *a = arg; + + if (a->end - a->start < res->end - res->start) { + a->start = res->start; + a->end = res->end; + } + return 0; +} + +/* + * Find biggest 'System RAM' resource and store its start and end address in + * @start and @end, respectively. If no System RAM is found, returns false. + */ +static bool get_monitoring_region(unsigned long *start, unsigned long *end) +{ + struct damon_reclaim_ram_walk_arg arg = {}; + + walk_system_ram_res(0, ULONG_MAX, &arg, walk_system_ram); + if (arg.end <= arg.start) + return false; + + *start = arg.start; + *end = arg.end; + return true; +} + +static struct damos *damon_reclaim_new_scheme(void) +{ + struct damos_watermarks wmarks = { + .metric = wmarks_metric, + .interval = wmarks_interval, + .high = wmarks_high, + .mid = wmarks_mid, + .low = wmarks_low, + }; + struct damos_quota quota = { + /* + * Do not try reclamation for more than quota_ms milliseconds + * or quota_sz bytes within quota_reset_interval_ms. + */ + .ms = quota_ms, + .sz = quota_sz, + .reset_interval = quota_reset_interval_ms, + /* Within the quota, page out older regions first. */ + .weight_sz = 0, + .weight_nr_accesses = 0, + .weight_age = 1 + }; + struct damos *scheme = damon_new_scheme( + /* Find regions having PAGE_SIZE or larger size */ + PAGE_SIZE, ULONG_MAX, + /* and not accessed at all */ + 0, 0, + /* for min_age or more micro-seconds, and */ + min_age / aggr_interval, UINT_MAX, + /* page out those, as soon as found */ + DAMOS_PAGEOUT, + /* under the quota. */ + "a, + /* (De)activate this according to the watermarks. */ + &wmarks); + + return scheme; +} + +static int damon_reclaim_turn(bool on) +{ + struct damon_region *region; + struct damos *scheme; + int err; + + if (!on) { + err = damon_stop(&ctx, 1); + if (!err) + kdamond_pid = -1; + return err; + } + + err = damon_set_attrs(ctx, sample_interval, aggr_interval, 0, + min_nr_regions, max_nr_regions); + if (err) + return err; + + if (monitor_region_start > monitor_region_end) + return -EINVAL; + if (!monitor_region_start && !monitor_region_end && + !get_monitoring_region(&monitor_region_start, + &monitor_region_end)) + return -EINVAL; + /* DAMON will free this on its own when finish monitoring */ + region = damon_new_region(monitor_region_start, monitor_region_end); + if (!region) + return -ENOMEM; + damon_add_region(region, target); + + /* Will be freed by 'damon_set_schemes()' below */ + scheme = damon_reclaim_new_scheme(); + if (!scheme) { + err = -ENOMEM; + goto free_region_out; + } + err = damon_set_schemes(ctx, &scheme, 1); + if (err) + goto free_scheme_out; + + err = damon_start(&ctx, 1, true); + if (!err) { + kdamond_pid = ctx->kdamond->pid; + return 0; + } + +free_scheme_out: + damon_destroy_scheme(scheme); +free_region_out: + damon_destroy_region(region, target); + return err; +} + +#define ENABLE_CHECK_INTERVAL_MS 1000 +static struct delayed_work damon_reclaim_timer; +static void damon_reclaim_timer_fn(struct work_struct *work) +{ + static bool last_enabled; + bool now_enabled; + + now_enabled = enabled; + if (last_enabled != now_enabled) { + if (!damon_reclaim_turn(now_enabled)) + last_enabled = now_enabled; + else + enabled = last_enabled; + } + + if (enabled) + schedule_delayed_work(&damon_reclaim_timer, + msecs_to_jiffies(ENABLE_CHECK_INTERVAL_MS)); +} +static DECLARE_DELAYED_WORK(damon_reclaim_timer, damon_reclaim_timer_fn); + +static int enabled_store(const char *val, + const struct kernel_param *kp) +{ + int rc = param_set_bool(val, kp); + + if (rc < 0) + return rc; + + if (enabled) + schedule_delayed_work(&damon_reclaim_timer, 0); + + return 0; +} + +static const struct kernel_param_ops enabled_param_ops = { + .set = enabled_store, + .get = param_get_bool, +}; + +module_param_cb(enabled, &enabled_param_ops, &enabled, 0664); +MODULE_PARM_DESC(enabled, + "Enable or disable DAMON_RECLAIM (default: disabled)"); + +static int damon_reclaim_after_aggregation(struct damon_ctx *c) +{ + struct damos *s; + + /* update the stats parameter */ + damon_for_each_scheme(s, c) { + nr_reclaim_tried_regions = s->stat.nr_tried; + bytes_reclaim_tried_regions = s->stat.sz_tried; + nr_reclaimed_regions = s->stat.nr_applied; + bytes_reclaimed_regions = s->stat.sz_applied; + nr_quota_exceeds = s->stat.qt_exceeds; + trace_damon_reclaim_statistics(nr_reclaim_tried_regions, + bytes_reclaim_tried_regions, + nr_reclaimed_regions, + bytes_reclaimed_regions, + nr_quota_exceeds); + } + return 0; +} + +static int __init damon_reclaim_init(void) +{ + ctx = damon_new_ctx(); + if (!ctx) + return -ENOMEM; + + if (damon_select_ops(ctx, DAMON_OPS_PADDR)) + return -EINVAL; + + ctx->callback.after_aggregation = damon_reclaim_after_aggregation; + + target = damon_new_target(); + if (!target) { + damon_destroy_ctx(ctx); + return -ENOMEM; + } + damon_add_target(ctx, target); + + schedule_delayed_work(&damon_reclaim_timer, 0); + return 0; +} + +module_init(damon_reclaim_init); diff --git a/mm/healthinfo b/mm/healthinfo new file mode 120000 index 000000000000..e97c46b7f19a --- /dev/null +++ b/mm/healthinfo @@ -0,0 +1 @@ +../../../vendor/oplus/kernel/oplus_performance/healthinfo/mm/ \ No newline at end of file diff --git a/mm/huge_memory.c b/mm/huge_memory.c index 8f260c1cc09a..df1280f08e07 100644 --- a/mm/huge_memory.c +++ b/mm/huge_memory.c @@ -2285,6 +2285,8 @@ void __split_huge_pmd(struct vm_area_struct *vma, pmd_t *pmd, unsigned long address, bool freeze, struct page *page) { spinlock_t *ptl; + bool was_locked = false; + pmd_t _pmd; struct mm_struct *mm = vma->vm_mm; unsigned long haddr = address & HPAGE_PMD_MASK; bool do_unlock_page = false; @@ -2475,7 +2477,8 @@ static void __split_huge_page_tail(struct page *head, int tail, (1L << PG_workingset) | (1L << PG_locked) | (1L << PG_unevictable) | - (1L << PG_dirty))); + (1L << PG_dirty) | + LRU_GEN_MASK | LRU_REFS_MASK)); /* ->mapping in first tail page is compound_mapcount */ VM_BUG_ON_PAGE(tail > 2 && page_tail->mapping != TAIL_MAPPING, diff --git a/mm/kasan/report.c b/mm/kasan/report.c index 0772820ad098..c66945905434 100644 --- a/mm/kasan/report.c +++ b/mm/kasan/report.c @@ -94,6 +94,10 @@ static void end_report(unsigned long *flags) if (panic_on_warn) panic("panic_on_warn set ...\n"); kasan_enable_current(); +#ifdef OPLUS_BUG_STABILITY +/* trigger KE to get the KAsan double free message*/ + BUG(); +#endif } static void print_track(struct kasan_track *track, const char *prefix) diff --git a/mm/kmemleak.c b/mm/kmemleak.c index 740cba23f4a3..560b94ba595c 100644 --- a/mm/kmemleak.c +++ b/mm/kmemleak.c @@ -112,6 +112,9 @@ #include #include +#ifdef OPLUS_BUG_STABILITY +#include +#endif /* * Kmemleak configuration and common defines. */ @@ -2113,12 +2116,20 @@ void __init kmemleak_init(void) */ static int __init kmemleak_late_init(void) { +#ifdef OPLUS_BUG_STABILITY + struct proc_dir_entry *dentry = NULL; +#else struct dentry *dentry; - +#endif kmemleak_initialized = 1; +#ifdef OPLUS_BUG_STABILITY + dentry = proc_create("kmemleak", 0644, NULL, &kmemleak_fops); +#else dentry = debugfs_create_file("kmemleak", 0644, NULL, NULL, &kmemleak_fops); +#endif + if (!dentry) pr_warn("Failed to create the debugfs kmemleak file\n"); diff --git a/mm/madvise.c b/mm/madvise.c index 31b2a86d126d..8042f9cc34ac 100644 --- a/mm/madvise.c +++ b/mm/madvise.c @@ -192,8 +192,13 @@ out: } #ifdef CONFIG_SWAP +#if defined(CONFIG_NANDSWAP) || defined(CONFIG_PROCESS_RECLAIM_ENHANCE) +int swapin_walk_pmd_entry(pmd_t *pmd, unsigned long start, + unsigned long end, struct mm_walk *walk) +#else static int swapin_walk_pmd_entry(pmd_t *pmd, unsigned long start, unsigned long end, struct mm_walk *walk) +#endif { pte_t *orig_pte; struct vm_area_struct *vma = walk->private; @@ -208,6 +213,10 @@ static int swapin_walk_pmd_entry(pmd_t *pmd, unsigned long start, struct page *page; spinlock_t *ptl; +#if defined(CONFIG_NANDSWAP) || defined(CONFIG_PROCESS_RECLAIM_ENHANCE) + if (!list_empty(&vma->vm_mm->mmap_sem.wait_list)) + return -1; +#endif orig_pte = pte_offset_map_lock(vma->vm_mm, pmd, start, &ptl); pte = *(orig_pte + ((index - start) / PAGE_SIZE)); pte_unmap_unlock(orig_pte, ptl); diff --git a/mm/malloc_track b/mm/malloc_track new file mode 120000 index 000000000000..1574043ed9dc --- /dev/null +++ b/mm/malloc_track @@ -0,0 +1 @@ +../../../vendor/oplus/kernel/oplus_performance/memleak_detect/malloc_track \ No newline at end of file diff --git a/mm/memcontrol.c b/mm/memcontrol.c index f3aa6e6214d5..f51bbe61492a 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c @@ -73,6 +73,7 @@ #include #include +#include struct cgroup_subsys memory_cgrp_subsys __read_mostly; EXPORT_SYMBOL(memory_cgrp_subsys); @@ -1184,12 +1185,14 @@ void mem_cgroup_update_lru_size(struct lruvec *lruvec, enum lru_list lru, *lru_size += nr_pages; size = *lru_size; +#ifndef CONFIG_LRU_GEN if (WARN_ONCE(size < 0, "%s(%p, %d, %d): lru_size %ld\n", __func__, lruvec, lru, nr_pages, size)) { VM_BUG_ON(1); *lru_size = 0; } +#endif if (nr_pages > 0) *lru_size += nr_pages; @@ -2392,7 +2395,7 @@ static void lock_page_lru(struct page *page, int *isolated) lruvec = mem_cgroup_page_lruvec(page, zone->zone_pgdat); ClearPageLRU(page); - del_page_from_lru_list(page, lruvec, page_lru(page)); + del_page_from_lru_list(page, lruvec); *isolated = 1; } else *isolated = 0; @@ -2408,7 +2411,7 @@ static void unlock_page_lru(struct page *page, int isolated) lruvec = mem_cgroup_page_lruvec(page, zone->zone_pgdat); VM_BUG_ON_PAGE(PageLRU(page), page); SetPageLRU(page); - add_page_to_lru_list(page, lruvec, page_lru(page)); + add_page_to_lru_list(page, lruvec); } spin_unlock_irq(zone_lru_lock(zone)); } @@ -2440,6 +2443,7 @@ static void commit_charge(struct page *page, struct mem_cgroup *memcg, * * - a page cache insertion, a swapin fault, or a migration * have the page locked + * - mem_cgroup_trylock_pages() */ page->mem_cgroup = memcg; @@ -3516,8 +3520,8 @@ static int memcg_stat_show(struct seq_file *m, void *v) pg_data_t *pgdat; struct mem_cgroup_per_node *mz; struct zone_reclaim_stat *rstat; - unsigned long recent_rotated[2] = {0, 0}; - unsigned long recent_scanned[2] = {0, 0}; + unsigned long recent_rotated[ANON_AND_FILE] = {}; + unsigned long recent_scanned[ANON_AND_FILE] = {}; for_each_online_pgdat(pgdat) { mz = mem_cgroup_nodeinfo(memcg, pgdat->node_id); @@ -4401,6 +4405,7 @@ static DEFINE_IDR(mem_cgroup_idr); static void mem_cgroup_id_remove(struct mem_cgroup *memcg) { if (memcg->id.id > 0) { + trace_android_vh_mem_cgroup_id_remove(memcg); idr_remove(&mem_cgroup_idr, memcg->id.id); memcg->id.id = 0; } @@ -4444,6 +4449,7 @@ struct mem_cgroup *mem_cgroup_from_id(unsigned short id) WARN_ON_ONCE(!rcu_read_lock_held()); return idr_find(&mem_cgroup_idr, id); } +EXPORT_SYMBOL(mem_cgroup_from_id); static int alloc_mem_cgroup_per_node_info(struct mem_cgroup *memcg, int node) { @@ -4496,11 +4502,13 @@ static void __mem_cgroup_free(struct mem_cgroup *memcg) for_each_node(node) free_mem_cgroup_per_node_info(memcg, node); free_percpu(memcg->stat_cpu); + trace_android_vh_mem_cgroup_free(memcg); kfree(memcg); } static void mem_cgroup_free(struct mem_cgroup *memcg) { + lru_gen_exit_memcg(memcg); memcg_wb_domain_exit(memcg); __mem_cgroup_free(memcg); } @@ -4551,6 +4559,8 @@ static struct mem_cgroup *mem_cgroup_alloc(void) INIT_LIST_HEAD(&memcg->cgwb_list); #endif idr_replace(&mem_cgroup_idr, memcg, memcg->id.id); + lru_gen_init_memcg(memcg); + trace_android_vh_mem_cgroup_alloc(memcg); return memcg; fail: mem_cgroup_id_remove(memcg); @@ -4634,6 +4644,7 @@ static int mem_cgroup_css_online(struct cgroup_subsys_state *css) /* Online state pins memcg ID, memcg ID pins CSS */ atomic_set(&memcg->id.ref, 1); css_get(css); + trace_android_vh_mem_cgroup_css_online(css, memcg); return 0; } @@ -4642,6 +4653,7 @@ static void mem_cgroup_css_offline(struct cgroup_subsys_state *css) struct mem_cgroup *memcg = mem_cgroup_from_css(css); struct mem_cgroup_event *event, *tmp; + trace_android_vh_mem_cgroup_css_offline(css, memcg); /* * Unregister events and notify userspace. * Notify userspace about cgroup removing only after rmdir of cgroup @@ -5425,6 +5437,29 @@ static void mem_cgroup_move_task(void) } #endif +#ifdef CONFIG_LRU_GEN +static void mem_cgroup_attach(struct cgroup_taskset *tset) +{ + struct cgroup_subsys_state *css; + struct task_struct *task = NULL; + + cgroup_taskset_for_each_leader(task, css, tset) + break; + + if (!task) + return; + + task_lock(task); + if (task->mm && task->mm->owner == task) + lru_gen_migrate_mm(task->mm); + task_unlock(task); +} +#else +static void mem_cgroup_attach(struct cgroup_taskset *tset) +{ +} +#endif /* CONFIG_LRU_GEN */ + /* * Cgroup retains root cgroups across [un]mount cycles making it necessary * to verify whether we're attached to the default hierarchy on each mount @@ -5794,6 +5829,7 @@ struct cgroup_subsys memory_cgrp_subsys = { .css_free = mem_cgroup_css_free, .css_reset = mem_cgroup_css_reset, .can_attach = mem_cgroup_can_attach, + .attach = mem_cgroup_attach, .cancel_attach = mem_cgroup_cancel_attach, .post_attach = mem_cgroup_move_task, .bind = mem_cgroup_bind, diff --git a/mm/memory.c b/mm/memory.c index f955f87d080e..77fc30df4ce9 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -40,6 +40,7 @@ #include #include +#include #include #include #include @@ -1124,6 +1125,12 @@ static int copy_pte_range(struct mm_struct *dst_mm, struct mm_struct *src_mm, spinlock_t *src_ptl, *dst_ptl; int progress = 0; int rss[NR_MM_COUNTERS]; + +#ifdef OPLUS_BUG_STABILITY +//Bin.Xu @ BSP.Kernel.Stability, 2020/4/1, checklist: flush_tlb_range for dirty pages + unsigned long orig_addr = addr; +#endif /* OPLUS_BUG_STABILITY */ + swp_entry_t entry = (swp_entry_t){0}; again: @@ -1162,6 +1169,14 @@ again: } while (dst_pte++, src_pte++, addr += PAGE_SIZE, addr != end); arch_leave_lazy_mmu_mode(); + +#ifdef OPLUS_BUG_STABILITY +//Bin.Xu @ BSP.Kernel.Stability, 2020/4/1, checklist: flush_tlb_range for dirty pages + if (IS_ENABLED(CONFIG_SPECULATIVE_PAGE_FAULT) && + is_cow_mapping(vma->vm_flags)) + flush_tlb_range(vma, orig_addr, end); +#endif /* OPLUS_BUG_STABILITY */ + spin_unlock(src_ptl); pte_unmap(orig_src_pte); add_mm_rss_vec(dst_mm, rss); @@ -3235,6 +3250,47 @@ void unmap_mapping_range(struct address_space *mapping, } EXPORT_SYMBOL(unmap_mapping_range); +#ifdef CONFIG_LRU_GEN +static void lru_gen_enter_fault(struct vm_area_struct *vma) +{ + /* the LRU algorithm doesn't apply to sequential or random reads */ + current->in_lru_fault = !(vma->vm_flags & (VM_SEQ_READ | VM_RAND_READ)); +} + +static void lru_gen_exit_fault(void) +{ + current->in_lru_fault = false; +} + +static void lru_gen_swap_refault(struct page *page, swp_entry_t entry) +{ + void *item; + struct address_space *mapping = swap_address_space(entry); + pgoff_t index = swp_offset(entry); + + if (!lru_gen_enabled()) + return; + + rcu_read_lock(); + item = radix_tree_lookup(&mapping->i_pages, index); + rcu_read_unlock(); + if (radix_tree_exceptional_entry(item)) + lru_gen_refault(page, item); +} +#else +static void lru_gen_enter_fault(struct vm_area_struct *vma) +{ +} + +static void lru_gen_exit_fault(void) +{ +} + +static void lru_gen_swap_refault(struct page *page, swp_entry_t entry) +{ +} +#endif /* CONFIG_LRU_GEN */ + /* * We enter with non-exclusive mmap_sem (to exclude vma changes, * but allow concurrent faults), and pte mapped but not yet locked. @@ -3316,6 +3372,7 @@ vm_fault_t do_swap_page(struct vm_fault *vmf) __SetPageLocked(page); __SetPageSwapBacked(page); set_page_private(page, entry.val); + lru_gen_swap_refault(page, entry); lru_cache_add_anon(page); swap_readpage(page, true); } @@ -3449,7 +3506,8 @@ vm_fault_t do_swap_page(struct vm_fault *vmf) } else { do_page_add_anon_rmap(page, vma, vmf->address, exclusive); mem_cgroup_commit_charge(page, memcg, true, false); - activate_page(page); + if (!lru_gen_enabled()) + activate_page(page); } swap_free(entry); @@ -3497,6 +3555,7 @@ out_release: } return ret; } +EXPORT_SYMBOL(do_swap_page); /* * We enter with non-exclusive mmap_sem (to exclude vma changes, @@ -4791,7 +4850,9 @@ int __handle_speculative_fault(struct mm_struct *mm, unsigned long address, } mem_cgroup_enter_user_fault(); + lru_gen_enter_fault(vmf.vma); ret = handle_pte_fault(&vmf); + lru_gen_exit_fault(); mem_cgroup_exit_user_fault(); /* @@ -4882,11 +4943,15 @@ vm_fault_t handle_mm_fault(struct vm_area_struct *vma, unsigned long address, if (flags & FAULT_FLAG_USER) mem_cgroup_enter_user_fault(); + lru_gen_enter_fault(vma); + if (unlikely(is_vm_hugetlb_page(vma))) ret = hugetlb_fault(vma->vm_mm, vma, address, flags); else ret = __handle_mm_fault(vma, address, flags); + lru_gen_exit_fault(); + if (flags & FAULT_FLAG_USER) { mem_cgroup_exit_user_fault(); /* diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c index f062207dce9e..0ca7693664ae 100644 --- a/mm/memory_hotplug.c +++ b/mm/memory_hotplug.c @@ -42,6 +42,9 @@ #include "internal.h" +#if defined(OPLUS_FEATURE_MULTI_FREEAREA) && defined(CONFIG_PHYSICAL_ANTI_FRAGMENTATION) +#include "multi_freearea.h" +#endif /* * online_page_callback contains pointer to current page onlining function. * Initially it is generic_online_page(). If it is required it could be @@ -396,6 +399,9 @@ static void shrink_zone_span(struct zone *zone, unsigned long start_pfn, zone->spanned_pages = pfn - zone_start_pfn + 1; } +#if defined(OPLUS_FEATURE_MULTI_FREEAREA) && defined(CONFIG_PHYSICAL_ANTI_FRAGMENTATION) + ajust_zone_label(zone); +#endif /* * The section is not biggest or smallest mem_section in the zone, it * only creates a hole in the zone. So in this case, we need not @@ -422,6 +428,9 @@ static void shrink_zone_span(struct zone *zone, unsigned long start_pfn, /* The zone has no valid section */ zone->zone_start_pfn = 0; zone->spanned_pages = 0; +#if defined(OPLUS_FEATURE_MULTI_FREEAREA) && defined(CONFIG_PHYSICAL_ANTI_FRAGMENTATION) + ajust_zone_label(zone); +#endif zone_span_writeunlock(zone); } @@ -737,6 +746,9 @@ static void __meminit resize_zone_range(struct zone *zone, unsigned long start_p zone->zone_start_pfn = start_pfn; zone->spanned_pages = max(start_pfn + nr_pages, old_end_pfn) - zone->zone_start_pfn; +#if defined(OPLUS_FEATURE_MULTI_FREEAREA) && defined(CONFIG_PHYSICAL_ANTI_FRAGMENTATION) + ajust_zone_label(zone); +#endif } static void __meminit resize_pgdat_range(struct pglist_data *pgdat, unsigned long start_pfn, diff --git a/mm/memory_isolate b/mm/memory_isolate new file mode 120000 index 000000000000..3f86ff9c5cba --- /dev/null +++ b/mm/memory_isolate @@ -0,0 +1 @@ +../../../vendor/oplus/kernel/oplus_performance/memory_isolate \ No newline at end of file diff --git a/mm/mlock.c b/mm/mlock.c index 622c845a3ab8..2fab3675f6f2 100644 --- a/mm/mlock.c +++ b/mm/mlock.c @@ -23,7 +23,6 @@ #include #include #include - #include "internal.h" bool can_do_mlock(void) @@ -115,7 +114,7 @@ static bool __munlock_isolate_lru_page(struct page *page, bool getpage) if (getpage) get_page(page); ClearPageLRU(page); - del_page_from_lru_list(page, lruvec, page_lru(page)); + del_page_from_lru_list(page, lruvec); return true; } @@ -795,6 +794,7 @@ static int apply_mlockall_flags(int flags) mlock_fixup(vma, &prev, vma->vm_start, vma->vm_end, newflags); cond_resched(); } + out: return 0; } diff --git a/mm/mm_init.c b/mm/mm_init.c index 6838a530789b..7333da18eee6 100644 --- a/mm/mm_init.c +++ b/mm/mm_init.c @@ -66,13 +66,17 @@ void __init mminit_verify_pageflags_layout(void) unsigned long or_mask, add_mask; shift = 8 * sizeof(unsigned long); - width = shift - SECTIONS_WIDTH - NODES_WIDTH - ZONES_WIDTH - LAST_CPUPID_SHIFT; + width = shift - SECTIONS_WIDTH - NODES_WIDTH - ZONES_WIDTH + - LAST_CPUPID_SHIFT - KASAN_TAG_WIDTH - LRU_GEN_WIDTH - LRU_REFS_WIDTH; mminit_dprintk(MMINIT_TRACE, "pageflags_layout_widths", - "Section %d Node %d Zone %d Lastcpupid %d Flags %d\n", + "Section %d Node %d Zone %d Lastcpupid %d Kasantag %d Gen %d Tier %d Flags %d\n", SECTIONS_WIDTH, NODES_WIDTH, ZONES_WIDTH, LAST_CPUPID_WIDTH, + KASAN_TAG_WIDTH, + LRU_GEN_WIDTH, + LRU_REFS_WIDTH, NR_PAGEFLAGS); mminit_dprintk(MMINIT_TRACE, "pageflags_layout_shifts", "Section %d Node %d Zone %d Lastcpupid %d\n", diff --git a/mm/mmap.c b/mm/mmap.c index cbddfcc871ce..f761de345e20 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -51,6 +51,9 @@ #include #include #include +#if defined(OPLUS_FEATURE_VIRTUAL_RESERVE_MEMORY) && defined(CONFIG_VIRTUAL_RESERVE_MEMORY) +#include +#endif #include "internal.h" @@ -242,6 +245,7 @@ SYSCALL_DEFINE1(brk, unsigned long, brk) newbrk = PAGE_ALIGN(brk); oldbrk = PAGE_ALIGN(mm->brk); + if (oldbrk == newbrk) goto set_brk; @@ -1942,6 +1946,7 @@ unsigned long unmapped_area(struct vm_unmapped_area_info *info) if (RB_EMPTY_ROOT(&mm->mm_rb)) goto check_highest; vma = rb_entry(mm->mm_rb.rb_node, struct vm_area_struct, vm_rb); + if (vma->rb_subtree_gap < length) goto check_highest; @@ -2007,7 +2012,6 @@ found: /* Adjust gap address to the desired alignment */ gap_start += (info->align_offset - gap_start) & info->align_mask; - VM_BUG_ON(gap_start + info->length > info->high_limit); VM_BUG_ON(gap_start + info->length > gap_end); return gap_start; @@ -2024,6 +2028,9 @@ unsigned long unmapped_area_topdown(struct vm_unmapped_area_info *info) if (length < info->length) return -ENOMEM; +#if defined(OPLUS_FEATURE_VIRTUAL_RESERVE_MEMORY) && defined(CONFIG_VIRTUAL_RESERVE_MEMORY) + GET_UNMMPAED_AREA_FROME_ANTI_FRAGMENT(info, mm); +#endif /* * Adjust search limits by the desired length. * See implementation comment at top of unmapped_area(). @@ -2193,6 +2200,11 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, info.flags = VM_UNMAPPED_AREA_TOPDOWN; info.length = len; info.low_limit = max(PAGE_SIZE, mmap_min_addr); +#if defined(OPLUS_FEATURE_VIRTUAL_RESERVE_MEMORY) && defined(CONFIG_VIRTUAL_RESERVE_MEMORY) + /* get unmmaped area first time, update the low limit */ + GET_UNMMAPED_AREA_FIRST_TIME(info); +#endif + info.high_limit = mm->mmap_base; info.align_mask = 0; info.align_offset = 0; @@ -2209,9 +2221,17 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, info.flags = 0; info.low_limit = TASK_UNMAPPED_BASE; info.high_limit = TASK_SIZE; +#if defined(OPLUS_FEATURE_VIRTUAL_RESERVE_MEMORY) && defined(CONFIG_VIRTUAL_RESERVE_MEMORY) + /* get unmmaped area second time */ addr = vm_unmapped_area(&info); +#endif } +#if defined(OPLUS_FEATURE_VIRTUAL_RESERVE_MEMORY) && defined(CONFIG_VIRTUAL_RESERVE_MEMORY) + /* get unmmaped area third time */ + GET_UNMMAPED_AREA_THIRD_TIME(info, mm, addr); +#endif + return addr; } #endif @@ -2700,7 +2720,6 @@ detach_vmas_to_be_unmapped(struct mm_struct *mm, struct vm_area_struct *vma, { struct vm_area_struct **insertion_point; struct vm_area_struct *tail_vma = NULL; - insertion_point = (prev ? &prev->vm_next : &mm->mmap); vma->vm_prev = NULL; do { diff --git a/mm/mmzone.c b/mm/mmzone.c index 4dd4f96ddfc0..97ead93e02df 100644 --- a/mm/mmzone.c +++ b/mm/mmzone.c @@ -95,6 +95,8 @@ void lruvec_init(struct lruvec *lruvec) for_each_lru(lru) INIT_LIST_HEAD(&lruvec->lists[lru]); + + lru_gen_init_lruvec(lruvec); } #if defined(CONFIG_NUMA_BALANCING) && !defined(LAST_CPUPID_NOT_IN_PAGE_FLAGS) diff --git a/mm/multi_freearea.c b/mm/multi_freearea.c new file mode 120000 index 000000000000..a1028c576e80 --- /dev/null +++ b/mm/multi_freearea.c @@ -0,0 +1 @@ +../../../vendor/oplus/kernel/oplus_performance/multi_freearea/multi_freearea.c \ No newline at end of file diff --git a/mm/multi_freearea.h b/mm/multi_freearea.h new file mode 120000 index 000000000000..a4893b7c8491 --- /dev/null +++ b/mm/multi_freearea.h @@ -0,0 +1 @@ +../../../vendor/oplus/kernel/oplus_performance/multi_freearea/multi_freearea.h \ No newline at end of file diff --git a/mm/multi_kswapd b/mm/multi_kswapd new file mode 120000 index 000000000000..61c4d72d370d --- /dev/null +++ b/mm/multi_kswapd @@ -0,0 +1 @@ +../../../vendor/oplus/kernel/oplus_performance/multi_kswapd \ No newline at end of file diff --git a/mm/oom_kill.c b/mm/oom_kill.c index 07a669936654..da2bbc802a9b 100644 --- a/mm/oom_kill.c +++ b/mm/oom_kill.c @@ -583,8 +583,8 @@ void dump_tasks(struct mem_cgroup *memcg, const nodemask_t *nodemask) struct task_struct *p; struct task_struct *task; - pr_info("Tasks state (memory values in pages):\n"); - pr_info("[ pid ] uid tgid total_vm rss pgtables_bytes swapents oom_score_adj name\n"); + pr_warn("Tasks state (memory values in pages):\n"); + pr_warn("[ pid ] uid tgid total_vm rss pgtables_bytes swapents oom_score_adj name\n"); rcu_read_lock(); for_each_process(p) { if (oom_unkillable_task(p, memcg, nodemask)) @@ -600,7 +600,7 @@ void dump_tasks(struct mem_cgroup *memcg, const nodemask_t *nodemask) continue; } - pr_info("[%7d] %5d %5d %8lu %8lu %8ld %8lu %5hd %s\n", + pr_warn("[%7d] %5d %5d %8lu %8lu %8ld %8lu %5hd %s\n", task->pid, from_kuid(&init_user_ns, task_uid(task)), task->tgid, task->mm->total_vm, get_mm_rss(task->mm), mm_pgtables_bytes(task->mm), diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 05fc5b60a050..3830b4ee9c9b 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -69,12 +69,27 @@ #include #include #include +#include #include #include #include #include "internal.h" +#ifdef OPLUS_FEATURE_HEALTHINFO +#ifdef CONFIG_OPLUS_MEM_MONITOR +#include +#endif +#endif /* OPLUS_FEATURE_HEALTHINFO */ + +#if defined(OPLUS_FEATURE_MEMORY_ISOLATE) && defined(CONFIG_OPLUS_MEMORY_ISOLATE) +#include +#endif /*OPLUS_FEATURE_MEMORY_ISOLATE*/ + +#if defined(OPLUS_FEATURE_MULTI_FREEAREA) && defined(CONFIG_PHYSICAL_ANTI_FRAGMENTATION) +#include "multi_freearea.h" +#endif + /* prevent >1 _updater_ of zone percpu pageset ->high and ->batch fields */ static DEFINE_MUTEX(pcp_batch_high_lock); #define MIN_PERCPU_PAGELIST_FRACTION (8) @@ -183,6 +198,7 @@ static int __init early_init_on_free(char *buf) } early_param("init_on_free", early_init_on_free); + /* * A cached value of the page's pageblock's migratetype, used when the page is * put on a pcplist. Used to avoid the pageblock migratetype lookup when @@ -296,6 +312,10 @@ char * const migratetype_names[MIGRATE_TYPES] = { #ifdef CONFIG_CMA "CMA", #endif +#if defined(OPLUS_FEATURE_MEMORY_ISOLATE) && defined(CONFIG_OPLUS_MEMORY_ISOLATE) + "OPLUS2", +#endif /* OPLUS_FEATURE_MEMORY_ISOLATE */ + "HighAtomic", #ifdef CONFIG_MEMORY_ISOLATION "Isolate", @@ -935,6 +955,9 @@ static inline void __free_one_page(struct page *page, struct page *buddy; unsigned int max_order; struct capture_control *capc = task_capc(zone); +#if defined(OPLUS_FEATURE_MULTI_FREEAREA) && defined(CONFIG_PHYSICAL_ANTI_FRAGMENTATION) + unsigned int flc; +#endif max_order = min_t(unsigned int, MAX_ORDER - 1, pageblock_order); @@ -970,7 +993,12 @@ continue_merging: clear_page_guard(zone, buddy, order, migratetype); } else { list_del(&buddy->lru); +#if defined(OPLUS_FEATURE_MULTI_FREEAREA) && defined(CONFIG_PHYSICAL_ANTI_FRAGMENTATION) + flc = page_to_flc(buddy); + zone->free_area[flc][order].nr_free--; +#else zone->free_area[order].nr_free--; +#endif rmv_page_order(buddy); } combined_pfn = buddy_pfn & pfn; @@ -1022,15 +1050,27 @@ done_merging: higher_buddy = higher_page + (buddy_pfn - combined_pfn); if (pfn_valid_within(buddy_pfn) && page_is_buddy(higher_page, higher_buddy, order + 1)) { +#if defined(OPLUS_FEATURE_MULTI_FREEAREA) && defined(CONFIG_PHYSICAL_ANTI_FRAGMENTATION) + flc = page_to_flc(page); + list_add_tail(&page->lru, + &zone->free_area[flc][order].free_list[migratetype]); +#else list_add_tail(&page->lru, &zone->free_area[order].free_list[migratetype]); +#endif goto out; } } - +#if defined(OPLUS_FEATURE_MULTI_FREEAREA) && defined(CONFIG_PHYSICAL_ANTI_FRAGMENTATION) + list_sort_add(page, zone, order, migratetype); +out: + flc = page_to_flc(page); + zone->free_area[flc][order].nr_free++; +#else list_add(&page->lru, &zone->free_area[order].free_list[migratetype]); out: zone->free_area[order].nr_free++; +#endif } /* @@ -1453,6 +1493,7 @@ static void __free_pages_boot_core(struct page *page, unsigned int order) page_zone(page)->managed_pages += nr_pages; set_page_refcounted(page); __free_pages(page, order); + } #if defined(CONFIG_HAVE_ARCH_EARLY_PFN_TO_NID) || \ @@ -1969,6 +2010,9 @@ static inline void expand(struct zone *zone, struct page *page, int migratetype) { unsigned long size = 1 << high; +#if defined(OPLUS_FEATURE_MULTI_FREEAREA) && defined(CONFIG_PHYSICAL_ANTI_FRAGMENTATION) + unsigned int flc = 0; +#endif while (high > low) { area--; @@ -1984,9 +2028,14 @@ static inline void expand(struct zone *zone, struct page *page, */ if (set_page_guard(zone, &page[size], high, migratetype)) continue; - +#if defined(OPLUS_FEATURE_MULTI_FREEAREA) && defined(CONFIG_PHYSICAL_ANTI_FRAGMENTATION) + list_sort_add(&page[size], zone, high, migratetype); + flc = page_to_flc(&page[size]); + zone->free_area[flc][high].nr_free++; +#else list_add(&page[size].lru, &area->free_list[migratetype]); area->nr_free++; +#endif set_page_order(&page[size], high); } } @@ -2120,22 +2169,37 @@ struct page *__rmqueue_smallest(struct zone *zone, unsigned int order, unsigned int current_order; struct free_area *area; struct page *page; - +#if defined(OPLUS_FEATURE_MULTI_FREEAREA) && defined(CONFIG_PHYSICAL_ANTI_FRAGMENTATION) + unsigned int flc = 0, flc_tmp = 0, flc_last = 0; + for (flc = 0; flc < FREE_AREA_COUNTS; flc++) { + flc_tmp = ajust_flc(flc, order); +#endif /* Find a page of the appropriate size in the preferred list */ for (current_order = order; current_order < MAX_ORDER; ++current_order) { +#if defined(OPLUS_FEATURE_MULTI_FREEAREA) && defined(CONFIG_PHYSICAL_ANTI_FRAGMENTATION) + area = &(zone->free_area[flc_tmp][current_order]); +#else area = &(zone->free_area[current_order]); +#endif page = list_first_entry_or_null(&area->free_list[migratetype], struct page, lru); if (!page) continue; list_del(&page->lru); rmv_page_order(page); +#if defined(OPLUS_FEATURE_MULTI_FREEAREA) && defined(CONFIG_PHYSICAL_ANTI_FRAGMENTATION) + flc_last = page_to_flc(page); + zone->free_area[flc_last][current_order].nr_free--; +#else area->nr_free--; +#endif expand(zone, page, order, current_order, area, migratetype); set_pcppage_migratetype(page, migratetype); return page; } - +#if defined(OPLUS_FEATURE_MULTI_FREEAREA) && defined(CONFIG_PHYSICAL_ANTI_FRAGMENTATION) + } +#endif return NULL; } @@ -2220,8 +2284,13 @@ static int move_freepages(struct zone *zone, } order = page_order(page); +#if defined(OPLUS_FEATURE_MULTI_FREEAREA) && defined(CONFIG_PHYSICAL_ANTI_FRAGMENTATION) + __list_del_entry(&page->lru); + list_sort_add(page, zone, order, migratetype); +#else list_move(&page->lru, &zone->free_area[order].free_list[migratetype]); +#endif page += 1 << order; pages_moved += 1 << order; } @@ -2276,6 +2345,11 @@ static void change_pageblock_range(struct page *pageblock_page, */ static bool can_steal_fallback(unsigned int order, int start_mt) { +#if defined(OPLUS_FEATURE_MEMORY_ISOLATE) && defined(CONFIG_OPLUS_MEMORY_ISOLATE) + if(is_migrate_(start_mt)) + return false; +#endif /*OPLUS_FEATURE_MEMORY_ISOLATE*/ + /* * Leaving this order check is intended, although there is * relaxed order check in next check. The reason is that @@ -2322,6 +2396,7 @@ static bool boost_eligible(struct zone *z) return true; } +#ifndef CONFIG_DYNAMIC_TUNNING_SWAPPINESS static inline void boost_watermark(struct zone *zone) { unsigned long max_boost; @@ -2348,6 +2423,35 @@ static inline void boost_watermark(struct zone *zone) zone->watermark_boost = min(zone->watermark_boost + pageblock_nr_pages, max_boost); } +#else +static inline bool boost_watermark(struct zone *zone) +{ + unsigned long max_boost; + + if (!watermark_boost_factor || !boost_eligible(zone)) + return false; + + max_boost = mult_frac(zone->_watermark[WMARK_HIGH], + watermark_boost_factor, 10000); + + /* + * high watermark may be uninitialised if fragmentation occurs + * very early in boot so do not boost. We do not fall + * through and boost by pageblock_nr_pages as failing + * allocations that early means that reclaim is not going + * to help and it may even be impossible to reclaim the + * boosted watermark resulting in a hang. + */ + if (!max_boost) + return false; + + max_boost = max(pageblock_nr_pages, max_boost); + + zone->watermark_boost = min(zone->watermark_boost + pageblock_nr_pages, + max_boost); + return true; +} +#endif /* * This function implements actual steal behaviour. If order is large enough, @@ -2361,7 +2465,9 @@ static void steal_suitable_fallback(struct zone *zone, struct page *page, unsigned int alloc_flags, int start_type, bool whole_block) { unsigned int current_order = page_order(page); +#if !defined(OPLUS_FEATURE_MULTI_FREEAREA) || !defined(CONFIG_PHYSICAL_ANTI_FRAGMENTATION) struct free_area *area; +#endif int free_pages, movable_pages, alike_pages; int old_block_type; @@ -2385,9 +2491,14 @@ static void steal_suitable_fallback(struct zone *zone, struct page *page, * likelihood of future fallbacks. Wake kswapd now as the node * may be balanced overall and kswapd will not wake naturally. */ +#ifndef CONFIG_DYNAMIC_TUNNING_SWAPPINESS boost_watermark(zone); if (alloc_flags & ALLOC_KSWAPD) set_bit(ZONE_BOOSTED_WATERMARK, &zone->flags); +#else + if (boost_watermark(zone) && alloc_flags & ALLOC_KSWAPD) + set_bit(ZONE_BOOSTED_WATERMARK, &zone->flags); +#endif /* We are not allowed to try stealing from the whole block */ if (!whole_block) @@ -2432,8 +2543,13 @@ static void steal_suitable_fallback(struct zone *zone, struct page *page, return; single_page: +#if defined(OPLUS_FEATURE_MULTI_FREEAREA) && defined(CONFIG_PHYSICAL_ANTI_FRAGMENTATION) + __list_del_entry(&page->lru); + list_sort_add(page, zone, current_order, start_type); +#else area = &zone->free_area[current_order]; list_move(&page->lru, &area->free_list[start_type]); +#endif } /* @@ -2500,6 +2616,9 @@ static void reserve_highatomic_pageblock(struct page *page, struct zone *zone, /* Yoink! */ mt = get_pageblock_migratetype(page); if (!is_migrate_highatomic(mt) && !is_migrate_isolate(mt) +#if defined(OPLUS_FEATURE_MEMORY_ISOLATE) && defined(CONFIG_OPLUS_MEMORY_ISOLATE) + &&!is_migrate_oplus2(mt) +#endif /*OPLUS_FEATURE_MEMORY_ISOLATE*/ && !is_migrate_cma(mt)) { zone->nr_reserved_highatomic += pageblock_nr_pages; set_pageblock_migratetype(page, MIGRATE_HIGHATOMIC); @@ -2529,6 +2648,9 @@ static bool unreserve_highatomic_pageblock(const struct alloc_context *ac, struct page *page; int order; bool ret; +#if defined(OPLUS_FEATURE_MULTI_FREEAREA) && defined(CONFIG_PHYSICAL_ANTI_FRAGMENTATION) + int flc; +#endif for_each_zone_zonelist_nodemask(zone, z, zonelist, ac->high_zoneidx, ac->nodemask) { @@ -2541,8 +2663,15 @@ static bool unreserve_highatomic_pageblock(const struct alloc_context *ac, continue; spin_lock_irqsave(&zone->lock, flags); +#if defined(OPLUS_FEATURE_MULTI_FREEAREA) && defined(CONFIG_PHYSICAL_ANTI_FRAGMENTATION) + for (flc = 0; flc < FREE_AREA_COUNTS; flc++) { +#endif for (order = 0; order < MAX_ORDER; order++) { +#if defined(OPLUS_FEATURE_MULTI_FREEAREA) && defined(CONFIG_PHYSICAL_ANTI_FRAGMENTATION) + struct free_area *area = &(zone->free_area[flc][order]); +#else struct free_area *area = &(zone->free_area[order]); +#endif page = list_first_entry_or_null( &area->free_list[MIGRATE_HIGHATOMIC], @@ -2587,6 +2716,9 @@ static bool unreserve_highatomic_pageblock(const struct alloc_context *ac, return ret; } } +#if defined(OPLUS_FEATURE_MULTI_FREEAREA) && defined(CONFIG_PHYSICAL_ANTI_FRAGMENTATION) + } +#endif spin_unlock_irqrestore(&zone->lock, flags); } @@ -2613,6 +2745,9 @@ __rmqueue_fallback(struct zone *zone, int order, int start_migratetype, struct page *page; int fallback_mt; bool can_steal; +#if defined(OPLUS_FEATURE_MULTI_FREEAREA) && defined(CONFIG_PHYSICAL_ANTI_FRAGMENTATION) + unsigned int flc = 0, flc_tmp = 0; +#endif /* * Do not steal pages from freelists belonging to other pageblocks @@ -2627,9 +2762,17 @@ __rmqueue_fallback(struct zone *zone, int order, int start_migratetype, * approximates finding the pageblock with the most free pages, which * would be too costly to do exactly. */ +#if defined(OPLUS_FEATURE_MULTI_FREEAREA) && defined(CONFIG_PHYSICAL_ANTI_FRAGMENTATION) + for (flc = 0; flc < FREE_AREA_COUNTS; flc++) { + flc_tmp = ajust_flc(flc, order); +#endif for (current_order = MAX_ORDER - 1; current_order >= min_order; --current_order) { +#if defined(OPLUS_FEATURE_MULTI_FREEAREA) && defined(CONFIG_PHYSICAL_ANTI_FRAGMENTATION) + area = &(zone->free_area[flc_tmp][current_order]); +#else area = &(zone->free_area[current_order]); +#endif fallback_mt = find_suitable_fallback(area, current_order, start_migratetype, false, &can_steal); if (fallback_mt == -1) @@ -2649,18 +2792,35 @@ __rmqueue_fallback(struct zone *zone, int order, int start_migratetype, goto do_steal; } - +#if defined(OPLUS_FEATURE_MULTI_FREEAREA) && defined(CONFIG_PHYSICAL_ANTI_FRAGMENTATION) + } +#endif return false; find_smallest: +#if defined(OPLUS_FEATURE_MULTI_FREEAREA) && defined(CONFIG_PHYSICAL_ANTI_FRAGMENTATION) + for (flc = 0; flc < FREE_AREA_COUNTS; flc++) { + flc_tmp = ajust_flc(flc, order); +#endif for (current_order = order; current_order < MAX_ORDER; current_order++) { +#if defined(OPLUS_FEATURE_MULTI_FREEAREA) && defined(CONFIG_PHYSICAL_ANTI_FRAGMENTATION) + area = &(zone->free_area[flc_tmp][current_order]); +#else area = &(zone->free_area[current_order]); +#endif fallback_mt = find_suitable_fallback(area, current_order, start_migratetype, false, &can_steal); if (fallback_mt != -1) +#if defined(OPLUS_FEATURE_MULTI_FREEAREA) && defined(CONFIG_PHYSICAL_ANTI_FRAGMENTATION) + goto do_steal; +#else break; +#endif } +#if defined(OPLUS_FEATURE_MULTI_FREEAREA) && defined(CONFIG_PHYSICAL_ANTI_FRAGMENTATION) + } +#endif /* * This should not happen - we already found a suitable fallback @@ -2767,6 +2927,12 @@ static int rmqueue_bulk(struct zone *zone, unsigned int order, if (is_migrate_cma(get_pcppage_migratetype(page))) __mod_zone_page_state(zone, NR_FREE_CMA_PAGES, -(1 << order)); +#if defined(OPLUS_FEATURE_MEMORY_ISOLATE) && defined(CONFIG_OPLUS_MEMORY_ISOLATE) + if (is_migrate_oplus2(get_pcppage_migratetype(page))) + __mod_zone_page_state(zone, NR_FREE_OPLUS2_PAGES, + -(1 << order)); +#endif /* OPLUS_FEATURE_MEMORY_ISOLATE */ + } /* @@ -2983,6 +3149,9 @@ void mark_free_pages(struct zone *zone) unsigned long flags; unsigned int order, t; struct page *page; +#if defined(OPLUS_FEATURE_MULTI_FREEAREA) && defined(CONFIG_PHYSICAL_ANTI_FRAGMENTATION) + unsigned int flc; +#endif if (zone_is_empty(zone)) return; @@ -3007,8 +3176,14 @@ void mark_free_pages(struct zone *zone) } for_each_migratetype_order(order, t) { +#if defined(OPLUS_FEATURE_MULTI_FREEAREA) && defined(CONFIG_PHYSICAL_ANTI_FRAGMENTATION) + for (flc = 0; flc < FREE_AREA_COUNTS; flc++) { + list_for_each_entry(page, + &zone->free_areai[flc][order].free_list[t], lru) { +#else list_for_each_entry(page, &zone->free_area[order].free_list[t], lru) { +#endif unsigned long i; pfn = page_to_pfn(page); @@ -3020,6 +3195,9 @@ void mark_free_pages(struct zone *zone) swsusp_set_page_free(pfn_to_page(pfn + i)); } } +#if defined(OPLUS_FEATURE_MULTI_FREEAREA) && defined(CONFIG_PHYSICAL_ANTI_FRAGMENTATION) + } +#endif } spin_unlock_irqrestore(&zone->lock, flags); } @@ -3150,6 +3328,9 @@ int __isolate_free_page(struct page *page, unsigned int order) unsigned long watermark; struct zone *zone; int mt; +#if defined(OPLUS_FEATURE_MULTI_FREEAREA) && defined(CONFIG_PHYSICAL_ANTI_FRAGMENTATION) + unsigned int flc; +#endif BUG_ON(!PageBuddy(page)); @@ -3172,7 +3353,13 @@ int __isolate_free_page(struct page *page, unsigned int order) /* Remove page from free list */ list_del(&page->lru); +#if defined(OPLUS_FEATURE_MULTI_FREEAREA) && defined(CONFIG_PHYSICAL_ANTI_FRAGMENTATION) + flc = page_to_flc(page); + zone->free_area[flc][order].nr_free--; +#else zone->free_area[order].nr_free--; +#endif + rmv_page_order(page); /* @@ -3184,6 +3371,9 @@ int __isolate_free_page(struct page *page, unsigned int order) for (; page < endpage; page += pageblock_nr_pages) { int mt = get_pageblock_migratetype(page); if (!is_migrate_isolate(mt) && !is_migrate_cma(mt) +#if defined(OPLUS_FEATURE_MEMORY_ISOLATE) && defined(CONFIG_OPLUS_MEMORY_ISOLATE) + && !is_migrate_oplus2(mt) +#endif /*OPLUS_FEATURE_MEMORY_ISOLATE*/ && !is_migrate_highatomic(mt)) set_pageblock_migratetype(page, MIGRATE_MOVABLE); @@ -3319,9 +3509,18 @@ struct page *rmqueue(struct zone *preferred_zone, gfp_flags & __GFP_CMA) page = __rmqueue_cma(zone, order); +#if defined(OPLUS_FEATURE_MEMORY_ISOLATE) && defined(CONFIG_OPLUS_MEMORY_ISOLATE) + if (!page && is_oplus2_order(order)) + page = __rmqueue_smallest(zone, order, MIGRATE_OPLUS2); +#endif /* OPLUS_FEATURE_MEMORY_ISOLATE */ + if (!page) page = __rmqueue(zone, order, migratetype, alloc_flags); } while (page && check_new_pages(page, order)); +#if defined(OPLUS_FEATURE_MEMORY_ISOLATE) && defined(CONFIG_OPLUS_MEMORY_ISOLATE) + if (!page && is_oplus2_order(order)) + page = __rmqueue_smallest(zone, order, MIGRATE_HIGHATOMIC); +#endif /* OPLUS_FEATURE_MEMORY_ISOLATE */ spin_unlock(&zone->lock); if (!page) @@ -3331,6 +3530,8 @@ struct page *rmqueue(struct zone *preferred_zone, __count_zid_vm_events(PGALLOC, page_zonenum(page), 1 << order); zone_statistics(preferred_zone, zone); + trace_android_vh_rmqueue(preferred_zone, zone, order, + gfp_flags, alloc_flags, migratetype); local_irq_restore(flags); out: @@ -3462,6 +3663,9 @@ bool __zone_watermark_ok(struct zone *z, unsigned int order, unsigned long mark, long min = mark; int o; const bool alloc_harder = (alloc_flags & (ALLOC_HARDER|ALLOC_OOM)); +#if defined(OPLUS_FEATURE_MULTI_FREEAREA) && defined(CONFIG_PHYSICAL_ANTI_FRAGMENTATION) + int flc; +#endif /* free_pages may go negative - that's OK */ free_pages -= __zone_watermark_unusable_free(z, order, alloc_flags); @@ -3479,9 +3683,28 @@ bool __zone_watermark_ok(struct zone *z, unsigned int order, unsigned long mark, if (alloc_flags & ALLOC_OOM) min -= min / 2; else +#if defined(OPLUS_FEATURE_MEMORY_ISOLATE) && defined(CONFIG_OPLUS_MEMORY_ISOLATE) +/* + * ALLOC_HIGH:ALLOC_HARDER is about 1:10, so more for ALLOC_HARDER + * and since 2-order might allocate from MIGRATE_HIGHATOMIC as fallback, + * so here should make it easier for ALLOC_HARDER. + * after this change, kswapd might reclaim a bit more, which is what we want. + */ + min -= min / 4 + min / 8; +#else min -= min / 4; +#endif /*OPLUS_FEATURE_MEMORY_ISOLATE*/ + } +#if defined(OPLUS_FEATURE_MEMORY_ISOLATE) && defined(CONFIG_OPLUS_MEMORY_ISOLATE) +/* + * Not OPLUS2_ORDER allocation cannot use MIGRATE_OPLUS + */ + if (!is_oplus2_order(order)) + free_pages -= zone_page_state(z, NR_FREE_OPLUS2_PAGES); +#endif /* OPLUS_FEATURE_MEMORY_ISOLATE */ + /* * Check watermarks for an order-0 allocation request. If these * are not met, then a high-order request also cannot go ahead @@ -3495,12 +3718,23 @@ bool __zone_watermark_ok(struct zone *z, unsigned int order, unsigned long mark, return true; /* For a high-order request, check at least one suitable page is free */ +#if defined(OPLUS_FEATURE_MULTI_FREEAREA) && defined(CONFIG_PHYSICAL_ANTI_FRAGMENTATION) + for (flc = 0; flc < FREE_AREA_COUNTS; flc++) { +#endif for (o = order; o < MAX_ORDER; o++) { +#if defined(OPLUS_FEATURE_MULTI_FREEAREA) && defined(CONFIG_PHYSICAL_ANTI_FRAGMENTATION) + struct free_area *area = &z->free_area[flc][o]; +#else struct free_area *area = &z->free_area[o]; +#endif int mt; if (!area->nr_free) continue; +#if defined(OPLUS_FEATURE_MEMORY_ISOLATE) && defined(CONFIG_OPLUS_MEMORY_ISOLATE) + if (is_oplus2_order(order) && !list_empty(&area->free_list[MIGRATE_OPLUS2])) + return true; +#endif /* OPLUS_FEATURE_MEMORY_ISOLATE */ for (mt = 0; mt < MIGRATE_PCPTYPES; mt++) { #ifdef CONFIG_CMA @@ -3514,6 +3748,13 @@ bool __zone_watermark_ok(struct zone *z, unsigned int order, unsigned long mark, if (!list_empty(&area->free_list[mt])) return true; } +#if defined(OPLUS_FEATURE_MEMORY_ISOLATE) && defined(CONFIG_OPLUS_MEMORY_ISOLATE) +/* + * OPLUS2_ORDER could allocate from MIGRATE_HIGHATOMIC as last resert + */ + if (is_oplus2_order(order) && !list_empty(&area->free_list[MIGRATE_HIGHATOMIC])) + return true; +#endif /* OPLUS_FEATURE_MEMORY_ISOLATE */ #ifdef CONFIG_CMA if ((alloc_flags & ALLOC_CMA) && @@ -3525,6 +3766,9 @@ bool __zone_watermark_ok(struct zone *z, unsigned int order, unsigned long mark, !list_empty(&area->free_list[MIGRATE_HIGHATOMIC])) return true; } +#if defined(OPLUS_FEATURE_MULTI_FREEAREA) && defined(CONFIG_PHYSICAL_ANTI_FRAGMENTATION) + } +#endif return false; } @@ -4252,7 +4496,7 @@ static int __perform_reclaim(gfp_t gfp_mask, unsigned int order, const struct alloc_context *ac) { - struct reclaim_state reclaim_state; + struct reclaim_state reclaim_state = {}; int progress; unsigned int noreclaim_flag; unsigned long pflags; @@ -4562,13 +4806,22 @@ __alloc_pages_slowpath(gfp_t gfp_mask, unsigned int order, unsigned int cpuset_mems_cookie; unsigned int zonelist_iter_cookie; int reserve_flags; - +#ifdef OPLUS_FEATURE_HEALTHINFO +#ifdef CONFIG_OPLUS_MEM_MONITOR + unsigned long oplus_alloc_start = jiffies; +#endif +#endif /* OPLUS_FEATURE_HEALTHINFO */ /* * We also sanity check to catch abuse of atomic reserves being used by * callers that are not in atomic context. */ if (WARN_ON_ONCE((gfp_mask & (__GFP_ATOMIC|__GFP_DIRECT_RECLAIM)) == +#ifdef OPLUS_FEATURE_PERFORMANCE + (__GFP_ATOMIC|__GFP_DIRECT_RECLAIM)) && + !(gfp_mask & ___GFP_HIGH_ATOMIC_ZRAM)) +#else (__GFP_ATOMIC|__GFP_DIRECT_RECLAIM))) +#endif gfp_mask &= ~__GFP_ATOMIC; restart: @@ -4810,6 +5063,12 @@ fail: warn_alloc(gfp_mask, ac->nodemask, "page allocation failure: order:%u", order); got_pg: +#ifdef OPLUS_FEATURE_HEALTHINFO +#ifdef CONFIG_OPLUS_MEM_MONITOR + memory_alloc_monitor(gfp_mask, order, jiffies_to_msecs(jiffies - oplus_alloc_start)); + trace_android_vh_alloc_pages_slowpath(gfp_mask, order, oplus_alloc_start); +#endif +#endif /* OPLUS_FEATURE_HEALTHINFO */ return page; } @@ -5362,6 +5621,10 @@ static void show_migration_types(unsigned char type) #ifdef CONFIG_CMA [MIGRATE_CMA] = 'C', #endif +#if defined(OPLUS_FEATURE_MEMORY_ISOLATE) && defined(CONFIG_OPLUS_MEMORY_ISOLATE) + [MIGRATE_OPLUS2] = 'P', +#endif /* OPLUS_FEATURE_MEMORY_ISOLATE */ + #ifdef CONFIG_MEMORY_ISOLATION [MIGRATE_ISOLATE] = 'I', #endif @@ -5394,6 +5657,9 @@ void show_free_areas(unsigned int filter, nodemask_t *nodemask) int cpu; struct zone *zone; pg_data_t *pgdat; +#if defined(OPLUS_FEATURE_MULTI_FREEAREA) && defined(CONFIG_PHYSICAL_ANTI_FRAGMENTATION) + int flc = 0; +#endif for_each_populated_zone(zone) { if (show_mem_node_skip(filter, zone_to_nid(zone), nodemask)) @@ -5545,7 +5811,11 @@ void show_free_areas(unsigned int filter, nodemask_t *nodemask) for_each_populated_zone(zone) { unsigned int order; +#if defined(OPLUS_FEATURE_MULTI_FREEAREA) && defined(CONFIG_PHYSICAL_ANTI_FRAGMENTATION) + unsigned long nr[FREE_AREA_COUNTS][MAX_ORDER], flags, total = 0; +#else unsigned long nr[MAX_ORDER], flags, total = 0; +#endif unsigned char types[MAX_ORDER]; if (show_mem_node_skip(filter, zone_to_nid(zone), nodemask)) @@ -5554,26 +5824,51 @@ void show_free_areas(unsigned int filter, nodemask_t *nodemask) printk(KERN_CONT "%s: ", zone->name); spin_lock_irqsave(&zone->lock, flags); +#if defined(OPLUS_FEATURE_MULTI_FREEAREA) && defined(CONFIG_PHYSICAL_ANTI_FRAGMENTATION) + for (flc = 0 ; flc < FREE_AREA_COUNTS; flc++) { +#endif for (order = 0; order < MAX_ORDER; order++) { - struct free_area *area = &zone->free_area[order]; +#if defined(OPLUS_FEATURE_MULTI_FREEAREA) && defined(CONFIG_PHYSICAL_ANTI_FRAGMENTATION) + struct free_area *area = &zone->free_area[flc][order]; +#else + struct free_area *area = &zone->free_area[order]; +#endif int type; - nr[order] = area->nr_free; +#if defined(OPLUS_FEATURE_MULTI_FREEAREA) && defined(CONFIG_PHYSICAL_ANTI_FRAGMENTATION) + nr[flc][order] = area->nr_free; + total += nr[flc][order] << order; +#else + nr[order] = area->nr_free; total += nr[order] << order; - +#endif types[order] = 0; for (type = 0; type < MIGRATE_TYPES; type++) { if (!list_empty(&area->free_list[type])) types[order] |= 1 << type; } } +#if defined(OPLUS_FEATURE_MULTI_FREEAREA) && defined(CONFIG_PHYSICAL_ANTI_FRAGMENTATION) + } +#endif spin_unlock_irqrestore(&zone->lock, flags); +#if defined(OPLUS_FEATURE_MULTI_FREEAREA) && defined(CONFIG_PHYSICAL_ANTI_FRAGMENTATION) + for (flc = 0 ; flc < FREE_AREA_COUNTS; flc++) { +#endif for (order = 0; order < MAX_ORDER; order++) { printk(KERN_CONT "%lu*%lukB ", - nr[order], K(1UL) << order); - if (nr[order]) +#if defined(OPLUS_FEATURE_MULTI_FREEAREA) && defined(CONFIG_PHYSICAL_ANTI_FRAGMENTATION) + nr[flc][order], K(1UL) << order); + if (nr[flc][order]) +#else + nr[order], K(1UL) << order); + if (nr[order]) +#endif show_migration_types(types[order]); } +#if defined(OPLUS_FEATURE_MULTI_FREEAREA) && defined(CONFIG_PHYSICAL_ANTI_FRAGMENTATION) + } +#endif printk(KERN_CONT "= %lukB\n", K(total)); } @@ -6088,10 +6383,21 @@ not_early: static void __meminit zone_init_free_lists(struct zone *zone) { unsigned int order, t; +#if defined(OPLUS_FEATURE_MULTI_FREEAREA) && defined(CONFIG_PHYSICAL_ANTI_FRAGMENTATION) + int flc; + + for (flc = 0; flc < FREE_AREA_COUNTS; flc++) { + for_each_migratetype_order(order, t) { + INIT_LIST_HEAD(&zone->free_area[flc][order].free_list[t]); + zone->free_area[flc][order].nr_free = 0; + } + } +#else for_each_migratetype_order(order, t) { INIT_LIST_HEAD(&zone->free_area[order].free_list[t]); zone->free_area[order].nr_free = 0; } +#endif } #ifndef __HAVE_ARCH_MEMMAP_INIT @@ -6877,6 +7183,10 @@ static void __init free_area_init_core(struct pglist_data *pgdat) set_pageblock_order(); setup_usemap(pgdat, zone, zone_start_pfn, size); init_currently_empty_zone(zone, zone_start_pfn, size); +#if defined(OPLUS_FEATURE_MULTI_FREEAREA) && defined(CONFIG_PHYSICAL_ANTI_FRAGMENTATION) + ajust_zone_label(zone); +#endif + memmap_init(size, nid, j, zone_start_pfn); } } @@ -7861,6 +8171,9 @@ static void __setup_per_zone_wmarks(void) low + min; zone->_watermark[WMARK_HIGH] = min_wmark_pages(zone) + low + min * 2; +#if defined(OPLUS_FEATURE_MEMORY_ISOLATE) && defined(CONFIG_OPLUS_MEMORY_ISOLATE) + setup_zone_migrate_oplus(zone, MIGRATE_OPLUS2); +#endif /* OPLUS_FEATURE_MEMORY_ISOLATE */ spin_unlock_irqrestore(&zone->lock, flags); } @@ -7975,21 +8288,6 @@ int watermark_boost_factor_sysctl_handler(struct ctl_table *table, int write, return 0; } -int kswapd_threads_sysctl_handler(struct ctl_table *table, int write, - void __user *buffer, size_t *length, loff_t *ppos) -{ - int rc; - - rc = proc_dointvec_minmax(table, write, buffer, length, ppos); - if (rc) - return rc; - - if (write) - update_kswapd_threads(); - - return 0; -} - int watermark_scale_factor_sysctl_handler(struct ctl_table *table, int write, void __user *buffer, size_t *length, loff_t *ppos) { @@ -8666,6 +8964,9 @@ __offline_isolated_pages(unsigned long start_pfn, unsigned long end_pfn) unsigned int order, i; unsigned long pfn; unsigned long flags; +#if defined(OPLUS_FEATURE_MULTI_FREEAREA) && defined(CONFIG_PHYSICAL_ANTI_FRAGMENTATION) + unsigned int flc; +#endif /* find the first valid pfn */ for (pfn = start_pfn; pfn < end_pfn; pfn++) if (pfn_valid(pfn)) @@ -8701,7 +9002,12 @@ __offline_isolated_pages(unsigned long start_pfn, unsigned long end_pfn) #endif list_del(&page->lru); rmv_page_order(page); +#if defined(OPLUS_FEATURE_MULTI_FREEAREA) && defined(CONFIG_PHYSICAL_ANTI_FRAGMENTATION) + flc = page_to_flc(page); + zone->free_area[flc][order].nr_free--; +#else zone->free_area[order].nr_free--; +#endif for (i = 0; i < (1 << order); i++) SetPageReserved((page+i)); pfn += (1 << order); diff --git a/mm/page_ext.c b/mm/page_ext.c index 9e7f56e45b5a..f044a2b09dc5 100644 --- a/mm/page_ext.c +++ b/mm/page_ext.c @@ -58,6 +58,16 @@ * can utilize this callback to initialize the state of it correctly. */ +#if defined(CONFIG_PAGE_IDLE_FLAG) && !defined(CONFIG_64BIT) +static bool need_page_idle(void) +{ + return true; +} +struct page_ext_operations page_idle_ops = { + .need = need_page_idle, +}; +#endif + static struct page_ext_operations *page_ext_ops[] = { #ifdef CONFIG_DEBUG_PAGEALLOC &debug_guardpage_ops, @@ -65,7 +75,7 @@ static struct page_ext_operations *page_ext_ops[] = { #ifdef CONFIG_PAGE_OWNER &page_owner_ops, #endif -#if defined(CONFIG_IDLE_PAGE_TRACKING) && !defined(CONFIG_64BIT) +#if defined(CONFIG_PAGE_IDLE_FLAG) && !defined(CONFIG_64BIT) &page_idle_ops, #endif }; diff --git a/mm/page_idle.c b/mm/page_idle.c index 52ed59bbc275..a26eb3b218fa 100644 --- a/mm/page_idle.c +++ b/mm/page_idle.c @@ -214,16 +214,6 @@ static const struct attribute_group page_idle_attr_group = { .name = "page_idle", }; -#ifndef CONFIG_64BIT -static bool need_page_idle(void) -{ - return true; -} -struct page_ext_operations page_idle_ops = { - .need = need_page_idle, -}; -#endif - static int __init page_idle_init(void) { int err; diff --git a/mm/pagewalk.c b/mm/pagewalk.c index 3c0930d94a29..bec758e07569 100644 --- a/mm/pagewalk.c +++ b/mm/pagewalk.c @@ -131,6 +131,11 @@ static int walk_p4d_range(pgd_t *pgd, unsigned long addr, unsigned long end, break; continue; } + if (walk->p4d_entry) { + err = walk->p4d_entry(p4d, addr, next, walk); + if (err) + break; + } if (walk->pmd_entry || walk->pte_entry) err = walk_pud_range(p4d, addr, next, walk); if (err) @@ -157,7 +162,7 @@ static int walk_pgd_range(unsigned long addr, unsigned long end, break; continue; } - if (walk->pmd_entry || walk->pte_entry) + if (walk->p4d_entry || walk->pmd_entry || walk->pte_entry) err = walk_p4d_range(pgd, addr, next, walk); if (err) break; diff --git a/mm/process_mm_reclaim.c b/mm/process_mm_reclaim.c new file mode 120000 index 000000000000..8d509a3acb02 --- /dev/null +++ b/mm/process_mm_reclaim.c @@ -0,0 +1 @@ +../../../vendor/oplus/kernel/oplus_performance/process_reclaim/process_mm_reclaim.c \ No newline at end of file diff --git a/mm/process_mm_reclaim_weak.c b/mm/process_mm_reclaim_weak.c new file mode 120000 index 000000000000..e126aef9e1fd --- /dev/null +++ b/mm/process_mm_reclaim_weak.c @@ -0,0 +1 @@ +../../../vendor/oplus/kernel/oplus_performance/process_reclaim/process_mm_reclaim_weak.c \ No newline at end of file diff --git a/mm/reserve_area.c b/mm/reserve_area.c new file mode 120000 index 000000000000..49f2e044b9a4 --- /dev/null +++ b/mm/reserve_area.c @@ -0,0 +1 @@ +../../../vendor/oplus/kernel/oplus_performance/gloom_new/reserve_area.c \ No newline at end of file diff --git a/mm/rmap.c b/mm/rmap.c index 1ddb8f4de0ae..a038477eedc3 100644 --- a/mm/rmap.c +++ b/mm/rmap.c @@ -65,6 +65,7 @@ #include #include #include +#include #include @@ -307,6 +308,73 @@ int anon_vma_clone(struct vm_area_struct *dst, struct vm_area_struct *src) return -ENOMEM; } +#ifdef OPLUS_BUG_STABILITY +#define RECURSIVE_MAX_FORK_TIME 30 + +/* + * Attach the anon_vmas from src to dst. + * Returns length of anon_vma_chain on success, -ENOMEM on failure. + * + * If dst->anon_vma is NULL this function tries to find and reuse existing + * anon_vma which has no vmas and only one child anon_vma. This prevents + * degradation of anon_vma hierarchy to endless linear chain in case of + * constantly forking task. On the other hand, an anon_vma with more than one + * child isn't reused even if there was no alive vma, thus rmap walker has a + * good chance of avoiding scanning the whole hierarchy when it searches where + * page is mapped. + */ +int anon_vma_clone_oplus(struct vm_area_struct *dst, struct vm_area_struct *src) +{ + struct anon_vma_chain *avc, *pavc; + struct anon_vma *root = NULL; + int length = 0; + + list_for_each_entry_reverse(pavc, &src->anon_vma_chain, same_vma) { + struct anon_vma *anon_vma; + + avc = anon_vma_chain_alloc(GFP_NOWAIT | __GFP_NOWARN); + if (unlikely(!avc)) { + unlock_anon_vma_root(root); + root = NULL; + avc = anon_vma_chain_alloc(GFP_KERNEL); + if (!avc) + goto enomem_failure; + } + anon_vma = pavc->anon_vma; + root = lock_anon_vma_root(root, anon_vma); + anon_vma_chain_link(dst, avc, anon_vma); + length++; + + /* + * Reuse existing anon_vma if its degree lower than two, + * that means it has no vma and only one anon_vma child. + * + * Do not chose parent anon_vma, otherwise first child + * will always reuse it. Root anon_vma is never reused: + * it has self-parent reference and at least one child. + */ + if (!dst->anon_vma && anon_vma != src->anon_vma && + anon_vma->degree < 2) + dst->anon_vma = anon_vma; + } + if (dst->anon_vma) + dst->anon_vma->degree++; + unlock_anon_vma_root(root); + return length; + + enomem_failure: + /* + * dst->anon_vma is dropped here otherwise its degree can be incorrectly + * decremented in unlink_anon_vmas(). + * We can safely do this because callers of anon_vma_clone() don't care + * about dst->anon_vma if anon_vma_clone() failed. + */ + dst->anon_vma = NULL; + unlink_anon_vmas(dst); + return -ENOMEM; +} +#endif + /* * Attach vma to its own anon_vma, as well as to the anon_vmas that * the corresponding VMA in the parent process is attached to. @@ -329,9 +397,19 @@ int anon_vma_fork(struct vm_area_struct *vma, struct vm_area_struct *pvma) * First, attach the new VMA to the parent VMA's anon_vmas, * so rmap can find non-COWed pages in child processes. */ + #ifdef OPLUS_BUG_STABILITY + error = anon_vma_clone_oplus(vma, pvma); + if (error < 0) + return error; + else if (error > RECURSIVE_MAX_FORK_TIME) { + pr_err("[anon_vma_fork]%d: recursive fork more then 30 timges, pid is %d[%s]\n", __LINE__, get_current()->pid, get_current()->comm); + return -ENOMEM; + } + #else error = anon_vma_clone(vma, pvma); if (error) return error; + #endif /* An existing anon_vma has been reused, all done then. */ if (vma->anon_vma) @@ -768,6 +846,12 @@ static bool page_referenced_one(struct page *page, struct vm_area_struct *vma, } if (pvmw.pte) { + if (lru_gen_enabled() && pte_young(*pvmw.pte) && + !(vma->vm_flags & (VM_SEQ_READ | VM_RAND_READ))) { + lru_gen_look_around(&pvmw); + referenced++; + } + if (ptep_clear_flush_young_notify(vma, address, pvmw.pte)) { /* diff --git a/mm/slab.h b/mm/slab.h index 77a1a26f2001..922db9bd0bba 100644 --- a/mm/slab.h +++ b/mm/slab.h @@ -136,6 +136,9 @@ static inline slab_flags_t kmem_cache_flags(unsigned int object_size, #elif defined(CONFIG_SLUB_DEBUG) #define SLAB_DEBUG_FLAGS (SLAB_RED_ZONE | SLAB_POISON | SLAB_STORE_USER | \ SLAB_TRACE | SLAB_CONSISTENCY_CHECKS) +#elif defined(OPLUS_FEATURE_MEMLEAK_DETECT) && defined(CONFIG_KMALLOC_DEBUG) +/* create kmalloc cache with sotre user. */ +#define SLAB_DEBUG_FLAGS (SLAB_STORE_USER) #else #define SLAB_DEBUG_FLAGS (0) #endif diff --git a/mm/slab_common.c b/mm/slab_common.c index 0d8d00bbd5cd..3b6061ec2026 100644 --- a/mm/slab_common.c +++ b/mm/slab_common.c @@ -1069,6 +1069,18 @@ struct kmem_cache *kmalloc_slab(size_t size, gfp_t flags) index = fls(size - 1); } +#if defined(OPLUS_FEATURE_MEMLEAK_DETECT) && defined(CONFIG_KMALLOC_DEBUG) + /* try to kmalloc from kmalloc_debug + * caches fisrt. + */ + if (unlikely(kmalloc_debug_enable)) { + struct kmem_cache *s; + + s = (struct kmem_cache *)atomic64_read(&kmalloc_debug_caches[kmalloc_type(flags)][index]); + if (unlikely(s)) + return s; + } +#endif return kmalloc_caches[kmalloc_type(flags)][index]; } @@ -1171,8 +1183,13 @@ new_kmalloc_cache(int idx, int type, slab_flags_t flags) } kmalloc_caches[type][idx] = create_kmalloc_cache(name, +#if defined(CONFIG_OPLUS_FEATURE_SLABTRACE_DEBUG) + kmalloc_info[idx].size, flags|SLAB_STORE_USER, 0, +#else kmalloc_info[idx].size, flags, 0, +#endif kmalloc_info[idx].size); + } /* @@ -1324,6 +1341,12 @@ static void print_slabinfo_header(struct seq_file *m) seq_puts(m, " : globalstat "); seq_puts(m, " : cpustat "); #endif +#ifdef OPLUS_FEATURE_HEALTHINFO + /* if SLAB_STAT_DEBUG is enabled, + * /proc/slabinfo is created for getting more slab details. + */ + seq_puts(m, " "); +#endif /* OPLUS_FEATURE_HEALTHINFO */ seq_putc(m, '\n'); } @@ -1379,8 +1402,17 @@ static void cache_show(struct kmem_cache *s, struct seq_file *m) seq_printf(m, " : tunables %4u %4u %4u", sinfo.limit, sinfo.batchcount, sinfo.shared); +#ifndef OPLUS_FEATURE_HEALTHINFO + /* if SLAB_STAT_DEBUG is enabled, + * /proc/slabinfo is created for getting more slab details. + */ seq_printf(m, " : slabdata %6lu %6lu %6lu", sinfo.active_slabs, sinfo.num_slabs, sinfo.shared_avail); +#else /* OPLUS_FEATURE_HEALTHINFO */ + seq_printf(m, " : slabdata %6lu %6lu %6lu %1d", + sinfo.active_slabs, sinfo.num_slabs, sinfo.shared_avail, + ((s->flags & SLAB_RECLAIM_ACCOUNT) == SLAB_RECLAIM_ACCOUNT) ? 1: 0); +#endif /* OPLUS_FEATURE_HEALTHINFO */ slabinfo_show_stats(m, s); seq_putc(m, '\n'); } diff --git a/mm/slub.c b/mm/slub.c index 32d0de2a651a..315e8afd33f3 100644 --- a/mm/slub.c +++ b/mm/slub.c @@ -35,6 +35,10 @@ #include #include #include +#if defined(OPLUS_FEATURE_MEMLEAK_DETECT) && defined(CONFIG_KMALLOC_DEBUG) +/* calc the stack hash */ +#include +#endif #include @@ -43,6 +47,17 @@ #endif #include "internal.h" +/* Enalbe slabtrace: + * CONFIG_OPLUS_FEATURE_SLABTRACE_DEBUG=y + * Get more info disable Randomize_base + * CONFIG_RANDOMIZE_BASE=n + * after add the config, cat /proc/slabtrace to get slab userinfo + */ +#if defined(CONFIG_OPLUS_FEATURE_SLABTRACE_DEBUG) +#ifndef CONFIG_RANDOMIZE_BASE +#define COMPACT_OPLUS_SLUB_TRACK +#endif +#endif /* * Lock order: @@ -204,11 +219,30 @@ static inline bool kmem_cache_has_cpu_partial(struct kmem_cache *s) /* * Tracking user of a slab. */ +#if defined(OPLUS_FEATURE_MEMLEAK_DETECT) && defined(CONFIG_KMALLOC_DEBUG) && !defined(CONFIG_MEMLEAK_DETECT_THREAD) +/* set kmalloc_debug tack stack depth. + */ +#define TRACK_ADDRS_COUNT 12 +#else #define TRACK_ADDRS_COUNT 16 +#endif struct track { unsigned long addr; /* Called from address */ #ifdef CONFIG_STACKTRACE +#if defined(COMPACT_OPLUS_SLUB_TRACK) +/* Store the offset after MODULES_VADDR for + * kernel module and kernel text address + */ + u32 addrs[TRACK_ADDRS_COUNT]; +#else unsigned long addrs[TRACK_ADDRS_COUNT]; /* Called from address */ +#endif +#if defined(OPLUS_FEATURE_MEMLEAK_DETECT) && defined(CONFIG_KMALLOC_DEBUG) + /* save the stack depth and hash. + */ + u32 depth; + u32 hash; +#endif #endif int cpu; /* Was running on cpu */ int pid; /* Pid context */ @@ -451,7 +485,12 @@ static inline bool cmpxchg_double_slab(struct kmem_cache *s, struct page *page, * Node listlock must be held to guarantee that the page does * not vanish from under us. */ -static void get_map(struct kmem_cache *s, struct page *page, unsigned long *map) +#if defined(CONFIG_OPLUS_FEATURE_SLABTRACE_DEBUG) +void +#else +static void +#endif +get_map(struct kmem_cache *s, struct page *page, unsigned long *map) { void *p; void *addr = page_address(page); @@ -459,7 +498,9 @@ static void get_map(struct kmem_cache *s, struct page *page, unsigned long *map) for (p = page->freelist; p; p = get_freepointer(s, p)) set_bit(slab_index(p, s, addr), map); } - +#if defined(CONFIG_OPLUS_FEATURE_SLABTRACE_DEBUG) +EXPORT_SYMBOL(get_map); +#endif static inline unsigned int size_from_object(struct kmem_cache *s) { if (s->flags & SLAB_RED_ZONE) @@ -557,6 +598,34 @@ static void set_track(struct kmem_cache *s, void *object, if (addr) { #ifdef CONFIG_STACKTRACE +#if defined(COMPACT_OPLUS_SLUB_TRACK) + unsigned long addrs[TRACK_ADDRS_COUNT]; + struct stack_trace trace; + int i; + + memset(addrs, 0, sizeof(addrs)); + trace.nr_entries = 0; + trace.max_entries = TRACK_ADDRS_COUNT; + + trace.entries = addrs; + trace.skip = 3; + save_stack_trace(&trace); + + /* See rant in lockdep.c */ + if (trace.nr_entries != 0 && + trace.entries[trace.nr_entries - 1] == ULONG_MAX) + trace.nr_entries--; + + for (i = trace.nr_entries; i < TRACK_ADDRS_COUNT; i++) + addrs[i] = 0; + + for (i = 0; i < TRACK_ADDRS_COUNT; i++) { + if (addrs[i]) + p->addrs[i] = addrs[i] - MODULES_VADDR; + else + p->addrs[i] = 0; + } +#else struct stack_trace trace; int i; @@ -575,6 +644,16 @@ static void set_track(struct kmem_cache *s, void *object, for (i = trace.nr_entries; i < TRACK_ADDRS_COUNT; i++) p->addrs[i] = 0; +#endif +#if defined(OPLUS_FEATURE_MEMLEAK_DETECT) && defined(CONFIG_KMALLOC_DEBUG) + /* save the stack depth + * and hash. + */ + p->depth = trace.nr_entries; + p->hash = jhash2((u32 *)p->addrs, + sizeof(p->addrs[0])/sizeof(u32)*trace.nr_entries, + 0xabcd); +#endif #endif p->addr = addr; p->cpu = smp_processor_id(); @@ -589,7 +668,11 @@ static void init_tracking(struct kmem_cache *s, void *object) if (!(s->flags & SLAB_STORE_USER)) return; +#if !defined(OPLUS_FEATURE_MEMLEAK_DETECT) || !defined(CONFIG_KMALLOC_DEBUG) || defined(CONFIG_SLUB_DEBUG_ON) || defined(CONFIG_OPLUS_FEATURE_SLABTRACE_DEBUG) + /* only record alloc stack. + */ set_track(s, object, TRACK_FREE, 0UL); +#endif set_track(s, object, TRACK_ALLOC, 0UL); } @@ -601,6 +684,28 @@ static void print_track(const char *s, struct track *t, unsigned long pr_time) pr_err("INFO: %s in %pS age=%lu cpu=%u pid=%d\n", s, (void *)t->addr, pr_time - t->when, t->cpu, t->pid); #ifdef CONFIG_STACKTRACE +#if defined(COMPACT_OPLUS_SLUB_TRACK) + { + int i; + unsigned long addrs[TRACK_ADDRS_COUNT]; + + /* we store the offset after MODULES_VADDR for + * kernel module and kernel text address + */ + for (i = 0; i < TRACK_ADDRS_COUNT; i++) { + if (t->addrs[i]) + addrs[i] = MODULES_VADDR + t->addrs[i]; + else + addrs[i] = 0; + } + for (i = 0; i < TRACK_ADDRS_COUNT; i++) { + if (addrs[i]) + pr_err("\t%pS\n", (void *)addrs[i]); + else + break; + } + } +#else { int i; for (i = 0; i < TRACK_ADDRS_COUNT; i++) @@ -610,6 +715,7 @@ static void print_track(const char *s, struct track *t, unsigned long pr_time) break; } #endif +#endif } static void print_tracking(struct kmem_cache *s, void *object) @@ -619,7 +725,11 @@ static void print_tracking(struct kmem_cache *s, void *object) return; print_track("Allocated", get_track(s, object, TRACK_ALLOC), pr_time); +#if !defined(OPLUS_FEATURE_MEMLEAK_DETECT) || !defined(CONFIG_KMALLOC_DEBUG) || defined(CONFIG_SLUB_DEBUG_ON) || defined(CONFIG_OPLUS_FEATURE_SLABTRACE_DEBUG) + /* only record alloc stack. + */ print_track("Freed", get_track(s, object, TRACK_FREE), pr_time); +#endif } static void print_page_info(struct page *page) @@ -700,8 +810,13 @@ static void print_trailer(struct kmem_cache *s, struct page *page, u8 *p) else off = s->inuse; +#if !defined(OPLUS_FEATURE_MEMLEAK_DETECT) || !defined(CONFIG_KMALLOC_DEBUG) || defined(CONFIG_SLUB_DEBUG_ON) || defined(CONFIG_OPLUS_FEATURE_SLABTRACE_DEBUG) if (s->flags & SLAB_STORE_USER) off += 2 * sizeof(struct track); +#else + if (s->flags & SLAB_STORE_USER) + off += sizeof(struct track); +#endif off += kasan_metadata_size(s); @@ -841,9 +956,15 @@ static int check_pad_bytes(struct kmem_cache *s, struct page *page, u8 *p) /* Freepointer is placed after the object. */ off += sizeof(void *); +#if !defined(OPLUS_FEATURE_MEMLEAK_DETECT) || !defined(CONFIG_KMALLOC_DEBUG) || defined(CONFIG_SLUB_DEBUG_ON) || defined(CONFIG_OPLUS_FEATURE_SLABTRACE_DEBUG) if (s->flags & SLAB_STORE_USER) /* We also have user information there */ off += 2 * sizeof(struct track); +#else + if (s->flags & SLAB_STORE_USER) + /* We also have user information there */ + off += sizeof(struct track); +#endif off += kasan_metadata_size(s); @@ -1231,8 +1352,12 @@ next_object: goto out; } +#if !defined(OPLUS_FEATURE_MEMLEAK_DETECT) || !defined(CONFIG_KMALLOC_DEBUG) || defined(CONFIG_SLUB_DEBUG_ON) || defined(CONFIG_OPLUS_FEATURE_SLABTRACE_DEBUG) + /* only record alloc stack. + */ if (s->flags & SLAB_STORE_USER) set_track(s, object, TRACK_FREE, addr); +#endif trace(s, page, object, 0); /* Freepointer not overwritten by init_object(), SLAB_POISON moved it */ init_object(s, object, SLUB_RED_INACTIVE); @@ -2399,11 +2524,18 @@ static bool has_cpu_slab(int cpu, void *info) return c->page || slub_percpu_partial(c); } -static void flush_all(struct kmem_cache *s) +#if defined(CONFIG_OPLUS_FEATURE_SLABTRACE_DEBUG) +void +#else +static void +#endif +flush_all(struct kmem_cache *s) { on_each_cpu_cond(has_cpu_slab, flush_cpu_slab, s, 1, GFP_ATOMIC); } - +#if defined(CONFIG_OPLUS_FEATURE_SLABTRACE_DEBUG) +EXPORT_SYMBOL(flush_all); +#endif /* * Use the cpu notifier to insure that the cpu slabs are flushed when * necessary. @@ -3630,12 +3762,17 @@ static int calculate_sizes(struct kmem_cache *s, int forced_order) } #ifdef CONFIG_SLUB_DEBUG +#if defined(OPLUS_FEATURE_MEMLEAK_DETECT) && defined(CONFIG_KMALLOC_DEBUG) && !defined(CONFIG_SLUB_DEBUG_ON) && !defined(CONFIG_OPLUS_FEATURE_SLABTRACE_DEBUG) + if (flags & SLAB_STORE_USER) + size += sizeof(struct track); +#else if (flags & SLAB_STORE_USER) /* * Need to store information about allocs and frees after * the object. */ size += 2 * sizeof(struct track); +#endif #endif kasan_cache_create(s, &size, &s->flags); @@ -4576,9 +4713,20 @@ static long validate_slab_cache(struct kmem_cache *s) * and freed. */ +#if defined(CONFIG_OPLUS_FEATURE_SLABTRACE_DEBUG) +#define OPLUS_MEMCFG_SLABTRACE_CNT 4 +#if (OPLUS_MEMCFG_SLABTRACE_CNT > TRACK_ADDRS_COUNT) +#error (OPLUS_MEMCFG_SLABTRACE_CNT > TRACK_ADDRS_COUNT) +#endif +#endif struct location { unsigned long count; unsigned long addr; +#if defined(CONFIG_OPLUS_FEATURE_SLABTRACE_DEBUG) +#ifdef CONFIG_STACKTRACE + unsigned long addrs[OPLUS_MEMCFG_SLABTRACE_CNT]; /* caller address */ +#endif +#endif long long sum_time; long min_time; long max_time; @@ -4601,7 +4749,12 @@ static void free_loc_track(struct loc_track *t) get_order(sizeof(struct location) * t->max)); } -static int alloc_loc_track(struct loc_track *t, unsigned long max, gfp_t flags) +#if defined(CONFIG_OPLUS_FEATURE_SLABTRACE_DEBUG) +int +#else +static int +#endif +alloc_loc_track(struct loc_track *t, unsigned long max, gfp_t flags) { struct location *l; int order; @@ -4620,7 +4773,9 @@ static int alloc_loc_track(struct loc_track *t, unsigned long max, gfp_t flags) t->loc = l; return 1; } - +#if defined(CONFIG_OPLUS_FEATURE_SLABTRACE_DEBUG) +EXPORT_SYMBOL(alloc_loc_track); +#endif static int add_location(struct loc_track *t, struct kmem_cache *s, const struct track *track) { @@ -5382,7 +5537,14 @@ static ssize_t free_calls_show(struct kmem_cache *s, char *buf) { if (!(s->flags & SLAB_STORE_USER)) return -ENOSYS; + +#if !defined(OPLUS_FEATURE_MEMLEAK_DETECT) || !defined(CONFIG_KMALLOC_DEBUG) || defined(CONFIG_SLUB_DEBUG_ON) || defined(CONFIG_OPLUS_FEATURE_SLABTRACE_DEBUG) + /* only record alloc stack. + */ return list_locations(s, buf, TRACK_FREE); +#else + return -ENOSYS; +#endif } SLAB_ATTR_RO(free_calls); #endif /* CONFIG_SLUB_DEBUG */ @@ -6135,3 +6297,17 @@ ssize_t slabinfo_write(struct file *file, const char __user *buffer, return -EIO; } #endif /* CONFIG_SLUB_DEBUG */ + +#ifdef CONFIG_KMALLOC_DEBUG +#ifdef OPLUS_FEATURE_MEMLEAK_DETECT +/* calc the stack hash */ +#include "malloc_track/slub_track.c" +#else +int __init __weak create_kmalloc_debug(struct proc_dir_entry *parent) +{ + pr_warn("OPLUS_FEATURE_MEMLEAK_DETECT is off.\n"); + return 0; +} +EXPORT_SYMBOL(create_kmalloc_debug); +#endif +#endif diff --git a/mm/swap.c b/mm/swap.c index c48106674912..0ff28ea70b27 100644 --- a/mm/swap.c +++ b/mm/swap.c @@ -65,9 +65,8 @@ static void __page_cache_release(struct page *page) spin_lock_irqsave(zone_lru_lock(zone), flags); lruvec = mem_cgroup_page_lruvec(page, zone->zone_pgdat); - VM_BUG_ON_PAGE(!PageLRU(page), page); - __ClearPageLRU(page); - del_page_from_lru_list(page, lruvec, page_off_lru(page)); + del_page_from_lru_list(page, lruvec); + __clear_page_lru_flags(page); spin_unlock_irqrestore(zone_lru_lock(zone), flags); } __ClearPageWaiters(page); @@ -221,9 +220,9 @@ static void pagevec_move_tail_fn(struct page *page, struct lruvec *lruvec, int *pgmoved = arg; if (PageLRU(page) && !PageUnevictable(page)) { - del_page_from_lru_list(page, lruvec, page_lru(page)); + del_page_from_lru_list(page, lruvec); ClearPageActive(page); - add_page_to_lru_list_tail(page, lruvec, page_lru(page)); + add_page_to_lru_list_tail(page, lruvec); (*pgmoved)++; } } @@ -276,12 +275,10 @@ static void __activate_page(struct page *page, struct lruvec *lruvec, { if (PageLRU(page) && !PageActive(page) && !PageUnevictable(page)) { int file = page_is_file_cache(page); - int lru = page_lru_base_type(page); - del_page_from_lru_list(page, lruvec, lru); + del_page_from_lru_list(page, lruvec); SetPageActive(page); - lru += LRU_ACTIVE; - add_page_to_lru_list(page, lruvec, lru); + add_page_to_lru_list(page, lruvec); trace_mm_lru_activate(page); __count_vm_event(PGACTIVATE); @@ -359,6 +356,43 @@ static void __lru_cache_activate_page(struct page *page) put_cpu_var(lru_add_pvec); } +#ifdef CONFIG_LRU_GEN +static void page_inc_refs(struct page *page) +{ + unsigned long refs; + unsigned long old_flags, new_flags; + + if (PageUnevictable(page)) + return; + + /* see the comment on MAX_NR_TIERS */ + do { + new_flags = old_flags = READ_ONCE(page->flags); + + if (!(new_flags & BIT(PG_referenced))) { + new_flags |= BIT(PG_referenced); + continue; + } + + if (!(new_flags & BIT(PG_workingset))) { + new_flags |= BIT(PG_workingset); + continue; + } + + refs = new_flags & LRU_REFS_MASK; + refs = min(refs + BIT(LRU_REFS_PGOFF), LRU_REFS_MASK); + + new_flags &= ~LRU_REFS_MASK; + new_flags |= refs; + } while (new_flags != old_flags && + cmpxchg(&page->flags, old_flags, new_flags) != old_flags); +} +#else +static void page_inc_refs(struct page *page) +{ +} +#endif /* CONFIG_LRU_GEN */ + /* * Mark a page as having seen activity. * @@ -372,6 +406,12 @@ static void __lru_cache_activate_page(struct page *page) void mark_page_accessed(struct page *page) { page = compound_head(page); + + if (lru_gen_enabled()) { + page_inc_refs(page); + return; + } + if (!PageActive(page) && !PageUnevictable(page) && PageReferenced(page)) { @@ -400,6 +440,11 @@ static void __lru_cache_add(struct page *page) { struct pagevec *pvec = &get_cpu_var(lru_add_pvec); + /* see the comment in lru_gen_add_page() */ + if (lru_gen_enabled() && !PageUnevictable(page) && !PageActive(page) && + lru_gen_in_fault() && !(current->flags & PF_MEMALLOC)) + SetPageActive(page); + get_page(page); if (!pagevec_add(pvec, page) || PageCompound(page)) __pagevec_lru_add(pvec); @@ -495,7 +540,7 @@ void __lru_cache_add_active_or_unevictable(struct page *page, static void lru_deactivate_file_fn(struct page *page, struct lruvec *lruvec, void *arg) { - int lru, file; + int file; bool active; if (!PageLRU(page)) @@ -510,12 +555,10 @@ static void lru_deactivate_file_fn(struct page *page, struct lruvec *lruvec, active = PageActive(page); file = page_is_file_cache(page); - lru = page_lru_base_type(page); - del_page_from_lru_list(page, lruvec, lru + active); + del_page_from_lru_list(page, lruvec); ClearPageActive(page); ClearPageReferenced(page); - add_page_to_lru_list(page, lruvec, lru); if (PageWriteback(page) || PageDirty(page)) { /* @@ -523,13 +566,14 @@ static void lru_deactivate_file_fn(struct page *page, struct lruvec *lruvec, * It can make readahead confusing. But race window * is _really_ small and it's non-critical problem. */ + add_page_to_lru_list(page, lruvec); SetPageReclaim(page); } else { /* * The page's writeback ends up during pagevec * We moves tha page into tail of inactive. */ - list_move_tail(&page->lru, &lruvec->lists[lru]); + add_page_to_lru_list_tail(page, lruvec); __count_vm_event(PGROTATED); } @@ -538,16 +582,12 @@ static void lru_deactivate_file_fn(struct page *page, struct lruvec *lruvec, update_page_reclaim_stat(lruvec, file, 0); } - static void lru_lazyfree_fn(struct page *page, struct lruvec *lruvec, void *arg) { if (PageLRU(page) && PageAnon(page) && PageSwapBacked(page) && !PageSwapCache(page) && !PageUnevictable(page)) { - bool active = PageActive(page); - - del_page_from_lru_list(page, lruvec, - LRU_INACTIVE_ANON + active); + del_page_from_lru_list(page, lruvec); ClearPageActive(page); ClearPageReferenced(page); /* @@ -556,7 +596,7 @@ static void lru_lazyfree_fn(struct page *page, struct lruvec *lruvec, * pages */ ClearPageSwapBacked(page); - add_page_to_lru_list(page, lruvec, LRU_INACTIVE_FILE); + add_page_to_lru_list(page, lruvec); __count_vm_events(PGLAZYFREE, hpage_nr_pages(page)); count_memcg_page_event(page, PGLAZYFREE); @@ -782,13 +822,10 @@ void release_pages(struct page **pages, int nr) } lruvec = mem_cgroup_page_lruvec(page, locked_pgdat); - VM_BUG_ON_PAGE(!PageLRU(page), page); - __ClearPageLRU(page); - del_page_from_lru_list(page, lruvec, page_off_lru(page)); + del_page_from_lru_list(page, lruvec); + __clear_page_lru_flags(page); } - /* Clear Active bit in case of parallel mark_page_accessed */ - __ClearPageActive(page); __ClearPageWaiters(page); list_add(&page->lru, &pages_to_free); @@ -845,17 +882,14 @@ void lru_add_page_tail(struct page *page, struct page *page_tail, get_page(page_tail); list_add_tail(&page_tail->lru, list); } else { - struct list_head *list_head; /* * Head page has not yet been counted, as an hpage, * so we must account for each subpage individually. * - * Use the standard add function to put page_tail on the list, - * but then correct its position so they all end up in order. + * Put page_tail on the list at the correct position + * so they all end up in order. */ - add_page_to_lru_list(page_tail, lruvec, page_lru(page_tail)); - list_head = page_tail->lru.prev; - list_move_tail(&page_tail->lru, list_head); + add_page_to_lru_list_tail(page_tail, lruvec); } if (!PageUnevictable(page)) @@ -866,7 +900,6 @@ void lru_add_page_tail(struct page *page, struct page *page_tail, static void __pagevec_lru_add_fn(struct page *page, struct lruvec *lruvec, void *arg) { - enum lru_list lru; int was_unevictable = TestClearPageUnevictable(page); VM_BUG_ON_PAGE(PageLRU(page), page); @@ -901,21 +934,19 @@ static void __pagevec_lru_add_fn(struct page *page, struct lruvec *lruvec, smp_mb(); if (page_evictable(page)) { - lru = page_lru(page); update_page_reclaim_stat(lruvec, page_is_file_cache(page), PageActive(page)); if (was_unevictable) count_vm_event(UNEVICTABLE_PGRESCUED); } else { - lru = LRU_UNEVICTABLE; ClearPageActive(page); SetPageUnevictable(page); if (!was_unevictable) count_vm_event(UNEVICTABLE_PGCULLED); } - add_page_to_lru_list(page, lruvec, lru); - trace_mm_lru_insertion(page, lru); + add_page_to_lru_list(page, lruvec); + trace_mm_lru_insertion(page); } /* @@ -1043,4 +1074,7 @@ void __init swap_setup(void) * Right now other parts of the system means that we * _really_ don't want to cluster much more */ +#if defined(OPLUS_FEATURE_ZRAM_OPT) && defined(CONFIG_OPLUS_ZRAM_OPT) + page_cluster = 0; +#endif /*OPLUS_FEATURE_ZRAM_OPT*/ } diff --git a/mm/swap_slots.c b/mm/swap_slots.c index c8828c3757ff..a389a9fa8aea 100644 --- a/mm/swap_slots.c +++ b/mm/swap_slots.c @@ -334,7 +334,12 @@ swp_entry_t get_swap_page(struct page *page) */ cache = raw_cpu_ptr(&swp_slots); +#if defined(CONFIG_NANDSWAP) + if (likely(check_cache_active() && cache->slots) && + !current_is_nswapoutd()) { +#else if (likely(check_cache_active() && cache->slots)) { +#endif mutex_lock(&cache->alloc_lock); if (cache->slots) { repeat: diff --git a/mm/swap_state.c b/mm/swap_state.c index 565e3464a364..84e1900da610 100644 --- a/mm/swap_state.c +++ b/mm/swap_state.c @@ -8,6 +8,7 @@ * Rewritten to use page cache, (C) 1998 Stephen Tweedie */ #include +#include #include #include #include @@ -98,20 +99,26 @@ static atomic_t swapin_readahead_hits = ATOMIC_INIT(4); void show_swap_cache_info(void) { + unsigned long totalswap = total_swap_pages; +#if defined(CONFIG_NANDSWAP) + if (nandswap_si) + totalswap -= nandswap_si->pages; +#endif + printk("%lu pages in swap cache\n", total_swapcache_pages()); printk("Swap cache stats: add %lu, delete %lu, find %lu/%lu\n", swap_cache_info.add_total, swap_cache_info.del_total, swap_cache_info.find_success, swap_cache_info.find_total); printk("Free swap = %ldkB\n", get_nr_swap_pages() << (PAGE_SHIFT - 10)); - printk("Total swap = %lukB\n", total_swap_pages << (PAGE_SHIFT - 10)); + printk("Total swap = %lukB\n", totalswap << (PAGE_SHIFT - 10)); } /* * __add_to_swap_cache resembles add_to_page_cache_locked on swapper_space, * but sets SwapCache flag and private instead of mapping and index. */ -int __add_to_swap_cache(struct page *page, swp_entry_t entry) +int __add_to_swap_cache(struct page *page, swp_entry_t entry, void **shadowp) { int error, i, nr = hpage_nr_pages(page); struct address_space *address_space; @@ -127,11 +134,30 @@ int __add_to_swap_cache(struct page *page, swp_entry_t entry) address_space = swap_address_space(entry); xa_lock_irq(&address_space->i_pages); for (i = 0; i < nr; i++) { + void *item; + void __rcu **slot; + struct radix_tree_node *node; + set_page_private(page + i, entry.val + i); - error = radix_tree_insert(&address_space->i_pages, - idx + i, page + i); + error = __radix_tree_create(&address_space->i_pages, + idx + i, 0, &node, &slot); if (unlikely(error)) break; + + item = radix_tree_deref_slot_protected(slot, + &address_space->i_pages.xa_lock); + if (WARN_ON_ONCE(item && !radix_tree_exceptional_entry(item))) { + error = -EEXIST; + break; + } + + __radix_tree_replace(&address_space->i_pages, node, slot, + page + i, NULL); + + if (shadowp) { + VM_BUG_ON(i); + *shadowp = item; + } } if (likely(!error)) { address_space->nrpages += nr; @@ -164,7 +190,7 @@ int add_to_swap_cache(struct page *page, swp_entry_t entry, gfp_t gfp_mask) error = radix_tree_maybe_preload_order(gfp_mask, compound_order(page)); if (!error) { - error = __add_to_swap_cache(page, entry); + error = __add_to_swap_cache(page, entry, NULL); radix_tree_preload_end(); } return error; @@ -174,7 +200,7 @@ int add_to_swap_cache(struct page *page, swp_entry_t entry, gfp_t gfp_mask) * This must be called only on pages that have * been verified to be in the swap cache. */ -void __delete_from_swap_cache(struct page *page) +void __delete_from_swap_cache(struct page *page, void *shadow) { struct address_space *address_space; int i, nr = hpage_nr_pages(page); @@ -184,12 +210,23 @@ void __delete_from_swap_cache(struct page *page) VM_BUG_ON_PAGE(!PageLocked(page), page); VM_BUG_ON_PAGE(!PageSwapCache(page), page); VM_BUG_ON_PAGE(PageWriteback(page), page); + VM_BUG_ON(shadow && !radix_tree_exceptional_entry(shadow)); entry.val = page_private(page); address_space = swap_address_space(entry); idx = swp_offset(entry); for (i = 0; i < nr; i++) { - radix_tree_delete(&address_space->i_pages, idx + i); + void *item; + void __rcu **slot; + struct radix_tree_node *node; + + item = __radix_tree_lookup(&address_space->i_pages, + idx + i, &node, &slot); + if (WARN_ON_ONCE(item != page + i)) + continue; + + __radix_tree_replace(&address_space->i_pages, + node, slot, shadow, NULL); set_page_private(page + i, 0); } ClearPageSwapCache(page); @@ -271,13 +308,47 @@ void delete_from_swap_cache(struct page *page) address_space = swap_address_space(entry); xa_lock_irq(&address_space->i_pages); - __delete_from_swap_cache(page); + __delete_from_swap_cache(page, NULL); xa_unlock_irq(&address_space->i_pages); put_swap_page(page, entry); page_ref_sub(page, hpage_nr_pages(page)); } +void clear_shadow_from_swap_cache(int type, unsigned long begin, + unsigned long end) +{ + unsigned long curr = begin; + + for (;;) { + void *item; + void __rcu **slot; + struct radix_tree_iter iter; + swp_entry_t entry = swp_entry(type, curr); + struct address_space *address_space = swap_address_space(entry); + + xa_lock_irq(&address_space->i_pages); + radix_tree_for_each_slot(slot, &address_space->i_pages, + &iter, curr) { + item = radix_tree_deref_slot_protected(slot, + &address_space->i_pages.xa_lock); + if (radix_tree_exceptional_entry(item)) + radix_tree_iter_delete(&address_space->i_pages, + &iter, slot); + if (iter.next_index > end) + break; + } + xa_unlock_irq(&address_space->i_pages); + + /* search the next swapcache until we meet end */ + curr >>= SWAP_ADDRESS_SPACE_SHIFT; + curr++; + curr <<= SWAP_ADDRESS_SPACE_SHIFT; + if (curr > end) + break; + } +} + /* * If we are the only user, then try to free up the swap cache. * @@ -382,6 +453,8 @@ struct page *__read_swap_cache_async(swp_entry_t entry, gfp_t gfp_mask, struct page *found_page, *new_page = NULL; struct address_space *swapper_space = swap_address_space(entry); int err; + void *shadow; + *new_page_allocated = false; do { @@ -443,13 +516,16 @@ struct page *__read_swap_cache_async(swp_entry_t entry, gfp_t gfp_mask, /* May fail (-ENOMEM) if radix-tree node allocation failed. */ __SetPageLocked(new_page); __SetPageSwapBacked(new_page); - err = __add_to_swap_cache(new_page, entry); + err = __add_to_swap_cache(new_page, entry, &shadow); if (likely(!err)) { radix_tree_preload_end(); /* * Initiate read into locked page and return. */ - SetPageWorkingset(new_page); + if (!lru_gen_enabled()) + SetPageWorkingset(new_page); + else if (shadow) + lru_gen_refault(new_page, shadow); lru_cache_add_anon(new_page); *new_page_allocated = true; return new_page; diff --git a/mm/swapfile.c b/mm/swapfile.c index fd2ce14e790f..d2b3e4a63c45 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -6,6 +6,7 @@ */ #include +#include #include #include #include @@ -44,6 +45,8 @@ #include #include +#include + static bool swap_count_continued(struct swap_info_struct *, pgoff_t, unsigned char); static void free_swap_count_continuations(struct swap_info_struct *); @@ -90,6 +93,10 @@ DEFINE_SPINLOCK(swap_avail_lock); struct swap_info_struct *swap_info[MAX_SWAPFILES]; +#if defined(CONFIG_NANDSWAP) +struct swap_info_struct *nandswap_si; +#endif + static DEFINE_MUTEX(swapon_mutex); static DECLARE_WAIT_QUEUE_HEAD(proc_poll_wait); @@ -98,6 +105,10 @@ static atomic_t proc_poll_event = ATOMIC_INIT(0); atomic_t nr_rotate_swap = ATOMIC_INIT(0); +static struct notifier_block pm_notifier; +char swapoff_flag; +static DEFINE_SPINLOCK(swapoff_lock); + static struct swap_info_struct *swap_type_to_swap_info(int type) { if (type >= READ_ONCE(nr_swapfiles)) @@ -663,6 +674,7 @@ static void add_to_avail_list(struct swap_info_struct *p) static void swap_range_free(struct swap_info_struct *si, unsigned long offset, unsigned int nr_entries) { + unsigned long begin = offset; unsigned long end = offset + nr_entries - 1; void (*swap_slot_free_notify)(struct block_device *, unsigned long); @@ -688,6 +700,7 @@ static void swap_range_free(struct swap_info_struct *si, unsigned long offset, swap_slot_free_notify(si->bdev, offset); offset++; } + clear_shadow_from_swap_cache(si->type, begin, end); } static int scan_swap_map_slots(struct swap_info_struct *si, @@ -957,11 +970,20 @@ int get_swap_pages(int n_goal, swp_entry_t swp_entries[], int entry_size) int n_ret = 0; int node; int swap_ratio_off = 0; +#if defined(CONFIG_NANDSWAP) + long nandswap_avail_pgs = 0; +#endif /* Only single cluster request supported */ WARN_ON_ONCE(n_goal > 1 && size == SWAPFILE_CLUSTER); +#if defined(CONFIG_NANDSWAP) + if (nandswap_si) + nandswap_avail_pgs = nandswap_si->pages - nandswap_si->inuse_pages; + avail_pgs = (atomic_long_read(&nr_swap_pages) - nandswap_avail_pgs) / size; +#else avail_pgs = atomic_long_read(&nr_swap_pages) / size; +#endif if (avail_pgs <= 0) goto noswap; @@ -1002,6 +1024,14 @@ start_over: spin_unlock(&swap_avail_lock); start: spin_lock(&si->lock); +#if defined(CONFIG_NANDSWAP) + if ((current_is_nswapoutd() && !(si->flags & SWP_NANDSWAP)) || + (!current_is_nswapoutd() && (si->flags & SWP_NANDSWAP))) { + spin_lock(&swap_avail_lock); + spin_unlock(&si->lock); + goto nextsi; + } +#endif if (!si->highest_bit || !(si->flags & SWP_WRITEOK)) { spin_lock(&swap_avail_lock); if (plist_node_empty(&si->avail_lists[node])) { @@ -1830,7 +1860,8 @@ static int unuse_pte(struct vm_area_struct *vma, pmd_t *pmd, * Move the page to the active list so it is not * immediately swapped out again after swapon. */ - activate_page(page); + if (!lru_gen_enabled()) + activate_page(page); out: pte_unmap_unlock(pte, ptl); out_nolock: @@ -1979,7 +2010,8 @@ static int unuse_mm(struct mm_struct *mm, * Activate page so shrink_inactive_list is unlikely to unmap * its ptes while lock is dropped, so swapoff can make progress. */ - activate_page(page); + if (!lru_gen_enabled()) + activate_page(page); unlock_page(page); down_read(&mm->mmap_sem); lock_page(page); @@ -2498,6 +2530,13 @@ static void _enable_swap_info(struct swap_info_struct *p, int prio, atomic_long_add(p->pages, &nr_swap_pages); total_swap_pages += p->pages; +#if defined(CONFIG_NANDSWAP) + if (p->prio == SWAP_NANDSWAP_PRIO) { + p->flags |= SWP_NANDSWAP; + nandswap_si = p; + } +#endif + assert_spin_locked(&swap_lock); /* * both lists are plists, and thus priority ordered. @@ -2573,6 +2612,10 @@ SYSCALL_DEFINE1(swapoff, const char __user *, specialfile) if (IS_ERR(victim)) goto out; + spin_lock(&swapoff_lock); + swapoff_flag |= 0x01; + spin_unlock(&swapoff_lock); + mapping = victim->f_mapping; spin_lock(&swap_lock); plist_for_each_entry(p, &swap_active_head, list) { @@ -2615,6 +2658,10 @@ SYSCALL_DEFINE1(swapoff, const char __user *, specialfile) atomic_long_sub(p->pages, &nr_swap_pages); total_swap_pages -= p->pages; p->flags &= ~SWP_WRITEOK; +#if defined(CONFIG_NANDSWAP) + if (p->flags & SWP_NANDSWAP) + nandswap_si = NULL; +#endif spin_unlock(&p->lock); spin_unlock(&swap_lock); @@ -2710,6 +2757,9 @@ out_dput: filp_close(victim, NULL); out: putname(pathname); + spin_lock(&swapoff_lock); + swapoff_flag &= 0x00; + spin_unlock(&swapoff_lock); return err; } @@ -3377,6 +3427,10 @@ void si_swapinfo(struct sysinfo *val) { unsigned int type; unsigned long nr_to_be_unused = 0; +#if defined(CONFIG_NANDSWAP) + unsigned long nandswap_free = 0; + unsigned long nandswap_total = 0; +#endif spin_lock(&swap_lock); for (type = 0; type < nr_swapfiles; type++) { @@ -3384,9 +3438,23 @@ void si_swapinfo(struct sysinfo *val) if ((si->flags & SWP_USED) && !(si->flags & SWP_WRITEOK)) nr_to_be_unused += si->inuse_pages; +#if defined(CONFIG_NANDSWAP) + if (si->flags & SWP_NANDSWAP) { + if ((si->flags & SWP_USED) && !(si->flags & SWP_WRITEOK)) + nandswap_free = si->pages; + else + nandswap_free = si->pages - si->inuse_pages; + nandswap_total = si->pages; + } +#endif } val->freeswap = atomic_long_read(&nr_swap_pages) + nr_to_be_unused; val->totalswap = total_swap_pages + nr_to_be_unused; +#if defined(CONFIG_NANDSWAP) + val->freeswap -= nandswap_free; + val->totalswap -= nandswap_total; +#endif + spin_unlock(&swap_lock); } @@ -3801,9 +3869,28 @@ void mem_cgroup_throttle_swaprate(struct mem_cgroup *memcg, int node, } #endif +static int swapoff_pm_notifier(struct notifier_block *notifier, + unsigned long pm_event, void *unused) +{ + switch (pm_event) { + case PM_SUSPEND_PREPARE: + spin_lock(&swapoff_lock); + if (swapoff_flag & 0x01) { + pr_info("stop suspending until swapoff is done"); + spin_unlock(&swapoff_lock); + return NOTIFY_BAD; + } + spin_unlock(&swapoff_lock); + default: + break; + } + return NOTIFY_DONE; +} + static int __init swapfile_init(void) { int nid; + int retval; swap_avail_heads = kmalloc_array(nr_node_ids, sizeof(struct plist_head), GFP_KERNEL); @@ -3815,6 +3902,11 @@ static int __init swapfile_init(void) for_each_node(nid) plist_head_init(&swap_avail_heads[nid]); + pm_notifier.notifier_call = swapoff_pm_notifier; + retval = register_pm_notifier(&pm_notifier); + if (retval) + pr_err("swap error registering pm notifier %d\n", retval); + return 0; } subsys_initcall(swapfile_init); diff --git a/mm/task_mem b/mm/task_mem new file mode 120000 index 000000000000..e449c6ad2550 --- /dev/null +++ b/mm/task_mem @@ -0,0 +1 @@ +../../../vendor/oplus/kernel/oplus_performance/memleak_detect/task_mem \ No newline at end of file diff --git a/mm/util.c b/mm/util.c index a47ac1ae7135..70be349df250 100644 --- a/mm/util.c +++ b/mm/util.c @@ -410,6 +410,7 @@ unsigned long vm_mmap(struct file *file, unsigned long addr, } EXPORT_SYMBOL(vm_mmap); +#define KMALLOC_MAX_PAGES 8 /** * kvmalloc_node - attempt to allocate physically contiguous memory, but upon * failure, fall back to non-contiguous (vmalloc) allocation. @@ -439,6 +440,10 @@ void *kvmalloc_node(size_t size, gfp_t flags, int node) if ((flags & GFP_KERNEL) != GFP_KERNEL) return kmalloc_node(size, flags, node); + /*do not attempt kmalloc if we need more than KMALLOC_MAX_PAGES pages at once*/ + if (size >= KMALLOC_MAX_PAGES * PAGE_SIZE) + goto use_vmalloc; + /* * We want to attempt a large physically contiguous block first because * it is less likely to fragment multiple larger blocks and therefore @@ -461,7 +466,7 @@ void *kvmalloc_node(size_t size, gfp_t flags, int node) */ if (ret || size <= PAGE_SIZE) return ret; - +use_vmalloc: return __vmalloc_node_flags_caller(size, node, flags, __builtin_return_address(0)); } diff --git a/mm/vm_anti_fragment.c b/mm/vm_anti_fragment.c new file mode 120000 index 000000000000..abfd08a1319c --- /dev/null +++ b/mm/vm_anti_fragment.c @@ -0,0 +1 @@ +../../../vendor/oplus/kernel/oplus_performance/vm_anti_fragment/vm_anti_fragment.c \ No newline at end of file diff --git a/mm/vmalloc.c b/mm/vmalloc.c index 8f63ba92fdb9..e028c9584840 100644 --- a/mm/vmalloc.c +++ b/mm/vmalloc.c @@ -39,6 +39,11 @@ #include #include "internal.h" +#if defined(OPLUS_FEATURE_MEMLEAK_DETECT) && defined(CONFIG_VMALLOC_DEBUG) +/* used for vmalloc_debug */ +static unsigned int save_vmalloc_stack(unsigned long flags, struct vmap_area *va); +static void dec_vmalloc_stat(struct vmap_area *va); +#endif struct vfree_deferred { struct llist_head list; @@ -2044,11 +2049,19 @@ EXPORT_SYMBOL_GPL(map_vm_area); static void setup_vmalloc_vm(struct vm_struct *vm, struct vmap_area *va, unsigned long flags, const void *caller) { +#if defined(OPLUS_FEATURE_MEMLEAK_DETECT) && defined(CONFIG_VMALLOC_DEBUG) + /* save vmalloc called stack. */ + unsigned int handle = save_vmalloc_stack(flags, va); +#endif spin_lock(&vmap_area_lock); vm->flags = flags; vm->addr = (void *)va->va_start; vm->size = va->va_end - va->va_start; vm->caller = caller; +#if defined(OPLUS_FEATURE_MEMLEAK_DETECT) && defined(CONFIG_VMALLOC_DEBUG) + /* save stach hash*/ + vm->hash = handle; +#endif va->vm = vm; va->flags |= VM_VM_AREA; spin_unlock(&vmap_area_lock); @@ -2173,6 +2186,11 @@ static struct vm_struct *__remove_vm_area(struct vmap_area *va) { struct vm_struct *vm = va->vm; +#if defined(OPLUS_FEATURE_MEMLEAK_DETECT) && defined(CONFIG_VMALLOC_DEBUG) + /* update the count while + * vfree. */ + dec_vmalloc_stat(va); +#endif spin_lock(&vmap_area_lock); va->vm = NULL; va->flags &= ~VM_VM_AREA; @@ -3466,7 +3484,11 @@ static int s_show(struct seq_file *m, void *p) seq_printf(m, "0x%pK-0x%pK %7ld", v->addr, v->addr + v->size, v->size); - if (v->caller) +#ifdef OPLUS_FEATURE_PERFORMANCE + if (v->caller && (strcmp(current->comm, "android.bg") != 0)) +#else + if (v->caller) +#endif seq_printf(m, " %pS", v->caller); if (v->nr_pages) @@ -3516,3 +3538,16 @@ module_init(proc_vmalloc_init); #endif +#ifdef CONFIG_VMALLOC_DEBUG +#ifdef OPLUS_FEATURE_MEMLEAK_DETECT +/* vmalloc debug used */ +#include "malloc_track/vmalloc_track.c" +#else +int __init __weak create_vmalloc_debug(struct proc_dir_entry *parent) +{ + pr_warn("OPLUS_FEATURE_MEMLEAK_DETECT is off.\n"); + return 0; +} +EXPORT_SYMBOL(create_vmalloc_debug); +#endif +#endif diff --git a/mm/vmscan.c b/mm/vmscan.c index bfe52b7ed24e..28fcabb14f9a 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -11,7 +11,6 @@ * Zone aware kswapd started 02/00, Kanoj Sarcar (kanoj@sgi.com). * Multiqueue VM started 5.8.00, Rik van Riel. */ - #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include @@ -50,6 +49,10 @@ #include #include #include +#include +#include +#include +#include #include #include @@ -57,11 +60,23 @@ #include #include +#if defined(OPLUS_FEATURE_PROCESS_RECLAIM) && defined(CONFIG_PROCESS_RECLAIM_ENHANCE) +#include +#endif + #include "internal.h" #define CREATE_TRACE_POINTS #include +#if defined(OPLUS_FEATURE_ZRAM_OPT) && defined(CONFIG_FG_TASK_UID) +#include +#endif /*OPLUS_FEATURE_ZRAM_OPT*/ +#if defined(OPLUS_FEATURE_MULTI_KSWAPD) && defined(CONFIG_OPLUS_MULTI_KSWAPD) +#include +#endif +#include + struct scan_control { /* How many pages shrink_list() should reclaim */ unsigned long nr_to_reclaim; @@ -103,6 +118,13 @@ struct scan_control { /* One of the zones is ready for compaction */ unsigned int compaction_ready:1; +#ifdef CONFIG_LRU_GEN + /* help make better choices when multiple memcgs are available */ + unsigned int memcgs_need_aging:1; + unsigned int memcgs_need_swapping:1; + unsigned int memcgs_avoid_swapping:1; +#endif + /* Allocation order */ s8 order; @@ -136,14 +158,20 @@ struct scan_control { * on memory until last task zap it. */ struct vm_area_struct *target_vma; + +#if defined(OPLUS_FEATURE_PROCESS_RECLAIM) && defined(CONFIG_PROCESS_RECLAIM_ENHANCE) + struct mm_walk *walk; +#endif }; +#ifndef CONFIG_OPLUS_MULTI_KSWAPD /* * Number of active kswapd threads */ #define DEF_KSWAPD_THREADS_PER_NODE 1 -int kswapd_threads = DEF_KSWAPD_THREADS_PER_NODE; +//int kswapd_threads = DEF_KSWAPD_THREADS_PER_NODE; int kswapd_threads_current = DEF_KSWAPD_THREADS_PER_NODE; +#endif /*CONFIG_OPLUS_MULTI_KSWAPD*/ #ifdef ARCH_HAS_PREFETCH #define prefetch_prev_lru_page(_page, _base, _field) \ @@ -177,6 +205,22 @@ int kswapd_threads_current = DEF_KSWAPD_THREADS_PER_NODE; * From 0 .. 100. Higher means more swappy. */ int vm_swappiness = 60; +#ifdef CONFIG_DYNAMIC_TUNNING_SWAPPINESS +int vm_swappiness_threshold1 = 0; +int vm_swappiness_threshold2 = 0; +int swappiness_threshold1_size = 0; +int swappiness_threshold2_size = 0; +#endif +#if defined(OPLUS_FEATURE_ZRAM_OPT) && defined(CONFIG_OPLUS_ZRAM_OPT) +/* + * Direct reclaim swappiness, exptct 0 - 60. Higher means more swappy and slower. + */ +int direct_vm_swappiness = 60; +#endif /*OPLUS_FEATURE_ZRAM_OPT*/ +#ifdef CONFIG_HYBRIDSWAP_SWAPD +static int hybridswapd_swappiness = 200; +#endif + /* * The total number of pages which are beyond the high watermark within all * zones. @@ -905,6 +949,7 @@ static int __remove_mapping(struct address_space *mapping, struct page *page, { unsigned long flags; int refcount; + void *shadow = NULL; BUG_ON(!PageLocked(page)); BUG_ON(mapping != page_mapping(page)); @@ -949,13 +994,15 @@ static int __remove_mapping(struct address_space *mapping, struct page *page, if (PageSwapCache(page)) { swp_entry_t swap = { .val = page_private(page) }; + + if (lru_gen_enabled()) + shadow = lru_gen_eviction(page); mem_cgroup_swapout(page, swap); - __delete_from_swap_cache(page); + __delete_from_swap_cache(page, shadow); xa_unlock_irqrestore(&mapping->i_pages, flags); put_swap_page(page, swap); } else { void (*freepage)(struct page *); - void *shadow = NULL; freepage = mapping->a_ops->freepage; /* @@ -1149,6 +1196,10 @@ static unsigned long shrink_page_list(struct list_head *page_list, enum page_references references = PAGEREF_RECLAIM; bool dirty, writeback; +#if defined(OPLUS_FEATURE_PROCESS_RECLAIM) && defined(CONFIG_PROCESS_RECLAIM_ENHANCE) + if (sc->walk && is_reclaim_should_cancel(sc->walk)) + break; +#endif cond_resched(); page = lru_to_page(page_list); @@ -1169,6 +1220,11 @@ static unsigned long shrink_page_list(struct list_head *page_list, if (!sc->may_unmap && page_mapped(page)) goto keep_locked; + /* page_update_gen() tried to promote this page? */ + if (lru_gen_enabled() && !force_reclaim && + page_mapped(page) && PageReferenced(page)) + goto keep_locked; + /* Double the slab pressure for mapped and swapcache pages */ if ((page_mapped(page) || PageSwapCache(page)) && !(PageAnon(page) && !PageSwapBacked(page))) @@ -1552,6 +1608,7 @@ unsigned long reclaim_clean_pages_from_list(struct zone *zone, unsigned long ret; struct page *page, *next; LIST_HEAD(clean_pages); + unsigned int noreclaim_flag; list_for_each_entry_safe(page, next, page_list, lru) { if (page_is_file_cache(page) && !PageDirty(page) && @@ -1561,16 +1618,67 @@ unsigned long reclaim_clean_pages_from_list(struct zone *zone, } } + /* + * We should be safe here since we are only dealing with file pages and + * we are not kswapd and therefore cannot write dirty file pages. But + * call memalloc_noreclaim_save() anyway, just in case these conditions + * change in the future. + */ + noreclaim_flag = memalloc_noreclaim_save(); ret = shrink_page_list(&clean_pages, zone->zone_pgdat, &sc, TTU_IGNORE_ACCESS, NULL, true); + memalloc_noreclaim_restore(noreclaim_flag); + list_splice(&clean_pages, page_list); mod_node_page_state(zone->zone_pgdat, NR_ISOLATED_FILE, -ret); return ret; } +#if defined(CONFIG_NANDSWAP) +unsigned long nswap_reclaim_page_list(struct list_head *page_list, + struct vm_area_struct *vma, bool scan) +{ + unsigned long nr_reclaimed; + unsigned long nr_scan = 0; + struct page *page; + struct scan_control sc = { + .gfp_mask = GFP_KERNEL, + .priority = DEF_PRIORITY, + .may_writepage = 1, + .may_unmap = 1, + .may_swap = 1, + .target_vma = vma, + }; + + list_for_each_entry(page, page_list, lru) { + ClearPageActive(page); + } + + nr_reclaimed = shrink_page_list(page_list, NULL, &sc, + TTU_IGNORE_ACCESS, NULL, true); + + while (!list_empty(page_list)) { + page = lru_to_page(page_list); + if (PageSwapCache(page) && !PageDirty(page)) + nr_scan++; + list_del(&page->lru); + dec_node_page_state(page, NR_ISOLATED_ANON + + page_is_file_cache(page)); + putback_lru_page(page); + } + + return scan ? nr_scan : nr_reclaimed; +} +#endif + #ifdef CONFIG_PROCESS_RECLAIM +#if defined(OPLUS_FEATURE_PROCESS_RECLAIM) && defined(CONFIG_PROCESS_RECLAIM_ENHANCE) +unsigned long reclaim_pages_from_list(struct list_head *page_list, + struct vm_area_struct *vma, struct mm_walk *walk) +#else unsigned long reclaim_pages_from_list(struct list_head *page_list, struct vm_area_struct *vma) +#endif { struct scan_control sc = { .gfp_mask = GFP_KERNEL, @@ -1579,6 +1687,9 @@ unsigned long reclaim_pages_from_list(struct list_head *page_list, .may_unmap = 1, .may_swap = 1, .target_vma = vma, +#if defined(OPLUS_FEATURE_PROCESS_RECLAIM) && defined(CONFIG_PROCESS_RECLAIM_ENHANCE) + .walk = walk, +#endif }; unsigned long nr_reclaimed; @@ -1693,10 +1804,7 @@ static __always_inline void update_lru_sizes(struct lruvec *lruvec, if (!nr_zone_taken[zid]) continue; - __update_lru_size(lruvec, lru, zid, -nr_zone_taken[zid]); -#ifdef CONFIG_MEMCG - mem_cgroup_update_lru_size(lruvec, lru, zid, -nr_zone_taken[zid]); -#endif + update_lru_size(lruvec, lru, zid, -nr_zone_taken[zid]); } } @@ -1833,7 +1941,15 @@ int isolate_lru_page(struct page *page) int ret = -EBUSY; VM_BUG_ON_PAGE(!page_count(page), page); +#if defined(OPLUS_FEATURE_PROCESS_RECLAIM) && defined(CONFIG_PROCESS_RECLAIM_ENHANCE) + /* + * Because process reclaim is doing page by + * page, so there many compound pages are relcaimed, so too many warning msg on this case. + */ + WARN_RATELIMIT((!current_is_reclaimer() && PageTail(page)), "trying to isolate tail page"); +#else WARN_RATELIMIT(PageTail(page), "trying to isolate tail page"); +#endif if (PageLRU(page)) { struct zone *zone = page_zone(page); @@ -1842,10 +1958,9 @@ int isolate_lru_page(struct page *page) spin_lock_irq(zone_lru_lock(zone)); lruvec = mem_cgroup_page_lruvec(page, zone->zone_pgdat); if (PageLRU(page)) { - int lru = page_lru(page); get_page(page); ClearPageLRU(page); - del_page_from_lru_list(page, lruvec, lru); + del_page_from_lru_list(page, lruvec); ret = 0; } spin_unlock_irq(zone_lru_lock(zone)); @@ -1902,7 +2017,6 @@ putback_inactive_pages(struct lruvec *lruvec, struct list_head *page_list) */ while (!list_empty(page_list)) { struct page *page = lru_to_page(page_list); - int lru; VM_BUG_ON_PAGE(PageLRU(page), page); list_del(&page->lru); @@ -1916,18 +2030,16 @@ putback_inactive_pages(struct lruvec *lruvec, struct list_head *page_list) lruvec = mem_cgroup_page_lruvec(page, pgdat); SetPageLRU(page); - lru = page_lru(page); - add_page_to_lru_list(page, lruvec, lru); + add_page_to_lru_list(page, lruvec); - if (is_active_lru(lru)) { - int file = is_file_lru(lru); + if (PageActive(page)) { + int file = page_is_file_cache(page); int numpages = hpage_nr_pages(page); reclaim_stat->recent_rotated[file] += numpages; } if (put_page_testzero(page)) { - __ClearPageLRU(page); - __ClearPageActive(page); - del_page_from_lru_list(page, lruvec, lru); + del_page_from_lru_list(page, lruvec); + __clear_page_lru_flags(page); if (unlikely(PageCompound(page))) { spin_unlock_irq(&pgdat->lru_lock); @@ -1953,6 +2065,14 @@ putback_inactive_pages(struct lruvec *lruvec, struct list_head *page_list) */ static int current_may_throttle(void) { +#if defined(OPLUS_FEATURE_ZRAM_OPT) && defined(CONFIG_OPLUS_ZRAM_OPT) + if ((current->signal->oom_score_adj < 0) +#ifdef CONFIG_FG_TASK_UID + || is_fg(current_uid().val) +#endif + ) + return 0; +#endif /*OPLUS_FEATURE_ZRAM_OPT*/ return !(current->flags & PF_LESS_THROTTLE) || current->backing_dev_info == NULL || bdi_write_congested(current->backing_dev_info); @@ -2100,7 +2220,6 @@ static unsigned move_active_pages_to_lru(struct lruvec *lruvec, { struct pglist_data *pgdat = lruvec_pgdat(lruvec); struct page *page; - int nr_pages; int nr_moved = 0; while (!list_empty(list)) { @@ -2108,16 +2227,13 @@ static unsigned move_active_pages_to_lru(struct lruvec *lruvec, lruvec = mem_cgroup_page_lruvec(page, pgdat); VM_BUG_ON_PAGE(PageLRU(page), page); + list_del(&page->lru); SetPageLRU(page); - - nr_pages = hpage_nr_pages(page); - update_lru_size(lruvec, lru, page_zonenum(page), nr_pages); - list_move(&page->lru, &lruvec->lists[lru]); + add_page_to_lru_list(page, lruvec); if (put_page_testzero(page)) { - __ClearPageLRU(page); - __ClearPageActive(page); - del_page_from_lru_list(page, lruvec, lru); + del_page_from_lru_list(page, lruvec); + __clear_page_lru_flags(page); if (unlikely(PageCompound(page))) { spin_unlock_irq(&pgdat->lru_lock); @@ -2127,7 +2243,7 @@ static unsigned move_active_pages_to_lru(struct lruvec *lruvec, } else list_add(&page->lru, pages_to_free); } else { - nr_moved += nr_pages; + nr_moved += hpage_nr_pages(page); } } @@ -2241,6 +2357,65 @@ static void shrink_active_list(unsigned long nr_to_scan, nr_deactivate, nr_rotated, sc->priority, file); } +unsigned long reclaim_pages(struct list_head *page_list) +{ + int nid = -1; + unsigned long nr_reclaimed = 0; + LIST_HEAD(node_page_list); + struct reclaim_stat dummy_stat; + struct page *page; + unsigned int noreclaim_flag; + + struct scan_control sc = { + .gfp_mask = GFP_KERNEL, + .priority = DEF_PRIORITY, + .may_writepage = 1, + .may_unmap = 1, + .may_swap = 1, + }; + noreclaim_flag = memalloc_noreclaim_save(); + + while (!list_empty(page_list)) { + page = lru_to_page(page_list); + if (nid == -1) { + nid = page_to_nid(page); + INIT_LIST_HEAD(&node_page_list); + } + + if (nid == page_to_nid(page)) { + list_move(&page->lru, &node_page_list); + continue; + } + + nr_reclaimed += shrink_page_list(&node_page_list, + NODE_DATA(nid), + &sc, 0, + &dummy_stat, false); + while (!list_empty(&node_page_list)) { + page = lru_to_page(&node_page_list); + list_del(&page->lru); + putback_lru_page(page); + } + + nid = -1; + } + + if (!list_empty(&node_page_list)) { + nr_reclaimed += shrink_page_list(&node_page_list, + NODE_DATA(nid), + &sc, 0, + &dummy_stat, false); + while (!list_empty(&node_page_list)) { + page = lru_to_page(&node_page_list); + list_del(&page->lru); + putback_lru_page(page); + } + } + memalloc_noreclaim_restore(noreclaim_flag); + + return nr_reclaimed; +} + /* * The inactive anon list should be small enough that the VM never has * to do too much work. @@ -2300,8 +2475,13 @@ static bool inactive_list_is_low(struct lruvec *lruvec, bool file, inactive_ratio = 0; } else { gb = (inactive + active) >> (30 - PAGE_SHIFT); +#if defined(OPLUS_FEATURE_ZRAM_OPT) && defined(CONFIG_OPLUS_ZRAM_OPT) + if (file && gb) + inactive_ratio = min(2UL, int_sqrt(10 * gb)); +#else if (gb) inactive_ratio = int_sqrt(10 * gb); +#endif /*OPLUS_FEATURE_ZRAM_OPT*/ else inactive_ratio = 1; } @@ -2334,6 +2514,14 @@ enum scan_balance { SCAN_FILE, }; +#ifdef CONFIG_HYBRIDSWAP_SWAPD +extern bool free_swap_is_low(void); +bool __weak free_swap_is_low(void) +{ + return false; +} +#endif + /* * Determine how aggressively the anon and file LRU lists should be * scanned. The relative value of each set of LRU lists is determined @@ -2349,7 +2537,7 @@ static void get_scan_count(struct lruvec *lruvec, struct mem_cgroup *memcg, { int swappiness = mem_cgroup_swappiness(memcg); struct zone_reclaim_stat *reclaim_stat = &lruvec->reclaim_stat; - u64 fraction[2]; + u64 fraction[ANON_AND_FILE]; u64 denominator = 0; /* gcc */ struct pglist_data *pgdat = lruvec_pgdat(lruvec); unsigned long anon_prio, file_prio; @@ -2357,9 +2545,47 @@ static void get_scan_count(struct lruvec *lruvec, struct mem_cgroup *memcg, unsigned long anon, file; unsigned long ap, fp; enum lru_list lru; + unsigned long totalswap = total_swap_pages; +#if defined(CONFIG_NANDSWAP) + if (nandswap_si) + totalswap -= nandswap_si->pages; +#endif + /* use vm_swappiness defaultly */ + swappiness = vm_swappiness; +#if defined(OPLUS_FEATURE_ZRAM_OPT) && defined(CONFIG_OPLUS_ZRAM_OPT) + if (!current_is_kswapd()) { +#ifdef CONFIG_HYBRIDSWAP_SWAPD + if (strncmp(current->comm, "hybridswapd:", sizeof("hybridswapd:") - 1) == 0) { + swappiness = hybridswapd_swappiness; + if (free_swap_is_low()) + swappiness = 0; + } else +#endif + swappiness = direct_vm_swappiness; + } +#ifdef CONFIG_DYNAMIC_TUNNING_SWAPPINESS + else { + unsigned long nr_file_pages = + global_node_page_state(NR_ACTIVE_FILE) + + global_node_page_state(NR_INACTIVE_FILE); + + if (swappiness_threshold1_size && vm_swappiness_threshold1 && + nr_file_pages >= (swappiness_threshold1_size << 8) && + swappiness > vm_swappiness_threshold1) { + swappiness = vm_swappiness_threshold1; + } else if (swappiness_threshold2_size && vm_swappiness_threshold2 && + nr_file_pages >= (swappiness_threshold2_size << 8) && + swappiness > vm_swappiness_threshold2) { + swappiness = vm_swappiness_threshold2; + } + } +#endif + if (!sc->may_swap || (mem_cgroup_get_nr_swap_pages(memcg) <= totalswap>>6)) { +#else /* If we have no swap space, do not bother scanning anon pages. */ if (!sc->may_swap || mem_cgroup_get_nr_swap_pages(memcg) <= 0) { +#endif /*OPLUS_FEATURE_ZRAM_OPT*/ scan_balance = SCAN_FILE; goto out; } @@ -2461,8 +2687,6 @@ static void get_scan_count(struct lruvec *lruvec, struct mem_cgroup *memcg, * Because workloads change over time (and to avoid overflow) * we keep these statistics as a floating average, which ends * up weighing recent references more than old ones. - * - * anon in [0], file in [1] */ anon = lruvec_lru_size(lruvec, LRU_ACTIVE_ANON, MAX_NR_ZONES) + @@ -2512,6 +2736,7 @@ out: if (!scan && !mem_cgroup_online(memcg)) scan = min(size, SWAP_CLUSTER_MAX); + trace_android_vh_tune_scan_type((char *)(&scan_balance)); switch (scan_balance) { case SCAN_EQUAL: /* Scan lists relative to size */ @@ -2547,6 +2772,2633 @@ out: } } +#ifdef CONFIG_LRU_GEN + +#ifdef CONFIG_LRU_GEN_ENABLED +DEFINE_STATIC_KEY_ARRAY_TRUE(lru_gen_caps, NR_LRU_GEN_CAPS); +#else +DEFINE_STATIC_KEY_ARRAY_FALSE(lru_gen_caps, NR_LRU_GEN_CAPS); +#endif + +/****************************************************************************** + * shorthand helpers + ******************************************************************************/ + +#define DEFINE_MAX_SEQ(lruvec) \ + unsigned long max_seq = READ_ONCE((lruvec)->lrugen.max_seq) + +#define DEFINE_MIN_SEQ(lruvec) \ + unsigned long min_seq[ANON_AND_FILE] = { \ + READ_ONCE((lruvec)->lrugen.min_seq[LRU_GEN_ANON]), \ + READ_ONCE((lruvec)->lrugen.min_seq[LRU_GEN_FILE]), \ + } + +#define for_each_gen_type_zone(gen, type, zone) \ + for ((gen) = 0; (gen) < MAX_NR_GENS; (gen)++) \ + for ((type) = 0; (type) < ANON_AND_FILE; (type)++) \ + for ((zone) = 0; (zone) < MAX_NR_ZONES; (zone)++) + +static int page_lru_gen(struct page *page) +{ + unsigned long flags = READ_ONCE(page->flags); + + return ((flags & LRU_GEN_MASK) >> LRU_GEN_PGOFF) - 1; +} + +static int page_lru_tier(struct page *page) +{ + int refs; + unsigned long flags = READ_ONCE(page->flags); + + refs = (flags & LRU_REFS_FLAGS) == LRU_REFS_FLAGS ? + ((flags & LRU_REFS_MASK) >> LRU_REFS_PGOFF) + 1 : 0; + + return lru_tier_from_refs(refs); +} + +static bool get_cap(int cap) +{ +#ifdef CONFIG_LRU_GEN_ENABLED + return static_branch_likely(&lru_gen_caps[cap]); +#else + return static_branch_unlikely(&lru_gen_caps[cap]); +#endif +} + +static struct lruvec *get_lruvec(struct mem_cgroup *memcg, int nid) +{ + struct pglist_data *pgdat = NODE_DATA(nid); + +#ifdef CONFIG_MEMCG + if (memcg) { + struct lruvec *lruvec = &memcg->nodeinfo[nid]->lruvec; + + /* for hotadd_new_pgdat() */ + if (!lruvec->pgdat) + lruvec->pgdat = pgdat; + + return lruvec; + } +#endif + VM_BUG_ON(!mem_cgroup_disabled()); + + return pgdat ? &pgdat->lruvec : NULL; +} + +static int get_swappiness(struct lruvec *lruvec, struct scan_control *sc) +{ + struct mem_cgroup *memcg = lruvec_memcg(lruvec); + + if (mem_cgroup_get_nr_swap_pages(memcg) < MIN_LRU_BATCH) + return 0; + + return mem_cgroup_swappiness(memcg); +} + +static int get_nr_gens(struct lruvec *lruvec, int type) +{ + return lruvec->lrugen.max_seq - lruvec->lrugen.min_seq[type] + 1; +} + +static bool __maybe_unused seq_is_valid(struct lruvec *lruvec) +{ + /* see the comment on lru_gen_struct */ + return get_nr_gens(lruvec, LRU_GEN_FILE) >= MIN_NR_GENS && + get_nr_gens(lruvec, LRU_GEN_FILE) <= get_nr_gens(lruvec, LRU_GEN_ANON) && + get_nr_gens(lruvec, LRU_GEN_ANON) <= MAX_NR_GENS; +} + +/****************************************************************************** + * mm_struct list + ******************************************************************************/ + +static struct lru_gen_mm_list *get_mm_list(struct mem_cgroup *memcg) +{ + static struct lru_gen_mm_list mm_list = { + .fifo = LIST_HEAD_INIT(mm_list.fifo), + .lock = __SPIN_LOCK_UNLOCKED(mm_list.lock), + }; + +#ifdef CONFIG_MEMCG + if (memcg) + return &memcg->mm_list; +#endif + VM_BUG_ON(!mem_cgroup_disabled()); + + return &mm_list; +} + +void lru_gen_add_mm(struct mm_struct *mm) +{ + int nid; + struct mem_cgroup *memcg = get_mem_cgroup_from_mm(mm); + struct lru_gen_mm_list *mm_list = get_mm_list(memcg); + + VM_BUG_ON_MM(!list_empty(&mm->lru_gen.list), mm); +#ifdef CONFIG_MEMCG + VM_BUG_ON_MM(mm->lru_gen.memcg, mm); + mm->lru_gen.memcg = memcg; +#endif + spin_lock(&mm_list->lock); + + for_each_node_state(nid, N_MEMORY) { + struct lruvec *lruvec = get_lruvec(memcg, nid); + + if (!lruvec) + continue; + + if (lruvec->mm_state.tail == &mm_list->fifo) + lruvec->mm_state.tail = &mm->lru_gen.list; + } + + list_add_tail(&mm->lru_gen.list, &mm_list->fifo); + + spin_unlock(&mm_list->lock); +} + +void lru_gen_del_mm(struct mm_struct *mm) +{ + int nid; + struct lru_gen_mm_list *mm_list; + struct mem_cgroup *memcg = NULL; + + if (list_empty(&mm->lru_gen.list)) + return; + +#ifdef CONFIG_MEMCG + memcg = mm->lru_gen.memcg; +#endif + mm_list = get_mm_list(memcg); + + spin_lock(&mm_list->lock); + + for_each_node(nid) { + struct lruvec *lruvec = get_lruvec(memcg, nid); + + if (!lruvec) + continue; + + if (lruvec->mm_state.tail == &mm->lru_gen.list) + lruvec->mm_state.tail = lruvec->mm_state.tail->next; + + if (lruvec->mm_state.head != &mm->lru_gen.list) + continue; + + lruvec->mm_state.head = lruvec->mm_state.head->next; + if (lruvec->mm_state.head == &mm_list->fifo) + WRITE_ONCE(lruvec->mm_state.seq, lruvec->mm_state.seq + 1); + } + + list_del_init(&mm->lru_gen.list); + + spin_unlock(&mm_list->lock); + +#ifdef CONFIG_MEMCG + mem_cgroup_put(mm->lru_gen.memcg); + mm->lru_gen.memcg = NULL; +#endif +} + +#ifdef CONFIG_MEMCG +void lru_gen_migrate_mm(struct mm_struct *mm) +{ + struct mem_cgroup *memcg; + + lockdep_assert_held(&mm->owner->alloc_lock); + + /* for mm_update_next_owner() */ + if (mem_cgroup_disabled()) + return; + + rcu_read_lock(); + memcg = mem_cgroup_from_task(mm->owner); + rcu_read_unlock(); + if (memcg == mm->lru_gen.memcg) + return; + + VM_BUG_ON_MM(!mm->lru_gen.memcg, mm); + VM_BUG_ON_MM(list_empty(&mm->lru_gen.list), mm); + + lru_gen_del_mm(mm); + lru_gen_add_mm(mm); +} +#endif + +/* + * Bloom filters with m=1<<15, k=2 and the false positive rates of ~1/5 when + * n=10,000 and ~1/2 when n=20,000, where, conventionally, m is the number of + * bits in a bitmap, k is the number of hash functions and n is the number of + * inserted items. + * + * Page table walkers use one of the two filters to reduce their search space. + * To get rid of non-leaf entries that no longer have enough leaf entries, the + * aging uses the double-buffering technique to flip to the other filter each + * time it produces a new generation. For non-leaf entries that have enough + * leaf entries, the aging carries them over to the next generation in + * walk_pmd_range(); the eviction also report them when walking the rmap + * in lru_gen_look_around(). + * + * For future optimizations: + * 1. It's not necessary to keep both filters all the time. The spare one can be + * freed after the RCU grace period and reallocated if needed again. + * 2. And when reallocating, it's worth scaling its size according to the number + * of inserted entries in the other filter, to reduce the memory overhead on + * small systems and false positives on large systems. + * 3. Jenkins' hash function is an alternative to Knuth's. + */ +#define BLOOM_FILTER_SHIFT 15 + +static inline int filter_gen_from_seq(unsigned long seq) +{ + return seq % NR_BLOOM_FILTERS; +} + +static void get_item_key(void *item, int *key) +{ + u32 hash = hash_ptr(item, BLOOM_FILTER_SHIFT * 2); + + BUILD_BUG_ON(BLOOM_FILTER_SHIFT * 2 > BITS_PER_TYPE(u32)); + + key[0] = hash & (BIT(BLOOM_FILTER_SHIFT) - 1); + key[1] = hash >> BLOOM_FILTER_SHIFT; +} + +static void reset_bloom_filter(struct lruvec *lruvec, unsigned long seq) +{ + unsigned long *filter; + int gen = filter_gen_from_seq(seq); + + lockdep_assert_held(&get_mm_list(lruvec_memcg(lruvec))->lock); + + filter = lruvec->mm_state.filters[gen]; + if (filter) { + bitmap_clear(filter, 0, BIT(BLOOM_FILTER_SHIFT)); + return; + } + + filter = bitmap_zalloc(BIT(BLOOM_FILTER_SHIFT), GFP_ATOMIC); + WRITE_ONCE(lruvec->mm_state.filters[gen], filter); +} + +static void update_bloom_filter(struct lruvec *lruvec, unsigned long seq, void *item) +{ + int key[2]; + unsigned long *filter; + int gen = filter_gen_from_seq(seq); + + filter = READ_ONCE(lruvec->mm_state.filters[gen]); + if (!filter) + return; + + get_item_key(item, key); + + if (!test_bit(key[0], filter)) + set_bit(key[0], filter); + if (!test_bit(key[1], filter)) + set_bit(key[1], filter); +} + +static bool test_bloom_filter(struct lruvec *lruvec, unsigned long seq, void *item) +{ + int key[2]; + unsigned long *filter; + int gen = filter_gen_from_seq(seq); + + filter = READ_ONCE(lruvec->mm_state.filters[gen]); + if (!filter) + return true; + + get_item_key(item, key); + + return test_bit(key[0], filter) && test_bit(key[1], filter); +} + +static void reset_mm_stats(struct lruvec *lruvec, struct lru_gen_mm_walk *walk, bool last) +{ + int i; + int hist; + + lockdep_assert_held(&get_mm_list(lruvec_memcg(lruvec))->lock); + + if (walk) { + hist = lru_hist_from_seq(walk->max_seq); + + for (i = 0; i < NR_MM_STATS; i++) { + WRITE_ONCE(lruvec->mm_state.stats[hist][i], + lruvec->mm_state.stats[hist][i] + walk->mm_stats[i]); + walk->mm_stats[i] = 0; + } + } + + if (NR_HIST_GENS > 1 && last) { + hist = lru_hist_from_seq(lruvec->mm_state.seq + 1); + + for (i = 0; i < NR_MM_STATS; i++) + WRITE_ONCE(lruvec->mm_state.stats[hist][i], 0); + } +} + +static bool should_skip_mm(struct mm_struct *mm, struct lru_gen_mm_walk *walk) +{ + int type; + unsigned long size = 0; + struct pglist_data *pgdat = lruvec_pgdat(walk->lruvec); + + if (!walk->full_scan && cpumask_empty(mm_cpumask(mm)) && + !node_isset(pgdat->node_id, mm->lru_gen.nodes)) + return true; + + node_clear(pgdat->node_id, mm->lru_gen.nodes); + + for (type = !walk->can_swap; type < ANON_AND_FILE; type++) { + size += type ? get_mm_counter(mm, MM_FILEPAGES) : + get_mm_counter(mm, MM_ANONPAGES) + + get_mm_counter(mm, MM_SHMEMPAGES); + } + + if (size < MIN_LRU_BATCH) + return true; + + if (mm_is_oom_victim(mm)) + return true; + + return !mmget_not_zero(mm); +} + +static bool iterate_mm_list(struct lruvec *lruvec, struct lru_gen_mm_walk *walk, + struct mm_struct **iter) +{ + bool first = false; + bool last = true; + struct mm_struct *mm = NULL; + struct mem_cgroup *memcg = lruvec_memcg(lruvec); + struct lru_gen_mm_list *mm_list = get_mm_list(memcg); + struct lru_gen_mm_state *mm_state = &lruvec->mm_state; + + /* + * There are four interesting cases for this page table walker: + * 1. It tries to start a new iteration of mm_list with a stale max_seq; + * there is nothing to be done. + * 2. It's the first of the current generation, and it needs to reset + * the Bloom filter for the next generation. + * 3. It reaches the end of mm_list, and it needs to increment + * mm_state->seq; the iteration is done. + * 4. It's the last of the current generation, and it needs to reset the + * mm stats counters for the next generation. + */ + if (*iter) + mmput_async(*iter); + else if (walk->max_seq <= READ_ONCE(mm_state->seq)) + return false; + + spin_lock(&mm_list->lock); + + VM_BUG_ON(mm_state->seq + 1 < walk->max_seq); + VM_BUG_ON(*iter && mm_state->seq > walk->max_seq); + VM_BUG_ON(*iter && !mm_state->nr_walkers); + + if (walk->max_seq <= mm_state->seq) { + if (!*iter) + last = false; + goto done; + } + + if (!mm_state->nr_walkers) { + VM_BUG_ON(mm_state->head && mm_state->head != &mm_list->fifo); + + mm_state->head = mm_list->fifo.next; + first = true; + } + + while (!mm && mm_state->head != &mm_list->fifo) { + mm = list_entry(mm_state->head, struct mm_struct, lru_gen.list); + + mm_state->head = mm_state->head->next; + + /* full scan for those added after the last iteration */ + if (!mm_state->tail || mm_state->tail == &mm->lru_gen.list) { + mm_state->tail = mm_state->head; + walk->full_scan = true; + } + + if (should_skip_mm(mm, walk)) + mm = NULL; + } + + if (mm_state->head == &mm_list->fifo) + WRITE_ONCE(mm_state->seq, mm_state->seq + 1); +done: + if (*iter && !mm) + mm_state->nr_walkers--; + if (!*iter && mm) + mm_state->nr_walkers++; + + if (mm_state->nr_walkers) + last = false; + + if (mm && first) + reset_bloom_filter(lruvec, walk->max_seq + 1); + + if (*iter || last) + reset_mm_stats(lruvec, walk, last); + + spin_unlock(&mm_list->lock); + + *iter = mm; + + return last; +} + +static bool iterate_mm_list_nowalk(struct lruvec *lruvec, unsigned long max_seq) +{ + bool success = false; + struct mem_cgroup *memcg = lruvec_memcg(lruvec); + struct lru_gen_mm_list *mm_list = get_mm_list(memcg); + struct lru_gen_mm_state *mm_state = &lruvec->mm_state; + + if (max_seq <= READ_ONCE(mm_state->seq)) + return false; + + spin_lock(&mm_list->lock); + + VM_BUG_ON(mm_state->seq + 1 < max_seq); + + if (max_seq > mm_state->seq && !mm_state->nr_walkers) { + VM_BUG_ON(mm_state->head && mm_state->head != &mm_list->fifo); + + WRITE_ONCE(mm_state->seq, mm_state->seq + 1); + reset_mm_stats(lruvec, NULL, true); + success = true; + } + + spin_unlock(&mm_list->lock); + + return success; +} + +/****************************************************************************** + * refault feedback loop + ******************************************************************************/ + +/* + * A feedback loop based on Proportional-Integral-Derivative (PID) controller. + * + * The P term is refaulted/(evicted+protected) from a tier in the generation + * currently being evicted; the I term is the exponential moving average of the + * P term over the generations previously evicted, using the smoothing factor + * 1/2; the D term isn't supported. + * + * The setpoint (SP) is always the first tier of one type; the process variable + * (PV) is either any tier of the other type or any other tier of the same + * type. + * + * The error is the difference between the SP and the PV; the correction is + * turn off protection when SP>PV or turn on protection when SPlrugen; + int hist = lru_hist_from_seq(lrugen->min_seq[type]); + + pos->refaulted = lrugen->avg_refaulted[type][tier] + + atomic_long_read(&lrugen->refaulted[hist][type][tier]); + pos->total = lrugen->avg_total[type][tier] + + atomic_long_read(&lrugen->evicted[hist][type][tier]); + if (tier) + pos->total += lrugen->protected[hist][type][tier - 1]; + pos->gain = gain; +} + +static void reset_ctrl_pos(struct lruvec *lruvec, int type, bool carryover) +{ + int hist, tier; + struct lru_gen_struct *lrugen = &lruvec->lrugen; + bool clear = carryover ? NR_HIST_GENS == 1 : NR_HIST_GENS > 1; + unsigned long seq = carryover ? lrugen->min_seq[type] : lrugen->max_seq + 1; + + lockdep_assert_held(&lruvec_pgdat(lruvec)->lru_lock); + + if (!carryover && !clear) + return; + + hist = lru_hist_from_seq(seq); + + for (tier = 0; tier < MAX_NR_TIERS; tier++) { + if (carryover) { + unsigned long sum; + + sum = lrugen->avg_refaulted[type][tier] + + atomic_long_read(&lrugen->refaulted[hist][type][tier]); + WRITE_ONCE(lrugen->avg_refaulted[type][tier], sum / 2); + + sum = lrugen->avg_total[type][tier] + + atomic_long_read(&lrugen->evicted[hist][type][tier]); + if (tier) + sum += lrugen->protected[hist][type][tier - 1]; + WRITE_ONCE(lrugen->avg_total[type][tier], sum / 2); + } + + if (clear) { + atomic_long_set(&lrugen->refaulted[hist][type][tier], 0); + atomic_long_set(&lrugen->evicted[hist][type][tier], 0); + if (tier) + WRITE_ONCE(lrugen->protected[hist][type][tier - 1], 0); + } + } +} + +static bool positive_ctrl_err(struct ctrl_pos *sp, struct ctrl_pos *pv) +{ + /* + * Return true if the PV has a limited number of refaults or a lower + * refaulted/total than the SP. + */ + return pv->refaulted < MIN_LRU_BATCH || + pv->refaulted * (sp->total + MIN_LRU_BATCH) * sp->gain <= + (sp->refaulted + 1) * pv->total * pv->gain; +} + +/****************************************************************************** + * the aging + ******************************************************************************/ + +static int page_update_gen(struct page *page, int gen) +{ + unsigned long old_flags, new_flags; + + VM_BUG_ON(gen >= MAX_NR_GENS); + VM_BUG_ON(!rcu_read_lock_held()); + + do { + new_flags = old_flags = READ_ONCE(page->flags); + + /* for shrink_page_list() */ + if (!(new_flags & LRU_GEN_MASK)) { + new_flags |= BIT(PG_referenced); + continue; + } + + new_flags &= ~LRU_GEN_MASK; + new_flags |= (gen + 1UL) << LRU_GEN_PGOFF; + new_flags &= ~(LRU_REFS_MASK | LRU_REFS_FLAGS); + } while (new_flags != old_flags && + cmpxchg(&page->flags, old_flags, new_flags) != old_flags); + + return ((old_flags & LRU_GEN_MASK) >> LRU_GEN_PGOFF) - 1; +} + +static int page_inc_gen(struct lruvec *lruvec, struct page *page, bool reclaiming) +{ + unsigned long old_flags, new_flags; + int type = page_is_file_cache(page); + struct lru_gen_struct *lrugen = &lruvec->lrugen; + int new_gen, old_gen = lru_gen_from_seq(lrugen->min_seq[type]); + + do { + new_flags = old_flags = READ_ONCE(page->flags); + VM_BUG_ON_PAGE(!(new_flags & LRU_GEN_MASK), page); + + new_gen = ((new_flags & LRU_GEN_MASK) >> LRU_GEN_PGOFF) - 1; + /* page_update_gen() has promoted this page? */ + if (new_gen >= 0 && new_gen != old_gen) + return new_gen; + + new_gen = (old_gen + 1) % MAX_NR_GENS; + + new_flags &= ~LRU_GEN_MASK; + new_flags |= (new_gen + 1UL) << LRU_GEN_PGOFF; + new_flags &= ~(LRU_REFS_MASK | LRU_REFS_FLAGS); + /* for end_page_writeback() */ + if (reclaiming) + new_flags |= BIT(PG_reclaim); + } while (cmpxchg(&page->flags, old_flags, new_flags) != old_flags); + + lru_gen_update_size(lruvec, page, old_gen, new_gen); + + return new_gen; +} + +static void update_batch_size(struct lru_gen_mm_walk *walk, struct page *page, + int old_gen, int new_gen) +{ + int type = page_is_file_cache(page); + int zone = page_zonenum(page); + int delta = hpage_nr_pages(page); + + VM_BUG_ON(old_gen >= MAX_NR_GENS); + VM_BUG_ON(new_gen >= MAX_NR_GENS); + + walk->batched++; + + walk->nr_pages[old_gen][type][zone] -= delta; + walk->nr_pages[new_gen][type][zone] += delta; +} + +static void reset_batch_size(struct lruvec *lruvec, struct lru_gen_mm_walk *walk) +{ + int gen, type, zone; + struct lru_gen_struct *lrugen = &lruvec->lrugen; + + walk->batched = 0; + + for_each_gen_type_zone(gen, type, zone) { + enum lru_list lru = type * LRU_INACTIVE_FILE; + int delta = walk->nr_pages[gen][type][zone]; + + if (!delta) + continue; + + walk->nr_pages[gen][type][zone] = 0; + WRITE_ONCE(lrugen->nr_pages[gen][type][zone], + lrugen->nr_pages[gen][type][zone] + delta); + + if (lru_gen_is_active(lruvec, gen)) + lru += LRU_ACTIVE; + update_lru_size(lruvec, lru, zone, delta); + } +} + +static int should_skip_vma(unsigned long start, unsigned long end, struct mm_walk *walk) +{ + struct address_space *mapping; + struct vm_area_struct *vma = walk->vma; + struct lru_gen_mm_walk *priv = walk->private; + + if (!(vma->vm_flags & (VM_READ | VM_EXEC | VM_WRITE)) || is_vm_hugetlb_page(vma) || + (vma->vm_flags & (VM_LOCKED | VM_SPECIAL | VM_SEQ_READ | VM_RAND_READ)) || + vma == get_gate_vma(vma->vm_mm)) + return true; + + if (vma_is_anonymous(vma)) + return !priv->can_swap; + + if (WARN_ON_ONCE(!vma->vm_file || !vma->vm_file->f_mapping)) + return true; + + mapping = vma->vm_file->f_mapping; + if (mapping_unevictable(mapping)) + return true; + + /* check readpage to exclude special mappings like dax, etc. */ + return shmem_mapping(mapping) ? !priv->can_swap : !mapping->a_ops->readpage; +} + +/* + * Some userspace memory allocators map many single-page VMAs. Instead of + * returning back to the PGD table for each of such VMAs, finish an entire PMD + * table to reduce zigzags and improve cache performance. + */ +static bool get_next_vma(struct mm_walk *walk, unsigned long mask, unsigned long size, + unsigned long *start, unsigned long *end) +{ + unsigned long next = round_up(*end, size); + + VM_BUG_ON(mask & size); + VM_BUG_ON(*start >= *end); + VM_BUG_ON((next & mask) != (*start & mask)); + + while (walk->vma) { + if (next >= walk->vma->vm_end) { + walk->vma = walk->vma->vm_next; + continue; + } + + if ((next & mask) != (walk->vma->vm_start & mask)) + return false; + + if (should_skip_vma(walk->vma->vm_start, walk->vma->vm_end, walk)) { + walk->vma = walk->vma->vm_next; + continue; + } + + *start = max(next, walk->vma->vm_start); + next = (next | ~mask) + 1; + /* rounded-up boundaries can wrap to 0 */ + *end = next && next < walk->vma->vm_end ? next : walk->vma->vm_end; + + return true; + } + + return false; +} + +static bool suitable_to_scan(int total, int young) +{ + int n = clamp_t(int, cache_line_size() / sizeof(pte_t), 2, 8); + + /* suitable if the average number of young PTEs per cacheline is >=1 */ + return young * n >= total; +} + +static bool walk_pte_range(pmd_t *pmd, unsigned long start, unsigned long end, + struct mm_walk *walk) +{ + int i; + pte_t *pte; + spinlock_t *ptl; + unsigned long addr; + int total = 0; + int young = 0; + struct lru_gen_mm_walk *priv = walk->private; + struct mem_cgroup *memcg = lruvec_memcg(priv->lruvec); + struct pglist_data *pgdat = lruvec_pgdat(priv->lruvec); + int old_gen, new_gen = lru_gen_from_seq(priv->max_seq); + + VM_BUG_ON(pmd_trans_huge(*pmd) || pmd_devmap(*pmd)); + + ptl = pte_lockptr(walk->mm, pmd); + if (!spin_trylock(ptl)) + return false; + + arch_enter_lazy_mmu_mode(); + + pte = pte_offset_map(pmd, start & PMD_MASK); +restart: + i = (start >> PAGE_SHIFT) & (PTRS_PER_PTE - 1); + for (addr = start; addr != end; i++, addr += PAGE_SIZE) { + struct page *page; + unsigned long pfn = pte_pfn(pte[i]); + + VM_BUG_ON(addr < walk->vma->vm_start || addr >= walk->vma->vm_end); + + total++; + priv->mm_stats[MM_PTE_TOTAL]++; + + if (!pte_present(pte[i]) || is_zero_pfn(pfn)) + continue; + + if (WARN_ON_ONCE(pte_devmap(pte[i]) || pte_special(pte[i]))) + continue; + + if (!pte_young(pte[i])) { + priv->mm_stats[MM_PTE_OLD]++; + continue; + } + + VM_BUG_ON(!pfn_valid(pfn)); + if (pfn < pgdat->node_start_pfn || pfn >= pgdat_end_pfn(pgdat)) + continue; + + page = compound_head(pfn_to_page(pfn)); + if (page_to_nid(page) != pgdat->node_id) + continue; + + if (page_memcg_rcu(page) != memcg) + continue; + + if (!ptep_test_and_clear_young(walk->vma, addr, pte + i)) + continue; + + young++; + priv->mm_stats[MM_PTE_YOUNG]++; + + if (pte_dirty(pte[i]) && !PageDirty(page) && + !(PageAnon(page) && PageSwapBacked(page) && !PageSwapCache(page))) + set_page_dirty(page); + + old_gen = page_update_gen(page, new_gen); + if (old_gen >= 0 && old_gen != new_gen) + update_batch_size(priv, page, old_gen, new_gen); + } + + if (i < PTRS_PER_PTE && get_next_vma(walk, PMD_MASK, PAGE_SIZE, &start, &end)) + goto restart; + + pte_unmap(pte); + + arch_leave_lazy_mmu_mode(); + spin_unlock(ptl); + + return suitable_to_scan(total, young); +} + +#if defined(CONFIG_TRANSPARENT_HUGEPAGE) || defined(CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG) +static void walk_pmd_range_locked(pud_t *pud, unsigned long next, struct vm_area_struct *vma, + struct mm_walk *walk, unsigned long *start) +{ + int i; + pmd_t *pmd; + spinlock_t *ptl; + struct lru_gen_mm_walk *priv = walk->private; + struct mem_cgroup *memcg = lruvec_memcg(priv->lruvec); + struct pglist_data *pgdat = lruvec_pgdat(priv->lruvec); + int old_gen, new_gen = lru_gen_from_seq(priv->max_seq); + + VM_BUG_ON(pud_trans_huge(*pud) || pud_devmap(*pud)); + + /* try to batch at most 1+MIN_LRU_BATCH+1 entries */ + if (*start == -1) { + *start = next; + return; + } + + i = next == -1 ? 0 : ((next - *start) >> PMD_SHIFT) & (PTRS_PER_PMD - 1); + if (i && i <= MIN_LRU_BATCH) { + __set_bit(i - 1, priv->bitmap); + return; + } + + pmd = pmd_offset(pud, *start); + + ptl = pmd_lockptr(walk->mm, pmd); + if (!spin_trylock(ptl)) + goto done; + + arch_enter_lazy_mmu_mode(); + + do { + struct page *page; + unsigned long pfn = pmd_pfn(pmd[i]); + unsigned long addr = i ? (*start & PMD_MASK) + i * PMD_SIZE : *start; + + VM_BUG_ON(addr < vma->vm_start || addr >= vma->vm_end); + + if (!pmd_present(pmd[i]) || is_huge_zero_pmd(pmd[i])) + goto next; + + if (WARN_ON_ONCE(pmd_devmap(pmd[i]))) + goto next; + + if (!pmd_trans_huge(pmd[i])) { + if (IS_ENABLED(CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG) && + get_cap(LRU_GEN_NONLEAF_YOUNG)) + pmdp_test_and_clear_young(vma, addr, pmd + i); + goto next; + } + + VM_BUG_ON(!pfn_valid(pfn)); + if (pfn < pgdat->node_start_pfn || pfn >= pgdat_end_pfn(pgdat)) + goto next; + + page = pfn_to_page(pfn); + VM_BUG_ON_PAGE(PageTail(page), page); + if (page_to_nid(page) != pgdat->node_id) + goto next; + + if (page_memcg_rcu(page) != memcg) + goto next; + + if (!pmdp_test_and_clear_young(vma, addr, pmd + i)) + goto next; + + priv->mm_stats[MM_PTE_YOUNG]++; + + if (pmd_dirty(pmd[i]) && !PageDirty(page) && + !(PageAnon(page) && PageSwapBacked(page) && !PageSwapCache(page))) + set_page_dirty(page); + + old_gen = page_update_gen(page, new_gen); + if (old_gen >= 0 && old_gen != new_gen) + update_batch_size(priv, page, old_gen, new_gen); +next: + i = i > MIN_LRU_BATCH ? 0 : + find_next_bit(priv->bitmap, MIN_LRU_BATCH, i) + 1; + } while (i <= MIN_LRU_BATCH); + + arch_leave_lazy_mmu_mode(); + spin_unlock(ptl); +done: + *start = -1; + bitmap_zero(priv->bitmap, MIN_LRU_BATCH); +} +#else +static void walk_pmd_range_locked(pud_t *pud, unsigned long next, struct vm_area_struct *vma, + struct mm_walk *walk, unsigned long *start) +{ +} +#endif + +static void walk_pmd_range(pud_t *pud, unsigned long start, unsigned long end, + struct mm_walk *walk) +{ + int i; + pmd_t *pmd; + unsigned long next; + unsigned long addr; + struct vm_area_struct *vma; + unsigned long pos = -1; + struct lru_gen_mm_walk *priv = walk->private; + + VM_BUG_ON(pud_trans_huge(*pud) || pud_devmap(*pud)); + + /* + * Finish an entire PMD in two passes: the first only reaches to PTE + * tables to avoid taking the PMD lock; the second, if necessary, takes + * the PMD lock to clear the accessed bit in PMD entries. + */ + pmd = pmd_offset(pud, start & PUD_MASK); +restart: + /* walk_pte_range() may call get_next_vma() */ + vma = walk->vma; + i = (start >> PMD_SHIFT) & (PTRS_PER_PMD - 1); + for (addr = start; addr != end; i++, addr = next) { + pmd_t val = pmd_read_atomic(pmd + i); + + /* for pmd_read_atomic() */ + barrier(); + + next = pmd_addr_end(addr, end); + + if (!pmd_present(val)) { + priv->mm_stats[MM_PTE_TOTAL]++; + continue; + } + +#ifdef CONFIG_TRANSPARENT_HUGEPAGE + if (pmd_trans_huge(val)) { + unsigned long pfn = pmd_pfn(val); + struct pglist_data *pgdat = lruvec_pgdat(priv->lruvec); + + priv->mm_stats[MM_PTE_TOTAL]++; + + if (is_huge_zero_pmd(val)) + continue; + + if (!pmd_young(val)) { + priv->mm_stats[MM_PTE_OLD]++; + continue; + } + + if (pfn < pgdat->node_start_pfn || pfn >= pgdat_end_pfn(pgdat)) + continue; + + walk_pmd_range_locked(pud, addr, vma, walk, &pos); + continue; + } +#endif + priv->mm_stats[MM_PMD_TOTAL]++; + +#ifdef CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG + if (get_cap(LRU_GEN_NONLEAF_YOUNG)) { + if (!pmd_young(val)) + continue; + + walk_pmd_range_locked(pud, addr, vma, walk, &pos); + } +#endif + if (!priv->full_scan && !test_bloom_filter(priv->lruvec, priv->max_seq, pmd + i)) + continue; + + priv->mm_stats[MM_PMD_FOUND]++; + + if (!walk_pte_range(&val, addr, next, walk)) + continue; + + priv->mm_stats[MM_PMD_ADDED]++; + + /* carry over to the next generation */ + update_bloom_filter(priv->lruvec, priv->max_seq + 1, pmd + i); + } + + walk_pmd_range_locked(pud, -1, vma, walk, &pos); + + if (i < PTRS_PER_PMD && get_next_vma(walk, PUD_MASK, PMD_SIZE, &start, &end)) + goto restart; +} + +static int walk_pud_range(p4d_t *p4d, unsigned long start, unsigned long end, + struct mm_walk *walk) +{ + int i; + pud_t *pud; + unsigned long addr; + unsigned long next; + struct lru_gen_mm_walk *priv = walk->private; + + pud = pud_offset(p4d, start & P4D_MASK); +restart: + i = (start >> PUD_SHIFT) & (PTRS_PER_PUD - 1); + for (addr = start; addr != end; i++, addr = next) { + pud_t val = READ_ONCE(pud[i]); + + next = pud_addr_end(addr, end); + + if (!pud_present(val) || WARN_ON_ONCE(pud_trans_huge(val) || pud_devmap(val))) + continue; + + walk_pmd_range(&val, addr, next, walk); + + if (priv->batched >= MAX_LRU_BATCH) { + end = (addr | ~PUD_MASK) + 1; + goto done; + } + } + + if (i < PTRS_PER_PUD && get_next_vma(walk, P4D_MASK, PUD_SIZE, &start, &end)) + goto restart; + + end = round_up(end, P4D_SIZE); +done: + /* rounded-up boundaries can wrap to 0 */ + priv->next_addr = end && walk->vma ? max(end, walk->vma->vm_start) : 0; + + return -EAGAIN; +} + +static void walk_mm(struct lruvec *lruvec, struct mm_struct *mm, struct lru_gen_mm_walk *walk) +{ + int err; + struct mem_cgroup *memcg = lruvec_memcg(lruvec); + struct pglist_data *pgdat = lruvec_pgdat(lruvec); + struct mm_walk args = { + .mm = mm, + .private = walk, + .test_walk = should_skip_vma, + .p4d_entry = walk_pud_range, + }; + + walk->next_addr = FIRST_USER_ADDRESS; + + do { + err = -EBUSY; + + /* page_update_gen() requires stable page_memcg() */ + if (!mem_cgroup_trylock_pages(memcg)) + break; + + /* the caller might be holding the lock for write */ + if (down_read_trylock(&mm->mmap_sem)) { + unsigned long start = walk->next_addr; + unsigned long end = mm->highest_vm_end; + + err = walk_page_range(start, end, &args); + + up_read(&mm->mmap_sem); + + if (walk->batched) { + spin_lock_irq(&pgdat->lru_lock); + reset_batch_size(lruvec, walk); + spin_unlock_irq(&pgdat->lru_lock); + } + } + + mem_cgroup_unlock_pages(); + + cond_resched(); + } while (err == -EAGAIN && walk->next_addr && !mm_is_oom_victim(mm)); +} + +static struct lru_gen_mm_walk *alloc_mm_walk(void) +{ + if (current->reclaim_state && current->reclaim_state->mm_walk) + return current->reclaim_state->mm_walk; + + return kzalloc(sizeof(struct lru_gen_mm_walk), + __GFP_HIGH | __GFP_NOMEMALLOC | __GFP_NOWARN); +} + +static void free_mm_walk(struct lru_gen_mm_walk *walk) +{ + if (!current->reclaim_state || !current->reclaim_state->mm_walk) + kfree(walk); +} + +static void inc_min_seq(struct lruvec *lruvec) +{ + int type; + struct lru_gen_struct *lrugen = &lruvec->lrugen; + + VM_BUG_ON(!seq_is_valid(lruvec)); + + for (type = 0; type < ANON_AND_FILE; type++) { + if (get_nr_gens(lruvec, type) != MAX_NR_GENS) + continue; + + reset_ctrl_pos(lruvec, type, true); + WRITE_ONCE(lrugen->min_seq[type], lrugen->min_seq[type] + 1); + } +} + +static bool try_to_inc_min_seq(struct lruvec *lruvec, bool can_swap) +{ + int gen, type, zone; + bool success = false; + struct lru_gen_struct *lrugen = &lruvec->lrugen; + DEFINE_MIN_SEQ(lruvec); + + VM_BUG_ON(!seq_is_valid(lruvec)); + + for (type = !can_swap; type < ANON_AND_FILE; type++) { + while (min_seq[type] + MIN_NR_GENS <= lrugen->max_seq) { + gen = lru_gen_from_seq(min_seq[type]); + + for (zone = 0; zone < MAX_NR_ZONES; zone++) { + if (!list_empty(&lrugen->lists[gen][type][zone])) + goto next; + } + + min_seq[type]++; + } +next: + ; + } + + /* see the comment on lru_gen_struct */ + if (can_swap) { + min_seq[LRU_GEN_ANON] = min(min_seq[LRU_GEN_ANON], min_seq[LRU_GEN_FILE]); + min_seq[LRU_GEN_FILE] = max(min_seq[LRU_GEN_ANON], lrugen->min_seq[LRU_GEN_FILE]); + } + + for (type = !can_swap; type < ANON_AND_FILE; type++) { + if (min_seq[type] == lrugen->min_seq[type]) + continue; + + reset_ctrl_pos(lruvec, type, true); + WRITE_ONCE(lrugen->min_seq[type], min_seq[type]); + success = true; + } + + return success; +} + +static void inc_max_seq(struct lruvec *lruvec) +{ + int prev, next; + int type, zone; + struct lru_gen_struct *lrugen = &lruvec->lrugen; + struct pglist_data *pgdat = lruvec_pgdat(lruvec); + + spin_lock_irq(&pgdat->lru_lock); + + VM_BUG_ON(!seq_is_valid(lruvec)); + + inc_min_seq(lruvec); + + /* + * Update the active/inactive LRU sizes for compatibility. Both sides of + * the current max_seq need to be covered, since max_seq+1 can overlap + * with min_seq[LRU_GEN_ANON] if swapping is constrained. And if they do + * overlap, cold/hot inversion happens. This can be solved by moving + * pages from min_seq to min_seq+1 but is omitted for simplicity. + */ + prev = lru_gen_from_seq(lrugen->max_seq - 1); + next = lru_gen_from_seq(lrugen->max_seq + 1); + + for (type = 0; type < ANON_AND_FILE; type++) { + for (zone = 0; zone < MAX_NR_ZONES; zone++) { + enum lru_list lru = type * LRU_INACTIVE_FILE; + long delta = lrugen->nr_pages[prev][type][zone] - + lrugen->nr_pages[next][type][zone]; + + if (!delta) + continue; + + WARN_ON_ONCE(delta != (int)delta); + + update_lru_size(lruvec, lru, zone, delta); + update_lru_size(lruvec, lru + LRU_ACTIVE, zone, -delta); + } + } + + for (type = 0; type < ANON_AND_FILE; type++) + reset_ctrl_pos(lruvec, type, false); + + WRITE_ONCE(lrugen->timestamps[next], jiffies); + /* make sure preceding modifications appear */ + smp_store_release(&lrugen->max_seq, lrugen->max_seq + 1); + + spin_unlock_irq(&pgdat->lru_lock); +} + +static bool try_to_inc_max_seq(struct lruvec *lruvec, unsigned long max_seq, + struct scan_control *sc, bool can_swap, bool full_scan) +{ + bool success; + struct lru_gen_mm_walk *walk; + struct mm_struct *mm = NULL; + struct lru_gen_struct *lrugen = &lruvec->lrugen; + + VM_BUG_ON(max_seq > READ_ONCE(lrugen->max_seq)); + + /* + * If the hardware doesn't automatically set the accessed bit, fallback + * to lru_gen_look_around(), which only clears the accessed bit in a + * handful of PTEs. Spreading the work out over a period of time usually + * is less efficient, but it avoids bursty page faults. + */ + if (!full_scan && (!arch_has_hw_pte_young() || !get_cap(LRU_GEN_MM_WALK))) { + success = iterate_mm_list_nowalk(lruvec, max_seq); + goto done; + } + + walk = alloc_mm_walk(); + if (!walk) { + success = iterate_mm_list_nowalk(lruvec, max_seq); + goto done; + } + + walk->lruvec = lruvec; + walk->max_seq = max_seq; + walk->can_swap = can_swap; + walk->full_scan = full_scan; + + do { + success = iterate_mm_list(lruvec, walk, &mm); + if (mm) + walk_mm(lruvec, mm, walk); + + cond_resched(); + } while (mm); + + free_mm_walk(walk); +done: + if (!success) { + if (!current_is_kswapd() && !sc->priority) + wait_event_killable(lruvec->mm_state.wait, + max_seq < READ_ONCE(lrugen->max_seq)); + + return max_seq < READ_ONCE(lrugen->max_seq); + } + + VM_BUG_ON(max_seq != READ_ONCE(lrugen->max_seq)); + + inc_max_seq(lruvec); + /* either this sees any waiters or they will see updated max_seq */ + if (wq_has_sleeper(&lruvec->mm_state.wait)) + wake_up_all(&lruvec->mm_state.wait); + + wakeup_flusher_threads(WB_REASON_VMSCAN); + + return true; +} + +static long get_nr_evictable(struct lruvec *lruvec, unsigned long max_seq, + unsigned long *min_seq, bool can_swap, bool *need_aging) +{ + int gen, type, zone; + long old = 0; + long young = 0; + long total = 0; + struct lru_gen_struct *lrugen = &lruvec->lrugen; + + for (type = !can_swap; type < ANON_AND_FILE; type++) { + unsigned long seq; + + for (seq = min_seq[type]; seq <= max_seq; seq++) { + long size = 0; + + gen = lru_gen_from_seq(seq); + + for (zone = 0; zone < MAX_NR_ZONES; zone++) + size += READ_ONCE(lrugen->nr_pages[gen][type][zone]); + + total += size; + if (seq == max_seq) + young += size; + if (seq + MIN_NR_GENS == max_seq) + old += size; + } + } + + /* + * The aging and the eviction is a typical producer-consumer model. The + * aging tries to be lazy to reduce the unnecessary overhead. On the + * other hand, the eviction stalls when the number of generations + * reaches MIN_NR_GENS. So ideally, there should be MIN_NR_GENS+1 + * generations, hence the first two if's. + * + * In addition, it's ideal to spread pages out evenly, meaning + * 1/(MIN_NR_GENS+1) of the total number of pages for each generation. A + * reasonable range for this average portion would [1/MIN_NR_GENS, + * 1/(MIN_NR_GENS+2)]. From the consumer's POV, the eviction only cares + * about the lower bound of cold pages, i.e., 1/(MIN_NR_GENS+2), whereas + * from the producer's POV, the aging only cares about the upper bound + * of hot pages, i.e., 1/MIN_NR_GENS. + */ + if (min_seq[!can_swap] + MIN_NR_GENS > max_seq) + *need_aging = true; + else if (min_seq[!can_swap] + MIN_NR_GENS < max_seq) + *need_aging = false; + else if (young * MIN_NR_GENS > total) + *need_aging = true; + else if (old * (MIN_NR_GENS + 2) < total) + *need_aging = true; + else + *need_aging = false; + + return total > 0 ? total : 0; +} + +static bool age_lruvec(struct lruvec *lruvec, struct scan_control *sc, + unsigned long min_ttl) +{ + bool need_aging; + long nr_to_scan; + int swappiness = get_swappiness(lruvec, sc); + struct mem_cgroup *memcg = lruvec_memcg(lruvec); + enum mem_cgroup_protection prot = mem_cgroup_protected(NULL, memcg); + DEFINE_MAX_SEQ(lruvec); + DEFINE_MIN_SEQ(lruvec); + + if (min_ttl) { + int gen = lru_gen_from_seq(min_seq[LRU_GEN_FILE]); + unsigned long birth = READ_ONCE(lruvec->lrugen.timestamps[gen]); + + if (time_is_after_jiffies(birth + min_ttl)) + return false; + } + + if (prot == MEMCG_PROT_MIN) + return false; + + nr_to_scan = get_nr_evictable(lruvec, max_seq, min_seq, swappiness, &need_aging); + if (!nr_to_scan) + return false; + + nr_to_scan >>= sc->priority; + + if (!mem_cgroup_online(memcg)) + nr_to_scan++; + + if (nr_to_scan && need_aging && (prot != MEMCG_PROT_LOW || sc->memcg_low_reclaim)) + try_to_inc_max_seq(lruvec, max_seq, sc, swappiness, false); + + return true; +} + +/* to protect the working set of the last N jiffies */ +static unsigned long lru_gen_min_ttl __read_mostly; + +static void lru_gen_age_node(struct pglist_data *pgdat, struct scan_control *sc) +{ + struct mem_cgroup *memcg; + bool success = false; + unsigned long min_ttl = READ_ONCE(lru_gen_min_ttl); + + VM_BUG_ON(!current_is_kswapd()); + + /* + * To reduce the chance of going into the aging path or swapping, which + * can be costly, optimistically skip them unless their corresponding + * flags were cleared in the eviction path. This improves the overall + * performance when multiple memcgs are available. + */ + if (!sc->memcgs_need_aging) { + sc->memcgs_need_aging = true; + sc->memcgs_avoid_swapping = !sc->memcgs_need_swapping; + sc->memcgs_need_swapping = true; + return; + } + + sc->memcgs_need_swapping = true; + sc->memcgs_avoid_swapping = true; + + current->reclaim_state->mm_walk = &pgdat->mm_walk; + + memcg = mem_cgroup_iter(NULL, NULL, NULL); + do { + struct lruvec *lruvec = mem_cgroup_lruvec(pgdat, memcg); + + if (age_lruvec(lruvec, sc, min_ttl)) + success = true; + + cond_resched(); + } while ((memcg = mem_cgroup_iter(NULL, memcg, NULL))); + + current->reclaim_state->mm_walk = NULL; + + /* + * The main goal is to OOM kill if every generation from all memcgs is + * younger than min_ttl. However, another theoretical possibility is all + * memcgs are either below min or empty. + */ + if (!success && !sc->order && mutex_trylock(&oom_lock)) { + struct oom_control oc = { + .gfp_mask = sc->gfp_mask, + }; + + out_of_memory(&oc); + + mutex_unlock(&oom_lock); + } +} + +/* + * This function exploits spatial locality when shrink_page_list() walks the + * rmap. It scans the adjacent PTEs of a young PTE and promotes hot pages. + * If the scan was done cacheline efficiently, it adds the PMD entry pointing + * to the PTE table to the Bloom filter. This process is a feedback loop from + * the eviction to the aging. + */ +void lru_gen_look_around(struct page_vma_mapped_walk *pvmw) +{ + int i; + pte_t *pte; + unsigned long start; + unsigned long end; + unsigned long addr; + struct page *page; + struct lru_gen_mm_walk *walk; + int young = 0; + unsigned long bitmap[BITS_TO_LONGS(MIN_LRU_BATCH)] = {}; + struct mem_cgroup *memcg = page_memcg(pvmw->page); + struct pglist_data *pgdat = page_pgdat(pvmw->page); + struct lruvec *lruvec = mem_cgroup_lruvec(pgdat, memcg); + DEFINE_MAX_SEQ(lruvec); + int old_gen, new_gen = lru_gen_from_seq(max_seq); + + lockdep_assert_held(pvmw->ptl); + VM_BUG_ON_PAGE(PageLRU(pvmw->page), pvmw->page); + + if (spin_is_contended(pvmw->ptl)) + return; + + start = max(pvmw->address & PMD_MASK, pvmw->vma->vm_start); + end = min(pvmw->address | ~PMD_MASK, pvmw->vma->vm_end - 1) + 1; + + if (end - start > MIN_LRU_BATCH * PAGE_SIZE) { + if (pvmw->address - start < MIN_LRU_BATCH * PAGE_SIZE / 2) + end = start + MIN_LRU_BATCH * PAGE_SIZE; + else if (end - pvmw->address < MIN_LRU_BATCH * PAGE_SIZE / 2) + start = end - MIN_LRU_BATCH * PAGE_SIZE; + else { + start = pvmw->address - MIN_LRU_BATCH * PAGE_SIZE / 2; + end = pvmw->address + MIN_LRU_BATCH * PAGE_SIZE / 2; + } + } + + pte = pvmw->pte - (pvmw->address - start) / PAGE_SIZE; + + rcu_read_lock(); + arch_enter_lazy_mmu_mode(); + + for (i = 0, addr = start; addr != end; i++, addr += PAGE_SIZE) { + unsigned long pfn = pte_pfn(pte[i]); + + VM_BUG_ON(addr < pvmw->vma->vm_start || addr >= pvmw->vma->vm_end); + + if (!pte_present(pte[i]) || is_zero_pfn(pfn)) + continue; + + if (WARN_ON_ONCE(pte_devmap(pte[i]) || pte_special(pte[i]))) + continue; + + if (!pte_young(pte[i])) + continue; + + VM_BUG_ON(!pfn_valid(pfn)); + if (pfn < pgdat->node_start_pfn || pfn >= pgdat_end_pfn(pgdat)) + continue; + + page = compound_head(pfn_to_page(pfn)); + if (page_to_nid(page) != pgdat->node_id) + continue; + + if (page_memcg_rcu(page) != memcg) + continue; + + if (!ptep_test_and_clear_young(pvmw->vma, addr, pte + i)) + continue; + + young++; + + if (pte_dirty(pte[i]) && !PageDirty(page) && + !(PageAnon(page) && PageSwapBacked(page) && !PageSwapCache(page))) + set_page_dirty(page); + + old_gen = page_lru_gen(page); + if (old_gen < 0) + SetPageReferenced(page); + else if (old_gen != new_gen) + __set_bit(i, bitmap); + } + + arch_leave_lazy_mmu_mode(); + rcu_read_unlock(); + + /* feedback from rmap walkers to page table walkers */ + if (suitable_to_scan(i, young)) + update_bloom_filter(lruvec, max_seq, pvmw->pmd); + + walk = current->reclaim_state ? current->reclaim_state->mm_walk : NULL; + + if (!walk && bitmap_weight(bitmap, MIN_LRU_BATCH) < PAGEVEC_SIZE) { + for_each_set_bit(i, bitmap, MIN_LRU_BATCH) + activate_page(pte_page(pte[i])); + return; + } + + /* page_update_gen() requires stable page_memcg() */ + if (!mem_cgroup_trylock_pages(memcg)) + return; + + if (!walk) { + spin_lock_irq(&pgdat->lru_lock); + new_gen = lru_gen_from_seq(lruvec->lrugen.max_seq); + } + + for_each_set_bit(i, bitmap, MIN_LRU_BATCH) { + page = compound_head(pte_page(pte[i])); + if (page_memcg_rcu(page) != memcg) + continue; + + old_gen = page_update_gen(page, new_gen); + if (old_gen < 0 || old_gen == new_gen) + continue; + + if (walk) + update_batch_size(walk, page, old_gen, new_gen); + else + lru_gen_update_size(lruvec, page, old_gen, new_gen); + } + + if (!walk) + spin_unlock_irq(&pgdat->lru_lock); + + mem_cgroup_unlock_pages(); +} + +/****************************************************************************** + * the eviction + ******************************************************************************/ + +static bool sort_page(struct lruvec *lruvec, struct page *page, int tier_idx) +{ + bool success; + int gen = page_lru_gen(page); + int type = page_is_file_cache(page); + int zone = page_zonenum(page); + int tier = page_lru_tier(page); + int delta = hpage_nr_pages(page); + struct lru_gen_struct *lrugen = &lruvec->lrugen; + + VM_BUG_ON_PAGE(gen >= MAX_NR_GENS, page); + + if (!page_evictable(page)) { + success = lru_gen_del_page(lruvec, page, true); + VM_BUG_ON_PAGE(!success, page); + SetPageUnevictable(page); + add_page_to_lru_list(page, lruvec); + __count_vm_events(UNEVICTABLE_PGCULLED, delta); + return true; + } + + if (type == LRU_GEN_FILE && PageAnon(page) && PageDirty(page)) { + success = lru_gen_del_page(lruvec, page, true); + VM_BUG_ON_PAGE(!success, page); + SetPageSwapBacked(page); + add_page_to_lru_list_tail(page, lruvec); + return true; + } + + if (gen != lru_gen_from_seq(lrugen->min_seq[type])) { + list_move(&page->lru, &lrugen->lists[gen][type][zone]); + return true; + } + + if (tier > tier_idx) { + int hist = lru_hist_from_seq(lrugen->min_seq[type]); + + gen = page_inc_gen(lruvec, page, false); + list_move_tail(&page->lru, &lrugen->lists[gen][type][zone]); + + WRITE_ONCE(lrugen->protected[hist][type][tier - 1], + lrugen->protected[hist][type][tier - 1] + delta); + __mod_lruvec_state(lruvec, WORKINGSET_ACTIVATE, delta); + return true; + } + + if (PageLocked(page) || PageWriteback(page) || + (type == LRU_GEN_FILE && PageDirty(page))) { + gen = page_inc_gen(lruvec, page, true); + list_move(&page->lru, &lrugen->lists[gen][type][zone]); + return true; + } + + return false; +} + +static bool isolate_page(struct lruvec *lruvec, struct page *page, struct scan_control *sc) +{ + bool success; + + if (!sc->may_unmap && page_mapped(page)) + return false; + + if (!(sc->may_writepage && (sc->gfp_mask & __GFP_IO)) && + (PageDirty(page) || (PageAnon(page) && !PageSwapCache(page)))) + return false; + + if (!get_page_unless_zero(page)) + return false; + + ClearPageLRU(page); + + success = lru_gen_del_page(lruvec, page, true); + VM_BUG_ON_PAGE(!success, page); + + return true; +} + +static int scan_pages(struct lruvec *lruvec, struct scan_control *sc, + int type, int tier, struct list_head *list) +{ + int gen, zone; + enum vm_event_item item; + int sorted = 0; + int scanned = 0; + int isolated = 0; + int remaining = MAX_LRU_BATCH; + struct lru_gen_struct *lrugen = &lruvec->lrugen; + struct mem_cgroup *memcg = lruvec_memcg(lruvec); + + VM_BUG_ON(!list_empty(list)); + + if (get_nr_gens(lruvec, type) == MIN_NR_GENS) + return 0; + + gen = lru_gen_from_seq(lrugen->min_seq[type]); + + for (zone = sc->reclaim_idx; zone >= 0; zone--) { + LIST_HEAD(moved); + int skipped = 0; + struct list_head *head = &lrugen->lists[gen][type][zone]; + + while (!list_empty(head)) { + struct page *page = lru_to_page(head); + int delta = hpage_nr_pages(page); + + VM_BUG_ON_PAGE(PageTail(page), page); + VM_BUG_ON_PAGE(PageUnevictable(page), page); + VM_BUG_ON_PAGE(PageActive(page), page); + VM_BUG_ON_PAGE(page_is_file_cache(page) != type, page); + VM_BUG_ON_PAGE(page_zonenum(page) != zone, page); + + prefetchw_prev_lru_page(page, head, flags); + + scanned += delta; + + if (sort_page(lruvec, page, tier)) + sorted += delta; + else if (isolate_page(lruvec, page, sc)) { + list_add(&page->lru, list); + isolated += delta; + } else { + list_move(&page->lru, &moved); + skipped += delta; + } + + if (!--remaining || max(isolated, skipped) >= MIN_LRU_BATCH) + break; + } + + if (skipped) { + list_splice(&moved, head); + __count_zid_vm_events(PGSCAN_SKIP, zone, skipped); + } + + if (!remaining || isolated >= MIN_LRU_BATCH) + break; + } + + item = current_is_kswapd() ? PGSCAN_KSWAPD : PGSCAN_DIRECT; + if (global_reclaim(sc)) { + __count_vm_events(item, isolated); + __count_vm_events(PGREFILL, sorted); + } + __count_memcg_events(memcg, item, isolated); + __count_memcg_events(memcg, PGREFILL, sorted); + + /* + * There might not be eligible pages due to reclaim_idx, may_unmap and + * may_writepage. Check the remaining to prevent livelock if there is no + * progress. + */ + return isolated || !remaining ? scanned : 0; +} + +static int get_tier_idx(struct lruvec *lruvec, int type) +{ + int tier; + struct ctrl_pos sp, pv; + + /* + * To leave a margin for fluctuations, use a larger gain factor (1:2). + * This value is chosen because any other tier would have at least twice + * as many refaults as the first tier. + */ + read_ctrl_pos(lruvec, type, 0, 1, &sp); + for (tier = 1; tier < MAX_NR_TIERS; tier++) { + read_ctrl_pos(lruvec, type, tier, 2, &pv); + if (!positive_ctrl_err(&sp, &pv)) + break; + } + + return tier - 1; +} + +static int get_type_to_scan(struct lruvec *lruvec, int swappiness, int *tier_idx) +{ + int type, tier; + struct ctrl_pos sp, pv; + int gain[ANON_AND_FILE] = { swappiness, 200 - swappiness }; + + /* + * Compare the first tier of anon with that of file to determine which + * type to scan. Also need to compare other tiers of the selected type + * with the first tier of the other type to determine the last tier (of + * the selected type) to evict. + */ + read_ctrl_pos(lruvec, LRU_GEN_ANON, 0, gain[LRU_GEN_ANON], &sp); + read_ctrl_pos(lruvec, LRU_GEN_FILE, 0, gain[LRU_GEN_FILE], &pv); + type = positive_ctrl_err(&sp, &pv); + + read_ctrl_pos(lruvec, !type, 0, gain[!type], &sp); + for (tier = 1; tier < MAX_NR_TIERS; tier++) { + read_ctrl_pos(lruvec, type, tier, gain[type], &pv); + if (!positive_ctrl_err(&sp, &pv)) + break; + } + + *tier_idx = tier - 1; + + return type; +} + +static int isolate_pages(struct lruvec *lruvec, struct scan_control *sc, int swappiness, + int *type_scanned, struct list_head *list) +{ + int i; + int type; + int scanned; + int tier = -1; + DEFINE_MIN_SEQ(lruvec); + + VM_BUG_ON(!seq_is_valid(lruvec)); + + /* + * Try to make the obvious choice first. When anon and file are both + * available from the same generation, interpret swappiness 1 as file + * first and 200 as anon first. + */ + if (!swappiness) + type = LRU_GEN_FILE; + else if (min_seq[LRU_GEN_ANON] < min_seq[LRU_GEN_FILE]) + type = LRU_GEN_ANON; + else if (swappiness == 1) + type = LRU_GEN_FILE; + else if (swappiness == 200) + type = LRU_GEN_ANON; + else + type = get_type_to_scan(lruvec, swappiness, &tier); + + for (i = !swappiness; i < ANON_AND_FILE; i++) { + if (tier < 0) + tier = get_tier_idx(lruvec, type); + + scanned = scan_pages(lruvec, sc, type, tier, list); + if (scanned) + break; + + type = !type; + tier = -1; + } + + *type_scanned = type; + + return scanned; +} + +static int evict_pages(struct lruvec *lruvec, struct scan_control *sc, int swappiness, + bool *swapped) +{ + int type; + int scanned; + int reclaimed; + LIST_HEAD(list); + struct page *page; + enum vm_event_item item; + struct lru_gen_mm_walk *walk; + struct mem_cgroup *memcg = lruvec_memcg(lruvec); + struct pglist_data *pgdat = lruvec_pgdat(lruvec); + + spin_lock_irq(&pgdat->lru_lock); + + scanned = isolate_pages(lruvec, sc, swappiness, &type, &list); + + if (try_to_inc_min_seq(lruvec, swappiness)) + scanned++; + + if (get_nr_gens(lruvec, !swappiness) == MIN_NR_GENS) + scanned = 0; + + spin_unlock_irq(&pgdat->lru_lock); + + if (list_empty(&list)) + return scanned; + + reclaimed = shrink_page_list(&list, pgdat, sc, 0, NULL, false); + + /* + * To avoid livelock, don't add rejected pages back to the same lists + * they were isolated from. See lru_gen_add_page(). + */ + list_for_each_entry(page, &list, lru) { + ClearPageReferenced(page); + ClearPageWorkingset(page); + + if (PageReclaim(page) && (PageDirty(page) || PageWriteback(page))) + ClearPageActive(page); + else + SetPageActive(page); + } + + spin_lock_irq(&pgdat->lru_lock); + + putback_inactive_pages(lruvec, &list); + + walk = current->reclaim_state ? current->reclaim_state->mm_walk : NULL; + if (walk && walk->batched) + reset_batch_size(lruvec, walk); + + item = current_is_kswapd() ? PGSTEAL_KSWAPD : PGSTEAL_DIRECT; + if (global_reclaim(sc)) + __count_vm_events(item, reclaimed); + __count_memcg_events(memcg, item, reclaimed); + + spin_unlock_irq(&pgdat->lru_lock); + + mem_cgroup_uncharge_list(&list); + free_unref_page_list(&list); + + sc->nr_reclaimed += reclaimed; + + if (type == LRU_GEN_ANON && swapped) + *swapped = true; + + return scanned; +} + +static long get_nr_to_scan(struct lruvec *lruvec, struct scan_control *sc, bool can_swap, + unsigned long reclaimed, bool *need_aging) +{ + int priority; + long nr_to_scan; + struct mem_cgroup *memcg = lruvec_memcg(lruvec); + DEFINE_MAX_SEQ(lruvec); + DEFINE_MIN_SEQ(lruvec); + + nr_to_scan = get_nr_evictable(lruvec, max_seq, min_seq, can_swap, need_aging); + if (!nr_to_scan) + return 0; + + /* adjust priority if memcg is offline or the target is met */ + if (!mem_cgroup_online(memcg)) + priority = 0; + else if (sc->nr_reclaimed - reclaimed >= sc->nr_to_reclaim) + priority = DEF_PRIORITY; + else + priority = sc->priority; + + nr_to_scan >>= priority; + if (!nr_to_scan) + return 0; + + if (!*need_aging) + return nr_to_scan; + + /* skip the aging path at the default priority */ + if (priority == DEF_PRIORITY) + return nr_to_scan; + + /* leave the work to lru_gen_age_node() */ + if (current_is_kswapd()) + return 0; + + if (try_to_inc_max_seq(lruvec, max_seq, sc, can_swap, false)) + return nr_to_scan; + + return min_seq[!can_swap] + MIN_NR_GENS <= max_seq ? nr_to_scan : 0; +} + +static void lru_gen_shrink_lruvec(struct lruvec *lruvec, struct scan_control *sc) +{ + struct blk_plug plug; + long scanned = 0; + bool need_aging = false; + bool swapped = false; + unsigned long reclaimed = sc->nr_reclaimed; + struct pglist_data *pgdat = lruvec_pgdat(lruvec); + + lru_add_drain(); + + blk_start_plug(&plug); + + if (current_is_kswapd()) + current->reclaim_state->mm_walk = &pgdat->mm_walk; + + while (true) { + int delta; + int swappiness; + long nr_to_scan; + + if (sc->may_swap) + swappiness = get_swappiness(lruvec, sc); + else if (global_reclaim(sc) && get_swappiness(lruvec, sc)) + swappiness = 1; + else + swappiness = 0; + + nr_to_scan = get_nr_to_scan(lruvec, sc, swappiness, reclaimed, &need_aging); + if (!nr_to_scan) + goto done; + + delta = evict_pages(lruvec, sc, swappiness, &swapped); + if (!delta) + goto done; + + if (sc->memcgs_avoid_swapping && swappiness < 200 && swapped) + break; + + scanned += delta; + if (scanned >= nr_to_scan) + break; + + cond_resched(); + } + + if (!need_aging) + sc->memcgs_need_aging = false; + if (!swapped) + sc->memcgs_need_swapping = false; +done: + if (current_is_kswapd()) + current->reclaim_state->mm_walk = NULL; + + blk_finish_plug(&plug); +} + +/****************************************************************************** + * state change + ******************************************************************************/ + +static bool __maybe_unused state_is_valid(struct lruvec *lruvec) +{ + struct lru_gen_struct *lrugen = &lruvec->lrugen; + + if (lrugen->enabled) { + enum lru_list lru; + + for_each_evictable_lru(lru) { + if (!list_empty(&lruvec->lists[lru])) + return false; + } + } else { + int gen, type, zone; + + for_each_gen_type_zone(gen, type, zone) { + if (!list_empty(&lrugen->lists[gen][type][zone])) + return false; + + /* unlikely but not a bug when reset_batch_size() is pending */ + VM_WARN_ON(lrugen->nr_pages[gen][type][zone]); + } + } + + return true; +} + +static bool fill_evictable(struct lruvec *lruvec) +{ + enum lru_list lru; + int remaining = MAX_LRU_BATCH; + + for_each_evictable_lru(lru) { + int type = is_file_lru(lru); + bool active = is_active_lru(lru); + struct list_head *head = &lruvec->lists[lru]; + + while (!list_empty(head)) { + bool success; + struct page *page = lru_to_page(head); + + VM_BUG_ON_PAGE(PageTail(page), page); + VM_BUG_ON_PAGE(PageUnevictable(page), page); + VM_BUG_ON_PAGE(PageActive(page) != active, page); + VM_BUG_ON_PAGE(page_is_file_cache(page) != type, page); + VM_BUG_ON_PAGE(page_lru_gen(page) < MAX_NR_GENS, page); + + prefetchw_prev_lru_page(page, head, flags); + + del_page_from_lru_list(page, lruvec); + success = lru_gen_add_page(lruvec, page, false); + VM_BUG_ON(!success); + + if (!--remaining) + return false; + } + } + + return true; +} + +static bool drain_evictable(struct lruvec *lruvec) +{ + int gen, type, zone; + int remaining = MAX_LRU_BATCH; + + for_each_gen_type_zone(gen, type, zone) { + struct list_head *head = &lruvec->lrugen.lists[gen][type][zone]; + + while (!list_empty(head)) { + bool success; + struct page *page = lru_to_page(head); + + VM_BUG_ON_PAGE(PageTail(page), page); + VM_BUG_ON_PAGE(PageUnevictable(page), page); + VM_BUG_ON_PAGE(PageActive(page), page); + VM_BUG_ON_PAGE(page_is_file_cache(page) != type, page); + VM_BUG_ON_PAGE(page_zonenum(page) != zone, page); + + prefetchw_prev_lru_page(page, head, flags); + + success = lru_gen_del_page(lruvec, page, false); + VM_BUG_ON(!success); + add_page_to_lru_list(page, lruvec); + + if (!--remaining) + return false; + } + } + + return true; +} + +static void lru_gen_change_state(bool enable) +{ + static DEFINE_MUTEX(state_mutex); + + struct mem_cgroup *memcg; + + cgroup_lock(); + cpus_read_lock(); + get_online_mems(); + mutex_lock(&state_mutex); + + if (enable == lru_gen_enabled()) + goto unlock; + + if (enable) + static_branch_enable_cpuslocked(&lru_gen_caps[LRU_GEN_CORE]); + else + static_branch_disable_cpuslocked(&lru_gen_caps[LRU_GEN_CORE]); + + memcg = mem_cgroup_iter(NULL, NULL, NULL); + do { + int nid; + + for_each_node(nid) { + struct pglist_data *pgdat = NODE_DATA(nid); + struct lruvec *lruvec = get_lruvec(memcg, nid); + + if (!lruvec) + continue; + + if (!pgdat) { + lruvec->lrugen.enabled = enable; + continue; + } + + spin_lock_irq(&pgdat->lru_lock); + + VM_BUG_ON(!seq_is_valid(lruvec)); + VM_BUG_ON(!state_is_valid(lruvec)); + + lruvec->lrugen.enabled = enable; + + while (!(enable ? fill_evictable(lruvec) : drain_evictable(lruvec))) { + spin_unlock_irq(&pgdat->lru_lock); + cond_resched(); + spin_lock_irq(&pgdat->lru_lock); + } + + spin_unlock_irq(&pgdat->lru_lock); + } + + cond_resched(); + } while ((memcg = mem_cgroup_iter(NULL, memcg, NULL))); +unlock: + mutex_unlock(&state_mutex); + put_online_mems(); + cpus_read_unlock(); + cgroup_unlock(); +} + +/****************************************************************************** + * sysfs interface + ******************************************************************************/ + +static ssize_t show_min_ttl(struct kobject *kobj, struct kobj_attribute *attr, char *buf) +{ + return sprintf(buf, "%u\n", jiffies_to_msecs(READ_ONCE(lru_gen_min_ttl))); +} + +static ssize_t store_min_ttl(struct kobject *kobj, struct kobj_attribute *attr, + const char *buf, size_t len) +{ + unsigned int msecs; + + if (kstrtouint(buf, 0, &msecs)) + return -EINVAL; + + WRITE_ONCE(lru_gen_min_ttl, msecs_to_jiffies(msecs)); + + return len; +} + +static struct kobj_attribute lru_gen_min_ttl_attr = __ATTR( + min_ttl_ms, 0644, show_min_ttl, store_min_ttl +); + +static ssize_t show_enable(struct kobject *kobj, struct kobj_attribute *attr, char *buf) +{ + unsigned int caps = 0; + + if (get_cap(LRU_GEN_CORE)) + caps |= BIT(LRU_GEN_CORE); + + if (arch_has_hw_pte_young() && get_cap(LRU_GEN_MM_WALK)) + caps |= BIT(LRU_GEN_MM_WALK); + + if (IS_ENABLED(CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG) && get_cap(LRU_GEN_NONLEAF_YOUNG)) + caps |= BIT(LRU_GEN_NONLEAF_YOUNG); + + return snprintf(buf, PAGE_SIZE, "0x%04x\n", caps); +} + +static ssize_t store_enable(struct kobject *kobj, struct kobj_attribute *attr, + const char *buf, size_t len) +{ + int i; + unsigned int caps; + + if (tolower(*buf) == 'n') + caps = 0; + else if (tolower(*buf) == 'y') + caps = -1; + else if (kstrtouint(buf, 0, &caps)) + return -EINVAL; + + for (i = 0; i < NR_LRU_GEN_CAPS; i++) { + bool enable = caps & BIT(i); + + if (i == LRU_GEN_CORE) + lru_gen_change_state(enable); + else if (enable) + static_branch_enable(&lru_gen_caps[i]); + else + static_branch_disable(&lru_gen_caps[i]); + } + pr_info("switch mglru_gen enabled: 0x%04x\n", caps); + return len; +} + +static struct kobj_attribute lru_gen_enabled_attr = __ATTR( + enabled, 0644, show_enable, store_enable +); + +static struct attribute *lru_gen_attrs[] = { + &lru_gen_min_ttl_attr.attr, + &lru_gen_enabled_attr.attr, + NULL +}; + +static struct attribute_group lru_gen_attr_group = { + .name = "lru_gen", + .attrs = lru_gen_attrs, +}; + +/****************************************************************************** + * debugfs interface + ******************************************************************************/ + +static void *lru_gen_seq_start(struct seq_file *m, loff_t *pos) +{ + struct mem_cgroup *memcg; + loff_t nr_to_skip = *pos; + + m->private = kvmalloc(PATH_MAX, GFP_KERNEL); + if (!m->private) + return ERR_PTR(-ENOMEM); + + memcg = mem_cgroup_iter(NULL, NULL, NULL); + do { + int nid; + + for_each_node_state(nid, N_MEMORY) { + if (!nr_to_skip--) + return get_lruvec(memcg, nid); + } + } while ((memcg = mem_cgroup_iter(NULL, memcg, NULL))); + + return NULL; +} + +static void lru_gen_seq_stop(struct seq_file *m, void *v) +{ + if (!IS_ERR_OR_NULL(v)) + mem_cgroup_iter_break(NULL, lruvec_memcg(v)); + + kvfree(m->private); + m->private = NULL; +} + +static void *lru_gen_seq_next(struct seq_file *m, void *v, loff_t *pos) +{ + int nid = lruvec_pgdat(v)->node_id; + struct mem_cgroup *memcg = lruvec_memcg(v); + + ++*pos; + + nid = next_memory_node(nid); + if (nid == MAX_NUMNODES) { + memcg = mem_cgroup_iter(NULL, memcg, NULL); + if (!memcg) + return NULL; + + nid = first_memory_node; + } + + return get_lruvec(memcg, nid); +} + +static void lru_gen_seq_show_full(struct seq_file *m, struct lruvec *lruvec, + unsigned long max_seq, unsigned long *min_seq, + unsigned long seq) +{ + int i; + int type, tier; + int hist = lru_hist_from_seq(seq); + struct lru_gen_struct *lrugen = &lruvec->lrugen; + + for (tier = 0; tier < MAX_NR_TIERS; tier++) { + seq_printf(m, " %10d", tier); + for (type = 0; type < ANON_AND_FILE; type++) { + unsigned long n[3] = {}; + + if (seq == max_seq) { + n[0] = READ_ONCE(lrugen->avg_refaulted[type][tier]); + n[1] = READ_ONCE(lrugen->avg_total[type][tier]); + + seq_printf(m, " %10luR %10luT %10lu ", n[0], n[1], n[2]); + } else if (seq == min_seq[type] || NR_HIST_GENS > 1) { + n[0] = atomic_long_read(&lrugen->refaulted[hist][type][tier]); + n[1] = atomic_long_read(&lrugen->evicted[hist][type][tier]); + if (tier) + n[2] = READ_ONCE(lrugen->protected[hist][type][tier - 1]); + + seq_printf(m, " %10lur %10lue %10lup", n[0], n[1], n[2]); + } else + seq_puts(m, " 0 0 0 "); + } + seq_putc(m, '\n'); + } + + seq_puts(m, " "); + for (i = 0; i < NR_MM_STATS; i++) { + if (seq == max_seq && NR_HIST_GENS == 1) + seq_printf(m, " %10lu%c", READ_ONCE(lruvec->mm_state.stats[hist][i]), + toupper(MM_STAT_CODES[i])); + else if (seq != max_seq && NR_HIST_GENS > 1) + seq_printf(m, " %10lu%c", READ_ONCE(lruvec->mm_state.stats[hist][i]), + MM_STAT_CODES[i]); + else + seq_puts(m, " 0 "); + } + seq_putc(m, '\n'); +} + +static int lru_gen_seq_show(struct seq_file *m, void *v) +{ + unsigned long seq; + bool full = !debugfs_real_fops(m->file)->write; + struct lruvec *lruvec = v; + struct lru_gen_struct *lrugen = &lruvec->lrugen; + int nid = lruvec_pgdat(lruvec)->node_id; + struct mem_cgroup *memcg = lruvec_memcg(lruvec); + DEFINE_MAX_SEQ(lruvec); + DEFINE_MIN_SEQ(lruvec); + + if (nid == first_memory_node) { + const char *path = memcg ? m->private : ""; + +#ifdef CONFIG_MEMCG + if (memcg) + cgroup_path(memcg->css.cgroup, m->private, PATH_MAX); +#endif + seq_printf(m, "memcg %5hu %s\n", mem_cgroup_id(memcg), path); + } + + seq_printf(m, " node %5d\n", nid); + + if (!full) + seq = min_seq[LRU_GEN_ANON]; + else if (max_seq >= MAX_NR_GENS) + seq = max_seq - MAX_NR_GENS + 1; + else + seq = 0; + + for (; seq <= max_seq; seq++) { + int type, zone; + int gen = lru_gen_from_seq(seq); + unsigned long birth = READ_ONCE(lruvec->lrugen.timestamps[gen]); + + seq_printf(m, " %10lu %10u", seq, jiffies_to_msecs(jiffies - birth)); + + for (type = 0; type < ANON_AND_FILE; type++) { + long size = 0; + char mark = full && seq < min_seq[type] ? 'x' : ' '; + + for (zone = 0; zone < MAX_NR_ZONES; zone++) + size += READ_ONCE(lrugen->nr_pages[gen][type][zone]); + + seq_printf(m, " %10lu%c", max(size, 0L), mark); + } + + seq_putc(m, '\n'); + + if (full) + lru_gen_seq_show_full(m, lruvec, max_seq, min_seq, seq); + } + + return 0; +} + +static const struct seq_operations lru_gen_seq_ops = { + .start = lru_gen_seq_start, + .stop = lru_gen_seq_stop, + .next = lru_gen_seq_next, + .show = lru_gen_seq_show, +}; + +static int run_aging(struct lruvec *lruvec, unsigned long seq, struct scan_control *sc, + bool can_swap, bool full_scan) +{ + DEFINE_MAX_SEQ(lruvec); + + if (seq == max_seq) + try_to_inc_max_seq(lruvec, max_seq, sc, can_swap, full_scan); + + return seq > max_seq ? -EINVAL : 0; +} + +static int run_eviction(struct lruvec *lruvec, unsigned long seq, struct scan_control *sc, + int swappiness, unsigned long nr_to_reclaim) +{ + struct blk_plug plug; + int err = -EINTR; + DEFINE_MAX_SEQ(lruvec); + + if (seq + MIN_NR_GENS > max_seq) + return -EINVAL; + + sc->nr_reclaimed = 0; + + blk_start_plug(&plug); + + while (!signal_pending(current)) { + DEFINE_MIN_SEQ(lruvec); + + if (seq < min_seq[!swappiness] || sc->nr_reclaimed >= nr_to_reclaim || + !evict_pages(lruvec, sc, swappiness, NULL)) { + err = 0; + break; + } + + cond_resched(); + } + + blk_finish_plug(&plug); + + return err; +} + +static int run_cmd(char cmd, int memcg_id, int nid, unsigned long seq, + struct scan_control *sc, int swappiness, unsigned long opt) +{ + struct lruvec *lruvec; + int err = -EINVAL; + struct mem_cgroup *memcg = NULL; + + if (!mem_cgroup_disabled()) { + rcu_read_lock(); + memcg = mem_cgroup_from_id(memcg_id); +#ifdef CONFIG_MEMCG + if (memcg && !css_tryget(&memcg->css)) + memcg = NULL; +#endif + rcu_read_unlock(); + + if (!memcg) + goto done; + } + if (memcg_id != mem_cgroup_id(memcg)) + goto done; + + if (nid < 0 || nid >= MAX_NUMNODES || !node_state(nid, N_MEMORY)) + goto done; + + lruvec = get_lruvec(memcg, nid); + + if (swappiness < 0) + swappiness = get_swappiness(lruvec, sc); + else if (swappiness > 200) + goto done; + + switch (cmd) { + case '+': + err = run_aging(lruvec, seq, sc, swappiness, opt); + break; + case '-': + err = run_eviction(lruvec, seq, sc, swappiness, opt); + break; + } +done: + mem_cgroup_put(memcg); + + return err; +} + +static ssize_t lru_gen_seq_write(struct file *file, const char __user *src, + size_t len, loff_t *pos) +{ + void *buf; + char *cur, *next; + unsigned int flags; + int err = 0; + struct reclaim_state rs = {}; + struct scan_control sc = { + .may_writepage = true, + .may_unmap = true, + .may_swap = true, + .reclaim_idx = MAX_NR_ZONES - 1, + .gfp_mask = GFP_KERNEL, + }; + + buf = kvmalloc(len + 1, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + if (copy_from_user(buf, src, len)) { + kvfree(buf); + return -EFAULT; + } + + next = buf; + next[len] = '\0'; + + rs.mm_walk = alloc_mm_walk(); + if (!rs.mm_walk) { + kvfree(buf); + return -ENOMEM; + } + + current->reclaim_state = &rs; + flags = memalloc_noreclaim_save(); + + while ((cur = strsep(&next, ",;\n"))) { + int n; + int end; + char cmd; + unsigned int memcg_id; + unsigned int nid; + unsigned long seq; + unsigned int swappiness = -1; + unsigned long opt = -1; + + cur = skip_spaces(cur); + if (!*cur) + continue; + + n = sscanf(cur, "%c %u %u %lu %n %u %n %lu %n", &cmd, &memcg_id, &nid, + &seq, &end, &swappiness, &end, &opt, &end); + if (n < 4 || cur[end]) { + err = -EINVAL; + break; + } + + err = run_cmd(cmd, memcg_id, nid, seq, &sc, swappiness, opt); + if (err) + break; + } + + memalloc_noreclaim_restore(flags); + current->reclaim_state = NULL; + + free_mm_walk(rs.mm_walk); + kvfree(buf); + + return err ? : len; +} + +static int lru_gen_seq_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &lru_gen_seq_ops); +} + +static const struct file_operations lru_gen_rw_fops = { + .open = lru_gen_seq_open, + .read = seq_read, + .write = lru_gen_seq_write, + .llseek = seq_lseek, + .release = seq_release, +}; + +static const struct file_operations lru_gen_ro_fops = { + .open = lru_gen_seq_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +/****************************************************************************** + * initialization + ******************************************************************************/ + +void lru_gen_init_lruvec(struct lruvec *lruvec) +{ + int i; + int gen, type, zone; + struct lru_gen_struct *lrugen = &lruvec->lrugen; + + lrugen->max_seq = MIN_NR_GENS + 1; + lrugen->enabled = lru_gen_enabled(); + + for (i = 0; i <= MIN_NR_GENS + 1; i++) + lrugen->timestamps[i] = jiffies; + + for_each_gen_type_zone(gen, type, zone) + INIT_LIST_HEAD(&lrugen->lists[gen][type][zone]); + + lruvec->mm_state.seq = MIN_NR_GENS; + init_waitqueue_head(&lruvec->mm_state.wait); +} + +#ifdef CONFIG_MEMCG +void lru_gen_init_memcg(struct mem_cgroup *memcg) +{ + INIT_LIST_HEAD(&memcg->mm_list.fifo); + spin_lock_init(&memcg->mm_list.lock); +} + +void lru_gen_exit_memcg(struct mem_cgroup *memcg) +{ + int i; + int nid; + + for_each_node(nid) { + struct lruvec *lruvec = get_lruvec(memcg, nid); + + VM_BUG_ON(memchr_inv(lruvec->lrugen.nr_pages, 0, + sizeof(lruvec->lrugen.nr_pages))); + + for (i = 0; i < NR_BLOOM_FILTERS; i++) { + bitmap_free(lruvec->mm_state.filters[i]); + lruvec->mm_state.filters[i] = NULL; + } + } +} +#endif + +static int __init init_lru_gen(void) +{ + BUILD_BUG_ON(MIN_NR_GENS + 1 >= MAX_NR_GENS); + BUILD_BUG_ON(BIT(LRU_GEN_WIDTH) <= MAX_NR_GENS); + BUILD_BUG_ON(sizeof(MM_STAT_CODES) != NR_MM_STATS + 1); + + if (sysfs_create_group(mm_kobj, &lru_gen_attr_group)) + pr_err("lru_gen: failed to create sysfs group\n"); + + debugfs_create_file("lru_gen", 0644, NULL, NULL, &lru_gen_rw_fops); + debugfs_create_file("lru_gen_full", 0444, NULL, NULL, &lru_gen_ro_fops); + + return 0; +}; +late_initcall(init_lru_gen); + +#else + +static void lru_gen_age_node(struct pglist_data *pgdat, struct scan_control *sc) +{ +} + +static void lru_gen_shrink_lruvec(struct lruvec *lruvec, struct scan_control *sc) +{ +} + +#endif /* CONFIG_LRU_GEN */ + /* * This is a basic per-node page freer. Used by both kswapd and direct reclaim. */ @@ -2563,6 +5415,11 @@ static void shrink_node_memcg(struct pglist_data *pgdat, struct mem_cgroup *memc struct blk_plug plug; bool scan_adjusted; + if (lru_gen_enabled()) { + lru_gen_shrink_lruvec(lruvec, sc); + return; + } + get_scan_count(lruvec, memcg, sc, nr, lru_pages); /* Record the original scan target for proportional adjustments later */ @@ -3069,6 +5926,9 @@ static void snapshot_refaults(struct mem_cgroup *root_memcg, pg_data_t *pgdat) { struct mem_cgroup *memcg; + if (lru_gen_enabled()) + return; + memcg = mem_cgroup_iter(root_memcg, NULL, NULL); do { unsigned long refaults; @@ -3434,6 +6294,11 @@ static void age_active_anon(struct pglist_data *pgdat, { struct mem_cgroup *memcg; + if (lru_gen_enabled()) { + lru_gen_age_node(pgdat, sc); + return; + } + if (!total_swap_pages) return; @@ -3623,6 +6488,9 @@ static int balance_pgdat(pg_data_t *pgdat, int order, int classzone_idx) .gfp_mask = GFP_KERNEL, .order = order, .may_unmap = 1, +#ifdef OPLUS_FEATURE_PERFORMANCE + .may_swap = 1, +#endif }; psi_memstall_enter(&pflags); @@ -3709,7 +6577,9 @@ restart: * reclaim will be aborted. */ sc.may_writepage = !laptop_mode && !nr_boost_reclaim; +#ifndef OPLUS_FEATURE_PERFORMANCE sc.may_swap = !nr_boost_reclaim; +#endif /* * Do some background aging of the anon list, to give @@ -3811,6 +6681,7 @@ out: * entered the allocator slow path while kswapd was awake, order will * remain at the higher level. */ + return sc.order; } @@ -3925,7 +6796,11 @@ static void kswapd_try_to_sleep(pg_data_t *pgdat, int alloc_order, int reclaim_o * If there are applications that are active memory-allocators * (most normal use), this basically shouldn't matter. */ + #if defined(OPLUS_FEATURE_MULTI_KSWAPD) && defined(CONFIG_OPLUS_MULTI_KSWAPD) + int kswapd(void *p) + #else static int kswapd(void *p) +#endif { unsigned int alloc_order, reclaim_order; unsigned int classzone_idx = MAX_NR_ZONES - 1; @@ -3935,7 +6810,17 @@ static int kswapd(void *p) struct reclaim_state reclaim_state = { .reclaimed_slab = 0, }; +#if defined(OPLUS_FEATURE_MULTI_KSWAPD) && defined(CONFIG_KSWAPD_UNBIND_MAX_CPU) + struct cpumask mask; + struct cpumask *cpumask = &mask; + + cpumask_copy(cpumask, cpumask_of_node(pgdat->node_id)); + if (kswapd_unbind_cpu != -1 && + cpumask_test_cpu(kswapd_unbind_cpu, cpumask)) + cpumask_clear_cpu(kswapd_unbind_cpu, cpumask); +#else const struct cpumask *cpumask = cpumask_of_node(pgdat->node_id); +#endif if (!cpumask_empty(cpumask)) set_cpus_allowed_ptr(tsk, cpumask); @@ -4069,7 +6954,7 @@ void wakeup_kswapd(struct zone *zone, gfp_t gfp_flags, int order, */ unsigned long shrink_all_memory(unsigned long nr_to_reclaim) { - struct reclaim_state reclaim_state; + struct reclaim_state reclaim_state = {}; struct scan_control sc = { .nr_to_reclaim = nr_to_reclaim, .gfp_mask = GFP_HIGHUSER_MOVABLE, @@ -4106,6 +6991,9 @@ unsigned long shrink_all_memory(unsigned long nr_to_reclaim) restore their cpu bindings. */ static int kswapd_cpu_online(unsigned int cpu) { +#if defined(OPLUS_FEATURE_MULTI_KSWAPD) && defined(CONFIG_OPLUS_MULTI_KSWAPD) + return kswapd_cpu_online_ext(cpu); +#else int nid, hid; int nr_threads = kswapd_threads_current; @@ -4122,73 +7010,18 @@ static int kswapd_cpu_online(unsigned int cpu) } } return 0; +#endif } -static void update_kswapd_threads_node(int nid) -{ - pg_data_t *pgdat; - int drop, increase; - int last_idx, start_idx, hid; - int nr_threads = kswapd_threads_current; - - pgdat = NODE_DATA(nid); - last_idx = nr_threads - 1; - if (kswapd_threads < nr_threads) { - drop = nr_threads - kswapd_threads; - for (hid = last_idx; hid > (last_idx - drop); hid--) { - if (pgdat->kswapd[hid]) { - kthread_stop(pgdat->kswapd[hid]); - pgdat->kswapd[hid] = NULL; - } - } - } else { - increase = kswapd_threads - nr_threads; - start_idx = last_idx + 1; - for (hid = start_idx; hid < (start_idx + increase); hid++) { - pgdat->kswapd[hid] = kthread_run(kswapd, pgdat, - "kswapd%d:%d", nid, hid); - if (IS_ERR(pgdat->kswapd[hid])) { - pr_err("Failed to start kswapd%d on node %d\n", - hid, nid); - pgdat->kswapd[hid] = NULL; - /* - * We are out of resources. Do not start any - * more threads. - */ - break; - } - } - } -} - -void update_kswapd_threads(void) -{ - int nid; - - if (kswapd_threads_current == kswapd_threads) - return; - - /* - * Hold the memory hotplug lock to avoid racing with memory - * hotplug initiated updates - */ - mem_hotplug_begin(); - for_each_node_state(nid, N_MEMORY) - update_kswapd_threads_node(nid); - - pr_info("kswapd_thread count changed, old:%d new:%d\n", - kswapd_threads_current, kswapd_threads); - kswapd_threads_current = kswapd_threads; - mem_hotplug_done(); -} - - /* * This kswapd start function will be called by init and node-hot-add. * On node-hot-add, kswapd will moved to proper cpus if cpus are hot-added. */ int kswapd_run(int nid) { +#if defined(OPLUS_FEATURE_MULTI_KSWAPD) && defined(CONFIG_OPLUS_MULTI_KSWAPD) + return kswapd_run_ext(nid); +#else pg_data_t *pgdat = NODE_DATA(nid); int ret = 0; int hid, nr_threads; @@ -4211,6 +7044,7 @@ int kswapd_run(int nid) } kswapd_threads_current = nr_threads; return ret; +#endif } /* @@ -4219,6 +7053,9 @@ int kswapd_run(int nid) */ void kswapd_stop(int nid) { +#if defined(OPLUS_FEATURE_MULTI_KSWAPD) && defined(CONFIG_OPLUS_MULTI_KSWAPD) + return kswapd_stop_ext(nid); +#else struct task_struct *kswapd; int hid; int nr_threads = kswapd_threads_current; @@ -4230,6 +7067,8 @@ void kswapd_stop(int nid) NODE_DATA(nid)->kswapd[hid] = NULL; } } +#endif + } static int __init kswapd_init(void) @@ -4331,7 +7170,7 @@ static int __node_reclaim(struct pglist_data *pgdat, gfp_t gfp_mask, unsigned in /* Minimum pages needed in order to stay on node */ const unsigned long nr_pages = 1 << order; struct task_struct *p = current; - struct reclaim_state reclaim_state; + struct reclaim_state reclaim_state = {}; unsigned int noreclaim_flag; struct scan_control sc = { .nr_to_reclaim = max(nr_pages, SWAP_CLUSTER_MAX), @@ -4477,12 +7316,9 @@ void check_move_unevictable_pages(struct page **pages, int nr_pages) continue; if (page_evictable(page)) { - enum lru_list lru = page_lru_base_type(page); - - VM_BUG_ON_PAGE(PageActive(page), page); + del_page_from_lru_list(page, lruvec); ClearPageUnevictable(page); - del_page_from_lru_list(page, lruvec, LRU_UNEVICTABLE); - add_page_to_lru_list(page, lruvec, lru); + add_page_to_lru_list(page, lruvec); pgrescued++; } } @@ -4494,3 +7330,115 @@ void check_move_unevictable_pages(struct page **pages, int nr_pages) } } #endif /* CONFIG_SHMEM */ + +#ifdef CONFIG_HYBRIDSWAP_SWAPD +#define PARA_BUF_LEN 128 + +static inline bool debug_get_val(char *buf, char *token, unsigned long *val) +{ + int ret = -EINVAL; + char *str = strstr(buf, token); + + if (!str) + return ret; + + ret = kstrtoul(str + strlen(token), 0, val); + if (ret) + return -EINVAL; + + if (*val > 200) { + pr_err("%lu is invalid\n", *val); + return -EINVAL; + } + + return 0; +} + +static ssize_t swappiness_para_write(struct file *file, + const char __user *buff, size_t len, loff_t *ppos) +{ + char kbuf[PARA_BUF_LEN] = {'0'}; + char *str; + long val; + + if (len > PARA_BUF_LEN - 1) { + pr_err("len %d is too long\n", len); + return -EINVAL; + } + + if (copy_from_user(&kbuf, buff, len)) + return -EFAULT; + kbuf[len] = '\0'; + + str = strstrip(kbuf); + if (!str) { + pr_err("buff %s is invalid\n", kbuf); + return -EINVAL; + } + + if (!debug_get_val(str, "vm_swappiness=", &val)) { + vm_swappiness = val; + return len; + } + + if (!debug_get_val(str, "direct_swappiness=", &val)) { + direct_vm_swappiness = val; + return len; + } + + if (!debug_get_val(str, "swapd_swappiness=", &val)) { + hybridswapd_swappiness = val; + return len; + } + + return -EINVAL; +} + +static ssize_t swappiness_para_read(struct file *file, + char __user *buffer, size_t count, loff_t *off) +{ + char kbuf[PARA_BUF_LEN] = {'0'}; + int len; + + len = snprintf(kbuf, PARA_BUF_LEN, "vm_swappiness: %d\n", vm_swappiness); + len += snprintf(kbuf + len, PARA_BUF_LEN - len, + "direct_swappiness: %d\n", direct_vm_swappiness); + len += snprintf(kbuf + len, PARA_BUF_LEN - len, + "swapd_swappiness: %d\n", hybridswapd_swappiness); + + if (len == PARA_BUF_LEN) + kbuf[len - 1] = '\0'; + + if (len > *off) + len -= *off; + else + len = 0; + + if (copy_to_user(buffer, kbuf + *off, (len < count ? len : count))) + return -EFAULT; + + *off += (len < count ? len : count); + return (len < count ? len : count); +} + +static const struct file_operations proc_swappiness_para_ops = { + .write = swappiness_para_write, + .read = swappiness_para_read, +}; + +int create_swappiness_para_proc(void) +{ + struct proc_dir_entry * para_entry = + proc_create("oplus_healthinfo/swappiness_para", + S_IRUSR|S_IWUSR, NULL, &proc_swappiness_para_ops); + + if (para_entry) { + printk("Register swappiness_para interface passed.\n"); + return 0; + } + + pr_err("Register swappiness_para interface failed.\n"); + return -ENOMEM; +} +EXPORT_SYMBOL(create_swappiness_para_proc); +#endif diff --git a/mm/vmstat.c b/mm/vmstat.c index 556df1590091..f09872ebcac0 100644 --- a/mm/vmstat.c +++ b/mm/vmstat.c @@ -30,6 +30,10 @@ #include "internal.h" +#if defined(OPLUS_FEATURE_MULTI_FREEAREA) && defined(CONFIG_PHYSICAL_ANTI_FRAGMENTATION) +#include "multi_freearea.h" +#endif + #define NUMA_STATS_THRESHOLD (U16_MAX - 2) #ifdef CONFIG_NUMA @@ -1021,26 +1025,39 @@ static void fill_contig_page_info(struct zone *zone, struct contig_page_info *info) { unsigned int order; +#if defined(OPLUS_FEATURE_MULTI_FREEAREA) && defined(CONFIG_PHYSICAL_ANTI_FRAGMENTATION) + int flc; +#endif info->free_pages = 0; info->free_blocks_total = 0; info->free_blocks_suitable = 0; - for (order = 0; order < MAX_ORDER; order++) { - unsigned long blocks; +#if defined(OPLUS_FEATURE_MULTI_FREEAREA) && defined(CONFIG_PHYSICAL_ANTI_FRAGMENTATION) + for (flc = 0; flc < FREE_AREA_COUNTS; flc++) { +#endif + for (order = 0; order < MAX_ORDER; order++) { + unsigned long blocks; - /* Count number of free blocks */ - blocks = zone->free_area[order].nr_free; - info->free_blocks_total += blocks; + /* Count number of free blocks */ +#if defined(OPLUS_FEATURE_MULTI_FREEAREA) && defined(CONFIG_PHYSICAL_ANTI_FRAGMENTATION) + blocks = zone->free_area[flc][order].nr_free; +#else + blocks = zone->free_area[order].nr_free; +#endif + info->free_blocks_total += blocks; - /* Count free base pages */ - info->free_pages += blocks << order; + /* Count free base pages */ + info->free_pages += blocks << order; - /* Count the suitable free blocks */ - if (order >= suitable_order) - info->free_blocks_suitable += blocks << - (order - suitable_order); - } + /* Count the suitable free blocks */ + if (order >= suitable_order) + info->free_blocks_suitable += blocks << + (order - suitable_order); + } +#if defined(OPLUS_FEATURE_MULTI_FREEAREA) && defined(CONFIG_PHYSICAL_ANTI_FRAGMENTATION) + } +#endif } /* @@ -1125,6 +1142,12 @@ const char * const vmstat_text[] = { "nr_zspages", #endif "nr_free_cma", +#if defined(OPLUS_FEATURE_MEMORY_ISOLATE) && defined(CONFIG_OPLUS_MEMORY_ISOLATE) + "nr_free_oplus2", +#endif /*OPLUS_FEATURE_MEMORY_ISOLATE*/ +#ifdef OPLUS_FEATURE_HEALTHINFO + "nr_ioncache_pages", +#endif /* OPLUS_FEATURE_HEALTHINFO */ /* enum numa_stat_item counters */ #ifdef CONFIG_NUMA @@ -1361,10 +1384,20 @@ static void frag_show_print(struct seq_file *m, pg_data_t *pgdat, struct zone *zone) { int order; +#if defined(OPLUS_FEATURE_MULTI_FREEAREA) && defined(CONFIG_PHYSICAL_ANTI_FRAGMENTATION) + int flc = 0; +#endif seq_printf(m, "Node %d, zone %8s ", pgdat->node_id, zone->name); +#if defined(OPLUS_FEATURE_MULTI_FREEAREA) && defined(CONFIG_PHYSICAL_ANTI_FRAGMENTATION) + for (flc = 0; flc < FREE_AREA_COUNTS; flc++) { + for (order = 0; order < MAX_ORDER; ++order) + seq_printf(m, "%6lu ", zone->free_area[flc][order].nr_free); + } +#else for (order = 0; order < MAX_ORDER; ++order) seq_printf(m, "%6lu ", zone->free_area[order].nr_free); +#endif seq_putc(m, '\n'); } @@ -1383,6 +1416,11 @@ static void pagetypeinfo_showfree_print(struct seq_file *m, { int order, mtype; +#if defined(OPLUS_FEATURE_MULTI_FREEAREA) && defined(CONFIG_PHYSICAL_ANTI_FRAGMENTATION) + int flc; + + for (flc = 0; flc < FREE_AREA_COUNTS; flc++) { +#endif for (mtype = 0; mtype < MIGRATE_TYPES; mtype++) { seq_printf(m, "Node %4d, zone %8s, type %12s ", pgdat->node_id, @@ -1393,7 +1431,11 @@ static void pagetypeinfo_showfree_print(struct seq_file *m, struct free_area *area; struct list_head *curr; +#if defined(OPLUS_FEATURE_MULTI_FREEAREA) && defined(CONFIG_PHYSICAL_ANTI_FRAGMENTATION) + area = &(zone->free_area[flc][order]); +#else area = &(zone->free_area[order]); +#endif list_for_each(curr, &area->free_list[mtype]) freecount++; @@ -1404,6 +1446,9 @@ static void pagetypeinfo_showfree_print(struct seq_file *m, } seq_putc(m, '\n'); } +#if defined(OPLUS_FEATURE_MULTI_FREEAREA) && defined(CONFIG_PHYSICAL_ANTI_FRAGMENTATION) + } +#endif } /* Print out the free pages at each order for each migatetype */ @@ -1967,6 +2012,9 @@ struct workqueue_struct *mm_percpu_wq; void __init init_mm_internals(void) { int ret __maybe_unused; +#if defined(OPLUS_FEATURE_MULTI_FREEAREA) && defined(CONFIG_PHYSICAL_ANTI_FRAGMENTATION) + struct proc_dir_entry *pentry; +#endif mm_percpu_wq = alloc_workqueue("mm_percpu_wq", WQ_MEM_RECLAIM, 0); @@ -1993,6 +2041,13 @@ void __init init_mm_internals(void) proc_create_seq("pagetypeinfo", 0400, NULL, &pagetypeinfo_op); proc_create_seq("vmstat", 0444, NULL, &vmstat_op); proc_create_seq("zoneinfo", 0444, NULL, &zoneinfo_op); +#if defined(OPLUS_FEATURE_MULTI_FREEAREA) && defined(CONFIG_PHYSICAL_ANTI_FRAGMENTATION) + pentry = proc_create("free_area_list_show", S_IRWXUGO, NULL, &proc_free_area_fops); + if (!pentry) { + pr_err("vmstat: failed to create '/proc/free_area_list_show'\n"); + return; + } +#endif #endif } diff --git a/mm/workingset.c b/mm/workingset.c index 99b7f7c09b13..d34a0901c8bb 100644 --- a/mm/workingset.c +++ b/mm/workingset.c @@ -6,6 +6,7 @@ */ #include +#include #include #include #include @@ -184,7 +185,6 @@ static unsigned int bucket_order __read_mostly; static void *pack_shadow(int memcgid, pg_data_t *pgdat, unsigned long eviction, bool workingset) { - eviction >>= bucket_order; eviction = (eviction << MEM_CGROUP_ID_SHIFT) | memcgid; eviction = (eviction << NODES_SHIFT) | pgdat->node_id; eviction = (eviction << 1) | workingset; @@ -210,10 +210,108 @@ static void unpack_shadow(void *shadow, int *memcgidp, pg_data_t **pgdat, *memcgidp = memcgid; *pgdat = NODE_DATA(nid); - *evictionp = entry << bucket_order; + *evictionp = entry; *workingsetp = workingset; } +#ifdef CONFIG_LRU_GEN + +static int page_lru_refs(struct page *page) +{ + unsigned long flags = READ_ONCE(page->flags); + + BUILD_BUG_ON(LRU_GEN_WIDTH + LRU_REFS_WIDTH > BITS_PER_LONG - EVICTION_SHIFT); + + /* see the comment on MAX_NR_TIERS */ + return flags & BIT(PG_workingset) ? (flags & LRU_REFS_MASK) >> LRU_REFS_PGOFF : 0; +} + +void *lru_gen_eviction(struct page *page) +{ + int hist, tier; + unsigned long token; + unsigned long min_seq; + struct lruvec *lruvec; + struct lru_gen_struct *lrugen; + int type = page_is_file_cache(page); + int refs = page_lru_refs(page); + int delta = hpage_nr_pages(page); + bool workingset = PageWorkingset(page); + struct mem_cgroup *memcg = page_memcg(page); + struct pglist_data *pgdat = page_pgdat(page); + + if (!mem_cgroup_disabled() && !memcg) + return NULL; + + lruvec = mem_cgroup_lruvec(pgdat, memcg); + lrugen = &lruvec->lrugen; + min_seq = READ_ONCE(lrugen->min_seq[type]); + token = (min_seq << LRU_REFS_WIDTH) | refs; + + hist = lru_hist_from_seq(min_seq); + tier = lru_tier_from_refs(refs + workingset); + atomic_long_add(delta, &lrugen->evicted[hist][type][tier]); + + return pack_shadow(mem_cgroup_id(memcg), pgdat, token, workingset); +} + +void lru_gen_refault(struct page *page, void *shadow) +{ + int hist, tier, refs; + int memcg_id; + bool workingset; + unsigned long token; + unsigned long min_seq; + struct lruvec *lruvec; + struct lru_gen_struct *lrugen; + struct mem_cgroup *memcg; + struct pglist_data *pgdat; + int type = page_is_file_cache(page); + int delta = hpage_nr_pages(page); + + unpack_shadow(shadow, &memcg_id, &pgdat, &token, &workingset); + + refs = token & (BIT(LRU_REFS_WIDTH) - 1); + if (refs && !workingset) + return; + + if (page_pgdat(page) != pgdat) + return; + + rcu_read_lock(); + memcg = mem_cgroup_from_id(memcg_id); + if (!mem_cgroup_disabled() && !memcg) + goto unlock; + + token >>= LRU_REFS_WIDTH; + lruvec = mem_cgroup_lruvec(pgdat, memcg); + lrugen = &lruvec->lrugen; + min_seq = READ_ONCE(lrugen->min_seq[type]); + if (token != (min_seq & (EVICTION_MASK >> LRU_REFS_WIDTH))) + goto unlock; + + hist = lru_hist_from_seq(min_seq); + tier = lru_tier_from_refs(refs + workingset); + atomic_long_add(delta, &lrugen->refaulted[hist][type][tier]); + mod_lruvec_state(lruvec, WORKINGSET_REFAULT, delta); + + /* + * Count the following two cases as stalls: + * 1. For pages accessed through page tables, hotter pages pushed out + * hot pages which refaulted immediately. + * 2. For pages accessed through file descriptors, numbers of accesses + * might have been beyond the limit. + */ + if (lru_gen_in_fault() || refs + workingset == BIT(LRU_REFS_WIDTH)) { + SetPageWorkingset(page); + mod_lruvec_state(lruvec, WORKINGSET_RESTORE, delta); + } +unlock: + rcu_read_unlock(); +} + +#endif /* CONFIG_LRU_GEN */ + /** * workingset_eviction - note the eviction of a page from memory * @mapping: address space the page was backing @@ -235,8 +333,12 @@ void *workingset_eviction(struct address_space *mapping, struct page *page) VM_BUG_ON_PAGE(page_count(page), page); VM_BUG_ON_PAGE(!PageLocked(page), page); + if (lru_gen_enabled()) + return lru_gen_eviction(page); + lruvec = mem_cgroup_lruvec(pgdat, memcg); eviction = atomic_long_inc_return(&lruvec->inactive_age); + eviction >>= bucket_order; return pack_shadow(memcgid, pgdat, eviction, PageWorkingset(page)); } @@ -260,7 +362,13 @@ void workingset_refault(struct page *page, void *shadow) bool workingset; int memcgid; + if (lru_gen_enabled()) { + lru_gen_refault(page, shadow); + return; + } + unpack_shadow(shadow, &memcgid, &pgdat, &eviction, &workingset); + eviction <<= bucket_order; rcu_read_lock(); /* diff --git a/mm/zsmalloc.c b/mm/zsmalloc.c index 526594ce508c..92cd36a374e8 100644 --- a/mm/zsmalloc.c +++ b/mm/zsmalloc.c @@ -71,7 +71,11 @@ * A single 'zspage' is composed of up to 2^N discontiguous 0-order (single) * pages. ZS_MAX_ZSPAGE_ORDER defines upper limit on N. */ +#if defined(OPLUS_FEATURE_ZRAM_OPT) && defined(CONFIG_OPLUS_ZRAM_OPT) +#define ZS_MAX_ZSPAGE_ORDER 3 +#else #define ZS_MAX_ZSPAGE_ORDER 2 +#endif /*OPLUS_FEATURE_ZRAM_OPT*/ #define ZS_MAX_PAGES_PER_ZSPAGE (_AC(1, UL) << ZS_MAX_ZSPAGE_ORDER) #define ZS_HANDLE_SIZE (sizeof(unsigned long)) @@ -122,7 +126,11 @@ #define FULLNESS_BITS 2 #define CLASS_BITS 8 +#if defined(OPLUS_FEATURE_ZRAM_OPT) && defined(CONFIG_OPLUS_ZRAM_OPT) +#define ISOLATED_BITS (ZS_MAX_ZSPAGE_ORDER+1) +#else #define ISOLATED_BITS 3 +#endif /*OPLUS_FEATURE_ZRAM_OPT*/ #define MAGIC_VAL_BITS 8 #define MAX(a, b) ((a) >= (b) ? (a) : (b)) diff --git a/net/Kconfig b/net/Kconfig index 6870f6c838e5..c4b8f43615a2 100644 --- a/net/Kconfig +++ b/net/Kconfig @@ -472,3 +472,14 @@ config HAVE_CBPF_JIT # Extended BPF JIT (eBPF) config HAVE_EBPF_JIT bool + + + +source "net/oplus_score/Kconfig" + +source "net/oplus_connectivity_routerboost/Kconfig" + + +source "net/oplus_connectivity_sla/Kconfig" + +source "net/oplus_modules/Kconfig" diff --git a/net/Makefile b/net/Makefile index 449fc0b221f8..fa4af8d23121 100644 --- a/net/Makefile +++ b/net/Makefile @@ -87,3 +87,49 @@ endif obj-$(CONFIG_QRTR) += qrtr/ obj-$(CONFIG_NET_NCSI) += ncsi/ obj-$(CONFIG_XDP_SOCKETS) += xdp/ + +#ifdef OPLUS_FEATURE_NWPOWER +obj-y += oplus_nwpower/ +#endif /* OPLUS_FEATURE_NWPOWER */ +#ifdef OPLUS_FEATURE_WIFI_SLA +obj-y += oplus_connectivity_sla/ +#endif /* OPLUS_FEATURE_WIFI_SLA */ + +#ifdef OPLUS_FEATURE_WIFI_ROUTERBOOST +obj-$(CONFIG_OPLUS_FEATURE_WIFI_ROUTERBOOST) += oplus_connectivity_routerboost/ +#endif /* OPLUS_FEATURE_WIFI_ROUTERBOOST */ + +#ifdef OPLUS_FEATURE_IPV6_OPTIMIZE +obj-y += oplus_ipv6/ +#endif /* OPLUS_FEATURE_IPV6_OPTIMIZE */ + +OPLUS_FEATURE_WIFI_LUCKYMONEY=1 +ifneq ($(OPLUS_FEATURE_WIFI_LUCKYMONEY),) +obj-y += oplus_nf_hooks/ +endif #/* OPLUS_FEATURE_WIFI_LUCKYMONEY */ + +#ifdef OPLUS_FEATURE_APP_MONITOR +#Add for apps network monitors +obj-y += oplus_apps_monitor/ +#endif /* OPLUS_FEATURE_APP_MONITOR */ + +#ifdef OPLUS_FEATURE_DATA_EVAL +obj-$(CONFIG_OPLUS_FEATURE_DATA_EVAL) += oplus_score/ +#endif /* OPLUS_FEATURE_DATA_EVAL */ + +OPLUS_FEATURE_DHCP=1 +ifneq ($(OPLUS_FEATURE_DHCP),) +obj-y += oplus_dhcp/ +endif #/* OPLUS_FEATURE_DHCP */ + +OPLUS_FEATURE_WIFI_CAP_CENTER=1 +ifneq ($(OPLUS_FEATURE_WIFI_CAP_CENTER),) +obj-y += oplus_wificapcenter/ +endif #/* OPLUS_FEATURE_WIFI_CAP_CENTER */ + +ifneq ($(OPLUS_FEATURE_WIFI_ROUTERBOOST),) +obj-y += oplus_router_boost/ +endif #/* OPLUS_FEATURE_WIFI_ROUTERBOOST */ + +obj-y += oplus_modules/ + diff --git a/net/core/dev.c b/net/core/dev.c index 0fdb489ea725..98e92a2e7d15 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -3255,7 +3255,6 @@ static int xmit_one(struct sk_buff *skb, struct net_device *dev, { unsigned int len; int rc; - if (!list_empty(&ptype_all) || !list_empty(&dev->ptype_all)) dev_queue_xmit_nit(skb, dev); diff --git a/net/core/secure_seq.c b/net/core/secure_seq.c index 6fd25279bee9..608862647f06 100644 --- a/net/core/secure_seq.c +++ b/net/core/secure_seq.c @@ -123,6 +123,13 @@ u32 secure_tcp_ts_off(const struct net *net, __be32 saddr, __be32 daddr) if (net->ipv4.sysctl_tcp_timestamps != 1) return 0; + #ifdef OPLUS_BUG_STABILITY + if (net->ipv4.sysctl_tcp_random_timestamp == 0) + { + return 0; + } + #endif /* OPLUS_BUG_STABILITY */ + ts_secret_init(); return siphash_2u32((__force u32)saddr, (__force u32)daddr, &ts_secret); diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 1768e0c56866..1156795425c2 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -627,6 +627,7 @@ void skb_release_head_state(struct sk_buff *skb) WARN_ON(in_irq()); skb->destructor(skb); } + #if IS_ENABLED(CONFIG_NF_CONNTRACK) nf_conntrack_put(skb_nfct(skb)); #endif diff --git a/net/ipv4/Makefile b/net/ipv4/Makefile index 7446b98661d8..c7d1d13bd6de 100644 --- a/net/ipv4/Makefile +++ b/net/ipv4/Makefile @@ -20,6 +20,9 @@ obj-$(CONFIG_BPFILTER) += bpfilter/ obj-$(CONFIG_NET_IP_TUNNEL) += ip_tunnel.o obj-$(CONFIG_SYSCTL) += sysctl_net_ipv4.o +#ifdef OPLUS_BUG_STABILITY +#obj-$(CONFIG_SYSFS) += sysfs_net_ipv4.o +#endif /* OPLUS_BUG_STABILITY */ obj-$(CONFIG_PROC_FS) += proc.o obj-$(CONFIG_IP_MULTIPLE_TABLES) += fib_rules.o obj-$(CONFIG_IP_MROUTE) += ipmr.o diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c index 765921bac9a8..0995e0997588 100644 --- a/net/ipv4/inet_connection_sock.c +++ b/net/ipv4/inet_connection_sock.c @@ -1134,6 +1134,14 @@ struct dst_entry *inet_csk_update_pmtu(struct sock *sk, u32 mtu) goto out; } dst->ops->update_pmtu(dst, sk, NULL, mtu, true); + #ifdef OPLUS_FEATURE_WIFI_MTUDETECT + //Add for [1066205] when receives ICMP_FRAG_NEEDED, reduces the mtu of net_device. + pr_err("%s: current_mtu = %d , frag_mtu = %d mtu = %d\n", __func__, dst->dev->mtu, dst_mtu(dst),mtu); + //do not use dst_mtu here, because dst_mtu should be changed by update_pmtu after inet_csk_rebuild_route + if (dst->dev->mtu > mtu && mtu > IPV6_MIN_MTU) { + dst->dev->mtu = mtu; + } + #endif /* OPLUS_FEATURE_WIFI_MTUDETECT */ dst = __sk_dst_check(sk, 0); if (!dst) diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c index 7595c22b5265..5275c71bae87 100644 --- a/net/ipv4/netfilter/arp_tables.c +++ b/net/ipv4/netfilter/arp_tables.c @@ -625,25 +625,6 @@ static void get_counters(const struct xt_table_info *t, } } -static void get_old_counters(const struct xt_table_info *t, - struct xt_counters counters[]) -{ - struct arpt_entry *iter; - unsigned int cpu, i; - - for_each_possible_cpu(cpu) { - i = 0; - xt_entry_foreach(iter, t->entries, t->size) { - struct xt_counters *tmp; - - tmp = xt_get_per_cpu_counter(&iter->counters, cpu); - ADD_COUNTER(counters[i], tmp->bcnt, tmp->pcnt); - ++i; - } - cond_resched(); - } -} - static struct xt_counters *alloc_counters(const struct xt_table *table) { unsigned int countersize; @@ -920,7 +901,8 @@ static int __do_replace(struct net *net, const char *name, (newinfo->number <= oldinfo->initial_entries)) module_put(t->me); - get_old_counters(oldinfo, counters); + /* Get the old counters, and synchronize with replace */ + get_counters(oldinfo, counters); /* Decrease module usage counts and free resource */ loc_cpu_old_entry = oldinfo->entries; diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c index f71fdbafe71a..07a0d4be85c9 100644 --- a/net/ipv4/netfilter/ip_tables.c +++ b/net/ipv4/netfilter/ip_tables.c @@ -770,26 +770,6 @@ get_counters(const struct xt_table_info *t, } } -static void get_old_counters(const struct xt_table_info *t, - struct xt_counters counters[]) -{ - struct ipt_entry *iter; - unsigned int cpu, i; - - for_each_possible_cpu(cpu) { - i = 0; - xt_entry_foreach(iter, t->entries, t->size) { - const struct xt_counters *tmp; - - tmp = xt_get_per_cpu_counter(&iter->counters, cpu); - ADD_COUNTER(counters[i], tmp->bcnt, tmp->pcnt); - ++i; /* macro does multi eval of i */ - } - - cond_resched(); - } -} - static struct xt_counters *alloc_counters(const struct xt_table *table) { unsigned int countersize; @@ -1079,7 +1059,8 @@ __do_replace(struct net *net, const char *name, unsigned int valid_hooks, (newinfo->number <= oldinfo->initial_entries)) module_put(t->me); - get_old_counters(oldinfo, counters); + /* Get the old counters, and synchronize with replace */ + get_counters(oldinfo, counters); /* Decrease module usage counts and free resource */ xt_entry_foreach(iter, oldinfo->entries, oldinfo->size) diff --git a/net/ipv4/netfilter/ipt_REJECT.c b/net/ipv4/netfilter/ipt_REJECT.c index e8bed3390e58..e3c5f0d5f5f2 100644 --- a/net/ipv4/netfilter/ipt_REJECT.c +++ b/net/ipv4/netfilter/ipt_REJECT.c @@ -30,6 +30,7 @@ MODULE_LICENSE("GPL"); MODULE_AUTHOR("Netfilter Core Team "); MODULE_DESCRIPTION("Xtables: packet \"rejection\" target for IPv4"); + static unsigned int reject_tg(struct sk_buff *skb, const struct xt_action_param *par) { @@ -64,7 +65,6 @@ reject_tg(struct sk_buff *skb, const struct xt_action_param *par) /* Doesn't happen. */ break; } - return NF_DROP; } diff --git a/net/ipv4/netfilter/nf_dup_ipv4.c b/net/ipv4/netfilter/nf_dup_ipv4.c index 39895b9ddeb9..a086b390e4c4 100644 --- a/net/ipv4/netfilter/nf_dup_ipv4.c +++ b/net/ipv4/netfilter/nf_dup_ipv4.c @@ -26,7 +26,7 @@ static bool nf_dup_ipv4_route(struct net *net, struct sk_buff *skb, const struct in_addr *gw, int oif) { - const struct iphdr *iph = ip_hdr(skb); + const struct iphdr *iph = ip_hdr(skb); struct rtable *rt; struct flowi4 fl4; diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c index 4d473ea69b49..d9f906445c52 100644 --- a/net/ipv4/sysctl_net_ipv4.c +++ b/net/ipv4/sysctl_net_ipv4.c @@ -556,6 +556,16 @@ static struct ctl_table ipv4_table[] = { .mode = 0644, .proc_handler = proc_doulongvec_minmax, }, + #ifdef OPLUS_BUG_STABILITY + //ZhaoMengqingCONNECTIVITY.WIFI.INTERNET.1394484, 2019/04/02,add for: When find TCP SYN-ACK Timestamp value error, just do not use Timestamp + { + .procname = "tcp_timestamps_control", + .data = &sysctl_tcp_ts_control, + .maxlen = sizeof(sysctl_tcp_ts_control), + .mode = 0664, + .proc_handler = proc_dointvec + }, + #endif /* OPLUS_BUG_STABILITY */ { .procname = "tcp_delack_seg", .data = &sysctl_tcp_delack_seg, @@ -1024,6 +1034,15 @@ static struct ctl_table ipv4_net_table[] = { .mode = 0644, .proc_handler = proc_dointvec }, + #ifdef OPLUS_BUG_STABILITY + { + .procname = "tcp_random_timestamp", + .data = &init_net.ipv4.sysctl_tcp_random_timestamp, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec + }, + #endif /* OPLUS_BUG_STABILITY */ { .procname = "tcp_early_retrans", .data = &init_net.ipv4.sysctl_tcp_early_retrans, diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 0a271598676e..aa4d4bf5db91 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -302,6 +302,11 @@ EXPORT_SYMBOL(sysctl_tcp_delack_seg); int sysctl_tcp_use_userconfig __read_mostly; EXPORT_SYMBOL(sysctl_tcp_use_userconfig); +#ifdef OPLUS_BUG_STABILITY +int sysctl_tcp_ts_control[2] __read_mostly = {0,0}; +EXPORT_SYMBOL(sysctl_tcp_ts_control); +#endif /* OPLUS_BUG_STABILITY */ + /* * Current number of TCP sockets. */ diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 449ac51aed34..b87fceef67f5 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -108,6 +108,11 @@ int sysctl_tcp_max_orphans __read_mostly = NR_FILE; #define TCP_REMNANT (TCP_FLAG_FIN|TCP_FLAG_URG|TCP_FLAG_SYN|TCP_FLAG_PSH) #define TCP_HP_BITS (~(TCP_RESERVED_BITS|TCP_FLAG_PSH)) +//#ifdef OPLUS_FEATURE_NWPOWER +#include +//#endif /* OPLUS_FEATURE_NWPOWER */ + + #define REXMIT_NONE 0 /* no loss recovery to do */ #define REXMIT_LOST 1 /* retransmit packets marked lost */ #define REXMIT_NEW 2 /* FRTO-style transmit of unsent/new packets */ @@ -657,6 +662,11 @@ new_measure: tp->rcvq_space.time = tp->tcp_mstamp; } +#ifdef OPLUS_FEATURE_APP_MONITOR +/* Add code for push detect function */ +extern void oplus_app_monitor_update_app_info(struct sock *sk, const struct sk_buff *skb, int send, int retrans); +#endif /* OPLUS_FEATURE_APP_MONITOR */ + /* There is something which you must keep in mind when you analyze the * behavior of the tp->ato delayed ack timeout interval. When a * connection starts up, we want to ack as quickly as possible. The @@ -711,6 +721,11 @@ static void tcp_event_data_recv(struct sock *sk, struct sk_buff *skb) if (skb->len >= 128) tcp_grow_window(sk, skb); + + #ifdef OPLUS_FEATURE_APP_MONITOR + /* Add code for push detect function */ + oplus_app_monitor_update_app_info(sk, skb, 0, 0); + #endif /* OPLUS_FEATURE_APP_MONITOR */ } /* Called to compute a smoothed rtt estimate. The data fed to this @@ -4804,6 +4819,11 @@ queue_and_out: if (!after(TCP_SKB_CB(skb)->end_seq, tp->rcv_nxt)) { /* A retransmit, 2nd most common case. Force an immediate ack. */ + + //#ifdef OPLUS_FEATURE_NWPOWER + oplus_match_tcp_input_retrans(sk); + //#endif /* OPLUS_FEATURE_NWPOWER */ + NET_INC_STATS(sock_net(sk), LINUX_MIB_DELAYEDACKLOST); tcp_dsack_set(sk, TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq); @@ -5833,6 +5853,16 @@ static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb, struct tcp_fastopen_cookie foc = { .len = -1 }; int saved_clamp = tp->rx_opt.mss_clamp; bool fastopen_fail; + #ifdef OPLUS_BUG_STABILITY + static int ts_error_count = 0; + int ts_error_threshold = sysctl_tcp_ts_control[0]; + + //when network change (frameworks set sysctl_tcp_ts_control[1] = 1), clear ts_error_count + if (sysctl_tcp_ts_control[1] == 1) { + ts_error_count = 0; + sysctl_tcp_ts_control[1] = 0; + } + #endif /* OPLUS_BUG_STABILITY */ tcp_parse_options(sock_net(sk), skb, &tp->rx_opt, 0, &foc); if (tp->rx_opt.saw_tstamp && tp->rx_opt.rcv_tsecr) @@ -5856,9 +5886,25 @@ static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb, tcp_time_stamp(tp))) { NET_INC_STATS(sock_net(sk), LINUX_MIB_PAWSACTIVEREJECTED); + #ifdef OPLUS_BUG_STABILITY + //if count > threshold, disable TCP Timestamps + if (ts_error_threshold > 0) { + ts_error_count++; + if (ts_error_count >= ts_error_threshold) { + sock_net(sk)->ipv4.sysctl_tcp_timestamps = 0; + ts_error_count = 0; + } + } + #endif /* OPLUS_BUG_STABILITY */ goto reset_and_undo; } - + #ifdef OPLUS_BUG_STABILITY + //if other connection's Timestamp is correct, the network environment may be OK + if (tp->rx_opt.saw_tstamp && tp->rx_opt.rcv_tsecr && + ts_error_threshold > 0 && ts_error_count > 0) { + ts_error_count--; + } + #endif /* OPLUS_BUG_STABILITY */ /* Now ACK is acceptable. * * "If the RST bit is set diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index ee5a598a6301..6f1ed580fc52 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -87,6 +87,14 @@ #include +//#ifdef OPLUS_FEATURE_NWPOWER +#include +//#endif /* OPLUS_FEATURE_NWPOWER */ + +#ifdef OPLUS_FEATURE_WIFI_ROUTERBOOST +#include "net/oplus/oplus_router_boost.h" +#endif /* OPLUS_FEATURE_WIFI_ROUTERBOOST */ + #ifdef CONFIG_TCP_MD5SIG static int tcp_v4_md5_hash_hdr(char *md5_hash, const struct tcp_md5sig_key *key, __be32 daddr, __be32 saddr, const struct tcphdr *th); @@ -1721,6 +1729,10 @@ int tcp_v4_rcv(struct sk_buff *skb) struct sock *sk; int ret; + //#ifdef OPLUS_FEATURE_NWPOWER + oplus_match_ipa_ip_wakeup(OPLUS_TCP_TYPE_V4, skb); + //#endif /* OPLUS_FEATURE_NWPOWER */ + if (skb->pkt_type != PACKET_HOST) goto discard_it; @@ -1753,6 +1765,17 @@ lookup: if (!sk) goto no_tcp_socket; + //#ifdef OPLUS_FEATURE_NWPOWER + oplus_match_ipa_tcp_wakeup(OPLUS_TCP_TYPE_V4, sk); + //#endif /* OPLUS_FEATURE_NWPOWER */ + + #ifdef OPLUS_FEATURE_WIFI_ROUTERBOOST + if (oplus_router_boost_handler != NULL && + oplus_router_boost_handler(sk, skb) < 0) { + goto discard_it; + } + #endif /* OPLUS_FEATURE_WIFI_ROUTERBOOST */ + process: if (sk->sk_state == TCP_TIME_WAIT) goto do_time_wait; @@ -1873,6 +1896,9 @@ bad_packet: } discard_it: + //#ifdef OPLUS_FEATURE_NWPOWER + oplus_ipa_schedule_work(); + //#endif /* OPLUS_FEATURE_NWPOWER */ /* Discard frame. */ kfree_skb(skb); return 0; @@ -2589,6 +2615,11 @@ static int __net_init tcp_sk_init(struct net *net) net->ipv4.sysctl_tcp_sack = 1; net->ipv4.sysctl_tcp_window_scaling = 1; net->ipv4.sysctl_tcp_timestamps = 1; + + #ifdef OPLUS_BUG_STABILITY + net->ipv4.sysctl_tcp_random_timestamp = 1; + #endif /* OPLUS_BUG_STABILITY */ + net->ipv4.sysctl_tcp_early_retrans = 3; net->ipv4.sysctl_tcp_recovery = TCP_RACK_LOSS_DETECTION; net->ipv4.sysctl_tcp_slow_start_after_idle = 1; /* By default, RFC2861 behavior. */ diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 405f729bdc08..4b00e81c9ef9 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -41,13 +41,25 @@ #include #include #include +//#ifdef OPLUS_FEATURE_DATA_EVAL +#include +//#endif /* OPLUS_FEATURE_DATA_EVAL */ #include #include +//#ifdef OPLUS_FEATURE_NWPOWER +#include +//#endif /* OPLUS_FEATURE_NWPOWER */ + static bool tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle, int push_one, gfp_t gfp); +#ifdef OPLUS_FEATURE_APP_MONITOR +/* Add code for push detect function */ +extern void oplus_app_monitor_update_app_info(struct sock *sk, const struct sk_buff *skb, int send, int retrans); +#endif /* OPLUS_FEATURE_APP_MONITOR */ + /* Account for new data that has been sent to the network. */ static void tcp_event_new_data_sent(struct sock *sk, struct sk_buff *skb) { @@ -1164,8 +1176,17 @@ static int __tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, memset(skb->cb, 0, max(sizeof(struct inet_skb_parm), sizeof(struct inet6_skb_parm))); + #ifdef OPLUS_FEATURE_APP_MONITOR + /* Add code for push detect function */ + oplus_app_monitor_update_app_info(sk, skb, 1, 0); + #endif /* OPLUS_FEATURE_APP_MONITOR */ + err = icsk->icsk_af_ops->queue_xmit(sk, skb, &inet->cork.fl); + //#ifdef OPLUS_FEATURE_NWPOWER + oplus_match_tcp_output(sk); + //#endif /* OPLUS_FEATURE_NWPOWER */ + if (unlikely(err > 0)) { tcp_enter_cwr(sk); err = net_xmit_eval(err); @@ -2971,6 +2992,16 @@ int __tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb, int segs) if (likely(!err)) { TCP_SKB_CB(skb)->sacked |= TCPCB_EVER_RETRANS; + + #ifdef OPLUS_FEATURE_APP_MONITOR + /* Add code for push detect function */ + oplus_app_monitor_update_app_info(sk, skb, 1, 1); + #endif /* OPLUS_FEATURE_APP_MONITOR */ + + //#ifdef OPLUS_FEATURE_NWPOWER + oplus_match_tcp_output_retrans(sk); + //#endif /* OPLUS_FEATURE_NWPOWER */ + trace_tcp_retransmit_skb(sk, skb); } else if (err != -EBUSY) { NET_ADD_STATS(sock_net(sk), LINUX_MIB_TCPRETRANSFAIL, segs); diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c index dc218b4d2003..a8a1191f56e3 100644 --- a/net/ipv4/tcp_timer.c +++ b/net/ipv4/tcp_timer.c @@ -22,6 +22,11 @@ #include #include +#ifdef OPLUS_FEATURE_IPV6_OPTIMIZE +extern int ipv6_rto_encounter(kuid_t uid, struct in6_addr v6_saddr); +extern int ipv4_rto_encounter(kuid_t uid, unsigned int v4_saddr); +#endif /* OPLUS_FEATURE_IPV6_OPTIMIZE */ + static u32 tcp_clamp_rto_to_user_timeout(const struct sock *sk) { struct inet_connection_sock *icsk = inet_csk(sk); @@ -290,6 +295,18 @@ static int tcp_write_timeout(struct sock *sk) icsk->icsk_rto, (int)expired); if (expired) { + #ifdef OPLUS_FEATURE_IPV6_OPTIMIZE + if (((1 << sk->sk_state) & (TCPF_SYN_SENT | TCPF_ESTABLISHED)) + && !((1 << sk->sk_state) & (TCPF_SYN_RECV | TCPF_FIN_WAIT1 | TCPF_FIN_WAIT2 | TCPF_TIME_WAIT))) { + if(sk->sk_family == AF_INET6) { +#if IS_ENABLED(CONFIG_IPV6) + ipv6_rto_encounter(sk->sk_uid, sk->__sk_common.skc_v6_rcv_saddr); +#endif /* IS_ENABLED(CONFIG_IPV6) */ + } else if (sk->sk_family == AF_INET) { + ipv4_rto_encounter(sk->sk_uid, sk->__sk_common.skc_rcv_saddr); + } + } + #endif /* OPLUS_FEATURE_IPV6_OPTIMIZE */ /* Has it gone just too far? */ tcp_write_err(sk); return 1; diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 5c0fca672075..0f3e86f6e1f9 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -117,6 +117,10 @@ #include #include +#ifdef OPLUS_FEATURE_WIFI_ROUTERBOOST +#include "net/oplus/oplus_router_boost.h" +#endif /* OPLUS_FEATURE_WIFI_ROUTERBOOST */ + struct udp_table udp_table __read_mostly; EXPORT_SYMBOL(udp_table); @@ -2059,6 +2063,15 @@ static int udp_queue_rcv_skb(struct sock *sk, struct sk_buff *skb) struct sk_buff *next, *segs; int ret; + #ifdef OPLUS_FEATURE_WIFI_ROUTERBOOST + if (oplus_router_boost_handler != NULL && + oplus_router_boost_handler(sk, skb) < 0) { + kfree_skb(skb); + // note: <0 or 0 both infers that we have handled this pkt + return -1; + } + #endif /* OPLUS_FEATURE_WIFI_ROUTERBOOST */ + if (likely(!udp_unexpected_gso(sk, skb))) return udp_queue_rcv_one_skb(sk, skb); diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c index 6098e2097dc4..d99724f9c462 100644 --- a/net/ipv6/netfilter/ip6_tables.c +++ b/net/ipv6/netfilter/ip6_tables.c @@ -788,25 +788,6 @@ get_counters(const struct xt_table_info *t, } } -static void get_old_counters(const struct xt_table_info *t, - struct xt_counters counters[]) -{ - struct ip6t_entry *iter; - unsigned int cpu, i; - - for_each_possible_cpu(cpu) { - i = 0; - xt_entry_foreach(iter, t->entries, t->size) { - const struct xt_counters *tmp; - - tmp = xt_get_per_cpu_counter(&iter->counters, cpu); - ADD_COUNTER(counters[i], tmp->bcnt, tmp->pcnt); - ++i; - } - cond_resched(); - } -} - static struct xt_counters *alloc_counters(const struct xt_table *table) { unsigned int countersize; @@ -1097,7 +1078,8 @@ __do_replace(struct net *net, const char *name, unsigned int valid_hooks, (newinfo->number <= oldinfo->initial_entries)) module_put(t->me); - get_old_counters(oldinfo, counters); + /* Get the old counters, and synchronize with replace */ + get_counters(oldinfo, counters); /* Decrease module usage counts and free resource */ xt_entry_foreach(iter, oldinfo->entries, oldinfo->size) diff --git a/net/ipv6/route.c b/net/ipv6/route.c index b5b3fa3e33da..a3f495901e9e 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -2390,6 +2390,13 @@ static void __ip6_rt_update_pmtu(struct dst_entry *dst, const struct sock *sk, if (confirm_neigh) dst_confirm_neigh(dst, daddr); +#ifdef OPLUS_BUG_STABILITY + //ipv6 RFC8201 test + if (mtu < IPV6_MIN_MTU) { + return; + } +#endif /* OPLUS_BUG_STABILITY */ + mtu = max_t(u32, mtu, IPV6_MIN_MTU); if (mtu >= dst_mtu(dst)) return; diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 3052e531f4ee..240d496dd310 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -71,6 +71,10 @@ #include +//#ifdef OPLUS_FEATURE_NWPOWER +#include +//#endif /* OPLUS_FEATURE_NWPOWER */ + static void tcp_v6_send_reset(const struct sock *sk, struct sk_buff *skb); static void tcp_v6_reqsk_send_ack(const struct sock *sk, struct sk_buff *skb, struct request_sock *req); @@ -1472,6 +1476,10 @@ static int tcp_v6_rcv(struct sk_buff *skb) int ret; struct net *net = dev_net(skb->dev); + //#ifdef OPLUS_FEATURE_NWPOWER + oplus_match_ipa_ip_wakeup(OPLUS_TCP_TYPE_V6, skb); + //#endif /* OPLUS_FEATURE_NWPOWER */ + if (skb->pkt_type != PACKET_HOST) goto discard_it; @@ -1503,6 +1511,10 @@ lookup: if (!sk) goto no_tcp_socket; + //#ifdef OPLUS_FEATURE_NWPOWER + oplus_match_ipa_tcp_wakeup(OPLUS_TCP_TYPE_V6, sk); + //#endif /* OPLUS_FEATURE_NWPOWER */ + process: if (sk->sk_state == TCP_TIME_WAIT) goto do_time_wait; @@ -1617,6 +1629,9 @@ bad_packet: } discard_it: + //#ifdef OPLUS_FEATURE_NWPOWER + oplus_ipa_schedule_work(); + //#endif /* OPLUS_FEATURE_NWPOWER */ kfree_skb(skb); return 0; diff --git a/net/netfilter/nf_log_common.c b/net/netfilter/nf_log_common.c index b164a0e1e053..acb2221fa3d8 100644 --- a/net/netfilter/nf_log_common.c +++ b/net/netfilter/nf_log_common.c @@ -141,9 +141,16 @@ void nf_log_dump_sk_uid_gid(struct net *net, struct nf_log_buf *m, read_lock_bh(&sk->sk_callback_lock); if (sk->sk_socket && sk->sk_socket->file) { const struct cred *cred = sk->sk_socket->file->f_cred; - nf_log_buf_add(m, "UID=%u GID=%u ", + //#ifndef VENDOR_EDIT + /*nf_log_buf_add(m, "UID=%u GID=%u ", from_kuid_munged(&init_user_ns, cred->fsuid), - from_kgid_munged(&init_user_ns, cred->fsgid)); + from_kgid_munged(&init_user_ns, cred->fsgid));*/ + //else /* VENDOR_EDIT */ + nf_log_buf_add(m, "UID=%u GID=%u cmdline=%s", + from_kuid_munged(&init_user_ns, cred->fsuid), + from_kgid_munged(&init_user_ns, cred->fsgid), + sk->sk_cmdline); + //#enidf /* VENDOR_EDIT */ } read_unlock_bh(&sk->sk_callback_lock); } diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c index 5dd6f6ce92e6..1c91815d73b5 100644 --- a/net/netfilter/x_tables.c +++ b/net/netfilter/x_tables.c @@ -1357,7 +1357,6 @@ xt_replace_table(struct xt_table *table, int *error) { struct xt_table_info *private; - unsigned int cpu; int ret; ret = xt_jumpstack_alloc(newinfo); @@ -1387,28 +1386,14 @@ xt_replace_table(struct xt_table *table, smp_wmb(); table->private = newinfo; - /* make sure all cpus see new ->private value */ - smp_mb(); - /* * Even though table entries have now been swapped, other CPU's - * may still be using the old entries... + * may still be using the old entries. This is okay, because + * resynchronization happens because of the locking done + * during the get_counters() routine. */ local_bh_enable(); - /* ... so wait for even xt_recseq on all cpus */ - for_each_possible_cpu(cpu) { - seqcount_t *s = &per_cpu(xt_recseq, cpu); - u32 seq = raw_read_seqcount(s); - - if (seq & 1) { - do { - cond_resched(); - cpu_relax(); - } while (seq == raw_read_seqcount(s)); - } - } - #ifdef CONFIG_AUDIT if (audit_enabled) { audit_log(audit_context(), GFP_KERNEL, diff --git a/net/netfilter/xt_HARDIDLETIMER.c b/net/netfilter/xt_HARDIDLETIMER.c index 055763b785ce..4674a9bf678b 100644 --- a/net/netfilter/xt_HARDIDLETIMER.c +++ b/net/netfilter/xt_HARDIDLETIMER.c @@ -146,6 +146,10 @@ static enum alarmtimer_restart hardidletimer_tg_alarmproc(struct alarm *alarm, return ALARMTIMER_NORESTART; } +#ifdef OPLUS_FEATURE_POWERINFO_STANDBY +enum alarmtimer_restart (*net_alarm_func)(struct alarm *, ktime_t now) = hardidletimer_tg_alarmproc; +#endif /* OPLUS_FEATURE_POWERINFO_STANDBY */ + static int hardidletimer_tg_create(struct hardidletimer_tg_info *info) { int ret; diff --git a/net/netfilter/xt_owner.c b/net/netfilter/xt_owner.c index 46686fb73784..4fba95b496fc 100644 --- a/net/netfilter/xt_owner.c +++ b/net/netfilter/xt_owner.c @@ -20,6 +20,25 @@ #include #include + +#ifndef OPLUS_FEATURE_XTOWNER_INPUT +#define OPLUS_FEATURE_XTOWNER_INPUT +#endif + +#ifdef OPLUS_FEATURE_XTOWNER_INPUT +//add for BUG 2212301 +#include +#if IS_ENABLED(CONFIG_IP6_NF_IPTABLES) +#include +#include +#include +#endif +#include +#include +#define XT_SOCKET_SUPPORTED_HOOKS \ + ((1 << NF_INET_PRE_ROUTING) | (1 << NF_INET_LOCAL_IN)) +#endif /*OPLUS_FEATURE_XTOWNER_INPUT*/ + static int owner_check(const struct xt_mtchk_param *par) { struct xt_owner_match_info *info = par->matchinfo; @@ -59,6 +78,45 @@ static int owner_check(const struct xt_mtchk_param *par) return 0; } +#ifdef OPLUS_FEATURE_XTOWNER_INPUT +//add for BUG 2212301 +static struct sock *oem_qtaguid_find_sk(const struct sk_buff *skb, + struct xt_action_param *par) +{ + const struct nf_hook_state *parst = par->state; + struct sock *sk; + unsigned int hook_mask = (1 << parst->hook); + + + pr_debug("qtaguid[%d]: find_sk(skb=%pK) family=%d\n", + parst->hook, skb, parst->pf); + + /* + * Let's not abuse the the xt_socket_get*_sk(), or else it will + * return garbage SKs. + */ + if (!(hook_mask & XT_SOCKET_SUPPORTED_HOOKS)) + return NULL; + + switch (parst->pf) { + case NFPROTO_IPV6: + sk = nf_sk_lookup_slow_v6(dev_net(skb->dev), skb, parst->in); + break; + case NFPROTO_IPV4: + sk = nf_sk_lookup_slow_v4(dev_net(skb->dev), skb, parst->in); + break; + default: + return NULL; + } + + if (sk) { + pr_debug("qtaguid[%d]: %p->sk_proto=%u->sk_state=%d\n", parst->hook, sk, sk->sk_protocol, sk->sk_state); + } + + return sk; +} +#endif /*OPLUS_FEATURE_XTOWNER_INPUT*/ + static bool owner_mt(const struct sk_buff *skb, struct xt_action_param *par) { @@ -67,6 +125,55 @@ owner_mt(const struct sk_buff *skb, struct xt_action_param *par) struct sock *sk = skb_to_full_sk(skb); struct net *net = xt_net(par); + #ifdef OPLUS_FEATURE_XTOWNER_INPUT + //add for BUG 2212301 + /* + * When in TCP_TIME_WAIT the sk is not a "struct sock" but + * "struct inet_timewait_sock" which is missing fields + * So we ignore it + */ + if (sk && sk->sk_state == TCP_TIME_WAIT){ + pr_debug("owner_mt 1 : sk: %p, sk->sk_state: %d \n", sk, sk->sk_state); + sk = NULL; + } + if (sk == NULL) { + /* + * A missing sk->sk_socket happens when packets are in-flight + * and the matching socket is already closed and gone. + */ + sk = oem_qtaguid_find_sk(skb, par); + /* + * TCP_NEW_SYN_RECV are not "struct sock" but "struct request_sock" + * where we can get a pointer to a full socket to retrieve uid/gid. + * When in TCP_TIME_WAIT, sk is a struct inet_timewait_sock + * which is missing fields and does not contain any reference + * to a full socket, so just ignore the socket + */ + if (sk && sk->sk_state == TCP_NEW_SYN_RECV) { + pr_debug("owner_mt 2 : sk: %p, sk->sk_state: %d \n", sk, sk->sk_state); + sock_gen_put(sk); + sk = sk_to_full_sk(sk); + } else if (sk && (!sk_fullsock(sk) || sk->sk_state == TCP_TIME_WAIT)) { + pr_debug("owner_mt 3 : sk: %p, sk->sk_state: %d \n", sk, sk->sk_state); + sock_gen_put(sk); + sk = NULL; + } + //#ifdef OPLUS_FEATURE_XTOWNER_INPUT + else if (sk && sk->sk_state == TCP_CLOSE) { + sock_gen_put(sk); + } else if (sk) { + pr_debug("owner_mt: sk: %px, sk->sk_state: %d \n", sk, sk->sk_state); + //WARN_ON(1); + sock_gen_put(sk); + } + //#endif + } + + if(sk) { + pr_debug("owner_mt: sk: %p, sk->sk_state: %d, sk->sk_socket: %p\n", sk, sk->sk_state, sk->sk_socket); + } + #endif /*OPLUS_FEATURE_XTOWNER_INPUT*/ + if (!sk || !sk->sk_socket || !net_eq(net, sock_net(sk))) return (info->match ^ info->invert) == 0; else if (info->match & info->invert & XT_OWNER_SOCKET) @@ -79,14 +186,14 @@ owner_mt(const struct sk_buff *skb, struct xt_action_param *par) filp = sk->sk_socket->file; if (filp == NULL) return ((info->match ^ info->invert) & - (XT_OWNER_UID | XT_OWNER_GID)) == 0; + (XT_OWNER_UID | XT_OWNER_GID)) == 0; if (info->match & XT_OWNER_UID) { kuid_t uid_min = make_kuid(net->user_ns, info->uid_min); kuid_t uid_max = make_kuid(net->user_ns, info->uid_max); if ((uid_gte(filp->f_cred->fsuid, uid_min) && - uid_lte(filp->f_cred->fsuid, uid_max)) ^ - !(info->invert & XT_OWNER_UID)) + uid_lte(filp->f_cred->fsuid, uid_max)) ^ + !(info->invert & XT_OWNER_UID)) return false; } @@ -94,8 +201,8 @@ owner_mt(const struct sk_buff *skb, struct xt_action_param *par) kgid_t gid_min = make_kgid(net->user_ns, info->gid_min); kgid_t gid_max = make_kgid(net->user_ns, info->gid_max); if ((gid_gte(filp->f_cred->fsgid, gid_min) && - gid_lte(filp->f_cred->fsgid, gid_max)) ^ - !(info->invert & XT_OWNER_GID)) + gid_lte(filp->f_cred->fsgid, gid_max)) ^ + !(info->invert & XT_OWNER_GID)) return false; } @@ -109,8 +216,14 @@ static struct xt_match owner_mt_reg __read_mostly = { .checkentry = owner_check, .match = owner_mt, .matchsize = sizeof(struct xt_owner_match_info), +#ifndef OPLUS_FEATURE_XTOWNER_INPUT .hooks = (1 << NF_INET_LOCAL_OUT) | (1 << NF_INET_POST_ROUTING), +#else + .hooks = (1 << NF_INET_LOCAL_OUT) | + (1 << NF_INET_POST_ROUTING) | + (1 << NF_INET_LOCAL_IN), +#endif .me = THIS_MODULE, }; diff --git a/net/oplus_apps_monitor/Makefile b/net/oplus_apps_monitor/Makefile new file mode 100644 index 000000000000..de9585f4aab3 --- /dev/null +++ b/net/oplus_apps_monitor/Makefile @@ -0,0 +1,5 @@ +# +# Makefile for the netfilter modules on top of IPv4. +# +obj-y += oplus_app_monitor.o +oplus_app_monitor-objs := oplus_apps_monitor.o oplus_apps_power_monitor.o \ No newline at end of file diff --git a/net/oplus_apps_monitor/oplus_apps_monitor.c b/net/oplus_apps_monitor/oplus_apps_monitor.c new file mode 100644 index 000000000000..3db4d25f9d66 --- /dev/null +++ b/net/oplus_apps_monitor/oplus_apps_monitor.c @@ -0,0 +1,700 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* +* Copyright (C) 2018-2020 Oplus. All rights reserved. +*/ + +#include +#include + +#define MONITOR_APPS_NUM_MAX (32) +#define IFACE_NUM_MAX (2) +#define WLAN_INDEX (0) +#define CELL_INDEX (1) +#define ALL_IF_INDEX (IFACE_NUM_MAX) + +#define DEFAULT_RTT_EXCE_THRED (100) +#define DEFAULT_RTT_GOOD_THRED (150) +#define DEFAULT_RTT_FAIR_THRED (200) +#define DEFAULT_RTT_POOR_THRED (250) + +#define APP_UID_IS_EMPTY (-1) +#define TIMER_EXPIRES HZ + +//the dual sta feature, the wlan/cell index is changed in oplus_sla.c +#define DUAL_STA_FEATRUE_FLAG (1) +#define DUAL_STA_WLAN0_INDEX (0) +#define DUAL_STA_WLAN1_INDEX (1) +#define DUAL_STA_CELL_INDEX (2) + +/*NLMSG_MIN_TYPE is 0x10,so we start at 0x11*/ +enum{ + APPS_MONITOR_SET_ANDROID_PID = 0x11, + APPS_MONITOR_SET_APPS_UID = 0x12, + APPS_MONITOR_GET_APPS_CELL_RTT = 0x13, + APPS_MONITOR_GET_APPS_WLAN_RTT = 0x14, + APPS_MONITOR_GET_APPS_ALL_RTT = 0x15, + APPS_MONITOR_REPORT_APPS_CELL_RTT = 0x16, + APPS_MONITOR_REPORT_APPS_WLAN_RTT = 0x17, + APPS_MONITOR_REPORT_APPS_ALL_RTT = 0x18, + APPS_MOINTOR_SET_RTT_THRED = 0x19, + APPS_MONITOR_GET_DEV_RTT = 0x20, + APPS_MONITOR_REPORT_DEV_RTT = 0x21, + //added for power monitor function + APPS_POWER_MONITOR_MSG_DL_CTRL = 0x30, + APPS_POWER_MONITOR_MSG_DL_RPT_CTRL, + APPS_POWER_MONITOR_MSG_UL_INFO, + APPS_POWER_MONITOR_MSG_UL_BEAT_ALARM, + APPS_POWER_MONITOR_MSG_UL_PUSH_ALARM, + APPS_POWER_MONITOR_MSG_UL_TRAFFIC_ALARM, +}; + +typedef struct rtt_params { + u64 rtt_exce_count; + u64 rtt_good_count; + u64 rtt_fair_count; + u64 rtt_poor_count; + u64 rtt_bad_count; + u64 rtt_total_count; +} rtt_params; + +typedef struct rtt_params_thred { + u32 rtt_exce_thred; + u32 rtt_good_thred; + u32 rtt_fair_thred; + u32 rtt_poor_thred; +} rtt_params_thred; + +typedef struct monitor_app_params { + int app_uid; + rtt_params app_rtt[IFACE_NUM_MAX]; +} monitor_app_params; + +static int g_monitor_apps_num = 0; +static monitor_app_params g_monitor_apps_table[MONITOR_APPS_NUM_MAX]; +static rtt_params g_monitor_dev_table[IFACE_NUM_MAX]; +static rtt_params_thred g_rtt_params_thred = {DEFAULT_RTT_EXCE_THRED, DEFAULT_RTT_GOOD_THRED, DEFAULT_RTT_FAIR_THRED, DEFAULT_RTT_POOR_THRED}; + +static u32 apps_monitor_netlink_pid = 0; +static int apps_monitor_debug = 0; +static int rrt_period_report_enable = 1; +static int rrt_period_report_timer = 5; //5 sec +static struct sock *apps_monitor_netlink_sock; +static struct timer_list apps_monitor_timer; + +static DEFINE_MUTEX(apps_monitor_netlink_mutex); +static struct ctl_table_header *apps_monitor_table_hrd; +static rwlock_t apps_monitor_lock; + +#define apps_monitor_read_lock() read_lock_bh(&apps_monitor_lock); +#define apps_monitor_read_unlock() read_unlock_bh(&apps_monitor_lock); +#define apps_monitor_write_lock() write_lock_bh(&apps_monitor_lock); +#define apps_monitor_write_unlock() write_unlock_bh(&apps_monitor_lock); + +/* send to user space */ +int apps_monitor_netlink_send_to_user(int msg_type, char *payload, int payload_len) +{ + int ret = 0; + struct sk_buff *skbuff; + struct nlmsghdr *nlh; + + if (!apps_monitor_netlink_pid) { + printk("oplus_apps_monitor: apps_monitor_netlink_send_to_user, can not unicast skbuff, apps_monitor_netlink_pid=0\n"); + return -1; + } + + /*allocate new buffer cache */ + skbuff = alloc_skb(NLMSG_SPACE(payload_len), GFP_ATOMIC); + if (skbuff == NULL) { + printk("oplus_apps_monitor: apps_monitor_netlink_send_to_user, skbuff alloc_skb failed\n"); + return -1; + } + + /* fill in the data structure */ + nlh = nlmsg_put(skbuff, 0, 0, msg_type, NLMSG_ALIGN(payload_len), 0); + if (nlh == NULL) { + printk("oplus_apps_monitor: apps_monitor_netlink_send_to_user, nlmsg_put failaure\n"); + nlmsg_free(skbuff); + return -1; + } + + //compute nlmsg length + nlh->nlmsg_len = NLMSG_HDRLEN + NLMSG_ALIGN(payload_len); + + if(NULL != payload){ + memcpy((char *)NLMSG_DATA(nlh),payload,payload_len); + } + + /* set control field,sender's pid */ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,7,0)) + NETLINK_CB(skbuff).pid = 0; +#else + NETLINK_CB(skbuff).portid = 0; +#endif + + NETLINK_CB(skbuff).dst_group = 0; + + /* send data */ + if(apps_monitor_netlink_pid){ + ret = netlink_unicast(apps_monitor_netlink_sock, skbuff, apps_monitor_netlink_pid, MSG_DONTWAIT); + } else { + printk(KERN_ERR "oplus_apps_monitor: apps_monitor_netlink_send_to_user, can not unicast skbuff, apps_monitor_netlink_pid=0\n"); + kfree_skb(skbuff); + } + + if(ret < 0){ + printk(KERN_ERR "oplus_apps_monitor: apps_monitor_netlink_send_to_user, can not unicast skbuff, ret = %d\n", ret); + return -1; + } + + return 0; +} +EXPORT_SYMBOL(apps_monitor_netlink_send_to_user); + +static struct ctl_table apps_monitor_sysctl_table[] = { + { + .procname = "apps_monitor_debug", + .data = &apps_monitor_debug, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec, + }, + { + .procname = "rrt_period_report_enable", + .data = &rrt_period_report_enable, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec, + }, + { } +}; + +static void set_monitor_apps_param_default(void) +{ + int i = 0; + int j = 0; + + for (i = 0; i < MONITOR_APPS_NUM_MAX; ++i) { + g_monitor_apps_table[i].app_uid = APP_UID_IS_EMPTY; + + for (j = 0; j < IFACE_NUM_MAX; ++j) { + g_monitor_apps_table[i].app_rtt[j].rtt_exce_count = 0; + g_monitor_apps_table[i].app_rtt[j].rtt_fair_count = 0; + g_monitor_apps_table[i].app_rtt[j].rtt_good_count = 0; + g_monitor_apps_table[i].app_rtt[j].rtt_poor_count = 0; + g_monitor_apps_table[i].app_rtt[j].rtt_bad_count = 0; + g_monitor_apps_table[i].app_rtt[j].rtt_total_count = 0; + } + } +} + +static void clear_apps_rtt_record(int if_index) +{ + int i = 0; + int j = 0; + + switch (if_index) { + case WLAN_INDEX: + for (i = 0; i < g_monitor_apps_num; ++i) { + g_monitor_apps_table[i].app_rtt[WLAN_INDEX].rtt_exce_count = 0; + g_monitor_apps_table[i].app_rtt[WLAN_INDEX].rtt_fair_count = 0; + g_monitor_apps_table[i].app_rtt[WLAN_INDEX].rtt_good_count = 0; + g_monitor_apps_table[i].app_rtt[WLAN_INDEX].rtt_poor_count = 0; + g_monitor_apps_table[i].app_rtt[WLAN_INDEX].rtt_bad_count = 0; + g_monitor_apps_table[i].app_rtt[WLAN_INDEX].rtt_total_count = 0; + } + break; + case CELL_INDEX: + for (i = 0; i < g_monitor_apps_num; ++i) { + g_monitor_apps_table[i].app_rtt[CELL_INDEX].rtt_exce_count = 0; + g_monitor_apps_table[i].app_rtt[CELL_INDEX].rtt_fair_count = 0; + g_monitor_apps_table[i].app_rtt[CELL_INDEX].rtt_good_count = 0; + g_monitor_apps_table[i].app_rtt[CELL_INDEX].rtt_poor_count = 0; + g_monitor_apps_table[i].app_rtt[CELL_INDEX].rtt_bad_count = 0; + g_monitor_apps_table[i].app_rtt[CELL_INDEX].rtt_total_count = 0; + } + break; + case ALL_IF_INDEX: + for (i = 0; i < g_monitor_apps_num; ++i) { + for (j = 0; j < IFACE_NUM_MAX; ++j) { + g_monitor_apps_table[i].app_rtt[j].rtt_exce_count = 0; + g_monitor_apps_table[i].app_rtt[j].rtt_fair_count = 0; + g_monitor_apps_table[i].app_rtt[j].rtt_good_count = 0; + g_monitor_apps_table[i].app_rtt[j].rtt_poor_count = 0; + g_monitor_apps_table[i].app_rtt[j].rtt_bad_count = 0; + g_monitor_apps_table[i].app_rtt[j].rtt_total_count = 0; + } + } + break; + default: + break; + } +} + +static void clear_dev_rtt_record(void) +{ + int i = 0; + + for (i = 0; i < IFACE_NUM_MAX; ++i) { + g_monitor_dev_table[i].rtt_exce_count = 0; + g_monitor_dev_table[i].rtt_fair_count = 0; + g_monitor_dev_table[i].rtt_good_count = 0; + g_monitor_dev_table[i].rtt_poor_count = 0; + g_monitor_dev_table[i].rtt_bad_count = 0; + g_monitor_dev_table[i].rtt_total_count = 0; + } +} + +static int find_skb_uid_index_in_apps_record_table(struct sock *sk) +{ + kuid_t uid; + kuid_t sk_uid; + int index = 0; + int uid_index = -1; +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4,9,0)) + const struct file *filp = NULL; +#endif + + if (NULL == sk || !sk_fullsock(sk) || NULL == sk->sk_socket) { + return uid_index; + } + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4,9,0)) + filp = sk->sk_socket->file; + + if(NULL == filp) { + return false; + } + + sk_uid = filp->f_cred->fsuid; +#else + sk_uid = sk->sk_uid; +#endif + + for(index = 0; index < g_monitor_apps_num; ++index) { + uid = make_kuid(&init_user_ns, g_monitor_apps_table[index].app_uid); + + if(uid_eq(sk_uid, uid)) { + uid_index = index; + break; + } + } + + return uid_index; +} + +void update_dev_rtt_count(int if_index, int rtt) +{ + if (rtt < 0 || if_index < 0 || if_index >= IFACE_NUM_MAX) { + return; + } + + if (rtt <= g_rtt_params_thred.rtt_exce_thred) { + ++(g_monitor_dev_table[if_index].rtt_exce_count); + } else if (rtt <= g_rtt_params_thred.rtt_good_thred) { + ++(g_monitor_dev_table[if_index].rtt_good_count); + } else if (rtt <= g_rtt_params_thred.rtt_fair_thred) { + ++(g_monitor_dev_table[if_index].rtt_fair_count); + } else if (rtt <= g_rtt_params_thred.rtt_poor_thred) { + ++(g_monitor_dev_table[if_index].rtt_poor_count); + } else { + ++(g_monitor_dev_table[if_index].rtt_bad_count); + } + + ++(g_monitor_dev_table[if_index].rtt_total_count); + + return; +} + +void update_app_rtt_count(int if_index, int sk_uid_index, int rtt) +{ + if (rtt < 0 || if_index < 0 || if_index >= IFACE_NUM_MAX) { + return; + } + + if (rtt <= g_rtt_params_thred.rtt_exce_thred) { + ++(g_monitor_apps_table[sk_uid_index].app_rtt[if_index].rtt_exce_count); + } else if (rtt <= g_rtt_params_thred.rtt_good_thred) { + ++(g_monitor_apps_table[sk_uid_index].app_rtt[if_index].rtt_good_count); + } else if (rtt <= g_rtt_params_thred.rtt_fair_thred) { + ++(g_monitor_apps_table[sk_uid_index].app_rtt[if_index].rtt_fair_count); + } else if (rtt <= g_rtt_params_thred.rtt_poor_thred) { + ++(g_monitor_apps_table[sk_uid_index].app_rtt[if_index].rtt_poor_count); + } else { + ++(g_monitor_apps_table[sk_uid_index].app_rtt[if_index].rtt_bad_count); + } + + ++(g_monitor_apps_table[sk_uid_index].app_rtt[if_index].rtt_total_count); + + return; +} + +void statistics_monitor_apps_rtt_via_uid(int if_index, int rtt, struct sock *sk) +{ + int sk_uid_index = -1; + +#if DUAL_STA_FEATRUE_FLAG + if (if_index == DUAL_STA_WLAN0_INDEX || if_index == DUAL_STA_WLAN1_INDEX ) { + if_index = WLAN_INDEX; + } else { + if_index = CELL_INDEX; + } +#endif + + if (rtt < 0 || sk == NULL || if_index < 0 || if_index >= IFACE_NUM_MAX) { + return; + } + +#if 0 + printk("oplus_apps_monitor: statistics_monitor_apps_rtt_via_uid, if_index = %d, rtt = %d\n", if_index, rtt); +#endif + + apps_monitor_write_lock(); + update_dev_rtt_count(if_index, rtt); + + sk_uid_index = find_skb_uid_index_in_apps_record_table(sk); + + if (sk_uid_index < 0) { + apps_monitor_write_unlock(); //need release lock + return; + } + + update_app_rtt_count(if_index, sk_uid_index, rtt); + apps_monitor_write_unlock(); +} + +static int apps_monitor_sysctl_init(void) +{ + apps_monitor_table_hrd = register_net_sysctl(&init_net, "net/oplus_apps_monitor", + apps_monitor_sysctl_table); + return apps_monitor_table_hrd == NULL ? -ENOMEM : 0; +} + +static int apps_monitor_set_android_pid(struct sk_buff *skb) +{ + apps_monitor_netlink_pid = NETLINK_CB(skb).portid; + printk("oplus_apps_monitor: apps_monitor_netlink_set_android_pid pid=%d\n",apps_monitor_netlink_pid); + return 0; +} + +static int apps_monitor_set_apps_uid(struct nlmsghdr *nlh) +{ + int index = 0; + u32 *uidInfo = (u32 *)NLMSG_DATA(nlh); + u32 apps_uid_num = uidInfo[0]; + u32 *apps_uid = &(uidInfo[1]); + + if (apps_uid_num >= MONITOR_APPS_NUM_MAX) { + printk("oplus_apps_monitor: the input apps_uid_num is bigger than MONITOR_APPS_NUM_MAX! \n"); + return -EINVAL; + } + + set_monitor_apps_param_default(); + g_monitor_apps_num = apps_uid_num; + + for (index = 0; index < apps_uid_num; ++index) { + g_monitor_apps_table[index].app_uid = apps_uid[index]; + + if (apps_monitor_debug) { + printk("oplus_apps_monitor: apps_monitor_netlink_set_apps_uid, g_monitor_apps_table[%d].app_uid = %d \n", index, g_monitor_apps_table[index].app_uid); + } + } + + return 0; +} + +static int apps_monitor_set_rtt_thred(struct nlmsghdr *nlh) +{ + u32 *uidInfo = (u32 *)NLMSG_DATA(nlh); + u32 rtt_thred_num = uidInfo[0]; + u32 *rtt_thred = &(uidInfo[1]); + + if (rtt_thred_num > sizeof(rtt_params_thred) / sizeof(u32)) { + printk("oplus_apps_monitor: the input rtt_thred_num is bigger than except! the input rtt_thred_num= %d \n", rtt_thred_num); + return -EINVAL; + } + + g_rtt_params_thred.rtt_exce_thred = rtt_thred[0]; + g_rtt_params_thred.rtt_good_thred = rtt_thred[1]; + g_rtt_params_thred.rtt_fair_thred = rtt_thred[2]; + g_rtt_params_thred.rtt_poor_thred = rtt_thred[3]; + + return 0; +} + +static void print_apps_rtt_record(void) { + int i = 0; + int j = 0; + + for (i = 0; i < g_monitor_apps_num; ++i) { + for(j = 0; j < IFACE_NUM_MAX; ++j) { + printk("oplus_apps_monitor: print_apps_rtt_record, the uid = %d, the if_index = %d, RTT = %llu:%llu:%llu:%llu:%llu:%llu\n", + g_monitor_apps_table[i].app_uid, + j, + g_monitor_apps_table[i].app_rtt[j].rtt_exce_count, + g_monitor_apps_table[i].app_rtt[j].rtt_good_count, + g_monitor_apps_table[i].app_rtt[j].rtt_fair_count, + g_monitor_apps_table[i].app_rtt[j].rtt_poor_count, + g_monitor_apps_table[i].app_rtt[j].rtt_bad_count, + g_monitor_apps_table[i].app_rtt[j].rtt_total_count); + } + } +} + +static void print_dev_rtt_record(void) { + int i = 0; + + for(i = 0; i < IFACE_NUM_MAX; ++i) { + printk("oplus_apps_monitor: print_dev_rtt_record, the if_index = %d, RTT = %llu:%llu:%llu:%llu:%llu:%llu\n", + i, + g_monitor_dev_table[i].rtt_exce_count, + g_monitor_dev_table[i].rtt_good_count, + g_monitor_dev_table[i].rtt_fair_count, + g_monitor_dev_table[i].rtt_poor_count, + g_monitor_dev_table[i].rtt_bad_count, + g_monitor_dev_table[i].rtt_total_count); + } +} + +static int apps_monitor_report_apps_rtt_to_user(int if_index) +{ +#define MAX_RTT_MSG_LEN (2048) + int ret = 0; + int index = 0; + int step = 0; + int rtt_params_size = sizeof(rtt_params); + int int_size = sizeof(int); + static char send_msg[MAX_RTT_MSG_LEN] = {0}; + + memset(send_msg, 0, MAX_RTT_MSG_LEN); + + if ((rtt_params_size + int_size) * IFACE_NUM_MAX * g_monitor_apps_num > MAX_RTT_MSG_LEN) { + printk("oplus_apps_monitor: apps_monitor_report_apps_rtt_to_user, the RTT Msg is too big, len = %0x \n", + (rtt_params_size + int_size) * g_monitor_apps_num); + return -EINVAL; + } + + switch (if_index) { + case WLAN_INDEX: + for(index = 0; index < g_monitor_apps_num; ++index) { + step = (rtt_params_size * index) + index * int_size; + memcpy(send_msg + step, &g_monitor_apps_table[index].app_uid, int_size); + memcpy(send_msg + step + int_size, &(g_monitor_apps_table[index].app_rtt[WLAN_INDEX]), rtt_params_size); + } + + ret = apps_monitor_netlink_send_to_user(APPS_MONITOR_REPORT_APPS_WLAN_RTT, (char *) send_msg, + (rtt_params_size + int_size) * g_monitor_apps_num); + break; + case CELL_INDEX: + for(index = 0; index < g_monitor_apps_num; ++index) { + step = (rtt_params_size * index) + index * int_size; + memcpy(send_msg + step, &g_monitor_apps_table[index].app_uid, int_size); + memcpy(send_msg + step + int_size, &(g_monitor_apps_table[index].app_rtt[CELL_INDEX]), rtt_params_size); + } + + ret = apps_monitor_netlink_send_to_user(APPS_MONITOR_REPORT_APPS_CELL_RTT, (char *) send_msg, + (rtt_params_size + int_size) * g_monitor_apps_num); + break; + case ALL_IF_INDEX: + for(index = 0; index < g_monitor_apps_num; ++index) { + step = rtt_params_size * IFACE_NUM_MAX * index + index * int_size; + memcpy(send_msg + step, &g_monitor_apps_table[index].app_uid, int_size); + memcpy(send_msg + step + int_size, &(g_monitor_apps_table[index].app_rtt), rtt_params_size * IFACE_NUM_MAX); + } + + ret = apps_monitor_netlink_send_to_user(APPS_MONITOR_REPORT_APPS_ALL_RTT, (char *) send_msg, + (rtt_params_size + int_size) * IFACE_NUM_MAX * g_monitor_apps_num); + break; + default: + printk("oplus_apps_monitor: apps_monitor_report_apps_rtt_to_user, the if_index is unvalue! \n"); + return -EINVAL; + } + + if (ret == 0) { + if (apps_monitor_debug) { + print_apps_rtt_record(); + } + //report success,clear the rtt record in kernel + clear_apps_rtt_record(if_index); + } else { + printk("oplus_apps_monitor: apps_monitor_netlink_send_rtt_to_user fail! \n"); + } + + return ret; +} + +static int apps_monitor_report_dev_rtt_to_user(void) +{ +#define MAX_DEV_RTT_MSG_LEN (256) + int ret = 0; + int index = 0; + int step = 0; + int rtt_params_size = sizeof(rtt_params); + static char send_msg[MAX_DEV_RTT_MSG_LEN] = {0}; + + memset(send_msg, 0, MAX_DEV_RTT_MSG_LEN); + + if (rtt_params_size * IFACE_NUM_MAX > MAX_DEV_RTT_MSG_LEN) { + printk("oplus_apps_monitor: apps_monitor_report_dev_rtt_to_user, the RTT Msg is too big, len = %0x \n", + rtt_params_size * IFACE_NUM_MAX); + return -EINVAL; + } + + for(index = 0; index < IFACE_NUM_MAX; ++index) { + step = rtt_params_size * index; + memcpy(send_msg + step, &g_monitor_dev_table[index], rtt_params_size); + } + + ret = apps_monitor_netlink_send_to_user(APPS_MONITOR_REPORT_DEV_RTT, (char *) send_msg, + rtt_params_size * IFACE_NUM_MAX); + + if (ret == 0) { + if (apps_monitor_debug) { + print_dev_rtt_record(); + } + //report success,clear the rtt record in kernel + clear_dev_rtt_record(); + } else { + printk("oplus_apps_monitor: apps_monitor_report_dev_rtt_to_user fail! \n"); + } + + return ret; +} + +static int apps_monitor_netlink_nlmsg_handle(struct sk_buff *skb, struct nlmsghdr *nlh, struct netlink_ext_ack *extack) +{ + int ret = 0; + + if (apps_monitor_debug) { + printk("oplus_apps_monitor: apps_monitor_netlink_recv_handle, the nlh->nlmsg_type = %0x \n", nlh->nlmsg_type); + } + + switch (nlh->nlmsg_type) { + case APPS_MONITOR_SET_ANDROID_PID: + ret = apps_monitor_set_android_pid(skb); + break; + case APPS_MONITOR_SET_APPS_UID: + ret = apps_monitor_set_apps_uid(nlh); + break; + case APPS_MONITOR_GET_APPS_CELL_RTT: + ret = apps_monitor_report_apps_rtt_to_user(CELL_INDEX); + break; + case APPS_MONITOR_GET_APPS_WLAN_RTT: + ret = apps_monitor_report_apps_rtt_to_user(WLAN_INDEX); + break; + case APPS_MONITOR_GET_APPS_ALL_RTT: + ret = apps_monitor_report_apps_rtt_to_user(ALL_IF_INDEX); + break; + case APPS_MOINTOR_SET_RTT_THRED: + ret = apps_monitor_set_rtt_thred(nlh); + break; + case APPS_MONITOR_GET_DEV_RTT: + ret = apps_monitor_report_dev_rtt_to_user(); + break; + case APPS_POWER_MONITOR_MSG_DL_CTRL: + printk("[app_monitor]:rececice APPS_POWER_MONITOR_MSG_DL_CTRL\n"); + ret = app_monitor_dl_ctl_msg_handle(nlh); + break; + case APPS_POWER_MONITOR_MSG_DL_RPT_CTRL: + printk("[app_monitor]:rececice APPS_POWER_MONITOR_MSG_DL_RPT_CTRL\n"); + ret = app_monitor_dl_report_msg_handle(nlh); + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + +static void apps_monitor_netlink_recv(struct sk_buff *skb) +{ + mutex_lock(&apps_monitor_netlink_mutex); + netlink_rcv_skb(skb, &apps_monitor_netlink_nlmsg_handle); + mutex_unlock(&apps_monitor_netlink_mutex); +} + +static int apps_monitor_netlink_init(void) +{ + struct netlink_kernel_cfg cfg = { + .input = apps_monitor_netlink_recv, + }; + + apps_monitor_netlink_sock = netlink_kernel_create(&init_net, NETLINK_OPLUS_APPS_MONITOR, &cfg); + + return apps_monitor_netlink_sock == NULL ? -ENOMEM : 0; +} + +static void apps_monitor_netlink_exit(void) +{ + netlink_kernel_release(apps_monitor_netlink_sock); + apps_monitor_netlink_sock = NULL; +} + +static void apps_monitor_timer_function(void) { + if (rrt_period_report_enable && apps_monitor_netlink_pid != 0) { + apps_monitor_report_apps_rtt_to_user(ALL_IF_INDEX); + apps_monitor_report_dev_rtt_to_user(); + } + + mod_timer(&apps_monitor_timer, jiffies + rrt_period_report_timer * TIMER_EXPIRES); +} + +static int is_need_period_timer(void) { + return rrt_period_report_enable; //For more period funs, {return xx_period_enable | xx_period_enable} +} + +static void apps_monitor_timer_init(void) +{ + timer_setup(&apps_monitor_timer, (void*)apps_monitor_timer_function, 0); + apps_monitor_timer.expires = jiffies + rrt_period_report_timer * TIMER_EXPIRES; + add_timer(&apps_monitor_timer); +} + +static void apps_monitor_timer_del(void) +{ + del_timer(&apps_monitor_timer); +} + +static int __init oplus_apps_monitor_init(void) +{ + int ret = 0; + + rwlock_init(&apps_monitor_lock); + set_monitor_apps_param_default(); + ret = apps_monitor_netlink_init(); + + if (ret < 0) { + printk("oplus_apps_monitor: oplus_apps_monitor_init module failed to init netlink.\n"); + } else { + printk("oplus_apps_monitor: oplus_apps_monitor_init module init netlink successfully.\n"); + } + + ret |= apps_monitor_sysctl_init(); + + if (is_need_period_timer()) { + apps_monitor_timer_init(); + } + + oplus_app_power_monitor_init(); + return ret; +} + +static void __exit oplus_apps_monitor_fini(void) +{ + clear_apps_rtt_record(ALL_IF_INDEX); + clear_dev_rtt_record(); + apps_monitor_netlink_exit(); + + if (is_need_period_timer()) { + apps_monitor_timer_del(); + } + + if(apps_monitor_table_hrd){ + unregister_net_sysctl_table(apps_monitor_table_hrd); + } + + oplus_app_power_monitor_fini(); +} + +module_init(oplus_apps_monitor_init); +module_exit(oplus_apps_monitor_fini); diff --git a/net/oplus_apps_monitor/oplus_apps_power_monitor.c b/net/oplus_apps_monitor/oplus_apps_power_monitor.c new file mode 100644 index 000000000000..ab4597eef5fc --- /dev/null +++ b/net/oplus_apps_monitor/oplus_apps_power_monitor.c @@ -0,0 +1,1190 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* +* Copyright (C) 2018-2020 Oplus. All rights reserved. +*/ + +#include +#include +#include +#include + +#define TOP_APP_NUM 5 +#define APP_MONITOR_HASHTABLE_SIZE 64 +#define APP_MONITOR_HASH_MASK (APP_MONITOR_HASHTABLE_SIZE - 1) +#define INVALID_APP_INDEX 0xff +#define ALARM_TYPE_BEAT 0x01 +#define ALARM_TYPE_PUSH 0x02 +#define ALARM_TYPE_TRAFFIC 0x04 +#define PERIOD_CHECK_TIME 10 //unit second +#define ALARM_DETECT_PERIOD 600 //unit second +#define ALARM_DETECT_COUNT 10 +#define REPORT_INTERVAL 1800 //unit second +#define REPORT_PERIOD 5 + +enum +{ + APPS_POWER_MONITOR_MSG_DL_CTRL = 0x30, + APPS_POWER_MONITOR_MSG_DL_RPT_CTRL, + APPS_POWER_MONITOR_MSG_UL_INFO, + APPS_POWER_MONITOR_MSG_UL_BEAT_ALARM, + APPS_POWER_MONITOR_MSG_UL_PUSH_ALARM, + APPS_POWER_MONITOR_MSG_UL_TRAFFIC_ALARM, +}; + +#define IPV4ADDRTOSTR(addr) \ +((unsigned char *)&addr)[0], \ +((unsigned char *)&addr)[1], \ +((unsigned char *)&addr)[2], \ +((unsigned char *)&addr)[3] + +#pragma pack(4) +struct app_monitor_beat_msg_st +{ + u32 uid_val; + u32 beat_period; + u32 beat_count; +}; + +struct app_monitor_push_msg_st +{ + u32 uid_val; + u32 push_period; + u32 push_count; +}; + +struct app_monitor_traffic_msg_st +{ + u32 uid_val; + u64 total_packets; + u64 total_bytes; + u64 send_packets; + u64 send_bytes; + u64 recv_packets; + u64 recv_bytes; +}; + +struct app_monitor_retrans_msg_st +{ + u32 uid_val; + u64 app_retrans_total_packets; + u64 app_retrans_syn_packets; +}; + +struct app_monitor_dl_ctl_msg_st +{ + u32 msg_len; + u32 start_flag; +}; + +struct app_monitor_dl_req_report_msg_st +{ + u32 msg_len; + u32 request_report_flag; +}; + +struct app_monitor_ul_report_msg_st +{ + u32 msg_len; + u32 beat_app_count; + u32 push_app_count; + u32 traffic_app_count; + u32 retrans_app_count; //for retrams static + u64 sys_total_packets; + u64 sys_total_bytes; + u64 sys_send_packets; + u64 sys_send_bytes; + u64 sys_recv_packets; + u64 sys_recv_bytes; + u64 sys_retrans_total_packets; + u64 sys_retrans_syn_packets; + struct app_monitor_beat_msg_st app_beat_info[TOP_APP_NUM]; + struct app_monitor_push_msg_st app_push_info[TOP_APP_NUM]; + struct app_monitor_traffic_msg_st app_traffic_info[TOP_APP_NUM]; + struct app_monitor_retrans_msg_st app_retrans_info[TOP_APP_NUM]; //for retrans static +}; + +struct app_monitor_ul_beat_alarm_msg_st +{ + u32 msg_len; + u32 uid_val; + u32 beat_period; //unit second +}; + +struct app_monitor_ul_push_alarm_msg_st +{ + u32 msg_len; + u32 uid_val; + u32 push_period; //unit second +}; + +struct app_monitor_ul_traffic_alarm_msg_st +{ + u32 msg_len; + u32 uid_val; + u64 total_packets; + u64 total_bytes; + u64 send_packets; + u64 send_bytes; + u64 recv_packets; + u64 recv_bytes; + u32 traffic_period; //default 10 * 60 seconds; +}; +#pragma pack() + +struct app_monitor_app_info_st +{ + u32 uid_val; + u64 total_packets; + u64 total_bytes; + u64 send_packets; + u64 send_bytes; + u64 recv_packets; + u64 recv_bytes; + u64 retrans_total_packets; + u64 retrans_syn_packets; + u32 last_send_time; + u32 beat_period; + u32 beat_count; + u32 last_active_time; + u32 push_period; + u32 push_count; + u32 beat_alarm_start_time; + u32 push_alarm_start_time; +}; + +struct app_monitor_top_app_beat_info_st +{ + u32 real_app_num; + u32 max_index; + u32 read_flag[TOP_APP_NUM]; + struct app_monitor_app_info_st app_beat_info[TOP_APP_NUM]; +}; + +struct app_monitor_top_app_push_info_st +{ + u32 real_app_num; + u32 max_index; + u32 read_flag[TOP_APP_NUM]; + struct app_monitor_app_info_st app_push_info[TOP_APP_NUM]; +}; + +struct app_monitor_top_app_trafffic_info_st +{ + u32 real_app_num; + u32 min_index; + u32 read_flag[TOP_APP_NUM]; + struct app_monitor_app_info_st app_traffic_info[TOP_APP_NUM]; +}; + +struct app_monitor_top_app_retrans_info_st +{ + u32 real_app_num; + u32 min_index; + u32 read_flag[TOP_APP_NUM]; + struct app_monitor_app_info_st app_retrans_info[TOP_APP_NUM]; +}; + +struct app_monitor_app_info_list_node_st +{ + struct app_monitor_app_info_st app_info; + struct list_head list_node; +}; + +struct app_monitor_list_st +{ + u32 m_count; + struct list_head m_listhead; +}; + +struct sys_stati_info_st +{ + u64 sys_total_packets; + u64 sys_total_bytes; + u64 sys_send_packets; + u64 sys_send_bytes; + u64 sys_recv_packets; + u64 sys_recv_bytes; + u64 sys_retrans_total_packets; + u64 sys_retrans_syn_packets; +}; + +struct app_monitor_top_app_trafffic_info_st top_app_traffic_info; +struct app_monitor_top_app_beat_info_st top_app_beat_info; +struct app_monitor_top_app_push_info_st top_app_push_info; +struct app_monitor_top_app_retrans_info_st top_app_retrans_info; +struct sys_stati_info_st sys_stati_info; +struct app_monitor_list_st app_monitor_list[APP_MONITOR_HASHTABLE_SIZE]; +static rwlock_t app_power_monitor_lock; +static int app_monitor_enable = 0; +static int app_monitor_start = 0; +static int app_report_request = 0; +static int app_beat_alarm_period = 0; +static int app_push_alarm_period = 0; +static struct timer_list apps_monitor_report_timer; +static struct ctl_table_header *app_power_monitor_table_hrd; +static struct timeval last_report_tv; + +//added for test +static void print_report_info(struct app_monitor_ul_report_msg_st *report_msg){ + int i = 0; + + printk("[app_monitor]: report_info:beat_app_count=%u, push_app_count=%u, traffic_app_count=%u, retrans_app_count=%u\n", + report_msg->beat_app_count, report_msg->push_app_count, report_msg->traffic_app_count, report_msg->retrans_app_count); + printk("[app_monitor]:sys_total_packet=%llu,sys_send_packet=%llu,sys_recv_packet=%llu,sys_retrans_total_packet=%llu, sys_retrans_syn_packet=%llu\n", + report_msg->sys_total_packets, report_msg->sys_send_packets, report_msg->sys_recv_packets, + report_msg->sys_retrans_total_packets, report_msg->sys_retrans_syn_packets); + printk("[app_monitor]:sys_total_byte=%llu,sys_send_byte=%llu,sys_recv_byte=%llu\n", + report_msg->sys_total_bytes, report_msg->sys_send_bytes, report_msg->sys_recv_bytes); + for(i = 0; i < report_msg->beat_app_count; i++){ + printk("[app_monitor]:report_info:beat:i=%d,uid=%u,period=%u,count=%u\n", + i, report_msg->app_beat_info[i].uid_val, + report_msg->app_beat_info[i].beat_period, + report_msg->app_beat_info[i].beat_count); + } + + for(i = 0; i < report_msg->push_app_count; i++){ + printk("[app_monitor]:report_info:push:i=%d,uid=%u,period=%u,count=%u\n", + i, report_msg->app_push_info[i].uid_val, + report_msg->app_push_info[i].push_period, + report_msg->app_push_info[i].push_count); + } + + for(i = 0; i < report_msg->traffic_app_count; i++){ + printk("[app_monitor]:report_info:traffic:i=%d,uid=%u,t_bytes=%llu,t_packet=%llu,s_byte=%llu,s_packet=%llu,r_byte=%llu,r_packet=%llu\n", + i, report_msg->app_traffic_info[i].uid_val, + report_msg->app_traffic_info[i].total_bytes, + report_msg->app_traffic_info[i].total_packets, + report_msg->app_traffic_info[i].send_bytes, + report_msg->app_traffic_info[i].send_packets, + report_msg->app_traffic_info[i].recv_bytes, + report_msg->app_traffic_info[i].recv_packets); + } + + for(i = 0; i < report_msg->retrans_app_count; i++){ + printk("[app_monitor]:report_info:retrans:i=%d,uid=%u,total_retrans=%llu, syn_retrans=%llu\n", + i, report_msg->app_retrans_info[i].uid_val, + report_msg->app_retrans_info[i].app_retrans_total_packets, + report_msg->app_retrans_info[i].app_retrans_syn_packets); + } +} + +void oplus_app_monitor_fill_beat_app_info(struct app_monitor_ul_report_msg_st *report_msg) +{ + int i, j, k; + int app_num = top_app_beat_info.real_app_num; + int max_count = 0; + + for(i = 0; i < TOP_APP_NUM; i++){ + top_app_beat_info.read_flag[i] = 0; + } + + for(i = 0; i < app_num; i++){ + max_count = 0; + k = TOP_APP_NUM; + for(j = 0; j < TOP_APP_NUM; j++){ + if(top_app_beat_info.read_flag[j] || top_app_beat_info.app_beat_info[j].beat_period == 0) + continue; + + if(!max_count || max_count < top_app_beat_info.app_beat_info[j].beat_count){ + max_count = top_app_beat_info.app_beat_info[j].beat_count; + k = j; + } + } + + if(k < TOP_APP_NUM){ + report_msg->app_beat_info[i].uid_val = top_app_beat_info.app_beat_info[k].uid_val; + report_msg->app_beat_info[i].beat_period = top_app_beat_info.app_beat_info[k].beat_period; + report_msg->app_beat_info[i].beat_count= top_app_beat_info.app_beat_info[k].beat_count; + top_app_beat_info.read_flag[k] = 1; + } + } +} + +void oplus_app_monitor_fill_push_app_info(struct app_monitor_ul_report_msg_st *report_msg) +{ + int i, j, k; + int app_num = top_app_push_info.real_app_num; + int max_count = 0; + + for(i = 0; i < TOP_APP_NUM; i++){ + top_app_push_info.read_flag[i] = 0; + } + + for(i = 0; i < app_num; i++){ + max_count = 0; + k = TOP_APP_NUM; + for(j = 0; j < TOP_APP_NUM; j++){ + if(top_app_push_info.read_flag[j] || top_app_push_info.app_push_info[j].push_period == 0) + continue; + + if(!max_count || max_count < top_app_push_info.app_push_info[j].push_count){ + max_count = top_app_push_info.app_push_info[j].push_count; + k = j; + } + } + + if(k < TOP_APP_NUM){ + report_msg->app_push_info[i].uid_val = top_app_push_info.app_push_info[k].uid_val; + report_msg->app_push_info[i].push_period = top_app_push_info.app_push_info[k].push_period; + report_msg->app_push_info[i].push_count= top_app_push_info.app_push_info[k].push_count; + top_app_push_info.read_flag[k] = 1; + } + } +} + +void oplus_app_monitor_fill_traffic_app_info(struct app_monitor_ul_report_msg_st *report_msg) +{ + int i, j, k; + int app_num = top_app_traffic_info.real_app_num; + int max_traffic = 0; + + for(i = 0; i < TOP_APP_NUM; i++){ + top_app_traffic_info.read_flag[i] = 0; + } + + for(i = 0; i < app_num; i++){ + max_traffic = 0; + k = TOP_APP_NUM; + for(j = 0; j < TOP_APP_NUM; j++){ + if(top_app_traffic_info.read_flag[j] || top_app_traffic_info.app_traffic_info[j].total_bytes == 0) + continue; + + if(!max_traffic || max_traffic < top_app_traffic_info.app_traffic_info[j].total_bytes){ + max_traffic = top_app_traffic_info.app_traffic_info[j].total_bytes; + k = j; + } + } + + if(k < TOP_APP_NUM){ + report_msg->app_traffic_info[i].uid_val = top_app_traffic_info.app_traffic_info[k].uid_val; + report_msg->app_traffic_info[i].total_bytes = top_app_traffic_info.app_traffic_info[k].total_bytes; + report_msg->app_traffic_info[i].total_packets= top_app_traffic_info.app_traffic_info[k].total_packets; + report_msg->app_traffic_info[i].send_bytes = top_app_traffic_info.app_traffic_info[k].send_bytes; + report_msg->app_traffic_info[i].send_packets= top_app_traffic_info.app_traffic_info[k].send_packets; + report_msg->app_traffic_info[i].recv_bytes = top_app_traffic_info.app_traffic_info[k].recv_bytes; + report_msg->app_traffic_info[i].recv_packets= top_app_traffic_info.app_traffic_info[k].recv_packets; + top_app_traffic_info.read_flag[k] = 1; + } + } +} + +void oplus_app_monitor_fill_retrans_app_info(struct app_monitor_ul_report_msg_st *report_msg) +{ + int i, j, k; + int app_num = top_app_retrans_info.real_app_num; + int max_retrans = 0; + + for(i = 0; i < TOP_APP_NUM; i++){ + top_app_retrans_info.read_flag[i] = 0; + } + + for(i = 0; i < app_num; i++){ + max_retrans = 0; + k = TOP_APP_NUM; + for(j = 0; j < TOP_APP_NUM; j++){ + if(top_app_retrans_info.read_flag[j] || top_app_retrans_info.app_retrans_info[j].retrans_total_packets == 0) + continue; + + if(!max_retrans || max_retrans < top_app_retrans_info.app_retrans_info[j].retrans_total_packets){ + max_retrans = top_app_retrans_info.app_retrans_info[j].retrans_total_packets; + k = j; + } + } + + if(k < TOP_APP_NUM){ + report_msg->app_retrans_info[i].uid_val = top_app_retrans_info.app_retrans_info[k].uid_val; + report_msg->app_retrans_info[i].app_retrans_total_packets = top_app_retrans_info.app_retrans_info[k].retrans_total_packets; + report_msg->app_retrans_info[i].app_retrans_syn_packets= top_app_retrans_info.app_retrans_info[k].retrans_syn_packets; + top_app_retrans_info.read_flag[k] = 1; + } + } +} + + +extern int apps_monitor_netlink_send_to_user(int msg_type, char *payload, int payload_len); +void oplus_app_monitor_send_app_info_report(void) +{ + int ret; + char msg_buf[1024] = {0}; + struct app_monitor_ul_report_msg_st *report_msg = (struct app_monitor_ul_report_msg_st*)msg_buf; + struct timeval now_tv; + unsigned long flags; + + do_gettimeofday(&now_tv); + if(!app_monitor_start || before((u32)now_tv.tv_sec , (u32)(REPORT_INTERVAL + last_report_tv.tv_sec))){ + /*printk("[app_monitor]:oplus_app_monitor_send_app_info_report,now_tv=%lld,last_tv=%lld\n", + (long long)now_tv.tv_sec, (long long)last_report_tv.tv_sec);*/ + return; + } + + write_lock_irqsave(&app_power_monitor_lock, flags); + report_msg->msg_len = sizeof(struct app_monitor_ul_report_msg_st); + report_msg->sys_total_packets = sys_stati_info.sys_total_packets; + report_msg->sys_total_bytes = sys_stati_info.sys_total_bytes; + report_msg->sys_send_packets = sys_stati_info.sys_send_packets; + report_msg->sys_send_bytes = sys_stati_info.sys_send_bytes; + report_msg->sys_recv_packets = sys_stati_info.sys_recv_packets; + report_msg->sys_recv_bytes = sys_stati_info.sys_recv_bytes; + report_msg->sys_retrans_total_packets = sys_stati_info.sys_retrans_total_packets; + report_msg->sys_retrans_syn_packets = sys_stati_info.sys_retrans_syn_packets; + report_msg->beat_app_count = top_app_beat_info.real_app_num; + report_msg->push_app_count = top_app_push_info.real_app_num; + report_msg->traffic_app_count = top_app_traffic_info.real_app_num; + report_msg->retrans_app_count = top_app_retrans_info.real_app_num; + oplus_app_monitor_fill_push_app_info(report_msg); + oplus_app_monitor_fill_beat_app_info(report_msg); + oplus_app_monitor_fill_traffic_app_info(report_msg); + oplus_app_monitor_fill_retrans_app_info(report_msg); + write_unlock_irqrestore(&app_power_monitor_lock, flags); + + ret = apps_monitor_netlink_send_to_user(APPS_POWER_MONITOR_MSG_UL_INFO, (char *) msg_buf, report_msg->msg_len ); + if(ret){ + printk("[app_monitor]:send app info report error!\n"); + } + else{ + printk("[app_monitor]:send app info report success!now=%lld, now_jiffies=%u\n", (long long)now_tv.tv_sec, tcp_time_stamp); + print_report_info(report_msg); + } + + do_gettimeofday(&last_report_tv); + return; +} + +static void apps_monitor_report_timer_function(void){ + oplus_app_monitor_send_app_info_report(); + mod_timer(&apps_monitor_report_timer, jiffies + REPORT_PERIOD * HZ); +} + +static void report_timer_init(void) +{ + printk("[app_monitor]:report_timer_init\n"); + timer_setup(&apps_monitor_report_timer, (void*)apps_monitor_report_timer_function, 0); +} +static void report_timer_start(void){ + printk("[app_monitor]:report_timer_start\n"); + apps_monitor_report_timer.function = (void*)apps_monitor_report_timer_function; + apps_monitor_report_timer.expires = jiffies + REPORT_PERIOD * HZ; + //add_timer(&apps_monitor_report_timer); + mod_timer(&apps_monitor_report_timer, apps_monitor_report_timer.expires); +} + +static void report_timer_restart(void) +{ + apps_monitor_report_timer.function = (void*)apps_monitor_report_timer_function; + mod_timer(&apps_monitor_report_timer, jiffies + REPORT_PERIOD * HZ); +} + +static void report_timer_del(void) +{ + printk("[app_monitor]:report_timer_del\n"); + del_timer_sync(&apps_monitor_report_timer); +} + +static void oplus_app_monitor_start(void) +{ + int i; + struct list_head *head; + struct list_head *this_node; + struct list_head *next_node; + struct app_monitor_app_info_list_node_st *app_node_info; + unsigned long flags; + + read_lock(&app_power_monitor_lock); + if(app_monitor_enable == 1){ + read_unlock(&app_power_monitor_lock); + return; + } + else{ + read_unlock(&app_power_monitor_lock); + write_lock_irqsave(&app_power_monitor_lock, flags); + for(i = 0; i < APP_MONITOR_HASHTABLE_SIZE; i++){ + head = &(app_monitor_list[i].m_listhead); + this_node = head->next; + while(this_node != head){ + next_node = this_node->next; + list_del(this_node); + app_node_info = list_entry(this_node, struct app_monitor_app_info_list_node_st, list_node); + kfree(app_node_info); + this_node = next_node; + } + + app_monitor_list[i].m_count = 0; + } + + app_monitor_enable = 1; + do_gettimeofday(&last_report_tv); + app_monitor_start = 1; + write_unlock_irqrestore(&app_power_monitor_lock, flags); + } + + printk("[app_monitor]:monitor start\n"); + report_timer_start(); +} + +static void oplus_app_monitor_stop(void) +{ + unsigned long flags; + int i; + struct list_head *head; + struct list_head *this_node; + struct list_head *next_node; + struct app_monitor_app_info_list_node_st *app_node_info; + + write_lock_irqsave(&app_power_monitor_lock, flags); + app_monitor_enable = 0; + app_monitor_start = 0; + for(i = 0; i < APP_MONITOR_HASHTABLE_SIZE; i++){ + head = &(app_monitor_list[i].m_listhead); + this_node = head->next; + while(this_node != head){ + next_node = this_node->next; + list_del(this_node); + app_node_info = list_entry(this_node, struct app_monitor_app_info_list_node_st, list_node); + kfree(app_node_info); + this_node = next_node; + } + + app_monitor_list[i].m_count = 0; + } + write_unlock_irqrestore(&app_power_monitor_lock, flags); + printk("[app_monitor]:monitor end\n"); + report_timer_del(); + return; +} + +static inline u32 oplus_app_monitor_find_app_traffic_index(u32 uid_val) +{ + u32 index; + u32 app_num = top_app_traffic_info.real_app_num; + + for(index = 0; index < app_num; index++){ + if(uid_val == top_app_traffic_info.app_traffic_info[index].uid_val){ + return index; + } + } + + return INVALID_APP_INDEX; +} + +static inline u32 oplus_app_monitor_find_app_retrans_index(u32 uid_val) +{ + u32 index; + u32 app_num = top_app_retrans_info.real_app_num; + + for(index = 0; index < app_num; index++){ + if(uid_val == top_app_retrans_info.app_retrans_info[index].uid_val){ + return index; + } + } + + return INVALID_APP_INDEX; +} + +static inline u32 oplus_app_monitor_find_app_beat_index(u32 uid_val) +{ + u32 index; + u32 app_num = top_app_beat_info.real_app_num; + + for(index = 0; index < app_num; index++){ + if(uid_val == top_app_beat_info.app_beat_info[index].uid_val){ + return index; + } + } + + return INVALID_APP_INDEX; +} + +static inline u32 oplus_app_monitor_find_app_push_index(u32 uid_val) +{ + u32 index; + u32 app_num = top_app_push_info.real_app_num; + + for(index = 0; index < app_num; index++){ + if(uid_val == top_app_push_info.app_push_info[index].uid_val){ + return index; + } + } + + return INVALID_APP_INDEX; +} + +void oplus_app_monitor_update_top_trafffic_app(struct app_monitor_app_info_st *app_info) +{ + u32 min_index = top_app_traffic_info.min_index; + u32 app_index; + u32 app_uid = app_info->uid_val; + u32 i; + + app_index = oplus_app_monitor_find_app_traffic_index(app_uid); + //app record exsit, just update it + if(app_index < TOP_APP_NUM){ + top_app_traffic_info.app_traffic_info[app_index] = *app_info; + return; + } + + //record app traffic info is small than TOP_APP_NUM,just record it + if(top_app_traffic_info.real_app_num < TOP_APP_NUM){ + top_app_traffic_info.app_traffic_info[top_app_traffic_info.real_app_num] = *app_info; + top_app_traffic_info.real_app_num++; + return; + } + + //compare with the min record + if(app_info->total_bytes > top_app_traffic_info.app_traffic_info[min_index].total_bytes){ + top_app_traffic_info.app_traffic_info[min_index] = *app_info; + } + else{ + return; + } + + for(i = 0; i < TOP_APP_NUM; i++){ + if(i == 0){ + min_index = i; + } + else if(top_app_traffic_info.app_traffic_info[min_index].total_bytes > top_app_traffic_info.app_traffic_info[i].total_bytes){ + min_index = i; + } + } + + top_app_traffic_info.min_index = min_index; + return; +} + + +void oplus_app_monitor_update_top_retrans_app(struct app_monitor_app_info_st *app_info) +{ + u32 min_index = top_app_retrans_info.min_index; + u32 app_index; + u32 app_uid = app_info->uid_val; + u32 i; + + app_index = oplus_app_monitor_find_app_retrans_index(app_uid); + //app record exsit, just update it + if(app_index < TOP_APP_NUM){ + top_app_retrans_info.app_retrans_info[app_index] = *app_info; + return; + } + + //record app traffic info is small than TOP_APP_NUM,just record it + if(top_app_retrans_info.real_app_num < TOP_APP_NUM){ + top_app_retrans_info.app_retrans_info[top_app_retrans_info.real_app_num] = *app_info; + top_app_retrans_info.real_app_num++; + return; + } + + //compare with the min record + if(app_info->retrans_total_packets > top_app_retrans_info.app_retrans_info[min_index].retrans_total_packets){ + top_app_retrans_info.app_retrans_info[min_index] = *app_info; + } + else{ + return; + } + + for(i = 0; i < TOP_APP_NUM; i++){ + if(i == 0){ + min_index = i; + } + else if(top_app_retrans_info.app_retrans_info[min_index].retrans_total_packets > top_app_retrans_info.app_retrans_info[i].retrans_total_packets){ + min_index = i; + } + } + + top_app_retrans_info.min_index = min_index; + return; +} + + +void oplus_app_monitor_update_top_beat_app(struct app_monitor_app_info_st *app_info) +{ + u32 max_index = top_app_beat_info.max_index; + u32 app_index; + u32 app_uid = app_info->uid_val; + u32 i; + + app_index = oplus_app_monitor_find_app_beat_index(app_uid); + //app record exsit, just update it + if(app_index < TOP_APP_NUM){ + top_app_beat_info.app_beat_info[app_index] = *app_info; + return; + } + + //record app traffic info is small than TOP_APP_NUM,just record it + if(top_app_beat_info.real_app_num < TOP_APP_NUM){ + top_app_beat_info.app_beat_info[top_app_beat_info.real_app_num] = *app_info; + top_app_beat_info.real_app_num++; + return; + } + + //compare with the min record + if(app_info->beat_count > top_app_beat_info.app_beat_info[max_index].beat_count){ + top_app_beat_info.app_beat_info[max_index] = *app_info; + } + else{ + return; + } + + for(i = 0; i < TOP_APP_NUM; i++){ + if(i == 0){ + max_index = i; + } + else if(top_app_beat_info.app_beat_info[max_index].beat_count > top_app_beat_info.app_beat_info[i].beat_count){ + max_index = i; + } + } + + top_app_beat_info.max_index = max_index; + return; + +} + +static void oplus_app_monitor_update_top_push_app(struct app_monitor_app_info_st *app_info) +{ + u32 max_index = top_app_push_info.max_index; + u32 app_index; + u32 app_uid = app_info->uid_val; + u32 i; + + app_index = oplus_app_monitor_find_app_push_index(app_uid); + //app record exsit, just update it + if(app_index < TOP_APP_NUM){ + top_app_push_info.app_push_info[app_index] = *app_info; + return; + } + + //record app traffic info is small than TOP_APP_NUM,just record it + if(top_app_push_info.real_app_num < TOP_APP_NUM){ + top_app_push_info.app_push_info[top_app_push_info.real_app_num] = *app_info; + top_app_push_info.real_app_num++; + return; + } + + //compare with the min record + if(app_info->push_count > top_app_push_info.app_push_info[max_index].push_count){ + top_app_push_info.app_push_info[max_index] = *app_info; + } + else{ + return; + } + + for(i = 0; i < TOP_APP_NUM; i++){ + if(i == 0){ + max_index = i; + } + else if(top_app_push_info.app_push_info[max_index].push_count > top_app_push_info.app_push_info[i].push_count){ + max_index = i; + } + } + + top_app_push_info.max_index = max_index; + return; +} + +static struct app_monitor_app_info_list_node_st* oplus_app_monitor_get_app_info_by_uid(u32 uid) +{ + struct app_monitor_app_info_list_node_st *app_info_node = NULL; + u32 hash_index = uid & APP_MONITOR_HASH_MASK; + + //list_for_each_entry(app_info_node, &app_moniter_list_head[hash_index], list_node){ + list_for_each_entry(app_info_node, &app_monitor_list[hash_index].m_listhead, list_node){ + if(app_info_node->app_info.uid_val == uid){ + return app_info_node; + } + } + + app_info_node = kzalloc(sizeof(struct app_monitor_app_info_list_node_st), GFP_ATOMIC); + if(!app_info_node){ + return NULL; + } + else + { + app_info_node->app_info.uid_val = uid; + list_add(&app_info_node->list_node, &app_monitor_list[hash_index].m_listhead); + } + + return app_info_node; +} + +void oplus_app_monitor_update_flow_stat(struct app_monitor_app_info_list_node_st *app_info_node, + const struct sk_buff *skb, int send) +{ + if(send){ + app_info_node->app_info.send_packets++; + app_info_node->app_info.send_bytes += skb->len; + } + else{ + app_info_node->app_info.recv_packets++; + app_info_node->app_info.recv_bytes += skb->len; + } + + app_info_node->app_info.total_packets++; + app_info_node->app_info.total_bytes += skb->len; + return; +} + +void oplus_app_monitor_update_retrans_stat(struct app_monitor_app_info_list_node_st *app_info_node, + const struct sk_buff *skb) +{ + app_info_node->app_info.retrans_total_packets++; + if((TCP_SKB_CB(skb)->tcp_flags) & TCPHDR_SYN){ + app_info_node->app_info.retrans_syn_packets++; + } + + return; +} + + +void oplus_app_monitor_send_beat_alarm(u32 uid_val, u32 period) +{ + int ret; + char msg_buf[1024] = {0}; + struct app_monitor_ul_beat_alarm_msg_st *beat_alarm_msg = (struct app_monitor_ul_beat_alarm_msg_st *)msg_buf; + + beat_alarm_msg->uid_val = uid_val; + beat_alarm_msg->beat_period = period; + beat_alarm_msg->msg_len = sizeof(struct app_monitor_ul_beat_alarm_msg_st); + ret = apps_monitor_netlink_send_to_user(APPS_POWER_MONITOR_MSG_UL_BEAT_ALARM, (char *) msg_buf, + beat_alarm_msg->msg_len ); + if(ret){ + printk("[app_monitor]:send beat alarm info error!\n "); + } + + return; +} + +void oplus_app_monitor_send_push_alarm(u32 uid_val, u32 period) +{ + int ret; + char msg_buf[1024] = {0}; + struct app_monitor_ul_push_alarm_msg_st *push_alarm_msg = (struct app_monitor_ul_push_alarm_msg_st *)msg_buf; + + push_alarm_msg->uid_val = uid_val; + push_alarm_msg->push_period= period; + push_alarm_msg->msg_len = sizeof(struct app_monitor_ul_push_alarm_msg_st); + ret = apps_monitor_netlink_send_to_user(APPS_POWER_MONITOR_MSG_UL_PUSH_ALARM, (char *) msg_buf, push_alarm_msg->msg_len ); + if(ret){ + printk("[app_monitor]:send push alarm info error!\n "); + } + + return; +} + +void oplus_app_monitor_send_traffic_alarm(struct app_monitor_app_info_st *app_info) +{ + int ret; + char msg_buf[1024] = {0}; + struct app_monitor_ul_traffic_alarm_msg_st *traffic_alarm_msg = (struct app_monitor_ul_traffic_alarm_msg_st *)msg_buf; + + traffic_alarm_msg->uid_val = app_info->uid_val; + traffic_alarm_msg->msg_len = sizeof(struct app_monitor_ul_traffic_alarm_msg_st); + traffic_alarm_msg->total_bytes = app_info->total_bytes; + traffic_alarm_msg->total_packets = app_info->total_packets; + traffic_alarm_msg->recv_bytes = app_info->recv_bytes; + traffic_alarm_msg->recv_packets = app_info->recv_packets; + traffic_alarm_msg->send_bytes = app_info->send_bytes; + traffic_alarm_msg->send_packets = app_info->send_packets; + traffic_alarm_msg->traffic_period = ALARM_DETECT_PERIOD; + ret = apps_monitor_netlink_send_to_user(APPS_POWER_MONITOR_MSG_UL_TRAFFIC_ALARM,(char *) msg_buf,traffic_alarm_msg->msg_len); + if(ret){ + printk("[app_monitor]:send traffic alarm info error!\n "); + } + + return; +} + +void oplus_app_update_sys_static_info(const struct sk_buff *skb, int send, int retrans) +{ + if(send && retrans){ + sys_stati_info.sys_retrans_total_packets++; + if((TCP_SKB_CB(skb)->tcp_flags) & TCPHDR_SYN){ + sys_stati_info.sys_retrans_syn_packets++; + } + return; + } + + sys_stati_info.sys_total_packets++; + sys_stati_info.sys_total_bytes += skb->len; + if(send){ + sys_stati_info.sys_send_packets++; + sys_stati_info.sys_send_bytes += skb->len; + } + else{ + sys_stati_info.sys_recv_packets++; + sys_stati_info.sys_recv_bytes += skb->len; + } +} + +void oplus_app_monitor_update_app_info(struct sock *sk, const struct sk_buff *skb, int send, int retrans) +{ + u32 uid_val; + u32 hash_index; + struct app_monitor_app_info_list_node_st *app_info_node = 0; + u32 app_samp_time; //unit:second + struct timeval now_tv; + u32 now_sec; + unsigned long flags; + + uid_val = sk->sk_uid.val; + if(uid_val < 10000 || !skb){ + return; + } + + hash_index = uid_val & APP_MONITOR_HASH_MASK; + do_gettimeofday(&now_tv); + now_sec = (u32)now_tv.tv_sec; + write_lock_irqsave(&app_power_monitor_lock, flags); + if(!app_monitor_enable){ + goto exit_func; + } + + oplus_app_update_sys_static_info(skb, send, retrans); + + app_info_node = oplus_app_monitor_get_app_info_by_uid(uid_val); + if(!app_info_node){ + printk("[app_monitor]:get app_info_node error!\n"); + goto exit_func; + } + + if(retrans){ + oplus_app_monitor_update_retrans_stat(app_info_node, skb); + oplus_app_monitor_update_top_retrans_app(&app_info_node->app_info); + } + + if(!skb->len){ + goto exit_func; + } + //do traffic ralative operation + oplus_app_monitor_update_flow_stat(app_info_node, skb, send); + oplus_app_monitor_update_top_trafffic_app(&app_info_node->app_info); + + if(retrans){ + goto exit_func; + } + + //do beat check ralative operation + if(send){ + if(!app_info_node->app_info.last_send_time){ + goto exit_func; + } + + app_samp_time = now_sec - app_info_node->app_info.last_active_time; + if(app_samp_time >= PERIOD_CHECK_TIME && app_samp_time < REPORT_INTERVAL){ + app_info_node->app_info.beat_period = (app_info_node->app_info.beat_period * app_info_node->app_info.beat_count + + app_samp_time) / (app_info_node->app_info.beat_count + 1); + if(!app_info_node->app_info.beat_count) + app_info_node->app_info.beat_alarm_start_time = now_sec; + + app_info_node->app_info.beat_count++; + oplus_app_monitor_update_top_beat_app(&app_info_node->app_info); + + if(app_info_node->app_info.beat_count % ALARM_DETECT_COUNT == 0){ + int time_gap = now_sec - app_info_node->app_info.beat_alarm_start_time; + int period = time_gap / ALARM_DETECT_COUNT; + if(app_info_node->app_info.beat_alarm_start_time && time_gap < ALARM_DETECT_PERIOD){ + oplus_app_monitor_send_beat_alarm(app_info_node->app_info.uid_val, period); + } + app_info_node->app_info.beat_alarm_start_time = now_sec; + } + } + } + else{ + if(!app_info_node->app_info.last_active_time){ + goto exit_func; + } + + app_samp_time = now_sec - app_info_node->app_info.last_active_time; + if(app_samp_time > PERIOD_CHECK_TIME && app_samp_time < REPORT_INTERVAL){ + app_info_node->app_info.push_period = (app_info_node->app_info.push_period * app_info_node->app_info.push_count + + app_samp_time) / (app_info_node->app_info.push_count + 1); + if(!app_info_node->app_info.push_count) + app_info_node->app_info.push_alarm_start_time = now_sec; + + app_info_node->app_info.push_count++; + oplus_app_monitor_update_top_push_app(&app_info_node->app_info); + + if(app_info_node->app_info.push_count % ALARM_DETECT_COUNT == 0){ + int time_gap = now_sec - app_info_node->app_info.push_alarm_start_time; + int period = time_gap / ALARM_DETECT_COUNT; + if(app_info_node->app_info.push_alarm_start_time && time_gap < ALARM_DETECT_PERIOD){ + oplus_app_monitor_send_push_alarm(app_info_node->app_info.uid_val, period); + } + app_info_node->app_info.push_alarm_start_time = now_sec; + } + } + } + +exit_func: + if(app_info_node){ + app_info_node->app_info.last_active_time = now_sec; + if(send){ + app_info_node->app_info.last_send_time = now_sec; + } + } + write_unlock_irqrestore(&app_power_monitor_lock, flags); +} +EXPORT_SYMBOL(oplus_app_monitor_update_app_info); + +int app_monitor_dl_ctl_msg_handle(struct nlmsghdr *nlh) +{ + struct app_monitor_dl_ctl_msg_st *dl_ctl_msg = (struct app_monitor_dl_ctl_msg_st *)NLMSG_DATA(nlh); + printk("[app_monitor]:dl_ctl_msg received\n"); + + if(dl_ctl_msg->msg_len != sizeof(struct app_monitor_dl_ctl_msg_st)){ + printk("[app_monitor]:msg_len err, msg_len=%u, expected_len=%lu\n", + dl_ctl_msg->msg_len, sizeof(struct app_monitor_dl_ctl_msg_st)); + return -EINVAL; + } + + if(dl_ctl_msg->start_flag){ + oplus_app_monitor_start(); + }else{ + oplus_app_monitor_stop(); + } + + return 0; +} + +static int proc_app_power_monitor_start(struct ctl_table *ctl, int write, void __user *buffer, size_t *lenp,loff_t *ppos) +{ + int ret; + printk("[app_monitor]:proc_app_power_monitor_start\n"); + ret = proc_dointvec(ctl, write, buffer, lenp, ppos); + if (write && ret == 0){ + if(app_monitor_start){ + oplus_app_monitor_start(); + } + else{ + oplus_app_monitor_stop(); + } + } + + return ret; +} + +static int proc_app_power_report_request(struct ctl_table *ctl, int write, void __user *buffer, size_t *lenp, loff_t *ppos) +{ + int ret; + printk("[app_monitor]:proc_app_power_report_request"); + ret = proc_dointvec(ctl, write, buffer, lenp, ppos); + if (write && ret == 0){ + if(app_report_request){ + oplus_app_monitor_send_app_info_report(); + } + } + + return ret; +} + +static int proc_app_set_beat_alarm_period(struct ctl_table *ctl, int write, void __user *buffer, size_t *lenp, loff_t *ppos) +{ + int ret; + int index; + printk("[app_monitor]:proc_app_set_beat_alarm_period"); + ret = proc_dointvec(ctl, write, buffer, lenp, ppos); + if (write && ret == 0){ + index = top_app_beat_info.max_index; + oplus_app_monitor_send_beat_alarm(top_app_beat_info.app_beat_info[index].uid_val, (u32)app_beat_alarm_period); + printk("[app_monitor]:alarm:uid=%u,beat_period=%d", top_app_beat_info.app_beat_info[index].uid_val, app_beat_alarm_period); + } + + return ret; +} + +static int proc_app_set_push_alarm_period(struct ctl_table *ctl, int write, void __user *buffer, size_t *lenp, loff_t *ppos) +{ + int ret; + int index; + printk("[app_monitor]:proc_app_set_push_alarm_period"); + ret = proc_dointvec(ctl, write, buffer, lenp, ppos); + if (write && ret == 0){ + index = top_app_push_info.max_index; + oplus_app_monitor_send_push_alarm(top_app_push_info.app_push_info[index].uid_val, (u32)app_push_alarm_period); + printk("[app_monitor]:alarm:uid=%u,push_period=%d", top_app_push_info.app_push_info[index].uid_val, app_push_alarm_period); + } + + return ret; +} + +int app_monitor_dl_report_msg_handle(struct nlmsghdr *nlh) +{ + printk("[app_monitor]:dl_report_req_msg received\n"); + oplus_app_monitor_send_app_info_report(); + report_timer_restart(); + return 0; +} + +static struct ctl_table app_power_monitor_sysctl_table[] = +{ + { + .procname = "app_monitor_start", + .data = &app_monitor_start, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_app_power_monitor_start, + }, + { + .procname = "app_report_request", + .data = &app_report_request, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_app_power_report_request, + }, + { + .procname = "app_beat_alarn_period", + .data = &app_beat_alarm_period, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_app_set_beat_alarm_period, + }, + { + .procname = "app_push_alarn_period", + .data = &app_push_alarm_period, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_app_set_push_alarm_period, + }, + { } +}; + +static int oplus_app_power_monitor_sysctl_init(void) +{ + app_power_monitor_table_hrd = register_net_sysctl(&init_net, "net/oplus_app_power_monitor", app_power_monitor_sysctl_table); + return app_power_monitor_table_hrd == NULL ? -ENOMEM : 0; +} + +void oplus_app_power_monitor_init(void) +{ + int i; + unsigned long flags; + + report_timer_init(); + oplus_app_power_monitor_sysctl_init(); + rwlock_init(&app_power_monitor_lock); + write_lock_irqsave(&app_power_monitor_lock, flags); + app_monitor_enable = 0; + + memset(&top_app_traffic_info, 0, sizeof(struct app_monitor_top_app_trafffic_info_st)); + memset(&top_app_beat_info, 0, sizeof(struct app_monitor_top_app_beat_info_st)); + memset(&top_app_push_info, 0, sizeof(struct app_monitor_top_app_push_info_st)); + memset(&top_app_retrans_info, 0, sizeof(struct app_monitor_top_app_retrans_info_st)); + memset(&sys_stati_info, 0, sizeof(struct sys_stati_info_st)); + + for(i = 0; i < APP_MONITOR_HASHTABLE_SIZE; i++){ + INIT_LIST_HEAD(&app_monitor_list[i].m_listhead); + } + + write_unlock_irqrestore(&app_power_monitor_lock, flags); + printk("[app_monitor]:oplus_app_power_monitor_init\n"); + return; +} + +void oplus_app_power_monitor_fini(void) +{ + report_timer_del(); + oplus_app_monitor_stop(); + if(app_power_monitor_table_hrd){ + unregister_net_sysctl_table(app_power_monitor_table_hrd); + } +} + + + diff --git a/net/oplus_connectivity_routerboost/Kconfig b/net/oplus_connectivity_routerboost/Kconfig new file mode 100644 index 000000000000..80e37b15499e --- /dev/null +++ b/net/oplus_connectivity_routerboost/Kconfig @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: GPL-2.0-only +# Copyright (C) 2020-2022 Oplus. All rights reserved. + +config OPLUS_FEATURE_WIFI_ROUTERBOOST + tristate "Add for oplus routerboost function" + help + Add for oplus routerboost function. diff --git a/net/oplus_connectivity_routerboost/Makefile b/net/oplus_connectivity_routerboost/Makefile new file mode 100644 index 000000000000..b90fad6deccc --- /dev/null +++ b/net/oplus_connectivity_routerboost/Makefile @@ -0,0 +1,22 @@ +#/************************************************************************************ +#** File: - Makefile +#** Copyright (C), 2008-2020, OPLUS Mobile Comm Corp., Ltd +#** +#** Description: +#** 1. Add for routerboost +#** +#** Version: 1.0 +#** Date : 2021-04-09 +#** TAG : OPLUS_FEATURE_WIFI_ROUTERBOOST +#** +#** ---------------------Revision History: --------------------- +#** +#** --------------------------------------------------------------- +#** +#************************************************************************************/ + +# +# Makefile for the netfilter modules on top of IPv4. +# +obj-$(CONFIG_OPLUS_FEATURE_WIFI_ROUTERBOOST) += oplus_connectivity_routerboost.o +oplus_connectivity_routerboost-objs := oplus_routerboost.o oplus_routerboost_game_monitor.o diff --git a/net/oplus_connectivity_routerboost/oplus_routerboost.c b/net/oplus_connectivity_routerboost/oplus_routerboost.c new file mode 100644 index 000000000000..141038ce6eaa --- /dev/null +++ b/net/oplus_connectivity_routerboost/oplus_routerboost.c @@ -0,0 +1,303 @@ +/************************************************************************************ +** File: - oplus_routerboost.c +** Copyright (C), 2008-2020, OPLUS Mobile Comm Corp., Ltd +** +** Description: +** 1. Add for RouterBoost GKI +** +** Version: 1.0 +** Date : 2021-04-19 +** TAG: OPLUS_FEATURE_WIFI_ROUTERBOOST +** +** ---------------------Revision History: --------------------- +** +** --------------------------------------------------------------- +************************************************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "oplus_routerboost.h" + +int routerboost_debug = 0; +static int routerboost_netlink_pid = 0; + +static struct ctl_table_header *routerboost_sysctl_table_header = NULL; + +/* ---- sysctl process func start ---- */ +static struct ctl_table routerboost_sysctl_table[] = { + { + .procname = "routerboost_debug", + .data = &routerboost_debug, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec, + }, + { } +}; + +static int routerboost_sysctl_register(void) +{ + routerboost_sysctl_table_header = register_net_sysctl(&init_net, + "net/oplus_routerboost", routerboost_sysctl_table); + return routerboost_sysctl_table_header == NULL ? -ENOMEM : 0; +} + +static void routerboost_sysctl_unregister(void) +{ + if (routerboost_sysctl_table_header != NULL) { + unregister_net_sysctl_table(routerboost_sysctl_table_header); + } +} +/* ---- sysctl process func end ---- */ + +/* ---- genl process func start ---- */ +static int handle_nlmsg_set_android_pid(struct sk_buff *skb) +{ + struct nlmsghdr *nlhdr = nlmsg_hdr(skb); + routerboost_netlink_pid = nlhdr->nlmsg_pid; + return 0; +} + +static int handle_nlmsg_set_kernel_debug(struct nlattr *nla) +{ + routerboost_debug = *(u32 *)NLA_DATA(nla); + debug("routerboost_debug = %d\n", routerboost_debug); + return 0; +} + +static int handle_nlmsg_set_game_uid(struct nlattr *nla) +{ + u32 uid = *(u32 *)NLA_DATA(nla); + set_game_monitor_uid(uid);/*defined in oplus_routerboost_game_monitor.c*/ + return 0; +} + +static int handle_nlmsg_set_wlan_index(struct nlattr *nla) +{ + u32 monitor_wlan_index = *(u32 *)NLA_DATA(nla); + set_game_monitor_wlan_index(monitor_wlan_index);/*defined in oplus_routerboost_game_monitor.c*/ + return 0; +} + +static int handle_nlmsg_set_game_playing_state(struct nlattr *nla) +{ + u32 is_playing = *(u32 *)NLA_DATA(nla); + set_game_playing_state(is_playing);/*defined in oplus_routerboost_game_monitor.c*/ + return 0; +} + +static int routerboost_genl_nlmsg_handle(struct sk_buff *skb, + struct genl_info *info) +{ + int ret = 0; + struct nlmsghdr *nlhdr; + struct genlmsghdr *genlhdr; + struct nlattr *nla; + + nlhdr = nlmsg_hdr(skb); + genlhdr = nlmsg_data(nlhdr); + nla = genlmsg_data(genlhdr); + + if (routerboost_debug) { + debug("routerboost_genl_nlmsg_handle, the nla->nla_type = %u, len = %u\n", + nla->nla_type, nla->nla_len); + } + + switch (nla->nla_type) { + case ROUTERBOOST_MSG_SET_ANDROID_PID: + ret = handle_nlmsg_set_android_pid(skb); + break; + + case ROUTERBOOST_MSG_SET_KERNEL_DEBUG: + ret = handle_nlmsg_set_kernel_debug(nla); + break; + + case ROUTERBOOST_MSG_SET_GAME_UID: + ret = handle_nlmsg_set_game_uid(nla); + break; + + case ROUTERBOOST_MSG_SET_WLAN_INDEX: + ret = handle_nlmsg_set_wlan_index(nla); + break; + + case ROUTERBOOST_MSG_SET_GAME_PLAYING_STATE: + ret = handle_nlmsg_set_game_playing_state(nla); + break; + + default: + break; + } + + return ret; +} + +static const struct genl_ops routerboost_genl_ops[] = { + { + .cmd = ROUTERBOOST_CMD_DOWNLINK, + .flags = 0, + .doit = routerboost_genl_nlmsg_handle, + .dumpit = NULL, + }, +}; + +static struct genl_family routerboost_genl_family = { + .id = 0, + .hdrsize = 0, + .name = ROUTERBOOST_FAMILY, + .version = ROUTERBOOST_FAMILY_VERSION, + .maxattr = ROUTERBOOSt_MSG_MAX, + .ops = routerboost_genl_ops, + .n_ops = ARRAY_SIZE(routerboost_genl_ops), +}; + +static inline int genl_msg_prepare_usr_msg(u8 cmd, size_t size, pid_t pid, + struct sk_buff **skbp) +{ + struct sk_buff *skb; + /* create a new netlink msg */ + skb = genlmsg_new(size, GFP_ATOMIC); + + if (skb == NULL) { + return -ENOMEM; + } + + /* Add a new netlink message to an skb */ + genlmsg_put(skb, pid, 0, &routerboost_genl_family, 0, cmd); + *skbp = skb; + return 0; +} + +static inline int genl_msg_mk_usr_msg(struct sk_buff *skb, int type, void *data, + int len) +{ + int ret; + + /* add a netlink attribute to a socket buffer */ + if ((ret = nla_put(skb, type, len, data)) != 0) { + return ret; + } + + return 0; +} + +/* send to user space */ +int routerboost_genl_msg_send_to_user(int msg_type, char *payload, + int payload_len) +{ + int ret = 0; + void *head; + struct sk_buff *skbuff; + size_t size; + + if (!routerboost_netlink_pid) { + debug("routerboost_netlink_pid == 0!!\n"); + return -1; + } + + /*allocate new buffer cache */ + size = nla_total_size(payload_len); + ret = genl_msg_prepare_usr_msg(ROUTERBOOST_CMD_UPLINK, size, + routerboost_netlink_pid, &skbuff); + + if (ret) { + return ret; + } + + ret = genl_msg_mk_usr_msg(skbuff, msg_type, payload, payload_len); + + if (ret) { + kfree_skb(skbuff); + return ret; + } + + head = genlmsg_data(nlmsg_data(nlmsg_hdr(skbuff))); + genlmsg_end(skbuff, head); + + /* send data */ + ret = genlmsg_unicast(&init_net, skbuff, routerboost_netlink_pid); + + if (ret < 0) { + debug("routerboost_send_to_user fail, can not unicast skbuff, ret = %d\n", ret); + return -1; + } + + return 0; +} + +static int routerboost_genl_register(void) +{ + int ret; + ret = genl_register_family(&routerboost_genl_family); + + if (ret) { + debug("genl_register_family:%s error,ret = %d\n", ROUTERBOOST_FAMILY, ret); + return ret; + + } else { + debug("genl_register_family complete, id = %d!\n", routerboost_genl_family.id); + } + + return 0; +} + +static void routerboost_genl_unregister(void) +{ + genl_unregister_family(&routerboost_genl_family); +} +/* ---- genl process func end ---- */ + +static int __init routerboost_module_init(void) +{ + int ret = 0; + + ret = routerboost_genl_register(); + + if (ret < 0) { + debug(" module can not init netlink.\n"); + } + + ret |= routerboost_sysctl_register(); + ret |= routerboost_game_monitor_init(); + + debug(" enter.\n"); + return ret; +} + +static void __exit routerboost_module_exit(void) +{ + routerboost_genl_unregister(); + routerboost_sysctl_unregister(); + routerboost_game_monitor_exit(); + debug(" exit.\n"); +} + +module_init(routerboost_module_init); +module_exit(routerboost_module_exit); +MODULE_LICENSE("GPL v2"); diff --git a/net/oplus_connectivity_routerboost/oplus_routerboost.h b/net/oplus_connectivity_routerboost/oplus_routerboost.h new file mode 100644 index 000000000000..42a27aa7513b --- /dev/null +++ b/net/oplus_connectivity_routerboost/oplus_routerboost.h @@ -0,0 +1,63 @@ + +/************************************************************************************ +** File: - oplus_routerboost_game_monitor.h +** Copyright (C), 2008-2020, OPLUS Mobile Comm Corp., Ltd +** +** Description: +** 1. Add for RouterBoost GKI +** +** Version: 1.0 +** Date : 2021-04-19 +** TAG: OPLUS_FEATURE_WIFI_ROUTERBOOST +** OPLUS Java File Skip Rule:readability/double backslash +** ---------------------Revision History: --------------------- +** +** --------------------------------------------------------------- +************************************************************************************/ +#ifndef OPLUS_ROUTER_BOOST_H_ +#define OPLUS_ROUTER_BOOST_H_ + +enum ROUTERBOOST_MSG { + ROUTERBOOST_MSG_UNSPEC = 0, + ROUTERBOOST_MSG_SET_ANDROID_PID = 1, + ROUTERBOOST_MSG_SET_KERNEL_DEBUG = 2, + ROUTERBOOST_MSG_SET_GAME_UID = 3, + ROUTERBOOST_MSG_REPOET_GAME_STREEM_INFO = 4, + ROUTERBOOST_MSG_SET_WLAN_INDEX = 5, + ROUTERBOOST_MSG_SET_GAME_PLAYING_STATE = 6, + ROUTERBOOST_MSG_REPOET_GAME_PKT_INFO = 7, + ROUTERBOOST_MSG_REPOET_GAME_PKT_INFO_FIN = 8, + __ROUTERBOOST_MSG_MAX +}; + +enum ROUTERBOOST_CMD { + ROUTERBOOST_CMD_UNSPEC = 0, + ROUTERBOOST_CMD_DOWNLINK = 1, + ROUTERBOOST_CMD_UPLINK = 2, + __ROUTERBOOST_CMD_MAX +}; + +#define ROUTERBOOSt_MSG_MAX (__ROUTERBOOST_MSG_MAX - 1) +#define ROUTERBOOST_CMD_MAX (__ROUTERBOOST_CMD_MAX - 1) +#define ROUTERBOOST_FAMILY_VERSION 1 +#define ROUTERBOOST_FAMILY "routerboost" + +#define NLA_DATA(na) ((char *)((char*)(na) + NLA_HDRLEN)) +#define LOG_TAG "[oplus_routerboost] %s line:%d " +#define debug(fmt, args...) printk(LOG_TAG fmt, __FUNCTION__, __LINE__, ##args) + +#define WLAN0 "wlan0" +#define WLAN1 "wlan1" + +/*defined in oplus_routerboost.c*/ +extern int routerboost_debug; +extern int routerboost_genl_msg_send_to_user(int msg_type, char *payload, int payload_len); + +/*defined in oplus_routerboost_game_monitor.c*/ +extern void set_game_monitor_uid(u32 uid); +extern void set_game_monitor_wlan_index(u32 wlan_index); +extern void set_game_playing_state(u32 is_game_playing); + +extern int routerboost_game_monitor_init(void); +extern void routerboost_game_monitor_exit(void); +#endif /*OPLUS_ROUTER_BOOST_H_*/ diff --git a/net/oplus_connectivity_routerboost/oplus_routerboost_game_monitor.c b/net/oplus_connectivity_routerboost/oplus_routerboost_game_monitor.c new file mode 100644 index 000000000000..621e41f9732d --- /dev/null +++ b/net/oplus_connectivity_routerboost/oplus_routerboost_game_monitor.c @@ -0,0 +1,267 @@ +/************************************************************************************ +** File: - oplus_routerboost_game_monitor.c +** Copyright (C), 2008-2020, OPLUS Mobile Comm Corp., Ltd +** +** Description: +** 1. Add for RouterBoost GKI +** +** Version: 1.0 +** Date : 2021-04-19 +** TAG: OPLUS_FEATURE_WIFI_ROUTERBOOST +** +** ---------------------Revision History: --------------------- +** +** --------------------------------------------------------------- +************************************************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "oplus_routerboost.h" + +#define DETECT_PKT_THRED (32) + +static u32 detect_game_uid = 0; +static char detect_ifname[10] = {0}; + +static int detect_playing_pkt_cnt = 0; +static int is_game_playing = 0; + +void set_game_monitor_uid(u32 uid) +{ + detect_game_uid = uid; + debug("detect_game_uid = %d\n", detect_game_uid); +} + +void set_game_monitor_wlan_index(u32 monitor_wlan_index) +{ + if (monitor_wlan_index == 0) { + strcpy(detect_ifname, WLAN0); + + } else if (monitor_wlan_index == 1) { + strcpy(detect_ifname, WLAN1); + + } else { + memset(detect_ifname, 0, sizeof(detect_ifname)); + } + + debug("detect_ifname = %s\n", detect_ifname); +} + +void set_game_playing_state(u32 is_playing) +{ + if (is_playing == 1) { + is_game_playing = 1; + + } else { + is_game_playing = 0; + } + + if (is_game_playing) { + /*a new game start, reset the detect_main_stream_pkt_cnt to detect the game main stream*/ + detect_playing_pkt_cnt = 0; + } + + debug("set_game_playing_state = %d\n", is_game_playing); +} + +static int is_game_monitor_interface(char *dev_name) +{ + if (NULL == dev_name) { + return 0; + } + + if (!strcmp(dev_name, detect_ifname)) { + return 1; + } + + return 0; +} + +static int is_game_monitor_stream(u32 uid) +{ + if (detect_game_uid != 0 && uid == detect_game_uid) { + return 1; + } + + return 0; +} + +static int is_game_monitor_enable(void) +{ + return detect_game_uid; /*if detect_game_uid = 0, it means not need detect*/ +} + +static int is_game_monitor_need_detect_pkt(void) +{ + if (is_game_playing && (detect_playing_pkt_cnt <= DETECT_PKT_THRED)) { + return 1; + + } else { + return 0; + } +} + +static void detect_game_stream_info(struct sk_buff *skb) +{ + int send_msg[10] = {0}; + + u32 uid = 0; + int srcport = 0; + int dstport = 0; + unsigned char *dstip = NULL; + unsigned char *srcip = NULL; + + struct sock *sk = NULL; + struct iphdr *iph = NULL; + struct nf_conn *ct = NULL; + struct net_device *dev = NULL; + enum ip_conntrack_info ctinfo; + const struct file *filp = NULL; + + if (NULL == skb) { + return; + } + + if (!is_game_monitor_enable()) { + return; + } + + dev = skb_dst(skb)->dev; + + if (NULL == dev) { + return; + } + + if (!is_game_monitor_interface(dev->name)) { + return; + } + + ct = nf_ct_get(skb, &ctinfo); + + if (NULL == ct) { + return; + } + + sk = skb_to_full_sk(skb); + + if (NULL == sk || NULL == sk->sk_socket) { + return; + } + + filp = sk->sk_socket->file; + + if (NULL == filp) { + return; + } + + uid = filp->f_cred->fsuid.val; + + if (!is_game_monitor_stream(uid)) { + return; + } + + iph = ip_hdr(skb); + + if (NULL == iph) { + return; + } + + if (iph->protocol == IPPROTO_UDP /*|| iph->protocol == IPPROTO_TCP*/) { + dstport = ntohs(udp_hdr(skb)->dest); + srcport = ntohs(udp_hdr(skb)->source); + dstip = (unsigned char *)&iph->daddr; + srcip = (unsigned char *)&iph->saddr; + + send_msg[0] = uid; + send_msg[1] = iph->protocol; + + send_msg[2] = dstip[0]; + send_msg[3] = dstip[1]; + send_msg[4] = dstip[2]; + send_msg[5] = dstip[3]; + + send_msg[6] = srcip[0]; + send_msg[7] = srcip[1]; + send_msg[8] = srcip[2]; + send_msg[9] = srcip[3]; + + if (ctinfo == IP_CT_NEW) { + /*send detect new game stream info to userspace*/ + routerboost_genl_msg_send_to_user(ROUTERBOOST_MSG_REPOET_GAME_STREEM_INFO, + (char *)send_msg, sizeof(send_msg)); + + } else if (is_game_monitor_need_detect_pkt()) { + /*send the first DETECT_PKT_THRED pkt info to userspace*/ + /*From these DETECT_PKT_THRED packets, statistics identify the game's main data stream*/ + routerboost_genl_msg_send_to_user(ROUTERBOOST_MSG_REPOET_GAME_PKT_INFO, + (char *)send_msg, sizeof(send_msg)); + ++detect_playing_pkt_cnt; + + if (detect_playing_pkt_cnt == DETECT_PKT_THRED) { + routerboost_genl_msg_send_to_user(ROUTERBOOST_MSG_REPOET_GAME_PKT_INFO_FIN, + (char *)send_msg, sizeof(send_msg)); + } + } + } +} + +static unsigned int routerboost_nf_output_hook_func(void *priv, + struct sk_buff *skb, const struct nf_hook_state *state) +{ + int ret = NF_ACCEPT; + detect_game_stream_info(skb); + return ret; +} + +static struct nf_hook_ops routerboost_nf_hook_ops[] __read_mostly = { + { + .hook = routerboost_nf_output_hook_func, + .pf = NFPROTO_IPV4, + .hooknum = NF_INET_LOCAL_OUT, + .priority = NF_IP_PRI_CONNTRACK + 2, + } +}; + +int routerboost_game_monitor_init(void) +{ + int ret = 0; + ret = nf_register_net_hooks(&init_net, routerboost_nf_hook_ops, + ARRAY_SIZE(routerboost_nf_hook_ops)); + + debug(" enter.\n"); + return ret; +} + +void routerboost_game_monitor_exit(void) +{ + nf_unregister_net_hooks(&init_net, routerboost_nf_hook_ops, + ARRAY_SIZE(routerboost_nf_hook_ops)); + debug(" exit.\n"); +} diff --git a/net/oplus_connectivity_sla/Kconfig b/net/oplus_connectivity_sla/Kconfig new file mode 100644 index 000000000000..e4f3d4749684 --- /dev/null +++ b/net/oplus_connectivity_sla/Kconfig @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: GPL-2.0-only +# Copyright (C) 2020-2022 Oplus. All rights reserved. + +config OPLUS_FEATURE_WIFI_SLA + tristate "Add for oplus sla function" + help + Add for oplus sla function. diff --git a/net/oplus_connectivity_sla/Makefile b/net/oplus_connectivity_sla/Makefile new file mode 100644 index 000000000000..e6b421088765 --- /dev/null +++ b/net/oplus_connectivity_sla/Makefile @@ -0,0 +1,21 @@ +#/************************************************************************************ +#** File: - Makefile +#** Copyright (C), 2008-2020, OPLUS Mobile Comm Corp., Ltd +#** +#** Description: +#** 1. Add for sla +#** +#** Version: 1.0 +#** Date : 2021-7-17 +#** TAG : OPLUS_FEATURE_WIFI_SLA +#** +#** ---------------------Revision History: --------------------- +#** +#** --------------------------------------------------------------- +#** +#************************************************************************************/ + +# +# Makefile for the netfilter modules on top of IPv4. +# +obj-$(CONFIG_OPLUS_FEATURE_WIFI_SLA) += oplus_connectivity_sla.o diff --git a/net/oplus_connectivity_sla/oplus_connectivity_sla.c b/net/oplus_connectivity_sla/oplus_connectivity_sla.c new file mode 100644 index 000000000000..1187eafb4e7c --- /dev/null +++ b/net/oplus_connectivity_sla/oplus_connectivity_sla.c @@ -0,0 +1,1616 @@ +/************************************************************************************ +** File: - oplus_connectivity_sla.c +** Copyright (C), 2008-2020, OPLUS Mobile Comm Corp., Ltd +** +** Description: +** 1. Add for SLA GKI +** +** Version: 1.0 +** Date : 2021-04-19 +** TAG : OPLUS_FEATURE_WIFI_CONNECTIVITY_SLA +** +** ---------------------Revision History: --------------------- +** +** --------------------------------------------------------------- +** +************************************************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#define LOG_TAG "[oplus_connectivity_sla] %s line:%d " +#define debug(fmt,args...) printk(LOG_TAG fmt,__FUNCTION__,__LINE__,##args) + +#define IFACE_NUM 3 +#define WLAN_NUM 2 +#define WLAN0_INDEX 0 +#define WLAN1_INDEX 1 +#define CELL_INDEX 2 + +#define MARK_MASK 0x0fff +#define GAME_UNSPEC_MASK 0x8000 +#define CT_MARK_APP_TYPE_MASK 0xfff00000 //mark for detect white list +#define CT_MARK_APP_TYPE_OFFSET 20 + +#define GAME_NUM 7 +#define IFACE_LEN 16 +#define WHITE_APP_BASE 100 +#define DUAL_STA_APP_BASE 200 +#define WHITE_APP_NUM 64 +#define DUAL_STA_APP_NUM 256 + +//#define DNS_TIME 10 + +#define UID_MASK 100000 +#define INIT_APP_TYPE 0 +#define UNKNOW_APP_TYPE 0xfff /*for distinguish dual sta app*/ + +#define OPLUS_SLA_CMD_MAX (__OPLUS_SLA_CMD_MAX - 1) +#define OPLUS_SLA_FAMILY_VERSION 1 +#define OPLUS_SLA_FAMILY "oplus_sla" +#define NLA_DATA(na) ((char *)((char*)(na) + NLA_HDRLEN)) +#define GENL_ID_GENERATE 0 + +enum { + OPLUS_SLA_CMD_UNSPEC = 1, + OPLUS_SLA_CMD_SET_ANDROID_PID = 2, + OPLUS_SLA_CMD_ENABLE = 3, + OPLUS_SLA_CMD_DISABLE = 4, + OPLUS_SLA_CMD_IFACE_CHANGED = 5, + OPLUS_SLA_CMD_SET_WHITE_LIST_APP = 6, + OPLUS_SLA_CMD_SET_DUAL_STA_LIST_APP = 7, + OPLUS_SLA_CMD_SET_GAME_LIST_APP = 8, + OPLUS_SLA_CMD_SET_VIDEO_LIST_APP = 9, + OPLUS_SLA_CMD_CHANGE_GAME_NETWORK = 10, + OPLUS_SLA_CMD_CHANGE_VIDEO_APP_NETWORK = 11, + OPLUS_SLA_CMD_CHANGE_DNS_NETWORK = 12, + OPLUS_SLA_CMD_UPDATE_WEIGHT = 13, + OPLUS_SLA_CMD_SET_KERNEL_DEBUG = 14, + OPLUS_SLA_CMD_CHANGE_VPN_STATE = 15, + OPLUS_SLA_CMD_CHANGE_DEFAULT_NETWORK = 16, + OPLUS_SLA_ENABLED_EVENT = 18, + OPLUS_SLA_DISABLED_EVENT = 19, + OPLUS_SLA_GAME_NETWORK_CHANGED_EVENT = 20, + __SLA_MSG_MAX, +}; + +enum { + OPLUS_SLA_UNSPEC, + OPLUS_SLA_CMD_DOWNLINK, + OPLUS_SLA_CMD_UPLINK, + __OPLUS_SLA_CMD_MAX +}; + + +#define OPLUS_SLA_MSG_MAX (__SLA_MSG_MAX - 1) + + +/* dev info struct + * if we need to consider wifi RSSI ?if we need consider screen state? +*/ +struct oplus_dev_info { + int if_up; + int weight; + //int weight_state; + u32 mark; + char dev_name[IFACE_LEN]; +}; + +struct oplus_white_app_info { + u32 count; + u32 uid[WHITE_APP_NUM]; + u64 cell_bytes[WHITE_APP_NUM]; + u64 cell_bytes_normal[WHITE_APP_NUM]; +}; + +struct oplus_dual_sta_info { + u32 count; + u32 uid[DUAL_STA_APP_NUM]; +}; + +struct oplus_sla_game_info { + u32 game_type; + u32 uid; + u32 mark; +}; + +enum { + SLA_SKB_ACCEPT, + SLA_SKB_CONTINUE, + SLA_SKB_MARKED, + SLA_SKB_REMARK, + SLA_SKB_DROP, +}; + +enum { + GAME_UNSPEC = 0, + GAME_WZRY = 1, + GAME_CJZC, + GAME_QJCJ, + GAME_HYXD_NM, + GAME_HYXD, + GAME_HYXD_ALI, +}; + +enum { + + WLAN0_MARK_BIT = 8, //WLAN mark value,mask 0x0fff + WLAN0_MARK = (1 << WLAN0_MARK_BIT), + + WLAN1_MARK_BIT = 9, //WLAN mark value,mask 0x0fff + WLAN1_MARK = (1 << WLAN1_MARK_BIT), + + CELL_MARK_BIT = 10, //cellular mark value mask 0x0fff + CELL_MARK = (1 << CELL_MARK_BIT), + + RETRAN_BIT = 12, //first retran mark value, mask 0xf000 + RETRAN_MARK = (1 << RETRAN_BIT), + + RETRAN_SECOND_BIT = 13, //second retran mark value, mask 0xf000 + RETRAN_SECOND_MARK = (1 << RETRAN_SECOND_BIT), + + RTT_MARK_BIT = 14, //one ct only statitisc once rtt,mask 0xf000 + RTT_MARK = (1 << RTT_MARK_BIT), + + GAME_UNSPEC_MARK_BIT = 15, //mark game skb when game not start + GAME_UNSPEC_MARK = (1 << GAME_UNSPEC_MARK_BIT), +}; + +enum { + SLA_MODE_INIT = 0, + SLA_MODE_DUAL_WIFI = 1, + /*if the dual wifi is enable,please do not send + disable msg to kernel when rcv SLA_MODE_WIFI_CELL msg*/ + SLA_MODE_WIFI_CELL = 2, + SLA_MODE_DUAL_WIFI_CELL = 3, + SLA_MODE_RESERVER = 4, +}; + +static volatile u32 oplus_sla_netlink_pid; +static int MAIN_WLAN = WLAN0_INDEX; +static int SECOND_WLAN = WLAN1_INDEX; + +static int oplus_sla_enable_status; +static int oplus_sla_screen_on; +static int oplus_sla_debug = 0; +static int oplus_sla_def_net = 0; //WLAN0->0 WLAN1->1 CELL->2 +static int sla_work_mode = SLA_MODE_INIT; +static int dns_network = WLAN0_INDEX; +static int video_app_network = WLAN0_INDEX; //init + +static struct oplus_white_app_info white_app_list; +static struct oplus_dual_sta_info dual_wifi_app_list; +static struct oplus_dual_sta_info video_app_list; +static struct oplus_sla_game_info game_info[GAME_NUM]; +static int game_mark = 0; //for proc debug +static int oplus_sla_vpn_connected = 0; +static struct ctl_table_header *oplus_sla_table_hrd; + +static rwlock_t sla_lock; +static rwlock_t sla_game_lock; + +static int MAIN_WLAN_MARK = WLAN0_MARK; +static int SECOND_WLAN_MARK = WLAN1_MARK; +static struct oplus_dev_info oplus_sla_info[IFACE_NUM]; + +#define sla_read_lock() read_lock_bh(&sla_lock); +#define sla_read_unlock() read_unlock_bh(&sla_lock); +#define sla_write_lock() write_lock_bh(&sla_lock); +#define sla_write_unlock() write_unlock_bh(&sla_lock); + +#define sla_game_write_lock() write_lock_bh(&sla_game_lock); +#define sla_game_write_unlock() write_unlock_bh(&sla_game_lock); + + + +static u32 get_app_type(struct nf_conn *ct) +{ + if (ct != NULL) { + return (ct->mark & CT_MARK_APP_TYPE_MASK) >> CT_MARK_APP_TYPE_OFFSET; + } + + return 0; +} + +static void set_app_type(struct nf_conn *ct, int type) +{ + if (ct != NULL) { + ct->mark = (ct->mark & ~CT_MARK_APP_TYPE_MASK) | ((type << + CT_MARK_APP_TYPE_OFFSET) & CT_MARK_APP_TYPE_MASK); + } +} + +static bool is_same_app(u32 source_app_uid, u32 target_app_uid) +{ + return (source_app_uid % UID_MASK) == (target_app_uid % UID_MASK); +} + +static u32 get_ct_mark(struct nf_conn *ct) +{ + if (ct != NULL) { + return (ct->mark & ~CT_MARK_APP_TYPE_MASK); + } + return 0; +} + +static void set_ct_mark(struct nf_conn *ct, int mark) +{ + if (ct != NULL) { + ct->mark = (ct->mark & ~MARK_MASK) | mark; + } +} + +static void print_stream_info(struct sk_buff *skb) +{ + u32 uid = 0; + int srcport = 0; + int dstport = 0; + unsigned char *dstip; + + struct sock *sk = NULL; + struct iphdr *iph = NULL; + struct nf_conn *ct = NULL; + struct net_device *dev = NULL; + enum ip_conntrack_info ctinfo; + const struct file *filp = NULL; + + if (oplus_sla_debug) { + ct = nf_ct_get(skb, &ctinfo); + + if (NULL == ct) { + return; + } + + if (ctinfo == IP_CT_NEW) { + sk = skb_to_full_sk(skb); + + if (sk && sk_fullsock(sk)) { + if (NULL == sk->sk_socket) { + return; + } + + filp = sk->sk_socket->file; + + if (NULL == filp) { + return; + } + + iph = ip_hdr(skb); + + if (NULL != iph && + (iph->protocol == IPPROTO_TCP || iph->protocol == IPPROTO_UDP)) { + + dev = skb_dst(skb)->dev; + uid = filp->f_cred->fsuid.val; + dstport = ntohs(udp_hdr(skb)->dest); + srcport = ntohs(udp_hdr(skb)->source); + dstip = (unsigned char *)&iph->daddr; + + debug("screen_on[%d] uid[%u] proto[%d] srcport[%d] dstport[%d]" + " dstip[%d.%d.%d.%d] dev[%s] mark[%x] ct_mark[%x] app_type[%d]\n", + oplus_sla_screen_on, uid, iph->protocol, srcport, dstport, + dstip[0], dstip[1], dstip[2], dstip[3], dev ? dev->name : "null", skb->mark, + get_ct_mark(ct), get_app_type(ct)); + } + } + } + } + + return; +} + +static bool is_skb_pre_bound(struct sk_buff *skb) +{ + u32 pre_mark = skb->mark & 0x10000; + + if (0x10000 == pre_mark) { + return true; + } + + return false; +} + +static bool is_sla_white_or_game_app(struct nf_conn *ct, struct sk_buff *skb) +{ + u32 oplus_app_type = get_app_type(ct); + //debug("type : %u \n", get_app_type(ct)); + if (oplus_app_type > 0 && + oplus_app_type < DUAL_STA_APP_BASE) { /* game app skb */ + return true; + } + + return false; +} + +static bool is_dual_sta_white_app(struct nf_conn *ct, struct sk_buff *skb, + kuid_t *app_uid) +{ + int i = 0; + int last_type = UNKNOW_APP_TYPE; + kuid_t uid; + struct sock *sk = NULL; + const struct file *filp = NULL; + + //debug("type : %u \n", get_app_type(ct)); + + if (get_app_type(ct) >= DUAL_STA_APP_BASE) { + return true; + } + + if (UNKNOW_APP_TYPE != get_app_type(ct)) { + + last_type = get_app_type(ct); + + sk = skb_to_full_sk(skb); + + if (NULL == sk || NULL == sk->sk_socket) { + return false; + } + + filp = sk->sk_socket->file; + + if (NULL == filp) { + return false; + } + + *app_uid = filp->f_cred->fsuid; + uid = filp->f_cred->fsuid; + + for (i = 0; i < dual_wifi_app_list.count; i++) { + if (dual_wifi_app_list.uid[i]) { + if (is_same_app(uid.val, dual_wifi_app_list.uid[i])) { + + set_app_type(ct, i + DUAL_STA_APP_BASE); + return true; + } + } + } + + set_app_type(ct, last_type); + } + + return false; +} + + +static bool is_video_app(kuid_t app_uid) +{ + int i = 0; + kuid_t uid; + + for (i = 0; i < video_app_list.count; i++) { + if (video_app_list.uid[i]) { + uid = make_kuid(&init_user_ns, video_app_list.uid[i]); + + if (is_same_app(uid.val, app_uid.val)) { + debug("oplus_sla video app, the uid = %d", app_uid.val); + return true; + } + } + } + + return false; +} + +static int mark_video_app(struct sock *sk, + kuid_t app_uid, + struct nf_conn *ct, + struct sk_buff *skb) +{ + int choose_mark = 0; + int ret = SLA_SKB_CONTINUE; + + if (SLA_MODE_DUAL_WIFI == sla_work_mode && + is_video_app(app_uid)) { + if (video_app_network == MAIN_WLAN) { + choose_mark = MAIN_WLAN_MARK; + + } else if (video_app_network == SECOND_WLAN) { + choose_mark = SECOND_WLAN_MARK; + } + } + + if (choose_mark) { + skb->mark = choose_mark; + set_ct_mark(ct, skb->mark); + return SLA_SKB_MARKED; + } + + return ret; +} + + +/* +LAN IP: +A:10.0.0.0-10.255.255.255 +B:172.16.0.0-172.31.255.255 +C:192.168.0.0-192.168.255.255 +*/ +static bool dst_is_lan_ip(struct sk_buff *skb) +{ + struct iphdr *iph = NULL; + unsigned char *dstip = NULL; + + iph = ip_hdr(skb); + + if (NULL != iph) { + dstip = (unsigned char *)&iph->daddr; + + if ((10 == dstip[0]) || + (192 == dstip[0] && 168 == dstip[1]) || + (172 == dstip[0] && dstip[1] >= 16 && dstip[1] <= 31)) { + return true; + } + } + + return false; +} + +static int sla_skb_reroute(struct sk_buff *skb, struct nf_conn *ct, + const struct nf_hook_state *state) +{ + int err; + + /* err = ip_route_me_harder(state->net, state->sk, skb, RTN_UNSPEC); */ + err = ip_route_me_harder(state->net, skb, RTN_UNSPEC); + + if (err < 0) { + return NF_DROP_ERR(err); + } + + return NF_ACCEPT; +} + + +static u32 get_skb_mark_by_weight(void) +{ + int i = 0; + u32 sla_random = prandom_u32() & 0x7FFFFFFF; + + /*0x147AE15 = 0x7FFFFFFF /100 + 1; for we let the weight * 100 to void + *decimal point operation at linux kernel + */ + for (i = 0; i < IFACE_NUM; i++) { + if (oplus_sla_info[i].if_up && + oplus_sla_info[i].weight) { + if (sla_random < (0x147AE15 * oplus_sla_info[i].weight)) { + return oplus_sla_info[i].mark; + } + } + } + + return oplus_sla_info[MAIN_WLAN].mark; +} + +static bool is_need_change_dns_network(int index) +{ + if (dns_network != 0) { + return true; + + } else { + return false; + } + +} + +static int dns_skb_need_sla(struct nf_conn *ct, struct sk_buff *skb) +{ + int ret = SLA_SKB_CONTINUE; + struct iphdr *iph = NULL; + u_int32_t dns_ct_mark = MAIN_WLAN_MARK; + + iph = ip_hdr(skb); + + if (NULL != iph && + (iph->protocol == IPPROTO_TCP || iph->protocol == IPPROTO_UDP) && + 53 == ntohs(udp_hdr(skb)->dest)) { + + ret = SLA_SKB_ACCEPT; + + if (SLA_MODE_DUAL_WIFI == sla_work_mode) { + if (is_need_change_dns_network(SECOND_WLAN)) { + //for the dns packet will do DNAT at iptables,if do DNAT,the packet + //will be reroute,so here just mark and accept it + dns_ct_mark = SECOND_WLAN_MARK; + skb->mark = SECOND_WLAN_MARK; + //todo: same dst ip should do this ,differ dst ip just let it go and reroute by DNAT + //debug("dual sta reroute skb->mark = %x\n", skb->mark); + ret = SLA_SKB_MARKED; + } + + } else if (SLA_MODE_WIFI_CELL == sla_work_mode) { + if (is_need_change_dns_network(CELL_INDEX)) { + dns_ct_mark = CELL_MARK; + skb->mark = CELL_MARK; + //todo: same dst ip should do this + //ret = SLA_SKB_MARKED; + } + } + + //debug("dns mark = %x\n", skb->mark); + ct->mark = dns_ct_mark; + } + + return ret; +} + +static bool is_game_app_skb(struct nf_conn *ct, struct sk_buff *skb, + enum ip_conntrack_info ctinfo) +{ + int i = 0; + kuid_t uid; + struct sock *sk = NULL; + struct iphdr *iph = NULL; + const struct file *filp = NULL; + + if (INIT_APP_TYPE == get_app_type(ct)) { + + sk = skb_to_full_sk(skb); + + if (NULL == sk || NULL == sk->sk_socket) { + return false; + } + + filp = sk->sk_socket->file; + + if (NULL == filp) { + return false; + } + + iph = ip_hdr(skb); + + uid = filp->f_cred->fsuid; + + for (i = 1; i < GAME_NUM; i++) { + if (game_info[i].uid) { + if (is_same_app(uid.val, game_info[i].uid)) { + set_app_type(ct, i); + + if (game_mark) { + set_ct_mark(ct, game_mark); + + } else { + set_ct_mark(ct, game_info[i].mark); + } + + return true; + } + } + } + + } else if (get_app_type(ct) > 0 && get_app_type(ct) < GAME_NUM) { + i = get_app_type(ct); + return true; + } + + return false; + +} + +static int detect_game_skb(struct sk_buff *skb) +{ + //struct iphdr *iph = NULL; + struct nf_conn *ct = NULL; + int ret = SLA_SKB_ACCEPT; + enum ip_conntrack_info ctinfo; + + if (oplus_sla_vpn_connected) { + return SLA_SKB_CONTINUE; + } + + ct = nf_ct_get(skb, &ctinfo); + + if (NULL == ct) { + return SLA_SKB_ACCEPT; + } + + if (!is_game_app_skb(ct, skb, ctinfo)) { + return SLA_SKB_CONTINUE; + } + + //TCP and udp need to switch network + ret = SLA_SKB_CONTINUE; + return ret; +} + + +static void detect_white_list_app_skb(struct sk_buff *skb) +{ + int i = 0; + int index = -1; + kuid_t uid; + struct nf_conn *ct = NULL; + enum ip_conntrack_info ctinfo; + struct sock *sk = NULL; + const struct file *filp = NULL; + + ct = nf_ct_get(skb, &ctinfo); + + if (NULL == ct) { + return; + } + + /*when the app type is dual sta app,but the work mode is not + SLA_MODE_DUAL_WIFI, we should detect it is WIFI+CELL white + list app again + */ + if (SLA_MODE_DUAL_WIFI != sla_work_mode && + get_app_type(ct) >= DUAL_STA_APP_BASE) { + set_app_type(ct, INIT_APP_TYPE); + } + + if (INIT_APP_TYPE == get_app_type(ct)) { + sk = skb_to_full_sk(skb); + + if (NULL == sk || NULL == sk->sk_socket) { + return; + } + + filp = sk->sk_socket->file; + + if (NULL == filp) { + return; + } + + uid = filp->f_cred->fsuid; + + for (i = 0; i < white_app_list.count; i++) { + if (white_app_list.uid[i]) { + if (is_same_app(uid.val, white_app_list.uid[i])) { + set_app_type(ct, i + WHITE_APP_BASE); + return; + } + } + } + + /* we need to detect the whether it is dual sta white list app */ + if (SLA_MODE_DUAL_WIFI != sla_work_mode) { + set_app_type(ct, UNKNOW_APP_TYPE); + } + + } else if (get_app_type(ct) >= WHITE_APP_BASE && + get_app_type(ct) < DUAL_STA_APP_BASE) { + /*calc white app cell bytes when sla is not enable, + when the default network is change to cell,we should + disable dual sta from framework + */ + if (oplus_sla_info[CELL_INDEX].if_up) { + if (!oplus_sla_info[MAIN_WLAN].if_up || + oplus_sla_def_net == CELL_INDEX) { + index = get_app_type(ct) - WHITE_APP_BASE; + + if (index < WHITE_APP_NUM) { + white_app_list.cell_bytes_normal[index] += skb->len; + } + } + } + } + + return; +} + +static int mark_game_app_skb(struct nf_conn *ct, struct sk_buff *skb, + enum ip_conntrack_info ctinfo) +{ + int game_index = -1; + struct iphdr *iph = NULL; + u32 ct_mark = 0; + int ret = SLA_SKB_CONTINUE; + int oplus_app_type = get_app_type(ct); + + if (oplus_app_type > 0 && oplus_app_type < GAME_NUM) { + ret = SLA_SKB_ACCEPT; + game_index = oplus_app_type; + + if (GAME_WZRY != game_index && + GAME_CJZC != game_index) { + return ret; + } + + iph = ip_hdr(skb); + + if (iph && + (IPPROTO_UDP == iph->protocol || + IPPROTO_TCP == iph->protocol)) { + + /* For WZRY, switch tcp and udp packets */ + /* + if (GAME_WZRY == game_index && oplus_sla_lobby_status != 1 && + IPPROTO_TCP == iph->protocol) { + return SLA_SKB_ACCEPT; + } + */ + ct_mark = get_ct_mark(ct) & MARK_MASK; + + if (GAME_CJZC == game_index && + IPPROTO_TCP == iph->protocol && + ((XT_STATE_BIT(ctinfo) & XT_STATE_BIT(IP_CT_ESTABLISHED)) || + (XT_STATE_BIT(ctinfo) & XT_STATE_BIT(IP_CT_RELATED)))) { + if (MAIN_WLAN_MARK == ct_mark) { + return SLA_SKB_ACCEPT; + + } else if (CELL_MARK == ct_mark) { + skb->mark = CELL_MARK; + return SLA_SKB_MARKED; + } + } + + if (game_mark) { + skb->mark = game_mark; + + } else { + skb->mark = game_info[game_index].mark; + } + + if (ct_mark && skb->mark && + ct_mark != skb->mark) { + + debug("oplus_sla_game:reset game ct proto= %u,srcport = %d," + "ct dying = %d,ct confirmed = %d,game type = %d,ct mark = %x,skb mark = %x\n", + iph->protocol, ntohs(udp_hdr(skb)->source), + nf_ct_is_dying(ct), nf_ct_is_confirmed(ct), game_index, ct_mark, skb->mark); + + if (!nf_ct_is_dying(ct) && + nf_ct_is_confirmed(ct)) { + nf_ct_kill(ct); + return SLA_SKB_DROP; + + } else { + skb->mark = ct_mark; + ret = SLA_SKB_MARKED; + } + } + + if (!ct_mark) { + //set_ct_mark(ct, game_info[game_index].mark); + set_ct_mark(ct, skb->mark); + } + + ret = SLA_SKB_MARKED; + } + } + + return ret; +} + + +static int sla_mark_skb(struct sk_buff *skb, const struct nf_hook_state *state) +{ + int ret = SLA_SKB_CONTINUE; + //int index = 0; + kuid_t app_uid = {0}; + //u32 ct_mark = 0x0; + struct sock *sk = NULL; + struct nf_conn *ct = NULL; + enum ip_conntrack_info ctinfo; + + //if wlan assistant has change network to cell,do not mark SKB + if (oplus_sla_def_net == CELL_INDEX) { + return NF_ACCEPT; + } + + ct = nf_ct_get(skb, &ctinfo); + + if (NULL == ct) { + return NF_ACCEPT; + } + + /* + * when the wifi is poor,the dns request allways can not rcv respones, + * so please let the dns packet with the cell network mark. + */ + ret = dns_skb_need_sla(ct, skb); + + if (SLA_SKB_ACCEPT == ret) { + return NF_ACCEPT; + + } else if (SLA_SKB_MARKED == ret) { + goto sla_reroute; + } + + if (is_skb_pre_bound(skb) || dst_is_lan_ip(skb)) { + return NF_ACCEPT; + } + + if (SLA_MODE_WIFI_CELL == sla_work_mode && + !is_sla_white_or_game_app(ct, skb)) { + return NF_ACCEPT; + } + + if (SLA_MODE_DUAL_WIFI == sla_work_mode && + !is_dual_sta_white_app(ct, skb, &app_uid)) { + return NF_ACCEPT; + } + + ret = mark_game_app_skb(ct, skb, ctinfo); + + if (SLA_SKB_MARKED == ret) { + goto sla_reroute; + + } else if (SLA_SKB_ACCEPT == ret) { + return NF_ACCEPT; + + } else if (SLA_SKB_DROP == ret) { + return NF_DROP; + } + + if (ctinfo == IP_CT_NEW) { + sk = skb_to_full_sk(skb); + + if (NULL != sk) { +#if 0 + // add for download app stream + ret = mark_download_app(sk, app_uid, ct, skb); + + if (SLA_SKB_MARKED == ret) { + goto sla_reroute; + } + +#endif + // add for video app stream + ret = mark_video_app(sk, app_uid, ct, skb); + + if (SLA_SKB_MARKED == ret) { + goto sla_reroute; + } + + sla_read_lock(); + skb->mark = get_skb_mark_by_weight(); + sla_read_unlock(); + set_ct_mark(ct, skb->mark); + if (oplus_sla_debug) { + debug("skb->mark = %x ct->mark = %x get_ct_mark = %x\n", skb->mark, ct->mark, + get_ct_mark(ct)); + } + } + + } else if ((XT_STATE_BIT(ctinfo) & XT_STATE_BIT(IP_CT_ESTABLISHED)) || + (XT_STATE_BIT(ctinfo) & XT_STATE_BIT(IP_CT_RELATED))) { + + skb->mark = get_ct_mark(ct) & MARK_MASK; + /* + if (oplus_sla_debug) { + debug("skb->mark = %x ct->mark = %x get_ct_mark = %x\n", skb->mark, ct->mark, + get_ct_mark(ct)); + } + */ + } + +//If the mark value of the packet is equal to WLAN0_MARK, no re routing is required + if (MAIN_WLAN_MARK == skb->mark) { + return NF_ACCEPT; + } + +#if 0 + +//calc white list app cell bytes + if (ct->oplus_app_type >= WHITE_APP_BASE && + ct->oplus_app_type < DUAL_STA_APP_BASE) { + ct_mark = ct->mark & MARK_MASK; + + if (CELL_MARK == ct_mark) { + index = ct->oplus_app_type - WHITE_APP_BASE; + + if (index < WHITE_APP_NUM) { + white_app_list.cell_bytes[index] += skb->len; + } + } + } + +#endif + +sla_reroute: + ret = sla_skb_reroute(skb, ct, state); + return ret; + +} +/* +oplus sla hook function, mark skb and rerout skb +*/ +static unsigned int oplus_sla_output_hook(void *priv, + struct sk_buff *skb, + const struct nf_hook_state *state) +{ + int ret = NF_ACCEPT; + int game_ret = NF_ACCEPT; + + game_ret = detect_game_skb(skb); + + if (SLA_SKB_ACCEPT == game_ret) { + goto end_sla_output; + } + + //we need to calc white list app cell bytes when sla not enabled + detect_white_list_app_skb(skb); + + if (oplus_sla_enable_status) { + + ret = sla_mark_skb(skb, state); + + }/* else { + + if (!oplus_sla_screen_on) { + goto end_sla_output; + } + }*/ + +end_sla_output: + //add for android Q statictis tcp tx and tx + //statistics_wlan_tcp_tx_rx(state, skb); + print_stream_info(skb); + return ret; +} + +static int TIMESTAMP_ERROR_THRESHOLD = 10; +static int ts_error_count = 0; +static void handle_timestamp_error_case(struct sk_buff *skb, const struct nf_hook_state *state) +{ + struct sock *sk = NULL; + struct iphdr *iph; + struct tcp_options_received tcp_opt; + const __be32 *ptr; + + if ((iph = ip_hdr(skb)) != NULL && iph->protocol == IPPROTO_TCP) { + sk = skb_to_full_sk(skb); + + if (sk && (!sk_fullsock(sk) || sk->sk_state == TCP_TIME_WAIT || sk->sk_state == TCP_NEW_SYN_RECV)) { + return; + } + + if (NULL != sk) { + struct tcp_sock *tp = tcp_sk(sk); + struct tcphdr *th = tcp_hdr(skb); + + //handle syn + ack + if (NULL != tp && NULL != th && th->ack && th->syn) { + //fast path + memset(&tcp_opt, 0, sizeof(tcp_opt)); + ptr = (const __be32 *)(th + 1); + + if (*ptr == htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) + | (TCPOPT_TIMESTAMP << 8) | TCPOLEN_TIMESTAMP)) { + ptr += 2; + + if (*ptr) { + tcp_opt.rcv_tsecr = ntohl(*ptr) - tp->tsoffset; + tcp_opt.saw_tstamp = 1; + //debug("fast path rcv_tsecr = %u\n", tcp_opt.rcv_tsecr); + } + + }/*else { + //fall back slow path + debug("state->net addr: %p\n", state->net); + debug("sk addr: %p\n", sock_net(sk)); + tcp_parse_options(state->net, skb, &tcp_opt, 0, NULL); + tcp_opt.rcv_tsecr -= tp->tsoffset; + }*/ + /* + if (tcp_opt.saw_tstamp && tcp_opt.rcv_tsecr) { + debug("rcv_tsecr = %u retrans_stamp = %u tcp_time_stamp(tp) = %u ipid = %x\n", + tcp_opt.rcv_tsecr, + tp->retrans_stamp, tcp_time_stamp(tp), ntohs(iph->id)); + } + */ + if (tcp_opt.saw_tstamp && tcp_opt.rcv_tsecr && + !between(tcp_opt.rcv_tsecr, tp->retrans_stamp, tcp_time_stamp(tp))) { + debug("timestamp error count : %d\n", ts_error_count); + ts_error_count ++; + + if (ts_error_count >= TIMESTAMP_ERROR_THRESHOLD) { + debug("TimeStamp error:disable tcp timestamp\n"); + (state->net)->ipv4.sysctl_tcp_timestamps = 0; + ts_error_count = 0; + } + + } else { + if (ts_error_count > 0) { + ts_error_count --; + } + } + } + } + } +} + + +static int oplus_sla_genl_nlmsg_handle(struct sk_buff *skb, + struct genl_info *info); +static const struct genl_ops oplus_sla_genl_ops[] = { + { + .cmd = OPLUS_SLA_CMD_DOWNLINK, + .flags = 0, + .doit = oplus_sla_genl_nlmsg_handle, + .dumpit = NULL, + }, +}; + + +static struct genl_family oplus_sla_genl_family = { + .id = 0, + .hdrsize = 0, + .name = OPLUS_SLA_FAMILY, + .version = OPLUS_SLA_FAMILY_VERSION, + .maxattr = OPLUS_SLA_MSG_MAX, + .ops = oplus_sla_genl_ops, + .n_ops = ARRAY_SIZE(oplus_sla_genl_ops), +}; + +static inline int genl_msg_prepare_usr_msg(u8 cmd, size_t size, pid_t pid, + struct sk_buff **skbp) +{ + struct sk_buff *skb; + /* create a new netlink msg */ + skb = genlmsg_new(size, GFP_ATOMIC); + + if (skb == NULL) { + return -ENOMEM; + } + + /* Add a new netlink message to an skb */ + genlmsg_put(skb, pid, 0, &oplus_sla_genl_family, 0, cmd); + *skbp = skb; + return 0; +} + +static inline int genl_msg_mk_usr_msg(struct sk_buff *skb, int type, void *data, + int len) +{ + int ret; + + /* add a netlink attribute to a socket buffer */ + if ((ret = nla_put(skb, type, len, data)) != 0) { + return ret; + } + + return 0; +} + +/* send to user space */ +static int oplus_sla_send_to_user(int msg_type, char *payload, int payload_len) +{ + int ret = 0; + void *head; + struct sk_buff *skbuff; + size_t size; + + if (!oplus_sla_netlink_pid) { + debug("oplus_sla_netlink_pid == 0!!\n"); + return -1; + } + + /*allocate new buffer cache */ + size = nla_total_size(payload_len); + ret = genl_msg_prepare_usr_msg(OPLUS_SLA_CMD_UPLINK, size, + oplus_sla_netlink_pid, &skbuff); + + if (ret) { + return ret; + } + + ret = genl_msg_mk_usr_msg(skbuff, msg_type, payload, payload_len); + + if (ret) { + kfree_skb(skbuff); + return ret; + } + + head = genlmsg_data(nlmsg_data(nlmsg_hdr(skbuff))); + genlmsg_end(skbuff, head); + + /* send data */ + ret = genlmsg_unicast(&init_net, skbuff, oplus_sla_netlink_pid); + + if (ret < 0) { + printk(KERN_ERR + "oplus_connectivity_sla: oplus_sla_send_to_user, can not unicast skbuff, ret = %d\n", ret); + return -1; + } + + return 0; +} + +static int oplus_sla_set_android_pid(struct sk_buff *skb) +{ + /*apps_monitor_netlink_pid = NETLINK_CB(skb).portid;*/ + struct nlmsghdr *nlhdr = nlmsg_hdr(skb); + oplus_sla_netlink_pid = nlhdr->nlmsg_pid; + debug("oplus_sla_set_android_pid oplus_sla_netlink_pid=%d\n", + oplus_sla_netlink_pid); + return 0; +} + +static int oplus_sla_iface_changed(struct nlattr *nla) +{ + int index = -1; + int up = 0; + char *p; + struct oplus_dev_info *node = NULL; + u32 mark = 0x0; + + int *data = (int *)NLA_DATA(nla); + index = data[0]; + up = data[1]; + p = (char *)(data + 2); + debug("oplus_sla_iface_changed index:%d, up:%d, ifname:%s\n", + index, up, p); + + if (index >= 0 && index < IFACE_NUM) { + if (up) { + sla_write_lock(); + oplus_sla_info[index].if_up = 0; + + if (index == MAIN_WLAN) { + mark = MAIN_WLAN_MARK; + oplus_sla_info[MAIN_WLAN].if_up = 1; + + } else if (index == SECOND_WLAN) { + mark = SECOND_WLAN_MARK; + oplus_sla_info[SECOND_WLAN].if_up = 1; + + } else if (index == CELL_INDEX) { + mark = CELL_MARK; + oplus_sla_info[CELL_INDEX].if_up = 1; + } + + if (p) { + node = &oplus_sla_info[index]; + node->mark = mark; + memcpy(node->dev_name, p, IFACE_LEN); + debug("ifname = %s,ifup = %d\n", node->dev_name, node->if_up); + } + + sla_write_unlock(); + + } else { + sla_write_lock(); + memset(&oplus_sla_info[index], 0x0, sizeof(struct oplus_dev_info)); + sla_write_unlock(); + } + } + + return 0; +} + +static int oplus_sla_set_white_list_app_uid(struct nlattr *nla) +{ + u32 *info = (u32 *)NLA_DATA(nla); + memset(&white_app_list, 0x0, sizeof(struct oplus_white_app_info)); + white_app_list.count = info[0]; + + if (white_app_list.count > 0 && white_app_list.count < WHITE_APP_NUM) { + int i; + + for (i = 0; i < white_app_list.count; i++) { + white_app_list.uid[i] = info[i + 1]; + debug("oplus_sla_set_white_list_app_uid count=%d, uid[%d]=%d\n", + white_app_list.count, i, white_app_list.uid[i]); + } + } + + return 0; +} + +static int oplus_sla_set_dual_wifi_app_uid(struct nlattr *nla) +{ + u32 *info = (u32 *)NLA_DATA(nla); + memset(&dual_wifi_app_list, 0x0, sizeof(struct oplus_dual_sta_info)); + dual_wifi_app_list.count = info[0]; + + if (dual_wifi_app_list.count > 0 + && dual_wifi_app_list.count < DUAL_STA_APP_NUM) { + int i; + + for (i = 0; i < dual_wifi_app_list.count; i++) { + dual_wifi_app_list.uid[i] = info[i + 1]; + debug("set_dual_wifi_app_uid count=%d, uid[%d]=%d\n", + dual_wifi_app_list.count, i, dual_wifi_app_list.uid[i]); + } + } + + return 0; +} + +static int oplus_sla_set_game_app_uid(struct nlattr *nla) +{ + u32 *uidInfo = (u32 *)NLA_DATA(nla); + u32 index = uidInfo[0]; + u32 uid = uidInfo[1]; + + sla_game_write_lock(); + if (index < GAME_NUM) { + game_info[index].uid = uid; + game_info[index].game_type = index; + game_info[index].mark = MAIN_WLAN_MARK; + debug("oplus_sla_set_game_app_uid:index=%d uid=%d\n", index, uid); + } + sla_game_write_unlock(); + + return 0; +} + +static void init_game_info(void) +{ + int i = 0; + + sla_game_write_lock(); + for(i = 1; i < GAME_NUM; i++){ + game_info[i].mark = MAIN_WLAN_MARK; + } + sla_game_write_unlock(); + if(oplus_sla_debug){ + debug("oplus_sla:init_game_online_info\n"); + } +} + +static int oplus_sla_change_game_network(struct nlattr *nla) +{ + u32 *data = (u32 *)NLA_DATA(nla); + u32 game_index = data[0]; + u32 network_index = data[1]; + int game_feed_back[2]; + + sla_game_write_lock(); + if (CELL_INDEX == network_index) { + game_info[game_index].mark = CELL_MARK; + + } else if (WLAN0_INDEX == network_index) { + game_info[game_index].mark = MAIN_WLAN_MARK; + } + sla_game_write_unlock(); + + game_feed_back[0] = game_index; + game_feed_back[1] = network_index; + oplus_sla_send_to_user(OPLUS_SLA_GAME_NETWORK_CHANGED_EVENT, + (char *)game_feed_back, sizeof(game_feed_back)); + debug("game_index = %d network_index = %d \n", game_index, network_index); + return 0; +} + +static int oplus_sla_set_video_app_uid(struct nlattr *nla) +{ + u32 *info = (u32 *)NLA_DATA(nla); + memset(&video_app_list, 0x0, sizeof(struct oplus_dual_sta_info)); + video_app_list.count = info[0]; + + if (video_app_list.count > 0 && video_app_list.count < DUAL_STA_APP_NUM) { + int i; + + for (i = 0; i < video_app_list.count; i++) { + video_app_list.uid[i] = info[i + 1]; + debug("video_app_list count=%d, uid[%d]=%d\n", + video_app_list.count, i, video_app_list.uid[i]); + } + } + + return 0; +} + +static int oplus_sla_enable(struct nlattr *nla) +{ + int *data = (int *)NLA_DATA(nla); + int enable_type = data[0]; + + sla_write_lock(); + + oplus_sla_enable_status = 1; + sla_work_mode = enable_type; + + debug("oplus_sla_enable: enable type = %d\n", enable_type); + oplus_sla_send_to_user(OPLUS_SLA_ENABLED_EVENT, (char *)&enable_type, + sizeof(int)); + + sla_write_unlock(); + return 0; +} + +static int oplus_sla_disable(struct nlattr *nla) +{ + int disable_type = 0; + + int *data = (int *)NLA_DATA(nla); + disable_type = data[0]; + + debug("type[%d] disable,oplus_sla_enable_status[%d],work_mode[%d]\n", + disable_type, oplus_sla_enable_status, sla_work_mode); + + init_game_info(); + sla_write_lock(); + + if (oplus_sla_enable_status && disable_type) { + if (disable_type == sla_work_mode) { + oplus_sla_enable_status = 0; + sla_work_mode = SLA_MODE_INIT; + debug("type[%d] disabled\n", disable_type); + } + + dns_network = 0; + video_app_network = 0; + oplus_sla_send_to_user(OPLUS_SLA_DISABLED_EVENT, (char *)&disable_type, + sizeof(int)); + } + sla_write_unlock(); + return 0; +} + +static int oplus_sla_update_weight(struct nlattr *nla) +{ + int *weight = (int *)NLA_DATA(nla); + sla_write_lock(); + oplus_sla_info[0].weight = weight[0]; + oplus_sla_info[1].weight = weight[1]; + oplus_sla_info[2].weight = weight[2]; + debug("weight: %u:%u:%u\n", oplus_sla_info[0].weight, oplus_sla_info[1].weight, + oplus_sla_info[2].weight); + sla_write_unlock(); + return 0; +} + +static int oplus_sla_change_default_network(struct nlattr *nla) +{ + oplus_sla_def_net = *(u32 *)NLA_DATA(nla); + debug("oplus_sla_change_default_network = %d\n", oplus_sla_def_net); + return 0; +} + +static int oplus_sla_set_kernel_debug(struct nlattr *nla) +{ + oplus_sla_debug = *(u32 *)NLA_DATA(nla); + debug("oplus_sla_set_kernel_debug = %d\n", oplus_sla_debug); + return 0; +} + +static int oplus_sla_change_vpn_state(struct nlattr *nla) +{ + oplus_sla_vpn_connected = *(u32 *)NLA_DATA(nla); + debug("oplus_sla_vpn_connected = %d\n", oplus_sla_vpn_connected); + return 0; +} + +static int oplus_sla_change_video_app_network(struct nlattr *nla) +{ + video_app_network = *(u32 *)NLA_DATA(nla); + debug("video_app_network = %d\n", video_app_network); + return 0; +} + +static int oplus_sla_change_dns_network(struct nlattr *nla) +{ + dns_network = *(u32 *)NLA_DATA(nla); + debug("dns_network = %d\n", dns_network); + return 0; +} + +static int oplus_sla_genl_nlmsg_handle(struct sk_buff *skb, + struct genl_info *info) +{ + int ret = 0; + struct nlmsghdr *nlhdr; + struct genlmsghdr *genlhdr; + struct nlattr *nla; + + nlhdr = nlmsg_hdr(skb); + genlhdr = nlmsg_data(nlhdr); + nla = genlmsg_data(genlhdr); + + if (oplus_sla_debug) { + debug("oplus_sla_genl_nlmsg_handle, the nla->nla_type = %u, len = %u\n", + nla->nla_type, nla->nla_len); + } + + switch (nla->nla_type) { + case OPLUS_SLA_CMD_SET_ANDROID_PID: + ret = oplus_sla_set_android_pid(skb); + break; + + case OPLUS_SLA_CMD_IFACE_CHANGED: + ret = oplus_sla_iface_changed(nla); + break; + + case OPLUS_SLA_CMD_ENABLE: + ret = oplus_sla_enable(nla); + break; + + case OPLUS_SLA_CMD_DISABLE: + ret = oplus_sla_disable(nla); + break; + + case OPLUS_SLA_CMD_SET_WHITE_LIST_APP: + ret = oplus_sla_set_white_list_app_uid(nla); + break; + + case OPLUS_SLA_CMD_SET_DUAL_STA_LIST_APP: + ret = oplus_sla_set_dual_wifi_app_uid(nla); + break; + + case OPLUS_SLA_CMD_SET_VIDEO_LIST_APP: + ret = oplus_sla_set_video_app_uid(nla); + break; + + case OPLUS_SLA_CMD_SET_GAME_LIST_APP: + ret = oplus_sla_set_game_app_uid(nla); + break; + + case OPLUS_SLA_CMD_CHANGE_GAME_NETWORK: + ret = oplus_sla_change_game_network(nla); + break; + + case OPLUS_SLA_CMD_UPDATE_WEIGHT: + ret = oplus_sla_update_weight(nla); + break; + + case OPLUS_SLA_CMD_CHANGE_DEFAULT_NETWORK: + ret = oplus_sla_change_default_network(nla); + break; + + case OPLUS_SLA_CMD_SET_KERNEL_DEBUG: + ret = oplus_sla_set_kernel_debug(nla); + break; + + case OPLUS_SLA_CMD_CHANGE_VPN_STATE: + ret = oplus_sla_change_vpn_state(nla); + break; + + case OPLUS_SLA_CMD_CHANGE_VIDEO_APP_NETWORK: + ret = oplus_sla_change_video_app_network(nla); + break; + + case OPLUS_SLA_CMD_CHANGE_DNS_NETWORK: + ret = oplus_sla_change_dns_network(nla); + break; + + default: + break; + } + + return ret; +} + +static unsigned int oplus_sla_input_hook(void *priv, + struct sk_buff *skb, + const struct nf_hook_state *state) +{ + handle_timestamp_error_case(skb, state); + return NF_ACCEPT; +} + +static struct nf_hook_ops oplus_sla_ops[] __read_mostly = { + { + .hook = oplus_sla_output_hook, + .pf = NFPROTO_IPV4, + .hooknum = NF_INET_LOCAL_OUT, + //must be here,for dns packet will do DNAT at mangle table with skb->mark + .priority = NF_IP_PRI_CONNTRACK + 1, + }, + { + .hook = oplus_sla_input_hook, + .pf = NFPROTO_IPV4, + .hooknum = NF_INET_LOCAL_IN, + .priority = NF_IP_PRI_FILTER + 1, + }, +}; + +static struct ctl_table oplus_sla_sysctl_table[] = { + { + .procname = "oplus_sla_enable", + .data = &oplus_sla_enable_status, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec, + }, + { + .procname = "oplus_sla_debug", + .data = &oplus_sla_debug, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec, + }, + { + .procname = "oplus_sla_vpn_connected", + .data = &oplus_sla_vpn_connected, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec, + }, + { + .procname = "game_mark", + .data = &game_mark, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec, + }, + { } +}; + +static int oplus_sla_sysctl_init(void) +{ + oplus_sla_table_hrd = register_net_sysctl(&init_net, "net/oplus_sla", + oplus_sla_sysctl_table); + return oplus_sla_table_hrd == NULL ? -ENOMEM : 0; +} + + +static int oplus_sla_genl_init(void) +{ + int ret; + ret = genl_register_family(&oplus_sla_genl_family); + + if (ret) { + debug("genl_register_family:%s error,ret = %d\n", OPLUS_SLA_FAMILY, ret); + return ret; + + } else { + debug("genl_register_family complete, id = %d!\n", oplus_sla_genl_family.id); + } + + return 0; +} + +static void oplus_sla_genl_fini(void) +{ + + genl_unregister_family(&oplus_sla_genl_family); +} + +static int __init oplus_sla_init(void) +{ + int ret = 0; + rwlock_init(&sla_lock); + rwlock_init(&sla_game_lock); + + ret = oplus_sla_genl_init(); + + if (ret < 0) { + debug(" module can not init sla netlink.\n"); + } + + ret |= oplus_sla_sysctl_init(); + ret |= nf_register_net_hooks(&init_net, oplus_sla_ops, + ARRAY_SIZE(oplus_sla_ops)); + + debug(" enter.\n"); + return ret; +} + +static void __exit oplus_sla_exit(void) +{ + debug(" exit.\n"); + oplus_sla_genl_fini(); + + if (oplus_sla_table_hrd) { + unregister_net_sysctl_table(oplus_sla_table_hrd); + } + + nf_unregister_net_hooks(&init_net, oplus_sla_ops, ARRAY_SIZE(oplus_sla_ops)); +} + +module_init(oplus_sla_init); +module_exit(oplus_sla_exit); +MODULE_LICENSE("GPL v2"); diff --git a/net/oplus_dhcp/Makefile b/net/oplus_dhcp/Makefile new file mode 100644 index 000000000000..1dd10a081df1 --- /dev/null +++ b/net/oplus_dhcp/Makefile @@ -0,0 +1,23 @@ +#/************************************************************************************ +#** File: - Makefile +#** VENDOR_EDIT +#** Copyright (C), 2008-2020, OPLUS Mobile Comm Corp., Ltd +#** +#** Description: +#** 1. Add for dhcp conflict +#** +#** Version: 1.0 +#** Date : 2020-05-09 +#** TAG : OPLUS_FEATURE_DHCP_CONFLICT +#** +#** ---------------------Revision History: --------------------- +#** +#** --------------------------------------------------------------- +#** +#************************************************************************************/ + +# +# Makefile for the netfilter modules on top of IPv4. +# +KBUILD_CFLAGS += -Wno-unused-variable -Wno-unused-function +obj-y += oplus_dhcp.o diff --git a/net/oplus_dhcp/oplus_dhcp.c b/net/oplus_dhcp/oplus_dhcp.c new file mode 100644 index 000000000000..d63da5a66294 --- /dev/null +++ b/net/oplus_dhcp/oplus_dhcp.c @@ -0,0 +1,658 @@ +/************************************************************************************ +** File: - oplus_dhcp.c +** VENDOR_EDIT +** Copyright (C), 2008-2020, OPLUS Mobile Comm Corp., Ltd +** +** Description: +** 1. Add for dhcp conflict +** +** Version: 1.0 +** Date : 2020-05-09 +** TAG : OPLUS_FEATURE_WIFI_DHCP +** +** ---------------------Revision History: --------------------- +** +** --------------------------------------------------------------- +** +************************************************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* packet ops */ +#define BOOTP_REQUEST 1 +#define BOOTP_REPLY 2 + +/* DHCP message types */ +#define DHCPDISCOVER 1 +#define DHCPOFFER 2 +#define DHCPREQUEST 3 +#define DHCPDECLINE 4 +#define DHCPACK 5 +#define DHCPNAK 6 +#define DHCPRELEASE 7 +#define DHCPINFORM 8 + +#define NONE cpu_to_be32(INADDR_NONE) +#define ANY cpu_to_be32(INADDR_ANY) + +#define DUP_SERVER_COUNT 2 +#define IFACE_COUNT 2 +#define OPLUS_DHCP_MAX_SERVERS 4 + +#define MAIN_WLAN_IFACE "wlan0" +#define SECOND_WLAN_IFACE "wlan1" + +#define MAIN_WLAN_INDEX 0 +#define SECOND_WLAN_INDEX 1 + +#define LOG_TAG "[oplus_dhcp] %s line:%d " +#define debug(fmt,args...) printk(LOG_TAG fmt,__FUNCTION__,__LINE__,##args) + +#define IP_MASK(addr) ((unsigned char *)&addr)[0], \ + ((unsigned char *)&addr)[1], \ + ((unsigned char *)&addr)[2] + +#define MAC_MASK(addr) addr[0], \ + addr[1], \ + addr[4], \ + addr[5] + +extern int (*handle_dhcp)(struct sock *sk, struct sk_buff *skb, struct net_device *dev, struct packet_type *pt); +static bool oplus_dhcp_get_notify_state(struct net_device *dev); + +/*NLMSG_MIN_TYPE is 0x10,so we start at 0x11*/ +enum{ + OPLUS_DHCP_SET_ANDROID_PID = 0x11, + OPLUS_DHCP_L2CONNECTED_CMD =0x12, + OPLUS_DHCP_NOTIFY_DUP_OFFER_EVENT = 0x13, + OPLUS_DHCP_INTERNET_ACCESS_CMD = 0x14, + OPLUS_DHCP_L2DISCONNECTED_CMD = 0x15, + OPLUS_DHCP_MAX = 0x16, +}; + +/* dhcp packet */ +struct dhcp_pkt { /* BOOTP packet format */ + struct iphdr iph; /* IP header */ + struct udphdr udph; /* UDP header */ + u8 op; /* 1=request, 2=reply */ + u8 htype; /* HW address type */ + u8 hlen; /* HW address length */ + u8 hops; /* Used only by gateways */ + __be32 xid; /* Transaction ID */ + __be16 secs; /* Seconds since we started */ + __be16 flags; /* Just what it says */ + __be32 client_ip; /* Client's IP address if known */ + __be32 your_ip; /* Assigned IP address */ + __be32 server_ip; /* (Next, e.g. NFS) Server's IP address */ + __be32 relay_ip; /* IP address of BOOTP relay */ + u8 hw_addr[16]; /* Client's HW address */ + u8 serv_name[64]; /* Server host name */ + u8 boot_file[128]; /* Name of boot file */ + u8 exten[312]; /* DHCP options / BOOTP vendor extensions */ +}; + + +struct dhcp_server { + int wlan_index; // -1 for unset item + u8 server_mac[6]; + unsigned int server_addr; +}; + +/* + * black list and white list offer, we only need one for each interface + * so we got one for each interface index + */ +struct dhcp_server oplus_dhcp_drop_list[IFACE_COUNT]; +struct dhcp_server oplus_dhcp_expect_list[IFACE_COUNT]; +static bool do_notify[IFACE_COUNT] = {false}; + +static DEFINE_MUTEX(oplus_dhcp_netlink_mutex); +static struct ctl_table_header *oplus_dhcp_hooks_table_hrd; + +static rwlock_t dhcp_hooks_lock; + +static u32 dhcp_hooks_debug = 0; + +// user space pid +static u32 oplus_dhcp_pid = 0; + +//kernel sock +static struct sock *oplus_dhcp_sock; + +/* send to user space */ +static int oplus_dhcp_send_to_user(int msg_type, char *payload, int payload_len) +{ + int ret = 0; + struct sk_buff *skbuff; + struct nlmsghdr *nlh; + + /*allocate new buffer cache */ + skbuff = alloc_skb(NLMSG_SPACE(payload_len), GFP_ATOMIC); + if (skbuff == NULL) { + printk("oplus_nf_hooks_netlink: skbuff alloc_skb failed\n"); + return -1; + } + + /* fill in the data structure */ + nlh = nlmsg_put(skbuff, 0, 0, msg_type, NLMSG_ALIGN(payload_len), 0); + if (nlh == NULL) { + printk("oplus_nf_hooks_netlink:nlmsg_put failaure\n"); + nlmsg_free(skbuff); + return -1; + + } + + //compute nlmsg length + nlh->nlmsg_len = NLMSG_HDRLEN + NLMSG_ALIGN(payload_len); + + if(NULL != payload){ + memcpy((char *)NLMSG_DATA(nlh),payload,payload_len); + } + + /* set control field,sender's pid */ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,7,0)) + NETLINK_CB(skbuff).pid = 0; +#else + NETLINK_CB(skbuff).portid = 0; +#endif + + NETLINK_CB(skbuff).dst_group = 0; + + /* send data */ + if(oplus_dhcp_pid){ + ret = netlink_unicast(oplus_dhcp_sock, skbuff, oplus_dhcp_pid, MSG_DONTWAIT); + } else { + printk(KERN_ERR "oplus_dhcp_hooks_netlink: can not unicast skbuff, oplus_dhcp_pid=0\n"); + kfree_skb(skbuff); + } + if(ret < 0){ + printk(KERN_ERR "oplus_dhcp_hooks_netlink: can not unicast skbuff,ret = %d\n", ret); + return 1; + } + + return 0; +} + +struct notify_offer { + u32 index; + u32 server_addr; + char server_mac[ETH_ALEN]; +}; + +static void send_dhcp_offer_packet_to_userspace(char *wlan_iface, __be32 server_addr, char *server_mac) { + struct notify_offer payload; + int index = MAIN_WLAN_INDEX; + + debug("%s, %u.%u.%u.***, %02x:%02x:***:***:%02x:%02x\n", wlan_iface, IP_MASK(server_addr), MAC_MASK(server_mac)); + if (wlan_iface != NULL) { + if (0 == memcmp(wlan_iface, MAIN_WLAN_IFACE,strlen(MAIN_WLAN_IFACE))) { + index = MAIN_WLAN_INDEX; + } else if (0 == memcmp(wlan_iface, SECOND_WLAN_IFACE, strlen(SECOND_WLAN_IFACE))) { + index = SECOND_WLAN_INDEX; + } + } + payload.index = index; + payload.server_addr = server_addr; + memcpy(payload.server_mac, server_mac, ETH_ALEN); + oplus_dhcp_send_to_user(OPLUS_DHCP_NOTIFY_DUP_OFFER_EVENT,(char *)&payload,sizeof(payload)); +} + +/* + * get wlan index, return -1 for not found + */ +static int get_iface_index(char *dev_name) { + if (0 == memcmp(dev_name, MAIN_WLAN_IFACE,strlen(MAIN_WLAN_IFACE))) { + return MAIN_WLAN_INDEX; + } + if (0 == memcmp(dev_name, SECOND_WLAN_IFACE, strlen(SECOND_WLAN_IFACE))) { + return SECOND_WLAN_INDEX; + } + return -1; // not found +} + +/* + * @return true, drop packet + * @return false, allow packet + */ +static bool blackwhite_list_match(struct net_device *dev, __be32 server_id) { + bool is_list_empty = true; + int wlan_index; + + wlan_index = get_iface_index(dev->name); + // ignore all pkts come from interface which is not in our list + if (wlan_index < 0 || wlan_index >= IFACE_COUNT) { + return false; + } + + read_lock_bh(&dhcp_hooks_lock); + // white list first + if (oplus_dhcp_expect_list[wlan_index].wlan_index >= 0) { + is_list_empty = false; + if (oplus_dhcp_expect_list[wlan_index].server_addr == server_id) { + debug("allow white address %u.%u.%u.*** on %s\n", IP_MASK(server_id), dev->name); + read_unlock_bh(&dhcp_hooks_lock); + return false; + } + } + // white list not empty, drop all pkts not matched + if (!is_list_empty) { + read_unlock_bh(&dhcp_hooks_lock); + return true; + } + // then blacklist, only drop ptks in it + if (oplus_dhcp_drop_list[wlan_index].wlan_index >= 0) { + if (oplus_dhcp_drop_list[wlan_index].server_addr == server_id) { + debug("drop black address %u.%u.%u.*** on %s\n", IP_MASK(server_id), dev->name); + read_unlock_bh(&dhcp_hooks_lock); + return true; + } + } + read_unlock_bh(&dhcp_hooks_lock); + return false; +} +static int handle_dhcp_packet(struct sock *sk, struct sk_buff *skb, struct net_device *dev, struct packet_type *pt) { + struct dhcp_pkt *b; + struct iphdr *iph; + int len, ext_len; + + /* + * To be more fast, We first ignore non-raw socket and + * non-ETH_P_IP packet types, such as ipv6 + * Note: ETH_P_IP should be sync with raw socket in DhcpClient.java + */ + if (sk->sk_type != SOCK_RAW || pt->type != htons(ETH_P_IP)) + goto ignore; + + b = (struct dhcp_pkt *)skb_network_header(skb); + iph = &b->iph; + if (iph->ihl != 5 || iph->version != 4 || iph->protocol != IPPROTO_UDP) + goto ignore; + + /* Fragments are not supported */ + if (ip_is_fragment(iph)) { + net_err_ratelimited("DHCP/BOOTP: Ignoring fragmented reply\n"); + goto ignore; + } + + if (skb->len < ntohs(iph->tot_len)) + goto ignore; + + if (ip_fast_csum((char *) iph, iph->ihl)) + goto ignore; + + if (b->udph.source != htons(67) || b->udph.dest != htons(68)) + goto ignore; + + if (ntohs(iph->tot_len) < ntohs(b->udph.len) + sizeof(struct iphdr)) + goto ignore; + + len = ntohs(b->udph.len) - sizeof(struct udphdr); + ext_len = len - (sizeof(*b) - + sizeof(struct iphdr) - + sizeof(struct udphdr) - + sizeof(b->exten)); + if (ext_len < 0) + goto ignore; + + /* Ok the front looks good, make sure we can get at the rest. */ + if (!pskb_may_pull(skb, skb->len)) + goto ignore; + + b = (struct dhcp_pkt *)skb_network_header(skb); + iph = &b->iph; + + if (b->op != BOOTP_REPLY) { + debug("handle_dhcp_packet: not A reply message"); + goto ignore; + } + + /* Parse extensions */ + if (ext_len >= 4 ) { + u8 *end = (u8 *) b + ntohs(b->iph.tot_len); + u8 *ext; + __be32 server_id = NONE; + int mt = 0; + + ext = &b->exten[4]; + while (ext < end && *ext != 0xff) { + u8 *opt = ext++; + if (*opt == 0) /* Padding */ + continue; + ext += *ext + 1; + if (ext >= end) + break; + switch (*opt) { + case 53: /* Message type */ + if (opt[1]) + mt = opt[2]; + break; + case 54: /* Server ID (IP address) */ + if (opt[1] >= 4) + memcpy(&server_id, opt + 2, 4); + break; + } + } + + switch (mt) { + case DHCPOFFER: + case DHCPNAK: + case DHCPACK: + if (memcmp(dev->dev_addr,b->hw_addr,dev->addr_len) != 0) { + debug("this packet is not for us"); + goto ignore; + } + + // notify offers + if (oplus_dhcp_get_notify_state(dev)) { + char server_mac[ETH_ALEN] = {0}; + + memcpy(server_mac, eth_hdr(skb)->h_source, ETH_ALEN); + send_dhcp_offer_packet_to_userspace(dev->name, server_id, server_mac); + } + if (blackwhite_list_match(dev, server_id)) { + return 1; + } + break; + default: + break; + } + } +ignore: + return 0; + +} + +/* + * record mode, ignore expected offer list and drop offer list + * just notify offers to user space + */ +static int oplus_dhcp_start_notify_offers(u32 if_index) +{ + if (if_index >= IFACE_COUNT) + return 0; + + write_lock_bh(&dhcp_hooks_lock); + do_notify[if_index] = true; + write_unlock_bh(&dhcp_hooks_lock); + return 0; +} + +static bool oplus_dhcp_get_notify_state(struct net_device *dev) { + int wlan_index; + bool state; + + wlan_index = get_iface_index(dev->name); + // ignore all pkts come from interface which is not in our list + if (wlan_index < 0 || wlan_index >= IFACE_COUNT) { + return false; + } + read_lock_bh(&dhcp_hooks_lock); + state = do_notify[wlan_index]; + read_unlock_bh(&dhcp_hooks_lock); + return state; +} +static int oplus_dhcp_stop_notify_offers(u32 if_index) +{ + if (if_index >= IFACE_COUNT) + return 0; + + write_lock_bh(&dhcp_hooks_lock); + do_notify[if_index] = false; + write_unlock_bh(&dhcp_hooks_lock); + return 0; +} + +/* + * @param clear: set if we need clear the list on interface @if_index + */ +static int oplus_dhcp_set_drop_offer(u32 if_index, __be32 offer, bool clear) +{ + struct dhcp_server *p, *n; + + if (if_index >= IFACE_COUNT) + return 0; + + write_lock_bh(&dhcp_hooks_lock); + if (clear) { + oplus_dhcp_drop_list[if_index].wlan_index = -1; + oplus_dhcp_drop_list[if_index].server_addr = 0; + write_unlock_bh(&dhcp_hooks_lock); + return 0; + } + oplus_dhcp_drop_list[if_index].wlan_index = if_index; + oplus_dhcp_drop_list[if_index].server_addr = offer; + write_unlock_bh(&dhcp_hooks_lock); + return 0; +} + + +static int oplus_dhcp_set_expect_offer(u32 if_index, __be32 offer, bool clear) +{ + struct dhcp_server *p, *n; + + if (if_index >= IFACE_COUNT) + return 0; + + write_lock_bh(&dhcp_hooks_lock); + if (clear) { + oplus_dhcp_expect_list[if_index].wlan_index = -1; + oplus_dhcp_expect_list[if_index].server_addr = 0; + write_unlock_bh(&dhcp_hooks_lock); + return 0; + } + oplus_dhcp_expect_list[if_index].wlan_index = if_index; + oplus_dhcp_expect_list[if_index].server_addr = offer; + write_unlock_bh(&dhcp_hooks_lock); + return 0; +} + + +static int oplus_dhcp_set_android_pid(struct sk_buff *skb) +{ + oplus_dhcp_pid = NETLINK_CB(skb).portid; + debug("oplus_dhcp_set_android_pid pid=%d\n", oplus_dhcp_pid); + return 0; +} + +static int oplus_dhcp_l2connected_cmd(struct nlmsghdr *nlh) +{ + u32 *data = (u32 *)NLMSG_DATA(nlh); + u32 index = data[0]; + u32 dup_dhcp = data[1]; + __be32 server_addr = data[2]; + + debug("iface_index = %u, dup_dhcp = %u, server_addr=%u.%u.%u.***\n", index, dup_dhcp, IP_MASK(server_addr)); + oplus_dhcp_start_notify_offers(index); + if (!dup_dhcp) { + oplus_dhcp_set_drop_offer(index, 0, true); + oplus_dhcp_set_expect_offer(index, 0, true); + } else { + oplus_dhcp_set_drop_offer(index, 0, true); + oplus_dhcp_set_expect_offer(index, server_addr, false); + } + return 0; +} + +static int oplus_dhcp_internet_access_cmd(struct nlmsghdr *nlh) +{ + u32 *data = (u32 *)NLMSG_DATA(nlh); + u32 index = data[0]; + u32 internet_access = data[1]; + __be32 server_addr = data[2]; + + debug("iface_index = %u, internet_access = %u, server_addr=%u.%u.%u.***\n", index, internet_access, IP_MASK(server_addr)); + // no internet access, so drop address + if (!internet_access) { + oplus_dhcp_start_notify_offers(index); + oplus_dhcp_set_expect_offer(index, 0, true); + oplus_dhcp_set_drop_offer(index, server_addr, false); + } else { + // we have internet access, stops everything + oplus_dhcp_stop_notify_offers(index); + oplus_dhcp_set_drop_offer(index, 0, true); + oplus_dhcp_set_expect_offer(index, 0, true); + } + return 0; +} + +static int oplus_dhcp_l2disconnected_cmd(struct nlmsghdr *nlh) +{ + u32 *data = (u32 *)NLMSG_DATA(nlh); + u32 index = data[0]; + + oplus_dhcp_stop_notify_offers(index); + oplus_dhcp_set_drop_offer(index, 0, true); + oplus_dhcp_set_expect_offer(index, 0, true); + + return 0; +} + +static int oplus_dhcp_netlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, struct netlink_ext_ack *extack) +{ + int ret = 0; + u32 portid = NETLINK_CB(skb).portid; + + + if (nlh->nlmsg_type == OPLUS_DHCP_SET_ANDROID_PID) { + return oplus_dhcp_set_android_pid(skb); + } + // only recv msg from target pid + if (portid != oplus_dhcp_pid) { + return ret; + } + switch (nlh->nlmsg_type) { + case OPLUS_DHCP_L2CONNECTED_CMD: + ret = oplus_dhcp_l2connected_cmd(nlh); + break; + case OPLUS_DHCP_L2DISCONNECTED_CMD: + ret = oplus_dhcp_l2disconnected_cmd(nlh); + break; + case OPLUS_DHCP_INTERNET_ACCESS_CMD: + ret = oplus_dhcp_internet_access_cmd(nlh); + break; + default: + return -EINVAL; + } + + return ret; +} + + +static void oplus_dhcp_netlink_rcv(struct sk_buff *skb) +{ + mutex_lock(&oplus_dhcp_netlink_mutex); + netlink_rcv_skb(skb, &oplus_dhcp_netlink_rcv_msg); + mutex_unlock(&oplus_dhcp_netlink_mutex); +} + +static int oplus_dhcp_netlink_init(void) +{ + struct netlink_kernel_cfg cfg = { + .input = oplus_dhcp_netlink_rcv, + }; + + oplus_dhcp_sock = netlink_kernel_create(&init_net, NETLINK_OPLUS_DHCP, &cfg); + return oplus_dhcp_sock == NULL ? -ENOMEM : 0; +} + +static void oplus_dhcp_netlink_exit(void) +{ + netlink_kernel_release(oplus_dhcp_sock); + oplus_dhcp_sock = NULL; +} + + +static struct ctl_table oplus_dhcp_hooks_sysctl_table[] = { + { + .procname = "dhcp_hooks_debug", + .data = &dhcp_hooks_debug, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec, + }, + { } +}; + +static int oplus_dhcp_hooks_sysctl_init(void) +{ + oplus_dhcp_hooks_table_hrd = register_net_sysctl(&init_net, "net/oplus_dhcp_hooks", + oplus_dhcp_hooks_sysctl_table); + return oplus_dhcp_hooks_table_hrd == NULL ? -ENOMEM : 0; +} + +static void oplus_dhcp_hooks_sysctl_fini(void) +{ + if(oplus_dhcp_hooks_table_hrd){ + unregister_net_sysctl_table(oplus_dhcp_hooks_table_hrd); + oplus_dhcp_hooks_table_hrd = NULL; + } +} + +static int __init oplus_dhcp_init(void) +{ + int ret = 0; + int i; + rwlock_init(&dhcp_hooks_lock); + + memset(oplus_dhcp_drop_list, 0, sizeof(struct dhcp_server) * IFACE_COUNT); + memset(oplus_dhcp_expect_list, 0, sizeof(struct dhcp_server) * IFACE_COUNT); + /* set wlan_index = -1 to init black white list */ + for(i = 0; i < IFACE_COUNT; i++) { + oplus_dhcp_set_drop_offer(i, 0, true); + oplus_dhcp_set_expect_offer(i, 0, true); + oplus_dhcp_stop_notify_offers(i); + } + + ret = oplus_dhcp_netlink_init(); + if (ret < 0) { + debug("oplus_dhcp_init module failed to init netlink.\n"); + } + + ret = oplus_dhcp_hooks_sysctl_init(); + if (ret < 0) { + debug("oplus_dhcp_init module failed to init sysctl.\n"); + } + + handle_dhcp = handle_dhcp_packet; + + return ret; +} + +static void __exit oplus_dhcp_fini(void) +{ + handle_dhcp = NULL; + + oplus_dhcp_hooks_sysctl_fini(); + + oplus_dhcp_netlink_exit(); +} + +module_init(oplus_dhcp_init); +module_exit(oplus_dhcp_fini); + diff --git a/net/oplus_ipv6/Makefile b/net/oplus_ipv6/Makefile new file mode 100644 index 000000000000..bbfc71a77db9 --- /dev/null +++ b/net/oplus_ipv6/Makefile @@ -0,0 +1,4 @@ +# +# Makefile for the modules on optimize of IPv6. +# +obj-y += oplus_ipv6_rto.o diff --git a/net/oplus_ipv6/oplus_ipv6_rto.c b/net/oplus_ipv6/oplus_ipv6_rto.c new file mode 100644 index 000000000000..0cb7dcbb2649 --- /dev/null +++ b/net/oplus_ipv6/oplus_ipv6_rto.c @@ -0,0 +1,263 @@ +/****************************************************************************** +** Copyright (C), 2019-2029, OPLUS Mobile Comm Corp., Ltd +** VENDOR_EDIT, All rights reserved. +** File: - oplus_ipv6_rto.c +** Description: ipv6 optimize +** +** Version: 1.0 +** Date : 2020/09/14 +** TAG: OPLUS_FEATURE_IPV6_OPTIMIZE +** ------------------------------- Revision History: ---------------------------- +** +** ------------------------------------------------------------------------------ + *******************************************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define KLOGD(format, ...) { \ + if (oplus_ipv6_rto_debug) {\ + printk("%s[%d]: ", __func__, __LINE__);\ + printk(format, ##__VA_ARGS__);\ + }\ +} + +#define KLOGE(format, ...) { \ + printk("Error %s[%d]: ", __func__, __LINE__);\ + printk(format, ##__VA_ARGS__);\ +} + +#define IPV6_RTO_ENABLED 1 +#define IPV6_RTO_DISABLED 0 + +enum{ + IPV6_RTO_ENABLE = 0x101, + IPV6_RTO_DISABLE = 0x102, + IPV6_RTO_UID_NOTIFY = 0x103, + IPV6_RTO_PID_NOTIFY = 0x104, + IPV6_RTO_DEBUG = 0x105, + IPV4_RTO_UID_NOTIFY = 0x106 +}; + +struct oplus_ipv6_rto_info{ + struct in6_addr v6_saddr; + unsigned short sk_uid; +}; + +struct oplus_ipv4_rto_info{ + unsigned int v4_saddr; + unsigned short sk_uid; +}; + +static int oplus_ipv6_rto_enable; +static int oplus_ipv6_rto_debug = 1; +static volatile u32 oplus_ipv6_rto_pid; +static struct sock *oplus_ipv6_rto_sock; +static DEFINE_MUTEX(ipv6_rto_netlink_mutex); + + +static int oplus_ipv6_rto_get_pid(struct sk_buff *skb,struct nlmsghdr *nlh) +{ + oplus_ipv6_rto_pid = NETLINK_CB(skb).portid; + KLOGD("oplus_ipv6_rto_netlink:get oplus_ipv6_rto_pid = %u\n", oplus_ipv6_rto_pid); + return 0; +} + +static int ipv6_rto_netlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, struct netlink_ext_ack *extack) +{ + int ret = 0; + + switch (nlh->nlmsg_type) { + case IPV6_RTO_ENABLE: + if(!oplus_ipv6_rto_enable) { + oplus_ipv6_rto_enable = IPV6_RTO_ENABLED; + } + break; + case IPV6_RTO_DISABLE: + if(oplus_ipv6_rto_enable) { + oplus_ipv6_rto_enable = IPV6_RTO_DISABLED; + } + break; + case IPV6_RTO_PID_NOTIFY: + ret = oplus_ipv6_rto_get_pid(skb, nlh); + break; + default: + return -EINVAL; + } + + return ret; +} + +static int oplus_ipv6_rto_send_to_user(int msg_type, char *payload, int payload_len) +{ + int ret = 0; + struct sk_buff *skbuff; + struct nlmsghdr *nlh; + + if (!oplus_ipv6_rto_pid) { + KLOGE("oplus_ipv6_rto_netlink: oplus_ipv6_rto_pid == 0!!\n"); + return -1; + } + + /*allocate new buffer cache */ + skbuff = alloc_skb(NLMSG_SPACE(payload_len), GFP_ATOMIC); + if (skbuff == NULL) { + KLOGE("oplus_ipv6_rto_netlink: skbuff alloc_skb failed\n"); + return -1; + } + + /* fill in the data structure */ + nlh = nlmsg_put(skbuff, 0, 0, msg_type, NLMSG_ALIGN(payload_len), 0); + if (nlh == NULL) { + KLOGE("oplus_ipv6_rto_netlink:nlmsg_put failaure\n"); + nlmsg_free(skbuff); + return -1; + } + + //compute nlmsg length + nlh->nlmsg_len = NLMSG_HDRLEN + NLMSG_ALIGN(payload_len); + if(NULL != payload){ + memcpy((char *)NLMSG_DATA(nlh), payload, payload_len); + } + + /* set control field,sender's pid */ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,7,0)) + NETLINK_CB(skbuff).pid = 0; +#else + NETLINK_CB(skbuff).portid = 0; +#endif + NETLINK_CB(skbuff).dst_group = 0; + + /* send data */ + ret = netlink_unicast(oplus_ipv6_rto_sock, skbuff, oplus_ipv6_rto_pid, MSG_DONTWAIT); + if(ret < 0){ + KLOGE("oplus_ipv6_rto_netlink: can not unicast skbuff,ret = %d\n", ret); + return -1; + } + return 0; +} + + +int ipv6_rto_encounter(kuid_t uid, struct in6_addr v6_saddr) +{ + struct oplus_ipv6_rto_info rto_info; + + if (uid.val <= 0) + { + KLOGE("Invalid uid\n"); + return -1; + } + KLOGD("ipv6 RTO at uid: %d", uid.val); + + if (!oplus_ipv6_rto_enable) + { + KLOGD("oplus_ipv6_rto is disabled.\n"); + return -1; + } + + rto_info.sk_uid = uid.val; + rto_info.v6_saddr = v6_saddr; + oplus_ipv6_rto_send_to_user(IPV6_RTO_UID_NOTIFY, (char*)(&rto_info), sizeof(struct oplus_ipv6_rto_info)); + memset(&rto_info, 0x0, sizeof(struct oplus_ipv6_rto_info)); + return 0; +} + +EXPORT_SYMBOL(ipv6_rto_encounter); + +int ipv4_rto_encounter(kuid_t uid, unsigned int v4_saddr) +{ + struct oplus_ipv4_rto_info rto_info; + + if (uid.val <= 0) + { + KLOGE("Invalid uid\n"); + return -1; + } + KLOGD("ipv4 RTO at uid: %d", uid.val); + + if (!oplus_ipv6_rto_enable) + { + KLOGD("oplus_ipv6_rto is disabled.\n"); + return -1; + } + + rto_info.sk_uid = uid.val; + rto_info.v4_saddr = v4_saddr; + oplus_ipv6_rto_send_to_user(IPV4_RTO_UID_NOTIFY, (char*)(&rto_info), sizeof(struct oplus_ipv4_rto_info)); + memset(&rto_info, 0x0, sizeof(struct oplus_ipv4_rto_info)); + return 0; +} + +EXPORT_SYMBOL(ipv4_rto_encounter); + +static void ipv6_rto_netlink_rcv(struct sk_buff *skb) +{ + mutex_lock(&ipv6_rto_netlink_mutex); + netlink_rcv_skb(skb, &ipv6_rto_netlink_rcv_msg); + mutex_unlock(&ipv6_rto_netlink_mutex); +} + +static int oplus_ipv6_rto_netlink_init(void) +{ + struct netlink_kernel_cfg cfg = { + .input = ipv6_rto_netlink_rcv, + }; + oplus_ipv6_rto_sock = netlink_kernel_create(&init_net, NETLINK_OPLUS_IPV6_RTO, &cfg); + return oplus_ipv6_rto_sock == NULL ? -ENOMEM : 0; +} + + +static void oplus_ipv6_rto_netlink_exit(void) +{ + netlink_kernel_release(oplus_ipv6_rto_sock); + oplus_ipv6_rto_sock = NULL; +} + +static int __init oplus_ipv6_rto_init(void) +{ + int ret = 0; + + //Disable this feature default. + oplus_ipv6_rto_enable = IPV6_RTO_DISABLED; + ret = oplus_ipv6_rto_netlink_init(); + if (ret < 0) { + KLOGE("oplus_ipv6_rto module can not init netlink.\n"); + } + return ret; +} + + +static void __exit oplus_ipv6_rto_fini(void) +{ + oplus_ipv6_rto_netlink_exit(); +} + +module_init(oplus_ipv6_rto_init); +module_exit(oplus_ipv6_rto_fini); diff --git a/net/oplus_nf_hooks/Makefile b/net/oplus_nf_hooks/Makefile new file mode 100644 index 000000000000..6ef316d2a25c --- /dev/null +++ b/net/oplus_nf_hooks/Makefile @@ -0,0 +1,22 @@ +#/************************************************************************************ +#** File: - Makefile +#** VENDOR_EDIT +#** Copyright (C), 2008-2020, OPLUS Mobile Comm Corp., Ltd +#** +#** Description: +#** 1. Add for WeChat lucky money recognition +#** +#** Version: 1.0 +#** Date : 2020-03-20 +#** TAG : OPLUS_FEATURE_WIFI_LUCKYMONEY +#** +#** ---------------------Revision History: --------------------- +#** +#** --------------------------------------------------------------- +#** +#************************************************************************************/ + +# +# Makefile for the netfilter modules on top of IPv4. +# +obj-y += oplus_nf_hooks.o diff --git a/net/oplus_nf_hooks/oplus_nf_hooks.c b/net/oplus_nf_hooks/oplus_nf_hooks.c new file mode 100644 index 000000000000..32137d381b83 --- /dev/null +++ b/net/oplus_nf_hooks/oplus_nf_hooks.c @@ -0,0 +1,461 @@ +/************************************************************************************ +** File: - oplus_nf_hooks.c +** VENDOR_EDIT +** Copyright (C), 2008-2020, OPLUS Mobile Comm Corp., Ltd +** +** Description: +** 1. Add for WeChat lucky money recognition +** +** Version: 1.0 +** Date : 2020-03-20 +** TAG : OPLUS_FEATURE_WIFI_LUCKYMONEY +** +** ---------------------Revision History: --------------------- +** +** --------------------------------------------------------------- +** +************************************************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/*NLMSG_MIN_TYPE is 0x10,so we start at 0x11*/ +enum{ + NF_HOOKS_ANDROID_PID = 0x11, + NF_HOOKS_WECHAT_PARAM = 0x12, + NF_HOOKS_LM_DETECTED = 0x13, +}; + +#define MAX_FIXED_VALUE_LEN 20 +#define MAX_WECHAT_PARAMS 10 + +#define UID_MASK 100000 + +struct wechat_pattern_info { + u32 max_tot_len; + u32 min_tot_len; + int offset; + u32 len; + u8 fixed_value[MAX_FIXED_VALUE_LEN]; +}; + +struct wechat_pattern_info wechat_infos[MAX_WECHAT_PARAMS]; + + +static DEFINE_MUTEX(nf_hooks_netlink_mutex); +static struct ctl_table_header *oplus_nf_hooks_table_hrd; + +static rwlock_t nf_hooks_lock; + +#define nf_hooks_read_lock() read_lock_bh(&nf_hooks_lock); +#define nf_hooks_read_unlock() read_unlock_bh(&nf_hooks_lock); +#define nf_hooks_write_lock() write_lock_bh(&nf_hooks_lock); +#define nf_hooks_write_unlock() write_unlock_bh(&nf_hooks_lock); + +static u32 wechat_uid; +static u32 wechat_param_count; + +static u32 nf_hooks_debug = 0; + +//portid of android netlink socket +static u32 oplus_nf_hooks_pid; +//kernel sock +static struct sock *oplus_nf_hooks_sock; + + +/* send to user space */ +static int oplus_nf_hooks_send_to_user(int msg_type, char *payload, int payload_len) +{ + int ret = 0; + struct sk_buff *skbuff; + struct nlmsghdr *nlh; + + /*allocate new buffer cache */ + skbuff = alloc_skb(NLMSG_SPACE(payload_len), GFP_ATOMIC); + if (skbuff == NULL) { + printk("oplus_nf_hooks_netlink: skbuff alloc_skb failed\n"); + return -1; + } + + /* fill in the data structure */ + nlh = nlmsg_put(skbuff, 0, 0, msg_type, NLMSG_ALIGN(payload_len), 0); + if (nlh == NULL) { + printk("oplus_nf_hooks_netlink:nlmsg_put failaure\n"); + nlmsg_free(skbuff); + return -1; + } + + //compute nlmsg length + nlh->nlmsg_len = NLMSG_HDRLEN + NLMSG_ALIGN(payload_len); + + if(NULL != payload){ + memcpy((char *)NLMSG_DATA(nlh),payload,payload_len); + } + + /* set control field,sender's pid */ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,7,0)) + NETLINK_CB(skbuff).pid = 0; +#else + NETLINK_CB(skbuff).portid = 0; +#endif + + NETLINK_CB(skbuff).dst_group = 0; + + /* send data */ + if(oplus_nf_hooks_pid){ + ret = netlink_unicast(oplus_nf_hooks_sock, skbuff, oplus_nf_hooks_pid, MSG_DONTWAIT); + } else { + printk(KERN_ERR "oplus_nf_hooks_netlink: can not unicast skbuff, oplus_nf_hooks_pid=0\n"); + kfree_skb(skbuff); + } + if(ret < 0){ + printk(KERN_ERR "oplus_nf_hooks_netlink: can not unicast skbuff,ret = %d\n", ret); + return 1; + } + + return 0; +} + + +static bool is_wechat_skb(struct nf_conn *ct,struct sk_buff *skb) +{ + kuid_t sk_uid; + struct sock *sk = NULL; +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4,9,0)) + const struct file *filp = NULL; +#endif + + if (ct->oplus_app_uid == -1 || wechat_uid == 0) { + return false; + } else if(ct->oplus_app_uid == 0) { + + sk = skb_to_full_sk(skb); + if(NULL == sk || !sk_fullsock(sk) || NULL == sk->sk_socket){ + return false; + } +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4,9,0)) + filp = sk->sk_socket->file; + if(NULL == filp){ + return false; + } + sk_uid = filp->f_cred->fsuid; +#else + sk_uid = sk->sk_uid; +#endif + if ((sk_uid.val % UID_MASK) == (wechat_uid % UID_MASK)) { + ct->oplus_app_uid = wechat_uid; + /*if (nf_hooks_debug) printk("oplus_nf_hooks_lm:this is wechat skb...\n");*/ + return true; + } else { + ct->oplus_app_uid = -1; + /*if (nf_hooks_debug) printk("oplus_nf_hooks_lm:this is NOT wechat skb!!!\n");*/ + return false; + } + } else if ((ct->oplus_app_uid % UID_MASK) == (wechat_uid % UID_MASK)) { + return true; + } + + return false; +} + +/* + *To detect incoming Lucky Money event. +*/ +static unsigned int oplus_nf_hooks_lm_detect(void *priv, + struct sk_buff *skb, + const struct nf_hook_state *state) +{ + struct nf_conn *ct = NULL; + enum ip_conntrack_info ctinfo; + struct iphdr *iph = NULL; + struct tcphdr *tcph = NULL; + u32 header_len, i; + u8 *payload = NULL; + u16 tot_len; + + ct = nf_ct_get(skb, &ctinfo); + + if(NULL == ct){ + return NF_ACCEPT; + } + + if ((iph = ip_hdr(skb)) != NULL && iph->protocol == IPPROTO_TCP) { + if (is_wechat_skb(ct, skb)) { + tot_len = ntohs(iph->tot_len); + if (unlikely(skb_linearize(skb))) { + return NF_ACCEPT; + } + iph = ip_hdr(skb); + tcph = tcp_hdr(skb); + header_len = iph->ihl * 4 + tcph->doff * 4; + payload = (u8 *)(skb->data + header_len); + for (i = 0; i < wechat_param_count; i++) { + if (tot_len >= wechat_infos[i].min_tot_len && tot_len <= wechat_infos[i].max_tot_len) { + if (memcmp(payload + wechat_infos[i].offset, wechat_infos[i].fixed_value, wechat_infos[i].len) == 0) { + printk("oplus_nf_hooks_lm:i=%d received hong bao...\n", i); + oplus_nf_hooks_send_to_user(NF_HOOKS_LM_DETECTED, NULL, 0); + break; + } else { + if (nf_hooks_debug) printk("oplus_nf_hooks_lm:i=%d fixed value not match!!\n", i); + } + } else { + if (nf_hooks_debug) printk("oplus_nf_hooks_lm:i=%d incorrect tot_len=%d\n", i, tot_len); + } + } + } + } + + return NF_ACCEPT; +} + +/* + *To detect incoming Lucky Money event with IPv6. +*/ +static unsigned int oplus_nf_hooks_v6_lm_detect(void *priv, + struct sk_buff *skb, + const struct nf_hook_state *state) +{ + struct nf_conn *ct = NULL; + enum ip_conntrack_info ctinfo; + struct ipv6hdr *ipv6h = NULL; + struct tcphdr *tcph = NULL; + u32 header_len, i; + __be16 fo = 0; + u8 ip_proto; + int ihl = 0; + u8 *payload = NULL; + u16 tot_len; + + ct = nf_ct_get(skb, &ctinfo); + + if (NULL == ct) { + return NF_ACCEPT; + } + + if (skb->protocol == htons(ETH_P_IPV6) && (ipv6h = ipv6_hdr(skb)) != NULL + && ipv6h->nexthdr == NEXTHDR_TCP) { + if (is_wechat_skb(ct, skb)) { + tot_len = ntohs(ipv6h->payload_len); + ip_proto = ipv6h->nexthdr; + if (unlikely(skb_linearize(skb))) { + return NF_ACCEPT; + } + + ihl = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr), &ip_proto, &fo); /* ipv6 header length */ + + tcph = tcp_hdr(skb); + if (NULL == tcph) { + return NF_ACCEPT; + } + + header_len = ihl + tcph->doff * 4; /* total length of ipv6 header and tcp header */ + payload = (u8 *)(skb->data + header_len); /* tcp payload buffer */ + for (i = 0; i < wechat_param_count; i++) { + if (tot_len >= wechat_infos[i].min_tot_len && tot_len <= wechat_infos[i].max_tot_len) { + if (memcmp(payload + wechat_infos[i].offset, wechat_infos[i].fixed_value, wechat_infos[i].len) == 0) { + printk("oplus_nf_hooks_lm:i=%d received hong bao from ipv6...\n", i); + oplus_nf_hooks_send_to_user(NF_HOOKS_LM_DETECTED, NULL, 0); + break; + } else { + if (nf_hooks_debug) printk("oplus_nf_hooks_lm:i=%d fixed value not match from ipv6!!\n", i); + } + } else { + if (nf_hooks_debug) printk("oplus_nf_hooks_lm:i=%d incorrect tot_len=%d from ipv6\n", i, tot_len); + } + } + } + } + return NF_ACCEPT; +} + +static struct nf_hook_ops oplus_nf_hooks_ops[] __read_mostly = { + { + .hook = oplus_nf_hooks_lm_detect, + .pf = NFPROTO_IPV4, + .hooknum = NF_INET_LOCAL_IN, + .priority = NF_IP_PRI_FILTER + 1, + }, + { + .hook = oplus_nf_hooks_v6_lm_detect, + .pf = NFPROTO_IPV6, + .hooknum = NF_INET_LOCAL_IN, + .priority = NF_IP6_PRI_FILTER + 1, + }, +}; + +static struct ctl_table oplus_nf_hooks_sysctl_table[] = { + { + .procname = "wechat_uid", + .data = &wechat_uid, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec, + }, + { + .procname = "nf_hooks_debug", + .data = &nf_hooks_debug, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec, + }, + { } +}; + +static int oplus_nf_hooks_sysctl_init(void) +{ + oplus_nf_hooks_table_hrd = register_net_sysctl(&init_net, "net/oplus_nf_hooks", + oplus_nf_hooks_sysctl_table); + return oplus_nf_hooks_table_hrd == NULL ? -ENOMEM : 0; +} + +static int oplus_nf_hooks_set_android_pid(struct sk_buff *skb) +{ + oplus_nf_hooks_pid = NETLINK_CB(skb).portid; + printk("oplus_nf_hooks_set_android_pid pid=%d\n",oplus_nf_hooks_pid); + return 0; +} + +static int oplus_nf_hooks_set_wechat_param(struct nlmsghdr *nlh) +{ + int i, j; + u32 *data; + struct wechat_pattern_info * info = NULL; + data = (u32 *)NLMSG_DATA(nlh); + wechat_uid = *data; + wechat_param_count = *(data + 1); + if (nlh->nlmsg_len == NLMSG_HDRLEN + 2*sizeof(u32) + wechat_param_count*sizeof(struct wechat_pattern_info)) { + for (i = 0; i < wechat_param_count && i < MAX_WECHAT_PARAMS; i++) { + info = (struct wechat_pattern_info *)(data + 2) + i; + memset(&(wechat_infos[i]), 0, sizeof(struct wechat_pattern_info)); + //wechat_infos[i].uid = info->uid; + wechat_infos[i].max_tot_len = info->max_tot_len; + wechat_infos[i].min_tot_len = info->min_tot_len; + wechat_infos[i].offset = info->offset; + wechat_infos[i].len = info->len; + memcpy(wechat_infos[i].fixed_value, info->fixed_value, info->len); + if (nf_hooks_debug) { + printk("oplus_nf_hooks_set_wechat_param i=%d uid=%d,max=%d,min=%d,offset=%d,len=%d,value=", + i, wechat_uid, wechat_infos[i].max_tot_len, wechat_infos[i].min_tot_len, + wechat_infos[i].offset, wechat_infos[i].len); + for (j = 0; j < wechat_infos[i].len; j++) { + printk("%d -> %02x ", j, wechat_infos[i].fixed_value[j]); + } + printk("\n"); + } + } + return 0; + } else { + if (nf_hooks_debug) printk("oplus_nf_hooks_set_wechat_param invalid param!! nlmsg_len=%d\n", nlh->nlmsg_len); + return -1; + } +} + +static int nf_hooks_netlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, struct netlink_ext_ack *extack) +{ + int ret = 0; + + switch (nlh->nlmsg_type) { + case NF_HOOKS_ANDROID_PID: + ret = oplus_nf_hooks_set_android_pid(skb); + break; + case NF_HOOKS_WECHAT_PARAM: + ret = oplus_nf_hooks_set_wechat_param(nlh); + break; + default: + return -EINVAL; + } + + return ret; +} + + +static void nf_hooks_netlink_rcv(struct sk_buff *skb) +{ + mutex_lock(&nf_hooks_netlink_mutex); + netlink_rcv_skb(skb, &nf_hooks_netlink_rcv_msg); + mutex_unlock(&nf_hooks_netlink_mutex); +} + +static int oplus_nf_hooks_netlink_init(void) +{ + struct netlink_kernel_cfg cfg = { + .input = nf_hooks_netlink_rcv, + }; + + oplus_nf_hooks_sock = netlink_kernel_create(&init_net, NETLINK_OPLUS_NF_HOOKS, &cfg); + return oplus_nf_hooks_sock == NULL ? -ENOMEM : 0; +} + +static void oplus_nf_hooks_netlink_exit(void) +{ + netlink_kernel_release(oplus_nf_hooks_sock); + oplus_nf_hooks_sock = NULL; +} + +static int __init oplus_nf_hooks_init(void) +{ + int ret = 0; + + ret = oplus_nf_hooks_netlink_init(); + if (ret < 0) { + printk("oplus_nf_hooks_init module failed to init netlink.\n"); + } else { + printk("oplus_nf_hooks_init module init netlink successfully.\n"); + } + + ret |= oplus_nf_hooks_sysctl_init(); + + ret |= nf_register_net_hooks(&init_net,oplus_nf_hooks_ops,ARRAY_SIZE(oplus_nf_hooks_ops)); + if (ret < 0) { + printk("oplus_nf_hooks_init module failed to register netfilter ops.\n"); + } else { + printk("oplus_nf_hooks_init module register netfilter ops successfully.\n"); + } + + return ret; +} + +static void __exit oplus_nf_hooks_fini(void) +{ + rwlock_init(&nf_hooks_lock); + + oplus_nf_hooks_netlink_exit(); + + if(oplus_nf_hooks_table_hrd){ + unregister_net_sysctl_table(oplus_nf_hooks_table_hrd); + } + + nf_unregister_net_hooks(&init_net,oplus_nf_hooks_ops, ARRAY_SIZE(oplus_nf_hooks_ops)); +} + +module_init(oplus_nf_hooks_init); +module_exit(oplus_nf_hooks_fini); diff --git a/net/oplus_nwpower/Makefile b/net/oplus_nwpower/Makefile new file mode 100644 index 000000000000..308a7bcfb063 --- /dev/null +++ b/net/oplus_nwpower/Makefile @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-only +# Copyright (C) 2018-2020 Oplus. All rights reserved. + +obj-y += oplus_nwpower.o diff --git a/net/oplus_nwpower/oplus_nwpower.c b/net/oplus_nwpower/oplus_nwpower.c new file mode 100644 index 000000000000..799fff1d990c --- /dev/null +++ b/net/oplus_nwpower/oplus_nwpower.c @@ -0,0 +1,995 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2018-2020 Oplus. All rights reserved. + */ + +/**************************************************************** +** ------------------ Revision History:------------------------ +** +** Asiga 2019/07/31 1.0 build this module +****************************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef OPLUS_FEATURE_POWERINFO_STANDBY +#include +#endif /* OPLUS_FEATURE_POWERINFO_STANDBY */ + +static void tcp_output_hook_work_callback(struct work_struct *work); +static void tcp_input_hook_work_callback(struct work_struct *work); +static void tcp_output_tcpsynretrans_hook_work_callback(struct work_struct *work); +static void tcp_input_tcpsynretrans_hook_work_callback(struct work_struct *work); + +static int nwpower_send_to_user(int msg_type,char *msg_data, int msg_len); + +//Add for feature switch +static atomic_t qrtr_wakeup_hook_boot = ATOMIC_INIT(0); +static atomic_t ipa_wakeup_hook_boot = ATOMIC_INIT(0); +static atomic_t tcpsynretrans_hook_boot = ATOMIC_INIT(0); + +//Add for qmi wakeup msg +#define GLINK_MODEM_NODE_ID 0x3 +#define GLINK_ADSP_NODE_ID 0x5 +#define GLINK_CDSP_NODE_ID 0xa +#define GLINK_SLPI_NODE_ID 0x9 +#define GLINK_NPU_NODE_ID 0xb + +#define OPLUS_MAX_QRTR_SERVICE_LEN 120 + +atomic_t qrtr_first_msg = ATOMIC_INIT(0); +u64 oplus_nw_wakeup[OPLUS_NW_WAKEUP_SUM] = {0}; +static u64 service_wakeup_times[OPLUS_MAX_QRTR_SERVICE_LEN][4] = {{0}}; + +//Add for ipa wakeup msg +#define OPLUS_MAX_RECORD_IP_LEN 60 +#define OPLUS_TRANSMISSION_INTERVAL 3 * 1000//3s +#define OPLUS_TCP_RETRANSMISSION_INTERVAL 1 * 1000//1s +#define OPLUS_MAX_RECORD_APP_WAKEUP_LEN 100 + +struct tcp_hook_struct { + u32 uid; + u32 pid; + bool is_ipv6; + u32 ipv4_addr; + u64 ipv6_addr1; + u64 ipv6_addr2; + u64 set[OPLUS_MAX_RECORD_IP_LEN*3]; +}; + +struct tcp_hook_simple_struct { + u32 count; + u64 set[OPLUS_MAX_RECORD_APP_WAKEUP_LEN*3+1]; +}; +static struct tcp_hook_simple_struct app_wakeup_monitor_list = { + .set = {0}, +}; + +static bool tcp_input_sch_work = false; +static atomic_t tcp_is_input = ATOMIC_INIT(0);//1=v4_input,2=v6_input,3=output,0=default +static struct timespec tcp_last_transmission_stamp; +static struct tcp_hook_struct tcp_output_list = { + .is_ipv6 = false, + .set = {0}, +}; +static struct tcp_hook_struct tcp_input_list = { + .is_ipv6 = false, + .set = {0}, +}; +static struct tcp_hook_struct tcp_output_retrans_list = { + .is_ipv6 = false, + .set = {0}, +}; +static struct tcp_hook_struct tcp_input_retrans_list = { + .is_ipv6 = false, + .set = {0}, +}; +DECLARE_WORK(tcp_output_hook_work, tcp_output_hook_work_callback); +DECLARE_WORK(tcp_input_hook_work, tcp_input_hook_work_callback); +DECLARE_WORK(tcp_output_tcpsynretrans_hook_work, tcp_output_tcpsynretrans_hook_work_callback); +DECLARE_WORK(tcp_input_tcpsynretrans_hook_work, tcp_input_tcpsynretrans_hook_work_callback); + +//Add for modem eap buffer +u64 oplus_mdaci_nw_wakeup[OPLUS_NW_WAKEUP_SUM] = {0}; +static u64 mdaci_service_wakeup_times[OPLUS_MAX_QRTR_SERVICE_LEN][4] = {{0}}; +static struct tcp_hook_struct mdaci_tcp_output_list = { + .is_ipv6 = false, + .set = {0}, +}; +static struct tcp_hook_struct mdaci_tcp_input_list = { + .is_ipv6 = false, + .set = {0}, +}; +static struct tcp_hook_struct mdaci_tcp_output_retrans_list = { + .is_ipv6 = false, + .set = {0}, +}; +static struct tcp_hook_struct mdaci_tcp_input_retrans_list = { + .is_ipv6 = false, + .set = {0}, +}; + +//Add for Netlink +enum{ + NW_POWER_ANDROID_PID = 0x11, + NW_POWER_BOOT_MONITOR = 0x12, + NW_POWER_STOP_MONITOR = 0x13, + NW_POWER_STOP_MONITOR_UNSL = 0x14, + NW_POWER_UNSL_MONITOR = 0x15, + NW_POWER_REQUEST_MDACI = 0x16, + NW_POWER_REPORT_MDACI = 0x17, + NW_POWER_BLACK_LIST = 0x18, + NW_POWER_REQUEST_BLACK_REJECT = 0x19, + NW_POWER_REPORT_BLACK_REJECT = 0x1A, + NW_POWER_REQUEST_APP_WAKEUP = 0x1D, + NW_POWER_REPORT_APP_WAKEUP = 0x1E, + NW_POWER_REPORT_MDACI_APP_WAKEUP = 0x1F, +}; +static DEFINE_MUTEX(netlink_mutex); +static u32 oplus_nwpower_pid = 0; +static struct sock *oplus_nwpower_sock; + +//Add for unsl wakeup msg +#define KERNEL_UNSL_MONITOR_LEN 7 +static u64 wakeup_unsl_msg[KERNEL_UNSL_MONITOR_LEN] = {0}; + +#define KERNEL_UNSL_APP_WAKEUP_LEN 300 +static u32 blacklist_len = 0; +static u32 blacklist_uid[KERNEL_UNSL_APP_WAKEUP_LEN] = {0}; + +#define OPLUS_MAX_RECORD_BLACK_REJECT_LEN 100 +#define KERNEL_UNSL_BLACK_REJECT_LEN 201 +static u32 record_blacklist_reject_index = 0; +static u64 blacklist_reject_uid[KERNEL_UNSL_BLACK_REJECT_LEN] = {0}; + +/*Add for qrtr bts info*/ +#define BTS_BUFFER_SIZE (80) +static char bts_net_wakeup_buffer[BTS_BUFFER_SIZE+1]; + +/*Add for mdaci wakeup apps*/ +static struct tcp_hook_simple_struct mdaci_app_wakeup_monitor_list = { + .set = {0}, +}; + +static uid_t get_uid_from_sock(const struct sock *sk) +{ + uid_t sk_uid; + #if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 9, 0)) + const struct file *filp = NULL; + #endif + if(NULL == sk || !sk_fullsock(sk) || NULL == sk->sk_socket) { + return 0; + } + #if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 9, 0)) + filp = sk->sk_socket->file; + if(NULL == filp) { + return 0; + } + sk_uid = __kuid_val(filp->f_cred->fsuid); + #else + sk_uid = __kuid_val(sk->sk_uid); + #endif + return sk_uid; +} + +static void nwpower_unsl_blacklist_reject() { + if (record_blacklist_reject_index > 0) { + blacklist_reject_uid[0] = record_blacklist_reject_index; + nwpower_send_to_user(NW_POWER_REPORT_BLACK_REJECT, (char*)blacklist_reject_uid, sizeof(blacklist_reject_uid)); + memset(blacklist_reject_uid, 0x0, OPLUS_MAX_RECORD_BLACK_REJECT_LEN * sizeof(u32)); + record_blacklist_reject_index = 0; + } +} + +extern bool oplus_check_socket_in_blacklist(int is_input, struct socket *sock) { + int i = 0; + uid_t uid = 0; + struct timespec now_ts; + if (blacklist_len > 0 && sock && sock->sk && (sock->sk->sk_family == 2 || sock->sk->sk_family == 10)){ + uid = get_uid_from_sock(sock->sk); + if(uid == 0) { + return false; + } + now_ts = current_kernel_time(); + for (i = 0; i < blacklist_len; i++) { + if(blacklist_uid[i] == uid) { + if (is_input != 1) { + if (record_blacklist_reject_index >= OPLUS_MAX_RECORD_BLACK_REJECT_LEN) { + nwpower_unsl_blacklist_reject(); + } + if (record_blacklist_reject_index < OPLUS_MAX_RECORD_BLACK_REJECT_LEN) { + blacklist_reject_uid[record_blacklist_reject_index*2+1] = now_ts.tv_sec * 1000 + now_ts.tv_nsec / 1000000; + blacklist_reject_uid[record_blacklist_reject_index*2+2] = (u64)uid << 32 | is_input; + record_blacklist_reject_index++; + } + } + printk("[oplus_netcontroller] blacklist reject, stamp=%ld, is_input=%d, uid=%u", + now_ts.tv_sec * 1000 + now_ts.tv_nsec / 1000000, is_input, uid); + return true; + } + } + return false; + } + return false; +} + +static int nwpower_set_blacklist_uids(struct nlmsghdr *nlh) { + u32 *data; + int i = 0; + data = (u32 *)NLMSG_DATA(nlh); + memset(blacklist_uid, 0x0, KERNEL_UNSL_APP_WAKEUP_LEN * sizeof(u32)); + blacklist_len = *data; + for (i = 0; i < blacklist_len; i++) { + if (i >= KERNEL_UNSL_APP_WAKEUP_LEN) { + printk("[oplus_netcontroller] uids length exceed the limit!"); + break; + } else { + blacklist_uid[i] = *(data + i + 1); + } + } + return 0; +} + +extern void oplus_match_modem_wakeup() { + atomic_set(&qrtr_first_msg, 1); + oplus_nw_wakeup[OPLUS_NW_MPSS]++; + oplus_mdaci_nw_wakeup[OPLUS_NW_MPSS]++; + snprintf(bts_net_wakeup_buffer, BTS_BUFFER_SIZE, "qmi"); +} + +extern void oplus_match_wlan_wakeup() { + oplus_nw_wakeup[OPLUS_NW_WIFI]++; + oplus_mdaci_nw_wakeup[OPLUS_NW_WIFI]++; +} + +static void match_qrtr_new_service_port(int id, int port, u64 qrtr[][4]) { + int i; + for (i = 0; i < OPLUS_MAX_QRTR_SERVICE_LEN; ++i) { + if (qrtr[i][0] == 0) { + qrtr[i][0] = 1; + qrtr[i][1] = id; + qrtr[i][2] = port; + //printk("[oplus_nwpower] QrtrNewService[%d]: ServiceID: %d, PortID: %d", i, id, port); + break; + } else { + if (qrtr[i][1] == id && qrtr[i][2] == port) { + //printk("[oplus_nwpower] QrtrNewService[%d]: Ignore."); + break; + } + } + } +} + +static void match_qrtr_del_service_port(int id, u64 qrtr[][4]) { + int i; + for (i = 0; i < OPLUS_MAX_QRTR_SERVICE_LEN; ++i) { + if (qrtr[i][0] == 1 && qrtr[i][1] == id) { + qrtr[i][0] = 0; + //printk("[oplus_nwpower] QrtrDelService[%d]: ServiceID: %d", i, id); + break; + } + } +} + +extern void oplus_match_qrtr_service_port(int type, int id, int port) { + if (type == QRTR_TYPE_NEW_SERVER) { + match_qrtr_new_service_port(id, port, service_wakeup_times); + match_qrtr_new_service_port(id, port, mdaci_service_wakeup_times); + } else if (type == QRTR_TYPE_DEL_SERVER) { + match_qrtr_del_service_port(id, service_wakeup_times); + match_qrtr_del_service_port(id, mdaci_service_wakeup_times); + } +} + +void bts_net_clear(void) +{ + memset(bts_net_wakeup_buffer, 0, sizeof(bts_net_wakeup_buffer)); +} +bool bts_net_exist(void) +{ + int platform_id = get_cached_platform_id(); + if (platform_id == LAGOON) { + bts_net_clear(); + } + return bts_net_wakeup_buffer[0] == 0 ? false : true; +} +ssize_t bts_net_fill(char * desc, ssize_t size) +{ + return scnprintf(desc, size > BTS_BUFFER_SIZE ? BTS_BUFFER_SIZE : size, "999 %s\n", bts_net_wakeup_buffer); +} + +static void __oplus_match_qrtr_wakeup(int src_node, int src_port, int dst_port, unsigned int arg1, unsigned int arg2, u64 qrtr[][4], u64 wakeup[OPLUS_NW_WAKEUP_SUM], bool prt) { + int i; + int repeat[4] = {0}; + int repeat_index = 0; + if (atomic_read(&qrtr_wakeup_hook_boot) == 1 && atomic_read(&qrtr_first_msg) == 1) { + for (i = 0; i < OPLUS_MAX_QRTR_SERVICE_LEN; ++i) { + if (qrtr[i][0] == 1 && (qrtr[i][2] == src_port || qrtr[i][2] == dst_port)) { + if (repeat_index < 4) repeat[repeat_index++] = i; + } + } + if (repeat_index == 1) { + qrtr[repeat[0]][3]++; + if (prt) + printk("[oplus_nwpower] QrtrWakeup: ServiceID: %d, NodeID: %d, PortID: %d, Msg: [%08x %08x], Count: %d", + qrtr[repeat[0]][1], src_node, qrtr[repeat[0]][2], arg1, arg2, qrtr[repeat[0]][3]); + } else if (repeat_index > 1) { + qrtr[repeat[repeat_index-1]][3]++; + if (prt) + printk("[oplus_nwpower] QrtrWakeup: ServiceID: [%d/%d/%d/%d], NodeID: %d, PortID: %d, Msg: [%08x %08x], Count: %d", + qrtr[repeat[0]][1], qrtr[repeat[1]][1], + repeat_index > 2 ? qrtr[repeat[2]][1]:-1, + repeat_index > 3 ? qrtr[repeat[3]][1]:-1, + src_node, qrtr[repeat[repeat_index-1]][2], arg1, arg2, qrtr[repeat[repeat_index-1]][3]); + } else { + if (prt) + printk("[oplus_nwpower] QrtrWakeup: ServiceID: %d, NodeID: %d, PortID: %d, Msg: [%08x %08x], Count: %d", + -1, src_node, -1, arg1, arg2, -1); + } + wakeup[OPLUS_NW_QRTR]++; + if (src_node == GLINK_MODEM_NODE_ID) { + wakeup[OPLUS_NW_MD]++; + + } else if (src_node == GLINK_ADSP_NODE_ID) { + } else if (src_node == GLINK_CDSP_NODE_ID) { + } else if (src_node == GLINK_SLPI_NODE_ID) { + } else if (src_node == GLINK_NPU_NODE_ID) { + } + } +} + +extern void oplus_match_qrtr_wakeup(int src_node, int src_port, int dst_port, unsigned int arg1, unsigned int arg2) { + __oplus_match_qrtr_wakeup(src_node, src_port, dst_port, arg1, arg2, service_wakeup_times, oplus_nw_wakeup, true); + __oplus_match_qrtr_wakeup(src_node, src_port, dst_port, arg1, arg2, mdaci_service_wakeup_times, oplus_mdaci_nw_wakeup, false); + atomic_set(&qrtr_first_msg, 0); +} + +extern void oplus_update_qrtr_flag(int flag){ + if (atomic_read(&qrtr_wakeup_hook_boot) == 1) { + atomic_set(&qrtr_first_msg, flag); + } +} + +static void print_qrtr_wakeup(bool unsl, u64 qrtr[][4], u64 wakeup[OPLUS_NW_WAKEUP_SUM], bool prt) { + u64 temp[5][4] = {{0}}; + u64 max_count = 0; + u64 max_count_id = 0; + int j; + int i; + int k; + for (j = 0; j < 5; ++j) { + for (i = 0; i < OPLUS_MAX_QRTR_SERVICE_LEN; ++i) { + if (qrtr[i][0] == 1 && qrtr[i][3] > max_count) { + max_count = qrtr[i][3]; + max_count_id = i; + } + } + for (k = 0;k < 4; ++k) { + temp[j][k] = qrtr[max_count_id][k]; + } + max_count = 0; + qrtr[max_count_id][3] = 0; + if (unsl) { + if (temp[j][3] > 0) wakeup_unsl_msg[j] = temp[j][2] << 32 | ((u32)temp[j][1] << 16 | (u16)temp[j][3]); + } + if (temp[j][3] > 0) printk("[oplus_nwpower] QrtrWakeupMax[%d]: ServiceID: %d, PortID: %d, Count: %d", + j, temp[j][1], temp[j][2], temp[j][3]); + } + if (unsl) { + wakeup_unsl_msg[5] = (wakeup[OPLUS_NW_MD] << 48) | + ((wakeup[OPLUS_NW_QRTR] & 0xFFFF) << 32) | + ((wakeup[OPLUS_NW_WIFI] & 0xFFFF) << 16) | + (wakeup[OPLUS_NW_MPSS] & 0xFFFF); + } + if (prt) + printk("[oplus_nwpower] AllWakeups: Mpss: %d, Qrtr: %d, Modem: %d, WiFi: %d", + wakeup[OPLUS_NW_MPSS], wakeup[OPLUS_NW_QRTR], wakeup[OPLUS_NW_MD], wakeup[OPLUS_NW_WIFI]); +} + +extern void oplus_match_ipa_ip_wakeup(int type, struct sk_buff *skb) { + struct timespec now_ts; + struct iphdr *tmp_v4iph; + struct ipv6hdr *tmp_v6iph; + tcp_input_sch_work = false; + if (atomic_read(&ipa_wakeup_hook_boot) == 1) { + if (atomic_read(&tcp_is_input) == 0) { + now_ts = current_kernel_time(); + if (((now_ts.tv_sec * 1000 + now_ts.tv_nsec / 1000000) - (tcp_last_transmission_stamp.tv_sec * 1000 + tcp_last_transmission_stamp.tv_nsec / 1000000)) > OPLUS_TRANSMISSION_INTERVAL) { + if (type == OPLUS_TCP_TYPE_V4) { + tmp_v4iph = ip_hdr(skb); + atomic_set(&tcp_is_input, OPLUS_TCP_TYPE_V4); + tcp_input_list.ipv4_addr = tmp_v4iph->saddr; + tcp_input_list.is_ipv6 = false; + mdaci_tcp_input_list.ipv4_addr = tcp_input_list.ipv4_addr; + mdaci_tcp_input_list.is_ipv6 = false; + } else { + tmp_v6iph = ipv6_hdr(skb); + atomic_set(&tcp_is_input, OPLUS_TCP_TYPE_V6); + tcp_input_list.ipv6_addr1 = (u64)ntohl(tmp_v6iph->saddr.s6_addr32[0]) << 32 | ntohl(tmp_v6iph->saddr.s6_addr32[1]); + tcp_input_list.ipv6_addr2 = (u64)ntohl(tmp_v6iph->saddr.s6_addr32[2]) << 32 | ntohl(tmp_v6iph->saddr.s6_addr32[3]); + tcp_input_list.is_ipv6 = true; + mdaci_tcp_input_list.ipv6_addr1 = tcp_input_list.ipv6_addr1; + mdaci_tcp_input_list.ipv6_addr2 = tcp_input_list.ipv6_addr2; + mdaci_tcp_input_list.is_ipv6 = true; + } + tcp_input_list.uid = 0; + tcp_input_list.pid = 0; + mdaci_tcp_input_list.uid = 0; + mdaci_tcp_input_list.pid = 0; + } + } + tcp_last_transmission_stamp = current_kernel_time(); + } +} + +extern void oplus_match_ipa_tcp_wakeup(int type, struct sock *sk) { + if (atomic_read(&ipa_wakeup_hook_boot) == 1) { + if (atomic_read(&tcp_is_input) == type && !tcp_input_sch_work) { + if (sk->sk_state != TCP_TIME_WAIT) { + tcp_input_list.uid = get_uid_from_sock(sk); + tcp_input_list.pid = sk->sk_oplus_pid; + mdaci_tcp_input_list.uid = tcp_input_list.uid; + mdaci_tcp_input_list.pid = tcp_input_list.pid; + } + schedule_work(&tcp_input_hook_work); + tcp_input_sch_work = true; + } + sk->oplus_last_rcv_stamp[0] = sk->oplus_last_rcv_stamp[1]; + sk->oplus_last_rcv_stamp[1] = tcp_last_transmission_stamp.tv_sec * 1000 + tcp_last_transmission_stamp.tv_nsec / 1000000; + } +} + +extern void oplus_ipa_schedule_work() { + if (atomic_read(&ipa_wakeup_hook_boot) == 1 && atomic_read(&tcp_is_input) == 1 && !tcp_input_sch_work) { + schedule_work(&tcp_input_hook_work); + tcp_input_sch_work = true; + } +} + +extern void oplus_match_tcp_output(struct sock *sk) { + struct timespec now_ts; + if (atomic_read(&ipa_wakeup_hook_boot) == 1) { + if (atomic_read(&tcp_is_input) == 0) { + now_ts = current_kernel_time(); + if (((now_ts.tv_sec * 1000 + now_ts.tv_nsec / 1000000) - (tcp_last_transmission_stamp.tv_sec * 1000 + tcp_last_transmission_stamp.tv_nsec / 1000000)) > OPLUS_TRANSMISSION_INTERVAL) { + atomic_set(&tcp_is_input, 3); + if (sk->sk_v6_daddr.s6_addr32[0] == 0 && sk->sk_v6_daddr.s6_addr32[1] == 0) { + tcp_output_list.ipv4_addr = sk->sk_daddr; + tcp_output_list.is_ipv6 = false; + mdaci_tcp_output_list.ipv4_addr = tcp_output_list.ipv4_addr; + mdaci_tcp_output_list.is_ipv6 = false; + } else { + tcp_output_list.ipv6_addr1 = (u64)ntohl(sk->sk_v6_daddr.s6_addr32[0]) << 32 | ntohl(sk->sk_v6_daddr.s6_addr32[1]); + tcp_output_list.ipv6_addr2 = (u64)ntohl(sk->sk_v6_daddr.s6_addr32[2]) << 32 | ntohl(sk->sk_v6_daddr.s6_addr32[3]); + tcp_output_list.is_ipv6 = true; + mdaci_tcp_output_list.ipv6_addr1 = tcp_output_list.ipv6_addr1; + mdaci_tcp_output_list.ipv6_addr2 = tcp_output_list.ipv6_addr2; + mdaci_tcp_output_list.is_ipv6 = true; + } + tcp_output_list.uid = get_uid_from_sock(sk); + tcp_output_list.pid = sk->sk_oplus_pid; + mdaci_tcp_output_list.uid = tcp_output_list.uid; + mdaci_tcp_output_list.pid = tcp_output_list.pid; + schedule_work(&tcp_output_hook_work); + } + } + tcp_last_transmission_stamp = current_kernel_time(); + sk->oplus_last_send_stamp[0] = sk->oplus_last_send_stamp[1]; + sk->oplus_last_send_stamp[1] = tcp_last_transmission_stamp.tv_sec * 1000 + tcp_last_transmission_stamp.tv_nsec / 1000000; + } +} + +extern void oplus_match_tcp_input_retrans(struct sock *sk) { + struct timespec now_ts; + if (atomic_read(&tcpsynretrans_hook_boot) == 1) { + now_ts = current_kernel_time(); + if (((now_ts.tv_sec * 1000 + now_ts.tv_nsec / 1000000) - sk->oplus_last_rcv_stamp[0]) > OPLUS_TCP_RETRANSMISSION_INTERVAL) { + if (sk->sk_v6_daddr.s6_addr32[0] == 0 && sk->sk_v6_daddr.s6_addr32[1] == 0) { + tcp_input_retrans_list.ipv4_addr = sk->sk_daddr; + tcp_input_retrans_list.is_ipv6 = false; + mdaci_tcp_input_retrans_list.ipv4_addr = tcp_input_retrans_list.ipv4_addr; + mdaci_tcp_input_retrans_list.is_ipv6 = false; + } else { + tcp_input_retrans_list.ipv6_addr1 = (u64)ntohl(sk->sk_v6_daddr.s6_addr32[0]) << 32 | ntohl(sk->sk_v6_daddr.s6_addr32[1]); + tcp_input_retrans_list.ipv6_addr2 = (u64)ntohl(sk->sk_v6_daddr.s6_addr32[2]) << 32 | ntohl(sk->sk_v6_daddr.s6_addr32[3]); + tcp_input_retrans_list.is_ipv6 = true; + mdaci_tcp_input_retrans_list.ipv6_addr1 = tcp_input_retrans_list.ipv6_addr1; + mdaci_tcp_input_retrans_list.ipv6_addr2 = tcp_input_retrans_list.ipv6_addr2; + mdaci_tcp_input_retrans_list.is_ipv6 = true; + } + tcp_input_retrans_list.uid = get_uid_from_sock(sk); + tcp_input_retrans_list.pid = sk->sk_oplus_pid; + mdaci_tcp_input_retrans_list.uid = tcp_input_retrans_list.uid; + mdaci_tcp_input_retrans_list.pid = tcp_input_retrans_list.pid; + schedule_work(&tcp_input_tcpsynretrans_hook_work); + } + } +} + +extern void oplus_match_tcp_output_retrans(struct sock *sk) { + struct timespec now_ts; + if (atomic_read(&tcpsynretrans_hook_boot) == 1) { + now_ts = current_kernel_time(); + if (((now_ts.tv_sec * 1000 + now_ts.tv_nsec / 1000000) - sk->oplus_last_send_stamp[0]) > OPLUS_TCP_RETRANSMISSION_INTERVAL) { + if (sk->sk_v6_daddr.s6_addr32[0] == 0 && sk->sk_v6_daddr.s6_addr32[1] == 0) { + tcp_output_retrans_list.ipv4_addr = sk->sk_daddr; + tcp_output_retrans_list.is_ipv6 = false; + mdaci_tcp_output_retrans_list.ipv4_addr = tcp_output_retrans_list.ipv4_addr; + mdaci_tcp_output_retrans_list.is_ipv6 = false; + } else { + tcp_output_retrans_list.ipv6_addr1 = (u64)ntohl(sk->sk_v6_daddr.s6_addr32[0]) << 32 | ntohl(sk->sk_v6_daddr.s6_addr32[1]); + tcp_output_retrans_list.ipv6_addr2 = (u64)ntohl(sk->sk_v6_daddr.s6_addr32[2]) << 32 | ntohl(sk->sk_v6_daddr.s6_addr32[3]); + tcp_output_retrans_list.is_ipv6 = true; + mdaci_tcp_output_retrans_list.ipv6_addr1 = tcp_output_retrans_list.ipv6_addr1; + mdaci_tcp_output_retrans_list.ipv6_addr2 = tcp_output_retrans_list.ipv6_addr2; + mdaci_tcp_output_retrans_list.is_ipv6 = true; + } + tcp_output_retrans_list.uid = get_uid_from_sock(sk); + tcp_output_retrans_list.pid = sk->sk_oplus_pid; + mdaci_tcp_output_retrans_list.uid = tcp_output_retrans_list.uid; + mdaci_tcp_output_retrans_list.pid = tcp_output_retrans_list.pid; + schedule_work(&tcp_output_tcpsynretrans_hook_work); + } + } +} + +static void tcp_hook_insert_sort(struct tcp_hook_struct *pval) { + int i; + int j; + u64 count = 0; + u64 temp_sort[3] = {0}; + //Insert sort + for (i = 1; i < OPLUS_MAX_RECORD_IP_LEN; ++i) { + temp_sort[0] = pval->set[3*i]; + temp_sort[1] = pval->set[3*i+1]; + temp_sort[2] = pval->set[3*i+2]; + //If IPv4 + if (temp_sort[0] == 0 && temp_sort[1] == 0 && temp_sort[2] != 0) { + count = (temp_sort[2] & 0xFFFC000000000000) >> 50; + } else { + count = temp_sort[2] & 0xFFFFFFFF; + } + j = i - 1; + while (j >= 0) { + if (pval->set[3*j] == 0 && pval->set[3*j+1] == 0 && pval->set[3*j+2] != 0) { + if (count > (pval->set[3*j+2] & 0xFFFC000000000000) >> 50) { + pval->set[3*(j+1)] = pval->set[3*j]; + pval->set[3*(j+1)+1] = pval->set[3*j+1]; + pval->set[3*(j+1)+2] = pval->set[3*j+2]; + --j; + } else { + break; + } + } else { + if (count > (pval->set[3*j+2] & 0xFFFFFFFF)) { + pval->set[3*(j+1)] = pval->set[3*j]; + pval->set[3*(j+1)+1] = pval->set[3*j+1]; + pval->set[3*(j+1)+2] = pval->set[3*j+2]; + --j; + } else { + break; + } + } + } + pval->set[3*(j+1)] = temp_sort[0]; + pval->set[3*(j+1)+1] = temp_sort[1]; + pval->set[3*(j+1)+2] = temp_sort[2]; + } +} + +static int match_tcp_hook(struct tcp_hook_struct *pval) { + int i; + u32 uid = 0; + u64 count = 0; + bool handle = false; + + for (i = 0; i < OPLUS_MAX_RECORD_IP_LEN; ++i) { + if (pval->is_ipv6) { + if (pval->ipv6_addr1 == pval->set[3*i] && pval->ipv6_addr2 == pval->set[3*i+1]) { + count = pval->set[3*i+2] & 0xFFFFFFFF; + uid = (pval->set[3*i+2] & 0xFFFFFFFF00000000) >> 32; + if (uid == 0) { + pval->set[3*i+2] = (u64)(pval->uid) << 32 | (u32)(++count); + } else { + pval->set[3*i+2] = (pval->set[3*i+2] & 0xFFFFFFFF00000000) | (u32)(++count); + } + handle = true; + break; + } else if (pval->set[3*i+2] == 0) { + pval->set[3*i] = pval->ipv6_addr1; + pval->set[3*i+1] = pval->ipv6_addr2; + count = 1; + pval->set[3*i+2] = (u64)(pval->uid) << 32 | (u32)(count); + handle = true; + break; + } + } else { + if (pval->ipv4_addr == (pval->set[3*i+2] & 0xFFFFFFFF)) { + count = (pval->set[3*i+2] & 0xFFFC000000000000) >> 50; + uid = (pval->set[3*i+2] & 0x3FFFF00000000) >> 32; + if (uid == 0) { + count++; + count = count << 18 | (pval->uid & 0x3FFFF); + pval->set[3*i+2] = count << 32 | (pval->set[3*i+2] & 0xFFFFFFFF); + } else { + pval->set[3*i+2] = (++count) << 50 | (pval->set[3*i+2] & 0x3FFFFFFFFFFFF); + } + handle = true; + break; + } else if (pval->set[3*i+2] == 0) { + count = 1 << 18 | (pval->uid & 0x3FFFF); + pval->set[3*i+2] = count << 32 | pval->ipv4_addr; + handle = true; + break; + } + } + } + if (!handle) { + tcp_hook_insert_sort(pval); + i = OPLUS_MAX_RECORD_IP_LEN - 1; + if (pval->is_ipv6) { + pval->set[3*i] = pval->ipv6_addr1; + pval->set[3*i+1] = pval->ipv6_addr2; + count = 1; + pval->set[3*i+2] = (u64)(pval->uid) << 32 | (u32)(count); + } else { + pval->set[3*i] = 0; + pval->set[3*i+1] = 0; + count = 1 << 18 | (pval->uid & 0x3FFFF); + pval->set[3*i+2] = (u64)count << 32 | pval->ipv4_addr; + } + } + + return i; +} + +static bool tcp_monitor_check_uid_in_whitelist(int uid) { + int i = 0; + if (blacklist_len > 0) { + for (i = 0; i < blacklist_len; i++) { + if (i >= KERNEL_UNSL_APP_WAKEUP_LEN) { + printk("[oplus_netcontroller] uids length exceed the limit!"); + return true; + } + if(blacklist_uid[i] == uid) { + return false; + } + } + } + return true; +} + +static void nwpower_unsl_app_wakeup() +{ + nwpower_send_to_user(NW_POWER_REPORT_APP_WAKEUP, (char*)app_wakeup_monitor_list.set, sizeof(app_wakeup_monitor_list.set)); + app_wakeup_monitor_list.count = 0; + memset(app_wakeup_monitor_list.set, 0x0, sizeof(app_wakeup_monitor_list.set)); +} + + +static void app_wakeup_monitor(struct tcp_hook_simple_struct *pval, bool is_block, bool is_input, int pid, int uid) { + struct timespec now_ts = current_kernel_time(); + int block = is_block ? 1:0; + int input = is_input ? 1:0; + int whitelist = tcp_monitor_check_uid_in_whitelist(uid) ? 1:0; + if (pval->count < OPLUS_MAX_RECORD_APP_WAKEUP_LEN) { + pval->set[1+pval->count*3] = (u64)pid << 32 | uid; + pval->set[1+pval->count*3+1] = + ((u64)block << 48) | + ((u64)(input & 0xFFFF) << 32) | + ((u64)(whitelist & 0xFFFF) << 16) | + (0xFFFF); + pval->set[1+pval->count*3+2] = now_ts.tv_sec * 1000 + now_ts.tv_nsec / 1000000; + /* + printk("[oplus_nwpower] count:%d, block:%d, input:%d, pid:%d, uid:%d, stamp:%ld", + pval->set[0], block, input, pid, uid, pval->set[1+pval->count*3+2]); + */ + pval->set[0] = (++pval->count); + } else { + printk("[oplus_nwpower] warning! OPLUS_MAX_RECORD_APP_WAKEUP_LEN reached"); + } +} + +static void tcp_output_hook_work_callback(struct work_struct *work) { + int i = match_tcp_hook(&tcp_output_list); + match_tcp_hook(&mdaci_tcp_output_list); + app_wakeup_monitor(&app_wakeup_monitor_list, false, false, tcp_output_list.pid, tcp_output_list.uid); + app_wakeup_monitor(&mdaci_app_wakeup_monitor_list, false, false, tcp_output_list.pid, tcp_output_list.uid); + if (tcp_output_list.is_ipv6) { + printk("[oplus_nwpower] IPAOutputWakeup: [%ld,****], %d, %d, %d", + tcp_output_list.ipv6_addr1, + tcp_output_list.pid, tcp_output_list.uid, tcp_output_list.set[3*i+2] & 0xFFFFFFFF); + snprintf(bts_net_wakeup_buffer, BTS_BUFFER_SIZE, "ipa"); + } else { + printk("[oplus_nwpower] IPAOutputWakeup: %#X, %d, %d, %d", + tcp_output_list.ipv4_addr & 0xFFFFFF, tcp_output_list.pid, tcp_output_list.uid, + (tcp_output_list.set[3*i+2] & 0xFFFC000000000000) >> 50); + snprintf(bts_net_wakeup_buffer, BTS_BUFFER_SIZE, "ipa"); + } + atomic_set(&tcp_is_input, 0); +} + +static void tcp_input_hook_work_callback(struct work_struct *work) { + int i = match_tcp_hook(&tcp_input_list); + match_tcp_hook(&mdaci_tcp_input_list); + app_wakeup_monitor(&app_wakeup_monitor_list, false, true, tcp_input_list.pid, tcp_input_list.uid); + app_wakeup_monitor(&mdaci_app_wakeup_monitor_list, false, true, tcp_input_list.pid, tcp_input_list.uid); + #ifdef OPLUS_FEATURE_POWERINFO_STANDBY + wakeup_reasons_statics(IRQ_NAME_MODEM_IPA, WS_CNT_MODEM); + #endif /* OPLUS_FEATURE_POWERINFO_STANDBY */ + if (tcp_input_list.is_ipv6) { + printk("[oplus_nwpower] IPAInputWakeup: [%ld,****], %d, %d, %d", + tcp_input_list.ipv6_addr1, + tcp_input_list.pid, tcp_input_list.uid, tcp_input_list.set[3*i+2] & 0xFFFFFFFF); + snprintf(bts_net_wakeup_buffer, BTS_BUFFER_SIZE, "ipa"); + } else { + printk("[oplus_nwpower] IPAInputWakeup: %#X, %d, %d, %d", + tcp_input_list.ipv4_addr & 0xFFFFFF, tcp_input_list.pid, tcp_input_list.uid, + (tcp_input_list.set[3*i+2] & 0xFFFC000000000000) >> 50); + snprintf(bts_net_wakeup_buffer, BTS_BUFFER_SIZE, "ipa"); + } + atomic_set(&tcp_is_input, 0); +} + +static void tcp_output_tcpsynretrans_hook_work_callback(struct work_struct *work) { + int i = match_tcp_hook(&tcp_output_retrans_list); + match_tcp_hook(&mdaci_tcp_output_retrans_list); + if (tcp_output_retrans_list.is_ipv6) { + if (tcp_output_retrans_list.ipv6_addr1 == 0 && tcp_output_retrans_list.ipv6_addr2 == 0) + return; + printk("[oplus_nwpower] TCPOutputRetrans: [%ld,****], %d, %d, %d", + tcp_output_retrans_list.ipv6_addr1, + tcp_output_retrans_list.pid, tcp_output_retrans_list.uid, tcp_output_retrans_list.set[3*i+2] & 0xFFFFFFFF); + } else { + if (tcp_output_retrans_list.ipv4_addr == 0) + return; + printk("[oplus_nwpower] TCPOutputRetrans: %#X, %d, %d, %d", + tcp_output_retrans_list.ipv4_addr & 0xFFFFFF, tcp_output_retrans_list.pid, tcp_output_retrans_list.uid, + (tcp_output_retrans_list.set[3*i+2] & 0xFFFC000000000000) >> 50); + } +} + +static void tcp_input_tcpsynretrans_hook_work_callback(struct work_struct *work) { + int i = match_tcp_hook(&tcp_input_retrans_list); + match_tcp_hook(&mdaci_tcp_input_retrans_list); + if (tcp_input_retrans_list.is_ipv6) { + if (tcp_input_retrans_list.ipv6_addr1 == 0 && tcp_input_retrans_list.ipv6_addr2 == 0) + return; + printk("[oplus_nwpower] TCPInputRetrans: [%ld,****], %d, %d, %d", + tcp_input_retrans_list.ipv6_addr1, + tcp_input_retrans_list.pid, tcp_input_retrans_list.uid, tcp_input_retrans_list.set[3*i+2] & 0xFFFFFFFF); + } else { + if (tcp_input_retrans_list.ipv4_addr == 0) + return; + printk("[oplus_nwpower] TCPInputRetrans: %#X, %d, %d, %d", + tcp_input_retrans_list.ipv4_addr & 0xFFFFFF, tcp_input_retrans_list.pid, tcp_input_retrans_list.uid, + (tcp_input_retrans_list.set[3*i+2] & 0xFFFC000000000000) >> 50); + } +} + +static int print_tcp_wakeup(const char *type, struct tcp_hook_struct *pval, bool prt) { + int i; + u32 count; + u32 tcp_wakeup_times = 0; + tcp_hook_insert_sort(pval); + for (i = 0; i < 5;++i) { + if (pval->set[3*i] == 0 && pval->set[3*i+1] == 0 && pval->set[3*i+2] != 0) { + count = (pval->set[3*i+2] & 0xFFFC000000000000) >> 50; + if (prt && count > 0) { + printk("[oplus_nwpower] IPA%sMAX[%d]: %#X, %d, %d", + type, i, (pval->set[3*i+2] & 0xFFFFFFFF) & 0xFFFFFF, + (pval->set[3*i+2] & 0x3FFFF00000000) >> 32, count); + } + } else { + count = pval->set[3*i+2] & 0xFFFFFFFF; + if (prt && count > 0) { + printk("[oplus_nwpower] IPA%sMAX[%d]: [%ld,****], %d, %d", + type, i, pval->set[3*i], + pval->set[3*i+2] >> 32, count); + } + } + } + for (i = 0; i < OPLUS_MAX_RECORD_IP_LEN;++i) { + if (pval->set[3*i] == 0 && pval->set[3*i+1] == 0 && pval->set[3*i+2] != 0) { + count = (pval->set[3*i+2] & 0xFFFC000000000000) >> 50; + } else { + count = pval->set[3*i+2] & 0xFFFFFFFF; + } + if (count > 0) { + tcp_wakeup_times += count; + } + } + return tcp_wakeup_times; +} + +static void print_ipa_wakeup(bool unsl, struct tcp_hook_struct *ptcp_in, struct tcp_hook_struct *ptcp_out, struct tcp_hook_struct *ptcp_re_in, struct tcp_hook_struct *ptcp_re_out, u64 wakeup[OPLUS_NW_WAKEUP_SUM], bool prt) { + wakeup[OPLUS_NW_TCP_IN] = print_tcp_wakeup("Input", ptcp_in, prt); + wakeup[OPLUS_NW_TCP_OUT] = print_tcp_wakeup("Output", ptcp_out, prt); + wakeup[OPLUS_NW_TCP_RE_IN] = print_tcp_wakeup("InputRetrans", ptcp_re_in, prt); + wakeup[OPLUS_NW_TCP_RE_OUT] = print_tcp_wakeup("OutputRetrans", ptcp_re_out, prt); + if (prt) + printk("[oplus_nwpower] IPAAllWakeups: TCPInput: %d, TCPOutput: %d, TCPInputRetrans: %d, TCPOutputRetrans: %d", + wakeup[OPLUS_NW_TCP_IN], wakeup[OPLUS_NW_TCP_OUT], wakeup[OPLUS_NW_TCP_RE_IN], wakeup[OPLUS_NW_TCP_RE_OUT]); + if (unsl) { + wakeup_unsl_msg[6] = (wakeup[OPLUS_NW_TCP_IN] << 48) | + ((wakeup[OPLUS_NW_TCP_OUT] & 0xFFFF) << 32) | + ((wakeup[OPLUS_NW_TCP_RE_IN] & 0xFFFF) << 16) | + (wakeup[OPLUS_NW_TCP_RE_OUT] & 0xFFFF); + } +} + +static void reset_count(u64 qrtr[][4], struct tcp_hook_struct *ptcp_in, struct tcp_hook_struct *ptcp_out, + struct tcp_hook_struct *ptcp_re_in, struct tcp_hook_struct *ptcp_re_out, u64 wakeup[OPLUS_NW_WAKEUP_SUM]) { + int i; + int j; + for (i = 0; i < OPLUS_MAX_QRTR_SERVICE_LEN; ++i) { + if (qrtr[i][0] == 1) { + qrtr[i][3] = 0; + } + } + for (i = 0; i < OPLUS_MAX_RECORD_IP_LEN; ++i) { + for (j = 0; j < 3; ++j) { + ptcp_in->set[i+j] = 0; + ptcp_out->set[i+j] = 0; + ptcp_re_in->set[i+j] = 0; + ptcp_re_out->set[i+j] = 0; + } + } + for (i = 0; i < OPLUS_NW_WAKEUP_SUM; ++i) { + wakeup[i] = 0; + } + +} + +static void nwpower_hook_on() { + atomic_set(&qrtr_wakeup_hook_boot, 1); + atomic_set(&ipa_wakeup_hook_boot, 1); + atomic_set(&tcpsynretrans_hook_boot, 1); +} + +static void nwpower_hook_off(bool unsl) { + atomic_set(&qrtr_wakeup_hook_boot, 0); + atomic_set(&ipa_wakeup_hook_boot, 0); + atomic_set(&tcpsynretrans_hook_boot, 0); + print_qrtr_wakeup(unsl, service_wakeup_times, oplus_nw_wakeup, true); + print_ipa_wakeup(unsl, &tcp_input_list, &tcp_output_list, &tcp_input_retrans_list, &tcp_output_retrans_list, oplus_nw_wakeup, true); + reset_count(service_wakeup_times, &tcp_input_list, &tcp_output_list, &tcp_input_retrans_list, &tcp_output_retrans_list, oplus_nw_wakeup); + app_wakeup_monitor_list.count = 0; + memset(app_wakeup_monitor_list.set, 0x0, sizeof(app_wakeup_monitor_list.set)); + if (unsl) { + nwpower_send_to_user(NW_POWER_UNSL_MONITOR, (char*)wakeup_unsl_msg, sizeof(wakeup_unsl_msg)); + memset(wakeup_unsl_msg, 0x0, sizeof(wakeup_unsl_msg)); + } +} + +static void nwpower_unsl_mdaci() { + print_qrtr_wakeup(true, mdaci_service_wakeup_times, oplus_mdaci_nw_wakeup, true); + print_ipa_wakeup(true, &mdaci_tcp_input_list, &mdaci_tcp_output_list, + &mdaci_tcp_input_retrans_list, &mdaci_tcp_output_retrans_list, oplus_mdaci_nw_wakeup, true); + reset_count(mdaci_service_wakeup_times, &mdaci_tcp_input_list, &mdaci_tcp_output_list, + &mdaci_tcp_input_retrans_list, &mdaci_tcp_output_retrans_list, oplus_mdaci_nw_wakeup); + nwpower_send_to_user(NW_POWER_REPORT_MDACI, (char*)wakeup_unsl_msg, sizeof(wakeup_unsl_msg)); + memset(wakeup_unsl_msg, 0x0, sizeof(wakeup_unsl_msg)); + nwpower_send_to_user(NW_POWER_REPORT_MDACI_APP_WAKEUP, (char*)mdaci_app_wakeup_monitor_list.set, sizeof(mdaci_app_wakeup_monitor_list.set)); + mdaci_app_wakeup_monitor_list.count = 0; + memset(mdaci_app_wakeup_monitor_list.set, 0x0, sizeof(mdaci_app_wakeup_monitor_list.set)); +} + +static int nwpower_send_to_user(int msg_type,char *msg_data, int msg_len) { + int ret = 0; + struct sk_buff *skb; + struct nlmsghdr *nlh; + if (oplus_nwpower_pid == 0) { + printk("[oplus_nwpower] netlink: oplus_nwpower_pid = 0.\n"); + return -1; + } + skb = alloc_skb(NLMSG_SPACE(msg_len), GFP_ATOMIC); + if (skb == NULL) { + printk("[oplus_nwpower] netlink: alloc_skb failed.\n"); + return -2; + } + nlh = nlmsg_put(skb, 0, 0, msg_type, NLMSG_ALIGN(msg_len), 0); + if (nlh == NULL) { + printk("[oplus_nwpower] netlink: nlmsg_put failed.\n"); + nlmsg_free(skb); + return -3; + } + nlh->nlmsg_len = NLMSG_HDRLEN + NLMSG_ALIGN(msg_len); + if(msg_data != NULL) { + memcpy((char*)NLMSG_DATA(nlh), msg_data, msg_len); + } + NETLINK_CB(skb).portid = 0; + NETLINK_CB(skb).dst_group = 0; + ret = netlink_unicast(oplus_nwpower_sock, skb, oplus_nwpower_pid, MSG_DONTWAIT); + if(ret < 0) { + printk(KERN_ERR "[oplus_nwpower] netlink: netlink_unicast failed, ret = %d.\n",ret); + return -4; + } + return 0; +} + +static int nwpower_netlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, struct netlink_ext_ack *extack) { + int ret = 0; + switch (nlh->nlmsg_type) { + case NW_POWER_ANDROID_PID: + oplus_nwpower_pid = NETLINK_CB(skb).portid; + printk("[oplus_nwpower] netlink: oplus_nwpower_pid = %d", oplus_nwpower_pid); + break; + case NW_POWER_BOOT_MONITOR: + nwpower_hook_on(); + printk("[oplus_nwpower] netlink: hook_on"); + break; + case NW_POWER_STOP_MONITOR: + nwpower_hook_off(false); + printk("[oplus_nwpower] netlink: hook_off"); + break; + case NW_POWER_STOP_MONITOR_UNSL: + nwpower_hook_off(true); + printk("[oplus_nwpower] netlink: hook_off_unsl"); + break; + case NW_POWER_BLACK_LIST: + ret = nwpower_set_blacklist_uids(nlh); + break; + case NW_POWER_REQUEST_BLACK_REJECT: + nwpower_unsl_blacklist_reject(); + printk("[oplus_nwpower] netlink: unsl_blacklist_reject"); + break; + case NW_POWER_REQUEST_APP_WAKEUP: + nwpower_unsl_app_wakeup(); + printk("[oplus_nwpower] netlink: unsl_app_wakeup"); + break; + case NW_POWER_REQUEST_MDACI: + nwpower_unsl_mdaci(); + printk("[oplus_nwpower] netlink: unsl_mdaci"); + break; + default: + return -EINVAL; + } + return ret; +} + +static void nwpower_netlink_rcv(struct sk_buff *skb) { + mutex_lock(&netlink_mutex); + netlink_rcv_skb(skb, &nwpower_netlink_rcv_msg); + mutex_unlock(&netlink_mutex); +} + +static int nwpower_netlink_init(void) { + struct netlink_kernel_cfg cfg = { + .input = nwpower_netlink_rcv, + }; + oplus_nwpower_sock = netlink_kernel_create(&init_net, NETLINK_OPLUS_NWPOWERSTATE, &cfg); + return oplus_nwpower_sock == NULL ? -ENOMEM : 0; +} + +static void nwpower_netlink_exit(void) { + netlink_kernel_release(oplus_nwpower_sock); + oplus_nwpower_sock = NULL; +} + +static int __init nwpower_init(void) { + int ret = 0; + ret = nwpower_netlink_init(); + if (ret < 0) { + printk("[oplus_nwpower] netlink: failed to init netlink.\n"); + } else { + printk("[oplus_nwpower] netlink: init netlink successfully.\n"); + } + return ret; +} + +static void __exit nwpower_fini(void) { + nwpower_netlink_exit(); +} + +module_init(nwpower_init); +module_exit(nwpower_fini); diff --git a/net/oplus_router_boost/Makefile b/net/oplus_router_boost/Makefile new file mode 100644 index 000000000000..d75f166e7207 --- /dev/null +++ b/net/oplus_router_boost/Makefile @@ -0,0 +1,19 @@ +#/************************************************************************************ +#** File: - Makefile +#** VENDOR_EDIT +#** Copyright (C), 2008-2020, OPLUS Mobile Comm Corp., Ltd +#** +#** Description: +#** 1. Add for oplus router boost +#** +#** Version: 1.0 +#** Date : 2020-05-09 +#** TAG : OPLUS_FEATURE_WIFI_ROUTERBOOST +#** +#** ---------------------Revision History: --------------------- +#** +#** --------------------------------------------------------------- +#** +#************************************************************************************/ + +obj-y += oplus_router_boost.o \ No newline at end of file diff --git a/net/oplus_router_boost/oplus_router_boost.c b/net/oplus_router_boost/oplus_router_boost.c new file mode 100644 index 000000000000..f171750fac14 --- /dev/null +++ b/net/oplus_router_boost/oplus_router_boost.c @@ -0,0 +1,221 @@ +/************************************************************************************ +** File: - oplus_router_boost.c +** VENDOR_EDIT +** Copyright (C), 2008-2020, OPLUS Mobile Comm Corp., Ltd +** +** Description: +** 1. Add for oplus router boost +** +** Version: 1.0 +** Date : 2020-05-09 +** TAG : OPLUS_FEATURE_WIFI_ROUTERBOOST +** +** ---------------------Revision History: --------------------- +** +** --------------------------------------------------------------- +** +************************************************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "net/oplus/oplus_router_boost.h" + +#define DBG_DETAIL (0) +#define LOG_TAG "[oplus_router_boost] %s line:%d " + +#if DBG_DETAIL +#define debug(fmt, args...) printk(LOG_TAG fmt, __FUNCTION__, __LINE__, ##args) +#else +#define debug(fmt, args...) +#endif + +static u32 g_router_boost_app_uid = 0; +static int g_router_boost_enabled = 0; +static int g_router_boost_tcp_enabled = 0; + +int (*oplus_router_boost_handler)(struct sock *sk, struct sk_buff *skb) = NULL; + + +/* every connection has 64 recently ids + * the smaller it is, we more likely fail to dedeup pkt + * which is not very critical + */ +#define DEDUP_IDS_LEN 128 +/* + * we stores 128 connections at max + * the smaller it is, we more likely drop necessary pkt + * which is critical + */ +#define MAX_CONNECTIONS 16 + +/* + * this struct maintains server's recent id list + * As for linux, ip-to-ip pair owns one ip id generator + */ +struct connection_ids { + __be32 src_ip; + int32_t recently_ids[DEDUP_IDS_LEN]; /*use 32-bit and init with -1, to avoid 0-id ambiguity*/ + unsigned char next_index; +}; + +static DEFINE_SPINLOCK(g_id_list_lock); +static struct connection_ids g_id_list[MAX_CONNECTIONS]; +static unsigned short g_next_conn_index = 0; +static unsigned long g_dup_pkt_recv_cnt = 0; +static unsigned long g_dup_pkt_drop_cnt = 0; + +int handle_router_boost(struct sock *sk, struct sk_buff *skb) { + kuid_t sk_uid, uid; + int cid = -1; /*not found*/ + int i = 0; + + if(!g_router_boost_enabled) { + return 0; + } + + if (!g_router_boost_tcp_enabled && ip_hdr(skb)->protocol == IPPROTO_TCP) { + return 0; + } + + if (g_router_boost_app_uid == 0) { + return 0; + } + + sk_uid = sk->sk_uid; + uid = make_kuid(&init_user_ns, g_router_boost_app_uid); + + if (!uid_eq(sk_uid, uid)) { + return 0; + } + + spin_lock_bh(&g_id_list_lock); + /* Firstly, get the related connection */ + for(i = 0; i < MAX_CONNECTIONS; i++) { + if(g_id_list[i].src_ip == ip_hdr(skb)->saddr) { + cid = i; + break; + } + } + + if (cid >= 0) { + unsigned char next_index = 0; + + /* Secondly, search id list, if match, then drop pkt */ + for(i = 0; i < DEDUP_IDS_LEN; i++) { + if(g_id_list[cid].recently_ids[i] == ip_hdr(skb)->id) { + ++g_dup_pkt_drop_cnt; + debug("drop id = %u, drop = %u, recv = %u\n", ntohs(ip_hdr(skb)->id), g_dup_pkt_drop_cnt, g_dup_pkt_recv_cnt); + spin_unlock_bh(&g_id_list_lock); + return -1; + } + } + /* found connection, but no match id, so record it and pass up*/ + next_index = g_id_list[cid].next_index; + + g_id_list[cid].recently_ids[next_index] = ip_hdr(skb)->id; + g_id_list[cid].src_ip = ip_hdr(skb)->saddr; + g_id_list[cid].next_index = (next_index + 1) % DEDUP_IDS_LEN; + } else { + /* add new connection into set*/ + g_id_list[g_next_conn_index].src_ip = ip_hdr(skb)->saddr; + /* init id list with -1 */ + for(i = 0; i < DEDUP_IDS_LEN; i++) { + g_id_list[g_next_conn_index].recently_ids[i] = -1; + } + g_id_list[g_next_conn_index].recently_ids[0] = ip_hdr(skb)->id; + g_id_list[g_next_conn_index].next_index = 1; + + g_next_conn_index = (g_next_conn_index + 1) % MAX_CONNECTIONS; + } + spin_unlock_bh(&g_id_list_lock); + + ++g_dup_pkt_recv_cnt; + + debug("recv id = %u, drop = %u, recv = %u\n", ntohs(ip_hdr(skb)->id), g_dup_pkt_drop_cnt, g_dup_pkt_recv_cnt); + return 0; +} + + +void oplus_router_boost_set_params(struct nlmsghdr *nlh) { + int *data = (int *)NLMSG_DATA(nlh); + + g_router_boost_enabled = data[0]; + g_router_boost_app_uid = data[1]; + g_router_boost_tcp_enabled = data[2]; + printk("oplus_router_boost: g_router_boost_enabled = %d, g_router_boost_app_uid = %d, g_router_boost_tcp_enabled=%d\n", data[0], data[1], data[2]); +} + +void oplus_router_boost_set_enable(struct nlmsghdr *nlh) +{ + int *data = (int *)NLMSG_DATA(nlh); + + /* + * 1 ---> enable + * 0 ---> disable + */ + g_router_boost_enabled = data[0]; + + debug("enable = %d\n", data[0]); +} + +void oplus_router_boost_set_app_uid(struct nlmsghdr *nlh) +{ + int *data = (int *)NLMSG_DATA(nlh); + + /* + * 1 ---> enable + * 0 ---> disable + */ + g_router_boost_app_uid = data[0]; + + debug("oplus_router_boost_app_uid = %d\n", data[0]); +} + +int oplus_router_boost_get_enable(void) { + return g_router_boost_enabled; +} + +int oplus_router_boost_get_app_uid(void) { + return g_router_boost_app_uid; +} + +static int __init oplus_router_boost_init(void) +{ + oplus_router_boost_handler = handle_router_boost; + spin_lock_init(&g_id_list_lock); + return 0; +} + +static void __exit oplus_router_boost_fini(void) +{ + oplus_router_boost_handler = NULL; +} + +module_init(oplus_router_boost_init); +module_exit(oplus_router_boost_fini); + diff --git a/net/oplus_score/Kconfig b/net/oplus_score/Kconfig new file mode 100644 index 000000000000..60481e8916b9 --- /dev/null +++ b/net/oplus_score/Kconfig @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: GPL-2.0-only +# Copyright (C) 2020-2022 Oplus. All rights reserved. + +config OPLUS_FEATURE_DATA_EVAL + tristate "Add for network score" + help + Add for Add for network score. diff --git a/net/oplus_score/Makefile b/net/oplus_score/Makefile new file mode 100644 index 000000000000..a13fad1b44f4 --- /dev/null +++ b/net/oplus_score/Makefile @@ -0,0 +1,5 @@ +# +# Add for kernel data info send to user space. +# +obj-$(CONFIG_OPLUS_FEATURE_DATA_EVAL) += oplus_score.o + diff --git a/net/oplus_score/oplus_score.c b/net/oplus_score/oplus_score.c new file mode 100644 index 000000000000..f4f76495967d --- /dev/null +++ b/net/oplus_score/oplus_score.c @@ -0,0 +1,1436 @@ +/*********************************************************** +** Copyright (C), 2008-2019, oplus Mobile Comm Corp., Ltd. +** File: oplus_score.c +** Description: Add for kernel data info send to user space. +** +** Version: 1.0 +** Date : 2019/10/02 +** +** ------------------ Revision History:------------------------ +** +** penghao 2019/10/02 1.0 build this module +****************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define IFNAME_LEN 16 +#define IPV4ADDRTOSTR(addr) \ +((unsigned char *)&addr)[0], \ +((unsigned char *)&addr)[1], \ +((unsigned char *)&addr)[2], \ +((unsigned char *)&addr)[3] + +#define OPLUS_TRUE 1 +#define OPLUS_FALSE 0 +#define REPORT_PERIOD 1 +#define SCORE_WINDOW 3 +#define OPLUS_UPLINK 1 +#define OPLUS_DOWNLINK 0 + +struct link_score_msg_st +{ + u32 link_index; + s32 uplink_score; + s32 downlink_score; +}; + +struct score_param_st +{ + u32 score_debug; + u32 threshold_retansmit; + u32 threshold_normal; + u32 smooth_factor; + u32 protect_score; + u32 threshold_gap; +}; + +struct uplink_score_info_st{ + u32 link_index; + u32 uplink_rtt_stamp; + u32 uplink_retrans_packets; + u32 uplink_packets; + s32 uplink_score_save[SCORE_WINDOW]; + u32 uplink_score_index; + u32 uplink_srtt; + u32 uplink_rtt_num; + u32 seq; + s32 uplink_score_count; + u32 uplink_nodata_count; + char ifname[IFNAME_LEN]; +}; + +struct downlink_score_info_st{ + u32 link_index; + u32 downlink_update_stamp; + u32 downlink_retrans_packets; + u32 downlink_packets; + s32 downlink_score_save[SCORE_WINDOW]; + u32 downlink_score_index; + u32 downlink_srtt; + u32 downlink_rtt_num; + u32 seq; + s32 downlink_score_count; + u32 downlink_nodata_count; + char ifname[IFNAME_LEN]; +}; + +#define MAX_LINK_SCORE 100 +#define MAX_LINK_NUM 4 +#define FOREGROUND_UID_MAX_NUM 10 + +static int oplus_score_uplink_num = 0; +static int oplus_score_downlink_num = 0; +static int oplus_score_enable_flag = 1; +static u32 oplus_score_foreground_uid[FOREGROUND_UID_MAX_NUM]; +static u32 oplus_score_user_pid = 0; +static spinlock_t uplink_score_lock; +static struct uplink_score_info_st uplink_score_info[MAX_LINK_NUM]; +static spinlock_t downlink_score_lock; +static struct downlink_score_info_st downlink_score_info[MAX_LINK_NUM]; +static struct score_param_st oplus_score_param_info; +static struct ctl_table_header *oplus_score_table_hrd = NULL; +//static u32 time_gap = 5; /* sec */ +/* static u32 last_report_time = 0; */ +static struct timer_list oplus_score_report_timer; +static int oplus_score_debug = 0; +static u32 para_rtt = 8; +static u32 para_rate = 8; +static u32 para_loss = 16; + +#define WORST_VIDEO_RTT_THRESH 1000 +#define WORST_RTT_THRESH 400 +#define WORSE_RTT_THRESH 300 +#define NORMAL_RTT_THRESH 200 +#define BAD_GAME_RTT_THREAD 170 +#define WORST_BASE_SCORE 59 +#define WORSE_BASE_SCORE 70 +#define NORMAL_BASE_SCORE 80 +#define GOOD_BASE_SCORE 100 + +/*for test*/ +static u32 test_foreground_uid = 0; +static u32 test_link_index = 0; +#define PACKET_PER_SEC 240 +#define VIDEO_GOOD_RATE 400 +#define LOWER_RATE_PACKET 20 +#define LOWEST_RATE_PACKET 10 +#define SCORE_KEEP 3 +#define VALID_RTT_THRESH 10 + + +enum score_msg_type_et{ + OPLUS_SCORE_MSG_UNSPEC, + OPLUS_SCORE_MSG_ENABLE, + OPLUS_SCORE_MSG_FOREGROUND_ANDROID_UID, + OPLUS_SCORE_MSG_REQUEST_SCORE, + OPLUS_SCORE_MSG_ADD_LINK, + OPLUS_SCORE_MSG_DEL_LINK, + OPLUS_SCORE_MSG_CLEAR_LINK, + OPLUS_SCORE_MSG_CONFIG, + OPLUS_SCORE_MSG_REPORT_NETWORK_SCORE, + __OPLUS_SCORE_MSG_MAX, +}; +#define OPLUS_SCORE_MSG_MAX (__OPLUS_SCORE_MSG_MAX - 1) + +enum score_cmd_type_et{ + OPLUS_SCORE_CMD_UNSPEC, + OPLUS_SCORE_CMD_DOWNLINK, + __OPLUS_SCORE_CMD_MAX, +}; +#define OPLUS_SCORE_CMD_MAX (__OPLUS_SCORE_CMD_MAX - 1) + +#define OPLUS_SCORE_FAMILY_VERSION 1 +#define OPLUS_SCORE_FAMILY_NAME "net_score" +#define NLA_DATA(na) ((char *)((char*)(na) + NLA_HDRLEN)) +#define GENL_ID_GENERATE 0 +static int oplus_score_netlink_rcv_msg(struct sk_buff *skb, struct genl_info *info); +static const struct genl_ops oplus_score_genl_ops[] = +{ + { + .cmd = OPLUS_SCORE_CMD_DOWNLINK, + .flags = 0, + .doit = oplus_score_netlink_rcv_msg, + .dumpit = NULL, + }, +}; + +static struct genl_family oplus_score_genl_family = +{ + .id = 0, + .hdrsize = 0, + .name = OPLUS_SCORE_FAMILY_NAME, + .version = OPLUS_SCORE_FAMILY_VERSION, + .maxattr = OPLUS_SCORE_MSG_MAX, + .ops = oplus_score_genl_ops, + .n_ops = ARRAY_SIZE(oplus_score_genl_ops), +}; + +static int oplus_score_send_netlink_msg(int msg_type, char *payload, int payload_len); +/* score = 100 - rtt * 10 / 500 - 100 * loss_rate * 8*/ + +static s32 oplus_get_smooth_score(int link, int flag) +{ + int i; + int j = 0; + u32 score_sum = 0; + if (flag) { + for (i = 0; i < SCORE_WINDOW; i++) { + if (uplink_score_info[link].uplink_score_save[i] > 0) { + score_sum += uplink_score_info[link].uplink_score_save[i]; + j++; + } + } + } else { + for (i = 0; i < SCORE_WINDOW; i++) { + if (downlink_score_info[link].downlink_score_save[i] > 0) { + score_sum += downlink_score_info[link].downlink_score_save[i]; + j++; + } + } + } + + if (j == 0) { + return -1; + } else { + return score_sum / j; + } +} + +static int oplus_update_score_count(int link, int score, int flag) +{ + int ret = OPLUS_FALSE; + if (score == -1) { + return OPLUS_TRUE; + } + + if (flag) { + if(score > WORSE_BASE_SCORE) { + uplink_score_info[link].uplink_score_count++; + if (uplink_score_info[link].uplink_score_count > SCORE_KEEP) { + uplink_score_info[link].uplink_score_count = SCORE_KEEP; + } + } + else if (score <= WORST_BASE_SCORE && score >= 0) { + uplink_score_info[link].uplink_score_count--; + if (uplink_score_info[link].uplink_score_count < -SCORE_KEEP) { + uplink_score_info[link].uplink_score_count = -SCORE_KEEP; + } + } + + if (((score > WORST_BASE_SCORE) && (uplink_score_info[link].uplink_score_count >= 0)) || + ((score <= WORST_BASE_SCORE) && (uplink_score_info[link].uplink_score_count <= 0))) { + ret = OPLUS_TRUE; + } + + if (oplus_score_debug) { + printk("[oplus_score]:uplink_report=%d,score=%d,score_count=%d\n", + ret, score, uplink_score_info[link].uplink_score_count); + } + } else { + if(score > WORSE_BASE_SCORE) { + downlink_score_info[link].downlink_score_count++; + if (downlink_score_info[link].downlink_score_count > SCORE_KEEP) { + downlink_score_info[link].downlink_score_count = SCORE_KEEP; + } + } + else if (score <= WORST_BASE_SCORE && score >= 0) { + downlink_score_info[link].downlink_score_count--; + if (downlink_score_info[link].downlink_score_count < -SCORE_KEEP) { + downlink_score_info[link].downlink_score_count = -SCORE_KEEP; + } + } + + if (((score <= WORST_BASE_SCORE) && (downlink_score_info[link].downlink_score_count <= 0)) || + ((score > WORST_BASE_SCORE) && (downlink_score_info[link].downlink_score_count >= 0))) { + ret = OPLUS_TRUE; + } + + if (oplus_score_debug) { + printk("[oplus_score]:downlink_report=%d,score=%d,score_count=%d\n", + ret, score, downlink_score_info[link].downlink_score_count); + } + } + + return ret; +} + +void oplus_score_calc_and_report(void) +{ + struct link_score_msg_st link_score_msg; + int i; + u32 uplink_index, downlink_index; + u32 uplink_packets, uplink_retrans_packets, uplink_srtt; + u32 downlink_packets, downlink_retrans_packets, downlink_srtt; + s32 uplink_score, downlink_score; + u32 uplink_seq, downlink_seq; + u32 retrans_rate = 0; + s32 uplink_smooth_score, downlink_smooth_score; + u32 index = 0; + int uplink_report, downlink_report; + char ifname[IFNAME_LEN]; + u32 uplink_nodata_count; + u32 downlink_nodata_count; + int downlink_rate = 0; + u32 uplink_total_packets = 0; + u32 downlink_total_packets = 0; + + /* printk("[oplus_score]:enter oplus_score_calc_and_report,jiffies=%llu\n", jiffies);*/ + for (i = 0; i < MAX_LINK_NUM; i++) { + uplink_smooth_score = -1; + downlink_smooth_score = -1; + uplink_report = 0; + downlink_report = 0; + spin_lock_bh(&downlink_score_lock); + if (downlink_score_info[i].link_index == 0) { + spin_unlock_bh(&downlink_score_lock); + continue; + } + downlink_index = downlink_score_info[i].link_index; + downlink_packets = downlink_score_info[i].downlink_packets; + downlink_retrans_packets = downlink_score_info[i].downlink_retrans_packets; + downlink_total_packets = downlink_packets + downlink_retrans_packets; + downlink_srtt = downlink_score_info[i].downlink_srtt; + downlink_seq = downlink_score_info[i].seq; + downlink_score_info[i].downlink_packets = 0; + downlink_score_info[i].downlink_retrans_packets = 0; + /*downlink_score_info[i].downlink_srtt = 0;*/ + downlink_score_info[i].downlink_rtt_num = 1; + downlink_nodata_count = downlink_score_info[i].downlink_nodata_count; + spin_unlock_bh(&downlink_score_lock); + + spin_lock_bh(&uplink_score_lock); + if (uplink_score_info[i].link_index == 0) { + spin_unlock_bh(&uplink_score_lock); + continue; + } + uplink_index = uplink_score_info[i].link_index; + if (uplink_index != downlink_index) { + printk("[oplus_score]:link error:uplink_index=%u,downlink_index=%u\n", + uplink_index, downlink_index); + spin_unlock_bh(&uplink_score_lock); + continue; + } + memcpy((void*)ifname, (void*)uplink_score_info[i].ifname, IFNAME_LEN); + uplink_packets = uplink_score_info[i].uplink_packets; + uplink_retrans_packets = uplink_score_info[i].uplink_retrans_packets; + uplink_total_packets = uplink_packets + uplink_retrans_packets; + uplink_srtt = uplink_score_info[i].uplink_srtt; + uplink_seq = uplink_score_info[i].seq; + uplink_nodata_count = uplink_score_info[i].uplink_nodata_count; + uplink_score_info[i].uplink_packets = 0; + uplink_score_info[i].uplink_retrans_packets = 0; + /*uplink_score_info[i].uplink_srtt = 0;*/ + if (uplink_score_info[i].uplink_rtt_num) { + uplink_score_info[i].uplink_rtt_num = 1; + } + + if (uplink_total_packets == 0) { + if (oplus_score_debug) { + printk("[oplus_score]:uplink no_data\n"); + } + uplink_score = -1; + uplink_score_info[i].uplink_nodata_count++; + } else { + uplink_score_info[i].uplink_nodata_count = 0; + retrans_rate = 100 * uplink_retrans_packets / uplink_total_packets; + if (uplink_packets > ((para_rate * PACKET_PER_SEC) >> 3)) { + uplink_score = (s32)(GOOD_BASE_SCORE - (retrans_rate * para_loss) / 8); + } /*else if (uplink_srtt > BAD_GAME_RTT_THREAD && (uplink_total_packets < 10) && (downlink_total_packets < 10)) { + uplink_score = (s32)(WORST_BASE_SCORE - (WORST_BASE_SCORE * retrans_rate * para_loss) / 800); + } */else { + if (uplink_srtt > WORST_VIDEO_RTT_THRESH) { + uplink_score = (s32)(WORST_BASE_SCORE - (WORST_BASE_SCORE * retrans_rate * para_loss) / 800); + } else if (uplink_srtt > WORST_RTT_THRESH) { + downlink_rate = downlink_packets * 1000 / uplink_srtt; + if (downlink_rate == 0) { + uplink_score = -1; + } else if (downlink_rate > VIDEO_GOOD_RATE) { + uplink_score = (s32)(GOOD_BASE_SCORE - (GOOD_BASE_SCORE * retrans_rate * para_loss) / 800); + } else if (downlink_rate > PACKET_PER_SEC) { + uplink_score = (s32)(NORMAL_BASE_SCORE - (NORMAL_BASE_SCORE * retrans_rate * para_loss) / 800); + } else { + uplink_score = (s32)(WORST_BASE_SCORE - (WORST_BASE_SCORE * retrans_rate * para_loss) / 800); + } + } else if (uplink_srtt > WORSE_RTT_THRESH) { + uplink_score = (s32)(WORSE_BASE_SCORE - (WORSE_BASE_SCORE * retrans_rate * para_loss) / 800); + } else if (uplink_srtt > NORMAL_RTT_THRESH) { + uplink_score = (s32)(NORMAL_BASE_SCORE - (NORMAL_BASE_SCORE * retrans_rate * para_loss) / 800); + } else { + uplink_score = (s32)(GOOD_BASE_SCORE - (retrans_rate * para_loss) / 8); + } + } + if (uplink_score <= 0) { + uplink_score = 1; + } + } + + uplink_report = oplus_update_score_count(i, uplink_score, OPLUS_UPLINK); + if (uplink_report) { + index = uplink_score_info[i].uplink_score_index++ % SCORE_WINDOW; + uplink_score_info[i].uplink_score_save[index] = uplink_score; + } + uplink_smooth_score = oplus_get_smooth_score(i, OPLUS_UPLINK); + if (uplink_smooth_score == -1) { + uplink_report = 0; + } + spin_unlock_bh(&uplink_score_lock); + + if (oplus_score_debug || (uplink_smooth_score > 0 && uplink_smooth_score <= WORST_BASE_SCORE)) { + if (net_ratelimit()) + printk("[oplus_score]:up_score:link=%u,if=%s,up_pack=%u,up_retran=%u,up_rtt=%u,score=%d,s_score=%d,seq=%u,uid=%u,retrans_rate=%u,index=%u,nodata=%u\n", + uplink_index, ifname, uplink_packets, uplink_retrans_packets, uplink_srtt, uplink_score, + uplink_smooth_score, uplink_seq, oplus_score_foreground_uid[0], retrans_rate, index, uplink_nodata_count); + } + + /*start downlink score calc*/ + if (downlink_total_packets == 0) { + if (oplus_score_debug) { + printk("[oplus_score]:downlink no_data,if=%s\n", ifname); + } + downlink_score = -1; + downlink_score_info[i].downlink_nodata_count++; + } else { + downlink_score_info[i].downlink_nodata_count = 0; + retrans_rate = 100 * downlink_retrans_packets / downlink_total_packets; + if (downlink_packets > ((para_rate * PACKET_PER_SEC) >> 3)) { + downlink_score = (s32)(GOOD_BASE_SCORE - retrans_rate * para_loss / 4); + } else { + if (uplink_srtt > WORST_RTT_THRESH) { + downlink_score = (s32)(WORST_BASE_SCORE - (WORST_BASE_SCORE * retrans_rate * para_loss) / 800); + } else { + downlink_score = (s32)(100 - (2 * downlink_retrans_packets * uplink_srtt) / 10); + } + } + + if (downlink_score < 0) { + downlink_score = 1; + } + } + + if ((downlink_total_packets < 15) && (downlink_score > WORST_BASE_SCORE)) { + downlink_score = -1; + } + + spin_lock_bh(&downlink_score_lock); + downlink_report = oplus_update_score_count(i, downlink_score, OPLUS_DOWNLINK); + if (downlink_report) { + index = downlink_score_info[i].downlink_score_index++ % SCORE_WINDOW; + downlink_score_info[i].downlink_score_save[index] = downlink_score; + } + downlink_smooth_score = oplus_get_smooth_score(i, OPLUS_DOWNLINK); + if (downlink_smooth_score == -1) { + downlink_report = 0; + } + spin_unlock_bh(&downlink_score_lock); + + if (oplus_score_debug || (downlink_smooth_score > 0 && downlink_smooth_score <= WORST_BASE_SCORE)) { + if (net_ratelimit()) + printk("[oplus_score]:down_score:link=%u,if=%s,down_pack=%u,down_retran=%u,rtt=%u,score=%d,s_score=%d,seq=%u,uid=%u,retrans_rate=%u,index=%u,nodata=%u\n", + downlink_index, ifname, downlink_packets, downlink_retrans_packets, uplink_srtt, downlink_score, + downlink_smooth_score, downlink_seq, oplus_score_foreground_uid[0], retrans_rate, index, downlink_nodata_count); + } + + if (uplink_report || downlink_report) { + link_score_msg.link_index = uplink_index; + if (uplink_smooth_score == -1) { + link_score_msg.uplink_score = downlink_smooth_score; + } else { + link_score_msg.uplink_score = uplink_smooth_score; + } + + if (downlink_smooth_score == -1) { + link_score_msg.downlink_score = uplink_smooth_score; + } else { + link_score_msg.downlink_score = downlink_smooth_score; + } + + oplus_score_send_netlink_msg(OPLUS_SCORE_MSG_REPORT_NETWORK_SCORE, (char *)&link_score_msg, sizeof(link_score_msg)); + if (oplus_score_debug || (downlink_smooth_score <= WORST_BASE_SCORE) || (uplink_smooth_score <= WORST_BASE_SCORE)) { + if (net_ratelimit()) + printk("[oplus_score]:report_score1:link=%u,if=%s,up_score=%d,down_score=%d,uid=%u,ul_p=%d,dl_p=%d\n", + uplink_index, ifname, link_score_msg.uplink_score, link_score_msg.downlink_score, + oplus_score_foreground_uid[0], uplink_report, downlink_report); + } + } + + if (oplus_score_debug) { + printk("[oplus_score]:report_score_all:link=%u,uplink_score=%d,us_score=%d,downlink_score=%d,ds_score=%d,uid=%u,ul_p=%d,dl_p=%d\n", + uplink_index, uplink_score, uplink_smooth_score, downlink_score, + downlink_smooth_score, oplus_score_foreground_uid[0], uplink_report, downlink_report); + } + } + + return; +} + +static void oplus_score_report_timer_function(struct timer_list *t) +{ + oplus_score_calc_and_report(); + mod_timer(&oplus_score_report_timer, jiffies + REPORT_PERIOD * HZ); +} + +static void oplus_score_report_timer_init(void) +{ + printk("[oplus_score]:report_timer_init\n"); + timer_setup(&oplus_score_report_timer, oplus_score_report_timer_function, 0); +} + +static void oplus_score_report_timer_start(void) +{ + printk("[oplus_score]:report_timer_start\n"); + /*oplus_score_report_timer.function = (void *)oplus_score_report_timer_function;*/ + oplus_score_report_timer.expires = jiffies + REPORT_PERIOD * HZ; + mod_timer(&oplus_score_report_timer, oplus_score_report_timer.expires); +} + +static void oplus_score_report_timer_del(void) +{ + printk("[oplus_score]:report_timer_del\n"); + del_timer_sync(&oplus_score_report_timer); +} + +static inline int genl_msg_prepare_usr_msg(u8 cmd, size_t size, pid_t pid, struct sk_buff **skbp) +{ + struct sk_buff *skb; + /* create a new netlink msg */ + skb = genlmsg_new(size, GFP_ATOMIC); + if (skb == NULL) { + return -ENOMEM; + } + + /* Add a new netlink message to an skb */ + genlmsg_put(skb, pid, 0, &oplus_score_genl_family, 0, cmd); + *skbp = skb; + return 0; +} + +static inline int genl_msg_mk_usr_msg(struct sk_buff *skb, int type, void *data, int len) +{ + int ret; + /* add a netlink attribute to a socket buffer */ + if ((ret = nla_put(skb, type, len, data)) != 0) { + return ret; + } + + return 0; +} + +static inline int uplink_get_array_index_by_link_index(int link_index) +{ + int array_index = -1; + int i; + + for (i = 0; i < MAX_LINK_NUM; i++) { + if (uplink_score_info[i].link_index == link_index) { + return i; + } + } + + return array_index; +} + +static inline int downlink_get_array_index_by_link_index(int link_index) +{ + int array_index = -1; + int i; + + for (i = 0; i < MAX_LINK_NUM; i++) { + if (downlink_score_info[i].link_index == link_index) { + return i; + } + } + + return array_index; +} + +static inline int is_foreground_uid(int uid) +{ + int i; + for (i = 0; i < FOREGROUND_UID_MAX_NUM; i++) { + if (uid == oplus_score_foreground_uid[i]) { + return OPLUS_TRUE; + } + } + + return OPLUS_FALSE; +} + +/* send to user space */ +static int oplus_score_send_netlink_msg(int msg_type, char *payload, int payload_len) +{ + int ret = 0; + void * head; + struct sk_buff *skbuff; + size_t size; + + if (!oplus_score_user_pid) { + printk("[oplus_score]: oplus_score_send_netlink_msg,oplus_score_user_pid=0\n"); + return -1; + } + + /* allocate new buffer cache */ + size = nla_total_size(payload_len); + ret = genl_msg_prepare_usr_msg(OPLUS_SCORE_CMD_DOWNLINK, size, oplus_score_user_pid, &skbuff); + if (ret) { + return ret; + } + + ret = genl_msg_mk_usr_msg(skbuff, msg_type, payload, payload_len); + if (ret) { + kfree_skb(skbuff); + return ret; + } + + head = genlmsg_data(nlmsg_data(nlmsg_hdr(skbuff))); + genlmsg_end(skbuff, head); + + /* send data */ + ret = genlmsg_unicast(&init_net, skbuff, oplus_score_user_pid); + if(ret < 0) { + printk("[oplus_score]:oplus_score_send_netlink_msg error, ret = %d\n", ret); + return -1; + } + + return 0; +} + +static void oplus_score_uplink_stat(struct sk_buff *skb) +{ + int link_index; + int i; + struct sock *sk; + struct tcp_sock *tp; + struct tcphdr *tcph = tcp_hdr(skb); + struct inet_connection_sock *icsk; + u32 srtt; + + sk = skb_to_full_sk(skb); + tp = tcp_sk(sk); + icsk = inet_csk(sk); + link_index = skb->dev->ifindex; + + spin_lock_bh(&uplink_score_lock); + i = uplink_get_array_index_by_link_index(link_index); + if (i < 0) { + if (oplus_score_debug) { + printk("[oplus_score]:upskb_linkerr,link=%d,if=%s,seq=%u,ack=%u,sport=%u,dport=%u,uid=%u\n", + link_index, skb->dev->name, ntohl(tcph->seq), ntohl(tcph->ack_seq), ntohs(tcph->source), + ntohs(tcph->dest), (u32)(sk->sk_uid.val)); + } + spin_unlock_bh(&uplink_score_lock); + return; + } + + if (icsk->icsk_ca_state >= TCP_CA_Recovery && tp->high_seq !=0 && before(ntohl(tcph->seq), tp->high_seq)) { + uplink_score_info[i].uplink_retrans_packets++; + } else { + uplink_score_info[i].uplink_packets++; + } + if (oplus_score_debug) { + printk("[oplus_score]:uplink=%d,if=%s,seq=%u,high_seq=%u,uplink_retran=%u,npacket=%u,uid=%u,sport=%u,dport=%u,state=%d,len=%u\n", + link_index, skb->dev->name, ntohl(tcph->seq), tp->high_seq, uplink_score_info[i].uplink_retrans_packets, + uplink_score_info[i].uplink_packets, (u32)(sk->sk_uid.val), ntohs(tcph->source), + ntohs(tcph->dest), sk->sk_state, skb->len); + } + + uplink_score_info[i].seq = ntohl(tcph->seq); + srtt = (tp->srtt_us >> 3) / 1000; + if (oplus_score_debug) { + printk("[oplus_score]:rtt_sample_up:rtt=%u,rtt_num=%u,uid=%u\n", + srtt, uplink_score_info[i].uplink_rtt_num, (u32)(sk->sk_uid.val)); + } + + if (srtt > VALID_RTT_THRESH) { + uplink_score_info[i].uplink_rtt_num++; + if (uplink_score_info[i].uplink_rtt_num != 0) { + uplink_score_info[i].uplink_srtt = + (uplink_score_info[i].uplink_srtt * (uplink_score_info[i].uplink_rtt_num -1) + srtt) / uplink_score_info[i].uplink_rtt_num; + uplink_score_info[i].uplink_rtt_stamp = (u32)jiffies; + } + } + spin_unlock_bh(&uplink_score_lock); + + return; +} + + +static int is_downlink_retrans_pack(u32 skb_seq, struct sock *sk) +{ + struct tcp_sock *tp = (struct tcp_sock*)sk; + struct inet_connection_sock *icsk = inet_csk(sk); + u32 now = (u32)jiffies; + + if((skb_seq == tp->rcv_nxt) && (!RB_EMPTY_ROOT(&tp->out_of_order_queue))) { + int m = (int)(now - icsk->icsk_ack.lrcvtime) * 1000 / HZ; + int half_rtt = (tp->srtt_us / 8000) >> 1; + if ((tp->srtt_us != 0) && (m > 50)) { + if (oplus_score_debug) { + printk("[oplus_score]:now=%u,lrcttime=%u,half_rtt=%d,m=%d,Hz=%u,rtt=%u,seq=%u\n", + now, icsk->icsk_ack.lrcvtime, half_rtt, m, HZ, tp->srtt_us, skb_seq); + } + return OPLUS_TRUE; + } + } + + return OPLUS_FALSE; +} + +static void oplus_score_downlink_stat(struct sk_buff *skb) +{ + int link_index; + int i; + struct sock *sk; + struct tcp_sock *tp; + struct tcphdr *tcph = tcp_hdr(skb); + struct inet_connection_sock *icsk; + u32 srtt; + + sk = skb_to_full_sk(skb); + tp = tcp_sk(sk); + icsk = inet_csk(sk); + link_index = skb->dev->ifindex; + + spin_lock_bh(&downlink_score_lock); + i = downlink_get_array_index_by_link_index(link_index); + if (i < 0) { + if (oplus_score_debug) { + printk("[oplus_score]:downskb_linkerr,link=%d,if=%s,seq=%u,ack=%u,sport=%u,dport=%u,uid=%u\n", + link_index, skb->dev->name, ntohl(tcph->seq), ntohl(tcph->ack_seq), ntohs(tcph->source), + ntohs(tcph->dest), (u32)(sk->sk_uid.val)); + } + spin_unlock_bh(&downlink_score_lock); + return; + } + + if ((sk->sk_state != TCP_SYN_SENT) && (is_downlink_retrans_pack(ntohl(tcph->seq), sk))) { + downlink_score_info[i].downlink_retrans_packets++; + } else { + downlink_score_info[i].downlink_packets++; + } + if (oplus_score_debug) { + printk("[oplus_score]:downlink=%d,if=%s,seq=%u,rcv_nxt=%u,downlink_retran=%u,npacket=%u,uid=%u,sport=%u,dport=%u,state=%d,len=%u\n", + link_index, skb->dev->name, ntohl(tcph->seq), tp->rcv_nxt, downlink_score_info[i].downlink_retrans_packets, + downlink_score_info[i].downlink_packets, (u32)(sk->sk_uid.val), ntohs(tcph->source), + ntohs(tcph->dest), sk->sk_state, skb->len); + } + + downlink_score_info[i].seq = ntohl(tcph->seq); + srtt = (tp->rcv_rtt_est.rtt_us >> 3) / 1000; + if (oplus_score_debug) { + printk("[oplus_score]:rtt_sample_down:rtt=%u,rtt_num=%u,uid=%u\n", + srtt, downlink_score_info[i].downlink_rtt_num, (u32)(sk->sk_uid.val)); + } + + if (srtt) { + downlink_score_info[i].downlink_rtt_num++; + if (downlink_score_info[i].downlink_rtt_num != 0) { + downlink_score_info[i].downlink_srtt = + (downlink_score_info[i].downlink_srtt * (downlink_score_info[i].downlink_rtt_num -1) + srtt) / downlink_score_info[i].downlink_rtt_num; + } + downlink_score_info[i].downlink_update_stamp = (u32)jiffies; + } + spin_unlock_bh(&downlink_score_lock); + + return; +} + +uid_t get_uid_from_sock(const struct sock *sk) +{ + uid_t sk_uid; + #if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 9, 0)) + const struct file *filp = NULL; + #endif + if (NULL == sk || !sk_fullsock(sk) || NULL == sk->sk_socket) { + return 0; + } + #if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 9, 0)) + filp = sk->sk_socket->file; + if (NULL == filp) { + return 0; + } + sk_uid = __kuid_val(filp->f_cred->fsuid); + #else + sk_uid = __kuid_val(sk->sk_uid); + #endif + return sk_uid; +} + +static inline int skb_v4_check(struct sk_buff *skb) +{ + uid_t sk_uid; + struct sock *sk; + struct iphdr *iph = NULL; + struct tcphdr *tcph = NULL; + struct net_device *dev; + + iph = ip_hdr(skb); + tcph = tcp_hdr(skb); + if (skb->protocol != htons(ETH_P_IP) || (!iph)) + return OPLUS_FALSE; + + if (iph->protocol != IPPROTO_TCP || !tcph) + return OPLUS_FALSE; + + sk = skb_to_full_sk(skb); + if (!sk) { + return OPLUS_FALSE; + } + + if (sk->sk_state > TCP_SYN_SENT) { + return OPLUS_FALSE; + } + + /* skb is pure ack*/ + if ((ntohs(iph ->tot_len) == (iph->ihl + tcph->doff) * 4) && (!tcph->syn || !tcph->fin)) + return OPLUS_FALSE; + + sk_uid = get_uid_from_sock(sk); + if(sk_uid == 0) { + return OPLUS_FALSE; + } + + /* check uid is foreground*/ + if (!is_foreground_uid(sk_uid)) + return OPLUS_FALSE; + + dev = skb->dev; + if (!dev) { + return OPLUS_FALSE; + } + + return OPLUS_TRUE; +} + +static inline int skb_v6_check(struct sk_buff *skb) +{ + uid_t sk_uid; + struct sock *sk; + struct tcphdr *tcph = NULL; + struct ipv6hdr *ipv6h = NULL; + struct net_device *dev; + + ipv6h = ipv6_hdr(skb); + tcph = tcp_hdr(skb); + if (skb->protocol != htons(ETH_P_IPV6) || (!ipv6h)) + return OPLUS_FALSE; + + if ((ipv6h->nexthdr != NEXTHDR_TCP) || (!tcph)) + return OPLUS_FALSE; + + sk = skb_to_full_sk(skb); + if (!sk) { + return OPLUS_FALSE; + } + + if (sk->sk_state > TCP_SYN_SENT) { + return OPLUS_FALSE; + } + + /* skb is pure ack*/ + if ((ntohs(ipv6h ->payload_len) == tcph->doff * 4) && (!tcph->syn || !tcph->fin)) + return OPLUS_FALSE; + + /* check uid is foreground*/ + sk_uid = get_uid_from_sock(sk); + if (!is_foreground_uid(sk_uid)) + return OPLUS_FALSE; + + dev = skb->dev; + if (!dev) { + return OPLUS_FALSE; + } + + return OPLUS_TRUE; +} + +static unsigned int oplus_score_postrouting_hook4(void *priv, struct sk_buff *skb, const struct nf_hook_state *state) +{ + if (!oplus_score_enable_flag) + return NF_ACCEPT; + + if (skb_v4_check(skb) == OPLUS_FALSE) { + return NF_ACCEPT; + } + + oplus_score_uplink_stat(skb); + + return NF_ACCEPT; +} + +static unsigned int oplus_score_postrouting_hook6(void *priv, struct sk_buff *skb, const struct nf_hook_state *state) +{ + if (!oplus_score_enable_flag) + return NF_ACCEPT; + + if (skb_v6_check(skb) == OPLUS_FALSE) { + return NF_ACCEPT; + } + + oplus_score_uplink_stat(skb); + + return NF_ACCEPT; +} + +static unsigned int oplus_score_input_hook4(void *priv, struct sk_buff *skb, const struct nf_hook_state *state) +{ + if (!oplus_score_enable_flag) { + return NF_ACCEPT; + } + + if (skb_v4_check(skb) == OPLUS_FALSE) { + return NF_ACCEPT; + } + + oplus_score_downlink_stat(skb); + + return NF_ACCEPT; +} + +static unsigned int oplus_score_input_hook6(void *priv, struct sk_buff *skb, const struct nf_hook_state *state) +{ + if (!oplus_score_enable_flag) + return NF_ACCEPT; + + if (skb_v6_check(skb) == OPLUS_FALSE) + return NF_ACCEPT; + + oplus_score_downlink_stat(skb); + + return NF_ACCEPT; +} + +static struct nf_hook_ops oplus_score_netfilter_ops[] __read_mostly = +{ + { + .hook = oplus_score_postrouting_hook4, + .pf = NFPROTO_IPV4, + .hooknum = NF_INET_POST_ROUTING, + .priority = NF_IP_PRI_FILTER + 1, + }, + { + .hook = oplus_score_input_hook4, + .pf = NFPROTO_IPV4, + .hooknum = NF_INET_LOCAL_IN, + .priority = NF_IP_PRI_FILTER + 1, + }, + { + .hook = oplus_score_postrouting_hook6, + .pf = NFPROTO_IPV6, + .hooknum = NF_INET_POST_ROUTING, + .priority = NF_IP_PRI_FILTER + 1, + }, + { + .hook = oplus_score_input_hook6, + .pf = NFPROTO_IPV6, + .hooknum = NF_INET_LOCAL_IN, + .priority = NF_IP_PRI_FILTER + 1, + }, +}; + +static void oplus_score_enable(struct nlattr *nla) +{ + u32 *data = (u32*)NLA_DATA(nla); + oplus_score_enable_flag = data[0]; + printk("[oplus_score]:oplus_score_enable_flag = %u", oplus_score_enable_flag); + return; +} + +static void oplus_score_set_foreground_uid(struct nlattr *nla) +{ + u32 *data; + int i, num; + + data = (u32 *)NLA_DATA(nla); + num = data[0]; + if (num <= 0 || num > FOREGROUND_UID_MAX_NUM) { + printk("[oplus_score]: foreground uid num out of range, num = %d", num); + return; + } + + memset(oplus_score_foreground_uid, 0, sizeof(oplus_score_foreground_uid)); + for (i = 0; i < num; i++) { + oplus_score_foreground_uid[i] = data[i + 1]; + printk("[oplus_score]: add uid, num = %d, index = %d, uid=%u\n", num, i, data[i + 1]); + } + + /* forground uid change, so reset score static */ + spin_lock_bh(&uplink_score_lock); + for (i = 0; i < MAX_LINK_NUM; i++) { + uplink_score_info[i].uplink_retrans_packets = 0; + uplink_score_info[i].uplink_packets = 0; + uplink_score_info[i].uplink_nodata_count = 0; + /*uplink_score_info[i].uplink_score = MAX_LINK_SCORE;*/ + if (uplink_score_info[i].uplink_rtt_num) { + uplink_score_info[i].uplink_rtt_num = 1; + } + } + spin_unlock_bh(&uplink_score_lock); + + spin_lock_bh(&downlink_score_lock); + for (i = 0; i < MAX_LINK_NUM; i++) { + downlink_score_info[i].downlink_retrans_packets = 0; + downlink_score_info[i].downlink_packets = 0; + downlink_score_info[i].downlink_nodata_count = 0; + /*downlink_score_info[i].downlink_score = MAX_LINK_SCORE;*/ + } + spin_unlock_bh(&downlink_score_lock); + + return; +} + +static void oplus_score_request_score(struct nlattr *nla) +{ + u32 *data; + u32 link_index; + int i; + + struct link_score_msg_st link_score_msg; + data = (u32 *)NLA_DATA(nla); + link_index = data[0]; + + spin_lock_bh(&uplink_score_lock); + i = uplink_get_array_index_by_link_index(link_index); + if (i < 0) { + /* printk("[oplus_score]:uplink get index falure!\n"); */ + spin_unlock_bh(&uplink_score_lock); + return; + } + link_score_msg.uplink_score = oplus_get_smooth_score(link_index, OPLUS_UPLINK); + spin_unlock_bh(&uplink_score_lock); + + spin_lock_bh(&downlink_score_lock); + i = downlink_get_array_index_by_link_index(link_index); + if (i < 0) { + /* printk("[oplus_score]:downlink get index falure!\n");*/ + spin_unlock_bh(&downlink_score_lock); + return; + } + link_score_msg.downlink_score = oplus_get_smooth_score(link_index, OPLUS_DOWNLINK); + spin_unlock_bh(&downlink_score_lock); + + link_score_msg.link_index = link_index; + printk("[oplus_score]:request_report:link=%d,uscore=%d,dscore=%d\n", link_index, link_score_msg.uplink_score, link_score_msg.downlink_score); + oplus_score_send_netlink_msg(OPLUS_SCORE_MSG_REPORT_NETWORK_SCORE, (char *)&link_score_msg, sizeof(link_score_msg)); + return; +} + +static void oplus_score_add_uplink(u32 link_index, struct net_device *dev) +{ + int i, j; + if (oplus_score_uplink_num == MAX_LINK_NUM) { + printk("[oplus_score]:error, uplink num reach max.\n"); + return; + } + + for (i = 0; i < MAX_LINK_NUM; i++) { + if (uplink_score_info[i].link_index == link_index) { + printk("[oplus_score]:warning,uplink already exist,index = %u.\n", link_index); + return; + } + } + + for (i =0; i < MAX_LINK_NUM; i++) { + if (uplink_score_info[i].link_index != 0) + continue; + + memset(&uplink_score_info[i], 0, sizeof(struct uplink_score_info_st)); + uplink_score_info[i].link_index = link_index; + memcpy((void*)uplink_score_info[i].ifname, (void*)dev->name, IFNAME_LEN); + for (j = 0; j < SCORE_WINDOW; j++) { + uplink_score_info[i].uplink_score_save[j] = -1; + } + oplus_score_uplink_num++; + printk("[oplus_score]:up:add_link finish,link_index=%u,i=%d,link_num=%u", link_index, i, oplus_score_uplink_num); + break; + } + + return; +} + +static void oplus_score_add_downlink(u32 link_index, struct net_device *dev) +{ + int i, j; + if (oplus_score_downlink_num == MAX_LINK_NUM) { + printk("[oplus_score]:error, downlink num reach max.\n"); + return; + } + + for (i = 0; i < MAX_LINK_NUM; i++) { + if (downlink_score_info[i].link_index == link_index) { + printk("[oplus_score]:warning,downlink already exist,index = %u.\n", link_index); + return; + } + } + + for (i =0; i < MAX_LINK_NUM; i++) { + if (downlink_score_info[i].link_index != 0) + continue; + + memset(&downlink_score_info[i], 0, sizeof(struct downlink_score_info_st)); + downlink_score_info[i].link_index = link_index; + memcpy((void*)uplink_score_info[i].ifname, (void*)dev->name, IFNAME_LEN); + for (j = 0; j < SCORE_WINDOW; j++) { + downlink_score_info[i].downlink_score_save[j] = -1; + } + oplus_score_downlink_num++; + printk("[oplus_score]:down:add_link finish,link_index=%u,i=%d,link_num=%u", link_index, i, oplus_score_downlink_num); + break; + } +} + +static void oplus_score_add_link(struct nlattr *nla) +{ + u32 *data; + u32 link_index; + struct net_device *dev; + + data = (u32 *)NLA_DATA(nla); + link_index = data[0]; + + if (link_index == 0) { + printk("[oplus_score]:error, link index is 0!\n"); + return; + } + + dev = dev_get_by_index(&init_net, link_index); + if(!dev) { + printk("[oplus_score]:dev is null,index=%d\n", link_index); + return; + } + + printk("[oplus_score]:to add_link index=%u,dev_name=%s, uplink_num=%d,downlink_num=%d!\n", + link_index, dev->name, oplus_score_uplink_num, oplus_score_downlink_num); + + spin_lock_bh(&uplink_score_lock); + oplus_score_add_uplink(link_index, dev); + spin_unlock_bh(&uplink_score_lock); + + spin_lock_bh(&downlink_score_lock); + oplus_score_add_downlink(link_index, dev); + spin_unlock_bh(&downlink_score_lock); + + dev_put(dev); + + return; +} + +static void oplus_score_del_link(struct nlattr *nla) +{ + u32 *data; + u32 i, link_index; + + data = (u32 *)NLA_DATA(nla); + link_index = data[0]; + + printk("[oplus_score]:to del_link index=%u,uplink_num=%d,downlink_num=%d!\n", + link_index, oplus_score_uplink_num, oplus_score_downlink_num); + + if (link_index == 0) { + printk("[oplus_score]:error, link index is 0!\n"); + return; + } + + spin_lock_bh(&uplink_score_lock); + for (i = 0; i < MAX_LINK_NUM; i++) { + if (uplink_score_info[i].link_index == link_index) { + memset(&uplink_score_info[i], 0, sizeof(struct uplink_score_info_st)); + oplus_score_uplink_num--; + } + } + spin_unlock_bh(&uplink_score_lock); + + spin_lock_bh(&downlink_score_lock); + for (i = 0; i < MAX_LINK_NUM; i++) { + if (downlink_score_info[i].link_index == link_index) { + memset(&downlink_score_info[i], 0, sizeof(struct downlink_score_info_st)); + oplus_score_downlink_num--; + } + } + spin_unlock_bh(&downlink_score_lock); + + return; +} + +static void oplus_score_clear_link(struct nlattr *nla) +{ + int i; + + spin_lock_bh(&uplink_score_lock); + for (i = 0; i < MAX_LINK_NUM; i++) { + memset(&uplink_score_info[i], 0, sizeof(struct uplink_score_info_st)); + } + oplus_score_uplink_num = 0; + spin_unlock_bh(&uplink_score_lock); + + spin_lock_bh(&downlink_score_lock); + for (i = 0; i < MAX_LINK_NUM; i++) { + memset(&downlink_score_info[i], 0, sizeof(struct downlink_score_info_st)); + } + oplus_score_downlink_num = 0; + spin_unlock_bh(&downlink_score_lock); + + return; +} + +static void oplus_score_config(struct nlattr *nla) +{ + struct score_param_st *config; + config = (struct score_param_st*)NLA_DATA(nla); + oplus_score_param_info = *config; + oplus_score_debug = oplus_score_param_info.score_debug; + return; +} + +static int oplus_score_netlink_rcv_msg(struct sk_buff *skb, struct genl_info *info) +{ + int ret = 0; + struct nlmsghdr *nlhdr; + struct genlmsghdr *genlhdr; + struct nlattr *nla; + + nlhdr = nlmsg_hdr(skb); + genlhdr = nlmsg_data(nlhdr); + nla = genlmsg_data(genlhdr); + + if (oplus_score_user_pid == 0) { + oplus_score_user_pid = nlhdr->nlmsg_pid; + if (oplus_score_debug) { + printk("[oplus_score]:set oplus_score_user_pid=%u.\n", oplus_score_user_pid); + } + } + + /* to do: may need to some head check here*/ + if (oplus_score_debug) { + printk("[oplus_score]:score_netlink_rcv_msg type=%u.\n", nla->nla_type); + } + switch (nla->nla_type) { + case OPLUS_SCORE_MSG_ENABLE: + oplus_score_enable(nla); + break; + case OPLUS_SCORE_MSG_FOREGROUND_ANDROID_UID: + oplus_score_set_foreground_uid(nla); + break; + case OPLUS_SCORE_MSG_REQUEST_SCORE: + oplus_score_request_score(nla); + break; + case OPLUS_SCORE_MSG_ADD_LINK: + oplus_score_add_link(nla); + break; + case OPLUS_SCORE_MSG_DEL_LINK: + oplus_score_del_link(nla); + break; + case OPLUS_SCORE_MSG_CLEAR_LINK: + oplus_score_clear_link(nla); + break; + case OPLUS_SCORE_MSG_CONFIG: + oplus_score_config(nla); + break; + default: + return -EINVAL; + } + + return ret; +} + +static int oplus_score_netlink_init(void) +{ + int ret; + ret = genl_register_family(&oplus_score_genl_family); + if (ret) { + printk("[oplus_score]:genl_register_family:%s failed,ret = %d\n", OPLUS_SCORE_FAMILY_NAME, ret); + return ret; + } else { + printk("[oplus_score]:genl_register_family complete, id = %d!\n", oplus_score_genl_family.id); + } + + return 0; +} + +static void oplus_score_netlink_exit(void) +{ + genl_unregister_family(&oplus_score_genl_family); +} + +static int proc_set_test_foreground_uid(struct ctl_table *ctl, int write, void __user *buffer, size_t *lenp,loff_t *ppos) +{ + int ret; + u32 data[3]; + struct nlattr *nla = (struct nlattr*)data; + + ret = proc_dointvec(ctl, write, buffer, lenp, ppos); + printk("[oplus_score]:proc_set_test_foreground_uid,write=%d,ret=%d\n", write, ret); + if (ret == 0) { + data[1] = 1; + data[2] = test_foreground_uid; + if (test_foreground_uid) { + oplus_score_set_foreground_uid(nla); + } + } + + return ret; +} + +static int proc_set_test_link_index(struct ctl_table *ctl, int write, void __user *buffer, size_t *lenp,loff_t *ppos) +{ + int ret; + u32 data[2]; + struct nlattr *nla = (struct nlattr*)data; + u32 old_link_index = test_link_index; + + ret = proc_dointvec(ctl, write, buffer, lenp, ppos); + if (oplus_score_debug) { + printk("[oplus_score]:proc_set_test_link,write=%d,ret=%d\n", write, ret); + } + if (ret == 0) { + if (test_link_index) { + data[1] = test_link_index; + oplus_score_add_link(nla); + } + else{ + data[1] = old_link_index; + oplus_score_del_link(nla); + } + } + + return ret; +} + +static struct ctl_table oplus_score_sysctl_table[] = +{ + { + .procname = "oplus_score_debug", + .data = &oplus_score_debug, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec, + }, + { + .procname = "oplus_para_rtt", + .data = ¶_rtt, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec, + }, + { + .procname = "oplus_score_para_rate", + .data = ¶_rate, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec, + }, + { + .procname = "oplus_score_para_loss", + .data = ¶_loss, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec, + }, + { + .procname = "test_foreground_uid", + .data = &test_foreground_uid, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_set_test_foreground_uid, + }, + { + .procname = "test_link_index", + .data = &test_link_index, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_set_test_link_index, + }, + { } +}; + +static int oplus_score_sysctl_init(void) +{ + oplus_score_table_hrd = register_net_sysctl(&init_net, "net/oplus_score", oplus_score_sysctl_table); + return oplus_score_table_hrd == NULL ? -ENOMEM : 0; +} + +static void oplus_score_param_init(void) +{ + oplus_score_uplink_num = 0; + oplus_score_uplink_num = 0; + oplus_score_enable_flag = 1; + oplus_score_user_pid = 0; + memset(oplus_score_foreground_uid, 0, sizeof(oplus_score_foreground_uid)); + memset(&uplink_score_info, 0, sizeof(uplink_score_info)); + memset(&downlink_score_info, 0, sizeof(downlink_score_info)); + oplus_score_param_info.score_debug = 0; + oplus_score_param_info.threshold_retansmit = 10; + oplus_score_param_info.threshold_normal = 100; + oplus_score_param_info.smooth_factor = 20; + oplus_score_param_info.protect_score = 60; + oplus_score_param_info.threshold_gap = 5; +} + +static int __init oplus_score_init(void) +{ + int ret = 0; + + ret = oplus_score_netlink_init(); + if (ret < 0) { + printk("[oplus_score]:init module failed to init netlink, ret =% d\n", ret); + return ret; + } else { + printk("[oplus_score]:init module init netlink successfully.\n"); + } + + oplus_score_param_init(); + spin_lock_init(&uplink_score_lock); + spin_lock_init(&downlink_score_lock); + ret = nf_register_net_hooks(&init_net, oplus_score_netfilter_ops, ARRAY_SIZE(oplus_score_netfilter_ops)); + if (ret < 0) { + printk("oplus_score_init netfilter register failed, ret=%d\n", ret); + oplus_score_netlink_exit(); + return ret; + } else { + printk("oplus_score_init netfilter register successfully.\n"); + } + + oplus_score_sysctl_init(); + oplus_score_report_timer_init(); + oplus_score_report_timer_start(); + return ret; +} + +static void __exit oplus_score_fini(void) +{ + oplus_score_netlink_exit(); + nf_unregister_net_hooks(&init_net, oplus_score_netfilter_ops, ARRAY_SIZE(oplus_score_netfilter_ops)); + if (oplus_score_table_hrd) { + unregister_net_sysctl_table(oplus_score_table_hrd); + } + oplus_score_report_timer_del(); +} + +module_init(oplus_score_init); +module_exit(oplus_score_fini); +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("oplus_score"); diff --git a/net/oplus_sla/Makefile b/net/oplus_sla/Makefile new file mode 100644 index 000000000000..2a015946d5b1 --- /dev/null +++ b/net/oplus_sla/Makefile @@ -0,0 +1,4 @@ +# +# Makefile for the netfilter modules on top of IPv4. +# +obj-y += oplus_sla.o diff --git a/net/oplus_sla/oplus_sla.c b/net/oplus_sla/oplus_sla.c new file mode 100644 index 000000000000..e4218ed675b9 --- /dev/null +++ b/net/oplus_sla/oplus_sla.c @@ -0,0 +1,4959 @@ +/****************************************************************************** +** Copyright (C), 2019-2029, OPLUS Mobile Comm Corp., Ltd +** VENDOR_EDIT, All rights reserved. +** File: - oplus_sla.c +** Description: sla +** +** Version: 1.0 +** Date : 2018/04/03 +** TAG: OPLUS_FEATURE_WIFI_SLA +** ------------------------------- Revision History: ---------------------------- +** +** ------------------------------------------------------------------------------ + *******************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef OPLUS_FEATURE_APP_MONITOR +#include +#endif /* OPLUS_FEATURE_APP_MONITOR */ + +#ifdef OPLUS_FEATURE_WIFI_ROUTERBOOST +#include +#endif /* OPLUS_FEATURE_WIFI_ROUTERBOOST */ + +#define MARK_MASK 0x0fff +#define RETRAN_MASK 0xf000 +#define RTT_MASK 0xf000 +#define GAME_UNSPEC_MASK 0x8000 + +#define WLAN_NUM 2 +#define WLAN0_INDEX 0 +#define WLAN1_INDEX 1 +#define CELL_INDEX 2 +#define DOWNLOAD_FLAG 5 +#define MAX_SYN_RETRANS 5 +#define RTT_NUM 5 + +#define NORMAL_RTT 100 +#define BACK_OFF_RTT_1 200 //200ms +#define BACK_OFF_RTT_2 300 //300ms +#define SYN_RETRAN_RTT 300 //500ms +#define MAX_RTT 500 + +#define DNS_TIME 10 +#define CALC_DEV_SPEED_TIME 1 +#define DOWNLOAD_SPEED_TIME 2 +#define RECALC_WEIGHT_TIME 5 //5 seconds to recalc weight +#define MAX_SYN_NEW_COUNT 10 //statitis new syn count max number +#define LITTLE_FLOW_TIME 60 //small flow detect time internal + +#define ADJUST_SPEED_NUM 5 +#define DOWNLOAD_SPEED 200 // download speed level min +#define VIDEO_SPEED 300 +#define DUAL_WLAN_MAX_DOWNLOAD_SPEED 2200 // 2MB/S + +#define MAX_CELLULAR_SPEED 500 //LTE CALC WEITHT MAX SPEED +#define MAX_WLAN_SPEED 1000 //WIFI CALC WEITHT MAX SPEED +#define LOW_RSSI_MAX_WLAN_SPEED 500 + + +#define CALC_WEIGHT_MIN_SPEED_1 10 //10KB/s +#define CALC_WEIGHT_MIN_SPEED_2 50 //50KB/s +#define CALC_WEIGHT_MIN_SPEED_3 100 //100KB/s + +#define GAME_NUM 7 +#define IFACE_NUM 3 +#define IFACE_LEN 16 +#define WHITE_APP_BASE 100 +#define DUAL_STA_APP_BASE 200 +#define WHITE_APP_NUM 64 +#define DUAL_STA_APP_NUM 256 +#define MAX_GAME_RTT 300 +#define MAX_DETECT_PKTS 100 +#define UDP_RX_WIN_SIZE 20 +#define TCP_RX_WIN_SIZE 5 +#define TCP_DOWNLOAD_THRESHOLD (100*1024) //100KB/s +#define SLA_TIMER_EXPIRES HZ +#define MINUTE_LITTE_RATE 60 //60Kbit/s +#define INIT_APP_TYPE 0 +#define UNKNOW_APP_TYPE -1 +#define WLAN_SCORE_BAD_NUM 5 +#define GAME_SKB_TIME_OUT 120 //120s +#define WLAN_SCORE_GOOD 75 +#define WLAN_SCORE_BAD 55 +#define DUAL_WLAN_SCORE_BAD 55 +#define DNS_MAX_NUM 10 +#define WLAN_NETWORK_INVALID 10 + +#define MIN_GAME_RTT 10 //ms +#define ENABLE_TO_USER_TIMEOUT 25 //second + +#define MAX_FIXED_VALUE_LEN 20 + +#define UID_MASK 100000 + + +/* dev info struct + * if we need to consider wifi RSSI ?if we need consider screen state? +*/ +struct oplus_dev_info{ + bool need_up; + bool need_disable; + int max_speed; //KB/S + int download_speed; //KB/S + int dl_mx_speed; + int download_num; + int little_speed_num; + int tmp_little_speed; + int dl_little_speed; //for detect little speed + int dual_wifi_download; + int current_speed; + int left_speed; + int minute_speed; //kbit/s + int download_flag; + int congestion_flag; + int if_up; + int syn_retran; + int wlan_score; + int wlan_score_bad_count; + int weight; + int weight_state; + int rtt_index; + u32 mark; + u32 avg_rtt; + u32 sum_rtt; //ms + u32 sla_rtt_num; //ms + u32 sla_sum_rtt; //ms + u32 sla_avg_rtt; //ms + u64 total_bytes; + u64 minute_rx_bytes; + u64 dl_total_bytes; + char dev_name[IFACE_LEN]; +}; + +struct oplus_speed_calc{ + int speed; + int speed_done; + int ms_speed_flag; + u64 rx_bytes; + u64 bytes_time; + u64 first_time; + u64 last_time; + u64 sum_bytes; +}; + +struct oplus_sla_game_info{ + u32 game_type; + u32 uid; + u32 rtt; + u32 mark; + u32 switch_time; + u32 rtt_150_num; + u32 rtt_200_num; + u32 rtt_250_num; + u64 rtt_normal_num; + u64 cell_bytes; +}; + + +struct oplus_white_app_info{ + u32 count; + u32 uid[WHITE_APP_NUM]; + u64 cell_bytes[WHITE_APP_NUM]; + u64 cell_bytes_normal[WHITE_APP_NUM]; +}; + +struct oplus_dual_sta_info{ + u32 count; + u32 uid[DUAL_STA_APP_NUM]; +}; + + +struct oplus_game_online{ + bool game_online; + struct timeval last_game_skb_tv; + u32 udp_rx_pkt_count; //count of all received game udp packets + u64 tcp_rx_byte_count; //count of all received game tcp bytes +}; + +struct game_traffic_info{ + bool game_in_front; + u32 udp_rx_packet[UDP_RX_WIN_SIZE]; //udp packets received per second + u64 tcp_rx_byte[TCP_RX_WIN_SIZE]; //tcp bytes received per second + u32 window_index; + u32 udp_rx_min; //min rx udp packets as valid game udp rx data + u32 udp_rx_low_thr; //udp rx packet count low threshold + u32 in_game_true_thr; //greater than this -> inGame==true + u32 in_game_false_thr; //less than this -> inGame==false + u32 rx_bad_thr; //greater than this -> game_rx_bad==true +}; + +struct oplus_syn_retran_statistic{ + u32 syn_retran_num; + u32 syn_total_num; +}; + +struct sla_dns_statistic{ + bool in_timer; + u32 send_num; + struct timeval last_tv; +}; + +struct oplus_rate_limit_info{ + int front_uid; + int rate_limit_enable; //oplus_rate_limit enable or not + int disable_rtt_num; + int disable_rtt_sum; + int disable_rtt; //oplus_rate_limit disable front avg rtt + int enable_rtt_num; + int enable_rtt_sum; + int enable_rtt; //oplus_rate_limit enable front avg rtt + struct timeval last_tv; +}; + +struct oplus_sla_rom_update_info{ + u32 sla_speed; //sla speed threshold + u32 cell_speed; //cell max speed threshold + u32 wlan_speed; //wlan max speed threshold; + u32 wlan_little_score_speed; //wlan little score speed threshold; + u32 sla_rtt; //sla rtt threshold + u32 wzry_rtt; //wzry rtt threshold + u32 cjzc_rtt; //cjzc rtt threshold + u32 wlan_bad_score; //wifi bad score threshold + u32 wlan_good_score; //wifi good socre threshold + u32 second_wlan_speed; //wlan max speed threshold + u32 dual_wlan_download_speed; //dual wifi download max speed + u32 dual_wifi_rtt; //sla dual wifi rtt threshold + u32 dual_wlan_bad_score; //dual wifi bad score threshold +}; + +struct oplus_sla_game_rtt_params { + int game_index; + int tx_offset; + int tx_len; + u8 tx_fixed_value[MAX_FIXED_VALUE_LEN]; + int rx_offset; + int rx_len; + u8 rx_fixed_value[MAX_FIXED_VALUE_LEN]; +}; + +struct oplus_smart_bw_rom_update_info { + u32 feature_enable; + u32 debug_level; + u32 ll_com_score_thre; + u32 acs_weight_thre; + u32 mov_avg_beta; + u32 thre_tune_dist; + u32 sample_interval; + u32 good_mcs; + u32 bad_mcs; +}; + +enum{ + SLA_SKB_ACCEPT, + SLA_SKB_CONTINUE, + SLA_SKB_MARKED, + SLA_SKB_REMARK, + SLA_SKB_DROP, +}; + +enum{ + SLA_WEIGHT_NORMAL, + SLA_WEIGHT_RECOVERY, +}; + +enum{ + WEIGHT_STATE_NORMAL, + WEIGHT_STATE_USELESS, + WEIGHT_STATE_RECOVERY, + WEIGHT_STATE_SCORE_INVALID, +}; + +enum{ + CONGESTION_LEVEL_NORMAL, + CONGESTION_LEVEL_MIDDLE, + CONGESTION_LEVEL_HIGH, +}; + +enum{ + WLAN_SCORE_LOW, + WLAN_SCORE_HIGH, +}; + + +enum{ + + WLAN0_MARK_BIT = 8, //WLAN mark value,mask 0x0fff + WLAN0_MARK = (1 << WLAN0_MARK_BIT), + + WLAN1_MARK_BIT = 9, //WLAN mark value,mask 0x0fff + WLAN1_MARK = (1 << WLAN1_MARK_BIT), + + CELL_MARK_BIT = 10, //cellular mark value mask 0x0fff + CELL_MARK = (1 << CELL_MARK_BIT), + + RETRAN_BIT = 12, //first retran mark value, mask 0xf000 + RETRAN_MARK = (1 << RETRAN_BIT), + + RETRAN_SECOND_BIT = 13, //second retran mark value, mask 0xf000 + RETRAN_SECOND_MARK = (1 << RETRAN_SECOND_BIT), + + RTT_MARK_BIT = 14, //one ct only statitisc once rtt,mask 0xf000 + RTT_MARK = (1 << RTT_MARK_BIT), + + GAME_UNSPEC_MARK_BIT = 15, //mark game skb when game not start + GAME_UNSPEC_MARK = (1 << GAME_UNSPEC_MARK_BIT), +}; + + +/*NLMSG_MIN_TYPE is 0x10,so we start at 0x11*/ +enum{ + SLA_NOTIFY_WIFI_SCORE = 0x11, + SLA_NOTIFY_PID = 0x12, + SLA_ENABLE = 0x13, + SLA_DISABLE = 0x14, + SLA_IFACE_CHANGED = 0x15, + SLA_NOTIFY_APP_UID = 0x1A, + SLA_NOTIFY_GAME_RTT = 0x1B, + SLA_NOTIFY_WHITE_LIST_APP = 0x1C, + SLA_ENABLED = 0x1D, + SLA_DISABLED = 0x1E, + SLA_ENABLE_GAME_RTT = 0x1F, + SLA_DISABLE_GAME_RTT = 0x20, + SLA_NOTIFY_SWITCH_STATE = 0x21, + SLA_NOTIFY_SPEED_RTT = 0x22, + SLA_SWITCH_GAME_NETWORK = 0x23, + SLA_NOTIFY_SCREEN_STATE = 0x24, + SLA_NOTIFY_CELL_QUALITY = 0x25, + SLA_SHOW_DIALOG_NOW = 0x26, + SLA_NOTIFY_SHOW_DIALOG = 0x27, + SLA_SEND_WHITE_LIST_APP_TRAFFIC = 0x28, + SLA_SEND_GAME_APP_STATISTIC = 0x29, + SLA_GET_SYN_RETRAN_INFO = 0x2A, + SLA_GET_SPEED_UP_APP = 0x2B, + SLA_SET_DEBUG = 0x2C, + SLA_NOTIFY_DEFAULT_NETWORK = 0x2D, + SLA_NOTIFY_PARAMS = 0x2E, + SLA_NOTIFY_GAME_STATE = 0x2F, + SLA_NOTIFY_GAME_PARAMS = 0x30, + SLA_NOTIFY_GAME_RX_PKT = 0x31, + SLA_NOTIFY_GAME_IN_FRONT = 0x32, + SLA_NOTIFY_PRIMARY_WIFI = 0x33, + SLA_NOTIFY_DUAL_STA_APP = 0x34, + //Add for WLAN Assistant Four Issues + SLA_WEIGHT_BY_WLAN_ASSIST = 0x35, + //end add + SLA_NOTIFY_VPN_CONNECTED = 0x36, + SLA_NOTIFY_DOWNLOAD_APP = 0x37, + SLA_NOTIFY_VEDIO_APP = 0x38, + SLA_LIMIT_SPEED_ENABLE = 0x39, + SLA_LIMIT_SPEED_DISABLE = 0x40, + SLA_LIMIT_SPEED_FRONT_UID = 0x41, + SMART_BW_SET_PARAMS = 0x42, + #ifdef OPLUS_FEATURE_WIFI_ROUTERBOOST + SLA_NOTIFY_ROUTER_BOOST_DUPPKT_PARAMS = 0x43, + #endif /* OPLUS_FEATURE_WIFI_ROUTERBOOST */ +}; + + +enum{ + GAME_SKB_DETECTING = 0, + GAME_SKB_COUNT_ENOUGH = 1, + GAME_RTT_STREAM = 2, + GAME_VOICE_STREAM = 4, +}; + +enum{ + GAME_UNSPEC = 0, + GAME_WZRY = 1, + GAME_CJZC, + GAME_QJCJ, + GAME_HYXD_NM, + GAME_HYXD, + GAME_HYXD_ALI, +}; + +enum{ + SLA_MODE_INIT = 0, + SLA_MODE_DUAL_WIFI = 1, + + /*if the dual wifi is enable,please do not send + disable msg to kernel when rcv SLA_MODE_WIFI_CELL msg*/ + SLA_MODE_WIFI_CELL = 2, + SLA_MODE_DUAL_WIFI_CELL = 3, + + SLA_MODE_FINISH = 4, +}; + + +enum{ + DISABLE_DUAL_WIFI = 1, + DISABLE_WIFI_CELL = 2, +}; + +//add for dual sta DCS +enum{ + INIT_ACTIVE_TYPE, + LOW_SPEED_HIGH_RTT, + LOW_WLAN_SCORE, + LOW_DL_SPEED, + WLAN_DOWNLOAD, +}; + +static bool enable_cell_to_user = 0; +static bool enable_second_wifi_to_user = 0; +static int oplus_sla_vpn_connected = 0; +static int game_mark = 0; +static bool inGame = false; +static bool game_cell_to_wifi = false; +static bool game_rx_bad = false; +static int udp_rx_show_toast = 0; +static int game_rtt_show_toast = 0; +int tee_use_src = 0; +static int oplus_sla_enable; +static int oplus_sla_debug = 0; +static int oplus_sla_calc_speed; +static int oplus_sla_def_net = 0; //WLAN0->0 WLAN1->1 CELL->2 +static int send_show_dailog_msg = 0; +static int game_start_state[GAME_NUM]; +static int MAIN_WLAN = WLAN0_INDEX; +static int SECOND_WLAN = WLAN1_INDEX; +static int MAIN_WLAN_MARK = WLAN0_MARK; +static int SECOND_WLAN_MARK = WLAN1_MARK; +static int main_wlan_download = 1; +//add for android Q statictis tcp tx and tx +static u64 wlan0_tcp_tx = 0; +static u64 wlan0_tcp_rx = 0; +static u64 wlan1_tcp_tx = 0; +static u64 wlan1_tcp_rx = 0; + +static int sla_work_mode = SLA_MODE_INIT; +static int sla_detect_mode = SLA_MODE_DUAL_WIFI; + +static int init_weight_delay_count = 0; +static int dual_wifi_active_type = 0; + +static bool dual_wifi_switch_enable = true; +static bool sla_switch_enable = false; +static bool sla_screen_on = true; +static bool cell_quality_good = true; +static bool need_show_dailog = true; + +static volatile u32 oplus_sla_pid; +static struct sock *oplus_sla_sock; +static struct timer_list sla_timer; + +static struct timeval last_speed_tv; +static struct timeval last_weight_tv; +static struct timeval last_minute_speed_tv; +static struct timeval last_download_speed_tv; +static struct timeval last_enable_cellular_tv; +static struct timeval calc_wlan_rtt_tv; +static struct timeval last_enable_second_wifi_tv; +static struct timeval last_enable_cell_tv; + +static struct timeval last_show_daillog_msg_tv; +static struct timeval last_calc_small_speed_tv; + +static struct sla_dns_statistic dns_info[IFACE_NUM]; +static struct oplus_rate_limit_info rate_limit_info; +static struct oplus_game_online game_online_info; +static struct oplus_white_app_info white_app_list; +static struct oplus_dual_sta_info dual_wifi_app_list; +static struct oplus_dual_sta_info download_app_list; +static struct oplus_dual_sta_info vedio_app_list; +static struct oplus_sla_game_info game_uid[GAME_NUM]; +static struct oplus_dev_info oplus_sla_info[IFACE_NUM]; +static struct oplus_speed_calc oplus_speed_info[IFACE_NUM]; +static struct oplus_syn_retran_statistic syn_retran_statistic; + +static struct work_struct oplus_sla_work; +static struct workqueue_struct *workqueue_sla; + +static DEFINE_MUTEX(sla_netlink_mutex); +static struct ctl_table_header *oplus_sla_table_hrd; + +/*we statistic rtt when tcp state is TCP_ESTABLISHED,for somtimes(when the network has qos to let syn pass first) + * the three handshark (syn-synack) rtt is good but the network is worse. +*/ +extern void (*statistic_dev_rtt)(struct sock *sk,long rtt); + +/*sometimes when skb reject by iptables, +*it will retran syn which may make the rtt much high +*so just mark the stream(ct) with mark IPTABLE_REJECT_MARK when this happens +*/ +extern void (*mark_streams_for_iptables_reject)(struct sk_buff *skb,enum ipt_reject_with); + + +static rwlock_t sla_lock; +static rwlock_t sla_rtt_lock; +static rwlock_t sla_game_lock; + + +#define sla_read_lock() read_lock_bh(&sla_lock); +#define sla_read_unlock() read_unlock_bh(&sla_lock); +#define sla_write_lock() write_lock_bh(&sla_lock); +#define sla_write_unlock() write_unlock_bh(&sla_lock); + +#define sla_rtt_write_lock() write_lock_bh(&sla_rtt_lock); +#define sla_rtt_write_unlock() write_unlock_bh(&sla_rtt_lock); + +#define sla_game_write_lock() write_lock_bh(&sla_game_lock); +#define sla_game_write_unlock() write_unlock_bh(&sla_game_lock); + + +static struct oplus_sla_rom_update_info rom_update_info ={ + .sla_speed = 200, + .cell_speed = MAX_CELLULAR_SPEED, + .wlan_speed = MAX_WLAN_SPEED, + .wlan_little_score_speed = LOW_RSSI_MAX_WLAN_SPEED, + .sla_rtt = 230, /*test with 230ms*/ + .wzry_rtt = 200, + .cjzc_rtt = 220, + .wlan_bad_score = WLAN_SCORE_BAD, + .wlan_good_score = WLAN_SCORE_GOOD, + .second_wlan_speed = (2 * MAX_WLAN_SPEED), + .dual_wlan_download_speed = DUAL_WLAN_MAX_DOWNLOAD_SPEED, + .dual_wifi_rtt = 200, + .dual_wlan_bad_score = DUAL_WLAN_SCORE_BAD, +}; + +static struct oplus_sla_game_rtt_params game_params[GAME_NUM]; + +static struct game_traffic_info default_traffic_info = { + .game_in_front = 0, + //.udp_rx_packet[UDP_RX_WIN_SIZE]; + //.tcp_rx_byte[TCP_RX_WIN_SIZE]; + .window_index = 0, + .udp_rx_min = 3, + .udp_rx_low_thr = 12, + .in_game_true_thr = 15, + .in_game_false_thr = 10, + .rx_bad_thr = 4, +}; + +static struct game_traffic_info wzry_traffic_info = { + .game_in_front = 0, + //.udp_rx_packet[UDP_RX_WIN_SIZE]; + //.tcp_rx_byte[TCP_RX_WIN_SIZE]; + .window_index = 0, + .udp_rx_min = 3, + .udp_rx_low_thr = 12, + .in_game_true_thr = 15, + .in_game_false_thr = 10, + .rx_bad_thr = 4, +}; + +static struct game_traffic_info cjzc_traffic_info = { + .game_in_front = 0, + //.udp_rx_packet[UDP_RX_WIN_SIZE]; + //.tcp_rx_byte[TCP_RX_WIN_SIZE]; + .window_index = 0, + .udp_rx_min = 3, + .udp_rx_low_thr = 14, + .in_game_true_thr = 15, + .in_game_false_thr = 10, + .rx_bad_thr = 4, +}; + +/* for Smart BW RUS related */ +static struct oplus_smart_bw_rom_update_info smart_bw_rom_update_info; +static bool get_smartbw_romupdate = false; +static int oplus_smart_bw_set_params(struct nlmsghdr *nlh) +{ + u32* params = (u32 *)NLMSG_DATA(nlh); + u32 count = (nlh)->nlmsg_len - NLMSG_HDRLEN; /* this is in fact the payload length which already aligned */ + if (1) { + printk("oplus_smart_bw_set_params: (nlh)->nlmsg_len = %u, NLMSG_HDRLEN=%d," + "NLMSG_PAYLOAD(nlh, NLMSG_HDRLEN) = %u, sizeof(oplus_smart_bw_rom) = %lu", + (nlh)->nlmsg_len, NLMSG_HDRLEN, count, sizeof(struct oplus_smart_bw_rom_update_info)); + } +#if 1 + if (count == sizeof(struct oplus_smart_bw_rom_update_info)) { +#endif + get_smartbw_romupdate = true; + smart_bw_rom_update_info.feature_enable = params[0]; + smart_bw_rom_update_info.debug_level = params[1]; + smart_bw_rom_update_info.ll_com_score_thre = params[2]; + smart_bw_rom_update_info.acs_weight_thre = params[3]; + smart_bw_rom_update_info.mov_avg_beta = params[4]; + smart_bw_rom_update_info.thre_tune_dist = params[5]; + smart_bw_rom_update_info.sample_interval = params[6]; + smart_bw_rom_update_info.good_mcs = params[7]; + smart_bw_rom_update_info.bad_mcs = params[8]; + if (smart_bw_rom_update_info.debug_level == 2 && oplus_sla_debug) { + printk("oplus_smart_bw_set_params:set params count=%d params[0] = %d, params[1] = %d, params[2] = %d, params[3] = %d," + "params[4] = %d, params[5] = %d, params[6] = %d, params[7] = %d, params[8] = %d", + count, params[0], params[1], params[2], params[3], params[4], + params[5], params[6], params[7], params[8]); + } +#if 1 + } else { + printk("oplus_smart_bw_set_params:set params invalid param count:%d", count); + } +#endif + return 0; +} + +/* Get RUS rom update which comes from FWK, true: success */ +bool get_smart_bw_rom_update(int payload[], int len) +{ + if (len < sizeof(struct oplus_smart_bw_rom_update_info) / sizeof(int) || !get_smartbw_romupdate) { + if (1) printk("%s target payload len not match or hasn't got ROM update from FWK !\n", __func__); + return false; + } + + if (1) printk("%s enter!\n", __func__); + memcpy(payload, &smart_bw_rom_update_info, sizeof(struct oplus_smart_bw_rom_update_info)); + + if (1) printk("%s exit!\n", __func__); + return true; +} + +EXPORT_SYMBOL(get_smart_bw_rom_update); +/* send to user space */ +static int oplus_sla_send_to_user(int msg_type,char *payload,int payload_len) +{ + int ret = 0; + struct sk_buff *skbuff; + struct nlmsghdr *nlh; + + if (!oplus_sla_pid) { + printk("oplus_sla_netlink: oplus_sla_pid == 0!!\n"); + return -1; + } + + /*allocate new buffer cache */ + skbuff = alloc_skb(NLMSG_SPACE(payload_len), GFP_ATOMIC); + if (skbuff == NULL) { + printk("oplus_sla_netlink: skbuff alloc_skb failed\n"); + return -1; + } + + /* fill in the data structure */ + nlh = nlmsg_put(skbuff, 0, 0, msg_type, NLMSG_ALIGN(payload_len), 0); + if (nlh == NULL) { + printk("oplus_sla_netlink:nlmsg_put failaure\n"); + nlmsg_free(skbuff); + return -1; + } + + //compute nlmsg length + nlh->nlmsg_len = NLMSG_HDRLEN + NLMSG_ALIGN(payload_len); + + if(NULL != payload){ + memcpy((char *)NLMSG_DATA(nlh),payload,payload_len); + } + + /* set control field,sender's pid */ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,7,0)) + NETLINK_CB(skbuff).pid = 0; +#else + NETLINK_CB(skbuff).portid = 0; +#endif + + NETLINK_CB(skbuff).dst_group = 0; + + /* send data */ + ret = netlink_unicast(oplus_sla_sock, skbuff, oplus_sla_pid, MSG_DONTWAIT); + if(ret < 0){ + printk(KERN_ERR "oplus_sla_netlink: can not unicast skbuff,ret = %d\n",ret); + return 1; + } + + return 0; +} + +static void calc_network_congestion(void) +{ + int i = 0; + int avg_rtt = 0; + int rtt_num = 2; + + if(oplus_sla_info[MAIN_WLAN].wlan_score <= rom_update_info.wlan_bad_score){ + rtt_num = 1; + } + + sla_rtt_write_lock(); + for(i = 0; i < IFACE_NUM; i++){ + if(oplus_sla_info[i].if_up){ + + if(oplus_sla_info[i].sla_rtt_num >= rtt_num){ + avg_rtt = 0; + if(oplus_sla_info[i].download_flag < DOWNLOAD_FLAG){ + avg_rtt = oplus_sla_info[i].sla_sum_rtt / oplus_sla_info[i].sla_rtt_num; + oplus_sla_info[i].sla_avg_rtt = avg_rtt; + } + + if(oplus_sla_debug){ + printk("oplus_sla_rtt: sla rtt ,num = %d,sum = %d,avg rtt[%d] = %d\n", + oplus_sla_info[i].sla_rtt_num,oplus_sla_info[i].sla_sum_rtt,i,avg_rtt); + } + + oplus_sla_info[i].sla_rtt_num = 0; + oplus_sla_info[i].sla_sum_rtt = 0; + + if(avg_rtt >= BACK_OFF_RTT_2){ + + oplus_sla_info[i].congestion_flag = CONGESTION_LEVEL_HIGH; + oplus_sla_info[i].max_speed /= 2; + oplus_sla_info[i].download_speed /= 2; + } + else if(avg_rtt >= BACK_OFF_RTT_1){ + + oplus_sla_info[i].congestion_flag = CONGESTION_LEVEL_MIDDLE; + oplus_sla_info[i].max_speed /= 2; + oplus_sla_info[i].download_speed /= 2; + } + else{ + if(WEIGHT_STATE_NORMAL == oplus_sla_info[i].weight_state){ + oplus_sla_info[i].congestion_flag = CONGESTION_LEVEL_NORMAL; + } + } + } + } + } + sla_rtt_write_unlock(); + + return; +} + +static void init_dual_wifi_weight(void) +{ + init_weight_delay_count = 5; + if (INIT_ACTIVE_TYPE != dual_wifi_active_type && + (oplus_sla_info[MAIN_WLAN].sla_avg_rtt >= BACK_OFF_RTT_2 || + oplus_sla_info[MAIN_WLAN].max_speed <= CALC_WEIGHT_MIN_SPEED_2)){ + oplus_sla_info[MAIN_WLAN].weight = 0; + oplus_sla_info[SECOND_WLAN].weight = 100; + } else if (LOW_SPEED_HIGH_RTT == dual_wifi_active_type || + LOW_WLAN_SCORE == dual_wifi_active_type || + LOW_DL_SPEED == dual_wifi_active_type){ + oplus_sla_info[MAIN_WLAN].weight = 30; + oplus_sla_info[SECOND_WLAN].weight = 100; + } else if (WLAN_DOWNLOAD == dual_wifi_active_type){ + // for download active + oplus_sla_info[MAIN_WLAN].weight = 50; + oplus_sla_info[SECOND_WLAN].weight = 100; + } else { + // for manual active or networkReuqest + init_weight_delay_count = 0; + oplus_sla_info[MAIN_WLAN].weight = 100; + oplus_sla_info[SECOND_WLAN].weight = 0; + } + printk("oplus_sla_weight:init_dual_wifi_weight [%d] [%d]", + oplus_sla_info[MAIN_WLAN].weight,oplus_sla_info[SECOND_WLAN].weight); +} + +static void init_wifi_cell_weight(void) +{ + init_weight_delay_count = 10; + oplus_sla_info[MAIN_WLAN].weight = 0; + oplus_sla_info[CELL_INDEX].weight = 100; + printk("oplus_sla_weight:init_wifi_cell_weight [%d] [%d]", + oplus_sla_info[MAIN_WLAN].weight,oplus_sla_info[CELL_INDEX].weight); +} + +static void init_dual_wifi_cell_weight(void) +{ + if (oplus_sla_info[MAIN_WLAN].sla_avg_rtt >= BACK_OFF_RTT_2){ + oplus_sla_info[MAIN_WLAN].weight = 0; + + if (oplus_sla_info[SECOND_WLAN].sla_avg_rtt >= BACK_OFF_RTT_2) { + oplus_sla_info[SECOND_WLAN].weight = 0; + } + else { + oplus_sla_info[SECOND_WLAN].weight = 30; + } + + oplus_sla_info[CELL_INDEX].weight = 100; + } else { + + if (oplus_sla_info[SECOND_WLAN].sla_avg_rtt >= BACK_OFF_RTT_2) { + oplus_sla_info[MAIN_WLAN].weight = 30; + oplus_sla_info[SECOND_WLAN].weight = 0; + } + else { + oplus_sla_info[MAIN_WLAN].weight = 15; + oplus_sla_info[SECOND_WLAN].weight = 30; + } + oplus_sla_info[CELL_INDEX].weight = 100; + } +} + +static void init_oplus_sla_weight(struct timeval tv,int work_mode) +{ + last_weight_tv = tv; + + if (SLA_MODE_DUAL_WIFI == work_mode) { + init_dual_wifi_weight(); + } + else if (SLA_MODE_WIFI_CELL == work_mode) { + init_wifi_cell_weight(); + } + else if (SLA_MODE_DUAL_WIFI_CELL == work_mode) { + init_dual_wifi_cell_weight(); + } +} + +static void send_enable_to_framework(int enable_mode,int active_type) +{ + int payload[2]; + if (SLA_MODE_DUAL_WIFI == enable_mode) { + enable_second_wifi_to_user = true; + do_gettimeofday(&last_enable_second_wifi_tv); + } + else if (SLA_MODE_WIFI_CELL == enable_mode) { + enable_cell_to_user = true; + do_gettimeofday(&last_enable_cell_tv); + } + + if(oplus_sla_info[MAIN_WLAN].need_up){ + oplus_sla_info[MAIN_WLAN].if_up = 1; + } + + if(oplus_sla_info[SECOND_WLAN].need_up){ + oplus_sla_info[SECOND_WLAN].if_up = 1; + } + + payload[0] = enable_mode; + payload[1] = active_type; + oplus_sla_send_to_user(SLA_ENABLE,(char *)payload,sizeof(payload)); + printk("oplus_sla_netlink:mode[%d] [%d] send SLA_ENABLE to user\n",enable_mode, active_type); +} + +static int enable_oplus_sla_module(struct nlmsghdr *nlh) +{ + int *data = (int *)NLMSG_DATA(nlh); + int enable_type = data[0]; + struct timeval tv; + + sla_write_lock(); + + do_gettimeofday(&tv); + last_enable_cellular_tv = tv; + init_oplus_sla_weight(tv,enable_type); + + oplus_sla_enable = 1; + sla_work_mode = enable_type; + if (SLA_MODE_DUAL_WIFI == enable_type) { + sla_detect_mode = SLA_MODE_WIFI_CELL; + } + else if (SLA_MODE_WIFI_CELL == enable_type) { + sla_detect_mode = SLA_MODE_FINISH; + } + + printk("oplus_sla_netlink: enable type = %d\n",enable_type); + oplus_sla_send_to_user(SLA_ENABLED, (char *)&enable_type, sizeof(int)); + + sla_write_unlock(); + return 0; +} + +static int enable_oplus_limit_speed() +{ + sla_write_lock(); + rate_limit_info.rate_limit_enable = 1; + printk("enable_oplus_limit_speed "); + sla_write_unlock(); + return 0; +} + +static int disable_oplus_limit_speed() +{ + sla_write_lock(); + rate_limit_info.rate_limit_enable = 0; + printk("disable_oplus_limit_speed "); + sla_write_unlock(); + return 0; +} + +static int oplus_limit_uid_changed(struct nlmsghdr *nlh) +{ + int uid = -1; + int *data = (int *)NLMSG_DATA(nlh); + uid = data[0]; + printk("oplus_limit_uid_changed uid:%d\n", uid); + sla_write_lock(); + rate_limit_info.front_uid = uid; + sla_write_unlock(); + + return 0; +} + +//add for rate limit function to statistics front uid rtt +static void statistics_front_uid_rtt(int rtt,struct sock *sk) +{ + kuid_t uid; + const struct file *filp = NULL; + if(sk && sk_fullsock(sk)){ + + if(NULL == sk->sk_socket){ + return; + } + + filp = sk->sk_socket->file; + if(NULL == filp){ + return; + } + + if(rate_limit_info.front_uid){ + uid = make_kuid(&init_user_ns, rate_limit_info.front_uid); + if(uid_eq(filp->f_cred->fsuid, uid)){ + if(rate_limit_info.rate_limit_enable){ + rate_limit_info.enable_rtt_num++; + rate_limit_info.enable_rtt_sum += rtt; + } else{ + rate_limit_info.disable_rtt_num++; + rate_limit_info.disable_rtt_sum += rtt; + } + } + } + } + return; +} + +static void calc_rtt_by_dev_index(int index, int tmp_rtt, struct sock *sk) +{ + + /*do not calc rtt when the screen is off which may make the rtt too big + */ + if(!sla_screen_on){ + return; + } + + if(tmp_rtt < 30) { + return; + } + + if(tmp_rtt > MAX_RTT){ + tmp_rtt = MAX_RTT; + } + + sla_rtt_write_lock(); + + statistics_front_uid_rtt(tmp_rtt,sk); + + if(!rate_limit_info.rate_limit_enable){ + oplus_sla_info[index].rtt_index++; + oplus_sla_info[index].sum_rtt += tmp_rtt; + } + + sla_rtt_write_unlock(); + return; + +} + + +static int find_dev_index_by_mark(__u32 mark) +{ + int i; + + for(i = 0; i < IFACE_NUM; i++){ + if(oplus_sla_info[i].if_up && + mark == oplus_sla_info[i].mark){ + return i; + } + } + + return -1; +} + +static int calc_retran_syn_rtt(struct sk_buff *skb, struct nf_conn *ct) +{ + int index = -1; + int ret = SLA_SKB_CONTINUE; + int tmp_mark = ct->mark & MARK_MASK; + int rtt_mark = ct->mark & RTT_MASK; + + if(rtt_mark & RTT_MARK){ + skb->mark = ct->mark; + return SLA_SKB_MARKED; + } + + index = find_dev_index_by_mark(tmp_mark); + + if(-1 != index) { + + calc_rtt_by_dev_index(index, SYN_RETRAN_RTT, NULL); + + //oplus_sla_info[index].syn_retran++; + syn_retran_statistic.syn_retran_num++; + + ct->mark |= RTT_MARK; + skb->mark = ct->mark; + + ret = SLA_SKB_MARKED; + } + + syn_retran_statistic.syn_total_num++; + + return ret; +} + +/* +LAN IP: +A:10.0.0.0-10.255.255.255 +B:172.16.0.0-172.31.255.255 +C:192.168.0.0-192.168.255.255 +*/ +static bool dst_is_lan_ip(struct sk_buff *skb) +{ + struct iphdr *iph = NULL; + unsigned char *dstip = NULL; + + iph = ip_hdr(skb); + if (NULL != iph) { + dstip = (unsigned char *)&iph->daddr; + if ((10 == dstip[0]) || + (192 == dstip[0] && 168 == dstip[1]) || + (172 == dstip[0] && dstip[1] >= 16 && dstip[1] <= 31)) { + return true; + } + } + return false; +} + +/*icsk_syn_retries*/ +static int syn_retransmits_packet_do_specail(struct sock *sk, + struct nf_conn *ct, + struct sk_buff *skb) +{ + + int ret = SLA_SKB_CONTINUE; + struct iphdr *iph; + struct tcphdr *th = NULL; + + if((iph = ip_hdr(skb)) != NULL && + iph->protocol == IPPROTO_TCP){ + + th = tcp_hdr(skb); + //only statictis SYN retran packet, sometimes some RST packets also arrive here + if(NULL != th && th->syn && + !th->rst && !th->ack && !th->fin){ + + ret = calc_retran_syn_rtt(skb, ct); + } + } + + return ret; +} + + +static bool is_download_app(kuid_t app_uid) +{ + int i = 0; + kuid_t uid; + + for(i = 0;i < download_app_list.count;i++){ + if(download_app_list.uid[i]){ + uid = make_kuid(&init_user_ns,download_app_list.uid[i]); + if(uid_eq(app_uid, uid)){ + return true; + } + } + } + return false; +} + +static int mark_download_app(struct sock *sk, + kuid_t app_uid, + struct nf_conn *ct, + struct sk_buff *skb) +{ + int choose_mark = 0; + int ret = SLA_SKB_CONTINUE; + + if (SLA_MODE_DUAL_WIFI == sla_work_mode && + is_download_app(app_uid)) { + // for manual active + if (INIT_ACTIVE_TYPE == dual_wifi_active_type) { + if ((oplus_sla_info[MAIN_WLAN].max_speed < CALC_WEIGHT_MIN_SPEED_3 && + oplus_sla_info[SECOND_WLAN].max_speed < CALC_WEIGHT_MIN_SPEED_3 && + oplus_sla_info[MAIN_WLAN].sla_avg_rtt < NORMAL_RTT) || + (oplus_sla_info[MAIN_WLAN].download_flag < DOWNLOAD_FLAG && + oplus_sla_info[MAIN_WLAN].download_speed >= DUAL_WLAN_MAX_DOWNLOAD_SPEED)) { + + choose_mark= MAIN_WLAN_MARK; + + } else if (100 == oplus_sla_info[MAIN_WLAN].weight && + oplus_sla_info[MAIN_WLAN].download_flag >= DOWNLOAD_FLAG && + oplus_sla_info[SECOND_WLAN].download_flag < DOWNLOAD_FLAG) { + choose_mark = SECOND_WLAN_MARK; + } + } else { + if ((init_weight_delay_count > 0 && + oplus_sla_info[SECOND_WLAN].download_flag < DOWNLOAD_FLAG) || + (oplus_sla_info[MAIN_WLAN].download_flag < DOWNLOAD_FLAG && + oplus_sla_info[SECOND_WLAN].download_flag < DOWNLOAD_FLAG && + oplus_sla_info[MAIN_WLAN].download_speed >= MAX_WLAN_SPEED && + oplus_sla_info[SECOND_WLAN].download_speed >= MAX_WLAN_SPEED)) { + if (main_wlan_download) { + main_wlan_download = 0; + choose_mark = MAIN_WLAN_MARK; + } else if (!main_wlan_download) { + main_wlan_download = 1; + choose_mark = SECOND_WLAN_MARK; + } + } + } + } + + if (choose_mark) { + skb->mark = choose_mark; + ct->mark = skb->mark; + sk->oplus_sla_mark = skb->mark; + //sk->sk_mark = sk->oplus_sla_mark; + return SLA_SKB_MARKED; + } + + return ret; +} + +static bool is_vedio_app(kuid_t app_uid) +{ + int i = 0; + kuid_t uid; + + for(i = 0;i < vedio_app_list.count;i++){ + if(vedio_app_list.uid[i]){ + uid = make_kuid(&init_user_ns,vedio_app_list.uid[i]); + if(uid_eq(app_uid, uid)){ + return true; + } + } + } + return false; +} + +static int mark_video_app(struct sock *sk, + kuid_t app_uid, + struct nf_conn *ct, + struct sk_buff *skb) +{ + int choose_mark = 0; + int ret = SLA_SKB_CONTINUE; + + if (SLA_MODE_DUAL_WIFI == sla_work_mode && + is_vedio_app(app_uid)) { + if (oplus_sla_info[MAIN_WLAN].download_speed >= MAX_WLAN_SPEED) { + + choose_mark = MAIN_WLAN_MARK; + + } else if (oplus_sla_info[SECOND_WLAN].download_speed > MAX_WLAN_SPEED || + (oplus_sla_info[MAIN_WLAN].download_speed <= VIDEO_SPEED && + ((init_weight_delay_count > 0 && oplus_sla_info[MAIN_WLAN].dl_little_speed < DOWNLOAD_SPEED) || + (oplus_sla_info[SECOND_WLAN].download_speed > VIDEO_SPEED && oplus_sla_info[SECOND_WLAN].sla_avg_rtt <= 150)))) { + + choose_mark= SECOND_WLAN_MARK; + } + } + + if (choose_mark) { + skb->mark = choose_mark; + ct->mark = skb->mark; + sk->oplus_sla_mark = skb->mark; + //sk->sk_mark = sk->oplus_sla_mark; + return SLA_SKB_MARKED; + } + + return ret; +} + + +static void is_http_get(struct nf_conn *ct,struct sk_buff *skb, + struct tcphdr *tcph,int header_len) +{ + + u32 *payload = NULL; + payload =(u32 *)(skb->data + header_len); + + if(0 == ct->oplus_http_flag && (80 == ntohs(tcph->dest))){ + + if( *payload == 0x20544547){//http get + + ct->oplus_http_flag = 1; + ct->oplus_skb_count = 1; + } + } + + return; +} + +static struct tcphdr * is_valid_http_packet(struct sk_buff *skb, int *header_len) +{ + int datalen = 0; + int tmp_len = 0; + struct tcphdr *tcph = NULL; + struct iphdr *iph; + + if((iph = ip_hdr(skb)) != NULL && + iph->protocol == IPPROTO_TCP){ + + tcph = tcp_hdr(skb); + datalen = ntohs(iph->tot_len); + tmp_len = iph->ihl * 4 + tcph->doff * 4; + + if((datalen - tmp_len) > 64){ + *header_len = tmp_len; + return tcph; + } + } + return NULL; +} + +static u32 get_skb_mark_by_weight(void) +{ + int i = 0; + u32 sla_random = prandom_u32() & 0x7FFFFFFF; + + /*0x147AE15 = 0x7FFFFFFF /100 + 1; for we let the weight * 100 to void + *decimal point operation at linux kernel + */ + for (i = 0; i < IFACE_NUM; i++) { + if (oplus_sla_info[i].if_up && + oplus_sla_info[i].weight) { + if (sla_random < (0x147AE15 * oplus_sla_info[i].weight)) { + return oplus_sla_info[i].mark; + } + } + } + + return oplus_sla_info[MAIN_WLAN].mark; +} + +static void reset_oplus_sla_calc_speed(struct timeval tv) +{ + int time_interval = 0; + time_interval = tv.tv_sec - last_calc_small_speed_tv.tv_sec; + + if(time_interval >= 60 && + oplus_speed_info[MAIN_WLAN].speed_done){ + + oplus_sla_calc_speed = 0; + oplus_speed_info[MAIN_WLAN].speed_done = 0; + + } +} + +static int wlan_get_speed_prepare(struct sk_buff *skb) +{ + + int header_len = 0; + struct tcphdr *tcph = NULL; + struct nf_conn *ct = NULL; + enum ip_conntrack_info ctinfo; + + ct = nf_ct_get(skb, &ctinfo); + + if(NULL == ct){ + return NF_ACCEPT; + } + + if(ctinfo == IP_CT_ESTABLISHED){ + tcph = is_valid_http_packet(skb,&header_len); + if(tcph){ + is_http_get(ct,skb,tcph,header_len); + } + } + return NF_ACCEPT; +} + + +static int get_wlan_syn_retran(struct sk_buff *skb) +{ + int tmp_mark; + int rtt_mark; + struct iphdr *iph; + struct sock *sk = NULL; + struct nf_conn *ct = NULL; + struct tcphdr *th = NULL; + enum ip_conntrack_info ctinfo; + + ct = nf_ct_get(skb, &ctinfo); + + if(NULL == ct){ + return NF_ACCEPT; + } + + if(ctinfo == IP_CT_NEW && + (iph = ip_hdr(skb)) != NULL && + iph->protocol == IPPROTO_TCP){ + + th = tcp_hdr(skb); + /*only statictis syn retran packet, + * sometimes some rst packet also will be here + */ + if(NULL != th && th->syn && + !th->rst && !th->ack && !th->fin){ + + /*Some third-party apps will send TCP syn + *messages of the Intranet, resulting in retransmission + */ + if (dst_is_lan_ip(skb)) { + ct->mark |= RTT_MARK; + return NF_ACCEPT; + } + + rtt_mark = ct->mark & RTT_MASK; + tmp_mark = ct->mark & MARK_MASK; + + if(rtt_mark & RTT_MARK){ + return NF_ACCEPT; + } + + if(tmp_mark != MAIN_WLAN_MARK) { + struct net_device *dev = NULL; + dev = skb_dst(skb)->dev; + + if (dev && !memcmp(dev->name,oplus_sla_info[MAIN_WLAN].dev_name,strlen(dev->name))) { + if (oplus_sla_debug) { + printk("oplus_dev_info: dev name = %s\n",dev->name); + } + + ct->mark = MAIN_WLAN_MARK; + + sk = skb_to_full_sk(skb); + if(sk) { + sk->oplus_sla_mark = MAIN_WLAN_MARK; + //sk->sk_mark = sk->oplus_sla_mark; + } + + syn_retran_statistic.syn_total_num++; + } + return NF_ACCEPT; + } + + syn_retran_statistic.syn_retran_num++; + calc_rtt_by_dev_index(MAIN_WLAN, SYN_RETRAN_RTT, sk); + + ct->mark |= RTT_MARK; + } + } + return NF_ACCEPT; +} + +static void game_rtt_estimator(int game_type, u32 rtt) +{ + long m = rtt; /* RTT */ + int shift = 3; + u32 srtt = 0; + + if(game_type && + game_type < GAME_NUM){ + + srtt = game_uid[game_type].rtt; + if(GAME_WZRY == game_type) { + shift = 2; + } + + if (srtt != 0) { + + m -= (srtt >> shift); + srtt += m; /* rtt = 7/8 rtt + 1/8 new */ + + } else { + //void first time the rtt bigger than 200ms which will switch game network + m = m >> 2; + srtt = m << shift; + + } + game_uid[game_type].rtt = srtt; + + if(rtt >= 250){ + game_uid[game_type].rtt_250_num++; + } + else if(rtt >= 200){ + game_uid[game_type].rtt_200_num++; + } + else if(rtt >= 150){ + game_uid[game_type].rtt_150_num++; + } + else { + game_uid[game_type].rtt_normal_num++; + } + } + return; +} + +static void game_app_switch_network(u32 game_type) +{ + int index = -1; + u32 game_rtt = 0; + u32 uid = 0; + int shift = 3; + u32 time_now = 0; + int max_rtt = MAX_GAME_RTT; + int game_bp_info[4]; + bool wlan_bad = false; + + if(!oplus_sla_enable){ + return; + } + + if(GAME_WZRY != game_type && + GAME_CJZC != game_type){ + return; + } + + if(oplus_sla_info[MAIN_WLAN].wlan_score_bad_count >= WLAN_SCORE_BAD_NUM){ + wlan_bad = true; + } + + index = game_type; + uid = game_uid[game_type].uid; + + if(!game_start_state[index] && !inGame){ + return; + } + + if(GAME_WZRY == game_type) { + shift = 2; + max_rtt = rom_update_info.wzry_rtt; + } + else if(GAME_CJZC == game_type){ + max_rtt = rom_update_info.cjzc_rtt; + } + + time_now = ktime_get_ns() / 1000000; + game_rtt = game_uid[game_type].rtt >> shift; + + if(cell_quality_good && + !game_cell_to_wifi && + (wlan_bad || game_rx_bad || game_rtt >= max_rtt) && + game_uid[index].mark == MAIN_WLAN_MARK){ + if(!game_uid[index].switch_time || + (time_now - game_uid[index].switch_time) > 60000){ + + game_uid[game_type].rtt = 0; + game_uid[index].switch_time = time_now; + game_uid[index].mark = CELL_MARK; + + memset(game_bp_info,0x0,sizeof(game_bp_info)); + game_bp_info[0] = game_type; + game_bp_info[1] = CELL_MARK; + game_bp_info[2] = wlan_bad; + game_bp_info[3] = cell_quality_good; + oplus_sla_send_to_user(SLA_SWITCH_GAME_NETWORK,(char *)game_bp_info,sizeof(game_bp_info)); + printk("oplus_sla_game_rtt:uid = %u,game rtt = %u,wlan_bad = %d,game_rx_bad = %d,changing to cellular...\n", + uid,game_rtt,wlan_bad,game_rx_bad); + return; + } + } + + if(!wlan_bad && + game_uid[index].mark == CELL_MARK && game_rx_bad){ + + if(!game_uid[index].switch_time || + (time_now - game_uid[index].switch_time) > 60000){ + + game_uid[game_type].rtt = 0; + game_uid[index].switch_time = time_now; + game_uid[index].mark = MAIN_WLAN_MARK; + game_cell_to_wifi = true; + + memset(game_bp_info,0x0,sizeof(game_bp_info)); + game_bp_info[0] = game_type; + game_bp_info[1] = MAIN_WLAN_MARK; + game_bp_info[2] = wlan_bad; + game_bp_info[3] = cell_quality_good; + oplus_sla_send_to_user(SLA_SWITCH_GAME_NETWORK,(char *)game_bp_info,sizeof(game_bp_info)); + printk("oplus_sla_game_rtt:uid = %u,game rtt = %u,wlan_bad = %d,game_rx_bad = %d,changing to wlan...\n", + uid,game_rtt,wlan_bad,game_rx_bad); + return; + } + } + return; +} + +static bool is_game_rtt_skb(struct nf_conn *ct, struct sk_buff *skb, bool isTx) +{ + struct iphdr *iph = NULL; + struct udphdr *udph = NULL; + u32 header_len; + u8 *payload = NULL; + u32 gameType = ct->oplus_app_type; + + if (gameType <= 0 || gameType >= GAME_NUM || game_params[gameType].game_index == 0 || + (iph = ip_hdr(skb)) == NULL || iph->protocol != IPPROTO_UDP) { + //printk("oplus_sla_game_rtt_detect: not game skb."); + return false; + } + + if ((isTx && ct->oplus_game_up_count >= MAX_DETECT_PKTS) || + (!isTx && ct->oplus_game_down_count >= MAX_DETECT_PKTS)) { + ct->oplus_game_detect_status = GAME_SKB_COUNT_ENOUGH; + return false; + } + + if (unlikely(skb_linearize(skb))) { + return false; + } + iph = ip_hdr(skb); + udph = udp_hdr(skb); + header_len = iph->ihl * 4 + sizeof(struct udphdr); + payload =(u8 *)(skb->data + header_len); + if (isTx) { + int tx_offset = game_params[gameType].tx_offset; + int tx_len = game_params[gameType].tx_len; + //u8 tx_fixed_value[MAX_FIXED_VALUE_LEN]; + //memcpy(tx_fixed_value, game_params[gameType].tx_fixed_value, MAX_FIXED_VALUE_LEN); + if (udph->len >= (tx_offset + tx_len) && + memcmp(payload + tx_offset, game_params[gameType].tx_fixed_value, tx_len) == 0) { + if (oplus_sla_debug) { + printk("oplus_sla_game_rtt_detect:srcport[%d] this is game RTT Tx skb.\n",ntohs(udph->source)); + } + ct->oplus_game_detect_status |= GAME_RTT_STREAM; + return true; + } + } else { + int rx_offset = game_params[gameType].rx_offset; + int rx_len = game_params[gameType].rx_len; + //u8 rx_fixed_value[MAX_FIXED_VALUE_LEN]; + //memcpy(rx_fixed_value, game_params[gameType].rx_fixed_value, MAX_FIXED_VALUE_LEN); + if (udph->len >= (rx_offset + rx_len) && + memcmp(payload + rx_offset, game_params[gameType].rx_fixed_value, rx_len) == 0) { + if (oplus_sla_debug) { + printk("oplus_sla_game_rtt_detect: this is game RTT Rx skb.\n"); + } + ct->oplus_game_detect_status |= GAME_RTT_STREAM; + return true; + } + } + return false; +} + +static int mark_game_app_skb(struct nf_conn *ct,struct sk_buff *skb,enum ip_conntrack_info ctinfo) +{ + int game_index = -1; + struct iphdr *iph = NULL; + u32 ct_mark = 0; + int ret = SLA_SKB_CONTINUE; + + if(ct->oplus_app_type > 0 && ct->oplus_app_type < GAME_NUM){ + ret = SLA_SKB_ACCEPT; + game_index = ct->oplus_app_type; + + if(GAME_WZRY != game_index && + GAME_CJZC != game_index){ + return ret; + } + + ct_mark = GAME_UNSPEC_MASK & ct->mark; + if(!game_start_state[game_index] && !inGame && + (GAME_UNSPEC_MARK & ct_mark)){ + + return SLA_SKB_ACCEPT; + } + + iph = ip_hdr(skb); + if(iph && + (IPPROTO_UDP == iph->protocol || + IPPROTO_TCP == iph->protocol)){ + + //WZRY can not switch tcp packets + if(GAME_WZRY == game_index && + IPPROTO_TCP == iph->protocol) { + return SLA_SKB_ACCEPT; + } + + ct_mark = ct->mark & MARK_MASK; + + if(GAME_CJZC == game_index && + IPPROTO_TCP == iph->protocol && + ((XT_STATE_BIT(ctinfo) & XT_STATE_BIT(IP_CT_ESTABLISHED)) || + (XT_STATE_BIT(ctinfo) & XT_STATE_BIT(IP_CT_RELATED)))) { + if(MAIN_WLAN_MARK == ct_mark && oplus_sla_info[MAIN_WLAN].wlan_score > 40){ + return SLA_SKB_ACCEPT; + } + else if(CELL_MARK == ct_mark){ + skb->mark = CELL_MARK; + return SLA_SKB_MARKED; + } + } + + if (game_mark) { + skb->mark = game_mark; + } else { + skb->mark = game_uid[game_index].mark; + } + + if(ct_mark && skb->mark && + ct_mark != skb->mark){ + + printk("oplus_sla_game_rtt:reset game ct proto= %u,srcport = %d," + "ct dying = %d,ct confirmed = %d,game type = %d,ct mark = %x,skb mark = %x\n", + iph->protocol,ntohs(udp_hdr(skb)->source), + nf_ct_is_dying(ct),nf_ct_is_confirmed(ct),game_index,ct_mark,skb->mark); + + game_uid[game_index].rtt = 0; + + if(!nf_ct_is_dying(ct) && + nf_ct_is_confirmed(ct)){ + nf_ct_kill(ct); + return SLA_SKB_DROP; + } + else{ + skb->mark = ct_mark; + ret = SLA_SKB_MARKED; + } + } + + if(!ct_mark){ + ct->mark = (ct->mark & RTT_MASK) | game_uid[game_index].mark; + } + ret = SLA_SKB_MARKED; + } + } + + return ret; +} + +static bool is_game_app_skb(struct nf_conn *ct,struct sk_buff *skb,enum ip_conntrack_info ctinfo) +{ + int i = 0; + kuid_t uid; + struct sock *sk = NULL; + struct iphdr *iph = NULL; + const struct file *filp = NULL; + + if(INIT_APP_TYPE == ct->oplus_app_type){ + + sk = skb_to_full_sk(skb); + if(NULL == sk || NULL == sk->sk_socket){ + return false; + } + + filp = sk->sk_socket->file; + if(NULL == filp){ + return false; + } + + iph = ip_hdr(skb); + + uid = filp->f_cred->fsuid; + for(i = 1;i < GAME_NUM;i++){ + if(game_uid[i].uid){ + if((uid.val % UID_MASK) == (game_uid[i].uid % UID_MASK)) { + ct->oplus_app_type = i; + if(oplus_sla_enable && + CELL_MARK == game_uid[i].mark){ + game_uid[i].cell_bytes += skb->len; + } + //ct->mark = (ct->mark & RTT_MASK) | game_uid[i].mark; + if(!game_start_state[i] && !inGame && + iph && IPPROTO_TCP == iph->protocol){ + ct->mark = (ct->mark & RTT_MASK) | MAIN_WLAN_MARK; + ct->mark |= GAME_UNSPEC_MARK; + } else{ + if (game_mark) { + ct->mark = (ct->mark & RTT_MASK) | game_mark; + } else { + ct->mark = (ct->mark & RTT_MASK) | game_uid[i].mark; + } + } + return true; + } + } + } + } + else if(ct->oplus_app_type > 0 && + ct->oplus_app_type < GAME_NUM){ + i = ct->oplus_app_type; + if(oplus_sla_enable && + (oplus_sla_def_net == MAIN_WLAN || oplus_sla_def_net == SECOND_WLAN) && + CELL_MARK == game_uid[i].mark){ + game_uid[i].cell_bytes += skb->len; + } + return true; + } + + return false; + +} + +static int detect_game_up_skb(struct sk_buff *skb) +{ + struct timeval tv; + struct iphdr *iph = NULL; + struct nf_conn *ct = NULL; + int ret = SLA_SKB_ACCEPT; + enum ip_conntrack_info ctinfo; + + if(oplus_sla_vpn_connected){ + return SLA_SKB_CONTINUE; + } + + ct = nf_ct_get(skb, &ctinfo); + if(NULL == ct){ + return SLA_SKB_ACCEPT; + } + + if(!is_game_app_skb(ct,skb,ctinfo)){ + return SLA_SKB_CONTINUE; + } + + do_gettimeofday(&tv); + game_online_info.game_online = true; + game_online_info.last_game_skb_tv = tv; + + //TCP and udp need to switch network + ret = SLA_SKB_CONTINUE; + iph = ip_hdr(skb); + if(iph && IPPROTO_UDP == iph->protocol){ + if (ct->oplus_game_up_count < MAX_DETECT_PKTS && + ct->oplus_game_detect_status == GAME_SKB_DETECTING) { + ct->oplus_game_up_count++; + } + //only udp packet can trigger switching network to avoid updating game with cell. + sla_game_write_lock(); + game_app_switch_network(ct->oplus_app_type); + sla_game_write_unlock(); + + if (is_game_rtt_skb(ct, skb, true)) { + s64 time_now = ktime_get_ns() / 1000000; + if (ct->oplus_game_timestamp && time_now - ct->oplus_game_timestamp > 200) { + //Tx done and no Rx, we've lost a response pkt + ct->oplus_game_lost_count++; + sla_game_write_lock(); + game_rtt_estimator(ct->oplus_app_type, MAX_GAME_RTT); + sla_game_write_unlock(); + + if(game_rtt_show_toast) { + u32 game_rtt = MAX_GAME_RTT; + oplus_sla_send_to_user(SLA_NOTIFY_GAME_RTT,(char *)&game_rtt,sizeof(game_rtt)); + } + if(oplus_sla_debug) { + u32 shift = 3; + if(GAME_WZRY == ct->oplus_app_type) { + shift = 2; + } + printk("oplus_sla_game_rtt: lost packet!! game_rtt=%u, srtt=%u\n", + MAX_GAME_RTT, game_uid[ct->oplus_app_type].rtt >> shift); + } + } + ct->oplus_game_timestamp = time_now; + } + } + + return ret; +} + +static bool is_game_voice_packet(struct nf_conn *ct, struct sk_buff *skb) +{ + struct iphdr *iph = NULL; + struct udphdr *udph = NULL; + u32 header_len; + u8 *payload = NULL; + u8 wzry_fixed_value[2] = {0x55, 0xf4}; + u32 wzry_offset = 9; + u32 wzry_len = 2; + u8 cjzc_fixed_value[3] = {0x10, 0x01, 0x01}; + u32 cjzc_offset = 4; + u32 cjzc_len = 3; + int game_type = ct->oplus_app_type; + //u16 tot_len; + + if (ct->oplus_game_down_count >= MAX_DETECT_PKTS) { + ct->oplus_game_detect_status = GAME_SKB_COUNT_ENOUGH; + return false; + } + + if ((iph = ip_hdr(skb)) != NULL && iph->protocol == IPPROTO_UDP) { + if (unlikely(skb_linearize(skb))) { + return false; + } + iph = ip_hdr(skb); + udph = udp_hdr(skb); + header_len = iph->ihl * 4 + sizeof(struct udphdr); + payload =(u8 *)(skb->data + header_len); + if (game_type == GAME_WZRY) { + if (udph->len >= (wzry_offset + wzry_len) && + memcmp(payload + wzry_offset, wzry_fixed_value, wzry_len) == 0) { //for cjzc voice pkt + //printk("oplus_sla_game_rx_voice:this is voice skb!\n"); + ct->oplus_game_detect_status |= GAME_VOICE_STREAM; + return true; + } else { + //memcpy(fixed_value, payload + 4, 3); + //printk("oplus_sla_game_rx_voice:this is NOT voice skb, value=%02x%02x%02x\n", + // fixed_value[0], fixed_value[1], fixed_value[2]); + return false; + } + } else if (game_type == GAME_CJZC) { + if (udph->len >= (cjzc_offset + cjzc_len) && + memcmp(payload + cjzc_offset, cjzc_fixed_value, cjzc_len) == 0) { //for cjzc voice pkt + //printk("oplus_sla_game_rx_voice:this is voice skb!\n"); + ct->oplus_game_detect_status |= GAME_VOICE_STREAM; + return true; + } else { + //memcpy(fixed_value, payload + 4, 3); + //printk("oplus_sla_game_rx_voice:this is NOT voice skb, value=%02x%02x%02x\n", + // fixed_value[0], fixed_value[1], fixed_value[2]); + return false; + } + } + } + return false; +} + +static void record_sla_app_cell_bytes(struct nf_conn *ct, struct sk_buff *skb) +{ + int index = 0; + u32 ct_mark = 0x0; + //calc game or white list app cell bytes + if(oplus_sla_enable && + (oplus_sla_def_net == MAIN_WLAN || oplus_sla_def_net == SECOND_WLAN)){ + if(ct->oplus_app_type > 0 && + ct->oplus_app_type < GAME_NUM){ + index = ct->oplus_app_type; + if(CELL_MARK == game_uid[index].mark){ + game_uid[index].cell_bytes += skb->len; + } + } else if(ct->oplus_app_type >= WHITE_APP_BASE && + ct->oplus_app_type < DUAL_STA_APP_BASE){ + ct_mark = ct->mark & MARK_MASK; + if(CELL_MARK == ct_mark){ + index = ct->oplus_app_type - WHITE_APP_BASE; + if(index < WHITE_APP_NUM){ + white_app_list.cell_bytes[index] += skb->len; + } + } + } + } + + //calc white app cell bytes when sla is not enable + if(oplus_sla_info[CELL_INDEX].if_up){ + + if(!oplus_sla_info[MAIN_WLAN].if_up || oplus_sla_def_net == CELL_INDEX){ + if(ct->oplus_app_type >= WHITE_APP_BASE && + ct->oplus_app_type < DUAL_STA_APP_BASE){ + index = ct->oplus_app_type - WHITE_APP_BASE; + if(index < WHITE_APP_NUM){ + white_app_list.cell_bytes_normal[index] += skb->len; + } + } + } + } +} + +//add for android Q statictis tcp tx and tx +static void statistics_wlan_tcp_tx_rx(const struct nf_hook_state *state,struct sk_buff *skb) +{ + struct iphdr *iph; + struct nf_conn *ct = NULL; + enum ip_conntrack_info ctinfo; + struct net_device *dev = NULL; + struct tcphdr *th = NULL; + unsigned int hook = state->hook; + + if((oplus_sla_info[MAIN_WLAN].if_up || oplus_sla_info[MAIN_WLAN].need_up) && + (iph = ip_hdr(skb)) != NULL && iph->protocol == IPPROTO_TCP){ + + th = tcp_hdr(skb); + if(NF_INET_LOCAL_OUT == hook + && NULL != th + && (th->rst || th->fin)){ + //ignore TX fin or rst + return; + } + ct = nf_ct_get(skb, &ctinfo); +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4,14,0)) + if(NULL == ct || (0 == ct->mark)){ +#else + if(NULL == ct || nf_ct_is_untracked(ct) || (0 == ct->mark)){ +#endif + if (NF_INET_LOCAL_OUT == hook) { + dev = skb_dst(skb)->dev; + } else if (NF_INET_LOCAL_IN == hook){ + dev = state->in; + } + + if (dev && !memcmp(dev->name,oplus_sla_info[MAIN_WLAN].dev_name,strlen(dev->name))) { + if (NF_INET_LOCAL_OUT == hook) { + wlan0_tcp_tx++; + } else if (NF_INET_LOCAL_IN == hook) { + wlan0_tcp_rx++; + } + } else if (dev && !memcmp(dev->name,oplus_sla_info[SECOND_WLAN].dev_name,strlen(dev->name))) { + if (NF_INET_LOCAL_OUT == hook) { + wlan1_tcp_tx++; + } else if (NF_INET_LOCAL_IN == hook) { + wlan1_tcp_rx++; + } + } + } else if (MAIN_WLAN_MARK == (ct->mark & MARK_MASK)) { + if (NF_INET_LOCAL_OUT == hook) { + wlan0_tcp_tx++; + } else if (NF_INET_LOCAL_IN == hook) { + wlan0_tcp_rx++; + } + } else if (SECOND_WLAN_MARK == (ct->mark & MARK_MASK)) { + if (NF_INET_LOCAL_OUT == hook) { + wlan1_tcp_tx++; + } else if (NF_INET_LOCAL_IN == hook) { + wlan1_tcp_rx++; + } + } + } +} + +static unsigned int oplus_sla_game_rtt_calc(struct sk_buff *skb) +{ + int shift = 3; + s64 time_now; + u32 game_rtt = 0; + struct iphdr *iph = NULL; + struct nf_conn *ct = NULL; + enum ip_conntrack_info ctinfo; + + if(oplus_sla_vpn_connected){ + return NF_ACCEPT; + } + + ct = nf_ct_get(skb, &ctinfo); + if(NULL == ct){ + return NF_ACCEPT; + } + + iph = ip_hdr(skb); + + + //calc game or white list app cell bytes + record_sla_app_cell_bytes(ct,skb); + + //calc game app udp packet count(except for voice packets) and tcp bytes + if (ct->oplus_app_type > 0 && ct->oplus_app_type < GAME_NUM) { + if (iph && IPPROTO_UDP == iph->protocol) { + if (ct->oplus_game_down_count < MAX_DETECT_PKTS && + ct->oplus_game_detect_status == GAME_SKB_DETECTING) { + ct->oplus_game_down_count++; + } + if (!is_game_voice_packet(ct, skb)) { + game_online_info.udp_rx_pkt_count++; + } + } else if (iph && IPPROTO_TCP == iph->protocol) { + game_online_info.tcp_rx_byte_count += skb->len; + } + } + + if (is_game_rtt_skb(ct, skb, false)) { + time_now = ktime_get_ns() / 1000000; + if(ct->oplus_game_timestamp && time_now > ct->oplus_game_timestamp){ + + game_rtt = (u32)(time_now - ct->oplus_game_timestamp); + if (game_rtt < MIN_GAME_RTT) { + if(oplus_sla_debug){ + printk("oplus_sla_game_rtt:invalid RTT %dms\n", game_rtt); + } + ct->oplus_game_timestamp = 0; + return NF_ACCEPT; + } + + ct->oplus_game_timestamp = 0; + + if(game_rtt > MAX_GAME_RTT){ + game_rtt = MAX_GAME_RTT; + } + + if (sla_switch_enable && cell_quality_good) { + if (oplus_sla_enable && sla_work_mode == SLA_MODE_DUAL_WIFI) { + /* dualsta Mode, enable sla, just game rtt is bad */ + if (game_rx_bad || game_rtt >= (MAX_GAME_RTT - 80)) { + send_enable_to_framework(SLA_MODE_WIFI_CELL, INIT_ACTIVE_TYPE); + printk("oplus_sla_netlink: dualsta Mode, game app send enable sla to user\n"); + } + } else if (!enable_cell_to_user && !oplus_sla_enable) { + /* Normal Mode, enable sla */ + if (game_rx_bad || game_rtt >= (MAX_GAME_RTT / 2)) { + send_enable_to_framework(SLA_MODE_WIFI_CELL, INIT_ACTIVE_TYPE); + printk("oplus_sla_netlink: Normal Mode, game app send enable sla to user\n"); + } + } + } + + if(game_rtt_show_toast) { + oplus_sla_send_to_user(SLA_NOTIFY_GAME_RTT,(char *)&game_rtt,sizeof(game_rtt)); + } + ct->oplus_game_lost_count = 0; + + sla_game_write_lock(); + game_rtt_estimator(ct->oplus_app_type,game_rtt); + sla_game_write_unlock(); + + if(oplus_sla_debug){ + if(GAME_WZRY == ct->oplus_app_type) { + shift = 2; + } + printk("oplus_sla_game_rtt: game_rtt=%u, srtt=%u\n", game_rtt, game_uid[ct->oplus_app_type].rtt >> shift); + } + } + } + + return NF_ACCEPT; +} + + +static bool is_skb_pre_bound(struct sk_buff *skb) +{ + u32 pre_mark = skb->mark & 0x10000; + + if(0x10000 == pre_mark){ + return true; + } + + return false; +} + +static bool is_sla_white_or_game_app(struct nf_conn *ct,struct sk_buff *skb) +{ + + if(ct->oplus_app_type > 0 && + ct->oplus_app_type < DUAL_STA_APP_BASE){//game app skb + return true; + } + + return false; +} + + +static int sla_skb_reroute(struct sk_buff *skb,struct nf_conn *ct,const struct nf_hook_state *state) +{ + int err; + + err = ip_route_me_harder(state->net, skb, RTN_UNSPEC); + if (err < 0){ + return NF_DROP_ERR(err); + } + + return NF_ACCEPT; +} + +static void statistic_dns_send_info(int index) +{ + struct timeval tv; + + if (dns_info[index].send_num < DNS_MAX_NUM) { + dns_info[index].send_num++; + } + else { + do_gettimeofday(&tv); + dns_info[index].last_tv = tv; + dns_info[index].in_timer = true; + } + return; +} + +static bool is_need_change_dns_network(int index) +{ + bool ret = false; + + if (oplus_sla_info[index].weight && + WEIGHT_STATE_USELESS != oplus_sla_info[index].weight_state && + WEIGHT_STATE_SCORE_INVALID != oplus_sla_info[index].weight_state) { + + if (0 == oplus_sla_info[MAIN_WLAN].weight || + WEIGHT_STATE_USELESS == oplus_sla_info[MAIN_WLAN].weight_state || + WEIGHT_STATE_SCORE_INVALID == oplus_sla_info[MAIN_WLAN].weight_state || + (oplus_sla_info[index].max_speed >= 100 && + oplus_sla_info[MAIN_WLAN].wlan_score_bad_count >= WLAN_SCORE_BAD_NUM)) { + + ret = true; + } + } + + return ret; +} + +static int dns_skb_need_sla(struct nf_conn *ct,struct sk_buff *skb) +{ + int ret = SLA_SKB_CONTINUE; + struct iphdr *iph = NULL; + int dns_iface = MAIN_WLAN; + u_int32_t dns_ct_mark = MAIN_WLAN_MARK; + + iph = ip_hdr(skb); + if(NULL != iph && + (iph->protocol == IPPROTO_TCP || iph->protocol == IPPROTO_UDP) && + 53 == ntohs(udp_hdr(skb)->dest)){ + + ret = SLA_SKB_ACCEPT; + + if (SLA_MODE_DUAL_WIFI == sla_work_mode) { + if (is_need_change_dns_network(SECOND_WLAN)) { + //for the dns packet will do DNAT at iptables,if do DNAT,the packet + //will be reroute,so here just mark and accept it + dns_iface = SECOND_WLAN; + dns_ct_mark = SECOND_WLAN_MARK; + skb->mark = SECOND_WLAN_MARK; + } + } else if (SLA_MODE_WIFI_CELL == sla_work_mode) { + if (is_need_change_dns_network(CELL_INDEX)) { + + dns_iface = CELL_INDEX; + dns_ct_mark = CELL_MARK; + skb->mark = CELL_MARK; + } + } + + ct->mark = dns_ct_mark; + statistic_dns_send_info(dns_iface); + } + return ret; +} + + +static void dns_respond_statistics(struct sk_buff *skb) +{ + int index = -1; + int tmp_mark = 0; + struct iphdr *iph = NULL; + struct nf_conn *ct = NULL; + enum ip_conntrack_info ctinfo; + + if (!oplus_sla_enable) { + return; + } + + ct = nf_ct_get(skb, &ctinfo); + + if(NULL == ct){ + return; + } + + iph = ip_hdr(skb); + if(NULL != iph && + (iph->protocol == IPPROTO_TCP || iph->protocol == IPPROTO_UDP) && + 53 == ntohs(udp_hdr(skb)->source)){ + + tmp_mark = ct->mark & MARK_MASK; + index = find_dev_index_by_mark(tmp_mark); + + if (-1 != index) { + if (dns_info[index].send_num) { + + dns_info[index].send_num = 0; + dns_info[index].in_timer = false; + } + } + } + return; +} + +static void detect_white_list_app_skb(struct sk_buff *skb) +{ + int i = 0; + int index = -1; + kuid_t uid; + struct nf_conn *ct = NULL; + enum ip_conntrack_info ctinfo; + struct sock *sk = NULL; + const struct file *filp = NULL; + + ct = nf_ct_get(skb, &ctinfo); + + if(NULL == ct){ + return; + } + + /*when the app type is dual sta app,but the work mode is not + SLA_MODE_DUAL_WIFI, we should detect it is WIFI+CELL white + list app again + */ + if (SLA_MODE_DUAL_WIFI != sla_work_mode && + ct->oplus_app_type >= DUAL_STA_APP_BASE) { + ct->oplus_app_type = INIT_APP_TYPE; + } + + if(INIT_APP_TYPE == ct->oplus_app_type){ + sk = skb_to_full_sk(skb); + if(NULL == sk || NULL == sk->sk_socket){ + return; + } + + filp = sk->sk_socket->file; + if(NULL == filp){ + return; + } + + uid = filp->f_cred->fsuid; + for(i = 0;i < white_app_list.count;i++){ + if(white_app_list.uid[i]){ + if((uid.val % UID_MASK) == (white_app_list.uid[i] % UID_MASK)) { + ct->oplus_app_type = i + WHITE_APP_BASE; + return; + } + } + } + + //we need to detect the whether it is dual sta white list app + if (SLA_MODE_DUAL_WIFI != sla_work_mode) { + ct->oplus_app_type = UNKNOW_APP_TYPE; + } + } + else if(ct->oplus_app_type >= WHITE_APP_BASE && + ct->oplus_app_type < DUAL_STA_APP_BASE){ + /*calc white app cell bytes when sla is not enable, + when the default network is change to cell,we should + disable dual sta from framework + */ + if(oplus_sla_info[CELL_INDEX].if_up){ + if(!oplus_sla_info[MAIN_WLAN].if_up || + oplus_sla_def_net == CELL_INDEX){ + index = ct->oplus_app_type - WHITE_APP_BASE; + if(index < WHITE_APP_NUM){ + white_app_list.cell_bytes_normal[index] += skb->len; + } + } + } + } + return; +} + +static bool is_dual_sta_white_app(struct nf_conn *ct,struct sk_buff *skb,kuid_t *app_uid) +{ + int i = 0; + int last_type = UNKNOW_APP_TYPE; + kuid_t uid; + struct sock *sk = NULL; + const struct file *filp = NULL; + + if (ct->oplus_app_type >= DUAL_STA_APP_BASE) { + return true; + } + + if(UNKNOW_APP_TYPE != ct->oplus_app_type){ + + last_type = ct->oplus_app_type; + + sk = skb_to_full_sk(skb); + if(NULL == sk || NULL == sk->sk_socket){ + return false; + } + + filp = sk->sk_socket->file; + if(NULL == filp){ + return false; + } + + *app_uid = filp->f_cred->fsuid; + uid = filp->f_cred->fsuid; + for(i = 0;i < dual_wifi_app_list.count;i++){ + if(dual_wifi_app_list.uid[i]){ + if((uid.val % UID_MASK) == (dual_wifi_app_list.uid[i] % UID_MASK)) { + ct->oplus_app_type = i + DUAL_STA_APP_BASE; + return true; + } + } + } + ct->oplus_app_type = last_type; + } + + return false; +} + +static void print_stream_info(struct sk_buff *skb) +{ + u32 uid = 0; + int srcport = 0; + int dstport = 0; + unsigned char *dstip; + + struct sock *sk = NULL; + struct iphdr *iph = NULL; + struct nf_conn *ct = NULL; + struct net_device *dev = NULL; + enum ip_conntrack_info ctinfo; + const struct file *filp = NULL; + + if (oplus_sla_debug) { + ct = nf_ct_get(skb, &ctinfo); + if(NULL == ct){ + return; + } + + if (ctinfo == IP_CT_NEW) { + sk = skb_to_full_sk(skb); + if(sk && sk_fullsock(sk)){ + if(NULL == sk->sk_socket){ + return; + } + + filp = sk->sk_socket->file; + if(NULL == filp){ + return; + } + + iph = ip_hdr(skb); + if (NULL != iph && + (iph->protocol == IPPROTO_TCP || iph->protocol == IPPROTO_UDP)) { + + dev = skb_dst(skb)->dev; + uid = filp->f_cred->fsuid.val; + dstport = ntohs(udp_hdr(skb)->dest); + srcport = ntohs(udp_hdr(skb)->source); + dstip = (unsigned char *)&iph->daddr; + + printk("oplus_sla_stream: screen_on[%d] uid[%u]" + " proto[%d] srcport[%d] dstport[%d] dstip[%d.%d.%d.%d] dev[%s] mark[%x]\n", + sla_screen_on,uid,iph->protocol,srcport,dstport, + dstip[0],dstip[1],dstip[2],dstip[3],dev?dev->name:"null",skb->mark); + } + } + } + } + return; +} + +static int sla_mark_skb(struct sk_buff *skb, const struct nf_hook_state *state) +{ + int index = 0; + kuid_t app_uid = {0}; + u32 ct_mark = 0x0; + struct sock *sk = NULL; + struct nf_conn *ct = NULL; + int ret = SLA_SKB_CONTINUE; + enum ip_conntrack_info ctinfo; + + //if wlan assistant has change network to cell,do not mark SKB + if(oplus_sla_def_net == CELL_INDEX){ + return NF_ACCEPT; + } + + ct = nf_ct_get(skb, &ctinfo); + if(NULL == ct){ + return NF_ACCEPT; + } + + /* + * when the wifi is poor,the dns request allways can not rcv respones, + * so please let the dns packet with the cell network mark. + */ + ret = dns_skb_need_sla(ct,skb); + if(SLA_SKB_ACCEPT == ret) { + return NF_ACCEPT; + } + + if(is_skb_pre_bound(skb) || dst_is_lan_ip(skb)){ + return NF_ACCEPT; + } + + if(SLA_MODE_WIFI_CELL == sla_work_mode && + !is_sla_white_or_game_app(ct,skb)){ + return NF_ACCEPT; + } + + if (SLA_MODE_DUAL_WIFI == sla_work_mode && + !is_dual_sta_white_app(ct,skb,&app_uid)) { + return NF_ACCEPT; + } + + ret = mark_game_app_skb(ct,skb,ctinfo); + if(SLA_SKB_MARKED == ret){ + goto sla_reroute; + } + else if(SLA_SKB_ACCEPT == ret){ + return NF_ACCEPT; + } + else if(SLA_SKB_DROP == ret){ + return NF_DROP; + } + + if(ctinfo == IP_CT_NEW){ + sk = skb_to_full_sk(skb); + if(NULL != sk){ + ret = syn_retransmits_packet_do_specail(sk,ct,skb); + if(SLA_SKB_MARKED == ret){ + goto sla_reroute; + } + else if(SLA_SKB_REMARK == ret){ + return NF_DROP; + } + else if(SLA_SKB_ACCEPT == ret){ + return NF_ACCEPT; + } + + // add for download app stream + ret = mark_download_app(sk,app_uid,ct,skb); + if (SLA_SKB_MARKED == ret) { + goto sla_reroute; + } + + // add for vedio app stream + ret = mark_video_app(sk,app_uid,ct,skb); + if (SLA_SKB_MARKED == ret) { + goto sla_reroute; + } + + sla_read_lock(); + skb->mark = get_skb_mark_by_weight(); + sla_read_unlock(); + + ct->mark = skb->mark; + sk->oplus_sla_mark = skb->mark; + //sk->sk_mark = sk->oplus_sla_mark; + } + } + else if((XT_STATE_BIT(ctinfo) & XT_STATE_BIT(IP_CT_ESTABLISHED)) || + (XT_STATE_BIT(ctinfo) & XT_STATE_BIT(IP_CT_RELATED))){ + + skb->mark = ct->mark & MARK_MASK; + } + + //If the mark value of the packet is equal to WLAN0_MARK, no re routing is required + if (MAIN_WLAN_MARK == skb->mark) { + return NF_ACCEPT; + } + + //calc white list app cell bytes + if(ct->oplus_app_type >= WHITE_APP_BASE && + ct->oplus_app_type < DUAL_STA_APP_BASE){ + ct_mark = ct->mark & MARK_MASK; + if(CELL_MARK == ct_mark){ + index = ct->oplus_app_type - WHITE_APP_BASE; + if(index < WHITE_APP_NUM){ + white_app_list.cell_bytes[index] += skb->len; + } + } + } + +sla_reroute: + ret = sla_skb_reroute(skb,ct,state); + return ret; + +} + +/* + * so how can we calc speed when app connect server with 443 dport(https) + */ +static void get_content_lenght(struct nf_conn *ct,struct sk_buff *skb,int header_len,int index){ + + char *p = (char *)skb->data + header_len; + + char *start = NULL; + char *end = NULL; + int temp_len = 0; + u64 tmp_time; + u32 content_len = 0; + char data_buf[256]; + char data_len[11]; + memset(data_len,0x0,sizeof(data_len)); + memset(data_buf,0x0,sizeof(data_buf)); + + if(ct->oplus_http_flag != 1 || ct->oplus_skb_count > 3){ + return; + } + ct->oplus_skb_count++; + + temp_len = (char *)skb_tail_pointer(skb) - p; + if(temp_len < 25){//HTTP/1.1 200 OK + Content-Length + return; + } + + p += 25; + + temp_len = (char *)skb_tail_pointer(skb) - p; + if(temp_len){ + if(temp_len > (sizeof(data_buf)-1)){ + + temp_len = (sizeof(data_buf)-1); + } + memcpy(data_buf,p,temp_len); + start = strstr(data_buf,"Content-Length"); + if(start != NULL){ + ct->oplus_http_flag = 2; + start += 16; //add Content-Length: + + end = strchr(start,0x0d);//get '\r\n' + + if(NULL != end){ + if((end - start) < 11){ + memcpy(data_len,start,end - start); + sscanf(data_len,"%u",&content_len); + //printk("oplus_sla_speed:content = %u\n",content_len); + } + else{ + content_len = 0x7FFFFFFF; + } + + tmp_time = ktime_get_ns(); + oplus_speed_info[index].sum_bytes += content_len; + if(0 == oplus_speed_info[index].bytes_time){ + oplus_speed_info[index].bytes_time = tmp_time; + } else { + if(oplus_speed_info[index].sum_bytes >= 20000 || + (tmp_time - oplus_speed_info[index].bytes_time) > 5000000000) { + oplus_speed_info[index].bytes_time = tmp_time; + if(oplus_speed_info[index].sum_bytes >= 20000){ + oplus_speed_info[index].ms_speed_flag = 1; + } + oplus_speed_info[index].sum_bytes = 0; + } + } + } + } + } +} + +/*only work for wifi +lte mode*/ +static unsigned int oplus_sla_speed_calc(struct sk_buff *skb) +{ + enum ip_conntrack_info ctinfo; + struct nf_conn *ct = NULL; + int index = -1; + int tmp_speed = 0; + u64 time_now = 0; + u64 tmp_time = 0; + struct iphdr *iph; + struct tcphdr *tcph; + int datalen = 0; + int header_len = 0; + + if(!sla_switch_enable || oplus_sla_enable){ + return NF_ACCEPT; + } + + //only calc wlan speed + if(oplus_sla_info[MAIN_WLAN].if_up && + !oplus_sla_info[CELL_INDEX].if_up){ + index = MAIN_WLAN; + } else { + return NF_ACCEPT; + } + + if(!enable_cell_to_user && + oplus_sla_calc_speed && + !oplus_speed_info[index].speed_done){ + + ct = nf_ct_get(skb, &ctinfo); + + if(NULL == ct){ + return NF_ACCEPT; + + } + + if(XT_STATE_BIT(ctinfo) & XT_STATE_BIT(IP_CT_ESTABLISHED)){ + if((iph = ip_hdr(skb)) != NULL && + iph->protocol == IPPROTO_TCP){ + + tcph = tcp_hdr(skb); + datalen = ntohs(iph->tot_len); + header_len = iph->ihl * 4 + tcph->doff * 4; + + if((datalen - header_len) >= 64){//ip->len > tcphdrlen + + if(!oplus_speed_info[index].ms_speed_flag){ + get_content_lenght(ct,skb,header_len,index); + } + + if(oplus_speed_info[index].ms_speed_flag){ + + time_now = ktime_get_ns(); + if(0 == oplus_speed_info[index].last_time && + 0 == oplus_speed_info[index].first_time){ + oplus_speed_info[index].last_time = time_now; + oplus_speed_info[index].first_time = time_now; + oplus_speed_info[index].rx_bytes = skb->len; + return NF_ACCEPT; + } + + tmp_time = time_now - oplus_speed_info[index].first_time; + oplus_speed_info[index].rx_bytes += skb->len; + oplus_speed_info[index].last_time = time_now; + if(tmp_time > 500000000) { + oplus_speed_info[index].ms_speed_flag = 0; + tmp_time = oplus_speed_info[index].last_time - oplus_speed_info[index].first_time; + tmp_speed = (1000 *1000*oplus_speed_info[index].rx_bytes) / (tmp_time);//kB/s + + oplus_speed_info[index].speed_done = 1; + do_gettimeofday(&last_calc_small_speed_tv); + + if(cell_quality_good && + !rate_limit_info.rate_limit_enable && + tmp_speed > CALC_WEIGHT_MIN_SPEED_1 && + tmp_speed < CALC_WEIGHT_MIN_SPEED_3 && + oplus_sla_info[index].max_speed < 100){ + + send_enable_to_framework(SLA_MODE_WIFI_CELL,INIT_ACTIVE_TYPE); + printk("oplus_sla_netlink: calc speed is small,send enable sla to user\n"); + } + + printk("oplus_sla_speed: speed[%d] = %d\n",index,tmp_speed); + } + } + } + } + } + } + + return NF_ACCEPT; +} + +/* oplus sla hook function, mark skb and rerout skb +*/ +static unsigned int oplus_sla_output_hook(void *priv, + struct sk_buff *skb, + const struct nf_hook_state *state) +{ + int ret = NF_ACCEPT; + int game_ret = NF_ACCEPT; + + game_ret = detect_game_up_skb(skb); + if(SLA_SKB_ACCEPT == game_ret){ + goto end_sla_output; + } + + //we need to calc white list app cell bytes when sla not enabled + detect_white_list_app_skb(skb); + + if(oplus_sla_enable){ + + ret = sla_mark_skb(skb,state); + } + else{ + + if(!sla_screen_on){ + goto end_sla_output; + } + + if(oplus_sla_info[MAIN_WLAN].if_up){ + + ret = get_wlan_syn_retran(skb); + + if(oplus_sla_calc_speed && + !oplus_speed_info[MAIN_WLAN].speed_done){ + ret = wlan_get_speed_prepare(skb); + } + } + } +end_sla_output: + //add for android Q statictis tcp tx and tx + statistics_wlan_tcp_tx_rx(state,skb); + print_stream_info(skb); + return ret; +} + +static unsigned int oplus_sla_input_hook(void *priv, + struct sk_buff *skb, + const struct nf_hook_state *state) +{ + //add for android Q statictis tcp tx and tx + statistics_wlan_tcp_tx_rx(state,skb); + dns_respond_statistics(skb); + oplus_sla_speed_calc(skb); + oplus_sla_game_rtt_calc(skb); + + return NF_ACCEPT; +} + +static void oplus_statistic_dev_rtt(struct sock *sk,long rtt) +{ + int index = -1; + int tmp_rtt = rtt / 1000; //us -> ms + u32 mark = sk->oplus_sla_mark & MARK_MASK; + + if(oplus_sla_def_net == CELL_INDEX){ + index = CELL_INDEX; + }else if(!oplus_sla_enable) { + if (oplus_sla_info[MAIN_WLAN].if_up){ + index = MAIN_WLAN; + } else if (oplus_sla_info[CELL_INDEX].if_up){ + index = CELL_INDEX; + } + } else { + index = find_dev_index_by_mark(mark); + } + + if(-1 != index){ + calc_rtt_by_dev_index(index, tmp_rtt, sk); + #ifdef OPLUS_FEATURE_APP_MONITOR + /* Add for apps network monitors */ + statistics_monitor_apps_rtt_via_uid(index, tmp_rtt, sk); + #endif /* OPLUS_FEATURE_APP_MONITOR */ + } +} + +/*sometimes when skb reject by iptables, +*it will retran syn which may make the rtt much high +*so just mark the stream(ct) with mark IPTABLE_REJECT_MARK when this happens +*/ +static void sla_mark_streams_for_iptables_reject(struct sk_buff *skb,enum ipt_reject_with reject_type) +{ + struct nf_conn *ct = NULL; + enum ip_conntrack_info ctinfo; + + ct = nf_ct_get(skb, &ctinfo); + if(NULL == ct){ + return; + } + ct->mark |= RTT_MARK; + + if (oplus_sla_debug) { + if(ctinfo == IP_CT_NEW){ + struct sock *sk = skb_to_full_sk(skb); + const struct file *filp = NULL; + if(sk && sk_fullsock(sk)){ + if(NULL == sk->sk_socket){ + return; + } + + filp = sk->sk_socket->file; + if(NULL == filp){ + return; + } + printk("oplus_sla_iptables:uid = %u,reject type = %u\n",filp->f_cred->fsuid.val,reject_type); + } + } + } + + return; +} + +static void is_need_calc_wlan_small_speed(int speed) +{ + if(sla_screen_on && + !enable_cell_to_user && + !oplus_sla_enable && + !oplus_sla_calc_speed && + !rate_limit_info.rate_limit_enable){ + + if(speed <= 100 && + speed > CALC_WEIGHT_MIN_SPEED_1 && + oplus_sla_info[MAIN_WLAN].minute_speed > MINUTE_LITTE_RATE){ + + printk("oplus_sla_speed: detect speed is little\n"); + oplus_sla_calc_speed = 1; + memset(&oplus_speed_info[MAIN_WLAN],0x0,sizeof(struct oplus_speed_calc)); + } + } +} + +static bool is_wlan_speed_good(int index) +{ + int i = index; + bool ret = false; + + if(oplus_sla_info[i].max_speed >= 300 && + oplus_sla_info[i].sla_avg_rtt < 150 && + oplus_sla_info[i].wlan_score >= 60 && + oplus_sla_info[i].download_flag < DOWNLOAD_FLAG){ + ret = true; + } + return ret; +} + +static void auto_disable_sla_for_good_wlan(void) +{ + int work_mode = SLA_MODE_WIFI_CELL; + int time_interval; + struct timeval tv; + + do_gettimeofday(&tv); + time_interval = tv.tv_sec - last_enable_cellular_tv.tv_sec; + + if(oplus_sla_enable && + time_interval >= 300 && + !game_online_info.game_online && + SLA_MODE_WIFI_CELL == sla_work_mode && + oplus_sla_info[MAIN_WLAN].sla_avg_rtt < 150 && + oplus_sla_info[MAIN_WLAN].max_speed >= 300){ + + enable_cell_to_user = false; + oplus_sla_send_to_user(SLA_DISABLE,(char *)&work_mode,sizeof(int)); + + sla_write_lock(); + oplus_sla_info[MAIN_WLAN].weight = 100; + oplus_sla_info[CELL_INDEX].weight = 0; + sla_write_unlock(); + + printk("oplus_sla_netlink:speed good,disable sla\n"); + } +} + +static void auto_disable_dual_wifi(void) +{ + int work_mode = SLA_MODE_DUAL_WIFI; + int time_interval; + struct timeval tv; + + do_gettimeofday(&tv); + time_interval = tv.tv_sec - last_enable_cellular_tv.tv_sec; + + if(oplus_sla_enable && + time_interval >= 300 && + !game_online_info.game_online && + SLA_MODE_DUAL_WIFI == sla_work_mode && + is_wlan_speed_good(MAIN_WLAN) && + oplus_sla_info[SECOND_WLAN].minute_speed < MINUTE_LITTE_RATE){ + + enable_second_wifi_to_user = false; + oplus_sla_send_to_user(SLA_DISABLE,(char *)&work_mode,sizeof(int)); + + sla_write_lock(); + oplus_sla_info[MAIN_WLAN].weight = 100; + oplus_sla_info[SECOND_WLAN].weight = 0; + sla_write_unlock(); + + printk("oplus_sla_netlink:speed good,disable dual wifi\n"); + } +} + +static void detect_wlan_state_with_speed(void) +{ + auto_disable_dual_wifi(); + auto_disable_sla_for_good_wlan(); + is_need_calc_wlan_small_speed(oplus_sla_info[MAIN_WLAN].max_speed); +} + +static void reset_network_state_by_speed(int index,int speed) +{ + int i = index; + if(speed > 400) { + if (oplus_sla_info[i].avg_rtt > 150) { + oplus_sla_info[i].avg_rtt -= 50; + } + if (oplus_sla_info[i].sla_avg_rtt > 150) { + oplus_sla_info[i].sla_avg_rtt -=50; + } + oplus_sla_info[i].congestion_flag = CONGESTION_LEVEL_NORMAL; + } + + //when the network speed is bigger than 50KB/s,we shoud reset the weight_state + if (speed >= 50 && + WEIGHT_STATE_USELESS == oplus_sla_info[i].weight_state) { + oplus_sla_info[i].weight_state = WEIGHT_STATE_NORMAL; + } + + return; +} +static void detect_dl_little_speed(int index,int speed) +{ + int i = index; + + if(speed >= CALC_WEIGHT_MIN_SPEED_2){ + if (oplus_sla_info[i].little_speed_num < ADJUST_SPEED_NUM) { + oplus_sla_info[i].little_speed_num++; + if (speed > oplus_sla_info[i].tmp_little_speed) { + oplus_sla_info[i].tmp_little_speed = speed; + } + + if (ADJUST_SPEED_NUM == oplus_sla_info[i].little_speed_num) { + oplus_sla_info[i].dl_little_speed = oplus_sla_info[i].tmp_little_speed; + } + } + } else { + oplus_sla_info[i].tmp_little_speed = 0; + oplus_sla_info[i].little_speed_num = 0; + } +} + +static void detect_network_download(int index,int speed) +{ + int i = index; + + if(speed > DOWNLOAD_SPEED){ + if (oplus_sla_info[i].download_num < ADJUST_SPEED_NUM) { + oplus_sla_info[i].download_num++; + if (speed > oplus_sla_info[i].dl_mx_speed) { + oplus_sla_info[i].dl_mx_speed = speed; + } + } + + //Adjust the speed to prevent speed burst leading to high speed + if (ADJUST_SPEED_NUM == oplus_sla_info[i].download_num) { + + if (oplus_sla_info[i].download_speed > oplus_sla_info[i].dl_mx_speed) { + oplus_sla_info[i].download_speed += oplus_sla_info[i].dl_mx_speed; + oplus_sla_info[i].download_speed /= 2; + } + else { + oplus_sla_info[i].download_speed = oplus_sla_info[i].dl_mx_speed; + } + + if (oplus_sla_info[i].max_speed > oplus_sla_info[i].download_speed) { + oplus_sla_info[i].max_speed = oplus_sla_info[i].download_speed; + } + + oplus_sla_info[i].download_num = 0; + oplus_sla_info[i].dl_mx_speed = 0; + if (oplus_sla_debug) { + printk("oplus_sla_speed: adjust download speed = %d\n",oplus_sla_info[i].download_speed); + } + } + + if (speed > (oplus_sla_info[i].download_speed / 2)) { + if (speed < rom_update_info.dual_wlan_download_speed && + oplus_sla_info[i].download_speed < rom_update_info.dual_wlan_download_speed && + oplus_sla_info[i].dual_wifi_download < (2 * DOWNLOAD_FLAG)) { + + oplus_sla_info[i].dual_wifi_download++; + } else if (speed >= rom_update_info.dual_wlan_download_speed || + oplus_sla_info[i].download_speed >= rom_update_info.dual_wlan_download_speed){ + + if(oplus_sla_info[i].dual_wifi_download >= 2){ + oplus_sla_info[i].dual_wifi_download -= 2; + } + else if(oplus_sla_info[i].dual_wifi_download){ + oplus_sla_info[i].dual_wifi_download--; + } + } + + if(oplus_sla_info[i].download_flag < (2 * DOWNLOAD_FLAG)){ + oplus_sla_info[i].download_flag++; + } + } + } + else { + oplus_sla_info[i].download_num = 0; + oplus_sla_info[i].dl_mx_speed = 0; + } + + if(speed < (oplus_sla_info[i].download_speed / 3)){ + + if(oplus_sla_info[i].download_flag >= 2){ + oplus_sla_info[i].download_flag -= 2; + } + else if(oplus_sla_info[i].download_flag){ + oplus_sla_info[i].download_flag--; + } + + if(oplus_sla_info[i].dual_wifi_download >= 2){ + oplus_sla_info[i].dual_wifi_download -= 2; + } + else if(oplus_sla_info[i].dual_wifi_download){ + oplus_sla_info[i].dual_wifi_download--; + } + } + return; +} + +static void adjust_speed_with_romupdate_param(int index) +{ + int i = index; + + if(CELL_INDEX == i && + oplus_sla_info[i].max_speed > rom_update_info.cell_speed){ + + oplus_sla_info[i].max_speed = rom_update_info.cell_speed; + } + + if(MAIN_WLAN == i || SECOND_WLAN == i){ + if(oplus_sla_info[i].wlan_score <= rom_update_info.wlan_bad_score && + oplus_sla_info[i].max_speed > rom_update_info.wlan_little_score_speed){ + oplus_sla_info[i].max_speed = rom_update_info.wlan_little_score_speed; + } + else if(MAIN_WLAN == i && + oplus_sla_info[i].max_speed > rom_update_info.wlan_speed){ + oplus_sla_info[i].max_speed = rom_update_info.wlan_speed; + } + else if (SECOND_WLAN == i && + oplus_sla_info[i].max_speed > rom_update_info.second_wlan_speed) { + oplus_sla_info[i].max_speed = rom_update_info.second_wlan_speed; + } + } + return; +} + +static void calc_download_speed(int index,u64 total_bytes,int time) +{ + int i = index; + int dl_speed = 0; + u64 bytes = 0; + + if (time >= DOWNLOAD_SPEED_TIME ) { + if (0 == oplus_sla_info[i].dl_total_bytes || + oplus_sla_info[i].dl_total_bytes > total_bytes) { + + oplus_sla_info[i].dl_total_bytes = total_bytes; + } + else { + bytes = total_bytes - oplus_sla_info[i].dl_total_bytes; + dl_speed = bytes / time; + dl_speed = dl_speed / 1000; + oplus_sla_info[i].dl_total_bytes = total_bytes; + + detect_dl_little_speed(i,dl_speed); + detect_network_download(i,dl_speed); + + if (dl_speed > oplus_sla_info[i].download_speed) { + oplus_sla_info[i].left_speed = dl_speed - oplus_sla_info[i].download_speed; + } + else { + oplus_sla_info[i].left_speed = oplus_sla_info[i].download_speed - dl_speed; + } + + if (oplus_sla_debug) { + printk("oplus_sla: cur download speed[%d] = %d\n",i,dl_speed); + } + } + } +} + +static inline int dev_isalive(const struct net_device *dev) +{ + return dev->reg_state <= NETREG_REGISTERED; +} + +static void statistic_dev_speed(struct timeval tv,int time_interval) +{ + int i=0; + int temp_speed; + u64 temp_bytes; + u64 total_bytes = 0; + int tmp_minute_time; + int tmp_minute_speed; + int download_time = 0; + int do_calc_minute_speed = 0; + struct net_device *dev; + const struct rtnl_link_stats64 *stats; + struct rtnl_link_stats64 temp; + + tmp_minute_time = tv.tv_sec - last_minute_speed_tv.tv_sec; + if(tmp_minute_time >= LITTLE_FLOW_TIME){ + last_minute_speed_tv = tv; + do_calc_minute_speed = 1; + } + + download_time = tv.tv_sec - last_download_speed_tv.tv_sec; + if (download_time >= DOWNLOAD_SPEED_TIME) { + last_download_speed_tv = tv; + } + + for(i = 0; i < IFACE_NUM; i++){ + if(oplus_sla_info[i].if_up || oplus_sla_info[i].need_up){ + dev = dev_get_by_name(&init_net, oplus_sla_info[i].dev_name); + if(dev) { + if (dev_isalive(dev) && + (NULL != dev->netdev_ops) && + (stats = dev_get_stats(dev, &temp))){ + //first time have no value,and maybe oplus_sla_info[i].rx_bytes will more than stats->rx_bytes + total_bytes = stats->rx_bytes + stats->tx_bytes; + if(0 == oplus_sla_info[i].total_bytes || + oplus_sla_info[i].total_bytes > total_bytes){ + + oplus_sla_info[i].total_bytes = total_bytes; + oplus_sla_info[i].minute_rx_bytes = total_bytes; + } + else{ + + if(do_calc_minute_speed){ + + temp_bytes = total_bytes - oplus_sla_info[i].minute_rx_bytes; + oplus_sla_info[i].minute_rx_bytes = total_bytes; + tmp_minute_speed = (8 * temp_bytes) / tmp_minute_time; //kbit/s + oplus_sla_info[i].minute_speed = tmp_minute_speed / 1000; + + if(MAIN_WLAN == i){ + detect_wlan_state_with_speed(); + } + } + + temp_bytes = total_bytes - oplus_sla_info[i].total_bytes; + oplus_sla_info[i].total_bytes = total_bytes; + + temp_speed = temp_bytes / time_interval; + temp_speed = temp_speed / 1000;//kB/s + oplus_sla_info[i].current_speed = temp_speed; + + if(temp_speed > oplus_sla_info[i].max_speed){ + oplus_sla_info[i].max_speed = temp_speed; + } + + if (temp_speed > oplus_sla_info[i].download_speed) { + oplus_sla_info[i].download_speed = temp_speed; + } + + calc_download_speed(i,total_bytes,download_time); + reset_network_state_by_speed(i,temp_speed); + adjust_speed_with_romupdate_param(i); + + } + } + dev_put(dev); + } + + if(oplus_sla_debug /*&& net_ratelimit()*/){ + printk("oplus_sla: dev_name = %s,if_up = %d,max_speed = %d," + "current_speed = %d,avg_rtt = %d,congestion = %d," + "is_download = %d,syn_retran = %d,minute_speed = %d," + "weight_state = %d,download_speed = %d,dual_wifi_download = %d,dl_little_speed = %d\n", + oplus_sla_info[i].dev_name,oplus_sla_info[i].if_up, + oplus_sla_info[i].max_speed,oplus_sla_info[i].current_speed, + oplus_sla_info[i].sla_avg_rtt,oplus_sla_info[i].congestion_flag, + oplus_sla_info[i].download_flag,oplus_sla_info[i].syn_retran, + oplus_sla_info[i].minute_speed,oplus_sla_info[i].weight_state, + oplus_sla_info[i].download_speed,oplus_sla_info[i].dual_wifi_download,oplus_sla_info[i].dl_little_speed); + } + + } + } +} + + +static void reset_invalid_network_info(struct oplus_dev_info *node) +{ + struct timeval tv; + + //to avoid when weight_state change WEIGHT_STATE_USELESS now , + //but the next moment change to WEIGHT_STATE_RECOVERY + //because of minute_speed is little than MINUTE_LITTE_RATE; + do_gettimeofday(&tv); + last_minute_speed_tv = tv; + node->minute_speed = MINUTE_LITTE_RATE; + + sla_rtt_write_lock(); + node->rtt_index = 0; + node->sum_rtt= 0; + node->avg_rtt = 0; + node->sla_avg_rtt = 0; + node->sla_rtt_num = 0; + node->sla_sum_rtt = 0; + sla_rtt_write_unlock(); + + node->max_speed = 0; + node->left_speed = 0; + node->current_speed = 0; + node->syn_retran = 0; + node->download_flag = 0; + node->download_speed = 0; + node->dual_wifi_download = 0; + node->weight_state = WEIGHT_STATE_USELESS; + + if(oplus_sla_debug){ + printk("oplus_sla: reset_invalid_network_info,dev_name = %s\n",node->dev_name); + } +} + +static bool calc_weight_with_wlan_state(void) +{ + bool ret = false; + + if(is_wlan_speed_good(MAIN_WLAN)){ + ret = true; + oplus_sla_info[MAIN_WLAN].weight = 100; + if (SLA_MODE_WIFI_CELL == sla_work_mode) { + oplus_sla_info[CELL_INDEX].weight = 0; + } else if (SLA_MODE_DUAL_WIFI == sla_work_mode){ + oplus_sla_info[SECOND_WLAN].weight = 0; + } + } + return ret; +} + +static int calc_weight_with_speed(int speed_1,int speed_2) +{ + int tmp_weight; + int sum_speed = speed_1 + speed_2; + + tmp_weight = (100 * speed_1) / sum_speed; + + return tmp_weight; +} + +/*network_1 must be the main wifi */ +static int calc_weight_with_left_speed(int network_1,int network_2) +{ + int speed1; + int speed2; + int index1 = network_1; + int index2 = network_2; + + if((oplus_sla_info[index1].download_flag >= DOWNLOAD_FLAG || + oplus_sla_info[index2].download_flag >= DOWNLOAD_FLAG) && + (oplus_sla_info[index1].max_speed > CALC_WEIGHT_MIN_SPEED_2 && + oplus_sla_info[index2].max_speed > CALC_WEIGHT_MIN_SPEED_2)){ + + if (oplus_sla_info[index1].download_flag >= DOWNLOAD_FLAG) { + if (is_wlan_speed_good(index2) && + oplus_sla_info[index1].download_speed <= MAX_WLAN_SPEED){ + if (oplus_sla_debug) { + printk("oplus_sla_weight:network1 is download and network2 is much better\n"); + } + oplus_sla_info[index1].weight = 0; + oplus_sla_info[index2].weight = 100; + return 1; + } + + if (oplus_sla_info[index2].max_speed <= CALC_WEIGHT_MIN_SPEED_3) { + if (oplus_sla_info[index2].avg_rtt >= rom_update_info.sla_rtt) { + if (oplus_sla_debug) { + printk("oplus_sla_weight:network1 is download but network1 is very bad\n"); + } + oplus_sla_info[index1].weight = 100; + oplus_sla_info[index2].weight = 0; + return 1; + } + speed1 = oplus_sla_info[index1].max_speed; + } else { + speed1 = oplus_sla_info[index1].left_speed; + } + } + else { + speed1 = oplus_sla_info[index1].max_speed; + } + + if (oplus_sla_info[index2].download_flag >= DOWNLOAD_FLAG) { + if (is_wlan_speed_good(index1) && + oplus_sla_info[index2].download_speed <= MAX_WLAN_SPEED){ + if (oplus_sla_debug) { + printk("oplus_sla_weight:network2 is download and network1 is much better\n"); + } + oplus_sla_info[index1].weight = 100; + oplus_sla_info[index2].weight = 0; + return 1; + } + + if (oplus_sla_info[index1].max_speed <= CALC_WEIGHT_MIN_SPEED_3) { + if (oplus_sla_info[index1].avg_rtt >= rom_update_info.sla_rtt) { + if (oplus_sla_debug) { + printk("oplus_sla_weight:network2 is download but network1 is very bad\n"); + } + oplus_sla_info[index1].weight = 0; + oplus_sla_info[index2].weight = 100; + return 1; + } + speed2 = oplus_sla_info[index2].max_speed; + } else { + speed2 = oplus_sla_info[index2].left_speed; + } + } + else { + speed2 = oplus_sla_info[index2].max_speed; + } + + oplus_sla_info[index1].weight = calc_weight_with_speed(speed1,speed2); + oplus_sla_info[index2].weight = 100; + if (oplus_sla_debug) { + printk("oplus_sla_weight: calc weight with download speed\n"); + } + return 1; + } + + return 0; +} + +static int calc_weight_with_weight_state(int network_1,int network_2) +{ + int index1 = network_1; + int index2 = network_2; + + if ((WEIGHT_STATE_USELESS == oplus_sla_info[index1].weight_state || + WEIGHT_STATE_SCORE_INVALID == oplus_sla_info[index1].weight_state) && + (WEIGHT_STATE_USELESS != oplus_sla_info[index2].weight_state && + WEIGHT_STATE_SCORE_INVALID != oplus_sla_info[index2].weight_state)) { + + oplus_sla_info[index1].weight = 0; + oplus_sla_info[index2].weight = 100; + if (oplus_sla_debug) { + printk("oplus_sla_weight: [%d] calc weight with WEIGHT_STATE_USELESS \n",index1); + } + return 1; + } + else if ((WEIGHT_STATE_USELESS != oplus_sla_info[index1].weight_state && + WEIGHT_STATE_SCORE_INVALID != oplus_sla_info[index1].weight_state) && + (WEIGHT_STATE_USELESS == oplus_sla_info[index2].weight_state || + WEIGHT_STATE_SCORE_INVALID == oplus_sla_info[index2].weight_state)) { + + oplus_sla_info[index2].weight = 0; + oplus_sla_info[index1].weight = 100; + if (oplus_sla_debug) { + printk("oplus_sla_weight: [%d]calc weight with WEIGHT_STATE_USELESS \n",index2); + } + return 1; + } + return 0; +} + +static int calc_weight_with_little_speed(int network_1,int network_2) +{ + int index1 = network_1; + int index2 = network_2; + + if((is_wlan_speed_good(index2) && + oplus_sla_info[index1].max_speed <= CALC_WEIGHT_MIN_SPEED_2) || + (oplus_sla_info[index1].max_speed < CALC_WEIGHT_MIN_SPEED_1 && + CONGESTION_LEVEL_HIGH == oplus_sla_info[index1].congestion_flag)){ + + oplus_sla_info[index1].weight = 0; + oplus_sla_info[index2].weight = 100; + if (oplus_sla_debug) { + printk("oplus_sla_weight:calc weight with little speed \n"); + } + return 1; + } + + return 0; +} + +static bool is_main_wlan_poor(void) +{ + int index = MAIN_WLAN; + int score = 10 + rom_update_info.dual_wlan_bad_score; + + if(oplus_sla_info[index].wlan_score > 10 && + oplus_sla_info[index].wlan_score <= score) { + return true; + } + + if (oplus_sla_info[index].download_flag >= DOWNLOAD_FLAG) { + return true; + } + + if (oplus_sla_info[index].max_speed <= rom_update_info.sla_speed && + oplus_sla_info[index].sla_avg_rtt >= rom_update_info.dual_wifi_rtt) { + return true; + } + + if (oplus_sla_info[index].dl_little_speed < rom_update_info.sla_speed && + oplus_sla_info[index].download_speed < VIDEO_SPEED) { + return true; + } + + return false; +} + +/*network_1 must be the main wifi */ +static void recalc_two_network_weight(int network_1,int network_2) +{ + int index1 = network_1; + int index2 = network_2; + + int speed1 = oplus_sla_info[index1].max_speed; + int speed2 = oplus_sla_info[index2].max_speed; + + if(oplus_sla_info[index1].if_up && + oplus_sla_info[index2].if_up){ + + if(calc_weight_with_wlan_state() || + calc_weight_with_weight_state (index1, index2) || + calc_weight_with_left_speed(index1, index2) || + calc_weight_with_little_speed(index1, index2)){ + goto calc_weight_finish; + } + + if((speed1 >= CALC_WEIGHT_MIN_SPEED_2 && + speed2 >= CALC_WEIGHT_MIN_SPEED_2) || + (CONGESTION_LEVEL_HIGH == oplus_sla_info[index1].congestion_flag || + CONGESTION_LEVEL_HIGH == oplus_sla_info[index2].congestion_flag) || + ((CONGESTION_LEVEL_MIDDLE == oplus_sla_info[index1].congestion_flag || + CONGESTION_LEVEL_MIDDLE == oplus_sla_info[index2].congestion_flag) && + (speed1 >= CALC_WEIGHT_MIN_SPEED_1 && speed2 >= CALC_WEIGHT_MIN_SPEED_1))){ + + oplus_sla_info[index1].weight = calc_weight_with_speed(speed1,speed2); + } + else{ + if (SLA_MODE_DUAL_WIFI == sla_work_mode && + INIT_ACTIVE_TYPE == dual_wifi_active_type && + !is_main_wlan_poor()) { + + //for maul active or NetworRequest + oplus_sla_info[index1].weight = 100; + oplus_sla_info[index2].weight = 0; + } else if (SLA_MODE_DUAL_WIFI == sla_work_mode) { + oplus_sla_info[index1].weight = 30; + oplus_sla_info[index2].weight = 100; + } else if (SLA_MODE_WIFI_CELL == sla_work_mode) { + oplus_sla_info[index1].weight = 15; + oplus_sla_info[index2].weight = 100; + } + goto calc_weight_finish; + } + } + else if(oplus_sla_info[index1].if_up){ + oplus_sla_info[index1].weight = 100; + } + oplus_sla_info[index2].weight = 100; + +calc_weight_finish: + + if(oplus_sla_debug){ + printk("oplus_sla_weight: work_mode = %d,weight[%d] = %d,weight[%d] = %d\n", + sla_work_mode,index1,oplus_sla_info[index1].weight,index2,oplus_sla_info[index2].weight); + } + return; +} + +static void recalc_dual_wifi_weight(void) +{ + recalc_two_network_weight(MAIN_WLAN,SECOND_WLAN); + return; +} + +static void recalc_wifi_cell_weight(void) +{ + recalc_two_network_weight(MAIN_WLAN,CELL_INDEX); + oplus_sla_info[SECOND_WLAN].weight = 0; + return; +} + + +static void recalc_dual_wifi_cell_weight(void) +{ + int i = 0; + int sum_speed = 0; + int speed1 = oplus_sla_info[0].max_speed; + int speed2 = oplus_sla_info[1].max_speed; + int speed3 = oplus_sla_info[2].max_speed; + + for (i = 0; i < IFACE_NUM; i++) { + if (!oplus_sla_info[i].if_up) { + return; + } + } + + if (is_wlan_speed_good(MAIN_WLAN) || + is_wlan_speed_good(SECOND_WLAN) || + oplus_sla_info[MAIN_WLAN].download_flag >= DOWNLOAD_FLAG || + oplus_sla_info[SECOND_WLAN].download_flag >= DOWNLOAD_FLAG) { + recalc_two_network_weight(MAIN_WLAN,SECOND_WLAN); + goto finish_calc; + } + + if ((speed1 >= CALC_WEIGHT_MIN_SPEED_2 && + speed2 >= CALC_WEIGHT_MIN_SPEED_2 && + speed2 >= CALC_WEIGHT_MIN_SPEED_2) || + (oplus_sla_info[0].congestion_flag > CONGESTION_LEVEL_NORMAL && + oplus_sla_info[1].congestion_flag > CONGESTION_LEVEL_NORMAL && + oplus_sla_info[2].congestion_flag > CONGESTION_LEVEL_NORMAL)) { + + sum_speed = speed1 + speed2 + speed3; + oplus_sla_info[0].weight = (100 * speed1) / sum_speed; + oplus_sla_info[1].weight = (100 * (speed1 + speed2)) / sum_speed; + oplus_sla_info[2].weight = 100; + goto finish_calc; + } + + /*INIT dual wifi cell weight*/ + init_dual_wifi_cell_weight(); +finish_calc: + if(oplus_sla_debug){ + printk("oplus_sla_weight: work_mode = %d,weight[0] = %d,weight[1] = %d,weight[2] = %d\n", + sla_work_mode,oplus_sla_info[0].weight,oplus_sla_info[1].weight,oplus_sla_info[2].weight); + } + return; +} + +static void recalc_sla_weight(void) +{ + if(!oplus_sla_enable){ + return; + } + + sla_write_lock(); + if (SLA_MODE_DUAL_WIFI == sla_work_mode) { + recalc_dual_wifi_weight(); + } + else if (SLA_MODE_WIFI_CELL == sla_work_mode) { + recalc_wifi_cell_weight(); + } + else if (SLA_MODE_DUAL_WIFI_CELL == sla_work_mode) { + recalc_dual_wifi_cell_weight(); + } + sla_write_unlock(); + + return; +} + + +/*for when wlan up,but cell down,this will affect the rtt calc at wlan network(will calc big)*/ +static void up_wlan_iface_by_timer(struct timeval tv) +{ + int i = 0; + int time = 10; + for (i = 0; i < WLAN_NUM; i++) { + if(oplus_sla_info[i].need_up) { + if (SECOND_WLAN == i) { + time = 5; + } + + if ((tv.tv_sec - calc_wlan_rtt_tv.tv_sec) >= time){ + + oplus_sla_info[i].if_up = 1; + oplus_sla_info[i].need_up = false; + + printk("oplus_sla:wlan[%d]time[%d] up wlan iface actually\n",i, time); + } + } + } +} + +static void enable_to_user_time_out(struct timeval tv) +{ + if(enable_cell_to_user && + (tv.tv_sec - last_enable_cell_tv.tv_sec) >= ENABLE_TO_USER_TIMEOUT){ + enable_cell_to_user = false; + } + + if(enable_second_wifi_to_user && + (tv.tv_sec - last_enable_second_wifi_tv.tv_sec) >= ENABLE_TO_USER_TIMEOUT){ + enable_second_wifi_to_user = false; + } + + return; +} + +static void send_speed_and_rtt_to_user(void) +{ + int ret = 0; + if (oplus_sla_info[MAIN_WLAN].if_up || oplus_sla_info[MAIN_WLAN].need_up || + oplus_sla_info[CELL_INDEX].if_up) { + int payload[8]; + //add for android Q statictis tcp tx and tx + u64 tcp_tx_rx[4]; + char total_payload[64] = {0}; + + payload[0] = oplus_sla_info[MAIN_WLAN].max_speed; + payload[1] = oplus_sla_info[MAIN_WLAN].avg_rtt; + + payload[2] = oplus_sla_info[SECOND_WLAN].max_speed; + payload[3] = oplus_sla_info[SECOND_WLAN].avg_rtt; + + payload[4] = oplus_sla_info[CELL_INDEX].max_speed; + payload[5] = oplus_sla_info[CELL_INDEX].avg_rtt; + + payload[6] = sla_work_mode; + payload[7] = oplus_sla_info[MAIN_WLAN].download_speed; + + tcp_tx_rx[0] = wlan0_tcp_rx; + tcp_tx_rx[1] = wlan0_tcp_tx; + tcp_tx_rx[2] = wlan1_tcp_rx; + tcp_tx_rx[3] = wlan1_tcp_tx; + + memcpy(total_payload,payload,sizeof(payload)); + memcpy(total_payload + sizeof(payload),tcp_tx_rx,sizeof(tcp_tx_rx)); + + ret = oplus_sla_send_to_user(SLA_NOTIFY_SPEED_RTT, (char *) total_payload, sizeof(total_payload)); + if (oplus_sla_debug) { + printk("oplus_sla:send_speed_and_rtt_to_user wlan0:max_speed=%d, avg_rtt=%d " + "wlan1:max_speed=%d, avg_rtt=%d " + "cell:max_speed=%d, avg_rtt=%d, sla_work_mode=%d, wlan0_max_speed=%dKB/s, " + "wlan0_tcp_rx = %llu, wlan0_tcp_tx = %llu, wlan1_tcp_rx = %llu, wlan1_tcp_tx = %llu\n", + payload[0], payload[1], payload[2], payload[3], payload[4], payload[5], payload[6], payload[7], + tcp_tx_rx[0],tcp_tx_rx[1], tcp_tx_rx[2],tcp_tx_rx[3]); + } + } + return; +} + +static int wlan_can_enable_second_wifi(int index) +{ + int active_type = 0; + + /*if game is in front, do not active dual wifi by kernel*/ + if (wzry_traffic_info.game_in_front || + cjzc_traffic_info.game_in_front) { + return active_type; + } + + if (oplus_sla_info[index].if_up || + oplus_sla_info[index].need_up) { + int score = 10 + rom_update_info.dual_wlan_bad_score; + + if (oplus_sla_info[index].max_speed <= rom_update_info.sla_speed && + oplus_sla_info[index].sla_avg_rtt >= rom_update_info.dual_wifi_rtt) { + active_type = LOW_SPEED_HIGH_RTT; + return active_type; + } + + if(oplus_sla_info[index].wlan_score > 10 && + oplus_sla_info[index].wlan_score <= score) { + printk("oplus_sla: send enable dual wifi with score[%d]\n",score); + active_type = LOW_WLAN_SCORE; + return active_type; + } + } + return active_type; +} + +static bool wlan_can_enable_cell(int index) +{ + if (oplus_sla_info[index].if_up || + oplus_sla_info[index].need_up) { + + if (oplus_sla_info[index].download_flag < DOWNLOAD_FLAG) { + int score = rom_update_info.wlan_bad_score; + + if(SLA_MODE_DUAL_WIFI != sla_work_mode && + oplus_sla_info[index].wlan_score > 10 && + oplus_sla_info[index].wlan_score <= score) { + printk("oplus_sla: send enable sla with score[%d]\n",score); + return true; + } + + if (oplus_sla_info[index].max_speed <= rom_update_info.sla_speed && + (oplus_sla_info[index].sla_avg_rtt >= rom_update_info.sla_rtt || + oplus_sla_info[index].wlan_score_bad_count >= WLAN_SCORE_BAD_NUM)) { + + return true; + } + } + } + return false; +} + +static void sla_show_dailog(void) +{ + int i = 0; + int bad_count = 0; + bool wlan_bad = false; + + /*if has send msg to up second wifi,do no + show SLA dailog*/ + if(enable_second_wifi_to_user) { + return; + } + + if(sla_screen_on && + !sla_switch_enable && + need_show_dailog && + cell_quality_good && + !send_show_dailog_msg && + !rate_limit_info.rate_limit_enable) { + + for (i = 0; i < WLAN_NUM; i++) { + if (oplus_sla_info[i].if_up && + oplus_sla_info[i].download_flag < DOWNLOAD_FLAG && + oplus_sla_info[i].sla_avg_rtt >= rom_update_info.sla_rtt){ + + bad_count++; + if (MAIN_WLAN == i && + SLA_MODE_DUAL_WIFI != sla_work_mode){ + wlan_bad = true; + } + else if (WLAN_NUM == bad_count){ + wlan_bad = true; + } + } + } + + if (wlan_bad) { + send_show_dailog_msg = 1; + do_gettimeofday(&last_show_daillog_msg_tv); + oplus_sla_send_to_user(SLA_SHOW_DIALOG_NOW,NULL,0); + if(oplus_sla_debug){ + printk("oplus_sla_netlink:show dailog now\n"); + } + } + + } + return; +} + +static bool dual_wlan_enable_cell(void) +{ + int sum_speed = 0; + if (wlan_can_enable_cell(MAIN_WLAN) && + wlan_can_enable_cell(SECOND_WLAN)) { + if (oplus_sla_enable) { + printk("oplus_sla_netlink:[0] dual sta enable cell\n"); + } + return true; + } + else if (!init_weight_delay_count) { + sum_speed = oplus_sla_info[MAIN_WLAN].max_speed + oplus_sla_info[SECOND_WLAN].max_speed; + if (sum_speed <= rom_update_info.sla_speed && + (oplus_sla_info[MAIN_WLAN].sla_avg_rtt >= rom_update_info.sla_rtt || + oplus_sla_info[SECOND_WLAN].sla_avg_rtt >= rom_update_info.sla_rtt)) { + + if (oplus_sla_enable) { + printk("oplus_sla_netlink:[1] dual sta enable cell\n"); + } + return true; + } + } + + return false; +} + +static void sla_detect_should_enable(void) +{ + int active_type = 0; + if (sla_screen_on && CELL_INDEX != oplus_sla_def_net) { + if (dual_wifi_switch_enable && + SLA_MODE_DUAL_WIFI == sla_detect_mode) { + if (!oplus_sla_enable) { + if (!enable_second_wifi_to_user) { + active_type = wlan_can_enable_second_wifi(MAIN_WLAN); + dual_wifi_active_type = active_type; + if (active_type) { + send_enable_to_framework(SLA_MODE_DUAL_WIFI,active_type); + } + } + else if (!enable_cell_to_user && + sla_switch_enable && + cell_quality_good && + !rate_limit_info.rate_limit_enable && + wlan_can_enable_cell(MAIN_WLAN)) { + send_enable_to_framework(SLA_MODE_WIFI_CELL,INIT_ACTIVE_TYPE); + } + } + } + else if(!enable_cell_to_user && + sla_switch_enable && + cell_quality_good && + !rate_limit_info.rate_limit_enable && + SLA_MODE_WIFI_CELL == sla_detect_mode) { + + if (SLA_MODE_DUAL_WIFI == sla_work_mode) { + if (dual_wlan_enable_cell()) { + send_enable_to_framework(SLA_MODE_WIFI_CELL,INIT_ACTIVE_TYPE); + } + }else if (!oplus_sla_enable && + wlan_can_enable_cell(MAIN_WLAN)) { + send_enable_to_framework(SLA_MODE_WIFI_CELL,INIT_ACTIVE_TYPE); + } + } + } +} + +static void calc_network_rtt(struct timeval tv) +{ + + int index = 0; + int avg_rtt = 0; + + sla_rtt_write_lock(); + for(index = 0; index < IFACE_NUM; index++){ + avg_rtt = 0; + if(oplus_sla_info[index].if_up || oplus_sla_info[index].need_up){ + + if(oplus_sla_info[index].rtt_index >= RTT_NUM){ + + avg_rtt = oplus_sla_info[index].sum_rtt / oplus_sla_info[index].rtt_index; + if(oplus_sla_info[index].download_flag >= DOWNLOAD_FLAG) { + avg_rtt = avg_rtt / 2; + } + + oplus_sla_info[index].sla_rtt_num++; + oplus_sla_info[index].sla_sum_rtt += avg_rtt; + oplus_sla_info[index].avg_rtt = (7*oplus_sla_info[index].avg_rtt + avg_rtt) / 8; + oplus_sla_info[index].sum_rtt = 0; + oplus_sla_info[index].rtt_index = 0; + } + + avg_rtt = oplus_sla_info[index].sla_avg_rtt; + + if(oplus_sla_debug){ + printk("oplus_sla_rtt: index = %d,wlan_rtt = %d," + "wlan score bad = %u,cell_good = %d,need_show_dailog = %d,sceen_on = %d," + "enable_cell_to_user = %d,enable_wifi_to_user = %d,sla_switch_enable = %d,oplus_sla_enable= %d," + "oplus_sla_def_net = %d,sla_avg_rtt = %d,detect_mode = %d,work_mode = %d,game_cell_to_wifi = %d\n", + index,oplus_sla_info[index].avg_rtt, + oplus_sla_info[index].wlan_score_bad_count, + cell_quality_good,need_show_dailog,sla_screen_on, + enable_cell_to_user,enable_second_wifi_to_user,sla_switch_enable, + oplus_sla_enable,oplus_sla_def_net,avg_rtt,sla_detect_mode,sla_work_mode,game_cell_to_wifi); + } + } + } + sla_rtt_write_unlock(); + + return; + +} + +static void init_game_online_info(void) +{ + int i = 0; + + game_cell_to_wifi = false; + + sla_game_write_lock(); + for(i = 1; i < GAME_NUM; i++){ + game_uid[i].mark = MAIN_WLAN_MARK; + game_uid[i].switch_time = 0; + } + sla_game_write_unlock(); + if(oplus_sla_debug){ + printk("oplus_sla:init_game_online_info\n"); + } + memset(&game_online_info,0x0,sizeof(struct oplus_game_online)); +} + +static void init_game_start_state(void) +{ + int i = 0; + for(i = 1; i < GAME_NUM; i++){ + if(game_start_state[i]){ + game_start_state[i] = 0; + } + } +} + +static void game_rx_update(void) +{ + if (!oplus_sla_vpn_connected && + game_online_info.game_online) { + struct game_traffic_info* cur_info; + int i; + u32 game_index = 0; + u32 tcp_rx_large_count = 0; + u32 delta_udp_pkts = game_online_info.udp_rx_pkt_count; + u64 delta_tcp_bytes = game_online_info.tcp_rx_byte_count; + game_online_info.udp_rx_pkt_count = 0; + game_online_info.tcp_rx_byte_count = 0; + + if (wzry_traffic_info.game_in_front) { + cur_info = &wzry_traffic_info; + game_index = 1; + } else if (cjzc_traffic_info.game_in_front) { + cur_info = &cjzc_traffic_info; + game_index = 2; + } else { + //for debug only... + cur_info = &default_traffic_info; + cur_info->game_in_front = 0; + } + //fill in the latest delta udp rx packets and tcp rx bytes + cur_info->udp_rx_packet[cur_info->window_index % UDP_RX_WIN_SIZE] = delta_udp_pkts; + cur_info->tcp_rx_byte[cur_info->window_index % TCP_RX_WIN_SIZE] = delta_tcp_bytes; + cur_info->window_index++; + //deal with the control logic + if (udp_rx_show_toast) { + oplus_sla_send_to_user(SLA_NOTIFY_GAME_RX_PKT, (char *)&delta_udp_pkts, sizeof(delta_udp_pkts)); + } + + for (i = 0; i < TCP_RX_WIN_SIZE; i++) { + if (cur_info->tcp_rx_byte[i] > TCP_DOWNLOAD_THRESHOLD) { + tcp_rx_large_count++; + } + } + if (tcp_rx_large_count == TCP_RX_WIN_SIZE) { + if (oplus_sla_debug) { + //tcp downloading.. this should not be in a game. + if (oplus_sla_debug) { + printk("oplus_sla_game_rx_update:TCP downloading...should not be in a game.\n"); + } + } + if (inGame) { + inGame = false; + game_cell_to_wifi = false; + memset(cur_info->udp_rx_packet, 0x0, sizeof(u32)*UDP_RX_WIN_SIZE); + cur_info->window_index = 0; + } + } else { + int trafficCount = 0; + int lowTrafficCount = 0; + for (i = 0; i < UDP_RX_WIN_SIZE; i++) { + if (cur_info->udp_rx_packet[i] >= cur_info->udp_rx_min) { + trafficCount++; + if (cur_info->udp_rx_packet[i] <= cur_info->udp_rx_low_thr) { + lowTrafficCount++; + } + } + } + if (trafficCount >= cur_info->in_game_true_thr) { + if (!inGame) { + int index; + inGame = true; + game_cell_to_wifi = false; + for (index = 0; index < UDP_RX_WIN_SIZE; index++) { + cur_info->udp_rx_packet[index] = 20; + } + lowTrafficCount = 0; + } + } else if (trafficCount <= cur_info->in_game_false_thr) { + if (inGame) { + inGame = false; + game_cell_to_wifi = false; + memset(cur_info->udp_rx_packet, 0x0, sizeof(u32)*UDP_RX_WIN_SIZE); + cur_info->window_index = 0; + } + } + if (inGame && cur_info->game_in_front) { + if (lowTrafficCount >= cur_info->rx_bad_thr && + game_index > 0 && game_start_state[game_index]) {//wzry has low traffic when game ends + game_rx_bad = true; + } else { + game_rx_bad = false; + } + } + if (oplus_sla_debug) { + printk("oplus_sla_game_rx_update:delta_udp_pkts=%d, lowTrafficCount=%d, inGame=%d, " + "game_rx_bad=%d, delta_tcp_bytes=%llu, tcp_rx_large_count=%d, trafficCount=%d\n", + delta_udp_pkts, lowTrafficCount, inGame, + game_rx_bad, delta_tcp_bytes, tcp_rx_large_count, trafficCount); + } + } + } +} + +static void game_online_time_out(struct timeval tv) +{ + if(game_online_info.game_online && + (tv.tv_sec - game_online_info.last_game_skb_tv.tv_sec) >= GAME_SKB_TIME_OUT){ + init_game_start_state(); + init_game_online_info(); + } +} + +static void show_dailog_msg_time_out(struct timeval tv) +{ + int time_interval = 0; + int time_out = 30; + time_interval = tv.tv_sec - last_show_daillog_msg_tv.tv_sec; + + if(time_interval >= time_out && send_show_dailog_msg){ + send_show_dailog_msg = 0; + } +} + +//add for rate limit function to statistics front uid rtt +static void oplus_rate_limit_rtt_calc(struct timeval tv) +{ + int num = 0; + int sum = 0; + int time_interval = 0; + + time_interval = tv.tv_sec - rate_limit_info.last_tv.tv_sec; + if(time_interval >= 10){ + sla_rtt_write_lock(); + + if(rate_limit_info.disable_rtt_num >= 10){ + num = rate_limit_info.disable_rtt_num; + sum = rate_limit_info.disable_rtt_sum; + rate_limit_info.disable_rtt = sum / num; + } + + if(rate_limit_info.enable_rtt_num >= 10){ + num = rate_limit_info.enable_rtt_num; + sum = rate_limit_info.enable_rtt_sum; + rate_limit_info.enable_rtt = sum / num; + } + + rate_limit_info.disable_rtt_num = 0; + rate_limit_info.disable_rtt_sum = 0; + rate_limit_info.enable_rtt_num = 0; + rate_limit_info.enable_rtt_sum = 0; + rate_limit_info.last_tv = tv; + + sla_rtt_write_unlock(); + } +} + +static void dns_statistic_timer(struct timeval tv) +{ + int i; + + for (i = 0; i < IFACE_NUM; i++) { + if(dns_info[i].in_timer && + (tv.tv_sec - dns_info[i].last_tv.tv_sec) >= DNS_TIME){ + + dns_info[i].send_num = 0; + dns_info[i].in_timer = false; + reset_invalid_network_info(&oplus_sla_info[i]); + + sla_write_lock(); + if (SLA_MODE_DUAL_WIFI == sla_work_mode) { + calc_weight_with_weight_state (MAIN_WLAN,SECOND_WLAN); + } + else if (SLA_MODE_WIFI_CELL == sla_work_mode) { + calc_weight_with_weight_state (MAIN_WLAN,CELL_INDEX); + } + sla_write_unlock(); + + printk("oplus_sla_dns: detec dns[%d] error\n",i); + } + } + return; +} + +static void oplus_sla_work_queue_func(struct work_struct *work) +{ + int time_interval; + struct timeval tv; + + do_gettimeofday(&tv); + + time_interval = tv.tv_sec - last_speed_tv.tv_sec; + + if(time_interval >= CALC_DEV_SPEED_TIME){ + last_speed_tv = tv; + calc_network_congestion(); + statistic_dev_speed(tv,time_interval); + calc_network_rtt(tv); + sla_show_dailog(); + sla_detect_should_enable(); + } + + if(oplus_sla_enable){ + time_interval = tv.tv_sec - last_weight_tv.tv_sec; + if(time_interval >= RECALC_WEIGHT_TIME){ + last_weight_tv = tv; + + if (!init_weight_delay_count) { + recalc_sla_weight(); + } else { + init_weight_delay_count--; + } + } + } + + dns_statistic_timer(tv); + enable_to_user_time_out(tv); + up_wlan_iface_by_timer(tv); + game_online_time_out(tv); + game_rx_update(); + show_dailog_msg_time_out(tv); + reset_oplus_sla_calc_speed(tv); + oplus_rate_limit_rtt_calc(tv); + send_speed_and_rtt_to_user(); +} +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 19, 0)) +static void oplus_sla_timer_function(unsigned long a) +#else +static void oplus_sla_timer_function(struct timer_list *t) +#endif +{ + if (workqueue_sla) { + queue_work(workqueue_sla, &oplus_sla_work); + } +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 19, 0)) + mod_timer(&sla_timer, jiffies + SLA_TIMER_EXPIRES); +#else + mod_timer(t, jiffies + SLA_TIMER_EXPIRES); +#endif +} + +/* + timer to statistic each dev speed, + start it when sla is enabled +*/ +static void oplus_sla_timer_init(void) +{ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 19, 0)) + init_timer(&sla_timer); + sla_timer.function = oplus_sla_timer_function; + sla_timer.data = ((unsigned long)0); +#else + timer_setup(&sla_timer, oplus_sla_timer_function, 0); +#endif + + sla_timer.expires = jiffies + SLA_TIMER_EXPIRES;/* timer expires in ~1s */ + add_timer(&sla_timer); + + do_gettimeofday(&last_speed_tv); + do_gettimeofday(&last_weight_tv); + do_gettimeofday(&last_minute_speed_tv); + do_gettimeofday(&last_download_speed_tv); + do_gettimeofday(&rate_limit_info.last_tv); +} + + +/* + timer to statistic each dev speed, + stop it when sla is disabled +*/ +static void oplus_sla_timer_fini(void) +{ + del_timer(&sla_timer); +} + + +static struct nf_hook_ops oplus_sla_ops[] __read_mostly = { + { + .hook = oplus_sla_output_hook, + .pf = NFPROTO_IPV4, + .hooknum = NF_INET_LOCAL_OUT, + //must be here,for dns packet will do DNAT at mangle table with skb->mark + .priority = NF_IP_PRI_CONNTRACK + 1, + }, + { + .hook = oplus_sla_input_hook, + .pf = NFPROTO_IPV4, + .hooknum = NF_INET_LOCAL_IN, + .priority = NF_IP_PRI_FILTER + 1, + }, +}; + +static struct ctl_table oplus_sla_sysctl_table[] = { + { + .procname = "oplus_sla_enable", + .data = &oplus_sla_enable, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec, + }, + { + .procname = "oplus_sla_debug", + .data = &oplus_sla_debug, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec, + }, + { + .procname = "oplus_sla_calc_speed", + .data = &oplus_sla_calc_speed, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec, + }, + { + .procname = "oplus_sla_vpn_connected", + .data = &oplus_sla_vpn_connected, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec, + }, + { + .procname = "game_mark", + .data = &game_mark, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec, + }, + { + .procname = "disable_rtt", + .data = &rate_limit_info.disable_rtt, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec, + }, + { + .procname = "enable_rtt", + .data = &rate_limit_info.enable_rtt, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec, + }, + { + .procname = "udp_rx_show_toast", + .data = &udp_rx_show_toast, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec, + }, + { + .procname = "game_rtt_show_toast", + .data = &game_rtt_show_toast, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec, + }, + { + .procname = "tee_use_src", + .data = &tee_use_src, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec, + }, + { } +}; + +static int oplus_sla_sysctl_init(void) +{ + oplus_sla_table_hrd = register_net_sysctl(&init_net, "net/oplus_sla", + oplus_sla_sysctl_table); + return oplus_sla_table_hrd == NULL ? -ENOMEM : 0; +} + +static void oplus_sla_send_white_list_app_traffic(void) +{ + char *p = NULL; + char send_msg[1284]; + + memset(send_msg,0x0,sizeof(send_msg)); + + p = send_msg; + memcpy(p,&white_app_list.count,sizeof(u32)); + + p += sizeof(u32); + memcpy(p,white_app_list.uid,WHITE_APP_NUM*sizeof(u32)); + + p += WHITE_APP_NUM*sizeof(u32); + memcpy(p,white_app_list.cell_bytes,WHITE_APP_NUM*sizeof(u64)); + + p += WHITE_APP_NUM*sizeof(u64); + memcpy(p,white_app_list.cell_bytes_normal,WHITE_APP_NUM*sizeof(u64)); + + oplus_sla_send_to_user(SLA_SEND_WHITE_LIST_APP_TRAFFIC, + send_msg,sizeof(send_msg)); + + return; +} + +static int oplus_sla_set_debug(struct nlmsghdr *nlh) +{ + oplus_sla_debug = *(u32 *)NLMSG_DATA(nlh); + printk("oplus_sla_netlink:set debug = %d\n", oplus_sla_debug); + return 0; +} + +static int oplus_sla_set_default_network(struct nlmsghdr *nlh) +{ + oplus_sla_def_net = *(u32 *)NLMSG_DATA(nlh); + printk("oplus_sla_netlink:set default network = %d\n", oplus_sla_def_net); + + /* reset game udp rx data */ + memset(wzry_traffic_info.udp_rx_packet, 0x0, sizeof(u32)*UDP_RX_WIN_SIZE); + wzry_traffic_info.window_index = 0; + memset(cjzc_traffic_info.udp_rx_packet, 0x0, sizeof(u32)*UDP_RX_WIN_SIZE); + cjzc_traffic_info.window_index = 0; + + return 0; +} + +static void oplus_sla_send_game_app_traffic(void) +{ + oplus_sla_send_to_user(SLA_SEND_GAME_APP_STATISTIC, + (char *)game_uid,GAME_NUM*sizeof(struct oplus_sla_game_info)); + + return; +} + +static void oplus_sla_send_syn_retran_info(void) +{ + oplus_sla_send_to_user(SLA_GET_SYN_RETRAN_INFO, + (char *)&syn_retran_statistic,sizeof(struct oplus_syn_retran_statistic)); + + memset(&syn_retran_statistic,0x0,sizeof(struct oplus_syn_retran_statistic)); + return; +} + +static int disable_oplus_sla_module(struct nlmsghdr *nlh) +{ + int disable_type = 0; + + int *data = (int *)NLMSG_DATA(nlh); + disable_type = data[0]; + printk("oplus_sla_netlink: type[%d] disable,oplus_sla_enable[%d],work_mode[%d]\n", + disable_type,oplus_sla_enable,sla_work_mode); + + sla_write_lock(); + if(oplus_sla_enable && disable_type){ + if (SLA_MODE_DUAL_WIFI == disable_type) { + main_wlan_download = 1; + enable_second_wifi_to_user = false; + dual_wifi_active_type = INIT_ACTIVE_TYPE; + } + else if (SLA_MODE_WIFI_CELL == disable_type) { + enable_cell_to_user = false; + } + + if (disable_type == sla_work_mode) { + oplus_sla_enable = 0; + sla_work_mode = SLA_MODE_INIT; + + if (dual_wifi_switch_enable) { + sla_detect_mode = SLA_MODE_DUAL_WIFI; + } else { + sla_detect_mode = SLA_MODE_WIFI_CELL; + } + + init_game_online_info(); + printk("oplus_sla_netlink: type[%d] disabled\n",disable_type); + } + oplus_sla_send_to_user(SLA_DISABLED, (char *)&disable_type, sizeof(int)); + } + sla_write_unlock(); + return 0; +} + +static int oplus_sla_iface_changed(struct nlmsghdr *nlh) +{ + int index = -1; + int up = 0; + char *p; + struct oplus_dev_info *node = NULL; + u32 mark = 0x0; + + int *data = (int *)NLMSG_DATA(nlh); + index = data[0]; + up = data[1]; + p = (char *)(data + 2); + printk("oplus_sla_netlink:oplus_sla_iface_changed index:%d, up:%d, ifname:%s\n", index, up, p); + + if (index >= 0 && index < IFACE_NUM) { + struct timeval tv; + do_gettimeofday(&tv); + + if (up) { + sla_write_lock(); + oplus_sla_info[index].if_up = 0; + + if (index == MAIN_WLAN || index == SECOND_WLAN) { + if (index == MAIN_WLAN) { + mark = MAIN_WLAN_MARK; + oplus_sla_info[MAIN_WLAN].need_up = true; + } else { + mark = SECOND_WLAN_MARK; + oplus_sla_info[SECOND_WLAN].if_up = 1; + } + + last_speed_tv = tv; + last_weight_tv = tv; + last_minute_speed_tv = tv; + calc_wlan_rtt_tv = tv; + last_download_speed_tv = tv; + oplus_sla_info[CELL_INDEX].max_speed = 0; + oplus_sla_info[index].dl_little_speed = DOWNLOAD_SPEED; + } else if (index == CELL_INDEX) { + mark = CELL_MARK; + oplus_sla_info[CELL_INDEX].if_up = 1; + oplus_sla_info[CELL_INDEX].wlan_score = WLAN_SCORE_GOOD; + } + if(p) { + node = &oplus_sla_info[index]; + node->mark = mark; + node->minute_speed = MINUTE_LITTE_RATE; + memcpy(node->dev_name, p, IFACE_LEN); + printk("oplus_sla_netlink:ifname = %s,ifup = %d\n", node->dev_name, node->if_up); + } + sla_write_unlock(); + } else { + if (index == MAIN_WLAN || index == SECOND_WLAN) { + oplus_sla_calc_speed = 0; + enable_second_wifi_to_user = false; + + if (index == MAIN_WLAN) { + enable_cell_to_user = false; + oplus_sla_send_game_app_traffic(); + memset(game_uid, 0x0, GAME_NUM*sizeof(struct oplus_sla_game_info)); + } + } + + sla_write_lock(); + memset(&dns_info[index], 0x0, sizeof(struct sla_dns_statistic)); + memset(&oplus_speed_info[index], 0x0, sizeof(struct oplus_speed_calc)); + memset(&oplus_sla_info[index], 0x0, sizeof(struct oplus_dev_info)); + sla_write_unlock(); + } + } + + return 0; +} + +static int oplus_sla_set_primary_wifi(struct nlmsghdr *nlh) +{ + + int *data = (int *)NLMSG_DATA(nlh); + if (*data == WLAN0_INDEX || *data == WLAN1_INDEX) { + MAIN_WLAN = *data; + SECOND_WLAN = (WLAN0_INDEX == MAIN_WLAN) ? WLAN1_INDEX : WLAN0_INDEX; + if (WLAN0_INDEX == MAIN_WLAN) { + MAIN_WLAN_MARK = WLAN0_MARK; + SECOND_WLAN_MARK = WLAN1_MARK; + }else { + MAIN_WLAN_MARK = WLAN1_MARK; + SECOND_WLAN_MARK = WLAN0_MARK; + } + printk("oplus_sla_netlink: oplus_sla_set_primary_wifi main_wlan[%d],second_wlan[%d]\n", + MAIN_WLAN,SECOND_WLAN); + } else { + printk("oplus_sla_netlink: oplus_sla_set_primary_wifi invalid index = %d\n", *data); + } + + return 0; +} + +static int oplus_sla_get_pid(struct sk_buff *skb,struct nlmsghdr *nlh) +{ + oplus_sla_pid = NETLINK_CB(skb).portid; + printk("oplus_sla_netlink:get oplus_sla_pid = %u\n", oplus_sla_pid); + + return 0; +} + +static void set_weight_state_by_score(int index,int score) +{ + if (index >= 0 && + index < IFACE_NUM) { + if (WLAN_NETWORK_INVALID == score && + WEIGHT_STATE_SCORE_INVALID != oplus_sla_info[index].weight_state) { + printk("oplus_sla_score: network[%d] invalid\n",index); + reset_invalid_network_info(&oplus_sla_info[index]); + oplus_sla_info[index].weight_state = WEIGHT_STATE_SCORE_INVALID; + + sla_write_lock(); + if (SLA_MODE_DUAL_WIFI == sla_work_mode) { + calc_weight_with_weight_state (MAIN_WLAN,SECOND_WLAN); + } + else if (SLA_MODE_WIFI_CELL == sla_work_mode) { + calc_weight_with_weight_state (MAIN_WLAN,CELL_INDEX); + } + sla_write_unlock(); + + } else if (!oplus_sla_info[index].wlan_score_bad_count && + WEIGHT_STATE_SCORE_INVALID == oplus_sla_info[index].weight_state) { + printk("oplus_sla_score: network[%d] reset to normal\n",index); + oplus_sla_info[index].weight_state = WEIGHT_STATE_NORMAL; + } + } + + return; +} + +static int oplus_sla_set_wifi_score(struct nlmsghdr *nlh) +{ + int *data = (int *)NLMSG_DATA(nlh); + + if(NULL != data && + data[0] >= 0 && data[0] < IFACE_NUM) { + + int index = data[0]; + int score = data[1]; + + set_weight_state_by_score(index,score); + + oplus_sla_info[index].wlan_score = score; + + if(score <= (rom_update_info.wlan_bad_score - 5)) { + oplus_sla_info[index].wlan_score_bad_count += WLAN_SCORE_BAD_NUM; + } + else if(score <= rom_update_info.wlan_bad_score){ + oplus_sla_info[index].wlan_score_bad_count += 3; + } + else if(score >= rom_update_info.wlan_good_score){ + oplus_sla_info[index].wlan_score_bad_count = 0; + } + else if(score >= (rom_update_info.wlan_good_score - 5) && + oplus_sla_info[index].wlan_score_bad_count >= 3){ + oplus_sla_info[index].wlan_score_bad_count -= 3; + } + else if(score >= (rom_update_info.wlan_good_score - 10) && + oplus_sla_info[index].wlan_score_bad_count){ + oplus_sla_info[index].wlan_score_bad_count--; + } + + if(oplus_sla_info[index].wlan_score_bad_count > (2*WLAN_SCORE_BAD_NUM)){ + oplus_sla_info[index].wlan_score_bad_count = 2*WLAN_SCORE_BAD_NUM; + } + } else { + printk("oplus_sla_netlink:oplus_sla_set_wifi_score invalid message!\n"); + } + + return 0; +} + +static int oplus_sla_set_game_app_uid(struct nlmsghdr *nlh) +{ + u32 *uidInfo = (u32 *)NLMSG_DATA(nlh); + u32 index = uidInfo[0]; + u32 uid = uidInfo[1]; + + if (index < GAME_NUM) { + game_uid[index].uid = uid; + game_uid[index].switch_time = 0; + game_uid[index].game_type = index; + game_uid[index].mark = MAIN_WLAN_MARK; + printk("oplus_sla_netlink oplus_sla_set_game_app_uid:index=%d uid=%d\n", index, uid); + } + + return 0; +} + +static int oplus_sla_set_white_list_app_uid(struct nlmsghdr *nlh) +{ + u32 *info = (u32 *)NLMSG_DATA(nlh); + memset(&white_app_list,0x0,sizeof(struct oplus_white_app_info)); + white_app_list.count = info[0]; + if (white_app_list.count > 0 && white_app_list.count < WHITE_APP_NUM) { + int i; + for (i = 0; i < white_app_list.count; i++) { + white_app_list.uid[i] = info[i + 1]; + printk("oplus_sla_netlink oplus_sla_set_white_list_app_uid count=%d, uid[%d]=%d\n", + white_app_list.count, i, white_app_list.uid[i]); + } + } + return 0; +} + +static int oplus_sla_set_game_rtt_detecting(struct nlmsghdr *nlh) +{ + if(SLA_ENABLE_GAME_RTT== nlh->nlmsg_type){ + oplus_sla_vpn_connected = 1; + } else { + oplus_sla_vpn_connected = 0; + } + printk("oplus_sla_netlink: set game rtt detect:%d\n",nlh->nlmsg_type); + return 0; +} + +static int oplus_sla_set_switch_state(struct nlmsghdr *nlh) +{ + u32 *data = (u32 *)NLMSG_DATA(nlh); + + if (data[0]) { + sla_switch_enable = true; + } else { + sla_switch_enable = false; + } + + if (data[1]) { + dual_wifi_switch_enable = true; + if (SLA_MODE_INIT == sla_work_mode) { + sla_detect_mode = SLA_MODE_DUAL_WIFI; + } + } + else { + dual_wifi_switch_enable = false; + if (SLA_MODE_INIT == sla_work_mode) { + sla_detect_mode = SLA_MODE_WIFI_CELL; + } + } + printk("oplus_sla_netlink:sla switch sla_enable = %d,dual_wifi_enable = %d\n", + sla_switch_enable, dual_wifi_switch_enable); + return 0; +} + +static int oplus_sla_update_screen_state(struct nlmsghdr *nlh) +{ + u32 *screen_state = (u32 *)NLMSG_DATA(nlh); + sla_screen_on = (*screen_state) ? true : false; + printk("oplus_sla_netlink:update screen state = %u\n",sla_screen_on); + return 0; +} + +static int oplus_sla_update_cell_quality(struct nlmsghdr *nlh) +{ + u32 *cell_quality = (u32 *)NLMSG_DATA(nlh); + cell_quality_good = (*cell_quality) ? true : false; + printk("oplus_sla_netlink:update cell quality = %u\n", cell_quality_good); + return 0; +} + +static int oplus_sla_set_show_dialog_state(struct nlmsghdr *nlh) +{ + u32 *show_dailog = (u32 *)NLMSG_DATA(nlh); + need_show_dailog = (*show_dailog) ? true : false; + if (!need_show_dailog) { + send_show_dailog_msg = 0; + } + printk("oplus_sla_netlink:set show dialog = %u\n", need_show_dailog); + return 0; +} + +static int oplus_sla_set_params(struct nlmsghdr *nlh) +{ + u32* params = (u32 *)NLMSG_DATA(nlh); + u32 count = params[0]; + params++; + if (count == 13) { + rom_update_info.sla_speed = params[0]; + rom_update_info.cell_speed = params[1]; + rom_update_info.wlan_speed = params[2]; + rom_update_info.wlan_little_score_speed = params[3]; + rom_update_info.sla_rtt = params[4]; + rom_update_info.wzry_rtt = params[5]; + rom_update_info.cjzc_rtt = params[6]; + rom_update_info.wlan_bad_score = params[7]; + rom_update_info.wlan_good_score = params[8]; + rom_update_info.second_wlan_speed = params[9]; + rom_update_info.dual_wlan_download_speed = params[10]; + rom_update_info.dual_wifi_rtt = params[11]; + rom_update_info.dual_wlan_bad_score = params[12]; + printk("oplus_sla_netlink:set params count=%u params[0] = %u,params[1] = %u," + "params[2] = %u,params[3] = %u,params[4] = %u,params[5] = %u,params[6] = %u," + "params[7] = %u,params[8] = %u,params[9] = %u,params[10] = %u,params[11] = %u,params[12] = %u\n", + count, params[0],params[1],params[2],params[3],params[4],params[5], + params[6],params[7],params[8],params[9],params[10],params[11],params[12]); + } else { + printk("oplus_sla_netlink:set params invalid param count:%d", count); + } + + return 0; +} + +static int oplus_sla_set_game_start_state(struct nlmsghdr *nlh) +{ + int *data = (int *)NLMSG_DATA(nlh); + int index = data[0]; + + game_cell_to_wifi = false; + + if(index && index < GAME_NUM){ + game_start_state[index] = data[1]; + printk("oplus_sla_netlink:set game_start_state[%d] = %d\n",index,game_start_state[index]); + /* reset udp rx data */ + memset(wzry_traffic_info.udp_rx_packet, 0x0, sizeof(u32)*UDP_RX_WIN_SIZE); + wzry_traffic_info.window_index = 0; + memset(cjzc_traffic_info.udp_rx_packet, 0x0, sizeof(u32)*UDP_RX_WIN_SIZE); + cjzc_traffic_info.window_index = 0; + } else { + printk("oplus_sla_netlink: set game_start_state error,index = %d\n",index); + } + + return 0; +} + +static int oplus_sla_set_game_rtt_params(struct nlmsghdr *nlh) +{ + int *data = (int *)NLMSG_DATA(nlh); + int index = data[0]; + int i; + + if(index > 0 && index < GAME_NUM) { + memcpy(&game_params[index], data, sizeof(struct oplus_sla_game_rtt_params)); + printk("oplus_sla_netlink:set game params index=%d tx_offset=%d tx_len=%d tx_fix=", + game_params[index].game_index, game_params[index].tx_offset, game_params[index].tx_len); + for (i = 0; i < game_params[index].tx_len; i++) { + printk("%02x", game_params[index].tx_fixed_value[i]); + } + printk(" rx_offset=%d rx_len=%d rx_fix=", game_params[index].rx_offset, game_params[index].rx_len); + for (i = 0; i < game_params[index].rx_len; i++) { + printk("%02x", game_params[index].rx_fixed_value[i]); + } + printk("\n"); + } else { + printk("oplus_sla_netlink: set game params error,index = %d\n", index); + } + + return 0; +} + +static int oplus_sla_set_game_in_front(struct nlmsghdr *nlh) +{ + int *data = (int *)NLMSG_DATA(nlh); + int index = data[0]; + int in_front = data[1]; + + if(index > 0 && index < GAME_NUM) { + if (index == GAME_WZRY) { + if (in_front) { + wzry_traffic_info.game_in_front = 1; + cjzc_traffic_info.game_in_front = 0; + } else { + wzry_traffic_info.game_in_front = 0; + } + printk("oplus_sla_netlink: set_game_in_front game index = %d, in_front=%d\n", index, in_front); + } else if (index == GAME_CJZC) { + if (in_front) { + wzry_traffic_info.game_in_front = 0; + cjzc_traffic_info.game_in_front = 1; + } else { + cjzc_traffic_info.game_in_front = 0; + } + printk("oplus_sla_netlink: set_game_in_front game index = %d, in_front=%d\n", index, in_front); + } else { + printk("oplus_sla_netlink: set_game_in_front unknow game, index = %d\n", index); + } + } else { + printk("oplus_sla_netlink: set_game_in_front error, index = %d\n", index); + } + + return 0; +} + +static int oplus_sla_set_dual_wifi_app_uid(struct nlmsghdr *nlh) +{ + u32 *info = (u32 *)NLMSG_DATA(nlh); + memset(&dual_wifi_app_list,0x0,sizeof(struct oplus_dual_sta_info)); + dual_wifi_app_list.count = info[0]; + if (dual_wifi_app_list.count > 0 && dual_wifi_app_list.count < DUAL_STA_APP_NUM) { + int i; + for (i = 0; i < dual_wifi_app_list.count; i++) { + dual_wifi_app_list.uid[i] = info[i + 1]; + printk("oplus_sla_netlink:set_dual_wifi_app_uid count=%d, uid[%d]=%d\n", + dual_wifi_app_list.count, i, dual_wifi_app_list.uid[i]); + } + } + return 0; +} + +static int oplus_sla_set_download_app_uid(struct nlmsghdr *nlh) +{ + u32 *info = (u32 *)NLMSG_DATA(nlh); + memset(&download_app_list,0x0,sizeof(struct oplus_dual_sta_info)); + download_app_list.count = info[0]; + if (download_app_list.count > 0 && download_app_list.count < DUAL_STA_APP_NUM) { + int i; + for (i = 0; i < download_app_list.count; i++) { + download_app_list.uid[i] = info[i + 1]; + printk("oplus_sla_netlink:set_download_app_uid count=%d, uid[%d]=%d\n", + download_app_list.count, i, download_app_list.uid[i]); + } + } + return 0; +} + +static int oplus_sla_set_vedio_app_uid(struct nlmsghdr *nlh) +{ + u32 *info = (u32 *)NLMSG_DATA(nlh); + memset(&vedio_app_list,0x0,sizeof(struct oplus_dual_sta_info)); + vedio_app_list.count = info[0]; + if (vedio_app_list.count > 0 && vedio_app_list.count < DUAL_STA_APP_NUM) { + int i; + for (i = 0; i < vedio_app_list.count; i++) { + vedio_app_list.uid[i] = info[i + 1]; + printk("oplus_sla_netlink:vedio_app_list count=%d, uid[%d]=%d\n", + vedio_app_list.count, i, vedio_app_list.uid[i]); + } + } + return 0; +} + +static void oplus_sla_set_vpn_state(struct nlmsghdr *nlh) +{ + int *data = (int *)NLMSG_DATA(nlh); + + /*1 ---> vpn connected + *0 ---> vpn disconnected*/ + oplus_sla_vpn_connected = data[0]; + + printk("oplus_sla_netlink:set vpn connecet state = %d\n", data[0]); +} + +static void reset_main_wlan_info(void) +{ + struct timeval tv; + + if(oplus_sla_info[MAIN_WLAN].if_up){ + + do_gettimeofday(&tv); + last_minute_speed_tv = tv; + + oplus_sla_info[MAIN_WLAN].sum_rtt= 0; + oplus_sla_info[MAIN_WLAN].avg_rtt = 0; + oplus_sla_info[MAIN_WLAN].rtt_index = 0; + oplus_sla_info[MAIN_WLAN].sla_avg_rtt = 0; + oplus_sla_info[MAIN_WLAN].sla_rtt_num = 0; + oplus_sla_info[MAIN_WLAN].sla_sum_rtt = 0; + oplus_sla_info[MAIN_WLAN].syn_retran = 0; + oplus_sla_info[MAIN_WLAN].max_speed /= 2; + oplus_sla_info[MAIN_WLAN].left_speed = 0; + oplus_sla_info[MAIN_WLAN].current_speed = 0; + oplus_sla_info[MAIN_WLAN].minute_speed = MINUTE_LITTE_RATE; + oplus_sla_info[MAIN_WLAN].congestion_flag = CONGESTION_LEVEL_NORMAL; + } +} + +static void oplus_sla_init_weight_by_wlan_assi(void) +{ + struct timeval tv; + do_gettimeofday(&tv); + + sla_write_lock(); + init_weight_delay_count = 10; + + last_weight_tv = tv; + oplus_sla_info[MAIN_WLAN].weight = 30; + oplus_sla_info[CELL_INDEX].weight = 100; + + reset_main_wlan_info(); + + printk("oplus_sla_weight:init_weight_by_wlan_assi[%d] [%d]\n", + oplus_sla_info[MAIN_WLAN].weight, oplus_sla_info[CELL_INDEX].weight); + sla_write_unlock(); +} + +static int sla_netlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, struct netlink_ext_ack *extack) +{ + int ret = 0; + + switch (nlh->nlmsg_type) { + case SLA_ENABLE: + ret = enable_oplus_sla_module(nlh); + break; + case SLA_DISABLE: + ret = disable_oplus_sla_module(nlh); + break; + case SLA_IFACE_CHANGED: + ret = oplus_sla_iface_changed(nlh); + break; + case SLA_NOTIFY_PRIMARY_WIFI: + ret = oplus_sla_set_primary_wifi(nlh); + break; + case SLA_NOTIFY_PID: + ret = oplus_sla_get_pid(skb,nlh); + break; + case SLA_NOTIFY_WIFI_SCORE: + ret = oplus_sla_set_wifi_score(nlh); + break; + case SLA_NOTIFY_APP_UID: + ret = oplus_sla_set_game_app_uid(nlh); + break; + case SLA_NOTIFY_WHITE_LIST_APP: + oplus_sla_send_white_list_app_traffic(); + ret = oplus_sla_set_white_list_app_uid(nlh); + break; + case SLA_ENABLE_GAME_RTT: + case SLA_DISABLE_GAME_RTT: + ret = oplus_sla_set_game_rtt_detecting(nlh); + break; + case SLA_NOTIFY_SWITCH_STATE: + ret = oplus_sla_set_switch_state(nlh); + break; + case SLA_NOTIFY_SCREEN_STATE: + ret = oplus_sla_update_screen_state(nlh); + break; + case SLA_NOTIFY_CELL_QUALITY: + ret = oplus_sla_update_cell_quality(nlh); + break; + case SLA_NOTIFY_SHOW_DIALOG: + ret = oplus_sla_set_show_dialog_state(nlh); + break; + case SLA_GET_SYN_RETRAN_INFO: + oplus_sla_send_syn_retran_info(); + break; + case SLA_GET_SPEED_UP_APP: + oplus_sla_send_white_list_app_traffic(); + break; + case SLA_SET_DEBUG: + oplus_sla_set_debug(nlh); + break; + case SLA_NOTIFY_DEFAULT_NETWORK: + oplus_sla_set_default_network(nlh); + break; + case SLA_NOTIFY_PARAMS: + oplus_sla_set_params(nlh); + break; + case SLA_NOTIFY_GAME_STATE: + oplus_sla_set_game_start_state(nlh); + break; + case SLA_NOTIFY_GAME_PARAMS: + oplus_sla_set_game_rtt_params(nlh); + break; + case SLA_NOTIFY_GAME_IN_FRONT: + oplus_sla_set_game_in_front(nlh); + break; + case SLA_NOTIFY_DUAL_STA_APP: + oplus_sla_set_dual_wifi_app_uid(nlh); + break; + case SLA_WEIGHT_BY_WLAN_ASSIST: + oplus_sla_init_weight_by_wlan_assi(); + break; + case SLA_NOTIFY_VPN_CONNECTED: + oplus_sla_set_vpn_state(nlh); + break; + case SLA_NOTIFY_DOWNLOAD_APP: + oplus_sla_set_download_app_uid(nlh); + break; + case SLA_NOTIFY_VEDIO_APP: + oplus_sla_set_vedio_app_uid(nlh); + break; + case SLA_LIMIT_SPEED_ENABLE: + enable_oplus_limit_speed(); + break; + case SLA_LIMIT_SPEED_DISABLE: + disable_oplus_limit_speed(); + break; + case SLA_LIMIT_SPEED_FRONT_UID: + oplus_limit_uid_changed(nlh); + break; + case SMART_BW_SET_PARAMS: + oplus_smart_bw_set_params(nlh); + break; + #ifdef OPLUS_FEATURE_WIFI_ROUTERBOOST + case SLA_NOTIFY_ROUTER_BOOST_DUPPKT_PARAMS: + oplus_router_boost_set_params(nlh); + break; + #endif /* OPLUS_FEATURE_WIFI_ROUTERBOOST */ + default: + return -EINVAL; + } + + return ret; +} + + +static void sla_netlink_rcv(struct sk_buff *skb) +{ + mutex_lock(&sla_netlink_mutex); + netlink_rcv_skb(skb, &sla_netlink_rcv_msg); + mutex_unlock(&sla_netlink_mutex); +} + +static int oplus_sla_netlink_init(void) +{ + struct netlink_kernel_cfg cfg = { + .input = sla_netlink_rcv, + }; + + oplus_sla_sock = netlink_kernel_create(&init_net, NETLINK_OPLUS_SLA, &cfg); + return oplus_sla_sock == NULL ? -ENOMEM : 0; +} + +static void oplus_sla_netlink_exit(void) +{ + netlink_kernel_release(oplus_sla_sock); + oplus_sla_sock = NULL; +} + +static int __init oplus_sla_init(void) +{ + int ret = 0; + + rwlock_init(&sla_lock); + rwlock_init(&sla_rtt_lock); + rwlock_init(&sla_game_lock); + + ret = oplus_sla_netlink_init(); + if (ret < 0) { + printk("oplus_sla module can not init oplus sla netlink.\n"); + } + + ret |= oplus_sla_sysctl_init(); + + ret |= nf_register_net_hooks(&init_net,oplus_sla_ops,ARRAY_SIZE(oplus_sla_ops)); + if (ret < 0) { + printk("oplus_sla module can not register netfilter ops.\n"); + } + + workqueue_sla= create_singlethread_workqueue("workqueue_sla"); + if (workqueue_sla) { + INIT_WORK(&oplus_sla_work, oplus_sla_work_queue_func); + } + else { + printk("oplus_sla module can not create workqueue_sla\n"); + } + + oplus_sla_timer_init(); + statistic_dev_rtt = oplus_statistic_dev_rtt; + mark_streams_for_iptables_reject = sla_mark_streams_for_iptables_reject; + + return ret; +} + + +static void __exit oplus_sla_fini(void) +{ + oplus_sla_timer_fini(); + statistic_dev_rtt = NULL; + mark_streams_for_iptables_reject = NULL; + + if (workqueue_sla) { + flush_workqueue(workqueue_sla); + destroy_workqueue(workqueue_sla); + } + + oplus_sla_netlink_exit(); + + if(oplus_sla_table_hrd){ + unregister_net_sysctl_table(oplus_sla_table_hrd); + } + + nf_unregister_net_hooks(&init_net,oplus_sla_ops, ARRAY_SIZE(oplus_sla_ops)); +} + + +module_init(oplus_sla_init); +module_exit(oplus_sla_fini); diff --git a/net/oplus_wificapcenter/Makefile b/net/oplus_wificapcenter/Makefile new file mode 100644 index 000000000000..dda32cab3980 --- /dev/null +++ b/net/oplus_wificapcenter/Makefile @@ -0,0 +1,5 @@ +# +# Makefile for the wifi cap center. +# +KBUILD_CFLAGS += -Wno-unused-variable -Wno-unused-function +obj-y += oplus_wificapcenter.o diff --git a/net/oplus_wificapcenter/oplus_wificapcenter.c b/net/oplus_wificapcenter/oplus_wificapcenter.c new file mode 100644 index 000000000000..aa48f38a303c --- /dev/null +++ b/net/oplus_wificapcenter/oplus_wificapcenter.c @@ -0,0 +1,546 @@ +/****************************************************************************** +** Copyright (C), 2019-2029, OPLUS Mobile Comm Corp., Ltd +** VENDOR_EDIT, All rights reserved. +** File: - opluswificap center.c +** Description: wificapcenter (wcc) +** +** Version: 1.0 +** Date : 2020/07/05 +** TAG: OPLUS_FEATURE_WIFI_CAPCENTER +** ------------------------------- Revision History: ---------------------------- +** +** ------------------------------------------------------------------------------ + *******************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define LOG_TAG "[oplus_wificapcenter] %s line:%d " +#define debug(fmt, args...) printk(LOG_TAG fmt, __FUNCTION__, __LINE__, ##args) + +/*NLMSG_MIN_TYPE is 0x10,so we start at 0x11*/ +/*If response event is close contact with request,*/ +/*response can be same with req to reduce msg*/ +enum{ + /*common msg for sync and async from 0x11-0x29*/ + OPLUS_COMMON_MSG_BASE = 0x11, + OPLUS_WIFI_CAP_CENTER_NOTIFY_PID = OPLUS_COMMON_MSG_BASE, + + /*sync msg from 0x30-0x79;*/ + OPLUS_SYNC_MSG_BASE = 0x30, + OPLUS_SAMPLE_SYNC_GET = OPLUS_SYNC_MSG_BASE, + OPLUS_SAMPLE_SYNC_GET_NO_RESP = OPLUS_SYNC_MSG_BASE + 1, + + OPLUS_SYNC_REMOVE_HE_IE_FROM_PROBE_REQUEST = OPLUS_SYNC_MSG_BASE + 2, + OPLUS_SYNC_DBS_CAPACITY_GET = OPLUS_SYNC_MSG_BASE + 3, + OPLUS_SYNC_PHY_CAPACITY_GET = OPLUS_SYNC_MSG_BASE + 4, + OPLUS_SYNC_SUPPORTED_CHANNELS_GET = OPLUS_SYNC_MSG_BASE + 5, + OPLUS_SYNC_AVOID_CHANNELS_GET = OPLUS_SYNC_MSG_BASE + 6, + + /*async msg from 0x80-(max-1)*/ + OPLUS_ASYNC_MSG_BASE = 0x80, + OPLUS_SAMPLE_ASYNC_GET = OPLUS_ASYNC_MSG_BASE, + + OPLUS_WIFI_CAP_CENTER_MAX = 0x100, +}; + +static DEFINE_MUTEX(oplus_wcc_sync_nl_mutex); +static DEFINE_MUTEX(oplus_wcc_async_nl_mutex); +static struct ctl_table_header *oplus_table_hrd; +static rwlock_t oplus_sync_nl_lock; +static rwlock_t oplus_async_nl_lock; +static u32 oplus_wcc_debug = 1; +/*user space pid*/ +static u32 oplus_sync_nl_pid = 0; +static u32 oplus_async_nl_pid = 0; +/*kernel sock*/ +static struct sock *oplus_sync_nl_sock; +static struct sock *oplus_async_nl_sock; +static struct timer_list oplus_timer; +static int async_msg_type = 0; + +/*check msg_type in range of sync & async, 1 stands in range, 0 not in range*/ +static int check_msg_in_range(struct sock *nl_sock, int msg_type) +{ + debug("nl_sock: %p, msg_type:%d", nl_sock, msg_type); + if (msg_type >= OPLUS_COMMON_MSG_BASE && msg_type < OPLUS_SYNC_MSG_BASE) { + return 1; + } + + /*not in common part*/ + if (nl_sock == oplus_sync_nl_sock) { + if (msg_type >= OPLUS_SYNC_MSG_BASE && msg_type< OPLUS_ASYNC_MSG_BASE) { + return 1; + } else { + return 0; + } + } else if (nl_sock == oplus_async_nl_sock) { + if (msg_type >= OPLUS_ASYNC_MSG_BASE && msg_type < OPLUS_WIFI_CAP_CENTER_MAX) { + return 1; + } else { + return 0; + } + } else { + return 0; + } +} + +/* send to user space */ +static int oplus_wcc_send_to_user(struct sock *oplus_sock, + u32 oplus_pid, int msg_type, char *payload, int payload_len) +{ + int ret = 0; + struct sk_buff *skbuff; + struct nlmsghdr *nlh = NULL; + + if (!check_msg_in_range(oplus_sock, msg_type)) { + debug("msg_type:%d not in range\n", msg_type); + return -1; + } + + /*allocate new buffer cache */ + skbuff = alloc_skb(NLMSG_SPACE(payload_len), GFP_ATOMIC); + if (skbuff == NULL) { + printk("oplus_wcc_netlink: skbuff alloc_skb failed\n"); + return -1; + } + + /* fill in the data structure */ + nlh = nlmsg_put(skbuff, 0, 0, msg_type, NLMSG_ALIGN(payload_len), 0); + if (nlh == NULL) { + printk("oplus_wcc_netlink:nlmsg_put failaure\n"); + nlmsg_free(skbuff); + return -1; + } + + /*compute nlmsg length*/ + nlh->nlmsg_len = NLMSG_HDRLEN + NLMSG_ALIGN(payload_len); + + if(NULL != payload) { + memcpy((char *)NLMSG_DATA(nlh), payload, payload_len); + } + + /* set control field,sender's pid */ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 7, 0)) + NETLINK_CB(skbuff).pid = 0; +#else + NETLINK_CB(skbuff).portid = 0; +#endif + + NETLINK_CB(skbuff).dst_group = 0; + + /* send data */ + if(oplus_pid) { + ret = netlink_unicast(oplus_sock, skbuff, oplus_pid, MSG_DONTWAIT); + } else { + printk(KERN_ERR "oplus_wcc_netlink: can not unicast skbuff, oplus_pid=0\n"); + kfree_skb(skbuff); + } + if(ret < 0) { + printk(KERN_ERR "oplus_wcc_netlink: can not unicast skbuff,ret = %d\n", ret); + return 1; + } + + return 0; +} + +static void oplus_wcc_sample_resp(struct sock *oplus_sock, u32 oplus_pid, int msg_type) +{ + int payload[4]; + payload[0] = 5; + payload[1] = 6; + payload[2] = 7; + payload[3] = 8; + + oplus_wcc_send_to_user(oplus_sock, oplus_pid, msg_type, (char *)payload, sizeof(payload)); + if (oplus_wcc_debug) { + debug("msg_type = %d, sample_resp =%d%d%d%d\n", msg_type, payload[0], payload[1], payload[2], payload[3]); + } + + return; +} + +static int oplus_wcc_sample_sync_get(struct nlmsghdr *nlh) +{ + u32 *data = (u32 *)NLMSG_DATA(nlh); + + debug("sample_sync_get: %u%u%u%u\n", data[0], data[1], data[2], data[3]); + oplus_wcc_sample_resp(oplus_sync_nl_sock, oplus_sync_nl_pid, OPLUS_SAMPLE_SYNC_GET); + return 0; +} + +static int oplus_wcc_sample_sync_get_no_resp(struct nlmsghdr *nlh) +{ + u32 *data = (u32 *)NLMSG_DATA(nlh); + + debug("sample_sync_get_no_resp: %u%u%u%u\n", data[0], data[1], data[2], data[3]); + return 0; +} + +/*#ifdef OPLUS_FEATURE_WIFI_OPLUSWFD*/ +#define OPLUS_WFD_FREQS_NUM_MAX 100 +/*the first one for length*/ +static int s_oplus_wfd_freqs[OPLUS_WFD_FREQS_NUM_MAX + 1]; +enum oplus_wfd_band +{ + oplus_wfd_band_2g = 0, + oplus_wfd_band_5g, + oplus_wfd_band_6g, + oplus_wfd_band_max +}; + +static void remove_he_ie_from_probe_request_stub(int remove) { + debug("remove_he_ie_from_probe_request_stub"); +} + +static int get_dbs_capacity_stub() { + debug("get_dbs_capacity_stub"); + return 0; +} + +static int get_phy_capacity_stub(int band) +{ + debug("get_phy_capacity_stub"); + return 0; +} + +static void get_supported_channels_stub(int band, int *len, int *freqs, int max_num) +{ + debug("get_supported_channels_stub"); + *len = 0; +} +static void get_avoid_channels_stub(int *len, int *freqs, int max_num) +{ + debug("get_avoid_channels_stub"); + *len = 0; +} + +struct oplus_wfd_wlan_ops_t oplus_wfd_wlan_ops = { + .remove_he_ie_from_probe_request = remove_he_ie_from_probe_request_stub, + .get_dbs_capacity = get_dbs_capacity_stub, + .get_phy_capacity = get_phy_capacity_stub, + .get_supported_channels = get_supported_channels_stub, + .get_avoid_channels = get_avoid_channels_stub +}; + +void register_oplus_wfd_wlan_ops(struct oplus_wfd_wlan_ops_t *ops) { + if (ops == NULL) + return; + if (ops->remove_he_ie_from_probe_request) + oplus_wfd_wlan_ops.remove_he_ie_from_probe_request = ops->remove_he_ie_from_probe_request; + if (ops->get_dbs_capacity) + oplus_wfd_wlan_ops.get_dbs_capacity = ops->get_dbs_capacity; + if (ops->get_phy_capacity) + oplus_wfd_wlan_ops.get_phy_capacity = ops->get_phy_capacity; + if (ops->get_supported_channels) + oplus_wfd_wlan_ops.get_supported_channels = ops->get_supported_channels; + if (ops->get_avoid_channels) + oplus_wfd_wlan_ops.get_avoid_channels = ops->get_avoid_channels; +} + +static void oplus_wcc_remove_He_IE_from_probe_request(struct nlmsghdr *nlh) +{ + if (nlmsg_len(nlh) > 0) { + u32 *data = (u32 *)NLMSG_DATA(nlh); + debug("remove he from probe rquest: %d", *data); + oplus_wfd_wlan_ops.remove_he_ie_from_probe_request(*data); + } +} + +static void oplus_wcc_get_dbs_capacity(struct nlmsghdr *nlh) +{ + s32 cap = oplus_wfd_wlan_ops.get_dbs_capacity(); + oplus_wcc_send_to_user(oplus_sync_nl_sock, oplus_sync_nl_pid, OPLUS_SYNC_DBS_CAPACITY_GET, (char*)&cap, sizeof(cap)); +} +static void oplus_wcc_get_phy_capacity(struct nlmsghdr *nlh) +{ + u32 band = 0; + u32 cap = 0; + if (nlmsg_len(nlh) > 0) { + u32* data = (u32 *)NLMSG_DATA(nlh); + band = *data; + if (band < oplus_wfd_band_max) { + cap = oplus_wfd_wlan_ops.get_phy_capacity(band); + debug("oplus_wcc_get_phy_capacity, cap= %d", cap); + } + } + oplus_wcc_send_to_user(oplus_sync_nl_sock, oplus_sync_nl_pid, OPLUS_SYNC_PHY_CAPACITY_GET, (char*)&cap, sizeof(cap)); +} + +static void oplus_wcc_get_supported_channels(struct nlmsghdr *nlh) +{ + u32 band = 0; + u32 len = 0; + + memset(s_oplus_wfd_freqs, 0, sizeof(s_oplus_wfd_freqs)); + if (nlmsg_len(nlh) > 0) { + u32* data = (u32 *)NLMSG_DATA(nlh); + band = *data; + if (band < oplus_wfd_band_max) { + oplus_wfd_wlan_ops.get_supported_channels(band, &len, s_oplus_wfd_freqs + 1, OPLUS_WFD_FREQS_NUM_MAX); + s_oplus_wfd_freqs[0] = len; + debug("get supported channels, num = %d", len); + } + } + oplus_wcc_send_to_user(oplus_sync_nl_sock, oplus_sync_nl_pid, OPLUS_SYNC_SUPPORTED_CHANNELS_GET, (char*)s_oplus_wfd_freqs, (len + 1)*sizeof(u32)); +} + +static void oplus_wcc_get_avoid_channels(struct nlmsghdr *nlh) +{ + u32 len = 0; + + memset(s_oplus_wfd_freqs, 0, sizeof(s_oplus_wfd_freqs)); + + oplus_wfd_wlan_ops.get_avoid_channels(&len, s_oplus_wfd_freqs + 1, OPLUS_WFD_FREQS_NUM_MAX); + s_oplus_wfd_freqs[0] = len; + debug("get avoid channels, num = %d", len); + + oplus_wcc_send_to_user(oplus_sync_nl_sock, oplus_sync_nl_pid, OPLUS_SYNC_AVOID_CHANNELS_GET, (char*)s_oplus_wfd_freqs, (len + 1)*sizeof(u32)); +} + +EXPORT_SYMBOL(register_oplus_wfd_wlan_ops); + +/*#endif OPLUS_FEATURE_WIFI_OPLUSWFD*/ +static int oplus_wcc_sample_async_get(struct nlmsghdr *nlh) +{ + u32 *data = (u32 *)NLMSG_DATA(nlh); + + async_msg_type = OPLUS_SAMPLE_ASYNC_GET; + oplus_timer.expires = jiffies + HZ;/* timer expires in ~1s*/ + add_timer(&oplus_timer); + + debug("sample_async_set: %u%u%u%u\n", data[0], data[1], data[2], data[3]); + + return 0; +} + +static void oplus_wcc_timer_function(void) +{ + if (async_msg_type == OPLUS_SAMPLE_ASYNC_GET) { + oplus_wcc_sample_resp(oplus_async_nl_sock, oplus_async_nl_pid, OPLUS_SAMPLE_ASYNC_GET); + async_msg_type = 0; + } +} + +static void oplus_wcc_timer_init(void) +{ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 19, 0)) + init_timer(&oplus_timer); + oplus_timer.function = (void*)oplus_wcc_timer_function; +#else + timer_setup(&oplus_timer, (void*)oplus_wcc_timer_function, 0); +#endif +} + +static void oplus_wcc_timer_fini(void) +{ + del_timer(&oplus_timer); +} + +static int oplus_wcc_sync_nl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, struct netlink_ext_ack *extack) +{ + u32 portid = NETLINK_CB(skb).portid; + + if (nlh->nlmsg_type == OPLUS_WIFI_CAP_CENTER_NOTIFY_PID) { + oplus_sync_nl_pid = portid; + debug("oplus_sync_nl_pid pid=%d\n", oplus_sync_nl_pid); + } + /* only recv msg from target pid*/ + if (portid != oplus_sync_nl_pid) { + return -1; + } + if (!check_msg_in_range(oplus_sync_nl_sock, nlh->nlmsg_type)) { + debug("msg_type:%d not in range\n", nlh->nlmsg_type); + return -1; + } + + switch (nlh->nlmsg_type) { + case OPLUS_SAMPLE_SYNC_GET: + oplus_wcc_sample_sync_get(nlh); + break; + case OPLUS_SAMPLE_SYNC_GET_NO_RESP: + oplus_wcc_sample_sync_get_no_resp(nlh); + break; + case OPLUS_SYNC_REMOVE_HE_IE_FROM_PROBE_REQUEST: + oplus_wcc_remove_He_IE_from_probe_request(nlh); + break; + case OPLUS_SYNC_DBS_CAPACITY_GET: + oplus_wcc_get_dbs_capacity(nlh); + break; + case OPLUS_SYNC_PHY_CAPACITY_GET: + oplus_wcc_get_phy_capacity(nlh); + break; + case OPLUS_SYNC_SUPPORTED_CHANNELS_GET: + oplus_wcc_get_supported_channels(nlh); + break; + case OPLUS_SYNC_AVOID_CHANNELS_GET: + oplus_wcc_get_avoid_channels(nlh); + break; + default: + return -EINVAL; + } + + return 0; +} + +static int oplus_wcc_async_nl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, struct netlink_ext_ack *extack) +{ + u32 portid = NETLINK_CB(skb).portid; + + if (nlh->nlmsg_type == OPLUS_WIFI_CAP_CENTER_NOTIFY_PID) { + oplus_async_nl_pid = portid; + debug("oplus_async_nl_pid pid=%d\n", oplus_async_nl_pid); + } + /* only recv msg from target pid*/ + if (portid != oplus_async_nl_pid) { + return -1; + } + if (!check_msg_in_range(oplus_async_nl_sock, nlh->nlmsg_type)) { + debug("msg_type:%d not in range\n", nlh->nlmsg_type); + return -1; + } + + switch (nlh->nlmsg_type) { + case OPLUS_SAMPLE_ASYNC_GET: + oplus_wcc_sample_async_get(nlh); + break; + default: + return -EINVAL; + } + + return 0; +} + +static void oplus_wcc_sync_nl_rcv(struct sk_buff *skb) +{ + mutex_lock(&oplus_wcc_sync_nl_mutex); + netlink_rcv_skb(skb, &oplus_wcc_sync_nl_rcv_msg); + mutex_unlock(&oplus_wcc_sync_nl_mutex); +} + +static void oplus_wcc_async_nl_rcv(struct sk_buff *skb) +{ + mutex_lock(&oplus_wcc_async_nl_mutex); + netlink_rcv_skb(skb, &oplus_wcc_async_nl_rcv_msg); + mutex_unlock(&oplus_wcc_async_nl_mutex); +} + +static int oplus_wcc_netlink_init(void) +{ + struct netlink_kernel_cfg cfg1 = { + .input = oplus_wcc_sync_nl_rcv, + }; + struct netlink_kernel_cfg cfg2 = { + .input = oplus_wcc_async_nl_rcv, + }; + + oplus_sync_nl_sock = netlink_kernel_create(&init_net, NETLINK_OPLUS_WIFI_CAP_CENTER_SYNC, &cfg1); + oplus_async_nl_sock = netlink_kernel_create(&init_net, NETLINK_OPLUS_WIFI_CAP_CENTER_ASYNC, &cfg2); + debug("oplus_sync_nl_sock = %p, oplus_async_nl_sock = %p\n", oplus_sync_nl_sock, oplus_async_nl_sock); + + if (oplus_sync_nl_sock == NULL || oplus_async_nl_sock == NULL) { + return -ENOMEM; + } else { + return 0; + } +} + +static void oplus_wcc_netlink_exit(void) +{ + netlink_kernel_release(oplus_sync_nl_sock); + oplus_sync_nl_sock = NULL; + + netlink_kernel_release(oplus_async_nl_sock); + oplus_async_nl_sock = NULL; +} + +static struct ctl_table oplus_wcc_sysctl_table[] = { + { + .procname = "oplus_wcc_debug", + .data = &oplus_wcc_debug, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec, + }, + { } +}; + +static int oplus_wcc_sysctl_init(void) +{ + oplus_table_hrd = register_net_sysctl + (&init_net, "net/oplus_wcc", oplus_wcc_sysctl_table); + return oplus_table_hrd == NULL ? -ENOMEM : 0; +} + +static void oplus_wcc_sysctl_fini(void) +{ + if(oplus_table_hrd) { + unregister_net_sysctl_table(oplus_table_hrd); + oplus_table_hrd = NULL; + } +} + +static int __init oplus_wcc_init(void) +{ + int ret = 0; + rwlock_init(&oplus_sync_nl_lock); + rwlock_init(&oplus_async_nl_lock); + + ret = oplus_wcc_netlink_init(); + if (ret < 0) { + debug("oplus_wcc_init module failed to init netlink.\n"); + } else { + debug("oplus_wcc_init module init netlink successfully.\n"); + } + + ret = oplus_wcc_sysctl_init(); + if (ret < 0) { + debug("oplus_wcc_init module failed to init sysctl.\n"); + } + else { + debug("oplus_wcc_init module init sysctl successfully.\n"); + } + + oplus_wcc_timer_init(); + + return ret; +} + +static void __exit oplus_wcc_fini(void) +{ + oplus_wcc_sysctl_fini(); + oplus_wcc_netlink_exit(); + oplus_wcc_timer_fini(); +} + +module_init(oplus_wcc_init); +module_exit(oplus_wcc_fini); + diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index 5f3964635262..4fc6bbce8e43 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -241,6 +241,10 @@ struct packet_skb_cb { static void __fanout_unlink(struct sock *sk, struct packet_sock *po); static void __fanout_link(struct sock *sk, struct packet_sock *po); +//#ifdef OPLUS_FEATURE_DHCP +int (*handle_dhcp)(struct sock *sk, struct sk_buff *skb, struct net_device *dev, struct packet_type *pt) = NULL; +EXPORT_SYMBOL(handle_dhcp); +//#endif /* OPLUS_FEATURE_DHCP */ static int packet_direct_xmit(struct sk_buff *skb) { return dev_direct_xmit(skb, packet_pick_tx_queue(skb)); @@ -2127,6 +2131,13 @@ static int packet_rcv(struct sk_buff *skb, struct net_device *dev, /* drop conntrack reference */ nf_reset(skb); +//#ifdef OPLUS_FEATURE_DHCP + if (handle_dhcp != NULL && handle_dhcp(sk, skb, dev, pt)) { + printk("drop dhcp offer packet"); + goto drop; + } +//#endif /* OPLUS_FEATURE_DHCP */ + spin_lock(&sk->sk_receive_queue.lock); po->stats.stats1.tp_packets++; sock_skb_set_dropcount(sk, skb); diff --git a/net/qrtr/qrtr.c b/net/qrtr/qrtr.c index b4d8388afeea..a5f67f00ec35 100644 --- a/net/qrtr/qrtr.c +++ b/net/qrtr/qrtr.c @@ -1,6 +1,7 @@ /* * Copyright (c) 2015, Sony Mobile Communications Inc. * Copyright (c) 2013, 2018-2019 The Linux Foundation. All rights reserved. + * Copyright (C) 2020 Oplus. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -224,6 +225,10 @@ static void qrtr_log_tx_msg(struct qrtr_node *node, struct qrtr_hdr_v1 *hdr, if (!hdr || !skb) return; + //#ifdef OPLUS_FEATURE_NWPOWER + oplus_update_qrtr_flag(0); + //#endif /* OPLUS_FEATURE_NWPOWER */ + if (hdr->type == QRTR_TYPE_DATA) { skb_copy_bits(skb, QRTR_HDR_MAX_SIZE, &pl_buf, sizeof(pl_buf)); QRTR_INFO(node->ilc, @@ -237,12 +242,24 @@ static void qrtr_log_tx_msg(struct qrtr_node *node, struct qrtr_hdr_v1 *hdr, skb_copy_bits(skb, QRTR_HDR_MAX_SIZE, &pkt, sizeof(pkt)); if (hdr->type == QRTR_TYPE_NEW_SERVER || hdr->type == QRTR_TYPE_DEL_SERVER) + //#ifndef OPLUS_FEATURE_NWPOWER + // QRTR_INFO(node->ilc, + // "TX CTRL: cmd:0x%x SVC[0x%x:0x%x] addr[0x%x:0x%x]\n", + // hdr->type, le32_to_cpu(pkt.server.service), + // le32_to_cpu(pkt.server.instance), + // le32_to_cpu(pkt.server.node), + // le32_to_cpu(pkt.server.port)); + //#else + { QRTR_INFO(node->ilc, "TX CTRL: cmd:0x%x SVC[0x%x:0x%x] addr[0x%x:0x%x]\n", hdr->type, le32_to_cpu(pkt.server.service), le32_to_cpu(pkt.server.instance), le32_to_cpu(pkt.server.node), le32_to_cpu(pkt.server.port)); + oplus_match_qrtr_service_port(hdr->type, le32_to_cpu(pkt.server.service), le32_to_cpu(pkt.server.port)); + } + //#endif /* OPLUS_FEATURE_NWPOWER */ else if (hdr->type == QRTR_TYPE_DEL_CLIENT || hdr->type == QRTR_TYPE_RESUME_TX) QRTR_INFO(node->ilc, @@ -274,6 +291,9 @@ static void qrtr_log_rx_msg(struct qrtr_node *node, struct sk_buff *skb) if (cb->type == QRTR_TYPE_DATA) { skb_copy_bits(skb, 0, &pl_buf, sizeof(pl_buf)); + //#ifdef OPLUS_FEATURE_NWPOWER + oplus_match_qrtr_wakeup(cb->src_node, cb->src_port, cb->dst_port, (unsigned int)pl_buf, (unsigned int)(pl_buf >> 32)); + //#endif /* OPLUS_FEATURE_NWPOWER */ QRTR_INFO(node->ilc, "RX DATA: Len:0x%x CF:0x%x src[0x%x:0x%x] dst[0x%x:0x%x] [%08x %08x]\n", skb->len, cb->confirm_rx, cb->src_node, cb->src_port, @@ -283,12 +303,24 @@ static void qrtr_log_rx_msg(struct qrtr_node *node, struct sk_buff *skb) skb_copy_bits(skb, 0, &pkt, sizeof(pkt)); if (cb->type == QRTR_TYPE_NEW_SERVER || cb->type == QRTR_TYPE_DEL_SERVER) + //#ifndef OPLUS_FEATURE_NWPOWER + // QRTR_INFO(node->ilc, + // "RX CTRL: cmd:0x%x SVC[0x%x:0x%x] addr[0x%x:0x%x]\n", + // cb->type, le32_to_cpu(pkt.server.service), + // le32_to_cpu(pkt.server.instance), + // le32_to_cpu(pkt.server.node), + // le32_to_cpu(pkt.server.port)); + //#else + { QRTR_INFO(node->ilc, "RX CTRL: cmd:0x%x SVC[0x%x:0x%x] addr[0x%x:0x%x]\n", cb->type, le32_to_cpu(pkt.server.service), le32_to_cpu(pkt.server.instance), le32_to_cpu(pkt.server.node), le32_to_cpu(pkt.server.port)); + oplus_match_qrtr_service_port(cb->type, le32_to_cpu(pkt.server.service), le32_to_cpu(pkt.server.port)); + } + //#endif /* OPLUS_FEATURE_NWPOWER */ else if (cb->type == QRTR_TYPE_DEL_CLIENT || cb->type == QRTR_TYPE_RESUME_TX) QRTR_INFO(node->ilc, diff --git a/net/qrtr/qrtr.h b/net/qrtr/qrtr.h index 6a2cccb1296e..a7cf9a4cabaa 100644 --- a/net/qrtr/qrtr.h +++ b/net/qrtr/qrtr.h @@ -4,6 +4,10 @@ #include +//#ifdef OPLUS_FEATURE_NWPOWER +#include +//#endif /* OPLUS_FEATURE_NWPOWER */ + struct sk_buff; /* endpoint node id auto assignment */ diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c index bc9da594e1e3..1e76da0c2b8a 100644 --- a/net/sched/sch_generic.c +++ b/net/sched/sch_generic.c @@ -1150,7 +1150,6 @@ static void dev_deactivate_queue(struct net_device *dev, if (qdisc) { if (!(qdisc->flags & TCQ_F_BUILTIN)) set_bit(__QDISC_STATE_DEACTIVATED, &qdisc->state); - rcu_assign_pointer(dev_queue->qdisc, qdisc_default); } } diff --git a/net/socket.c b/net/socket.c index ef8b54a77848..263a657573a9 100644 --- a/net/socket.c +++ b/net/socket.c @@ -107,6 +107,9 @@ #include #include #include +//#ifdef OPLUS_FEATURE_NWPOWER_NETCONTROLLER +#include +//#endif /* OPLUS_FEATURE_NWPOWER_NETCONTROLLER */ #ifdef CONFIG_NET_RX_BUSY_POLL unsigned int sysctl_net_busy_read __read_mostly; @@ -409,6 +412,10 @@ static struct file_system_type sock_fs_type = { struct file *sock_alloc_file(struct socket *sock, int flags, const char *dname) { struct file *file; + //#ifdef VENDOR_EDIT + struct pid *pid; + struct task_struct *task; + //#enidf /* VENDOR_EDIT */ if (!dname) dname = sock->sk ? sock->sk->sk_prot_creator->name : ""; @@ -423,6 +430,25 @@ struct file *sock_alloc_file(struct socket *sock, int flags, const char *dname) sock->file = file; file->private_data = sock; + //#ifdef VENDOR_EDIT + pid = find_get_pid(current->tgid); + if (pid) { + task = get_pid_task(pid, PIDTYPE_PID); + if (task && sock->sk) { + strncpy(sock->sk->sk_cmdline, task->comm, TASK_COMM_LEN); + sock->sk->sk_cmdline[TASK_COMM_LEN - 1] = 0; + } + put_task_struct(task); + } + put_pid(pid); + //#enidf /* VENDOR_EDIT */ + + //#ifdef OPLUS_FEATURE_NWPOWER + if (sock->sk) { + sock->sk->sk_oplus_pid = current->tgid; + } + //#endif /* OPLUS_FEATURE_NWPOWER */ + return file; } EXPORT_SYMBOL(sock_alloc_file); @@ -1787,6 +1813,11 @@ int __sys_connect(int fd, struct sockaddr __user *uservaddr, int addrlen) if (err < 0) goto out_put; + //#ifdef OPLUS_FEATURE_NWPOWER_NETCONTROLLER + if(oplus_check_socket_in_blacklist(OPLUS_NET_OUTPUT, sock)) + return -EACCES; + //#endif /* OPLUS_FEATURE_NWPOWER_NETCONTROLLER */ + err = security_socket_connect(sock, (struct sockaddr *)&address, addrlen); if (err) @@ -1904,6 +1935,11 @@ int __sys_sendto(int fd, void __user *buff, size_t len, unsigned int flags, if (!sock) goto out; + //#ifdef OPLUS_FEATURE_NWPOWER_NETCONTROLLER + if(oplus_check_socket_in_blacklist(OPLUS_NET_OUTPUT, sock)) + return -EACCES; + //#endif /* OPLUS_FEATURE_NWPOWER_NETCONTROLLER */ + msg.msg_name = NULL; msg.msg_control = NULL; msg.msg_controllen = 0; @@ -1965,6 +2001,11 @@ int __sys_recvfrom(int fd, void __user *ubuf, size_t size, unsigned int flags, if (!sock) goto out; + //#ifdef OPLUS_FEATURE_NWPOWER_NETCONTROLLER + if(oplus_check_socket_in_blacklist(OPLUS_NET_INPUT, sock)) + return err; + //#endif /* OPLUS_FEATURE_NWPOWER_NETCONTROLLER */ + msg.msg_control = NULL; msg.msg_controllen = 0; /* Save some cycles and don't copy the address if not needed */ @@ -2260,8 +2301,14 @@ static int ___sys_sendmsg(struct socket *sock, struct user_msghdr __user *msg, } out_freectl: - if (ctl_buf != ctl) + if (ctl_buf != ctl){ +#ifdef CONFIG_OPLUS_SECURE_GUARD +#ifdef CONFIG_OPLUS_ROOT_CHECK + memset(ctl_buf, 0, ctl_len); +#endif /* CONFIG_OPLUS_ROOT_CHECK */ +#endif /* CONFIG_OPLUS_SECURE_GUARD */ sock_kfree_s(sock->sk, ctl_buf, ctl_len); + } out_freeiov: kfree(iov); return err; @@ -2285,6 +2332,11 @@ long __sys_sendmsg(int fd, struct user_msghdr __user *msg, unsigned int flags, if (!sock) goto out; + //#ifdef OPLUS_FEATURE_NWPOWER_NETCONTROLLER + if(oplus_check_socket_in_blacklist(OPLUS_NET_OUTPUT, sock)) + return -EACCES; + //#endif /* OPLUS_FEATURE_NWPOWER_NETCONTROLLER */ + err = ___sys_sendmsg(sock, msg, &msg_sys, flags, NULL, 0); fput_light(sock->file, fput_needed); @@ -2324,6 +2376,11 @@ int __sys_sendmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen, if (!sock) return err; + //#ifdef OPLUS_FEATURE_NWPOWER_NETCONTROLLER + if(oplus_check_socket_in_blacklist(OPLUS_NET_OUTPUT, sock)) + return -EACCES; + //#endif /* OPLUS_FEATURE_NWPOWER_NETCONTROLLER */ + used_address.name_len = UINT_MAX; entry = mmsg; compat_entry = (struct compat_mmsghdr __user *)mmsg; @@ -2458,6 +2515,11 @@ long __sys_recvmsg(int fd, struct user_msghdr __user *msg, unsigned int flags, if (!sock) goto out; + //#ifdef OPLUS_FEATURE_NWPOWER_NETCONTROLLER + if(oplus_check_socket_in_blacklist(OPLUS_NET_INPUT, sock)) + return err; + //#endif /* OPLUS_FEATURE_NWPOWER_NETCONTROLLER */ + err = ___sys_recvmsg(sock, msg, &msg_sys, flags, 0); fput_light(sock->file, fput_needed); @@ -2497,6 +2559,11 @@ int __sys_recvmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen, if (!sock) return err; + //#ifdef OPLUS_FEATURE_NWPOWER_NETCONTROLLER + if(oplus_check_socket_in_blacklist(OPLUS_NET_INPUT, sock)) + return err; + //#endif /* OPLUS_FEATURE_NWPOWER_NETCONTROLLER */ + if (likely(!(flags & MSG_ERRQUEUE))) { err = sock_error(sock->sk); if (err) { diff --git a/oplus_native_features.mk b/oplus_native_features.mk new file mode 100644 index 000000000000..b1e51ff0b666 --- /dev/null +++ b/oplus_native_features.mk @@ -0,0 +1,241 @@ +#this is generated by oplus/build/make/core/soong_config.mk +OPLUS_NATIVE_FEATURE_SET=OPLUS_BUG_STABILITY OPLUS_BUG_COMPATIBILITY OPLUS_BUG_DEBUG OPLUS_ARCH_INJECT OPLUS_ARCH_EXTENDS VENDOR_EDIT OPLUS_FEATURE_PLATFORM OPLUS_FEATURE_ORMS OPLUS_FEATURE_ENGINEERTOOLS OPLUS_FEATURE_SELINUX_CONTROL_LOG OPLUS_FEATURE_SELINUX_DEBUG_BUILD OPLUS_FEATURE_SELINUX_CONTEXTS OPLUS_FEATURE_PMS_EXCEPTION_FIX OPLUS_FEATURE_PMS_BOOT_TIME_OPT OPLUS_FEATURE_DATE_FIXUP OPLUS_FEATURE_DEXOPT_SPEED OPLUS_FEATURE_APP_ACCESS_FILES OPLUS_FEATURE_OTA_DATA_UPDATE OPLUS_FEATURE_CUSTOM_GIDS OPLUS_FEATURE_PERFORMANCE OPLUS_FEATURE_SENSOR OPLUS_FEATURE_CTS_FINGERPRINT OPLUS_FEATURE_MAINLINE OPLUS_FEATURE_SECURE_GUARD OPLUS_FEATURE_SECURE_ROOTGUARD OPLUS_FEATURE_SECURE_MOUNTGUARD OPLUS_FEATURE_SECURE_EXECGUARD OPLUS_FEATURE_SECURE_KEVENTUPLOAD OPLUS_FEATURE_SECURE_KEYINTERFACESGUARD OPLUS_FEATURE_STORAGE OPLUS_FEATURE_STORAGE_MOUNT OPLUS_FEATURE_STORAGE_RESIZE OPLUS_FEATURE_STORAGE_TRIM OPLUS_FEATURE_STORAGE_FBE OPLUS_FEATURE_STORAGE_MTP OPLUS_FEATURE_STORAGE_RESERVEPARTITION OPLUS_FEATURE_STORAGE_USB OPLUS_FEATURE_STORAGE_CUSTOMIZE_PARTITION OPLUS_FEATURE_STORAGE_FDE OPLUS_FEATURE_STORAGE_AUTOMATIC_TIMING OPLUS_BUG_UPDATABILITY OPLUS_FEATURE_RECOVERY_BUILD OPLUS_FEATURE_RECOVERY_BOOT OPLUS_FEATURE_RECOVERY_UI OPLUS_FEATURE_RECOVERY_RESET OPLUS_FEATURE_OTAPACKAGE_BUILD OPLUS_FEATURE_OTAPACKAGE_UPDATER OPLUS_FEATURE_OTAPACKAGE_SCRIPT OPLUS_FEATURE_DYNAMIC_KEYMAP OPLUS_FEATURE_DROP_STATUSBAR OPLUS_FEATURE_GESTURE_SCREENSHOT OPLUS_FEATURE_PHOENIX_RECOVERY OPLUS_FEATURE_BOOTANIMATION OPLUS_FEATURE_QUICKBOOT OPLUS_FEATURE_LOGKIT OPLUS_FEATURE_LFEH OPLUS_FEATURE_CRITICAL_LOG OPLUS_ARCH_CUSTOM_PARTITION OPLUS_FEATURE_ENGINEERING_FILEACCESS OPLUS_FEATURE_DEXOPT_STRATEGY OPLUS_FEATURE_BATTERY_MANAGER OPLUS_FEATURE_OTA_DDR5_COMPATIBLE OPLUS_FEATURE_RECOVERY_BOOT_REASON OPLUS_FEATURE_PMIC_MONITOR OPLUS_FEATURE_SHUTDOWN_DETECT OPLUS_FEATURE_FACERECOGNITION OPLUS_FEATURE_PHOENIX OPLUS_FEATURE_BINDER_MONITOR OPLUS_FEATURE_THEIA OPLUS_FEATURE_AGINGTEST OPLUS_FEATURE_OPPODL OPLUS_FEATURE_SCHED_ASSIST OPLUS_FEATURE_HEALTHINFO OPLUS_FEATURE_MULTI_KSWAPD OPLUS_FEATURE_FG_IO_OPT OPLUS_FEATURE_ZRAM_OPT OPLUS_FEATURE_PROCESS_RECLAIM OPLUS_FEATURE_MEMORY_ISOLATE OPLUS_FEATURE_MEMLEAK_DETECT OPLUS_FEATURE_QCOM_PMICWD OPLUS_FEATURE_TP_BASIC OPLUS_FEATURE_TP_BSPFWUPDATE OPLUS_FEATURE_FINGERPRINT OPLUS_FEATURE_FINGERPRINTPAY OPLUS_FEATURE_CRYPTOENG OPLUS_FEATURE_STORAGE_TOOL OPLUS_FEATURE_UFS_SHOW_LATENCY OPLUS_FEATURE_PADL_STATISTICS OPLUS_FEATURE_UFSPLUS OPLUS_FEATURE_EXFAT_SUPPORT OPLUS_FEATURE_SDCARDFS_SUPPORT OPLUS_FEATURE_ELEVATOR_DETECT OPLUS_FEATURE_ACTIVITY_RECOGNITION OPLUS_FEATURE_SENSOR_ALGORITHM OPLUS_FEATURE_SENSOR_SMEM OPLUS_FEATURE_ONEPLUSSENSOR OPLUS_FEATURE_FTM OPLUS_FEATURE_MULTI_FREEAREA OPLUS_FEATURE_VIRTUAL_RESERVE_MEMORY OPLUS_FEATURE_LOWMEM_DBG OPLUS_FEATURE_GAME_OPT OPLUS_FEATURE_CAMERA_COMMON OPLUS_FEATURE_VIRTUAL_CAMERA OPLUS_FEATURE_PHYSICAL_CAMERA_PROVIDER_VERSION OPLUS_FEATURE_WIFI_DATASTALL OPLUS_FEATURE_WIFI_HOSTAPDHIDL OPLUS_FEATURE_WIFI_BDF OPLUS_FEATURE_WIFI_FTM OPLUS_FEATURE_WIFI_SAR OPLUS_FEATURE_SWITCH_CHECK OPLUS_FEATURE_WIFI_MINIDUMP OPLUS_FEATURE_WIFI_DIAG OPLUS_FEATURE_WIFI_DCS_SWITCH OPLUS_FEATURE_WIFI_QPOWER OPLUS_FEATURE_WIFI_MTUDETECT OPLUS_FEATURE_WIFI_SLA OPLUS_FEATURE_IPV6_OPTIMIZE OPLUS_FEATURE_WIFI_GBK OPLUS_FEATURE_WIFI_DUALSTA OPLUS_FEATURE_WIFI_ROUTERBOOST OPLUS_FEATURE_WIFI_OSHARE OPLUS_FEATURE_WIFI_LIMMITBGSPEED OPLUS_FEATURE_WIFI_SUPPLICANTHIDL OPLUS_FEATURE_BT_INTEROPLIST OPLUS_FEATURE_BT_DCS OPLUS_FEATURE_BT_FW_OVERRIDE OPLUS_FEATURE_BT_FW_BTTESTMODE OPLUS_FEATURE_GPS_CONFIG_ADAPT OPLUS_FEATURE_BT_FW_SSRDUMP OPLUS_FEATURE_FORCE_NETWORK_SEARCH OPLUS_FEATURE_NW_RECOVERY_WHEN_SCREEN_ON OPLUS_FEATURE_GAMEECO_COOLEFFECT OPLUS_FEATURE_MODEM_MINIDUMP OPLUS_FEATURE_ELEV_MODE OPLUS_FEATURE_NONDDS_OPTIMIZE OPLUS_FEAUTRE_PIN_RETRY OPLUS_FEATURE_APP_MONITOR OPLUS_FEAUTRE_OAPP_NETCONTROL OPLUS_FEATURE_LOG_LISTEN OPLUS_FEATURE_NEW_FREQ_HOP_INTERFACE OPLUS_FEATURE_PLMN_SELECTION OPLUS_FEATURE_REGIONMARK_INDICATION OPLUS_FEATURE_SIP_RP_ERROR_RETRY OPLUS_FEATURE_DNS_HOOK OPLUS_FEATURE_STATS_CALC OPLUS_FEATURE_FONT_FLIP OPLUS_FEATURE_DARKMODE OPLUS_FEATURE_LINKERCONFIG_CUSTOM OPLUS_FEATURE_HANS_FREEZE OPLUS_FEATURE_RESOURCES_COMPILE OPLUS_FEATURE_MOTION_INTERCEPT OPLUS_FEATURE_ATLAS OPLUS_FEATURE_AUDIOSERVER_DEBUG OPLUS_FEATURE_MM_FEEDBACK OPLUS_FEATURE_VIP_RECORD OPLUS_FEATURE_VOIP_ENHANCE OPLUS_FEATURE_KTV OPLUS_FEATURE_PLAYBACKCAPTURE OPLUS_FEATURE_GAME_MUTE OPLUS_FEATURE_VOICE_CHANGER OPLUS_FEATURE_VIBRING_SYNC OPLUS_FEATURE_SVA_TRNSPARENT OPLUS_FEATURE_INPUTCHANNEL_CHOICE OPLUS_FEATURE_AUDIOVOICE_SCENCE OPLUS_FEATURE_DOLBY OPLUS_FEATURE_AUDIOLL OPLUS_FEATURE_SURROUND_AUDIO OPLUS_FEATURE_SPK_PROTECTION OPLUS_FEATURE_OPERATOR_RINGTONE OPLUS_FEATURE_CAMERASOUND_FORCE OPLUS_FEATURE_FORBID_RECORD OPLUS_VDF_LEFT_SPEAKER_MUTE OPLUS_FEATURE_SPEAKER_MUTE OPLUS_FEATURE_ADJUST_VOLUME OPLUS_FEATURE_GAME_AUDIO_EFFECTS OPLUS_FEATURE_DUALHEADPHONE OPLUS_FEATURE_SMARTPA_PM OPLUS_FEATURE_IMPEDANCE_MATCH OPLUS_FEATURE_MIC_VA_MIC_CLK_SWITCH OPLUS_FEATURE_SWITCH_MIC OPLUS_FEATURE_QVA_MIC_SUPPORT OPLUS_FEATURE_CAR_VOICE_DL_MUTE OPLUS_FEATURE_DOLBY_ATMOS_GAME OPLUS_FEATURE_EAR_PROTECTION OPLUS_FEATURE_MULTISCENE_RECORD OPLUS_FEATURE_SSR OPLUS_FEATURE_MI2S_SLAVE OPLUS_FEATURE_AUDIO_FTM OPLUS_FEATURE_ADSP_RECOVERY OPLUS_FEATURE_AP_LVIMFS OPLUS_FEATURE_AEC OPLUS_FEATURE_AUDIODETECT OPLUS_FEATURE_AUDIOHAL_SCHED OPLUS_FEATURE_AUDIO_BINAURAL_RECORD OPLUS_FEATURE_DRM_WIDEVINEL3 OPLUS_FEATURE_OPLUS_AVENHANCEMENT OPLUS_FEATURE_DRM_OMA OPLUS_FEATURE_APE_DECODER OPLUS_FEATURE_VIDEO_TITLE OPLUS_FEATURE_AUDIOBITRATE OPLUS_FEATURE_MP3_RECORDER OPLUS_FEATURE_FFMPEG_INTEGRATION OPLUS_FEATURE_QP_OPTIMIZATION OPLUS_FEATURE_VIDEO_MIRROR OPLUS_FEATURE_HQV_SUPPORT_APP OPLUS_FEATURE_FEEDBACK_INFO OPLUS_FEATURE_ZEN_MODE OPLUS_FEATRUE_HEIF_OPTIMIZE OPLUS_FEATURE_IMAGE_PROCESSING OPLUS_FEATURE_HEIF_CONVERTER OPLUS_FEATURE_10BIT_HEIF OPLUS_FEATURE_OITHMB_INTEGRATION OPLUS_FEATURE_ROI_ENCODE_QCOM OPLUS_FEATURE_OSIE_SR OPLUS_FEATURE_HQV OPLUS_FEATURE_ONSCREENFINGERPRINT OPLUS_FEATURE_AUTOBRIGHTNESS OPLUS_FEATURE_DYNAMIC_DSI OPLUS_FEATURE_GPU_MINIDUMP OPLUS_FEATURE_VPP OPLUS_FEATURE_AI_FRAMERATE OPLUS_FEATURE_RESOLUTIONSWITCH OPLUS_FEATURE_FORBIDDEN_RECORD OPLUS_FEATURE_SMOOTH_BRIGHTNESS OPLUS_FEATURE_PXLW_IRIS5 OPLUS_FEATURE_AOD OPLUS_FEATURE_DC OPLUS_FEATURE_ADFR_KERNEL OPLUS_FEATURE_ADFR OPLUS_FEATURE_GAME_OIFACE OPLUS_FEATURE_ADPF OPLUS_FEATURE_HAPTIC_VIBRATE OPLUS_FEATURE_GAME_JOYSTICK OPLUS_FEATURE_TV_VOIP OPLUS_FEATURE_VC_MUTE OPLUS_FEATURE_AUDIO_OCAR OPLUS_FEATURE_VIRTUAL_AUDIO OPLUS_NATIVE_MACRO_FEATURES TARGET_PRODUCT +OPLUS_BUG_STABILITY=yes +OPLUS_BUG_COMPATIBILITY=yes +OPLUS_BUG_DEBUG=yes +OPLUS_ARCH_INJECT=yes +OPLUS_ARCH_EXTENDS=yes +VENDOR_EDIT=yes +OPLUS_FEATURE_PLATFORM=QCOM +OPLUS_FEATURE_ORMS=yes +OPLUS_FEATURE_ENGINEERTOOLS=true +OPLUS_FEATURE_SELINUX_CONTROL_LOG=true +OPLUS_FEATURE_SELINUX_DEBUG_BUILD=true +OPLUS_FEATURE_SELINUX_CONTEXTS=true +OPLUS_FEATURE_PMS_EXCEPTION_FIX=true +OPLUS_FEATURE_PMS_BOOT_TIME_OPT=true +OPLUS_FEATURE_DATE_FIXUP=true +OPLUS_FEATURE_DEXOPT_SPEED=true +OPLUS_FEATURE_APP_ACCESS_FILES=true +OPLUS_FEATURE_OTA_DATA_UPDATE=true +OPLUS_FEATURE_CUSTOM_GIDS=true +OPLUS_FEATURE_PERFORMANCE=yes +OPLUS_FEATURE_SENSOR=yes +OPLUS_FEATURE_CTS_FINGERPRINT=yes +OPLUS_FEATURE_MAINLINE=yes +OPLUS_FEATURE_SECURE_GUARD=yes +OPLUS_FEATURE_SECURE_ROOTGUARD=yes +OPLUS_FEATURE_SECURE_MOUNTGUARD=yes +OPLUS_FEATURE_SECURE_EXECGUARD=yes +OPLUS_FEATURE_SECURE_KEVENTUPLOAD=yes +OPLUS_FEATURE_SECURE_KEYINTERFACESGUARD=yes +OPLUS_FEATURE_STORAGE=yes +OPLUS_FEATURE_STORAGE_MOUNT=yes +OPLUS_FEATURE_STORAGE_RESIZE=yes +OPLUS_FEATURE_STORAGE_TRIM=yes +OPLUS_FEATURE_STORAGE_FBE=yes +OPLUS_FEATURE_STORAGE_MTP=yes +OPLUS_FEATURE_STORAGE_RESERVEPARTITION=yes +OPLUS_FEATURE_STORAGE_USB=yes +OPLUS_FEATURE_STORAGE_CUSTOMIZE_PARTITION=yes +OPLUS_FEATURE_STORAGE_FDE=yes +OPLUS_FEATURE_STORAGE_AUTOMATIC_TIMING=yes +OPLUS_BUG_UPDATABILITY=yes +OPLUS_FEATURE_RECOVERY_BUILD=yes +OPLUS_FEATURE_RECOVERY_BOOT=yes +OPLUS_FEATURE_RECOVERY_UI=yes +OPLUS_FEATURE_RECOVERY_RESET=yes +OPLUS_FEATURE_OTAPACKAGE_BUILD=yes +OPLUS_FEATURE_OTAPACKAGE_UPDATER=yes +OPLUS_FEATURE_OTAPACKAGE_SCRIPT=yes +OPLUS_FEATURE_DYNAMIC_KEYMAP=yes +OPLUS_FEATURE_DROP_STATUSBAR=yes +OPLUS_FEATURE_GESTURE_SCREENSHOT=yes +OPLUS_FEATURE_PHOENIX_RECOVERY=yes +OPLUS_FEATURE_BOOTANIMATION=yes +OPLUS_FEATURE_QUICKBOOT=yes +OPLUS_FEATURE_LOGKIT=true +OPLUS_FEATURE_LFEH=true +OPLUS_FEATURE_CRITICAL_LOG=true +OPLUS_ARCH_CUSTOM_PARTITION=yes +OPLUS_FEATURE_ENGINEERING_FILEACCESS=yes +OPLUS_FEATURE_DEXOPT_STRATEGY=true +OPLUS_FEATURE_BATTERY_MANAGER=yes +OPLUS_FEATURE_OTA_DDR5_COMPATIBLE=yes +OPLUS_FEATURE_RECOVERY_BOOT_REASON=yes +OPLUS_FEATURE_PMIC_MONITOR=yes +OPLUS_FEATURE_SHUTDOWN_DETECT=yes +OPLUS_FEATURE_FACERECOGNITION=yes +OPLUS_FEATURE_PHOENIX=yes +OPLUS_FEATURE_BINDER_MONITOR=yes +OPLUS_FEATURE_THEIA=yes +OPLUS_FEATURE_AGINGTEST=yes +OPLUS_FEATURE_OPPODL=yes +OPLUS_FEATURE_SCHED_ASSIST=yes +OPLUS_FEATURE_HEALTHINFO=yes +OPLUS_FEATURE_MULTI_KSWAPD=yes +OPLUS_FEATURE_FG_IO_OPT=yes +OPLUS_FEATURE_ZRAM_OPT=yes +OPLUS_FEATURE_PROCESS_RECLAIM=yes +OPLUS_FEATURE_MEMORY_ISOLATE=yes +OPLUS_FEATURE_MEMLEAK_DETECT=yes +OPLUS_FEATURE_QCOM_PMICWD=yes +OPLUS_FEATURE_TP_BASIC=yes +OPLUS_FEATURE_TP_BSPFWUPDATE=yes +OPLUS_FEATURE_FINGERPRINT=oneplus_upgrade +OPLUS_FEATURE_FINGERPRINTPAY=yes +OPLUS_FEATURE_CRYPTOENG=yes +OPLUS_FEATURE_STORAGE_TOOL=yes +OPLUS_FEATURE_UFS_SHOW_LATENCY=yes +OPLUS_FEATURE_PADL_STATISTICS=yes +OPLUS_FEATURE_UFSPLUS=yes +OPLUS_FEATURE_EXFAT_SUPPORT=yes +OPLUS_FEATURE_SDCARDFS_SUPPORT=yes +OPLUS_FEATURE_ELEVATOR_DETECT=yes +OPLUS_FEATURE_ACTIVITY_RECOGNITION=yes +OPLUS_FEATURE_SENSOR_ALGORITHM=yes +OPLUS_FEATURE_SENSOR_SMEM=yes +OPLUS_FEATURE_ONEPLUSSENSOR=yes +OPLUS_FEATURE_FTM=yes +OPLUS_FEATURE_MULTI_FREEAREA=yes +OPLUS_FEATURE_VIRTUAL_RESERVE_MEMORY=yes +OPLUS_FEATURE_LOWMEM_DBG=yes +OPLUS_FEATURE_GAME_OPT=yes +OPLUS_FEATURE_CAMERA_COMMON=yes +OPLUS_FEATURE_VIRTUAL_CAMERA=yes +OPLUS_FEATURE_PHYSICAL_CAMERA_PROVIDER_VERSION=2.4 +OPLUS_FEATURE_WIFI_DATASTALL=yes +OPLUS_FEATURE_WIFI_HOSTAPDHIDL=yes +OPLUS_FEATURE_WIFI_BDF=yes +OPLUS_FEATURE_WIFI_FTM=yes +OPLUS_FEATURE_WIFI_SAR=yes +OPLUS_FEATURE_SWITCH_CHECK=yes +OPLUS_FEATURE_WIFI_MINIDUMP=yes +OPLUS_FEATURE_WIFI_DIAG=yes +OPLUS_FEATURE_WIFI_DCS_SWITCH=yes +OPLUS_FEATURE_WIFI_QPOWER=yes +OPLUS_FEATURE_WIFI_MTUDETECT=yes +OPLUS_FEATURE_WIFI_SLA=yes +OPLUS_FEATURE_IPV6_OPTIMIZE=yes +OPLUS_FEATURE_WIFI_GBK=yes +OPLUS_FEATURE_WIFI_DUALSTA=yes +OPLUS_FEATURE_WIFI_ROUTERBOOST=yes +OPLUS_FEATURE_WIFI_OSHARE=yes +OPLUS_FEATURE_WIFI_LIMMITBGSPEED=yes +OPLUS_FEATURE_WIFI_SUPPLICANTHIDL=yes +OPLUS_FEATURE_BT_INTEROPLIST=yes +OPLUS_FEATURE_BT_DCS=yes +OPLUS_FEATURE_BT_FW_OVERRIDE=yes +OPLUS_FEATURE_BT_FW_BTTESTMODE=yes +OPLUS_FEATURE_GPS_CONFIG_ADAPT=yes +OPLUS_FEATURE_BT_FW_SSRDUMP=yes +OPLUS_FEATURE_FORCE_NETWORK_SEARCH=yes +OPLUS_FEATURE_NW_RECOVERY_WHEN_SCREEN_ON=yes +OPLUS_FEATURE_GAMEECO_COOLEFFECT=yes +OPLUS_FEATURE_MODEM_MINIDUMP=true +OPLUS_FEATURE_ELEV_MODE=true +OPLUS_FEATURE_NONDDS_OPTIMIZE=true +OPLUS_FEAUTRE_PIN_RETRY=true +OPLUS_FEATURE_APP_MONITOR=true +OPLUS_FEAUTRE_OAPP_NETCONTROL=true +OPLUS_FEATURE_LOG_LISTEN=true +OPLUS_FEATURE_NEW_FREQ_HOP_INTERFACE=true +OPLUS_FEATURE_PLMN_SELECTION=true +OPLUS_FEATURE_REGIONMARK_INDICATION=true +OPLUS_FEATURE_SIP_RP_ERROR_RETRY=true +OPLUS_FEATURE_DNS_HOOK=true +OPLUS_FEATURE_STATS_CALC=true +OPLUS_FEATURE_FONT_FLIP=yes +OPLUS_FEATURE_DARKMODE=yes +OPLUS_FEATURE_LINKERCONFIG_CUSTOM=yes +OPLUS_FEATURE_HANS_FREEZE=yes +OPLUS_FEATURE_RESOURCES_COMPILE=yes +OPLUS_FEATURE_MOTION_INTERCEPT=yes +OPLUS_FEATURE_ATLAS=yes +OPLUS_FEATURE_AUDIOSERVER_DEBUG=yes +OPLUS_FEATURE_MM_FEEDBACK=yes +OPLUS_FEATURE_VIP_RECORD=yes +OPLUS_FEATURE_VOIP_ENHANCE=yes +OPLUS_FEATURE_KTV=true +OPLUS_FEATURE_PLAYBACKCAPTURE=yes +OPLUS_FEATURE_GAME_MUTE=yes +OPLUS_FEATURE_VOICE_CHANGER=yes +OPLUS_FEATURE_VIBRING_SYNC=true +OPLUS_FEATURE_SVA_TRNSPARENT=true +OPLUS_FEATURE_INPUTCHANNEL_CHOICE=yes +OPLUS_FEATURE_AUDIOVOICE_SCENCE=true +OPLUS_FEATURE_DOLBY=true +OPLUS_FEATURE_AUDIOLL=true +OPLUS_FEATURE_SURROUND_AUDIO=yes +OPLUS_FEATURE_SPK_PROTECTION=true +OPLUS_FEATURE_OPERATOR_RINGTONE=yes +OPLUS_FEATURE_CAMERASOUND_FORCE=yes +OPLUS_FEATURE_FORBID_RECORD=yes +OPLUS_VDF_LEFT_SPEAKER_MUTE=yes +OPLUS_FEATURE_SPEAKER_MUTE=true +OPLUS_FEATURE_ADJUST_VOLUME=yes +OPLUS_FEATURE_GAME_AUDIO_EFFECTS=true +OPLUS_FEATURE_DUALHEADPHONE=yes +OPLUS_FEATURE_SMARTPA_PM=yes +OPLUS_FEATURE_IMPEDANCE_MATCH=true +OPLUS_FEATURE_MIC_VA_MIC_CLK_SWITCH=yes +OPLUS_FEATURE_SWITCH_MIC=yes +OPLUS_FEATURE_QVA_MIC_SUPPORT=yes +OPLUS_FEATURE_CAR_VOICE_DL_MUTE=yes +OPLUS_FEATURE_DOLBY_ATMOS_GAME=yes +OPLUS_FEATURE_EAR_PROTECTION=true +OPLUS_FEATURE_MULTISCENE_RECORD=yes +OPLUS_FEATURE_SSR=yes +OPLUS_FEATURE_MI2S_SLAVE=true +OPLUS_FEATURE_AUDIO_FTM=yes +OPLUS_FEATURE_ADSP_RECOVERY=true +OPLUS_FEATURE_AP_LVIMFS=yes +OPLUS_FEATURE_AEC=yes +OPLUS_FEATURE_AUDIODETECT=true +OPLUS_FEATURE_AUDIOHAL_SCHED=yes +OPLUS_FEATURE_AUDIO_BINAURAL_RECORD=true +OPLUS_FEATURE_DRM_WIDEVINEL3=yes +OPLUS_FEATURE_OPLUS_AVENHANCEMENT=yes +OPLUS_FEATURE_DRM_OMA=yes +OPLUS_FEATURE_APE_DECODER=yes +OPLUS_FEATURE_VIDEO_TITLE=yes +OPLUS_FEATURE_AUDIOBITRATE=yes +OPLUS_FEATURE_MP3_RECORDER=yes +OPLUS_FEATURE_FFMPEG_INTEGRATION=yes +OPLUS_FEATURE_QP_OPTIMIZATION=yes +OPLUS_FEATURE_VIDEO_MIRROR=yes +OPLUS_FEATURE_HQV_SUPPORT_APP=yes +OPLUS_FEATURE_FEEDBACK_INFO=yes +OPLUS_FEATURE_ZEN_MODE=yes +OPLUS_FEATRUE_HEIF_OPTIMIZE=yes +OPLUS_FEATURE_IMAGE_PROCESSING=yes +OPLUS_FEATURE_HEIF_CONVERTER=yes +OPLUS_FEATURE_10BIT_HEIF=yes +OPLUS_FEATURE_OITHMB_INTEGRATION=yes +OPLUS_FEATURE_ROI_ENCODE_QCOM=yes +OPLUS_FEATURE_OSIE_SR=yes +OPLUS_FEATURE_HQV=yes +OPLUS_FEATURE_ONSCREENFINGERPRINT=yes +OPLUS_FEATURE_AUTOBRIGHTNESS=yes +OPLUS_FEATURE_DYNAMIC_DSI=yes +OPLUS_FEATURE_GPU_MINIDUMP=yes +OPLUS_FEATURE_VPP=yes +OPLUS_FEATURE_AI_FRAMERATE=yes +OPLUS_FEATURE_RESOLUTIONSWITCH=yes +OPLUS_FEATURE_FORBIDDEN_RECORD=yes +OPLUS_FEATURE_SMOOTH_BRIGHTNESS=yes +OPLUS_FEATURE_PXLW_IRIS5=yes +OPLUS_FEATURE_AOD=yes +OPLUS_FEATURE_DC=yes +OPLUS_FEATURE_ADFR_KERNEL=yes +OPLUS_FEATURE_ADFR=yes +OPLUS_FEATURE_GAME_OIFACE=yes +OPLUS_FEATURE_ADPF=yes +OPLUS_FEATURE_HAPTIC_VIBRATE=yes +OPLUS_FEATURE_GAME_JOYSTICK=yes +OPLUS_FEATURE_TV_VOIP=yes +OPLUS_FEATURE_VC_MUTE=yes +OPLUS_FEATURE_AUDIO_OCAR=yes +OPLUS_FEATURE_VIRTUAL_AUDIO=yes +OPLUS_NATIVE_MACRO_FEATURES=OPLUS_BUG_STABILITY OPLUS_BUG_COMPATIBILITY OPLUS_BUG_DEBUG OPLUS_ARCH_INJECT OPLUS_ARCH_EXTENDS VENDOR_EDIT OPLUS_FEATURE_PLATFORM OPLUS_FEATURE_ORMS OPLUS_FEATURE_ENGINEERTOOLS OPLUS_FEATURE_SELINUX_CONTROL_LOG OPLUS_FEATURE_SELINUX_DEBUG_BUILD OPLUS_FEATURE_SELINUX_CONTEXTS OPLUS_FEATURE_PMS_EXCEPTION_FIX OPLUS_FEATURE_PMS_BOOT_TIME_OPT OPLUS_FEATURE_DATE_FIXUP OPLUS_FEATURE_DEXOPT_SPEED OPLUS_FEATURE_APP_ACCESS_FILES OPLUS_FEATURE_OTA_DATA_UPDATE OPLUS_FEATURE_CUSTOM_GIDS OPLUS_FEATURE_PERFORMANCE OPLUS_FEATURE_SENSOR OPLUS_FEATURE_CTS_FINGERPRINT OPLUS_FEATURE_MAINLINE OPLUS_FEATURE_SECURE_GUARD OPLUS_FEATURE_SECURE_ROOTGUARD OPLUS_FEATURE_SECURE_MOUNTGUARD OPLUS_FEATURE_SECURE_EXECGUARD OPLUS_FEATURE_SECURE_KEVENTUPLOAD OPLUS_FEATURE_SECURE_KEYINTERFACESGUARD OPLUS_FEATURE_STORAGE OPLUS_FEATURE_STORAGE_MOUNT OPLUS_FEATURE_STORAGE_RESIZE OPLUS_FEATURE_STORAGE_TRIM OPLUS_FEATURE_STORAGE_FBE OPLUS_FEATURE_STORAGE_MTP OPLUS_FEATURE_STORAGE_RESERVEPARTITION OPLUS_FEATURE_STORAGE_USB OPLUS_FEATURE_STORAGE_CUSTOMIZE_PARTITION OPLUS_FEATURE_STORAGE_FDE OPLUS_FEATURE_STORAGE_AUTOMATIC_TIMING OPLUS_BUG_UPDATABILITY OPLUS_FEATURE_RECOVERY_BUILD OPLUS_FEATURE_RECOVERY_BOOT OPLUS_FEATURE_RECOVERY_UI OPLUS_FEATURE_RECOVERY_RESET OPLUS_FEATURE_OTAPACKAGE_BUILD OPLUS_FEATURE_OTAPACKAGE_UPDATER OPLUS_FEATURE_OTAPACKAGE_SCRIPT OPLUS_FEATURE_DYNAMIC_KEYMAP OPLUS_FEATURE_DROP_STATUSBAR OPLUS_FEATURE_GESTURE_SCREENSHOT OPLUS_FEATURE_PHOENIX_RECOVERY OPLUS_FEATURE_BOOTANIMATION OPLUS_FEATURE_QUICKBOOT OPLUS_FEATURE_LOGKIT OPLUS_FEATURE_LFEH OPLUS_FEATURE_CRITICAL_LOG OPLUS_ARCH_CUSTOM_PARTITION OPLUS_FEATURE_ENGINEERING_FILEACCESS OPLUS_FEATURE_DEXOPT_STRATEGY OPLUS_FEATURE_BATTERY_MANAGER OPLUS_FEATURE_OTA_DDR5_COMPATIBLE OPLUS_FEATURE_RECOVERY_BOOT_REASON OPLUS_FEATURE_PMIC_MONITOR OPLUS_FEATURE_SHUTDOWN_DETECT OPLUS_FEATURE_FACERECOGNITION OPLUS_FEATURE_PHOENIX OPLUS_FEATURE_BINDER_MONITOR OPLUS_FEATURE_THEIA OPLUS_FEATURE_AGINGTEST OPLUS_FEATURE_OPPODL OPLUS_FEATURE_SCHED_ASSIST OPLUS_FEATURE_HEALTHINFO OPLUS_FEATURE_MULTI_KSWAPD OPLUS_FEATURE_FG_IO_OPT OPLUS_FEATURE_ZRAM_OPT OPLUS_FEATURE_PROCESS_RECLAIM OPLUS_FEATURE_MEMORY_ISOLATE OPLUS_FEATURE_MEMLEAK_DETECT OPLUS_FEATURE_QCOM_PMICWD OPLUS_FEATURE_TP_BASIC OPLUS_FEATURE_TP_BSPFWUPDATE OPLUS_FEATURE_FINGERPRINT OPLUS_FEATURE_FINGERPRINTPAY OPLUS_FEATURE_CRYPTOENG OPLUS_FEATURE_STORAGE_TOOL OPLUS_FEATURE_UFS_SHOW_LATENCY OPLUS_FEATURE_PADL_STATISTICS OPLUS_FEATURE_UFSPLUS OPLUS_FEATURE_EXFAT_SUPPORT OPLUS_FEATURE_SDCARDFS_SUPPORT OPLUS_FEATURE_ELEVATOR_DETECT OPLUS_FEATURE_ACTIVITY_RECOGNITION OPLUS_FEATURE_SENSOR_ALGORITHM OPLUS_FEATURE_SENSOR_SMEM OPLUS_FEATURE_ONEPLUSSENSOR OPLUS_FEATURE_FTM OPLUS_FEATURE_MULTI_FREEAREA OPLUS_FEATURE_VIRTUAL_RESERVE_MEMORY OPLUS_FEATURE_LOWMEM_DBG OPLUS_FEATURE_GAME_OPT OPLUS_FEATURE_CAMERA_COMMON OPLUS_FEATURE_VIRTUAL_CAMERA OPLUS_FEATURE_PHYSICAL_CAMERA_PROVIDER_VERSION OPLUS_FEATURE_WIFI_DATASTALL OPLUS_FEATURE_WIFI_HOSTAPDHIDL OPLUS_FEATURE_WIFI_BDF OPLUS_FEATURE_WIFI_FTM OPLUS_FEATURE_WIFI_SAR OPLUS_FEATURE_SWITCH_CHECK OPLUS_FEATURE_WIFI_MINIDUMP OPLUS_FEATURE_WIFI_DIAG OPLUS_FEATURE_WIFI_DCS_SWITCH OPLUS_FEATURE_WIFI_QPOWER OPLUS_FEATURE_WIFI_MTUDETECT OPLUS_FEATURE_WIFI_SLA OPLUS_FEATURE_IPV6_OPTIMIZE OPLUS_FEATURE_WIFI_GBK OPLUS_FEATURE_WIFI_DUALSTA OPLUS_FEATURE_WIFI_ROUTERBOOST OPLUS_FEATURE_WIFI_OSHARE OPLUS_FEATURE_WIFI_LIMMITBGSPEED OPLUS_FEATURE_WIFI_SUPPLICANTHIDL OPLUS_FEATURE_BT_INTEROPLIST OPLUS_FEATURE_BT_DCS OPLUS_FEATURE_BT_FW_OVERRIDE OPLUS_FEATURE_BT_FW_BTTESTMODE OPLUS_FEATURE_GPS_CONFIG_ADAPT OPLUS_FEATURE_BT_FW_SSRDUMP OPLUS_FEATURE_FORCE_NETWORK_SEARCH OPLUS_FEATURE_NW_RECOVERY_WHEN_SCREEN_ON OPLUS_FEATURE_GAMEECO_COOLEFFECT OPLUS_FEATURE_MODEM_MINIDUMP OPLUS_FEATURE_ELEV_MODE OPLUS_FEATURE_NONDDS_OPTIMIZE OPLUS_FEAUTRE_PIN_RETRY OPLUS_FEATURE_APP_MONITOR OPLUS_FEAUTRE_OAPP_NETCONTROL OPLUS_FEATURE_LOG_LISTEN OPLUS_FEATURE_NEW_FREQ_HOP_INTERFACE OPLUS_FEATURE_PLMN_SELECTION OPLUS_FEATURE_REGIONMARK_INDICATION OPLUS_FEATURE_SIP_RP_ERROR_RETRY OPLUS_FEATURE_DNS_HOOK OPLUS_FEATURE_STATS_CALC OPLUS_FEATURE_FONT_FLIP OPLUS_FEATURE_DARKMODE OPLUS_FEATURE_LINKERCONFIG_CUSTOM OPLUS_FEATURE_HANS_FREEZE OPLUS_FEATURE_RESOURCES_COMPILE OPLUS_FEATURE_MOTION_INTERCEPT OPLUS_FEATURE_ATLAS OPLUS_FEATURE_AUDIOSERVER_DEBUG OPLUS_FEATURE_MM_FEEDBACK OPLUS_FEATURE_VIP_RECORD OPLUS_FEATURE_VOIP_ENHANCE OPLUS_FEATURE_KTV OPLUS_FEATURE_PLAYBACKCAPTURE OPLUS_FEATURE_GAME_MUTE OPLUS_FEATURE_VOICE_CHANGER OPLUS_FEATURE_VIBRING_SYNC OPLUS_FEATURE_SVA_TRNSPARENT OPLUS_FEATURE_INPUTCHANNEL_CHOICE OPLUS_FEATURE_AUDIOVOICE_SCENCE OPLUS_FEATURE_DOLBY OPLUS_FEATURE_AUDIOLL OPLUS_FEATURE_SURROUND_AUDIO OPLUS_FEATURE_SPK_PROTECTION OPLUS_FEATURE_OPERATOR_RINGTONE OPLUS_FEATURE_CAMERASOUND_FORCE OPLUS_FEATURE_FORBID_RECORD OPLUS_VDF_LEFT_SPEAKER_MUTE OPLUS_FEATURE_SPEAKER_MUTE OPLUS_FEATURE_ADJUST_VOLUME OPLUS_FEATURE_GAME_AUDIO_EFFECTS OPLUS_FEATURE_DUALHEADPHONE OPLUS_FEATURE_SMARTPA_PM OPLUS_FEATURE_IMPEDANCE_MATCH OPLUS_FEATURE_MIC_VA_MIC_CLK_SWITCH OPLUS_FEATURE_SWITCH_MIC OPLUS_FEATURE_QVA_MIC_SUPPORT OPLUS_FEATURE_CAR_VOICE_DL_MUTE OPLUS_FEATURE_DOLBY_ATMOS_GAME OPLUS_FEATURE_EAR_PROTECTION OPLUS_FEATURE_MULTISCENE_RECORD OPLUS_FEATURE_SSR OPLUS_FEATURE_MI2S_SLAVE OPLUS_FEATURE_AUDIO_FTM OPLUS_FEATURE_ADSP_RECOVERY OPLUS_FEATURE_AP_LVIMFS OPLUS_FEATURE_AEC OPLUS_FEATURE_AUDIODETECT OPLUS_FEATURE_AUDIOHAL_SCHED OPLUS_FEATURE_AUDIO_BINAURAL_RECORD OPLUS_FEATURE_DRM_WIDEVINEL3 OPLUS_FEATURE_OPLUS_AVENHANCEMENT OPLUS_FEATURE_DRM_OMA OPLUS_FEATURE_APE_DECODER OPLUS_FEATURE_VIDEO_TITLE OPLUS_FEATURE_AUDIOBITRATE OPLUS_FEATURE_MP3_RECORDER OPLUS_FEATURE_FFMPEG_INTEGRATION OPLUS_FEATURE_QP_OPTIMIZATION OPLUS_FEATURE_VIDEO_MIRROR OPLUS_FEATURE_HQV_SUPPORT_APP OPLUS_FEATURE_FEEDBACK_INFO OPLUS_FEATURE_ZEN_MODE OPLUS_FEATRUE_HEIF_OPTIMIZE OPLUS_FEATURE_IMAGE_PROCESSING OPLUS_FEATURE_HEIF_CONVERTER OPLUS_FEATURE_10BIT_HEIF OPLUS_FEATURE_OITHMB_INTEGRATION OPLUS_FEATURE_ROI_ENCODE_QCOM OPLUS_FEATURE_OSIE_SR OPLUS_FEATURE_HQV OPLUS_FEATURE_ONSCREENFINGERPRINT OPLUS_FEATURE_AUTOBRIGHTNESS OPLUS_FEATURE_DYNAMIC_DSI OPLUS_FEATURE_GPU_MINIDUMP OPLUS_FEATURE_VPP OPLUS_FEATURE_AI_FRAMERATE OPLUS_FEATURE_RESOLUTIONSWITCH OPLUS_FEATURE_FORBIDDEN_RECORD OPLUS_FEATURE_SMOOTH_BRIGHTNESS OPLUS_FEATURE_PXLW_IRIS5 OPLUS_FEATURE_AOD OPLUS_FEATURE_DC OPLUS_FEATURE_ADFR_KERNEL OPLUS_FEATURE_ADFR OPLUS_FEATURE_GAME_OIFACE OPLUS_FEATURE_ADPF OPLUS_FEATURE_HAPTIC_VIBRATE OPLUS_FEATURE_GAME_JOYSTICK OPLUS_FEATURE_TV_VOIP OPLUS_FEATURE_VC_MUTE OPLUS_FEATURE_AUDIO_OCAR OPLUS_FEATURE_VIRTUAL_AUDIO +TARGET_PRODUCT=kona diff --git a/scripts/Makefile.kasan b/scripts/Makefile.kasan index 6410bd22fe38..5731f2b1802e 100644 --- a/scripts/Makefile.kasan +++ b/scripts/Makefile.kasan @@ -27,6 +27,7 @@ else $(call cc-param,asan-globals=1) \ $(call cc-param,asan-instrumentation-with-call-threshold=$(call_threshold)) \ $(call cc-param,asan-stack=$(CONFIG_KASAN_STACK)) \ + $(call cc-param,asan-use-after-scope=1) \ $(call cc-param,asan-instrument-allocas=1) endif diff --git a/security/selinux/avc.c b/security/selinux/avc.c index b1b74431d351..617bd34b115f 100644 --- a/security/selinux/avc.c +++ b/security/selinux/avc.c @@ -33,6 +33,9 @@ #include "avc.h" #include "avc_ss.h" #include "classmap.h" +#ifdef OPLUS_FEATURE_SELINUX_CONTROL_LOG +#include +#endif /* OPLUS_FEATURE_SELINUX_CONTROL_LOG */ #define AVC_CACHE_SLOTS 512 #define AVC_DEF_CACHE_THRESHOLD 512 @@ -770,6 +773,11 @@ noinline int slow_avc_audit(struct selinux_state *state, struct common_audit_data stack_data; struct selinux_audit_data sad; +#ifdef OPLUS_FEATURE_SELINUX_CONTROL_LOG + if (!is_avc_audit_enable()) + return 0; +#endif /* OPLUS_FEATURE_SELINUX_CONTROL_LOG */ + if (!a) { a = &stack_data; a->type = LSM_AUDIT_DATA_NONE; diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 2e48b6205810..8b8229f0f3b6 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -7355,6 +7355,14 @@ void selinux_complete_init(void) iterate_supers(delayed_superblock_init, NULL); } +#ifdef CONFIG_OPLUS_SECURE_GUARD +int get_current_security_context(char **context, u32 *context_len) +{ + u32 sid = current_sid(); + return security_sid_to_context(&selinux_state, sid, context, context_len); +} +#endif /* CONFIG_OPLUS_SECURE_GUARD */ + /* SELinux requires early initialization in order to label all processes and objects when they are created. */ security_initcall(selinux_init); diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c index f6bc78aba75a..e8db8c8061de 100644 --- a/security/selinux/selinuxfs.c +++ b/security/selinux/selinuxfs.c @@ -42,6 +42,10 @@ #include "objsec.h" #include "conditional.h" +#ifdef OPLUS_FEATURE_SELINUX_CONTROL_LOG +#include +#endif /* OPLUS_FEATURE_SELINUX_CONTROL_LOG */ + enum sel_inos { SEL_ROOT_INO = 2, SEL_LOAD, /* load policy */ @@ -2129,6 +2133,10 @@ static int __init init_sel_fs(void) selinux_null.dentry = NULL; } +#ifdef OPLUS_FEATURE_SELINUX_CONTROL_LOG + init_denied_proc(); +#endif /* OPLUS_FEATURE_SELINUX_CONTROL_LOG */ + return err; } diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c index 45b7e60b915b..9a4dce7b7250 100644 --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c @@ -1476,7 +1476,7 @@ u64 snd_usb_interface_dsd_format_quirks(struct snd_usb_audio *chip, switch (USB_ID_VENDOR(chip->usb_id)) { case 0x152a: /* Thesycon devices */ case 0x20b1: /* XMOS based devices */ - case 0x22d9: /* Oppo */ + case 0x22d9: /* Oplus */ case 0x23ba: /* Playback Designs */ case 0x25ce: /* Mytek devices */ case 0x278b: /* Rotel? */